diff --git a/.ci/AppImageBuilder.yml b/.ci/AppImageBuilder.yml new file mode 100644 index 000000000..be2a7f1c1 --- /dev/null +++ b/.ci/AppImageBuilder.yml @@ -0,0 +1,90 @@ +# +# 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. +# +# Recipe file for appimage-builder. +# +# build.sh processes conditional comments based on CMakeCache +# options at the end of each line. For example, a line ending in: +# +# # if QT:BOOL=ON +# +# will be removed from the dynamically-generated copy of this +# file if "QT" is not a boolean option set to ON, either through +# a -D definition or the option's default value in CMakeLists. +# +# +# Authors: RichardG, +# +# Copyright 2022 RichardG. +# + +version: 1 +AppDir: + path: ./archive_tmp + app_info: + id: !ENV '${project_id}' + name: !ENV '${project}' + icon: !ENV '${project_icon}' + version: !ENV '${project_version}' + exec: !ENV 'usr/local/bin/${project}' + exec_args: $@ + apt: + arch: !ENV '${arch_deb}' + sources: + - sourceline: 'deb http://deb.debian.org/debian bullseye main' + key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x1f89983e0081fde018f3cc9673a4f27b8dd47936' + - sourceline: 'deb http://security.debian.org/debian-security bullseye-security main' + key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x1f89983e0081fde018f3cc9673a4f27b8dd47936' + - sourceline: 'deb http://deb.debian.org/debian bullseye-updates main' + key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xac530d520f2f3269f5e98313a48449044aad5c5d' + include: + - libedit2 # if (CLI:BOOL=ON|QT:BOOL=OFF) + - libevdev2 # if QT:BOOL=ON + - libfluidsynth2 + - libfreetype6 + - libgbm1 # if QT:BOOL=ON + - libgl1 # if QT:BOOL=ON + - libgles2 # if QT:BOOL=ON + - libglvnd0 # if QT:BOOL=ON + - libglx0 # if QT:BOOL=ON + - libgs9 + - libpng16-16 + - libqt5core5a # if QT:BOOL=ON + - libqt5gui5 # if QT:BOOL=ON + - libqt5widgets5 # if QT:BOOL=ON + - libsixel1 # if CLI:BOOL=ON + - libslirp0 # if SLIRP_EXTERNAL:BOOL=ON + - libsndio7.0 # if OPENAL:BOOL=ON + - libwayland-client0 # if QT:BOOL=ON + - libx11-6 # if QT:BOOL=ON + - libx11-xcb1 # if QT:BOOL=ON + - libxcb1 # if QT:BOOL=ON + - libxcb-render0 # if QT:BOOL=ON + - libxcb-shape0 # if QT:BOOL=ON + - libxcb-shm0 # if QT:BOOL=ON + - libxcb-xfixes0 # if QT:BOOL=ON + - zlib1g + files: + exclude: + - etc + - lib/udev + - opt/libc/usr/share + - usr/[a-km-rt-zA-Z]* + - usr/lib/*/libasound.so.* + - usr/lib/*.a + - usr/lib/cmake + - usr/lib/pkgconfig + - usr/s[a-gi-zA-Z]* + - usr/share/[a-hj-ln-zA-Z]* + - usr/share/i[a-bd-zA-Z]* + - usr/share/m[a-df-zA-Z]* + - usr/share/metainfo/*.metainfo.xml + - var +AppImage: + arch: !ENV '${arch_appimage}' + file_name: '-n' # nasty hack to disable metainfo validation diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile new file mode 100644 index 000000000..e6f717a3d --- /dev/null +++ b/.ci/Jenkinsfile @@ -0,0 +1,335 @@ +/* + * 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. + * + * Jenkins build pipeline definition. + * + * + * + * Authors: RichardG, + * + * Copyright 2021-2022 RichardG. + */ + +/* ['main builds', 'branch builds'] */ +def repository = ['https://github.com/86Box/86Box.git', scm.userRemoteConfigs[0].url] +def commitBrowser = ['https://github.com/86Box/86Box/commit/%s', null] +def branch = ['master', scm.branches[0].name] +def buildType = ['beta', 'alpha'] +def buildBranch = env.JOB_BASE_NAME.contains('-') ? 1 : 0 + +def osArchs = [ + 'Windows': ['32', '64'], + 'Linux': ['x86', 'x86_64', 'arm32', 'arm64'], + 'macOS': ['x86_64+arm64'] +] + +def osFlags = [ + 'Windows': '-D QT=ON', + 'Linux': '-D QT=ON', + 'macOS': '-D QT=ON' +] + +def archNames = [ + '32': 'x86 (32-bit)', + 'x86': 'x86 (32-bit)', + '64': 'x64 (64-bit)', + 'x86_64': 'x64 (64-bit)', + 'arm32': 'ARM (32-bit)', + 'arm64': 'ARM (64-bit)' +] + +def archNamesMac = [ + 'x86_64': 'Intel', + 'arm64': 'Apple Silicon', + 'x86_64+arm64': 'Universal (Intel and Apple Silicon)' +] + +def dynarecNames = [ + 'ODR': 'Old Recompiler (recommended)', + 'NDR': 'New Recompiler (beta)', + 'NoDR': 'No Dynamic Recompiler' +] + +def dynarecArchs = [ + '32': ['ODR', 'NDR'], + 'x86': ['ODR', 'NDR'], + '64': ['ODR', 'NDR'], + 'x86_64': ['ODR', 'NDR'], + 'arm32': ['NDR'], + 'arm64': ['NDR'], + 'x86_64+arm64': ['ODR', 'NDR'] +] + +def dynarecFlags = [ + 'ODR': '-D NEW_DYNAREC=OFF', + 'NDR': '-D NEW_DYNAREC=ON', + 'NoDR': '-D DYNAREC=OFF' +] + +def dynarecSlugs = [ + 'ODR': '', + 'NDR': '-NDR', + 'NoDR': '' +] + +def presets = [ + 'Regular', + 'Debug' +] + +def presetSlugs = [ + 'Regular': '', + 'Debug': '-Debug', + 'Dev': '-Dev' +] + +def presetFlags = [ + 'Regular': '-t --preset=regular -D CMAKE_BUILD_TYPE=Release', + 'Debug': '--preset=debug -D CMAKE_BUILD_TYPE=Debug -D STATIC_BUILD=OFF', + 'Dev': '--preset=experimental -D CMAKE_BUILD_TYPE=Debug -D VNC=OFF -D STATIC_BUILD=OFF' +] + +def gitClone(repository, branch) { + /* Clean workspace. */ + cleanWs() + + /* Use stashes to pass the repository around debian.citadel, as it's known to be faster than git clone there. */ + if (env.NODE_NAME != 'debian.citadel' || env.GIT_STASHED != 'true') { + /* Perform clone/checkout. */ + def scmVars = checkout poll: true, + changelog: true, + scm: [$class: 'GitSCM', + branches: [[name: branch]], + userRemoteConfigs: [[url: repository]]] + + if (env.GIT_COMMIT == null) { + /* Save the current HEAD commit. */ + env.GIT_COMMIT = scmVars.GIT_COMMIT + } else if (env.GIT_COMMIT != scmVars.GIT_COMMIT) { + /* Checkout the commit read from the polling log. */ + if (isUnix()) + sh(returnStatus: true, script: "git checkout ${env.GIT_COMMIT}") + else + bat(returnStatus: true, script: "git checkout ${env.GIT_COMMIT}") + } + println "[-] Using git commit [${env.GIT_COMMIT}]" + + /* Stash data and mark it as stashed if required. */ + if (env.GIT_STASHED != 'true') { + stash name: 'git', useDefaultExcludes: false + env.GIT_STASHED = 'true' + } + } else { + /* Unstash data. */ + unstash name: 'git' + } +} + +def removeDir(dir) { + if (isUnix()) + return sh(returnStatus: true, script: "rm -rf '$dir'") + else + return bat(returnStatus: true, script: "rd /s /q \"$dir\"") +} + +def runBuild(args) { + if (isUnix()) + return sh(returnStatus: true, script: "chmod u+x '$WORKSPACE/.ci/build.sh' && exec '$WORKSPACE/.ci/build.sh' $args") + else + return bat(returnStatus: true, script: "C:\\msys64\\msys2_shell.cmd -msys2 -defterm -here -no-start -c 'exec \"\$(cygpath -u \\'%WORKSPACE%\\')/.ci/build.sh\" $args'") +} + +def failStage() { + /* Force this stage to fail. */ + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + def x = 1 / 0 + } +} + +pipeline { + agent none + + environment { + DISCORD_WEBHOOK_URL = credentials('discord-webhook-url') + } + + options { + quietPeriod(0) + } + + parameters { + string(name: 'BUILD_TYPE', + defaultValue: buildType[buildBranch], + description: "Build type to pass on to CMake (on main builds) or feature branch identifier (on branch builds).") + } + + stages { + stage('Source Tarball') { + agent none + failFast false + + steps { + script { + /* Extract the polled commit from the polling log, so that git checkout + can be used to avoid JENKINS-20518 race conditions caused by the + webhook being triggered more than once in a short period of time. + This is a backup strategy for FilterProxy's webhook queuing. */ + node('master') { /* must run on master node to read polling log */ + /* Ignore exceptions as this is not really critical. */ + try { + /* Switch to this build's directory. */ + dir("${env.JENKINS_HOME}/jobs/${env.JOB_NAME}/builds/${env.BUILD_NUMBER}") { + /* Parse polling log. */ + def pollingLog = readFile file: 'polling.log' + def match = pollingLog =~ /Latest remote head revision on [^ ]+ is: ([a-zA-Z0-9]+)/ + if (match && match[0]) { + env.GIT_COMMIT = match[0][1] + println "[-] Read git commit [${env.GIT_COMMIT}] from polling log" + } + } + } catch (e) {} + } + + /* Adding to the above, run a git clone as soon as possible on any node + to further avoid race conditions caused by busy node executor delays. */ + retry(10) { + node('!Windows') { + /* Run git clone. */ + gitClone(repository[buildBranch], branch[buildBranch]) + + /* Clean workspace, in case this is running in a non-build node. */ + cleanWs() + } + } + + /* Determine build metadata. */ + def buildFlags = "-D \"BUILD_TYPE=$BUILD_TYPE\" -D \"EMU_BUILD=build ${env.BUILD_NUMBER}\" -D \"EMU_BUILD_NUM=${env.BUILD_NUMBER}\"" + def buildSuffix = "-b${env.BUILD_NUMBER}" + if (buildBranch > 0) { + def date = new Date().format("yyyyMMdd") + buildFlags = "-D \"BUILD_TYPE=${buildType[buildBranch]}\" -D \"EMU_BUILD=${env.JOB_BASE_NAME.split('-')[1]} build $date.$BUILD_TYPE\"" + buildSuffix = "-$date-$BUILD_TYPE" + } + + /* Create source tarball. */ + try { + retry(10) { + node('Linux || macOS') { + /* Run git clone. */ + gitClone(repository[buildBranch], branch[buildBranch]) + + /* Switch to temp directory. */ + dir("${env.WORKSPACE_TMP}/output") { + /* Run source tarball creation process. */ + def packageName = "${env.JOB_BASE_NAME}-Source$buildSuffix" + if (runBuild("-s \"$packageName\"") == 0) { + /* Archive resulting artifacts. */ + archiveArtifacts artifacts: "$packageName*" + } else { + /* Fail this stage. */ + failStage() + } + } + + /* Clean up. */ + removeDir("${env.WORKSPACE_TMP}/output") + } + } + } catch (e) { + /* Fail this stage. */ + failStage() + } + + /* Build here to avoid creating a redundant parent stage on the stage view. */ + osArchs.each { os, thisOsArchs -> + def combinations = [:] + thisOsArchs.each { arch -> + def thisArchDynarecs = dynarecArchs[arch.toLowerCase()] + if (!thisArchDynarecs) + thisArchDynarecs = ['NoDR'] + thisArchDynarecs.each { dynarec -> + presets.each { preset -> + def combination = "$os $arch $dynarec $preset" + combinations[combination] = { + catchError(buildResult: 'FAILURE', stageResult: 'SUCCESS') { + retry(10) { + node(os) { + stage(combination) { + /* Run git clone. */ + gitClone(repository[buildBranch], branch[buildBranch]) + + /* Switch to output directory. */ + dir("${env.WORKSPACE_TMP}/output") { + /* Run build process. */ + def packageName = "${env.JOB_BASE_NAME}${dynarecSlugs[dynarec]}${presetSlugs[preset]}-$os-$arch$buildSuffix" + def ret = -1 + def archName = archNames[arch] + if (os == 'macOS') + archName = archNamesMac[arch] + dir("${dynarecNames[dynarec]}/$os - $archName") { + ret = runBuild("-b \"$packageName\" \"$arch\" ${presetFlags[preset]} ${dynarecFlags[dynarec]} ${osFlags[os]} $buildFlags") + } + + if (ret == 0) { + /* Archive resulting artifacts. */ + archiveArtifacts artifacts: "**/**/$packageName*" + } else { + /* Fail this stage. */ + failStage() + } + } + + /* Clean up. */ + removeDir("${env.WORKSPACE_TMP}/output") + } + } + } + } + } + } + } + } + parallel combinations + } + } + } + } + } + + post { + always { + script { + /* Send out build notifications. */ + if (commitBrowser[buildBranch]) { + try { + /* Notify Discord. */ + def result = currentBuild.currentResult.toLowerCase() + discordSend webhookURL: DISCORD_WEBHOOK_URL, + title: "${env.JOB_BASE_NAME} #${env.BUILD_NUMBER}", + link: env.BUILD_URL, + result: currentBuild.currentResult, + description: "**Status:** ${result}\n\u2060", /* word joiner character forces a blank line */ + enableArtifactsList: false, + showChangeset: true, + scmWebUrl: commitBrowser[buildBranch] + + /* Notify IRC, which needs a node for whatever reason. */ + node('citadel || rg || master') { + ircNotify() + } + } catch (e) { + /* Force this stage to fail. */ + catchError(buildResult: currentBuild.result, stageResult: 'FAILURE') { + throw e; + } + } + } + } + } + } +} diff --git a/.ci/build.sh b/.ci/build.sh new file mode 100644 index 000000000..b5edae736 --- /dev/null +++ b/.ci/build.sh @@ -0,0 +1,1085 @@ +#!/bin/sh +# +# 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. +# +# Jenkins build script. +# +# +# Authors: RichardG, +# +# Copyright 2021-2022 RichardG. +# + +# +# While this script was made for our Jenkins infrastructure, you can run it +# to produce Jenkins-like builds on your local machine by following these notes: +# +# - Run build.sh without parameters to see its usage +# - Any boolean CMake definitions (-D ...=ON/OFF) must be ON or OFF to ensure correct behavior +# - For Windows (MSYS MinGW) builds: +# - Packaging requires 7-Zip on Program Files +# - Packaging the Ghostscript DLL requires 32-bit and/or 64-bit Ghostscript on Program Files +# - Packaging the FluidSynth DLL requires it to be at /home/86Box/dll32/libfluidsynth.dll +# and/or /home/86Box/dll64/libfluidsynth64.dll (for 32-bit and 64-bit builds respectively) +# - Packaging the Discord DLL requires wget (MSYS should come with it) +# - For Linux builds: +# - Only Debian and derivatives are supported +# - dpkg and apt-get are called through sudo to manage dependencies; make sure those +# are configured as NOPASSWD in /etc/sudoers if you're doing unattended builds +# - For macOS builds: +# - A standard MacPorts installation is required, with the following macports.conf settings: +# buildfromsource always +# build_arch x86_64 (or arm64) +# universal_archs (blank) +# ui_interactive no +# macosx_deployment_target 10.13 (for x86_64, or 11.0 for arm64) +# - For universal building on Apple Silicon hardware, install native MacPorts on the default +# /opt/local and Intel MacPorts on /opt/intel, then tell build.sh to build for "x86_64+arm64" +# - port is called through sudo to manage dependencies; make sure it is configured +# as NOPASSWD in /etc/sudoers if you're doing unattended builds +# + +# Define common functions. +alias is_windows='[ -n "$MSYSTEM" ]' +alias is_mac='uname -s | grep -q Darwin' + +make_tar() { + # Install dependencies. + if ! which tar xz > /dev/null 2>&1 + then + if which apt-get > /dev/null 2>&1 + then + sudo apt-get update + DEBIAN_FRONTEND=noninteractive sudo apt-get install -y tar xz-utils + sudo apt-get clean + elif which port > /dev/null 2>&1 + then + sudo port selfupdate + sudo port install gnutar xz + fi + fi + + # Use MacPorts gnutar (if installed) on macOS. + local tar_cmd=tar + which gnutar > /dev/null 2>&1 && local tar_cmd=gnutar + + # Determine the best supported compression type. + local compression_flag= + local compression_ext= + if which xz > /dev/null 2>&1 + then + local compression_flag=-J + local compression_ext=.xz + elif which bzip2 > /dev/null 2>&1 + then + local compression_flag=-j + local compression_ext=.bz2 + elif which gzip > /dev/null 2>&1 + then + local compression_flag=-z + local compression_ext=.gz + fi + + # Make tar verbose if requested. + [ -n "$VERBOSE" ] && local compression_flag="$compression_flag -v" + + # tar is notorious for having many diverging implementations. For instance, + # the flags we use to strip UID/GID metadata can be --owner/group (GNU), + # --uid/gid (bsdtar) or even none at all (MSYS2 bsdtar). Account for such + # flag differences by checking if they're mentioned on the help text. + local ownership_flags= + local tar_help=$("$tar_cmd" --help 2>&1) + if echo $tar_help | grep -q -- --owner + then + local ownership_flags="--owner=0 --group=0" + elif echo $tar_help | grep -q -- --uid + then + local ownership_flags="--uid 0 --gid 0" + fi + + # Run tar. + "$tar_cmd" -c $compression_flag -f "$1$compression_ext" $ownership_flags * + return $? +} + +cache_dir="$HOME/86box-build-cache" +[ ! -d "$cache_dir" ] && mkdir -p "$cache_dir" +check_buildtag() { + [ -z "$BUILD_TAG" -o "$BUILD_TAG" != "$(cat "$cache_dir/buildtag.$1" 2> /dev/null)" ] + return $? +} +save_buildtag() { + local contents="$BUILD_TAG" + [ -n "$2" ] && local contents="$2" + echo "$contents" > "$cache_dir/buildtag.$1" + return $? +} + +# Set common variables. +project=86Box +cwd=$(pwd) + +# Parse arguments. +package_name= +arch= +tarball_name= +skip_archive=0 +strip=0 +cmake_flags= +while [ $# -gt 0 ] +do + case $1 in + -b) + shift + package_name="$1" + shift + arch="$1" + shift + ;; + + -n) + shift + skip_archive=1 + ;; + + -s) + shift + tarball_name="$1" + shift + ;; + + -t) + shift + strip=1 + ;; + + *) + if echo $1 | grep -q " " + then + cmake_flag="\"$1\"" + else + cmake_flag="$1" + fi + if [ -z "$cmake_flags" ] + then + cmake_flags="$cmake_flag" + else + cmake_flags="$cmake_flags $cmake_flag" + fi + shift + ;; + esac +done +cmake_flags_extra= + +# Check if mandatory arguments were specified. +if [ -z "$package_name" -a -z "$tarball_name" ] || [ -n "$package_name" -a -z "$arch" ] +then + echo '[!] Usage: build.sh -b {package_name} {architecture} [-t] [cmake_flags...]' + echo ' build.sh -s {source_tarball_name}' + exit 100 +fi + +# Switch to the repository root directory. +cd "$(dirname "$0")/.." + +# Make source tarball if requested. +if [ -n "$tarball_name" ] +then + echo [-] Making source tarball [$tarball_name] + + # Clean local tree of gitignored files. + git clean -dfX + + # Recreate working directory if it was removed by git clean. + [ ! -d "$cwd" ] && mkdir -p "$cwd" + + # Save current HEAD commit to VERSION. + git log --stat -1 > VERSION || rm -f VERSION + + # Archive source. + make_tar "$cwd/$tarball_name.tar" + status=$? + + # Check if the archival succeeded. + if [ $status -ne 0 ] + then + echo [!] Tarball creation failed with status [$status] + exit 1 + else + echo [-] Source tarball [$tarball_name] created successfully + [ -z "$package_name" ] && exit 0 + fi +fi + +echo [-] Building [$package_name] for [$arch] with flags [$cmake_flags] + +# Determine CMake toolchain file for this architecture. +toolchain_prefix=flags-gcc +is_mac && toolchain_prefix=llvm-macos +case $arch in + 32 | x86) toolchain="$toolchain_prefix-i686";; + 64 | x86_64) toolchain="$toolchain_prefix-x86_64";; + ARM32 | arm32) toolchain="$toolchain_prefix-armv7";; + ARM64 | arm64) toolchain="$toolchain_prefix-aarch64";; + *) toolchain="$toolchain_prefix-$arch";; +esac +[ ! -e "cmake/$toolchain.cmake" ] && toolchain=flags-gcc +toolchain_file="cmake/$toolchain.cmake" + +# Perform platform-specific setup. +strip_binary=strip +if is_windows +then + # Switch into the correct MSYSTEM if required. + msys=MINGW$arch + [ ! -d "/$msys" ] && msys=CLANG$arch + if [ -d "/$msys" ] + then + if [ "$MSYSTEM" != "$msys" ] + then + # Call build with the correct MSYSTEM. + echo [-] Switching to MSYSTEM [$msys] + cd "$cwd" + args= + [ $strip -ne 0 ] && args="-t $args" + [ $skip_archive -ne 0 ] && args="-n $args" + CHERE_INVOKING=yes MSYSTEM="$msys" bash -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$args""$cmake_flags" + exit $? + fi + else + echo [!] No MSYSTEM for architecture [$arch] + exit 2 + fi + echo [-] Using MSYSTEM [$MSYSTEM] + + # Install dependencies only if we're in a new build and/or architecture. + freetype_dll="$cache_dir/freetype.$MSYSTEM.dll" + if check_buildtag "$MSYSTEM" + then + # Update databases and keyring only if we're in a new build. + if check_buildtag pacmansync + then + # Update keyring as well, since the package signing keys sometimes change. + echo [-] Updating package databases and keyring + yes | pacman -Sy --needed msys2-keyring + + # Save build tag to skip pacman sync/keyring later. + save_buildtag pacmansync + else + echo [-] Not updating package databases and keyring again + fi + + # Query installed packages. + pacman -Qe > "$cache_dir/pacman.txt" + + # Download the specified versions of architecture-specific dependencies. + echo -n [-] Downloading dependencies: + pkg_dir="/var/cache/pacman/pkg" + repo_base="https://repo.msys2.org/mingw/$(echo $MSYSTEM | tr '[:upper:]' '[:lower:]')" + cat .ci/dependencies_msys.txt | tr -d '\r' > "$cache_dir/deps.txt" + pkgs="" + while IFS=" " read pkg version + do + prefixed_pkg="$MINGW_PACKAGE_PREFIX-$pkg" + installed_version=$(grep -E "^$prefixed_pkg " "$cache_dir/pacman.txt" | cut -d " " -f 2) + if [ "$installed_version" != "$version" ] # installed_version will be empty if not installed + then + echo -n " [$pkg" + + # Download package if not already present in the local cache. + pkg_tar="$prefixed_pkg-$version-any.pkg.tar" + if [ -s "$pkg_dir/$pkg_tar.xz" ] + then + pkg_fn="$pkg_tar.xz" + pkg_dest="$pkg_dir/$pkg_fn" + else + pkg_fn="$pkg_tar.zst" + pkg_dest="$pkg_dir/$pkg_fn" + if [ ! -s "$pkg_dest" ] + then + if ! wget -qO "$pkg_dest" "$repo_base/$pkg_fn" + then + rm -f "$pkg_dest" + pkg_fn="$pkg_tar.xz" + pkg_dest="$pkg_dir/$pkg_fn" + wget -qO "$pkg_dest" "$repo_base/$pkg_fn" || rm -f "$pkg_dest" + fi + if [ -s "$pkg_dest" ] + then + wget -qO "$pkg_dest.sig" "$repo_base/$pkg_fn.sig" || rm -f "$pkg_dest.sig" + [ ! -s "$pkg_dest.sig" ] && rm -f "$pkg_dest.sig" + fi + fi + fi + + # Check if the cached package is valid. + if [ -s "$pkg_dest" ] + then + # Add cached zst package. + pkgs="$pkgs $pkg_fn" + else + # Not valid, remove if it exists. + rm -f "$pkg_dest" "$pkg_dest.sig" + echo -n " FAIL" + fi + echo -n "]" + fi + done < "$cache_dir/deps.txt" + [ -z "$pkgs" ] && echo -n ' none required' + echo + + # Install the downloaded architecture-specific dependencies. + echo [-] Installing dependencies through pacman + if [ -n "$pkgs" ] + then + pushd "$pkg_dir" + yes | pacman -U --needed $pkgs + if [ $? -ne 0 ] + then + # Install packages individually if installing them all together failed. + for pkg in $pkgs + do + yes | pacman -U --needed "$pkg" + done + fi + popd + + # Query installed packages again. + pacman -Qe > "$cache_dir/pacman.txt" + fi + + # Install the latest versions for any missing packages (if the specified version couldn't be installed). + pkgs="git" + while IFS=" " read pkg version + do + prefixed_pkg="$MINGW_PACKAGE_PREFIX-$pkg" + grep -qE "^$prefixed_pkg " "$cache_dir/pacman.txt" || pkgs="$pkgs $prefixed_pkg" + done < "$cache_dir/deps.txt" + rm -f "$cache_dir/pacman.txt" "$cache_dir/deps.txt" + yes | pacman -S --needed $pkgs + if [ $? -ne 0 ] + then + # Install packages individually if installing them all together failed. + for pkg in $pkgs + do + yes | pacman -S --needed "$pkg" + done + fi + + # Generate a new freetype DLL for this architecture. + rm -f "$freetype_dll" + + # Save build tag to skip this later. Doing it here (once everything is + # in place) is important to avoid potential issues with retried builds. + save_buildtag "$MSYSTEM" + else + echo [-] Not installing dependencies again + fi +elif is_mac +then + # macOS lacks nproc, but sysctl can do the same job. + alias nproc='sysctl -n hw.logicalcpu' + + # Handle universal building. + if echo "$arch" | grep -q '+' + then + # Create temporary directory for merging app bundles. + rm -rf archive_tmp_universal + mkdir archive_tmp_universal + + # Build for each architecture. + merge_src= + for arch_universal in $(echo "$arch" | tr '+' ' ') + do + # Run build for the architecture. + args= + [ $strip -ne 0 ] && args="-t $args" + case $arch_universal in # workaround: force new dynarec on for ARM + arm32 | arm64) cmake_flags_extra="-D NEW_DYNAREC=ON";; + *) cmake_flags_extra=;; + esac + zsh -lc 'exec "'"$0"'" -n -b "universal part" "'"$arch_universal"'" '"$args""$cmake_flags"' '"$cmake_flags_extra" + status=$? + + if [ $status -eq 0 ] + then + # Move app bundle to the temporary directory. + app_bundle_name="archive_tmp/$(ls archive_tmp | grep '.app$')" + mv "$app_bundle_name" "archive_tmp_universal/$arch_universal.app" + status=$? + + # Merge app bundles. + if [ -z "$merge_src" ] + then + # This is the first bundle, nothing to merge with. + merge_src="$arch_universal" + else + # Merge previous bundle with this one. + merge_dest="$merge_src+$arch_universal" + echo [-] Merging app bundles [$merge_src] and [$arch_universal] into [$merge_dest] + + # Merge directory structures. + (cd "archive_tmp_universal/$merge_src.app" && find . -type d && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type d && cd ../..) | sort > "$cache_dir/universal_listing.txt" + cat "$cache_dir/universal_listing.txt" | uniq | while IFS= read line + do + echo "> Directory: $line" + mkdir -p "archive_tmp_universal/$merge_dest.app/$line" + done + + # Create merged file listing. + (cd "archive_tmp_universal/$merge_src.app" && find . -type f && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type f && cd ../..) | sort > "$cache_dir/universal_listing.txt" + + # Copy files that only exist on one bundle. + cat "$cache_dir/universal_listing.txt" | uniq -u | while IFS= read line + do + if [ -e "archive_tmp_universal/$merge_src.app/$line" ] + then + file_src="$merge_src" + else + file_src="$arch_universal" + fi + echo "> Only on [$file_src]: $line" + cp -p "archive_tmp_universal/$file_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line" + done + + # Copy or lipo files that exist on both bundles. + cat "$cache_dir/universal_listing.txt" | uniq -d | while IFS= read line + do + if cmp -s "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$arch_universal.app/$line" + then + echo "> Identical: $line" + cp -p "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line" + elif lipo -create -output "archive_tmp_universal/$merge_dest.app/$line" "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$arch_universal.app/$line" 2> /dev/null + then + echo "> Merged: $line" + else + echo "> Copied from [$merge_src]: $line" + cp -p "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line" + fi + done + + # Merge symlinks. + (cd "archive_tmp_universal/$merge_src.app" && find . -type l && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type l && cd ../..) | sort > "$cache_dir/universal_listing.txt" + cat "$cache_dir/universal_listing.txt" | uniq | while IFS= read line + do + # Get symlink destinations. + other_link_dest= + if [ -e "archive_tmp_universal/$merge_src.app/$line" ] + then + file_src="$merge_src" + other_link_path="archive_tmp_universal/$arch_universal.app/$line" + if [ -L "$other_link_path" ] + then + other_link_dest="$(readlink "$other_link_path")" + elif [ -e "$other_link_path" ] + then + other_link_dest='[not a symlink]' + fi + else + file_src="$arch_universal" + fi + link_dest="$(readlink "archive_tmp_universal/$file_src.app/$line")" + + # Warn if destinations differ. + if [ -n "$other_link_dest" -a "$link_dest" != "$other_link_dest" ] + then + echo "> Symlink: $line => WARNING: different targets" + echo ">> Using: [$merge_src] $link_dest" + echo ">> Other: [$arch_universal] $other_link_dest" + else + echo "> Symlink: $line => $link_dest" + fi + ln -s "$link_dest" "archive_tmp_universal/$merge_dest.app/$line" + done + + # Merge a subsequent bundle with this one. + merge_src="$merge_dest" + fi + fi + + if [ $status -ne 0 ] + then + echo [!] Aborting universal build: [$arch_universal] failed with status [$status] + exit $status + fi + done + + # Rename final app bundle. + rm -rf archive_tmp + mkdir archive_tmp + mv "archive_tmp_universal/$merge_src.app" "$app_bundle_name" + + # Sign final app bundle. + arch -"$(uname -m)" codesign --force --deep -s - "$app_bundle_name" + + # Create zip. + echo [-] Creating artifact archive + cd archive_tmp + zip --symlinks -r "$cwd/$package_name.zip" . + status=$? + + # Check if the archival succeeded. + if [ $status -ne 0 ] + then + echo [!] Artifact archive creation failed with status [$status] + exit 7 + fi + + # All good. + echo [-] Universal build of [$package_name] for [$arch] with flags [$cmake_flags] successful + exit 0 + fi + + # Switch into the correct architecture if required. + case $arch in + x86_64) arch_mac="i386";; + *) arch_mac="$arch";; + esac + if [ "$(arch)" != "$arch" -a "$(arch)" != "$arch_mac" ] + then + # Call build with the correct architecture. + echo [-] Switching to architecture [$arch] + cd "$cwd" + args= + [ $strip -ne 0 ] && args="-t $args" + [ $skip_archive -ne 0 ] && args="-n $args" + arch -"$arch" zsh -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$args""$cmake_flags" + exit $? + fi + echo [-] Using architecture [$(arch)] + + # Locate the MacPorts prefix. + macports="/opt/local" + [ -e "/opt/$arch/bin/port" ] && macports="/opt/$arch" + [ "$arch" = "x86_64" -a -e "/opt/intel/bin/port" ] && macports="/opt/intel" + export PATH="$macports/bin:$macports/sbin:$macports/libexec/qt5/bin:$PATH" + + # Install dependencies only if we're in a new build and/or architecture. + if check_buildtag "$(arch)" + then + # Install dependencies. + echo [-] Installing dependencies through MacPorts + sudo "$macports/bin/port" selfupdate + sudo "$macports/bin/port" install $(cat .ci/dependencies_macports.txt) + + # Save build tag to skip this later. Doing it here (once everything is + # in place) is important to avoid potential issues with retried builds. + save_buildtag "$(arch)" + else + echo [-] Not installing dependencies again + + fi +else + # Determine Debian architecture. + case $arch in + x86) arch_deb="i386";; + x86_64) arch_deb="amd64";; + arm32) arch_deb="armhf";; + *) arch_deb="$arch";; + esac + + # Establish general dependencies. + pkgs="cmake ninja-build pkg-config git wget p7zip-full extra-cmake-modules wayland-protocols tar gzip file appstream" + if [ "$(dpkg --print-architecture)" = "$arch_deb" ] + then + pkgs="$pkgs build-essential" + else + # Add foreign architecture if required. + if ! dpkg --print-foreign-architectures | grep -qE '^'"$arch_deb"'$' + then + sudo dpkg --add-architecture "$arch_deb" + + # Force an apt-get update. + save_buildtag aptupdate "arch_$arch_deb" + fi + + pkgs="$pkgs crossbuild-essential-$arch_deb" + fi + + # Establish architecture-specific dependencies we don't want listed on the readme... + pkgs="$pkgs linux-libc-dev:$arch_deb qttools5-dev:$arch_deb qtbase5-private-dev:$arch_deb" + + # ...and the ones we do want listed. Non-dev packages fill missing spots on the list. + libpkgs="" + longest_libpkg=0 + for pkg in libc6-dev libstdc++6 libopenal-dev libfreetype6-dev libx11-dev libsdl2-dev libpng-dev librtmidi-dev qtdeclarative5-dev libwayland-dev libevdev-dev libglib2.0-dev libslirp-dev libfaudio-dev libaudio-dev libjack-jackd2-dev libpipewire-0.3-dev libsamplerate0-dev libsndio-dev + do + libpkgs="$libpkgs $pkg:$arch_deb" + length=$(echo -n $pkg | sed 's/-dev$//' | sed "s/qtdeclarative/qt/" | wc -c) + [ $length -gt $longest_libpkg ] && longest_libpkg=$length + done + + # Determine toolchain architecture triplet. + case $arch in + x86) arch_triplet="i686-linux-gnu";; + arm32) arch_triplet="arm-linux-gnueabihf";; + arm64) arch_triplet="aarch64-linux-gnu";; + *) arch_triplet="$arch-linux-gnu";; + esac + + # Determine library directory name for this architecture. + case $arch in + x86) libdir="i386-linux-gnu";; + *) libdir="$arch_triplet";; + esac + + # Create CMake cross toolchain file. The file is saved on a fixed location for + # the library builds we do later, since running CMake again on a library we've + # already built before will *not* update its toolchain file path; therefore, we + # cannot point them to our working directory, which may change across builds. + toolchain_file_new="$cache_dir/toolchain.$arch_deb.cmake" + cat << EOF > "$toolchain_file_new" +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR $arch) + +set(CMAKE_AR $arch_triplet-ar) +set(CMAKE_ASM_COMPILER $arch_triplet-gcc) +set(CMAKE_C_COMPILER $arch_triplet-gcc) +set(CMAKE_CXX_COMPILER $arch_triplet-g++) +set(CMAKE_LINKER $arch_triplet-ld) +set(CMAKE_OBJCOPY $arch_triplet-objcopy) +set(CMAKE_RANLIB $arch_triplet-ranlib) +set(CMAKE_SIZE $arch_triplet-size) +set(CMAKE_STRIP $arch_triplet-strip) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(ENV{PKG_CONFIG_PATH} "") +set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig") + +include("$(realpath "$toolchain_file")") +EOF + toolchain_file="$toolchain_file_new" + strip_binary="$arch_triplet-strip" + + # Install dependencies only if we're in a new build and/or architecture. + if check_buildtag "$arch_deb" + then + # Install or update dependencies. + echo [-] Installing dependencies through apt + if check_buildtag aptupdate + then + sudo apt-get update + + # Save build tag to skip apt-get update later, unless a new architecture + # is added to dpkg, in which case, this saved tag file gets replaced. + save_buildtag aptupdate + fi + DEBIAN_FRONTEND=noninteractive sudo apt-get -y install $pkgs $libpkgs + sudo apt-get clean + + # Save build tag to skip this later. Doing it here (once everything is + # in place) is important to avoid potential issues with retried builds. + save_buildtag "$arch_deb" + else + echo [-] Not installing dependencies again + fi + + # Link against the system libslirp instead of compiling ours. + cmake_flags_extra="$cmake_flags_extra -D SLIRP_EXTERNAL=ON" +fi + +# Point CMake to the toolchain file. +[ -e "$toolchain_file" ] && cmake_flags_extra="$cmake_flags_extra -D \"CMAKE_TOOLCHAIN_FILE=$toolchain_file\"" + +# Clean workspace. +echo [-] Cleaning workspace +rm -rf build + +# Add ARCH to skip the arch_detect process. +case $arch in + 32 | x86) cmake_flags_extra="$cmake_flags_extra -D ARCH=i386";; + 64 | x86_64) cmake_flags_extra="$cmake_flags_extra -D ARCH=x86_64";; + ARM32 | arm32) cmake_flags_extra="$cmake_flags_extra -D ARCH=arm";; + ARM64 | arm64) cmake_flags_extra="$cmake_flags_extra -D ARCH=arm64";; + *) cmake_flags_extra="$cmake_flags_extra -D \"ARCH=$arch\"";; +esac + +# Add git hash. +git_hash=$(git rev-parse --short HEAD 2> /dev/null) +if [ "$CI" = "true" ] +then + # Backup strategy when running under Jenkins. + [ -z "$git_hash" ] && git_hash=$(echo $GIT_COMMIT | cut -c 1-8) +elif [ -n "$git_hash" ] +then + # Append + to denote a dirty tree. + git diff --quiet 2> /dev/null || git_hash="$git_hash+" +fi +[ -n "$git_hash" ] && cmake_flags_extra="$cmake_flags_extra -D \"EMU_GIT_HASH=$git_hash\"" + +# Add copyright year. +year=$(date +%Y) +[ -n "$year" ] && cmake_flags_extra="$cmake_flags_extra -D \"EMU_COPYRIGHT_YEAR=$year\"" + +# Run CMake. +echo [-] Running CMake with flags [$cmake_flags $cmake_flags_extra] +eval cmake -G Ninja $cmake_flags $cmake_flags_extra -S . -B build +status=$? +if [ $status -ne 0 ] +then + echo [!] CMake failed with status [$status] + exit 3 +fi + +# Run actual build, unless we're running a dry build to precondition a node. +if [ "$BUILD_TAG" != "precondition" ] +then + echo [-] Running build + cmake --build build -j$(nproc) + status=$? + if [ $status -ne 0 ] + then + echo [!] Build failed with status [$status] + exit 4 + fi +else + # Copy dummy binary into place. + echo [-] Preconditioning build node + mkdir -p build/src + if is_windows + then + cp "$(which cp)" "build/src/$project.exe" + elif is_mac + then + : # Special check during app bundle generation. + else + cp "$(which cp)" "build/src/$project" + fi +fi + +# Download Discord Game SDK from their CDN if we're in a new build. +discord_version="3.2.1" +discord_zip="$cache_dir/discord_game_sdk-$discord_version.zip" +if [ ! -e "$discord_zip" ] +then + # Download file. + echo [-] Downloading Discord Game SDK + rm -f "$cache_dir/discord_game_sdk"* # remove old versions + wget -qO "$discord_zip" "https://dl-game-sdk.discordapp.net/$discord_version/discord_game_sdk.zip" + status=$? + if [ $status -ne 0 ] + then + echo [!] Discord Game SDK download failed with status [$status] + rm -f "$discord_zip" + fi +else + echo [-] Not downloading Discord Game SDK again +fi + +# Determine Discord Game SDK architecture. +case $arch in + 32) arch_discord="x86";; + 64) arch_discord="x86_64";; + arm64 | ARM64) arch_discord="aarch64";; + *) arch_discord="$arch";; +esac + +# Create temporary directory for archival. +echo [-] Gathering archive files +rm -rf archive_tmp +mkdir archive_tmp +if [ ! -d "archive_tmp" ] +then + echo [!] Archive directory creation failed + exit 5 +fi + +# Archive the executable and its dependencies. +# The executable should always be archived last for the check after this block. +status=0 +if is_windows +then + # Determine Program Files directory for Ghostscript and 7-Zip. + # Manual checks because MSYS is bad at passing the ProgramFiles variables. + pf="/c/Program Files" + sevenzip="$pf/7-Zip/7z.exe" + [ "$arch" = "32" -a -d "/c/Program Files (x86)" ] && pf="/c/Program Files (x86)" + + # Archive freetype from cache or generate it from local MSYS installation. + [ ! -e "$freetype_dll" ] && .ci/static2dll.sh -p freetype2 /$MSYSTEM/lib/libfreetype.a "$freetype_dll" + cp -p "$freetype_dll" archive_tmp/freetype.dll + + # Archive Ghostscript DLL from local official distribution installation. + for gs in "$pf"/gs/gs*.*.* + do + cp -p "$gs"/bin/gsdll*.dll archive_tmp/ + done + + # Archive Discord Game SDK DLL. + "$sevenzip" e -y -o"archive_tmp" "$discord_zip" "lib/$arch_discord/discord_game_sdk.dll" + [ ! -e "archive_tmp/discord_game_sdk.dll" ] && echo [!] No Discord Game SDK for architecture [$arch_discord] + + # Archive other DLLs from local directory. + cp -p "/home/$project/dll$arch/"* archive_tmp/ + + # Archive executable, while also stripping it if requested. + if [ $strip -ne 0 ] + then + "$strip_binary" -o "archive_tmp/$project.exe" "build/src/$project.exe" + status=$? + else + mv "build/src/$project.exe" "archive_tmp/$project.exe" + status=$? + fi +elif is_mac +then + # Archive app bundle with libraries. + cmake_flags_install= + [ $strip -ne 0 ] && cmake_flags_install="$cmake_flags_install --strip" + cmake --install build --prefix "$(pwd)/archive_tmp" $cmake_flags_install + status=$? + + if [ $status -eq 0 ] + then + # Archive Discord Game SDK library. + unzip -j "$discord_zip" "lib/$arch_discord/discord_game_sdk.dylib" -d "archive_tmp/"*".app/Contents/Frameworks" + [ ! -e "archive_tmp/"*".app/Contents/Frameworks/discord_game_sdk.dylib" ] && echo [!] No Discord Game SDK for architecture [$arch_discord] + + # Sign app bundle, unless we're in an universal build. + [ $skip_archive -eq 0 ] && codesign --force --deep -s - "archive_tmp/"*".app" + elif [ "$BUILD_TAG" = "precondition" ] + then + # Continue with no app bundle on a dry build. + status=0 + fi +else + cwd_root="$(pwd)" + check_buildtag "libs.$arch_deb" + + if grep -q "OPENAL:BOOL=ON" build/CMakeCache.txt + then + # Build openal-soft 1.21.1 manually to fix audio issues. This is a temporary + # workaround until a newer version of openal-soft trickles down to Debian repos. + prefix="$cache_dir/openal-soft-1.21.1" + if [ ! -d "$prefix" ] + then + rm -rf "$cache_dir/openal-soft-"* # remove old versions + wget -qO - https://github.com/kcat/openal-soft/archive/refs/tags/1.21.1.tar.gz | tar zxf - -C "$cache_dir" || rm -rf "$prefix" + fi + prefix_build="$prefix/build-$arch_deb" + cmake -G Ninja -D "CMAKE_TOOLCHAIN_FILE=$toolchain_file" -D "CMAKE_INSTALL_PREFIX=$cwd_root/archive_tmp/usr" -S "$prefix" -B "$prefix_build" || exit 99 + cmake --build "$prefix_build" -j$(nproc) || exit 99 + cmake --install "$prefix_build" || exit 99 + + # Build SDL2 without sound systems. + sdl_ss=OFF + else + # Build FAudio 22.03 manually to remove the dependency on GStreamer. This is a temporary + # workaround until a newer version of FAudio trickles down to Debian repos. + prefix="$cache_dir/FAudio-22.03" + if [ ! -d "$prefix" ] + then + rm -rf "$cache_dir/FAudio-"* # remove old versions + wget -qO - https://github.com/FNA-XNA/FAudio/archive/refs/tags/22.03.tar.gz | tar zxf - -C "$cache_dir" || rm -rf "$prefix" + fi + prefix_build="$prefix/build-$arch_deb" + cmake -G Ninja -D "CMAKE_TOOLCHAIN_FILE=$toolchain_file" -D "CMAKE_INSTALL_PREFIX=$cwd_root/archive_tmp/usr" -S "$prefix" -B "$prefix_build" || exit 99 + cmake --build "$prefix_build" -j$(nproc) || exit 99 + cmake --install "$prefix_build" || exit 99 + + # Build SDL2 with sound systems. + sdl_ss=ON + fi + + # Build SDL2 with video systems (and some dependencies) only if the SDL interface is used. + sdl_ui=OFF + grep -qiE "^QT:BOOL=ON" build/CMakeCache.txt || sdl_ui=ON + + # Build rtmidi without JACK support to remove the dependency on libjack. + prefix="$cache_dir/rtmidi-4.0.0" + if [ ! -d "$prefix" ] + then + rm -rf "$cache_dir/rtmidi-"* # remove old versions + wget -qO - https://github.com/thestk/rtmidi/archive/refs/tags/4.0.0.tar.gz | tar zxf - -C "$cache_dir" || rm -rf "$prefix" + fi + prefix_build="$prefix/build-$arch_deb" + cmake -G Ninja -D RTMIDI_API_JACK=OFF -D "CMAKE_TOOLCHAIN_FILE=$toolchain_file" -D "CMAKE_INSTALL_PREFIX=$cwd_root/archive_tmp/usr" -S "$prefix" -B "$prefix_build" || exit 99 + cmake --build "$prefix_build" -j$(nproc) || exit 99 + cmake --install "$prefix_build" || exit 99 + + # Build SDL2 for joystick and FAudio support, with most components + # disabled to remove the dependencies on PulseAudio and libdrm. + prefix="$cache_dir/SDL2-2.0.20" + if [ ! -d "$prefix" ] + then + rm -rf "$cache_dir/SDL2-"* # remove old versions + wget -qO - https://www.libsdl.org/release/SDL2-2.0.20.tar.gz | tar zxf - -C "$cache_dir" || rm -rf "$prefix" + fi + prefix_build="$cache_dir/SDL2-2.0.20-build-$arch_deb" + cmake -G Ninja -D SDL_SHARED=ON -D SDL_STATIC=OFF \ + \ + -D SDL_AUDIO=$sdl_ss -D SDL_DUMMYAUDIO=$sdl_ss -D SDL_DISKAUDIO=OFF -D SDL_OSS=OFF -D SDL_ALSA=$sdl_ss -D SDL_ALSA_SHARED=$sdl_ss \ + -D SDL_JACK=$sdl_ss -D SDL_JACK_SHARED=$sdl_ss -D SDL_ESD=OFF -D SDL_ESD_SHARED=OFF -D SDL_PIPEWIRE=$sdl_ss \ + -D SDL_PIPEWIRE_SHARED=$sdl_ss -D SDL_PULSEAUDIO=$sdl_ss -D SDL_PULSEAUDIO_SHARED=$sdl_ss -D SDL_ARTS=OFF -D SDL_ARTS_SHARED=OFF \ + -D SDL_NAS=$sdl_ss -D SDL_NAS_SHARED=$sdl_ss -D SDL_SNDIO=$sdl_ss -D SDL_SNDIO_SHARED=$sdl_ss -D SDL_FUSIONSOUND=OFF \ + -D SDL_FUSIONSOUND_SHARED=OFF -D SDL_LIBSAMPLERATE=$sdl_ss -D SDL_LIBSAMPLERATE_SHARED=$sdl_ss \ + \ + -D SDL_VIDEO=$sdl_ui -D SDL_X11=$sdl_ui -D SDL_X11_SHARED=$sdl_ui -D SDL_WAYLAND=$sdl_ui -D SDL_WAYLAND_SHARED=$sdl_ui \ + -D SDL_WAYLAND_LIBDECOR=$sdl_ui -D SDL_WAYLAND_LIBDECOR_SHARED=$sdl_ui -D SDL_WAYLAND_QT_TOUCH=OFF -D SDL_RPI=OFF -D SDL_VIVANTE=OFF \ + -D SDL_VULKAN=OFF -D SDL_KMSDRM=$sdl_ui -D SDL_KMSDRM_SHARED=$sdl_ui -D SDL_OFFSCREEN=$sdl_ui -D SDL_RENDER=$sdl_ui \ + \ + -D SDL_JOYSTICK=ON -D SDL_HIDAPI_JOYSTICK=ON -D SDL_VIRTUAL_JOYSTICK=ON \ + \ + -D SDL_ATOMIC=OFF -D SDL_EVENTS=ON -D SDL_HAPTIC=OFF -D SDL_POWER=OFF -D SDL_THREADS=ON -D SDL_TIMERS=ON -D SDL_FILE=OFF \ + -D SDL_LOADSO=ON -D SDL_CPUINFO=ON -D SDL_FILESYSTEM=$sdl_ui -D SDL_DLOPEN=OFF -D SDL_SENSOR=OFF -D SDL_LOCALE=OFF \ + \ + -D "CMAKE_TOOLCHAIN_FILE=$toolchain_file" -D "CMAKE_INSTALL_PREFIX=$cwd_root/archive_tmp/usr" \ + -S "$prefix" -B "$prefix_build" || exit 99 + cmake --build "$prefix_build" -j$(nproc) || exit 99 + cmake --install "$prefix_build" || exit 99 + + # Archive Discord Game SDK library. + 7z e -y -o"archive_tmp/usr/lib" "$discord_zip" "lib/$arch_discord/discord_game_sdk.so" + [ ! -e "archive_tmp/usr/lib/discord_game_sdk.so" ] && echo [!] No Discord Game SDK for architecture [$arch_discord] + + # Archive readme with library package versions. + echo Libraries used to compile this $arch build of $project: > archive_tmp/README + dpkg-query -f '${Package} ${Version}\n' -W $libpkgs | sed "s/-dev / /" | sed "s/qtdeclarative/qt/" | while IFS=" " read pkg version + do + for i in $(seq $(expr $longest_libpkg - $(echo -n $pkg | wc -c))) + do + echo -n " " >> archive_tmp/README + done + echo $pkg $version >> archive_tmp/README + done + + # Archive metadata. + project_id=$(ls src/unix/assets/*.*.xml | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+\.[^\.]+$)') + metainfo_base=archive_tmp/usr/share/metainfo + mkdir -p "$metainfo_base" + cp -p "src/unix/assets/$project_id."*".xml" "$metainfo_base/$project_id.appdata.xml" + + # Archive icons. + icon_base=archive_tmp/usr/share/icons + mkdir -p "$icon_base" + cp -rp src/unix/assets/[0-9]*x[0-9]* "$icon_base/" + project_icon=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') + + # Archive executable, while also stripping it if requested. + mkdir -p archive_tmp/usr/local/bin + if [ $strip -ne 0 ] + then + "$strip_binary" -o "archive_tmp/usr/local/bin/$project" "build/src/$project" + status=$? + else + mv "build/src/$project" "archive_tmp/usr/local/bin/$project" + status=$? + fi +fi + +# Check if the executable strip/move succeeded. +if [ $status -ne 0 ] +then + echo [!] Executable strip/move failed with status [$status] + exit 6 +fi + +# Stop if artifact archive creation was disabled. +if [ $skip_archive -ne 0 ] +then + echo [-] Skipping artifact archive creation + exit 0 +fi + +# Produce artifact archive. +echo [-] Creating artifact archive +if is_windows +then + # Create zip. + cd archive_tmp + "$sevenzip" a -y "$(cygpath -w "$cwd")\\$package_name.zip" * + status=$? +elif is_mac +then + # Create zip. + cd archive_tmp + zip --symlinks -r "$cwd/$package_name.zip" . + status=$? +else + # Determine AppImage runtime architecture. + case $arch in + x86) arch_appimage="i686";; + arm32) arch_appimage="armhf";; + arm64) arch_appimage="aarch64";; + *) arch_appimage="$arch";; + esac + + # Get version for AppImage metadata. + project_version=$(grep -oP '#define\s+EMU_VERSION\s+"\K([^"]+)' "build/src/include/"*"/version.h" 2> /dev/null) + [ -z "$project_version" ] && project_version=unknown + build_num=$(grep -oP '#define\s+EMU_BUILD_NUM\s+\K([0-9]+)' "build/src/include/"*"/version.h" 2> /dev/null) + [ -n "$build_num" -a "$build_num" != "0" ] && project_version="$project_version-b$build_num" + + # Generate modified AppImage metadata to suit build requirements. + cat << EOF > AppImageBuilder-generated.yml +# This file is generated automatically by .ci/build.sh and will be +# overwritten if edited. Please edit .ci/AppImageBuilder.yml instead. +EOF + while IFS= read line + do + # Skip blank or comment lines. + echo "$line" | grep -qE '^(#|$)' && continue + + # Parse "# if OPTION VALUE" condition lines. + condition=$(echo "$line" | grep -oP '# if \K(.+)') + if [ -n "$condition" ] + then + # Skip line if the condition is not matched. + grep -qiE "^$condition" build/CMakeCache.txt || continue + fi + + # Copy line. + echo "$line" >> AppImageBuilder-generated.yml + done < .ci/AppImageBuilder.yml + + # Download appimage-builder if necessary. + appimage_builder_url="https://github.com/AppImageCrafters/appimage-builder/releases/download/v0.9.2/appimage-builder-0.9.2-35e3eab-x86_64.AppImage" + appimage_builder_binary="$cache_dir/$(basename "$appimage_builder_url")" + if [ ! -e "$appimage_builder_binary" ] + then + rm -rf "$cache_dir/"*".AppImage" # remove old versions + wget -qO "$appimage_builder_binary" "$appimage_builder_url" + fi + + # Symlink appimage-builder binary and 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. + project="$project" project_id="$project_id" project_version="$project_version" project_icon="$project_icon" arch_deb="$arch_deb" \ + arch_appimage="$arch_appimage" APPIMAGE_EXTRACT_AND_RUN=1 ./appimage-builder.AppImage --recipe AppImageBuilder-generated.yml + status=$? + + # Rename AppImage to the final name if the build succeeded. + if [ $status -eq 0 ] + then + mv "$project-"*".AppImage" "$cwd/$package_name.AppImage" + status=$? + else + # Remove appimage-builder binary just in case it's corrupted. + rm -f "$appimage_builder_binary" + fi +fi + +# Check if the archival succeeded. +if [ $status -ne 0 ] +then + echo [!] Artifact archive creation failed with status [$status] + exit 7 +fi + +# All good. +echo [-] Build of [$package_name] for [$arch] with flags [$cmake_flags] successful +exit 0 diff --git a/.ci/dependencies_macports.txt b/.ci/dependencies_macports.txt new file mode 100644 index 000000000..88270b4da --- /dev/null +++ b/.ci/dependencies_macports.txt @@ -0,0 +1,10 @@ +cmake +pkgconfig +ninja +freetype +libsdl2 +libpng +FAudio +rtmidi +qt5 +wget diff --git a/.ci/dependencies_msys.txt b/.ci/dependencies_msys.txt new file mode 100644 index 000000000..35e3506fd --- /dev/null +++ b/.ci/dependencies_msys.txt @@ -0,0 +1,24 @@ +zlib 1.2.11-9 +binutils 2.37-4 +headers-git 9.0.0.6357.eac8c38c1-1 +crt-git 9.0.0.6357.eac8c38c1-2 +libwinpthread-git 9.0.0.6357.eac8c38c1-1 +winpthreads-git 9.0.0.6357.eac8c38c1-1 +winstorecompat-git 9.0.0.6357.eac8c38c1-1 +gcc-libs 11.2.0-4 +gcc-ada 11.2.0-4 +gcc-fortran 11.2.0-4 +gcc-libgfortran 11.2.0-4 +gcc-objc 11.2.0-4 +gcc 11.2.0-4 +libgccjit 11.2.0-4 +tools-git 9.0.0.6357.eac8c38c1-1 +ninja 1.10.2-3 +pkgconf 1.8.0-2 +openal 1.21.1-3 +libpng 1.6.37-6 +freetype 2.11.1-1 +SDL2 2.0.18-2 +rtmidi 4.0.0-1 +cmake 3.22.1-1 +qt5-static 5.15.2-4 diff --git a/.ci/static2dll.sh b/.ci/static2dll.sh new file mode 100644 index 000000000..f6e5b63b9 --- /dev/null +++ b/.ci/static2dll.sh @@ -0,0 +1,160 @@ +#!/bin/sh +# +# 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. +# +# Script for converting MinGW static libraries into a DLL. +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +def_file="static2dll.def" +seen_file="static2dll.seen" +libs_file="static2dll.libs" + +find_lib() { + # Try to find a static library's file. + local msystem_lib="/$(echo $MSYSTEM | tr '[:upper:]' '[:lower:]')/lib/lib" + if [ -e "$msystem_lib$1.a" ] + then + echo "$msystem_lib$1.a" + elif [ -e "$msystem_lib$1.dll.a" ] + then + echo "$msystem_lib$1.dll.a" + else + # Return dynamic reference to the library. + echo "-l$1" + return 1 + fi +} + +add_lib() { + # Always make sure this lib is listed after the last lib that depends on it. + old_libs=$(cat "$libs_file") + rm -f "$libs_file" + for lib in $old_libs + do + [ "$lib" != "$*" ] && echo "$lib" >> "$libs_file" + done + echo "$*" >> "$libs_file" + + # Add libstdc++ in the end if required. + if echo "$*" | grep -q "/" + then + grep -Eq -- "__cxa_|__gxx_" "$1" 2> /dev/null && add_lib -static -lstdc++ + fi + + # Add libiconv for libintl. + if echo "$*" | grep -q "libintl" + then + add_lib $(find_lib iconv) + fi + + # Add libuuid for glib. + if echo "$*" | grep -q "libglib" + then + add_lib $(find_lib uuid) + fi +} + +run_pkgconfig() { + local cache_file="static2dll.$1.cache" + if [ -e "$cache_file" ] + then + cat "$cache_file" + else + pkg-config --static --libs "$1" 2> /dev/null | tee "$cache_file" + fi +} + +parse_pkgconfig() { + # Parse arguments. + local layers=$1 + shift + local input_lib_name=$1 + shift + + # Don't process the same file again. + grep -q '^'$input_lib_name'$' "$seen_file" && return + echo $input_lib_name >> "$seen_file" + + echo "$layers" parse_pkgconfig $input_lib_name + + # Parse pkg-config arguments. + for arg in $* + do + local arg_base="$(echo $arg | cut -c1-2)" + if [ "x$arg_base" = "x-l" ] + then + # Don't process the same lib again. + local lib_name="$(echo $arg | cut -c3-)" + [ "x$lib_name" == "x$input_lib_name" ] && continue + + # Add lib path. + add_lib "$(find_lib $lib_name)" + + # Get this lib's dependencies through pkg-config. + local pkgconfig="$(run_pkgconfig "$lib_name")" + [ $? -eq 0 ] && parse_pkgconfig "$layers"'>' "$lib_name" $pkgconfig || echo $lib_name >> "$seen_file" + elif [ "x$(echo $arg_base | cut -c1)" = "x-" ] + then + # Ignore other arguments. + continue + else + # Add lib path. + add_lib "$arg" + fi + done +} + +# Parse arguments. +case $1 in + -p) # -p pkg_config_name static_lib_path out_dll + shift + base_pkgconfig=$(run_pkgconfig "$1") + base_path="$2" + base_name="$1" + ;; + + *) # pc_path static_lib_path out_dll + base_pkgconfig="$(grep ^Libs.private: $1 | cut -d: -f2-)" + base_path="$2" + base_name="$2" + ;; +esac + +# Check arguments. +if [ -z "$base_pkgconfig" -o -z "$base_path" -o -z "$base_name" ] +then + echo Usage: + echo static2dll.sh -p {pkgconfig_package_name} {static_lib_path} {out_dll_name} + echo static2dll.sh {pc_file_path} {static_lib_path} {out_dll_name} + exit 1 +fi + +# Produce .def file. +echo LIBRARY $(basename "$3") > "$def_file" +echo EXPORTS >> "$def_file" +nm "$base_path" | grep " [TC] " | sed "/ _/s// /" | awk '{ print $3 }' >> "$def_file" + +# Parse dependencies recursively. +rm -f "$seen_file" "$libs_file" "$libs_file.tmp" +touch "$seen_file" "$libs_file" +parse_pkgconfig '>' $base_name $base_pkgconfig + +# Produce final DLL. +dllwrap --def "$def_file" -o "$3" -Wl,--allow-multiple-definition "$base_path" $(cat "$libs_file") +status=$? +[ $status -eq 0 ] && rm -f "$def_file" "$seen_file" "$libs_file" "static2dll.*.cache" + +# Update final DLL timestamp. +touch -r "$base_path" "$3" + +exit $status diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..7e38e8e4b --- /dev/null +++ b/.clang-format @@ -0,0 +1,18 @@ +BasedOnStyle: WebKit +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Left +AlignConsecutiveMacros: AcrossEmptyLines +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveBitFields: AcrossEmptyLines +AlignConsecutiveDeclarations: Consecutive +AlignEscapedNewlines: Left +AlignTrailingComments: true +AlwaysBreakAfterReturnType: TopLevelDefinitions +BreakBeforeTernaryOperators: true +IndentCaseLabels: true +IndentCaseBlocks: true +IndentGotoLabels: false +IndentPPDirectives: AfterHash +IndentExternBlock: NoIndent +PointerAlignment: Right +SpaceAfterCStyleCast: true diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..29d9ac0ba --- /dev/null +++ b/.editorconfig @@ -0,0 +1,38 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +tab_width = 4 + +# Disabled for now since not all editors support setting a tab_width value different from indent_size +# Relevant VSCode extension issue: https://github.com/editorconfig/editorconfig-vscode/issues/190 +# [*.rc] +# indent_style = space +# indent_size = 4 +# tab_width = 4 + +# [Makefile.*] +# indent_style = space +# indent_size = 4 +# tab_width = 4 + +[*.manifest] +indent_style = space +indent_size = 2 + +[*.yml] +indent_style = space +indent_size = 2 + +[**/CMakeLists.txt] +indent_style = space +indent_size = 4 + +[*.cmake] +indent_style = space +indent_size = 4 + +[*.json] +indent_style = space +indent_size = 4 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0e3472957..340d89500 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -25,8 +25,8 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. Windows 10] - - Version [e.g. v2.06 build 2007] - - Build type [i.e. regular, optimized, or dev] + - 86Box version: [e.g. v3.00 build 3333; saying "Latest from Jenkins" isn't helpful] + - Build information: [i.e. new/old dynarec, architecture and build type] **Additional context** Add any other context about the problem here. If you are using an Optimized build, make sure to try the regular build too before filing a bug report! diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e5cd315d1..cc1ec7f8e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,5 @@ +blank_issues_enabled: false contact_links: - name: Question - url: https://discord.gg/QXK9XTv + url: https://github.com/86Box/86Box/discussions about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index e301d68ce..4fe86d5ec 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: '' -labels: feature request +labels: feature assignees: '' --- diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 000000000..3a15916d4 --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1,2 @@ +patreon: 86box +custom: ["https://paypal.me/86Box"] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..e09b5636f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,14 @@ +Summary +======= +_Briefly describe what you are submitting._ + +Checklist +========= +* [ ] Closes #xxx +* [ ] I have discussed this with core contributors already +* [ ] This pull request requires changes to the ROM set + * [ ] I have opened a roms pull request - https://github.com/86Box/roms/pull/changeme/ + +References +========== +_Provide links to datasheets or other documentation that helped you implement this pull request._ diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 000000000..6d13f5b72 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,58 @@ +name: MinGW64 Makefile + +on: + + push: + paths: + - src/** + - .github/workflows/c-cpp.yml + - "!**/CMakeLists.txt" + + pull_request: + paths: + - src/** + - .github/workflows/c-cpp.yml + - "!**/CMakeLists.txt" + +jobs: + build: + name: ${{ matrix.environment.msystem }} Makefile build (DEV_BUILD=${{ matrix.dev-build }}, NEW_DYNAREC=${{ matrix.new-dynarec }}) + + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + strategy: + fail-fast: true + matrix: + dev-build: ['y', 'n'] + new-dynarec: ['y', 'n'] + environment: + - msystem: MINGW32 + prefix: mingw-w64-i686 + x64: n + - msystem: MINGW64 + prefix: mingw-w64-x86_64 + x64: y + + steps: + - uses: msys2/setup-msys2@v2 + with: + update: true + msystem: ${{ matrix.environment.msystem }} + install: >- + make + ${{ matrix.environment.prefix }}-gcc + ${{ matrix.environment.prefix }}-pkg-config + ${{ matrix.environment.prefix }}-freetype + ${{ matrix.environment.prefix }}-SDL2 + ${{ matrix.environment.prefix }}-zlib + ${{ matrix.environment.prefix }}-libpng + ${{ matrix.environment.prefix }}-libvncserver + ${{ matrix.environment.prefix }}-rtmidi + - uses: actions/checkout@v2 + - name: make + run: make -fwin/makefile.mingw -j DEV_BUILD=${{ matrix.dev-build }} NEW_DYNAREC=${{ matrix.new-dynarec }} X64=${{ matrix.environment.x64 }} VNC=n + working-directory: ./src diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 000000000..a1b9b4d5b --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,291 @@ +name: CMake + +on: + + push: + paths: + - src/** + - cmake/** + - "**/CMakeLists.txt" + - "CMakePresets.json" + - .github/workflows/cmake.yml + - vcpkg.json + - "!**/Makefile*" + + pull_request: + paths: + - src/** + - cmake/** + - "**/CMakeLists.txt" + - "CMakePresets.json" + - .github/workflows/** + - .github/workflows/cmake.yml + - vcpkg.json + - "!**/Makefile*" + +jobs: + msys2: + name: MSYS2 ${{ matrix.build.name }} ${{ matrix.dynarec.name }} build (${{ matrix.environment.msystem }}) + + runs-on: windows-2022 + + defaults: + run: + shell: msys2 {0} + + strategy: + fail-fast: true + matrix: + build: + - name: Debug + preset: debug + slug: -Debug + - name: Dev + preset: experimental + slug: -Dev + dynarec: + - name: ODR + new: off + slug: -ODR + - name: NDR + new: on + slug: -NDR + environment: + - msystem: MINGW32 + prefix: mingw-w64-i686 + toolchain: ./cmake/flags-gcc-i686.cmake + - msystem: MINGW64 + prefix: mingw-w64-x86_64 + toolchain: ./cmake/flags-gcc-x86_64.cmake + - msystem: UCRT64 + prefix: mingw-w64-ucrt-x86_64 + toolchain: ./cmake/flags-gcc-x86_64.cmake + + steps: + - uses: msys2/setup-msys2@v2 + with: + path-type: inherit + update: true + msystem: ${{ matrix.environment.msystem }} + install: >- + ${{ matrix.environment.prefix }}-ninja + ${{ matrix.environment.prefix }}-cc + ${{ matrix.environment.prefix }}-pkg-config + ${{ matrix.environment.prefix }}-freetype + ${{ matrix.environment.prefix }}-SDL2 + ${{ matrix.environment.prefix }}-zlib + ${{ matrix.environment.prefix }}-libpng + ${{ matrix.environment.prefix }}-libvncserver + ${{ matrix.environment.prefix }}-openal + ${{ matrix.environment.prefix }}-rtmidi + - uses: actions/checkout@v2 + - name: Configure CMake + run: >- + cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} + --toolchain ${{ matrix.environment.toolchain }} + -D NEW_DYNAREC=${{ matrix.dynarec.new }} + -D CMAKE_INSTALL_PREFIX=./build/artifacts + -D QT=OFF + - name: Build + run: cmake --build build + - name: Generate package + run: cmake --install build + - uses: actions/upload-artifact@v2 + with: + name: '86Box${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-Windows-${{ matrix.environment.msystem }}-gha${{ github.run_number }}' + path: build/artifacts/** + + llvm-windows: + name: "Windows vcpkg/LLVM (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.target.name }})" + + runs-on: windows-2022 + + env: + VCPKG_BINARY_SOURCES: 'clear;nuget,GitHub,readwrite' + + strategy: + fail-fast: true + matrix: + build: + - name: Debug + preset: debug + slug: -Debug + - name: Dev + preset: experimental + slug: -Dev + dynarec: + - name: ODR + new: off + slug: -ODR + - name: NDR + new: on + slug: -NDR + ui: + - name: Win32 GUI + qt: off + - name: Qt GUI + qt: on + slug: -Qt + target: + - name: x86 + triplet: x86-windows-static + toolchain: cmake/llvm-win32-i686.cmake + vcvars: x64_x86 + - name: x64 + triplet: x64-windows-static + toolchain: cmake/llvm-win32-x86_64.cmake + vcvars: x64 + - name: ARM64 + triplet: arm64-windows-static + toolchain: cmake/llvm-win32-aarch64.cmake + vcvars: x64_arm64 + exclude: + - dynarec: + new: off + target: + name: ARM64 + + steps: + - uses: actions/checkout@v2 + - name: Prepare VS environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.target.vcvars }} + - name: Add LLVM to path + run: echo "C:/Program Files/LLVM/bin" >> $env:GITHUB_PATH + - name: Download Ninja + run: > + Invoke-WebRequest https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-win.zip -OutFile ninja-win.zip && + Expand-Archive ninja-win.zip -DestinationPath . + - name: Setup NuGet Credentials + run: > + & (C:/vcpkg/vcpkg fetch nuget | tail -n 2) + sources add + -source "https://nuget.pkg.github.com/86Box/index.json" + -storepasswordincleartext + -name "GitHub" + -username "86Box" + -password "${{ secrets.GITHUB_TOKEN }}" + - name: Fix MSVC atomic headers + run: dir "C:/Program Files/Microsoft Visual Studio/2022/*/VC/Tools/MSVC/*/include" -include stdatomic.h -recurse | del + - name: Configure CMake + run: > + cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} + --toolchain C:/vcpkg/scripts/buildsystems/vcpkg.cmake + -D NEW_DYNAREC=${{ matrix.dynarec.new }} -D QT=${{ matrix.ui.qt }} + -D VCPKG_CHAINLOAD_TOOLCHAIN_FILE=${{ github.workspace }}/${{ matrix.target.toolchain }} + -D VCPKG_TARGET_TRIPLET=${{ matrix.target.triplet }} + -D VCPKG_HOST_TRIPLET=x64-windows + -D VCPKG_USE_HOST_TOOLS=ON + - name: Fix Qt + if: matrix.ui.qt == 'on' + run: | + $qtTargetsPath = "${{ github.workspace }}/build/vcpkg_installed/${{ matrix.target.triplet }}/share/Qt6/Qt6Targets.cmake" + (Get-Content $qtTargetsPath) -replace "^.*-Zc:__cplusplus;-permissive-.*$","#$&" | Set-Content $qtTargetsPath + - name: Reconfigure CMake + if: matrix.ui.qt == 'on' + run: cmake clean build + - name: Build + run: cmake --build build + - name: Generate package + run: cmake --install build --prefix ./build/artifacts + - uses: actions/upload-artifact@v2 + with: + name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-Windows-LLVM-${{ matrix.target.name }}-gha${{ github.run_number }}' + path: build/artifacts/** + + linux: + name: "Linux GCC 11 (${{ matrix.build.name }} ${{ matrix.dynarec.name }} x86_64)" + + runs-on: ubuntu-22.04 + + strategy: + fail-fast: true + matrix: + build: + - name: Debug + preset: debug + slug: -Debug + - name: Dev + preset: experimental + slug: -Dev + dynarec: + - name: ODR + new: off + slug: -ODR + - name: NDR + new: on + slug: -NDR + + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: >- + sudo apt update && sudo apt install + build-essential + ninja-build + libfreetype-dev + libsdl2-dev + libpng-dev + libc6-dev + librtmidi-dev + qtbase5-dev + qttools5-dev + libopenal-dev + - name: Configure CMake + run: >- + cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} + --toolchain ./cmake/flags-gcc-x86_64.cmake + -D NEW_DYNAREC=${{ matrix.dynarec.new }} + - name: Build + run: cmake --build build +# - name: Generate package +# run: cmake --install build --prefix ./build/artifacts +# - uses: actions/upload-artifact@v2 +# with: +# name: '86Box${{ matrix.build.slug }}-UbuntuJammy-x86_64-gha${{ github.run_number }}' +# path: build/artifacts/** + + macos11: + name: "macOS 11 (${{ matrix.build.name }} x86_64)" + + runs-on: macos-11 + + strategy: + fail-fast: true + matrix: + build: + - name: Debug + preset: debug + slug: -Debug + - name: Dev + preset: experimental + slug: -Dev + dynarec: + - name: ODR + new: off + slug: -ODR + - name: NDR + new: on + slug: -NDR + + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: brew install freetype sdl2 libpng rtmidi qt@5 openal-soft ninja + - name: Configure CMake + run: >- + cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} + --toolchain cmake/flags-gcc-x86_64.cmake + -D NEW_DYNAREC=${{ matrix.build.new-dynarec }} + -D Qt5_ROOT=$(brew --prefix qt@5) + -D Qt5LinguistTools_ROOT=$(brew --prefix qt@5) + -D OpenAL_ROOT=$(brew --prefix openal-soft) + - name: Build + run: cmake --build build + - name: Generate package + run: cmake --install build --prefix ./build/artifacts + - uses: actions/upload-artifact@v2 + with: + name: '86Box${{ matrix.build.slug }}-macOS-x86_64-gha${{ github.run_number }}' + path: build/artifacts/** diff --git a/.gitignore b/.gitignore index cc9da153b..267f3d766 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,46 @@ -src/*.o -src/*.exe -src/*.res -src/*.d -src/NUL +# CMake +CMakeUserPresets.json +CMakeCache.txt +CMakeFiles +/build +Makefile +*.a +/src/*.exe +/src/86Box +/src/include/86box/version.h + +# Legacy Makefile +/src/*.o +/src/*.d +/src/*.res +/src/*.dll +/src/NUL + +# State +/src/*.cfg +/src/*.log +/src/*.dmp +/src/nvr/ +/src/roms/ +/src/screenshots/ + +# Build scripts +/archive_tmp +/archive_tmp_universal +/static2dll.* +/VERSION +*.zip +*.tar +*.tar.* +*.AppImage +/appimage-builder-cache + +# Visual Studio Code +/.vs +/.vscode + +# Windows resource compiler +RC* + +# Qt Creator +CMakeLists.txt.user diff --git a/AUTHORS b/AUTHORS index cef4e3773..bea36a263 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,5 @@ -All authors of this emulator are documented in at the top of each file in the source code. - -They own portions of the code, or in cases, the entirety of it. - -resid-fp and slirp folders have their own exceptions. \ No newline at end of file +All authors of this emulator are documented in at the top of each file in the source code. + +They own portions of the code, or in cases, the entirety of it. + +resid-fp and slirp folders have their own exceptions. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..561e1eeda --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,201 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +cmake_minimum_required(VERSION 3.16) + +cmake_policy(SET CMP0091 NEW) +cmake_policy(SET CMP0079 NEW) + +if(HAIKU) + set(OPENAL ON) + set(RTMIDI OFF) +endif() + +if(NOT DEFINED QT OR QT) + list(APPEND VCPKG_MANIFEST_FEATURES "qt-ui") +endif() + +if(NOT DEFINED OPENAL OR OPENAL) + list(APPEND VCPKG_MANIFEST_FEATURES "openal") +endif() + +if(SLIRP_EXTERNAL) + list(APPEND VCPKG_MANIFEST_FEATURES "slirp") +endif() + +if(MUNT_EXTERNAL) + list(APPEND VCPKG_MANIFEST_FEATURES "munt") +endif() + +project(86Box + VERSION 3.6 + DESCRIPTION "Emulator of x86-based systems" + HOMEPAGE_URL "https://86box.net" + LANGUAGES C CXX) + +include(CPack) +include(CMakeDependentOption) + +# Basic build options +if(VCPKG_TOOLCHAIN) + # For vcpkg builds we have to respect the linking method used by the + # specified triplet. + set(NO_STATIC_OPTION ON) + if(VCPKG_TARGET_TRIPLET MATCHES "-static$") + # `-static` triplet, use static linking + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + set(STATIC_BUILD ON) + elseif(VCPKG_TARGET_TRIPLET MATCHES "-static-md$") + # `-static-md` triplet, use static linking with dynamic CRT + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + set(STATIC_BUILD ON) + elseif() + # Regular triplet, use dynamic linking + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + set(STATIC_BUILD OFF) + endif() + + # `vcpkg.json` defaults to Qt6 + set(USE_QT6 ON) +endif() + +if(WIN32) + # Prefer static builds on Windows + set(PREFER_STATIC ON) + + # Default value for the `WIN32` target property, which specifies whether + # to build the application for the Windows GUI or console subsystem + option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" ON) +else() + # Prefer dynamic builds everywhere else + set(PREFER_STATIC OFF) +endif() + +if(APPLE) + option(CMAKE_MACOSX_BUNDLE "Build a macOS bundle (.app)" ON) +endif() + +if(NOT NO_STATIC_OPTION) + if(PREFER_STATIC) + option(STATIC_BUILD "Static build" ON) + else() + option(STATIC_BUILD "Static build" OFF) + endif() +endif() + +# Detect the target architecture by trying to compile `src/arch_detect.c` +try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/src/arch_detect.c" OUTPUT_VARIABLE ARCH) +string(REGEX MATCH "ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") +string(REPLACE "ARCH " "" ARCH "${ARCH}") +if (NOT ARCH) + set(ARCH unknown) +endif() + +add_compile_definitions(CMAKE) +add_compile_definitions("$<$:DEBUG>") + +if(WIN32) + # Disables *_s function warnings + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + + # Disables POSIX name warnings + add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS) + + # Disables WinSock deprecation warnings + add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS) +endif() + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) + +# Optional features +# +# Option Description Def. +# ------ ----------- ---- +option(RELEASE "Release build" OFF) +option(DYNAREC "Dynamic recompiler" ON) +option(OPENAL "OpenAL" ON) +option(RTMIDI "RtMidi" ON) +option(FLUIDSYNTH "FluidSynth" ON) +option(MUNT "MUNT" ON) +option(VNC "VNC renderer" OFF) +option(DINPUT "DirectInput" OFF) +option(CPPTHREADS "C++11 threads" ON) +option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) +option(MINITRACE "Enable Chrome tracing using the modified minitrace library" OFF) +option(GDBSTUB "Enable GDB stub server for debugging" OFF) +option(DEV_BRANCH "Development branch" OFF) +option(QT "Qt GUI" ON) + +# Development branch features +# +# 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(CYRIX_6X86 "Cyrix 6x86" ON "DEV_BRANCH" OFF) +cmake_dependent_option(DESKPRO386 "Compaq Deskpro 386" 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(MGA "Matrox Mystique graphics adapters" 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(PAS16 "Pro Audio Spectrum 16" ON "DEV_BRANCH" OFF) +cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" ON "DEV_BRANCH" OFF) +cmake_dependent_option(TANDY_ISA "Tandy PSG ISA clone boards" ON "DEV_BRANCH" OFF) +cmake_dependent_option(VGAWONDER "ATI VGA Wonder (ATI-18800)" ON "DEV_BRANCH" OFF) +cmake_dependent_option(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" OFF) + +# Ditto but for Qt +if(QT) + option(USE_QT6 "Use Qt6 instead of Qt5" OFF) +endif() + +# Determine the build type +set(RELEASE_BUILD OFF) +set(BETA_BUILD OFF) +set(ALPHA_BUILD OFF) + +string(TOLOWER "${BUILD_TYPE}" BUILD_TYPE_LOWER) +if(BUILD_TYPE_LOWER STREQUAL "release") + # Release build + set(RELEASE_BUILD ON) + add_compile_definitions(RELEASE_BUILD) +elseif(BUILD_TYPE_LOWER STREQUAL "beta") + # Beta build + set(BETA_BUILD ON) + add_compile_definitions(BETA_BUILD) +elseif(BUILD_TYPE_LOWER STREQUAL "alpha") + # Alpha build + set(ALPHA_BUILD ON) + add_compile_definitions(ALPHA_BUILD) +endif() + +# Versioning variables +if(NOT CMAKE_PROJECT_VERSION_PATCH) + set(CMAKE_PROJECT_VERSION_PATCH 0) +endif() +if(NOT EMU_BUILD_NUM) + set(EMU_BUILD_NUM 0) +endif() +if(NOT EMU_COPYRIGHT_YEAR) + set(EMU_COPYRIGHT_YEAR 2022) +endif() + +add_subdirectory(src) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..2cb84ee6f --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,45 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21 + }, + "configurePresets": [ + { + "name": "regular", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "DEV_BRANCH": "OFF", + "NEW_DYNAREC": "OFF" + }, + "generator": "Ninja" + }, + { + "name": "optimized", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Optimized", + "DEV_BRANCH": "OFF", + "NEW_DYNAREC": "OFF" + }, + "generator": "Ninja" + }, + { + "name": "debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "DEV_BRANCH": "OFF", + "NEW_DYNAREC": "OFF" + }, + "generator": "Ninja" + }, + { + "name": "experimental", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "DEV_BRANCH": "ON", + "NEW_DYNAREC": "ON" + }, + "generator": "Ninja" + } + ] +} diff --git a/README.md b/README.md index a207eaf31..10d801f12 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,57 @@ 86Box ===== -**86Box** is 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. +[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box) -86Box is released under the GNU General Public License, version 2. For more -information, see the `LICENSE` file. +**86Box** is a low level x86 emulator that runs older operating systems and software designed for IBM PC systems and compatibles from 1981 through fairly recent system designs based on the PCI bus. -The project maintainer is OBattler. +Features +-------- +* Easy to use interface inspired by mainstream hypervisor software +* Low level emulation of 8086-based processors up to the Pentium with focus on accuracy +* Great range of customizability of virtual machines +* Many available systems, such as the very first IBM PC 5150 from 1981, or the more obscure IBM PS/2 line of systems based on the Micro Channel Architecture +* Lots of supported peripherals including video adapters, sound cards, network adapters, hard disk controllers, and SCSI adapters +* MIDI output to Windows built-in MIDI support, FluidSynth, or emulated Roland synthesizers +* Supports running MS-DOS, older Windows versions, OS/2, many Linux distributions, or vintage systems such as BeOS or NEXTSTEP, and applications for these systems -If you need a configuration manager for 86Box, use the [86Box Manager](https://github.com/86Box/86BoxManager), our -officially endorsed 86Box configuration manager, developed by Overdoze (daviunic). +System requirements and recommendations +--------------------------------------- +* Intel Core 2 or AMD Athlon 64 processor +* Windows version: Windows 7 Service Pack 1, Windows 8.1 or Windows 10 +* Linux version: Ubuntu 16.04, Debian 9.0 or other distributions from 2016 onwards +* 4 GB of RAM -Community ---------- -We operate an IRC channel and a Discord server for discussing anything related -to retro computing and, of course, 86Box. We look forward to hearing from you! +Performance may vary depending on both host and guest configuration. Most emulation logic is executed in a single thread, therefore generally systems with better IPC (instructions per clock) should be able to emulate higher clock speeds. -[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/softhistory.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#softhistory) +It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines. +* [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only) +* [86Box Manager Lite](https://github.com/insanemal/86box_manager_py) by [Insanemal](https://github.com/insanemal) +* [WinBox for 86Box](https://github.com/86Box/WinBox-for-86Box) by Laci bá' (Windows only) -[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv) +However, it is also possible to use 86Box on its own with the `--vmpath`/`-P` command line option. Getting started --------------- -See [this](https://86box.github.io/gettingstarted) page on our website for a quick guide that should help you get started with the emulator. +See [our documentation](https://86box.readthedocs.io/en/latest/index.html) for an overview of the emulator's features and user interface. -Building --------- -See the [build guide](doc/build.md). +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! -Automatic builds --------------- -For your convenience, we compile a number of 86Box builds per revision on our -Jenkins instance. +[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/86Box.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#86Box) -| Regular | Debug | Optimized | Experimental | -|:-------:|:-----:|:---------:|:------------:| -|[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)|[![Build Status](http://ci.86box.net/job/86Box-Debug/badge/icon)](http://ci.86box.net/job/86Box-Debug)|[![Build Status](http://ci.86box.net/job/86Box-Optimized/badge/icon)](http://ci.86box.net/job/86Box-Optimized)|[![Build Status](http://ci.86box.net/job/86Box-Dev/badge/icon)](http://ci.86box.net/job/86Box-Dev) +[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv) -### Legend -* **Regular** builds are compiled using the settings in the building guide - above. Use these if you don't know which build to use. -* **Debug** builds are same as regular builds but include debug symbols. - If you don't need them, you don't need to use this build. -* **Optimized** builds have the same feature set as regular builds, but are - optimized for every modern Intel and AMD processor architecture, which might - improve the emulator's performance in certain scenarios. -* **Experimental (Dev)** builds are similar to regular builds but are compiled - with certain unfinished features enabled. These builds are not optimized for maximum performance. +Licensing +--------- +86Box is released under the [GNU General Public License, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) or later. For more information, see the `COPYING` file in the root of the repository. + +The emulator can also optionally make use of [munt](https://github.com/munt/munt), [FluidSynth](https://www.fluidsynth.org/), [Ghostscript](https://www.ghostscript.com/) and [Discord Game SDK](https://discord.com/developers/docs/game-sdk/sdk-starter-guide), which are distributed under their respective licenses. Donations --------- We do not charge you for the emulator but donations are still welcome: https://paypal.me/86Box. + +You can also support the project on Patreon: +https://www.patreon.com/86box. diff --git a/bumpversion.sh b/bumpversion.sh new file mode 100644 index 000000000..7fb0e96eb --- /dev/null +++ b/bumpversion.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# +# 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. +# +# Convenience script for changing the emulator's version. +# +# +# Authors: RichardG, +# +# Copyright 2022 RichardG. +# + +# Parse arguments. +newversion="$1" +romversion="$2" +if [ -z "$(echo "$newversion" | grep '\.')" ] +then + echo '[!] Usage: bumpversion.sh x.y[.z] [romversion]' + exit 1 +fi +shift + +# Extract version components. +newversion_maj=$(echo "$newversion" | cut -d. -f1) +newversion_min=$(echo "$newversion" | cut -d. -f2) +newversion_patch=$(echo "$newversion" | cut -d. -f3) +[ -z "$newversion_patch" ] && newversion_patch=0 + + +if [ -z "${romversion}" ]; then + # Get the latest ROM release from the GitHub API. + romversion=$(curl --silent "https://api.github.com/repos/86Box/roms/releases/latest" | + grep '"tag_name":' | + sed -E 's/.*"([^"]+)".*/\1/') +fi + +# Switch to the repository root directory. +cd "$(dirname "$0")" || exit + +pretty_date() { + # Ensure we get the date in English. + LANG=en_US.UTF-8 date '+%a %b %d %Y' +} + +# Patch files. +patch_file() { + # Stop if the file doesn't exist. + [ ! -e "$1" ] && return + + # Patch file. + if sed -i -r -e "$3" "$1" + then + echo "[-] Patched $2 on $1" + else + echo "[!] Patching $2 on $1 failed" + fi +} +patch_file CMakeLists.txt VERSION 's/^(\s*VERSION ).+/\1'"$newversion"'/' +patch_file vcpkg.json version-string 's/(^\s*"version-string"\s*:\s*")[^"]+/\1'"$newversion"'/' +patch_file src/include_make/*/version.h EMU_VERSION 's/(#\s*define\s+EMU_VERSION\s+")[^"]+/\1'"$newversion"'/' +patch_file src/include_make/*/version.h EMU_VERSION_MAJ 's/(#\s*define\s+EMU_VERSION_MAJ\s+)[0-9]+/\1'"$newversion_maj"'/' +patch_file src/include_make/*/version.h EMU_VERSION_MIN 's/(#\s*define\s+EMU_VERSION_MIN\s+)[0-9]+/\1'"$newversion_min"'/' +patch_file src/include_make/*/version.h EMU_VERSION_PATCH 's/(#\s*define\s+EMU_VERSION_PATCH\s+)[0-9]+/\1'"$newversion_patch"'/' +patch_file src/include_make/*/version.h COPYRIGHT_YEAR 's/(#\s*define\s+COPYRIGHT_YEAR\s+)[0-9]+/\1'"$(date +%Y)"'/' +patch_file src/include_make/*/version.h EMU_DOCS_URL 's/(#\s*define\s+EMU_DOCS_URL\s+"https:\/\/[^\/]+\/en\/v)[^\/]+/\1'"$newversion_maj.$newversion_min"'/' +patch_file src/unix/assets/*.spec Version 's/(Version:\s+)[0-9].+/\1'"$newversion"'/' +patch_file src/unix/assets/*.spec '%global romver' 's/(^%global\ romver\s+)[0-9]{8}/\1'"$romversion"'/' +patch_file src/unix/assets/*.spec 'changelog version' 's/(^[*]\s.*>\s+)[0-9].+/\1'"$newversion"-1'/' +patch_file src/unix/assets/*.spec 'changelog date' 's/(^[*]\s)[a-zA-Z]{3}\s[a-zA-Z]{3}\s[0-9]{2}\s[0-9]{4}/\1'"$(pretty_date)"'/' +patch_file src/unix/assets/*.metainfo.xml release 's/( +# +# Copyright 2021 David Hrdlička. +# + +string(APPEND CMAKE_C_FLAGS_INIT " -march=armv8-a") +string(APPEND CMAKE_CXX_FLAGS_INIT " -march=armv8-a") + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc.cmake) \ No newline at end of file diff --git a/cmake/flags-gcc-armv7.cmake b/cmake/flags-gcc-armv7.cmake new file mode 100644 index 000000000..e73f55edd --- /dev/null +++ b/cmake/flags-gcc-armv7.cmake @@ -0,0 +1,20 @@ +# +# 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. +# +# CMake toolchain file defining GCC compiler flags +# for ARMv7 targets. +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +string(APPEND CMAKE_C_FLAGS_INIT " -march=armv7-a -mfloat-abi=hard") +string(APPEND CMAKE_CXX_FLAGS_INIT " -march=armv7-a -mfloat-abi=hard") + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc.cmake) \ No newline at end of file diff --git a/cmake/flags-gcc-i686.cmake b/cmake/flags-gcc-i686.cmake new file mode 100644 index 000000000..2d12b7937 --- /dev/null +++ b/cmake/flags-gcc-i686.cmake @@ -0,0 +1,20 @@ +# +# 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. +# +# CMake toolchain file defining GCC compiler flags +# for 32-bit x86 targets. +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +string(APPEND CMAKE_C_FLAGS_INIT " -m32 -march=i686 -msse2 -mfpmath=sse -mstackrealign") +string(APPEND CMAKE_CXX_FLAGS_INIT " -m32 -march=i686 -msse2 -mfpmath=sse -mstackrealign") + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc.cmake) diff --git a/cmake/flags-gcc-x86_64.cmake b/cmake/flags-gcc-x86_64.cmake new file mode 100644 index 000000000..f9f39eb97 --- /dev/null +++ b/cmake/flags-gcc-x86_64.cmake @@ -0,0 +1,20 @@ +# +# 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. +# +# CMake toolchain file defining GCC compiler flags +# for 64-bit x86 targets. +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +string(APPEND CMAKE_C_FLAGS_INIT " -m64 -march=x86-64 -msse2 -mfpmath=sse -mstackrealign") +string(APPEND CMAKE_CXX_FLAGS_INIT " -m64 -march=x86-64 -msse2 -mfpmath=sse -mstackrealign") + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc.cmake) diff --git a/cmake/flags-gcc.cmake b/cmake/flags-gcc.cmake new file mode 100644 index 000000000..3339ad063 --- /dev/null +++ b/cmake/flags-gcc.cmake @@ -0,0 +1,35 @@ +# +# 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. +# +# CMake toolchain file defining GCC compiler flags. +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +# Define our flags +string(APPEND CMAKE_C_FLAGS_INIT " -fomit-frame-pointer -Wall -fno-strict-aliasing") +string(APPEND CMAKE_CXX_FLAGS_INIT " -fomit-frame-pointer -Wall -fno-strict-aliasing") +string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -g0 -O3") +string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -g0 -O3") +string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -ggdb -Og") +string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -ggdb -Og") +string(APPEND CMAKE_C_FLAGS_OPTIMIZED_INIT " -march=native -mtune=native -O3 -ffp-contract=fast -flto") +string(APPEND CMAKE_CXX_FLAGS_OPTIMIZED_INIT " -march=native -mtune=native -O3 -ffp-contract=fast -flto") + +# Set up the variables +foreach(LANG C;CXX) + set(CMAKE_${LANG}_FLAGS "$ENV{${LANG}FLAGS} ${CMAKE_${LANG}_FLAGS_INIT}" CACHE STRING "Flags used by the ${LANG} compiler during all build types.") + mark_as_advanced(CMAKE_${LANG}_FLAGS) + + foreach(CONFIG RELEASE;DEBUG;OPTIMIZED) + set(CMAKE_${LANG}_FLAGS_${CONFIG} "${CMAKE_${LANG}_FLAGS_${CONFIG}_INIT}" CACHE STRING "Flags used by the ${LANG} compiler during ${CONFIG} builds.") + mark_as_advanced(CMAKE_${LANG}_FLAGS_${CONFIG}) + endforeach() +endforeach() \ No newline at end of file diff --git a/cmake/llvm-macos-aarch64.cmake b/cmake/llvm-macos-aarch64.cmake new file mode 100644 index 000000000..da9ccb449 --- /dev/null +++ b/cmake/llvm-macos-aarch64.cmake @@ -0,0 +1,22 @@ +# +# 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. +# +# CMake toolchain file defining Clang compiler flags +# for AArch64 (ARM64)-based Apple Silicon targets. +# +# Authors: David Hrdlička, +# dob205 +# +# Copyright 2021 David Hrdlička. +# Copyright 2022 dob205. +# + +string(APPEND CMAKE_C_FLAGS_INIT " -march=armv8.5-a+simd") +string(APPEND CMAKE_CXX_FLAGS_INIT " -march=armv8.5-a+simd") + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc.cmake) \ No newline at end of file diff --git a/cmake/llvm-win32-aarch64.cmake b/cmake/llvm-win32-aarch64.cmake new file mode 100644 index 000000000..4aacb248f --- /dev/null +++ b/cmake/llvm-win32-aarch64.cmake @@ -0,0 +1,30 @@ +# +# 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. +# +# CMake toolchain file for Clang on Windows builds (ARM64 target). +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc-aarch64.cmake) + +# Use the GCC-compatible Clang executables in order to use our flags +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) + +# `llvm-rc` is barely usable as of LLVM 13, using MS' rc.exe for now +set(CMAKE_RC_COMPILER rc) + +set(CMAKE_C_COMPILER_TARGET aarch64-pc-windows-msvc) +set(CMAKE_CXX_COMPILER_TARGET aarch64-pc-windows-msvc) + +set(CMAKE_SYSTEM_PROCESSOR ARM64) + +# TODO: set the vcpkg target triplet perhaps? \ No newline at end of file diff --git a/cmake/llvm-win32-i686.cmake b/cmake/llvm-win32-i686.cmake new file mode 100644 index 000000000..8221f8bc2 --- /dev/null +++ b/cmake/llvm-win32-i686.cmake @@ -0,0 +1,30 @@ +# +# 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. +# +# CMake toolchain file for Clang on Windows builds (x86 target). +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc-i686.cmake) + +# Use the GCC-compatible Clang executables in order to use our flags +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) + +# `llvm-rc` is barely usable as of LLVM 13, using MS' rc.exe for now +set(CMAKE_RC_COMPILER rc) + +set(CMAKE_C_COMPILER_TARGET i686-pc-windows-msvc) +set(CMAKE_CXX_COMPILER_TARGET i686-pc-windows-msvc) + +set(CMAKE_SYSTEM_PROCESSOR X86) + +# TODO: set the vcpkg target triplet perhaps? \ No newline at end of file diff --git a/cmake/llvm-win32-x86_64.cmake b/cmake/llvm-win32-x86_64.cmake new file mode 100644 index 000000000..7caeb7836 --- /dev/null +++ b/cmake/llvm-win32-x86_64.cmake @@ -0,0 +1,30 @@ +# +# 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. +# +# CMake toolchain file for Clang on Windows builds (x64/AMD64 target). +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc-x86_64.cmake) + +# Use the GCC-compatible Clang executables in order to use our flags +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) + +# `llvm-rc` is barely usable as of LLVM 13, using MS' rc.exe for now +set(CMAKE_RC_COMPILER rc) + +set(CMAKE_C_COMPILER_TARGET x86_64-pc-windows-msvc) +set(CMAKE_CXX_COMPILER_TARGET x86_64-pc-windows-msvc) + +set(CMAKE_SYSTEM_PROCESSOR AMD64) + +# TODO: set the vcpkg target triplet perhaps? \ No newline at end of file diff --git a/doc/README b/doc/README deleted file mode 100644 index dff34b92d..000000000 --- a/doc/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains 86Box documentation. \ No newline at end of file diff --git a/doc/build.md b/doc/build.md deleted file mode 100644 index 0b226dc33..000000000 --- a/doc/build.md +++ /dev/null @@ -1,38 +0,0 @@ -Building -======== -In order to compile 86Box from this repository, please follow this step-by-step guide: - -1. Install the [MSYS2](https://www.msys2.org/) environment. The rest of the guide will refer to the directory that you install it to (C:\msys32 or C:\msys64 by default) as the MSYS2 root. - -2. Launch your MSYS2 environment using the `MSYS2 MinGW 32-bit` shortcut. If you do not want to use the shortcut, launch it using the `mingw32.exe` executable in the MSYS2 root. - -3. Once launched, you should update the environment: - ```console - $ pacman -Syu - ``` - You may need to do this twice, just follow the on-screen instructions. Make sure you re-run the command periodically to keep the environment up-to-date. - -4. Run the following command to install all of the dependencies: - ```console - $ pacman -S gdb make git mingw-w64-i686-toolchain mingw-w64-i686-openal mingw-w64-i686-freetype mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-libpng - ``` - -5. Once the environment is fully updated and all dependencies are installed, change directory to `src`: - ```console - $ cd path/to/86Box/src - ``` - -6. Start the actual compilation process: - ```console - $ make -f win/Makefile.mingw - ``` - By default, `make` does not run in parallel. If you want it to use more threads, use the `-j` switch with the number of threads, e.g. `-j4`. However, keep in mind that you should not exceed your thread (logical processor) count, since that just uses more resources for little to no gain. - -7. If the compilation succeeded (which it almost always should), you will find `86Box.exe` in the `src` directory. - -8. In order to test your fresh build, replace the `86Box.exe` in your current 86Box environment with your freshly built one. If you do not have a pre-existing 86Box environment, download the latest successful build from http://ci.86box.net, and the latest ROM set from https://github.com/86Box/roms. - -9. Enjoy using and testing the emulator! :) - -If you encounter issues at any step or have additional questions, please join -the IRC channel or the appropriate channel on our Discord server and wait patiently for someone to help you. diff --git a/src/86box.c b/src/86box.c new file mode 100644 index 000000000..f6b791901 --- /dev/null +++ b/src/86box.c @@ -0,0 +1,1383 @@ +/* + * 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. + * + * Main emulator module where most things are controlled. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2021 Laci bá' + * Copyright 2021 dob205 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#endif +#ifdef __APPLE__ +#include +#include +#ifdef __aarch64__ +#include +#endif +#endif + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/mem.h> +#include "cpu.h" +#ifdef USE_DYNAREC +# include "codegen_public.h" +#endif +#include "x86_ops.h" +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/dma.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/pit.h> +#include <86box/random.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/machine.h> +#include <86box/bugger.h> +#include <86box/postcard.h> +#include <86box/isamem.h> +#include <86box/isartc.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/keyboard.h> +#include <86box/mouse.h> +#include <86box/gameport.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/hdd.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/cdrom.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/scsi_disk.h> +#include <86box/cdrom_image.h> +#include <86box/network.h> +#include <86box/sound.h> +#include <86box/midi.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> +#include <86box/ui.h> +#include <86box/path.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/version.h> +#include <86box/gdbstub.h> +#include <86box/machine_status.h> + +// Disable c99-designator to avoid the warnings about int ng +#ifdef __clang__ +#if __has_warning("-Wunused-but-set-variable") +#pragma clang diagnostic ignored "-Wunused-but-set-variable" +#endif +#endif + + +/* Stuff that used to be globally declared in plat.h but is now extern there + and declared here instead. */ +int dopause; /* system is paused */ +atomic_flag doresize; /* screen resize requested */ +volatile int is_quit; /* system exit requested */ +uint64_t timer_freq; +char emu_version[200]; /* version ID string */ + +#ifdef MTR_ENABLED +int tracing_on = 0; +#endif + +/* Commandline options. */ +int dump_on_exit = 0; /* (O) dump regs on exit */ +int do_dump_config = 0; /* (O) dump config on load */ +int start_in_fullscreen = 0; /* (O) start in fullscreen */ +#ifdef _WIN32 +int force_debug = 0; /* (O) force debug output */ +#endif +#ifdef USE_WX +int video_fps = RENDER_FPS; /* (O) render speed in fps */ +#endif +int settings_only = 0; /* (O) show only the settings dialog */ +int confirm_exit_cmdl = 1; /* (O) do not ask for confirmation on quit if set to 0 */ +#ifdef _WIN32 +uint64_t unique_id = 0; +uint64_t source_hwnd = 0; +#endif +char rom_path[1024] = { '\0'}; /* (O) full path to ROMs */ +rom_path_t rom_paths = { "", NULL }; /* (O) full paths to ROMs */ +char log_path[1024] = { '\0'}; /* (O) full path of logfile */ +char vm_name[1024] = { '\0'}; /* (O) display name of the VM */ + +/* Configuration values. */ +int window_remember; +int vid_resize; /* (C) allow resizing */ +int invert_display = 0; /* (C) invert the display */ +int suppress_overscan = 0; /* (C) suppress overscans */ +int scale = 0; /* (C) screen scale factor */ +int dpi_scale = 0; /* (C) DPI scaling of the emulated screen */ +int vid_api = 0; /* (C) video renderer */ +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; /* (C) video */ +int enable_overscan = 0; /* (C) video */ +int force_43 = 0; /* (C) video */ +int video_filter_method = 1; /* (C) video */ +int video_vsync = 0; /* (C) video */ +int video_framerate = -1; /* (C) video */ +char video_shader[512] = { '\0' }; /* (C) video */ +int serial_enabled[SERIAL_MAX] = {0,0}; /* (C) enable serial ports */ +int bugger_enabled = 0; /* (C) enable ISAbugger */ +int postcard_enabled = 0; /* (C) enable POST card */ +int isamem_type[ISAMEM_MAX] = { 0,0,0,0 }; /* (C) enable ISA mem cards */ +int isartc_type = 0; /* (C) enable ISA RTC card */ +int gfxcard = 0; /* (C) graphics/video card */ +int gfxcard_2 = 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 GAMEBLASTER = 0; /* (C) sound option */ +int GUS = 0; /* (C) sound option */ +int SSI2001 = 0; /* (C) sound option */ +int voodoo_enabled = 0; /* (C) video option */ +int ibm8514_enabled = 0; /* (C) video option */ +int xga_enabled = 0; /* (C) video option */ +uint32_t mem_size = 0; /* (C) memory size (Installed on system board)*/ +uint32_t isa_mem_size = 0; /* (C) memory size (ISA Memory Cards) */ +int cpu_use_dynarec = 0; /* (C) cpu uses/needs Dyna */ +int cpu = 0; /* (C) cpu type */ +int fpu_type = 0; /* (C) fpu type */ +int time_sync = 0; /* (C) enable time sync */ +int confirm_reset = 1; /* (C) enable reset confirmation */ +int confirm_exit = 1; /* (C) enable exit confirmation */ +int confirm_save = 1; /* (C) enable save confirmation */ +int enable_discord = 0; /* (C) enable Discord integration */ +int pit_mode = -1; /* (C) force setting PIT mode */ +int fm_driver = 0; /* (C) select FM sound driver */ + +/* Statistics. */ +extern int mmuflush; +extern int readlnum; +extern int writelnum; + +/* emulator % */ +int fps; +int framecount; + +extern int CPUID; +extern int output; +int atfullspeed; + +char exe_path[2048]; /* path (dir) of executable */ +char usr_path[1024]; /* path (dir) of user data */ +char cfg_path[1024]; /* full path of config file */ +FILE *stdlog = NULL; /* file to log output to */ +//int scrnsz_x = SCREEN_RES_X; /* current screen size, X */ +//int scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ +int config_changed; /* config has changed */ +int title_update; +int framecountx = 0; +int hard_reset_pending = 0; + + +//int unscaled_size_x = SCREEN_RES_X; /* current unscaled size X */ +//int unscaled_size_y = SCREEN_RES_Y; /* current unscaled size Y */ +//int efscrnsz_y = SCREEN_RES_Y; + + +static wchar_t mouse_msg[3][200]; + + +#ifndef RELEASE_BUILD +static char buff[1024]; +static int seen = 0; + +static int suppr_seen = 1; +#endif + +/* + * Log something to the logfile or stdout. + * + * To avoid excessively-large logfiles because some + * module repeatedly logs, we keep track of what is + * being logged, and catch repeating entries. + */ +void +pclog_ex(const char *fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + char temp[1024]; + + if (strcmp(fmt, "") == 0) + return; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + if (suppr_seen && ! strcmp(buff, temp)) + seen++; + else { + if (suppr_seen && seen) + fprintf(stdlog, "*** %d repeats ***\n", seen); + seen = 0; + strcpy(buff, temp); + fprintf(stdlog, "%s", temp); + } + + fflush(stdlog); +#endif +} + + +void +pclog_toggle_suppr(void) +{ +#ifndef RELEASE_BUILD + suppr_seen ^= 1; +#endif +} + + +/* Log something. We only do this in non-release builds. */ +void +pclog(const char *fmt, ...) +{ +#ifndef RELEASE_BUILD + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +#endif +} + + +/* Log a fatal error, and display a UI message before exiting. */ +void +fatal(const char *fmt, ...) +{ + char temp[1024]; + va_list ap; + char *sp; + + va_start(ap, fmt); + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); + + nvr_save(); + + config_save(); + +#ifdef ENABLE_808X_LOG + dumpregs(1); +#endif + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + + /* Cleanly terminate all of the emulator's components so as + to avoid things like threads getting stuck. */ + do_stop(); + + ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp); + + fflush(stdlog); + + exit(-1); +} + + +void +fatal_ex(const char *fmt, va_list ap) +{ + char temp[1024]; + char *sp; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + + nvr_save(); + + config_save(); + +#ifdef ENABLE_808X_LOG + dumpregs(1); +#endif + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + + /* Cleanly terminate all of the emulator's components so as + to avoid things like threads getting stuck. */ + do_stop(); + + ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp); + + fflush(stdlog); +} + + +#ifdef ENABLE_PC_LOG +int pc_do_log = ENABLE_PC_LOG; + + +static void +pc_log(const char *fmt, ...) +{ + va_list ap; + + if (pc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pc_log(fmt, ...) +#endif + + +/* + * Perform initial startup of the PC. + * + * This is the platform-indepenent part of the startup, + * where we check commandline arguments and load a + * configuration file. + */ +int +pc_init(int argc, char *argv[]) +{ + char *ppath = NULL, *rpath = NULL; + char *cfg = NULL, *p; + char temp[2048]; + struct tm *info; + time_t now; + int c, lvmp = 0; +#ifdef ENABLE_NG + int ng = 0; +#endif +#ifdef _WIN32 + uint32_t *uid, *shwnd; +#endif + uint32_t lang_init = 0; + + /* Grab the executable's full path. */ + plat_get_exe_name(exe_path, sizeof(exe_path)-1); + p = path_get_filename(exe_path); + *p = '\0'; +#if defined(__APPLE__) + c = strlen(exe_path); + if ((c >= 16) && !strcmp(&exe_path[c - 16], "/Contents/MacOS/")) { + exe_path[c - 16] = '\0'; + p = path_get_filename(exe_path); + *p = '\0'; + } + if (!strncmp(exe_path, "/private/var/folders/", 21)) { + ui_msgbox_header(MBX_FATAL, L"App Translocation", EMU_NAME_W L" cannot determine the emulated machine's location due to a macOS security feature. Please move the " EMU_NAME_W L" app to another folder (not /Applications), or make a copy of it and open that copy instead."); + return(0); + } +#elif !defined(_WIN32) + /* Grab the actual path if we are an AppImage. */ + p = getenv("APPIMAGE"); + if (p && (p[0] != '\0')) + path_get_dirname(exe_path, p); +#endif + + path_slash(exe_path); + + /* + * Get the current working directory. + * + * This is normally the directory from where the + * program was run. If we have been started via + * a shortcut (desktop icon), however, the CWD + * could have been set to something else. + */ + plat_getcwd(usr_path, sizeof(usr_path) - 1); + plat_getcwd(rom_path, sizeof(rom_path) - 1); + + for (c=1; cnext) { + pclog("# ROM path: %s\n", rom_path->path); + } + + pclog("# 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(); + + /* Load the configuration file. */ + config_load(); + + /* Load the desired language */ + if (lang_init) + lang_id = lang_init; + + gdbstub_init(); + + /* All good! */ + return(1); +} + + +void +pc_speed_changed(void) +{ + if (cpu_s->cpu_type >= CPU_286) + pit_set_clock(cpu_s->rspeed); + else + pit_set_clock(14318184.0); +} + + +void +pc_full_speed(void) +{ + if (! atfullspeed) { + pc_log("Set fullspeed - %i %i\n", is386, AT); + pc_speed_changed(); + } + atfullspeed = 1; +} + + +/* Initialize modules, ran once, after pc_init. */ +int +pc_init_modules(void) +{ + int c, m; + wchar_t temp[512]; + char tempc[512]; + +#ifdef PRINT_MISSING_MACHINES_AND_VIDEO_CARDS + c = m = 0; + while (machine_get_internal_name_ex(c) != NULL) { + m = machine_available(c); + if (!m) + pclog("Missing machine: %s\n", machine_getname_ex(c)); + c++; + } + + c = m = 0; + while (video_get_internal_name(c) != NULL) { + memset(tempc, 0, sizeof(tempc)); + device_get_name(video_card_getdevice(c), 0, tempc); + if ((c > 1) && !(tempc[0])) + break; + m = video_card_available(c); + if (!m) + pclog("Missing video card: %s\n", tempc); + c++; + } +#endif + + pc_log("Scanning for ROM images:\n"); + c = m = 0; + while (machine_get_internal_name_ex(m) != NULL) { + c += machine_available(m); + m++; + } + if (c == 0) { + /* No usable ROMs found, aborting. */ + return(0); + } + pc_log("A total of %d ROM sets have been loaded.\n", c); + + /* Load the ROMs for the selected machine. */ + if (! machine_available(machine)) { + swprintf(temp, sizeof(temp), plat_get_string(IDS_2063), machine_getname()); + c = 0; + machine = -1; + while (machine_get_internal_name_ex(c) != NULL) { + if (machine_available(c)) { + ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2128, temp); + machine = c; + config_save(); + break; + } + c++; + } + if (machine == -1) { + fatal("No available machines\n"); + exit(-1); + return(0); + } + } + + /* Make sure we have a usable video card. */ + if (! video_card_available(gfxcard)) { + memset(tempc, 0, sizeof(tempc)); + device_get_name(video_card_getdevice(gfxcard), 0, tempc); + swprintf(temp, sizeof(temp), plat_get_string(IDS_2064), tempc); + c = 0; + while (video_get_internal_name(c) != NULL) { + gfxcard = -1; + if (video_card_available(c)) { + ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2128, temp); + gfxcard = c; + config_save(); + break; + } + c++; + } + if (gfxcard == -1) { + fatal("No available video cards\n"); + exit(-1); + return(0); + } + } + + if (! video_card_available(gfxcard_2)) { + char temp[1024] = { 0 }; + char tempc[1024] = { 0 }; + device_get_name(video_card_getdevice(gfxcard_2), 0, tempc); + snprintf(temp, sizeof(temp), "Video card #2 \"%s\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card.", tempc); + ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2128, temp); + gfxcard_2 = 0; + } + + atfullspeed = 0; + + random_init(); + + mem_init(); + +#ifdef USE_DYNAREC +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(0); +#endif + codegen_init(); +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(1); +#endif +#endif + + keyboard_init(); + joystick_init(); + + video_init(); + + fdd_init(); + + sound_init(); + + hdc_init(); + + video_reset_close(); + + machine_status_init(); + + return(1); +} + + +void +pc_send_ca(uint16_t sc) +{ + keyboard_input(1, 0x1D); /* Ctrl key pressed */ + keyboard_input(1, 0x38); /* Alt key pressed */ + keyboard_input(1, sc); + keyboard_input(0, sc); + keyboard_input(0, 0x38); /* Alt key released */ + keyboard_input(0, 0x1D); /* Ctrl key released */ +} + + +/* Send the machine a Control-Alt-DEL sequence. */ +void +pc_send_cad(void) +{ + pc_send_ca(0x153); +} + + +/* Send the machine a Control-Alt-ESC sequence. */ +void +pc_send_cae(void) +{ + pc_send_ca(1); +} + + +void +pc_reset_hard_close(void) +{ + ui_sb_set_ready(0); + + /* Close all the memory mappings. */ + mem_close(); + + network_timer_stop(); + + /* Turn off timer processing to avoid potential segmentation faults. */ + timer_close(); + + suppress_overscan = 0; + + nvr_save(); + nvr_close(); + + mouse_close(); + + lpt_devices_close(); + + device_close_all(); + + scsi_device_close_all(); + + midi_out_close(); + + midi_in_close(); + + cdrom_close(); + + zip_close(); + + mo_close(); + + scsi_disk_close(); + + closeal(); + + video_reset_close(); + + cpu_close(); +} + + +/* + * This is basically the spot where we start up the actual machine, + * by issuing a 'hard reset' to the entire configuration. Order is + * somewhat important here. Functions here should be named _reset + * really, as that is what they do. + */ +void +pc_reset_hard_init(void) +{ + /* + * First, we reset the modules that are not part of + * the actual machine, but which support some of the + * modules that are. + */ + + /* Reset the general machine support modules. */ + io_init(); + + /* Turn on and (re)initialize timer processing. */ + timer_init(); + + device_init(); + + sound_reset(); + + scsi_reset(); + scsi_device_init(); + + /* Initialize the actual machine and its basic modules. */ + machine_init(); + + /* Reset and reconfigure the serial ports. */ + serial_standalone_init(); + + /* Reset and reconfigure the Sound Card layer. */ + sound_card_reset(); + + /* Reset any ISA RTC cards. */ + isartc_reset(); + + fdc_card_init(); + + fdd_reset(); + + /* + * Once the machine has been initialized, all that remains + * should be resetting all devices set up for it, to their + * current configurations ! + * + * For now, we will call their reset functions here, but + * that will be a call to device_reset_all() later ! + */ + + /* Reset some basic devices. */ + speaker_init(); + lpt_devices_init(); + shadowbios = 0; + + /* + * Reset the mouse, this will attach it to any port needed. + */ + mouse_reset(); + + /* Reset the Hard Disk Controller module. */ + hdc_reset(); + /* Reset and reconfigure the SCSI layer. */ + scsi_card_init(); + + cdrom_hard_reset(); + + zip_hard_reset(); + + mo_hard_reset(); + + scsi_disk_hard_reset(); + + /* Reset and reconfigure the Network Card layer. */ + network_reset(); + + if (joystick_type) + gameport_update_joystick_type(); + + ui_sb_update_panes(); + + if (config_changed) { + config_save(); + + config_changed = 0; + } else + ui_sb_set_ready(1); + + /* Needs the status bar... */ + if (bugger_enabled) + device_add(&bugger_device); + if (postcard_enabled) + device_add(&postcard_device); + + /* Reset the CPU module. */ + resetx86(); + dma_reset(); + pci_pic_reset(); + cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; + + atfullspeed = 0; + pc_full_speed(); + + cycles = 0; +#ifdef FPU_CYCLES + fpu_cycles = 0; +#endif +#ifdef USE_DYNAREC + cycles_main = 0; +#endif + + update_mouse_msg(); +} + +void update_mouse_msg() +{ + wchar_t wcpufamily[2048], wcpu[2048], wmachine[2048], *wcp; + + mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1); + + if (!cpu_override) + mbstowcs(wcpufamily, cpu_f->name, strlen(cpu_f->name)+1); + else + swprintf(wcpufamily, sizeof_w(wcpufamily), L"[U] %hs", cpu_f->name); + + wcp = wcschr(wcpufamily, L'('); + if (wcp) /* remove parentheses */ + *(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", + plat_get_string(IDS_2077)); + swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%i%%%% - %ls", + (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + wcsncpy(mouse_msg[2], L"%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", + EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu, + plat_get_string(IDS_2077)); + swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls", + EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu, + (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls", + EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu); +#endif +} + +void +pc_reset_hard(void) +{ + hard_reset_pending = 1; +} + + +void +pc_close(thread_t *ptr) +{ + int i; + + /* Wait a while so things can shut down. */ + plat_delay_ms(200); + + /* Claim the video blitter. */ + startblit(); + + /* Terminate the UI thread. */ + is_quit = 1; + +#if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) + codegen_close(); +#endif + + nvr_save(); + + config_save(); + + plat_mouse_capture(0); + + /* Close all the memory mappings. */ + mem_close(); + + network_timer_stop(); + + /* Turn off timer processing to avoid potential segmentation faults. */ + timer_close(); + + lpt_devices_close(); + + for (i=0; irspeed / 100); +#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ + if (gdbstub_step == GDBSTUB_EXEC) +#endif + mouse_process(); + joystick_process(); + endblit(); + + /* Done with this frame, update statistics. */ + framecount++; + if (++framecountx >= 100) { + framecountx = 0; + frames = 0; + } + + if (title_update) { + mouse_msg_idx = (mouse_type == MOUSE_TYPE_NONE) ? 2 : !!mouse_capture; + swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps); +#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); +#else + ui_window_title(temp); +#endif + title_update = 0; + } +} + + +/* Handler for the 1-second timer to refresh the window title. */ +void +pc_onesec(void) +{ + fps = framecount; + framecount = 0; + + title_update = 1; +} + +void +set_screen_size_monitor(int x, int y, int monitor_index) +{ + int temp_overscan_x = monitors[monitor_index].mon_overscan_x; + int temp_overscan_y = monitors[monitor_index].mon_overscan_y; + double dx, dy, dtx, dty; + + /* Make sure we keep usable values. */ +#if 0 + pc_log("SetScreenSize(%d, %d) resize=%d\n", x, y, vid_resize); +#endif + if (x < 320) x = 320; + if (y < 200) y = 200; + if (x > 2048) x = 2048; + if (y > 2048) y = 2048; + + /* Save the new values as "real" (unscaled) resolution. */ + monitors[monitor_index].mon_unscaled_size_x = x; + monitors[monitor_index].mon_efscrnsz_y = y; + + if (suppress_overscan) + temp_overscan_x = temp_overscan_y = 0; + + if (force_43) { + dx = (double)x; + dtx = (double)temp_overscan_x; + + dy = (double)y; + dty = (double)temp_overscan_y; + + /* Account for possible overscan. */ + if (video_get_type_monitor(monitor_index) != VIDEO_FLAG_TYPE_SPECIAL && (temp_overscan_y == 16)) { + /* CGA */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else if (video_get_type_monitor(monitor_index) != VIDEO_FLAG_TYPE_SPECIAL && (temp_overscan_y < 16)) { + /* MDA/Hercules */ + dy = (x / 4.0) * 3.0; + } else { + if (enable_overscan) { + /* EGA/(S)VGA with overscan */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else { + /* EGA/(S)VGA without overscan */ + dy = (x / 4.0) * 3.0; + } + } + monitors[monitor_index].mon_unscaled_size_y = (int)dy; + } else + monitors[monitor_index].mon_unscaled_size_y = monitors[monitor_index].mon_efscrnsz_y; + + switch(scale) { + case 0: /* 50% */ + monitors[monitor_index].mon_scrnsz_x = (monitors[monitor_index].mon_unscaled_size_x>>1); + monitors[monitor_index].mon_scrnsz_y = (monitors[monitor_index].mon_unscaled_size_y>>1); + break; + + case 1: /* 100% */ + monitors[monitor_index].mon_scrnsz_x = monitors[monitor_index].mon_unscaled_size_x; + monitors[monitor_index].mon_scrnsz_y = monitors[monitor_index].mon_unscaled_size_y; + break; + + case 2: /* 150% */ + monitors[monitor_index].mon_scrnsz_x = ((monitors[monitor_index].mon_unscaled_size_x*3)>>1); + monitors[monitor_index].mon_scrnsz_y = ((monitors[monitor_index].mon_unscaled_size_y*3)>>1); + break; + + case 3: /* 200% */ + monitors[monitor_index].mon_scrnsz_x = (monitors[monitor_index].mon_unscaled_size_x<<1); + monitors[monitor_index].mon_scrnsz_y = (monitors[monitor_index].mon_unscaled_size_y<<1); + break; + } + + plat_resize_request(monitors[monitor_index].mon_scrnsz_x, monitors[monitor_index].mon_scrnsz_y, monitor_index); +} + +void +set_screen_size(int x, int y) +{ + set_screen_size_monitor(x, y, monitor_index_global); +} + +void +reset_screen_size_monitor(int monitor_index) +{ + set_screen_size(monitors[monitor_index].mon_unscaled_size_x, monitors[monitor_index].mon_efscrnsz_y); +} + +void +reset_screen_size(void) +{ + for (int i = 0; i < MONITORS_NUM; i++) + set_screen_size(monitors[i].mon_unscaled_size_x, monitors[i].mon_efscrnsz_y); +} + + +void +set_screen_size_natural(void) +{ + for (int i = 0; i < MONITORS_NUM; i++) + set_screen_size(monitors[i].mon_unscaled_size_x, monitors[i].mon_unscaled_size_y); +} + + +int +get_actual_size_x(void) +{ + return(unscaled_size_x); +} + + +int +get_actual_size_y(void) +{ + return(efscrnsz_y); +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..1420aaa89 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,209 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# dob205 +# +# Copyright 2020-2022 David Hrdlička. +# Copyright 2021 dob205. +# + +add_executable(86Box 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c + dma.c ddma.c discord.c nmi.c pic.c pit.c pit_fast.c port_6x.c port_92.c ppi.c pci.c + mca.c usb.c fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c machine_status.c) + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1) +endif() + +if(CPPTHREADS) + target_sources(86Box PRIVATE thread.cpp) +endif() + +if(GDBSTUB) + add_compile_definitions(USE_GDBSTUB) + target_sources(86Box PRIVATE gdbstub.c) +endif() + +if(NEW_DYNAREC) + add_compile_definitions(USE_NEW_DYNAREC) +endif() + +if(RELEASE) + add_compile_definitions(RELEASE_BUILD) +endif() + +if(DYNAREC) + add_compile_definitions(USE_DYNAREC) +endif() + +if(DEV_BRANCH) + add_compile_definitions(DEV_BRANCH) +endif() + +if(VNC) + add_compile_definitions(USE_VNC) + add_library(vnc OBJECT vnc.c vnc_keymap.c) + target_link_libraries(86Box vnc vncserver) + if(WIN32) + target_link_libraries(86Box ws2_32) + endif() +endif() + +target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom zip mo hdd + net print scsi sio snd vid voodoo plat ui) + +if(WIN32 AND ARCH STREQUAL "i386") + if(MINGW) + target_link_options(86Box PRIVATE "LINKER:--large-address-aware") + else() + target_link_options(86Box PRIVATE "LINKER:/LARGEADDRESSAWARE") + endif() +endif() + +if(STATIC_BUILD) + if(MINGW OR UNIX) + target_link_options(86Box PRIVATE "-static") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + endif() +endif() + +if(APPLE) + # Force using the newest library if it's installed by homebrew + set(CMAKE_FIND_FRAMEWORK LAST) + + # setting our compilation target to macOS 10.15 Catalina if targetting Qt6, macOS 10.13 High Sierra otherwise + if (USE_QT6) + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15") + else() + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13") + endif() +endif() + +find_package(Freetype REQUIRED) +include_directories(${FREETYPE_INCLUDE_DIRS}) +if(APPLE) + # Freetype is dynamically loaded by the emulator, however, we link it + # on macOS so it gets copied to the bundle by the installation process + 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) + +configure_file(include/86box/version.h.in include/86box/version.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) + +include_directories(include) +if(NEW_DYNAREC) + include_directories(cpu codegen_new) +else() + include_directories(cpu codegen) +endif() + +add_subdirectory(cdrom) +add_subdirectory(chipset) + +add_subdirectory(cpu) +if(NEW_DYNAREC) + add_subdirectory(codegen_new) +else() + add_subdirectory(codegen) +endif() + +if(MINITRACE) + add_compile_definitions(MTR_ENABLED) + add_library(minitrace OBJECT minitrace/minitrace.c) + target_link_libraries(86Box minitrace) +endif() + +if(WIN32 OR (APPLE AND CMAKE_MACOSX_BUNDLE)) + # Copy the binary to the root of the install prefix on Windows and macOS + install(TARGETS 86Box DESTINATION ".") +else() + # On Linux we want to copy the binary to the `bin` folder. + install(TARGETS 86Box) +endif() + + +# Install our dependencies if using vcpkg +if(VCPKG_TOOLCHAIN) + x_vcpkg_install_local_dependencies(TARGETS 86Box DESTINATION ".") +endif() + + +# Install other dependencies +if(WIN32) + install(CODE " + include(BundleUtilities) + get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE) + fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/$\" \"\" \"\")" + COMPONENT Runtime) +elseif(APPLE AND NOT QT) + install(CODE " + include(BundleUtilities) + get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE) + fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"\" \"\")" + COMPONENT Runtime) +endif() + + +# Install the PDB file on Windows builds +if(MSVC) + # CMake fully supports PDB files on MSVC-compatible compilers + install(FILES $ + CONFIGURATIONS Debug RelWithDebInfo + DESTINATION ".") +elseif(WIN32) + # Other compilers/linkers (such as Clang in GCC-compatible mode) also + # emit PDB files when targeting Windows, however, CMake only supports + # the relevant properties with MSVC and clones. Try to install + # the PDB file assuming it's in the same path as the EXE. + install(FILES "$/$.pdb" + CONFIGURATIONS Debug RelWithDebInfo + DESTINATION "." + OPTIONAL) +endif() + + +add_subdirectory(device) +add_subdirectory(disk) +add_subdirectory(floppy) +add_subdirectory(game) +add_subdirectory(machine) +add_subdirectory(mem) +add_subdirectory(network) +add_subdirectory(printer) +add_subdirectory(sio) +add_subdirectory(scsi) +add_subdirectory(sound) +add_subdirectory(video) +if (APPLE) + add_subdirectory(mac) +endif() + +if (QT) + add_subdirectory(qt) +elseif(WIN32) + add_subdirectory(win) +else() + add_subdirectory(unix) +endif() diff --git a/src/Makefile.local b/src/Makefile.local index 8b528ff28..4c6830afd 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -30,8 +30,6 @@ STUFF := # Add feature selections here. # -DANSI_CFG forces the config file to ANSI encoding. -# -DENABLE_VRAM_DUMP enables Video Ram dumping. -# -DENABLE_LOG_BREAKPOINT enables extra logging. # Root logging: # -DENABLE_ACPI_LOG=N sets logging level at N. # -DENABLE_APM_LOG=N sets logging level at N. @@ -74,8 +72,11 @@ STUFF := # chipset/ logging: # -DENABLE_I420EX_LOG=N sets logging level at N. # -DENABLE_NEAT_LOG=N sets logging level at N. +# -DENABLE_OPTI495_LOG=N sets logging level at N. +# -DENABLE_OPTI895_LOG=N sets logging level at N. # -DENABLE_PIIX_LOG=N sets logging level at N. # -DENABLE_SIO_LOG=N sets logging level at N. +# -DENABLE_SIS_85C496_LOG=N sets logging level at N. # codegen/, codegen_new/, cpu/ logging: # -DENABLE_X86SEG_LOG=N sets logging level at N. # cpu/ logging: @@ -122,7 +123,7 @@ STUFF := # -DENABLE_3COM503_LOG=N sets logging level at N. # -DENABLE_DP8390_LOG=N sets logging level at N. # -DENABLE_NETWORK_LOG=N sets logging level at N. -# -DENABLE_NIC_LOG=N sets logging level at N. +# -DENABLE_NE2K_LOG=N sets logging level at N. # -DENABLE_PCAP_LOG=N sets logging level at N. # -DENABLE_PCNET_LOG=N sets logging level at N. # -DENABLE_SLIRP_LOG=N sets logging level at N. @@ -165,14 +166,12 @@ STUFF := # -DENABLE_DISCORD_LOG=N sets logging level at N. # -DENABLE_DYNLD_LOG=N sets logging level at N. # -DENABLE_JOYSTICK_LOG=N sets logging level at N. -# -DENABLE_LOG_TOGGLES=N sets logging level at N. # -DENABLE_SDL_LOG=N sets logging level at N. # -DENABLE_SETTINGS_LOG=N sets logging level at N. EXTRAS := AUTODEP := n -CRASHDUMP := n DEBUG := n OPTIM := n X64 := n diff --git a/src/acpi.c b/src/acpi.c index 91dc44eae..db181cee8 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -20,6 +20,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -28,13 +29,20 @@ #include <86box/io.h> #include <86box/pci.h> #include <86box/pic.h> +#include <86box/plat.h> #include <86box/timer.h> #include <86box/keyboard.h> #include <86box/nvr.h> #include <86box/pit.h> #include <86box/apm.h> #include <86box/acpi.h> +#include <86box/machine.h> +#include <86box/i2c.h> +#include <86box/video.h> +int acpi_rtc_status = 0; + +static double cpu_to_acpi; #ifdef ENABLE_ACPI_LOG int acpi_do_log = ENABLE_ACPI_LOG; @@ -55,46 +63,210 @@ acpi_log(const char *fmt, ...) #define acpi_log(fmt, ...) #endif +static uint64_t acpi_clock_get() { + return tsc * cpu_to_acpi; +} + +static uint32_t acpi_timer_get(acpi_t *dev) { + uint64_t clock = acpi_clock_get(); + if (dev->regs.timer32) + return clock & 0xffffffff; + else + return clock & 0xffffff; +} + +static double acpi_get_overflow_period(acpi_t *dev) { + uint64_t timer = acpi_clock_get(); + uint64_t overflow_time; + + if (dev->regs.timer32) { + overflow_time = (timer + 0x80000000LL) & ~0x7fffffffLL; + } else { + overflow_time = (timer + 0x800000LL) & ~0x7fffffLL; + } + + uint64_t time_to_overflow = overflow_time - timer; + + return ((double)time_to_overflow / (double)ACPI_TIMER_FREQ) * 1000000.0; +} static void -acpi_update_irq(void *priv) +acpi_timer_overflow(void *priv) { acpi_t *dev = (acpi_t *) priv; - int sci_level; + dev->regs.pmsts |= TMROF_STS; + acpi_update_irq(dev); +} - sci_level = (dev->regs.pmsts & dev->regs.pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN); - - if (sci_level) { - if (dev->regs.irq_mode == 1) - pci_set_irq(dev->regs.slot, dev->regs.irq_pin); - else - picintlevel(1 << 9); +static void +acpi_timer_update(acpi_t *dev, bool enable) +{ + if (enable) { + timer_on_auto(&dev->timer, acpi_get_overflow_period(dev)); } else { - if (dev->regs.irq_mode == 1) - pci_clear_irq(dev->regs.slot, dev->regs.irq_pin); + timer_stop(&dev->timer); + } +} + +void +acpi_update_irq(acpi_t *dev) +{ + int sci_level = (dev->regs.pmsts & dev->regs.pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN); + if (dev->vendor == VEN_SMC) + sci_level |= (dev->regs.pmsts & BM_STS); + + if (sci_level) { + if (dev->irq_mode == 1) + pci_set_irq(dev->slot, dev->irq_pin); + else if (dev->irq_mode == 2) + pci_set_mirq(5, dev->mirq_is_level); else - picintc(1 << 9); + pci_set_mirq(0xf0 | dev->irq_line, 1); + } else { + if (dev->irq_mode == 1) + pci_clear_irq(dev->slot, dev->irq_pin); + else if (dev->irq_mode == 2) + pci_clear_mirq(5, dev->mirq_is_level); + else + pci_clear_mirq(0xf0 | dev->irq_line, 1); + } + + acpi_timer_update(dev, (dev->regs.pmen & TMROF_EN) && !(dev->regs.pmsts & TMROF_STS)); +} + + +void +acpi_raise_smi(void *priv, int do_smi) +{ + acpi_t *dev = (acpi_t *) priv; + + if (dev->regs.glbctl & 0x01) { + if ((dev->vendor == VEN_VIA) || (dev->vendor == VEN_VIA_596B)) { + if ((!dev->regs.smi_lock || !dev->regs.smi_active)) { + if (do_smi) + smi_raise(); + dev->regs.smi_active = 1; + } + } else if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) { + if (do_smi) + smi_raise(); + /* Clear bit 16 of GLBCTL. */ + if (dev->vendor == VEN_INTEL) + dev->regs.glbctl &= ~0x00010000; + else + dev->regs.ali_soft_smi = 1; + } else if (dev->vendor == VEN_SMC) { + if (do_smi) + smi_raise(); + } } } -static void -acpi_raise_smi(void *priv) +static uint32_t +acpi_reg_read_common_regs(int size, uint16_t addr, void *p) { - acpi_t *dev = (acpi_t *) priv; + acpi_t *dev = (acpi_t *) p; + uint32_t ret = 0x00000000; + int shift16, shift32; - if (dev->vendor == VEN_VIA) { - if ((dev->regs.glbctl & 0x01) && (!dev->regs.smi_lock || !dev->regs.smi_active)) { - smi_line = 1; - dev->regs.smi_active = 1; - } - } else { - if (dev->regs.glbctl & 0x01) { - smi_line = 1; - /* Clear bit 16 of GLBCTL. */ - dev->regs.glbctl &= ~0x00010000; - } + addr &= 0x3f; + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x00: case 0x01: + /* PMSTS - Power Management Status Register (IO) */ + ret = (dev->regs.pmsts >> shift16) & 0xff; + if (addr == 0x01) + ret |= (acpi_rtc_status << 2); + break; + case 0x02: case 0x03: + /* PMEN - Power Management Resume Enable Register (IO) */ + ret = (dev->regs.pmen >> shift16) & 0xff; + break; + case 0x04: case 0x05: + /* PMCNTRL - Power Management Control Register (IO) */ + ret = (dev->regs.pmcntrl >> shift16) & 0xff; + if (addr == 0x05) + ret = (ret & 0xdf); /* Bit 5 is write-only. */ + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + /* PMTMR - Power Management Timer Register (IO) */ + ret = (acpi_timer_get(dev) >> shift32) & 0xff; +#ifdef USE_DYNAREC + if (cpu_use_dynarec) + update_tsc(); +#endif + break; } + +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; +} + + +static uint32_t +acpi_reg_read_ali(int size, uint16_t addr, void *p) +{ + acpi_t *dev = (acpi_t *) p; + uint32_t ret = 0x00000000; + int shift16, shift32; + + addr &= 0x3f; + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch(addr) { + case 0x10: case 0x11: case 0x12: case 0x13: + /* PCNTRL - Processor Control Register (IO) */ + ret = (dev->regs.pcntrl >> shift16) & 0xff; + break; + case 0x14: + /* LVL2 - Processor Level 2 Register */ + ret = dev->regs.plvl2; + break; + case 0x15: + /* LVL3 - Processor Level 3 Register */ + ret = dev->regs.plvl3; + break; + case 0x18: case 0x19: + /* GPE0_STS - General Purpose Event0 Status Register */ + ret = (dev->regs.gpsts >> shift16) & 0xff; + break; + case 0x1a: case 0x1b: + /* GPE0_EN - General Purpose Event0 Enable Register */ + ret = (dev->regs.gpen >> shift16) & 0xff; + break; + case 0x1d: case 0x1c: + /* GPE1_STS - General Purpose Event1 Status Register */ + ret = (dev->regs.gpsts1 >> shift16) & 0xff; + break; + case 0x1f: case 0x1e: + /* GPE1_EN - General Purpose Event1 Enable Register */ + ret = (dev->regs.gpen1 >> shift16) & 0xff; + break; + case 0x20 ... 0x27: + /* GPE1_CTL - General Purpose Event1 Control Register */ + ret = (dev->regs.gpcntrl >> shift32) & 0xff; + break; + case 0x30: + /* PM2_CNTRL - Power Management 2 Control Register( */ + ret = dev->regs.pmcntrl; + break; + default: + ret = acpi_reg_read_common_regs(size, addr, p); + break; + } + +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; } @@ -110,26 +282,6 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p) shift32 = (addr & 3) << 3; switch (addr) { - case 0x00: case 0x01: - /* PMSTS - Power Management Status Register (IO) */ - ret = (dev->regs.pmsts >> shift16) & 0xff; - break; - case 0x02: case 0x03: - /* PMEN - Power Management Resume Enable Register (IO) */ - ret = (dev->regs.pmen >> shift16) & 0xff; - break; - case 0x04: case 0x05: - /* PMCNTRL - Power Management Control Register (IO) */ - ret = (dev->regs.pmcntrl >> shift16) & 0xff; - break; - case 0x08: case 0x09: case 0x0a: case 0x0b: - /* PMTMR - Power Management Timer Register (IO) */ - ret = (dev->regs.timer_val >> shift32) & 0xff; -#ifdef USE_DYNAREC - if (cpu_use_dynarec) - update_tsc(); -#endif - break; case 0x0c: case 0x0d: /* GPSTS - General Purpose Status Register (IO) */ ret = (dev->regs.gpsts >> shift16) & 0xff; @@ -146,7 +298,7 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p) /* GLBSTS - Global Status Register (IO) */ ret = (dev->regs.glbsts >> shift16) & 0xff; if (addr == 0x18) { - ret &= 0x25; + ret &= 0x27; if (dev->regs.gpsts != 0x0000) ret |= 0x80; if (dev->regs.pmsts != 0x0000) @@ -181,15 +333,21 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p) if (size == 1) ret = dev->regs.gporeg[addr & 3]; break; + default: + ret = acpi_reg_read_common_regs(size, addr, p); + break; } - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + // if (size != 1) + // acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } static uint32_t -acpi_reg_read_via(int size, uint16_t addr, void *p) +acpi_reg_read_via_common(int size, uint16_t addr, void *p) { acpi_t *dev = (acpi_t *) p; uint32_t ret = 0x00000000; @@ -200,26 +358,6 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) shift32 = (addr & 3) << 3; switch (addr) { - case 0x00: case 0x01: - /* PMSTS - Power Management Status Register (IO) */ - ret = (dev->regs.pmsts >> shift16) & 0xff; - break; - case 0x02: case 0x03: - /* PMEN - Power Management Resume Enable Register (IO) */ - ret = (dev->regs.pmen >> shift16) & 0xff; - break; - case 0x04: case 0x05: - /* PMCNTRL - Power Management Control Register (IO) */ - ret = (dev->regs.pmcntrl >> shift16) & 0xff; - break; - case 0x08: case 0x09: case 0x0a: case 0x0b: - /* PMTMR - Power Management Timer Register (IO) */ - ret = (dev->regs.timer_val >> shift32) & 0xff; -#ifdef USE_DYNAREC - if (cpu_use_dynarec) - update_tsc(); -#endif - break; case 0x10: case 0x11: case 0x12: case 0x13: /* PCNTRL - Processor Control Register (IO) */ ret = (dev->regs.pcntrl >> shift32) & 0xff; @@ -272,6 +410,30 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) /* GP Timer Reload Enable */ ret = (dev->regs.gptren >> shift32) & 0xff; break; + default: + ret = acpi_reg_read_common_regs(size, addr, p); + break; + } + +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; +} + + +static uint32_t +acpi_reg_read_via(int size, uint16_t addr, void *p) +{ + acpi_t *dev = (acpi_t *) p; + uint32_t ret = 0x00000000; + int shift16; + + addr &= 0xff; + shift16 = (addr & 1) << 3; + + switch (addr) { case 0x40: /* GPIO Direction Control */ if (size == 1) @@ -280,12 +442,21 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) case 0x42: /* GPIO port Output Value */ if (size == 1) - ret = dev->regs.gpio_val & 0xff; + ret = dev->regs.gpio_val & 0x13; break; case 0x44: - /* GPIO port Output Value */ - if (size == 1) + /* GPIO port Input Value */ + if (size == 1) { ret = dev->regs.extsmi_val & 0xff; + + if (dev->i2c) { + ret &= 0xf9; + if (!(dev->regs.gpio_dir & 0x02) && i2c_gpio_get_scl(dev->i2c)) + ret |= 0x02; + if (!(dev->regs.gpio_dir & 0x04) && i2c_gpio_get_sda(dev->i2c)) + ret |= 0x04; + } + } break; case 0x46: case 0x47: /* GPO Port Output Value */ @@ -295,6 +466,110 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) /* GPO Port Input Value */ ret = (dev->regs.gpi_val >> shift16) & 0xff; break; + default: + ret = acpi_reg_read_via_common(size, addr, p); + break; + } + +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; +} + + +static uint32_t +acpi_reg_read_via_596b(int size, uint16_t addr, void *p) +{ + acpi_t *dev = (acpi_t *) p; + uint32_t ret = 0x00000000; + int shift16, shift32; + + addr &= 0x7f; + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x40: /* Extended I/O Trap Status (686A/B) */ + ret = dev->regs.extiotrapsts; + break; + case 0x42: /* Extended I/O Trap Enable (686A/B) */ + ret = dev->regs.extiotrapen; + break; + case 0x44: case 0x45: + /* External SMI Input Value */ + ret = (dev->regs.extsmi_val >> shift16) & 0xff; + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + /* GPI Port Input Value */ + ret = (dev->regs.gpi_val >> shift32) & 0xff; + break; + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + /* GPO Port Output Value */ + ret = (dev->regs.gpo_val >> shift32) & 0xff; + break; + default: + ret = acpi_reg_read_via_common(size, addr, p); + break; + } + +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; +} + + +static uint32_t +acpi_reg_read_smc(int size, uint16_t addr, void *p) +{ + uint32_t ret = 0x00000000; + + addr &= 0x0f; + + ret = acpi_reg_read_common_regs(size, addr, p); + +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif + return ret; +} + + +static uint32_t +acpi_aux_reg_read_smc(int size, uint16_t addr, void *p) +{ + acpi_t *dev = (acpi_t *) p; + uint32_t ret = 0x00000000; + int shift16; + + addr &= 0x07; + shift16 = (addr & 1) << 3; + + switch (addr) { + case 0x00: case 0x01: + /* SCI Status Register */ + ret = (dev->regs.pcntrl >> shift16) & 0xff; + break; + case 0x02: case 0x03: + /* SCI Enable Register */ + ret = (dev->regs.gpscien >> shift16) & 0xff; + break; + case 0x04: case 0x05: + /* Miscellaneous Status Register */ + ret = (dev->regs.glbsts >> shift16) & 0xff; + break; + case 0x06: + /* Miscellaneous Enable Register */ + ret = dev->regs.glben & 0xff; + break; + case 0x07: + /* Miscellaneous Control Register */ + ret = dev->regs.glbctl & 0xff; + break; } acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); @@ -303,21 +578,24 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) static void -acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) +acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; - int shift16, shift32; - int sus_typ; + int shift16, sus_typ; addr &= 0x3f; - acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#endif shift16 = (addr & 1) << 3; - shift32 = (addr & 3) << 3; switch (addr) { case 0x00: case 0x01: /* PMSTS - Power Management Status Register (IO) */ dev->regs.pmsts &= ~((val << shift16) & 0x8d31); + if ((addr == 0x01) && (val & 0x04)) + acpi_rtc_status = 0; acpi_update_irq(dev); break; case 0x02: case 0x03: @@ -327,42 +605,133 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) break; case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ - dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07; - /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ - if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { - dev->regs.glbsts |= 0x01; - if (dev->regs.glben & 0x02) - acpi_raise_smi(dev); - } - if (dev->regs.pmcntrl & 0x2000) { - sus_typ = (dev->regs.pmcntrl >> 10) & 7; - switch (sus_typ) { - case 0: - /* Soft power off. */ - exit(-1); - break; - case 1: + if ((addr == 0x05) && (val & 0x20)) { + sus_typ = dev->suspend_types[(val >> 2) & 7]; + + if (sus_typ & SUS_POWER_OFF) { + /* Soft power off. */ + plat_power_off(); + return; + } + + if (sus_typ & SUS_SUSPEND) { + if (sus_typ & SUS_NVR) { /* Suspend to RAM. */ nvr_reg_write(0x000f, 0xff, dev->nvr); + } - /* Do a hard reset. */ + if (sus_typ & SUS_RESET_PCI) device_reset_all_pci(); + if (sus_typ & SUS_RESET_CPU) cpu_alt_reset = 0; + if (sus_typ & SUS_RESET_PCI) { pci_reset(); keyboard_at_reset(); mem_a20_alt = 0; mem_a20_recalc(); + } + if (sus_typ & (SUS_RESET_CPU | SUS_RESET_CACHE)) flushmmucache(); + if (sus_typ & SUS_RESET_CPU) resetx86(); - break; + + /* Since the UI doesn't have a power button at the moment, pause emulation, + then trigger a resume event so that the system resumes after unpausing. */ + plat_pause(1); + timer_set_delay_u64(&dev->resume_timer, 50 * TIMER_USEC); } } + dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3f07 /* 0x3c07 */; break; + } +} + + +static void +acpi_reg_write_ali(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + int shift16, shift32; + + addr &= 0x3f; +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#endif + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x10: case 0x11: case 0x12: case 0x13: + /* PCNTRL - Processor Control Register (IO) */ + dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00023e1e; + break; + case 0x14: + /* LVL2 - Processor Level 2 Register */ + dev->regs.plvl2 = val; + break; + case 0x15: + /* LVL3 - Processor Level 3 Register */ + dev->regs.plvl3 = val; + break; + case 0x18: case 0x19: + /* GPE0_STS - General Purpose Event0 Status Register */ + dev->regs.gpsts &= ~((val << shift16) & 0x0d07); + break; + case 0x1a: case 0x1b: + /* GPE0_EN - General Purpose Event0 Enable Register */ + dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0d07; + break; + case 0x1d: case 0x1c: + /* GPE1_STS - General Purpose Event1 Status Register */ + dev->regs.gpsts1 &= ~((val << shift16) & 0x0c01); + break; + case 0x1f: case 0x1e: + /* GPE1_EN - General Purpose Event1 Enable Register */ + dev->regs.gpen1 = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0c01; + break; + case 0x20 ... 0x27: + /* GPE1_CTL - General Purpose Event1 Control Register */ + dev->regs.gpcntrl = ((dev->regs.gpcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00000001; + break; + case 0x30: + /* PM2_CNTRL - Power Management 2 Control Register( */ + dev->regs.pmcntrl = val & 1; + break; + default: + acpi_reg_write_common_regs(size, addr, val, p); + /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ + if ((addr == 0x00) && !(dev->regs.pmsts & 0x20)) + dev->regs.gpcntrl &= ~0x0002; + else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { + dev->regs.gpsts1 |= 0x01; + if (dev->regs.gpen1 & 0x01) + acpi_raise_smi(dev, 1); + } + } +} + + +static void +acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + int shift16, shift32; + + addr &= 0x3f; +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#endif + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { case 0x0c: case 0x0d: /* GPSTS - General Purpose Status Register (IO) */ dev->regs.gpsts &= ~((val << shift16) & 0x0f81); @@ -371,13 +740,17 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) /* GPEN - General Purpose Enable Register (IO) */ dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0f01; break; - case 0x10: case 0x11: case 0x12: case 0x13: + case 0x10: case 0x11: case 0x13: /* PCNTRL - Processor Control Register (IO) */ dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00023e1e; break; + case 0x12: + /* PCNTRL - Processor Control Register (IO) */ + dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xfd << shift32)) | (val << shift32)) & 0x00023e1e; + break; case 0x18: case 0x19: /* GLBSTS - Global Status Register (IO) */ - dev->regs.glbsts &= ~((val << shift16) & 0x0df7); + dev->regs.glbsts &= ~((val << shift16) & 0x0d27); break; case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* DEVSTS - Device Status Register (IO) */ @@ -400,22 +773,34 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) case 0x2c: case 0x2d: case 0x2e: case 0x2f: /* DEVCTL - Device Control Register (IO) */ dev->regs.devctl = ((dev->regs.devctl & ~(0xff << shift32)) | (val << shift32)) & 0x0fffffff; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); break; case 0x34: case 0x35: case 0x36: case 0x37: /* GPOREG - General Purpose Output Register (IO) */ if (size == 1) dev->regs.gporeg[addr & 3] = val; break; + default: + acpi_reg_write_common_regs(size, addr, val, p); + /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ + if ((addr == 0x00) && !(dev->regs.pmsts & 0x20)) + dev->regs.glbctl &= ~0x0002; + else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { + dev->regs.glbsts |= 0x01; + if (dev->regs.glben & 0x02) + acpi_raise_smi(dev, 1); + } + break; } } static void -acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) +acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; int shift16, shift32; - int sus_typ; addr &= 0xff; acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); @@ -423,56 +808,6 @@ acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) shift32 = (addr & 3) << 3; switch (addr) { - case 0x00: case 0x01: - /* PMSTS - Power Management Status Register (IO) */ - dev->regs.pmsts &= ~((val << shift16) & 0x8d31); - acpi_update_irq(dev); - if ((addr == 0x00) && !(dev->regs.pmsts & 0x20)) - dev->regs.glbctl &= ~0x0002; - break; - case 0x02: case 0x03: - /* PMEN - Power Management Resume Enable Register (IO) */ - dev->regs.pmen = ((dev->regs.pmen & ~(0xff << shift16)) | (val << shift16)) & 0x0521; - acpi_update_irq(dev); - break; - case 0x04: case 0x05: - /* PMCNTRL - Power Management Control Register (IO) */ - dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07; - /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ - if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { - dev->regs.glbsts |= 0x20; - if (dev->regs.glben & 0x20) - acpi_raise_smi(dev); - } - if (dev->regs.pmcntrl & 0x2000) { - sus_typ = (dev->regs.pmcntrl >> 10) & 7; - switch (sus_typ) { - case 0: - /* Soft power off. */ - exit(-1); - break; - case 1: - /* Suspend to RAM. */ - nvr_reg_write(0x000f, 0xff, dev->nvr); - - /* Do a hard reset. */ - device_reset_all_pci(); - - cpu_alt_reset = 0; - - pci_reset(); - keyboard_at_reset(); - - mem_a20_alt = 0; - mem_a20_recalc(); - - flushmmucache(); - - resetx86(); - break; - } - } - break; case 0x10: case 0x11: case 0x12: case 0x13: /* PCNTRL - Processor Control Register (IO) */ dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x0000001e; @@ -493,14 +828,6 @@ acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) /* Power Supply Control */ dev->regs.pscntrl = ((dev->regs.pscntrl & ~(0xff << shift16)) | (val << shift16)) & 0x0701; break; - case 0x28: case 0x29: - /* GLBSTS - Global Status Register (IO) */ - dev->regs.glbsts &= ~((val << shift16) & 0x007f); - break; - case 0x2a: case 0x2b: - /* GLBEN - Global Enable Register (IO) */ - dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0x007f; - break; case 0x2c: /* GLBCTL - Global Control Register (IO) */ dev->regs.glbctl = (dev->regs.glbctl & ~0xff) | (val & 0xff); @@ -524,9 +851,56 @@ acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) dev->regs.smicmd = val & 0xff; dev->regs.glbsts |= 0x40; if (dev->regs.glben & 0x40) - acpi_raise_smi(dev); + acpi_raise_smi(dev, 1); } break; + case 0x38: case 0x39: case 0x3a: case 0x3b: + /* GP Timer Reload Enable */ + dev->regs.gptren = ((dev->regs.gptren & ~(0xff << shift32)) | (val << shift32)) & 0x000000d9; + break; + default: + acpi_reg_write_common_regs(size, addr, val, p); + /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ + if ((addr == 0x00) && !(dev->regs.pmsts & 0x20)) + dev->regs.glbctl &= ~0x0002; + else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { + dev->regs.glbsts |= 0x20; + if (dev->regs.glben & 0x20) + acpi_raise_smi(dev, 1); + } + break; + } +} + + +static void +acpi_i2c_set(acpi_t *dev) +{ + if (dev->i2c) + i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); +} + + +static void +acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + int shift16, shift32; + + addr &= 0xff; + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x28: case 0x29: + /* GLBSTS - Global Status Register (IO) */ + dev->regs.glbsts &= ~((val << shift16) & 0x007f); + break; + case 0x2a: case 0x2b: + /* GLBEN - Global Enable Register (IO) */ + dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0x007f; + break; case 0x30: case 0x31: case 0x32: case 0x33: /* Primary Activity Detect Status */ dev->regs.padsts &= ~((val << shift32) & 0x000000fd); @@ -534,25 +908,143 @@ acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) case 0x34: case 0x35: case 0x36: case 0x37: /* Primary Activity Detect Enable */ dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000000fd; - break; - case 0x38: case 0x39: case 0x3a: case 0x3b: - /* GP Timer Reload Enable */ - dev->regs.gptren = ((dev->regs.gptren & ~(0xff << shift32)) | (val << shift32)) & 0x000000d9; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); break; case 0x40: /* GPIO Direction Control */ - if (size == 1) - dev->regs.gpio_dir = val & 0xff; + if (size == 1) { + dev->regs.gpio_dir = val & 0x7f; + acpi_i2c_set(dev); + } break; case 0x42: /* GPIO port Output Value */ - if (size == 1) - dev->regs.gpio_val = val & 0xff; + if (size == 1) { + dev->regs.gpio_val = val & 0x13; + acpi_i2c_set(dev); + } break; case 0x46: case 0x47: /* GPO Port Output Value */ dev->regs.gpo_val = ((dev->regs.gpo_val & ~(0xff << shift16)) | (val << shift16)) & 0xffff; break; + default: + acpi_reg_write_via_common(size, addr, val, p); + break; + } +} + + +static void +acpi_reg_write_via_596b(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + int shift16, shift32; + + addr &= 0x7f; + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); + shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; + + switch (addr) { + case 0x28: case 0x29: + /* GLBSTS - Global Status Register (IO) */ + dev->regs.glbsts &= ~((val << shift16) & 0xfdff); + break; + case 0x2a: case 0x2b: + /* GLBEN - Global Enable Register (IO) */ + dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0xfdff; + break; + case 0x30: case 0x31: case 0x32: case 0x33: + /* Primary Activity Detect Status */ + dev->regs.padsts &= ~((val << shift32) & 0x000007ff); + break; + case 0x34: case 0x35: case 0x36: case 0x37: + /* Primary Activity Detect Enable */ + dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000007ff; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); + break; + case 0x40: /* Extended I/O Trap Status (686A/B) */ + dev->regs.extiotrapsts &= ~(val & 0x13); + break; + case 0x42: /* Extended I/O Trap Enable (686A/B) */ + dev->regs.extiotrapen = val & 0x13; + break; + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + /* GPO Port Output Value */ + dev->regs.gpo_val = ((dev->regs.gpo_val & ~(0xff << shift32)) | (val << shift32)) & 0x7fffffff; + break; + default: + acpi_reg_write_via_common(size, addr, val, p); + break; + } +} + + +static void +acpi_reg_write_smc(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + + addr &= 0x0f; + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); + + acpi_reg_write_common_regs(size, addr, val, p); + /* Setting GBL_RLS also sets BIOS_STS and generates SMI. */ + if ((addr == 0x00) && !(dev->regs.pmsts & 0x20)) + dev->regs.glbctl &= ~0x0001; + else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) { + dev->regs.glbsts |= 0x01; + if (dev->regs.glben & 0x01) + acpi_raise_smi(dev, 1); + } +} + + +static void +acpi_aux_reg_write_smc(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + int shift16; + + addr &= 0x07; + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); + shift16 = (addr & 1) << 3; + + switch (addr) { + case 0x00: case 0x01: + /* SCI Status Register */ + dev->regs.gpscists &= ~((val << shift16) & 0x000c); + break; + case 0x02: case 0x03: + /* SCI Enable Register */ + dev->regs.gpscien = ((dev->regs.gpscien & ~(0xff << shift16)) | (val << shift16)) & 0x3fff; + break; + case 0x04: case 0x05: + /* Miscellanous Status Register */ + dev->regs.glbsts &= ~((val << shift16) & 0x001f); + break; + case 0x06: + /* Miscellaneous Enable Register */ + dev->regs.glben = (uint16_t) (val & 0x03); + break; + case 0x07: + /* Miscellaneous Control Register */ + dev->regs.glbctl = (uint16_t) (val & 0x03); + /* Setting BIOS_RLS also sets GBL_STS and generates SMI. */ + if (dev->regs.glbctl & 0x0001) { + dev->regs.pmsts |= 0x20; + if (dev->regs.pmen & 0x20) + acpi_update_irq(dev); + } + if (dev->regs.glbctl & 0x0002) { + dev->regs.pmsts |= 0x10; + if (dev->regs.pmcntrl & 0x02) + acpi_update_irq(dev); + } + break; } } @@ -563,10 +1055,16 @@ acpi_reg_read_common(int size, uint16_t addr, void *p) acpi_t *dev = (acpi_t *) p; uint8_t ret = 0xff; - if (dev->vendor == VEN_VIA) + if (dev->vendor == VEN_ALI) + ret = acpi_reg_read_ali(size, addr, p); + else if (dev->vendor == VEN_VIA) ret = acpi_reg_read_via(size, addr, p); - else + else if (dev->vendor == VEN_VIA_596B) + ret = acpi_reg_read_via_596b(size, addr, p); + else if (dev->vendor == VEN_INTEL) ret = acpi_reg_read_intel(size, addr, p); + else if (dev->vendor == VEN_SMC) + ret = acpi_reg_read_smc(size, addr, p); return ret; } @@ -577,10 +1075,39 @@ acpi_reg_write_common(int size, uint16_t addr, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; - if (dev->vendor == VEN_VIA) + if (dev->vendor == VEN_ALI) + acpi_reg_write_ali(size, addr, val, p); + else if (dev->vendor == VEN_VIA) acpi_reg_write_via(size, addr, val, p); - else + else if (dev->vendor == VEN_VIA_596B) + acpi_reg_write_via_596b(size, addr, val, p); + else if (dev->vendor == VEN_INTEL) acpi_reg_write_intel(size, addr, val, p); + else if (dev->vendor == VEN_SMC) + acpi_reg_write_smc(size, addr, val, p); +} + + +static uint32_t +acpi_aux_reg_read_common(int size, uint16_t addr, void *p) +{ + acpi_t *dev = (acpi_t *) p; + uint8_t ret = 0xff; + + if (dev->vendor == VEN_SMC) + ret = acpi_aux_reg_read_smc(size, addr, p); + + return ret; +} + + +static void +acpi_aux_reg_write_common(int size, uint16_t addr, uint8_t val, void *p) +{ + acpi_t *dev = (acpi_t *) p; + + if (dev->vendor == VEN_SMC) + acpi_aux_reg_write_smc(size, addr, val, p); } @@ -621,6 +1148,51 @@ acpi_reg_read(uint16_t addr, void *p) ret = acpi_reg_read_common(1, addr, p); + acpi_log("ACPI: Read B %02X from %04X\n", ret, addr); + + return ret; +} + + +static uint32_t +acpi_aux_reg_readl(uint16_t addr, void *p) +{ + uint32_t ret = 0x00000000; + + ret = acpi_aux_reg_read_common(4, addr, p); + ret |= (acpi_aux_reg_read_common(4, addr + 1, p) << 8); + ret |= (acpi_aux_reg_read_common(4, addr + 2, p) << 16); + ret |= (acpi_aux_reg_read_common(4, addr + 3, p) << 24); + + acpi_log("ACPI: Read Aux L %08X from %04X\n", ret, addr); + + return ret; +} + + +static uint16_t +acpi_aux_reg_readw(uint16_t addr, void *p) +{ + uint16_t ret = 0x0000; + + ret = acpi_aux_reg_read_common(2, addr, p); + ret |= (acpi_aux_reg_read_common(2, addr + 1, p) << 8); + + acpi_log("ACPI: Read Aux W %04X from %04X\n", ret, addr); + + return ret; +} + + +static uint8_t +acpi_aux_reg_read(uint16_t addr, void *p) +{ + uint8_t ret = 0x00; + + ret = acpi_aux_reg_read_common(1, addr, p); + + acpi_log("ACPI: Read Aux B %02X from %04X\n", ret, addr); + return ret; } @@ -628,16 +1200,20 @@ acpi_reg_read(uint16_t addr, void *p) static void acpi_reg_writel(uint16_t addr, uint32_t val, void *p) { + acpi_log("ACPI: Write L %08X to %04X\n", val, addr); + acpi_reg_write_common(4, addr, val & 0xff, p); acpi_reg_write_common(4, addr + 1, (val >> 8) & 0xff, p); - acpi_reg_write_common(4, addr + 1, (val >> 16) & 0xff, p); - acpi_reg_write_common(4, addr + 1, (val >> 24) & 0xff, p); + acpi_reg_write_common(4, addr + 2, (val >> 16) & 0xff, p); + acpi_reg_write_common(4, addr + 3, (val >> 24) & 0xff, p); } static void acpi_reg_writew(uint16_t addr, uint16_t val, void *p) { + acpi_log("ACPI: Write W %04X to %04X\n", val, addr); + acpi_reg_write_common(2, addr, val & 0xff, p); acpi_reg_write_common(2, addr + 1, (val >> 8) & 0xff, p); } @@ -646,52 +1222,125 @@ acpi_reg_writew(uint16_t addr, uint16_t val, void *p) static void acpi_reg_write(uint16_t addr, uint8_t val, void *p) { + acpi_log("ACPI: Write B %02X to %04X\n", val, addr); + acpi_reg_write_common(1, addr, val, p); } +static void +acpi_aux_reg_writel(uint16_t addr, uint32_t val, void *p) +{ + acpi_log("ACPI: Write Aux L %08X to %04X\n", val, addr); + + acpi_aux_reg_write_common(4, addr, val & 0xff, p); + acpi_aux_reg_write_common(4, addr + 1, (val >> 8) & 0xff, p); + acpi_aux_reg_write_common(4, addr + 2, (val >> 16) & 0xff, p); + acpi_aux_reg_write_common(4, addr + 3, (val >> 24) & 0xff, p); +} + + +static void +acpi_aux_reg_writew(uint16_t addr, uint16_t val, void *p) +{ + acpi_log("ACPI: Write Aux W %04X to %04X\n", val, addr); + + acpi_aux_reg_write_common(2, addr, val & 0xff, p); + acpi_aux_reg_write_common(2, addr + 1, (val >> 8) & 0xff, p); +} + + +static void +acpi_aux_reg_write(uint16_t addr, uint8_t val, void *p) +{ + acpi_log("ACPI: Write Aux B %02X to %04X\n", val, addr); + + acpi_aux_reg_write_common(1, addr, val, p); +} + + void acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) { - if (dev->regs.io_base != 0x0000) { - io_removehandler(dev->regs.io_base, 0x40, + int size; + + switch (dev->vendor) { + case VEN_ALI: + case VEN_INTEL: + default: + size = 0x040; + break; + case VEN_SMC: + size = 0x010; + break; + case VEN_VIA: + size = 0x100; + break; + case VEN_VIA_596B: + size = 0x080; + break; + } + + acpi_log("ACPI: Update I/O %04X to %04X (%sabled)\n", dev->io_base, base, chipset_en ? "en" : "dis"); + + if (dev->io_base != 0x0000) { + io_removehandler(dev->io_base, size, acpi_reg_read, acpi_reg_readw, acpi_reg_readl, acpi_reg_write, acpi_reg_writew, acpi_reg_writel, dev); } - dev->regs.io_base = base; + dev->io_base = base; - if (chipset_en && (dev->regs.io_base != 0x0000)) { - io_sethandler(dev->regs.io_base, 0x40, + if (chipset_en && (dev->io_base != 0x0000)) { + io_sethandler(dev->io_base, size, acpi_reg_read, acpi_reg_readw, acpi_reg_readl, acpi_reg_write, acpi_reg_writew, acpi_reg_writel, dev); } } +void +acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en) +{ + int size; + + switch (dev->vendor) { + case VEN_SMC: + size = 0x008; + break; + default: + size = 0x000; + break; + } + + acpi_log("ACPI: Update Aux I/O %04X to %04X (%sabled)\n", dev->aux_io_base, base, chipset_en ? "en" : "dis"); + + if (dev->aux_io_base != 0x0000) { + io_removehandler(dev->aux_io_base, size, + acpi_aux_reg_read, acpi_aux_reg_readw, acpi_aux_reg_readl, + acpi_aux_reg_write, acpi_aux_reg_writew, acpi_aux_reg_writel, dev); + } + + dev->aux_io_base = base; + + if (chipset_en && (dev->aux_io_base != 0x0000)) { + io_sethandler(dev->aux_io_base, size, + acpi_aux_reg_read, acpi_aux_reg_readw, acpi_aux_reg_readl, + acpi_aux_reg_write, acpi_aux_reg_writew, acpi_aux_reg_writel, dev); + } +} + static void -acpi_timer_count(void *priv) +acpi_timer_resume(void *priv) { acpi_t *dev = (acpi_t *) priv; - int overflow; - uint32_t old; - old = dev->regs.timer_val; - dev->regs.timer_val++; + dev->regs.pmsts |= 0x8000; - if (dev->regs.timer32) - overflow = (old ^ dev->regs.timer_val) & 0x80000000; - else { - dev->regs.timer_val &= 0x00ffffff; - overflow = (old ^ dev->regs.timer_val) & 0x00800000; - } - - if (overflow) { - dev->regs.pmsts |= TMROF_EN; - acpi_update_irq(dev); - } - - timer_advance_u64(&dev->timer, ACPICONST); + /* Nasty workaround for ASUS P2B-LS and potentially others, where the PMCNTRL + SMI trap handler clears the resume bit before returning control to the OS. */ + if (in_smm) + timer_set_delay_u64(&dev->resume_timer, 50 * TIMER_USEC); } @@ -710,30 +1359,49 @@ void acpi_set_timer32(acpi_t *dev, uint8_t timer32) { dev->regs.timer32 = timer32; - - if (!dev->regs.timer32) - dev->regs.timer_val &= 0x00ffffff; } void acpi_set_slot(acpi_t *dev, int slot) { - dev->regs.slot = slot; + dev->slot = slot; } void acpi_set_irq_mode(acpi_t *dev, int irq_mode) { - dev->regs.irq_mode = irq_mode; + dev->irq_mode = irq_mode; } void acpi_set_irq_pin(acpi_t *dev, int irq_pin) { - dev->regs.irq_pin = irq_pin; + dev->irq_pin = irq_pin; +} + + +void +acpi_set_irq_line(acpi_t *dev, int irq_line) +{ + dev->irq_line = irq_line; +} + + +void +acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level) +{ + dev->mirq_is_level = mirq_is_level; +} + + +void +acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default) +{ + dev->gpireg2_default = gpireg2_default; + dev->regs.gpireg[2] = dev->gpireg2_default; } @@ -744,24 +1412,56 @@ acpi_set_nvr(acpi_t *dev, nvr_t *nvr) } +void +acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv) +{ + dev->trap_update = update; + dev->trap_priv = priv; +} + + +uint8_t +acpi_ali_soft_smi_status_read(acpi_t *dev) +{ + return dev->regs.ali_soft_smi = 1; +} + + +void +acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi) +{ + dev->regs.ali_soft_smi = soft_smi; +} + + static void acpi_apm_out(uint16_t port, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; - acpi_log("[%04X:%08X] APM write: %04X = %02X (BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, BX, CX); + acpi_log("[%04X:%08X] APM write: %04X = %02X (AX = %04X, BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, AX, BX, CX); port &= 0x0001; - if (port == 0x0000) { - dev->apm->cmd = val; - if (dev->apm->do_smi) { + if (dev->vendor == VEN_ALI) { + if (port == 0x0001) { + acpi_log("ALi SOFT SMI# status set (%i)\n", dev->apm->do_smi); + dev->apm->cmd = val; + // acpi_raise_smi(dev, dev->apm->do_smi); + if (dev->apm->do_smi) + smi_raise(); + dev->regs.ali_soft_smi = 1; + } else if (port == 0x0003) + dev->apm->stat = val; + } else { + if (port == 0x0000) { + dev->apm->cmd = val; if (dev->vendor == VEN_INTEL) dev->regs.glbsts |= 0x20; - acpi_raise_smi(dev); - } - } else - dev->apm->stat = val; + acpi_raise_smi(dev, dev->apm->do_smi); + } else + dev->apm->stat = val; + } } @@ -773,10 +1473,17 @@ acpi_apm_in(uint16_t port, void *p) port &= 0x0001; - if (port == 0x0000) - ret = dev->apm->cmd; - else - ret = dev->apm->stat; + if (dev->vendor == VEN_ALI) { + if (port == 0x0001) + ret = dev->apm->cmd; + else if (port == 0x0003) + ret = dev->apm->stat; + } else { + if (port == 0x0000) + ret = dev->apm->cmd; + else + ret = dev->apm->stat; + } acpi_log("[%04X:%08X] APM read: %04X = %02X\n", CS, cpu_state.pc, port, ret); @@ -791,9 +1498,43 @@ acpi_reset(void *priv) int i; memset(&dev->regs, 0x00, sizeof(acpi_regs_t)); - dev->regs.gpireg[0] = dev->regs.gpireg[1] = dev->regs.gpireg[2] = 0xff; + dev->regs.gpireg[0] = 0xff; dev->regs.gpireg[1] = 0xff; + /* A-Trend ATC7020BXII: + - Bit 3: 80-conductor cable on secondary IDE channel (active low) + - Bit 2: 80-conductor cable on primary IDE channel (active low) + Gigabyte GA-686BX: + - Bit 1: CMOS battery low (active high) */ + dev->regs.gpireg[2] = dev->gpireg2_default; for (i = 0; i < 4; i++) dev->regs.gporeg[i] = dev->gporeg_default[i]; + if (dev->vendor == VEN_VIA_596B) { + dev->regs.gpo_val = 0x7fffffff; + /* FIC VA-503A: + - Bit 11: ATX power (active high) + - Bit 4: 80-conductor cable on primary IDE channel (active low) + - Bit 3: 80-conductor cable on secondary IDE channel (active low) + - Bit 2: password cleared (active low) + ASUS P3V4X: + - Bit 15: 80-conductor cable on secondary IDE channel (active low) + - Bit 5: 80-conductor cable on primary IDE channel (active low) + BCM GT694VA: + - Bit 19: 80-conductor cable on secondary IDE channel (active low) + - Bit 17: 80-conductor cable on primary IDE channel (active low) + ASUS CUV4X-LS: + - Bit 2: 80-conductor cable on secondary IDE channel (active low) + - Bit 1: 80-conductor cable on primary IDE channel (active low) + Acorp 6VIA90AP: + - Bit 3: 80-conductor cable on secondary IDE channel (active low) + - Bit 1: 80-conductor cable on primary IDE channel (active low) */ + dev->regs.gpi_val = 0xfff57fc1; + if (!strcmp(machine_get_internal_name(), "ficva503a") || !strcmp(machine_get_internal_name(), "6via90ap")) + dev->regs.gpi_val |= 0x00000004; + } + + /* Power on always generates a resume event. */ + dev->regs.pmsts |= 0x8000; + + acpi_rtc_status = 0; } @@ -801,9 +1542,12 @@ static void acpi_speed_changed(void *priv) { acpi_t *dev = (acpi_t *) priv; + cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock; + bool timer_enabled = timer_is_enabled(&dev->timer); + timer_stop(&dev->timer); - timer_disable(&dev->timer); - timer_set_delay_u64(&dev->timer, ACPICONST); + if (timer_enabled) + timer_on_auto(&dev->timer, acpi_get_overflow_period(dev)); } @@ -812,7 +1556,13 @@ acpi_close(void *priv) { acpi_t *dev = (acpi_t *) priv; - timer_disable(&dev->timer); + if (dev->i2c) { + if (i2c_smbus == i2c_gpio_get_bus(dev->i2c)) + i2c_smbus = NULL; + i2c_gpio_close(dev->i2c); + } + + timer_stop(&dev->timer); free(dev); } @@ -827,47 +1577,129 @@ acpi_init(const device_t *info) if (dev == NULL) return(NULL); memset(dev, 0x00, sizeof(acpi_t)); + cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock; dev->vendor = info->local; - if (dev->vendor == VEN_INTEL) { + dev->irq_line = 9; + + if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) { + if (dev->vendor == VEN_ALI) + dev->irq_mode = 2; dev->apm = device_add(&apm_pci_acpi_device); - io_sethandler(0x00b2, 0x0002, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); + if (dev->vendor == VEN_ALI) { + acpi_log("Setting I/O handler at port B1\n"); + io_sethandler(0x00b1, 0x0003, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); + } else + io_sethandler(0x00b2, 0x0002, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); + } else if (dev->vendor == VEN_VIA) { + dev->i2c = i2c_gpio_init("smbus_vt82c586b"); + i2c_smbus = i2c_gpio_get_bus(dev->i2c); } - timer_add(&dev->timer, acpi_timer_count, dev, 0); - timer_set_delay_u64(&dev->timer, ACPICONST); + switch (dev->vendor) { + case VEN_ALI: + dev->suspend_types[0] = SUS_POWER_OFF; + dev->suspend_types[1] = SUS_POWER_OFF; + dev->suspend_types[2] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[3] = SUS_SUSPEND; + break; - dev->regs.gpireg[0] = dev->regs.gpireg[1] = dev->regs.gpireg[2] = 0xff; + case VEN_VIA: + dev->suspend_types[0] = SUS_POWER_OFF; + dev->suspend_types[2] = SUS_SUSPEND; + break; + + case VEN_VIA_596B: + dev->suspend_types[1] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[2] = SUS_POWER_OFF; + dev->suspend_types[4] = SUS_SUSPEND; + dev->suspend_types[5] = SUS_SUSPEND | SUS_RESET_CPU; + dev->suspend_types[6] = SUS_SUSPEND | SUS_RESET_CPU | SUS_RESET_PCI; + break; + + case VEN_INTEL: + dev->suspend_types[0] = SUS_POWER_OFF; + dev->suspend_types[1] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI; + dev->suspend_types[2] = SUS_SUSPEND | SUS_RESET_CPU; + dev->suspend_types[3] = SUS_SUSPEND | SUS_RESET_CACHE; + dev->suspend_types[4] = SUS_SUSPEND; + break; + } + + timer_add(&dev->timer, acpi_timer_overflow, dev, 0); + timer_add(&dev->resume_timer, acpi_timer_resume, dev, 0); + + acpi_reset(dev); return dev; } - -const device_t acpi_intel_device = -{ - "ACPI v1.0", - DEVICE_PCI, - VEN_INTEL, - acpi_init, - acpi_close, - acpi_reset, - NULL, - acpi_speed_changed, - NULL, - NULL +const device_t acpi_ali_device = { + .name = "ALi M7101 ACPI", + .internal_name = "acpi_ali", + .flags = DEVICE_PCI, + .local = VEN_ALI, + .init = acpi_init, + .close = acpi_close, + .reset = acpi_reset, + { .available = NULL }, + .speed_changed = acpi_speed_changed, + .force_redraw = NULL, + .config = NULL }; - -const device_t acpi_via_device = -{ - "ACPI v1.2", - DEVICE_PCI, - VEN_VIA, - acpi_init, - acpi_close, - acpi_reset, - NULL, - acpi_speed_changed, - NULL, - NULL +const device_t acpi_intel_device = { + .name = "Intel ACPI", + .internal_name = "acpi_intel", + .flags = DEVICE_PCI, + .local = VEN_INTEL, + .init = acpi_init, + .close = acpi_close, + .reset = acpi_reset, + { .available = NULL }, + .speed_changed = acpi_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t acpi_via_device = { + .name = "VIA ACPI", + .internal_name = "acpi_via", + .flags = DEVICE_PCI, + .local = VEN_VIA, + .init = acpi_init, + .close = acpi_close, + .reset = acpi_reset, + { .available = NULL }, + .speed_changed = acpi_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t acpi_via_596b_device = { + .name = "VIA VT82C596 ACPI", + .internal_name = "acpi_via_596b", + .flags = DEVICE_PCI, + .local = VEN_VIA_596B, + .init = acpi_init, + .close = acpi_close, + .reset = acpi_reset, + { .available = NULL }, + .speed_changed = acpi_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t acpi_smc_device = { + .name = "SMC FDC73C931APM ACPI", + .internal_name = "acpi_smc", + .flags = DEVICE_PCI, + .local = VEN_SMC, + .init = acpi_init, + .close = acpi_close, + .reset = acpi_reset, + { .available = NULL }, + .speed_changed = acpi_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/apm.c b/src/apm.c index 38d223e88..3fe8d54c6 100644 --- a/src/apm.c +++ b/src/apm.c @@ -67,7 +67,7 @@ apm_out(uint16_t port, uint8_t val, void *p) if (port == 0x0000) { dev->cmd = val; if (dev->do_smi) - smi_line = 1; + smi_raise(); } else dev->stat = val; } @@ -123,46 +123,44 @@ static void } -const device_t apm_device = -{ - "Advanced Power Management", - 0, - 0, - apm_init, - apm_close, - NULL, - NULL, - NULL, - NULL, - NULL +const device_t apm_device = { + .name = "Advanced Power Management", + .internal_name = "apm", + .flags = 0, + .local = 0, + .init = apm_init, + .close = apm_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t apm_pci_device = -{ - "Advanced Power Management (PCI)", - DEVICE_PCI, - 0, - apm_init, - apm_close, - apm_reset, - NULL, - NULL, - NULL, - NULL +const device_t apm_pci_device = { + .name = "Advanced Power Management (PCI)", + .internal_name = "apm_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = apm_init, + .close = apm_close, + .reset = apm_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t apm_pci_acpi_device = -{ - "Advanced Power Management (PCI)", - DEVICE_PCI, - 1, - apm_init, - apm_close, - apm_reset, - NULL, - NULL, - NULL, - NULL +const device_t apm_pci_acpi_device = { + .name = "Advanced Power Management (PCI)", + .internal_name = "apm_pci_acpi", + .flags = DEVICE_PCI, + .local = 1, + .init = apm_init, + .close = apm_close, + .reset = apm_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/arch_detect.c b/src/arch_detect.c new file mode 100644 index 000000000..03d3b61e7 --- /dev/null +++ b/src/arch_detect.c @@ -0,0 +1,27 @@ +/* + * 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. + * + * Configure-time architecture detection for the CMake build. + * + * + * + * Authors: David Hrdlička, + * + * Copyright 2020-2021 David Hrdlička. + */ + +#if defined(__arm__) || defined(__TARGET_ARCH_ARM) + #error ARCH arm +#elif defined(__aarch64__) || defined(_M_ARM64) + #error ARCH arm64 +#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) + #error ARCH i386 +#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) + #error ARCH x86_64 +#endif +#error ARCH unknown diff --git a/src/cdrom/CMakeLists.txt b/src/cdrom/CMakeLists.txt new file mode 100644 index 000000000..ecd0d934e --- /dev/null +++ b/src/cdrom/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(cdrom OBJECT cdrom.c cdrom_image_backend.c cdrom_image.c) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 891606606..f57981234 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -8,11 +8,9 @@ * * Generic CD-ROM drive core. * - * - * * Author: Miran Grca, * - * Copyright 2018,2019 Miran Grca. + * Copyright 2018-2021 Miran Grca. */ #include #include @@ -35,21 +33,21 @@ there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #undef MSFtoLBA -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) -#define RAW_SECTOR_SIZE 2352 -#define COOKED_SECTOR_SIZE 2048 +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 -#define MIN_SEEK 2000 -#define MAX_SEEK 333333 +#define MIN_SEEK 2000 +#define MAX_SEEK 333333 -#define CD_BCD(x) (((x) % 10) | (((x) / 10) << 4)) -#define CD_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) +#define CD_BCD(x) (((x) % 10) | (((x) / 10) << 4)) +#define CD_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) #pragma pack(push,1) typedef struct { uint8_t user_data[2048], - ecc[288]; + ecc[288]; } m1_data_t; typedef struct { @@ -89,16 +87,16 @@ typedef union { #pragma pack(pop) -static int cdrom_sector_size; -static uint8_t raw_buffer[2856]; /* Needs to be the same size as sector_buffer_t in the structs. */ -static uint8_t extra_buffer[296]; +static int cdrom_sector_size; +static uint8_t raw_buffer[2856]; /* Needs to be the same size as sector_buffer_t in the structs. */ +static uint8_t extra_buffer[296]; cdrom_t cdrom[CDROM_NUM]; #ifdef ENABLE_CDROM_LOG -int cdrom_do_log = ENABLE_CDROM_LOG; +int cdrom_do_log = ENABLE_CDROM_LOG; void @@ -107,9 +105,9 @@ cdrom_log(const char *fmt, ...) va_list ap; if (cdrom_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else @@ -140,30 +138,30 @@ static double cdrom_get_short_seek(cdrom_t *dev) { switch(dev->cur_speed) { - case 0: - fatal("CD-ROM %i: 0x speed\n", dev->id); - return 0.0; - case 1: - return 240.0; - case 2: - return 160.0; - case 3: - return 150.0; - case 4: case 5: case 6: case 7: case 8: - case 9: case 10: case 11: - return 112.0; - case 12: case 13: case 14: case 15: - return 75.0; - case 16: case 17: case 18: case 19: - return 58.0; - case 20: case 21: case 22: case 23: - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - case 48: - return 50.0; - default: - /* 24-32, 52+ */ - return 45.0; + case 0: + fatal("CD-ROM %i: 0x speed\n", dev->id); + return 0.0; + case 1: + return 240.0; + case 2: + return 160.0; + case 3: + return 150.0; + case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: + return 112.0; + case 12: case 13: case 14: case 15: + return 75.0; + case 16: case 17: case 18: case 19: + return 58.0; + case 20: case 21: case 22: case 23: + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + case 48: + return 50.0; + default: + /* 24-32, 52+ */ + return 45.0; } } @@ -172,30 +170,30 @@ static double cdrom_get_long_seek(cdrom_t *dev) { switch(dev->cur_speed) { - case 0: - fatal("CD-ROM %i: 0x speed\n", dev->id); - return 0.0; - case 1: - return 1446.0; - case 2: - return 1000.0; - case 3: - return 900.0; - case 4: case 5: case 6: case 7: case 8: - case 9: case 10: case 11: - return 675.0; - case 12: case 13: case 14: case 15: - return 400.0; - case 16: case 17: case 18: case 19: - return 350.0; - case 20: case 21: case 22: case 23: - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - case 48: - return 300.0; - default: - /* 24-32, 52+ */ - return 270.0; + case 0: + fatal("CD-ROM %i: 0x speed\n", dev->id); + return 0.0; + case 1: + return 1446.0; + case 2: + return 1000.0; + case 3: + return 900.0; + case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: + return 675.0; + case 12: case 13: case 14: case 15: + return 400.0; + case 16: case 17: case 18: case 19: + return 350.0; + case 20: case 21: case 22: case 23: + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + case 48: + return 300.0; + default: + /* 24-32, 52+ */ + return 270.0; } } @@ -207,9 +205,9 @@ cdrom_seek_time(cdrom_t *dev) double sd = (double) (MAX_SEEK - MIN_SEEK); if (diff < MIN_SEEK) - return 0.0; + return 0.0; if (diff > MAX_SEEK) - diff = MAX_SEEK; + diff = MAX_SEEK; diff -= MIN_SEEK; @@ -221,7 +219,7 @@ void cdrom_stop(cdrom_t *dev) { if (dev->cd_status > CD_STATUS_DATA_ONLY) - dev->cd_status = CD_STATUS_STOPPED; + dev->cd_status = CD_STATUS_STOPPED; } @@ -229,7 +227,7 @@ void cdrom_seek(cdrom_t *dev, uint32_t pos) { if (!dev) - return; + return; cdrom_log("CD-ROM %i: Seek to LBA %08X\n", dev->id, pos); @@ -238,44 +236,51 @@ cdrom_seek(cdrom_t *dev, uint32_t pos) } +int +cdrom_is_pre(cdrom_t *dev, uint32_t lba) +{ + if (dev->ops && dev->ops->is_track_pre) + return dev->ops->is_track_pre(dev, lba); + + return 0; +} + + int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len) { int ret = 1; if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING)) { - cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id); - if (dev->cd_status == CD_STATUS_PLAYING) - dev->seek_pos += (len >> 11); - memset(output, 0, len * 2); - return 0; + cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id); + if (dev->cd_status == CD_STATUS_PLAYING) + dev->seek_pos += (len >> 11); + memset(output, 0, len * 2); + return 0; } while (dev->cd_buflen < len) { - if (dev->seek_pos < dev->cd_end) { - if (dev->ops->read_sector(dev, CD_READ_AUDIO, - (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), - dev->seek_pos)) { - cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos); - dev->seek_pos++; - dev->cd_buflen += (RAW_SECTOR_SIZE / 2); - ret = 1; - } else { - cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos); - memset(&(dev->cd_buffer[dev->cd_buflen]), - 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_status = CD_STATUS_STOPPED; - dev->cd_buflen = len; - ret = 0; - } - } else { - cdrom_log("CD-ROM %i: Playing completed\n", dev->id); - memset(&dev->cd_buffer[dev->cd_buflen], - 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_status = CD_STATUS_PLAYING_COMPLETED; - dev->cd_buflen = len; - ret = 0; - } + if (dev->seek_pos < dev->cd_end) { + if (dev->ops->read_sector(dev, CD_READ_AUDIO, (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), + dev->seek_pos)) { + cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos); + dev->seek_pos++; + dev->cd_buflen += (RAW_SECTOR_SIZE / 2); + ret = 1; + } else { + cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos); + memset(&(dev->cd_buffer[dev->cd_buflen]), 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_status = CD_STATUS_STOPPED; + dev->cd_buflen = len; + ret = 0; + } + } else { + cdrom_log("CD-ROM %i: Playing completed\n", dev->id); + memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_status = CD_STATUS_PLAYING_COMPLETED; + dev->cd_buflen = len; + ret = 0; + } } memcpy(output, dev->cd_buffer, len * 2); @@ -294,51 +299,51 @@ cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) int m = 0, s = 0, f = 0; if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; + return 0; cdrom_log("CD-ROM %i: Play audio - %08X %08X %i\n", dev->id, pos, len, ismsf); if (ismsf & 0x100) { - /* Track-relative audio play. */ - dev->ops->get_track_info(dev, ismsf & 0xff, 0, &ti); - pos += MSFtoLBA(ti.m, ti.s, ti.f) - 150; + /* Track-relative audio play. */ + dev->ops->get_track_info(dev, ismsf & 0xff, 0, &ti); + pos += MSFtoLBA(ti.m, ti.s, ti.f) - 150; } else if (ismsf == 2) { - dev->ops->get_track_info(dev, pos, 0, &ti); - pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - /* We have to end at the *end* of the specified track, - not at the beginning. */ - dev->ops->get_track_info(dev, len, 1, &ti); - len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + dev->ops->get_track_info(dev, pos, 0, &ti); + pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + /* We have to end at the *end* of the specified track, + not at the beginning. */ + dev->ops->get_track_info(dev, len, 1, &ti); + len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; } else if (ismsf == 1) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; - if (pos == 0xffffff) { - cdrom_log("CD-ROM %i: Playing from current position (MSF)\n", dev->id); - pos = dev->seek_pos; - } else - pos = MSFtoLBA(m, s, f) - 150; + if (pos == 0xffffff) { + cdrom_log("CD-ROM %i: Playing from current position (MSF)\n", dev->id); + pos = dev->seek_pos; + } else + pos = MSFtoLBA(m, s, f) - 150; - m = (len >> 16) & 0xff; - s = (len >> 8) & 0xff; - f = len & 0xff; - len = MSFtoLBA(m, s, f) - 150; + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f) - 150; - cdrom_log("CD-ROM %i: MSF - pos = %08X len = %08X\n", dev->id, pos, len); + cdrom_log("CD-ROM %i: MSF - pos = %08X len = %08X\n", dev->id, pos, len); } else if (ismsf == 0) { - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: Playing from current position\n", dev->id); - pos = dev->seek_pos; - } - len += pos; + if (pos == 0xffffffff) { + cdrom_log("CD-ROM %i: Playing from current position\n", dev->id); + pos = dev->seek_pos; + } + len += pos; } /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_stop(dev); + return 0; } dev->seek_pos = pos; @@ -349,30 +354,31 @@ cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) return 1; } + uint8_t cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit) { int m = 0, s = 0, f = 0; - + if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - + return 0; + switch (type) { - case 0x40: - cdrom_log("Audio Track Search: MSF = %06x, type = %02x\n", pos, type); - m = CD_DCB((pos >> 24) & 0xff); - s = CD_DCB((pos >> 16) & 0xff); - f = CD_DCB((pos >> 8) & 0xff); - pos = MSFtoLBA(m, s, f) - 150; - break; + case 0x40: + cdrom_log("Audio Track Search: MSF = %06x, type = %02x\n", pos, type); + m = CD_DCB((pos >> 24) & 0xff); + s = CD_DCB((pos >> 16) & 0xff); + f = CD_DCB((pos >> 8) & 0xff); + pos = MSFtoLBA(m, s, f) - 150; + break; } - + /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_stop(dev); + return 0; } dev->seek_pos = pos; @@ -381,46 +387,48 @@ cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit) return 1; } -uint8_t + +uint8_t cdrom_toshiba_audio_play(cdrom_t *dev, uint32_t pos, int type) { int m = 0, s = 0, f = 0; if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; + return 0; if (dev->cd_status == CD_STATUS_STOPPED || dev->cd_status == CD_STATUS_PAUSED) - dev->cd_status = CD_STATUS_PLAYING; + dev->cd_status = CD_STATUS_PLAYING; /*Preliminary support, revert if too incomplete*/ switch (type) { - case 0x40: - cdrom_log("Toshiba Play Audio: MSF = %06x, type = %02x\n", pos, type); - m = CD_DCB((pos >> 24) & 0xff); - s = CD_DCB((pos >> 16) & 0xff); - f = CD_DCB((pos >> 8) & 0xff); - pos = MSFtoLBA(m, s, f) - 150; - break; + case 0x40: + cdrom_log("Toshiba Play Audio: MSF = %06x, type = %02x\n", pos, type); + m = CD_DCB((pos >> 24) & 0xff); + s = CD_DCB((pos >> 16) & 0xff); + f = CD_DCB((pos >> 8) & 0xff); + pos = MSFtoLBA(m, s, f) - 150; + break; } - + /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; - } - + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_stop(dev); + return 0; + } + dev->cd_end = pos; dev->cd_buflen = 0; return 1; } + void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume) { if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) - dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01); + dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01); } @@ -430,55 +438,57 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) uint8_t ret; subchannel_t subc; int pos = 1; + uint32_t dat; dev->ops->get_subchannel(dev, dev->seek_pos, &subc); cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i\n", subc.abs_m, subc.abs_s, subc.abs_f); if (dev->cd_status == CD_STATUS_DATA_ONLY) - ret = 0x15; + ret = 0x15; else { - if (dev->cd_status == CD_STATUS_PLAYING) - ret = 0x11; - else if (dev->cd_status == CD_STATUS_PAUSED) - ret = 0x12; - else - ret = 0x13; + if (dev->cd_status == CD_STATUS_PLAYING) + ret = 0x11; + else if (dev->cd_status == CD_STATUS_PAUSED) + ret = 0x12; + else + ret = 0x13; } if (b[pos] > 1) - return ret; + return ret; b[pos++] = subc.attr; b[pos++] = subc.track; b[pos++] = subc.index; if (msf) { - b[pos] = 0; - b[pos + 1] = subc.abs_m; - b[pos + 2] = subc.abs_s; - b[pos + 3] = subc.abs_f; - pos += 4; - b[pos] = 0; - b[pos + 1] = subc.rel_m; - b[pos + 2] = subc.rel_s; - b[pos + 3] = subc.rel_f; - pos += 4; + b[pos] = 0; + b[pos + 1] = subc.abs_m; + b[pos + 2] = subc.abs_s; + b[pos + 3] = subc.abs_f; + pos += 4; + b[pos] = 0; + b[pos + 1] = subc.rel_m; + b[pos + 2] = subc.rel_s; + b[pos + 3] = subc.rel_f; + pos += 4; } else { - uint32_t dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; + dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; } return ret; } + uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) { @@ -486,17 +496,16 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) subchannel_t subc; dev->ops->get_subchannel(dev, dev->seek_pos, &subc); - + if (dev->cd_status == CD_STATUS_PLAYING) - ret = 0x00; + ret = 0x00; else if (dev->cd_status == CD_STATUS_PAUSED) { - if (dev->noplay) - ret = 0x02; - else - ret = 0x01; - } - else - ret = 0x03; + if (dev->noplay) + ret = 0x02; + else + ret = 0x01; + } else + ret = 0x03; b[0] = subc.attr; b[1] = CD_BCD(subc.track); @@ -508,39 +517,58 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) b[7] = CD_BCD(subc.abs_s); b[8] = CD_BCD(subc.abs_f); cdrom_log("CD-ROM %i: Returned subcode-q at %02i:%02i.%02i, track=%02x\n", dev->id, b[3], b[4], b[5], b[1]); - + return ret; } + static int read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf) { track_info_t ti; - int len = 4; - int c, d, first_track, last_track; + int i, len = 4; + int first_track, last_track; uint32_t temp; + cdrom_log("read_toc_normal(%08X, %08X, %02X, %i)\n", dev, b, start_track, msf); + dev->ops->get_tracks(dev, &first_track, &last_track); - b[2] = first_track; - b[3] = last_track; + /* Byte 2 = Number of the first track */ + dev->ops->get_track_info(dev, 1, 0, &ti); + b[2] = ti.number; + cdrom_log(" b[2] = %02X\n", b[2]); - d = 0; - for (c = 0; c <= last_track; c++) { - dev->ops->get_track_info(dev, c + 1, 0, &ti); - if (ti.number >= start_track) { - d = c; - break; - } + /* Byte 3 = Number of the last track before the lead-out track */ + dev->ops->get_track_info(dev, last_track, 0, &ti); + b[3] = ti.number; + cdrom_log(" b[3] = %02X\n", b[2]); + + if (start_track == 0x00) + first_track = 0; + else { + first_track = -1; + for (i = 0; i <= last_track; i++) { + dev->ops->get_track_info(dev, i + 1, 0, &ti); + if (ti.number >= start_track) { + first_track = i; + break; + } + } + } + cdrom_log(" first_track = %i, last_track = %i\n", first_track, last_track); + + /* No suitable starting track, return with error. */ + if (first_track == -1) { +#ifdef ENABLE_CDROM_LOG + cdrom_log(" [ERROR] No suitable track found\n"); +#endif + return -1; } - if (start_track != 0xAA) { - dev->ops->get_track_info(dev, c + 1, 0, &ti); - b[2] = ti.number; - } - - for (c = d; c <= last_track; c++) { - dev->ops->get_track_info(dev, c + 1, 0, &ti); + for (i = first_track; i <= last_track; i++) { + cdrom_log(" tracks(%i) = %02X, %02X, %i:%02i.%02i\n", i, ti.attr, ti.number, ti.m, ti.s, ti.f); + dev->ops->get_track_info(dev, i + 1, 0, &ti); b[len++] = 0; /* reserved */ b[len++] = ti.attr; @@ -548,17 +576,17 @@ read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int m b[len++] = 0; /* reserved */ if (msf) { - b[len++] = 0; - b[len++] = ti.m; - b[len++] = ti.s; - b[len++] = ti.f; + b[len++] = 0; + b[len++] = ti.m; + b[len++] = ti.s; + b[len++] = ti.f; } else { - temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } + temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } } return len; @@ -572,27 +600,31 @@ read_toc_session(cdrom_t *dev, unsigned char *b, int msf) int len = 4; uint32_t temp; + cdrom_log("read_toc_session(%08X, %08X, %i)\n", dev, b, msf); + + /* Bytes 2 and 3 = Number of first and last sessions */ + b[2] = b[3] = 1; + dev->ops->get_track_info(dev, 1, 0, &ti); - if (ti.number == 0) - ti.number = 1; + cdrom_log(" tracks(0) = %02X, %02X, %i:%02i.%02i\n", ti.attr, ti.number, ti.m, ti.s, ti.f); - b[2] = b[3] = 1; b[len++] = 0; /* reserved */ b[len++] = ti.attr; b[len++] = ti.number; /* track number */ b[len++] = 0; /* reserved */ + if (msf) { - b[len++] = 0; - b[len++] = ti.m; - b[len++] = ti.s; - b[len++] = ti.f; + b[len++] = 0; + b[len++] = ti.m; + b[len++] = ti.s; + b[len++] = ti.f; } else { - temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; /* Do the - 150. */ - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; + temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; } return len; @@ -603,28 +635,31 @@ static int read_toc_raw(cdrom_t *dev, unsigned char *b) { track_info_t ti; + int i, len = 4; int first_track, last_track; - int track, len = 4; + + cdrom_log("read_toc_raw(%08X, %08X)\n", dev, b); dev->ops->get_tracks(dev, &first_track, &last_track); - b[2] = first_track; - b[3] = last_track; + /* Bytes 2 and 3 = Number of first and last sessions */ + b[2] = b[3] = 1; - for (track = first_track; track <= last_track; track++) { - dev->ops->get_track_info(dev, track, 0, &ti); + for (i = 0; i <= last_track; i++) { + dev->ops->get_track_info(dev, i + 1, 0, &ti); - b[len++] = track; - b[len++] = ti.attr; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = ti.m; - b[len++] = ti.s; - b[len++] = ti.f; + cdrom_log(" tracks(%i) = %02X, %02X, %i:%02i.%02i\n", i, ti.attr, ti.number, ti.m, ti.s, ti.f); + + b[len++] = 1; /* Session number */ + b[len++] = ti.attr; /* Track ADR and Control */ + b[len++] = 0; /* TNO (always 0) */ + b[len++] = ti.number; /* Point (for track points - track number) */ + b[len++] = ti.m; /* M */ + b[len++] = ti.s; /* S */ + b[len++] = ti.f; /* F */ + b[len++] = 0; + b[len++] = 0; + b[len++] = 0; } return len; @@ -637,18 +672,18 @@ cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_tra int len; switch(type) { - case CD_TOC_NORMAL: - len = read_toc_normal(dev, b, start_track, msf); - break; - case CD_TOC_SESSION: - len = read_toc_session(dev, b, msf); - break; - case CD_TOC_RAW: - len = read_toc_raw(dev, b); - break; - default: - cdrom_log("CD-ROM %i: Unknown TOC read type: %i\n", dev->id, type); - return 0; + case CD_TOC_NORMAL: + len = read_toc_normal(dev, b, start_track, msf); + break; + case CD_TOC_SESSION: + len = read_toc_session(dev, b, msf); + break; + case CD_TOC_RAW: + len = read_toc_raw(dev, b); + break; + default: + cdrom_log("CD-ROM %i: Unknown TOC read type: %i\n", dev->id, type); + return 0; } len = MIN(len, max_len); @@ -659,6 +694,32 @@ cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_tra return len; } + +/* A new API call for Mitsumi CD-ROM. */ +void +cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf) +{ + track_info_t ti; + int first_track, last_track; + + if (dev != NULL) { + dev->ops->get_tracks(dev, &first_track, &last_track); + buf[0] = 1; + buf[1] = last_track + 1; + dev->ops->get_track_info(dev, 1, 0, &ti); + buf[2] = ti.m; + buf[3] = ti.s; + buf[4] = ti.f; + dev->ops->get_track_info(dev, last_track + 1, 0, &ti); + buf[5] = ti.m; + buf[6] = ti.s; + buf[7] = ti.f; + buf[8] = 0x00; + } else + memset(buf, 0x00, 9); +} + + void cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type) { @@ -668,80 +729,76 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in dev->ops->get_tracks(dev, &first_track, &last_track); switch (type) { - case 0: - b[0] = CD_BCD(first_track); - b[1] = CD_BCD(last_track); - b[2] = 0; - b[3] = 0; - break; - case 1: - dev->ops->get_track_info(dev, 0xAA, 0, &ti); - b[0] = CD_BCD(ti.m); - b[1] = CD_BCD(ti.s); - b[2] = CD_BCD(ti.f); - b[3] = 0; - break; - case 2: - dev->ops->get_track_info(dev, CD_DCB(track), 0, &ti); - b[0] = CD_BCD(ti.m); - b[1] = CD_BCD(ti.s); - b[2] = CD_BCD(ti.f); - b[3] = ti.attr; - cdrom_log("CD-ROM %i: Returned Toshiba disc information at %02i:%02i.%02i, track=%d\n", dev->id, b[0], b[1], b[2], CD_DCB(track)); - break; - case 3: - b[0] = 0x00; /*TODO: correct it further, mark it as CD-Audio/CD-ROM disc for now*/ - b[1] = 0; - b[2] = 0; - b[3] = 0; - break; + case 0: + b[0] = CD_BCD(first_track); + b[1] = CD_BCD(last_track); + b[2] = 0; + b[3] = 0; + break; + case 1: + dev->ops->get_track_info(dev, 0xAA, 0, &ti); + b[0] = CD_BCD(ti.m); + b[1] = CD_BCD(ti.s); + b[2] = CD_BCD(ti.f); + b[3] = 0; + break; + case 2: + dev->ops->get_track_info(dev, CD_DCB(track), 0, &ti); + b[0] = CD_BCD(ti.m); + b[1] = CD_BCD(ti.s); + b[2] = CD_BCD(ti.f); + b[3] = ti.attr; + cdrom_log("CD-ROM %i: Returned Toshiba disc information at %02i:%02i.%02i, track=%d\n", dev->id, b[0], b[1], b[2], CD_DCB(track)); + break; + case 3: + b[0] = 0x00; /*TODO: correct it further, mark it as CD-Audio/CD-ROM disc for now*/ + b[1] = 0; + b[2] = 0; + b[3] = 0; + break; } } + static int track_type_is_valid(uint8_t id, int type, int flags, int audio, int mode2) { - if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; + if (!(flags & 0x70) && (flags & 0xf8)) { /* 0x08/0x80/0x88 are illegal modes */ + cdrom_log("CD-ROM %i: [Any Mode] 0x08/0x80/0x88 are illegal modes\n", id); + return 0; } if ((type != 1) && !audio) { - if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } + if ((flags & 0x06) == 0x06) { + cdrom_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); + return 0; + } - if ((flags & 0x06) == 0x06) { - cdrom_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); - return 0; - } + if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) { + cdrom_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, flags & 0x700); + return 0; + } - if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) { - cdrom_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, flags & 0x700); - return 0; - } + if ((flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ + cdrom_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } - if ((flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ - cdrom_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); - return 0; - } + if (((flags & 0xf0) == 0x90) || ((flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ + cdrom_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); + return 0; + } - if (((flags & 0xf0) == 0x90) || ((flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ - cdrom_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); - return 0; - } - - if (((type > 3) && (type != 8)) || (mode2 && (mode2 & 0x03))) { - if ((flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ - cdrom_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); - return 0; - } - if (((flags & 0xf0) == 0xb0) || ((flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ - cdrom_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); - return 0; - } - } + if (((type > 3) && (type != 8)) || (mode2 && (mode2 & 0x03))) { + if ((flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ + cdrom_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); + return 0; + } + if (((flags & 0xf0) == 0xb0) || ((flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ + cdrom_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); + return 0; + } + } } return 1; @@ -770,9 +827,9 @@ read_sector_to_buffer(cdrom_t *dev, uint8_t *rbuf, uint32_t msf, uint32_t lba, i bb += mode2 ? 12 : 4; bb += len; if (mode2 && ((mode2 & 0x03) == 1)) - memset(bb, 0, 280); + memset(bb, 0, 280); else if (!mode2) - memset(bb, 0, 288); + memset(bb, 0, 288); } @@ -791,47 +848,53 @@ static void read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) { if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); else - dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); cdrom_sector_size = 0; - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_log("CD-ROM %i: [Mode 1] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log("CD-ROM %i: [Mode 1] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; } - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_log("CD-ROM %i: [Mode 1] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log("CD-ROM %i: [Mode 1] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; } - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - if (!(cdrom_sector_flags & 0x10)) { /* No user data */ - cdrom_log("CD-ROM %i: [Mode 1] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) { + /* No user data */ + cdrom_log("CD-ROM %i: [Mode 1] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } } - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_log("CD-ROM %i: [Mode 1] User data\n", dev->id); - memcpy(b, raw_buffer + 16, 2048); - cdrom_sector_size += 2048; - b += 2048; + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log("CD-ROM %i: [Mode 1] User data\n", dev->id); + memcpy(b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + b += 2048; } - if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ - cdrom_log("CD-ROM %i: [Mode 1] EDC/ECC\n", dev->id); - memcpy(b, raw_buffer + 2064, 288); - cdrom_sector_size += 288; - b += 288; + if (cdrom_sector_flags & 0x08) { + /* EDC/ECC */ + cdrom_log("CD-ROM %i: [Mode 1] EDC/ECC\n", dev->id); + memcpy(b, raw_buffer + 2064, 288); + cdrom_sector_size += 288; + b += 288; } } @@ -840,39 +903,43 @@ static void read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) { if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2336)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2336); + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2336); else - dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); cdrom_sector_size = 0; - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; } - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; } /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; } - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] User data\n", dev->id); - memcpy(b, raw_buffer + 24, 2336); - cdrom_sector_size += 2336; - b += 2336; + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] User data\n", dev->id); + memcpy(b, raw_buffer + 24, 2336); + cdrom_sector_size += 2336; + b += 2336; } } @@ -881,45 +948,50 @@ static void read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) { if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); else - dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); cdrom_sector_size = 0; - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; } - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; } - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; } - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", dev->id); - memcpy(b, raw_buffer + 24, 2048); - cdrom_sector_size += 2048; - b += 2048; + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", dev->id); + memcpy(b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + b += 2048; } - if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", dev->id); - memcpy(b, raw_buffer + 2072, 280); - cdrom_sector_size += 280; - b += 280; + if (cdrom_sector_flags & 0x08) { + /* EDC/ECC */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", dev->id); + memcpy(b, raw_buffer + 2072, 280); + cdrom_sector_size += 280; + b += 280; } } @@ -928,38 +1000,42 @@ static void read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) { if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2324)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2324); + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2324); else - dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); cdrom_sector_size = 0; - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; } - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; } - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; } - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", dev->id); - memcpy(b, raw_buffer + 24, 2328); - cdrom_sector_size += 2328; - b += 2328; + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", dev->id); + memcpy(b, raw_buffer + 24, 2328); + cdrom_sector_size += 2328; + b += 2328; } } @@ -974,25 +1050,25 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c int m, s, f; if (dev->cd_status == CD_STATUS_EMPTY) - return 0; + return 0; b = temp_b = buffer; *len = 0; if (ismsf) { - m = (sector >> 16) & 0xff; - s = (sector >> 8) & 0xff; - f = sector & 0xff; - lba = MSFtoLBA(m, s, f) - 150; - msf = sector; + m = (sector >> 16) & 0xff; + s = (sector >> 8) & 0xff; + f = sector & 0xff; + lba = MSFtoLBA(m, s, f) - 150; + msf = sector; } else { - lba = sector; - msf = cdrom_lba_to_msf_accurate(sector); + lba = sector; + msf = cdrom_lba_to_msf_accurate(sector); } if (dev->ops->track_type) - audio = dev->ops->track_type(dev, lba); + audio = dev->ops->track_type(dev, lba); mode2 = audio & ~CD_TRACK_AUDIO; audio &= CD_TRACK_AUDIO; @@ -1000,106 +1076,107 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c memset(raw_buffer, 0, 2448); memset(extra_buffer, 0, 296); - if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ - cdrom_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", dev->id); - return 0; + if ((cdrom_sector_flags & 0xf8) == 0x08) { + /* 0x08 is an illegal mode */ + cdrom_log("CD-ROM %i: [Mode 1] 0x08 is an illegal mode\n", dev->id); + return 0; } if (!track_type_is_valid(dev->id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) - return 0; + return 0; if ((cdrom_sector_type > 5) && (cdrom_sector_type != 8)) { - cdrom_log("CD-ROM %i: Attempting to read an unrecognized sector type from an image\n", dev->id); - return 0; + cdrom_log("CD-ROM %i: Attempting to read an unrecognized sector type from an image\n", dev->id); + return 0; } else if (cdrom_sector_type == 1) { - if (!audio || (dev->cd_status == CD_STATUS_DATA_ONLY)) { - cdrom_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", dev->id); - return 0; - } + if (!audio || (dev->cd_status == CD_STATUS_DATA_ONLY)) { + cdrom_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", dev->id); + return 0; + } - read_audio(dev, lba, temp_b); + read_audio(dev, lba, temp_b); } else if (cdrom_sector_type == 2) { - if (audio || mode2) { - cdrom_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", dev->id); - return 0; - } + if (audio || mode2) { + cdrom_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", dev->id); + return 0; + } - read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); } else if (cdrom_sector_type == 3) { - if (audio || !mode2 || (mode2 & 0x03)) { - cdrom_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", dev->id); - return 0; - } + if (audio || !mode2 || (mode2 & 0x03)) { + cdrom_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", dev->id); + return 0; + } - read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); } else if (cdrom_sector_type == 4) { - if (audio || !mode2 || ((mode2 & 0x03) != 1)) { - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", dev->id); - return 0; - } + if (audio || !mode2 || ((mode2 & 0x03) != 1)) { + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", dev->id); + return 0; + } - read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); } else if (cdrom_sector_type == 5) { - if (audio || !mode2 || ((mode2 & 0x03) != 2)) { - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", dev->id); - return 0; - } + if (audio || !mode2 || ((mode2 & 0x03) != 2)) { + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", dev->id); + return 0; + } - read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); } else if (cdrom_sector_type == 8) { - if (audio) { - cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", dev->id); - return 0; - } + if (audio) { + cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", dev->id); + return 0; + } - if (mode2 && ((mode2 & 0x03) == 1)) - read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); - else if (!mode2) - read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); - else { - cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", dev->id); - return 0; - } + if (mode2 && ((mode2 & 0x03) == 1)) + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if (!mode2) + read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else { + cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", dev->id); + return 0; + } } else { - if (mode2) { - if ((mode2 & 0x03) == 0x01) - read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); - else if ((mode2 & 0x03) == 0x02) - read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); - else - read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); - } else { - if (audio) - read_audio(dev, lba, temp_b); - else - read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); - } + if (mode2) { + if ((mode2 & 0x03) == 0x01) + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if ((mode2 & 0x03) == 0x02) + read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else + read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else { + if (audio) + read_audio(dev, lba, temp_b); + else + read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } } if ((cdrom_sector_flags & 0x06) == 0x02) { - /* Add error flags. */ - cdrom_log("CD-ROM %i: Error flags\n", dev->id); - memcpy(b + cdrom_sector_size, extra_buffer, 294); - cdrom_sector_size += 294; + /* Add error flags. */ + cdrom_log("CD-ROM %i: Error flags\n", dev->id); + memcpy(b + cdrom_sector_size, extra_buffer, 294); + cdrom_sector_size += 294; } else if ((cdrom_sector_flags & 0x06) == 0x04) { - /* Add error flags. */ - cdrom_log("CD-ROM %i: Full error flags\n", dev->id); - memcpy(b + cdrom_sector_size, extra_buffer, 296); - cdrom_sector_size += 296; + /* Add error flags. */ + cdrom_log("CD-ROM %i: Full error flags\n", dev->id); + memcpy(b + cdrom_sector_size, extra_buffer, 296); + cdrom_sector_size += 296; } if ((cdrom_sector_flags & 0x700) == 0x100) { - cdrom_log("CD-ROM %i: Raw subchannel data\n", dev->id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; + cdrom_log("CD-ROM %i: Raw subchannel data\n", dev->id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; } else if ((cdrom_sector_flags & 0x700) == 0x200) { - cdrom_log("CD-ROM %i: Q subchannel data\n", dev->id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); - cdrom_sector_size += 16; + cdrom_log("CD-ROM %i: Q subchannel data\n", dev->id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); + cdrom_sector_size += 16; } else if ((cdrom_sector_flags & 0x700) == 0x400) { - cdrom_log("CD-ROM %i: R/W subchannel data\n", dev->id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; + cdrom_log("CD-ROM %i: R/W subchannel data\n", dev->id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; } *len = cdrom_sector_size; @@ -1135,29 +1212,29 @@ cdrom_hard_reset(void) int i; for (i = 0; i < CDROM_NUM; i++) { - dev = &cdrom[i]; - if (dev->bus_type) { - cdrom_log("CD-ROM %i: Hard reset\n", i); + dev = &cdrom[i]; + if (dev->bus_type) { + cdrom_log("CD-ROM %i: Hard reset\n", i); - dev->id = i; + dev->id = i; - cdrom_drive_reset(dev); + cdrom_drive_reset(dev); - switch(dev->bus_type) { - case CDROM_BUS_ATAPI: - case CDROM_BUS_SCSI: - scsi_cdrom_drive_reset(i); - break; + switch(dev->bus_type) { + case CDROM_BUS_ATAPI: + case CDROM_BUS_SCSI: + scsi_cdrom_drive_reset(i); + break; - default: - break; - } + default: + break; + } - dev->cd_status = CD_STATUS_EMPTY; + dev->cd_status = CD_STATUS_EMPTY; - if (dev->host_drive == 200) - cdrom_image_open(dev, dev->image_path); - } + if (dev->host_drive == 200) + cdrom_image_open(dev, dev->image_path); + } } sound_cd_thread_reset(); @@ -1171,21 +1248,21 @@ cdrom_close(void) int i; for (i = 0; i < CDROM_NUM; i++) { - dev = &cdrom[i]; + dev = &cdrom[i]; - if (dev->bus_type == CDROM_BUS_SCSI) - memset(&scsi_devices[dev->scsi_device_id], 0x00, sizeof(scsi_device_t)); + if (dev->bus_type == CDROM_BUS_SCSI) + memset(&scsi_devices[dev->scsi_device_id], 0x00, sizeof(scsi_device_t)); - if (dev->close) - dev->close(dev->priv); + if (dev->close) + dev->close(dev->priv); - if (dev->ops && dev->ops->exit) - dev->ops->exit(dev); + if (dev->ops && dev->ops->exit) + dev->ops->exit(dev); - dev->ops = NULL; - dev->priv = NULL; + dev->ops = NULL; + dev->priv = NULL; - cdrom_drive_reset(dev); + cdrom_drive_reset(dev); } } @@ -1197,8 +1274,8 @@ cdrom_insert(uint8_t id) cdrom_t *dev = &cdrom[id]; if (dev->bus_type) { - if (dev->insert) - dev->insert(dev->priv); + if (dev->insert) + dev->insert(dev->priv); } } @@ -1211,12 +1288,12 @@ cdrom_eject(uint8_t id) /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ if (dev->host_drive == 0) { - /* Switch from empty to empty. Do nothing. */ - return; + /* Switch from empty to empty. Do nothing. */ + return; } if (dev->host_drive == 200) - wcscpy(dev->prev_image_path, dev->image_path); + strcpy(dev->prev_image_path, dev->image_path); dev->prev_host_drive = dev->host_drive; dev->host_drive = 0; @@ -1240,27 +1317,27 @@ cdrom_reload(uint8_t id) cdrom_t *dev = &cdrom[id]; if ((dev->host_drive == dev->prev_host_drive) || - (dev->prev_host_drive == 0) || (dev->host_drive != 0)) { - /* Switch from empty to empty. Do nothing. */ - return; + (dev->prev_host_drive == 0) || (dev->host_drive != 0)) { + /* Switch from empty to empty. Do nothing. */ + return; } if (dev->ops && dev->ops->exit) - dev->ops->exit(dev); + dev->ops->exit(dev); dev->ops = NULL; memset(dev->image_path, 0, sizeof(dev->image_path)); if (dev->prev_host_drive == 200) { - /* Reload a previous image. */ - wcscpy(dev->image_path, dev->prev_image_path); - cdrom_image_open(dev, dev->image_path); + /* Reload a previous image. */ + strcpy(dev->image_path, dev->prev_image_path); + cdrom_image_open(dev, dev->image_path); - cdrom_insert(id); + cdrom_insert(id); - if (wcslen(dev->image_path) == 0) - dev->host_drive = 0; - else - dev->host_drive = 200; + if (strlen(dev->image_path) == 0) + dev->host_drive = 0; + else + dev->host_drive = 200; } plat_cdrom_ui_update(id, 1); diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 3bef1a356..9a653b310 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -8,8 +8,6 @@ * * CD-ROM image support. * - * - * * Author: RichardG867, * Miran Grca, * bit, @@ -18,9 +16,6 @@ * Copyright 2015-2019 Miran Grca. * Copyright 2017-2019 bit. */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #include #include #include @@ -31,6 +26,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/config.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/scsi_device.h> #include <86box/cdrom_image_backend.h> @@ -61,7 +57,7 @@ cdrom_image_log(const char *fmt, ...) /* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) static void @@ -95,7 +91,7 @@ image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) TMSF rel_pos, abs_pos; cdi_get_audio_sub(img, lba, &subc->attr, &subc->track, &subc->index, - &rel_pos, &abs_pos); + &rel_pos, &abs_pos); subc->abs_m = abs_pos.min; subc->abs_s = abs_pos.sec; @@ -117,14 +113,14 @@ image_get_capacity(cdrom_t *dev) uint32_t address = 0, lb = 0; if (!img) - return 0; + return 0; cdi_get_audio_tracks_lba(img, &first_track, &last_track, &lb); for (c = 0; c <= last_track; c++) { - cdi_get_audio_track_info_lba(img, 0, c + 1, &number, &address, &attr); - if (address > lb) - lb = address; + cdi_get_audio_track_info_lba(img, 0, c + 1, &number, &address, &attr); + if (address > lb) + lb = address; } return lb; @@ -141,27 +137,43 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) int number, track; if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) - return 0; + return 0; if (ismsf) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - pos = MSFtoLBA(m, s, f) - 150; + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f) - 150; } /* GetTrack requires LBA. */ track = cdi_get_track(img, pos); if (track == -1) - return 0; + return 0; else { - cdi_get_audio_track_info(img, 0, cdi_get_track(img, pos), &number, &tmsf, &attr); - return attr == AUDIO_TRACK; + cdi_get_audio_track_info(img, 0, track, &number, &tmsf, &attr); + return attr == AUDIO_TRACK; } } -static int +static int +image_is_track_pre(cdrom_t *dev, uint32_t lba) +{ + cd_img_t *img = (cd_img_t *)dev->image; + int track; + + /* GetTrack requires LBA. */ + track = cdi_get_track(img, lba); + + if (track != -1) + return cdi_get_audio_track_pre(img, track); + + return 0; +} + + +static int image_sector_size(struct cdrom *dev, uint32_t lba) { cd_img_t *img = (cd_img_t *)dev->image; @@ -176,18 +188,18 @@ image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) cd_img_t *img = (cd_img_t *)dev->image; switch (type) { - case CD_READ_DATA: - return cdi_read_sector(img, b, 0, lba); - case CD_READ_AUDIO: - return cdi_read_sector(img, b, 1, lba); - case CD_READ_RAW: - if (cdi_get_sector_size(img, lba) == 2352) - return cdi_read_sector(img, b, 1, lba); - else - return cdi_read_sector_sub(img, b, lba); - default: - cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); - return 0; + case CD_READ_DATA: + return cdi_read_sector(img, b, 0, lba); + case CD_READ_AUDIO: + return cdi_read_sector(img, b, 1, lba); + case CD_READ_RAW: + if (cdi_get_sector_size(img, lba) == 2352) + return cdi_read_sector(img, b, 1, lba); + else + return cdi_read_sector_sub(img, b, lba); + default: + cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); + return 0; } } @@ -198,11 +210,11 @@ image_track_type(cdrom_t *dev, uint32_t lba) cd_img_t *img = (cd_img_t *)dev->image; if (img) { - if (image_is_track_audio(dev, lba, 0)) - return CD_TRACK_AUDIO; - else { - if (cdi_is_mode2(img, lba)) - return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); + if (image_is_track_audio(dev, lba, 0)) + return CD_TRACK_AUDIO; + else { + if (cdi_is_mode2(img, lba)) + return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); } } @@ -215,12 +227,12 @@ image_exit(cdrom_t *dev) { cd_img_t *img = (cd_img_t *)dev->image; -cdrom_image_log("CDROM: image_exit(%ls)\n", dev->image_path); + cdrom_image_log("CDROM: image_exit(%s)\n", dev->image_path); dev->cd_status = CD_STATUS_EMPTY; if (img) { - cdi_close(img); - dev->image = NULL; + cdi_close(img); + dev->image = NULL; } dev->ops = NULL; @@ -231,6 +243,7 @@ static const cdrom_ops_t cdrom_image_ops = { image_get_tracks, image_get_track_info, image_get_subchannel, + image_is_track_pre, image_sector_size, image_read_sector, image_track_type, @@ -249,29 +262,32 @@ image_open_abort(cdrom_t *dev) int -cdrom_image_open(cdrom_t *dev, const wchar_t *fn) +cdrom_image_open(cdrom_t *dev, const char *fn) { cd_img_t *img; - wcscpy(dev->image_path, fn); + /* Make sure to not STRCPY if the two are pointing + at the same place. */ + if (fn != dev->image_path) + strcpy(dev->image_path, fn); /* Create new instance of the CDROM_Image class. */ img = (cd_img_t *) malloc(sizeof(cd_img_t)); /* This guarantees that if ops is not NULL, then neither is the image pointer. */ - if (!img) - return image_open_abort(dev); + if (!img) + return image_open_abort(dev); memset(img, 0, sizeof(cd_img_t)); dev->image = img; /* Open the image. */ if (!cdi_set_device(img, fn)) - return image_open_abort(dev); + return image_open_abort(dev); /* All good, reset state. */ - if (! wcscasecmp(plat_get_extension((wchar_t *) fn), L"ISO")) + if (! strcasecmp(path_get_extension((char *) fn), "ISO")) dev->cd_status = CD_STATUS_DATA_ONLY; else dev->cd_status = CD_STATUS_STOPPED; @@ -290,8 +306,8 @@ cdrom_image_open(cdrom_t *dev, const wchar_t *fn) void cdrom_image_close(cdrom_t *dev) { - cdrom_image_log("CDROM: image_close(%ls)\n", dev->image_path); + cdrom_image_log("CDROM: image_close(%s)\n", dev->image_path); if (dev && dev->ops && dev->ops->exit) - dev->ops->exit(dev); + dev->ops->exit(dev); } diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c index 802069978..028c3c3ed 100644 --- a/src/cdrom/cdrom_image_backend.c +++ b/src/cdrom/cdrom_image_backend.c @@ -9,8 +9,6 @@ * CD-ROM image file handling module, translated to C from * cdrom_dosbox.cpp. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * The DOSBox Team, @@ -19,14 +17,13 @@ * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2002-2020 The DOSBox Team. */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #define __STDC_FORMAT_MACROS #include #include #include #include #include +#include #include #ifdef _WIN32 # include @@ -36,6 +33,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/cdrom_image_backend.h> @@ -77,23 +75,23 @@ bin_read(void *p, uint8_t *buffer, uint64_t seek, size_t count) track_file_t *tf = (track_file_t *) p; cdrom_image_backend_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n", - tf->file, seek, count); + tf->file, seek, count); if (tf->file == NULL) - return 0; + return 0; if (fseeko64(tf->file, seek, SEEK_SET) == -1) { #ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - cdrom_image_backend_log("CDROM: binary_read failed during seek!\n"); + cdrom_image_backend_log("CDROM: binary_read failed during seek!\n"); #endif - return 0; + return 0; } if (fread(buffer, count, 1, tf->file) != 1) { #ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - cdrom_image_backend_log("CDROM: binary_read failed during read!\n"); + cdrom_image_backend_log("CDROM: binary_read failed during read!\n"); #endif - return 0; + return 0; } return 1; @@ -106,10 +104,10 @@ bin_get_length(void *p) off64_t len; track_file_t *tf = (track_file_t *) p; - cdrom_image_backend_log("CDROM: binary_length(%08lx)\n", bf->file); + cdrom_image_backend_log("CDROM: binary_length(%08lx)\n", tf->file); if (tf->file == NULL) - return 0; + return 0; fseeko64(tf->file, 0, SEEK_END); len = ftello64(tf->file); @@ -125,11 +123,11 @@ bin_close(void *p) track_file_t *tf = (track_file_t *) p; if (tf == NULL) - return; + return; if (tf->file != NULL) { - fclose(tf->file); - tf->file = NULL; + fclose(tf->file); + tf->file = NULL; } memset(tf->fn, 0x00, sizeof(tf->fn)); @@ -139,33 +137,30 @@ bin_close(void *p) static track_file_t * -bin_init(const wchar_t *filename, int *error) +bin_init(const char *filename, int *error) { track_file_t *tf = (track_file_t *) malloc(sizeof(track_file_t)); if (tf == NULL) { - *error = 1; - return NULL; + *error = 1; + return NULL; } memset(tf->fn, 0x00, sizeof(tf->fn)); - if (wcslen(filename) <= 260) - wcscpy(tf->fn, filename); - else - wcsncpy(tf->fn, filename, 260); - tf->file = plat_fopen64(tf->fn, L"rb"); - cdrom_image_backend_log("CDROM: binary_open(%ls) = %08lx\n", tf->fn, tf->file); + strncpy(tf->fn, filename, sizeof(tf->fn) - 1); + tf->file = plat_fopen64(tf->fn, "rb"); + cdrom_image_backend_log("CDROM: binary_open(%s) = %08lx\n", tf->fn, tf->file); *error = (tf->file == NULL); /* Set the function pointers. */ if (!*error) { - tf->read = bin_read; - tf->get_length = bin_get_length; - tf->close = bin_close; + tf->read = bin_read; + tf->get_length = bin_get_length; + tf->close = bin_close; } else { - free(tf); - tf = NULL; + free(tf); + tf = NULL; } return tf; @@ -173,7 +168,7 @@ bin_init(const wchar_t *filename, int *error) static track_file_t * -track_file_init(const wchar_t *filename, int *error) +track_file_init(const char *filename, int *error) { /* Current we only support .BIN files, either combined or one per track. In the future, more is planned. */ @@ -185,13 +180,13 @@ static void track_file_close(track_t *trk) { if (trk == NULL) - return; + return; if (trk->file == NULL) - return; + return; if (trk->file->close == NULL) - return; + return; trk->file->close(trk->file); trk->file = NULL; @@ -207,17 +202,17 @@ cdi_clear_tracks(cd_img_t *cdi) track_t *cur = NULL; if ((cdi->tracks == NULL) || (cdi->tracks_num == 0)) - return; + return; for (i = 0; i < cdi->tracks_num; i++) { - cur = &cdi->tracks[i]; + cur = &cdi->tracks[i]; - /* Make sure we do not attempt to close a NULL file. */ - if (cur->file != last) { - last = cur->file; - track_file_close(cur); - } else - cur->file = NULL; + /* Make sure we do not attempt to close a NULL file. */ + if (cur->file != last) { + last = cur->file; + track_file_close(cur); + } else + cur->file = NULL; } /* Now free the array. */ @@ -238,13 +233,13 @@ cdi_close(cd_img_t *cdi) int -cdi_set_device(cd_img_t *cdi, const wchar_t *path) +cdi_set_device(cd_img_t *cdi, const char *path) { if (cdi_load_cue(cdi, path)) - return 1; + return 1; if (cdi_load_iso(cdi, path)) - return 1; + return 1; return 0; } @@ -262,6 +257,7 @@ cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out) } +/* TODO: This never returns anything other than 1, should it even be an int? */ int cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out) { @@ -273,6 +269,18 @@ cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_ } +int +cdi_get_audio_track_pre(cd_img_t *cdi, int track) +{ + track_t *trk = &cdi->tracks[track - 1]; + + if ((track < 1) || (track > cdi->tracks_num)) + return 0; + + return trk->pre; +} + + /* This replaces both Info and EndInfo, they are specified by a variable. */ int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr) @@ -281,7 +289,7 @@ cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF int pos = trk->start + 150; if ((track < 1) || (track > cdi->tracks_num)) - return 0; + return 0; pos = trk->start + 150; @@ -300,7 +308,7 @@ cdi_get_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, track_t *trk = &cdi->tracks[track - 1]; if ((track < 1) || (track > cdi->tracks_num)) - return 0; + return 0; *start = (uint32_t) trk->start; @@ -319,15 +327,15 @@ cdi_get_track(cd_img_t *cdi, uint32_t sector) /* There must be at least two tracks - data and lead out. */ if (cdi->tracks_num < 2) - return -1; + return -1; /* This has a problem - the code skips the last track, which is lead out - is that correct? */ for (i = 0; i < (cdi->tracks_num - 1); i++) { - cur = &cdi->tracks[i]; - next = &cdi->tracks[i + 1]; - if ((cur->start <= sector) && (sector < next->start)) - return cur->number; + cur = &cdi->tracks[i]; + next = &cdi->tracks[i + 1]; + if ((cur->start <= sector) && (sector < next->start)) + return cur->number; } return -1; @@ -342,7 +350,7 @@ cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, track_t *trk; if (cur_track < 1) - return 0; + return 0; *track = (uint8_t) cur_track; trk = &cdi->tracks[*track - 1]; @@ -371,7 +379,7 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) int m = 0, s = 0, f = 0; if (track < 0) - return 0; + return 0; trk = &cdi->tracks[track]; track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448)); @@ -379,44 +387,45 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) seek = trk->skip + ((sect - trk->start) * trk->sector_size); if (track_is_raw) - raw_size = trk->sector_size; + raw_size = trk->sector_size; else - raw_size = 2448; + raw_size = 2448; if (trk->mode2 && (trk->form != 1)) { - if (trk->form == 2) - cooked_size = (track_is_raw ? 2328 : trk->sector_size); /* Both 2324 + ECC and 2328 variants are valid. */ - else - cooked_size = 2336; + if (trk->form == 2) + cooked_size = (track_is_raw ? 2328 : trk->sector_size); /* Both 2324 + ECC and 2328 variants are valid. */ + else + cooked_size = 2336; } else - cooked_size = COOKED_SECTOR_SIZE; + cooked_size = COOKED_SECTOR_SIZE; length = (raw ? raw_size : cooked_size); if (trk->mode2 && (trk->form >= 1)) - offset = 24ULL; + offset = 24ULL; else - offset = 16ULL; + offset = 16ULL; if (raw && !track_is_raw) { - memset(buffer, 0x00, 2448); - ret = trk->file->read(trk->file, buffer + offset, seek, length); - if (!ret) - return 0; - /* Construct the rest of the raw sector. */ - memset(buffer + 1, 0xff, 10); - buffer += 12; - FRAMES_TO_MSF(sector + 150, &m, &s, &f); - /* These have to be BCD. */ - buffer[12] = CDROM_BCD(m & 0xff); - buffer[13] = CDROM_BCD(s & 0xff); - buffer[14] = CDROM_BCD(f & 0xff); - buffer[15] = trk->mode2 ? 2 : 1; /* Data, should reflect the actual sector type. */ - return 1; + memset(buffer, 0x00, 2448); + ret = trk->file->read(trk->file, buffer + offset, seek, length); + if (!ret) + return 0; + /* Construct the rest of the raw sector. */ + memset(buffer + 1, 0xff, 10); + buffer += 12; + FRAMES_TO_MSF(sector + 150, &m, &s, &f); + /* These have to be BCD. */ + buffer[12] = CDROM_BCD(m & 0xff); + buffer[13] = CDROM_BCD(s & 0xff); + buffer[14] = CDROM_BCD(f & 0xff); + /* Data, should reflect the actual sector type. */ + buffer[15] = trk->mode2 ? 2 : 1; + return 1; } else if (!raw && track_is_raw) - return trk->file->read(trk->file, buffer, seek + offset, length); + return trk->file->read(trk->file, buffer, seek + offset, length); else - return trk->file->read(trk->file, buffer, seek, length); + return trk->file->read(trk->file, buffer, seek, length); } @@ -424,19 +433,24 @@ int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num) { int sector_size, success = 1; - uint8_t buf_len, *buf; - uint32_t i; + uint8_t *buf; + uint32_t buf_len, i; - /* TODO: This fails to account for Mode 2. Shouldn't we have a function - to get sector size? */ + /* TODO: This fails to account for Mode 2. Shouldn't we have a function + to get sector size? */ sector_size = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; buf_len = num * sector_size; buf = (uint8_t *) malloc(buf_len * sizeof(uint8_t)); for (i = 0; i < num; i++) { - success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i); - if (!success) + success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i); + if (!success) break; + /* Based on the DOSBox patch, but check all 8 bytes and makes sure it's not an + audio track. */ + if (raw && sector < cdi->tracks[0].length && !cdi->tracks[0].mode2 && + (cdi->tracks[0].attr != AUDIO_TRACK) && *(uint64_t *) &(buf[i * sector_size + 2068])) + return 0; } memcpy((void *) buffer, buf, buf_len); @@ -456,12 +470,12 @@ cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector) uint64_t s = (uint64_t) sector, seek; if (track < 0) - return 0; + return 0; trk = &cdi->tracks[track]; seek = trk->skip + ((s - trk->start) * trk->sector_size); if (trk->sector_size != 2448) - return 0; + return 0; return trk->file->read(trk->file, buffer, seek, 2448); } @@ -474,7 +488,7 @@ cdi_get_sector_size(cd_img_t *cdi, uint32_t sector) track_t *trk; if (track < 0) - return 0; + return 0; trk = &cdi->tracks[track]; return trk->sector_size; @@ -488,7 +502,7 @@ cdi_is_mode2(cd_img_t *cdi, uint32_t sector) track_t *trk; if (track < 0) - return 0; + return 0; trk = &cdi->tracks[track]; @@ -503,7 +517,7 @@ cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector) track_t *trk; if (track < 0) - return 0; + return 0; trk = &cdi->tracks[track]; @@ -518,9 +532,9 @@ cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2, int form) uint64_t seek = 16ULL * sector_size; /* First VD is located at sector 16. */ if ((!mode2 || (form == 0)) && (sector_size == RAW_SECTOR_SIZE)) - seek += 16; + seek += 16; if (mode2 && (form >= 1)) - seek += 24; + seek += 24; file->read(file, pvd, seek, COOKED_SECTOR_SIZE); @@ -536,9 +550,9 @@ cdi_track_push_back(cd_img_t *cdi, track_t *trk) /* This has to be done so situations in which realloc would misbehave can be detected and reported to the user. */ if ((cdi->tracks != NULL) && (cdi->tracks_num == 0)) - fatal("CD-ROM Image: Non-null tracks array at 0 loaded tracks\n"); + fatal("CD-ROM Image: Non-null tracks array at 0 loaded tracks\n"); if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) - fatal("CD-ROM Image: Null tracks array at non-zero loaded tracks\n"); + fatal("CD-ROM Image: Null tracks array at non-zero loaded tracks\n"); cdi->tracks = realloc(cdi->tracks, (cdi->tracks_num + 1) * sizeof(track_t)); memcpy(&(cdi->tracks[cdi->tracks_num]), trk, sizeof(track_t)); @@ -547,7 +561,7 @@ cdi_track_push_back(cd_img_t *cdi, track_t *trk) int -cdi_load_iso(cd_img_t *cdi, const wchar_t *filename) +cdi_load_iso(cd_img_t *cdi, const char *filename) { int error; track_t trk; @@ -560,9 +574,9 @@ cdi_load_iso(cd_img_t *cdi, const wchar_t *filename) /* Data track (shouldn't there be a lead in track?). */ trk.file = bin_init(filename, &error); if (error) { - if ((trk.file != NULL) && (trk.file->close != NULL)) - trk.file->close(trk.file); - return 0; + if ((trk.file != NULL) && (trk.file->close != NULL)) + trk.file->close(trk.file); + return 0; } trk.number = 1; trk.track_number = 1; @@ -573,20 +587,20 @@ cdi_load_iso(cd_img_t *cdi, const wchar_t *filename) trk.mode2 = 0; /* TODO: Merge the first and last cases since they result in the same thing. */ if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 0, 0)) - trk.sector_size = RAW_SECTOR_SIZE; + trk.sector_size = RAW_SECTOR_SIZE; else if (cdi_can_read_pvd(trk.file, 2336, 1, 0)) { - trk.sector_size = 2336; - trk.mode2 = 1; + trk.sector_size = 2336; + trk.mode2 = 1; } else if (cdi_can_read_pvd(trk.file, 2324, 1, 2)) { - trk.sector_size = 2324; - trk.mode2 = 1; - trk.form = 2; + trk.sector_size = 2324; + trk.mode2 = 1; + trk.form = 2; } else if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 1, 0)) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.mode2 = 1; + trk.sector_size = RAW_SECTOR_SIZE; + trk.mode2 = 1; } else { - /* We use 2048 mode 1 as the default. */ - trk.sector_size = COOKED_SECTOR_SIZE; + /* We use 2048 mode 1 as the default. */ + trk.sector_size = COOKED_SECTOR_SIZE; } trk.length = trk.file->get_length(trk.file) / trk.sector_size; @@ -617,41 +631,40 @@ cdi_cue_get_buffer(char *str, char **line, int up) /* Copy to local buffer until we have end of string or whitespace. */ while (! done) { - switch(*s) { - case '\0': - if (quote) { - /* Ouch, unterminated string.. */ - return 0; - } - done = 1; - break; + switch(*s) { + case '\0': + if (quote) { + /* Ouch, unterminated string.. */ + return 0; + } + done = 1; + break; - case '\"': - quote ^= 1; - break; + case '\"': + quote ^= 1; + break; - case ' ': - case '\t': - if (space) - break; + case ' ': case '\t': + if (space) + break; - if (! quote) { - done = 1; - break; - } - /*FALLTHROUGH*/ + if (! quote) { + done = 1; + break; + } + /*FALLTHROUGH*/ - default: - if (up && islower((int) *s)) - *p++ = toupper((int) *s); - else - *p++ = *s; - space = 0; - break; - } + default: + if (up && islower((int) *s)) + *p++ = toupper((int) *s); + else + *p++ = *s; + space = 0; + break; + } - if (! done) - s++; + if (! done) + s++; } *p = '\0'; @@ -668,7 +681,7 @@ cdi_cue_get_keyword(char **dest, char **line) success = cdi_cue_get_buffer(temp_keyword, line, 1); if (success) - *dest = temp_keyword; + *dest = temp_keyword; return success; } @@ -682,10 +695,10 @@ cdi_cue_get_number(char **line) uint64_t num; if (!cdi_cue_get_buffer(temp, line, 0)) - return 0; + return 0; if (sscanf(temp, "%" PRIu64, &num) != 1) - return 0; + return 0; return num; } @@ -699,10 +712,12 @@ cdi_cue_get_frame(uint64_t *frames, char **line) int success; success = cdi_cue_get_buffer(temp, line, 0); - if (! success) return 0; + if (!success) + return 0; success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; - if (! success) return 0; + if (!success) + return 0; *frames = MSF_TO_FRAMES(min, sec, fr); @@ -710,6 +725,27 @@ cdi_cue_get_frame(uint64_t *frames, char **line) } +static int +cdi_cue_get_flags(track_t *cur, char **line) +{ + char temp[128], temp2[128]; + int success; + + success = cdi_cue_get_buffer(temp, line, 0); + if (!success) + return 0; + + memset(temp2, 0x00, sizeof(temp2)); + success = sscanf(temp, "%s", temp2) == 1; + if (!success) + return 0; + + cur->pre = (strstr(temp2, "PRE") != NULL); + + return 1; +} + + static int cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, uint64_t *total_pregap, uint64_t cur_pregap) { @@ -717,58 +753,60 @@ cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, u uint64_t skip, temp; track_t *prev = NULL; - if (prestart > 0) { - if (prestart > cur->start) - return 0; - skip = cur->start - prestart; + /* Skip *MUST* be calculated even if prestart is 0. */ + if (prestart >= 0) { + if (prestart > cur->start) + return 0; + skip = cur->start - prestart; } else - skip = 0ULL; + skip = 0ULL; if ((cdi->tracks != NULL) && (cdi->tracks_num != 0)) - prev = &cdi->tracks[cdi->tracks_num - 1]; + prev = &cdi->tracks[cdi->tracks_num - 1]; else if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) { - fatal("NULL cdi->tracks with non-zero cdi->tracks_num\n"); - return 0; + fatal("NULL cdi->tracks with non-zero cdi->tracks_num\n"); + return 0; } /* First track (track number must be 1). */ if (cdi->tracks_num == 0) { - /* I guess this makes sure the structure is not filled with invalid data. */ - if (cur->number != 1) - return 0; - cur->skip = skip * cur->sector_size; - cur->start += cur_pregap; - *total_pregap = cur_pregap; - cdi_track_push_back(cdi, cur); - return 1; + /* I guess this makes sure the structure is not filled with invalid data. */ + if (cur->number != 1) + return 0; + cur->skip = skip * cur->sector_size; + cur->start += cur_pregap; + *total_pregap = cur_pregap; + cdi_track_push_back(cdi, cur); + return 1; } /* Current track consumes data from the same file as the previous. */ if (prev->file == cur->file) { - cur->start += *shift; - prev->length = cur->start + *total_pregap - prev->start - skip; - cur->skip += prev->skip + (prev->length * prev->sector_size) + (skip * cur->sector_size); - *total_pregap += cur_pregap; - cur->start += *total_pregap; + cur->start += *shift; + prev->length = cur->start + *total_pregap - prev->start - skip; + cur->skip += prev->skip + (prev->length * prev->sector_size) + (skip * cur->sector_size); + *total_pregap += cur_pregap; + cur->start += *total_pregap; } else { - temp = prev->file->get_length(prev->file) - ((uint64_t) prev->skip); - prev->length = temp / ((uint64_t) prev->sector_size); - if ((temp % prev->sector_size) != 0) - prev->length++; /* Padding. */ + temp = prev->file->get_length(prev->file) - ((uint64_t) prev->skip); + prev->length = temp / ((uint64_t) prev->sector_size); + if ((temp % prev->sector_size) != 0) + prev->length++; + /* Padding. */ - cur->start += prev->start + prev->length + cur_pregap; - cur->skip = skip * cur->sector_size; - *shift += prev->start + prev->length; - *total_pregap = cur_pregap; + cur->start += prev->start + prev->length + cur_pregap; + cur->skip = skip * cur->sector_size; + *shift += prev->start + prev->length; + *total_pregap = cur_pregap; } /* Error checks. */ if (cur->number <= 1) - return 0; + return 0; if ((prev->number + 1) != cur->number) - return 0; + return 0; if (cur->start < (prev->start + prev->length)) - return 0; + return 0; cdi_track_push_back(cdi, cur); @@ -777,11 +815,11 @@ cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, u int -cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile) +cdi_load_cue(cd_img_t *cdi, const char *cuefile) { track_t trk; - wchar_t pathname[MAX_FILENAME_LENGTH], filename[MAX_FILENAME_LENGTH]; - wchar_t temp[MAX_FILENAME_LENGTH]; + char pathname[MAX_FILENAME_LENGTH], filename[MAX_FILENAME_LENGTH]; + char temp[MAX_FILENAME_LENGTH]; uint64_t shift = 0ULL, prestart = 0ULL; uint64_t cur_pregap = 0ULL, total_pregap = 0ULL; uint64_t frame = 0ULL, index; @@ -798,197 +836,203 @@ cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile) memset(&trk, 0, sizeof(track_t)); /* Get a copy of the filename into pathname, we need it later. */ - memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - plat_get_dirname(pathname, cuefile); + memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(char)); + path_get_dirname(pathname, cuefile); /* Open the file. */ - fp = plat_fopen((wchar_t *) cuefile, L"r"); + fp = plat_fopen(cuefile, "r"); if (fp == NULL) - return 0; + return 0; success = 0; for (;;) { - line = buf; + line = buf; - /* Read a line from the cuesheet file. */ - if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp)) - break; + /* Read a line from the cuesheet file. */ + if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp)) + break; - /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, - but do checks to make sure we're not nuking other bytes. */ - for (i = 0; i < 2; i++) { - if (strlen(buf) > 0) { - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ - else if (buf[strlen(buf) - 1] == '\r') - buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ - } + /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, + but do checks to make sure we're not nuking other bytes. */ + for (i = 0; i < 2; i++) { + if (strlen(buf) > 0) { + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + /* nuke trailing newline */ + else if (buf[strlen(buf) - 1] == '\r') + buf[strlen(buf) - 1] = '\0'; + /* nuke trailing newline */ + } + } + + success = cdi_cue_get_keyword(&command, &line); + + if (!strcmp(command, "TRACK")) { + if (can_add_track) + success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); + else + success = 1; + if (!success) + break; + + trk.start = 0; + trk.skip = 0; + cur_pregap = 0; + prestart = 0; + + trk.number = cdi_cue_get_number(&line); + trk.track_number = trk.number; + success = cdi_cue_get_keyword(&type, &line); + if (!success) + break; + + trk.form = 0; + trk.mode2 = 0; + + trk.pre = 0; + + if (!strcmp(type, "AUDIO")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = AUDIO_TRACK; + } else if (!strcmp(type, "MODE1/2048")) { + trk.sector_size = COOKED_SECTOR_SIZE; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE1/2352")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE1/2448")) { + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE2/2048")) { + trk.form = 1; + trk.sector_size = COOKED_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2324")) { + trk.form = 2; + trk.sector_size = 2324; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2328")) { + trk.form = 2; + trk.sector_size = 2328; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2336")) { + trk.sector_size = 2336; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2352")) { + /* Assume this is XA Mode 2 Form 1. */ + trk.form = 1; + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2448")) { + /* Assume this is XA Mode 2 Form 1. */ + trk.form = 1; + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDG/2448")) { + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDI/2336")) { + trk.sector_size = 2336; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDI/2352")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else + success = 0; + + can_add_track = 1; + } else if (!strcmp(command, "INDEX")) { + index = cdi_cue_get_number(&line); + success = cdi_cue_get_frame(&frame, &line); + + switch(index) { + case 0: + prestart = frame; + break; + + case 1: + trk.start = frame; + break; + + default: + /* Ignore other indices. */ + break; + } + } else if (!strcmp(command, "FILE")) { + if (can_add_track) + success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); + else + success = 1; + if (!success) + break; + can_add_track = 0; + + memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); + memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(char)); + + success = cdi_cue_get_buffer(ansi, &line, 0); + if (!success) + break; + success = cdi_cue_get_keyword(&type, &line); + if (!success) + break; + + trk.file = NULL; + error = 1; + + if (!strcmp(type, "BINARY")) { + memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(char)); + path_append_filename(filename, pathname, ansi); + trk.file = track_file_init(filename, &error); + } + if (error) { +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG + cdrom_image_backend_log("CUE: cannot open fille '%s' in cue sheet!\n", + filename); +#endif + if (trk.file != NULL) { + trk.file->close(trk.file); + trk.file = NULL; + } + success = 0; + } + } else if (!strcmp(command, "PREGAP")) + success = cdi_cue_get_frame(&cur_pregap, &line); + else if (!strcmp(command, "FLAGS")) + success = cdi_cue_get_flags(&trk, &line); + else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "ISRC") || + !strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") || + !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) { + /* Ignored commands. */ + success = 1; + } else { +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG + cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n", command); +#endif + success = 0; } - success = cdi_cue_get_keyword(&command, &line); - - if (!strcmp(command, "TRACK")) { - if (can_add_track) - success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); - else - success = 1; - if (!success) - break; - - trk.start = 0; - trk.skip = 0; - cur_pregap = 0; - prestart = 0; - - trk.number = cdi_cue_get_number(&line); - trk.track_number = trk.number; - success = cdi_cue_get_keyword(&type, &line); - if (!success) - break; - - trk.form = 0; - trk.mode2 = 0; - - if (!strcmp(type, "AUDIO")) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = AUDIO_TRACK; - } else if (!strcmp(type, "MODE1/2048")) { - trk.sector_size = COOKED_SECTOR_SIZE; - trk.attr = DATA_TRACK; - } else if (!strcmp(type, "MODE1/2352")) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = DATA_TRACK; - } else if (!strcmp(type, "MODE1/2448")) { - trk.sector_size = 2448; - trk.attr = DATA_TRACK; - } else if (!strcmp(type, "MODE2/2048")) { - trk.form = 1; - trk.sector_size = COOKED_SECTOR_SIZE; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2324")) { - trk.form = 2; - trk.sector_size = 2324; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2328")) { - trk.form = 2; - trk.sector_size = 2328; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2336")) { - trk.sector_size = 2336; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2352")) { - trk.form = 1; /* Assume this is XA Mode 2 Form 1. */ - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "MODE2/2448")) { - trk.form = 1; /* Assume this is XA Mode 2 Form 1. */ - trk.sector_size = 2448; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "CDG/2448")) { - trk.sector_size = 2448; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "CDI/2336")) { - trk.sector_size = 2336; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else if (!strcmp(type, "CDI/2352")) { - trk.sector_size = RAW_SECTOR_SIZE; - trk.attr = DATA_TRACK; - trk.mode2 = 1; - } else - success = 0; - - can_add_track = 1; - } else if (!strcmp(command, "INDEX")) { - index = cdi_cue_get_number(&line); - success = cdi_cue_get_frame(&frame, &line); - - switch(index) { - case 0: - prestart = frame; - break; - - case 1: - trk.start = frame; - break; - - default: - /* ignore other indices */ - break; - } - } else if (!strcmp(command, "FILE")) { - if (can_add_track) - success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); - else - success = 1; - if (!success) - break; - can_add_track = 0; - - memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); - memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - - success = cdi_cue_get_buffer(ansi, &line, 0); - if (!success) - break; - success = cdi_cue_get_keyword(&type, &line); - if (!success) - break; - - trk.file = NULL; - error = 1; - - if (!strcmp(type, "BINARY")) { - memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - mbstowcs(temp, ansi, sizeof_w(temp)); - plat_append_filename(filename, pathname, temp); - trk.file = track_file_init(filename, &error); - } - if (error) { -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - cdrom_image_backend_log("CUE: cannot open fille '%ls' in cue sheet!\n", - filename); -#endif - if (trk.file != NULL) { - trk.file->close(trk.file); - trk.file = NULL; - } - success = 0; - } - } else if (!strcmp(command, "PREGAP")) - success = cdi_cue_get_frame(&cur_pregap, &line); - else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "FLAGS") || !strcmp(command, "ISRC") || - !strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") || - !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) { - /* Ignored commands. */ - success = 1; - } else { -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n", - command.c_str()); -#endif - success = 0; - } - - if (!success) - break; + if (!success) + break; } fclose(fp); if (!success) - return 0; + return 0; /* Add last track. */ if (!cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap)) - return 0; + return 0; /* Add lead out track. */ trk.number++; @@ -998,7 +1042,7 @@ cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile) trk.length = 0; trk.file = NULL; if (!cdi_add_track(cdi, &trk, &shift, 0, &total_pregap, 0)) - return 0; + return 0; return 1; } @@ -1010,12 +1054,12 @@ cdi_has_data_track(cd_img_t *cdi) int i; if ((cdi == NULL) || (cdi->tracks == NULL)) - return 0; + return 0; /* Data track has attribute 0x14. */ for (i = 0; i < cdi->tracks_num; i++) { - if (cdi->tracks[i].attr == DATA_TRACK) - return 1; + if (cdi->tracks[i].attr == DATA_TRACK) + return 1; } return 0; @@ -1028,12 +1072,12 @@ cdi_has_audio_track(cd_img_t *cdi) int i; if ((cdi == NULL) || (cdi->tracks == NULL)) - return 0; + return 0; /* Audio track has attribute 0x14. */ for (i = 0; i < cdi->tracks_num; i++) { - if (cdi->tracks[i].attr == AUDIO_TRACK) - return 1; + if (cdi->tracks[i].attr == AUDIO_TRACK) + return 1; } return 0; diff --git a/src/chipset/82c100.c b/src/chipset/82c100.c new file mode 100644 index 000000000..8b2259374 --- /dev/null +++ b/src/chipset/82c100.c @@ -0,0 +1,411 @@ +/* + * 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 Chips&Technology's 82C100 chipset. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include "cpu.h" +#include "x86.h" +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/nmi.h> +#include <86box/port_92.h> +#include <86box/rom.h> +#include <86box/chipset.h> + + +typedef struct +{ + int enabled; + uint32_t virt, phys; +} ems_page_t; + + +typedef struct +{ + uint8_t index, access; + uint16_t ems_io_base; + uint32_t ems_window_base; + uint8_t ems_page_regs[4], + regs[256]; + ems_page_t ems_pages[4]; + mem_mapping_t ems_mappings[4]; +} ct_82c100_t; + + +#ifdef ENABLE_CT_82C100_LOG +int ct_82c100_do_log = ENABLE_CT82C100_LOG; + + +static void +ct_82c100_log(const char *fmt, ...) +{ + va_list ap; + + if (ct_82c100_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ct_82c100_log(fmt, ...) +#endif + + +static void +ct_82c100_ems_pages_recalc(ct_82c100_t *dev) +{ + int i; + uint32_t page_base; + + for (i = 0; i < 4; i++) { + page_base = dev->ems_window_base + (i << 14); + if ((i == 1) || (i == 2)) + page_base ^= 0xc000; + if (dev->ems_page_regs[i] & 0x80) { + dev->ems_pages[i].virt = page_base; + dev->ems_pages[i].phys = 0xa0000 + (((uint32_t) (dev->ems_page_regs[i] & 0x7f)) << 14); + ct_82c100_log("Enabling EMS page %i: %08X-%08X -> %08X-%08X\n", i, + dev->ems_pages[i].virt, dev->ems_pages[i].virt + 0x00003fff, + dev->ems_pages[i].phys, dev->ems_pages[i].phys + 0x00003fff); + mem_mapping_set_addr(&(dev->ems_mappings[i]), dev->ems_pages[i].virt, 0x4000); + mem_mapping_set_exec(&(dev->ems_mappings[i]), &(ram[dev->ems_pages[i].phys])); + mem_set_mem_state_both(page_base, 0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else { + ct_82c100_log("Disabling EMS page %i\n", i); + mem_mapping_disable(&(dev->ems_mappings[i])); + mem_set_mem_state_both(page_base, 0x00004000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + } + + flushmmucache_nopc(); +} + + +static void +ct_82c100_ems_out(uint16_t port, uint8_t val, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + ct_82c100_log("[%04X] dev->ems_page_regs[%i] = %02X\n", port, port >> 14, val); + dev->ems_page_regs[port >> 14] = val; + ct_82c100_ems_pages_recalc(dev); +} + + +static uint8_t +ct_82c100_ems_in(uint16_t port, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + uint8_t ret = 0xff; + + ret = dev->ems_page_regs[port >> 14]; + + return ret; +} + + +static void +ct_82c100_ems_update(ct_82c100_t *dev) +{ + int i; + + for (i = 0; i < 4; i++) { + ct_82c100_log("Disabling EMS I/O handler %i at %04X\n", i, dev->ems_io_base + (i << 14)); + io_handler(0, dev->ems_io_base + (i << 14), 1, + ct_82c100_ems_in, NULL, NULL, ct_82c100_ems_out, NULL, NULL, dev); + } + + dev->ems_io_base = 0x0208 + (dev->regs[0x4c] & 0xf0); + + for (i = 0; i < 4; i++) { + ct_82c100_log("Enabling EMS I/O handler %i at %04X\n", i, dev->ems_io_base + (i << 14)); + io_handler(1, dev->ems_io_base + (i << 14), 1, + ct_82c100_ems_in, NULL, NULL, ct_82c100_ems_out, NULL, NULL, dev); + } + + dev->ems_window_base = 0xc0000 + (((uint32_t) (dev->regs[0x4c] & 0x0f)) << 14); + + ct_82c100_ems_pages_recalc(dev); +} + + +static void +ct_82c100_reset(void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + ct_82c100_log("Reset\n"); + + memset(dev->regs, 0x00, sizeof(dev->regs)); + memset(dev->ems_page_regs, 0x00, sizeof(dev->ems_page_regs)); + + dev->index = dev->access = 0x00; + + /* INTERNAL CONFIGURATION/CONTROL REGISTERS */ + dev->regs[0x40] = 0x01; /* Defaults to 8086/V30 mode. */ + dev->regs[0x43] = 0x30; + dev->regs[0x48] = 0x01; + + use_custom_nmi_vector = 0; + ct_82c100_ems_update(dev); + + /* ADDITIONAL I/O REGISTERS */ +} + + +static void +ct_82c100_out(uint16_t port, uint8_t val, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + if (port == 0x0022) { + dev->index = val; + dev->access = 1; + } else if (port == 0x0023) { + if (dev->access) { + switch (dev->index) { + /* INTERNAL CONFIGURATION/CONTROL REGISTERS */ + case 0x40: + dev->regs[0x40] = val & 0xc7; + /* TODO: Clock stuff - needs CPU speed change functionality that's + going to be implemented in 86box v4.0. + Bit 0 is 0 for 8088/V20 and 1 for 8086/V30. */ + break; + case 0x41: + dev->regs[0x41] = val & 0xed; + /* TODO: Where is the Software Reset Function that's enabled by + setting bit 6 to 1? */ + break; + case 0x42: + dev->regs[0x42] = val & 0x01; + break; + case 0x43: + dev->regs[0x43] = val; + break; + case 0x44: + dev->regs[0x44] = val; + custom_nmi_vector = (custom_nmi_vector & 0xffffff00) | ((uint32_t) val); + break; + case 0x45: + dev->regs[0x45] = val; + custom_nmi_vector = (custom_nmi_vector & 0xffff00ff) | (((uint32_t) val) << 8); + break; + case 0x46: + dev->regs[0x46] = val; + custom_nmi_vector = (custom_nmi_vector & 0xff00ffff) | (((uint32_t) val) << 16); + break; + case 0x47: + dev->regs[0x47] = val; + custom_nmi_vector = (custom_nmi_vector & 0x00ffffff) | (((uint32_t) val) << 24); + break; + case 0x48: case 0x49: + dev->regs[dev->index] = val; + break; + case 0x4b: + dev->regs[0x4b] = val; + use_custom_nmi_vector = !!(val & 0x40); + break; + case 0x4c: + ct_82c100_log("CS4C: %02X\n", val); + dev->regs[0x4c] = val; + ct_82c100_ems_update(dev); + break; + } + dev->access = 0; + } + } else if (port == 0x72) + dev->regs[0x72] = val & 0x7e; + else if (port == 0x7e) + dev->regs[0x7e] = val; + else if (port == 0x7f) { + /* Bit 3 is Software Controlled Reset, asserted if set. Will be + done in the feature/machine_and_kb branch using hardresetx86(). */ + dev->regs[0x7f] = val; + if ((dev->regs[0x41] & 0x40) && (val & 0x08)) { + softresetx86(); + cpu_set_edx(); + ct_82c100_reset(dev); + } + } +} + + +static uint8_t +ct_82c100_in(uint16_t port, void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + uint8_t ret = 0xff; + + if (port == 0x0022) + ret = dev->index; + else if (port == 0x0023) { + if (dev->access) { + switch (dev->index) { + /* INTERNAL CONFIGURATION/CONTROL REGISTERS */ + case 0x40 ... 0x49: + case 0x4b: case 0x4c: + ret = dev->regs[dev->index]; + break; + } + dev->access = 0; + } + } else if (port == 0x72) + ret = dev->regs[0x72]; + else if (port == 0x7e) + ret = dev->regs[0x7e]; + else if (port == 0x7f) + ret = dev->regs[0x7f]; + + return ret; +} + + +static uint8_t +mem_read_emsb(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + uint8_t ret = 0xff; +#ifdef ENABLE_CT_82C100_LOG + uint32_t old_addr = addr; +#endif + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + ret = ram[addr]; + + ct_82c100_log("mem_read_emsb(%08X = %08X): %02X\n", old_addr, addr, ret); + + return ret; +} + + +static uint16_t +mem_read_emsw(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + uint16_t ret = 0xffff; +#ifdef ENABLE_CT_82C100_LOG + uint32_t old_addr = addr; +#endif + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + ret = *(uint16_t *)&ram[addr]; + + ct_82c100_log("mem_read_emsw(%08X = %08X): %04X\n", old_addr, addr, ret); + + return ret; +} + + +static void +mem_write_emsb(uint32_t addr, uint8_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; +#ifdef ENABLE_CT_82C100_LOG + uint32_t old_addr = addr; +#endif + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; + + ct_82c100_log("mem_write_emsb(%08X = %08X, %02X)\n", old_addr, addr, val); +} + + +static void +mem_write_emsw(uint32_t addr, uint16_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; +#ifdef ENABLE_CT_82C100_LOG + uint32_t old_addr = addr; +#endif + + addr = addr - page->virt + page->phys; + + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; + + ct_82c100_log("mem_write_emsw(%08X = %08X, %04X)\n", old_addr, addr, val); +} + + +static void +ct_82c100_close(void *priv) +{ + ct_82c100_t *dev = (ct_82c100_t *) priv; + + free(dev); +} + + +static void * +ct_82c100_init(const device_t *info) +{ + ct_82c100_t *dev; + uint32_t i; + + dev = (ct_82c100_t *)malloc(sizeof(ct_82c100_t)); + memset(dev, 0x00, sizeof(ct_82c100_t)); + + ct_82c100_reset(dev); + + io_sethandler(0x0022, 2, + ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev); + io_sethandler(0x0072, 1, + ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev); + io_sethandler(0x007e, 2, + ct_82c100_in, NULL, NULL, ct_82c100_out, NULL, NULL, dev); + + for (i = 0; i < 4; i++) { + mem_mapping_add(&(dev->ems_mappings[i]), (i + 28) << 14, 0x04000, + mem_read_emsb, mem_read_emsw, NULL, + mem_write_emsb, mem_write_emsw, NULL, + ram + 0xa0000 + (i << 14), MEM_MAPPING_INTERNAL, &dev->ems_pages[i]); + mem_mapping_disable(&(dev->ems_mappings[i])); + } + + mem_mapping_disable(&ram_mid_mapping); + + device_add(&port_92_device); + + return(dev); +} + + +const device_t ct_82c100_device = { + .name = "C&T 82C100", + .internal_name = "ct_82c100", + .flags = 0, + .local = 0, + .init = ct_82c100_init, + .close = ct_82c100_close, + .reset = ct_82c100_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt new file mode 100644 index 000000000..517630ae4 --- /dev/null +++ b/src/chipset/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(chipset OBJECT 82c100.c acc2168.c cs8230.c ali1429.c ali1489.c ali1531.c ali1541.c ali1543.c + ali1621.c ali6117.c headland.c ims8848.c intel_82335.c contaq_82c59x.c cs4031.c intel_420ex.c + intel_4x0.c intel_i450kx.c intel_sio.c intel_piix.c ../ioapic.c neat.c opti283.c opti291.c opti391.c + opti495.c opti822.c opti895.c opti5x7.c scamp.c scat.c sis_85c310.c sis_85c4xx.c + sis_85c496.c sis_85c50x.c sis_5511.c sis_5571.c via_vt82c49x.c via_vt82c505.c sis_85c310.c + sis_85c4xx.c sis_85c496.c sis_85c50x.c gc100.c stpc.c umc_8886.c umc_hb4.c via_apollo.c + via_pipc.c vl82c480.c wd76c10.c) + +if(OLIVETTI) + target_sources(chipset PRIVATE olivetti_eva.c) +endif() diff --git a/src/chipset/acc2168.c b/src/chipset/acc2168.c index 11bca1cac..9b8865784 100644 --- a/src/chipset/acc2168.c +++ b/src/chipset/acc2168.c @@ -6,151 +6,202 @@ * * This file is part of the 86Box distribution. * - * Implementation of the ACC 2168 chipset - * used by the Packard Bell Legend 760 Supreme (PB410A or PB430). + * Implementation of the ACC 2046/2168 chipset * * * * Authors: Sarah Walker, + * Tiseno100 * * Copyright 2019 Sarah Walker. + * Copyright 2021 Tiseno100. */ -#include +#include #include +#include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/timer.h> #include <86box/device.h> -#include <86box/keyboard.h> #include <86box/io.h> #include <86box/mem.h> -#include <86box/mouse.h> #include <86box/port_92.h> -#include <86box/sio.h> -#include <86box/hdc.h> -#include <86box/video.h> #include <86box/chipset.h> +#define ENABLED_SHADOW (MEM_READ_INTERNAL | ((dev->regs[0x02] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) +#define DISABLED_SHADOW (MEM_READ_EXTANY | MEM_WRITE_EXTANY) +#define SHADOW_ADDR ((i <= 1) ? (0xc0000 + (i << 15)) : (0xd0000 + ((i - 2) << 16))) +#define SHADOW_SIZE ((i <= 1) ? 0x8000 : 0x10000) +#define SHADOW_RECALC ((dev->regs[0x02] & (1 << i)) ? ENABLED_SHADOW : DISABLED_SHADOW) + +#ifdef ENABLE_ACC2168_LOG +int acc2168_do_log = ENABLE_ACC2168_LOG; +static void +acc2168_log(const char *fmt, ...) +{ + va_list ap; + + if (acc2168_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define acc2168_log(fmt, ...) +#endif typedef struct acc2168_t { - int reg_idx; - uint8_t regs[256]; - uint8_t port_78; + uint8_t reg_idx, regs[256]; } acc2168_t; - -/* - Based on reverse engineering using the AMI 386DX Clone BIOS: - Bit 0 of register 02 controls shadowing of C0000-C7FFF (1 = enabled, 0 = disabled); - Bit 1 of register 02 controls shadowing of C8000-CFFFF (1 = enabled, 0 = disabled); - Bit 2 of register 02 controls shadowing of D0000-DFFFF (1 = enabled, 0 = disabled); - Bit 3 of register 02 controls shadowing of E0000-EFFFF (1 = enabled, 0 = disabled); - Bit 4 of register 02 controls shadowing of F0000-FFFFF (1 = enabled, 0 = disabled); - Bit 5 is most likely: 1 = shadow enabled, 0 = shadow disabled; - Bit 6 of register 02 controls shadow RAM cacheability (1 = cacheable, 0 = non-cacheable). -*/ - -static void +static void acc2168_shadow_recalc(acc2168_t *dev) { - int state; - - if (dev->regs[0x02] & 0x20) - state = (dev->regs[0x02] & 0x20) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY); - - mem_set_mem_state(0xc0000, 0x08000, (dev->regs[0x02] & 0x01) ? state : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state(0xc8000, 0x08000, (dev->regs[0x02] & 0x02) ? state : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state(0xd0000, 0x10000, (dev->regs[0x02] & 0x04) ? state : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state(0xe0000, 0x10000, (dev->regs[0x02] & 0x08) ? state : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state(0xf0000, 0x10000, (dev->regs[0x02] & 0x10) ? state : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + for (uint32_t i = 0; i < 5; i++) + mem_set_mem_state_both(SHADOW_ADDR, SHADOW_SIZE, SHADOW_RECALC); } - -static void +static void acc2168_write(uint16_t addr, uint8_t val, void *p) { acc2168_t *dev = (acc2168_t *)p; - if (!(addr & 1)) - dev->reg_idx = val; - else { - dev->regs[dev->reg_idx] = val; + switch (addr) + { + case 0xf2: + dev->reg_idx = val; + break; + case 0xf3: + acc2168_log("ACC2168: dev->regs[%02x] = %02x\n", dev->reg_idx, val); + switch (dev->reg_idx) + { + case 0x00: + dev->regs[dev->reg_idx] = val; + break; - switch (dev->reg_idx) { - case 0x02: - acc2168_shadow_recalc(dev); - break; - } + case 0x01: + dev->regs[dev->reg_idx] = val & 0xd3; + cpu_update_waitstates(); + break; + + case 0x02: + dev->regs[dev->reg_idx] = val & 0x7f; + acc2168_shadow_recalc(dev); + break; + + case 0x03: + dev->regs[dev->reg_idx] = val & 0x1f; + break; + + case 0x04: + dev->regs[dev->reg_idx] = val; + cpu_cache_ext_enabled = !!(val & 0x01); + cpu_update_waitstates(); + break; + + case 0x05: + dev->regs[dev->reg_idx] = val & 0xf3; + break; + + case 0x06: + case 0x07: + dev->regs[dev->reg_idx] = val & 0x1f; + break; + + case 0x08: + dev->regs[dev->reg_idx] = val & 0x0f; + break; + + case 0x09: + dev->regs[dev->reg_idx] = val & 0x03; + break; + + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + dev->regs[dev->reg_idx] = val; + break; + + case 0x12: + dev->regs[dev->reg_idx] = val & 0xbb; + break; + + case 0x18: + dev->regs[dev->reg_idx] = val & 0x77; + break; + + case 0x19: + dev->regs[dev->reg_idx] = val & 0xfb; + break; + + case 0x1a: + dev->regs[dev->reg_idx] = val; + cpu_cache_int_enabled = !(val & 0x40); + cpu_update_waitstates(); + break; + + case 0x1b: + dev->regs[dev->reg_idx] = val & 0xef; + break; + + default: /* ACC 2168 has way more registers which we haven't documented */ + dev->regs[dev->reg_idx] = val; + break; + + } + break; } } - -static uint8_t +static uint8_t acc2168_read(uint16_t addr, void *p) { acc2168_t *dev = (acc2168_t *)p; - if (!(addr & 1)) - return dev->reg_idx; - - return dev->regs[dev->reg_idx]; + return (addr == 0xf3) ? dev->regs[dev->reg_idx] : dev->reg_idx; } - -/* - Bit 7 = Super I/O chip: 1 = enabled, 0 = disabled; - Bit 6 = Graphics card: 1 = standalone, 0 = on-board; - Bit 5 = ???? (if 1, siren and hangs). -*/ -static uint8_t -acc2168_port_78_read(uint16_t addr, void *p) -{ - acc2168_t *dev = (acc2168_t *)p; - - return dev->port_78; -} - - static void acc2168_close(void *priv) { - acc2168_t *dev = (acc2168_t *) priv; + acc2168_t *dev = (acc2168_t *)priv; free(dev); } - static void * acc2168_init(const device_t *info) { acc2168_t *dev = (acc2168_t *)malloc(sizeof(acc2168_t)); memset(dev, 0, sizeof(acc2168_t)); - - io_sethandler(0x00f2, 0x0002, - acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, dev); - io_sethandler(0x0078, 0x0001, - acc2168_port_78_read, NULL, NULL, NULL, NULL, NULL, dev); - device_add(&port_92_inv_device); - - if (gfxcard != VID_INTERNAL) - dev->port_78 = 0x40; - else - dev->port_78 = 0; + device_add(&port_92_device); + io_sethandler(0x00f2, 0x0002, acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, dev); return dev; } - const device_t acc2168_device = { - "ACC 2168", - 0, - 0, - acc2168_init, acc2168_close, NULL, - NULL, NULL, NULL, - NULL + .name = "ACC 2046/2168", + .internal_name = "acc2168", + .flags = 0, + .local = 0, + .init = acc2168_init, + .close = acc2168_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/acer_m3a.c b/src/chipset/acer_m3a.c deleted file mode 100644 index fc7717a11..000000000 --- a/src/chipset/acer_m3a.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 Acer M3A and V35N ports EAh and EBh. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2019 Miran Grca. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> -#include <86box/device.h> -#include <86box/keyboard.h> -#include <86box/chipset.h> - - -typedef struct -{ - int index; -} acerm3a_t; - - -static void -acerm3a_out(uint16_t port, uint8_t val, void *p) -{ - acerm3a_t *dev = (acerm3a_t *) p; - - if (port == 0xea) - dev->index = val; -} - - -static uint8_t -acerm3a_in(uint16_t port, void *p) -{ - acerm3a_t *dev = (acerm3a_t *) p; - - if (port == 0xeb) { - switch (dev->index) { - case 2: - return 0xfd; - } - } - return 0xff; -} - - -static void -acerm3a_close(void *p) -{ - acerm3a_t *dev = (acerm3a_t *)p; - - free(dev); -} - - -static void -*acerm3a_init(const device_t *info) -{ - acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); - memset(acerm3a, 0, sizeof(acerm3a_t)); - - io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); - - return acerm3a; -} - - -const device_t acerm3a_device = -{ - "Acer M3A Register", - 0, - 0, - acerm3a_init, - acerm3a_close, - NULL, - NULL, - NULL, - NULL, - NULL -}; diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index 5e19983c7..468ed4f00 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -6,103 +6,274 @@ * * This file is part of the 86Box distribution. * - * Implementation of the ALi M-1429/1431 chipset. + * Implementation of the ALi M1429 chipset. * + * Note: This chipset has no datasheet, everything were done via + * reverse engineering the BIOS of various machines using it. * - * - * Authors: Sarah Walker, + * Authors: Tiseno100, * Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2020,2021 Tiseno100. + * Copyright 2021,2021 Miran Grca. */ -#include + +/* + ALi M1429/M1429G Configuration Registers + + Notes: Incorporated sometimes with a M1435 PCI-to-VLB Bridge + M1429G is just a 1429 with Green Functionality + SMM in it's entirety needs more research + + Warning: Register documentation may be inaccurate! + + Register 03h: Write C5h to unlock the configuration registers + + Register 10h & 11h: DRAM Bank Configuration + + Register 12h: + Bit 2: Memory Remapping Enable (128KB) + + Register 13h: + Bit 7: Shadow RAM Enable for F8000-FFFFF + Bit 6: Shadow RAM Enable for F0000-F7FFF + Bit 5: Shadow RAM Enable for E8000-FFFFF + Bit 4: Shadow RAM Enable for E0000-F7FFF + Bit 3: Shadow RAM Enable for D8000-FFFFF + Bit 2: Shadow RAM Enable for D0000-F7FFF + Bit 1: Shadow RAM Enable for C8000-FFFFF + Bit 0: Shadow RAM Enable for C0000-F7FFF + + Register 14h: + Bit 1: Shadow RAM Write for Enabled Segments + Bit 0: Shadow RAM Read for Enabled Segments + + Register 18h: + Bit 6-5-4 (Cache Size) + 0 0 0 32KB + 0 0 1 128KB + 0 1 0 256KB + 0 1 1 512KB + 1 0 0 64KB + 1 0 1 256KB + 1 1 0 512KB + 1 1 1 1MB + + Bit 1: L2 Cache Enable + + Register 20h: + Bits 2-1-0: Bus Clock Speed + 0 0 0: 7.1519Mhz (ATCLK2) + 0 0 1: CLK2IN/4 + 0 1 0: CLK2IN/5 + 0 1 1: CLK2IN/6 + 1 0 0: CLK2IN/8 + 1 0 1: CLK2IN/10 + 1 1 0: CLK2IN/12 + +*/ + +#include #include +#include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/timer.h> #include <86box/io.h> -#include <86box/mem.h> #include <86box/device.h> -#include <86box/keyboard.h> + +#include <86box/apm.h> +#include <86box/mem.h> #include <86box/fdd.h> #include <86box/fdc.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/timer.h> #include <86box/port_92.h> +#include <86box/smram.h> #include <86box/chipset.h> +#define GREEN dev->is_g /* Is G Variant */ + + +#ifdef ENABLE_ALI1429_LOG +int ali1429_do_log = ENABLE_ALI1429_LOG; + + +static void +ali1429_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1429_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1429_log(fmt, ...) +#endif + typedef struct { - uint8_t cur_reg, - regs[256]; + uint8_t is_g, index, cfg_locked, reg_57h, + regs[90]; } ali1429_t; static void -ali1429_recalc(ali1429_t *dev) +ali1429_shadow_recalc(ali1429_t *dev) { - uint32_t base; - uint32_t i, shflags = 0; + uint32_t base, i, can_write, can_read; - shadowbios = 0; - shadowbios_write = 0; + shadowbios = (dev->regs[0x13] & 0x40) && (dev->regs[0x14] & 0x01); + shadowbios_write = (dev->regs[0x13] & 0x40) && (dev->regs[0x14] & 0x02); + + can_write = (dev->regs[0x14] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + can_read = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; for (i = 0; i < 8; i++) { - base = 0xc0000 + (i << 15); + base = 0xc0000 + (i << 15); - if (dev->regs[0x13] & (1 << i)) { - shadowbios |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x01); - shadowbios_write |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x02); - shflags = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - shflags |= !(dev->regs[0x14] & 0x02) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; - mem_set_mem_state(base, 0x8000, shflags); - } else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + if (dev->regs[0x13] & (1 << i)) + mem_set_mem_state_both(base, 0x8000, can_read | can_write); + else + mem_set_mem_state_both(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } - flushmmucache(); + flushmmucache_nopc(); } static void -ali1429_write(uint16_t port, uint8_t val, void *priv) +ali1429_write(uint16_t addr, uint8_t val, void *priv) { - ali1429_t *dev = (ali1429_t *) priv; + ali1429_t *dev = (ali1429_t *)priv; - if (port & 1) { - dev->regs[dev->cur_reg] = val; + switch (addr) { + case 0x22: + dev->index = val; + break; - switch (dev->cur_reg) { - case 0x13: - ali1429_recalc(dev); - break; - case 0x14: - ali1429_recalc(dev); - break; - } - } else - dev->cur_reg = val; + case 0x23: +#ifdef ENABLE_ALI1429_LOG + if (dev->index != 0x03) + ali1429_log("M1429: dev->regs[%02x] = %02x\n", dev->index, val); +#endif + + if (dev->index == 0x03) + dev->cfg_locked = !(val == 0xc5); + + if (!dev->cfg_locked) { + /* Common M1429 Registers */ + switch (dev->index) { + case 0x10: case 0x11: + dev->regs[dev->index] = val; + break; + + case 0x12: + dev->regs[dev->index] = val; + if(val & 4) + mem_remap_top(128); + else + mem_remap_top(0); + break; + + case 0x13: case 0x14: + dev->regs[dev->index] = val; + ali1429_shadow_recalc(dev); + break; + + case 0x15: case 0x16: + case 0x17: + dev->regs[dev->index] = val; + break; + + case 0x18: + dev->regs[dev->index] = (val & 0x8f) | 0x20; + cpu_cache_ext_enabled = !!(val & 2); + cpu_update_waitstates(); + break; + + case 0x19: case 0x1a: + case 0x1e: + dev->regs[dev->index] = val; + break; + + case 0x20: + dev->regs[dev->index] = val; + + switch(val & 7) { + case 0: case 7: /* Illegal */ + cpu_set_isa_speed(7159091); + break; + + case 1: + cpu_set_isa_speed(cpu_busspeed / 4); + break; + + case 2: + cpu_set_isa_speed(cpu_busspeed / 5); + break; + + case 3: + cpu_set_isa_speed(cpu_busspeed / 6); + break; + + case 4: + cpu_set_isa_speed(cpu_busspeed / 8); + break; + + case 5: + cpu_set_isa_speed(cpu_busspeed / 10); + break; + + case 6: + cpu_set_isa_speed(cpu_busspeed / 12); + break; + } + break; + + case 0x21 ... 0x27: + dev->regs[dev->index] = val; + break; + } + + /* M1429G Only Registers */ + if (GREEN) { + switch (dev->index) { + case 0x30 ... 0x41: + case 0x43: case 0x45: + case 0x4a: + dev->regs[dev->index] = val; + break; + + case 0x57: + dev->reg_57h = val; + break; + } + } + } + break; + } } static uint8_t -ali1429_read(uint16_t port, void *priv) +ali1429_read(uint16_t addr, void *priv) { + ali1429_t *dev = (ali1429_t *)priv; uint8_t ret = 0xff; - ali1429_t *dev = (ali1429_t *) priv; - if (!(port & 1)) - ret = dev->cur_reg; - else if (((dev->cur_reg >= 0xc0) || (dev->cur_reg == 0x20)) && cpu_iscyrix) - ret = 0xff; /*Don't conflict with Cyrix config registers*/ - else - ret = dev->regs[dev->cur_reg]; + if ((addr == 0x23) && (dev->index >= 0x10) && (dev->index <= 0x4a)) + ret = dev->regs[dev->index]; + else if ((addr == 0x23) && (dev->index == 0x57)) + ret = dev->reg_57h; + else if (addr == 0x22) + ret = dev->index; return ret; } @@ -111,36 +282,86 @@ ali1429_read(uint16_t port, void *priv) static void ali1429_close(void *priv) { - ali1429_t *dev = (ali1429_t *) priv; + ali1429_t *dev = (ali1429_t *)priv; free(dev); } +static void +ali1429_defaults(ali1429_t *dev) +{ + /* M1429 Defaults */ + dev->regs[0x10] = 0xf0; + dev->regs[0x11] = 0xff; + dev->regs[0x12] = 0x10; + dev->regs[0x14] = 0x48; + dev->regs[0x15] = 0x40; + dev->regs[0x17] = 0x7a; + dev->regs[0x1a] = 0x80; + dev->regs[0x22] = 0x80; + dev->regs[0x23] = 0x57; + dev->regs[0x25] = 0xc0; + dev->regs[0x27] = 0x30; + + /* M1429G Default Registers */ + if (GREEN) { + dev->regs[0x31] = 0x88; + dev->regs[0x32] = 0xc0; + dev->regs[0x38] = 0xe5; + dev->regs[0x40] = 0xe3; + dev->regs[0x41] = 2; + dev->regs[0x45] = 0x80; + } +} + + static void * ali1429_init(const device_t *info) { - ali1429_t *dev = (ali1429_t *) malloc(sizeof(ali1429_t)); + ali1429_t *dev = (ali1429_t *)malloc(sizeof(ali1429_t)); memset(dev, 0, sizeof(ali1429_t)); - memset(dev->regs, 0xff, 256); - dev->regs[0x13] = dev->regs[0x14] = 0x00; + dev->cfg_locked = 1; + GREEN = info->local; + /* M1429 Ports: + 22h Index Port + 23h Data Port + */ io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev); - ali1429_recalc(dev); - device_add(&port_92_device); + ali1429_defaults(dev); + return dev; } - const device_t ali1429_device = { - "ALi-M1429", - 0, - 0, - ali1429_init, ali1429_close, NULL, - NULL, NULL, NULL, - NULL + .name = "ALi M1429", + .internal_name = "ali1429", + .flags = 0, + .local = 0, + .init = ali1429_init, + .close = ali1429_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ali1429g_device = { + .name = "ALi M1429G", + .internal_name = "ali1429g", + .flags = 0, + .local = 1, + .init = ali1429_init, + .close = ali1429_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c new file mode 100644 index 000000000..da6ff39cc --- /dev/null +++ b/src/chipset/ali1489.c @@ -0,0 +1,641 @@ +/* + * 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 ALi M1489 chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2020,2021 Tiseno100. + * Copyright 2020,2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#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/hdc_ide.h> +#include <86box/hdc.h> +#include <86box/mem.h> +#include <86box/nmi.h> +#include <86box/pic.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/smram.h> + +#include <86box/chipset.h> + + +#define DEFINE_SHADOW_PROCEDURE (((dev->regs[0x14] & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x14] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)) +#define DISABLED_SHADOW (MEM_READ_EXTANY | MEM_WRITE_EXTANY) + + +#ifdef ENABLE_ALI1489_LOG +int ali1489_do_log = ENABLE_ALI1489_LOG; +static void +ali1489_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1489_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1489_log(fmt, ...) +#endif + + +typedef struct +{ + uint8_t index, ide_index, ide_chip_id, pci_slot, + regs[256], pci_conf[256], ide_regs[256]; + + port_92_t * port_92; + smram_t * smram; +} ali1489_t; + + +static void ali1489_ide_handler(ali1489_t *dev); + + +static void +ali1489_shadow_recalc(ali1489_t *dev) +{ + uint32_t i; + + shadowbios = shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + if (dev->regs[0x13] & (1 << i)) { + ali1489_log("%06Xh-%06Xh region shadow enabled: read = %i, write = %i\n", + 0xc0000 + (i << 14), 0xc3fff + (i << 14), !!(dev->regs[0x14] & 0x10), !!(dev->regs[0x14] & 0x20)); + mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, DEFINE_SHADOW_PROCEDURE); + } else { + ali1489_log("%06Xh-%06Xh region shadow disabled\n", 0xc0000 + (i << 14), 0xc3fff + (i << 14)); + mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, DISABLED_SHADOW); + } + } + + for (i = 0; i < 4; i++) { + if (dev->regs[0x14] & (1 << i)) { + ali1489_log("%06Xh-%06Xh region shadow enabled: read = %i, write = %i\n", + 0xe0000 + (i << 15), 0xe7fff + (i << 15), !!(dev->regs[0x14] & 0x10), !!(dev->regs[0x14] & 0x20)); + mem_set_mem_state_both(0xe0000 + (i << 15), 0x8000, DEFINE_SHADOW_PROCEDURE); + shadowbios |= !!(dev->regs[0x14] & 0x10); + shadowbios_write |= !!(dev->regs[0x14] & 0x20); + } else { + ali1489_log("%06Xh-%06Xh region shadow disabled\n", 0xe0000 + (i << 15), 0xe7fff + (i << 15)); + mem_set_mem_state_both(0xe0000 + (i << 15), 0x8000, DISABLED_SHADOW); + } + } + + flushmmucache_nopc(); +} + + +static void +ali1489_smram_recalc(ali1489_t *dev) +{ + /* The datasheet documents SMM behavior quite terribly. + Everything were done according to the M1489 programming guide. */ + smram_disable(dev->smram); + + switch (dev->regs[0x19] & 0x30) { + case 0x10: + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, (dev->regs[0x19] & 0x08), 1); + break; + case 0x20: + smram_enable(dev->smram, 0xe0000, 0xe0000, 0x10000, (dev->regs[0x19] & 0x08), 1); + break; + case 0x30: + if ((dev->regs[0x35] & 0xc0) == 0x80) + smram_enable(dev->smram, 0x68000, 0xa8000, 0x08000, (dev->regs[0x19] & 0x08), 1); + else + smram_enable(dev->smram, 0x38000, 0xa8000, 0x08000, (dev->regs[0x19] & 0x08), 1); + break; + } + + if ((dev->regs[0x19] & 0x31) == 0x11) { + /* If SMRAM is enabled and bit 0 is set, code still goes to DRAM. */ + mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); + } +} + + +static void +ali1489_defaults(ali1489_t *dev) +{ + memset(dev->ide_regs, 0x00, 256); + memset(dev->pci_conf, 0x00, 256); + memset(dev->regs, 0x00, 256); + + ide_pri_disable(); + ide_sec_disable(); + + /* IDE registers */ + dev->ide_regs[0x00] = 0x57; + dev->ide_regs[0x01] = 0x02; + dev->ide_regs[0x08] = 0xff; + dev->ide_regs[0x09] = 0x41; + dev->ide_regs[0x0c] = 0x02; + dev->ide_regs[0x0e] = 0x02; + dev->ide_regs[0x10] = 0x02; + dev->ide_regs[0x12] = 0x02; + dev->ide_regs[0x34] = 0xff; + dev->ide_regs[0x35] = 0x01; + + /* PCI registers */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x89; + dev->pci_conf[0x03] = 0x14; + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x0b] = 0x06; + + /* ISA registers */ + dev->regs[0x01] = 0x0f; + dev->regs[0x02] = 0x0f; + dev->regs[0x10] = 0xf1; + dev->regs[0x11] = 0xff; + dev->regs[0x15] = 0x20; + dev->regs[0x16] = 0x30; + dev->regs[0x19] = 0x04; + dev->regs[0x21] = 0x72; + dev->regs[0x28] = 0x02; + dev->regs[0x2b] = 0xdb; + dev->regs[0x3c] = 0x03; + dev->regs[0x3d] = 0x01; + dev->regs[0x40] = 0x03; + + ali1489_shadow_recalc(dev); + cpu_cache_int_enabled = 0; + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + ali1489_smram_recalc(dev); + + port_92_remove(dev->port_92); + + picintc(1 << 10); + picintc(1 << 15); + nmi = 0; + smi_line = 0; + in_smm = 0; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + ali1489_ide_handler(dev); +} + + +static void +ali1489_write(uint16_t addr, uint8_t val, void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + uint8_t old, irq; + const uint8_t irq_array[16] = { 0, 3, 4, 7, 0, 0, 0, 0, 9, 10, 5, 6, 11, 12, 14, 15 }; + + switch (addr) { + case 0x22: + dev->index = val; + break; + case 0x23: + /* Check if the configuration registers are unlocked */ + if (dev->regs[0x03] == 0xc5) { + switch (dev->index) { + case 0x03: /* Lock Register */ + case 0x10: /* DRAM Configuration Register I */ + case 0x11: /* DRAM Configuration Register II */ + case 0x12: /* ROM Function Register */ + dev->regs[dev->index] = val; + break; + + case 0x13: /* Shadow Region Register */ + case 0x14: /* Shadow Control Register */ + if (dev->index == 0x14) + dev->regs[dev->index] = (val & 0xbf); + else + dev->regs[dev->index] = val; + + ali1489_shadow_recalc(dev); + ali1489_smram_recalc(dev); + break; + + case 0x15: /* Cycle Check Point Control Register */ + dev->regs[dev->index] = (val & 0xf1); + break; + + case 0x16: /* Cache Control Register I */ + dev->regs[dev->index] = val; + cpu_cache_int_enabled = (val & 0x01); + cpu_cache_ext_enabled = (val & 0x02); + cpu_update_waitstates(); + break; + case 0x17: /* Cache Control Register II */ + dev->regs[dev->index] = val; + break; + + case 0x19: /* SMM Control Register */ + dev->regs[dev->index] = val; + ali1489_smram_recalc(dev); + break; + + case 0x1a: /* EDO DRAM Configuration Register */ + case 0x1b: /* DRAM Timing Control Register */ + dev->regs[dev->index] = val; + break; + case 0x1c: /* Memory Data Buffer Direction Control Register */ + dev->regs[dev->index] = val & 0x1f; + break; + + case 0x1e: /* Linear Wrapped Burst Order Mode Control Register */ + dev->regs[dev->index] = (val & 0x40); + break; + + case 0x20: /* CPU to PCI Buffer Control Register */ + dev->regs[dev->index] = val; + break; + case 0x21: /* DEVSELJ Check Point Setting Register */ + dev->regs[dev->index] = (val & 0xbb) | 0x04; + break; + case 0x22: /* PCI to CPU W/R Buffer Configuration Register */ + dev->regs[dev->index] = (val & 0xfd); + break; + + case 0x25: /* GP/MEM Address Definition Register I */ + case 0x26: /* GP/MEM Address Definition Register II */ + case 0x27: /* GP/MEM Address Definition Register III */ + dev->regs[dev->index] = val; + break; + case 0x28: /* PCI Arbiter Control Register */ + dev->regs[dev->index] = val & 0x3f; + break; + + case 0x29: /* System Clock Register */ + dev->regs[dev->index] = val; + + port_92_remove(dev->port_92); + if (val & 0x10) + port_92_add(dev->port_92); + break; + + case 0x2a: /* I/O Recovery Register */ + dev->regs[dev->index] = val; + break; + + case 0x2b: /* Turbo Function Register */ + dev->regs[dev->index] = (val & 0xbf) | 0x40; + break; + + case 0x30: /* Power Management Unit Control Register */ + old = dev->regs[dev->index]; + dev->regs[dev->index] = val; + + if (((val & 0x14) == 0x14) && !(old & 0x08) && (val & 0x08)) { + switch (dev->regs[0x35] & 0x30) { + case 0x00: + smi_raise(); + break; + case 0x10: + nmi_raise(); + break; + case 0x20: + picint(1 << 15); + break; + case 0x30: + picint(1 << 10); + break; + } + dev->regs[0x35] |= 0x0e; + } else if (!(val & 0x10)) + dev->regs[0x35] &= ~0x0f; + break; + + case 0x31: /* Mode Timer Monitoring Events Selection Register I */ + case 0x32: /* Mode Timer Monitoring Events Selection Register II */ + case 0x33: /* SMI Triggered Events Selection Register I */ + case 0x34: /* SMI Triggered Events Selection Register II */ + dev->regs[dev->index] = val; + break; + + case 0x35: /* SMI Status Register */ + dev->regs[dev->index] = (dev->regs[dev->index] & 0x0f) | (val & 0xf0); + break; + + case 0x36: /* IRQ Channel Group Selected Control Register I */ + dev->regs[dev->index] = (val & 0xe5); + break; + case 0x37: /* IRQ Channel Group Selected Control Register II */ + dev->regs[dev->index] = (val & 0xef); + break; + + case 0x38: /* DRQ Channel Selected Control Register */ + case 0x39: /* Mode Timer Setting Register */ + case 0x3a: /* Input_device Timer Setting Register */ + case 0x3b: /* GP/MEM Timer Setting Register */ + case 0x3c: /* LED Flash Control Register */ + dev->regs[dev->index] = val; + break; + + case 0x3d: /* Miscellaneous Register I */ + dev->regs[dev->index] = (val & 0x07); + break; + + case 0x40: /* Clock Generator Control Feature Register */ + dev->regs[dev->index] = (val & 0x3f); + break; + case 0x41: /* Power Control Output Register */ + dev->regs[dev->index] = val; + break; + + case 0x42: /* PCI INTx Routing Table Mapping Register I */ + irq = irq_array[val & 0x0f]; + pci_set_irq_routing(PCI_INTA, (irq != 0) ? irq : PCI_IRQ_DISABLED); + irq = irq_array[(val & 0xf0) >> 4]; + pci_set_irq_routing(PCI_INTB, (irq != 0) ? irq : PCI_IRQ_DISABLED); + break; + + case 0x43: /* PCI INTx Routing Table Mapping Register II */ + irq = irq_array[val & 0x0f]; + pci_set_irq_routing(PCI_INTC, (irq != 0) ? irq : PCI_IRQ_DISABLED); + irq = irq_array[(val & 0xf0) >> 4]; + pci_set_irq_routing(PCI_INTD, (irq != 0) ? irq : PCI_IRQ_DISABLED); + break; + + case 0x44: /* PCI INTx Sensitivity Register */ + /* TODO: When doing the IRQ and PCI IRQ rewrite, bits 0 to 3 toggle edge/level output. */ + dev->regs[dev->index] = val; + break; + } + + if (dev->index != 0x03) { + ali1489_log("M1489: dev->regs[%02x] = %02x\n", dev->index, val); + } + } else if (dev->index == 0x03) + dev->regs[dev->index] = val; + + break; + } +} + + +static uint8_t +ali1489_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + ali1489_t *dev = (ali1489_t *)priv; + + switch (addr) { + case 0x23: + /* Avoid conflict with Cyrix CPU registers */ + if (((dev->index == 0x20) || (dev->index >= 0xc0)) && cpu_iscyrix) + ret = 0xff; + else if (dev->index == 0x3f) + ret = inb(0x70); + else + ret = dev->regs[dev->index]; + break; + } + + ali1489_log("M1489: dev->regs[%02x] (%02x)\n", dev->index, ret); + + return ret; +} + + +static void +ali1489_pci_write(int func, int addr, uint8_t val, void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + + ali1489_log("M1489-PCI: dev->pci_conf[%02x] = %02x\n", addr, val); + + switch (addr) { + /* Dummy PCI Config */ + case 0x04: + dev->pci_conf[0x04] = val & 0x7f; + break; + + /* Dummy PCI Status */ + case 0x07: + dev->pci_conf[0x07] &= ~(val & 0xb8); + break; + } +} + + +static uint8_t +ali1489_pci_read(int func, int addr, void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + ali1489_log("M1489-PCI: dev->pci_conf[%02x] (%02x)\n", addr, ret); + return ret; +} + + +static void +ali1489_ide_handler(ali1489_t *dev) +{ + ide_pri_disable(); + ide_sec_disable(); + if (dev->ide_regs[0x01] & 0x01) { + ide_pri_enable(); + if (!(dev->ide_regs[0x35] & 0x40)) + ide_sec_enable(); + } +} + + +static void +ali1489_ide_write(uint16_t addr, uint8_t val, void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + + switch (addr) + { + case 0xf4: /* Usually it writes 30h here */ + dev->ide_chip_id = val; + break; + + case 0xf8: + dev->ide_index = val; + break; + + case 0xfc: + if (dev->ide_chip_id != 0x30) + break; + + switch(dev->ide_index) { + case 0x01: /* IDE Configuration Register */ + dev->ide_regs[dev->ide_index] = val & 0x8f; + ali1489_ide_handler(dev); + break; + case 0x02: /* DBA Data Byte Cative Count for IDE-1 */ + case 0x03: /* D0RA Disk 0 Read Active Count for IDE-1 */ + case 0x04: /* D0WA Disk 0 Write Active Count for IDE-1 */ + case 0x05: /* D1RA Disk 1 Read Active Count for IDE-1 */ + case 0x06: /* D1WA Disk 1 Write Active Count for IDE-1 */ + case 0x25: /* DBR Data Byte Recovery Count for IDE-1 */ + case 0x26: /* D0RR Disk 0 Read Byte Recovery Count for IDE-1 */ + case 0x27: /* D0WR Disk 0 Write Byte Recovery Count for IDE-1 */ + case 0x28: /* D1RR Disk 1 Read Byte Recovery Count for IDE-1 */ + case 0x29: /* D1WR Disk 1 Write Byte Recovery Count for IDE-1 */ + case 0x2a: /* DBA Data Byte Cative Count for IDE-2 */ + case 0x2b: /* D0RA Disk 0 Read Active Count for IDE-2 */ + case 0x2c: /* D0WA Disk 0 Write Active Count for IDE-2 */ + case 0x2d: /* D1RA Disk 1 Read Active Count for IDE-2 */ + case 0x2e: /* D1WA Disk 1 Write Active Count for IDE-2 */ + case 0x2f: /* DBR Data Byte Recovery Count for IDE-2 */ + case 0x30: /* D0RR Disk 0 Read Byte Recovery Count for IDE-2 */ + case 0x31: /* D0WR Disk 0 Write Byte Recovery Count for IDE-2 */ + case 0x32: /* D1RR Disk 1 Read Byte Recovery Count for IDE-2 */ + case 0x33: /* D1WR Disk 1 Write Byte Recovery Count for IDE-2 */ + dev->ide_regs[dev->ide_index] = val & 0x1f; + break; + case 0x07: /* Buffer Mode Register 1 */ + dev->ide_regs[dev->ide_index] = val; + break; + case 0x09: /* IDEPE1 IDE Port Enable Register 1 */ + dev->ide_regs[dev->ide_index] = val & 0xc3; + break; + case 0x0a: /* Buffer Mode Register 2 */ + dev->ide_regs[dev->ide_index] = val & 0x4f; + break; + case 0x0b: /* IDE Channel 1 Disk 0 Sector Byte Count Register 1 */ + case 0x0d: /* IDE Channel 1 Disk 1 Sector Byte Count Register 1 */ + case 0x0f: /* IDE Channel 2 Disk 0 Sector Byte Count Register 1 */ + case 0x11: /* IDE Channel 2 Disk 1 Sector Byte Count Register 1 */ + dev->ide_regs[dev->ide_index] = val & 0x03; + break; + case 0x0c: /* IDE Channel 1 Disk 0 Sector Byte Count Register 2 */ + case 0x0e: /* IDE Channel 1 Disk 1 Sector Byte Count Register 2 */ + case 0x10: /* IDE Channel 2 Disk 1 Sector Byte Count Register 2 */ + case 0x12: /* IDE Channel 2 Disk 1 Sector Byte Count Register 2 */ + dev->ide_regs[dev->ide_index] = val & 0x1f; + break; + case 0x35: /* IDEPE3 IDE Port Enable Register 3 */ + dev->ide_regs[dev->ide_index] = val; + ali1489_ide_handler(dev); + break; + } + break; + } +} + + +static uint8_t +ali1489_ide_read(uint16_t addr, void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + uint8_t ret = 0xff; + + switch (addr) + { + case 0xf4: + ret = dev->ide_chip_id; + break; + case 0xfc: + ret = dev->ide_regs[dev->ide_index]; + ali1489_log("M1489-IDE: dev->regs[%02x] (%02x)\n", dev->ide_index, ret); + break; + } + + return ret; +} + + +static void +ali1489_reset(void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + ali1489_defaults(dev); +} + + +static void +ali1489_close(void *priv) +{ + ali1489_t *dev = (ali1489_t *)priv; + + smram_del(dev->smram); + free(dev); +} + + +static void * +ali1489_init(const device_t *info) +{ + ali1489_t *dev = (ali1489_t *)malloc(sizeof(ali1489_t)); + memset(dev, 0, sizeof(ali1489_t)); + + /* M1487/M1489 + 22h Index Port + 23h Data Port */ + io_sethandler(0x0022, 0x0002, ali1489_read, NULL, NULL, ali1489_write, NULL, NULL, dev); + + /* M1489 IDE controller + F4h Chip ID we write always 30h onto it + F8h Index Port + FCh Data Port + */ + io_sethandler(0x0f4, 0x0001, ali1489_ide_read, NULL, NULL, ali1489_ide_write, NULL, NULL, dev); + io_sethandler(0x0f8, 0x0001, ali1489_ide_read, NULL, NULL, ali1489_ide_write, NULL, NULL, dev); + io_sethandler(0x0fc, 0x0001, ali1489_ide_read, NULL, NULL, ali1489_ide_write, NULL, NULL, dev); + + /* Dummy M1489 PCI device */ + dev->pci_slot = pci_add_card(PCI_ADD_NORTHBRIDGE, ali1489_pci_read, ali1489_pci_write, dev); + + device_add(&ide_pci_2ch_device); + + dev->port_92 = device_add(&port_92_pci_device); + dev->smram = smram_add(); + + ali1489_defaults(dev); + + return dev; +} + +const device_t ali1489_device = { + .name = "ALi M1489", + .internal_name = "ali1489", + .flags = 0, + .local = 0, + .init = ali1489_init, + .close = ali1489_close, + .reset = ali1489_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c new file mode 100644 index 000000000..350ec146f --- /dev/null +++ b/src/chipset/ali1531.c @@ -0,0 +1,391 @@ +/* + * 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 ALi M1531B CPU-to-PCI Bridge. + * + * + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + * + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> + +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> + +#include <86box/chipset.h> + + +typedef struct ali1531_t +{ + uint8_t pci_conf[256]; + + smram_t *smram; +} ali1531_t; + + +#ifdef ENABLE_ALI1531_LOG +int ali1531_do_log = ENABLE_ALI1531_LOG; +static void +ali1531_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1531_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1531_log(fmt, ...) +#endif + + +static void +ali1531_smram_recalc(uint8_t val, ali1531_t *dev) +{ + smram_disable_all(); + + if (val & 1) { + switch (val & 0x0c) { + case 0x00: + ali1531_log("SMRAM: D0000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xd0000, 0x10000, 0x02); + break; + case 0x04: + ali1531_log("SMRAM: A0000 -> A0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); + break; + case 0x08: + ali1531_log("SMRAM: 30000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0x30000, 0x10000, 0x02); + break; + } + } + + flushmmucache_nopc(); +} + + +static void +ali1531_shadow_recalc(int cur_reg, ali1531_t *dev) +{ + int i, bit, r_reg, w_reg; + uint32_t base, flags = 0; + + shadowbios = shadowbios_write = 0; + + for (i = 0; i < 16; i++) { + base = 0x000c0000 + (i << 14); + bit = i & 7; + r_reg = 0x4c + (i >> 3); + w_reg = 0x4e + (i >> 3); + + flags = (dev->pci_conf[r_reg] & (1 << bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[w_reg] & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (base >= 0x000e0000) { + if (dev->pci_conf[r_reg] & (1 << bit)) + shadowbios |= 1; + if (dev->pci_conf[w_reg] & (1 << bit)) + shadowbios_write |= 1; + } + + ali1531_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, + (dev->pci_conf[r_reg] & (1 << bit)) ? 'I' : 'E', (dev->pci_conf[w_reg] & (1 << bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00004000, flags); + } + + flushmmucache_nopc(); +} + + +static void +ali1531_write(int func, int addr, uint8_t val, void *priv) +{ + ali1531_t *dev = (ali1531_t *)priv; + + switch (addr) { + case 0x04: + dev->pci_conf[addr] = val; + break; + case 0x05: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf8); + break; + + case 0x0d: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (dev->pci_conf[0x70] & 0x08) + dev->pci_conf[addr] = val; + break; + + case 0x40: + dev->pci_conf[addr] = val & 0xf1; + break; + + case 0x41: + dev->pci_conf[addr] = (val & 0xd6) | 0x08; + break; + + case 0x42: /* L2 Cache */ + dev->pci_conf[addr] = val & 0xf7; + cpu_cache_ext_enabled = !!(val & 1); + cpu_update_waitstates(); + break; + + case 0x43: /* L1 Cache */ + dev->pci_conf[addr] = val; + cpu_cache_int_enabled = !!(val & 1); + cpu_update_waitstates(); + break; + + case 0x44: + dev->pci_conf[addr] = val; + break; + case 0x45: + dev->pci_conf[addr] = val; + break; + + case 0x46: + dev->pci_conf[addr] = val; + break; + + case 0x47: + dev->pci_conf[addr] = val & 0xfc; + + if (mem_size > 0xe00000) + mem_set_mem_state_both(0xe00000, 0x100000, (val & 0x20) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + if (mem_size > 0xf00000) + mem_set_mem_state_both(0xf00000, 0x100000, (val & 0x10) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + flushmmucache_nopc(); + break; + + case 0x48: /* SMRAM */ + dev->pci_conf[addr] = val; + ali1531_smram_recalc(val, dev); + break; + + case 0x49: + dev->pci_conf[addr] = val & 0x73; + break; + + case 0x4a: + dev->pci_conf[addr] = val; + break; + + case 0x4c ... 0x4f: /* Shadow RAM */ + dev->pci_conf[addr] = val; + ali1531_shadow_recalc(val, dev); + break; + + case 0x50: case 0x51: case 0x52: case 0x54: + case 0x55: case 0x56: + dev->pci_conf[addr] = val; + break; + + case 0x57: /* H2PO */ + dev->pci_conf[addr] = val & 0x60; + /* Find where the Shut-down Special cycle is initiated. */ + // if (!(val & 0x20)) + // outb(0x92, 0x01); + break; + + case 0x58: + dev->pci_conf[addr] = val & 0x86; + break; + + case 0x59: case 0x5a: + case 0x5c: + dev->pci_conf[addr] = val; + break; + + case 0x5b: + dev->pci_conf[addr] = val & 0x4f; + break; + + case 0x5d: + dev->pci_conf[addr] = val & 0x53; + break; + + case 0x5f: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x60 ... 0x6f: /* DRB's */ + dev->pci_conf[addr] = val; + spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); + break; + + case 0x70: case 0x71: + dev->pci_conf[addr] = val; + break; + + case 0x72: + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x74: + dev->pci_conf[addr] = val & 0x2b; + break; + + case 0x76: case 0x77: + dev->pci_conf[addr] = val; + break; + + case 0x80: + dev->pci_conf[addr] = val & 0x84; + break; + + case 0x81: + dev->pci_conf[addr] = val & 0x81; + break; + + case 0x83: + dev->pci_conf[addr] = val & 0x10; + break; + } +} + + +static uint8_t +ali1531_read(int func, int addr, void *priv) +{ + ali1531_t *dev = (ali1531_t *)priv; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ali1531_reset(void *priv) +{ + ali1531_t *dev = (ali1531_t *)priv; + int i; + + /* Default Registers */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x31; + dev->pci_conf[0x03] = 0x15; + dev->pci_conf[0x04] = 0x06; + dev->pci_conf[0x05] = 0x00; + dev->pci_conf[0x06] = 0x00; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x08] = 0xb0; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x0c] = 0x00; + dev->pci_conf[0x0d] = 0x20; + dev->pci_conf[0x0e] = 0x00; + dev->pci_conf[0x0f] = 0x00; + dev->pci_conf[0x2c] = 0xb9; + dev->pci_conf[0x2d] = 0x10; + dev->pci_conf[0x2e] = 0x31; + dev->pci_conf[0x2f] = 0x15; + dev->pci_conf[0x52] = 0xf0; + dev->pci_conf[0x54] = 0xff; + dev->pci_conf[0x55] = 0xff; + dev->pci_conf[0x59] = 0x20; + dev->pci_conf[0x5a] = 0x20; + dev->pci_conf[0x70] = 0x22; + + ali1531_write(0, 0x42, 0x00, dev); + ali1531_write(0, 0x43, 0x00, dev); + + ali1531_write(0, 0x47, 0x00, dev); + ali1531_write(0, 0x48, 0x00, dev); + + for (i = 0; i < 4; i++) + ali1531_write(0, 0x4c + i, 0x00, dev); + + for (i = 0; i < 16; i += 2) { + ali1531_write(0, 0x60 + i, 0x08, dev); + ali1531_write(0, 0x61 + i, 0x40, dev); + } +} + + +static void +ali1531_close(void *priv) +{ + ali1531_t *dev = (ali1531_t *)priv; + + smram_del(dev->smram); + free(dev); +} + + +static void * +ali1531_init(const device_t *info) +{ + ali1531_t *dev = (ali1531_t *)malloc(sizeof(ali1531_t)); + memset(dev, 0, sizeof(ali1531_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, ali1531_read, ali1531_write, dev); + + dev->smram = smram_add(); + + ali1531_reset(dev); + + return dev; +} + +const device_t ali1531_device = { + .name = "ALi M1531 CPU-to-PCI Bridge", + .internal_name = "ali1531", + .flags = DEVICE_PCI, + .local = 0, + .init = ali1531_init, + .close = ali1531_close, + .reset = ali1531_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/ali1541.c b/src/chipset/ali1541.c new file mode 100644 index 000000000..097726106 --- /dev/null +++ b/src/chipset/ali1541.c @@ -0,0 +1,656 @@ +/* + * 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 ALi M1541/2 CPU-to-PCI Bridge. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> + +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> + +#include <86box/chipset.h> + + +typedef struct ali1541_t +{ + uint8_t pci_conf[256]; + + smram_t * smram; + void * agp_bridge; +} ali1541_t; + + +#ifdef ENABLE_ALI1541_LOG +int ali1541_do_log = ENABLE_ALI1541_LOG; +static void +ali1541_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1541_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1541_log(fmt, ...) +#endif + + +static void +ali1541_smram_recalc(uint8_t val, ali1541_t *dev) +{ + smram_disable_all(); + + if (val & 1) { + switch (val & 0x0c) { + case 0x00: + ali1541_log("SMRAM: D0000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xd0000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xd0000, 0x10000, 0x02); + break; + case 0x04: + ali1541_log("SMRAM: A0000 -> A0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x20000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0xa0000, 0x20000, 0x02); + break; + case 0x08: + ali1541_log("SMRAM: 30000 -> B0000 (%i)\n", val & 2); + smram_enable(dev->smram, 0x30000, 0xb0000, 0x10000, val & 2, 1); + if (val & 0x10) + mem_set_mem_state_smram_ex(1, 0x30000, 0x10000, 0x02); + break; + } + } + + flushmmucache_nopc(); +} + + +static void +ali1541_shadow_recalc(int cur_reg, ali1541_t *dev) +{ + int i, bit, r_reg, w_reg; + uint32_t base, flags = 0; + + shadowbios = shadowbios_write = 0; + + for (i = 0; i < 16; i++) { + base = 0x000c0000 + (i << 14); + bit = i & 7; + r_reg = 0x56 + (i >> 3); + w_reg = 0x58 + (i >> 3); + + flags = (dev->pci_conf[r_reg] & (1 << bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[w_reg] & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (base >= 0x000e0000) { + if (dev->pci_conf[r_reg] & (1 << bit)) + shadowbios |= 1; + if (dev->pci_conf[w_reg] & (1 << bit)) + shadowbios_write |= 1; + } + + ali1541_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, + (dev->pci_conf[r_reg] & (1 << bit)) ? 'I' : 'E', (dev->pci_conf[w_reg] & (1 << bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00004000, flags); + } + + flushmmucache_nopc(); +} + + +static void +ali1541_mask_bar(ali1541_t *dev) +{ + uint32_t bar, mask; + + switch (dev->pci_conf[0xbc] & 0x0f) { + case 0x00: + default: + mask = 0x00000000; + break; + case 0x01: + mask = 0xfff00000; + break; + case 0x02: + mask = 0xffe00000; + break; + case 0x03: + mask = 0xffc00000; + break; + case 0x04: + mask = 0xff800000; + break; + case 0x06: + mask = 0xff000000; + break; + case 0x07: + mask = 0xfe000000; + break; + case 0x08: + mask = 0xfc000000; + break; + case 0x09: + mask = 0xf8000000; + break; + case 0x0a: + mask = 0xf0000000; + break; + } + + bar = ((dev->pci_conf[0x13] << 24) | (dev->pci_conf[0x12] << 16)) & mask; + dev->pci_conf[0x12] = (bar >> 16) & 0xff; + dev->pci_conf[0x13] = (bar >> 24) & 0xff; +} + + +static void +ali1541_write(int func, int addr, uint8_t val, void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + + switch (addr) { + case 0x04: + dev->pci_conf[addr] = val; + break; + case 0x05: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf8); + break; + + case 0x0d: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x12: + dev->pci_conf[0x12] = (val & 0xc0); + ali1541_mask_bar(dev); + break; + case 0x13: + dev->pci_conf[0x13] = val; + ali1541_mask_bar(dev); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val; + break; + + case 0x34: + if (dev->pci_conf[0x90] & 0x02) + dev->pci_conf[addr] = val; + break; + + case 0x40: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x41: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x42: /* L2 Cache */ + dev->pci_conf[addr] = val; + cpu_cache_ext_enabled = !!(val & 1); + cpu_update_waitstates(); + break; + + case 0x43: /* PLCTL-Pipe Line Control */ + dev->pci_conf[addr] = val & 0xf7; + break; + + case 0x44: + dev->pci_conf[addr] = val; + break; + case 0x45: + dev->pci_conf[addr] = val; + break; + case 0x46: + dev->pci_conf[addr] = val & 0xf0; + break; + case 0x47: + dev->pci_conf[addr] = val; + break; + + case 0x48: + dev->pci_conf[addr] = val; + break; + case 0x49: + dev->pci_conf[addr] = val; + break; + + case 0x4a: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x4b: + dev->pci_conf[addr] = val; + break; + + case 0x4c: + dev->pci_conf[addr] = val; + break; + case 0x4d: + dev->pci_conf[addr] = val; + break; + + case 0x4e: + dev->pci_conf[addr] = val; + break; + case 0x4f: + dev->pci_conf[addr] = val; + break; + + case 0x50: + dev->pci_conf[addr] = val & 0x71; + break; + + case 0x51: + dev->pci_conf[addr] = val; + break; + + case 0x52: + dev->pci_conf[addr] = val; + break; + + case 0x53: + dev->pci_conf[addr] = val; + break; + + case 0x54: + dev->pci_conf[addr] = val & 0x3c; + + if (mem_size > 0xe00000) + mem_set_mem_state_both(0xe00000, 0x100000, (val & 0x20) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + if (mem_size > 0xf00000) + mem_set_mem_state_both(0xf00000, 0x100000, (val & 0x10) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + mem_set_mem_state_both(0xa0000, 0x20000, (val & 8) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0x80000, 0x20000, (val & 4) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); + + flushmmucache_nopc(); + break; + + case 0x55: /* SMRAM */ + dev->pci_conf[addr] = val & 0x1f; + ali1541_smram_recalc(val, dev); + break; + + case 0x56 ... 0x59: /* Shadow RAM */ + dev->pci_conf[addr] = val; + ali1541_shadow_recalc(val, dev); + break; + + case 0x5a: case 0x5b: + dev->pci_conf[addr] = val; + break; + + case 0x5c: + dev->pci_conf[addr] = val; + break; + + case 0x5d: + dev->pci_conf[addr] = val & 0x17; + break; + + case 0x5e: + dev->pci_conf[addr] = val; + break; + + case 0x5f: + dev->pci_conf[addr] = val & 0xc1; + break; + + case 0x60 ... 0x6f: /* DRB's */ + dev->pci_conf[addr] = val; + spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); + break; + + case 0x70: + dev->pci_conf[addr] = val; + break; + + case 0x71: + dev->pci_conf[addr] = val; + break; + + case 0x72: + dev->pci_conf[addr] = val & 0xc7; + break; + + case 0x73: + dev->pci_conf[addr] = val & 0x1f; + break; + + case 0x84: case 0x85: + dev->pci_conf[addr] = val; + break; + + case 0x86: + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x87: /* H2PO */ + dev->pci_conf[addr] = val; + /* Find where the Shut-down Special cycle is initiated. */ + // if (!(val & 0x20)) + // outb(0x92, 0x01); + break; + + case 0x88: + dev->pci_conf[addr] = val; + break; + + case 0x89: + dev->pci_conf[addr] = val; + break; + + case 0x8a: + dev->pci_conf[addr] = val; + break; + + case 0x8b: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x8c: + dev->pci_conf[addr] = val; + break; + + case 0x8d: + dev->pci_conf[addr] = val; + break; + + case 0x8e: + dev->pci_conf[addr] = val; + break; + + case 0x8f: + dev->pci_conf[addr] = val; + break; + + case 0x90: + dev->pci_conf[addr] = val; + pci_bridge_set_ctl(dev->agp_bridge, val); + break; + + case 0x91: + dev->pci_conf[addr] = val; + break; + + case 0xb4: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val & 0x03; + break; + case 0xb5: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val & 0x02; + break; + case 0xb7: + if (dev->pci_conf[0x90] & 0x01) + dev->pci_conf[addr] = val; + break; + + case 0xb8: + dev->pci_conf[addr] = val & 0x03; + break; + case 0xb9: + dev->pci_conf[addr] = val & 0x03; + break; + case 0xbb: + dev->pci_conf[addr] = val; + break; + + case 0xbc: + dev->pci_conf[addr] = val & 0x0f; + ali1541_mask_bar(dev); + break; + case 0xbd: + dev->pci_conf[addr] = val & 0xf0; + break; + case 0xbe: case 0xbf: + dev->pci_conf[addr] = val; + break; + + case 0xc0: + dev->pci_conf[addr] = val & 0x90; + break; + case 0xc1: case 0xc2: + case 0xc3: + dev->pci_conf[addr] = val; + break; + + case 0xc8: case 0xc9: + dev->pci_conf[addr] = val; + break; + + case 0xd1: + dev->pci_conf[addr] = val & 0xf1; + break; + case 0xd2: case 0xd3: + dev->pci_conf[addr] = val; + break; + + case 0xe0: case 0xe1: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + case 0xe2: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0x3f; + break; + case 0xe3: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0xe4: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0x03; + break; + case 0xe5: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + + case 0xe6: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val & 0xc0; + break; + + case 0xe7: + if (dev->pci_conf[0x90] & 0x20) + dev->pci_conf[addr] = val; + break; + + case 0xe8: case 0xe9: + if (dev->pci_conf[0x90] & 0x04) + dev->pci_conf[addr] = val; + break; + + case 0xea: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0xeb: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0xec: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0xed: + dev->pci_conf[addr] = val; + break; + + case 0xee: + dev->pci_conf[addr] = val & 0x3e; + break; + case 0xef: + dev->pci_conf[addr] = val; + break; + + case 0xf3: + dev->pci_conf[addr] = val & 0x08; + break; + + case 0xf5: + dev->pci_conf[addr] = val; + break; + + case 0xf6: + dev->pci_conf[addr] = val; + break; + + case 0xf7: + dev->pci_conf[addr] = val & 0x43; + break; + } +} + + +static uint8_t +ali1541_read(int func, int addr, void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ali1541_reset(void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + int i; + + /* Default Registers */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x41; + dev->pci_conf[0x03] = 0x15; + dev->pci_conf[0x04] = 0x06; + dev->pci_conf[0x05] = 0x00; + dev->pci_conf[0x06] = 0x10; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x08] = 0x00; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x0c] = 0x00; + dev->pci_conf[0x0d] = 0x20; + dev->pci_conf[0x0e] = 0x00; + dev->pci_conf[0x0f] = 0x00; + dev->pci_conf[0x2c] = 0xb9; + dev->pci_conf[0x2d] = 0x10; + dev->pci_conf[0x2e] = 0x41; + dev->pci_conf[0x2f] = 0x15; + dev->pci_conf[0x34] = 0xb0; + dev->pci_conf[0x89] = 0x20; + dev->pci_conf[0x8a] = 0x20; + dev->pci_conf[0x91] = 0x13; + dev->pci_conf[0xb0] = 0x02; + dev->pci_conf[0xb1] = 0xe0; + dev->pci_conf[0xb2] = 0x10; + dev->pci_conf[0xb4] = 0x03; + dev->pci_conf[0xb5] = 0x02; + dev->pci_conf[0xb7] = 0x1c; + dev->pci_conf[0xc8] = 0xbf; + dev->pci_conf[0xc9] = 0x0a; + dev->pci_conf[0xe0] = 0x01; + + cpu_cache_int_enabled = 1; + ali1541_write(0, 0x42, 0x00, dev); + + ali1541_write(0, 0x54, 0x00, dev); + ali1541_write(0, 0x55, 0x00, dev); + + for (i = 0; i < 4; i++) + ali1541_write(0, 0x56 + i, 0x00, dev); + + ali1541_write(0, 0x60 + i, 0x07, dev); + ali1541_write(0, 0x61 + i, 0x40, dev); + for (i = 0; i < 14; i += 2) { + ali1541_write(0, 0x62 + i, 0x00, dev); + ali1541_write(0, 0x63 + i, 0x00, dev); + } +} + + +static void +ali1541_close(void *priv) +{ + ali1541_t *dev = (ali1541_t *)priv; + + smram_del(dev->smram); + free(dev); +} + + +static void * +ali1541_init(const device_t *info) +{ + ali1541_t *dev = (ali1541_t *)malloc(sizeof(ali1541_t)); + memset(dev, 0, sizeof(ali1541_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, ali1541_read, ali1541_write, dev); + + dev->smram = smram_add(); + + ali1541_reset(dev); + + dev->agp_bridge = device_add(&ali5243_agp_device); + + return dev; +} + +const device_t ali1541_device = { + .name = "ALi M1541 CPU-to-PCI Bridge", + .internal_name = "ali1541", + .flags = DEVICE_PCI, + .local = 0, + .init = ali1541_init, + .close = ali1541_close, + .reset = ali1541_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c new file mode 100644 index 000000000..bbbf7d705 --- /dev/null +++ b/src/chipset/ali1543.c @@ -0,0 +1,1600 @@ +/* + * 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 ALi M1543 Desktop South Bridge. + * + * + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + * + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/io.h> + +#include <86box/apm.h> +#include <86box/dma.h> +#include <86box/ddma.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/port_92.h> +#include <86box/sio.h> +#include <86box/smbus.h> +#include <86box/usb.h> + +#include <86box/acpi.h> + +#include <86box/chipset.h> + + +typedef struct ali1543_t +{ + uint8_t pci_conf[256], pmu_conf[256], usb_conf[256], ide_conf[256], + pci_slot, ide_slot, usb_slot, pmu_slot, usb_dev_enable, ide_dev_enable, + pmu_dev_enable, type; + int offset; + + apm_t * apm; + acpi_t * acpi; + ddma_t * ddma; + nvr_t * nvr; + port_92_t * port_92; + sff8038i_t * ide_controller[2]; + smbus_ali7101_t * smbus; + usb_t * usb; + +} ali1543_t; + +/* + Notes: + - Power Managment isn't functioning properly + - IDE isn't functioning properly + - 1543C differences have to be examined + - Some Chipset functionality might be missing + - Device numbers and types might be incorrect + - Code quality is abysmal and needs lot's of cleanup. +*/ + +int ali1533_irq_routing[16] = { PCI_IRQ_DISABLED, 9, 3, 10, 4, 5, 7, 6, + 1, 11, PCI_IRQ_DISABLED, 12, PCI_IRQ_DISABLED, 14, PCI_IRQ_DISABLED, 15 }; + + +#ifdef ENABLE_ALI1543_LOG +int ali1543_do_log = ENABLE_ALI1543_LOG; +static void +ali1543_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1543_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1543_log(fmt, ...) +#endif + + +static void +ali1533_ddma_handler(ali1543_t *dev) +{ + /* TODO: Find any documentation that actually explains the ALi southbridge DDMA mapping. */ +} + + +static void ali5229_ide_handler(ali1543_t *dev); +static void ali5229_ide_irq_handler(ali1543_t *dev); + +static void ali5229_write(int func, int addr, uint8_t val, void *priv); + +static void ali7101_write(int func, int addr, uint8_t val, void *priv); +static uint8_t ali7101_read(int func, int addr, void *priv); + + +static void +ali1533_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + int irq; + ali1543_log("M1533: dev->pci_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + switch (addr) { + case 0x04: /* Command Register */ + if (dev->type == 1) { + if (dev->pci_conf[0x5f] & 0x08) + dev->pci_conf[0x04] = val & 0x0f; + else + dev->pci_conf[0x04] = val; + } else { + if (!(dev->pci_conf[0x5f] & 0x08)) + dev->pci_conf[0x04] = val; + } + break; + case 0x05: /* Command Register */ + if (!(dev->pci_conf[0x5f] & 0x08)) + dev->pci_conf[0x04] = val & 0x03; + break; + + case 0x07: /* Status Byte */ + dev->pci_conf[addr] &= ~(val & 0x30); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->pci_conf[0x74] & 0x40)) + dev->pci_conf[addr] = val; + break; + + case 0x40: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x41: + /* TODO: Bit 7 selects keyboard controller type: + 0 = AT, 1 = PS/2 */ + keyboard_at_set_mouse_scan((val & 0x40) ? 1 : 0); + dev->pci_conf[addr] = val & 0xbf; + break; + + case 0x42: /* ISA Bus Speed */ + dev->pci_conf[addr] = val & 0xcf; + switch (val & 7) { + case 0: + cpu_set_isa_speed(7159091); + break; + case 1: case 2: case 3: case 4: + case 5: case 6: + cpu_set_isa_pci_div((val & 7) + 1); + break; + } + break; + + case 0x43: + dev->pci_conf[addr] = val; + if (val & 0x80) + port_92_add(dev->port_92); + else + port_92_remove(dev->port_92); + break; + + /* We're going to cheat a little bit here and use MIRQ's as a substitute for the ALi's INTAJ's, + as they work pretty much the same - specifically, we're going to use MIRQ2 and MIRQ3 for them, + as MIRQ0 and MIRQ1 map to the ALi's MBIRQ0 and MBIRQ1. */ + case 0x44: /* Set IRQ Line for Primary IDE if it's on native mode */ + dev->pci_conf[addr] = val & 0xdf; + soft_reset_pci = !!(val & 0x80); + sff_set_irq_level(dev->ide_controller[0], 0, !(val & 0x10)); + sff_set_irq_level(dev->ide_controller[1], 0, !(val & 0x10)); + ali1543_log("INTAJ = IRQ %i\n", ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ2, ali1533_irq_routing[val & 0x0f]); + break; + + /* TODO: Implement a ROMCS# assertion bitmask for I/O ports. */ + case 0x45: /* DDMA Enable */ + dev->pci_conf[addr] = val & 0xcb; + ali1533_ddma_handler(dev); + break; + + /* TODO: For 0x47, we need a way to obtain the memory state for an address + and toggle ROMCS#. */ + case 0x47: /* BIOS chip select control */ + dev->pci_conf[addr] = val; + break; + + /* PCI IRQ Routing */ + case 0x48: case 0x49: case 0x4a: case 0x4b: + dev->pci_conf[addr] = val; + + pci_set_irq_routing(((addr & 0x03) << 1) + 2, ali1533_irq_routing[(val >> 4) & 0x0f]); + pci_set_irq_routing(((addr & 0x03) << 1) + 1, ali1533_irq_routing[val & 0x0f]); + break; + + case 0x4c: /* PCI INT to ISA Level to Edge transfer */ + dev->pci_conf[addr] = val; + + for (irq = 1; irq < 9; irq++) + pci_set_irq_level(irq, !(val & (1 << (irq - 1)))); + break; + + case 0x4d: /* MBIRQ0(SIRQI#), MBIRQ1(SIRQII#) Interrupt to ISA IRQ routing table */ + if (dev->type == 0) { + dev->pci_conf[addr] = val; + + ali1543_log("SIRQI = IRQ %i; SIRQII = IRQ %i\n", ali1533_irq_routing[(val >> 4) & 0x0f], ali1533_irq_routing[val & 0x0f]); + // pci_set_mirq_routing(PCI_MIRQ0, ali1533_irq_routing[(val >> 4) & 0x0f]); + // pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]); + } + break; + + /* I/O cycle posted-write first port definition */ + case 0x50: + dev->pci_conf[addr] = val; + break; + case 0x51: + dev->pci_conf[addr] = val & 0x8f; + break; + + /* I/O cycle posted-write second port definition */ + case 0x52: + dev->pci_conf[addr] = val; + break; + case 0x53: + if (dev->type == 1) + dev->pci_conf[addr] = val; + else + dev->pci_conf[addr] = val & 0xcf; + /* This actually enables/disables the USB *device* rather than the interface itself. */ + dev->usb_dev_enable = !(val & 0x40); + break; + + /* Hardware setting status bits, read-only (register 0x54) */ + + /* Programmable chip select (pin PCSJ) address define */ + case 0x55: case 0x56: + dev->pci_conf[addr] = val; + break; + case 0x57: + if (dev->type == 1) + dev->pci_conf[addr] = val & 0xf0; + else + dev->pci_conf[addr] = val & 0xe0; + break; + + /* IDE interface control */ + case 0x58: + dev->pci_conf[addr] = val & 0x7f; + ali1543_log("PCI58: %02X\n", val); + dev->ide_dev_enable = !!(val & 0x40); + switch (val & 0x30) { + case 0x00: + dev->ide_slot = 0x10; /* A27 = slot 16 */ + break; + case 0x10: + dev->ide_slot = 0x0f; /* A26 = slot 15 */ + break; + case 0x20: + dev->ide_slot = 0x0e; /* A25 = slot 14 */ + break; + case 0x30: + dev->ide_slot = 0x0d; /* A24 = slot 13 */ + break; + } + pci_relocate_slot(PCI_CARD_SOUTHBRIDGE_IDE, ((int) dev->ide_slot) + dev->offset); + ali1543_log("IDE slot = %02X (A%0i)\n", ((int) dev->ide_slot) + dev->offset, dev->ide_slot + 11); + ali5229_ide_irq_handler(dev); + break; + + /* General Purpose input multiplexed pin(GPI) select */ + case 0x59: + dev->pci_conf[addr] = val & 0x0e; + break; + + /* General Purpose output multiplexed pin(GPO) select low */ + case 0x5a: + dev->pci_conf[addr] = val & 0x0f; + break; + /* General Purpose output multiplexed pin(GPO) select high */ + case 0x5b: + dev->pci_conf[addr] = val & 0x02; + break; + + case 0x5c: + dev->pci_conf[addr] = val & 0x7f; + break; + case 0x5d: + dev->pci_conf[addr] = val & 0x02; + break; + + case 0x5e: + if (dev->type == 1) + dev->pci_conf[addr] = val & 0xe1; + else + dev->pci_conf[addr] = val & 0xe0; + break; + + case 0x5f: + dev->pci_conf[addr] = val; + dev->pmu_dev_enable = !(val & 0x04); + break; + + case 0x6c: /* Deleted - no idea what it used to do */ + dev->pci_conf[addr] = val; + break; + + case 0x6d: + dev->pci_conf[addr] = val & 0xbf; + break; + + case 0x6e: case 0x70: + dev->pci_conf[addr] = val; + break; + + case 0x71: + dev->pci_conf[addr] = val & 0xef; + break; + + case 0x72: + dev->pci_conf[addr] = val & 0xef; + switch (val & 0x0c) { + case 0x00: + dev->pmu_slot = 0x11; /* A28 = slot 17 */ + break; + case 0x04: + dev->pmu_slot = 0x12; /* A29 = slot 18 */ + break; + case 0x08: + dev->pmu_slot = 0x03; /* A14 = slot 03 */ + break; + case 0x0c: + dev->pmu_slot = 0x04; /* A15 = slot 04 */ + break; + } + pci_relocate_slot(PCI_CARD_SOUTHBRIDGE_PMU, ((int) dev->pmu_slot) + dev->offset); + ali1543_log("PMU slot = %02X (A%0i)\n", ((int) dev->pmu_slot) + dev->offset, dev->pmu_slot + 11); + switch (val & 0x03) { + case 0x00: + dev->usb_slot = 0x14; /* A31 = slot 20 */ + break; + case 0x01: + dev->usb_slot = 0x13; /* A30 = slot 19 */ + break; + case 0x02: + dev->usb_slot = 0x02; /* A13 = slot 02 */ + break; + case 0x03: + dev->usb_slot = 0x01; /* A12 = slot 01 */ + break; + } + pci_relocate_slot(PCI_CARD_SOUTHBRIDGE_USB, ((int) dev->usb_slot) + dev->offset); + ali1543_log("USB slot = %02X (A%0i)\n", ((int) dev->usb_slot) + dev->offset, dev->usb_slot + 11); + break; + + case 0x73: /* DDMA Base Address */ + dev->pci_conf[addr] = val; + ali1533_ddma_handler(dev); + break; + + case 0x74: /* USB IRQ Routing - we cheat and use MIRQ4 */ + dev->pci_conf[addr] = val & 0xdf; + /* TODO: MIRQ level/edge control - if bit 4 = 1, it's level */ + pci_set_mirq_routing(PCI_MIRQ4, ali1533_irq_routing[val & 0x0f]); + break; + + case 0x75: /* Set IRQ Line for Secondary IDE if it's on native mode */ + dev->pci_conf[addr] = val & 0x1f; + sff_set_irq_level(dev->ide_controller[0], 1, !(val & 0x10)); + sff_set_irq_level(dev->ide_controller[1], 1, !(val & 0x10)); + ali1543_log("INTBJ = IRQ %i\n", ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ1, ali1533_irq_routing[val & 0x0f]); + pci_set_mirq_routing(PCI_MIRQ3, ali1533_irq_routing[val & 0x0f]); + break; + + case 0x76: /* PMU IRQ Routing - we cheat and use MIRQ5 */ + if (dev->type == 1) + dev->pci_conf[addr] = val & 0x9f; + else + dev->pci_conf[addr] = val & 0x1f; + acpi_set_mirq_is_level(dev->acpi, !!(val & 0x10)); + if ((dev->type == 1) && (val & 0x80)) + pci_set_mirq_routing(PCI_MIRQ5, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ5, ali1533_irq_routing[val & 0x0f]); + /* TODO: Tell ACPI to use MIRQ5 */ + break; + + case 0x77: /* SMBus IRQ Routing - we cheat and use MIRQ6 */ + dev->pci_conf[addr] = val & 0x1f; + pci_set_mirq_routing(PCI_MIRQ6, ali1533_irq_routing[val & 0x0f]); + break; + + case 0x78: + if (dev->type == 1) { + ali1543_log("PCI78 = %02X\n", val); + dev->pci_conf[addr] = val & 0x33; + } + break; + + case 0x7c ... 0xff: + if ((dev->type == 1) && !dev->pmu_dev_enable) { + dev->pmu_dev_enable = 1; + ali7101_write(func, addr, val, priv); + dev->pmu_dev_enable = 0; + } + break; + } +} + +static uint8_t +ali1533_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (func == 0) { + if (((dev->pci_conf[0x42] & 0x80) && (addr >= 0x40)) || ((dev->pci_conf[0x5f] & 8) && (addr == 4))) + ret = 0x00; + else { + ret = dev->pci_conf[addr]; + if (addr == 0x41) + ret |= (keyboard_at_get_mouse_scan() << 2); + else if (addr == 0x58) + ret = (ret & 0xbf) | (dev->ide_dev_enable ? 0x40 : 0x00); + else if ((dev->type == 1) && ((addr >= 0x7c) && (addr <= 0xff)) && !dev->pmu_dev_enable) { + dev->pmu_dev_enable = 1; + ret = ali7101_read(func, addr, priv); + dev->pmu_dev_enable = 0; + } + } + } + + return ret; +} + + +static void +ali5229_ide_irq_handler(ali1543_t *dev) +{ + int ctl = 0, ch = 0; + int bit = 0; + + if (dev->ide_conf[0x52] & 0x10) { + ctl ^= 1; + ch ^= 1; + bit ^= 5; + } + + if (dev->ide_conf[0x09] & (1 ^ bit)) { + /* Primary IDE is native. */ + ali1543_log("Primary IDE IRQ mode: Native, Native\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 4); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 4); + } else { + /* Primary IDE is legacy. */ + switch (dev->pci_conf[0x58] & 0x03) { + case 0x00: + /* SIRQI, SIRQII */ + ali1543_log("Primary IDE IRQ mode: SIRQI, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 2); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x01: + /* IRQ14, IRQ15 */ + ali1543_log("Primary IDE IRQ mode: IRQ14, IRQ15\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 0); + break; + case 0x02: + /* IRQ14, SIRQII */ + ali1543_log("Primary IDE IRQ mode: IRQ14, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x03: + /* IRQ14, SIRQI */ + ali1543_log("Primary IDE IRQ mode: IRQ14, SIRQI\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 2); + break; + } + } + + ctl ^= 1; + + if (dev->ide_conf[0x09] & (4 ^ bit)) { + /* Secondary IDE is native. */ + ali1543_log("Secondary IDE IRQ mode: Native, Native\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 4); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 4); + } else { + /* Secondary IDE is legacy. */ + switch (dev->pci_conf[0x58] & 0x03) { + case 0x00: + /* SIRQI, SIRQII */ + ali1543_log("Secondary IDE IRQ mode: SIRQI, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 2); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x01: + /* IRQ14, IRQ15 */ + ali1543_log("Secondary IDE IRQ mode: IRQ14, IRQ15\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 0); + break; + case 0x02: + /* IRQ14, SIRQII */ + ali1543_log("Secondary IDE IRQ mode: IRQ14, SIRQII\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 5); + break; + case 0x03: + /* IRQ14, SIRQI */ + ali1543_log("Secondary IDE IRQ mode: IRQ14, SIRQI\n"); + sff_set_irq_mode(dev->ide_controller[ctl], 0 ^ ch, 0); + sff_set_irq_mode(dev->ide_controller[ctl], 1 ^ ch, 2); + break; + } + } +} + + +static void +ali5229_ide_handler(ali1543_t *dev) +{ + uint32_t ch = 0; + + uint16_t native_base_pri_addr = ((dev->ide_conf[0x11] | dev->ide_conf[0x10] << 8)) & 0xfffe; + uint16_t native_side_pri_addr = ((dev->ide_conf[0x15] | dev->ide_conf[0x14] << 8)) & 0xfffe; + uint16_t native_base_sec_addr = ((dev->ide_conf[0x19] | dev->ide_conf[0x18] << 8)) & 0xfffe; + uint16_t native_side_sec_addr = ((dev->ide_conf[0x1c] | dev->ide_conf[0x1b] << 8)) & 0xfffe; + + uint16_t comp_base_pri_addr = 0x01f0; + uint16_t comp_side_pri_addr = 0x03f6; + uint16_t comp_base_sec_addr = 0x0170; + uint16_t comp_side_sec_addr = 0x0376; + + uint16_t current_pri_base, current_pri_side, current_sec_base, current_sec_side; + + /* Primary Channel Programming */ + if (dev->ide_conf[0x52] & 0x10) { + current_pri_base = (!(dev->ide_conf[0x09] & 1)) ? comp_base_sec_addr : native_base_sec_addr; + current_pri_side = (!(dev->ide_conf[0x09] & 1)) ? comp_side_sec_addr : native_side_sec_addr; + } else { + current_pri_base = (!(dev->ide_conf[0x09] & 1)) ? comp_base_pri_addr : native_base_pri_addr; + current_pri_side = (!(dev->ide_conf[0x09] & 1)) ? comp_side_pri_addr : native_side_pri_addr; + } + + /* Secondary Channel Programming */ + if (dev->ide_conf[0x52] & 0x10) { + current_sec_base = (!(dev->ide_conf[0x09] & 4)) ? comp_base_pri_addr : native_base_pri_addr; + current_sec_side = (!(dev->ide_conf[0x09] & 4)) ? comp_side_pri_addr : native_side_pri_addr; + } else { + current_sec_base = (!(dev->ide_conf[0x09] & 4)) ? comp_base_sec_addr : native_base_sec_addr; + current_sec_side = (!(dev->ide_conf[0x09] & 4)) ? comp_side_sec_addr : native_side_sec_addr; + } + + if (dev->ide_conf[0x52] & 0x10) + ch ^= 8; + + ali1543_log("ali5229_ide_handler(): Disabling primary IDE...\n"); + ide_pri_disable(); + ali1543_log("ali5229_ide_handler(): Disabling secondary IDE...\n"); + ide_sec_disable(); + + if (dev->ide_conf[0x04] & 0x01) { + /* Primary Channel Setup */ + if ((dev->ide_conf[0x09] & 0x20) || (dev->ide_conf[0x4d] & 0x80)) { + ali1543_log("ali5229_ide_handler(): Primary IDE base now %04X...\n", current_pri_base); + ide_set_base(0, current_pri_base); + ali1543_log("ali5229_ide_handler(): Primary IDE side now %04X...\n", current_pri_side); + ide_set_side(0, current_pri_side); + + ali1543_log("ali5229_ide_handler(): Enabling primary IDE...\n"); + ide_pri_enable(); + + sff_bus_master_handler(dev->ide_controller[0], dev->ide_conf[0x04] & 0x01, ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + (0 ^ ch)); + ali1543_log("M5229 PRI: BASE %04x SIDE %04x\n", current_pri_base, current_pri_side); + } + + /* Secondary Channel Setup */ + if ((dev->ide_conf[0x09] & 0x10) || (dev->ide_conf[0x4d] & 0x80)) { + ali1543_log("ali5229_ide_handler(): Secondary IDE base now %04X...\n", current_sec_base); + ide_set_base(1, current_sec_base); + ali1543_log("ali5229_ide_handler(): Secondary IDE side now %04X...\n", current_sec_side); + ide_set_side(1, current_sec_side); + + ali1543_log("ali5229_ide_handler(): Enabling secondary IDE...\n"); + ide_sec_enable(); + + sff_bus_master_handler(dev->ide_controller[1], dev->ide_conf[0x04] & 0x01, (((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8))) + (8 ^ ch)); + ali1543_log("M5229 SEC: BASE %04x SIDE %04x\n", current_sec_base, current_sec_side); + } + } else { + sff_bus_master_handler(dev->ide_controller[0], dev->ide_conf[0x04] & 0x01, (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); + sff_bus_master_handler(dev->ide_controller[1], dev->ide_conf[0x04] & 0x01, ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); + } +} + + +static void +ali5229_chip_reset(ali1543_t *dev) +{ + /* M5229 */ + memset(dev->ide_conf, 0x00, sizeof(dev->pmu_conf)); + dev->ide_conf[0x00] = 0xb9; + dev->ide_conf[0x01] = 0x10; + dev->ide_conf[0x02] = 0x29; + dev->ide_conf[0x03] = 0x52; + dev->ide_conf[0x06] = 0x80; + dev->ide_conf[0x07] = 0x02; + dev->ide_conf[0x08] = 0x20; + dev->ide_conf[0x0a] = 0x01; + dev->ide_conf[0x0b] = 0x01; + dev->ide_conf[0x10] = 0xf1; + dev->ide_conf[0x11] = 0x01; + dev->ide_conf[0x14] = 0xf5; + dev->ide_conf[0x15] = 0x03; + dev->ide_conf[0x18] = 0x71; + dev->ide_conf[0x19] = 0x01; + dev->ide_conf[0x1c] = 0x75; + dev->ide_conf[0x1d] = 0x03; + dev->ide_conf[0x20] = 0x01; + dev->ide_conf[0x21] = 0xf0; + dev->ide_conf[0x3d] = 0x01; + dev->ide_conf[0x3e] = 0x02; + dev->ide_conf[0x3f] = 0x04; + dev->ide_conf[0x53] = 0x03; + dev->ide_conf[0x54] = 0x55; + dev->ide_conf[0x55] = 0x55; + dev->ide_conf[0x63] = 0x01; + dev->ide_conf[0x64] = 0x02; + dev->ide_conf[0x67] = 0x01; + dev->ide_conf[0x78] = 0x21; + + if (dev->type == 1) { + dev->ide_conf[0x08] = 0xc1; + dev->ide_conf[0x43] = 0x00; + dev->ide_conf[0x4b] = 0x4a; + dev->ide_conf[0x4e] = 0xba; + dev->ide_conf[0x4f] = 0x1a; + } + + ali5229_write(0, 0x04, 0x05, dev); + ali5229_write(0, 0x10, 0xf1, dev); + ali5229_write(0, 0x11, 0x01, dev); + ali5229_write(0, 0x14, 0xf5, dev); + ali5229_write(0, 0x15, 0x03, dev); + ali5229_write(0, 0x18, 0x71, dev); + ali5229_write(0, 0x19, 0x01, dev); + ali5229_write(0, 0x1a, 0x75, dev); + ali5229_write(0, 0x1b, 0x03, dev); + ali5229_write(0, 0x20, 0x01, dev); + ali5229_write(0, 0x21, 0xf0, dev); + ali5229_write(0, 0x4d, 0x00, dev); + dev->ide_conf[0x09] = 0xfa; + ali5229_write(0, 0x09, 0xfa, dev); + ali5229_write(0, 0x52, 0x00, dev); + + ali5229_write(0, 0x50, 0x00, dev); + + sff_set_slot(dev->ide_controller[0], dev->ide_slot); + sff_set_slot(dev->ide_controller[1], dev->ide_slot); + sff_bus_master_reset(dev->ide_controller[0], (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); + sff_bus_master_reset(dev->ide_controller[1], ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); + ali5229_ide_handler(dev); +} + + +static void +ali5229_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + ali1543_log("M5229: dev->ide_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + if (!dev->ide_dev_enable) + return; + + switch (addr) { + case 0x04: /* COM - Command Register */ + ali1543_log("IDE04: %02X\n", val); + dev->ide_conf[addr] = val & 0x45; + ali5229_ide_handler(dev); + break; + + case 0x05: + dev->ide_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->ide_conf[addr] &= ~(val & 0xf1); + break; + + case 0x09: /* Control */ + ali1543_log("IDE09: %02X\n", val); + + if (dev->type == 1) { + val &= ~(dev->ide_conf[0x43]); + val |= (dev->ide_conf[addr] & dev->ide_conf[0x43]); + } + + if (dev->ide_conf[0x4d] & 0x80) + dev->ide_conf[addr] = (dev->ide_conf[addr] & 0xfa) | (val & 0x05); + else + dev->ide_conf[addr] = (dev->ide_conf[addr] & 0x8a) | (val & 0x75); + ali5229_ide_handler(dev); + ali5229_ide_irq_handler(dev); + break; + + /* Primary Base Address */ + case 0x10: case 0x11: case 0x14: case 0x15: + /* FALLTHROUGH */ + + /* Secondary Base Address */ + case 0x18: case 0x19: case 0x1c: case 0x1d: + /* FALLTHROUGH */ + + /* Bus Mastering Base Address */ + case 0x20: case 0x21: case 0x22: case 0x23: + dev->ide_conf[addr] = val; + ali5229_ide_handler(dev); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->ide_conf[0x53] & 0x80)) + dev->ide_conf[addr] = val; + break; + + case 0x3c: /* Interrupt Line */ + case 0x3d: /* Interrupt Pin */ + dev->ide_conf[addr] = val; + break; + + /* The machines don't touch anything beyond that point so we avoid any programming */ + case 0x43: + if (dev->type == 1) + dev->ide_conf[addr] = val & 0x7f; + break; + + case 0x4b: + if (dev->type == 1) + dev->ide_conf[addr] = val; + break; + + case 0x4d: + dev->ide_conf[addr] = val & 0x80; + ali5229_ide_handler(dev); + break; + + case 0x4f: + if (dev->type == 0) + dev->ide_conf[addr] = val & 0x3f; + break; + + case 0x50: /* Configuration */ + ali1543_log("IDE50: %02X\n", val); + dev->ide_conf[addr] = val & 0x2b; + dev->ide_dev_enable = !!(val & 0x01); + break; + + case 0x51: + dev->ide_conf[addr] = val & 0xf7; + if (val & 0x80) + ali5229_chip_reset(dev); + else if (val & 0x40) { + sff_bus_master_reset(dev->ide_controller[0], (dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)); + sff_bus_master_reset(dev->ide_controller[1], ((dev->ide_conf[0x20] & 0xf0) | (dev->ide_conf[0x21] << 8)) + 8); + } + break; + + case 0x52: /* FCS - Flexible Channel Setting Register */ + dev->ide_conf[addr] = val; + ali5229_ide_handler(dev); + ali5229_ide_irq_handler(dev); + break; + + case 0x53: /* Subsystem Vendor ID */ + dev->ide_conf[addr] = val & 0x8b; + break; + + case 0x54: /* FIFO threshold of primary channel drive 0 and drive 1 */ + case 0x55: /* FIFO threshold of secondary channel drive 0 and drive 1 */ + case 0x56: /* Ultra DMA /33 setting for Primary drive 0 and drive 1 */ + case 0x57: /* Ultra DMA /33 setting for Secondary drive 0 and drive 1 */ + case 0x78: /* IDE clock's frequency (default value is 33 = 21H) */ + dev->ide_conf[addr] = val; + break; + + case 0x58: + dev->ide_conf[addr] = val & 3; + break; + + case 0x59: case 0x5a: + case 0x5b: + dev->ide_conf[addr] = val & 0x7f; + break; + + case 0x5c: + dev->ide_conf[addr] = val & 3; + break; + + case 0x5d: case 0x5e: + case 0x5f: + dev->ide_conf[addr] = val & 0x7f; + break; + } +} + + +static uint8_t +ali5229_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (dev->ide_dev_enable && (func == 0)) { + ret = dev->ide_conf[addr]; + if ((addr == 0x09) && !(dev->ide_conf[0x50] & 0x02)) + ret &= 0x0f; + else if (addr == 0x50) + ret = (ret & 0xfe) | (dev->ide_dev_enable ? 0x01 : 0x00); + else if (addr == 0x75) + ret = ide_read_ali_75(); + else if (addr == 0x76) + ret = ide_read_ali_76(); + } + + return ret; +} + + +static void +ali5237_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + ali1543_log("M5237: dev->usb_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + if (!dev->usb_dev_enable) + return; + + switch (addr) { + case 0x04: /* USB Enable */ + dev->usb_conf[addr] = val & 0x5f; + ohci_update_mem_mapping(dev->usb, dev->usb_conf[0x11], dev->usb_conf[0x12], dev->usb_conf[0x13], dev->usb_conf[0x04] & 1); + break; + + case 0x05: + dev->usb_conf[addr] = 0x01; + break; + + case 0x07: + dev->usb_conf[addr] &= ~(val & 0xc9); + break; + + case 0x0c: /* Cache Line Size */ + case 0x0d: /* Latency Timer */ + case 0x3c: /* Interrupt Line Register */ + + case 0x42: /* Test Mode Register */ + dev->usb_conf[addr] = val & 0x10; + break; + case 0x43: + if (dev->type == 1) + dev->usb_conf[addr] = val & 0x04; + break; + + /* USB Base I/O */ + case 0x11: + dev->usb_conf[addr] = val & 0xf0; + ohci_update_mem_mapping(dev->usb, dev->usb_conf[0x11], dev->usb_conf[0x12], dev->usb_conf[0x13], dev->usb_conf[0x04] & 1); + break; + case 0x12: case 0x13: + dev->usb_conf[addr] = val; + ohci_update_mem_mapping(dev->usb, dev->usb_conf[0x11], dev->usb_conf[0x12], dev->usb_conf[0x13], dev->usb_conf[0x04] & 1); + break; + + case 0x2c: /* Subsystem Vendor ID */ + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->usb_conf[0x42] & 0x10)) + dev->usb_conf[addr] = val; + break; + } +} + + +static uint8_t +ali5237_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (dev->usb_dev_enable && (func == 0)) + ret = dev->usb_conf[addr]; + + return ret; +} + + +static void +ali7101_write(int func, int addr, uint8_t val, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + ali1543_log("M7101: dev->pmu_conf[%02x] = %02x\n", addr, val); + + if (func > 0) + return; + + if (!dev->pmu_dev_enable) + return; + + if ((dev->pmu_conf[0xc9] & 0x01) && (addr >= 0x40) && (addr != 0xc9)) + return; + + switch (addr) { + case 0x04: /* Enable PMU */ + ali1543_log("PMU04: %02X\n", val); + dev->pmu_conf[addr] = val & 0x01; + if (!(dev->pmu_conf[0x5b] & 0x02)) + acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); + if (!(dev->pmu_conf[0x5b] & 0x04)) { + if (dev->type == 1) + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + else + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + } + break; + + /* PMU Base I/O */ + case 0x10: case 0x11: + if (!(dev->pmu_conf[0x5b] & 0x02)) { + if (addr == 0x10) + dev->pmu_conf[addr] = (val & 0xc0) | 1; + else if (addr == 0x11) + dev->pmu_conf[addr] = val; + + ali1543_log("New ACPI base address: %08X\n", (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0)); + acpi_update_io_mapping(dev->acpi, (dev->pmu_conf[0x11] << 8) | (dev->pmu_conf[0x10] & 0xc0), dev->pmu_conf[0x04] & 1); + } + break; + + /* SMBus Base I/O */ + case 0x14: case 0x15: + if (!(dev->pmu_conf[0x5b] & 0x04)) { + if (addr == 0x14) { + if (dev->type == 1) + dev->pmu_conf[addr] = (val & 0xc0) | 1; + else + dev->pmu_conf[addr] = (val & 0xe0) | 1; + } else if (addr == 0x15) + dev->pmu_conf[addr] = val; + + if (dev->type == 1) { + ali1543_log("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0)); + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + } else { + ali1543_log("New SMBUS base address: %08X\n", (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0)); + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1)); + } + } + break; + + /* Subsystem Vendor ID */ + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + if (!(dev->pmu_conf[0xd8] & 0x08)) + dev->pmu_conf[addr] = val; + break; + + case 0x40: + dev->pmu_conf[addr] = val & 0x1f; + pic_set_smi_irq_mask(8, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x40] & 0x03)); + break; + case 0x41: + dev->pmu_conf[addr] = val & 0x10; + ali1543_log("PMU41: %02X\n", val); + apm_set_do_smi(dev->acpi->apm, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x41] & 0x10)); + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x42: + dev->pmu_conf[addr] &= ~(val & 0x1f); + break; + case 0x43: + dev->pmu_conf[addr] &= ~(val & 0x10); + if (val & 0x10) + acpi_ali_soft_smi_status_write(dev->acpi, 0); + break; + + case 0x44: + dev->pmu_conf[addr] = val; + break; + case 0x45: + dev->pmu_conf[addr] = val & 0x9f; + break; + case 0x46: + dev->pmu_conf[addr] = val & 0x18; + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x48: + dev->pmu_conf[addr] &= ~val; + break; + case 0x49: + dev->pmu_conf[addr] &= ~(val & 0x9f); + break; + case 0x4a: + dev->pmu_conf[addr] &= ~(val & 0x38); + break; + + case 0x4c: + dev->pmu_conf[addr] = val & 5; + break; + case 0x4d: + dev->pmu_conf[addr] = val & 1; + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x4e: + dev->pmu_conf[addr] &= ~(val & 5); + break; + case 0x4f: + dev->pmu_conf[addr] &= ~(val & 1); + break; + + case 0x50: case 0x51: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + + case 0x52: case 0x53: + if (dev->type == 1) + dev->pmu_conf[addr] &= ~val; + break; + + case 0x54: /* Standby timer */ + dev->pmu_conf[addr] = val; + break; + case 0x55: /* APM Timer */ + dev->pmu_conf[addr] = val & 0x7f; + break; + case 0x59: /* Global display timer. */ + dev->pmu_conf[addr] = val & 0x1f; + break; + + case 0x5b: /* ACPI/SMB Base I/O Control */ + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x87; + else + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0x60: + dev->pmu_conf[addr] = val; + break; + case 0x61: + dev->pmu_conf[addr] = val & 0x13; + break; + case 0x62: + dev->pmu_conf[addr] = val & 0xf1; + break; + case 0x63: + dev->pmu_conf[addr] = val & 0x07; + break; + + case 0x64: + dev->pmu_conf[addr] = val; + break; + case 0x65: + dev->pmu_conf[addr] = val & 0x11; + break; + + case 0x68: + dev->pmu_conf[addr] = val & 0x07; + break; + + case 0x6c: case 0x6d: + dev->pmu_conf[addr] = val; + break; + case 0x6e: + dev->pmu_conf[addr] = val & 0xbf; + break; + case 0x6f: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x1e; + else + dev->pmu_conf[addr] = val & 0x1f; + break; + + case 0x70: + dev->pmu_conf[addr] = val; + break; + case 0x71: + dev->pmu_conf[addr] = val & 0x3f; + break; + + case 0x72: + dev->pmu_conf[addr] = val & 0x0f; + break; + + /* TODO: Is the status R/W or R/WC? */ + case 0x74: + dev->pmu_conf[addr] &= ~(val & 0x33); + break; + + case 0x75: + dev->pmu_conf[addr] = val; + break; + + case 0x76: + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0x77: + /* TODO: If bit 1 is clear, then status bit is set even if SMI is disabled. */ + dev->pmu_conf[addr] = val; + pic_set_smi_irq_mask(8, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x40] & 0x03)); + ali1543_log("PMU77: %02X\n", val); + apm_set_do_smi(dev->acpi->apm, (dev->pmu_conf[0x77] & 0x08) && (dev->pmu_conf[0x41] & 0x10)); + break; + + case 0x78: + dev->pmu_conf[addr] = val; + break; + case 0x79: + dev->pmu_conf[addr] = val & 0x0f; + break; + + case 0x7a: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x07; + else + dev->pmu_conf[addr] = val & 0x02; + break; + + case 0x7b: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + else + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0x7c ... 0x7f: + dev->pmu_conf[addr] = val; + break; + + case 0x81: + dev->pmu_conf[addr] = val & 0xf0; + break; + + case 0x82: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0x84 ... 0x87: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + case 0x88 ... 0x8b: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + + case 0x8c: case 0x8d: + dev->pmu_conf[addr] = val & 0x0f; + break; + + case 0x90: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x0f; + else + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0x91: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x02; + break; + + case 0x94: + dev->pmu_conf[addr] = val & 0xf0; + break; + case 0x95 ... 0x97: + dev->pmu_conf[addr] = val; + break; + + case 0x98: case 0x99: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + + case 0xa4: case 0xa5: + dev->pmu_conf[addr] = val; + break; + + case 0xb2: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0xb3: + dev->pmu_conf[addr] = val & 0x7f; + break; + + case 0xb4: + dev->pmu_conf[addr] = val & 0x7c; + break; + + case 0xb5: case 0xb7: + dev->pmu_conf[addr] = val & 0x0f; + break; + + case 0xb8: case 0xb9: + if (dev->type == 1) + dev->pmu_conf[addr] = val; + break; + + case 0xbc: + outb(0x70, val); + break; + + case 0xbd: + dev->pmu_conf[addr] = val & 0x0f; + acpi_set_timer32(dev->acpi, val & 0x04); + break; + + case 0xbe: + dev->pmu_conf[addr] = val & 0x03; + break; + + /* Continue Further Later */ + /* GPO Registers */ + case 0xc0: + dev->pmu_conf[addr] = val & 0x0f; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + case 0xc1: + dev->pmu_conf[addr] = val & 0x12; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + case 0xc2: + dev->pmu_conf[addr] = val & 0x1c; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + case 0xc3: + dev->pmu_conf[addr] = val & 0x06; + acpi_init_gporeg(dev->acpi, dev->pmu_conf[0xc0], dev->pmu_conf[0xc1], dev->pmu_conf[0xc2] | (dev->pmu_conf[0xc3] << 5), 0x00); + break; + + case 0xc6: + dev->pmu_conf[addr] = val & 0x06; + break; + + case 0xc8: case 0xc9: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0xca: + /* TODO: Write to this port causes a beep. */ + dev->pmu_conf[addr] = val; + break; + + case 0xcc: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x1f; + break; + case 0xcd: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x33; + break; + + case 0xd4: + dev->pmu_conf[addr] = val & 0x01; + break; + + case 0xd8: + dev->pmu_conf[addr] = val & 0xfd; + break; + case 0xd9: + if (dev->type == 1) + dev->pmu_conf[addr] = val & 0x3f; + break; + + case 0xe0: + dev->pmu_conf[addr] = val & 0x03; + if (dev->type == 1) + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xc0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); + else + smbus_ali7101_remap(dev->smbus, (dev->pmu_conf[0x15] << 8) | (dev->pmu_conf[0x14] & 0xe0), (dev->pmu_conf[0xe0] & 1) && (dev->pmu_conf[0x04] & 1) && (!(dev->pci_conf[0x5f] & 4))); + break; + + case 0xe1: + dev->pmu_conf[addr] = val; + break; + + case 0xe2: + dev->pmu_conf[addr] = val & 0xf8; + break; + + default: + dev->pmu_conf[addr] = val; + break; + } +} + + +static uint8_t +ali7101_read(int func, int addr, void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + uint8_t ret = 0xff; + + if (dev->pmu_dev_enable && (func == 0)) { + if ((dev->pmu_conf[0xc9] & 0x01) && (addr >= 0x40) && (addr != 0xc9)) + return 0xff; + + /* TODO: C4, C5 = GPIREG (masks: 0D, 0E) */ + if (addr == 0x43) + ret = acpi_ali_soft_smi_status_read(dev->acpi) ? 0x10 : 0x00; + else if (addr == 0x7f) + ret = 0x80; + else if (addr == 0xbc) + ret = inb(0x70); + else + ret = dev->pmu_conf[addr]; + + if (dev->pmu_conf[0x77] & 0x10) { + switch (addr) { + case 0x42: + dev->pmu_conf[addr] &= 0xe0; + break; + case 0x43: + dev->pmu_conf[addr] &= 0xef; + acpi_ali_soft_smi_status_write(dev->acpi, 0); + break; + + case 0x48: + dev->pmu_conf[addr] = 0x00; + break; + case 0x49: + dev->pmu_conf[addr] &= 0x60; + break; + case 0x4a: + dev->pmu_conf[addr] &= 0xc7; + break; + + case 0x4e: + dev->pmu_conf[addr] &= 0xfa; + break; + case 0x4f: + dev->pmu_conf[addr] &= 0xfe; + break; + + case 0x74: + dev->pmu_conf[addr] &= 0xcc; + break; + } + } + } + + return ret; +} + + +static void +ali1543_reset(void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + + /* Temporarily enable everything. Register writes will disable the devices. */ + dev->ide_dev_enable = 1; + dev->usb_dev_enable = 1; + dev->pmu_dev_enable = 1; + + /* M5229 */ + ali5229_chip_reset(dev); + + /* M5237 */ + memset(dev->usb_conf, 0x00, sizeof(dev->usb_conf)); + dev->usb_conf[0x00] = 0xb9; + dev->usb_conf[0x01] = 0x10; + dev->usb_conf[0x02] = 0x37; + dev->usb_conf[0x03] = 0x52; + dev->usb_conf[0x06] = 0x80; + dev->usb_conf[0x07] = 0x02; + dev->usb_conf[0x08] = 0x03; + dev->usb_conf[0x09] = 0x10; + dev->usb_conf[0x0a] = 0x03; + dev->usb_conf[0x0b] = 0x0c; + dev->usb_conf[0x3d] = 0x01; + + ali5237_write(0, 0x04, 0x00, dev); + ali5237_write(0, 0x10, 0x00, dev); + ali5237_write(0, 0x11, 0x00, dev); + ali5237_write(0, 0x12, 0x00, dev); + ali5237_write(0, 0x13, 0x00, dev); + + /* M7101 */ + memset(dev->pmu_conf, 0x00, sizeof(dev->pmu_conf)); + dev->pmu_conf[0x00] = 0xb9; + dev->pmu_conf[0x01] = 0x10; + dev->pmu_conf[0x02] = 0x01; + dev->pmu_conf[0x03] = 0x71; + dev->pmu_conf[0x05] = 0x00; + dev->pmu_conf[0x0a] = 0x01; + dev->pmu_conf[0x0b] = 0x06; + dev->pmu_conf[0xe2] = 0x20; + + acpi_set_slot(dev->acpi, dev->pmu_slot); + acpi_set_nvr(dev->acpi, dev->nvr); + + ali7101_write(0, 0x04, 0x0f, dev); + ali7101_write(0, 0x10, 0x01, dev); + ali7101_write(0, 0x11, 0x00, dev); + ali7101_write(0, 0x12, 0x00, dev); + ali7101_write(0, 0x13, 0x00, dev); + ali7101_write(0, 0x14, 0x01, dev); + ali7101_write(0, 0x15, 0x00, dev); + ali7101_write(0, 0x16, 0x00, dev); + ali7101_write(0, 0x17, 0x00, dev); + ali7101_write(0, 0x40, 0x00, dev); + ali7101_write(0, 0x41, 0x00, dev); + ali7101_write(0, 0x42, 0x00, dev); + ali7101_write(0, 0x43, 0x00, dev); + ali7101_write(0, 0x77, 0x00, dev); + ali7101_write(0, 0xbd, 0x00, dev); + ali7101_write(0, 0xc0, 0x00, dev); + ali7101_write(0, 0xc1, 0x00, dev); + ali7101_write(0, 0xc2, 0x00, dev); + ali7101_write(0, 0xc3, 0x00, dev); + ali7101_write(0, 0xe0, 0x00, dev); + + /* Do the bridge last due to device deactivations. */ + /* M1533 */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x33; + dev->pci_conf[0x03] = 0x15; + dev->pci_conf[0x04] = 0x0f; + dev->pci_conf[0x07] = 0x02; + if (dev->type == 1) + dev->pci_conf[0x08] = 0xc0; + dev->pci_conf[0x0a] = 0x01; + dev->pci_conf[0x0b] = 0x06; + + ali1533_write(0, 0x48, 0x00, dev); // Disables all IRQ's + ali1533_write(0, 0x44, 0x00, dev); + ali1533_write(0, 0x4d, 0x00, dev); + ali1533_write(0, 0x53, 0x00, dev); + ali1533_write(0, 0x58, 0x00, dev); + ali1533_write(0, 0x5f, 0x00, dev); + ali1533_write(0, 0x72, 0x00, dev); + ali1533_write(0, 0x74, 0x00, dev); + ali1533_write(0, 0x75, 0x00, dev); + ali1533_write(0, 0x76, 0x00, dev); + + unmask_a20_in_smm = 1; +} + + +static void +ali1543_close(void *priv) +{ + ali1543_t *dev = (ali1543_t *)priv; + + free(dev); +} + + +static void * +ali1543_init(const device_t *info) +{ + ali1543_t *dev = (ali1543_t *)malloc(sizeof(ali1543_t)); + memset(dev, 0, sizeof(ali1543_t)); + + /* Device 02: M1533 Southbridge */ + dev->pci_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, ali1533_read, ali1533_write, dev); + + /* Device 0B: M5229 IDE Controller*/ + dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE_IDE, ali5229_read, ali5229_write, dev); + + /* Device 0C: M7101 Power Managment Controller */ + dev->pmu_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE_PMU, ali7101_read, ali7101_write, dev); + + /* Device 0F: M5237 USB */ + dev->usb_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE_USB, ali5237_read, ali5237_write, dev); + + /* ACPI */ + dev->acpi = device_add(&acpi_ali_device); + dev->nvr = device_add(&piix4_nvr_device); + + /* DMA */ + dma_alias_set(); + + dma_set_sg_base(0x04); + dma_set_params(1, 0xffffffff); + dma_ext_mode_init(); + dma_high_page_init(); + + /* DDMA */ + dev->ddma = device_add(&ddma_device); + + /* IDE Controllers */ + dev->ide_controller[0] = device_add_inst(&sff8038i_device, 1); + dev->ide_controller[1] = device_add_inst(&sff8038i_device, 2); + + /* Port 92h */ + dev->port_92 = device_add(&port_92_pci_device); + + /* Standard SMBus */ + dev->smbus = device_add(&ali7101_smbus_device); + + /* USB */ + dev->usb = device_add(&usb_device); + + dev->type = info->local & 0xff; + dev->offset = (info->local >> 8) & 0x7f; + if (info->local & 0x8000) + dev->offset = -dev->offset; + pclog("Offset = %i\n", dev->offset); + + pci_enable_mirq(0); + pci_enable_mirq(1); + pci_enable_mirq(2); + pci_enable_mirq(3); + pci_enable_mirq(4); + pci_enable_mirq(5); + pci_enable_mirq(6); + + /* Super I/O chip */ + device_add(&ali5123_device); + + ali1543_reset(dev); + + return dev; +} + +const device_t ali1543_device = { + .name = "ALi M1543 Desktop South Bridge", + .internal_name = "ali1543", + .flags = DEVICE_PCI, + .local = 0x8500, /* -5 slot offset, we can do this because we currently + have no case of M1543 non-C with a different offset */ + .init = ali1543_init, + .close = ali1543_close, + .reset = ali1543_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ali1543c_device = { + .name = "ALi M1543C Desktop South Bridge", + .internal_name = "ali1543c", + .flags = DEVICE_PCI, + .local = 1, + .init = ali1543_init, + .close = ali1543_close, + .reset = ali1543_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/ali1621.c b/src/chipset/ali1621.c new file mode 100644 index 000000000..c234e65ce --- /dev/null +++ b/src/chipset/ali1621.c @@ -0,0 +1,685 @@ +/* + * 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 ALi M1621/2 CPU-to-PCI Bridge. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> + +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> + +#include <86box/chipset.h> + + +typedef struct ali1621_t +{ + uint8_t pci_conf[256]; + + smram_t * smram[2]; +} ali1621_t; + + +#ifdef ENABLE_ALI1621_LOG +int ali1621_do_log = ENABLE_ALI1621_LOG; +static void +ali1621_log(const char *fmt, ...) +{ + va_list ap; + + if (ali1621_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali1621_log(fmt, ...) +#endif + + +/* Table translated to a more sensible format: + Read cycles: + SMREN SMM Mode Code Data + 0 X X PCI PCI + 1 0 Close PCI PCI + 1 0 Lock PCI PCI + 1 0 Protect PCI PCI + 1 0 Open DRAM DRAM + 1 1 Open DRAM DRAM + 1 1 Protect DRAM DRAM + 1 1 Close DRAM PCI + 1 1 Lock DRAM PCI + + Write cycles: + SMWEN SMM Mode Data + 0 X X PCI + 1 0 Close PCI + 1 0 Lock PCI + 1 0 Protect PCI + 1 0 Open DRAM + 1 1 Open DRAM + 1 1 Protect DRAM + 1 1 Close PCI + 1 1 Lock PCI + + Explanation of the modes based above: + If SM*EN = 0, SMRAM is entirely disabled, otherwise: + If mode is Close or Lock, then SMRAM always goes to PCI outside SMM, + and data to PCI, code to DRAM in SMM; + If mode is Protect, then SMRAM always goes to PCI outside SMM and + DRAM in SMM; + If mode is Open, then SMRAM always goes to DRAM. + Read and write are enabled separately. + */ +static void +ali1621_smram_recalc(uint8_t val, ali1621_t *dev) +{ + uint16_t access_smm = 0x0000, access_normal = 0x0000; + + smram_disable_all(); + + if (val & 0xc0) { + /* SMRAM 0: A0000-BFFFF */ + if (val & 0x80) { + access_smm = ACCESS_SMRAM_X; + + switch (val & 0x30) { + case 0x10: /* Open. */ + access_normal = ACCESS_SMRAM_RX; + /* FALLTHROUGH */ + case 0x30: /* Protect. */ + access_smm |= ACCESS_SMRAM_R; + break; + } + } + + if (val & 0x40) switch (val & 0x30) { + case 0x10: /* Open. */ + access_normal |= ACCESS_SMRAM_W; + /* FALLTHROUGH */ + case 0x30: /* Protect. */ + access_smm |= ACCESS_SMRAM_W; + break; + } + + smram_enable(dev->smram[0], 0xa0000, 0xa0000, 0x20000, ((val & 0x30) == 0x10), (val & 0x30)); + + mem_set_access(ACCESS_NORMAL, 3, 0xa0000, 0x20000, access_normal); + mem_set_access(ACCESS_SMM, 3, 0xa0000, 0x20000, access_smm); + } + + if (val & 0x08) + smram_enable(dev->smram[1], 0x38000, 0xa8000, 0x08000, 0, 1); + + flushmmucache_nopc(); +} + + +static void +ali1621_shadow_recalc(int cur_reg, ali1621_t *dev) +{ + int i, r_bit, w_bit, reg; + uint32_t base, flags = 0; + + shadowbios = shadowbios_write = 0; + + /* C0000-EFFFF */ + for (i = 0; i < 12; i++) { + base = 0x000c0000 + (i << 14); + r_bit = (i << 1) + 4; + reg = 0x84; + if (r_bit > 23) { + r_bit &= 7; + reg += 3; + } else if (r_bit > 15) { + r_bit &= 7; + reg += 2; + } else if (r_bit > 7) { + r_bit &= 7; + reg++; + } + w_bit = r_bit + 1; + + flags = (dev->pci_conf[reg] & (1 << r_bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[reg] & (1 << w_bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (base >= 0x000e0000) { + if (dev->pci_conf[reg] & (1 << r_bit)) + shadowbios |= 1; + if (dev->pci_conf[reg] & (1 << r_bit)) + shadowbios_write |= 1; + } + + ali1621_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x00003fff, + (dev->pci_conf[reg] & (1 << r_bit)) ? 'I' : 'E', (dev->pci_conf[reg] & (1 << w_bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00004000, flags); + } + + /* F0000-FFFFF */ + base = 0x000f0000; + r_bit = 4; + w_bit = 5; + reg = 0x87; + + flags = (dev->pci_conf[reg] & (1 << r_bit)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + flags |= ((dev->pci_conf[reg] & (1 << w_bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY); + + if (dev->pci_conf[reg] & (1 << r_bit)) + shadowbios |= 1; + if (dev->pci_conf[reg] & (1 << r_bit)) + shadowbios_write |= 1; + + ali1621_log("%08X-%08X shadow: R%c, W%c\n", base, base + 0x0000ffff, + (dev->pci_conf[reg] & (1 << r_bit)) ? 'I' : 'E', (dev->pci_conf[reg] & (1 << w_bit)) ? 'I' : 'E'); + mem_set_mem_state_both(base, 0x00010000, flags); + + flushmmucache_nopc(); +} + + +static void +ali1621_mask_bar(ali1621_t *dev) +{ + uint32_t bar, mask; + + switch (dev->pci_conf[0xbc] & 0x0f) { + case 0x00: + default: + mask = 0x00000000; + break; + case 0x01: + mask = 0xfff00000; + break; + case 0x02: + mask = 0xffe00000; + break; + case 0x03: + mask = 0xffc00000; + break; + case 0x04: + mask = 0xff800000; + break; + case 0x06: + mask = 0xff000000; + break; + case 0x07: + mask = 0xfe000000; + break; + case 0x08: + mask = 0xfc000000; + break; + case 0x09: + mask = 0xf8000000; + break; + case 0x0a: + mask = 0xf0000000; + break; + } + + bar = ((dev->pci_conf[0x13] << 24) | (dev->pci_conf[0x12] << 16)) & mask; + dev->pci_conf[0x12] = (bar >> 16) & 0xff; + dev->pci_conf[0x13] = (bar >> 24) & 0xff; +} + + +static void +ali1621_write(int func, int addr, uint8_t val, void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + + switch (addr) { + case 0x04: + dev->pci_conf[addr] = val & 0x01; + break; + case 0x05: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf0); + break; + + case 0x0d: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x12: + dev->pci_conf[0x12] = (val & 0xc0); + ali1621_mask_bar(dev); + break; + case 0x13: + dev->pci_conf[0x13] = val; + ali1621_mask_bar(dev); + break; + + case 0x34: + dev->pci_conf[addr] = val; + break; + + case 0x40: + dev->pci_conf[addr] = val; + break; + case 0x41: + dev->pci_conf[addr] = val; + break; + + case 0x42: + dev->pci_conf[addr] = val; + break; + case 0x43: + dev->pci_conf[addr] = val; + break; + + case 0x44: + dev->pci_conf[addr] = val; + break; + case 0x45: + dev->pci_conf[addr] = val; + break; + + case 0x46: + dev->pci_conf[addr] = val; + break; + case 0x47: + dev->pci_conf[addr] = val; + break; + + case 0x48: + dev->pci_conf[addr] = val; + break; + case 0x49: + dev->pci_conf[addr] = val; + break; + + case 0x4a: + dev->pci_conf[addr] = val; + break; + + case 0x4b: + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x4c: + dev->pci_conf[addr] = val; + break; + + case 0x4d: + dev->pci_conf[addr] = val; + break; + + case 0x4e: + dev->pci_conf[addr] = val; + break; + case 0x4f: + dev->pci_conf[addr] = val; + break; + + case 0x50: + dev->pci_conf[addr] = val & 0xef; + break; + + case 0x51: + dev->pci_conf[addr] = val; + break; + + case 0x52: + dev->pci_conf[addr] = val & 0x9f; + break; + + case 0x53: + dev->pci_conf[addr] = val; + break; + + case 0x54: + dev->pci_conf[addr] = val & 0xb4; + break; + case 0x55: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x56: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x57: + dev->pci_conf[addr] = val & 0x08; + break; + + case 0x58: + dev->pci_conf[addr] = val; + break; + + case 0x59: + dev->pci_conf[addr] = val; + break; + + case 0x5a: + dev->pci_conf[addr] = val; + break; + + case 0x5c: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x60: + dev->pci_conf[addr] = val; + break; + + case 0x61: + dev->pci_conf[addr] = val; + break; + + case 0x62: + dev->pci_conf[addr] = val; + break; + + case 0x63: + dev->pci_conf[addr] = val; + break; + + case 0x64: + dev->pci_conf[addr] = val & 0xb7; + break; + case 0x65: + dev->pci_conf[addr] = val & 0x01; + break; + + case 0x66: + dev->pci_conf[addr] &= ~(val & 0x33); + break; + + case 0x67: + dev->pci_conf[addr] = val; + break; + + case 0x68: + dev->pci_conf[addr] = val; + break; + + case 0x69: + dev->pci_conf[addr] = val; + break; + + case 0x6c ... 0x7b: + /* Bits 22:20 = DRAM Row size: + - 000: 4 MB; + - 001: 8 MB; + - 010: 16 MB; + - 011: 32 MB; + - 100: 64 MB; + - 101: 128 MB; + - 110: 256 MB; + - 111: Reserved. */ + dev->pci_conf[addr] = val; + spd_write_drbs_ali1621(dev->pci_conf, 0x6c, 0x7b); + break; + + case 0x7c ... 0x7f: + dev->pci_conf[addr] = val; + break; + + case 0x80: + dev->pci_conf[addr] = val; + break; + case 0x81: + dev->pci_conf[addr] = val & 0xdf; + break; + + case 0x82: + dev->pci_conf[addr] = val & 0xf7; + break; + + case 0x83: + dev->pci_conf[addr] = val & 0xfc; + ali1621_smram_recalc(val & 0xfc, dev); + break; + + case 0x84 ... 0x87: + if (addr == 0x87) + dev->pci_conf[addr] = val & 0x3f; + else + dev->pci_conf[addr] = val; + ali1621_shadow_recalc(val, dev); + break; + + case 0x88: case 0x89: + dev->pci_conf[addr] = val; + break; + case 0x8a: + dev->pci_conf[addr] = val & 0xc5; + break; + case 0x8b: + dev->pci_conf[addr] = val & 0xbf; + break; + + case 0x8c ... 0x8f: + dev->pci_conf[addr] = val; + break; + + case 0x90: + dev->pci_conf[addr] = val; + break; + case 0x91: + dev->pci_conf[addr] = val & 0x07; + break; + + case 0x94 ... 0x97: + dev->pci_conf[addr] = val; + break; + + case 0x98 ... 0x9b: + dev->pci_conf[addr] = val; + break; + + case 0x9c ... 0x9f: + dev->pci_conf[addr] = val; + break; + + case 0xa0: case 0xa1: + dev->pci_conf[addr] = val; + break; + + case 0xbc: + dev->pci_conf[addr] = val & 0x0f; + ali1621_mask_bar(dev); + break; + case 0xbd: + dev->pci_conf[addr] = val & 0xf0; + break; + case 0xbe: case 0xbf: + dev->pci_conf[addr] = val; + break; + + case 0xc0: + dev->pci_conf[addr] = val & 0xb1; + break; + + case 0xc4 ... 0xc7: + dev->pci_conf[addr] = val; + break; + + case 0xc8: + dev->pci_conf[addr] = val & 0x8c; + break; + case 0xc9: + dev->pci_conf[addr] = val; + break; + case 0xca: + dev->pci_conf[addr] = val & 0x7f; + break; + case 0xcb: + dev->pci_conf[addr] = val & 0x87; + break; + + case 0xcc ... 0xcf: + dev->pci_conf[addr] = val; + break; + + case 0xd0: + dev->pci_conf[addr] = val & 0x80; + break; + case 0xd2: + dev->pci_conf[addr] = val & 0x40; + break; + case 0xd3: + dev->pci_conf[addr] = val & 0xb0; + break; + + case 0xd4: + dev->pci_conf[addr] = val; + break; + case 0xd5: + dev->pci_conf[addr] = val & 0xef; + break; + case 0xd6: case 0xd7: + dev->pci_conf[addr] = val; + break; + + case 0xf0 ... 0xff: + dev->pci_conf[addr] = val; + break; + } +} + + +static uint8_t +ali1621_read(int func, int addr, void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + uint8_t ret = 0xff; + + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ali1621_reset(void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + int i; + + /* Default Registers */ + dev->pci_conf[0x00] = 0xb9; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x21; + dev->pci_conf[0x03] = 0x16; + dev->pci_conf[0x04] = 0x06; + dev->pci_conf[0x05] = 0x00; + dev->pci_conf[0x06] = 0x10; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x08] = 0x01; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x10] = 0x08; + dev->pci_conf[0x34] = 0xb0; + dev->pci_conf[0x40] = 0x0c; + dev->pci_conf[0x41] = 0x0c; + dev->pci_conf[0x4c] = 0x04; + dev->pci_conf[0x4d] = 0x04; + dev->pci_conf[0x4e] = 0x7f; + dev->pci_conf[0x4f] = 0x7f; + dev->pci_conf[0x50] = 0x0c; + dev->pci_conf[0x53] = 0x02; + dev->pci_conf[0x5a] = 0x02; + dev->pci_conf[0x63] = 0x02; + dev->pci_conf[0x6c] = dev->pci_conf[0x70] = dev->pci_conf[0x74] = dev->pci_conf[0x78] = 0xff; + dev->pci_conf[0x6d] = dev->pci_conf[0x71] = dev->pci_conf[0x75] = dev->pci_conf[0x79] = 0xff; + dev->pci_conf[0x6e] = dev->pci_conf[0x72] = dev->pci_conf[0x76] = dev->pci_conf[0x7a] = 0x00; + dev->pci_conf[0x6f] = dev->pci_conf[0x73] = dev->pci_conf[0x77] = dev->pci_conf[0x7b] = 0xe0; + dev->pci_conf[0x6f] |= 0x06; + dev->pci_conf[0x7c] = 0x11; + dev->pci_conf[0x7d] = 0xc4; + dev->pci_conf[0x7e] = 0xc7; + dev->pci_conf[0x80] = 0x01; + dev->pci_conf[0x81] = 0xc0; + dev->pci_conf[0x8e] = 0x01; + dev->pci_conf[0xa0] = 0x20; + dev->pci_conf[0xb0] = 0x02; + dev->pci_conf[0xb2] = 0x10; + dev->pci_conf[0xb4] = 0x03; + dev->pci_conf[0xb5] = 0x02; + dev->pci_conf[0xb7] = 0x20; + dev->pci_conf[0xc0] = 0x80; + dev->pci_conf[0xc9] = 0x28; + dev->pci_conf[0xd4] = 0x10; + dev->pci_conf[0xd5] = 0x01; + dev->pci_conf[0xf0] = dev->pci_conf[0xf4] = dev->pci_conf[0xf8] = dev->pci_conf[0xfc] = 0x20; + dev->pci_conf[0xf1] = dev->pci_conf[0xf5] = dev->pci_conf[0xf9] = dev->pci_conf[0xfd] = 0x43; + dev->pci_conf[0xf2] = dev->pci_conf[0xf6] = dev->pci_conf[0xfa] = dev->pci_conf[0xfe] = 0x21; + dev->pci_conf[0xf3] = dev->pci_conf[0xf7] = dev->pci_conf[0xfb] = dev->pci_conf[0xff] = 0x43; + + ali1621_write(0, 0x83, 0x08, dev); + + for (i = 0; i < 4; i++) + ali1621_write(0, 0x84 + i, 0x00, dev); +} + + +static void +ali1621_close(void *priv) +{ + ali1621_t *dev = (ali1621_t *)priv; + + smram_del(dev->smram[1]); + smram_del(dev->smram[0]); + + free(dev); +} + + +static void * +ali1621_init(const device_t *info) +{ + ali1621_t *dev = (ali1621_t *)malloc(sizeof(ali1621_t)); + memset(dev, 0, sizeof(ali1621_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, ali1621_read, ali1621_write, dev); + + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); + + ali1621_reset(dev); + + device_add(&ali5247_agp_device); + + return dev; +} + +const device_t ali1621_device = { + .name = "ALi M1621 CPU-to-PCI Bridge", + .internal_name = "ali1621", + .flags = DEVICE_PCI, + .local = 0, + .init = ali1621_init, + .close = ali1621_close, + .reset = ali1621_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c new file mode 100644 index 000000000..612970e45 --- /dev/null +++ b/src/chipset/ali6117.c @@ -0,0 +1,512 @@ +/* + * 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 ALi M6117 SoC. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/device.h> +#include <86box/port_92.h> +#include <86box/usb.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/chipset.h> + + +typedef struct ali6117_t +{ + uint32_t local; + + /* Main registers (port 22h/23h) */ + uint8_t unlocked, mode; + uint8_t reg_offset; + uint8_t regs[256]; +} ali6117_t; + + +/* Total size, Bank 0 size, Bank 1 size, Bank 2 size, Bank 3 size. */ +static uint32_t ali6117_modes[32][5] = { + { 1024, 512, 512, 0, 0 }, + { 2048, 512, 512, 512, 512 }, + { 3072, 512, 512, 2048, 0 }, + { 5120, 512, 512, 2048, 2048 }, + { 9216, 512, 512, 8192, 0 }, + { 1024, 1024, 0, 0, 0 }, + { 2048, 1024, 1024, 0, 0 }, + { 4096, 1024, 1024, 2048, 0 }, + { 6144, 1024, 1024, 2048, 2048 }, + { 10240, 1024, 1024, 8192, 0 }, + { 18432, 1024, 1024, 8192, 8192 }, + { 3072, 1024, 2048, 0, 0 }, + { 5120, 1024, 2048, 2048, 0 }, + { 9216, 1024, 8192, 0, 0 }, + { 2048, 2048, 0, 0, 0 }, + { 4096, 2048, 2048, 0, 0 }, + { 6144, 2048, 2048, 2048, 0 }, + { 8192, 2048, 2048, 2048, 2048 }, + { 12288, 2048, 2048, 8192, 0 }, + { 20480, 2048, 2048, 8192, 8192 }, + { 10240, 2048, 8192, 0, 0 }, + { 18432, 2048, 8192, 8192, 0 }, + { 26624, 2048, 8192, 8192, 8192 }, + { 4096, 4096, 0, 0, 0 }, + { 8192, 4096, 4096, 0, 0 }, + { 24576, 4096, 4096, 8192, 8192 }, + { 12288, 4096, 8192, 0, 0 }, + { 8192, 8192, 0, 0, 0 }, + { 16384, 8192, 8192, 0, 0 }, + { 24576, 8192, 8192, 8192, 0 }, + { 32768, 8192, 8192, 8192, 8192 }, + { 65536, 32768, 32768, 0, 0 } +}; + + +#ifdef ENABLE_ALI6117_LOG +int ali6117_do_log = ENABLE_ALI6117_LOG; + +static void +ali6117_log(const char *fmt, ...) +{ + va_list ap; + + if (ali6117_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ali6117_log(fmt, ...) +#endif + + +static void +ali6117_recalcmapping(ali6117_t *dev) +{ + uint8_t reg, bitpair; + uint32_t base, size; + int state; + + shadowbios = 0; + shadowbios_write = 0; + + ali6117_log("ALI6117: Shadowing for A0000-BFFFF (reg 12 bit 1) = %s\n", (dev->regs[0x12] & 0x02) ? "on" : "off"); + mem_set_mem_state(0xa0000, 0x20000, (dev->regs[0x12] & 0x02) ? (MEM_WRITE_INTERNAL | MEM_READ_INTERNAL) : (MEM_WRITE_EXTANY | MEM_READ_EXTANY)); + + for (reg = 0; reg <= 1; reg++) { + for (bitpair = 0; bitpair <= 3; bitpair++) { + size = 0x8000; + base = 0xc0000 + (size * ((reg * 4) + bitpair)); + ali6117_log("ALI6117: Shadowing for %05X-%05X (reg %02X bp %d wmask %02X rmask %02X) =", base, base + size - 1, 0x14 + reg, bitpair, 1 << ((bitpair * 2) + 1), 1 << (bitpair * 2)); + + state = 0; + if (dev->regs[0x14 + reg] & (1 << ((bitpair * 2) + 1))) { + ali6117_log(" w on"); + state |= MEM_WRITE_INTERNAL; + if (base >= 0xe0000) + shadowbios_write |= 1; + } else { + ali6117_log(" w off"); + state |= MEM_WRITE_EXTANY; + } + if (dev->regs[0x14 + reg] & (1 << (bitpair * 2))) { + ali6117_log("; r on\n"); + state |= MEM_READ_INTERNAL; + if (base >= 0xe0000) + shadowbios |= 1; + } else { + ali6117_log("; r off\n"); + state |= MEM_READ_EXTANY; + } + + mem_set_mem_state(base, size, state); + } + } + + flushmmucache_nopc(); +} + + +static void +ali6117_bank_recalc(ali6117_t *dev) +{ + int i; + uint32_t bank, addr; + + for (i = 0x00000000; i < (mem_size << 10); i += 4096) { + if ((i >= 0x000a0000) && (i < 0x00100000)) + continue; + + if (!is6117 && (i >= 0x00f00000) && (i < 0x01000000)) + continue; + + if (is6117 && (i >= 0x03f00000) && (i < 0x04000000)) + continue; + + switch (dev->regs[0x10] & 0xf8) { + case 0xe8: + bank = (i >> 12) & 3; + addr = (i & 0xfff) | ((i >> 14) << 12); + ali6117_log("E8 (%08X): Bank %i, address %08X vs. bank size %08X\n", i, bank, addr, ali6117_modes[dev->mode][bank + 1] * 1024); + if (addr < (ali6117_modes[dev->mode][bank + 1] * 1024)) + mem_set_mem_state_both(i, 4096, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(i, 4096, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 0xf8: + bank = (i >> 12) & 1; + addr = (i & 0xfff) | ((i >> 13) << 12); + ali6117_log("F8 (%08X): Bank %i, address %08X vs. bank size %08X\n", i, bank, addr, ali6117_modes[dev->mode][bank + 1] * 1024); + if (addr < (ali6117_modes[dev->mode][bank + 1] * 1024)) + mem_set_mem_state_both(i, 4096, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(i, 4096, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + default: + mem_set_mem_state_both(i, 4096, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } + + flushmmucache(); +} + + +static void +ali6117_reg_write(uint16_t addr, uint8_t val, void *priv) +{ + ali6117_t *dev = (ali6117_t *) priv; + + ali6117_log("ALI6117: reg_write(%04X, %02X)\n", addr, val); + + if (addr == 0x22) + dev->reg_offset = val; + else if (dev->reg_offset == 0x13) + dev->unlocked = (val == 0xc5); + else if (dev->unlocked) { + ali6117_log("ALI6117: regs[%02X] = %02X\n", dev->reg_offset, val); + + if (!(dev->local & 0x08) || (dev->reg_offset < 0x30)) switch (dev->reg_offset) { + case 0x30: case 0x34: case 0x35: case 0x3e: + case 0x3f: case 0x46: case 0x4c: case 0x6a: + case 0x73: + return; /* read-only registers */ + + case 0x10: + refresh_at_enable = !(val & 0x02) || !!(dev->regs[0x20] & 0x80); + dev->regs[dev->reg_offset] = val; + + if (dev->local != 0x8) { + if (val & 0x04) + mem_set_mem_state_both(0x00f00000, 0x00100000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else + mem_set_mem_state_both(0x00f00000, 0x00100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + ali6117_bank_recalc(dev); + } + break; + + case 0x12: + val &= 0xf7; + /* FALL-THROUGH */ + + case 0x14: case 0x15: + dev->regs[dev->reg_offset] = val; + ali6117_recalcmapping(dev); + break; + + case 0x1e: + val &= 0x07; + + switch (val) { + /* Half PIT clock. */ + case 0x0: + cpu_set_isa_speed(7159091); + break; + + /* Divisors on the input clock PCLK2, which is double the CPU clock. */ + case 0x1: + cpu_set_isa_speed(cpu_busspeed / 1.5); + break; + + case 0x2: + cpu_set_isa_speed(cpu_busspeed / 2); + break; + + case 0x3: + cpu_set_isa_speed(cpu_busspeed / 2.5); + break; + + case 0x4: + cpu_set_isa_speed(cpu_busspeed / 3); + break; + + case 0x5: + cpu_set_isa_speed(cpu_busspeed / 4); + break; + + case 0x6: + cpu_set_isa_speed(cpu_busspeed / 5); + break; + + case 0x7: + cpu_set_isa_speed(cpu_busspeed / 6); + break; + } + break; + + case 0x20: + val &= 0xbf; + refresh_at_enable = !(dev->regs[0x10] & 0x02) || !!(val & 0x80); + break; + + case 0x31: + /* TODO: fast gate A20 (bit 0) */ + val &= 0x21; + break; + + case 0x32: + val &= 0xc1; + break; + + case 0x33: + val &= 0xfd; + break; + + case 0x36: + val &= 0xf0; + val |= dev->regs[dev->reg_offset]; + break; + + case 0x37: + val &= 0xf5; + break; + + case 0x3c: + val &= 0x8f; + ide_pri_disable(); + ide_set_base(1, (val & 0x01) ? 0x170 : 0x1f0); + ide_set_side(1, (val & 0x01) ? 0x376 : 0x3f6); + ide_pri_enable(); + break; + + case 0x44: case 0x45: + val &= 0x3f; + break; + + case 0x4a: + val &= 0xfe; + break; + + case 0x55: + val &= 0x03; + break; + + case 0x56: + val &= 0xc7; + break; + + case 0x58: + val &= 0xc3; + break; + + case 0x59: + val &= 0x60; + break; + + case 0x5b: + val &= 0x1f; + break; + + case 0x64: + val &= 0xf7; + break; + + case 0x66: + val &= 0xe3; + break; + + case 0x67: + val &= 0xdf; + break; + + case 0x69: + val &= 0x50; + break; + + case 0x6b: + val &= 0x7f; + break; + + case 0x6e: case 0x6f: + val &= 0x03; + break; + + case 0x71: + val &= 0x1f; + break; + } + + dev->regs[dev->reg_offset] = val; + } +} + + +static uint8_t +ali6117_reg_read(uint16_t addr, void *priv) +{ + ali6117_t *dev = (ali6117_t *) priv; + uint8_t ret; + + if (addr == 0x22) + ret = dev->reg_offset; + else + ret = dev->regs[dev->reg_offset]; + + ali6117_log("ALI6117: reg_read(%04X) = %02X\n", dev->reg_offset, ret); + return ret; +} + + +static void +ali6117_reset(void *priv) +{ + ali6117_t *dev = (ali6117_t *) priv; + + ali6117_log("ALI6117: reset()\n"); + + memset(dev->regs, 0, sizeof(dev->regs)); + dev->regs[0x11] = 0xf8; + dev->regs[0x12] = 0x20; + dev->regs[0x17] = 0xff; + dev->regs[0x18] = 0xf0; + dev->regs[0x1a] = 0xff; + dev->regs[0x1b] = 0xf0; + dev->regs[0x1d] = 0xff; + dev->regs[0x20] = 0x80; + if (dev->local & 0x08) { + dev->regs[0x30] = 0x08; + dev->regs[0x31] = 0x01; + dev->regs[0x34] = 0x04; /* enable internal RTC */ + dev->regs[0x35] = 0x20; /* enable internal KBC */ + dev->regs[0x36] = dev->local & 0x07; /* M6117D ID */ + } + + cpu_set_isa_speed(7159091); + + refresh_at_enable = 1; + + if (dev->local != 0x8) { + /* On-board memory 15-16M is enabled by default. */ + mem_set_mem_state_both(0x00f00000, 0x00100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + ali6117_bank_recalc(dev); + } +} + + +static void +ali6117_setup(ali6117_t *dev) +{ + ali6117_log("ALI6117: setup()\n"); + + /* Main register interface */ + io_sethandler(0x22, 2, + ali6117_reg_read, NULL, NULL, ali6117_reg_write, NULL, NULL, dev); +} + + +static void +ali6117_close(void *priv) +{ + ali6117_t *dev = (ali6117_t *) priv; + + ali6117_log("ALI6117: close()\n"); + + io_removehandler(0x22, 2, + ali6117_reg_read, NULL, NULL, ali6117_reg_write, NULL, NULL, dev); + + free(dev); +} + + +static void * +ali6117_init(const device_t *info) +{ + int i, last_match = 0; + + ali6117_log("ALI6117: init()\n"); + + ali6117_t *dev = (ali6117_t *) malloc(sizeof(ali6117_t)); + memset(dev, 0, sizeof(ali6117_t)); + + dev->local = info->local; + + device_add(&ide_isa_device); + + ali6117_setup(dev); + + for (i = 31; i >= 0; i--) { + if ((mem_size >= ali6117_modes[i][0]) && (ali6117_modes[i][0] > last_match)) { + last_match = ali6117_modes[i][0]; + dev->mode = i; + } + } + + ali6117_reset(dev); + + if (!(dev->local & 0x08)) + pic_elcr_io_handler(0); + + return dev; +} + +const device_t ali1217_device = { + .name = "ALi M1217", + .internal_name = "ali1217", + .flags = DEVICE_AT, + .local = 0x8, + .init = ali6117_init, + .close = ali6117_close, + .reset = ali6117_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ali6117d_device = { + .name = "ALi M6117D", + .internal_name = "ali6117d", + .flags = DEVICE_AT, + .local = 0x2, + .init = ali6117_init, + .close = ali6117_close, + .reset = ali6117_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c new file mode 100644 index 000000000..97c8716eb --- /dev/null +++ b/src/chipset/contaq_82c59x.c @@ -0,0 +1,375 @@ +/* + * 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 Contaq/Cypress 82C596(A) and 597 chipsets. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ + +#include +#include +#include +#include +#include +#include +#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/smram.h> +#include <86box/chipset.h> + + +#ifdef ENABLE_CONTAQ_82C59X_LOG +int contaq_82c59x_do_log = ENABLE_CONTAQ_82C59X_LOG; + +static void +contaq_82c59x_log(const char *fmt, ...) +{ + va_list ap; + + if (contaq_82c59x_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define contaq_82c59x_log(fmt, ...) +#endif + + +typedef struct +{ + uint32_t phys, virt; +} mem_remapping_t; + + +typedef struct +{ + uint8_t index, green, + smi_status_set, + regs[256], smi_status[2]; + + smram_t *smram[2]; +} contaq_82c59x_t; + + +static void +contaq_82c59x_isa_speed_recalc(contaq_82c59x_t *dev) +{ + if (dev->regs[0x1c] & 0x02) + cpu_set_isa_speed(7159091); + else { + /* TODO: ISA clock dividers for 386 and alt. 486. */ + switch (dev->regs[0x10] & 0x03) { + case 0x00: + cpu_set_isa_speed(cpu_busspeed / 4); + break; + case 0x01: + cpu_set_isa_speed(cpu_busspeed / 6); + break; + case 0x02: + cpu_set_isa_speed(cpu_busspeed / 8); + break; + case 0x03: + cpu_set_isa_speed(cpu_busspeed / 5); + break; + } + } +} + + +static void +contaq_82c59x_shadow_recalc(contaq_82c59x_t *dev) +{ + uint32_t i, base; + uint8_t bit; + + shadowbios = shadowbios_write = 0; + + /* F0000-FFFFF */ + if (dev->regs[0x15] & 0x80) { + shadowbios |= 1; + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + } else { + shadowbios_write |= 1; + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + + /* C0000-CFFFF */ + if (dev->regs[0x15] & 0x01) + mem_set_mem_state_both(0xc0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else { + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + bit = 1 << (i + 2); + if (dev->regs[0x15] & bit) { + if (dev->regs[0x15] & 0x02) + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + if (dev->green) { + /* D0000-DFFFF */ + if (dev->regs[0x6e] & 0x01) + mem_set_mem_state_both(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else { + for (i = 0; i < 4; i++) { + base = 0xd0000 + (i << 14); + bit = 1 << (i + 2); + if (dev->regs[0x6e] & bit) { + if (dev->regs[0x6e] & 0x02) + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + else + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + /* E0000-EFFFF */ + if (dev->regs[0x6f] & 0x01) + mem_set_mem_state_both(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else { + for (i = 0; i < 4; i++) { + base = 0xe0000 + (i << 14); + bit = 1 << (i + 2); + if (dev->regs[0x6f] & bit) { + shadowbios |= 1; + if (dev->regs[0x6f] & 0x02) + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + else { + shadowbios_write |= 1; + mem_set_mem_state_both(base, 0x04000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + } else + mem_set_mem_state_both(base, 0x04000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + } +} + + +static void +contaq_82c59x_smram_recalc(contaq_82c59x_t *dev) +{ + smram_disable(dev->smram[1]); + + if (dev->regs[0x70] & 0x04) + smram_enable(dev->smram[1], 0x00040000, 0x000a0000, 0x00020000, 1, 1); +} + + +static void +contaq_82c59x_write(uint16_t addr, uint8_t val, void *priv) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + + switch (addr) { + case 0x22: + dev->index = val; + break; + + case 0x23: + contaq_82c59x_log("Contaq 82C59x: dev->regs[%02x] = %02x\n", dev->index, val); + + if ((dev->index >= 0x60) && !dev->green) + return; + + switch (dev->index) { + /* Registers common to 82C596(A) and 82C597. */ + case 0x10: + dev->regs[dev->index] = val; + contaq_82c59x_isa_speed_recalc(dev); + break; + + case 0x11: + dev->regs[dev->index] = val; + cpu_cache_int_enabled = !!(val & 0x01); + cpu_update_waitstates(); + break; + + case 0x12: case 0x13: + dev->regs[dev->index] = val; + break; + + case 0x14: + dev->regs[dev->index] = val; + reset_on_hlt = !!(val & 0x80); + break; + + case 0x15: + dev->regs[dev->index] = val; + contaq_82c59x_shadow_recalc(dev); + break; + + case 0x16 ... 0x1b: + dev->regs[dev->index] = val; + break; + + case 0x1c: + /* TODO: What's NPRST (generated if bit 3 is set)? */ + dev->regs[dev->index] = val; + contaq_82c59x_isa_speed_recalc(dev); + break; + + case 0x1d ... 0x1f: + dev->regs[dev->index] = val; + break; + + /* Green (82C597-specific) registers. */ + case 0x60 ... 0x63: + dev->regs[dev->index] = val; + break; + + case 0x64: + dev->regs[dev->index] = val; + if (val & 0x80) { + if (dev->regs[0x65] & 0x80) + smi_raise(); + dev->smi_status[0] |= 0x10; + } + break; + + case 0x65 ... 0x69: + dev->regs[dev->index] = val; + break; + + case 0x6a: + dev->regs[dev->index] = val; + dev->smi_status_set = !!(val & 0x80); + break; + + case 0x6b ... 0x6d: + dev->regs[dev->index] = val; + break; + + case 0x6e: case 0x6f: + dev->regs[dev->index] = val; + contaq_82c59x_shadow_recalc(dev); + break; + + case 0x70: + dev->regs[dev->index] = val; + contaq_82c59x_smram_recalc(dev); + break; + + case 0x71 ... 0x79: + dev->regs[dev->index] = val; + break; + + case 0x7b: case 0x7c: + dev->regs[dev->index] = val; + break; + } + break; + } +} + + +static uint8_t +contaq_82c59x_read(uint16_t addr, void *priv) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + uint8_t ret = 0xff; + + if (addr == 0x23) { + if (dev->index == 0x6a) { + ret = dev->smi_status[dev->smi_status_set]; + /* I assume it's cleared on read. */ + dev->smi_status[dev->smi_status_set] = 0x00; + } else + ret = dev->regs[dev->index]; + } + + return ret; +} + + +static void +contaq_82c59x_close(void *priv) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)priv; + + smram_del(dev->smram[1]); + smram_del(dev->smram[0]); + + free(dev); +} + + +static void * +contaq_82c59x_init(const device_t *info) +{ + contaq_82c59x_t *dev = (contaq_82c59x_t *)malloc(sizeof(contaq_82c59x_t)); + memset(dev, 0x00, sizeof(contaq_82c59x_t)); + + dev->green = info->local; + + io_sethandler(0x0022, 0x0002, contaq_82c59x_read, NULL, NULL, contaq_82c59x_write, NULL, NULL, dev); + + contaq_82c59x_isa_speed_recalc(dev); + + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + + reset_on_hlt = 0; + + contaq_82c59x_shadow_recalc(dev); + + if (dev->green) { + /* SMRAM 0: Fixed A0000-BFFFF to A0000-BFFFF DRAM. */ + dev->smram[0] = smram_add(); + smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x00020000, 0, 1); + + /* SMRAM 1: Optional. */ + dev->smram[1] = smram_add(); + contaq_82c59x_smram_recalc(dev); + } + + return dev; +} + +const device_t contaq_82c596a_device = { + .name = "Contaq 82C596A", + .internal_name = "contaq_82c596a", + .flags = 0, + .local = 0, + .init = contaq_82c59x_init, + .close = contaq_82c59x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t contaq_82c597_device = { + .name = "Contaq 82C597", + .internal_name = "contaq_82c597", + .flags = 0, + .local = 1, + .init = contaq_82c59x_init, + .close = contaq_82c59x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/cs4031.c b/src/chipset/cs4031.c new file mode 100644 index 000000000..d5970b048 --- /dev/null +++ b/src/chipset/cs4031.c @@ -0,0 +1,190 @@ +/* + * 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 CS4031 chipset. + * + * + * + * Authors: Tiseno100 + * + * Copyright 2021 Tiseno100 + * + */ + +#include +#include +#include +#include +#include +#include +#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/port_92.h> +#include <86box/chipset.h> + +typedef struct +{ + uint8_t index, + regs[256]; + port_92_t *port_92; +} cs4031_t; + +#ifdef ENABLE_CS4031_LOG +int cs4031_do_log = ENABLE_CS4031_LOG; +static void +cs4031_log(const char *fmt, ...) +{ + va_list ap; + + if (cs4031_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cs4031_log(fmt, ...) +#endif + +static void cs4031_shadow_recalc(cs4031_t *dev) +{ + mem_set_mem_state_both(0xa0000, 0x10000, (dev->regs[0x18] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0xb0000, 0x10000, (dev->regs[0x18] & 0x02) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + + for (uint32_t i = 0; i < 7; i++) + { + if (i < 4) + mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, ((dev->regs[0x19] & (1 << i)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x1a] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + else + mem_set_mem_state_both(0xd0000 + ((i - 4) << 16), 0x10000, ((dev->regs[0x19] & (1 << i)) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x1a] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + } + shadowbios = !!(dev->regs[0x19] & 0x40); + shadowbios_write = !!(dev->regs[0x1a] & 0x40); +} + +static void +cs4031_write(uint16_t addr, uint8_t val, void *priv) +{ + cs4031_t *dev = (cs4031_t *)priv; + + switch (addr) + { + case 0x22: + dev->index = val; + break; + case 0x23: + cs4031_log("CS4031: dev->regs[%02x] = %02x\n", dev->index, val); + switch (dev->index) + { + case 0x05: + dev->regs[dev->index] = val & 0x3f; + break; + + case 0x06: + dev->regs[dev->index] = val & 0xbc; + break; + + case 0x07: + dev->regs[dev->index] = val & 0x0f; + break; + + case 0x10: + dev->regs[dev->index] = val & 0x3d; + break; + + case 0x11: + dev->regs[dev->index] = val & 0x8d; + break; + + case 0x12: + case 0x13: + dev->regs[dev->index] = val & 0x8d; + break; + + case 0x14: + case 0x15: + case 0x16: + case 0x17: + dev->regs[dev->index] = val & 0x7f; + break; + + case 0x18: + dev->regs[dev->index] = val & 0xf3; + cs4031_shadow_recalc(dev); + break; + + case 0x19: + case 0x1a: + dev->regs[dev->index] = val & 0x7f; + cs4031_shadow_recalc(dev); + break; + + case 0x1b: + dev->regs[dev->index] = val; + break; + + case 0x1c: + dev->regs[dev->index] = val & 0xb3; + port_92_set_features(dev->port_92, val & 0x10, val & 0x20); + break; + } + break; + } +} + +static uint8_t +cs4031_read(uint16_t addr, void *priv) +{ + cs4031_t *dev = (cs4031_t *)priv; + + return (addr == 0x23) ? dev->regs[dev->index] : 0xff; +} + +static void +cs4031_close(void *priv) +{ + cs4031_t *dev = (cs4031_t *)priv; + + free(dev); +} + +static void * +cs4031_init(const device_t *info) +{ + cs4031_t *dev = (cs4031_t *)malloc(sizeof(cs4031_t)); + memset(dev, 0, sizeof(cs4031_t)); + + dev->port_92 = device_add(&port_92_device); + + dev->regs[0x05] = 0x05; + dev->regs[0x1b] = 0x60; + + io_sethandler(0x0022, 0x0002, cs4031_read, NULL, NULL, cs4031_write, NULL, NULL, dev); + + return dev; +} + +const device_t cs4031_device = { + .name = "Chips & Technogies CS4031", + .internal_name = "cs4031", + .flags = 0, + .local = 0, + .init = cs4031_init, + .close = cs4031_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/cs8230.c b/src/chipset/cs8230.c index a0f64d55c..f6a77cabc 100644 --- a/src/chipset/cs8230.c +++ b/src/chipset/cs8230.c @@ -32,129 +32,140 @@ typedef struct { - int idx; - uint8_t regs[256]; + int idx; + uint8_t regs[256]; } cs8230_t; + static void shadow_control(uint32_t addr, uint32_t size, int state) { - switch (state) { - case 0x00: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 0x01: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 0x10: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 0x11: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - } - flushmmucache_nopc(); + switch (state) { + case 0x00: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x01: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 0x10: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 0x11: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + } + + flushmmucache_nopc(); } static void rethink_shadow_mappings(cs8230_t *cs8230) { - int c; + int c; - for (c = 0; c < 4*8; c++) { /*Addresses 40000-bffff in 16k blocks*/ - if (cs8230->regs[0xa + (c >> 3)] & (1 << (c & 7))) - mem_set_mem_state(0x40000 + c*0x4000, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); /*IO channel*/ - else - mem_set_mem_state(0x40000 + c*0x4000, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); /*System board*/ - } - for (c = 0; c < 2*8; c++) { /*Addresses c0000-fffff in 16k blocks. System board ROM can be mapped here*/ - if (cs8230->regs[0xe + (c >> 3)] & (1 << (c & 7))) - mem_set_mem_state(0xc0000 + c*0x4000, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); /*IO channel*/ - else - shadow_control(0xc0000 + c*0x4000, 0x4000, (cs8230->regs[9] >> (3-(c >> 2))) & 0x11); - } + for (c = 0; c < 32; c++) { + /* Addresses 40000-bffff in 16k blocks */ + if (cs8230->regs[0xa + (c >> 3)] & (1 << (c & 7))) + mem_set_mem_state(0x40000 + (c << 14), 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); /* I/O channel */ + else + mem_set_mem_state(0x40000 + (c << 14), 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); /* System board */ + } + + for (c = 0; c < 16; c++) { + /* Addresses c0000-fffff in 16k blocks. System board ROM can be mapped here */ + if (cs8230->regs[0xe + (c >> 3)] & (1 << (c & 7))) + mem_set_mem_state(0xc0000 + (c << 14), 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); /* I/O channel */ + else + shadow_control(0xc0000 + (c << 14), 0x4000, (cs8230->regs[9] >> (3 - (c >> 2))) & 0x11); + } } + static uint8_t cs8230_read(uint16_t port, void *p) { - cs8230_t *cs8230 = (cs8230_t *)p; - uint8_t ret = 0xff; + cs8230_t *cs8230 = (cs8230_t *) p; + uint8_t ret = 0xff; - if (port & 1) { - switch (cs8230->idx) { - case 0x04: /*82C301 ID/version*/ - ret = cs8230->regs[cs8230->idx] & ~0xe3; - break; + if (port & 1) { + switch (cs8230->idx) { + case 0x04: /* 82C301 ID/version */ + ret = cs8230->regs[cs8230->idx] & ~0xe3; + break; - case 0x08: /*82C302 ID/Version*/ - ret = cs8230->regs[cs8230->idx] & ~0xe0; - break; - - case 0x05: case 0x06: /*82C301 registers*/ - case 0x09: case 0x0a: case 0x0b: case 0x0c: /*82C302 registers*/ - case 0x0d: case 0x0e: case 0x0f: - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x28: case 0x29: case 0x2a: - ret = cs8230->regs[cs8230->idx]; - break; - } + case 0x08: /* 82C302 ID/Version */ + ret = cs8230->regs[cs8230->idx] & ~0xe0; + break; + + case 0x05: case 0x06: /* 82C301 registers */ + case 0x09: case 0x0a: case 0x0b: case 0x0c: /* 82C302 registers */ + case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x28: case 0x29: case 0x2a: + ret = cs8230->regs[cs8230->idx]; + break; } + } - return ret; + return ret; } + static void cs8230_write(uint16_t port, uint8_t val, void *p) { - cs8230_t *cs8230 = (cs8230_t *)p; - - if (!(port & 1)) - cs8230->idx = val; - else { - cs8230->regs[cs8230->idx] = val; - switch (cs8230->idx) { - case 0x09: /*RAM/ROM Configuration in boot area*/ - case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /*Address maps*/ - rethink_shadow_mappings(cs8230); - break; - } + cs8230_t *cs8230 = (cs8230_t *)p; + + if (!(port & 1)) + cs8230->idx = val; + else { + cs8230->regs[cs8230->idx] = val; + switch (cs8230->idx) { + case 0x09: /* RAM/ROM Configuration in boot area */ + case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* Address maps */ + rethink_shadow_mappings(cs8230); + break; } + } } + static void cs8230_close(void *priv) { - cs8230_t *cs8230 = (cs8230_t *)priv; - - free(cs8230); + cs8230_t *cs8230 = (cs8230_t *)priv; + + free(cs8230); } + static void *cs8230_init(const device_t *info) { - cs8230_t *cs8230 = (cs8230_t *)malloc(sizeof(cs8230_t)); - memset(cs8230, 0, sizeof(cs8230_t)); + cs8230_t *cs8230 = (cs8230_t *)malloc(sizeof(cs8230_t)); + memset(cs8230, 0, sizeof(cs8230_t)); - io_sethandler(0x0022, 0x0002, - cs8230_read, NULL, NULL, - cs8230_write, NULL, NULL, - cs8230); + io_sethandler(0x0022, 0x0002, cs8230_read, NULL, NULL, cs8230_write, NULL, NULL, cs8230); - if (mem_size > 768) { - mem_mapping_set_addr(&ram_mid_mapping, 0xa0000, mem_size > 1024 ? 0x60000 : 0x20000 + (mem_size - 768) * 1024); - mem_mapping_set_exec(&ram_mid_mapping, ram + 0xa0000); - } + if (mem_size > 768) { + mem_mapping_set_addr(&ram_mid_mapping, 0xa0000, mem_size > 1024 ? 0x60000 : 0x20000 + (mem_size - 768) * 1024); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0xa0000); + } - return cs8230; + return cs8230; } const device_t cs8230_device = { - "C&T CS8230 (386/AT)", - 0, - 0, - cs8230_init, cs8230_close, NULL, - NULL, NULL, NULL, - NULL -}; \ No newline at end of file + .name = "C&T CS8230 (386/AT)", + .internal_name = "cs8230", + .flags = 0, + .local = 0, + .init = cs8230_init, + .close = cs8230_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/et6000.c b/src/chipset/et6000.c new file mode 100644 index 000000000..1d7541c7e --- /dev/null +++ b/src/chipset/et6000.c @@ -0,0 +1,163 @@ +/* + * 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 ETEQ Cheetah ET6000 chipset. + * + * Authors: Tiseno100 + * + * Copyright 2021 Tiseno100 + * + */ + +#include +#include +#include +#include +#include +#include +#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/pit.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + +#define INDEX (dev->index - 0x10) + +typedef struct +{ + uint8_t index, regs[6]; +} et6000_t; + +#ifdef ENABLE_ET6000_LOG +int et6000_do_log = ENABLE_ET6000_LOG; +static void +et6000_log(const char *fmt, ...) +{ + va_list ap; + + if (et6000_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define et6000_log(fmt, ...) +#endif + +static void et6000_shadow_control(int base, int size, int can_read, int can_write) +{ + mem_set_mem_state_both(base, size, (can_read ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | (can_write ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + flushmmucache_nopc(); +} + +static void +et6000_write(uint16_t addr, uint8_t val, void *priv) +{ + et6000_t *dev = (et6000_t *)priv; + + switch (addr) + { + case 0x22: + dev->index = val; + break; + case 0x23: + switch (INDEX) + { + case 0: /* System Configuration Register */ + dev->regs[INDEX] = val & 0xdf; + et6000_shadow_control(0xa0000, 0x20000, val & 1, val & 1); + refresh_at_enable = !(val & 0x10); + break; + + case 1: /* CACHE Configuration and Non-Cacheable Block Size */ + dev->regs[INDEX] = val & 0xf0; + break; + + case 2: /* Non-Cacheable Block Address Register */ + dev->regs[INDEX] = val & 0xfe; + break; + + case 3: /* DRAM Bank and Type Configuration Register */ + dev->regs[INDEX] = val; + break; + + case 4: /* DRAM Configuration Register */ + dev->regs[INDEX] = val; + et6000_shadow_control(0xc0000, 0x10000, (dev->regs[0x15] & 2) && (val & 0x20), (dev->regs[0x15] & 2) && (val & 0x20) && (dev->regs[0x15] & 1)); + et6000_shadow_control(0xd0000, 0x10000, (dev->regs[0x15] & 8) && (val & 0x20), (dev->regs[0x15] & 8) && (val & 0x20) && (dev->regs[0x15] & 4)); + break; + + case 5: /* Shadow RAM Configuration Register */ + dev->regs[INDEX] = val; + et6000_shadow_control(0xc0000, 0x10000, (val & 2) && (dev->regs[0x14] & 0x20), (val & 2) && (dev->regs[0x14] & 0x20) && (val & 1)); + et6000_shadow_control(0xd0000, 0x10000, (val & 8) && (dev->regs[0x14] & 0x20), (val & 8) && (dev->regs[0x14] & 0x20) && (val & 4)); + et6000_shadow_control(0xe0000, 0x10000, val & 0x20, (val & 0x20) && (val & 0x10)); + et6000_shadow_control(0xf0000, 0x10000, val & 0x40, !(val & 0x40)); + break; + } + et6000_log("ET6000: dev->regs[%02x] = %02x\n", dev->index, dev->regs[dev->index]); + break; + } +} + +static uint8_t +et6000_read(uint16_t addr, void *priv) +{ + et6000_t *dev = (et6000_t *)priv; + + return ((addr == 0x23) && (INDEX >= 0) && (INDEX <= 5)) ? dev->regs[INDEX] : 0xff; +} + +static void +et6000_close(void *priv) +{ + et6000_t *dev = (et6000_t *)priv; + + free(dev); +} + +static void * +et6000_init(const device_t *info) +{ + et6000_t *dev = (et6000_t *)malloc(sizeof(et6000_t)); + memset(dev, 0, sizeof(et6000_t)); + + /* Port 92h */ + device_add(&port_92_device); + + /* Defaults */ + dev->regs[3] = 1; + + /* Shadow Programming */ + et6000_shadow_control(0xf0000, 0x10000, 0, 1); + + io_sethandler(0x0022, 2, et6000_read, NULL, NULL, et6000_write, NULL, NULL, dev); /* Ports 22h-23h: ETEQ Cheetah ET6000 */ + + return dev; +} + +const device_t et6000_device = { + .name = "ETEQ Cheetah ET6000", + .internal_name = "et6000", + .flags = 0, + .local = 0, + .init = et6000_init, + .close = et6000_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/gc100.c b/src/chipset/gc100.c new file mode 100644 index 000000000..09df87856 --- /dev/null +++ b/src/chipset/gc100.c @@ -0,0 +1,259 @@ +/* + * 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 G2 GC100/GC100A chipset. + * NOTE: As documentation is currently available only for the + * CG100 chipset, the GC100A chipset has been reverese-engineered. + * Thus, its behavior may not be fully accurate. + * + * Authors: EngiNerd, + * + * Copyright 2020-2021 EngiNerd. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/nmi.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/hdc.h> +#include <86box/gameport.h> +#include <86box/ibm_5161.h> +#include <86box/keyboard.h> +#include <86box/rom.h> +#include <86box/machine.h> +#include <86box/chipset.h> +#include <86box/io.h> +#include <86box/video.h> + + +typedef struct +{ + uint8_t reg[0x10]; +} gc100_t; + + +#ifdef ENABLE_GC100_LOG +int gc100_do_log = ENABLE_GC100_LOG; + +static void +gc100_log(const char *fmt, ...) +{ + va_list ap; + + if (gc100_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define gc100_log(fmt, ...) +#endif + + +static uint8_t +get_fdd_switch_settings(void) +{ + int i, fdd_count = 0; + + for (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 +gc100_write(uint16_t port, uint8_t val, void *priv) +{ + gc100_t *dev = (gc100_t *) priv; + uint16_t addr = port & 0xf; + + dev->reg[addr] = val; + + switch (addr) { + /* addr 0x2 + * bits 5-7: not used + * bit 4: intenal memory wait states + * bits 2-3: external memory wait states + * bits 0-1: i/o access wait states + */ + case 2: + break; + + /* addr 0x3 + * bits 1-7: not used + * bit 0: turbo 0 xt 1 + */ + case 3: + if (val & 1) + cpu_dynamic_switch(0); + else + cpu_dynamic_switch(cpu); + break; + + /* addr 0x5 + * programmable dip-switches + * bits 6-7: floppy drive number + * bits 4-5: video mode + * bits 2-3: memory size + * bit 1: fpu + * bit 0: not used + */ + + /* addr 0x6 */ + + /* addr 0x7 */ + } + + gc100_log("GC100: Write %02x at %02x\n", val, port); +} + + +static uint8_t +gc100_read(uint16_t port, void *priv) +{ + gc100_t *dev = (gc100_t *) priv; + uint8_t ret = 0xff; + uint16_t addr = port & 0xf; + + ret = dev->reg[addr]; + + gc100_log("GC100: Read %02x at %02x\n", ret, port); + + switch (addr) { + /* addr 0x2 + * bits 5-7: not used + * bit 4: intenal memory wait states + * bits 2-3: external memory wait states + * bits 0-1: i/o access wait states + */ + case 0x2: + break; + + /* addr 0x3 + * bits 1-7: not used + * bit 0: turbo 0 xt 1 + */ + case 0x3: + break; + + /* addr 0x5 + * programmable dip-switches + * bits 6-7: floppy drive number + * bits 4-5: video mode + * bits 2-3: memory size + * bit 1: fpu + * bit 0: not used + */ + case 0x5: + ret = ret & 0x0c; + ret |= get_fdd_switch_settings(); + ret |= get_videomode_switch_settings(); + if (hasfpu) + ret |= 0x02; + break; + + /* addr 0x6 */ + + /* addr 0x7 */ + } + + return ret; +} + + +static void +gc100_close(void *priv) +{ + gc100_t *dev = (gc100_t *) priv; + + free(dev); +} + + +static void * +gc100_init(const device_t *info) +{ + gc100_t *dev = (gc100_t *) malloc(sizeof(gc100_t)); + memset(dev, 0, sizeof(gc100_t)); + + dev->reg[0x2] = 0xff; + dev->reg[0x3] = 0x0; + dev->reg[0x5] = 0x0; + dev->reg[0x6] = 0x0; + dev->reg[0x7] = 0x0; + + if (info->local) { + /* GC100A */ + io_sethandler(0x0c2, 0x02, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); + io_sethandler(0x0c5, 0x03, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); + } else { + /* GC100 */ + io_sethandler(0x022, 0x02, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); + io_sethandler(0x025, 0x01, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); + } + + return dev; +} + +const device_t gc100_device = { + .name = "G2 GC100", + .internal_name = "gc100", + .flags = 0, + .local = 0, + .init = gc100_init, + .close = gc100_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gc100a_device = { + .name = "G2 GC100A", + .internal_name = "gc100a", + .flags = 0, + .local = 1, + .init = gc100_init, + .close = gc100_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 5d20e1fa4..ed2e318fc 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -31,9 +31,7 @@ #include <86box/timer.h> #include <86box/io.h> #include <86box/mem.h> -#include <86box/rom.h> #include <86box/device.h> -#include <86box/keyboard.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/port_92.h> @@ -41,18 +39,19 @@ typedef struct { - uint8_t valid, pad; + uint8_t valid, enabled; uint16_t mr; + uint32_t virt_base; struct headland_t * headland; } headland_mr_t; typedef struct headland_t { - uint8_t type; + uint8_t revision; uint8_t cri; - uint8_t cr[8]; + uint8_t cr[7]; uint8_t indx; uint8_t regs[256]; @@ -62,12 +61,11 @@ typedef struct headland_t { headland_mr_t null_mr, ems_mr[64]; - rom_t vid_bios; - mem_mapping_t low_mapping; mem_mapping_t ems_mapping[64]; mem_mapping_t mid_mapping; mem_mapping_t high_mapping; + mem_mapping_t shadow_mapping[2]; mem_mapping_t upper_mapping[24]; } headland_t; @@ -95,38 +93,51 @@ static const int mem_conf_cr1[41] = { static uint32_t get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) { + uint32_t bank_base[4], bank_shift[4], shift, other_shift, bank; + + if ((addr >= 0x0e0000) && (addr <= 0x0fffff)) + return addr; + else if ((addr >= 0xfe0000) && (addr <= 0xffffff)) + return addr & 0x0fffff; + + if (dev->revision == 8) { + shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[6] & 0x01) ? 23 : 19); + other_shift = (dev->cr[0] & 0x80) ? ((dev->cr[6] & 0x01) ? 19 : 23) : 21; + } else { + shift = (dev->cr[0] & 0x80) ? 21 : 19; + other_shift = (dev->cr[0] & 0x80) ? 21 : 19; + } + + /* Bank size = 1 << (bank shift + 2) . */ + bank_shift[0] = bank_shift[1] = shift; + + bank_base[0] = 0x00000000; + bank_base[1] = bank_base[0] + (1 << shift); + bank_base[2] = bank_base[1] + (1 << shift); + + if ((dev->revision > 0) && (dev->revision < 8) && (dev->cr[1] & 0x40)) { + bank_shift[2] = bank_shift[3] = other_shift; + bank_base[3] = bank_base[2] + (1 << other_shift); + /* First address after the memory is bank_base[3] + (1 << other_shift) */ + } else { + bank_shift[2] = bank_shift[3] = shift; + bank_base[3] = bank_base[2] + (1 << shift); + /* First address after the memory is bank_base[3] + (1 << shift) */ + } + if (mr && mr->valid && (dev->cr[0] & 2) && (mr->mr & 0x200)) { addr = (addr & 0x3fff) | ((mr->mr & 0x1F) << 14); - if (dev->cr[1] & 0x40) { - if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) { - if (dev->cr[0] & 0x80) { - addr |= (mr->mr & 0x60) << 14; - if (mr->mr & 0x100) - addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x80) << 15); - else - addr += (mr->mr & 0x80) << 14; - } else if (mr->mr & 0x100) - addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x20) << 15); - else - addr += (mr->mr & 0x80) << 12; - } else if (dev->cr[0] & 0x80) - addr |= (mr->mr & 0x100) ? ((mr->mr & 0x80) + 0x400) << 12 : (mr->mr & 0xE0) << 14; - else - addr |= (mr->mr & 0x100) ? ((mr->mr & 0xE0) + 0x40) << 14 : (mr->mr & 0x80) << 12; - } else { - if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) { - if (dev->cr[0] & 0x80) { - addr |= ((mr->mr & 0x60) << 14); - if (mr->mr & 0x180) - addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x180) - 0x60) << 16); - } else - addr |= ((mr->mr & 0x60) << 14) | ((mr->mr & 0x180) << 16) | ((mr->mr & 0xC00) << 13); - } else if (dev->cr[0] & 0x80) - addr |= (mr->mr & 0x1E0) << 14; - else - addr |= (mr->mr & 0x180) << 12; - } - } else if ((mr == NULL) && ((dev->cr[0] & 4) == 0) && (mem_size >= 1024) && (addr >= 0x100000)) + + bank = (mr->mr >> 7) & 3; + + if (bank_shift[bank] >= 21) + addr |= (mr->mr & 0x060) << 14; + + if ((dev->revision == 8) && (bank_shift[bank] == 23)) + addr |= (mr->mr & 0xc00) << 11; + + addr |= bank_base[(mr->mr >> 7) & 3]; + } else if (((mr == NULL) || !mr->valid) && (mem_size >= 1024) && (addr >= 0x100000) && ((dev->cr[0] & 4) == 0)) addr -= 0x60000; return addr; @@ -134,68 +145,174 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) static void -set_global_EMS_state(headland_t *dev, int state) +hl_ems_disable(headland_t *dev, uint8_t mar, uint32_t base_addr, uint8_t indx) +{ + if (base_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[mar & 0x3f], ram + base_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[mar & 0x3f], NULL); + mem_mapping_disable(&dev->ems_mapping[mar & 0x3f]); + if (indx < 24) { + mem_set_mem_state(base_addr, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_enable(&dev->upper_mapping[indx]); + } else + mem_set_mem_state(base_addr, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); +} + + +static void +hl_ems_update(headland_t *dev, uint8_t mar) { uint32_t base_addr, virt_addr; - int i; + uint8_t indx = mar & 0x1f; - for (i = 0; i < 32; i++) { - base_addr = (i + 16) << 14; - if (i >= 24) - base_addr += 0x20000; - if ((state & 2) && (dev->ems_mr[((state & 1) << 5) | i].mr & 0x200)) { - virt_addr = get_addr(dev, base_addr, &dev->ems_mr[((state & 1) << 5) | i]); - if (i < 24) - mem_mapping_disable(&dev->upper_mapping[i]); - mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]); - mem_mapping_enable(&dev->ems_mapping[((state & 1) << 5) | i]); - if (virt_addr < ((uint32_t)mem_size << 10)) - mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + virt_addr); - else - mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], NULL); - } else { - mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + base_addr); - mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]); - mem_mapping_disable(&dev->ems_mapping[((state & 1) << 5) | i]); - if (i < 24) - mem_mapping_enable(&dev->upper_mapping[i]); - } + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x20000; + hl_ems_disable(dev, mar, base_addr, indx); + dev->ems_mr[mar & 0x3f].enabled = 0; + dev->ems_mr[mar & 0x3f].virt_base = base_addr; + if ((dev->cr[0] & 2) && ((dev->cr[0] & 1) == ((mar & 0x20) >> 5)) && (dev->ems_mr[mar & 0x3f].mr & 0x200)) { + mem_set_mem_state(base_addr, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[mar & 0x3f]); + dev->ems_mr[mar & 0x3f].enabled = 1; + dev->ems_mr[mar & 0x3f].virt_base = virt_addr; + if (indx < 24) + mem_mapping_disable(&dev->upper_mapping[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[mar & 0x3f], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[mar & 0x3f], NULL); + mem_mapping_enable(&dev->ems_mapping[mar & 0x3f]); } flushmmucache(); } +static void +set_global_EMS_state(headland_t *dev, int state) +{ + int i; + + for (i = 0; i < 32; i++) { + hl_ems_update(dev, i | (((dev->cr[0] & 0x01) << 5) ^ 0x20)); + hl_ems_update(dev, i | ((dev->cr[0] & 0x01) << 5)); + } +} + + +static void +memmap_state_default(headland_t *dev, uint8_t ht_romcs) +{ + mem_mapping_disable(&dev->mid_mapping); + + if (ht_romcs) + mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); + else + mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); + + mem_mapping_disable(&dev->shadow_mapping[0]); + mem_mapping_disable(&dev->shadow_mapping[1]); +} + + static void memmap_state_update(headland_t *dev) { uint32_t addr; int i; + uint8_t ht_cr0 = dev->cr[0]; + uint8_t ht_romcs = !(dev->cr[4] & 0x01); + if (dev->revision <= 1) + ht_romcs = 1; + if (!(dev->cr[0] & 0x04)) + ht_cr0 &= ~0x18; for (i = 0; i < 24; i++) { addr = get_addr(dev, 0x40000 + (i << 14), NULL); mem_mapping_set_exec(&dev->upper_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); } - mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + memmap_state_default(dev, ht_romcs); + if (mem_size > 640) { - if ((dev->cr[0] & 4) == 0) { - mem_mapping_set_addr(&dev->mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + if (ht_cr0 & 0x04) { + mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, 0x40000); mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); + mem_mapping_disable(&dev->mid_mapping); if (mem_size > 1024) { - mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); } } else { - mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + /* 1 MB - 1 MB + 384k: RAM pointing to A0000-FFFFF + 1 MB + 384k: Any ram pointing 1 MB onwards. */ + /* First, do the addresses above 1 MB. */ + mem_mapping_set_addr(&dev->mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); if (mem_size > 1024) { - mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); + /* We have ram above 1 MB, we need to relocate that. */ + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); } } } - set_global_EMS_state(dev, dev->cr[0] & 3); + switch (ht_cr0) { + case 0x18: + if ((mem_size << 10) > 0xe0000) { + mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + mem_mapping_set_addr(&dev->shadow_mapping[0], 0x0e0000, 0x20000); + mem_mapping_set_exec(&dev->shadow_mapping[0], ram + 0xe0000); + mem_mapping_set_addr(&dev->shadow_mapping[1], 0xfe0000, 0x20000); + mem_mapping_set_exec(&dev->shadow_mapping[1], ram + 0xe0000); + } else { + mem_mapping_disable(&dev->shadow_mapping[0]); + mem_mapping_disable(&dev->shadow_mapping[1]); + } + break; + case 0x10: + if ((mem_size << 10) > 0xf0000) { + mem_set_mem_state(0x0f0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + mem_set_mem_state(0xff0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + mem_mapping_set_addr(&dev->shadow_mapping[0], 0x0f0000, 0x10000); + mem_mapping_set_exec(&dev->shadow_mapping[0], ram + 0xf0000); + mem_mapping_set_addr(&dev->shadow_mapping[1], 0xff0000, 0x10000); + mem_mapping_set_exec(&dev->shadow_mapping[1], ram + 0xf0000); + } else { + mem_mapping_disable(&dev->shadow_mapping[0]); + mem_mapping_disable(&dev->shadow_mapping[1]); + } + break; + case 0x08: + if ((mem_size << 10) > 0xe0000) { + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + mem_set_mem_state(0xfe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + mem_mapping_set_addr(&dev->shadow_mapping[0], 0x0e0000, 0x10000); + mem_mapping_set_exec(&dev->shadow_mapping[0], ram + 0xe0000); + mem_mapping_set_addr(&dev->shadow_mapping[1], 0xfe0000, 0x10000); + mem_mapping_set_exec(&dev->shadow_mapping[1], ram + 0xe0000); + } else { + mem_mapping_disable(&dev->shadow_mapping[0]); + mem_mapping_disable(&dev->shadow_mapping[1]); + } + break; + case 0x00: + default: + mem_mapping_disable(&dev->shadow_mapping[0]); + mem_mapping_disable(&dev->shadow_mapping[1]); + break; + } + + set_global_EMS_state(dev, ht_cr0 & 3); } @@ -203,55 +320,18 @@ static void hl_write(uint16_t addr, uint8_t val, void *priv) { headland_t *dev = (headland_t *)priv; - uint32_t base_addr, virt_addr; - uint8_t old_val, indx; switch(addr) { - case 0x0022: - dev->indx = val; - break; - - case 0x0023: - old_val = dev->regs[dev->indx]; - if ((dev->indx == 0xc1) && !is486) - val = 0; - dev->regs[dev->indx] = val; - if (dev->indx == 0x82) { - shadowbios = val & 0x10; - shadowbios_write = !(val & 0x10); - if (shadowbios) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - } else if (dev->indx == 0x87) { - if ((val & 1) && !(old_val & 1)) - softresetx86(); - } - break; - case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00; - indx = dev->ems_mar & 0x1f; - base_addr = (indx + 16) << 14; - if (indx >= 24) - base_addr += 0x20000; - if ((dev->cr[0] & 2) && ((dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5))) { - virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3F]); - if (indx < 24) - mem_mapping_disable(&dev->upper_mapping[indx]); - if (virt_addr < ((uint32_t)mem_size << 10)) - mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr); - else - mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL); - mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]); - flushmmucache(); - } + hl_ems_update(dev, dev->ems_mar & 0x3f); if (dev->ems_mar & 0x80) dev->ems_mar++; break; case 0x01ed: - dev->cri = val; + if (dev->revision > 0) + dev->cri = val; break; case 0x01ee: @@ -259,12 +339,9 @@ hl_write(uint16_t addr, uint8_t val, void *priv) break; case 0x01ef: - old_val = dev->cr[dev->cri]; switch(dev->cri) { case 0: dev->cr[0] = (val & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; - mem_set_mem_state(0xe0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | MEM_WRITE_DISABLED); - mem_set_mem_state(0xf0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTANY) | MEM_WRITE_DISABLED); memmap_state_update(dev); break; @@ -282,17 +359,11 @@ hl_write(uint16_t addr, uint8_t val, void *priv) case 4: dev->cr[4] = (dev->cr[4] & 0xf0) | (val & 0x0f); - if (val & 1) { - mem_mapping_set_addr(&bios_mapping, 0x000f0000, 0x10000); - mem_mapping_set_exec(&bios_mapping, &(rom[0x10000])); - } else { - mem_mapping_set_addr(&bios_mapping, 0x000e0000, 0x20000); - mem_mapping_set_exec(&bios_mapping, rom); - } + memmap_state_update(dev); break; case 6: - if (dev->cr[4] & 0x80) { + if (dev->revision == 8) { dev->cr[dev->cri] = (val & 0xfe) | (mem_size > 8192 ? 1 : 0); memmap_state_update(dev); } @@ -313,34 +384,11 @@ static void hl_writew(uint16_t addr, uint16_t val, void *priv) { headland_t *dev = (headland_t *)priv; - uint32_t base_addr, virt_addr; - uint8_t indx; switch(addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val; - indx = dev->ems_mar & 0x1f; - base_addr = (indx + 16) << 14; - if (indx >= 24) - base_addr += 0x20000; - if ((dev->cr[0] & 2) && (dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5)) { - if (val & 0x200) { - virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3f]); - if (indx < 24) - mem_mapping_disable(&dev->upper_mapping[indx]); - if (virt_addr < ((uint32_t)mem_size << 10)) - mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr); - else - mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL); - mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]); - } else { - mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + base_addr); - mem_mapping_disable(&dev->ems_mapping[dev->ems_mar & 0x3f]); - if (indx < 24) - mem_mapping_enable(&dev->upper_mapping[indx]); - } - flushmmucache(); - } + hl_ems_update(dev, dev->ems_mar & 0x3f); if (dev->ems_mar & 0x80) dev->ems_mar++; break; @@ -351,6 +399,14 @@ hl_writew(uint16_t addr, uint16_t val, void *priv) } +static void +hl_writel(uint16_t addr, uint32_t val, void *priv) +{ + hl_writew(addr, val, priv); + hl_writew(addr + 2, val >> 16, priv); +} + + static uint8_t hl_read(uint16_t addr, void *priv) { @@ -358,17 +414,6 @@ hl_read(uint16_t addr, void *priv) uint8_t ret = 0xff; switch(addr) { - case 0x0022: - ret = dev->indx; - break; - - case 0x0023: - if ((dev->indx >= 0xc0 || dev->indx == 0x20) && cpu_iscyrix) - ret = 0xff; /*Don't conflict with Cyrix config registers*/ - else - ret = dev->regs[dev->indx]; - break; - case 0x01ec: ret = (uint8_t)dev->ems_mr[dev->ems_mar & 0x3f].mr; if (dev->ems_mar & 0x80) @@ -376,7 +421,8 @@ hl_read(uint16_t addr, void *priv) break; case 0x01ed: - ret = dev->cri; + if (dev->revision > 0) + ret = dev->cri; break; case 0x01ee: @@ -394,7 +440,7 @@ hl_read(uint16_t addr, void *priv) break; case 6: - if (dev->cr[4] & 0x80) + if (dev->revision == 8) ret = (dev->cr[6] & 0xfe) | (mem_size > 8192 ? 1 : 0); else ret = 0; @@ -435,6 +481,18 @@ hl_readw(uint16_t addr, void *priv) } +static uint32_t +hl_readl(uint16_t addr, void *priv) +{ + uint32_t ret = 0xffffffff; + + ret = hl_readw(addr, priv); + ret |= (hl_readw(addr + 2, priv) << 16); + + return ret; +} + + static uint8_t mem_read_b(uint32_t addr, void *priv) { @@ -529,34 +587,28 @@ static void * headland_init(const device_t *info) { headland_t *dev; - int ht386; + int ht386 = 0; uint32_t i; dev = (headland_t *) malloc(sizeof(headland_t)); memset(dev, 0x00, sizeof(headland_t)); - dev->type = info->local; - ht386 = (dev->type == 32) ? 1 : 0; + dev->revision = info->local; - for (i = 0; i < 8; i++) - dev->cr[i] = 0x00; - dev->cr[0] = 0x04; + if (dev->revision > 0) + ht386 = 1; - if (ht386) { - dev->cr[4] = 0x20; + dev->cr[4] = dev->revision << 4; + if (ht386) device_add(&port_92_inv_device); - } else - dev->cr[4] = 0x00; - io_sethandler(0x01ec, 1, - hl_read,hl_readw,NULL, hl_write,hl_writew,NULL, dev); + io_sethandler(0x01ec, 4, + hl_read,hl_readw,hl_readl, hl_write,hl_writew,hl_writel, dev); - io_sethandler(0x01ed, 3, hl_read,NULL,NULL, hl_write,NULL,NULL, dev); - - dev->ems_mr[i].valid = 0; - dev->ems_mr[i].mr = 0xff; - dev->ems_mr[i].headland = dev; + dev->null_mr.valid = 0; + dev->null_mr.mr = 0xff; + dev->null_mr.headland = dev; for (i = 0; i < 64; i++) { dev->ems_mr[i].valid = 1; @@ -575,11 +627,11 @@ headland_init(const device_t *info) ram, MEM_MAPPING_INTERNAL, &dev->null_mr); if (mem_size > 640) { - mem_mapping_add(&dev->mid_mapping, 0xa0000, 0x60000, + mem_mapping_add(&dev->mid_mapping, 0xa0000, 0x40000, mem_read_b, mem_read_w, mem_read_l, mem_write_b, mem_write_w, mem_write_l, ram + 0xa0000, MEM_MAPPING_INTERNAL, &dev->null_mr); - mem_mapping_enable(&dev->mid_mapping); + mem_mapping_disable(&dev->mid_mapping); } if (mem_size > 1024) { @@ -595,11 +647,27 @@ headland_init(const device_t *info) 0x40000 + (i << 14), 0x4000, mem_read_b, mem_read_w, mem_read_l, mem_write_b, mem_write_w, mem_write_l, - mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, + mem_size > (256 + (i << 4)) ? (ram + 0x40000 + (i << 14)) : NULL, MEM_MAPPING_INTERNAL, &dev->null_mr); mem_mapping_enable(&dev->upper_mapping[i]); } + mem_mapping_add(&dev->shadow_mapping[0], + 0xe0000, 0x20000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ((mem_size << 10) > 0xe0000) ? (ram + 0xe0000) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_disable(&dev->shadow_mapping[0]); + + mem_mapping_add(&dev->shadow_mapping[1], + 0xfe0000, 0x20000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ((mem_size << 10) > 0xe0000) ? (ram + 0xe0000) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_disable(&dev->shadow_mapping[1]); + for (i = 0; i < 64; i++) { dev->ems_mr[i].mr = 0x00; mem_mapping_add(&dev->ems_mapping[i], @@ -607,7 +675,8 @@ headland_init(const device_t *info) mem_read_b, mem_read_w, mem_read_l, mem_write_b, mem_write_w, mem_write_l, ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), - 0, &dev->ems_mr[i]); + MEM_MAPPING_INTERNAL, &dev->ems_mr[i]); + mem_mapping_disable(&dev->ems_mapping[i]); } memmap_state_update(dev); @@ -615,21 +684,58 @@ headland_init(const device_t *info) return(dev); } - -const device_t headland_device = { - "Headland 286", - 0, - 0, - headland_init, headland_close, NULL, - NULL, NULL, NULL, - NULL +const device_t headland_gc10x_device = { + .name = "Headland GC101/102/103", + .internal_name = "headland_gc10x", + .flags = 0, + .local = 0, + .init = headland_init, + .close = headland_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t headland_386_device = { - "Headland 386", - 0, - 32, - headland_init, headland_close, NULL, - NULL, NULL, NULL, - NULL +const device_t headland_ht18a_device = { + .name = "Headland HT18 Rev. A", + .internal_name = "headland_ht18a", + .flags = 0, + .local = 1, + .init = headland_init, + .close = headland_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t headland_ht18b_device = { + .name = "Headland HT18 Rev. B", + .internal_name = "headland_ht18b", + .flags = 0, + .local = 2, + .init = headland_init, + .close = headland_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t headland_ht18c_device = { + .name = "Headland HT18 Rev. C", + .internal_name = "headland_ht18c", + .flags = 0, + .local = 8, + .init = headland_init, + .close = headland_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/i82335.c b/src/chipset/i82335.c deleted file mode 100644 index b5594f4da..000000000 --- a/src/chipset/i82335.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Intel 82335 SX emulation, used by the Phoenix 386 clone. */ - -#include -#include -#include -#include -#include <86box/io.h> -#include <86box/mem.h> - -typedef struct -{ - uint8_t reg_22; - uint8_t reg_23; -} i82335_t; - -i82335_t i82335; - -uint8_t i82335_read(uint16_t addr, void *priv); - -void i82335_write(uint16_t addr, uint8_t val, void *priv) -{ - int i = 0; - - int mem_write = 0; - - // pclog("i82335_write(%04X, %02X)\n", addr, val); - - switch (addr) - { - case 0x22: - if ((val ^ i82335.reg_22) & 1) - { - if (val & 1) - { - for (i = 0; i < 8; i++) - { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - shadowbios = 1; - } - } - else - { - for (i = 0; i < 8; i++) - { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - shadowbios = 0; - } - } - - flushmmucache(); - } - - i82335.reg_22 = val | 0xd8; - break; - case 0x23: - i82335.reg_23 = val; - - if ((val ^ i82335.reg_22) & 2) - { - if (val & 2) - { - for (i = 0; i < 8; i++) - { - mem_set_mem_state(0xc0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - shadowbios = 1; - } - } - else - { - for (i = 0; i < 8; i++) - { - mem_set_mem_state(0xc0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - shadowbios = 0; - } - } - } - - if ((val ^ i82335.reg_22) & 0xc) - { - if (val & 2) - { - for (i = 0; i < 8; i++) - { - mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | mem_write); - shadowbios = 1; - } - } - else - { - for (i = 0; i < 8; i++) - { - mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY; - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTANY | mem_write); - shadowbios = 0; - } - } - } - - if ((val ^ i82335.reg_22) & 0xe) - { - flushmmucache(); - } - - if (val & 0x80) - { - io_removehandler(0x0022, 0x0001, i82335_read, NULL, NULL, i82335_write, NULL, NULL, NULL); - } - break; - } -} - -uint8_t i82335_read(uint16_t addr, void *priv) -{ - // pclog("i82335_read(%04X)\n", addr); - if (addr == 0x22) - { - return i82335.reg_22; - } - else if (addr == 0x23) - { - return i82335.reg_23; - } - else - { - return 0; - } -} - -void i82335_init() -{ - memset(&i82335, 0, sizeof(i82335_t)); - - i82335.reg_22 = 0xd8; - - io_sethandler(0x0022, 0x0014, i82335_read, NULL, NULL, i82335_write, NULL, NULL, NULL); -} diff --git a/src/chipset/ims8848.c b/src/chipset/ims8848.c new file mode 100644 index 000000000..35b1ef62b --- /dev/null +++ b/src/chipset/ims8848.c @@ -0,0 +1,415 @@ +/* + * 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 IMS 8848/8849 chipset. + * + * + * + * Authors: Miran Grca, + * Tiseno100, + * + * Copyright 2021 Miran Grca. + * Copyright 2021 Tiseno100. + */ +#include +#include +#include +#include +#include +#include +#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/smram.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + + +/* + IMS 884x Configuration Registers + + Note: IMS 884x are rebadged ATMEL AT 40411/40412 chipsets + + By: Tiseno100, Miran Grca(OBattler) + + Register 00h: + Bit 3: F0000-FFFFF Shadow Enable + Bit 2: E0000-EFFFF Shadow Enable + Bit 0: ???? + + Register 04h: + Bit 3: Cache Write Hit Wait State + Bit 2: Cache Read Hit Wait State + + Register 06h: + Bit 3: System BIOS Cacheable (1: Yes / 0: No) + Bit 1: Power Management Mode (1: IRQ / 0: SMI#) + + Register 08h: + Bit 2: System BIOS Shadow Write (1: Enable / 0: Disable) + Bit 1: System BIOS Shadow Read? + + Register 0Dh: + Bit 0: IO 100H-3FFH Idle Detect (1: Enable / 0: Disable) + + Register 0Eh: + Bit 7: DMA & Local Bus Idle Detect (1: Enable / 0: Disable) + Bit 6: Floppy Disk Idle Detect (1: Enable / 0: Disable) + Bit 5: IDE Idle Detect (1: Enable / 0: Disable) + Bit 4: Serial Port Idle Detect (1: Enable / 0: Disable) + Bit 3: Parallel Port Idle Detect (1: Enable / 0: Disable) + Bit 2: Keyboard Idle Detect (1: Enable / 0: Disable) + Bit 1: Video Idle Detect (1: Enable / 0: Disable) + + Register 12h: + Bits 3-2: Power Saving Timer (00 = 1 MIN, 01 = 3 MIN, 10 = 5 MIN, 11 = 8 MIN) + Bit 1: Base Memory (1: 512KB / 0: 640KB) + + Register 1Ah: + Bit 3: Cache Write Hit W/S For PCI (1: Enabled / 0: Disable) + Bit 2: Cache Read Hit W/S For PCI (1: Enabled / 0: Disable) + Bit 1: VESA Clock Skew (1: 4ns/6ns, 0: No Delay/2ns) + + Register 1Bh: + Bit 6: Enable SMRAM (always at 30000-4FFFF) in SMM + Bit 5: ???? + Bit 4: Software SMI# + Bit 3: DC000-DFFFF Shadow Enable + Bit 2: D8000-DBFFF Shadow Enable + Bit 1: D4000-D7FFF Shadow Enable + Bit 0: D0000-D3FFF Shadow Enable + + Register 1Ch: + Bits 7-4: INTA IRQ routing (0 = disabled, 1 to F = IRQ) + Bit 3: CC000-CFFFF Shadow Enable + Bit 2: C8000-CBFFF Shadow Enable + Bit 1: C4000-C7FFF Shadow Enable + Bit 0: C0000-C3FFF Shadow Enable + + Register 1Dh: + Bits 7-4: INTB IRQ routing (0 = disabled, 1 to F = IRQ) + + Register 1Eh: + Bits 7-4: INTC IRQ routing (0 = disabled, 1 to F = IRQ) + Bit 1: C4000-C7FFF Cacheable + Bit 0: C0000-C3FFF Cacheable + + Register 21h: + Bits 7-4: INTD IRQ routing (0 = disabled, 1 to F = IRQ) + + Register 22h: + Bit 5: Local Bus Master #2 select (0 = VESA, 1 = PCI) + Bit 4: Local Bus Master #1 select (0 = VESA, 1 = PCI) + Bits 1-0: Internal HADS# Delay Always (00 = No Delay, 01 = 1 Clk, 10 = 2 Clks) + + Register 23h: + Bit 7: Seven Bits Tag (1: Enabled / 0: Disable) + Bit 3: Extend LBRDY#(VL Master) (1: Enabled / 0: Disable) + Bit 2: Sync LRDY#(VL Slave) (1: Enabled / 0: Disable) + Bit 0: HADS# Delay After LB. Cycle (1: Enabled / 0: Disable) +*/ + +typedef struct +{ + uint8_t idx, access_data, + regs[256], pci_conf[256]; + + smram_t *smram; +} ims8848_t; + + +#ifdef ENABLE_IMS8848_LOG +int ims8848_do_log = ENABLE_IMS8848_LOG; + + +static void +ims8848_log(const char *fmt, ...) +{ + va_list ap; + + if (ims8848_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ims8848_log(fmt, ...) +#endif + + +/* Shadow write always enabled, 1B and 1C control C000-DFFF read. */ +static void +ims8848_recalc(ims8848_t *dev) +{ + int i, state_on; + uint32_t base; + ims8848_log("SHADOW: 00 = %02X, 08 = %02X, 1B = %02X, 1C = %02X\n", + dev->regs[0x00], dev->regs[0x08], dev->regs[0x1b], dev->regs[0x1c]); + + state_on = MEM_READ_INTERNAL; + state_on |= (dev->regs[0x08] & 0x04) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + + for (i = 0; i < 2; i++) { + base = 0xe0000 + (i << 16); + if (dev->regs[0x00] & (1 << (i + 2))) + mem_set_mem_state_both(base, 0x10000, state_on); + else + mem_set_mem_state_both(base, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + if (dev->regs[0x1c] & (1 << i)) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + + base = 0xd0000 + (i << 14); + if (dev->regs[0x1b] & (1 << i)) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + + flushmmucache_nopc(); +} + + +static void +ims8848_base_memory(ims8848_t *dev) +{ + /* We can use the proper mem_set_access to handle that. */ + mem_set_mem_state_both(0x80000, 0x20000, (dev->regs[0x12] & 2) ? + (MEM_READ_DISABLED | MEM_WRITE_DISABLED) : (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL)); +} + + +static void +ims8848_smram(ims8848_t *dev) +{ + smram_disable_all(); + + smram_enable(dev->smram, 0x00030000, 0x00030000, 0x20000, dev->regs[0x1b] & 0x40, 1); +} + + +static void +ims8848_write(uint16_t addr, uint8_t val, void *priv) +{ + ims8848_t *dev = (ims8848_t *) priv; + uint8_t old = dev->regs[dev->idx]; + + switch (addr) { + case 0x22: + ims8848_log("[W] IDX = %02X\n", val); + dev->idx = val; + break; + case 0x23: + ims8848_log("[W] IDX IN = %02X\n", val); + if (((val & 0x0f) == ((dev->idx >> 4) & 0x0f)) && ((val & 0xf0) == ((dev->idx << 4) & 0xf0))) + dev->access_data = 1; + break; + case 0x24: + ims8848_log("[W] [%i] REG %02X = %02X\n", dev->access_data, dev->idx, val); + if (dev->access_data) { + dev->regs[dev->idx] = val; + switch (dev->idx) { + case 0x00: case 0x08: case 0x1b: case 0x1c: + /* Shadow RAM */ + ims8848_recalc(dev); + if (dev->idx == 0x1b) { + ims8848_smram(dev); + if (!(old & 0x10) && (val & 0x10)) + smi_raise(); + } else if (dev->idx == 0x1c) + pci_set_irq_routing(PCI_INTA, (val >> 4) ? (val >> 4) : PCI_IRQ_DISABLED); + break; + + case 0x1d: case 0x1e: + pci_set_irq_routing(PCI_INTB + (dev->idx - 0x1d), (val >> 4) ? (val >> 4) : PCI_IRQ_DISABLED); + break; + case 0x21: + pci_set_irq_routing(PCI_INTD, (val >> 4) ? (val >> 4) : PCI_IRQ_DISABLED); + break; + + case 0x12: + /* Base Memory */ + ims8848_base_memory(dev); + break; + } + dev->access_data = 0; + } + break; + } +} + + +static uint8_t +ims8848_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + ims8848_t *dev = (ims8848_t *) priv; +#ifdef ENABLE_IMS8848_LOG + uint8_t old_ad = dev->access_data; +#endif + + switch (addr) { + case 0x22: + ims8848_log("[R] IDX = %02X\n", ret); + ret = dev->idx; + break; + case 0x23: + ims8848_log("[R] IDX IN = %02X\n", ret); + ret = (dev->idx >> 4) | (dev->idx << 4); + break; + case 0x24: + if (dev->access_data) { + ret = dev->regs[dev->idx]; + dev->access_data = 0; + } + ims8848_log("[R] [%i] REG %02X = %02X\n", old_ad, dev->idx, ret); + break; + } + + return ret; +} + + +static void +ims8849_pci_write(int func, int addr, uint8_t val, void *priv) +{ + ims8848_t *dev = (ims8848_t *)priv; + + ims8848_log("IMS 884x-PCI: dev->regs[%02x] = %02x POST: %02x\n", addr, val, inb(0x80)); + + if (func == 0) switch (addr) { + case 0x04: + dev->pci_conf[addr] = val; + break; + + case 0x05: + dev->pci_conf[addr] = val & 3; + break; + + case 0x07: + dev->pci_conf[addr] &= val & 0xf7; + break; + + case 0x0c ... 0x0d: + dev->pci_conf[addr] = val; + break; + + case 0x52 ... 0x55: + dev->pci_conf[addr] = val; + break; + } +} + + +static uint8_t +ims8849_pci_read(int func, int addr, void *priv) +{ + ims8848_t *dev = (ims8848_t *)priv; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +ims8848_reset(void *priv) +{ + ims8848_t *dev = (ims8848_t *)priv; + + memset(dev->regs, 0x00, sizeof(dev->regs)); + memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); + + dev->pci_conf[0x00] = 0xe0; /* Integrated Micro Solutions (IMS) */ + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x49; /* 8849 */ + dev->pci_conf[0x03] = 0x88; + + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x07] = 0x02; + + dev->pci_conf[0x0b] = 0x06; + + ims8848_recalc(dev); /* Shadow RAM Setup */ + ims8848_base_memory(dev); /* Base Memory Setup */ + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + ims8848_smram(dev); +} + + +static void +ims8848_close(void *priv) +{ + ims8848_t *dev = (ims8848_t *) priv; + + smram_del(dev->smram); + + free(dev); +} + + +static void * +ims8848_init(const device_t *info) +{ + ims8848_t *dev = (ims8848_t *) malloc(sizeof(ims8848_t)); + memset(dev, 0, sizeof(ims8848_t)); + + device_add(&port_92_device); + + /* IMS 8848: + 22h Index + 23h Data Unlock + 24h Data + + IMS 8849: + PCI Device 0: IMS 8849 Dummy for compatibility reasons + */ + io_sethandler(0x0022, 0x0003, ims8848_read, NULL, NULL, ims8848_write, NULL, NULL, dev); + pci_add_card(PCI_ADD_NORTHBRIDGE, ims8849_pci_read, ims8849_pci_write, dev); + + dev->smram = smram_add(); + smram_set_separate_smram(1); + + cpu_cache_ext_enabled = 1; + cpu_update_waitstates(); + + ims8848_reset(dev); + + return dev; +} + +const device_t ims8848_device = { + .name = "IMS 8848/8849", + .internal_name = "ims8848", + .flags = 0, + .local = 0, + .init = ims8848_init, + .close = ims8848_close, + .reset = ims8848_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/intel_420ex.c b/src/chipset/intel_420ex.c index ca872599d..11c66b833 100644 --- a/src/chipset/intel_420ex.c +++ b/src/chipset/intel_420ex.c @@ -19,11 +19,13 @@ #include #include #include <86box/86box.h> +#include "cpu.h" #include <86box/device.h> #include <86box/io.h> #include <86box/apm.h> #include <86box/dma.h> #include <86box/mem.h> +#include <86box/smram.h> #include <86box/pci.h> #include <86box/timer.h> #include <86box/pit.h> @@ -32,6 +34,7 @@ #include <86box/hdc.h> #include <86box/machine.h> #include <86box/chipset.h> +#include <86box/spd.h> #define MEM_STATE_SHADOW_R 0x01 @@ -41,12 +44,14 @@ typedef struct { - uint8_t id, smram_locked, + uint8_t has_ide, smram_locked, regs[256]; uint16_t timer_base, timer_latch; + smram_t *smram; + double fast_off_period; pc_timer_t timer, fast_off_timer; @@ -97,25 +102,11 @@ i420ex_map(uint32_t addr, uint32_t size, int state) } -static void -i420ex_smram_map(int smm, uint32_t addr, uint32_t size, int is_smram) -{ - mem_set_mem_state_smram(smm, addr, size, is_smram); - flushmmucache(); -} - - static void i420ex_smram_handler_phase0(void) { /* Disable low extended SMRAM. */ - if (smram[0].size != 0x00000000) { - i420ex_smram_map(0, smram[0].host_base, smram[0].size, 0); - i420ex_smram_map(1, smram[0].host_base, smram[0].size, 0); - - memset(&smram[0], 0x00, sizeof(smram_t)); - mem_mapping_disable(&ram_smram_mapping[0]); - } + smram_disable_all(); } @@ -124,58 +115,43 @@ i420ex_smram_handler_phase1(i420ex_t *dev) { uint8_t *regs = (uint8_t *) dev->regs; - uint32_t base = 0x000a0000; + uint32_t host_base = 0x000a0000, ram_base = 0x000a0000; uint32_t size = 0x00010000; switch (regs[0x70] & 0x07) { case 0: case 1: default: - base = size = 0x00000000; + host_base = ram_base = 0x00000000; + size = 0x00000000; break; case 2: - base = 0x000a0000; - smram[0].host_base = 0x000a0000; - smram[0].ram_base = 0x000a0000; + host_base = 0x000a0000; + ram_base = 0x000a0000; break; case 3: - base = 0x000b0000; - smram[0].host_base = 0x000b0000; - smram[0].ram_base = 0x000b0000; + host_base = 0x000b0000; + ram_base = 0x000b0000; break; case 4: - base = 0x000c0000; - smram[0].host_base = 0x000c0000; - smram[0].ram_base = 0x000a0000; + host_base = 0x000c0000; + ram_base = 0x000a0000; break; case 5: - base = 0x000d0000; - smram[0].host_base = 0x000d0000; - smram[0].ram_base = 0x000a0000; + host_base = 0x000d0000; + ram_base = 0x000a0000; break; case 6: - base = 0x000e0000; - smram[0].host_base = 0x000e0000; - smram[0].ram_base = 0x000a0000; + host_base = 0x000e0000; + ram_base = 0x000a0000; break; case 7: - base = 0x000f0000; - smram[0].host_base = 0x000f0000; - smram[0].ram_base = 0x000a0000; + host_base = 0x000f0000; + ram_base = 0x000a0000; break; } - smram[0].size = size; - - if (size != 0x00000000) { - mem_mapping_set_addr(&ram_smram_mapping[0], smram[0].host_base, 0x00010000); - mem_mapping_set_exec(&ram_smram_mapping[0], ram + smram[0].ram_base); - - /* If OSS = 1 and LSS = 0, extended SMRAM is visible outside SMM. */ - i420ex_smram_map(0, base, size, (regs[0x70] & 0x70) == 0x40); - - /* If the register is set accordingly, disable the mapping also in SMM. */ - i420ex_smram_map(1, base, size, !(regs[0x70] & 0x20)); - } + smram_enable(dev->smram, host_base, ram_base, size, + (regs[0x70] & 0x70) == 0x40, !(regs[0x70] & 0x20)); } @@ -190,10 +166,6 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) if (((addr >= 0x0f) && (addr < 0x4c)) && (addr != 0x40)) return; - /* The IB (original) variant of the I420EX has no PCI IRQ steering. */ - if ((addr >= 0x60) && (addr <= 0x63) && (dev->id < 0x03)) - return; - switch (addr) { case 0x05: dev->regs[addr] = (val & 0x01); @@ -211,29 +183,27 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) break; case 0x48: dev->regs[addr] = (val & 0x3f); -#ifdef USE_420EX_IDE - ide_pri_disable(); - switch (val & 0x03) { - case 0x01: - ide_set_base(0, 0x01f0); - ide_set_side(0, 0x03f6); - ide_pri_enable(); - break; - case 0x02: - ide_set_base(0, 0x0170); - ide_set_side(0, 0x0376); - ide_pri_enable(); - break; + if (dev->has_ide) { + ide_pri_disable(); + switch (val & 0x03) { + case 0x01: + ide_set_base(0, 0x01f0); + ide_set_side(0, 0x03f6); + ide_pri_enable(); + break; + case 0x02: + ide_set_base(0, 0x0170); + ide_set_side(0, 0x0376); + ide_pri_enable(); + break; + } } -#endif break; case 0x49: case 0x53: dev->regs[addr] = (val & 0x1f); break; case 0x4c: case 0x51: case 0x57: - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x68: case 0x69: dev->regs[addr] = val; if (addr == 0x4c) { @@ -306,6 +276,9 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) i420ex_map(0xec000, 0x04000, val >> 4); dev->regs[0x5f] = val; break; + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: + spd_write_drbs(dev->regs, 0x60, 0x64, 1); + break; case 0x66: case 0x67: i420ex_log("Set IRQ routing: INT %c -> %02X\n", 0x41 + (addr & 0x01), val); dev->regs[addr] = val & 0x8f; @@ -344,10 +317,8 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) dev->fast_off_period = PCICLK * 32768.0; break; } - cpu_fast_off_count = dev->regs[0xa8] + 1; - timer_disable(&dev->fast_off_timer); - if (dev->fast_off_period != 0.0) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + cpu_fast_off_count = cpu_fast_off_val + 1; + cpu_fast_off_period_set(cpu_fast_off_val, dev->fast_off_period); break; case 0xa2: dev->regs[addr] = val & 0xff; @@ -375,9 +346,7 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) dev->regs[addr] = val & 0xff; cpu_fast_off_val = val; cpu_fast_off_count = val + 1; - timer_disable(&dev->fast_off_timer); - if (dev->fast_off_period != 0.0) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + cpu_fast_off_period_set(cpu_fast_off_val, dev->fast_off_period); break; } } @@ -409,7 +378,6 @@ i420ex_reset_hard(void *priv) dev->regs[0x02] = 0x86; dev->regs[0x03] = 0x04; /*82378IB (I420EX)*/ dev->regs[0x04] = 0x07; dev->regs[0x07] = 0x02; - dev->regs[0x08] = dev->id; dev->regs[0x4c] = 0x4d; dev->regs[0x4e] = 0x03; @@ -428,8 +396,9 @@ i420ex_reset_hard(void *priv) pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + if (dev->has_ide) + ide_pri_disable(); } @@ -450,13 +419,8 @@ i420ex_fast_off_count(void *priv) cpu_fast_off_count--; - if (cpu_fast_off_count == 0) { - smi_line = 1; - dev->regs[0xaa] |= 0x20; - cpu_fast_off_count = dev->regs[0xa8] + 1; - } - - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + smi_raise(); + dev->regs[0xaa] |= 0x20; } @@ -466,6 +430,8 @@ i420ex_reset(void *p) i420ex_t *dev = (i420ex_t *) p; int i; + i420ex_write(0, 0x48, 0x00, p); + for (i = 0; i < 7; i++) i420ex_write(0, 0x59 + i, 0x00, p); @@ -494,6 +460,8 @@ i420ex_close(void *p) { i420ex_t *dev = (i420ex_t *)p; + smram_del(dev->smram); + free(dev); } @@ -510,13 +478,11 @@ i420ex_speed_changed(void *priv) if (te) timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); - if (dev->id == 0x03) { - te = timer_is_enabled(&dev->fast_off_timer); + te = timer_is_enabled(&dev->fast_off_timer); - timer_stop(&dev->fast_off_timer); - if (te) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); - } + timer_stop(&dev->fast_off_timer); + if (te) + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); } @@ -526,19 +492,21 @@ i420ex_init(const device_t *info) i420ex_t *dev = (i420ex_t *) malloc(sizeof(i420ex_t)); memset(dev, 0, sizeof(i420ex_t)); + dev->smram = smram_add(); + pci_add_card(PCI_ADD_NORTHBRIDGE, i420ex_read, i420ex_write, dev); - dev->id = info->local; + dev->has_ide = info->local; timer_add(&dev->fast_off_timer, i420ex_fast_off_count, dev, 0); - i420ex_reset_hard(dev); - cpu_fast_off_flags = 0x00000000; cpu_fast_off_val = dev->regs[0xa8]; cpu_fast_off_count = cpu_fast_off_val + 1; + cpu_register_fast_off_handler(&dev->fast_off_timer); + dev->apm = device_add(&apm_pci_device); /* APM intercept handler to update 82420EX SMI status on APM SMI. */ io_sethandler(0x00b2, 0x0001, NULL, NULL, NULL, i420ex_apm_out, NULL, NULL, dev); @@ -547,27 +515,37 @@ i420ex_init(const device_t *info) dma_alias_set(); -#ifdef USE_420EX_IDE - device_add(&ide_pci_device); - ide_pri_disable(); -#else device_add(&ide_pci_2ch_device); -#endif + + i420ex_reset_hard(dev); return dev; } - -const device_t i420ex_device = -{ - "Intel 82420EX", - DEVICE_PCI, - 0x00, - i420ex_init, - i420ex_close, - i420ex_reset, - NULL, - i420ex_speed_changed, - NULL, - NULL +const device_t i420ex_device = { + .name = "Intel 82420EX", + .internal_name = "i420ex", + .flags = DEVICE_PCI, + .local = 0x00, + .init = i420ex_init, + .close = i420ex_close, + .reset = i420ex_reset, + { .available = NULL }, + .speed_changed = i420ex_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i420ex_ide_device = { + .name = "Intel 82420EX (With IDE)", + .internal_name = "i420ex_ide", + .flags = DEVICE_PCI, + .local = 0x01, + .init = i420ex_init, + .close = i420ex_close, + .reset = i420ex_reset, + { .available = NULL }, + .speed_changed = i420ex_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index a65e06dd3..7e8ff9405 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of the Intel PCISet chips from 420TX to 440BX. + * Implementation of the Intel PCISet chips from 420TX to 440GX. * * * @@ -22,12 +22,14 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/smram.h> #include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> #include <86box/device.h> -#include <86box/keyboard.h> +#include <86box/pci.h> #include <86box/chipset.h> +#include <86box/spd.h> +#include <86box/machine.h> +#include <86box/video.h> enum @@ -50,39 +52,51 @@ enum typedef struct { - uint8_t pm2_cntrl, max_func, + uint8_t pm2_cntrl, smram_locked, max_drb, - drb_default; - uint8_t regs[2][256], regs_locked[2][256]; + drb_unit, drb_default; + uint8_t regs[256], regs_locked[256]; + uint8_t mem_state[256]; int type; + smram_t *smram_low, *smram_high; + void *agpgart; + void (*write_drbs)(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); } i4x0_t; +#ifdef ENABLE_I4X0_LOG +int i4x0_do_log = ENABLE_I4X0_LOG; + + static void -i4x0_map(uint32_t addr, uint32_t size, int state) +i4x0_log(const char *fmt, ...) { - switch (state & 3) { - case 0: - mem_set_mem_state_both(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state_both(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 2: - mem_set_mem_state_both(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state_both(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; + va_list ap; + + if (i4x0_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } - flushmmucache_nopc(); } +#else +#define i4x0_log(fmt, ...) +#endif static void -i4x0_smram_map(int smm, uint32_t addr, uint32_t size, int is_smram) +i4x0_map(i4x0_t *dev, uint32_t addr, uint32_t size, int state) { - mem_set_mem_state_smram(smm, addr, size, is_smram); + uint32_t base = addr >> 12; + int states[4] = { MEM_READ_EXTANY | MEM_WRITE_EXTANY, MEM_READ_INTERNAL | MEM_WRITE_EXTANY, + MEM_READ_EXTANY | MEM_WRITE_INTERNAL, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL }; + + state &= 3; + if (dev->mem_state[base] != state) { + mem_set_mem_state_both(addr, size, states[state]); + dev->mem_state[base] = state; + flushmmucache_nopc(); + } } @@ -91,93 +105,72 @@ i4x0_smram_handler_phase0(i4x0_t *dev) { uint32_t tom = (mem_size << 10); - /* Disable any active mappings. */ - if (smram[0].size != 0x00000000) { - i4x0_smram_map(0, smram[0].host_base, smram[0].size, 0); - i4x0_smram_map(1, smram[0].host_base, smram[0].size, 0); - - memset(&smram[0], 0x00, sizeof(smram_t)); - mem_mapping_disable(&ram_smram_mapping[0]); - } - - if ((dev->type >= INTEL_440BX) && (smram[1].size != 0x00000000)) { - i4x0_smram_map(1, smram[1].host_base, smram[1].size, 0); - + if (((dev->type == INTEL_430TX) || (dev->type >= INTEL_440BX)) && + smram_enabled(dev->smram_high)) { tom -= (1 << 20); mem_set_mem_state_smm(tom, (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - - memset(&smram[1], 0x00, sizeof(smram_t)); - mem_mapping_disable(&ram_smram_mapping[1]); } + + /* Disable any active mappings. */ + smram_disable_all(); } static void i4x0_smram_handler_phase1(i4x0_t *dev) { - uint8_t *regs = (uint8_t *) dev->regs[0]; + + uint8_t *regs = (uint8_t *) dev->regs; uint32_t tom = (mem_size << 10); + uint8_t *reg = (dev->type >= INTEL_430LX) ? &(regs[0x72]) : &(regs[0x57]); + uint8_t *ext_reg = (dev->type >= INTEL_440BX) ? &(regs[0x73]) : &(regs[0x71]); - uint32_t s, base[2] = { 0x000a0000, 0x00020000 }; - uint32_t size[2] = { 0, 0 }; + uint32_t s, base[2] = { 0x000a0000, 0x00000000 }; + uint32_t size[2] = { 0x00010000, 0x00000000 }; - if (dev->type >= INTEL_430FX) { + if ((dev->type <= INTEL_420ZX) || (dev->type >= INTEL_430FX)) { /* Set temporary bases and sizes. */ - if ((dev->type >= INTEL_440BX) && (regs[0x73] & 0x80)) { + if (((dev->type == INTEL_430TX) || (dev->type >= INTEL_440BX)) && + (*ext_reg & 0x80)) { base[0] = 0x100a0000; size[0] = 0x00060000; + } else if (((dev->type == INTEL_440LX) || (dev->type == INTEL_440EX)) && ((*reg & 0x07) == 0x04)) { + base[0] = 0x000c0000; + size[0] = 0x00010000; } else { - if (((dev->type == INTEL_440LX) || (dev->type == INTEL_440EX)) && ((regs[0x72] & 0x07) == 0x04)) { - base[0] = 0x000c0000; - size[0] = 0x00010000; - } else { - base[0] = 0x000a0000; - size[0] = 0x00020000; - } + base[0] = 0x000a0000; + size[0] = 0x00020000; } - if (((regs[0x72] & 0x70) == 0x40) || ((regs[0x72] & 0x08) && !(regs[0x72] & 0x20))) { - smram[0].host_base = base[0]; - smram[0].ram_base = base[0] & 0x000f0000; - smram[0].size = size[0]; + if (*reg & 0x08) + smram_enable(dev->smram_low, base[0], base[0] & 0x000f0000, size[0], + ((*reg & 0x78) == 0x48), (*reg & 0x08)); - mem_mapping_set_addr(&ram_smram_mapping[0], smram[0].host_base, size[0]); - mem_mapping_set_exec(&ram_smram_mapping[0], ram + smram[0].ram_base); - - /* If D_OPEN = 1 and D_LCK = 0, extended SMRAM is visible outside SMM. */ - i4x0_smram_map(0, base[0], size[0], ((regs[0x72] & 0x70) == 0x40)); - - /* If the register is set accordingly, disable the mapping also in SMM. */ - i4x0_smram_map(1, base[0], size[0], ((regs[0x72] & 0x08) && !(regs[0x72] & 0x20))); + if ((*reg & 0x28) == 0x28) { + /* If SMRAM is enabled and DCLS is set, then data goes to PCI, but + code still goes to DRAM. */ + mem_set_mem_state_smram_ex(1, base[0], size[0], 0x02); } /* TSEG mapping. */ - if (dev->type >= INTEL_440BX) { - if ((regs[0x72] & 0x08) && (regs[0x73] & 0x01)) { - size[1] = (1 << (17 + ((regs[0x73] >> 1) & 0x03))); + if ((dev->type == INTEL_430TX) || (dev->type >= INTEL_440BX)) { + if ((*reg & 0x08) && (*ext_reg & 0x01)) { + size[1] = (1 << (17 + ((*ext_reg >> 1) & 0x03))); tom -= size[1]; base[1] = tom; } else base[1] = size[1] = 0x00000000; if (size[1] != 0x00000000) { - smram[1].host_base = base[1] + (1 << 28); - smram[1].ram_base = base[1]; - smram[1].size = size[1]; - - mem_mapping_set_addr(&ram_smram_mapping[1], smram[1].host_base, smram[1].size); - if (smram[1].ram_base < (1 << 30)) - mem_mapping_set_exec(&ram_smram_mapping[1], ram + smram[1].ram_base); - else - mem_mapping_set_exec(&ram_smram_mapping[1], ram2 + smram[1].ram_base - (1 << 30)); + smram_enable(dev->smram_high, base[1] + (1 << 28), base[1], size[1], + 0, 1); mem_set_mem_state_smm(base[1], size[1], MEM_READ_EXTANY | MEM_WRITE_EXTANY); - i4x0_smram_map(1, smram[1].host_base, size[1], 1); } } } else { size[0] = 0x00010000; - switch (regs[0x72] & 0x03) { + switch (*reg & 0x03) { case 0: default: base[0] = (mem_size << 10) - size[0]; @@ -197,19 +190,15 @@ i4x0_smram_handler_phase1(i4x0_t *dev) break; } - if (((((regs[0x72] & 0x38) == 0x20) || s) || (!(regs[0x72] & 0x10) || s)) && (size[0] != 0x00000000)) { - smram[0].host_base = base[0]; - smram[0].ram_base = base[0]; - smram[0].size = size[0]; + if (size[0] != 0x00000000) { + smram_enable(dev->smram_low, base[0], base[0], size[0], + (((*reg & 0x38) == 0x20) || s), 1); - mem_mapping_set_addr(&ram_smram_mapping[0], smram[0].host_base, size[0]); - mem_mapping_set_exec(&ram_smram_mapping[0], ram + smram[0].ram_base); - - /* If OSS = 1 and LSS = 0, extended SMRAM is visible outside SMM. */ - i4x0_smram_map(0, base[0], size[0], (((regs[0x72] & 0x38) == 0x20) || s)); - - /* If the register is set accordingly, disable the mapping also in SMM. */ - i4x0_smram_map(0, base[0], size[0], (!(regs[0x72] & 0x10) || s)); + if (*reg & 0x10) { + /* If SMRAM is enabled and DCLS is set, then data goes to PCI, but + code still goes to DRAM. */ + mem_set_mem_state_smram_ex(1, base[0], size[0], 0x02); + } } } @@ -218,14 +207,25 @@ i4x0_smram_handler_phase1(i4x0_t *dev) static void -i4x0_mask_bar(uint8_t *regs) +i4x0_mask_bar(uint8_t *regs, void *agpgart) { uint32_t bar; + /* Make sure the aperture's base is aligned to its size. */ bar = (regs[0x13] << 24) | (regs[0x12] << 16); bar &= (((uint32_t) regs[0xb4] << 22) | 0xf0000000); regs[0x12] = (bar >> 16) & 0xff; regs[0x13] = (bar >> 24) & 0xff; + + if (!agpgart) + return; + + /* Map aperture and GART. */ + agpgart_set_aperture(agpgart, + bar, + ((uint32_t) (uint8_t) (~regs[0xb4] & 0x3f) + 1) << 22, + !!(regs[0x51] & 0x02)); + agpgart_set_gart(agpgart, (regs[0xb9] << 8) | (regs[0xba] << 16) | (regs[0xbb] << 24)); } @@ -251,16 +251,13 @@ static void i4x0_write(int func, int addr, uint8_t val, void *priv) { i4x0_t *dev = (i4x0_t *) priv; - uint8_t *regs = (uint8_t *) dev->regs[func]; - uint8_t *regs_l = (uint8_t *) dev->regs_locked[func]; + uint8_t *regs = (uint8_t *) dev->regs; + uint8_t *regs_l = (uint8_t *) dev->regs_locked; int i; - if (func > dev->max_func) + if (func > 0) return; - if ((addr >= 0x10) && (addr < 0x4f)) - return; - if (func == 0) switch (addr) { case 0x04: /*Command register*/ switch (dev->type) { @@ -270,34 +267,45 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[0x04] = (regs[0x04] & ~0x42) | (val & 0x42); break; case INTEL_430FX: case INTEL_430HX: case INTEL_430VX: case INTEL_430TX: - case INTEL_440FX: case INTEL_440LX: case INTEL_440EX: + case INTEL_440FX: regs[0x04] = (regs[0x04] & ~0x02) | (val & 0x02); break; + case INTEL_440LX: case INTEL_440EX: + regs[0x04] = val & 0x40; + break; } break; case 0x05: switch (dev->type) { - case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: case INTEL_430HX: - case INTEL_440FX: case INTEL_440LX: case INTEL_440EX: - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: + case INTEL_430HX: case INTEL_440FX: case INTEL_440BX: case INTEL_440GX: + case INTEL_440ZX: regs[0x05] = (regs[0x05] & ~0x01) | (val & 0x01); break; + case INTEL_440LX: case INTEL_440EX: + regs[0x05] = val & 0x01; + break; } break; case 0x07: switch (dev->type) { - case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: case INTEL_430HX: + case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: + case INTEL_430HX: default: regs[0x07] &= ~(val & 0x70); break; - case INTEL_430FX: case INTEL_430VX: case INTEL_430TX: - case INTEL_440LX: case INTEL_440EX: + case INTEL_430FX: case INTEL_430VX: + case INTEL_430TX: regs[0x07] &= ~(val & 0x30); break; case INTEL_440FX: regs[0x07] &= ~(val & 0xf9); break; - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + regs[0x07] &= ~(val & 0xf1); + break; + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x07] &= ~(val & 0xf0); break; } @@ -321,23 +329,28 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x12: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x12] = (val & 0xc0); - i4x0_mask_bar(regs); + i4x0_mask_bar(regs, dev->agpgart); break; } break; case 0x13: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x13] = val; - i4x0_mask_bar(regs); + i4x0_mask_bar(regs, dev->agpgart); break; } break; case 0x2c: case 0x2d: case 0x2e: case 0x2f: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: if (!regs_l[addr]) { regs[addr] = val; regs_l[addr] = 1; @@ -346,13 +359,6 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; - case 0x34: - switch (dev->type) { - case INTEL_440LX: case INTEL_440EX: - regs[0x34] = (val & 0xa0); - } - break; - case 0x4f: switch (dev->type) { case INTEL_430HX: @@ -388,18 +394,16 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[0x50] = (val & 0xf4); break; case INTEL_440LX: - regs[0x50] = (val & 0x03); + regs[0x50] = (val & 0x70); break; case INTEL_440EX: - regs[0x50] = (val & 0x23); + regs[0x50] = (val & 0x20); break; case INTEL_440BX: regs[0x50] = (regs[0x50] & 0x14) | (val & 0xeb); break; case INTEL_440GX: - /* TODO: Understand it more specifically */ - regs[0x50] = (regs[0x50] & 0x2b) | (val & 0x28); - /*regs[0x50] = (regs[0x50] & 0x2b) | (val & 0xd7);*/ + regs[0x50] = (regs[0x50] & 0x04) | (val & 0xe8); break; case INTEL_440ZX: regs[0x50] = (regs[0x50] & 0x34) | (val & 0xcb); @@ -415,15 +419,21 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_440FX: regs[0x51] = (val & 0xc3); break; - case INTEL_440LX: case INTEL_440EX: - regs[0x51] = (val & 0x80); + case INTEL_440LX: + regs[0x51] = (regs[0x51] & 0x40) | (val & 0x87); + i4x0_mask_bar(regs, dev->agpgart); + break; + case INTEL_440EX: + regs[0x51] = (val & 0x86); + i4x0_mask_bar(regs, dev->agpgart); break; case INTEL_440BX: case INTEL_440ZX: - regs[0x51] = (regs[0x50] & 0x70) | (val & 0x8f); + regs[0x51] = (regs[0x51] & 0x70) | (val & 0x8f); + i4x0_mask_bar(regs, dev->agpgart); break; case INTEL_440GX: - regs[0x51] = (regs[0x50] & 0x88) | (val & 0x08); - /*regs[0x51] = (regs[0x50] & 0x88) | (val & 0x77);*/ + regs[0x51] = (regs[0x51] & 0xb0) | (val & 0x4f); + i4x0_mask_bar(regs, dev->agpgart); break; } break; @@ -439,10 +449,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_440FX: regs[0x52] = val; break; - case INTEL_440LX: - regs[0x52] = (val & 0xd0); - break; - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x52] = val & 0x07; break; } @@ -459,10 +467,10 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430VX: case INTEL_430TX: regs[0x53] = val & 0x3f; break; - case INTEL_440LX: - regs[0x53] = val & 0x0a; + case INTEL_440LX: case INTEL_440EX: + regs[0x53] = val & 0x60; break; - case INTEL_440EX: case INTEL_440BX: case INTEL_440GX: + case INTEL_440BX: case INTEL_440GX: /* Not applicable to 440ZX as that does not support ECC. */ regs[0x53] = val; break; @@ -483,13 +491,15 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_440FX: regs[0x54] = val & 0x82; break; - case INTEL_440LX: - regs[0x54] = val; - break; } break; case 0x55: switch (dev->type) { + case INTEL_420TX: case INTEL_420ZX: + /* According to the FreeBSD 3.x source code, the 420TX/ZX chipset has + this register. The mask is unknown, so write all bits. */ + regs[0x55] = val; + break; case INTEL_430VX: case INTEL_430TX: regs[0x55] = val & 0x01; break; @@ -501,6 +511,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x56: switch (dev->type) { + case INTEL_420TX: case INTEL_420ZX: + /* According to the FreeBSD 3.x source code, the 420TX/ZX chipset has + this register. The mask is unknown, so write all bits. */ + regs[0x56] = val; + break; case INTEL_430HX: regs[0x56] = val & 0x1f; break; @@ -510,19 +525,31 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430TX: regs[0x56] = val & 0x76; break; - case INTEL_440FX: case INTEL_440LX: - case INTEL_440EX: + case INTEL_440FX: + case INTEL_440LX: case INTEL_440EX: regs[0x56] = val; break; } break; case 0x57: switch (dev->type) { + /* On the 420TX and 420ZX, this is the SMRAM space register. */ case INTEL_420TX: case INTEL_420ZX: + i4x0_smram_handler_phase0(dev); + if (dev->smram_locked) + regs[0x57] = (regs[0x57] & 0xdf) | (val & 0x20); + else { + regs[0x57] = (regs[0x57] & 0x87) | (val & 0x78); + dev->smram_locked = (val & 0x10); + if (dev->smram_locked) + regs[0x57] &= 0xbf; + } + i4x0_smram_handler_phase1(dev); + break; case INTEL_430LX: default: regs[0x57] = val & 0x3f; break; - case INTEL_430NX: case INTEL_440EX: + case INTEL_430NX: regs[0x57] = val; break; case INTEL_430FX: case INTEL_430HX: @@ -535,8 +562,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_440FX: regs[0x57] = val & 0x77; break; - case INTEL_440LX: - regs[0x57] = val & 0x11; + case INTEL_440LX: case INTEL_440EX: + regs[0x57] = val & 0x37; break; case INTEL_440BX: case INTEL_440GX: regs[0x57] = val & 0x3f; @@ -552,7 +579,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430LX: default: regs[0x58] = val & 0x01; break; - case INTEL_430NX: case INTEL_440LX: + case INTEL_430NX: case INTEL_440BX: case INTEL_440ZX: regs[0x58] = val & 0x03; break; @@ -560,23 +587,21 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[0x58] = val & 0x7f; break; case INTEL_430HX: case INTEL_430VX: - regs[0x57] = val; + case INTEL_440LX: case INTEL_440EX: + regs[0x58] = val; break; case INTEL_430TX: - regs[0x57] = val & 0x7b; - break; - case INTEL_440EX: - regs[0x58] = val & 0xbf; + regs[0x58] = val & 0x7b; break; } break; case 0x59: /* PAM0 */ if (dev->type <= INTEL_430NX) { if ((regs[0x59] ^ val) & 0x0f) - i4x0_map(0x80000, 0x20000, val & 0x0f); + i4x0_map(dev, 0x80000, 0x20000, val & 0x0f); } if ((regs[0x59] ^ val) & 0xf0) { - i4x0_map(0xf0000, 0x10000, val >> 4); + i4x0_map(dev, 0xf0000, 0x10000, val >> 4); shadowbios = (val & 0x10); } if (dev->type > INTEL_430NX) @@ -586,54 +611,59 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x5a: /* PAM1 */ if ((regs[0x5a] ^ val) & 0x0f) - i4x0_map(0xc0000, 0x04000, val & 0xf); + i4x0_map(dev, 0xc0000, 0x04000, val & 0xf); if ((regs[0x5a] ^ val) & 0xf0) - i4x0_map(0xc4000, 0x04000, val >> 4); + i4x0_map(dev, 0xc4000, 0x04000, val >> 4); regs[0x5a] = val & 0x77; break; case 0x5b: /*PAM2 */ if ((regs[0x5b] ^ val) & 0x0f) - i4x0_map(0xc8000, 0x04000, val & 0xf); + i4x0_map(dev, 0xc8000, 0x04000, val & 0xf); if ((regs[0x5b] ^ val) & 0xf0) - i4x0_map(0xcc000, 0x04000, val >> 4); + i4x0_map(dev, 0xcc000, 0x04000, val >> 4); regs[0x5b] = val & 0x77; break; case 0x5c: /*PAM3 */ if ((regs[0x5c] ^ val) & 0x0f) - i4x0_map(0xd0000, 0x04000, val & 0xf); + i4x0_map(dev, 0xd0000, 0x04000, val & 0xf); if ((regs[0x5c] ^ val) & 0xf0) - i4x0_map(0xd4000, 0x04000, val >> 4); + i4x0_map(dev, 0xd4000, 0x04000, val >> 4); regs[0x5c] = val & 0x77; break; case 0x5d: /* PAM4 */ if ((regs[0x5d] ^ val) & 0x0f) - i4x0_map(0xd8000, 0x04000, val & 0xf); + i4x0_map(dev, 0xd8000, 0x04000, val & 0xf); if ((regs[0x5d] ^ val) & 0xf0) - i4x0_map(0xdc000, 0x04000, val >> 4); + i4x0_map(dev, 0xdc000, 0x04000, val >> 4); regs[0x5d] = val & 0x77; break; case 0x5e: /* PAM5 */ if ((regs[0x5e] ^ val) & 0x0f) - i4x0_map(0xe0000, 0x04000, val & 0xf); + i4x0_map(dev, 0xe0000, 0x04000, val & 0xf); if ((regs[0x5e] ^ val) & 0xf0) - i4x0_map(0xe4000, 0x04000, val >> 4); + i4x0_map(dev, 0xe4000, 0x04000, val >> 4); regs[0x5e] = val & 0x77; break; case 0x5f: /* PAM6 */ if ((regs[0x5f] ^ val) & 0x0f) - i4x0_map(0xe8000, 0x04000, val & 0xf); + i4x0_map(dev, 0xe8000, 0x04000, val & 0xf); if ((regs[0x5f] ^ val) & 0xf0) - i4x0_map(0xec000, 0x04000, val >> 4); + i4x0_map(dev, 0xec000, 0x04000, val >> 4); regs[0x5f] = val & 0x77; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: + if ((addr & 0x7) <= dev->max_drb) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: case INTEL_430HX: case INTEL_440FX: case INTEL_440LX: case INTEL_440EX: - case INTEL_440BX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: default: regs[addr] = val; break; @@ -646,13 +676,17 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x65: + if ((addr & 0x7) <= dev->max_drb) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: case INTEL_430HX: case INTEL_440FX: case INTEL_440LX: case INTEL_440EX: - case INTEL_440GX: + case INTEL_440GX: case INTEL_440BX: case INTEL_440ZX: regs[addr] = val; break; @@ -665,6 +699,10 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x66: + if ((addr & 0x7) <= dev->max_drb) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { case INTEL_430NX: case INTEL_430HX: case INTEL_440FX: case INTEL_440LX: @@ -675,12 +713,16 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x67: + if ((addr & 0x7) <= dev->max_drb) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: case INTEL_430HX: - case INTEL_440FX: case INTEL_440LX: - case INTEL_440EX: + case INTEL_430NX: case INTEL_430HX: + case INTEL_440FX: + case INTEL_440LX: case INTEL_440EX: case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440ZX: regs[addr] = val; break; case INTEL_430VX: @@ -692,53 +734,61 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x68: + if (dev->type == INTEL_430NX) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: case INTEL_430HX: + case INTEL_430HX: case INTEL_430VX: case INTEL_430TX: regs[0x68] = val; break; case INTEL_430FX: regs[0x68] = val & 0x1f; break; - case INTEL_440FX: case INTEL_440LX: - case INTEL_440EX: + case INTEL_440FX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440GX: regs[0x68] = val & 0xc0; break; case INTEL_440BX: regs[0x68] = (regs[0x68] & 0x38) | (val & 0xc7); break; - case INTEL_440GX: - regs[0x68] = (regs[0x68] & 0xc0) | (val & 0x3f); - break; case INTEL_440ZX: regs[0x68] = (regs[0x68] & 0x3f) | (val & 0xc0); break; } break; case 0x69: + if (dev->type == INTEL_430NX) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: - case INTEL_440BX: - case INTEL_440GX: + case INTEL_440BX: case INTEL_440GX: regs[0x69] = val; break; case INTEL_430VX: regs[0x69] = val & 0x07; break; - case INTEL_440ZX: + case INTEL_440ZX: regs[0x69] = val & 0x3f; break; } break; case 0x6a: case 0x6b: + if (dev->type == INTEL_430NX) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: - case INTEL_440LX: - case INTEL_440EX: - case INTEL_440BX: - case INTEL_440GX: + case INTEL_440BX: case INTEL_440GX: regs[addr] = val; break; + case INTEL_440LX: case INTEL_440EX: + if (addr == 0x6a) + regs[addr] = val & 0xef; + break; case INTEL_440ZX: if (addr == 0x6a) regs[addr] = val & 0xfc; @@ -749,11 +799,10 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x6c: case 0x6d: case 0x6e: switch (dev->type) { - case INTEL_440LX: - case INTEL_440EX: - case INTEL_440BX: - case INTEL_440GX: - regs[addr] = val; + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440GX: + if (addr != 0x6e) + regs[addr] = val; break; case INTEL_440ZX: if (addr == 0x6c) @@ -764,11 +813,13 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x6f: - switch (dev->type){ + switch (dev->type) { case INTEL_440LX: + regs[addr] = val; + break; case INTEL_440EX: - regs[addr] = val; - break; + regs[addr] = val & 0xcf; + break; } break; case 0x70: @@ -783,8 +834,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430VX: case INTEL_430TX: regs[addr] = val & 0xfc; break; - case INTEL_440FX: case INTEL_440LX: - case INTEL_440EX: + case INTEL_440FX: + case INTEL_440LX: case INTEL_440EX: regs[addr] = val & 0xf8; break; } @@ -795,7 +846,14 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430LX: regs[addr] = val & 0x4d; break; - case INTEL_430TX: case INTEL_440EX: + case INTEL_430TX: + if (!dev->smram_locked) { + i4x0_smram_handler_phase0(dev); + regs[0x71] = (regs[0x71] & 0x20) | (val & 0xdf); + i4x0_smram_handler_phase1(dev); + } + break; + case INTEL_440EX: regs[addr] = val; break; case INTEL_440FX: case INTEL_440LX: @@ -804,13 +862,17 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x72: /* SMRAM */ + if (dev->type <= INTEL_420ZX) + break; + i4x0_smram_handler_phase0(dev); if (dev->type >= INTEL_430FX) { if (dev->smram_locked) regs[0x72] = (regs[0x72] & 0xdf) | (val & 0x20); else { - if ((dev->type == INTEL_440LX) || (dev->type == INTEL_440EX)) - regs[0x72] = (regs[0x72] & 0x80) | (val & 0x7f); + if ((dev->type == INTEL_440LX) || (dev->type == INTEL_440EX) || + (dev->type == INTEL_440GX)) + regs[0x72] = (val & 0x7f); else regs[0x72] = (regs[0x72] & 0x87) | (val & 0x78); dev->smram_locked = (val & 0x10); @@ -834,10 +896,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430VX: regs[0x73] = val & 0x03; break; - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: if (!dev->smram_locked) { i4x0_smram_handler_phase0(dev); - regs[0x73] = (regs[0x72] & 0x38) | (val & 0xc7); + regs[0x73] = (regs[0x73] & 0x38) | (val & 0xc7); i4x0_smram_handler_phase1(dev); } break; @@ -847,6 +910,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) switch (dev->type) { case INTEL_430VX: case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x74] = val; break; } @@ -854,13 +918,14 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0x75: case 0x76: case 0x7b: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[addr] = val; } break; case 0x77: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: regs[0x77] = val & 0x03; } break; @@ -869,9 +934,12 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430VX: regs[0x78] = val & 0xcf; break; - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: regs[0x78] = val & 0x0f; break; + case INTEL_440GX: + regs[0x78] = val & 0x1f; + break; } break; case 0x79: @@ -882,14 +950,16 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) if (val & 0x40) io_sethandler(0x0022, 0x01, pm2_cntrl_read, NULL, NULL, pm2_cntrl_write, NULL, NULL, dev); break; - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x79] = val; break; } break; case 0x7a: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x7a] = (regs[0x7a] & 0x0a) | (val & 0xf5); io_removehandler(0x0022, 0x01, pm2_cntrl_read, NULL, NULL, pm2_cntrl_write, NULL, NULL, dev); if (val & 0x40) @@ -904,17 +974,19 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[0x7c] = val & 0x8f; break; case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440ZX: regs[0x7c] = val & 0x1f; break; } + break; case 0x7d: switch (dev->type) { case INTEL_420TX: case INTEL_420ZX: case INTEL_430LX: case INTEL_430NX: - regs[0x7c] = val & 0x32; + regs[0x7d] = val & 0x32; break; } + break; case 0x7e: case 0x7f: switch (dev->type) { case INTEL_420TX: case INTEL_420ZX: @@ -922,9 +994,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[addr] = val; break; } + break; case 0x80: switch (dev->type) { case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x80] &= ~(val & 0x03); break; } @@ -932,19 +1006,20 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0x90: switch (dev->type) { case INTEL_430HX: - regs[0x80] = val & 0x87; + regs[0x90] = val & 0x87; break; case INTEL_440FX: - regs[0x80] = val & 0x1b; + regs[0x90] = val & 0x1b; break; case INTEL_440LX: - regs[0x80] = val & 0x08; + regs[0x90] = val & 0xfb; break; - case INTEL_440EX: case INTEL_440GX: - regs[0x80] = val & 0x18; + case INTEL_440EX: + regs[0x90] = val & 0xf8; break; case INTEL_440BX: case INTEL_440ZX: - regs[0x7c] = val; + case INTEL_440GX: + regs[0x90] = val; break; } break; @@ -952,8 +1027,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) switch (dev->type) { case INTEL_430HX: case INTEL_440BX: case INTEL_440FX: case INTEL_440LX: - case INTEL_440EX: case INTEL_440GX: - /* Not applicable on 82443ZX. */ + case INTEL_440GX: + /* Not applicable on 82443EX and 82443ZX. */ regs[0x91] &= ~(val & 0x11); break; } @@ -961,8 +1036,10 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0x92: switch (dev->type) { case INTEL_440LX: case INTEL_440EX: - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + regs[0x92] &= ~(val & 0x07); + break; + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0x92] &= ~(val & 0x1f); break; } @@ -970,71 +1047,86 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0x93: switch (dev->type) { case INTEL_440FX: - case INTEL_440LX: - case INTEL_440EX: regs[0x93] = (val & 0x0f); trc_write(0x0093, val & 0x06, NULL); break; + case INTEL_440LX: case INTEL_440EX: + regs[0x93] = (val & 0x0e); + trc_write(0x0093, val & 0x06, NULL); + break; + } + break; + case 0xa7: + switch (dev->type) { + case INTEL_440LX: case INTEL_440EX: + regs[0xa7] = val & 0x1f; + break; } break; case 0xa8: case 0xa9: switch (dev->type) { + case INTEL_440LX: case INTEL_440EX: case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[addr] = (val & 0x03); break; } break; case 0xb0: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0xb0] = (val & 0x80); break; } break; case 0xb1: switch (dev->type) { - case INTEL_440EX: + case INTEL_440LX: case INTEL_440EX: regs[0xb1] = (val & 0x22); break; case INTEL_440BX: case INTEL_440ZX: - regs[0xb1] = (val & 0xa0); - break; case INTEL_440GX: - regs[0xb1] = (val & 0xa2); + regs[0xb1] = (val & 0xa0); break; } break; case 0xb4: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0xb4] = (val & 0x3f); - i4x0_mask_bar(regs); + i4x0_mask_bar(regs, dev->agpgart); break; } break; case 0xb9: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0xb9] = (val & 0xf0); + i4x0_mask_bar(regs, dev->agpgart); break; } break; case 0xba: case 0xbb: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440LX: case INTEL_440EX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[addr] = val; + i4x0_mask_bar(regs, dev->agpgart); break; } break; case 0xbc: switch (dev->type) { - case INTEL_440EX: case INTEL_440GX: + case INTEL_440LX: case INTEL_440EX: regs[addr] = (val & 0xf8); break; } @@ -1042,16 +1134,17 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0xbd: switch (dev->type) { - case INTEL_440EX: case INTEL_440GX: + case INTEL_440LX: case INTEL_440EX: regs[addr] = (val & 0xf8); break; } break; - case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[addr] = val; break; } @@ -1089,8 +1182,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: if (!regs_l[addr]) regs[addr] = val; break; @@ -1098,8 +1191,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0xe5: case 0xed: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: if (!regs_l[addr]) regs[addr] = (val & 0x3f); break; @@ -1107,8 +1200,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0xe7: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0xe7] = 0x80; for (i = 0; i < 16; i++) regs_l[0xe0 + i] = !!(val & 0x80); @@ -1120,79 +1213,17 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0xf0: switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: + case INTEL_440BX: case INTEL_440ZX: + case INTEL_440GX: regs[0xf0] = (val & 0xc0); break; } break; case 0xf1: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[0xf1] = (val & 0x03); - break; - } - break; - } else if (func == 1) switch (addr) { - case 0x04: switch (dev->type) { case INTEL_440BX: case INTEL_440ZX: - regs[0x04] = (val & 0x1f); - break; - case INTEL_440GX: - regs[0x04] = val; - } - break; - case 0x05: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[0x05] = (val & 0x01); - break; - } - break; - case 0x0d: case 0x1b: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[addr] = (val & 0xf8); - break; - } - break; - case 0x19: case 0x1a: - case 0x21: case 0x23: - case 0x25: case 0x27: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[addr] = val; - break; - } - break; - case 0x1c: case 0x1d: - case 0x20: case 0x22: - case 0x24: case 0x26: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[addr] = (val & 0xf0); - break; - } - break; - case 0x1f: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[0x1f] &= ~(val & 0xf0); - break; - } - break; - case 0x3e: - switch (dev->type) { - case INTEL_440BX: case INTEL_440GX: - case INTEL_440ZX: - regs[0x3e] = (val & 0xed); + case INTEL_440GX: + regs[0xf1] = (val & 0x03); break; } break; @@ -1205,15 +1236,15 @@ i4x0_read(int func, int addr, void *priv) { i4x0_t *dev = (i4x0_t *) priv; uint8_t ret = 0xff; - uint8_t *regs = (uint8_t *) dev->regs[func]; + uint8_t *regs = (uint8_t *) dev->regs; - if (func > dev->max_func) - ret = 0xff; - else { + if (func == 0) { ret = regs[addr]; /* Special behavior for 440FX register 0x93 which is basically TRC in PCI space with the addition of bits 3 and 0. */ - if ((func == 0) && (addr == 0x93) && (dev->type == INTEL_440FX)) + if ((func == 0) && (addr == 0x93) && + ((dev->type == INTEL_440FX) || (dev->type == INTEL_440LX) || + (dev->type == INTEL_440EX))) ret = (ret & 0xf9) | (trc_read(0x0093, NULL) & 0x06); } @@ -1227,6 +1258,10 @@ i4x0_reset(void *priv) i4x0_t *dev = (i4x0_t *)priv; int i; + if ((dev->type == INTEL_440LX) || (dev->type == INTEL_440BX) || + (dev->type == INTEL_440ZX)) + memset(dev->regs_locked, 0x00, 256 * sizeof(uint8_t)); + if (dev->type >= INTEL_430FX) i4x0_write(0, 0x59, 0x00, priv); else @@ -1239,16 +1274,19 @@ i4x0_reset(void *priv) i4x0_write(0, 0x60 + i, dev->drb_default, priv); if (dev->type >= INTEL_430FX) { - dev->regs[0][0x72] &= 0xef; /* Forcibly unlock the SMRAM register. */ + dev->regs[0x72] &= 0xef; /* Forcibly unlock the SMRAM register. */ i4x0_write(0, 0x72, 0x02, priv); - } else { - dev->regs[0][0x72] &= 0xf7; /* Forcibly unlock the SMRAM register. */ + } else if (dev->type >= INTEL_430LX) { + dev->regs[0x72] &= 0xf7; /* Forcibly unlock the SMRAM register. */ i4x0_write(0, 0x72, 0x00, priv); + } else { + dev->regs[0x57] &= 0xef; /* Forcibly unlock the SMRAM register. */ + i4x0_write(0, 0x57, 0x02, priv); } - if ((dev->type == INTEL_440LX) || (dev->type == INTEL_440BX) || (dev->type == INTEL_440ZX)) { - for (i = 0; i <= dev->max_func; i++) - memset(dev->regs_locked[i], 0x00, 256 * sizeof(uint8_t)); + if ((dev->type == INTEL_430TX) || (dev->type >= INTEL_440BX)) { + i4x0_write(0, (dev->type >= INTEL_440BX) ? 0x73 : 0x71, + (dev->type >= INTEL_440BX) ? 0x38 : 0x00, priv); } } @@ -1256,9 +1294,12 @@ i4x0_reset(void *priv) static void i4x0_close(void *p) { - i4x0_t *i4x0 = (i4x0_t *)p; + i4x0_t *dev = (i4x0_t *)p; - free(i4x0); + smram_del(dev->smram_high); + smram_del(dev->smram_low); + + free(dev); } @@ -1270,12 +1311,17 @@ static void memset(dev, 0, sizeof(i4x0_t)); + dev->smram_low = smram_add(); + dev->smram_high = smram_add(); + dev->type = info->local & 0xff; - regs = (uint8_t *) dev->regs[0]; + regs = (uint8_t *) dev->regs; regs[0x00] = 0x86; regs[0x01] = 0x80; /*Intel*/ + dev->write_drbs = spd_write_drbs; + switch (dev->type) { case INTEL_420TX: case INTEL_420ZX: @@ -1283,28 +1329,33 @@ static void regs[0x06] = 0x40; regs[0x08] = (dev->type == INTEL_420ZX) ? 0x01 : 0x00; regs[0x0d] = 0x20; - if (is486sx) + /* According to information from FreeBSD 3.x source code: + 0x00 = 486DX, 0x20 = 486SX, 0x40 = 486DX2 or 486DX4, 0x80 = Pentium OverDrive. */ + if (!(hasfpu) && (cpu_multi == 1)) regs[0x50] = 0x20; - else if (is486sx2) + else if (!(hasfpu) && (cpu_multi == 2)) regs[0x50] = 0x60; /* Guess based on the SX, DX, and DX2 values. */ - else if (is486dx || isdx4) + else if (hasfpu && (cpu_multi == 1)) regs[0x50] = 0x00; - else if (is486dx2) + else if (hasfpu && (cpu_multi >= 2) && !(cpu_s->cpu_type == CPU_P24T)) regs[0x50] = 0x40; else regs[0x50] = 0x80; /* Pentium OverDrive. */ - if (cpu_busspeed <= 25000000) + /* According to information from FreeBSD 3.x source code: + 00 = 25 MHz, 01 = 33 MHz. */ + if (cpu_busspeed > 25000000) regs[0x50] |= 0x01; - else if ((cpu_busspeed > 25000000) && (cpu_busspeed <= 30000000)) - regs[0x50] |= 0x02; - else if ((cpu_busspeed > 30000000) && (cpu_busspeed <= 33333333)) - regs[0x50] |= 0x03; regs[0x51] = 0x80; - regs[0x52] = 0xea; /* 512 kB burst cache, set to 0xaa for 256 kB */ + /* According to information from FreeBSD 3.x source code: + 0x00 = None, 0x01 = 64 kB, 0x41 = 128 kB, 0x81 = 256 kB, 0xc1 = 512 kB, + If bit 0 is set, then if bit 2 is also set, the cache is write back, + otherwise it's write through. */ + regs[0x52] = 0xc3; /* 512 kB writeback cache */ regs[0x57] = 0x31; regs[0x59] = 0x0f; - regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = 0x02; - dev->max_drb = 5; + regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = 0x02; + dev->max_drb = 3; + dev->drb_unit = 4; dev->drb_default = 0x02; break; case INTEL_430LX: @@ -1319,10 +1370,10 @@ static void regs[0x50] |= 0x01; regs[0x51] = 0x80; regs[0x52] = 0xea; /* 512 kB burst cache, set to 0xaa for 256 kB */ - regs[0x57] = 0x31; regs[0x59] = 0x0f; - regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = 0x02; + regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = 0x02; dev->max_drb = 5; + dev->drb_unit = 1; dev->drb_default = 0x02; break; case INTEL_430NX: @@ -1343,7 +1394,9 @@ static void regs[0x59] = 0x0f; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x02; dev->max_drb = 7; + dev->drb_unit = 1; dev->drb_default = 0x02; + dev->write_drbs = spd_write_drbs_with_ext; break; case INTEL_430FX: regs[0x02] = 0x2d; regs[0x03] = 0x12; /* SB82437FX-66 */ @@ -1358,6 +1411,7 @@ static void regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = 0x02; regs[0x72] = 0x02; dev->max_drb = 4; + dev->drb_unit = 4; dev->drb_default = 0x02; break; case INTEL_430HX: @@ -1372,6 +1426,7 @@ static void regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x02; regs[0x72] = 0x02; dev->max_drb = 7; + dev->drb_unit = 4; dev->drb_default = 0x02; break; case INTEL_430VX: @@ -1393,6 +1448,7 @@ static void regs[0x74] = 0x0e; regs[0x78] = 0x23; dev->max_drb = 4; + dev->drb_unit = 4; dev->drb_default = 0x02; break; case INTEL_430TX: @@ -1410,6 +1466,7 @@ static void regs[0x70] = 0x20; regs[0x72] = 0x02; dev->max_drb = 5; + dev->drb_unit = 4; dev->drb_default = 0x02; break; case INTEL_440FX: @@ -1426,21 +1483,21 @@ static void regs[0x71] = 0x10; regs[0x72] = 0x02; dev->max_drb = 7; + dev->drb_unit = 8; dev->drb_default = 0x02; break; case INTEL_440LX: - dev->max_func = 1; - regs[0x02] = 0x80; regs[0x03] = 0x71; /* 82443LX */ + regs[0x08] = 0x03; regs[0x06] = 0x90; regs[0x10] = 0x08; regs[0x34] = 0xa0; - if (cpu_busspeed <= 66666667) + if (cpu_busspeed <= 60000000) + regs[0x51] |= 0x40; + else if ((cpu_busspeed > 60000000) && (cpu_busspeed <= 66666667)) regs[0x51] |= 0x00; - else if ((cpu_busspeed > 66666667) && (cpu_busspeed <= 100000000)) - regs[0x51] |= 0x20; regs[0x53] = 0x83; - regs[0x57] = 0x28; + regs[0x57] = 0x01; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x01; regs[0x6c] = regs[0x6d] = regs[0x6e] = regs[0x6f] = 0x55; regs[0x72] = 0x02; @@ -1450,21 +1507,18 @@ static void regs[0xa5] = 0x02; regs[0xa7] = 0x1f; dev->max_drb = 7; + dev->drb_unit = 8; dev->drb_default = 0x01; break; case INTEL_440EX: - dev->max_func = 1; - - regs[0x02] = 0x80; regs[0x03] = 0x71; /* 82443EX. Same Vendor ID as 440LX*/ + regs[0x02] = 0x80; regs[0x03] = 0x71; /* 82443EX. Same Vendor ID as 440LX */ + regs[0x08] = 0x03; regs[0x06] = 0x90; regs[0x10] = 0x08; regs[0x34] = 0xa0; - if (cpu_busspeed <= 66666667) - regs[0x51] |= 0x00; - else if ((cpu_busspeed > 66666667) && (cpu_busspeed <= 100000000)) - regs[0x51] |= 0x20; + regs[0x51] = 0x80; regs[0x53] = 0x83; - regs[0x57] = 0x28; + regs[0x57] = 0x01; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x01; regs[0x6c] = regs[0x6d] = regs[0x6e] = regs[0x6f] = 0x55; regs[0x72] = 0x02; @@ -1474,21 +1528,21 @@ static void regs[0xa5] = 0x02; regs[0xa7] = 0x1f; dev->max_drb = 7; + dev->drb_unit = 8; dev->drb_default = 0x01; break; case INTEL_440BX: case INTEL_440ZX: regs[0x7a] = (info->local >> 8) & 0xff; - dev->max_func = (regs[0x7a] & 0x02) ? 0 : 1; regs[0x02] = (regs[0x7a] & 0x02) ? 0x92 : 0x90; regs[0x03] = 0x71; /* 82443BX */ regs[0x06] = (regs[0x7a] & 0x02) ? 0x00 : 0x10; - regs[0x08] = 0x02; + regs[0x08] = (regs[0x7a] & 0x02) ? 0x03 : 0x02; regs[0x10] = 0x08; regs[0x34] = (regs[0x7a] & 0x02) ? 0x00 : 0xa0; if (cpu_busspeed <= 66666667) - regs[0x51] |= 0x00; - else if ((cpu_busspeed > 66666667) && (cpu_busspeed <= 100000000)) regs[0x51] |= 0x20; + else if ((cpu_busspeed > 66666667) && (cpu_busspeed <= 100000000)) + regs[0x51] |= 0x00; regs[0x57] = 0x28; /* 4 DIMMs, SDRAM */ regs[0x58] = 0x03; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x01; @@ -1502,20 +1556,17 @@ static void regs[0xa5] = 0x02; regs[0xa7] = 0x1f; dev->max_drb = 7; + dev->drb_unit = 8; dev->drb_default = 0x01; break; case INTEL_440GX: regs[0x7a] = (info->local >> 8) & 0xff; - dev->max_func = (regs[0x7a] & 0x02) ? 0 : 1; - regs[0x02] = 0xa0; regs[0x03] = 0x71; /* 82443GX */ + regs[0x02] = (regs[0x7a] & 0x02) ? 0xa2 : 0xa0; regs[0x03] = 0x71; /* 82443GX */ regs[0x06] = (regs[0x7a] & 0x02) ? 0x00 : 0x10; - regs[0x08] = 0x02; regs[0x10] = 0x08; regs[0x34] = (regs[0x7a] & 0x02) ? 0x00 : 0xa0; - regs[0x51] |= 0x20; regs[0x57] = 0x28; - regs[0x58] = 0x03; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x01; regs[0x72] = 0x02; regs[0x73] = 0x38; @@ -1527,6 +1578,7 @@ static void regs[0xa5] = 0x02; regs[0xa7] = 0x1f; dev->max_drb = 7; + dev->drb_unit = 8; dev->drb_default = 0x01; break; } @@ -1539,6 +1591,15 @@ static void cpu_update_waitstates(); } + /* Out-of-spec PCI and AGP clocks with overclocked bus. */ + if ((dev->type <= INTEL_440FX) && (cpu_busspeed >= 66666666)) + cpu_set_pci_speed(cpu_busspeed / 2); + + if ((dev->type >= INTEL_440BX) && (cpu_busspeed >= 100000000)) + cpu_set_agp_speed(cpu_busspeed / 1.5); + else if (dev->type >= INTEL_440LX) + cpu_set_agp_speed(cpu_busspeed); + i4x0_write(regs[0x59], 0x59, 0x00, dev); i4x0_write(regs[0x5a], 0x5a, 0x00, dev); i4x0_write(regs[0x5b], 0x5b, 0x00, dev); @@ -1546,264 +1607,252 @@ static void i4x0_write(regs[0x5d], 0x5d, 0x00, dev); i4x0_write(regs[0x5e], 0x5e, 0x00, dev); i4x0_write(regs[0x5f], 0x5f, 0x00, dev); - i4x0_write(regs[0x72], 0x72, 0x00, dev); - if (((dev->type == INTEL_440LX) || (dev->type == INTEL_440EX)) && (dev->max_func == 1)) { - regs = (uint8_t *) dev->regs[1]; + if (dev->type >= INTEL_430FX) + i4x0_write(0, 0x72, 0x02, dev); + else if (dev->type >= INTEL_430LX) + i4x0_write(0, 0x72, 0x00, dev); + else + i4x0_write(0, 0x57, 0x02, dev); - regs[0x00] = 0x86; regs[0x01] = 0x80; /* Intel */ - regs[0x02] = 0x81; regs[0x03] = 0x71; /* 82443LX */ - regs[0x06] = 0xa0; regs[0x07] = 0x02; - regs[0x0a] = 0x04; regs[0x0b] = 0x06; - regs[0x0e] = 0x01; - regs[0x1c] = 0xf0; - regs[0x1e] = 0xa0; regs[0x1f] = 0x02; - regs[0x20] = 0xf0; regs[0x21] = 0xff; - regs[0x24] = 0xf0; regs[0x25] = 0xff; - } - - if (((dev->type == INTEL_440BX) || (dev->type == INTEL_440GX) || (dev->type == INTEL_440ZX)) && (dev->max_func == 1)) { - regs = (uint8_t *) dev->regs[1]; - - regs[0x00] = 0x86; regs[0x01] = 0x80; /* Intel */ - if(dev->type != INTEL_440GX){ - regs[0x02] = 0x91; regs[0x03] = 0x71; /* 82443BX */ - } else { - regs[0x02] = 0xa1; regs[0x03] = 0x71; /* 82443GX (They seem to share the same deal*/ - } - regs[0x06] = 0x20; regs[0x07] = 0x02; - regs[0x08] = 0x02; - regs[0x0a] = 0x04; regs[0x0b] = 0x06; - regs[0x0e] = 0x01; - regs[0x1c] = 0xf0; - regs[0x1e] = 0xa0; regs[0x1f] = 0x02; - regs[0x20] = 0xf0; regs[0x21] = 0xff; - regs[0x24] = 0xf0; regs[0x25] = 0xff; - regs[0x3e] = 0x80; + if ((dev->type == INTEL_430TX) || (dev->type >= INTEL_440BX)) { + i4x0_write(0, (dev->type >= INTEL_440BX) ? 0x73 : 0x71, + (dev->type >= INTEL_440BX) ? 0x38 : 0x00, dev); } pci_add_card(PCI_ADD_NORTHBRIDGE, i4x0_read, i4x0_write, dev); + if ((dev->type >= INTEL_440BX) && !(regs[0x7a] & 0x02)) { + device_add((dev->type == INTEL_440GX) ? &i440gx_agp_device : &i440bx_agp_device); + dev->agpgart = device_add(&agpgart_device); + } else if (dev->type >= INTEL_440LX) { + device_add(&i440lx_agp_device); + dev->agpgart = device_add(&agpgart_device); + } + return dev; } - -const device_t i420tx_device = -{ - "Intel 82424TX", - DEVICE_PCI, - INTEL_420TX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i420tx_device = { + .name = "Intel 82424TX", + .internal_name = "i420tx", + .flags = DEVICE_PCI, + .local = INTEL_420TX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i420zx_device = -{ - "Intel 82424ZX", - DEVICE_PCI, - INTEL_420ZX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i420zx_device = { + .name = "Intel 82424ZX", + .internal_name = "i420zx", + .flags = DEVICE_PCI, + .local = INTEL_420ZX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430lx_device = -{ - "Intel 82434LX", - DEVICE_PCI, - INTEL_430LX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430lx_device = { + .name = "Intel 82434LX", + .internal_name = "i430lx", + .flags = DEVICE_PCI, + .local = INTEL_430LX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430nx_device = -{ - "Intel 82434NX", - DEVICE_PCI, - INTEL_430NX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430nx_device = { + .name = "Intel 82434NX", + .internal_name = "i430nx", + .flags = DEVICE_PCI, + .local = INTEL_430NX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430fx_device = -{ - "Intel SB82437FX-66", - DEVICE_PCI, - INTEL_430FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430fx_device = { + .name = "Intel SB82437FX-66", + .internal_name = "i430fx", + .flags = DEVICE_PCI, + .local = INTEL_430FX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430fx_rev02_device = -{ - "Intel SB82437FX-66 (Rev. 02)", - DEVICE_PCI, - 0x0200 | INTEL_430FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430fx_rev02_device = { + .name = "Intel SB82437FX-66 (Rev. 02)", + .internal_name = "i430fx_rev02", + .flags = DEVICE_PCI, + .local = 0x0200 | INTEL_430FX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430hx_device = -{ - "Intel 82439HX", - DEVICE_PCI, - INTEL_430HX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430hx_device = { + .name = "Intel 82439HX", + .internal_name = "i430hx", + .flags = DEVICE_PCI, + .local = INTEL_430HX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430vx_device = -{ - "Intel 82437VX", - DEVICE_PCI, - INTEL_430VX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430vx_device = { + .name = "Intel 82437VX", + .internal_name = "i430vx", + .flags = DEVICE_PCI, + .local = INTEL_430VX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i430tx_device = -{ - "Intel 82439TX", - DEVICE_PCI, - INTEL_430TX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i430tx_device = { + .name = "Intel 82439TX", + .internal_name = "i430tx", + .flags = DEVICE_PCI, + .local = INTEL_430TX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i440fx_device = -{ - "Intel 82441FX", - DEVICE_PCI, - INTEL_440FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i440fx_device = { + .name = "Intel 82441FX", + .internal_name = "i440fx", + .flags = DEVICE_PCI, + .local = INTEL_440FX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t i440lx_device = -{ - "Intel 82443LX", - DEVICE_PCI, - INTEL_440LX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i440lx_device = { + .name = "Intel 82443LX", + .internal_name = "i440lx", + .flags = DEVICE_PCI, + .local = INTEL_440LX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t i440ex_device = -{ - "Intel 82443EX", - DEVICE_PCI, - INTEL_440EX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i440ex_device = { + .name = "Intel 82443EX", + .internal_name = "i440ex", + .flags = DEVICE_PCI, + .local = INTEL_440EX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i440bx_device = -{ - "Intel 82443BX", - DEVICE_PCI, - 0x8000 | INTEL_440BX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i440bx_device = { + .name = "Intel 82443BX", + .internal_name = "i440bx", + .flags = DEVICE_PCI, + .local = 0x8000 | INTEL_440BX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t i440gx_device = -{ - "Intel 82443GX", - DEVICE_PCI, - 0x8000 | INTEL_440GX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i440bx_no_agp_device = { + .name = "Intel 82443BX", + .internal_name = "i440bx_no_agp", + .flags = DEVICE_PCI, + .local = 0x8200 | INTEL_440BX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t i440zx_device = -{ - "Intel 82443ZX", - DEVICE_PCI, - 0x8000 | INTEL_440ZX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL +const device_t i440gx_device = { + .name = "Intel 82443GX", + .internal_name = "i440gx", + .flags = DEVICE_PCI, + .local = 0x8000 | INTEL_440GX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i440zx_device = { + .name = "Intel 82443ZX", + .internal_name = "i440zx", + .flags = DEVICE_PCI, + .local = 0x8000 | INTEL_440ZX, + .init = i4x0_init, + .close = i4x0_close, + .reset = i4x0_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/intel_82335.c b/src/chipset/intel_82335.c new file mode 100644 index 000000000..2c018d3ef --- /dev/null +++ b/src/chipset/intel_82335.c @@ -0,0 +1,211 @@ +/* + * 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 Intel 82335(KU82335) chipset. + * + * Copyright 2021 Tiseno100 + * + */ + +#include +#include +#include +#include +#include +#include +#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> + +/* Shadow capabilities */ +#define DISABLED_SHADOW (MEM_READ_EXTANY | MEM_WRITE_EXTANY) +#define ENABLED_SHADOW ((LOCK_STATUS) ? RO_SHADOW : RW_SHADOW) +#define RW_SHADOW (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) +#define RO_SHADOW (MEM_READ_INTERNAL | MEM_WRITE_DISABLED) + +/* Granularity Register Enable & Recalc */ +#define EXTENDED_GRANULARITY_ENABLED (dev->regs[0x2c] & 0x01) +#define GRANULARITY_RECALC ((dev->regs[0x2e] & (1 << (i + 8))) ? ((dev->regs[0x2e] & (1 << i)) ? RO_SHADOW : RW_SHADOW) : DISABLED_SHADOW) + +/* R/W operator for the Video RAM region */ +#define DETERMINE_VIDEO_RAM_WRITE_ACCESS ((dev->regs[0x22] & (0x08 << 8)) ? RW_SHADOW : RO_SHADOW) + +/* Base System 512/640KB switch */ +#define ENABLE_TOP_128KB (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) +#define DISABLE_TOP_128KB (MEM_READ_EXTANY | MEM_WRITE_EXTANY) + +/* ROM size determination */ +#define ROM_SIZE ((dev->regs[0x22] & (0x01 << 8)) ? 0xe0000 : 0xf0000) + +/* Lock status */ +#define LOCK_STATUS (dev->regs[0x22] & (0x80 << 8)) + +/* Define Memory Remap Sizes */ +#define DEFINE_RC1_REMAP_SIZE ((dev->regs[0x24] & 0x02) ? 128 : 256) +#define DEFINE_RC2_REMAP_SIZE ((dev->regs[0x26] & 0x02) ? 128 : 256) + +typedef struct +{ + + uint16_t regs[256], + + cfg_locked; + +} intel_82335_t; + +#ifdef ENABLE_INTEL_82335_LOG +int intel_82335_do_log = ENABLE_INTEL_82335_LOG; +static void +intel_82335_log(const char *fmt, ...) +{ + va_list ap; + + if (intel_82335_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define intel_82335_log(fmt, ...) +#endif + +static void +intel_82335_write(uint16_t addr, uint16_t val, void *priv) +{ + intel_82335_t *dev = (intel_82335_t *)priv; + uint32_t romsize = 0, base = 0, i = 0, rc1_remap = 0, rc2_remap = 0; + + dev->regs[addr] = val; + + if (!dev->cfg_locked) + { + + intel_82335_log("Register %02x: Write %04x\n", addr, val); + + switch (addr) + { + case 0x22: /* Memory Controller */ + + /* Check if the ROM chips are 256 or 512Kbit (Just for Shadowing sanity) */ + romsize = ROM_SIZE; + + if (!EXTENDED_GRANULARITY_ENABLED) + { + shadowbios = !!(dev->regs[0x22] & 0x01); + shadowbios_write = !!(dev->regs[0x22] & 0x01); + + /* Base System 512/640KB set */ + mem_set_mem_state_both(0x80000, 0x20000, (dev->regs[0x22] & 0x08) ? ENABLE_TOP_128KB : DISABLE_TOP_128KB); + + /* Video RAM shadow*/ + mem_set_mem_state_both(0xa0000, 0x20000, (dev->regs[0x22] & (0x04 << 8)) ? DETERMINE_VIDEO_RAM_WRITE_ACCESS : DISABLED_SHADOW); + + /* Option ROM shadow */ + mem_set_mem_state_both(0xc0000, 0x20000, (dev->regs[0x22] & (0x02 << 8)) ? ENABLED_SHADOW : DISABLED_SHADOW); + + /* System ROM shadow */ + mem_set_mem_state_both(0xe0000, 0x20000, (dev->regs[0x22] & 0x01) ? ENABLED_SHADOW : DISABLED_SHADOW); + } + break; + + case 0x24: /* Roll Compare (Just top remapping. Not followed according to datasheet!) */ + case 0x26: + rc1_remap = (dev->regs[0x24] & 0x01) ? DEFINE_RC1_REMAP_SIZE : 0; + rc2_remap = (dev->regs[0x26] & 0x01) ? DEFINE_RC2_REMAP_SIZE : 0; + mem_remap_top(rc1_remap + rc2_remap); + break; + + case 0x2e: /* Extended Granularity (Enabled if Bit 0 in Register 2Ch is set) */ + if (EXTENDED_GRANULARITY_ENABLED) + { + for (i = 0; i < 8; i++) + { + base = 0xc0000 + (i << 15); + shadowbios = (dev->regs[0x2e] & (1 << (i + 8))) && (base == romsize); + shadowbios_write = (dev->regs[0x2e] & (1 << i)) && (base == romsize); + mem_set_mem_state_both(base, 0x8000, GRANULARITY_RECALC); + } + break; + } + } + } + + /* Unlock/Lock configuration registers */ + dev->cfg_locked = LOCK_STATUS; +} + +static uint16_t +intel_82335_read(uint16_t addr, void *priv) +{ + intel_82335_t *dev = (intel_82335_t *)priv; + + intel_82335_log("Register %02x: Read %04x\n", addr, dev->regs[addr]); + + return dev->regs[addr]; +} + +static void +intel_82335_close(void *priv) +{ + intel_82335_t *dev = (intel_82335_t *)priv; + + free(dev); +} + +static void * +intel_82335_init(const device_t *info) +{ + intel_82335_t *dev = (intel_82335_t *)malloc(sizeof(intel_82335_t)); + memset(dev, 0, sizeof(intel_82335_t)); + + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->regs[0x28] = 0xf9; + + dev->cfg_locked = 0; + + /* Memory Configuration */ + io_sethandler(0x0022, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + + /* Roll Comparison */ + io_sethandler(0x0024, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + io_sethandler(0x0026, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + + /* Address Range Comparison */ + io_sethandler(0x0028, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + io_sethandler(0x002a, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + + /* Granularity Enable */ + io_sethandler(0x002c, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + + /* Extended Granularity */ + io_sethandler(0x002e, 0x0001, NULL, intel_82335_read, NULL, NULL, intel_82335_write, NULL, dev); + + return dev; +} + +const device_t intel_82335_device = { + .name = "Intel 82335", + .internal_name = "intel_82335", + .flags = 0, + .local = 0, + .init = intel_82335_init, + .close = intel_82335_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/intel_i450kx.c b/src/chipset/intel_i450kx.c new file mode 100644 index 000000000..ad92218f8 --- /dev/null +++ b/src/chipset/intel_i450kx.c @@ -0,0 +1,821 @@ +/* + * 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 Intel 450KX Mars Chipset. + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + */ + +/* +Note: i450KX PB manages PCI memory access with MC manages DRAM memory access. +Due to 86Box limitations we can't manage them seperately thus it is dev branch till then. + +i450GX is way more popular of an option but needs more stuff. +*/ + +#include +#include +#include +#include +#include +#include +#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/pci.h> +#include <86box/smram.h> +#include <86box/spd.h> +#include <86box/chipset.h> + + +#ifdef ENABLE_450KX_LOG +int i450kx_do_log = ENABLE_450KX_LOG; +static void +i450kx_log(const char *fmt, ...) +{ + va_list ap; + + if (i450kx_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i450kx_log(fmt, ...) +#endif + + +/* TODO: Finish the bus index stuff. */ +typedef struct i450kx_t { + smram_t * smram[2]; + + uint8_t pb_pci_conf[256], mc_pci_conf[256]; + uint8_t mem_state[2][256]; + + uint8_t bus_index; +} i450kx_t; + + +static void +i450kx_map(i450kx_t *dev, int bus, uint32_t addr, uint32_t size, int state) +{ + uint32_t base = addr >> 12; + int states[4] = { MEM_READ_EXTANY | MEM_WRITE_EXTANY, MEM_READ_INTERNAL | MEM_WRITE_EXTANY, + MEM_READ_EXTANY | MEM_WRITE_INTERNAL, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL }; + + state &= 3; + if (dev->mem_state[bus][base] != state) { + if (bus) + mem_set_mem_state_bus_both(addr, size, states[state]); + else + mem_set_mem_state_cpu_both(addr, size, states[state]); + dev->mem_state[bus][base] = state; + flushmmucache_nopc(); + } +} + + +static void +i450kx_smram_recalc(i450kx_t *dev, int bus) +{ + uint8_t *regs = bus ? dev->pb_pci_conf : dev->mc_pci_conf; + uint32_t addr, size; + + smram_disable(dev->smram[bus]); + + addr = ((uint32_t) regs[0xb8] << 16) | ((uint32_t) regs[0xb9] << 24); + size = (((uint32_t) ((regs[0xbb] >> 4) & 0x0f)) << 16) + 0x00010000; + + if ((addr != 0x00000000) && !!(regs[0x57] & 0x08)) { + if (bus) + smram_enable_ex(dev->smram[bus], addr, addr, size, 0, !!(regs[0x57] & 8), 0, 1); + else + smram_enable_ex(dev->smram[bus], addr, addr, size, !!(regs[0x57] & 8), 0, 1, 0); + } + + flushmmucache(); +} + + +static void +i450kx_vid_buf_recalc(i450kx_t *dev, int bus) +{ + uint8_t *regs = bus ? dev->pb_pci_conf : dev->mc_pci_conf; + + // int state = (regs[0x58] & 0x02) ? (MEM_READ_EXTANY | MEM_WRITE_EXTANY) : (MEM_READ_DISABLED | MEM_WRITE_DISABLED); + int state = (regs[0x58] & 0x02) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + if (bus) + mem_set_mem_state_bus_both(0x000a0000, 0x00020000, state); + else + mem_set_mem_state_cpu_both(0x000a0000, 0x00020000, state); + + flushmmucache_nopc(); +} + + +static void +pb_write(int func, int addr, uint8_t val, void *priv) +{ + i450kx_t *dev = (i450kx_t *)priv; + + // pclog("i450KX-PB: [W] dev->pb_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + i450kx_log("i450KX-PB: [W] dev->pb_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + + if (func == 0) switch (addr) { + case 0x04: + dev->pb_pci_conf[addr] = (dev->pb_pci_conf[addr] & 0x04) | (val & 0x53); + break; + case 0x05: + dev->pb_pci_conf[addr] = val & 0x01; + break; + + case 0x07: + dev->pb_pci_conf[addr] &= ~(val & 0xf9); + break; + + case 0x0d: + dev->pb_pci_conf[addr] = val; + break; + + case 0x0f: + dev->pb_pci_conf[addr] = val & 0xcf; + break; + + case 0x40: case 0x41: + dev->pb_pci_conf[addr] = val; + break; + case 0x43: + dev->pb_pci_conf[addr] = val & 0x80; + break; + + case 0x48: + dev->pb_pci_conf[addr] = val & 0x06; + break; + + case 0x4a: case 0x4b: + dev->pb_pci_conf[addr] = val; + // if (addr == 0x4a) + // pci_remap_bus(dev->bus_index, val); + break; + + case 0x4c: + dev->pb_pci_conf[addr] = (dev->pb_pci_conf[addr] & 0x01) | (val & 0xd8); + break; + + case 0x51: + dev->pb_pci_conf[addr] = val; + break; + + case 0x53: + dev->pb_pci_conf[addr] = val & 0x02; + break; + + case 0x54: + dev->pb_pci_conf[addr] = val & 0x7b; + break; + case 0x55: + dev->pb_pci_conf[addr] = val & 0x03; + break; + + case 0x57: + dev->pb_pci_conf[addr] = val & 0x08; + i450kx_smram_recalc(dev, 1); + break; + + case 0x58: + dev->pb_pci_conf[addr] = val & 0x02; + i450kx_vid_buf_recalc(dev, 1); + break; + + case 0x59: /* PAM0 */ + if ((dev->pb_pci_conf[0x59] ^ val) & 0x0f) + i450kx_map(dev, 1, 0x80000, 0x20000, val & 0x0f); + if ((dev->pb_pci_conf[0x59] ^ val) & 0xf0) { + i450kx_map(dev, 1, 0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + dev->pb_pci_conf[0x59] = val & 0x33; + break; + case 0x5a: /* PAM1 */ + if ((dev->pb_pci_conf[0x5a] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xc0000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5a] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xc4000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5a] = val & 0x33; + break; + case 0x5b: /*PAM2 */ + if ((dev->pb_pci_conf[0x5b] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xc8000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5b] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xcc000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5b] = val & 0x33; + break; + case 0x5c: /*PAM3 */ + if ((dev->pb_pci_conf[0x5c] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xd0000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5c] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xd4000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5c] = val & 0x33; + break; + case 0x5d: /* PAM4 */ + if ((dev->pb_pci_conf[0x5d] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xd8000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5d] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xdc000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5d] = val & 0x33; + break; + case 0x5e: /* PAM5 */ + if ((dev->pb_pci_conf[0x5e] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xe0000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5e] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xe4000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5e] = val & 0x33; + break; + case 0x5f: /* PAM6 */ + if ((dev->pb_pci_conf[0x5f] ^ val) & 0x0f) + i450kx_map(dev, 1, 0xe8000, 0x04000, val & 0xf); + if ((dev->pb_pci_conf[0x5f] ^ val) & 0xf0) + i450kx_map(dev, 1, 0xec000, 0x04000, val >> 4); + dev->pb_pci_conf[0x5f] = val & 0x33; + break; + + case 0x70: + dev->pb_pci_conf[addr] = val & 0xf8; + break; + + case 0x71: + dev->pb_pci_conf[addr] = val & 0x71; + break; + + case 0x78: + dev->pb_pci_conf[addr] = val & 0xf0; + break; + case 0x79: + dev->pb_pci_conf[addr] = val & 0xfc; + break; + case 0x7a: + dev->pb_pci_conf[addr] = val; + break; + case 0x7b: + dev->pb_pci_conf[addr] = val & 0x0f; + break; + + case 0x7c: + dev->pb_pci_conf[addr] = val & 0x9f; + break; + case 0x7d: + dev->pb_pci_conf[addr] = val & 0x1a; + break; + case 0x7e: + dev->pb_pci_conf[addr] = val & 0xf0; + break; + case 0x7f: + dev->pb_pci_conf[addr] = val; + break; + + case 0x88: case 0x89: + dev->pb_pci_conf[addr] = val; + break; + case 0x8b: + dev->pb_pci_conf[addr] = val & 0x80; + break; + case 0x8c: case 0x8d: + dev->pb_pci_conf[addr] = val; + break; + + case 0x9c: + dev->pb_pci_conf[addr] = val & 0x01; + break; + + case 0xa4: + dev->pb_pci_conf[addr] = val & 0xf8; + break; + case 0xa5: case 0xa6: + dev->pb_pci_conf[addr] = val; + break; + case 0xa7: + dev->pb_pci_conf[addr] = val & 0x0f; + break; + + case 0xb0: + dev->pb_pci_conf[addr] = val & 0xe0; + break; + case 0xb1: + dev->pb_pci_conf[addr] = val & /*0x1a*/ 0x1f; + break; + + case 0xb4: + dev->pb_pci_conf[addr] = val & 0xe0; + break; + case 0xb5: + dev->pb_pci_conf[addr] = val & 0x1f; + break; + + case 0xb8: case 0xb9: + dev->pb_pci_conf[addr] = val; + i450kx_smram_recalc(dev, 1); + break; + case 0xbb: + dev->pb_pci_conf[addr] = val & 0xf0; + i450kx_smram_recalc(dev, 1); + break; + + case 0xbc: + dev->pb_pci_conf[addr] = val & 0x11; + break; + + case 0xc0: + dev->pb_pci_conf[addr] = val & 0xdf; + break; + case 0xc1: + dev->pb_pci_conf[addr] = val & 0x3f; + break; + + case 0xc4: + dev->pb_pci_conf[addr] &= ~(val & 0x0f); + break; + case 0xc5: + dev->pb_pci_conf[addr] &= ~(val & 0x0a); + break; + case 0xc6: + dev->pb_pci_conf[addr] &= ~(val & 0x1f); + break; + + case 0xc8: + dev->pb_pci_conf[addr] = val & 0x1f; + break; + + case 0xca: + case 0xcb: + dev->pb_pci_conf[addr] = val; + break; + } +} + + +static uint8_t +pb_read(int func, int addr, void *priv) +{ + i450kx_t *dev = (i450kx_t *)priv; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->pb_pci_conf[addr]; + + // pclog("i450KX-PB: [R] dev->pb_pci_conf[%02X] = %02X POST: %02X\n", addr, ret, inb(0x80)); + + return ret; +} + + +/* A way to use spd_write_drbs_interlaved() and convert the output to what we need. */ +static void +mc_fill_drbs(i450kx_t *dev) +{ + int i; + + spd_write_drbs_interleaved(dev->mc_pci_conf, 0x60, 0x6f, 4); + for (i = 0x60; i <= 0x6f; i++) { + if (i & 0x01) + dev->mc_pci_conf[i] = 0x00; + else + dev->mc_pci_conf[i] &= 0x7f; + } +} + + +static void +mc_write(int func, int addr, uint8_t val, void *priv) +{ + i450kx_t *dev = (i450kx_t *)priv; + + // pclog("i450KX-MC: [W] dev->mc_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + i450kx_log("i450KX-MC: [W] dev->mc_pci_conf[%02X] = %02X POST: %02X\n", addr, val, inb(0x80)); + + if (func == 0) switch (addr) { + case 0x4c: + dev->mc_pci_conf[addr] = val & 0xdf; + break; + case 0x4d: + dev->mc_pci_conf[addr] = val & 0xff; + break; + + case 0x57: + dev->mc_pci_conf[addr] = val & 0x08; + i450kx_smram_recalc(dev, 0); + break; + + case 0x58: + dev->mc_pci_conf[addr] = val & 0x02; + i450kx_vid_buf_recalc(dev, 0); + break; + + case 0x59: /* PAM0 */ + if ((dev->mc_pci_conf[0x59] ^ val) & 0x0f) + i450kx_map(dev, 0, 0x80000, 0x20000, val & 0x0f); + if ((dev->mc_pci_conf[0x59] ^ val) & 0xf0) { + i450kx_map(dev, 0, 0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + dev->mc_pci_conf[0x59] = val & 0x33; + break; + case 0x5a: /* PAM1 */ + if ((dev->mc_pci_conf[0x5a] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xc0000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5a] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xc4000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5a] = val & 0x33; + break; + case 0x5b: /*PAM2 */ + if ((dev->mc_pci_conf[0x5b] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xc8000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5b] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xcc000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5b] = val & 0x33; + break; + case 0x5c: /*PAM3 */ + if ((dev->mc_pci_conf[0x5c] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xd0000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5c] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xd4000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5c] = val & 0x33; + break; + case 0x5d: /* PAM4 */ + if ((dev->mc_pci_conf[0x5d] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xd8000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5d] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xdc000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5d] = val & 0x33; + break; + case 0x5e: /* PAM5 */ + if ((dev->mc_pci_conf[0x5e] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xe0000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5e] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xe4000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5e] = val & 0x33; + break; + case 0x5f: /* PAM6 */ + if ((dev->mc_pci_conf[0x5f] ^ val) & 0x0f) + i450kx_map(dev, 0, 0xe8000, 0x04000, val & 0xf); + if ((dev->mc_pci_conf[0x5f] ^ val) & 0xf0) + i450kx_map(dev, 0, 0xec000, 0x04000, val >> 4); + dev->mc_pci_conf[0x5f] = val & 0x33; + break; + + case 0x60 ... 0x6f: + dev->mc_pci_conf[addr] = ((addr & 0x0f) & 0x01) ? 0x00 : (val & 0x7f); + mc_fill_drbs(dev); + break; + + case 0x74 ... 0x77: + dev->mc_pci_conf[addr] = val; + break; + + case 0x78: + dev->mc_pci_conf[addr] = val & 0xf0; + break; + case 0x79: + dev->mc_pci_conf[addr] = val & 0xfe; + break; + case 0x7a: + dev->mc_pci_conf[addr] = val; + break; + case 0x7b: + dev->mc_pci_conf[addr] = val & 0x0f; + break; + + case 0x7c: + dev->mc_pci_conf[addr] = val & 0x1f; + break; + case 0x7d: + dev->mc_pci_conf[addr] = val & 0x0c; + break; + case 0x7e: + dev->mc_pci_conf[addr] = val & 0xf0; + break; + case 0x7f: + dev->mc_pci_conf[addr] = val; + break; + + case 0x88: case 0x89: + dev->mc_pci_conf[addr] = val; + break; + case 0x8b: + dev->mc_pci_conf[addr] = val & 0x80; + break; + + case 0x8c: case 0x8d: + dev->mc_pci_conf[addr] = val; + break; + + case 0xa4: + dev->mc_pci_conf[addr] = val & 0x01; + break; + case 0xa5: + dev->pb_pci_conf[addr] = val & 0xf0; + break; + case 0xa6: + dev->mc_pci_conf[addr] = val; + break; + case 0xa7: + dev->mc_pci_conf[addr] = val & 0x0f; + break; + + case 0xa8: + dev->mc_pci_conf[addr] = val & 0xfe; + break; + case 0xa9 ... 0xab: + dev->mc_pci_conf[addr] = val; + break; + + case 0xac ... 0xae: + dev->mc_pci_conf[addr] = val; + break; + case 0xaf: + dev->mc_pci_conf[addr] = val & 0x7f; + break; + + case 0xb8: case 0xb9: + dev->mc_pci_conf[addr] = val; + i450kx_smram_recalc(dev, 0); + break; + case 0xbb: + dev->mc_pci_conf[addr] = val & 0xf0; + i450kx_smram_recalc(dev, 0); + break; + + case 0xbc: + dev->mc_pci_conf[addr] = val & 0x01; + break; + + case 0xc0: + dev->mc_pci_conf[addr] = val & 0x07; + break; + + case 0xc2: + dev->mc_pci_conf[addr] &= ~(val & 0x03); + break; + + case 0xc4: + dev->mc_pci_conf[addr] = val & 0xbf; + break; + case 0xc5: + dev->mc_pci_conf[addr] = val & 0x03; + break; + + case 0xc6: + dev->mc_pci_conf[addr] &= ~(val & 0x19); + break; + + case 0xc8: + dev->mc_pci_conf[addr] = val & 0x1f; + break; + case 0xca: case 0xcb: + dev->mc_pci_conf[addr] = val; + break; + } +} + + +static uint8_t +mc_read(int func, int addr, void *priv) +{ + i450kx_t *dev = (i450kx_t *)priv; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->mc_pci_conf[addr]; + + // pclog("i450KX-MC: [R] dev->mc_pci_conf[%02X] = %02X POST: %02X\n", addr, ret, inb(0x80)); + + return ret; +} + + +static void +i450kx_reset(void *priv) +{ + i450kx_t *dev = (i450kx_t *)priv; + uint32_t i; + + // pclog("i450KX: i450kx_reset()\n"); + + /* Defaults PB */ + dev->pb_pci_conf[0x00] = 0x86; + dev->pb_pci_conf[0x01] = 0x80; + dev->pb_pci_conf[0x02] = 0xc4; + dev->pb_pci_conf[0x03] = 0x84; + dev->pb_pci_conf[0x04] = 0x07; + dev->pb_pci_conf[0x05] = 0x00; + dev->pb_pci_conf[0x06] = 0x40; + dev->pb_pci_conf[0x07] = 0x02; + dev->pb_pci_conf[0x08] = 0x02; + dev->pb_pci_conf[0x09] = 0x00; + dev->pb_pci_conf[0x0a] = 0x00; + dev->pb_pci_conf[0x0b] = 0x06; + dev->pb_pci_conf[0x0c] = 0x08; + dev->pb_pci_conf[0x0d] = 0x20; + dev->pb_pci_conf[0x0e] = 0x00; + dev->pb_pci_conf[0x0f] = 0x00; + dev->pb_pci_conf[0x40] = 0x00; + dev->pb_pci_conf[0x41] = 0x00; + dev->pb_pci_conf[0x42] = 0x00; + dev->pb_pci_conf[0x43] = 0x00; + dev->pb_pci_conf[0x48] = 0x06; + dev->pb_pci_conf[0x49] = 0x19; + dev->pb_pci_conf[0x4a] = 0x00; + dev->pb_pci_conf[0x4b] = 0x00; + dev->pb_pci_conf[0x4c] = 0x19; + dev->pb_pci_conf[0x51] = 0x80; + dev->pb_pci_conf[0x53] = 0x00; + dev->pb_pci_conf[0x54] = 0x00; + dev->pb_pci_conf[0x55] = 0x00; + dev->pb_pci_conf[0x57] = 0x00; + dev->pb_pci_conf[0x58] = 0x02; + dev->pb_pci_conf[0x70] = 0x00; + dev->pb_pci_conf[0x71] = 0x00; + dev->pb_pci_conf[0x78] = 0x00; + dev->pb_pci_conf[0x79] = 0x00; + dev->pb_pci_conf[0x7a] = 0x00; + dev->pb_pci_conf[0x7b] = 0x00; + dev->pb_pci_conf[0x7c] = 0x00; + dev->pb_pci_conf[0x7d] = 0x00; + dev->pb_pci_conf[0x7e] = 0x00; + dev->pb_pci_conf[0x7f] = 0x00; + dev->pb_pci_conf[0x88] = 0x00; + dev->pb_pci_conf[0x89] = 0x00; + dev->pb_pci_conf[0x8a] = 0x00; + dev->pb_pci_conf[0x8b] = 0x00; + dev->pb_pci_conf[0x8c] = 0x00; + dev->pb_pci_conf[0x8d] = 0x00; + dev->pb_pci_conf[0x8e] = 0x00; + dev->pb_pci_conf[0x8f] = 0x00; + dev->pb_pci_conf[0x9c] = 0x00; + dev->pb_pci_conf[0xa4] = 0x01; + dev->pb_pci_conf[0xa5] = 0xc0; + dev->pb_pci_conf[0xa6] = 0xfe; + dev->pb_pci_conf[0xa7] = 0x00; + /* Note: Do NOT reset these two registers on programmed (TRC) hard reset! */ + // dev->pb_pci_conf[0xb0] = 0x00; + // dev->pb_pci_conf[0xb1] = 0x00; + dev->pb_pci_conf[0xb4] = 0x00; + dev->pb_pci_conf[0xb5] = 0x00; + dev->pb_pci_conf[0xb8] = 0x05; + dev->pb_pci_conf[0xb9] = 0x00; + dev->pb_pci_conf[0xba] = 0x00; + dev->pb_pci_conf[0xbb] = 0x00; + dev->pb_pci_conf[0xbc] = 0x01; + dev->pb_pci_conf[0xc0] = 0x02; + dev->pb_pci_conf[0xc1] = 0x00; + dev->pb_pci_conf[0xc2] = 0x00; + dev->pb_pci_conf[0xc3] = 0x00; + dev->pb_pci_conf[0xc4] = 0x00; + dev->pb_pci_conf[0xc5] = 0x00; + dev->pb_pci_conf[0xc6] = 0x00; + dev->pb_pci_conf[0xc7] = 0x00; + dev->pb_pci_conf[0xc8] = 0x03; + dev->pb_pci_conf[0xc9] = 0x00; + dev->pb_pci_conf[0xca] = 0x00; + dev->pb_pci_conf[0xcb] = 0x00; + + // pci_remap_bus(dev->bus_index, 0x00); + i450kx_smram_recalc(dev, 1); + i450kx_vid_buf_recalc(dev, 1); + pb_write(0, 0x59, 0x30, dev); + for (i = 0x5a; i <= 0x5f; i++) + pb_write(0, i, 0x33, dev); + + /* Defaults MC */ + dev->mc_pci_conf[0x00] = 0x86; + dev->mc_pci_conf[0x01] = 0x80; + dev->mc_pci_conf[0x02] = 0xc5; + dev->mc_pci_conf[0x03] = 0x84; + dev->mc_pci_conf[0x04] = 0x00; + dev->mc_pci_conf[0x05] = 0x00; + dev->mc_pci_conf[0x06] = 0x80; + dev->mc_pci_conf[0x07] = 0x00; + dev->mc_pci_conf[0x08] = 0x04; + dev->mc_pci_conf[0x09] = 0x00; + dev->mc_pci_conf[0x0a] = 0x00; + dev->mc_pci_conf[0x0b] = 0x05; + dev->mc_pci_conf[0x49] = 0x14; + dev->mc_pci_conf[0x4c] = 0x0b; + dev->mc_pci_conf[0x4d] = 0x08; + dev->mc_pci_conf[0x4e] = 0x00; + dev->mc_pci_conf[0x4f] = 0x00; + dev->mc_pci_conf[0x57] = 0x00; + dev->mc_pci_conf[0x58] = 0x00; + dev->mc_pci_conf[0x74] = 0x00; + dev->mc_pci_conf[0x75] = 0x00; + dev->mc_pci_conf[0x76] = 0x00; + dev->mc_pci_conf[0x77] = 0x00; + dev->mc_pci_conf[0x78] = 0x10; + dev->mc_pci_conf[0x79] = 0x00; + dev->mc_pci_conf[0x7a] = 0x00; + dev->mc_pci_conf[0x7b] = 0x00; + dev->mc_pci_conf[0x7c] = 0x00; + dev->mc_pci_conf[0x7d] = 0x00; + dev->mc_pci_conf[0x7e] = 0x10; + dev->mc_pci_conf[0x7f] = 0x00; + dev->mc_pci_conf[0x88] = 0x00; + dev->mc_pci_conf[0x89] = 0x00; + dev->mc_pci_conf[0x8a] = 0x00; + dev->mc_pci_conf[0x8b] = 0x00; + dev->mc_pci_conf[0x8c] = 0x00; + dev->mc_pci_conf[0x8d] = 0x00; + dev->mc_pci_conf[0x8e] = 0x00; + dev->mc_pci_conf[0x8f] = 0x00; + dev->mc_pci_conf[0xa4] = 0x01; + dev->mc_pci_conf[0xa5] = 0xc0; + dev->mc_pci_conf[0xa6] = 0xfe; + dev->mc_pci_conf[0xa7] = 0x00; + dev->mc_pci_conf[0xa8] = 0x00; + dev->mc_pci_conf[0xa9] = 0x00; + dev->mc_pci_conf[0xaa] = 0x00; + dev->mc_pci_conf[0xab] = 0x00; + dev->mc_pci_conf[0xac] = 0x16; + dev->mc_pci_conf[0xad] = 0x35; + dev->mc_pci_conf[0xae] = 0xdf; + dev->mc_pci_conf[0xaf] = 0x30; + dev->mc_pci_conf[0xb8] = 0x0a; + dev->mc_pci_conf[0xb9] = 0x00; + dev->mc_pci_conf[0xba] = 0x00; + dev->mc_pci_conf[0xbb] = 0x00; + dev->mc_pci_conf[0xbc] = 0x01; + dev->mc_pci_conf[0xc0] = 0x00; + dev->mc_pci_conf[0xc1] = 0x00; + dev->mc_pci_conf[0xc2] = 0x00; + dev->mc_pci_conf[0xc3] = 0x00; + dev->mc_pci_conf[0xc4] = 0x00; + dev->mc_pci_conf[0xc5] = 0x00; + dev->mc_pci_conf[0xc6] = 0x00; + dev->mc_pci_conf[0xc7] = 0x00; + + i450kx_smram_recalc(dev, 0); + i450kx_vid_buf_recalc(dev, 0); + mc_write(0, 0x59, 0x03, dev); + for (i = 0x5a; i <= 0x5f; i++) + mc_write(0, i, 0x00, dev); + for (i = 0x60; i <= 0x6f; i++) + dev->mc_pci_conf[i] = 0x01; +} + + +static void +i450kx_close(void *priv) +{ + i450kx_t *dev = (i450kx_t *)priv; + + smram_del(dev->smram[1]); + smram_del(dev->smram[0]); + free(dev); +} + + +static void * +i450kx_init(const device_t *info) +{ + i450kx_t *dev = (i450kx_t *)malloc(sizeof(i450kx_t)); + memset(dev, 0, sizeof(i450kx_t)); + pci_add_card(PCI_ADD_NORTHBRIDGE, pb_read, pb_write, dev); /* Device 19h: Intel 450KX PCI Bridge PB */ + pci_add_card(PCI_ADD_AGPBRIDGE, mc_read, mc_write, dev); /* Device 14h: Intel 450KX Memory Controller MC */ + + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); + + cpu_cache_int_enabled = 1; + cpu_cache_ext_enabled = 1; + cpu_update_waitstates(); + + i450kx_reset(dev); + + return dev; +} + +const device_t i450kx_device = { + .name = "Intel 450KX (Mars)", + .internal_name = "i450kx", + .flags = DEVICE_PCI, + .local = 0, + .init = i450kx_init, + .close = i450kx_close, + .reset = i450kx_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 43ad5abaf..f8302e854 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -25,10 +25,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/cdrom.h> #include "cpu.h" -#include <86box/scsi_device.h> -#include <86box/scsi_cdrom.h> #include <86box/dma.h> #include <86box/io.h> #include <86box/device.h> @@ -44,21 +41,28 @@ #include <86box/pic.h> #include <86box/pit.h> #include <86box/port_92.h> +#include <86box/scsi_device.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/hdc_ide_sff8038i.h> #include <86box/usb.h> -#include <86box/zip.h> #include <86box/machine.h> -#include <86box/smbus_piix4.h> +#include <86box/smbus.h> #include <86box/chipset.h> -typedef struct -{ +typedef struct { + struct _piix_ *dev; + void *trap; + uint8_t dev_id; + uint32_t *sts_reg, *en_reg, sts_mask, en_mask; +} piix_io_trap_t; + +typedef struct _piix_ { uint8_t cur_readout_reg, rev, type, func_shift, max_func, pci_slot, + no_mirq0, pad, regs[4][256], readout_regs[256], board_config[2]; uint16_t func0_id, nvr_io_base, @@ -71,6 +75,7 @@ typedef struct ddma_t * ddma; usb_t * usb; acpi_t * acpi; + piix_io_trap_t io_traps[26]; port_92_t * port_92; pc_timer_t fast_off_timer; } piix_t; @@ -235,7 +240,7 @@ kbc_alias_update_io_mapping(piix_t *dev) static void smbus_update_io_mapping(piix_t *dev) { - smbus_piix4_remap(dev->smbus, (dev->regs[3][0x91] << 8) | (dev->regs[3][0x90] & 0xf0), (dev->regs[3][PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->regs[3][0xd2] & 0x01)); + smbus_piix4_remap(dev->smbus, ((uint16_t) (dev->regs[3][0x91] << 8)) | (dev->regs[3][0x90] & 0xf0), (dev->regs[3][PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->regs[3][0xd2] & 0x01)); } @@ -270,11 +275,165 @@ nvr_update_io_mapping(piix_t *dev) } +static void +piix_trap_io(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + piix_io_trap_t *trap = (piix_io_trap_t *) priv; + + if (*(trap->en_reg) & trap->en_mask) { + *(trap->sts_reg) |= trap->sts_mask; + acpi_raise_smi(trap->dev->acpi, 1); + } +} + + +static void +piix_trap_io_ide(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + piix_io_trap_t *trap = (piix_io_trap_t *) priv; + + /* IDE traps are per drive, not per channel. */ + if (ide_drives[trap->dev_id]->selected) + piix_trap_io(size, addr, write, val, priv); +} + + +static void +piix_trap_update_devctl(piix_t *dev, uint8_t trap_id, uint8_t dev_id, + uint32_t devctl_mask, uint8_t enable, + uint16_t addr, uint16_t size) +{ + piix_io_trap_t *trap = &dev->io_traps[trap_id]; + enable = (dev->acpi->regs.devctl & devctl_mask) && enable; + + /* Set up Device I/O traps dynamically. */ + if (enable && !trap->trap) { + trap->dev = dev; + trap->trap = io_trap_add((dev_id <= 3) ? piix_trap_io_ide : piix_trap_io, trap); + trap->dev_id = dev_id; + trap->sts_reg = &dev->acpi->regs.devsts; + trap->sts_mask = 0x00010000 << dev_id; + trap->en_reg = &dev->acpi->regs.devctl; + trap->en_mask = devctl_mask; + } + +#ifdef ENABLE_PIIX_LOG + if ((dev_id == 9) || (dev_id == 10) || (dev_id == 12) || (dev_id == 13)) + piix_log("PIIX: Mapping trap device %d to %04X-%04X (enable %d)\n", dev_id, addr, addr + size - 1, enable); +#endif + + /* Remap I/O trap. */ + io_trap_remap(trap->trap, enable, addr, size); +} + + +static void +piix_trap_update(void *priv) +{ + piix_t *dev = (piix_t *) priv; + uint8_t trap_id = 0, *fregs = dev->regs[3]; + uint16_t temp; + + piix_trap_update_devctl(dev, trap_id++, 0, 0x00000002, 1, 0x1f0, 8); + piix_trap_update_devctl(dev, trap_id++, 0, 0x00000002, 1, 0x3f6, 1); + + piix_trap_update_devctl(dev, trap_id++, 1, 0x00000008, 1, 0x1f0, 8); + piix_trap_update_devctl(dev, trap_id++, 1, 0x00000008, 1, 0x3f6, 1); + + piix_trap_update_devctl(dev, trap_id++, 2, 0x00000020, 1, 0x170, 8); + piix_trap_update_devctl(dev, trap_id++, 2, 0x00000020, 1, 0x376, 1); + + piix_trap_update_devctl(dev, trap_id++, 3, 0x00000080, 1, 0x170, 8); + piix_trap_update_devctl(dev, trap_id++, 3, 0x00000080, 1, 0x376, 1); + + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x08, 0x220 + (0x20 * ((fregs[0x5c] >> 5) & 0x03)), 20); + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x10, 0x200, 8); + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x08, 0x388, 4); + switch (fregs[0x5d] & 0x03) { + case 0x00: temp = 0x530; break; + case 0x01: temp = 0x604; break; + case 0x02: temp = 0xe80; break; + default: temp = 0xf40; break; + } + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x80, temp, 8); + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x01, 0x300 + (0x10 * ((fregs[0x5c] >> 1) & 0x03)), 4); + + piix_trap_update_devctl(dev, trap_id++, 5, 0x00000800, fregs[0x51] & 0x10, 0x370 + (0x80 * !(fregs[0x63] & 0x10)), 6); + piix_trap_update_devctl(dev, trap_id++, 5, 0x00000800, fregs[0x51] & 0x10, 0x377 + (0x80 * !(fregs[0x63] & 0x10)), 1); + + switch (fregs[0x67] & 0x07) { + case 0x00: temp = 0x3f8; break; + case 0x01: temp = 0x2f8; break; + case 0x02: temp = 0x220; break; + case 0x03: temp = 0x228; break; + case 0x04: temp = 0x238; break; + case 0x05: temp = 0x2e8; break; + case 0x06: temp = 0x338; break; + default: temp = 0x3e8; break; + } + piix_trap_update_devctl(dev, trap_id++, 6, 0x00002000, fregs[0x51] & 0x40, temp, 8); + + switch (fregs[0x67] & 0x70) { + case 0x00: temp = 0x3f8; break; + case 0x10: temp = 0x2f8; break; + case 0x20: temp = 0x220; break; + case 0x30: temp = 0x228; break; + case 0x40: temp = 0x238; break; + case 0x50: temp = 0x2e8; break; + case 0x60: temp = 0x338; break; + default: temp = 0x3e8; break; + } + piix_trap_update_devctl(dev, trap_id++, 7, 0x00008000, fregs[0x52] & 0x01, temp, 8); + + switch (fregs[0x63] & 0x06) { + case 0x00: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x3bc, 4); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x7bc, 3); + break; + + case 0x02: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x378, 8); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x778, 3); + break; + + case 0x04: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x278, 8); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x678, 3); + break; + + default: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0, 0); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0, 0); + break; + } + + temp = fregs[0x62] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 9, 0x00080000, fregs[0x62] & 0x20, (fregs[0x60] | (fregs[0x61] << 8)) & ~temp, temp + 1); + + temp = fregs[0x66] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 10, 0x00200000, fregs[0x66] & 0x20, (fregs[0x64] | (fregs[0x65] << 8)) & ~temp, temp + 1); + + piix_trap_update_devctl(dev, trap_id++, 11, 0x00800000, fregs[0x5f] & 0x04, 0x3b0, 48); + piix_trap_update_devctl(dev, trap_id++, 11, 0x00800000, fregs[0x5f] & 0x10, 0x60, 1); + piix_trap_update_devctl(dev, trap_id++, 11, 0x00800000, fregs[0x5f] & 0x10, 0x64, 1); + /* [A0000:BFFFF] memory trap not implemented. */ + + temp = fregs[0x6a] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 12, 0x01000000, fregs[0x6a] & 0x10, (fregs[0x68] | (fregs[0x69] << 8)) & ~temp, temp + 1); + /* Programmable memory trap not implemented. */ + + temp = fregs[0x72] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 13, 0x02000000, fregs[0x72] & 0x10, (fregs[0x70] | (fregs[0x71] << 8)) & ~temp, temp + 1); + /* Programmable memory trap not implemented. */ +} + + static void piix_write(int func, int addr, uint8_t val, void *priv) { piix_t *dev = (piix_t *) priv; uint8_t *fregs; + uint16_t base; int i; /* Return on unsupported function. */ @@ -400,9 +559,9 @@ piix_write(int func, int addr, uint8_t val, void *priv) else fregs[addr] = val & 0xcf; if (val & 0x80) - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ0 + (addr & 0x01), PCI_IRQ_DISABLED); else - pci_set_mirq_routing(PCI_MIRQ0, val & 0xf); + pci_set_mirq_routing(PCI_MIRQ0 + (addr & 0x01), val & 0xf); piix_log("MIRQ%i is %s\n", addr & 0x01, (val & 0x20) ? "disabled" : "enabled"); } break; @@ -443,8 +602,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) else fregs[addr] = val & 0xc0; + base = fregs[addr | 0x01] << 8; + base |= fregs[addr & 0xfe]; + for (i = 0; i < 4; i++) - ddma_update_io_mapping(dev->ddma, (addr & 4) + i, fregs[addr & 0xfe] + (i << 4), fregs[addr | 0x01], 1); + ddma_update_io_mapping(dev->ddma, (addr & 4) + i, fregs[addr & 0xfe] + (i << 4), fregs[addr | 0x01], (base != 0x0000)); } break; case 0xa0: @@ -466,10 +628,8 @@ piix_write(int func, int addr, uint8_t val, void *priv) dev->fast_off_period = PCICLK * 32768.0; break; } - cpu_fast_off_count = fregs[0xa8] + 1; - timer_disable(&dev->fast_off_timer); - if (dev->fast_off_period != 0.0) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + cpu_fast_off_count = cpu_fast_off_val + 1; + cpu_fast_off_period_set(cpu_fast_off_val, dev->fast_off_period); } break; case 0xa2: @@ -517,9 +677,7 @@ piix_write(int func, int addr, uint8_t val, void *priv) fregs[addr] = val & 0xff; cpu_fast_off_val = val; cpu_fast_off_count = val + 1; - timer_disable(&dev->fast_off_timer); - if (dev->fast_off_period != 0.0) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + cpu_fast_off_period_set(cpu_fast_off_val, dev->fast_off_period); } break; case 0xaa: @@ -529,12 +687,17 @@ piix_write(int func, int addr, uint8_t val, void *priv) case 0xab: if (dev->type == 3) fregs[addr] &= (val & 0x01); + else if (dev->type < 3) + fregs[addr] = val; break; case 0xb0: if (dev->type == 4) fregs[addr] = (fregs[addr] & 0x8c) | (val & 0x73); else if (dev->type == 5) fregs[addr] = val & 0x7f; + + if (dev->type >= 4) + alt_access = !!(val & 0x20); break; case 0xb1: if (dev->type > 3) @@ -587,18 +750,13 @@ piix_write(int func, int addr, uint8_t val, void *priv) } else if (func == 1) switch(addr) { /* IDE */ case 0x04: fregs[0x04] = (val & 5); - if (dev->type < 3) + if (dev->type <= 3) fregs[0x04] |= 0x02; piix_ide_handlers(dev, 0x03); piix_ide_bm_handlers(dev); break; case 0x07: - if (val & 0x20) - fregs[0x07] &= 0xdf; - if (val & 0x10) - fregs[0x07] &= 0xef; - if (val & 0x08) - fregs[0x07] &= 0xf7; + fregs[0x07] &= ~(val & 0x38); break; case 0x09: if (dev->type == 5) { @@ -611,36 +769,52 @@ piix_write(int func, int addr, uint8_t val, void *priv) fregs[0x0d] = val & 0xf0; break; case 0x10: - fregs[0x10] = (val & 0xf8) | 1; - piix_ide_handlers(dev, 0x01); + if (dev->type == 5) { + fregs[0x10] = (val & 0xf8) | 1; + piix_ide_handlers(dev, 0x01); + } break; case 0x11: - fregs[0x11] = val; - piix_ide_handlers(dev, 0x01); + if (dev->type == 5) { + fregs[0x11] = val; + piix_ide_handlers(dev, 0x01); + } break; case 0x14: - fregs[0x14] = (val & 0xfc) | 1; - piix_ide_handlers(dev, 0x01); + if (dev->type == 5) { + fregs[0x14] = (val & 0xfc) | 1; + piix_ide_handlers(dev, 0x01); + } break; case 0x15: - fregs[0x15] = val; - piix_ide_handlers(dev, 0x01); + if (dev->type == 5) { + fregs[0x15] = val; + piix_ide_handlers(dev, 0x01); + } break; case 0x18: - fregs[0x18] = (val & 0xf8) | 1; - piix_ide_handlers(dev, 0x02); + if (dev->type == 5) { + fregs[0x18] = (val & 0xf8) | 1; + piix_ide_handlers(dev, 0x02); + } break; case 0x19: - fregs[0x19] = val; - piix_ide_handlers(dev, 0x02); + if (dev->type == 5) { + fregs[0x19] = val; + piix_ide_handlers(dev, 0x02); + } break; case 0x1c: - fregs[0x1c] = (val & 0xfc) | 1; - piix_ide_handlers(dev, 0x02); + if (dev->type == 5) { + fregs[0x1c] = (val & 0xfc) | 1; + piix_ide_handlers(dev, 0x02); + } break; case 0x1d: - fregs[0x1d] = val; - piix_ide_handlers(dev, 0x02); + if (dev->type == 5) { + fregs[0x1d] = val; + piix_ide_handlers(dev, 0x02); + } break; case 0x20: fregs[0x20] = (val & 0xf0) | 1; @@ -651,7 +825,8 @@ piix_write(int func, int addr, uint8_t val, void *priv) piix_ide_bm_handlers(dev); break; case 0x3c: - fregs[0x3c] = val; + if (dev->type == 5) + fregs[0x3c] = val; break; case 0x3d: if (dev->type == 5) @@ -688,6 +863,8 @@ piix_write(int func, int addr, uint8_t val, void *priv) if (dev->type > 4) fregs[addr] = val; break; + default: + break; } else if (func == 2) switch(addr) { /* USB */ case 0x04: if (dev->type > 4) { @@ -819,6 +996,10 @@ piix_write(int func, int addr, uint8_t val, void *priv) case 0xd3: case 0xd4: case 0xd5: fregs[addr] = val; + if ((addr == 0x5c) || (addr == 0x60) || (addr == 0x61) || (addr == 0x62) || + (addr == 0x64) || (addr == 0x65) || (addr == 0x68) || (addr == 0x69) || + (addr == 0x70) || (addr == 0x71)) + piix_trap_update(dev); break; case 0x4a: fregs[addr] = val & 0x73; @@ -838,9 +1019,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) break; case 0x51: fregs[addr] = val & 0x58; + piix_trap_update(dev); break; case 0x52: fregs[addr] = val & 0x7f; + piix_trap_update(dev); break; case 0x58: fregs[addr] = val & 0x77; @@ -851,12 +1034,16 @@ piix_write(int func, int addr, uint8_t val, void *priv) break; case 0x63: fregs[addr] = val & 0xf7; + piix_trap_update(dev); break; case 0x66: fregs[addr] = val & 0xef; + piix_trap_update(dev); break; case 0x6a: case 0x72: case 0x7a: case 0x7e: fregs[addr] = val & 0x1f; + if ((addr == 0x6a) || (addr == 0x72)) + piix_trap_update(dev); break; case 0x6d: case 0x75: fregs[addr] = val & 0x80; @@ -884,8 +1071,12 @@ piix_read(int func, int addr, void *priv) /* Return on unsupported function. */ if ((func <= dev->max_func) || ((func == 1) && (dev->max_func == 0))) { - fregs = (uint8_t *) dev->regs[func]; + fregs = (uint8_t *) dev->regs[func]; ret = fregs[addr]; + if ((func == 0) && (addr == 0x4e)) + ret |= keyboard_at_get_mouse_scan(); + else if ((func == 2) && (addr == 0xff)) + ret |= 0xef; piix_log("PIIX function %i read: %02X from %02X\n", func, ret, addr); } @@ -968,21 +1159,21 @@ piix_reset_hard(piix_t *dev) /* Clear all 4 functions' arrays and set their vendor and device ID's. */ for (i = 0; i < 4; i++) { - memset(dev->regs[i], 0, 256); - if (dev->type == 5) { - dev->regs[i][0x00] = 0x55; dev->regs[i][0x01] = 0x10; /* SMSC/EFAR */ - if (i == 1) { /* IDE controller is 9130, breaking convention */ - dev->regs[i][0x02] = 0x30; - dev->regs[i][0x03] = 0x91; - } else { - dev->regs[i][0x02] = (dev->func0_id & 0xff) + (i << dev->func_shift); - dev->regs[i][0x03] = (dev->func0_id >> 8); - } - } else { - dev->regs[i][0x00] = 0x86; dev->regs[i][0x01] = 0x80; /* Intel */ - dev->regs[i][0x02] = (dev->func0_id & 0xff) + (i << dev->func_shift); - dev->regs[i][0x03] = (dev->func0_id >> 8); - } + memset(dev->regs[i], 0, 256); + if (dev->type == 5) { + dev->regs[i][0x00] = 0x55; dev->regs[i][0x01] = 0x10; /* SMSC/EFAR */ + if (i == 1) { /* IDE controller is 9130, breaking convention */ + dev->regs[i][0x02] = 0x30; + dev->regs[i][0x03] = 0x91; + } else { + dev->regs[i][0x02] = (dev->func0_id & 0xff) + (i << dev->func_shift); + dev->regs[i][0x03] = (dev->func0_id >> 8); + } + } else { + dev->regs[i][0x00] = 0x86; dev->regs[i][0x01] = 0x80; /* Intel */ + dev->regs[i][0x02] = (dev->func0_id & 0xff) + (i << dev->func_shift); + dev->regs[i][0x03] = (dev->func0_id >> 8); + } } /* Function 0: PCI to ISA Bridge */ @@ -993,7 +1184,7 @@ piix_reset_hard(piix_t *dev) if (dev->type == 4) fregs[0x08] = (dev->rev & 0x08) ? 0x02 : (dev->rev & 0x07); else - fregs[0x08] = dev->rev; + fregs[0x08] = dev->rev; fregs[0x09] = 0x00; fregs[0x0a] = 0x01; fregs[0x0b] = 0x06; fregs[0x0e] = ((dev->type > 1) || (dev->rev != 2)) ? 0x80 : 0x00; @@ -1029,6 +1220,8 @@ piix_reset_hard(piix_t *dev) /* Function 1: IDE */ fregs = (uint8_t *) dev->regs[1]; piix_log("PIIX Function 1: %02X%02X:%02X%02X\n", fregs[0x01], fregs[0x00], fregs[0x03], fregs[0x02]); + if (dev->type < 4) + fregs[0x04] = 0x02; fregs[0x06] = 0x80; fregs[0x07] = 0x02; if (dev->type == 4) fregs[0x08] = dev->rev & 0x07; @@ -1040,12 +1233,15 @@ piix_reset_hard(piix_t *dev) fregs[0x09] = 0x80; fregs[0x0a] = 0x01; fregs[0x0b] = 0x01; if (dev->type == 5) { - fregs[0x10] = fregs[0x14] = fregs[0x18] = fregs[0x1c] = 0x01; + fregs[0x10] = 0xf1; fregs[0x11] = 0x01; + fregs[0x14] = 0xf5; fregs[0x15] = 0x03; + fregs[0x18] = 0x71; fregs[0x19] = 0x01; + fregs[0x1c] = 0x75; fregs[0x1d] = 0x03; } fregs[0x20] = 0x01; if (dev->type == 5) { - fregs[0x3c] = 0x0e; - fregs[0x3d] = 0x01; + fregs[0x3c] = 0x0e; fregs[0x3d] = 0x01; + fregs[0x45] = 0x55; fregs[0x46] = 0x01; } if ((dev->type == 1) && (dev->rev == 2)) dev->max_func = 0; /* It starts with IDE disabled, then enables it. */ @@ -1060,7 +1256,7 @@ piix_reset_hard(piix_t *dev) if (dev->type == 4) fregs[0x08] = dev->rev & 0x07; else if (dev->type < 4) - fregs[0x08] = dev->rev; + fregs[0x08] = 0x01; else fregs[0x08] = 0x02; if (dev->type > 4) @@ -1081,13 +1277,13 @@ piix_reset_hard(piix_t *dev) /* Function 3: Power Management */ if (dev->type > 3) { - fregs = (uint8_t *) dev->regs[3]; + fregs = (uint8_t *) dev->regs[3]; piix_log("PIIX Function 3: %02X%02X:%02X%02X\n", fregs[0x01], fregs[0x00], fregs[0x03], fregs[0x02]); fregs[0x06] = 0x80; fregs[0x07] = 0x02; if (dev->type > 4) fregs[0x08] = 0x02; else - fregs[0x08] = (dev->rev & 0x08) ? 0x02 : (dev->rev & 0x07); + fregs[0x08] = (dev->rev & 0x08) ? 0x02 : 0x01 /*(dev->rev & 0x07)*/; fregs[0x0a] = 0x80; fregs[0x0b] = 0x06; /* NOTE: The Specification Update says this should default to 0x00 and be read-only. */ #ifdef WRONG_SPEC @@ -1131,15 +1327,8 @@ piix_fast_off_count(void *priv) { piix_t *dev = (piix_t *) priv; - cpu_fast_off_count--; - - if (cpu_fast_off_count == 0) { - smi_line = 1; - dev->regs[0][0xaa] |= 0x20; - cpu_fast_off_count = dev->regs[0][0xa8] + 1; - } - - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + smi_raise(); + dev->regs[0][0xaa] |= 0x20; } @@ -1161,21 +1350,77 @@ piix_reset(void *p) piix_write(0, 0xa8, 0x0f, p); } + if (dev->type == 5) + piix_write(0, 0xe1, 0x40, p); piix_write(1, 0x04, 0x00, p); + if (dev->type == 5) { + piix_write(1, 0x09, 0x8a, p); + piix_write(1, 0x10, 0xf1, p); + piix_write(1, 0x11, 0x01, p); + piix_write(1, 0x14, 0xf5, p); + piix_write(1, 0x15, 0x03, p); + piix_write(1, 0x18, 0x71, p); + piix_write(1, 0x19, 0x01, p); + piix_write(1, 0x1c, 0x75, p); + piix_write(1, 0x1d, 0x03, p); + } else + piix_write(1, 0x09, 0x80, p); + piix_write(1, 0x20, 0x01, p); + piix_write(1, 0x21, 0x00, p); piix_write(1, 0x41, 0x00, p); piix_write(1, 0x43, 0x00, p); ide_pri_disable(); ide_sec_disable(); + + if (dev->type >= 3) { + piix_write(2, 0x04, 0x00, p); + if (dev->type == 5) { + piix_write(2, 0x10, 0x00, p); + piix_write(2, 0x11, 0x00, p); + piix_write(2, 0x12, 0x00, p); + piix_write(2, 0x13, 0x00, p); + } else { + piix_write(2, 0x20, 0x01, p); + piix_write(2, 0x21, 0x00, p); + piix_write(2, 0x22, 0x00, p); + piix_write(2, 0x23, 0x00, p); + } + } + + if (dev->type >= 4) { + piix_write(0, 0xb0, (is_pentium) ? 0x00 : 0x04, p); + piix_write(3, 0x40, 0x01, p); + piix_write(3, 0x41, 0x00, p); + piix_write(3, 0x5b, 0x00, p); + piix_write(3, 0x80, 0x00, p); + piix_write(3, 0x90, 0x01, p); + piix_write(3, 0x91, 0x00, p); + piix_write(3, 0xd2, 0x00, p); + } + + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[1], 0, 0); + + if (dev->no_mirq0 || (dev->type >= 4)) { + sff_set_irq_mode(dev->bm[0], 1, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + } else { + sff_set_irq_mode(dev->bm[0], 1, 2); + sff_set_irq_mode(dev->bm[1], 1, 2); + } } static void -piix_close(void *p) +piix_close(void *priv) { - piix_t *piix = (piix_t *)p; + piix_t *dev = (piix_t *) priv; - free(piix); + for (int i = 0; i < (sizeof(dev->io_traps) / sizeof(dev->io_traps[0])); i++) + io_trap_remove(dev->io_traps[i].trap); + + free(dev); } @@ -1183,13 +1428,14 @@ static void piix_speed_changed(void *priv) { piix_t *dev = (piix_t *) priv; - int te; + if (!dev) + return; - te = timer_is_enabled(&dev->fast_off_timer); + int te = timer_is_enabled(&dev->fast_off_timer); timer_stop(&dev->fast_off_timer); if (te) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + timer_on_auto(&dev->fast_off_timer, ((double) cpu_fast_off_val + 1) * dev->fast_off_period); } @@ -1202,7 +1448,8 @@ static void dev->type = info->local & 0x0f; /* If (dev->type == 4) and (dev->rev & 0x08), then this is PIIX4E. */ dev->rev = (info->local >> 4) & 0x0f; - dev->func_shift = info->local >> 8; + dev->func_shift = (info->local >> 8) & 0x0f; + dev->no_mirq0 = (info->local >> 12) & 0x0f; dev->func0_id = info->local >> 16; dev->pci_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, piix_read, piix_write, dev); @@ -1218,6 +1465,17 @@ static void ide_board_set_force_ata3(1, 1); } + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[1], 0, 0); + + if (dev->no_mirq0 || (dev->type >= 4)) { + sff_set_irq_mode(dev->bm[0], 1, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + } else { + sff_set_irq_mode(dev->bm[0], 1, 2); + sff_set_irq_mode(dev->bm[1], 1, 2); + } + if (dev->type >= 3) dev->usb = device_add(&usb_device); @@ -1228,6 +1486,8 @@ static void dev->acpi = device_add(&acpi_intel_device); acpi_set_slot(dev->acpi, dev->pci_slot); acpi_set_nvr(dev->acpi, dev->nvr); + acpi_set_gpireg2_default(dev->acpi, (dev->type > 4) ? 0xf1 : 0xdd); + acpi_set_trap_update(dev->acpi, piix_trap_update, dev); dev->ddma = device_add(&ddma_device); } else @@ -1239,18 +1499,21 @@ static void if (dev->type < 4) { cpu_fast_off_val = dev->regs[0][0xa8]; cpu_fast_off_count = cpu_fast_off_val + 1; + cpu_register_fast_off_handler(&dev->fast_off_timer); } else cpu_fast_off_val = cpu_fast_off_count = 0; /* On PIIX4, PIIX4E, and SMSC, APM is added by the ACPI device. */ if (dev->type < 4) { - dev->apm = device_add(&apm_pci_device); + dev->apm = device_add(&apm_pci_device); /* APM intercept handler to update PIIX/PIIX3 and PIIX4/4E/SMSC ACPI SMI status on APM SMI. */ io_sethandler(0x00b2, 0x0001, NULL, NULL, NULL, piix_apm_out, NULL, NULL, dev); } dev->port_92 = device_add(&port_92_pci_device); + cpu_set_isa_pci_div(4); + dma_alias_set(); if (dev->type < 4) @@ -1258,7 +1521,9 @@ static void 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): @@ -1319,90 +1584,105 @@ static void else dev->board_config[1] |= 0x00; + // device_add(&i8254_sec_device); + return dev; } - -const device_t piix_device = -{ - "Intel 82371FB (PIIX)", - DEVICE_PCI, - 0x122e0101, - piix_init, - piix_close, - piix_reset, - NULL, - piix_speed_changed, - NULL, - NULL +const device_t piix_device = { + .name = "Intel 82371FB (PIIX)", + .internal_name = "piix", + .flags = DEVICE_PCI, + .local = 0x122e0101, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t piix_rev02_device = -{ - "Intel 82371FB (PIIX) (Faulty BusMastering!!)", - DEVICE_PCI, - 0x122e0121, - piix_init, - piix_close, - piix_reset, - NULL, - piix_speed_changed, - NULL, - NULL +const device_t piix_rev02_device = { + .name = "Intel 82371FB (PIIX) (Faulty BusMastering!!)", + .internal_name = "piix_rev02", + .flags = DEVICE_PCI, + .local = 0x122e0121, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t piix3_device = -{ - "Intel 82371SB (PIIX3)", - DEVICE_PCI, - 0x70000403, - piix_init, - piix_close, - piix_reset, - NULL, - piix_speed_changed, - NULL, - NULL +const device_t piix3_device = { + .name = "Intel 82371SB (PIIX3)", + .internal_name = "piix3", + .flags = DEVICE_PCI, + .local = 0x70000403, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t piix4_device = -{ - "Intel 82371AB/EB (PIIX4/PIIX4E)", - DEVICE_PCI, - 0x71100004, - piix_init, - piix_close, - piix_reset, - NULL, - piix_speed_changed, - NULL, - NULL +const device_t piix3_ioapic_device = { + .name = "Intel 82371SB (PIIX3) (Boards with I/O APIC)", + .internal_name = "piix3_ioapic", + .flags = DEVICE_PCI, + .local = 0x70001403, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t piix4e_device = -{ - "Intel 82371EB (PIIX4E)", - DEVICE_PCI, - 0x71100094, - piix_init, - piix_close, - piix_reset, - NULL, - piix_speed_changed, - NULL, - NULL +const device_t piix4_device = { + .name = "Intel 82371AB/EB (PIIX4/PIIX4E)", + .internal_name = "piix4", + .flags = DEVICE_PCI, + .local = 0x71100004, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t slc90e66_device = -{ - "SMSC SLC90E66 (Victory66)", - DEVICE_PCI, - 0x94600005, - piix_init, - piix_close, - piix_reset, - NULL, - piix_speed_changed, - NULL, - NULL +const device_t piix4e_device = { + .name = "Intel 82371EB (PIIX4E)", + .internal_name = "piix4e", + .flags = DEVICE_PCI, + .local = 0x71100094, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t slc90e66_device = { + .name = "SMSC SLC90E66 (Victory66)", + .internal_name = "slc90e66", + .flags = DEVICE_PCI, + .local = 0x94600005, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index 370bed928..bbc85662d 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -18,6 +18,7 @@ #include #include #include <86box/86box.h> +#include "cpu.h" #include <86box/device.h> #include <86box/io.h> #include <86box/apm.h> @@ -105,7 +106,7 @@ sio_timer_read(uint16_t addr, void *priv) uint8_t ret = 0xff; if (!(addr & 0x0002)) { - sub_cycles((int)(PITCONST >> 32)); + cycles -= ((int) (PITCONST >> 32)); sio_timer_latch = timer_get_remaining_us(&dev->timer); @@ -126,7 +127,7 @@ sio_timer_readw(uint16_t addr, void *priv) uint16_t ret = 0xffff; if (!(addr & 0x0002)) { - sub_cycles((int)(PITCONST >> 32)); + cycles -= ((int) (PITCONST >> 32)); ret = timer_get_remaining_us(&dev->timer); } @@ -264,10 +265,8 @@ sio_write(int func, int addr, uint8_t val, void *priv) dev->fast_off_period = PCICLK * 32768.0; break; } - cpu_fast_off_count = dev->regs[0xa8] + 1; - timer_disable(&dev->fast_off_timer); - if (dev->fast_off_period != 0.0) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + cpu_fast_off_count = cpu_fast_off_val + 1; + cpu_fast_off_period_set(cpu_fast_off_val, dev->fast_off_period); } break; case 0xa2: @@ -306,9 +305,7 @@ sio_write(int func, int addr, uint8_t val, void *priv) dev->regs[addr] = val & 0xff; cpu_fast_off_val = val; cpu_fast_off_count = val + 1; - timer_disable(&dev->fast_off_timer); - if (dev->fast_off_period != 0.0) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + cpu_fast_off_period_set(cpu_fast_off_val, dev->fast_off_period); break; } } @@ -429,15 +426,8 @@ sio_fast_off_count(void *priv) { sio_t *dev = (sio_t *) priv; - cpu_fast_off_count--; - - if (cpu_fast_off_count == 0) { - smi_line = 1; - dev->regs[0xaa] |= 0x20; - cpu_fast_off_count = dev->regs[0xa8] + 1; - } - - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + smi_raise(); + dev->regs[0xaa] |= 0x20; } @@ -513,6 +503,8 @@ sio_init(const device_t *info) if (dev->id == 0x03) { cpu_fast_off_val = dev->regs[0xa8]; cpu_fast_off_count = cpu_fast_off_val + 1; + + cpu_register_fast_off_handler(&dev->fast_off_timer); } else cpu_fast_off_val = cpu_fast_off_count = 0; @@ -539,35 +531,37 @@ sio_init(const device_t *info) timer_add(&dev->timer, NULL, NULL, 0); + // device_add(&i8254_sec_device); + return dev; } -const device_t sio_device = -{ - "Intel 82378IB (SIO)", - DEVICE_PCI, - 0x00, - sio_init, - sio_close, - sio_reset, - NULL, - sio_speed_changed, - NULL, - NULL +const device_t sio_device = { + .name = "Intel 82378IB (SIO)", + .internal_name = "sio", + .flags = DEVICE_PCI, + .local = 0x00, + .init = sio_init, + .close = sio_close, + .reset = sio_reset, + { .available = NULL }, + .speed_changed = sio_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t sio_zb_device = -{ - "Intel 82378ZB (SIO)", - DEVICE_PCI, - 0x03, - sio_init, - sio_close, - sio_reset, - NULL, - sio_speed_changed, - NULL, - NULL +const device_t sio_zb_device = { + .name = "Intel 82378ZB (SIO)", + .internal_name = "sio_zb", + .flags = DEVICE_PCI, + .local = 0x03, + .init = sio_init, + .close = sio_close, + .reset = sio_reset, + { .available = NULL }, + .speed_changed = sio_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/mcr.c b/src/chipset/mcr.c deleted file mode 100644 index ec1931882..000000000 --- a/src/chipset/mcr.c +++ /dev/null @@ -1,38 +0,0 @@ -/*INTEL 82355 MCR emulation - This chip was used as part of many 386 chipsets - It controls memory addressing and shadowing*/ -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/mem.h> - - -int nextreg6; -uint8_t mcr22; -int mcrlock,mcrfirst; - - -void resetmcr(void) -{ - mcrlock=0; - mcrfirst=1; - shadowbios=0; -} - -void writemcr(uint16_t addr, uint8_t val) -{ - switch (addr) - { - case 0x22: - if (val==6 && mcr22==6) nextreg6=1; - else nextreg6=0; - break; - case 0x23: - if (nextreg6) shadowbios=!val; - break; - } - mcr22=val; -} - diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 8e4e710f2..8e7bc1937 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -26,13 +26,8 @@ #include #include <86box/86box.h> #include <86box/device.h> -#include <86box/timer.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/keyboard.h> #include <86box/io.h> #include <86box/mem.h> -#include <86box/nmi.h> #include <86box/chipset.h> #define NEAT_DEBUG 0 @@ -255,16 +250,11 @@ neat_log(const char *fmt, ...) static uint8_t ems_readb(uint32_t addr, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - neat_t *dev = (neat_t *)map->dev; + neat_t *dev = (neat_t *)priv; uint8_t ret = 0xff; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); /* Grab the data. */ - ret = *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)); + ret = *(uint8_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)); return(ret); } @@ -273,16 +263,11 @@ ems_readb(uint32_t addr, void *priv) static uint16_t ems_readw(uint32_t addr, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - neat_t *dev = (neat_t *)map->dev; + neat_t *dev = (neat_t *)priv; uint16_t ret = 0xffff; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); /* Grab the data. */ - ret = *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)); + ret = *(uint16_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)); return(ret); } @@ -291,30 +276,20 @@ ems_readw(uint32_t addr, void *priv) static void ems_writeb(uint32_t addr, uint8_t val, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - neat_t *dev = (neat_t *)map->dev; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); + neat_t *dev = (neat_t *)priv; /* Write the data. */ - *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; + *(uint8_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)) = val; } /* Write one word to paged RAM. */ static void ems_writew(uint32_t addr, uint16_t val, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - neat_t *dev = (neat_t *)map->dev; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); + neat_t *dev = (neat_t *)priv; /* Write the data. */ - *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; + *(uint16_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)) = val; } /* Re-calculate the active-page physical address. */ @@ -441,8 +416,7 @@ ems_init(neat_t *dev, int en) ems_readb, ems_readw, NULL, ems_writeb, ems_writew, NULL, ram, MEM_MAPPING_EXTERNAL, - &dev->ems[i].mapping); - mem_mapping_set_dev(&dev->ems[i].mapping, dev); + dev); /* Disable for now. */ mem_mapping_disable(&dev->ems[i].mapping); @@ -506,7 +480,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB0: + case REG_RB0: val &= RB0_MASK; *reg = (*reg & ~RB0_MASK) | val | \ (RB0_REV_ID << RB0_REV_SH); @@ -515,7 +489,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB1: + case REG_RB1: val &= RB1_MASK; *reg = (*reg & ~RB1_MASK) | val; #if NEAT_DEBUG > 1 @@ -523,7 +497,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB2: + case REG_RB2: val &= RB2_MASK; *reg = (*reg & ~RB2_MASK) | val; #if NEAT_DEBUG > 1 @@ -531,7 +505,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB3: + case REG_RB3: val &= RB3_MASK; *reg = (*reg & ~RB3_MASK) | val; #if NEAT_DEBUG > 1 @@ -539,7 +513,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB4: + case REG_RB4: val &= RB4_MASK; *reg = (*reg & ~RB4_MASK) | val; #if NEAT_DEBUG > 1 @@ -547,7 +521,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB5: + case REG_RB5: val &= RB5_MASK; *reg = (*reg & ~RB5_MASK) | val; #if NEAT_DEBUG > 1 @@ -555,7 +529,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB6: + case REG_RB6: val &= RB6_MASK; *reg = (*reg & ~RB6_MASK) | val; #if NEAT_DEBUG > 1 @@ -563,7 +537,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB7: + case REG_RB7: val &= RB7_MASK; *reg = val; #if NEAT_DEBUG > 1 @@ -582,7 +556,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) } break; - case REG_RB8: + case REG_RB8: val &= RB8_MASK; *reg = (*reg & ~RB8_MASK) | val; #if NEAT_DEBUG > 1 @@ -590,7 +564,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) #endif break; - case REG_RB9: + case REG_RB9: val &= RB9_MASK; *reg = (*reg & ~RB9_MASK) | val; #if NEAT_DEBUG > 1 @@ -602,7 +576,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) } break; - case REG_RB10: + case REG_RB10: val &= RB10_MASK; *reg = (*reg & ~RB10_MASK) | val; #if NEAT_DEBUG > 1 @@ -617,7 +591,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) ems_recalc(dev, &dev->ems[i]); break; - case REG_RB11: + case REG_RB11: val &= RB11_MASK; *reg = (*reg & ~RB11_MASK) | val; #if NEAT_DEBUG > 1 @@ -850,12 +824,16 @@ neat_init(const device_t *info) return dev; } - const device_t neat_device = { - "C&T CS8121 (NEAT)", - 0, - 0, - neat_init, neat_close, NULL, - NULL, NULL, NULL, - NULL + .name = "C&T CS8121 (NEAT)", + .internal_name = "neat", + .flags = 0, + .local = 0, + .init = neat_init, + .close = neat_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/olivetti_eva.c b/src/chipset/olivetti_eva.c new file mode 100644 index 000000000..0728d44e5 --- /dev/null +++ b/src/chipset/olivetti_eva.c @@ -0,0 +1,171 @@ +/* + * 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 Olivetti EVA (98/86) Gate Array. + * + * Note: This chipset has no datasheet, everything were done via + * reverse engineering the BIOS of various machines using it. + * + * Authors: EngiNerd + * + * Copyright 2020-2021 EngiNerd + */ + + +#include +#include +#include +#include +#include +#include +#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/chipset.h> +#include <86box/video.h> +#include <86box/mem.h> + +typedef struct +{ + uint8_t reg_065; + uint8_t reg_067; + uint8_t reg_069; +} olivetti_eva_t; + +#ifdef ENABLE_OLIVETTI_EVA_LOG +int olivetti_eva_do_log = ENABLE_OLIVETTI_EVA_LOG; +static void +olivetti_eva_log(const char *fmt, ...) +{ + va_list ap; + + if (olivetti_eva_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define olivetti_eva_log(fmt, ...) +#endif + +static void +olivetti_eva_write(uint16_t addr, uint8_t val, void *priv) +{ + olivetti_eva_t *dev = (olivetti_eva_t *) priv; + olivetti_eva_log("Olivetti EVA Gate Array: Write %02x at %02x\n", val, addr); + + switch (addr) { + case 0x065: + dev->reg_065 = val; + break; + case 0x067: + dev->reg_067 = val; + 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 (val & 1){ + // /* + // * Set the register to 7 or above for the BIOS to trigger the + // * memory remapping function if shadowing is active. + // */ + // dev->reg_069 = 0x7; + // } + // if (val & 8) { + // /* + // * Activate shadowing for region e0000-fffff + // */ + // mem_remap_top(256); + // mem_set_mem_state_both(0xa0000, 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + // } + break; + } +} + +static uint8_t +olivetti_eva_read(uint16_t addr, void *priv) +{ + olivetti_eva_t *dev = (olivetti_eva_t *) priv; + uint8_t ret = 0xff; + switch (addr) { + case 0x065: + ret = dev->reg_065; + break; + case 0x067: + /* never happens */ + ret = dev->reg_067; + break; + case 0x069: + ret = dev->reg_069; + break; + } + olivetti_eva_log("Olivetti EVA Gate Array: Read %02x at %02x\n", ret, addr); + return ret; +} + + +static void +olivetti_eva_close(void *priv) +{ + olivetti_eva_t *dev = (olivetti_eva_t *) priv; + + free(dev); +} + +static void * +olivetti_eva_init(const device_t *info) +{ + olivetti_eva_t *dev = (olivetti_eva_t *) malloc(sizeof(olivetti_eva_t)); + memset(dev, 0, sizeof(olivetti_eva_t)); + + /* GA98 registers */ + dev->reg_065 = 0x00; + + /* RAM page registers: never read, only set */ + dev->reg_067 = 0x00; + + /* RAM enable registers */ + dev->reg_069 = 0x0; + + 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); + io_sethandler(0x0069, 0x0001, olivetti_eva_read, NULL, NULL, olivetti_eva_write, NULL, NULL, dev); + + /* 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; +} + +const device_t olivetti_eva_device = { + .name = "Olivetti EVA Gate Array", + .internal_name = "olivetta_eva", + .flags = 0, + .local = 0, + .init = olivetti_eva_init, + .close = olivetti_eva_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c new file mode 100644 index 000000000..8e9403c29 --- /dev/null +++ b/src/chipset/opti283.c @@ -0,0 +1,317 @@ +/* + * 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 82C283 chipset. + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2021 Tiseno100. + * Copyright 2021 Miran Grca. + */ + +#include +#include +#include +#include +#include +#include +#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> + + +#ifdef ENABLE_OPTI283_LOG +int opti283_do_log = ENABLE_OPTI283_LOG; + +static void +opti283_log(const char *fmt, ...) +{ + va_list ap; + + if (opti283_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti283_log(fmt, ...) +#endif + + +typedef struct +{ + uint32_t phys, virt; +} mem_remapping_t; + + +typedef struct +{ + uint8_t index, shadow_high, + regs[256]; + mem_remapping_t mem_remappings[2]; + mem_mapping_t mem_mappings[2]; +} opti283_t; + + +static uint8_t +opti283_read_remapped_ram(uint32_t addr, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_ram((addr - dev->virt) + dev->phys, priv); +} + + +static uint16_t +opti283_read_remapped_ramw(uint32_t addr, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_ramw((addr - dev->virt) + dev->phys, priv); +} + + +static uint32_t +opti283_read_remapped_raml(uint32_t addr, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_raml((addr - dev->virt) + dev->phys, priv); +} + + +static void +opti283_write_remapped_ram(uint32_t addr, uint8_t val, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_ram((addr - dev->virt) + dev->phys, val, priv); +} + + +static void +opti283_write_remapped_ramw(uint32_t addr, uint16_t val, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_ramw((addr - dev->virt) + dev->phys, val, priv); +} + + +static void +opti283_write_remapped_raml(uint32_t addr, uint32_t val, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_raml((addr - dev->virt) + dev->phys, val, priv); +} + + +static void +opti283_shadow_recalc(opti283_t *dev) +{ + uint32_t i, base; + uint32_t rbase; + uint8_t sh_enable, sh_mode; + uint8_t rom, sh_copy; + + shadowbios = shadowbios_write = 0; + dev->shadow_high = 0; + + opti283_log("OPTI 283: %02X %02X %02X %02X\n", dev->regs[0x11], dev->regs[0x12], dev->regs[0x13], dev->regs[0x14]); + + if (dev->regs[0x11] & 0x80) { + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + opti283_log("OPTI 283: F0000-FFFFF READ_EXTANY, WRITE_INTERNAL\n"); + shadowbios_write = 1; + } else { + shadowbios = 1; + if (dev->regs[0x14] & 0x80) { + mem_set_mem_state_both(0xf0000, 0x01000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + opti283_log("OPTI 283: F0000-F0FFF READ_INTERNAL, WRITE_INTERNAL\n"); + shadowbios_write = 1; + } else { + mem_set_mem_state_both(0xf0000, 0x01000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + opti283_log("OPTI 283: F0000-F0FFF READ_INTERNAL, WRITE_DISABLED\n"); + } + + mem_set_mem_state_both(0xf1000, 0x0f000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + opti283_log("OPTI 283: F1000-FFFFF READ_INTERNAL, WRITE_DISABLED\n"); + } + + sh_copy = dev->regs[0x11] & 0x08; + for (i = 0; i < 12; i++) { + base = 0xc0000 + (i << 14); + if (i >= 4) + sh_enable = dev->regs[0x12] & (1 << (i - 4)); + else + sh_enable = dev->regs[0x13] & (1 << (i + 4)); + sh_mode = dev->regs[0x11] & (1 << (i >> 2)); + 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 (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); + opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_DISABLED\n", base, base + 0x3fff); + } else { + 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); + } + } + } else { + if (base >= 0xe0000) { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_DISABLED); + opti283_log("OPTI 283: %08X-%08X READ_EXTANY, WRITE_DISABLED\n", base, base + 0x3fff); + } else { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); + opti283_log("OPTI 283: %08X-%08X READ_EXTERNAL, WRITE_DISABLED\n", base, base + 0x3fff); + } + } + } + + rbase = ((uint32_t) (dev->regs[0x13] & 0x0f)) << 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 +opti283_write(uint16_t addr, uint8_t val, void *priv) +{ + opti283_t *dev = (opti283_t *)priv; + + switch (addr) { + case 0x22: + dev->index = val; + break; + + case 0x24: + opti283_log("OPTi 283: dev->regs[%02x] = %02x\n", dev->index, val); + + switch (dev->index) { + case 0x10: + dev->regs[dev->index] = val; + break; + + case 0x14: + reset_on_hlt = !!(val & 0x40); + /* FALLTHROUGH */ + case 0x11: case 0x12: + case 0x13: + dev->regs[dev->index] = val; + opti283_shadow_recalc(dev); + break; + } + break; + } +} + + +static uint8_t +opti283_read(uint16_t addr, void *priv) +{ + opti283_t *dev = (opti283_t *)priv; + uint8_t ret = 0xff; + + if (addr == 0x24) + ret = dev->regs[dev->index]; + + return ret; +} + + +static void +opti283_close(void *priv) +{ + opti283_t *dev = (opti283_t *)priv; + + free(dev); +} + + +static void * +opti283_init(const device_t *info) +{ + opti283_t *dev = (opti283_t *)malloc(sizeof(opti283_t)); + memset(dev, 0x00, sizeof(opti283_t)); + + io_sethandler(0x0022, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); + + dev->regs[0x10] = 0x3f; + dev->regs[0x11] = 0xf0; + + dev->mem_remappings[0].phys = 0x000a0000; + dev->mem_remappings[1].phys = 0x000d0000; + + mem_mapping_add(&dev->mem_mappings[0], 0, 0x00020000, + opti283_read_remapped_ram, opti283_read_remapped_ramw, opti283_read_remapped_raml, + opti283_write_remapped_ram, opti283_write_remapped_ramw, opti283_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, + opti283_read_remapped_ram, opti283_read_remapped_ramw, opti283_read_remapped_raml, + opti283_write_remapped_ram, opti283_write_remapped_ramw, opti283_write_remapped_raml, + &ram[dev->mem_remappings[1].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[1]); + mem_mapping_disable(&dev->mem_mappings[1]); + + opti283_shadow_recalc(dev); + + return dev; +} + +const device_t opti283_device = { + .name = "OPTi 82C283", + .internal_name = "opti283", + .flags = 0, + .local = 0, + .init = opti283_init, + .close = opti283_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti291.c b/src/chipset/opti291.c new file mode 100644 index 000000000..6bf8851e7 --- /dev/null +++ b/src/chipset/opti291.c @@ -0,0 +1,161 @@ +/* + * 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 82C291 chipset. + + * Authors: plant/nerd73, Tiseno100 + * + * Copyright 2020 plant/nerd73. + * Copyright 2021 Tiseno100. + */ +#include +#include +#include +#include +#include +#include +#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/port_92.h> +#include <86box/chipset.h> + +#ifdef ENABLE_OPTI291_LOG +int opti291_do_log = ENABLE_OPTI291_LOG; +static void +opti291_log(const char *fmt, ...) +{ + va_list ap; + + if (opti291_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti291_log(fmt, ...) +#endif + +typedef struct +{ + uint8_t index, regs[256]; + port_92_t *port_92; +} opti291_t; + +static void opti291_recalc(opti291_t *dev) +{ + mem_set_mem_state_both(0xf0000, 0x10000, (!(dev->regs[0x23] & 0x40) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x27] & 0x80) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)); + + for (uint32_t i = 0; i < 4; i++) + { + mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, ((dev->regs[0x26] & (1 << (i + 4))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x27] & 0x10) ? MEM_WRITE_DISABLED : ((dev->regs[0x26] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY))); + mem_set_mem_state_both(0xd0000 + (i << 14), 0x4000, ((dev->regs[0x25] & (1 << (i + 4))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x27] & 0x20) ? MEM_WRITE_DISABLED : ((dev->regs[0x25] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY))); + mem_set_mem_state_both(0xe0000 + (i << 14), 0x4000, ((dev->regs[0x24] & (1 << (i + 4))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[0x27] & 0x40) ? MEM_WRITE_DISABLED : ((dev->regs[0x24] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY))); + } + flushmmucache(); +} +static void +opti291_write(uint16_t addr, uint8_t val, void *priv) +{ + opti291_t *dev = (opti291_t *)priv; + + switch (addr) + { + case 0x22: + dev->index = val; + break; + case 0x24: + opti291_log("OPTi 291: dev->regs[%02x] = %02x\n", dev->index, val); + switch (dev->index) + { + case 0x20: + dev->regs[dev->index] = val & 0x3f; + break; + case 0x21: + dev->regs[dev->index] = val & 0xf3; + break; + case 0x22: + dev->regs[dev->index] = val; + break; + case 0x23: + case 0x24: + case 0x25: + case 0x26: + dev->regs[dev->index] = val; + opti291_recalc(dev); + break; + case 0x27: + case 0x28: + dev->regs[dev->index] = val; + break; + case 0x29: + dev->regs[dev->index] = val & 0x0f; + break; + case 0x2a: + case 0x2b: + case 0x2c: + dev->regs[dev->index] = val; + break; + } + break; + } +} + +static uint8_t +opti291_read(uint16_t addr, void *priv) +{ + opti291_t *dev = (opti291_t *)priv; + + return (addr == 0x24) ? dev->regs[dev->index] : 0xff; +} + +static void +opti291_close(void *priv) +{ + opti291_t *dev = (opti291_t *)priv; + + free(dev); +} + +static void * +opti291_init(const device_t *info) +{ + opti291_t *dev = (opti291_t *)malloc(sizeof(opti291_t)); + memset(dev, 0, sizeof(opti291_t)); + + io_sethandler(0x022, 0x0001, opti291_read, NULL, NULL, opti291_write, NULL, NULL, dev); + io_sethandler(0x024, 0x0001, opti291_read, NULL, NULL, opti291_write, NULL, NULL, dev); + dev->regs[0x22] = 0xf0; + dev->regs[0x23] = 0x40; + dev->regs[0x28] = 0x08; + dev->regs[0x29] = 0xa0; + device_add(&port_92_device); + opti291_recalc(dev); + + return dev; +} + +const device_t opti291_device = { + .name = "OPTi 82C291", + .internal_name = "opti291", + .flags = 0, + .local = 0, + .init = opti291_init, + .close = opti291_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti391.c b/src/chipset/opti391.c new file mode 100644 index 000000000..51c8d9daa --- /dev/null +++ b/src/chipset/opti391.c @@ -0,0 +1,226 @@ +/* + * 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 82C391/392 chipset. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ + +#include +#include +#include +#include +#include +#include +#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> + + +#ifdef ENABLE_OPTI391_LOG +int opti391_do_log = ENABLE_OPTI391_LOG; + +static void +opti391_log(const char *fmt, ...) +{ + va_list ap; + + if (opti391_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti391_log(fmt, ...) +#endif + + +typedef struct +{ + uint32_t phys, virt; +} mem_remapping_t; + + +typedef struct +{ + uint8_t index, regs[256]; +} opti391_t; + + +static void +opti391_shadow_recalc(opti391_t *dev) +{ + uint32_t i, base; + uint8_t sh_enable, sh_master; + uint8_t sh_wp, sh_write_internal; + + shadowbios = shadowbios_write = 0; + + /* F0000-FFFFF */ + sh_enable = !(dev->regs[0x22] & 0x80); + if (sh_enable) + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + sh_write_internal = (dev->regs[0x26] & 0x40); + /* D0000-EFFFF */ + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + if (base >= 0xe0000) { + sh_master = (dev->regs[0x22] & 0x40); + sh_wp = (dev->regs[0x22] & 0x10); + } else { + sh_master = (dev->regs[0x22] & 0x20); + sh_wp = (dev->regs[0x22] & 0x08); + } + sh_enable = dev->regs[0x23] & (1 << i); + + if (sh_master) { + if (sh_enable) { + if (sh_wp) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + + /* C0000-CFFFF */ + sh_master = !(dev->regs[0x26] & 0x10); + sh_wp = (dev->regs[0x26] & 0x20); + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + sh_enable = dev->regs[0x26] & (1 << i); + + if (sh_master) { + if (sh_enable) { + if (sh_wp) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } else if (sh_write_internal) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } +} + + +static void +opti391_write(uint16_t addr, uint8_t val, void *priv) +{ + opti391_t *dev = (opti391_t *)priv; + + switch (addr) { + case 0x22: + dev->index = val; + break; + + case 0x24: + opti391_log("OPTi 391: dev->regs[%02x] = %02x\n", dev->index, val); + + switch (dev->index) { + case 0x20: + dev->regs[dev->index] = (dev->regs[dev->index] & 0xc0) | (val & 0x3f); + break; + + case 0x21: case 0x24: case 0x25: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + dev->regs[dev->index] = val; + break; + + case 0x22: case 0x23: + case 0x26: + dev->regs[dev->index] = val; + opti391_shadow_recalc(dev); + break; + } + break; + } +} + + +static uint8_t +opti391_read(uint16_t addr, void *priv) +{ + opti391_t *dev = (opti391_t *)priv; + uint8_t ret = 0xff; + + if (addr == 0x24) + ret = dev->regs[dev->index]; + + return ret; +} + + +static void +opti391_close(void *priv) +{ + opti391_t *dev = (opti391_t *)priv; + + free(dev); +} + + +static void * +opti391_init(const device_t *info) +{ + opti391_t *dev = (opti391_t *)malloc(sizeof(opti391_t)); + memset(dev, 0x00, sizeof(opti391_t)); + + io_sethandler(0x0022, 0x0001, opti391_read, NULL, NULL, opti391_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti391_read, NULL, NULL, opti391_write, NULL, NULL, dev); + + dev->regs[0x21] = 0x84; + dev->regs[0x24] = 0x07; + dev->regs[0x25] = 0xf0; + dev->regs[0x26] = 0x30; + dev->regs[0x27] = 0x91; + dev->regs[0x28] = 0x80; + dev->regs[0x29] = 0x10; + dev->regs[0x2a] = 0x80; + dev->regs[0x2b] = 0x10; + + opti391_shadow_recalc(dev); + + return dev; +} + +const device_t opti391_device = { + .name = "OPTi 82C391", + .internal_name = "opti391", + .flags = 0, + .local = 0, + .init = opti391_init, + .close = opti391_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti495.c b/src/chipset/opti495.c index 47ee25582..c02f9cc1f 100644 --- a/src/chipset/opti495.c +++ b/src/chipset/opti495.c @@ -1,256 +1,21 @@ -/*OPTi 82C495 emulation - This is the chipset used in the AMI386 model - - Details for the chipset from Ralph Brown's interrupt list - This describes the OPTi 82C493, the 82C495 seems similar except there is one - more register (2C) - -----------P00220024-------------------------- -PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS -Desc: The OPTi 486SXWB contains three chips and is designed for systems - running at 20, 25 and 33MHz. The chipset includes an 82C493 System - Controller (SYSC), the 82C392 Data Buffer Controller, and the - 82C206 Integrated peripheral Controller (IPC). -Note: every access to PORT 0024h must be preceded by a write to PORT 0022h, - even if the same register is being accessed a second time -SeeAlso: PORT 0022h"82C206" - -0022 ?W configuration register index (see #P0178) -0024 RW configuration register data - -(Table P0178) -Values for OPTi 82C493 System Controller configuration register index: - 20h Control Register 1 (see #P0179) - 21h Control Register 2 (see #P0180) - 22h Shadow RAM Control Register 1 (see #P0181) - 23h Shadow RAM Control Register 2 (see #P0182) - 24h DRAM Control Register 1 (see #P0183) - 25h DRAM Control Register 2 (see #P0184) - 26h Shadow RAM Control Register 3 (see #P0185) - 27h Control Register 3 (see #P0186) - 28h Non-cachable Block 1 Register 1 (see #P0187) - 29h Non-cachable Block 1 Register 2 (see #P0188) - 2Ah Non-cachable Block 2 Register 1 (see #P0187) - 2Bh Non-cachable Block 2 Register 2 (see #P0188) - -Bitfields for OPTi-82C493 Control Register 1: -Bit(s) Description (Table P0179) - 7-6 Revision of 82C493 (readonly) (default=01) - 5 Burst wait state control - 1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2 - 0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default) - (if bit 5 is set to 1, bit 4 must be set to 0) - 4 Cache memory data buffer output enable control - 0 = disable (default) - 1 = enable - (must be disabled for frequency <= 33Mhz) - 3 Single Address Latch Enable (ALE) - 0 = disable (default) - 1 = enable - (if enabled, SYSC will activate single ALE rather than multiples - during bus conversion cycles) - 2 enable Extra AT Cycle Wait State (default is 0 = disabled) - 1 Emulation keyboard Reset Control - 0 = disable (default) - 1 = enable - Note: This bit must be enabled in BIOS default value; enabling this - bit requires HALT instruction to be executed before SYSC - generates processor reset (CPURST) - 0 enable Alternative Fast Reset (default is 0 = disabled) -SeeAlso: #P0180,#P0186 - -Bitfields for OPTi-82C493 Control Register 2: -Bit(s) Description (Table P0180) - 7 Master Mode Byte Swap Enable - 0 = disable (default) - 1 = enable - 6 Emulation Keyboard Reset Delay Control - 0 = Generate reset pulse 2us later (default) - 1 = Generate reset pulse immediately - 5 disable Parity Check (default is 0 = enabled) - 4 Cache Enable - 0 = Cache disabled and DRAM burst mode enabled (default) - 1 = Cache enabled and DRAM burst mode disabled - 3-2 Cache Size - 00 64KB (default) - 01 128KB - 10 256KB - 11 512KB - 1 Secondary Cache Read Burst Cycles Control - 0 = 3-1-1-1 cycle (default) - 1 = 2-1-1-1 cycle - 0 Cache Write Wait State Control - 0 = 1 wait state (default) - 1 = 0 wait state -SeeAlso: #P0179,#P0186 - -Bitfields for OPTi-82C493 Shadow RAM Control Register 1: -Bit(s) Description (Table P0181) - 7 ROM(F0000h - FFFFFh) Enable - 0 = read/write on write-protected DRAM - 1 = read from ROM, write to DRAM (default) - 6 Shadow RAM at D0000h - EFFFFh Area - 0 = disable (default) - 1 = enable - 5 Shadow RAM at E0000h - EFFFFh Area - 0 = disable shadow RAM (default) - E0000h - EFFFFh ROM is defaulted to reside on XD bus - 1 = enable shadow RAM - 4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area - 0 = disable (default) - 1 = enable - 3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area - 0 = disable (default) - 1 = enable - 2 Hidden refresh enable (with holding CPU) - (Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used) - 1 = disable (default) - 0 = enable - 1 unused - 0 enable Slow Refresh (four times slower than normal refresh) - (default is 0 = disable) -SeeAlso: #P0182 - -Bitfields for OPTi-82C493 Shadow RAM Control Register 2: -Bit(s) Description (Table P0182) - 7 enable Shadow RAM at EC000h - EFFFFh area - 6 enable Shadow RAM at E8000h - EBFFFh area - 5 enable Shadow RAM at E4000h - E7FFFh area - 4 enable Shadow RAM at E0000h - E3FFFh area - 3 enable Shadow RAM at DC000h - DFFFFh area - 2 enable Shadow RAM at D8000h - DBFFFh area - 1 enable Shadow RAM at D4000h - D7FFFh area - 0 enable Shadow RAM at D0000h - D3FFFh area -Note: the default is disabled (0) for all areas - -Bitfields for OPTi-82C493 DRAM Control Register 1: -Bit(s) Description (Table P0183) - 7 DRAM size - 0 = 256K DRAM mode - 1 = 1M and 4M DRAM mode - 6-4 DRAM types used for bank0 and bank1 - bits 7-4 Bank0 Bank1 - 0000 256K x - 0001 256K 256K - 0010 256K 1M - 0011 x x - 01xx x x - 1000 1M x (default) - 1001 1M 1M - 1010 1M 4M - 1011 4M 1M - 1100 4M x - 1101 4M 4M - 111x x x - 3 unused - 2-0 DRAM types used for bank2 and bank3 - bits 7,2-0 Bank2 Bank3 - x000 1M x - x001 1M 1M - x010 x x - x011 4M 1M - x100 4M x - x101 4M 4M - x11x x x (default) -SeeAlso: #P0184 - -Bitfields for OPTi-82C493 DRAM Control Register 2: -Bit(s) Description (Table P0184) - 7-6 Read cycle additional wait states - 00 not used - 01 = 0 - 10 = 1 - 11 = 2 (default) - 5-4 Write cycle additional wait states - 00 = 0 - 01 = 1 - 10 = 2 - 11 = 3 (default) - 3 Fast decode enable - 0 = disable fast decode. DRAM base wait states not changed (default) - 1 = enable fast decode. DRAM base wait state is decreased by 1 - Note: This function may be enabled in 20/25Mhz operation to speed up - DRAM access. If bit 4 of index register 21h (cache enable - bit) is enabled, this bit is automatically disabled--even if - set to 1 - 2 unused - 1-0 ATCLK selection - 00 ATCLK = CLKI/6 (default) - 01 ATCLK = CLKI/4 (default) - 10 ATCLK = CLKI/3 - 11 ATCLK = CLK2I/5 (CLKI * 2 /5) - Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be - set to 0 when 82C493 is reset. -SeeAlso: #P0183,#P0185 - -Bitfields for OPTi-82C493 Shadow RAM Control Register 3: -Bit(s) Description (Table P0185) - 7 unused - 6 Shadow RAM copy enable for address C0000h - CFFFFh - 0 = Read/write at AT bus (default) - 1 = Read from AT bus and write into shadow RAM - 5 Shadow write protect at address C0000h - CFFFFh - 0 = Write protect disable (default) - 1 = Write protect enable - 4 enable Shadow RAM at C0000h - CFFFFh - 3 enable Shadow RAM at CC000h - CFFFFh - 2 enable Shadow RAM at C8000h - CBFFFh - 1 enable Shadow RAM at C4000h - C7FFFh - 0 enable Shadow RAM at C0000h - C3FFFh -Note: the default is disabled (0) for bits 4-0 -SeeAlso: #P0183,#P0184 - -Bitfields for OPTi-82C493 Control Register 3: -Bit(s) Description (Table P0186) - 7 enable NCA# pin to low state (default is 1 = enabled) - 6-5 unused - 4 Video BIOS at C0000h - C8000h non-cacheable - 0 = cacheable - 1 = non-cacheable (default) - 3-0 Cacheable address range for local memory - 0000 0 - 64MB - 0001 0 - 4MB (default) - 0010 0 - 8MB - 0011 0 - 12MB - 0100 0 - 16MB - 0101 0 - 20MB - 0110 0 - 24MB - 0111 0 - 28MB - 1000 0 - 32MB - 1001 0 - 36MB - 1010 0 - 40MB - 1011 0 - 44MB - 1100 0 - 48MB - 1101 0 - 52MB - 1110 0 - 56MB - 1111 0 - 60MB - Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or - 0-2 MB and independent of the value of bits 3-0 -SeeAlso: #P0179,#P0180 - -Bitfields for OPTi-82C493 Non-cacheable Block Register 1: -Bit(s) Description (Table P0187) - 7-5 Size of non-cachable memory block - 000 64K - 001 128K - 010 256K - 011 512K - 1xx disabled (default) - 4-2 unused - 1-0 Address bits 25 and 24 of non-cachable memory block (default = 00) -Note: this register is used together with configuration register 29h - (non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to - define a non-cacheable block. The starting address must be a - multiple of the block size -SeeAlso: #P0178,#P0188 - -Bitfields for OPTi-82C493 Non-cacheable Block Register 2: -Bit(s) Description (Table P0188) - 7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx) -Note: the block address is forced to be a multiple of the block size by - ignoring the appropriate number of the least-significant bits -SeeAlso: #P0178,#P0187 -*/ +/* + * 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 82C493/82C495 chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2008-2020 Tiseno100. + * Copyright 2016-2020 Miran Grca. + */ #include #include #include @@ -260,24 +25,101 @@ SeeAlso: #P0178,#P0187 #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/keyboard.h> #include <86box/mem.h> -#include <86box/fdd.h> -#include <86box/fdc.h> +#include <86box/port_92.h> #include <86box/chipset.h> typedef struct { - uint8_t cur_reg, - regs[16], + uint8_t idx, + regs[256], scratch[2]; } opti495_t; +#ifdef ENABLE_OPTI495_LOG +int opti495_do_log = ENABLE_OPTI495_LOG; + + +static void +opti495_log(const char *fmt, ...) +{ + va_list ap; + + if (opti495_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti495_log(fmt, ...) +#endif + + +static void +opti495_recalc(opti495_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + if (dev->regs[0x22] & 0x80) { + shadowbios = 1; + shadowbios_write = 0; + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + } else { + shadowbios = 0; + shadowbios_write = 1; + shflags = MEM_READ_INTERNAL | MEM_WRITE_DISABLED; + } + + mem_set_mem_state_both(0xf0000, 0x10000, shflags); + + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + + if ((dev->regs[0x22] & ((base >= 0xe0000) ? 0x20 : 0x40)) && + (dev->regs[0x23] & (1 << i))) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x26] & 0x40) { + shflags = MEM_READ_EXTANY; + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + + if ((dev->regs[0x26] & 0x10) && (dev->regs[0x26] & (1 << i))) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x26] & 0x40) { + shflags = MEM_READ_EXTANY; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + flushmmucache(); +} + + static void opti495_write(uint16_t addr, uint8_t val, void *priv) { @@ -285,26 +127,32 @@ opti495_write(uint16_t addr, uint8_t val, void *priv) switch (addr) { case 0x22: - dev->cur_reg = val; + opti495_log("[%04X:%08X] [W] dev->idx = %02X\n", CS, cpu_state.pc, val); + dev->idx = val; break; case 0x24: - if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) { - dev->regs[dev->cur_reg - 0x20] = val; - if (dev->cur_reg == 0x21) { - cpu_cache_ext_enabled = val & 0x10; - cpu_update_waitstates(); - } - if (dev->cur_reg == 0x22) { - if (!(val & 0x80)) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + dev->regs[dev->idx] = val; + opti495_log("[%04X:%08X] [W] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, val); + + switch(dev->idx) { + case 0x21: + cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); + cpu_update_waitstates(); + break; + + case 0x22: + case 0x23: + case 0x26: + opti495_recalc(dev); + break; } } break; + case 0xe1: case 0xe2: - dev->scratch[addr - 0xe1] = val; + dev->scratch[~addr & 0x01] = val; break; } } @@ -317,13 +165,18 @@ opti495_read(uint16_t addr, void *priv) opti495_t *dev = (opti495_t *) priv; switch (addr) { + case 0x22: + opti495_log("[%04X:%08X] [R] dev->idx = %02X\n", CS, cpu_state.pc, ret); + break; case 0x24: - if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) - ret = dev->regs[dev->cur_reg - 0x20]; + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + ret = dev->regs[dev->idx]; + opti495_log("[%04X:%08X] [R] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, ret); + } break; case 0xe1: case 0xe2: - ret = dev->scratch[addr - 0xe1]; + ret = dev->scratch[~addr & 0x01]; break; } @@ -346,24 +199,67 @@ opti495_init(const device_t *info) opti495_t *dev = (opti495_t *) malloc(sizeof(opti495_t)); memset(dev, 0, sizeof(opti495_t)); + device_add(&port_92_device); + io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); dev->scratch[0] = dev->scratch[1] = 0xff; - io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + if (info->local == 1) { + /* 85C495 */ + dev->regs[0x20] = 0x02; + dev->regs[0x21] = 0x20; + dev->regs[0x22] = 0xe4; + dev->regs[0x25] = 0xf0; + dev->regs[0x26] = 0x80; + dev->regs[0x27] = 0xb1; + dev->regs[0x28] = 0x80; + dev->regs[0x29] = 0x10; + } else { + /* 85C493 */ + dev->regs[0x20] = 0x40; + dev->regs[0x22] = 0x84; + dev->regs[0x24] = 0x87; + dev->regs[0x25] = 0xf1; /* Note: 0xf0 is also valid default. */ + dev->regs[0x27] = 0x91; + dev->regs[0x28] = 0x80; + dev->regs[0x29] = 0x10; + dev->regs[0x2a] = 0x80; + dev->regs[0x2b] = 0x10; + } - dev->regs[0x22 - 0x20] = 0x80; + opti495_recalc(dev); + + io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); return dev; } +const device_t opti493_device = { + .name = "OPTi 82C493", + .internal_name = "opti493", + .flags = 0, + .local = 0, + .init = opti495_init, + .close = opti495_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; const device_t opti495_device = { - "OPTi 82C495", - 0, - 0, - opti495_init, opti495_close, NULL, - NULL, NULL, NULL, - NULL + .name = "OPTi 82C495", + .internal_name = "opti495", + .flags = 0, + .local = 1, + .init = opti495_init, + .close = opti495_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c new file mode 100644 index 000000000..08c06d58c --- /dev/null +++ b/src/chipset/opti499.c @@ -0,0 +1,268 @@ +/* + * 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 82C493/82C499 chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2008-2020 Tiseno100. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#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/port_92.h> +#include <86box/chipset.h> + + +typedef struct +{ + uint8_t idx, + regs[256], scratch[2]; +} opti499_t; + + +#ifdef ENABLE_OPTI499_LOG +int opti499_do_log = ENABLE_OPTI499_LOG; + + +static void +opti499_log(const char *fmt, ...) +{ + va_list ap; + + if (opti499_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti499_log(fmt, ...) +#endif + + +static void +opti499_recalc(opti499_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + if (dev->regs[0x22] & 0x80) { + shadowbios = 1; + shadowbios_write = 0; + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + } else { + shadowbios = 0; + shadowbios_write = 1; + shflags = MEM_READ_INTERNAL | MEM_WRITE_DISABLED; + } + + mem_set_mem_state_both(0xf0000, 0x10000, shflags); + + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + + if ((dev->regs[0x22] & ((base >= 0xe0000) ? 0x20 : 0x40)) && + (dev->regs[0x23] & (1 << i))) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x2d] && (1 << ((i >> 1) + 2))) + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + else + shflags = MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + + if ((dev->regs[0x26] & 0x10) && (dev->regs[0x26] & (1 << i))) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x26] & 0x40) { + if (dev->regs[0x2d] && (1 << (i >> 1))) + shflags = MEM_READ_EXTANY; + else + shflags = MEM_READ_EXTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + if (dev->regs[0x2d] && (1 << (i >> 1))) + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + else + shflags = MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + } + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + flushmmucache_nopc(); +} + + +static void +opti499_write(uint16_t addr, uint8_t val, void *priv) +{ + opti499_t *dev = (opti499_t *) priv; + + switch (addr) { + case 0x22: + opti499_log("[%04X:%08X] [W] dev->idx = %02X\n", CS, cpu_state.pc, val); + dev->idx = val; + break; + case 0x24: + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + if (dev->idx == 0x20) + dev->regs[dev->idx] = (dev->regs[dev->idx] & 0xc0) | (val & 0x3f); + else + dev->regs[dev->idx] = val; + opti499_log("[%04X:%08X] [W] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, val); + + switch(dev->idx) { + case 0x20: + reset_on_hlt = !(val & 0x02); + break; + + case 0x21: + cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); + cpu_update_waitstates(); + break; + + case 0x22: case 0x23: + case 0x26: case 0x2d: + opti499_recalc(dev); + break; + } + } + break; + + case 0xe1: case 0xe2: + dev->scratch[~addr & 0x01] = val; + break; + } +} + + +static uint8_t +opti499_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + opti499_t *dev = (opti499_t *) priv; + + switch (addr) { + case 0x22: + opti499_log("[%04X:%08X] [R] dev->idx = %02X\n", CS, cpu_state.pc, ret); + break; + case 0x24: + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + if (dev->idx == 0x2d) + ret = dev->regs[dev->idx] & 0xbf; + else + ret = dev->regs[dev->idx]; + opti499_log("[%04X:%08X] [R] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, ret); + } + break; + case 0xe1: + case 0xe2: + ret = dev->scratch[~addr & 0x01]; + break; + } + + return ret; +} + + +static void +opti499_reset(void *priv) +{ + opti499_t *dev = (opti499_t *) priv; + + memset(dev->regs, 0xff, sizeof(dev->regs)); + memset(&(dev->regs[0x20]), 0x00, 14 * sizeof(uint8_t)); + + dev->scratch[0] = dev->scratch[1] = 0xff; + + dev->regs[0x22] = 0x84; + dev->regs[0x24] = 0x87; + dev->regs[0x25] = 0xf0; + dev->regs[0x27] = 0xd1; + dev->regs[0x28] = dev->regs[0x2a] = 0x80; + dev->regs[0x29] = dev->regs[0x2b] = 0x10; + dev->regs[0x2d] = 0x40; + + reset_on_hlt = 1; + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + opti499_recalc(dev); + + free(dev); +} + + +static void +opti499_close(void *priv) +{ + opti499_t *dev = (opti499_t *) priv; + + free(dev); +} + + +static void * +opti499_init(const device_t *info) +{ + opti499_t *dev = (opti499_t *) malloc(sizeof(opti499_t)); + memset(dev, 0, sizeof(opti499_t)); + + device_add(&port_92_device); + + io_sethandler(0x0022, 0x0001, opti499_read, NULL, NULL, opti499_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti499_read, NULL, NULL, opti499_write, NULL, NULL, dev); + + opti499_reset(dev); + + io_sethandler(0x00e1, 0x0002, opti499_read, NULL, NULL, opti499_write, NULL, NULL, dev); + + return dev; +} + +const device_t opti499_device = { + .name = "OPTi 82C499", + .internal_name = "opti499", + .flags = 0, + .local = 1, + .init = opti499_init, + .close = opti499_close, + .reset = opti499_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti5x7.c b/src/chipset/opti5x7.c index 4a83ed98d..f0459a97f 100644 --- a/src/chipset/opti5x7.c +++ b/src/chipset/opti5x7.c @@ -1,5 +1,21 @@ -/*Based off the OPTI 82C546/82C547 datasheet. -The earlier 596/597 appears to be register compatible with the 546/547 from testing.*/ +/* + * 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 82C546/82C547(Python) & 82C596/82C597(Cobra) chipsets. + + * Authors: plant/nerd73, + * Miran Grca, + * Tiseno100 + * + * Copyright 2020 plant/nerd73. + * Copyright 2020 Miran Grca. + * Copyright 2021 Tiseno100. + */ #include #include #include @@ -12,114 +28,163 @@ The earlier 596/597 appears to be register compatible with the 546/547 from test #include <86box/timer.h> #include <86box/io.h> #include <86box/device.h> -#include <86box/keyboard.h> #include <86box/mem.h> -#include <86box/fdd.h> -#include <86box/fdc.h> #include <86box/port_92.h> #include <86box/chipset.h> - typedef struct { - uint8_t cur_reg, - regs[64]; - port_92_t *port_92; + uint8_t idx, regs[16]; } opti5x7_t; +#ifdef ENABLE_OPTI5X7_LOG +int opti5x7_do_log = ENABLE_OPTI5X7_LOG; + static void -opti5x7_recalcmapping(opti5x7_t *dev) +opti5x7_log(const char *fmt, ...) { - uint32_t shflags = 0; + va_list ap; - shadowbios = 0; - shadowbios_write = 0; - - - shadowbios |= !!(dev->regs[0x06] & 0x05); - shadowbios_write |= !!(dev->regs[0x06] & 0x0a); - - shflags = (dev->regs[0x06] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - shflags |= (dev->regs[0x06] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; - mem_set_mem_state(0xe0000, 0x10000, shflags); - - shflags = (dev->regs[0x06] & 0x04) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - shflags |= (dev->regs[0x06] & 0x08) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; - mem_set_mem_state(0xf0000, 0x10000, shflags); - - flushmmucache(); -} -static void -opti5x7_write(uint16_t addr, uint8_t val, void *priv) -{ - opti5x7_t *dev = (opti5x7_t *) priv; -// pclog("Write %02x to OPTi 5x7 address %02x\n", val, addr); - - switch (addr) { - case 0x22: - dev->cur_reg = val; - break; - case 0x24: - dev->regs[dev->cur_reg] = val; - if (dev->cur_reg == 0x02) { - cpu_cache_ext_enabled = val & 0x10; - } - if (dev->cur_reg == 0x06) { - opti5x7_recalcmapping(dev); - } - break; + if (opti5x7_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } +#else +#define opti5x7_log(fmt, ...) +#endif +static void +opti5x7_shadow_map(int cur_reg, opti5x7_t *dev) +{ + +/* +Register 4h: Cxxxx Segment +Register 5h: Dxxxx Segment + +Bits 7-6: xC000-xFFFF +Bits 5-4: x8000-xBFFF +Bits 3-2: x4000-x7FFF +Bits 0-1: x0000-x3FFF + + x-y + 0 0 Read/Write AT bus + 1 0 Read from AT - Write to DRAM + 1 1 Read from DRAM - Write to DRAM + 0 1 Read from DRAM (write protected) +*/ + if (cur_reg == 0x06) + { + mem_set_mem_state_both(0xe0000, 0x10000, ((dev->regs[6] & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[6] & 2) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + mem_set_mem_state_both(0xf0000, 0x10000, ((dev->regs[6] & 4) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[6] & 8) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + } + else + { + for (int i = 0; i < 4; i++) + mem_set_mem_state_both(0xc0000 + ((cur_reg & 1) << 16) + (i << 14), 0x4000, ((dev->regs[cur_reg] & (1 << (2 * i))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((dev->regs[cur_reg] & (2 << (2 * i))) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); + } + + flushmmucache_nopc(); +} + +static void +opti5x7_write(uint16_t addr, uint8_t val, void *priv) +{ + opti5x7_t *dev = (opti5x7_t *)priv; + + switch (addr) + { + case 0x22: + dev->idx = val; + break; + case 0x24: + switch (dev->idx) + { + case 0x00: /* DRAM Configuration Register #1 */ + dev->regs[dev->idx] = val & 0x7f; + break; + case 0x01: /* DRAM Control Register #1 */ + dev->regs[dev->idx] = val; + break; + case 0x02: /* Cache Control Register #1 */ + dev->regs[dev->idx] = val; + cpu_cache_ext_enabled = !!(dev->regs[0x02] & 0x0c); + cpu_update_waitstates(); + break; + case 0x03: /* Cache Control Register #2 */ + dev->regs[dev->idx] = val; + break; + case 0x04: /* Shadow RAM Control Register #1 */ + case 0x05: /* Shadow RAM Control Register #2 */ + case 0x06: /* Shadow RAM Control Register #3 */ + dev->regs[dev->idx] = val; + opti5x7_shadow_map(dev->idx, dev); + break; + case 0x07: /* Tag Test Register */ + case 0x08: /* CPU Cache Control Register #1 */ + case 0x09: /* System Memory Function Register #1 */ + case 0x0a: /* System Memory Address Decode Register #1 */ + case 0x0b: /* System Memory Address Decode Register #2 */ + dev->regs[dev->idx] = val; + break; + case 0x0c: /* Extended DMA Register */ + dev->regs[dev->idx] = val & 0xcf; + break; + case 0x0d: /* ROMCS# Register */ + case 0x0e: /* Local Master Preemption Register */ + case 0x0f: /* Deturbo Control Register #1 */ + case 0x10: /* Cache Write-Hit Control Register */ + case 0x11: /* Master Cycle Control Register */ + dev->regs[dev->idx] = val; + break; + } + opti5x7_log("OPTi 5x7: dev->regs[%02x] = %02x\n", dev->idx, dev->regs[dev->idx]); + break; + } +} static uint8_t opti5x7_read(uint16_t addr, void *priv) { - uint8_t ret = 0xff; - opti5x7_t *dev = (opti5x7_t *) priv; + opti5x7_t *dev = (opti5x7_t *)priv; - switch (addr) { - case 0x24: -// pclog("Read from OPTI 5x7 register %02x\n", dev->cur_reg); - ret = dev->regs[dev->cur_reg]; - break; - } - - return ret; + return (addr == 0x24) ? dev->regs[dev->idx] : 0xff; } - static void opti5x7_close(void *priv) { - opti5x7_t *dev = (opti5x7_t *) priv; + opti5x7_t *dev = (opti5x7_t *)priv; free(dev); } - static void * opti5x7_init(const device_t *info) { - opti5x7_t *dev = (opti5x7_t *) malloc(sizeof(opti5x7_t)); + opti5x7_t *dev = (opti5x7_t *)malloc(sizeof(opti5x7_t)); memset(dev, 0, sizeof(opti5x7_t)); io_sethandler(0x0022, 0x0001, opti5x7_read, NULL, NULL, opti5x7_write, NULL, NULL, dev); io_sethandler(0x0024, 0x0001, opti5x7_read, NULL, NULL, opti5x7_write, NULL, NULL, dev); - dev->port_92 = device_add(&port_92_device); -// pclog("OPTi 5x7 init\n"); - opti5x7_recalcmapping(dev); - + device_add(&port_92_device); return dev; } const device_t opti5x7_device = { - "OPTi 82C5x6/82C5x7", - 0, - 0, - opti5x7_init, opti5x7_close, NULL, - NULL, NULL, NULL, - NULL + .name = "OPTi 82C5x6/82C5x7", + .internal_name = "opti5x7", + .flags = 0, + .local = 0, + .init = opti5x7_init, + .close = opti5x7_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/opti822.c b/src/chipset/opti822.c new file mode 100644 index 000000000..0235e3ee9 --- /dev/null +++ b/src/chipset/opti822.c @@ -0,0 +1,324 @@ +/* + * 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 82C822 VESA Local Bus to PCI Bridge Interface. + * + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#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/pci.h> + +#include <86box/chipset.h> + +/* Shadow RAM */ +#define SYSTEM_READ ((dev->pci_conf[0x44] & 2) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define SYSTEM_WRITE ((dev->pci_conf[0x44] & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) +#define SHADOW_READ ((dev->pci_conf[cur_reg] & (1 << (4 + i))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define SHADOW_WRITE ((dev->pci_conf[cur_reg] & (1 << i)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) + +#ifdef ENABLE_OPTI822_LOG +int opti822_do_log = ENABLE_OPTI822_LOG; +static void +opti822_log(const char *fmt, ...) +{ + va_list ap; + + if (opti822_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti822_log(fmt, ...) +#endif + +typedef struct opti822_t +{ + uint8_t pci_conf[256]; +} opti822_t; + +int opti822_irq_routing[7] = {5, 9, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f}; + +void opti822_shadow(int cur_reg, opti822_t *dev) +{ + if (cur_reg == 0x44) + mem_set_mem_state_both(0xf0000, 0x10000, SYSTEM_READ | SYSTEM_WRITE); + else + for (int i = 0; i < 4; i++) + mem_set_mem_state_both(0xe0000 - (((cur_reg & 3) - 1) << 16) + (i << 14), 0x4000, SHADOW_READ | SHADOW_WRITE); + + flushmmucache_nopc(); +} + +static void +opti822_write(int func, int addr, uint8_t val, void *priv) +{ + + opti822_t *dev = (opti822_t *)priv; + + switch (func) + { + case 0x04: /* Command Register */ + dev->pci_conf[addr] = val & 0x40; + break; + + case 0x05: /* Command Register */ + dev->pci_conf[addr] = val & 1; + break; + + case 0x06: /* Status Register */ + dev->pci_conf[addr] |= val & 0xc0; + break; + + case 0x07: /* Status Register */ + dev->pci_conf[addr] = val & 0xa9; + break; + + case 0x40: + dev->pci_conf[addr] = val & 0xc0; + break; + + case 0x41: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0x42: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x43: + dev->pci_conf[addr] = val; + break; + + case 0x44: /* Shadow RAM */ + case 0x45: + case 0x46: + case 0x47: + dev->pci_conf[addr] = (addr == 0x44) ? (val & 0xcb) : val; + opti822_shadow(addr, dev); + break; + + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + dev->pci_conf[addr] = val; + break; + + case 0x58: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + dev->pci_conf[addr] = val; + break; + + case 0x60: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + dev->pci_conf[addr] = val; + break; + + case 0x68: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + dev->pci_conf[addr] = val; + break; + + case 0x70: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x71: + case 0x72: + case 0x73: + dev->pci_conf[addr] = val; + break; + + case 0x74: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x75: + case 0x76: + dev->pci_conf[addr] = val; + break; + + case 0x77: + dev->pci_conf[addr] = val & 0xe7; + break; + + case 0x78: + dev->pci_conf[addr] = val; + break; + + case 0x79: + dev->pci_conf[addr] = val & 0xfc; + break; + + case 0x7a: + case 0x7b: + case 0x7c: + case 0x7d: + case 0x7e: + dev->pci_conf[addr] = val; + break; + + case 0x7f: + dev->pci_conf[addr] = val & 3; + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x86: + dev->pci_conf[addr] = val; + break; + + case 0x88: /* PCI IRQ Routing */ + case 0x89: /* Very hacky implementation. Needs surely a rewrite after */ + case 0x8a: /* a PCI rework happens. */ + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + dev->pci_conf[addr] = val; + if (addr % 2) + { + pci_set_irq_routing(PCI_INTB, ((val & 0x0f) != 0) ? opti822_irq_routing[(val & 7) - 1] : PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTA, (((val >> 4) & 0x0f) != 0) ? opti822_irq_routing[((val >> 4) & 7) - 1] : PCI_IRQ_DISABLED); + } + else + { + pci_set_irq_routing(PCI_INTD, ((val & 0x0f) != 0) ? opti822_irq_routing[(val & 7) - 1] : PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, (((val >> 4) & 0x0f) != 0) ? opti822_irq_routing[((val >> 4) & 7) - 1] : PCI_IRQ_DISABLED); + } + break; + } + + opti822_log("OPTI822: dev->pci_conf[%02x] = %02x\n", addr, dev->pci_conf[addr]); +} + +static uint8_t +opti822_read(int func, int addr, void *priv) +{ + opti822_t *dev = (opti822_t *)priv; + return dev->pci_conf[addr]; +} + +static void +opti822_reset(void *priv) +{ + opti822_t *dev = (opti822_t *)priv; + + dev->pci_conf[0x00] = 0x45; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x22; + dev->pci_conf[0x03] = 0xc8; + dev->pci_conf[0x04] = 7; + dev->pci_conf[0x06] = 0x40; + dev->pci_conf[0x07] = 1; + dev->pci_conf[0x08] = 1; + dev->pci_conf[0x0b] = 6; + dev->pci_conf[0x0d] = 0x20; + dev->pci_conf[0x40] = 1; + dev->pci_conf[0x43] = 0x20; + dev->pci_conf[0x52] = 6; + dev->pci_conf[0x53] = 0x90; +} + +static void +opti822_close(void *priv) +{ + opti822_t *dev = (opti822_t *)priv; + + free(dev); +} + +static void * +opti822_init(const device_t *info) +{ + opti822_t *dev = (opti822_t *)malloc(sizeof(opti822_t)); + memset(dev, 0, sizeof(opti822_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, opti822_read, opti822_write, dev); + + opti822_reset(dev); + + return dev; +} + +const device_t opti822_device = { + .name = "OPTi 82C822 PCIB", + .internal_name = "opti822", + .flags = DEVICE_PCI, + .local = 0, + .init = opti822_init, + .close = opti822_close, + .reset = opti822_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c new file mode 100644 index 000000000..9eb360e02 --- /dev/null +++ b/src/chipset/opti895.c @@ -0,0 +1,301 @@ +/* + * 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 82C802G/82C895 chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2008-2020 Tiseno100. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#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/smram.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + + +typedef struct +{ + uint8_t idx, forced_green, + regs[256], + scratch[2]; + + smram_t *smram; +} opti895_t; + + +#ifdef ENABLE_OPTI895_LOG +int opti895_do_log = ENABLE_OPTI895_LOG; + + +static void +opti895_log(const char *fmt, ...) +{ + va_list ap; + + if (opti895_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti895_log(fmt, ...) +#endif + + +static void +opti895_recalc(opti895_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + if (dev->regs[0x22] & 0x80) { + shadowbios = 1; + shadowbios_write = 0; + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + } else { + shadowbios = 0; + shadowbios_write = 1; + shflags = MEM_READ_INTERNAL | MEM_WRITE_DISABLED; + } + + mem_set_mem_state_both(0xf0000, 0x10000, shflags); + + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + + if (dev->regs[0x23] & (1 << i)) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + shflags = (dev->regs[0x2d] & (1 << ((i >> 1) + 2))) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + if (dev->regs[0x26] & 0x40) + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + else { + if (dev->regs[0x26] & 0x80) + shflags |= (dev->regs[0x2d] & (1 << ((i >> 1) + 2))) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + else + shflags |= MEM_WRITE_EXTERNAL; + } + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + + if (dev->regs[0x26] & (1 << i)) { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } else { + shflags = (dev->regs[0x2d] & (1 << (i >> 1))) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + if (dev->regs[0x26] & 0x40) + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + else { + if (dev->regs[0x26] & 0x80) + shflags |= (dev->regs[0x2d] & (1 << (i >> 1))) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + else + shflags |= MEM_WRITE_EXTERNAL; + } + } + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + flushmmucache_nopc(); +} + + +static void +opti895_write(uint16_t addr, uint8_t val, void *priv) +{ + opti895_t *dev = (opti895_t *) priv; + + switch (addr) { + case 0x22: + dev->idx = val; + break; + case 0x23: + if (dev->idx == 0x01) { + dev->regs[dev->idx] = val; + opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); + } + break; + case 0x24: + if (((dev->idx >= 0x20) && (dev->idx <= 0x2f)) || + ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { + dev->regs[dev->idx] = val; + opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); + + switch(dev->idx) { + case 0x21: + cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); + cpu_update_waitstates(); + break; + + case 0x22: + case 0x23: + case 0x26: + case 0x2d: + opti895_recalc(dev); + break; + + case 0x24: + smram_state_change(dev->smram, 0, !!(val & 0x80)); + break; + + case 0xe0: + if (!(val & 0x01)) + dev->forced_green = 0; + break; + + case 0xe1: + if ((val & 0x08) && (dev->regs[0xe0] & 0x01)) { + smi_raise(); + dev->forced_green = 1; + break; + } + break; + } + } + break; + + case 0xe1: + case 0xe2: + dev->scratch[addr - 0xe1] = val; + break; + } +} + + +static uint8_t +opti895_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + opti895_t *dev = (opti895_t *) priv; + + switch (addr) { + case 0x23: + if (dev->idx == 0x01) + ret = dev->regs[dev->idx]; + break; + case 0x24: + if (((dev->idx >= 0x20) && (dev->idx <= 0x2f)) || + ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { + ret = dev->regs[dev->idx]; + if (dev->idx == 0xe0) + ret = (ret & 0xf6) | (in_smm ? 0x00 : 0x08) | !!dev->forced_green; + } + break; + case 0xe1: + case 0xe2: + ret = dev->scratch[addr - 0xe1]; + break; + } + + return ret; +} + + +static void +opti895_close(void *priv) +{ + opti895_t *dev = (opti895_t *) priv; + + smram_del(dev->smram); + + free(dev); +} + + +static void * +opti895_init(const device_t *info) +{ + opti895_t *dev = (opti895_t *) malloc(sizeof(opti895_t)); + memset(dev, 0, sizeof(opti895_t)); + + device_add(&port_92_device); + + io_sethandler(0x0022, 0x0003, opti895_read, NULL, NULL, opti895_write, NULL, NULL, dev); + + dev->scratch[0] = dev->scratch[1] = 0xff; + + dev->regs[0x01] = 0xc0; + + dev->regs[0x22] = 0xc4; + dev->regs[0x25] = 0x7c; + dev->regs[0x26] = 0x10; + dev->regs[0x27] = 0xde; + dev->regs[0x28] = 0xf8; + dev->regs[0x29] = 0x10; + dev->regs[0x2a] = 0xe0; + dev->regs[0x2b] = 0x10; + dev->regs[0x2d] = 0xc0; + + dev->regs[0xe8] = 0x08; + dev->regs[0xe9] = 0x08; + dev->regs[0xeb] = 0xff; + dev->regs[0xef] = 0x40; + + opti895_recalc(dev); + + io_sethandler(0x00e1, 0x0002, opti895_read, NULL, NULL, opti895_write, NULL, NULL, dev); + + dev->smram = smram_add(); + + smram_enable(dev->smram, 0x00030000, 0x000b0000, 0x00010000, 0, 1); + + return dev; +} + +const device_t opti802g_device = { + .name = "OPTi 82C802G", + .internal_name = "opti802g", + .flags = 0, + .local = 0, + .init = opti895_init, + .close = opti895_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t opti895_device = { + .name = "OPTi 82C895", + .internal_name = "opti895", + .flags = 0, + .local = 0, + .init = opti895_init, + .close = opti895_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 35e97714e..621f7d9c5 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -34,28 +34,6 @@ #include <86box/port_92.h> #include <86box/chipset.h> -typedef struct { - void *parent; - int bank; -} ram_struct_t; - -typedef struct { - int cfg_index; - uint8_t cfg_regs[256]; - int cfg_enable; - - int ram_config; - - mem_mapping_t ram_mapping[2]; - - ram_struct_t ram_struct[3]; - - uint32_t ram_virt_base[2], ram_phys_base[2]; - uint32_t ram_mask[2]; - int row_virt_shift[2], row_phys_shift[2]; - int ram_interleaved[2]; - int ibank_shift[2]; -} scamp_t; #define CFG_ID 0x00 #define CFG_SLTPTR 0x02 @@ -71,705 +49,922 @@ typedef struct { #define RAMMAP_REMP386 (1 << 4) +#define EMSEN1_EMSMAP (1 << 4) +#define EMSEN1_EMSENAB (1 << 7) + +#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0])) + + /*Commodore SL386SX requires proper memory slot decoding to detect memory size. Therefore we emulate the SCAMP memory address decoding, and therefore are limited to the DRAM combinations supported by the actual chip*/ enum { - BANK_NONE, - BANK_256K, - BANK_256K_INTERLEAVED, - BANK_1M, - BANK_1M_INTERLEAVED, - BANK_4M, - BANK_4M_INTERLEAVED + BANK_NONE, + BANK_256K, + BANK_256K_INTERLEAVED, + BANK_1M, + BANK_1M_INTERLEAVED, + BANK_4M, + BANK_4M_INTERLEAVED }; + +typedef struct { + void * parent; + int bank; +} ram_struct_t; + +typedef struct { + void * parent; + int segment; +} ems_struct_t; + +typedef struct { + int cfg_index; + uint8_t cfg_regs[256]; + int cfg_enable, ram_config; + + int ems_index; + int ems_autoinc; + uint16_t ems[0x24]; + mem_mapping_t ems_mappings[20]; /*a0000-effff*/ + uint32_t mappings[20]; + + mem_mapping_t ram_mapping[2]; + ram_struct_t ram_struct[2]; + ems_struct_t ems_struct[20]; + + uint32_t ram_virt_base[2], ram_phys_base[2]; + uint32_t ram_mask[2]; + int row_virt_shift[2], row_phys_shift[2]; + int ram_interleaved[2], ibank_shift[2]; + + port_92_t * port_92; +} scamp_t; + static const struct { - int size_kb; - int rammap; - int bank[2]; + int size_kb; + int rammap; + int bank[2]; } ram_configs[] = { - {512, 0x0, {BANK_256K, BANK_NONE}}, - {1024, 0x1, {BANK_256K_INTERLEAVED, BANK_NONE}}, - {1536, 0x2, {BANK_256K_INTERLEAVED, BANK_256K}}, - {2048, 0x3, {BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}}, - {3072, 0xc, {BANK_256K_INTERLEAVED, BANK_1M}}, - {4096, 0x5, {BANK_1M_INTERLEAVED, BANK_NONE}}, - {5120, 0xd, {BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}}, - {6144, 0x6, {BANK_1M_INTERLEAVED, BANK_1M}}, - {8192, 0x7, {BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}}, - {12288, 0xe, {BANK_1M_INTERLEAVED, BANK_4M}}, - {16384, 0x9, {BANK_4M_INTERLEAVED, BANK_NONE}}, + {512, 0x0, {BANK_256K, BANK_NONE}}, + {1024, 0x1, {BANK_256K_INTERLEAVED, BANK_NONE}}, + {1536, 0x2, {BANK_256K_INTERLEAVED, BANK_256K}}, + {2048, 0x3, {BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}}, + {3072, 0xc, {BANK_256K_INTERLEAVED, BANK_1M}}, + {4096, 0x5, {BANK_1M_INTERLEAVED, BANK_NONE}}, + {5120, 0xd, {BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}}, + {6144, 0x6, {BANK_1M_INTERLEAVED, BANK_1M}}, + {8192, 0x7, {BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}}, + {12288, 0xe, {BANK_1M_INTERLEAVED, BANK_4M}}, + {16384, 0x9, {BANK_4M_INTERLEAVED, BANK_NONE}}, }; static const struct { - int bank[2]; - int remapped; + int bank[2]; + int remapped; } rammap[16] = { - {{BANK_256K, BANK_NONE}, 0}, - {{BANK_256K_INTERLEAVED, BANK_NONE}, 0}, - {{BANK_256K_INTERLEAVED, BANK_256K}, 0}, - {{BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}, 0}, + {{BANK_256K, BANK_NONE}, 0}, + {{BANK_256K_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_256K_INTERLEAVED, BANK_256K}, 0}, + {{BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}, 0}, - {{BANK_1M, BANK_NONE}, 0}, - {{BANK_1M_INTERLEAVED, BANK_NONE}, 0}, - {{BANK_1M_INTERLEAVED, BANK_1M}, 0}, - {{BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, + {{BANK_1M, BANK_NONE}, 0}, + {{BANK_1M_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_1M_INTERLEAVED, BANK_1M}, 0}, + {{BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, - {{BANK_4M, BANK_NONE}, 0}, - {{BANK_4M_INTERLEAVED, BANK_NONE}, 0}, - {{BANK_NONE, BANK_4M}, 1}, /*Bank 2 remapped to 0*/ - {{BANK_NONE, BANK_4M_INTERLEAVED}, 1}, /*Banks 2/3 remapped to 0/1*/ + {{BANK_4M, BANK_NONE}, 0}, + {{BANK_4M_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_NONE, BANK_4M}, 1}, /*Bank 2 remapped to 0*/ + {{BANK_NONE, BANK_4M_INTERLEAVED}, 1}, /*Banks 2/3 remapped to 0/1*/ - {{BANK_256K_INTERLEAVED, BANK_1M}, 0}, - {{BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, - {{BANK_1M_INTERLEAVED, BANK_4M}, 0}, - {{BANK_1M_INTERLEAVED, BANK_4M_INTERLEAVED}, 0}, /*Undocumented - probably wrong!*/ + {{BANK_256K_INTERLEAVED, BANK_1M}, 0}, + {{BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, + {{BANK_1M_INTERLEAVED, BANK_4M}, 0}, + {{BANK_1M_INTERLEAVED, BANK_4M_INTERLEAVED}, 0}, /*Undocumented - probably wrong!*/ }; -/*The column bits masked when using 256kbit DRAMs in 4Mbit mode aren't contiguous, - so we use separate routines for that special case*/ -static uint8_t + +/* The column bits masked when using 256kbit DRAMs in 4Mbit mode aren't contiguous, + so we use separate routines for that special case */ +static uint8_t ram_mirrored_256k_in_4mi_read(uint32_t addr, void *priv) { - ram_struct_t *rs = (ram_struct_t *) priv; - scamp_t *dev = rs->parent; - int bank = rs->bank; - int row, column, byte; + ram_struct_t *rs = (ram_struct_t *) priv; + scamp_t *dev = rs->parent; + int bank = rs->bank, byte; + int row, column; - addr -= dev->ram_virt_base[bank]; - byte = addr & 1; - if (!dev->ram_interleaved[bank]) { - if (addr & 0x400) - return 0xff; + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return 0xff; - addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); - column = (addr >> 1) & dev->ram_mask[bank]; - row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); - addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); - } else { - column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); - row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); - addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); - } + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } - return ram[addr + dev->ram_phys_base[bank]]; + return ram[addr + dev->ram_phys_base[bank]]; } -static void + + +static void ram_mirrored_256k_in_4mi_write(uint32_t addr, uint8_t val, void *priv) { - ram_struct_t *rs = (ram_struct_t *) priv; - scamp_t *dev = rs->parent; - int bank = rs->bank; - int row, column, byte; + ram_struct_t *rs = (ram_struct_t *) priv; + scamp_t *dev = rs->parent; + int bank = rs->bank, byte; + int row, column; - addr -= dev->ram_virt_base[bank]; - byte = addr & 1; - if (!dev->ram_interleaved[bank]) { - if (addr & 0x400) - return; + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return; - addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); - column = (addr >> 1) & dev->ram_mask[bank]; - row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); - addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); - } else { - column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); - row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); - addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); - } + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } - ram[addr + dev->ram_phys_base[bank]] = val; + ram[addr + dev->ram_phys_base[bank]] = val; } + /*Read/write handlers for interleaved memory banks. We must keep CPU and ram array mapping linear, otherwise we won't be able to execute code from interleaved banks*/ -static uint8_t +static uint8_t ram_mirrored_interleaved_read(uint32_t addr, void *priv) { - ram_struct_t *rs = (ram_struct_t *) priv; - scamp_t *dev = rs->parent; - int bank = rs->bank; - int row, column, byte; + ram_struct_t *rs = (ram_struct_t *) priv; + scamp_t *dev = rs->parent; + int bank = rs->bank, byte; + int row, column; - addr -= dev->ram_virt_base[bank]; - byte = addr & 1; - if (!dev->ram_interleaved[bank]) { - if (addr & 0x400) - return 0xff; + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return 0xff; - addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); - column = (addr >> 1) & dev->ram_mask[bank]; - row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; - addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); - } else { - column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); - row = (addr >> (dev->row_virt_shift[bank]+1)) & dev->ram_mask[bank]; - - addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); - } + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = (addr >> (dev->row_virt_shift[bank]+1)) & dev->ram_mask[bank]; - return ram[addr + dev->ram_phys_base[bank]]; + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } + + return ram[addr + dev->ram_phys_base[bank]]; } -static void + + +static void ram_mirrored_interleaved_write(uint32_t addr, uint8_t val, void *priv) { - ram_struct_t *rs = (ram_struct_t *) priv; - scamp_t *dev = rs->parent; - int bank = rs->bank; - int row, column, byte; + ram_struct_t *rs = (ram_struct_t *) priv; + scamp_t *dev = rs->parent; + int bank = rs->bank, byte; + int row, column; - addr -= dev->ram_virt_base[bank]; - byte = addr & 1; - if (!dev->ram_interleaved[bank]) { - if (addr & 0x400) - return; + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return; - addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); - column = (addr >> 1) & dev->ram_mask[bank]; - row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; - addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); - } - else { - column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); - row = (addr >> (dev->row_virt_shift[bank]+1)) & dev->ram_mask[bank]; + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = (addr >> (dev->row_virt_shift[bank]+1)) & dev->ram_mask[bank]; - addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); - } + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } - ram[addr + dev->ram_phys_base[bank]] = val; + ram[addr + dev->ram_phys_base[bank]] = val; } -static uint8_t + +static uint8_t ram_mirrored_read(uint32_t addr, void *priv) { - ram_struct_t *rs = (ram_struct_t *) priv; - scamp_t *dev = rs->parent; - int bank = rs->bank; - int row, column, byte; - - addr -= dev->ram_virt_base[bank]; - byte = addr & 1; - column = (addr >> 1) & dev->ram_mask[bank]; - row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; - addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + ram_struct_t *rs = (ram_struct_t *) priv; + scamp_t *dev = rs->parent; + int bank = rs->bank, byte; + int row, column; - return ram[addr + dev->ram_phys_base[bank]]; + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + + return ram[addr + dev->ram_phys_base[bank]]; } -static void + + +static void ram_mirrored_write(uint32_t addr, uint8_t val, void *priv) { - ram_struct_t *rs = (ram_struct_t *) priv; - scamp_t *dev = rs->parent; - int bank = rs->bank; - int row, column, byte; - - addr -= dev->ram_virt_base[bank]; - byte = addr & 1; - column = (addr >> 1) & dev->ram_mask[bank]; - row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; - addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + ram_struct_t *rs = (ram_struct_t *) priv; + scamp_t *dev = rs->parent; + int bank = rs->bank, byte; + int row, column; - ram[addr + dev->ram_phys_base[bank]] = val; + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + + ram[addr + dev->ram_phys_base[bank]] = val; } -static void + +static void recalc_mappings(void *priv) { - scamp_t *dev = (scamp_t *) priv; - int c; - uint32_t virt_base = 0; - uint8_t cur_rammap = dev->cfg_regs[CFG_RAMMAP] & 0xf; - int bank_nr = 0; - - for (c = 0; c < 2; c++) - mem_mapping_disable(&dev->ram_mapping[c]); + scamp_t *dev = (scamp_t *) priv; + int c; + uint32_t virt_base = 0, old_virt_base; + uint8_t cur_rammap = dev->cfg_regs[CFG_RAMMAP] & 0xf; + int bank_nr = 0, phys_bank; - /*Once the BIOS programs the correct DRAM configuration, switch to regular - linear memory mapping*/ - if (cur_rammap == ram_configs[dev->ram_config].rammap) { - mem_mapping_set_handler(&ram_low_mapping, - mem_read_ram, mem_read_ramw, mem_read_raml, - mem_write_ram, mem_write_ramw, mem_write_raml); - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_enable(&ram_high_mapping); - return; - } else { - mem_mapping_set_handler(&ram_low_mapping, - ram_mirrored_read, NULL, NULL, - ram_mirrored_write, NULL, NULL); - mem_mapping_disable(&ram_low_mapping); - } - - if (rammap[cur_rammap].bank[0] == BANK_NONE) - bank_nr = 1; + mem_set_mem_state_both((1 << 20), (16256 - 1024) * 1024, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); -/* pclog("Bank remap, cur_rammap=%x\n", cur_rammap); */ - - for (; bank_nr < 2; bank_nr++) { - uint32_t old_virt_base = virt_base; - int phys_bank = ram_configs[dev->ram_config].bank[bank_nr]; - -/* pclog(" Bank %i: phys_bank=%i rammap_bank=%i virt_base=%08x phys_base=%08x\n", bank_nr, phys_bank, rammap[cur_rammap].bank[bank_nr], virt_base, dev->ram_phys_base[bank_nr]); */ - dev->ram_virt_base[bank_nr] = virt_base; + for (c = 0; c < 2; c++) + mem_mapping_disable(&dev->ram_mapping[c]); - if (virt_base == 0) { - switch (rammap[cur_rammap].bank[bank_nr]) { - case BANK_NONE: - fatal("Bank 0 is empty!\n"); - break; + /* Once the BIOS programs the correct DRAM configuration, switch to regular + linear memory mapping */ + if (cur_rammap == ram_configs[dev->ram_config].rammap) { + mem_mapping_set_handler(&ram_low_mapping, + mem_read_ram, mem_read_ramw, mem_read_raml, + mem_write_ram, mem_write_ramw, mem_write_raml); + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + if (mem_size > 1024) + mem_set_mem_state_both((1 << 20), (mem_size - 1024) << 10, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_enable(&ram_high_mapping); + return; + } else { + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_low_mapping); + } - case BANK_256K: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); - mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); - } - virt_base += 512*1024; - dev->row_virt_shift[bank_nr] = 10; - break; + if (rammap[cur_rammap].bank[0] == BANK_NONE) + bank_nr = 1; - case BANK_256K_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); - } - virt_base += 512*1024*2; - dev->row_virt_shift[bank_nr] = 10; - break; + for (; bank_nr < 2; bank_nr++) { + old_virt_base = virt_base; + phys_bank = ram_configs[dev->ram_config].bank[bank_nr]; - case BANK_1M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x100000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - } - virt_base += 2048*1024; - dev->row_virt_shift[bank_nr] = 11; - break; + dev->ram_virt_base[bank_nr] = virt_base; - case BANK_1M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x300000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - } - virt_base += 2048*1024*2; - dev->row_virt_shift[bank_nr] = 11; - break; + if (virt_base == 0) { + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_NONE: + fatal(" Bank %i is empty!\n }\n}\n", bank_nr); + break; - case BANK_4M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x700000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - } - virt_base += 8192*1024; - dev->row_virt_shift[bank_nr] = 12; - break; + case BANK_256K: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); + mem_mapping_set_p(&ram_low_mapping, (void *)&dev->ram_struct[bank_nr]); + } + virt_base += (1 << 19); + dev->row_virt_shift[bank_nr] = 10; + break; - case BANK_4M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0xf00000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - } - virt_base += 8192*1024*2; - dev->row_virt_shift[bank_nr] = 12; - break; - } - } else { - switch (rammap[cur_rammap].bank[bank_nr]) { - case BANK_NONE: - break; + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)&dev->ram_struct[bank_nr]); + } + virt_base += (1 << 20); + dev->row_virt_shift[bank_nr] = 10; + break; - case BANK_256K: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x80000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - } - virt_base += 512*1024; - dev->row_virt_shift[bank_nr] = 10; - break; + case BANK_1M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)&dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x100000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 21); + dev->row_virt_shift[bank_nr] = 11; + break; - case BANK_256K_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x100000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - } - virt_base += 512*1024*2; - dev->row_virt_shift[bank_nr] = 10; - break; + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)&dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x300000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (3 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 22); + dev->row_virt_shift[bank_nr] = 11; + break; - case BANK_1M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x200000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - } - virt_base += 2048*1024; - dev->row_virt_shift[bank_nr] = 11; - break; + case BANK_4M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)&dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x700000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (7 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 23); + dev->row_virt_shift[bank_nr] = 12; + break; - case BANK_1M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x400000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - } - virt_base += 2048*1024*2; - dev->row_virt_shift[bank_nr] = 11; - break; + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)&dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0xf00000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (15 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 24); + dev->row_virt_shift[bank_nr] = 12; + break; + } + } else { + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_NONE: + break; - case BANK_4M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x800000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - } - virt_base += 8192*1024; - dev->row_virt_shift[bank_nr] = 12; - break; + case BANK_256K: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x80000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 19), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 19); + dev->row_virt_shift[bank_nr] = 10; + break; - case BANK_4M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x1000000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - } - virt_base += 8192*1024*2; - dev->row_virt_shift[bank_nr] = 12; - break; - } - } - switch (rammap[cur_rammap].bank[bank_nr]) { - case BANK_256K: case BANK_1M: case BANK_4M: - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x100000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 20); + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_1M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x200000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 21), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 21); + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x400000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 22), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 22); + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_4M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x800000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 23), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 23); + dev->row_virt_shift[bank_nr] = 12; + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x1000000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 24), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 24); + dev->row_virt_shift[bank_nr] = 12; + break; + } + } + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_256K: case BANK_1M: case BANK_4M: + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], ram_mirrored_read, NULL, NULL, ram_mirrored_write, NULL, NULL); - if (!old_virt_base) - mem_mapping_set_handler(&ram_low_mapping, + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_read, NULL, NULL, ram_mirrored_write, NULL, NULL); - /*pclog(" not interleaved\n");*/ - break; + break; - case BANK_256K_INTERLEAVED: case BANK_1M_INTERLEAVED: - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + case BANK_256K_INTERLEAVED: case BANK_1M_INTERLEAVED: + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], ram_mirrored_interleaved_read, NULL, NULL, ram_mirrored_interleaved_write, NULL, NULL); - if (!old_virt_base) - mem_mapping_set_handler(&ram_low_mapping, + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_interleaved_read, NULL, NULL, ram_mirrored_interleaved_write, NULL, NULL); - /*pclog(" interleaved\n");*/ - break; - - case BANK_4M_INTERLEAVED: - if (phys_bank == BANK_256K || phys_bank == BANK_256K_INTERLEAVED) { - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank == BANK_256K || phys_bank == BANK_256K_INTERLEAVED) { + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], ram_mirrored_256k_in_4mi_read, NULL, NULL, ram_mirrored_256k_in_4mi_write, NULL, NULL); - if (!old_virt_base) - mem_mapping_set_handler(&ram_low_mapping, + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_256k_in_4mi_read, NULL, NULL, ram_mirrored_256k_in_4mi_write, NULL, NULL); - /*pclog(" 256k in 4mi\n");*/ - } else { - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + } else { + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], ram_mirrored_interleaved_read, NULL, NULL, ram_mirrored_interleaved_write, NULL, NULL); - if (!old_virt_base) - mem_mapping_set_handler(&ram_low_mapping, + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_interleaved_read, NULL, NULL, ram_mirrored_interleaved_write, NULL, NULL); - /*pclog(" interleaved\n");*/ - } - break; + } + break; + } + } +} + + +static void +recalc_sltptr(scamp_t *dev) +{ + uint32_t sltptr = dev->cfg_regs[CFG_SLTPTR] << 16; + + if (sltptr >= 0xa0000 && sltptr < 0x100000) + sltptr = 0x100000; + if (sltptr > 0xfe0000) + sltptr = 0xfe0000; + + if (sltptr >= 0xa0000) + { + mem_set_mem_state(0, 0xa0000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x100000, sltptr - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(sltptr, 0x1000000 - sltptr, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + else + { + mem_set_mem_state(0, sltptr, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(sltptr, 0xa0000-sltptr, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state(0x100000, 0xf00000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } +} + +static uint8_t +scamp_ems_read(uint32_t addr, void *priv) +{ + ems_struct_t *ems = (ems_struct_t *) priv; + scamp_t *dev = ems->parent; + int segment = ems->segment; + + addr = (addr & 0x3fff) | dev->mappings[segment]; + return ram[addr]; +} + +static void +scamp_ems_write(uint32_t addr, uint8_t val, void *priv) +{ + ems_struct_t *ems = (ems_struct_t *) priv; + scamp_t *dev = ems->parent; + int segment = ems->segment; + + addr = (addr & 0x3fff) | dev->mappings[segment]; + ram[addr] = val; +} + +static void +recalc_ems(scamp_t *dev) +{ + int segment; + const uint32_t ems_base[12] = + { + 0xc0000, 0xc4000, 0xc8000, 0xcc000, + 0xd0000, 0xd4000, 0xd8000, 0xdc000, + 0xe0000, 0xe4000, 0xe8000, 0xec000 + }; + uint32_t new_mappings[20]; + uint16_t ems_enable; + + for (segment = 0; segment < 20; segment++) + new_mappings[segment] = 0xa0000 + segment*0x4000; + + if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSENAB) + ems_enable = dev->cfg_regs[CFG_EMSEN2] | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 8); + else + ems_enable = 0; + + for (segment = 0; segment < 12; segment++) + { + if (ems_enable & (1 << segment)) + { + uint32_t phys_addr = dev->ems[segment] << 14; + + /*If physical address is in remapped memory then adjust down to a0000-fffff range*/ + if ((dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) && phys_addr >= (mem_size * 1024) + && phys_addr < ((mem_size + 384) * 1024)) + phys_addr = (phys_addr - mem_size * 1024) + 0xa0000; + new_mappings[(ems_base[segment] - 0xa0000) >> 14] = phys_addr; + } + } + + for (segment = 0; segment < 20; segment++) + { + if (new_mappings[segment] != dev->mappings[segment]) + { + dev->mappings[segment] = new_mappings[segment]; + if (new_mappings[segment] < (mem_size * 1024)) + { + mem_mapping_set_exec(&dev->ems_mappings[segment], ram + dev->mappings[segment]); + mem_mapping_enable(&dev->ems_mappings[segment]); + } + else + mem_mapping_disable(&dev->ems_mappings[segment]); } } } -#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0])) - - -static void -shadow_control(uint32_t addr, uint32_t size, int state) +static void +shadow_control(uint32_t addr, uint32_t size, int state, int ems_enable) { -/* pclog("shadow_control: addr=%08x size=%04x state=%i\n", addr, size, state); */ - switch (state) { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); + if (ems_enable) + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else switch (state) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + + flushmmucache_nopc(); } -static void +static void +shadow_recalc(scamp_t *dev) +{ + uint8_t abaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_ABAXS]; + uint8_t caxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_CAXS]; + uint8_t daxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_DAXS]; + uint8_t feaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_FEAXS]; + uint32_t ems_enable; + + if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSENAB) { + if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSMAP) /*Axxx/Bxxx/Dxxx*/ + ems_enable = (dev->cfg_regs[CFG_EMSEN2] & 0xf) | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 4) | ((dev->cfg_regs[CFG_EMSEN2] & 0xf0) << 8); + else /*Cxxx/Dxxx/Exxx*/ + ems_enable = (dev->cfg_regs[CFG_EMSEN2] << 8) | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 16); + } else + ems_enable = 0; + + /*Enabling remapping will disable all shadowing*/ + if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) + mem_remap_top(384); + + shadow_control(0xa0000, 0x4000, abaxs & 3, ems_enable & 0x00001); + shadow_control(0xa0000, 0x4000, abaxs & 3, ems_enable & 0x00002); + shadow_control(0xa8000, 0x4000, (abaxs >> 2) & 3, ems_enable & 0x00004); + shadow_control(0xa8000, 0x4000, (abaxs >> 2) & 3, ems_enable & 0x00008); + + shadow_control(0xb0000, 0x4000, (abaxs >> 4) & 3, ems_enable & 0x00010); + shadow_control(0xb0000, 0x4000, (abaxs >> 4) & 3, ems_enable & 0x00020); + shadow_control(0xb8000, 0x4000, (abaxs >> 6) & 3, ems_enable & 0x00040); + shadow_control(0xb8000, 0x4000, (abaxs >> 6) & 3, ems_enable & 0x00080); + + shadow_control(0xc0000, 0x4000, caxs & 3, ems_enable & 0x00100); + shadow_control(0xc4000, 0x4000, (caxs >> 2) & 3, ems_enable & 0x00200); + shadow_control(0xc8000, 0x4000, (caxs >> 4) & 3, ems_enable & 0x00400); + shadow_control(0xcc000, 0x4000, (caxs >> 6) & 3, ems_enable & 0x00800); + + shadow_control(0xd0000, 0x4000, daxs & 3, ems_enable & 0x01000); + shadow_control(0xd4000, 0x4000, (daxs >> 2) & 3, ems_enable & 0x02000); + shadow_control(0xd8000, 0x4000, (daxs >> 4) & 3, ems_enable & 0x04000); + shadow_control(0xdc000, 0x4000, (daxs >> 6) & 3, ems_enable & 0x08000); + + shadow_control(0xe0000, 0x4000, feaxs & 3, ems_enable & 0x10000); + shadow_control(0xe4000, 0x4000, feaxs & 3, ems_enable & 0x20000); + shadow_control(0xe8000, 0x4000, (feaxs >> 2) & 3, ems_enable & 0x40000); + shadow_control(0xec000, 0x4000, (feaxs >> 2) & 3, ems_enable & 0x80000); + + shadow_control(0xf0000, 0x8000, (feaxs >> 4) & 3, 0); + shadow_control(0xf8000, 0x8000, (feaxs >> 6) & 3, 0); +} + +static void scamp_write(uint16_t addr, uint8_t val, void *priv) { - scamp_t *dev = (scamp_t *) priv; - -/* pclog("scamp_write: addr=%04x val=%02x\n", addr, val); */ - switch (addr) { - case 0xec: - if (dev->cfg_enable) - dev->cfg_index = val; - break; - - case 0xed: - if (dev->cfg_enable) { - if (dev->cfg_index >= 0x02 && dev->cfg_index <= 0x16) { - dev->cfg_regs[dev->cfg_index] = val; -/* pclog("SCAMP CFG[%02x]=%02x\n", dev->cfg_index, val); */ - switch (dev->cfg_index) { - case CFG_SLTPTR: - break; + scamp_t *dev = (scamp_t *) priv; - case CFG_RAMMAP: - recalc_mappings(dev); - mem_mapping_disable(&ram_remapped_mapping); - if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) { - /*Enabling remapping will disable all shadowing*/ - mem_remap_top(384); - shadow_control(0xa0000, 0x60000, 0); - } else { - shadow_control(0xa0000, 0x8000, dev->cfg_regs[CFG_ABAXS] & 3); - shadow_control(0xa8000, 0x8000, (dev->cfg_regs[CFG_ABAXS] >> 2) & 3); - shadow_control(0xb0000, 0x8000, (dev->cfg_regs[CFG_ABAXS] >> 4) & 3); - shadow_control(0xb8000, 0x8000, (dev->cfg_regs[CFG_ABAXS] >> 6) & 3); + switch (addr) { + case 0xe8: + dev->ems_index = val & 0x1f; + dev->ems_autoinc = val & 0x40; + break; - shadow_control(0xc0000, 0x4000, dev->cfg_regs[CFG_CAXS] & 3); - shadow_control(0xc4000, 0x4000, (dev->cfg_regs[CFG_CAXS] >> 2) & 3); - shadow_control(0xc8000, 0x4000, (dev->cfg_regs[CFG_CAXS] >> 4) & 3); - shadow_control(0xcc000, 0x4000, (dev->cfg_regs[CFG_CAXS] >> 6) & 3); + case 0xea: + if (dev->ems_index < 0x24) { + dev->ems[dev->ems_index] = (dev->ems[dev->ems_index] & 0x300) | val; + recalc_ems(dev); + } + break; + case 0xeb: + if (dev->ems_index < 0x24) { + dev->ems[dev->ems_index] = (dev->ems[dev->ems_index] & 0x0ff) | ((val & 3) << 8); + recalc_ems(dev); + } + if (dev->ems_autoinc) + dev->ems_index = (dev->ems_index + 1) & 0x3f; + break; - shadow_control(0xd0000, 0x4000, dev->cfg_regs[CFG_DAXS] & 3); - shadow_control(0xd4000, 0x4000, (dev->cfg_regs[CFG_DAXS] >> 2) & 3); - shadow_control(0xd8000, 0x4000, (dev->cfg_regs[CFG_DAXS] >> 4) & 3); - shadow_control(0xdc000, 0x4000, (dev->cfg_regs[CFG_DAXS] >> 6) & 3); + case 0xec: + if (dev->cfg_enable) + dev->cfg_index = val; + break; - shadow_control(0xe0000, 0x8000, dev->cfg_regs[CFG_FEAXS] & 3); - shadow_control(0xe8000, 0x8000, (dev->cfg_regs[CFG_FEAXS] >> 2) & 3); - shadow_control(0xf0000, 0x8000, (dev->cfg_regs[CFG_FEAXS] >> 4) & 3); - shadow_control(0xf8000, 0x8000, (dev->cfg_regs[CFG_FEAXS] >> 6) & 3); - } - break; + case 0xed: + if (dev->cfg_enable && (dev->cfg_index >= 0x02) && (dev->cfg_index <= 0x16)) { + dev->cfg_regs[dev->cfg_index] = val; + switch (dev->cfg_index) { + case CFG_SLTPTR: + recalc_sltptr(dev); + break; - case CFG_ABAXS: - if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { - shadow_control(0xa0000, 0x8000, val & 3); - shadow_control(0xa8000, 0x8000, (val >> 2) & 3); - shadow_control(0xb0000, 0x8000, (val >> 4) & 3); - shadow_control(0xb8000, 0x8000, (val >> 6) & 3); - } - break; - - case CFG_CAXS: - if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { - shadow_control(0xc0000, 0x4000, val & 3); - shadow_control(0xc4000, 0x4000, (val >> 2) & 3); - shadow_control(0xc8000, 0x4000, (val >> 4) & 3); - shadow_control(0xcc000, 0x4000, (val >> 6) & 3); - } - break; - - case CFG_DAXS: - if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { - shadow_control(0xd0000, 0x4000, val & 3); - shadow_control(0xd4000, 0x4000, (val >> 2) & 3); - shadow_control(0xd8000, 0x4000, (val >> 4) & 3); - shadow_control(0xdc000, 0x4000, (val >> 6) & 3); - } - break; - - case CFG_FEAXS: - if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { - shadow_control(0xe0000, 0x8000, val & 3); - shadow_control(0xe8000, 0x8000, (val >> 2) & 3); - shadow_control(0xf0000, 0x8000, (val >> 4) & 3); - shadow_control(0xf8000, 0x8000, (val >> 6) & 3); - } - break; - } - } + case CFG_RAMMAP: + recalc_mappings(dev); + mem_mapping_disable(&ram_remapped_mapping); + shadow_recalc(dev); + break; + + case CFG_EMSEN1: + case CFG_EMSEN2: + shadow_recalc(dev); + recalc_ems(dev); + break; + + case CFG_ABAXS: + case CFG_CAXS: + case CFG_DAXS: + case CFG_FEAXS: + shadow_recalc(dev); + break; } - break; + } + break; - case 0xee: - if (dev->cfg_enable && mem_a20_alt) - outb(0x92, inb(0x92) & ~2); - break; - } + case 0xee: + if (dev->cfg_enable && mem_a20_alt) { + dev->port_92->reg &= 0xfd; + mem_a20_alt = 0; + mem_a20_recalc(); + } + break; + } } -static uint8_t +static uint8_t scamp_read(uint16_t addr, void *priv) { - uint8_t ret = 0xff; - - switch (addr) { - case 0xee: - if (!mem_a20_alt) - outb(0x92, inb(0x92) | 2); - break; - - case 0xef: - softresetx86(); - cpu_set_edx(); - break; - } + scamp_t *dev = (scamp_t *) priv; + uint8_t ret = 0xff; -/* pclog("scamp_read: addr=%04x ret=%02x\n", addr, ret); */ - return ret; + switch (addr) { + case 0xe8: + ret = dev->ems_index | dev->ems_autoinc; + break; + + case 0xea: + if (dev->ems_index < 0x24) + ret = dev->ems[dev->ems_index] & 0xff; + break; + case 0xeb: + if (dev->ems_index < 0x24) + ret = (dev->ems[dev->ems_index] >> 8) | 0xfc; + if (dev->ems_autoinc) + dev->ems_index = (dev->ems_index + 1) & 0x3f; + break; + + case 0xed: + if (dev->cfg_enable && (dev->cfg_index >= 0x00) && (dev->cfg_index <= 0x16)) + ret = (dev->cfg_regs[dev->cfg_index]); + break; + + case 0xee: + if (!mem_a20_alt) { + dev->port_92->reg |= 0x02; + mem_a20_alt = 1; + mem_a20_recalc(); + } + break; + + case 0xef: + softresetx86(); + cpu_set_edx(); + break; + } + + return ret; } + static void scamp_close(void *priv) { - scamp_t *dev = (scamp_t *) priv; + scamp_t *dev = (scamp_t *) priv; - free(dev); + free(dev); } static void * scamp_init(const device_t *info) { - uint32_t addr; - int c; - scamp_t *dev = (scamp_t *)malloc(sizeof(scamp_t)); - memset(dev, 0, sizeof(scamp_t)); - - dev->cfg_regs[CFG_ID] = ID_VL82C311; - dev->cfg_enable = 1; - - io_sethandler(0x00e8, 0x0001, - scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); - io_sethandler(0x00ea, 0x0006, - scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); - io_sethandler(0x00f4, 0x0002, - scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); - io_sethandler(0x00f9, 0x0001, - scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); - io_sethandler(0x00fb, 0x0001, - scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); - - dev->ram_config = 0; + uint32_t addr; + int c; + scamp_t *dev = (scamp_t *)malloc(sizeof(scamp_t)); + memset(dev, 0x00, sizeof(scamp_t)); - /*Find best fit configuration for the requested memory size*/ - for (c = 0; c < NR_ELEMS(ram_configs); c++) { - if (mem_size < ram_configs[c].size_kb) - break; - - dev->ram_config = c; - } + dev->cfg_regs[CFG_ID] = ID_VL82C311; + dev->cfg_enable = 1; - mem_mapping_set_handler(&ram_low_mapping, + io_sethandler(0x00e8, 0x0001, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00ea, 0x0006, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00f4, 0x0002, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00f9, 0x0001, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00fb, 0x0001, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + + dev->ram_config = 0; + + /* Find best fit configuration for the requested memory size */ + for (c = 0; c < NR_ELEMS(ram_configs); c++) { + if (mem_size < ram_configs[c].size_kb) + break; + + dev->ram_config = c; + } + + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[0]); + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_high_mapping); + mem_mapping_set_addr(&ram_mid_mapping, 0xf0000, 0x10000); + mem_mapping_set_exec(&ram_mid_mapping, ram+0xf0000); + + addr = 0; + for (c = 0; c < 2; c++) { + dev->ram_struct[c].parent = dev; + dev->ram_struct[c].bank = c; + mem_mapping_add(&dev->ram_mapping[c], 0, 0, ram_mirrored_read, NULL, NULL, - ram_mirrored_write, NULL, NULL); - dev->ram_struct[2].parent = dev; - dev->ram_struct[2].bank = 0; - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[2]); - mem_mapping_disable(&ram_high_mapping); + ram_mirrored_write, NULL, NULL, + &ram[addr], MEM_MAPPING_INTERNAL, (void *) &dev->ram_struct[c]); + mem_mapping_disable(&dev->ram_mapping[c]); - addr = 0; - for (c = 0; c < 2; c++) { - dev->ram_struct[c].parent = dev; - dev->ram_struct[c].bank = c; - mem_mapping_add(&dev->ram_mapping[c], 0, 0, - ram_mirrored_read, NULL, NULL, - ram_mirrored_write, NULL, NULL, - &ram[addr], MEM_MAPPING_INTERNAL, (void *) &dev->ram_struct[c]); - mem_mapping_disable(&dev->ram_mapping[c]); - - dev->ram_phys_base[c] = addr; -/* pclog("Bank calc : %i = %08x\n", c ,addr);*/ - - switch (ram_configs[dev->ram_config].bank[c]) { - case BANK_NONE: - dev->ram_mask[c] = 0; - dev->ram_interleaved[c] = 0; - break; - - case BANK_256K: - addr += 512*1024; - dev->ram_mask[c] = 0x1ff; - dev->row_phys_shift[c] = 10; - dev->ram_interleaved[c] = 0; - break; - - case BANK_256K_INTERLEAVED: - addr += 512*1024*2; - dev->ram_mask[c] = 0x1ff; - dev->row_phys_shift[c] = 10; - dev->ibank_shift[c] = 19; - dev->ram_interleaved[c] = 1; - break; + dev->ram_phys_base[c] = addr; - case BANK_1M: - addr += 2048*1024; - dev->ram_mask[c] = 0x3ff; - dev->row_phys_shift[c] = 11; - dev->ram_interleaved[c] = 0; - break; - - case BANK_1M_INTERLEAVED: - addr += 2048*1024*2; - dev->ram_mask[c] = 0x3ff; - dev->row_phys_shift[c] = 11; - dev->ibank_shift[c] = 21; - dev->ram_interleaved[c] = 1; - break; + switch (ram_configs[dev->ram_config].bank[c]) { + case BANK_NONE: + dev->ram_mask[c] = 0; + dev->ram_interleaved[c] = 0; + break; - case BANK_4M: - addr += 8192*1024; - dev->ram_mask[c] = 0x7ff; - dev->row_phys_shift[c] = 12; - dev->ram_interleaved[c] = 0; - break; + case BANK_256K: + addr += (1 << 19); + dev->ram_mask[c] = 0x1ff; + dev->row_phys_shift[c] = 10; + dev->ram_interleaved[c] = 0; + break; - case BANK_4M_INTERLEAVED: - addr += 8192*1024*2; - dev->ram_mask[c] = 0x7ff; - dev->row_phys_shift[c] = 12; - dev->ibank_shift[c] = 23; - dev->ram_interleaved[c] = 1; - break; - } - } - - mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - - return dev; + case BANK_256K_INTERLEAVED: + addr += (1 << 20); + dev->ram_mask[c] = 0x1ff; + dev->row_phys_shift[c] = 10; + dev->ibank_shift[c] = 19; + dev->ram_interleaved[c] = 1; + break; + + case BANK_1M: + addr += (1 << 21); + dev->ram_mask[c] = 0x3ff; + dev->row_phys_shift[c] = 11; + dev->ram_interleaved[c] = 0; + break; + + case BANK_1M_INTERLEAVED: + addr += (1 << 22); + dev->ram_mask[c] = 0x3ff; + dev->row_phys_shift[c] = 11; + dev->ibank_shift[c] = 21; + dev->ram_interleaved[c] = 1; + break; + + case BANK_4M: + addr += (1 << 23); + dev->ram_mask[c] = 0x7ff; + dev->row_phys_shift[c] = 12; + dev->ram_interleaved[c] = 0; + break; + + case BANK_4M_INTERLEAVED: + addr += (1 << 24); + dev->ram_mask[c] = 0x7ff; + dev->row_phys_shift[c] = 12; + dev->ibank_shift[c] = 23; + dev->ram_interleaved[c] = 1; + break; + } + } + + mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + for (c = 0; c < 20; c++) { + dev->ems_struct[c].parent = dev; + dev->ems_struct[c].segment = c; + mem_mapping_add(&dev->ems_mappings[c], + 0xa0000 + c*0x4000, 0x4000, + scamp_ems_read, NULL, NULL, + scamp_ems_write, NULL, NULL, + ram + 0xa0000 + c*0x4000, MEM_MAPPING_INTERNAL, (void *)&dev->ems_struct[c]); + dev->mappings[c] = 0xa0000 + c*0x4000; + } + + dev->port_92 = device_add(&port_92_device); + + return dev; } - const device_t vlsi_scamp_device = { - "VLSI SCAMP", - 0, - 0, - scamp_init, scamp_close, NULL, - NULL, NULL, NULL, - NULL -}; \ No newline at end of file + .name = "VLSI SCAMP", + .internal_name = "vlsi_scamp", + .flags = 0, + .local = 0, + .init = scamp_init, + .close = scamp_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/scat.c b/src/chipset/scat.c index ed2daee08..1e7ba9263 100644 --- a/src/chipset/scat.c +++ b/src/chipset/scat.c @@ -27,10 +27,6 @@ #include <86box/device.h> #include "cpu.h" #include "x86.h" -#include <86box/timer.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/keyboard.h> #include <86box/io.h> #include <86box/mem.h> #include <86box/nmi.h> @@ -84,7 +80,6 @@ typedef struct scat_t { ems_page_t null_page, page[32]; mem_mapping_t low_mapping[32]; - mem_mapping_t high_mapping[16]; mem_mapping_t remap_mapping[6]; mem_mapping_t efff_mapping[44]; mem_mapping_t ems_mapping[32]; @@ -121,28 +116,30 @@ shadow_state_update(scat_t *dev) { int i, val; - uint32_t base, bit, romcs, wp, shflags = 0; + uint32_t base, bit, romcs, shflags = 0; + + shadowbios = shadowbios_write = 0; for (i = 0; i < 24; i++) { - val = (dev->regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1; + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0xf) < 4) + val = 0; + else + val = (dev->regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1; base = 0xa0000 + (i << 14); bit = (base - 0xc0000) >> 15; romcs = 0; - wp = 0; - if (base >= 0xc0000) { + if (base >= 0xc0000) romcs = dev->regs[SCAT_ROM_ENABLE] & (1 << bit); - wp = dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << bit); + if (base >= 0xe0000) { + shadowbios |= val; + shadowbios_write |= val; } - shflags = val ? MEM_READ_INTERNAL : (romcs ? MEM_READ_ROMCS : MEM_READ_EXTERNAL); - - if (wp) - shflags |= MEM_WRITE_DISABLED; - else - shflags |= (val ? MEM_WRITE_INTERNAL : (romcs ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL)); + shflags = val ? MEM_READ_INTERNAL : (romcs ? MEM_READ_EXTANY : MEM_READ_EXTERNAL); + shflags |= (val ? MEM_WRITE_INTERNAL : (romcs ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL)); mem_set_mem_state(base, 0x4000, shflags); } @@ -234,7 +231,7 @@ set_xms_bound(scat_t *dev, uint8_t val) if (dev->xms_bound < 0x160000) mem_set_mem_state(dev->xms_bound, 0x160000 - dev->xms_bound, - MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + MEM_READ_EXTANY | MEM_WRITE_EXTANY); } else { if (dev->xms_bound > xms_max) dev->xms_bound = xms_max; @@ -245,7 +242,7 @@ set_xms_bound(scat_t *dev, uint8_t val) if (dev->xms_bound < ((uint32_t)mem_size << 10)) mem_set_mem_state(dev->xms_bound, (mem_size << 10) - dev->xms_bound, - MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + MEM_READ_EXTANY | MEM_WRITE_EXTANY); } mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, @@ -254,9 +251,9 @@ set_xms_bound(scat_t *dev, uint8_t val) if (dev->regs[SCAT_VERSION] & 0xf0) { for (i = 0; i < 8; i++) { if (val & 0x10) - mem_mapping_disable(&dev->high_mapping[i]); + mem_mapping_disable(&bios_high_mapping); else - mem_mapping_enable(&dev->high_mapping[i]); + mem_mapping_enable(&bios_high_mapping); } } } @@ -387,7 +384,7 @@ get_addr(scat_t *dev, uint32_t addr, ems_page_t *p) if (mem_size <= ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 2048 : 4096) && (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8) || dev->external_is_RAS)) { nbanks_2048k = 0; nbanks_512k = mem_size >> 9; - } else { + } else { nbanks_2048k = mem_size >> 11; nbanks_512k = (mem_size & 1536) >> 9; } @@ -943,21 +940,21 @@ memmap_state_update(scat_t *dev) int i; for (i = (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 16); i < 44; i++) { - addr = get_addr(dev, 0x40000 + (i << 14), NULL); + addr = get_addr(dev, 0x40000 + (i << 14), &dev->null_page); mem_mapping_set_exec(&dev->efff_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); } - addr = get_addr(dev, 0, NULL); + addr = get_addr(dev, 0, &dev->null_page); mem_mapping_set_exec(&dev->low_mapping[0], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); - addr = get_addr(dev, 0xf0000, NULL); + addr = get_addr(dev, 0xf0000, &dev->null_page); mem_mapping_set_exec(&dev->low_mapping[1], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); for (i = 2; i < 32; i++) { - addr = get_addr(dev, i << 19, NULL); + addr = get_addr(dev, i << 19, &dev->null_page); mem_mapping_set_exec(&dev->low_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); } @@ -999,7 +996,7 @@ memmap_state_update(scat_t *dev) mem_mapping_disable(&dev->low_mapping[2]); for (i = 0; i < 6; i++) { - addr = get_addr(dev, 0x100000 + (i << 16), NULL); + addr = get_addr(dev, 0x100000 + (i << 16), &dev->null_page); mem_mapping_set_exec(&dev->remap_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); mem_mapping_enable(&dev->remap_mapping[i]); @@ -1094,7 +1091,7 @@ scat_out(uint16_t port, uint8_t val, void *priv) } else set_xms_bound(dev, val & 0x1f); - mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTANY | MEM_WRITE_EXTANY : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); if ((val ^ dev->regs[SCAT_EXTENDED_BOUNDARY]) & 0xc0) map_update = 1; @@ -1330,23 +1327,13 @@ static void mem_write_scatb(uint32_t addr, uint8_t val, void *priv) { ems_page_t *page = (ems_page_t *)priv; - scat_t *dev; + scat_t *dev = (scat_t *)page->scat; uint32_t oldaddr = addr, chkaddr; - if (page == NULL) - dev = NULL; - else - dev = (scat_t *)page->scat; - - if (dev == NULL) - chkaddr = oldaddr; - else { - addr = get_addr(dev, addr, page); - chkaddr = addr; - } - - if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { - if ((dev == NULL) || (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15)))) + addr = get_addr(dev, addr, page); + chkaddr = page->valid ? addr : oldaddr; + if ((chkaddr >= 0xc0000) && (chkaddr < 0x100000)) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; } @@ -1359,23 +1346,13 @@ static void mem_write_scatw(uint32_t addr, uint16_t val, void *priv) { ems_page_t *page = (ems_page_t *)priv; - scat_t *dev; + scat_t *dev = (scat_t *)page->scat; uint32_t oldaddr = addr, chkaddr; - if (page == NULL) - dev = NULL; - else - dev = (scat_t *)page->scat; - - if (dev == NULL) - chkaddr = oldaddr; - else { - addr = get_addr(dev, addr, page); - chkaddr = addr; - } - - if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { - if (dev != NULL && (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15)))) + addr = get_addr(dev, addr, page); + chkaddr = page->valid ? addr : oldaddr; + if ((chkaddr >= 0xc0000) && (chkaddr < 0x100000)) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; } @@ -1388,23 +1365,13 @@ static void mem_write_scatl(uint32_t addr, uint32_t val, void *priv) { ems_page_t *page = (ems_page_t *)priv; - scat_t *dev; + scat_t *dev = (scat_t *)page->scat; uint32_t oldaddr = addr, chkaddr; - if (page == NULL) - dev = NULL; - else - dev = (scat_t *)page->scat; - - if (dev == NULL) - chkaddr = oldaddr; - else { - addr = get_addr(dev, addr, page); - chkaddr = addr; - } - - if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { - if (dev != NULL && (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15)))) + addr = get_addr(dev, addr, page); + chkaddr = page->valid ? addr : oldaddr; + if ((chkaddr >= 0xc0000) && (chkaddr < 0x100000)) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; } @@ -1478,9 +1445,6 @@ scat_init(const device_t *info) if (! sx) mem_mapping_disable(&ram_mid_mapping); mem_mapping_disable(&ram_high_mapping); -#if 0 - mem_mapping_disable(&bios_mapping); -#endif k = (sx) ? 0x80000 : 0x40000; @@ -1538,14 +1502,6 @@ scat_init(const device_t *info) ram + ((i + 28) << 14), 0, &dev->page[i]); mem_mapping_disable(&dev->ems_mapping[i]); } - - for (i = 0; i < 16; i++) { - mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000, - mem_read_bios, mem_read_biosw, mem_read_biosl, - mem_write_null, mem_write_nullw, mem_write_nulll, - rom + ((i << 14) & biosmask), 0, NULL); - mem_mapping_enable(&dev->high_mapping[i]); - } } else { for (i = 0; i < 32; i++) { dev->page[i].valid = 1; @@ -1558,21 +1514,13 @@ scat_init(const device_t *info) ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &dev->page[i]); } - - for (i = (dev->regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) { - mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000, - mem_read_bios, mem_read_biosw, mem_read_biosl, - mem_write_null, mem_write_nullw, mem_write_nulll, - rom + ((i << 14) & biosmask), 0, NULL); - mem_mapping_enable(&dev->high_mapping[i]); - } } for (i = 0; i < 6; i++) { mem_mapping_add(&dev->remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, - mem_size >= 1024 ? ram + get_addr(dev, 0x100000 + (i << 16), NULL) : NULL, + mem_size >= 1024 ? ram + get_addr(dev, 0x100000 + (i << 16), &dev->null_page) : NULL, MEM_MAPPING_INTERNAL, &dev->null_page); } @@ -1594,30 +1542,44 @@ scat_init(const device_t *info) return(dev); } - const device_t scat_device = { - "C&T SCAT (v1)", - 0, - 0, - scat_init, scat_close, NULL, - NULL, NULL, NULL, - NULL + .name = "C&T SCAT (v1)", + .internal_name = "scat", + .flags = 0, + .local = 0, + .init = scat_init, + .close = scat_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t scat_4_device = { - "C&T SCAT (v4)", - 0, - 4, - scat_init, scat_close, NULL, - NULL, NULL, NULL, - NULL + .name = "C&T SCAT (v4)", + .internal_name = "scat_4", + .flags = 0, + .local = 4, + .init = scat_init, + .close = scat_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t scat_sx_device = { - "C&T SCATsx", - 0, - 32, - scat_init, scat_close, NULL, - NULL, NULL, NULL, - NULL + .name = "C&T SCATsx", + .internal_name = "scat_sx", + .flags = 0, + .local = 32, + .init = scat_init, + .close = scat_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/sis_5511.c b/src/chipset/sis_5511.c new file mode 100644 index 000000000..d0900629d --- /dev/null +++ b/src/chipset/sis_5511.c @@ -0,0 +1,754 @@ +/* + * 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 SiS 5511/5512/5513 Pentium PCI/ISA Chipset. + * + * + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/timer.h> + +#include <86box/mem.h> +#include <86box/hdd.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/smram.h> + +#include <86box/chipset.h> + +/* IDE Flags (1 Native / 0 Compatibility)*/ +#define PRIMARY_COMP_NAT_SWITCH (dev->pci_conf_sb[1][9] & 1) +#define SECONDARY_COMP_NAT_SWITCH (dev->pci_conf_sb[1][9] & 4) +#define PRIMARY_NATIVE_BASE (dev->pci_conf_sb[1][0x11] << 8) | (dev->pci_conf_sb[1][0x10] & 0xf8) +#define PRIMARY_NATIVE_SIDE (((dev->pci_conf_sb[1][0x15] << 8) | (dev->pci_conf_sb[1][0x14] & 0xfc)) + 2) +#define SECONDARY_NATIVE_BASE (dev->pci_conf_sb[1][0x19] << 8) | (dev->pci_conf_sb[1][0x18] & 0xf8) +#define SECONDARY_NATIVE_SIDE (((dev->pci_conf_sb[1][0x1d] << 8) | (dev->pci_conf_sb[1][0x1c] & 0xfc)) + 2) +#define BUS_MASTER_BASE ((dev->pci_conf_sb[1][0x20] & 0xf0) | (dev->pci_conf_sb[1][0x21] << 8)) + +#ifdef ENABLE_SIS_5511_LOG +int sis_5511_do_log = ENABLE_SIS_5511_LOG; +static void +sis_5511_log(const char *fmt, ...) +{ + va_list ap; + + if (sis_5511_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sis_5511_log(fmt, ...) +#endif + +typedef struct sis_5511_t +{ + uint8_t pci_conf[256], pci_conf_sb[2][256], + index, regs[16]; + + int nb_pci_slot, sb_pci_slot; + + sff8038i_t *ide_drive[2]; + smram_t *smram; + port_92_t *port_92; + +} sis_5511_t; + +static void +sis_5511_shadow_recalc(sis_5511_t *dev) +{ + int i, state; + uint32_t base; + + for (i = 0x80; i <= 0x86; i++) { + if (i == 0x86) { + state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + mem_set_mem_state_both(0xf0000, 0x10000, state); + pclog("000F0000-000FFFFF\n"); + } else { + base = ((i & 0x07) << 15) + 0xc0000; + + state = (dev->pci_conf[i] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[i] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + mem_set_mem_state_both(base, 0x4000, state); + pclog("%08X-%08X\n", base, base + 0x3fff); + + state = (dev->pci_conf[i] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + state |= (dev->pci_conf[i] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + mem_set_mem_state_both(base + 0x4000, 0x4000, state); + pclog("%08X-%08X\n", base + 0x4000, base + 0x7fff); + } + } + + flushmmucache_nopc(); +} + +static void +sis_5511_smram_recalc(sis_5511_t *dev) +{ + smram_disable_all(); + + switch (dev->pci_conf[0x65] >> 6) { + case 0: + smram_enable(dev->smram, 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); + break; + case 1: + smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); + break; + case 2: + smram_enable(dev->smram, 0x000e0000, 0x000b0000, 0x8000, dev->pci_conf[0x65] & 0x10, 1); + break; + } + + flushmmucache(); +} + + +void sis_5513_ide_handler(sis_5511_t *dev) +{ + ide_pri_disable(); + ide_sec_disable(); + if (dev->pci_conf_sb[1][4] & 1) + { + if (dev->pci_conf_sb[1][0x4a] & 4) + { + ide_set_base(0, PRIMARY_COMP_NAT_SWITCH ? PRIMARY_NATIVE_BASE : 0x1f0); + ide_set_side(0, PRIMARY_COMP_NAT_SWITCH ? PRIMARY_NATIVE_SIDE : 0x3f6); + ide_pri_enable(); + } + if (dev->pci_conf_sb[1][0x4a] & 2) + { + ide_set_base(1, SECONDARY_COMP_NAT_SWITCH ? SECONDARY_NATIVE_BASE : 0x170); + ide_set_side(1, SECONDARY_COMP_NAT_SWITCH ? SECONDARY_NATIVE_SIDE : 0x376); + ide_sec_enable(); + } + } +} + +void sis_5513_bm_handler(sis_5511_t *dev) +{ + sff_bus_master_handler(dev->ide_drive[0], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE); + sff_bus_master_handler(dev->ide_drive[1], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE + 8); +} + + +static void +sis_5511_write(int func, int addr, uint8_t val, void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + + switch (addr) { + case 0x07: /* Status - High Byte */ + dev->pci_conf[addr] &= 0xb0; + break; + + case 0x50: + dev->pci_conf[addr] = val; + cpu_cache_ext_enabled = !!(val & 0x40); + cpu_update_waitstates(); + break; + + case 0x51: + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0x52: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x53: case 0x54: + dev->pci_conf[addr] = val; + break; + + case 0x55: + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x56 ... 0x59: + dev->pci_conf[addr] = val; + break; + + case 0x5a: + /* TODO: Fast Gate A20 Emulation and Fast Reset Emulation on the KBC. + The former (bit 7) means the chipset intercepts D1h to 64h and 00h to 60h. + The latter (bit 6) means the chipset intercepts all odd FXh to 64h. + Bit 5 sets fast reset latency. This should be fixed on the other SiS + chipsets as well. */ + dev->pci_conf[addr] = val; + break; + + case 0x5b: + dev->pci_conf[addr] = val & 0xf7; + break; + + case 0x5c: + dev->pci_conf[addr] = val & 0xcf; + break; + + case 0x5d: + dev->pci_conf[addr] = val; + break; + + case 0x5e: + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0x5f: + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0x60: + dev->pci_conf[addr] = val & 0x3e; + if ((dev->pci_conf[0x68] & 1) && (val & 2)) { + smi_raise(); + dev->pci_conf[0x69] |= 1; + } + break; + + case 0x61 ... 0x64: + dev->pci_conf[addr] = val; + break; + + case 0x65: + dev->pci_conf[addr] = val & 0xd0; + sis_5511_smram_recalc(dev); + break; + + case 0x66: + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x67: case 0x68: + dev->pci_conf[addr] = val; + break; + + case 0x69: + dev->pci_conf[addr] &= val; + break; + + case 0x6a ... 0x6e: + dev->pci_conf[addr] = val; + break; + + case 0x6f: + dev->pci_conf[addr] = val & 0x3f; + break; + + case 0x70: /* DRAM Bank Register 0-0 */ + case 0x71: /* DRAM Bank Register 0-0 */ + case 0x72: /* DRAM Bank Register 0-1 */ + dev->pci_conf[addr] = val; + break; + + case 0x73: /* DRAM Bank Register 0-1 */ + dev->pci_conf[addr] = val & 0x83; + break; + + case 0x74: /* DRAM Bank Register 1-0 */ + dev->pci_conf[addr] = val; + break; + + case 0x75: /* DRAM Bank Register 1-0 */ + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x76: /* DRAM Bank Register 1-1 */ + dev->pci_conf[addr] = val; + break; + + case 0x77: /* DRAM Bank Register 1-1 */ + dev->pci_conf[addr] = val & 0x83; + break; + + case 0x78: /* DRAM Bank Register 2-0 */ + dev->pci_conf[addr] = val; + break; + + case 0x79: /* DRAM Bank Register 2-0 */ + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x7a: /* DRAM Bank Register 2-1 */ + dev->pci_conf[addr] = val; + break; + + case 0x7b: /* DRAM Bank Register 2-1 */ + dev->pci_conf[addr] = val & 0x83; + break; + + case 0x7c: /* DRAM Bank Register 3-0 */ + dev->pci_conf[addr] = val; + break; + + case 0x7d: /* DRAM Bank Register 3-0 */ + dev->pci_conf[addr] = val & 0x7f; + break; + + case 0x7e: /* DRAM Bank Register 3-1 */ + dev->pci_conf[addr] = val; + break; + + case 0x7f: /* DRAM Bank Register 3-1 */ + dev->pci_conf[addr] = val & 0x83; + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + dev->pci_conf[addr] = val & ((addr == 0x86) ? 0xe8 : 0xee); + sis_5511_shadow_recalc(dev); + break; + + case 0x90: /* 5512 General Purpose Register Index */ + case 0x91: /* 5512 General Purpose Register Index */ + case 0x92: /* 5512 General Purpose Register Index */ + case 0x93: /* 5512 General Purpose Register Index */ + dev->pci_conf[addr] = val; + break; + } + sis_5511_log("SiS 5511: dev->pci_conf[%02x] = %02x POST: %02x\n", addr, dev->pci_conf[addr], inb(0x80)); +} + +static uint8_t +sis_5511_read(int func, int addr, void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + sis_5511_log("SiS 5511: dev->pci_conf[%02x] (%02x) POST %02x\n", addr, dev->pci_conf[addr], inb(0x80)); + return dev->pci_conf[addr]; +} + +void sis_5513_pci_to_isa_write(int addr, uint8_t val, sis_5511_t *dev) +{ + switch (addr) + { + case 0x04: /* Command */ + dev->pci_conf_sb[0][addr] = val & 7; + break; + + case 0x07: /* Status */ + dev->pci_conf_sb[0][addr] &= val & 0x36; + break; + + case 0x40: /* BIOS Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x3f; + break; + + case 0x41: /* INTA# Remapping Control Register */ + case 0x42: /* INTB# Remapping Control Register */ + case 0x43: /* INTC# Remapping Control Register */ + case 0x44: /* INTD# Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x8f; + pci_set_irq_routing(addr & 7, (val & 0x80) ? (val & 0x80) : PCI_IRQ_DISABLED); + break; + + case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */ + case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */ + case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */ + case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */ + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x60: /* MIRQ0 Remapping Control Register */ + case 0x61: /* MIRQ1 Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val & 0xcf; + pci_set_mirq_routing(addr & 1, (val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED); + break; + + case 0x62: /* On-board Device DMA Control Register */ + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x63: /* IDEIRQ Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x8f; + if (val & 0x80) + { + sff_set_irq_line(dev->ide_drive[0], (val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED); + sff_set_irq_line(dev->ide_drive[1], (val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED); + } + break; + + case 0x64: /* GPIO0 Control Register */ + dev->pci_conf_sb[0][addr] = val & 0xef; + break; + + case 0x65: + dev->pci_conf_sb[0][addr] = val & 0x80; + break; + + case 0x66: /* GPIO0 Output Mode Control Register */ + case 0x67: /* GPIO0 Output Mode Control Register */ + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x6a: /* GPIO Status Register */ + dev->pci_conf_sb[0][addr] &= val & 0x15; + break; + } +} + +void sis_5513_ide_write(int addr, uint8_t val, sis_5511_t *dev) +{ + switch (addr) + { + case 0x04: /* Command low byte */ + dev->pci_conf_sb[1][addr] = val & 5; + sis_5513_ide_handler(dev); + sis_5513_bm_handler(dev); + break; + case 0x07: /* Status high byte */ + dev->pci_conf_sb[1][addr] &= val & 0x3f; + break; + case 0x09: /* Programming Interface Byte */ + dev->pci_conf_sb[1][addr] = val; + sis_5513_ide_handler(dev); + break; + case 0x0d: /* Latency Timer */ + dev->pci_conf_sb[1][addr] = val; + break; + + case 0x10: /* Primary Channel Base Address Register */ + case 0x11: /* Primary Channel Base Address Register */ + case 0x12: /* Primary Channel Base Address Register */ + case 0x13: /* Primary Channel Base Address Register */ + case 0x14: /* Primary Channel Base Address Register */ + case 0x15: /* Primary Channel Base Address Register */ + case 0x16: /* Primary Channel Base Address Register */ + case 0x17: /* Primary Channel Base Address Register */ + case 0x18: /* Secondary Channel Base Address Register */ + case 0x19: /* Secondary Channel Base Address Register */ + case 0x1a: /* Secondary Channel Base Address Register */ + case 0x1b: /* Secondary Channel Base Address Register */ + case 0x1c: /* Secondary Channel Base Address Register */ + case 0x1d: /* Secondary Channel Base Address Register */ + case 0x1e: /* Secondary Channel Base Address Register */ + case 0x1f: /* Secondary Channel Base Address Register */ + dev->pci_conf_sb[1][addr] = val; + sis_5513_ide_handler(dev); + break; + + case 0x20: /* Bus Master IDE Control Register Base Address */ + case 0x21: /* Bus Master IDE Control Register Base Address */ + case 0x22: /* Bus Master IDE Control Register Base Address */ + case 0x23: /* Bus Master IDE Control Register Base Address */ + dev->pci_conf_sb[1][addr] = val; + sis_5513_bm_handler(dev); + break; + + case 0x30: /* Expansion ROM Base Address */ + case 0x31: /* Expansion ROM Base Address */ + case 0x32: /* Expansion ROM Base Address */ + case 0x33: /* Expansion ROM Base Address */ + dev->pci_conf_sb[1][addr] = val; + break; + + case 0x40: /* IDE Primary Channel/Master Drive Data Recovery Time Control */ + case 0x41: /* IDE Primary Channel/Master Drive DataActive Time Control */ + case 0x42: /* IDE Primary Channel/Slave Drive Data Recovery Time Control */ + case 0x43: /* IDE Primary Channel/Slave Drive Data Active Time Control */ + case 0x44: /* IDE Secondary Channel/Master Drive Data Recovery Time Control */ + case 0x45: /* IDE Secondary Channel/Master Drive Data Active Time Control */ + case 0x46: /* IDE Secondary Channel/Slave Drive Data Recovery Time Control */ + case 0x47: /* IDE Secondary Channel/Slave Drive Data Active Time Control */ + case 0x48: /* IDE Command Recovery Time Control */ + case 0x49: /* IDE Command Active Time Control */ + dev->pci_conf_sb[1][addr] = val; + break; + + case 0x4a: /* IDE General Control Register 0 */ + dev->pci_conf_sb[1][addr] = val & 0x9f; + sis_5513_ide_handler(dev); + break; + + case 0x4b: /* IDE General Control Register 1 */ + dev->pci_conf_sb[1][addr] = val & 0xef; + break; + + case 0x4c: /* Prefetch Count of Primary Channel (Low Byte) */ + case 0x4d: /* Prefetch Count of Primary Channel (High Byte) */ + case 0x4e: /* Prefetch Count of Secondary Channel (Low Byte) */ + case 0x4f: /* Prefetch Count of Secondary Channel (High Byte) */ + dev->pci_conf_sb[1][addr] = val; + break; + } +} + +static void +sis_5513_write(int func, int addr, uint8_t val, void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + switch (func) + { + case 0: + sis_5513_pci_to_isa_write(addr, val, dev); + break; + case 1: + sis_5513_ide_write(addr, val, dev); + break; + } + sis_5511_log("SiS 5513: dev->pci_conf[%02x][%02x] = %02x POST: %02x\n", func, addr, dev->pci_conf_sb[func][addr], inb(0x80)); +} + +static uint8_t +sis_5513_read(int func, int addr, void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + + sis_5511_log("SiS 5513: dev->pci_conf[%02x][%02x] = %02x POST %02x\n", func, addr, dev->pci_conf_sb[func][addr], inb(0x80)); + if ((func >= 0) && (func <= 1)) + return dev->pci_conf_sb[func][addr]; + else + return 0xff; +} + +static void +sis_5513_isa_write(uint16_t addr, uint8_t val, void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + + switch (addr) + { + case 0x22: + dev->index = val - 0x50; + break; + case 0x23: + switch (dev->index) + { + case 0x00: + dev->regs[dev->index] = val & 0xed; + switch (val >> 6) + { + case 0: + cpu_set_isa_speed(7159091); + break; + case 1: + cpu_set_isa_pci_div(4); + break; + case 2: + cpu_set_isa_pci_div(3); + break; + } + break; + case 0x01: + dev->regs[dev->index] = val & 0xf4; + break; + case 0x03: + dev->regs[dev->index] = val & 3; + break; + case 0x04: /* BIOS Register */ + dev->regs[dev->index] = val; + break; + case 0x05: + dev->regs[dev->index] = inb(0x70); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + dev->regs[dev->index] = val; + break; + } + sis_5511_log("SiS 5513-ISA: dev->regs[%02x] = %02x POST: %02x\n", dev->index + 0x50, dev->regs[dev->index], inb(0x80)); + break; + } +} + +static uint8_t +sis_5513_isa_read(uint16_t addr, void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + + if (addr == 0x23) + { + sis_5511_log("SiS 5513-ISA: dev->regs[%02x] (%02x) POST: %02x\n", dev->index + 0x50, dev->regs[dev->index], inb(0x80)); + return dev->regs[dev->index]; + } + else + return 0xff; +} + + +static void +sis_5511_reset(void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + + /* SiS 5511 */ + dev->pci_conf[0x00] = 0x39; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x11; + dev->pci_conf[0x03] = 0x55; + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x05] = dev->pci_conf[0x06] = 0x00; + dev->pci_conf[0x07] = 0x02; + dev->pci_conf[0x08] = 0x00; + dev->pci_conf[0x09] = dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x50] = dev->pci_conf[0x51] = 0x00; + dev->pci_conf[0x52] = 0x20; + dev->pci_conf[0x53] = dev->pci_conf[0x54] = 0x00; + dev->pci_conf[0x55] = dev->pci_conf[0x56] = 0x00; + dev->pci_conf[0x57] = dev->pci_conf[0x58] = 0x00; + dev->pci_conf[0x59] = dev->pci_conf[0x5a] = 0x00; + dev->pci_conf[0x5b] = dev->pci_conf[0x5c] = 0x00; + dev->pci_conf[0x5d] = dev->pci_conf[0x5e] = 0x00; + dev->pci_conf[0x5f] = dev->pci_conf[0x60] = 0x00; + dev->pci_conf[0x61] = dev->pci_conf[0x62] = 0xff; + dev->pci_conf[0x63] = 0xff; + dev->pci_conf[0x64] = dev->pci_conf[0x65] = 0x00; + dev->pci_conf[0x66] = 0x00; + dev->pci_conf[0x67] = 0xff; + dev->pci_conf[0x68] = dev->pci_conf[0x69] = 0x00; + dev->pci_conf[0x6a] = dev->pci_conf[0x6b] = 0x00; + dev->pci_conf[0x6c] = dev->pci_conf[0x6d] = 0x00; + dev->pci_conf[0x6e] = dev->pci_conf[0x6f] = 0x00; + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + dev->pci_conf[0x6b] = 0xff; + dev->pci_conf[0x6c] = 0xff; + dev->pci_conf[0x70] = 4; + dev->pci_conf[0x72] = 4; + dev->pci_conf[0x73] = 0x80; + dev->pci_conf[0x74] = 4; + dev->pci_conf[0x76] = 4; + dev->pci_conf[0x77] = 0x80; + dev->pci_conf[0x78] = 4; + dev->pci_conf[0x7a] = 4; + dev->pci_conf[0x7b] = 0x80; + dev->pci_conf[0x7c] = 4; + dev->pci_conf[0x7e] = 4; + dev->pci_conf[0x7f] = 0x80; + dev->pci_conf[0x80] = 0x00; + dev->pci_conf[0x81] = 0x00; + dev->pci_conf[0x82] = 0x00; + dev->pci_conf[0x83] = 0x00; + dev->pci_conf[0x84] = 0x00; + dev->pci_conf[0x85] = 0x00; + dev->pci_conf[0x86] = 0x00; + sis_5511_smram_recalc(dev); + sis_5511_shadow_recalc(dev); + + /* SiS 5513 */ + dev->pci_conf_sb[0][0x00] = 0x39; + dev->pci_conf_sb[0][0x01] = 0x10; + dev->pci_conf_sb[0][0x02] = 8; + dev->pci_conf_sb[0][0x04] = 7; + dev->pci_conf_sb[0][0x0a] = 1; + dev->pci_conf_sb[0][0x0b] = 6; + dev->pci_conf_sb[0][0x0e] = 0x80; + + /* SiS 5513 IDE Controller */ + dev->pci_conf_sb[1][0x00] = 0x39; + dev->pci_conf_sb[1][0x01] = 0x10; + dev->pci_conf_sb[1][0x02] = 0x13; + dev->pci_conf_sb[1][0x03] = 0x55; + dev->pci_conf_sb[1][0x0a] = 1; + dev->pci_conf_sb[1][0x0b] = 1; + dev->pci_conf_sb[1][0x0e] = 0x80; + sff_set_slot(dev->ide_drive[0], dev->sb_pci_slot); + sff_set_slot(dev->ide_drive[1], dev->sb_pci_slot); + sff_bus_master_reset(dev->ide_drive[0], BUS_MASTER_BASE); + sff_bus_master_reset(dev->ide_drive[1], BUS_MASTER_BASE + 8); +} + +static void +sis_5511_close(void *priv) +{ + sis_5511_t *dev = (sis_5511_t *)priv; + + smram_del(dev->smram); + free(dev); +} + +static void * +sis_5511_init(const device_t *info) +{ + sis_5511_t *dev = (sis_5511_t *)malloc(sizeof(sis_5511_t)); + memset(dev, 0, sizeof(sis_5511_t)); + + dev->nb_pci_slot = pci_add_card(PCI_ADD_NORTHBRIDGE, sis_5511_read, sis_5511_write, dev); /* Device 0: SiS 5511 */ + dev->sb_pci_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, sis_5513_read, sis_5513_write, dev); /* Device 1: SiS 5513 */ + io_sethandler(0x0022, 0x0002, sis_5513_isa_read, NULL, NULL, sis_5513_isa_write, NULL, NULL, dev); /* Ports 22h-23h: SiS 5513 ISA */ + + /* MIRQ */ + pci_enable_mirq(0); + pci_enable_mirq(1); + + /* Port 92h */ + dev->port_92 = device_add(&port_92_device); + + /* SFF IDE */ + dev->ide_drive[0] = device_add_inst(&sff8038i_device, 1); + dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2); + + /* SMRAM */ + dev->smram = smram_add(); + + sis_5511_reset(dev); + + return dev; +} + +const device_t sis_5511_device = { + .name = "SiS 5511", + .internal_name = "sis_5511", + .flags = DEVICE_PCI, + .local = 0, + .init = sis_5511_init, + .close = sis_5511_close, + .reset = sis_5511_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c new file mode 100644 index 000000000..2d9d92c8d --- /dev/null +++ b/src/chipset/sis_5571.c @@ -0,0 +1,756 @@ +/* + * 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 SiS 5571 Chipset. + * + * Authors: Tiseno100, + * + * Copyright 2021 Tiseno100. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/timer.h> + +#include <86box/dma.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/smram.h> +#include <86box/usb.h> + +#include <86box/chipset.h> + +/* Shadow RAM */ +#define LSB_READ ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x08) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define LSB_WRITE ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) +#define MSB_READ ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define MSB_WRITE ((dev->pci_conf[0x70 + (cur_reg & 0x07)] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) +#define SYSTEM_READ ((dev->pci_conf[0x76] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) +#define SYSTEM_WRITE ((dev->pci_conf[0x76] & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY) + +/* IDE Flags (1 Native / 0 Compatibility)*/ +#define PRIMARY_COMP_NAT_SWITCH (dev->pci_conf_sb[1][9] & 1) +#define SECONDARY_COMP_NAT_SWITCH (dev->pci_conf_sb[1][9] & 4) +#define PRIMARY_NATIVE_BASE (dev->pci_conf_sb[1][0x11] << 8) | (dev->pci_conf_sb[1][0x10] & 0xf8) +#define PRIMARY_NATIVE_SIDE (((dev->pci_conf_sb[1][0x15] << 8) | (dev->pci_conf_sb[1][0x14] & 0xfc)) + 2) +#define SECONDARY_NATIVE_BASE (dev->pci_conf_sb[1][0x19] << 8) | (dev->pci_conf_sb[1][0x18] & 0xf8) +#define SECONDARY_NATIVE_SIDE (((dev->pci_conf_sb[1][0x1d] << 8) | (dev->pci_conf_sb[1][0x1c] & 0xfc)) + 2) +#define BUS_MASTER_BASE ((dev->pci_conf_sb[1][0x20] & 0xf0) | (dev->pci_conf_sb[1][0x21] << 8)) + +#ifdef ENABLE_SIS_5571_LOG +int sis_5571_do_log = ENABLE_SIS_5571_LOG; +static void +sis_5571_log(const char *fmt, ...) +{ + va_list ap; + + if (sis_5571_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sis_5571_log(fmt, ...) +#endif + +typedef struct sis_5571_t +{ + uint8_t pci_conf[256], pci_conf_sb[3][256]; + + int nb_pci_slot, sb_pci_slot; + + port_92_t *port_92; + sff8038i_t *ide_drive[2]; + smram_t *smram; + usb_t *usb; + +} sis_5571_t; + +static void +sis_5571_shadow_recalc(int cur_reg, sis_5571_t *dev) +{ + if (cur_reg != 0x76) + { + mem_set_mem_state_both(0xc0000 + (0x8000 * (cur_reg & 0x07)), 0x4000, LSB_READ | LSB_WRITE); + mem_set_mem_state_both(0xc4000 + (0x8000 * (cur_reg & 0x07)), 0x4000, MSB_READ | MSB_WRITE); + } + else + mem_set_mem_state_both(0xf0000, 0x10000, SYSTEM_READ | SYSTEM_WRITE); + + flushmmucache_nopc(); +} + +static void +sis_5571_smm_recalc(sis_5571_t *dev) +{ + smram_disable_all(); + + switch ((dev->pci_conf[0xa3] & 0xc0) >> 6) + { + case 0x00: + smram_enable(dev->smram, 0xe0000, 0xe0000, 0x8000, (dev->pci_conf[0xa3] & 0x10), 1); + break; + case 0x01: + smram_enable(dev->smram, 0xe0000, 0xa0000, 0x8000, (dev->pci_conf[0xa3] & 0x10), 1); + break; + case 0x02: + smram_enable(dev->smram, 0xe0000, 0xb0000, 0x8000, (dev->pci_conf[0xa3] & 0x10), 1); + break; + case 0x03: + smram_enable(dev->smram, 0xa0000, 0xa0000, 0x10000, (dev->pci_conf[0xa3] & 0x10), 1); + break; + } + + flushmmucache(); +} + +void sis_5571_ide_handler(sis_5571_t *dev) +{ + ide_pri_disable(); + ide_sec_disable(); + if (dev->pci_conf_sb[1][4] & 1) + { + if (dev->pci_conf_sb[1][0x4a] & 4) + { + ide_set_base(0, PRIMARY_COMP_NAT_SWITCH ? PRIMARY_NATIVE_BASE : 0x1f0); + ide_set_side(0, PRIMARY_COMP_NAT_SWITCH ? PRIMARY_NATIVE_SIDE : 0x3f6); + ide_pri_enable(); + } + if (dev->pci_conf_sb[1][0x4a] & 2) + { + ide_set_base(1, SECONDARY_COMP_NAT_SWITCH ? SECONDARY_NATIVE_BASE : 0x170); + ide_set_side(1, SECONDARY_COMP_NAT_SWITCH ? SECONDARY_NATIVE_SIDE : 0x376); + ide_sec_enable(); + } + } +} + +void sis_5571_bm_handler(sis_5571_t *dev) +{ + sff_bus_master_handler(dev->ide_drive[0], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE); + sff_bus_master_handler(dev->ide_drive[1], dev->pci_conf_sb[1][4] & 4, BUS_MASTER_BASE + 8); +} + +static void +memory_pci_bridge_write(int func, int addr, uint8_t val, void *priv) +{ + sis_5571_t *dev = (sis_5571_t *)priv; + + switch (addr) + { + case 0x04: /* Command - low byte */ + case 0x05: /* Command - high byte */ + dev->pci_conf[addr] |= val; + break; + + case 0x06: /* Status - Low Byte */ + dev->pci_conf[addr] &= val; + break; + + case 0x07: /* Status - High Byte */ + dev->pci_conf[addr] &= val & 0xbe; + break; + + case 0x0d: /* Master latency timer */ + dev->pci_conf[addr] = val; + break; + + case 0x50: /* Host Interface and DRAM arbiter */ + dev->pci_conf[addr] = val & 0xec; + break; + + case 0x51: /* CACHE */ + dev->pci_conf[addr] = val; + cpu_cache_ext_enabled = !!(val & 0x40); + cpu_update_waitstates(); + break; + + case 0x52: + dev->pci_conf[addr] = val & 0xd0; + break; + + case 0x53: /* DRAM */ + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0x54: /* FP/EDO */ + dev->pci_conf[addr] = val; + break; + + case 0x55: + dev->pci_conf[addr] = val & 0xe0; + break; + + case 0x56: /* MDLE delay */ + case 0x57: /* SDRAM */ + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x59: /* Buffer strength and current rating */ + dev->pci_conf[addr] = val; + break; + + case 0x5a: + dev->pci_conf[addr] = val & 0x03; + break; + + case 0x60: /* Undocumented */ + case 0x61: /* Undocumented */ + case 0x62: /* Undocumented */ + case 0x63: /* Undocumented */ + case 0x64: /* Undocumented */ + case 0x65: /* Undocumented */ + case 0x66: /* Undocumented */ + case 0x67: /* Undocumented */ + case 0x68: /* Undocumented */ + case 0x69: /* Undocumented */ + case 0x6a: /* Undocumented */ + case 0x6b: /* Undocumented */ + dev->pci_conf[addr] = val; + break; + + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: /* Attribute of shadow RAM for BIOS area */ + dev->pci_conf[addr] = val & ((addr != 0x76) ? 0xee : 0xe8); + sis_5571_shadow_recalc(addr, dev); + sis_5571_smm_recalc(dev); + break; + + case 0x77: /* Characteristics of non-cacheable area */ + dev->pci_conf[addr] = val & 0x0f; + break; + + case 0x78: /* Allocation of Non-Cacheable area #1 */ + case 0x79: /* NCA1REG2 */ + case 0x7a: /* Allocation of Non-Cacheable area #2 */ + case 0x7b: /* NCA2REG2 */ + dev->pci_conf[addr] = val; + break; + + case 0x80: /* PCI master characteristics */ + dev->pci_conf[addr] = val & 0xfe; + break; + + case 0x81: + dev->pci_conf[addr] = val & 0xcc; + break; + + case 0x82: + dev->pci_conf[addr] = val; + break; + + case 0x83: /* CPU to PCI characteristics */ + dev->pci_conf[addr] = val; + port_92_set_features(dev->port_92, !!(val & 0x40), !!(val & 0x80)); + break; + + case 0x84: + case 0x85: + case 0x86: + dev->pci_conf[addr] = val; + break; + + case 0x87: /* Miscellanea */ + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x90: /* PMU control register */ + case 0x91: /* Address trap for green function */ + case 0x92: + dev->pci_conf[addr] = val; + break; + + case 0x93: /* STPCLK# and APM SMI control */ + dev->pci_conf[addr] = val; + + if ((dev->pci_conf[0x9b] & 1) && !!(val & 2)) + { + smi_raise(); + dev->pci_conf[0x9d] |= 1; + } + break; + + case 0x94: /* 6x86 and Green function control */ + dev->pci_conf[addr] = val & 0xf8; + break; + + case 0x95: /* Test mode control */ + case 0x96: /* Time slot and Programmable 10-bit I/O port definition */ + dev->pci_conf[addr] = val & 0xfb; + break; + + case 0x97: /* programmable 10-bit I/O port address */ + case 0x98: /* Programmable 16-bit I/O port */ + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + dev->pci_conf[addr] = val; + break; + + case 0x9d: + dev->pci_conf[addr] &= val; + break; + + case 0x9e: /* STPCLK# Assertion Timer */ + case 0x9f: /* STPCLK# De-assertion Timer */ + case 0xa0: + case 0xa1: + case 0xa2: + dev->pci_conf[addr] = val; + break; + + case 0xa3: /* SMRAM access control and Power supply control */ + dev->pci_conf[addr] = val & 0xd0; + sis_5571_smm_recalc(dev); + break; + } + sis_5571_log("SiS5571: dev->pci_conf[%02x] = %02x\n", addr, val); +} + +static uint8_t +memory_pci_bridge_read(int func, int addr, void *priv) +{ + sis_5571_t *dev = (sis_5571_t *)priv; + sis_5571_log("SiS5571: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf[addr]); + return dev->pci_conf[addr]; +} + +static void +pci_isa_bridge_write(int func, int addr, uint8_t val, void *priv) +{ + sis_5571_t *dev = (sis_5571_t *)priv; + switch (func) + { + case 0: /* Bridge */ + switch (addr) + { + case 0x04: /* Command */ + dev->pci_conf_sb[0][addr] |= val & 0x0f; + break; + + case 0x06: /* Status */ + dev->pci_conf_sb[0][addr] &= val; + break; + + case 0x40: /* BIOS Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x3f; + break; + + case 0x41: /* INTA# Remapping Control Register */ + case 0x42: /* INTB# Remapping Control Register */ + case 0x43: /* INTC# Remapping Control Register */ + case 0x44: /* INTD# Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x8f; + pci_set_irq_routing((addr & 0x07), !(val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED); + break; + + case 0x45: + dev->pci_conf_sb[0][addr] = val & 0xec; + switch ((val & 0xc0) >> 6) + { + case 0: + cpu_set_isa_speed(7159091); + break; + case 1: + cpu_set_isa_pci_div(4); + break; + case 2: + cpu_set_isa_pci_div(3); + break; + } + break; + + case 0x46: + dev->pci_conf_sb[0][addr] = val & 0xec; + break; + + case 0x47: /* DMA Clock and Wait State Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x3e; + break; + + case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */ + case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */ + case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */ + case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */ + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x5f: + dev->pci_conf_sb[0][addr] = val & 0x3f; + break; + + case 0x60: + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x61: /* MIRQ Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val; + pci_set_mirq_routing(PCI_MIRQ0, !(val & 0x80) ? (val & 0x0f) : PCI_IRQ_DISABLED); + break; + + case 0x62: /* On-board Device DMA Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x0f; + dma_set_drq((val & 0x07), 1); + break; + + case 0x63: /* IDEIRQ Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x8f; + if (val & 0x80) + { + sff_set_irq_line(dev->ide_drive[0], val & 0x0f); + sff_set_irq_line(dev->ide_drive[1], val & 0x0f); + } + break; + + case 0x64: /* GPIO Control Register */ + dev->pci_conf_sb[0][addr] = val & 0xef; + break; + + case 0x65: + dev->pci_conf_sb[0][addr] = val & 0x1b; + break; + + case 0x66: /* GPIO Output Mode Control Register */ + case 0x67: /* GPIO Output Mode Control Register */ + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x68: /* USBIRQ Remapping Control Register */ + dev->pci_conf_sb[0][addr] = val & 0x1b; + break; + + case 0x69: + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x6a: + dev->pci_conf_sb[0][addr] = val & 0xfc; + break; + + case 0x6b: + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x6c: + dev->pci_conf_sb[0][addr] = val & 0x03; + break; + + case 0x6e: /* Software-Controlled Interrupt Request, Channels 7-0 */ + case 0x6f: /* Software-Controlled Interrupt Request, channels 15-8 */ + dev->pci_conf_sb[0][addr] = val; + break; + + case 0x70: + dev->pci_conf_sb[0][addr] = val & 0xde; + break; + + case 0x71: /* Type-F DMA Control Register */ + dev->pci_conf_sb[0][addr] = val & 0xfe; + break; + + case 0x72: /* SMI Triggered By IRQ/GPIO Control */ + case 0x73: /* SMI Triggered By IRQ/GPIO Control */ + dev->pci_conf_sb[0][addr] = (addr == 0x72) ? val & 0xfe : val; + break; + + case 0x74: /* System Standby Timer Reload, System Standby State Exit And Throttling State Exit Control */ + case 0x75: /* System Standby Timer Reload, System Standby State Exit And Throttling State Exit Control */ + case 0x76: /* Monitor Standby Timer Reload And Monitor Standby State ExitControl */ + case 0x77: /* Monitor Standby Timer Reload And Monitor Standby State ExitControl */ + dev->pci_conf_sb[0][addr] = val; + break; + } + sis_5571_log("SiS5571-SB: dev->pci_conf[%02x] = %02x\n", addr, val); + break; + + case 1: /* IDE Controller */ + switch (addr) + { + case 0x04: /* Command low byte */ + dev->pci_conf_sb[1][addr] = val & 0x05; + sis_5571_ide_handler(dev); + sis_5571_bm_handler(dev); + break; + + case 0x07: /* Status high byte */ + dev->pci_conf_sb[1][addr] &= val; + break; + + case 0x09: /* Programming Interface Byte */ + dev->pci_conf_sb[1][addr] = val & 0xcf; + sis_5571_ide_handler(dev); + break; + + case 0x0d: /* Latency Time */ + case 0x10: /* Primary Channel Base Address Register */ + case 0x11: /* Primary Channel Base Address Register */ + case 0x12: /* Primary Channel Base Address Register */ + case 0x13: /* Primary Channel Base Address Register */ + case 0x14: /* Primary Channel Base Address Register */ + case 0x15: /* Primary Channel Base Address Register */ + case 0x16: /* Primary Channel Base Address Register */ + case 0x17: /* Primary Channel Base Address Register */ + case 0x18: /* Secondary Channel Base Address Register */ + case 0x19: /* Secondary Channel Base Address Register */ + case 0x1a: /* Secondary Channel Base Address Register */ + case 0x1b: /* Secondary Channel Base Address Register */ + case 0x1c: /* Secondary Channel Base Address Register */ + case 0x1d: /* Secondary Channel Base Address Register */ + case 0x1e: /* Secondary Channel Base Address Register */ + case 0x1f: /* Secondary Channel Base Address Register */ + dev->pci_conf_sb[1][addr] = val; + sis_5571_ide_handler(dev); + break; + + case 0x20: /* Bus Master IDE Control Register Base Address */ + case 0x21: /* Bus Master IDE Control Register Base Address */ + case 0x22: /* Bus Master IDE Control Register Base Address */ + case 0x23: /* Bus Master IDE Control Register Base Address */ + dev->pci_conf_sb[1][addr] = val; + sis_5571_bm_handler(dev); + break; + + case 0x30: /* Expansion ROM Base Address */ + case 0x31: /* Expansion ROM Base Address */ + case 0x32: /* Expansion ROM Base Address */ + case 0x33: /* Expansion ROM Base Address */ + case 0x40: /* IDE Primary Channel/Master Drive Data Recovery Time Control */ + case 0x41: /* IDE Primary Channel/Master Drive DataActive Time Control */ + case 0x42: /* IDE Primary Channel/Slave Drive Data Recovery Time Control */ + case 0x43: /* IDE Primary Channel/Slave Drive Data Active Time Control */ + case 0x44: /* IDE Secondary Channel/Master Drive Data Recovery Time Control */ + case 0x45: /* IDE Secondary Channel/Master Drive Data Active Time Control */ + case 0x46: /* IDE Secondary Channel/Slave Drive Data Recovery Time Control */ + case 0x47: /* IDE Secondary Channel/Slave Drive Data Active Time Control */ + case 0x48: /* IDE Command Recovery Time Control */ + case 0x49: /* IDE Command Active Time Control */ + dev->pci_conf_sb[1][addr] = val; + break; + + case 0x4a: /* IDE General Control Register 0 */ + dev->pci_conf_sb[1][addr] = val & 0xaf; + sis_5571_ide_handler(dev); + break; + + case 0x4b: /* IDE General Control register 1 */ + case 0x4c: /* Prefetch Count of Primary Channel (Low Byte) */ + case 0x4d: /* Prefetch Count of Primary Channel (High Byte) */ + case 0x4e: /* Prefetch Count of Secondary Channel (Low Byte) */ + case 0x4f: /* Prefetch Count of Secondary Channel (High Byte) */ + dev->pci_conf_sb[1][addr] = val; + break; + } + sis_5571_log("SiS5571-IDE: dev->pci_conf[%02x] = %02x\n", addr, val); + break; + + case 2: /* USB Controller */ + switch (addr) + { + case 0x04: /* Command - Low Byte */ + dev->pci_conf_sb[2][addr] = val; + ohci_update_mem_mapping(dev->usb, dev->pci_conf_sb[2][0x11], dev->pci_conf_sb[2][0x12], dev->pci_conf_sb[2][0x13], dev->pci_conf_sb[2][4] & 1); + break; + + case 0x05: /* Command - High Byte */ + dev->pci_conf_sb[2][addr] = val & 0x03; + break; + + case 0x06: /* Status - Low Byte */ + dev->pci_conf_sb[2][addr] &= val & 0xc0; + break; + + case 0x07: /* Status - High Byte */ + dev->pci_conf_sb[2][addr] &= val; + break; + + case 0x10: /* Memory Space Base Address Register */ + case 0x11: /* Memory Space Base Address Register */ + case 0x12: /* Memory Space Base Address Register */ + case 0x13: /* Memory Space Base Address Register */ + dev->pci_conf_sb[2][addr] = val & ((addr == 0x11) ? 0x0f : 0xff); + ohci_update_mem_mapping(dev->usb, dev->pci_conf_sb[2][0x11], dev->pci_conf_sb[2][0x12], dev->pci_conf_sb[2][0x13], dev->pci_conf_sb[2][4] & 1); + break; + + case 0x14: /* IO Space Base Address Register */ + case 0x15: /* IO Space Base Address Register */ + case 0x16: /* IO Space Base Address Register */ + case 0x17: /* IO Space Base Address Register */ + case 0x3c: /* Interrupt Line */ + dev->pci_conf_sb[2][addr] = val; + break; + } + sis_5571_log("SiS5571-USB: dev->pci_conf[%02x] = %02x\n", addr, val); + } +} + +static uint8_t +pci_isa_bridge_read(int func, int addr, void *priv) +{ + sis_5571_t *dev = (sis_5571_t *)priv; + + switch (func) + { + case 0: + sis_5571_log("SiS5571-SB: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf_sb[0][addr]); + return dev->pci_conf_sb[0][addr]; + case 1: + sis_5571_log("SiS5571-IDE: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf_sb[1][addr]); + return dev->pci_conf_sb[1][addr]; + case 2: + sis_5571_log("SiS5571-USB: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf_sb[2][addr]); + return dev->pci_conf_sb[2][addr]; + default: + return 0xff; + } +} + +static void +sis_5571_reset(void *priv) +{ + sis_5571_t *dev = (sis_5571_t *)priv; + + /* Memory/PCI Bridge */ + dev->pci_conf[0x00] = 0x39; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x71; + dev->pci_conf[0x03] = 0x55; + dev->pci_conf[0x04] = 0xfd; + dev->pci_conf[0x0b] = 0x06; + dev->pci_conf[0x9e] = 0xff; + dev->pci_conf[0x9f] = 0xff; + dev->pci_conf[0xa2] = 0xff; + + /* PCI to ISA bridge */ + dev->pci_conf_sb[0][0x00] = 0x39; + dev->pci_conf_sb[0][0x01] = 0x10; + dev->pci_conf_sb[0][0x02] = 0x08; + dev->pci_conf_sb[0][0x04] = 0xfd; + dev->pci_conf_sb[0][0x08] = 0x01; + dev->pci_conf_sb[0][0x0a] = 0x01; + dev->pci_conf_sb[0][0x0b] = 0x06; + + /* IDE Controller */ + dev->pci_conf_sb[1][0x00] = 0x39; + dev->pci_conf_sb[1][0x01] = 0x10; + dev->pci_conf_sb[1][0x02] = 0x13; + dev->pci_conf_sb[1][0x03] = 0x55; + dev->pci_conf_sb[1][0x08] = 0xc0; + dev->pci_conf_sb[1][0x0a] = 0x01; + dev->pci_conf_sb[1][0x0b] = 0x01; + dev->pci_conf_sb[1][0x0e] = 0x80; + dev->pci_conf_sb[1][0x4a] = 0x06; + sff_set_slot(dev->ide_drive[0], dev->sb_pci_slot); + sff_set_slot(dev->ide_drive[1], dev->sb_pci_slot); + sff_bus_master_reset(dev->ide_drive[0], BUS_MASTER_BASE); + sff_bus_master_reset(dev->ide_drive[1], BUS_MASTER_BASE + 8); + + /* USB Controller */ + dev->pci_conf_sb[2][0x00] = 0x39; + dev->pci_conf_sb[2][0x01] = 0x10; + dev->pci_conf_sb[2][0x02] = 0x01; + dev->pci_conf_sb[2][0x03] = 0x70; + dev->pci_conf_sb[2][0x08] = 0xb0; + dev->pci_conf_sb[2][0x09] = 0x10; + dev->pci_conf_sb[2][0x0a] = 0x03; + dev->pci_conf_sb[2][0x0b] = 0xc0; + dev->pci_conf_sb[2][0x0e] = 0x80; + dev->pci_conf_sb[2][0x14] = 0x01; + dev->pci_conf_sb[2][0x3d] = 0x01; +} + +static void +sis_5571_close(void *priv) +{ + sis_5571_t *dev = (sis_5571_t *)priv; + + smram_del(dev->smram); + free(dev); +} + +static void * +sis_5571_init(const device_t *info) +{ + sis_5571_t *dev = (sis_5571_t *)malloc(sizeof(sis_5571_t)); + memset(dev, 0x00, sizeof(sis_5571_t)); + + dev->nb_pci_slot = pci_add_card(PCI_ADD_NORTHBRIDGE, memory_pci_bridge_read, memory_pci_bridge_write, dev); + dev->sb_pci_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, pci_isa_bridge_read, pci_isa_bridge_write, dev); + + /* MIRQ */ + pci_enable_mirq(0); + + /* Port 92 & SMRAM */ + dev->port_92 = device_add(&port_92_pci_device); + dev->smram = smram_add(); + + /* SFF IDE */ + dev->ide_drive[0] = device_add_inst(&sff8038i_device, 1); + dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2); + + /* USB */ + dev->usb = device_add(&usb_device); + + sis_5571_reset(dev); + + return dev; +} + +const device_t sis_5571_device = { + .name = "SiS 5571", + .internal_name = "sis_5571", + .flags = DEVICE_PCI, + .local = 0, + .init = sis_5571_init, + .close = sis_5571_close, + .reset = sis_5571_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/sis_85c310.c b/src/chipset/sis_85c310.c index 2a11f9654..2e83e3367 100644 --- a/src/chipset/sis_85c310.c +++ b/src/chipset/sis_85c310.c @@ -7,13 +7,9 @@ #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/keyboard.h> #include <86box/mem.h> -#include <86box/fdd.h> -#include <86box/fdc.h> #include <86box/chipset.h> @@ -139,12 +135,16 @@ rabbit_init(const device_t *info) return dev; } - const device_t rabbit_device = { - "SiS Rabbit", - 0, - 0, - rabbit_init, rabbit_close, NULL, - NULL, NULL, NULL, - NULL -}; \ No newline at end of file + .name = "SiS Rabbit", + .internal_name = "rabbit", + .flags = 0, + .local = 0, + .init = rabbit_init, + .close = rabbit_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/sis_85c471.c b/src/chipset/sis_85c471.c deleted file mode 100644 index 6518cd0f3..000000000 --- a/src/chipset/sis_85c471.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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 the SiS 85c471 chip. - * - * SiS sis85c471 Super I/O Chip - * Used by DTK PKM-0038S E-2 - * - * - * - * Authors: Miran Grca, - * - * Copyright 2019 Miran Grca. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include "cpu.h" -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/lpt.h> -#include <86box/rom.h> -#include <86box/pci.h> -#include <86box/device.h> -#include <86box/hdc_ide.h> -#include <86box/keyboard.h> -#include <86box/timer.h> -#include <86box/port_92.h> -#include <86box/serial.h> -#include <86box/machine.h> -#include <86box/chipset.h> - - -typedef struct { - uint8_t cur_reg, - regs[39], - scratch[2]; - port_92_t * port_92; -} sis_85c471_t; - - -static void -sis_85c471_recalcmapping(sis_85c471_t *dev) -{ - uint32_t base; - uint32_t i, shflags = 0; - - shadowbios = 0; - shadowbios_write = 0; - - for (i = 0; i < 8; i++) { - base = 0xc0000 + (i << 15); - - if ((i > 5) || (dev->regs[0x02] & (1 << i))) { - shadowbios |= (base >= 0xe0000) && (dev->regs[0x02] & 0x80); - shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40); - shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; - shflags |= (dev->regs[0x02] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; - mem_set_mem_state(base, 0x8000, shflags); - } else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTERNAL); - } - - flushmmucache(); -} - - -static void -sis_85c471_write(uint16_t port, uint8_t val, void *priv) -{ - sis_85c471_t *dev = (sis_85c471_t *) priv; - uint8_t valxor = 0x00; - - if (port == 0x22) { - if ((val >= 0x50) && (val <= 0x76)) - dev->cur_reg = val; - return; - } else if (port == 0x23) { - if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76)) - return; - valxor = val ^ dev->regs[dev->cur_reg - 0x50]; - dev->regs[dev->cur_reg - 0x50] = val; - } else if ((port == 0xe1) || (port == 0xe2)) { - dev->scratch[port - 0xe1] = val; - return; - } - - switch(dev->cur_reg) { - case 0x51: - cpu_cache_ext_enabled = ((val & 0x84) == 0x84); - cpu_update_waitstates(); - break; - - case 0x52: - sis_85c471_recalcmapping(dev); - break; - - case 0x57: - if (valxor & 0x12) - port_92_set_features(dev->port_92, !!(val & 0x10), !!(val & 0x02)); - - if (valxor & 0x08) { - if (val & 0x08) - port_92_set_period(dev->port_92, 6ULL * TIMER_USEC); - else - port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); - } - break; - - case 0x5b: - if (valxor & 0x02) { - if (val & 0x02) - mem_remap_top(0); - else - mem_remap_top(256); - } - break; - - case 0x63: - if (valxor & 0x10) { - if (dev->regs[0x13] & 0x10) - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - else - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - } - break; - - case 0x72: - if (valxor & 0x01) { - port_92_remove(dev->port_92); - if (val & 0x01) - port_92_add(dev->port_92); - } - break; - } - - dev->cur_reg = 0; -} - - -static uint8_t -sis_85c471_read(uint16_t port, void *priv) -{ - sis_85c471_t *dev = (sis_85c471_t *) priv; - uint8_t ret = 0xff; - - if (port == 0x22) - ret = dev->cur_reg; - else if (port == 0x23) { - if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) { - ret = dev->regs[dev->cur_reg - 0x50]; - if (dev->cur_reg == 0x58) - ret &= 0xf7; - dev->cur_reg = 0; - } - } else if ((port == 0xe1) || (port == 0xe2)) - ret = dev->scratch[port - 0xe1]; - - return ret; -} - - -static void -sis_85c471_close(void *priv) -{ - sis_85c471_t *dev = (sis_85c471_t *) priv; - - free(dev); -} - - -static void * -sis_85c471_init(const device_t *info) -{ - int mem_size_mb, i = 0; - - sis_85c471_t *dev = (sis_85c471_t *) malloc(sizeof(sis_85c471_t)); - memset(dev, 0, sizeof(sis_85c471_t)); - - dev->cur_reg = 0; - for (i = 0; i < 0x27; i++) - dev->regs[i] = 0x00; - - dev->regs[9] = 0x40; - - mem_size_mb = mem_size >> 10; - switch (mem_size_mb) { - case 0: case 1: - dev->regs[9] |= 0; - break; - case 2: case 3: - dev->regs[9] |= 1; - break; - case 4: - dev->regs[9] |= 2; - break; - case 5: - dev->regs[9] |= 0x20; - break; - case 6: case 7: - dev->regs[9] |= 9; - break; - case 8: case 9: - dev->regs[9] |= 4; - break; - case 10: case 11: - dev->regs[9] |= 5; - break; - case 12: case 13: case 14: case 15: - dev->regs[9] |= 0xB; - break; - case 16: - dev->regs[9] |= 0x13; - break; - case 17: - dev->regs[9] |= 0x21; - break; - case 18: case 19: - dev->regs[9] |= 6; - break; - case 20: case 21: case 22: case 23: - dev->regs[9] |= 0xD; - break; - case 24: case 25: case 26: case 27: - case 28: case 29: case 30: case 31: - dev->regs[9] |= 0xE; - break; - case 32: case 33: case 34: case 35: - dev->regs[9] |= 0x1B; - break; - case 36: case 37: case 38: case 39: - dev->regs[9] |= 0xF; - break; - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - dev->regs[9] |= 0x17; - break; - case 48: - dev->regs[9] |= 0x1E; - break; - default: - if (mem_size_mb < 64) - dev->regs[9] |= 0x1E; - else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) - dev->regs[9] |= 0x22; - else - dev->regs[9] |= 0x24; - break; - } - - dev->regs[0x11] = 9; - dev->regs[0x12] = 0xFF; - dev->regs[0x1f] = 0x20; /* Video access enabled. */ - dev->regs[0x23] = 0xF0; - dev->regs[0x26] = 1; - - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed < 25000000) - dev->regs[0x08] |= 0x80; - - io_sethandler(0x0022, 0x0002, - sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); - - dev->scratch[0] = dev->scratch[1] = 0xff; - - io_sethandler(0x00e1, 0x0002, - sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); - - dev->port_92 = device_add(&port_92_device); - port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); - port_92_set_features(dev->port_92, 0, 0); - - sis_85c471_recalcmapping(dev); - - return dev; -} - - -const device_t sis_85c471_device = { - "SiS 85c471", - 0, - 0, - sis_85c471_init, sis_85c471_close, NULL, - NULL, NULL, NULL, - NULL -}; diff --git a/src/chipset/sis_85c496.c b/src/chipset/sis_85c496.c index 7fafa9607..36d1f2030 100644 --- a/src/chipset/sis_85c496.c +++ b/src/chipset/sis_85c496.c @@ -10,74 +10,113 @@ * * * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2019 Miran Grca. + * Copyright 2019,2020 Miran Grca. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/smram.h> #include <86box/io.h> -#include <86box/rom.h> #include <86box/pci.h> #include <86box/device.h> -#include <86box/keyboard.h> #include <86box/timer.h> +#include <86box/dma.h> +#include <86box/nvr.h> +#include <86box/pic.h> #include <86box/port_92.h> #include <86box/hdc_ide.h> #include <86box/machine.h> #include <86box/chipset.h> +#include <86box/spd.h> typedef struct sis_85c496_t { - uint8_t cur_reg, + uint8_t cur_reg, rmsmiblk_count, regs[127], pci_conf[256]; + smram_t *smram; + pc_timer_t rmsmiblk_timer; port_92_t * port_92; + nvr_t * nvr; } sis_85c496_t; +#ifdef ENABLE_SIS_85C496_LOG +int sis_85c496_do_log = ENABLE_SIS_85C496_LOG; + + +void +sis_85c496_log(const char *fmt, ...) +{ + va_list ap; + + if (sis_85c496_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sis_85c496_log(fmt, ...) +#endif + + static void -sis_85c497_write(uint16_t port, uint8_t val, void *priv) +sis_85c497_isa_write(uint16_t port, uint8_t val, void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; - uint8_t index = (port & 1) ? 0 : 1; - if (index) { - if ((val != 0x01) || ((val >= 0x70) && (val <= 0x76))) - dev->cur_reg = val; - } else { - if (((dev->cur_reg < 0x70) && (dev->cur_reg != 0x01)) || (dev->cur_reg > 0x76)) - return; - dev->regs[dev->cur_reg] = val; - dev->cur_reg = 0; + sis_85c496_log("[%04X:%08X] ISA Write %02X to %04X\n", CS, cpu_state.pc, val, port); + + if (port == 0x22) + dev->cur_reg = val; + else if (port == 0x23) switch (dev->cur_reg) { + case 0x01: /* Built-in 206 Timing Control */ + dev->regs[dev->cur_reg] = val; + break; + case 0x70: /* ISA Bus Clock Selection */ + dev->regs[dev->cur_reg] = val & 0xc0; + break; + case 0x71: /* ISA Bus Timing Control */ + dev->regs[dev->cur_reg] = val & 0xf6; + break; + case 0x72: case 0x76: /* SMOUT */ + case 0x74: /* BIOS Timer */ + dev->regs[dev->cur_reg] = val; + break; + case 0x73: /* BIOS Timer */ + dev->regs[dev->cur_reg] = val & 0xfd; + break; + case 0x75: /* DMA / Deturbo Control */ + dev->regs[dev->cur_reg] = val & 0xfc; + dma_set_mask((val & 0x80) ? 0xffffffff : 0x00ffffff); + break; } } static uint8_t -sis_85c497_read(uint16_t port, void *priv) +sis_85c497_isa_read(uint16_t port, void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; - uint8_t index = (port & 1) ? 0 : 1; uint8_t ret = 0xff; - if (index) - ret = dev->cur_reg; - else { - if ((dev->cur_reg != 0x01) || ((dev->cur_reg >= 0x70) && (dev->cur_reg <= 0x76))) { - ret = dev->regs[dev->cur_reg]; - dev->cur_reg = 0; - } - } + if (port == 0x23) + ret = dev->regs[dev->cur_reg]; + else if (port == 0x33) + ret = 0x3c /*random_generate()*/; + + sis_85c496_log("[%04X:%08X] ISA Read %02X from %04X\n", CS, cpu_state.pc, ret, port); return ret; } @@ -100,170 +139,373 @@ sis_85c496_recalcmapping(sis_85c496_t *dev) shadowbios_write |= (base >= 0xe0000) && !(dev->pci_conf[0x45] & 0x01); shflags = (dev->pci_conf[0x45] & 0x02) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; shflags |= (dev->pci_conf[0x45] & 0x01) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; - mem_set_mem_state(base, 0x8000, shflags); + mem_set_mem_state_both(base, 0x8000, shflags); } else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state_both(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } - flushmmucache(); + flushmmucache_nopc(); +} + + +static void +sis_85c496_ide_handler(sis_85c496_t *dev) +{ + uint8_t ide_cfg[2]; + + ide_cfg[0] = dev->pci_conf[0x58]; + ide_cfg[1] = dev->pci_conf[0x59]; + + ide_pri_disable(); + ide_sec_disable(); + + if (ide_cfg[1] & 0x02) { + ide_set_base(0, 0x0170); + ide_set_side(0, 0x0376); + ide_set_base(1, 0x01f0); + ide_set_side(1, 0x03f6); + + if (ide_cfg[1] & 0x01) { + if (!(ide_cfg[0] & 0x40)) + ide_pri_enable(); + if (!(ide_cfg[0] & 0x80)) + ide_sec_enable(); + } + } else { + ide_set_base(0, 0x01f0); + ide_set_side(0, 0x03f6); + ide_set_base(1, 0x0170); + ide_set_side(1, 0x0376); + + if (ide_cfg[1] & 0x01) { + if (!(ide_cfg[0] & 0x40)) + ide_sec_enable(); + if (!(ide_cfg[0] & 0x80)) + ide_pri_enable(); + } + } } /* 00 - 3F = PCI Configuration, 40 - 7F = 85C496, 80 - FF = 85C497 */ static void -sis_85c496_write(int func, int addr, uint8_t val, void *priv) +sis_85c49x_pci_write(int func, int addr, uint8_t val, void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; - uint8_t old = dev->pci_conf[addr]; - uint8_t valxor; + uint8_t old, valxor; + uint8_t smm_irq[4] = { 10, 11, 12, 15 }; + uint32_t host_base, ram_base, size; - if ((addr >= 4 && addr < 8) || addr >= 0x40) - dev->pci_conf[addr] = val; + old = dev->pci_conf[addr]; + valxor = (dev->pci_conf[addr]) ^ val; - valxor = old ^ val; + sis_85c496_log("[%04X:%08X] PCI Write %02X to %02X:%02X\n", CS, cpu_state.pc, val, func, addr); switch (addr) { - case 0x42: /*Cache configure*/ + /* PCI Configuration Header Registers (00h ~ 3Fh) */ + case 0x04: /* PCI Device Command */ + dev->pci_conf[addr] = val & 0x40; + break; + case 0x05: /* PCI Device Command */ + dev->pci_conf[addr] = val & 0x03; + break; + case 0x07: /* Device Status */ + dev->pci_conf[addr] &= ~(val & 0xf1); + break; + + /* 86C496 Specific Registers (40h ~ 7Fh) */ + case 0x40: /* CPU Configuration */ + dev->pci_conf[addr] = val & 0x7f; + break; + case 0x41: /* DRAM Configuration */ + dev->pci_conf[addr] = val; + break; + case 0x42: /* Cache Configure */ + dev->pci_conf[addr] = val; cpu_cache_ext_enabled = (val & 0x01); cpu_update_waitstates(); break; - - case 0x44: /*Shadow configure*/ - if (valxor & 0xff) - sis_85c496_recalcmapping(dev); + case 0x43: /* Cache Configure */ + dev->pci_conf[addr] = val & 0x8f; break; - case 0x45: /*Shadow configure*/ + case 0x44: /* Shadow Configure */ + dev->pci_conf[addr] = val; + if (valxor & 0xff) { + sis_85c496_recalcmapping(dev); + if (((old & 0xf0) == 0xf0) && ((val & 0xf0) == 0x30)) + flushmmucache_nopc(); + else if (((old & 0xf0) == 0xf0) && ((val & 0xf0) == 0x00)) + flushmmucache_nopc(); + else + flushmmucache(); + } + break; + case 0x45: /* Shadow Configure */ + dev->pci_conf[addr] = val & 0x0f; if (valxor & 0x03) sis_85c496_recalcmapping(dev); break; - - case 0x56: + case 0x46: /* Cacheable Control */ + dev->pci_conf[addr] = val; + break; + case 0x47: /* 85C496 Address Decoder */ + dev->pci_conf[addr] = val & 0x1f; + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: /* DRAM Boundary */ + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + // dev->pci_conf[addr] = val; + spd_write_drbs(dev->pci_conf, 0x48, 0x4f, 1); + break; + case 0x50: case 0x51: /* Exclusive Area 0 Setup */ + dev->pci_conf[addr] = val; + break; + case 0x52: case 0x53: /* Exclusive Area 1 Setup */ + dev->pci_conf[addr] = val; + break; + case 0x54: /* Exclusive Area 2 Setup */ + dev->pci_conf[addr] = val; + break; + case 0x55: /* Exclusive Area 3 Setup */ + dev->pci_conf[addr] = val & 0xf0; + break; + case 0x56: /* PCI / Keyboard Configure */ + dev->pci_conf[addr] = val; if (valxor & 0x02) { port_92_remove(dev->port_92); if (val & 0x02) port_92_add(dev->port_92); } break; + case 0x57: /* Output Pin Configuration */ + dev->pci_conf[addr] = val; + break; + case 0x58: /* Build-in IDE Controller / VESA Bus Configuration */ + dev->pci_conf[addr] = val & 0xd7; + if (valxor & 0xc0) + sis_85c496_ide_handler(dev); + break; + case 0x59: /* Build-in IDE Controller / VESA Bus Configuration */ + dev->pci_conf[addr] = val; + if (valxor & 0x03) + sis_85c496_ide_handler(dev); + break; + case 0x5a: /* SMRAM Remapping Configuration */ + dev->pci_conf[addr] = val & 0xbe; + if (valxor & 0x3e) { + unmask_a20_in_smm = !!(val & 0x20); + + smram_disable_all(); - case 0x59: - if (valxor & 0x02) { if (val & 0x02) { - ide_set_base(0, 0x0170); - ide_set_side(0, 0x0376); - ide_set_base(1, 0x01f0); - ide_set_side(1, 0x03f6); - } else { - ide_set_base(0, 0x01f0); - ide_set_side(0, 0x03f6); - ide_set_base(1, 0x0170); - ide_set_side(1, 0x0376); + host_base = 0x00060000; + ram_base = 0x000a0000; + size = 0x00010000; + switch ((val >> 3) & 0x03) { + case 0x00: + host_base = 0x00060000; + ram_base = 0x000a0000; + break; + case 0x01: + host_base = 0x00060000; + ram_base = 0x000b0000; + break; + case 0x02: + host_base = 0x000e0000; + ram_base = 0x000a0000; + break; + case 0x03: + host_base = 0x000e0000; + ram_base = 0x000b0000; + break; + } + + smram_enable(dev->smram, host_base, ram_base, size, + ((val & 0x06) == 0x06), (val & 0x02)); } } break; - - case 0x58: - if (valxor & 0x80) { - if (dev->pci_conf[0x59] & 0x02) { - ide_sec_disable(); - if (val & 0x80) - ide_sec_enable(); - } else { - ide_pri_disable(); - if (val & 0x80) - ide_pri_enable(); - } - } - if (valxor & 0x40) { - if (dev->pci_conf[0x59] & 0x02) { - ide_pri_disable(); - if (val & 0x40) - ide_pri_enable(); - } else { - ide_sec_disable(); - if (val & 0x40) - ide_sec_enable(); - } - } + case 0x5b: /* Programmable I/O Traps Configure */ + case 0x5c: case 0x5d: /* Programmable I/O Trap 0 Base */ + case 0x5e: case 0x5f: /* Programmable I/O Trap 0 Base */ + case 0x60: case 0x61: /* IDE Controller Channel 0 Configuration */ + case 0x62: case 0x63: /* IDE Controller Channel 1 Configuration */ + case 0x64: case 0x65: /* Exclusive Area 3 Setup */ + case 0x66: /* EDO DRAM Configuration */ + case 0x68: case 0x69: /* Asymmetry DRAM Configuration */ + dev->pci_conf[addr] = val; break; - - case 0x5a: - if (valxor & 0x04) { - if (val & 0x04) - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - else - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - } - break; - - case 0x67: + case 0x67: /* Miscellaneous Control */ + dev->pci_conf[addr] = val & 0xf9; if (valxor & 0x60) port_92_set_features(dev->port_92, !!(val & 0x20), !!(val & 0x40)); break; - case 0x82: - sis_85c497_write(0x22, val, priv); + /* 86C497 Specific Registers (80h ~ FFh) */ + case 0x80: /* PMU Configuration */ + case 0x85: /* STPCLK# Event Control */ + case 0x86: case 0x87: /* STPCLK# Deassertion IRQ Selection */ + case 0x89: /* Fast Timer Count */ + case 0x8a: /* Generic Timer Count */ + case 0x8b: /* Slow Timer Count */ + case 0x8e: /* Clock Throttling On Timer Count */ + case 0x8f: /* Clock Throttling Off Timer Count */ + case 0x90: /* Clock Throttling On Timer Reload Condition */ + case 0x92: /* Fast Timer Reload Condition */ + case 0x94: /* Generic Timer Reload Condition */ + case 0x96: /* Slow Timer Reload Condition */ + case 0x98: case 0x99: /* Fast Timer Reload IRQ Selection */ + case 0x9a: case 0x9b: /* Generic Timer Reload IRQ Selection */ + case 0x9c: case 0x9d: /* Slow Timer Reload IRQ Selection */ + case 0xa2: /* SMI Request Status Selection */ + case 0xa4: case 0xa5: /* SMI Request IRQ Selection */ + case 0xa6: case 0xa7: /* Clock Throttlign On Timer Reload IRQ Selection */ + case 0xa8: /* GPIO Control */ + case 0xaa: /* GPIO DeBounce Count */ + case 0xd2: /* Exclusive Area 2 Base Address */ + dev->pci_conf[addr] = val; break; - - case 0xc0: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, val & 0xf); - else - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + case 0x81: /* PMU CPU Type Configuration */ + dev->pci_conf[addr] = val & 0x9f; break; - case 0xc1: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, val & 0xf); - else - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + case 0x88: /* Timer Control */ + dev->pci_conf[addr] = val & 0x3f; break; - case 0xc2: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, val & 0xf); - else - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + case 0x8d: /* RMSMIBLK Timer Count */ + dev->pci_conf[addr] = val; + dev->rmsmiblk_count = val; + timer_stop(&dev->rmsmiblk_timer); + if (val >= 0x02) + timer_on_auto(&dev->rmsmiblk_timer, 35.0); break; - case 0xc3: + case 0x91: /* Clock Throttling On Timer Reload Condition */ + case 0x93: /* Fast Timer Reload Condition */ + case 0x95: /* Generic Timer Reload Condition */ + dev->pci_conf[addr] = val & 0x03; + break; + case 0x97: /* Slow Timer Reload Condition */ + dev->pci_conf[addr] = val & 0xc3; + break; + case 0x9e: /* Soft-SMI Generation / RMSMIBLK Trigger */ + if (!smi_block && (val & 0x01) && (dev->pci_conf[0x80] & 0x80) && (dev->pci_conf[0xa2] & 0x10)) { + if (dev->pci_conf[0x80] & 0x10) + picint(1 << smm_irq[dev->pci_conf[0x81] & 0x03]); + else + smi_raise(); + smi_block = 1; + dev->pci_conf[0xa0] |= 0x10; + } + if (val & 0x02) { + timer_stop(&dev->rmsmiblk_timer); + if (dev->rmsmiblk_count >= 0x02) + timer_on_auto(&dev->rmsmiblk_timer, 35.0); + } + break; + case 0xa0: case 0xa1: /* SMI Request Status */ + dev->pci_conf[addr] &= ~val; + break; + case 0xa3: /* SMI Request Status Selection */ + dev->pci_conf[addr] = val & 0x7f; + break; + case 0xa9: /* GPIO SMI Request Status */ + dev->pci_conf[addr] = ~(val & 0x03); + break; + case 0xc0: /* PCI INTA# -to-IRQ Link */ + case 0xc1: /* PCI INTB# -to-IRQ Link */ + case 0xc2: /* PCI INTC# -to-IRQ Link */ + case 0xc3: /* PCI INTD# -to-IRQ Link */ + dev->pci_conf[addr] = val & 0x8f; if (val & 0x80) - pci_set_irq_routing(PCI_INTD, val & 0xf); + pci_set_irq_routing(PCI_INTA + (addr & 0x03), val & 0xf); else - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTA + (addr & 0x03), PCI_IRQ_DISABLED); + break; + case 0xc6: /* 85C497 Post / INIT Configuration */ + dev->pci_conf[addr] = val & 0x0f; + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: /* Mail Box */ + dev->pci_conf[addr] = val; + break; + case 0xd0: /* ISA BIOS Configuration */ + dev->pci_conf[addr] = val & 0xfb; + break; + case 0xd1: /* ISA Address Decoder */ + if (dev->pci_conf[0xd0] & 0x01) + dev->pci_conf[addr] = val; + break; + case 0xd3: /* Exclusive Area 2 Base Address */ + dev->pci_conf[addr] = val & 0xf0; + break; + case 0xd4: /* Miscellaneous Configuration */ + dev->pci_conf[addr] = val & 0x6e; + nvr_bank_set(0, !!(val & 0x40), dev->nvr); break; } } static uint8_t -sis_85c496_read(int func, int addr, void *priv) +sis_85c49x_pci_read(int func, int addr, void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; uint8_t ret = dev->pci_conf[addr]; switch (addr) { - case 0x82: /*Port 22h Mirror*/ - ret = inb(0x22); + case 0xa0: + ret &= 0x10; break; - case 0x70: /*Port 70h Mirror*/ + case 0xa1: + ret = 0x00; + break; + case 0x82: /*Port 22h Mirror*/ + ret = dev->cur_reg; + break; + case 0x83: /*Port 70h Mirror*/ ret = inb(0x70); break; } + sis_85c496_log("[%04X:%08X] PCI Read %02X from %02X:%02X\n", CS, cpu_state.pc, ret, func, addr); + return ret; } - + static void -sis_85c497_reset(sis_85c496_t *dev) +sis_85c496_rmsmiblk_count(void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + + dev->rmsmiblk_count--; + + if (dev->rmsmiblk_count == 1) { + smi_block = 0; + dev->rmsmiblk_count = 0; + timer_stop(&dev->rmsmiblk_timer); + } else + timer_on_auto(&dev->rmsmiblk_timer, 35.0); +} + + +static void +sis_85c497_isa_reset(sis_85c496_t *dev) { memset(dev->regs, 0, sizeof(dev->regs)); dev->regs[0x01] = 0xc0; dev->regs[0x71] = 0x01; dev->regs[0x72] = 0xff; + dev->regs[0x76] = 0xff; + + dma_set_mask(0x00ffffff); io_removehandler(0x0022, 0x0002, - sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); + sis_85c497_isa_read, NULL, NULL, sis_85c497_isa_write, NULL, NULL, dev); + io_removehandler(0x0033, 0x0001, + sis_85c497_isa_read, NULL, NULL, sis_85c497_isa_write, NULL, NULL, dev); io_sethandler(0x0022, 0x0002, - sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); + sis_85c497_isa_read, NULL, NULL, sis_85c497_isa_write, NULL, NULL, dev); + io_sethandler(0x0033, 0x0001, + sis_85c497_isa_read, NULL, NULL, sis_85c497_isa_write, NULL, NULL, dev); } @@ -271,17 +513,55 @@ static void sis_85c496_reset(void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; + int i; - sis_85c497_reset(dev); + sis_85c49x_pci_write(0, 0x44, 0x00, dev); + sis_85c49x_pci_write(0, 0x45, 0x00, dev); + sis_85c49x_pci_write(0, 0x58, 0x00, dev); + sis_85c49x_pci_write(0, 0x59, 0x00, dev); + sis_85c49x_pci_write(0, 0x5a, 0x00, dev); + // sis_85c49x_pci_write(0, 0x5a, 0x06, dev); + + for (i = 0; i < 8; i++) + sis_85c49x_pci_write(0, 0x48 + i, 0x00, dev); + + sis_85c49x_pci_write(0, 0x80, 0x00, dev); + sis_85c49x_pci_write(0, 0x81, 0x00, dev); + sis_85c49x_pci_write(0, 0x9e, 0x00, dev); + sis_85c49x_pci_write(0, 0x8d, 0x00, dev); + sis_85c49x_pci_write(0, 0xa0, 0xff, dev); + sis_85c49x_pci_write(0, 0xa1, 0xff, dev); + sis_85c49x_pci_write(0, 0xc0, 0x00, dev); + sis_85c49x_pci_write(0, 0xc1, 0x00, dev); + sis_85c49x_pci_write(0, 0xc2, 0x00, dev); + sis_85c49x_pci_write(0, 0xc3, 0x00, dev); + sis_85c49x_pci_write(0, 0xc8, 0x00, dev); + sis_85c49x_pci_write(0, 0xc9, 0x00, dev); + sis_85c49x_pci_write(0, 0xca, 0x00, dev); + sis_85c49x_pci_write(0, 0xcb, 0x00, dev); + + sis_85c49x_pci_write(0, 0xd0, 0x79, dev); + sis_85c49x_pci_write(0, 0xd1, 0xff, dev); + sis_85c49x_pci_write(0, 0xd0, 0x78, dev); + sis_85c49x_pci_write(0, 0xd4, 0x00, dev); + + ide_pri_disable(); + ide_sec_disable(); + + nvr_bank_set(0, 0, dev->nvr); + + sis_85c497_isa_reset(dev); } static void sis_85c496_close(void *p) { - sis_85c496_t *sis_85c496 = (sis_85c496_t *)p; + sis_85c496_t *dev = (sis_85c496_t *)p; - free(sis_85c496); + smram_del(dev->smram); + + free(dev); } @@ -289,33 +569,31 @@ static void *sis_85c496_init(const device_t *info) { sis_85c496_t *dev = malloc(sizeof(sis_85c496_t)); - memset(dev, 0, sizeof(sis_85c496_t)); + memset(dev, 0x00, sizeof(sis_85c496_t)); - dev->pci_conf[0x00] = 0x39; /*SiS*/ - dev->pci_conf[0x01] = 0x10; - dev->pci_conf[0x02] = 0x96; /*496/497*/ - dev->pci_conf[0x03] = 0x04; - - dev->pci_conf[0x04] = 7; - dev->pci_conf[0x05] = 0; + dev->smram = smram_add(); + /* PCI Configuration Header Registers (00h ~ 3Fh) */ + dev->pci_conf[0x00] = 0x39; /* SiS */ + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x96; /* 496/497 */ + dev->pci_conf[0x03] = 0x04; + dev->pci_conf[0x04] = 0x07; dev->pci_conf[0x06] = 0x80; dev->pci_conf[0x07] = 0x02; - - dev->pci_conf[0x08] = 2; /*Device revision*/ - - dev->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x08] = 0x02; /* Device revision */ + dev->pci_conf[0x09] = 0x00; /* Device class (PCI bridge) */ dev->pci_conf[0x0b] = 0x06; - dev->pci_conf[0x0e] = 0x00; /*Single function device*/ + /* 86C496 Specific Registers (40h ~ 7Fh) */ + /* 86C497 Specific Registers (80h ~ FFh) */ dev->pci_conf[0xd0] = 0x78; /* ROM at E0000-FFFFF, Flash enable. */ dev->pci_conf[0xd1] = 0xff; - pci_add_card(PCI_ADD_NORTHBRIDGE, sis_85c496_read, sis_85c496_write, dev); + pci_add_card(PCI_ADD_NORTHBRIDGE, sis_85c49x_pci_read, sis_85c49x_pci_write, dev); - sis_85c497_reset(dev); + // sis_85c497_isa_reset(dev); dev->port_92 = device_add(&port_92_device); port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); @@ -323,20 +601,47 @@ static void sis_85c496_recalcmapping(dev); + ide_pri_disable(); + ide_sec_disable(); + + if (info->local) + dev->nvr = device_add(&ami_1994_nvr_device); + else + dev->nvr = device_add(&at_nvr_device); + + dma_high_page_init(); + + timer_add(&dev->rmsmiblk_timer, sis_85c496_rmsmiblk_count, dev, 0); + + sis_85c496_reset(dev); + return dev; } - -const device_t sis_85c496_device = -{ - "SiS 85c496/85c497", - DEVICE_PCI, - 0, - sis_85c496_init, - sis_85c496_close, - sis_85c496_reset, - NULL, - NULL, - NULL, - NULL +const device_t sis_85c496_device = { + .name = "SiS 85c496/85c497", + .internal_name = "sis_85c496", + .flags = DEVICE_PCI, + .local = 0, + .init = sis_85c496_init, + .close = sis_85c496_close, + .reset = sis_85c496_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sis_85c496_ls486e_device = { + .name = "SiS 85c496/85c497 (Lucky Star LS-486E)", + .internal_name = "sis_85c496_ls486e", + .flags = DEVICE_PCI, + .local = 1, + .init = sis_85c496_init, + .close = sis_85c496_close, + .reset = sis_85c496_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c new file mode 100644 index 000000000..508f653e2 --- /dev/null +++ b/src/chipset/sis_85c4xx.c @@ -0,0 +1,416 @@ +/* + * 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 the SiS 85c401/85c402, 85c460, 85c461, and + * 85c407/85c471 chipsets. + * + * Authors: Miran Grca, + * + * Copyright 2019,2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/port_92.h> +#include <86box/mem.h> +#include <86box/smram.h> +#include <86box/pic.h> +#include <86box/machine.h> +#include <86box/chipset.h> + + +typedef struct +{ + uint8_t cur_reg, tries, + reg_base, reg_last, + reg_00, is_471, + regs[39], scratch[2]; + uint32_t mem_state[8]; + smram_t *smram; + port_92_t *port_92; +} sis_85c4xx_t; + + +static void +sis_85c4xx_recalcmapping(sis_85c4xx_t *dev) +{ + uint32_t base, n = 0; + uint32_t i, shflags = 0; + uint32_t readext, writeext; + uint8_t romcs = 0xc0, cur_romcs; + + shadowbios = 0; + shadowbios_write = 0; + + if (dev->regs[0x03] & 0x40) + romcs |= 0x01; + if (dev->regs[0x03] & 0x80) + romcs |= 0x30; + if (dev->regs[0x08] & 0x04) + romcs |= 0x02; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + cur_romcs = romcs & (1 << i); + readext = cur_romcs ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + writeext = cur_romcs ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + + if ((i > 5) || (dev->regs[0x02] & (1 << i))) { + shadowbios |= (base >= 0xe0000) && (dev->regs[0x02] & 0x80); + shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40); + shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : readext; + shflags |= (dev->regs[0x02] & 0x40) ? writeext : MEM_WRITE_INTERNAL; + if (dev->mem_state[i] != shflags) { + n++; + mem_set_mem_state(base, 0x8000, shflags); + if ((base >= 0xf0000) && (dev->mem_state[i] & MEM_READ_INTERNAL) && !(shflags & MEM_READ_INTERNAL)) + mem_invalidate_range(base, base + 0x7fff); + dev->mem_state[i] = shflags; + } + } else { + shflags = readext | writeext; + if (dev->mem_state[i] != shflags) { + n++; + mem_set_mem_state(base, 0x8000, shflags); + dev->mem_state[i] = shflags; + } + } + } + + if (n > 0) + flushmmucache_nopc(); +} + + +static void +sis_85c4xx_sw_smi_out(uint16_t port, uint8_t val, void *priv) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; + + if (dev->regs[0x18] & 0x02) { + if (dev->regs[0x0b] & 0x10) + smi_raise(); + else + picint(1 << ((dev->regs[0x0b] & 0x08) ? 15 : 12)); + soft_reset_mask = 1; + dev->regs[0x19] |= 0x02; + } +} + + +static void +sis_85c4xx_sw_smi_handler(sis_85c4xx_t *dev) +{ + uint16_t addr; + + if (!dev->is_471) + return; + + addr = dev->regs[0x14] | (dev->regs[0x15] << 8); + + io_handler((dev->regs[0x0b] & 0x80) && (dev->regs[0x18] & 0x02), addr, 0x0001, + NULL, NULL, NULL, sis_85c4xx_sw_smi_out, NULL, NULL, dev); +} + + +static void +sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; + uint8_t rel_reg = dev->cur_reg - dev->reg_base; + uint8_t valxor = 0x00; + uint32_t host_base = 0x000e0000, ram_base = 0x000a0000; + + switch (port) { + case 0x22: + dev->cur_reg = val; + break; + case 0x23: + if ((dev->cur_reg >= dev->reg_base) && (dev->cur_reg <= dev->reg_last)) { + valxor = val ^ dev->regs[rel_reg]; + if (rel_reg == 0x19) + dev->regs[rel_reg] &= ~val; + else + dev->regs[rel_reg] = val; + + switch (rel_reg) { + case 0x01: + cpu_cache_ext_enabled = ((val & 0x84) == 0x84); + cpu_update_waitstates(); + break; + + case 0x02: case 0x03: + case 0x08: + if (valxor) + sis_85c4xx_recalcmapping(dev); + break; + + case 0x0b: + sis_85c4xx_sw_smi_handler(dev); + if (dev->is_471 && (valxor & 0x02)) { + if (val & 0x02) + mem_remap_top(0); + else + mem_remap_top(256); + } + break; + + case 0x13: + if (dev->is_471 && (valxor & 0xf0)) { + smram_disable(dev->smram); + host_base = (val & 0x80) ? 0x00060000 : 0x000e0000; + switch ((val >> 5) & 0x03) { + case 0x00: + ram_base = 0x000a0000; + break; + case 0x01: + ram_base = 0x000b0000; + break; + case 0x02: + ram_base = (val & 0x80) ? 0x00000000 : 0x000e0000; + break; + default: + ram_base = 0x00000000; + break; + } + if (ram_base != 0x00000000) + smram_enable(dev->smram, host_base, ram_base, 0x00010000, (val & 0x10), 1); + } + break; + + case 0x14: case 0x15: + case 0x18: + sis_85c4xx_sw_smi_handler(dev); + break; + + case 0x1c: + if (dev->is_471) + soft_reset_mask = 0; + break; + + case 0x22: + if (dev->is_471 && (valxor & 0x01)) { + port_92_remove(dev->port_92); + if (val & 0x01) + port_92_add(dev->port_92); + } + break; + } + } else if ((dev->reg_base == 0x60) && (dev->cur_reg == 0x00)) + dev->reg_00 = val; + dev->cur_reg = 0x00; + break; + + case 0xe1: case 0xe2: + dev->scratch[port - 0xe1] = val; + return; + } +} + + +static uint8_t +sis_85c4xx_in(uint16_t port, void *priv) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; + uint8_t rel_reg = dev->cur_reg - dev->reg_base; + uint8_t ret = 0xff; + + switch (port) { + case 0x23: + if (dev->is_471 && (dev->cur_reg == 0x1c)) + ret = inb(0x70); + /* On the SiS 40x, the shadow RAM read and write enable bits are write-only! */ + if ((dev->reg_base == 0x60) && (dev->cur_reg == 0x62)) + ret = dev->regs[rel_reg] & 0x3f; + else if ((dev->cur_reg >= dev->reg_base) && (dev->cur_reg <= dev->reg_last)) + ret = dev->regs[rel_reg]; + else if ((dev->reg_base == 0x60) && (dev->cur_reg == 0x00)) + ret = dev->reg_00; + if (dev->reg_base != 0x60) + dev->cur_reg = 0x00; + break; + + case 0xe1: case 0xe2: + ret = dev->scratch[port - 0xe1]; + } + + return ret; +} + + +static void +sis_85c4xx_reset(void *priv) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; + int mem_size_mb = mem_size >> 10; + static uint8_t ram_4xx[64] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09, 0x04, 0x04, 0x05, 0x05, 0x0b, 0x0b, 0x0b, 0x0b, + 0x13, 0x21, 0x06, 0x06, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e }; + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + if (cpu_s->rspeed < 25000000) + dev->regs[0x08] = 0x80; + + if (dev->is_471) { + dev->regs[0x09] = 0x40; + if (mem_size_mb >= 64) { + if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[0x09] |= 0x22; + else + dev->regs[0x09] |= 0x24; + } else + dev->regs[0x09] |= ram_471[mem_size_mb]; + + dev->regs[0x11] = 0x09; + dev->regs[0x12] = 0xff; + dev->regs[0x1f] = 0x20; /* Video access enabled. */ + dev->regs[0x23] = 0xf0; + dev->regs[0x26] = 0x01; + + smram_enable(dev->smram, 0x000e0000, 0x000a0000, 0x00010000, 0, 1); + + port_92_remove(dev->port_92); + + mem_remap_top(256); + soft_reset_mask = 0; + } else { + /* Bits 6 and 7 must be clear on the SiS 40x. */ + if (dev->reg_base == 0x60) + dev->reg_00 = 0x24; + + if (mem_size_mb == 64) + dev->regs[0x00] = 0x1f; + else if (mem_size_mb < 64) + dev->regs[0x00] = ram_4xx[mem_size_mb]; + + dev->regs[0x11] = 0x01; + } + + dev->scratch[0] = dev->scratch[1] = 0xff; + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + sis_85c4xx_recalcmapping(dev); +} + + +static void +sis_85c4xx_close(void *priv) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; + + if (dev->is_471) + smram_del(dev->smram); + + free(dev); +} + + +static void * +sis_85c4xx_init(const device_t *info) +{ + sis_85c4xx_t *dev = (sis_85c4xx_t *) malloc(sizeof(sis_85c4xx_t)); + memset(dev, 0, sizeof(sis_85c4xx_t)); + + dev->is_471 = (info->local >> 8) & 0xff; + + dev->reg_base = info->local & 0xff; + + if (dev->is_471) { + dev->reg_last = dev->reg_base + 0x76; + + dev->smram = smram_add(); + + dev->port_92 = device_add(&port_92_device); + } else + dev->reg_last = dev->reg_base + 0x11; + + io_sethandler(0x0022, 0x0002, + sis_85c4xx_in, NULL, NULL, sis_85c4xx_out, NULL, NULL, dev); + + io_sethandler(0x00e1, 0x0002, + sis_85c4xx_in, NULL, NULL, sis_85c4xx_out, NULL, NULL, dev); + + sis_85c4xx_reset(dev); + + return dev; +} + +const device_t sis_85c401_device = { + .name = "SiS 85c401/85c402", + .internal_name = "sis_85c401", + .flags = 0, + .local = 0x060, + .init = sis_85c4xx_init, + .close = sis_85c4xx_close, + .reset = sis_85c4xx_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sis_85c460_device = { + .name = "SiS 85c460", + .internal_name = "sis_85c460", + .flags = 0, + .local = 0x050, + .init = sis_85c4xx_init, + .close = sis_85c4xx_close, + .reset = sis_85c4xx_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +/* TODO: Log to make sure the registers are correct. */ +const device_t sis_85c461_device = { + .name = "SiS 85c461", + .internal_name = "sis_85c461", + .flags = 0, + .local = 0x050, + .init = sis_85c4xx_init, + .close = sis_85c4xx_close, + .reset = sis_85c4xx_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sis_85c471_device = { + .name = "SiS 85c407/85c471", + .internal_name = "sis_85c471", + .flags = 0, + .local = 0x150, + .init = sis_85c4xx_init, + .close = sis_85c4xx_close, + .reset = sis_85c4xx_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c index d8ff68704..1c46074b1 100644 --- a/src/chipset/sis_85c50x.c +++ b/src/chipset/sis_85c50x.c @@ -6,405 +6,365 @@ * * This file is part of the 86Box distribution. * - * Implementation of the SiS 85c501/85c503 chip. + * Implementation of the SiS 85C50x Chipset. * * * - * Authors: Sarah Walker, + * Authors: Tiseno100, * Miran Grca, * - * Copyright 2019 Miran Grca. + * Copyright 2020,2021 Tiseno100. + * Copyright 2020,2021 Miran Grca. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> #include <86box/device.h> -#include <86box/keyboard.h> +#include <86box/io.h> +#include <86box/timer.h> + +#include <86box/apm.h> +#include <86box/mem.h> +#include <86box/smram.h> +#include <86box/pci.h> #include <86box/port_92.h> + #include <86box/chipset.h> -typedef struct sis_85c501_t +#ifdef ENABLE_SIS_85C50X_LOG +int sis_85c50x_do_log = ENABLE_SIS_85C50X_LOG; +static void +sis_85c50x_log(const char *fmt, ...) { - /* 85c501 */ - uint8_t turbo_reg; + va_list ap; - /* 85c503 */ + if (sis_85c50x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sis_85c50x_log(fmt, ...) +#endif - /* Registers */ - uint8_t pci_conf[2][256]; - /* 85c50x ISA */ - uint8_t cur_reg, - regs[39]; +typedef struct sis_85c50x_t +{ + uint8_t index, + pci_conf[256], pci_conf_sb[256], + regs[256]; + + smram_t * smram; + port_92_t * port_92; } sis_85c50x_t; static void -sis_85c501_recalcmapping(sis_85c50x_t *dev) +sis_85c50x_shadow_recalc(sis_85c50x_t *dev) { - int c, d; - uint32_t base; + uint32_t base, i, can_read, can_write; - for (c = 0; c < 1; c++) { - for (d = 0; d < 4; d++) { - base = 0xe0000 + (d << 14); - if (dev->pci_conf[0][0x54 + c] & (1 << (d + 4))) { - switch (dev->pci_conf[0][0x53] & 0x60) { - case 0x00: - mem_set_mem_state(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 0x20: - mem_set_mem_state(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 0x40: - mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 0x60: - mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - } - } else - mem_set_mem_state(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - } + can_read = (dev->pci_conf[0x53] & 0x40) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + can_write = (dev->pci_conf[0x53] & 0x20) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; + if (!can_read) + can_write = MEM_WRITE_EXTANY; + + mem_set_mem_state_both(0xf0000, 0x10000, can_read | can_write); + shadowbios = 1; + shadowbios_write = 1; + + for (i = 0; i < 4; i++) { + base = 0xe0000 + (i << 14); + mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x54] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + base = 0xd0000 + (i << 14); + mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x55] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + base = 0xc0000 + (i << 14); + mem_set_mem_state_both(base, 0x4000, (dev->pci_conf[0x56] & (1 << (7 - i))) ? (can_read | can_write) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); } - flushmmucache(); - shadowbios = 1; + flushmmucache_nopc(); } static void -sis_85c501_write(int func, int addr, uint8_t val, void *priv) +sis_85c50x_smm_recalc(sis_85c50x_t *dev) { - sis_85c50x_t *dev = (sis_85c50x_t *) priv; + /* NOTE: Naming mismatch - what the datasheet calls "host address" is what we call ram_base. */ + uint32_t ram_base = (dev->pci_conf[0x64] << 20) | + ((dev->pci_conf[0x65] & 0x07) << 28); - if (func) + smram_disable(dev->smram); + + if ((((dev->pci_conf[0x65] & 0xe0) >> 5) != 0x00) && (ram_base == 0x00000000)) return; - if ((addr >= 0x10) && (addr < 0x4f)) - return; + switch ((dev->pci_conf[0x65] & 0xe0) >> 5) { + case 0x00: + smram_enable(dev->smram, 0xe0000, 0xe0000, 0x8000, (dev->pci_conf[0x65] & 0x10), 1); + break; + case 0x01: + smram_enable(dev->smram, 0xb0000, ram_base, 0x10000, (dev->pci_conf[0x65] & 0x10), 1); + break; + case 0x02: + smram_enable(dev->smram, 0xa0000, ram_base, 0x10000, (dev->pci_conf[0x65] & 0x10), 1); + break; + case 0x04: + smram_enable(dev->smram, 0xa0000, ram_base, 0x8000, (dev->pci_conf[0x65] & 0x10), 1); + break; + case 0x06: + smram_enable(dev->smram, 0xb0000, ram_base, 0x8000, (dev->pci_conf[0x65] & 0x10), 1); + break; + } +} + + +static void +sis_85c50x_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + uint8_t valxor = (val ^ dev->pci_conf[addr]); switch (addr) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x42; - val |= 0x04; + case 0x04: /* Command - low byte */ + dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xb4) | (val & 0x4b); break; - case 0x05: - val &= 0x01; + case 0x07: /* Status - high byte */ + dev->pci_conf[addr] = ((dev->pci_conf[addr] & 0xf9) & ~(val & 0xf8)) | (val & 0x06); + break; + case 0x50: + dev->pci_conf[addr] = val; + break; + case 0x51: /* Cache */ + dev->pci_conf[addr] = val; + cpu_cache_ext_enabled = (val & 0x40); + cpu_update_waitstates(); + break; + case 0x52: + dev->pci_conf[addr] = val; + break; + case 0x53: /* Shadow RAM */ + case 0x54: + case 0x55: + case 0x56: + dev->pci_conf[addr] = val; + sis_85c50x_shadow_recalc(dev); + if (addr == 0x54) + sis_85c50x_smm_recalc(dev); + break; + case 0x57: case 0x58: case 0x59: case 0x5a: + case 0x5c: case 0x5d: case 0x5e: case 0x61: + case 0x62: case 0x63: case 0x67: case 0x68: + case 0x6a: case 0x6b: case 0x6c: case 0x6d: + case 0x6e: case 0x6f: + dev->pci_conf[addr] = val; + break; + case 0x5f: + dev->pci_conf[addr] = val & 0xfe; + break; + case 0x5b: + dev->pci_conf[addr] = val; + if (valxor & 0xc0) + port_92_set_features(dev->port_92, !!(val & 0x40), !!(val & 0x80)); + break; + case 0x60: /* SMI */ + if ((dev->pci_conf[0x68] & 0x01) && !(dev->pci_conf[addr] & 0x02) && (val & 0x02)) { + dev->pci_conf[0x69] |= 0x01; + smi_raise(); + } + dev->pci_conf[addr] = val & 0x3e; + break; + case 0x64: /* SMRAM */ + case 0x65: + dev->pci_conf[addr] = val; + sis_85c50x_smm_recalc(dev); + break; + case 0x66: + dev->pci_conf[addr] = (val & 0x7f); + break; + case 0x69: + dev->pci_conf[addr] &= ~(val); + break; + } + + sis_85c50x_log("85C501: dev->pci_conf[%02x] = %02x\n", addr, val); +} + + +static uint8_t +sis_85c50x_read(int func, int addr, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + + sis_85c50x_log("85C501: dev->pci_conf[%02x] (%02x)\n", addr, dev->pci_conf[addr]); + + return dev->pci_conf[addr]; +} + + +static void +sis_85c50x_sb_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + + switch (addr) { + case 0x04: /* Command */ + dev->pci_conf_sb[addr] = val & 0x0f; + break; + case 0x07: /* Status */ + dev->pci_conf_sb[addr] &= ~(val & 0x30); + break; + case 0x40: /* BIOS Control Register */ + dev->pci_conf_sb[addr] = val & 0x3f; + break; + case 0x41: case 0x42: case 0x43: case 0x44: + /* INTA/B/C/D# Remapping Control Register */ + dev->pci_conf_sb[addr] = val & 0x8f; + if (val & 0x80) + pci_set_irq_routing(PCI_INTA + (addr - 0x41), PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA + (addr - 0x41), val & 0xf); + break; + case 0x48: /* ISA Master/DMA Memory Cycle Control Register 1 */ + case 0x49: /* ISA Master/DMA Memory Cycle Control Register 2 */ + case 0x4a: /* ISA Master/DMA Memory Cycle Control Register 3 */ + case 0x4b: /* ISA Master/DMA Memory Cycle Control Register 4 */ + dev->pci_conf_sb[addr] = val; + break; + } + + sis_85c50x_log("85C503: dev->pci_conf_sb[%02x] = %02x\n", addr, val); +} + + +static uint8_t +sis_85c50x_sb_read(int func, int addr, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + sis_85c50x_log("85C503: dev->pci_conf_sb[%02x] (%02x)\n", addr, dev->pci_conf_sb[addr]); + + return dev->pci_conf_sb[addr]; +} + + +static void +sis_85c50x_isa_write(uint16_t addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + + switch (addr) { + case 0x22: + dev->index = val; break; - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x54: /*Shadow configure*/ - if ((dev->pci_conf[0][0x54] & val) ^ 0xf0) { - dev->pci_conf[0][0x54] = val; - sis_85c501_recalcmapping(dev); + case 0x23: + switch (dev->index) { + case 0x80: + dev->regs[dev->index] = val & 0xe7; + break; + case 0x81: + dev->regs[dev->index] = val & 0xf4; + break; + case 0x84: case 0x88: case 0x9: case 0x8a: + case 0x8b: + dev->regs[dev->index] = val; + break; + case 0x85: + outb(0x70, val); + break; } break; } - dev->pci_conf[0][addr] = val; + sis_85c50x_log("85C501-ISA: dev->regs[%02x] = %02x\n", addr, val); } -static void -sis_85c503_write(int func, int addr, uint8_t val, void *priv) +static uint8_t +sis_85c50x_isa_read(uint16_t addr, void *priv) { - sis_85c50x_t *dev = (sis_85c50x_t *) priv; + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + uint8_t ret = 0xff; - if (func > 0) - return; - - if (addr >= 0x0f && addr < 0x41) - return; - - switch(addr) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x08; - val |= 0x07; - break; - case 0x05: - val = 0; + switch (addr) { + case 0x22: + ret = dev->index; break; - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x41: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + case 0x23: + if (dev->index == 0x85) + ret = inb(0x70); else - pci_set_irq_routing(PCI_INTA, val & 0xf); - break; - case 0x42: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); - break; - case 0x43: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x44: - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); + ret = dev->regs[dev->index]; break; } - dev->pci_conf[1][addr] = val; -} + sis_85c50x_log("85C501-ISA: dev->regs[%02x] (%02x)\n", dev->index, ret); - -static void -sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv) -{ - sis_85c50x_t *dev = (sis_85c50x_t *) priv; - - if (port & 1) { - if (dev->cur_reg <= 0x1a) - dev->regs[dev->cur_reg] = val; - } else - dev->cur_reg = val; -} - - -static uint8_t -sis_85c501_read(int func, int addr, void *priv) -{ - sis_85c50x_t *dev = (sis_85c50x_t *) priv; - - if (func) - return 0xff; - - return dev->pci_conf[0][addr]; -} - - -static uint8_t -sis_85c503_read(int func, int addr, void *priv) -{ - sis_85c50x_t *dev = (sis_85c50x_t *) priv; - - if (func > 0) - return 0xff; - - return dev->pci_conf[1][addr]; -} - - -static uint8_t -sis_85c50x_isa_read(uint16_t port, void *priv) -{ - sis_85c50x_t *dev = (sis_85c50x_t *) priv; - - if (port & 1) { - if (dev->cur_reg <= 0x1a) - return dev->regs[dev->cur_reg]; - else - return 0xff; - } else - return dev->cur_reg; -} - - -static void -sis_85c50x_isa_reset(sis_85c50x_t *dev) -{ - int mem_size_mb, i = 0; - - memset(dev->regs, 0, sizeof(dev->regs)); - - dev->cur_reg = 0; - for (i = 0; i < 0x27; i++) - dev->regs[i] = 0x00; - - dev->regs[9] = 0x40; - - mem_size_mb = mem_size >> 10; - switch (mem_size_mb) { - case 0: case 1: - dev->regs[9] |= 0; - break; - case 2: case 3: - dev->regs[9] |= 1; - break; - case 4: - dev->regs[9] |= 2; - break; - case 5: - dev->regs[9] |= 0x20; - break; - case 6: case 7: - dev->regs[9] |= 9; - break; - case 8: case 9: - dev->regs[9] |= 4; - break; - case 10: case 11: - dev->regs[9] |= 5; - break; - case 12: case 13: case 14: case 15: - dev->regs[9] |= 0xB; - break; - case 16: - dev->regs[9] |= 0x13; - break; - case 17: - dev->regs[9] |= 0x21; - break; - case 18: case 19: - dev->regs[9] |= 6; - break; - case 20: case 21: case 22: case 23: - dev->regs[9] |= 0xD; - break; - case 24: case 25: case 26: case 27: - case 28: case 29: case 30: case 31: - dev->regs[9] |= 0xE; - break; - case 32: case 33: case 34: case 35: - dev->regs[9] |= 0x1B; - break; - case 36: case 37: case 38: case 39: - dev->regs[9] |= 0xF; - break; - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - dev->regs[9] |= 0x17; - break; - case 48: - dev->regs[9] |= 0x1E; - break; - default: - if (mem_size_mb < 64) - dev->regs[9] |= 0x1E; - else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) - dev->regs[9] |= 0x22; - else - dev->regs[9] |= 0x24; - break; - } - - dev->regs[0x11] = 9; - dev->regs[0x12] = 0xFF; - dev->regs[0x23] = 0xF0; - dev->regs[0x26] = 1; - - io_removehandler(0x22, 0x0002, - sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); - io_sethandler(0x22, 0x0002, - sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); + return ret; } static void sis_85c50x_reset(void *priv) { - sis_85c50x_t *dev = (sis_85c50x_t *) priv; + sis_85c50x_t *dev = (sis_85c50x_t *)priv; - uint8_t val = 0; + /* North Bridge (SiS 85C501/502) */ + dev->pci_conf[0x00] = 0x39; + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x06; + dev->pci_conf[0x03] = 0x04; + dev->pci_conf[0x04] = 0x04; + dev->pci_conf[0x07] = 0x04; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; - val = sis_85c501_read(0, 0x54, priv); /* Read current value of 0x44. */ - sis_85c501_write(0, 0x54, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ + sis_85c50x_write(0, 0x51, 0x00, dev); + sis_85c50x_write(0, 0x53, 0x00, dev); + sis_85c50x_write(0, 0x54, 0x00, dev); + sis_85c50x_write(0, 0x55, 0x00, dev); + sis_85c50x_write(0, 0x56, 0x00, dev); + sis_85c50x_write(0, 0x5b, 0x00, dev); + sis_85c50x_write(0, 0x60, 0x00, dev); + sis_85c50x_write(0, 0x64, 0x00, dev); + sis_85c50x_write(0, 0x65, 0x00, dev); + sis_85c50x_write(0, 0x68, 0x00, dev); + sis_85c50x_write(0, 0x69, 0xff, dev); - sis_85c50x_isa_reset(dev); -} - - -static void -sis_85c50x_setup(sis_85c50x_t *dev) -{ - memset(dev, 0, sizeof(sis_85c50x_t)); - - /* 85c501 */ - dev->pci_conf[0][0x00] = 0x39; /*SiS*/ - dev->pci_conf[0][0x01] = 0x10; - dev->pci_conf[0][0x02] = 0x06; /*501/502*/ - dev->pci_conf[0][0x03] = 0x04; - - dev->pci_conf[0][0x04] = 7; - dev->pci_conf[0][0x05] = 0; - - dev->pci_conf[0][0x06] = 0x80; - dev->pci_conf[0][0x07] = 0x02; - - dev->pci_conf[0][0x08] = 0; /*Device revision*/ - - dev->pci_conf[0][0x09] = 0x00; /*Device class (PCI bridge)*/ - dev->pci_conf[0][0x0a] = 0x00; - dev->pci_conf[0][0x0b] = 0x06; - - dev->pci_conf[0][0x0e] = 0x00; /*Single function device*/ - - dev->pci_conf[0][0x50] = 0xbc; - dev->pci_conf[0][0x51] = 0xfb; - dev->pci_conf[0][0x52] = 0xad; - dev->pci_conf[0][0x53] = 0xfe; - - shadowbios = 1; - - /* 85c503 */ - dev->pci_conf[1][0x00] = 0x39; /*SiS*/ - dev->pci_conf[1][0x01] = 0x10; - dev->pci_conf[1][0x02] = 0x08; /*503*/ - dev->pci_conf[1][0x03] = 0x00; - - dev->pci_conf[1][0x04] = 7; - dev->pci_conf[1][0x05] = 0; - - dev->pci_conf[1][0x06] = 0x80; - dev->pci_conf[1][0x07] = 0x02; - - dev->pci_conf[1][0x08] = 0; /*Device revision*/ - - dev->pci_conf[1][0x09] = 0x00; /*Device class (PCI bridge)*/ - dev->pci_conf[1][0x0a] = 0x01; - dev->pci_conf[1][0x0b] = 0x06; - - dev->pci_conf[1][0x0e] = 0x00; /*Single function device*/ - - dev->pci_conf[1][0x41] = dev->pci_conf[1][0x42] = - dev->pci_conf[1][0x43] = dev->pci_conf[1][0x44] = 0x80; + /* South Bridge (SiS 85C503) */ + dev->pci_conf_sb[0x00] = 0x39; + dev->pci_conf_sb[0x01] = 0x10; + dev->pci_conf_sb[0x02] = 0x08; + dev->pci_conf_sb[0x03] = 0x00; + dev->pci_conf_sb[0x04] = 0x07; + dev->pci_conf_sb[0x05] = 0x00; + dev->pci_conf_sb[0x06] = 0x00; + dev->pci_conf_sb[0x07] = 0x02; + dev->pci_conf_sb[0x08] = 0x00; + dev->pci_conf_sb[0x09] = 0x00; + dev->pci_conf_sb[0x0a] = 0x01; + dev->pci_conf_sb[0x0b] = 0x06; + sis_85c50x_write(0, 0x41, 0x80, dev); + sis_85c50x_write(0, 0x42, 0x80, dev); + sis_85c50x_write(0, 0x43, 0x80, dev); + sis_85c50x_write(0, 0x44, 0x80, dev); } static void sis_85c50x_close(void *priv) { - sis_85c50x_t *dev = (sis_85c50x_t *) priv; + sis_85c50x_t *dev = (sis_85c50x_t *)priv; + smram_del(dev->smram); free(dev); } @@ -412,30 +372,34 @@ sis_85c50x_close(void *priv) static void * sis_85c50x_init(const device_t *info) { - sis_85c50x_t *dev = (sis_85c50x_t *) malloc(sizeof(sis_85c50x_t)); + sis_85c50x_t *dev = (sis_85c50x_t *)malloc(sizeof(sis_85c50x_t)); + memset(dev, 0x00, sizeof(sis_85c50x_t)); - pci_add_card(0, sis_85c501_read, sis_85c501_write, dev); - pci_add_card(5, sis_85c503_read, sis_85c503_write, dev); + /* 501/502 (Northbridge) */ + pci_add_card(PCI_ADD_NORTHBRIDGE, sis_85c50x_read, sis_85c50x_write, dev); - sis_85c50x_setup(dev); - sis_85c50x_isa_reset(dev); + /* 503 (Southbridge) */ + pci_add_card(PCI_ADD_SOUTHBRIDGE, sis_85c50x_sb_read, sis_85c50x_sb_write, dev); + io_sethandler(0x0022, 0x0002, sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); - device_add(&port_92_pci_device); + dev->smram = smram_add(); + dev->port_92 = device_add(&port_92_device); + + sis_85c50x_reset(dev); return dev; } - -const device_t sis_85c50x_device = -{ - "SiS 85c501/85c503", - DEVICE_PCI, - 0, - sis_85c50x_init, - sis_85c50x_close, - sis_85c50x_reset, - NULL, - NULL, - NULL, - NULL +const device_t sis_85c50x_device = { + .name = "SiS 85C50x", + .internal_name = "sis_85c50x", + .flags = DEVICE_PCI, + .local = 0, + .init = sis_85c50x_init, + .close = sis_85c50x_close, + .reset = sis_85c50x_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c new file mode 100644 index 000000000..f9bd8faff --- /dev/null +++ b/src/chipset/stpc.c @@ -0,0 +1,1142 @@ +/* + * 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 STMicroelectronics STPC series of SoCs. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/smram.h> +#include <86box/io.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/device.h> +#include <86box/port_92.h> +#include <86box/usb.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/serial.h> +#include <86box/lpt.h> +#include <86box/chipset.h> + + +#define STPC_CONSUMER2 0x104a020b +#define STPC_ATLAS 0x104a0210 +#define STPC_ELITE 0x104a021a +#define STPC_CLIENT 0x100e55cc + + +typedef struct stpc_t +{ + uint32_t local; + + /* Main registers (port 22h/23h) */ + uint8_t reg_offset; + uint8_t regs[256]; + + /* Host bus interface */ + uint16_t host_base; + uint8_t host_offset; + uint8_t host_regs[256]; + + /* Local bus */ + uint16_t localbus_base; + uint8_t localbus_offset; + uint8_t localbus_regs[256]; + + /* PCI devices */ + uint8_t pci_conf[4][256]; + smram_t *smram; + usb_t *usb; + int ide_slot; + sff8038i_t *bm[2]; +} stpc_t; + +typedef struct stpc_serial_t +{ + serial_t *uart[2]; +} stpc_serial_t; + +typedef struct stpc_lpt_t +{ + uint8_t unlocked; + uint8_t offset; + uint8_t reg1; + uint8_t reg4; +} stpc_lpt_t; + + +#ifdef ENABLE_STPC_LOG +int stpc_do_log = ENABLE_STPC_LOG; + + +static void +stpc_log(const char *fmt, ...) +{ + va_list ap; + + if (stpc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define stpc_log(fmt, ...) +#endif + + +static void +stpc_recalcmapping(stpc_t *dev) +{ + uint8_t reg, bitpair; + uint32_t base, size; + int state; + + shadowbios = 0; + shadowbios_write = 0; + + for (reg = 0; reg <= 3; reg++) { + for (bitpair = 0; bitpair <= ((reg == 3) ? 0 : 3); bitpair++) { + if (reg == 3) { + size = 0x10000; + base = 0xf0000; + } else { + size = 0x4000; + base = 0xc0000 + (size * ((reg * 4) + bitpair)); + } + stpc_log("STPC: Shadowing for %05X-%05X (reg %02X bp %d wmask %02X rmask %02X) =", base, base + size - 1, 0x25 + reg, bitpair, 1 << (bitpair * 2), 1 << ((bitpair * 2) + 1)); + + state = 0; + if (dev->regs[0x25 + reg] & (1 << (bitpair * 2))) { + stpc_log(" w on"); + state |= MEM_WRITE_INTERNAL; + if (base >= 0xe0000) + shadowbios_write |= 1; + } else { + stpc_log(" w off"); + state |= MEM_WRITE_EXTANY; + } + if (dev->regs[0x25 + reg] & (1 << ((bitpair * 2) + 1))) { + stpc_log("; r on\n"); + state |= MEM_READ_INTERNAL; + if (base >= 0xe0000) + shadowbios |= 1; + } else { + stpc_log("; r off\n"); + state |= MEM_READ_EXTANY; + } + + mem_set_mem_state(base, size, state); + } + } + + flushmmucache_nopc(); +} + + +static void +stpc_host_write(uint16_t addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: host_write(%04X, %02X)\n", addr, val); + + if (addr == dev->host_base) + dev->host_offset = val; + else if (addr == (dev->host_base + 4)) + dev->host_regs[dev->host_offset] = val; +} + + +static uint8_t +stpc_host_read(uint16_t addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if (addr == dev->host_base) + ret = dev->host_offset; + else if (addr == (dev->host_base + 4)) + ret = dev->host_regs[dev->host_offset]; + else + ret = 0xff; + + stpc_log("STPC: host_read(%04X) = %02X\n", addr, ret); + return ret; +} + + +static void +stpc_localbus_write(uint16_t addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: localbus_write(%04X, %02X)\n", addr, val); + + if (addr == dev->localbus_base) + dev->localbus_offset = val; + else if (addr == (dev->localbus_base + 4)) + dev->localbus_regs[addr] = val; +} + + +static uint8_t +stpc_localbus_read(uint16_t addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if (addr == dev->localbus_base) + ret = dev->localbus_offset; + else if (addr == (dev->localbus_base + 4)) + ret = dev->localbus_regs[dev->localbus_offset]; + else + ret = 0xff; + + stpc_log("STPC: localbus_read(%04X) = %02X\n", addr, ret); + return ret; +} + + +static void +stpc_nb_write(int func, int addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: nb_write(%d, %02X, %02X)\n", func, addr, val); + + if (func > 0) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x06: case 0x07: case 0x08: + case 0x09: case 0x0a: case 0x0b: case 0x0e: + case 0x51: case 0x53: case 0x54: + return; + + case 0x05: + val &= 0x01; + break; + + case 0x50: + val &= 0x1f; + break; + + case 0x52: + val &= 0x70; + break; + } + + dev->pci_conf[0][addr] = val; +} + + +static uint8_t +stpc_nb_read(int func, int addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if (func > 0) + ret = 0xff; + else + ret = dev->pci_conf[0][addr]; + + stpc_log("STPC: nb_read(%d, %02X) = %02X\n", func, addr, ret); + return ret; +} + + +static void +stpc_ide_handlers(stpc_t *dev, int bus) +{ + uint16_t main, side; + + if (bus & 0x01) { + ide_pri_disable(); + + if (dev->pci_conf[2][0x09] & 0x01) { + main = (dev->pci_conf[2][0x11] << 8) | (dev->pci_conf[2][0x10] & 0xf8); + side = ((dev->pci_conf[2][0x15] << 8) | (dev->pci_conf[2][0x14] & 0xfc)) + 2; + } else { + main = 0x1f0; + side = 0x3f6; + } + + ide_set_base(0, main); + ide_set_side(0, side); + + stpc_log("STPC: IDE primary main %04X side %04X enable ", main, side); + if ((dev->pci_conf[2][0x04] & 0x01) && !(dev->pci_conf[2][0x48] & 0x04)) { + stpc_log("1\n"); + ide_pri_enable(); + } else { + stpc_log("0\n"); + } + } + + if (bus & 0x02) { + ide_sec_disable(); + + if (dev->pci_conf[2][0x09] & 0x04) { + main = (dev->pci_conf[2][0x19] << 8) | (dev->pci_conf[2][0x18] & 0xf8); + side = ((dev->pci_conf[2][0x1d] << 8) | (dev->pci_conf[2][0x1c] & 0xfc)) + 2; + } else { + main = 0x170; + side = 0x376; + } + + ide_set_base(1, main); + ide_set_side(1, side); + + stpc_log("STPC: IDE secondary main %04X side %04X enable ", main, side); + if ((dev->pci_conf[2][0x04] & 0x01) && !(dev->pci_conf[2][0x48] & 0x08)) { + stpc_log("1\n"); + ide_sec_enable(); + } else { + stpc_log("0\n"); + } + } +} + + +static void +stpc_ide_bm_handlers(stpc_t *dev) +{ + uint16_t base = (dev->pci_conf[2][0x20] & 0xf0) | (dev->pci_conf[2][0x21] << 8); + + sff_bus_master_handler(dev->bm[0], dev->pci_conf[2][0x04] & 1, base); + sff_bus_master_handler(dev->bm[1], dev->pci_conf[2][0x04] & 1, base + 8); +} + + +static void +stpc_ide_write(int func, int addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: ide_write(%d, %02X, %02X)\n", func, addr, val); + + if (func > 0) + return; + + switch (addr) { + case 0x04: + dev->pci_conf[2][addr] = (dev->pci_conf[2][addr] & 0xbe) | (val & 0x41); + stpc_ide_handlers(dev, 0x03); + stpc_ide_bm_handlers(dev); + break; + + case 0x05: + dev->pci_conf[2][addr] = val & 0x01; + break; + + case 0x07: + dev->pci_conf[2][addr] &= ~(val & 0x70); + break; + + case 0x09: + dev->pci_conf[2][addr] = (dev->pci_conf[2][addr] & 0x8a) | (val & 0x05); + stpc_ide_handlers(dev, 0x03); + break; + + case 0x10: + dev->pci_conf[2][addr] = (val & 0xf8) | 1; + stpc_ide_handlers(dev, 0x01); + break; + case 0x11: + dev->pci_conf[2][addr] = val; + stpc_ide_handlers(dev, 0x01); + break; + + case 0x14: + dev->pci_conf[2][addr] = (val & 0xfc) | 1; + stpc_ide_handlers(dev, 0x01); + break; + case 0x15: + dev->pci_conf[2][addr] = val; + stpc_ide_handlers(dev, 0x01); + break; + + case 0x18: + dev->pci_conf[2][addr] = (val & 0xf8) | 1; + stpc_ide_handlers(dev, 0x02); + break; + case 0x19: + dev->pci_conf[2][addr] = val; + stpc_ide_handlers(dev, 0x02); + break; + + case 0x1c: + dev->pci_conf[2][addr] = (val & 0xfc) | 1; + stpc_ide_handlers(dev, 0x02); + break; + case 0x1d: + dev->pci_conf[2][addr] = val; + stpc_ide_handlers(dev, 0x02); + break; + + case 0x20: + dev->pci_conf[2][0x20] = (val & 0xf0) | 1; + stpc_ide_bm_handlers(dev); + break; + case 0x21: + dev->pci_conf[2][0x21] = val; + stpc_ide_bm_handlers(dev); + break; + + case 0x3c: + dev->pci_conf[2][addr] = val; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + dev->pci_conf[2][addr] = val; + break; + + case 0x48: + dev->pci_conf[2][addr] = (val & 0x8c) & ~(val & 0x03); + stpc_ide_handlers(dev, 0x03); + if (val & 0x02) { + sff_bus_master_set_irq(0x01, dev->bm[0]); + sff_bus_master_set_irq(0x01, dev->bm[1]); + } + if (val & 0x01) { + sff_bus_master_set_irq(0x00, dev->bm[0]); + sff_bus_master_set_irq(0x00, dev->bm[1]); + } + break; + } +} + + +static uint8_t +stpc_ide_read(int func, int addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if (func > 0) + ret = 0xff; + else { + ret = dev->pci_conf[2][addr]; + if (addr == 0x48) { + ret &= 0xfc; + ret |= !!(dev->bm[0]->status & 0x04); + ret |= (!!(dev->bm[1]->status & 0x04)) << 1; + } + } + + stpc_log("STPC: ide_read(%d, %02X) = %02X\n", func, addr, ret); + return ret; +} + + +static void +stpc_isab_write(int func, int addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + if ((func == 1) && (dev->local != STPC_ATLAS)) { + stpc_ide_write(0, addr, val, priv); + return; + } + + stpc_log("STPC: isab_write(%d, %02X, %02X)\n", func, addr, val); + + if (func > 0) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x06: case 0x07: case 0x08: + case 0x09: case 0x0a: case 0x0b: case 0x0e: + return; + + case 0x05: + val &= 0x01; + break; + } + + dev->pci_conf[1][addr] = val; +} + + +static uint8_t +stpc_isab_read(int func, int addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if ((func == 1) && (dev->local != STPC_ATLAS)) + ret = stpc_ide_read(0, addr, priv); + else if (func > 0) + ret = 0xff; + else + ret = dev->pci_conf[1][addr]; + + stpc_log("STPC: isab_read(%d, %02X) = %02X\n", func, addr, ret); + return ret; +} + + +static void +stpc_usb_write(int func, int addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: usb_write(%d, %02X, %02X)\n", func, addr, val); + + if (func > 0) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x06: case 0x07: case 0x08: + case 0x09: case 0x0a: case 0x0b: case 0x0e: + case 0x10: + return; + + case 0x05: + val &= 0x01; + break; + + case 0x11: + dev->pci_conf[3][addr] = val & 0xf0; + ohci_update_mem_mapping(dev->usb, dev->pci_conf[3][0x11], dev->pci_conf[3][0x12], dev->pci_conf[3][0x13], 1); + break; + + case 0x12: case 0x13: + dev->pci_conf[3][addr] = val; + ohci_update_mem_mapping(dev->usb, dev->pci_conf[3][0x11], dev->pci_conf[3][0x12], dev->pci_conf[3][0x13], 1); + break; + } + + dev->pci_conf[3][addr] = val; +} + + +static uint8_t +stpc_usb_read(int func, int addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if (func > 0) + ret = 0xff; + else + ret = dev->pci_conf[3][addr]; + + stpc_log("STPC: usb_read(%d, %02X) = %02X\n", func, addr, ret); + return ret; +} + + +static void +stpc_remap_host(stpc_t *dev, uint16_t host_base) +{ + stpc_log("STPC: Remapping host bus from %04X to %04X\n", dev->host_base, host_base); + + io_removehandler(dev->host_base, 5, + stpc_host_read, NULL, NULL, stpc_host_write, NULL, NULL, dev); + if (host_base) { + io_sethandler(host_base, 5, + stpc_host_read, NULL, NULL, stpc_host_write, NULL, NULL, dev); + } + dev->host_base = host_base; +} + + +static void +stpc_remap_localbus(stpc_t *dev, uint16_t localbus_base) +{ + stpc_log("STPC: Remapping local bus from %04X to %04X\n", dev->localbus_base, localbus_base); + + io_removehandler(dev->localbus_base, 5, + stpc_localbus_read, NULL, NULL, stpc_localbus_write, NULL, NULL, dev); + if (localbus_base) { + io_sethandler(localbus_base, 5, + stpc_localbus_read, NULL, NULL, stpc_localbus_write, NULL, NULL, dev); + } + dev->localbus_base = localbus_base; +} + + +static uint8_t +stpc_serial_handlers(uint8_t val) +{ + stpc_serial_t *dev = device_get_priv(&stpc_serial_device); + if (!dev) { + stpc_log("STPC: Not remapping UARTs, disabled by strap (raw %02X)\n", val); + return 0; + } + + uint16_t uart0_io = 0x3f8, uart1_io = 0x3f8; + uint8_t uart0_irq = 4, uart1_irq = 3; + + if (val & 0x10) + uart1_io &= 0xfeff; + if (val & 0x20) + uart1_io &= 0xffef; + if (val & 0x40) + uart0_io &= 0xfeff; + if (val & 0x80) + uart0_io &= 0xffef; + + if (uart0_io == uart1_io) { + /* Apply defaults if both UARTs are set to the same address. */ + stpc_log("STPC: Both UARTs set to %02X, resetting to defaults\n", uart0_io); + uart0_io = 0x3f8; + uart1_io = 0x2f8; + } + + if (!(uart0_io & 0x100)) { + /* The address for UART0 establishes the IRQs for both ports. */ + uart0_irq = 3; + uart1_irq = 4; + } + + stpc_log("STPC: Remapping UART0 to %04X %d and UART1 to %04X %d (raw %02X)\n", uart0_io, uart0_irq, uart1_io, uart1_irq, val); + + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], uart0_io, uart0_irq); + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], uart1_io, uart1_irq); + + return 1; +} + + +static void +stpc_reg_write(uint16_t addr, uint8_t val, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: reg_write(%04X, %02X)\n", addr, val); + + if (addr == 0x22) { + dev->reg_offset = val; + } else { + stpc_log("STPC: regs[%02X] = %02X\n", dev->reg_offset, val); + + switch (dev->reg_offset) { + case 0x12: + if (dev->regs[0x10] == 0x07) + stpc_remap_host(dev, (dev->host_base & 0xff00) | val); + else if (dev->regs[0x10] == 0x06) + stpc_remap_localbus(dev, (dev->localbus_base & 0xff00) | val); + break; + + case 0x13: + if (dev->regs[0x10] == 0x07) + stpc_remap_host(dev, (dev->host_base & 0x00ff) | (val << 8)); + else if (dev->regs[0x10] == 0x06) + stpc_remap_localbus(dev, (dev->localbus_base & 0x00ff) | (val << 8)); + break; + + case 0x21: + val &= 0xfe; + break; + + case 0x22: + val &= 0x7f; + break; + + case 0x25: case 0x26: case 0x27: case 0x28: + if (dev->reg_offset == 0x28) { + val &= 0xe3; + smram_state_change(dev->smram, 0, !!(val & 0x80)); + } + dev->regs[dev->reg_offset] = val; + stpc_recalcmapping(dev); + break; + + case 0x29: + val &= 0x0f; + break; + + case 0x36: + val &= 0x3f; + break; + + case 0x52: case 0x53: case 0x54: case 0x55: + stpc_log("STPC: Set IRQ routing: INT %c -> %d\n", 0x41 + ((dev->reg_offset - 2) & 0x03), (val & 0x80) ? (val & 0xf) : -1); + val &= 0x8f; + pci_set_irq_routing(PCI_INTA + ((dev->reg_offset - 2) & 0x03), (val & 0x80) ? (val & 0xf) : PCI_IRQ_DISABLED); + break; + + case 0x56: case 0x57: + pic_elcr_write(dev->reg_offset, val, (dev->reg_offset & 1) ? &pic2 : &pic); + if (dev->reg_offset == 0x57) + refresh_at_enable = (val & 0x01); + break; + + case 0x59: + val &= 0xf1; + stpc_serial_handlers(val); + break; + } + + dev->regs[dev->reg_offset] = val; + } +} + + +static uint8_t +stpc_reg_read(uint16_t addr, void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + uint8_t ret; + + if (addr == 0x22) + ret = dev->reg_offset; + else if (dev->reg_offset >= 0xc0) + return 0xff; /* let the CPU code handle Cyrix CPU registers */ + else if ((dev->reg_offset == 0x56) || (dev->reg_offset == 0x57)) { + /* ELCR registers. */ + ret = pic_elcr_read(dev->reg_offset, (dev->reg_offset & 1) ? &pic2 : &pic); + if (dev->reg_offset == 0x57) + ret |= (dev->regs[dev->reg_offset] & 0x01); + } else + ret = dev->regs[dev->reg_offset]; + + stpc_log("STPC: reg_read(%04X) = %02X\n", dev->reg_offset, ret); + return ret; +} + + +static void +stpc_reset(void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: reset()\n"); + + memset(dev->regs, 0, sizeof(dev->regs)); + dev->regs[0x7b] = 0xff; + if (device_get_priv(&stpc_lpt_device)) + dev->regs[0x4c] |= 0x80; /* LPT strap */ + if (stpc_serial_handlers(0x00)) + dev->regs[0x4c] |= 0x03; /* UART straps */ +} + + +static void +stpc_setup(stpc_t *dev) +{ + stpc_log("STPC: setup()\n"); + + /* Main register interface */ + io_sethandler(0x22, 2, + stpc_reg_read, NULL, NULL, stpc_reg_write, NULL, NULL, dev); + + /* Northbridge */ + if (dev->local & STPC_CLIENT) { + dev->pci_conf[0][0x00] = 0x0e; + dev->pci_conf[0][0x01] = 0x10; + dev->pci_conf[0][0x02] = 0x64; + dev->pci_conf[0][0x03] = 0x05; + } else { + dev->pci_conf[0][0x00] = 0x4a; + dev->pci_conf[0][0x01] = 0x10; + dev->pci_conf[0][0x02] = 0x0a; + dev->pci_conf[0][0x03] = 0x02; + } + + dev->pci_conf[0][0x04] = 0x07; + + dev->pci_conf[0][0x06] = 0x80; + dev->pci_conf[0][0x07] = 0x02; + + dev->pci_conf[0][0x0b] = 0x06; + + /* ISA Bridge */ + dev->pci_conf[1][0x00] = dev->local >> 16; + dev->pci_conf[1][0x01] = dev->local >> 24; + dev->pci_conf[1][0x02] = dev->local; + dev->pci_conf[1][0x03] = dev->local >> 8; + + dev->pci_conf[1][0x04] = 0x0f; + + dev->pci_conf[1][0x06] = 0x80; + dev->pci_conf[1][0x07] = 0x02; + + dev->pci_conf[1][0x0a] = 0x01; + dev->pci_conf[1][0x0b] = 0x06; + + /* NOTE: This is an erratum in the STPC Atlas programming manual, the programming manuals for the other + STPC chipsets say 0x80, which is indeed multi-function (as the STPC Atlas programming manual + indicates as well), and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ + dev->pci_conf[1][0x0e] = /*0x40*/ 0x80; + + /* IDE */ + dev->pci_conf[2][0x00] = dev->local >> 16; + dev->pci_conf[2][0x01] = dev->local >> 24; + + if (dev->local == STPC_ATLAS) { + dev->pci_conf[2][0x02] = 0x28; + dev->pci_conf[2][0x03] = 0x02; + } else { + dev->pci_conf[2][0x02] = dev->pci_conf[1][0x02]; + dev->pci_conf[2][0x03] = dev->pci_conf[1][0x03]; + } + + dev->pci_conf[2][0x06] = 0x80; + dev->pci_conf[2][0x07] = 0x02; + + dev->pci_conf[2][0x09] = 0x8a; + dev->pci_conf[2][0x0a] = 0x01; + dev->pci_conf[2][0x0b] = 0x01; + + /* NOTE: This is an erratum in the STPC Atlas programming manual, the programming manuals for the other + STPC chipsets say 0x80, which is indeed multi-function (as the STPC Atlas programming manual + indicates as well), and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ + dev->pci_conf[2][0x0e] = /*0x40*/ 0x80; + + dev->pci_conf[2][0x10] = 0x01; + dev->pci_conf[2][0x14] = 0x01; + dev->pci_conf[2][0x18] = 0x01; + dev->pci_conf[2][0x1c] = 0x01; + dev->pci_conf[2][0x20] = 0x01; + + dev->pci_conf[2][0x40] = 0x60; + dev->pci_conf[2][0x41] = 0x97; + dev->pci_conf[2][0x42] = 0x60; + dev->pci_conf[2][0x43] = 0x97; + dev->pci_conf[2][0x44] = 0x60; + dev->pci_conf[2][0x45] = 0x97; + dev->pci_conf[2][0x46] = 0x60; + dev->pci_conf[2][0x47] = 0x97; + + /* USB */ + if (dev->usb) { + dev->pci_conf[3][0x00] = dev->local >> 16; + dev->pci_conf[3][0x01] = dev->local >> 24; + dev->pci_conf[3][0x02] = 0x30; + dev->pci_conf[3][0x03] = 0x02; + + dev->pci_conf[3][0x06] = 0x80; + dev->pci_conf[3][0x07] = 0x02; + + dev->pci_conf[3][0x09] = 0x10; + dev->pci_conf[3][0x0a] = 0x03; + dev->pci_conf[3][0x0b] = 0x0c; + + /* NOTE: This is an erratum in the STPC Atlas programming manual, the programming manuals for the other + STPC chipsets say 0x80, which is indeed multi-function (as the STPC Atlas programming manual + indicates as well), and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ + dev->pci_conf[3][0x0e] = /*0x40*/ 0x80; + } + + /* PCI setup */ + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); +} + + +static void +stpc_close(void *priv) +{ + stpc_t *dev = (stpc_t *) priv; + + stpc_log("STPC: close()\n"); + + smram_del(dev->smram); + + free(dev); +} + + +static void * +stpc_init(const device_t *info) +{ + stpc_log("STPC: init()\n"); + + stpc_t *dev = (stpc_t *) malloc(sizeof(stpc_t)); + memset(dev, 0, sizeof(stpc_t)); + + dev->local = info->local; + + pci_add_card(PCI_ADD_NORTHBRIDGE, stpc_nb_read, stpc_nb_write, dev); + dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_isab_read, stpc_isab_write, dev); + if (dev->local == STPC_ATLAS) { + dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_ide_read, stpc_ide_write, dev); + dev->usb = device_add(&usb_device); + pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_usb_read, stpc_usb_write, dev); + } + + dev->bm[0] = device_add_inst(&sff8038i_device, 1); + dev->bm[1] = device_add_inst(&sff8038i_device, 2); + + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[0], 1, 0); + + sff_set_irq_mode(dev->bm[1], 0, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + + stpc_setup(dev); + stpc_reset(dev); + + dev->smram = smram_add(); + + smram_enable(dev->smram, 0x000a0000, 0x000a0000, 0x00020000, 0, 1); + + device_add(&port_92_pci_device); + + pic_elcr_io_handler(0); + refresh_at_enable = 0; + + return dev; +} + + +static void +stpc_serial_close(void *priv) +{ + stpc_serial_t *dev = (stpc_serial_t *) priv; + + stpc_log("STPC: serial_close()\n"); + + free(dev); +} + + +static void * +stpc_serial_init(const device_t *info) +{ + stpc_log("STPC: serial_init()\n"); + + stpc_serial_t *dev = (stpc_serial_t *) malloc(sizeof(stpc_serial_t)); + memset(dev, 0, sizeof(stpc_serial_t)); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + /* Initialization is performed by stpc_reset */ + + return dev; +} + + +static void +stpc_lpt_handlers(stpc_lpt_t *dev, uint8_t val) +{ + uint8_t old_addr = (dev->reg1 & 0x03), new_addr = (val & 0x03); + + switch (old_addr) { + case 0x1: + lpt3_remove(); + break; + + case 0x2: + lpt1_remove(); + break; + + case 0x3: + lpt2_remove(); + break; + } + + switch (new_addr) { + case 0x1: + stpc_log("STPC: Remapping parallel port to LPT3\n"); + lpt3_init(0x3bc); + break; + + case 0x2: + stpc_log("STPC: Remapping parallel port to LPT1\n"); + lpt1_init(0x378); + break; + + case 0x3: + stpc_log("STPC: Remapping parallel port to LPT2\n"); + lpt2_init(0x278); + break; + + default: + stpc_log("STPC: Disabling parallel port\n"); + break; + } + + dev->reg1 = (val & 0x08); + dev->reg1 |= new_addr; + dev->reg1 |= 0x84; /* reserved bits that default to 1; hardwired? */ +} + + +static void +stpc_lpt_write(uint16_t addr, uint8_t val, void *priv) +{ + stpc_lpt_t *dev = (stpc_lpt_t *) priv; + + if (dev->unlocked < 2) { + /* Cheat a little bit: in reality, any write to any + I/O port is supposed to reset the unlock counter. */ + if ((addr == 0x3f0) && (val == 0x55)) + dev->unlocked++; + else + dev->unlocked = 0; + } else if (addr == 0x3f0) { + if (val == 0xaa) + dev->unlocked = 0; + else + dev->offset = val; + } else if (dev->offset == 1) { + /* dev->reg1 is set by stpc_lpt_handlers */ + stpc_lpt_handlers(dev, val); + } else if (dev->offset == 4) { + dev->reg4 = (val & 0x03); + } +} + + +static void +stpc_lpt_reset(void *priv) +{ + stpc_lpt_t *dev = (stpc_lpt_t *) priv; + + stpc_log("STPC: lpt_reset()\n"); + + dev->unlocked = 0; + dev->offset = 0x00; + dev->reg1 = 0x9f; + dev->reg4 = 0x00; + stpc_lpt_handlers(dev, dev->reg1); +} + + +static void +stpc_lpt_close(void *priv) +{ + stpc_lpt_t *dev = (stpc_lpt_t *) priv; + + stpc_log("STPC: lpt_close()\n"); + + free(dev); +} + + +static void * +stpc_lpt_init(const device_t *info) +{ + stpc_log("STPC: lpt_init()\n"); + + stpc_lpt_t *dev = (stpc_lpt_t *) malloc(sizeof(stpc_lpt_t)); + memset(dev, 0, sizeof(stpc_lpt_t)); + + stpc_lpt_reset(dev); + + io_sethandler(0x3f0, 2, + NULL, NULL, NULL, stpc_lpt_write, NULL, NULL, dev); + + return dev; +} + +/* STPC SoCs */ +const device_t stpc_client_device = { + .name = "STPC Client", + .internal_name = "stpc_client", + .flags = DEVICE_PCI, + .local = STPC_CLIENT, + .init = stpc_init, + .close = stpc_close, + .reset = stpc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t stpc_consumer2_device = { + .name = "STPC Consumer-II", + .internal_name = "stpc_consumer2", + .flags = DEVICE_PCI, + .local = STPC_CONSUMER2, + .init = stpc_init, + .close = stpc_close, + .reset = stpc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t stpc_elite_device = { + .name = "STPC Elite", + .internal_name = "stpc_elite", + .flags = DEVICE_PCI, + .local = STPC_ELITE, + .init = stpc_init, + .close = stpc_close, + .reset = stpc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t stpc_atlas_device = { + .name = "STPC Atlas", + .internal_name = "stpc_atlas", + .flags = DEVICE_PCI, + .local = STPC_ATLAS, + .init = stpc_init, + .close = stpc_close, + .reset = stpc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +/* Auxiliary devices */ +const device_t stpc_serial_device = { + .name = "STPC Serial UARTs", + .internal_name = "stpc_serial", + .flags = 0, + .local = 0, + .init = stpc_serial_init, + .close = stpc_serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t stpc_lpt_device = { + .name = "STPC Parallel Port", + .internal_name = "stpc_lpt", + .flags = 0, + .local = 0, + .init = stpc_lpt_init, + .close = stpc_lpt_close, + .reset = stpc_lpt_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c new file mode 100644 index 000000000..ba11ba829 --- /dev/null +++ b/src/chipset/umc_8886.c @@ -0,0 +1,406 @@ +/* + * 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 UMC 8886xx PCI to ISA Bridge . + * + * Note: This chipset has no datasheet, everything were done via + * reverse engineering the BIOS of various machines using it. + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2021 Tiseno100. + * Copyright 2021 Miran Grca. + */ + +/* + UMC 8886xx Configuration Registers + + Note: PMU functionality is quite basic. There may be Enable/Disable bits, IRQ/SMI picks and it also + required for 386_common.c to get patched in order to function properly. + + Warning: Register documentation may be inaccurate! + + UMC 8886xx: + (F: Has No Internal IDE / AF or BF: Has Internal IDE) + + Function 0 Register 43: + Bits 7-4 PCI IRQ for INTB + Bits 3-0 PCI IRQ for INTA + + Function 0 Register 44: + Bits 7-4 PCI IRQ for INTD + Bits 3-0 PCI IRQ for INTC + + Function 0 Register 46 (corrected by Miran Grca): + Bit 7: IRQ SMI Request (1: IRQ 15, 0: IRQ 10) + Bit 6: PMU Trigger(1: By IRQ/0: By SMI) + + Function 0 Register 56: + Bit 1-0 ISA Bus Speed + 0 0 PCICLK/3 + 0 1 PCICLK/4 + 1 0 PCICLK/2 + + Function 0 Register A2 - non-software SMI# status register + (documented by Miran Grca): + Bit 4: I set, graphics card goes into sleep mode + This register is most likely R/WC + + Function 0 Register A3 (added more details by Miran Grca): + Bit 7: Unlock SMM + Bit 6: Software SMI trigger (also doubles as software SMI# status register, + cleared by writing a 0 to it - see the handler used by Phoenix BIOS'es): + If Function 0 Register 46 Bit 6 is set, it raises the specified IRQ (15 + or 10) instead. + + Function 0 Register A4: + Bit 0: Host to PCI Clock (1: 1 by 1/0: 1 by half) + + Function 1 Register 4: (UMC 8886AF/8886BF Only!) + Bit 0: Enable Internal IDE +*/ + +#include +#include +#include +#include +#include +#include +#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/hdd.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/pic.h> +#include <86box/pci.h> + +#include <86box/chipset.h> + + +#define IDE_BIT 0x01 + + +#ifdef ENABLE_UMC_8886_LOG +int umc_8886_do_log = ENABLE_UMC_8886_LOG; + + +static void +umc_8886_log(const char *fmt, ...) +{ + va_list ap; + + if (umc_8886_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define umc_8886_log(fmt, ...) +#endif + + +/* PCI IRQ Flags */ +#define INTA (PCI_INTA + (2 * !(addr & 1))) +#define INTB (PCI_INTB + (2 * !(addr & 1))) +#define IRQRECALCA (((val & 0xf0) != 0) ? ((val & 0xf0) >> 4) : PCI_IRQ_DISABLED) +#define IRQRECALCB (((val & 0x0f) != 0) ? (val & 0x0f) : PCI_IRQ_DISABLED) + +/* Disable Internal IDE Flag needed for the AF or BF Southbridge variant */ +#define HAS_IDE dev->has_ide + +/* Southbridge Revision */ +#define SB_ID dev->sb_id + + +typedef struct umc_8886_t +{ + uint8_t max_func, /* Last function number */ + pci_conf_sb[2][256]; /* PCI Registers */ + uint16_t sb_id; /* Southbridge Revision */ + int has_ide; /* Check if Southbridge Revision is AF or F */ +} umc_8886_t; + + +static void +umc_8886_ide_handler(int status) +{ + ide_pri_disable(); + ide_sec_disable(); + + if (status) { + ide_pri_enable(); + ide_sec_enable(); + } +} + + +static void +umc_8886_write(int func, int addr, uint8_t val, void *priv) +{ + umc_8886_t *dev = (umc_8886_t *)priv; + + if (func <= dev->max_func) switch (func) { + case 0: /* PCI to ISA Bridge */ + umc_8886_log("UM8886: dev->regs[%02x] = %02x POST %02x\n", addr, val, inb(0x80)); + + switch (addr) { + case 0x04: case 0x05: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x07: + dev->pci_conf_sb[func][addr] &= ~(val & 0xf9); + break; + + case 0x0c: case 0x0d: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x40: case 0x41: + case 0x42: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x43: case 0x44: + dev->pci_conf_sb[func][addr] = val; + pci_set_irq_routing(INTA, IRQRECALCA); + pci_set_irq_routing(INTB, IRQRECALCB); + break; + + case 0x45: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x46: + /* Bit 6 seems to be the IRQ/SMI# toggle, 1 = IRQ, 0 = SMI#. */ + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x47: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0x56: + dev->pci_conf_sb[func][addr] = val; + + switch (val & 2) { + case 0: + cpu_set_isa_pci_div(3); + break; + case 1: + cpu_set_isa_pci_div(4); + break; + case 2: + cpu_set_isa_pci_div(2); + break; + } + + break; + + case 0x57: + case 0x70 ... 0x76: + case 0x80: case 0x81: + case 0x90 ... 0x92: + case 0xa0 ... 0xa1: + dev->pci_conf_sb[func][addr] = val; + break; + + case 0xa2: + dev->pci_conf_sb[func][addr] &= ~val; + break; + + case 0xa3: + /* SMI Provocation (Bit 7 Enable SMM + Bit 6 Software SMI) */ + if (((val & 0xc0) == 0xc0) && !(dev->pci_conf_sb[0][0xa3] & 0x40)) { + if (dev->pci_conf_sb[0][0x46] & 0x40) + picint(1 << ((dev->pci_conf_sb[0][0x46] & 0x80) ? 15 : 10)); + else + smi_raise(); + dev->pci_conf_sb[0][0xa3] |= 0x04; + } + + dev->pci_conf_sb[func][addr] = val; + break; + + case 0xa4: + dev->pci_conf_sb[func][addr] = val; + cpu_set_pci_speed(cpu_busspeed / ((val & 1) ? 1 : 2)); + break; + + case 0xa5 ... 0xa8: + dev->pci_conf_sb[func][addr] = val; + break; + } + break; + + case 1: /* IDE Controller */ + umc_8886_log("UM8886-IDE: dev->regs[%02x] = %02x POST: %02x\n", addr, val, inb(0x80)); + + switch (addr) { + case 0x04: + dev->pci_conf_sb[func][addr] = val; + umc_8886_ide_handler(val & 1); + break; + + case 0x07: + dev->pci_conf_sb[func][addr] &= ~(val & 0xf9); + break; + + case 0x3c: + case 0x40: case 0x41: + dev->pci_conf_sb[func][addr] = val; + break; + } + break; + } +} + + +static uint8_t +umc_8886_read(int func, int addr, void *priv) +{ + umc_8886_t *dev = (umc_8886_t *)priv; + uint8_t ret = 0xff; + + if (func <= dev->max_func) + ret = dev->pci_conf_sb[func][addr]; + + return ret; +} + + +static void +umc_8886_reset(void *priv) +{ + umc_8886_t *dev = (umc_8886_t *)priv; + + memset(dev->pci_conf_sb[0], 0x00, sizeof(dev->pci_conf_sb[0])); + memset(dev->pci_conf_sb[1], 0x00, sizeof(dev->pci_conf_sb[1])); + + dev->pci_conf_sb[0][0] = 0x60; /* UMC */ + dev->pci_conf_sb[0][1] = 0x10; + + dev->pci_conf_sb[0][2] = (SB_ID & 0xff); /* 8886xx */ + dev->pci_conf_sb[0][3] = ((SB_ID >> 8) & 0xff); + + dev->pci_conf_sb[0][4] = 0x0f; + dev->pci_conf_sb[0][7] = 2; + + dev->pci_conf_sb[0][8] = 0x0e; + + dev->pci_conf_sb[0][0x09] = 0x00; + dev->pci_conf_sb[0][0x0a] = 0x01; + dev->pci_conf_sb[0][0x0b] = 0x06; + + dev->pci_conf_sb[0][0x40] = 1; + dev->pci_conf_sb[0][0x41] = 6; + dev->pci_conf_sb[0][0x42] = 8; + dev->pci_conf_sb[0][0x43] = 0x9a; + dev->pci_conf_sb[0][0x44] = 0xbc; + dev->pci_conf_sb[0][0x45] = 4; + dev->pci_conf_sb[0][0x47] = 0x40; + dev->pci_conf_sb[0][0x50] = 1; + dev->pci_conf_sb[0][0x51] = 3; + dev->pci_conf_sb[0][0xa8] = 0x20; + + if (HAS_IDE) { + dev->pci_conf_sb[1][0] = 0x60; /* UMC */ + dev->pci_conf_sb[1][1] = 0x10; + + dev->pci_conf_sb[1][2] = 0x3a; /* 8886BF IDE */ + dev->pci_conf_sb[1][3] = 0x67; + + dev->pci_conf_sb[1][4] = 1; /* Start with Internal IDE Enabled */ + + dev->pci_conf_sb[1][8] = 0x10; + + dev->pci_conf_sb[1][0x09] = 0x0f; + dev->pci_conf_sb[1][0x0a] = dev->pci_conf_sb[1][0x0b] = 1; + + umc_8886_ide_handler(1); + } + + for (int i = 1; i < 5; i++) /* Disable all IRQ interrupts */ + pci_set_irq_routing(i, PCI_IRQ_DISABLED); + + cpu_set_isa_pci_div(3); + cpu_set_pci_speed(cpu_busspeed / 2); +} + + +static void +umc_8886_close(void *priv) +{ + umc_8886_t *dev = (umc_8886_t *)priv; + + free(dev); +} + + +static void * +umc_8886_init(const device_t *info) +{ + umc_8886_t *dev = (umc_8886_t *)malloc(sizeof(umc_8886_t)); + memset(dev, 0, sizeof(umc_8886_t)); + + dev->has_ide = !!(info->local == 0x886a); + pci_add_card(PCI_ADD_SOUTHBRIDGE, umc_8886_read, umc_8886_write, dev); /* Device 12: UMC 8886xx */ + + /* Add IDE if UM8886AF variant */ + if (HAS_IDE) + device_add(&ide_pci_2ch_device); + + dev->max_func = (HAS_IDE) ? 1 : 0; + + /* Get the Southbridge Revision */ + SB_ID = info->local; + + umc_8886_reset(dev); + + return dev; +} + +const device_t umc_8886f_device = { + .name = "UMC 8886F", + .internal_name = "umc_8886f", + .flags = DEVICE_PCI, + .local = 0x8886, + .init = umc_8886_init, + .close = umc_8886_close, + .reset = umc_8886_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t umc_8886af_device = { + .name = "UMC 8886AF/8886BF", + .internal_name = "umc_8886af", + .flags = DEVICE_PCI, + .local = 0x886a, + .init = umc_8886_init, + .close = umc_8886_close, + .reset = umc_8886_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c new file mode 100644 index 000000000..4440b7eef --- /dev/null +++ b/src/chipset/umc_hb4.c @@ -0,0 +1,431 @@ +/* + * 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 UMC HB4 "Super Energy Star Green" PCI Chipset. + * + * Note: This chipset has no datasheet, everything were done via + * reverse engineering the BIOS of various machines using it. + * + * Note 2: Additional information were also used from all + * around the web. + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2021 Tiseno100. + * Copyright 2021 Miran Grca. + */ + +/* + UMC HB4 Configuration Registers + + Sources & Notes: + Cache registers were found at Vogons: https://www.vogons.org/viewtopic.php?f=46&t=68829&start=20 + Basic Reverse engineering effort was done personally by me + + Warning: Register documentation may be inaccurate! + + UMC 8881x: + + Register 50: + Bit 7: Enable L2 Cache + Bit 6: Cache Policy (0: Write Thru / 1: Write Back) + + Bit 5-4 Cache Speed + 0 0 Read 3-2-2-2 Write 3T + 0 1 Read 3-1-1-1 Write 3T + 1 0 Read 2-2-2-2 Write 2T + 1 1 Read 2-1-1-1 Write 2T + + Bit 3 Cache Banks (0: 1 Bank / 1: 2 Banks) + + Bit 2-1-0 Cache Size + 0 0 0 0KB + 0 0 1 64KB + x-x-x Multiplications of 2(64*2 for 0 1 0) till 2MB + + Register 51: + Bit 7-6 DRAM Read Speed + 5-4 DRAM Write Speed + 0 0 1 Waits + 0 1 1 Waits + 1 0 1 Wait + 1 1 0 Waits + + Bit 3 Resource Lock Enable + Bit 2 Graphics Adapter (0: VL Bus / 1: PCI Bus) + Bit 1 L1 WB Policy (0: WT / 1: WB) + Bit 0 L2 Cache Tag Lenght (0: 7 Bits / 1: 8 Bits) + + Register 52: + Bit 7: Host-to-PCI Post Write (0: 1 Wait State / 1: 0 Wait States) + + Register 54: + Bit 7: DC000-DFFFF Read Enable + Bit 6: D8000-DBFFF Read Enable + Bit 5: D4000-D7FFF Read Enable + Bit 4: D0000-D3FFF Read Enable + Bit 3: CC000-CFFFF Read Enable + Bit 2: C8000-CBFFF Read Enable + Bit 1: C0000-C7FFF Read Enable + Bit 0: Enable C0000-DFFFF Shadow Segment Bits + + Register 55: + Bit 7: E0000-FFFF Read Enable + Bit 6: Shadow Write Status (1: Write Protect/0: Write) + + Register 56h & 57h: DRAM Bank 0 Configuration + Register 58h & 59h: DRAM Bank 1 Configuration + + Register 60: + Bit 5: If set and SMRAM is enabled, data cycles go to PCI and code cycles go to DRAM + Bit 0: SMRAM Local Access Enable - if set, SMRAM is also enabled outside SMM + SMRAM appears to always be enabled in SMM, and always set to A0000-BFFFF. +*/ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> + +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/smram.h> + +#ifdef USE_DYNAREC +# include "codegen_public.h" +#else +#ifdef USE_NEW_DYNAREC +# define PAGE_MASK_SHIFT 6 +#else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_SHIFT 4 +#endif +# define PAGE_MASK_MASK 63 +#endif +#include <86box/chipset.h> + + +#ifdef ENABLE_HB4_LOG +int hb4_do_log = ENABLE_HB4_LOG; + + +static void +hb4_log(const char *fmt, ...) +{ + va_list ap; + + if (hb4_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define hb4_log(fmt, ...) +#endif + + +typedef struct hb4_t +{ + uint8_t shadow, + shadow_read, shadow_write, + pci_conf[256]; /* PCI Registers */ + int mem_state[9]; + smram_t *smram[3]; /* SMRAM Handlers */ +} hb4_t; + + +static int shadow_bios[4] = { (MEM_READ_EXTANY | MEM_WRITE_INTERNAL), (MEM_READ_EXTANY | MEM_WRITE_EXTANY), + (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL), (MEM_READ_INTERNAL | MEM_WRITE_EXTANY) }; +static int shadow_read[2] = { MEM_READ_EXTANY, MEM_READ_INTERNAL }; +static int shadow_write[2] = { MEM_WRITE_INTERNAL, MEM_WRITE_EXTANY }; + + +int +hb4_shadow_bios_high(hb4_t *dev) +{ + int state; + + state = shadow_bios[dev->pci_conf[0x55] >> 6]; + + if (state != dev->mem_state[8]) { + mem_set_mem_state_both(0xf0000, 0x10000, state); + if ((dev->mem_state[8] & MEM_READ_INTERNAL) && !(state & MEM_READ_INTERNAL)) + mem_invalidate_range(0xf0000, 0xfffff); + dev->mem_state[8] = state; + return 1; + } + + return 0; +} + + +int +hb4_shadow_bios_low(hb4_t *dev) +{ + int state; + + state = shadow_bios[(dev->pci_conf[0x55] >> 6) & (dev->shadow | 0x01)]; + + if (state != dev->mem_state[7]) { + mem_set_mem_state_both(0xe0000, 0x10000, state); + dev->mem_state[7] = state; + return 1; + } + + return 0; +} + + +int +hb4_shadow_main(hb4_t *dev) +{ + int i, state; + int n = 0; + + for (i = 0; i < 6; i++) { + state = shadow_read[dev->shadow && ((dev->pci_conf[0x54] >> (i + 2)) & 0x01)] | + shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01]; + + if (state != dev->mem_state[i + 1]) { + n++; + mem_set_mem_state_both(0xc8000 + (i << 14), 0x4000, state); + dev->mem_state[i + 1] = state; + } + } + + return n; +} + + +int +hb4_shadow_video(hb4_t *dev) +{ + int state; + + state = shadow_read[dev->shadow && ((dev->pci_conf[0x54] >> 1) & 0x01)] | + shadow_write[(dev->pci_conf[0x55] >> 6) & 0x01]; + + if (state != dev->mem_state[0]) { + mem_set_mem_state_both(0xc0000, 0x8000, state); + dev->mem_state[0] = state; + return 1; + } + + return 0; +} + + +void +hb4_shadow(hb4_t *dev) +{ + int n = 0; + hb4_log("SHADOW: %02X%02X\n", dev->pci_conf[0x55], dev->pci_conf[0x54]); + + n = hb4_shadow_bios_high(dev); + n += hb4_shadow_bios_low(dev); + n += hb4_shadow_main(dev); + n += hb4_shadow_video(dev); + + if (n > 0) + flushmmucache_nopc(); +} + + +static void +hb4_smram(hb4_t *dev) +{ + smram_disable_all(); + + /* Bit 0, if set, enables SMRAM access outside SMM. SMRAM appears to be always enabled + in SMM, and is always set to A0000-BFFFF. */ + smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + /* There's a mirror of the SMRAM at 0E0A0000, mapped to A0000. */ + smram_enable(dev->smram[1], 0x0e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + /* There's another mirror of the SMRAM at 4E0A0000, mapped to A0000. */ + smram_enable(dev->smram[2], 0x4e0a0000, 0x000a0000, 0x20000, dev->pci_conf[0x60] & 0x01, 1); + + /* Bit 5 seems to set data to go to PCI and code to DRAM. The Samsung SPC7700P-LW uses + this. */ + if (dev->pci_conf[0x60] & 0x20) { + if (dev->pci_conf[0x60] & 0x01) + mem_set_mem_state_smram_ex(0, 0x000a0000, 0x20000, 0x02); + mem_set_mem_state_smram_ex(1, 0x000a0000, 0x20000, 0x02); + } +} + + +static void +hb4_write(int func, int addr, uint8_t val, void *priv) +{ + hb4_t *dev = (hb4_t *)priv; + + hb4_log("UM8881: dev->regs[%02x] = %02x POST: %02x \n", addr, val, inb(0x80)); + + switch (addr) { + case 0x04: case 0x05: + dev->pci_conf[addr] = val; + break; + + case 0x07: + dev->pci_conf[addr] &= ~(val & 0xf9); + break; + + case 0x0c: case 0x0d: + dev->pci_conf[addr] = val; + break; + + case 0x50: + dev->pci_conf[addr] = ((val & 0xf8) | 4); /* Hardcode Cache Size to 512KB */ + cpu_cache_ext_enabled = !!(val & 0x80); /* Fixes freezing issues on the HOT-433A*/ + cpu_update_waitstates(); + break; + + case 0x51: case 0x52: + dev->pci_conf[addr] = val; + break; + + case 0x53: + dev->pci_conf[addr] = val; + hb4_log("HB53: %02X\n", val); + break; + + case 0x55: + dev->shadow_read = (val & 0x80); + dev->shadow_write = (val & 0x40); + dev->pci_conf[addr] = val; + hb4_shadow(dev); + break; + case 0x54: + dev->shadow = (val & 0x01) << 1; + dev->pci_conf[addr] = val; + hb4_shadow(dev); + break; + + case 0x56 ... 0x5f: + dev->pci_conf[addr] = val; + break; + + case 0x60: + dev->pci_conf[addr] = val; + hb4_smram(dev); + break; + + case 0x61: + dev->pci_conf[addr] = val; + break; + } +} + + +static uint8_t +hb4_read(int func, int addr, void *priv) +{ + hb4_t *dev = (hb4_t *)priv; + uint8_t ret = 0xff; + + if (func == 0) + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +hb4_reset(void *priv) +{ + hb4_t *dev = (hb4_t *)priv; + memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); + + dev->pci_conf[0] = 0x60; /* UMC */ + dev->pci_conf[1] = 0x10; + + dev->pci_conf[2] = 0x81; /* 8881x */ + dev->pci_conf[3] = 0x88; + + dev->pci_conf[7] = 2; + + dev->pci_conf[8] = 4; + + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + + dev->pci_conf[0x51] = 1; + dev->pci_conf[0x52] = 1; + dev->pci_conf[0x5a] = 4; + dev->pci_conf[0x5c] = 0xc0; + dev->pci_conf[0x5d] = 0x20; + dev->pci_conf[0x5f] = 0xff; + + hb4_write(0, 0x54, 0x00, dev); + hb4_write(0, 0x55, 0x00, dev); + hb4_write(0, 0x60, 0x80, dev); + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); + + memset(dev->mem_state, 0x00, sizeof(dev->mem_state)); +} + + +static void +hb4_close(void *priv) +{ + hb4_t *dev = (hb4_t *)priv; + + free(dev); +} + + +static void * +hb4_init(const device_t *info) +{ + hb4_t *dev = (hb4_t *)malloc(sizeof(hb4_t)); + memset(dev, 0, sizeof(hb4_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, hb4_read, hb4_write, dev); /* Device 10: UMC 8881x */ + + /* Port 92 */ + device_add(&port_92_pci_device); + + /* SMRAM */ + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); + dev->smram[2] = smram_add(); + + hb4_reset(dev); + + return dev; +} + +const device_t umc_hb4_device = { + .name = "UMC HB4(8881F)", + .internal_name = "umc_hb4", + .flags = DEVICE_PCI, + .local = 0x886a, + .init = hb4_init, + .close = hb4_close, + .reset = hb4_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/via_apollo.c b/src/chipset/via_apollo.c index a3200669a..9a491478f 100644 --- a/src/chipset/via_apollo.c +++ b/src/chipset/via_apollo.c @@ -25,19 +25,33 @@ #include #include #include <86box/86box.h> +#include "cpu.h" #include <86box/mem.h> +#include <86box/smram.h> #include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> #include <86box/device.h> -#include <86box/keyboard.h> +#include <86box/pci.h> #include <86box/chipset.h> +#include <86box/spd.h> +#include <86box/video.h> +#define VIA_585 0x05851000 +#define VIA_595 0x05950000 +#define VIA_597 0x05970100 +#define VIA_598 0x05980000 +#define VIA_691 0x06910600 +#define VIA_693A 0x06914400 +#define VIA_694 0x0691c200 +#define VIA_8601 0x86010500 typedef struct via_apollo_t { - uint16_t id; - uint8_t pci_conf[2][256]; + uint32_t id; + uint8_t drb_unit; + uint8_t pci_conf[256]; + + smram_t *smram; + void *agpgart; } via_apollo_t; @@ -64,99 +78,151 @@ apollo_map(uint32_t addr, uint32_t size, int state) static void -apollo_smram_map(int smm, uint32_t addr, uint32_t size, int is_smram) +apollo_smram_map(via_apollo_t *dev, int smm, uint32_t host_base, uint32_t size, int is_smram) { - if (((is_smram & 0x03) == 0x01) || ((is_smram & 0x03) == 0x02)) { - smram[0].ram_base = 0x000a0000; - smram[0].size = size; + if (((is_smram & 0x03) == 0x01) || ((is_smram & 0x03) == 0x02)) + smram_enable(dev->smram, host_base, 0x000a0000, size, 0, 1); - mem_mapping_set_addr(&ram_smram_mapping[0], smram[0].host_base, size); - mem_mapping_set_exec(&ram_smram_mapping[0], ram + smram[0].ram_base); - } - - mem_set_mem_state_smram_ex(smm, addr, size, is_smram & 0x03); + mem_set_mem_state_smram_ex(smm, host_base, size, is_smram & 0x03); flushmmucache(); } +static void +apollo_agp_map(via_apollo_t *dev) +{ + /* Make sure the aperture's base is aligned to its size. */ + dev->pci_conf[0x12] &= dev->pci_conf[0x84] << 4; + dev->pci_conf[0x13] &= 0xf0 | (dev->pci_conf[0x84] >> 4); + + if (!dev->agpgart) + return; + + /* Map aperture and GART. */ + agpgart_set_aperture(dev->agpgart, + (dev->pci_conf[0x12] << 16) | (dev->pci_conf[0x13] << 24), + ((uint32_t) (uint8_t) ~dev->pci_conf[0x84] + 1) << 20, + !!(dev->pci_conf[0x88] & 0x02)); + agpgart_set_gart(dev->agpgart, (dev->pci_conf[0x89] << 8) | (dev->pci_conf[0x8a] << 16) | (dev->pci_conf[0x8b] << 24)); +} + + static void via_apollo_setup(via_apollo_t *dev) { /* Host Bridge */ - dev->pci_conf[0][0x00] = 0x06; /*VIA*/ - dev->pci_conf[0][0x01] = 0x11; - dev->pci_conf[0][0x02] = dev->id & 0xff; - dev->pci_conf[0][0x03] = (dev->id >> 8); + dev->pci_conf[0x00] = 0x06; /*VIA*/ + dev->pci_conf[0x01] = 0x11; + dev->pci_conf[0x02] = dev->id >> 16; + dev->pci_conf[0x03] = dev->id >> 24; - dev->pci_conf[0][0x04] = 6; - dev->pci_conf[0][0x05] = 0; + dev->pci_conf[0x04] = 6; + dev->pci_conf[0x05] = 0; - dev->pci_conf[0][0x06] = 0x90; - dev->pci_conf[0][0x07] = 0x02; + if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x06] = 0xa0; + else + dev->pci_conf[0x06] = 0x90; - if (dev->id == 0x0597) - dev->pci_conf[0][0x08] = 1; /* Production Silicon ("Revision B") */ - dev->pci_conf[0][0x09] = 0; - dev->pci_conf[0][0x0a] = 0; - dev->pci_conf[0][0x0b] = 6; - dev->pci_conf[0][0x0c] = 0; - dev->pci_conf[0][0x0d] = 0; - dev->pci_conf[0][0x0e] = 0; - dev->pci_conf[0][0x0f] = 0; - dev->pci_conf[0][0x10] = 0x08; - dev->pci_conf[0][0x34] = 0xa0; + dev->pci_conf[0x07] = 0x02; - if (dev->id == 0x0691) { - dev->pci_conf[0][0x56] = 0x01; - dev->pci_conf[0][0x57] = 0x01; + dev->pci_conf[0x08] = dev->id >> 8; + dev->pci_conf[0x09] = 0; + dev->pci_conf[0x0a] = 0; + dev->pci_conf[0x0b] = 6; + dev->pci_conf[0x0c] = 0; + dev->pci_conf[0x0d] = 0; + dev->pci_conf[0x0e] = 0; + dev->pci_conf[0x0f] = 0; + + if (dev->id >= VIA_597) { + dev->pci_conf[0x10] = 0x08; + dev->pci_conf[0x34] = 0xa0; } - dev->pci_conf[0][0x5a] = 0x01; - dev->pci_conf[0][0x5b] = 0x01; - dev->pci_conf[0][0x5c] = 0x01; - dev->pci_conf[0][0x5d] = 0x01; - dev->pci_conf[0][0x5e] = 0x01; - dev->pci_conf[0][0x5f] = 0x01; - dev->pci_conf[0][0x64] = 0xec; - dev->pci_conf[0][0x65] = 0xec; - dev->pci_conf[0][0x66] = 0xec; - if (dev->id == 0x0691) - dev->pci_conf[0][0x67] = 0xec; /* DRAM Timing for Banks 6,7. */ - dev->pci_conf[0][0x6b] = 0x01; + if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x52] = 0x02; + else if (dev->id >= VIA_694) + dev->pci_conf[0x52] = (dev->id == VIA_694) ? 0x90 : 0x10; - dev->pci_conf[0][0xa0] = 0x02; - dev->pci_conf[0][0xa2] = 0x10; - dev->pci_conf[0][0xa4] = 0x03; - dev->pci_conf[0][0xa5] = 0x02; - dev->pci_conf[0][0xa7] = 0x07; + if (dev->id >= VIA_693A) + dev->pci_conf[0x53] = 0x10; - /* PCI-to-PCI Bridge */ + if (dev->id == VIA_691) { + dev->pci_conf[0x56] = 0x01; + dev->pci_conf[0x57] = 0x01; + } - dev->pci_conf[1][0x00] = 0x06; /*VIA*/ - dev->pci_conf[1][0x01] = 0x11; - dev->pci_conf[1][0x02] = dev->id & 0xff; - dev->pci_conf[1][0x03] = (dev->id >> 8) | 0x80; + if (dev->id >= VIA_694) + dev->pci_conf[0x58] = 0x40; + else if (dev->id >= VIA_585) + dev->pci_conf[0x58] = 0x05; - dev->pci_conf[1][0x04] = 7; - dev->pci_conf[1][0x05] = 0; + if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x59] = 0x02; - dev->pci_conf[1][0x06] = 0x20; - dev->pci_conf[1][0x07] = 0x02; + dev->pci_conf[0x5a] = 0x01; + dev->pci_conf[0x5b] = 0x01; + dev->pci_conf[0x5c] = 0x01; + dev->pci_conf[0x5d] = 0x01; + dev->pci_conf[0x5e] = 0x01; + dev->pci_conf[0x5f] = 0x01; - dev->pci_conf[1][0x09] = 0; - dev->pci_conf[1][0x0a] = 4; - dev->pci_conf[1][0x0b] = 6; - dev->pci_conf[1][0x0c] = 0; - dev->pci_conf[1][0x0d] = 0; - dev->pci_conf[1][0x0e] = 1; - dev->pci_conf[1][0x0f] = 0; + dev->pci_conf[0x64] = ((dev->id >= VIA_585) || (dev->id < VIA_597)) ? 0xab : 0xec; + if (dev->id >= VIA_597) { + dev->pci_conf[0x65] = 0xec; + dev->pci_conf[0x66] = 0xec; + } + if (dev->id >= VIA_691) + dev->pci_conf[0x67] = 0xec; /* DRAM Timing for Banks 6, 7 */ + if (dev->id >= VIA_693A) { + if (cpu_busspeed < 95000000) { /* 66 MHz */ + cpu_set_pci_speed(cpu_busspeed / 2); + cpu_set_agp_speed(cpu_busspeed); + dev->pci_conf[0x68] |= 0x00; + } else if (cpu_busspeed < 124000000) { /* 100 MHz */ + cpu_set_pci_speed(cpu_busspeed / 3); + cpu_set_agp_speed(cpu_busspeed / 1.5); + dev->pci_conf[0x68] |= 0x01; + } else { /* 133 MHz */ + cpu_set_pci_speed(cpu_busspeed / 4); + cpu_set_agp_speed(cpu_busspeed / 2); + dev->pci_conf[0x68] |= (dev->id == VIA_8601) ? 0x03 : 0x02; + } + } else if (dev->id >= VIA_598) { + if (cpu_busspeed < ((dev->id >= VIA_691) ? 100000000 : 75000000)) { /* 66 MHz */ + cpu_set_pci_speed(cpu_busspeed / 2); + cpu_set_agp_speed(cpu_busspeed); + dev->pci_conf[0x68] |= 0x00; + } else if (cpu_busspeed < 100000000) { /* 75/83 MHz (not available on 691) */ + cpu_set_pci_speed(cpu_busspeed / 2.5); + cpu_set_agp_speed(cpu_busspeed / 1.25); + dev->pci_conf[0x68] |= 0x03; + } else { /* 100 MHz */ + cpu_set_pci_speed(cpu_busspeed / 3); + cpu_set_agp_speed(cpu_busspeed / 1.5); + dev->pci_conf[0x68] |= 0x01; + } + } + dev->pci_conf[0x6b] = 0x01; - dev->pci_conf[1][0x1c] = 0xf0; + if (dev->id >= VIA_597) { + dev->pci_conf[0xa0] = 0x02; + dev->pci_conf[0xa2] = 0x10; + dev->pci_conf[0xa4] = 0x03; + dev->pci_conf[0xa5] = 0x02; + dev->pci_conf[0xa7] = 0x07; - dev->pci_conf[1][0x20] = 0xf0; - dev->pci_conf[1][0x21] = 0xff; - dev->pci_conf[1][0x24] = 0xf0; - dev->pci_conf[1][0x25] = 0xff; + if (dev->id == VIA_693A) { + dev->pci_conf[0xac] = 0x08; + dev->pci_conf[0xad] = 0x02; + } + + if (dev->id == VIA_694) { + dev->pci_conf[0xb0] = 0x80; /* The datasheet refers it as 8xh */ + dev->pci_conf[0xb1] = 0x63; + } + } } @@ -164,319 +230,434 @@ static void via_apollo_host_bridge_write(int func, int addr, uint8_t val, void *priv) { via_apollo_t *dev = (via_apollo_t *) priv; - if (func) return; /*Read-only addresses*/ - if ((addr < 4) || ((addr >= 5) && (addr < 7)) || ((addr >= 8) && (addr < 0xd)) || - ((addr >= 0xe) && (addr < 0x12)) || ((addr >= 0x14) && (addr < 0x50)) || - (addr == 0x69) || ((addr >= 0x79) && (addr < 0x7e)) || - ((addr >= 0x81) && (addr < 0x84)) || ((addr >= 0x85) && (addr < 0x88)) || - ((addr >= 0x8c) && (addr < 0xa8)) || ((addr >= 0xaa) && (addr < 0xac)) || - ((addr >= 0xad) && (addr < 0xf0)) || ((addr >= 0xf8) && (addr < 0xfc)) || - (addr == 0xfd)) + if ((addr < 4) || ((addr > 5) && (addr < 7)) || ((addr >= 8) && (addr < 0xd)) || + ((addr >= 0xe) && (addr != 0x0f) && (addr < 0x12)) || ((addr >= 0x14) && (addr < 0x50)) || + ((addr > 0x7a) && (addr < 0x7e)) || ((addr >= 0x81) && (addr < 0x84)) || + ((addr >= 0x85) && (addr < 0x88)) || ((addr >= 0x8c) && (addr < 0xa8)) || + ((addr >= 0xaa) && (addr < 0xac)) || ((addr > 0xad) && (addr < 0xf0)) || + ((addr >= 0xf8) && (addr < 0xfc))) return; - if (((addr == 0x78) || (addr >= 0xad)) && (dev->id == 0x0597)) + if (((addr == 0x12) || (addr == 0x13)) && (dev->id < VIA_597)) return; - if (((addr == 0x67) || ((addr >= 0xf0) && (addr < 0xfc))) && (dev->id != 0x0691)) + if (((addr == 0x78) || (addr >= 0xad)) && (dev->id == VIA_597)) + return; + if (((addr == 0x67) || ((addr >= 0xf0) && (addr < 0xfc))) && (dev->id < VIA_691)) return; switch(addr) { case 0x04: - dev->pci_conf[0][0x04] = (dev->pci_conf[0][0x04] & ~0x40) | (val & 0x40); - break; - case 0x07: - dev->pci_conf[0][0x07] &= ~(val & 0xb0); - break; - case 0x0d: - dev->pci_conf[0][0x0d] = (dev->pci_conf[0][0x0d] & ~0x07) | (val & 0x07); - dev->pci_conf[0][0x75] = (dev->pci_conf[0][0x75] & ~0x30) | ((val & 0x06) << 3); + dev->pci_conf[0x04] = (dev->pci_conf[0x04] & ~0x40) | (val & 0x40); break; + case 0x05: + if((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x05] = (dev->pci_conf[0x05] & ~0x03) | (val & 0x03); + else + dev->pci_conf[0x05] = val; + break; + + case 0x07: + dev->pci_conf[0x07] &= ~(val & 0xb0); + break; + case 0x0d: + if(dev->id == VIA_8601) + dev->pci_conf[0x0d] = (dev->pci_conf[0x0d] & ~0x07) | (val & 0x07); + else if(dev->id == VIA_694) + dev->pci_conf[0x0d] = (dev->pci_conf[0x0d] & ~0xf8) | (val & 0xf8); + else + dev->pci_conf[0x0d] = (dev->pci_conf[0x0d] & ~0x07) | (val & 0x07); + + dev->pci_conf[0x75] = (dev->pci_conf[0x75] & ~0x30) | ((val & 0x06) << 3); + break; + + case 0x0f: + if((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x0f] = (dev->pci_conf[0x0f] & ~0xcf) | (val & 0x0cf); + else + dev->pci_conf[0x0f] = val; + break; case 0x12: /* Graphics Aperture Base */ - dev->pci_conf[0][0x12] = (val & 0xf0); + dev->pci_conf[0x12] = (val & 0xf0); + apollo_agp_map(dev); break; case 0x13: /* Graphics Aperture Base */ - dev->pci_conf[0][0x13] = val; + dev->pci_conf[0x13] = val; + apollo_agp_map(dev); break; case 0x50: /* Cache Control 1 */ - if (dev->id == 0x0691) - dev->pci_conf[0][0x50] = val; + if (dev->id == VIA_8601) + dev->pci_conf[0x50] = (dev->pci_conf[0x50] & ~0xd3) | (val & 0xd3); + else if (dev->id >= VIA_693A) + dev->pci_conf[0x50] = (dev->pci_conf[0x50] & ~0xd1) | (val & 0xd1); + else if (dev->id == VIA_595) + dev->pci_conf[0x50] = (dev->pci_conf[0x50] & ~0xfb) | (val & 0xfb); + else if ((dev->id == VIA_585) || (dev->id == VIA_691)) + dev->pci_conf[0x50] = val; else - dev->pci_conf[0][0x50] = (dev->pci_conf[0][0x50] & ~0xf8) | (val & 0xf8); + dev->pci_conf[0x50] = (dev->pci_conf[0x50] & ~0xf8) | (val & 0xf8); break; case 0x51: /* Cache Control 2 */ - if (dev->id == 0x0691) - dev->pci_conf[0][0x51] = val; + if (dev->id == VIA_694) + dev->pci_conf[0x51] = (dev->pci_conf[0x51] & ~0xdd) | (val & 0xdd); + else if (dev->id >= VIA_693A) + dev->pci_conf[0x51] = (dev->pci_conf[0x51] & ~0xd9) | (val & 0xd9); + else if (dev->id >= VIA_691) + dev->pci_conf[0x51] = val; + else if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x51] = (dev->pci_conf[0x51] & ~0x2b) | (val & 0x2b); else - dev->pci_conf[0][0x51] = (dev->pci_conf[0][0x51] & ~0xeb) | (val & 0xeb); + dev->pci_conf[0x51] = (dev->pci_conf[0x51] & ~0xeb) | (val & 0xeb); break; case 0x52: /* Non_Cacheable Control */ - if (dev->id == 0x0691) - dev->pci_conf[0][0x52] = (dev->pci_conf[0][0x52] & ~0x9f) | (val & 0x9f); + if (dev->id == VIA_8601) + dev->pci_conf[0x52] = (dev->pci_conf[0x52] & ~0xdf) | (val & 0xdf); + else if (dev->id >= VIA_693A) + dev->pci_conf[0x52] = val; + else if (dev->id == VIA_691) + dev->pci_conf[0x52] = (dev->pci_conf[0x52] & ~0x9f) | (val & 0x9f); else - dev->pci_conf[0][0x52] = (dev->pci_conf[0][0x52] & ~0xf5) | (val & 0xf5); + dev->pci_conf[0x52] = (dev->pci_conf[0x52] & ~0xf5) | (val & 0xf5); break; case 0x53: /* System Performance Control */ - if (dev->id == 0x0691) - dev->pci_conf[0][0x53] = val; + if (dev->id == VIA_8601) + dev->pci_conf[0x53] = (dev->pci_conf[0x53] & ~0xfc) | (val & 0xfc); + else if ((dev->id == VIA_691) || (dev->id == VIA_694)) + dev->pci_conf[0x53] = val; + else if ((dev->id >= VIA_585) || (dev->id < VIA_597) || (dev->id == VIA_693A)) + dev->pci_conf[0x53] = (dev->pci_conf[0x53] & ~0xf8) | (val & 0xf8); else - dev->pci_conf[0][0x53] = (dev->pci_conf[0][0x53] & ~0xf0) | (val & 0xf0); + dev->pci_conf[0x53] = (dev->pci_conf[0x53] & ~0xf0) | (val & 0xf0); + break; + case 0x54: + if (dev->id == VIA_585) + dev->pci_conf[0x54] = val; + else + dev->pci_conf[0x54] = (dev->pci_conf[0x54] & ~0x07) | (val & 0x07); + break; + + case 0x56: case 0x57: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* DRAM Row Ending Address */ + if ((dev->id >= VIA_691) && (dev->id != VIA_8601)) + spd_write_drbs(dev->pci_conf, 0x5a, 0x56, dev->drb_unit); + else if (addr >= 0x5a) + spd_write_drbs(dev->pci_conf, 0x5a, 0x5f, dev->drb_unit); break; case 0x58: - if (dev->id == 0x0597) - dev->pci_conf[0][0x58] = (dev->pci_conf[0][0x58] & ~0xee) | (val & 0xee); + if ((dev->id >= VIA_585) || (dev->id < VIA_597) || (dev->id == VIA_597) || ((dev->id >= VIA_693A) || (dev->id < VIA_8601))) + dev->pci_conf[0x58] = (dev->pci_conf[0x58] & ~0xee) | (val & 0xee); else - dev->pci_conf[0][0x58] = val; + dev->pci_conf[0x58] = val; break; case 0x59: - if (dev->id == 0x0691) - dev->pci_conf[0][0x59] = val; + if (dev->id >= VIA_693A) + dev->pci_conf[0x59] = (dev->pci_conf[0x59] & ~0xee) | (val & 0xee); + else if (dev->id == VIA_691) + dev->pci_conf[0x59] = val; + else if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x59] = (dev->pci_conf[0x59] & ~0xe7) | (val & 0xe7); else - dev->pci_conf[0][0x59] = (dev->pci_conf[0][0x59] & ~0xf0) | (val & 0xf0); + dev->pci_conf[0x59] = (dev->pci_conf[0x59] & ~0xf0) | (val & 0xf0); break; case 0x61: /* Shadow RAM Control 1 */ - if ((dev->pci_conf[0][0x61] ^ val) & 0x03) - apollo_map(0xc0000, 0x04000, val & 0x03); - if ((dev->pci_conf[0][0x61] ^ val) & 0x0c) - apollo_map(0xc4000, 0x04000, (val & 0x0c) >> 2); - if ((dev->pci_conf[0][0x61] ^ val) & 0x30) - apollo_map(0xc8000, 0x04000, (val & 0x30) >> 4); - if ((dev->pci_conf[0][0x61] ^ val) & 0xc0) - apollo_map(0xcc000, 0x04000, (val & 0xc0) >> 6); - dev->pci_conf[0][0x61] = val; + apollo_map(0xc0000, 0x04000, val & 0x03); + apollo_map(0xc4000, 0x04000, (val & 0x0c) >> 2); + apollo_map(0xc8000, 0x04000, (val & 0x30) >> 4); + apollo_map(0xcc000, 0x04000, (val & 0xc0) >> 6); + + dev->pci_conf[0x61] = val; break; case 0x62: /* Shadow RAM Control 2 */ - if ((dev->pci_conf[0][0x62] ^ val) & 0x03) - apollo_map(0xd0000, 0x04000, val & 0x03); - if ((dev->pci_conf[0][0x62] ^ val) & 0x0c) - apollo_map(0xd4000, 0x04000, (val & 0x0c) >> 2); - if ((dev->pci_conf[0][0x62] ^ val) & 0x30) - apollo_map(0xd8000, 0x04000, (val & 0x30) >> 4); - if ((dev->pci_conf[0][0x62] ^ val) & 0xc0) - apollo_map(0xdc000, 0x04000, (val & 0xc0) >> 6); - dev->pci_conf[0][0x62] = val; + apollo_map(0xd0000, 0x04000, val & 0x03); + apollo_map(0xd4000, 0x04000, (val & 0x0c) >> 2); + apollo_map(0xd8000, 0x04000, (val & 0x30) >> 4); + apollo_map(0xdc000, 0x04000, (val & 0xc0) >> 6); + + dev->pci_conf[0x62] = val; break; case 0x63: /* Shadow RAM Control 3 */ - if ((dev->pci_conf[0][0x63] ^ val) & 0x30) { - apollo_map(0xf0000, 0x10000, (val & 0x30) >> 4); - shadowbios = (((val & 0x30) >> 4) & 0x02); - } - if ((dev->pci_conf[0][0x63] ^ val) & 0xc0) - apollo_map(0xe0000, 0x10000, (val & 0xc0) >> 6); - dev->pci_conf[0][0x63] = val; - if (smram[0].size != 0x00000000) { - mem_set_mem_state_smram_ex(0, smram[0].host_base, smram[0].size, 0x00); - mem_set_mem_state_smram_ex(1, smram[0].host_base, smram[0].size, 0x00); + shadowbios = 0; + shadowbios_write = 0; - memset(&smram[0], 0x00, sizeof(smram_t)); - mem_mapping_disable(&ram_smram_mapping[0]); - flushmmucache(); - } - if (dev->id == 0x0691) switch (val & 0x03) { + apollo_map(0xf0000, 0x10000, (val & 0x30) >> 4); + shadowbios = (((val & 0x30) >> 4) & 0x02); + shadowbios_write = (((val & 0x30) >> 4) & 0x01); + + apollo_map(0xe0000, 0x10000, (val & 0xc0) >> 6); + shadowbios |= (((val & 0xc0) >> 6) & 0x02); + shadowbios_write |= (((val & 0xc0) >> 6) & 0x01); + + dev->pci_conf[0x63] = val; + smram_disable_all(); + if (dev->id >= VIA_691) switch (val & 0x03) { case 0x00: default: - apollo_smram_map(1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ - apollo_smram_map(0, 0x000a0000, 0x00020000, 0); /* Non-SMM: Code PCI, Data PCI */ + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 0); /* Non-SMM: Code PCI, Data PCI */ break; case 0x01: - apollo_smram_map(1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ - apollo_smram_map(0, 0x000a0000, 0x00020000, 1); /* Non-SMM: Code DRAM, Data DRAM */ + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 1); /* Non-SMM: Code DRAM, Data DRAM */ break; case 0x02: - apollo_smram_map(1, 0x000a0000, 0x00020000, 3); /* SMM: Code Invalid, Data Invalid */ - apollo_smram_map(0, 0x000a0000, 0x00020000, 2); /* Non-SMM: Code DRAM, Data PCI */ + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 3); /* SMM: Code Invalid, Data Invalid */ + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 2); /* Non-SMM: Code DRAM, Data PCI */ break; case 0x03: - apollo_smram_map(1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ - apollo_smram_map(0, 0x000a0000, 0x00020000, 3); /* Non-SMM: Code Invalid, Data Invalid */ + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 3); /* Non-SMM: Code Invalid, Data Invalid */ break; - } else switch (val & 0x03) { + } else if (dev->id >= VIA_597) switch (val & 0x03) { case 0x00: default: /* Disable SMI Address Redirection (default) */ - apollo_smram_map(1, 0x000a0000, 0x00020000, 0); - if (dev->id == 0x0597) - apollo_smram_map(1, 0x00030000, 0x00020000, 1); - apollo_smram_map(0, 0x000a0000, 0x00020000, 0); + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 0); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 0); break; case 0x01: /* Allow access to DRAM Axxxx-Bxxxx for both normal and SMI cycles */ - apollo_smram_map(1, 0x000a0000, 0x00020000, 1); - if (dev->id == 0x0597) - apollo_smram_map(1, 0x00030000, 0x00020000, 1); - apollo_smram_map(0, 0x000a0000, 0x00020000, 1); + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 1); break; case 0x02: /* Reserved */ - apollo_smram_map(1, 0x000a0000, 0x00020000, 3); - if (dev->id == 0x0597) { + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 3); + if (dev->id == VIA_597) { /* SMI 3xxxx-4xxxx redirect to Axxxx-Bxxxx. */ - smram[0].host_base = 0x00030000; - apollo_smram_map(1, 0x00030000, 0x00020000, 1); + apollo_smram_map(dev, 1, 0x00030000, 0x00020000, 1); } - apollo_smram_map(0, 0x000a0000, 0x00020000, 3); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 3); break; case 0x03: /* Allow SMI Axxxx-Bxxxx DRAM access */ - apollo_smram_map(1, 0x000a0000, 0x00020000, 1); - if (dev->id == 0x0597) - apollo_smram_map(1, 0x00030000, 0x00020000, 1); - apollo_smram_map(0, 0x000a0000, 0x00020000, 0); + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 0); + break; + } else switch(val & 0x03) { + case 0x00: + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 0); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 0); + break; + case 0x01: + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 0); + break; + case 0x02: + apollo_smram_map(dev, 1, 0x00030000, 0x00020000, 1); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 3); + break; + case 0x03: + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 1); + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 3); + apollo_smram_map(dev, 0, 0x000a0000, 0x00020000, 3); break; } break; - case 0x68: - if (dev->id == 0x0597) - dev->pci_conf[0][0x68] = (dev->pci_conf[0][0x6b] & ~0xfe) | (val & 0xfe); - else if (dev->id == 0x0598) - dev->pci_conf[0][0x68] = val; + case 0x65: + if (dev->id == VIA_585) + dev->pci_conf[0x65] = (dev->pci_conf[0x65] & ~0xfd) | (val & 0xfd); + else if (dev->id == VIA_595) + dev->pci_conf[0x65] = (dev->pci_conf[0x65] & ~0xf9) | (val & 0xf9); else - dev->pci_conf[0][0x68] = (dev->pci_conf[0][0x6b] & ~0xfd) | (val & 0xfd); + dev->pci_conf[0x65] = val; + break; + case 0x66: + if (dev->id == VIA_585) + dev->pci_conf[0x66] = (dev->pci_conf[0x66] & ~0xaf) | (val & 0xaf); + else if (dev->id == VIA_595) + dev->pci_conf[0x66] = (dev->pci_conf[0x66] & ~0x8f) | (val & 0x8f); + else + dev->pci_conf[0x66] = val; + break; + case 0x68: + if (dev->id != VIA_595) { + if (dev->id == VIA_597) + dev->pci_conf[0x68] = (dev->pci_conf[0x68] & ~0xfe) | (val & 0xfe); + else if ((dev->id == VIA_693A) || (dev->id == VIA_694)) + dev->pci_conf[0x68] = (dev->pci_conf[0x68] & ~0xdc) | (val & 0xdc); + else + dev->pci_conf[0x68] = (dev->pci_conf[0x68] & ~0xfc) | (val & 0xfc); + } + break; + case 0x69: + if ((dev->id != VIA_585) || (dev->id != VIA_595)){ + if ((dev->id == VIA_693A) || (dev->id < VIA_8601)) + dev->pci_conf[0x69] = (dev->pci_conf[0x69] & ~0xfe) | (val & 0xfe); + else + dev->pci_conf[0x69] = val; + } break; case 0x6b: - if (dev->id == 0x0691) - dev->pci_conf[0][0x6b] = (dev->pci_conf[0][0x6b] & ~0xcf) | (val & 0xcf); + if ((dev->id == VIA_693A) || (dev->id < VIA_8601)) + dev->pci_conf[0x6b] = val; + else if (dev->id == VIA_691) + dev->pci_conf[0x6b] = (dev->pci_conf[0x6b] & ~0xcf) | (val & 0xcf); + else if (dev->id == VIA_595) + dev->pci_conf[0x6b] = (dev->pci_conf[0x6b] & ~0xc0) | (val & 0xc0); + else if (dev->id == VIA_585) + dev->pci_conf[0x6b] = (dev->pci_conf[0x6b] & ~0xc4) | (val & 0xc4); else - dev->pci_conf[0][0x6b] = (dev->pci_conf[0][0x6b] & ~0xc1) | (val & 0xc1); + dev->pci_conf[0x6b] = (dev->pci_conf[0x6b] & ~0xc1) | (val & 0xc1); break; case 0x6c: - if (dev->id == 0x0597) - dev->pci_conf[0][0x6c] = (dev->pci_conf[0][0x6c] & ~0x1f) | (val & 0x1f); - else if (dev->id == 0x0598) - dev->pci_conf[0][0x6c] = (dev->pci_conf[0][0x6c] & ~0x7f) | (val & 0x7f); + if ((dev->id == VIA_597) || ((dev->id == VIA_693A) || (dev->id < VIA_8601))) + dev->pci_conf[0x6c] = (dev->pci_conf[0x6c] & ~0x1f) | (val & 0x1f); + else if (dev->id == VIA_598) + dev->pci_conf[0x6c] = (dev->pci_conf[0x6c] & ~0x7f) | (val & 0x7f); + else if (dev->id == VIA_585) + dev->pci_conf[0x6c] = (dev->pci_conf[0x6c] & ~0xef) | (val & 0xef); else - dev->pci_conf[0][0x6c] = val; + dev->pci_conf[0x6c] = val; break; case 0x6d: - if (dev->id == 0x0597) - dev->pci_conf[0][0x6d] = (dev->pci_conf[0][0x6d] & ~0x0f) | (val & 0x0f); - else if (dev->id == 0x0598) - dev->pci_conf[0][0x6d] = (dev->pci_conf[0][0x6d] & ~0x7f) | (val & 0x7f); + if ((dev->id == VIA_597) || (dev->id == VIA_694)) + dev->pci_conf[0x6d] = (dev->pci_conf[0x6d] & ~0x0f) | (val & 0x0f); + else if ((dev->id == VIA_598) || (dev->id == VIA_693A) || (dev->id == VIA_8601)) + dev->pci_conf[0x6d] = (dev->pci_conf[0x6d] & ~0x7f) | (val & 0x7f); else - dev->pci_conf[0][0x6d] = val; + dev->pci_conf[0x6d] = val; break; case 0x6e: - dev->pci_conf[0][0x6e] = (dev->pci_conf[0][0x6e] & ~0xb7) | (val & 0xb7); + if((dev->id == VIA_595) || (dev->id == VIA_694)) + dev->pci_conf[0x6e] = val; + else + dev->pci_conf[0x6e] = (dev->pci_conf[0x6e] & ~0xb7) | (val & 0xb7); break; case 0x70: - if (dev->id == 0x0597) - dev->pci_conf[0][0x70] = (dev->pci_conf[0][0x70] & ~0xf1) | (val & 0xf1); + if ((dev->id >= VIA_693A)) + dev->pci_conf[0x70] = (dev->pci_conf[0x70] & ~0xdf) | (val & 0xdf); + else if (dev->id == VIA_597) + dev->pci_conf[0x70] = (dev->pci_conf[0x70] & ~0xf1) | (val & 0xf1); + else if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x70] = (dev->pci_conf[0x70] & ~0xe3) | (val & 0xe3); else - dev->pci_conf[0][0x70] = val; + dev->pci_conf[0x70] = val; + break; + case 0x71: + if((dev->id >= VIA_585) || (dev->id == VIA_694)) + dev->pci_conf[0x71] = (dev->pci_conf[0x71] & ~0xdf) | (val & 0xdf); + else + dev->pci_conf[0x71] = val; + break; + case 0x73: + if (dev->id >= VIA_693A) + dev->pci_conf[0x73] = (dev->pci_conf[0x73] & ~0x7f) | (val & 0x7f); + else if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x73] = (dev->pci_conf[0x73] & ~0xef) | (val & 0xef); + else + dev->pci_conf[0x73] = val; break; case 0x74: - dev->pci_conf[0][0x74] = (dev->pci_conf[0][0x74] & ~0xc0) | (val & 0xc0); + if ((dev->id == VIA_693A) || (dev->id == VIA_8601)) + dev->pci_conf[0x74] = (dev->pci_conf[0x74] & ~0xdf) | (val & 0xdf); + else if (dev->id == VIA_694) + dev->pci_conf[0x74] = (dev->pci_conf[0x74] & ~0x9f) | (val & 0x9f); + else + dev->pci_conf[0x74] = (dev->pci_conf[0x74] & ~0xc0) | (val & 0xc0); break; case 0x75: - dev->pci_conf[0][0x75] = (dev->pci_conf[0][0x75] & ~0xcf) | (val & 0xcf); + if (dev->id >= VIA_693A) + dev->pci_conf[0x75] = val; + else + dev->pci_conf[0x75] = (dev->pci_conf[0x75] & ~0xcf) | (val & 0xcf); break; case 0x76: - dev->pci_conf[0][0x76] = (dev->pci_conf[0][0x76] & ~0xf0) | (val & 0xf0); + if (dev->id >= VIA_693A) + dev->pci_conf[0x76] = val; + else if ((dev->id >= VIA_585) || (dev->id < VIA_597)) + dev->pci_conf[0x76] = (dev->pci_conf[0x76] & ~0xb0) | (val & 0xb0); + else + dev->pci_conf[0x76] = (dev->pci_conf[0x76] & ~0xf0) | (val & 0xf0); break; case 0x77: - dev->pci_conf[0][0x77] = (dev->pci_conf[0][0x77] & ~0xc0) | (val & 0xc0); + if (dev->id < VIA_693A) + dev->pci_conf[0x77] = (dev->pci_conf[0x77] & ~0xc0) | (val & 0xc0); + break; + case 0x78: + dev->pci_conf[0x78] = (dev->pci_conf[0x78] & ~0xd5) | (val & 0xd5); + break; + case 0x79: + dev->pci_conf[0x79] = (dev->pci_conf[0x79] & ~0xfc) | (val & 0xfc); + break; + case 0x7a: + dev->pci_conf[0x7a] = (dev->pci_conf[0x7a] & ~0x89) | (val & 0x89); break; case 0x7e: - dev->pci_conf[0][0x7e] = (dev->pci_conf[0][0x7e] & ~0x3f) | (val & 0x3f); + if ((dev->id != VIA_8601) || (dev->id != VIA_694)) + dev->pci_conf[0x7e] = (dev->pci_conf[0x7e] & ~0x3f) | (val & 0x3f); break; case 0x80: - dev->pci_conf[0][0x80] = (dev->pci_conf[0][0x80] & ~0x8f) | (val & 0x8f); + dev->pci_conf[0x80] = (dev->pci_conf[0x80] & ~0x8f) | (val & 0x8f); break; case 0x84: /* The datasheet first mentions 7-0 but then says 3-0 are reserved - - - minimum of 16 MB for the graphics aperture? */ - dev->pci_conf[0][0x84] = (dev->pci_conf[0][0x84] & ~0xf0) | (val & 0xf0); + - minimum of 16 MB for the graphics aperture? 8601 datasheet doesn't refer it. */ + if(dev->id >= VIA_693A) + dev->pci_conf[0x84] = val; + else + dev->pci_conf[0x84] = (dev->pci_conf[0x84] & ~0xf0) | (val & 0xf0); + apollo_agp_map(dev); break; case 0x88: - dev->pci_conf[0][0x88] = (dev->pci_conf[0][0x88] & ~0x07) | (val & 0x07); + if((dev->id == VIA_693A) || (dev->id == VIA_8601)) + dev->pci_conf[0x88] = (dev->pci_conf[0x88] & ~0x06) | (val & 0x06); + else + dev->pci_conf[0x88] = (dev->pci_conf[0x88] & ~0x07) | (val & 0x07); + apollo_agp_map(dev); break; case 0x89: - dev->pci_conf[0][0x89] = (dev->pci_conf[0][0x89] & ~0xf0) | (val & 0xf0); + dev->pci_conf[0x89] = val & 0xf0; + apollo_agp_map(dev); + break; + case 0x8a: + case 0x8b: + dev->pci_conf[addr] = val; + apollo_agp_map(dev); break; case 0xa8: - dev->pci_conf[0][0xa8] = (dev->pci_conf[0][0xa8] & ~0x03) | (val & 0x03); + if(dev->id == VIA_694) + dev->pci_conf[0xa8] = (dev->pci_conf[0xa8] & ~0x33) | (val & 0x33); + else + dev->pci_conf[0xa8] = (dev->pci_conf[0xa8] & ~0x03) | (val & 0x03); break; case 0xa9: - dev->pci_conf[0][0xa9] = (dev->pci_conf[0][0xa9] & ~0x03) | (val & 0x03); + dev->pci_conf[0xa9] = (dev->pci_conf[0xa9] & ~0x03) | (val & 0x03); break; case 0xac: - dev->pci_conf[0][0xac] = (dev->pci_conf[0][0xac] & ~0x0f) | (val & 0x0f); - break; - case 0xfc: - if (dev->id > 0x0597) - dev->pci_conf[0][0xfc] = (dev->pci_conf[0][0xfc] & ~0x01) | (val & 0x01); - break; - - default: - dev->pci_conf[0][addr] = val; - break; - } -} - - -static void -via_apollo_pci_bridge_write(int func, int addr, uint8_t val, void *priv) -{ - via_apollo_t *dev = (via_apollo_t *) priv; - - if (func != 1) - return; - - /*Read-only addresses*/ - - if ((addr < 4) || ((addr >= 5) && (addr < 7)) || - ((addr >= 8) && (addr < 0x18)) || (addr == 0x1b) || - ((addr >= 0x1e) && (addr < 0x20)) || ((addr >= 0x28) && (addr < 0x3e)) || - (addr == 0x3f) || (addr >= 0x43)) - return; - - switch(addr) { - case 0x04: - dev->pci_conf[1][0x04] = (dev->pci_conf[1][0x04] & ~0x47) | (val & 0x47); - break; - case 0x07: - dev->pci_conf[1][0x07] &= ~(val & 0x30); - break; - - case 0x20: /* Memory Base */ - dev->pci_conf[1][0x20] = val & 0xf0; - break; - case 0x22: /* Memory Limit */ - dev->pci_conf[1][0x22] = val & 0xf0; - break; - case 0x24: /* Prefetchable Memory Base */ - dev->pci_conf[1][0x24] = val & 0xf0; - break; - case 0x26: /* Prefetchable Memory Limit */ - dev->pci_conf[1][0x26] = val & 0xf0; - break; - - case 0x3e: - dev->pci_conf[0][0x3e] = (dev->pci_conf[0][0x3e] & ~0x06) | (val & 0x06); - break; - - case 0x41: - dev->pci_conf[0][0x41] = (dev->pci_conf[0][0x41] & ~0xfe) | (val & 0xfe); - break; - case 0x42: - if (dev->id == 0x0597) - dev->pci_conf[0][0x42] = (dev->pci_conf[0][0x42] & ~0xec) | (val & 0xec); - else if (dev->id == 0x0598) - dev->pci_conf[0][0x42] = (dev->pci_conf[0][0x42] & ~0xfc) | (val & 0xfc); + if(dev->id == VIA_8601) + dev->pci_conf[0xac] = (dev->pci_conf[0xac] & ~0x7f) | (val & 0x7f); else - dev->pci_conf[0][0x42] = (dev->pci_conf[0][0x42] & ~0xf4) | (val & 0xf4); + dev->pci_conf[0xac] = (dev->pci_conf[0xac] & ~0x0f) | (val & 0x0f); + break; + case 0xad: + dev->pci_conf[0xac] = (dev->pci_conf[0xac] & ~0x0f) | (val & 0x0f); + break; + + case 0xfc: + if (dev->id == VIA_8601) + dev->pci_conf[0xfc] = (dev->pci_conf[0xfc] & ~0x03) | (val & 0x03); + else if (dev->id > VIA_597) + dev->pci_conf[0xfc] = (dev->pci_conf[0xfc] & ~0x01) | (val & 0x01); + break; + + case 0xfd: + if (dev->id == VIA_8601) + dev->pci_conf[0xfd] = (dev->pci_conf[0xfd] & ~0x07) | (val & 0x07); + else + dev->pci_conf[0xfd] = val; break; default: - dev->pci_conf[1][addr] = val; + dev->pci_conf[addr] = val; break; } } @@ -490,10 +671,7 @@ via_apollo_read(int func, int addr, void *priv) switch(func) { case 0: - ret = dev->pci_conf[0][addr]; - break; - case 1: - ret = dev->pci_conf[1][addr]; + ret = dev->pci_conf[addr]; break; } @@ -508,9 +686,6 @@ via_apollo_write(int func, int addr, uint8_t val, void *priv) case 0: via_apollo_host_bridge_write(func, addr, val, priv); break; - case 1: - via_apollo_pci_bridge_write(func, addr, val, priv); - break; } } @@ -530,9 +705,44 @@ via_apollo_init(const device_t *info) via_apollo_t *dev = (via_apollo_t *) malloc(sizeof(via_apollo_t)); memset(dev, 0, sizeof(via_apollo_t)); + dev->smram = smram_add(); + if (dev->id != VIA_8601) + apollo_smram_map(dev, 1, 0x000a0000, 0x00020000, 1); /* SMM: Code DRAM, Data DRAM */ + pci_add_card(PCI_ADD_NORTHBRIDGE, via_apollo_read, via_apollo_write, dev); dev->id = info->local; + + switch (dev->id) { + case VIA_597: + device_add(&via_vp3_agp_device); + break; + + case VIA_691: + device_add(&via_apro_agp_device); + break; + + case VIA_8601: + device_add(&via_vt8601_agp_device); + break; + + case VIA_598: + case VIA_693A: + case VIA_694: + device_add(&via_mvp3_agp_device); + break; + } + + if (dev->id >= VIA_597) + dev->agpgart = device_add(&agpgart_device); + + if ((dev->id >= VIA_694) && (dev->id != VIA_8601)) + dev->drb_unit = 16; + else if (dev->id >= VIA_597) + dev->drb_unit = 8; + else + dev->drb_unit = 4; + via_apollo_setup(dev); via_apollo_reset(dev); @@ -545,47 +755,119 @@ via_apollo_close(void *priv) { via_apollo_t *dev = (via_apollo_t *) priv; + smram_del(dev->smram); + free(dev); } - -const device_t via_vp3_device = -{ - "VIA Apollo VP3", - DEVICE_PCI, - 0x0597, /*VT82C597*/ - via_apollo_init, - via_apollo_close, - via_apollo_reset, - NULL, - NULL, - NULL, - NULL +const device_t via_vpx_device = { + .name = "VIA Apollo VPX", + .internal_name = "via_vpx", + .flags = DEVICE_PCI, + .local = VIA_585, /*VT82C585*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t via_mvp3_device = -{ - "VIA Apollo MVP3", - DEVICE_PCI, - 0x0598, /*VT82C598MVP*/ - via_apollo_init, - via_apollo_close, - via_apollo_reset, - NULL, - NULL, - NULL, - NULL +const device_t amd640_device = { + .name = "AMD 640 System Controller", + .internal_name = "amd640", + .flags = DEVICE_PCI, + .local = VIA_595, /*VT82C595*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vp3_device = { + .name = "VIA Apollo VP3", + .internal_name = "via_vp3", + .flags = DEVICE_PCI, + .local = VIA_597, /*VT82C597*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_mvp3_device = { + .name = "VIA Apollo MVP3", + .internal_name = "via_mvp3", + .flags = DEVICE_PCI, + .local = VIA_598, /*VT82C598MVP*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t via_apro_device = { - "VIA Apollo Pro", - DEVICE_PCI, - 0x0691, /*VT82C691*/ - via_apollo_init, - via_apollo_close, - via_apollo_reset, - NULL, - NULL, - NULL, - NULL + .name = "VIA Apollo Pro", + .internal_name = "via_apro", + .flags = DEVICE_PCI, + .local = VIA_691, /*VT82C691*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_apro133_device = { + .name = "VIA Apollo Pro133", + .internal_name = "via_apro133", + .flags = DEVICE_PCI, + .local = VIA_693A, /*VT82C693A*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_apro133a_device = { + .name = "VIA Apollo Pro133A", + .internal_name = "via_apro_133a", + .flags = DEVICE_PCI, + .local = VIA_694, /*VT82C694X*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt8601_device = { + .name = "VIA Apollo ProMedia", + .internal_name = "via_vt8601", + .flags = DEVICE_PCI, + .local = VIA_8601, /*VT8601*/ + .init = via_apollo_init, + .close = via_apollo_close, + .reset = via_apollo_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c new file mode 100644 index 000000000..b8c06b9f4 --- /dev/null +++ b/src/chipset/via_pipc.c @@ -0,0 +1,1716 @@ +/* + * 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. + * + * Emulation of the VIA PIPC southbridges. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * RichardG, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2020 Melissa Goad. + * Copyright 2020-2021 RichardG. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/scsi_device.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/apm.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/acpi.h> +#include <86box/ddma.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/port_92.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/usb.h> +#include <86box/machine.h> +#include <86box/smbus.h> +#include <86box/chipset.h> +#include <86box/sio.h> +#include <86box/hwm.h> +#include <86box/gameport.h> +#include <86box/sound.h> +#include <86box/snd_ac97.h> +#include <86box/snd_sb.h> +#include <86box/nmi.h> + +/* Most revision numbers (PCI-ISA bridge or otherwise) were lifted from PCI device + listings on forums, as VIA's datasheets are not very helpful regarding those. */ +#define VIA_PIPC_586A 0x05862500 +#define VIA_PIPC_586B 0x05864700 +#define VIA_PIPC_596A 0x05960900 +#define VIA_PIPC_596B 0x05962300 +#define VIA_PIPC_686A 0x06861400 +#define VIA_PIPC_686B 0x06864000 +#define VIA_PIPC_8231 0x82311000 + + +enum { + TRAP_DRQ = 0, + TRAP_PIRQ, + TRAP_PIDE_MAIN, + TRAP_PIDE_SIDE, + TRAP_SIDE_MAIN, + TRAP_SIDE_SIDE, + TRAP_FLP_MAIN, + TRAP_FLP_SIDE, + TRAP_COM1, + TRAP_COM3, + TRAP_COM2, + TRAP_COM4, + TRAP_LPT1, + TRAP_LPT2, + TRAP_VGA, + TRAP_KBC, + TRAP_AUD_MIDI_0, + TRAP_AUD_MIDI_1, + TRAP_AUD_MIDI_2, + TRAP_AUD_MIDI_3, + TRAP_AUD_SB_0, + TRAP_AUD_SB_1, + TRAP_AUD_SB_2, + TRAP_AUD_SB_3, + TRAP_AUD_GAME, + TRAP_AUD_WSS_0, + TRAP_AUD_WSS_1, + TRAP_AUD_WSS_2, + TRAP_AUD_WSS_3, + TRAP_GR0, + TRAP_GR1, + TRAP_GR2, + TRAP_GR3, + TRAP_MAX +}; + +typedef struct { + struct _pipc_ *dev; + void *trap; + uint32_t *sts_reg, *en_reg, mask; +} pipc_io_trap_t; + +typedef struct _pipc_ { + uint32_t local; + uint8_t max_func, max_pcs; + + uint8_t pci_isa_regs[256], + ide_regs[256], + usb_regs[2][256], + power_regs[256], + ac97_regs[2][256], fmnmi_regs[4]; + + sff8038i_t *bm[2]; + nvr_t *nvr; + int nvr_enabled, slot; + ddma_t *ddma; + smbus_piix4_t *smbus; + usb_t *usb[2]; + + acpi_t *acpi; + pipc_io_trap_t io_traps[TRAP_MAX]; + + void *gameport, *ac97, *sio, *hwm; + sb_t *sb; + uint16_t midigame_base, sb_base, fmnmi_base; +} pipc_t; + + +#ifdef ENABLE_PIPC_LOG +int pipc_do_log = ENABLE_PIPC_LOG; + + +static void +pipc_log(const char *fmt, ...) +{ + va_list ap; + + if (pipc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pipc_log(fmt, ...) +#endif + + +static void pipc_sgd_handlers(pipc_t *dev, uint8_t modem); +static void pipc_codec_handlers(pipc_t *dev, uint8_t modem); +static void pipc_sb_handlers(pipc_t *dev, uint8_t modem); +static uint8_t pipc_read(int func, int addr, void *priv); +static void pipc_write(int func, int addr, uint8_t val, void *priv); + + +static void +pipc_io_trap_pact(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + pipc_io_trap_t *trap = (pipc_io_trap_t *) priv; + + if (*(trap->en_reg) & trap->mask) { + *(trap->sts_reg) |= trap->mask; + trap->dev->acpi->regs.glbsts |= 0x0001; + if (trap->dev->acpi->regs.glben & 0x0001) + acpi_raise_smi(trap->dev->acpi, 1); + } +} + + +static void +pipc_io_trap_glb(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + pipc_io_trap_t *trap = (pipc_io_trap_t *) priv; + + if (*(trap->en_reg) & trap->mask) { + *(trap->sts_reg) |= trap->mask; + if (trap->dev->local >= VIA_PIPC_686A) { + if (write) + trap->dev->acpi->regs.extsmi_val |= 0x1000; + else + trap->dev->acpi->regs.extsmi_val &= ~0x1000; + } + acpi_raise_smi(trap->dev->acpi, 1); + } +} + + +static void +pipc_reset_hard(void *priv) +{ + int i; + + pipc_log("PIPC: reset_hard()\n"); + + pipc_t *dev = (pipc_t *) priv; + uint16_t old_base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); + + sff_bus_master_reset(dev->bm[0], old_base); + sff_bus_master_reset(dev->bm[1], old_base + 8); + + memset(dev->pci_isa_regs, 0, 256); + memset(dev->ide_regs, 0, 256); + memset(dev->usb_regs, 0, 512); + memset(dev->power_regs, 0, 256); + memset(dev->ac97_regs, 0, 512); + + /* PCI-ISA bridge registers. */ + dev->pci_isa_regs[0x00] = 0x06; dev->pci_isa_regs[0x01] = 0x11; + dev->pci_isa_regs[0x02] = dev->local >> 16; + dev->pci_isa_regs[0x03] = dev->local >> 24; + dev->pci_isa_regs[0x04] = (dev->local <= VIA_PIPC_586B) ? 0x0f : 0x87; + dev->pci_isa_regs[0x07] = 0x02; + dev->pci_isa_regs[0x08] = dev->local >> 8; + dev->pci_isa_regs[0x0a] = 0x01; + dev->pci_isa_regs[0x0b] = 0x06; + dev->pci_isa_regs[0x0e] = 0x80; + + dev->pci_isa_regs[0x48] = 0x01; + dev->pci_isa_regs[0x4a] = 0x04; + dev->pci_isa_regs[0x4f] = 0x03; + + dev->pci_isa_regs[0x50] = (dev->local >= VIA_PIPC_686A) ? 0x0e : 0x24; /* 686A/B default value does not line up with default bits */ + dev->pci_isa_regs[0x59] = 0x04; + if (dev->local >= VIA_PIPC_686A) + dev->pci_isa_regs[0x5a] = dev->pci_isa_regs[0x5f] = 0x04; + + dma_e = 0x00; + for (i = 0; i < 8; i++) { + dma[i].ab &= 0xffff000f; + dma[i].ac &= 0xffff000f; + } + + pic_set_shadow(0); + + dev->max_pcs = (dev->local >= VIA_PIPC_686A) ? 3 : 1; + + /* IDE registers. */ + dev->max_func++; + dev->ide_regs[0x00] = 0x06; dev->ide_regs[0x01] = 0x11; + dev->ide_regs[0x02] = 0x71; dev->ide_regs[0x03] = 0x05; + dev->ide_regs[0x04] = 0x80; + dev->ide_regs[0x06] = (dev->local == VIA_PIPC_686A) ? 0x90 : 0x80; dev->ide_regs[0x07] = 0x02; + dev->ide_regs[0x08] = (dev->local == VIA_PIPC_596B) ? 0x10 : 0x06; /* only 596B has rev 0x10? */ + dev->ide_regs[0x09] = 0x85; + dev->ide_regs[0x0a] = 0x01; + dev->ide_regs[0x0b] = 0x01; + + dev->ide_regs[0x10] = 0xf1; dev->ide_regs[0x11] = 0x01; + dev->ide_regs[0x14] = 0xf5; dev->ide_regs[0x15] = 0x03; + dev->ide_regs[0x18] = 0x71; dev->ide_regs[0x19] = 0x01; + dev->ide_regs[0x1c] = 0x75; dev->ide_regs[0x1d] = 0x03; + dev->ide_regs[0x20] = 0x01; dev->ide_regs[0x21] = 0xcc; + if (dev->local >= VIA_PIPC_686A) + dev->ide_regs[0x34] = 0xc0; + dev->ide_regs[0x3c] = 0x0e; + + if (dev->local <= VIA_PIPC_586B) + dev->ide_regs[0x40] = 0x04; + dev->ide_regs[0x41] = (dev->local == VIA_PIPC_686B) ? 0x06 : 0x02; + dev->ide_regs[0x42] = 0x09; + dev->ide_regs[0x43] = (dev->local >= VIA_PIPC_686A) ? 0x0a : 0x3a; + dev->ide_regs[0x44] = 0x68; + if (dev->local == VIA_PIPC_686B) + dev->ide_regs[0x45] = 0x20; + else if (dev->local >= VIA_PIPC_8231) + dev->ide_regs[0x45] = 0x03; + dev->ide_regs[0x46] = 0xc0; + dev->ide_regs[0x48] = 0xa8; dev->ide_regs[0x49] = 0xa8; + dev->ide_regs[0x4a] = 0xa8; dev->ide_regs[0x4b] = 0xa8; + dev->ide_regs[0x4c] = 0xff; + if (dev->local != VIA_PIPC_686B) + dev->ide_regs[0x4e] = dev->ide_regs[0x4f] = 0xff; + dev->ide_regs[0x50] = dev->ide_regs[0x51] = dev->ide_regs[0x52] = dev->ide_regs[0x53] = ((dev->local == VIA_PIPC_686A) || (dev->local == VIA_PIPC_686B)) ? 0x07 : 0x03; + if (dev->local >= VIA_PIPC_596A) + dev->ide_regs[0x54] = ((dev->local == VIA_PIPC_686A) || (dev->local == VIA_PIPC_686B)) ? 0x04 : 0x06; + + dev->ide_regs[0x61] = 0x02; + dev->ide_regs[0x69] = 0x02; + + if (dev->local >= VIA_PIPC_686A) { + dev->ide_regs[0xc0] = 0x01; + dev->ide_regs[0xc2] = 0x02; + } + + /* USB registers. */ + for (i = 0; i <= (dev->local >= VIA_PIPC_686A); i++) { + dev->max_func++; + dev->usb_regs[i][0x00] = 0x06; dev->usb_regs[i][0x01] = 0x11; + dev->usb_regs[i][0x02] = 0x38; dev->usb_regs[i][0x03] = 0x30; + dev->usb_regs[i][0x04] = 0x00; dev->usb_regs[i][0x05] = 0x00; + dev->usb_regs[i][0x06] = 0x00; dev->usb_regs[i][0x07] = 0x02; + switch (dev->local) { + case VIA_PIPC_586A: + case VIA_PIPC_586B: + case VIA_PIPC_596A: + dev->usb_regs[i][0x08] = 0x02; + break; + + case VIA_PIPC_596B: + dev->usb_regs[i][0x08] = 0x08; + break; + + case VIA_PIPC_686A: + dev->usb_regs[i][0x08] = 0x06; + break; + + case VIA_PIPC_686B: + dev->usb_regs[i][0x08] = 0x1a; + break; + + case VIA_PIPC_8231: + dev->usb_regs[i][0x08] = 0x1e; + break; + } + + dev->usb_regs[i][0x0a] = 0x03; + dev->usb_regs[i][0x0b] = 0x0c; + dev->usb_regs[i][0x0d] = 0x16; + dev->usb_regs[i][0x20] = 0x01; + dev->usb_regs[i][0x21] = 0x03; + if (dev->local == VIA_PIPC_686B) + dev->usb_regs[i][0x34] = 0x80; + dev->usb_regs[i][0x3d] = 0x04; + + dev->usb_regs[i][0x60] = 0x10; + if (dev->local >= VIA_PIPC_686A) { + dev->usb_regs[i][0x80] = 0x01; + dev->usb_regs[i][0x82] = 0x02; + } + dev->usb_regs[i][0xc1] = 0x20; + } + + /* Power management registers. */ + if (dev->acpi) { + dev->max_func++; + dev->power_regs[0x00] = 0x06; dev->power_regs[0x01] = 0x11; + if (dev->local >= VIA_PIPC_8231) { + /* The VT8231 preliminary datasheet lists *two* inaccurate + device IDs (3068 and 3057). Real dumps have 8235. */ + dev->power_regs[0x02] = 0x35; dev->power_regs[0x03] = 0x82; + } else { + if (dev->local <= VIA_PIPC_586B) + dev->power_regs[0x02] = 0x40; + else if (dev->local <= VIA_PIPC_596B) + dev->power_regs[0x02] = 0x50; + else + dev->power_regs[0x02] = 0x57; + dev->power_regs[0x03] = 0x30; + } + dev->power_regs[0x04] = 0x00; dev->power_regs[0x05] = 0x00; + dev->power_regs[0x06] = (dev->local == VIA_PIPC_686B) ? 0x90 : 0x80; dev->power_regs[0x07] = 0x02; + switch (dev->local) { + case VIA_PIPC_586B: + case VIA_PIPC_686A: + case VIA_PIPC_8231: + dev->power_regs[0x08] = 0x10; + break; + + case VIA_PIPC_596A: + dev->power_regs[0x08] = 0x20; + break; + + case VIA_PIPC_596B: + dev->power_regs[0x08] = 0x30; + break; + + case VIA_PIPC_686B: + dev->power_regs[0x08] = 0x40; + break; + } + if (dev->local == VIA_PIPC_686B) + dev->power_regs[0x34] = 0x68; + dev->power_regs[0x40] = 0x20; + + dev->power_regs[0x42] = 0x50; + dev->power_regs[0x48] = 0x01; + + if (dev->local == VIA_PIPC_686B) { + dev->power_regs[0x68] = 0x01; + dev->power_regs[0x6a] = 0x02; + } + + if (dev->local >= VIA_PIPC_686A) + dev->power_regs[0x70] = 0x01; + + if (dev->local == VIA_PIPC_596A) + dev->power_regs[0x80] = 0x01; + else if (dev->local >= VIA_PIPC_596B) + dev->power_regs[0x90] = 0x01; + + /* Set up PCS I/O traps. */ + pipc_io_trap_t *trap; + for (i = 0; i <= dev->max_pcs; i++) { + trap = &dev->io_traps[TRAP_GR0 + i]; + trap->dev = dev; + trap->trap = io_trap_add(pipc_io_trap_glb, trap); + if (i & 2) { + trap->sts_reg = (uint32_t *) &dev->acpi->regs.extiotrapsts; + trap->en_reg = (uint32_t *) &dev->acpi->regs.extiotrapen; + trap->mask = 0x01 << (i & 1); + } else { + trap->sts_reg = &dev->acpi->regs.glbsts; + trap->en_reg = &dev->acpi->regs.glben; + trap->mask = 0x4000 << i; + } + } + } + + /* AC97/MC97 registers. */ + if (dev->local >= VIA_PIPC_686A) { + for (i = 0; i <= 1; i++) { + dev->max_func++; + dev->ac97_regs[i][0x00] = 0x06; dev->ac97_regs[i][0x01] = 0x11; + dev->ac97_regs[i][0x02] = 0x58 + (0x10 * i); dev->ac97_regs[i][0x03] = 0x30; + dev->ac97_regs[i][0x06] = 0x10 * (1 - i); dev->ac97_regs[i][0x07] = 0x02; + switch (dev->local) { + case VIA_PIPC_686A: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x12 : 0x01; + break; + + case VIA_PIPC_686B: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x50 : 0x30; + break; + + case VIA_PIPC_8231: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x40 : 0x20; + break; + } + + if (i == 0) { + dev->ac97_regs[i][0x0a] = 0x01; + dev->ac97_regs[i][0x0b] = 0x04; + } else { + dev->ac97_regs[i][0x0a] = 0x80; + dev->ac97_regs[i][0x0b] = 0x07; + } + + dev->ac97_regs[i][0x10] = 0x01; + if (i == 0) { + dev->ac97_regs[i][0x14] = 0x01; + dev->ac97_regs[i][0x18] = 0x01; + } + dev->ac97_regs[i][0x1c] = 0x01; + + dev->ac97_regs[i][0x3d] = 0x03; + + if (i == 0) + dev->ac97_regs[i][0x40] = 0x01; + + dev->ac97_regs[i][0x43] = 0x1c; + dev->ac97_regs[i][0x48] = 0x01; + dev->ac97_regs[i][0x4b] = 0x02; + + pipc_sgd_handlers(dev, i); + pipc_codec_handlers(dev, i); + pipc_sb_handlers(dev, i); + } + } + + if (dev->gameport) + gameport_remap(dev->gameport, 0x200); + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + if (dev->local <= VIA_PIPC_586B) { + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + if (dev->local == VIA_PIPC_586B) + pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED); + } + + ide_pri_disable(); + ide_sec_disable(); + + nvr_via_wp_set(0x00, 0x32, dev->nvr); + nvr_via_wp_set(0x00, 0x0d, dev->nvr); +} + + +static void +pipc_ide_handlers(pipc_t *dev) +{ + uint16_t main, side; + + ide_pri_disable(); + ide_sec_disable(); + + if (dev->ide_regs[0x09] & 0x01) { + main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8); + side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2; + } else { + main = 0x1f0; + side = 0x3f6; + } + ide_set_base(0, main); + ide_set_side(0, side); + + if (dev->ide_regs[0x09] & 0x04) { + main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8); + side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2; + } else { + main = 0x170; + side = 0x376; + } + ide_set_base(1, main); + ide_set_side(1, side); + + if (dev->ide_regs[0x04] & PCI_COMMAND_IO) { + if (dev->ide_regs[0x40] & 0x02) + ide_pri_enable(); + if (dev->ide_regs[0x40] & 0x01) + ide_sec_enable(); + } +} + + +static void +pipc_ide_irqs(pipc_t *dev) +{ + int irq_mode[2] = { 0, 0 }; + + if (dev->ide_regs[0x09] & 0x01) + irq_mode[0] = (dev->ide_regs[0x3d] & 0x01); + + if (dev->ide_regs[0x09] & 0x04) + irq_mode[1] = (dev->ide_regs[0x3d] & 0x01); + + sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]); + sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]); + + sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]); + sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]); +} + + +static void +pipc_bus_master_handlers(pipc_t *dev) +{ + uint16_t base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); + + sff_bus_master_handler(dev->bm[0], (dev->ide_regs[0x04] & 1), base); + sff_bus_master_handler(dev->bm[1], (dev->ide_regs[0x04] & 1), base + 8); +} + + +static void +pipc_pcs_update(pipc_t *dev) +{ + uint8_t i, io_base_reg, io_mask_reg, io_mask_shift, enable; + uint16_t io_base, io_mask; + + for (i = 0; i <= dev->max_pcs; i++) { + if (i & 2) { + io_base_reg = 0x8c; + io_mask_reg = 0x8a; + } else { + io_base_reg = 0x78; + io_mask_reg = 0x80; + } + io_base_reg |= (i & 1) << 1; + io_mask_shift = (i & 1) << 2; + + if (dev->local <= VIA_PIPC_596B) + enable = dev->pci_isa_regs[0x76] & (0x10 << i); + else + enable = dev->pci_isa_regs[0x8b] & (0x01 << i); + + io_base = dev->pci_isa_regs[io_base_reg] | (dev->pci_isa_regs[io_base_reg | 1] << 8); + io_mask = (dev->pci_isa_regs[io_mask_reg] >> io_mask_shift) & 0x000f; + + pipc_log("PIPC: Mapping PCS%d to %04X-%04X (enable %d)\n", i, io_base, io_base + io_mask, enable); + io_trap_remap(dev->io_traps[TRAP_GR0 + i].trap, enable, io_base & ~io_mask, io_mask + 1); + } +} + + +static void +pipc_trap_update_paden(pipc_t *dev, uint8_t trap_id, + uint32_t paden_mask, uint8_t enable, + uint16_t addr, uint16_t size) +{ + pipc_io_trap_t *trap = &dev->io_traps[trap_id]; + enable = (dev->acpi->regs.paden & paden_mask) && enable; + + /* Set up Primary Activity Detect I/O traps dynamically. */ + if (enable && !trap->trap) { + trap->dev = dev; + trap->trap = io_trap_add(pipc_io_trap_pact, trap); + trap->sts_reg = &dev->acpi->regs.padsts; + trap->en_reg = &dev->acpi->regs.paden; + trap->mask = paden_mask; + } + + /* Remap I/O trap. */ + io_trap_remap(trap->trap, enable, addr, size); +} + + +static void +pipc_trap_update_586(void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + + /* TRAP_DRQ (00000001) and TRAP_PIRQ (00000002) not implemented. */ + + pipc_trap_update_paden(dev, TRAP_PIDE_MAIN, 0x00000008, 1, 0x1f0, 8); + pipc_trap_update_paden(dev, TRAP_SIDE_MAIN, 0x00000008, 1, 0x170, 8); + pipc_trap_update_paden(dev, TRAP_FLP_MAIN, 0x00000008, 1, 0x3f5, 1); + + pipc_trap_update_paden(dev, TRAP_VGA, 0x00000010, 1, 0x3b0, 48); + /* [A0000:BFFFF] memory trap not implemented. */ + + pipc_trap_update_paden(dev, TRAP_LPT1, 0x00000020, 1, 0x378, 8); + pipc_trap_update_paden(dev, TRAP_LPT2, 0x00000020, 1, 0x278, 8); + + pipc_trap_update_paden(dev, TRAP_COM1, 0x00000040, 1, 0x3f8, 8); + pipc_trap_update_paden(dev, TRAP_COM2, 0x00000040, 1, 0x2f8, 8); + pipc_trap_update_paden(dev, TRAP_COM3, 0x00000040, 1, 0x3e8, 8); + pipc_trap_update_paden(dev, TRAP_COM4, 0x00000040, 1, 0x2e8, 8); + + pipc_trap_update_paden(dev, TRAP_KBC, 0x00000080, 1, 0x60, 1); +} + + +static void +pipc_trap_update_596(void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + int i; + + /* TRAP_DRQ (00000001) and TRAP_PIRQ (00000002) not implemented. */ + + pipc_trap_update_paden(dev, TRAP_PIDE_MAIN, 0x00000004, 1, 0x1f0, 8); + pipc_trap_update_paden(dev, TRAP_PIDE_SIDE, 0x00000004, 1, 0x3f6, 1); + + pipc_trap_update_paden(dev, TRAP_SIDE_MAIN, 0x00000008, 1, 0x170, 8); + pipc_trap_update_paden(dev, TRAP_SIDE_SIDE, 0x00000008, 1, 0x376, 1); + + pipc_trap_update_paden(dev, TRAP_FLP_MAIN, 0x00000010, 1, 0x3f0, 6); + pipc_trap_update_paden(dev, TRAP_FLP_SIDE, 0x00000010, 1, 0x3f7, 1); + + pipc_trap_update_paden(dev, TRAP_COM1, 0x00000020, 1, 0x3f8, 8); + pipc_trap_update_paden(dev, TRAP_COM3, 0x00000020, 1, 0x3e8, 8); + + pipc_trap_update_paden(dev, TRAP_COM2, 0x00000040, 1, 0x2f8, 8); + pipc_trap_update_paden(dev, TRAP_COM4, 0x00000040, 1, 0x2e8, 8); + + pipc_trap_update_paden(dev, TRAP_LPT1, 0x00000080, 1, 0x378, 8); + pipc_trap_update_paden(dev, TRAP_LPT2, 0x00000080, 1, 0x278, 8); + + pipc_trap_update_paden(dev, TRAP_VGA, 0x00000100, 1, 0x3b0, 48); + /* [A0000:BFFFF] memory trap not implemented. */ + + pipc_trap_update_paden(dev, TRAP_KBC, 0x00000200, 1, 0x60, 1); + + /* The following traps are poorly documented and assumed to operate on all ranges allowed + by the Positive Decoding Control registers. I couldn't probe this behavior on hardware. + It's better to be safe and cover all of them than to assume Intel-like behavior (one range). */ + + for (i = 0; i < 3; i++) { + pipc_trap_update_paden(dev, TRAP_AUD_MIDI_0 + i, + 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x01), + 0x300 + (0x10 * i), 4); + + pipc_trap_update_paden(dev, TRAP_AUD_SB_0 + i, + 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x02), + 0x220 + (0x20 * i), 20); + } + + pipc_trap_update_paden(dev, TRAP_AUD_GAME, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x04), 0x200, 8); + + pipc_trap_update_paden(dev, TRAP_AUD_WSS_0, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0x530, 8); + pipc_trap_update_paden(dev, TRAP_AUD_WSS_1, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0x604, 8); + pipc_trap_update_paden(dev, TRAP_AUD_WSS_2, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0xe80, 8); + pipc_trap_update_paden(dev, TRAP_AUD_WSS_3, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0xf40, 8); +} + + +static void +pipc_sgd_handlers(pipc_t *dev, uint8_t modem) +{ + if (!dev->ac97) + return; + + if (modem) + ac97_via_remap_modem_sgd(dev->ac97, dev->ac97_regs[1][0x11] << 8, dev->ac97_regs[1][0x04] & PCI_COMMAND_IO); + else + ac97_via_remap_audio_sgd(dev->ac97, dev->ac97_regs[0][0x11] << 8, dev->ac97_regs[0][0x04] & PCI_COMMAND_IO); +} + + +static void +pipc_codec_handlers(pipc_t *dev, uint8_t modem) +{ + if (!dev->ac97) + return; + + if (modem) + ac97_via_remap_modem_codec(dev->ac97, dev->ac97_regs[1][0x1d] << 8, dev->ac97_regs[1][0x04] & PCI_COMMAND_IO); + else + ac97_via_remap_audio_codec(dev->ac97, dev->ac97_regs[0][0x1d] << 8, dev->ac97_regs[0][0x04] & PCI_COMMAND_IO); +} + + +static uint8_t +pipc_fmnmi_read(uint16_t addr, void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + uint8_t ret = dev->fmnmi_regs[addr & 0x03]; + + pipc_log("PIPC: fmnmi_read(%02X) = %02X\n", addr & 0x03, ret); + +#ifdef VIA_PIPC_FM_EMULATION + /* Clear NMI/SMI if enabled. */ + if (dev->ac97_regs[0][0x48] & 0x01) { + if (dev->ac97_regs[0][0x48] & 0x04) + smi_line = 0; + else + nmi = 0; + } +#endif + + return ret; +} + + +static void +pipc_fmnmi_handlers(pipc_t *dev, uint8_t modem) +{ + if (!dev->ac97 || modem) + return; + + if (dev->fmnmi_base) + io_removehandler(dev->fmnmi_base, 4, pipc_fmnmi_read, NULL, NULL, NULL, NULL, NULL, dev); + + dev->fmnmi_base = (dev->ac97_regs[0][0x15] << 8) | (dev->ac97_regs[0][0x14] & 0xfc); + + if (dev->fmnmi_base && (dev->ac97_regs[0][0x04] & PCI_COMMAND_IO)) + io_sethandler(dev->fmnmi_base, 4, pipc_fmnmi_read, NULL, NULL, NULL, NULL, NULL, dev); +} + + +static uint8_t +pipc_fm_read(uint16_t addr, void *priv) +{ +#ifdef VIA_PIPC_FM_EMULATION + uint8_t ret = 0x00; +#else + pipc_t *dev = (pipc_t *) priv; + uint8_t ret = dev->sb->opl.read(addr, dev->sb->opl.priv); +#endif + + pipc_log("PIPC: fm_read(%02X) = %02X\n", addr & 0x03, ret); + + return ret; +} + + +static void +pipc_fm_write(uint16_t addr, uint8_t val, void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + + pipc_log("PIPC: fm_write(%02X, %02X)\n", addr & 0x03, val); + +#ifdef VIA_PIPC_FM_EMULATION + /* Real 686B only updates the bank ID register when writing to the + index port, and only fires NMI/SMI when writing to the data port. */ + if (!(addr & 0x01)) { + dev->fmnmi_regs[0x00] = (addr & 0x02) ? 0x02 : 0x01; + dev->fmnmi_regs[0x01] = val; + } else { + dev->fmnmi_regs[0x02] = val; + + /* Fire NMI/SMI if enabled. */ + if (dev->ac97_regs[0][0x48] & 0x01) { + if (dev->ac97_regs[0][0x48] & 0x04) + smi_raise(); + else + nmi_raise(); + } + } +#else + dev->sb->opl.write(addr, val, dev->sb->opl.priv); +#endif +} + + +static void +pipc_sb_handlers(pipc_t *dev, uint8_t modem) +{ + if (!dev->ac97 || modem) + return; + + sb_dsp_setaddr(&dev->sb->dsp, 0); + if (dev->sb_base) { + io_removehandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + } + + mpu401_change_addr(dev->sb->mpu, 0); + mpu401_setirq(dev->sb->mpu, 0); + + io_removehandler(0x388, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + + if (dev->ac97_regs[0][0x42] & 0x01) { + dev->sb_base = 0x220 + (0x20 * (dev->ac97_regs[0][0x43] & 0x03)); + sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); + if (dev->ac97_regs[0][0x42] & 0x04) { + io_sethandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + } + io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + + uint8_t irq = 5 + (2 * ((dev->ac97_regs[0][0x43] >> 6) & 0x03)); + sb_dsp_setirq(&dev->sb->dsp, (irq == 11) ? 10 : irq); + + sb_dsp_setdma8(&dev->sb->dsp, (dev->ac97_regs[0][0x43] >> 4) & 0x03); + + /* Set up CD audio filter. This might not actually work if VIAUDIO writes to CD volume through AC97. */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); + } + + if (dev->ac97_regs[0][0x42] & 0x02) { + /* BAR 2 is a mess. The MPU and game port remapping registers that VIA claims to be there don't + seem to actually exist on a real 686B. Remapping the MPU to BAR 2 itself does work, though. */ + if (dev->ac97_regs[0][0x42] & 0x80) + mpu401_change_addr(dev->sb->mpu, (dev->ac97_regs[0][0x19] << 8) | (dev->ac97_regs[0][0x18] & 0xfc)); + else + mpu401_change_addr(dev->sb->mpu, 0x300 | ((dev->ac97_regs[0][0x43] << 2) & 0x30)); + + if (!(dev->ac97_regs[0][0x42] & 0x40)) + mpu401_setirq(dev->sb->mpu, dev->sb->dsp.sb_irqnum); + } + + if (dev->ac97_regs[0][0x42] & 0x04) { + io_sethandler(0x388, 4, pipc_fm_read, NULL, NULL, pipc_fm_write, NULL, NULL, dev); + } +} + + +static uint8_t +pipc_read(int func, int addr, void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + uint8_t ret = 0xff; + int c; + uint8_t pm_func = dev->usb[1] ? 4 : 3; + + if (func > dev->max_func) + return ret; + else if (func == 0) { /* PCI-ISA bridge */ + if ((addr >= 0x60) && (addr <= 0x6f)) { /* DMA shadow registers */ + c = (addr & 0x0e) >> 1; + if (addr & 0x01) + ret = (dma[c].ab & 0x0000ff00) >> 8; + else { + ret = (dma[c].ab & 0x000000f0); + ret |= (!!(dma_e & (1 << c)) << 3); + } + } else + ret = dev->pci_isa_regs[addr]; + } + else if ((func == 1) && !(dev->pci_isa_regs[0x48] & 0x02)) { /* IDE */ + ret = dev->ide_regs[addr]; + if ((addr >= 0x50) && (addr <= 0x53)) { /* UDMA timing registers */ + /* Set or clear bit 5 according to UDMA mode. Documentation is unclear, but a real + 686B does set bit 5 when UDMA is enabled through the method specified in bit 7. */ + c = 0x53 - addr; + if (ret & 0x80) /* bit 7 set = use bit 6 */ + c = ret & 0x40; + else if (ide_drives[c]) /* bit 7 clear = use SET FEATURES mode */ + c = (ide_drives[c]->mdma_mode & 0x300) == 0x300; + else /* no drive here */ + c = 0; + /* 586A/B datasheet claims bit 5 must be clear for UDMA, unlike later models where + it must be set, but the Windows driver doesn't care and always checks if it's set. */ + if (c) + ret |= 0x20; + else + ret &= ~0x20; + } + } + else if ((func < pm_func) && !((func == 2) ? (dev->pci_isa_regs[0x48] & 0x04) : (dev->pci_isa_regs[0x85] & 0x10))) /* USB */ + ret = dev->usb_regs[func - 2][addr]; + else if (func == pm_func) { /* Power */ + ret = dev->power_regs[addr]; + if (addr == 0x42) { + if (dev->nvr->regs[0x0d] & 0x80) + ret |= 0x10; + else + ret &= ~0x10; + } else if ((addr == 0xd2) && (dev->local == VIA_PIPC_686B)) { + /* SMBus clock select bit. */ + if (dev->smbus->clock == 16384) + ret &= ~0x10; + else + ret |= 0x10; + } + } + else if ((func <= (pm_func + 2)) && !(dev->pci_isa_regs[0x85] & ((func == (pm_func + 1)) ? 0x04 : 0x08))) { /* AC97 / MC97 */ + if (addr == 0x40) + ret = ac97_via_read_status(dev->ac97, func - pm_func - 1); + else + ret = dev->ac97_regs[func - pm_func - 1][addr]; + } + + pipc_log("PIPC: read(%d, %02X) = %02X\n", func, addr, ret); + + return ret; +} + + +static void +nvr_update_io_mapping(pipc_t *dev) +{ + if (dev->nvr_enabled) + nvr_at_handler(0, 0x0074, dev->nvr); + + if ((dev->pci_isa_regs[0x5b] & 0x02) || (dev->pci_isa_regs[0x48] & 0x08)) + nvr_at_handler(1, 0x0074, dev->nvr); +} + + +static void +usb_update_io_mapping(pipc_t *dev, int func) +{ + uhci_update_io_mapping(dev->usb[func - 2], dev->usb_regs[func - 2][0x20] & ~0x1f, dev->usb_regs[func - 2][0x21], dev->usb_regs[func - 2][PCI_REG_COMMAND] & PCI_COMMAND_IO); +} + + +static void +pipc_ddma_update(pipc_t *dev, int addr) +{ + uint32_t base; + + if (dev->local >= VIA_PIPC_8231) + return; + + base = (dev->pci_isa_regs[addr] & 0xf0) | (((uint32_t) dev->pci_isa_regs[addr | 0x01]) << 8); + ddma_update_io_mapping(dev->ddma, (addr & 0x0e) >> 1, (dev->pci_isa_regs[addr] & 0xf0), dev->pci_isa_regs[addr | 0x01], (dev->pci_isa_regs[addr] & 0x08) && (base != 0x0000)); +} + + +static void +pipc_write(int func, int addr, uint8_t val, void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + int c; + uint8_t pm_func = dev->usb[1] ? 4 : 3; + + if (func > dev->max_func) + return; + + pipc_log("PIPC: write(%d, %02X, %02X)\n", func, addr, val); + + if (func == 0) { /* PCI-ISA bridge */ + /* Read-only addresses. */ + if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) || (addr == 0x49) || (addr == 0x4b) || + (addr == 0x53) || ((addr >= 0x5d) && (addr < 0x5f)) || (addr >= 0x90)) + return; + + if ((dev->local <= VIA_PIPC_586A) && ((addr >= 0x58) && (addr < 0x80))) + return; + + if ((dev->local <= VIA_PIPC_586B) && (addr >= 0x74)) + return; + + if ((dev->local <= VIA_PIPC_596A) && ((addr == 0x51) || (addr == 0x52) || (addr == 0x5f) || (addr == 0x85) || + (addr == 0x86) || ((addr >= 0x8a) && (addr < 0x90)))) + return; + + switch (addr) { + case 0x04: + dev->pci_isa_regs[0x04] = (val & 8) | 7; + break; + case 0x07: + dev->pci_isa_regs[0x07] &= ~(val & 0xb0); + break; + + case 0x42: + dev->pci_isa_regs[0x42] = val & 0xcf; + + switch (val & 0xf) { + /* Divisors on the PCI clock. */ + case 0x8: + cpu_set_isa_pci_div(3); + break; + + case 0x9: + cpu_set_isa_pci_div(2); + break; + + /* case 0xa: same as default */ + + case 0xb: + cpu_set_isa_pci_div(6); + break; + + case 0xc: + cpu_set_isa_pci_div(5); + break; + + case 0xd: + cpu_set_isa_pci_div(10); + break; + + case 0xe: + cpu_set_isa_pci_div(12); + break; + + /* Half oscillator clock. */ + case 0xf: + cpu_set_isa_speed(7159091); + break; + + /* Divisor 4 on the PCI clock whenever bit 3 is clear. */ + default: + cpu_set_isa_pci_div(4); + break; + } + + break; + + case 0x47: + if (val & 0x01) + trc_write(0x0047, (val & 0x80) ? 0x06 : 0x04, NULL); + pic_set_shadow(!!(val & 0x10)); + pic_elcr_io_handler(!!(val & 0x20)); + dev->pci_isa_regs[0x47] = val & 0xfe; + break; + case 0x48: + dev->pci_isa_regs[0x48] = val; + nvr_update_io_mapping(dev); + break; + + case 0x50: case 0x51: case 0x52: case 0x85: + dev->pci_isa_regs[addr] = val; + /* Forward Super I/O-related registers to sio_vt82c686.c */ + if (dev->sio) + vt82c686_sio_write(addr, val, dev->sio); + break; + + case 0x54: + pci_set_irq_level(PCI_INTA, !(val & 8)); + pci_set_irq_level(PCI_INTB, !(val & 4)); + pci_set_irq_level(PCI_INTC, !(val & 2)); + pci_set_irq_level(PCI_INTD, !(val & 1)); + dev->pci_isa_regs[0x54] = val & 0x0f; + break; + case 0x55: + pipc_log("PIPC: Steering PIRQ%c to IRQ %d\n", (dev->local >= VIA_PIPC_596A) ? 'A' : 'D', val >> 4); + pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTA : PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); + if (dev->local <= VIA_PIPC_586B) { + pipc_log("PIPC: Steering MIRQ0 to IRQ %d\n", val & 0x0f); + pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + } + dev->pci_isa_regs[0x55] = val; + break; + case 0x56: + pipc_log("PIPC: Steering PIRQ%c to IRQ %d\n", (dev->local >= VIA_PIPC_596A) ? 'C' : 'A', val >> 4); + pipc_log("PIPC: Steering PIRQB to IRQ %d\n", val & 0x0f); + pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTC : PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + dev->pci_isa_regs[0x56] = val; + break; + case 0x57: + pipc_log("PIPC: Steering PIRQ%c to IRQ %d\n", (dev->local >= VIA_PIPC_596A) ? 'D' : 'C', val >> 4); + pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTD : PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); + if (dev->local <= VIA_PIPC_586B) { + pipc_log("PIPC: Steering MIRQ1 to IRQ %d\n", val & 0x0f); + pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + } + dev->pci_isa_regs[0x57] = val; + break; + case 0x58: + if (dev->local == VIA_PIPC_586B) { + pipc_log("PIPC: Steering MIRQ2 to IRQ %d\n", val & 0x0f); + pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + } + dev->pci_isa_regs[0x58] = val; + break; + case 0x5b: + dev->pci_isa_regs[0x5b] = val; + nvr_update_io_mapping(dev); + break; + + case 0x60: case 0x62: case 0x64: case 0x66: + case 0x6a: case 0x6c: case 0x6e: + dev->pci_isa_regs[addr] = val & 0xf8; + pipc_ddma_update(dev, addr); + break; + case 0x61: case 0x63: case 0x65: case 0x67: + case 0x6b: case 0x6d: case 0x6f: + dev->pci_isa_regs[addr] = val; + pipc_ddma_update(dev, addr & 0xfe); + break; + + case 0x70: case 0x71: case 0x72: case 0x73: + dev->pci_isa_regs[(addr - 0x44)] = val; + break; + + case 0x74: case 0x8b: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x80: case 0x8a: + dev->pci_isa_regs[addr] = val; + pipc_pcs_update(dev); + break; + + case 0x77: + if ((dev->local >= VIA_PIPC_686A) && (val & 0x10)) + pclog("PIPC: Warning: Internal I/O APIC enabled.\n"); + nvr_via_wp_set(!!(val & 0x04), 0x32, dev->nvr); + nvr_via_wp_set(!!(val & 0x02), 0x0d, dev->nvr); + break; + + default: + dev->pci_isa_regs[addr] = val; + break; + } + } else if (func == 1) { /* IDE */ + /* Read-only addresses. */ + if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) || + ((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) || + ((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) || + ((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) || + ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x55) && (addr < 0x60)) || + ((addr >= 0x62) && (addr < 0x68)) || ((addr >= 0x6a) && (addr < 0x70)) || + (addr == 0x72) || (addr == 0x73) || (addr == 0x76) || (addr == 0x77) || + (addr == 0x7a) || (addr == 0x7b) || (addr == 0x7e) || (addr == 0x7f) || + ((addr >= 0x84) && (addr < 0x88)) || (addr >= 0x8c)) + return; + + if ((dev->local <= VIA_PIPC_586B) && ((addr == 0x54) || (addr >= 0x70))) + return; + + /* Check disable bit. */ + if (dev->pci_isa_regs[0x48] & 0x02) + return; + + switch (addr) { + case 0x04: + dev->ide_regs[0x04] = val & 0x85; + pipc_ide_handlers(dev); + pipc_bus_master_handlers(dev); + break; + case 0x07: + dev->ide_regs[0x07] &= ~(val & 0xf1); + break; + + case 0x09: + dev->ide_regs[0x09] = (val & 0x05) | 0x8a; + pipc_ide_handlers(dev); + pipc_ide_irqs(dev); + break; + + case 0x10: + dev->ide_regs[0x10] = (val & 0xf8) | 1; + pipc_ide_handlers(dev); + break; + case 0x11: + dev->ide_regs[0x11] = val; + pipc_ide_handlers(dev); + break; + + case 0x14: + dev->ide_regs[0x14] = (val & 0xfc) | 1; + pipc_ide_handlers(dev); + break; + case 0x15: + dev->ide_regs[0x15] = val; + pipc_ide_handlers(dev); + break; + + case 0x18: + dev->ide_regs[0x18] = (val & 0xf8) | 1; + pipc_ide_handlers(dev); + break; + case 0x19: + dev->ide_regs[0x19] = val; + pipc_ide_handlers(dev); + break; + + case 0x1c: + dev->ide_regs[0x1c] = (val & 0xfc) | 1; + pipc_ide_handlers(dev); + break; + case 0x1d: + dev->ide_regs[0x1d] = val; + pipc_ide_handlers(dev); + break; + + case 0x20: + dev->ide_regs[0x20] = (val & 0xf0) | 1; + pipc_bus_master_handlers(dev); + break; + case 0x21: + dev->ide_regs[0x21] = val; + pipc_bus_master_handlers(dev); + break; + + case 0x3d: + dev->ide_regs[0x3d] = val & 0x01; + pipc_ide_irqs(dev); + break; + + case 0x40: + if (dev->local <= VIA_PIPC_586B) + dev->ide_regs[0x40] = (val & 0x03) | 0x04; + else + dev->ide_regs[0x40] = val & 0x0f; + pipc_ide_handlers(dev); + break; + + case 0x41: + if (dev->local <= VIA_PIPC_686A) + dev->ide_regs[0x41] = val; + else if (dev->local == VIA_PIPC_8231) + dev->ide_regs[0x41] = val & 0xf6; + else + dev->ide_regs[0x41] = val & 0xf2; + break; + + case 0x43: + if (dev->local <= VIA_PIPC_586A) + dev->ide_regs[0x43] = (val & 0x6f) | 0x10; + else if (dev->local <= VIA_PIPC_586B) + dev->ide_regs[0x43] = (val & 0xef) | 0x10; + else + dev->ide_regs[0x43] = val & 0x0f; + break; + + case 0x44: + if (dev->local <= VIA_PIPC_586A) + dev->ide_regs[0x44] = val & 0x78; + else if (dev->local <= VIA_PIPC_586B) + dev->ide_regs[0x44] = val & 0x7b; + else if (dev->local <= VIA_PIPC_596B) + dev->ide_regs[0x44] = val & 0x7f; + else if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) + dev->ide_regs[0x44] = val & 0x69; + else + dev->ide_regs[0x44] = val & 0x7d; + break; + + case 0x45: + if (dev->local <= VIA_PIPC_586B) + dev->ide_regs[0x45] = val & 0x40; + else if ((dev->local <= VIA_PIPC_596B) || (dev->local == VIA_PIPC_8231)) + dev->ide_regs[0x45] = val & 0x4f; + else if (dev->local <= VIA_PIPC_686A) + dev->ide_regs[0x45] = val & 0x5f; + else + dev->ide_regs[0x45] = (val & 0x5c) | 0x20; + break; + + case 0x46: + if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) + dev->ide_regs[0x46] = val & 0xf3; + else + dev->ide_regs[0x46] = val & 0xc0; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: + if (dev->local <= VIA_PIPC_586B) + dev->ide_regs[addr] = val & 0xc3; + else if (dev->local <= VIA_PIPC_596B) + dev->ide_regs[addr] = val & ((addr & 1) ? 0xc3 : 0xcb); + else if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) + dev->ide_regs[addr] = val & ((addr & 1) ? 0xc7 : 0xcf); + else + dev->ide_regs[addr] = val & 0xd7; + break; + + case 0x61: case 0x69: + dev->ide_regs[addr] = val & 0x0f; + break; + + default: + dev->ide_regs[addr] = val; + break; + } + } else if (func < pm_func) { /* USB */ + /* Read-only addresses. */ + if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) || + ((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) || + ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) || + ((addr >= 0x46) && (addr < 0x84)) || ((addr >= 0x85) && (addr < 0xc0)) || (addr >= 0xc2)) + return; + + if ((dev->local <= VIA_PIPC_596B) && (addr == 0x84)) + return; + + /* Check disable bits for both controllers. */ + if ((func == 2) ? (dev->pci_isa_regs[0x48] & 0x04) : (dev->pci_isa_regs[0x85] & 0x10)) + return; + + switch (addr) { + case 0x04: + dev->usb_regs[func - 2][0x04] = val & 0x97; + usb_update_io_mapping(dev, func); + break; + case 0x07: + dev->usb_regs[func - 2][0x07] &= ~(val & 0x78); + break; + + case 0x20: + dev->usb_regs[func - 2][0x20] = (val & ~0x1f) | 1; + usb_update_io_mapping(dev, func); + break; + case 0x21: + dev->usb_regs[func - 2][0x21] = val; + usb_update_io_mapping(dev, func); + break; + + default: + dev->usb_regs[func - 2][addr] = val; + break; + } + } else if (func == pm_func) { /* Power */ + /* Read-only addresses */ + if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x4a) || (addr == 0x4b) || + (addr == 0x4e) || (addr == 0x4f) || (addr == 0x56) || (addr == 0x57) || ((addr >= 0x5c) && (addr < 0x61)) || + ((addr >= 0x64) && (addr < 0x70)) || (addr == 0x72) || (addr == 0x73) || ((addr >= 0x75) && (addr < 0x80)) || + (addr == 0x83) || ((addr >= 0x85) && (addr < 0x90)) || ((addr >= 0x92) && (addr < 0xd2)) || (addr >= 0xd7)) + return; + + if ((dev->local <= VIA_PIPC_586B) && ((addr == 0x48) || (addr == 0x4c) || (addr == 0x4d) || (addr >= 0x54))) + return; + + if ((dev->local <= VIA_PIPC_596B) && ((addr >= 0x64) && (addr < (dev->local == VIA_PIPC_596A ? 0x80 : 0x85)))) + return; + + switch (addr) { + case 0x41: case 0x48: case 0x49: + if (addr == 0x48) { + if (dev->local >= VIA_PIPC_596A) + val = (val & 0x80) | 0x01; + else + val = 0x01; + } + + dev->power_regs[addr] = val; + c = (dev->power_regs[0x49] << 8); + if (dev->local >= VIA_PIPC_596A) + c |= (dev->power_regs[0x48] & 0x80); + /* Workaround for P3V133 BIOS in 596B mode mapping ACPI to E800 (same as SMBus) instead of E400. */ + if ((dev->local == VIA_PIPC_596B) && (c == ((dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0))) && (dev->power_regs[0xd2] & 0x01)) + c -= 0x400; + acpi_set_timer32(dev->acpi, dev->power_regs[0x41] & 0x08); + acpi_update_io_mapping(dev->acpi, c, dev->power_regs[0x41] & 0x80); + break; + + case 0x42: + dev->power_regs[addr] = (dev->power_regs[addr] & 0xf0) | (val & 0x0f); + acpi_set_irq_line(dev->acpi, dev->power_regs[addr] & 0x0f); + break; + + case 0x54: + if (dev->local <= VIA_PIPC_596B) + dev->power_regs[addr] = val; /* write-only on 686A+ */ + else + smbus_piix4_setclock(dev->smbus, (val & 0x80) ? 65536 : 16384); /* final clock undocumented on 686A, assume RTC*2 like 686B */ + break; + + case 0x61: case 0x62: case 0x63: + dev->power_regs[(addr - 0x58)] = val; + break; + + case 0x70: case 0x71: case 0x74: + dev->power_regs[addr] = val; + /* Forward hardware monitor-related registers to hwm_vt82c686.c */ + if (dev->hwm) + vt82c686_hwm_write(addr, val, dev->hwm); + break; + + case 0x80: case 0x81: case 0x84: /* 596A has the SMBus I/O base and enable bit here instead. */ + dev->power_regs[addr] = val; + smbus_piix4_remap(dev->smbus, (dev->power_regs[0x81] << 8) | (dev->power_regs[0x80] & 0xf0), dev->power_regs[0x84] & 0x01); + break; + + case 0xd2: + if (dev->local == VIA_PIPC_686B) + smbus_piix4_setclock(dev->smbus, (val & 0x04) ? 65536 : 16384); + /* fall-through */ + + case 0x90: case 0x91: + dev->power_regs[addr] = val; + smbus_piix4_remap(dev->smbus, (dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0), dev->power_regs[0xd2] & 0x01); + break; + + default: + dev->power_regs[addr] = val; + break; + } + } else if (func <= pm_func + 2) { /* AC97 / MC97 */ + /* Read-only addresses. */ + if ((addr < 0x4) || ((addr >= 0x6) && (addr < 0x9)) || ((addr >= 0xc) && (addr < 0x11)) || (addr == 0x16) || + (addr == 0x17) || (addr == 0x1a) || (addr == 0x1b) || ((addr >= 0x1e) && (addr < 0x2c)) || + ((addr >= 0x30) && (addr < 0x34)) || ((addr >= 0x35) && (addr < 0x3c)) || ((addr >= 0x3d) && (addr < 0x41)) || + ((addr >= 0x45) && (addr < 0x4a)) || (addr >= 0x4c)) + return; + + /* Small shortcut. */ + func = func - pm_func - 1; + + /* Check disable bits and specific read-only addresses for both controllers. */ + if ((func == 0) && (((addr >= 0x09) && (addr < 0xc)) || (addr == 0x44) || (dev->pci_isa_regs[0x85] & 0x04))) + return; + + if ((func == 1) && ((addr == 0x14) || (addr == 0x15) || (addr == 0x18) || (addr == 0x19) || (addr == 0x42) || + (addr == 0x43) || (addr == 0x48) || (addr == 0x4a) || (addr == 0x4b) || (dev->pci_isa_regs[0x85] & 0x08))) + return; + + switch (addr) { + case 0x04: + dev->ac97_regs[func][addr] = val; + pipc_sgd_handlers(dev, func); + pipc_codec_handlers(dev, func); + pipc_fmnmi_handlers(dev, func); + break; + + case 0x09: case 0x0a: case 0x0b: + if (dev->ac97_regs[func][0x44] & 0x20) + dev->ac97_regs[func][addr] = val; + break; + + case 0x10: case 0x11: + dev->ac97_regs[func][addr] = val; + pipc_sgd_handlers(dev, func); + break; + + case 0x14: case 0x15: + if (addr == 0x14) + val = (val & 0xfc) | 1; + dev->ac97_regs[func][addr] = val; + pipc_fmnmi_handlers(dev, func); + break; + + case 0x18: case 0x19: + if (addr == 0x18) + val = (val & 0xfc) | 1; + dev->ac97_regs[func][addr] = val; + pipc_sb_handlers(dev, func); + break; + + case 0x1c: case 0x1d: + dev->ac97_regs[func][addr] = val; + pipc_codec_handlers(dev, func); + break; + + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + if ((func == 0) && (dev->ac97_regs[func][0x42] & 0x20)) + dev->ac97_regs[func][addr] = val; + break; + + case 0x41: + dev->ac97_regs[func][addr] = val; + ac97_via_write_control(dev->ac97, func, val); + break; + + case 0x42: case 0x4a: case 0x4b: + dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val; + gameport_remap(dev->gameport, (dev->ac97_regs[0][0x42] & 0x08) ? ((dev->ac97_regs[0][0x4b] << 8) | (dev->ac97_regs[0][0x4a] & 0xf8)) : 0); + if (addr == 0x42) + pipc_sb_handlers(dev, func); + break; + + case 0x43: + dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val; + break; + + case 0x44: + dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val & 0xf0; + break; + + case 0x45: case 0x48: + dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val & 0x0f; + break; + + default: + dev->ac97_regs[func][addr] = val; + break; + } + } +} + + +static void +pipc_reset(void *p) +{ + pipc_t *dev = (pipc_t *) p; + uint8_t pm_func = dev->usb[1] ? 4 : 3; + + pipc_write(pm_func, 0x41, 0x00, p); + pipc_write(pm_func, 0x48, 0x01, p); + pipc_write(pm_func, 0x49, 0x00, p); + + pipc_write(1, 0x04, 0x80, p); + pipc_write(1, 0x09, 0x85, p); + pipc_write(1, 0x10, 0xf1, p); + pipc_write(1, 0x11, 0x01, p); + pipc_write(1, 0x14, 0xf5, p); + pipc_write(1, 0x15, 0x03, p); + pipc_write(1, 0x18, 0x71, p); + pipc_write(1, 0x19, 0x01, p); + pipc_write(1, 0x1c, 0x75, p); + pipc_write(1, 0x1d, 0x03, p); + pipc_write(1, 0x20, 0x01, p); + pipc_write(1, 0x21, 0xcc, p); + if (dev->local <= VIA_PIPC_586B) + pipc_write(1, 0x40, 0x04, p); + else + pipc_write(1, 0x40, 0x00, p); + + pipc_write(0, 0x77, 0x00, p); +} + + +static void * +pipc_init(const device_t *info) +{ + pipc_t *dev = (pipc_t *) malloc(sizeof(pipc_t)); + memset(dev, 0, sizeof(pipc_t)); + + pipc_log("PIPC: init()\n"); + + dev->local = info->local; + dev->slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, pipc_read, pipc_write, dev); + + dev->bm[0] = device_add_inst(&sff8038i_device, 1); + sff_set_slot(dev->bm[0], dev->slot); + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[0], 1, 0); + sff_set_irq_pin(dev->bm[0], PCI_INTA); + + dev->bm[1] = device_add_inst(&sff8038i_device, 2); + sff_set_slot(dev->bm[1], dev->slot); + sff_set_irq_mode(dev->bm[1], 0, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + sff_set_irq_pin(dev->bm[1], PCI_INTA); + + dev->nvr = device_add(&via_nvr_device); + + if (dev->local == VIA_PIPC_686B) + dev->smbus = device_add(&via_smbus_device); + else if (dev->local >= VIA_PIPC_596A) + dev->smbus = device_add(&piix4_smbus_device); + + if (dev->local >= VIA_PIPC_596A) { + dev->acpi = device_add(&acpi_via_596b_device); + acpi_set_trap_update(dev->acpi, pipc_trap_update_596, dev); + } else if (dev->local >= VIA_PIPC_586B) { + dev->acpi = device_add(&acpi_via_device); + acpi_set_trap_update(dev->acpi, pipc_trap_update_586, dev); + } + + dev->usb[0] = device_add_inst(&usb_device, 1); + if (dev->local >= VIA_PIPC_686A) { + dev->usb[1] = device_add_inst(&usb_device, 2); + + dev->ac97 = device_add(&ac97_via_device); + ac97_via_set_slot(dev->ac97, dev->slot, PCI_INTC); + + dev->sb = device_add_inst(&sb_pro_compat_device, 2); +#ifndef VIA_PIPC_FM_EMULATION + dev->sb->opl_enabled = 1; +#endif + sound_add_handler(sb_get_buffer_sbpro, dev->sb); + + dev->gameport = gameport_add(&gameport_sio_device); + + dev->sio = device_add(&via_vt82c686_sio_device); + dev->hwm = device_add(&via_vt82c686_hwm_device); + } + + pipc_reset_hard(dev); + + device_add(&port_92_pci_device); + + cpu_set_isa_pci_div(4); + + dma_alias_set(); + + if (dev->local <= VIA_PIPC_586B) { + pci_enable_mirq(0); + pci_enable_mirq(1); + if (dev->local == VIA_PIPC_586B) + pci_enable_mirq(2); + } + + if (dev->local < VIA_PIPC_8231) + dev->ddma = device_add(&ddma_device); + + if (dev->acpi) { + acpi_set_slot(dev->acpi, dev->slot); + acpi_set_nvr(dev->acpi, dev->nvr); + + acpi_init_gporeg(dev->acpi, 0xff, 0xbf, 0xff, 0x7f); + } + + return dev; +} + + +static void +pipc_close(void *p) +{ + pipc_t *dev = (pipc_t *) p; + + pipc_log("PIPC: close()\n"); + + for (int i = 0; i < TRAP_MAX; i++) + io_trap_remove(dev->io_traps[i].trap); + + free(dev); +} + +const device_t via_vt82c586b_device = { + .name = "VIA VT82C586B", + .internal_name = "via_vt82c586b", + .flags = DEVICE_PCI, + .local = VIA_PIPC_586B, + .init = pipc_init, + .close = pipc_close, + .reset = pipc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c596a_device = { + .name = "VIA VT82C596A", + .internal_name = "via_vt82c596a", + .flags = DEVICE_PCI, + .local = VIA_PIPC_596A, + .init = pipc_init, + .close = pipc_close, + .reset = pipc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c596b_device = { + .name = "VIA VT82C596B", + .internal_name = "via_vt82c596b", + .flags = DEVICE_PCI, + .local = VIA_PIPC_596B, + .init = pipc_init, + .close = pipc_close, + .reset = pipc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c686a_device = { + .name = "VIA VT82C686A", + .internal_name = "via_vt82c686a", + .flags = DEVICE_PCI, + .local = VIA_PIPC_686A, + .init = pipc_init, + .close = pipc_close, + .reset = pipc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c686b_device = { + .name = "VIA VT82C686B", + .internal_name = "via_vt82c686b", + .flags = DEVICE_PCI, + .local = VIA_PIPC_686B, + .init = pipc_init, + .close = pipc_close, + .reset = pipc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt8231_device = { + .name = "VIA VT8231", + .internal_name = "via_vt8231", + .flags = DEVICE_PCI, + .local = VIA_PIPC_8231, + .init = pipc_init, + .close = pipc_close, + .reset = pipc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/via_vpx.c b/src/chipset/via_vpx.c deleted file mode 100644 index c9798e319..000000000 --- a/src/chipset/via_vpx.c +++ /dev/null @@ -1,228 +0,0 @@ -/* -* -* 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. -* -* -* -* VIA Apollo VPX North Bridge emulation -* -* VT82C585VPX used in the FIC VA-502 board -* based on the model of VIA MVP3 by mooch & Sarah -* -* There's also a SOYO board using the ETEQ chipset which is a rebranded -* VPX + 586B but fails to save on CMOS properly. -* -* Authors: Sarah Walker, -* Copyright(C) 2020 Tiseno100 -* Copyright(C) 2020 Melissa Goad -* Copyright(C) 2020 Miran Grca -* -*/ - -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> -#include <86box/device.h> -#include <86box/keyboard.h> -#include <86box/chipset.h> - -typedef struct via_vpx_t -{ - uint8_t pci_conf[256]; -} via_vpx_t; - -static void -vpx_map(uint32_t addr, uint32_t size, int state) -{ - switch (state & 3) { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - - flushmmucache_nopc(); -} - -static void -via_vpx_write(int func, int addr, uint8_t val, void *priv) -{ - -via_vpx_t *dev = (via_vpx_t *) priv; - - // Read-Only registers - switch(addr){ - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: case 0x0f: - return; - } - - switch(addr){ - case 0x04: - // Bitfield 6: Parity Error Response - // Bitfield 8: SERR# Enable - // Bitfield 9: Fast Back-to-Back Cycle Enable - if(dev->pci_conf[0x04] && 0x40){ //Bitfield 6 - dev->pci_conf[0x04] = (dev->pci_conf[0x04] & ~0x40) | (val & 0x40); - } else if(dev->pci_conf[0x04] && 0x100){ //Bitfield 8 - dev->pci_conf[0x04] = (dev->pci_conf[0x04] & ~0x100) | (val & 0x100); - } else if(dev->pci_conf[0x04] && 0x200){ //Bitfield 9 - dev->pci_conf[0x04] = (dev->pci_conf[0x04] & ~0x200) | (val & 0x200); - } - break; - - case 0x07: // Status - dev->pci_conf[0x07] &= ~(val & 0xb0); - break; - - case 0x61: // Shadow RAM control 1 - if ((dev->pci_conf[0x61] ^ val) & 0x03) - vpx_map(0xc0000, 0x04000, val & 0x03); - if ((dev->pci_conf[0x61] ^ val) & 0x0c) - vpx_map(0xc4000, 0x04000, (val & 0x0c) >> 2); - if ((dev->pci_conf[0x61] ^ val) & 0x30) - vpx_map(0xc8000, 0x04000, (val & 0x30) >> 4); - if ((dev->pci_conf[0x61] ^ val) & 0xc0) - vpx_map(0xcc000, 0x04000, (val & 0xc0) >> 6); - dev->pci_conf[0x61] = val; - return; - - case 0x62: // Shadow RAM Control 2 - if ((dev->pci_conf[0x62] ^ val) & 0x03) - vpx_map(0xd0000, 0x04000, val & 0x03); - if ((dev->pci_conf[0x62] ^ val) & 0x0c) - vpx_map(0xd4000, 0x04000, (val & 0x0c) >> 2); - if ((dev->pci_conf[0x62] ^ val) & 0x30) - vpx_map(0xd8000, 0x04000, (val & 0x30) >> 4); - if ((dev->pci_conf[0x62] ^ val) & 0xc0) - vpx_map(0xdc000, 0x04000, (val & 0xc0) >> 6); - dev->pci_conf[0x62] = val; - return; - - case 0x63: // Shadow RAM Control 3 - if ((dev->pci_conf[0x63] ^ val) & 0x30) { - vpx_map(0xf0000, 0x10000, (val & 0x30) >> 4); - shadowbios = (((val & 0x30) >> 4) & 0x02); - } - if ((dev->pci_conf[0x63] ^ val) & 0xc0) - vpx_map(0xe0000, 0x10000, (val & 0xc0) >> 6); - dev->pci_conf[0x63] = val; - return; - - default: - dev->pci_conf[addr] = val; - break; - } -} - -static uint8_t -via_vpx_read(int func, int addr, void *priv) -{ - via_vpx_t *dev = (via_vpx_t *) priv; - uint8_t ret = 0xff; - - switch(func) { - case 0: - ret = dev->pci_conf[addr]; - break; - } - - return ret; -} - -static void -via_vpx_reset(void *priv) -{ - via_vpx_write(0, 0x63, via_vpx_read(0, 0x63, priv) & 0xcf, priv); -} - -static void * -via_vpx_init(const device_t *info) -{ - via_vpx_t *dev = (via_vpx_t *) malloc(sizeof(via_vpx_t)); - memset(dev, 0, sizeof(via_vpx_t)); - - pci_add_card(PCI_ADD_NORTHBRIDGE, via_vpx_read, via_vpx_write, dev); - - dev->pci_conf[0x00] = 0x06; // VIA - dev->pci_conf[0x01] = 0x11; - - dev->pci_conf[0x02] = 0x85; // VT82C585VPX - dev->pci_conf[0x03] = 0x05; - - dev->pci_conf[0x04] = 7; // Command - dev->pci_conf[0x05] = 0; - - dev->pci_conf[0x06] = 0xa0; // Status - dev->pci_conf[0x07] = 2; - - dev->pci_conf[0x08] = 0; // Silicon Rev. - - dev->pci_conf[0x09] = 0; // Program Interface - - dev->pci_conf[0x0a] = 0; // Sub Class Code - - dev->pci_conf[0x0b] = 6; // Base Class Code - - dev->pci_conf[0x0c] = 0; // reserved - - dev->pci_conf[0x0d] = 0; // Latency Timer - - dev->pci_conf[0x0e] = 0; // Header Type - - dev->pci_conf[0x0f] = 0; // Built-in Self test - - dev->pci_conf[0x58] = 0x40; // DRAM Configuration 1 - dev->pci_conf[0x59] = 0x05; // DRAM Configuration 2 - - dev->pci_conf[0x5a] = 1; // Bank 0 Ending - dev->pci_conf[0x5b] = 1; // Bank 1 Ending - dev->pci_conf[0x5c] = 1; // Bank 2 Ending - dev->pci_conf[0x5d] = 1; // Bank 3 Ending - dev->pci_conf[0x5e] = 1; // Bank 4 Ending - dev->pci_conf[0x5f] = 1; // Bank 5 Ending - - dev->pci_conf[0x64] = 0xab; // DRAM reference timing - - return dev; -} - -static void -via_vpx_close(void *priv) -{ - via_vpx_t *dev = (via_vpx_t *) priv; - - free(dev); -} - -const device_t via_vpx_device = { - "VIA Apollo VPX", - DEVICE_PCI, - 0, - via_vpx_init, - via_vpx_close, - via_vpx_reset, - NULL, - NULL, - NULL, - NULL -}; \ No newline at end of file diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c new file mode 100644 index 000000000..f951741e7 --- /dev/null +++ b/src/chipset/via_vt82c49x.c @@ -0,0 +1,415 @@ +/* + * 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 VIA VT82C49X chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2020 Tiseno100. + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#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/smram.h> +#include <86box/pic.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + +typedef struct +{ + uint8_t has_ide, index, + regs[256]; + + smram_t *smram_smm, *smram_low, + *smram_high; +} vt82c49x_t; + + +#ifdef ENABLE_VT82C49X_LOG +int vt82c49x_do_log = ENABLE_VT82C49X_LOG; +static void +vt82c49x_log(const char *fmt, ...) +{ + va_list ap; + + if (vt82c49x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define vt82c49x_log(fmt, ...) +#endif + + +static void +vt82c49x_recalc(vt82c49x_t *dev) +{ + int i, relocate; + uint8_t reg, bit; + uint32_t base, state; + uint32_t shadow_bitmap = 0x00000000; + + relocate = (dev->regs[0x33] >> 2) & 0x03; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 14); + reg = 0x30 + (i >> 2); + bit = (i & 3) << 1; + + if ((base >= 0xc0000) && (base <= 0xc7fff)) { + if (dev->regs[0x40] & 0x80) + state = MEM_WRITE_DISABLED; + else if ((dev->regs[reg]) & (1 << bit)) + state = MEM_WRITE_INTERNAL; + else + state = (dev->regs[0x33] & 0x40) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL; + + if ((dev->regs[reg]) & (1 << (bit + 1))) + state |= MEM_READ_INTERNAL; + else + state |= (dev->regs[0x33] & 0x40) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL; + } if ((base >= 0xc8000) && (base <= 0xcffff)) { + if ((dev->regs[reg]) & (1 << bit)) + state = MEM_WRITE_INTERNAL; + else + state = (dev->regs[0x33] & 0x80) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL; + + if ((dev->regs[reg]) & (1 << (bit + 1))) + state |= MEM_READ_INTERNAL; + else + state |= (dev->regs[0x33] & 0x80) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL; + } else { + state = ((dev->regs[reg]) & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + state |= ((dev->regs[reg]) & (1 << (bit + 1))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + } + + vt82c49x_log("(%02X=%02X, %i) Setting %08X-%08X to: write %sabled, read %sabled\n", + reg, dev->regs[reg], bit, base, base + 0x3fff, + ((dev->regs[reg]) & (1 << bit)) ? "en" : "dis", ((dev->regs[reg]) & (1 << (bit + 1))) ? "en" : "dis"); + + if ((dev->regs[reg]) & (1 << bit)) + shadow_bitmap |= (1 << i); + if ((dev->regs[reg]) & (1 << (bit + 1))) + shadow_bitmap |= (1 << (i + 16)); + + mem_set_mem_state_both(base, 0x4000, state); + } + + for (i = 0; i < 4; i++) { + base = 0xe0000 + (i << 15); + bit = 6 - (i & 2); + + if ((base >= 0xe0000) && (base <= 0xe7fff)) { + if (dev->regs[0x40] & 0x20) + state = MEM_WRITE_DISABLED; + else if ((dev->regs[0x32]) & (1 << bit)) + state = MEM_WRITE_INTERNAL; + else + state = (dev->regs[0x33] & 0x10) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL; + + if ((dev->regs[0x32]) & (1 << (bit + 1))) + state |= MEM_READ_INTERNAL; + else + state |= (dev->regs[0x33] & 0x10) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL; + } else if ((base >= 0xe8000) && (base <= 0xeffff)) { + if (dev->regs[0x40] & 0x20) + state = MEM_WRITE_DISABLED; + else if ((dev->regs[0x32]) & (1 << bit)) + state = MEM_WRITE_INTERNAL; + else + state = (dev->regs[0x33] & 0x20) ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL; + + if ((dev->regs[0x32]) & (1 << (bit + 1))) + state |= MEM_READ_INTERNAL; + else + state |= (dev->regs[0x33] & 0x20) ? MEM_READ_ROMCS : MEM_READ_EXTERNAL; + } else { + if (dev->regs[0x40] & 0x40) + state = MEM_WRITE_DISABLED; + else if ((dev->regs[0x32]) & (1 << bit)) + state = ((dev->regs[0x32]) & (1 << bit)) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + + state |= ((dev->regs[0x32]) & (1 << (bit + 1))) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + } + + vt82c49x_log("(32=%02X, %i) Setting %08X-%08X to: write %sabled, read %sabled\n", + dev->regs[0x32], bit, base, base + 0x7fff, + ((dev->regs[0x32]) & (1 << bit)) ? "en" : "dis", ((dev->regs[0x32]) & (1 << (bit + 1))) ? "en" : "dis"); + + if ((dev->regs[0x32]) & (1 << bit)) { + shadow_bitmap |= (0xf << ((i << 2) + 8)); + shadowbios_write |= 1; + } + if ((dev->regs[0x32]) & (1 << (bit + 1))) { + shadow_bitmap |= (0xf << ((i << 2) + 24)); + shadowbios |= 1; + } + + mem_set_mem_state_both(base, 0x8000, state); + } + + vt82c49x_log("Shadow bitmap: %08X\n", shadow_bitmap); + + mem_remap_top(0); + + switch (relocate) { + case 0x02: + if (!(shadow_bitmap & 0xfff0fff0)) + mem_remap_top(256); + break; + case 0x03: + if (!shadow_bitmap) + mem_remap_top(384); + break; + } +} + + +static void +vt82c49x_write(uint16_t addr, uint8_t val, void *priv) +{ + vt82c49x_t *dev = (vt82c49x_t *) priv; + uint8_t valxor; + + switch (addr) { + case 0xa8: + dev->index = val; + break; + + case 0xa9: + valxor = (val ^ dev->regs[dev->index]); + if (dev->index == 0x55) + dev->regs[dev->index] &= ~val; + else + dev->regs[dev->index] = val; + + vt82c49x_log("dev->regs[0x%02x] = %02x\n", dev->index, val); + + switch(dev->index) { + /* Wait States */ + case 0x03: + cpu_update_waitstates(); + break; + + /* Shadow RAM and top of RAM relocation */ + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x40: + vt82c49x_recalc(dev); + break; + + /* External Cache Enable(Based on the 486-VC-HD BIOS) */ + case 0x50: + cpu_cache_ext_enabled = (val & 0x84); + break; + + /* Software SMI */ + case 0x54: + if ((dev->regs[0x5b] & 0x80) && (valxor & 0x01) && (val & 0x01)) { + if (dev->regs[0x5b] & 0x20) + smi_raise(); + else + picint(1 << 15); + dev->regs[0x55] = 0x01; + } + break; + + /* SMRAM */ + case 0x5b: + smram_disable_all(); + + if (val & 0x80) { + smram_enable(dev->smram_smm, (val & 0x40) ? 0x00060000 : 0x00030000, 0x000a0000, 0x00020000, + 0, (val & 0x10)); + smram_enable(dev->smram_high, 0x000a0000, 0x000a0000, 0x00020000, + (val & 0x08), (val & 0x08)); + smram_enable(dev->smram_low, 0x00030000, 0x000a0000, 0x00020000, + (val & 0x02), 0); + } + break; + + /* Edge/Level IRQ Control */ + case 0x62: case 0x63: + if (dev->index == 0x63) + pic_elcr_write(dev->index, val & 0xde, &pic2); + else { + pic_elcr_write(dev->index, val & 0xf8, &pic); + pic_elcr_set_enabled(val & 0x01); + } + break; + + /* Local Bus IDE Controller */ + case 0x71: + if (dev->has_ide) { + ide_pri_disable(); + ide_set_base(0, (val & 0x40) ? 0x170 : 0x1f0); + ide_set_side(0, (val & 0x40) ? 0x376 : 0x3f6); + if (val & 0x01) + ide_pri_enable(); + vt82c49x_log("VT82C496 IDE now %sabled as %sary\n", (val & 0x01) ? "en": "dis", + (val & 0x40) ? "second" : "prim"); + } + break; + } + break; + } +} + + +static uint8_t +vt82c49x_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + vt82c49x_t *dev = (vt82c49x_t *) priv; + + switch (addr) { + case 0xa9: + /* Register 64h is jumper readout. */ + if (dev->index == 0x64) + ret = 0xff; + else if (dev->index == 0x63) + ret = pic_elcr_read(dev->index, &pic2) | (dev->regs[dev->index] & 0x01); + else if (dev->index == 0x62) + ret = pic_elcr_read(dev->index, &pic) | (dev->regs[dev->index] & 0x07); + else if (dev->index < 0x80) + ret = dev->regs[dev->index]; + break; + } + + return ret; +} + + +static void +vt82c49x_reset(void *priv) +{ + uint16_t i; + + for (i = 0; i < 256; i++) + vt82c49x_write(i, 0x00, priv); +} + + +static void +vt82c49x_close(void *priv) +{ + vt82c49x_t *dev = (vt82c49x_t *) priv; + + smram_del(dev->smram_high); + smram_del(dev->smram_low); + smram_del(dev->smram_smm); + + free(dev); +} + + +static void * +vt82c49x_init(const device_t *info) +{ + vt82c49x_t *dev = (vt82c49x_t *) malloc(sizeof(vt82c49x_t)); + memset(dev, 0x00, sizeof(vt82c49x_t)); + + dev->smram_smm = smram_add(); + dev->smram_low = smram_add(); + dev->smram_high = smram_add(); + + dev->has_ide = info->local & 1; + if (dev->has_ide) { + device_add(&ide_vlb_2ch_device); + ide_sec_disable(); + } + + device_add(&port_92_device); + + io_sethandler(0x0a8, 0x0002, vt82c49x_read, NULL, NULL, vt82c49x_write, NULL, NULL, dev); + + pic_elcr_io_handler(0); + pic_elcr_set_enabled(1); + + vt82c49x_recalc(dev); + + return dev; +} + +const device_t via_vt82c49x_device = { + .name = "VIA VT82C49X", + .internal_name = "via_vt82c49x", + .flags = 0, + .local = 0, + .init = vt82c49x_init, + .close = vt82c49x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c49x_pci_device = { + .name = "VIA VT82C49X PCI", + .internal_name = "via_vt82c49x_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = vt82c49x_init, + .close = vt82c49x_close, + .reset = vt82c49x_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c49x_ide_device = { + .name = "VIA VT82C49X (With IDE)", + .internal_name = "via_vt82c49x_ide", + .flags = 0, + .local = 1, + .init = vt82c49x_init, + .close = vt82c49x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt82c49x_pci_ide_device = { + .name = "VIA VT82C49X PCI (With IDE)", + .internal_name = "via_vt82c49x_pci_ide", + .flags = DEVICE_PCI, + .local = 1, + .init = vt82c49x_init, + .close = vt82c49x_close, + .reset = vt82c49x_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/via_vt82c505.c b/src/chipset/via_vt82c505.c new file mode 100644 index 000000000..5ce799ab6 --- /dev/null +++ b/src/chipset/via_vt82c505.c @@ -0,0 +1,231 @@ +/* + * 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 VIA VT82C505 VL/PCI Bridge Controller. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2020 Tiseno100. + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> + + +typedef struct vt82c505_t +{ + uint8_t index; + uint8_t pci_conf[256]; +} vt82c505_t; + + +static void +vt82c505_write(int func, int addr, uint8_t val, void *priv) +{ + vt82c505_t *dev = (vt82c505_t *) priv; + uint8_t irq; + const uint8_t irq_array[8] = { 0, 5, 9, 10, 11, 14, 15, 0 }; + + if (func != 0) + return; + + switch(addr) { + /* RX00-07h: Mandatory header field */ + case 0x04: + dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xbf) | (val & 0x40); + break; + case 0x07: + dev->pci_conf[addr] &= ~(val & 0x90); + break; + + /* RX80-9F: VT82C505 internal configuration registers */ + case 0x80: + dev->pci_conf[addr] = (dev->pci_conf[addr] & 0x0f) | (val & 0xf0); + break; + case 0x81: case 0x84: case 0x85: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x92: case 0x94: + dev->pci_conf[addr] = val; + break; + case 0x82: + dev->pci_conf[addr] = val & 0xdb; + break; + case 0x83: + dev->pci_conf[addr] = val & 0xf9; + break; + case 0x86: + dev->pci_conf[addr] = val & 0xef; + /* Bit 7 switches between the two PCI configuration mechanisms: + 0 = configuration mechanism 1, 1 = configuration mechanism 2 */ + pci_set_pmc(!(val & 0x80)); + break; + case 0x90: + dev->pci_conf[addr] = val; + irq = irq_array[val & 0x07]; + if ((val & 0x08) && (irq != 0)) + pci_set_irq_routing(PCI_INTC, irq); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + + irq = irq_array[(val & 0x70) >> 4]; + if ((val & 0x80) && (irq != 0)) + pci_set_irq_routing(PCI_INTD, irq); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; + case 0x91: + dev->pci_conf[addr] = val; + irq = irq_array[val & 0x07]; + if ((val & 0x08) && (irq != 0)) + pci_set_irq_routing(PCI_INTA, irq); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + + irq = irq_array[(val & 0x70) >> 4]; + if ((val & 0x80) && (irq != 0)) + pci_set_irq_routing(PCI_INTB, irq); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + case 0x93: + dev->pci_conf[addr] = val & 0xe0; + break; + } +} + + +static uint8_t +vt82c505_read(int func, int addr, void *priv) +{ + vt82c505_t *dev = (vt82c505_t *) priv; + uint8_t ret = 0xff; + + if (func != 0) + return ret; + + ret = dev->pci_conf[addr]; + + return ret; +} + + +static void +vt82c505_out(uint16_t addr, uint8_t val, void *priv) +{ + vt82c505_t *dev = (vt82c505_t *) priv; + + if (addr == 0xa8) + dev->index = val; + else if ((addr == 0xa9) && (dev->index >= 0x80) && (dev->index <= 0x9f)) + vt82c505_write(0, dev->index, val, priv); +} + + +static uint8_t +vt82c505_in(uint16_t addr, void *priv) +{ + vt82c505_t *dev = (vt82c505_t *) priv; + uint8_t ret = 0xff; + + if ((addr == 0xa9) && (dev->index >= 0x80) && (dev->index <= 0x9f)) + ret = vt82c505_read(0, dev->index, priv); + + return ret; +} + + +static void +vt82c505_reset(void *priv) +{ + vt82c505_t *dev = (vt82c505_t *) malloc(sizeof(vt82c505_t)); + int i; + + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x07] = 0x00; + + for (i = 0x80; i <= 0x9f; i++) { + switch (i) { + case 0x81: + vt82c505_write(0, i, 0x01, priv); + break; + case 0x84: + vt82c505_write(0, i, 0x03, priv); + break; + case 0x93: + vt82c505_write(0, i, 0x40, priv); + break; + default: + vt82c505_write(0, i, 0x00, priv); + break; + } + } + + pic_reset(); + pic_set_pci_flag(1); +} + + +static void +vt82c505_close(void *priv) +{ + vt82c505_t *dev = (vt82c505_t *) priv; + + free(dev); +} + + +static void * +vt82c505_init(const device_t *info) +{ + vt82c505_t *dev = (vt82c505_t *) malloc(sizeof(vt82c505_t)); + memset(dev, 0, sizeof(vt82c505_t)); + + pci_add_card(PCI_ADD_NORTHBRIDGE, vt82c505_read, vt82c505_write, dev); + + dev->pci_conf[0x00] = 0x06; + dev->pci_conf[0x01] = 0x11; + dev->pci_conf[0x02] = 0x05; + dev->pci_conf[0x03] = 0x05; + dev->pci_conf[0x04] = 0x07; + dev->pci_conf[0x07] = 0x00; + dev->pci_conf[0x81] = 0x01; + dev->pci_conf[0x84] = 0x03; + dev->pci_conf[0x93] = 0x40; + + io_sethandler(0x0a8, 0x0002, vt82c505_in, NULL, NULL, vt82c505_out, NULL, NULL, dev); + + return dev; +} + +const device_t via_vt82c505_device = { + .name = "VIA VT82C505", + .internal_name = "via_vt82c505", + .flags = DEVICE_PCI, + .local = 0, + .init = vt82c505_init, + .close = vt82c505_close, + .reset = vt82c505_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/via_vt82c586b.c b/src/chipset/via_vt82c586b.c deleted file mode 100644 index 3524ed30b..000000000 --- a/src/chipset/via_vt82c586b.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * 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. - * - * Emulation of the VIA Apollo MVP3 southbridge - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * Melissa Goad, - * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2020 Melissa Goad. - */ - -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/cdrom.h> -#include "cpu.h" -#include <86box/scsi_device.h> -#include <86box/scsi_cdrom.h> -#include <86box/dma.h> -#include <86box/io.h> -#include <86box/device.h> -#include <86box/apm.h> -#include <86box/keyboard.h> -#include <86box/mem.h> -#include <86box/timer.h> -#include <86box/nvr.h> -#include <86box/pci.h> -#include <86box/pic.h> -#include <86box/port_92.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/hdc_ide_sff8038i.h> -#include <86box/zip.h> -#include <86box/machine.h> -#include <86box/chipset.h> - - -#define ACPI_TIMER_FREQ 3579545 - -#define ACPI_IO_ENABLE (1 << 7) -#define ACPI_TIMER_32BIT (1 << 3) - - -typedef struct -{ - uint8_t pci_isa_regs[256]; - uint8_t ide_regs[256]; - uint8_t usb_regs[256]; - uint8_t power_regs[256]; - sff8038i_t * bm[2]; - nvr_t * nvr; - int nvr_enabled, slot; - - struct - { - uint16_t io_base; - } usb; - - struct - { - uint16_t io_base; - } power; -} via_vt82c586b_t; - - -static void -via_vt82c586b_reset_hard(void *priv) -{ - int i; - - via_vt82c586b_t *via_vt82c586b = (via_vt82c586b_t *) priv; - uint16_t old_base = (via_vt82c586b->ide_regs[0x20] & 0xf0) | (via_vt82c586b->ide_regs[0x21] << 8); - - sff_bus_master_reset(via_vt82c586b->bm[0], old_base); - sff_bus_master_reset(via_vt82c586b->bm[1], old_base + 8); - - memset(via_vt82c586b->pci_isa_regs, 0, 256); - memset(via_vt82c586b->ide_regs, 0, 256); - memset(via_vt82c586b->usb_regs, 0, 256); - memset(via_vt82c586b->power_regs, 0, 256); - - via_vt82c586b->pci_isa_regs[0x00] = 0x06; via_vt82c586b->pci_isa_regs[0x01] = 0x11; /*VIA*/ - via_vt82c586b->pci_isa_regs[0x02] = 0x86; via_vt82c586b->pci_isa_regs[0x03] = 0x05; /*VT82C586B*/ - via_vt82c586b->pci_isa_regs[0x04] = 0x0f; - via_vt82c586b->pci_isa_regs[0x07] = 0x02; - via_vt82c586b->pci_isa_regs[0x0a] = 0x01; - via_vt82c586b->pci_isa_regs[0x0b] = 0x06; - via_vt82c586b->pci_isa_regs[0x0e] = 0x80; - - via_vt82c586b->pci_isa_regs[0x48] = 0x01; - via_vt82c586b->pci_isa_regs[0x4a] = 0x04; - via_vt82c586b->pci_isa_regs[0x4f] = 0x03; - - via_vt82c586b->pci_isa_regs[0x50] = 0x24; - via_vt82c586b->pci_isa_regs[0x59] = 0x04; - - dma_e = 0x00; - for (i = 0; i < 8; i++) { - dma[i].ab &= 0xffff000f; - dma[i].ac &= 0xffff000f; - } - - pic_set_shadow(0); - - /* IDE registers */ - via_vt82c586b->ide_regs[0x00] = 0x06; via_vt82c586b->ide_regs[0x01] = 0x11; /*VIA*/ - via_vt82c586b->ide_regs[0x02] = 0x71; via_vt82c586b->ide_regs[0x03] = 0x05; /*VT82C586B*/ - via_vt82c586b->ide_regs[0x04] = 0x80; - via_vt82c586b->ide_regs[0x06] = 0x80; via_vt82c586b->ide_regs[0x07] = 0x02; - via_vt82c586b->ide_regs[0x09] = 0x85; - via_vt82c586b->ide_regs[0x0a] = 0x01; - via_vt82c586b->ide_regs[0x0b] = 0x01; - - via_vt82c586b->ide_regs[0x10] = 0xf1; via_vt82c586b->ide_regs[0x11] = 0x01; - via_vt82c586b->ide_regs[0x14] = 0xf5; via_vt82c586b->ide_regs[0x15] = 0x03; - via_vt82c586b->ide_regs[0x18] = 0x71; via_vt82c586b->ide_regs[0x19] = 0x01; - via_vt82c586b->ide_regs[0x1c] = 0x75; via_vt82c586b->ide_regs[0x1d] = 0x03; - via_vt82c586b->ide_regs[0x20] = 0x01; via_vt82c586b->ide_regs[0x21] = 0xcc; - via_vt82c586b->ide_regs[0x3c] = 0x0e; - - via_vt82c586b->ide_regs[0x40] = 0x08; - via_vt82c586b->ide_regs[0x41] = 0x02; - via_vt82c586b->ide_regs[0x42] = 0x09; - via_vt82c586b->ide_regs[0x43] = 0x3a; - via_vt82c586b->ide_regs[0x44] = 0x68; - via_vt82c586b->ide_regs[0x46] = 0xc0; - via_vt82c586b->ide_regs[0x48] = 0xa8; via_vt82c586b->ide_regs[0x49] = 0xa8; - via_vt82c586b->ide_regs[0x4a] = 0xa8; via_vt82c586b->ide_regs[0x4b] = 0xa8; - via_vt82c586b->ide_regs[0x4c] = 0xff; - via_vt82c586b->ide_regs[0x4e] = 0xff; - via_vt82c586b->ide_regs[0x4f] = 0xff; - via_vt82c586b->ide_regs[0x50] = 0x03; via_vt82c586b->ide_regs[0x51] = 0x03; - via_vt82c586b->ide_regs[0x52] = 0x03; via_vt82c586b->ide_regs[0x53] = 0x03; - - via_vt82c586b->ide_regs[0x61] = 0x02; - via_vt82c586b->ide_regs[0x69] = 0x02; - - via_vt82c586b->usb_regs[0x00] = 0x06; via_vt82c586b->usb_regs[0x01] = 0x11; /*VIA*/ - via_vt82c586b->usb_regs[0x02] = 0x38; via_vt82c586b->usb_regs[0x03] = 0x30; - via_vt82c586b->usb_regs[0x04] = 0x00; via_vt82c586b->usb_regs[0x05] = 0x00; - via_vt82c586b->usb_regs[0x06] = 0x00; via_vt82c586b->usb_regs[0x07] = 0x02; - via_vt82c586b->usb_regs[0x0a] = 0x03; - via_vt82c586b->usb_regs[0x0b] = 0x0c; - via_vt82c586b->usb_regs[0x0d] = 0x16; - via_vt82c586b->usb_regs[0x20] = 0x01; - via_vt82c586b->usb_regs[0x21] = 0x03; - via_vt82c586b->usb_regs[0x3d] = 0x04; - - via_vt82c586b->usb_regs[0x60] = 0x10; - via_vt82c586b->usb_regs[0xc1] = 0x20; - - via_vt82c586b->power_regs[0x00] = 0x06; via_vt82c586b->power_regs[0x01] = 0x11; /*VIA*/ - via_vt82c586b->power_regs[0x02] = 0x40; via_vt82c586b->power_regs[0x03] = 0x30; - via_vt82c586b->power_regs[0x04] = 0x00; via_vt82c586b->power_regs[0x05] = 0x00; - via_vt82c586b->power_regs[0x06] = 0x80; via_vt82c586b->power_regs[0x07] = 0x02; - via_vt82c586b->power_regs[0x08] = 0x10; /*Production version (3041)*/ - via_vt82c586b->power_regs[0x48] = 0x01; - - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED); - - ide_pri_disable(); - ide_sec_disable(); -} - - -static void -via_vt82c586b_ide_handlers(via_vt82c586b_t *dev) -{ - uint16_t main, side; - - ide_pri_disable(); - ide_sec_disable(); - - if (dev->ide_regs[0x09] & 0x01) { - main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8); - side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2; - } else { - main = 0x1f0; - side = 0x3f6; - } - ide_set_base(0, main); - ide_set_side(0, side); - - if (dev->ide_regs[0x09] & 0x04) { - main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8); - side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2; - } else { - main = 0x170; - side = 0x376; - } - ide_set_base(1, main); - ide_set_side(1, side); - - if (dev->ide_regs[0x04] & PCI_COMMAND_IO) { - if (dev->ide_regs[0x40] & 0x02) - ide_pri_enable(); - if (dev->ide_regs[0x40] & 0x01) - ide_sec_enable(); - } -} - - -static void -via_vt82c586b_ide_irqs(via_vt82c586b_t *dev) -{ - int irq_mode[2] = { 0, 0 }; - - if (dev->ide_regs[0x09] & 0x01) - irq_mode[0] = (dev->ide_regs[0x3d] & 0x01); - - if (dev->ide_regs[0x09] & 0x04) - irq_mode[1] = (dev->ide_regs[0x3d] & 0x01); - - sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]); - sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]); - - sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]); - sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]); -} - - -static void -via_vt82c586b_bus_master_handlers(via_vt82c586b_t *dev) -{ - uint16_t base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); - - sff_bus_master_handler(dev->bm[0], (dev->ide_regs[0x04] & 1), base); - sff_bus_master_handler(dev->bm[1], (dev->ide_regs[0x04] & 1), base + 8); -} - - -static uint8_t -via_vt82c586b_read(int func, int addr, void *priv) -{ - via_vt82c586b_t *dev = (via_vt82c586b_t *) priv; - - uint8_t ret = 0xff; - int c; - - switch(func) { - case 0: - if ((addr >= 0x60) && (addr <= 0x6f)) { - c = (addr & 0x0e) >> 1; - if (addr & 0x01) - ret = (dma[c].ab & 0x0000ff00) >> 8; - else { - ret = (dma[c].ab & 0x000000f0); - ret |= (!!(dma_e & (1 << c)) << 3); - } - } else - ret = dev->pci_isa_regs[addr]; - break; - case 1: - ret = dev->ide_regs[addr]; - break; - case 2: - ret = dev->usb_regs[addr]; - break; - case 3: - ret = dev->power_regs[addr]; - break; - } - - return ret; -} - - -static uint8_t -usb_reg_read(uint16_t addr, void *p) -{ - uint8_t ret = 0xff; - - switch (addr & 0x1f) { - case 0x10: case 0x11: case 0x12: case 0x13: - /* Port status */ - ret = 0x00; - break; - } - - return ret; -} - - -static void -usb_reg_write(uint16_t addr, uint8_t val, void *p) -{ -} - - -static void -nvr_update_io_mapping(via_vt82c586b_t *dev) -{ - if (dev->nvr_enabled) - nvr_at_handler(0, 0x0074, dev->nvr); - - if ((dev->pci_isa_regs[0x5b] & 0x02) && (dev->pci_isa_regs[0x48] & 0x08)) - nvr_at_handler(1, 0x0074, dev->nvr); -} - - -static void -usb_update_io_mapping(via_vt82c586b_t *dev) -{ - if (dev->usb.io_base != 0x0000) - io_removehandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev); - - dev->usb.io_base = (dev->usb_regs[0x20] & ~0x1f) | (dev->usb_regs[0x21] << 8); - - if ((dev->usb_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->usb.io_base != 0x0000)) - io_sethandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev); -} - - -static uint8_t -power_reg_read(uint16_t addr, void *p) -{ - via_vt82c586b_t *dev = (via_vt82c586b_t *) p; - - uint32_t timer; - uint8_t ret = 0xff; - - switch (addr & 0xff) { - case 0x08: case 0x09: case 0x0a: case 0x0b: - /* ACPI timer */ - timer = (tsc * ACPI_TIMER_FREQ) / machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; - if (!(dev->power_regs[0x41] & ACPI_TIMER_32BIT)) - timer &= 0x00ffffff; - ret = (timer >> (8 * (addr & 3))) & 0xff; - break; - } - - return ret; -} - - -static void -power_reg_write(uint16_t addr, uint8_t val, void *p) -{ -} - - -static void -power_update_io_mapping(via_vt82c586b_t *dev) -{ - if (dev->power.io_base != 0x0000) - io_removehandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev); - - dev->power.io_base = (dev->power_regs[0x49] << 8); - - if ((dev->power_regs[0x41] & ACPI_IO_ENABLE) && (dev->power.io_base != 0x0000)) - io_sethandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev); -} - - -static void -via_vt82c586b_write(int func, int addr, uint8_t val, void *priv) -{ - via_vt82c586b_t *dev = (via_vt82c586b_t *) priv; - int c; - - if (func > 3) - return; - - switch(func) { - case 0: /* PCI-ISA bridge */ - /* Read-only addresses */ - if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) || - (addr == 0x49) || (addr == 0x4b) || ((addr >= 0x51) && (addr < 0x54)) || ((addr >= 0x5d) && (addr < 0x60)) || - ((addr >= 0x68) && (addr < 0x6a)) || (addr >= 0x73)) - return; - - switch (addr) { - case 0x04: - dev->pci_isa_regs[0x04] = (val & 8) | 7; - break; - case 0x07: - dev->pci_isa_regs[0x07] &= ~(val & 0xb0); - break; - - case 0x47: - if ((val & 0x81) == 0x81) - resetx86(); - pic_set_shadow(!!(val & 0x10)); - pci_elcr_set_enabled(!!(val & 0x20)); - dev->pci_isa_regs[0x47] = val & 0xfe; - break; - case 0x48: - dev->pci_isa_regs[0x48] = val; - nvr_update_io_mapping(dev); - break; - - case 0x54: - pci_set_irq_level(PCI_INTA, !(val & 8)); - pci_set_irq_level(PCI_INTB, !(val & 4)); - pci_set_irq_level(PCI_INTC, !(val & 2)); - pci_set_irq_level(PCI_INTD, !(val & 1)); - break; - case 0x55: - pci_set_irq_routing(PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_isa_regs[0x55] = val; - break; - case 0x56: - pci_set_irq_routing(PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_isa_regs[0x56] = val; - break; - case 0x57: - pci_set_irq_routing(PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_isa_regs[0x57] = val; - break; - case 0x58: - pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_isa_regs[0x58] = val; - break; - case 0x5b: - dev->pci_isa_regs[0x5b] = val; - nvr_update_io_mapping(dev); - break; - - case 0x60: case 0x62: case 0x64: case 0x66: - case 0x6a: case 0x6c: case 0x6e: - c = (addr & 0x0e) >> 1; - dma[c].ab = (dma[c].ab & 0xffffff0f) | (val & 0xf0); - dma[c].ac = (dma[c].ac & 0xffffff0f) | (val & 0xf0); - if (val & 0x08) - dma_e |= (1 << c); - else - dma_e &= ~(1 << c); - break; - case 0x61: case 0x63: case 0x65: case 0x67: - case 0x6b: case 0x6d: case 0x6f: - c = (addr & 0x0e) >> 1; - dma[c].ab = (dma[c].ab & 0xffff00ff) | (val << 8); - dma[c].ac = (dma[c].ac & 0xffff00ff) | (val << 8); - break; - - case 0x70: case 0x71: case 0x72: case 0x73: - dev->pci_isa_regs[(addr - 0x44)] = val; - break; - } - break; - - case 1: /* IDE regs */ - /* Read-only addresses */ - if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) || - ((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) || - ((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) || - ((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) || - ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x54) && (addr < 0x60)) || - ((addr >= 0x52) && (addr < 0x68)) || (addr >= 0x62)) - return; - - switch (addr) { - case 0x04: - dev->ide_regs[0x04] = val & 0x85; - via_vt82c586b_ide_handlers(dev); - via_vt82c586b_bus_master_handlers(dev); - break; - case 0x07: - dev->ide_regs[0x07] &= ~(val & 0xf1); - break; - - case 0x09: - dev->ide_regs[0x09] = (val & 0x05) | 0x8a; - via_vt82c586b_ide_handlers(dev); - via_vt82c586b_ide_irqs(dev); - break; - - case 0x10: - dev->ide_regs[0x10] = (val & 0xf8) | 1; - via_vt82c586b_ide_handlers(dev); - break; - case 0x11: - dev->ide_regs[0x11] = val; - via_vt82c586b_ide_handlers(dev); - break; - - case 0x14: - dev->ide_regs[0x14] = (val & 0xfc) | 1; - via_vt82c586b_ide_handlers(dev); - break; - case 0x15: - dev->ide_regs[0x15] = val; - via_vt82c586b_ide_handlers(dev); - break; - - case 0x18: - dev->ide_regs[0x18] = (val & 0xf8) | 1; - via_vt82c586b_ide_handlers(dev); - break; - case 0x19: - dev->ide_regs[0x19] = val; - via_vt82c586b_ide_handlers(dev); - break; - - case 0x1c: - dev->ide_regs[0x1c] = (val & 0xfc) | 1; - via_vt82c586b_ide_handlers(dev); - break; - case 0x1d: - dev->ide_regs[0x1d] = val; - via_vt82c586b_ide_handlers(dev); - break; - - case 0x20: - dev->ide_regs[0x20] = (val & 0xf0) | 1; - via_vt82c586b_bus_master_handlers(dev); - break; - case 0x21: - dev->ide_regs[0x21] = val; - via_vt82c586b_bus_master_handlers(dev); - break; - - case 0x3d: - dev->ide_regs[0x3d] = val & 0x01; - via_vt82c586b_ide_irqs(dev); - break; - - case 0x40: - dev->ide_regs[0x40] = val; - via_vt82c586b_ide_handlers(dev); - break; - - default: - dev->ide_regs[addr] = val; - break; - } - break; - - case 2: - /* Read-only addresses */ - if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) || - ((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) || - ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) || - ((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2)) - return; - - switch (addr) { - case 0x04: - dev->usb_regs[0x04] = val & 0x97; - usb_update_io_mapping(dev); - break; - case 0x07: - dev->usb_regs[0x07] &= ~(val & 0x78); - break; - - case 0x20: - dev->usb_regs[0x20] = (val & ~0x1f) | 1; - usb_update_io_mapping(dev); - break; - case 0x21: - dev->usb_regs[0x21] = val; - usb_update_io_mapping(dev); - break; - - default: - dev->usb_regs[addr] = val; - break; - } - break; - - case 3: - /* Read-only addresses */ - if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x48) || - ((addr >= 0x4a) && (addr < 0x50)) || (addr >= 0x54)) - return; - - switch (addr) { - case 0x41: case 0x49: - dev->power_regs[addr] = val; - power_update_io_mapping(dev); - break; - - default: - dev->power_regs[addr] = val; - break; - } - } -} - - -static void -*via_vt82c586b_init(const device_t *info) -{ - via_vt82c586b_t *dev = (via_vt82c586b_t *) malloc(sizeof(via_vt82c586b_t)); - memset(dev, 0, sizeof(via_vt82c586b_t)); - - dev->slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, via_vt82c586b_read, via_vt82c586b_write, dev); - - dev->bm[0] = device_add_inst(&sff8038i_device, 1); - sff_set_slot(dev->bm[0], dev->slot); - sff_set_irq_mode(dev->bm[0], 0, 0); - sff_set_irq_mode(dev->bm[0], 1, 0); - sff_set_irq_pin(dev->bm[0], PCI_INTA); - - dev->bm[1] = device_add_inst(&sff8038i_device, 2); - sff_set_slot(dev->bm[1], dev->slot); - sff_set_irq_mode(dev->bm[1], 0, 0); - sff_set_irq_mode(dev->bm[1], 1, 0); - sff_set_irq_pin(dev->bm[1], PCI_INTA); - - dev->nvr = device_add(&via_nvr_device); - - via_vt82c586b_reset_hard(dev); - - device_add(&port_92_pci_device); - - dma_alias_set(); - - pci_enable_mirq(0); - pci_enable_mirq(1); - pci_enable_mirq(2); - - return dev; -} - -static void -via_vt82c586b_close(void *p) -{ - via_vt82c586b_t *via_vt82c586b = (via_vt82c586b_t *)p; - - free(via_vt82c586b); -} - -const device_t via_vt82c586b_device = -{ - "VIA VT82C586B", - DEVICE_PCI, - 0, - via_vt82c586b_init, - via_vt82c586b_close, - NULL, - NULL, - NULL, - NULL, - NULL -}; diff --git a/src/chipset/via_vt82c596b.c b/src/chipset/via_vt82c596b.c deleted file mode 100644 index 5cc9a2e4e..000000000 --- a/src/chipset/via_vt82c596b.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - - 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. - - - Implementation of the VT82C596B. Based on VT82C586B + PIIX4 - - Authors: Sarah Walker, - - Copyright 2020 Tiseno100 - Copyright 2020 Sarah Walker
- Copyright 2020 Miran Grca - Copyright 2020 Melissa Goad - - TODO: - - The SMBus must be checked and implemented properly - - Fix Documentation errors - -*/ - -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/cdrom.h> -#include "cpu.h" -#include <86box/scsi_device.h> -#include <86box/scsi_cdrom.h> -#include <86box/dma.h> -#include <86box/io.h> -#include <86box/device.h> -#include <86box/apm.h> -#include <86box/keyboard.h> -#include <86box/mem.h> -#include <86box/timer.h> -#include <86box/nvr.h> -#include <86box/pci.h> -#include <86box/pic.h> -#include <86box/port_92.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/hdc_ide_sff8038i.h> -#include <86box/zip.h> -#include <86box/machine.h> -#include <86box/chipset.h> - -// As of now -#include <86box/smbus_piix4.h> - -#define ACPI_TIMER_FREQ 3579545 // Probably Emulator related - -#define ACPI_IO_ENABLE (1 << 7) -#define ACPI_TIMER_32BIT (1 << 3) - -#if defined(DEV_BRANCH) && defined(USE_596B) - -typedef struct -{ - uint8_t pci_to_isa_regs[256]; // PCI-to-ISA (Same as 586B) - uint8_t ide_regs[256]; // Common VIA IDE controller - uint8_t usb_regs[256]; // Common VIA USB controller - uint8_t power_regs[256]; // VT82C596B Power Managment Device(Same as 586B + SMBus) - sff8038i_t * bm[2]; - - nvr_t * nvr; - int nvr_enabled, slot; - - struct - { - uint16_t io_base; - }usb; - - struct - { - uint16_t io_base; - }power; - - smbus_piix4_t * smbus; - -} via_vt82c596b_t; - -static void -via_vt82c596b_reset(void *priv) -{ - - via_vt82c596b_t *via_vt82c596b = (via_vt82c596b_t *) priv; - uint16_t old_base = (via_vt82c596b->ide_regs[0x20] & 0xf0) | (via_vt82c596b->ide_regs[0x21] << 8); - - sff_bus_master_reset(via_vt82c596b->bm[0], old_base); - sff_bus_master_reset(via_vt82c596b->bm[1], old_base + 8); - - memset(via_vt82c596b->pci_to_isa_regs, 0, 256); - memset(via_vt82c596b->ide_regs, 0, 256); - memset(via_vt82c596b->usb_regs, 0, 256); - memset(via_vt82c596b->power_regs, 0, 256); - - - //PCI-to-ISA registers - via_vt82c596b->pci_to_isa_regs[0x00] = 0x06; //VIA - via_vt82c596b->pci_to_isa_regs[0x01] = 0x11; - - via_vt82c596b->pci_to_isa_regs[0x02] = 0x96; //VT82C596B - via_vt82c596b->pci_to_isa_regs[0x03] = 0x05; - - via_vt82c596b->pci_to_isa_regs[0x04] = 0x0f; //Control - - via_vt82c596b->pci_to_isa_regs[0x07] = 2; //Status - - via_vt82c596b->pci_to_isa_regs[0x09] = 0; //Program Interface - - via_vt82c596b->pci_to_isa_regs[0x0A] = 1; //Sub-Class code - via_vt82c596b->pci_to_isa_regs[0x0B] = 6; //Class code - - via_vt82c596b->pci_to_isa_regs[0x0E] = 0x80; //Header Type - - via_vt82c596b->pci_to_isa_regs[0x2C] = 0x73; //Subsystem ID - via_vt82c596b->pci_to_isa_regs[0x2D] = 0x72; - via_vt82c596b->pci_to_isa_regs[0x2E] = 0x71; - via_vt82c596b->pci_to_isa_regs[0x2F] = 0x70; - - via_vt82c596b->pci_to_isa_regs[0x48] = 1; //Miscellaneous control 3 - via_vt82c596b->pci_to_isa_regs[0x4A] = 4; - via_vt82c596b->pci_to_isa_regs[0x4F] = 3; - - via_vt82c596b->pci_to_isa_regs[0x50] = 0x24; //Reserved(?) - via_vt82c596b->pci_to_isa_regs[0x59] = 4; //PIRQ Pin Configuration - - //Resetting the DMA - dma_e = 0x00; - for (int i = 0; i < 8; i++) { - dma[i].ab &= 0xffff000f; - dma[i].ac &= 0xffff000f; - } - - pic_set_shadow(0); - - //IDE registers - via_vt82c596b->ide_regs[0x00] = 0x06; //VIA - via_vt82c596b->ide_regs[0x01] = 0x11; - - via_vt82c596b->ide_regs[0x02] = 0x71; //Common VIA IDE Controller - via_vt82c596b->ide_regs[0x03] = 0x05; - - via_vt82c596b->ide_regs[0x04] = 0x80; //Command - - via_vt82c596b->ide_regs[0x06] = 0x80; //Status - via_vt82c596b->ide_regs[0x07] = 0x02; - - via_vt82c596b->ide_regs[0x09] = 0x85; //Programming Interface - - via_vt82c596b->ide_regs[0x0A] = 0x01; //Sub class code - via_vt82c596b->ide_regs[0x0B] = 0x01; //Base class code - - //Base address control commands - via_vt82c596b->ide_regs[0x10] = 0xF0; - via_vt82c596b->ide_regs[0x11] = 0x01; - - via_vt82c596b->ide_regs[0x14] = 0xF4; - via_vt82c596b->ide_regs[0x15] = 0x03; - - via_vt82c596b->ide_regs[0x18] = 0x70; - via_vt82c596b->ide_regs[0x19] = 0x01; - - via_vt82c596b->ide_regs[0x1C] = 0x74; - via_vt82c596b->ide_regs[0x1D] = 0x03; - - via_vt82c596b->ide_regs[0x20] = 0x01; - via_vt82c596b->ide_regs[0x21] = 0xCC; - //// - - via_vt82c596b->ide_regs[0x3C] = 0x0E; //Interrupt line - - via_vt82c596b->ide_regs[0x40] = 0x08; //Chip Enable - - via_vt82c596b->ide_regs[0x41] = 0x02; //IDE Configuration - - via_vt82c596b->ide_regs[0x42] = 0x09; //Reserved - - via_vt82c596b->ide_regs[0x43] = 0x3A; //FIFO Configuration - - via_vt82c596b->ide_regs[0x44] = 0x68; //Miscellaneous Control 1 - - via_vt82c596b->ide_regs[0x46] = 0xC0; //Miscellaneous Control 3 - - via_vt82c596b->ide_regs[0x48] = 0xA8; //Driver Timing Control - via_vt82c596b->ide_regs[0x49] = 0xA8; - via_vt82c596b->ide_regs[0x4A] = 0xA8; - via_vt82c596b->ide_regs[0x4B] = 0xA8; - - via_vt82c596b->ide_regs[0x4C] = 0xFF; //Address Setup Time - - via_vt82c596b->ide_regs[0x4E] = 0xFF; //Sec Non-1F0 Port Access Timing - via_vt82c596b->ide_regs[0x4F] = 0xFF; //Pri Non-1F0 Port Access Timing - - via_vt82c596b->ide_regs[0x50] = 0x03; //UltraDMA33 Extended Timing Control - via_vt82c596b->ide_regs[0x51] = 0x03; - via_vt82c596b->ide_regs[0x52] = 0x03; - via_vt82c596b->ide_regs[0x53] = 0x03; - - via_vt82c596b->ide_regs[0x61] = 0x02; //IDE Primary Sector Size - via_vt82c596b->ide_regs[0x69] = 0x02; //IDE Secondary Sector Size - - via_vt82c596b->usb_regs[0x00] = 0x06; //VIA USB Common Controller - via_vt82c596b->usb_regs[0x01] = 0x11; - via_vt82c596b->usb_regs[0x02] = 0x38; - via_vt82c596b->usb_regs[0x03] = 0x30; - - //USB Registers - via_vt82c596b->usb_regs[0x04] = 0; //Control - via_vt82c596b->usb_regs[0x05] = 0; - - via_vt82c596b->usb_regs[0x06] = 0; - via_vt82c596b->usb_regs[0x07] = 2; //Status - - via_vt82c596b->usb_regs[0x0A] = 3; //Sub Class Code - via_vt82c596b->usb_regs[0x0B] = 0x0C; //Base Class Code - - via_vt82c596b->usb_regs[0x0D] = 0x16; //Latency Timer - - via_vt82c596b->usb_regs[0x20] = 1; //Base address - via_vt82c596b->usb_regs[0x21] = 3; - - via_vt82c596b->usb_regs[0x3D] = 4; //Interrupt Pin - - via_vt82c596b->usb_regs[0x60] = 0x10; //Serial Bus Release Number(USB 1.0) - via_vt82c596b->usb_regs[0xC1] = 0x20; //Legacy Support - - //Power Management Registers - via_vt82c596b->power_regs[0x00] = 0x06; //VT82C596B Power Managment Controller - via_vt82c596b->power_regs[0x01] = 0x11; - via_vt82c596b->power_regs[0x02] = 0x50; - via_vt82c596b->power_regs[0x03] = 0x30; - - via_vt82c596b->power_regs[0x04] = 0; //Control - via_vt82c596b->power_regs[0x05] = 0; - - via_vt82c596b->power_regs[0x06] = 0x80; //Status - via_vt82c596b->power_regs[0x07] = 2; - - via_vt82c596b->power_regs[0x48] = 1; //Power Managment IO Base - - via_vt82c596b->power_regs[0x90] = 1; //SMBus IO Base - - //Setting up Routing - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED); - - //Disabling the Primary & Secondary controller(?) - ide_pri_disable(); - ide_sec_disable(); -} - - -// IDE CONTROLLER -static void -ide_handlers(via_vt82c596b_t *dev) -{ - uint16_t main, side; - - ide_pri_disable(); - ide_sec_disable(); - - //On Bitfield 0(0x01) Primary Channel operating mode - if (dev->ide_regs[0x09] & 0x01) { - main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8); - side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2; - } else { - main = 0x1f0; - side = 0x3f6; - } - ide_set_base(0, main); - ide_set_side(0, side); - - //On Bitfield 2(0x04) Secondary Channel operating mode - if (dev->ide_regs[0x09] & 0x04) { - main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8); - side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2; - } else { - main = 0x170; - side = 0x376; - } - ide_set_base(1, main); - ide_set_side(1, side); - - //Enable the Primary & Secondary Controllers - if (dev->ide_regs[0x04] & PCI_COMMAND_IO) { - - //On Bitfield 0(0x01) Enable the Secondary Controller - //On Bitfield 1(0x02) Enable the Primary Controller - if (dev->ide_regs[0x40] & 0x02) - ide_pri_enable(); - if (dev->ide_regs[0x40] & 0x01) - ide_sec_enable(); - } -} - - -static void -ide_irqs(via_vt82c596b_t *dev) -{ - int irq_mode[2] = { 0, 0 }; - - if (dev->ide_regs[0x09] & 0x01) - irq_mode[0] = (dev->ide_regs[0x3d] & 0x01); - - if (dev->ide_regs[0x09] & 0x04) - irq_mode[1] = (dev->ide_regs[0x3d] & 0x01); - - sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]); - sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]); - - sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]); - sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]); -} - - -static void -bus_master_handlers(via_vt82c596b_t *dev) -{ - uint16_t base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); - - //On Bitfield 0(0x01) I/O Space - sff_bus_master_handler(dev->bm[0], (dev->ide_regs[0x04] & 1), base); - sff_bus_master_handler(dev->bm[1], (dev->ide_regs[0x04] & 1), base + 8); -} -//// - -// USB CONTROLLER - -static uint8_t -usb_reg_read(uint16_t addr, void *p) -{ - uint8_t ret = 0xff; - - switch (addr & 0x1f) { - case 0x10: case 0x11: case 0x12: case 0x13: - // Return 0 on port status - ret = 0x00; - break; - } - - return ret; -} - -static void -usb_reg_write(uint16_t addr, uint8_t val, void *p) {} - -static void -usb_update_io_mapping(via_vt82c596b_t *dev) -{ - if (dev->usb.io_base != 0x0000) - io_removehandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev); - - //On Bitfield 31 defaults to zero (0x20) - dev->usb.io_base = (dev->usb_regs[0x20] & ~0x1f) | (dev->usb_regs[0x21] << 8); - - //0x20 - //Master Interrupt Control(?) - //TODO: Find the exact meaning - if ((dev->usb_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->usb.io_base != 0x0000)) - io_sethandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev); -} - -//// - -// NVR -static void -nvr_update_io_mapping(via_vt82c596b_t *dev) -{ - - //0x74 CMOS Memory Address - //0x75 CMOS Memory Data - - //Ports 74-75 may be used to access CMOS if the internal RTC is disabled. - - if (dev->nvr_enabled) - nvr_at_handler(0, 0x0074, dev->nvr); - - //In case of we are set on 5B bitfield 1(0x02)(RTC SRAM Access Enable) and 48 bitfield 3(0x08) - //(Extra RTC Port 74/75 Enable) - if ((dev->pci_to_isa_regs[0x5b] & 0x02) && (dev->pci_to_isa_regs[0x48] & 0x08)) - nvr_at_handler(1, 0x0074, dev->nvr); -} -//// - -// POWER MANAGMENT - -// Need excessive documentation -static uint8_t -power_reg_read(uint16_t addr, void *p) -{ - via_vt82c596b_t *dev = (via_vt82c596b_t *) p; - - uint32_t timer; - uint8_t ret = 0xff; - - switch (addr & 0xff) { - case 0x08: case 0x09: case 0x0a: case 0x0b: - - //ACPI Timer - timer = (tsc * ACPI_TIMER_FREQ) / machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; - - if (!(dev->power_regs[0x41] & ACPI_TIMER_32BIT)) - timer &= 0x00ffffff; - ret = (timer >> (8 * (addr & 3))) & 0xff; - - break; - } - - return ret; -} - -static void -power_reg_write(uint16_t addr, uint8_t val, void *p) {} - -static void -power_update_io_mapping(via_vt82c596b_t *dev) -{ - if (dev->power.io_base != 0x0000) - io_removehandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev); - - dev->power.io_base = (dev->power_regs[0x49] << 8); - - if ((dev->power_regs[0x41] & ACPI_IO_ENABLE) && (dev->power.io_base != 0x0000)) - io_sethandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev); -} - -static void -smbus_update_io_mapping(via_vt82c596b_t *dev) -{ - smbus_piix4_remap(dev->smbus, (dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0), (dev->power_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->power_regs[0xD2] & 0x01)); -} -//// - - -static uint8_t -via_vt82c596b_read(int func, int addr, void *priv) -{ - via_vt82c596b_t *dev = (via_vt82c596b_t *) priv; - - uint8_t ret = 0xff; - int c; - - switch(func) { - case 0: - //By System I/O Map, setting up the Keyboard Controller - //60-6F Keyboard Controller [0000 0000 0110] xnxn - if ((addr >= 0x60) && (addr <= 0x6f)) { - c = (addr & 0x0e) >> 1; - if (addr & 0x01) //If Enabled - ret = (dma[c].ab & 0x0000ff00) >> 8; - else { - ret = (dma[c].ab & 0x000000f0); - ret |= (!!(dma_e & (1 << c)) << 3); - } - } else - ret = dev->pci_to_isa_regs[addr]; - break; - case 1: - ret = dev->ide_regs[addr]; - break; - case 2: - ret = dev->usb_regs[addr]; - break; - case 3: - ret = dev->power_regs[addr]; - break; - } - - return ret; -} - -static void -via_vt82c596b_write(int func, int addr, uint8_t val, void *priv) -{ - via_vt82c596b_t *dev = (via_vt82c596b_t *) priv; - int c; - - //Excessive Documentation is needed!! - - if (func > 3) - return; - - switch(func) { - //PCI-to-ISA - case 0: - //Read-only addresses - if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) || - (addr == 0x49) || (addr == 0x4b) || ((addr >= 0x51) && (addr < 0x54)) || - ((addr >= 0x5d) && (addr < 0x60)) || - ((addr >= 0x68) && (addr < 0x6a)) || (addr >= 0x73)) - return; - - switch (addr) { - case 0x04: - dev->pci_to_isa_regs[0x04] = (val & 8) | 7; - break; - case 0x07: - dev->pci_to_isa_regs[0x07] &= ~(val & 0xb0); - break; - - case 0x47: - if ((val & 0x81) == 0x81) - resetx86(); - pic_set_shadow(!!(val & 0x10)); - pci_elcr_set_enabled(!!(val & 0x20)); - dev->pci_to_isa_regs[0x47] = val & 0xfe; - break; - case 0x48: - dev->pci_to_isa_regs[0x48] = val; - nvr_update_io_mapping(dev); - break; - - case 0x54: - pci_set_irq_level(PCI_INTA, !(val & 8)); - pci_set_irq_level(PCI_INTB, !(val & 4)); - pci_set_irq_level(PCI_INTC, !(val & 2)); - pci_set_irq_level(PCI_INTD, !(val & 1)); - break; - case 0x55: - pci_set_irq_routing(PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_to_isa_regs[0x55] = val; - break; - case 0x56: - pci_set_irq_routing(PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_to_isa_regs[0x56] = val; - break; - case 0x57: - pci_set_irq_routing(PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); - pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_to_isa_regs[0x57] = val; - break; - case 0x58: - pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); - dev->pci_to_isa_regs[0x58] = val; - break; - case 0x5b: - dev->pci_to_isa_regs[0x5b] = val; - nvr_update_io_mapping(dev); - break; - - case 0x60: case 0x62: case 0x64: case 0x66: - case 0x6a: case 0x6c: case 0x6e: - c = (addr & 0x0e) >> 1; - dma[c].ab = (dma[c].ab & 0xffffff0f) | (val & 0xf0); - dma[c].ac = (dma[c].ac & 0xffffff0f) | (val & 0xf0); - if (val & 0x08) - dma_e |= (1 << c); - else - dma_e &= ~(1 << c); - break; - case 0x61: case 0x63: case 0x65: case 0x67: - case 0x6b: case 0x6d: case 0x6f: - c = (addr & 0x0e) >> 1; - dma[c].ab = (dma[c].ab & 0xffff00ff) | (val << 8); - dma[c].ac = (dma[c].ac & 0xffff00ff) | (val << 8); - break; - - case 0x70: case 0x71: case 0x72: case 0x73: - dev->pci_to_isa_regs[(addr - 0x44)] = val; - break; - } - break; - - //IDE Controller - case 1: - //Read-only addresses - if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) || - ((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) || - ((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) || - ((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) || - ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x54) && (addr < 0x60)) || - ((addr >= 0x52) && (addr < 0x68)) || (addr >= 0x62)) - return; - - switch (addr) { - case 0x04: - dev->ide_regs[0x04] = val & 0x85; - ide_handlers(dev); - bus_master_handlers(dev); - break; - case 0x07: - dev->ide_regs[0x07] &= ~(val & 0xf1); - break; - - case 0x09: - dev->ide_regs[0x09] = (val & 0x05) | 0x8a; - ide_handlers(dev); - ide_irqs(dev); - break; - - case 0x10: - dev->ide_regs[0x10] = (val & 0xf8) | 1; - ide_handlers(dev); - break; - case 0x11: - dev->ide_regs[0x11] = val; - ide_handlers(dev); - break; - - case 0x14: - dev->ide_regs[0x14] = (val & 0xfc) | 1; - ide_handlers(dev); - break; - case 0x15: - dev->ide_regs[0x15] = val; - ide_handlers(dev); - break; - - case 0x18: - dev->ide_regs[0x18] = (val & 0xf8) | 1; - ide_handlers(dev); - break; - case 0x19: - dev->ide_regs[0x19] = val; - ide_handlers(dev); - break; - - case 0x1c: - dev->ide_regs[0x1c] = (val & 0xfc) | 1; - ide_handlers(dev); - break; - case 0x1d: - dev->ide_regs[0x1d] = val; - ide_handlers(dev); - break; - - case 0x20: - dev->ide_regs[0x20] = (val & 0xf0) | 1; - bus_master_handlers(dev); - break; - case 0x21: - dev->ide_regs[0x21] = val; - bus_master_handlers(dev); - break; - - case 0x3d: - dev->ide_regs[0x3d] = val & 0x01; - ide_irqs(dev); - break; - - case 0x40: - dev->ide_regs[0x40] = val; - ide_handlers(dev); - break; - - default: - dev->ide_regs[addr] = val; - break; - } - break; - - //USB Controller - case 2: - //Read-only addresses - if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) || - ((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) || - ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) || - ((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2)) - return; - - switch (addr) { - case 0x04: - dev->usb_regs[0x04] = val & 0x97; - usb_update_io_mapping(dev); - break; - case 0x07: - dev->usb_regs[0x07] &= ~(val & 0x78); - break; - - case 0x20: - dev->usb_regs[0x20] = (val & ~0x1f) | 1; - usb_update_io_mapping(dev); - break; - case 0x21: - dev->usb_regs[0x21] = val; - usb_update_io_mapping(dev); - break; - - default: - dev->usb_regs[addr] = val; - break; - } - break; - - //Power Management - case 3: - //Read-Only Addresses - if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x48) || - ((addr >= 0x4a) && (addr < 0x50)) || (addr >= 0x54)) - return; - - switch (addr) { - case 0x41: case 0x49: - dev->power_regs[addr] = val; - power_update_io_mapping(dev); - smbus_update_io_mapping(dev); - break; - - case 0x90: - dev->power_regs[0x90] = (val & 0xf0) | 1; - smbus_update_io_mapping(dev); - break; - case 0x91: - dev->power_regs[0x91] = val; - smbus_update_io_mapping(dev); - break; - - default: - dev->power_regs[addr] = val; - break; - } - } -} - -static void * -via_vt82c596b_init(const device_t *info) -{ - via_vt82c596b_t *dev = (via_vt82c596b_t *) malloc(sizeof(via_vt82c596b_t)); - memset(dev, 0, sizeof(via_vt82c596b_t)); - - dev->slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, via_vt82c596b_read, via_vt82c596b_write, dev); - - dev->bm[0] = device_add_inst(&sff8038i_device, 1); - sff_set_slot(dev->bm[0], dev->slot); - sff_set_irq_mode(dev->bm[0], 0, 0); - sff_set_irq_mode(dev->bm[0], 1, 0); - sff_set_irq_pin(dev->bm[0], PCI_INTA); - - dev->bm[1] = device_add_inst(&sff8038i_device, 2); - sff_set_slot(dev->bm[1], dev->slot); - sff_set_irq_mode(dev->bm[1], 0, 0); - sff_set_irq_mode(dev->bm[1], 1, 0); - sff_set_irq_pin(dev->bm[1], PCI_INTA); - - dev->nvr = device_add(&via_nvr_device); - - via_vt82c596b_reset(dev); - - dev->smbus = device_add(&piix4_smbus_device); - - device_add(&port_92_pci_device); - - dma_alias_set(); - - pci_enable_mirq(0); - pci_enable_mirq(1); - pci_enable_mirq(2); - - return dev; -} - -static void -via_vt82c596b_close(void *p) -{ - via_vt82c596b_t *via_vt82c596b = (via_vt82c596b_t *)p; - - free(via_vt82c596b); -} - -const device_t via_vt82c596b_device = -{ - "VIA VT82C596B", - DEVICE_PCI, - 0, - via_vt82c596b_init, - via_vt82c596b_close, - NULL, - NULL, - NULL, - NULL, - NULL -}; -#endif \ No newline at end of file diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c new file mode 100644 index 000000000..ec4703399 --- /dev/null +++ b/src/chipset/vl82c480.c @@ -0,0 +1,217 @@ +/* + * 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 VLSI VL82c480 chipset. + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/nmi.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + +typedef struct { + uint8_t idx, + regs[256]; +} vl82c480_t; + + +static int +vl82c480_shflags(uint8_t access) +{ + int ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + + switch (access) { + case 0x00: + default: + ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + break; + case 0x01: + ret = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + break; + case 0x02: + ret = MEM_READ_INTERNAL | MEM_WRITE_EXTANY; + break; + case 0x03: + ret = MEM_READ_INTERNAL | MEM_WRITE_INTERNAL; + break; + } + + return ret; +} + + +static void +vl82c480_recalc(vl82c480_t *dev) +{ + int i, j; + uint32_t base; + uint8_t access; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 6; i++) { + for (j = 0; j < 8; j += 2) { + 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)); + } + } + + flushmmucache(); +} + + +static void +vl82c480_write(uint16_t addr, uint8_t val, void *p) +{ + vl82c480_t *dev = (vl82c480_t *)p; + + switch (addr) { + case 0xec: + dev->idx = val; + break; + + case 0xed: + if (dev->idx >= 0x01 && dev->idx <= 0x24) { + switch (dev->idx) { + default: + dev->regs[dev->idx] = val; + break; + case 0x04: + if (dev->regs[0x00] == 0x98) + dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7); + else + dev->regs[dev->idx] = val; + break; + case 0x05: + dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x10) | (val & 0xef); + break; + 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: + dev->regs[dev->idx] = val; + vl82c480_recalc(dev); + break; + } + } + break; + + case 0xee: + if (mem_a20_alt) + outb(0x92, inb(0x92) & ~2); + break; + } +} + + +static uint8_t +vl82c480_read(uint16_t addr, void *p) +{ + vl82c480_t *dev = (vl82c480_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0xec: + ret = dev->idx; + break; + + case 0xed: + ret = dev->regs[dev->idx]; + break; + + case 0xee: + if (!mem_a20_alt) + outb(0x92, inb(0x92) | 2); + break; + + case 0xef: + softresetx86(); + cpu_set_edx(); + break; + } + + return ret; +} + + +static void +vl82c480_close(void *p) +{ + vl82c480_t *dev = (vl82c480_t *)p; + + free(dev); +} + + +static void * +vl82c480_init(const device_t *info) +{ + vl82c480_t *dev = (vl82c480_t *)malloc(sizeof(vl82c480_t)); + memset(dev, 0, sizeof(vl82c480_t)); + + dev->regs[0x00] = info->local; + dev->regs[0x01] = 0xff; + dev->regs[0x02] = 0x8a; + dev->regs[0x03] = 0x88; + dev->regs[0x06] = 0x1b; + if (info->local == 0x98) + dev->regs[0x07] = 0x21; + dev->regs[0x08] = 0x38; + + io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, dev); + + device_add(&port_92_device); + + return dev; +} + +const device_t vl82c480_device = { + .name = "VLSI VL82c480", + .internal_name = "vl82c480", + .flags = 0, + .local = 0x90, + .init = vl82c480_init, + .close = vl82c480_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t vl82c486_device = { + .name = "VLSI VL82c486", + .internal_name = "vl82c486", + .flags = 0, + .local = 0x98, + .init = vl82c480_init, + .close = vl82c480_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index 98e0d24d5..12b7e19a0 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -6,234 +6,422 @@ * * This file is part of the 86Box distribution. * - * Implementation of the WD76C10 System Controller chip. + * Implementation of the Western Digital WD76C10 chipset. * + * Note: This chipset has no datasheet, everything were done via + * reverse engineering the BIOS of various machines using it. * + * Authors: Tiseno100 * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, + * Copyright 2021 Tiseno100 * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. */ + +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/device.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/io.h> -#include <86box/keyboard.h> +#include <86box/device.h> +#include <86box/dma.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/hdd.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/lpt.h> #include <86box/mem.h> #include <86box/port_92.h> #include <86box/serial.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/video.h> #include <86box/chipset.h> +/* Lock/Unlock Procedures */ +#define LOCK dev->lock +#define UNLOCKED !dev->lock -typedef struct { - int type; +#ifdef ENABLE_WD76C10_LOG +int wd76c10_do_log = ENABLE_WD76C10_LOG; +static void +wd76c10_log(const char *fmt, ...) +{ + va_list ap; - uint16_t reg_0092; - uint16_t reg_2072; - uint16_t reg_2872; - uint16_t reg_5872; + if (wd76c10_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define wd76c10_log(fmt, ...) +#endif - uint16_t reg_f872; +typedef struct +{ + uint16_t lock_reg, oscillator_40mhz, cache_flush, ems_page_reg, + ems_page_reg_pointer, port_shadow, pmc_interrupt, + high_mem_protect_boundry, delay_line, diagnostic, + nmi_status, pmc_input, pmc_timer, + pmc_output, ems_control_low_address_boundry, shadow_ram, + split_addr, bank32staddr, bank10staddr, + non_page_mode_dram_timing, mem_control, + refresh_control, disk_chip_select, prog_chip_sel_addr, + bus_timing_power_down_ctl, clk_control; - serial_t *uart[2]; + int lock; - fdc_t *fdc; - - mem_mapping_t extram_mapping; - uint8_t extram[65536]; + fdc_t *fdc_controller; + mem_mapping_t *mem_mapping; + serial_t *uart[2]; } wd76c10_t; +static void wd76c10_refresh_control(wd76c10_t *dev) +{ + serial_remove(dev->uart[1]); + /* Serial B */ + switch ((dev->refresh_control >> 1) & 7) + { + case 1: + serial_setup(dev->uart[1], 0x3f8, 3); + break; + case 2: + serial_setup(dev->uart[1], 0x2f8, 3); + break; + case 3: + serial_setup(dev->uart[1], 0x3e8, 3); + break; + case 4: + serial_setup(dev->uart[1], 0x2e8, 3); + break; + } + + serial_remove(dev->uart[0]); + /* Serial A */ + switch ((dev->refresh_control >> 5) & 7) + { + case 1: + serial_setup(dev->uart[0], 0x3f8, 4); + break; + case 2: + serial_setup(dev->uart[0], 0x2f8, 4); + break; + case 3: + serial_setup(dev->uart[0], 0x3e8, 4); + break; + case 4: + serial_setup(dev->uart[0], 0x2e8, 4); + break; + } + + lpt1_remove(); + /* LPT */ + switch ((dev->refresh_control >> 9) & 3) + { + case 1: + lpt1_init(0x3bc); + lpt1_irq(7); + break; + case 2: + lpt1_init(0x378); + lpt1_irq(7); + break; + case 3: + lpt1_init(0x278); + lpt1_irq(7); + break; + } +} + +static void wd76c10_split_addr(wd76c10_t *dev) +{ + switch ((dev->split_addr >> 8) & 3) + { + case 1: + if (((dev->shadow_ram >> 8) & 3) == 2) + mem_remap_top(256); + break; + case 2: + if (((dev->shadow_ram >> 8) & 3) == 1) + mem_remap_top(320); + break; + case 3: + if (((dev->shadow_ram >> 8) & 3) == 3) + mem_remap_top(384); + break; + } +} + +static void wd76c10_disk_chip_select(wd76c10_t *dev) +{ + ide_pri_disable(); + if (!(dev->disk_chip_select & 1)) + { + ide_set_base(0, !(dev->disk_chip_select & 0x0010) ? 0x1f0 : 0x170); + ide_set_side(0, !(dev->disk_chip_select & 0x0010) ? 0x3f6 : 0x376); + } + ide_pri_enable(); + + fdc_remove(dev->fdc_controller); + if (!(dev->disk_chip_select & 2)) + fdc_set_base(dev->fdc_controller, !(dev->disk_chip_select & 0x0010) ? FDC_PRIMARY_ADDR : FDC_SECONDARY_ADDR); +} + +static void wd76c10_shadow_recalc(wd76c10_t *dev) +{ + switch ((dev->shadow_ram >> 14) & 3) + { + case 0: + mem_set_mem_state_both(0x20000, 0x80000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 1: + mem_set_mem_state_both(0x80000, 0x20000, MEM_READ_DISABLED | MEM_WRITE_DISABLED); + break; + case 2: + mem_set_mem_state_both(0x40000, 0x60000, MEM_READ_DISABLED | MEM_WRITE_DISABLED); + break; + case 3: + mem_set_mem_state_both(0x20000, 0x80000, MEM_READ_DISABLED | MEM_WRITE_DISABLED); + break; + } + + switch ((dev->shadow_ram >> 8) & 3) + { + case 0: + mem_set_mem_state_both(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state_both(0xc0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | (!!(dev->shadow_ram & 0x1000) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)); + break; + case 2: + mem_set_mem_state_both(0xe0000, 0x20000, MEM_READ_INTERNAL | (!!(dev->shadow_ram & 0x1000) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)); + break; + case 3: + mem_set_mem_state_both(0x20000, 0x80000, MEM_READ_DISABLED | (!!(dev->shadow_ram & 0x1000) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)); + break; + } +} + +static void +wd76c10_write(uint16_t addr, uint16_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + if (UNLOCKED) + { + switch (addr) + { + case 0x1072: + dev->clk_control = val; + break; + + case 0x1872: + dev->bus_timing_power_down_ctl = val; + break; + + case 0x2072: + dev->refresh_control = val; + wd76c10_refresh_control(dev); + break; + + case 0x2872: + dev->disk_chip_select = val; + wd76c10_disk_chip_select(dev); + break; + + case 0x3072: + dev->prog_chip_sel_addr = val; + break; + + case 0x3872: + dev->non_page_mode_dram_timing = val; + break; + + case 0x4072: + dev->mem_control = val; + break; + + case 0x4872: + dev->bank10staddr = val; + break; + + case 0x5072: + dev->bank32staddr = val; + break; + + case 0x5872: + dev->split_addr = val; + wd76c10_split_addr(dev); + break; + + case 0x6072: + dev->shadow_ram = val & 0xffbf; + wd76c10_shadow_recalc(dev); + break; + + case 0x6872: + dev->ems_control_low_address_boundry = val & 0xecff; + break; + + case 0x7072: + dev->pmc_output = (val >> 8) & 0x00ff; + break; + + case 0x7872: + dev->pmc_output = val & 0xff00; + break; + + case 0x8072: + dev->pmc_timer = val; + break; + + case 0x8872: + dev->pmc_input = val; + break; + + case 0x9072: + dev->nmi_status = val & 0x00fc; + break; + + case 0x9872: + dev->diagnostic = val & 0xfdff; + break; + + case 0xa072: + dev->delay_line = val; + break; + + case 0xc872: + dev->pmc_interrupt = val & 0xfcfc; + break; + + case 0xf072: + dev->oscillator_40mhz = 0; + break; + + case 0xf472: + dev->oscillator_40mhz = 1; + break; + + case 0xf872: + dev->cache_flush = val; + flushmmucache(); + break; + } + wd76c10_log("WD76C10: dev->regs[%04x] = %04x\n", addr, val); + } + + switch (addr) + { + case 0xe072: + dev->ems_page_reg_pointer = val & 0x003f; + break; + + case 0xe872: + dev->ems_page_reg = val & 0x8fff; + break; + + case 0xf073: + dev->lock_reg = val & 0x00ff; + LOCK = !(val & 0x00da); + break; + } +} static uint16_t -wd76c10_read(uint16_t port, void *priv) +wd76c10_read(uint16_t addr, void *priv) { wd76c10_t *dev = (wd76c10_t *)priv; - int16_t ret = 0xffff; + wd76c10_log("WD76C10: R dev->regs[%04x]\n", addr); + switch (addr) + { + case 0x1072: + return dev->clk_control; - switch (port) { - case 0x2072: - ret = dev->reg_2072; - break; + case 0x1872: + return dev->bus_timing_power_down_ctl; - case 0x2872: - ret = dev->reg_2872; - break; + case 0x2072: + return dev->refresh_control; - case 0x5872: - ret = dev->reg_5872; - break; + case 0x2872: + return dev->disk_chip_select; - case 0xf872: - ret = dev->reg_f872; - break; - } + case 0x3072: + return dev->prog_chip_sel_addr; - return(ret); -} + case 0x3872: + return dev->non_page_mode_dram_timing; + case 0x4072: + return dev->mem_control; -static void -wd76c10_write(uint16_t port, uint16_t val, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; + case 0x4872: + return dev->bank10staddr; - switch (port) { - case 0x2072: - dev->reg_2072 = val; + case 0x5072: + return dev->bank32staddr; - serial_remove(dev->uart[0]); - if (!(val & 0x10)) - { - switch ((val >> 5) & 7) - { - case 1: serial_setup(dev->uart[0], 0x3f8, 4); break; - case 2: serial_setup(dev->uart[0], 0x2f8, 4); break; - case 3: serial_setup(dev->uart[0], 0x3e8, 4); break; - case 4: serial_setup(dev->uart[0], 0x2e8, 4); break; - default: break; - } - } - serial_remove(dev->uart[1]); - if (!(val & 0x01)) - { - switch ((val >> 1) & 7) - { - case 1: serial_setup(dev->uart[1], 0x3f8, 3); break; - case 2: serial_setup(dev->uart[1], 0x2f8, 3); break; - case 3: serial_setup(dev->uart[1], 0x3e8, 3); break; - case 4: serial_setup(dev->uart[1], 0x2e8, 3); break; - default: break; - } - } - break; + case 0x5872: + return dev->split_addr; - case 0x2872: - dev->reg_2872 = val; + case 0x6072: + return dev->shadow_ram; - fdc_remove(dev->fdc); - if (! (val & 1)) - fdc_set_base(dev->fdc, 0x03f0); - break; + case 0x6872: + return dev->ems_control_low_address_boundry; - case 0x5872: - dev->reg_5872 = val; - break; + case 0x7072: + return (dev->pmc_output << 8) & 0xff00; - case 0xf872: - dev->reg_f872 = val; - switch (val & 3) { - case 0: - mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 2: - mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); - if (val & 4) - mem_mapping_enable(&dev->extram_mapping); - else - mem_mapping_disable(&dev->extram_mapping); - flushmmucache_nopc(); - break; + case 0x7872: + return (dev->pmc_output) & 0xff00; + + case 0x8072: + return dev->pmc_timer; + + case 0x8872: + return dev->pmc_input; + + case 0x9072: + return dev->nmi_status; + + case 0x9872: + return dev->diagnostic; + + case 0xa072: + return dev->delay_line; + + case 0xb872: + return (inb(0x040b) << 8) | inb(0x04d6); + + case 0xc872: + return dev->pmc_interrupt; + + case 0xd072: + return dev->port_shadow; + + case 0xe072: + return dev->ems_page_reg_pointer; + + case 0xe872: + return dev->ems_page_reg; + + case 0xfc72: + return 0x0ff0; + + default: + return 0xffff; } } - -static uint8_t -wd76c10_readb(uint16_t port, void *priv) -{ - if (port & 1) - return(wd76c10_read(port & ~1, priv) >> 8); - - return(wd76c10_read(port, priv) & 0xff); -} - - -static void -wd76c10_writeb(uint16_t port, uint8_t val, void *priv) -{ - uint16_t temp = wd76c10_read(port, priv); - - if (port & 1) - wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); - else - wd76c10_write(port , (temp & 0xff00) | val, priv); -} - - -uint8_t -wd76c10_read_extram(uint32_t addr, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; - - return dev->extram[addr & 0xffff]; -} - - -uint16_t -wd76c10_read_extramw(uint32_t addr, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; - - return *(uint16_t *)&dev->extram[addr & 0xffff]; -} - - -uint32_t -wd76c10_read_extraml(uint32_t addr, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; - - return *(uint32_t *)&dev->extram[addr & 0xffff]; -} - - -void -wd76c10_write_extram(uint32_t addr, uint8_t val, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; - - dev->extram[addr & 0xffff] = val; -} - - -void -wd76c10_write_extramw(uint32_t addr, uint16_t val, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; - - *(uint16_t *)&dev->extram[addr & 0xffff] = val; -} - - -void -wd76c10_write_extraml(uint32_t addr, uint32_t val, void *priv) -{ - wd76c10_t *dev = (wd76c10_t *)priv; - - *(uint32_t *)&dev->extram[addr & 0xffff] = val; -} - - static void wd76c10_close(void *priv) { @@ -242,51 +430,121 @@ wd76c10_close(void *priv) free(dev); } - static void * wd76c10_init(const device_t *info) { - wd76c10_t *dev; + wd76c10_t *dev = (wd76c10_t *)malloc(sizeof(wd76c10_t)); + memset(dev, 0, sizeof(wd76c10_t)); - dev = (wd76c10_t *) malloc(sizeof(wd76c10_t)); - memset(dev, 0x00, sizeof(wd76c10_t)); - dev->type = info->local; + device_add(&port_92_inv_device); + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + dev->fdc_controller = device_add(&fdc_at_device); + device_add(&ide_isa_device); - dev->fdc = (fdc_t *)device_add(&fdc_at_device); + /* Lock Configuration */ + LOCK = 1; - dev->uart[0] = device_add_inst(&i8250_device, 1); - dev->uart[1] = device_add_inst(&i8250_device, 2); + /* Clock Control */ + io_sethandler(0x1072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); - device_add(&port_92_word_device); + /* Bus Timing & Power Down Control */ + io_sethandler(0x1872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); - io_sethandler(0x2072, 2, - wd76c10_readb,wd76c10_read,NULL, - wd76c10_writeb,wd76c10_write,NULL, dev); - io_sethandler(0x2872, 2, - wd76c10_readb,wd76c10_read,NULL, - wd76c10_writeb,wd76c10_write,NULL, dev); - io_sethandler(0x5872, 2, - wd76c10_readb,wd76c10_read,NULL, - wd76c10_writeb,wd76c10_write,NULL, dev); - io_sethandler(0xf872, 2, - wd76c10_readb,wd76c10_read,NULL, - wd76c10_writeb,wd76c10_write,NULL, dev); + /* Refresh Control(Serial & Parallel) */ + io_sethandler(0x2072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); - mem_mapping_add(&dev->extram_mapping, 0xd0000, 0x10000, - wd76c10_read_extram,wd76c10_read_extramw,wd76c10_read_extraml, - wd76c10_write_extram,wd76c10_write_extramw,wd76c10_write_extraml, - dev->extram, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->extram_mapping); + /* Disk Chip Select */ + io_sethandler(0x2872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); - return(dev); + /* Programmable Chip Select Address(Needs more further examination!) */ + io_sethandler(0x3072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* Bank 1 & 0 Start Address */ + io_sethandler(0x4872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* Bank 3 & 2 Start Address */ + io_sethandler(0x5072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* Split Address */ + io_sethandler(0x5872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* EMS Control & EMS Low level boundry */ + io_sethandler(0x6072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* EMS Control & EMS Low level boundry */ + io_sethandler(0x6872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* PMC Output */ + io_sethandler(0x7072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* PMC Output */ + io_sethandler(0x7872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* PMC Status */ + io_sethandler(0x8072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* PMC Status */ + io_sethandler(0x8872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* NMI Status (Needs further checkup) */ + io_sethandler(0x9072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* Diagnostics */ + io_sethandler(0x9872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* Delay Line */ + io_sethandler(0xa072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* DMA Mode Shadow(Needs Involvement on the DMA code) */ + io_sethandler(0xb872, 1, NULL, wd76c10_read, NULL, NULL, NULL, NULL, dev); + + /* High Memory Protection Boundry */ + io_sethandler(0xc072, 1, NULL, wd76c10_read, NULL, NULL, NULL, NULL, dev); + + /* PMC Interrupt Enable */ + io_sethandler(0xc872, 1, NULL, wd76c10_read, NULL, NULL, NULL, NULL, dev); + + /* Port Shadow (Needs further lookup) */ + io_sethandler(0xd072, 1, NULL, wd76c10_read, NULL, NULL, NULL, NULL, dev); + + /* EMS Page Register Pointer */ + io_sethandler(0xe072, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* EMS Page Register */ + io_sethandler(0xe872, 1, NULL, wd76c10_read, NULL, NULL, wd76c10_write, NULL, dev); + + /* Lock/Unlock Configuration */ + io_sethandler(0xf073, 1, NULL, NULL, NULL, NULL, wd76c10_write, NULL, dev); + + /* 40Mhz Oscillator Enable Disable */ + io_sethandler(0xf072, 1, NULL, NULL, NULL, NULL, wd76c10_write, NULL, dev); + io_sethandler(0xf472, 1, NULL, NULL, NULL, NULL, wd76c10_write, NULL, dev); + + /* Lock Status */ + io_sethandler(0xfc72, 1, NULL, wd76c10_read, NULL, NULL, NULL, NULL, dev); + + /* Cache Flush */ + io_sethandler(0xf872, 1, NULL, wd76c10_read, NULL, NULL, NULL, NULL, dev); + + dma_ext_mode_init(); + + wd76c10_shadow_recalc(dev); + wd76c10_refresh_control(dev); + wd76c10_disk_chip_select(dev); + return dev; } - const device_t wd76c10_device = { - "WD 76C10", - 0, - 0, - wd76c10_init, wd76c10_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Western Digital WD76C10", + .internal_name = "wd76c10", + .flags = 0, + .local = 0, + .init = wd76c10_init, + .close = wd76c10_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/codegen/CMakeLists.txt b/src/codegen/CMakeLists.txt new file mode 100644 index 000000000..416b4792a --- /dev/null +++ b/src/codegen/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +if(DYNAREC) + add_library(dynarec OBJECT codegen.c codegen_ops.c) + + if(ARCH STREQUAL "i386") + target_sources(dynarec PRIVATE codegen_x86.c + codegen_accumulate_x86.c) + elseif(ARCH STREQUAL "x86_64") + target_sources(dynarec PRIVATE codegen_x86-64.c + codegen_accumulate_x86-64.c) + else() + message(SEND_ERROR + "Dynarec is incompatible with target platform ${ARCH}") + endif() + + target_link_libraries(86Box dynarec cgt) +endif() diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h index 086d00347..ac85d8662 100644 --- a/src/codegen/codegen.h +++ b/src/codegen/codegen.h @@ -56,18 +56,18 @@ added to the page_lookup for this purpose. When in the page_lookup, each write will go through the mem_write_ram*_page() functions and set the dirty mask appropriately. - + Each codeblock also contains a code mask (actually two masks, one for each page the block is/may be in), again with each bit representing 64 bytes. - + Each page has a list of codeblocks present in it. As each codeblock can span up to two pages, two lists are present. - + When a codeblock is about to be executed, the code masks are compared with the dirty masks for the relevant pages. If either intersect, then codegen_check_flush() is called on the affected page(s), and all affected blocks are evicted. - + The 64 byte granularity appears to work reasonably well for most cases, avoiding most unnecessary evictions (eg when code & data are stored in the same page). @@ -78,17 +78,17 @@ typedef struct codeblock_t uint64_t page_mask, page_mask2; uint64_t *dirty_mask, *dirty_mask2; uint64_t cmp; - + /*Previous and next pointers, for the codeblock list associated with each physical page. Two sets of pointers, as a codeblock can be present in two pages.*/ struct codeblock_t *prev, *next; struct codeblock_t *prev_2, *next_2; - + /*Pointers for codeblock tree, used to search for blocks when hash lookup fails.*/ struct codeblock_t *parent, *left, *right; - + int pnt; int ins; @@ -116,7 +116,7 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) { codeblock_t *block = pages[phys >> 12].head; uint64_t a = _cs | ((uint64_t)phys << 32); - + while (block) { if (a == block->cmp) @@ -130,7 +130,7 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) else block = block->right; } - + return block; } @@ -139,7 +139,7 @@ static inline void codeblock_tree_add(codeblock_t *new_block) codeblock_t *block = pages[new_block->phys >> 12].head; uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32); new_block->cmp = a; - + if (!block) { pages[new_block->phys >> 12].head = new_block; @@ -148,7 +148,7 @@ static inline void codeblock_tree_add(codeblock_t *new_block) else { codeblock_t *old_block = NULL; - + while (block) { old_block = block; @@ -157,12 +157,12 @@ static inline void codeblock_tree_add(codeblock_t *new_block) else block = block->right; } - + if (a < old_block->cmp) old_block->left = new_block; else old_block->right = new_block; - + new_block->parent = old_block; new_block->left = new_block->right = NULL; } @@ -237,7 +237,7 @@ static inline void codeblock_tree_delete(codeblock_t *block) /*Difficult case - node has two children. Walk right child to find lowest node*/ codeblock_t *lowest = block->right, *highest; codeblock_t *old_parent; - + while (lowest->left) lowest = lowest->left; @@ -260,7 +260,7 @@ static inline void codeblock_tree_delete(codeblock_t *block) lowest->left->parent = lowest; old_parent->left = NULL; - + highest = lowest->right; if (!highest) { @@ -308,13 +308,6 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr); extern int cpu_block_end; extern uint32_t codegen_endpc; -extern int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; -extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; -extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; -extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; -extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; -extern int cpu_recomp_removed, cpu_recomp_removed_latched; - extern int codegen_block_cycles; extern void (*codegen_timing_start)(); diff --git a/src/codegen/codegen_accumulate.h b/src/codegen/codegen_accumulate.h index 8f9f6c95b..b1e64db18 100644 --- a/src/codegen/codegen_accumulate.h +++ b/src/codegen/codegen_accumulate.h @@ -1,8 +1,7 @@ enum { - ACCREG_ins = 0, - ACCREG_cycles = 1, - + ACCREG_cycles = 0, + ACCREG_COUNT }; diff --git a/src/codegen/codegen_accumulate_x86-64.c b/src/codegen/codegen_accumulate_x86-64.c index 9b089df02..05a728ae5 100644 --- a/src/codegen/codegen_accumulate_x86-64.c +++ b/src/codegen/codegen_accumulate_x86-64.c @@ -13,38 +13,57 @@ static struct uintptr_t dest_reg; } acc_regs[] = { - [ACCREG_ins] = {0, (uintptr_t) &(ins)}, [ACCREG_cycles] = {0, (uintptr_t) &(cycles)}, }; void codegen_accumulate(int acc_reg, int delta) { acc_regs[acc_reg].count += delta; + +#ifdef USE_ACYCS + if ((acc_reg == ACCREG_cycles) && (delta != 0)) { + if (delta == -1) { + /* -delta = 1 */ + addbyte(0xff); /*inc dword ptr[&acycs]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t) (uintptr_t) &(acycs)); + } else if (delta == 1) { + /* -delta = -1 */ + addbyte(0xff); /*dec dword ptr[&acycs]*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t) (uintptr_t) &(acycs)); + } else { + addbyte(0x81); /*ADD $acc_regs[c].count,acc_regs[c].dest*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t) (uintptr_t) &(acycs)); + addlong(-delta); + } + } +#endif } void codegen_accumulate_flush(void) { - int c; - - for (c = 0; c < ACCREG_COUNT; c++) - { - if (acc_regs[c].count) - { - addbyte(0x81); /*ADD $acc_regs[c].count,acc_regs[c].dest*/ - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t) acc_regs[c].dest_reg); - addlong(acc_regs[c].count); - } + if (acc_regs[0].count) { + addbyte(0x55); /*push rbp*/ + addbyte(0x48); /*mov rbp,val*/ + addbyte(0xbd); + addlong((uint32_t) (acc_regs[0].dest_reg & 0xffffffffULL)); + addlong((uint32_t) (acc_regs[0].dest_reg >> 32ULL)); + addbyte(0x81); /* add d,[rbp][0],val */ + addbyte(0x45); + addbyte(0x00); + addlong(acc_regs[0].count); + addbyte(0x5d); /*pop rbp*/ + } - acc_regs[c].count = 0; - } + acc_regs[0].count = 0; } void codegen_accumulate_reset() { - int c; - - for (c = 0; c < ACCREG_COUNT; c++) - acc_regs[c].count = 0; + acc_regs[0].count = 0; } diff --git a/src/codegen/codegen_accumulate_x86.c b/src/codegen/codegen_accumulate_x86.c index 2b99d4c66..424cc45ab 100644 --- a/src/codegen/codegen_accumulate_x86.c +++ b/src/codegen/codegen_accumulate_x86.c @@ -13,37 +13,48 @@ static struct uintptr_t dest_reg; } acc_regs[] = { - [ACCREG_ins] = {0, (uintptr_t) &(ins)}, - [ACCREG_cycles] = {0, (uintptr_t) &(cycles)}, + [ACCREG_cycles] = {0, (uintptr_t) &(cycles)} }; void codegen_accumulate(int acc_reg, int delta) { acc_regs[acc_reg].count += delta; + +#ifdef USE_ACYCS + if ((acc_reg == ACCREG_cycles) && (delta != 0)) { + if (delta == -1) { + /* -delta = 1 */ + addbyte(0xff); /*inc dword ptr[&acycs]*/ + addbyte(0x05); + addlong((uint32_t) (uintptr_t) &(acycs)); + } else if (delta == 1) { + /* -delta = -1 */ + addbyte(0xff); /*dec dword ptr[&acycs]*/ + addbyte(0x0d); + addlong((uint32_t) (uintptr_t) &(acycs)); + } else { + addbyte(0x81); /*ADD $acc_regs[c].count,acc_regs[c].dest*/ + addbyte(0x05); + addlong((uint32_t) (uintptr_t) &(acycs)); + addlong((uintptr_t) -delta); + } + } +#endif } void codegen_accumulate_flush(void) { - int c; - - for (c = 0; c < ACCREG_COUNT; c++) - { - if (acc_regs[c].count) - { - addbyte(0x81); /*ADD $acc_regs[c].count,acc_regs[c].dest*/ - addbyte(0x05); - addlong((uint32_t) acc_regs[c].dest_reg); - addlong(acc_regs[c].count); - } + if (acc_regs[0].count) { + addbyte(0x81); /*ADD $acc_regs[0].count,acc_regs[0].dest*/ + addbyte(0x05); + addlong((uint32_t) acc_regs[0].dest_reg); + addlong(acc_regs[0].count); + } - acc_regs[c].count = 0; - } + acc_regs[0].count = 0; } void codegen_accumulate_reset() { - int c; - - for (c = 0; c < ACCREG_COUNT; c++) - acc_regs[c].count = 0; + acc_regs[0].count = 0; } diff --git a/src/codegen/codegen_ops.c b/src/codegen/codegen_ops.c index d1410346f..aedeb88a9 100644 --- a/src/codegen/codegen_ops.c +++ b/src/codegen/codegen_ops.c @@ -15,9 +15,9 @@ #include "codegen.h" #include "codegen_ops.h" -#ifdef __amd64__ +#if defined __amd64__ || defined _M_X64 #include "codegen_ops_x86-64.h" -#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 #include "codegen_ops_x86.h" #endif @@ -35,7 +35,7 @@ RecompOpFn recomp_opcodes[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropADD_b_rmw, ropADD_w_rmw, ropADD_b_rm, ropADD_w_rm, ropADD_AL_imm, ropADD_AX_imm, ropPUSH_ES_16, ropPOP_ES_16, ropOR_b_rmw, ropOR_w_rmw, ropOR_b_rm, ropOR_w_rm, ropOR_AL_imm, ropOR_AX_imm, ropPUSH_CS_16, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_16, ropPOP_DS_16, /*20*/ ropAND_b_rmw, ropAND_w_rmw, ropAND_b_rm, ropAND_w_rm, ropAND_AL_imm, ropAND_AX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_w_rmw, ropSUB_b_rm, ropSUB_w_rm, ropSUB_AL_imm, ropSUB_AX_imm, NULL, NULL, @@ -57,7 +57,7 @@ RecompOpFn recomp_opcodes[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_w, NULL, NULL, ropCLI, ropSTI, ropCLD, ropSTD, ropFE, ropFF_16, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropADD_b_rmw, ropADD_l_rmw, ropADD_b_rm, ropADD_l_rm, ropADD_AL_imm, ropADD_EAX_imm, ropPUSH_ES_32, ropPOP_ES_32, ropOR_b_rmw, ropOR_l_rmw, ropOR_b_rm, ropOR_l_rm, ropOR_AL_imm, ropOR_EAX_imm, ropPUSH_CS_32, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_32, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_32, ropPOP_DS_32, /*20*/ ropAND_b_rmw, ropAND_l_rmw, ropAND_b_rm, ropAND_l_rm, ropAND_AL_imm, ropAND_EAX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_l_rmw, ropSUB_b_rm, ropSUB_l_rm, ropSUB_AL_imm, ropSUB_EAX_imm, NULL, NULL, @@ -82,7 +82,7 @@ RecompOpFn recomp_opcodes[512] = RecompOpFn recomp_opcodes_0f[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -104,7 +104,7 @@ RecompOpFn recomp_opcodes_0f[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -130,7 +130,7 @@ RecompOpFn recomp_opcodes_0f[512] = RecompOpFn recomp_opcodes_d8[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, /*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, /*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, @@ -152,7 +152,7 @@ RecompOpFn recomp_opcodes_d8[512] = /*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, /*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, /*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, @@ -177,7 +177,7 @@ RecompOpFn recomp_opcodes_d8[512] = RecompOpFn recomp_opcodes_d9[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, @@ -199,7 +199,7 @@ RecompOpFn recomp_opcodes_d9[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, @@ -224,7 +224,7 @@ RecompOpFn recomp_opcodes_d9[512] = RecompOpFn recomp_opcodes_da[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, /*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, /*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, @@ -246,7 +246,7 @@ RecompOpFn recomp_opcodes_da[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, /*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, /*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, @@ -271,7 +271,7 @@ RecompOpFn recomp_opcodes_da[512] = RecompOpFn recomp_opcodes_db[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -293,7 +293,7 @@ RecompOpFn recomp_opcodes_db[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -318,7 +318,7 @@ RecompOpFn recomp_opcodes_db[512] = RecompOpFn recomp_opcodes_dc[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, /*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, /*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, @@ -340,7 +340,7 @@ RecompOpFn recomp_opcodes_dc[512] = /*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, /*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, /*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, @@ -365,7 +365,7 @@ RecompOpFn recomp_opcodes_dc[512] = RecompOpFn recomp_opcodes_dd[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -387,7 +387,7 @@ RecompOpFn recomp_opcodes_dd[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -412,7 +412,7 @@ RecompOpFn recomp_opcodes_dd[512] = RecompOpFn recomp_opcodes_de[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, /*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, /*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, @@ -434,7 +434,7 @@ RecompOpFn recomp_opcodes_de[512] = /*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, /*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, /*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, @@ -459,7 +459,7 @@ RecompOpFn recomp_opcodes_de[512] = RecompOpFn recomp_opcodes_df[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, @@ -481,7 +481,7 @@ RecompOpFn recomp_opcodes_df[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, @@ -506,7 +506,7 @@ RecompOpFn recomp_opcodes_df[512] = RecompOpFn recomp_opcodes_REPE[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -528,7 +528,7 @@ RecompOpFn recomp_opcodes_REPE[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -553,7 +553,7 @@ RecompOpFn recomp_opcodes_REPE[512] = RecompOpFn recomp_opcodes_REPNE[512] = { /*16-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -575,7 +575,7 @@ RecompOpFn recomp_opcodes_REPNE[512] = /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff --git a/src/codegen/codegen_ops_arith.h b/src/codegen/codegen_ops_arith.h index ed2ce1ece..2e497f17c 100644 --- a/src/codegen/codegen_ops_arith.h +++ b/src/codegen/codegen_ops_arith.h @@ -1,18 +1,19 @@ static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg; - + CALL_FUNC((uintptr_t)flags_rebuild_c); - + host_reg = LOAD_REG_W(opcode & 7); - + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_W(host_reg, 1); + // ADD_HOST_REG_IMM_W(host_reg, 1); + INC_HOST_REG_W(host_reg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); - + codegen_flags_changed = 1; return op_pc; @@ -22,11 +23,12 @@ static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin int host_reg; CALL_FUNC((uintptr_t)flags_rebuild_c); - + host_reg = LOAD_REG_L(opcode & 7); - + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM(host_reg, 1); + // ADD_HOST_REG_IMM(host_reg, 1); + INC_HOST_REG(host_reg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); @@ -39,13 +41,14 @@ static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg; - + CALL_FUNC((uintptr_t)flags_rebuild_c); host_reg = LOAD_REG_W(opcode & 7); - + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_W(host_reg, 1); + // SUB_HOST_REG_IMM_W(host_reg, 1); + DEC_HOST_REG_W(host_reg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); @@ -58,13 +61,14 @@ static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg; - + CALL_FUNC((uintptr_t)flags_rebuild_c); host_reg = LOAD_REG_L(opcode & 7); - + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM(host_reg, 1); + // SUB_HOST_REG_IMM(host_reg, 1); + DEC_HOST_REG(host_reg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); @@ -470,10 +474,10 @@ static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_B_RELEASE(host_reg); - codegen_flags_changed = 1; + codegen_flags_changed = 1; return op_pc + 1; } static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -484,9 +488,9 @@ static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); - + codegen_flags_changed = 1; return op_pc + 2; } @@ -499,9 +503,9 @@ static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 ADD_HOST_REG_IMM(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); - + codegen_flags_changed = 1; return op_pc + 4; } @@ -514,23 +518,23 @@ static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 1; } static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg = LOAD_REG_W(REG_AX); - + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 2; } @@ -543,9 +547,9 @@ static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 host_reg = CMP_HOST_REG_IMM_L(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 4; } @@ -558,9 +562,9 @@ static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_B_RELEASE(host_reg); - + codegen_flags_changed = 1; return op_pc + 1; } @@ -572,9 +576,9 @@ static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); - + codegen_flags_changed = 1; return op_pc + 2; } @@ -587,9 +591,9 @@ static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 SUB_HOST_REG_IMM(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); - + codegen_flags_changed = 1; return op_pc + 4; } @@ -599,7 +603,7 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ int host_reg; uint32_t imm; x86seg *target_seg = NULL; - + if ((fetchdat & 0x30) == 0x10) return 0; @@ -625,7 +629,7 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ host_reg = LOAD_REG_B(fetchdat & 7); imm = (fetchdat >> 8) & 0xff; } - + switch (fetchdat & 0x38) { case 0x00: /*ADD*/ @@ -659,8 +663,8 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); break; } - - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -675,7 +679,7 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ } else RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 2; } @@ -685,10 +689,10 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 int host_reg; uint32_t imm; x86seg *target_seg = NULL; - + if ((fetchdat & 0x30) == 0x10) return 0; - + if ((fetchdat & 0xc0) != 0xc0) { target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); @@ -711,7 +715,7 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 host_reg = LOAD_REG_W(fetchdat & 7); imm = (fetchdat >> 8) & 0xffff; } - + switch (fetchdat & 0x38) { case 0x00: /*ADD*/ @@ -745,8 +749,8 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); break; } - - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -761,7 +765,7 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } else RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 3; } @@ -770,10 +774,10 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 int host_reg; uint32_t imm; x86seg *target_seg = NULL; - + if ((fetchdat & 0x30) == 0x10) return 0; - + if ((fetchdat & 0xc0) != 0xc0) { target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); @@ -795,7 +799,7 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 host_reg = LOAD_REG_L(fetchdat & 7); } imm = fastreadl(cs + op_pc + 1); - + switch (fetchdat & 0x38) { case 0x00: /*ADD*/ @@ -829,8 +833,8 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); break; } - - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -845,7 +849,7 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } else RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 5; } @@ -855,10 +859,10 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 int host_reg; uint32_t imm; x86seg *target_seg = NULL; - + if ((fetchdat & 0x30) == 0x10) return 0; - + if ((fetchdat & 0xc0) != 0xc0) { target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); @@ -884,7 +888,7 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 if (imm & 0x80) imm |= 0xff80; - + switch (fetchdat & 0x38) { case 0x00: /*ADD*/ @@ -918,8 +922,8 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); break; } - - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) @@ -934,7 +938,7 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } else RELEASE_REG(host_reg); - + codegen_flags_changed = 1; return op_pc + 2; } @@ -946,7 +950,7 @@ static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 if ((fetchdat & 0x30) == 0x10) return 0; - + if ((fetchdat & 0xc0) != 0xc0) { target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); @@ -972,7 +976,7 @@ static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 if (imm & 0x80) imm |= 0xffffff80; - + switch (fetchdat & 0x38) { case 0x00: /*ADD*/ @@ -1006,8 +1010,8 @@ static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); break; } - - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); if ((fetchdat & 0x38) != 0x38) { if ((fetchdat & 0xc0) != 0xc0) diff --git a/src/codegen/codegen_ops_fpu.h b/src/codegen/codegen_ops_fpu.h index 481eadb8c..930e0182c 100644 --- a/src/codegen/codegen_ops_fpu.h +++ b/src/codegen/codegen_ops_fpu.h @@ -3,7 +3,7 @@ static uint32_t ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 FP_ENTER(); FP_FXCH(opcode & 7); - + return op_pc; } @@ -12,7 +12,7 @@ static uint32_t ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 FP_ENTER(); FP_FLD(opcode & 7); - + return op_pc; } @@ -21,7 +21,7 @@ static uint32_t ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 FP_ENTER(); FP_FST(opcode & 7); - + return op_pc; } static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -30,7 +30,7 @@ static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 FP_FST(opcode & 7); FP_POP(); - + return op_pc; } @@ -38,13 +38,13 @@ static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_L(target_seg); @@ -55,13 +55,13 @@ static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_Q(target_seg); @@ -73,13 +73,13 @@ static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_W(target_seg); @@ -90,13 +90,13 @@ static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_L(target_seg); @@ -107,20 +107,20 @@ static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint static uint32_t ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_Q(target_seg); FP_LOAD_IQ(); codegen_fpu_loaded_iq[(cpu_state.TOP - 1) & 7] = 1; - + return op_pc + 1; } @@ -128,7 +128,7 @@ static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { x86seg *target_seg; int host_reg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); @@ -138,7 +138,7 @@ static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); CHECK_SEG_WRITE(target_seg); - + MEM_STORE_ADDR_EA_L(target_seg, host_reg); return op_pc + 1; @@ -146,8 +146,8 @@ static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - int host_reg1, host_reg2; - + int host_reg1, host_reg2 = 0; + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); @@ -158,7 +158,7 @@ static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 7); - + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); return op_pc + 1; @@ -167,17 +167,17 @@ static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 static uint32_t ropFSTPs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t new_pc = ropFSTs(opcode, fetchdat, op_32, op_pc, block); - + FP_POP(); - + return new_pc; } static uint32_t ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t new_pc = ropFSTd(opcode, fetchdat, op_32, op_pc, block); - + FP_POP(); - + return new_pc; } @@ -260,13 +260,13 @@ ropFcompare(COM, il, MEM_LOAD_ADDR_EA_L, FP_COMPARE_IL); /*static uint32_t ropFADDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_L(target_seg); @@ -277,13 +277,13 @@ ropFcompare(COM, il, MEM_LOAD_ADDR_EA_L, FP_COMPARE_IL); static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_L(target_seg); @@ -294,13 +294,13 @@ static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_L(target_seg); @@ -311,13 +311,13 @@ static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint static uint32_t ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { x86seg *target_seg; - + FP_ENTER(); op_pc--; target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_L(target_seg); @@ -331,49 +331,49 @@ static uint32_t ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { FP_ENTER(); FP_OP_REG(FPU_ADD, 0, opcode & 7); - + return op_pc; } static uint32_t ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_COMPARE_REG(0, opcode & 7); - + return op_pc; } static uint32_t ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_DIV, 0, opcode & 7); - + return op_pc; } static uint32_t ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_DIVR, 0, opcode & 7); - + return op_pc; } static uint32_t ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_MUL, 0, opcode & 7); - + return op_pc; } static uint32_t ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_SUB, 0, opcode & 7); - + return op_pc; } static uint32_t ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_SUBR, 0, opcode & 7); - + return op_pc; } @@ -381,42 +381,42 @@ static uint32_t ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint { FP_ENTER(); FP_OP_REG(FPU_ADD, opcode & 7, 0); - + return op_pc; } static uint32_t ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_DIV, opcode & 7, 0); - + return op_pc; } static uint32_t ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_DIVR, opcode & 7, 0); - + return op_pc; } static uint32_t ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_MUL, opcode & 7, 0); - + return op_pc; } static uint32_t ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_SUB, opcode & 7, 0); - + return op_pc; } static uint32_t ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { FP_ENTER(); FP_OP_REG(FPU_SUBR, opcode & 7, 0); - + return op_pc; } @@ -425,7 +425,7 @@ static uint32_t ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint FP_ENTER(); FP_OP_REG(FPU_ADD, opcode & 7, 0); FP_POP(); - + return op_pc; } static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -433,7 +433,7 @@ static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint FP_ENTER(); FP_COMPARE_REG(0, opcode & 7); FP_POP(); - + return op_pc; } static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -441,7 +441,7 @@ static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint FP_ENTER(); FP_OP_REG(FPU_DIV, opcode & 7, 0); FP_POP(); - + return op_pc; } static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -449,7 +449,7 @@ static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin FP_ENTER(); FP_OP_REG(FPU_DIVR, opcode & 7, 0); FP_POP(); - + return op_pc; } static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -457,7 +457,7 @@ static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint FP_ENTER(); FP_OP_REG(FPU_MUL, opcode & 7, 0); FP_POP(); - + return op_pc; } static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -465,7 +465,7 @@ static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint FP_ENTER(); FP_OP_REG(FPU_SUB, opcode & 7, 0); FP_POP(); - + return op_pc; } static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -473,7 +473,7 @@ static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin FP_ENTER(); FP_OP_REG(FPU_SUBR, opcode & 7, 0); FP_POP(); - + return op_pc; } @@ -482,18 +482,18 @@ static uint32_t ropFCOMPP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin FP_ENTER(); FP_COMPARE_REG(0, 1); FP_POP2(); - + return op_pc; } static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg; - + FP_ENTER(); host_reg = LOAD_VAR_W((uintptr_t)&cpu_state.npxs); STORE_REG_TARGET_W_RELEASE(host_reg, REG_AX); - + return op_pc; } @@ -512,7 +512,7 @@ static uint32_t ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); CHECK_SEG_WRITE(target_seg); - + MEM_STORE_ADDR_EA_W(target_seg, host_reg); return op_pc + 1; @@ -531,7 +531,7 @@ static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); CHECK_SEG_WRITE(target_seg); - + MEM_STORE_ADDR_EA_L(target_seg, host_reg); return op_pc + 1; @@ -540,17 +540,17 @@ static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint static uint32_t ropFISTPw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t new_pc = ropFISTw(opcode, fetchdat, op_32, op_pc, block); - + FP_POP(); - + return new_pc; } static uint32_t ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t new_pc = ropFISTl(opcode, fetchdat, op_32, op_pc, block); - + FP_POP(); - + return new_pc; } static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -567,11 +567,11 @@ static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); CHECK_SEG_WRITE(target_seg); - + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); FP_POP(); - + return op_pc + 1; } @@ -585,11 +585,11 @@ static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); CHECK_SEG_READ(target_seg); - + MEM_LOAD_ADDR_EA_W(target_seg); STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.npxc, 0); UPDATE_NPXC(0); - + return op_pc + 1; } static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -605,7 +605,7 @@ static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint host_reg = LOAD_VAR_W((uintptr_t)&cpu_state.npxc); MEM_STORE_ADDR_EA_W(target_seg, host_reg); - + return op_pc + 1; } @@ -614,7 +614,7 @@ static uint32_t ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 { FP_ENTER(); FP_FCHS(); - + return op_pc; } diff --git a/src/codegen/codegen_ops_jump.h b/src/codegen/codegen_ops_jump.h index 0ad293744..54e51f150 100644 --- a/src/codegen/codegen_ops_jump.h +++ b/src/codegen/codegen_ops_jump.h @@ -6,7 +6,7 @@ static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin offset |= 0xffffff00; STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset); - + return -1; } @@ -15,7 +15,7 @@ static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui uint16_t offset = fetchdat & 0xffff; STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); - + return -1; } @@ -24,7 +24,7 @@ static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui uint32_t offset = fastreadl(cs + op_pc); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); - + return -1; } @@ -42,11 +42,11 @@ static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 TEST_ZERO_JUMP_L(host_reg, op_pc+1+offset, 0); } else - { + { int host_reg = LOAD_REG_W(REG_CX); TEST_ZERO_JUMP_W(host_reg, op_pc+1+offset, 0); } - + return op_pc+1; } @@ -56,7 +56,7 @@ static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 if (offset & 0x80) offset |= 0xffffff00; - + if (op_32 & 0x200) { int host_reg = LOAD_REG_L(REG_ECX); @@ -71,7 +71,7 @@ static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_REG_W_RELEASE(host_reg); TEST_NONZERO_JUMP_W(host_reg, op_pc+1+offset, 0); } - + return op_pc+1; } @@ -87,10 +87,10 @@ static void BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int no static void BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { int host_reg; - + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: case FLAGS_ADD8: @@ -120,7 +120,7 @@ static void BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int no else TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; - + case FLAGS_UNKNOWN: CALL_FUNC((uintptr_t)ZF_SET); if (not) @@ -152,10 +152,10 @@ static void BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int no static void BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { int host_reg; - + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ADD8: case FLAGS_SUB8: case FLAGS_SHL8: @@ -186,7 +186,7 @@ static void BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int no else TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; - + case FLAGS_ZN32: case FLAGS_ADD32: case FLAGS_SUB32: @@ -202,7 +202,7 @@ static void BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int no else TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; - + case FLAGS_UNKNOWN: CALL_FUNC((uintptr_t)NF_SET); if (not) diff --git a/src/codegen/codegen_ops_logic.h b/src/codegen/codegen_ops_logic.h index c0ffa641a..117b19d97 100644 --- a/src/codegen/codegen_ops_logic.h +++ b/src/codegen/codegen_ops_logic.h @@ -275,9 +275,9 @@ static uint32_t ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, AND_HOST_REG_IMM(host_reg, (fetchdat & 0xff) | 0xffffff00); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - STORE_REG_B_RELEASE(host_reg); - + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + return op_pc + 1; } static uint32_t ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -286,9 +286,9 @@ static uint32_t ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, AND_HOST_REG_IMM(host_reg, (fetchdat & 0xffff) | 0xffff0000); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); - + return op_pc + 2; } static uint32_t ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -298,9 +298,9 @@ static uint32_t ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 fetchdat = fastreadl(cs + op_pc); AND_HOST_REG_IMM(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); - + return op_pc + 4; } @@ -310,9 +310,9 @@ static uint32_t ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, OR_HOST_REG_IMM(host_reg, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - STORE_REG_B_RELEASE(host_reg); - + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + return op_pc + 1; } static uint32_t ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -321,9 +321,9 @@ static uint32_t ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, OR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); - + return op_pc + 2; } static uint32_t ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -333,9 +333,9 @@ static uint32_t ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, fetchdat = fastreadl(cs + op_pc); OR_HOST_REG_IMM(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); - + return op_pc + 4; } @@ -345,9 +345,9 @@ static uint32_t ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); - + return op_pc + 1; } static uint32_t ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -356,9 +356,9 @@ static uint32_t ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); - + return op_pc + 2; } static uint32_t ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -368,9 +368,9 @@ static uint32_t ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_3 fetchdat = fastreadl(cs + op_pc); host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); - + return op_pc + 4; } @@ -380,9 +380,9 @@ static uint32_t ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, XOR_HOST_REG_IMM(host_reg, fetchdat & 0xff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - STORE_REG_B_RELEASE(host_reg); - + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + return op_pc + 1; } static uint32_t ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -391,9 +391,9 @@ static uint32_t ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, XOR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); - + return op_pc + 2; } static uint32_t ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -403,9 +403,9 @@ static uint32_t ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 fetchdat = fastreadl(cs + op_pc); XOR_HOST_REG_IMM(host_reg, fetchdat); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); - + return op_pc + 4; } @@ -414,7 +414,7 @@ static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ x86seg *target_seg; int host_reg; uint8_t imm; - + switch (fetchdat & 0x38) { case 0x00: /*TEST b,#8*/ @@ -433,7 +433,7 @@ static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ } STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); host_reg = TEST_HOST_REG_IMM(host_reg, imm); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); return op_pc + 2; @@ -457,7 +457,7 @@ static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); return op_pc + 1; } - + return 0; } static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -465,7 +465,7 @@ static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 x86seg *target_seg; int host_reg; uint16_t imm; - + switch (fetchdat & 0x38) { case 0x00: /*TEST w,#*/ @@ -484,7 +484,7 @@ static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); host_reg = TEST_HOST_REG_IMM(host_reg, imm); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); return op_pc + 3; @@ -508,7 +508,7 @@ static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); return op_pc + 1; } - + return 0; } static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -516,7 +516,7 @@ static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 x86seg *target_seg; int host_reg; uint32_t imm; - + switch (fetchdat & 0x38) { case 0x00: /*TEST l,#*/ @@ -535,7 +535,7 @@ static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 } STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); host_reg = TEST_HOST_REG_IMM(host_reg, imm); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); RELEASE_REG(host_reg); return op_pc + 5; @@ -559,6 +559,6 @@ static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); return op_pc + 1; } - + return 0; } diff --git a/src/codegen/codegen_ops_misc.h b/src/codegen/codegen_ops_misc.h index 1752c4180..9438da2d3 100644 --- a/src/codegen/codegen_ops_misc.h +++ b/src/codegen/codegen_ops_misc.h @@ -19,6 +19,9 @@ static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; CLEAR_BITS((uintptr_t)&cpu_state.flags, I_FLAG); +#ifdef CHECK_INT + CLEAR_BITS((uintptr_t)&pic_pending, 0xffffffff); +#endif return op_pc; } static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -38,7 +41,7 @@ static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ return 0; CALL_FUNC((uintptr_t)flags_rebuild_c); - + if ((fetchdat & 0xc0) == 0xc0) host_reg = LOAD_REG_B(fetchdat & 7); else @@ -50,7 +53,7 @@ static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ MEM_CHECK_WRITE(target_seg); host_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); } - + switch (fetchdat & 0x38) { case 0x00: /*INC*/ @@ -77,7 +80,7 @@ static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, host_reg); } codegen_flags_changed = 1; - + return op_pc + 1; } static uint32_t codegen_temp; @@ -85,7 +88,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint { x86seg *target_seg = NULL; int host_reg; - + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) return 0; @@ -111,7 +114,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); } } - + switch (fetchdat & 0x38) { case 0x00: /*INC*/ @@ -156,7 +159,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint SP_MODIFY(-2); host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); - STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.pc, host_reg); + STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.pc, host_reg); return -1; case 0x20: /*JMP*/ @@ -178,13 +181,13 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint { x86seg *target_seg = NULL; int host_reg; - + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) return 0; if ((fetchdat & 0x30) == 0x00) CALL_FUNC((uintptr_t)flags_rebuild_c); - + if ((fetchdat & 0xc0) == 0xc0) host_reg = LOAD_REG_L(fetchdat & 7); else @@ -204,7 +207,7 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); } } - + switch (fetchdat & 0x38) { case 0x00: /*INC*/ @@ -249,7 +252,7 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint SP_MODIFY(-4); host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); return -1; case 0x20: /*JMP*/ diff --git a/src/codegen/codegen_ops_mmx.h b/src/codegen/codegen_ops_mmx.h index 14730cb93..4cdb080fb 100644 --- a/src/codegen/codegen_ops_mmx.h +++ b/src/codegen/codegen_ops_mmx.h @@ -1,11 +1,11 @@ static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - int host_reg1, host_reg2; + int host_reg1, host_reg2 = 0; MMX_ENTER(); - + LOAD_MMX_Q((fetchdat >> 3) & 7, &host_reg1, &host_reg2); - + if ((fetchdat & 0xc0) == 0xc0) { STORE_MMX_Q(fetchdat & 7, host_reg1, host_reg2); @@ -15,10 +15,10 @@ static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 7); - + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); } @@ -28,11 +28,11 @@ static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, static uint32_t ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { MMX_ENTER(); - + if ((fetchdat & 0xc0) == 0xc0) { int host_reg1, host_reg2; - + LOAD_MMX_Q(fetchdat & 7, &host_reg1, &host_reg2); STORE_MMX_Q((fetchdat >> 3) & 7, host_reg1, host_reg2); } @@ -56,9 +56,9 @@ static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, int host_reg; MMX_ENTER(); - + host_reg = LOAD_MMX_D((fetchdat >> 3) & 7); - + if ((fetchdat & 0xc0) == 0xc0) { STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); @@ -68,10 +68,10 @@ static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 3); - + MEM_STORE_ADDR_EA_L(target_seg, host_reg); } @@ -80,7 +80,7 @@ static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, static uint32_t ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { MMX_ENTER(); - + if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_L(fetchdat & 7); @@ -192,9 +192,9 @@ static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, return 0; if ((fetchdat & 0x08) || !(fetchdat & 0x30)) return 0; - + MMX_ENTER(); - + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); switch (fetchdat & 0x38) { @@ -209,7 +209,7 @@ static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, break; } STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); - + return op_pc + 2; } static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -220,9 +220,9 @@ static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, return 0; if ((fetchdat & 0x08) || !(fetchdat & 0x30)) return 0; - + MMX_ENTER(); - + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); switch (fetchdat & 0x38) { @@ -237,7 +237,7 @@ static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, break; } STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); - + return op_pc + 2; } static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -248,9 +248,9 @@ static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, return 0; if ((fetchdat & 0x08) || !(fetchdat & 0x30)) return 0; - + MMX_ENTER(); - + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); switch (fetchdat & 0x38) { @@ -265,13 +265,13 @@ static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, break; } STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); - + return op_pc + 2; } static uint32_t ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { codegen_mmx_entered = 0; - + return 0; } diff --git a/src/codegen/codegen_ops_mov.h b/src/codegen/codegen_ops_mov.h index fc4ec1637..df7a6a31b 100644 --- a/src/codegen/codegen_ops_mov.h +++ b/src/codegen/codegen_ops_mov.h @@ -1,7 +1,7 @@ static uint32_t ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { STORE_IMM_REG_B(opcode & 7, fetchdat & 0xff); - + return op_pc + 1; } static uint32_t ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -15,7 +15,7 @@ static uint32_t ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, fetchdat = fastreadl(cs + op_pc); STORE_IMM_REG_L(opcode & 7, fetchdat); - + return op_pc + 4; } @@ -23,7 +23,7 @@ static uint32_t ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, static uint32_t ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg = LOAD_REG_B((fetchdat >> 3) & 7); - + if ((fetchdat & 0xc0) == 0xc0) { STORE_REG_TARGET_B_RELEASE(host_reg, fetchdat & 7); @@ -33,20 +33,20 @@ static uint32_t ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 0); MEM_STORE_ADDR_EA_B(target_seg, host_reg); RELEASE_REG(host_reg); } - + return op_pc + 1; } static uint32_t ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg = LOAD_REG_W((fetchdat >> 3) & 7); - + if ((fetchdat & 0xc0) == 0xc0) { STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); @@ -56,23 +56,23 @@ static uint32_t ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 1); MEM_STORE_ADDR_EA_W(target_seg, host_reg); RELEASE_REG(host_reg); } - + return op_pc + 1; } static uint32_t ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int host_reg; - + host_reg = LOAD_REG_L((fetchdat >> 3) & 7); - + if ((fetchdat & 0xc0) == 0xc0) { STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); @@ -82,13 +82,13 @@ static uint32_t ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 3); - + MEM_STORE_ADDR_EA_L(target_seg, host_reg); RELEASE_REG(host_reg); - + } return op_pc + 1; @@ -106,13 +106,13 @@ static uint32_t ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_B(target_seg); STORE_REG_TARGET_B_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } static uint32_t ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -133,7 +133,7 @@ static uint32_t ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui MEM_LOAD_ADDR_EA_W(target_seg); STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } static uint32_t ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -154,7 +154,7 @@ static uint32_t ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui MEM_LOAD_ADDR_EA_L(target_seg); STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } @@ -220,7 +220,7 @@ static uint32_t ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, MEM_STORE_ADDR_EA_L(target_seg, host_reg); RELEASE_REG(host_reg); } - + return op_pc + 5; } @@ -239,7 +239,7 @@ static uint32_t ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u MEM_LOAD_ADDR_IMM_B(op_ea_seg, addr); STORE_REG_TARGET_B_RELEASE(0, REG_AL); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -256,7 +256,7 @@ static uint32_t ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u MEM_LOAD_ADDR_IMM_W(op_ea_seg, addr); STORE_REG_TARGET_W_RELEASE(0, REG_AX); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -273,7 +273,7 @@ static uint32_t ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, MEM_LOAD_ADDR_IMM_L(op_ea_seg, addr); STORE_REG_TARGET_L_RELEASE(0, REG_EAX); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } @@ -289,12 +289,12 @@ static uint32_t ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u CHECK_SEG_WRITE(op_ea_seg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + host_reg = LOAD_REG_B(REG_AL); MEM_STORE_ADDR_IMM_B(op_ea_seg, addr, host_reg); RELEASE_REG(host_reg); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -309,12 +309,12 @@ static uint32_t ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u CHECK_SEG_WRITE(op_ea_seg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + host_reg = LOAD_REG_W(REG_AX); MEM_STORE_ADDR_IMM_W(op_ea_seg, addr, host_reg); RELEASE_REG(host_reg); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -329,24 +329,24 @@ static uint32_t ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, CHECK_SEG_WRITE(op_ea_seg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + host_reg = LOAD_REG_L(REG_EAX); MEM_STORE_ADDR_IMM_L(op_ea_seg, addr, host_reg); RELEASE_REG(host_reg); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int dest_reg = (fetchdat >> 3) & 7; - + if ((fetchdat & 0xc0) == 0xc0) return 0; - + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - + STORE_REG_TARGET_W_RELEASE(0, dest_reg); return op_pc + 1; @@ -354,12 +354,12 @@ static uint32_t ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint static uint32_t ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { int dest_reg = (fetchdat >> 3) & 7; - + if ((fetchdat & 0xc0) == 0xc0) return 0; - + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - + STORE_REG_TARGET_L_RELEASE(0, dest_reg); return op_pc + 1; @@ -378,14 +378,14 @@ static uint32_t ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_B(target_seg); ZERO_EXTEND_W_B(0); STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } static uint32_t ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -401,14 +401,14 @@ static uint32_t ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_B(target_seg); ZERO_EXTEND_L_B(0); STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } static uint32_t ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -424,14 +424,14 @@ static uint32_t ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_W(target_seg); ZERO_EXTEND_L_W(0); STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } @@ -448,14 +448,14 @@ static uint32_t ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_B(target_seg); SIGN_EXTEND_W_B(0); STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } static uint32_t ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -471,14 +471,14 @@ static uint32_t ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_B(target_seg); SIGN_EXTEND_L_B(0); STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } static uint32_t ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -494,14 +494,14 @@ static uint32_t ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_W(target_seg); SIGN_EXTEND_L_W(0); STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); } - + return op_pc + 1; } @@ -532,7 +532,7 @@ static uint32_t ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, default: return 0; } - + if ((fetchdat & 0xc0) == 0xc0) { if (op_32 & 0x100) @@ -545,14 +545,14 @@ static uint32_t ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + CHECK_SEG_WRITE(target_seg); CHECK_SEG_LIMITS(target_seg, 1); MEM_STORE_ADDR_EA_W(target_seg, host_reg); RELEASE_REG(host_reg); } - + return op_pc + 1; } static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -572,7 +572,7 @@ static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, } STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - + if ((fetchdat & 0xc0) == 0xc0) host_reg = LOAD_REG_W(fetchdat & 7); else @@ -581,10 +581,10 @@ static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, CHECK_SEG_READ(target_seg); MEM_LOAD_ADDR_EA_W(target_seg); - + host_reg = 0; } - + switch (fetchdat & 0x38) { case 0x00: /*ES*/ @@ -600,7 +600,7 @@ static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, LOAD_SEG(host_reg, &cpu_state.seg_gs); break; } - + return op_pc + 1; } diff --git a/src/codegen/codegen_ops_shift.h b/src/codegen/codegen_ops_shift.h index b67c34544..57a828232 100644 --- a/src/codegen/codegen_ops_shift.h +++ b/src/codegen/codegen_ops_shift.h @@ -67,7 +67,7 @@ static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 return 0; SHIFT(W, 16, STORE_HOST_REG_ADDR_WL, 1); - + return op_pc + 2; } static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -80,7 +80,7 @@ static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 return 0; SHIFT(L, 32, STORE_HOST_REG_ADDR, 1); - + return op_pc + 2; } @@ -107,7 +107,7 @@ static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 return 0; SHIFT(W, 16, STORE_HOST_REG_ADDR_WL, 0); - + return op_pc + 1; } static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -120,6 +120,6 @@ static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 return 0; SHIFT(L, 32, STORE_HOST_REG_ADDR, 0); - + return op_pc + 1; } diff --git a/src/codegen/codegen_ops_stack.h b/src/codegen/codegen_ops_stack.h index 288be2c6c..d2fc53aad 100644 --- a/src/codegen/codegen_ops_stack.h +++ b/src/codegen/codegen_ops_stack.h @@ -7,7 +7,7 @@ static uint32_t ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui host_reg = LOAD_REG_W(opcode & 7); MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); - + return op_pc; } static uint32_t ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -33,7 +33,7 @@ static uint32_t ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 host_reg = LOAD_REG_IMM(imm); MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); - + return op_pc+2; } static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -46,7 +46,7 @@ static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 host_reg = LOAD_REG_IMM(imm); MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); - + return op_pc+4; } @@ -63,7 +63,7 @@ static uint32_t ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_3 host_reg = LOAD_REG_IMM(imm); MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); - + return op_pc+1; } static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -79,7 +79,7 @@ static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_3 host_reg = LOAD_REG_IMM(imm); MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); - + return op_pc+1; } @@ -90,7 +90,7 @@ static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); SP_MODIFY(2); STORE_REG_TARGET_W_RELEASE(0, opcode & 7); - + return op_pc; } static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -100,7 +100,7 @@ static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); SP_MODIFY(4); STORE_REG_TARGET_L_RELEASE(0, opcode & 7); - + return op_pc; } @@ -111,7 +111,7 @@ static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(2); - + return -1; } static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -121,7 +121,7 @@ static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(4); - + return -1; } @@ -134,7 +134,7 @@ static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(2+offset); - + return -1; } static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -146,7 +146,7 @@ static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(4+offset); - + return -1; } @@ -161,7 +161,7 @@ static uint32_t ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); - + return -1; } static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -175,7 +175,7 @@ static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); - + return -1; } @@ -204,7 +204,7 @@ static uint32_t ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u ADD_HOST_REG_IMM(host_reg, 4); STORE_REG_TARGET_L_RELEASE(host_reg, REG_ESP); STORE_REG_TARGET_L_RELEASE(0, REG_EBP); /*EBP = POP_L()*/ - + return op_pc; } diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index 178f0f868..9184b4bff 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -16,19 +16,19 @@ static inline int find_host_xmm_reg() if (host_reg_xmm_mapping[c] == -1) break; } - + if (c == HOST_REG_XMM_END) fatal("Out of host XMM regs!\n"); return c; } static inline void call(codeblock_t *block, uintptr_t func) { - uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; + intptr_t diff = (intptr_t)(func - (uintptr_t)&block->data[block_pos + 5]); codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; - if (diff >= -0x80000000 && diff < 0x7fffffff) + if (diff >= -0x80000000LL && diff < 0x7fffffffLL) { addbyte(0xE8); /*CALL*/ addlong((uint32_t)diff); @@ -57,7 +57,7 @@ static inline void call_long(uintptr_t func) static inline void load_param_1_32(codeblock_t *block, uint32_t param) { -#if WIN64 +#if _WIN64 addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ #else addbyte(0xbf); /*MOVL $fetchdat,%edi*/ @@ -66,7 +66,7 @@ static inline void load_param_1_32(codeblock_t *block, uint32_t param) } static inline void load_param_1_reg_32(int reg) { -#if WIN64 +#if _WIN64 if (reg & 8) addbyte(0x44); addbyte(0x89); /*MOV ECX, EAX*/ @@ -82,7 +82,7 @@ static inline void load_param_1_reg_32(int reg) static inline void load_param_1_64(codeblock_t *block, uint64_t param) { addbyte(0x48); -#if WIN64 +#if _WIN64 addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ #else addbyte(0xbf); /*MOVL $fetchdat,%edi*/ @@ -93,7 +93,7 @@ static inline void load_param_1_64(codeblock_t *block, uint64_t param) static inline void load_param_2_32(codeblock_t *block, uint32_t param) { -#if WIN64 +#if _WIN64 addbyte(0xba); /*MOVL $fetchdat,%edx*/ #else addbyte(0xbe); /*MOVL $fetchdat,%esi*/ @@ -102,7 +102,7 @@ static inline void load_param_2_32(codeblock_t *block, uint32_t param) } static inline void load_param_2_reg_32(int reg) { -#if WIN64 +#if _WIN64 if (reg & 8) addbyte(0x44); addbyte(0x89); /*MOV EDX, EAX*/ @@ -117,19 +117,46 @@ static inline void load_param_2_reg_32(int reg) static inline void load_param_2_64(codeblock_t *block, uint64_t param) { addbyte(0x48); -#if WIN64 +#if _WIN64 addbyte(0xba); /*MOVL $fetchdat,%edx*/ #else addbyte(0xbe); /*MOVL $fetchdat,%esi*/ #endif addquad(param); } +static inline void load_param_2_reg_64(int reg) +{ + if (reg & 8) + { +#if _WIN64 + addbyte(0x4c); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#else + addbyte(0x4c); /*MOVL ESI,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_ESI | ((reg & 7) << 3)); +#endif + } + else + { +#if _WIN64 + addbyte(0x48); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#else + addbyte(0x48); /*MOVL ESI,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_ESI | ((reg & 7) << 3)); +#endif + } +} static inline void load_param_3_reg_32(int reg) { if (reg & 8) { -#if WIN64 +#if _WIN64 addbyte(0x45); /*MOVL R8,reg*/ addbyte(0x89); addbyte(0xc0 | ((reg & 7) << 3)); @@ -141,7 +168,7 @@ static inline void load_param_3_reg_32(int reg) } else { -#if WIN64 +#if _WIN64 addbyte(0x41); /*MOVL R8,reg*/ addbyte(0x89); addbyte(0xc0 | ((reg & 7) << 3)); @@ -156,7 +183,7 @@ static inline void load_param_3_reg_64(int reg) { if (reg & 8) { -#if WIN64 +#if _WIN64 addbyte(0x4d); /*MOVL R8,reg*/ addbyte(0x89); addbyte(0xc0 | ((reg & 7) << 3)); @@ -168,7 +195,7 @@ static inline void load_param_3_reg_64(int reg) } else { -#if WIN64 +#if _WIN64 addbyte(0x49); /*MOVL R8,reg*/ addbyte(0x89); addbyte(0xc0 | ((reg & 7) << 3)); @@ -209,10 +236,10 @@ static inline int LOAD_REG_B(int reg) } codegen_reg_loaded[reg & 3] = 1; - + if (reg & 4) return host_reg | 0x18; - + return host_reg | 8; } static inline int LOAD_REG_W(int reg) @@ -228,7 +255,7 @@ static inline int LOAD_REG_W(int reg) } codegen_reg_loaded[reg & 7] = 1; - + return host_reg | 8; } static inline int LOAD_REG_L(int reg) @@ -244,7 +271,7 @@ static inline int LOAD_REG_L(int reg) } codegen_reg_loaded[reg & 7] = 1; - + return host_reg | 8; } @@ -254,14 +281,14 @@ static inline int LOAD_REG_IMM(uint32_t imm) addbyte(0xb8 | REG_EBX); /*MOVL EBX, imm*/ addlong(imm); - + return host_reg; } static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) { int dest_reg = LOAD_REG_L(guest_reg & 3) & 7; - + if (guest_reg & 4) { if (host_reg & 8) @@ -270,33 +297,26 @@ static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) addbyte(0x44); addbyte(0x89); addbyte(0xc0 | ((host_reg & 3) << 3)); - if (host_reg & 0x10) - { - addbyte(0x66); /*AND AX, 0xff00*/ - addbyte(0x25); - addword(0xff00); - } - else - { - addbyte(0x66); /*SHL AX, 8*/ - addbyte(0xc1); - addbyte(0xe0); - addbyte(0x08); - } } - else - { - if (host_reg) - { - addbyte(0x66); /*MOV AX, host_reg*/ - addbyte(0x89); - addbyte(0xc0 | ((host_reg & 3) << 3)); - } - addbyte(0x66); /*SHL AX, 8*/ - addbyte(0xc1); - addbyte(0xe0); - addbyte(0x08); + else if (host_reg & 3) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); } + if (host_reg & 0x10) + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + else + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } addbyte(0x66); /*AND dest_reg, 0x00ff*/ addbyte(0x41); addbyte(0x81); @@ -362,7 +382,7 @@ static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) static inline void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) { int dest_reg = LOAD_REG_L(guest_reg & 7) & 7; - + if (host_reg & 8) { addbyte(0x66); /*MOVW guest_reg, host_reg*/ @@ -535,8 +555,8 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u int mod = (fetchdat >> 6) & 3; int rm = fetchdat & 7; - if (!mod && rm == 6) - { + if (!mod && rm == 6) + { addbyte(0xb8); /*MOVL EAX, imm*/ addlong((fetchdat >> 8) & 0xffff); (*op_pc) += 2; @@ -544,7 +564,7 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u else { int base_reg = 0, index_reg = 0; - + switch (rm) { case 0: case 1: case 7: @@ -569,7 +589,7 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u } base_reg &= 7; index_reg &= 7; - + switch (mod) { case 0: @@ -638,7 +658,7 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u } (*op_pc) += 2; break; - + } if (mod || !(rm & 4)) { @@ -725,7 +745,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u } } else - { + { switch (mod) { case 0: @@ -803,7 +823,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u int base_reg; if (!mod && rm == 5) - { + { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ addlong(new_eaaddr); @@ -811,20 +831,20 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u return op_ea_seg; } base_reg = LOAD_REG_L(rm) & 7; - if (mod) + if (mod) { if (rm == 5 && !op_ssegs) op_ea_seg = &cpu_state.seg_ss; - if (mod == 1) + if (mod == 1) { addbyte(0x67); /*LEA EAX, base_reg+imm8*/ addbyte(0x41); addbyte(0x8d); addbyte(0x40 | base_reg); addbyte((fetchdat >> 8) & 0xff); - (*op_pc)++; + (*op_pc)++; } - else + else { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0x67); /*LEA EAX, base_reg+imm32*/ @@ -887,7 +907,7 @@ static inline void CHECK_SEG_READ(x86seg *seg) addbyte(0x0f); /*JE GPF_BLOCK_OFFSET*/ addbyte(0x84); addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); - + seg->checked = 1; } static inline void CHECK_SEG_WRITE(x86seg *seg) @@ -902,7 +922,7 @@ static inline void CHECK_SEG_WRITE(x86seg *seg) return; if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; - + if (IS_32_ADDR(&seg->base)) { addbyte(0x83); /*CMP seg->base, -1*/ @@ -1026,9 +1046,10 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemb386l); + call_long((uintptr_t)readmembl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -1105,8 +1126,9 @@ static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemwl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1190,8 +1212,9 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemll); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1269,8 +1292,9 @@ static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemql); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1392,12 +1416,17 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(REG_EDI | (REG_ESI << 3)); } addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12+4+6); + if (host_reg & 8) { + addbyte(2+2+3+12+4+6); + } else { + addbyte(2+2+2+12+4+6); + } /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); - call_long((uintptr_t)writememb386l); + load_param_2_reg_32(host_reg); + call_long((uintptr_t)writemembl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -1483,11 +1512,16 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) addbyte(REG_EDI | (REG_ESI << 3)); } addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12+4+6); + if (host_reg & 8) { + addbyte(2+2+3+12+4+6); + } else { + addbyte(2+2+2+12+4+6); + } /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); call_long((uintptr_t)writememwl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1572,11 +1606,16 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) addbyte(REG_EDI | (REG_ESI << 3)); } addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12+4+6); + if (host_reg & 8) { + addbyte(2+2+3+12+4+6); + } else { + addbyte(2+2+2+12+4+6); + } /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); call_long((uintptr_t)writememll); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1664,9 +1703,10 @@ static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_64(host_reg); + load_param_2_reg_64(host_reg); call_long((uintptr_t)writememql); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1700,14 +1740,14 @@ static inline void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg static inline void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) { int temp_reg = REG_ECX; - + if (host_reg_mapping[REG_ECX] != -1) temp_reg = REG_EBX; - + if (host_reg & 0x10) { if (host_reg & 8) - addbyte(0x41); + addbyte(0x41); addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ addbyte(0xb7); addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); @@ -1718,7 +1758,7 @@ static inline void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) else { if (host_reg & 8) - addbyte(0x41); + addbyte(0x41); addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ addbyte(0xb6); addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); @@ -1748,12 +1788,12 @@ static inline void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) static inline void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) { int temp_reg = REG_ECX; - + if (host_reg_mapping[REG_ECX] != -1) temp_reg = REG_EBX; - + if (host_reg & 8) - addbyte(0x41); + addbyte(0x41); addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ addbyte(0xb7); addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); @@ -1940,7 +1980,7 @@ static inline void AND_HOST_REG_B(int dst_reg, int src_reg) addbyte(0x44); /*ANDB dst_reg, src_reg*/ addbyte(0x20); addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } else { @@ -1965,7 +2005,7 @@ static inline void AND_HOST_REG_B(int dst_reg, int src_reg) { addbyte(0x20); /*ANDB dst_reg, src_reg*/ addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } } static inline void AND_HOST_REG_W(int dst_reg, int src_reg) @@ -2052,12 +2092,12 @@ static inline int TEST_HOST_REG_B(int dst_reg, int src_reg) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); - + dst_reg = (dst_reg & 0x10) | REG_EDX; } - + AND_HOST_REG_B(dst_reg, src_reg); - + return dst_reg & ~0x10; } static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) @@ -2067,12 +2107,12 @@ static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); - + dst_reg = REG_EDX; } - + AND_HOST_REG_W(dst_reg, src_reg); - + return dst_reg; } static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) @@ -2082,12 +2122,12 @@ static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); - + dst_reg = REG_EDX; } - + AND_HOST_REG_L(dst_reg, src_reg); - + return dst_reg; } static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) @@ -2112,7 +2152,7 @@ static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) addbyte(0xe0 | (host_reg & 7)); addlong(imm); } - + return host_reg; } @@ -2210,7 +2250,7 @@ static inline void OR_HOST_REG_B(int dst_reg, int src_reg) addbyte(0x44); /*ORB dst_reg, src_reg*/ addbyte(0x08); addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } else { @@ -2235,7 +2275,7 @@ static inline void OR_HOST_REG_B(int dst_reg, int src_reg) { addbyte(0x08); /*ORB dst_reg, src_reg*/ addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } } static inline void OR_HOST_REG_W(int dst_reg, int src_reg) @@ -2413,7 +2453,7 @@ static inline void XOR_HOST_REG_B(int dst_reg, int src_reg) addbyte(0x44); /*XORB dst_reg, src_reg*/ addbyte(0x30); addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } else { @@ -2438,7 +2478,7 @@ static inline void XOR_HOST_REG_B(int dst_reg, int src_reg) { addbyte(0x30); /*XORB dst_reg, src_reg*/ addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } } static inline void XOR_HOST_REG_W(int dst_reg, int src_reg) @@ -2760,7 +2800,7 @@ static inline void SUB_HOST_REG_B(int dst_reg, int src_reg) addbyte(0x44); /*SUBB dst_reg, src_reg*/ addbyte(0x28); addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } else { @@ -2785,7 +2825,7 @@ static inline void SUB_HOST_REG_B(int dst_reg, int src_reg) { addbyte(0x28); /*SUBB dst_reg, src_reg*/ addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } + } } } static inline void SUB_HOST_REG_W(int dst_reg, int src_reg) @@ -2852,12 +2892,12 @@ static inline int CMP_HOST_REG_B(int dst_reg, int src_reg) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); - + dst_reg = (dst_reg & 0x10) | REG_EDX; } - + SUB_HOST_REG_B(dst_reg, src_reg); - + return dst_reg & ~0x10; } static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) @@ -2867,12 +2907,12 @@ static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); - + dst_reg = REG_EDX; } - + SUB_HOST_REG_W(dst_reg, src_reg); - + return dst_reg; } static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) @@ -2882,12 +2922,12 @@ static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); - + dst_reg = REG_EDX; } - + SUB_HOST_REG_L(dst_reg, src_reg); - + return dst_reg; } @@ -2967,6 +3007,37 @@ static inline void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) addlong(imm); } +static inline void INC_HOST_REG_W(int host_reg) +{ + addbyte(0x66); /*INCW host_reg*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0xff); + addbyte(0xc0 | (host_reg & 7)); +} +static inline void INC_HOST_REG(int host_reg) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0xff); /*INCL host_reg*/ + addbyte(0xc0 | (host_reg & 7)); +} +static inline void DEC_HOST_REG_W(int host_reg) +{ + addbyte(0x66); /*DECW host_reg*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0xff); + addbyte(0xc8 | (host_reg & 7)); +} +static inline void DEC_HOST_REG(int host_reg) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0xff); /*DECL host_reg*/ + addbyte(0xc8 | (host_reg & 7)); +} + static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) { if (host_reg & 8) @@ -2974,12 +3045,12 @@ static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); - + host_reg = (host_reg & 0x10) | REG_EDX; } - + SUB_HOST_REG_IMM_B(host_reg, imm); - + return host_reg; } static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) @@ -2989,12 +3060,12 @@ static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); - + host_reg = REG_EDX; } - + SUB_HOST_REG_IMM_W(host_reg, imm); - + return host_reg; } static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) @@ -3004,12 +3075,12 @@ static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) addbyte(0x44); /*MOV EDX, dst_reg*/ addbyte(0x89); addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); - + host_reg = REG_EDX; } - + SUB_HOST_REG_IMM(host_reg, imm); - + return host_reg; } @@ -3209,7 +3280,7 @@ static inline void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_ static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { uint8_t *jump1; - + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) { addbyte(0x83); /*CMP flags_res, 0*/ @@ -3234,7 +3305,7 @@ static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset addbyte(0x75); /*JNZ +*/ else addbyte(0x74); /*JZ +*/ - addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(7+5+(timing_bt ? 4 : 0)); if (!not) *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; @@ -3275,7 +3346,7 @@ static inline void BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, addbyte(0x75); /*JNZ +*/ else addbyte(0x74); /*JZ +*/ - addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(7+5+(timing_bt ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(pc)); @@ -3329,7 +3400,7 @@ static inline void BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset addbyte(0x75); /*JNZ +*/ else addbyte(0x74); /*JZ +*/ - addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(7+5+(timing_bt ? 4 : 0)); if (!not) *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; addbyte(0xC7); /*MOVL [pc], new_pc*/ @@ -3419,7 +3490,7 @@ static inline int COPY_REG(int src_reg) addbyte(0x44); addbyte(0x89); addbyte(0xc0 | REG_ECX | ((src_reg & 7) << 3)); - + return REG_ECX | (src_reg & 0x10); } @@ -3429,7 +3500,7 @@ static inline int LOAD_HOST_REG(int host_reg) addbyte(0x44); addbyte(0x89); addbyte(0xc0 | REG_EBX | ((host_reg & 7) << 3)); - + return REG_EBX | (host_reg & 0x10); } @@ -3443,16 +3514,16 @@ static inline int ZERO_EXTEND_W_B(int reg) addbyte(0x0f); /*MOVZX EAX, AH*/ addbyte(0xb6); addbyte(0xc4); - + return REG_EAX; } - + if (reg & 8) addbyte(0x41); addbyte(0x0f); /*MOVZX regl, regb*/ addbyte(0xb6); addbyte(0xc0 | (reg & 7)); - + return REG_EAX; } static inline int ZERO_EXTEND_L_B(int reg) @@ -3465,7 +3536,7 @@ static inline int ZERO_EXTEND_L_B(int reg) addbyte(0x0f); /*MOVZX EAX, AH*/ addbyte(0xb6); addbyte(0xc4); - + return REG_EAX; } @@ -3474,7 +3545,7 @@ static inline int ZERO_EXTEND_L_B(int reg) addbyte(0x0f); /*MOVZX regl, regb*/ addbyte(0xb6); addbyte(0xc0 | (reg & 7)); - + return REG_EAX; } static inline int ZERO_EXTEND_L_W(int reg) @@ -3484,7 +3555,7 @@ static inline int ZERO_EXTEND_L_W(int reg) addbyte(0x0f); /*MOVZX regl, regw*/ addbyte(0xb7); addbyte(0xc0 | (reg & 7)); - + return REG_EAX; } @@ -3498,7 +3569,7 @@ static inline int SIGN_EXTEND_W_B(int reg) addbyte(0x0f); /*MOVSX EAX, AH*/ addbyte(0xbe); addbyte(0xc4); - + return REG_EAX; } @@ -3507,7 +3578,7 @@ static inline int SIGN_EXTEND_W_B(int reg) addbyte(0x0f); /*MOVSX regl, regb*/ addbyte(0xbe); addbyte(0xc0 | (reg & 7)); - + return REG_EAX; } static inline int SIGN_EXTEND_L_B(int reg) @@ -3520,7 +3591,7 @@ static inline int SIGN_EXTEND_L_B(int reg) addbyte(0x0f); /*MOVSX EAX, AH*/ addbyte(0xbe); addbyte(0xc4); - + return REG_EAX; } @@ -3529,7 +3600,7 @@ static inline int SIGN_EXTEND_L_B(int reg) addbyte(0x0f); /*MOVSX regl, regb*/ addbyte(0xbe); addbyte(0xc0 | (reg & 7)); - + return REG_EAX; } static inline int SIGN_EXTEND_L_W(int reg) @@ -3539,7 +3610,7 @@ static inline int SIGN_EXTEND_L_W(int reg) addbyte(0x0f); /*MOVSX regl, regw*/ addbyte(0xbf); addbyte(0xc0 | (reg & 7)); - + return REG_EAX; } @@ -3702,7 +3773,7 @@ static inline void NEG_HOST_REG_L(int reg) addbyte(0xf7); addbyte(0xd8 | (reg & 7)); } - + static inline void FP_ENTER() { @@ -3735,7 +3806,7 @@ static inline void FP_ENTER() CALL_FUNC((uintptr_t)x86_int); addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - + codegen_fpu_entered = 1; } @@ -3773,7 +3844,7 @@ static inline void FP_FXCH(int reg) addbyte(0x4c); addbyte(0xdd); addbyte((uint8_t)cpu_state_offset(ST)); - + addbyte(0x8a); /*MOV CL, tag[EAX]*/ addbyte(0x4c); addbyte(0x05); @@ -3811,7 +3882,6 @@ static inline void FP_FXCH(int reg) addbyte(0x4c); addbyte(0xdd); addbyte((uint8_t)cpu_state_offset(MM)); - reg = reg; } @@ -3840,7 +3910,7 @@ static inline void FP_FLD(int reg) addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(0x01); - } + } addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ addbyte(0x8b); @@ -4218,8 +4288,8 @@ static inline int FP_LOAD_REG(int reg) addbyte(0x66); /*MOVD EBX, XMM0*/ addbyte(0x0f); addbyte(0x7e); - addbyte(0xc0 | REG_EBX); - + addbyte(0xc0 | REG_EBX); + return REG_EBX; } static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) @@ -4241,13 +4311,63 @@ static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) addbyte(0x5c); addbyte(0xdd); addbyte((uint8_t)cpu_state_offset(ST)); - + *host_reg1 = REG_EBX; } +static inline int64_t x87_fround16_64(double b) +{ + int16_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int16_t)floor(b); + c = (int16_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return (int64_t) a; + else if ((b - a) > (c - b)) + return (int64_t) c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)((int16_t)floor(b)); + case 2: /*Up*/ + return (int64_t)((int16_t)ceil(b)); + case 3: /*Chop*/ + return (int64_t)((int16_t)b); + } + + return 0; +} +static inline int64_t x87_fround32_64(double b) +{ + int32_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int32_t)floor(b); + c = (int32_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return (int64_t) a; + else if ((b - a) > (c - b)) + return (int64_t) c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)((int32_t)floor(b)); + case 2: /*Up*/ + return (int64_t)((int32_t)ceil(b)); + case 3: /*Chop*/ + return (int64_t)((int32_t)b); + } + + return 0; +} static inline int64_t x87_fround(double b) { int64_t a, c; - + switch ((cpu_state.npxc >> 10) & 3) { case 0: /*Nearest*/ @@ -4266,7 +4386,7 @@ static inline int64_t x87_fround(double b) case 3: /*Chop*/ return (int64_t)b; } - + return 0; } static inline int FP_LOAD_REG_INT_W(int reg) @@ -4293,10 +4413,10 @@ static inline int FP_LOAD_REG_INT_W(int reg) addbyte(0xc5); addbyte((uint8_t)cpu_state_offset(ST)); - CALL_FUNC((uintptr_t)x87_fround); - + CALL_FUNC((uintptr_t)x87_fround16_64); + addbyte(0x93); /*XCHG EBX, EAX*/ - + return REG_EBX; } static inline int FP_LOAD_REG_INT(int reg) @@ -4323,10 +4443,10 @@ static inline int FP_LOAD_REG_INT(int reg) addbyte(0xc5); addbyte((uint8_t)cpu_state_offset(ST)); - CALL_FUNC((uintptr_t)x87_fround); - + CALL_FUNC((uintptr_t)x87_fround32_64); + addbyte(0x93); /*XCHG EBX, EAX*/ - + return REG_EBX; } static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) @@ -4362,16 +4482,16 @@ static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x93); *host_reg1 = REG_EBX; - + return; } - + addbyte(0xf6); /*TEST TAG[EAX], TAG_UINT64*/ addbyte(0x44); addbyte(0x05); addbyte((uint8_t)cpu_state_offset(tag)); addbyte(TAG_UINT64); - + addbyte(0x74); /*JZ +*/ addbyte(5+2); @@ -4380,7 +4500,7 @@ static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x44); addbyte(0xc5); addbyte((uint8_t)cpu_state_offset(MM)); - + addbyte(0xeb); /*JMP done*/ addbyte(6+12); @@ -4392,10 +4512,10 @@ static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte((uint8_t)cpu_state_offset(ST)); CALL_FUNC((uintptr_t)x87_fround); - + addbyte(0x48); /*XCHG RBX, RAX*/ addbyte(0x93); - + *host_reg1 = REG_EBX; } @@ -4895,7 +5015,7 @@ static inline void MMX_ENTER() { if (codegen_mmx_entered) return; - + if (IS_32_ADDR(&cr0)) { addbyte(0xf6); /*TEST cr0, 0xc*/ @@ -4924,7 +5044,7 @@ static inline void MMX_ENTER() addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - + addbyte(0x31); /*XOR EAX, EAX*/ addbyte(0xc0); addbyte(0xc6); /*MOV ISMMX, 1*/ @@ -4934,7 +5054,7 @@ static inline void MMX_ENTER() addbyte(0x89); /*MOV TOP, EAX*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV tag, EAX*/ + addbyte(0x89); /*MOV tag, EAX*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x89); /*MOV tag+4, EAX*/ @@ -4954,7 +5074,7 @@ static inline int LOAD_MMX_D(int guest_reg) addbyte(0x44 | (host_reg << 3)); addbyte(0x25); addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); - + return host_reg; } static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) @@ -4969,7 +5089,7 @@ static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) addbyte(0x44 | ((host_reg & 7) << 3)); addbyte(0x25); addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); - + *host_reg1 = host_reg; } static inline int LOAD_MMX_Q_MMX(int guest_reg) @@ -4983,7 +5103,7 @@ static inline int LOAD_MMX_Q_MMX(int guest_reg) addbyte(0x44 | ((dst_reg & 7) << 3)); addbyte(0x25); addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); - + return dst_reg; } @@ -4991,7 +5111,7 @@ static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = 100; - + addbyte(0x66); /*MOVQ host_reg, src_reg1*/ if (src_reg1 & 8) addbyte(0x49); @@ -5000,7 +5120,7 @@ static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) addbyte(0x0f); addbyte(0x6e); addbyte(0xc0 | (dst_reg << 3) | (src_reg1 & 7)); - + return dst_reg; } @@ -5262,7 +5382,7 @@ static inline void LOAD_EA() static inline void MEM_CHECK_WRITE(x86seg *seg) { uint8_t *jump1, *jump2, *jump3 = NULL; - + CHECK_SEG_WRITE(seg); if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) @@ -5288,7 +5408,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) /*seg = ESI, addr = EAX*/ - + if (IS_32_ADDR(&cr0)) { addbyte(0x83); /*CMP cr0, 0*/ @@ -5348,7 +5468,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) addbyte(0); if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) - *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; + *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; /*slowpath:*/ addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ addbyte(0x8d); @@ -5377,7 +5497,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) { uint8_t *jump1, *jump2, *jump3, *jump4 = NULL; int jump_pos; - + CHECK_SEG_WRITE(seg); if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) @@ -5403,7 +5523,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) /*seg = ESI, addr = EAX*/ - + if (IS_32_ADDR(&cr0)) { addbyte(0x83); /*CMP cr0, 0*/ @@ -5490,7 +5610,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) addbyte(0x75); /*JNE +*/ jump3 = &codeblock[block_current].data[block_pos]; addbyte(0); - + /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) @@ -5526,7 +5646,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) { uint8_t *jump1, *jump2, *jump3, *jump4 = NULL; int jump_pos; - + CHECK_SEG_WRITE(seg); if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) @@ -5552,7 +5672,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) /*seg = ESI, addr = EAX*/ - + if (IS_32_ADDR(&cr0)) { addbyte(0x83); /*CMP cr0, 0*/ @@ -5639,7 +5759,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) addbyte(0x75); /*JNE +*/ jump3 = &codeblock[block_current].data[block_pos]; addbyte(0); - + /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) @@ -5732,15 +5852,16 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemb386l); + call_long((uintptr_t)readmembl); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); /*done:*/ host_reg_mapping[REG_ECX] = 8; - + return REG_ECX; } static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) @@ -5810,15 +5931,16 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemwl); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); /*done:*/ host_reg_mapping[REG_ECX] = 8; - + return REG_ECX; } static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) @@ -5887,15 +6009,16 @@ static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemll); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); /*done:*/ host_reg_mapping[REG_ECX] = 8; - + return REG_ECX; } @@ -5990,12 +6113,17 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(REG_EDI | (REG_ESI << 3)); } addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12); + if (host_reg & 8) { + addbyte(2+2+3+12); + } else { + addbyte(2+2+2+12); + } /*slowpath:*/ - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xc3); load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)writememb386l); + call_long((uintptr_t)writemembl); /*done:*/ } static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) @@ -6074,11 +6202,16 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) addbyte(REG_EDI | (REG_ESI << 3)); } addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12); + if (host_reg & 8) { + addbyte(2+2+3+12); + } else { + addbyte(2+2+2+12); + } /*slowpath:*/ - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xc3); load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)writememwl); /*done:*/ } @@ -6156,11 +6289,16 @@ static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) addbyte(REG_EDI | (REG_ESI << 3)); } addbyte(0xeb); /*JMP done*/ - addbyte(2+2+3+12); + if (host_reg & 8) { + addbyte(2+2+3+12); + } else { + addbyte(2+2+2+12); + } /*slowpath:*/ - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xc3); load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)writememll); /*done:*/ } diff --git a/src/codegen/codegen_ops_x86.h b/src/codegen/codegen_ops_x86.h index 5dcfdef87..35bdeb5ff 100644 --- a/src/codegen/codegen_ops_x86.h +++ b/src/codegen/codegen_ops_x86.h @@ -16,7 +16,7 @@ static inline int find_host_reg() if (host_reg_mapping[c] == -1) break; } - + if (c == NR_HOST_REGS) fatal("Out of host regs!\n"); return c; @@ -29,7 +29,7 @@ static inline int find_host_xmm_reg() if (host_reg_xmm_mapping[c] == -1) break; } - + if (c == HOST_REG_XMM_END) fatal("Out of host XMM regs!\n"); return c; @@ -151,12 +151,12 @@ static inline int LOAD_VAR_WL(uintptr_t addr) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 0; - + addbyte(0x0f); /*MOVZX host_reg, [addr]*/ addbyte(0xb7); addbyte(0x05 | (host_reg << 3)); addlong((uint32_t)addr); - + return host_reg; } static inline int LOAD_VAR_L(uintptr_t addr) @@ -175,11 +175,11 @@ static inline int LOAD_REG_IMM(uint32_t imm) { int host_reg = find_host_reg(); host_reg_mapping[host_reg] = 0; - + addbyte(0xc7); /*MOVL host_reg, imm*/ addbyte(0xc0 | host_reg); addlong(imm); - + return host_reg; } @@ -187,10 +187,10 @@ static inline int LOAD_HOST_REG(int host_reg) { int new_host_reg = find_host_reg(); host_reg_mapping[new_host_reg] = 0; - + addbyte(0x89); /*MOV new_host_reg, host_reg*/ addbyte(0xc0 | (host_reg << 3) | new_host_reg); - + return new_host_reg; } @@ -366,25 +366,25 @@ static inline void AND_HOST_REG_IMM(int host_reg, uint32_t imm) static inline int TEST_HOST_REG_B(int dst_reg, int src_reg) { AND_HOST_REG_B(dst_reg, src_reg); - + return dst_reg; } static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) { AND_HOST_REG_W(dst_reg, src_reg); - + return dst_reg; } static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) { AND_HOST_REG_L(dst_reg, src_reg); - + return dst_reg; } static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) { AND_HOST_REG_IMM(host_reg, imm); - + return host_reg; } @@ -483,40 +483,59 @@ static inline void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) } } +static inline void INC_HOST_REG_W(int host_reg) +{ + addbyte(0x66); /*INCW host_reg*/ + addbyte(0x40 | host_reg); +} +static inline void INC_HOST_REG(int host_reg) +{ + addbyte(0x40 | host_reg); /*DECL host_reg*/ +} +static inline void DEC_HOST_REG_W(int host_reg) +{ + addbyte(0x66); /*DECW host_reg*/ + addbyte(0x48 | host_reg); +} +static inline void DEC_HOST_REG(int host_reg) +{ + addbyte(0x48 | host_reg); /*DECL host_reg*/ +} + static inline int CMP_HOST_REG_B(int dst_reg, int src_reg) { SUB_HOST_REG_B(dst_reg, src_reg); - + return dst_reg; } static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) { SUB_HOST_REG_W(dst_reg, src_reg); - + return dst_reg; } static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) { SUB_HOST_REG_L(dst_reg, src_reg); - + return dst_reg; } static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) { SUB_HOST_REG_IMM_B(host_reg, imm); - + return host_reg; } static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) { SUB_HOST_REG_IMM_W(host_reg, imm); - + return host_reg; } static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) { SUB_HOST_REG_IMM(host_reg, imm); - + return host_reg; } @@ -628,7 +647,7 @@ static inline void CHECK_SEG_READ(x86seg *seg) addbyte(0x0f); addbyte(0x84); /*JE BLOCK_GPF_OFFSET*/ addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); - + seg->checked = 1; } static inline void CHECK_SEG_WRITE(x86seg *seg) @@ -643,7 +662,7 @@ static inline void CHECK_SEG_WRITE(x86seg *seg) return; if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; - + addbyte(0x83); /*CMP seg->base, -1*/ addbyte(0x05|0x38); addlong((uint32_t)&seg->base); @@ -717,7 +736,7 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) addlong(mem_load_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[REG_ECX] = 8; - + return REG_ECX; } static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) @@ -776,7 +795,7 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) addlong(mem_load_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[REG_ECX] = 8; - + return REG_ECX; } static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) @@ -815,7 +834,7 @@ static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) addlong(mem_load_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); host_reg_mapping[REG_ECX] = 8; - + return REG_ECX; } @@ -1034,8 +1053,8 @@ static inline x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_s { int mod = (fetchdat >> 6) & 3; int rm = fetchdat & 7; - if (!mod && rm == 6) - { + if (!mod && rm == 6) + { addbyte(0xb8); /*MOVL EAX, imm16*/ addlong((fetchdat >> 8) & 0xffff); (*op_pc) += 2; @@ -1102,7 +1121,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s { uint8_t sib = fetchdat >> 8; (*op_pc)++; - + switch (mod) { case 0: @@ -1120,7 +1139,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); } break; - case 1: + case 1: addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); @@ -1185,7 +1204,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s else { if (!mod && rm == 5) - { + { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xb8); /*MOVL EAX, imm32*/ addlong(new_eaaddr); @@ -1196,22 +1215,22 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s addbyte(0x45); addbyte((uint8_t)cpu_state_offset(regs[rm].l)); cpu_state.eaaddr = cpu_state.regs[rm].l; - if (mod) + if (mod) { if (rm == 5 && !op_ssegs) op_ea_seg = &cpu_state.seg_ss; - if (mod == 1) + if (mod == 1) { addbyte(0x83); /*ADD EAX, imm8*/ addbyte(0xc0 | REG_EAX); - addbyte((int8_t)(fetchdat >> 8)); - (*op_pc)++; + addbyte((int8_t)(fetchdat >> 8)); + (*op_pc)++; } - else + else { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0x05); /*ADD EAX, imm32*/ - addlong(new_eaaddr); + addlong(new_eaaddr); (*op_pc) += 4; } } @@ -1456,7 +1475,7 @@ static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset else addbyte(0x77); /*JNBE*/ break; - + default: if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) { @@ -1486,7 +1505,7 @@ static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset addbyte(0x74); /*JZ +*/ break; } - addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(7+5+(timing_bt ? 4 : 0)); addbyte(0xC7); /*MOVL [pc], new_pc*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(pc)); @@ -1687,7 +1706,7 @@ static inline void FP_ENTER() { if (codegen_fpu_entered) return; - + addbyte(0xf6); /*TEST cr0, 0xc*/ addbyte(0x05); addlong((uintptr_t)&cr0); @@ -1706,7 +1725,7 @@ static inline void FP_ENTER() addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - + codegen_fpu_entered = 1; } @@ -1769,7 +1788,7 @@ static inline void FP_FLD(int reg) addbyte(0x83); /*SUB EBX, 1*/ addbyte(0xeb); addbyte(0x01); - } + } addbyte(0xdd); /*FLD [ST+EAX*8]*/ addbyte(0x44); @@ -2406,7 +2425,7 @@ static inline int FP_LOAD_REG(int reg) addbyte(0x8b); /*MOV EAX, [ESP]*/ addbyte(0x04 | (REG_EBX << 3)); addbyte(0x24); - + return REG_EBX; } @@ -2447,7 +2466,7 @@ static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) addbyte(0x44 | (REG_ECX << 3)); addbyte(0x24); addbyte(0x04); - + *host_reg1 = REG_EBX; *host_reg2 = REG_ECX; } @@ -2470,7 +2489,7 @@ static inline int FP_LOAD_REG_INT_W(int reg) addbyte(0x44); addbyte(0xdd); addbyte((uint8_t)cpu_state_offset(ST)); - + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ addbyte(0x6d); addbyte((uint8_t)cpu_state_offset(new_npxc)); @@ -2547,10 +2566,10 @@ static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x5c); addbyte(0xdd); addbyte((uint8_t)cpu_state_offset(MM)); - + return; } - + addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ addbyte(0x44); addbyte(0x1d); @@ -2567,10 +2586,10 @@ static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(0x5c); addbyte(0xdd); addbyte((uint8_t)cpu_state_offset(MM)); - + addbyte(0xeb); /*JMP done*/ addbyte(4+3+3+3+3+4); - + addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); @@ -2797,7 +2816,7 @@ static inline void FP_OP_D(int op) addbyte(0x6d); addbyte((uint8_t)cpu_state_offset(old_npxc)); } - } + } } static inline void FP_OP_IW(int op) { @@ -3557,7 +3576,7 @@ static inline void MMX_ENTER() { if (codegen_mmx_entered) return; - + addbyte(0xf6); /*TEST cr0, 0xc*/ addbyte(0x05); addlong((uintptr_t)&cr0); @@ -3576,7 +3595,7 @@ static inline void MMX_ENTER() addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); addbyte(0xe9); /*JMP end*/ addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - + addbyte(0x31); /*XOR EAX, EAX*/ addbyte(0xc0); addbyte(0xc6); /*MOV ISMMX, 1*/ @@ -3586,7 +3605,7 @@ static inline void MMX_ENTER() addbyte(0x89); /*MOV TOP, EAX*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV tag, EAX*/ + addbyte(0x89); /*MOV tag, EAX*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(tag[0])); addbyte(0x89); /*MOV tag+4, EAX*/ @@ -3606,7 +3625,7 @@ static inline int LOAD_MMX_D(int guest_reg) addbyte(0x8b); /*MOV EBX, reg*/ addbyte(0x45 | (host_reg << 3)); addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); - + return host_reg; } static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) @@ -3640,7 +3659,7 @@ static inline int LOAD_MMX_Q_MMX(int guest_reg) addbyte(0x7e); addbyte(0x45 | (dst_reg << 3)); addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); - + return dst_reg; } @@ -3648,7 +3667,7 @@ static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = 100; - + addbyte(0x66); /*MOVD dst_reg, src_reg1*/ addbyte(0x0f); addbyte(0x6e); @@ -3661,7 +3680,7 @@ static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) addbyte(0x0f); addbyte(0x62); addbyte(0xc0 | 7 | (dst_reg << 3)); - + return dst_reg; } diff --git a/src/codegen/codegen_ops_xchg.h b/src/codegen/codegen_ops_xchg.h index 597d26e1b..a51f42eda 100644 --- a/src/codegen/codegen_ops_xchg.h +++ b/src/codegen/codegen_ops_xchg.h @@ -44,9 +44,6 @@ OP_XCHG_EAX_(EBP) static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { -/* #ifdef __amd64__ - return 0; -#else */ int src_reg, dst_reg, temp_reg; if ((fetchdat & 0xc0) != 0xc0) @@ -57,9 +54,8 @@ static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin temp_reg = COPY_REG(src_reg); STORE_REG_TARGET_B_RELEASE(dst_reg, (fetchdat >> 3) & 7); STORE_REG_TARGET_B_RELEASE(temp_reg, fetchdat & 7); - + return op_pc + 1; -/* #endif */ } static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { @@ -73,7 +69,7 @@ static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin temp_reg = COPY_REG(src_reg); STORE_REG_TARGET_W_RELEASE(dst_reg, (fetchdat >> 3) & 7); STORE_REG_TARGET_W_RELEASE(temp_reg, fetchdat & 7); - + return op_pc + 1; } static uint32_t ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -88,6 +84,6 @@ static uint32_t ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin temp_reg = COPY_REG(src_reg); STORE_REG_TARGET_L_RELEASE(dst_reg, (fetchdat >> 3) & 7); STORE_REG_TARGET_L_RELEASE(temp_reg, fetchdat & 7); - + return op_pc + 1; } diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index f674df1e4..0559cc06d 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -1,7 +1,8 @@ -#ifdef __amd64__ +#if defined __amd64__ || defined _M_X64 #include #include +#include #include #include #define HAVE_STDARG_H @@ -20,11 +21,11 @@ #include "codegen_ops.h" #include "codegen_ops_x86-64.h" -#if defined(__linux__) || defined(__APPLE__) +#if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) #include #include #endif -#if WIN64 +#if _WIN64 #include #endif @@ -49,11 +50,6 @@ int block_current = 0; static int block_num; int block_pos; -int cpu_recomp_flushes, cpu_recomp_flushes_latched; -int cpu_recomp_evicted, cpu_recomp_evicted_latched; -int cpu_recomp_reuse, cpu_recomp_reuse_latched; -int cpu_recomp_removed, cpu_recomp_removed_latched; - uint32_t codegen_endpc; int codegen_block_cycles; @@ -68,15 +64,10 @@ void codegen_init() { int c; -#if defined(__linux__) || defined(__APPLE__) - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif - -#if WIN64 +#if _WIN64 codeblock = VirtualAlloc(NULL, BLOCK_SIZE * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#elif defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) + codeblock = mmap(NULL, BLOCK_SIZE * sizeof(codeblock_t), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); #else codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); #endif @@ -87,22 +78,12 @@ void codegen_init() for (c = 0; c < BLOCK_SIZE; c++) codeblock[c].valid = 0; - -#if defined(__linux__) || defined(__APPLE__) - start = (void *)((long)codeblock & pagemask); - len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; - if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - { - perror("mprotect"); - exit(-1); - } -#endif } void codegen_reset() { int c; - + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); mem_reset_page_blocks(); @@ -139,7 +120,7 @@ static void add_to_block_list(codeblock_t *block) if (block->next->valid == 0) fatal("block->next->valid=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); } - + if (block->page_mask2) { block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; @@ -224,7 +205,6 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) if (mask & block->page_mask) { delete_block(block); - cpu_recomp_evicted++; } if (block == block->next) fatal("Broken 1\n"); @@ -232,13 +212,12 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) } block = page->block_2[(phys_addr >> 10) & 3]; - + while (block) { if (mask & block->page_mask2) { delete_block(block); - cpu_recomp_evicted++; } if (block == block->next_2) fatal("Broken 2\n"); @@ -250,7 +229,7 @@ void codegen_block_init(uint32_t phys_addr) { codeblock_t *block; page_t *page = &pages[phys_addr >> 12]; - + if (!page->block[(phys_addr >> 10) & 3]) mem_flush_write_page(phys_addr, cs+cpu_state.pc); @@ -260,7 +239,6 @@ void codegen_block_init(uint32_t phys_addr) if (block->valid != 0) { delete_block(block); - cpu_recomp_reuse++; } block_num = HASH(phys_addr); codeblock_hash[block_num] = &codeblock[block_current]; @@ -278,18 +256,18 @@ void codegen_block_init(uint32_t phys_addr) block->page_mask = 0; block->flags = 0; block->status = cpu_cur_status; - + block->was_recompiled = 0; recomp_page = block->phys & ~0xfff; - + codeblock_tree_add(block); } void codegen_block_start_recompile(codeblock_t *block) { page_t *page = &pages[block->phys >> 12]; - + if (!page->block[(block->phys >> 10) & 3]) mem_flush_write_page(block->phys, cs+cpu_state.pc); @@ -300,9 +278,10 @@ void codegen_block_start_recompile(codeblock_t *block) fatal("Recompile to used block!\n"); block->status = cpu_cur_status; - + block_pos = BLOCK_GPF_OFFSET; -#if WIN64 +#ifdef OLD_GPF +#if _WIN64 addbyte(0x48); /*XOR RCX, RCX*/ addbyte(0x31); addbyte(0xc9); @@ -318,6 +297,17 @@ void codegen_block_start_recompile(codeblock_t *block) call(block, (uintptr_t)x86gpf); while (block_pos < BLOCK_EXIT_OFFSET) addbyte(0x90); /*NOP*/ +#else + addbyte(0xc6); /* mov byte ptr[&(cpu_state.abrt)],ABRT_GPF */ + addbyte(0x05); + addlong((uint32_t) (uintptr_t) &(cpu_state.abrt)); + addbyte(ABRT_GPF); + addbyte(0x31); /* xor eax,eax */ + addbyte(0xc0); + addbyte(0x67); /* mov [&(abrt_error)],eax */ + addbyte(0xa3); + addlong((uint32_t) (uintptr_t) &(abrt_error)); +#endif block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ addbyte(0x48); /*ADDL $40,%rsp*/ addbyte(0x83); @@ -361,22 +351,22 @@ void codegen_block_start_recompile(codeblock_t *block) last_op32 = -1; last_ea_seg = NULL; last_ssegs = -1; - + codegen_block_cycles = 0; codegen_timing_block_start(); - + codegen_block_ins = 0; codegen_block_full_ins = 0; recomp_page = block->phys & ~0xfff; - + codegen_flags_changed = 0; codegen_fpu_entered = 0; codegen_mmx_entered = 0; - + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; - + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = @@ -393,7 +383,6 @@ void codegen_block_remove() codeblock_t *block = &codeblock[block_current]; delete_block(block); - cpu_recomp_removed++; recomp_page = -1; } @@ -437,7 +426,7 @@ void codegen_block_generate_end_mask() for (; start_pc <= end_pc; start_pc++) block->page_mask2 |= ((uint64_t)1 << start_pc); page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; - + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) mem_flush_write_page(block->phys_2, block->endpc); @@ -448,7 +437,7 @@ void codegen_block_generate_end_mask() if (block->next_2->valid == 0) fatal("block->next_2->valid=0 %p\n", (void *)block->next_2); } - + block->dirty_mask2 = &page_2->dirty_mask[(block->phys_2 >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; } } @@ -488,7 +477,7 @@ void codegen_block_end_recompile(codeblock_t *block) addbyte(0x5d); /*POP RBP*/ addbyte(0x5b); /*POP RDX*/ addbyte(0xC3); /*RET*/ - + if (block_pos > BLOCK_GPF_OFFSET) fatal("Over limit!\n"); @@ -531,7 +520,7 @@ int opcode_0f_modrm[256] = 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ @@ -548,15 +537,15 @@ int opcode_0f_modrm[256] = 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ }; - + void codegen_debug() { } static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) { - if (!cpu_mod && cpu_rm == 6) - { + if (!cpu_mod && cpu_rm == 6) + { addbyte(0xC7); /*MOVL $0,(ssegs)*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(eaaddr)); @@ -566,7 +555,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, else { int base_reg = 0, index_reg = 0; - + switch (cpu_rm) { case 0: case 1: case 7: @@ -591,7 +580,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, } base_reg &= 7; index_reg &= 7; - + switch (cpu_mod) { case 0: @@ -660,7 +649,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, } (*op_pc) += 2; break; - + } if (cpu_mod || !(cpu_rm & 4)) { @@ -749,7 +738,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, } } else - { + { switch (cpu_mod) { case 0: @@ -831,7 +820,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int base_reg; if (!cpu_mod && cpu_rm == 5) - { + { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ addbyte(0x45); @@ -841,20 +830,20 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, return op_ea_seg; } base_reg = LOAD_REG_L(cpu_rm) & 7; - if (cpu_mod) + if (cpu_mod) { if (cpu_rm == 5 && !op_ssegs) op_ea_seg = &cpu_state.seg_ss; - if (cpu_mod == 1) + if (cpu_mod == 1) { addbyte(0x67); /*LEA EAX, base_reg+imm8*/ addbyte(0x41); addbyte(0x8d); addbyte(0x40 | base_reg); addbyte((fetchdat >> 8) & 0xff); - (*op_pc)++; + (*op_pc)++; } - else + else { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0x67); /*LEA EAX, base_reg+imm32*/ @@ -892,16 +881,16 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t int pc_off = 0; int test_modrm = 1; int c; - + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; op_old_pc = old_pc; - + for (c = 0; c < NR_HOST_REGS; c++) host_reg_mapping[c] = -1; for (c = 0; c < NR_HOST_XMM_REGS; c++) host_reg_xmm_mapping[c] = -1; - + codegen_timing_start(); while (!over) @@ -913,7 +902,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t recomp_op_table = recomp_opcodes_0f; over = 1; break; - + case 0x26: /*ES:*/ op_ea_seg = &cpu_state.seg_es; op_ssegs = 1; @@ -938,14 +927,14 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t op_ea_seg = &cpu_state.seg_gs; op_ssegs = 1; break; - + case 0x66: /*Data size select*/ op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); break; case 0x67: /*Address size select*/ op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); break; - + case 0xd8: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; recomp_op_table = recomp_opcodes_d8; @@ -1020,7 +1009,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t test_modrm = 0; block->flags |= CODEBLOCK_HAS_FPU; break; - + case 0xf0: /*LOCK*/ break; @@ -1045,14 +1034,13 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t fetchdat >>= 8; op_pc++; } - + generate_call: codegen_timing_opcode(opcode, fetchdat, op_32, op_pc); - codegen_accumulate(ACCREG_ins, 1); codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); codegen_block_cycles = 0; - + if ((op_table == x86_dynarec_opcodes && ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || @@ -1095,6 +1083,17 @@ generate_call: codegen_block_full_ins++; codegen_endpc = (cs + cpu_state.pc) + 8; +#ifdef CHECK_INT + /* Check for interrupts. */ + addbyte(0xf6); /* test byte ptr[&pic_pending],1 */ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t) (uintptr_t) &pic_pending); + addbyte(0x01); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)(uintptr_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(uintptr_t)(&block->data[block_pos + 4])); +#endif + return; } } @@ -1113,7 +1112,7 @@ generate_call: (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))/* && !(op_32 & 0x200)*/) { int stack_offset = 0; - + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ stack_offset = (op_32 & 0x100) ? 4 : 2; @@ -1161,12 +1160,20 @@ generate_call: } load_param_1_32(block, fetchdat); - call(block, (uintptr_t)op); + call(block, (uintptr_t)op); codegen_block_ins++; - + block->ins++; +#ifdef CHECK_INT + /* Check for interrupts. */ + addbyte(0x0a); /* or al,byte ptr[&pic_pending] */ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t) (uintptr_t) &pic_pending); +#endif + addbyte(0x85); /*OR %eax, %eax*/ addbyte(0xc0); addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ diff --git a/src/codegen/codegen_x86-64.h b/src/codegen/codegen_x86-64.h index 648a30342..529be99ae 100644 --- a/src/codegen/codegen_x86-64.h +++ b/src/codegen/codegen_x86-64.h @@ -8,7 +8,11 @@ #define HASH(l) ((l) & 0x1ffff) #define BLOCK_EXIT_OFFSET 0x7e0 +#ifdef OLD_GPF #define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) +#else +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 15) +#endif #define BLOCK_MAX 1620 diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index 44d66b42f..c104883ef 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -36,7 +36,7 @@ * Boston, MA 02111-1307 * USA. */ -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 #include #include @@ -50,6 +50,9 @@ #include "x86_flags.h" #include "x86_ops.h" #include "x87.h" +/*ex*/ +#include <86box/nmi.h> +#include <86box/pic.h> #include "386_common.h" @@ -58,7 +61,7 @@ #include "codegen_ops.h" #include "codegen_ops_x86.h" -#ifdef __linux__ +#ifdef __unix__ #include #include #endif @@ -88,11 +91,6 @@ int block_current = 0; static int block_num; int block_pos; -int cpu_recomp_flushes, cpu_recomp_flushes_latched; -int cpu_recomp_evicted, cpu_recomp_evicted_latched; -int cpu_recomp_reuse, cpu_recomp_reuse_latched; -int cpu_recomp_removed, cpu_recomp_removed_latched; - uint32_t codegen_endpc; int codegen_block_cycles; @@ -150,13 +148,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmembl*/ - addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addlong((uint32_t)readmembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -168,7 +167,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B() addbyte(0x85); addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); addbyte(0xc3); /*RET*/ - + return addr; } @@ -205,13 +204,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemwl*/ addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -223,7 +223,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W() addbyte(0x85); addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); addbyte(0xc3); /*RET*/ - + return addr; } @@ -259,13 +259,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemll*/ addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -274,14 +275,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L() addbyte(0x85); addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); addbyte(0xc3); /*RET*/ - + return addr; } static uint32_t gen_MEM_LOAD_ADDR_EA_Q() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + addbyte(0x89); /*MOV ESI, EDX*/ addbyte(0xd6); addbyte(0x01); /*ADDL EDX, EAX*/ @@ -314,13 +315,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_Q() addbyte(4); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemql*/ addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -329,14 +331,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_Q() addbyte(0x85); addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); addbyte(0xc3); /*RET*/ - + return addr; } static uint32_t gen_MEM_STORE_ADDR_EA_B() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); @@ -362,13 +364,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememb386l*/ - addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xe8); /*CALL writemembl*/ + addlong((uint32_t)writemembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -384,7 +387,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B() static uint32_t gen_MEM_STORE_ADDR_EA_W() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); @@ -416,13 +419,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememwl*/ addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -438,7 +442,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W() static uint32_t gen_MEM_STORE_ADDR_EA_L() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); @@ -469,13 +473,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememll*/ addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -491,7 +496,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L() static uint32_t gen_MEM_STORE_ADDR_EA_Q() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = EBX/ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EDX, ESI*/ addbyte(0xf2); @@ -527,13 +532,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_Q() addbyte(0x51); /*slowpath: PUSH ECX*/ addbyte(0x53); /*PUSH EBX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EDX,EAX*/ + addbyte(0xC2); addbyte(0x52); /*PUSH EDX*/ addbyte(0xe8); /*CALL writememql*/ addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 16*/ + addbyte(0x83); /*ADD ESP, 12*/ addbyte(0xc4); - addbyte(16); + addbyte(12); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -577,13 +583,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmembl*/ - addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addlong((uint32_t)readmembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -598,7 +605,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() addbyte(1); #endif addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD +#ifndef RELEASE_BUILD addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); @@ -606,7 +613,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ -#endif +#endif return addr; } @@ -646,13 +653,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemwl*/ addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -714,13 +722,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemll*/ addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); #ifndef RELEASE_BUILD @@ -743,7 +752,7 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() addbyte(0xe8); /*CALL fatal*/ addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); /*Should not return!*/ -#endif +#endif return addr; } @@ -753,7 +762,7 @@ static char gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_B_NO_ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); @@ -779,13 +788,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xc3); addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememb386l*/ - addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xe8); /*CALL writemembl*/ + addlong((uint32_t)writemembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -795,7 +805,7 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() addbyte(1); #endif addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD +#ifndef RELEASE_BUILD addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err*/ addbyte(0x04); addbyte(0x24); @@ -813,7 +823,7 @@ static char gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_W_NO_ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); @@ -845,13 +855,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememwl*/ addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -879,7 +890,7 @@ static char gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_L_NO_ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*dat = ECX, seg = ESI, addr = EAX*/ addbyte(0x89); /*MOV EBX, ESI*/ addbyte(0xf3); @@ -910,13 +921,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememll*/ addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -941,9 +953,9 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() static uint32_t gen_MEM_CHECK_WRITE() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*seg = ESI, addr = EAX*/ - + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ addbyte(0x3c); addbyte(0x30); @@ -970,7 +982,7 @@ static uint32_t gen_MEM_CHECK_WRITE() addbyte(0x74); /*JE +*/ addbyte(1); addbyte(0xc3); /*RET*/ - + /*slowpath:*/ addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ addbyte(0x3c); @@ -998,9 +1010,9 @@ static uint32_t gen_MEM_CHECK_WRITE() static uint32_t gen_MEM_CHECK_WRITE_W() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*seg = ESI, addr = EAX*/ - + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ addbyte(0x3c); addbyte(0x30); @@ -1042,7 +1054,7 @@ static uint32_t gen_MEM_CHECK_WRITE_W() addbyte(0x74); /*JE +*/ addbyte(1); addbyte(0xc3); /*RET*/ - + /*slowpath:*/ addbyte(0x89); /*MOV EDI, EAX*/ addbyte(0xc7); @@ -1080,9 +1092,9 @@ static uint32_t gen_MEM_CHECK_WRITE_W() static uint32_t gen_MEM_CHECK_WRITE_L() { uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - + /*seg = ESI, addr = EAX*/ - + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ addbyte(0x3c); addbyte(0x30); @@ -1124,7 +1136,7 @@ static uint32_t gen_MEM_CHECK_WRITE_L() addbyte(0x74); /*JE +*/ addbyte(1); addbyte(0xc3); /*RET*/ - + /*slowpath:*/ addbyte(0x89); /*MOV EDI, EAX*/ addbyte(0xc7); @@ -1161,15 +1173,10 @@ static uint32_t gen_MEM_CHECK_WRITE_L() void codegen_init() { -#ifdef __linux__ - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif - #ifdef _WIN32 codeblock = VirtualAlloc(NULL, (BLOCK_SIZE+1) * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#elif defined __unix__ + codeblock = mmap(NULL, (BLOCK_SIZE+1) * sizeof(codeblock_t), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, 0, 0); #else codeblock = malloc((BLOCK_SIZE+1) * sizeof(codeblock_t)); #endif @@ -1178,19 +1185,9 @@ void codegen_init() memset(codeblock, 0, (BLOCK_SIZE+1) * sizeof(codeblock_t)); memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); -#ifdef __linux__ - start = (void *)((long)codeblock & pagemask); - len = (((BLOCK_SIZE+1) * sizeof(codeblock_t)) + pagesize) & pagemask; - if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - { - perror("mprotect"); - exit(-1); - } -#endif - block_current = BLOCK_SIZE; block_pos = 0; - mem_abrt_rout = (uint32_t)&codeblock[block_current].data[block_pos]; + mem_abrt_rout = (uint32_t)&codeblock[block_current].data[block_pos]; addbyte(0x83); /*ADDL $16+4,%esp*/ addbyte(0xC4); addbyte(0x10+4); @@ -1233,7 +1230,7 @@ void codegen_init() mem_check_write_w = (uint32_t)gen_MEM_CHECK_WRITE_W(); block_pos = (block_pos + 15) & ~15; mem_check_write_l = (uint32_t)gen_MEM_CHECK_WRITE_L(); - + #ifndef _MSC_VER asm( "fstcw %0\n" @@ -1282,7 +1279,7 @@ static void add_to_block_list(codeblock_t *block) if (!block->next->valid) fatal("block->next->valid=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); } - + if (block->page_mask2) { block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; @@ -1367,7 +1364,6 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) if (mask & block->page_mask) { delete_block(block); - cpu_recomp_evicted++; } if (block == block->next) fatal("Broken 1\n"); @@ -1375,13 +1371,12 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) } block = page->block_2[(phys_addr >> 10) & 3]; - + while (block) { if (mask & block->page_mask2) { delete_block(block); - cpu_recomp_evicted++; } if (block == block->next_2) fatal("Broken 2\n"); @@ -1393,7 +1388,7 @@ void codegen_block_init(uint32_t phys_addr) { codeblock_t *block; page_t *page = &pages[phys_addr >> 12]; - + if (!page->block[(phys_addr >> 10) & 3]) mem_flush_write_page(phys_addr, cs+cpu_state.pc); @@ -1403,7 +1398,6 @@ void codegen_block_init(uint32_t phys_addr) if (block->valid != 0) { delete_block(block); - cpu_recomp_reuse++; } block_num = HASH(phys_addr); codeblock_hash[block_num] = &codeblock[block_current]; @@ -1421,18 +1415,18 @@ void codegen_block_init(uint32_t phys_addr) block->page_mask = 0; block->flags = CODEBLOCK_STATIC_TOP; block->status = cpu_cur_status; - + block->was_recompiled = 0; recomp_page = block->phys & ~0xfff; - + codeblock_tree_add(block); } void codegen_block_start_recompile(codeblock_t *block) { page_t *page = &pages[block->phys >> 12]; - + if (!page->block[(block->phys >> 10) & 3]) mem_flush_write_page(block->phys, cs+cpu_state.pc); @@ -1445,6 +1439,7 @@ void codegen_block_start_recompile(codeblock_t *block) block->status = cpu_cur_status; block_pos = BLOCK_GPF_OFFSET; +#ifdef OLD_GPF addbyte(0xc7); /*MOV [ESP],0*/ addbyte(0x04); addbyte(0x24); @@ -1456,6 +1451,16 @@ void codegen_block_start_recompile(codeblock_t *block) addlong(0); addbyte(0xe8); /*CALL x86gpf*/ addlong((uint32_t)x86gpf - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +#else + addbyte(0xc6); /* mov byte ptr[&(cpu_state.abrt)],ABRT_GPF */ + addbyte(0x05); + addlong((uint32_t) (uintptr_t) &(cpu_state.abrt)); + addbyte(ABRT_GPF); + addbyte(0x31); /* xor eax,eax */ + addbyte(0xc0); + addbyte(0xa3); /* mov [&(abrt_error)],eax */ + addlong((uint32_t) (uintptr_t) &(abrt_error)); +#endif block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ addbyte(0x83); /*ADDL $16,%esp*/ addbyte(0xC4); @@ -1480,29 +1485,29 @@ void codegen_block_start_recompile(codeblock_t *block) last_op32 = -1; last_ea_seg = NULL; last_ssegs = -1; - + codegen_block_cycles = 0; codegen_timing_block_start(); - + codegen_block_ins = 0; codegen_block_full_ins = 0; recomp_page = block->phys & ~0xfff; - + codegen_flags_changed = 0; codegen_fpu_entered = 0; codegen_mmx_entered = 0; codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; - + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; block->TOP = cpu_state.TOP & 7; block->was_recompiled = 1; codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); - codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); codegen_accumulate_reset(); } @@ -1512,7 +1517,6 @@ void codegen_block_remove() codeblock_t *block = &codeblock[block_current]; delete_block(block); - cpu_recomp_removed++; recomp_page = -1; } @@ -1535,12 +1539,12 @@ void codegen_block_generate_end_mask() end_pc = 0x3ff; start_pc >>= PAGE_MASK_SHIFT; end_pc >>= PAGE_MASK_SHIFT; - + for (; start_pc <= end_pc; start_pc++) - { + { block->page_mask |= ((uint64_t)1 << start_pc); } - + pages[block->phys >> 12].code_present_mask[(block->phys >> 10) & 3] |= block->page_mask; block->phys_2 = -1; @@ -1558,7 +1562,7 @@ void codegen_block_generate_end_mask() for (; start_pc <= end_pc; start_pc++) block->page_mask2 |= ((uint64_t)1 << start_pc); page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; - + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) mem_flush_write_page(block->phys_2, block->endpc); @@ -1600,7 +1604,7 @@ void codegen_block_end_recompile(codeblock_t *block) addbyte(0x5d); /*POP EBP*/ addbyte(0x5b); /*POP EDX*/ addbyte(0xC3); /*RET*/ - + if (block_pos > BLOCK_GPF_OFFSET) fatal("Over limit!\n"); @@ -1646,7 +1650,7 @@ int opcode_0f_modrm[256] = 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ @@ -1670,8 +1674,8 @@ void codegen_debug() static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) { - if (!cpu_mod && cpu_rm == 6) - { + if (!cpu_mod && cpu_rm == 6) + { addbyte(0xC7); /*MOVL $0,(ssegs)*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(eaaddr)); @@ -1731,7 +1735,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, { uint8_t sib = fetchdat >> 8; (*op_pc)++; - + switch (cpu_mod) { case 0: @@ -1749,7 +1753,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); } break; - case 1: + case 1: new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ addlong(new_eaaddr); @@ -1807,7 +1811,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, else { if (!cpu_mod && cpu_rm == 5) - { + { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ addbyte(0x45); @@ -1820,21 +1824,21 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addbyte(0x45); addbyte((uint8_t)cpu_state_offset(regs[cpu_rm].l)); cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; - if (cpu_mod) + if (cpu_mod) { if (cpu_rm == 5 && !op_ssegs) op_ea_seg = &cpu_state.seg_ss; - if (cpu_mod == 1) + if (cpu_mod == 1) { addbyte(0x05); - addlong((uint32_t)(int8_t)(fetchdat >> 8)); - (*op_pc)++; + addlong((uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; } - else + else { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0x05); - addlong(new_eaaddr); + addlong(new_eaaddr); (*op_pc) += 4; } } @@ -1861,13 +1865,13 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; op_old_pc = old_pc; - + for (c = 0; c < NR_HOST_REGS; c++) host_reg_mapping[c] = -1; mmx_ebx_ecx_loaded = 0; for (c = 0; c < NR_HOST_XMM_REGS; c++) host_reg_xmm_mapping[c] = -1; - + codegen_timing_start(); while (!over) @@ -1879,7 +1883,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t recomp_op_table = recomp_opcodes_0f; over = 1; break; - + case 0x26: /*ES:*/ op_ea_seg = &cpu_state.seg_es; op_ssegs = 1; @@ -1904,14 +1908,14 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t op_ea_seg = &cpu_state.seg_gs; op_ssegs = 1; break; - + case 0x66: /*Data size select*/ op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); break; case 0x67: /*Address size select*/ op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); break; - + case 0xd8: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; recomp_op_table = recomp_opcodes_d8; @@ -1986,10 +1990,10 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t test_modrm = 0; block->flags |= CODEBLOCK_HAS_FPU; break; - + case 0xf0: /*LOCK*/ break; - + case 0xf2: /*REPNE*/ op_table = x86_dynarec_opcodes_REPNE; recomp_op_table = recomp_opcodes_REPNE; @@ -2009,14 +2013,13 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t opcode = fetchdat & 0xff; if (!pc_off) fetchdat >>= 8; - + op_pc++; } - + generate_call: codegen_timing_opcode(opcode, fetchdat, op_32, op_pc); - codegen_accumulate(ACCREG_ins, 1); codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); codegen_block_cycles = 0; @@ -2062,10 +2065,20 @@ generate_call: codegen_block_full_ins++; codegen_endpc = (cs + cpu_state.pc) + 8; +#ifdef CHECK_INT + /* Check for interrupts. */ + addbyte(0xf6); /* test byte ptr[&pic_pending],1 */ + addbyte(0x05); + addlong((uint32_t) (uintptr_t) &pic_pending); + addbyte(0x01); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); +#endif + return; } } - + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; if (op_ssegs != last_ssegs) { @@ -2082,7 +2095,7 @@ generate_call: (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode])) { int stack_offset = 0; - + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ stack_offset = (op_32 & 0x100) ? 4 : 2; @@ -2137,14 +2150,21 @@ generate_call: addbyte(0x04); addbyte(0x24); addlong(fetchdat); - + addbyte(0xE8); /*CALL*/ addlong(((uint8_t *)op - (uint8_t *)(&block->data[block_pos + 4]))); codegen_block_ins++; - + block->ins++; +#ifdef CHECK_INT + /* Check for interrupts. */ + addbyte(0x0a); /* or al,byte ptr[&pic_pending] */ + addbyte(0x05); + addlong((uint32_t) (uintptr_t) &pic_pending); +#endif + addbyte(0x09); /*OR %eax, %eax*/ addbyte(0xc0); addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ diff --git a/src/codegen/codegen_x86.h b/src/codegen/codegen_x86.h index 3a3662d32..369614329 100644 --- a/src/codegen/codegen_x86.h +++ b/src/codegen/codegen_x86.h @@ -8,7 +8,11 @@ #define HASH(l) ((l) & 0x1ffff) #define BLOCK_EXIT_OFFSET 0x7f0 +#ifdef OLD_GPF #define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) +#else +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 14) +#endif #define BLOCK_MAX 1720 diff --git a/src/codegen/x86_flags.h b/src/codegen/x86_flags.h deleted file mode 100644 index 7068a243d..000000000 --- a/src/codegen/x86_flags.h +++ /dev/null @@ -1,526 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern int tempc; - -enum -{ - FLAGS_UNKNOWN, - - FLAGS_ZN8, - FLAGS_ZN16, - FLAGS_ZN32, - - FLAGS_ADD8, - FLAGS_ADD16, - FLAGS_ADD32, - - FLAGS_SUB8, - FLAGS_SUB16, - FLAGS_SUB32, - - FLAGS_SHL8, - FLAGS_SHL16, - FLAGS_SHL32, - - FLAGS_SHR8, - FLAGS_SHR16, - FLAGS_SHR32, - - FLAGS_SAR8, - FLAGS_SAR16, - FLAGS_SAR32, - - FLAGS_INC8, - FLAGS_INC16, - FLAGS_INC32, - - FLAGS_DEC8, - FLAGS_DEC16, - FLAGS_DEC32 -}; - -static __inline int ZF_SET() -{ - switch (cpu_state.flags_op) - { - case FLAGS_ZN8: - case FLAGS_ZN16: - case FLAGS_ZN32: - case FLAGS_ADD8: - case FLAGS_ADD16: - case FLAGS_ADD32: - case FLAGS_SUB8: - case FLAGS_SUB16: - case FLAGS_SUB32: - case FLAGS_SHL8: - case FLAGS_SHL16: - case FLAGS_SHL32: - case FLAGS_SHR8: - case FLAGS_SHR16: - case FLAGS_SHR32: - case FLAGS_SAR8: - case FLAGS_SAR16: - case FLAGS_SAR32: - case FLAGS_INC8: - case FLAGS_INC16: - case FLAGS_INC32: - case FLAGS_DEC8: - case FLAGS_DEC16: - case FLAGS_DEC32: - return !cpu_state.flags_res; - - case FLAGS_UNKNOWN: - return cpu_state.flags & Z_FLAG; - - default: - return 0; - } -} - -static __inline int NF_SET() -{ - switch (cpu_state.flags_op) - { - case FLAGS_ZN8: - case FLAGS_ADD8: - case FLAGS_SUB8: - case FLAGS_SHL8: - case FLAGS_SHR8: - case FLAGS_SAR8: - case FLAGS_INC8: - case FLAGS_DEC8: - return cpu_state.flags_res & 0x80; - - case FLAGS_ZN16: - case FLAGS_ADD16: - case FLAGS_SUB16: - case FLAGS_SHL16: - case FLAGS_SHR16: - case FLAGS_SAR16: - case FLAGS_INC16: - case FLAGS_DEC16: - return cpu_state.flags_res & 0x8000; - - case FLAGS_ZN32: - case FLAGS_ADD32: - case FLAGS_SUB32: - case FLAGS_SHL32: - case FLAGS_SHR32: - case FLAGS_SAR32: - case FLAGS_INC32: - case FLAGS_DEC32: - return cpu_state.flags_res & 0x80000000; - - case FLAGS_UNKNOWN: - return cpu_state.flags & N_FLAG; - - default: - return 0; - } -} - -static __inline int PF_SET() -{ - switch (cpu_state.flags_op) - { - case FLAGS_ZN8: - case FLAGS_ZN16: - case FLAGS_ZN32: - case FLAGS_ADD8: - case FLAGS_ADD16: - case FLAGS_ADD32: - case FLAGS_SUB8: - case FLAGS_SUB16: - case FLAGS_SUB32: - case FLAGS_SHL8: - case FLAGS_SHL16: - case FLAGS_SHL32: - case FLAGS_SHR8: - case FLAGS_SHR16: - case FLAGS_SHR32: - case FLAGS_SAR8: - case FLAGS_SAR16: - case FLAGS_SAR32: - case FLAGS_INC8: - case FLAGS_INC16: - case FLAGS_INC32: - case FLAGS_DEC8: - case FLAGS_DEC16: - case FLAGS_DEC32: - return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; - - case FLAGS_UNKNOWN: - return cpu_state.flags & P_FLAG; - - default: - return 0; - } -} - -static __inline int VF_SET() -{ - switch (cpu_state.flags_op) - { - case FLAGS_ZN8: - case FLAGS_ZN16: - case FLAGS_ZN32: - case FLAGS_SAR8: - case FLAGS_SAR16: - case FLAGS_SAR32: - return 0; - - case FLAGS_ADD8: - case FLAGS_INC8: - return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); - case FLAGS_ADD16: - case FLAGS_INC16: - return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); - case FLAGS_ADD32: - case FLAGS_INC32: - return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); - - case FLAGS_SUB8: - case FLAGS_DEC8: - return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); - case FLAGS_SUB16: - case FLAGS_DEC16: - return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); - case FLAGS_SUB32: - case FLAGS_DEC32: - return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); - - case FLAGS_SHL8: - return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); - case FLAGS_SHL16: - return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); - case FLAGS_SHL32: - return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); - - case FLAGS_SHR8: - return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); - case FLAGS_SHR16: - return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); - case FLAGS_SHR32: - return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); - - case FLAGS_UNKNOWN: - return cpu_state.flags & V_FLAG; - - default: - return 0; - } -} - -static __inline int AF_SET() -{ - switch (cpu_state.flags_op) - { - case FLAGS_ZN8: - case FLAGS_ZN16: - case FLAGS_ZN32: - case FLAGS_SHL8: - case FLAGS_SHL16: - case FLAGS_SHL32: - case FLAGS_SHR8: - case FLAGS_SHR16: - case FLAGS_SHR32: - case FLAGS_SAR8: - case FLAGS_SAR16: - case FLAGS_SAR32: - return 0; - - case FLAGS_ADD8: - case FLAGS_ADD16: - case FLAGS_ADD32: - case FLAGS_INC8: - case FLAGS_INC16: - case FLAGS_INC32: - return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; - - case FLAGS_SUB8: - case FLAGS_SUB16: - case FLAGS_SUB32: - case FLAGS_DEC8: - case FLAGS_DEC16: - case FLAGS_DEC32: - return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; - - case FLAGS_UNKNOWN: - return cpu_state.flags & A_FLAG; - - default: - return 0; - } -} - -static __inline int CF_SET() -{ - switch (cpu_state.flags_op) - { - case FLAGS_ADD8: - return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; - case FLAGS_ADD16: - return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; - case FLAGS_ADD32: - return (cpu_state.flags_res < cpu_state.flags_op1); - - case FLAGS_SUB8: - case FLAGS_SUB16: - case FLAGS_SUB32: - return (cpu_state.flags_op1 < cpu_state.flags_op2); - - case FLAGS_SHL8: - return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; - case FLAGS_SHL16: - return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; - case FLAGS_SHL32: - return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; - - case FLAGS_SHR8: - case FLAGS_SHR16: - case FLAGS_SHR32: - return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; - - case FLAGS_SAR8: - return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; - case FLAGS_SAR16: - return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; - case FLAGS_SAR32: - return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; - - case FLAGS_ZN8: - case FLAGS_ZN16: - case FLAGS_ZN32: - return 0; - - case FLAGS_DEC8: - case FLAGS_DEC16: - case FLAGS_DEC32: - case FLAGS_INC8: - case FLAGS_INC16: - case FLAGS_INC32: - case FLAGS_UNKNOWN: - return cpu_state.flags & C_FLAG; - - default: - return 0; - } -} - -static __inline void flags_rebuild() -{ - if (cpu_state.flags_op != FLAGS_UNKNOWN) - { - uint16_t tempf = 0; - if (CF_SET()) tempf |= C_FLAG; - if (PF_SET()) tempf |= P_FLAG; - if (AF_SET()) tempf |= A_FLAG; - if (ZF_SET()) tempf |= Z_FLAG; - if (NF_SET()) tempf |= N_FLAG; - if (VF_SET()) tempf |= V_FLAG; - cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; - cpu_state.flags_op = FLAGS_UNKNOWN; - } -} - -static __inline void flags_extract() -{ - cpu_state.flags_op = FLAGS_UNKNOWN; -} - -static __inline void flags_rebuild_c() -{ - if (cpu_state.flags_op != FLAGS_UNKNOWN) - { - if (CF_SET()) - cpu_state.flags |= C_FLAG; - else - cpu_state.flags &= ~C_FLAG; - } -} - -static __inline void setznp8(uint8_t val) -{ - cpu_state.flags_op = FLAGS_ZN8; - cpu_state.flags_res = val; -} -static __inline void setznp16(uint16_t val) -{ - cpu_state.flags_op = FLAGS_ZN16; - cpu_state.flags_res = val; -} -static __inline void setznp32(uint32_t val) -{ - cpu_state.flags_op = FLAGS_ZN32; - cpu_state.flags_res = val; -} - -#define set_flags_shift(op, orig, shift, res) \ - cpu_state.flags_op = op; \ - cpu_state.flags_res = res; \ - cpu_state.flags_op1 = orig; \ - cpu_state.flags_op2 = shift; - -static __inline void setadd8(uint8_t a, uint8_t b) -{ - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a + b) & 0xff; - cpu_state.flags_op = FLAGS_ADD8; -} -static __inline void setadd16(uint16_t a, uint16_t b) -{ - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a + b) & 0xffff; - cpu_state.flags_op = FLAGS_ADD16; -} -static __inline void setadd32(uint32_t a, uint32_t b) -{ - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = a + b; - cpu_state.flags_op = FLAGS_ADD32; -} -static __inline void setadd8nc(uint8_t a, uint8_t b) -{ - flags_rebuild_c(); - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a + b) & 0xff; - cpu_state.flags_op = FLAGS_INC8; -} -static __inline void setadd16nc(uint16_t a, uint16_t b) -{ - flags_rebuild_c(); - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a + b) & 0xffff; - cpu_state.flags_op = FLAGS_INC16; -} -static __inline void setadd32nc(uint32_t a, uint32_t b) -{ - flags_rebuild_c(); - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = a + b; - cpu_state.flags_op = FLAGS_INC32; -} - -static __inline void setsub8(uint8_t a, uint8_t b) -{ - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a - b) & 0xff; - cpu_state.flags_op = FLAGS_SUB8; -} -static __inline void setsub16(uint16_t a, uint16_t b) -{ - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a - b) & 0xffff; - cpu_state.flags_op = FLAGS_SUB16; -} -static __inline void setsub32(uint32_t a, uint32_t b) -{ - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = a - b; - cpu_state.flags_op = FLAGS_SUB32; -} - -static __inline void setsub8nc(uint8_t a, uint8_t b) -{ - flags_rebuild_c(); - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a - b) & 0xff; - cpu_state.flags_op = FLAGS_DEC8; -} -static __inline void setsub16nc(uint16_t a, uint16_t b) -{ - flags_rebuild_c(); - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = (a - b) & 0xffff; - cpu_state.flags_op = FLAGS_DEC16; -} -static __inline void setsub32nc(uint32_t a, uint32_t b) -{ - flags_rebuild_c(); - cpu_state.flags_op1 = a; - cpu_state.flags_op2 = b; - cpu_state.flags_res = a - b; - cpu_state.flags_op = FLAGS_DEC32; -} - -static __inline void setadc8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a+(uint16_t)b+tempc; - cpu_state.flags_op = FLAGS_UNKNOWN; - cpu_state.flags&=~0x8D5; - cpu_state.flags|=znptable8[c&0xFF]; - if (c&0x100) cpu_state.flags|=C_FLAG; - if (!((a^b)&0x80)&&((a^c)&0x80)) cpu_state.flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; -} -static __inline void setadc16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b+tempc; - cpu_state.flags_op = FLAGS_UNKNOWN; - cpu_state.flags&=~0x8D5; - cpu_state.flags|=znptable16[c&0xFFFF]; - if (c&0x10000) cpu_state.flags|=C_FLAG; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) cpu_state.flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; -} -static __inline void setadc32(uint32_t a, uint32_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b+tempc; - cpu_state.flags_op = FLAGS_UNKNOWN; - cpu_state.flags&=~0x8D5; - cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); - cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); - if ((ca) || (c==a && tempc)) cpu_state.flags|=C_FLAG; - if ((a^b)&(a^c)&0x80000000) cpu_state.flags|=V_FLAG; - if (((a&0xF)-((b&0xF)+tempc))&0x10) cpu_state.flags|=A_FLAG; -} - -extern void cpu_386_flags_extract(); -extern void cpu_386_flags_rebuild(); \ No newline at end of file diff --git a/src/codegen/x86_ops_call.h b/src/codegen/x86_ops_call.h deleted file mode 100644 index 8c52e632e..000000000 --- a/src/codegen/x86_ops_call.h +++ /dev/null @@ -1,457 +0,0 @@ -#define CALL_FAR_w(new_seg, new_pc) \ - old_cs = CS; \ - old_pc = cpu_state.pc; \ - oxpc = cpu_state.pc; \ - cpu_state.pc = new_pc; \ - optype = CALL; \ - cgate16 = cgate32 = 0; \ - if (msw & 1) loadcscall(new_seg); \ - else \ - { \ - loadcs(new_seg); \ - cycles -= timing_call_rm; \ - } \ - optype = 0; \ - if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - oldss = ss; \ - if (cgate32) \ - { \ - uint32_t old_esp = ESP; \ - PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ - } \ - else \ - { \ - uint32_t old_esp = ESP; \ - PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ - } - -#define CALL_FAR_l(new_seg, new_pc) \ - old_cs = CS; \ - old_pc = cpu_state.pc; \ - oxpc = cpu_state.pc; \ - cpu_state.pc = new_pc; \ - optype = CALL; \ - cgate16 = cgate32 = 0; \ - if (msw & 1) loadcscall(new_seg); \ - else \ - { \ - loadcs(new_seg); \ - cycles -= timing_call_rm; \ - } \ - optype = 0; \ - if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - oldss = ss; \ - if (cgate16) \ - { \ - uint32_t old_esp = ESP; \ - PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ - } \ - else \ - { \ - uint32_t old_esp = ESP; \ - PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ - } - - -static int opCALL_far_w(uint32_t fetchdat) -{ - uint32_t old_cs, old_pc; - uint16_t new_cs, new_pc; - int cycles_old = cycles; UN_USED(cycles_old); - - new_pc = getwordf(); - new_cs = getword(); if (cpu_state.abrt) return 1; - - CALL_FAR_w(new_cs, new_pc); - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 5, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); - PREFETCH_FLUSH(); - - return 0; -} -static int opCALL_far_l(uint32_t fetchdat) -{ - uint32_t old_cs, old_pc; - uint32_t new_cs, new_pc; - int cycles_old = cycles; UN_USED(cycles_old); - - new_pc = getlong(); - new_cs = getword(); if (cpu_state.abrt) return 1; - - CALL_FAR_l(new_cs, new_pc); - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 7, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); - PREFETCH_FLUSH(); - - return 0; -} - - -static int opFF_w_a16(uint32_t fetchdat) -{ - uint16_t old_cs, new_cs; - uint32_t old_pc, new_pc; - int cycles_old = cycles; UN_USED(cycles_old); - - uint16_t temp; - - fetch_ea_16(fetchdat); - - switch (rmdat & 0x38) - { - case 0x00: /*INC w*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - seteaw(temp + 1); if (cpu_state.abrt) return 1; - setadd16nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); - break; - case 0x08: /*DEC w*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - seteaw(temp - 1); if (cpu_state.abrt) return 1; - setsub16nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); - break; - case 0x10: /*CALL*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteaw(); if (cpu_state.abrt) return 1; - PUSH_W(cpu_state.pc); - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); - PREFETCH_FLUSH(); - break; - case 0x18: /*CALL far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = readmemw(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; - - CALL_FAR_w(new_cs, new_pc); - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); - PREFETCH_FLUSH(); - break; - case 0x20: /*JMP*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteaw(); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); - PREFETCH_FLUSH(); - break; - case 0x28: /*JMP far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - oxpc = cpu_state.pc; - new_pc = readmemw(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 0); - PREFETCH_FLUSH(); - break; - case 0x30: /*PUSH w*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - PUSH_W(temp); - CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); - PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); - break; - - default: -// fatal("Bad FF opcode %02X\n",rmdat&0x38); - x86illegal(); - } - return cpu_state.abrt; -} -static int opFF_w_a32(uint32_t fetchdat) -{ - uint16_t old_cs, new_cs; - uint32_t old_pc, new_pc; - int cycles_old = cycles; UN_USED(cycles_old); - - uint16_t temp; - - fetch_ea_32(fetchdat); - - switch (rmdat & 0x38) - { - case 0x00: /*INC w*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - seteaw(temp + 1); if (cpu_state.abrt) return 1; - setadd16nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); - break; - case 0x08: /*DEC w*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - seteaw(temp - 1); if (cpu_state.abrt) return 1; - setsub16nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); - break; - case 0x10: /*CALL*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteaw(); if (cpu_state.abrt) return 1; - PUSH_W(cpu_state.pc); - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); - PREFETCH_FLUSH(); - break; - case 0x18: /*CALL far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = readmemw(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; - - CALL_FAR_w(new_cs, new_pc); - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 1); - PREFETCH_FLUSH(); - break; - case 0x20: /*JMP*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteaw(); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,0,0,0, 1); - PREFETCH_FLUSH(); - break; - case 0x28: /*JMP far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - oxpc = cpu_state.pc; - new_pc = readmemw(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 1); - PREFETCH_FLUSH(); - break; - case 0x30: /*PUSH w*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - PUSH_W(temp); - CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); - PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); - break; - - default: -// fatal("Bad FF opcode %02X\n",rmdat&0x38); - x86illegal(); - } - return cpu_state.abrt; -} - -static int opFF_l_a16(uint32_t fetchdat) -{ - uint16_t old_cs, new_cs; - uint32_t old_pc, new_pc; - int cycles_old = cycles; UN_USED(cycles_old); - - uint32_t temp; - - fetch_ea_16(fetchdat); - - switch (rmdat & 0x38) - { - case 0x00: /*INC l*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - seteal(temp + 1); if (cpu_state.abrt) return 1; - setadd32nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); - break; - case 0x08: /*DEC l*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - seteal(temp - 1); if (cpu_state.abrt) return 1; - setsub32nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); - break; - case 0x10: /*CALL*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteal(); if (cpu_state.abrt) return 1; - PUSH_L(cpu_state.pc); - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); - PREFETCH_FLUSH(); - break; - case 0x18: /*CALL far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = readmeml(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; - - CALL_FAR_l(new_cs, new_pc); - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 0); - PREFETCH_FLUSH(); - break; - case 0x20: /*JMP*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteal(); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 0,1,0,0, 0); - PREFETCH_FLUSH(); - break; - case 0x28: /*JMP far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - oxpc = cpu_state.pc; - new_pc = readmeml(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 0); - PREFETCH_FLUSH(); - break; - case 0x30: /*PUSH l*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - PUSH_L(temp); - CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); - PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); - break; - - default: -// fatal("Bad FF opcode %02X\n",rmdat&0x38); - x86illegal(); - } - return cpu_state.abrt; -} -static int opFF_l_a32(uint32_t fetchdat) -{ - uint16_t old_cs, new_cs; - uint32_t old_pc, new_pc; - int cycles_old = cycles; UN_USED(cycles_old); - - uint32_t temp; - - fetch_ea_32(fetchdat); - - switch (rmdat & 0x38) - { - case 0x00: /*INC l*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - seteal(temp + 1); if (cpu_state.abrt) return 1; - setadd32nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); - break; - case 0x08: /*DEC l*/ - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - seteal(temp - 1); if (cpu_state.abrt) return 1; - setsub32nc(temp, 1); - CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); - PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); - break; - case 0x10: /*CALL*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteal(); if (cpu_state.abrt) return 1; - PUSH_L(cpu_state.pc); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); - PREFETCH_FLUSH(); - break; - case 0x18: /*CALL far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = readmeml(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; - - CALL_FAR_l(new_cs, new_pc); - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 1); - PREFETCH_FLUSH(); - break; - case 0x20: /*JMP*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - new_pc = geteal(); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); - PREFETCH_FLUSH(); - break; - case 0x28: /*JMP far*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - oxpc = cpu_state.pc; - new_pc = readmeml(easeg, cpu_state.eaaddr); - new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; - CPU_BLOCK_END(); - PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); - PREFETCH_FLUSH(); - break; - case 0x30: /*PUSH l*/ - if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - PUSH_L(temp); - PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); - break; - - default: -// fatal("Bad FF opcode %02X\n",rmdat&0x38); - x86illegal(); - } - return cpu_state.abrt; -} diff --git a/src/codegen/x86seg.c b/src/codegen/x86seg.c deleted file mode 100644 index c903fbb79..000000000 --- a/src/codegen/x86seg.c +++ /dev/null @@ -1,2607 +0,0 @@ -/* - * 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. - * - * x86 CPU segment emulation. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include "cpu.h" -#include <86box/device.h> -#include <86box/timer.h> -#include <86box/machine.h> -#include <86box/mem.h> -#include <86box/nvr.h> -#include "x86.h" -#include "x86_flags.h" -#include "386_common.h" - - -/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ -#define CS_ACCESSED - -/*Controls whether the accessed bit in a descriptor is set when a data or stack - selector is loaded.*/ -#define SEL_ACCESSED -int stimes = 0; -int dtimes = 0; -int btimes = 0; - -uint32_t abrt_error; -int cgate16, cgate32; - -#define breaknullsegs 0 - -int intgatesize; - -void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); -void taskswitch386(uint16_t seg, uint16_t *segdat); - -void pmodeint(int num, int soft); -/*NOT PRESENT is INT 0B - GPF is INT 0D*/ - - -#ifdef ENABLE_X86SEG_LOG -int x86seg_do_log = ENABLE_X86SEG_LOG; - - -static void -x86seg_log(const char *fmt, ...) -{ - va_list ap; - - if (x86seg_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define x86seg_log(fmt, ...) -#endif - - -void x86abort(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - - nvr_save(); -#ifdef ENABLE_808X_LOG - dumpregs(1); -#endif - fflush(stdlog); - exit(-1); -} - -uint8_t opcode2; - -static void seg_reset(x86seg *s) -{ - s->access = (0 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->limit = 0xFFFF; - s->limit_low = 0; - s->limit_high = 0xffff; - if(s == &cpu_state.seg_cs) - { - // TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below. - s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; - // s->base = AT ? 0xF0000 : 0xFFFF0; - s->seg = AT ? 0xF000 : 0xFFFF; - } - else - { - s->base = 0; - s->seg = 0; - } - -} - -void x86seg_reset() -{ - seg_reset(&cpu_state.seg_cs); - seg_reset(&cpu_state.seg_ds); - seg_reset(&cpu_state.seg_es); - seg_reset(&cpu_state.seg_fs); - seg_reset(&cpu_state.seg_gs); - seg_reset(&cpu_state.seg_ss); -} - -void x86_doabrt(int x86_abrt) -{ - CS = oldcs; - cpu_state.pc = cpu_state.oldpc; - cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - - if (msw & 1) - pmodeint(x86_abrt, 0); - else - { - uint32_t addr = (x86_abrt << 2) + idt.base; - if (stack32) - { - writememw(ss,ESP-2,cpu_state.flags); - writememw(ss,ESP-4,CS); - writememw(ss,ESP-6,cpu_state.pc); - ESP-=6; - } - else - { - writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); - SP-=6; - } - - cpu_state.flags&=~I_FLAG; - cpu_state.flags&=~T_FLAG; - oxpc=cpu_state.pc; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - return; - } - - if (cpu_state.abrt || x86_was_reset) return; - - if (intgatesize == 16) - { - if (stack32) - { - writememw(ss, ESP-2, abrt_error); - ESP-=2; - } - else - { - writememw(ss, ((SP-2)&0xFFFF), abrt_error); - SP-=2; - } - } - else - { - if (stack32) - { - writememl(ss, ESP-4, abrt_error); - ESP-=4; - } - else - { - writememl(ss, ((SP-4)&0xFFFF), abrt_error); - SP-=4; - } - } -} -void x86gpf(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_GPF; - abrt_error = error; -} -void x86ss(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_SS; - abrt_error = error; -} -void x86ts(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_TS; - abrt_error = error; -} -void x86np(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_NP; - abrt_error = error; -} - - -static void set_stack32(int s) -{ - stack32 = s; - if (stack32) - cpu_cur_status |= CPU_STATUS_STACK32; - else - cpu_cur_status &= ~CPU_STATUS_STACK32; -} - -static void set_use32(int u) -{ - if (u) - { - use32 = 0x300; - cpu_cur_status |= CPU_STATUS_USE32; - } - else - { - use32 = 0; - cpu_cur_status &= ~CPU_STATUS_USE32; - } -} - -void do_seg_load(x86seg *s, uint16_t *segdat) -{ - s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); - if (segdat[3] & 0x80) - s->limit = (s->limit << 12) | 0xFFF; - s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); - if (is386) - s->base |= ((segdat[3] >> 8) << 24); - s->access = segdat[2] >> 8; - s->ar_high = segdat[3] & 0xff; - - if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ - { - s->limit_high = s->limit; - s->limit_low = 0; - } - else - { - s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; - s->limit_low = s->limit + 1; - } - - if (s == &cpu_state.seg_ds) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - } - if (s == &cpu_state.seg_ss) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - } -} - -static void do_seg_v86_init(x86seg *s) -{ - s->access = (3 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->limit = 0xffff; - s->limit_low = 0; - s->limit_high = 0xffff; -} - -static void check_seg_valid(x86seg *s) -{ - int dpl = (s->access >> 5) & 3; - int valid = 1; - - if (s->seg & 4) - { - if ((s->seg & ~7) >= ldt.limit) - { - valid = 0; - } - } - else - { - if ((s->seg & ~7) >= gdt.limit) - { - valid = 0; - } - } - - switch (s->access & 0x1f) - { - case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1A: case 0x1B: /*Readable non-conforming code*/ - if ((s->seg & 3) > dpl || (CPL) > dpl) - { - valid = 0; - break; - } - break; - - case 0x1E: case 0x1F: /*Readable conforming code*/ - break; - - default: - valid = 0; - break; - } - - if (!valid) - loadseg(0, s); -} - -void loadseg(uint16_t seg, x86seg *s) -{ - uint16_t segdat[4]; - uint32_t addr; - int dpl; - - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - if (s==&cpu_state.seg_ss) - { - x86ss(NULL,0); - return; - } - s->seg = 0; - s->access = 0x80; - s->ar_high = 0x10; - s->base=-1; - if (s == &cpu_state.seg_ds) - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - return; - } - addr=seg&~7; - if (seg&4) - { -#if 0 - if (addr>=ldt.limit) -#else - if ((addr+7)>ldt.limit) -#endif - { - x86gpf("loadseg(): Bigger than LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { -#if 0 - if (addr>=gdt.limit) -#else - if ((addr+7)>gdt.limit) -#endif - { - x86gpf("loadseg(): Bigger than GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - dpl=(segdat[2]>>13)&3; - if (s==&cpu_state.seg_ss) - { - if (!(seg&~3)) - { - x86gpf("loadseg(): Stack segment is zero",seg&~3); - return; - } - if ((seg&3)!=CPL) - { - x86gpf("loadseg(): Stack segment RPL != CPL",seg&~3); - return; - } - if (dpl!=CPL) - { - x86gpf("loadseg(): Stack segment DPL != CPL",seg&~3); - return; - } - switch ((segdat[2]>>8)&0x1F) - { - case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ - break; - default: - x86gpf("loadseg(): Unknown stack segment type",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86ss(NULL,seg&~3); - return; - } - set_stack32((segdat[3] & 0x40) ? 1 : 0); - } - else if (s!=&cpu_state.seg_cs) - { - x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); - x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); - switch ((segdat[2]>>8)&0x1F) - { - case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1A: case 0x1B: /*Readable non-conforming code*/ - if ((seg&3)>dpl) - { - x86gpf("loadseg(): Normal segment is zero",seg&~3); - return; - } - if ((CPL)>dpl) - { - x86gpf("loadseg(): Normal segment DPL < CPL",seg&~3); - return; - } - break; - case 0x1E: case 0x1F: /*Readable conforming code*/ - break; - default: - x86gpf("loadseg(): Unknown normal segment type",seg&~3); - return; - } - } - - if (!(segdat[2] & 0x8000)) - { - x86np("Load data seg not present", seg & 0xfffc); - return; - } - s->seg = seg; - do_seg_load(s, segdat); - -#ifndef CS_ACCESSED - if (s != &cpu_state.seg_cs) - { -#endif -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif -#ifndef CS_ACCESSED - } -#endif - s->checked = 0; -#ifdef USE_DYNAREC - if (s == &cpu_state.seg_ds) - codegen_flat_ds = 0; - if (s == &cpu_state.seg_ss) - codegen_flat_ss = 0; -#endif - } - else - { - s->access = (3 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->base = seg << 4; - s->seg = seg; - s->checked = 1; -#ifdef USE_DYNAREC - if (s == &cpu_state.seg_ds) - codegen_flat_ds = 0; - if (s == &cpu_state.seg_ss) - codegen_flat_ss = 0; -#endif - if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) - set_stack32(0); - } - - if (s == &cpu_state.seg_ds) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - } - if (s == &cpu_state.seg_ss) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - } -} - -#define DPL ((segdat[2]>>13)&3) -#define DPL2 ((segdat2[2]>>13)&3) -#define DPL3 ((segdat3[2]>>13)&3) - -void loadcs(uint16_t seg) -{ - uint16_t segdat[4]; - uint32_t addr; - x86seg_log("Load CS %04X\n",seg); - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcs(): Protected mode selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcs(): Protected mode selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - if (segdat[2]&0x1000) /*Normal code segment*/ - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcs(): Non-conforming RPL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcs(): Non-conforming CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcs(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS not present", seg & 0xfffc); - return; - } - set_use32(segdat[3] & 0x40); - CS=(seg&~3)|CPL; - do_seg_load(&cpu_state.seg_cs, segdat); - use32=(segdat[3]&0x40)?0x300:0; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - } - else /*System segment*/ - { - if (!(segdat[2]&0x8000)) - { - x86np("Load CS system seg not present", seg & 0xfffc); - return; - } - switch (segdat[2]&0xF00) - { - default: - x86gpf("Load CS system segment has bits 0-3 of access rights set",seg&~3); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg & 0xFFFF; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - } -} - -void loadcsjmp(uint16_t seg, uint32_t old_pc) -{ - uint16_t segdat[4]; - uint32_t addr; - uint16_t type,seg2; - uint32_t newpc; - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - x86gpf("loadcsjmp(): Selector is zero",0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("loacsjmp(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loacsjmp(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - x86seg_log("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); - if (segdat[2]&0x1000) /*Normal code segment*/ - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcsjmp(): CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcsjmp(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP not present\n", seg & 0xfffc); - return; - } - set_use32(segdat[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - CS = (seg & ~3) | CPL; - segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - cycles -= timing_jmp_pm; - } - else /*System segment*/ - { - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP system selector not present\n", seg & 0xfffc); - return; - } - type=segdat[2]&0xF00; - newpc=segdat[0]; - if (type&0x800) newpc|=segdat[3]<<16; - switch (type) - { - case 0x400: /*Call gate*/ - case 0xC00: - cgate32=(type&0x800); - cgate16=!cgate32; - oldcs=CS; - cpu_state.oldpc = cpu_state.pc; - if (DPL < CPL) - { - x86gpf("loadcsjmp(): Call gate DPL < CPL",seg&~3); - return; - } - if (DPL < (seg&3)) - { - x86gpf("loadcsjmp(): Call gate DPL< RPL",seg&~3); - return; - } - if (DPL < CPL) - { - x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); - return; - } - if ((DPL < (seg&3))) - { - x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP call gate not present\n", seg & 0xfffc); - return; - } - seg2=segdat[1]; - - if (!(seg2&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg2&~7; - if (seg2&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcsjmp(): Call gate selector > LDT limit",seg2&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcsjmp(): Call gate selector > GDT limit",seg2&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - - if (DPL > CPL) - { - x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); - return; - } - - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if (DPL > CPL) - { - x86gpf("loadcsjmp(): Non-conforming DPL > CPL",seg2&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - break; - - default: - x86gpf("loadcsjmp(): Unknown type",seg2&~3); - return; - } - cycles -= timing_jmp_pm_gate; - break; - - - case 0x100: /*286 Task gate*/ - case 0x900: /*386 Task gate*/ - cpu_state.pc=old_pc; - optype=JMP; - cpl_override=1; - taskswitch286(seg,segdat,segdat[2]&0x800); - cpu_state.flags &= ~NT_FLAG; - cpl_override=0; - return; - - default: - x86gpf(NULL,0); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - cycles -= timing_jmp_rm; - } -} - -void PUSHW(uint16_t v) -{ - if (stack32) - { - writememw(ss,ESP-2,v); - if (cpu_state.abrt) return; - ESP-=2; - } - else - { - writememw(ss,((SP-2)&0xFFFF),v); - if (cpu_state.abrt) return; - SP-=2; - } -} -void PUSHL(uint32_t v) -{ - if (stack32) - { - writememl(ss,ESP-4,v); - if (cpu_state.abrt) return; - ESP-=4; - } - else - { - writememl(ss,((SP-4)&0xFFFF),v); - if (cpu_state.abrt) return; - SP-=4; - } -} -uint16_t POPW() -{ - uint16_t tempw; - if (stack32) - { - tempw=readmemw(ss,ESP); - if (cpu_state.abrt) return 0; - ESP+=2; - } - else - { - tempw=readmemw(ss,SP); - if (cpu_state.abrt) return 0; - SP+=2; - } - return tempw; -} -uint32_t POPL() -{ - uint32_t templ; - if (stack32) - { - templ=readmeml(ss,ESP); - if (cpu_state.abrt) return 0; - ESP+=4; - } - else - { - templ=readmeml(ss,SP); - if (cpu_state.abrt) return 0; - SP+=4; - } - return templ; -} - -void loadcscall(uint16_t seg) -{ - uint16_t seg2; - uint16_t segdat[4],segdat2[4],newss; - uint32_t addr,oldssbase=ss, oaddr; - uint32_t newpc; - int count; - uint32_t oldss,oldsp,newsp, oldsp2; - int type; - uint16_t tempw; - - int csout = output; - - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); - if (!(seg&~3)) - { - x86gpf("loadcscall(): Protected mode selector is zero",0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcscall(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcscall(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - type=segdat[2]&0xF00; - newpc=segdat[0]; - if (type&0x800) newpc|=segdat[3]<<16; - - if (csout) x86seg_log("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); - if (segdat[2]&0x1000) - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcscall(): Non-conforming RPL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcscall(): Non-conforming CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcscall(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS call not present", seg & 0xfffc); - return; - } - set_use32(segdat[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - /*Conforming segments don't change CPL, so preserve existing CPL*/ - if (segdat[2]&0x400) - { - seg = (seg & ~3) | CPL; - segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - } - else /*On non-conforming segments, set RPL = CPL*/ - seg = (seg & ~3) | CPL; - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - - if (csout) x86seg_log("Complete\n"); - cycles -= timing_call_pm; - } - else - { - type=segdat[2]&0xF00; - if (csout) x86seg_log("Type %03X\n",type); - switch (type) - { - case 0x400: /*Call gate*/ - case 0xC00: /*386 Call gate*/ - x86seg_log("Callgate %08X\n", cpu_state.pc); - cgate32=(type&0x800); - cgate16=!cgate32; - oldcs=CS; - count=segdat[2]&31; - if (DPL < CPL) - { - x86gpf("loadcscall(): ex DPL < CPL",seg&~3); - return; - } - if ((DPL < (seg&3))) - { - x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86seg_log("Call gate not present %04X\n",seg); - x86np("Call gate not present\n", seg & 0xfffc); - return; - } - seg2=segdat[1]; - - x86seg_log("New address : %04X:%08X\n", seg2, newpc); - - if (!(seg2&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg2&~7; - if (seg2&4) - { - if (addr>=ldt.limit) - { - x86gpf("loadcscall(): ex Selector > LDT limit",seg2&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("loadcscall(): ex Selector > GDT limit",seg2&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - - x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); - - if (DPL > CPL) - { - x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86seg_log("Call gate CS not present %04X\n",seg2); - x86np("Call gate CS not present", seg2 & 0xfffc); - return; - } - - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if (DPL < CPL) - { - oaddr = addr; - /*Load new stack*/ - oldss=SS; - oldsp=oldsp2=ESP; - cpl_override=1; - if (tr.access&8) - { - addr = 4 + tr.base + (DPL * 8); - newss=readmemw(0,addr+4); - newsp=readmeml(0,addr); - } - else - { - addr = 2 + tr.base + (DPL * 4); - newss=readmemw(0,addr+2); - newsp=readmemw(0,addr); - } - cpl_override=0; - if (cpu_state.abrt) return; - x86seg_log("New stack %04X:%08X\n",newss,newsp); - if (!(newss&~3)) - { - x86ts(NULL,newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { -#if 0 - if (addr>=ldt.limit) -#else - if ((addr+7)>ldt.limit) -#endif - { - x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); - x86ts(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { -#if 0 - if (addr>=gdt.limit) -#else - if ((addr+7)>gdt.limit) -#endif - { - x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); - x86ts(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - x86seg_log("Read stack seg\n"); - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - x86seg_log("Read stack seg done!\n"); - if (((newss & 3) != DPL) || (DPL2 != DPL)) - { - x86ts(NULL,newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - x86ts(NULL,newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - x86ss("Call gate loading SS not present\n", newss & 0xfffc); - return; - } - if (!stack32) oldsp &= 0xFFFF; - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - - do_seg_load(&cpu_state.seg_ss, segdat2); - - x86seg_log("Set access 1\n"); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; - - x86seg_log("Set access 2\n"); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - x86seg_log("Type %04X\n",type); - if (type==0xC00) - { - PUSHL(oldss); - PUSHL(oldsp2); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - return; - } - if (count) - { - while (count) - { - count--; - PUSHL(readmeml(oldssbase,oldsp+(count*4))); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - return; - } - } - } - } - else - { - x86seg_log("Stack %04X\n",SP); - PUSHW(oldss); - x86seg_log("Write SS to %04X:%04X\n",SS,SP); - PUSHW(oldsp2); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - return; - } - x86seg_log("Write SP to %04X:%04X\n",SS,SP); - if (count) - { - while (count) - { - count--; - tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); - x86seg_log("PUSH %04X\n",tempw); - PUSHW(tempw); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - return; - } - } - } - } - cycles -= timing_call_pm_gate_inner; - break; - } - else if (DPL > CPL) - { - x86gpf("loadcscall(): Call PM Gate Inner DPL > CPL",seg2&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - cycles -= timing_call_pm_gate; - break; - - default: - x86gpf("loadcscall(): Unknown subtype",seg2&~3); - return; - } - break; - - case 0x100: /*286 Task gate*/ - case 0x900: /*386 Task gate*/ - cpu_state.pc=oxpc; - cpl_override=1; - taskswitch286(seg,segdat,segdat[2]&0x800); - cpl_override=0; - break; - - default: - x86gpf("loadcscall(): Unknown type",seg&~3); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - } -} - -void pmoderetf(int is32, uint16_t off) -{ - uint32_t newpc; - uint32_t newsp; - uint32_t addr, oaddr; - uint16_t segdat[4],segdat2[4],seg,newss; - uint32_t oldsp=ESP; - x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); - if (is32) - { - newpc=POPL(); - seg=POPL(); if (cpu_state.abrt) return; - } - else - { - x86seg_log("PC read from %04X:%04X\n",SS,SP); - newpc=POPW(); - x86seg_log("CS read from %04X:%04X\n",SS,SP); - seg=POPW(); if (cpu_state.abrt) return; - } - x86seg_log("Return to %04X:%08X\n",seg,newpc); - if ((seg&3)=ldt.limit) - { - x86gpf("pmoderetf(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("pmoderetf(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } - oaddr = addr; - - x86seg_log("CPL %i RPL %i %i\n",CPL,seg&3,is32); - - if (stack32) ESP+=off; - else SP+=off; - - if (CPL==(seg&3)) - { - x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if (CPL != DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Non-conforming CPL != DPL",seg&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if (CPL < DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Conforming CPL < DPL",seg&~3); - return; - } - break; - default: - x86gpf("pmoderetf(): Unknown type",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF CS not present\n", seg & 0xfffc); - return; - } - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - cpu_state.pc=newpc; - if (segdat[2] & 0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - CS = seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(segdat[3] & 0x40); - - cycles -= timing_retf_pm; - } - else - { - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((seg&3) != DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Non-conforming RPL != DPL",seg&~3); - return; - } - x86seg_log("RETF non-conforming, %i %i\n",seg&3, DPL); - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((seg&3) < DPL) - { - ESP=oldsp; - x86gpf("pmoderetf(): Conforming RPL < DPL",seg&~3); - return; - } - x86seg_log("RETF conforming, %i %i\n",seg&3, DPL); - break; - default: - ESP=oldsp; - x86gpf("pmoderetf(): Unknown type",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF CS not present\n", seg & 0xfffc); - return; - } - if (is32) - { - newsp=POPL(); - newss=POPL(); if (cpu_state.abrt) return; - } - else - { - x86seg_log("SP read from %04X:%04X\n",SS,SP); - newsp=POPW(); - x86seg_log("SS read from %04X:%04X\n",SS,SP); - newss=POPW(); if (cpu_state.abrt) return; - } - x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); - if (!(newss&~3)) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS selector is zero",newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if (addr>=ldt.limit) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS selector > LDT limit",newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS selector > GDT limit",newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } - x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); - if ((newss & 3) != (seg & 3)) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS RPL > CS RPL",newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS unknown type",newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF loading SS not present\n", newss & 0xfffc); - return; - } - if (DPL2 != (seg & 3)) - { - ESP=oldsp; - x86gpf("pmoderetf(): New SS DPL != CS RPL",newss&~3); - return; - } - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - -#ifdef CS_ACCESSED - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ -#endif - cpl_override = 0; -#endif - /*Conforming segments don't change CPL, so CPL = RPL*/ - if (segdat[2]&0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - - cpu_state.pc=newpc; - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(segdat[3] & 0x40); - - if (stack32) ESP+=off; - else SP+=off; - - check_seg_valid(&cpu_state.seg_ds); - check_seg_valid(&cpu_state.seg_es); - check_seg_valid(&cpu_state.seg_fs); - check_seg_valid(&cpu_state.seg_gs); - cycles -= timing_retf_pm_outer; - } -} - -void restore_stack() -{ - ss=oldss; cpu_state.seg_ss.limit=oldsslimit; -} - -void pmodeint(int num, int soft) -{ - uint16_t segdat[4],segdat2[4],segdat3[4]; - uint32_t addr, oaddr; - uint16_t newss; - uint32_t oldss,oldsp; - int type; - uint32_t newsp; - uint16_t seg = 0; - int new_cpl; - - if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) - { - x86seg_log("V86 banned int\n"); - x86gpf("pmodeint(): V86 banned int",0); - return; - } - addr=(num<<3); - if (addr>=idt.limit) - { - if (num==8) - { - /*Triple fault - reset!*/ - softresetx86(); - cpu_set_edx(); - } - else if (num==0xD) - { - pmodeint(8,0); - } - else - { - x86gpf("pmodeint(): Vector > IDT limit",(num*8)+2+((soft)?0:1)); - } - x86seg_log("addr >= IDT.limit\n"); - return; - } - addr+=idt.base; - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(2,addr); - segdat[2]=readmemw(4,addr); - segdat[3]=readmemw(6,addr); cpl_override=0; if (cpu_state.abrt) { /* x86seg_log("Abrt reading from %08X\n",addr); */ return; } - oaddr = addr; - - x86seg_log("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); - if (!(segdat[2]&0x1F00)) - { - x86gpf("pmodeint(): Vector descriptor with bad type",(num*8)+2); - return; - } - if (DPL=0x800)?32:16; - if (!(segdat[2]&0x8000)) - { - x86np("Int gate not present\n", (num << 3) | 2); - return; - } - seg=segdat[1]; - new_cpl = seg & 3; - - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("pmodeint(): Interrupt or trap gate selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("pmodeint(): Interrupt or trap gate selector > GDT limit", seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - oaddr = addr; - - if (DPL2 > CPL) - { - x86gpf("pmodeint(): Interrupt or trap gate DPL > CPL",seg&~3); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if (DPL2=ldt.limit) - { - x86ss(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ss(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat3[0]=readmemw(0,addr); - segdat3[1]=readmemw(0,addr+2); - segdat3[2]=readmemw(0,addr+4); - segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - if (((newss & 3) != DPL2) || (DPL3 != DPL2)) - { - x86ss(NULL,newss&~3); - return; - } - if ((segdat3[2]&0x1A00)!=0x1200) - { - x86ss(NULL,newss&~3); - return; - } - if (!(segdat3[2]&0x8000)) - { - x86np("Int gate loading SS not present\n", newss & 0xfffc); - return; - } - SS=newss; - set_stack32((segdat3[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat3); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - x86seg_log("New stack %04X:%08X\n",SS,ESP); - cpl_override=1; - if (type>=0x800) - { - if (cpu_state.eflags & VM_FLAG) - { - PUSHL(GS); - PUSHL(FS); - PUSHL(DS); - PUSHL(ES); if (cpu_state.abrt) return; - loadseg(0,&cpu_state.seg_ds); - loadseg(0,&cpu_state.seg_es); - loadseg(0,&cpu_state.seg_fs); - loadseg(0,&cpu_state.seg_gs); - } - PUSHL(oldss); - PUSHL(oldsp); - PUSHL(cpu_state.flags|(cpu_state.eflags<<16)); - PUSHL(CS); - PUSHL(cpu_state.pc); if (cpu_state.abrt) return; - } - else - { - PUSHW(oldss); - PUSHW(oldsp); - PUSHW(cpu_state.flags); - PUSHW(CS); - PUSHW(cpu_state.pc); if (cpu_state.abrt) return; - } - cpl_override=0; - cpu_state.seg_cs.access=0 | 0x80; - cycles -= timing_int_pm_outer - timing_int_pm; - break; - } - else if (DPL2!=CPL) - { - x86gpf("pmodeint(): DPL != CPL",seg&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if (!(segdat2[2]&0x8000)) - { - x86np("Int gate CS not present\n", segdat[1] & 0xfffc); - return; - } - if ((cpu_state.eflags & VM_FLAG) && DPL20x800) - { - PUSHL(cpu_state.flags|(cpu_state.eflags<<16)); - PUSHL(CS); - PUSHL(cpu_state.pc); if (cpu_state.abrt) return; - } - else - { - PUSHW(cpu_state.flags); - PUSHW(CS); - PUSHW(cpu_state.pc); if (cpu_state.abrt) return; - } - new_cpl = CS & 3; - break; - default: - x86gpf("pmodeint(): Unknown type",seg&~3); - return; - } - do_seg_load(&cpu_state.seg_cs, segdat2); - CS = (seg & ~3) | new_cpl; - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); - else cpu_state.pc=segdat[0]; - set_use32(segdat2[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - cpu_state.eflags&=~VM_FLAG; - cpu_cur_status &= ~CPU_STATUS_V86; - if (!(type&0x100)) - { - cpu_state.flags&=~I_FLAG; - } - cpu_state.flags&=~(T_FLAG|NT_FLAG); - cycles -= timing_int_pm; - break; - - case 0x500: /*Task gate*/ - seg=segdat[1]; - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf("pmodeint(): Task gate selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf("pmodeint(): Task gate selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - cpl_override=0; if (cpu_state.abrt) return; - if (!(segdat2[2]&0x8000)) - { - x86np("Int task gate not present\n", segdat[1] & 0xfffc); - return; - } - optype=OPTYPE_INT; - cpl_override=1; - taskswitch286(seg,segdat2,segdat2[2]&0x800); - cpl_override=0; - break; - - default: - x86gpf(NULL,seg&~3); - return; - } -} - -void pmodeiret(int is32) -{ - uint32_t newsp; - uint16_t newss; - uint32_t tempflags,flagmask; - uint32_t newpc; - uint16_t segdat[4],segdat2[4]; - uint16_t segs[4]; - uint16_t seg; - uint32_t addr, oaddr; - uint32_t oldsp=ESP; - if (is386 && (cpu_state.eflags&VM_FLAG)) - { - if (IOPL!=3) - { - x86gpf(NULL,0); - return; - } - oxpc=cpu_state.pc; - if (is32) - { - newpc=POPL(); - seg=POPL(); - tempflags=POPL(); if (cpu_state.abrt) return; - } - else - { - newpc=POPW(); - seg=POPW(); - tempflags=POPW(); if (cpu_state.abrt) return; - } - cpu_state.pc = newpc; - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - cpu_state.seg_cs.access |= 0x80; - cpu_state.seg_cs.ar_high = 0x10; - CS=seg; - cpu_state.flags=(cpu_state.flags&0x3000)|(tempflags&0xCFD5)|2; - cycles -= timing_iret_rm; - return; - } - - if (cpu_state.flags&NT_FLAG) - { - seg=readmemw(tr.base,0); - addr=seg&~7; - if (seg&4) - { - x86seg_log("TS LDT %04X %04X IRET\n",seg,gdt.limit); - x86ts("pmodeiret(): Selector points to LDT",seg&~3); - return; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); - taskswitch286(seg,segdat,segdat[2] & 0x800); - cpl_override=0; - return; - } - oxpc=cpu_state.pc; - flagmask=0xFFFF; - if (CPL) flagmask&=~0x3000; - if (IOPL>16)&VM_FLAG)) - { - newsp=POPL(); - newss=POPL(); - segs[0]=POPL(); - segs[1]=POPL(); - segs[2]=POPL(); - segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } - cpu_state.eflags=tempflags>>16; - cpu_cur_status |= CPU_STATUS_V86; - loadseg(segs[0],&cpu_state.seg_es); - do_seg_v86_init(&cpu_state.seg_es); - loadseg(segs[1],&cpu_state.seg_ds); - do_seg_v86_init(&cpu_state.seg_ds); - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - loadseg(segs[2],&cpu_state.seg_fs); - do_seg_v86_init(&cpu_state.seg_fs); - loadseg(segs[3],&cpu_state.seg_gs); - do_seg_v86_init(&cpu_state.seg_gs); - - cpu_state.pc=newpc; - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high=0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - - ESP=newsp; - loadseg(newss,&cpu_state.seg_ss); - do_seg_v86_init(&cpu_state.seg_ss); - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - use32=0; - cpu_cur_status &= ~CPU_STATUS_USE32; - cpu_state.flags=(tempflags&0xFFD5)|2; - cycles -= timing_iret_v86; - return; - } - } - else - { - newpc=POPW(); - seg=POPW(); - tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - if (!(seg&~3)) - { - ESP = oldsp; - x86gpf(NULL,0); - return; - } - - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): Selector > LDT limit",seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): Selector > GDT limit",seg&~3); - return; - } - addr+=gdt.base; - } - if ((seg&3) < CPL) - { - ESP = oldsp; - x86gpf("pmodeiret(): RPL < CPL",seg&~3); - return; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if ((seg&3) != DPL) - { - ESP = oldsp; - x86gpf("pmodeiret(): Non-conforming RPL != DPL",seg&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ - if ((seg&3) < DPL) - { - ESP = oldsp; - x86gpf("pmodeiret(): Conforming RPL < DPL",seg&~3); - return; - } - break; - default: - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP = oldsp; - x86np("IRET CS not present\n", seg & 0xfffc); - return; - } - if ((seg&3) == CPL) - { - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(segdat[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - cycles -= timing_iret_pm; - } - else /*Return to outer level*/ - { - oaddr = addr; - x86seg_log("Outer level\n"); - if (is32) - { - newsp=POPL(); - newss=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - else - { - newsp=POPW(); - newss=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - - x86seg_log("IRET load stack %04X:%04X\n",newss,newsp); - - if (!(newss&~3)) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS selector is zero",newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if (addr>=ldt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS selector > LDT limit",newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS selector > GDT limit",newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } - if ((newss & 3) != (seg & 3)) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS RPL > CS RPL",newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS bad type",newss&~3); - return; - } - if (DPL2 != (seg & 3)) - { - ESP = oldsp; - x86gpf("pmodeiret(): New SS DPL != CS RPL",newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - ESP = oldsp; - x86np("IRET loading SS not present\n", newss & 0xfffc); - return; - } - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - -#ifdef CS_ACCESSED - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ -#endif - cpl_override = 0; -#endif - /*Conforming segments don't change CPL, so CPL = RPL*/ - if (segdat[2]&0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(segdat[3] & 0x40); - - check_seg_valid(&cpu_state.seg_ds); - check_seg_valid(&cpu_state.seg_es); - check_seg_valid(&cpu_state.seg_fs); - check_seg_valid(&cpu_state.seg_gs); - cycles -= timing_iret_pm_outer; - } - cpu_state.pc=newpc; - cpu_state.flags=(cpu_state.flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; - if (is32) cpu_state.eflags=tempflags>>16; -} - -void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) -{ - uint32_t base; - uint32_t limit; - uint32_t templ; - uint16_t tempw; - - uint32_t new_cr3=0; - uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; - uint16_t new_ldt; - - uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; - - uint32_t addr; - - uint16_t segdat2[4]; - - base=segdat[1]|((segdat[2]&0xFF)<<16); - limit=segdat[0]; - if(is386) - { - base |= (segdat[3]>>8)<<24; - limit |= (segdat[3]&0xF)<<16; - } - - if (is32) - { - if (limit < 103) - { - x86ts(NULL, seg); - return; - } - - if (optype==JMP || optype==CALL || optype==OPTYPE_INT) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==IRET) cpu_state.flags&=~NT_FLAG; - - cpu_386_flags_rebuild(); - writememl(tr.base,0x1C,cr3); - writememl(tr.base,0x20,cpu_state.pc); - writememl(tr.base,0x24,cpu_state.flags|(cpu_state.eflags<<16)); - - writememl(tr.base,0x28,EAX); - writememl(tr.base,0x2C,ECX); - writememl(tr.base,0x30,EDX); - writememl(tr.base,0x34,EBX); - writememl(tr.base,0x38,ESP); - writememl(tr.base,0x3C,EBP); - writememl(tr.base,0x40,ESI); - writememl(tr.base,0x44,EDI); - - writememl(tr.base,0x48,ES); - writememl(tr.base,0x4C,CS); - writememl(tr.base,0x50,SS); - writememl(tr.base,0x54,DS); - writememl(tr.base,0x58,FS); - writememl(tr.base,0x5C,GS); - - if (optype==JMP || optype==IRET) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.abrt) return; - tempw&=~0x200; - if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); - else writememw(gdt.base,(tr.seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==OPTYPE_INT || optype==CALL) - { - writememl(base,0,tr.seg); - if (cpu_state.abrt) - return; - } - - - new_cr3=readmeml(base,0x1C); - new_pc=readmeml(base,0x20); - new_flags=readmeml(base,0x24); - if (optype == OPTYPE_INT || optype == CALL) - new_flags |= NT_FLAG; - - new_eax=readmeml(base,0x28); - new_ecx=readmeml(base,0x2C); - new_edx=readmeml(base,0x30); - new_ebx=readmeml(base,0x34); - new_esp=readmeml(base,0x38); - new_ebp=readmeml(base,0x3C); - new_esi=readmeml(base,0x40); - new_edi=readmeml(base,0x44); - - new_es=readmemw(base,0x48); - new_cs=readmemw(base,0x4C); - new_ss=readmemw(base,0x50); - new_ds=readmemw(base,0x54); - new_fs=readmemw(base,0x58); - new_gs=readmemw(base,0x5C); - new_ldt=readmemw(base,0x60); - - cr0 |= 8; - - cr3=new_cr3; - flushmmucache(); - - cpu_state.pc=new_pc; - cpu_state.flags=new_flags; - cpu_state.eflags=new_flags>>16; - cpu_386_flags_extract(); - - ldt.seg=new_ldt; - templ=(ldt.seg&~7)+gdt.base; - ldt.limit=readmemw(0,templ); - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); - - if (cpu_state.eflags & VM_FLAG) - { - loadcs(new_cs); - set_use32(0); - cpu_cur_status |= CPU_STATUS_V86; - } - else - { - if (!(new_cs&~3)) - { - x86ts(NULL,0); - return; - } - addr=new_cs&~7; - if (new_cs&4) - { - if (addr>=ldt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=gdt.base; - } - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - if (!(segdat2[2]&0x8000)) - { - x86np("TS loading CS not present\n", new_cs & 0xfffc); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((new_cs&3) != DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((new_cs&3) < DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - default: - x86ts(NULL,new_cs&~3); - return; - } - - CS=new_cs; - do_seg_load(&cpu_state.seg_cs, segdat2); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(segdat2[3] & 0x40); - cpu_cur_status &= ~CPU_STATUS_V86; - } - - EAX=new_eax; - ECX=new_ecx; - EDX=new_edx; - EBX=new_ebx; - ESP=new_esp; - EBP=new_ebp; - ESI=new_esi; - EDI=new_edi; - - loadseg(new_es,&cpu_state.seg_es); - loadseg(new_ss,&cpu_state.seg_ss); - loadseg(new_ds,&cpu_state.seg_ds); - loadseg(new_fs,&cpu_state.seg_fs); - loadseg(new_gs,&cpu_state.seg_gs); - } - else - { - if (limit < 43) - { - x86ts(NULL, seg); - return; - } - - if (optype==JMP || optype==CALL || optype==OPTYPE_INT) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==IRET) cpu_state.flags&=~NT_FLAG; - - cpu_386_flags_rebuild(); - writememw(tr.base,0x0E,cpu_state.pc); - writememw(tr.base,0x10,cpu_state.flags); - - writememw(tr.base,0x12,AX); - writememw(tr.base,0x14,CX); - writememw(tr.base,0x16,DX); - writememw(tr.base,0x18,BX); - writememw(tr.base,0x1A,SP); - writememw(tr.base,0x1C,BP); - writememw(tr.base,0x1E,SI); - writememw(tr.base,0x20,DI); - - writememw(tr.base,0x22,ES); - writememw(tr.base,0x24,CS); - writememw(tr.base,0x26,SS); - writememw(tr.base,0x28,DS); - - if (optype==JMP || optype==IRET) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.abrt) return; - tempw&=~0x200; - if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); - else writememw(gdt.base,(tr.seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==OPTYPE_INT || optype==CALL) - { - writememw(base,0,tr.seg); - if (cpu_state.abrt) - return; - } - - new_pc=readmemw(base,0x0E); - new_flags=readmemw(base,0x10); - if (optype == OPTYPE_INT || optype == CALL) - new_flags |= NT_FLAG; - - new_eax=readmemw(base,0x12); - new_ecx=readmemw(base,0x14); - new_edx=readmemw(base,0x16); - new_ebx=readmemw(base,0x18); - new_esp=readmemw(base,0x1A); - new_ebp=readmemw(base,0x1C); - new_esi=readmemw(base,0x1E); - new_edi=readmemw(base,0x20); - - new_es=readmemw(base,0x22); - new_cs=readmemw(base,0x24); - new_ss=readmemw(base,0x26); - new_ds=readmemw(base,0x28); - new_ldt=readmemw(base,0x2A); - - msw |= 8; - - cpu_state.pc=new_pc; - cpu_state.flags=new_flags; - cpu_386_flags_extract(); - - ldt.seg=new_ldt; - templ=(ldt.seg&~7)+gdt.base; - ldt.limit=readmemw(0,templ); - ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); - if (is386) - { - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base|=(readmemb(0,templ+7)<<24); - } - - if (!(new_cs&~3)) - { - x86ts(NULL,0); - return; - } - addr=new_cs&~7; - if (new_cs&4) - { - if (addr>=ldt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=gdt.base; - } - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - if (!(segdat2[2]&0x8000)) - { - x86np("TS loading CS not present\n", new_cs & 0xfffc); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((new_cs&3) != DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((new_cs&3) < DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - default: - x86ts(NULL,new_cs&~3); - return; - } - - CS=new_cs; - do_seg_load(&cpu_state.seg_cs, segdat2); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - set_use32(0); - - EAX=new_eax | 0xFFFF0000; - ECX=new_ecx | 0xFFFF0000; - EDX=new_edx | 0xFFFF0000; - EBX=new_ebx | 0xFFFF0000; - ESP=new_esp | 0xFFFF0000; - EBP=new_ebp | 0xFFFF0000; - ESI=new_esi | 0xFFFF0000; - EDI=new_edi | 0xFFFF0000; - - loadseg(new_es,&cpu_state.seg_es); - loadseg(new_ss,&cpu_state.seg_ss); - loadseg(new_ds,&cpu_state.seg_ds); - if (is386) - { - loadseg(0,&cpu_state.seg_fs); - loadseg(0,&cpu_state.seg_gs); - } - } - - tr.seg=seg; - tr.base=base; - tr.limit=limit; - tr.access=segdat[2]>>8; - tr.ar_high = segdat[3] & 0xff; -} diff --git a/src/codegen_new/CMakeLists.txt b/src/codegen_new/CMakeLists.txt new file mode 100644 index 000000000..a96d0b57e --- /dev/null +++ b/src/codegen_new/CMakeLists.txt @@ -0,0 +1,51 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +if(DYNAREC) + add_library(dynarec OBJECT codegen.c codegen_accumulate.c + codegen_allocator.c codegen_block.c codegen_ir.c codegen_ops.c + codegen_ops_3dnow.c codegen_ops_branch.c codegen_ops_arith.c + codegen_ops_fpu_arith.c codegen_ops_fpu_constant.c + codegen_ops_fpu_loadstore.c codegen_ops_fpu_misc.c + codegen_ops_helpers.c codegen_ops_jump.c codegen_ops_logic.c + codegen_ops_misc.c codegen_ops_mmx_arith.c codegen_ops_mmx_cmp.c + codegen_ops_mmx_loadstore.c codegen_ops_mmx_logic.c + codegen_ops_mmx_pack.c codegen_ops_mmx_shift.c codegen_ops_mov.c + codegen_ops_shift.c codegen_ops_stack.c codegen_reg.c) + + if(ARCH STREQUAL "i386") + target_sources(dynarec PRIVATE codegen_backend_x86.c + codegen_backend_x86_ops.c codegen_backend_x86_ops_fpu.c + codegen_backend_x86_ops_sse.c + codegen_backend_x86_uops.c) + elseif(ARCH STREQUAL "x86_64") + target_sources(dynarec PRIVATE codegen_backend_x86-64.c + codegen_backend_x86-64_ops.c + codegen_backend_x86-64_ops_sse.c + codegen_backend_x86-64_uops.c) + elseif(ARCH STREQUAL "arm64") + target_sources(dynarec PRIVATE codegen_backend_arm64.c + codegen_backend_arm64_ops.c codegen_backend_arm64_uops.c + codegen_backend_arm64_imm.c) + elseif(ARCH STREQUAL "arm") + target_sources(dynarec PRIVATE codegen_backend_arm.c + codegen_backend_arm_ops.c codegen_backend_arm_uops.c) + else() + message(SEND_ERROR + "Dynarec is incompatible with target platform ${ARCH}") + endif() + + target_link_libraries(86Box dynarec cgt) +endif() diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index f385fb448..ef928dd51 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -31,8 +31,8 @@ static struct int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_instruction, int *TOP) { int c; - - for (c = 0; c < block->ins; c++) + + for (c = 0; c <= block->ins; c++) { if (codegen_instructions[c].pc == pc) { @@ -41,7 +41,7 @@ int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_inst return codegen_instructions[c].first_uop; } } - + *first_instruction = block->ins; return -1; } @@ -139,7 +139,7 @@ static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uin switch (cpu_rm & 7) { - case 0: case 1: case 7: + case 0: case 1: case 7: default: base_reg = IREG_EBX; break; case 2: case 3: case 6: @@ -185,7 +185,7 @@ static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uin op_ea_seg = &cpu_state.seg_ss; } } - + codegen_mark_code_present(ir->block, cs+old_pc, ((*op_pc)+1)-old_pc); return op_ea_seg; } @@ -290,7 +290,7 @@ static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uin uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); extra_bytes = 4; } - + (*op_pc) += 4; } else @@ -327,7 +327,7 @@ static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uin if (extra_bytes) codegen_mark_code_present(ir->block, cs+old_pc, extra_bytes); - + return op_ea_seg; } @@ -372,7 +372,7 @@ static uint8_t opcode_0f_modrm[256] = 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ @@ -599,8 +599,7 @@ generate_call: codegen_timing_opcode(opcode, fetchdat, op_32, op_pc); - codegen_accumulate(ACCREG_ins, 1); - codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); + codegen_accumulate(ir, ACCREG_cycles, -codegen_block_cycles); codegen_block_cycles = 0; if ((op_table == x86_dynarec_opcodes && @@ -618,12 +617,12 @@ generate_call: if (codegen_timing_jump_cycles) codegen_timing_jump_cycles(); - + if (jump_cycles) - codegen_accumulate(ACCREG_cycles, -jump_cycles); + codegen_accumulate(ir, ACCREG_cycles, -jump_cycles); codegen_accumulate_flush(ir); if (jump_cycles) - codegen_accumulate(ACCREG_cycles, jump_cycles); + codegen_accumulate(ir, ACCREG_cycles, jump_cycles); } if (op_table == x86_dynarec_opcodes_0f && opcode == 0x0f) @@ -674,7 +673,7 @@ generate_call: if (recomp_opcodes_3DNOW[opcode_3dnow]) { next_pc = opcode_pc + 1; - + op_table = (OpFn *) x86_dynarec_opcodes_3DNOW; recomp_op_table = recomp_opcodes_3DNOW; opcode = opcode_3dnow; @@ -684,6 +683,9 @@ generate_call: } codegen_mark_code_present(block, cs+old_pc, (op_pc - old_pc) - pc_off); /* It is apparently a prefixed instruction. */ + // if ((recomp_op_table == recomp_opcodes) && (opcode == 0x48)) + // 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); @@ -702,7 +704,8 @@ generate_call: return; } } - + +// codegen_skip: if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) { op_table = (OpFn *) x86_dynarec_opcodes; @@ -762,14 +765,14 @@ generate_call: last_op_ea_seg = op_ea_seg; last_op_ssegs = op_ssegs; //codegen_block_ins++; - + block->ins++; if (block->ins >= MAX_INSTRUCTION_COUNT) CPU_BLOCK_END(); codegen_endpc = (cs + cpu_state.pc) + 8; - + // if (has_ea) // fatal("Has EA\n"); } diff --git a/src/codegen_new/codegen.h b/src/codegen_new/codegen.h index 38a061f97..082874f28 100644 --- a/src/codegen_new/codegen.h +++ b/src/codegen_new/codegen.h @@ -13,18 +13,18 @@ added to the page_lookup for this purpose. When in the page_lookup, each write will go through the mem_write_ram*_page() functions and set the dirty mask appropriately. - + Each codeblock also contains a code mask (actually two masks, one for each page the block is/may be in), again with each bit representing 64 bytes. - + Each page has a list of codeblocks present in it. As each codeblock can span up to two pages, two lists are present. - + When a codeblock is about to be executed, the code masks are compared with the dirty masks for the relevant pages. If either intersect, then codegen_check_flush() is called on the affected page(s), and all affected blocks are evicted. - + The 64 byte granularity appears to work reasonably well for most cases, avoiding most unnecessary evictions (eg when code & data are stored in the same page). @@ -45,7 +45,7 @@ typedef struct codeblock_t uint16_t parent, left, right; uint8_t *data; - + uint64_t page_mask, page_mask2; uint64_t *dirty_mask, *dirty_mask2; @@ -96,10 +96,10 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) { codeblock_t *block; uint64_t a = _cs | ((uint64_t)phys << 32); - + if (!pages[phys >> 12].head) return NULL; - + block = &codeblock[pages[phys >> 12].head]; while (block) { @@ -115,7 +115,7 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) else block = block->right ? &codeblock[block->right] : NULL; } - + return block; } @@ -133,23 +133,23 @@ static inline void codeblock_tree_add(codeblock_t *new_block) { codeblock_t *old_block = NULL; uint64_t old_block_cmp = 0; - + while (block) { old_block = block; old_block_cmp = old_block->_cs | ((uint64_t)old_block->phys << 32); - + if (a < old_block_cmp) block = block->left ? &codeblock[block->left] : NULL; else block = block->right ? &codeblock[block->right] : NULL; } - + if (a < old_block_cmp) old_block->left = get_block_nr(new_block); else old_block->right = get_block_nr(new_block); - + new_block->parent = get_block_nr(old_block); new_block->left = new_block->right = BLOCK_INVALID; } @@ -173,7 +173,7 @@ static inline void codeblock_tree_delete(codeblock_t *block) else { uint16_t block_nr = get_block_nr(block); - + if (parent->left == block_nr) parent->left = BLOCK_INVALID; if (parent->right == block_nr) @@ -237,11 +237,11 @@ static inline void codeblock_tree_delete(codeblock_t *block) codeblock_t *lowest = &codeblock[block->right], *highest; codeblock_t *old_parent; uint16_t lowest_nr; - + while (lowest->left) lowest = &codeblock[lowest->left]; lowest_nr = get_block_nr(lowest); - + old_parent = &codeblock[lowest->parent]; /*Replace deleted node with lowest node*/ @@ -263,7 +263,7 @@ static inline void codeblock_tree_delete(codeblock_t *block) codeblock[lowest->left].parent = lowest_nr; old_parent->left = BLOCK_INVALID; - + highest = &codeblock[lowest->right]; if (!lowest->right) { @@ -341,15 +341,8 @@ void codegen_delete_random_block(int required_mem_block); extern int cpu_block_end; extern uint32_t codegen_endpc; -extern int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; -extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; -extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; -extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; -extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; -extern int cpu_recomp_removed, cpu_recomp_removed_latched; - -extern int cpu_reps, cpu_reps_latched; -extern int cpu_notreps, cpu_notreps_latched; +extern int cpu_reps; +extern int cpu_notreps; extern int codegen_block_cycles; diff --git a/src/codegen_new/codegen_accumulate.c b/src/codegen_new/codegen_accumulate.c index 2a5d0956b..f15776b74 100644 --- a/src/codegen_new/codegen_accumulate.c +++ b/src/codegen_new/codegen_accumulate.c @@ -13,34 +13,30 @@ static struct int dest_reg; } acc_regs[] = { - [ACCREG_ins] = {0, IREG_ins}, - [ACCREG_cycles] = {0, IREG_cycles}, + [ACCREG_cycles] = {0, IREG_cycles} }; -void codegen_accumulate(int acc_reg, int delta) +void codegen_accumulate(ir_data_t *ir, int acc_reg, int delta) { acc_regs[acc_reg].count += delta; + +#ifdef USE_ACYCS + if ((acc_reg == ACCREG_cycles) && (delta != 0)) { + uop_ADD_IMM(ir, IREG_acycs, IREG_acycs, -delta); + } +#endif } void codegen_accumulate_flush(ir_data_t *ir) { - int c; - - for (c = 0; c < ACCREG_COUNT; c++) - { - if (acc_regs[c].count) - { - uop_ADD_IMM(ir, acc_regs[c].dest_reg, acc_regs[c].dest_reg, acc_regs[c].count); - } + if (acc_regs[0].count) { + uop_ADD_IMM(ir, acc_regs[0].dest_reg, acc_regs[0].dest_reg, acc_regs[0].count); + } - acc_regs[c].count = 0; - } + acc_regs[0].count = 0; } void codegen_accumulate_reset() { - int c; - - for (c = 0; c < ACCREG_COUNT; c++) - acc_regs[c].count = 0; + acc_regs[0].count = 0; } diff --git a/src/codegen_new/codegen_accumulate.h b/src/codegen_new/codegen_accumulate.h index 55d7c8eba..908dba2e2 100644 --- a/src/codegen_new/codegen_accumulate.h +++ b/src/codegen_new/codegen_accumulate.h @@ -1,13 +1,12 @@ enum { - ACCREG_ins = 0, - ACCREG_cycles = 1, - + ACCREG_cycles = 0, + ACCREG_COUNT }; struct ir_data_t; -void codegen_accumulate(int acc_reg, int delta); +void codegen_accumulate(struct ir_data_t *ir, int acc_reg, int delta); void codegen_accumulate_flush(struct ir_data_t *ir); void codegen_accumulate_reset(); diff --git a/src/codegen_new/codegen_allocator.c b/src/codegen_new/codegen_allocator.c index 9f46a8354..baeea52b6 100644 --- a/src/codegen_new/codegen_allocator.c +++ b/src/codegen_new/codegen_allocator.c @@ -1,6 +1,7 @@ -#if defined(__linux__) || defined(__APPLE__) +#if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) #include #include +#include #endif #if defined WIN32 || defined _WIN32 || defined _WIN32 #include @@ -35,8 +36,12 @@ void codegen_allocator_init() #if defined WIN32 || defined _WIN32 || defined _WIN32 mem_block_alloc = VirtualAlloc(NULL, MEM_BLOCK_NR * MEM_BLOCK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + /* TODO: check deployment target: older Intel-based versions of macOS don't play + nice with MAP_JIT. */ +#elif defined(__APPLE__) && defined(MAP_JIT) + mem_block_alloc = mmap(0, MEM_BLOCK_NR * MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE|MAP_JIT, -1, 0); #else - mem_block_alloc = mmap(0, MEM_BLOCK_NR * MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); + mem_block_alloc = mmap(0, MEM_BLOCK_NR * MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); #endif for (c = 0; c < MEM_BLOCK_NR; c++) @@ -55,13 +60,13 @@ mem_block_t *codegen_allocator_allocate(mem_block_t *parent, int code_block) { mem_block_t *block; uint32_t block_nr; - + while (!mem_block_free_list) { /*Pick a random memory block and free the owning code block*/ block_nr = rand() & MEM_BLOCK_MASK; block = &mem_blocks[block_nr]; - + if (block->code_block && block->code_block != code_block) codegen_delete_block(&codeblock[block->code_block]); } @@ -70,7 +75,7 @@ mem_block_t *codegen_allocator_allocate(mem_block_t *parent, int code_block) block_nr = mem_block_free_list; block = &mem_blocks[block_nr-1]; mem_block_free_list = block->next; - + block->code_block = code_block; if (parent) { @@ -92,12 +97,12 @@ void codegen_allocator_free(mem_block_t *block) { int next_block_nr = block->next; codegen_allocator_usage--; - + block->next = mem_block_free_list; block->code_block = BLOCK_INVALID; mem_block_free_list = block_nr; block_nr = next_block_nr; - + if (block_nr) block = &mem_blocks[block_nr - 1]; else @@ -112,10 +117,14 @@ uint8_t *codeblock_allocator_get_ptr(mem_block_t *block) void codegen_allocator_clean_blocks(struct mem_block_t *block) { -#if defined __ARM_EABI__ || defined _ARM_ || defined __aarch64__ +#if defined __ARM_EABI__ || defined _ARM_ || defined __aarch64__ || defined _M_ARM || defined _M_ARM64 while (1) { +#ifndef _MSC_VER __clear_cache(&mem_block_alloc[block->offset], &mem_block_alloc[block->offset + MEM_BLOCK_SIZE]); +#else + FlushInstructionCache(GetCurrentProcess(), &mem_block_alloc[block->offset], MEM_BLOCK_SIZE); +#endif if (block->next) block = &mem_blocks[block->next - 1]; else diff --git a/src/codegen_new/codegen_allocator.h b/src/codegen_new/codegen_allocator.h index 3b57de166..f9e70d248 100644 --- a/src/codegen_new/codegen_allocator.h +++ b/src/codegen_new/codegen_allocator.h @@ -4,16 +4,16 @@ /*The allocator handles all allocation of executable memory. Since the two-pass recompiler design makes applying hard limits to codeblock size difficult, the allocator allows memory to be provided as and when required. - + The allocator provides a block size of a little under 1 kB (slightly lower to limit cache aliasing). Each generated codeblock is allocated one block by default, and will allocate additional block(s) once the existing memory is sorted. Blocks are chained together by jump instructions. - + Due to the chaining, the total memory size is limited by the range of a jump instruction. ARMv7 is restricted to +/- 32 MB, ARMv8 to +/- 128 MB, x86 to +/- 2GB. As a result, total memory size is limited to 32 MB on ARMv7*/ -#if defined __ARM_EABI__ || _ARM_ +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM #define MEM_BLOCK_NR 32768 #else #define MEM_BLOCK_NR 131072 diff --git a/src/codegen_new/codegen_backend.h b/src/codegen_new/codegen_backend.h index 931939004..56884c84b 100644 --- a/src/codegen_new/codegen_backend.h +++ b/src/codegen_new/codegen_backend.h @@ -1,13 +1,13 @@ #ifndef _CODEGEN_BACKEND_H_ #define _CODEGEN_BACKEND_H_ -#if defined __amd64__ +#if defined __amd64__ || defined _M_X64 #include "codegen_backend_x86-64.h" #elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 #include "codegen_backend_x86.h" -#elif defined __ARM_EABI__ || defined _ARM_ +#elif defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM #include "codegen_backend_arm.h" -#elif defined __aarch64__ +#elif defined __aarch64__ || defined _M_ARM64 #include "codegen_backend_arm64.h" #else #error Dynamic recompiler not implemented on your platform diff --git a/src/codegen_new/codegen_backend_arm.c b/src/codegen_new/codegen_backend_arm.c index 06a06b78e..7030c401a 100644 --- a/src/codegen_new/codegen_backend_arm.c +++ b/src/codegen_new/codegen_backend_arm.c @@ -1,4 +1,4 @@ -#if defined __ARM_EABI__ || defined _ARM_ +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM #include #include @@ -22,6 +22,7 @@ #if defined WIN32 || defined _WIN32 || defined _WIN32 #include #endif +#include void *codegen_mem_load_byte; void *codegen_mem_load_word; @@ -283,7 +284,7 @@ static void build_fp_round_routine(codeblock_t *block) host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); host_arm_VMSR_FPSCR(block, REG_TEMP); host_arm_MOV_REG(block, REG_PC, REG_LR); - + jump_table[X87_ROUNDING_CHOP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //zero host_arm_VCVT_IS_D(block, REG_D_TEMP, REG_D_TEMP); host_arm_MOV_REG(block, REG_PC, REG_LR); @@ -310,7 +311,7 @@ void codegen_backend_init() block->data = codeblock_allocator_get_ptr(block->head_mem_block); block_write_data = block->data; build_loadstore_routines(&codeblock[block_current]); -printf("block_pos=%i\n", block_pos); +//pclog("block_pos=%i\n", block_pos); codegen_fp_round = &block_write_data[block_pos]; build_fp_round_routine(&codeblock[block_current]); diff --git a/src/codegen_new/codegen_backend_arm.h b/src/codegen_new/codegen_backend_arm.h index 87dc2d8a0..8b8936a98 100644 --- a/src/codegen_new/codegen_backend_arm.h +++ b/src/codegen_new/codegen_backend_arm.h @@ -21,4 +21,4 @@ void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm void host_arm_call(codeblock_t *block, void *dst_addr); void host_arm_nop(codeblock_t *block); -void codegen_alloc(codeblock_t *block, int size); \ No newline at end of file +void codegen_alloc(codeblock_t *block, int size); diff --git a/src/codegen_new/codegen_backend_arm64.c b/src/codegen_new/codegen_backend_arm64.c index 5f2550e23..ce1082d0a 100644 --- a/src/codegen_new/codegen_backend_arm64.c +++ b/src/codegen_new/codegen_backend_arm64.c @@ -1,4 +1,4 @@ -#ifdef __aarch64__ +#if defined __aarch64__ || defined _M_ARM64 #include #include @@ -22,6 +22,7 @@ #if defined WIN32 || defined _WIN32 || defined _WIN32 #include #endif +#include void *codegen_mem_load_byte; void *codegen_mem_load_word; @@ -73,7 +74,6 @@ static void build_load_routine(codeblock_t *block, int size, int is_float) { uint32_t *branch_offset; uint32_t *misaligned_offset; - int offset; /*In - W0 = address Out - W0 = data, W1 = abrt*/ @@ -142,7 +142,6 @@ static void build_store_routine(codeblock_t *block, int size, int is_float) { uint32_t *branch_offset; uint32_t *misaligned_offset; - int offset; /*In - R0 = address, R1 = data Out - R1 = abrt*/ @@ -269,7 +268,7 @@ static void build_fp_round_routine(codeblock_t *block, int is_quad) else host_arm64_FCVTMS_W_D(block, REG_TEMP, REG_V_TEMP); host_arm64_RET(block, REG_X30); - + jump_table[X87_ROUNDING_CHOP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //zero if (is_quad) host_arm64_FCVTZS_X_D(block, REG_TEMP, REG_V_TEMP); @@ -282,12 +281,6 @@ void codegen_backend_init() { codeblock_t *block; int c; -#if defined(__linux__) || defined(__APPLE__) - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); diff --git a/src/codegen_new/codegen_backend_arm64.h b/src/codegen_new/codegen_backend_arm64.h index b4888d38e..3e3d16575 100644 --- a/src/codegen_new/codegen_backend_arm64.h +++ b/src/codegen_new/codegen_backend_arm64.h @@ -28,4 +28,4 @@ void host_arm64_STRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int o void host_arm64_call(codeblock_t *block, void *dst_addr); void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); -uint32_t host_arm64_find_imm(uint32_t data); \ No newline at end of file +uint32_t host_arm64_find_imm(uint32_t data); diff --git a/src/codegen_new/codegen_backend_arm64_defs.h b/src/codegen_new/codegen_backend_arm64_defs.h index dabfe8ae8..ac2d238da 100644 --- a/src/codegen_new/codegen_backend_arm64_defs.h +++ b/src/codegen_new/codegen_backend_arm64_defs.h @@ -132,4 +132,4 @@ extern void *codegen_fp_round; extern void *codegen_fp_round_quad; extern void *codegen_gpf_rout; -extern void *codegen_exit_rout; \ No newline at end of file +extern void *codegen_exit_rout; diff --git a/src/codegen_new/codegen_backend_arm64_ops.c b/src/codegen_new/codegen_backend_arm64_ops.c index 3f64b8d4e..0cc20d788 100644 --- a/src/codegen_new/codegen_backend_arm64_ops.c +++ b/src/codegen_new/codegen_backend_arm64_ops.c @@ -1,4 +1,4 @@ -#ifdef __aarch64__ +#if defined __aarch64__ || defined _M_ARM64 #include #include <86box/86box.h> @@ -270,12 +270,6 @@ static inline int imm_is_imm16(uint32_t imm_data) return 1; return 0; } -static inline int imm_is_imm12(uint32_t imm_data) -{ - if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff)) - return 1; - return 0; -} static void codegen_allocate_new_block(codeblock_t *block); diff --git a/src/codegen_new/codegen_backend_arm64_ops.h b/src/codegen_new/codegen_backend_arm64_ops.h index 2a514edbe..c89a02311 100644 --- a/src/codegen_new/codegen_backend_arm64_ops.h +++ b/src/codegen_new/codegen_backend_arm64_ops.h @@ -261,4 +261,4 @@ void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p); -void codegen_alloc(codeblock_t *block, int size); \ No newline at end of file +void codegen_alloc(codeblock_t *block, int size); diff --git a/src/codegen_new/codegen_backend_arm64_uops.c b/src/codegen_new/codegen_backend_arm64_uops.c index 5710b8902..10a07a4a2 100644 --- a/src/codegen_new/codegen_backend_arm64_uops.c +++ b/src/codegen_new/codegen_backend_arm64_uops.c @@ -1,4 +1,4 @@ -#ifdef __aarch64__ +#if defined __aarch64__ || defined _M_ARM64 #include #include <86box/86box.h> @@ -1410,7 +1410,7 @@ static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); host_arm64_call(block, codegen_fp_round_quad); host_arm64_FMOV_D_Q(block, dest_reg, REG_TEMP); - + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); } else diff --git a/src/codegen_new/codegen_backend_arm_ops.c b/src/codegen_new/codegen_backend_arm_ops.c index 65e48cd46..43d1ea090 100644 --- a/src/codegen_new/codegen_backend_arm_ops.c +++ b/src/codegen_new/codegen_backend_arm_ops.c @@ -1,4 +1,4 @@ -#if defined __ARM_EABI__ || defined _ARM_ +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM #include #include <86box/86box.h> diff --git a/src/codegen_new/codegen_backend_arm_uops.c b/src/codegen_new/codegen_backend_arm_uops.c index fd17e78d8..8b0990016 100644 --- a/src/codegen_new/codegen_backend_arm_uops.c +++ b/src/codegen_new/codegen_backend_arm_uops.c @@ -1,4 +1,4 @@ -#if defined __ARM_EABI__ || defined _ARM_ +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM #include #include @@ -416,7 +416,7 @@ static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) jump_p = host_arm_BHI_(block); *jump_p |= ((((uintptr_t)uop->p - (uintptr_t)jump_p) - 8) & 0x3fffffc) >> 2; - + return 0; } @@ -913,8 +913,8 @@ static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) *branch_ptr |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_ptr) - 8) & 0x3fffffc) >> 2; host_arm_MOV_IMM(block, REG_TEMP, 0x01010101); - host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[0] - (uintptr_t)&cpu_state); - host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[4] - (uintptr_t)&cpu_state); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[0] - (uintptr_t)&cpu_state); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[4] - (uintptr_t)&cpu_state); host_arm_MOV_IMM(block, REG_TEMP, 0); host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); host_arm_STRB_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.ismmx - (uintptr_t)&cpu_state); @@ -1488,7 +1488,7 @@ static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) static int64_t x87_fround64(double b) { int64_t a, c; - + switch ((cpu_state.npxc >> 10) & 3) { case 0: /*Nearest*/ @@ -1507,7 +1507,7 @@ static int64_t x87_fround64(double b) case 3: /*Chop*/ return (int64_t)b; } - + return 0; } static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) @@ -1529,7 +1529,7 @@ static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) host_arm_VMOV_D_D(block, REG_D0, src_reg); host_arm_call(block, x87_fround64); host_arm_VMOV_D_64(block, REG_D_TEMP, REG_R0, REG_R1); - + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; } else diff --git a/src/codegen_new/codegen_backend_x86-64.c b/src/codegen_new/codegen_backend_x86-64.c index 10abe3c72..8411ca8da 100644 --- a/src/codegen_new/codegen_backend_x86-64.c +++ b/src/codegen_new/codegen_backend_x86-64.c @@ -1,5 +1,6 @@ -#ifdef __amd64__ +#if defined __amd64__ || defined _M_X64 +#include #include #include <86box/86box.h> #include "cpu.h" @@ -21,6 +22,7 @@ #if defined WIN32 || defined _WIN32 || defined _WIN32 #include #endif +#include void *codegen_mem_load_byte; void *codegen_mem_load_word; @@ -51,7 +53,7 @@ host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = { -#if WIN64 +#if _WIN64 /*Windows x86-64 calling convention preserves XMM6-XMM15*/ {REG_XMM6, 0}, {REG_XMM7, 0}, @@ -123,7 +125,7 @@ static void build_load_routine(codeblock_t *block, int size, int is_float) *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; host_x86_PUSH(block, REG_RAX); host_x86_PUSH(block, REG_RDX); -#if WIN64 +#if _WIN64 host_x86_SUB64_REG_IMM(block, REG_RSP, 0x20); //host_x86_MOV32_REG_REG(block, REG_ECX, uop->imm_data); #else @@ -155,7 +157,7 @@ static void build_load_routine(codeblock_t *block, int size, int is_float) host_x86_CALL(block, (void *)readmemql); host_x86_MOVQ_XREG_REG(block, REG_XMM_TEMP, REG_RAX); } -#if WIN64 +#if _WIN64 host_x86_ADD64_REG_IMM(block, REG_RSP, 0x20); #endif host_x86_POP(block, REG_RDX); @@ -221,7 +223,7 @@ static void build_store_routine(codeblock_t *block, int size, int is_float) *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; host_x86_PUSH(block, REG_RAX); host_x86_PUSH(block, REG_RDX); -#if WIN64 +#if _WIN64 host_x86_SUB64_REG_IMM(block, REG_RSP, 0x28); if (size == 4 && is_float) host_x86_MOVD_REG_XREG(block, REG_EDX, REG_XMM_TEMP); //data @@ -248,7 +250,7 @@ static void build_store_routine(codeblock_t *block, int size, int is_float) host_x86_CALL(block, (void *)writememll); else if (size == 8) host_x86_CALL(block, (void *)writememql); -#if WIN64 +#if _WIN64 host_x86_ADD64_REG_IMM(block, REG_RSP, 0x28); #else host_x86_ADD64_REG_IMM(block, REG_RSP, 0x8); @@ -292,12 +294,6 @@ void codegen_backend_init() { codeblock_t *block; int c; -#if defined(__linux__) || defined(__APPLE__) - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); @@ -317,14 +313,13 @@ void codegen_backend_init() build_loadstore_routines(&codeblock[block_current]); codegen_gpf_rout = &codeblock[block_current].data[block_pos]; -#if WIN64 +#if _WIN64 host_x86_XOR32_REG_REG(block, REG_ECX, REG_ECX); host_x86_XOR32_REG_REG(block, REG_EDX, REG_EDX); #else host_x86_XOR32_REG_REG(block, REG_EDI, REG_EDI); host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); #endif - /* host_x86_CALL(block, (uintptr_t)x86gpf); */ host_x86_CALL(block, (void *)x86gpf); codegen_exit_rout = &codeblock[block_current].data[block_pos]; host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); diff --git a/src/codegen_new/codegen_backend_x86-64.h b/src/codegen_new/codegen_backend_x86-64.h index 70e953a6b..ccc526b30 100644 --- a/src/codegen_new/codegen_backend_x86-64.h +++ b/src/codegen_new/codegen_backend_x86-64.h @@ -10,3 +10,5 @@ #define HASH(l) ((l) & 0x1ffff) #define BLOCK_MAX 0x3c0 + +#define CODEGEN_BACKEND_HAS_MOV_IMM diff --git a/src/codegen_new/codegen_backend_x86-64_defs.h b/src/codegen_new/codegen_backend_x86-64_defs.h index a21f62902..8955773cd 100644 --- a/src/codegen_new/codegen_backend_x86-64_defs.h +++ b/src/codegen_new/codegen_backend_x86-64_defs.h @@ -44,7 +44,7 @@ #define REG_XMM6 6 #define REG_XMM7 7 -#define REG_XMM_TEMP REG_XMM7 +#define REG_XMM_TEMP REG_XMM0 #define CODEGEN_HOST_REGS 3 #define CODEGEN_HOST_FP_REGS 7 diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index 1ffec61b9..2baa0f585 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -1,4 +1,4 @@ -#ifdef __amd64__ +#if defined __amd64__ || defined _M_X64 #include #include <86box/86box.h> @@ -27,12 +27,12 @@ static inline void call(codeblock_t *block, uintptr_t func) { - uintptr_t diff; + intptr_t diff; codegen_alloc_bytes(block, 5); - diff = func - (uintptr_t)&block_write_data[block_pos + 5]; + diff = (intptr_t)(func - (uintptr_t)&block_write_data[block_pos + 5]); - if (diff >= -0x80000000 && diff < 0x7fffffff) + if (diff >= -0x80000000LL && diff < 0x7fffffffLL) { codegen_addbyte(block, 0xE8); /*CALL*/ codegen_addlong(block, (uint32_t)diff); @@ -48,12 +48,12 @@ static inline void call(codeblock_t *block, uintptr_t func) static inline void jmp(codeblock_t *block, uintptr_t func) { - uintptr_t diff; + intptr_t diff; codegen_alloc_bytes(block, 5); - diff = func - (uintptr_t)&block_write_data[block_pos + 5]; + diff = (intptr_t)(func - (uintptr_t)&block_write_data[block_pos + 5]); - if (diff >= -0x80000000 && diff < 0x7fffffff) + if (diff >= -0x80000000LL && diff < 0x7fffffffLL) { codegen_addbyte(block, 0xe9); /*JMP*/ codegen_addlong(block, (uint32_t)diff); @@ -521,6 +521,26 @@ void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) codegen_addbyte(block, imm_data); } } +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ + codegen_addword(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); + codegen_alloc_bytes(block, 10); + codegen_addbyte4(block, 0x66, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addword(block, imm_data); + } +} void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); @@ -681,7 +701,7 @@ void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; - + if (dst_reg & 8) fatal("host_x86_MOV8_REG_ABS reg & 8\n"); @@ -747,7 +767,7 @@ void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; - + if (dst_reg & 8) fatal("host_x86_MOV32_REG_ABS reg & 8\n"); @@ -945,6 +965,30 @@ void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset fatal("MOV64_BASE_OFFSET_REG - offset %i\n", offset); } +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data) +{ + if (base_reg & 8) + fatal("host_x86_MOV32_BASE_OFFSET_IMM reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset); + codegen_addlong(block, imm_data); + } + } + else + fatal("MOV32_BASE_OFFSET_IMM - offset %i\n", offset); +} + void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) { if (reg >= 8) @@ -1095,7 +1139,7 @@ void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; - + if (dst_reg & 8) fatal("host_x86_MOVZX_REG_ABS_16_8 - bad reg\n"); @@ -1126,7 +1170,7 @@ void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; - + // if (dst_reg & 8) // fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); @@ -1170,7 +1214,7 @@ void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; - + if (dst_reg & 8) fatal("host_x86_MOVZX_REG_ABS_32_16 - bad reg\n"); diff --git a/src/codegen_new/codegen_backend_x86-64_ops.h b/src/codegen_new/codegen_backend_x86-64_ops.h index 62a9ba203..e570813de 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.h +++ b/src/codegen_new/codegen_backend_x86-64_ops.h @@ -56,6 +56,7 @@ void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int sr void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data); void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); @@ -72,6 +73,8 @@ void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg); void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data); + void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p); void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p); void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); diff --git a/src/codegen_new/codegen_backend_x86-64_ops_sse.c b/src/codegen_new/codegen_backend_x86-64_ops_sse.c index 00ffb2db3..e2a4e7044 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops_sse.c +++ b/src/codegen_new/codegen_backend_x86-64_ops_sse.c @@ -1,4 +1,4 @@ -#ifdef __amd64__ +#if defined __amd64__ || defined _M_X64 #include #include <86box/86box.h> diff --git a/src/codegen_new/codegen_backend_x86-64_uops.c b/src/codegen_new/codegen_backend_x86-64_uops.c index c87ce26e1..9997ea738 100644 --- a/src/codegen_new/codegen_backend_x86-64_uops.c +++ b/src/codegen_new/codegen_backend_x86-64_uops.c @@ -1,4 +1,4 @@ -#ifdef __amd64__ +#if defined __amd64__ || defined _M_X64 #include #include <86box/86box.h> @@ -199,9 +199,9 @@ static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); - /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ #ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); if (!REG_IS_L(dest_size)) fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); #endif @@ -803,7 +803,7 @@ static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); branch_offset = host_x86_JZ_long(block); host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); -#if WIN64 +#if _WIN64 host_x86_MOV32_REG_IMM(block, REG_ECX, 7); #else host_x86_MOV32_REG_IMM(block, REG_EDI, 7); @@ -822,7 +822,7 @@ static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); branch_offset = host_x86_JZ_long(block); host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); -#if WIN64 +#if _WIN64 host_x86_MOV32_REG_IMM(block, REG_ECX, 7); #else host_x86_MOV32_REG_IMM(block, REG_EDI, 7); @@ -852,7 +852,7 @@ static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) if (REG_IS_W(src_size)) { -#if WIN64 +#if _WIN64 host_x86_MOVZX_REG_32_16(block, REG_ECX, src_reg); #else host_x86_MOVZX_REG_32_16(block, REG_EDI, src_reg); @@ -888,7 +888,7 @@ static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) { -#if WIN64 +#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); @@ -897,7 +897,7 @@ static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) } static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) { -#if WIN64 +#if _WIN64 host_x86_MOV32_REG_IMM(block, REG_EDX, uop->imm_data); #else host_x86_MOV32_REG_IMM(block, REG_ESI, uop->imm_data); @@ -922,13 +922,13 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) { int src_reg = HOST_REG_GET(uop->src_reg_a_real); - /* int src_size = IREG_GET_SIZE(uop->src_reg_a_real); */ #ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); if (!REG_IS_W(src_size)) fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); #endif -#if WIN64 +#if _WIN64 host_x86_MOV16_REG_REG(block, REG_CX, src_reg); host_x86_MOV64_REG_IMM(block, REG_EDX, (uint64_t)uop->p); #else @@ -1033,9 +1033,9 @@ static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); - /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ #ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); if (!REG_IS_D(dest_size)) fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); #endif @@ -1052,9 +1052,9 @@ static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); - /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ #ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); if (!REG_IS_D(dest_size)) fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); #endif @@ -1178,9 +1178,9 @@ static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) { int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); - /* int src_size = IREG_GET_SIZE(uop->src_reg_c_real); */ #ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); if (!REG_IS_D(src_size)) fatal("MEM_STORE_SINGLE - %02x\n", uop->src_reg_b_real); #endif @@ -1197,9 +1197,9 @@ static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) { int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); - /* int src_size = IREG_GET_SIZE(uop->src_reg_c_real); */ #ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); if (!REG_IS_D(src_size)) fatal("MEM_STORE_DOUBLE - %02x\n", uop->src_reg_b_real); #endif @@ -1449,7 +1449,7 @@ static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) host_x86_CVTSD2SI_REG64_XREG(block, REG_RCX, src_reg); host_x86_LDMXCSR(block, &cpu_state.old_fp_control); host_x86_MOVQ_XREG_REG(block, dest_reg, REG_RCX); - + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; } #ifdef RECOMPILER_DEBUG @@ -1499,7 +1499,7 @@ static int codegen_OR(codeblock_t *block, uop_t *uop) } static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) { - int dest_reg = HOST_REG_GET(uop->dest_reg_a_real)/*, src_reg = HOST_REG_GET(uop->src_reg_a_real)*/; + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); if (REG_IS_L(dest_size) && REG_IS_L(src_size)) @@ -2770,7 +2770,7 @@ static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) static int codegen_XOR(codeblock_t *block, uop_t *uop) { - int dest_reg = HOST_REG_GET(uop->dest_reg_a_real)/*, src_reg_a = HOST_REG_GET(uop->src_reg_a_real)*/, src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) @@ -2797,7 +2797,7 @@ static int codegen_XOR(codeblock_t *block, uop_t *uop) } static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) { - int dest_reg = HOST_REG_GET(uop->dest_reg_a_real)/*, src_reg = HOST_REG_GET(uop->src_reg_a_real)*/; + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); if (REG_IS_L(dest_size) && REG_IS_L(src_size)) @@ -3145,4 +3145,21 @@ void codegen_set_jump_dest(codeblock_t *block, void *p) *(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4); } +void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data) +{ + host_x86_MOV8_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data) +{ + host_x86_MOV16_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data) +{ + host_x86_MOV32_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data) +{ + host_x86_MOV32_BASE_OFFSET_IMM(block, REG_ESP, stack_offset, imm_data); +} + #endif diff --git a/src/codegen_new/codegen_backend_x86.c b/src/codegen_new/codegen_backend_x86.c index 1e22caa2e..14327607b 100644 --- a/src/codegen_new/codegen_backend_x86.c +++ b/src/codegen_new/codegen_backend_x86.c @@ -23,6 +23,7 @@ #if defined WIN32 || defined _WIN32 || defined _WIN32 #include #endif +#include void *codegen_mem_load_byte; void *codegen_mem_load_word; @@ -65,7 +66,7 @@ static void build_load_routine(codeblock_t *block, int size, int is_float) { uint8_t *branch_offset; uint8_t *misaligned_offset = NULL; - + /*In - ESI = address Out - ECX = data, ESI = abrt*/ /*MOV ECX, ESI @@ -110,7 +111,7 @@ static void build_load_routine(codeblock_t *block, int size, int is_float) fatal("build_load_routine: size=%i\n", size); host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); host_x86_RET(block); - + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; if (size != 1) *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; @@ -154,7 +155,7 @@ static void build_store_routine(codeblock_t *block, int size, int is_float) { uint8_t *branch_offset; uint8_t *misaligned_offset = NULL; - + /*In - ECX = data, ESI = address Out - ESI = abrt Corrupts EDI*/ @@ -267,12 +268,7 @@ void codegen_backend_init() { codeblock_t *block; int c; -#if defined(__linux__) || defined(__APPLE__) - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); @@ -289,7 +285,7 @@ void codegen_backend_init() block->data = codeblock_allocator_get_ptr(block->head_mem_block); block_write_data = block->data; build_loadstore_routines(block); - + codegen_gpf_rout = &codeblock[block_current].data[block_pos]; host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 0); host_x86_MOV32_STACK_IMM(block, STACK_ARG1, 0); diff --git a/src/codegen_new/codegen_backend_x86.h b/src/codegen_new/codegen_backend_x86.h index a5aec727c..582e46430 100644 --- a/src/codegen_new/codegen_backend_x86.h +++ b/src/codegen_new/codegen_backend_x86.h @@ -10,3 +10,5 @@ #define HASH(l) ((l) & 0x1ffff) #define BLOCK_MAX 0x3c0 + +#define CODEGEN_BACKEND_HAS_MOV_IMM diff --git a/src/codegen_new/codegen_backend_x86_ops.c b/src/codegen_new/codegen_backend_x86_ops.c index 3d71cc081..5e89ffbc8 100644 --- a/src/codegen_new/codegen_backend_x86_ops.c +++ b/src/codegen_new/codegen_backend_x86_ops.c @@ -449,6 +449,24 @@ void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) codegen_addbyte(block, imm_data); } } +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0x66, 0xc7, 0x05); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addword(block, imm_data); + } +} void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); @@ -705,6 +723,27 @@ void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset); } +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset); + codegen_addlong(block, imm_data); + } + } + else + fatal("MOV32_BASE_OFFSET_IMM - offset %i\n", offset); +} + void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) { codegen_alloc_bytes(block, 2); diff --git a/src/codegen_new/codegen_backend_x86_ops.h b/src/codegen_new/codegen_backend_x86_ops.h index 294b42236..53b6e0e73 100644 --- a/src/codegen_new/codegen_backend_x86_ops.h +++ b/src/codegen_new/codegen_backend_x86_ops.h @@ -60,6 +60,7 @@ void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int sr void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data); void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); @@ -75,6 +76,8 @@ void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg void host_x86_MOV16_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg); void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg); +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data); + void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p); void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p); void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); diff --git a/src/codegen_new/codegen_backend_x86_uops.c b/src/codegen_new/codegen_backend_x86_uops.c index 43737560c..3f7e2dd9a 100644 --- a/src/codegen_new/codegen_backend_x86_uops.c +++ b/src/codegen_new/codegen_backend_x86_uops.c @@ -66,7 +66,7 @@ static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) { int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); - + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) { if (uop->dest_reg_a_real != uop->src_reg_a_real) @@ -280,7 +280,7 @@ static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); #endif uop->p = host_x86_JZ_long(block); - + return 0; } @@ -319,7 +319,7 @@ static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) #endif jump_p = host_x86_JNBE_long(block); *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); - + return 0; } @@ -801,7 +801,7 @@ static int codegen_FSUB(codeblock_t *block, uop_t *uop) static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) { uint32_t *branch_offset; - + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); branch_offset = host_x86_JZ_long(block); @@ -830,7 +830,7 @@ static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[4], 0x01010101); host_x86_MOV32_ABS_IMM(block, &cpu_state.TOP, 0); host_x86_MOV8_ABS_IMM(block, &cpu_state.ismmx, 1); - + return 0; } @@ -1047,7 +1047,7 @@ static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) host_x86_TEST32_REG(block, REG_ESI, REG_ESI); host_x86_JNZ(block, codegen_exit_rout); host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); - + return 0; } @@ -1266,7 +1266,7 @@ static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) } else fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); - + return 0; } static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) @@ -2643,6 +2643,11 @@ static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) host_x86_MOV8_ABS_IMM(block, uop->p, uop->imm_data); return 0; } +static int codegen_STORE_PTR_IMM_16(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV16_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} static int codegen_SUB(codeblock_t *block, uop_t *uop) { @@ -2825,7 +2830,7 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_JMP_DEST & UOP_MASK] = codegen_JMP_DEST, [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, - + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, @@ -2838,12 +2843,13 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, - + [UOP_STORE_P_IMM_16 & UOP_MASK] = codegen_STORE_PTR_IMM_16, + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, - + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, @@ -2851,7 +2857,7 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, - + [UOP_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, @@ -2911,16 +2917,16 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, - + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, - + [UOP_FADD & UOP_MASK] = codegen_FADD, [UOP_FDIV & UOP_MASK] = codegen_FDIV, [UOP_FMUL & UOP_MASK] = codegen_FMUL, [UOP_FSUB & UOP_MASK] = codegen_FSUB, [UOP_FCOM & UOP_MASK] = codegen_FCOM, - + [UOP_FABS & UOP_MASK] = codegen_FABS, [UOP_FCHS & UOP_MASK] = codegen_FCHS, [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, @@ -2957,11 +2963,11 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, - + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, - + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, @@ -2971,7 +2977,7 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, - + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, @@ -2979,7 +2985,7 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, - + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, @@ -2988,7 +2994,7 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP, - + #ifdef DEBUG_EXTRA [UOP_LOG_INSTR & UOP_MASK] = codegen_LOG_INSTR #endif @@ -3138,4 +3144,21 @@ void codegen_set_jump_dest(codeblock_t *block, void *p) *(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4); } +void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data) +{ + host_x86_MOV8_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data) +{ + host_x86_MOV16_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data) +{ + host_x86_MOV32_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data) +{ + host_x86_MOV32_BASE_OFFSET_IMM(block, REG_ESP, stack_offset, imm_data); +} + #endif diff --git a/src/codegen_new/codegen_block.c b/src/codegen_new/codegen_block.c index a6584c03a..e2aaddb5c 100644 --- a/src/codegen_new/codegen_block.c +++ b/src/codegen_new/codegen_block.c @@ -37,11 +37,6 @@ int block_current = 0; static int block_num; int block_pos; -int cpu_recomp_flushes, cpu_recomp_flushes_latched; -int cpu_recomp_evicted, cpu_recomp_evicted_latched; -int cpu_recomp_reuse, cpu_recomp_reuse_latched; -int cpu_recomp_removed, cpu_recomp_removed_latched; - uint32_t codegen_endpc; int codegen_block_cycles; @@ -63,7 +58,7 @@ static void delete_dirty_block(codeblock_t *block); /*Temporary list of code blocks that have recently been evicted. This allows for some historical state to be kept when a block is the target of self-modifying code. - + The size of this list is limited to DIRTY_LIST_MAX_SIZE blocks. When this is exceeded the oldest entry will be moved to the free list.*/ static uint16_t block_dirty_list_head, block_dirty_list_tail; @@ -72,8 +67,10 @@ static int dirty_list_size = 0; static void block_free_list_add(codeblock_t *block) { +#ifndef RELEASE_BUILD if (block->flags & CODEBLOCK_IN_DIRTY_LIST) fatal("block_free_list_add: block=%p in dirty list\n", block); +#endif if (block_free_list) block->next = block_free_list; else @@ -84,12 +81,14 @@ static void block_free_list_add(codeblock_t *block) static void block_dirty_list_add(codeblock_t *block) { +#ifndef RELEASE_BUILD if (block->flags & CODEBLOCK_IN_DIRTY_LIST) fatal("block_dirty_list_add: block=%p already in dirty list\n", block); +#endif if (block_dirty_list_head != BLOCK_INVALID) { codeblock_t *old_head = &codeblock[block_dirty_list_head]; - + block->next = block_dirty_list_head; block->prev = BLOCK_INVALID; block_dirty_list_head = old_head->prev = get_block_nr(block); @@ -107,12 +106,14 @@ static void block_dirty_list_add(codeblock_t *block) /*Evict oldest block to the free list*/ codeblock_t *evict_block = &codeblock[block_dirty_list_tail]; +#ifndef RELEASE_BUILD if (!(evict_block->flags & CODEBLOCK_IN_DIRTY_LIST)) fatal("block_dirty_list_add: evict_block=%p %x %x not in dirty list\n", evict_block, evict_block->phys, evict_block->flags); if (!block_dirty_list_tail) fatal("block_dirty_list_add - !block_dirty_list_tail\n"); if (evict_block->prev == BLOCK_INVALID) fatal("block_dirty_list_add - evict_block->prev == BLOCK_INVALID\n"); +#endif block_dirty_list_tail = evict_block->prev; codeblock[evict_block->prev].next = BLOCK_INVALID; @@ -128,8 +129,10 @@ static void block_dirty_list_remove(codeblock_t *block) codeblock_t *prev_block = &codeblock[block->prev]; codeblock_t *next_block = &codeblock[block->next]; +#ifndef RELEASE_BUILD if (!(block->flags & CODEBLOCK_IN_DIRTY_LIST)) fatal("block_dirty_list_remove: block=%p not in dirty list\n", block); +#endif /*Is block head of list*/ if (block->prev == BLOCK_INVALID) @@ -144,8 +147,10 @@ static void block_dirty_list_remove(codeblock_t *block) next_block->prev = block->prev; dirty_list_size--; +#ifndef RELEASE_BUILD if (dirty_list_size < 0) fatal("remove - dirty_list_size < 0!\n"); +#endif block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; } @@ -175,9 +180,10 @@ static codeblock_t *block_free_list_get() /*Free list is empty, check the dirty list*/ if (block_dirty_list_tail) { +#ifndef RELEASE_BUILD if (dirty_list_size <= 0) fatal("get - dirty_list_size <= 0!\n"); - +#endif /*Reuse oldest block*/ block = &codeblock[block_dirty_list_tail]; @@ -207,9 +213,9 @@ static codeblock_t *block_free_list_get() void codegen_init() { int c; - + codegen_allocator_init(); - + codegen_backend_init(); block_free_list = 0; for (c = 0; c < BLOCK_SIZE; c++) @@ -229,7 +235,7 @@ void codegen_close() { int c; uint32_t highest_num = 0, highest_idx = 0; - + for (c = 0; c < 256*256; c++) { if (instr_counts[c] > highest_num) @@ -257,7 +263,7 @@ void codegen_reset() for (c = 1; c < BLOCK_SIZE; c++) { codeblock_t *block = &codeblock[c]; - + if (block->pc != BLOCK_PC_INVALID) { block->phys = 0; @@ -290,7 +296,7 @@ void dump_block() pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); if (!block->pc) fatal("Dead PC=0\n"); - + block = block->next; } pclog("dump_block done\n");*/ @@ -301,8 +307,10 @@ static void add_to_block_list(codeblock_t *block) uint16_t block_prev_nr = pages[block->phys >> 12].block; uint16_t block_nr = get_block_nr(block); +#ifndef RELEASE_BUILD if (!block->page_mask) fatal("add_to_block_list - mask = 0 %llx %llx\n", block->page_mask,block->page_mask2); +#endif if (block_prev_nr) { @@ -318,14 +326,16 @@ static void add_to_block_list(codeblock_t *block) if (block->next) { +#ifndef RELEASE_BUILD if (codeblock[block->next].pc == BLOCK_PC_INVALID) fatal("block->next->pc=BLOCK_PC_INVALID %p %p %x %x\n", (void *)&codeblock[block->next], (void *)codeblock, block_current, block_pos); +#endif } - + if (block->page_mask2) { block->flags |= CODEBLOCK_HAS_PAGE2; - + block_prev_nr = pages[block->phys_2 >> 12].block_2; if (block_prev_nr) @@ -346,9 +356,10 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) { if (!block->page_mask) return; +#ifndef RELEASE_BUILD if (block->flags & CODEBLOCK_IN_DIRTY_LIST) fatal("remove_from_block_list: in dirty list\n"); - +#endif if (block->prev) { codeblock[block->prev].next = block->next; @@ -366,8 +377,10 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) if (!(block->flags & CODEBLOCK_HAS_PAGE2)) { +#ifndef RELEASE_BUILD if (block->prev_2 || block->next_2) fatal("Invalid block_2 %x %p %08x\n", block->flags, block, block->phys); +#endif return; } block->flags &= ~CODEBLOCK_HAS_PAGE2; @@ -392,11 +405,12 @@ static void invalidate_block(codeblock_t *block) { uint32_t old_pc = block->pc; +#ifndef RELEASE_BUILD if (block->flags & CODEBLOCK_IN_DIRTY_LIST) fatal("invalidate_block: already in dirty list\n"); if (block->pc == BLOCK_PC_INVALID) fatal("Invalidating deleted block\n"); - +#endif remove_from_block_list(block, old_pc); block_dirty_list_add(block); if (block->head_mem_block) @@ -411,8 +425,10 @@ static void delete_block(codeblock_t *block) if (block == &codeblock[codeblock_hash[HASH(block->phys)]]) codeblock_hash[HASH(block->phys)] = BLOCK_INVALID; +#ifndef RELEASE_BUILD if (block->pc == BLOCK_PC_INVALID) fatal("Deleting deleted block\n"); +#endif block->pc = BLOCK_PC_INVALID; codeblock_tree_delete(block); @@ -431,8 +447,10 @@ static void delete_dirty_block(codeblock_t *block) if (block == &codeblock[codeblock_hash[HASH(block->phys)]]) codeblock_hash[HASH(block->phys)] = BLOCK_INVALID; +#ifndef RELEASE_BUILD if (block->pc == BLOCK_PC_INVALID) fatal("Deleting deleted block\n"); +#endif block->pc = BLOCK_PC_INVALID; codeblock_tree_delete(block); @@ -448,7 +466,7 @@ void codegen_delete_block(codeblock_t *block) void codegen_delete_random_block(int required_mem_block) { int block_nr = rand() & BLOCK_MASK; - + while (1) { if (block_nr && block_nr != block_current) @@ -475,19 +493,20 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) { codeblock_t *block = &codeblock[block_nr]; uint16_t next_block = block->next; - + if (*block->dirty_mask & block->page_mask) { invalidate_block(block); - cpu_recomp_evicted++; } +#ifndef RELEASE_BUILD if (block_nr == next_block) fatal("Broken 1\n"); +#endif block_nr = next_block; } block_nr = page->block_2; - + while (block_nr) { codeblock_t *block = &codeblock[block_nr]; @@ -496,18 +515,19 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) if (*block->dirty_mask2 & block->page_mask2) { invalidate_block(block); - cpu_recomp_evicted++; } +#ifndef RELEASE_BUILD if (block_nr == next_block) fatal("Broken 2\n"); +#endif block_nr = next_block; } - + if (page->code_present_mask & page->dirty_mask) remove_from_evict_list = 1; page->code_present_mask &= ~page->dirty_mask; page->dirty_mask = 0; - + for (c = 0; c < 64; c++) { if (page->byte_code_present_mask[c] & page->byte_dirty_mask[c]) @@ -527,8 +547,10 @@ void codegen_block_init(uint32_t phys_addr) if (!page->block) mem_flush_write_page(phys_addr, cs+cpu_state.pc); block = block_free_list_get(); +#ifndef RELEASE_BUILD if (!block) fatal("codegen_block_init: block_free_list_get() returned NULL\n"); +#endif block_current = get_block_nr(block); block_num = HASH(phys_addr); @@ -545,7 +567,7 @@ void codegen_block_init(uint32_t phys_addr) block->page_mask = block->page_mask2 = 0; block->flags = CODEBLOCK_STATIC_TOP; block->status = cpu_cur_status; - + recomp_page = block->phys & ~0xfff; codeblock_tree_add(block); } @@ -567,14 +589,16 @@ void codegen_block_start_recompile(codeblock_t *block) block_num = HASH(block->phys); block_current = get_block_nr(block);//block->pnt; +#ifndef RELEASE_BUILD if (block->pc != cs + cpu_state.pc || (block->flags & CODEBLOCK_WAS_RECOMPILED)) fatal("Recompile to used block!\n"); +#endif block->head_mem_block = codegen_allocator_allocate(NULL, block_current); block->data = codeblock_allocator_get_ptr(block->head_mem_block); block->status = cpu_cur_status; - + block->page_mask = block->page_mask2 = 0; block->ins = 0; @@ -583,30 +607,30 @@ void codegen_block_start_recompile(codeblock_t *block) last_op32 = -1; last_ea_seg = NULL; last_ssegs = -1; - + codegen_block_cycles = 0; codegen_timing_block_start(); - + codegen_block_ins = 0; codegen_block_full_ins = 0; recomp_page = block->phys & ~0xfff; - + codegen_flags_changed = 0; codegen_fpu_entered = 0; codegen_mmx_entered = 0; codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; - + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; block->TOP = cpu_state.TOP & 7; block->flags |= CODEBLOCK_WAS_RECOMPILED; codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); - codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); - + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); + if (block->flags & CODEBLOCK_BYTE_MASK) { block->dirty_mask = &page->byte_dirty_mask[(block->phys >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK]; @@ -626,7 +650,6 @@ void codegen_block_remove() codeblock_t *block = &codeblock[block_current]; delete_block(block); - cpu_recomp_removed++; recomp_page = -1; } @@ -661,7 +684,7 @@ void codegen_block_generate_end_mask_recompile() if (block->flags & CODEBLOCK_BYTE_MASK) { int offset = (block->phys_2 >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; - + page_2->byte_code_present_mask[offset] |= block->page_mask2; block->dirty_mask2 = &page_2->byte_dirty_mask[offset]; } @@ -676,6 +699,7 @@ void codegen_block_generate_end_mask_recompile() if (!pages[block->phys_2 >> 12].block_2) mem_flush_write_page(block->phys_2, codegen_endpc); +#ifndef RELEASE_BUILD if (!block->page_mask2) fatal("!page_mask2\n"); if (block->next_2) @@ -683,6 +707,7 @@ void codegen_block_generate_end_mask_recompile() if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); } +#endif } else { @@ -703,8 +728,10 @@ void codegen_block_generate_end_mask_mark() uint32_t end_pc; page_t *p; +#ifndef RELEASE_BUILD if (block->flags & CODEBLOCK_BYTE_MASK) fatal("codegen_block_generate_end_mask2() - BYTE_MASK\n"); +#endif block->page_mask = 0; start_pc = (block->pc & 0xfff) & ~63; @@ -749,6 +776,7 @@ void codegen_block_generate_end_mask_mark() if (!pages[block->phys_2 >> 12].block_2) mem_flush_write_page(block->phys_2, codegen_endpc); +#ifndef RELEASE_BUILD if (!block->page_mask2) fatal("!page_mask2\n"); if (block->next_2) @@ -756,7 +784,7 @@ void codegen_block_generate_end_mask_mark() if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); } - +#endif block->dirty_mask2 = &page_2->dirty_mask; } else @@ -782,7 +810,7 @@ void codegen_block_end() void codegen_block_end_recompile(codeblock_t *block) { codegen_timing_block_end(); - codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); + codegen_accumulate(ir_data, ACCREG_cycles, -codegen_block_cycles); if (block->flags & CODEBLOCK_IN_DIRTY_LIST) block_dirty_list_remove(block); diff --git a/src/codegen_new/codegen_ir.c b/src/codegen_new/codegen_ir.c index aa27f206e..49a7adac5 100644 --- a/src/codegen_new/codegen_ir.c +++ b/src/codegen_new/codegen_ir.c @@ -48,7 +48,7 @@ static void duplicate_uop(ir_data_t *ir, uop_t *uop, int offset) new_uop->imm_data = uop->imm_data; new_uop->p = uop->p; new_uop->pc = uop->pc; - + if (uop->jump_dest_uop != -1) { new_uop->jump_dest_uop = uop->jump_dest_uop + offset; @@ -64,15 +64,17 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) { int unroll_count; int unroll_end; - + codegen_set_loop_start(ir, codegen_unroll_first_instruction); unroll_end = ir->wr_pos; - + for (unroll_count = 1; unroll_count < codegen_unroll_count; unroll_count++) { int offset = ir->wr_pos - codegen_unroll_start; +// pclog("Unroll from %i to %i, offset %i - iteration %i\n", codegen_unroll_start, ir->wr_pos, offset, unroll_count); for (c = codegen_unroll_start; c < unroll_end; c++) { +// pclog(" Duplicate uop %i\n", c); duplicate_uop(ir, &ir->uops[c], offset); } } @@ -88,6 +90,8 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) { uop_t *uop = &ir->uops[c]; +// pclog("uOP %i : %08x\n", c, uop->type); + if (uop->type & UOP_TYPE_BARRIER) codegen_reg_flush_invalidate(ir, block); @@ -105,37 +109,61 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) if ((uop->type & UOP_MASK) == UOP_INVALID) continue; - if (uop->type & UOP_TYPE_PARAMS_REGS) +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM + if ((uop->type & UOP_MASK) == (UOP_MOV_IMM & UOP_MASK) && reg_is_native_size(uop->dest_reg_a) && !codegen_reg_is_loaded(uop->dest_reg_a) && reg_version[IREG_GET_REG(uop->dest_reg_a.reg)][uop->dest_reg_a.version].refcount <= 0) { - codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c); - if (uop->src_reg_a.reg != IREG_INVALID) - { - uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); - } - if (uop->src_reg_b.reg != IREG_INVALID) - { - uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL); - } - if (uop->src_reg_c.reg != IREG_INVALID) - { - uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL); - } + /*Special case for UOP_MOV_IMM - if destination not already in host register + and won't be used again then just store directly to memory*/ + codegen_reg_write_imm(block, uop->dest_reg_a, uop->imm_data); } - - if (uop->type & UOP_TYPE_ORDER_BARRIER) - codegen_reg_flush(ir, block); + else +#endif + if ((uop->type & UOP_MASK) == (UOP_MOV & UOP_MASK) && reg_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version].refcount <= 1 && + reg_is_native_size(uop->src_reg_a) && reg_is_native_size(uop->dest_reg_a)) + { + /*Special case for UOP_MOV - if source register won't be used again then + just rename it to dest register instead of moving*/ + codegen_reg_alloc_register(invalid_ir_reg, uop->src_reg_a, invalid_ir_reg, invalid_ir_reg); + uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); + codegen_reg_rename(block, uop->src_reg_a, uop->dest_reg_a); + if (uop->type & UOP_TYPE_ORDER_BARRIER) + codegen_reg_flush(ir, block); + } + else + { + if (uop->type & UOP_TYPE_PARAMS_REGS) + { + codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c); + if (uop->src_reg_a.reg != IREG_INVALID) + { + uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL); + } + if (uop->src_reg_c.reg != IREG_INVALID) + { + uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL); + } + } - if (uop->type & UOP_TYPE_PARAMS_REGS) - { - if (uop->dest_reg_a.reg != IREG_INVALID) + if (uop->type & UOP_TYPE_ORDER_BARRIER) + codegen_reg_flush(ir, block); + + if (uop->type & UOP_TYPE_PARAMS_REGS) { - uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); + if (uop->dest_reg_a.reg != IREG_INVALID) + { + uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); + } } +#ifndef RELEASE_BUILD + if (!uop_handlers[uop->type & UOP_MASK]) + fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type); +#endif + uop_handlers[uop->type & UOP_MASK](block, uop); } - - if (!uop_handlers[uop->type & UOP_MASK]) - fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type); - uop_handlers[uop->type & UOP_MASK](block, uop); if (uop->type & UOP_TYPE_JUMP) { @@ -156,7 +184,7 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) else { uop_t *uop_dest = &ir->uops[uop->jump_dest_uop]; - + while (uop_dest->jump_list_next != -1) uop_dest = &ir->uops[uop_dest->jump_list_next]; @@ -167,7 +195,7 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) } codegen_reg_flush_invalidate(ir, block); - + if (jump_target_at_end != -1) { uop_t *uop_dest = &ir->uops[jump_target_at_end]; diff --git a/src/codegen_new/codegen_ir_defs.h b/src/codegen_new/codegen_ir_defs.h index 9d6c0e69d..30bf44d98 100644 --- a/src/codegen_new/codegen_ir_defs.h +++ b/src/codegen_new/codegen_ir_defs.h @@ -9,7 +9,7 @@ All registers must have been written back or discarded. This should be used when calling external functions that may change any emulated registers.*/ -#define UOP_TYPE_BARRIER (1 << 31) +#define UOP_TYPE_BARRIER (1u << 31) /*uOP is a barrier. All previous uOPs must have completed before this one executes. All registers must have been written back, but do not have to be discarded. @@ -55,6 +55,7 @@ /*UOP_JMP_DEST - jump to ptr*/ #define UOP_JMP_DEST (UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x17 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) #define UOP_NOP_BARRIER (UOP_TYPE_BARRIER | 0x18) +#define UOP_STORE_P_IMM_16 (UOP_TYPE_PARAMS_IMM | 0x19) #ifdef DEBUG_EXTRA /*UOP_LOG_INSTR - log non-recompiled instruction in imm_data*/ @@ -360,19 +361,19 @@ typedef struct ir_data_t static inline uop_t *uop_alloc(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->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; @@ -385,7 +386,7 @@ static inline uop_t *uop_alloc(ir_data_t *ir, uint32_t uop_type) static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop) { uop_t *uop = &ir->uops[jump_uop]; - + uop->jump_dest_uop = ir->wr_pos; } @@ -401,7 +402,7 @@ static inline int uop_gen(uint32_t uop_type, ir_data_t *ir) static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a) { uop_t *uop = uop_alloc(ir, uop_type); - + uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -423,7 +424,7 @@ static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg); uop->imm_data = imm; - + return ir->wr_pos-1; } @@ -513,7 +514,7 @@ static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); uop->src_reg_b = codegen_reg_read(src_reg_b); - + return ir->wr_pos-1; } @@ -551,7 +552,7 @@ static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int sr static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) { uop_t *uop = uop_alloc(ir, uop_type); - + uop->type = uop_type; uop->imm_data = imm; } @@ -559,7 +560,7 @@ static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p) { uop_t *uop = uop_alloc(ir, uop_type); - + uop->type = uop_type; uop->p = p; } @@ -567,7 +568,7 @@ static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p) static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p, uint32_t imm) { uop_t *uop = uop_alloc(ir, uop_type); - + uop->type = uop_type; uop->p = p; uop->imm_data = imm; @@ -765,6 +766,7 @@ static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, in #define uop_STORE_PTR_IMM(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM, ir, p, imm) #define uop_STORE_PTR_IMM_8(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_8, ir, p, imm) +#define uop_STORE_PTR_IMM_16(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_16, ir, p, imm) #define uop_TEST_JNS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JNS_DEST, ir, src_reg) #define uop_TEST_JS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JS_DEST, ir, src_reg) @@ -807,4 +809,9 @@ void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int void codegen_set_jump_dest(codeblock_t *block, void *p); +void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data); +void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data); +void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data); +void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data); + #endif diff --git a/src/codegen_new/codegen_ops.c b/src/codegen_new/codegen_ops.c index a1570fc31..1e7183fff 100644 --- a/src/codegen_new/codegen_ops.c +++ b/src/codegen_new/codegen_ops.c @@ -85,8 +85,13 @@ RecompOpFn recomp_opcodes_0f[512] = /*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM || defined __aarch64__ || defined _M_ARM64 +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#else /*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_r_d, ropMOVQ_r_q, /*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_d_r, ropMOVQ_q_r, +#endif /*80*/ ropJO_16, ropJNO_16, ropJB_16, ropJNB_16, ropJE_16, ropJNE_16, ropJBE_16, ropJNBE_16, ropJS_16, ropJNS_16, ropJP_16, ropJNP_16, ropJL_16, ropJNL_16, ropJLE_16, ropJNLE_16, /*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -94,9 +99,15 @@ RecompOpFn recomp_opcodes_0f[512] = /*b0*/ NULL, NULL, ropLSS_16, NULL, ropLFS_16, ropLGS_16, ropMOVZX_16_8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_16_8, NULL, /*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM || defined __aarch64__ || defined _M_ARM64 +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#else /*d0*/ NULL, NULL, NULL, NULL, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, /*e0*/ NULL, NULL, NULL, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, /*f0*/ NULL, NULL, NULL, NULL, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +#endif /*32-bit data*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -107,8 +118,13 @@ RecompOpFn recomp_opcodes_0f[512] = /*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM || defined __aarch64__ || defined _M_ARM64 +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#else /*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_r_d, ropMOVQ_r_q, /*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_d_r, ropMOVQ_q_r, +#endif /*80*/ ropJO_32, ropJNO_32, ropJB_32, ropJNB_32, ropJE_32, ropJNE_32, ropJBE_32, ropJNBE_32, ropJS_32, ropJNS_32, ropJP_32, ropJNP_32, ropJL_32, ropJNL_32, ropJLE_32, ropJNLE_32, /*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -116,13 +132,22 @@ RecompOpFn recomp_opcodes_0f[512] = /*b0*/ NULL, NULL, ropLSS_32, NULL, ropLFS_32, ropLGS_32, ropMOVZX_32_8, ropMOVZX_32_16, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_32_8, ropMOVSX_32_16, /*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM || defined __aarch64__ || defined _M_ARM64 +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#else /*d0*/ NULL, NULL, NULL, NULL, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, /*e0*/ NULL, NULL, NULL, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, /*f0*/ NULL, NULL, NULL, NULL, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +#endif }; RecompOpFn recomp_opcodes_3DNOW[256] = { +#if defined __ARM_EABI__ || defined _ARM_ || defined _M_ARM || defined __aarch64__ || defined _M_ARM64 +0 +#else /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPI2FD, NULL, NULL, /*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPF2ID, NULL, NULL, @@ -143,6 +168,7 @@ RecompOpFn recomp_opcodes_3DNOW[256] = /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#endif }; RecompOpFn recomp_opcodes_d8[512] = diff --git a/src/codegen_new/codegen_ops_arith.c b/src/codegen_new/codegen_ops_arith.c index 576cf7719..66715730d 100644 --- a/src/codegen_new/codegen_ops_arith.c +++ b/src/codegen_new/codegen_ops_arith.c @@ -309,7 +309,7 @@ uint32_t ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32 uint32_t ropADD_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { uop_MOV(ir, IREG_flags_op1, IREG_EAX); - + if (block->flags & CODEBLOCK_NO_IMMEDIATES) { LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); @@ -337,7 +337,7 @@ uint32_t ropADD_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t if ((fetchdat & 0xc0) == 0xc0) { int src_reg = fetchdat & 7; - + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); @@ -1283,7 +1283,7 @@ uint32_t rop80(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetch { int dest_reg = fetchdat & 7; uint8_t imm = fastreadb(cs + op_pc + 1); - + if (block->flags & CODEBLOCK_NO_IMMEDIATES) { skip_immediate = 1; @@ -1779,7 +1779,7 @@ uint32_t rop81_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { int skip_immediate = 0; - + codegen_mark_code_present(block, cs+op_pc, 1); if ((fetchdat & 0xc0) == 0xc0) { @@ -1836,7 +1836,7 @@ uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); break; - + case 0x18: /*SBB*/ get_cf(ir, IREG_temp1); uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); @@ -1954,7 +1954,7 @@ uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_MOV(ir, IREG_flags_res, IREG_temp0); uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); break; - + case 0x10: /*ADC*/ get_cf(ir, IREG_temp3); if (block->flags & CODEBLOCK_NO_IMMEDIATES) @@ -2157,7 +2157,7 @@ uint32_t rop83_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); break; - + case 0x10: /*ADC*/ get_cf(ir, IREG_temp2); uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); @@ -2227,7 +2227,7 @@ uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet { int dest_reg = fetchdat & 7; uint32_t imm = (int32_t)(int8_t)fastreadb(cs + op_pc + 1); - + switch (fetchdat & 0x38) { case 0x00: /*ADD*/ @@ -2243,7 +2243,7 @@ uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); break; - + case 0x10: /*ADC*/ get_cf(ir, IREG_temp1); uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); @@ -2299,7 +2299,7 @@ uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet { x86seg *target_seg; uint32_t imm; - + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); if ((fetchdat & 0x38) == 0x38) /*CMP*/ @@ -2326,7 +2326,7 @@ uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_MOV(ir, IREG_flags_res, IREG_temp0); uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); break; - + case 0x10: /*ADC*/ get_cf(ir, IREG_temp2); uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); @@ -2392,7 +2392,7 @@ uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet static void rebuild_c(ir_data_t *ir) { int needs_rebuild = 1; - + if (codegen_flags_changed) { switch (cpu_state.flags_op) @@ -2403,7 +2403,7 @@ static void rebuild_c(ir_data_t *ir) break; } } - + if (needs_rebuild) { uop_CALL_FUNC(ir, flags_rebuild_c); @@ -2426,7 +2426,7 @@ uint32_t ropINC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uint32_t ropINC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { rebuild_c(ir); - + uop_MOV(ir, IREG_flags_op1, IREG_32(opcode & 7)); uop_ADD_IMM(ir, IREG_32(opcode & 7), IREG_32(opcode & 7), 1); uop_MOV(ir, IREG_flags_res, IREG_32(opcode & 7)); @@ -2468,7 +2468,7 @@ uint32_t ropINCDEC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f { codegen_mark_code_present(block, cs+op_pc, 1); rebuild_c(ir); - + if ((fetchdat & 0xc0) == 0xc0) { uop_MOVZX(ir, IREG_flags_op1, IREG_8(fetchdat & 7)); diff --git a/src/codegen_new/codegen_ops_branch.c b/src/codegen_new/codegen_ops_branch.c index 88c30f2af..b05ce5bac 100644 --- a/src/codegen_new/codegen_ops_branch.c +++ b/src/codegen_new/codegen_ops_branch.c @@ -622,7 +622,7 @@ static int ropJNL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, { int jump_uop; int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr)); - + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { case FLAGS_ZN8: diff --git a/src/codegen_new/codegen_ops_fpu_arith.c b/src/codegen_new/codegen_ops_fpu_arith.c index 3500397e3..598f63b80 100644 --- a/src/codegen_new/codegen_ops_fpu_arith.c +++ b/src/codegen_new/codegen_ops_fpu_arith.c @@ -21,7 +21,7 @@ uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_FP_ENTER(ir); uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); - + return op_pc; } uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) @@ -42,7 +42,7 @@ uint32_t ropFADDP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fe uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); fpu_POP(block, ir); - + return op_pc; } @@ -128,7 +128,7 @@ uint32_t ropFDIVP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fe uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); fpu_POP(block, ir); - + return op_pc; } uint32_t ropFDIVRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) @@ -234,7 +234,7 @@ uint32_t ropFSUBRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); fpu_POP(block, ir); - + return op_pc; } @@ -277,8 +277,8 @@ uint32_t ropFADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint { \ x86seg *target_seg; \ \ - if ((cpu_state.npxc >> 10) & 3) \ - return 0; \ + if ((cpu_state.npxc >> 10) & 3) \ + return 0; \ uop_FP_ENTER(ir); \ uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ op_pc--; \ diff --git a/src/codegen_new/codegen_ops_fpu_constant.c b/src/codegen_new/codegen_ops_fpu_constant.c index a9888f9b3..fc59ae784 100644 --- a/src/codegen_new/codegen_ops_fpu_constant.c +++ b/src/codegen_new/codegen_ops_fpu_constant.c @@ -31,6 +31,6 @@ uint32_t ropFLDZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); fpu_PUSH(block, ir); - + return op_pc; } diff --git a/src/codegen_new/codegen_ops_fpu_misc.c b/src/codegen_new/codegen_ops_fpu_misc.c index 2aea3678b..cfe2ff698 100644 --- a/src/codegen_new/codegen_ops_fpu_misc.c +++ b/src/codegen_new/codegen_ops_fpu_misc.c @@ -91,7 +91,7 @@ uint32_t ropFSTSW_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t { uop_FP_ENTER(ir); uop_MOV(ir, IREG_AX, IREG_NPXS); - + return op_pc; } diff --git a/src/codegen_new/codegen_ops_helpers.c b/src/codegen_new/codegen_ops_helpers.c index 41450151d..9c2280f07 100644 --- a/src/codegen_new/codegen_ops_helpers.c +++ b/src/codegen_new/codegen_ops_helpers.c @@ -52,17 +52,17 @@ int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, return 0; } else - { + { start = ir->wr_pos; - TOP = cpu_state.TOP; - } + TOP = cpu_state.TOP; + } } - if (TOP != cpu_state.TOP) - return 0; + if (TOP != cpu_state.TOP) + return 0; max_unroll = UNROLL_MAX_UOPS / ((ir->wr_pos-start)+6); - if (max_unroll > (UNROLL_MAX_REG_REFERENCES / max_version_refcount)) + if ((max_version_refcount != 0) && (max_unroll > (UNROLL_MAX_REG_REFERENCES / max_version_refcount))) max_unroll = (UNROLL_MAX_REG_REFERENCES / max_version_refcount); if (max_unroll > UNROLL_MAX_COUNT) max_unroll = UNROLL_MAX_COUNT; diff --git a/src/codegen_new/codegen_ops_jump.c b/src/codegen_new/codegen_ops_jump.c index f56018d76..f672b40ca 100644 --- a/src/codegen_new/codegen_ops_jump.c +++ b/src/codegen_new/codegen_ops_jump.c @@ -13,7 +13,7 @@ uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { - int32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); uint32_t dest_addr = op_pc+1+offset; if (!(op_32 & 0x100)) @@ -26,9 +26,9 @@ uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f } uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { - int32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); uint32_t dest_addr = op_pc+2+offset; - + dest_addr &= 0xffff; if (offset < 0) @@ -38,9 +38,9 @@ uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t } uint32_t ropJMP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { - int32_t offset = fastreadl(cs + op_pc); + uint32_t offset = fastreadl(cs + op_pc); uint32_t dest_addr = op_pc+4+offset; - + if (offset < 0) codegen_can_unroll(block, ir, op_pc+1, dest_addr); codegen_mark_code_present(block, cs+op_pc, 4); @@ -100,13 +100,13 @@ uint32_t ropCALL_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uint32_t ret_addr = op_pc + 4; uint32_t dest_addr = ret_addr + offset; int sp_reg; - + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, ret_addr); SUB_SP(ir, 4); uop_MOV_IMM(ir, IREG_pc, dest_addr); - + codegen_mark_code_present(block, cs+op_pc, 4); return -1; } @@ -114,7 +114,7 @@ uint32_t ropCALL_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uint32_t ropRET_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); - + if (stack32) uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); else @@ -130,7 +130,7 @@ uint32_t ropRET_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f uint32_t ropRET_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); - + if (stack32) uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_ESP); else @@ -146,7 +146,7 @@ uint32_t ropRET_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f uint32_t ropRET_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { uint16_t offset = fastreadw(cs + op_pc); - + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); if (stack32) @@ -267,7 +267,7 @@ uint32_t ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) return 0; - + offset = fastreadw(cs + op_pc); uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); diff --git a/src/codegen_new/codegen_ops_logic.c b/src/codegen_new/codegen_ops_logic.c index 5d50423c1..dd02bd3f9 100644 --- a/src/codegen_new/codegen_ops_logic.c +++ b/src/codegen_new/codegen_ops_logic.c @@ -64,7 +64,7 @@ uint32_t ropAND_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t if ((fetchdat & 0xc0) == 0xc0) { int src_reg = fetchdat & 7; - + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); } else diff --git a/src/codegen_new/codegen_ops_misc.c b/src/codegen_new/codegen_ops_misc.c index c4aae7598..adb478d13 100644 --- a/src/codegen_new/codegen_ops_misc.c +++ b/src/codegen_new/codegen_ops_misc.c @@ -22,13 +22,13 @@ uint32_t ropLEA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f codegen_mark_code_present(block, cs+op_pc, 1); codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); uop_MOV(ir, IREG_16(dest_reg), IREG_eaaddr_W); - + return op_pc + 1; } uint32_t ropLEA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { int dest_reg = (fetchdat >> 3) & 7; - + if ((fetchdat & 0xc0) == 0xc0) return 0; @@ -44,7 +44,7 @@ uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetch x86seg *target_seg = NULL; uint8_t imm_data; int reg; - + if (fetchdat & 0x20) return 0; @@ -67,7 +67,7 @@ uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetch { case 0x00: case 0x08: /*TEST*/ imm_data = fastreadb(cs + op_pc + 1); - + uop_AND_IMM(ir, IREG_flags_res_B, reg, imm_data); uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); @@ -75,7 +75,7 @@ uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetch codegen_flags_changed = 1; codegen_mark_code_present(block, cs+op_pc+1, 1); return op_pc+2; - + case 0x10: /*NOT*/ uop_XOR_IMM(ir, reg, reg, 0xff); if ((fetchdat & 0xc0) != 0xc0) @@ -321,7 +321,7 @@ uint32_t ropFF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fe uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); } return op_pc+1; - + case 0x08: /*DEC*/ rebuild_c(ir); codegen_flags_changed = 1; @@ -357,7 +357,7 @@ uint32_t ropFF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fe case 0x20: /*JMP*/ uop_MOVZX(ir, IREG_pc, src_reg); return -1; - + case 0x28: /*JMP far*/ uop_MOVZX(ir, IREG_pc, src_reg); uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); diff --git a/src/codegen_new/codegen_ops_mmx_loadstore.c b/src/codegen_new/codegen_ops_mmx_loadstore.c index 94c46f86a..ebdf81555 100644 --- a/src/codegen_new/codegen_ops_mmx_loadstore.c +++ b/src/codegen_new/codegen_ops_mmx_loadstore.c @@ -41,6 +41,9 @@ uint32_t ropMOVD_d_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t { int src_reg = (fetchdat >> 3) & 7; + if (cpu_iscyrix && in_smm) + return 0; + uop_MMX_ENTER(ir); codegen_mark_code_present(block, cs+op_pc, 1); if ((fetchdat & 0xc0) == 0xc0) diff --git a/src/codegen_new/codegen_ops_mov.c b/src/codegen_new/codegen_ops_mov.c index a5618f354..eb748a027 100644 --- a/src/codegen_new/codegen_ops_mov.c +++ b/src/codegen_new/codegen_ops_mov.c @@ -242,7 +242,7 @@ uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 uop_MEM_LOAD_REG(ir, IREG_EAX, ireg_seg_base(op_ea_seg), IREG_eaaddr); else uop_MEM_LOAD_ABS(ir, IREG_EAX, ireg_seg_base(op_ea_seg), addr); - + return op_pc + ((op_32 & 0x200) ? 4 : 2); } @@ -421,7 +421,7 @@ uint32_t ropMOV_w_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_ uint32_t ropMOV_l_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { int src_reg; - + codegen_mark_code_present(block, cs+op_pc, 1); switch (fetchdat & 0x38) { @@ -490,7 +490,7 @@ uint32_t ropMOV_seg_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_ } uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); - + if ((fetchdat & 0xc0) == 0xc0) { uop_MOV(ir, IREG_temp0_W, IREG_16(fetchdat & 7)); @@ -655,11 +655,11 @@ uint32_t ropMOVZX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 uint32_t ropXCHG_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { int reg2 = IREG_16(opcode & 7); - + uop_MOV(ir, IREG_temp0_W, IREG_AX); uop_MOV(ir, IREG_AX, reg2); uop_MOV(ir, reg2, IREG_temp0_W); - + return op_pc; } uint32_t ropXCHG_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) @@ -681,7 +681,7 @@ uint32_t ropXCHG_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f if ((fetchdat & 0xc0) == 0xc0) { int reg2 = IREG_8(fetchdat & 7); - + uop_MOV(ir, IREG_temp0_B, reg1); uop_MOV(ir, reg1, reg2); uop_MOV(ir, reg2, IREG_temp0_B); @@ -693,7 +693,7 @@ uint32_t ropXCHG_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); codegen_check_seg_write(block, ir, target_seg); - + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); uop_MOV(ir, reg1, IREG_temp0_B); @@ -761,7 +761,7 @@ uint32_t ropXCHG_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uint32_t ropXLAT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); - + uop_MOVZX(ir, IREG_eaaddr, IREG_AL); uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, IREG_EBX); if (!(op_32 & 0x200)) diff --git a/src/codegen_new/codegen_ops_shift.c b/src/codegen_new/codegen_ops_shift.c index de9a0fecf..370585bf2 100644 --- a/src/codegen_new/codegen_ops_shift.c +++ b/src/codegen_new/codegen_ops_shift.c @@ -58,7 +58,7 @@ static uint32_t shift_common_8(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); break; - + default: return 0; } @@ -454,7 +454,7 @@ uint32_t ropC0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetch } imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (imm) return shift_common_8(ir, fetchdat, op_pc, target_seg, imm) + 1; return op_pc+1; @@ -477,7 +477,7 @@ uint32_t ropC1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet } imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (imm) return shift_common_16(ir, fetchdat, op_pc, target_seg, imm) + 1; return op_pc+1; @@ -501,7 +501,7 @@ uint32_t ropC1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet { uint32_t new_pc; int jump_uop; - + LOAD_IMMEDIATE_FROM_RAM_8(block, ir, IREG_temp2, cs + op_pc + 1); uop_AND_IMM(ir, IREG_temp2, IREG_temp2, 0x1f); jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp2, 0); @@ -515,7 +515,7 @@ uint32_t ropC1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet { uint8_t imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (imm) return shift_common_32(ir, fetchdat, op_pc, target_seg, imm) + 1; } @@ -584,7 +584,7 @@ uint32_t ropD2(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetch if (!(CL & 0x1f) || !block->ins) return 0; - + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); @@ -706,7 +706,7 @@ uint32_t ropD3_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fet if (!(CL & 0x1f) || !block->ins) return 0; - + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); @@ -958,7 +958,7 @@ uint32_t ropSHLD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 } imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (!imm) return op_pc+2; @@ -1006,7 +1006,7 @@ uint32_t ropSHLD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 } imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (!imm) return op_pc+2; @@ -1054,7 +1054,7 @@ uint32_t ropSHRD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 } imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (!imm) return op_pc+2; @@ -1102,7 +1102,7 @@ uint32_t ropSHRD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint3 } imm = fastreadb(cs + op_pc + 1) & 0x1f; codegen_mark_code_present(block, cs+op_pc+1, 1); - + if (!imm) return op_pc+2; diff --git a/src/codegen_new/codegen_ops_stack.c b/src/codegen_new/codegen_ops_stack.c index 1bb791a3b..ff421488e 100644 --- a/src/codegen_new/codegen_ops_stack.c +++ b/src/codegen_new/codegen_ops_stack.c @@ -141,7 +141,7 @@ uint32_t ropPOP_W(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fe { x86seg *target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 2); codegen_check_seg_write(block, ir, target_seg); - + if (stack32) uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); else @@ -340,7 +340,7 @@ uint32_t ropPUSHA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t uint32_t ropPOPA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) { int sp_reg; - + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); sp_reg = LOAD_SP(ir); uop_MEM_LOAD_REG(ir, IREG_DI, IREG_SS_base, sp_reg); diff --git a/src/codegen_new/codegen_reg.c b/src/codegen_new/codegen_reg.c index f986104f1..6b0cc0fd3 100644 --- a/src/codegen_new/codegen_reg.c +++ b/src/codegen_new/codegen_reg.c @@ -92,12 +92,14 @@ struct [IREG_op32] = {REG_DWORD, &cpu_state.op32, REG_INTEGER, REG_PERMANENT}, [IREG_ssegsx] = {REG_BYTE, &cpu_state.ssegs, REG_INTEGER, REG_PERMANENT}, - + [IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data, REG_INTEGER, REG_PERMANENT}, - [IREG_ins] = {REG_DWORD, &cpu_state.cpu_recomp_ins, REG_INTEGER, REG_PERMANENT}, +#ifdef USE_ACYCS + [IREG_acycs] = {REG_DWORD, &acycs, REG_INTEGER, REG_PERMANENT}, +#endif [IREG_cycles] = {REG_DWORD, &cpu_state._cycles, REG_INTEGER, REG_PERMANENT}, - + [IREG_CS_base] = {REG_DWORD, &cpu_state.seg_cs.base, REG_INTEGER, REG_PERMANENT}, [IREG_DS_base] = {REG_DWORD, &cpu_state.seg_ds.base, REG_INTEGER, REG_PERMANENT}, [IREG_ES_base] = {REG_DWORD, &cpu_state.seg_es.base, REG_INTEGER, REG_PERMANENT}, @@ -111,7 +113,7 @@ struct [IREG_FS_seg] = {REG_WORD, &cpu_state.seg_fs.seg, REG_INTEGER, REG_PERMANENT}, [IREG_GS_seg] = {REG_WORD, &cpu_state.seg_gs.seg, REG_INTEGER, REG_PERMANENT}, [IREG_SS_seg] = {REG_WORD, &cpu_state.seg_ss.seg, REG_INTEGER, REG_PERMANENT}, - + [IREG_FPU_TOP] = {REG_DWORD, &cpu_state.TOP, REG_INTEGER, REG_PERMANENT}, [IREG_ST0] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, @@ -122,7 +124,7 @@ struct [IREG_ST5] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, [IREG_ST6] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, [IREG_ST7] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, - + [IREG_tag0] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, [IREG_tag1] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, [IREG_tag2] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, @@ -149,7 +151,7 @@ struct [IREG_MM5x] = {REG_QWORD, &cpu_state.MM[5], REG_FP, REG_PERMANENT}, [IREG_MM6x] = {REG_QWORD, &cpu_state.MM[6], REG_FP, REG_PERMANENT}, [IREG_MM7x] = {REG_QWORD, &cpu_state.MM[7], REG_FP, REG_PERMANENT}, - + [IREG_NPXCx] = {REG_WORD, &cpu_state.npxc, REG_INTEGER, REG_PERMANENT}, [IREG_NPXSx] = {REG_WORD, &cpu_state.npxs, REG_INTEGER, REG_PERMANENT}, @@ -177,7 +179,7 @@ struct [IREG_temp1] = {REG_DWORD, (void *)20, REG_INTEGER, REG_VOLATILE}, [IREG_temp2] = {REG_DWORD, (void *)24, REG_INTEGER, REG_VOLATILE}, [IREG_temp3] = {REG_DWORD, (void *)28, REG_INTEGER, REG_VOLATILE}, - + [IREG_temp0d] = {REG_DOUBLE, (void *)40, REG_FP, REG_VOLATILE}, [IREG_temp1d] = {REG_DOUBLE, (void *)48, REG_FP, REG_VOLATILE}, }; @@ -185,11 +187,11 @@ struct void codegen_reg_mark_as_required() { int reg; - + for (reg = 0; reg < IREG_COUNT; reg++) { int last_version = reg_last_version[reg]; - + if (last_version > 0 && ireg_data[reg].is_volatile == REG_PERMANENT) reg_version[reg][last_version].flags |= REG_FLAGS_REQUIRED; } @@ -199,7 +201,7 @@ int 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: @@ -214,11 +216,11 @@ int reg_is_native_size(ir_reg_t ir_reg) 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; } @@ -252,7 +254,7 @@ void codegen_reg_reset() host_fp_reg_set.regs[c] = invalid_ir_reg; host_fp_reg_set.dirty[c] = 0; } - + reg_dead_list = 0; max_version_refcount = 0; } @@ -275,78 +277,95 @@ static void codegen_reg_load(host_reg_set_t *reg_set, codeblock_t *block, int c, switch (ireg_data[IREG_GET_REG(ir_reg.reg)].native_size) { case REG_WORD: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) - fatal("codegen_reg_load - REG_WORD !REG_INTEGER\n"); - if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_16_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); - else +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_WORD !REG_INTEGER\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_16_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else codegen_direct_read_16(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); - break; - - case REG_DWORD: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) - fatal("codegen_reg_load - REG_DWORD !REG_INTEGER\n"); - if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_32_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); - else + break; + + case REG_DWORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_DWORD !REG_INTEGER\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_32_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else codegen_direct_read_32(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); - break; - - case REG_QWORD: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) - fatal("codegen_reg_load - REG_QWORD !REG_FP\n"); - if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_64_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); - else + break; + + case REG_QWORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_QWORD !REG_FP\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_64_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else codegen_direct_read_64(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); - break; - - case REG_POINTER: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) - fatal("codegen_reg_load - REG_POINTER !REG_INTEGER\n"); - if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_pointer_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); - else + break; + + case REG_POINTER: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_POINTER !REG_INTEGER\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_pointer_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else codegen_direct_read_pointer(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); - break; - - case REG_DOUBLE: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) - fatal("codegen_reg_load - REG_DOUBLE !REG_FP\n"); - if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_double_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); - else + break; + + case REG_DOUBLE: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_DOUBLE !REG_FP\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_double_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else codegen_direct_read_double(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); - break; - - case REG_FPU_ST_BYTE: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) - fatal("codegen_reg_load - REG_FPU_ST_BYTE !REG_INTEGER\n"); - if (block->flags & CODEBLOCK_STATIC_TOP) + break; + + case REG_FPU_ST_BYTE: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_FPU_ST_BYTE !REG_INTEGER\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) codegen_direct_read_8(block, reg_set->reg_list[c].reg, &cpu_state.tag[ir_reg.reg & 7]); - else + else codegen_direct_read_st_8(block, reg_set->reg_list[c].reg, &cpu_state.tag[0], ir_reg.reg & 7); - break; - - case REG_FPU_ST_QWORD: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) - fatal("codegen_reg_load - REG_FPU_ST_QWORD !REG_FP\n"); - if (block->flags & CODEBLOCK_STATIC_TOP) + break; + + case REG_FPU_ST_QWORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_QWORD !REG_FP\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) codegen_direct_read_64(block, reg_set->reg_list[c].reg, &cpu_state.MM[ir_reg.reg & 7]); - else + else codegen_direct_read_st_64(block, reg_set->reg_list[c].reg, &cpu_state.MM[0], ir_reg.reg & 7); - break; - - case REG_FPU_ST_DOUBLE: - if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) - fatal("codegen_reg_load - REG_FPU_ST_DOUBLE !REG_FP\n"); - if (block->flags & CODEBLOCK_STATIC_TOP) + break; + + case REG_FPU_ST_DOUBLE: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_DOUBLE !REG_FP\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) codegen_direct_read_double(block, reg_set->reg_list[c].reg, &cpu_state.ST[ir_reg.reg & 7]); - else + else codegen_direct_read_st_double(block, reg_set->reg_list[c].reg, &cpu_state.ST[0], ir_reg.reg & 7); - break; - - default: fatal("codegen_reg_load - native_size=%i reg=%i\n", ireg_data[IREG_GET_REG(ir_reg.reg)].native_size, IREG_GET_REG(ir_reg.reg)); + break; + + default: + fatal("codegen_reg_load - native_size=%i reg=%i\n", ireg_data[IREG_GET_REG(ir_reg.reg)].native_size, IREG_GET_REG(ir_reg.reg)); } reg_set->regs[c] = ir_reg; @@ -364,59 +383,73 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i switch (ireg_data[ir_reg].native_size) { case REG_BYTE: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_INTEGER) fatal("codegen_reg_writeback - REG_BYTE !REG_INTEGER\n"); if ((uintptr_t)p < 256) fatal("codegen_reg_writeback - REG_BYTE %p\n", p); +#endif codegen_direct_write_8(block, p, reg_set->reg_list[c].reg); break; case REG_WORD: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_INTEGER) fatal("codegen_reg_writeback - REG_WORD !REG_INTEGER\n"); if ((uintptr_t)p < 256) fatal("codegen_reg_writeback - REG_WORD %p\n", p); +#endif codegen_direct_write_16(block, p, reg_set->reg_list[c].reg); break; case REG_DWORD: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_INTEGER) fatal("codegen_reg_writeback - REG_DWORD !REG_INTEGER\n"); +#endif if ((uintptr_t)p < 256) - codegen_direct_write_32_stack(block, (int)(uintptr_t)p, reg_set->reg_list[c].reg); + codegen_direct_write_32_stack(block, (intptr_t)p, reg_set->reg_list[c].reg); else codegen_direct_write_32(block, p, reg_set->reg_list[c].reg); break; case REG_QWORD: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_FP) fatal("codegen_reg_writeback - REG_QWORD !REG_FP\n"); +#endif if ((uintptr_t)p < 256) - codegen_direct_write_64_stack(block, (int)(uintptr_t)p, reg_set->reg_list[c].reg); + codegen_direct_write_64_stack(block, (intptr_t)p, reg_set->reg_list[c].reg); else codegen_direct_write_64(block, p, reg_set->reg_list[c].reg); break; case REG_POINTER: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_INTEGER) fatal("codegen_reg_writeback - REG_POINTER !REG_INTEGER\n"); if ((uintptr_t)p < 256) fatal("codegen_reg_writeback - REG_POINTER %p\n", p); +#endif codegen_direct_write_ptr(block, p, reg_set->reg_list[c].reg); break; case REG_DOUBLE: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_FP) fatal("codegen_reg_writeback - REG_DOUBLE !REG_FP\n"); +#endif if ((uintptr_t)p < 256) - codegen_direct_write_double_stack(block, (int)(uintptr_t)p, reg_set->reg_list[c].reg); + codegen_direct_write_double_stack(block, (intptr_t)p, reg_set->reg_list[c].reg); else codegen_direct_write_double(block, p, reg_set->reg_list[c].reg); break; case REG_FPU_ST_BYTE: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_INTEGER) fatal("codegen_reg_writeback - REG_FPU_ST_BYTE !REG_INTEGER\n"); +#endif if (block->flags & CODEBLOCK_STATIC_TOP) codegen_direct_write_8(block, &cpu_state.tag[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); else @@ -424,8 +457,10 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i break; case REG_FPU_ST_QWORD: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_FP) fatal("codegen_reg_writeback - REG_FPU_ST_QWORD !REG_FP\n"); +#endif if (block->flags & CODEBLOCK_STATIC_TOP) codegen_direct_write_64(block, &cpu_state.MM[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); else @@ -433,8 +468,10 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i break; case REG_FPU_ST_DOUBLE: +#ifndef RELEASE_BUILD if (ireg_data[ir_reg].type != REG_FP) fatal("codegen_reg_writeback - REG_FPU_ST_DOUBLE !REG_FP\n"); +#endif if (block->flags & CODEBLOCK_STATIC_TOP) codegen_direct_write_double(block, &cpu_state.ST[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); else @@ -450,18 +487,63 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i reg_set->dirty[c] = 0; } +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM +void codegen_reg_write_imm(codeblock_t *block, ir_reg_t ir_reg, uint32_t imm_data) +{ + int reg_idx = IREG_GET_REG(ir_reg.reg); + void *p = ireg_data[reg_idx].p; + + switch (ireg_data[reg_idx].native_size) + { + case REG_BYTE: +#ifndef RELEASE_BUILD + if ((uintptr_t)p < 256) + fatal("codegen_reg_write_imm - REG_BYTE %p\n", p); +#endif + codegen_direct_write_8_imm(block, p, imm_data); + break; + + case REG_WORD: +#ifndef RELEASE_BUILD + if ((uintptr_t)p < 256) + fatal("codegen_reg_write_imm - REG_WORD %p\n", p); +#endif + codegen_direct_write_16_imm(block, p, imm_data); + break; + + case REG_DWORD: + if ((uintptr_t)p < 256) + codegen_direct_write_32_imm_stack(block, (int)((uintptr_t) p), imm_data); + else + codegen_direct_write_32_imm(block, p, imm_data); + break; + + case REG_POINTER: + case REG_QWORD: + case REG_DOUBLE: + case REG_FPU_ST_BYTE: + case REG_FPU_ST_QWORD: + case REG_FPU_ST_DOUBLE: + default: + fatal("codegen_reg_write_imm - native_size=%i\n", ireg_data[reg_idx].native_size); + } +} +#endif + static void alloc_reg(ir_reg_t ir_reg) { host_reg_set_t *reg_set = get_reg_set(ir_reg); int nr_regs = (reg_set == &host_reg_set) ? CODEGEN_HOST_REGS : CODEGEN_HOST_FP_REGS; int c; - + for (c = 0; c < nr_regs; c++) { if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) { +#ifndef RELEASE_BUILD if (reg_set->regs[c].version != ir_reg.version) fatal("alloc_reg - host_regs[c].version != ir_reg.version %i %p %p %i %i\n", c, reg_set, &host_reg_set, reg_set->regs[c].reg, ir_reg.reg); +#endif reg_set->locked |= (1 << c); return; } @@ -509,7 +591,7 @@ static void alloc_dest_reg(ir_reg_t ir_reg, int dest_reference) void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c) { int dest_reference = 0; - + host_reg_set.locked = 0; host_fp_reg_set.locked = 0; @@ -549,8 +631,10 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in break; } +#ifndef RELEASE_BUILD if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount) fatal("codegen_reg_alloc_read_reg - version mismatch!\n"); +#endif } if (c == reg_set->nr_regs) @@ -569,8 +653,10 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in if (!(reg_set->locked & (1 << c))) break; } +#ifndef RELEASE_BUILD if (c == reg_set->nr_regs) fatal("codegen_reg_alloc_read_reg - out of registers\n"); +#endif } if (reg_set->dirty[c]) codegen_reg_writeback(reg_set, block, c, 1); @@ -580,8 +666,10 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in } reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount--; +#ifndef RELEASE_BUILD if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount == (uint8_t)-1) fatal("codegen_reg_alloc_read_reg - refcount < 0\n"); +#endif if (host_reg_idx) *host_reg_idx = c; @@ -592,29 +680,31 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) { host_reg_set_t *reg_set = get_reg_set(ir_reg); int c; - + if (!reg_is_native_size(ir_reg)) { /*Read in parent register so we can do partial accesses to it*/ ir_reg_t parent_reg; - + parent_reg.reg = IREG_GET_REG(ir_reg.reg) | IREG_SIZE_L; parent_reg.version = ir_reg.version - 1; reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1].refcount++; - + codegen_reg_alloc_read_reg(block, parent_reg, &c); +#ifndef RELEASE_BUILD if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version > ir_reg.version-1) fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c, reg_set->regs[c].reg,reg_set->regs[c].version, ir_reg.reg,ir_reg.version); - +#endif + reg_set->regs[c].reg = ir_reg.reg; reg_set->regs[c].version = ir_reg.version; reg_set->dirty[c] = 1; return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); } - + /*Search for previous version in host register*/ for (c = 0; c < reg_set->nr_regs; c++) { @@ -622,13 +712,15 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) { if (reg_set->regs[c].version <= ir_reg.version-1) { +#ifndef RELEASE_BUILD if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0) fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); +#endif break; } } } - + if (c == reg_set->nr_regs) { /*Search for unused registers*/ @@ -637,7 +729,7 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) if (ir_reg_is_invalid(reg_set->regs[c])) break; } - + if (c == reg_set->nr_regs) { /*No unused registers. Search for an unlocked register*/ @@ -646,24 +738,88 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) if (!(reg_set->locked & (1 << c))) break; } +#ifndef RELEASE_BUILD if (c == reg_set->nr_regs) fatal("codegen_reg_alloc_write_reg - out of registers\n"); +#endif if (reg_set->dirty[c]) codegen_reg_writeback(reg_set, block, c, 1); } } - + reg_set->regs[c].reg = ir_reg.reg; reg_set->regs[c].version = ir_reg.version; reg_set->dirty[c] = 1; return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); } +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM +int codegen_reg_is_loaded(ir_reg_t ir_reg) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int c; + + /*Search for previous version in host register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version <= ir_reg.version-1) + { +#ifndef RELEASE_BUILD + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0) + fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); +#endif + return 1; + } + } + } + return 0; +} +#endif + +void codegen_reg_rename(codeblock_t *block, ir_reg_t src, ir_reg_t dst) +{ + host_reg_set_t *reg_set = get_reg_set(src); + int c; + int target; + +// pclog("rename: %i.%i -> %i.%i\n", src.reg,src.version, dst.reg, dst.version); + /*Search for required register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(src.reg) && reg_set->regs[c].version == src.version) + break; + } +#ifndef RELEASE_BUILD + if (c == reg_set->nr_regs) + fatal("codegen_reg_rename: Can't find register to rename\n"); +#endif + target = c; + if (reg_set->dirty[target]) + codegen_reg_writeback(reg_set, block, target, 0); + reg_set->regs[target] = dst; + reg_set->dirty[target] = 1; +// pclog("renamed reg %i dest=%i.%i\n", target, dst.reg, dst.version); + + /*Invalidate any stale copies of the dest register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (c == target) + continue; + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(dst.reg)) + { + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + } +} + void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) { host_reg_set_t *reg_set; int c; - + reg_set = &host_reg_set; for (c = 0; c < reg_set->nr_regs; c++) { @@ -697,7 +853,7 @@ void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block) { host_reg_set_t *reg_set; int c; - + reg_set = &host_reg_set; for (c = 0; c < reg_set->nr_regs; c++) { diff --git a/src/codegen_new/codegen_reg.h b/src/codegen_new/codegen_reg.h index 85bb9f142..d822a950f 100644 --- a/src/codegen_new/codegen_reg.h +++ b/src/codegen_new/codegen_reg.h @@ -38,10 +38,10 @@ enum IREG_ea_seg = 15, IREG_op32 = 16, IREG_ssegsx = 17, - + IREG_rm_mod_reg = 18, - - IREG_ins = 19, + + IREG_acycs = 19, IREG_cycles = 20, IREG_CS_base = 21, @@ -70,7 +70,7 @@ enum IREG_temp0d = 38, IREG_temp1d = 39, - + /*FPU stack registers are physical registers. Use IREG_ST() / IREG_tag() to access. When CODEBLOCK_STATIC_TOP is set, the physical register number will be @@ -85,7 +85,7 @@ enum IREG_ST5 = 45, IREG_ST6 = 46, IREG_ST7 = 47, - + IREG_tag0 = 48, IREG_tag1 = 49, IREG_tag2 = 50, @@ -103,7 +103,7 @@ enum IREG_ST5_i64 = 61, IREG_ST6_i64 = 62, IREG_ST7_i64 = 63, - + IREG_MM0x = 64, IREG_MM1x = 65, IREG_MM2x = 66, @@ -112,13 +112,13 @@ enum IREG_MM5x = 69, IREG_MM6x = 70, IREG_MM7x = 71, - + IREG_NPXCx = 72, IREG_NPXSx = 73, - + IREG_flagsx = 74, IREG_eflagsx = 75, - + IREG_CS_limit_low = 76, IREG_DS_limit_low = 77, IREG_ES_limit_low = 78, @@ -134,9 +134,9 @@ enum IREG_SS_limit_high = 87, IREG_COUNT = 88, - + IREG_INVALID = 255, - + IREG_AX = IREG_EAX + IREG_SIZE_W, IREG_CX = IREG_ECX + IREG_SIZE_W, IREG_DX = IREG_EDX + IREG_SIZE_W, @@ -155,7 +155,7 @@ enum IREG_CH = IREG_ECX + IREG_SIZE_BH, IREG_DH = IREG_EDX + IREG_SIZE_BH, IREG_BH = IREG_EBX + IREG_SIZE_BH, - + IREG_flags_res_W = IREG_flags_res + IREG_SIZE_W, IREG_flags_op1_W = IREG_flags_op1 + IREG_SIZE_W, IREG_flags_op2_W = IREG_flags_op2 + IREG_SIZE_W, @@ -168,7 +168,7 @@ enum IREG_temp1_W = IREG_temp1 + IREG_SIZE_W, IREG_temp2_W = IREG_temp2 + IREG_SIZE_W, IREG_temp3_W = IREG_temp3 + IREG_SIZE_W, - + IREG_temp0_B = IREG_temp0 + IREG_SIZE_B, IREG_temp1_B = IREG_temp1 + IREG_SIZE_B, IREG_temp2_B = IREG_temp2 + IREG_SIZE_B, @@ -181,14 +181,14 @@ enum IREG_temp1_Q = IREG_temp1d + IREG_SIZE_Q, IREG_eaaddr_W = IREG_eaaddr + IREG_SIZE_W, - + IREG_CS_seg_W = IREG_CS_seg + IREG_SIZE_W, IREG_DS_seg_W = IREG_DS_seg + IREG_SIZE_W, IREG_ES_seg_W = IREG_ES_seg + IREG_SIZE_W, IREG_FS_seg_W = IREG_FS_seg + IREG_SIZE_W, IREG_GS_seg_W = IREG_GS_seg + IREG_SIZE_W, IREG_SS_seg_W = IREG_SS_seg + IREG_SIZE_W, - + IREG_MM0 = IREG_MM0x + IREG_SIZE_Q, IREG_MM1 = IREG_MM1x + IREG_SIZE_Q, IREG_MM2 = IREG_MM2x + IREG_SIZE_Q, @@ -197,12 +197,12 @@ enum IREG_MM5 = IREG_MM5x + IREG_SIZE_Q, IREG_MM6 = IREG_MM6x + IREG_SIZE_Q, IREG_MM7 = IREG_MM7x + IREG_SIZE_Q, - + IREG_NPXC = IREG_NPXCx + IREG_SIZE_W, IREG_NPXS = IREG_NPXSx + IREG_SIZE_W, - + IREG_ssegs = IREG_ssegsx + IREG_SIZE_B, - + IREG_flags = IREG_flagsx + IREG_SIZE_W, IREG_eflags = IREG_eflagsx + IREG_SIZE_W }; @@ -324,21 +324,26 @@ static inline ir_reg_t codegen_reg_read(int reg) { ir_reg_t ireg; reg_version_t *version; - + +#ifndef RELEASE_BUILD if (IREG_GET_REG(reg) == IREG_INVALID) fatal("codegen_reg_read - IREG_INVALID\n"); - +#endif ireg.reg = reg; ireg.version = reg_last_version[IREG_GET_REG(reg)]; version = ®_version[IREG_GET_REG(ireg.reg)][ireg.version]; version->flags = 0; version->refcount++; +#ifndef RELEASE_BUILD if (!version->refcount) fatal("codegen_reg_read - refcount overflow\n"); - else if (version->refcount > REG_REFCOUNT_MAX) + else +#endif + if (version->refcount > REG_REFCOUNT_MAX) CPU_BLOCK_END(); if (version->refcount > max_version_refcount) max_version_refcount = version->refcount; +// pclog("codegen_reg_read: %i %i %i\n", reg & IREG_REG_MASK, ireg.version, reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]); return ireg; } @@ -349,24 +354,28 @@ static inline ir_reg_t codegen_reg_write(int reg, int uop_nr) ir_reg_t ireg; 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 ireg.reg = reg; ireg.version = last_version + 1; - + if (IREG_GET_REG(reg) > IREG_EBX && last_version && !reg_version[IREG_GET_REG(reg)][last_version].refcount && !(reg_version[IREG_GET_REG(reg)][last_version].flags & REG_FLAGS_REQUIRED)) { if (reg_is_native_size(ireg)) /*Non-native size registers have an implicit dependency on the previous version, so don't add to dead list*/ add_to_dead_list(®_version[IREG_GET_REG(reg)][last_version], IREG_GET_REG(reg), last_version); } - + 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 if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX) + else +#endif + 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)]; @@ -375,6 +384,7 @@ static inline ir_reg_t codegen_reg_write(int reg, int uop_nr) version->refcount = 0; version->flags = 0; version->parent_uop = uop_nr; +// pclog("codegen_reg_write: %i\n", reg & IREG_REG_MASK); return ireg; } @@ -394,9 +404,16 @@ void codegen_reg_flush_invalidate(struct ir_data_t *ir, codeblock_t *block); /*Register ir_reg usage for this uOP. This ensures that required registers aren't evicted*/ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c); +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM +int codegen_reg_is_loaded(ir_reg_t ir_reg); +void codegen_reg_write_imm(codeblock_t *block, ir_reg_t ir_reg, uint32_t imm_data); +#endif + ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx); ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg); +void codegen_reg_rename(codeblock_t *block, ir_reg_t src, ir_reg_t dst); + void codegen_reg_mark_as_required(); void codegen_reg_process_dead_list(struct ir_data_t *ir); #endif diff --git a/src/codegen_new/x86_ops_shift.h b/src/codegen_new/x86_ops_shift.h deleted file mode 100644 index 106a5701a..000000000 --- a/src/codegen_new/x86_ops_shift.h +++ /dev/null @@ -1,607 +0,0 @@ -#define OP_SHIFT_b(c, ea32) \ - { \ - uint8_t temp_orig = temp; \ - if (!c) return 0; \ - flags_rebuild(); \ - switch (rmdat & 0x38) \ - { \ - case 0x00: /*ROL b, c*/ \ - temp = (temp << (c & 7)) | (temp >> (8-(c & 7))); \ - seteab(temp); if (cpu_state.abrt) return 1; \ - set_flags_rotate(FLAGS_ROL8, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x08: /*ROR b,CL*/ \ - temp = (temp >> (c & 7)) | (temp << (8-(c & 7))); \ - seteab(temp); if (cpu_state.abrt) return 1; \ - set_flags_rotate(FLAGS_ROR8, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x10: /*RCL b,CL*/ \ - temp2 = cpu_state.flags & C_FLAG; \ - if (is486) CLOCK_CYCLES_ALWAYS(c); \ - while (c > 0) \ - { \ - tempc = temp2 ? 1 : 0; \ - temp2 = temp & 0x80; \ - temp = (temp << 1) | tempc; \ - c--; \ - } \ - seteab(temp); if (cpu_state.abrt) return 1; \ - cpu_state.flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) cpu_state.flags |= C_FLAG; \ - if ((cpu_state.flags & C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ - PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x18: /*RCR b,CL*/ \ - temp2 = cpu_state.flags & C_FLAG; \ - if (is486) CLOCK_CYCLES_ALWAYS(c); \ - while (c > 0) \ - { \ - tempc = temp2 ? 0x80 : 0; \ - temp2 = temp & 1; \ - temp = (temp >> 1) | tempc; \ - c--; \ - } \ - seteab(temp); if (cpu_state.abrt) return 1; \ - cpu_state.flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) cpu_state.flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ - PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x20: case 0x30: /*SHL b,CL*/ \ - seteab(temp << c); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x28: /*SHR b,CL*/ \ - seteab(temp >> c); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x38: /*SAR b,CL*/ \ - temp = (int8_t)temp >> c; \ - seteab(temp); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SAR8, temp_orig, c, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - } \ - } - -#define OP_SHIFT_w(c, ea32) \ - { \ - uint16_t temp_orig = temp; \ - if (!c) return 0; \ - flags_rebuild(); \ - switch (rmdat & 0x38) \ - { \ - case 0x00: /*ROL w, c*/ \ - temp = (temp << (c & 15)) | (temp >> (16-(c & 15))); \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - set_flags_rotate(FLAGS_ROL16, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x08: /*ROR w,CL*/ \ - temp = (temp >> (c & 15)) | (temp << (16-(c & 15))); \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - set_flags_rotate(FLAGS_ROR16, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x10: /*RCL w, c*/ \ - temp2 = cpu_state.flags & C_FLAG; \ - if (is486) CLOCK_CYCLES_ALWAYS(c); \ - while (c > 0) \ - { \ - tempc = temp2 ? 1 : 0; \ - temp2 = temp & 0x8000; \ - temp = (temp << 1) | tempc; \ - c--; \ - } \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - cpu_state.flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) cpu_state.flags |= C_FLAG; \ - if ((cpu_state.flags & C_FLAG) ^ (temp >> 15)) cpu_state.flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ - PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x18: /*RCR w, c*/ \ - temp2 = cpu_state.flags & C_FLAG; \ - if (is486) CLOCK_CYCLES_ALWAYS(c); \ - while (c > 0) \ - { \ - tempc = temp2 ? 0x8000 : 0; \ - temp2 = temp & 1; \ - temp = (temp >> 1) | tempc; \ - c--; \ - } \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - cpu_state.flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) cpu_state.flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ - PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x20: case 0x30: /*SHL w, c*/ \ - seteaw(temp << c); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x28: /*SHR w, c*/ \ - seteaw(temp >> c); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x38: /*SAR w, c*/ \ - temp = (int16_t)temp >> c; \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SAR16, temp_orig, c, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - } \ - } - -#define OP_SHIFT_l(c, ea32) \ - { \ - uint32_t temp_orig = temp; \ - if (!c) return 0; \ - flags_rebuild(); \ - switch (rmdat & 0x38) \ - { \ - case 0x00: /*ROL l, c*/ \ - temp = (temp << c) | (temp >> (32-c)); \ - seteal(temp); if (cpu_state.abrt) return 1; \ - set_flags_rotate(FLAGS_ROL32, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x08: /*ROR l,CL*/ \ - temp = (temp >> c) | (temp << (32-c)); \ - seteal(temp); if (cpu_state.abrt) return 1; \ - set_flags_rotate(FLAGS_ROR32, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ - case 0x10: /*RCL l, c*/ \ - temp2 = CF_SET(); \ - if (is486) CLOCK_CYCLES_ALWAYS(c); \ - while (c > 0) \ - { \ - tempc = temp2 ? 1 : 0; \ - temp2 = temp & 0x80000000; \ - temp = (temp << 1) | tempc; \ - c--; \ - } \ - seteal(temp); if (cpu_state.abrt) return 1; \ - cpu_state.flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) cpu_state.flags |= C_FLAG; \ - if ((cpu_state.flags & C_FLAG) ^ (temp >> 31)) cpu_state.flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ - PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ - break; \ - case 0x18: /*RCR l, c*/ \ - temp2 = cpu_state.flags & C_FLAG; \ - if (is486) CLOCK_CYCLES_ALWAYS(c); \ - while (c > 0) \ - { \ - tempc = temp2 ? 0x80000000 : 0; \ - temp2 = temp & 1; \ - temp = (temp >> 1) | tempc; \ - c--; \ - } \ - seteal(temp); if (cpu_state.abrt) return 1; \ - cpu_state.flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) cpu_state.flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ - PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ - break; \ - case 0x20: case 0x30: /*SHL l, c*/ \ - seteal(temp << c); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ - break; \ - case 0x28: /*SHR l, c*/ \ - seteal(temp >> c); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ - break; \ - case 0x38: /*SAR l, c*/ \ - temp = (int32_t)temp >> c; \ - seteal(temp); if (cpu_state.abrt) return 1; \ - set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ - break; \ - } \ - } - -static int opC0_a16(uint32_t fetchdat) -{ - int c; - int tempc; - uint8_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; - PREFETCH_PREFIX(); - temp = geteab(); if (cpu_state.abrt) return 1; - OP_SHIFT_b(c, 0); - return 0; -} -static int opC0_a32(uint32_t fetchdat) -{ - int c; - int tempc; - uint8_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; - PREFETCH_PREFIX(); - temp = geteab(); if (cpu_state.abrt) return 1; - OP_SHIFT_b(c, 1); - return 0; -} -static int opC1_w_a16(uint32_t fetchdat) -{ - int c; - int tempc; - uint16_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; - PREFETCH_PREFIX(); - temp = geteaw(); if (cpu_state.abrt) return 1; - OP_SHIFT_w(c, 0); - return 0; -} -static int opC1_w_a32(uint32_t fetchdat) -{ - int c; - int tempc; - uint16_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; - PREFETCH_PREFIX(); - temp = geteaw(); if (cpu_state.abrt) return 1; - OP_SHIFT_w(c, 1); - return 0; -} -static int opC1_l_a16(uint32_t fetchdat) -{ - int c; - int tempc; - uint32_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; - PREFETCH_PREFIX(); - temp = geteal(); if (cpu_state.abrt) return 1; - OP_SHIFT_l(c, 0); - return 0; -} -static int opC1_l_a32(uint32_t fetchdat) -{ - int c; - int tempc; - uint32_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; - PREFETCH_PREFIX(); - temp = geteal(); if (cpu_state.abrt) return 1; - OP_SHIFT_l(c, 1); - return 0; -} - -static int opD0_a16(uint32_t fetchdat) -{ - int c = 1; - int tempc; - uint8_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteab(); if (cpu_state.abrt) return 1; - OP_SHIFT_b(c, 0); - return 0; -} -static int opD0_a32(uint32_t fetchdat) -{ - int c = 1; - int tempc; - uint8_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteab(); if (cpu_state.abrt) return 1; - OP_SHIFT_b(c, 1); - return 0; -} -static int opD1_w_a16(uint32_t fetchdat) -{ - int c = 1; - int tempc; - uint16_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - OP_SHIFT_w(c, 0); - return 0; -} -static int opD1_w_a32(uint32_t fetchdat) -{ - int c = 1; - int tempc; - uint16_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteaw(); if (cpu_state.abrt) return 1; - OP_SHIFT_w(c, 1); - return 0; -} -static int opD1_l_a16(uint32_t fetchdat) -{ - int c = 1; - int tempc; - uint32_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - OP_SHIFT_l(c, 0); - return 0; -} -static int opD1_l_a32(uint32_t fetchdat) -{ - int c = 1; - int tempc; - uint32_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - temp = geteal(); if (cpu_state.abrt) return 1; - OP_SHIFT_l(c, 1); - return 0; -} - -static int opD2_a16(uint32_t fetchdat) -{ - int c; - int tempc; - uint8_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = CL & 31; - temp = geteab(); if (cpu_state.abrt) return 1; - OP_SHIFT_b(c, 0); - return 0; -} -static int opD2_a32(uint32_t fetchdat) -{ - int c; - int tempc; - uint8_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = CL & 31; - temp = geteab(); if (cpu_state.abrt) return 1; - OP_SHIFT_b(c, 1); - return 0; -} -static int opD3_w_a16(uint32_t fetchdat) -{ - int c; - int tempc; - uint16_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = CL & 31; - temp = geteaw(); if (cpu_state.abrt) return 1; - OP_SHIFT_w(c, 0); - return 0; -} -static int opD3_w_a32(uint32_t fetchdat) -{ - int c; - int tempc; - uint16_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = CL & 31; - temp = geteaw(); if (cpu_state.abrt) return 1; - OP_SHIFT_w(c, 1); - return 0; -} -static int opD3_l_a16(uint32_t fetchdat) -{ - int c; - int tempc; - uint32_t temp, temp2 = 0; - - fetch_ea_16(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = CL & 31; - temp = geteal(); if (cpu_state.abrt) return 1; - OP_SHIFT_l(c, 0); - return 0; -} -static int opD3_l_a32(uint32_t fetchdat) -{ - int c; - int tempc; - uint32_t temp, temp2 = 0; - - fetch_ea_32(fetchdat); - if (cpu_mod != 3) - SEG_CHECK_WRITE(cpu_state.ea_seg); - c = CL & 31; - temp = geteal(); if (cpu_state.abrt) return 1; - OP_SHIFT_l(c, 1); - return 0; -} - - -#define SHLD_w() \ - if (count) \ - { \ - int tempc; \ - uint32_t templ; \ - uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ - tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ - templ = (tempw << 16) | cpu_state.regs[cpu_reg].w; \ - if (count <= 16) tempw = templ >> (16 - count); \ - else tempw = (templ << count) >> 16; \ - seteaw(tempw); if (cpu_state.abrt) return 1; \ - setznp16(tempw); \ - flags_rebuild(); \ - if (tempc) cpu_state.flags |= C_FLAG; \ - } - -#define SHLD_l() \ - if (count) \ - { \ - int tempc; \ - uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ - tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ - templ = (templ << count) | (cpu_state.regs[cpu_reg].l >> (32 - count)); \ - seteal(templ); if (cpu_state.abrt) return 1; \ - setznp32(templ); \ - flags_rebuild(); \ - if (tempc) cpu_state.flags |= C_FLAG; \ - } - - -#define SHRD_w() \ - if (count) \ - { \ - int tempc; \ - uint32_t templ; \ - uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ - tempc = (tempw >> (count - 1)) & 1; \ - templ = tempw | (cpu_state.regs[cpu_reg].w << 16); \ - tempw = templ >> count; \ - seteaw(tempw); if (cpu_state.abrt) return 1; \ - setznp16(tempw); \ - flags_rebuild(); \ - if (tempc) cpu_state.flags |= C_FLAG; \ - } - -#define SHRD_l() \ - if (count) \ - { \ - int tempc; \ - uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ - tempc = (templ >> (count - 1)) & 1; \ - templ = (templ >> count) | (cpu_state.regs[cpu_reg].l << (32 - count)); \ - seteal(templ); if (cpu_state.abrt) return 1; \ - setznp32(templ); \ - flags_rebuild(); \ - if (tempc) cpu_state.flags |= C_FLAG; \ - } - -#define opSHxD(operation) \ - static int op ## operation ## _i_a16(uint32_t fetchdat) \ - { \ - int count; \ - \ - fetch_ea_16(fetchdat); \ - if (cpu_mod != 3) \ - SEG_CHECK_WRITE(cpu_state.ea_seg); \ - count = getbyte() & 31; \ - operation(); \ - \ - CLOCK_CYCLES(3); \ - PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ - return 0; \ - } \ - static int op ## operation ## _CL_a16(uint32_t fetchdat) \ - { \ - int count; \ - \ - fetch_ea_16(fetchdat); \ - if (cpu_mod != 3) \ - SEG_CHECK_WRITE(cpu_state.ea_seg); \ - count = CL & 31; \ - operation(); \ - \ - CLOCK_CYCLES(3); \ - PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ - return 0; \ - } \ - static int op ## operation ## _i_a32(uint32_t fetchdat) \ - { \ - int count; \ - \ - fetch_ea_32(fetchdat); \ - if (cpu_mod != 3) \ - SEG_CHECK_WRITE(cpu_state.ea_seg); \ - count = getbyte() & 31; \ - operation(); \ - \ - CLOCK_CYCLES(3); \ - PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ - return 0; \ - } \ - static int op ## operation ## _CL_a32(uint32_t fetchdat) \ - { \ - int count; \ - \ - fetch_ea_32(fetchdat); \ - if (cpu_mod != 3) \ - SEG_CHECK_WRITE(cpu_state.ea_seg); \ - count = CL & 31; \ - operation(); \ - \ - CLOCK_CYCLES(3); \ - PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ - return 0; \ - } - -opSHxD(SHLD_w) -opSHxD(SHLD_l) -opSHxD(SHRD_w) -opSHxD(SHRD_l) diff --git a/src/codegen_new/x86seg.c b/src/codegen_new/x86seg.c deleted file mode 100644 index f8738e824..000000000 --- a/src/codegen_new/x86seg.c +++ /dev/null @@ -1,2600 +0,0 @@ -/* - * 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. - * - * x86 CPU segment emulation. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include "cpu.h" -#include <86box/device.h> -#include <86box/timer.h> -#include <86box/machine.h> -#include <86box/mem.h> -#include <86box/nvr.h> -#include "x86.h" -#include "x86_flags.h" -#include "386_common.h" - - -extern FILE *stdlog; /* file to log output to */ - - -/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ -#define CS_ACCESSED - -/*Controls whether the accessed bit in a descriptor is set when a data or stack - selector is loaded.*/ -#define SEL_ACCESSED -int stimes = 0; -int dtimes = 0; -int btimes = 0; - -uint32_t abrt_error; -int cgate16, cgate32; - -#define breaknullsegs 0 - -int intgatesize; - -void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); -void taskswitch386(uint16_t seg, uint16_t *segdat); - -void pmodeint(int num, int soft); -/*NOT PRESENT is INT 0B - GPF is INT 0D*/ - - -#ifdef ENABLE_X86SEG_LOG -int x86seg_do_log = ENABLE_X86SEG_LOG; - - -static void -x86seg_log(const char *fmt, ...) -{ - va_list ap; - - if (x86seg_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define x86seg_log(fmt, ...) -#endif - - -void x86abort(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - - nvr_save(); -#ifdef ENABLE_808X_LOG - dumpregs(1); -#endif - fflush(stdlog); - exit(-1); -} - -uint8_t opcode2; - -static void seg_reset(x86seg *s) -{ - s->access = (0 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->limit = 0xFFFF; - s->limit_low = 0; - s->limit_high = 0xffff; - if (s == &cpu_state.seg_cs) - { - /* TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below: - s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; */ - s->base = AT ? 0xF0000 : 0xFFFF0; - s->seg = AT ? 0xF000 : 0xFFFF; - } - else - { - s->base = 0; - s->seg = 0; - } -} - -void x86seg_reset() -{ - seg_reset(&cpu_state.seg_cs); - seg_reset(&cpu_state.seg_ds); - seg_reset(&cpu_state.seg_es); - seg_reset(&cpu_state.seg_fs); - seg_reset(&cpu_state.seg_gs); - seg_reset(&cpu_state.seg_ss); -} - -void x86_doabrt(int x86_abrt) -{ - cpu_state.pc = cpu_state.oldpc; - cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; - - if (msw & 1) - pmodeint(x86_abrt, 0); - else - { - uint32_t addr = (x86_abrt << 2) + idt.base; - if (stack32) - { - writememw(ss,ESP-2,cpu_state.flags); - writememw(ss,ESP-4,CS); - writememw(ss,ESP-6,cpu_state.pc); - ESP-=6; - } - else - { - writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); - SP-=6; - } - - cpu_state.flags &= ~I_FLAG; - cpu_state.flags &= ~T_FLAG; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - return; - } - - if (cpu_state.abrt || x86_was_reset) return; - - if (intgatesize == 16) - { - if (stack32) - { - writememw(ss, ESP-2, abrt_error); - ESP-=2; - } - else - { - writememw(ss, ((SP-2)&0xFFFF), abrt_error); - SP-=2; - } - } - else - { - if (stack32) - { - writememl(ss, ESP-4, abrt_error); - ESP-=4; - } - else - { - writememl(ss, ((SP-4)&0xFFFF), abrt_error); - SP-=4; - } - } -} -void x86gpf(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_GPF; - abrt_error = error; -} -void x86ss(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_SS; - abrt_error = error; -} -void x86ts(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_TS; - abrt_error = error; -} -void x86np(char *s, uint16_t error) -{ - cpu_state.abrt = ABRT_NP; - abrt_error = error; -} - - -static void set_stack32(int s) -{ - stack32 = s; - if (stack32) - cpu_cur_status |= CPU_STATUS_STACK32; - else - cpu_cur_status &= ~CPU_STATUS_STACK32; -} - -static void set_use32(int u) -{ - if (u) - { - use32 = 0x300; - cpu_cur_status |= CPU_STATUS_USE32; - } - else - { - use32 = 0; - cpu_cur_status &= ~CPU_STATUS_USE32; - } -} - -void do_seg_load(x86seg *s, uint16_t *segdat) -{ - s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); - if (segdat[3] & 0x80) - s->limit = (s->limit << 12) | 0xFFF; - s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); - if (is386) - s->base |= ((segdat[3] >> 8) << 24); - s->access = segdat[2] >> 8; - s->ar_high = segdat[3] & 0xff; - - if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ - { - s->limit_high = s->limit; - s->limit_low = 0; - } - else - { - s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; - s->limit_low = s->limit + 1; - } - - if (s == &cpu_state.seg_ds) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - } - if (s == &cpu_state.seg_ss) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - } -} - -static void do_seg_v86_init(x86seg *s) -{ - s->access = (3 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->limit = 0xffff; - s->limit_low = 0; - s->limit_high = 0xffff; -} - -static void check_seg_valid(x86seg *s) -{ - int dpl = (s->access >> 5) & 3; - int valid = 1; - - if (s->seg & 4) - { - if ((s->seg & ~7) >= ldt.limit) - { - valid = 0; - } - } - else - { - if ((s->seg & ~7) >= gdt.limit) - { - valid = 0; - } - } - - switch (s->access & 0x1f) - { - case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1A: case 0x1B: /*Readable non-conforming code*/ - if ((s->seg & 3) > dpl || (CPL) > dpl) - { - valid = 0; - break; - } - break; - - case 0x1E: case 0x1F: /*Readable conforming code*/ - break; - - default: - valid = 0; - break; - } - - if (!valid) - loadseg(0, s); -} - -int loadseg(uint16_t seg, x86seg *s) -{ - uint16_t segdat[4]; - uint32_t addr; - int dpl; - - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - if (s==&cpu_state.seg_ss) - { - x86ss(NULL,0); - return 1; - } - s->seg=0; - s->access = 0x80; - s->ar_high = 0x10; - s->base=-1; - if (s == &cpu_state.seg_ds) - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - return 0; - } - addr=seg&~7; - if (seg&4) - { - if ((addr+7)>ldt.limit) - { - x86gpf("loadseg(): Bigger than LDT limit",seg&~3); - return 1; - } - addr+=ldt.base; - } - else - { - if ((addr+7)>gdt.limit) - { - x86gpf("loadseg(): Bigger than GDT limit",seg&~3); - return 1; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return 1; - dpl=(segdat[2]>>13)&3; - if (s==&cpu_state.seg_ss) - { - if (!(seg&~3)) - { - x86gpf("loadseg(): Zero stack segment",seg&~3); - return 1; - } - if ((seg&3)!=CPL) - { - x86gpf("loadseg(): Stack segment RPL != CPL",seg&~3); - return 1; - } - if (dpl!=CPL) - { - x86gpf("loadseg(): Stack segment DPL != CPL",seg&~3); - return 1; - } - switch ((segdat[2]>>8)&0x1F) - { - case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ - break; - default: - x86gpf("loadseg(): Unknown stack segment type",seg&~3); - return 1; - } - if (!(segdat[2]&0x8000)) - { - x86ss(NULL,seg&~3); - return 1; - } - set_stack32((segdat[3] & 0x40) ? 1 : 0); - } - else if (s!=&cpu_state.seg_cs) - { - x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); - x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); - switch ((segdat[2]>>8)&0x1F) - { - case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1A: case 0x1B: /*Readable non-conforming code*/ - if ((seg&3)>dpl) - { - x86gpf("loadseg(): Normal segment RPL > DPL",seg&~3); - return 1; - } - if ((CPL)>dpl) - { - x86gpf("loadseg(): Normal segment DPL < CPL",seg&~3); - return 1; - } - break; - case 0x1E: case 0x1F: /*Readable conforming code*/ - break; - default: - x86gpf("loadseg(): Unknown normal segment type",seg&~3); - return 1; - } - } - - if (!(segdat[2] & 0x8000)) - { - x86np("Load data seg not present", seg & 0xfffc); - return 1; - } - s->seg = seg; - do_seg_load(s, segdat); - -#ifndef CS_ACCESSED - if (s != &_cs) - { -#endif -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif -#ifndef CS_ACCESSED - } -#endif - s->checked = 0; -#ifdef USE_DYNAREC - if (s == &cpu_state.seg_ds) - codegen_flat_ds = 0; - if (s == &cpu_state.seg_ss) - codegen_flat_ss = 0; -#endif - } - else - { - s->access = (3 << 5) | 2 | 0x80; - s->ar_high = 0x10; - s->base = seg << 4; - s->seg = seg; - s->checked = 1; -#ifdef USE_DYNAREC - if (s == &cpu_state.seg_ds) - codegen_flat_ds = 0; - if (s == &cpu_state.seg_ss) - codegen_flat_ss = 0; -#endif - if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) - set_stack32(0); - } - - if (s == &cpu_state.seg_ds) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - } - if (s == &cpu_state.seg_ss) - { - if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - } - - return cpu_state.abrt; -} - -#define DPL ((segdat[2]>>13)&3) -#define DPL2 ((segdat2[2]>>13)&3) -#define DPL3 ((segdat3[2]>>13)&3) - -void loadcs(uint16_t seg) -{ - uint16_t segdat[4]; - uint32_t addr; - x86seg_log("Load CS %04X\n",seg); - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - if (segdat[2]&0x1000) /*Normal code segment*/ - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf(NULL,seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcs(): CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcs(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS not present", seg & 0xfffc); - return; - } - set_use32(segdat[3] & 0x40); - CS=(seg&~3)|CPL; - do_seg_load(&cpu_state.seg_cs, segdat); - use32=(segdat[3]&0x40)?0x300:0; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - } - else /*System segment*/ - { - if (!(segdat[2]&0x8000)) - { - x86np("Load CS system seg not present\n", seg & 0xfffc); - return; - } - switch (segdat[2]&0xF00) - { - default: - x86gpf(NULL,seg&~3); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg & 0xFFFF; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - } -} - -void loadcsjmp(uint16_t seg, uint32_t old_pc) -{ - uint16_t segdat[4]; - uint32_t addr; - uint16_t type,seg2; - uint32_t newpc; - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (!(seg&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - x86seg_log("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); - if (segdat[2]&0x1000) /*Normal code segment*/ - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf("loadcsjmp(): CPL != DPL",seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf("loadcsjmp(): CPL < DPL",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP not present\n", seg & 0xfffc); - return; - } - set_use32(segdat[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - CS = (seg & ~3) | CPL; - segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - cycles -= timing_jmp_pm; - } - else /*System segment*/ - { - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP system selector not present\n", seg & 0xfffc); - return; - } - type=segdat[2]&0xF00; - newpc=segdat[0]; - if (type&0x800) newpc|=segdat[3]<<16; - switch (type) - { - case 0x400: /*Call gate*/ - case 0xC00: - cgate32=(type&0x800); - cgate16=!cgate32; - cpu_state.oldpc = cpu_state.pc; - if ((DPL < CPL) || (DPL < (seg&3))) - { - x86gpf(NULL,seg&~3); - return; - } - if (DPL < CPL) - { - x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); - return; - } - if ((DPL < (seg&3))) - { - x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP call gate not present\n", seg & 0xfffc); - return; - } - seg2=segdat[1]; - - if (!(seg2&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg2&~7; - if (seg2&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg2&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg2&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - - if (DPL > CPL) - { - x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); - return; - } - - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if (DPL > CPL) - { - x86gpf(NULL,seg2&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - break; - - default: - x86gpf(NULL,seg2&~3); - return; - } - cycles -= timing_jmp_pm_gate; - break; - - - case 0x100: /*286 Task gate*/ - case 0x900: /*386 Task gate*/ - cpu_state.pc = old_pc; - optype=JMP; - cpl_override=1; - taskswitch286(seg,segdat,segdat[2]&0x800); - cpu_state.flags &= ~NT_FLAG; - cpl_override=0; - return; - - default: - x86gpf(NULL,0); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - cycles -= timing_jmp_rm; - } -} - -void PUSHW(uint16_t v) -{ - if (stack32) - { - writememw(ss,ESP-2,v); - if (cpu_state.abrt) return; - ESP-=2; - } - else - { - writememw(ss,((SP-2)&0xFFFF),v); - if (cpu_state.abrt) return; - SP-=2; - } -} -void PUSHL(uint32_t v) -{ - if (stack32) - { - writememl(ss,ESP-4,v); - if (cpu_state.abrt) return; - ESP-=4; - } - else - { - writememl(ss,((SP-4)&0xFFFF),v); - if (cpu_state.abrt) return; - SP-=4; - } -} -uint16_t POPW() -{ - uint16_t tempw; - if (stack32) - { - tempw=readmemw(ss,ESP); - if (cpu_state.abrt) return 0; - ESP+=2; - } - else - { - tempw=readmemw(ss,SP); - if (cpu_state.abrt) return 0; - SP+=2; - } - return tempw; -} -uint32_t POPL() -{ - uint32_t templ; - if (stack32) - { - templ=readmeml(ss,ESP); - if (cpu_state.abrt) return 0; - ESP+=4; - } - else - { - templ=readmeml(ss,SP); - if (cpu_state.abrt) return 0; - SP+=4; - } - return templ; -} - -void loadcscall(uint16_t seg, uint32_t old_pc) -{ - uint16_t seg2; - uint16_t segdat[4],segdat2[4],newss; - uint32_t addr,oldssbase=ss, oaddr; - uint32_t newpc; - int count; - uint32_t oldss,oldsp,newsp, oldsp2; - int type; - uint16_t tempw; - - int csout = output; - - if (msw&1 && !(cpu_state.eflags&VM_FLAG)) - { - if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); - if (!(seg&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - type=segdat[2]&0xF00; - newpc=segdat[0]; - if (type&0x800) newpc|=segdat[3]<<16; - - if (csout) x86seg_log("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); - if (segdat[2]&0x1000) - { - if (!(segdat[2]&0x400)) /*Not conforming*/ - { - if ((seg&3)>CPL) - { - x86gpf("loadcscall(): segment > CPL",seg&~3); - return; - } - if (CPL != DPL) - { - x86gpf(NULL,seg&~3); - return; - } - } - if (CPL < DPL) - { - x86gpf(NULL,seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86np("Load CS call not present", seg & 0xfffc); - return; - } - set_use32(segdat[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - /*Conforming segments don't change CPL, so preserve existing CPL*/ - if (segdat[2]&0x400) - { - seg = (seg & ~3) | CPL; - segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - } - else /*On non-conforming segments, set RPL = CPL*/ - seg = (seg & ~3) | CPL; - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - if (csout) x86seg_log("Complete\n"); - cycles -= timing_call_pm; - } - else - { - type=segdat[2]&0xF00; - if (csout) x86seg_log("Type %03X\n",type); - switch (type) - { - case 0x400: /*Call gate*/ - case 0xC00: /*386 Call gate*/ - x86seg_log("Callgate %08X\n", cpu_state.pc); - cgate32=(type&0x800); - cgate16=!cgate32; - count=segdat[2]&31; - if (DPL < CPL) - { - x86gpf("loadcscall(): ex DPL < CPL",seg&~3); - return; - } - if ((DPL < (seg&3))) - { - x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86seg_log("Call gate not present %04X\n",seg); - x86np("Call gate not present\n", seg & 0xfffc); - return; - } - seg2=segdat[1]; - - x86seg_log("New address : %04X:%08X\n", seg2, newpc); - - if (!(seg2&~3)) - { - x86gpf(NULL,0); - return; - } - addr=seg2&~7; - if (seg2&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg2&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg2&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - - x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); - - if (DPL > CPL) - { - x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - x86seg_log("Call gate CS not present %04X\n",seg2); - x86np("Call gate CS not present", seg2 & 0xfffc); - return; - } - - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if (DPL < CPL) - { - uint16_t oldcs = CS; - oaddr = addr; - /*Load new stack*/ - oldss=SS; - oldsp=oldsp2=ESP; - cpl_override=1; - if (tr.access&8) - { - addr = 4 + tr.base + (DPL * 8); - newss=readmemw(0,addr+4); - newsp=readmeml(0,addr); - } - else - { - addr = 2 + tr.base + (DPL * 4); - newss=readmemw(0,addr+2); - newsp=readmemw(0,addr); - } - cpl_override=0; - if (cpu_state.abrt) return; - x86seg_log("New stack %04X:%08X\n",newss,newsp); - if (!(newss&~3)) - { - x86ts(NULL,newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if ((addr+7)>ldt.limit) - { - x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); - x86ts(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if ((addr+7)>gdt.limit) - { - x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); - x86ts(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - x86seg_log("Read stack seg\n"); - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - x86seg_log("Read stack seg done!\n"); - if (((newss & 3) != DPL) || (DPL2 != DPL)) - { - x86ts(NULL,newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - x86ts(NULL,newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - x86ss("Call gate loading SS not present\n", newss & 0xfffc); - return; - } - if (!stack32) oldsp &= 0xFFFF; - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - - do_seg_load(&cpu_state.seg_ss, segdat2); - - x86seg_log("Set access 1\n"); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; - - x86seg_log("Set access 2\n"); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - x86seg_log("Type %04X\n",type); - if (type==0xC00) - { - PUSHL(oldss); - PUSHL(oldsp2); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - CS = oldcs; - return; - } - if (count) - { - while (count) - { - count--; - PUSHL(readmeml(oldssbase,oldsp+(count*4))); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - CS = oldcs; - return; - } - } - } - } - else - { - x86seg_log("Stack %04X\n",SP); - PUSHW(oldss); - x86seg_log("Write SS to %04X:%04X\n",SS,SP); - PUSHW(oldsp2); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - CS = oldcs; - return; - } - x86seg_log("Write SP to %04X:%04X\n",SS,SP); - if (count) - { - while (count) - { - count--; - tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); - x86seg_log("PUSH %04X\n",tempw); - PUSHW(tempw); - if (cpu_state.abrt) - { - SS = oldss; - ESP = oldsp2; - CS = oldcs; - return; - } - } - } - } - cycles -= timing_call_pm_gate_inner; - break; - } - else if (DPL > CPL) - { - x86gpf(NULL,seg2&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - CS=seg2; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3]&0x40); - cpu_state.pc=newpc; - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - cycles -= timing_call_pm_gate; - break; - - default: - x86gpf(NULL,seg2&~3); - return; - } - break; - - case 0x100: /*286 Task gate*/ - case 0x900: /*386 Task gate*/ - cpu_state.pc = old_pc; - cpl_override=1; - taskswitch286(seg,segdat,segdat[2]&0x800); - cpl_override=0; - break; - - default: - x86gpf(NULL,seg&~3); - return; - } - } - } - else - { - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - } -} - -void pmoderetf(int is32, uint16_t off) -{ - uint32_t newpc; - uint32_t newsp; - uint32_t addr, oaddr; - uint16_t segdat[4],segdat2[4],seg,newss; - uint32_t oldsp=ESP; - x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); - if (is32) - { - newpc=POPL(); - seg=POPL(); if (cpu_state.abrt) return; - } - else - { - x86seg_log("PC read from %04X:%04X\n",SS,SP); - newpc=POPW(); - x86seg_log("CS read from %04X:%04X\n",SS,SP); - seg=POPW(); if (cpu_state.abrt) return; - } - x86seg_log("Return to %04X:%08X\n",seg,newpc); - if ((seg&3)=ldt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } - oaddr = addr; - - x86seg_log("CPL %i RPL %i %i\n",CPL,seg&3,is32); - - if (stack32) ESP+=off; - else SP+=off; - - if (CPL==(seg&3)) - { - x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if (CPL != DPL) - { - ESP=oldsp; - x86gpf(NULL,seg&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if (CPL < DPL) - { - ESP=oldsp; - x86gpf(NULL,seg&~3); - return; - } - break; - default: - x86gpf(NULL,seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF CS not present\n", seg & 0xfffc); - return; - } - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - cpu_state.pc=newpc; - if (segdat[2] & 0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - CS = seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3] & 0x40); - - cycles -= timing_retf_pm; - } - else - { - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((seg&3) != DPL) - { - ESP=oldsp; - x86gpf(NULL,seg&~3); - return; - } - x86seg_log("RETF non-conforming, %i %i\n",seg&3, DPL); - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((seg&3) < DPL) - { - ESP=oldsp; - x86gpf(NULL,seg&~3); - return; - } - x86seg_log("RETF conforming, %i %i\n",seg&3, DPL); - break; - default: - ESP=oldsp; - x86gpf(NULL,seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF CS not present\n", seg & 0xfffc); - return; - } - if (is32) - { - newsp=POPL(); - newss=POPL(); if (cpu_state.abrt) return; - } - else - { - x86seg_log("SP read from %04X:%04X\n",SS,SP); - newsp=POPW(); - x86seg_log("SS read from %04X:%04X\n",SS,SP); - newss=POPW(); if (cpu_state.abrt) return; - } - x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); - if (!(newss&~3)) - { - ESP=oldsp; - x86gpf(NULL,newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if (addr>=ldt.limit) - { - ESP=oldsp; - x86gpf(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP=oldsp; - x86gpf(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } - x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); - if ((newss & 3) != (seg & 3)) - { - ESP=oldsp; - x86gpf(NULL,newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - ESP=oldsp; - x86gpf(NULL,newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - ESP=oldsp; - x86np("RETF loading SS not present\n", newss & 0xfffc); - return; - } - if (DPL2 != (seg & 3)) - { - ESP=oldsp; - x86gpf(NULL,newss&~3); - return; - } - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - -#ifdef CS_ACCESSED - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ -#endif - cpl_override = 0; -#endif - /*Conforming segments don't change CPL, so CPL = RPL*/ - if (segdat[2]&0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - - cpu_state.pc=newpc; - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3] & 0x40); - - if (stack32) ESP+=off; - else SP+=off; - - check_seg_valid(&cpu_state.seg_ds); - check_seg_valid(&cpu_state.seg_es); - check_seg_valid(&cpu_state.seg_fs); - check_seg_valid(&cpu_state.seg_gs); - cycles -= timing_retf_pm_outer; - } -} - -void pmodeint(int num, int soft) -{ - uint16_t segdat[4],segdat2[4],segdat3[4]; - uint32_t addr, oaddr; - uint16_t newss; - uint32_t oldss,oldsp; - int type; - uint32_t newsp; - uint16_t seg = 0; - int new_cpl; - - if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) - { - x86seg_log("V86 banned int\n"); - x86gpf(NULL,0); - return; - } - addr=(num<<3); - if (addr>=idt.limit) - { - if (num==8) - { - /*Triple fault - reset!*/ - softresetx86(); - cpu_set_edx(); - } - else if (num==0xD) - { - pmodeint(8,0); - } - else - { - x86gpf(NULL,(num*8)+2+((soft)?0:1)); - } - x86seg_log("addr >= IDT.limit\n"); - return; - } - addr+=idt.base; - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(2,addr); - segdat[2]=readmemw(4,addr); - segdat[3]=readmemw(6,addr); cpl_override=0; - if (cpu_state.abrt) { - x86seg_log("Abrt reading from %08X\n",addr); - return; - } - oaddr = addr; - - x86seg_log("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); - if (!(segdat[2]&0x1F00)) - { - x86gpf(NULL,(num*8)+2); - return; - } - if (DPL=0x800)?32:16; - if (!(segdat[2]&0x8000)) - { - x86np("Int gate not present\n", (num << 3) | 2); - return; - } - seg=segdat[1]; - new_cpl = seg & 3; - - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - oaddr = addr; - - if (DPL2 > CPL) - { - x86gpf(NULL,seg&~3); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if (DPL2=ldt.limit) - { - x86ss(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ss(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat3[0]=readmemw(0,addr); - segdat3[1]=readmemw(0,addr+2); - segdat3[2]=readmemw(0,addr+4); - segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; - if (((newss & 3) != DPL2) || (DPL3 != DPL2)) - { - x86ss(NULL,newss&~3); - return; - } - if ((segdat3[2]&0x1A00)!=0x1200) - { - x86ss(NULL,newss&~3); - return; - } - if (!(segdat3[2]&0x8000)) - { - x86np("Int gate loading SS not present\n", newss & 0xfffc); - return; - } - SS=newss; - set_stack32((segdat3[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat3); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - x86seg_log("New stack %04X:%08X\n",SS,ESP); - cpl_override=1; - if (type>=0x800) - { - if (cpu_state.eflags & VM_FLAG) - { - PUSHL(GS); - PUSHL(FS); - PUSHL(DS); - PUSHL(ES); if (cpu_state.abrt) return; - loadseg(0,&cpu_state.seg_ds); - loadseg(0,&cpu_state.seg_es); - loadseg(0,&cpu_state.seg_fs); - loadseg(0,&cpu_state.seg_gs); - } - PUSHL(oldss); - PUSHL(oldsp); - PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL(CS); - PUSHL(cpu_state.pc); if (cpu_state.abrt) return; - } - else - { - PUSHW(oldss); - PUSHW(oldsp); - PUSHW(cpu_state.flags); - PUSHW(CS); - PUSHW(cpu_state.pc); if (cpu_state.abrt) return; - } - cpl_override=0; - cpu_state.seg_cs.access=0 | 0x80; - cycles -= timing_int_pm_outer - timing_int_pm; - break; - } - else if (DPL2!=CPL) - { - x86gpf(NULL,seg&~3); - return; - } - /*FALLTHROUGH*/ - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if (!(segdat2[2]&0x8000)) - { - x86np("Int gate CS not present\n", segdat[1] & 0xfffc); - return; - } - if ((cpu_state.eflags & VM_FLAG) && DPL20x800) - { - PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL(CS); - PUSHL(cpu_state.pc); if (cpu_state.abrt) return; - } - else - { - PUSHW(cpu_state.flags); - PUSHW(CS); - PUSHW(cpu_state.pc); if (cpu_state.abrt) return; - } - new_cpl = CS & 3; - break; - default: - x86gpf(NULL,seg&~3); - return; - } - do_seg_load(&cpu_state.seg_cs, segdat2); - CS = (seg & ~3) | new_cpl; - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); - else cpu_state.pc=segdat[0]; - set_use32(segdat2[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - - cpu_state.eflags &= ~VM_FLAG; - cpu_cur_status &= ~CPU_STATUS_V86; - if (!(type&0x100)) - cpu_state.flags &= ~I_FLAG; - cpu_state.flags &= ~(T_FLAG|NT_FLAG); - cycles -= timing_int_pm; - break; - - case 0x500: /*Task gate*/ - seg=segdat[1]; - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - cpl_override=0; if (cpu_state.abrt) return; - if (!(segdat2[2]&0x8000)) - { - x86np("Int task gate not present\n", segdat[1] & 0xfffc); - return; - } - optype=OPTYPE_INT; - cpl_override=1; - taskswitch286(seg,segdat2,segdat2[2]&0x800); - cpl_override=0; - break; - - default: - x86gpf(NULL,seg&~3); - return; - } -} - -void pmodeiret(int is32) -{ - uint32_t newsp; - uint16_t newss; - uint32_t tempflags,flagmask; - uint32_t newpc; - uint16_t segdat[4],segdat2[4]; - uint16_t segs[4]; - uint16_t seg = 0; - uint32_t addr, oaddr; - uint32_t oldsp=ESP; - if (is386 && (cpu_state.eflags & VM_FLAG)) - { - if (IOPL!=3) - { - x86gpf(NULL,0); - return; - } - if (is32) - { - newpc=POPL(); - seg=POPL(); - tempflags=POPL(); if (cpu_state.abrt) return; - } - else - { - newpc=POPW(); - seg=POPW(); - tempflags=POPW(); if (cpu_state.abrt) return; - } - cpu_state.pc=newpc; - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - cpu_state.seg_cs.access |= 0x80; - cpu_state.seg_cs.ar_high = 0x10; - CS=seg; - cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xCFD5) | 2; - cycles -= timing_iret_rm; - return; - } - - if (cpu_state.flags & NT_FLAG) - { - seg=readmemw(tr.base,0); - addr=seg&~7; - if (seg&4) - { - x86seg_log("TS LDT %04X %04X IRET\n",seg,gdt.limit); - x86ts(NULL,seg&~3); - return; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); - taskswitch286(seg,segdat,segdat[2] & 0x800); - cpl_override=0; - return; - } - flagmask=0xFFFF; - if (CPL) flagmask&=~0x3000; - if (IOPL>16)&VM_FLAG)) - { - newsp=POPL(); - newss=POPL(); - segs[0]=POPL(); - segs[1]=POPL(); - segs[2]=POPL(); - segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } - cpu_state.eflags = tempflags>>16; - cpu_cur_status |= CPU_STATUS_V86; - loadseg(segs[0],&cpu_state.seg_es); - do_seg_v86_init(&cpu_state.seg_es); - loadseg(segs[1],&cpu_state.seg_ds); - do_seg_v86_init(&cpu_state.seg_ds); - cpu_cur_status |= CPU_STATUS_NOTFLATDS; - loadseg(segs[2],&cpu_state.seg_fs); - do_seg_v86_init(&cpu_state.seg_fs); - loadseg(segs[3],&cpu_state.seg_gs); - do_seg_v86_init(&cpu_state.seg_gs); - - cpu_state.pc = newpc & 0xffff; - cpu_state.seg_cs.base=seg<<4; - cpu_state.seg_cs.limit=0xFFFF; - cpu_state.seg_cs.limit_low = 0; - cpu_state.seg_cs.limit_high = 0xffff; - CS=seg; - cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; - cpu_state.seg_cs.ar_high = 0x10; - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - - ESP=newsp; - loadseg(newss,&cpu_state.seg_ss); - do_seg_v86_init(&cpu_state.seg_ss); - cpu_cur_status |= CPU_STATUS_NOTFLATSS; - use32=0; - cpu_cur_status &= ~CPU_STATUS_USE32; - cpu_state.flags = (tempflags&0xFFD5)|2; - cycles -= timing_iret_v86; - return; - } - } - else - { - newpc=POPW(); - seg=POPW(); - tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - if (!(seg&~3)) - { - ESP = oldsp; - x86gpf(NULL,0); - return; - } - - addr=seg&~7; - if (seg&4) - { - if (addr>=ldt.limit) - { - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - addr+=gdt.base; - } - if ((seg&3) < CPL) - { - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - cpl_override=1; - segdat[0]=readmemw(0,addr); - segdat[1]=readmemw(0,addr+2); - segdat[2]=readmemw(0,addr+4); - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } - - switch (segdat[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ - if ((seg&3) != DPL) - { - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ - if ((seg&3) < DPL) - { - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - break; - default: - ESP = oldsp; - x86gpf(NULL,seg&~3); - return; - } - if (!(segdat[2]&0x8000)) - { - ESP = oldsp; - x86np("IRET CS not present\n", seg & 0xfffc); - return; - } - if ((seg&3) == CPL) - { - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3]&0x40); - -#ifdef CS_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ - cpl_override = 0; -#endif - cycles -= timing_iret_pm; - } - else /*Return to outer level*/ - { - oaddr = addr; - x86seg_log("Outer level\n"); - if (is32) - { - newsp=POPL(); - newss=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - else - { - newsp=POPW(); - newss=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } - } - - x86seg_log("IRET load stack %04X:%04X\n",newss,newsp); - - if (!(newss&~3)) - { - ESP = oldsp; - x86gpf(NULL,newss&~3); - return; - } - addr=newss&~7; - if (newss&4) - { - if (addr>=ldt.limit) - { - ESP = oldsp; - x86gpf(NULL,newss&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - ESP = oldsp; - x86gpf(NULL,newss&~3); - return; - } - addr+=gdt.base; - } - cpl_override=1; - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } - if ((newss & 3) != (seg & 3)) - { - ESP = oldsp; - x86gpf(NULL,newss&~3); - return; - } - if ((segdat2[2]&0x1A00)!=0x1200) - { - ESP = oldsp; - x86gpf(NULL,newss&~3); - return; - } - if (DPL2 != (seg & 3)) - { - ESP = oldsp; - x86gpf(NULL,newss&~3); - return; - } - if (!(segdat2[2]&0x8000)) - { - ESP = oldsp; - x86np("IRET loading SS not present\n", newss & 0xfffc); - return; - } - SS=newss; - set_stack32((segdat2[3] & 0x40) ? 1 : 0); - if (stack32) ESP=newsp; - else SP=newsp; - do_seg_load(&cpu_state.seg_ss, segdat2); - -#ifdef SEL_ACCESSED - cpl_override = 1; - writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ - -#ifdef CS_ACCESSED - writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ -#endif - cpl_override = 0; -#endif - /*Conforming segments don't change CPL, so CPL = RPL*/ - if (segdat[2]&0x400) - segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); - - CS=seg; - do_seg_load(&cpu_state.seg_cs, segdat); - cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat[3] & 0x40); - - check_seg_valid(&cpu_state.seg_ds); - check_seg_valid(&cpu_state.seg_es); - check_seg_valid(&cpu_state.seg_fs); - check_seg_valid(&cpu_state.seg_gs); - cycles -= timing_iret_pm_outer; - } - cpu_state.pc=newpc; - cpu_state.flags = (cpu_state.flags&~flagmask) | (tempflags&flagmask&0xFFD5)|2; - if (is32) cpu_state.eflags = tempflags>>16; -} - -void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) -{ - uint32_t base; - uint32_t limit; - uint32_t templ; - uint16_t tempw; - - uint32_t new_cr3=0; - uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; - uint16_t new_ldt; - - uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; - - uint32_t addr; - - uint16_t segdat2[4]; - - base=segdat[1]|((segdat[2]&0xFF)<<16); - limit=segdat[0]; - if(is386) - { - base |= (segdat[3]>>8)<<24; - limit |= (segdat[3]&0xF)<<16; - } - - if (is32) - { - if (limit < 103) - { - x86ts(NULL, seg); - return; - } - - if (optype==JMP || optype==CALL || optype==OPTYPE_INT) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==IRET) cpu_state.flags&=~NT_FLAG; - - cpu_386_flags_rebuild(); - writememl(tr.base,0x1C,cr3); - writememl(tr.base,0x20,cpu_state.pc); - writememl(tr.base,0x24,cpu_state.flags | (cpu_state.eflags<<16)); - - writememl(tr.base,0x28,EAX); - writememl(tr.base,0x2C,ECX); - writememl(tr.base,0x30,EDX); - writememl(tr.base,0x34,EBX); - writememl(tr.base,0x38,ESP); - writememl(tr.base,0x3C,EBP); - writememl(tr.base,0x40,ESI); - writememl(tr.base,0x44,EDI); - - writememl(tr.base,0x48,ES); - writememl(tr.base,0x4C,CS); - writememl(tr.base,0x50,SS); - writememl(tr.base,0x54,DS); - writememl(tr.base,0x58,FS); - writememl(tr.base,0x5C,GS); - - if (optype==JMP || optype==IRET) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.abrt) return; - tempw&=~0x200; - if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); - else writememw(gdt.base,(tr.seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==OPTYPE_INT || optype==CALL) - { - writememl(base,0,tr.seg); - if (cpu_state.abrt) - return; - } - - - new_cr3=readmeml(base,0x1C); - new_pc=readmeml(base,0x20); - new_flags=readmeml(base,0x24); - if (optype == OPTYPE_INT || optype == CALL) - new_flags |= NT_FLAG; - - new_eax=readmeml(base,0x28); - new_ecx=readmeml(base,0x2C); - new_edx=readmeml(base,0x30); - new_ebx=readmeml(base,0x34); - new_esp=readmeml(base,0x38); - new_ebp=readmeml(base,0x3C); - new_esi=readmeml(base,0x40); - new_edi=readmeml(base,0x44); - - new_es=readmemw(base,0x48); - new_cs=readmemw(base,0x4C); - new_ss=readmemw(base,0x50); - new_ds=readmemw(base,0x54); - new_fs=readmemw(base,0x58); - new_gs=readmemw(base,0x5C); - new_ldt=readmemw(base,0x60); - - cr0 |= 8; - - cr3=new_cr3; - flushmmucache(); - - cpu_state.pc=new_pc; - cpu_state.flags = new_flags; - cpu_state.eflags = new_flags>>16; - cpu_386_flags_extract(); - - ldt.seg=new_ldt; - templ=(ldt.seg&~7)+gdt.base; - ldt.limit=readmemw(0,templ); - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); - - if (cpu_state.eflags & VM_FLAG) - { - loadcs(new_cs); - set_use32(0); - cpu_cur_status |= CPU_STATUS_V86; - } - else - { - if (!(new_cs&~3)) - { - x86ts(NULL,0); - return; - } - addr=new_cs&~7; - if (new_cs&4) - { - if (addr>=ldt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=gdt.base; - } - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - if (!(segdat2[2]&0x8000)) - { - x86np("TS loading CS not present\n", new_cs & 0xfffc); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((new_cs&3) != DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((new_cs&3) < DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - default: - x86ts(NULL,new_cs&~3); - return; - } - - CS=new_cs; - do_seg_load(&cpu_state.seg_cs, segdat2); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(segdat2[3] & 0x40); - cpu_cur_status &= ~CPU_STATUS_V86; - } - - EAX=new_eax; - ECX=new_ecx; - EDX=new_edx; - EBX=new_ebx; - ESP=new_esp; - EBP=new_ebp; - ESI=new_esi; - EDI=new_edi; - - loadseg(new_es,&cpu_state.seg_es); - loadseg(new_ss,&cpu_state.seg_ss); - loadseg(new_ds,&cpu_state.seg_ds); - loadseg(new_fs,&cpu_state.seg_fs); - loadseg(new_gs,&cpu_state.seg_gs); - } - else - { - if (limit < 43) - { - x86ts(NULL, seg); - return; - } - - if (optype==JMP || optype==CALL || optype==OPTYPE_INT) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype == IRET) - cpu_state.flags &= ~NT_FLAG; - - cpu_386_flags_rebuild(); - writememw(tr.base,0x0E,cpu_state.pc); - writememw(tr.base,0x10,cpu_state.flags); - - writememw(tr.base,0x12,AX); - writememw(tr.base,0x14,CX); - writememw(tr.base,0x16,DX); - writememw(tr.base,0x18,BX); - writememw(tr.base,0x1A,SP); - writememw(tr.base,0x1C,BP); - writememw(tr.base,0x1E,SI); - writememw(tr.base,0x20,DI); - - writememw(tr.base,0x22,ES); - writememw(tr.base,0x24,CS); - writememw(tr.base,0x26,SS); - writememw(tr.base,0x28,DS); - - if (optype==JMP || optype==IRET) - { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.abrt) return; - tempw&=~0x200; - if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); - else writememw(gdt.base,(tr.seg&~7)+4,tempw); - } - if (cpu_state.abrt) return; - - if (optype==OPTYPE_INT || optype==CALL) - { - writememw(base,0,tr.seg); - if (cpu_state.abrt) - return; - } - - new_pc=readmemw(base,0x0E); - new_flags=readmemw(base,0x10); - if (optype == OPTYPE_INT || optype == CALL) - new_flags |= NT_FLAG; - - new_eax=readmemw(base,0x12); - new_ecx=readmemw(base,0x14); - new_edx=readmemw(base,0x16); - new_ebx=readmemw(base,0x18); - new_esp=readmemw(base,0x1A); - new_ebp=readmemw(base,0x1C); - new_esi=readmemw(base,0x1E); - new_edi=readmemw(base,0x20); - - new_es=readmemw(base,0x22); - new_cs=readmemw(base,0x24); - new_ss=readmemw(base,0x26); - new_ds=readmemw(base,0x28); - new_ldt=readmemw(base,0x2A); - - msw |= 8; - - cpu_state.pc=new_pc; - cpu_state.flags = new_flags; - cpu_386_flags_extract(); - - ldt.seg=new_ldt; - templ=(ldt.seg&~7)+gdt.base; - ldt.limit=readmemw(0,templ); - ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); - if (is386) - { - if (readmemb(0,templ+6)&0x80) - { - ldt.limit<<=12; - ldt.limit|=0xFFF; - } - ldt.base|=(readmemb(0,templ+7)<<24); - } - - if (!(new_cs&~3)) - { - x86ts(NULL,0); - return; - } - addr=new_cs&~7; - if (new_cs&4) - { - if (addr>=ldt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=ldt.base; - } - else - { - if (addr>=gdt.limit) - { - x86ts(NULL,new_cs&~3); - return; - } - addr+=gdt.base; - } - segdat2[0]=readmemw(0,addr); - segdat2[1]=readmemw(0,addr+2); - segdat2[2]=readmemw(0,addr+4); - segdat2[3]=readmemw(0,addr+6); - if (!(segdat2[2]&0x8000)) - { - x86np("TS loading CS not present\n", new_cs & 0xfffc); - return; - } - switch (segdat2[2]&0x1F00) - { - case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ - if ((new_cs&3) != DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ - if ((new_cs&3) < DPL2) - { - x86ts(NULL,new_cs&~3); - return; - } - break; - default: - x86ts(NULL,new_cs&~3); - return; - } - - CS=new_cs; - do_seg_load(&cpu_state.seg_cs, segdat2); - if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - oldcpl = CPL; - set_use32(0); - - EAX=new_eax | 0xFFFF0000; - ECX=new_ecx | 0xFFFF0000; - EDX=new_edx | 0xFFFF0000; - EBX=new_ebx | 0xFFFF0000; - ESP=new_esp | 0xFFFF0000; - EBP=new_ebp | 0xFFFF0000; - ESI=new_esi | 0xFFFF0000; - EDI=new_edi | 0xFFFF0000; - - loadseg(new_es,&cpu_state.seg_es); - loadseg(new_ss,&cpu_state.seg_ss); - loadseg(new_ds,&cpu_state.seg_ds); - if (is386) - { - loadseg(0,&cpu_state.seg_fs); - loadseg(0,&cpu_state.seg_gs); - } - } - - tr.seg=seg; - tr.base=base; - tr.limit=limit; - tr.access=segdat[2]>>8; - tr.ar_high = 0x10; -} - diff --git a/src/config.c b/src/config.c index 5d3962c6f..81bbc016f 100644 --- a/src/config.c +++ b/src/config.c @@ -1,30 +1,31 @@ -/* - * 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. +/* + * 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. + * This file is part of the 86Box distribution. * - * Configuration file handler. + * Configuration file handler. * * * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * Overdoze, - * David Hrdlička, + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Overdoze, + * David Hrdlička, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2018,2019 David Hrdlička. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David Hrdlička. * - * NOTE: Forcing config files to be in Unicode encoding breaks - * it on Windows XP, and possibly also Vista. Use the - * -DANSI_CFG for use on these systems. + * NOTE: Forcing config files to be in Unicode encoding breaks + * it on Windows XP, and possibly also Vista. Use the + * -DANSI_CFG for use on these systems. */ + #include #include #include @@ -37,6 +38,8 @@ #include "cpu.h" #include <86box/device.h> #include <86box/timer.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> #include <86box/nvr.h> #include <86box/config.h> #include <86box/isamem.h> @@ -61,9 +64,11 @@ #include <86box/midi.h> #include <86box/snd_mpu401.h> #include <86box/video.h> +#include <86box/path.h> #include <86box/plat.h> -#include <86box/plat_midi.h> +#include <86box/plat_dir.h> #include <86box/ui.h> +#include <86box/snd_opl.h> typedef struct _list_ { @@ -71,139 +76,154 @@ typedef struct _list_ { } list_t; typedef struct { - list_t list; + list_t list; - char name[128]; + char name[128]; - list_t entry_head; + list_t entry_head; } section_t; typedef struct { - list_t list; + list_t list; - char name[128]; - char data[512]; - wchar_t wdata[512]; + char name[128]; + char data[512]; + wchar_t wdata[512]; } entry_t; -#define list_add(new, head) { \ - list_t *next = head; \ - \ - while (next->next != NULL) \ - next = next->next; \ - \ - (next)->next = new; \ - (new)->next = NULL; \ -} +#define list_add(new, head) \ + { \ + list_t *next = head; \ + \ + while (next->next != NULL) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ + } -#define list_delete(old, head) { \ - list_t *next = head; \ - \ - while ((next)->next != old) { \ - next = (next)->next; \ - } \ - \ - (next)->next = (old)->next; \ - if ((next) == (head)) \ - (head)->next = (old)->next; \ -} +#define list_delete(old, head) \ + { \ + list_t *next = head; \ + \ + while ((next)->next != old) { \ + next = (next)->next; \ + } \ + \ + (next)->next = (old)->next; \ + if ((next) == (head)) \ + (head)->next = (old)->next; \ + } +static list_t config_head; -static list_t config_head; - +/* TODO: Backwards compatibility, get rid of this when enough time has passed. */ +static int backwards_compat = 0; +static int backwards_compat2 = 0; #ifdef ENABLE_CONFIG_LOG int config_do_log = ENABLE_CONFIG_LOG; - static void config_log(const char *fmt, ...) { va_list ap; if (config_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define config_log(fmt, ...) +# define config_log(fmt, ...) #endif - static section_t * find_section(char *name) { section_t *sec; - char blank[] = ""; + char blank[] = ""; - sec = (section_t *)config_head.next; + sec = (section_t *) config_head.next; if (name == NULL) - name = blank; + name = blank; while (sec != NULL) { - if (! strncmp(sec->name, name, sizeof(sec->name))) - return(sec); + if (!strncmp(sec->name, name, sizeof(sec->name))) + return (sec); - sec = (section_t *)sec->list.next; + sec = (section_t *) sec->list.next; } - return(NULL); + return (NULL); } +void * +config_find_section(char *name) +{ + return (void *) find_section(name); +} + +void +config_rename_section(void *priv, char *name) +{ + section_t *sec = (section_t *) priv; + + memset(sec->name, 0x00, sizeof(sec->name)); + memcpy(sec->name, name, MIN(128, strlen(name) + 1)); +} static entry_t * find_entry(section_t *section, char *name) { entry_t *ent; - ent = (entry_t *)section->entry_head.next; + ent = (entry_t *) section->entry_head.next; while (ent != NULL) { - if (! strncmp(ent->name, name, sizeof(ent->name))) - return(ent); + if (!strncmp(ent->name, name, sizeof(ent->name))) + return (ent); - ent = (entry_t *)ent->list.next; + ent = (entry_t *) ent->list.next; } - return(NULL); + return (NULL); } - static int entries_num(section_t *section) { entry_t *ent; - int i = 0; + int i = 0; - ent = (entry_t *)section->entry_head.next; + ent = (entry_t *) section->entry_head.next; while (ent != NULL) { - if (strlen(ent->name) > 0) i++; + if (strlen(ent->name) > 0) + i++; - ent = (entry_t *)ent->list.next; + ent = (entry_t *) ent->list.next; } - return(i); + return (i); } - static void delete_section_if_empty(char *head) { section_t *section; section = find_section(head); - if (section == NULL) return; + if (section == NULL) + return; if (entries_num(section) == 0) { - list_delete(§ion->list, &config_head); - free(section); + list_delete(§ion->list, &config_head); + free(section); } } - static section_t * create_section(char *name) { @@ -213,10 +233,9 @@ create_section(char *name) memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, &config_head); - return(ns); + return (ns); } - static entry_t * create_entry(section_t *section, char *name) { @@ -226,10 +245,9 @@ create_entry(section_t *section, char *name) memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); - return(ne); + return (ne); } - #if 0 static void config_free(void) @@ -239,130 +257,195 @@ config_free(void) sec = (section_t *)config_head.next; while (sec != NULL) { - ns = (section_t *)sec->list.next; - ent = (entry_t *)sec->entry_head.next; + ns = (section_t *)sec->list.next; + ent = (entry_t *)sec->entry_head.next; - while (ent != NULL) { - entry_t *nent = (entry_t *)ent->list.next; + while (ent != NULL) { + entry_t *nent = (entry_t *)ent->list.next; - free(ent); - ent = nent; - } + free(ent); + ent = nent; + } - free(sec); - sec = ns; + free(sec); + sec = ns; } } #endif +static int +config_detect_bom(char *fn) +{ + FILE *f; + unsigned char bom[4] = { 0, 0, 0, 0 }; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, "rt"); +#else + f = plat_fopen(fn, "rt, ccs=UTF-8"); +#endif + if (f == NULL) + return (0); + fread(bom, 1, 3, f); + if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) { + fclose(f); + return 1; + } + fclose(f); + return 0; +} + +#ifdef __HAIKU__ +/* Local version of fgetws to avoid a crash */ +static wchar_t * +config_fgetws(wchar_t *str, int count, FILE *stream) +{ + int i = 0; + if (feof(stream)) + return NULL; + for (i = 0; i < count; i++) { + wint_t curChar = fgetwc(stream); + if (curChar == WEOF) { + if (i + 1 < count) + str[i + 1] = 0; + return feof(stream) ? str : NULL; + } + str[i] = curChar; + if (curChar == '\n') + break; + } + if (i + 1 < count) + str[i + 1] = 0; + return str; +} +#endif /* Read and parse the configuration file into memory. */ static int -config_read(wchar_t *fn) +config_read(char *fn) { - char sname[128], ename[128]; - wchar_t buff[1024]; + char sname[128], ename[128]; + wchar_t buff[1024]; section_t *sec, *ns; - entry_t *ne; - int c, d; - FILE *f; + entry_t *ne; + int c, d, bom; + FILE *f; + bom = config_detect_bom(fn); #if defined(ANSI_CFG) || !defined(_WIN32) - f = plat_fopen(fn, L"rt"); + f = plat_fopen(fn, "rt"); #else - f = plat_fopen(fn, L"rt, ccs=UNICODE"); + f = plat_fopen(fn, "rt, ccs=UTF-8"); #endif - if (f == NULL) return(0); - + if (f == NULL) + return (0); + sec = malloc(sizeof(section_t)); memset(sec, 0x00, sizeof(section_t)); memset(&config_head, 0x00, sizeof(list_t)); list_add(&sec->list, &config_head); + if (bom) + fseek(f, 3, SEEK_SET); while (1) { - memset(buff, 0x00, sizeof(buff)); - fgetws(buff, sizeof_w(buff), f); - if (feof(f)) break; + memset(buff, 0x00, sizeof(buff)); +#ifdef __HAIKU__ + config_fgetws(buff, sizeof_w(buff), f); +#else + fgetws(buff, sizeof_w(buff), f); +#endif + if (feof(f)) + break; - /* Make sure there are no stray newlines or hard-returns in there. */ - if (wcslen(buff) > 0) - if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; - if (wcslen(buff) > 0) - if (buff[wcslen(buff)-1] == L'\r') buff[wcslen(buff)-1] = L'\0'; + /* Make sure there are no stray newlines or hard-returns in there. */ + if (wcslen(buff) > 0) + if (buff[wcslen(buff) - 1] == L'\n') + buff[wcslen(buff) - 1] = L'\0'; + if (wcslen(buff) > 0) + if (buff[wcslen(buff) - 1] == L'\r') + buff[wcslen(buff) - 1] = L'\0'; - /* Skip any leading whitespace. */ - c = 0; - while ((buff[c] == L' ') || (buff[c] == L'\t')) - c++; + /* Skip any leading whitespace. */ + c = 0; + while ((buff[c] == L' ') || (buff[c] == L'\t')) + c++; - /* Skip empty lines. */ - if (buff[c] == L'\0') continue; + /* Skip empty lines. */ + if (buff[c] == L'\0') + continue; - /* Skip lines that (only) have a comment. */ - if ((buff[c] == L'#') || (buff[c] == L';')) continue; + /* Skip lines that (only) have a comment. */ + if ((buff[c] == L'#') || (buff[c] == L';')) + continue; - if (buff[c] == L'[') { /*Section*/ - c++; - d = 0; - while (buff[c] != L']' && buff[c]) - wctomb(&(sname[d++]), buff[c++]); - sname[d] = L'\0'; + if (buff[c] == L'[') { /*Section*/ + c++; + d = 0; + while (buff[c] != L']' && buff[c]) + wctomb(&(sname[d++]), buff[c++]); + sname[d] = L'\0'; - /* Is the section name properly terminated? */ - if (buff[c] != L']') continue; + /* Is the section name properly terminated? */ + if (buff[c] != L']') + continue; - /* Create a new section and insert it. */ - ns = malloc(sizeof(section_t)); - memset(ns, 0x00, sizeof(section_t)); - memcpy(ns->name, sname, 128); - list_add(&ns->list, &config_head); + /* Create a new section and insert it. */ + ns = malloc(sizeof(section_t)); + memset(ns, 0x00, sizeof(section_t)); + memcpy(ns->name, sname, 128); + list_add(&ns->list, &config_head); - /* New section is now the current one. */ - sec = ns; - continue; - } + /* New section is now the current one. */ + sec = ns; + continue; + } - /* Get the variable name. */ - d = 0; - while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) - wctomb(&(ename[d++]), buff[c++]); - ename[d] = L'\0'; + /* Get the variable name. */ + d = 0; + while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) + wctomb(&(ename[d++]), buff[c++]); + ename[d] = L'\0'; - /* Skip incomplete lines. */ - if (buff[c] == L'\0') continue; + /* Skip incomplete lines. */ + if (buff[c] == L'\0') + continue; - /* Look for =, skip whitespace. */ - while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) - c++; + /* Look for =, skip whitespace. */ + while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) + c++; - /* Skip incomplete lines. */ - if (buff[c] == L'\0') continue; + /* Skip incomplete lines. */ + if (buff[c] == L'\0') + continue; - /* This is where the value part starts. */ - d = c; + /* This is where the value part starts. */ + d = c; - /* Allocate a new variable entry.. */ - ne = malloc(sizeof(entry_t)); - memset(ne, 0x00, sizeof(entry_t)); - memcpy(ne->name, ename, 128); - wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); - ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; - wcstombs(ne->data, ne->wdata, sizeof(ne->data)); - ne->data[sizeof(ne->data)-1] = '\0'; + /* Allocate a new variable entry.. */ + ne = malloc(sizeof(entry_t)); + memset(ne, 0x00, sizeof(entry_t)); + memcpy(ne->name, ename, 128); + wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata) - 1); + ne->wdata[sizeof_w(ne->wdata) - 1] = L'\0'; +#ifdef _WIN32 /* Make sure the string is converted to UTF-8 rather than a legacy codepage */ + c16stombs(ne->data, ne->wdata, sizeof(ne->data)); +#else + wcstombs(ne->data, ne->wdata, sizeof(ne->data)); +#endif + ne->data[sizeof(ne->data) - 1] = '\0'; - /* .. and insert it. */ - list_add(&ne->list, &sec->entry_head); + /* .. and insert it. */ + list_add(&ne->list, &sec->entry_head); } - (void)fclose(f); + (void) fclose(f); if (do_dump_config) - config_dump(); + config_dump(); - return(1); + return (1); } - /* * Write the in-memory configuration to disk. * This is a public function, because the Settings UI @@ -370,82 +453,83 @@ config_read(wchar_t *fn) * has changed it. */ void -config_write(wchar_t *fn) +config_write(char *fn) { - wchar_t wtemp[512]; + wchar_t wtemp[512]; section_t *sec; - FILE *f; - int fl = 0; + FILE *f; + int fl = 0; #if defined(ANSI_CFG) || !defined(_WIN32) - f = plat_fopen(fn, L"wt"); + f = plat_fopen(fn, "wt"); #else - f = plat_fopen(fn, L"wt, ccs=UNICODE"); + f = plat_fopen(fn, "wt, ccs=UTF-8"); #endif - if (f == NULL) return; + if (f == NULL) + return; - sec = (section_t *)config_head.next; + sec = (section_t *) config_head.next; while (sec != NULL) { - entry_t *ent; + entry_t *ent; - if (sec->name[0]) { - mbstowcs(wtemp, sec->name, strlen(sec->name)+1); - if (fl) - fwprintf(f, L"\n[%ls]\n", wtemp); - else - fwprintf(f, L"[%ls]\n", wtemp); - fl++; - } + if (sec->name[0]) { + mbstowcs(wtemp, sec->name, strlen(sec->name) + 1); + if (fl) + fwprintf(f, L"\n[%ls]\n", wtemp); + else + fwprintf(f, L"[%ls]\n", wtemp); + fl++; + } - ent = (entry_t *)sec->entry_head.next; - while (ent != NULL) { - if (ent->name[0] != '\0') { - mbstowcs(wtemp, ent->name, 128); - if (ent->wdata[0] == L'\0') - fwprintf(f, L"%ls = \n", wtemp); - else - fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); - fl++; - } + ent = (entry_t *) sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + mbstowcs(wtemp, ent->name, 128); + if (ent->wdata[0] == L'\0') + fwprintf(f, L"%ls = \n", wtemp); + else + fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); + fl++; + } - ent = (entry_t *)ent->list.next; - } + ent = (entry_t *) ent->list.next; + } - sec = (section_t *)sec->list.next; + sec = (section_t *) sec->list.next; } - - (void)fclose(f); -} + (void) fclose(f); +} #if NOT_USED static void config_new(void) { -#if defined(ANSI_CFG) || !defined(_WIN32) +# if defined(ANSI_CFG) || !defined(_WIN32) FILE *f = _wfopen(config_file, L"wt"); -#else - FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); -#endif +# else + FILE *f = _wfopen(config_file, L"wt, ccs=UTF-8"); +# endif if (file != NULL) - (void)fclose(f); + (void) fclose(f); } #endif - /* Load "General" section. */ static void load_general(void) { char *cat = "General"; - char temp[512]; + char temp[512]; char *p; - vid_resize = !!config_get_int(cat, "vid_resize", 0); + vid_resize = config_get_int(cat, "vid_resize", 0); + if (vid_resize & ~3) + vid_resize &= 3; memset(temp, '\0', sizeof(temp)); - p = config_get_string(cat, "vid_renderer", "default"); + p = config_get_string(cat, "vid_renderer", "default"); vid_api = plat_vidapi(p); config_delete_var(cat, "vid_api"); @@ -453,236 +537,588 @@ load_general(void) video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 1); - force_43 = !!config_get_int(cat, "force_43", 0); - scale = config_get_int(cat, "scale", 1); - if (scale > 3) - scale = 3; + video_filter_method = config_get_int(cat, "video_filter_method", 1); - enable_overscan = !!config_get_int(cat, "enable_overscan", 0); + force_43 = !!config_get_int(cat, "force_43", 0); + scale = config_get_int(cat, "scale", 1); + if (scale > 3) + scale = 3; + dpi_scale = config_get_int(cat, "dpi_scale", 1); + + enable_overscan = !!config_get_int(cat, "enable_overscan", 0); vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); - video_grayscale = config_get_int(cat, "video_grayscale", 0); - video_graytype = config_get_int(cat, "video_graytype", 0); + video_grayscale = config_get_int(cat, "video_grayscale", 0); + video_graytype = config_get_int(cat, "video_graytype", 0); rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); - update_icons = config_get_int(cat, "update_icons", 1); + update_icons = config_get_int(cat, "update_icons", 1); window_remember = config_get_int(cat, "window_remember", 0); - if (window_remember) { - p = config_get_string(cat, "window_coordinates", NULL); - if (p == NULL) - p = "0, 0, 0, 0"; - sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); + if (window_remember || (vid_resize & 2)) { + if (!window_remember) + config_delete_var(cat, "window_remember"); } else { - config_delete_var(cat, "window_remember"); - config_delete_var(cat, "window_coordinates"); + config_delete_var(cat, "window_remember"); - window_w = window_h = window_x = window_y = 0; + window_w = window_h = window_x = window_y = 0; + } + + if (vid_resize & 2) { + p = config_get_string(cat, "window_fixed_res", NULL); + if (p == NULL) + p = "120x120"; + sscanf(p, "%ix%i", &fixed_size_x, &fixed_size_y); + if (fixed_size_x < 120) + fixed_size_x = 120; + if (fixed_size_x > 2048) + fixed_size_x = 2048; + if (fixed_size_y < 120) + fixed_size_y = 120; + if (fixed_size_y > 2048) + fixed_size_y = 2048; + } else { + config_delete_var(cat, "window_fixed_res"); + + fixed_size_x = fixed_size_y = 120; } sound_gain = config_get_int(cat, "sound_gain", 0); -#ifdef USE_LANGUAGE - /* - * Currently, 86Box is English (US) only, but in the future - * (version 3.0 at the earliest) other languages will be - * added, therefore it is better to future-proof the code. - */ - plat_langid = config_get_hex16(cat, "language", 0x0409); -#endif + kbd_req_capture = config_get_int(cat, "kbd_req_capture", 0); + hide_status_bar = config_get_int(cat, "hide_status_bar", 0); + hide_tool_bar = config_get_int(cat, "hide_tool_bar", 0); + + confirm_reset = config_get_int(cat, "confirm_reset", 1); + confirm_exit = config_get_int(cat, "confirm_exit", 1); + confirm_save = config_get_int(cat, "confirm_save", 1); + + p = config_get_string(cat, "language", NULL); + if (p != NULL) + lang_id = plat_language_code(p); + + mouse_sensitivity = config_get_double(cat, "mouse_sensitivity", 1.0); + if (mouse_sensitivity < 0.5) + mouse_sensitivity = 0.5; + else if (mouse_sensitivity > 2.0) + mouse_sensitivity = 2.0; + + p = config_get_string(cat, "iconset", NULL); + if (p != NULL) + strcpy(icon_set, p); + else + strcpy(icon_set, ""); -#if USE_DISCORD enable_discord = !!config_get_int(cat, "enable_discord", 0); -#endif -} + video_framerate = config_get_int(cat, "video_gl_framerate", -1); + video_vsync = config_get_int(cat, "video_gl_vsync", 0); + strncpy(video_shader, config_get_string(cat, "video_gl_shader", ""), sizeof(video_shader)); +} /* Load "Machine" section. */ static void load_machine(void) { - char *cat = "Machine"; - char *p; + char *cat = "Machine"; + char *p, *migrate_from = NULL; + int c, i, j, speed, legacy_mfg, legacy_cpu; + double multi; p = config_get_string(cat, "machine", NULL); - if (p != NULL) - machine = machine_get_machine_from_internal_name(p); - else - machine = 0; - if (machine >= machine_count()) - machine = machine_count() - 1; + if (p != NULL) { + migrate_from = p; + if (!strcmp(p, "8500ttc")) /* migrate typo... */ + machine = machine_get_machine_from_internal_name("8600ttc"); + else if (!strcmp(p, "eagle_pcspirit")) /* ...legacy names... */ + machine = machine_get_machine_from_internal_name("pcspirit"); + else if (!strcmp(p, "multitech_pc700")) + machine = machine_get_machine_from_internal_name("pc700"); + else if (!strcmp(p, "ncr_pc4i")) + machine = machine_get_machine_from_internal_name("pc4i"); + else if (!strcmp(p, "olivetti_m19")) + machine = machine_get_machine_from_internal_name("m19"); + else if (!strcmp(p, "open_xt")) + machine = machine_get_machine_from_internal_name("openxt"); + else if (!strcmp(p, "open_at")) + machine = machine_get_machine_from_internal_name("openat"); + else if (!strcmp(p, "philips_p3105")) + machine = machine_get_machine_from_internal_name("p3105"); + else if (!strcmp(p, "philips_p3120")) + machine = machine_get_machine_from_internal_name("p3120"); + else if (!strcmp(p, "olivetti_m24")) + machine = machine_get_machine_from_internal_name("m24"); + else if (!strcmp(p, "olivetti_m240")) + machine = machine_get_machine_from_internal_name("m240"); + else if (!strcmp(p, "ncr_pc8")) + machine = machine_get_machine_from_internal_name("pc8"); + else if (!strcmp(p, "olivetti_m290")) + machine = machine_get_machine_from_internal_name("m290"); + else if (!strcmp(p, "ncr_3302")) + machine = machine_get_machine_from_internal_name("3302"); + else if (!strcmp(p, "ncr_pc916sx")) + machine = machine_get_machine_from_internal_name("pc916sx"); + else if (!strcmp(p, "cbm_sl386sx16")) + machine = machine_get_machine_from_internal_name("cmdsl386sx16"); + else if (!strcmp(p, "cbm_sl386sx25")) + machine = machine_get_machine_from_internal_name("cmdsl386sx25"); + else if (!strcmp(p, "mr586")) + machine = machine_get_machine_from_internal_name("p54tp4xe_mr"); + else if (!strcmp(p, "pcv240")) + machine = machine_get_machine_from_internal_name("pcv90"); + else if (!strcmp(p, "v60n")) + machine = machine_get_machine_from_internal_name("acerv60n"); + else if (!strcmp(p, "tsunamiatx")) + machine = machine_get_machine_from_internal_name("s1846"); + else if (!strcmp(p, "trinity371")) + machine = machine_get_machine_from_internal_name("s1857"); + else if (!strcmp(p, "63a")) + machine = machine_get_machine_from_internal_name("63a1"); + else if (!strcmp(p, "4sa2")) + machine = machine_get_machine_from_internal_name("4saw2"); + else if (!strcmp(p, "award386dx")) /* ...merged machines... */ + machine = machine_get_machine_from_internal_name("award495"); + else if (!strcmp(p, "ami386dx")) + machine = machine_get_machine_from_internal_name("ami495"); + else if (!strcmp(p, "mr386dx")) + machine = machine_get_machine_from_internal_name("mr495"); + else if (!strcmp(p, "award486")) + machine = machine_get_machine_from_internal_name("award495"); + else if (!strcmp(p, "ami486")) + machine = machine_get_machine_from_internal_name("ami495"); + else if (!strcmp(p, "mr486")) + machine = machine_get_machine_from_internal_name("mr495"); + else if (!strcmp(p, "ibmps1_2121_isa")) + machine = machine_get_machine_from_internal_name("ibmps1_2121"); + else if (!strcmp(p, "fw6400gx_s1")) + machine = machine_get_machine_from_internal_name("fw6400gx"); + else if (!strcmp(p, "p54vl")) + machine = machine_get_machine_from_internal_name("p5vl"); + else if (!strcmp(p, "chariot")) + machine = machine_get_machine_from_internal_name("fmb"); + else if (!strcmp(p, "president")) { /* ...and removed machines */ + machine = machine_get_machine_from_internal_name("mb500n"); + migrate_from = NULL; + } else if (!strcmp(p, "j656vxd")) { + machine = machine_get_machine_from_internal_name("p55va"); + migrate_from = NULL; + } else { + machine = machine_get_machine_from_internal_name(p); + migrate_from = NULL; + } + } else + machine = 0; /* This is for backwards compatibility. */ p = config_get_string(cat, "model", NULL); if (p != NULL) { - /* Detect the old model typos and fix them. */ - if (! strcmp(p, "p55r2p4")) { - machine = machine_get_machine_from_internal_name("p55t2p4"); - } else { - machine = machine_get_machine_from_internal_name(p); - } - config_delete_var(cat, "model"); + migrate_from = p; + if (!strcmp(p, "p55r2p4")) /* migrate typo */ + machine = machine_get_machine_from_internal_name("p55t2p4"); + else { + machine = machine_get_machine_from_internal_name(p); + migrate_from = NULL; + } + config_delete_var(cat, "model"); } if (machine >= machine_count()) - machine = machine_count() - 1; + machine = machine_count() - 1; + + /* Copy NVR files when migrating a machine to a new internal name. */ + if (migrate_from) { + char old_fn[256]; + strcpy(old_fn, migrate_from); + strcat(old_fn, "."); + c = strlen(old_fn); + char new_fn[256]; + strcpy(new_fn, machines[machine].internal_name); + strcat(new_fn, "."); + i = strlen(new_fn); + + /* Iterate through NVR files. */ + DIR *dirp = opendir(nvr_path(".")); + if (dirp) { + struct dirent *entry; + while ((entry = readdir(dirp))) { + /* Check if this file corresponds to the old name. */ + if (strncmp(entry->d_name, old_fn, c)) + continue; + + /* Add extension to the new name. */ + strcpy(&new_fn[i], &entry->d_name[c]); + + /* Only copy if a file with the new name doesn't already exist. */ + FILE *g = nvr_fopen(new_fn, "rb"); + if (!g) { + FILE *f = nvr_fopen(entry->d_name, "rb"); + g = nvr_fopen(new_fn, "wb"); + + uint8_t buf[4096]; + while ((j = fread(buf, 1, sizeof(buf), f))) + fwrite(buf, 1, j, g); + + fclose(f); + } + fclose(g); + } + } + } + + cpu_override = config_get_int(cat, "cpu_override", 0); + cpu_f = NULL; + p = config_get_string(cat, "cpu_family", NULL); + if (p) { + if (!strcmp(p, "enh_am486dx2")) /* migrate modified names */ + cpu_f = cpu_get_family("am486dx2_slenh"); + else if (!strcmp(p, "enh_am486dx4")) + cpu_f = cpu_get_family("am486dx4_slenh"); + else + cpu_f = cpu_get_family(p); + + if (cpu_f && !cpu_family_is_eligible(cpu_f, machine)) /* only honor eligible families */ + cpu_f = NULL; + } else { + /* Backwards compatibility with the previous CPU model system. */ + legacy_mfg = config_get_int(cat, "cpu_manufacturer", 0); + legacy_cpu = config_get_int(cat, "cpu", 0); + + /* Check if either legacy ID is present, and if they are within bounds. */ + if (((legacy_mfg > 0) || (legacy_cpu > 0)) && (legacy_mfg >= 0) && (legacy_mfg < 4) && (legacy_cpu >= 0)) { + /* Look for a machine entry on the legacy table. */ + p = machine_get_internal_name(); + c = 0; + while (cpu_legacy_table[c].machine) { + if (!strcmp(p, cpu_legacy_table[c].machine)) + break; + c++; + } + if (cpu_legacy_table[c].machine) { + /* Determine the amount of CPU entries on the table. */ + i = -1; + while (cpu_legacy_table[c].tables[legacy_mfg][++i].family) + ; + + /* If the CPU ID is out of bounds, reset to the last known ID. */ + if (legacy_cpu >= i) + legacy_cpu = i - 1; + + const cpu_legacy_table_t *legacy_table_entry = &cpu_legacy_table[c].tables[legacy_mfg][legacy_cpu]; + + /* Check if the referenced family exists. */ + cpu_f = cpu_get_family(legacy_table_entry->family); + if (cpu_f) { + /* Save the new values. */ + config_set_string(cat, "cpu_family", (char *) legacy_table_entry->family); + config_set_int(cat, "cpu_speed", legacy_table_entry->rspeed); + config_set_double(cat, "cpu_multi", legacy_table_entry->multi); + } + } + } + } + + if (cpu_f) { + speed = config_get_int(cat, "cpu_speed", 0); + multi = config_get_double(cat, "cpu_multi", 0); + + /* Find the configured CPU. */ + cpu = 0; + c = 0; + i = 256; + while (cpu_f->cpus[cpu].cpu_type) { + if (cpu_is_eligible(cpu_f, cpu, machine)) { /* skip ineligible CPUs */ + if ((cpu_f->cpus[cpu].rspeed == speed) && (cpu_f->cpus[cpu].multi == multi)) /* exact speed/multiplier match */ + break; + else if ((cpu_f->cpus[cpu].rspeed >= speed) && (i == 256)) /* closest speed match */ + i = cpu; + c = cpu; /* store fastest eligible CPU */ + } + cpu++; + } + if (!cpu_f->cpus[cpu].cpu_type) /* if no exact match was found, use closest matching faster CPU, or fastest eligible CPU */ + cpu = MIN(i, c); + } else { /* default */ + /* Find first eligible family. */ + c = 0; + while (!cpu_family_is_eligible(&cpu_families[c], machine)) { + if (cpu_families[c++].package == 0) { /* end of list */ + fatal("No eligible CPU families for the selected machine\n"); + return; + } + } + cpu_f = (cpu_family_t *) &cpu_families[c]; + + /* Find first eligible CPU in that family. */ + cpu = 0; + while (!cpu_is_eligible(cpu_f, cpu, machine)) { + if (cpu_f->cpus[cpu++].cpu_type == 0) { /* end of list */ + cpu = 0; + break; + } + } + } + cpu_s = (CPU *) &cpu_f->cpus[cpu]; - cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); - cpu = config_get_int(cat, "cpu", 0); cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); - p = (char *)config_get_string(cat, "fpu_type", "none"); - fpu_type = fpu_get_type(machine, cpu_manufacturer, cpu, p); + p = (char *) config_get_string(cat, "fpu_type", "none"); + fpu_type = fpu_get_type(cpu_f, cpu, p); - mem_size = config_get_int(cat, "mem_size", 4096); - + mem_size = config_get_int(cat, "mem_size", 64); #if 0 - if (mem_size < (((machines[machine].flags & MACHINE_AT) && + if (mem_size < ((machine_has_bus(machine, MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) - mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); -#endif - + mem_size = (((machine_has_bus(machine, MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); +#endif + if (mem_size > 2097152) - mem_size = 2097152; + mem_size = 2097152; cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); p = config_get_string(cat, "time_sync", NULL); - if (p != NULL) { - if (!strcmp(p, "disabled")) - time_sync = TIME_SYNC_DISABLED; - else - if (!strcmp(p, "local")) - time_sync = TIME_SYNC_ENABLED; - else - if (!strcmp(p, "utc") || !strcmp(p, "gmt")) - time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; - else - time_sync = TIME_SYNC_ENABLED; + if (p != NULL) { + if (!strcmp(p, "disabled")) + time_sync = TIME_SYNC_DISABLED; + else if (!strcmp(p, "local")) + time_sync = TIME_SYNC_ENABLED; + else if (!strcmp(p, "utc") || !strcmp(p, "gmt")) + time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; + else + time_sync = TIME_SYNC_ENABLED; } else - time_sync = !!config_get_int(cat, "enable_sync", 1); + time_sync = !!config_get_int(cat, "enable_sync", 1); + + pit_mode = config_get_int(cat, "pit_mode", -1); /* Remove this after a while.. */ config_delete_var(cat, "nvr_path"); config_delete_var(cat, "enable_sync"); } - /* Load "Video" section. */ static void load_video(void) { char *cat = "Video"; char *p; - int free_p = 0; + int free_p = 0; - if (machines[machine].flags & MACHINE_VIDEO_FIXED) { - config_delete_var(cat, "gfxcard"); - gfxcard = VID_INTERNAL; + if (machine_has_flags(machine, MACHINE_VIDEO_ONLY)) { + config_delete_var(cat, "gfxcard"); + gfxcard = VID_INTERNAL; } else { - p = config_get_string(cat, "gfxcard", NULL); - if (p == NULL) { - if (machines[machine].flags & MACHINE_VIDEO) { - p = (char *)malloc((strlen("internal")+1)*sizeof(char)); - strcpy(p, "internal"); - } else { - p = (char *)malloc((strlen("none")+1)*sizeof(char)); - strcpy(p, "none"); - } - free_p = 1; - } - gfxcard = video_get_video_from_internal_name(p); - if (free_p) - free(p); + p = config_get_string(cat, "gfxcard", NULL); + if (p == NULL) { + if (machine_has_flags(machine, MACHINE_VIDEO)) { + p = (char *) malloc((strlen("internal") + 1) * sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *) malloc((strlen("none") + 1) * sizeof(char)); + strcpy(p, "none"); + } + free_p = 1; + } + if (!strcmp(p, "virge375_vbe20_pci")) /* migrate renamed cards */ + gfxcard = video_get_video_from_internal_name("virge385_pci"); + else + gfxcard = video_get_video_from_internal_name(p); + if (free_p) + free(p); } - voodoo_enabled = !!config_get_int(cat, "voodoo", 0); + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); + ibm8514_enabled = !!config_get_int(cat, "8514a", 0); + xga_enabled = !!config_get_int(cat, "xga", 0); + show_second_monitors = !!config_get_int(cat, "show_second_monitors", 1); + p = config_get_string(cat, "gfxcard_2", NULL); + if (!p) + p = "none"; + gfxcard_2 = video_get_video_from_internal_name(p); } +static void +load_monitor(int monitor_index) +{ + char monitor_config_name[sizeof("Monitor #") + 12] = { [0] = 0 }; + char *ptr = NULL; + + if (monitor_index == 0) { + /* Migrate configs */ + ptr = config_get_string("General", "window_coordinates", NULL); + + config_delete_var("General", "window_coordinates"); + } + snprintf(monitor_config_name, sizeof(monitor_config_name), "Monitor #%i", monitor_index + 1); + if (!ptr) + ptr = config_get_string(monitor_config_name, "window_coordinates", "0, 0, 0, 0"); + if (window_remember || (vid_resize & 2)) + sscanf(ptr, "%i, %i, %i, %i", + &monitor_settings[monitor_index].mon_window_x, &monitor_settings[monitor_index].mon_window_y, + &monitor_settings[monitor_index].mon_window_w, &monitor_settings[monitor_index].mon_window_h); +} + +static void +save_monitor(int monitor_index) +{ + char monitor_config_name[sizeof("Monitor #") + 12] = { [0] = 0 }; + char saved_coordinates[12 * 4 + 8 + 1] = { [0] = 0 }; + + snprintf(monitor_config_name, sizeof(monitor_config_name), "Monitor #%i", monitor_index + 1); + if (!(monitor_settings[monitor_index].mon_window_x == 0 + && monitor_settings[monitor_index].mon_window_y == 0 + && monitor_settings[monitor_index].mon_window_w == 0 + && monitor_settings[monitor_index].mon_window_h == 0) + && (window_remember || (vid_resize & 2))) { + snprintf(saved_coordinates, sizeof(saved_coordinates), "%i, %i, %i, %i", monitor_settings[monitor_index].mon_window_x, monitor_settings[monitor_index].mon_window_y, + monitor_settings[monitor_index].mon_window_w, monitor_settings[monitor_index].mon_window_h); + + config_set_string(monitor_config_name, "window_coordinates", saved_coordinates); + } else + config_delete_var(monitor_config_name, "window_coordinates"); +} /* Load "Input Devices" section. */ static void load_input_devices(void) { char *cat = "Input devices"; - char temp[512]; - int c, d; + char temp[512]; + int c, d; char *p; p = config_get_string(cat, "mouse_type", NULL); if (p != NULL) - mouse_type = mouse_get_from_internal_name(p); - else - mouse_type = 0; + mouse_type = mouse_get_from_internal_name(p); + else + mouse_type = 0; - joystick_type = config_get_int(cat, "joystick_type", JOYSTICK_TYPE_NONE); + p = config_get_string(cat, "joystick_type", NULL); + if (p != NULL) { + if (!strcmp(p, "standard_2button")) /* migrate renamed types */ + joystick_type = joystick_get_from_internal_name("2axis_2button"); + else if (!strcmp(p, "standard_4button")) + joystick_type = joystick_get_from_internal_name("2axis_4button"); + else if (!strcmp(p, "standard_6button")) + joystick_type = joystick_get_from_internal_name("2axis_6button"); + else if (!strcmp(p, "standard_8button")) + joystick_type = joystick_get_from_internal_name("2axis_8button"); + else if (!strcmp(p, "ch_flighstick_pro")) /* fix typo */ + joystick_type = joystick_get_from_internal_name("ch_flightstick_pro"); + else + joystick_type = joystick_get_from_internal_name(p); - for (c=0; c 511) + fatal("load_sound(): strlen(p) > 511\n"); else - strncpy(temp, p, 511); + strncpy(temp, p, strlen(p) + 1); if (!strcmp(temp, "float") || !strcmp(temp, "1")) - sound_is_float = 1; - else - sound_is_float = 0; -} + sound_is_float = 1; + else + sound_is_float = 0; + p = config_get_string(cat, "fm_driver", "nuked"); + if (!strcmp(p, "ymfm")) { + fm_driver = FM_DRV_YMFM; + } else { + fm_driver = FM_DRV_NUKED; + } +} /* Load "Network" section. */ static void @@ -693,81 +1129,928 @@ load_network(void) p = config_get_string(cat, "net_type", NULL); if (p != NULL) { - if (!strcmp(p, "pcap") || !strcmp(p, "1")) - network_type = NET_TYPE_PCAP; - else - if (!strcmp(p, "slirp") || !strcmp(p, "2")) - network_type = NET_TYPE_SLIRP; - else - network_type = NET_TYPE_NONE; + if (!strcmp(p, "pcap") || !strcmp(p, "1")) + network_type = NET_TYPE_PCAP; + else if (!strcmp(p, "slirp") || !strcmp(p, "2")) + network_type = NET_TYPE_SLIRP; + else + network_type = NET_TYPE_NONE; } else - network_type = NET_TYPE_NONE; + network_type = NET_TYPE_NONE; memset(network_host, '\0', sizeof(network_host)); p = config_get_string(cat, "net_host_device", NULL); if (p == NULL) { - p = config_get_string(cat, "net_host_device", NULL); - if (p != NULL) - config_delete_var(cat, "net_host_device"); + p = config_get_string(cat, "net_host_device", NULL); + if (p != NULL) + config_delete_var(cat, "net_host_device"); } if (p != NULL) { - if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) { - if ((network_ndev == 1) && strcmp(network_host, "none")) { - ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2094, (wchar_t *) IDS_2129); - } else if (network_dev_to_id(p) == -1) { - ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2129); - } + if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) { + if ((network_ndev == 1) && strcmp(network_host, "none")) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2094, (wchar_t *) IDS_2129); + } else if (network_dev_to_id(p) == -1) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2129); + } - strcpy(network_host, "none"); - } else { - if (strlen(p) <= 522) - strcpy(network_host, p); - else - strncpy(network_host, p, 522); - } + strcpy(network_host, "none"); + } else { + strncpy(network_host, p, sizeof(network_host) - 1); + } } else - strcpy(network_host, "none"); + strcpy(network_host, "none"); p = config_get_string(cat, "net_card", NULL); if (p != NULL) - network_card = network_card_get_from_internal_name(p); - else - network_card = 0; + network_card = network_card_get_from_internal_name(p); + else + network_card = 0; } - /* Load "Ports" section. */ static void load_ports(void) { char *cat = "Ports (COM & LPT)"; char *p; - char temp[512]; - int c, d; + char temp[512]; + int c, d; - for (c = 0; c < 2; c++) { - sprintf(temp, "serial%d_enabled", c + 1); - serial_enabled[c] = !!config_get_int(cat, temp, 1); + for (c = 0; c < SERIAL_MAX; c++) { + sprintf(temp, "serial%d_enabled", c + 1); + serial_enabled[c] = !!config_get_int(cat, temp, (c >= 2) ? 0 : 1); + + /* + sprintf(temp, "serial%d_device", c + 1); + p = (char *) config_get_string(cat, temp, "none"); + com_ports[c].device = com_device_get_from_internal_name(p); + */ } - for (c = 0; c < 3; c++) { - sprintf(temp, "lpt%d_enabled", c + 1); - lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0); + for (c = 0; c < PARALLEL_MAX; c++) { + sprintf(temp, "lpt%d_enabled", c + 1); + lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0); - sprintf(temp, "lpt%d_device", c + 1); - p = (char *) config_get_string(cat, temp, "none"); - lpt_ports[c].device = lpt_device_get_from_internal_name(p); + sprintf(temp, "lpt%d_device", c + 1); + p = (char *) config_get_string(cat, temp, "none"); + lpt_ports[c].device = lpt_device_get_from_internal_name(p); } /* Legacy config compatibility. */ d = config_get_int(cat, "lpt_enabled", 2); if (d < 2) { - for (c = 0; c < 3; c++) - lpt_ports[c].enabled = d; + for (c = 0; c < PARALLEL_MAX; c++) + lpt_ports[c].enabled = d; } config_delete_var(cat, "lpt_enabled"); } +/* Load "Storage Controllers" section. */ +static void +load_storage_controllers(void) +{ + char *cat = "Storage controllers"; + char *p, temp[512]; + int c, min = 0; + int free_p = 0; + + /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ + backwards_compat2 = (find_section(cat) == NULL); + + /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ + p = config_get_string(cat, "scsicard", NULL); + if (p != NULL) { + scsi_card_current[0] = scsi_card_get_from_internal_name(p); + min++; + } + config_delete_var(cat, "scsi_card"); + + for (c = min; c < SCSI_BUS_MAX; c++) { + sprintf(temp, "scsicard_%d", c + 1); + + p = config_get_string(cat, temp, NULL); + if (p != NULL) + scsi_card_current[c] = scsi_card_get_from_internal_name(p); + else + scsi_card_current[c] = 0; + } + + p = config_get_string(cat, "fdc", NULL); + if (p != NULL) + fdc_type = fdc_card_get_from_internal_name(p); + else + fdc_type = FDC_INTERNAL; + + p = config_get_string(cat, "hdc", NULL); + if (p == NULL) { + if (machine_has_flags(machine, MACHINE_HDC)) { + p = (char *) malloc((strlen("internal") + 1) * sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *) malloc((strlen("none") + 1) * sizeof(char)); + strcpy(p, "none"); + } + free_p = 1; + } + if (!strcmp(p, "mfm_xt")) + hdc_current = hdc_get_from_internal_name("st506_xt"); + else if (!strcmp(p, "mfm_xt_dtc5150x")) + hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x"); + else if (!strcmp(p, "mfm_at")) + hdc_current = hdc_get_from_internal_name("st506_at"); + else if (!strcmp(p, "vlb_isa")) + hdc_current = hdc_get_from_internal_name("ide_vlb"); + else if (!strcmp(p, "vlb_isa_2ch")) + hdc_current = hdc_get_from_internal_name("ide_vlb_2ch"); + else + hdc_current = hdc_get_from_internal_name(p); + + if (free_p) { + free(p); + p = NULL; + } + + ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); + ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); + + /* TODO: Re-enable by default after we actually have a proper machine flag for this. */ + cassette_enable = !!config_get_int(cat, "cassette_enabled", 0); + p = config_get_string(cat, "cassette_file", ""); + if (strlen(p) > 511) + fatal("load_storage_controllers(): strlen(p) > 511\n"); + else + strncpy(cassette_fname, p, MIN(512, strlen(p) + 1)); + p = config_get_string(cat, "cassette_mode", ""); + if (strlen(p) > 511) + fatal("load_storage_controllers(): strlen(p) > 511\n"); + else + strncpy(cassette_mode, p, MIN(512, strlen(p) + 1)); + cassette_pos = config_get_int(cat, "cassette_position", 0); + cassette_srate = config_get_int(cat, "cassette_srate", 44100); + cassette_append = !!config_get_int(cat, "cassette_append", 0); + cassette_pcm = config_get_int(cat, "cassette_pcm", 0); + cassette_ui_writeprot = !!config_get_int(cat, "cassette_writeprot", 0); + + for (c = 0; c < 2; c++) { + sprintf(temp, "cartridge_%02i_fn", c + 1); + p = config_get_string(cat, temp, ""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(cart_fns[c])); + } else +#endif + if (strlen(p) > 511) + fatal("load_storage_controllers(): strlen(p) > 511\n"); + else + strncpy(cart_fns[c], p, strlen(p) + 1); + } +} + +/* Load "Hard Disks" section. */ +static void +load_hard_disks(void) +{ + char *cat = "Hard disks"; + char temp[512], tmp2[512]; + char s[512]; + int c; + char *p; + uint32_t max_spt, max_hpc, max_tracks; + uint32_t board = 0, dev = 0; + + memset(temp, '\0', sizeof(temp)); + for (c = 0; c < HDD_NUM; c++) { + sprintf(temp, "hdd_%02i_parameters", c + 1); + p = config_get_string(cat, temp, "0, 0, 0, 0, none"); + sscanf(p, "%u, %u, %u, %i, %s", + &hdd[c].spt, &hdd[c].hpc, &hdd[c].tracks, (int *) &hdd[c].wp, s); + + hdd[c].bus = hdd_string_to_bus(s, 0); + switch (hdd[c].bus) { + case HDD_BUS_DISABLED: + default: + max_spt = max_hpc = max_tracks = 0; + break; + + case HDD_BUS_MFM: + max_spt = 26; /* 26 for RLL */ + max_hpc = 15; + max_tracks = 2047; + break; + + case HDD_BUS_XTA: + max_spt = 63; + max_hpc = 16; + max_tracks = 1023; + break; + + case HDD_BUS_ESDI: + max_spt = 99; + max_hpc = 16; + max_tracks = 266305; + break; + + case HDD_BUS_IDE: + max_spt = 63; + max_hpc = 16; + max_tracks = 266305; + break; + + case HDD_BUS_SCSI: + max_spt = 99; + max_hpc = 255; + max_tracks = 266305; + break; + } + + if (hdd[c].spt > max_spt) + hdd[c].spt = max_spt; + if (hdd[c].hpc > max_hpc) + hdd[c].hpc = max_hpc; + if (hdd[c].tracks > max_tracks) + hdd[c].tracks = max_tracks; + + sprintf(temp, "hdd_%02i_speed", c + 1); + switch (hdd[c].bus) { + case HDD_BUS_IDE: + sprintf(tmp2, "1997_5400rpm"); + break; + default: + sprintf(tmp2, "ramdisk"); + break; + } + p = config_get_string(cat, temp, tmp2); + hdd[c].speed_preset = hdd_preset_get_from_internal_name(p); + + /* MFM/RLL */ + sprintf(temp, "hdd_%02i_mfm_channel", c + 1); + if (hdd[c].bus == HDD_BUS_MFM) + hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* XTA */ + sprintf(temp, "hdd_%02i_xta_channel", c + 1); + if (hdd[c].bus == HDD_BUS_XTA) + hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* ESDI */ + sprintf(temp, "hdd_%02i_esdi_channel", c + 1); + if (hdd[c].bus == HDD_BUS_ESDI) + hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* IDE */ + sprintf(temp, "hdd_%02i_ide_channel", c + 1); + if (hdd[c].bus == HDD_BUS_IDE) { + sprintf(tmp2, "%01u:%01u", c >> 1, c & 1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + hdd[c].ide_channel = (board << 1) + dev; + + if (hdd[c].ide_channel > 7) + hdd[c].ide_channel = 7; + } else { + config_delete_var(cat, temp); + } + + /* SCSI */ + if (hdd[c].bus == HDD_BUS_SCSI) { + sprintf(temp, "hdd_%02i_scsi_location", c + 1); + sprintf(tmp2, "%01u:%02u", SCSI_BUS_MAX, c + 2); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%02u", &board, &dev); + if (board >= SCSI_BUS_MAX) { + /* Invalid bus - check legacy ID */ + sprintf(temp, "hdd_%02i_scsi_id", c + 1); + hdd[c].scsi_id = config_get_int(cat, temp, c + 2); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + } else { + board %= SCSI_BUS_MAX; + dev &= 15; + hdd[c].scsi_id = (board << 4) + dev; + } + } else { + sprintf(temp, "hdd_%02i_scsi_location", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "hdd_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); + memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); + sprintf(temp, "hdd_%02i_fn", c + 1); + p = config_get_string(cat, temp, ""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + /* + * ANOTHER NOTE: + * When loading differencing VHDs, the absolute path is required. + * So we should not convert absolute paths to relative. -sards + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the CFG path. Just strip + * that off for now... + */ + wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); + } else +#endif + if (path_abs(p)) { + strncpy(hdd[c].fn, p, sizeof(hdd[c].fn) - 1); + } else { + path_append_filename(hdd[c].fn, usr_path, p); + } + path_normalize(hdd[c].fn); + + /* If disk is empty or invalid, mark it for deletion. */ + if (!hdd_is_valid(c)) { + sprintf(temp, "hdd_%02i_parameters", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_preide_channels", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channels", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "hdd_%02i_mfm_channel", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + } +} + +/* TODO: Backwards compatibility, get rid of this when enough time has passed. */ +/* Load "Floppy Drives" section. */ +static void +load_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512], *p; + int c; + + if (!backwards_compat) + return; + + for (c = 0; c < FDD_NUM; c++) { + sprintf(temp, "fdd_%02i_type", c + 1); + p = config_get_string(cat, temp, (c < 2) ? "525_2dd" : "none"); + fdd_set_type(c, fdd_get_from_internal_name(p)); + if (fdd_get_type(c) > 13) + fdd_set_type(c, 13); + config_delete_var(cat, temp); + + sprintf(temp, "fdd_%02i_fn", c + 1); + p = config_get_string(cat, temp, ""); + config_delete_var(cat, temp); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); + } else +#endif + if (strlen(p) > 511) + fatal("load_floppy_drives(): strlen(p) > 511\n"); + else + strncpy(floppyfns[c], p, strlen(p) + 1); + + /* if (*wp != L'\0') + config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ + sprintf(temp, "fdd_%02i_writeprot", c + 1); + ui_writeprot[c] = !!config_get_int(cat, temp, 0); + config_delete_var(cat, temp); + sprintf(temp, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); + config_delete_var(cat, temp); + sprintf(temp, "fdd_%02i_check_bpb", c + 1); + fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); + config_delete_var(cat, temp); + } + + delete_section_if_empty(cat); +} + +/* Load "Floppy and CD-ROM Drives" section. */ +static void +load_floppy_and_cdrom_drives(void) +{ + char *cat = "Floppy and CD-ROM drives"; + char temp[512], tmp2[512], *p; + char s[512]; + unsigned int board = 0, dev = 0; + int c, d = 0; + + /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ + backwards_compat = (find_section(cat) == NULL); + + memset(temp, 0x00, sizeof(temp)); + for (c = 0; c < FDD_NUM; c++) { + sprintf(temp, "fdd_%02i_type", c + 1); + p = config_get_string(cat, temp, (c < 2) ? "525_2dd" : "none"); + fdd_set_type(c, fdd_get_from_internal_name(p)); + if (fdd_get_type(c) > 13) + fdd_set_type(c, 13); + + sprintf(temp, "fdd_%02i_fn", c + 1); + p = config_get_string(cat, temp, ""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); + } else +#endif + if (strlen(p) > 511) + fatal("load_floppy_and_cdrom_drives(): strlen(p) > 511\n"); + else + strncpy(floppyfns[c], p, strlen(p) + 1); + + /* if (*wp != L'\0') + config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ + sprintf(temp, "fdd_%02i_writeprot", c + 1); + ui_writeprot[c] = !!config_get_int(cat, temp, 0); + sprintf(temp, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); + sprintf(temp, "fdd_%02i_check_bpb", c + 1); + fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); + + /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { + sprintf(temp, "fdd_%02i_type", c + 1); + config_delete_var(cat, temp); + } + if (strlen(floppyfns[c]) == 0) { + sprintf(temp, "fdd_%02i_fn", c + 1); + config_delete_var(cat, temp); + } + if (ui_writeprot[c] == 0) { + sprintf(temp, "fdd_%02i_writeprot", c + 1); + config_delete_var(cat, temp); + } + if (fdd_get_turbo(c) == 0) { + sprintf(temp, "fdd_%02i_turbo", c + 1); + config_delete_var(cat, temp); + } + if (fdd_get_check_bpb(c) == 1) { + sprintf(temp, "fdd_%02i_check_bpb", c + 1); + config_delete_var(cat, temp); + } + } + + memset(temp, 0x00, sizeof(temp)); + for (c = 0; c < CDROM_NUM; c++) { + sprintf(temp, "cdrom_%02i_host_drive", c + 1); + cdrom[c].host_drive = config_get_int(cat, temp, 0); + cdrom[c].prev_host_drive = cdrom[c].host_drive; + + sprintf(temp, "cdrom_%02i_parameters", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) + sscanf(p, "%01u, %s", &d, s); + else if (c == 0) + /* If this is the first drive, unmute the audio. */ + sscanf("1, none", "%01u, %s", &d, s); + else + sscanf("0, none", "%01u, %s", &d, s); + cdrom[c].sound_on = d; + cdrom[c].bus_type = hdd_string_to_bus(s, 1); + + sprintf(temp, "cdrom_%02i_speed", c + 1); + cdrom[c].speed = config_get_int(cat, temp, 8); + + /* Default values, needed for proper operation of the Settings dialog. */ + cdrom[c].ide_channel = cdrom[c].scsi_device_id = c + 2; + + if (cdrom[c].bus_type == CDROM_BUS_ATAPI) { + sprintf(temp, "cdrom_%02i_ide_channel", c + 1); + sprintf(tmp2, "%01u:%01u", (c + 2) >> 1, (c + 2) & 1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom[c].ide_channel = (board << 1) + dev; + + if (cdrom[c].ide_channel > 7) + cdrom[c].ide_channel = 7; + } else if (cdrom[c].bus_type == CDROM_BUS_SCSI) { + sprintf(temp, "cdrom_%02i_scsi_location", c + 1); + sprintf(tmp2, "%01u:%02u", SCSI_BUS_MAX, c + 2); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%02u", &board, &dev); + if (board >= SCSI_BUS_MAX) { + /* Invalid bus - check legacy ID */ + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + cdrom[c].scsi_device_id = config_get_int(cat, temp, c + 2); + + if (cdrom[c].scsi_device_id > 15) + cdrom[c].scsi_device_id = 15; + } else { + board %= SCSI_BUS_MAX; + dev &= 15; + cdrom[c].scsi_device_id = (board << 4) + dev; + } + } + + if (cdrom[c].bus_type != CDROM_BUS_ATAPI) { + sprintf(temp, "cdrom_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + } + + if (cdrom[c].bus_type != CDROM_BUS_SCSI) { + sprintf(temp, "cdrom_%02i_scsi_location", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + p = config_get_string(cat, temp, ""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path)); + } else +#endif + strncpy(cdrom[c].image_path, p, sizeof(cdrom[c].image_path) - 1); + + if (cdrom[c].host_drive && (cdrom[c].host_drive != 200)) + cdrom[c].host_drive = 0; + + if ((cdrom[c].host_drive == 0x200) && (strlen(cdrom[c].image_path) == 0)) + cdrom[c].host_drive = 0; + + /* If the CD-ROM is disabled, delete all its variables. */ + if (cdrom[c].bus_type == CDROM_BUS_DISABLED) { + sprintf(temp, "cdrom_%02i_host_drive", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_parameters", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_iso_path", c + 1); + config_delete_var(cat, temp); + } +} + +/* Load "Other Removable Devices" section. */ +static void +load_other_removable_devices(void) +{ + char *cat = "Other removable devices"; + char temp[512], tmp2[512], *p; + char s[512]; + unsigned int board = 0, dev = 0; + int c, d = 0; + + /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ + if (backwards_compat) { + memset(temp, 0x00, sizeof(temp)); + for (c = 0; c < CDROM_NUM; c++) { + sprintf(temp, "cdrom_%02i_host_drive", c + 1); + cdrom[c].host_drive = config_get_int(cat, temp, 0); + cdrom[c].prev_host_drive = cdrom[c].host_drive; + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_parameters", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) + sscanf(p, "%01u, %s", &d, s); + else + sscanf("0, none", "%01u, %s", &d, s); + cdrom[c].sound_on = d; + cdrom[c].bus_type = hdd_string_to_bus(s, 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_speed", c + 1); + cdrom[c].speed = config_get_int(cat, temp, 8); + config_delete_var(cat, temp); + + /* Default values, needed for proper operation of the Settings dialog. */ + cdrom[c].ide_channel = cdrom[c].scsi_device_id = c + 2; + config_delete_var(cat, temp); + + if (cdrom[c].bus_type == CDROM_BUS_ATAPI) { + sprintf(temp, "cdrom_%02i_ide_channel", c + 1); + sprintf(tmp2, "%01u:%01u", (c + 2) >> 1, (c + 2) & 1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom[c].ide_channel = (board << 1) + dev; + + if (cdrom[c].ide_channel > 7) + cdrom[c].ide_channel = 7; + + config_delete_var(cat, temp); + } else if (cdrom[c].bus_type == CDROM_BUS_SCSI) { + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + cdrom[c].scsi_device_id = config_get_int(cat, temp, c + 2); + + if (cdrom[c].scsi_device_id > 15) + cdrom[c].scsi_device_id = 15; + + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + p = config_get_string(cat, temp, ""); + config_delete_var(cat, temp); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path)); + } else +#endif + strncpy(cdrom[c].image_path, p, sizeof(cdrom[c].image_path) - 1); + + if (cdrom[c].host_drive && (cdrom[c].host_drive != 200)) + cdrom[c].host_drive = 0; + + if ((cdrom[c].host_drive == 0x200) && (strlen(cdrom[c].image_path) == 0)) + cdrom[c].host_drive = 0; + } + } + backwards_compat = 0; + + memset(temp, 0x00, sizeof(temp)); + for (c = 0; c < ZIP_NUM; c++) { + sprintf(temp, "zip_%02i_parameters", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) + sscanf(p, "%01u, %s", &zip_drives[c].is_250, s); + else + sscanf("0, none", "%01u, %s", &zip_drives[c].is_250, s); + zip_drives[c].bus_type = hdd_string_to_bus(s, 1); + + /* Default values, needed for proper operation of the Settings dialog. */ + zip_drives[c].ide_channel = zip_drives[c].scsi_device_id = c + 2; + + if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { + sprintf(temp, "zip_%02i_ide_channel", c + 1); + sprintf(tmp2, "%01u:%01u", (c + 2) >> 1, (c + 2) & 1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + zip_drives[c].ide_channel = (board << 1) + dev; + + if (zip_drives[c].ide_channel > 7) + zip_drives[c].ide_channel = 7; + } else if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { + sprintf(temp, "zip_%02i_scsi_location", c + 1); + sprintf(tmp2, "%01u:%02u", SCSI_BUS_MAX, c + 2); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%02u", &board, &dev); + if (board >= SCSI_BUS_MAX) { + /* Invalid bus - check legacy ID */ + sprintf(temp, "zip_%02i_scsi_id", c + 1); + zip_drives[c].scsi_device_id = config_get_int(cat, temp, c + 2); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + } else { + board %= SCSI_BUS_MAX; + dev &= 15; + zip_drives[c].scsi_device_id = (board << 4) + dev; + } + } + + if (zip_drives[c].bus_type != ZIP_BUS_ATAPI) { + sprintf(temp, "zip_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + } + + if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { + sprintf(temp, "zip_%02i_scsi_location", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_image_path", c + 1); + p = config_get_string(cat, temp, ""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); + } else +#endif + strncpy(zip_drives[c].image_path, p, sizeof(zip_drives[c].image_path) - 1); + + /* If the CD-ROM is disabled, delete all its variables. */ + if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { + sprintf(temp, "zip_%02i_host_drive", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_parameters", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_image_path", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_iso_path", c + 1); + config_delete_var(cat, temp); + } + + memset(temp, 0x00, sizeof(temp)); + for (c = 0; c < MO_NUM; c++) { + sprintf(temp, "mo_%02i_parameters", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) + sscanf(p, "%u, %s", &mo_drives[c].type, s); + else + sscanf("00, none", "%u, %s", &mo_drives[c].type, s); + mo_drives[c].bus_type = hdd_string_to_bus(s, 1); + + /* Default values, needed for proper operation of the Settings dialog. */ + mo_drives[c].ide_channel = mo_drives[c].scsi_device_id = c + 2; + + if (mo_drives[c].bus_type == MO_BUS_ATAPI) { + sprintf(temp, "mo_%02i_ide_channel", c + 1); + sprintf(tmp2, "%01u:%01u", (c + 2) >> 1, (c + 2) & 1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + mo_drives[c].ide_channel = (board << 1) + dev; + + if (mo_drives[c].ide_channel > 7) + mo_drives[c].ide_channel = 7; + } else if (mo_drives[c].bus_type == MO_BUS_SCSI) { + sprintf(temp, "mo_%02i_scsi_location", c + 1); + sprintf(tmp2, "%01u:%02u", SCSI_BUS_MAX, c + 2); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%02u", &board, &dev); + if (board >= SCSI_BUS_MAX) { + /* Invalid bus - check legacy ID */ + sprintf(temp, "mo_%02i_scsi_id", c + 1); + mo_drives[c].scsi_device_id = config_get_int(cat, temp, c + 2); + + if (mo_drives[c].scsi_device_id > 15) + mo_drives[c].scsi_device_id = 15; + } else { + board %= SCSI_BUS_MAX; + dev &= 15; + mo_drives[c].scsi_device_id = (board << 4) + dev; + } + } + + if (mo_drives[c].bus_type != MO_BUS_ATAPI) { + sprintf(temp, "mo_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + } + + if (mo_drives[c].bus_type != MO_BUS_SCSI) { + sprintf(temp, "mo_%02i_scsi_location", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "mo_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "mo_%02i_image_path", c + 1); + p = config_get_string(cat, temp, ""); + + strncpy(mo_drives[c].image_path, p, sizeof(mo_drives[c].image_path) - 1); + + /* If the CD-ROM is disabled, delete all its variables. */ + if (mo_drives[c].bus_type == MO_BUS_DISABLED) { + sprintf(temp, "mo_%02i_host_drive", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "mo_%02i_parameters", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "mo_%02i_ide_channel", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "mo_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "mo_%02i_image_path", c + 1); + config_delete_var(cat, temp); + } + + sprintf(temp, "mo_%02i_iso_path", c + 1); + config_delete_var(cat, temp); + } +} /* Load "Other Peripherals" section. */ static void @@ -775,560 +2058,82 @@ load_other_peripherals(void) { char *cat = "Other peripherals"; char *p; - char temp[512]; - int c, free_p = 0; - - p = config_get_string(cat, "scsicard", NULL); - if (p != NULL) - scsi_card_current = scsi_card_get_from_internal_name(p); - else - scsi_card_current = 0; + char temp[512]; + int c, free_p = 0; - p = config_get_string(cat, "fdc", NULL); - if (p != NULL) - fdc_type = fdc_card_get_from_internal_name(p); - else - fdc_type = FDC_INTERNAL; + if (backwards_compat2) { + p = config_get_string(cat, "scsicard", NULL); + if (p != NULL) + scsi_card_current[0] = scsi_card_get_from_internal_name(p); + else + scsi_card_current[0] = 0; + config_delete_var(cat, "scsicard"); - p = config_get_string(cat, "hdc", NULL); - if (p == NULL) { - if (machines[machine].flags & MACHINE_HDC) { - p = (char *)malloc((strlen("internal")+1)*sizeof(char)); - strcpy(p, "internal"); - } else { - p = (char *)malloc((strlen("none")+1)*sizeof(char)); - strcpy(p, "none"); - } - free_p = 1; + p = config_get_string(cat, "fdc", NULL); + if (p != NULL) + fdc_type = fdc_card_get_from_internal_name(p); + else + fdc_type = FDC_INTERNAL; + config_delete_var(cat, "fdc"); + + p = config_get_string(cat, "hdc", NULL); + if (p == NULL) { + if (machine_has_flags(machine, MACHINE_HDC)) { + p = (char *) malloc((strlen("internal") + 1) * sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *) malloc((strlen("none") + 1) * sizeof(char)); + strcpy(p, "none"); + } + free_p = 1; + } + if (!strcmp(p, "mfm_xt")) + hdc_current = hdc_get_from_internal_name("st506_xt"); + else if (!strcmp(p, "mfm_xt_dtc5150x")) + hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x"); + else if (!strcmp(p, "mfm_at")) + hdc_current = hdc_get_from_internal_name("st506_at"); + else if (!strcmp(p, "vlb_isa")) + hdc_current = hdc_get_from_internal_name("ide_vlb"); + else if (!strcmp(p, "vlb_isa_2ch")) + hdc_current = hdc_get_from_internal_name("ide_vlb_2ch"); + else + hdc_current = hdc_get_from_internal_name(p); + config_delete_var(cat, "hdc"); + + if (free_p) { + free(p); + p = NULL; + } + + ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); + config_delete_var(cat, "ide_ter"); + ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); + config_delete_var(cat, "ide_qua"); } - if (!strcmp(p, "mfm_xt")) - hdc_current = hdc_get_from_internal_name("st506_xt"); - else if (!strcmp(p, "mfm_xt_dtc5150x")) - hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x"); - else if (!strcmp(p, "mfm_at")) - hdc_current = hdc_get_from_internal_name("st506_at"); - else - hdc_current = hdc_get_from_internal_name(p); + backwards_compat2 = 0; - if (free_p) { - free(p); - p = NULL; - } - - ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); - ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); - - bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); + bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); postcard_enabled = !!config_get_int(cat, "postcard_enabled", 0); for (c = 0; c < ISAMEM_MAX; c++) { - sprintf(temp, "isamem%d_type", c); + sprintf(temp, "isamem%d_type", c); - p = config_get_string(cat, temp, "none"); - isamem_type[c] = isamem_get_from_internal_name(p); + p = config_get_string(cat, temp, "none"); + isamem_type[c] = isamem_get_from_internal_name(p); } - p = config_get_string(cat, "isartc_type", "none"); - isartc_type = isartc_get_from_internal_name(p); + p = config_get_string(cat, "isartc_type", "none"); + isartc_type = isartc_get_from_internal_name(p); } - -/* Load "Hard Disks" section. */ -static void -load_hard_disks(void) -{ - char *cat = "Hard disks"; - char temp[512], tmp2[512]; - char s[512]; - int c; - char *p; - wchar_t *wp; - uint32_t max_spt, max_hpc, max_tracks; - uint32_t board = 0, dev = 0; - - memset(temp, '\0', sizeof(temp)); - for (c=0; c max_spt) - hdd[c].spt = max_spt; - if (hdd[c].hpc > max_hpc) - hdd[c].hpc = max_hpc; - if (hdd[c].tracks > max_tracks) - hdd[c].tracks = max_tracks; - - /* MFM/RLL */ - sprintf(temp, "hdd_%02i_mfm_channel", c+1); - if (hdd[c].bus == HDD_BUS_MFM) - hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); - else - config_delete_var(cat, temp); - - /* XTA */ - sprintf(temp, "hdd_%02i_xta_channel", c+1); - if (hdd[c].bus == HDD_BUS_XTA) - hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); - else - config_delete_var(cat, temp); - - /* ESDI */ - sprintf(temp, "hdd_%02i_esdi_channel", c+1); - if (hdd[c].bus == HDD_BUS_ESDI) - hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); - else - config_delete_var(cat, temp); - - /* IDE */ - sprintf(temp, "hdd_%02i_ide_channel", c+1); - if (hdd[c].bus == HDD_BUS_IDE) { - sprintf(tmp2, "%01u:%01u", c>>1, c&1); - p = config_get_string(cat, temp, tmp2); - sscanf(p, "%01u:%01u", &board, &dev); - board &= 3; - dev &= 1; - hdd[c].ide_channel = (board<<1) + dev; - - if (hdd[c].ide_channel > 7) - hdd[c].ide_channel = 7; - } else { - config_delete_var(cat, temp); - } - - /* SCSI */ - sprintf(temp, "hdd_%02i_scsi_id", c+1); - if (hdd[c].bus == HDD_BUS_SCSI) { - hdd[c].scsi_id = config_get_int(cat, temp, c); - - if (hdd[c].scsi_id > 15) - hdd[c].scsi_id = 15; - } else - config_delete_var(cat, temp); - - memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); - memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); - sprintf(temp, "hdd_%02i_fn", c+1); - wp = config_get_wstring(cat, temp, L""); - -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the CFG path. Just strip - * that off for now... - */ - wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); - } else -#endif - if (plat_path_abs(wp)) { - wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); - } else { - wcsncpy(hdd[c].fn, usr_path, sizeof_w(hdd[c].fn)); - wcsncat(hdd[c].fn, wp, sizeof_w(hdd[c].fn)-wcslen(usr_path)); - } - - /* If disk is empty or invalid, mark it for deletion. */ - if (! hdd_is_valid(c)) { - sprintf(temp, "hdd_%02i_parameters", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "hdd_%02i_preide_channels", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "hdd_%02i_ide_channels", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "hdd_%02i_scsi_id", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "hdd_%02i_fn", c+1); - config_delete_var(cat, temp); - } - - sprintf(temp, "hdd_%02i_mfm_channel", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "hdd_%02i_ide_channel", c+1); - config_delete_var(cat, temp); - } -} - - -/* Load "Floppy Drives" section. */ -static void -load_floppy_drives(void) -{ - char *cat = "Floppy drives"; - char temp[512], *p; - wchar_t *wp; - int c; - - for (c=0; c 13) - fdd_set_type(c, 13); - - sprintf(temp, "fdd_%02i_fn", c + 1); - wp = config_get_wstring(cat, temp, L""); - -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); - } else -#endif - wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); - - /* if (*wp != L'\0') - config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ - sprintf(temp, "fdd_%02i_writeprot", c+1); - ui_writeprot[c] = !!config_get_int(cat, temp, 0); - sprintf(temp, "fdd_%02i_turbo", c + 1); - fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); - sprintf(temp, "fdd_%02i_check_bpb", c+1); - fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); - - /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ - if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { - sprintf(temp, "fdd_%02i_type", c+1); - config_delete_var(cat, temp); - } - if (wcslen(floppyfns[c]) == 0) { - sprintf(temp, "fdd_%02i_fn", c+1); - config_delete_var(cat, temp); - } - if (ui_writeprot[c] == 0) { - sprintf(temp, "fdd_%02i_writeprot", c+1); - config_delete_var(cat, temp); - } - if (fdd_get_turbo(c) == 0) { - sprintf(temp, "fdd_%02i_turbo", c+1); - config_delete_var(cat, temp); - } - if (fdd_get_check_bpb(c) == 1) { - sprintf(temp, "fdd_%02i_check_bpb", c+1); - config_delete_var(cat, temp); - } - } -} - - -/* Load "Other Removable Devices" section. */ -static void -load_other_removable_devices(void) -{ - char *cat = "Other removable devices"; - char temp[512], tmp2[512], *p; - char s[512]; - unsigned int board = 0, dev = 0; - wchar_t *wp; - int c, d = 0; - - memset(temp, 0x00, sizeof(temp)); - for (c=0; c>1, (c+2)&1); - p = config_get_string(cat, temp, tmp2); - sscanf(p, "%01u:%01u", &board, &dev); - board &= 3; - dev &= 1; - cdrom[c].ide_channel = (board<<1)+dev; - - if (cdrom[c].ide_channel > 7) - cdrom[c].ide_channel = 7; - } else { - sprintf(temp, "cdrom_%02i_scsi_id", c+1); - if (cdrom[c].bus_type == CDROM_BUS_SCSI) { - cdrom[c].scsi_device_id = config_get_int(cat, temp, c+2); - - if (cdrom[c].scsi_device_id > 15) - cdrom[c].scsi_device_id = 15; - } else - config_delete_var(cat, temp); - } - - sprintf(temp, "cdrom_%02i_image_path", c+1); - wp = config_get_wstring(cat, temp, L""); - -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path)); - } else -#endif - wcsncpy(cdrom[c].image_path, wp, sizeof_w(cdrom[c].image_path)); - - if (cdrom[c].host_drive && (cdrom[c].host_drive != 200)) - cdrom[c].host_drive = 0; - - if ((cdrom[c].host_drive == 0x200) && - (wcslen(cdrom[c].image_path) == 0)) - cdrom[c].host_drive = 0; - - /* If the CD-ROM is disabled, delete all its variables. */ - if (cdrom[c].bus_type == CDROM_BUS_DISABLED) { - sprintf(temp, "cdrom_%02i_host_drive", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_parameters", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_ide_channel", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_scsi_id", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_image_path", c+1); - config_delete_var(cat, temp); - } - - sprintf(temp, "cdrom_%02i_iso_path", c+1); - config_delete_var(cat, temp); - } - - memset(temp, 0x00, sizeof(temp)); - for (c=0; c>1, (c+2)&1); - p = config_get_string(cat, temp, tmp2); - sscanf(p, "%01u:%01u", &board, &dev); - board &= 3; - dev &= 1; - zip_drives[c].ide_channel = (board<<1)+dev; - - if (zip_drives[c].ide_channel > 7) - zip_drives[c].ide_channel = 7; - } else { - sprintf(temp, "zip_%02i_scsi_id", c+1); - if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { - zip_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); - - if (zip_drives[c].scsi_device_id > 15) - zip_drives[c].scsi_device_id = 15; - } else - config_delete_var(cat, temp); - } - - sprintf(temp, "zip_%02i_image_path", c+1); - wp = config_get_wstring(cat, temp, L""); - -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); - } else -#endif - wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); - - /* If the CD-ROM is disabled, delete all its variables. */ - if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { - sprintf(temp, "zip_%02i_host_drive", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "zip_%02i_parameters", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "zip_%02i_ide_channel", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "zip_%02i_scsi_id", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "zip_%02i_image_path", c+1); - config_delete_var(cat, temp); - } - - sprintf(temp, "zip_%02i_iso_path", c+1); - config_delete_var(cat, temp); - } - - - memset(temp, 0x00, sizeof(temp)); - for (c=0; c>1, (c+2)&1); - p = config_get_string(cat, temp, tmp2); - sscanf(p, "%01u:%01u", &board, &dev); - board &= 3; - dev &= 1; - mo_drives[c].ide_channel = (board<<1)+dev; - - if (mo_drives[c].ide_channel > 7) - mo_drives[c].ide_channel = 7; - } else { - sprintf(temp, "mo_%02i_scsi_id", c+1); - if (mo_drives[c].bus_type == MO_BUS_SCSI) { - mo_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); - - if (mo_drives[c].scsi_device_id > 15) - mo_drives[c].scsi_device_id = 15; - } else - config_delete_var(cat, temp); - } - - sprintf(temp, "mo_%02i_image_path", c+1); - wp = config_get_wstring(cat, temp, L""); - - wcsncpy(mo_drives[c].image_path, wp, sizeof_w(mo_drives[c].image_path)); - - /* If the CD-ROM is disabled, delete all its variables. */ - if (mo_drives[c].bus_type == MO_BUS_DISABLED) { - sprintf(temp, "mo_%02i_host_drive", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "mo_%02i_parameters", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "mo_%02i_ide_channel", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "mo_%02i_scsi_id", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "mo_%02i_image_path", c+1); - config_delete_var(cat, temp); - } - - sprintf(temp, "mo_%02i_iso_path", c+1); - config_delete_var(cat, temp); - } -} - - /* Load the specified or a default configuration file. */ void config_load(void) { int i; - config_log("Loading config file '%ls'..\n", cfg_path); + config_log("Loading config file '%s'..\n", cfg_path); memset(hdd, 0, sizeof(hard_disk_t)); memset(cdrom, 0, sizeof(cdrom_t) * CDROM_NUM); @@ -1337,211 +2142,361 @@ config_load(void) #endif memset(zip_drives, 0, sizeof(zip_drive_t)); - if (! config_read(cfg_path)) { - cpu = 0; -#ifdef USE_LANGUAGE - plat_langid = 0x0409; -#endif - scale = 1; - machine = machine_get_machine_from_internal_name("ibmpc"); - fpu_type = fpu_get_type(machine, cpu_manufacturer, cpu, "none"); - gfxcard = video_get_video_from_internal_name("cga"); - vid_api = plat_vidapi("default"); - time_sync = TIME_SYNC_ENABLED; - joystick_type = JOYSTICK_TYPE_NONE; - hdc_current = hdc_get_from_internal_name("none"); - serial_enabled[0] = 1; - serial_enabled[1] = 1; - lpt_ports[0].enabled = 1; - lpt_ports[1].enabled = 0; - lpt_ports[2].enabled = 0; - for (i = 0; i < FDD_NUM; i++) { - if (i < 2) - fdd_set_type(i, 2); - else - fdd_set_type(i, 0); + if (!config_read(cfg_path)) { + config_changed = 1; - fdd_set_turbo(i, 0); - fdd_set_check_bpb(i, 1); - } - mem_size = 640; - isartc_type = 0; - for (i = 0; i < ISAMEM_MAX; i++) - isamem_type[i] = 0; + cpu_f = (cpu_family_t *) &cpu_families[0]; + cpu = 0; - config_log("Config file not present or invalid!\n"); - return; + kbd_req_capture = 0; + hide_status_bar = 0; + hide_tool_bar = 0; + scale = 1; + machine = machine_get_machine_from_internal_name("ibmpc"); + dpi_scale = 1; + + fpu_type = fpu_get_type(cpu_f, cpu, "none"); + gfxcard = video_get_video_from_internal_name("cga"); + vid_api = plat_vidapi("default"); + vid_resize = 0; + video_fullscreen_first = 1; + time_sync = TIME_SYNC_ENABLED; + hdc_current = hdc_get_from_internal_name("none"); + + serial_enabled[0] = 1; + serial_enabled[1] = 1; + for (i = 2; i < SERIAL_MAX; i++) + serial_enabled[i] = 0; + + lpt_ports[0].enabled = 1; + + for (i = 1; i < PARALLEL_MAX; i++) + lpt_ports[i].enabled = 0; + + for (i = 0; i < FDD_NUM; i++) { + if (i < 2) + fdd_set_type(i, 2); + else + fdd_set_type(i, 0); + + fdd_set_turbo(i, 0); + fdd_set_check_bpb(i, 1); + } + + /* Unmute the CD audio on the first CD-ROM drive. */ + cdrom[0].sound_on = 1; + mem_size = 64; + isartc_type = 0; + for (i = 0; i < ISAMEM_MAX; i++) + isamem_type[i] = 0; + + /* TODO: Re-enable by default when we have a proper machine flag for this. */ + cassette_enable = 0; + memset(cassette_fname, 0x00, sizeof(cassette_fname)); + memcpy(cassette_mode, "load", strlen("load") + 1); + cassette_pos = 0; + cassette_srate = 44100; + cassette_append = 0; + cassette_pcm = 0; + cassette_ui_writeprot = 0; + + config_log("Config file not present or invalid!\n"); + } else { + load_general(); /* General */ + for (i = 0; i < MONITORS_NUM; i++) + load_monitor(i); + load_machine(); /* Machine */ + load_video(); /* Video */ + load_input_devices(); /* Input devices */ + load_sound(); /* Sound */ + load_network(); /* Network */ + load_ports(); /* Ports (COM & LPT) */ + load_storage_controllers(); /* Storage controllers */ + load_hard_disks(); /* Hard disks */ + load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ + /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ + load_floppy_drives(); /* Floppy drives */ + load_other_removable_devices(); /* Other removable devices */ + load_other_peripherals(); /* Other peripherals */ + + /* Mark the configuration as changed. */ + config_changed = 1; + + config_log("Config loaded.\n\n"); } - load_general(); /* General */ - load_machine(); /* Machine */ - load_video(); /* Video */ - load_input_devices(); /* Input devices */ - load_sound(); /* Sound */ - load_network(); /* Network */ - load_ports(); /* Ports (COM & LPT) */ - load_other_peripherals(); /* Other peripherals */ - load_hard_disks(); /* Hard disks */ - load_floppy_drives(); /* Floppy drives */ - load_other_removable_devices(); /* Other removable devices */ - - /* Mark the configuration as changed. */ - config_changed = 1; - - config_log("Config loaded.\n\n"); + video_copy = (video_grayscale || invert_display) ? video_transform_copy : memcpy; } - /* Save "General" section. */ static void save_general(void) { char *cat = "General"; - char temp[512]; + char temp[512], buffer[512] = { 0 }; char *va_name; config_set_int(cat, "vid_resize", vid_resize); if (vid_resize == 0) - config_delete_var(cat, "vid_resize"); + config_delete_var(cat, "vid_resize"); va_name = plat_vidapi_name(vid_api); - if (!strcmp(va_name, "default")) { - config_delete_var(cat, "vid_renderer"); - } else { - config_set_string(cat, "vid_renderer", va_name); - } + if (!strcmp(va_name, "default")) + config_delete_var(cat, "vid_renderer"); + else + config_set_string(cat, "vid_renderer", va_name); if (video_fullscreen_scale == 0) - config_delete_var(cat, "video_fullscreen_scale"); - else - config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); + config_delete_var(cat, "video_fullscreen_scale"); + else + config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); - if (video_fullscreen_first == 0) - config_delete_var(cat, "video_fullscreen_first"); - else - config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + if (video_fullscreen_first == 1) + config_delete_var(cat, "video_fullscreen_first"); + else + config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + + if (video_filter_method == 1) + config_delete_var(cat, "video_filter_method"); + else + config_set_int(cat, "video_filter_method", video_filter_method); if (force_43 == 0) - config_delete_var(cat, "force_43"); - else - config_set_int(cat, "force_43", force_43); + config_delete_var(cat, "force_43"); + else + config_set_int(cat, "force_43", force_43); if (scale == 1) - config_delete_var(cat, "scale"); - else - config_set_int(cat, "scale", scale); + config_delete_var(cat, "scale"); + else + config_set_int(cat, "scale", scale); + + if (dpi_scale == 1) + config_delete_var(cat, "dpi_scale"); + else + config_set_int(cat, "dpi_scale", dpi_scale); if (enable_overscan == 0) - config_delete_var(cat, "enable_overscan"); - else - config_set_int(cat, "enable_overscan", enable_overscan); + config_delete_var(cat, "enable_overscan"); + else + config_set_int(cat, "enable_overscan", enable_overscan); if (vid_cga_contrast == 0) - config_delete_var(cat, "vid_cga_contrast"); - else - config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); + config_delete_var(cat, "vid_cga_contrast"); + else + config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); if (video_grayscale == 0) - config_delete_var(cat, "video_grayscale"); - else - config_set_int(cat, "video_grayscale", video_grayscale); + config_delete_var(cat, "video_grayscale"); + else + config_set_int(cat, "video_grayscale", video_grayscale); if (video_graytype == 0) - config_delete_var(cat, "video_graytype"); - else - config_set_int(cat, "video_graytype", video_graytype); + config_delete_var(cat, "video_graytype"); + else + config_set_int(cat, "video_graytype", video_graytype); if (rctrl_is_lalt == 0) - config_delete_var(cat, "rctrl_is_lalt"); - else - config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); + config_delete_var(cat, "rctrl_is_lalt"); + else + config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); if (update_icons == 1) - config_delete_var(cat, "update_icons"); - else - config_set_int(cat, "update_icons", update_icons); + config_delete_var(cat, "update_icons"); + else + config_set_int(cat, "update_icons", update_icons); - if (window_remember) { - config_set_int(cat, "window_remember", window_remember); + if (window_remember || (vid_resize & 2)) { + if (window_remember) + config_set_int(cat, "window_remember", window_remember); + else + config_delete_var(cat, "window_remember"); + } else + config_delete_var(cat, "window_remember"); - sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); - config_set_string(cat, "window_coordinates", temp); - } else { - config_delete_var(cat, "window_remember"); - config_delete_var(cat, "window_coordinates"); - } + if (vid_resize & 2) { + sprintf(temp, "%ix%i", fixed_size_x, fixed_size_y); + config_set_string(cat, "window_fixed_res", temp); + } else + config_delete_var(cat, "window_fixed_res"); if (sound_gain != 0) - config_set_int(cat, "sound_gain", sound_gain); + config_set_int(cat, "sound_gain", sound_gain); else - config_delete_var(cat, "sound_gain"); + config_delete_var(cat, "sound_gain"); -#ifdef USE_LANGUAGE - if (plat_langid == 0x0409) - config_delete_var(cat, "language"); - else - config_set_hex16(cat, "language", plat_langid); -#endif + if (kbd_req_capture != 0) + config_set_int(cat, "kbd_req_capture", kbd_req_capture); + else + config_delete_var(cat, "kbd_req_capture"); + + if (hide_status_bar != 0) + config_set_int(cat, "hide_status_bar", hide_status_bar); + else + config_delete_var(cat, "hide_status_bar"); + + if (hide_tool_bar != 0) + config_set_int(cat, "hide_tool_bar", hide_tool_bar); + else + config_delete_var(cat, "hide_tool_bar"); + + if (confirm_reset != 1) + config_set_int(cat, "confirm_reset", confirm_reset); + else + config_delete_var(cat, "confirm_reset"); + + if (confirm_exit != 1) + config_set_int(cat, "confirm_exit", confirm_exit); + else + config_delete_var(cat, "confirm_exit"); + + if (confirm_save != 1) + config_set_int(cat, "confirm_save", confirm_save); + else + config_delete_var(cat, "confirm_save"); + + if (mouse_sensitivity != 1.0) + config_set_double(cat, "mouse_sensitivity", mouse_sensitivity); + else + config_delete_var(cat, "mouse_sensitivity"); + + if (lang_id == DEFAULT_LANGUAGE) + config_delete_var(cat, "language"); + else { + plat_language_code_r(lang_id, buffer, 511); + config_set_string(cat, "language", buffer); + } + + if (!strcmp(icon_set, "")) + config_delete_var(cat, "iconset"); + else + config_set_string(cat, "iconset", icon_set); -#if USE_DISCORD if (enable_discord) - config_set_int(cat, "enable_discord", enable_discord); + config_set_int(cat, "enable_discord", enable_discord); else - config_delete_var(cat, "enable_discord"); -#endif + config_delete_var(cat, "enable_discord"); + + if (video_framerate != -1) + config_set_int(cat, "video_gl_framerate", video_framerate); + else + config_delete_var(cat, "video_gl_framerate"); + if (video_vsync != 0) + config_set_int(cat, "video_gl_vsync", video_vsync); + else + config_delete_var(cat, "video_gl_vsync"); + if (strlen(video_shader) > 0) + config_set_string(cat, "video_gl_shader", video_shader); + else + config_delete_var(cat, "video_gl_shader"); delete_section_if_empty(cat); } - /* Save "Machine" section. */ static void save_machine(void) { char *cat = "Machine"; + char *p; + int c, i = 0, legacy_mfg, legacy_cpu = -1, closest_legacy_cpu = -1; - config_set_string(cat, "machine", machine_get_internal_name()); + p = machine_get_internal_name(); + config_set_string(cat, "machine", p); - if (cpu_manufacturer == 0) - config_delete_var(cat, "cpu_manufacturer"); - else - config_set_int(cat, "cpu_manufacturer", cpu_manufacturer); + config_set_string(cat, "cpu_family", (char *) cpu_f->internal_name); + config_set_int(cat, "cpu_speed", cpu_f->cpus[cpu].rspeed); + config_set_double(cat, "cpu_multi", cpu_f->cpus[cpu].multi); + if (cpu_override) + config_set_int(cat, "cpu_override", cpu_override); + else + config_delete_var(cat, "cpu_override"); - if (cpu == 0) - config_delete_var(cat, "cpu"); - else - config_set_int(cat, "cpu", cpu); + /* Forwards compatibility with the previous CPU model system. */ + config_delete_var(cat, "cpu_manufacturer"); + config_delete_var(cat, "cpu"); + + /* Look for a machine entry on the legacy table. */ + c = 0; + while (cpu_legacy_table[c].machine) { + if (!strcmp(p, cpu_legacy_table[c].machine)) + break; + c++; + } + if (cpu_legacy_table[c].machine) { + /* Look for a corresponding CPU entry. */ + cpu_legacy_table_t *legacy_table_entry; + for (legacy_mfg = 0; legacy_mfg < 4; legacy_mfg++) { + if (!cpu_legacy_table[c].tables[legacy_mfg]) + continue; + + i = 0; + while (cpu_legacy_table[c].tables[legacy_mfg][i].family) { + legacy_table_entry = (cpu_legacy_table_t *) &cpu_legacy_table[c].tables[legacy_mfg][i]; + + /* Match the family name, speed and multiplier. */ + if (!strcmp(cpu_f->internal_name, legacy_table_entry->family)) { + if ((legacy_table_entry->rspeed == cpu_f->cpus[cpu].rspeed) && (legacy_table_entry->multi == cpu_f->cpus[cpu].multi)) { /* exact speed/multiplier match */ + legacy_cpu = i; + break; + } else if ((legacy_table_entry->rspeed >= cpu_f->cpus[cpu].rspeed) && (closest_legacy_cpu == -1)) { /* closest speed match */ + closest_legacy_cpu = i; + } + } + + i++; + } + + /* Use the closest speed match if no exact match was found. */ + if ((legacy_cpu == -1) && (closest_legacy_cpu > -1)) { + legacy_cpu = closest_legacy_cpu; + break; + } else if (legacy_cpu > -1) /* exact match found */ + break; + } + + /* Set legacy values if a match was found. */ + if (legacy_cpu > -1) { + if (legacy_mfg) + config_set_int(cat, "cpu_manufacturer", legacy_mfg); + if (legacy_cpu) + config_set_int(cat, "cpu", legacy_cpu); + } + } if (cpu_waitstates == 0) - config_delete_var(cat, "cpu_waitstates"); - else - config_set_int(cat, "cpu_waitstates", cpu_waitstates); + config_delete_var(cat, "cpu_waitstates"); + else + config_set_int(cat, "cpu_waitstates", cpu_waitstates); if (fpu_type == 0) - config_delete_var(cat, "fpu_type"); - else - config_set_string(cat, "fpu_type", fpu_get_internal_name(machine, cpu_manufacturer, cpu, fpu_type)); + config_delete_var(cat, "fpu_type"); + else + config_set_string(cat, "fpu_type", (char *) fpu_get_internal_name(cpu_f, cpu, fpu_type)); - if (mem_size == 4096) - config_delete_var(cat, "mem_size"); - else - config_set_int(cat, "mem_size", mem_size); + // Write the mem_size explicitly to the setttings in order to help managers to display it without having the actual machine table + config_delete_var(cat, "mem_size"); + config_set_int(cat, "mem_size", mem_size); config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); if (time_sync & TIME_SYNC_ENABLED) - if (time_sync & TIME_SYNC_UTC) - config_set_string(cat, "time_sync", "utc"); - else - config_set_string(cat, "time_sync", "local"); + if (time_sync & TIME_SYNC_UTC) + config_set_string(cat, "time_sync", "utc"); + else + config_set_string(cat, "time_sync", "local"); else - config_set_string(cat, "time_sync", "disabled"); + config_set_string(cat, "time_sync", "disabled"); + + if (pit_mode == -1) + config_delete_var(cat, "pit_mode"); + else + config_set_int(cat, "pit_mode", pit_mode); delete_section_if_empty(cat); } - /* Save "Video" section. */ static void save_video(void) @@ -1549,76 +2504,94 @@ save_video(void) char *cat = "Video"; config_set_string(cat, "gfxcard", - video_get_internal_name(gfxcard)); + video_get_internal_name(gfxcard)); if (voodoo_enabled == 0) - config_delete_var(cat, "voodoo"); - else - config_set_int(cat, "voodoo", voodoo_enabled); + config_delete_var(cat, "voodoo"); + else + config_set_int(cat, "voodoo", voodoo_enabled); + + if (ibm8514_enabled == 0) + config_delete_var(cat, "8514a"); + else + config_set_int(cat, "8514a", ibm8514_enabled); + + if (xga_enabled == 0) + config_delete_var(cat, "xga"); + else + config_set_int(cat, "xga", xga_enabled); + + if (gfxcard_2 == 0) + config_delete_var(cat, "gfxcard_2"); + else + config_set_string(cat, "gfxcard_2", video_get_internal_name(gfxcard_2)); + + if (show_second_monitors == 1) + config_delete_var(cat, "show_second_monitors"); + else + config_set_int(cat, "show_second_monitors", show_second_monitors); delete_section_if_empty(cat); } - /* Save "Input Devices" section. */ static void save_input_devices(void) { char *cat = "Input devices"; - char temp[512], tmp2[512]; - int c, d; + char temp[512], tmp2[512]; + int c, d; config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); - if (joystick_type == JOYSTICK_TYPE_NONE) { - config_delete_var(cat, "joystick_type"); + if (!joystick_type) { + config_delete_var(cat, "joystick_type"); - for (c = 0; c < 16; c++) { - sprintf(tmp2, "joystick_%i_nr", c); - config_delete_var(cat, tmp2); + for (c = 0; c < 16; c++) { + sprintf(tmp2, "joystick_%i_nr", c); + config_delete_var(cat, tmp2); - for (d=0; d<16; d++) { - sprintf(tmp2, "joystick_%i_axis_%i", c, d); - config_delete_var(cat, tmp2); - } - for (d=0; d<16; d++) { - sprintf(tmp2, "joystick_%i_button_%i", c, d); - config_delete_var(cat, tmp2); - } - for (d=0; d<16; d++) { - sprintf(tmp2, "joystick_%i_pov_%i", c, d); - config_delete_var(cat, tmp2); - } - } + for (d = 0; d < 16; d++) { + sprintf(tmp2, "joystick_%i_axis_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d = 0; d < 16; d++) { + sprintf(tmp2, "joystick_%i_button_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d = 0; d < 16; d++) { + sprintf(tmp2, "joystick_%i_pov_%i", c, d); + config_delete_var(cat, tmp2); + } + } } else { - config_set_int(cat, "joystick_type", joystick_type); + config_set_string(cat, "joystick_type", joystick_get_internal_name(joystick_type)); - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { - sprintf(tmp2, "joystick_%i_nr", c); - config_set_int(cat, tmp2, joystick_state[c].plat_joystick_nr); + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { + sprintf(tmp2, "joystick_%i_nr", c); + config_set_int(cat, tmp2, joystick_state[c].plat_joystick_nr); - if (joystick_state[c].plat_joystick_nr) { - for (d=0; d= 2) && !serial_enabled[c])) + config_delete_var(cat, temp); + else + config_set_int(cat, temp, serial_enabled[c]); + + /* + sprintf(temp, "serial%d_type", c + 1); + if (!serial_enabled[c]) + config_delete_var(cat, temp); + // else + // config_set_string(cat, temp, (char *) serial_type[c]) + + sprintf(temp, "serial%d_device", c + 1); + if (com_ports[c].device == 0) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, + (char *) com_device_get_internal_name(com_ports[c].device)); + */ } - for (c = 0; c < 3; c++) { - sprintf(temp, "lpt%d_enabled", c + 1); - d = (c == 0) ? 1 : 0; - if (lpt_ports[c].enabled == d) - config_delete_var(cat, temp); - else - config_set_int(cat, temp, lpt_ports[c].enabled); + for (c = 0; c < PARALLEL_MAX; c++) { + sprintf(temp, "lpt%d_enabled", c + 1); + d = (c == 0) ? 1 : 0; + if (lpt_ports[c].enabled == d) + config_delete_var(cat, temp); + else + config_set_int(cat, temp, lpt_ports[c].enabled); - sprintf(temp, "lpt%d_device", c + 1); - if (lpt_ports[c].device == 0) - config_delete_var(cat, temp); - else - config_set_string(cat, temp, - (char *) lpt_device_get_internal_name(lpt_ports[c].device)); + sprintf(temp, "lpt%d_device", c + 1); + if (lpt_ports[c].device == 0) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, + (char *) lpt_device_get_internal_name(lpt_ports[c].device)); } delete_section_if_empty(cat); } +/* Save "Storage Controllers" section. */ +static void +save_storage_controllers(void) +{ + char *cat = "Storage controllers"; + char temp[512]; + int c; + + config_delete_var(cat, "scsicard"); + + for (c = 0; c < SCSI_BUS_MAX; c++) { + sprintf(temp, "scsicard_%d", c + 1); + + if (scsi_card_current[c] == 0) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, + scsi_card_get_internal_name(scsi_card_current[c])); + } + + if (fdc_type == FDC_INTERNAL) + config_delete_var(cat, "fdc"); + else + config_set_string(cat, "fdc", + fdc_card_get_internal_name(fdc_type)); + + config_set_string(cat, "hdc", + hdc_get_internal_name(hdc_current)); + + if (ide_ter_enabled == 0) + config_delete_var(cat, "ide_ter"); + else + config_set_int(cat, "ide_ter", ide_ter_enabled); + + if (ide_qua_enabled == 0) + config_delete_var(cat, "ide_qua"); + else + config_set_int(cat, "ide_qua", ide_qua_enabled); + + delete_section_if_empty(cat); + + if (cassette_enable == 1) + config_delete_var(cat, "cassette_enabled"); + else + config_set_int(cat, "cassette_enabled", cassette_enable); + + if (strlen(cassette_fname) == 0) + config_delete_var(cat, "cassette_file"); + else + config_set_string(cat, "cassette_file", cassette_fname); + + if (strlen(cassette_mode) == 0) + config_delete_var(cat, "cassette_mode"); + else + config_set_string(cat, "cassette_mode", cassette_mode); + + if (cassette_pos == 0) + config_delete_var(cat, "cassette_position"); + else + config_set_int(cat, "cassette_position", cassette_pos); + + if (cassette_srate == 44100) + config_delete_var(cat, "cassette_srate"); + else + config_set_int(cat, "cassette_srate", cassette_srate); + + if (cassette_append == 0) + config_delete_var(cat, "cassette_append"); + else + config_set_int(cat, "cassette_append", cassette_append); + + if (cassette_pcm == 0) + config_delete_var(cat, "cassette_pcm"); + else + config_set_int(cat, "cassette_pcm", cassette_pcm); + + if (cassette_ui_writeprot == 0) + config_delete_var(cat, "cassette_writeprot"); + else + config_set_int(cat, "cassette_writeprot", cassette_ui_writeprot); + + for (c = 0; c < 2; c++) { + sprintf(temp, "cartridge_%02i_fn", c + 1); + if (strlen(cart_fns[c]) == 0) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, cart_fns[c]); + } +} /* Save "Other Peripherals" section. */ static void save_other_peripherals(void) { char *cat = "Other peripherals"; - char temp[512]; - int c; - - if (scsi_card_current == 0) - config_delete_var(cat, "scsicard"); - else - config_set_string(cat, "scsicard", - scsi_card_get_internal_name(scsi_card_current)); - - if (fdc_type == FDC_INTERNAL) - config_delete_var(cat, "fdc"); - else - config_set_string(cat, "fdc", - fdc_card_get_internal_name(fdc_type)); - - config_set_string(cat, "hdc", - hdc_get_internal_name(hdc_current)); - - if (ide_ter_enabled == 0) - config_delete_var(cat, "ide_ter"); - else - config_set_int(cat, "ide_ter", ide_ter_enabled); - - if (ide_qua_enabled == 0) - config_delete_var(cat, "ide_qua"); - else - config_set_int(cat, "ide_qua", ide_qua_enabled); + char temp[512]; + int c; if (bugger_enabled == 0) - config_delete_var(cat, "bugger_enabled"); - else - config_set_int(cat, "bugger_enabled", bugger_enabled); + config_delete_var(cat, "bugger_enabled"); + else + config_set_int(cat, "bugger_enabled", bugger_enabled); if (postcard_enabled == 0) - config_delete_var(cat, "postcard_enabled"); - else - config_set_int(cat, "postcard_enabled", postcard_enabled); + config_delete_var(cat, "postcard_enabled"); + else + config_set_int(cat, "postcard_enabled", postcard_enabled); for (c = 0; c < ISAMEM_MAX; c++) { - sprintf(temp, "isamem%d_type", c); - if (isamem_type[c] == 0) - config_delete_var(cat, temp); - else - config_set_string(cat, temp, - (char *) isamem_get_internal_name(isamem_type[c])); + sprintf(temp, "isamem%d_type", c); + if (isamem_type[c] == 0) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, + (char *) isamem_get_internal_name(isamem_type[c])); } if (isartc_type == 0) - config_delete_var(cat, "isartc_type"); - else - config_set_string(cat, "isartc_type", - isartc_get_internal_name(isartc_type)); - + config_delete_var(cat, "isartc_type"); + else + config_set_string(cat, "isartc_type", + isartc_get_internal_name(isartc_type)); + delete_section_if_empty(cat); } - /* Save "Hard Disks" section. */ static void save_hard_disks(void) { char *cat = "Hard disks"; - char temp[32], tmp2[512]; + char temp[32], tmp2[512]; char *p; - int c; + int c; memset(temp, 0x00, sizeof(temp)); - for (c=0; c> 1, hdd[c].ide_channel & 1); - config_set_string(cat, temp, tmp2); - } + sprintf(temp, "hdd_%02i_ide_channel", c + 1); + if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE)) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%01u:%01u", hdd[c].ide_channel >> 1, hdd[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } - sprintf(temp, "hdd_%02i_scsi_id", c+1); - if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_SCSI)) - config_set_int(cat, temp, hdd[c].scsi_id); - else - config_delete_var(cat, temp); + sprintf(temp, "hdd_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); - sprintf(temp, "hdd_%02i_fn", c+1); - if (hdd_is_valid(c) && (wcslen(hdd[c].fn) != 0)) - if (!wcsnicmp(hdd[c].fn, usr_path, wcslen(usr_path))) - config_set_wstring(cat, temp, &hdd[c].fn[wcslen(usr_path)]); - else - config_set_wstring(cat, temp, hdd[c].fn); - else - config_delete_var(cat, temp); + sprintf(temp, "hdd_%02i_scsi_location", c + 1); + if (hdd[c].bus != HDD_BUS_SCSI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%02u", hdd[c].scsi_id >> 4, + hdd[c].scsi_id & 15); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_fn", c + 1); + if (hdd_is_valid(c) && (strlen(hdd[c].fn) != 0)) { + path_normalize(hdd[c].fn); + if (!strnicmp(hdd[c].fn, usr_path, strlen(usr_path))) + config_set_string(cat, temp, &hdd[c].fn[strlen(usr_path)]); + else + config_set_string(cat, temp, hdd[c].fn); + } else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_speed", c + 1); + if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE)) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, hdd_preset_get_internal_name(hdd[c].speed_preset)); } delete_section_if_empty(cat); } - /* Save "Floppy Drives" section. */ static void -save_floppy_drives(void) +save_floppy_and_cdrom_drives(void) { - char *cat = "Floppy drives"; - char temp[512]; - int c; + char *cat = "Floppy and CD-ROM drives"; + char temp[512], tmp2[512]; + int c; - for (c=0; c> 1, + cdrom[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_location", c + 1); + if (cdrom[c].bus_type != CDROM_BUS_SCSI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%02u", cdrom[c].scsi_device_id >> 4, + cdrom[c].scsi_device_id & 15); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + if ((cdrom[c].bus_type == 0) || (strlen(cdrom[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_string(cat, temp, cdrom[c].image_path); + } } delete_section_if_empty(cat); } - /* Save "Other Removable Devices" section. */ static void save_other_removable_devices(void) { char *cat = "Other removable devices"; - char temp[512], tmp2[512]; - int c; + char temp[512], tmp2[512]; + int c; - for (c=0; c> 1, + zip_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } - sprintf(temp, "cdrom_%02i_parameters", c+1); - if (cdrom[c].bus_type == 0) { - config_delete_var(cat, temp); - } else { - sprintf(tmp2, "%u, %s", cdrom[c].sound_on, - hdd_bus_to_string(cdrom[c].bus_type, 1)); - config_set_string(cat, temp, tmp2); - } + sprintf(temp, "zip_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); - sprintf(temp, "cdrom_%02i_ide_channel", c+1); - if (cdrom[c].bus_type != CDROM_BUS_ATAPI) - config_delete_var(cat, temp); - else { - sprintf(tmp2, "%01u:%01u", cdrom[c].ide_channel>>1, - cdrom[c].ide_channel & 1); - config_set_string(cat, temp, tmp2); - } + sprintf(temp, "zip_%02i_scsi_location", c + 1); + if (zip_drives[c].bus_type != ZIP_BUS_SCSI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%02u", zip_drives[c].scsi_device_id >> 4, + zip_drives[c].scsi_device_id & 15); + config_set_string(cat, temp, tmp2); + } - sprintf(temp, "cdrom_%02i_scsi_id", c + 1); - if (cdrom[c].bus_type != CDROM_BUS_SCSI) { - config_delete_var(cat, temp); - } else { - config_set_int(cat, temp, cdrom[c].scsi_device_id); - } - - sprintf(temp, "cdrom_%02i_image_path", c + 1); - if ((cdrom[c].bus_type == 0) || - (wcslen(cdrom[c].image_path) == 0)) { - config_delete_var(cat, temp); - } else { - config_set_wstring(cat, temp, cdrom[c].image_path); - } + sprintf(temp, "zip_%02i_image_path", c + 1); + if ((zip_drives[c].bus_type == 0) || (strlen(zip_drives[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_string(cat, temp, zip_drives[c].image_path); + } } - for (c=0; c>1, - zip_drives[c].ide_channel & 1); - config_set_string(cat, temp, tmp2); - } + for (c = 0; c < MO_NUM; c++) { + sprintf(temp, "mo_%02i_parameters", c + 1); + if (mo_drives[c].bus_type == 0) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%u, %s", mo_drives[c].type, + hdd_bus_to_string(mo_drives[c].bus_type, 1)); + config_set_string(cat, temp, tmp2); + } - sprintf(temp, "zip_%02i_scsi_id", c + 1); - if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { - config_delete_var(cat, temp); - } else { - config_set_int(cat, temp, zip_drives[c].scsi_device_id); - } + sprintf(temp, "mo_%02i_ide_channel", c + 1); + if (mo_drives[c].bus_type != MO_BUS_ATAPI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%01u", mo_drives[c].ide_channel >> 1, + mo_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } - sprintf(temp, "zip_%02i_image_path", c + 1); - if ((zip_drives[c].bus_type == 0) || - (wcslen(zip_drives[c].image_path) == 0)) { - config_delete_var(cat, temp); - } else { - config_set_wstring(cat, temp, zip_drives[c].image_path); - } - } + sprintf(temp, "mo_%02i_scsi_id", c + 1); + config_delete_var(cat, temp); - for (c=0; c>1, - mo_drives[c].ide_channel & 1); - config_set_string(cat, temp, tmp2); - } + sprintf(temp, "mo_%02i_scsi_location", c + 1); + if (mo_drives[c].bus_type != MO_BUS_SCSI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%02u", mo_drives[c].scsi_device_id >> 4, + mo_drives[c].scsi_device_id & 15); + config_set_string(cat, temp, tmp2); + } - sprintf(temp, "mo_%02i_scsi_id", c + 1); - if (mo_drives[c].bus_type != MO_BUS_SCSI) { - config_delete_var(cat, temp); - } else { - config_set_int(cat, temp, mo_drives[c].scsi_device_id); - } - - sprintf(temp, "mo_%02i_image_path", c + 1); - if ((mo_drives[c].bus_type == 0) || - (wcslen(mo_drives[c].image_path) == 0)) { - config_delete_var(cat, temp); - } else { - config_set_wstring(cat, temp, mo_drives[c].image_path); - } + sprintf(temp, "mo_%02i_image_path", c + 1); + if ((mo_drives[c].bus_type == 0) || (strlen(mo_drives[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_string(cat, temp, mo_drives[c].image_path); + } } delete_section_if_empty(cat); } - void config_save(void) { - save_general(); /* General */ - save_machine(); /* Machine */ - save_video(); /* Video */ - save_input_devices(); /* Input devices */ - save_sound(); /* Sound */ - save_network(); /* Network */ - save_ports(); /* Ports (COM & LPT) */ - save_other_peripherals(); /* Other peripherals */ - save_hard_disks(); /* Hard disks */ - save_floppy_drives(); /* Floppy drives */ - save_other_removable_devices(); /* Other removable devices */ + int i; + + save_general(); /* General */ + for (i = 0; i < MONITORS_NUM; i++) + save_monitor(i); + save_machine(); /* Machine */ + save_video(); /* Video */ + save_input_devices(); /* Input devices */ + save_sound(); /* Sound */ + save_network(); /* Network */ + save_ports(); /* Ports (COM & LPT) */ + save_storage_controllers(); /* Storage controllers */ + save_hard_disks(); /* Hard disks */ + save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ + save_other_removable_devices(); /* Other removable devices */ + save_other_peripherals(); /* Other peripherals */ config_write(cfg_path); } - void config_dump(void) { section_t *sec; - - sec = (section_t *)config_head.next; + + sec = (section_t *) config_head.next; while (sec != NULL) { - entry_t *ent; + entry_t *ent; - if (sec->name[0]) - config_log("[%s]\n", sec->name); - - ent = (entry_t *)sec->entry_head.next; - while (ent != NULL) { - config_log("%s = %ls\n", ent->name, ent->wdata); + if (sec->name[0]) + config_log("[%s]\n", sec->name); - ent = (entry_t *)ent->list.next; - } + ent = (entry_t *) sec->entry_head.next; + while (ent != NULL) { + config_log("%s = %s\n", ent->name, ent->data); - sec = (section_t *)sec->list.next; + ent = (entry_t *) ent->list.next; + } + + sec = (section_t *) sec->list.next; } } - void config_delete_var(char *head, char *name) { section_t *section; - entry_t *entry; + entry_t *entry; section = find_section(head); - if (section == NULL) return; - + if (section == NULL) + return; + entry = find_entry(section, name); if (entry != NULL) { - list_delete(&entry->list, §ion->entry_head); - free(entry); + list_delete(&entry->list, §ion->entry_head); + free(entry); } } - int config_get_int(char *head, char *name, int def) { section_t *section; - entry_t *entry; - int value; + entry_t *entry; + int value; section = find_section(head); if (section == NULL) - return(def); - + return (def); + entry = find_entry(section, name); if (entry == NULL) - return(def); + return (def); sscanf(entry->data, "%i", &value); - return(value); + return (value); } +double +config_get_double(char *head, char *name, double def) +{ + section_t *section; + entry_t *entry; + double value; + + section = find_section(head); + if (section == NULL) + return (def); + + entry = find_entry(section, name); + if (entry == NULL) + return (def); + + sscanf(entry->data, "%lg", &value); + + return (value); +} int config_get_hex16(char *head, char *name, int def) { - section_t *section; - entry_t *entry; + section_t *section; + entry_t *entry; unsigned int value; section = find_section(head); if (section == NULL) - return(def); + return (def); entry = find_entry(section, name); if (entry == NULL) - return(def); + return (def); sscanf(entry->data, "%04X", &value); - return(value); + return (value); } - int config_get_hex20(char *head, char *name, int def) { - section_t *section; - entry_t *entry; + section_t *section; + entry_t *entry; unsigned int value; section = find_section(head); if (section == NULL) - return(def); + return (def); entry = find_entry(section, name); if (entry == NULL) - return(def); + return (def); sscanf(entry->data, "%05X", &value); - return(value); + return (value); } - int config_get_mac(char *head, char *name, int def) { - section_t *section; - entry_t *entry; + section_t *section; + entry_t *entry; unsigned int val0 = 0, val1 = 0, val2 = 0; section = find_section(head); if (section == NULL) - return(def); + return (def); entry = find_entry(section, name); if (entry == NULL) - return(def); + return (def); sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); - return((val0 << 16) + (val1 << 8) + val2); + return ((val0 << 16) + (val1 << 8) + val2); } - char * config_get_string(char *head, char *name, char *def) { section_t *section; - entry_t *entry; + entry_t *entry; section = find_section(head); if (section == NULL) - return(def); + return (def); entry = find_entry(section, name); if (entry == NULL) - return(def); - - return(entry->data); -} + return (def); + return (entry->data); +} wchar_t * config_get_wstring(char *head, char *name, wchar_t *def) { section_t *section; - entry_t *entry; + entry_t *entry; section = find_section(head); if (section == NULL) - return(def); + return (def); entry = find_entry(section, name); if (entry == NULL) - return(def); - - return(entry->wdata); -} + return (def); + return (entry->wdata); +} void config_set_int(char *head, char *name, int val) { section_t *section; - entry_t *ent; + entry_t *ent; section = find_section(head); if (section == NULL) - section = create_section(head); + section = create_section(head); ent = find_entry(section, name); if (ent == NULL) - ent = create_entry(section, name); + ent = create_entry(section, name); sprintf(ent->data, "%i", val); mbstowcs(ent->wdata, ent->data, 512); } +void +config_set_double(char *head, char *name, double val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%lg", val); + mbstowcs(ent->wdata, ent->data, 512); +} void config_set_hex16(char *head, char *name, int val) { section_t *section; - entry_t *ent; + entry_t *ent; section = find_section(head); if (section == NULL) - section = create_section(head); + section = create_section(head); ent = find_entry(section, name); if (ent == NULL) - ent = create_entry(section, name); + ent = create_entry(section, name); sprintf(ent->data, "%04X", val); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } - void config_set_hex20(char *head, char *name, int val) { section_t *section; - entry_t *ent; + entry_t *ent; section = find_section(head); if (section == NULL) - section = create_section(head); + section = create_section(head); ent = find_entry(section, name); if (ent == NULL) - ent = create_entry(section, name); + ent = create_entry(section, name); sprintf(ent->data, "%05X", val); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } - void config_set_mac(char *head, char *name, int val) { section_t *section; - entry_t *ent; + entry_t *ent; section = find_section(head); if (section == NULL) - section = create_section(head); + section = create_section(head); ent = find_entry(section, name); if (ent == NULL) - ent = create_entry(section, name); + ent = create_entry(section, name); sprintf(ent->data, "%02x:%02x:%02x", - (val>>16)&0xff, (val>>8)&0xff, val&0xff); + (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); mbstowcs(ent->wdata, ent->data, 512); } - void config_set_string(char *head, char *name, char *val) { section_t *section; - entry_t *ent; + entry_t *ent; section = find_section(head); if (section == NULL) - section = create_section(head); + section = create_section(head); ent = find_entry(section, name); if (ent == NULL) - ent = create_entry(section, name); + ent = create_entry(section, name); if ((strlen(val) + 1) <= sizeof(ent->data)) - memcpy(ent->data, val, strlen(val) + 1); + memcpy(ent->data, val, strlen(val) + 1); else - memcpy(ent->data, val, sizeof(ent->data)); + memcpy(ent->data, val, sizeof(ent->data)); +#ifdef _WIN32 /* Make sure the string is converted from UTF-8 rather than a legacy codepage */ + mbstoc16s(ent->wdata, ent->data, sizeof_w(ent->wdata)); +#else mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +#endif } - void config_set_wstring(char *head, char *name, wchar_t *val) { section_t *section; - entry_t *ent; + entry_t *ent; section = find_section(head); if (section == NULL) - section = create_section(head); + section = create_section(head); ent = find_entry(section, name); if (ent == NULL) - ent = create_entry(section, name); + ent = create_entry(section, name); memcpy(ent->wdata, val, sizeof_w(ent->wdata)); +#ifdef _WIN32 /* Make sure the string is converted to UTF-8 rather than a legacy codepage */ + c16stombs(ent->data, ent->wdata, sizeof(ent->data)); +#else wcstombs(ent->data, ent->wdata, sizeof(ent->data)); +#endif } diff --git a/src/cpu/386.c b/src/cpu/386.c index e5d65dbf1..5f30e1199 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -22,6 +22,7 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/machine.h> +#include <86box/gdbstub.h> #include "386_common.h" #ifdef USE_NEW_DYNAREC #include "codegen.h" @@ -71,119 +72,6 @@ x386_log(const char *fmt, ...) #undef CPU_BLOCK_END #define CPU_BLOCK_END() -static inline void fetch_ea_32_long(uint32_t rmdat) -{ - eal_r = eal_w = NULL; - easeg = cpu_state.ea_seg->base; - if (cpu_rm == 4) - { - uint8_t sib = rmdat >> 8; - - switch (cpu_mod) - { - case 0: - cpu_state.eaaddr = cpu_state.regs[sib & 7].l; - cpu_state.pc++; - break; - case 1: - cpu_state.pc++; - cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; -// pc++; - break; - case 2: - cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; - cpu_state.pc += 5; - break; - } - /*SIB byte present*/ - if ((sib & 7) == 5 && !cpu_mod) - cpu_state.eaaddr = getlong(); - else if ((sib & 6) == 4 && !cpu_state.ssegs) - { - easeg = ss; - cpu_state.ea_seg = &cpu_state.seg_ss; - } - if (((sib >> 3) & 7) != 4) - cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); - } - else - { - cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; - if (cpu_mod) - { - if (cpu_rm == 5 && !cpu_state.ssegs) - { - easeg = ss; - cpu_state.ea_seg = &cpu_state.seg_ss; - } - if (cpu_mod == 1) - { - cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); - cpu_state.pc++; - } - else - { - cpu_state.eaaddr += getlong(); - } - } - else if (cpu_rm == 5) - { - cpu_state.eaaddr = getlong(); - } - } - if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) - { - uint32_t addr = easeg + cpu_state.eaaddr; - if ( readlookup2[addr >> 12] != -1) - eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); - if (writelookup2[addr >> 12] != -1) - eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); - } -} - -static inline void fetch_ea_16_long(uint32_t rmdat) -{ - eal_r = eal_w = NULL; - easeg = cpu_state.ea_seg->base; - if (!cpu_mod && cpu_rm == 6) - { - cpu_state.eaaddr = getword(); - } - else - { - switch (cpu_mod) - { - case 0: - cpu_state.eaaddr = 0; - break; - case 1: - cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; - break; - case 2: - cpu_state.eaaddr = getword(); - break; - } - cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); - if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) - { - easeg = ss; - cpu_state.ea_seg = &cpu_state.seg_ss; - } - cpu_state.eaaddr &= 0xFFFF; - } - if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) - { - uint32_t addr = easeg + cpu_state.eaaddr; - if ( readlookup2[addr >> 12] != -1) - eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); - if (writelookup2[addr >> 12] != -1) - eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); - } -} - -#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; } -#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0 - #include "x86_flags.h" #define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ @@ -194,15 +82,35 @@ static inline void fetch_ea_16_long(uint32_t rmdat) #define OP_TABLE(name) ops_ ## name +#if 0 +#define CLOCK_CYCLES(c) \ + {\ + if (fpu_cycles > 0) {\ + fpu_cycles -= (c);\ + if (fpu_cycles < 0) {\ + cycles += fpu_cycles;\ + }\ + } else {\ + cycles -= (c);\ + }\ + } + +#define CLOCK_CYCLES_FPU(c) cycles -= (c) +#define CONCURRENCY_CYCLES(c) fpu_cycles = (c) +#else #define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_FPU(c) cycles -= (c) +#define CONCURRENCY_CYCLES(c) +#endif + #define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) #include "x86_ops.h" + void exec386(int cycs) { - // uint8_t opcode; int vector, tempi, cycdiff, oldcyc; int cycle_period, ins_cycles; uint32_t addr; @@ -257,9 +165,12 @@ exec386(int cycs) if (!use32) cpu_state.pc &= 0xffff; #endif + if (cpu_end_block_after_ins) + cpu_end_block_after_ins--; + if (cpu_state.abrt) { flags_rebuild(); - tempi = cpu_state.abrt; + tempi = cpu_state.abrt & ABRT_MASK; cpu_state.abrt = 0; x86_doabrt(tempi); if (cpu_state.abrt) { @@ -268,7 +179,7 @@ exec386(int cycs) CS = oldcs; #endif cpu_state.pc = cpu_state.oldpc; - x386_log("Double fault %i\n", ins); + x386_log("Double fault\n"); pmodeint(8, 0); if (cpu_state.abrt) { cpu_state.abrt = 0; @@ -281,11 +192,6 @@ exec386(int cycs) } } - ins_cycles -= cycles; - tsc += ins_cycles; - - cycdiff = oldcyc - cycles; - if (smi_line) enter_smm_check(0); else if (trap) { @@ -304,17 +210,18 @@ exec386(int cycs) loadcs(readmemw(0, addr + 2)); } } else if (nmi && nmi_enable && nmi_mask) { - if (AT && (cpu_fast_off_flags & 0x20000000)) - cpu_fast_off_count = cpu_fast_off_val + 1; - cpu_state.oldpc = cpu_state.pc; x86_int(2); nmi_enable = 0; +#ifdef OLD_NMI_BEHAVIOR if (nmi_auto_clear) { nmi_auto_clear = 0; nmi = 0; } - } else if ((cpu_state.flags & I_FLAG) && pic_intpending) { +#else + nmi = 0; +#endif + } else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) { vector = picinterrupt(); if (vector != -1) { flags_rebuild(); @@ -334,7 +241,10 @@ exec386(int cycs) } } - ins++; + ins_cycles -= cycles; + tsc += ins_cycles; + + cycdiff = oldcyc - cycles; if (timetolive) { timetolive--; @@ -343,7 +253,12 @@ exec386(int cycs) } if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) - timer_process(); + timer_process_inline(); + +#ifdef USE_GDBSTUB + if (gdbstub_instruction()) + return; +#endif } } } diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 1bda39a95..6c09e588a 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -16,11 +16,13 @@ #include "x87.h" #include <86box/nmi.h> #include <86box/mem.h> +#include <86box/smram.h> #include <86box/pic.h> #include <86box/pit.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/keyboard.h> +#include <86box/timer.h> #include "386_common.h" #include "x86_flags.h" #include "x86seg.h" @@ -45,9 +47,7 @@ uint32_t *eal_r, *eal_w; int nmi_enable = 1; -int cpl_override=0; - -int fpucount=0; +int alt_access, cpl_override = 0; #ifdef USE_NEW_DYNAREC uint16_t cpu_cur_status = 0; @@ -61,23 +61,34 @@ extern int optype; extern uint32_t pccache; -int in_sys = 0; +int in_sys = 0, unmask_a20_in_smm = 0; +uint32_t old_rammask = 0xffffffff; -smram_t temp_smram[2]; +int soft_reset_mask = 0; + +int smi_latched = 0; +int smm_in_hlt = 0, smi_block = 0; + +uint32_t addr64, addr64_2; +uint32_t addr64a[8], addr64a_2[8]; + +static pc_timer_t *cpu_fast_off_timer = NULL; +static double cpu_fast_off_period = 0.0; -#define AMD_SYSCALL_EIP (star & 0xFFFFFFFF) -#define AMD_SYSCALL_SB ((star >> 32) & 0xFFFF) -#define AMD_SYSRET_SB ((star >> 48) & 0xFFFF) +#define AMD_SYSCALL_EIP (msr.star & 0xFFFFFFFF) +#define AMD_SYSCALL_SB ((msr.star >> 32) & 0xFFFF) +#define AMD_SYSRET_SB ((msr.star >> 48) & 0xFFFF) /* These #define's and enum have been borrowed from Bochs. */ /* SMM feature masks */ #define SMM_IO_INSTRUCTION_RESTART (0x00010000) #define SMM_SMBASE_RELOCATION (0x00020000) +#define SMM_REVISION (0x20000000) /* TODO: Which CPU added SMBASE relocation? */ -#define SMM_REVISION_ID SMM_SMBASE_RELOCATION +#define SMM_REVISION_ID (SMM_SMBASE_RELOCATION | SMM_IO_INSTRUCTION_RESTART | SMM_REVISION) #define SMM_SAVE_STATE_MAP_SIZE 128 @@ -321,7 +332,10 @@ x386_common_log(const char *fmt, ...) static __inline void set_stack32(int s) { - stack32 = s; + if ((cr0 & 1) && ! (cpu_state.eflags & VM_FLAG)) + stack32 = s; + else + stack32 = 0; if (stack32) cpu_cur_status |= CPU_STATUS_STACK32; @@ -333,13 +347,15 @@ set_stack32(int s) static __inline void set_use32(int u) { - if (u) { - use32 = 0x300; - cpu_cur_status |= CPU_STATUS_USE32; - } else { + if ((cr0 & 1) && ! (cpu_state.eflags & VM_FLAG)) + use32 = u ? 0x300 : 0; + else use32 = 0; + + if (use32) + cpu_cur_status |= CPU_STATUS_USE32; + else cpu_cur_status &= ~CPU_STATUS_USE32; - } } @@ -983,14 +999,38 @@ smram_restore_state_amd_k(uint32_t *saved_state) } +static void +smram_save_state_cyrix(uint32_t *saved_state, int in_hlt) +{ + saved_state[0] = dr[7]; + saved_state[1] = cpu_state.flags | (cpu_state.eflags << 16); + saved_state[2] = cr0; + saved_state[3] = cpu_state.oldpc; + saved_state[4] = cpu_state.pc; + saved_state[5] = CS | (CPL << 21); + saved_state[6] = 0x00000000; +} + + +static void +smram_restore_state_cyrix(uint32_t *saved_state) +{ + dr[7] = saved_state[0]; + cpu_state.flags = saved_state[1] & 0xffff; + cpu_state.eflags = saved_state[1] >> 16; + cr0 = saved_state[2]; + cpu_state.pc = saved_state[4]; +} + + void enter_smm(int in_hlt) { uint32_t saved_state[SMM_SAVE_STATE_MAP_SIZE], n; uint32_t smram_state = smbase + 0x10000; - /* If it's a CPU on which SMM is not supporter, do nothing. */ - if (!is_pentium && !is_k5 && !is_k6 && !is_p6) + /* If it's a CPU on which SMM is not supported, do nothing. */ + if (!is_am486 && !is_pentium && !is_k5 && !is_k6 && !is_p6 && !is_cxsmm) return; x386_common_log("enter_smm(): smbase = %08X\n", smbase); @@ -1025,21 +1065,24 @@ enter_smm(int in_hlt) x386_common_log("EAX = %08X, EBX = %08X, ECX = %08X, EDX = %08X, ESI = %08X, EDI = %08X, ESP = %08X, EBP = %08X\n", EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP); + flags_rebuild(); in_smm = 1; - if (smram[0].size) - mem_mapping_recalc(smram[0].host_base, smram[0].size); - if (smram[1].size) - mem_mapping_recalc(smram[1].host_base, smram[1].size); - /* This is used by leave_smm() to make sure we don't keep the old mappings in SMM mode if the SMM - handler has told the chipset to change the actual mappings. */ - memcpy(temp_smram, smram, sizeof(temp_smram)); - flushmmucache(); + smram_backup_all(); + smram_recalc_all(0); + + if (is_cxsmm) { + if (!(cyrix.smhr & SMHR_VALID)) + cyrix.smhr = (cyrix.arr[3].base + cyrix.arr[3].size) | SMHR_VALID; + smram_state = cyrix.smhr & SMHR_ADDR_MASK; + } memset(saved_state, 0x00, SMM_SAVE_STATE_MAP_SIZE * sizeof(uint32_t)); - if (is_pentium || is_am486) /* Am486 / 5x86 / Intel P5 (Pentium) */ + if (is_cxsmm) /* Cx6x86 */ + smram_save_state_cyrix(saved_state, in_hlt); + else if (is_pentium || is_am486) /* Am486 / 5x86 / Intel P5 (Pentium) */ smram_save_state_p5(saved_state, in_hlt); - else if (is_k5 || is_k6) /* AMD K5 and K6 */ + else if (is_k5 || is_k6) /* AMD K5 and K6 */ smram_save_state_amd_k(saved_state, in_hlt); else if (is_p6) /* Intel P6 (Pentium Pro, Pentium II, Celeron) */ smram_save_state_p6(saved_state, in_hlt); @@ -1051,44 +1094,71 @@ enter_smm(int in_hlt) cr4 = 0; dr[7] = 0x400; - cpu_state.pc = 0x8000; - cpu_state.seg_ds.seg = 0x00000000; - cpu_state.seg_ds.base = 0x00000000; - cpu_state.seg_ds.limit = 0xffffffff; - cpu_state.seg_ds.access = 0x93; - cpu_state.seg_ds.ar_high = 0x80; + if (is_cxsmm) { + cpu_state.pc = 0x0000; + cpl_override = 1; + cyrix_write_seg_descriptor(smram_state - 0x20, &cpu_state.seg_cs); + cpl_override = 0; + cpu_state.seg_cs.seg = (cyrix.arr[3].base >> 4); + cpu_state.seg_cs.base = cyrix.arr[3].base; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.access = 0x93; + cpu_state.seg_cs.ar_high = 0x80; + cpu_state.seg_cs.checked = 1; - memcpy(&cpu_state.seg_es, &cpu_state.seg_ds, sizeof(x86seg)); - memcpy(&cpu_state.seg_ss, &cpu_state.seg_ds, sizeof(x86seg)); - memcpy(&cpu_state.seg_fs, &cpu_state.seg_ds, sizeof(x86seg)); - memcpy(&cpu_state.seg_gs, &cpu_state.seg_ds, sizeof(x86seg)); + smm_seg_load(&cpu_state.seg_cs); + } else { + cpu_state.pc = 0x8000; + cpu_state.seg_ds.seg = 0x00000000; + cpu_state.seg_ds.base = 0x00000000; + cpu_state.seg_ds.limit = 0xffffffff; + cpu_state.seg_ds.access = 0x93; + cpu_state.seg_ds.ar_high = 0x80; - if (is_p6) - cpu_state.seg_cs.seg = (smbase >> 4); - else - cpu_state.seg_cs.seg = 0x3000; + memcpy(&cpu_state.seg_es, &cpu_state.seg_ds, sizeof(x86seg)); + memcpy(&cpu_state.seg_ss, &cpu_state.seg_ds, sizeof(x86seg)); + memcpy(&cpu_state.seg_fs, &cpu_state.seg_ds, sizeof(x86seg)); + memcpy(&cpu_state.seg_gs, &cpu_state.seg_ds, sizeof(x86seg)); - /* On Pentium, CS selector in SMM is always 3000, regardless of SMBASE. */ - cpu_state.seg_cs.base = smbase; - cpu_state.seg_cs.limit = 0xffffffff; - cpu_state.seg_cs.access = 0x93; - cpu_state.seg_cs.ar_high = 0x80; - cpu_state.seg_cs.checked = 1; + if (is_p6) + cpu_state.seg_cs.seg = (smbase >> 4); + else + cpu_state.seg_cs.seg = 0x3000; - smm_seg_load(&cpu_state.seg_es); - smm_seg_load(&cpu_state.seg_cs); - smm_seg_load(&cpu_state.seg_ds); - smm_seg_load(&cpu_state.seg_ss); - smm_seg_load(&cpu_state.seg_fs); - smm_seg_load(&cpu_state.seg_gs); + /* On Pentium, CS selector in SMM is always 3000, regardless of SMBASE. */ + cpu_state.seg_cs.base = smbase; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.access = 0x93; + cpu_state.seg_cs.ar_high = 0x80; + cpu_state.seg_cs.checked = 1; + + smm_seg_load(&cpu_state.seg_es); + smm_seg_load(&cpu_state.seg_cs); + smm_seg_load(&cpu_state.seg_ds); + smm_seg_load(&cpu_state.seg_ss); + smm_seg_load(&cpu_state.seg_fs); + smm_seg_load(&cpu_state.seg_gs); + } cpu_state.op32 = use32; - for (n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { - smram_state -= 4; - writememl(0, smram_state, saved_state[n]); + cpl_override = 1; + if (is_cxsmm) { + writememl(0, smram_state - 0x04, saved_state[0]); + writememl(0, smram_state - 0x08, saved_state[1]); + writememl(0, smram_state - 0x0c, saved_state[2]); + writememl(0, smram_state - 0x10, saved_state[3]); + writememl(0, smram_state - 0x14, saved_state[4]); + writememl(0, smram_state - 0x18, saved_state[5]); + writememl(0, smram_state - 0x24, saved_state[6]); + } else { + for (n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { + smram_state -= 4; + writememl(0, smram_state, saved_state[n]); + } } + cpl_override = 0; nmi_mask = 0; @@ -1100,6 +1170,18 @@ enter_smm(int in_hlt) smm_in_hlt = in_hlt; + if (unmask_a20_in_smm) { + old_rammask = rammask; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + if (is6117) + rammask |= 0x3000000; + + flushmmucache(); + } + + oldcpl = 0; + + cpu_cur_status &= ~(CPU_STATUS_PMODE | CPU_STATUS_V86); CPU_BLOCK_END(); } @@ -1107,9 +1189,6 @@ enter_smm(int in_hlt) void enter_smm_check(int in_hlt) { - if (smi_line && (cpu_fast_off_flags & 0x80000000)) - cpu_fast_off_count = cpu_fast_off_val + 1; - if ((in_smm == 0) && smi_line) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SMI while not in SMM\n"); @@ -1140,41 +1219,62 @@ leave_smm(void) uint32_t smram_state = smbase + 0x10000; /* If it's a CPU on which SMM is not supported (or not implemented in 86Box), do nothing. */ - if (!is_pentium && !is_k5 && !is_k6 && !is_p6) + if (!is_am486 && !is_pentium && !is_k5 && !is_k6 && !is_p6 && !is_cxsmm) return; memset(saved_state, 0x00, SMM_SAVE_STATE_MAP_SIZE * sizeof(uint32_t)); - for (n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { - smram_state -= 4; - saved_state[n] = readmeml(0, smram_state); - x386_common_log("Reading %08X from memory at %08X to array element %i\n", saved_state[n], smram_state, n); + cpl_override = 1; + if (is_cxsmm) { + smram_state = cyrix.smhr & SMHR_ADDR_MASK; + saved_state[0] = readmeml(0, smram_state - 0x04); + saved_state[1] = readmeml(0, smram_state - 0x08); + saved_state[2] = readmeml(0, smram_state - 0x0c); + saved_state[3] = readmeml(0, smram_state - 0x10); + saved_state[4] = readmeml(0, smram_state - 0x14); + saved_state[5] = readmeml(0, smram_state - 0x18); + cyrix_load_seg_descriptor(smram_state - 0x20, &cpu_state.seg_cs); + saved_state[6] = readmeml(0, smram_state - 0x24); + } else { + for (n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { + smram_state -= 4; + saved_state[n] = readmeml(0, smram_state); + x386_common_log("Reading %08X from memory at %08X to array element %i\n", saved_state[n], smram_state, n); + } + } + cpl_override = 0; + + if (unmask_a20_in_smm) { + rammask = old_rammask; + + flushmmucache(); } x386_common_log("New SMBASE: %08X (%08X)\n", saved_state[SMRAM_FIELD_P5_SMBASE_OFFSET], saved_state[66]); - if (is_pentium) /* Intel P5 (Pentium) */ + if (is_cxsmm) /* Cx6x86 */ + smram_restore_state_cyrix(saved_state); + else if (is_pentium || is_am486) /* Am486 / 5x86 / Intel P5 (Pentium) */ smram_restore_state_p5(saved_state); - else if (is_k5 || is_k6) /* AMD K5 and K6 */ + else if (is_k5 || is_k6) /* AMD K5 and K6 */ smram_restore_state_amd_k(saved_state); else if (is_p6) /* Intel P6 (Pentium Pro, Pentium II, Celeron) */ smram_restore_state_p6(saved_state); in_smm = 0; - if (temp_smram[0].size) - mem_mapping_recalc(temp_smram[0].host_base, temp_smram[0].size); - if (temp_smram[1].size) - mem_mapping_recalc(temp_smram[1].host_base, temp_smram[1].size); - memset(temp_smram, 0x00, sizeof(temp_smram)); - if (smram[0].size) - mem_mapping_recalc(smram[0].host_base, smram[0].size); - if (smram[1].size) - mem_mapping_recalc(smram[1].host_base, smram[1].size); - flushmmucache(); + smram_recalc_all(1); - cpu_state.op32 = use32; + cpu_386_flags_extract(); + cpu_cur_status &= ~(CPU_STATUS_PMODE | CPU_STATUS_V86); + if (cr0 & 1) { + cpu_cur_status |= CPU_STATUS_PMODE; + if (cpu_state.eflags & VM_FLAG) + cpu_cur_status |= CPU_STATUS_V86; + } nmi_mask = 1; + oldcpl = CPL; + CPU_BLOCK_END(); x386_common_log("CS : seg = %04X, base = %08X, limit = %08X, limit_low = %08X, limit_high = %08X, access = %02X, ar_high = %02X\n", @@ -1224,7 +1324,7 @@ x86_int(int num) else { addr = (num << 2) + idt.base; - if ((num << 2) + 3 > idt.limit) { + if ((num << 2UL) + 3UL > idt.limit) { if (idt.limit < 35) { cpu_state.abrt = 0; softresetx86(); @@ -1275,7 +1375,7 @@ x86_int_sw(int num) else { addr = (num << 2) + idt.base; - if ((num << 2) + 3 > idt.limit) + if ((num << 2UL) + 3UL > idt.limit) x86_int(0x0d); else { if (stack32) { @@ -1359,7 +1459,7 @@ x86illegal() int -checkio(int port) +checkio(uint32_t port) { uint16_t t; uint8_t d; @@ -1371,15 +1471,11 @@ checkio(int port) if (cpu_state.abrt) return 0; - if ((t + (port >> 3)) > tr.limit) + if ((t + (port >> 3UL)) > tr.limit) return 1; cpl_override = 1; -#ifdef USE_NEW_DYNAREC d = readmembl(tr.base + t + (port >> 3)); -#else - d = readmemb386l(0, tr.base + t + (port >> 3)); -#endif cpl_override = 0; return d & (1 << (port & 7)); } @@ -1425,7 +1521,7 @@ idivl(int32_t val) int64_t num, quo; int32_t rem, quo32; - if (val == 0) { + if (val == 0) { divexcp(); return 1; } @@ -1461,50 +1557,9 @@ cpu_386_flags_rebuild() } -/* 0 = Limit 0-15 - 1 = Base 0-15 - 2 = Base 16-23 (bits 0-7), Access rights - 8-11 Type - 12 S - 13, 14 DPL - 15 P - 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. - 4 A - 6 DB - 7 G */ -static __inline void -read_seg_data(uint16_t *seg_data, uint16_t seg, x86seg *s) -{ - uint32_t addr; - - if (seg & 0x0004) - addr = (seg & 0xfff8) + ldt.base; - else - addr = (seg & 0xfff8) + gdt.base; - - cpl_override = 1; - x386_common_log("read_seg_data(abrt = %02X): Begin (descriptor at %08X)\n", cpu_state.abrt, addr); - seg_data[0]=readmemw(0, addr); - x386_common_log("read_seg_data(abrt = %02X): seg_data[0] = %04X\n", cpu_state.abrt, seg_data[0]); - seg_data[1]=readmemw(0, addr + 2); - x386_common_log("read_seg_data(abrt = %02X): seg_data[1] = %04X\n", cpu_state.abrt, seg_data[1]); - seg_data[2]=readmemw(0, addr + 4); - x386_common_log("read_seg_data(abrt = %02X): seg_data[2] = %04X\n", cpu_state.abrt, seg_data[2]); - seg_data[3]=readmemw(0, addr + 6); - x386_common_log("read_seg_data(abrt = %02X): seg_data[3] = %04X\n", cpu_state.abrt, seg_data[3]); - if (s != &cpu_state.seg_cs) { - writememw(0, addr + 4, seg_data[2] | 0x100); /*Set accessed bit*/ - x386_common_log("read_seg_data(abrt = %02X): accessed bit set\n", cpu_state.abrt); - } - cpl_override = 0; -} - - int sysenter(uint32_t fetchdat) { - uint16_t seg_data[4]; - #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSENTER called\n"); #endif @@ -1517,7 +1572,7 @@ sysenter(uint32_t fetchdat) return cpu_state.abrt; } - if (!(cs_msr & 0xFFF8)) { + if (!(msr.sysenter_cs & 0xFFF8)) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSENTER: CS MSR is zero"); #endif @@ -1529,67 +1584,55 @@ sysenter(uint32_t fetchdat) x386_common_log("SYSENTER started:\n"); x386_common_log(" CS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; EIP=%08X\n", cpu_state.seg_cs.seg, !!cpu_state.seg_cs.checked, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.ar_high, cpu_state.seg_cs.access, cpu_state.pc); x386_common_log(" SS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; ESP=%08X\n", cpu_state.seg_ss.seg, !!cpu_state.seg_ss.checked, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.ar_high, cpu_state.seg_ss.access, ESP); - x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", cs_msr, esp_msr, eip_msr, pccache, pccache2); + x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", msr.sysenter_cs, msr.sysenter_esp, msr.sysenter_eip, pccache, pccache2); x386_common_log(" EFLAGS=%04X%04X/%i 32=%i/%i ECX=%08X EDX=%08X abrt=%02X\n", cpu_state.eflags, cpu_state.flags, !!trap, !!use32, !!stack32, ECX, EDX, cpu_state.abrt); #endif /* Set VM, RF, and IF to 0. */ - flags_rebuild(); cpu_state.eflags &= ~(RF_FLAG | VM_FLAG); cpu_state.flags &= ~I_FLAG; - cpu_cur_status &= ~CPU_STATUS_V86; #ifndef USE_NEW_DYNAREC oldcs = CS; #endif cpu_state.oldpc = cpu_state.pc; -#if 0 - old_pc = cpu_state.pc; -#endif - ESP = esp_msr; - cpu_state.pc = eip_msr; + ESP = msr.sysenter_esp; + cpu_state.pc = msr.sysenter_eip; -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SYSENTER: Loading CS...\n"); -#endif - CS = (cs_msr & 0xFFFC); - cpu_state.seg_cs.access &= 0x9f; - read_seg_data(seg_data, CS, &cpu_state.seg_cs); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_cs, seg_data); - cpu_state.seg_cs.checked = 0; - set_use32(0x40); + cpu_state.seg_cs.seg = (msr.sysenter_cs & 0xfffc); + cpu_state.seg_cs.base = 0; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = 0x9b; + cpu_state.seg_cs.ar_high = 0xcf; + cpu_state.seg_cs.checked = 1; + oldcpl = 0; -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SYSENTER: Loading SS...\n"); -#endif - SS = ((cs_msr + 8) & 0xFFFC); - read_seg_data(seg_data, SS, &cpu_state.seg_ss); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_ss, seg_data); - cpu_state.seg_ss.checked = 0; + cpu_state.seg_ss.seg = ((msr.sysenter_cs + 8) & 0xfffc); + cpu_state.seg_ss.base = 0; + cpu_state.seg_ss.limit_low = 0; + cpu_state.seg_ss.limit = 0xffffffff; + cpu_state.seg_ss.limit_high = 0xffffffff; + cpu_state.seg_ss.access = 0x93; + cpu_state.seg_ss.ar_high = 0xcf; + cpu_state.seg_ss.checked = 1; #ifdef USE_DYNAREC codegen_flat_ss = 0; #endif - if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && - cpu_state.seg_ss.limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; + + cpu_cur_status &= ~(CPU_STATUS_NOTFLATSS | CPU_STATUS_V86); + cpu_cur_status |= (CPU_STATUS_USE32 | CPU_STATUS_STACK32/* | CPU_STATUS_PMODE*/); + set_use32(1); set_stack32(1); - oldcpl = CPL; - flags_extract(); - trap = 0; in_sys = 1; #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSENTER completed:\n"); x386_common_log(" CS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; EIP=%08X\n", cpu_state.seg_cs.seg, !!cpu_state.seg_cs.checked, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.ar_high, cpu_state.seg_cs.access, cpu_state.pc); x386_common_log(" SS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; ESP=%08X\n", cpu_state.seg_ss.seg, !!cpu_state.seg_ss.checked, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.ar_high, cpu_state.seg_ss.access, ESP); - x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", cs_msr, esp_msr, eip_msr, pccache, pccache2); + x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", msr.sysenter_cs, msr.sysenter_esp, msr.sysenter_eip, pccache, pccache2); x386_common_log(" EFLAGS=%04X%04X/%i 32=%i/%i ECX=%08X EDX=%08X abrt=%02X\n", cpu_state.eflags, cpu_state.flags, !!trap, !!use32, !!stack32, ECX, EDX, cpu_state.abrt); #endif @@ -1600,13 +1643,11 @@ sysenter(uint32_t fetchdat) int sysexit(uint32_t fetchdat) { - uint16_t seg_data[4]; - #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSEXIT called\n"); #endif - if (!(cs_msr & 0xFFF8)) { + if (!(msr.sysenter_cs & 0xFFF8)) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSEXIT: CS MSR is zero"); #endif @@ -1634,7 +1675,7 @@ sysexit(uint32_t fetchdat) x386_common_log("SYSEXIT start:\n"); x386_common_log(" CS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; EIP=%08X\n", cpu_state.seg_cs.seg, !!cpu_state.seg_cs.checked, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.ar_high, cpu_state.seg_cs.access, cpu_state.pc); x386_common_log(" SS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; ESP=%08X\n", cpu_state.seg_ss.seg, !!cpu_state.seg_ss.checked, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.ar_high, cpu_state.seg_ss.access, ESP); - x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", cs_msr, esp_msr, eip_msr, pccache, pccache2); + x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", msr.sysenter_cs, msr.sysenter_esp, msr.sysenter_eip, pccache, pccache2); x386_common_log(" EFLAGS=%04X%04X/%i 32=%i/%i ECX=%08X EDX=%08X abrt=%02X\n", cpu_state.eflags, cpu_state.flags, !!trap, !!use32, !!stack32, ECX, EDX, cpu_state.abrt); #endif @@ -1645,46 +1686,41 @@ sysexit(uint32_t fetchdat) ESP = ECX; cpu_state.pc = EDX; -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SYSEXIT: Loading CS...\n"); -#endif - CS = (((cs_msr + 16) & 0xFFFC) | 3); - read_seg_data(seg_data, CS, &cpu_state.seg_cs); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_cs, seg_data); - cpu_state.seg_cs.checked = 0; - set_use32(0x40); + cpu_state.seg_cs.seg = (((msr.sysenter_cs + 16) & 0xfffc) | 3); + cpu_state.seg_cs.base = 0; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = 0xfb; + cpu_state.seg_cs.ar_high = 0xcf; + cpu_state.seg_cs.checked = 1; + oldcpl = 3; -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SYSEXIT: Loading SS...\n"); -#endif - SS = (((cs_msr + 24) & 0xFFFC) | 3); - read_seg_data(seg_data, SS, &cpu_state.seg_ss); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_ss, seg_data); - cpu_state.seg_ss.checked = 0; + cpu_state.seg_ss.seg = (((msr.sysenter_cs + 24) & 0xfffc) | 3); + cpu_state.seg_ss.base = 0; + cpu_state.seg_ss.limit_low = 0; + cpu_state.seg_ss.limit = 0xffffffff; + cpu_state.seg_ss.limit_high = 0xffffffff; + cpu_state.seg_ss.access = 0xf3; + cpu_state.seg_ss.ar_high = 0xcf; + cpu_state.seg_ss.checked = 1; #ifdef USE_DYNAREC codegen_flat_ss = 0; #endif - if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && - cpu_state.seg_ss.limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; + + cpu_cur_status &= ~(CPU_STATUS_NOTFLATSS/* | CPU_STATUS_V86*/); + cpu_cur_status |= (CPU_STATUS_USE32 | CPU_STATUS_STACK32 | CPU_STATUS_PMODE); + flushmmucache_cr3(); + set_use32(1); set_stack32(1); - flushmmucache_cr3(); - oldcpl = CPL; - trap = 0; in_sys = 0; #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSEXIT completed:\n"); x386_common_log(" CS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; EIP=%08X\n", cpu_state.seg_cs.seg, !!cpu_state.seg_cs.checked, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.ar_high, cpu_state.seg_cs.access, cpu_state.pc); x386_common_log(" SS %04X/%i: b=%08X l=%08X (%08X-%08X) a=%02X%02X; ESP=%08X\n", cpu_state.seg_ss.seg, !!cpu_state.seg_ss.checked, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.ar_high, cpu_state.seg_ss.access, ESP); - x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", cs_msr, esp_msr, eip_msr, pccache, pccache2); + x386_common_log(" Misc. : MSR (CS/ESP/EIP)=%04X/%08X/%08X pccache=%08X/%08X\n", msr.sysenter_cs, msr.sysenter_esp, msr.sysenter_eip, pccache, pccache2); x386_common_log(" EFLAGS=%04X%04X/%i 32=%i/%i ECX=%08X EDX=%08X abrt=%02X\n", cpu_state.eflags, cpu_state.flags, !!trap, !!use32, !!stack32, ECX, EDX, cpu_state.abrt); #endif @@ -1693,61 +1729,52 @@ sysexit(uint32_t fetchdat) int -syscall(uint32_t fetchdat) +syscall_op(uint32_t fetchdat) { - uint16_t seg_data[4]; - #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSCALL called\n"); #endif - if (!(cr0 & 1)) { - x86gpf("SYSCALL: CPU not in protected mode", 0); - return cpu_state.abrt; - } - - if (!AMD_SYSCALL_SB) { - x86gpf("SYSCALL: AMD SYSCALL SB MSR is zero", 0); - return cpu_state.abrt; - } - /* Let's do this by the AMD spec. */ + /* Set VM and IF to 0. */ + cpu_state.eflags &= ~VM_FLAG; + cpu_state.flags &= ~I_FLAG; + +#ifndef USE_NEW_DYNAREC + oldcs = CS; +#endif + cpu_state.oldpc = cpu_state.pc; ECX = cpu_state.pc; - flags_rebuild(); - cpu_state.eflags &= ~0x0002; - cpu_state.flags &= ~0x0200; - cpu_cur_status &= ~CPU_STATUS_V86; - /* CS */ - CS = AMD_SYSCALL_SB & 0xFFFC; - read_seg_data(seg_data, CS, &cpu_state.seg_cs); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_cs, seg_data); - cpu_state.seg_cs.checked = 0; - set_use32(0x40); + CS = AMD_SYSCALL_SB & 0xfffc; + cpu_state.seg_cs.base = 0; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = 0x9b; + cpu_state.seg_cs.ar_high = 0xcf; + cpu_state.seg_cs.checked = 1; + oldcpl = 0; /* SS */ - SS = (AMD_SYSCALL_SB + 8) & 0xFFFC; - read_seg_data(seg_data, SS, &cpu_state.seg_ss); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_ss, seg_data); - cpu_state.seg_ss.checked = 0; + SS = (AMD_SYSCALL_SB + 8) & 0xfffc; + cpu_state.seg_ss.base = 0; + cpu_state.seg_ss.limit_low = 0; + cpu_state.seg_ss.limit = 0xffffffff; + cpu_state.seg_ss.limit_high = 0xffffffff; + cpu_state.seg_ss.access = 0x93; + cpu_state.seg_ss.ar_high = 0xcf; + cpu_state.seg_ss.checked = 1; #ifdef USE_DYNAREC codegen_flat_ss = 0; #endif - if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && - cpu_state.seg_ss.limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; + + cpu_cur_status &= ~(CPU_STATUS_NOTFLATSS | CPU_STATUS_V86); + cpu_cur_status |= (CPU_STATUS_USE32 | CPU_STATUS_STACK32 | CPU_STATUS_PMODE); + set_use32(1); set_stack32(1); - oldcpl = CPL; - flags_extract(); - trap = 0; in_sys = 1; return 1; @@ -1757,67 +1784,120 @@ syscall(uint32_t fetchdat) int sysret(uint32_t fetchdat) { - uint16_t seg_data[4]; - #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSRET called\n"); #endif - if (!AMD_SYSRET_SB) { - x86gpf("SYSRET: CS MSR is zero", 0); + if (CPL) { +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SYSRET: CPL not 0"); +#endif + x86gpf("SYSRET: CPL not 0", 0); return cpu_state.abrt; } - if (!(cr0 & 1)) { - x86gpf("SYSRET: CPU not in protected mode", 0); - return cpu_state.abrt; - } + cpu_state.flags |= I_FLAG; + /* First instruction after SYSRET will always execute, regardless of whether + there is a pending interrupt, following the STI logic */ + cpu_end_block_after_ins = 2; +#ifndef USE_NEW_DYNAREC + oldcs = CS; +#endif + cpu_state.oldpc = cpu_state.pc; cpu_state.pc = ECX; - cpu_state.eflags |= (1 << 1); - /* CS */ - CS = (AMD_SYSRET_SB & 0xFFFC) | 3; - cpu_state.seg_cs.seg = AMD_SYSRET_SB & ~7; - read_seg_data(seg_data, CS, &cpu_state.seg_cs); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_cs, seg_data); - cpu_state.seg_cs.checked = 0; - set_use32(0x40); + CS = (AMD_SYSRET_SB & 0xfffc) | 3; + cpu_state.seg_cs.base = 0; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = 0xfb; + cpu_state.seg_cs.ar_high = 0xcf; + cpu_state.seg_cs.checked = 1; + oldcpl = 3; /* SS */ - SS = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; - read_seg_data(seg_data, SS, &cpu_state.seg_ss); - if (cpu_state.abrt) - return 1; - do_seg_load(&cpu_state.seg_ss, seg_data); - cpu_state.seg_ss.checked = 0; + SS = ((AMD_SYSRET_SB + 8) & 0xfffc) | 3; + cpu_state.seg_ss.base = 0; + cpu_state.seg_ss.limit_low = 0; + cpu_state.seg_ss.limit = 0xffffffff; + cpu_state.seg_ss.limit_high = 0xffffffff; + cpu_state.seg_ss.access = 0xf3; + cpu_state.seg_cs.ar_high = 0xcf; + cpu_state.seg_ss.checked = 1; #ifdef USE_DYNAREC codegen_flat_ss = 0; #endif - if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && - cpu_state.seg_ss.limit_high == 0xffffffff) - cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; - else - cpu_cur_status |= CPU_STATUS_NOTFLATSS; + + cpu_cur_status &= ~(CPU_STATUS_NOTFLATSS/* | CPU_STATUS_V86*/); + cpu_cur_status |= (CPU_STATUS_USE32 | CPU_STATUS_STACK32 | CPU_STATUS_PMODE); + flushmmucache_cr3(); + set_use32(1); set_stack32(1); - flushmmucache_cr3(); - oldcpl = CPL; - trap = 0; in_sys = 0; return 1; } +void +cpu_register_fast_off_handler(void *timer) +{ + cpu_fast_off_timer = (pc_timer_t *) timer; +} + + +void +cpu_fast_off_advance(void) +{ + timer_disable(cpu_fast_off_timer); + if (cpu_fast_off_period != 0.0) + timer_on_auto(cpu_fast_off_timer, cpu_fast_off_period); +} + + +void +cpu_fast_off_period_set(uint16_t val, double period) +{ + cpu_fast_off_period = ((double) (val + 1)) * period; + cpu_fast_off_advance(); +} + + +void +cpu_fast_off_reset(void) +{ + cpu_register_fast_off_handler(NULL); + cpu_fast_off_period = 0.0; + cpu_fast_off_advance(); +} + + +void +smi_raise(void) +{ + if (is486 && (cpu_fast_off_flags & 0x80000000)) + cpu_fast_off_advance(); + + smi_line = 1; +} + + +void +nmi_raise(void) +{ + if (is486 && (cpu_fast_off_flags & 0x20000000)) + cpu_fast_off_advance(); +} + + #ifndef USE_DYNAREC /* This is for compatibility with new x87 code. */ void codegen_set_rounding_mode(int mode) { - /* cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); */ - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (mode << 10); + /* cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (mode << 10); */ } #endif diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index 294c82b98..28aab7450 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -15,64 +15,55 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ - #ifndef _386_COMMON_H_ #define _386_COMMON_H_ #include -#ifdef USE_NEW_DYNAREC -#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) -#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemb_n(s,a,b) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF)?readmembl_no_mmut((s)+(a),b): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) ) +#define readmemw_n(s,a,b) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl_no_mmut((s)+(a),b):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml_n(s,a,b) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll_no_mmut((s)+(a),b):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) ) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) -#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#else -#undef readmemb -#undef writememb +#define writememb_n(s,a,b,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF) writemembl_no_mmut((s)+(a),b,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememw_n(s,a,b,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl_no_mmut((s)+(a),b,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememl_n(s,a,b,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll_no_mmut((s)+(a),b,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v + +#define do_mmut_rb(s,a,b) if (readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF) do_mmutranslate((s)+(a), b, 1, 0) +#define do_mmut_rw(s,a,b) if (readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) do_mmutranslate((s)+(a), b, 2, 0) +#define do_mmut_rl(s,a,b) if (readlookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) do_mmutranslate((s)+(a), b, 4, 0) +#define do_mmut_rb2(s,a,b) old_rl2 = readlookup2[(uint32_t)((s)+(a))>>12]; if (old_rl2==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF) do_mmutranslate((s)+(a), b, 1, 0) +#define do_mmut_rw2(s,a,b) old_rl2 = readlookup2[(uint32_t)((s)+(a))>>12]; if (old_rl2==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) do_mmutranslate((s)+(a), b, 2, 0) +#define do_mmut_rl2(s,a,b) old_rl2 = readlookup2[(uint32_t)((s)+(a))>>12]; if (old_rl2==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) do_mmutranslate((s)+(a), b, 4, 0) + +#define do_mmut_wb(s,a,b) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF) do_mmutranslate((s)+(a), b, 1, 1) +#define do_mmut_ww(s,a,b) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) do_mmutranslate((s)+(a), b, 2, 1) +#define do_mmut_wl(s,a,b) if (writelookup2[(uint32_t)((s)+(a))>>12]==(uintptr_t)LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) do_mmutranslate((s)+(a), b, 4, 1) -#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) -#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) - -#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v - -#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#endif +int checkio(uint32_t port); -int checkio(int port); - - -#ifdef USE_NEW_DYNAREC -#define check_io_perm(port) if (!IOPLp || (cpu_state.eflags&VM_FLAG)) \ - { \ - int tempi = checkio(port); \ - if (cpu_state.abrt) return 1; \ - if (tempi) \ - { \ - x86gpf("check_io_perm(): no permission",0); \ - return 1; \ - } \ - } -#else #define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (cpu_state.eflags&VM_FLAG))) \ { \ int tempi = checkio(port); \ if (cpu_state.abrt) return 1; \ if (tempi) \ { \ - x86gpf("check_io_perm(): no permission",0); \ + if (cpu_state.eflags & VM_FLAG) \ + x86gpf_expected(NULL,0); \ + else \ + x86gpf(NULL,0); \ return 1; \ } \ } -#endif #define SEG_CHECK_READ(seg) \ do \ @@ -107,12 +98,6 @@ int checkio(int port); else \ x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ return 1; \ - } \ - if (cr0 >> 31) { \ - (void) mmutranslatereal((chseg)->base + low, 0); \ - (void) mmutranslatereal((chseg)->base + high, 0); \ - if (cpu_state.abrt) \ - return 1; \ } #define CHECK_READ_REP(chseg, low, high) \ @@ -128,12 +113,6 @@ int checkio(int port); else \ x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ break; \ - } \ - if (cr0 >> 31) { \ - (void) mmutranslatereal((chseg)->base + low, 0); \ - (void) mmutranslatereal((chseg)->base + high, 0); \ - if (cpu_state.abrt) \ - break; \ } #define CHECK_WRITE_COMMON(chseg, low, high) \ @@ -152,13 +131,7 @@ int checkio(int port); } #define CHECK_WRITE(chseg, low, high) \ - CHECK_WRITE_COMMON(chseg, low, high) \ - if (cr0 >> 31) { \ - (void) mmutranslatereal((chseg)->base + low, 1); \ - (void) mmutranslatereal((chseg)->base + high, 1); \ - if (cpu_state.abrt) \ - return 1; \ - } + CHECK_WRITE_COMMON(chseg, low, high) #define CHECK_WRITE_REP(chseg, low, high) \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ @@ -173,12 +146,6 @@ int checkio(int port); else \ x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ break; \ - } \ - if (cr0 >> 31) { \ - (void) mmutranslatereal((chseg)->base + low, 1); \ - (void) mmutranslatereal((chseg)->base + high, 1); \ - if (cpu_state.abrt) \ - break; \ } @@ -194,8 +161,8 @@ int checkio(int port); static __inline uint8_t fastreadb(uint32_t a) { uint8_t *t; - - if ((a >> 12) == pccache) + + if ((a >> 12) == pccache) return *((uint8_t *)&pccache2[a]); t = getpccache(a); if (cpu_state.abrt) @@ -341,32 +308,16 @@ static __inline void seteaq(uint64_t v) { if (seteaq_cwc()) return; -#ifdef USE_NEW_DYNAREC writememql(easeg + cpu_state.eaaddr, v); -#else - writememql(easeg, cpu_state.eaaddr, v); -#endif } -#ifdef USE_NEW_DYNAREC #define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v -#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v -#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v -#else -#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writememb386l(easeg,cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v -#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else { writememwl(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].w=v -#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else { writememll(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].l=v -#endif +#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v +#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v -#ifdef USE_NEW_DYNAREC #define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); #define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); #define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); -#else -#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); -#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); -#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); -#endif #define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ #define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index af004521a..3e4d91ed2 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -3,6 +3,9 @@ #include #include #include +#if defined(__APPLE__) && defined(__aarch64__) +#include +#endif #include #include #ifndef INFINITY @@ -23,21 +26,29 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/machine.h> +#include <86box/gdbstub.h> #ifdef USE_DYNAREC #include "codegen.h" #ifdef USE_NEW_DYNAREC #include "codegen_backend.h" #endif #endif + +#ifdef IS_DYNAREC +#undef IS_DYNAREC +#endif + #include "386_common.h" +#if defined(__APPLE__) && defined(__aarch64__) +#include +#endif #define CPU_BLOCK_END() cpu_block_end = 1 int inrecomp = 0, cpu_block_end = 0; -int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; -int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; +int cpu_end_block_after_ins = 0; #ifdef ENABLE_386_DYNAREC_LOG @@ -67,54 +78,54 @@ static __inline void fetch_ea_32_long(uint32_t rmdat) if (cpu_rm == 4) { uint8_t sib = rmdat >> 8; - + switch (cpu_mod) { - case 0: - cpu_state.eaaddr = cpu_state.regs[sib & 7].l; - cpu_state.pc++; - break; - case 1: + case 0: + cpu_state.eaaddr = cpu_state.regs[sib & 7].l; cpu_state.pc++; - cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; break; - case 2: - cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; - cpu_state.pc += 5; + case 1: + cpu_state.pc++; + cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; + break; + case 2: + cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; break; } /*SIB byte present*/ - if ((sib & 7) == 5 && !cpu_mod) + if ((sib & 7) == 5 && !cpu_mod) cpu_state.eaaddr = getlong(); else if ((sib & 6) == 4 && !cpu_state.ssegs) { easeg = ss; cpu_state.ea_seg = &cpu_state.seg_ss; } - if (((sib >> 3) & 7) != 4) + if (((sib >> 3) & 7) != 4) cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); } else { cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; - if (cpu_mod) + if (cpu_mod) { if (cpu_rm == 5 && !cpu_state.ssegs) { easeg = ss; cpu_state.ea_seg = &cpu_state.seg_ss; } - if (cpu_mod == 1) - { - cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); - cpu_state.pc++; - } - else + if (cpu_mod == 1) { - cpu_state.eaaddr += getlong(); + cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + cpu_state.eaaddr += getlong(); } } - else if (cpu_rm == 5) + else if (cpu_rm == 5) { cpu_state.eaaddr = getlong(); } @@ -122,20 +133,19 @@ static __inline void fetch_ea_32_long(uint32_t rmdat) if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; - if ( readlookup2[addr >> 12] != -1) + if ( readlookup2[addr >> 12] != (uintptr_t) -1) eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); - if (writelookup2[addr >> 12] != -1) + if (writelookup2[addr >> 12] != (uintptr_t) -1) eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); } - cpu_state.last_ea = cpu_state.eaaddr; } static __inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - if (!cpu_mod && cpu_rm == 6) - { + if (!cpu_mod && cpu_rm == 6) + { cpu_state.eaaddr = getword(); } else @@ -163,15 +173,14 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; - if ( readlookup2[addr >> 12] != -1) + if (readlookup2[addr >> 12] != (uintptr_t) -1) eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); - if (writelookup2[addr >> 12] != -1) + if (writelookup2[addr >> 12] != (uintptr_t) -1) eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); } - cpu_state.last_ea = cpu_state.eaaddr; } -#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; } +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; } #define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 1 #include "x86_flags.h" @@ -229,23 +238,23 @@ static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int prefetch_bytes -= ((modrm & 0xc0) >> 6); } } - + /* Fill up prefetch queue */ while (prefetch_bytes < 0) { prefetch_bytes += cpu_prefetch_width; cycles -= cpu_prefetch_cycles; } - + /* Subtract cycles used for memory access by instruction */ instr_cycles -= mem_cycles; - + while (instr_cycles >= cpu_prefetch_cycles) { prefetch_bytes += cpu_prefetch_width; instr_cycles -= cpu_prefetch_cycles; } - + prefetch_prefixes = 0; if (prefetch_bytes > 16) prefetch_bytes = 16; @@ -264,587 +273,602 @@ static void prefetch_flush() #define OP_TABLE(name) ops_ ## name +#if 0 +#define CLOCK_CYCLES(c) \ + {\ + if (fpu_cycles > 0) {\ + fpu_cycles -= (c);\ + if (fpu_cycles < 0) {\ + cycles += fpu_cycles;\ + }\ + } else {\ + cycles -= (c);\ + }\ + } +#define CLOCK_CYCLES_FPU(c) cycles -= (c) +#define CONCURRENCY_CYCLES(c) fpu_cycles = (c) +#else #define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_FPU(c) cycles -= (c) +#define CONCURRENCY_CYCLES(c) +#endif #define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + #include "386_ops.h" #define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) #ifdef USE_DYNAREC -static int cycles_main = 0, cycles_old = 0; +int cycles_main = 0; +static int cycles_old = 0; static uint64_t tsc_old = 0; -void update_tsc(void) +#ifdef USE_ACYCS +int acycs = 0; +#endif + + +void +update_tsc(void) { int cycdiff; uint64_t delta; cycdiff = cycles_old - cycles; +#ifdef USE_ACYCS + if (inrecomp) + cycdiff += acycs; +#endif + delta = tsc - tsc_old; if (delta > 0) { /* TSC has changed, this means interim timer processing has happened, see how much we still need to add. */ cycdiff -= delta; - if (cycdiff > 0) - tsc += cycdiff; - } else { - /* TSC has not changed. */ - tsc += cycdiff; } + if (cycdiff > 0) + tsc += cycdiff; + if (cycdiff > 0) { if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) - timer_process(); + timer_process_inline(); } } -void exec386_dynarec(int cycs) + +static __inline void +exec386_dynarec_int(void) { - int vector; - uint32_t addr; - int tempi; - int cycdiff; - int oldcyc; - int oldcyc2; - uint64_t oldtsc, delta; - uint32_t start_pc = 0; + cpu_block_end = 0; + x86_was_reset = 0; - int cyc_period = cycs / 2000; /*5us*/ + while (!cpu_block_end) { +#ifndef USE_NEW_DYNAREC + oldcs = CS; + oldcpl = CPL; +#endif + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; - cycles_main += cycs; - while (cycles_main > 0) - { - int cycles_start; + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; - cycles += cyc_period; - cycles_start = cycles; + fetchdat = fastreadl(cs + cpu_state.pc); +#ifdef ENABLE_386_DYNAREC_LOG + if (in_smm) + x386_dynarec_log("[%04X:%08X] fetchdat = %08X\n", CS, cpu_state.pc, fetchdat); +#endif - while (cycles>0) + if (!cpu_state.abrt) { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + trap = cpu_state.flags & T_FLAG; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + } + +#ifndef USE_NEW_DYNAREC + if (!use32) + cpu_state.pc &= 0xffff; +#endif + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + + if (cpu_end_block_after_ins) { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + if (cpu_state.abrt) + CPU_BLOCK_END(); + if (smi_line) + CPU_BLOCK_END(); + else if (trap) + CPU_BLOCK_END(); + else if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + if (trap) { + trap = 0; +#ifndef USE_NEW_DYNAREC + oldcs = CS; +#endif + cpu_state.oldpc = cpu_state.pc; + x86_int(1); + } + + cpu_end_block_after_ins = 0; +} + + +static __inline void +exec386_dynarec_dyn(void) +{ + uint32_t start_pc = 0, phys_addr = get_phys(cs + cpu_state.pc); + int hash = HASH(phys_addr); +#ifdef USE_NEW_DYNAREC + codeblock_t *block = &codeblock[codeblock_hash[hash]]; +#else + codeblock_t *block = codeblock_hash[hash]; +#endif + int valid_block = 0; + +#ifdef USE_NEW_DYNAREC + if (!cpu_state.abrt) +#else + if (block && !cpu_state.abrt) +#endif + { + page_t *page = &pages[phys_addr >> 12]; + + /* Block must match current CS, PC, code segment size, + and physical address. The physical address check will + also catch any page faults at this stage */ + valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && + (block->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (!valid_block) { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); +#ifdef USE_NEW_DYNAREC + int byte_offset = (phys_addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = 1ull << (PAGE_BYTE_MASK_MASK & 0x3f); + + if ((page->code_present_mask & mask) || (page->byte_code_present_mask[byte_offset] & byte_mask)) +#else + if (page->code_present_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] & mask) +#endif { + /* Walk page tree to see if we find the correct block */ + codeblock_t *new_block = codeblock_tree_find(phys_addr, cs); + if (new_block) { + valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && + (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (valid_block) { + block = new_block; +#ifdef USE_NEW_DYNAREC + codeblock_hash[hash] = get_block_nr(block); +#endif + } + } + } + } + + if (valid_block && (block->page_mask & *block->dirty_mask)) { +#ifdef USE_NEW_DYNAREC + codegen_check_flush(page, page->dirty_mask, phys_addr); + if (block->pc == BLOCK_PC_INVALID) + valid_block = 0; + else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; +#else + codegen_check_flush(page, page->dirty_mask[(phys_addr >> 10) & 3], phys_addr); + page->dirty_mask[(phys_addr >> 10) & 3] = 0; + if (!block->valid) + valid_block = 0; +#endif + } + if (valid_block && block->page_mask2) { + /* We don't want the second page to cause a page + fault at this stage - that would break any + code crossing a page boundary where the first + page is present but the second isn't. Instead + allow the first page to be interpreted and for + the page fault to occur when the page boundary + is actually crossed.*/ +#ifdef USE_NEW_DYNAREC + uint32_t phys_addr_2 = get_phys_noabrt(block->pc + ((block->flags & CODEBLOCK_BYTE_MASK) ? 0x40 : 0x400)); +#else + uint32_t phys_addr_2 = get_phys_noabrt(block->endpc); +#endif + page_t *page_2 = &pages[phys_addr_2 >> 12]; + + if ((block->phys_2 ^ phys_addr_2) & ~0xfff) + valid_block = 0; + else if (block->page_mask2 & *block->dirty_mask2) { +#ifdef USE_NEW_DYNAREC + codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); + if (block->pc == BLOCK_PC_INVALID) + valid_block = 0; + else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; +#else + codegen_check_flush(page_2, page_2->dirty_mask[(phys_addr_2 >> 10) & 3], phys_addr_2); + page_2->dirty_mask[(phys_addr_2 >> 10) & 3] = 0; + if (!block->valid) + valid_block = 0; +#endif + } + } +#ifdef USE_NEW_DYNAREC + if (valid_block && (block->flags & CODEBLOCK_IN_DIRTY_LIST)) { + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + if (block->flags & CODEBLOCK_BYTE_MASK) + block->flags |= CODEBLOCK_NO_IMMEDIATES; + else + block->flags |= CODEBLOCK_BYTE_MASK; + } + if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED) && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != (cpu_state.TOP & 7)) +#else + if (valid_block && block->was_recompiled && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != cpu_state.TOP) +#endif + { + /* FPU top-of-stack does not match the value this block was compiled + with, re-compile using dynamic top-of-stack*/ +#ifdef USE_NEW_DYNAREC + block->flags &= ~(CODEBLOCK_STATIC_TOP | CODEBLOCK_WAS_RECOMPILED); +#else + block->flags &= ~CODEBLOCK_STATIC_TOP; + block->was_recompiled = 0; +#endif + } + } + +#ifdef USE_NEW_DYNAREC + if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED)) +#else + if (valid_block && block->was_recompiled) +#endif + { + void (*code)() = (void *)&block->data[BLOCK_START]; + +#ifndef USE_NEW_DYNAREC + codeblock_hash[hash] = block; +#endif + inrecomp = 1; + code(); +#ifdef USE_ACYCS + acycs = 0; +#endif + inrecomp = 0; + +#ifndef USE_NEW_DYNAREC + if (!use32) cpu_state.pc &= 0xffff; +#endif + } else if (valid_block && !cpu_state.abrt) { +#ifdef USE_NEW_DYNAREC + start_pc = cs + cpu_state.pc; + const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; +#else + start_pc = cpu_state.pc; +#endif + + cpu_block_end = 0; + x86_was_reset = 0; + +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(0); +#endif + codegen_block_start_recompile(block); + codegen_in_recompile = 1; + + while (!cpu_block_end) { +#ifndef USE_NEW_DYNAREC + oldcs = CS; + oldcpl = CPL; +#endif + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); +#ifdef ENABLE_386_DYNAREC_LOG + if (in_smm) + x386_dynarec_log("[%04X:%08X] fetchdat = %08X\n", CS, cpu_state.pc, fetchdat); +#endif + + if (!cpu_state.abrt) { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + cpu_state.pc++; + + codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + +#ifndef USE_NEW_DYNAREC + if (!use32) + cpu_state.pc &= 0xffff; +#endif + + /* Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ +#ifdef USE_NEW_DYNAREC + if (((cs + cpu_state.pc) - start_pc) >= max_block_size) +#else + if ((cpu_state.pc - start_pc) > 1000) +#endif + CPU_BLOCK_END(); + + if (cpu_state.flags & T_FLAG) + CPU_BLOCK_END(); + if (smi_line) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) + CPU_BLOCK_END(); + + if (cpu_end_block_after_ins) { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + if (cpu_state.abrt) { + if (!(cpu_state.abrt & ABRT_EXPECTED)) + codegen_block_remove(); + CPU_BLOCK_END(); + } + } + + cpu_end_block_after_ins = 0; + + if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset) + codegen_block_end_recompile(block); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(1); +#endif + } else if (!cpu_state.abrt) { + /* Mark block but do not recompile */ +#ifdef USE_NEW_DYNAREC + start_pc = cs + cpu_state.pc; + const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; +#else + start_pc = cpu_state.pc; +#endif + + cpu_block_end = 0; + x86_was_reset = 0; + + codegen_block_init(phys_addr); + + while (!cpu_block_end) { +#ifndef USE_NEW_DYNAREC + oldcs = CS; + oldcpl = CPL; +#endif + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + codegen_endpc = (cs + cpu_state.pc) + 8; + fetchdat = fastreadl(cs + cpu_state.pc); + +#ifdef ENABLE_386_DYNAREC_LOG + if (in_smm) + x386_dynarec_log("[%04X:%08X] fetchdat = %08X\n", CS, cpu_state.pc, fetchdat); +#endif + + if (!cpu_state.abrt) { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + cpu_state.pc++; + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + +#ifndef USE_NEW_DYNAREC + if (!use32) + cpu_state.pc &= 0xffff; +#endif + + /* Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB */ +#ifdef USE_NEW_DYNAREC + if (((cs + cpu_state.pc) - start_pc) >= max_block_size) +#else + if ((cpu_state.pc - start_pc) > 1000) +#endif + CPU_BLOCK_END(); + + if (cpu_state.flags & T_FLAG) + CPU_BLOCK_END(); + if (smi_line) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) + CPU_BLOCK_END(); + + if (cpu_end_block_after_ins) { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + if (cpu_state.abrt) { + if (!(cpu_state.abrt & ABRT_EXPECTED)) + codegen_block_remove(); + CPU_BLOCK_END(); + } + } + + cpu_end_block_after_ins = 0; + + if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + } +#ifdef USE_NEW_DYNAREC + else + cpu_state.oldpc = cpu_state.pc; +#endif +} + + +void +exec386_dynarec(int cycs) +{ + int vector, tempi; + int cycdiff; + int oldcyc, oldcyc2; + uint64_t oldtsc, delta; + + int cyc_period = cycs / 2000; /*5us*/ + +#ifdef USE_ACYCS + acycs = 0; +#endif + cycles_main += cycs; + while (cycles_main > 0) { + int cycles_start; + + cycles += cyc_period; + cycles_start = cycles; + + while (cycles > 0) { +#ifndef USE_NEW_DYNAREC + oldcs = CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl = CPL; + cpu_state.op32 = use32; + + cycdiff = 0; +#endif + oldcyc = oldcyc2 = cycles; + cycles_old = cycles; + oldtsc = tsc; + tsc_old = tsc; + if (!CACHE_ON()) /*Interpret block*/ + { + exec386_dynarec_int(); + } + else + { + exec386_dynarec_dyn(); + } + + if (cpu_state.abrt) { + flags_rebuild(); + tempi = cpu_state.abrt & ABRT_MASK; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) { + cpu_state.abrt = 0; + cpu_state.pc = cpu_state.oldpc; +#ifndef USE_NEW_DYNAREC + CS = oldcs; +#endif + pmodeint(8, 0); + if (cpu_state.abrt) { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); +#ifdef ENABLE_386_DYNAREC_LOG + x386_dynarec_log("Triple fault - reset\n"); +#endif + } + } + } + + if (smi_line) + enter_smm_check(0); + else if (nmi && nmi_enable && nmi_mask) { #ifndef USE_NEW_DYNAREC oldcs = CS; +#endif cpu_state.oldpc = cpu_state.pc; - oldcpl = CPL; - cpu_state.op32 = use32; - - cycdiff=0; -#endif - oldcyc = oldcyc2 = cycles; - cycles_old = cycles; - oldtsc = tsc; - tsc_old = tsc; - if (!CACHE_ON()) /*Interpret block*/ - { - cpu_block_end = 0; - x86_was_reset = 0; - while (!cpu_block_end) - { -#ifndef USE_NEW_DYNAREC - oldcs = CS; - oldcpl = CPL; -#endif - cpu_state.oldpc = cpu_state.pc; - cpu_state.op32 = use32; - - cpu_state.ea_seg = &cpu_state.seg_ds; - cpu_state.ssegs = 0; - - fetchdat = fastreadl(cs + cpu_state.pc); -#ifdef ENABLE_386_DYNAREC_LOG - if (in_smm) - x386_dynarec_log("[%04X:%08X] fetchdat = %08X\n", CS, cpu_state.pc, fetchdat); -#endif - - if (!cpu_state.abrt) - { - opcode = fetchdat & 0xFF; - fetchdat >>= 8; - - trap = cpu_state.flags & T_FLAG; - - cpu_state.pc++; - x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); - } - -#ifndef USE_NEW_DYNAREC - if (!use32) cpu_state.pc &= 0xffff; -#endif - - if (((cs + cpu_state.pc) >> 12) != pccache) - CPU_BLOCK_END(); - - if (cpu_state.abrt) - CPU_BLOCK_END(); - if (trap) - CPU_BLOCK_END(); - else if (smi_line) - CPU_BLOCK_END(); - else if (nmi && nmi_enable && nmi_mask) - CPU_BLOCK_END(); - else if ((cpu_state.flags & I_FLAG) && pic_intpending) - CPU_BLOCK_END(); - - ins++; - } + x86_int(2); + nmi_enable = 0; +#ifdef OLD_NMI_BEHAVIOR + if (nmi_auto_clear) { + nmi_auto_clear = 0; + nmi = 0; } - else - { - uint32_t phys_addr = get_phys(cs+cpu_state.pc); - int hash = HASH(phys_addr); -#ifdef USE_NEW_DYNAREC - codeblock_t *block = &codeblock[codeblock_hash[hash]]; #else - codeblock_t *block = codeblock_hash[hash]; + nmi = 0; #endif - int valid_block = 0; -#ifdef USE_NEW_DYNAREC - - if (!cpu_state.abrt) -#else - trap = 0; - - if (block && !cpu_state.abrt) -#endif - { - page_t *page = &pages[phys_addr >> 12]; - - /*Block must match current CS, PC, code segment size, - and physical address. The physical address check will - also catch any page faults at this stage*/ - valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && - (block->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && - ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); - if (!valid_block) - { - uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); -#ifdef USE_NEW_DYNAREC - int byte_offset = (phys_addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; - uint64_t byte_mask = 1ull << (PAGE_BYTE_MASK_MASK & 0x3f); - - if ((page->code_present_mask & mask) || (page->byte_code_present_mask[byte_offset] & byte_mask)) -#else - if (page->code_present_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] & mask) -#endif - { - /*Walk page tree to see if we find the correct block*/ - codeblock_t *new_block = codeblock_tree_find(phys_addr, cs); - if (new_block) - { - valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && - (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && - ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); - if (valid_block) - { - block = new_block; -#ifdef USE_NEW_DYNAREC - codeblock_hash[hash] = get_block_nr(block); -#endif - } - } - } - } - - if (valid_block && (block->page_mask & *block->dirty_mask)) - { -#ifdef USE_NEW_DYNAREC - codegen_check_flush(page, page->dirty_mask, phys_addr); - if (block->pc == BLOCK_PC_INVALID) - valid_block = 0; - else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) - block->flags &= ~CODEBLOCK_WAS_RECOMPILED; -#else - codegen_check_flush(page, page->dirty_mask[(phys_addr >> 10) & 3], phys_addr); - page->dirty_mask[(phys_addr >> 10) & 3] = 0; - if (!block->valid) - valid_block = 0; -#endif - } - if (valid_block && block->page_mask2) - { - /*We don't want the second page to cause a page - fault at this stage - that would break any - code crossing a page boundary where the first - page is present but the second isn't. Instead - allow the first page to be interpreted and for - the page fault to occur when the page boundary - is actually crossed.*/ -#ifdef USE_NEW_DYNAREC - uint32_t phys_addr_2 = get_phys_noabrt(block->pc + ((block->flags & CODEBLOCK_BYTE_MASK) ? 0x40 : 0x400)); -#else - uint32_t phys_addr_2 = get_phys_noabrt(block->endpc); -#endif - page_t *page_2 = &pages[phys_addr_2 >> 12]; - - if ((block->phys_2 ^ phys_addr_2) & ~0xfff) - valid_block = 0; - else if (block->page_mask2 & *block->dirty_mask2) - { -#ifdef USE_NEW_DYNAREC - codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); - if (block->pc == BLOCK_PC_INVALID) - valid_block = 0; - else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) - block->flags &= ~CODEBLOCK_WAS_RECOMPILED; -#else - codegen_check_flush(page_2, page_2->dirty_mask[(phys_addr_2 >> 10) & 3], phys_addr_2); - page_2->dirty_mask[(phys_addr_2 >> 10) & 3] = 0; - if (!block->valid) - valid_block = 0; -#endif - } - } -#ifdef USE_NEW_DYNAREC - if (valid_block && (block->flags & CODEBLOCK_IN_DIRTY_LIST)) - { - block->flags &= ~CODEBLOCK_WAS_RECOMPILED; - if (block->flags & CODEBLOCK_BYTE_MASK) - block->flags |= CODEBLOCK_NO_IMMEDIATES; - else - block->flags |= CODEBLOCK_BYTE_MASK; - } - if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED) && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != (cpu_state.TOP & 7)) -#else - if (valid_block && block->was_recompiled && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != cpu_state.TOP) -#endif - { - /*FPU top-of-stack does not match the value this block was compiled - with, re-compile using dynamic top-of-stack*/ -#ifdef USE_NEW_DYNAREC - block->flags &= ~(CODEBLOCK_STATIC_TOP | CODEBLOCK_WAS_RECOMPILED); -#else - block->flags &= ~CODEBLOCK_STATIC_TOP; - block->was_recompiled = 0; -#endif - } - } - -#ifdef USE_NEW_DYNAREC - if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED)) -#else - if (valid_block && block->was_recompiled) -#endif - { - void (*code)() = (void *)&block->data[BLOCK_START]; - -#ifndef USE_NEW_DYNAREC - codeblock_hash[hash] = block; -#endif - - inrecomp=1; - code(); - inrecomp=0; - -#ifndef USE_NEW_DYNAREC - if (!use32) cpu_state.pc &= 0xffff; -#endif - cpu_recomp_blocks++; - } - else if (valid_block && !cpu_state.abrt) - { -#ifdef USE_NEW_DYNAREC - start_pc = cs+cpu_state.pc; - const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; -#else - start_pc = cpu_state.pc; -#endif - - cpu_block_end = 0; - x86_was_reset = 0; - - cpu_new_blocks++; - - codegen_block_start_recompile(block); - codegen_in_recompile = 1; - - while (!cpu_block_end) - { -#ifndef USE_NEW_DYNAREC - oldcs = CS; - oldcpl = CPL; -#endif - cpu_state.oldpc = cpu_state.pc; - cpu_state.op32 = use32; - - cpu_state.ea_seg = &cpu_state.seg_ds; - cpu_state.ssegs = 0; - - fetchdat = fastreadl(cs + cpu_state.pc); -#ifdef ENABLE_386_DYNAREC_LOG - if (in_smm) - x386_dynarec_log("[%04X:%08X] fetchdat = %08X\n", CS, cpu_state.pc, fetchdat); -#endif - - if (!cpu_state.abrt) - { - opcode = fetchdat & 0xFF; - fetchdat >>= 8; - - trap = cpu_state.flags & T_FLAG; - - cpu_state.pc++; - - codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); - - x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); - - if (x86_was_reset) - break; - } - -#ifndef USE_NEW_DYNAREC - if (!use32) cpu_state.pc &= 0xffff; -#endif - - /*Cap source code at 4000 bytes per block; this - will prevent any block from spanning more than - 2 pages. In practice this limit will never be - hit, as host block size is only 2kB*/ -#ifdef USE_NEW_DYNAREC - if (((cs+cpu_state.pc) - start_pc) >= max_block_size) -#else - if ((cpu_state.pc - start_pc) > 1000) -#endif - CPU_BLOCK_END(); - - if (cpu_state.abrt) - { - codegen_block_remove(); - CPU_BLOCK_END(); - } - - if (trap) - CPU_BLOCK_END(); - else if (smi_line) - CPU_BLOCK_END(); - else if (nmi && nmi_enable && nmi_mask) - CPU_BLOCK_END(); - else if ((cpu_state.flags & I_FLAG) && pic_intpending) - CPU_BLOCK_END(); - ins++; - } - - if (!cpu_state.abrt && !x86_was_reset) - codegen_block_end_recompile(block); - - if (x86_was_reset) - codegen_reset(); - - codegen_in_recompile = 0; - } - else if (!cpu_state.abrt) - { - /*Mark block but do not recompile*/ -#ifdef USE_NEW_DYNAREC - start_pc = cs+cpu_state.pc; - const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; -#else - start_pc = cpu_state.pc; -#endif - - cpu_block_end = 0; - x86_was_reset = 0; - - codegen_block_init(phys_addr); - - while (!cpu_block_end) - { -#ifndef USE_NEW_DYNAREC - oldcs=CS; - oldcpl = CPL; -#endif - cpu_state.oldpc = cpu_state.pc; - cpu_state.op32 = use32; - - cpu_state.ea_seg = &cpu_state.seg_ds; - cpu_state.ssegs = 0; - - codegen_endpc = (cs + cpu_state.pc) + 8; - - fetchdat = fastreadl(cs + cpu_state.pc); -#ifdef ENABLE_386_DYNAREC_LOG - if (in_smm) - x386_dynarec_log("[%04X:%08X] fetchdat = %08X\n", CS, cpu_state.pc, fetchdat); -#endif - - if (!cpu_state.abrt) - { - opcode = fetchdat & 0xFF; - fetchdat >>= 8; - - trap = cpu_state.flags & T_FLAG; - - cpu_state.pc++; - - x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); - - if (x86_was_reset) - break; - } - -#ifndef USE_NEW_DYNAREC - if (!use32) cpu_state.pc &= 0xffff; -#endif - - /*Cap source code at 4000 bytes per block; this - will prevent any block from spanning more than - 2 pages. In practice this limit will never be - hit, as host block size is only 2kB*/ -#ifdef USE_NEW_DYNAREC - if (((cs+cpu_state.pc) - start_pc) >= max_block_size) -#else - if ((cpu_state.pc - start_pc) > 1000) -#endif - CPU_BLOCK_END(); - - if (cpu_state.abrt) - { - codegen_block_remove(); - CPU_BLOCK_END(); - } - - if (trap) - CPU_BLOCK_END(); - else if (smi_line) - CPU_BLOCK_END(); - else if (nmi && nmi_enable && nmi_mask) - CPU_BLOCK_END(); - else if ((cpu_state.flags & I_FLAG) && pic_intpending) - CPU_BLOCK_END(); - - ins++; - } - - if (!cpu_state.abrt && !x86_was_reset) - codegen_block_end(); - - if (x86_was_reset) - codegen_reset(); - } -#ifdef USE_NEW_DYNAREC - else - cpu_state.oldpc = cpu_state.pc; -#endif - } - - cycdiff = oldcyc - cycles; - delta = tsc - oldtsc; - if (delta > 0) { - /* TSC has changed, this means interim timer processing has happened, - see how much we still need to add. */ - cycdiff -= delta; - if (cycdiff > 0) - tsc += cycdiff; - } else { - /* TSC has not changed. */ - tsc += cycdiff; - } - - if (cpu_state.abrt) - { - flags_rebuild(); - tempi = cpu_state.abrt; - cpu_state.abrt = 0; - x86_doabrt(tempi); - if (cpu_state.abrt) - { - cpu_state.abrt = 0; - cpu_state.pc = cpu_state.oldpc; -#ifndef USE_NEW_DYNAREC - CS = oldcs; -#endif - pmodeint(8, 0); - if (cpu_state.abrt) - { - cpu_state.abrt = 0; - softresetx86(); - cpu_set_edx(); -#ifdef ENABLE_386_DYNAREC_LOG - x386_dynarec_log("Triple fault - reset\n"); -#endif - } - } - } - - if (smi_line) - enter_smm_check(0); - else if (trap) - { -#ifdef USE_NEW_DYNAREC - trap = 0; -#endif - flags_rebuild(); - if (msw&1) - { - pmodeint(1,0); - } - else - { - writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - addr = (1 << 2) + idt.base; - cpu_state.flags &= ~I_FLAG; - cpu_state.flags &= ~T_FLAG; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - } - } - else if (nmi && nmi_enable && nmi_mask) - { - if (AT && (cpu_fast_off_flags & 0x20000000)) - cpu_fast_off_count = cpu_fast_off_val + 1; - - CPU_BLOCK_END(); + } else if ((cpu_state.flags & I_FLAG) && pic.int_pending) { + vector = picinterrupt(); + if (vector != -1) { #ifndef USE_NEW_DYNAREC oldcs = CS; #endif cpu_state.oldpc = cpu_state.pc; - x86_int(2); - nmi_enable = 0; - if (nmi_auto_clear) - { - nmi_auto_clear = 0; - nmi = 0; - } - } - else if ((cpu_state.flags & I_FLAG) && pic_intpending) - { - vector = picinterrupt(); - if (vector != -1) - { - flags_rebuild(); - if (msw&1) - { - pmodeint(vector,0); - } - else - { - writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - addr=vector<<2; - cpu_state.flags &= ~I_FLAG; - cpu_state.flags &= ~T_FLAG; -#ifndef USE_NEW_DYNAREC - oxpc=cpu_state.pc; -#endif - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - } - } - } - - if (cycdiff > 0) { - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) - timer_process(); + x86_int(vector); } } - cycles_main -= (cycles_start - cycles); + cycdiff = oldcyc - cycles; + delta = tsc - oldtsc; + if (delta > 0) { + /* TSC has changed, this means interim timer processing has happened, + see how much we still need to add. */ + cycdiff -= delta; + if (cycdiff > 0) + tsc += cycdiff; + } else { + /* TSC has not changed. */ + tsc += cycdiff; + } + + if (cycdiff > 0) { + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + timer_process_inline(); + } + +#ifdef USE_GDBSTUB + if (gdbstub_instruction()) + return; +#endif } + + cycles_main -= (cycles_start - cycles); + } } #endif diff --git a/src/cpu/386_dynarec_ops.c b/src/cpu/386_dynarec_ops.c index 9965efdff..0b02676f8 100644 --- a/src/cpu/386_dynarec_ops.c +++ b/src/cpu/386_dynarec_ops.c @@ -19,10 +19,15 @@ #include <86box/mem.h> #include <86box/nmi.h> #include <86box/pic.h> +#include <86box/gdbstub.h> #include "codegen.h" #define CPU_BLOCK_END() cpu_block_end = 1 +#ifndef IS_DYNAREC +#define IS_DYNAREC +#endif + #include "386_common.h" @@ -33,12 +38,11 @@ static __inline void fetch_ea_32_long(uint32_t rmdat) if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; - if ( readlookup2[addr >> 12] != -1) + if ( readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); - if (writelookup2[addr >> 12] != -1) + if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); } - cpu_state.last_ea = cpu_state.eaaddr; } static __inline void fetch_ea_16_long(uint32_t rmdat) @@ -48,12 +52,11 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; - if ( readlookup2[addr >> 12] != -1) + if ( readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); - if (writelookup2[addr >> 12] != -1) + if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); } - cpu_state.last_ea = cpu_state.eaaddr; } #define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat); @@ -67,6 +70,13 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) #define OP_TABLE(name) dynarec_ops_ ## name #define CLOCK_CYCLES(c) +#if 0 +#define CLOCK_CYCLES_FPU(c) +#define CONCURRENCY_CYCLES(c) fpu_cycles = (c) +#else +#define CLOCK_CYCLES_FPU(c) +#define CONCURRENCY_CYCLES(c) +#endif #define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) #include "386_ops.h" diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 674186337..790216cb9 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -58,13 +58,11 @@ static __inline void PUSH_W(uint16_t val) { writememw(ss, ESP - 2, val); if (cpu_state.abrt) return; ESP -= 2; - cpu_state.last_ea = ESP; } else { writememw(ss, (SP - 2) & 0xFFFF, val); if (cpu_state.abrt) return; SP -= 2; - cpu_state.last_ea = SP; } } @@ -74,13 +72,11 @@ static __inline void PUSH_L(uint32_t val) { writememl(ss, ESP - 4, val); if (cpu_state.abrt) return; ESP -= 4; - cpu_state.last_ea = ESP; } else { writememl(ss, (SP - 4) & 0xFFFF, val); if (cpu_state.abrt) return; SP -= 4; - cpu_state.last_ea = SP; } } @@ -91,13 +87,11 @@ static __inline uint16_t POP_W() { ret = readmemw(ss, ESP); if (cpu_state.abrt) return 0; ESP += 2; - cpu_state.last_ea = ESP; } else { ret = readmemw(ss, SP); if (cpu_state.abrt) return 0; SP += 2; - cpu_state.last_ea = SP; } return ret; } @@ -109,13 +103,11 @@ static __inline uint32_t POP_L() { ret = readmeml(ss, ESP); if (cpu_state.abrt) return 0; ESP += 4; - cpu_state.last_ea = ESP; } else { ret = readmeml(ss, SP); if (cpu_state.abrt) return 0; SP += 4; - cpu_state.last_ea = SP; } return ret; } @@ -127,13 +119,11 @@ static __inline uint16_t POP_W_seg(uint32_t seg) { ret = readmemw(seg, ESP); if (cpu_state.abrt) return 0; ESP += 2; - cpu_state.last_ea = ESP; } else { ret = readmemw(seg, SP); if (cpu_state.abrt) return 0; SP += 2; - cpu_state.last_ea = SP; } return ret; } @@ -145,13 +135,11 @@ static __inline uint32_t POP_L_seg(uint32_t seg) { ret = readmeml(seg, ESP); if (cpu_state.abrt) return 0; ESP += 4; - cpu_state.last_ea = ESP; } else { ret = readmeml(seg, SP); if (cpu_state.abrt) return 0; SP += 4; - cpu_state.last_ea = SP; } return ret; } @@ -160,9 +148,9 @@ static int fopcode; static int ILLEGAL(uint32_t fetchdat) { + pclog("[%04X:%08X] Illegal instruction %08X (%02X)\n", CS, cpu_state.pc, fetchdat, fopcode); cpu_state.pc = cpu_state.oldpc; - pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); x86illegal(); return 0; } @@ -182,6 +170,7 @@ extern void x386_dynarec_log(const char *fmt, ...); #include "x86_ops_bcd.h" #include "x86_ops_bit.h" #include "x86_ops_bitscan.h" +#include "x86_ops_cyrix.h" #include "x86_ops_flag.h" #include "x86_ops_fpu.h" #include "x86_ops_inc_dec.h" @@ -206,7 +195,11 @@ extern void x386_dynarec_log(const char *fmt, ...); #include "x86_ops_mul.h" #include "x86_ops_pmode.h" #include "x86_ops_prefix.h" +#ifdef IS_DYNAREC +#include "x86_ops_rep_dyn.h" +#else #include "x86_ops_rep.h" +#endif #include "x86_ops_ret.h" #include "x86_ops_set.h" #include "x86_ops_stack.h" @@ -216,6 +209,118 @@ extern void x386_dynarec_log(const char *fmt, ...); #include "x86_ops_shift.h" #include "x86_ops_amd.h" #include "x86_ops_3dnow.h" +#include + + +static int opVPCEXT(uint32_t fetchdat) +{ + uint8_t b1, b2; + uint16_t cent; + time_t now; + struct tm *tm; + + if (!is_vpc) /* only emulate this on Virtual PC machines */ + return ILLEGAL(fetchdat); + + cpu_state.pc += 2; + + b1 = fetchdat & 0xff; + b2 = (fetchdat >> 8) & 0xff; + + /* a lot of these opcodes (which?) return illegal instruction in user mode */ + ILLEGAL_ON(CPL > 0); + + CLOCK_CYCLES(1); + + /* 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); + } + + if ((b1 == 0x07) && (b2 == 0x0b)) { + /* 0f 3f 07 0b: unknown, EDX output depends on EAX input */ + switch (EAX) { + case 0x00000000: + EDX = 0x00000003; + break; + + case 0x00000001: + EDX = 0x00000012; + break; + + case 0x00000002: + case 0x00000003: + case 0x00000004: + case 0x00000005: + EDX = 0x00000001; + break; + + case 0x00000007: + EDX = 0x0000009c; + break; + + default: + EDX = 0x00000000; + if (EAX > 0x00000012) /* unknown EAX values set zero flag */ + cpu_state.flags &= ~(Z_FLAG); + } + } else if ((b1 == 0x03) && (b2 == 0x00)) { + /* 0f 3f 03 00: host time in BCD */ + EDX = BCD8(tm->tm_hour); + ECX = BCD8(tm->tm_min); + EAX = BCD8(tm->tm_sec); + } else if ((b1 == 0x03) && (b2 == 0x01)) { + /* 0f 3f 03 00: host date in BCD */ + EDX = BCD8(tm->tm_year % 100); + ECX = BCD8(tm->tm_mon + 1); + EAX = BCD8(tm->tm_mday); + cent = (((tm->tm_year - (tm->tm_year % 100)) / 100) % 4); /* Sunday = 0 */ + EBX = ((tm->tm_mday + tm->tm_mon + (tm->tm_year % 100) + cent + 3) % 7); + } else if ((b1 == 0x03) && (b2 == 0x03)) { + /* 0f 3f 03 03: host time in binary */ + EDX = tm->tm_hour; + ECX = tm->tm_min; + EAX = tm->tm_sec; + } else if ((b1 == 0x03) && (b2 == 0x04)) { + /* 0f 3f 03 04: host date in binary */ + EDX = 1900 + tm->tm_year; + ECX = tm->tm_mon + 1; + EBX = tm->tm_mday; + } else if ((b1 == 0x03) && (b2 == 0x05)) { + /* 0f 3f 03 05: unknown */ + EBX = 0x0000000F; + ECX = 0x0000000A; + } else if ((b1 == 0x03) && (b2 == 0x06)) { + /* 0f 3f 03 06: some kind of timestamp. BX jumps around very quickly, CX not so much. */ + EBX = 0x00000000; + ECX = 0x00000000; + } else if ((b1 == 0x03) && (b2 >= 0x07)) { + /* 0f 3f 03 07+: set zero flag */ + cpu_state.flags &= ~(Z_FLAG); + } else if ((b1 == 0x0a) && (b2 == 0x00)) { + /* 0f 3f 0a 00: memory size in KB */ + EAX = mem_size; + } else if ((b1 == 0x11) && (b2 == 0x00)) { + /* 0f 3f 11 00: unknown, set EAX to 0 */ + EAX = 0x00000000; + } else if ((b1 == 0x11) && (b2 == 0x01)) { + /* 0f 3f 11 00: unknown, set EAX to 0 and set zero flag */ + EAX = 0x00000000; + cpu_state.flags &= ~(Z_FLAG); + } else if ((b1 == 0x11) && (b2 == 0x02)) { + /* 0f 3f 11 02: unknown, no-op */ + } else { + /* other unknown opcodes: illegal instruction */ + cpu_state.pc = cpu_state.oldpc; + + pclog("Illegal VPCEXT %08X (%02X %02X)\n", fetchdat, b1, b2); + x86illegal(); + return 0; + } + + return 1; +} static int op0F_w_a16(uint32_t fetchdat) @@ -233,7 +338,7 @@ static int op0F_l_a16(uint32_t fetchdat) int opcode = fetchdat & 0xff; fopcode = opcode; cpu_state.pc++; - + PREFETCH_PREFIX(); return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); @@ -243,7 +348,7 @@ static int op0F_w_a32(uint32_t fetchdat) int opcode = fetchdat & 0xff; fopcode = opcode; cpu_state.pc++; - + PREFETCH_PREFIX(); return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); @@ -253,17 +358,17 @@ static int op0F_l_a32(uint32_t fetchdat) int opcode = fetchdat & 0xff; fopcode = opcode; cpu_state.pc++; - + PREFETCH_PREFIX(); return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); } -const OpFn OP_TABLE(286_0f)[1024] = +const OpFn OP_TABLE(286_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -285,7 +390,7 @@ const OpFn OP_TABLE(286_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -307,7 +412,7 @@ const OpFn OP_TABLE(286_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -329,7 +434,7 @@ const OpFn OP_TABLE(286_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -351,12 +456,12 @@ const OpFn OP_TABLE(286_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; -const OpFn OP_TABLE(386_0f)[1024] = +const OpFn OP_TABLE(386_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -376,9 +481,9 @@ const OpFn OP_TABLE(386_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -398,9 +503,9 @@ const OpFn OP_TABLE(386_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -420,9 +525,9 @@ const OpFn OP_TABLE(386_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -442,12 +547,12 @@ const OpFn OP_TABLE(386_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; -const OpFn OP_TABLE(486_0f)[1024] = +const OpFn OP_TABLE(486_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -467,9 +572,9 @@ const OpFn OP_TABLE(486_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -489,9 +594,9 @@ const OpFn OP_TABLE(486_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -511,9 +616,9 @@ const OpFn OP_TABLE(486_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -533,10 +638,283 @@ const OpFn OP_TABLE(486_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; -const OpFn OP_TABLE(winchip_0f)[1024] = +const OpFn OP_TABLE(c486_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(stpc_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(ibm486_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, ILLEGAL, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(winchip_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -558,7 +936,7 @@ const OpFn OP_TABLE(winchip_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -580,7 +958,7 @@ const OpFn OP_TABLE(winchip_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -602,7 +980,7 @@ const OpFn OP_TABLE(winchip_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -715,12 +1093,12 @@ const OpFn OP_TABLE(winchip2_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; -const OpFn OP_TABLE(pentium_0f)[1024] = +const OpFn OP_TABLE(pentium_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -740,9 +1118,9 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -762,9 +1140,9 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -784,9 +1162,9 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -806,10 +1184,103 @@ const OpFn OP_TABLE(pentium_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; -const OpFn OP_TABLE(pentiummmx_0f)[1024] = +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +const OpFn OP_TABLE(c6x86_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +#endif + +const OpFn OP_TABLE(pentiummmx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -831,7 +1302,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -853,7 +1324,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -875,7 +1346,7 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -897,10 +1368,10 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; -const OpFn OP_TABLE(k6_0f)[1024] = +const OpFn OP_TABLE(k6_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -922,7 +1393,7 @@ const OpFn OP_TABLE(k6_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -944,7 +1415,7 @@ const OpFn OP_TABLE(k6_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -966,7 +1437,7 @@ const OpFn OP_TABLE(k6_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -988,10 +1459,10 @@ const OpFn OP_TABLE(k6_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; -const OpFn OP_TABLE(k62_0f)[1024] = +const OpFn OP_TABLE(k62_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a16, opFEMMS, op3DNOW_a16, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1013,7 +1484,7 @@ const OpFn OP_TABLE(k62_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a16, opFEMMS, op3DNOW_a16, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1035,7 +1506,7 @@ const OpFn OP_TABLE(k62_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a32, opFEMMS, op3DNOW_a32, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1057,7 +1528,7 @@ const OpFn OP_TABLE(k62_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a32, opFEMMS, op3DNOW_a32, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1080,19 +1551,19 @@ const OpFn OP_TABLE(k62_0f)[1024] = }; #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) -const OpFn OP_TABLE(c6x86mx_0f)[1024] = +const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a16_cx,opMOVQ_mm_q_a16, /*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, /*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, @@ -1105,16 +1576,16 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a16_cx,opMOVQ_mm_q_a16, /*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, /*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, @@ -1127,16 +1598,16 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opMOVD_mm_l_a32_cx,opMOVQ_mm_q_a32, /*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, /*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, @@ -1149,16 +1620,16 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a32_cx,opMOVQ_mm_q_a32, /*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, /*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, @@ -1172,10 +1643,10 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = }; #endif -const OpFn OP_TABLE(pentiumpro_0f)[1024] = +const OpFn OP_TABLE(pentiumpro_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1197,7 +1668,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1219,7 +1690,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1241,7 +1712,7 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1263,10 +1734,10 @@ const OpFn OP_TABLE(pentiumpro_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; -const OpFn OP_TABLE(pentium2_0f)[1024] = +const OpFn OP_TABLE(pentium2_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1288,7 +1759,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1310,7 +1781,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1332,7 +1803,7 @@ const OpFn OP_TABLE(pentium2_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1354,14 +1825,14 @@ const OpFn OP_TABLE(pentium2_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; -const OpFn OP_TABLE(pentium2d_0f)[1024] = +const OpFn OP_TABLE(pentium2d_0f)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opVPCEXT, /*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1379,11 +1850,11 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, opHINT_NOP_a16, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opVPCEXT, /*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1401,11 +1872,11 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opVPCEXT, /*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1423,11 +1894,11 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, opHINT_NOP_a32, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opVPCEXT, /*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1445,17 +1916,17 @@ const OpFn OP_TABLE(pentium2d_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; -const OpFn OP_TABLE(286)[1024] = +const OpFn OP_TABLE(286)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, /*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, /*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, /*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, -/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, -/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, /*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1470,14 +1941,14 @@ const OpFn OP_TABLE(286)[1024] = /*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, /*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, /*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, /*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, -/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, -/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, /*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1492,14 +1963,14 @@ const OpFn OP_TABLE(286)[1024] = /*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, /*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, /*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, /*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, -/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, -/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, /*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1514,14 +1985,14 @@ const OpFn OP_TABLE(286)[1024] = /*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, /*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, /*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, /*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, -/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, -/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, /*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1536,17 +2007,17 @@ const OpFn OP_TABLE(286)[1024] = /*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, }; -const OpFn OP_TABLE(386)[1024] = +const OpFn OP_TABLE(386)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, /*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, /*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, /*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, -/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, -/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, /*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, opFS_w_a16, opGS_w_a16, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1568,7 +2039,7 @@ const OpFn OP_TABLE(386)[1024] = /*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a16, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a16, opAAS, /*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, -/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, /*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, opFS_l_a16, opGS_l_a16, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1589,8 +2060,8 @@ const OpFn OP_TABLE(386)[1024] = /*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, opES_w_a32, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a32, opDAS, /*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a32, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a32, opAAS, -/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, -/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, /*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, opFS_w_a32, opGS_w_a32, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1612,7 +2083,7 @@ const OpFn OP_TABLE(386)[1024] = /*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a32, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a32, opAAS, /*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, -/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, /*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, opFS_l_a32, opGS_l_a32, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, /*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, @@ -1625,12 +2096,12 @@ const OpFn OP_TABLE(386)[1024] = /*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, /*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, /*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, -}; +}; -const OpFn OP_TABLE(REPE)[1024] = +const OpFn OP_TABLE(REPE)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a16,0, @@ -1652,7 +2123,7 @@ const OpFn OP_TABLE(REPE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a16,0, @@ -1674,7 +2145,7 @@ const OpFn OP_TABLE(REPE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a32,0, @@ -1696,7 +2167,7 @@ const OpFn OP_TABLE(REPE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a32,0, @@ -1718,10 +2189,10 @@ const OpFn OP_TABLE(REPE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -const OpFn OP_TABLE(REPNE)[1024] = +const OpFn OP_TABLE(REPNE)[1024] = { /*16-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a16,0, @@ -1743,7 +2214,7 @@ const OpFn OP_TABLE(REPNE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a16,0, @@ -1765,7 +2236,7 @@ const OpFn OP_TABLE(REPNE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a32,0, @@ -1787,7 +2258,7 @@ const OpFn OP_TABLE(REPNE)[1024] = /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a32,0, diff --git a/src/cpu/808x.c b/src/cpu/808x.c index a712e6830..96b184bc4 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -9,13 +9,11 @@ * 808x CPU emulation, mostly ported from reenigne's XTCE, which * is cycle-accurate. * - * - * * Authors: Andrew Jenner, * Miran Grca, * - * Copyright 2015-2019 Andrew Jenner. - * Copyright 2016-2019 Miran Grca. + * Copyright 2015-2020 Andrew Jenner. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -36,42 +34,13 @@ #include <86box/pic.h> #include <86box/ppi.h> #include <86box/timer.h> - -/* The opcode of the instruction currently being executed. */ -uint8_t opcode; - -/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ -uint8_t znptable8[256]; -uint16_t znptable16[65536]; - -/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ -uint16_t zero = 0; - -/* MOD and R/M stuff. */ -uint16_t *mod1add[2][8]; -uint32_t *mod1seg[8]; -uint32_t rmdat; - -/* XT CPU multiplier. */ -uint64_t xt_cpu_multi; +#include <86box/gdbstub.h> /* Is the CPU 8088 or 8086. */ int is8086 = 0; -/* Variables for handling the non-maskable interrupts. */ -int nmi = 0, nmi_auto_clear = 0; - -/* Was the CPU ever reset? */ -int x86_was_reset = 0; - -/* Amount of instructions executed - used to calculate the % shown in the title bar. */ -int ins = 0; - -/* Is the TRAP flag on? */ -int trap = 0; - -/* The current effective address's segment. */ -uint32_t easeg; +uint8_t use_custom_nmi_vector = 0; +uint32_t custom_nmi_vector = 0x00000000; /* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ @@ -91,15 +60,16 @@ static int noint = 0; static int in_lock = 0; static int cpu_alu_op, pfq_size; -static uint16_t cpu_src = 0, cpu_dest = 0; -static uint16_t cpu_data = 0, last_addr = 0x0000; +static uint32_t cpu_src = 0, cpu_dest = 0; +static uint32_t cpu_data = 0; + +static uint16_t last_addr = 0x0000; static uint32_t *ovr_seg = NULL; static int prefetching = 1, completed = 1; static int in_rep = 0, repeating = 0; static int oldc, clear_lock = 0; -static int refresh = 0, takeint = 0; -static int cycdiff; +static int refresh = 0, cycdiff; /* Various things needed for 8087. */ @@ -120,11 +90,46 @@ static int cycdiff; wait(val, 0); \ } +#define CLOCK_CYCLES_ALWAYS(val) \ + { \ + wait(val, 0); \ + } + +#if 0 +#define CLOCK_CYCLES_FPU(val) \ + { \ + wait(val, 0); \ + } + + +#define CLOCK_CYCLES(val) \ + { \ + if (fpu_cycles > 0) { \ + fpu_cycles -= (val); \ + if (fpu_cycles < 0) { \ + wait(val, 0); \ + } \ + } else { \ + wait(val, 0); \ + } \ + } + +#define CONCURRENCY_CYCLES(c) fpu_cycles = (c) +#else #define CLOCK_CYCLES(val) \ { \ wait(val, 0); \ } +#define CLOCK_CYCLES_FPU(val) \ + { \ + wait(val, 0); \ + } + +#define CONCURRENCY_CYCLES(c) +#endif + + typedef int (*OpFn)(uint32_t fetchdat); @@ -149,50 +154,6 @@ x808x_log(const char *fmt, ...) va_end(ap); } } - - -void -dumpregs(int force) -{ - int c; - char *seg_names[4] = { "ES", "CS", "SS", "DS" }; - - /* Only dump when needed, and only once.. */ - if (indump || (!force && !dump_on_exit)) - return; - - x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", - cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); - x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); - for (c = 0; c < 4; c++) { - x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", - seg_names[c], _opseg[c]->base, _opseg[c]->limit, - _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); - } - if (is386) { - x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", - seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); - x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", - gs, cpu_state.seg_gs.limit, cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_gs.limit_high); - x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); - x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); - x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); - x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); - x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", - (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", - (use32) ? 32 : 16, (stack32) ? 32 : 16); - x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); - x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", - EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP); - } else { - x808x_log("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); - x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n", - AX, BX, CX, DX, DI, SI, BP, SP); - } - x808x_log("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); - x87_dumpregs(); - indump = 0; -} #else #define x808x_log(fmt, ...) #endif @@ -209,22 +170,6 @@ get_last_addr(void) } -static int -irq_pending(void) -{ - uint8_t temp; - - if (takeint && !noint) - temp = 1; - else - temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint); - - takeint = (cpu_state.flags & I_FLAG) && (pic.pend &~ pic.mask); - - return temp; -} - - static void clock_start(void) { @@ -232,7 +177,7 @@ clock_start(void) } -static void +static void clock_end(void) { int diff = cycdiff - cycles; @@ -270,7 +215,6 @@ static void wait(int c, int bus) { cycles -= c; - fetch_and_bus(c, bus); } @@ -289,29 +233,68 @@ sub_cycles(int c) } +void +resub_cycles(int old_cycles) +{ + int cyc_diff = 0; + + if (old_cycles > cycles) { + cyc_diff = old_cycles - cycles; + cycles = old_cycles; + sub_cycles(cyc_diff); + } +} + + #undef readmemb #undef readmemw #undef readmeml #undef readmemq -/* Common read function. */ -static uint8_t -readmemb_common(uint32_t a) -{ - uint8_t ret; - if (readlookup2 == NULL) - ret = readmembl(a); - else { - if (readlookup2[(a) >> 12] == ((uintptr_t) -1)) - ret = readmembl(a); - else - ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +static void +cpu_io(int bits, int out, uint16_t port) +{ + int old_cycles = cycles; + + if (out) { + wait(4, 1); + if (bits == 16) { + if (is8086 && !(port & 1)) { + old_cycles = cycles; + outw(port, AX); + } else { + wait(4, 1); + old_cycles = cycles; + outb(port++, AL); + outb(port, AH); + } + } else { + old_cycles = cycles; + outb(port, AL); + } + } else { + wait(4, 1); + if (bits == 16) { + if (is8086 && !(port & 1)) { + old_cycles = cycles; + AX = inw(port); + } else { + wait(4, 1); + old_cycles = cycles; + AL = inb(port++); + AH = inb(port); + } + } else { + old_cycles = cycles; + AL = inb(port); + } } - return ret; + resub_cycles(old_cycles); } + /* Reads a byte from the memory and advances the BIU. */ static uint8_t readmemb(uint32_t a) @@ -319,7 +302,7 @@ readmemb(uint32_t a) uint8_t ret; wait(4, 1); - ret = readmemb_common(a); + ret = read_mem_b(a); return ret; } @@ -332,35 +315,26 @@ readmembf(uint32_t a) uint8_t ret; a = cs + (a & 0xffff); - ret = readmemb_common(a); + ret = read_mem_b(a); return ret; } /* Reads a word from the memory and advances the BIU. */ -static uint16_t -readmemw_common(uint32_t s, uint16_t a) -{ - uint16_t ret; - - ret = readmemb_common(s + a); - ret |= readmemb_common(s + ((a + 1) & 0xffff)) << 8; - - return ret; -} - - static uint16_t readmemw(uint32_t s, uint16_t a) { uint16_t ret; + wait(4, 1); if (is8086 && !(a & 1)) + ret = read_mem_w(s + a); + else { wait(4, 1); - else - wait(8, 1); - ret = readmemw_common(s, a); + ret = read_mem_b(s + a); + ret |= read_mem_b(s + ((a + 1) & 0xffff)) << 8; + } return ret; } @@ -371,7 +345,7 @@ readmemwf(uint16_t a) { uint16_t ret; - ret = readmemw_common(cs, a & 0xffff); + ret = read_mem_w(cs + (a & 0xffff)); return ret; } @@ -411,29 +385,17 @@ readmemq(uint32_t s, uint16_t a) } -static void -writememb_common(uint32_t a, uint8_t v) -{ - if (writelookup2 == NULL) - writemembl(a, v); - else { - if (writelookup2[(a) >> 12] == ((uintptr_t) -1)) - writemembl(a, v); - else - *(uint8_t *)(writelookup2[a >> 12] + a) = v; - } - - if ((a >= 0xf0000) && (a <= 0xfffff)) - last_addr = a & 0xffff; -} - - /* Writes a byte to the memory and advances the BIU. */ static void writememb(uint32_t s, uint32_t a, uint8_t v) { + uint32_t addr = s + a; + wait(4, 1); - writememb_common(s + a, v); + write_mem_b(addr, v); + + if ((addr >= 0xf0000) && (addr <= 0xfffff)) + last_addr = addr & 0xffff; } @@ -441,12 +403,20 @@ writememb(uint32_t s, uint32_t a, uint8_t v) static void writememw(uint32_t s, uint32_t a, uint16_t v) { + uint32_t addr = s + a; + + wait(4, 1); if (is8086 && !(a & 1)) + write_mem_w(addr, v); + else { + write_mem_b(addr, v & 0xff); wait(4, 1); - else - wait(8, 1); - writememb_common(s + a, v & 0xff); - writememb_common(s + ((a + 1) & 0xffff), v >> 8); + addr = s + ((a + 1) & 0xffff); + write_mem_b(addr, v >> 8); + } + + if ((addr >= 0xf0000) && (addr <= 0xfffff)) + last_addr = addr & 0xffff; } @@ -454,9 +424,9 @@ static void writemem(uint32_t s, uint16_t v) { if (opcode & 1) - return writememw(s, cpu_state.eaaddr, v); + writememw(s, cpu_state.eaaddr, v); else - return writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); + writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); } @@ -594,6 +564,60 @@ pfq_clear() } +static void +load_cs(uint16_t seg) +{ + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.seg = seg & 0xffff; +} + + +static void +load_seg(uint16_t seg, x86seg *s) +{ + s->base = seg << 4; + s->seg = seg & 0xffff; +} + + +void +reset_808x(int hard) +{ + biu_cycles = 0; + in_rep = 0; + in_lock = 0; + completed = 1; + repeating = 0; + clear_lock = 0; + refresh = 0; + ovr_seg = NULL; + + if (hard) { + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &cpu_state.seg_es; + _opseg[1] = &cpu_state.seg_cs; + _opseg[2] = &cpu_state.seg_ss; + _opseg[3] = &cpu_state.seg_ds; + + pfq_size = (is8086) ? 6 : 4; + pfq_clear(); + } + + load_cs(0xFFFF); + cpu_state.pc = 0; + rammask = 0xfffff; + + prefetching = 1; + cpu_alu_op = 0; + + use_custom_nmi_vector = 0x00; + custom_nmi_vector = 0x00000000; +} + + static void set_ip(uint16_t new_ip) { pfq_ip = cpu_state.pc = new_ip; @@ -608,42 +632,20 @@ refreshread(void) { } -/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ -static void -makemod1table(void) +static uint16_t +get_accum(int bits) { - mod1add[0][0] = &BX; - mod1add[0][1] = &BX; - mod1add[0][2] = &BP; - mod1add[0][3] = &BP; - mod1add[0][4] = &SI; - mod1add[0][5] = &DI; - mod1add[0][6] = &BP; - mod1add[0][7] = &BX; - mod1add[1][0] = &SI; - mod1add[1][1] = &DI; - mod1add[1][2] = &SI; - mod1add[1][3] = &DI; - mod1add[1][4] = &zero; - mod1add[1][5] = &zero; - mod1add[1][6] = &zero; - mod1add[1][7] = &zero; - mod1seg[0] = &ds; - mod1seg[1] = &ds; - mod1seg[2] = &ss; - mod1seg[3] = &ss; - mod1seg[4] = &ds; - mod1seg[5] = &ds; - mod1seg[6] = &ss; - mod1seg[7] = &ds; - opseg[0] = &es; - opseg[1] = &cs; - opseg[2] = &ss; - opseg[3] = &ds; - _opseg[0] = &cpu_state.seg_es; - _opseg[1] = &cpu_state.seg_cs; - _opseg[2] = &cpu_state.seg_ss; - _opseg[3] = &cpu_state.seg_ds; + return (bits == 16) ? AX : AL; +} + + +static void +set_accum(int bits, uint16_t val) +{ + if (bits == 16) + AX = val; + else + AL = val; } @@ -654,13 +656,6 @@ sign_extend(uint8_t data) } -static uint32_t -sign_extend32(uint16_t data) -{ - return data + (data < 0x8000 ? 0 : 0xffff0000); -} - - /* Fetches the effective address from the prefetch queue according to MOD and R/M. */ static void do_mod_rm(void) @@ -847,163 +842,6 @@ seteaq(uint64_t val) #undef FPU_8087 -/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ -static void -makeznptable(void) -{ - int c, d, e; - for (c = 0; c < 256; c++) { - d = 0; - for (e = 0; e < 8; e++) { - if (c & (1 << e)) - d++; - } - if (d & 1) - znptable8[c] = 0; - else - znptable8[c] = P_FLAG; -#ifdef ENABLE_808X_LOG - if (c == 0xb1) - x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); -#endif - if (!c) - znptable8[c] |= Z_FLAG; - if (c & 0x80) - znptable8[c] |= N_FLAG; - } - - for (c = 0; c < 65536; c++) { - d = 0; - for (e = 0; e < 8; e++) { - if (c & (1 << e)) - d++; - } - if (d & 1) - znptable16[c] = 0; - else - znptable16[c] = P_FLAG; -#ifdef ENABLE_808X_LOG - if (c == 0xb1) - x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); - if (c == 0x65b1) - x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); -#endif - if (!c) - znptable16[c] |= Z_FLAG; - if (c & 0x8000) - znptable16[c] |= N_FLAG; - } -} - - -/* Common reset function. */ -static void -reset_common(int hard) -{ - /* Make sure to gracefully leave SMM. */ - if (in_smm) - leave_smm(); - - biu_cycles = 0; - in_rep = 0; - in_lock = 0; - completed = 1; - repeating = 0; - clear_lock = 0; - refresh = 0; - - if (hard) { -#ifdef ENABLE_808X_LOG - x808x_log("x86 reset\n"); -#endif - ins = 0; - } - use32 = 0; - cpu_cur_status = 0; - stack32 = 0; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - msw = 0; - if (hascache) - cr0 = 1 << 30; - else - cr0 = 0; - cpu_cache_int_enabled = 0; - cpu_update_waitstates(); - cr4 = 0; - cpu_state.eflags = 0; - cgate32 = 0; - if (AT) { - loadcs(0xF000); - cpu_state.pc = 0xFFF0; - rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; - } else { - loadcs(0xFFFF); - cpu_state.pc = 0; - rammask = 0xfffff; - } - idt.base = 0; - idt.limit = is386 ? 0x03FF : 0xFFFF; - cpu_state.flags = 2; - trap = 0; - ovr_seg = NULL; - - EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; - - if (hard) { - makeznptable(); - resetreadlookup(); - makemod1table(); - pfq_clear(); - cpu_set_edx(); - mmu_perm = 4; - pfq_size = (is8086) ? 6 : 4; - } - x86seg_reset(); -#ifdef USE_DYNAREC - if (hard) - codegen_reset(); -#endif - if (!hard) - flushmmucache(); - x86_was_reset = 1; - cpu_alt_reset = 0; - - prefetching = 1; - takeint = 0; - - cpu_ven_reset(); - - cpu_alu_op = 0; - - in_smm = smi_latched = 0; - smi_line = smm_in_hlt = 0; - - if (hard) { - smbase = 0x00030000; - ppi_reset(); - } - in_sys = 0; - - shadowbios = shadowbios_write = 0; -} - - -/* Hard reset. */ -void -resetx86(void) -{ - reset_common(1); -} - - -/* Soft reset. */ -void -softresetx86(void) -{ - reset_common(0); -} - - /* Pushes a word to the stack. */ static void push(uint16_t *val) @@ -1124,7 +962,9 @@ interrupt(uint16_t addr) cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; access(6, 16); new_cs = readmemw(0, cpu_state.eaaddr); + prefetching = 0; pfq_clear(); + ovr_seg = NULL; access(39, 16); tempf = cpu_state.flags & 0x0fd7; push(&tempf); @@ -1132,7 +972,7 @@ interrupt(uint16_t addr) access(40, 16); push(&old_cs); old_ip = cpu_state.pc; - loadcs(new_cs); + load_cs(new_cs); access(68, 16); set_ip(new_ip); access(41, 16); @@ -1140,6 +980,53 @@ interrupt(uint16_t addr) } +static void +custom_nmi(void) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; + + cpu_state.eaaddr = 0x0002; + old_cs = CS; + access(5, 16); + (void) readmemw(0, cpu_state.eaaddr); + new_ip = custom_nmi_vector & 0xffff; + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + (void) readmemw(0, cpu_state.eaaddr); + new_cs = custom_nmi_vector >> 16; + prefetching = 0; + pfq_clear(); + ovr_seg = NULL; + access(39, 16); + tempf = cpu_state.flags & 0x0fd7; + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + load_cs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); +} + + +static int +irq_pending(void) +{ + uint8_t temp; + + temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint) || + ((cpu_state.flags & I_FLAG) && pic.int_pending && !noint); + + return temp; +} + + static void check_interrupts(void) { @@ -1152,19 +1039,35 @@ check_interrupts(void) } if (nmi && nmi_enable && nmi_mask) { nmi_enable = 0; - interrupt(2); + if (use_custom_nmi_vector) + custom_nmi(); + else + interrupt(2); +#ifndef OLD_NMI_BEHAVIOR + nmi = 0; +#endif return; } - temp = picinterrupt(); - if (temp != -1) { + if ((cpu_state.flags & I_FLAG) && pic.int_pending && !noint) { repeating = 0; completed = 1; ovr_seg = NULL; + wait(3, 0); + /* ACK to PIC */ + temp = pic_irq_ack(); + wait(4, 1); + wait(1, 0); + /* ACK to PIC */ + temp = pic_irq_ack(); + wait(4, 1); + wait(1, 0); in_lock = 0; clear_lock = 0; - ovr_seg = NULL; - wait(9, 0); - interrupt((uint16_t) (temp & 0xffff)); + wait(1, 0); + /* Here is where temp should be filled, but we cheat. */ + wait(3, 0); + opcode = 0x00; + interrupt(temp); } } } @@ -1290,10 +1193,7 @@ set_of(int of) static int top_bit(uint16_t w, int bits) { - if (bits == 16) - return ((w & 0x8000) != 0); - else - return ((w & 0x80) != 0); + return (w & (1 << (bits - 1))); } @@ -1510,6 +1410,7 @@ mul(uint16_t a, uint16_t b) set_sf(bit_count); set_pf(); + set_af(0); } @@ -1520,12 +1421,19 @@ set_of_rotate(int bits) } +static void +set_zf_ex(int zf) +{ + cpu_state.flags = (cpu_state.flags & ~0x40) | (zf ? 0x40 : 0); +} + + static void set_zf(int bits) { int size_mask = (1 << bits) - 1; - cpu_state.flags = (cpu_state.flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); + set_zf_ex((cpu_data & size_mask) == 0); } @@ -1539,10 +1447,13 @@ set_pzs(int bits) static void -set_co_mul(int carry) +set_co_mul(int bits, int carry) { set_cf(carry); set_of(carry); + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ + set_zf_ex(!carry); if (!carry) wait(1, 0); } @@ -1692,8 +1603,8 @@ stos(int bits) static void aa(void) { - set_of(0); - AL &= 0x0f; + set_pzs(8); + AL = cpu_data & 0x0f; wait(6, 0); } @@ -1770,9 +1681,9 @@ void execx86(int cycs) { uint8_t temp = 0, temp2; + uint8_t old_af; uint16_t addr, tempw; uint16_t new_cs, new_ip; - uint32_t result; int bits; cycles += cycs; @@ -1792,6 +1703,7 @@ execx86(int cycs) } completed = 1; + // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); switch (opcode) { case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ access(29, 16); @@ -1800,10 +1712,10 @@ execx86(int cycs) case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ access(22, 16); if (opcode == 0x0F) { - loadcs(pop()); + load_cs(pop()); pfq_pos = 0; } else - loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); + load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); wait(1, 0); /* All POP segment instructions suppress interrupts for one instruction. */ noint = 1; @@ -1865,19 +1777,19 @@ execx86(int cycs) bits = 8 << (opcode & 1); wait(1, 0); cpu_data = pfq_fetch(); - cpu_dest = get_reg(0); /* AX/AL */ + cpu_dest = get_accum(bits); /* AX/AL */ cpu_src = cpu_data; cpu_alu_op = (opcode >> 3) & 7; alu_op(bits); if (cpu_alu_op != 7) - set_reg(0, cpu_data); + set_accum(bits, cpu_data); wait(1, 0); break; case 0x27: /*DAA*/ cpu_dest = AL; set_of(0); - temp = !!(cpu_state.flags & A_FLAG); + old_af = !!(cpu_state.flags & A_FLAG); if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { cpu_src = 6; cpu_data = cpu_dest + cpu_src; @@ -1885,7 +1797,7 @@ execx86(int cycs) cpu_dest = cpu_data; set_af(1); } - if ((cpu_state.flags & C_FLAG) || AL > (temp ? 0x9f : 0x99)) { + if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { cpu_src = 0x60; cpu_data = cpu_dest + cpu_src; set_of_add(8); @@ -1899,7 +1811,7 @@ execx86(int cycs) case 0x2F: /*DAS*/ cpu_dest = AL; set_of(0); - temp = !!(cpu_state.flags & A_FLAG); + old_af = !!(cpu_state.flags & A_FLAG); if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { cpu_src = 6; cpu_data = cpu_dest - cpu_src; @@ -1907,7 +1819,7 @@ execx86(int cycs) cpu_dest = cpu_data; set_af(1); } - if ((cpu_state.flags & C_FLAG) || AL > (temp ? 0x9f : 0x99)) { + if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { cpu_src = 0x60; cpu_data = cpu_dest - cpu_src; set_of_sub(8); @@ -1931,7 +1843,6 @@ execx86(int cycs) } cpu_dest = AL; cpu_data = cpu_dest + cpu_src; - AL = cpu_data; set_of_add(8); aa(); break; @@ -1948,7 +1859,6 @@ execx86(int cycs) } cpu_dest = AL; cpu_data = cpu_dest - cpu_src; - AL = cpu_data; set_of_sub(8); aa(); break; @@ -2136,10 +2046,10 @@ execx86(int cycs) access(51, 16); tempw = geteaw(); if ((rmdat & 0x18) == 0x08) { - loadcs(tempw); + load_cs(tempw); pfq_pos = 0; } else - loadseg(tempw, _opseg[(rmdat & 0x18) >> 3]); + load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); wait(1, 0); if (cpu_mod != 3) wait(2, 0); @@ -2194,7 +2104,7 @@ execx86(int cycs) push(&(CS)); access(60, 16); cpu_state.oldpc = cpu_state.pc; - loadcs(new_cs); + load_cs(new_cs); set_ip(new_ip); access(32, 16); push((uint16_t *) &(cpu_state.oldpc)); @@ -2243,7 +2153,7 @@ execx86(int cycs) wait(1, 0); cpu_state.eaaddr = pfq_fetchw(); access(1, bits); - set_reg(0, readmem((ovr_seg ? *ovr_seg : ds))); + set_accum(bits, readmem((ovr_seg ? *ovr_seg : ds))); wait(1, 0); break; case 0xA2: case 0xA3: @@ -2252,7 +2162,7 @@ execx86(int cycs) wait(1, 0); cpu_state.eaaddr = pfq_fetchw(); access(7, bits); - writemem((ovr_seg ? *ovr_seg : ds), get_reg(0)); + writemem((ovr_seg ? *ovr_seg : ds), get_accum(bits)); break; case 0xA4: case 0xA5: /* MOVS */ @@ -2277,7 +2187,7 @@ execx86(int cycs) access(27, bits); stos(bits); } else { - set_reg(0, cpu_data); + set_accum(bits, cpu_data); if (in_rep != 0) wait(2, 0); } @@ -2303,7 +2213,7 @@ execx86(int cycs) if (in_rep != 0) wait(1, 0); wait(1, 0); - cpu_dest = get_reg(0); + cpu_dest = get_accum(bits); if ((opcode & 8) == 0) { access(21, bits); lods(bits); @@ -2335,7 +2245,7 @@ execx86(int cycs) bits = 8 << (opcode & 1); wait(1, 0); cpu_data = pfq_fetch(); - test(bits, get_reg(0), cpu_data); + test(bits, get_accum(bits), cpu_data); wait(1, 0); break; @@ -2406,7 +2316,7 @@ execx86(int cycs) SP += cpu_src; wait(1, 0); } - loadcs(new_cs); + load_cs(new_cs); access(72, bits); set_ip(new_ip); break; @@ -2420,7 +2330,7 @@ execx86(int cycs) cpu_state.regs[cpu_reg].w = cpu_data; access(57, bits); read_ea2(bits); - loadseg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); + load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); wait(1, 0); break; @@ -2459,7 +2369,7 @@ execx86(int cycs) wait(3, 0); access(44, 8); new_cs = pop(); - loadcs(new_cs); + load_cs(new_cs); access(62, 8); set_ip(new_ip); access(45, 8); @@ -2493,6 +2403,7 @@ execx86(int cycs) cpu_data <<= 1; cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); set_of_rotate(bits); + set_af(0); break; case 0x08: /* ROR */ set_cf((cpu_data & 1) != 0); @@ -2500,11 +2411,13 @@ execx86(int cycs) if (cpu_state.flags & C_FLAG) cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); set_of_rotate(bits); + set_af(0); break; case 0x10: /* RCL */ set_cf(top_bit(cpu_data, bits)); cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); set_of_rotate(bits); + set_af(0); break; case 0x18: /* RCR */ set_cf((cpu_data & 1) != 0); @@ -2513,18 +2426,20 @@ execx86(int cycs) cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); set_cf((cpu_dest & 1) != 0); set_of_rotate(bits); + set_af(0); break; case 0x20: /* SHL */ set_cf(top_bit(cpu_data, bits)); cpu_data <<= 1; set_of_rotate(bits); + set_af((cpu_data & 0x10) != 0); set_pzs(bits); break; case 0x28: /* SHR */ set_cf((cpu_data & 1) != 0); cpu_data >>= 1; set_of_rotate(bits); - set_af(1); + set_af(0); set_pzs(bits); break; case 0x30: /* SETMO - undocumented? */ @@ -2542,7 +2457,7 @@ execx86(int cycs) else cpu_data |= (cpu_dest & 0x8000); set_of_rotate(bits); - set_af(1); + set_af(0); set_pzs(bits); break; } @@ -2563,9 +2478,11 @@ execx86(int cycs) case 0xD5: /*AAD*/ wait(1, 0); mul(pfq_fetchb(), AH); - AL += cpu_data; + cpu_dest = AL; + cpu_src = cpu_data; + add(8); + AL = cpu_data; AH = 0x00; - set_pzs(16); break; case 0xD6: /*SALC*/ wait(1, 0); @@ -2657,30 +2574,20 @@ execx86(int cycs) cpu_state.eaaddr = cpu_data; if ((opcode & 2) == 0) { access(3, bits); - if ((opcode & 1) && is8086 && !(cpu_data & 1)) { - AX = inw(cpu_data); - wait(4, 1); /* I/O access and wait state. */ - } else { - AL = inb(cpu_data); - if (opcode & 1) - AH = inb(cpu_data + 1); - wait(bits >> 1, 1); /* I/O access. */ - } + if (opcode & 1) + cpu_io(16, 0, cpu_data); + else + cpu_io(8, 0, cpu_data); wait(1, 0); } else { if ((opcode & 8) == 0) access(8, bits); else access(9, bits); - if ((opcode & 1) && is8086 && !(cpu_data & 1)) { - outw(cpu_data, AX); - wait(4, 1); - } else { - outb(cpu_data, AL); - if (opcode & 1) - outb(cpu_data + 1, AH); - wait(bits >> 1, 1); /* I/O access. */ - } + if (opcode & 1) + cpu_io(16, 1, cpu_data); + else + cpu_io(8, 1, cpu_data); } break; @@ -2699,7 +2606,7 @@ execx86(int cycs) addr = pfq_fetchw(); wait(1, 0); tempw = pfq_fetchw(); - loadcs(tempw); + load_cs(tempw); access(70, 8); pfq_clear(); set_ip(addr); @@ -2777,30 +2684,22 @@ execx86(int cycs) case 0x20: /* MUL */ case 0x28: /* IMUL */ wait(1, 0); + mul(get_accum(bits), cpu_data); if (opcode & 1) { - result = cpu_data; - mul(AX, cpu_data); AX = cpu_data; DX = cpu_dest; - cpu_data |= DX; - result = ((uint32_t) DX << 16) | AX; - if ((rmdat & 0x38) == 0x20) - set_co_mul(DX != 0x0000); - else - set_co_mul(result != sign_extend32(AX)); + set_co_mul(bits, DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); + cpu_data = DX; } else { - mul(AL, cpu_data); AL = (uint8_t) cpu_data; AH = (uint8_t) cpu_dest; - cpu_data |= AH; - if ((rmdat & 0x38) == 0x20) - set_co_mul(AH != 0x00); - else - set_co_mul(AX != sign_extend(AL)); + set_co_mul(bits, AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); + cpu_data = AH; } /* NOTE: When implementing the V20, care should be taken to not change the zero flag. */ - set_zf(bits); + set_sf(bits); + set_pf(); if (cpu_mod != 3) wait(1, 0); break; @@ -2882,7 +2781,7 @@ execx86(int cycs) access(64, bits); wait(4, 0); cpu_state.oldpc = cpu_state.pc; - loadcs(new_cs); + load_cs(new_cs); set_ip(new_ip); access(37, bits); push((uint16_t *) &(cpu_state.oldpc)); @@ -2899,7 +2798,7 @@ execx86(int cycs) if (!(opcode & 1)) cpu_data |= 0xff00; new_cs = cpu_data; - loadcs(new_cs); + load_cs(new_cs); access(66, bits); set_ip(new_ip); break; @@ -2908,7 +2807,7 @@ execx86(int cycs) if (cpu_mod != 3) wait(1, 0); access(38, bits); - push(&(cpu_data)); + push((uint16_t *) &(cpu_data)); break; } break; @@ -2935,6 +2834,9 @@ execx86(int cycs) cpu_alu_op = 0; } - ins++; +#ifdef USE_GDBSTUB + if (gdbstub_instruction()) + return; +#endif } } diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt new file mode 100644 index 000000000..20452bf88 --- /dev/null +++ b/src/cpu/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(cpu OBJECT cpu.c cpu_table.c fpu.c x86.c 808x.c 386.c 386_common.c + 386_dynarec.c x86seg.c x87.c x87_timings.c) + +if(AMD_K5) + target_compile_definitions(cpu PRIVATE USE_AMD_K5) +endif() + +if(CYRIX_6X86) + target_compile_definitions(cpu PRIVATE USE_CYRIX_6X86) +endif() + +if(DYNAREC) + target_sources(cpu PRIVATE 386_dynarec_ops.c) + + add_library(cgt OBJECT codegen_timing_486.c codegen_timing_686.c + codegen_timing_common.c codegen_timing_k6.c + codegen_timing_pentium.c codegen_timing_p6.c + codegen_timing_winchip.c codegen_timing_winchip2.c) +endif() diff --git a/src/cpu/codegen_timing_486.c b/src/cpu/codegen_timing_486.c index a3859ecce..ce451421d 100644 --- a/src/cpu/codegen_timing_486.c +++ b/src/cpu/codegen_timing_486.c @@ -306,14 +306,14 @@ void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin uint64_t *deps; int mod3 = ((fetchdat & 0xc0) == 0xc0); int bit8 = !(opcode & 1); - + switch (last_prefix) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; break; - + case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; @@ -368,13 +368,13 @@ void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; opcode = (fetchdat >> 3) & 7; break; - + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; @@ -397,12 +397,12 @@ void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin break; } } - + timing_count += COUNT(timings[opcode], op_32); if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) timing_count++; /*AGI stall*/ codegen_block_cycles += timing_count; - + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); } diff --git a/src/cpu/codegen_timing_686.c b/src/cpu/codegen_timing_686.c index ff7ff54d2..cde59d9cb 100644 --- a/src/cpu/codegen_timing_686.c +++ b/src/cpu/codegen_timing_686.c @@ -77,7 +77,7 @@ static uint32_t opcode_timings[256] = /*10*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, /* ADC ADC PUSH SS POP SS*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), -/* SBB SBB SBB SBB*/ +/* SBB SBB SBB SBB*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, /* SBB SBB PUSH DS POP DS*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), @@ -90,7 +90,7 @@ static uint32_t opcode_timings[256] = PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, /* SUB SUB DAS*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), - + /* XOR XOR XOR XOR*/ /*30*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, /* XOR XOR AAA*/ @@ -108,7 +108,7 @@ static uint32_t opcode_timings[256] = PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* DEC ESP DEC EBP DEC ESI DEC EDI*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, - + /* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ /*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ @@ -125,8 +125,8 @@ static uint32_t opcode_timings[256] = PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(10), /* INSB INSW OUTSB OUTSW*/ PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), - -/* Jxx*/ + +/* Jxx*/ /*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, @@ -139,7 +139,7 @@ static uint32_t opcode_timings[256] = PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* MOV from seg LEA MOV to seg POP*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG, CYCLES(3), PAIR_XY | CYCLES(1), - + /* NOP XCHG XCHG XCHG*/ /*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), /* XCHG XCHG XCHG XCHG*/ @@ -149,7 +149,7 @@ static uint32_t opcode_timings[256] = /* PUSHF POPF SAHF LAHF*/ PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), -/* MOV MOV MOV MOV*/ +/* MOV MOV MOV MOV*/ /*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* MOVSB MOVSW CMPSB CMPSW*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), @@ -177,7 +177,7 @@ static uint32_t opcode_timings[256] = /*d0*/ INVALID, INVALID, INVALID, INVALID, /* AAM AAD SETALC XLAT*/ PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /* LOOPNE LOOPE LOOP JCXZ*/ /*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, @@ -213,7 +213,7 @@ static uint32_t opcode_timings_mod3[256] = /*10*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* ADC ADC PUSH SS POP SS*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), -/* SBB SBB SBB SBB*/ +/* SBB SBB SBB SBB*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* SBB SBB PUSH DS POP DS*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), @@ -226,7 +226,7 @@ static uint32_t opcode_timings_mod3[256] = PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* SUB SUB DAS*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), - + /* XOR XOR XOR XOR*/ /*30*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* XOR XOR AAA*/ @@ -244,7 +244,7 @@ static uint32_t opcode_timings_mod3[256] = PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* DEC ESP DEC EBP DEC ESI DEC EDI*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, - + /* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ /*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ @@ -261,8 +261,8 @@ static uint32_t opcode_timings_mod3[256] = PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(10), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(10), /* INSB INSW OUTSB OUTSW*/ PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), - -/* Jxx*/ + +/* Jxx*/ /*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, @@ -275,7 +275,7 @@ static uint32_t opcode_timings_mod3[256] = PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* MOV from seg LEA MOV to seg POP*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_XY | CYCLES(1), - + /* NOP XCHG XCHG XCHG*/ /*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), /* XCHG XCHG XCHG XCHG*/ @@ -285,8 +285,8 @@ static uint32_t opcode_timings_mod3[256] = /* PUSHF POPF SAHF LAHF*/ PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), -/* MOV MOV MOV MOV*/ -/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* MOVSB MOVSW CMPSB CMPSW*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), /* TEST TEST STOSB STOSW*/ @@ -313,7 +313,7 @@ static uint32_t opcode_timings_mod3[256] = /*d0*/ INVALID, INVALID, INVALID, INVALID, /* AAM AAD SETALC XLAT*/ PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /* LOOPNE LOOPE LOOP JCXZ*/ @@ -346,12 +346,12 @@ static uint32_t opcode_timings_0f[256] = INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -361,17 +361,17 @@ static uint32_t opcode_timings_0f[256] = PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), - + /*50*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*60*/ PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, - + /*70*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES(1), INVALID, INVALID, INVALID, INVALID, @@ -381,17 +381,17 @@ static uint32_t opcode_timings_0f[256] = PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, - + /*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), - + /*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), - + /*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), @@ -406,12 +406,12 @@ static uint32_t opcode_timings_0f[256] = INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, - + /*e0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, - + /*f0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, @@ -428,12 +428,12 @@ static uint32_t opcode_timings_0f_mod3[256] = INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -443,17 +443,17 @@ static uint32_t opcode_timings_0f_mod3[256] = PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), - + /*50*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*60*/ PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, - + /*70*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES(1), INVALID, INVALID, INVALID, INVALID, @@ -463,17 +463,17 @@ static uint32_t opcode_timings_0f_mod3[256] = PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, - + /*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), - + /*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), - + /*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), @@ -482,17 +482,17 @@ static uint32_t opcode_timings_0f_mod3[256] = INVALID, INVALID, INVALID, INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), - + /*d0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, - + /*e0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, - PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, - + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + /*f0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, @@ -564,7 +564,7 @@ static uint32_t opcode_timings_ff[8] = PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), /* JMP JMP far PUSH*/ PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1), INVALID -}; +}; static uint32_t opcode_timings_ff_mod3[8] = { /* INC DEC CALL CALL far*/ @@ -605,10 +605,10 @@ static uint32_t opcode_timings_d9_mod3[64] = PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), /*FNOP*/ PAIR_X | CYCLES(2), INVALID, INVALID, INVALID, - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, /*FSTP*/ PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), - PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), /* opFCHS opFABS*/ PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, /* opFTST opFXAM (oddly low) */ @@ -652,27 +652,27 @@ static uint32_t opcode_timings_db_mod3[64] = { PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), - + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), - + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), - + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), - + /* opFNOP opFCLEX opFINIT*/ INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(5), PAIR_X | CYCLES(8), /* opFNOP opFNOP*/ PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, }; @@ -822,7 +822,7 @@ static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_3 if (last_regmask_modified & addr_regmask) return 1; - + return 0; } @@ -839,7 +839,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; break; - + case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; @@ -894,7 +894,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; opcode = (fetchdat >> 3) & 7; break; - + case 0xc0: case 0xc1: timings = mod3 ? opcode_timings_shift_imm_mod3 : opcode_timings_shift_imm; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; @@ -906,13 +906,13 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_cl_mod3 : opcode_timings_shift_cl; deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; opcode = (fetchdat >> 3) & 7; break; - + case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; @@ -935,17 +935,17 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin break; } } - - /*One prefix per instruction is free*/ + + /*One prefix per instruction is free*/ decode_delay--; if (decode_delay < 0) decode_delay = 0; - + if (prev_full) { uint32_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, op_32); int agi_stall = 0; - + if (regmask & IMPL_ESP) regmask |= SRCDEP_ESP | DSTDEP_ESP; @@ -996,7 +996,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin codegen_block_cycles += t_pair + agi_stall; decode_delay = (-t_pair) + 1 + agi_stall; - + last_regmask_modified = regmask_modified; regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | prev_regmask; prev_full = 0; @@ -1013,7 +1013,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin int agi_stall = 0; agi_stall = check_agi(deps, opcode, fetchdat, op_32); - + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay + agi_stall; decode_delay = (-COUNT(timings[opcode], op_32)) + 1 + agi_stall; last_regmask_modified = regmask_modified; diff --git a/src/cpu/codegen_timing_common.c b/src/cpu/codegen_timing_common.c index 7d4a37453..a1f1b6ce7 100644 --- a/src/cpu/codegen_timing_common.c +++ b/src/cpu/codegen_timing_common.c @@ -10,41 +10,41 @@ uint64_t opcode_deps[256] = { -/* ADD ADD ADD ADD*/ -/*00*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* ADD ADD PUSH ES POP ES*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, -/* OR OR OR OR*/ - SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* OR OR PUSH CS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, 0, +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, 0, -/* ADC ADC ADC ADC*/ -/*10*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* ADC ADC PUSH SS POP SS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, -/* SBB SBB SBB SBB*/ - SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* SBB SBB PUSH DS POP DS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, -/* AND AND AND AND*/ -/*20*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* AND AND DAA*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, -/* SUB SUB SUB SUB*/ - SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* SUB SUB DAS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, - -/* XOR XOR XOR XOR*/ -/*30*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, -/* XOR XOR AAA*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, -/* CMP CMP CMP CMP*/ - SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, -/* CMP CMP AAS*/ - SRCDEP_EAX, SRCDEP_EAX, 0, SRCDEP_EAX | DSTDEP_EAX, +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX | HAS_IMM8, SRCDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, /* INC EAX INC ECX INC EDX INC EBX*/ /*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, @@ -54,7 +54,7 @@ uint64_t opcode_deps[256] = SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, /* DEC ESP DEC EBP DEC ESI DEC EDI*/ SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, - + /* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ /*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, /* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ @@ -68,11 +68,11 @@ uint64_t opcode_deps[256] = /*60*/ IMPL_ESP, IMPL_ESP, 0, 0, 0, 0, 0, 0, /* PUSH imm IMUL PUSH imm IMUL*/ - IMPL_ESP, DSTDEP_REG | MODRM, IMPL_ESP, DSTDEP_REG | MODRM, + IMPL_ESP | HAS_IMM1632,DSTDEP_REG | MODRM, IMPL_ESP | HAS_IMM8, DSTDEP_REG | MODRM, /* INSB INSW OUTSB OUTSW*/ 0, 0, 0, 0, - -/* Jxx*/ + +/* Jxx*/ /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 0, 0, 0, 0, @@ -82,7 +82,7 @@ uint64_t opcode_deps[256] = SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, /* MOV from seg LEA MOV to seg POP*/ MODRM, DSTDEP_REG | MODRM, MODRM, IMPL_ESP | MODRM, - + /* NOP XCHG XCHG XCHG*/ /*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, /* XCHG XCHG XCHG XCHG*/ @@ -92,7 +92,7 @@ uint64_t opcode_deps[256] = /* PUSHF POPF SAHF LAHF*/ IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, -/* MOV MOV MOV MOV*/ +/* MOV MOV MOV MOV*/ /*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, /* MOVSB MOVSW CMPSB CMPSW*/ 0, 0, 0, 0, @@ -102,15 +102,15 @@ uint64_t opcode_deps[256] = 0, 0, 0, 0, /* MOV*/ -/*b0*/ DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, - DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, - DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, - DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, +/*b0*/ DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM1632, DSTDEP_ECX | HAS_IMM1632, DSTDEP_EDX | HAS_IMM1632, DSTDEP_EBX | HAS_IMM1632, + DSTDEP_ESP | HAS_IMM1632, DSTDEP_EBP | HAS_IMM1632, DSTDEP_ESI | HAS_IMM1632, DSTDEP_EDI | HAS_IMM1632, /* RET imm RET*/ /*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, /* LES LDS MOV MOV*/ - DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, MODRM, MODRM, + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, MODRM | HAS_IMM8, MODRM | HAS_IMM1632, /* ENTER LEAVE RETF RETF*/ IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, /* INT3 INT INTO IRET*/ @@ -147,38 +147,38 @@ uint64_t opcode_deps_mod3[256] = /* ADD ADD ADD ADD*/ /*00*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* ADD ADD PUSH ES POP ES*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, /* OR OR OR OR*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* OR OR PUSH CS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, 0, + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, 0, /* ADC ADC ADC ADC*/ /*10*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* ADC ADC PUSH SS POP SS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, -/* SBB SBB SBB SBB*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ SRCDEP_REG |SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* SBB SBB PUSH DS POP DS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, /* AND AND AND AND*/ /*20*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* AND AND DAA*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, /* SUB SUB SUB SUB*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* SUB SUB DAS*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, - + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, + /* XOR XOR XOR XOR*/ /*30*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, /* XOR XOR AAA*/ - SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, /* CMP CMP CMP CMP*/ SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, /* CMP CMP AAS*/ - SRCDEP_EAX, SRCDEP_EAX, 0, SRCDEP_EAX | DSTDEP_EAX, + SRCDEP_EAX | HAS_IMM8, SRCDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, /* INC EAX INC ECX INC EDX INC EBX*/ /*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, @@ -188,7 +188,7 @@ uint64_t opcode_deps_mod3[256] = SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, /* DEC ESP DEC EBP DEC ESI DEC EDI*/ SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, - + /* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ /*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, /* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ @@ -202,11 +202,11 @@ uint64_t opcode_deps_mod3[256] = /*60*/ IMPL_ESP, IMPL_ESP, 0, 0, 0, 0, 0, 0, /* PUSH imm IMUL PUSH imm IMUL*/ - IMPL_ESP, DSTDEP_REG | SRCDEP_RM | MODRM, IMPL_ESP, DSTDEP_REG | SRCDEP_RM | MODRM, + IMPL_ESP | HAS_IMM1632,DSTDEP_REG | SRCDEP_RM | MODRM, IMPL_ESP | HAS_IMM8, DSTDEP_REG | SRCDEP_RM | MODRM, /* INSB INSW OUTSB OUTSW*/ 0, 0, 0, 0, - -/* Jxx*/ + +/* Jxx*/ /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 0, 0, 0, 0, @@ -216,7 +216,7 @@ uint64_t opcode_deps_mod3[256] = SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, /* MOV from seg LEA MOV to seg POP*/ DSTDEP_RM | MODRM, DSTDEP_REG | MODRM, SRCDEP_RM | MODRM, IMPL_ESP | DSTDEP_RM | MODRM, - + /* NOP XCHG XCHG XCHG*/ /*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, /* XCHG XCHG XCHG XCHG*/ @@ -226,7 +226,7 @@ uint64_t opcode_deps_mod3[256] = /* PUSHF POPF SAHF LAHF*/ IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, -/* MOV MOV MOV MOV*/ +/* MOV MOV MOV MOV*/ /*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, /* MOVSB MOVSW CMPSB CMPSW*/ 0, 0, 0, 0, @@ -236,19 +236,19 @@ uint64_t opcode_deps_mod3[256] = 0, 0, 0, 0, /* MOV*/ -/*b0*/ DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, - DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, - DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, - DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, +/*b0*/ DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM1632, DSTDEP_ECX | HAS_IMM1632, DSTDEP_EDX | HAS_IMM1632, DSTDEP_EBX | HAS_IMM1632, + DSTDEP_ESP | HAS_IMM1632, DSTDEP_EBP | HAS_IMM1632, DSTDEP_ESI | HAS_IMM1632, DSTDEP_EDI | HAS_IMM1632, -/* RET imm RET*/ -/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, -/* LES LDS MOV MOV*/ - DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_RM | MODRM, DSTDEP_RM | MODRM, -/* ENTER LEAVE RETF RETF*/ - IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, -/* INT3 INT INTO IRET*/ - 0, 0, 0, 0, +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_RM | MODRM | HAS_IMM8, DSTDEP_RM | MODRM | HAS_IMM1632, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, /*d0*/ 0, 0, 0, 0, @@ -287,12 +287,12 @@ uint64_t opcode_deps_0f[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*20*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -302,17 +302,17 @@ uint64_t opcode_deps_0f[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*60*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM, MODRM, MODRM, MODRM, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, 0, MODRM, MODRM, - + /*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM, MODRM, MODRM, 0, 0, 0, 0, 0, @@ -322,17 +322,17 @@ uint64_t opcode_deps_0f[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*90*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, - + /*a0*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, 0, 0, MODRM, MODRM, 0, MODRM, - MODRM, MODRM, 0, MODRM, - + MODRM, MODRM, MODRM, MODRM, + /*b0*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, 0, 0, MODRM, MODRM, @@ -347,12 +347,12 @@ uint64_t opcode_deps_0f[256] = 0, MODRM | MMX_MULTIPLY, 0, 0, MODRM, MODRM, 0, MODRM, MODRM, MODRM, 0, MODRM, - + /*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, 0, MODRM | MMX_MULTIPLY, 0, 0, MODRM, MODRM, 0, MODRM, MODRM, MODRM, 0, MODRM, - + /*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, MODRM | MMX_MULTIPLY, 0, 0, MODRM, MODRM, MODRM, 0, @@ -369,12 +369,12 @@ uint64_t opcode_deps_0f_mod3[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*20*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -384,17 +384,17 @@ uint64_t opcode_deps_0f_mod3[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*60*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM, MODRM, MODRM, MODRM, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, 0, MODRM, MODRM, - + /*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM, MODRM, MODRM, 0, 0, 0, 0, 0, @@ -404,17 +404,17 @@ uint64_t opcode_deps_0f_mod3[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /*90*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, - + /*a0*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, 0, 0, MODRM, MODRM, 0, MODRM, - MODRM, MODRM, 0, MODRM, - + MODRM, MODRM, MODRM, MODRM, + /*b0*/ MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, MODRM, 0, 0, MODRM, MODRM, @@ -429,12 +429,12 @@ uint64_t opcode_deps_0f_mod3[256] = 0, MODRM | MMX_MULTIPLY, 0, 0, MODRM, MODRM, 0, MODRM, MODRM, MODRM, 0, MODRM, - + /*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, 0, MODRM | MMX_MULTIPLY, 0, 0, MODRM, MODRM, 0, MODRM, MODRM, MODRM, 0, MODRM, - + /*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, MODRM | MMX_MULTIPLY, 0, 0, MODRM, MODRM, MODRM, 0, @@ -749,24 +749,24 @@ uint64_t opcode_deps_db[8] = uint64_t opcode_deps_db_mod3[64] = { 0, 0, 0, 0, 0, 0, 0, 0, - + 0, 0, 0, 0, 0, 0, 0, 0, - + 0, 0, 0, 0, 0, 0, 0, 0, - - + + 0, 0, 0, 0, 0, 0, 0, 0, - + /* opFNOP opFCLEX opFINIT*/ 0, 0, 0, 0, /* opFNOP opFNOP*/ 0, 0, 0, 0, - + 0, 0, 0, 0, 0, 0, 0, 0, - + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, }; uint64_t opcode_deps_dc[8] = diff --git a/src/cpu/codegen_timing_common.h b/src/cpu/codegen_timing_common.h index 71daf80ef..a3faca27d 100644 --- a/src/cpu/codegen_timing_common.h +++ b/src/cpu/codegen_timing_common.h @@ -171,7 +171,7 @@ static inline uint32_t get_addr_regmask(uint64_t data, uint32_t fetchdat, int op if (data & IMPL_ESP) addr_regmask |= REGMASK_IMPL_ESP; - + return addr_regmask; } diff --git a/src/cpu/codegen_timing_k6.c b/src/cpu/codegen_timing_k6.c index 1186c4bf0..66ec33052 100644 --- a/src/cpu/codegen_timing_k6.c +++ b/src/cpu/codegen_timing_k6.c @@ -1780,7 +1780,7 @@ static int uop_run(const risc86_uop_t *uop, int decode_time) int c; k6_unit_t *best_unit = NULL; int best_start_cycle = 99999; - + /*UOP_LIMM does not require execution*/ if (uop->type == UOP_LIMM) return decode_time; @@ -1876,12 +1876,12 @@ void decode_flush() for (c = 0; c < decode_buffer.nr_uops; c++) { int start_timestamp; - + if (decode_buffer.earliest_start[c] == -1) start_timestamp = last_uop_timestamp; else start_timestamp = decode_buffer.earliest_start[c]; - + last_uop_timestamp = uop_run(decode_buffer.uops[c], start_timestamp); if (last_uop_timestamp > uop_timestamp) uop_timestamp = last_uop_timestamp; @@ -2023,11 +2023,11 @@ static void decode_instruction(const risc86_instruction_t *ins, uint64_t deps, u } } break; - + case DECODE_LONG: if (decode_buffer.nr_uops) decode_flush(); - + decode_buffer.nr_uops = ins->nr_uops; for (c = 0; c < ins->nr_uops; c++) { @@ -2039,11 +2039,11 @@ static void decode_instruction(const risc86_instruction_t *ins, uint64_t deps, u } decode_flush(); break; - + case DECODE_VECTOR: if (decode_buffer.nr_uops) decode_flush(); - + decode_timestamp++; d = 0; @@ -2055,7 +2055,7 @@ static void decode_instruction(const risc86_instruction_t *ins, uint64_t deps, u else decode_buffer.earliest_start[d] = -1; d++; - + if (d == 4) { d = 0; @@ -2125,11 +2125,11 @@ void codegen_timing_k6_block_start() decode_timestamp = 0; last_complete_timestamp = 0; - + for (c = 0; c < NR_OPQUADS; c++) opquad_completion_timestamp[c] = 0; next_opquad = 0; - + for (c = 0; c < NR_REGS; c++) reg_available_timestamp[c] = 0; for (c = 0; c < 8; c++) @@ -2138,7 +2138,7 @@ void codegen_timing_k6_block_start() void codegen_timing_k6_start() { - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6) + if (cpu_s->cpu_type == CPU_K6) { units = k6_units; nr_units = NR_K6_UNITS; @@ -2214,7 +2214,7 @@ void codegen_timing_k6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint opcode_pc += 2; } } - + opcode = fastreadb(cs + opcode_pc); ins_table = mod3 ? opcode_timings_0f0f_mod3 : opcode_timings_0f0f; @@ -2287,7 +2287,7 @@ void codegen_timing_k6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xc1: case 0xd1: case 0xd3: ins_table = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; diff --git a/src/cpu/codegen_timing_p6.c b/src/cpu/codegen_timing_p6.c index a69f68f04..0fb5359fe 100644 --- a/src/cpu/codegen_timing_p6.c +++ b/src/cpu/codegen_timing_p6.c @@ -92,7 +92,7 @@ static const macro_op_t alu_store_op = .uop[0] = {.type = UOP_LOAD, .latency = 1}, .uop[1] = {.type = UOP_ALU, .latency = 1}, .uop[2] = {.type = UOP_STORED, .latency = 1}, - .uop[3] = {.type = UOP_STOREA, .latency = 1} + .uop[3] = {.type = UOP_STOREA, .latency = 1} }; static const macro_op_t alup0_store_op = { @@ -101,7 +101,7 @@ static const macro_op_t alup0_store_op = .uop[0] = {.type = UOP_LOAD, .latency = 1}, .uop[1] = {.type = UOP_ALUP0, .latency = 1}, .uop[2] = {.type = UOP_STORED, .latency = 1}, - .uop[3] = {.type = UOP_STOREA, .latency = 1} + .uop[3] = {.type = UOP_STOREA, .latency = 1} }; static const macro_op_t branch_op = @@ -130,7 +130,7 @@ static const macro_op_t store_op = .nr_uops = 2, .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_STORED, .latency = 1}, - .uop[1] = {.type = UOP_STOREA, .latency = 1} + .uop[1] = {.type = UOP_STOREA, .latency = 1} }; @@ -139,7 +139,7 @@ static const macro_op_t bswap_op = .nr_uops = 2, .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_ALU, .latency = 1}, - .uop[1] = {.type = UOP_ALU, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .latency = 1}, }; static const macro_op_t leave_op = { @@ -175,7 +175,7 @@ static const macro_op_t movs_op = .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_LOAD, .latency = 1}, .uop[1] = {.type = UOP_STORED, .latency = 1}, - .uop[2] = {.type = UOP_STOREA, .latency = 1}, + .uop[2] = {.type = UOP_STOREA, .latency = 1}, .uop[3] = {.type = UOP_ALU, .latency = 1} }; static const macro_op_t pop_reg_op = @@ -191,7 +191,7 @@ static const macro_op_t pop_mem_op = .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_LOAD, .latency = 1}, .uop[1] = {.type = UOP_STORED, .latency = 1}, - .uop[2] = {.type = UOP_STOREA, .latency = 1}, + .uop[2] = {.type = UOP_STOREA, .latency = 1}, .uop[3] = {.type = UOP_ALU, .latency = 1} }; static const macro_op_t push_imm_op = @@ -199,7 +199,7 @@ static const macro_op_t push_imm_op = .nr_uops = 2, .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_STORED, .latency = 1}, - .uop[1] = {.type = UOP_STOREA, .latency = 1}, + .uop[1] = {.type = UOP_STOREA, .latency = 1}, }; static const macro_op_t push_mem_op = { @@ -223,7 +223,7 @@ static const macro_op_t stos_op = .nr_uops = 3, .decode_type = DECODE_COMPLEX, .uop[1] = {.type = UOP_STORED, .latency = 1}, - .uop[2] = {.type = UOP_STOREA, .latency = 1}, + .uop[2] = {.type = UOP_STOREA, .latency = 1}, .uop[3] = {.type = UOP_ALU, .latency = 1} }; static const macro_op_t test_reg_op = @@ -359,7 +359,7 @@ static const macro_op_t fchs_op = .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_FLOAT, .latency = 2}, .uop[1] = {.type = UOP_FLOAT, .latency = 2}, - .uop[2] = {.type = UOP_FLOAT, .latency = 2} + .uop[2] = {.type = UOP_FLOAT, .latency = 2} }; static const macro_op_t load_float_op = { @@ -399,7 +399,7 @@ static const macro_op_t load_fiadd_op = .uop[3] = {.type = UOP_FLOAT, .latency = 1}, .uop[4] = {.type = UOP_FLOAT, .latency = 1}, .uop[5] = {.type = UOP_FLOAT, .latency = 1}, - .uop[6] = {.type = UOP_FLOAT, .latency = 1} + .uop[6] = {.type = UOP_FLOAT, .latency = 1} }; static const macro_op_t fdiv_op = { @@ -547,7 +547,7 @@ static const macro_op_t call_far_op = .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_ALU, .latency = 3}, .uop[1] = {.type = UOP_STORED, .latency = 1}, - .uop[2] = {.type = UOP_STOREA, .latency = 1}, + .uop[2] = {.type = UOP_STOREA, .latency = 1}, .uop[3] = {.type = UOP_BRANCH, .latency = 1} }; static const macro_op_t cli_sti_op = @@ -675,7 +675,7 @@ static const macro_op_t int_op = .uop[3] = {.type = UOP_STORED, .latency = 1}, .uop[4] = {.type = UOP_STOREA, .latency = 1}, .uop[5] = {.type = UOP_STORED, .latency = 1}, - .uop[6] = {.type = UOP_STOREA, .latency = 1}, + .uop[6] = {.type = UOP_STOREA, .latency = 1}, .uop[7] = {.type = UOP_BRANCH, .latency = 1} }; static const macro_op_t iret_op = @@ -771,7 +771,7 @@ static const macro_op_t outs_op = .nr_uops = 3, .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_LOAD, .latency = 1}, - .uop[1] = {.type = UOP_ALU, .latency = 18} + .uop[1] = {.type = UOP_ALU, .latency = 18} }; static const macro_op_t pusha_op = { @@ -804,7 +804,7 @@ static const macro_op_t popf_op = .nr_uops = 3, .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_LOAD, .latency = 1}, - .uop[1] = {.type = UOP_ALU, .latency = 6}, + .uop[1] = {.type = UOP_ALU, .latency = 6}, .uop[2] = {.type = UOP_ALUP0, .latency = 10} }; static const macro_op_t pushf_op = @@ -881,7 +881,7 @@ static const macro_op_t xchg_mem_op = .decode_type = DECODE_COMPLEX, .uop[0] = {.type = UOP_LOAD, .latency = 1}, .uop[1] = {.type = UOP_STORED, .latency = 1}, - .uop[2] = {.type = UOP_STOREA, .latency = 1}, + .uop[2] = {.type = UOP_STOREA, .latency = 1}, .uop[3] = {.type = UOP_ALU, .latency = 1} }; static const macro_op_t xlat_op = @@ -1152,7 +1152,7 @@ static const macro_op_t *opcode_timings_mod3[256] = &alup0_6_op, &alup0_3_op, &complex_alup0_1_op, &xlat_op, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /* LOOPNE LOOPE LOOP JCXZ*/ /*e0*/ &loop_op, &loop_op, &loop_op, &loop_op, /* IN AL IN AX OUT_AL OUT_AX*/ @@ -1372,7 +1372,7 @@ static const macro_op_t *opcode_timings_8x[8] = { &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, -}; +}; static const macro_op_t *opcode_timings_8x_mod3[8] = { &alu_op, &alu_op, &alu_store_op, &alu_store_op, @@ -1618,7 +1618,7 @@ static p6_unit_t p2_units[] = {.uop_mask = (1 << UOP_ALU) | (1 << UOP_ALUP0) | (1 << UOP_FLOAT) | /*Port 0*/ (1 << UOP_MMX) | (1 << UOP_MMX_MUL)}, {.uop_mask = (1 << UOP_ALU) | (1 << UOP_BRANCH) | /*Port 1*/ - (1 << UOP_MMX) | (1 << UOP_MMX_SHIFT)}, + (1 << UOP_MMX) | (1 << UOP_MMX_SHIFT)}, {.uop_mask = (1 << UOP_LOAD) | (1 << UOP_FLOAD) | (1 << UOP_MLOAD)}, /*Port 2*/ {.uop_mask = (1 << UOP_STORED) | (1 << UOP_FSTORED) | (1 << UOP_MSTORED)}, /*Port 3*/ {.uop_mask = (1 << UOP_STOREA) | (1 << UOP_FSTOREA) | (1 << UOP_MSTOREA)}, /*Port 4*/ @@ -1630,11 +1630,11 @@ static int uop_run(const p6_uop_t *uop, int decode_time) int c; p6_unit_t *best_unit = NULL; int best_start_cycle = 99999; - + /*UOP_FXCH does not require execution*/ if (uop->type == UOP_FXCH) return decode_time; - + /*Find execution unit for this uOP*/ for (c = 0; c < nr_units; c++) { @@ -1653,7 +1653,7 @@ static int uop_run(const p6_uop_t *uop, int decode_time) if (best_start_cycle < decode_time) best_start_cycle = decode_time; best_unit->first_available_cycle = best_start_cycle + uop->latency; - + return best_start_cycle + uop->latency; @@ -1692,7 +1692,7 @@ void decode_flush_p6() { int c; int start_timestamp, uop_timestamp = 0; - + /*Decoded opseq can not be submitted if there are no free spaces in the opseq buffer*/ if (decode_timestamp < opseq_completion_timestamp[next_opseq]) @@ -1709,7 +1709,7 @@ void decode_flush_p6() start_timestamp = last_uop_timestamp; else start_timestamp = decode_buffer.earliest_start[c]; - + last_uop_timestamp = uop_run(decode_buffer.uops[c], start_timestamp); if (last_uop_timestamp > uop_timestamp) uop_timestamp = last_uop_timestamp; @@ -1785,7 +1785,7 @@ static int codegen_timing_instr_length(uint64_t deps, uint32_t fetchdat, int op_ static void decode_instruction(const macro_op_t *ins, uint64_t deps, uint32_t fetchdat, int op_32, int bit8) { uint32_t regmask_required; - uint32_t regmask_modified; + uint32_t regmask_modified; int c; int d = 0; /*Complex decoder uOPs*/ int earliest_start = 0; @@ -1822,43 +1822,43 @@ static void decode_instruction(const macro_op_t *ins, uint64_t deps, uint32_t fe decode_type = DECODE_COMPLEX; switch (decode_type) - { - case DECODE_SIMPLE: + { + case DECODE_SIMPLE: if (decode_buffer.nr_uops - d == 2) { decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0]; decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start; decode_buffer.nr_uops = 3; decode_flush_p6(); - } + } else if (decode_buffer.nr_uops - d == 1) - { + { decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0]; decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start; decode_buffer.nr_uops = 2+d; if (d) decode_flush_p6(); - } + } else if (decode_buffer.nr_uops) { decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0]; decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start; - decode_buffer.nr_uops = 1+d; + decode_buffer.nr_uops = 1+d; } else { decode_buffer.nr_uops = 1; decode_buffer.uops[0] = &ins->uop[0]; decode_buffer.earliest_start[0] = earliest_start; - } + } break; - + case DECODE_COMPLEX: if (decode_buffer.nr_uops) decode_flush_p6(); /*The 4-1-1 arrangement implies that a complex ins. can't be decoded after a simple one*/ - + d = 0; - + for (c = 0; c < ins->nr_uops; c++) { decode_buffer.uops[d] = &ins->uop[c]; @@ -1867,7 +1867,7 @@ static void decode_instruction(const macro_op_t *ins, uint64_t deps, uint32_t fe else decode_buffer.earliest_start[d] = -1; d++; - + if ((d == 3) && (ins->nr_uops > 4)) /*Ins. with >4 uOPs require the use of special units only present on 3 translate PLAs*/ { d = 0; @@ -1877,9 +1877,9 @@ static void decode_instruction(const macro_op_t *ins, uint64_t deps, uint32_t fe } if (d) { - decode_buffer.nr_uops = d; - } - break; + decode_buffer.nr_uops = d; + } + break; } /*Update write timestamps for any output registers*/ @@ -1932,11 +1932,11 @@ void codegen_timing_p6_block_start() decode_timestamp = 0; last_complete_timestamp = 0; - + for (c = 0; c < NR_OPSEQS; c++) opseq_completion_timestamp[c] = 0; next_opseq = 0; - + for (c = 0; c < NR_REGS; c++) reg_available_timestamp[c] = 0; for (c = 0; c < 8; c++) @@ -1945,7 +1945,7 @@ void codegen_timing_p6_block_start() void codegen_timing_p6_start() { - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) + if (cpu_s->cpu_type == CPU_PENTIUMPRO) { units = ppro_units; nr_units = NR_PPRO_UNITS; @@ -2043,7 +2043,7 @@ void codegen_timing_p6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xc1: case 0xd1: case 0xd3: ins_table = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; diff --git a/src/cpu/codegen_timing_pentium.c b/src/cpu/codegen_timing_pentium.c index ec6b8f2a7..263608682 100644 --- a/src/cpu/codegen_timing_pentium.c +++ b/src/cpu/codegen_timing_pentium.c @@ -124,7 +124,7 @@ static uint64_t opcode_timings[256] = /*10*/ PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, /* ADC ADC PUSH SS POP SS*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), -/* SBB SBB SBB SBB*/ +/* SBB SBB SBB SBB*/ PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, /* SBB SBB PUSH DS POP DS*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), @@ -137,7 +137,7 @@ static uint64_t opcode_timings[256] = PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, /* SUB SUB DAS*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), - + /* XOR XOR XOR XOR*/ /*30*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, /* XOR XOR AAA*/ @@ -155,7 +155,7 @@ static uint64_t opcode_timings[256] = PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* DEC ESP DEC EBP DEC ESI DEC EDI*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, - + /* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ /*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ @@ -172,8 +172,8 @@ static uint64_t opcode_timings[256] = PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), /* INSB INSW OUTSB OUTSW*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), - -/* Jxx*/ + +/* Jxx*/ /*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, @@ -186,7 +186,7 @@ static uint64_t opcode_timings[256] = PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV, /* MOV from seg LEA MOV to seg POP*/ PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, CYCLES(3), PAIR_NP | CYCLES(3), - + /* NOP XCHG XCHG XCHG*/ /*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), /* XCHG XCHG XCHG XCHG*/ @@ -196,7 +196,7 @@ static uint64_t opcode_timings[256] = /* PUSHF POPF SAHF LAHF*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), -/* MOV MOV MOV MOV*/ +/* MOV MOV MOV MOV*/ /*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* MOVSB MOVSW CMPSB CMPSW*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), @@ -224,7 +224,7 @@ static uint64_t opcode_timings[256] = /*d0*/ INVALID, INVALID, INVALID, INVALID, /* AAM AAD SETALC XLAT*/ PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /* LOOPNE LOOPE LOOP JCXZ*/ /*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), @@ -260,7 +260,7 @@ static uint64_t opcode_timings_mod3[256] = /*10*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, /* ADC ADC PUSH SS POP SS*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), -/* SBB SBB SBB SBB*/ +/* SBB SBB SBB SBB*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, /* SBB SBB PUSH DS POP DS*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), @@ -273,7 +273,7 @@ static uint64_t opcode_timings_mod3[256] = PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* SUB SUB DAS*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), - + /* XOR XOR XOR XOR*/ /*30*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* XOR XOR AAA*/ @@ -291,7 +291,7 @@ static uint64_t opcode_timings_mod3[256] = PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* DEC ESP DEC EBP DEC ESI DEC EDI*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, - + /* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ /*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ @@ -308,8 +308,8 @@ static uint64_t opcode_timings_mod3[256] = PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), /* INSB INSW OUTSB OUTSW*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), - -/* Jxx*/ + +/* Jxx*/ /*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, @@ -322,7 +322,7 @@ static uint64_t opcode_timings_mod3[256] = PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* MOV from seg LEA MOV to seg POP*/ PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), - + /* NOP XCHG XCHG XCHG*/ /*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), /* XCHG XCHG XCHG XCHG*/ @@ -332,7 +332,7 @@ static uint64_t opcode_timings_mod3[256] = /* PUSHF POPF SAHF LAHF*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), -/* MOV MOV MOV MOV*/ +/* MOV MOV MOV MOV*/ /*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* MOVSB MOVSW CMPSB CMPSW*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), @@ -360,7 +360,7 @@ static uint64_t opcode_timings_mod3[256] = /*d0*/ INVALID, INVALID, INVALID, INVALID, /* AAM AAD SETALC XLAT*/ PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /* LOOPNE LOOPE LOOP JCXZ*/ @@ -393,32 +393,32 @@ static uint64_t opcode_timings_0f[256] = INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, -/*40*/ INVALID, INVALID, INVALID, INVALID, - INVALID, INVALID, INVALID, INVALID, +/*40*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, + /*50*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*60*/ PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, - + /*70*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_NP | CYCLES(100), INVALID, INVALID, INVALID, INVALID, @@ -428,17 +428,17 @@ static uint64_t opcode_timings_0f[256] = PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), - + /*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), - + /*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), - + /*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), @@ -453,12 +453,12 @@ static uint64_t opcode_timings_0f[256] = INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, - + /*e0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, - + /*f0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, @@ -470,7 +470,7 @@ static uint64_t opcode_timings_0f_mod3[256] = INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -480,7 +480,7 @@ static uint64_t opcode_timings_0f_mod3[256] = PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*30*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(9), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -490,17 +490,17 @@ static uint64_t opcode_timings_0f_mod3[256] = INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*50*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /*60*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, - + /*70*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(100), INVALID, INVALID, INVALID, INVALID, @@ -515,12 +515,12 @@ static uint64_t opcode_timings_0f_mod3[256] = PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), - + /*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), - + /*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), @@ -530,17 +530,17 @@ static uint64_t opcode_timings_0f_mod3[256] = INVALID, INVALID, INVALID, INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), - + /*d0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, - + /*e0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, - PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, - + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + /*f0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, @@ -633,7 +633,7 @@ static uint64_t opcode_timings_d9_mod3[64] = PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), /*FNOP*/ PAIR_NP | FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, /*FSTP*/ PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), @@ -681,27 +681,27 @@ static uint64_t opcode_timings_db_mod3[64] = { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + /* opFNOP opFCLEX opFINIT*/ INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(7,0,0), PAIR_NP | FPU_CYCLES(17,0,0), /* opFNOP opFNOP*/ PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, }; @@ -803,9 +803,9 @@ static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) if (!(timings & PAIR_MASK)) return timings & 0xffff; if ((timings & PAIR_MASK) == PAIR_FX) - return timings & 0xffff; + return timings & 0xffff; if ((timings & PAIR_MASK) == PAIR_FXCH) - return timings & 0xffff; + return timings & 0xffff; if ((timings & PAIR_UV) && !(timings & PAIR_FPU)) timings &= 3; switch (timings & CYCLES_MASK) @@ -819,23 +819,23 @@ static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) case CYCLES_BRANCH: return cpu_has_feature(CPU_FEATURE_MMX) ? 1 : 2; } - + fatal("Illegal COUNT %016llx\n", timings); - + return timings; } static int codegen_fpu_latencies(uint64_t deps, int reg) { int latency = fpu_latency; - + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) latency = fpu_st_latency[0]; if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) latency = fpu_st_latency[1]; if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) latency = fpu_st_latency[reg]; - + return latency; } @@ -843,7 +843,7 @@ static int codegen_fpu_latencies(uint64_t deps, int reg) latency -= count; \ if (latency < 0) \ latency = 0 - + static void codegen_fpu_latency_clock(int count) { SUB_AND_CLAMP(fpu_latency, count); @@ -879,7 +879,7 @@ static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32) return 1; } return 0; -} +} /*The instruction is only of interest here if it's longer than 7 bytes, as that's the limit on Pentium MMX parallel decoding*/ @@ -927,7 +927,7 @@ static inline int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat len += 2; } } - + return len; } @@ -1016,11 +1016,11 @@ static void codegen_instruction(uint64_t *timings, uint64_t *deps, uint8_t opcod codegen_block_cycles += instr_cycles; decode_delay = (-instr_cycles) + 1; - + if (deps[opcode] & FPU_POP) { int c; - + for (c = 0; c < 7; c++) fpu_st_latency[c] = fpu_st_latency[c+1]; fpu_st_latency[7] = 0; @@ -1028,7 +1028,7 @@ static void codegen_instruction(uint64_t *timings, uint64_t *deps, uint8_t opcod if (deps[opcode] & FPU_POP2) { int c; - + for (c = 0; c < 6; c++) fpu_st_latency[c] = fpu_st_latency[c+2]; fpu_st_latency[6] = fpu_st_latency[7] = 0; @@ -1041,7 +1041,7 @@ static void codegen_instruction(uint64_t *timings, uint64_t *deps, uint8_t opcod if (deps[opcode] & FPU_PUSH) { int c; - + for (c = 0; c < 7; c++) fpu_st_latency[c+1] = fpu_st_latency[c]; fpu_st_latency[0] = 0; @@ -1086,7 +1086,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; break; - + case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; @@ -1141,19 +1141,19 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; opcode = (fetchdat >> 3) & 7; break; - + case 0xc0: case 0xc1: case 0xd0: case 0xd1: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; opcode = (fetchdat >> 3) & 7; break; - + case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; @@ -1176,7 +1176,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, break; } } - + if (u_pipe_full) { uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); @@ -1190,7 +1190,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, goto nopair; if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && - (timings[opcode] & PAIR_MASK) == PAIR_FXCH) + (timings[opcode] & PAIR_MASK) == PAIR_FXCH) { int temp; @@ -1209,16 +1209,16 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, addr_regmask = 0; return; } - + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && (decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) <= 0) { int has_displacement; - + if (timings[opcode] & CYCLES_HASIMM) has_displacement = codegen_timing_has_displacement(fetchdat, op_32); else has_displacement = 0; - + if (!has_displacement && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) { int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; @@ -1226,15 +1226,15 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, int t_pair; uint64_t temp_timing; uint64_t temp_deps = 0; - + if (!(u_pipe_timings[u_pipe_opcode] & PAIR_FPU)) t1 &= 3; if (!(timings[opcode] & PAIR_FPU)) - t2 &= 3; + t2 &= 3; if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) fatal("Pair out of range\n"); - + t_pair = pair_timings[t1][t2]; if (t_pair < 1) fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); @@ -1246,7 +1246,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, codegen_instruction(&temp_timing, &temp_deps, 0, 0, 0, 0, agi_stall); u_pipe_full = 0; decode_delay_offset = 0; - + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | u_pipe_regmask; addr_regmask = 0; return; @@ -1266,14 +1266,14 @@ nopair: if ((timings[opcode] & PAIR_U) && (decode_delay + decode_delay_offset) <= 0) { int has_displacement; - + if (timings[opcode] & CYCLES_HASIMM) has_displacement = codegen_timing_has_displacement(fetchdat, op_32); else has_displacement = 0; - + if ((!has_displacement || cpu_has_feature(CPU_FEATURE_MMX)) && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) - { + { /*Instruction might pair with next*/ u_pipe_full = 1; u_pipe_opcode = opcode; diff --git a/src/cpu/codegen_timing_winchip.c b/src/cpu/codegen_timing_winchip.c index dd2123f49..c945d7f21 100644 --- a/src/cpu/codegen_timing_winchip.c +++ b/src/cpu/codegen_timing_winchip.c @@ -313,7 +313,7 @@ void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; break; - + case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; @@ -368,13 +368,13 @@ void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; opcode = (fetchdat >> 3) & 7; break; - + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; @@ -397,12 +397,12 @@ void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, break; } } - + timing_count += COUNT(timings[opcode], op_32); if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) timing_count++; /*AGI stall*/ codegen_block_cycles += timing_count; - + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); } diff --git a/src/cpu/codegen_timing_winchip2.c b/src/cpu/codegen_timing_winchip2.c index 06cc06697..38c8924d4 100644 --- a/src/cpu/codegen_timing_winchip2.c +++ b/src/cpu/codegen_timing_winchip2.c @@ -582,7 +582,7 @@ static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, in timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; break; - + case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; @@ -637,13 +637,13 @@ static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, in deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; opcode = (fetchdat >> 3) & 7; break; - + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; break; - + case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; @@ -666,11 +666,11 @@ static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, in break; } } - + if (u_pipe_full) { uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); - + if (can_pair(u_pipe_timings[u_pipe_opcode], timings[opcode], regmask)) { int cycles_a = u_pipe_timings[u_pipe_opcode] & 0xff; @@ -711,7 +711,7 @@ static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, in decode_delay_offset = 0; return; } - + if (check_agi(deps, opcode, fetchdat, op_32)) agi_stall = 1; codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); @@ -724,7 +724,7 @@ static void codegen_timing_winchip2_block_end() if (u_pipe_full) { int agi_stall = 0; - + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) agi_stall = 1; codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index aa942acd9..9942269bf 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1,42 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 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 VARCem Project. + * This file is part of the 86Box distribution. * * CPU type handler. * - * - * - * Authors: Fred N. van Kempen, - * Sarah Walker, + * Authors: Sarah Walker, * leilei, * Miran Grca, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 leilei. * Copyright 2016-2018 Miran Grca. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2018 Fred N. van Kempen. */ #include #include @@ -56,197 +36,126 @@ #include <86box/nmi.h> #include <86box/pic.h> #include <86box/pci.h> +#include <86box/gdbstub.h> #ifdef USE_DYNAREC # include "codegen.h" #endif #include "x87_timings.h" -/*#define ENABLE_CPU_LOG 1*/ +#define CCR1_USE_SMI (1 << 1) +#define CCR1_SMAC (1 << 2) +#define CCR1_SM3 (1 << 7) -static void cpu_write(uint16_t addr, uint8_t val, void *priv); -static uint8_t cpu_read(uint16_t addr, void *priv); +#define CCR3_SMI_LOCK (1 << 0) +#define CCR3_NMI_EN (1 << 1) enum { - CPUID_FPU = (1 << 0), - CPUID_VME = (1 << 1), - CPUID_PSE = (1 << 3), - CPUID_TSC = (1 << 4), - CPUID_MSR = (1 << 5), - CPUID_PAE = (1 << 6), - CPUID_CMPXCHG8B = (1 << 8), - CPUID_AMDSEP = (1 << 10), - CPUID_SEP = (1 << 11), - CPUID_MTRR = (1 << 12), - CPUID_CMOV = (1 << 15), - CPUID_MMX = (1 << 23), - CPUID_FXSR = (1 << 24) + CPUID_FPU = (1 << 0), + CPUID_VME = (1 << 1), + CPUID_PSE = (1 << 3), + CPUID_TSC = (1 << 4), + CPUID_MSR = (1 << 5), + CPUID_PAE = (1 << 6), + CPUID_MCE = (1 << 7), + CPUID_CMPXCHG8B = (1 << 8), + CPUID_AMDSEP = (1 << 10), + CPUID_SEP = (1 << 11), + CPUID_MTRR = (1 << 12), + CPUID_MCA = (1 << 14), + CPUID_CMOV = (1 << 15), + CPUID_MMX = (1 << 23), + CPUID_FXSR = (1 << 24) }; /*Addition flags returned by CPUID function 0x80000001*/ -enum -{ - CPUID_3DNOW = (1 << 31) -}; +#define CPUID_3DNOW (1UL << 31UL) +/* Make sure this is as low as possible. */ +cpu_state_t cpu_state; + #ifdef USE_DYNAREC -const OpFn *x86_dynarec_opcodes; -const OpFn *x86_dynarec_opcodes_0f; -const OpFn *x86_dynarec_opcodes_d8_a16; -const OpFn *x86_dynarec_opcodes_d8_a32; -const OpFn *x86_dynarec_opcodes_d9_a16; -const OpFn *x86_dynarec_opcodes_d9_a32; -const OpFn *x86_dynarec_opcodes_da_a16; -const OpFn *x86_dynarec_opcodes_da_a32; -const OpFn *x86_dynarec_opcodes_db_a16; -const OpFn *x86_dynarec_opcodes_db_a32; -const OpFn *x86_dynarec_opcodes_dc_a16; -const OpFn *x86_dynarec_opcodes_dc_a32; -const OpFn *x86_dynarec_opcodes_dd_a16; -const OpFn *x86_dynarec_opcodes_dd_a32; -const OpFn *x86_dynarec_opcodes_de_a16; -const OpFn *x86_dynarec_opcodes_de_a32; -const OpFn *x86_dynarec_opcodes_df_a16; -const OpFn *x86_dynarec_opcodes_df_a32; -const OpFn *x86_dynarec_opcodes_REPE; -const OpFn *x86_dynarec_opcodes_REPNE; -const OpFn *x86_dynarec_opcodes_3DNOW; +const OpFn *x86_dynarec_opcodes, *x86_dynarec_opcodes_0f, + *x86_dynarec_opcodes_d8_a16, *x86_dynarec_opcodes_d8_a32, + *x86_dynarec_opcodes_d9_a16, *x86_dynarec_opcodes_d9_a32, + *x86_dynarec_opcodes_da_a16, *x86_dynarec_opcodes_da_a32, + *x86_dynarec_opcodes_db_a16, *x86_dynarec_opcodes_db_a32, + *x86_dynarec_opcodes_dc_a16, *x86_dynarec_opcodes_dc_a32, + *x86_dynarec_opcodes_dd_a16, *x86_dynarec_opcodes_dd_a32, + *x86_dynarec_opcodes_de_a16, *x86_dynarec_opcodes_de_a32, + *x86_dynarec_opcodes_df_a16, *x86_dynarec_opcodes_df_a32, + *x86_dynarec_opcodes_REPE, *x86_dynarec_opcodes_REPNE, + *x86_dynarec_opcodes_3DNOW; #endif -const OpFn *x86_opcodes; -const OpFn *x86_opcodes_0f; -const OpFn *x86_opcodes_d8_a16; -const OpFn *x86_opcodes_d8_a32; -const OpFn *x86_opcodes_d9_a16; -const OpFn *x86_opcodes_d9_a32; -const OpFn *x86_opcodes_da_a16; -const OpFn *x86_opcodes_da_a32; -const OpFn *x86_opcodes_db_a16; -const OpFn *x86_opcodes_db_a32; -const OpFn *x86_opcodes_dc_a16; -const OpFn *x86_opcodes_dc_a32; -const OpFn *x86_opcodes_dd_a16; -const OpFn *x86_opcodes_dd_a32; -const OpFn *x86_opcodes_de_a16; -const OpFn *x86_opcodes_de_a32; -const OpFn *x86_opcodes_df_a16; -const OpFn *x86_opcodes_df_a32; -const OpFn *x86_opcodes_REPE; -const OpFn *x86_opcodes_REPNE; -const OpFn *x86_opcodes_3DNOW; +const OpFn *x86_opcodes, *x86_opcodes_0f, + *x86_opcodes_d8_a16, *x86_opcodes_d8_a32, + *x86_opcodes_d9_a16, *x86_opcodes_d9_a32, + *x86_opcodes_da_a16, *x86_opcodes_da_a32, + *x86_opcodes_db_a16, *x86_opcodes_db_a32, + *x86_opcodes_dc_a16, *x86_opcodes_dc_a32, + *x86_opcodes_dd_a16, *x86_opcodes_dd_a32, + *x86_opcodes_de_a16, *x86_opcodes_de_a32, + *x86_opcodes_df_a16, *x86_opcodes_df_a32, + *x86_opcodes_REPE, *x86_opcodes_REPNE, + *x86_opcodes_3DNOW; -int in_smm = 0, smi_line = 0, smi_latched = 0, smm_in_hlt = 0; -uint32_t smbase = 0x30000; - -CPU *cpu_s; -int cpu_effective; -int cpu_multi; -double cpu_dmulti; -int cpu_16bitbus, cpu_64bitbus; -int cpu_busspeed; -int cpu_cyrix_alignment; -int CPUID; -uint64_t cpu_CR4_mask; -int isa_cycles; -int cpu_cycles_read, cpu_cycles_read_l, - cpu_cycles_write, cpu_cycles_write_l; -int cpu_prefetch_cycles, cpu_prefetch_width, - cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; -int cpu_waitstates; -int cpu_cache_int_enabled, cpu_cache_ext_enabled; -int cpu_pci_speed, cpu_alt_reset; uint16_t cpu_fast_off_count, cpu_fast_off_val; -uint32_t cpu_fast_off_flags; - -uint32_t cpu_features; - -int is286, - is386, - is486 = 1, - is486sx, is486dx, is486sx2, is486dx2, isdx4, - cpu_iscyrix, - hascache, - isibm486, - israpidcad, - is_am486, is_pentium, is_k5, is_k6, is_p6; - -int hasfpu; - -uint64_t tsc = 0; -msr_t msr; -cpu_state_t cpu_state; -uint64_t pmc[2] = {0, 0}; - uint16_t temp_seg_data[4] = {0, 0, 0, 0}; -uint64_t mtrr_cap_msr = 0x00000508; -uint64_t mtrr_physbase_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; -uint64_t mtrr_physmask_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; -uint64_t mtrr_fix64k_8000_msr = 0; -uint64_t mtrr_fix16k_8000_msr = 0; -uint64_t mtrr_fix16k_a000_msr = 0; -uint64_t mtrr_fix4k_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; -uint64_t mtrr_deftype_msr = 0; +int isa_cycles, cpu_inited, -uint16_t cs_msr = 0; -uint32_t esp_msr = 0; -uint32_t eip_msr = 0; -uint64_t apic_base_msr = 0; -uint64_t pat_msr = 0; -uint64_t msr_ia32_pmc[8] = {0, 0, 0, 0, 0, 0, 0, 0}; -uint64_t ecx17_msr = 0; -uint64_t ecx2a_msr = 0; -uint64_t ecx79_msr = 0; -uint64_t ecx8x_msr[4] = {0, 0, 0, 0}; -uint64_t ecx116_msr = 0; -uint64_t ecx11x_msr[4] = {0, 0, 0, 0}; -uint64_t ecx11e_msr = 0; -uint64_t ecx186_msr = 0; -uint64_t ecx187_msr = 0; -uint64_t ecx1e0_msr = 0; + cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l, + cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles, + cpu_waitstates, cpu_cache_int_enabled, cpu_cache_ext_enabled, + cpu_isa_speed, cpu_pci_speed, cpu_isa_pci_div, cpu_agp_speed, cpu_alt_reset, -/* Model Identification MSR's used by some Acer BIOSes*/ -uint64_t ecx404_msr = 0; -uint64_t ecx408_msr = 0; -uint64_t ecx40c_msr = 0; -uint64_t ecx410_msr = 0; -uint64_t ecx570_msr = 0; + cpu_override, cpu_effective, cpu_multi, cpu_16bitbus, cpu_64bitbus, cpu_busspeed, + cpu_cyrix_alignment, CPUID, -uint64_t ecx83_msr = 0; /* AMD K5 and K6 MSR's. */ + is286, is386, is6117, is486 = 1, + cpu_isintel, cpu_iscyrix, hascache, isibm486, israpidcad, is_vpc, + is_am486, is_am486dxl, is_pentium, is_k5, is_k6, is_p6, is_cxsmm, hasfpu, -/* MSR used by some Intel AMI boards */ -uint64_t ecx1002ff_msr = 0; + timing_rr, timing_mr, timing_mrl, timing_rm, timing_rml, + timing_mm, timing_mml, timing_bt, timing_bnt, + timing_int, timing_int_rm, timing_int_v86, timing_int_pm, + timing_int_pm_outer, timing_iret_rm, timing_iret_v86, timing_iret_pm, + timing_iret_pm_outer, timing_call_rm, timing_call_pm, timing_call_pm_gate, + timing_call_pm_gate_inner, timing_retf_rm, timing_retf_pm, timing_retf_pm_outer, + timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate, timing_misaligned; +uint32_t cpu_features, cpu_fast_off_flags; -/* Some weird long MSR's used by i686 AMI & some Phoenix BIOSes */ -uint64_t ecxf0f00250_msr = 0; -uint64_t ecxf0f00258_msr = 0; +uint32_t _tr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint32_t cache_index = 0; +uint8_t _cache[2048]; -uint64_t star = 0; /* AMD K6-2+. */ +uint64_t cpu_CR4_mask, tsc = 0; +uint64_t pmc[2] = {0, 0}; -uint64_t amd_efer = 0, amd_whcr = 0, - amd_uwccr = 0, amd_epmr = 0, /* AMD K6-2+ registers. */ - amd_psor = 0, amd_pfir = 0, - amd_l2aar = 0; +double cpu_dmulti; -int timing_rr; -int timing_mr, timing_mrl; -int timing_rm, timing_rml; -int timing_mm, timing_mml; -int timing_bt, timing_bnt; -int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, - timing_int_pm_outer; -int timing_iret_rm, timing_iret_v86, timing_iret_pm, - timing_iret_pm_outer; -int timing_call_rm, timing_call_pm, timing_call_pm_gate, - timing_call_pm_gate_inner; -int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; -int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; -int timing_misaligned; +msr_t msr; + +cyrix_t cyrix; + +cpu_family_t *cpu_f; +CPU *cpu_s; + +uint8_t do_translate = 0, do_translate2 = 0; + +void (*cpu_exec)(int cycs); static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; +static int cyrix_addr; + + +static void cpu_write(uint16_t addr, uint8_t val, void *priv); +static uint8_t cpu_read(uint16_t addr, void *priv); + #ifdef ENABLE_CPU_LOG int cpu_do_log = ENABLE_CPU_LOG; @@ -271,1454 +180,1299 @@ cpu_log(const char *fmt, ...) int cpu_has_feature(int feature) { - return cpu_features & feature; + return cpu_features & feature; } void cpu_dynamic_switch(int new_cpu) { - if (cpu_effective == new_cpu) - return; + int c; - int c = cpu; - cpu = new_cpu; - cpu_set(); - pc_speed_changed(); - cpu = c; + if (cpu_effective == new_cpu) + return; + + c = cpu; + cpu = new_cpu; + cpu_set(); + pc_speed_changed(); + cpu = c; } void cpu_set_edx(void) { - EDX = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].edx_reset; + EDX = cpu_s->edx_reset; } -int fpu_get_type(int machine, int cpu_manufacturer, int cpu, const char *internal_name) + +cpu_family_t * +cpu_get_family(const char *internal_name) { - CPU *cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu]; - const FPU *fpus = cpu_s->fpus; - int fpu_type = fpus[0].type; - int c = 0; - - while (fpus[c].internal_name) - { - if (!strcmp(internal_name, fpus[c].internal_name)) - fpu_type = fpus[c].type; - c++; - } - - return fpu_type; + int c = 0; + + while (cpu_families[c].package) { + if (!strcmp(internal_name, cpu_families[c].internal_name)) + return (cpu_family_t *) &cpu_families[c]; + c++; + } + + return NULL; } -const char *fpu_get_internal_name(int machine, int cpu_manufacturer, int cpu, int type) + +uint8_t +cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) { - CPU *cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu]; - const FPU *fpus = cpu_s->fpus; - int c = 0; + const machine_t *machine_s = &machines[machine]; + const CPU *cpu_s = &cpu_family->cpus[cpu]; + uint32_t packages, bus_speed; + uint8_t i; + double multi; - while (fpus[c].internal_name) - { - if (fpus[c].type == type) - return fpus[c].internal_name; - c++; - } + /* Full override. */ + if (cpu_override > 1) + return 1; - return fpus[0].internal_name; + /* Add implicit CPU package compatibility. */ + packages = machine_s->cpu.package; + if (packages & CPU_PKG_SOCKET3) + packages |= CPU_PKG_SOCKET1; + else if (packages & CPU_PKG_SLOT1) + packages |= CPU_PKG_SOCKET370; + + /* Package type. */ + if (!(cpu_family->package & packages)) + return 0; + + /* Partial override. */ + if (cpu_override) + return 1; + + /* Check CPU blocklist. */ + if (machine_s->cpu.block) { + i = 0; + + while (machine_s->cpu.block[i]) { + if (machine_s->cpu.block[i++] == cpu_s->cpu_type) + return 0; + } + } + + bus_speed = cpu_s->rspeed / cpu_s->multi; + + /* Minimum bus speed with ~0.84 MHz (for 8086) tolerance. */ + if (machine_s->cpu.min_bus && (bus_speed < (machine_s->cpu.min_bus - 840907))) + return 0; + + /* Maximum bus speed with ~0.84 MHz (for 8086) tolerance. */ + if (machine_s->cpu.max_bus && (bus_speed > (machine_s->cpu.max_bus + 840907))) + return 0; + + /* Minimum voltage with 0.1V tolerance. */ + if (machine_s->cpu.min_voltage && (cpu_s->voltage < (machine_s->cpu.min_voltage - 100))) + return 0; + + /* Maximum voltage with 0.1V tolerance. */ + if (machine_s->cpu.max_voltage && (cpu_s->voltage > (machine_s->cpu.max_voltage + 100))) + return 0; + + /* Account for CPUs which use a different internal multiplier than specified by jumpers. */ + multi = cpu_s->multi; + + /* Don't care about multiplier compatibility on fixed multiplier CPUs. */ + if (cpu_s->cpu_flags & CPU_FIXED_MULTIPLIER) + return 1; + else if (cpu_family->package & CPU_PKG_SOCKET5_7) { + if ((multi == 1.5) && (cpu_s->cpu_type == CPU_5K86) && (machine_s->cpu.min_multi > 1.5)) /* K5 5k86 */ + multi = 2.0; + else if (multi == 1.75) /* K5 5k86 */ + multi = 2.5; + else if (multi == 2.0) { + if (cpu_s->cpu_type == CPU_5K86) /* K5 5k86 */ + multi = 3.0; + /* K6-2+ / K6-3+ */ + else if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P)) + multi = 2.5; + else if (((cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type == CPU_WINCHIP2)) && + (machine_s->cpu.min_multi > 2.0)) /* WinChip (2) */ + multi = 2.5; + } + else if (multi == (7.0 / 3.0)) /* WinChip 2A - 2.33x */ + multi = 5.0; + else if (multi == (8.0 / 3.0)) /* WinChip 2A - 2.66x */ + multi = 5.5; + else if ((multi == 3.0) && (cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86L)) /* 6x86(L) */ + multi = 1.5; + else if (multi == (10.0 / 3.0)) /* WinChip 2A - 3.33x */ + multi = 2.0; + else if (multi == 3.5) /* standard set by the Pentium MMX */ + multi = 1.5; + else if (multi == 4.0) { + /* WinChip (2) */ + if ((cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type == CPU_WINCHIP2)) { + if (machine_s->cpu.min_multi >= 1.5) + multi = 1.5; + else if (machine_s->cpu.min_multi >= 3.5) + multi = 3.5; + else if (machine_s->cpu.min_multi >= 4.5) + multi = 4.5; + } else if ((cpu_s->cpu_type == CPU_Cx6x86) || (cpu_s->cpu_type == CPU_Cx6x86L)) /* 6x86(L) */ + multi = 3.0; + } else if ((multi == 5.0) && ((cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type == CPU_WINCHIP2)) && + (machine_s->cpu.min_multi > 5.0)) /* WinChip (2) */ + multi = 5.5; + else if (multi == 6.0) /* K6-2(+) / K6-3(+) */ + multi = 2.0; + } + + /* Minimum multiplier, */ + if (multi < machine_s->cpu.min_multi) + return 0; + + /* Maximum multiplier. */ + if (machine_s->cpu.max_multi && (multi > machine_s->cpu.max_multi)) + return 0; + + return 1; } -const char *fpu_get_name_from_index(int machine, int cpu_manufacturer, int cpu, int c) + +uint8_t +cpu_family_is_eligible(const cpu_family_t *cpu_family, int machine) { - CPU *cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu]; - const FPU *fpus = cpu_s->fpus; - - return fpus[c].name; + int c = 0; + + while (cpu_family->cpus[c].cpu_type) { + if (cpu_is_eligible(cpu_family, c, machine)) + return 1; + c++; + } + + return 0; } -int fpu_get_type_from_index(int machine, int cpu_manufacturer, int cpu, int c) -{ - CPU *cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu]; - const FPU *fpus = cpu_s->fpus; - - return fpus[c].type; -} void cpu_set(void) { - if (!machines[machine].cpu[cpu_manufacturer].cpus) - { - /*CPU is invalid, set to default*/ - cpu_manufacturer = 0; - cpu = 0; - } + cpu_inited = 1; - cpu_effective = cpu; - cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + cpu_effective = cpu; + cpu_s = (CPU *) &cpu_f->cpus[cpu_effective]; - cpu_alt_reset = 0; +#ifdef USE_ACYCS + acycs = 0; +#endif - CPUID = cpu_s->cpuid_model; - is8086 = (cpu_s->cpu_type > CPU_8088); - is286 = (cpu_s->cpu_type >= CPU_286); - is386 = (cpu_s->cpu_type >= CPU_386SX); - israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); - isibm486 = (cpu_s->cpu_type == CPU_IBM486SLC) || (cpu_s->cpu_type == CPU_IBM486BL); - is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD); - is486sx = (cpu_s->cpu_type >= CPU_i486SX) && (cpu_s->cpu_type < CPU_i486SX2); - is486sx2 = (cpu_s->cpu_type >= CPU_i486SX2) && (cpu_s->cpu_type < CPU_i486DX); - is486dx = (cpu_s->cpu_type >= CPU_i486DX) && (cpu_s->cpu_type < CPU_i486DX2); - is486dx2 = (cpu_s->cpu_type >= CPU_i486DX2) && (cpu_s->cpu_type < CPU_iDX4); - isdx4 = (cpu_s->cpu_type >= CPU_iDX4) && (cpu_s->cpu_type < CPU_WINCHIP); - is_am486 = (cpu_s->cpu_type == CPU_Am486SX) || (cpu_s->cpu_type == CPU_Am486SX2) || (cpu_s->cpu_type == CPU_Am486DX) || - (cpu_s->cpu_type == CPU_Am486DX2) || (cpu_s->cpu_type == CPU_Am486DX4) || (cpu_s->cpu_type == CPU_Am5x86); - is_pentium = (cpu_s->cpu_type == CPU_P24T) || (cpu_s->cpu_type == CPU_PENTIUM) || (cpu_s->cpu_type == CPU_PENTIUMMMX); - /* Not Pentiums, but they share the same SMM save state table layout. */ - is_pentium |= (cpu_s->cpu_type == CPU_i486DX2) || (cpu_s->cpu_type == CPU_iDX4); - /* The WinChip datasheet claims these are Pentium-compatible. */ - is_pentium |= (cpu_s->cpu_type == CPU_WINCHIP) || (cpu_s->cpu_type == CPU_WINCHIP2); -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) - is_k5 = (cpu_s->cpu_type == CPU_K5) || (cpu_s->cpu_type == CPU_5K86); + soft_reset_pci = 0; + + cpu_alt_reset = 0; + unmask_a20_in_smm = 0; + + CPUID = cpu_s->cpuid_model; + is8086 = (cpu_s->cpu_type > CPU_8088); + is286 = (cpu_s->cpu_type >= CPU_286); + is386 = (cpu_s->cpu_type >= CPU_386SX); + israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); + isibm486 = (cpu_s->cpu_type == CPU_IBM386SLC) || (cpu_s->cpu_type == CPU_IBM486SLC) || + (cpu_s->cpu_type == CPU_IBM486BL); + is486 = (cpu_s->cpu_type >= CPU_RAPIDCAD); + is_am486 = (cpu_s->cpu_type == CPU_ENH_Am486DX); + is_am486dxl = (cpu_s->cpu_type == CPU_Am486DXL); + + is6117 = !strcmp(cpu_f->manufacturer, "ALi"); + + cpu_isintel = !strcmp(cpu_f->manufacturer, "Intel"); + cpu_iscyrix = !strcmp(cpu_f->manufacturer, "Cyrix") || !strcmp(cpu_f->manufacturer, "ST"); + + /* SL-Enhanced Intel 486s have the same SMM save state table layout as Pentiums, + and the WinChip datasheet claims those are Pentium-compatible as well. AMD Am486DXL/DXL2 also has compatible SMM, or would if not for it's different SMBase*/ + is_pentium = (cpu_isintel && (cpu_s->cpu_type >= CPU_i486SX_SLENH) && (cpu_s->cpu_type < CPU_PENTIUMPRO)) || + !strcmp(cpu_f->manufacturer, "IDT") || (cpu_s->cpu_type == CPU_Am486DXL); + is_k5 = !strcmp(cpu_f->manufacturer, "AMD") && (cpu_s->cpu_type > CPU_ENH_Am486DX) && (cpu_s->cpu_type < CPU_K6); + is_k6 = (cpu_s->cpu_type >= CPU_K6) && !strcmp(cpu_f->manufacturer, "AMD"); + /* The Samuel 2 datasheet claims it's Celeron-compatible. */ + is_p6 = (cpu_isintel && (cpu_s->cpu_type >= CPU_PENTIUMPRO)) || !strcmp(cpu_f->manufacturer, "VIA"); + is_cxsmm = (!strcmp(cpu_f->manufacturer, "Cyrix") || !strcmp(cpu_f->manufacturer, "ST")) && + (cpu_s->cpu_type >= CPU_Cx486S); + + hasfpu = (fpu_type != FPU_NONE); + hascache = (cpu_s->cpu_type >= CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) || + (cpu_s->cpu_type == CPU_IBM486SLC) || (cpu_s->cpu_type == CPU_IBM486BL); + + cpu_16bitbus = (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || + (cpu_s->cpu_type == CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) || + (cpu_s->cpu_type == CPU_IBM486SLC); + cpu_64bitbus = (cpu_s->cpu_type >= CPU_WINCHIP); + + if (cpu_s->multi) + cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + else + cpu_busspeed = cpu_s->rspeed; + cpu_multi = (int) ceil(cpu_s->multi); + cpu_dmulti = cpu_s->multi; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + + cpu_update_waitstates(); + + isa_cycles = cpu_s->atclk_div; + + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; + else + cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; + + cpu_set_isa_pci_div(0); + cpu_set_pci_speed(0); + cpu_set_agp_speed(0); + + io_handler(cpu_iscyrix, 0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + + io_handler(hasfpu, 0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + io_handler(hasfpu, 0xf007, 0x0001, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); #else - is_k5 = 0; + x86_setopcodes(ops_386, ops_386_0f); #endif - is_k6 = (cpu_s->cpu_type == CPU_K6) || (cpu_s->cpu_type == CPU_K6_2) || - (cpu_s->cpu_type == CPU_K6_2C) || (cpu_s->cpu_type == CPU_K6_3) || - (cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P); - is_p6 = (cpu_s->cpu_type == CPU_PENTIUMPRO) || (cpu_s->cpu_type == CPU_PENTIUM2) || - (cpu_s->cpu_type == CPU_PENTIUM2D); - /* The Samuel 2 datasheet claims it's Celeron-compatible. */ - is_p6 |= (cpu_s->cpu_type == CPU_CYRIX3S); - hasfpu = (fpu_type != FPU_NONE); - hascache = (cpu_s->cpu_type >= CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC || cpu_s->cpu_type == CPU_IBM486SLC || cpu_s->cpu_type == CPU_IBM486BL); -#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) - cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); + x86_opcodes_REPE = ops_REPE; + x86_opcodes_REPNE = ops_REPNE; + x86_opcodes_3DNOW = ops_3DNOW; +#ifdef USE_DYNAREC + x86_dynarec_opcodes_REPE = dynarec_ops_REPE; + x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE; + x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW; +#endif + + if (hasfpu) { +#ifdef USE_DYNAREC + x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; +#endif + x86_opcodes_d8_a16 = ops_fpu_d8_a16; + x86_opcodes_d8_a32 = ops_fpu_d8_a32; + x86_opcodes_d9_a16 = ops_fpu_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_d9_a32; + x86_opcodes_da_a16 = ops_fpu_da_a16; + x86_opcodes_da_a32 = ops_fpu_da_a32; + x86_opcodes_db_a16 = ops_fpu_db_a16; + x86_opcodes_db_a32 = ops_fpu_db_a32; + x86_opcodes_dc_a16 = ops_fpu_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_dd_a32; + x86_opcodes_de_a16 = ops_fpu_de_a16; + x86_opcodes_de_a32 = ops_fpu_de_a32; + x86_opcodes_df_a16 = ops_fpu_df_a16; + x86_opcodes_df_a32 = ops_fpu_df_a32; + } else { +#ifdef USE_DYNAREC + x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; +#endif + x86_opcodes_d8_a16 = ops_nofpu_a16; + x86_opcodes_d8_a32 = ops_nofpu_a32; + x86_opcodes_d9_a16 = ops_nofpu_a16; + x86_opcodes_d9_a32 = ops_nofpu_a32; + x86_opcodes_da_a16 = ops_nofpu_a16; + x86_opcodes_da_a32 = ops_nofpu_a32; + x86_opcodes_db_a16 = ops_nofpu_a16; + x86_opcodes_db_a32 = ops_nofpu_a32; + x86_opcodes_dc_a16 = ops_nofpu_a16; + x86_opcodes_dc_a32 = ops_nofpu_a32; + x86_opcodes_dd_a16 = ops_nofpu_a16; + x86_opcodes_dd_a32 = ops_nofpu_a32; + x86_opcodes_de_a16 = ops_nofpu_a16; + x86_opcodes_de_a32 = ops_nofpu_a32; + x86_opcodes_df_a16 = ops_nofpu_a16; + x86_opcodes_df_a32 = ops_nofpu_a32; + } + +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_486); +#endif + + memset(&msr, 0, sizeof(msr)); + + timing_misaligned = 0; + cpu_cyrix_alignment = 0; + cpu_CR4_mask = 0; + + switch (cpu_s->cpu_type) { + case CPU_8088: + case CPU_8086: + break; + + case CPU_286: +#ifdef USE_DYNAREC + x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); #else - cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86); + x86_setopcodes(ops_286, ops_286_0f); #endif - cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_IBM386SLC || cpu_s->cpu_type == CPU_IBM486SLC ); - cpu_64bitbus = (cpu_s->cpu_type >= CPU_WINCHIP); - - if (cpu_s->multi) - cpu_busspeed = cpu_s->rspeed / cpu_s->multi; - else - cpu_busspeed = cpu_s->rspeed; - cpu_multi = (int) ceil(cpu_s->multi); - cpu_dmulti = cpu_s->multi; - ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; - - - - cpu_update_waitstates(); - - isa_cycles = cpu_s->atclk_div; - - if (cpu_s->rspeed <= 8000000) - cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; - else - cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; - - if (cpu_busspeed < 42500000) - cpu_pci_speed = cpu_busspeed; - else if ((cpu_busspeed > 42500000) && (cpu_busspeed < 84000000)) - cpu_pci_speed = cpu_busspeed / 2; - else - cpu_pci_speed = cpu_busspeed / 3; - - pci_burst_time = cpu_s->rspeed / cpu_pci_speed; - pci_nonburst_time = 4 * pci_burst_time; - - if (cpu_iscyrix) - io_sethandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); - else - io_removehandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); - - if (hasfpu) - io_sethandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); - else - io_removehandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); - + if (fpu_type == FPU_287) { #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); -#else - x86_setopcodes(ops_386, ops_386_0f); + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; #endif - x86_opcodes_REPE = ops_REPE; - x86_opcodes_REPNE = ops_REPNE; - x86_opcodes_3DNOW = ops_3DNOW; -#ifdef USE_DYNAREC - x86_dynarec_opcodes_REPE = dynarec_ops_REPE; - x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE; - x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW; -#endif - -#ifdef USE_DYNAREC - if (hasfpu) - { - x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; - x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; - x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; - x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; - x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; - x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; - x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; - x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; - x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; - x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; - } - else - { - x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; - } - codegen_timing_set(&codegen_timing_486); -#endif - - if (hasfpu) - { - x86_opcodes_d8_a16 = ops_fpu_d8_a16; - x86_opcodes_d8_a32 = ops_fpu_d8_a32; - x86_opcodes_d9_a16 = ops_fpu_d9_a16; - x86_opcodes_d9_a32 = ops_fpu_d9_a32; - x86_opcodes_da_a16 = ops_fpu_da_a16; - x86_opcodes_da_a32 = ops_fpu_da_a32; - x86_opcodes_db_a16 = ops_fpu_db_a16; - x86_opcodes_db_a32 = ops_fpu_db_a32; - x86_opcodes_dc_a16 = ops_fpu_dc_a16; - x86_opcodes_dc_a32 = ops_fpu_dc_a32; - x86_opcodes_dd_a16 = ops_fpu_dd_a16; - x86_opcodes_dd_a32 = ops_fpu_dd_a32; - x86_opcodes_de_a16 = ops_fpu_de_a16; - x86_opcodes_de_a32 = ops_fpu_de_a32; - x86_opcodes_df_a16 = ops_fpu_df_a16; - x86_opcodes_df_a32 = ops_fpu_df_a32; - } - else - { - x86_opcodes_d8_a16 = ops_nofpu_a16; - x86_opcodes_d8_a32 = ops_nofpu_a32; - x86_opcodes_d9_a16 = ops_nofpu_a16; - x86_opcodes_d9_a32 = ops_nofpu_a32; - x86_opcodes_da_a16 = ops_nofpu_a16; - x86_opcodes_da_a32 = ops_nofpu_a32; - x86_opcodes_db_a16 = ops_nofpu_a16; - x86_opcodes_db_a32 = ops_nofpu_a32; - x86_opcodes_dc_a16 = ops_nofpu_a16; - x86_opcodes_dc_a32 = ops_nofpu_a32; - x86_opcodes_dd_a16 = ops_nofpu_a16; - x86_opcodes_dd_a32 = ops_nofpu_a32; - x86_opcodes_de_a16 = ops_nofpu_a16; - x86_opcodes_de_a32 = ops_nofpu_a32; - x86_opcodes_df_a16 = ops_nofpu_a16; - x86_opcodes_df_a32 = ops_nofpu_a32; - } - - memset(&msr, 0, sizeof(msr)); - - timing_misaligned = 0; - cpu_cyrix_alignment = 0; - - switch (cpu_s->cpu_type) - { - case CPU_8088: - case CPU_8086: - break; - - case CPU_286: -#ifdef USE_DYNAREC - x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); -#else - x86_setopcodes(ops_286, ops_286_0f); -#endif - if (fpu_type == FPU_287) - { -#ifdef USE_DYNAREC - x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; - x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; - x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; - x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; - x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; - x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; - x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; - x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; -#endif - x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; - x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; - x86_opcodes_da_a16 = ops_fpu_287_da_a16; - x86_opcodes_da_a32 = ops_fpu_287_da_a32; - x86_opcodes_db_a16 = ops_fpu_287_db_a16; - x86_opcodes_db_a32 = ops_fpu_287_db_a32; - x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; - x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; - x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; - x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; - x86_opcodes_de_a16 = ops_fpu_287_de_a16; - x86_opcodes_de_a32 = ops_fpu_287_de_a32; - x86_opcodes_df_a16 = ops_fpu_287_df_a16; - x86_opcodes_df_a32 = ops_fpu_287_df_a32; + x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; + x86_opcodes_da_a16 = ops_fpu_287_da_a16; + x86_opcodes_da_a32 = ops_fpu_287_da_a32; + x86_opcodes_db_a16 = ops_fpu_287_db_a16; + x86_opcodes_db_a32 = ops_fpu_287_db_a32; + x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; + x86_opcodes_de_a16 = ops_fpu_287_de_a16; + x86_opcodes_de_a32 = ops_fpu_287_de_a32; + x86_opcodes_df_a16 = ops_fpu_287_df_a16; + x86_opcodes_df_a32 = ops_fpu_287_df_a32; } - timing_rr = 2; /*register dest - register src*/ - timing_rm = 7; /*register dest - memory src*/ - timing_mr = 7; /*memory dest - register src*/ - timing_mm = 7; /*memory dest - memory src*/ - timing_rml = 9; /*register dest - memory src long*/ - timing_mrl = 11; /*memory dest - register src long*/ - timing_mml = 11; /*memory dest - memory src*/ - timing_bt = 7-3; /*branch taken*/ - timing_bnt = 3; /*branch not taken*/ - timing_int = 0; - timing_int_rm = 23; - timing_int_v86 = 0; - timing_int_pm = 40; - timing_int_pm_outer = 78; - timing_iret_rm = 17; - timing_iret_v86 = 0; - timing_iret_pm = 31; - timing_iret_pm_outer = 55; - timing_call_rm = 13; - timing_call_pm = 26; - timing_call_pm_gate = 52; - timing_call_pm_gate_inner = 82; - timing_retf_rm = 15; - timing_retf_pm = 25; - timing_retf_pm_outer = 55; - timing_jmp_rm = 11; - timing_jmp_pm = 23; - timing_jmp_pm_gate = 38; - break; - - case CPU_IBM486SLC: + + timing_rr = 2; /* register dest - register src */ + timing_rm = 7; /* register dest - memory src */ + timing_mr = 7; /* memory dest - register src */ + timing_mm = 7; /* memory dest - memory src */ + timing_rml = 9; /* register dest - memory src long */ + timing_mrl = 11; /* memory dest - register src long */ + timing_mml = 11; /* memory dest - memory src */ + timing_bt = 4; /* branch taken */ + timing_bnt = 3; /* branch not taken */ + + timing_int = 0; + timing_int_rm = 23; + timing_int_v86 = 0; + timing_int_pm = 40; + timing_int_pm_outer = 78; + timing_iret_rm = 17; + timing_iret_v86 = 0; + timing_iret_pm = 31; + timing_iret_pm_outer = 55; + timing_call_rm = 13; + timing_call_pm = 26; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 82; + timing_retf_rm = 15; + timing_retf_pm = 25; + timing_retf_pm_outer = 55; + timing_jmp_rm = 11; + timing_jmp_pm = 23; + timing_jmp_pm_gate = 38; + break; + + case CPU_IBM486SLC: + case CPU_IBM386SLC: + case CPU_IBM486BL: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + x86_setopcodes(ops_386, ops_ibm486_0f, dynarec_ops_386, dynarec_ops_ibm486_0f); #else - x86_setopcodes(ops_386, ops_486_0f); + x86_setopcodes(ops_386, ops_ibm486_0f); #endif - case CPU_IBM386SLC: - case CPU_386SX: - timing_rr = 2; /*register dest - register src*/ - timing_rm = 6; /*register dest - memory src*/ - timing_mr = 7; /*memory dest - register src*/ - timing_mm = 6; /*memory dest - memory src*/ - timing_rml = 8; /*register dest - memory src long*/ - timing_mrl = 11; /*memory dest - register src long*/ - timing_mml = 10; /*memory dest - memory src*/ - timing_bt = 7-3; /*branch taken*/ - timing_bnt = 3; /*branch not taken*/ - timing_int = 0; - timing_int_rm = 37; - timing_int_v86 = 59; - timing_int_pm = 99; - timing_int_pm_outer = 119; - timing_iret_rm = 22; - timing_iret_v86 = 60; - timing_iret_pm = 38; - timing_iret_pm_outer = 82; - timing_call_rm = 17; - timing_call_pm = 34; - timing_call_pm_gate = 52; - timing_call_pm_gate_inner = 86; - timing_retf_rm = 18; - timing_retf_pm = 32; - timing_retf_pm_outer = 68; - timing_jmp_rm = 12; - timing_jmp_pm = 27; - timing_jmp_pm_gate = 45; - break; - - case CPU_IBM486BL: + cpu_features = CPU_FEATURE_MSR; + /* FALLTHROUGH */ + case CPU_386SX: + case CPU_386DX: + if (fpu_type == FPU_287) { /* In case we get Deskpro 386 emulation */ #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; +#endif + x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; + x86_opcodes_da_a16 = ops_fpu_287_da_a16; + x86_opcodes_da_a32 = ops_fpu_287_da_a32; + x86_opcodes_db_a16 = ops_fpu_287_db_a16; + x86_opcodes_db_a32 = ops_fpu_287_db_a32; + x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; + x86_opcodes_de_a16 = ops_fpu_287_de_a16; + x86_opcodes_de_a32 = ops_fpu_287_de_a32; + x86_opcodes_df_a16 = ops_fpu_287_df_a16; + x86_opcodes_df_a32 = ops_fpu_287_df_a32; + } + + timing_rr = 2; /* register dest - register src */ + timing_rm = 6; /* register dest - memory src */ + timing_mr = 7; /* memory dest - register src */ + timing_mm = 6; /* memory dest - memory src */ + if (cpu_s->cpu_type >= CPU_386DX) { + timing_rml = 6; /* register dest - memory src long */ + timing_mrl = 7; /* memory dest - register src long */ + timing_mml = 6; /* memory dest - memory src */ + } else { + timing_rml = 8; /* register dest - memory src long */ + timing_mrl = 11; /* memory dest - register src long */ + timing_mml = 10; /* memory dest - memory src */ + } + timing_bt = 4; /* branch taken */ + timing_bnt = 3; /* branch not taken */ + + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_486SLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); #else - x86_setopcodes(ops_386, ops_486_0f); + x86_setopcodes(ops_386, ops_486_0f); #endif - case CPU_386DX: - if (fpu_type == FPU_287) /*In case we get Deskpro 386 emulation*/ - { + + timing_rr = 1; /* register dest - register src */ + timing_rm = 3; /* register dest - memory src */ + timing_mr = 5; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 5; /* register dest - memory src long */ + timing_mrl = 7; /* memory dest - register src long */ + timing_mml = 7; + timing_bt = 5; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 4; /* unknown */ + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_486DLC: #ifdef USE_DYNAREC - x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; - x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; - x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; - x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; - x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; - x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; - x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; - x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; -#endif - x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; - x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; - x86_opcodes_da_a16 = ops_fpu_287_da_a16; - x86_opcodes_da_a32 = ops_fpu_287_da_a32; - x86_opcodes_db_a16 = ops_fpu_287_db_a16; - x86_opcodes_db_a32 = ops_fpu_287_db_a32; - x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; - x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; - x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; - x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; - x86_opcodes_de_a16 = ops_fpu_287_de_a16; - x86_opcodes_de_a32 = ops_fpu_287_de_a32; - x86_opcodes_df_a16 = ops_fpu_287_df_a16; - x86_opcodes_df_a32 = ops_fpu_287_df_a32; - } - timing_rr = 2; /*register dest - register src*/ - timing_rm = 6; /*register dest - memory src*/ - timing_mr = 7; /*memory dest - register src*/ - timing_mm = 6; /*memory dest - memory src*/ - timing_rml = 6; /*register dest - memory src long*/ - timing_mrl = 7; /*memory dest - register src long*/ - timing_mml = 6; /*memory dest - memory src*/ - timing_bt = 7-3; /*branch taken*/ - timing_bnt = 3; /*branch not taken*/ - timing_int = 0; - timing_int_rm = 37; - timing_int_v86 = 59; - timing_int_pm = 99; - timing_int_pm_outer = 119; - timing_iret_rm = 22; - timing_iret_v86 = 60; - timing_iret_pm = 38; - timing_iret_pm_outer = 82; - timing_call_rm = 17; - timing_call_pm = 34; - timing_call_pm_gate = 52; - timing_call_pm_gate_inner = 86; - timing_retf_rm = 18; - timing_retf_pm = 32; - timing_retf_pm_outer = 68; - timing_jmp_rm = 12; - timing_jmp_pm = 27; - timing_jmp_pm_gate = 45; - break; - - - case CPU_RAPIDCAD: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); #else - x86_setopcodes(ops_386, ops_486_0f); + x86_setopcodes(ops_386, ops_486_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 3-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 4; - timing_int_rm = 26; - timing_int_v86 = 82; - timing_int_pm = 44; - timing_int_pm_outer = 71; - timing_iret_rm = 15; - timing_iret_v86 = 36; /*unknown*/ - timing_iret_pm = 20; - timing_iret_pm_outer = 36; - timing_call_rm = 18; - timing_call_pm = 20; - timing_call_pm_gate = 35; - timing_call_pm_gate_inner = 69; - timing_retf_rm = 13; - timing_retf_pm = 17; - timing_retf_pm_outer = 35; - timing_jmp_rm = 17; - timing_jmp_pm = 19; - timing_jmp_pm_gate = 32; - timing_misaligned = 3; - break; - - case CPU_486SLC: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); -#else - x86_setopcodes(ops_386, ops_486_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 3; /*register dest - memory src*/ - timing_mr = 5; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 5; /*register dest - memory src long*/ - timing_mrl = 7; /*memory dest - register src long*/ - timing_mml = 7; - timing_bt = 6-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - /*unknown*/ - timing_int = 4; - timing_int_rm = 14; - timing_int_v86 = 82; - timing_int_pm = 49; - timing_int_pm_outer = 77; - timing_iret_rm = 14; - timing_iret_v86 = 66; - timing_iret_pm = 31; - timing_iret_pm_outer = 66; - timing_call_rm = 12; - timing_call_pm = 30; - timing_call_pm_gate = 41; - timing_call_pm_gate_inner = 83; - timing_retf_rm = 13; - timing_retf_pm = 26; - timing_retf_pm_outer = 61; - timing_jmp_rm = 9; - timing_jmp_pm = 26; - timing_jmp_pm_gate = 37; - timing_misaligned = 3; - break; - - case CPU_486DLC: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); -#else - x86_setopcodes(ops_386, ops_486_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 3; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 3; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 6-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - /*unknown*/ - timing_int = 4; - timing_int_rm = 14; - timing_int_v86 = 82; - timing_int_pm = 49; - timing_int_pm_outer = 77; - timing_iret_rm = 14; - timing_iret_v86 = 66; - timing_iret_pm = 31; - timing_iret_pm_outer = 66; - timing_call_rm = 12; - timing_call_pm = 30; - timing_call_pm_gate = 41; - timing_call_pm_gate_inner = 83; - timing_retf_rm = 13; - timing_retf_pm = 26; - timing_retf_pm_outer = 61; - timing_jmp_rm = 9; - timing_jmp_pm = 26; - timing_jmp_pm_gate = 37; - timing_misaligned = 3; - break; - - case CPU_iDX4: + + timing_rr = 1; /* register dest - register src */ + timing_rm = 3; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 3; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 5; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 4; /* unknown */ + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + + timing_misaligned = 3; + break; + + case CPU_i486SX_SLENH: + case CPU_i486DX_SLENH: cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; - /*FALLTHROUGH*/ - case CPU_i486SX: - case CPU_i486SX2: - case CPU_i486DX: - case CPU_i486DX2: + /* FALLTHROUGH */ + case CPU_RAPIDCAD: + case CPU_i486SX: + case CPU_i486DX: + case CPU_Am486SX: + case CPU_Am486DX: + case CPU_Am486DXL: + case CPU_ENH_Am486DX: + /*AMD timing identical to Intel*/ #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); #else - x86_setopcodes(ops_386, ops_486_0f); + x86_setopcodes(ops_386, ops_486_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 3-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 4; - timing_int_rm = 26; - timing_int_v86 = 82; - timing_int_pm = 44; - timing_int_pm_outer = 71; - timing_iret_rm = 15; - timing_iret_v86 = 36; /*unknown*/ - timing_iret_pm = 20; - timing_iret_pm_outer = 36; - timing_call_rm = 18; - timing_call_pm = 20; - timing_call_pm_gate = 35; - timing_call_pm_gate_inner = 69; - timing_retf_rm = 13; - timing_retf_pm = 17; - timing_retf_pm_outer = 35; - timing_jmp_rm = 17; - timing_jmp_pm = 19; - timing_jmp_pm_gate = 32; - timing_misaligned = 3; - break; - case CPU_Am486SX: - case CPU_Am486SX2: - case CPU_Am486DX: - case CPU_Am486DX2: - case CPU_Am486DX4: - case CPU_Am5x86: - /*AMD timing identical to Intel*/ -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); -#else - x86_setopcodes(ops_386, ops_486_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 3-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 4; - timing_int_rm = 26; - timing_int_v86 = 82; - timing_int_pm = 44; - timing_int_pm_outer = 71; - timing_iret_rm = 15; - timing_iret_v86 = 36; /*unknown*/ - timing_iret_pm = 20; - timing_iret_pm_outer = 36; - timing_call_rm = 18; - timing_call_pm = 20; - timing_call_pm_gate = 35; - timing_call_pm_gate_inner = 69; - timing_retf_rm = 13; - timing_retf_pm = 17; - timing_retf_pm_outer = 35; - timing_jmp_rm = 17; - timing_jmp_pm = 19; - timing_jmp_pm_gate = 32; - timing_misaligned = 3; - break; - - case CPU_Cx486S: - case CPU_Cx486DX: - case CPU_Cx486DX2: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); -#else - x86_setopcodes(ops_386, ops_486_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 3; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 3; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 4-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 4; - timing_int_rm = 14; - timing_int_v86 = 82; - timing_int_pm = 49; - timing_int_pm_outer = 77; - timing_iret_rm = 14; - timing_iret_v86 = 66; /*unknown*/ - timing_iret_pm = 31; - timing_iret_pm_outer = 66; - timing_call_rm = 12; - timing_call_pm = 30; - timing_call_pm_gate = 41; - timing_call_pm_gate_inner = 83; - timing_retf_rm = 13; - timing_retf_pm = 26; - timing_retf_pm_outer = 61; - timing_jmp_rm = 9; - timing_jmp_pm = 26; - timing_jmp_pm_gate = 37; - timing_misaligned = 3; - break; - - case CPU_Cx5x86: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); -#else - x86_setopcodes(ops_386, ops_486_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 1; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 2; - timing_rml = 1; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 2; - timing_bt = 5-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 0; - timing_int_rm = 9; - timing_int_v86 = 82; /*unknown*/ - timing_int_pm = 21; - timing_int_pm_outer = 32; - timing_iret_rm = 7; - timing_iret_v86 = 26; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 4; - timing_call_pm = 15; - timing_call_pm_gate = 26; - timing_call_pm_gate_inner = 35; - timing_retf_rm = 4; - timing_retf_pm = 7; - timing_retf_pm_outer = 23; - timing_jmp_rm = 5; - timing_jmp_pm = 7; - timing_jmp_pm_gate = 17; - timing_misaligned = 2; - cpu_cyrix_alignment = 1; - break; + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 2; /* branch taken */ + timing_bnt = 1; /* branch not taken */ - case CPU_WINCHIP: + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /* unknown */ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + + timing_misaligned = 3; + break; + + case CPU_Cx486S: + case CPU_Cx486DX: + case CPU_STPC: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); + if (cpu_s->cpu_type == CPU_STPC) + x86_setopcodes(ops_386, ops_stpc_0f, dynarec_ops_386, dynarec_ops_stpc_0f); + else + x86_setopcodes(ops_386, ops_c486_0f, dynarec_ops_386, dynarec_ops_c486_0f); #else - x86_setopcodes(ops_386, ops_winchip_0f); + if (cpu_s->cpu_type == CPU_STPC) + x86_setopcodes(ops_386, ops_stpc_0f); + else + x86_setopcodes(ops_386, ops_c486_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 3-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + + timing_rr = 1; /* register dest - register src */ + timing_rm = 3; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 3; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 3; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; /* unknown */ + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + + timing_misaligned = 3; + + if (cpu_s->cpu_type == CPU_STPC) + cpu_features = CPU_FEATURE_RDTSC; + break; + + case CPU_Cx5x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_c486_0f, dynarec_ops_386, dynarec_ops_c486_0f); +#else + x86_setopcodes(ops_386, ops_c486_0f); +#endif + + timing_rr = 1; /* register dest - register src */ + timing_rm = 1; /* register dest - memory src */ + timing_mr = 2; /* memory dest - register src */ + timing_mm = 2; + timing_rml = 1; /* register dest - memory src long */ + timing_mrl = 2; /* memory dest - register src long */ + timing_mml = 2; + timing_bt = 4; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 0; + timing_int_rm = 9; + timing_int_v86 = 82; /* unknown */ + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; /* unknown */ + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + + timing_misaligned = 2; + + cpu_cyrix_alignment = 1; + break; + + case CPU_WINCHIP: + case CPU_WINCHIP2: +#ifdef USE_DYNAREC + if (cpu_s->cpu_type == CPU_WINCHIP2) + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); + else + x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); +#else + if (cpu_s->cpu_type == CPU_WINCHIP2) + x86_setopcodes(ops_386, ops_winchip2_0f); + else + x86_setopcodes(ops_386, ops_winchip_0f); +#endif + + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 2; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 2; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 2; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + /*unknown*/ - timing_int_rm = 26; - timing_int_v86 = 82; - timing_int_pm = 44; - timing_int_pm_outer = 71; - timing_iret_rm = 7; - timing_iret_v86 = 26; - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 4; - timing_call_pm = 15; - timing_call_pm_gate = 26; - timing_call_pm_gate_inner = 35; - timing_retf_rm = 4; - timing_retf_pm = 7; - timing_retf_pm_outer = 23; - timing_jmp_rm = 5; - timing_jmp_pm = 7; - timing_jmp_pm_gate = 17; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_winchip); -#endif - timing_misaligned = 2; - cpu_cyrix_alignment = 1; - break; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; - case CPU_WINCHIP2: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); -#else - x86_setopcodes(ops_386, ops_winchip2_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 3-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21); - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; - /*unknown*/ - timing_int_rm = 26; - timing_int_v86 = 82; - timing_int_pm = 44; - timing_int_pm_outer = 71; - timing_iret_rm = 7; - timing_iret_v86 = 26; - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 4; - timing_call_pm = 15; - timing_call_pm_gate = 26; - timing_call_pm_gate_inner = 35; - timing_retf_rm = 4; - timing_retf_pm = 7; - timing_retf_pm_outer = 23; - timing_jmp_rm = 5; - timing_jmp_pm = 7; - timing_jmp_pm_gate = 17; - timing_misaligned = 2; - cpu_cyrix_alignment = 1; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_winchip2); -#endif - break; + timing_misaligned = 2; - case CPU_P24T: - case CPU_PENTIUM: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); -#else - x86_setopcodes(ops_386, ops_pentium_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 2; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_pentium); -#endif - break; + cpu_cyrix_alignment = 1; + + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4; + if (cpu_s->cpu_type == CPU_WINCHIP2) + cpu_features |= CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + if (cpu_s->cpu_type == CPU_WINCHIP2) + msr.fcr |= (1 << 18) | (1 << 20); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; - case CPU_PENTIUMMMX: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); + if (cpu_s->cpu_type == CPU_WINCHIP2) + codegen_timing_set(&codegen_timing_winchip2); + else + codegen_timing_set(&codegen_timing_winchip); +#endif + break; + + case CPU_P24T: + case CPU_PENTIUM: + case CPU_PENTIUMMMX: +#ifdef USE_DYNAREC + if (cpu_s->cpu_type == CPU_PENTIUMMMX) + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); + else + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); #else - x86_setopcodes(ops_386, ops_pentiummmx_0f); + if (cpu_s->cpu_type == CPU_PENTIUMMMX) + x86_setopcodes(ops_386, ops_pentiummmx_0f); + else + x86_setopcodes(ops_386, ops_pentium_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; + + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 0; /* branch taken */ + if (cpu_s->cpu_type == CPU_PENTIUMMMX) + timing_bnt = 1; /* branch not taken */ + else + timing_bnt = 2; /* branch not taken */ + + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /* unknown */ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + + timing_misaligned = 3; + + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; + if (cpu_s->cpu_type == CPU_PENTIUMMMX) + cpu_features |= CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_pentium); + codegen_timing_set(&codegen_timing_pentium); #endif - break; + break; #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) - case CPU_Cx6x86: + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + if (cpu_s->cpu_type == CPU_Cx6x86MX) { #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); -#else - x86_setopcodes(ops_386, ops_pentium_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 1; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 2; - timing_rml = 1; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 2; - timing_bt = 0; /*branch taken*/ - timing_bnt = 2; /*branch not taken*/ - timing_int_rm = 9; - timing_int_v86 = 46; - timing_int_pm = 21; - timing_int_pm_outer = 32; - timing_iret_rm = 7; - timing_iret_v86 = 26; - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 3; - timing_call_pm = 4; - timing_call_pm_gate = 15; - timing_call_pm_gate_inner = 26; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 1; - timing_jmp_pm = 4; - timing_jmp_pm_gate = 14; - timing_misaligned = 2; - cpu_cyrix_alignment = 1; - cpu_features = CPU_FEATURE_RDTSC; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_686); -#endif - CPUID = 0; /*Disabled on powerup by default*/ - break; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + } - case CPU_Cx6x86L: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + if (cpu_s->cpu_type == CPU_Cx6x86MX) + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + else if (cpu_s->cpu_type == CPU_Cx6x86L) + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + else + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + // x86_setopcodes(ops_386, ops_c6x86_0f, dynarec_ops_386, dynarec_ops_c6x86_0f); #else - x86_setopcodes(ops_386, ops_pentium_0f); + if (cpu_s->cpu_type == CPU_Cx6x86MX) + x86_setopcodes(ops_386, ops_c6x86mx_0f); + else if (cpu_s->cpu_type == CPU_Cx6x86L) + x86_setopcodes(ops_386, ops_pentium_0f); + else + x86_setopcodes(ops_386, ops_c6x86_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 1; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 2; - timing_rml = 1; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 2; - timing_bt = 0; /*branch taken*/ - timing_bnt = 2; /*branch not taken*/ - timing_int_rm = 9; - timing_int_v86 = 46; - timing_int_pm = 21; - timing_int_pm_outer = 32; - timing_iret_rm = 7; - timing_iret_v86 = 26; - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 3; - timing_call_pm = 4; - timing_call_pm_gate = 15; - timing_call_pm_gate_inner = 26; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 1; - timing_jmp_pm = 4; - timing_jmp_pm_gate = 14; - timing_misaligned = 2; - cpu_cyrix_alignment = 1; - cpu_features = CPU_FEATURE_RDTSC; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_686); -#endif - ccr4 = 0x80; - break; + timing_rr = 1; /* register dest - register src */ + timing_rm = 1; /* register dest - memory src */ + timing_mr = 2; /* memory dest - register src */ + timing_mm = 2; + timing_rml = 1; /* register dest - memory src long */ + timing_mrl = 2; /* memory dest - register src long */ + timing_mml = 2; + if (cpu_s->cpu_type == CPU_CxGX1) { + timing_bt = 4; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + } else { + timing_bt = 0; /* branch taken */ + timing_bnt = 2; /* branch not taken */ + } - case CPU_CxGX1: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); -#else - x86_setopcodes(ops_386, ops_pentium_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 1; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 2; - timing_rml = 1; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 2; - timing_bt = 5-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_misaligned = 2; - cpu_cyrix_alignment = 1; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_686); -#endif - break; + /* Make the CxGX1 share the timings with most other Cyrix C6x86's due to the real + ones still being unknown. */ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + + timing_misaligned = 2; + + cpu_cyrix_alignment = 1; + + cpu_features = CPU_FEATURE_RDTSC; + if (cpu_s->cpu_type >= CPU_CxGX1) + cpu_features |= CPU_FEATURE_MSR | CPU_FEATURE_CR4; + if (cpu_s->cpu_type == CPU_Cx6x86MX) + cpu_features |= CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + if (cpu_s->cpu_type >= CPU_CxGX1) + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; - - case CPU_Cx6x86MX: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; -#else - x86_setopcodes(ops_386, ops_c6x86mx_0f); + codegen_timing_set(&codegen_timing_686); #endif - x86_opcodes_da_a16 = ops_fpu_686_da_a16; - x86_opcodes_da_a32 = ops_fpu_686_da_a32; - x86_opcodes_db_a16 = ops_fpu_686_db_a16; - x86_opcodes_db_a32 = ops_fpu_686_db_a32; - x86_opcodes_df_a16 = ops_fpu_686_df_a16; - x86_opcodes_df_a32 = ops_fpu_686_df_a32; - timing_rr = 1; /*register dest - register src*/ - timing_rm = 1; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 2; - timing_rml = 1; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 2; - timing_bt = 0; /*branch taken*/ - timing_bnt = 2; /*branch not taken*/ - timing_int_rm = 9; - timing_int_v86 = 46; - timing_int_pm = 21; - timing_int_pm_outer = 32; - timing_iret_rm = 7; - timing_iret_v86 = 26; - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 3; - timing_call_pm = 4; - timing_call_pm_gate = 15; - timing_call_pm_gate_inner = 26; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 1; - timing_jmp_pm = 4; - timing_jmp_pm_gate = 14; - timing_misaligned = 2; - cpu_cyrix_alignment = 1; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_MMX; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_686); -#endif - ccr4 = 0x80; - break; + + if ((cpu_s->cpu_type == CPU_Cx6x86L) || (cpu_s->cpu_type == CPU_Cx6x86MX)) + ccr4 = 0x80; + else if (CPU_Cx6x86) + CPUID = 0; /* Disabled on powerup by default */ + break; #endif #if defined(DEV_BRANCH) && defined(USE_AMD_K5) - case CPU_K5: - case CPU_5K86: + case CPU_K5: + case CPU_5K86: +#endif + case CPU_K6: + case CPU_K6_2: + case CPU_K6_2C: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); + if (cpu_s->cpu_type >= CPU_K6_2) + x86_setopcodes(ops_386, ops_k62_0f, dynarec_ops_386, dynarec_ops_k62_0f); +#if defined(DEV_BRANCH) && defined(USE_AMD_K5) + else if (cpu_s->cpu_type == CPU_K6) + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + else + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); #else - x86_setopcodes(ops_386, ops_pentiummmx_0f); + else + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_k6); -#endif - break; -#endif - - case CPU_K6: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); #else - x86_setopcodes(ops_386, ops_k6_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_k6); -#endif - break; - - case CPU_K6_2: - case CPU_K6_2C: - case CPU_K6_3: - case CPU_K6_2P: - case CPU_K6_3P: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_k62_0f, dynarec_ops_386, dynarec_ops_k62_0f); + if (cpu_s->cpu_type >= CPU_K6_2) + x86_setopcodes(ops_386, ops_k62_0f); +#if defined(DEV_BRANCH) && defined(USE_AMD_K5) + else if (cpu_s->cpu_type = CPU_K6) + x86_setopcodes(ops_386, ops_k6_0f); + else + x86_setopcodes(ops_386, ops_pentiummmx_0f); #else - x86_setopcodes(ops_386, ops_k62_0f); + else + x86_setopcodes(ops_386, ops_k6_0f); #endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX | CPU_FEATURE_3DNOW; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_k6); #endif - break; - case CPU_PENTIUMPRO: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f); - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 0; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /* unknown */ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + + timing_misaligned = 3; + + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + if (cpu_s->cpu_type >= CPU_K6_2) + cpu_features |= CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); +#if defined(DEV_BRANCH) && defined(USE_AMD_K5) + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE; + if (cpu_s->cpu_type >= CPU_K6) { + cpu_CR4_mask |= (CR4_VME | CR4_PVI | CR4_PSE); + if (cpu_s->cpu_type <= CPU_K6) + cpu_CR4_mask |= CR4_PCE; + } #else - x86_setopcodes(ops_386, ops_pentiumpro_0f); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE; + if (cpu_s->cpu_type == CPU_K6) + cpu_CR4_mask |= CR4_PCE; #endif - x86_opcodes_da_a16 = ops_fpu_686_da_a16; - x86_opcodes_da_a32 = ops_fpu_686_da_a32; - x86_opcodes_db_a16 = ops_fpu_686_db_a16; - x86_opcodes_db_a32 = ops_fpu_686_db_a32; - x86_opcodes_df_a16 = ops_fpu_686_df_a16; - x86_opcodes_df_a32 = ops_fpu_686_df_a32; - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_PAE | CR4_MCE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_p6); -#endif - break; - case CPU_PENTIUM2: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f); - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; -#else - x86_setopcodes(ops_386, ops_pentium2_0f); + codegen_timing_set(&codegen_timing_k6); #endif - x86_opcodes_da_a16 = ops_fpu_686_da_a16; - x86_opcodes_da_a32 = ops_fpu_686_da_a32; - x86_opcodes_db_a16 = ops_fpu_686_db_a16; - x86_opcodes_db_a32 = ops_fpu_686_db_a32; - x86_opcodes_df_a16 = ops_fpu_686_df_a16; - x86_opcodes_df_a32 = ops_fpu_686_df_a32; - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_PAE | CR4_MCE | CR4_PCE; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_p6); -#endif - break; - - case CPU_PENTIUM2D: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); - x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; - x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; - x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; - x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; - x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; - x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; -#else - x86_setopcodes(ops_386, ops_pentium2d_0f); -#endif - x86_opcodes_da_a16 = ops_fpu_686_da_a16; - x86_opcodes_da_a32 = ops_fpu_686_da_a32; - x86_opcodes_db_a16 = ops_fpu_686_db_a16; - x86_opcodes_db_a32 = ops_fpu_686_db_a32; - x86_opcodes_df_a16 = ops_fpu_686_df_a16; - x86_opcodes_df_a32 = ops_fpu_686_df_a32; - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 3; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 3; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 0; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - timing_int = 6; - timing_int_rm = 11; - timing_int_v86 = 54; - timing_int_pm = 25; - timing_int_pm_outer = 42; - timing_iret_rm = 7; - timing_iret_v86 = 27; /*unknown*/ - timing_iret_pm = 10; - timing_iret_pm_outer = 27; - timing_call_rm = 4; - timing_call_pm = 4; - timing_call_pm_gate = 22; - timing_call_pm_gate_inner = 44; - timing_retf_rm = 4; - timing_retf_pm = 4; - timing_retf_pm_outer = 23; - timing_jmp_rm = 3; - timing_jmp_pm = 3; - timing_jmp_pm_gate = 18; - timing_misaligned = 3; - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PAE | CR4_PCE | CR4_OSFXSR; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_p6); -#endif - break; - - case CPU_CYRIX3S: -#ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); -#else - x86_setopcodes(ops_386, ops_winchip2_0f); -#endif - timing_rr = 1; /*register dest - register src*/ - timing_rm = 2; /*register dest - memory src*/ - timing_mr = 2; /*memory dest - register src*/ - timing_mm = 3; - timing_rml = 2; /*register dest - memory src long*/ - timing_mrl = 2; /*memory dest - register src long*/ - timing_mml = 3; - timing_bt = 3-1; /*branch taken*/ - timing_bnt = 1; /*branch not taken*/ - cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21); - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; - /*unknown*/ - timing_int_rm = 26; - timing_int_v86 = 82; - timing_int_pm = 44; - timing_int_pm_outer = 71; - timing_iret_rm = 7; - timing_iret_v86 = 26; - timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 4; - timing_call_pm = 15; - timing_call_pm_gate = 26; - timing_call_pm_gate_inner = 35; - timing_retf_rm = 4; - timing_retf_pm = 7; - timing_retf_pm_outer = 23; - timing_jmp_rm = 5; - timing_jmp_pm = 7; - timing_jmp_pm_gate = 17; - timing_misaligned = 2; - cpu_cyrix_alignment = 1; -#ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_winchip); -#endif - break; - - default: - fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); - } - - - switch (fpu_type) - { - case FPU_NONE: - break; - - case FPU_8087: - x87_timings = x87_timings_8087; break; - - case FPU_287: - x87_timings = x87_timings_287; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: +#ifdef USE_DYNAREC + /* TODO: Perhaps merge the three opcode tables with some instructions UD#'ing depending on + CPU type. */ + if (cpu_s->cpu_type == CPU_PENTIUM2D) + x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); + else if (cpu_s->cpu_type == CPU_PENTIUM2) + x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f); + else + x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + if (cpu_s->cpu_type == CPU_PENTIUM2D) + x86_setopcodes(ops_386, ops_pentium2d_0f); + else + x86_setopcodes(ops_386, ops_pentium2_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 0; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /* unknown */ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + + timing_misaligned = 3; + + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; + if (cpu_s->cpu_type >= CPU_PENTIUM2) + cpu_features |= CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PAE | CR4_PCE; + if (cpu_s->cpu_type == CPU_PENTIUM2D) + cpu_CR4_mask |= CR4_OSFXSR; + +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_p6); +#endif break; - - case FPU_287XL: - case FPU_387: - x87_timings = x87_timings_387; - break; - - default: + + case CPU_CYRIX3S: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); +#else + x86_setopcodes(ops_386, ops_winchip2_0f); +#endif + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 2; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 2; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 2; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int_rm = 26; /* unknown */ + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + + timing_misaligned = 2; + + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + + cpu_cyrix_alignment = 1; + +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_winchip); +#endif + break; + + default: + fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); + } + + switch (fpu_type) { + case FPU_NONE: + break; + + case FPU_8087: + x87_timings = x87_timings_8087; + break; + + case FPU_287: + x87_timings = x87_timings_287; + break; + + case FPU_287XL: + case FPU_387: + x87_timings = x87_timings_387; + break; + + case FPU_487SX: + default: x87_timings = x87_timings_486; - } + x87_concurrency = x87_concurrency_486; + } + + if (is386) { +#ifdef USE_DYNAREC + if (cpu_use_dynarec) + cpu_exec = exec386_dynarec; + else +#endif + cpu_exec = exec386; + } else if (cpu_s->cpu_type >= CPU_286) + cpu_exec = exec386; + else + cpu_exec = execx86; + gdbstub_cpu_init(); } + + +void +cpu_close(void) +{ + cpu_inited = 0; +} + + +void +cpu_set_isa_speed(int speed) +{ + if (speed) { + cpu_isa_speed = speed; + pc_speed_changed(); + } else if (cpu_busspeed >= 8000000) + cpu_isa_speed = 8000000; + else + cpu_isa_speed = cpu_busspeed; + + cpu_log("cpu_set_isa_speed(%d) = %d\n", speed, cpu_isa_speed); +} + + +void +cpu_set_pci_speed(int speed) +{ + if (speed) + cpu_pci_speed = speed; + else if (cpu_busspeed < 42500000) + cpu_pci_speed = cpu_busspeed; + else if (cpu_busspeed < 84000000) + cpu_pci_speed = cpu_busspeed / 2; + else if (cpu_busspeed < 120000000) + cpu_pci_speed = cpu_busspeed / 3; + else + cpu_pci_speed = cpu_busspeed / 4; + + if (cpu_isa_pci_div) + cpu_set_isa_pci_div(cpu_isa_pci_div); + else if (speed) + pc_speed_changed(); + + pci_burst_time = cpu_s->rspeed / cpu_pci_speed; + pci_nonburst_time = 4 * pci_burst_time; + + cpu_log("cpu_set_pci_speed(%d) = %d\n", speed, cpu_pci_speed); +} + + +void +cpu_set_isa_pci_div(int div) +{ + cpu_isa_pci_div = div; + + cpu_log("cpu_set_isa_pci_div(%d)\n", cpu_isa_pci_div); + + if (cpu_isa_pci_div) + cpu_set_isa_speed(cpu_pci_speed / cpu_isa_pci_div); + else + cpu_set_isa_speed(0); +} + + +void +cpu_set_agp_speed(int speed) +{ + if (speed) { + cpu_agp_speed = speed; + pc_speed_changed(); + } + else if (cpu_busspeed < 84000000) + cpu_agp_speed = cpu_busspeed; + else if (cpu_busspeed < 120000000) + cpu_agp_speed = cpu_busspeed / 1.5; + else + cpu_agp_speed = cpu_busspeed / 2; + + agp_burst_time = cpu_s->rspeed / cpu_agp_speed; + agp_nonburst_time = 4 * agp_burst_time; + + cpu_log("cpu_set_agp_speed(%d) = %d\n", speed, cpu_agp_speed); +} + + char * cpu_current_pc(char *bufp) { @@ -1736,1768 +1490,1416 @@ cpu_current_pc(char *bufp) void cpu_CPUID(void) { - switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) - { - case CPU_RAPIDCAD: - case CPU_i486DX: - case CPU_i486DX2: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU; /*FPU*/ - } - else - EAX = EBX = ECX = EDX = 0; - break; + switch (cpu_s->cpu_type) { + case CPU_i486SX_SLENH: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_VME; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_iDX4: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME; - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_i486DX_SLENH: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_Am486SX: - case CPU_Am486SX2: - if (!EAX) - { - EAX = 1; - EBX = 0x68747541; - ECX = 0x444D4163; - EDX = 0x69746E65; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = EDX = 0; /*No FPU*/ - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_ENH_Am486DX: + if (!EAX) { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_Am486DX: - case CPU_Am486DX2: - case CPU_Am486DX4: - case CPU_Am5x86: - if (!EAX) - { - EAX = 1; - EBX = 0x68747541; - ECX = 0x444D4163; - EDX = 0x69746E65; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU; /*FPU*/ - } - else - EAX = EBX = ECX = EDX = 0; - break; - - case CPU_WINCHIP: - if (!EAX) - { - EAX = 1; - if (msr.fcr2 & (1 << 14)) - { - EBX = msr.fcr3 >> 32; - ECX = msr.fcr3 & 0xffffffff; - EDX = msr.fcr2 >> 32; - } - else - { - EBX = 0x746e6543; /*CentaurHauls*/ - ECX = 0x736c7561; - EDX = 0x48727561; - } - } - else if (EAX == 1) - { - EAX = 0x540; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - if (msr.fcr & (1 << 9)) - EDX |= CPUID_MMX; - } - else - EAX = EBX = ECX = EDX = 0; - break; - - case CPU_WINCHIP2: - switch (EAX) - { - case 0: - EAX = 1; - if (msr.fcr2 & (1 << 14)) - { - EBX = msr.fcr3 >> 32; - ECX = msr.fcr3 & 0xffffffff; - EDX = msr.fcr2 >> 32; - } - else - { - EBX = 0x746e6543; /*CentaurHauls*/ - ECX = 0x736c7561; - EDX = 0x48727561; - } - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - if (msr.fcr & (1 << 9)) - EDX |= CPUID_MMX; - break; - case 0x80000000: - EAX = 0x80000005; - break; - case 0x80000001: - EAX = CPUID; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + case CPU_WINCHIP: + if (!EAX) { + EAX = 1; + if (msr.fcr2 & (1 << 14)) { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } else { + EBX = 0x746e6543; /* CentaurHauls */ + ECX = 0x736c7561; + EDX = 0x48727561; + } + } else if (EAX == 1) { + EAX = 0x540; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; if (cpu_has_feature(CPU_FEATURE_CX8)) EDX |= CPUID_CMPXCHG8B; - if (msr.fcr & (1 << 9)) - EDX |= CPUID_MMX; - if (cpu_has_feature(CPU_FEATURE_3DNOW)) - EDX |= CPUID_3DNOW; - break; - - case 0x80000002: /*Processor name string*/ - EAX = 0x20544449; /*IDT WinChip 2-3D*/ - EBX = 0x436e6957; - ECX = 0x20706968; - EDX = 0x44332d32; - break; - - case 0x80000005: /*Cache information*/ - EBX = 0x08800880; /*TLBs*/ - ECX = 0x20040120; /*L1 data cache*/ - EDX = 0x20020120; /*L1 instruction cache*/ - break; - - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; - - case CPU_P24T: - case CPU_PENTIUM: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; - } - else - EAX = EBX = ECX = EDX = 0; - break; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + } else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_WINCHIP2: + switch (EAX) { + case 0: + EAX = 1; + if (msr.fcr2 & (1 << 14)) { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } else { + EBX = 0x746e6543; /* CentaurHauls */ + ECX = 0x736c7561; + EDX = 0x48727561; + } + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = CPUID; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + if (cpu_has_feature(CPU_FEATURE_3DNOW)) + EDX |= CPUID_3DNOW; + break; + + case 0x80000002: /* Processor name string */ + EAX = 0x20544449; /* IDT WinChip 2-3D */ + EBX = 0x436e6957; + ECX = 0x20706968; + EDX = 0x44332d32; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x08800880; /*TLBs*/ + ECX = 0x20040120; /*L1 data cache*/ + EDX = 0x20020120; /*L1 instruction cache*/ + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_P24T: + case CPU_PENTIUM: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B; + } else + EAX = EBX = ECX = EDX = 0; + break; #if defined(DEV_BRANCH) && defined(USE_AMD_K5) - case CPU_K5: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x68747541; - EDX = 0x69746E65; - ECX = 0x444D4163; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_K5: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_5K86: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x68747541; - EDX = 0x69746E65; - ECX = 0x444D4163; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; - } - else if (EAX == 0x80000000) - { - EAX = 0x80000005; - EBX = ECX = EDX = 0; - } - else if (EAX == 0x80000001) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; - } - else if (EAX == 0x80000002) - { + case CPU_5K86: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B; + } else if (EAX == 0x80000000) { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } else if (EAX == 0x80000001) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B; + } else if (EAX == 0x80000002) { EAX = 0x2D444D41; EBX = 0x7428354B; ECX = 0x5020296D; EDX = 0x65636F72; - } - else if (EAX == 0x80000003) - { + } else if (EAX == 0x80000003) { EAX = 0x726F7373; EBX = ECX = EDX = 0; - } - else if (EAX == 0x80000004) - { + } else if (EAX == 0x80000004) EAX = EBX = ECX = EDX = 0; - } - else if (EAX == 0x80000005) - { + else if (EAX == 0x80000005) { EAX = 0; EBX = 0x04800000; ECX = 0x08040120; EDX = 0x10040120; - } - else - EAX = EBX = ECX = EDX = 0; - break; + } else + EAX = EBX = ECX = EDX = 0; + break; #endif - case CPU_K6: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x68747541; - EDX = 0x69746E65; - ECX = 0x444D4163; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; - } - else if (EAX == 0x80000000) - { - EAX = 0x80000005; - EBX = ECX = EDX = 0; - } - else if (EAX == 0x80000001) - { - EAX = CPUID + 0x100; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX; - } - else if (EAX == 0x80000002) - { + case CPU_K6: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX; + } else if (EAX == 0x80000000) { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } else if (EAX == 0x80000001) { + EAX = CPUID + 0x100; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX; + } else if (EAX == 0x80000002) { EAX = 0x2D444D41; EBX = 0x6D74364B; ECX = 0x202F7720; EDX = 0x746C756D; - } - else if (EAX == 0x80000003) - { + } else if (EAX == 0x80000003) { EAX = 0x64656D69; EBX = 0x65206169; ECX = 0x6E657478; EDX = 0x6E6F6973; - } - else if (EAX == 0x80000004) - { + } else if (EAX == 0x80000004) { EAX = 0x73; EBX = ECX = EDX = 0; - } - else if (EAX == 0x80000005) - { + } else if (EAX == 0x80000005) { EAX = 0; EBX = 0x02800140; ECX = 0x20020220; EDX = 0x20020220; - } - else if (EAX == 0x8FFFFFFF) - { + } else if (EAX == 0x8FFFFFFF) { EAX = 0x4778654E; EBX = 0x72656E65; ECX = 0x6F697461; EDX = 0x444D416E; + } else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K6_2: + case CPU_K6_2C: + switch (EAX) { + case 0: + EAX = 1; + EBX = 0x68747541; /* AuthenticAMD */ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = CPUID + 0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW; + break; + case 0x80000002: /* Processor name string */ + EAX = 0x2d444d41; /* AMD-K6(tm) 3D pr */ + EBX = 0x7428364b; + ECX = 0x3320296d; + EDX = 0x72702044; + break; + case 0x80000003: /* Processor name string */ + EAX = 0x7365636f; /* ocessor */ + EBX = 0x00726f73; + ECX = 0x00000000; + EDX = 0x00000000; + break; + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + default: + EAX = EBX = ECX = EDX = 0; + break; } - else - EAX = EBX = ECX = EDX = 0; - break; + break; - case CPU_K6_2: - case CPU_K6_2C: - switch (EAX) - { - case 0: - EAX = 1; - EBX = 0x68747541; /*AuthenticAMD*/ - ECX = 0x444d4163; - EDX = 0x69746e65; - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; - break; - case 0x80000000: - EAX = 0x80000005; - break; - case 0x80000001: - EAX = CPUID+0x100; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW; - break; + case CPU_K6_3: + switch (EAX) { + case 0: + EAX = 1; + EBX = 0x68747541; /* AuthenticAMD */ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000006; + break; + case 0x80000001: + EAX = CPUID + 0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW; + break; + case 0x80000002: /* Processor name string */ + EAX = 0x2d444d41; /* AMD-K6(tm) 3D+ P */ + EBX = 0x7428364b; + ECX = 0x3320296d; + EDX = 0x50202b44; + break; + case 0x80000003: /* Processor name string */ + EAX = 0x65636f72; /* rocessor */ + EBX = 0x726f7373; + ECX = 0x00000000; + EDX = 0x00000000; + break; + case 0x80000005: /* Cache information */ + EBX = 0x02800140; /* TLBs */ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + case 0x80000006: /* L2 Cache information */ + ECX = 0x01004220; + break; + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; - case 0x80000002: /*Processor name string*/ - EAX = 0x2d444d41; /*AMD-K6(tm) 3D pr*/ - EBX = 0x7428364b; - ECX = 0x3320296d; - EDX = 0x72702044; - break; - - case 0x80000003: /*Processor name string*/ - EAX = 0x7365636f; /*ocessor*/ - EBX = 0x00726f73; - ECX = 0x00000000; - EDX = 0x00000000; - break; - - case 0x80000005: /*Cache information*/ - EBX = 0x02800140; /*TLBs*/ - ECX = 0x20020220; /*L1 data cache*/ - EDX = 0x20020220; /*L1 instruction cache*/ - break; - - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; - - case CPU_K6_3: - switch (EAX) - { - case 0: - EAX = 1; - EBX = 0x68747541; /*AuthenticAMD*/ - ECX = 0x444d4163; - EDX = 0x69746e65; - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; - break; - case 0x80000000: - EAX = 0x80000006; - break; - case 0x80000001: - EAX = CPUID+0x100; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW; - break; - - case 0x80000002: /*Processor name string*/ - EAX = 0x2d444d41; /*AMD-K6(tm) 3D+ P*/ - EBX = 0x7428364b; - ECX = 0x3320296d; - EDX = 0x50202b44; - break; - - case 0x80000003: /*Processor name string*/ - EAX = 0x65636f72; /*rocessor*/ - EBX = 0x726f7373; - ECX = 0x00000000; - EDX = 0x00000000; - break; - - case 0x80000005: /*Cache information*/ - EBX = 0x02800140; /*TLBs*/ - ECX = 0x20020220; /*L1 data cache*/ - EDX = 0x20020220; /*L1 instruction cache*/ - break; - - case 0x80000006: /*L2 Cache information*/ - ECX = 0x01004220; - break; - - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; - - case CPU_K6_2P: - case CPU_K6_3P: - switch (EAX) - { - case 0: - EAX = 1; - EBX = 0x68747541; /*AuthenticAMD*/ - ECX = 0x444d4163; - EDX = 0x69746e65; - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; - break; - case 0x80000000: - EAX = 0x80000007; - break; - case 0x80000001: - EAX = CPUID+0x100; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW; - break; - - case 0x80000002: /*Processor name string*/ - EAX = 0x2d444d41; /*AMD-K6(tm)-III P*/ - EBX = 0x7428364b; - ECX = 0x492d296d; - EDX = 0x50204949; - break; - - case 0x80000003: /*Processor name string*/ - EAX = 0x65636f72; /*rocessor*/ - EBX = 0x726f7373; - ECX = 0x00000000; - EDX = 0x00000000; - break; - - case 0x80000005: /*Cache information*/ - EBX = 0x02800140; /*TLBs*/ - ECX = 0x20020220; /*L1 data cache*/ - EDX = 0x20020220; /*L1 instruction cache*/ - break; - - case 0x80000006: /*L2 Cache information*/ - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6_3P) - ECX = 0x01004220; - else - ECX = 0x00804220; - break; - - case 0x80000007: /*PowerNow information*/ - EDX = 7; - break; - - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; - - case CPU_PENTIUMMMX: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_K6_2P: + case CPU_K6_3P: + switch (EAX) { + case 0: + EAX = 1; + EBX = 0x68747541; /* AuthenticAMD */ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000007; + break; + case 0x80000001: + EAX = CPUID + 0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX | CPUID_3DNOW; + break; + case 0x80000002: /* Processor name string */ + EAX = 0x2d444d41; /* AMD-K6(tm)-III P */ + EBX = 0x7428364b; + ECX = 0x492d296d; + EDX = 0x50204949; + break; + case 0x80000003: /* Processor name string */ + EAX = 0x65636f72; /* rocessor */ + EBX = 0x726f7373; + ECX = 0x00000000; + EDX = 0x00000000; + break; + case 0x80000005: /* Cache information */ + EBX = 0x02800140; /* TLBs */ + ECX = 0x20020220; /* L1 data cache */ + EDX = 0x20020220; /* L1 instruction cache */ + break; + case 0x80000006: /* L2 Cache information */ + if (cpu_s->cpu_type == CPU_K6_3P) + ECX = 0x01004220; + else + ECX = 0x00804220; + break; + case 0x80000007: /* PowerNow information */ + EDX = 7; + break; + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + case CPU_PENTIUMMMX: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX; + } else + EAX = EBX = ECX = EDX = 0; + break; #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) - case CPU_Cx6x86: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x69727943; - EDX = 0x736e4978; - ECX = 0x64616574; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU; - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_Cx6x86: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; + } else + EAX = EBX = ECX = EDX = 0; + break; + case CPU_Cx6x86L: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_CMPXCHG8B; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_Cx6x86L: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x69727943; - EDX = 0x736e4978; - ECX = 0x64616574; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_CMPXCHG8B; - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_CxGX1: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } else + EAX = EBX = ECX = EDX = 0; + break; - - case CPU_CxGX1: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x69727943; - EDX = 0x736e4978; - ECX = 0x64616574; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; - } - else - EAX = EBX = ECX = EDX = 0; - break; - - - - case CPU_Cx6x86MX: - if (!EAX) - { - EAX = 0x00000001; - EBX = 0x69727943; - EDX = 0x736e4978; - ECX = 0x64616574; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; - } - else - EAX = EBX = ECX = EDX = 0; - break; + case CPU_Cx6x86MX: + if (!EAX) { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; + } else + EAX = EBX = ECX = EDX = 0; + break; #endif - case CPU_PENTIUMPRO: - if (!EAX) - { - EAX = 0x00000002; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_CMPXCHG8B | CPUID_MTRR | CPUID_SEP | CPUID_CMOV; - } - else if (EAX == 2) - { + case CPU_PENTIUMPRO: + if (!EAX) { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MTRR | CPUID_MCA | CPUID_SEP | CPUID_CMOV; + } else if (EAX == 2) { EAX = 0x00000001; EBX = ECX = 0; EDX = 0x00000000; - } - else - EAX = EBX = ECX = EDX = 0; - break; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_PENTIUM2: - if (!EAX) - { - EAX = 0x00000002; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR/* | CPUID_SEP*/ | CPUID_CMOV; -#ifdef USE_SEP - EDX |= CPUID_SEP; -#endif - } - else if (EAX == 2) - { + case CPU_PENTIUM2: + if (!EAX) { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_MCA | CPUID_SEP | CPUID_CMOV; + } else if (EAX == 2) { EAX = 0x00000001; EBX = ECX = 0; EDX = 0x00000000; - } - else - EAX = EBX = ECX = EDX = 0; - break; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_PENTIUM2D: - if (!EAX) - { - EAX = 0x00000002; - EBX = 0x756e6547; - EDX = 0x49656e69; - ECX = 0x6c65746e; - } - else if (EAX == 1) - { - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR/* | CPUID_SEP*/ | CPUID_FXSR | CPUID_CMOV; -#ifdef USE_SEP - EDX |= CPUID_SEP; -#endif - } - else if (EAX == 2) - { + case CPU_PENTIUM2D: + if (!EAX) { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } else if (EAX == 1) { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_MCA | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + } else if (EAX == 2) { EAX = 0x00000001; EBX = ECX = 0; EDX = 0x00000000; - } - else - EAX = EBX = ECX = EDX = 0; - break; + } else + EAX = EBX = ECX = EDX = 0; + break; - case CPU_CYRIX3S: - switch (EAX) - { - case 0: - EAX = 1; - if (msr.fcr2 & (1 << 14)) - { - EBX = msr.fcr3 >> 32; - ECX = msr.fcr3 & 0xffffffff; - EDX = msr.fcr2 >> 32; - } - else - { - EBX = 0x746e6543; /*CentaurHauls*/ - ECX = 0x736c7561; - EDX = 0x48727561; - } - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - break; - case 0x80000000: - EAX = 0x80000005; - break; - case 0x80000001: - EAX = CPUID; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - break; - case 0x80000002: /*Processor name string*/ - EAX = 0x20414956; /*VIA Samuel*/ - EBX = 0x756d6153; - ECX = 0x00006c65; - EDX = 0x00000000; - break; - - case 0x80000005: /*Cache information*/ - EBX = 0x08800880; /*TLBs*/ - ECX = 0x40040120; /*L1 data cache*/ - EDX = 0x40020120; /*L1 instruction cache*/ - break; - - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; - } + case CPU_CYRIX3S: + switch (EAX) { + case 0: + EAX = 1; + if (msr.fcr2 & (1 << 14)) { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } else { + EBX = 0x746e6543; /* CentaurHauls */ + ECX = 0x736c7561; + EDX = 0x48727561; + } + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = CPUID; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + break; + case 0x80000002: /* Processor name string */ + EAX = 0x20414956; /* VIA Samuel */ + EBX = 0x756d6153; + ECX = 0x00006c65; + EDX = 0x00000000; + break; + case 0x80000005: /* Cache information */ + EBX = 0x08800880; /* TLBs */ + ECX = 0x40040120; /* L1 data cache */ + EDX = 0x40020120; /* L1 instruction cache */ + break; + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + } } -void cpu_ven_reset(void) + +void +cpu_ven_reset(void) { - switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) - { + memset(&msr, 0, sizeof(msr)); + + switch (cpu_s->cpu_type) { + case CPU_K6_2P: + case CPU_K6_3P: + case CPU_K6_3: + case CPU_K6_2C: + msr.amd_psor = (cpu_s->cpu_type >= CPU_K6_3) ? 0x008cULL : 0x018cULL; + /* FALLTHROUGH */ + case CPU_K6_2: #if defined(DEV_BRANCH) && defined(USE_AMD_K5) - case CPU_K5: - case CPU_5K86: + case CPU_K5: + case CPU_5K86: #endif - case CPU_K6: - amd_efer = amd_whcr = 0ULL; - break; - case CPU_K6_2: - amd_efer = amd_whcr = 0ULL; - star = 0ULL; - break; - case CPU_K6_2C: - amd_efer = 2ULL; - amd_whcr = star = 0ULL; - amd_psor = 0x018cULL; - amd_uwccr = 0ULL; - break; - case CPU_K6_3: - amd_efer = 2ULL; - amd_whcr = star = 0ULL; - amd_psor = 0x008cULL; - amd_uwccr = 0ULL; - amd_pfir = amd_l2aar = 0ULL; - break; - case CPU_K6_2P: - case CPU_K6_3P: - amd_efer = 2ULL; - amd_whcr = star = 0ULL; - amd_psor = 0x008cULL; - amd_uwccr = 0ULL; - amd_pfir = amd_l2aar = 0ULL; - amd_epmr = 0ULL; - break; - } + case CPU_K6: + msr.amd_efer = (cpu_s->cpu_type >= CPU_K6_2C) ? 2ULL : 0ULL; + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + msr.mtrr_cap = 0x00000508ULL; + /* FALLTHROUGH */ + break; + } } -void cpu_RDMSR() + +void +cpu_RDMSR(void) { - switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) - { - case CPU_WINCHIP: - case CPU_WINCHIP2: - EAX = EDX = 0; - switch (ECX) - { - case 0x02: - EAX = msr.tr1; - break; - case 0x0e: - EAX = msr.tr12; - break; - case 0x10: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x11: - EAX = msr.cesr; - break; - case 0x107: - EAX = msr.fcr; - break; - case 0x108: - EAX = msr.fcr2 & 0xffffffff; - EDX = msr.fcr2 >> 32; - break; - case 0x10a: - EAX = cpu_multi & 3; - break; - } - break; - - case CPU_CYRIX3S: - EAX = EDX = 0; - switch (ECX) - { - case 0x10: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x2A: - EAX = 0xC4000000; - EDX = 0; - if (cpu_dmulti == 3) - EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); - else if (cpu_dmulti == 3.5) - EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (1 << 22)); - else if (cpu_dmulti == 4) - EAX |= ((0 << 25) | (0 << 24) | (1 << 23) | (0 << 22)); - else if (cpu_dmulti == 4.5) - EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (0 << 22)); - else if (cpu_dmulti == 5) - EAX |= 0; - else if (cpu_dmulti == 5.5) - EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (0 << 22)); - else if (cpu_dmulti == 6) - EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (1 << 22)); - else if (cpu_dmulti == 6.5) - EAX |= ((1 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); - else if (cpu_dmulti == 7) - EAX |= ((1 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); - else - EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); - if (cpu_busspeed >= 84000000) - EAX |= (1 << 19); - break; - case 0x1107: - EAX = msr.fcr; - break; - case 0x1108: - EAX = msr.fcr2 & 0xffffffff; - EDX = msr.fcr2 >> 32; - break; - case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: - case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: - if (ECX & 1) - { - EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; - EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; - } - else - { - EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; - EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; - } - break; - case 0x250: - EAX = mtrr_fix64k_8000_msr & 0xffffffff; - EDX = mtrr_fix64k_8000_msr >> 32; - break; - case 0x258: - EAX = mtrr_fix16k_8000_msr & 0xffffffff; - EDX = mtrr_fix16k_8000_msr >> 32; - break; - case 0x259: - EAX = mtrr_fix16k_a000_msr & 0xffffffff; - EDX = mtrr_fix16k_a000_msr >> 32; - break; - case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: - EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; - EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; - break; - case 0x2FF: - EAX = mtrr_deftype_msr & 0xffffffff; - EDX = mtrr_deftype_msr >> 32; - break; - } - break; - -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) - case CPU_K5: - case CPU_5K86: -#endif - case CPU_K6: - EAX = EDX = 0; - switch (ECX) - { - case 0x0000000e: - EAX = msr.tr12; - break; - case 0x00000010: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x00000083: - EAX = ecx83_msr & 0xffffffff; - EDX = ecx83_msr >> 32; - break; - case 0xC0000080: - EAX = amd_efer & 0xffffffff; - EDX = amd_efer >> 32; - break; - case 0xC0000082: - EAX = amd_whcr & 0xffffffff; - EDX = amd_whcr >> 32; - break; - default: - x86gpf(NULL, 0); - break; - } - break; + switch (cpu_s->cpu_type) { + case CPU_IBM386SLC: + case CPU_IBM486SLC: + case CPU_IBM486BL: + EAX = EDX = 0; + switch (ECX) { + case 0x1000: + EAX = msr.ibm_por & ((cpu_s->cpu_type > CPU_IBM386SLC) ? 0xffeff : 0xfeff); + break; - case CPU_K6_2: - EAX = EDX = 0; - switch (ECX) - { - case 0x0000000e: - EAX = msr.tr12; - break; - case 0x00000010: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x00000083: - EAX = ecx83_msr & 0xffffffff; - EDX = ecx83_msr >> 32; - break; - case 0xC0000080: - EAX = amd_efer & 0xffffffff; - EDX = amd_efer >> 32; - break; - case 0xC0000081: - EAX = star & 0xffffffff; - EDX = star >> 32; - break; - case 0xC0000082: - EAX = amd_whcr & 0xffffffff; - EDX = amd_whcr >> 32; - break; - default: - x86gpf(NULL, 0); - break; - } - break; + case 0x1001: + EAX = msr.ibm_crcr & 0xffffffffff; + break; - case CPU_K6_2C: - EAX = EDX = 0; - switch (ECX) - { - case 0x0000000e: - EAX = msr.tr12; - break; - case 0x00000010: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x00000083: - EAX = ecx83_msr & 0xffffffff; - EDX = ecx83_msr >> 32; - break; - case 0xC0000080: - EAX = amd_efer & 0xffffffff; - EDX = amd_efer >> 32; - break; - case 0xC0000081: - EAX = star & 0xffffffff; - EDX = star >> 32; - break; - case 0xC0000082: - EAX = amd_whcr & 0xffffffff; - EDX = amd_whcr >> 32; - break; - case 0xC0000085: - EAX = amd_uwccr & 0xffffffff; - EDX = amd_uwccr >> 32; - break; - case 0xC0000087: - EAX = amd_psor & 0xffffffff; - EDX = amd_psor >> 32; - break; - case 0xC0000088: - EAX = amd_pfir & 0xffffffff; - EDX = amd_pfir >> 32; - break; - default: - x86gpf(NULL, 0); - break; - } - break; + case 0x1002: + if ((cpu_s->cpu_type > CPU_IBM386SLC) && cpu_s->multi) + EAX = msr.ibm_por2 & 0x3f000000; + break; + } + break; - case CPU_K6_3: - EAX = EDX = 0; - switch (ECX) - { - case 0x0000000e: - EAX = msr.tr12; - break; - case 0x00000010: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x00000083: - EAX = ecx83_msr & 0xffffffff; - EDX = ecx83_msr >> 32; - break; - case 0xC0000080: - EAX = amd_efer & 0xffffffff; - EDX = amd_efer >> 32; - break; - case 0xC0000081: - EAX = star & 0xffffffff; - EDX = star >> 32; - break; - case 0xC0000082: - EAX = amd_whcr & 0xffffffff; - EDX = amd_whcr >> 32; - break; - case 0xC0000085: - EAX = amd_uwccr & 0xffffffff; - EDX = amd_uwccr >> 32; - break; - case 0xC0000087: - EAX = amd_psor & 0xffffffff; - EDX = amd_psor >> 32; - break; - case 0xC0000088: - EAX = amd_pfir & 0xffffffff; - EDX = amd_pfir >> 32; - break; - case 0xC0000089: - EAX = amd_l2aar & 0xffffffff; - EDX = amd_l2aar >> 32; - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_K6_2P: - case CPU_K6_3P: - EAX = EDX = 0; - switch (ECX) - { - case 0x0000000e: - EAX = msr.tr12; - break; - case 0x00000010: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x00000083: - EAX = ecx83_msr & 0xffffffff; - EDX = ecx83_msr >> 32; - break; - case 0xC0000080: - EAX = amd_efer & 0xffffffff; - EDX = amd_efer >> 32; - break; - case 0xC0000081: - EAX = star & 0xffffffff; - EDX = star >> 32; - break; - case 0xC0000082: - EAX = amd_whcr & 0xffffffff; - EDX = amd_whcr >> 32; - break; - case 0xC0000085: - EAX = amd_uwccr & 0xffffffff; - EDX = amd_uwccr >> 32; - break; - case 0xC0000086: - EAX = amd_epmr & 0xffffffff; - EDX = amd_epmr >> 32; - break; - case 0xC0000087: - EAX = amd_psor & 0xffffffff; - EDX = amd_psor >> 32; - break; - case 0xC0000088: - EAX = amd_pfir & 0xffffffff; - EDX = amd_pfir >> 32; - break; - case 0xC0000089: - EAX = amd_l2aar & 0xffffffff; - EDX = amd_l2aar >> 32; - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_P24T: - case CPU_PENTIUM: - case CPU_PENTIUMMMX: - EAX = EDX = 0; - switch (ECX) - { - case 0x10: + case CPU_WINCHIP: + case CPU_WINCHIP2: + EAX = EDX = 0; + switch (ECX) { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: EAX = tsc & 0xffffffff; EDX = tsc >> 32; break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + + case CPU_CYRIX3S: + EAX = EDX = 0; + switch (ECX) { + case 0x00: case 0x01: + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x2a: + EAX = 0xc4000000; + EDX = 0; + if (cpu_dmulti == 3) + EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); + else if (cpu_dmulti == 3.5) + EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (1 << 22)); + else if (cpu_dmulti == 4) + EAX |= ((0 << 25) | (0 << 24) | (1 << 23) | (0 << 22)); + else if (cpu_dmulti == 4.5) + EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (0 << 22)); + else if (cpu_dmulti == 5) + EAX |= 0; + else if (cpu_dmulti == 5.5) + EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (0 << 22)); + else if (cpu_dmulti == 6) + EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (1 << 22)); + else if (cpu_dmulti == 6.5) + EAX |= ((1 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); + else if (cpu_dmulti == 7) + EAX |= ((1 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); + else + EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); + if (cpu_busspeed >= 84000000) + EAX |= (1 << 19); + break; + case 0x1107: + EAX = msr.fcr; + break; + case 0x1108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + temp = EAX | ((uint64_t)EDX << 32); + temp2 = (ECX - 0x200) >> 1; + if (ECX & 1) { + cpu_log("MTRR physmask[%d] = %08llx\n", temp2, temp); + + if ((mtrr_physmask_msr[temp2] >> 11) & 0x1) + mem_del_mtrr(mtrr_physbase_msr[temp2] & ~(0xFFF), mtrr_physmask_msr[temp2] & ~(0xFFF)); + + if ((temp >> 11) & 0x1) + mem_add_mtrr(mtrr_physbase_msr[temp2] & ~(0xFFF), temp & ~(0xFFF), mtrr_physbase_msr[temp2] & 0xFF); + + mtrr_physmask_msr[temp2] = temp; + } else { + cpu_log("MTRR physbase[%d] = %08llx\n", temp2, temp); + + mtrr_physbase_msr[temp2] = temp; } break; -#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) - case CPU_Cx6x86: - case CPU_Cx6x86L: - case CPU_CxGX1: - case CPU_Cx6x86MX: - switch (ECX) - { - case 0x10: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - } - break; -#endif - - case CPU_PENTIUMPRO: - case CPU_PENTIUM2: - case CPU_PENTIUM2D: - EAX = EDX = 0; - switch (ECX) - { - case 0x10: - EAX = tsc & 0xffffffff; - EDX = tsc >> 32; - break; - case 0x17: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_rdmsr; - EAX = ecx17_msr & 0xffffffff; - EDX = ecx17_msr >> 32; - break; - case 0x1B: - EAX = apic_base_msr & 0xffffffff; - EDX = apic_base_msr >> 32; - cpu_log("APIC_BASE read : %08X%08X\n", EDX, EAX); - break; - case 0x2A: - EAX = 0xC4000000; - EDX = 0; - if (cpu_dmulti == 2.5) - EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); - else if (cpu_dmulti == 3) - EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); - else if (cpu_dmulti == 3.5) - EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (1 << 22)); - else if (cpu_dmulti == 4) - EAX |= ((0 << 25) | (0 << 24) | (1 << 23) | (0 << 22)); - else if (cpu_dmulti == 4.5) - EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (0 << 22)); - else if (cpu_dmulti == 5) - EAX |= 0; - else if (cpu_dmulti == 5.5) - EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (0 << 22)); - else if (cpu_dmulti == 6) - EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (1 << 22)); - else if (cpu_dmulti == 6.5) - EAX |= ((1 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); - else if (cpu_dmulti == 7) - EAX |= ((1 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); - else if (cpu_dmulti == 7.5) - EAX |= ((1 << 25) | (1 << 24) | (0 << 23) | (1 << 22)); - else if (cpu_dmulti == 8) - EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (0 << 22)); - else - EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUMPRO) { - if (cpu_busspeed >= 84000000) - EAX |= (1 << 19); - } - break; - case 0x79: - EAX = ecx79_msr & 0xffffffff; - EDX = ecx79_msr >> 32; - break; - case 0x88: case 0x89: case 0x8A: case 0x8B: - EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; - EDX = ecx8x_msr[ECX - 0x88] >> 32; - break; - case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: - EAX = msr_ia32_pmc[ECX - 0xC1] & 0xffffffff; - EDX = msr_ia32_pmc[ECX - 0xC1] >> 32; - break; - case 0xFE: - EAX = mtrr_cap_msr & 0xffffffff; - EDX = mtrr_cap_msr >> 32; - break; - case 0x116: - EAX = ecx116_msr & 0xffffffff; - EDX = ecx116_msr >> 32; - break; - case 0x118: case 0x119: case 0x11A: case 0x11B: - EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; - EDX = ecx11x_msr[ECX - 0x118] >> 32; - break; - case 0x11E: - EAX = ecx11e_msr & 0xffffffff; - EDX = ecx11e_msr >> 32; - break; - case 0x174: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; - EAX &= 0xFFFF0000; - EAX |= cs_msr; - EDX = 0x00000000; - break; - case 0x175: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; - EAX = esp_msr; - EDX = 0x00000000; - break; - case 0x176: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; - EAX = eip_msr; - EDX = 0x00000000; - break; - case 0x179: - EAX = EDX = 0x00000000; - break; - case 0x186: - EAX = ecx186_msr & 0xffffffff; - EDX = ecx186_msr >> 32; - break; - case 0x187: - EAX = ecx187_msr & 0xffffffff; - EDX = ecx187_msr >> 32; - break; - case 0x1E0: - EAX = ecx1e0_msr & 0xffffffff; - EDX = ecx1e0_msr >> 32; - break; - case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: - case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: - if (ECX & 1) - { - EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; - EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; - } - else - { - EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; - EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; - } - break; case 0x250: - EAX = mtrr_fix64k_8000_msr & 0xffffffff; - EDX = mtrr_fix64k_8000_msr >> 32; - break; + EAX = msr.mtrr_fix64k_8000 & 0xffffffff; + EDX = msr.mtrr_fix64k_8000 >> 32; + break; case 0x258: - EAX = mtrr_fix16k_8000_msr & 0xffffffff; - EDX = mtrr_fix16k_8000_msr >> 32; - break; + EAX = msr.mtrr_fix16k_8000 & 0xffffffff; + EDX = msr.mtrr_fix16k_8000 >> 32; + break; case 0x259: - EAX = mtrr_fix16k_a000_msr & 0xffffffff; - EDX = mtrr_fix16k_a000_msr >> 32; - break; - case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: - EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; - EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; - break; + EAX = msr.mtrr_fix16k_a000 & 0xffffffff; + EDX = msr.mtrr_fix16k_a000 >> 32; + break; + case 0x268: case 0x269: case 0x26a: case 0x26b: + case 0x26c: case 0x26d: case 0x26e: case 0x26f: + EAX = msr.mtrr_fix4k[ECX - 0x268] & 0xffffffff; + EDX = msr.mtrr_fix4k[ECX - 0x268] >> 32; + break; + case 0x2ff: + EAX = msr.mtrr_deftype & 0xffffffff; + EDX = msr.mtrr_deftype >> 32; + break; + } + break; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K5) + case CPU_K5: + case CPU_5K86: +#endif + case CPU_K6: + case CPU_K6_2: + case CPU_K6_2C: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + EAX = EDX = 0; + switch (ECX) { + case 0x00000000: + case 0x00000001: + break; + case 0x0000000e: + EAX = msr.tr12; + break; + case 0x00000010: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x00000083: + EAX = msr.ecx83 & 0xffffffff; + EDX = msr.ecx83 >> 32; + break; + case 0xc0000080: + EAX = msr.amd_efer & 0xffffffff; + EDX = msr.amd_efer >> 32; + break; + case 0xc0000081: + if (cpu_s->cpu_type < CPU_K6_2) + goto amd_k_invalid_rdmsr; + + EAX = msr.star & 0xffffffff; + EDX = msr.star >> 32; + break; + case 0xc0000082: + EAX = msr.amd_whcr & 0xffffffff; + EDX = msr.amd_whcr >> 32; + break; + case 0xc0000085: + if (cpu_s->cpu_type < CPU_K6_2C) + goto amd_k_invalid_rdmsr; + + EAX = msr.amd_uwccr & 0xffffffff; + EDX = msr.amd_uwccr >> 32; + break; + case 0xc0000086: + if (cpu_s->cpu_type < CPU_K6_2P) + goto amd_k_invalid_rdmsr; + + EAX = msr.amd_epmr & 0xffffffff; + EDX = msr.amd_epmr >> 32; + break; + case 0xc0000087: + if (cpu_s->cpu_type < CPU_K6_2C) + goto amd_k_invalid_rdmsr; + + EAX = msr.amd_psor & 0xffffffff; + EDX = msr.amd_psor >> 32; + break; + case 0xc0000088: + if (cpu_s->cpu_type < CPU_K6_2C) + goto amd_k_invalid_rdmsr; + + EAX = msr.amd_pfir & 0xffffffff; + EDX = msr.amd_pfir >> 32; + break; + case 0xc0000089: + if (cpu_s->cpu_type < CPU_K6_3) + goto amd_k_invalid_rdmsr; + + EAX = msr.amd_l2aar & 0xffffffff; + EDX = msr.amd_l2aar >> 32; + break; + default: +amd_k_invalid_rdmsr: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_P24T: + case CPU_PENTIUM: + case CPU_PENTIUMMMX: +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + if (cpu_s->cpu_type < CPU_Cx6x86) +#endif + EAX = EDX = 0; + switch (ECX) { + case 0x00: case 0x01: + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX); + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + EAX = EDX = 0; + switch (ECX) { + case 0x00: case 0x01: + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x17: + if (cpu_s->cpu_type != CPU_PENTIUM2D) + goto i686_invalid_rdmsr; + + if (cpu_f->package == CPU_PKG_SLOT2) + EDX |= 0x80000; + else if (cpu_f->package == CPU_PKG_SOCKET370) + EDX |= 0x100000; + break; + case 0x1B: + EAX = msr.apic_base & 0xffffffff; + EDX = msr.apic_base >> 32; + cpu_log("APIC_BASE read : %08X%08X\n", EDX, EAX); + break; + case 0x2a: + EAX = 0xc4000000; + EDX = 0; + if (cpu_dmulti == 2.5) + EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); + else if (cpu_dmulti == 3) + EAX |= ((0 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); + else if (cpu_dmulti == 3.5) + EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (1 << 22)); + else if (cpu_dmulti == 4) + EAX |= ((0 << 25) | (0 << 24) | (1 << 23) | (0 << 22)); + else if (cpu_dmulti == 4.5) + EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (0 << 22)); + else if (cpu_dmulti == 5) + EAX |= 0; + else if (cpu_dmulti == 5.5) + EAX |= ((0 << 25) | (1 << 24) | (0 << 23) | (0 << 22)); + else if (cpu_dmulti == 6) + EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (1 << 22)); + else if (cpu_dmulti == 6.5) + EAX |= ((1 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); + else if (cpu_dmulti == 7) + EAX |= ((1 << 25) | (0 << 24) | (0 << 23) | (1 << 22)); + else if (cpu_dmulti == 7.5) + EAX |= ((1 << 25) | (1 << 24) | (0 << 23) | (1 << 22)); + else if (cpu_dmulti == 8) + EAX |= ((1 << 25) | (0 << 24) | (1 << 23) | (0 << 22)); + else + EAX |= ((0 << 25) | (1 << 24) | (1 << 23) | (1 << 22)); + if (cpu_s->cpu_type != CPU_PENTIUMPRO) { + if (cpu_busspeed >= 84000000) + EAX |= (1 << 19); + } + break; + case 0x79: + EAX = msr.ecx79 & 0xffffffff; + EDX = msr.ecx79 >> 32; + break; + case 0x88: case 0x89: case 0x8a: case 0x8b: + EAX = msr.ecx8x[ECX - 0x88] & 0xffffffff; + EDX = msr.ecx8x[ECX - 0x88] >> 32; + break; + case 0xc1: case 0xc2: case 0xc3: case 0xc4: + case 0xc5: case 0xc6: case 0xc7: case 0xc8: + EAX = msr.ia32_pmc[ECX - 0xC1] & 0xffffffff; + EDX = msr.ia32_pmc[ECX - 0xC1] >> 32; + break; + case 0xfe: + EAX = msr.mtrr_cap & 0xffffffff; + EDX = msr.mtrr_cap >> 32; + break; + case 0x116: + EAX = msr.ecx116 & 0xffffffff; + EDX = msr.ecx116 >> 32; + break; + case 0x118: case 0x119: case 0x11a: case 0x11b: + EAX = msr.ecx11x[ECX - 0x118] & 0xffffffff; + EDX = msr.ecx11x[ECX - 0x118] >> 32; + break; + case 0x11e: + EAX = msr.ecx11e & 0xffffffff; + EDX = msr.ecx11e >> 32; + break; + case 0x174: + if (cpu_s->cpu_type == CPU_PENTIUMPRO) + goto i686_invalid_rdmsr; + + EAX &= 0xffff0000; + EAX |= msr.sysenter_cs; + EDX = 0x00000000; + break; + case 0x175: + if (cpu_s->cpu_type == CPU_PENTIUMPRO) + goto i686_invalid_rdmsr; + + EAX = msr.sysenter_esp; + EDX = 0x00000000; + break; + case 0x176: + if (cpu_s->cpu_type == CPU_PENTIUMPRO) + goto i686_invalid_rdmsr; + + EAX = msr.sysenter_eip; + EDX = 0x00000000; + break; + case 0x179: + EAX = 0x00000105; + EDX = 0x00000000; + break; + case 0x17a: + break; + case 0x17b: + EAX = msr.mcg_ctl & 0xffffffff; + EDX = msr.mcg_ctl >> 32; + break; + case 0x186: + EAX = msr.ecx186 & 0xffffffff; + EDX = msr.ecx186 >> 32; + break; + case 0x187: + EAX = msr.ecx187 & 0xffffffff; + EDX = msr.ecx187 >> 32; + break; + case 0x1e0: + EAX = msr.ecx1e0 & 0xffffffff; + EDX = msr.ecx1e0 >> 32; + break; + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + if (ECX & 1) { + EAX = msr.mtrr_physmask[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = msr.mtrr_physmask[(ECX - 0x200) >> 1] >> 32; + } else { + EAX = msr.mtrr_physbase[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = msr.mtrr_physbase[(ECX - 0x200) >> 1] >> 32; + } + break; + case 0x250: + EAX = msr.mtrr_fix64k_8000 & 0xffffffff; + EDX = msr.mtrr_fix64k_8000 >> 32; + break; + case 0x258: + EAX = msr.mtrr_fix16k_8000 & 0xffffffff; + EDX = msr.mtrr_fix16k_8000 >> 32; + break; + case 0x259: + EAX = msr.mtrr_fix16k_a000 & 0xffffffff; + EDX = msr.mtrr_fix16k_a000 >> 32; + break; + case 0x268: case 0x269: case 0x26a: case 0x26b: + case 0x26c: case 0x26d: case 0x26e: case 0x26f: + EAX = msr.mtrr_fix4k[ECX - 0x268] & 0xffffffff; + EDX = msr.mtrr_fix4k[ECX - 0x268] >> 32; + break; case 0x277: - EAX = pat_msr & 0xffffffff; - EDX = pat_msr >> 32; - break; - case 0x2FF: - EAX = mtrr_deftype_msr & 0xffffffff; - EDX = mtrr_deftype_msr >> 32; - break; - case 0x404: - EAX = ecx404_msr & 0xffffffff; - EDX = ecx404_msr >> 32; - break; - case 0x408: - EAX = ecx408_msr & 0xffffffff; - EDX = ecx408_msr >> 32; - break; - case 0x40c: - EAX = ecx40c_msr & 0xffffffff; - EDX = ecx40c_msr >> 32; - break; + EAX = msr.pat & 0xffffffff; + EDX = msr.pat >> 32; + break; + case 0x2ff: + EAX = msr.mtrr_deftype & 0xffffffff; + EDX = msr.mtrr_deftype >> 32; + break; + case 0x400: case 0x404: case 0x408: case 0x40c: case 0x410: - EAX = ecx410_msr & 0xffffffff; - EDX = ecx410_msr >> 32; - break; + EAX = msr.mca_ctl[(ECX - 0x400) >> 2] & 0xffffffff; + EDX = msr.mca_ctl[(ECX - 0x400) >> 2] >> 32; + break; + case 0x401: case 0x402: case 0x405: case 0x406: + case 0x407: case 0x409: case 0x40d: case 0x40e: + case 0x411: case 0x412: + break; case 0x570: - EAX = ecx570_msr & 0xffffffff; - EDX = ecx570_msr >> 32; - break; + EAX = msr.ecx570 & 0xffffffff; + EDX = msr.ecx570 >> 32; + break; case 0x1002ff: - EAX = ecx1002ff_msr & 0xffffffff; - EDX = ecx1002ff_msr >> 32; - break; + EAX = msr.ecx1002ff & 0xffffffff; + EDX = msr.ecx1002ff >> 32; + break; case 0xf0f00250: - EAX = ecxf0f00250_msr & 0xffffffff; - EDX = ecxf0f00250_msr >> 32; - break; + EAX = msr.ecxf0f00250 & 0xffffffff; + EDX = msr.ecxf0f00250 >> 32; + break; case 0xf0f00258: - EAX = ecxf0f00258_msr & 0xffffffff; - EDX = ecxf0f00258_msr >> 32; - break; + EAX = msr.ecxf0f00258 & 0xffffffff; + EDX = msr.ecxf0f00258 >> 32; + break; + case 0xf0f00259: + EAX = msr.ecxf0f00259 & 0xffffffff; + EDX = msr.ecxf0f00259 >> 32; + break; default: i686_invalid_rdmsr: - cpu_log("RDMSR: Invalid MSR: %08X\n", ECX); - x86gpf(NULL, 0); - break; - } - break; - } + cpu_log("RDMSR: Invalid MSR: %08X\n", ECX); + x86gpf(NULL, 0); + break; + } + break; + } - cpu_log("RDMSR %08X %08X%08X\n", ECX, EDX, EAX); + cpu_log("RDMSR %08X %08X%08X\n", ECX, EDX, EAX); } -void cpu_WRMSR() + +void +cpu_WRMSR(void) { - uint64_t temp, temp2; + uint64_t temp, temp2; - cpu_log("WRMSR %08X %08X%08X\n", ECX, EDX, EAX); - switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) - { - case CPU_WINCHIP: - case CPU_WINCHIP2: - switch (ECX) - { - case 0x02: - msr.tr1 = EAX & 2; - break; - case 0x0e: - msr.tr12 = EAX & 0x228; - break; - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x11: - msr.cesr = EAX & 0xff00ff; - break; - case 0x107: - msr.fcr = EAX; - if (EAX & (1 << 9)) - cpu_features |= CPU_FEATURE_MMX; - else - cpu_features &= ~CPU_FEATURE_MMX; - if (EAX & (1 << 1)) - cpu_features |= CPU_FEATURE_CX8; - else - cpu_features &= ~CPU_FEATURE_CX8; - if ((EAX & (1 << 20)) && machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type >= CPU_WINCHIP2) - cpu_features |= CPU_FEATURE_3DNOW; - else - cpu_features &= ~CPU_FEATURE_3DNOW; - if (EAX & (1 << 29)) - CPUID = 0; - else - CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; - break; - case 0x108: - msr.fcr2 = EAX | ((uint64_t)EDX << 32); - break; - case 0x109: - msr.fcr3 = EAX | ((uint64_t)EDX << 32); - break; - } - break; - case CPU_CYRIX3S: - switch (ECX) - { - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x1107: - msr.fcr = EAX; - if (EAX & (1 << 1)) - cpu_features |= CPU_FEATURE_CX8; - else - cpu_features &= ~CPU_FEATURE_CX8; - break; - case 0x1108: - msr.fcr2 = EAX | ((uint64_t)EDX << 32); - break; - case 0x1109: - msr.fcr3 = EAX | ((uint64_t)EDX << 32); - break; - case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: - case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: - temp = EAX | ((uint64_t)EDX << 32); - temp2 = (ECX - 0x200) >> 1; - if (ECX & 1) { - cpu_log("MTRR physmask[%d] = %08llx\n", temp2, temp); + cpu_log("WRMSR %08X %08X%08X\n", ECX, EDX, EAX); - if ((mtrr_physmask_msr[temp2] >> 11) & 0x1) - mem_del_mtrr(mtrr_physbase_msr[temp2] & ~(0xfff), mtrr_physmask_msr[temp2] & ~(0xfff)); + switch (cpu_s->cpu_type) { + case CPU_IBM386SLC: + case CPU_IBM486BL: + case CPU_IBM486SLC: + switch (ECX) { + case 0x1000: + msr.ibm_por = EAX & ((cpu_s->cpu_type > CPU_IBM386SLC) ? 0xffeff : 0xfeff); + cpu_cache_int_enabled = (EAX & (1 << 7)); + break; + case 0x1001: + msr.ibm_crcr = EAX & 0xffffffffff; + break; + case 0x1002: + if ((cpu_s->cpu_type > CPU_IBM386SLC) && cpu_s->multi) + msr.ibm_por2 = EAX & 0x3f000000; + break; + } + break; - if ((temp >> 11) & 0x1) - mem_add_mtrr(mtrr_physbase_msr[temp2] & ~(0xfff), temp & ~(0xfff), mtrr_physbase_msr[temp2] & 0xff); - - mtrr_physmask_msr[temp2] = temp; - } else { - cpu_log("MTRR physbase[%d] = %08llx\n", temp2, temp); - - mtrr_physbase_msr[temp2] = temp; - } - break; - case 0x250: - mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x258: - mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x259: - mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: - mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); - break; - case 0x2FF: - mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); - break; - } - break; - -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) - case CPU_K5: - case CPU_5K86: -#endif - case CPU_K6: - switch (ECX) - { - case 0x0e: - msr.tr12 = EAX & 0x228; - break; - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x83: - ecx83_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000080: - temp = EAX | ((uint64_t)EDX << 32); - if (temp & ~1ULL) - x86gpf(NULL, 0); - else - amd_efer = temp; - break; - case 0xC0000082: - amd_whcr = EAX | ((uint64_t)EDX << 32); - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_K6_2: - switch (ECX) - { - case 0x0e: - msr.tr12 = EAX & 0x228; - break; - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x83: - ecx83_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000080: - temp = EAX | ((uint64_t)EDX << 32); - if (temp & ~1ULL) - x86gpf(NULL, 0); - else - amd_efer = temp; - break; - case 0xC0000081: - star = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000082: - amd_whcr = EAX | ((uint64_t)EDX << 32); - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_K6_2C: - switch (ECX) - { - case 0x0e: - msr.tr12 = EAX & 0x228; - break; - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x83: - ecx83_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000080: - temp = EAX | ((uint64_t)EDX << 32); - if (temp & ~0xfULL) - x86gpf(NULL, 0); - else - amd_efer = temp; - break; - case 0xC0000081: - star = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000082: - amd_whcr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000085: - amd_uwccr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000087: - amd_psor = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000088: - amd_pfir = EAX | ((uint64_t)EDX << 32); - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_K6_3: - switch (ECX) - { - case 0x0e: - msr.tr12 = EAX & 0x228; - break; - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x83: - ecx83_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000080: - temp = EAX | ((uint64_t)EDX << 32); - if (temp & ~0x1fULL) - x86gpf(NULL, 0); - else - amd_efer = temp; - break; - case 0xC0000081: - star = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000082: - amd_whcr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000085: - amd_uwccr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000087: - amd_psor = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000088: - amd_pfir = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000089: - amd_l2aar = EAX | ((uint64_t)EDX << 32); - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_K6_2P: - case CPU_K6_3P: - switch (ECX) - { - case 0x0e: - msr.tr12 = EAX & 0x228; - break; - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x83: - ecx83_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000080: - temp = EAX | ((uint64_t)EDX << 32); - if (temp & ~0x1fULL) - x86gpf(NULL, 0); - else - amd_efer = temp; - break; - case 0xC0000081: - star = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000082: - amd_whcr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000085: - amd_uwccr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000086: - amd_epmr = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000087: - amd_psor = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000088: - amd_pfir = EAX | ((uint64_t)EDX << 32); - break; - case 0xC0000089: - amd_l2aar = EAX | ((uint64_t)EDX << 32); - break; - default: - x86gpf(NULL, 0); - break; - } - break; - - case CPU_P24T: - case CPU_PENTIUM: - case CPU_PENTIUMMMX: - switch (ECX) - { - case 0x10: + case CPU_WINCHIP: + case CPU_WINCHIP2: + switch (ECX) { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: tsc = EAX | ((uint64_t)EDX << 32); break; - case 0x8B: - cpu_log("WRMSR: Invalid MSR: 0x8B\n"); - x86gpf(NULL, 0); /*Needed for Vista to correctly break on Pentium*/ + case 0x11: + msr.cesr = EAX & 0xff00ff; break; + case 0x107: + msr.fcr = EAX; + if (EAX & (1 << 9)) + cpu_features |= CPU_FEATURE_MMX; + else + cpu_features &= ~CPU_FEATURE_MMX; + if (EAX & (1 << 1)) + cpu_features |= CPU_FEATURE_CX8; + else + cpu_features &= ~CPU_FEATURE_CX8; + if ((EAX & (1 << 20)) && cpu_s->cpu_type >= CPU_WINCHIP2) + cpu_features |= CPU_FEATURE_3DNOW; + else + cpu_features &= ~CPU_FEATURE_3DNOW; + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = cpu_s->cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_CYRIX3S: + switch (ECX) { + case 0x00: case 0x01: + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x1107: + msr.fcr = EAX; + if (EAX & (1 << 1)) + cpu_features |= CPU_FEATURE_CX8; + else + cpu_features &= ~CPU_FEATURE_CX8; + break; + case 0x1108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x1109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + temp = EAX | ((uint64_t)EDX << 32); + temp2 = (ECX - 0x200) >> 1; + if (ECX & 1) { + cpu_log("MTRR physmask[%d] = %08llx\n", temp2, temp); + + if ((mtrr_physmask_msr[temp2] >> 11) & 0x1) + mem_del_mtrr(mtrr_physbase_msr[temp2] & ~(0xfff), mtrr_physmask_msr[temp2] & ~(0xfff)); + + if ((temp >> 11) & 0x1) + mem_add_mtrr(mtrr_physbase_msr[temp2] & ~(0xfff), temp & ~(0xfff), mtrr_physbase_msr[temp2] & 0xff); + + mtrr_physmask_msr[temp2] = temp; + } else { + cpu_log("MTRR physbase[%d] = %08llx\n", temp2, temp); + + mtrr_physbase_msr[temp2] = temp; } - break; -#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) - case CPU_Cx6x86: - case CPU_Cx6x86L: - case CPU_CxGX1: - case CPU_Cx6x86MX: - switch (ECX) - { - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - } - break; -#endif - - case CPU_PENTIUMPRO: - case CPU_PENTIUM2: - case CPU_PENTIUM2D: - switch (ECX) - { - case 0x10: - tsc = EAX | ((uint64_t)EDX << 32); - break; - case 0x17: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type != CPU_PENTIUM2D) goto i686_invalid_wrmsr; - ecx17_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x1B: - cpu_log("APIC_BASE write: %08X%08X\n", EDX, EAX); - // apic_base_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x2A: - ecx2a_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x79: - ecx79_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x88: case 0x89: case 0x8A: case 0x8B: - ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); - break; - case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: - msr_ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32); - break; - case 0xFE: - mtrr_cap_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x116: - ecx116_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x118: case 0x119: case 0x11A: case 0x11B: - ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); - break; - case 0x11E: - ecx11e_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x174: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; - cs_msr = EAX & 0xFFFF; - break; - case 0x175: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; - esp_msr = EAX; - break; - case 0x176: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; - eip_msr = EAX; - break; - case 0x179: - break; - case 0x186: - ecx186_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x187: - ecx187_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x1E0: - ecx1e0_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: - case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: - temp = EAX | ((uint64_t)EDX << 32); - temp2 = (ECX - 0x200) >> 1; - if (ECX & 1) { - cpu_log("MTRR physmask[%d] = %08llx\n", temp2, temp); - - if ((mtrr_physmask_msr[temp2] >> 11) & 0x1) - mem_del_mtrr(mtrr_physbase_msr[temp2] & ~(0xFFF), mtrr_physmask_msr[temp2] & ~(0xFFF)); - - if ((temp >> 11) & 0x1) - mem_add_mtrr(mtrr_physbase_msr[temp2] & ~(0xFFF), temp & ~(0xFFF), mtrr_physbase_msr[temp2] & 0xFF); - - mtrr_physmask_msr[temp2] = temp; - } else { - cpu_log("MTRR physbase[%d] = %08llx\n", temp2, temp); - - mtrr_physbase_msr[temp2] = temp; - } - break; case 0x250: - mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.mtrr_fix64k_8000 = EAX | ((uint64_t)EDX << 32); + break; case 0x258: - mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.mtrr_fix16k_8000 = EAX | ((uint64_t)EDX << 32); + break; case 0x259: - mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.mtrr_fix16k_a000 = EAX | ((uint64_t)EDX << 32); + break; case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: - mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); - break; + msr.mtrr_fix4k[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; + case 0x2ff: + msr.mtrr_deftype = EAX | ((uint64_t)EDX << 32); + break; + } + break; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K5) + case CPU_K5: + case CPU_5K86: +#endif + case CPU_K6: + case CPU_K6_2: + case CPU_K6_2C: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + switch (ECX) { + case 0x00: case 0x01: + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + msr.ecx83 = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~1ULL) + x86gpf(NULL, 0); + else + msr.amd_efer = temp; + break; + case 0xc0000081: + if (cpu_s->cpu_type < CPU_K6_2) + goto amd_k_invalid_wrmsr; + + msr.star = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000082: + msr.amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000085: + if (cpu_s->cpu_type < CPU_K6_2C) + goto amd_k_invalid_wrmsr; + + msr.amd_uwccr = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000086: + if (cpu_s->cpu_type < CPU_K6_2P) + goto amd_k_invalid_wrmsr; + + msr.amd_epmr = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000087: + if (cpu_s->cpu_type < CPU_K6_2C) + goto amd_k_invalid_wrmsr; + + msr.amd_psor = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000088: + if (cpu_s->cpu_type < CPU_K6_2C) + goto amd_k_invalid_wrmsr; + + msr.amd_pfir = EAX | ((uint64_t)EDX << 32); + break; + case 0xc0000089: + if (cpu_s->cpu_type < CPU_K6_3) + goto amd_k_invalid_wrmsr; + + msr.amd_l2aar = EAX | ((uint64_t)EDX << 32); + break; + default: +amd_k_invalid_wrmsr: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_P24T: + case CPU_PENTIUM: + case CPU_PENTIUMMMX: +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: +#endif + cpu_log("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX); + switch (ECX) { + case 0x00: case 0x01: + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x8b: +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) + if (cpu_s->cpu_type < CPU_Cx6x86) { +#endif + cpu_log("WRMSR: Invalid MSR: 0x8B\n"); + x86gpf(NULL, 0); /* Needed for Vista to correctly break on Pentium */ +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) + } +#endif + break; + } + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + switch (ECX) { + case 0x00: case 0x01: + if (EAX || EDX) + x86gpf(NULL, 0); + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x1b: + cpu_log("APIC_BASE write: %08X%08X\n", EDX, EAX); + // msr.apic_base = EAX | ((uint64_t)EDX << 32); + break; + case 0x2a: + break; + case 0x79: + msr.ecx79 = EAX | ((uint64_t)EDX << 32); + break; + case 0x88: case 0x89: case 0x8a: case 0x8b: + msr.ecx8x[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); + break; + case 0xc1: case 0xc2: case 0xc3: case 0xc4: + case 0xc5: case 0xc6: case 0xc7: case 0xc8: + msr.ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32); + break; + case 0xfe: + msr.mtrr_cap = EAX | ((uint64_t)EDX << 32); + break; + case 0x116: + msr.ecx116 = EAX | ((uint64_t)EDX << 32); + break; + case 0x118: case 0x119: case 0x11a: case 0x11b: + msr.ecx11x[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); + break; + case 0x11e: + msr.ecx11e = EAX | ((uint64_t)EDX << 32); + break; + case 0x174: + if (cpu_s->cpu_type == CPU_PENTIUMPRO) + goto i686_invalid_wrmsr; + + msr.sysenter_cs = EAX & 0xFFFF; + break; + case 0x175: + if (cpu_s->cpu_type == CPU_PENTIUMPRO) + goto i686_invalid_wrmsr; + + msr.sysenter_esp = EAX; + break; + case 0x176: + if (cpu_s->cpu_type == CPU_PENTIUMPRO) + goto i686_invalid_wrmsr; + + msr.sysenter_eip = EAX; + break; + case 0x179: + break; + case 0x17a: + if (EAX || EDX) + x86gpf(NULL, 0); + break; + case 0x17b: + msr.mcg_ctl = EAX | ((uint64_t)EDX << 32); + break; + case 0x186: + msr.ecx186 = EAX | ((uint64_t)EDX << 32); + break; + case 0x187: + msr.ecx187 = EAX | ((uint64_t)EDX << 32); + break; + case 0x1e0: + msr.ecx1e0 = EAX | ((uint64_t)EDX << 32); + break; + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + if (ECX & 1) + msr.mtrr_physmask[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + else + msr.mtrr_physbase[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + break; + case 0x250: + msr.mtrr_fix64k_8000 = EAX | ((uint64_t)EDX << 32); + break; + case 0x258: + msr.mtrr_fix16k_8000 = EAX | ((uint64_t)EDX << 32); + break; + case 0x259: + msr.mtrr_fix16k_a000 = EAX | ((uint64_t)EDX << 32); + break; + case 0x268: case 0x269: case 0x26a: case 0x26b: + case 0x26c: case 0x26d: case 0x26e: case 0x26f: + msr.mtrr_fix4k[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; case 0x277: - pat_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x2FF: - mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x404: - ecx404_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x408: - ecx408_msr = EAX | ((uint64_t)EDX << 32); - break; - case 0x40c: - ecx40c_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.pat = EAX | ((uint64_t)EDX << 32); + break; + case 0x2ff: + msr.mtrr_deftype = EAX | ((uint64_t)EDX << 32); + break; + case 0x400: case 0x404: case 0x408: case 0x40c: case 0x410: - ecx410_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.mca_ctl[(ECX - 0x400) >> 2] = EAX | ((uint64_t)EDX << 32); + break; + case 0x401: case 0x402: case 0x405: case 0x406: + case 0x407: case 0x409: case 0x40d: case 0x40e: + case 0x411: case 0x412: + if (EAX || EDX) + x86gpf(NULL, 0); + break; case 0x570: - ecx570_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.ecx570 = EAX | ((uint64_t)EDX << 32); + break; case 0x1002ff: - ecx1002ff_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.ecx1002ff = EAX | ((uint64_t)EDX << 32); + break; case 0xf0f00250: - ecxf0f00250_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.ecxf0f00250 = EAX | ((uint64_t)EDX << 32); + break; case 0xf0f00258: - ecxf0f00258_msr = EAX | ((uint64_t)EDX << 32); - break; + msr.ecxf0f00258 = EAX | ((uint64_t)EDX << 32); + break; + case 0xf0f00259: + msr.ecxf0f00259 = EAX | ((uint64_t)EDX << 32); + break; default: i686_invalid_wrmsr: - cpu_log("WRMSR: Invalid MSR: %08X\n", ECX); - x86gpf(NULL, 0); - break; - } - break; - } + cpu_log("WRMSR: Invalid MSR: %08X\n", ECX); + x86gpf(NULL, 0); + break; + } + break; + } } void cpu_INVD(uint8_t wb) @@ -3507,83 +2909,127 @@ void cpu_INVD(uint8_t wb) static int cyrix_addr; -static void cpu_write(uint16_t addr, uint8_t val, void *priv) +static void +cpu_write(uint16_t addr, uint8_t val, void *priv) { - if (addr == 0xf0) { - /* Writes to F0 clear FPU error and deassert the interrupt. */ - if (is286) - picintc(1 << 13); - else - nmi = 0; - return; - } else if (addr >= 0xf1) - return; /* FPU stuff */ + if (addr == 0xf0) { + /* Writes to F0 clear FPU error and deassert the interrupt. */ + if (is286) + picintc(1 << 13); + else + nmi = 0; + return; + } else if (addr >= 0xf1) + return; /* FPU stuff */ - if (!(addr & 1)) - cyrix_addr = val; - else switch (cyrix_addr) - { - case 0xc0: /*CCR0*/ - ccr0 = val; - break; - case 0xc1: /*CCR1*/ - ccr1 = val; - break; - case 0xc2: /*CCR2*/ - ccr2 = val; - break; - case 0xc3: /*CCR3*/ - ccr3 = val; - break; - case 0xe8: /*CCR4*/ - if ((ccr3 & 0xf0) == 0x10) - { - ccr4 = val; + if (!(addr & 1)) + cyrix_addr = val; + else switch (cyrix_addr) { + case 0xc0: /* CCR0 */ + ccr0 = val; + break; + case 0xc1: /* CCR1 */ + if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) + val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)); + ccr1 = val; + break; + case 0xc2: /* CCR2 */ + ccr2 = val; + break; + case 0xc3: /* CCR3 */ + if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) + val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK; + ccr3 = val; + break; + case 0xcd: + if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { + cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xce: + if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xcf: + if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8); + if ((val & 0xf) == 0xf) + cyrix.arr[3].size = 1ull << 32; /* 4 GB */ + else if (val & 0xf) + cyrix.arr[3].size = 2048 << (val & 0xf); + else + cyrix.arr[3].size = 0; /* Disabled */ + cyrix.smhr &= ~SMHR_VALID; + } + break; + + case 0xe8: /* CCR4 */ + if ((ccr3 & 0xf0) == 0x10) { + ccr4 = val; #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_Cx6x86) - { - if (val & 0x80) - CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; - else - CPUID = 0; - } + if (cpu_s->cpu_type >= CPU_Cx6x86) { + if (val & 0x80) + CPUID = cpu_s->cpuid_model; + else + CPUID = 0; + } #endif - } - break; - case 0xe9: /*CCR5*/ - if ((ccr3 & 0xf0) == 0x10) - ccr5 = val; - break; - case 0xea: /*CCR6*/ - if ((ccr3 & 0xf0) == 0x10) - ccr6 = val; - break; - } + } + break; + case 0xe9: /* CCR5 */ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /* CCR6 */ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + } } -static uint8_t cpu_read(uint16_t addr, void *priv) -{ - if (addr >= 0xf0) - return 0xff; /* FPU stuff */ - if (addr & 1) - { - switch (cyrix_addr) - { - case 0xc0: return ccr0; - case 0xc1: return ccr1; - case 0xc2: return ccr2; - case 0xc3: return ccr3; - case 0xe8: return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; - case 0xe9: return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; - case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; - case 0xfe: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id & 0xff; - case 0xff: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id >> 8; - } - if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; - if (cyrix_addr == 0x20 && machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_Cx5x86) return 0xff; - } - return 0xff; +static uint8_t +cpu_read(uint16_t addr, void *priv) +{ + if (addr == 0xf007) + return 0x7f; + + if (addr >= 0xf0) + return 0xff; /* FPU stuff */ + + if (addr & 1) { + switch (cyrix_addr) { + case 0xc0: + return ccr0; + case 0xc1: + return ccr1; + case 0xc2: + return ccr2; + case 0xc3: + return ccr3; + case 0xe8: + return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + case 0xe9: + return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + case 0xea: + return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xfe: + return cpu_s->cyrix_id & 0xff; + case 0xff: + return cpu_s->cyrix_id >> 8; + } + + if ((cyrix_addr & 0xf0) == 0xc0) + return 0xff; + + if (cyrix_addr == 0x20 && (cpu_s->cpu_type == CPU_Cx5x86)) + return 0xff; + } + + return 0xff; } @@ -3592,16 +3038,16 @@ void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, const OpFn *dynarec_opcodes, const OpFn *dynarec_opcodes_0f) { - x86_opcodes = opcodes; - x86_opcodes_0f = opcodes_0f; - x86_dynarec_opcodes = dynarec_opcodes; - x86_dynarec_opcodes_0f = dynarec_opcodes_0f; + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; + x86_dynarec_opcodes = dynarec_opcodes; + x86_dynarec_opcodes_0f = dynarec_opcodes_0f; } #else x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f) { - x86_opcodes = opcodes; - x86_opcodes_0f = opcodes_0f; + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; } #endif @@ -3609,48 +3055,44 @@ x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f) void cpu_update_waitstates(void) { - cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + cpu_s = (CPU *) &cpu_f->cpus[cpu_effective]; - if (is486) - cpu_prefetch_width = 16; - else - cpu_prefetch_width = cpu_16bitbus ? 2 : 4; + if (is486) + cpu_prefetch_width = 16; + else + cpu_prefetch_width = cpu_16bitbus ? 2 : 4; - if (cpu_cache_int_enabled) - { - /* Disable prefetch emulation */ - cpu_prefetch_cycles = 0; - } - else if (cpu_waitstates && (cpu_s->cpu_type >= CPU_286 && cpu_s->cpu_type <= CPU_386DX)) - { - /* Waitstates override */ - cpu_prefetch_cycles = cpu_waitstates+1; - cpu_cycles_read = cpu_waitstates+1; - cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); - cpu_cycles_write = cpu_waitstates+1; - cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); - } - else if (cpu_cache_ext_enabled) - { - /* Use cache timings */ - cpu_prefetch_cycles = cpu_s->cache_read_cycles; - cpu_cycles_read = cpu_s->cache_read_cycles; - cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_read_cycles; - cpu_cycles_write = cpu_s->cache_write_cycles; - cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_write_cycles; - } - else - { - /* Use memory timings */ - cpu_prefetch_cycles = cpu_s->mem_read_cycles; - cpu_cycles_read = cpu_s->mem_read_cycles; - cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_read_cycles; - cpu_cycles_write = cpu_s->mem_write_cycles; - cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles; - } - if (is486) - cpu_prefetch_cycles = (cpu_prefetch_cycles * 11) / 16; - cpu_mem_prefetch_cycles = cpu_prefetch_cycles; - if (cpu_s->rspeed <= 8000000) - cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; + if (cpu_cache_int_enabled) { + /* Disable prefetch emulation */ + cpu_prefetch_cycles = 0; + } else if (cpu_waitstates && (cpu_s->cpu_type >= CPU_286 && cpu_s->cpu_type <= CPU_386DX)) { + /* Waitstates override */ + cpu_prefetch_cycles = cpu_waitstates+1; + cpu_cycles_read = cpu_waitstates+1; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + cpu_cycles_write = cpu_waitstates+1; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + } else if (cpu_cache_ext_enabled) { + /* Use cache timings */ + cpu_prefetch_cycles = cpu_s->cache_read_cycles; + cpu_cycles_read = cpu_s->cache_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_read_cycles; + cpu_cycles_write = cpu_s->cache_write_cycles; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_write_cycles; + } else { + /* Use memory timings */ + cpu_prefetch_cycles = cpu_s->mem_read_cycles; + cpu_cycles_read = cpu_s->mem_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_read_cycles; + cpu_cycles_write = cpu_s->mem_write_cycles; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles; + } + + if (is486) + cpu_prefetch_cycles = (cpu_prefetch_cycles * 11) / 16; + + cpu_mem_prefetch_cycles = cpu_prefetch_cycles; + + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 758b4294c..76fd909d4 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -27,11 +27,12 @@ enum { FPU_287, FPU_287XL, FPU_387, + FPU_487SX, FPU_INTERNAL }; enum { - CPU_8088, /* 808x class CPUs */ + CPU_8088 = 1, /* 808x class CPUs */ CPU_8086, #ifdef USE_NEC_808X CPU_V20, /* NEC 808x class CPUs - future proofing */ @@ -39,9 +40,9 @@ enum { #endif CPU_286, /* 286 class CPUs */ CPU_386SX, /* 386 class CPUs */ - CPU_386DX, CPU_IBM386SLC, CPU_IBM486SLC, + CPU_386DX, CPU_IBM486BL, CPU_RAPIDCAD, CPU_486SLC, @@ -49,34 +50,26 @@ enum { CPU_i486SX, /* 486 class CPUs */ CPU_Am486SX, CPU_Cx486S, - CPU_i486SX2, - CPU_Am486SX2, CPU_i486DX, - CPU_i486DX2, CPU_Am486DX, - CPU_Am486DX2, + CPU_Am486DXL, CPU_Cx486DX, - CPU_Cx486DX2, - CPU_iDX4, - CPU_Am486DX4, - CPU_Cx486DX4, - CPU_Am5x86, + CPU_STPC, + CPU_i486SX_SLENH, + CPU_i486DX_SLENH, + CPU_ENH_Am486DX, CPU_Cx5x86, CPU_P24T, CPU_WINCHIP, /* 586 class CPUs */ CPU_WINCHIP2, CPU_PENTIUM, CPU_PENTIUMMMX, -#if (defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_CYRIX_6X86))) CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L, CPU_CxGX1, -#endif -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) CPU_K5, CPU_5K86, -#endif CPU_K6, CPU_K6_2, CPU_K6_2C, @@ -86,8 +79,33 @@ enum { CPU_CYRIX3S, CPU_PENTIUMPRO, /* 686 class CPUs */ CPU_PENTIUM2, - CPU_PENTIUM2D, - CPU_MAX /* Only really needed to close the enum in a way independent of the #ifdef's. */ + CPU_PENTIUM2D +}; + +enum { + CPU_PKG_8088 = (1 << 0), + CPU_PKG_8088_EUROPC = (1 << 1), + CPU_PKG_8086 = (1 << 2), + CPU_PKG_286 = (1 << 3), + CPU_PKG_386SX = (1 << 4), + CPU_PKG_386DX = (1 << 5), + CPU_PKG_M6117 = (1 << 6), + CPU_PKG_386SLC_IBM = (1 << 7), + CPU_PKG_486SLC = (1 << 8), + CPU_PKG_486SLC_IBM = (1 << 9), + CPU_PKG_486BL = (1 << 10), + CPU_PKG_486DLC = (1 << 11), + CPU_PKG_SOCKET1 = (1 << 12), + CPU_PKG_SOCKET3 = (1 << 13), + CPU_PKG_SOCKET3_PC330 = (1 << 14), + CPU_PKG_STPC = (1 << 15), + CPU_PKG_SOCKET4 = (1 << 16), + CPU_PKG_SOCKET5_7 = (1 << 17), + CPU_PKG_SOCKET8 = (1 << 18), + CPU_PKG_SLOT1 = (1 << 19), + CPU_PKG_SLOT2 = (1 << 20), + CPU_PKG_SOCKET370 = (1 << 21), + CPU_PKG_EBGA368 = (1 << 22) }; @@ -100,19 +118,28 @@ enum { #define CPU_SUPPORTS_DYNAREC 1 #define CPU_REQUIRES_DYNAREC 2 #define CPU_ALTERNATE_XTAL 4 +#define CPU_FIXED_MULTIPLIER 8 + +#if (defined __amd64__ || defined _M_X64) +#define LOOKUP_INV -1LL +#else +#define LOOKUP_INV -1 +#endif + typedef struct { - const char *name; - const char *internal_name; - const int type; + const char *name; + const char *internal_name; + const int type; } FPU; typedef struct { const char *name; - int cpu_type; - const FPU *fpus; + uint64_t cpu_type; + const FPU *fpus; int rspeed; double multi; + uint16_t voltage; uint32_t edx_reset; uint32_t cpuid_model; uint16_t cyrix_id; @@ -122,50 +149,25 @@ typedef struct { int8_t atclk_div; } CPU; +typedef struct { + const uint32_t package; + const char *manufacturer; + const char *name; + const char *internal_name; + const CPU *cpus; +} cpu_family_t; + +typedef struct { + const char *family; + const int rspeed; + const double multi; +} cpu_legacy_table_t; + +typedef struct { + const char *machine; + const cpu_legacy_table_t **tables; +} cpu_legacy_machine_t; -extern CPU cpus_8088[]; -extern CPU cpus_8086[]; -extern CPU cpus_286[]; -extern CPU cpus_i386SX[]; -extern CPU cpus_i386DX[]; -extern CPU cpus_Am386SX[]; -extern CPU cpus_Am386DX[]; -extern CPU cpus_486SLC[]; -extern CPU cpus_486DLC[]; -extern CPU cpus_IBM386SLC[]; -extern CPU cpus_IBM486SLC[]; -extern CPU cpus_IBM486BL[]; -extern CPU cpus_i486S1[]; -extern CPU cpus_Am486S1[]; -extern CPU cpus_Cx486S1[]; -extern CPU cpus_i486[]; -extern CPU cpus_Am486[]; -extern CPU cpus_Cx486[]; -extern CPU cpus_WinChip[]; -extern CPU cpus_WinChip_SS7[]; -extern CPU cpus_Pentium5V[]; -extern CPU cpus_Pentium5V50[]; -extern CPU cpus_PentiumS5[]; -extern CPU cpus_Pentium3V[]; -extern CPU cpus_Pentium[]; -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) -extern CPU cpus_K5[]; -#endif -extern CPU cpus_K56[]; -extern CPU cpus_K56_SS7[]; -#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) -extern CPU cpus_6x863V[]; -extern CPU cpus_6x86[]; -#ifdef USE_NEW_DYNAREC -extern CPU cpus_6x86SS7[]; -#endif -#endif -extern CPU cpus_Cyrix3[]; -extern CPU cpus_PentiumPro[]; -extern CPU cpus_PentiumII66[]; -extern CPU cpus_PentiumII[]; -extern CPU cpus_Xeon[]; -extern CPU cpus_Celeron[]; #define C_FLAG 0x0001 @@ -210,12 +212,10 @@ typedef union { typedef struct { uint32_t base; uint32_t limit; - uint8_t access; - uint8_t ar_high; + uint8_t access, ar_high; uint16_t seg; - uint32_t limit_low, - limit_high; - int checked; /*Non-zero if selector is known to be valid*/ + uint32_t limit_low, limit_high; + int checked; /*Non-zero if selector is known to be valid*/ } x86seg; typedef union { @@ -231,18 +231,100 @@ typedef union { } MMX_REG; typedef struct { - uint32_t tr1, tr12; - uint32_t cesr; - uint32_t fcr; - uint64_t fcr2, fcr3; + /* IDT WinChip and WinChip 2 MSR's */ + uint32_t tr1, tr12; /* 0x00000002, 0x0000000e */ + uint32_t cesr; /* 0x00000011 */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t apic_base; /* 0x0000001b - Should the Pentium not also have this? */ + uint64_t ecx79; /* 0x00000079 */ + + /* AMD K5, 5k86, K6, K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */ + uint64_t ecx83; /* 0x00000083 - AMD K5 and K6 MSR's. */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t ecx8x[4]; /* 0x00000088 - 0x0000008b */ + uint64_t ia32_pmc[8]; /* 0x000000c1 - 0x000000c8 */ + uint64_t mtrr_cap; /* 0x000000fe */ + + /* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III */ + uint32_t fcr; /* 0x00000107 (IDT), 0x00001107 (VIA) */ + uint64_t fcr2, fcr3; /* 0x00000108 (IDT), 0x00001108 (VIA) */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t ecx116; /* 0x00000116 */ + uint64_t ecx11x[4]; /* 0x00000118 - 0x0000011b */ + uint64_t ecx11e; /* 0x0000011e */ + + /* Pentium II Klamath and Pentium II Deschutes MSR's */ + uint16_t sysenter_cs; /* 0x00000174 - SYSENTER/SYSEXIT MSR's */ + uint32_t sysenter_esp; /* 0x00000175 - SYSENTER/SYSEXIT MSR's */ + uint32_t sysenter_eip; /* 0x00000176 - SYSENTER/SYSEXIT MSR's */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t mcg_ctl; /* 0x0000017b - Machine Check Architecture */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t ecx186, ecx187; /* 0x00000186, 0x00000187 */ + uint64_t ecx1e0; /* 0x000001e0 */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also + on the VIA Cyrix III */ + uint64_t mtrr_physbase[8]; /* 0x00000200 - 0x0000020f */ + uint64_t mtrr_physmask[8]; /* 0x00000200 - 0x0000020f (ECX & 1) */ + uint64_t mtrr_fix64k_8000; /* 0x00000250 */ + uint64_t mtrr_fix16k_8000; /* 0x00000258 */ + uint64_t mtrr_fix16k_a000; /* 0x00000259 */ + uint64_t mtrr_fix4k[8]; /* 0x00000268 - 0x0000026f */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t pat; /* 0x00000277 */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also + on the VIA Cyrix III */ + uint64_t mtrr_deftype; /* 0x000002ff */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t mca_ctl[5]; /* 0x00000400, 0x00000404, 0x00000408, 0x0000040c, 0x00000410 - Machine Check Architecture */ + uint64_t ecx570; /* 0x00000570 */ + + /* IBM 386SLC, 486SLC, and 486BL MSR's */ + uint64_t ibm_por; /* 0x00001000 - Processor Operation Register */ + uint64_t ibm_crcr; /* 0x00001001 - Cache Region Control Register */ + + /* IBM 486SLC and 486BL MSR's */ + uint64_t ibm_por2; /* 0x00001002 - Processor Operation Register */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t ecx1002ff; /* 0x001002ff - MSR used by some Intel AMI boards */ + + /* AMD K5, 5k86, K6, K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */ + uint64_t amd_efer; /* 0xc0000080 */ + + /* AMD K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */ + uint64_t star; /* 0xc0000081 */ + + /* AMD K5, 5k86, K6, K6-2, K6-2C, K6-3, K6-2P, and K6-3P MSR's */ + uint64_t amd_whcr; /* 0xc0000082 */ + + /* AMD K6-2C, K6-3, K6-2P, and K6-3P MSR's */ + uint64_t amd_uwccr; /* 0xc0000085 */ + + /* AMD K6-2P and K6-3P MSR's */ + uint64_t amd_epmr; /* 0xc0000086 */ + + /* AMD K6-2C, K6-3, K6-2P, and K6-3P MSR's */ + uint64_t amd_psor, amd_pfir; /* 0xc0000087, 0xc0000088 */ + + /* K6-3, K6-2P, and K6-3P MSR's */ + uint64_t amd_l2aar; /* 0xc0000089 */ + + /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ + uint64_t ecxf0f00250; /* 0xf0f00250 - Some weird long MSR's used by i686 AMI & some Phoenix BIOSes */ + uint64_t ecxf0f00258; /* 0xf0f00258 */ + uint64_t ecxf0f00259; /* 0xf0f00259 */ } msr_t; -typedef union { - uint32_t l; - uint16_t w; -} cr0_t; - - typedef struct { x86reg regs[8]; @@ -252,13 +334,11 @@ typedef struct { uint32_t eaaddr; int flags_op; - uint32_t flags_res; - uint32_t flags_op1, - flags_op2; + uint32_t flags_res, + flags_op1, flags_op2; - uint32_t pc; - uint32_t oldpc; - uint32_t op32; + uint32_t pc, + oldpc, op32; int TOP; @@ -271,15 +351,16 @@ typedef struct { int32_t rm_mod_reg_data; } rm_data; - int8_t ssegs; - int8_t ismmx; - int8_t abrt; + uint8_t ssegs, ismmx, + abrt, _smi_line; - int _cycles; - int cpu_recomp_ins; +#ifdef FPU_CYCLES + int _cycles, _fpu_cycles, _in_smm; +#else + int _cycles, _in_smm; +#endif - uint16_t npxs, - npxc; + uint16_t npxs, npxc; double ST[8]; @@ -287,38 +368,45 @@ typedef struct { MMX_REG MM[8]; - uint16_t old_npxc, - new_npxc; - uint32_t last_ea; - #ifdef USE_NEW_DYNAREC uint32_t old_fp_control, new_fp_control; -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 uint16_t old_fp_control2, new_fp_control2; #endif -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined __amd64__ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined __amd64__ || defined _M_X64 uint32_t trunc_fp_control; #endif +#else + uint16_t old_npxc, new_npxc; #endif - x86seg seg_cs, - seg_ds, - seg_es, - seg_ss, - seg_fs, - seg_gs; + x86seg seg_cs, seg_ds, seg_es, seg_ss, + seg_fs, seg_gs; - uint16_t flags, eflags; + union { + uint32_t l; + uint16_t w; + } CR0; - cr0_t CR0; + uint16_t flags, eflags; + + uint32_t _smbase; } cpu_state_t; + +#define in_smm cpu_state._in_smm +#define smi_line cpu_state._smi_line + +#define smbase cpu_state._smbase + + /*The cpu_state.flags below must match in both cpu_cur_status and block->status for a block to be valid*/ #define CPU_STATUS_USE32 (1 << 0) #define CPU_STATUS_STACK32 (1 << 1) #define CPU_STATUS_PMODE (1 << 2) #define CPU_STATUS_V86 (1 << 3) +#define CPU_STATUS_SMM (1 << 4) #define CPU_STATUS_FLAGS 0xffff /*If the cpu_state.flags below are set in cpu_cur_status, they must be set in block->status. @@ -343,7 +431,7 @@ typedef struct { # endif #endif -COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) +COMPILE_TIME_ASSERT(sizeof(cpu_state_t) <= 128) #define cpu_state_offset(MEMBER) ((uint8_t)((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)) @@ -373,6 +461,9 @@ COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) #define DI cpu_state.regs[7].w #define cycles cpu_state._cycles +#ifdef FPU_CYCLES +#define fpu_cycles cpu_state._fpu_cycles +#endif #define cpu_rm cpu_state.rm_data.rm_mod_reg.rm #define cpu_mod cpu_state.rm_data.rm_mod_reg.mod @@ -386,6 +477,15 @@ COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) /* Global variables. */ +extern cpu_state_t cpu_state; + +extern const cpu_family_t cpu_families[]; +extern const cpu_legacy_machine_t cpu_legacy_table[]; +extern cpu_family_t *cpu_f; +extern CPU *cpu_s; +extern int cpu_override; + +extern int cpu_isintel; extern int cpu_iscyrix; extern int cpu_16bitbus, cpu_64bitbus; extern int cpu_busspeed, cpu_pci_speed; @@ -395,8 +495,8 @@ extern double fpu_multi; extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/ -extern int is8086, is286, is386, is486, is486sx, is486dx, is486sx2, is486dx2, isdx4; -extern int is_am486, is_pentium, is_k5, is_k6, is_p6; +extern int is8086, is286, is386, is6117, is486; +extern int is_am486, is_am486dxl, is_pentium, is_k5, is_k6, is_p6, is_cxsmm; extern int hascache; extern int isibm486; extern int is_rapidcad; @@ -411,8 +511,8 @@ extern int hasfpu; extern uint32_t cpu_features; -extern int in_smm, smi_line, smi_latched, smm_in_hlt; -extern uint32_t smbase; +extern int smi_latched, smm_in_hlt; +extern int smi_block; #ifdef USE_NEW_DYNAREC extern uint16_t cpu_cur_status; @@ -422,23 +522,17 @@ extern uint32_t cpu_cur_status; extern uint64_t cpu_CR4_mask; extern uint64_t tsc; extern msr_t msr; -extern cpu_state_t cpu_state; extern uint8_t opcode; -extern int insc; -extern int fpucount; -extern float mips,flops; -extern int clockrate; extern int cgate16; extern int cpl_override; extern int CPUID; -extern uint64_t xt_cpu_multi; -extern int isa_cycles; +extern uint64_t xt_cpu_multi; +extern int isa_cycles, cpu_inited; extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; -extern int ins,output; extern uint32_t pccache; extern uint8_t *pccache2; -extern double bus_timing, pci_timing; +extern double bus_timing, isa_timing, pci_timing, agp_timing; extern uint64_t pmc[2]; extern uint16_t temp_seg_data[4]; extern uint16_t cs_msr; @@ -446,7 +540,7 @@ extern uint32_t esp_msr; extern uint32_t eip_msr; /* For the AMD K6. */ -extern uint64_t star; +extern uint64_t amd_efer, star; #define FPU_CW_Reserved_Bits (0xe0c0) @@ -454,6 +548,9 @@ extern uint64_t star; #define msw cpu_state.CR0.w extern uint32_t cr2, cr3, cr4; extern uint32_t dr[8]; +extern uint32_t _tr[8]; +extern uint32_t cache_index; +extern uint8_t _cache[2048]; /*Segments - @@ -482,7 +579,7 @@ extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_writ extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; extern int cpu_waitstates; extern int cpu_cache_int_enabled, cpu_cache_ext_enabled; -extern int cpu_pci_speed; +extern int cpu_isa_speed, cpu_pci_speed, cpu_agp_speed; extern int timing_rr; extern int timing_mr, timing_mrl; @@ -497,22 +594,20 @@ extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; extern int timing_misaligned; -extern int in_sys; +extern int in_sys, unmask_a20_in_smm; +extern int cycles_main; +extern uint32_t old_rammask; + +#ifdef USE_ACYCS +extern int acycs; +#endif +extern int pic_pending, is_vpc; +extern int soft_reset_mask, alt_access; +extern int cpu_end_block_after_ins; extern uint16_t cpu_fast_off_count, cpu_fast_off_val; extern uint32_t cpu_fast_off_flags; -extern CPU cpus_pcjr[]; // FIXME: should be in machine file! -extern CPU cpus_europc[]; // FIXME: should be in machine file! -extern CPU cpus_pc1512[]; // FIXME: should be in machine file! -extern CPU cpus_ibmat[]; // FIXME: should be in machine file! -extern CPU cpus_ibmxt286[]; // FIXME: should be in machine file! -extern CPU cpus_ps1_m2011[]; // FIXME: should be in machine file! -extern CPU cpus_ps2_m30_286[]; // FIXME: should be in machine file! -#if 0 -extern CPU cpus_acer[]; // FIXME: should be in machine file! -#endif - /* Functions. */ extern int cpu_has_feature(int feature); @@ -530,13 +625,18 @@ extern char *cpu_current_pc(char *bufp); extern void cpu_update_waitstates(void); extern void cpu_set(void); +extern void cpu_close(void); +extern void cpu_set_isa_speed(int speed); +extern void cpu_set_pci_speed(int speed); +extern void cpu_set_isa_pci_div(int div); +extern void cpu_set_agp_speed(int speed); extern void cpu_CPUID(void); extern void cpu_RDMSR(void); extern void cpu_WRMSR(void); extern void cpu_INVD(uint8_t wb); -extern int checkio(int port); +extern int checkio(uint32_t port); extern void codegen_block_end(void); extern void codegen_reset(void); extern void cpu_set_edx(void); @@ -566,7 +666,8 @@ extern void resetx86(void); extern void refreshread(void); extern void resetreadlookup(void); extern void softresetx86(void); -extern void x86_int(int num); +extern void hardresetx86(void); +extern void x86_int(int num); extern void x86_int_sw(int num); extern int x86_int_sw_rm(int num); extern void x86gpf(char *s, uint16_t error); @@ -588,12 +689,57 @@ extern void update_tsc(void); extern int sysenter(uint32_t fetchdat); extern int sysexit(uint32_t fetchdat); -extern int syscall(uint32_t fetchdat); +extern int syscall_op(uint32_t fetchdat); extern int sysret(uint32_t fetchdat); -extern int fpu_get_type(int machine, int cpu_manufacturer, int cpu, const char *internal_name); -extern const char *fpu_get_internal_name(int machine, int cpu_manufacturer, int cpu, int type); -extern const char *fpu_get_name_from_index(int machine, int cpu_manufacturer, int cpu, int c); -extern int fpu_get_type_from_index(int machine, int cpu_manufacturer, int cpu, int c); +extern cpu_family_t *cpu_get_family(const char *internal_name); +extern uint8_t cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine); +extern uint8_t cpu_family_is_eligible(const cpu_family_t *cpu_family, int machine); +extern int fpu_get_type(const cpu_family_t *cpu_family, int cpu, const char *internal_name); +extern const char *fpu_get_internal_name(const cpu_family_t *cpu_family, int cpu, int type); +extern const char *fpu_get_name_from_index(const cpu_family_t *cpu_family, int cpu, int c); +extern int fpu_get_type_from_index(const cpu_family_t *cpu_family, int cpu, int c); + +void cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg); +void cyrix_write_seg_descriptor(uint32_t addr, x86seg *seg); + +#define SMHR_VALID (1 << 0) +#define SMHR_ADDR_MASK (0xfffffffc) + +typedef struct +{ + struct + { + uint32_t base; + uint64_t size; + } arr[8]; + uint32_t smhr; +} cyrix_t; + + +extern uint32_t addr64, addr64_2; +extern uint32_t addr64a[8], addr64a_2[8]; + +extern int soft_reset_pci; + +extern int reset_on_hlt, hlt_reset_pending; + +extern cyrix_t cyrix; + +extern uint8_t use_custom_nmi_vector; +extern uint32_t custom_nmi_vector; + +extern void (*cpu_exec)(int cycs); +extern uint8_t do_translate, do_translate2; + +extern void reset_808x(int hard); + +extern void cpu_register_fast_off_handler(void *timer); +extern void cpu_fast_off_advance(void); +extern void cpu_fast_off_period_set(uint16_t vla, double period); +extern void cpu_fast_off_reset(void); + +extern void smi_raise(); +extern void nmi_raise(); #endif /*EMU_CPU_H*/ diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 71df19605..96d8eafd5 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -8,38 +8,21 @@ * * Define all known processor types. * - * Available cpuspeeds: - * - * 0 = 16 MHz - * 1 = 20 MHz - * 2 = 25 MHz - * 3 = 33 MHz - * 4 = 40 MHz - * 5 = 50 MHz - * 6 = 66 MHz - * 7 = 75 MHz - * 8 = 80 MHz - * 9 = 90 MHz - * 10 = 100 MHz - * 11 = 120 MHz - * 12 = 133 MHz - * 13 = 150 MHz - * 14 = 160 MHz - * 15 = 166 MHz - * 16 = 180 MHz - * 17 = 200 MHz - * * * * Authors: Sarah Walker, * leilei, * Miran Grca, * Fred N. van Kempen, + * RichardG, + * dob205, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 leilei. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2020 RichardG. + * Copyright 2021 dob205. */ #include #include @@ -64,7 +47,7 @@ FPU fpus_80286[] = { {"None", "none", FPU_NONE}, {"287", "287", FPU_287}, - {"287XL","287xl", FPU_287XL}, + {"287XL","287xl", FPU_287XL}, {NULL, NULL, 0} }; FPU fpus_80386[] = @@ -73,6 +56,12 @@ FPU fpus_80386[] = {"387", "387", FPU_387}, {NULL, NULL, 0} }; +FPU fpus_486sx[] = +{ + {"None", "none", FPU_NONE}, + {"487SX","487sx", FPU_487SX}, + {NULL, NULL, 0} +}; FPU fpus_internal[] = { {"Internal", "internal", FPU_INTERNAL}, @@ -80,735 +69,1967 @@ FPU fpus_internal[] = }; -CPU cpus_8088[] = { - /*8088 standard*/ - {"8088/4.77", CPU_8088, fpus_8088, 4772728, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/7.16", CPU_8088, fpus_8088, 7159092, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/8", CPU_8088, fpus_8088, 8000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/10", CPU_8088, fpus_8088, 10000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/12", CPU_8088, fpus_8088, 12000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/16", CPU_8088, fpus_8088, 16000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_pcjr[] = { - /*8088 PCjr*/ - {"8088/4.77", CPU_8088, fpus_none, 4772728, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_europc[] = { - /*8088 EuroPC*/ - {"8088/4.77", CPU_8088, fpus_8088, 4772728, 1, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8088/7.16", CPU_8088, fpus_8088, 7159092, 1, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8088/9.54", CPU_8088, fpus_8088, 9545456, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_8086[] = { - /*8086 standard*/ - {"8086/7.16", CPU_8086, fpus_8088, 7159092, 1, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8086/8", CPU_8086, fpus_8088, 8000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8086/9.54", CPU_8086, fpus_8088, 9545456, 1, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8086/10", CPU_8086, fpus_8088, 10000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8086/12", CPU_8086, fpus_8088, 12000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8086/16", CPU_8086, fpus_8088, 16000000, 1, 0, 0, 0, 0, 0,0,0,0, 2}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_pc1512[] = { - /*8086 Amstrad*/ - {"8086/8", CPU_8086, fpus_8088, 8000000, 1, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_286[] = { - /*286*/ - {"286/6", CPU_286, fpus_80286, 6000000, 1, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/8", CPU_286, fpus_80286, 8000000, 1, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/10", CPU_286, fpus_80286, 10000000, 1, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/12", CPU_286, fpus_80286, 12500000, 1, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/16", CPU_286, fpus_80286, 16000000, 1, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/20", CPU_286, fpus_80286, 20000000, 1, 0, 0, 0, 0, 4,4,4,4, 3}, - {"286/25", CPU_286, fpus_80286, 25000000, 1, 0, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_ibmat[] = { - /*286*/ - {"286/6", CPU_286, fpus_80286, 6000000, 1, 0, 0, 0, 0, 3,3,3,3, 1}, - {"286/8", CPU_286, fpus_80286, 8000000, 1, 0, 0, 0, 0, 3,3,3,3, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_ibmxt286[] = { - /*286*/ - {"286/6", CPU_286, fpus_80286, 6000000, 1, 0, 0, 0, 0, 2,2,2,2, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_ps1_m2011[] = { - /*286*/ - {"286/10", CPU_286, fpus_80286, 10000000, 1, 0, 0, 0, 0, 2,2,2,2, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 9} -}; - -CPU cpus_ps2_m30_286[] = { - /*286*/ - {"286/10", CPU_286, fpus_80286, 10000000, 1, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/12", CPU_286, fpus_80286, 12500000, 1, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/16", CPU_286, fpus_80286, 16000000, 1, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/20", CPU_286, fpus_80286, 20000000, 1, 0, 0, 0, 0, 4,4,4,4, 3}, - {"286/25", CPU_286, fpus_80286, 25000000, 1, 0, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_i386SX[] = { - /*i386SX*/ - {"i386SX/16", CPU_386SX, fpus_80386, 16000000, 1, 0x2308, 0, 0, 0, 3,3,3,3, 2}, - {"i386SX/20", CPU_386SX, fpus_80386, 20000000, 1, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"i386SX/25", CPU_386SX, fpus_80386, 25000000, 1, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"i386SX/33", CPU_386SX, fpus_80386, 33333333, 1, 0x2308, 0, 0, 0, 6,6,3,3, 4}, - {"i386SX/40", CPU_386SX, fpus_80386, 40000000, 1, 0x2308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_i386DX[] = { - /*i386DX/RapidCAD*/ - {"i386DX/16", CPU_386DX, fpus_80386, 16000000, 1, 0x0308, 0, 0, 0, 3,3,3,3, 2}, - {"i386DX/20", CPU_386DX, fpus_80386, 20000000, 1, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"i386DX/25", CPU_386DX, fpus_80386, 25000000, 1, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"i386DX/33", CPU_386DX, fpus_80386, 33333333, 1, 0x0308, 0, 0, 0, 6,6,3,3, 4}, - {"i386DX/40", CPU_386DX, fpus_80386, 40000000, 1, 0x0308, 0, 0, 0, 7,7,3,3, 5}, - {"RapidCAD/25", CPU_RAPIDCAD, fpus_internal, 25000000, 1, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"RapidCAD/33", CPU_RAPIDCAD, fpus_internal, 33333333, 1, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"RapidCAD/40", CPU_RAPIDCAD, fpus_internal, 40000000, 1, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - - -CPU cpus_Am386SX[] = { - /*Am386SX*/ - {"Am386SX/16", CPU_386SX, fpus_80386, 16000000, 1, 0x2308, 0, 0, 0, 3,3,3,3, 2}, - {"Am386SX/20", CPU_386SX, fpus_80386, 20000000, 1, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386SX/25", CPU_386SX, fpus_80386, 25000000, 1, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386SX/33", CPU_386SX, fpus_80386, 33333333, 1, 0x2308, 0, 0, 0, 6,6,3,3, 4}, - {"Am386SX/40", CPU_386SX, fpus_80386, 40000000, 1, 0x2308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_Am386DX[] = { - /*Am386DX*/ - {"Am386DX/25", CPU_386DX, fpus_80386, 25000000, 1, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386DX/33", CPU_386DX, fpus_80386, 33333333, 1, 0x0308, 0, 0, 0, 6,6,3,3, 4}, - {"Am386DX/40", CPU_386DX, fpus_80386, 40000000, 1, 0x0308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_486SLC[] = { - /*Cx486SLC*/ - {"Cx486SLC/20", CPU_486SLC, fpus_80386, 20000000, 1, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, - {"Cx486SLC/25", CPU_486SLC, fpus_80386, 25000000, 1, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, - {"Cx486SLC/33", CPU_486SLC, fpus_80386, 33333333, 1, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, - {"Cx486SRx2/32", CPU_486SLC, fpus_80386, 32000000, 2, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, - {"Cx486SRx2/40", CPU_486SLC, fpus_80386, 40000000, 2, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, - {"Cx486SRx2/50", CPU_486SLC, fpus_80386, 50000000, 2, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_IBM386SLC[] = { - /*IBM 386SLC*/ - {"386SLC/16", CPU_IBM386SLC, fpus_80386, 16000000, 1, 0xA301, 0, 0, 0, 3,3,3,3, 2}, - {"386SLC/20", CPU_IBM386SLC, fpus_80386, 20000000, 1, 0xA301, 0, 0, 0, 4,4,3,3, 3}, - {"386SLC/25", CPU_IBM386SLC, fpus_80386, 25000000, 1, 0xA301, 0, 0, 0, 4,4,3,3, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_IBM486SLC[] = { - /*IBM 486SLC*/ - {"486SLC/33", CPU_IBM486SLC, fpus_80386, 33333333, 1, 0xA401, 0, 0, 0, 6,6,3,3, 4}, - {"486SLC2/40", CPU_IBM486SLC, fpus_80386, 40000000, 2, 0xA421, 0, 0, 0, 7,7,6,6, 5}, - {"486SLC2/50", CPU_IBM486SLC, fpus_80386, 50000000, 2, 0xA421, 0, 0, 0, 8,8,6,6, 6}, - {"486SLC2/66", CPU_IBM486SLC, fpus_80386, 66666666, 2, 0xA421, 0, 0, 0, 12,12,6,6, 8}, - {"486SLC3/60", CPU_IBM486SLC, fpus_80386, 60000000, 3, 0xA439, 0, 0, 0, 12,12,9,9, 7}, - {"486SLC3/75", CPU_IBM486SLC, fpus_80386, 75000000, 3, 0xA439, 0, 0, 0, 12,12,9,9, 9}, - {"486SLC3/100", CPU_IBM486SLC, fpus_80386, 100000000, 3, 0xA439, 0, 0, 0, 18,18,9,9, 12}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_IBM486BL[] = { - /*IBM Blue Lightning*/ - {"486BL2/50", CPU_IBM486BL, fpus_80386, 50000000, 2, 0xA439, 0, 0, 0, 8,8,6,6, 6}, - {"486BL2/66", CPU_IBM486BL, fpus_80386, 66666666, 2, 0xA439, 0, 0, 0, 12,12,6,6, 8}, - {"486BL3/75", CPU_IBM486BL, fpus_80386, 75000000, 3, 0xA439, 0, 0, 0, 12,12,9,9, 9}, - {"486BL3/100", CPU_IBM486BL, fpus_80386, 100000000, 3, 0xA439, 0, 0, 0, 18,18,9,9, 12}, - {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} -}; - -CPU cpus_486DLC[] = { - /*Cx486DLC*/ - {"Cx486DLC/25", CPU_486DLC, fpus_80386, 25000000, 1, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3}, - {"Cx486DLC/33", CPU_486DLC, fpus_80386, 33333333, 1, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4}, - {"Cx486DLC/40", CPU_486DLC, fpus_80386, 40000000, 1, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5}, - {"Cx486DRx2/32", CPU_486DLC, fpus_80386, 32000000, 2, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4}, - {"Cx486DRx2/40", CPU_486DLC, fpus_80386, 40000000, 2, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, - {"Cx486DRx2/50", CPU_486DLC, fpus_80386, 50000000, 2, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, - {"Cx486DRx2/66", CPU_486DLC, fpus_80386, 66666666, 2, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} -}; - -CPU cpus_i486S1[] = { - /*i486*/ - {"i486SX/16", CPU_i486SX, fpus_none, 16000000, 1, 0x420, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3,3,3, 2}, - {"i486SX/20", CPU_i486SX, fpus_none, 20000000, 1, 0x420, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, - {"i486SX/25", CPU_i486SX, fpus_none, 25000000, 1, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, - {"i486SX/33", CPU_i486SX, fpus_none, 33333333, 1, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, - {"i486SX2/50", CPU_i486SX2, fpus_none, 50000000, 2, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, - {"i486SX2/66 (Q0569)", CPU_i486SX2, fpus_none, 66666666, 2, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 8}, - {"i486DX/25", CPU_i486DX, fpus_internal, 25000000, 1, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, - {"i486DX/33", CPU_i486DX, fpus_internal, 33333333, 1, 0x414, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, - {"i486DX/50", CPU_i486DX, fpus_internal, 50000000, 1, 0x411, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, - {"i486DX2/40", CPU_i486DX2, fpus_internal, 40000000, 2, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, - {"i486DX2/50", CPU_i486DX2, fpus_internal, 50000000, 2, 0x433, 0x433, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, - {"i486DX2/66", CPU_i486DX2, fpus_internal, 66666666, 2, 0x435, 0x435, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"iDX4 OverDrive 75", CPU_iDX4, fpus_internal, 75000000, 3, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*Only added the DX4 OverDrive as the others would be redundant*/ - {"iDX4 OverDrive 100", CPU_iDX4, fpus_internal, 100000000, 3, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} -}; -CPU cpus_Am486S1[] = { - /*Am486*/ - {"Am486SX/33", CPU_Am486SX, fpus_none, 33333333, 1, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Am486SX/40", CPU_Am486SX, fpus_none, 40000000, 1, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Am486SX2/50", CPU_Am486SX2, fpus_none, 50000000, 2, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ - {"Am486SX2/66", CPU_Am486SX2, fpus_none, 66666666, 2, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/ - {"Am486DX/33", CPU_Am486DX, fpus_internal, 33333333, 1, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Am486DX/40", CPU_Am486DX, fpus_internal, 40000000, 1, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Am486DX2/50", CPU_Am486DX2, fpus_internal, 50000000, 2, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, - {"Am486DX2/66", CPU_Am486DX2, fpus_internal, 66666666, 2, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, - {"Am486DX2/80", CPU_Am486DX2, fpus_internal, 80000000, 2, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; -CPU cpus_Cx486S1[] = { - /*Cyrix 486*/ - {"Cx486S/25", CPU_Cx486S, fpus_none, 25000000, 1.0, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, - {"Cx486S/33", CPU_Cx486S, fpus_none, 33333333, 1.0, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Cx486S/40", CPU_Cx486S, fpus_none, 40000000, 1.0, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Cx486DX/33", CPU_Cx486DX, fpus_internal, 33333333, 1.0, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Cx486DX/40", CPU_Cx486DX, fpus_internal, 40000000, 1.0, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Cx486DX2/50", CPU_Cx486DX2, fpus_internal, 50000000, 2.0, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, - {"Cx486DX2/66", CPU_Cx486DX2, fpus_internal, 66666666, 2.0, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, - {"Cx486DX2/80", CPU_Cx486DX2, fpus_internal, 80000000, 2.0, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, - {"", -1, 0, 0.0, 0, 0, 0x0000, 0, 0, 0, 0, 0, 0} -}; - -CPU cpus_i486[] = { - /*i486/P24T*/ - {"i486SX/16", CPU_i486SX, fpus_none, 16000000, 1.0, 0x420, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 3, 3, 3, 3, 2}, - {"i486SX/20", CPU_i486SX, fpus_none, 20000000, 1.0, 0x420, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, - {"i486SX/25", CPU_i486SX, fpus_none, 25000000, 1.0, 0x422, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, - {"i486SX/33", CPU_i486SX, fpus_none, 33333333, 1.0, 0x42a, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"i486SX2/50", CPU_i486SX2, fpus_none, 50000000, 2.0, 0x45b, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, - {"i486SX2/66 (Q0569)", CPU_i486SX2, fpus_none, 66666666, 2.0, 0x45b, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 8}, - {"i486DX/25", CPU_i486DX, fpus_internal, 25000000, 1.0, 0x404, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, - {"i486DX/33", CPU_i486DX, fpus_internal, 33333333, 1.0, 0x414, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"i486DX/50", CPU_i486DX, fpus_internal, 50000000, 1.0, 0x411, 0, 0x0000, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 6}, - {"i486DX2/40", CPU_i486DX2, fpus_internal, 40000000, 2.0, 0x430, 0x430, 0x0000, CPU_SUPPORTS_DYNAREC, 7, 7, 6, 6, 5}, - {"i486DX2/50", CPU_i486DX2, fpus_internal, 50000000, 2.0, 0x433, 0x433, 0x0000, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, - {"i486DX2/66", CPU_i486DX2, fpus_internal, 66666666, 2.0, 0x435, 0x435, 0x0000, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, - {"iDX4/75", CPU_iDX4, fpus_internal, 75000000, 3.0, 0x480, 0x480, 0x0000, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, /*CPUID available on DX4, >= 75 MHz*/ - {"iDX4/100", CPU_iDX4, fpus_internal, 100000000, 3.0, 0x483, 0x483, 0x0000, CPU_SUPPORTS_DYNAREC, 18,18, 9, 9, 12}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ - {"iDX4 OverDrive 75", CPU_iDX4, fpus_internal, 75000000, 3.0, 0x1480, 0x1480, 0x0000, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, - {"iDX4 OverDrive 100", CPU_iDX4, fpus_internal, 100000000, 3.0, 0x1480, 0x1480, 0x0000, CPU_SUPPORTS_DYNAREC, 18,18, 9, 9, 12}, - {"Pentium OverDrive 63", CPU_P24T, fpus_internal, 62500000, 2.5, 0x1531, 0x1531, 0x0000, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, - {"Pentium OverDrive 83", CPU_P24T, fpus_internal, 83333333, 2.5, 0x1532, 0x1532, 0x0000, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, - {"", -1, 0, 0, 0, 0, 0x0000, 0, 0, 0, 0, 0, 0} -}; - -CPU cpus_Am486[] = { - /*Am486/5x86*/ - {"Am486SX/33", CPU_Am486SX, fpus_none, 33333333, 1.0, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Am486SX/40", CPU_Am486SX, fpus_none, 40000000, 1.0, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Am486SX2/50", CPU_Am486SX2, fpus_none, 50000000, 2.0, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ - {"Am486SX2/66", CPU_Am486SX2, fpus_none, 66666666, 2.0, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, - {"Am486DX/33", CPU_Am486DX, fpus_internal, 33333333, 1.0, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Am486DX/40", CPU_Am486DX, fpus_internal, 40000000, 1.0, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Am486DX2/50", CPU_Am486DX2, fpus_internal, 50000000, 2.0, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, - {"Am486DX2/66", CPU_Am486DX2, fpus_internal, 66666666, 2.0, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, - {"Am486DX2/80", CPU_Am486DX2, fpus_internal, 80000000, 2.0, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, - {"Am486DX4/75", CPU_Am486DX4, fpus_internal, 75000000, 3.0, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, - {"Am486DX4/90", CPU_Am486DX4, fpus_internal, 90000000, 3.0, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, - {"Am486DX4/100", CPU_Am486DX4, fpus_internal, 100000000, 3.0, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, - {"Am486DX4/120", CPU_Am486DX4, fpus_internal, 120000000, 3.0, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, - {"Am5x86/P75", CPU_Am5x86, fpus_internal, 133333333, 4.0, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, - {"Am5x86/P75+", CPU_Am5x86, fpus_internal, 150000000, 3.0, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*The rare P75+ was indeed a triple-clocked 150 MHz according to research*/ - {"Am5x86/P90", CPU_Am5x86, fpus_internal, 160000000, 4.0, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*160 MHz on a 40 MHz bus was a common overclock and "5x86/P90" was used by a number of BIOSes to refer to that configuration*/ - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; - -CPU cpus_Cx486[] = { - /*Cyrix 486*/ - {"Cx486S/25", CPU_Cx486S, fpus_none, 25000000, 1.0, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, - {"Cx486S/33", CPU_Cx486S, fpus_none, 33333333, 1.0, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Cx486S/40", CPU_Cx486S, fpus_none, 40000000, 1.0, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Cx486DX/33", CPU_Cx486DX, fpus_internal, 33333333, 1.0, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, - {"Cx486DX/40", CPU_Cx486DX, fpus_internal, 40000000, 1.0, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, - {"Cx486DX2/50", CPU_Cx486DX2, fpus_internal, 50000000, 2.0, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, - {"Cx486DX2/66", CPU_Cx486DX2, fpus_internal, 66666666, 2.0, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, - {"Cx486DX2/80", CPU_Cx486DX2, fpus_internal, 80000000, 2.0, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, - {"Cx486DX4/75", CPU_Cx486DX4, fpus_internal, 75000000, 3.0, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, - {"Cx486DX4/100", CPU_Cx486DX4, fpus_internal, 100000000, 3.0, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, - - /*Cyrix 5x86*/ - {"Cx5x86/80", CPU_Cx5x86, fpus_internal, 80000000, 2.0, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, /*If we're including the Pentium 50, might as well include this*/ - {"Cx5x86/100", CPU_Cx5x86, fpus_internal, 100000000, 3.0, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, - {"Cx5x86/120", CPU_Cx5x86, fpus_internal, 120000000, 3.0, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, - {"Cx5x86/133", CPU_Cx5x86, fpus_internal, 133333333, 4.0, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; - +const cpu_family_t cpu_families[] = { + { + .package = CPU_PKG_8088, + .manufacturer = "Intel", + .name = "8088", + .internal_name = "8088", + .cpus = (const CPU[]) { + {"4.77", CPU_8088, fpus_8088, 4772728, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"7.16", CPU_8088, fpus_8088, 7159092, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8", CPU_8088, fpus_8088, 8000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"10", CPU_8088, fpus_8088, 10000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"12", CPU_8088, fpus_8088, 12000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"16", CPU_8088, fpus_8088, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", 0} + } + }, { + .package = CPU_PKG_8088_EUROPC, + .manufacturer = "Intel", + .name = "8088", + .internal_name = "8088_europc", + .cpus = (const CPU[]) { + {"4.77", CPU_8088, fpus_8088, 4772728, 1, 5000, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"7.16", CPU_8088, fpus_8088, 7159092, 1, 5000, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"9.54", CPU_8088, fpus_8088, 9545456, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", 0} + } + }, { + .package = CPU_PKG_8086, + .manufacturer = "Intel", + .name = "8086", + .internal_name = "8086", + .cpus = (const CPU[]) { + {"7.16", CPU_8086, fpus_8088, 7159092, 1, 5000, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8", CPU_8086, fpus_8088, 8000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"9.54", CPU_8086, fpus_8088, 9545456, 1, 5000, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"10", CPU_8086, fpus_8088, 10000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"12", CPU_8086, fpus_8088, 12000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 1}, + {"16", CPU_8086, fpus_8088, 16000000, 1, 5000, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", 0} + } + }, { + .package = CPU_PKG_286, + .manufacturer = "Intel", + .name = "80286", + .internal_name = "286", + .cpus = (const CPU[]) { + {"6", CPU_286, fpus_80286, 6000000, 1, 5000, 0, 0, 0, 0, 2,2,2,2, 1}, + {"8", CPU_286, fpus_80286, 8000000, 1, 5000, 0, 0, 0, 0, 2,2,2,2, 1}, + {"10", CPU_286, fpus_80286, 10000000, 1, 5000, 0, 0, 0, 0, 2,2,2,2, 1}, + {"12", CPU_286, fpus_80286, 12500000, 1, 5000, 0, 0, 0, 0, 3,3,3,3, 2}, + {"16", CPU_286, fpus_80286, 16000000, 1, 5000, 0, 0, 0, 0, 3,3,3,3, 2}, + {"20", CPU_286, fpus_80286, 20000000, 1, 5000, 0, 0, 0, 0, 4,4,4,4, 3}, + {"25", CPU_286, fpus_80286, 25000000, 1, 5000, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", 0} + } + }, { + .package = CPU_PKG_386SX, + .manufacturer = "Intel", + .name = "i386SX", + .internal_name = "i386sx", + .cpus = (const CPU[]) { + {"16", CPU_386SX, fpus_80386, 16000000, 1, 5000, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"20", CPU_386SX, fpus_80386, 20000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"25", CPU_386SX, fpus_80386, 25000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"33", CPU_386SX, fpus_80386, 33333333, 1, 5000, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"40", CPU_386SX, fpus_80386, 40000000, 1, 5000, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_386SX, + .manufacturer = "AMD", + .name = "Am386SX", + .internal_name = "am386sx", + .cpus = (const CPU[]) { + {"16", CPU_386SX, fpus_80386, 16000000, 1, 5000, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"20", CPU_386SX, fpus_80386, 20000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"25", CPU_386SX, fpus_80386, 25000000, 1, 5000, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"33", CPU_386SX, fpus_80386, 33333333, 1, 5000, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"40", CPU_386SX, fpus_80386, 40000000, 1, 5000, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_386DX, + .manufacturer = "Intel", + .name = "i386DX", + .internal_name = "i386dx", + .cpus = (const CPU[]) { + {"16", CPU_386DX, fpus_80386, 16000000, 1, 5000, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"20", CPU_386DX, fpus_80386, 20000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"25", CPU_386DX, fpus_80386, 25000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"33", CPU_386DX, fpus_80386, 33333333, 1, 5000, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"40", CPU_386DX, fpus_80386, 40000000, 1, 5000, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_386DX, + .manufacturer = "Intel", + .name = "RapidCAD", + .internal_name = "rapidcad", + .cpus = (const CPU[]) { + {"25", CPU_RAPIDCAD, fpus_internal, 25000000, 1, 5000, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"33", CPU_RAPIDCAD, fpus_internal, 33333333, 1, 5000, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"40", CPU_RAPIDCAD, fpus_internal, 40000000, 1, 5000, 0x0340, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_386DX, + .manufacturer = "AMD", + .name = "Am386DX", + .internal_name = "am386dx", + .cpus = (const CPU[]) { + {"25", CPU_386DX, fpus_80386, 25000000, 1, 5000, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"33", CPU_386DX, fpus_80386, 33333333, 1, 5000, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"40", CPU_386DX, fpus_80386, 40000000, 1, 5000, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", 0} + } + }, + { + .package = CPU_PKG_M6117, + .manufacturer = "ALi", + .name = "M6117", + .internal_name = "m6117", + .cpus = (const CPU[]) { /* All timings and edx_reset values assumed. */ + {"33", CPU_386SX, fpus_none, 33333333, 1, 5000, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"40", CPU_386SX, fpus_none, 40000000, 1, 5000, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", 0} + } + }, + { + .package = CPU_PKG_386SLC_IBM, + .manufacturer = "IBM", + .name = "386SLC", + .internal_name = "ibm386slc", + .cpus = (const CPU[]) { + {"16", CPU_IBM386SLC, fpus_80386, 16000000, 1, 5000, 0xA301, 0, 0, 0, 3,3,3,3, 2}, + {"20", CPU_IBM386SLC, fpus_80386, 20000000, 1, 5000, 0xA301, 0, 0, 0, 4,4,3,3, 3}, + {"25", CPU_IBM386SLC, fpus_80386, 25000000, 1, 5000, 0xA301, 0, 0, 0, 4,4,3,3, 3}, + {"", 0} + } + }, { + .package = CPU_PKG_386SX, + .manufacturer = "Cyrix", + .name = "Cx486SLC", + .internal_name = "cx486slc", + .cpus = (const CPU[]) { + {"20", CPU_486SLC, fpus_80386, 20000000, 1, 5000, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"25", CPU_486SLC, fpus_80386, 25000000, 1, 5000, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"33", CPU_486SLC, fpus_80386, 33333333, 1, 5000, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"", 0} + } + }, { + .package = CPU_PKG_386SX, + .manufacturer = "Cyrix", + .name = "Cx486SRx2", + .internal_name = "cx486srx2", + .cpus = (const CPU[]) { + {"32", CPU_486SLC, fpus_80386, 32000000, 2, 5000, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, + {"40", CPU_486SLC, fpus_80386, 40000000, 2, 5000, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"50", CPU_486SLC, fpus_80386, 50000000, 2, 5000, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"", 0} + } + }, { + .package = CPU_PKG_486SLC_IBM, + .manufacturer = "IBM", + .name = "486SLC", + .internal_name = "ibm486slc", + .cpus = (const CPU[]) { + {"33", CPU_IBM486SLC, fpus_80386, 33333333, 1, 5000, 0xA401, 0, 0, 0, 6,6,3,3, 4}, + {"", 0} + } + }, { + .package = CPU_PKG_486SLC_IBM, + .manufacturer = "IBM", + .name = "486SLC2", + .internal_name = "ibm486slc2", + .cpus = (const CPU[]) { + {"40", CPU_IBM486SLC, fpus_80386, 40000000, 2, 5000, 0xA421, 0, 0, 0, 7,7,6,6, 5}, + {"50", CPU_IBM486SLC, fpus_80386, 50000000, 2, 5000, 0xA421, 0, 0, 0, 8,8,6,6, 6}, + {"66", CPU_IBM486SLC, fpus_80386, 66666666, 2, 5000, 0xA421, 0, 0, 0, 12,12,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_486SLC_IBM, + .manufacturer = "IBM", + .name = "486SLC3", + .internal_name = "ibm486slc3", + .cpus = (const CPU[]) { + {"60", CPU_IBM486SLC, fpus_80386, 60000000, 3, 5000, 0xA439, 0, 0, 0, 12,12,9,9, 7}, + {"75", CPU_IBM486SLC, fpus_80386, 75000000, 3, 5000, 0xA439, 0, 0, 0, 12,12,9,9, 9}, + {"100", CPU_IBM486SLC, fpus_80386, 100000000, 3, 5000, 0xA439, 0, 0, 0, 18,18,9,9, 12}, + {"", 0} + } + }, { + .package = CPU_PKG_486BL, + .manufacturer = "IBM", + .name = "486BL2", + .internal_name = "ibm486bl2", + .cpus = (const CPU[]) { + {"50", CPU_IBM486BL, fpus_80386, 50000000, 2, 5000, 0xA439, 0, 0, 0, 8,8,6,6, 6}, + {"66", CPU_IBM486BL, fpus_80386, 66666666, 2, 5000, 0xA439, 0, 0, 0, 12,12,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_486BL, + .manufacturer = "IBM", + .name = "486BL3", + .internal_name = "ibm486bl3", + .cpus = (const CPU[]) { + {"75", CPU_IBM486BL, fpus_80386, 75000000, 3, 5000, 0xA439, 0, 0, 0, 12,12,9,9, 9}, + {"100", CPU_IBM486BL, fpus_80386, 100000000, 3, 5000, 0xA439, 0, 0, 0, 18,18,9,9, 12}, + {"", 0} + } + }, { + .package = CPU_PKG_386DX, + .manufacturer = "Cyrix", + .name = "Cx486DLC", + .internal_name = "cx486dlc", + .cpus = (const CPU[]) { + {"25", CPU_486DLC, fpus_80386, 25000000, 1, 5000, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3}, + {"33", CPU_486DLC, fpus_80386, 33333333, 1, 5000, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4}, + {"40", CPU_486DLC, fpus_80386, 40000000, 1, 5000, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_386DX, + .manufacturer = "Cyrix", + .name = "Cx486DRx2", + .internal_name = "cx486drx2", + .cpus = (const CPU[]) { + {"32", CPU_486DLC, fpus_80386, 32000000, 2, 5000, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4}, + {"40", CPU_486DLC, fpus_80386, 40000000, 2, 5000, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"50", CPU_486DLC, fpus_80386, 50000000, 2, 5000, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"66", CPU_486DLC, fpus_80386, 66666666, 2, 5000, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486SX", + .internal_name = "i486sx", + .cpus = (const CPU[]) { + {"16", CPU_i486SX, fpus_486sx, 16000000, 1, 5000, 0x420, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3,3,3, 2}, + {"20", CPU_i486SX, fpus_486sx, 20000000, 1, 5000, 0x420, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"25", CPU_i486SX, fpus_486sx, 25000000, 1, 5000, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"33", CPU_i486SX, fpus_486sx, 33333333, 1, 5000, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486SX (SL-Enhanced)", + .internal_name = "i486sx_slenh", + .cpus = (const CPU[]) { + {"25", CPU_i486SX_SLENH, fpus_486sx, 25000000, 1, 5000, 0x423, 0x423, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"33", CPU_i486SX_SLENH, fpus_486sx, 33333333, 1, 5000, 0x42a, 0x42a, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486SX2", + .internal_name = "i486sx2", + .cpus = (const CPU[]) { + {"50", CPU_i486SX_SLENH, fpus_486sx, 50000000, 2, 5000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"66 (Q0569)", CPU_i486SX_SLENH, fpus_486sx, 66666666, 2, 5000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486DX", + .internal_name = "i486dx", + .cpus = (const CPU[]) { + {"25", CPU_i486DX, fpus_internal, 25000000, 1, 5000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"33", CPU_i486DX, fpus_internal, 33333333, 1, 5000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"50", CPU_i486DX, fpus_internal, 50000000, 1, 5000, 0x411, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486DX (SL-Enhanced)", + .internal_name = "i486dx_slenh", + .cpus = (const CPU[]) { + {"33", CPU_i486DX_SLENH, fpus_internal, 33333333, 1, 5000, 0x414, 0x414, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"50", CPU_i486DX_SLENH, fpus_internal, 50000000, 1, 5000, 0x414, 0x414, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486DX2", + .internal_name = "i486dx2", + .cpus = (const CPU[]) { + {"40", CPU_i486DX, fpus_internal, 40000000, 2, 5000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, + {"50", CPU_i486DX, fpus_internal, 50000000, 2, 5000, 0x433, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"66", CPU_i486DX, fpus_internal, 66666666, 2, 5000, 0x433, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Intel", + .name = "i486DX2 (SL-Enhanced)", + .internal_name = "i486dx2_slenh", + .cpus = (const CPU[]) { + {"40", CPU_i486DX_SLENH, fpus_internal, 40000000, 2, 5000, 0x435, 0x435, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, + {"50", CPU_i486DX_SLENH, fpus_internal, 50000000, 2, 5000, 0x435, 0x435, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"66", CPU_i486DX_SLENH, fpus_internal, 66666666, 2, 5000, 0x435, 0x435, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3_PC330, + .manufacturer = "Intel", + .name = "i486DX2", + .internal_name = "i486dx2_pc330", + .cpus = (const CPU[]) { + {"50", CPU_i486DX_SLENH, fpus_internal, 50000000, 2, 5000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"66", CPU_i486DX_SLENH, fpus_internal, 66666666, 2, 5000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1 | CPU_PKG_SOCKET3_PC330, /*OEM versions are 3.3V, Retail versions are 3.3V with a 5V regulator for installation in older boards. hey are functionally identical*/ + .manufacturer = "Intel", + .name = "iDX4", + .internal_name = "idx4", + .cpus = (const CPU[]) { + {"75", CPU_i486DX_SLENH, fpus_internal, 75000000, 3.0, 5000, 0x480, 0x480, 0x0000, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"100", CPU_i486DX_SLENH, fpus_internal, 100000000, 3.0, 5000, 0x483, 0x483, 0x0000, CPU_SUPPORTS_DYNAREC, 18,18, 9, 9, 12}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3 | CPU_PKG_SOCKET3_PC330, + .manufacturer = "Intel", + .name = "Pentium OverDrive", + .internal_name = "pentium_p24t", + .cpus = (const CPU[]) { + {"63", CPU_P24T, fpus_internal, 62500000, 2.5, 5000, 0x1531, 0x1531, 0x0000, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, + {"83", CPU_P24T, fpus_internal, 83333333, 2.5, 5000, 0x1532, 0x1532, 0x0000, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "AMD", + .name = "Am486SX", + .internal_name = "am486sx", + .cpus = (const CPU[]) { + {"33", CPU_Am486SX, fpus_486sx, 33333333, 1, 5000, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"40", CPU_Am486SX, fpus_486sx, 40000000, 1, 5000, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "AMD", + .name = "Am486SX2", + .internal_name = "am486sx2", + .cpus = (const CPU[]) { + {"50", CPU_Am486SX, fpus_486sx, 50000000, 2, 5000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"66", CPU_Am486SX, fpus_486sx, 66666666, 2, 5000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "AMD", + .name = "Am486DX", + .internal_name = "am486dx", + .cpus = (const CPU[]) { + {"33", CPU_Am486DX, fpus_internal, 33333333, 1, 5000, 0x412, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"40", CPU_Am486DX, fpus_internal, 40000000, 1, 5000, 0x412, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "AMD", + .name = "Am486DX2", + .internal_name = "am486dx2", + .cpus = (const CPU[]) { + {"50", CPU_Am486DX, fpus_internal, 50000000, 2, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"66", CPU_Am486DX, fpus_internal, 66666666, 2, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"80", CPU_Am486DX, fpus_internal, 80000000, 2, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "AMD", + .name = "Am486DXL", + .internal_name = "am486dxl", + .cpus = (const CPU[]) { + {"33", CPU_Am486DXL, fpus_internal, 33333333, 1, 5000, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"40", CPU_Am486DXL, fpus_internal, 40000000, 1, 5000, 0x422, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "AMD", + .name = "Am486DXL2", + .internal_name = "am486dxl2", + .cpus = (const CPU[]) { + {"50", CPU_Am486DXL, fpus_internal, 50000000, 2, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"66", CPU_Am486DXL, fpus_internal, 66666666, 2, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"80", CPU_Am486DXL, fpus_internal, 80000000, 2, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3, + .manufacturer = "AMD", + .name = "Am486DX4", + .internal_name = "am486dx4", + .cpus = (const CPU[]) { + {"75", CPU_Am486DX, fpus_internal, 75000000, 3.0, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"90", CPU_Am486DX, fpus_internal, 90000000, 3.0, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"100", CPU_Am486DX, fpus_internal, 100000000, 3.0, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"120", CPU_Am486DX, fpus_internal, 120000000, 3.0, 5000, 0x432, 0, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"", 0} + } + }, + { + .package = CPU_PKG_SOCKET3, + .manufacturer = "AMD", + .name = "Am486DX2 (Enhanced)", + .internal_name = "am486dx2_slenh", + .cpus = (const CPU[]) { + {"66", CPU_ENH_Am486DX, fpus_internal, 66666666, 2, 5000, 0x435, 0x435, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"80", CPU_ENH_Am486DX, fpus_internal, 80000000, 2, 5000, 0x435, 0x435, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3, + .manufacturer = "AMD", + .name = "Am486DX4 (Enhanced)", + .internal_name = "am486dx4_slenh", + .cpus = (const CPU[]) { + {"75", CPU_ENH_Am486DX, fpus_internal, 75000000, 3.0, 5000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"100", CPU_ENH_Am486DX, fpus_internal, 100000000, 3.0, 5000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"120", CPU_ENH_Am486DX, fpus_internal, 120000000, 3.0, 5000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3, + .manufacturer = "AMD", + .name = "Am5x86", + .internal_name = "am5x86", + .cpus = (const CPU[]) { + {"P75", CPU_ENH_Am486DX, fpus_internal, 133333333, 4.0, 5000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"P75+", CPU_ENH_Am486DX, fpus_internal, 150000000, 3.0, 5000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*The rare P75+ was indeed a triple-clocked 150 MHz according to research*/ + {"P90", CPU_ENH_Am486DX, fpus_internal, 160000000, 4.0, 5000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*160 MHz on a 40 MHz bus was a common overclock and "5x86/P90" was used by a number of BIOSes to refer to that configuration*/ + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Cyrix", + .name = "Cx486S", + .internal_name = "cx486s", + .cpus = (const CPU[]) { + {"25", CPU_Cx486S, fpus_486sx, 25000000, 1.0, 5000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, + {"33", CPU_Cx486S, fpus_486sx, 33333333, 1.0, 5000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"40", CPU_Cx486S, fpus_486sx, 40000000, 1.0, 5000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Cyrix", + .name = "Cx486DX", + .internal_name = "cx486dx", + .cpus = (const CPU[]) { + {"33", CPU_Cx486DX, fpus_internal, 33333333, 1.0, 5000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"40", CPU_Cx486DX, fpus_internal, 40000000, 1.0, 5000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET1, + .manufacturer = "Cyrix", + .name = "Cx486DX2", + .internal_name = "cx486dx2", + .cpus = (const CPU[]) { + {"50", CPU_Cx486DX, fpus_internal, 50000000, 2.0, 5000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"66", CPU_Cx486DX, fpus_internal, 66666666, 2.0, 5000, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"80", CPU_Cx486DX, fpus_internal, 80000000, 2.0, 5000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3, + .manufacturer = "Cyrix", + .name = "Cx486DX4", + .internal_name = "cx486dx4", + .cpus = (const CPU[]) { + {"75", CPU_Cx486DX, fpus_internal, 75000000, 3.0, 5000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"100", CPU_Cx486DX, fpus_internal, 100000000, 3.0, 5000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET3, + .manufacturer = "Cyrix", + .name = "Cx5x86", + .internal_name = "cx5x86", + .cpus = (const CPU[]) { + {"80", CPU_Cx5x86, fpus_internal, 80000000, 2.0, 5000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, /*If we're including the Pentium 50, might as well include this*/ + {"100", CPU_Cx5x86, fpus_internal, 100000000, 3.0, 5000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"120", CPU_Cx5x86, fpus_internal, 120000000, 3.0, 5000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"133", CPU_Cx5x86, fpus_internal, 133333333, 4.0, 5000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"", 0} + } + }, { + .package = CPU_PKG_STPC, + .manufacturer = "ST", + .name = "STPC-DX", + .internal_name = "stpc_dx", + .cpus = (const CPU[]) { + {"66", CPU_STPC, fpus_internal, 66666666, 1.0, 3300, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"75", CPU_STPC, fpus_internal, 75000000, 1.0, 3300, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"", 0} + } + }, { + .package = CPU_PKG_STPC, + .manufacturer = "ST", + .name = "STPC-DX2", + .internal_name = "stpc_dx2", + .cpus = (const CPU[]) { + {"133", CPU_STPC, fpus_internal, 133333333, 2.0, 3300, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET4, + .manufacturer = "Intel", + .name = "Pentium", + .internal_name = "pentium_p5", + .cpus = (const CPU[]) { + {"50 (Q0399)", CPU_PENTIUM, fpus_internal, 50000000, 1, 5000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 4, 4,3,3, 6}, + {"60", CPU_PENTIUM, fpus_internal, 60000000, 1, 5000, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6,3,3, 7}, + {"66", CPU_PENTIUM, fpus_internal, 66666666, 1, 5000, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6,3,3, 8}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET4, + .manufacturer = "Intel", + .name = "Pentium OverDrive", + .internal_name = "pentium_p54c_od5v", + .cpus = (const CPU[]) { + {"100", CPU_PENTIUM, fpus_internal, 100000000, 2, 5000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 8, 8,6,6, 12}, + {"120", CPU_PENTIUM, fpus_internal, 120000000, 2, 5000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,6,6, 14}, + {"133", CPU_PENTIUM, fpus_internal, 133333333, 2, 5000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,6,6, 16}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Intel", + .name = "Pentium", + .internal_name = "pentium_p54c", + .cpus = (const CPU[]) { + {"75", CPU_PENTIUM, fpus_internal, 75000000, 1.5, 3520, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"90", CPU_PENTIUM, fpus_internal, 90000000, 1.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"100/50", CPU_PENTIUM, fpus_internal, 100000000, 2.0, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, + {"100/66", CPU_PENTIUM, fpus_internal, 100000000, 1.5, 3520, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"120", CPU_PENTIUM, fpus_internal, 120000000, 2.0, 3520, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"133", CPU_PENTIUM, fpus_internal, 133333333, 2.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"200", CPU_PENTIUM, fpus_internal, 200000000, 3.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Intel", + .name = "Pentium MMX", + .internal_name = "pentium_p55c", + .cpus = (const CPU[]) { + {"166", CPU_PENTIUMMMX, fpus_internal, 166666666, 2.5, 2800, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 2800, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"233", CPU_PENTIUMMMX, fpus_internal, 233333333, 3.5, 2800, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Intel", + .name = "Mobile Pentium MMX", + .internal_name = "pentium_tillamook", + .cpus = (const CPU[]) { + {"120", CPU_PENTIUMMMX, fpus_internal, 120000000, 2.0, 2800, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"133", CPU_PENTIUMMMX, fpus_internal, 133333333, 2.0, 2800, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"150", CPU_PENTIUMMMX, fpus_internal, 150000000, 2.5, 2800, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"166", CPU_PENTIUMMMX, fpus_internal, 166666666, 2.5, 2800, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 2800, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"233", CPU_PENTIUMMMX, fpus_internal, 233333333, 3.5, 2800, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"266", CPU_PENTIUMMMX, fpus_internal, 266666666, 4.0, 2800, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"300", CPU_PENTIUMMMX, fpus_internal, 300000000, 4.5, 2800, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Intel", + .name = "Pentium OverDrive", + .internal_name = "pentium_p54c_od3v", + .cpus = (const CPU[]) { + {"125", CPU_PENTIUM, fpus_internal, 125000000, 3.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,7,7, 15}, + {"150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 35/2}, + {"166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 20}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Intel", + .name = "Pentium OverDrive MMX", + .internal_name = "pentium_p55c_od", + .cpus = (const CPU[]) { + {"75", CPU_PENTIUMMMX, fpus_internal, 75000000, 1.5, 3520, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 7, 7,4,4, 9}, + {"125", CPU_PENTIUMMMX, fpus_internal, 125000000, 2.5, 3520, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,7,7, 15}, + {"150/60", CPU_PENTIUMMMX, fpus_internal, 150000000, 2.5, 3520, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 35/2}, + {"166", CPU_PENTIUMMMX, fpus_internal, 166000000, 2.5, 3520, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 20}, + {"180", CPU_PENTIUMMMX, fpus_internal, 180000000, 3.0, 3520, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 18,18,9,9, 21}, + {"200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 3520, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 18,18,9,9, 24}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "IDT", + .name = "WinChip", + .internal_name = "winchip", + .cpus = (const CPU[]) { + {"75", CPU_WINCHIP, fpus_internal, 75000000, 1.5, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, + {"90", CPU_WINCHIP, fpus_internal, 90000000, 1.5, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, + {"100", CPU_WINCHIP, fpus_internal, 100000000, 1.5, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 12}, + {"120", CPU_WINCHIP, fpus_internal, 120000000, 2.0, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 14}, + {"133", CPU_WINCHIP, fpus_internal, 133333333, 2.0, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 16}, + {"150", CPU_WINCHIP, fpus_internal, 150000000, 2.5, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, + {"166", CPU_WINCHIP, fpus_internal, 166666666, 2.5, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 40}, + {"180", CPU_WINCHIP, fpus_internal, 180000000, 3.0, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 21}, + {"200", CPU_WINCHIP, fpus_internal, 200000000, 3.0, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, + {"225", CPU_WINCHIP, fpus_internal, 225000000, 3.0, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, + {"240", CPU_WINCHIP, fpus_internal, 240000000, 4.0, 3520, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "IDT", + .name = "WinChip 2", + .internal_name = "winchip2", + .cpus = (const CPU[]) { + {"200", CPU_WINCHIP2, fpus_internal, 200000000, 3.0, 3520, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*8}, + {"225", CPU_WINCHIP2, fpus_internal, 225000000, 3.0, 3520, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*9}, + {"240", CPU_WINCHIP2, fpus_internal, 240000000, 4.0, 3520, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"250", CPU_WINCHIP2, fpus_internal, 250000000, 3.0, 3520, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "IDT", + .name = "WinChip 2A", + .internal_name = "winchip2a", + .cpus = (const CPU[]) { + {"200", CPU_WINCHIP2, fpus_internal, 200000000, 3.0, 3520, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*8}, + {"233", CPU_WINCHIP2, fpus_internal, 233333333, 3.5, 3520, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 9, 9, (7*8)/2}, + {"266", CPU_WINCHIP2, fpus_internal, 233333333, 7.0/3.0, 3520, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 7, 7, 28}, + {"300", CPU_WINCHIP2, fpus_internal, 250000000, 2.5, 3520, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 8, 8, 30}, + {"", 0} + } + }, +#if defined(DEV_BRANCH) && defined(USE_AMD_K5) + { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K5 (5k86)", + .internal_name = "k5_5k86", + .cpus = (const CPU[]) { + {"75 (P75)", CPU_K5, fpus_internal, 75000000, 1.5, 3520, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"90 (P90)", CPU_K5, fpus_internal, 90000000, 1.5, 3520, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"100 (P100)", CPU_K5, fpus_internal, 100000000, 1.5, 3520, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"90 (PR120)", CPU_5K86, fpus_internal, 120000000, 2.0, 3520, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"100 (PR133)", CPU_5K86, fpus_internal, 133333333, 2.0, 3520, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"105 (PR150)", CPU_5K86, fpus_internal, 150000000, 2.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"116.5 (PR166)", CPU_5K86, fpus_internal, 166666666, 2.5, 3520, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"133 (PR200)", CPU_5K86, fpus_internal, 200000000, 3.0, 3520, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K5 (SSA/5)", + .internal_name = "k5_ssa5", + .cpus = (const CPU[]) { + {"75 (PR75)", CPU_K5, fpus_internal, 75000000, 1.5, 3520, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"90 (PR90)", CPU_K5, fpus_internal, 90000000, 1.5, 3520, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"100 (PR100)", CPU_K5, fpus_internal, 100000000, 1.5, 3520, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"", 0} + } + }, +#endif + { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K6 (Model 6)", + .internal_name = "k6_m6", + .cpus = (const CPU[]) { + {"66", CPU_K6, fpus_internal, 66666666, 1.0, 2900, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, /* out of spec */ + {"100", CPU_K6, fpus_internal, 100000000, 1.5, 2900, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_K6, fpus_internal, 133333333, 2.0, 2900, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, /* out of spec */ + {"166", CPU_K6, fpus_internal, 166666666, 2.5, 2900, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"200", CPU_K6, fpus_internal, 200000000, 3.0, 2900, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"233", CPU_K6, fpus_internal, 233333333, 3.5, 3200, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K6 (Model 7)", + .internal_name = "k6_m7", + .cpus = (const CPU[]) { + {"100", CPU_K6, fpus_internal, 100000000, 1.5, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_K6, fpus_internal, 133333333, 2.0, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, /* out of spec */ + {"166", CPU_K6, fpus_internal, 166666666, 2.5, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, /* out of spec */ + {"200", CPU_K6, fpus_internal, 200000000, 3.0, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"233", CPU_K6, fpus_internal, 233333333, 3.5, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"266", CPU_K6, fpus_internal, 266666666, 4.0, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"300", CPU_K6, fpus_internal, 300000000, 4.5, 2200, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K6-2", + .internal_name = "k6_2", + .cpus = (const CPU[]) { + {"100", CPU_K6_2, fpus_internal, 100000000, 1.5, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_K6_2, fpus_internal, 133333333, 2.0, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12, 12, 6, 6, 16}, /* out of spec */ + {"166", CPU_K6_2, fpus_internal, 166666666, 2.5, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15, 15, 7, 7, 20}, /* out of spec */ + {"200", CPU_K6_2, fpus_internal, 200000000, 3.0, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18, 18, 9, 9, 24}, /* out of spec */ + {"233", CPU_K6_2, fpus_internal, 233333333, 3.5, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21, 21, 10, 10, 28}, + {"266", CPU_K6_2, fpus_internal, 266666666, 4.0, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24, 24, 12, 12, 32}, + {"300", CPU_K6_2, fpus_internal, 300000000, 3.0, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27, 27, 9, 9, 36}, + {"333", CPU_K6_2, fpus_internal, 332500000, 3.5, 2200, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 30, 30, 11, 11, 40}, + {"350", CPU_K6_2C, fpus_internal, 350000000, 3.5, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, + {"366", CPU_K6_2C, fpus_internal, 366666666, 5.5, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, + {"380", CPU_K6_2C, fpus_internal, 380000000, 4.0, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, + {"400/66", CPU_K6_2C, fpus_internal, 400000000, 6.0, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"400/100", CPU_K6_2C, fpus_internal, 400000000, 4.0, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"450", CPU_K6_2C, fpus_internal, 450000000, 4.5, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"475", CPU_K6_2C, fpus_internal, 475000000, 5.0, 2400, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"500", CPU_K6_2C, fpus_internal, 500000000, 5.0, 2400, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"533", CPU_K6_2C, fpus_internal, 533333333, 5.5, 2200, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, + {"550", CPU_K6_2C, fpus_internal, 550000000, 5.5, 2300, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 50, 50, 17, 17, 66}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K6-2+", + .internal_name = "k6_2p", + .cpus = (const CPU[]) { + {"100", CPU_K6_2P, fpus_internal, 100000000, 1.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_K6_2P, fpus_internal, 133333333, 2.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12, 12, 6, 6, 16}, /* out of spec */ + {"166", CPU_K6_2P, fpus_internal, 166666666, 2.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15, 15, 7, 7, 20}, /* out of spec */ + {"200", CPU_K6_2P, fpus_internal, 200000000, 3.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18, 18, 9, 9, 24}, /* out of spec */ + {"233", CPU_K6_2P, fpus_internal, 233333333, 3.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21, 21, 10, 10, 28}, /* out of spec */ + {"266", CPU_K6_2P, fpus_internal, 266666666, 4.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24, 24, 12, 12, 32}, /* out of spec */ + {"300", CPU_K6_2P, fpus_internal, 300000000, 3.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27, 27, 9, 9, 36}, /* out of spec */ + {"333", CPU_K6_2P, fpus_internal, 332500000, 3.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 30, 30, 11, 11, 40}, /* out of spec */ + {"350", CPU_K6_2P, fpus_internal, 350000000, 3.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, /* out of spec */ + {"366", CPU_K6_2P, fpus_internal, 366666666, 5.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, /* out of spec */ + {"380", CPU_K6_2P, fpus_internal, 380000000, 4.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, /* out of spec */ + {"400/66", CPU_K6_2P, fpus_internal, 400000000, 6.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, /* out of spec */ + {"400/100", CPU_K6_2P, fpus_internal, 400000000, 4.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, /* out of spec */ + {"450", CPU_K6_2P, fpus_internal, 450000000, 4.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"475", CPU_K6_2P, fpus_internal, 475000000, 5.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"500", CPU_K6_2P, fpus_internal, 500000000, 5.0, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"533", CPU_K6_2P, fpus_internal, 533333333, 5.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, + {"550", CPU_K6_2P, fpus_internal, 550000000, 5.5, 2000, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 50, 50, 17, 17, 66}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K6-III", + .internal_name = "k6_3", + .cpus = (const CPU[]) { + {"100", CPU_K6_3, fpus_internal, 100000000, 1.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_K6_3, fpus_internal, 133333333, 2.0, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12, 12, 6, 6, 16}, /* out of spec */ + {"166", CPU_K6_3, fpus_internal, 166666666, 2.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15, 15, 7, 7, 20}, /* out of spec */ + {"200", CPU_K6_3, fpus_internal, 200000000, 3.0, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18, 18, 9, 9, 24}, /* out of spec */ + {"233", CPU_K6_3, fpus_internal, 233333333, 3.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21, 21, 10, 10, 28}, /* out of spec */ + {"266", CPU_K6_3, fpus_internal, 266666666, 4.0, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24, 24, 12, 12, 32}, /* out of spec */ + {"300", CPU_K6_3, fpus_internal, 300000000, 3.0, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27, 27, 9, 9, 36}, /* out of spec */ + {"333", CPU_K6_3, fpus_internal, 332500000, 3.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 30, 30, 11, 11, 40}, /* out of spec */ + {"350", CPU_K6_3, fpus_internal, 350000000, 3.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, /* out of spec */ + {"366", CPU_K6_3, fpus_internal, 366666666, 5.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, /* out of spec */ + {"380", CPU_K6_3, fpus_internal, 380000000, 4.0, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, /* out of spec */ + {"400", CPU_K6_3, fpus_internal, 400000000, 4.0, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"450", CPU_K6_3, fpus_internal, 450000000, 4.5, 2200, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "AMD", + .name = "K6-III+", + .internal_name = "k6_3p", + .cpus = (const CPU[]) { + {"100", CPU_K6_3P, fpus_internal, 100000000, 1.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, /* out of spec */ + {"133", CPU_K6_3P, fpus_internal, 133333333, 2.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12, 12, 6, 6, 16}, /* out of spec */ + {"166", CPU_K6_3P, fpus_internal, 166666666, 2.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15, 15, 7, 7, 20}, /* out of spec */ + {"200", CPU_K6_3P, fpus_internal, 200000000, 3.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18, 18, 9, 9, 24}, /* out of spec */ + {"233", CPU_K6_3P, fpus_internal, 233333333, 3.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21, 21, 10, 10, 28}, /* out of spec */ + {"266", CPU_K6_3P, fpus_internal, 266666666, 4.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24, 24, 12, 12, 32}, /* out of spec */ + {"300", CPU_K6_3P, fpus_internal, 300000000, 3.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27, 27, 9, 9, 36}, /* out of spec */ + {"333", CPU_K6_3P, fpus_internal, 332500000, 3.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 30, 30, 11, 11, 40}, /* out of spec */ + {"350", CPU_K6_3P, fpus_internal, 350000000, 3.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, /* out of spec */ + {"366", CPU_K6_3P, fpus_internal, 366666666, 5.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, /* out of spec */ + {"380", CPU_K6_3P, fpus_internal, 380000000, 4.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, /* out of spec */ + {"400", CPU_K6_3P, fpus_internal, 400000000, 4.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"450", CPU_K6_3P, fpus_internal, 450000000, 4.5, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"475", CPU_K6_3P, fpus_internal, 475000000, 5.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"500", CPU_K6_3P, fpus_internal, 500000000, 5.0, 2000, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"", 0} + } + }, #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) -CPU cpus_6x863V[] = { - /*Cyrix 6x86*/ - {"Cx6x86/P90", CPU_Cx6x86, fpus_internal, 80000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, - {"Cx6x86/PR120+", CPU_Cx6x86, fpus_internal, 100000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"Cx6x86/PR133+", CPU_Cx6x86, fpus_internal, 110000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"Cx6x86/PR150+", CPU_Cx6x86, fpus_internal, 120000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Cx6x86/PR166+", CPU_Cx6x86, fpus_internal, 133333333, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86/PR200+", CPU_Cx6x86, fpus_internal, 150000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; - -CPU cpus_6x86[] = { - /*Cyrix 6x86*/ - {"Cx6x86/P90", CPU_Cx6x86, fpus_internal, 80000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, - {"Cx6x86/PR120+", CPU_Cx6x86, fpus_internal, 100000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"Cx6x86/PR133+", CPU_Cx6x86, fpus_internal, 110000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"Cx6x86/PR150+", CPU_Cx6x86, fpus_internal, 120000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Cx6x86/PR166+", CPU_Cx6x86, fpus_internal, 133333333, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86/PR200+", CPU_Cx6x86, fpus_internal, 150000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, - - /*Cyrix 6x86L*/ - {"Cx6x86L/PR133+", CPU_Cx6x86L, fpus_internal, 110000000, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"Cx6x86L/PR150+", CPU_Cx6x86L, fpus_internal, 120000000, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Cx6x86L/PR166+", CPU_Cx6x86L, fpus_internal, 133333333, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86L/PR200+", CPU_Cx6x86L, fpus_internal, 150000000, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, - - /*Cyrix 6x86MX/MII*/ - {"Cx6x86MX/PR166", CPU_Cx6x86MX, fpus_internal, 133333333, 2.0, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86MX/PR200", CPU_Cx6x86MX, fpus_internal, 166666666, 2.5, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Cx6x86MX/PR233", CPU_Cx6x86MX, fpus_internal, 187500000, 2.5, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, - {"Cx6x86MX/PR266", CPU_Cx6x86MX, fpus_internal, 208333333, 2.5, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"MII/PR300", CPU_Cx6x86MX, fpus_internal, 233333333, 3.5, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, - {"MII/PR333", CPU_Cx6x86MX, fpus_internal, 250000000, 3.0, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - }; - - CPU cpus_6x86SS7[] = { - /*Cyrix 6x86*/ - {"Cx6x86/P90", CPU_Cx6x86, fpus_internal, 80000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, - {"Cx6x86/PR120+", CPU_Cx6x86, fpus_internal, 100000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"Cx6x86/PR133+", CPU_Cx6x86, fpus_internal, 110000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"Cx6x86/PR150+", CPU_Cx6x86, fpus_internal, 120000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Cx6x86/PR166+", CPU_Cx6x86, fpus_internal, 133333333, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86/PR200+", CPU_Cx6x86, fpus_internal, 150000000, 2.0, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, - - /*Cyrix 6x86L*/ - {"Cx6x86L/PR133+", CPU_Cx6x86L, fpus_internal, 110000000, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"Cx6x86L/PR150+", CPU_Cx6x86L, fpus_internal, 120000000, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Cx6x86L/PR166+", CPU_Cx6x86L, fpus_internal, 133333333, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86L/PR200+", CPU_Cx6x86L, fpus_internal, 150000000, 2.0, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, - - /*Cyrix 6x86MX/MII*/ - {"Cx6x86MX/PR166", CPU_Cx6x86MX, fpus_internal, 133333333, 2.0, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Cx6x86MX/PR200", CPU_Cx6x86MX, fpus_internal, 166666666, 2.5, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Cx6x86MX/PR233", CPU_Cx6x86MX, fpus_internal, 187500000, 2.5, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, - {"Cx6x86MX/PR266", CPU_Cx6x86MX, fpus_internal, 208333333, 2.5, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"MII/PR300", CPU_Cx6x86MX, fpus_internal, 233333333, 3.5, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, - {"MII/PR333", CPU_Cx6x86MX, fpus_internal, 250000000, 3.0, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30}, - {"MII/PR366", CPU_Cx6x86MX, fpus_internal, 250000000, 2.5, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 7, 7, 30}, - {"MII/PR400", CPU_Cx6x86MX, fpus_internal, 285000000, 3.0, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 34}, - {"MII/PR433", CPU_Cx6x86MX, fpus_internal, 300000000, 3.0, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 36}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - }; + { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Cyrix", + .name = "Cx6x86", + .internal_name = "cx6x86", + .cpus = (const CPU[]) { + {"P90", CPU_Cx6x86, fpus_internal, 80000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, + {"PR120+", CPU_Cx6x86, fpus_internal, 100000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"PR133+", CPU_Cx6x86, fpus_internal, 110000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"PR150+", CPU_Cx6x86, fpus_internal, 120000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"PR166+", CPU_Cx6x86, fpus_internal, 133333333, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"PR200+", CPU_Cx6x86, fpus_internal, 150000000, 2.0, 3520, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Cyrix", + .name = "Cx6x86L", + .internal_name = "cx6x86l", + .cpus = (const CPU[]) { + {"PR133+", CPU_Cx6x86L, fpus_internal, 110000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"PR150+", CPU_Cx6x86L, fpus_internal, 120000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"PR166+", CPU_Cx6x86L, fpus_internal, 133333333, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"PR200+", CPU_Cx6x86L, fpus_internal, 150000000, 2.0, 2800, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Cyrix", + .name = "Cx6x86MX", + .internal_name = "cx6x86mx", + .cpus = (const CPU[]) { + {"PR166", CPU_Cx6x86MX, fpus_internal, 133333333, 2.0, 2900, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"PR200", CPU_Cx6x86MX, fpus_internal, 166666666, 2.5, 2900, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"PR233", CPU_Cx6x86MX, fpus_internal, 187500000, 2.5, 2900, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, + {"PR266", CPU_Cx6x86MX, fpus_internal, 208333333, 2.5, 2700, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET5_7, + .manufacturer = "Cyrix", + .name = "MII", + .internal_name = "mii", + .cpus = (const CPU[]) { + {"PR300", CPU_Cx6x86MX, fpus_internal, 233333333, 3.5, 2900, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, + {"PR333", CPU_Cx6x86MX, fpus_internal, 250000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30}, + {"PR366", CPU_Cx6x86MX, fpus_internal, 250000000, 2.5, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 7, 7, 30}, + {"PR400", CPU_Cx6x86MX, fpus_internal, 285000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 34}, + {"PR433", CPU_Cx6x86MX, fpus_internal, 300000000, 3.0, 2900, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 36}, + {"", 0} + } + }, #endif - -CPU cpus_WinChip[] = { - /*IDT WinChip*/ - {"WinChip 75", CPU_WINCHIP, fpus_internal, 75000000, 1.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, - {"WinChip 90", CPU_WINCHIP, fpus_internal, 90000000, 1.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, - {"WinChip 100", CPU_WINCHIP, fpus_internal, 100000000, 1.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 12}, - {"WinChip 120", CPU_WINCHIP, fpus_internal, 120000000, 2.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 14}, - {"WinChip 133", CPU_WINCHIP, fpus_internal, 133333333, 2.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 16}, - {"WinChip 150", CPU_WINCHIP, fpus_internal, 150000000, 2.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, - {"WinChip 166", CPU_WINCHIP, fpus_internal, 166666666, 2.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 40}, - {"WinChip 180", CPU_WINCHIP, fpus_internal, 180000000, 3.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 21}, - {"WinChip 200", CPU_WINCHIP, fpus_internal, 200000000, 3.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, - {"WinChip 225", CPU_WINCHIP, fpus_internal, 225000000, 3.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, - {"WinChip 240", CPU_WINCHIP, fpus_internal, 240000000, 4.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, - {"WinChip 2/200", CPU_WINCHIP2, fpus_internal, 200000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, - {"WinChip 2/225", CPU_WINCHIP2, fpus_internal, 225000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, - {"WinChip 2/240", CPU_WINCHIP2, fpus_internal, 240000000, 4.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, - {"WinChip 2/250", CPU_WINCHIP2, fpus_internal, 250000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, - {"WinChip 2A/200", CPU_WINCHIP2, fpus_internal, 200000000, 3.0, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, - {"WinChip 2A/233", CPU_WINCHIP2, fpus_internal, 233333333, 3.5, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, (7*8)/2}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + { + .package = CPU_PKG_SOCKET8, + .manufacturer = "Intel", + .name = "Pentium Pro", + .internal_name = "pentiumpro", + .cpus = (const CPU[]) { + {"60", CPU_PENTIUMPRO, fpus_internal, 60000000, 1.0, 3100, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 1, 1, 7}, /* out of spec */ + {"66", CPU_PENTIUMPRO, fpus_internal, 66666666, 1.0, 3300, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 1, 1, 8}, /* out of spec */ + {"90", CPU_PENTIUMPRO, fpus_internal, 90000000, 1.5, 3100, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 3, 3, 11}, /* out of spec */ + {"100", CPU_PENTIUMPRO, fpus_internal, 100000000, 1.5, 3300, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 3, 3, 12}, /* out of spec */ + {"120", CPU_PENTIUMPRO, fpus_internal, 120000000, 2.0, 3100, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 5, 5, 14}, /* out of spec */ + {"133", CPU_PENTIUMPRO, fpus_internal, 133333333, 2.0, 3300, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 5, 5, 16}, /* out of spec */ + {"150", CPU_PENTIUMPRO, fpus_internal, 150000000, 2.5, 3100, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"166", CPU_PENTIUMPRO, fpus_internal, 166666666, 2.5, 3300, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"180", CPU_PENTIUMPRO, fpus_internal, 180000000, 3.0, 3300, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"200", CPU_PENTIUMPRO, fpus_internal, 200000000, 3.0, 3300, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET8, + .manufacturer = "Intel", + .name = "Pentium II OverDrive", + .internal_name = "pentium2_od", + .cpus = (const CPU[]) { + {"66", CPU_PENTIUM2D, fpus_internal, 66666666, 1.0, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6, 3, 3, 8}, /* out of spec */ + {"100", CPU_PENTIUM2D, fpus_internal, 100000000, 1.5, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_PENTIUM2D, fpus_internal, 133333333, 2.0, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12, 6, 6, 16}, /* out of spec */ + {"166", CPU_PENTIUM2D, fpus_internal, 166666666, 2.5, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15, 7, 7, 20}, /* out of spec */ + {"200", CPU_PENTIUM2D, fpus_internal, 200000000, 3.0, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 18,18, 9, 9, 24}, /* out of spec */ + {"233", CPU_PENTIUM2D, fpus_internal, 233333333, 3.5, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 21,21,10,10, 28}, /* out of spec */ + {"266", CPU_PENTIUM2D, fpus_internal, 266666666, 4.0, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 24,24,12,12, 32}, /* out of spec */ + {"300", CPU_PENTIUM2D, fpus_internal, 300000000, 5.0, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 27,27,13,13, 36}, + {"333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 3300, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 27,27,13,13, 40}, + {"", 0} + } + }, { + .package = CPU_PKG_SLOT1, + .manufacturer = "Intel", + .name = "Pentium II (Klamath)", + .internal_name = "pentium2_klamath", + .cpus = (const CPU[]) { + {"66", CPU_PENTIUM2, fpus_internal, 66666666, 1.0, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, /* out of spec */ + {"100", CPU_PENTIUM2, fpus_internal, 100000000, 1.5, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, /* out of spec */ + {"133", CPU_PENTIUM2, fpus_internal, 133333333, 2.0, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, /* out of spec */ + {"166", CPU_PENTIUM2, fpus_internal, 166666666, 2.5, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, /* out of spec */ + {"200", CPU_PENTIUM2, fpus_internal, 200000000, 3.0, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, /* out of spec */ + {"233", CPU_PENTIUM2, fpus_internal, 233333333, 3.5, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"266", CPU_PENTIUM2, fpus_internal, 266666666, 4.0, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"300", CPU_PENTIUM2, fpus_internal, 300000000, 4.5, 2800, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, + {"", 0} + } + }, { + .package = CPU_PKG_SLOT1, + .manufacturer = "Intel", + .name = "Pentium II (Deschutes)", + .internal_name = "pentium2_deschutes", + .cpus = (const CPU[]) { + {"66", CPU_PENTIUM2D, fpus_internal, 66666666, 1.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, /* out of spec */ + {"100", CPU_PENTIUM2D, fpus_internal, 100000000, 1.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 5, 5, 12}, /* out of spec */ + {"133", CPU_PENTIUM2D, fpus_internal, 133333333, 2.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, /* out of spec */ + {"166", CPU_PENTIUM2D, fpus_internal, 166666666, 2.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, /* out of spec */ + {"200", CPU_PENTIUM2D, fpus_internal, 200000000, 3.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, /* out of spec */ + {"233", CPU_PENTIUM2D, fpus_internal, 233333333, 3.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, /* out of spec */ + {"266", CPU_PENTIUM2D, fpus_internal, 266666666, 4.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"300", CPU_PENTIUM2D, fpus_internal, 300000000, 4.5, 2050, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, + {"333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 2050, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, + {"350", CPU_PENTIUM2D, fpus_internal, 350000000, 3.5, 2050, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32,32,11,11, 42}, + {"400", CPU_PENTIUM2D, fpus_internal, 400000000, 4.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36,36,12,12, 48}, + {"450", CPU_PENTIUM2D, fpus_internal, 450000000, 4.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41,41,14,14, 54}, + {"", 0} + } + }, { + .package = CPU_PKG_SLOT2, + .manufacturer = "Intel", + .name = "Pentium II Xeon", + .internal_name = "pentium2_xeon", + .cpus = (const CPU[]) { + {"100", CPU_PENTIUM2D, fpus_internal, 100000000, 1.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 3, 3, 12}, /* out of spec */ + {"150", CPU_PENTIUM2D, fpus_internal, 150000000, 1.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 14,14, 4, 4, 18}, /* out of spec */ + {"200", CPU_PENTIUM2D, fpus_internal, 200000000, 2.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 6, 6, 24}, /* out of spec */ + {"250", CPU_PENTIUM2D, fpus_internal, 250000000, 2.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 22,22, 7, 7, 30}, /* out of spec */ + {"300", CPU_PENTIUM2D, fpus_internal, 300000000, 3.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 36}, /* out of spec */ + {"350", CPU_PENTIUM2D, fpus_internal, 350000000, 3.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32,32,10,10, 42}, /* out of spec */ + {"400", CPU_PENTIUM2D, fpus_internal, 400000000, 4.0, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36,36,12,12, 48}, + {"450", CPU_PENTIUM2D, fpus_internal, 450000000, 4.5, 2050, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41,41,14,14, 54}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET370, + .manufacturer = "Intel", + .name = "Celeron (Mendocino)", + .internal_name = "celeron_mendocino", + .cpus = (const CPU[]) { + {"66", CPU_PENTIUM2D, fpus_internal, 66666666, 1.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6, 3, 3, 8}, /* out of spec */ + {"100", CPU_PENTIUM2D, fpus_internal, 100000000, 1.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 8, 8, 4, 4, 12}, /* out of spec */ + {"133", CPU_PENTIUM2D, fpus_internal, 133333333, 2.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 11,11, 5, 5, 16}, /* out of spec */ + {"166", CPU_PENTIUM2D, fpus_internal, 166666666, 2.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 14,14, 7, 7, 20}, /* out of spec */ + {"200", CPU_PENTIUM2D, fpus_internal, 200000000, 3.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 17,17, 8, 8, 24}, /* out of spec */ + {"233", CPU_PENTIUM2D, fpus_internal, 233333333, 3.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 19,19, 9, 9, 28}, /* out of spec */ + {"266", CPU_PENTIUM2D, fpus_internal, 266666666, 4.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 22,22,11,11, 32}, /* out of spec */ + {"300A", CPU_PENTIUM2D, fpus_internal, 300000000, 4.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 25,25,12,12, 36}, + {"333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 27,27,13,13, 40}, + {"366", CPU_PENTIUM2D, fpus_internal, 366666666, 5.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 33,33,17,17, 44}, + {"400", CPU_PENTIUM2D, fpus_internal, 400000000, 6.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 36,36,12,12, 48}, + {"433", CPU_PENTIUM2D, fpus_internal, 433333333, 6.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 39,39,13,13, 51}, + {"466", CPU_PENTIUM2D, fpus_internal, 466666666, 7.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 42,42,14,14, 56}, + {"500", CPU_PENTIUM2D, fpus_internal, 500000000, 7.5, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 45,45,15,15, 60}, + {"533", CPU_PENTIUM2D, fpus_internal, 533333333, 8.0, 2050, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 48,48,17,17, 64}, + {"", 0} + } + }, { + .package = CPU_PKG_SOCKET370, + .manufacturer = "VIA", + .name = "Cyrix III", + .internal_name = "c3_samuel", + .cpus = (const CPU[]) { + {"66", CPU_CYRIX3S, fpus_internal, 66666666, 1.0, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6, 3, 3, 8}, /* out of multiplier range */ + {"100", CPU_CYRIX3S, fpus_internal, 100000000, 1.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 9, 9, 4, 4, 12}, /* out of multiplier range */ + {"133", CPU_CYRIX3S, fpus_internal, 133333333, 2.0, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 12, 12, 6, 6, 16}, /* out of multiplier range */ + {"166", CPU_CYRIX3S, fpus_internal, 166666666, 2.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 15, 15, 7, 7, 20}, /* out of multiplier range */ + {"200", CPU_CYRIX3S, fpus_internal, 200000000, 3.0, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 18, 18, 8, 8, 24}, /* out of multiplier range */ + {"233", CPU_CYRIX3S, fpus_internal, 233333333, 3.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 21, 21, 9, 9, 28}, /* out of multiplier range */ + {"266", CPU_CYRIX3S, fpus_internal, 266666666, 4.0, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 24, 24, 12, 12, 32}, /* out of multiplier range */ + {"300", CPU_CYRIX3S, fpus_internal, 300000000, 4.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 27, 27, 13, 13, 36}, /* out of spec */ + {"333", CPU_CYRIX3S, fpus_internal, 333333333, 5.0, 2050, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 30, 30, 15, 15, 40}, /* out of spec */ + {"366", CPU_CYRIX3S, fpus_internal, 366666666, 5.5, 2050, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 33, 33, 16, 16, 44}, /* out of spec */ + {"400", CPU_CYRIX3S, fpus_internal, 400000000, 6.0, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 36, 36, 17, 17, 48}, + {"433", CPU_CYRIX3S, fpus_internal, 433333333, 6.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 39, 39, 18, 18, 52}, /* out of spec */ + {"450", CPU_CYRIX3S, fpus_internal, 450000000, 4.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 41, 41, 14, 14, 54}, + {"466", CPU_CYRIX3S, fpus_internal, 466666666, 6.5, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 42, 42, 14, 14, 56}, /* out of spec */ + {"500", CPU_CYRIX3S, fpus_internal, 500000000, 5.0, 2050, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 45, 45, 15, 15, 60}, + {"533", CPU_CYRIX3S, fpus_internal, 533333333, 8.0, 2050, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 48, 48, 15, 15, 64}, /* out of spec */ + {"550", CPU_CYRIX3S, fpus_internal, 550000000, 5.5, 2050, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 50, 50, 17, 17, 66}, + {"600/100", CPU_CYRIX3S, fpus_internal, 600000000, 6.0, 2050, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 54, 54, 18, 18, 72}, + {"600/133", CPU_CYRIX3S, fpus_internal, 600000000, 4.5, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 54, 54, 13, 13, 72}, + {"650", CPU_CYRIX3S, fpus_internal, 650000000, 6.5, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 58, 58, 20, 20, 78}, + {"667", CPU_CYRIX3S, fpus_internal, 666666667, 5.0, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 60, 60, 16, 16, 80}, + {"700", CPU_CYRIX3S, fpus_internal, 700000000, 7.0, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 63, 63, 21, 21, 84}, + {"733", CPU_CYRIX3S, fpus_internal, 733333333, 5.5, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 66, 66, 18, 18, 88}, + {"", 0} + } + }, { + .package = 0, + } }; -CPU cpus_WinChip_SS7[] = { - /*IDT WinChip*/ - {"WinChip 75", CPU_WINCHIP, fpus_internal, 75000000, 1.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, - {"WinChip 90", CPU_WINCHIP, fpus_internal, 90000000, 1.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, - {"WinChip 100", CPU_WINCHIP, fpus_internal, 100000000, 1.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 12}, - {"WinChip 120", CPU_WINCHIP, fpus_internal, 120000000, 2.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 14}, - {"WinChip 133", CPU_WINCHIP, fpus_internal, 133333333, 2.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 16}, - {"WinChip 150", CPU_WINCHIP, fpus_internal, 150000000, 2.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, - {"WinChip 166", CPU_WINCHIP, fpus_internal, 166666666, 2.5, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 40}, - {"WinChip 180", CPU_WINCHIP, fpus_internal, 180000000, 3.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 21}, - {"WinChip 200", CPU_WINCHIP, fpus_internal, 200000000, 3.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, - {"WinChip 225", CPU_WINCHIP, fpus_internal, 225000000, 3.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, - {"WinChip 240", CPU_WINCHIP, fpus_internal, 240000000, 4.0, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, - {"WinChip 2/200", CPU_WINCHIP2, fpus_internal, 200000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*8}, - {"WinChip 2/225", CPU_WINCHIP2, fpus_internal, 225000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*9}, - {"WinChip 2/240", CPU_WINCHIP2, fpus_internal, 240000000, 4.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, - {"WinChip 2/250", CPU_WINCHIP2, fpus_internal, 250000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, - {"WinChip 2A/200", CPU_WINCHIP2, fpus_internal, 200000000, 3.0, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*8}, - {"WinChip 2A/233", CPU_WINCHIP2, fpus_internal, 233333333, 3.5, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 9, 9, (7*8)/2}, - {"WinChip 2A/266", CPU_WINCHIP2, fpus_internal, 233333333, 7.0/3.0, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 7, 7, 28}, - {"WinChip 2A/300", CPU_WINCHIP2, fpus_internal, 250000000, 2.5, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 8, 8, 30}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +/* Legacy CPU tables for backwards compatibility. */ + +static const cpu_legacy_table_t cpus_8088[] = { + {"8088", 4772728, 1}, + {"8088", 7159092, 1}, + {"8088", 8000000, 1}, + {"8088", 10000000, 1}, + {"8088", 12000000, 1}, + {"8088", 16000000, 1}, + {NULL, 0, 0} }; -CPU cpus_Pentium5V[] = { - /*Intel Pentium (5V, socket 4)*/ - {"Pentium 60", CPU_PENTIUM, fpus_internal, 60000000, 1, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, fpus_internal, 66666666, 1, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, - {"Pentium OverDrive 120", CPU_PENTIUM, fpus_internal, 120000000, 2, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 133", CPU_PENTIUM, fpus_internal, 133333333, 2, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_pcjr[] = { + {"8088", 4772728, 1}, + {NULL, 0, 0} }; -CPU cpus_Pentium5V50[] = { - /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ - {"Pentium 50 (Q0399)", CPU_PENTIUM, fpus_internal, 50000000, 1, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4,3,3, 6}, - {"Pentium 60", CPU_PENTIUM, fpus_internal, 60000000, 1, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, fpus_internal, 66666666, 1, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, - {"Pentium OverDrive 100", CPU_PENTIUM, fpus_internal, 100000000, 2, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8,6,6, 12}, - {"Pentium OverDrive 120", CPU_PENTIUM, fpus_internal, 120000000, 2, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 133", CPU_PENTIUM, fpus_internal, 133333333, 2, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_europc[] = { + {"8088_europc", 4772728, 1}, + {"8088_europc", 7159092, 1}, + {"8088_europc", 9545456, 1}, + {NULL, 0, 0} }; -CPU cpus_PentiumS5[] = { - /*Intel Pentium (Socket 5)*/ - {"Pentium 75", CPU_PENTIUM, fpus_internal, 75000000, 1.5, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, fpus_internal, 75000000, 1.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, fpus_internal, 90000000, 1.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, fpus_internal, 100000000, 2.0, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"Pentium 100/66", CPU_PENTIUM, fpus_internal, 100000000, 1.5, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, - {"Pentium 120", CPU_PENTIUM, fpus_internal, 120000000, 2.0, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - - /*Intel Pentium OverDrive*/ - {"Pentium OverDrive 125", CPU_PENTIUM, fpus_internal, 125000000, 3.0, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 16}, - {"Pentium OverDrive 150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, fpus_internal, 125000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, fpus_internal, 150000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, fpus_internal, 166000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, fpus_internal, 180000000, 3.0, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_8086[] = { + {"8086", 7159092, 1}, + {"8086", 8000000, 1}, + {"8086", 9545456, 1}, + {"8086", 10000000, 1}, + {"8086", 12000000, 1}, + {"8086", 16000000, 1}, + {NULL, 0, 0} }; -CPU cpus_Pentium3V[] = { - /*Intel Pentium*/ - {"Pentium 75", CPU_PENTIUM, fpus_internal, 75000000, 1.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, fpus_internal, 75000000, 1.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium 90", CPU_PENTIUM, fpus_internal, 90000000, 1.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, fpus_internal, 100000000, 2.0, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"Pentium 100/66", CPU_PENTIUM, fpus_internal, 100000000, 1.5, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"Pentium 120", CPU_PENTIUM, fpus_internal, 120000000, 2.0, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Pentium 133", CPU_PENTIUM, fpus_internal, 133333333, 2.0, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Pentium 150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium 166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium 200", CPU_PENTIUM, fpus_internal, 200000000, 3.0, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - - /*Intel Pentium OverDrive*/ - {"Pentium OverDrive 125", CPU_PENTIUM, fpus_internal, 125000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive 150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, fpus_internal, 125000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, fpus_internal, 150000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, fpus_internal, 166000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, fpus_internal, 180000000, 3.0, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_pc1512[] = { + {"8086", 8000000, 1}, + {NULL, 0, 0} }; -CPU cpus_Pentium[] = { - /*Intel Pentium*/ - {"Pentium 75", CPU_PENTIUM, fpus_internal, 75000000, 1.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, fpus_internal, 75000000, 1.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium 90", CPU_PENTIUM, fpus_internal, 90000000, 1.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, fpus_internal, 100000000, 2.0, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"Pentium 100/66", CPU_PENTIUM, fpus_internal, 100000000, 1.5, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"Pentium 120", CPU_PENTIUM, fpus_internal, 120000000, 2.0, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Pentium 133", CPU_PENTIUM, fpus_internal, 133333333, 2.0, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Pentium 150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium 166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium 200", CPU_PENTIUM, fpus_internal, 200000000, 3.0, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - - /*Intel Pentium MMX*/ - {"Pentium MMX 166", CPU_PENTIUMMMX, fpus_internal, 166666666, 2.5, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium MMX 200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"Pentium MMX 233", CPU_PENTIUMMMX, fpus_internal, 233333333, 3.5, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - - /*Mobile Pentium*/ - {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, fpus_internal, 120000000, 2.0, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, fpus_internal, 133333333, 2.0, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, fpus_internal, 150000000, 2.5, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, fpus_internal, 166666666, 2.5, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, fpus_internal, 233333333, 3.5, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, fpus_internal, 266666666, 4.0, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, fpus_internal, 300000000, 4.5, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - - /*Intel Pentium OverDrive*/ - {"Pentium OverDrive 125", CPU_PENTIUM, fpus_internal, 125000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive 150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, fpus_internal, 125000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, fpus_internal, 150000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, fpus_internal, 166000000, 2.5, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, fpus_internal, 180000000, 3.0, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, fpus_internal, 200000000, 3.0, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"", -1, 0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_286[] = { + {"286", 6000000, 1}, + {"286", 8000000, 1}, + {"286", 10000000, 1}, + {"286", 12500000, 1}, + {"286", 16000000, 1}, + {"286", 20000000, 1}, + {"286", 25000000, 1}, + {NULL, 0, 0} }; -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) -CPU cpus_K5[] = { - /*AMD K5 (Socket 5)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, fpus_internal, 75000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, fpus_internal, 75000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, fpus_internal, 90000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, fpus_internal, 90000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, fpus_internal, 100000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, fpus_internal, 100000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, fpus_internal, 120000000, 2.0, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, fpus_internal, 133333333, 2.0, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, fpus_internal, 150000000, 2.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, fpus_internal, 166666666, 2.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, fpus_internal, 200000000, 3.0, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; -#endif - -CPU cpus_K56[] = { -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) - /*AMD K5 (Socket 7)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, fpus_internal, 75000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, fpus_internal, 75000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, fpus_internal, 90000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, fpus_internal, 90000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, fpus_internal, 100000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, fpus_internal, 100000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, fpus_internal, 120000000, 2.0, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, fpus_internal, 133333333, 2.0, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, fpus_internal, 150000000, 2.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, fpus_internal, 166666666, 2.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, fpus_internal, 200000000, 3.0, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, -#endif - - /*AMD K6 (Socket 7*/ - {"K6 (Model 6) 166", CPU_K6, fpus_internal, 166666666, 2.5, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"K6 (Model 6) 200", CPU_K6, fpus_internal, 200000000, 3.0, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"K6 (Model 6) 233", CPU_K6, fpus_internal, 233333333, 3.5, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, - {"K6 (Model 7) 200", CPU_K6, fpus_internal, 200000000, 3.0, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"K6 (Model 7) 233", CPU_K6, fpus_internal, 233333333, 3.5, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, - {"K6 (Model 7) 266", CPU_K6, fpus_internal, 266666666, 4.0, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24, 12, 12, 32}, - {"K6 (Model 7) 300", CPU_K6, fpus_internal, 300000000, 4.5, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 13, 13, 36}, - - /*AMD K6-2 (Socket 7)*/ - {"K6-2/233", CPU_K6_2, fpus_internal, 233333333, 3.5, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, - {"K6-2/266", CPU_K6_2, fpus_internal, 266666666, 4.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24, 12, 12, 32}, - {"K6-2/300 AFR-66", CPU_K6_2, fpus_internal, 300000000, 4.5, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 13, 13, 36}, - {"K6-2/366", CPU_K6_2, fpus_internal, 366666666, 5.5, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33,33, 17, 17, 44}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_ibmat[] = { + {"286", 6000000, 1}, + {"286", 8000000, 1}, + {NULL, 0, 0} }; -CPU cpus_K56_SS7[] = { -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) - /*AMD K5 (Socket 7)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, fpus_internal, 75000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, fpus_internal, 75000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, fpus_internal, 90000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, fpus_internal, 90000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, fpus_internal, 100000000, 1.5, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, fpus_internal, 100000000, 1.5, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, fpus_internal, 120000000, 2.0, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, fpus_internal, 133333333, 2.0, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, fpus_internal, 150000000, 2.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, fpus_internal, 166666666, 2.5, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, fpus_internal, 200000000, 3.0, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, -#endif - - /*AMD K6 (Socket 7)*/ - {"K6 (Model 6) 166", CPU_K6, fpus_internal, 166666666, 2.5, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"K6 (Model 6) 200", CPU_K6, fpus_internal, 200000000, 3.0, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"K6 (Model 6) 233", CPU_K6, fpus_internal, 233333333, 3.5, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"K6 (Model 7) 200", CPU_K6, fpus_internal, 200000000, 3.0, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"K6 (Model 7) 233", CPU_K6, fpus_internal, 233333333, 3.5, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"K6 (Model 7) 266", CPU_K6, fpus_internal, 266666666, 4.0, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"K6 (Model 7) 300", CPU_K6, fpus_internal, 300000000, 4.5, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - - /*AMD K6-2 (Socket 7/Super Socket 7)*/ - {"K6-2/233", CPU_K6_2, fpus_internal, 233333333, 3.5, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21, 21, 10, 10, 28}, - {"K6-2/266", CPU_K6_2, fpus_internal, 266666666, 4.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24, 24, 12, 12, 32}, - {"K6-2/300", CPU_K6_2, fpus_internal, 300000000, 3.0, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27, 27, 9, 9, 36}, - {"K6-2/333", CPU_K6_2, fpus_internal, 332500000, 3.5, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 30, 30, 11, 11, 40}, - {"K6-2/350", CPU_K6_2C, fpus_internal, 350000000, 3.5, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, - {"K6-2/366", CPU_K6_2C, fpus_internal, 366666666, 5.5, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, - {"K6-2/380", CPU_K6_2C, fpus_internal, 380000000, 4.0, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, - {"K6-2/400", CPU_K6_2C, fpus_internal, 400000000, 4.0, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, - {"K6-2/450", CPU_K6_2C, fpus_internal, 450000000, 4.5, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, - {"K6-2/475", CPU_K6_2C, fpus_internal, 475000000, 5.0, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, - {"K6-2/500", CPU_K6_2C, fpus_internal, 500000000, 5.0, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, - {"K6-2/533", CPU_K6_2C, fpus_internal, 533333333, 5.5, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, - {"K6-2/550", CPU_K6_2C, fpus_internal, 550000000, 5.5, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 50, 50, 17, 17, 66}, - - /*AMD K6-2+/K6-3/K6-3+ (Super Socket 7)*/ - {"K6-2+/450", CPU_K6_2P, fpus_internal, 450000000, 4.5, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, - {"K6-2+/475", CPU_K6_2P, fpus_internal, 475000000, 5.0, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, - {"K6-2+/500", CPU_K6_2P, fpus_internal, 500000000, 5.0, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, - {"K6-2+/533", CPU_K6_2P, fpus_internal, 533333333, 5.5, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, - {"K6-2+/550", CPU_K6_2P, fpus_internal, 550000000, 5.5, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 50, 50, 17, 17, 66}, - {"K6-III/400", CPU_K6_3, fpus_internal, 400000000, 4.0, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, - {"K6-III/450", CPU_K6_3, fpus_internal, 450000000, 4.5, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, - {"K6-III+/75", CPU_K6_3P, fpus_internal, 75000000, 1.5, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K6-III+/400", CPU_K6_3P, fpus_internal, 400000000, 4.0, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, - {"K6-III+/450", CPU_K6_3P, fpus_internal, 450000000, 4.5, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, - {"K6-III+/475", CPU_K6_3P, fpus_internal, 475000000, 5.0, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, - {"K6-III+/500", CPU_K6_3P, fpus_internal, 500000000, 5.0, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_ibmxt286[] = { + {"286", 6000000, 1}, + {NULL, 0, 0} }; -CPU cpus_PentiumPro[] = { - /*Intel Pentium Pro*/ - {"Pentium Pro 50", CPU_PENTIUMPRO, fpus_internal, 50000000, 1.0, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, - {"Pentium Pro 60" , CPU_PENTIUMPRO, fpus_internal, 60000000, 1.0, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, - {"Pentium Pro 66" , CPU_PENTIUMPRO, fpus_internal, 66666666, 1.0, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, - {"Pentium Pro 75", CPU_PENTIUMPRO, fpus_internal, 75000000, 1.5, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium Pro 150", CPU_PENTIUMPRO, fpus_internal, 150000000, 2.5, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium Pro 166", CPU_PENTIUMPRO, fpus_internal, 166666666, 2.5, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium Pro 180", CPU_PENTIUMPRO, fpus_internal, 180000000, 3.0, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, - {"Pentium Pro 200", CPU_PENTIUMPRO, fpus_internal, 200000000, 3.0, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - - /*Intel Pentium II OverDrive*/ - {"Pentium II Overdrive 50", CPU_PENTIUM2D, fpus_internal, 50000000, 1.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, - {"Pentium II Overdrive 60", CPU_PENTIUM2D, fpus_internal, 60000000, 1.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, - {"Pentium II Overdrive 66", CPU_PENTIUM2D, fpus_internal, 66666666, 1.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, - {"Pentium II Overdrive 75", CPU_PENTIUM2D, fpus_internal, 75000000, 1.5, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Overdrive 210", CPU_PENTIUM2D, fpus_internal, 210000000, 3.5, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"Pentium II Overdrive 233", CPU_PENTIUM2D, fpus_internal, 233333333, 3.5, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Pentium II Overdrive 240", CPU_PENTIUM2D, fpus_internal, 240000000, 4.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 29}, - {"Pentium II Overdrive 266", CPU_PENTIUM2D, fpus_internal, 266666666, 4.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Overdrive 270", CPU_PENTIUM2D, fpus_internal, 270000000, 4.5, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, - {"Pentium II Overdrive 300/66", CPU_PENTIUM2D, fpus_internal, 300000000, 4.5, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - {"Pentium II Overdrive 300/60", CPU_PENTIUM2D, fpus_internal, 300000000, 5.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium II Overdrive 333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_ps1_m2011[] = { + {"286", 10000000, 1}, + {NULL, 0, 0} }; -CPU cpus_PentiumII66[] = { - /*Intel Pentium II Klamath*/ - {"Pentium II Klamath 50", CPU_PENTIUM2, fpus_internal, 50000000, 1.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, - {"Pentium II Klamath 60", CPU_PENTIUM2, fpus_internal, 60000000, 1.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, - {"Pentium II Klamath 66", CPU_PENTIUM2, fpus_internal, 66666666, 1.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, - {"Pentium II Klamath 75", CPU_PENTIUM2, fpus_internal, 75000000, 1.5, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Klamath 233", CPU_PENTIUM2, fpus_internal, 233333333, 3.5, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Pentium II Klamath 266", CPU_PENTIUM2, fpus_internal, 266666666, 4.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Klamath 300/66", CPU_PENTIUM2, fpus_internal, 300000000, 4.5, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, +static const cpu_legacy_table_t cpus_ps2_m30_286[] = { + {"286", 10000000, 1}, + {"286", 12500000, 1}, + {"286", 16000000, 1}, + {"286", 20000000, 1}, + {"286", 25000000, 1}, + {NULL, 0, 0} +}; - /*Intel Pentium II Deschutes*/ - {"Pentium II Deschutes 50", CPU_PENTIUM2D, fpus_internal, 50000000, 1.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, - {"Pentium II Deschutes 60", CPU_PENTIUM2D, fpus_internal, 60000000, 1.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, - {"Pentium II Deschutes 66", CPU_PENTIUM2D, fpus_internal, 66666666, 1.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, - {"Pentium II Deschutes 75", CPU_PENTIUM2D, fpus_internal, 75000000, 1.5, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Deschutes 266", CPU_PENTIUM2D, fpus_internal, 266666666, 4.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Deschutes 300/66", CPU_PENTIUM2D, fpus_internal, 300000000, 4.5, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - {"Pentium II Deschutes 333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_i386SX[] = { + {"i386sx", 16000000, 1}, + {"i386sx", 20000000, 1}, + {"i386sx", 25000000, 1}, + {"i386sx", 33333333, 1}, + {"i386sx", 40000000, 1}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_i386DX[] = { + {"i386dx", 16000000, 1}, + {"i386dx", 20000000, 1}, + {"i386dx", 25000000, 1}, + {"i386dx", 33333333, 1}, + {"i386dx", 40000000, 1}, + {"rapidcad", 25000000, 1}, + {"rapidcad", 33333333, 1}, + {"rapidcad", 40000000, 1}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Am386SX[] = { + {"am386sx", 16000000, 1}, + {"am386sx", 20000000, 1}, + {"am386sx", 25000000, 1}, + {"am386sx", 33333333, 1}, + {"am386sx", 40000000, 1}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Am386DX[] = { + {"am386dx", 25000000, 1}, + {"am386dx", 33333333, 1}, + {"am386dx", 40000000, 1}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_ALiM6117[] = { + {"m6117", 33333333, 1}, + {"m6117", 40000000, 1}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_486SLC[] = { + {"cx486slc", 20000000, 1}, + {"cx486slc", 25000000, 1}, + {"cx486slc", 33333333, 1}, + {"cx486srx2", 32000000, 2}, + {"cx486srx2", 40000000, 2}, + {"cx486srx2", 50000000, 2}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_IBM486SLC[] = { + {"ibm486slc", 33333333, 1}, + {"ibm486slc2", 40000000, 2}, + {"ibm486slc2", 50000000, 2}, + {"ibm486slc2", 66666666, 2}, + {"ibm486slc3", 60000000, 3}, + {"ibm486slc3", 75000000, 3}, + {"ibm486slc3", 100000000, 3}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_IBM486BL[] = { + {"ibm486bl2", 50000000, 2}, + {"ibm486bl2", 66666666, 2}, + {"ibm486bl3", 75000000, 3}, + {"ibm486bl3", 100000000, 3}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_486DLC[] = { + {"cx486dlc", 25000000, 1}, + {"cx486dlc", 33333333, 1}, + {"cx486dlc", 40000000, 1}, + {"cx486drx2", 32000000, 2}, + {"cx486drx2", 40000000, 2}, + {"cx486drx2", 50000000, 2}, + {"cx486drx2", 66666666, 2}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_i486S1[] = { + {"i486sx", 16000000, 1}, + {"i486sx", 20000000, 1}, + {"i486sx", 25000000, 1}, + {"i486sx", 33333333, 1}, + {"i486sx2", 50000000, 2}, + {"i486sx2", 66666666, 2}, + {"i486dx", 25000000, 1}, + {"i486dx", 33333333, 1}, + {"i486dx", 50000000, 1}, + {"i486dx2", 40000000, 2}, + {"i486dx2", 50000000, 2}, + {"i486dx2", 66666666, 2}, + {"idx4_od", 75000000, 3}, + {"idx4_od", 100000000, 3}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Am486S1[] = { + {"am486sx", 33333333, 1}, + {"am486sx", 40000000, 1}, + {"am486sx2", 50000000, 2}, + {"am486sx2", 66666666, 2}, + {"am486dx", 33333333, 1}, + {"am486dx", 40000000, 1}, + {"am486dx2", 50000000, 2}, + {"am486dx2", 66666666, 2}, + {"am486dx2", 80000000, 2}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Cx486S1[] = { + {"cx486s", 25000000, 1.0}, + {"cx486s", 33333333, 1.0}, + {"cx486s", 40000000, 1.0}, + {"cx486dx", 33333333, 1.0}, + {"cx486dx", 40000000, 1.0}, + {"cx486dx2", 50000000, 2.0}, + {"cx486dx2", 66666666, 2.0}, + {"cx486dx2", 80000000, 2.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_i486[] = { + {"i486sx", 16000000, 1.0}, + {"i486sx", 20000000, 1.0}, + {"i486sx", 25000000, 1.0}, + {"i486sx", 33333333, 1.0}, + {"i486sx2", 50000000, 2.0}, + {"i486sx2", 66666666, 2.0}, + {"i486dx", 25000000, 1.0}, + {"i486dx", 33333333, 1.0}, + {"i486dx", 50000000, 1.0}, + {"i486dx2", 40000000, 2.0}, + {"i486dx2", 50000000, 2.0}, + {"i486dx2", 66666666, 2.0}, + {"idx4", 75000000, 3.0}, + {"idx4", 100000000, 3.0}, + {"idx4_od", 75000000, 3.0}, + {"idx4_od", 100000000, 3.0}, + {"pentium_p24t", 62500000, 2.5}, + {"pentium_p24t", 83333333, 2.5}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_i486_PC330[] = { + {"i486dx2", 50000000, 2.0}, + {"i486dx2", 66666666, 2.0}, + {"idx4", 75000000, 3.0}, + {"idx4", 100000000, 3.0}, + {"pentium_p24t", 62500000, 2.5}, + {"pentium_p24t", 83333333, 2.5}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Am486[] = { + {"am486sx", 33333333, 1.0}, + {"am486sx", 40000000, 1.0}, + {"am486sx2", 50000000, 2.0}, + {"am486sx2", 66666666, 2.0}, + {"am486dx", 33333333, 1.0}, + {"am486dx", 40000000, 1.0}, + {"am486dx2", 50000000, 2.0}, + {"am486dx2", 66666666, 2.0}, + {"am486dx2", 80000000, 2.0}, + {"am486dx4", 75000000, 3.0}, + {"am486dx4", 90000000, 3.0}, + {"am486dx4", 100000000, 3.0}, + {"am486dx4", 120000000, 3.0}, + {"am5x86", 133333333, 4.0}, + {"am5x86", 150000000, 3.0}, + {"am5x86", 160000000, 4.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Cx486[] = { + {"cx486s", 25000000, 1.0}, + {"cx486s", 33333333, 1.0}, + {"cx486s", 40000000, 1.0}, + {"cx486dx", 33333333, 1.0}, + {"cx486dx", 40000000, 1.0}, + {"cx486dx2", 50000000, 2.0}, + {"cx486dx2", 66666666, 2.0}, + {"cx486dx2", 80000000, 2.0}, + {"cx486dx4", 75000000, 3.0}, + {"cx486dx4", 100000000, 3.0}, + {"cx5x86", 80000000, 2.0}, + {"cx5x86", 100000000, 3.0}, + {"cx5x86", 120000000, 3.0}, + {"cx5x86", 133333333, 4.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_STPCDX[] = { + {"stpc_dx", 66666666, 1.0}, + {"stpc_dx", 75000000, 1.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_STPCDX2[] = { + {"stpc_dx2", 133333333, 2.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_6x863V[] = { + {"cx6x86", 80000000, 2.0}, + {"cx6x86", 100000000, 2.0}, + {"cx6x86", 110000000, 2.0}, + {"cx6x86", 120000000, 2.0}, + {"cx6x86", 133333333, 2.0}, + {"cx6x86", 150000000, 2.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_6x86[] = { + {"cx6x86", 80000000, 2.0}, + {"cx6x86", 100000000, 2.0}, + {"cx6x86", 110000000, 2.0}, + {"cx6x86", 120000000, 2.0}, + {"cx6x86", 133333333, 2.0}, + {"cx6x86", 150000000, 2.0}, + {"cx6x86l", 110000000, 2.0}, + {"cx6x86l", 120000000, 2.0}, + {"cx6x86l", 133333333, 2.0}, + {"cx6x86l", 150000000, 2.0}, + {"cx6x86mx", 133333333, 2.0}, + {"cx6x86mx", 166666666, 2.5}, + {"cx6x86mx", 187500000, 2.5}, + {"cx6x86mx", 208333333, 2.5}, + {"mii", 233333333, 3.5}, + {"mii", 250000000, 3.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_6x86SS7[] = { + {"cx6x86", 80000000, 2.0}, + {"cx6x86", 100000000, 2.0}, + {"cx6x86", 110000000, 2.0}, + {"cx6x86", 120000000, 2.0}, + {"cx6x86", 133333333, 2.0}, + {"cx6x86", 150000000, 2.0}, + {"cx6x86l", 110000000, 2.0}, + {"cx6x86l", 120000000, 2.0}, + {"cx6x86l", 133333333, 2.0}, + {"cx6x86l", 150000000, 2.0}, + {"cx6x86mx", 133333333, 2.0}, + {"cx6x86mx", 166666666, 2.5}, + {"cx6x86mx", 187500000, 2.5}, + {"cx6x86mx", 208333333, 2.5}, + {"mii", 233333333, 3.5}, + {"mii", 250000000, 3.0}, + {"mii", 250000000, 2.5}, + {"mii", 285000000, 3.0}, + {"mii", 300000000, 3.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_WinChip[] = { + {"winchip", 75000000, 1.5}, + {"winchip", 90000000, 1.5}, + {"winchip", 100000000, 1.5}, + {"winchip", 120000000, 2.0}, + {"winchip", 133333333, 2.0}, + {"winchip", 150000000, 2.5}, + {"winchip", 166666666, 2.5}, + {"winchip", 180000000, 3.0}, + {"winchip", 200000000, 3.0}, + {"winchip", 225000000, 3.0}, + {"winchip", 240000000, 4.0}, + {"winchip2", 200000000, 3.0}, + {"winchip2", 225000000, 3.0}, + {"winchip2", 240000000, 4.0}, + {"winchip2", 250000000, 3.0}, + {"winchip2a", 200000000, 3.0}, + {"winchip2a", 233333333, 3.5}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_WinChip_SS7[] = { + {"winchip", 75000000, 1.5}, + {"winchip", 90000000, 1.5}, + {"winchip", 100000000, 1.5}, + {"winchip", 120000000, 2.0}, + {"winchip", 133333333, 2.0}, + {"winchip", 150000000, 2.5}, + {"winchip", 166666666, 2.5}, + {"winchip", 180000000, 3.0}, + {"winchip", 200000000, 3.0}, + {"winchip", 225000000, 3.0}, + {"winchip", 240000000, 4.0}, + {"winchip2", 200000000, 3.0}, + {"winchip2", 225000000, 3.0}, + {"winchip2", 240000000, 4.0}, + {"winchip2", 250000000, 3.0}, + {"winchip2a", 200000000, 3.0}, + {"winchip2a", 233333333, 3.5}, + {"winchip2a", 233333333, 7.0}, + {"winchip2a", 250000000, 2.5}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Pentium5V[] = { + {"pentium_p5", 60000000, 1}, + {"pentium_p5", 66666666, 1}, + {"pentium_p54c_od5v", 120000000, 2}, + {"pentium_p54c_od5v", 133333333, 2}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_PentiumS5[] = { + {"pentium_p54c", 75000000, 1.5}, + {"pentium_p55c_od", 75000000, 1.5}, + {"pentium_p54c", 90000000, 1.5}, + {"pentium_p54c", 100000000, 2.0}, + {"pentium_p54c", 100000000, 1.5}, + {"pentium_p54c", 120000000, 2.0}, + {"pentium_p54c", 133333333, 2.0}, + {"pentium_p54c_od3v", 125000000, 3.0}, + {"pentium_p54c_od3v", 150000000, 2.5}, + {"pentium_p54c_od3v", 166666666, 2.5}, + {"pentium_p55c_od", 125000000, 2.5}, + {"pentium_p55c_od", 150000000, 2.5}, + {"pentium_p55c_od", 166000000, 2.5}, + {"pentium_p55c_od", 180000000, 3.0}, + {"pentium_p55c_od", 200000000, 3.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Pentium3V[] = { + {"pentium_p54c", 75000000, 1.5}, + {"pentium_p55c_od", 75000000, 1.5}, + {"pentium_p54c", 90000000, 1.5}, + {"pentium_p54c", 100000000, 2.0}, + {"pentium_p54c", 100000000, 1.5}, + {"pentium_p54c", 120000000, 2.0}, + {"pentium_p54c", 133333333, 2.0}, + {"pentium_p54c", 150000000, 2.5}, + {"pentium_p54c", 166666666, 2.5}, + {"pentium_p54c", 200000000, 3.0}, + {"pentium_p54c_od3v", 125000000, 2.5}, + {"pentium_p54c_od3v", 150000000, 2.5}, + {"pentium_p54c_od3v", 166666666, 2.5}, + {"pentium_p55c_od", 125000000, 2.5}, + {"pentium_p55c_od", 150000000, 2.5}, + {"pentium_p55c_od", 166000000, 2.5}, + {"pentium_p55c_od", 180000000, 3.0}, + {"pentium_p55c_od", 200000000, 3.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Pentium[] = { + {"pentium_p54c", 75000000, 1.5}, + {"pentium_p55c_od", 75000000, 1.5}, + {"pentium_p54c", 90000000, 1.5}, + {"pentium_p54c", 100000000, 2.0}, + {"pentium_p54c", 100000000, 1.5}, + {"pentium_p54c", 120000000, 2.0}, + {"pentium_p54c", 133333333, 2.0}, + {"pentium_p54c", 150000000, 2.5}, + {"pentium_p54c", 166666666, 2.5}, + {"pentium_p54c", 200000000, 3.0}, + {"pentium_p55c", 166666666, 2.5}, + {"pentium_p55c", 200000000, 3.0}, + {"pentium_p55c", 233333333, 3.5}, + {"pentium_tillamook", 120000000, 2.0}, + {"pentium_tillamook", 133333333, 2.0}, + {"pentium_tillamook", 150000000, 2.5}, + {"pentium_tillamook", 166666666, 2.5}, + {"pentium_tillamook", 200000000, 3.0}, + {"pentium_tillamook", 233333333, 3.5}, + {"pentium_tillamook", 266666666, 4.0}, + {"pentium_tillamook", 300000000, 4.5}, + {"pentium_p54c_od3v", 125000000, 2.5}, + {"pentium_p54c_od3v", 150000000, 2.5}, + {"pentium_p54c_od3v", 166666666, 2.5}, + {"pentium_p55c_od", 125000000, 2.5}, + {"pentium_p55c_od", 150000000, 2.5}, + {"pentium_p55c_od", 166000000, 2.5}, + {"pentium_p55c_od", 180000000, 3.0}, + {"pentium_p55c_od", 200000000, 3.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_K5[] = { + {"k5_5k86", 75000000, 1.5}, + {"k5_ssa5", 75000000, 1.5}, + {"k5_5k86", 90000000, 1.5}, + {"k5_ssa5", 90000000, 1.5}, + {"k5_5k86", 100000000, 1.5}, + {"k5_ssa5", 100000000, 1.5}, + {"k5_5k86", 120000000, 2.0}, + {"k5_5k86", 133333333, 2.0}, + {"k5_5k86", 150000000, 2.5}, + {"k5_5k86", 166666666, 2.5}, + {"k5_5k86", 200000000, 3.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_K56[] = { + {"k6_m6", 66666666, 1.0}, + {"k6_m6", 100000000, 1.5}, + {"k6_m6", 133333333, 2.0}, + {"k6_m6", 166666666, 2.5}, + {"k6_m6", 200000000, 3.0}, + {"k6_m6", 233333333, 3.5}, + {"k6_m7", 100000000, 1.5}, + {"k6_m7", 133333333, 2.0}, + {"k6_m7", 166666666, 2.5}, + {"k6_m7", 200000000, 3.0}, + {"k6_m7", 233333333, 3.5}, + {"k6_m7", 266666666, 4.0}, + {"k6_m7", 300000000, 4.5}, + {"k6_2", 100000000, 1.5}, + {"k6_2", 133333333, 2.0}, + {"k6_2", 166666666, 2.5}, + {"k6_2", 200000000, 3.0}, + {"k6_2", 233333333, 3.5}, + {"k6_2", 266666666, 4.0}, + {"k6_2", 300000000, 4.5}, + {"k6_2", 366666666, 5.5}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_K56_SS7[] = { + {"k6_m6", 66666666, 1.0}, + {"k6_m6", 100000000, 1.5}, + {"k6_m6", 133333333, 2.0}, + {"k6_m6", 166666666, 2.5}, + {"k6_m6", 200000000, 3.0}, + {"k6_m6", 233333333, 3.5}, + {"k6_m7", 100000000, 1.5}, + {"k6_m7", 133333333, 2.0}, + {"k6_m7", 166666666, 2.5}, + {"k6_m7", 200000000, 3.0}, + {"k6_m7", 233333333, 3.5}, + {"k6_m7", 266666666, 4.0}, + {"k6_m7", 300000000, 4.5}, + {"k6_2", 100000000, 1.5}, + {"k6_2", 133333333, 2.0}, + {"k6_2", 166666666, 2.5}, + {"k6_2", 200000000, 3.0}, + {"k6_2", 233333333, 3.5}, + {"k6_2", 266666666, 4.0}, + {"k6_2", 300000000, 3.0}, + {"k6_2", 332500000, 3.5}, + {"k6_2", 350000000, 3.5}, + {"k6_2", 366666666, 5.5}, + {"k6_2", 380000000, 4.0}, + {"k6_2", 400000000, 4.0}, + {"k6_2", 450000000, 4.5}, + {"k6_2", 475000000, 5.0}, + {"k6_2", 500000000, 5.0}, + {"k6_2", 533333333, 5.5}, + {"k6_2", 550000000, 5.5}, + {"k6_2p", 100000000, 1.5}, + {"k6_2p", 133333333, 2.0}, + {"k6_2p", 166666666, 2.5}, + {"k6_2p", 200000000, 3.0}, + {"k6_2p", 233333333, 3.5}, + {"k6_2p", 266666666, 4.0}, + {"k6_2p", 300000000, 3.0}, + {"k6_2p", 332500000, 3.5}, + {"k6_2p", 350000000, 3.5}, + {"k6_2p", 366666666, 5.5}, + {"k6_2p", 380000000, 4.0}, + {"k6_2p", 400000000, 4.0}, + {"k6_2p", 450000000, 4.5}, + {"k6_2p", 475000000, 5.0}, + {"k6_2p", 500000000, 5.0}, + {"k6_2p", 533333333, 5.5}, + {"k6_2p", 550000000, 5.5}, + {"k6_3", 100000000, 1.5}, + {"k6_3", 133333333, 2.0}, + {"k6_3", 166666666, 2.5}, + {"k6_3", 200000000, 3.0}, + {"k6_3", 233333333, 3.5}, + {"k6_3", 266666666, 4.0}, + {"k6_3", 300000000, 3.0}, + {"k6_3", 332500000, 3.5}, + {"k6_3", 350000000, 3.5}, + {"k6_3", 366666666, 5.5}, + {"k6_3", 380000000, 4.0}, + {"k6_3", 400000000, 4.0}, + {"k6_3", 450000000, 4.5}, + {"k6_3p", 75000000, 1.5}, + {"k6_3p", 100000000, 1.5}, + {"k6_3p", 133333333, 2.0}, + {"k6_3p", 166666666, 2.5}, + {"k6_3p", 200000000, 3.0}, + {"k6_3p", 233333333, 3.5}, + {"k6_3p", 266666666, 4.0}, + {"k6_3p", 300000000, 3.0}, + {"k6_3p", 332500000, 3.5}, + {"k6_3p", 350000000, 3.5}, + {"k6_3p", 366666666, 5.5}, + {"k6_3p", 380000000, 4.0}, + {"k6_3p", 400000000, 4.0}, + {"k6_3p", 450000000, 4.5}, + {"k6_3p", 475000000, 5.0}, + {"k6_3p", 500000000, 5.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_PentiumPro[] = { + {"pentiumpro", 50000000, 1.0}, + {"pentiumpro", 60000000, 1.0}, + {"pentiumpro", 66666666, 1.0}, + {"pentiumpro", 75000000, 1.5}, + {"pentiumpro", 150000000, 2.5}, + {"pentiumpro", 166666666, 2.5}, + {"pentiumpro", 180000000, 3.0}, + {"pentiumpro", 200000000, 3.0}, + {"pentium2_od", 50000000, 1.0}, + {"pentium2_od", 60000000, 1.0}, + {"pentium2_od", 66666666, 1.0}, + {"pentium2_od", 75000000, 1.5}, + {"pentium2_od", 210000000, 3.5}, + {"pentium2_od", 233333333, 3.5}, + {"pentium2_od", 240000000, 4.0}, + {"pentium2_od", 266666666, 4.0}, + {"pentium2_od", 270000000, 4.5}, + {"pentium2_od", 300000000, 4.5}, + {"pentium2_od", 300000000, 5.0}, + {"pentium2_od", 333333333, 5.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_PentiumII66[] = { + {"pentium2_klamath", 50000000, 1.0}, + {"pentium2_klamath", 60000000, 1.0}, + {"pentium2_klamath", 66666666, 1.0}, + {"pentium2_klamath", 75000000, 1.5}, + {"pentium2_klamath", 233333333, 3.5}, + {"pentium2_klamath", 266666666, 4.0}, + {"pentium2_klamath", 300000000, 4.5}, + {"pentium2_deschutes", 50000000, 1.0}, + {"pentium2_deschutes", 60000000, 1.0}, + {"pentium2_deschutes", 66666666, 1.0}, + {"pentium2_deschutes", 75000000, 1.5}, + {"pentium2_deschutes", 266666666, 4.0}, + {"pentium2_deschutes", 300000000, 4.5}, + {"pentium2_deschutes", 333333333, 5.0}, + {NULL, 0, 0} }; -CPU cpus_PentiumII[] = { - /*Intel Pentium II Klamath*/ - {"Pentium II Klamath 50", CPU_PENTIUM2, fpus_internal, 50000000, 1.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, - {"Pentium II Klamath 60", CPU_PENTIUM2, fpus_internal, 60000000, 1.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, - {"Pentium II Klamath 66", CPU_PENTIUM2, fpus_internal, 66666666, 1.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, - {"Pentium II Klamath 75", CPU_PENTIUM2, fpus_internal, 75000000, 1.5, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Klamath 233", CPU_PENTIUM2, fpus_internal, 233333333, 3.5, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Pentium II Klamath 266", CPU_PENTIUM2, fpus_internal, 266666666, 4.0, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Klamath 300/66", CPU_PENTIUM2, fpus_internal, 300000000, 4.5, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - - /*Intel Pentium II Deschutes*/ - {"Pentium II Deschutes 50", CPU_PENTIUM2D, fpus_internal, 50000000, 1.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, - {"Pentium II Deschutes 60", CPU_PENTIUM2D, fpus_internal, 60000000, 1.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, - {"Pentium II Deschutes 66", CPU_PENTIUM2D, fpus_internal, 66666666, 1.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, - {"Pentium II Deschutes 75", CPU_PENTIUM2D, fpus_internal, 75000000, 1.5, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Deschutes 266", CPU_PENTIUM2D, fpus_internal, 266666666, 4.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Deschutes 300/66", CPU_PENTIUM2D, fpus_internal, 300000000, 4.5, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - {"Pentium II Deschutes 333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"Pentium II Deschutes 350", CPU_PENTIUM2D, fpus_internal, 350000000, 3.5, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32,32,11,11, 42}, - {"Pentium II Deschutes 400", CPU_PENTIUM2D, fpus_internal, 400000000, 4.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36,36,12,12, 48}, - {"Pentium II Deschutes 450", CPU_PENTIUM2D, fpus_internal, 450000000, 4.5, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41,41,14,14, 54}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - +static const cpu_legacy_table_t cpus_PentiumII[] = { + {"pentium2_klamath", 50000000, 1.0}, + {"pentium2_klamath", 60000000, 1.0}, + {"pentium2_klamath", 66666666, 1.0}, + {"pentium2_klamath", 75000000, 1.5}, + {"pentium2_klamath", 233333333, 3.5}, + {"pentium2_klamath", 266666666, 4.0}, + {"pentium2_klamath", 300000000, 4.5}, + {"pentium2_deschutes", 50000000, 1.0}, + {"pentium2_deschutes", 60000000, 1.0}, + {"pentium2_deschutes", 66666666, 1.0}, + {"pentium2_deschutes", 75000000, 1.5}, + {"pentium2_deschutes", 266666666, 4.0}, + {"pentium2_deschutes", 300000000, 4.5}, + {"pentium2_deschutes", 333333333, 5.0}, + {"pentium2_deschutes", 350000000, 3.5}, + {"pentium2_deschutes", 400000000, 4.0}, + {"pentium2_deschutes", 450000000, 4.5}, + {NULL, 0, 0} }; -CPU cpus_Xeon[] = { - /* Slot 2 Xeons. Literal P2D's with more cache - The <400Mhz Xeons are only meant to not cause any struggle - to the recompiler. */ - {"Pentium II Xeon 75", CPU_PENTIUM2D, fpus_internal, 75000000, 1.5, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Xeon 133", CPU_PENTIUM2D, fpus_internal, 133333333, 2.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"Pentium II Xeon 166", CPU_PENTIUM2D, fpus_internal, 166666666, 2.5, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium II Xeon 400", CPU_PENTIUM2D, fpus_internal, 400000000, 4.0, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36,36,12,12, 48}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_Xeon[] = { + {"pentium2_xeon", 75000000, 1.5}, + {"pentium2_xeon", 100000000, 1.5}, + {"pentium2_xeon", 133333333, 2.0}, + {"pentium2_xeon", 166666666, 2.5}, + {"pentium2_xeon", 400000000, 4.0}, + {"pentium2_xeon", 450000000, 4.5}, + {NULL, 0, 0} }; -CPU cpus_Celeron[] = { - /* Mendocino Celerons. Exact architecture as the P2D series with their L2 cache on-dye. - Intended for the PGA370 boards but they were capable to fit on a PGA 370 to Slot 1 - adaptor card so they work on Slot 1 motherboards too!. - - The 100Mhz & 166Mhz Mendocino is only meant to not cause any struggle - to the recompiler. */ - {"Celeron Mendocino 100", CPU_PENTIUM2D, fpus_internal, 100000000, 1.5, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"Celeron Mendocino 166", CPU_PENTIUM2D, fpus_internal, 166666666, 2.5, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Celeron Mendocino 300/66", CPU_PENTIUM2D, fpus_internal, 300000000, 4.5, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - {"Celeron Mendocino 333", CPU_PENTIUM2D, fpus_internal, 333333333, 5.0, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"Celeron Mendocino 366", CPU_PENTIUM2D, fpus_internal, 366666666, 5.5, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33,33,17,17, 44}, - {"Celeron Mendocino 400", CPU_PENTIUM2D, fpus_internal, 400000000, 6.0, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36,36,12,12, 48}, - {"Celeron Mendocino 433", CPU_PENTIUM2D, fpus_internal, 433333333, 6.5, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 39,39,13,13, 51}, - {"Celeron Mendocino 500", CPU_PENTIUM2D, fpus_internal, 500000000, 7.5, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45,45,15,15, 60}, - {"Celeron Mendocino 533", CPU_PENTIUM2D, fpus_internal, 533333333, 8.0, 0x665, 0x665, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48,48,17,17, 64}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_Celeron[] = { + {"celeron_mendocino", 66666666, 1.0}, + {"celeron_mendocino", 100000000, 1.5}, + {"celeron_mendocino", 133333333, 2.0}, + {"celeron_mendocino", 166666666, 2.5}, + {"celeron_mendocino", 300000000, 4.5}, + {"celeron_mendocino", 333333333, 5.0}, + {"celeron_mendocino", 366666666, 5.5}, + {"celeron_mendocino", 400000000, 6.0}, + {"celeron_mendocino", 433333333, 6.5}, + {"celeron_mendocino", 466666666, 7.0}, + {"celeron_mendocino", 500000000, 7.5}, + {"celeron_mendocino", 533333333, 8.0}, + {NULL, 0, 0} }; -CPU cpus_Cyrix3[] = { - /*VIA Cyrix III (Samuel)*/ - {"Cyrix III 66", CPU_CYRIX3S, fpus_internal, 66666666, 1.0, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 8}, /*66 MHz version*/ - {"Cyrix III 233", CPU_CYRIX3S, fpus_internal, 233333333, 3.5, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 9, 9, 28}, - {"Cyrix III 266", CPU_CYRIX3S, fpus_internal, 266666666, 4.0, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 32}, - {"Cyrix III 300", CPU_CYRIX3S, fpus_internal, 300000000, 4.5, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 27, 27, 13, 13, 36}, - {"Cyrix III 333", CPU_CYRIX3S, fpus_internal, 333333333, 5.0, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 30, 30, 15, 15, 40}, - {"Cyrix III 350", CPU_CYRIX3S, fpus_internal, 350000000, 3.5, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 32, 32, 11, 11, 42}, - {"Cyrix III 400", CPU_CYRIX3S, fpus_internal, 400000000, 4.0, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 36, 36, 12, 12, 48}, - {"Cyrix III 450", CPU_CYRIX3S, fpus_internal, 450000000, 4.5, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 41, 41, 14, 14, 54}, /*^ is lower P2 speeds to allow emulation below 466 mhz*/ - {"Cyrix III 500", CPU_CYRIX3S, fpus_internal, 500000000, 5.0, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC, 45, 45, 15, 15, 60}, - {"Cyrix III 550", CPU_CYRIX3S, fpus_internal, 550000000, 5.5, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 50, 50, 17, 17, 66}, - {"Cyrix III 600", CPU_CYRIX3S, fpus_internal, 600000000, 6.0, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 54, 54, 18, 18, 72}, - {"Cyrix III 650", CPU_CYRIX3S, fpus_internal, 650000000, 6.5, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 58, 58, 20, 20, 78}, - {"Cyrix III 700", CPU_CYRIX3S, fpus_internal, 700000000, 7.0, 0x662, 0x662, 0, CPU_SUPPORTS_DYNAREC, 62, 62, 21, 21, 84}, - {"", -1, 0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const cpu_legacy_table_t cpus_PentiumIID[] = { + {"pentium2_deschutes", 50000000, 1.0}, + {"pentium2_deschutes", 60000000, 1.0}, + {"pentium2_deschutes", 66666666, 1.0}, + {"pentium2_deschutes", 75000000, 1.5}, + {"pentium2_deschutes", 266666666, 4.0}, + {"pentium2_deschutes", 300000000, 4.5}, + {"pentium2_deschutes", 333333333, 5.0}, + {"pentium2_deschutes", 350000000, 3.5}, + {"pentium2_deschutes", 400000000, 4.0}, + {"pentium2_deschutes", 450000000, 4.5}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t cpus_Cyrix3[] = { + {"c3_samuel", 66666666, 1.0}, + {"c3_samuel", 233333333, 3.5}, + {"c3_samuel", 266666666, 4.0}, + {"c3_samuel", 300000000, 4.5}, + {"c3_samuel", 333333333, 5.0}, + {"c3_samuel", 350000000, 3.5}, + {"c3_samuel", 400000000, 4.0}, + {"c3_samuel", 450000000, 4.5}, + {"c3_samuel", 500000000, 5.0}, + {"c3_samuel", 550000000, 5.5}, + {"c3_samuel", 600000000, 6.0}, + {"c3_samuel", 650000000, 6.5}, + {"c3_samuel", 700000000, 7.0}, + {NULL, 0, 0} +}; + +static const cpu_legacy_table_t *cputables_8088[4] = {cpus_8088}; +static const cpu_legacy_table_t *cputables_pcjr[4] = {cpus_pcjr}; +static const cpu_legacy_table_t *cputables_europc[4] = {cpus_europc}; +static const cpu_legacy_table_t *cputables_pc1512[4] = {cpus_pc1512}; +static const cpu_legacy_table_t *cputables_8086[4] = {cpus_8086}; +static const cpu_legacy_table_t *cputables_286[4] = {cpus_286}; +static const cpu_legacy_table_t *cputables_ibmat[4] = {cpus_ibmat}; +static const cpu_legacy_table_t *cputables_ps1_m2011[4] = {cpus_ps1_m2011}; +static const cpu_legacy_table_t *cputables_ps2_m30_286_IBM486SLC[4] = {cpus_ps2_m30_286, cpus_IBM486SLC}; +static const cpu_legacy_table_t *cputables_ibmxt286[4] = {cpus_ibmxt286}; +static const cpu_legacy_table_t *cputables_i386SX_Am386SX_486SLC[4] = {cpus_i386SX, cpus_Am386SX, cpus_486SLC}; +static const cpu_legacy_table_t *cputables_ALiM6117[4] = {cpus_ALiM6117}; +static const cpu_legacy_table_t *cputables_i386SX_Am386SX_486SLC_IBM486SLC[4] = {cpus_i386SX, cpus_Am386SX, cpus_486SLC, cpus_IBM486SLC}; +static const cpu_legacy_table_t *cputables_i386DX_Am386DX_486DLC[4] = {cpus_i386DX, cpus_Am386DX, cpus_486DLC}; +static const cpu_legacy_table_t *cputables_i386DX_Am386DX_486DLC_IBM486BL[4] = {cpus_i386DX, cpus_Am386DX, cpus_486DLC, cpus_IBM486BL}; +static const cpu_legacy_table_t *cputables_i486_Am486_Cx486[4] = {cpus_i486, cpus_Am486, cpus_Cx486}; +static const cpu_legacy_table_t *cputables_i486S1_Am486S1_Cx486S1[4] = {cpus_i486S1, cpus_Am486S1, cpus_Cx486S1}; +static const cpu_legacy_table_t *cputables_IBM486SLC[4] = {cpus_IBM486SLC}; +static const cpu_legacy_table_t *cputables_i486_PC330[4] = {cpus_i486_PC330}; +static const cpu_legacy_table_t *cputables_STPCDX[4] = {cpus_STPCDX}; +static const cpu_legacy_table_t *cputables_STPCDX2[4] = {cpus_STPCDX2}; +static const cpu_legacy_table_t *cputables_Pentium5V[4] = {cpus_Pentium5V}; +static const cpu_legacy_table_t *cputables_PentiumS5_WinChip_K5[4] = {cpus_PentiumS5, cpus_WinChip, cpus_K5}; +static const cpu_legacy_table_t *cputables_Pentium3V_WinChip_K5_6x863V[4] = {cpus_Pentium3V, cpus_WinChip, cpus_K5, cpus_6x863V}; +static const cpu_legacy_table_t *cputables_Pentium3V_K5[4] = {cpus_Pentium3V, cpus_K5}; +static const cpu_legacy_table_t *cputables_Pentium_WinChip_K56_6x86[4] = {cpus_Pentium, cpus_WinChip, cpus_K56, cpus_6x86}; +static const cpu_legacy_table_t *cputables_Pentium_WinChip_SS7_K56_SS7_6x86SS7[4] = {cpus_Pentium, cpus_WinChip_SS7, cpus_K56_SS7, cpus_6x86SS7}; +static const cpu_legacy_table_t *cputables_PentiumPro[4] = {cpus_PentiumPro}; +static const cpu_legacy_table_t *cputables_PentiumII66[4] = {cpus_PentiumII66}; +static const cpu_legacy_table_t *cputables_PentiumII_Celeron_Cyrix3[4] = {cpus_PentiumII, cpus_Celeron, cpus_Cyrix3}; +static const cpu_legacy_table_t *cputables_Xeon[4] = {cpus_Xeon}; +static const cpu_legacy_table_t *cputables_Celeron_Cyrix3[4] = {cpus_Celeron, cpus_Cyrix3}; +static const cpu_legacy_table_t *cputables_Celeron[4] = {cpus_Celeron}; +static const cpu_legacy_table_t *cputables_PentiumIID_Celeron[4] = {cpus_PentiumIID, cpus_Celeron}; + +const cpu_legacy_machine_t cpu_legacy_table[] = { + {"ibmpc", cputables_8088}, + {"ibmpc82", cputables_8088}, + {"ibmpcjr", cputables_pcjr}, + {"ibmxt", cputables_8088}, + {"ibmxt86", cputables_8088}, + {"americxt", cputables_8088}, + {"amixt", cputables_8088}, + {"portable", cputables_8088}, + {"dtk", cputables_8088}, + {"genxt", cputables_8088}, + {"jukopc", cputables_8088}, + {"openxt", cputables_8088}, + {"pxxt", cputables_8088}, + {"europc", cputables_europc}, + {"tandy", cputables_europc}, + {"tandy1000hx", cputables_europc}, + {"t1000", cputables_8088}, + {"ltxt", cputables_8088}, + {"xi8088", cputables_8088}, + {"zdsupers", cputables_8088}, + {"pc1512", cputables_pc1512}, + {"pc1640", cputables_8086}, + {"pc2086", cputables_8086}, + {"pc3086", cputables_8086}, + {"pc200", cputables_8086}, + {"ppc512", cputables_8086}, + {"deskpro", cputables_8086}, + {"m24", cputables_8086}, + {"iskra3104", cputables_8086}, + {"tandy1000sl2", cputables_8086}, + {"t1200", cputables_8086}, + {"lxt3", cputables_8086}, + {"hed919", cputables_286}, + {"ibmat", cputables_ibmat}, + {"ibmps1es", cputables_ps1_m2011}, + {"ibmps2_m30_286", cputables_ps2_m30_286_IBM486SLC}, + {"ibmxt286", cputables_ibmxt286}, + {"ibmatami", cputables_ibmat}, + {"cmdpc30", cputables_286}, + {"portableii", cputables_286}, + {"portableiii", cputables_286}, + {"mr286", cputables_286}, + {"open_at", cputables_286}, + {"ibmatpx", cputables_ibmat}, + {"ibmatquadtel", cputables_ibmat}, + {"siemens", cputables_286}, + {"t3100e", cputables_286}, + {"quadt286", cputables_286}, + {"tg286m", cputables_286}, + {"ami286", cputables_286}, + {"px286", cputables_286}, + {"award286", cputables_286}, + {"gw286ct", cputables_286}, + {"gdc212m", cputables_286}, + {"super286tr", cputables_286}, + {"spc4200p", cputables_286}, + {"spc4216p", cputables_286}, + {"deskmaster286", cputables_286}, + {"ibmps2_m50", cputables_ps2_m30_286_IBM486SLC}, + {"ibmps1_2121", cputables_i386SX_Am386SX_486SLC}, + {"ibmps1_2121_isa", cputables_i386SX_Am386SX_486SLC}, + {"arb1375", cputables_ALiM6117}, + {"pja511m", cputables_ALiM6117}, + {"ama932j", cputables_i386SX_Am386SX_486SLC}, + {"adi386sx", cputables_i386SX_Am386SX_486SLC}, + {"shuttle386sx", cputables_i386SX_Am386SX_486SLC}, + {"dtk386", cputables_i386SX_Am386SX_486SLC}, + {"awardsx", cputables_i386SX_Am386SX_486SLC}, + {"cmdsl386sx25", cputables_i386SX_Am386SX_486SLC}, + {"kmxc02", cputables_i386SX_Am386SX_486SLC}, + {"megapc", cputables_i386SX_Am386SX_486SLC}, + {"ibmps2_m55sx", cputables_i386SX_Am386SX_486SLC_IBM486SLC}, + {"acc386", cputables_i386DX_Am386DX_486DLC}, + {"ecs386", cputables_i386DX_Am386DX_486DLC}, + {"portableiii386", cputables_i386DX_Am386DX_486DLC}, + {"micronics386", cputables_i386DX_Am386DX_486DLC}, + {"asus386", cputables_i386DX_Am386DX_486DLC}, + {"ustechnologies386", cputables_i386DX_Am386DX_486DLC}, + {"award386dx", cputables_i386DX_Am386DX_486DLC}, + {"ibmps2_m70_type3", cputables_i386DX_Am386DX_486DLC_IBM486BL}, + {"ibmps2_m80", cputables_i386DX_Am386DX_486DLC_IBM486BL}, + {"pb410a", cputables_i486_Am486_Cx486}, + {"acera1g", cputables_i486_Am486_Cx486}, + {"win486", cputables_i486_Am486_Cx486}, + {"ali1429", cputables_i486S1_Am486S1_Cx486S1}, + {"cs4031", cputables_i486S1_Am486S1_Cx486S1}, + {"rycleopardlx", cputables_IBM486SLC}, + {"award486", cputables_i486S1_Am486S1_Cx486S1}, + {"ami486", cputables_i486S1_Am486S1_Cx486S1}, + {"mr486", cputables_i486_Am486_Cx486}, + {"pc330_6571", cputables_i486_PC330}, + {"403tg", cputables_i486_Am486_Cx486}, + {"sis401", cputables_i486_Am486_Cx486}, + {"valuepoint433", cputables_i486_Am486_Cx486}, + {"ami471", cputables_i486_Am486_Cx486}, + {"win471", cputables_i486_Am486_Cx486}, + {"vi15g", cputables_i486_Am486_Cx486}, + {"vli486sv2g", cputables_i486_Am486_Cx486}, + {"dtk486", cputables_i486_Am486_Cx486}, + {"px471", cputables_i486_Am486_Cx486}, + {"486vchd", cputables_i486S1_Am486S1_Cx486S1}, + {"ibmps1_2133", cputables_i486S1_Am486S1_Cx486S1}, + {"vect486vl", cputables_i486S1_Am486S1_Cx486S1}, + {"ibmps2_m70_type4", cputables_i486S1_Am486S1_Cx486S1}, + {"abpb4", cputables_i486_Am486_Cx486}, + {"486ap4", cputables_i486_Am486_Cx486}, + {"486sp3g", cputables_i486_Am486_Cx486}, + {"alfredo", cputables_i486_Am486_Cx486}, + {"ls486e", cputables_i486_Am486_Cx486}, + {"m4li", cputables_i486_Am486_Cx486}, + {"r418", cputables_i486_Am486_Cx486}, + {"4sa2", cputables_i486_Am486_Cx486}, + {"4dps", cputables_i486_Am486_Cx486}, + {"itoxstar", cputables_STPCDX}, + {"arb1479", cputables_STPCDX2}, + {"pcm9340", cputables_STPCDX2}, + {"pcm5330", cputables_STPCDX2}, + {"486vipio2", cputables_i486_Am486_Cx486}, + {"p5mp3", cputables_Pentium5V}, + {"dellxp60", cputables_Pentium5V}, + {"opti560l", cputables_Pentium5V}, + {"ambradp60", cputables_Pentium5V}, + {"valuepointp60", cputables_Pentium5V}, + {"revenge", cputables_Pentium5V}, + {"586mc1", cputables_Pentium5V}, + {"pb520r", cputables_Pentium5V}, + {"excalibur", cputables_Pentium5V}, + {"plato", cputables_PentiumS5_WinChip_K5}, + {"ambradp90", cputables_PentiumS5_WinChip_K5}, + {"430nx", cputables_PentiumS5_WinChip_K5}, + {"acerv30", cputables_PentiumS5_WinChip_K5}, + {"apollo", cputables_PentiumS5_WinChip_K5}, + {"vectra54", cputables_PentiumS5_WinChip_K5}, + {"zappa", cputables_PentiumS5_WinChip_K5}, + {"powermate_v", cputables_PentiumS5_WinChip_K5}, + {"mb500n", cputables_PentiumS5_WinChip_K5}, + {"p54tp4xe", cputables_Pentium3V_WinChip_K5_6x863V}, + {"mr586", cputables_Pentium3V_WinChip_K5_6x863V}, + {"gw2katx", cputables_Pentium3V_WinChip_K5_6x863V}, + {"thor", cputables_Pentium3V_WinChip_K5_6x863V}, + {"mrthor", cputables_Pentium3V_WinChip_K5_6x863V}, + {"endeavor", cputables_Pentium3V_WinChip_K5_6x863V}, + {"pb640", cputables_Pentium3V_WinChip_K5_6x863V}, + {"chariot", cputables_Pentium3V_K5}, + {"acerm3a", cputables_Pentium3V_WinChip_K5_6x863V}, + {"ap53", cputables_Pentium3V_WinChip_K5_6x863V}, + {"8500tuc", cputables_Pentium3V_WinChip_K5_6x863V}, + {"p55t2s", cputables_Pentium3V_WinChip_K5_6x863V}, + {"acerv35n", cputables_Pentium_WinChip_K56_6x86}, + {"p55t2p4", cputables_Pentium_WinChip_K56_6x86}, + {"m7shi", cputables_Pentium_WinChip_K56_6x86}, + {"tc430hx", cputables_Pentium_WinChip_K56_6x86}, + {"equium5200", cputables_Pentium_WinChip_K56_6x86}, + {"pcv240", cputables_Pentium_WinChip_K56_6x86}, + {"p65up5_cp55t2d", cputables_Pentium_WinChip_K56_6x86}, + {"p55tvp4", cputables_Pentium_WinChip_K56_6x86}, + {"8500tvxa", cputables_Pentium_WinChip_K56_6x86}, + {"presario4500", cputables_Pentium_WinChip_K56_6x86}, + {"p55va", cputables_Pentium_WinChip_K56_6x86}, + {"gw2kte", cputables_Pentium_WinChip_K56_6x86}, + {"brio80xx", cputables_Pentium_WinChip_K56_6x86}, + {"pb680", cputables_Pentium_WinChip_K56_6x86}, + {"430vx", cputables_Pentium_WinChip_K56_6x86}, + {"nupro592", cputables_Pentium_WinChip_K56_6x86}, + {"tx97", cputables_Pentium_WinChip_K56_6x86}, + {"an430tx", cputables_Pentium_WinChip_K56_6x86}, + {"ym430tx", cputables_Pentium_WinChip_K56_6x86}, + {"mb540n", cputables_Pentium_WinChip_K56_6x86}, + {"p5mms98", cputables_Pentium_WinChip_K56_6x86}, + {"ficva502", cputables_Pentium_WinChip_K56_6x86}, + {"ficpa2012", cputables_Pentium_WinChip_K56_6x86}, + {"ax59pro", cputables_Pentium_WinChip_SS7_K56_SS7_6x86SS7}, + {"ficva503p", cputables_Pentium_WinChip_SS7_K56_SS7_6x86SS7}, + {"ficva503a", cputables_Pentium_WinChip_SS7_K56_SS7_6x86SS7}, + {"v60n", cputables_PentiumPro}, + {"p65up5_cp6nd", cputables_PentiumPro}, + {"8600ttc", cputables_PentiumPro}, + {"686nx", cputables_PentiumPro}, + {"ap440fx", cputables_PentiumPro}, + {"vs440fx", cputables_PentiumPro}, + {"m6mi", cputables_PentiumPro}, + {"mb600n", cputables_PentiumPro}, + {"p65up5_cpknd", cputables_PentiumII66}, + {"kn97", cputables_PentiumII66}, + {"lx6", cputables_PentiumII66}, + {"spitfire", cputables_PentiumII66}, + {"p6i440e2", cputables_PentiumII66}, + {"p2bls", cputables_PentiumII_Celeron_Cyrix3}, + {"p3bf", cputables_PentiumII_Celeron_Cyrix3}, + {"bf6", cputables_PentiumII_Celeron_Cyrix3}, + {"ax6bc", cputables_PentiumII_Celeron_Cyrix3}, + {"atc6310bxii", cputables_PentiumII_Celeron_Cyrix3}, + {"686bx", cputables_PentiumII_Celeron_Cyrix3}, + {"tsunamiatx", cputables_PentiumII_Celeron_Cyrix3}, + {"p6sba", cputables_PentiumII_Celeron_Cyrix3}, + {"ergox365", cputables_PentiumII_Celeron_Cyrix3}, + {"ficka6130", cputables_PentiumII_Celeron_Cyrix3}, + {"6gxu", cputables_Xeon}, + {"fw6400gx", cputables_Xeon}, + {"s2dge", cputables_Xeon}, + {"s370slm", cputables_Celeron_Cyrix3}, + {"awo671r", cputables_Celeron_Cyrix3}, + {"cubx", cputables_Celeron_Cyrix3}, + {"atc7020bxii", cputables_Celeron_Cyrix3}, + {"ambx133", cputables_Celeron_Cyrix3}, + {"trinity371", cputables_Celeron}, + {"63a", cputables_Celeron_Cyrix3}, + {"apas3", cputables_Celeron_Cyrix3}, + {"wcf681", cputables_Celeron_Cyrix3}, + {"6via90ap", cputables_Celeron_Cyrix3}, + {"p6bap", cputables_Celeron_Cyrix3}, + {"603tcf", cputables_Celeron_Cyrix3}, + {"vpc2007", cputables_PentiumIID_Celeron}, + {NULL, NULL} }; diff --git a/src/cpu/fpu.c b/src/cpu/fpu.c new file mode 100644 index 000000000..2d74b256a --- /dev/null +++ b/src/cpu/fpu.c @@ -0,0 +1,101 @@ +/* + * 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. + * + * FPU type handler. + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" + + +#ifdef ENABLE_FPU_LOG +int fpu_do_log = ENABLE_FPU_LOG; + + +void +fpu_log(const char *fmt, ...) +{ + va_list ap; + + if (fpu_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define fpu_log(fmt, ...) +#endif + + +int +fpu_get_type(const cpu_family_t *cpu_family, int cpu, const char *internal_name) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + int fpu_type = fpus[0].type; + int c = 0; + + while (fpus[c].internal_name) { + if (!strcmp(internal_name, fpus[c].internal_name)) + fpu_type = fpus[c].type; + c++; + } + + return fpu_type; +} + + +const char * +fpu_get_internal_name(const cpu_family_t *cpu_family, int cpu, int type) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + int c = 0; + + while (fpus[c].internal_name) { + if (fpus[c].type == type) + return fpus[c].internal_name; + c++; + } + + return fpus[0].internal_name; +} + + +const char * +fpu_get_name_from_index(const cpu_family_t *cpu_family, int cpu, int c) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + + return fpus[c].name; +} + + +int +fpu_get_type_from_index(const cpu_family_t *cpu_family, int cpu, int c) +{ + const CPU *cpu_s = &cpu_family->cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + + return fpus[c].type; +} diff --git a/src/cpu/x86.c b/src/cpu/x86.c new file mode 100644 index 000000000..bf5b168db --- /dev/null +++ b/src/cpu/x86.c @@ -0,0 +1,373 @@ +/* + * 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. + * + * Functions common to all emulated x86 CPU's. + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2020 Andrew Jenner. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/nmi.h> +#include <86box/pic.h> +#include <86box/pci.h> +#include <86box/ppi.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +uint32_t rmdat; + +/* XT CPU multiplier. */ +uint64_t xt_cpu_multi; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0, soft_reset_pci = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + +/* This is for the OPTI 283 special reset handling mode. */ +int reset_on_hlt, hlt_reset_pending; + + +#ifdef ENABLE_X86_LOG +void dumpregs(int); + +int x86_do_log = ENABLE_X86_LOG; +int indump = 0; + + +static void +x808x_log(const char *fmt, ...) +{ + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} + + +void +dumpregs(int force) +{ + int c; + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); + x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); + x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + gs, cpu_state.seg_gs.limit, cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_gs.limit_high); + x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", + EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP); + } else { + x808x_log("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n", + AX, BX, CX, DX, DI, SI, BP, SP); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); + x87_dumpregs(); + indump = 0; +} +#else +#define x808x_log(fmt, ...) +#endif + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; +} + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ +static void +makeznptable(void) +{ + int c, d, e; + for (c = 0; c < 256; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); +#endif + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); +#endif + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +reset_common(int hard) +{ +#ifdef ENABLE_808X_LOG + if (hard) + x808x_log("x86 reset\n"); +#endif + + if (!hard && reset_on_hlt) { + hlt_reset_pending++; + pclog("hlt_reset_pending = %i\n", hlt_reset_pending); + if (hlt_reset_pending == 2) + hlt_reset_pending = 0; + else + return; + } + + /* Make sure to gracefully leave SMM. */ + if (in_smm) + leave_smm(); + + /* Needed for the ALi M1533. */ + if (is486 && (hard || soft_reset_pci)) { + pci_reset(); + if (!hard && soft_reset_pci) { + dma_reset(); + /* TODO: Hack, but will do for time being, because all AT machines currently are 286+, + and vice-versa. */ + dma_set_at(is286); + device_reset_all(); + } + } + + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (hascache) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + cpu_state.eflags = 0; + cgate32 = 0; + if (is286) { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + if (is6117) + rammask |= 0x03000000; + } + idt.base = 0; + cpu_state.flags = 2; + trap = 0; + + idt.limit = is386 ? 0x03ff : 0xffff; + if (is386 || hard) + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + cpu_set_edx(); + mmu_perm = 4; + } + x86seg_reset(); +#ifdef USE_DYNAREC + if (hard) + codegen_reset(); +#endif + if (!hard) + flushmmucache(); + x86_was_reset = 1; + cpu_alt_reset = 0; + + cpu_ven_reset(); + + in_smm = smi_latched = 0; + smi_line = smm_in_hlt = 0; + smi_block = 0; + + if (hard) { + if (is486) + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + ppi_reset(); + } + in_sys = 0; + + shadowbios = shadowbios_write = 0; + alt_access = cpu_end_block_after_ins = 0; + + if (hard) { + reset_on_hlt = hlt_reset_pending = 0; + cache_index = 0; + memset(_tr, 0x00, sizeof(_tr)); + memset(_cache, 0x00, sizeof(_cache)); + } + + if (!is286) + reset_808x(hard); +} + + +/* Hard reset. */ +void +resetx86(void) +{ + reset_common(1); + + soft_reset_mask = 0; +} + + +/* Soft reset. */ +void +softresetx86(void) +{ + if (soft_reset_mask) + return; + + if (ibm8514_enabled || xga_enabled) + vga_on = 1; + + reset_common(0); +} + + +/* Actual hard reset. */ +void +hardresetx86(void) +{ + dma_reset(); + /* TODO: Hack, but will do for time being, because all AT machines currently are 286+, + and vice-versa. */ + dma_set_at(is286); + device_reset_all(); + + cpu_alt_reset = 0; + + mem_a20_alt = 0; + mem_a20_recalc(); + + flushmmucache(); + + resetx86(); +} diff --git a/src/cpu/x86.h b/src/cpu/x86.h index e3505a2e2..b9726dc57 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -1,3 +1,14 @@ +#define ABRT_MASK 0x7f +/*An 'expected' exception is one that would be expected to occur on every execution + of this code path; eg a GPF due to being in v86 mode. An 'unexpected' exception is + one that would be unlikely to occur on the next exception, eg a page fault may be + fixed up by the exception handler and the next execution would not hit it. + + This distinction is used by the dynarec; a block that hits an 'expected' exception + would be compiled, a block that hits an 'unexpected' exception would be rejected so + that we don't end up with an unnecessarily short block*/ +#define ABRT_EXPECTED 0x80 + extern uint8_t opcode, opcode2; extern uint8_t flags_p; extern uint8_t znptable8[256]; @@ -11,7 +22,7 @@ extern int x86_was_reset, trap; extern int codegen_flat_ss, codegen_flat_ds; extern int timetolive, keyboardtimer, trap; extern int optype, stack32; -extern int oldcpl, cgate32, cpl_override, fpucount; +extern int oldcpl, cgate32, cpl_override; extern int nmi_enable; extern int oddeven, inttype; @@ -68,3 +79,4 @@ extern void x86_doabrt(int x86_abrt); extern void x86illegal(); extern void x86seg_reset(); extern void x86gpf(char *s, uint16_t error); +extern void x86gpf_expected(char *s, uint16_t error); diff --git a/src/codegen_new/x86_flags.h b/src/cpu/x86_flags.h similarity index 76% rename from src/codegen_new/x86_flags.h rename to src/cpu/x86_flags.h index 9a9983926..b46755e90 100644 --- a/src/codegen_new/x86_flags.h +++ b/src/cpu/x86_flags.h @@ -3,19 +3,19 @@ extern int tempc; enum { FLAGS_UNKNOWN, - + FLAGS_ZN8, FLAGS_ZN16, FLAGS_ZN32, - + FLAGS_ADD8, FLAGS_ADD16, FLAGS_ADD32, - + FLAGS_SUB8, FLAGS_SUB16, FLAGS_SUB32, - + FLAGS_SHL8, FLAGS_SHL16, FLAGS_SHL32, @@ -28,6 +28,7 @@ enum FLAGS_SAR16, FLAGS_SAR32, +#ifdef USE_NEW_DYNAREC FLAGS_ROL8, FLAGS_ROL16, FLAGS_ROL32, @@ -35,14 +36,17 @@ enum FLAGS_ROR8, FLAGS_ROR16, FLAGS_ROR32, +#endif FLAGS_INC8, FLAGS_INC16, FLAGS_INC32, - + FLAGS_DEC8, FLAGS_DEC16, - FLAGS_DEC32, + FLAGS_DEC32 +#ifdef USE_NEW_DYNAREC +, FLAGS_ADC8, FLAGS_ADC16, @@ -51,13 +55,14 @@ enum FLAGS_SBC8, FLAGS_SBC16, FLAGS_SBC32 +#endif }; -static inline int ZF_SET() +static __inline int ZF_SET() { switch (cpu_state.flags_op) { - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: case FLAGS_ADD8: @@ -81,31 +86,42 @@ static inline int ZF_SET() case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: +#ifdef USE_NEW_DYNAREC case FLAGS_ADC8: case FLAGS_ADC16: case FLAGS_ADC32: case FLAGS_SBC8: case FLAGS_SBC16: case FLAGS_SBC32: +#endif return !cpu_state.flags_res; - + +#ifdef USE_NEW_DYNAREC case FLAGS_ROL8: case FLAGS_ROL16: case FLAGS_ROL32: case FLAGS_ROR8: case FLAGS_ROR16: case FLAGS_ROR32: +#endif case FLAGS_UNKNOWN: return cpu_state.flags & Z_FLAG; + +#ifndef USE_NEW_DYNAREC + default: + return 0; +#endif } +#ifdef USE_NEW_DYNAREC return 0; +#endif } -static inline int NF_SET() +static __inline int NF_SET() { switch (cpu_state.flags_op) { - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ADD8: case FLAGS_SUB8: case FLAGS_SHL8: @@ -113,10 +129,12 @@ static inline int NF_SET() case FLAGS_SAR8: case FLAGS_INC8: case FLAGS_DEC8: +#ifdef USE_NEW_DYNAREC case FLAGS_ADC8: case FLAGS_SBC8: +#endif return cpu_state.flags_res & 0x80; - + case FLAGS_ZN16: case FLAGS_ADD16: case FLAGS_SUB16: @@ -125,10 +143,12 @@ static inline int NF_SET() case FLAGS_SAR16: case FLAGS_INC16: case FLAGS_DEC16: +#ifdef USE_NEW_DYNAREC case FLAGS_ADC16: case FLAGS_SBC16: +#endif return cpu_state.flags_res & 0x8000; - + case FLAGS_ZN32: case FLAGS_ADD32: case FLAGS_SUB32: @@ -137,27 +157,38 @@ static inline int NF_SET() case FLAGS_SAR32: case FLAGS_INC32: case FLAGS_DEC32: +#ifdef USE_NEW_DYNAREC case FLAGS_ADC32: case FLAGS_SBC32: +#endif return cpu_state.flags_res & 0x80000000; - + +#ifdef USE_NEW_DYNAREC case FLAGS_ROL8: case FLAGS_ROL16: case FLAGS_ROL32: case FLAGS_ROR8: case FLAGS_ROR16: case FLAGS_ROR32: +#endif case FLAGS_UNKNOWN: return cpu_state.flags & N_FLAG; + +#ifndef USE_NEW_DYNAREC + default: + return 0; +#endif } +#ifdef USE_NEW_DYNAREC return 0; +#endif } -static inline int PF_SET() +static __inline int PF_SET() { switch (cpu_state.flags_op) { - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: case FLAGS_ADD8: @@ -181,27 +212,38 @@ static inline int PF_SET() case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: +#ifdef USE_NEW_DYNAREC case FLAGS_ADC8: case FLAGS_ADC16: case FLAGS_ADC32: case FLAGS_SBC8: case FLAGS_SBC16: case FLAGS_SBC32: +#endif return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; - + +#ifdef USE_NEW_DYNAREC case FLAGS_ROL8: case FLAGS_ROL16: case FLAGS_ROL32: case FLAGS_ROR8: case FLAGS_ROR16: case FLAGS_ROR32: +#endif case FLAGS_UNKNOWN: return cpu_state.flags & P_FLAG; + +#ifndef USE_NEW_DYNAREC + default: + return 0; +#endif } +#ifdef USE_NEW_DYNAREC return 0; +#endif } -static inline int VF_SET() +static __inline int VF_SET() { switch (cpu_state.flags_op) { @@ -212,29 +254,41 @@ static inline int VF_SET() case FLAGS_SAR16: case FLAGS_SAR32: return 0; - + +#ifdef USE_NEW_DYNAREC case FLAGS_ADC8: +#endif case FLAGS_ADD8: case FLAGS_INC8: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); +#ifdef USE_NEW_DYNAREC case FLAGS_ADC16: +#endif case FLAGS_ADD16: case FLAGS_INC16: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); +#ifdef USE_NEW_DYNAREC case FLAGS_ADC32: +#endif case FLAGS_ADD32: case FLAGS_INC32: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); - + +#ifdef USE_NEW_DYNAREC case FLAGS_SBC8: +#endif case FLAGS_SUB8: case FLAGS_DEC8: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); +#ifdef USE_NEW_DYNAREC case FLAGS_SBC16: +#endif case FLAGS_SUB16: case FLAGS_DEC16: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); +#ifdef USE_NEW_DYNAREC case FLAGS_SBC32: +#endif case FLAGS_SUB32: case FLAGS_DEC32: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); @@ -245,7 +299,7 @@ static inline int VF_SET() return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); case FLAGS_SHL32: return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); - + case FLAGS_SHR8: return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); case FLAGS_SHR16: @@ -253,6 +307,7 @@ static inline int VF_SET() case FLAGS_SHR32: return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); +#ifdef USE_NEW_DYNAREC case FLAGS_ROL8: return (cpu_state.flags_res ^ (cpu_state.flags_res >> 7)) & 1; case FLAGS_ROL16: @@ -266,18 +321,26 @@ static inline int VF_SET() return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x4000; case FLAGS_ROR32: return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40000000; +#endif case FLAGS_UNKNOWN: return cpu_state.flags & V_FLAG; + +#ifndef USE_NEW_DYNAREC + default: + return 0; +#endif } +#ifdef USE_NEW_DYNAREC return 0; +#endif } -static inline int AF_SET() +static __inline int AF_SET() { switch (cpu_state.flags_op) { - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: case FLAGS_SHL8: @@ -290,7 +353,7 @@ static inline int AF_SET() case FLAGS_SAR16: case FLAGS_SAR32: return 0; - + case FLAGS_ADD8: case FLAGS_ADD16: case FLAGS_ADD32: @@ -299,6 +362,7 @@ static inline int AF_SET() case FLAGS_INC32: return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; +#ifdef USE_NEW_DYNAREC case FLAGS_ADC8: return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xff); @@ -308,6 +372,7 @@ static inline int AF_SET() case FLAGS_ADC32: return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffffffff); +#endif case FLAGS_SUB8: case FLAGS_SUB16: @@ -317,25 +382,34 @@ static inline int AF_SET() case FLAGS_DEC32: return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; +#ifdef USE_NEW_DYNAREC case FLAGS_SBC8: case FLAGS_SBC16: case FLAGS_SBC32: return ((cpu_state.flags_op1 & 0xf) < (cpu_state.flags_op2 & 0xf)) || ((cpu_state.flags_op1 & 0xf) == (cpu_state.flags_op2 & 0xf) && (cpu_state.flags_res & 0xf) != 0); - + case FLAGS_ROL8: case FLAGS_ROL16: case FLAGS_ROL32: case FLAGS_ROR8: case FLAGS_ROR16: case FLAGS_ROR32: +#endif case FLAGS_UNKNOWN: return cpu_state.flags & A_FLAG; + +#ifndef USE_NEW_DYNAREC + default: + return 0; +#endif } +#ifdef USE_NEW_DYNAREC return 0; +#endif } -static inline int CF_SET() +static __inline int CF_SET() { switch (cpu_state.flags_op) { @@ -346,6 +420,7 @@ static inline int CF_SET() case FLAGS_ADD32: return (cpu_state.flags_res < cpu_state.flags_op1); +#ifdef USE_NEW_DYNAREC case FLAGS_ADC8: return (cpu_state.flags_res < cpu_state.flags_op1) || (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xff); @@ -355,17 +430,20 @@ static inline int CF_SET() case FLAGS_ADC32: return (cpu_state.flags_res < cpu_state.flags_op1) || (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffffffff); +#endif case FLAGS_SUB8: case FLAGS_SUB16: case FLAGS_SUB32: return (cpu_state.flags_op1 < cpu_state.flags_op2); +#ifdef USE_NEW_DYNAREC case FLAGS_SBC8: case FLAGS_SBC16: case FLAGS_SBC32: return (cpu_state.flags_op1 < cpu_state.flags_op2) || (cpu_state.flags_op1 == cpu_state.flags_op2 && cpu_state.flags_res != 0); +#endif case FLAGS_SHL8: return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80) ? 1 : 0; @@ -386,23 +464,25 @@ static inline int CF_SET() case FLAGS_SAR32: return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; - case FLAGS_ZN8: + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: return 0; +#ifdef USE_NEW_DYNAREC case FLAGS_ROL8: case FLAGS_ROL16: case FLAGS_ROL32: return cpu_state.flags_res & 1; - + case FLAGS_ROR8: return (cpu_state.flags_res & 0x80) ? 1 : 0; case FLAGS_ROR16: return (cpu_state.flags_res & 0x8000) ? 1 :0; case FLAGS_ROR32: return (cpu_state.flags_res & 0x80000000) ? 1 : 0; - +#endif + case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: @@ -411,18 +491,18 @@ static inline int CF_SET() case FLAGS_INC32: case FLAGS_UNKNOWN: return cpu_state.flags & C_FLAG; + +#ifndef USE_NEW_DYNAREC + default: + return 0; +#endif } +#ifdef USE_NEW_DYNAREC return 0; +#endif } -//#define ZF_SET() (flags & Z_FLAG) -//#define NF_SET() (flags & N_FLAG) -//#define PF_SET() (flags & P_FLAG) -//#define VF_SET() (flags & V_FLAG) -//#define CF_SET() (flags & C_FLAG) -//#define AF_SET() (flags & A_FLAG) - -static inline void flags_rebuild() +static __inline void flags_rebuild() { if (cpu_state.flags_op != FLAGS_UNKNOWN) { @@ -430,7 +510,7 @@ static inline void flags_rebuild() if (CF_SET()) tempf |= C_FLAG; if (PF_SET()) tempf |= P_FLAG; if (AF_SET()) tempf |= A_FLAG; - if (ZF_SET()) tempf |= Z_FLAG; + if (ZF_SET()) tempf |= Z_FLAG; if (NF_SET()) tempf |= N_FLAG; if (VF_SET()) tempf |= V_FLAG; cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; @@ -438,12 +518,12 @@ static inline void flags_rebuild() } } -static inline void flags_extract() +static __inline void flags_extract() { cpu_state.flags_op = FLAGS_UNKNOWN; } -static inline void flags_rebuild_c() +static __inline void flags_rebuild_c() { if (cpu_state.flags_op != FLAGS_UNKNOWN) { @@ -451,10 +531,11 @@ static inline void flags_rebuild_c() cpu_state.flags |= C_FLAG; else cpu_state.flags &= ~C_FLAG; - } + } } -static inline int flags_res_valid() +#ifdef USE_NEW_DYNAREC +static __inline int flags_res_valid() { if (cpu_state.flags_op == FLAGS_UNKNOWN || (cpu_state.flags_op >= FLAGS_ROL8 && cpu_state.flags_op <= FLAGS_ROR32)) @@ -462,18 +543,19 @@ static inline int flags_res_valid() return 1; } +#endif -static inline void setznp8(uint8_t val) +static __inline void setznp8(uint8_t val) { cpu_state.flags_op = FLAGS_ZN8; cpu_state.flags_res = val; } -static inline void setznp16(uint16_t val) +static __inline void setznp16(uint16_t val) { cpu_state.flags_op = FLAGS_ZN16; cpu_state.flags_res = val; } -static inline void setznp32(uint32_t val) +static __inline void setznp32(uint32_t val) { cpu_state.flags_op = FLAGS_ZN32; cpu_state.flags_res = val; @@ -485,32 +567,34 @@ static inline void setznp32(uint32_t val) cpu_state.flags_op1 = orig; \ cpu_state.flags_op2 = shift; +#ifdef USE_NEW_DYNAREC #define set_flags_rotate(op, res) \ cpu_state.flags_op = op; \ cpu_state.flags_res = res; +#endif -static inline void setadd8(uint8_t a, uint8_t b) +static __inline void setadd8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a + b) & 0xff; cpu_state.flags_op = FLAGS_ADD8; } -static inline void setadd16(uint16_t a, uint16_t b) +static __inline void setadd16(uint16_t a, uint16_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a + b) & 0xffff; cpu_state.flags_op = FLAGS_ADD16; } -static inline void setadd32(uint32_t a, uint32_t b) +static __inline void setadd32(uint32_t a, uint32_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = a + b; cpu_state.flags_op = FLAGS_ADD32; } -static inline void setadd8nc(uint8_t a, uint8_t b) +static __inline void setadd8nc(uint8_t a, uint8_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -518,7 +602,7 @@ static inline void setadd8nc(uint8_t a, uint8_t b) cpu_state.flags_res = (a + b) & 0xff; cpu_state.flags_op = FLAGS_INC8; } -static inline void setadd16nc(uint16_t a, uint16_t b) +static __inline void setadd16nc(uint16_t a, uint16_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -526,7 +610,7 @@ static inline void setadd16nc(uint16_t a, uint16_t b) cpu_state.flags_res = (a + b) & 0xffff; cpu_state.flags_op = FLAGS_INC16; } -static inline void setadd32nc(uint32_t a, uint32_t b) +static __inline void setadd32nc(uint32_t a, uint32_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -535,21 +619,21 @@ static inline void setadd32nc(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_INC32; } -static inline void setsub8(uint8_t a, uint8_t b) +static __inline void setsub8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a - b) & 0xff; cpu_state.flags_op = FLAGS_SUB8; } -static inline void setsub16(uint16_t a, uint16_t b) +static __inline void setsub16(uint16_t a, uint16_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a - b) & 0xffff; cpu_state.flags_op = FLAGS_SUB16; } -static inline void setsub32(uint32_t a, uint32_t b) +static __inline void setsub32(uint32_t a, uint32_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; @@ -557,7 +641,7 @@ static inline void setsub32(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_SUB32; } -static inline void setsub8nc(uint8_t a, uint8_t b) +static __inline void setsub8nc(uint8_t a, uint8_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -565,7 +649,7 @@ static inline void setsub8nc(uint8_t a, uint8_t b) cpu_state.flags_res = (a - b) & 0xff; cpu_state.flags_op = FLAGS_DEC8; } -static inline void setsub16nc(uint16_t a, uint16_t b) +static __inline void setsub16nc(uint16_t a, uint16_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -573,7 +657,7 @@ static inline void setsub16nc(uint16_t a, uint16_t b) cpu_state.flags_res = (a - b) & 0xffff; cpu_state.flags_op = FLAGS_DEC16; } -static inline void setsub32nc(uint32_t a, uint32_t b) +static __inline void setsub32nc(uint32_t a, uint32_t b) { flags_rebuild_c(); cpu_state.flags_op1 = a; @@ -582,21 +666,22 @@ static inline void setsub32nc(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_DEC32; } -static inline void setadc8(uint8_t a, uint8_t b) +#ifdef USE_NEW_DYNAREC +static __inline void setadc8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a + b + tempc) & 0xff; cpu_state.flags_op = FLAGS_ADC8; } -static inline void setadc16(uint16_t a, uint16_t b) +static __inline void setadc16(uint16_t a, uint16_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a + b + tempc) & 0xffff; cpu_state.flags_op = FLAGS_ADC16; } -static inline void setadc32(uint32_t a, uint32_t b) +static __inline void setadc32(uint32_t a, uint32_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; @@ -604,27 +689,95 @@ static inline void setadc32(uint32_t a, uint32_t b) cpu_state.flags_op = FLAGS_ADC32; } -static inline void setsbc8(uint8_t a, uint8_t b) +static __inline void setsbc8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a - (b + tempc)) & 0xff; cpu_state.flags_op = FLAGS_SBC8; } -static inline void setsbc16(uint16_t a, uint16_t b) +static __inline void setsbc16(uint16_t a, uint16_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = (a - (b + tempc)) & 0xffff; cpu_state.flags_op = FLAGS_SBC16; } -static inline void setsbc32(uint32_t a, uint32_t b) +static __inline void setsbc32(uint32_t a, uint32_t b) { cpu_state.flags_op1 = a; cpu_state.flags_op2 = b; cpu_state.flags_res = a - (b + tempc); cpu_state.flags_op = FLAGS_SBC32; } +#else +static __inline void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=znptable8[c&0xFF]; + if (c&0x100) cpu_state.flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) cpu_state.flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; +} +static __inline void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=znptable16[c&0xFFFF]; + if (c&0x10000) cpu_state.flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) cpu_state.flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; +} +static __inline void setadc32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) cpu_state.flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) cpu_state.flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) cpu_state.flags|=A_FLAG; +} +#endif extern void cpu_386_flags_extract(); extern void cpu_386_flags_rebuild(); diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index f66e2392d..2c8812570 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -79,6 +79,9 @@ extern const OpFn dynarec_ops_386[1024]; extern const OpFn dynarec_ops_386_0f[1024]; extern const OpFn dynarec_ops_486_0f[1024]; +extern const OpFn dynarec_ops_c486_0f[1024]; +extern const OpFn dynarec_ops_stpc_0f[1024]; +extern const OpFn dynarec_ops_ibm486_0f[1024]; extern const OpFn dynarec_ops_winchip_0f[1024]; extern const OpFn dynarec_ops_winchip2_0f[1024]; @@ -87,6 +90,7 @@ extern const OpFn dynarec_ops_pentium_0f[1024]; extern const OpFn dynarec_ops_pentiummmx_0f[1024]; #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +extern const OpFn dynarec_ops_c6x86_0f[1024]; extern const OpFn dynarec_ops_c6x86mx_0f[1024]; #endif @@ -174,6 +178,9 @@ extern const OpFn ops_386[1024]; extern const OpFn ops_386_0f[1024]; extern const OpFn ops_486_0f[1024]; +extern const OpFn ops_c486_0f[1024]; +extern const OpFn ops_stpc_0f[1024]; +extern const OpFn ops_ibm486_0f[1024]; extern const OpFn ops_winchip_0f[1024]; extern const OpFn ops_winchip2_0f[1024]; @@ -182,6 +189,7 @@ extern const OpFn ops_pentium_0f[1024]; extern const OpFn ops_pentiummmx_0f[1024]; #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +extern const OpFn ops_c6x86_0f[1024]; extern const OpFn ops_c6x86mx_0f[1024]; #endif diff --git a/src/cpu/x86_ops_3dnow.h b/src/cpu/x86_ops_3dnow.h index c578c400a..8131967ca 100644 --- a/src/cpu/x86_ops_3dnow.h +++ b/src/cpu/x86_ops_3dnow.h @@ -159,14 +159,14 @@ static int opPFRCP(uint32_t fetchdat) uint32_t i; float f; } src; - + if (cpu_mod == 3) { src.f = cpu_state.MM[cpu_rm].f[0]; - CLOCK_CYCLES(1); - } - else - { + CLOCK_CYCLES(1); + } + else + { SEG_CHECK_READ(cpu_state.ea_seg); src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); @@ -334,13 +334,13 @@ static int op3DNOW_a16(uint32_t fetchdat) static int op3DNOW_a32(uint32_t fetchdat) { uint8_t opcode; - + MMX_ENTER(); fetch_ea_32(fetchdat); opcode = fastreadb(cs + cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc++; - + return x86_opcodes_3DNOW[opcode](0); } diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h index b152f548f..a378b9fe9 100644 --- a/src/cpu/x86_ops_amd.h +++ b/src/cpu/x86_ops_amd.h @@ -16,7 +16,11 @@ static int opSYSCALL(uint32_t fetchdat) { - int ret = syscall(fetchdat); + int ret; + + ILLEGAL_ON(!(msr.amd_efer & 0x0000000000000001)); + + ret = syscall_op(fetchdat); if (ret <= 1) { CLOCK_CYCLES(20); @@ -32,7 +36,11 @@ opSYSCALL(uint32_t fetchdat) static int opSYSRET(uint32_t fetchdat) { - int ret = sysret(fetchdat); + int ret; + + ILLEGAL_ON(!(msr.amd_efer & 0x0000000000000001)); + + ret = sysret(fetchdat); if (ret <= 1) { CLOCK_CYCLES(20); diff --git a/src/cpu/x86_ops_arith.h b/src/cpu/x86_ops_arith.h index 489fd5e57..b56abb26a 100644 --- a/src/cpu/x86_ops_arith.h +++ b/src/cpu/x86_ops_arith.h @@ -309,179 +309,179 @@ static int opCMP_b_rmw_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; setsub8(dst, getr8(cpu_reg)); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); return 0; } -static int opCMP_b_rmw_a32(uint32_t fetchdat) -{ +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ uint8_t dst; fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; setsub8(dst, getr8(cpu_reg)); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); return 0; -} - -static int opCMP_w_rmw_a16(uint32_t fetchdat) -{ +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ uint16_t dst; fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; setsub16(dst, cpu_state.regs[cpu_reg].w); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); return 0; -} -static int opCMP_w_rmw_a32(uint32_t fetchdat) -{ +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ uint16_t dst; fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; setsub16(dst, cpu_state.regs[cpu_reg].w); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); return 0; -} - -static int opCMP_l_rmw_a16(uint32_t fetchdat) -{ +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ uint32_t dst; fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; setsub32(dst, cpu_state.regs[cpu_reg].l); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); return 0; -} -static int opCMP_l_rmw_a32(uint32_t fetchdat) -{ +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ uint32_t dst; fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; setsub32(dst, cpu_state.regs[cpu_reg].l); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); return 0; -} - -static int opCMP_b_rm_a16(uint32_t fetchdat) -{ - uint8_t src; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; fetch_ea_16(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - src = geteab(); if (cpu_state.abrt) return 1; + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteab(); if (cpu_state.abrt) return 1; setsub8(getr8(cpu_reg), src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); - return 0; -} -static int opCMP_b_rm_a32(uint32_t fetchdat) -{ - uint8_t src; + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; fetch_ea_32(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - src = geteab(); if (cpu_state.abrt) return 1; + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteab(); if (cpu_state.abrt) return 1; setsub8(getr8(cpu_reg), src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); - return 0; -} - -static int opCMP_w_rm_a16(uint32_t fetchdat) -{ - uint16_t src; + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; fetch_ea_16(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - src = geteaw(); if (cpu_state.abrt) return 1; + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteaw(); if (cpu_state.abrt) return 1; setsub16(cpu_state.regs[cpu_reg].w, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); - return 0; -} -static int opCMP_w_rm_a32(uint32_t fetchdat) -{ - uint16_t src; + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; fetch_ea_32(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - src = geteaw(); if (cpu_state.abrt) return 1; + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteaw(); if (cpu_state.abrt) return 1; setsub16(cpu_state.regs[cpu_reg].w, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); - return 0; -} - -static int opCMP_l_rm_a16(uint32_t fetchdat) + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) { uint32_t src; fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - src = geteal(); if (cpu_state.abrt) return 1; + src = geteal(); if (cpu_state.abrt) return 1; setsub32(cpu_state.regs[cpu_reg].l, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); - return 0; -} -static int opCMP_l_rm_a32(uint32_t fetchdat) -{ + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ uint32_t src; fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - src = geteal(); if (cpu_state.abrt) return 1; + src = geteal(); if (cpu_state.abrt) return 1; setsub32(cpu_state.regs[cpu_reg].l, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); - return 0; -} - -static int opCMP_AL_imm(uint32_t fetchdat) -{ - uint8_t src = getbytef(); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); setsub8(AL, src); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); - return 0; -} - -static int opCMP_AX_imm(uint32_t fetchdat) -{ - uint16_t src = getwordf(); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); setsub16(AX, src); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); - return 0; -} - -static int opCMP_EAX_imm(uint32_t fetchdat) -{ + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ uint32_t src = getlong(); if (cpu_state.abrt) return 1; setsub32(EAX, src); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); - return 0; + return 0; } static int opTEST_b_a16(uint32_t fetchdat) @@ -493,8 +493,8 @@ static int opTEST_b_a16(uint32_t fetchdat) temp = geteab(); if (cpu_state.abrt) return 1; temp2 = getr8(cpu_reg); setznp8(temp & temp2); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); return 0; } @@ -507,8 +507,8 @@ static int opTEST_b_a32(uint32_t fetchdat) temp = geteab(); if (cpu_state.abrt) return 1; temp2 = getr8(cpu_reg); setznp8(temp & temp2); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); return 0; } @@ -522,8 +522,8 @@ static int opTEST_w_a16(uint32_t fetchdat) temp = geteaw(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].w; setznp16(temp & temp2); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); return 0; } @@ -536,8 +536,8 @@ static int opTEST_w_a32(uint32_t fetchdat) temp = geteaw(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].w; setznp16(temp & temp2); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); return 0; } @@ -551,8 +551,8 @@ static int opTEST_l_a16(uint32_t fetchdat) temp = geteal(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].l; setznp32(temp & temp2); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 0); return 0; } @@ -565,8 +565,8 @@ static int opTEST_l_a32(uint32_t fetchdat) temp = geteal(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].l; setznp32(temp & temp2); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 1); return 0; } @@ -643,8 +643,8 @@ static int opTEST_EAX(uint32_t fetchdat) break; \ case 0x38: /*CMP ea, #*/ \ setsub ## flag_width(dst, src); \ - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); \ - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); \ + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } \ + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); } \ break; \ } @@ -652,167 +652,176 @@ static int opTEST_EAX(uint32_t fetchdat) static int op80_a16(uint32_t fetchdat) { uint8_t src, dst; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; ARITH_MULTI(b, 8); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); - + } + return 0; } static int op80_a32(uint32_t fetchdat) { uint8_t src, dst; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; ARITH_MULTI(b, 8); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); - + } + return 0; } static int op81_w_a16(uint32_t fetchdat) { uint16_t src, dst; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getword(); if (cpu_state.abrt) return 1; ARITH_MULTI(w, 16); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); - + } + return 0; } static int op81_w_a32(uint32_t fetchdat) { uint16_t src, dst; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getword(); if (cpu_state.abrt) return 1; ARITH_MULTI(w, 16); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); - + } + return 0; } static int op81_l_a16(uint32_t fetchdat) { uint32_t src, dst; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getlong(); if (cpu_state.abrt) return 1; ARITH_MULTI(l, 32); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); - + } + return 0; } static int op81_l_a32(uint32_t fetchdat) { uint32_t src, dst; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getlong(); if (cpu_state.abrt) return 1; ARITH_MULTI(l, 32); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); - + } + return 0; } static int op83_w_a16(uint32_t fetchdat) { uint16_t src, dst; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xff00; ARITH_MULTI(w, 16); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); - + } + return 0; } static int op83_w_a32(uint32_t fetchdat) { uint16_t src, dst; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xff00; ARITH_MULTI(w, 16); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); - + } + return 0; } static int op83_l_a16(uint32_t fetchdat) { uint32_t src, dst; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xffffff00; ARITH_MULTI(l, 32); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); - + } + return 0; } static int op83_l_a32(uint32_t fetchdat) { uint32_t src, dst; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xffffff00; ARITH_MULTI(l, 32); - if ((rmdat & 0x38) == 0x38) + if ((rmdat & 0x38) == 0x38) { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); - else + } else { PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); - + } + return 0; } - diff --git a/src/cpu/x86_ops_bcd.h b/src/cpu/x86_ops_bcd.h index de9a49cd7..385d63cd7 100644 --- a/src/cpu/x86_ops_bcd.h +++ b/src/cpu/x86_ops_bcd.h @@ -19,7 +19,7 @@ static int opAAA(uint32_t fetchdat) static int opAAD(uint32_t fetchdat) { int base = getbytef(); - if (cpu_manufacturer != MANU_INTEL) base = 10; + if (!cpu_isintel) base = 10; AL = (AH * base) + AL; AH = 0; setznp16(AX); @@ -31,7 +31,7 @@ static int opAAD(uint32_t fetchdat) static int opAAM(uint32_t fetchdat) { int base = getbytef(); - if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + if (!base || !cpu_isintel) base = 10; AH = AL / base; AL %= base; setznp16(AX); @@ -61,7 +61,7 @@ static int opAAS(uint32_t fetchdat) static int opDAA(uint32_t fetchdat) { uint16_t tempw, old_AL, old_CF; - + flags_rebuild(); old_AL = AL; old_CF = cpu_state.flags & C_FLAG; @@ -89,7 +89,7 @@ static int opDAA(uint32_t fetchdat) cpu_state.flags = (cpu_state.flags & ~(C_FLAG | A_FLAG)) | tempw; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); - + return 0; } @@ -124,6 +124,6 @@ static int opDAS(uint32_t fetchdat) cpu_state.flags = (cpu_state.flags & ~(C_FLAG | A_FLAG)) | tempw; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); - + return 0; } diff --git a/src/cpu/x86_ops_bit.h b/src/cpu/x86_ops_bit.h index df2d48619..4fc8ac0f7 100644 --- a/src/cpu/x86_ops_bit.h +++ b/src/cpu/x86_ops_bit.h @@ -1,7 +1,7 @@ static int opBT_w_r_a16(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_16(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; @@ -9,7 +9,7 @@ static int opBT_w_r_a16(uint32_t fetchdat) flags_rebuild(); if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; else cpu_state.flags &= ~C_FLAG; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0); return 0; @@ -17,7 +17,7 @@ static int opBT_w_r_a16(uint32_t fetchdat) static int opBT_w_r_a32(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_32(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; @@ -25,7 +25,7 @@ static int opBT_w_r_a32(uint32_t fetchdat) flags_rebuild(); if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; else cpu_state.flags &= ~C_FLAG; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1); return 0; @@ -33,7 +33,7 @@ static int opBT_w_r_a32(uint32_t fetchdat) static int opBT_l_r_a16(uint32_t fetchdat) { uint32_t temp; - + fetch_ea_16(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; @@ -41,7 +41,7 @@ static int opBT_l_r_a16(uint32_t fetchdat) flags_rebuild(); if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; else cpu_state.flags &= ~C_FLAG; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0); return 0; @@ -49,7 +49,7 @@ static int opBT_l_r_a16(uint32_t fetchdat) static int opBT_l_r_a32(uint32_t fetchdat) { uint32_t temp; - + fetch_ea_32(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; @@ -57,7 +57,7 @@ static int opBT_l_r_a32(uint32_t fetchdat) flags_rebuild(); if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; else cpu_state.flags &= ~C_FLAG; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1); return 0; diff --git a/src/cpu/x86_ops_bitscan.h b/src/cpu/x86_ops_bitscan.h index 46f0fc605..af87a545d 100644 --- a/src/cpu/x86_ops_bitscan.h +++ b/src/cpu/x86_ops_bitscan.h @@ -1,3 +1,23 @@ +#ifdef IS_DYNAREC +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + if (temp) \ + { \ + int c; \ + cpu_state.flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + CLOCK_CYCLES(time); \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + cpu_state.flags |= Z_FLAG; +#else #define BS_common(start, end, dir, dest, time) \ flags_rebuild(); \ instr_cycles = 0; \ @@ -18,142 +38,174 @@ } \ else \ cpu_state.flags |= Z_FLAG; +#endif static int opBSF_w_a16(uint32_t fetchdat) { uint16_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - + BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); +#endif return 0; } static int opBSF_w_a32(uint32_t fetchdat) { uint16_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - + BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); +#endif return 0; } static int opBSF_l_a16(uint32_t fetchdat) { uint32_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; - + BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); +#endif return 0; } static int opBSF_l_a32(uint32_t fetchdat) { uint32_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; +#endif fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; - + BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); +#endif return 0; } static int opBSR_w_a16(uint32_t fetchdat) { uint16_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - + BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); +#endif return 0; } static int opBSR_w_a32(uint32_t fetchdat) { uint16_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - + BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); +#endif return 0; } static int opBSR_l_a16(uint32_t fetchdat) { uint32_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; - + BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); +#endif return 0; } static int opBSR_l_a32(uint32_t fetchdat) { uint32_t temp; +#ifndef IS_DYNAREC int instr_cycles = 0; - +#endif + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; - + BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); - + CLOCK_CYCLES((is486) ? 6 : 10); +#ifndef IS_DYNAREC instr_cycles += ((is486) ? 6 : 10); PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); +#endif return 0; } - diff --git a/src/codegen_new/x86_ops_call.h b/src/cpu/x86_ops_call.h similarity index 76% rename from src/codegen_new/x86_ops_call.h rename to src/cpu/x86_ops_call.h index a11bc9c97..1c928a70b 100644 --- a/src/codegen_new/x86_ops_call.h +++ b/src/cpu/x86_ops_call.h @@ -1,3 +1,4 @@ +#ifdef USE_NEW_DYNAREC #define CALL_FAR_w(new_seg, new_pc) \ old_cs = CS; \ old_pc = cpu_state.pc; \ @@ -25,7 +26,7 @@ PUSH_W(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ PUSH_W(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ } - + #define CALL_FAR_l(new_seg, new_pc) \ old_cs = CS; \ old_pc = cpu_state.pc; \ @@ -53,22 +54,81 @@ PUSH_L(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ PUSH_L(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ } - - +#else +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate32) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } + +#define CALL_FAR_l(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate16) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } +#endif + + static int opCALL_far_w(uint32_t fetchdat) { uint32_t old_cs, old_pc; uint16_t new_cs, new_pc; int cycles_old = cycles; UN_USED(cycles_old); - + new_pc = getwordf(); new_cs = getword(); if (cpu_state.abrt) return 1; - + CALL_FAR_w(new_cs, new_pc); CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 5, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); PREFETCH_FLUSH(); - + return 0; } static int opCALL_far_l(uint32_t fetchdat) @@ -76,15 +136,15 @@ static int opCALL_far_l(uint32_t fetchdat) uint32_t old_cs, old_pc; uint32_t new_cs, new_pc; int cycles_old = cycles; UN_USED(cycles_old); - + new_pc = getlong(); new_cs = getword(); if (cpu_state.abrt) return 1; - + CALL_FAR_l(new_cs, new_pc); CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 7, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); PREFETCH_FLUSH(); - + return 0; } @@ -94,11 +154,11 @@ static int opFF_w_a16(uint32_t fetchdat) uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; int cycles_old = cycles; UN_USED(cycles_old); - + uint16_t temp; - + fetch_ea_16(fetchdat); - + switch (rmdat & 0x38) { case 0x00: /*INC w*/ @@ -126,8 +186,8 @@ static int opFF_w_a16(uint32_t fetchdat) PUSH_W(cpu_state.pc); cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); PREFETCH_FLUSH(); break; @@ -136,7 +196,7 @@ static int opFF_w_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; - + CALL_FAR_w(new_cs, new_pc); CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); @@ -148,19 +208,27 @@ static int opFF_w_a16(uint32_t fetchdat) new_pc = geteaw(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); +#ifdef USE_NEW_DYNAREC old_pc = cpu_state.pc; +#else + oxpc = cpu_state.pc; +#endif new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; +#ifdef USE_NEW_DYNAREC loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; +#else + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; +#endif CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 0); PREFETCH_FLUSH(); @@ -185,11 +253,11 @@ static int opFF_w_a32(uint32_t fetchdat) uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; int cycles_old = cycles; UN_USED(cycles_old); - + uint16_t temp; - + fetch_ea_32(fetchdat); - + switch (rmdat & 0x38) { case 0x00: /*INC w*/ @@ -217,8 +285,8 @@ static int opFF_w_a32(uint32_t fetchdat) PUSH_W(cpu_state.pc); cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); PREFETCH_FLUSH(); break; @@ -227,7 +295,7 @@ static int opFF_w_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; - + CALL_FAR_w(new_cs, new_pc); CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 1); @@ -239,19 +307,27 @@ static int opFF_w_a32(uint32_t fetchdat) new_pc = geteaw(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,0,0,0, 1); PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); +#ifdef USE_NEW_DYNAREC old_pc = cpu_state.pc; +#else + oxpc = cpu_state.pc; +#endif new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; +#ifdef USE_NEW_DYNAREC loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; +#else + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; +#endif CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 1); PREFETCH_FLUSH(); @@ -277,11 +353,11 @@ static int opFF_l_a16(uint32_t fetchdat) uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; int cycles_old = cycles; UN_USED(cycles_old); - + uint32_t temp; - + fetch_ea_16(fetchdat); - + switch (rmdat & 0x38) { case 0x00: /*INC l*/ @@ -309,8 +385,8 @@ static int opFF_l_a16(uint32_t fetchdat) PUSH_L(cpu_state.pc); cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); PREFETCH_FLUSH(); break; @@ -319,7 +395,7 @@ static int opFF_l_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; - + CALL_FAR_l(new_cs, new_pc); CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 0); @@ -331,19 +407,27 @@ static int opFF_l_a16(uint32_t fetchdat) new_pc = geteal(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 0,1,0,0, 0); PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); +#ifdef USE_NEW_DYNAREC old_pc = cpu_state.pc; +#else + oxpc = cpu_state.pc; +#endif new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; - loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; +#ifdef USE_NEW_DYNAREC + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; +#else + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; +#endif CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 0); PREFETCH_FLUSH(); @@ -368,11 +452,11 @@ static int opFF_l_a32(uint32_t fetchdat) uint16_t old_cs, new_cs; uint32_t old_pc, new_pc; int cycles_old = cycles; UN_USED(cycles_old); - + uint32_t temp; - + fetch_ea_32(fetchdat); - + switch (rmdat & 0x38) { case 0x00: /*INC l*/ @@ -400,8 +484,8 @@ static int opFF_l_a32(uint32_t fetchdat) PUSH_L(cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); PREFETCH_FLUSH(); break; @@ -410,7 +494,7 @@ static int opFF_l_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; - + CALL_FAR_l(new_cs, new_pc); CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 1); @@ -422,19 +506,27 @@ static int opFF_l_a32(uint32_t fetchdat) new_pc = geteal(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); - if (is486) CLOCK_CYCLES(5); - else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + if (is486) { CLOCK_CYCLES(5); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); } PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); +#ifdef USE_NEW_DYNAREC old_pc = cpu_state.pc; +#else + oxpc = cpu_state.pc; +#endif new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; - loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; +#ifdef USE_NEW_DYNAREC + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; +#else + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; +#endif CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); PREFETCH_FLUSH(); diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h new file mode 100644 index 000000000..500b119fb --- /dev/null +++ b/src/cpu/x86_ops_cyrix.h @@ -0,0 +1,272 @@ +/*Cyrix-only instructions*/ +/*System Management Mode*/ +static void opSVDC_common(uint32_t fetchdat) +{ + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_es); + writememw(0, easeg+cpu_state.eaaddr+8, ES); + break; + case 0x08: /*CS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_cs); + writememw(0, easeg+cpu_state.eaaddr+8, CS); + break; + case 0x18: /*DS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ds); + writememw(0, easeg+cpu_state.eaaddr+8, DS); + break; + case 0x10: /*SS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ss); + writememw(0, easeg+cpu_state.eaaddr+8, SS); + break; + case 0x20: /*FS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_fs); + writememw(0, easeg+cpu_state.eaaddr+8, FS); + break; + case 0x28: /*GS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_gs); + writememw(0, easeg+cpu_state.eaaddr+8, GS); + break; + default: + x86illegal(); + } +} +static int opSVDC_a16(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + opSVDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opSVDC_a32(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + opSVDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static void opRSDC_common(uint32_t fetchdat) +{ + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_es); + break; + case 0x18: /*DS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ds); + break; + case 0x10: /*SS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ss); + break; + case 0x20: /*FS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_fs); + break; + case 0x28: /*GS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_gs); + break; + default: + x86illegal(); + } +} +static int opRSDC_a16(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + opRSDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opRSDC_a32(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + opRSDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opSVLDT_a16(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + writememw(0, easeg+cpu_state.eaaddr+8, ldt.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opSVLDT_a32(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + writememw(0, easeg+cpu_state.eaaddr+8, ldt.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opRSLDT_a16(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opRSLDT_a32(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opSVTS_a16(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opSVTS_a32(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opRSTS_a16(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opRSTS_a32(uint32_t fetchdat) +{ + if (in_smm) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opSMINT(uint32_t fetchdat) +{ + if (in_smm) + fatal("opSMINT\n"); + else + x86illegal(); + + return 1; +} + +static int opRDSHR_a16(uint32_t fetchdat) +{ + if (in_smm) + fatal("opRDSHR_a16\n"); + else + x86illegal(); + + return 1; +} +static int opRDSHR_a32(uint32_t fetchdat) +{ + if (in_smm) + fatal("opRDSHR_a32\n"); + else + x86illegal(); + + return 1; +} + +static int opWRSHR_a16(uint32_t fetchdat) +{ + if (in_smm) + fatal("opWRSHR_a16\n"); + else + x86illegal(); + + return 1; +} +static int opWRSHR_a32(uint32_t fetchdat) +{ + if (in_smm) + fatal("opWRSHR_a32\n"); + else + x86illegal(); + + return 1; +} diff --git a/src/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index 68f1bac2a..ce0cb4cd6 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/x86_ops_flag.h @@ -27,7 +27,7 @@ static int opCLI(uint32_t fetchdat) { if (!IOPLp) { - if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { cpu_state.eflags &= ~VIF_FLAG; @@ -40,7 +40,7 @@ static int opCLI(uint32_t fetchdat) } else cpu_state.flags &= ~I_FLAG; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); return 0; @@ -65,7 +65,7 @@ static int opSTI(uint32_t fetchdat) { if (!IOPLp) { - if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { if (cpu_state.eflags & VIP_FLAG) @@ -85,8 +85,10 @@ static int opSTI(uint32_t fetchdat) else cpu_state.flags |= I_FLAG; - CPU_BLOCK_END(); - + /*First instruction after STI will always execute, regardless of whether + there is a pending interrupt*/ + cpu_end_block_after_ins = 2; + CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -98,7 +100,7 @@ static int opSAHF(uint32_t fetchdat) cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); - + #if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) codegen_flags_changed = 0; #endif @@ -164,13 +166,13 @@ static int opPUSHFD(uint32_t fetchdat) static int opPOPF_286(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; @@ -181,7 +183,7 @@ static int opPOPF_286(uint32_t fetchdat) CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); - + #if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) codegen_flags_changed = 0; #endif @@ -191,7 +193,7 @@ static int opPOPF_286(uint32_t fetchdat) static int opPOPF(uint32_t fetchdat) { uint16_t tempw; - + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { if (cr4 & CR4_VME) @@ -225,7 +227,7 @@ static int opPOPF(uint32_t fetchdat) } } else - { + { tempw = POP_W(); if (cpu_state.abrt) return 1; @@ -241,7 +243,7 @@ static int opPOPF(uint32_t fetchdat) CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); - + #if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) codegen_flags_changed = 0; #endif @@ -251,31 +253,31 @@ static int opPOPF(uint32_t fetchdat) static int opPOPFD(uint32_t fetchdat) { uint32_t templ; - + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; } - + templ = POP_L(); if (cpu_state.abrt) return 1; if (!(CPL) || !(msw & 1)) cpu_state.flags = (templ & 0x7fd5) | 2; else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (templ & 0x4fd5) | 2; else cpu_state.flags = (cpu_state.flags & 0x3200) | (templ & 0x4dd5) | 2; - - templ &= (is486 || isibm486) ? 0x3c0000 : 0; + + templ &= (is486) ? 0x3c0000 : 0; templ |= ((cpu_state.eflags&3) << 16); if (cpu_CR4_mask & CR4_VME) cpu_state.eflags = (templ >> 16) & 0x3f; else if (CPUID) cpu_state.eflags = (templ >> 16) & 0x27; - else if (is486 || isibm486) cpu_state.eflags = (templ >> 16) & 7; + else if (is486) cpu_state.eflags = (templ >> 16) & 7; else cpu_state.eflags = (templ >> 16) & 3; - + flags_extract(); CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); - + #if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) codegen_flags_changed = 0; #endif diff --git a/src/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index dad86b410..3f2d85766 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -153,9 +153,6 @@ fx_save_stor_common(uint32_t fetchdat, int bits) x87_settag(rec_ftw); CLOCK_CYCLES((cr0 & 1) ? 34 : 44); - - if (cpu_state.abrt) - x386_dynarec_log("FXRSTOR: abrt != 0\n"); } else { /* FXSAVE */ if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; @@ -217,9 +214,6 @@ fx_save_stor_common(uint32_t fetchdat, int bits) cpu_state.ismmx = 0; CLOCK_CYCLES((cr0 & 1) ? 56 : 67); - - if (cpu_state.abrt) - x386_dynarec_log("FXSAVE: abrt != 0\n"); } return cpu_state.abrt; diff --git a/src/cpu/x86_ops_inc_dec.h b/src/cpu/x86_ops_inc_dec.h index ff4a4ab73..682662851 100644 --- a/src/cpu/x86_ops_inc_dec.h +++ b/src/cpu/x86_ops_inc_dec.h @@ -48,7 +48,7 @@ INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) static int opINCDEC_b_a16(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -71,7 +71,7 @@ static int opINCDEC_b_a16(uint32_t fetchdat) static int opINCDEC_b_a32(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); diff --git a/src/cpu/x86_ops_int.h b/src/cpu/x86_ops_int.h index 260fcdad5..0074aec29 100644 --- a/src/cpu/x86_ops_int.h +++ b/src/cpu/x86_ops_int.h @@ -1,6 +1,10 @@ static int opINT3(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); +#ifdef USE_GDBSTUB + if (gdbstub_int3()) + return 1; +#endif if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); @@ -59,7 +63,7 @@ static int opINT(uint32_t fetchdat) } } } - x86gpf(NULL,0); + x86gpf_expected(NULL,0); return 1; } @@ -71,7 +75,7 @@ static int opINT(uint32_t fetchdat) static int opINTO(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); @@ -88,4 +92,3 @@ static int opINTO(uint32_t fetchdat) PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); return 0; } - diff --git a/src/cpu/x86_ops_io.h b/src/cpu/x86_ops_io.h index 9fa91a215..50d7d94d1 100644 --- a/src/cpu/x86_ops_io.h +++ b/src/cpu/x86_ops_io.h @@ -1,5 +1,5 @@ static int opIN_AL_imm(uint32_t fetchdat) -{ +{ uint16_t port = (uint16_t)getbytef(); check_io_perm(port); AL = inb(port); @@ -38,7 +38,7 @@ static int opIN_EAX_imm(uint32_t fetchdat) static int opOUT_AL_imm(uint32_t fetchdat) { - uint16_t port = (uint16_t)getbytef(); + uint16_t port = (uint16_t)getbytef(); check_io_perm(port); outb(port, AL); CLOCK_CYCLES(10); @@ -51,7 +51,7 @@ static int opOUT_AL_imm(uint32_t fetchdat) } static int opOUT_AX_imm(uint32_t fetchdat) { - uint16_t port = (uint16_t)getbytef(); + uint16_t port = (uint16_t)getbytef(); check_io_perm(port); check_io_perm(port + 1); outw(port, AX); @@ -63,7 +63,7 @@ static int opOUT_AX_imm(uint32_t fetchdat) } static int opOUT_EAX_imm(uint32_t fetchdat) { - uint16_t port = (uint16_t)getbytef(); + uint16_t port = (uint16_t)getbytef(); check_io_perm(port); check_io_perm(port + 1); check_io_perm(port + 2); @@ -77,7 +77,7 @@ static int opOUT_EAX_imm(uint32_t fetchdat) } static int opIN_AL_DX(uint32_t fetchdat) -{ +{ check_io_perm(DX); AL = inb(DX); CLOCK_CYCLES(12); diff --git a/src/cpu/x86_ops_jump.h b/src/cpu/x86_ops_jump.h index c227939a3..7f9df37d7 100644 --- a/src/cpu/x86_ops_jump.h +++ b/src/cpu/x86_ops_jump.h @@ -69,7 +69,7 @@ PREFETCH_RUN(timing_bnt, 5, -1, 0,0,0,0, 0); \ return 0; \ } \ - + opJ(O) opJ(NO) opJ(B) @@ -112,7 +112,7 @@ static int opLOOPNE_l(uint32_t fetchdat) ECX--; CLOCK_CYCLES((is486) ? 7 : 11); PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); - if (ECX && !ZF_SET()) + if (ECX && !ZF_SET()) { cpu_state.pc += offset; if (!(cpu_state.op32 & 0x100)) @@ -309,7 +309,7 @@ static int opCALL_r16(uint32_t fetchdat) } static int opCALL_r32(uint32_t fetchdat) { - int32_t addr = getlong(); if (cpu_state.abrt) return 1; + int32_t addr = getlong(); if (cpu_state.abrt) return 1; PUSH_L(cpu_state.pc); cpu_state.pc += addr; CPU_BLOCK_END(); @@ -322,11 +322,11 @@ static int opCALL_r32(uint32_t fetchdat) static int opRET_w(uint32_t fetchdat) { uint16_t ret; - + ret = POP_W(); if (cpu_state.abrt) return 1; cpu_state.pc = ret; CPU_BLOCK_END(); - + CLOCK_CYCLES((is486) ? 5 : 10); PREFETCH_RUN(10, 1, -1, 1,0,0,0, 0); PREFETCH_FLUSH(); @@ -339,7 +339,7 @@ static int opRET_l(uint32_t fetchdat) ret = POP_L(); if (cpu_state.abrt) return 1; cpu_state.pc = ret; CPU_BLOCK_END(); - + CLOCK_CYCLES((is486) ? 5 : 10); PREFETCH_RUN(10, 1, -1, 0,1,0,0, 0); PREFETCH_FLUSH(); @@ -353,10 +353,10 @@ static int opRET_w_imm(uint32_t fetchdat) ret = POP_W(); if (cpu_state.abrt) return 1; if (stack32) ESP += offset; - else SP += offset; + else SP += offset; cpu_state.pc = ret; CPU_BLOCK_END(); - + CLOCK_CYCLES((is486) ? 5 : 10); PREFETCH_RUN(10, 5, -1, 1,0,0,0, 0); PREFETCH_FLUSH(); @@ -369,13 +369,12 @@ static int opRET_l_imm(uint32_t fetchdat) ret = POP_L(); if (cpu_state.abrt) return 1; if (stack32) ESP += offset; - else SP += offset; + else SP += offset; cpu_state.pc = ret; CPU_BLOCK_END(); - + CLOCK_CYCLES((is486) ? 5 : 10); PREFETCH_RUN(10, 5, -1, 0,1,0,0, 0); PREFETCH_FLUSH(); return 0; } - diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index bb25b15d6..b45e95889 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -50,7 +50,7 @@ static int opF6_a16(uint32_t fetchdat) uint16_t tempw, src16; uint8_t src, dst; int8_t temps; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) { SEG_CHECK_READ(cpu_state.ea_seg); @@ -63,8 +63,8 @@ static int opF6_a16(uint32_t fetchdat) case 0x08: src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; setznp8(src & dst); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x10: /*NOT b*/ @@ -106,7 +106,7 @@ static int opF6_a16(uint32_t fetchdat) { AH = src16 % dst; AL = (src16 / dst) &0xff; - if (!cpu_iscyrix) + if (!cpu_iscyrix) { flags_rebuild(); cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ @@ -129,7 +129,7 @@ static int opF6_a16(uint32_t fetchdat) { AH = (tempws % (int)((int8_t)dst)) & 0xff; AL = tempws2 & 0xff; - if (!cpu_iscyrix) + if (!cpu_iscyrix) { flags_rebuild(); cpu_state.flags|=0x8D5; /*Not a Cyrix*/ @@ -156,7 +156,7 @@ static int opF6_a32(uint32_t fetchdat) uint16_t tempw, src16; uint8_t src, dst; int8_t temps; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); @@ -167,8 +167,8 @@ static int opF6_a32(uint32_t fetchdat) case 0x08: src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; setznp8(src & dst); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x10: /*NOT b*/ @@ -210,7 +210,7 @@ static int opF6_a32(uint32_t fetchdat) { AH = src16 % dst; AL = (src16 / dst) &0xff; - if (!cpu_iscyrix) + if (!cpu_iscyrix) { flags_rebuild(); cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ @@ -233,7 +233,7 @@ static int opF6_a32(uint32_t fetchdat) { AH = (tempws % (int)((int8_t)dst)) & 0xff; AL = tempws2 & 0xff; - if (!cpu_iscyrix) + if (!cpu_iscyrix) { flags_rebuild(); cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ @@ -259,11 +259,11 @@ static int opF6_a32(uint32_t fetchdat) static int opF7_w_a16(uint32_t fetchdat) { - uint32_t templ, templ2; + uint32_t templ, templ2 = 0; int tempws, tempws2 = 0; int16_t temps16; uint16_t src, dst; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); @@ -274,8 +274,8 @@ static int opF7_w_a16(uint32_t fetchdat) case 0x08: src = getword(); if (cpu_state.abrt) return 1; setznp16(src & dst); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x10: /*NOT w*/ @@ -320,7 +320,7 @@ static int opF7_w_a16(uint32_t fetchdat) { DX = templ % dst; AX = (templ / dst) & 0xffff; - if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ } else { @@ -356,7 +356,7 @@ static int opF7_w_a16(uint32_t fetchdat) } static int opF7_w_a32(uint32_t fetchdat) { - uint32_t templ, templ2; + uint32_t templ, templ2 = 0; int tempws, tempws2 = 1; int16_t temps16; uint16_t src, dst; @@ -371,8 +371,8 @@ static int opF7_w_a32(uint32_t fetchdat) case 0x08: src = getword(); if (cpu_state.abrt) return 1; setznp16(src & dst); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x10: /*NOT w*/ @@ -417,7 +417,7 @@ static int opF7_w_a32(uint32_t fetchdat) { DX = templ % dst; AX = (templ / dst) & 0xffff; - if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ } else { @@ -469,8 +469,8 @@ static int opF7_l_a16(uint32_t fetchdat) case 0x08: src = getlong(); if (cpu_state.abrt) return 1; setznp32(src & dst); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; case 0x10: /*NOT l*/ @@ -544,8 +544,8 @@ static int opF7_l_a32(uint32_t fetchdat) case 0x08: src = getlong(); if (cpu_state.abrt) return 1; setznp32(src & dst); - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); - else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; case 0x10: /*NOT l*/ @@ -614,18 +614,22 @@ static int opHLT(uint32_t fetchdat) } if (smi_line) enter_smm_check(1); - else if (!((cpu_state.flags & I_FLAG) && pic_intpending)) + else if (!((cpu_state.flags & I_FLAG) && pic.int_pending)) { CLOCK_CYCLES_ALWAYS(100); - if (!((cpu_state.flags & I_FLAG) && pic_intpending)) + if (!((cpu_state.flags & I_FLAG) && pic.int_pending)) cpu_state.pc--; } - else + else { CLOCK_CYCLES(5); + } CPU_BLOCK_END(); PREFETCH_RUN(100, 1, -1, 0,0,0,0, 0); + if (hlt_reset_pending) + softresetx86(); + return 0; } @@ -635,7 +639,7 @@ static int opLOCK(uint32_t fetchdat) fetchdat = fastreadl(cs + cpu_state.pc); if (cpu_state.abrt) return 0; cpu_state.pc++; - + ILLEGAL_ON((fetchdat & 0xff) == 0x90); CLOCK_CYCLES(4); @@ -646,82 +650,82 @@ static int opLOCK(uint32_t fetchdat) static int opBOUND_w_a16(uint32_t fetchdat) -{ +{ int16_t low, high; - + fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) { x86_int(5); return 1; } - + CLOCK_CYCLES(is486 ? 7 : 10); PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 0); return 0; } static int opBOUND_w_a32(uint32_t fetchdat) -{ +{ int16_t low, high; - + fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) { x86_int(5); return 1; } - + CLOCK_CYCLES(is486 ? 7 : 10); PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 1); return 0; } static int opBOUND_l_a16(uint32_t fetchdat) -{ +{ int32_t low, high; - + fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) { x86_int(5); return 1; } - + CLOCK_CYCLES(is486 ? 7 : 10); PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 0); return 0; } static int opBOUND_l_a32(uint32_t fetchdat) -{ +{ int32_t low, high; - + fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) { x86_int(5); return 1; } - + CLOCK_CYCLES(is486 ? 7 : 10); PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 1); return 0; @@ -814,7 +818,7 @@ static int opLOADALL(uint32_t fetchdat) CLOCK_CYCLES(195); PREFETCH_RUN(195, 1, -1, 51,0,0,0, 0); return 0; -} +} static void set_segment_limit(x86seg *s, uint8_t segdat3) { @@ -843,7 +847,7 @@ static void loadall_load_segment(uint32_t addr, x86seg *s) use32 = (segdat3 & 0x40) ? 0x300 : 0; if (s == &cpu_state.seg_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; - + cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32); if (use32) cpu_cur_status |= CPU_STATUS_USE32; @@ -912,7 +916,7 @@ static int opLOADALL386(uint32_t fetchdat) CLOCK_CYCLES(350); return 0; -} +} static int opCPUID(uint32_t fetchdat) { @@ -966,4 +970,4 @@ static int opRSM(uint32_t fetchdat) cpu_state.pc = cpu_state.oldpc; x86illegal(); return 1; -} \ No newline at end of file +} diff --git a/src/cpu/x86_ops_mmx_arith.h b/src/cpu/x86_ops_mmx_arith.h index 3b9e2066c..afa8aa383 100644 --- a/src/cpu/x86_ops_mmx_arith.h +++ b/src/cpu/x86_ops_mmx_arith.h @@ -2,10 +2,10 @@ static int opPADDB_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] += src.b[0]; cpu_state.MM[cpu_reg].b[1] += src.b[1]; cpu_state.MM[cpu_reg].b[2] += src.b[2]; @@ -21,10 +21,10 @@ static int opPADDB_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] += src.b[0]; cpu_state.MM[cpu_reg].b[1] += src.b[1]; cpu_state.MM[cpu_reg].b[2] += src.b[2]; @@ -41,10 +41,10 @@ static int opPADDW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] += src.w[0]; cpu_state.MM[cpu_reg].w[1] += src.w[1]; cpu_state.MM[cpu_reg].w[2] += src.w[2]; @@ -56,10 +56,10 @@ static int opPADDW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] += src.w[0]; cpu_state.MM[cpu_reg].w[1] += src.w[1]; cpu_state.MM[cpu_reg].w[2] += src.w[2]; @@ -72,10 +72,10 @@ static int opPADDD_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].l[0] += src.l[0]; cpu_state.MM[cpu_reg].l[1] += src.l[1]; @@ -85,7 +85,7 @@ static int opPADDD_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -99,10 +99,10 @@ static int opPADDSB_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); @@ -118,7 +118,7 @@ static int opPADDSB_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -138,10 +138,10 @@ static int opPADDUSB_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); @@ -157,10 +157,10 @@ static int opPADDUSB_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); @@ -177,10 +177,10 @@ static int opPADDSW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); @@ -192,7 +192,7 @@ static int opPADDSW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -208,10 +208,10 @@ static int opPADDUSW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); @@ -223,10 +223,10 @@ static int opPADDUSW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); @@ -239,7 +239,7 @@ static int opPMADDWD_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -252,14 +252,14 @@ static int opPMADDWD_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].l[1] = 0x80000000; else cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); - + return 0; } static int opPMADDWD_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -272,7 +272,7 @@ static int opPMADDWD_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].l[1] = 0x80000000; else cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); - + return 0; } @@ -280,7 +280,7 @@ static int opPMADDWD_a32(uint32_t fetchdat) static int opPMULLW_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -308,7 +308,7 @@ static int opPMULLW_a16(uint32_t fetchdat) static int opPMULLW_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { @@ -321,7 +321,7 @@ static int opPMULLW_a32(uint32_t fetchdat) else { MMX_REG src; - + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; @@ -337,7 +337,7 @@ static int opPMULLW_a32(uint32_t fetchdat) static int opPMULHW_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -350,7 +350,7 @@ static int opPMULHW_a16(uint32_t fetchdat) else { MMX_REG src; - + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; @@ -365,7 +365,7 @@ static int opPMULHW_a16(uint32_t fetchdat) static int opPMULHW_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { @@ -378,7 +378,7 @@ static int opPMULHW_a32(uint32_t fetchdat) else { MMX_REG src; - + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; @@ -395,10 +395,10 @@ static int opPSUBB_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; cpu_state.MM[cpu_reg].b[1] -= src.b[1]; cpu_state.MM[cpu_reg].b[2] -= src.b[2]; @@ -414,10 +414,10 @@ static int opPSUBB_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; cpu_state.MM[cpu_reg].b[1] -= src.b[1]; cpu_state.MM[cpu_reg].b[2] -= src.b[2]; @@ -434,10 +434,10 @@ static int opPSUBW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; cpu_state.MM[cpu_reg].w[1] -= src.w[1]; cpu_state.MM[cpu_reg].w[2] -= src.w[2]; @@ -449,10 +449,10 @@ static int opPSUBW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; cpu_state.MM[cpu_reg].w[1] -= src.w[1]; cpu_state.MM[cpu_reg].w[2] -= src.w[2]; @@ -465,10 +465,10 @@ static int opPSUBD_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; cpu_state.MM[cpu_reg].l[1] -= src.l[1]; @@ -478,10 +478,10 @@ static int opPSUBD_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; cpu_state.MM[cpu_reg].l[1] -= src.l[1]; @@ -493,10 +493,10 @@ static int opPSUBSB_a16(uint32_t fetchdat) MMX_REG src; pclog("opPSUBSB_a16(%08X)\n", fetchdat); MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); @@ -513,10 +513,10 @@ static int opPSUBSB_a32(uint32_t fetchdat) MMX_REG src; pclog("opPSUBSB_a32(%08X)\n", fetchdat); MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); @@ -533,10 +533,10 @@ static int opPSUBUSB_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); @@ -552,10 +552,10 @@ static int opPSUBUSB_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); @@ -572,10 +572,10 @@ static int opPSUBSW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); @@ -587,10 +587,10 @@ static int opPSUBSW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); @@ -603,10 +603,10 @@ static int opPSUBUSW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); @@ -618,10 +618,10 @@ static int opPSUBUSW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); diff --git a/src/cpu/x86_ops_mmx_cmp.h b/src/cpu/x86_ops_mmx_cmp.h index 0fee95923..a07d8d0a8 100644 --- a/src/cpu/x86_ops_mmx_cmp.h +++ b/src/cpu/x86_ops_mmx_cmp.h @@ -1,9 +1,9 @@ static int opPCMPEQB_a16(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -15,15 +15,15 @@ static int opPCMPEQB_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; - + return 0; } static int opPCMPEQB_a32(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -35,16 +35,16 @@ static int opPCMPEQB_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; - + return 0; } static int opPCMPGTB_a16(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -56,15 +56,15 @@ static int opPCMPGTB_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; - + return 0; } static int opPCMPGTB_a32(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -76,16 +76,16 @@ static int opPCMPGTB_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; - + return 0; } static int opPCMPEQW_a16(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -93,15 +93,15 @@ static int opPCMPEQW_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; - + return 0; } static int opPCMPEQW_a32(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -109,16 +109,16 @@ static int opPCMPEQW_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; - + return 0; } static int opPCMPGTW_a16(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -126,15 +126,15 @@ static int opPCMPGTW_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; - + return 0; } static int opPCMPGTW_a32(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -142,64 +142,64 @@ static int opPCMPGTW_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; - + return 0; } static int opPCMPEQD_a16(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; - + return 0; } static int opPCMPEQD_a32(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; - + return 0; } static int opPCMPGTD_a16(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; - + return 0; } static int opPCMPGTD_a32(uint32_t fetchdat) { MMX_REG src; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; - + return 0; } diff --git a/src/cpu/x86_ops_mmx_logic.h b/src/cpu/x86_ops_mmx_logic.h index be5132e85..e3f1d9145 100644 --- a/src/cpu/x86_ops_mmx_logic.h +++ b/src/cpu/x86_ops_mmx_logic.h @@ -2,10 +2,10 @@ static int opPAND_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q &= src.q; return 0; } @@ -13,10 +13,10 @@ static int opPAND_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q &= src.q; return 0; } @@ -25,10 +25,10 @@ static int opPANDN_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; return 0; } @@ -36,10 +36,10 @@ static int opPANDN_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; return 0; } @@ -48,10 +48,10 @@ static int opPOR_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q |= src.q; return 0; } @@ -59,10 +59,10 @@ static int opPOR_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q |= src.q; return 0; } @@ -71,10 +71,10 @@ static int opPXOR_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q ^= src.q; return 0; } @@ -82,10 +82,10 @@ static int opPXOR_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].q ^= src.q; return 0; } diff --git a/src/cpu/x86_ops_mmx_mov.h b/src/cpu/x86_ops_mmx_mov.h index e17721229..fe06525b7 100644 --- a/src/cpu/x86_ops_mmx_mov.h +++ b/src/cpu/x86_ops_mmx_mov.h @@ -1,7 +1,7 @@ static int opMOVD_l_mm_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -25,7 +25,7 @@ static int opMOVD_l_mm_a16(uint32_t fetchdat) static int opMOVD_l_mm_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { @@ -50,7 +50,7 @@ static int opMOVD_l_mm_a32(uint32_t fetchdat) static int opMOVD_mm_l_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -69,7 +69,7 @@ static int opMOVD_mm_l_a16(uint32_t fetchdat) static int opMOVD_mm_l_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { @@ -86,10 +86,58 @@ static int opMOVD_mm_l_a32(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +/*Cyrix maps both MOVD and SMINT to the same opcode*/ +static int opMOVD_mm_l_a16_cx(uint32_t fetchdat) +{ + if (in_smm) + return opSMINT(fetchdat); + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_mm_l_a32_cx(uint32_t fetchdat) +{ + if (in_smm) + return opSMINT(fetchdat); + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +#endif + static int opMOVQ_q_mm_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -99,7 +147,7 @@ static int opMOVQ_q_mm_a16(uint32_t fetchdat) else { uint64_t dst; - + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].q = dst; @@ -110,7 +158,7 @@ static int opMOVQ_q_mm_a16(uint32_t fetchdat) static int opMOVQ_q_mm_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { @@ -120,7 +168,7 @@ static int opMOVQ_q_mm_a32(uint32_t fetchdat) else { uint64_t dst; - + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].q = dst; @@ -132,7 +180,7 @@ static int opMOVQ_q_mm_a32(uint32_t fetchdat) static int opMOVQ_mm_q_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -151,7 +199,7 @@ static int opMOVQ_mm_q_a16(uint32_t fetchdat) static int opMOVQ_mm_q_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { diff --git a/src/cpu/x86_ops_mmx_pack.h b/src/cpu/x86_ops_mmx_pack.h index b03ef842e..e12d1b448 100644 --- a/src/cpu/x86_ops_mmx_pack.h +++ b/src/cpu/x86_ops_mmx_pack.h @@ -1,7 +1,7 @@ static int opPUNPCKLDQ_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -11,7 +11,7 @@ static int opPUNPCKLDQ_a16(uint32_t fetchdat) else { uint32_t src; - + SEG_CHECK_READ(cpu_state.ea_seg); src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].l[1] = src; @@ -23,7 +23,7 @@ static int opPUNPCKLDQ_a16(uint32_t fetchdat) static int opPUNPCKLDQ_a32(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_32(fetchdat); if (cpu_mod == 3) { @@ -47,10 +47,10 @@ static int opPUNPCKHDQ_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); - + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; cpu_state.MM[cpu_reg].l[1] = src.l[1]; @@ -60,7 +60,7 @@ static int opPUNPCKHDQ_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -74,7 +74,7 @@ static int opPUNPCKLBW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -93,7 +93,7 @@ static int opPUNPCKLBW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -113,7 +113,7 @@ static int opPUNPCKHBW_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -125,14 +125,14 @@ static int opPUNPCKHBW_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = src.b[6]; cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; cpu_state.MM[cpu_reg].b[7] = src.b[7]; - + return 0; } static int opPUNPCKHBW_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -144,7 +144,7 @@ static int opPUNPCKHBW_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = src.b[6]; cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; cpu_state.MM[cpu_reg].b[7] = src.b[7]; - + return 0; } @@ -152,7 +152,7 @@ static int opPUNPCKLWD_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -167,7 +167,7 @@ static int opPUNPCKLWD_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -183,7 +183,7 @@ static int opPUNPCKHWD_a16(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); @@ -198,7 +198,7 @@ static int opPUNPCKHWD_a32(uint32_t fetchdat) { MMX_REG src; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); @@ -214,7 +214,7 @@ static int opPACKSSWB_a16(uint32_t fetchdat) { MMX_REG src, dst; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); dst = cpu_state.MM[cpu_reg]; @@ -227,14 +227,14 @@ static int opPACKSSWB_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); - + return 0; } static int opPACKSSWB_a32(uint32_t fetchdat) { MMX_REG src, dst; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); dst = cpu_state.MM[cpu_reg]; @@ -247,7 +247,7 @@ static int opPACKSSWB_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); - + return 0; } @@ -255,7 +255,7 @@ static int opPACKUSWB_a16(uint32_t fetchdat) { MMX_REG src, dst; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); dst = cpu_state.MM[cpu_reg]; @@ -268,14 +268,14 @@ static int opPACKUSWB_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); - + return 0; } static int opPACKUSWB_a32(uint32_t fetchdat) { MMX_REG src, dst; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); dst = cpu_state.MM[cpu_reg]; @@ -296,31 +296,31 @@ static int opPACKSSDW_a16(uint32_t fetchdat) { MMX_REG src, dst; MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSRC(); dst = cpu_state.MM[cpu_reg]; - + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); - + return 0; } static int opPACKSSDW_a32(uint32_t fetchdat) { MMX_REG src, dst; MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSRC(); dst = cpu_state.MM[cpu_reg]; - + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); - + return 0; } diff --git a/src/cpu/x86_ops_mmx_shift.h b/src/cpu/x86_ops_mmx_shift.h index a0a4d90c1..df8d75cf8 100644 --- a/src/cpu/x86_ops_mmx_shift.h +++ b/src/cpu/x86_ops_mmx_shift.h @@ -16,7 +16,7 @@ static int opPSxxW_imm(uint32_t fetchdat) int reg = fetchdat & 7; int op = fetchdat & 0x38; int shift = (fetchdat >> 8) & 0xff; - + cpu_state.pc += 2; MMX_ENTER(); @@ -65,9 +65,9 @@ static int opPSxxW_imm(uint32_t fetchdat) static int opPSLLW_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -86,9 +86,9 @@ static int opPSLLW_a16(uint32_t fetchdat) static int opPSLLW_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -108,9 +108,9 @@ static int opPSLLW_a32(uint32_t fetchdat) static int opPSRLW_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -129,9 +129,9 @@ static int opPSRLW_a16(uint32_t fetchdat) static int opPSRLW_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -151,9 +151,9 @@ static int opPSRLW_a32(uint32_t fetchdat) static int opPSRAW_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -164,15 +164,15 @@ static int opPSRAW_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].sw[1] >>= shift; cpu_state.MM[cpu_reg].sw[2] >>= shift; cpu_state.MM[cpu_reg].sw[3] >>= shift; - + return 0; } static int opPSRAW_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -183,7 +183,7 @@ static int opPSRAW_a32(uint32_t fetchdat) cpu_state.MM[cpu_reg].sw[1] >>= shift; cpu_state.MM[cpu_reg].sw[2] >>= shift; cpu_state.MM[cpu_reg].sw[3] >>= shift; - + return 0; } @@ -192,7 +192,7 @@ static int opPSxxD_imm(uint32_t fetchdat) int reg = fetchdat & 7; int op = fetchdat & 0x38; int shift = (fetchdat >> 8) & 0xff; - + cpu_state.pc += 2; MMX_ENTER(); @@ -235,9 +235,9 @@ static int opPSxxD_imm(uint32_t fetchdat) static int opPSLLD_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -254,9 +254,9 @@ static int opPSLLD_a16(uint32_t fetchdat) static int opPSLLD_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -274,9 +274,9 @@ static int opPSLLD_a32(uint32_t fetchdat) static int opPSRLD_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -293,9 +293,9 @@ static int opPSRLD_a16(uint32_t fetchdat) static int opPSRLD_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -313,9 +313,9 @@ static int opPSRLD_a32(uint32_t fetchdat) static int opPSRAD_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -324,15 +324,15 @@ static int opPSRAD_a16(uint32_t fetchdat) cpu_state.MM[cpu_reg].sl[0] >>= shift; cpu_state.MM[cpu_reg].sl[1] >>= shift; - + return 0; } static int opPSRAD_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -350,7 +350,7 @@ static int opPSxxQ_imm(uint32_t fetchdat) int reg = fetchdat & 7; int op = fetchdat & 0x38; int shift = (fetchdat >> 8) & 0xff; - + cpu_state.pc += 2; MMX_ENTER(); @@ -386,9 +386,9 @@ static int opPSxxQ_imm(uint32_t fetchdat) static int opPSLLQ_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -402,9 +402,9 @@ static int opPSLLQ_a16(uint32_t fetchdat) static int opPSLLQ_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); @@ -419,9 +419,9 @@ static int opPSLLQ_a32(uint32_t fetchdat) static int opPSRLQ_a16(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_16(fetchdat); MMX_GETSHIFT(); @@ -435,9 +435,9 @@ static int opPSRLQ_a16(uint32_t fetchdat) static int opPSRLQ_a32(uint32_t fetchdat) { int shift; - + MMX_ENTER(); - + fetch_ea_32(fetchdat); MMX_GETSHIFT(); diff --git a/src/cpu/x86_ops_mov.h b/src/cpu/x86_ops_mov.h index 2c96317b7..e7d5247d1 100644 --- a/src/cpu/x86_ops_mov.h +++ b/src/cpu/x86_ops_mov.h @@ -262,7 +262,7 @@ static int opMOV_AL_a16(uint32_t fetchdat) AL = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); - return 0; + return 0; } static int opMOV_AL_a32(uint32_t fetchdat) { @@ -274,19 +274,19 @@ static int opMOV_AL_a32(uint32_t fetchdat) AL = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); - return 0; + return 0; } static int opMOV_AX_a16(uint32_t fetchdat) { uint16_t temp; uint16_t addr = getwordf(); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ(cpu_state.ea_seg, addr, addr+1); + CHECK_READ(cpu_state.ea_seg, addr, addr + 1UL); temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); - return 0; + return 0; } static int opMOV_AX_a32(uint32_t fetchdat) { @@ -298,19 +298,19 @@ static int opMOV_AX_a32(uint32_t fetchdat) AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); - return 0; + return 0; } static int opMOV_EAX_a16(uint32_t fetchdat) { uint32_t temp; uint16_t addr = getwordf(); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ(cpu_state.ea_seg, addr, addr+3); + CHECK_READ(cpu_state.ea_seg, addr, addr + 3UL); temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 0,1,0,0, 0); - return 0; + return 0; } static int opMOV_EAX_a32(uint32_t fetchdat) { @@ -322,7 +322,7 @@ static int opMOV_EAX_a32(uint32_t fetchdat) EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 0,1,0,0, 1); - return 0; + return 0; } static int opMOV_a16_AL(uint32_t fetchdat) @@ -349,7 +349,7 @@ static int opMOV_a16_AX(uint32_t fetchdat) { uint16_t addr = getwordf(); SEG_CHECK_WRITE(cpu_state.ea_seg); - CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 1); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 1UL); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); @@ -369,7 +369,7 @@ static int opMOV_a16_EAX(uint32_t fetchdat) { uint16_t addr = getwordf(); SEG_CHECK_WRITE(cpu_state.ea_seg); - CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 3); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 3UL); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); @@ -431,7 +431,7 @@ static int opXLAT_a16(uint32_t fetchdat) { uint32_t addr = (BX + AL)&0xFFFF; uint8_t temp; - + SEG_CHECK_READ(cpu_state.ea_seg); temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; @@ -443,7 +443,7 @@ static int opXLAT_a32(uint32_t fetchdat) { uint32_t addr = EBX + AL; uint8_t temp; - + SEG_CHECK_READ(cpu_state.ea_seg); temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; @@ -498,7 +498,7 @@ static int opMOV_w_r_a16(uint32_t fetchdat) PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); } else - { + { SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); @@ -516,7 +516,7 @@ static int opMOV_w_r_a32(uint32_t fetchdat) PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); } else - { + { SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); @@ -525,7 +525,7 @@ static int opMOV_w_r_a32(uint32_t fetchdat) return cpu_state.abrt; } static int opMOV_l_r_a16(uint32_t fetchdat) -{ +{ fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -543,7 +543,7 @@ static int opMOV_l_r_a16(uint32_t fetchdat) return cpu_state.abrt; } static int opMOV_l_r_a32(uint32_t fetchdat) -{ +{ fetch_ea_32(fetchdat); if (cpu_mod == 3) { diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index dd224608c..667ea9d31 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -12,6 +12,12 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) cpu_state.regs[cpu_rm].l = cr0; if (is486 || isibm486) cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + else { + if (is386) + cpu_state.regs[cpu_rm].l |=0x7fffffe0; + else + cpu_state.regs[cpu_rm].l |=0x7ffffff0; + } break; case 2: cpu_state.regs[cpu_rm].l = cr2; @@ -48,6 +54,12 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat) cpu_state.regs[cpu_rm].l = cr0; if (is486 || isibm486) cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + else { + if (is386) + cpu_state.regs[cpu_rm].l |=0x7fffffe0; + else + cpu_state.regs[cpu_rm].l |=0x7ffffff0; + } break; case 2: cpu_state.regs[cpu_rm].l = cr2; @@ -101,7 +113,7 @@ static int opMOV_r_DRx_a32(uint32_t fetchdat) static int opMOV_CRx_r_a16(uint32_t fetchdat) { uint32_t old_cr0 = cr0; - + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x86gpf(NULL,0); @@ -113,6 +125,9 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) case 0: if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) flushmmucache(); + /* Make sure CPL = 0 when switching from real mode to protected mode. */ + if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) + cpu_state.seg_cs.access &= 0x9f; cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; @@ -157,7 +172,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) static int opMOV_CRx_r_a32(uint32_t fetchdat) { uint32_t old_cr0 = cr0; - + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x86gpf(NULL,0); @@ -169,6 +184,9 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) case 0: if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) flushmmucache(); + /* Make sure CPL = 0 when switching from real mode to protected mode. */ + if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) + cpu_state.seg_cs.access &= 0x9f; cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; @@ -238,55 +256,113 @@ static int opMOV_DRx_r_a32(uint32_t fetchdat) return 0; } +static void opMOV_r_TRx(void) +{ + uint32_t base; + + base = _tr[4] & 0xfffff800; + switch (cpu_reg) { + case 3: + pclog("[R] %08X cache = %08X\n", base + cache_index, _tr[3]); + _tr[3] = *(uint32_t *) &(_cache[cache_index]); + cache_index = (cache_index + 4) & 0xf; + break; + } + cpu_state.regs[cpu_rm].l = _tr[cpu_reg]; + CLOCK_CYCLES(6); +} static int opMOV_r_TRx_a16(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } fetch_ea_16(fetchdat); - cpu_state.regs[cpu_rm].l = 0; - CLOCK_CYCLES(6); + opMOV_r_TRx(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); return 0; } static int opMOV_r_TRx_a32(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } fetch_ea_32(fetchdat); - cpu_state.regs[cpu_rm].l = 0; - CLOCK_CYCLES(6); + opMOV_r_TRx(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); return 0; } +static void opMOV_TRx_r(void) +{ + uint32_t base; + int i, ctl; + + _tr[cpu_reg] = cpu_state.regs[cpu_rm].l; + base = _tr[4] & 0xfffff800; + ctl = _tr[5] & 3; + switch (cpu_reg) { + case 3: + pclog("[W] %08X cache = %08X\n", base + cache_index, _tr[3]); + *(uint32_t *) &(_cache[cache_index]) = _tr[3]; + cache_index = (cache_index + 4) & 0xf; + break; + case 4: + if (!(cr0 & 1) && !(_tr[5] & (1 << 19))) + pclog("TAG = %08X, DEST = %08X\n", base, base + cache_index - 16); + break; + case 5: + pclog("[16] EXT = %i (%i), SET = %04X\n", !!(_tr[5] & (1 << 19)), _tr[5] & 0x03, _tr[5] & 0x7f0); + if (!(_tr[5] & (1 << 19))) { + switch(ctl) { + case 0: + pclog(" Cache fill or read...\n", base); + break; + case 1: + base += (_tr[5] & 0x7f0); + pclog(" Writing 16 bytes to %08X...\n", base); + for (i = 0; i < 16; i += 4) + mem_writel_phys(base + i, *(uint32_t *) &(_cache[i])); + break; + case 2: + base += (_tr[5] & 0x7f0); + pclog(" Reading 16 bytes from %08X...\n", base); + for (i = 0; i < 16; i += 4) + *(uint32_t *) &(_cache[i]) = mem_readl_phys(base + i); + break; + case 3: + pclog(" Cache invalidate/flush...\n", base); + break; + } + } + break; + } + CLOCK_CYCLES(6); +} static int opMOV_TRx_r_a16(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } fetch_ea_16(fetchdat); - CLOCK_CYCLES(6); + opMOV_TRx_r(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); return 0; } static int opMOV_TRx_r_a32(uint32_t fetchdat) { - if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + if ((cpu_s->cpu_type == CPU_PENTIUM) || ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1))) { x86gpf(NULL, 0); return 1; } - fetch_ea_16(fetchdat); - CLOCK_CYCLES(6); + fetch_ea_32(fetchdat); + opMOV_TRx_r(); PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); return 0; } - diff --git a/src/cpu/x86_ops_mov_seg.h b/src/cpu/x86_ops_mov_seg.h index da7727143..02e2d50de 100644 --- a/src/cpu/x86_ops_mov_seg.h +++ b/src/cpu/x86_ops_mov_seg.h @@ -25,7 +25,7 @@ static int opMOV_w_seg_a16(uint32_t fetchdat) seteaw(GS); break; } - + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); return cpu_state.abrt; @@ -57,7 +57,7 @@ static int opMOV_w_seg_a32(uint32_t fetchdat) seteaw(GS); break; } - + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); return cpu_state.abrt; @@ -96,7 +96,7 @@ static int opMOV_l_seg_a16(uint32_t fetchdat) else seteaw(GS); break; } - + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); return cpu_state.abrt; @@ -134,7 +134,7 @@ static int opMOV_l_seg_a32(uint32_t fetchdat) else seteaw(GS); break; } - + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); return cpu_state.abrt; @@ -143,12 +143,12 @@ static int opMOV_l_seg_a32(uint32_t fetchdat) static int opMOV_seg_w_a16(uint32_t fetchdat) { uint16_t new_seg; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); new_seg=geteaw(); if (cpu_state.abrt) return 1; - + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -176,7 +176,7 @@ static int opMOV_seg_w_a16(uint32_t fetchdat) loadseg(new_seg, &cpu_state.seg_gs); break; } - + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); return cpu_state.abrt; @@ -184,12 +184,12 @@ static int opMOV_seg_w_a16(uint32_t fetchdat) static int opMOV_seg_w_a32(uint32_t fetchdat) { uint16_t new_seg; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); new_seg=geteaw(); if (cpu_state.abrt) return 1; - + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -217,7 +217,7 @@ static int opMOV_seg_w_a32(uint32_t fetchdat) loadseg(new_seg, &cpu_state.seg_gs); break; } - + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); return cpu_state.abrt; @@ -231,11 +231,12 @@ static int opLDS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state. eaaddr + 3); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); return 0; @@ -247,11 +248,12 @@ static int opLDS_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state. eaaddr + 3); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); return 0; @@ -264,11 +266,12 @@ static int opLDS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state. eaaddr + 5); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); return 0; @@ -281,11 +284,12 @@ static int opLDS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state. eaaddr + 5); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); return 0; @@ -298,11 +302,12 @@ static int opLSS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); return 1; @@ -314,11 +319,12 @@ static int opLSS_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); return 1; @@ -331,11 +337,12 @@ static int opLSS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); return 1; @@ -348,11 +355,12 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; - + CLOCK_CYCLES(7); PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); return 1; @@ -366,6 +374,7 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_16(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); \ addr = readmemw(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ @@ -383,6 +392,7 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); \ addr = readmemw(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ @@ -401,6 +411,7 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_16(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); \ addr = readmeml(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ @@ -419,6 +430,7 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); \ addr = readmeml(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ @@ -428,7 +440,7 @@ static int opLSS_l_a32(uint32_t fetchdat) PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); \ return 0; \ } - + opLsel(ES, cpu_state.seg_es) opLsel(FS, cpu_state.seg_fs) opLsel(GS, cpu_state.seg_gs) diff --git a/src/cpu/x86_ops_movx.h b/src/cpu/x86_ops_movx.h index 2e4fa2001..3ad89b7f0 100644 --- a/src/cpu/x86_ops_movx.h +++ b/src/cpu/x86_ops_movx.h @@ -1,13 +1,13 @@ static int opMOVZX_w_b_a16(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -15,13 +15,13 @@ static int opMOVZX_w_b_a16(uint32_t fetchdat) static int opMOVZX_w_b_a32(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -29,13 +29,13 @@ static int opMOVZX_w_b_a32(uint32_t fetchdat) static int opMOVZX_l_b_a16(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -43,13 +43,13 @@ static int opMOVZX_l_b_a16(uint32_t fetchdat) static int opMOVZX_l_b_a32(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -57,13 +57,13 @@ static int opMOVZX_l_b_a32(uint32_t fetchdat) static int opMOVZX_w_w_a16(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -71,13 +71,13 @@ static int opMOVZX_w_w_a16(uint32_t fetchdat) static int opMOVZX_w_w_a32(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -85,13 +85,13 @@ static int opMOVZX_w_w_a32(uint32_t fetchdat) static int opMOVZX_l_w_a16(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -99,13 +99,13 @@ static int opMOVZX_l_w_a16(uint32_t fetchdat) static int opMOVZX_l_w_a32(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -114,15 +114,15 @@ static int opMOVZX_l_w_a32(uint32_t fetchdat) static int opMOVSX_w_b_a16(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; - if (temp & 0x80) + if (temp & 0x80) cpu_state.regs[cpu_reg].w |= 0xff00; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -130,15 +130,15 @@ static int opMOVSX_w_b_a16(uint32_t fetchdat) static int opMOVSX_w_b_a32(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; - if (temp & 0x80) + if (temp & 0x80) cpu_state.regs[cpu_reg].w |= 0xff00; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -146,15 +146,15 @@ static int opMOVSX_w_b_a32(uint32_t fetchdat) static int opMOVSX_l_b_a16(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; - if (temp & 0x80) + if (temp & 0x80) cpu_state.regs[cpu_reg].l |= 0xffffff00; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -162,15 +162,15 @@ static int opMOVSX_l_b_a16(uint32_t fetchdat) static int opMOVSX_l_b_a32(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; - if (temp & 0x80) + if (temp & 0x80) cpu_state.regs[cpu_reg].l |= 0xffffff00; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -178,7 +178,7 @@ static int opMOVSX_l_b_a32(uint32_t fetchdat) static int opMOVSX_l_w_a16(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); @@ -186,7 +186,7 @@ static int opMOVSX_l_w_a16(uint32_t fetchdat) cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x8000) cpu_state.regs[cpu_reg].l |= 0xffff0000; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -194,7 +194,7 @@ static int opMOVSX_l_w_a16(uint32_t fetchdat) static int opMOVSX_l_w_a32(uint32_t fetchdat) { uint16_t temp; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); @@ -202,7 +202,7 @@ static int opMOVSX_l_w_a32(uint32_t fetchdat) cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x8000) cpu_state.regs[cpu_reg].l |= 0xffff0000; - + CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; diff --git a/src/cpu/x86_ops_mul.h b/src/cpu/x86_ops_mul.h index a96ce54a2..ca12a9add 100644 --- a/src/cpu/x86_ops_mul.h +++ b/src/cpu/x86_ops_mul.h @@ -1,15 +1,15 @@ static int opIMUL_w_iw_a16(uint32_t fetchdat) { int32_t templ; - int16_t tempw, tempw2; - + int16_t tempw, tempw2; + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getword(); if (cpu_state.abrt) return 1; - + templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; @@ -24,14 +24,14 @@ static int opIMUL_w_iw_a32(uint32_t fetchdat) { int32_t templ; int16_t tempw, tempw2; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getword(); if (cpu_state.abrt) return 1; - + templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; @@ -47,20 +47,20 @@ static int opIMUL_l_il_a16(uint32_t fetchdat) { int64_t temp64; int32_t templ, templ2; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getlong(); if (cpu_state.abrt) return 1; - + temp64 = ((int64_t)templ) * ((int64_t)templ2); flags_rebuild(); if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; - + CLOCK_CYCLES(25); PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 0); return 0; @@ -69,20 +69,20 @@ static int opIMUL_l_il_a32(uint32_t fetchdat) { int64_t temp64; int32_t templ, templ2; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getlong(); if (cpu_state.abrt) return 1; - + temp64 = ((int64_t)templ) * ((int64_t)templ2); flags_rebuild(); if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; - + CLOCK_CYCLES(25); PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 1); return 0; @@ -92,21 +92,21 @@ static int opIMUL_w_ib_a16(uint32_t fetchdat) { int32_t templ; int16_t tempw, tempw2; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getbyte(); if (cpu_state.abrt) return 1; if (tempw2 & 0x80) tempw2 |= 0xff00; - + templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; - + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 0); return 0; @@ -115,21 +115,21 @@ static int opIMUL_w_ib_a32(uint32_t fetchdat) { int32_t templ; int16_t tempw, tempw2; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); - + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getbyte(); if (cpu_state.abrt) return 1; if (tempw2 & 0x80) tempw2 |= 0xff00; - + templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; - + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 1); return 0; @@ -142,18 +142,18 @@ static int opIMUL_l_ib_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getbyte(); if (cpu_state.abrt) return 1; if (templ2 & 0x80) templ2 |= 0xffffff00; - + temp64 = ((int64_t)templ)*((int64_t)templ2); flags_rebuild(); if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; - + CLOCK_CYCLES(20); PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 0); return 0; @@ -165,18 +165,18 @@ static int opIMUL_l_ib_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getbyte(); if (cpu_state.abrt) return 1; if (templ2 & 0x80) templ2 |= 0xffffff00; - + temp64 = ((int64_t)templ)*((int64_t)templ2); flags_rebuild(); if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; - + CLOCK_CYCLES(20); PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 1); return 0; @@ -187,7 +187,7 @@ static int opIMUL_l_ib_a32(uint32_t fetchdat) static int opIMUL_w_w_a16(uint32_t fetchdat) { int32_t templ; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_READ(cpu_state.ea_seg); @@ -198,7 +198,7 @@ static int opIMUL_w_w_a16(uint32_t fetchdat) flags_rebuild(); if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); - + CLOCK_CYCLES(18); PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 0); return 0; @@ -206,18 +206,18 @@ static int opIMUL_w_w_a16(uint32_t fetchdat) static int opIMUL_w_w_a32(uint32_t fetchdat) { int32_t templ; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - + SEG_CHECK_READ(cpu_state.ea_seg); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = templ & 0xFFFF; flags_rebuild(); if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); - + CLOCK_CYCLES(18); PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 1); return 0; @@ -229,15 +229,15 @@ static int opIMUL_l_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; flags_rebuild(); if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); - + CLOCK_CYCLES(30); PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 0); return 0; @@ -248,17 +248,16 @@ static int opIMUL_l_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); if (cpu_mod != 3) - SEG_CHECK_READ(cpu_state.ea_seg); - + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; flags_rebuild(); if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; else cpu_state.flags &= ~(C_FLAG | V_FLAG); - + CLOCK_CYCLES(30); PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 1); return 0; } - diff --git a/src/cpu/x86_ops_pmode.h b/src/cpu/x86_ops_pmode.h index 26bdc3a11..698cfc838 100644 --- a/src/cpu/x86_ops_pmode.h +++ b/src/cpu/x86_ops_pmode.h @@ -1,13 +1,13 @@ static int opARPL_a16(uint32_t fetchdat) { uint16_t temp_seg; - + NOTRM fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); temp_seg = geteaw(); if (cpu_state.abrt) return 1; - + flags_rebuild(); if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) { @@ -17,7 +17,7 @@ static int opARPL_a16(uint32_t fetchdat) } else cpu_state.flags &= ~Z_FLAG; - + CLOCK_CYCLES(is486 ? 9 : 20); PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0); return 0; @@ -25,13 +25,13 @@ static int opARPL_a16(uint32_t fetchdat) static int opARPL_a32(uint32_t fetchdat) { uint16_t temp_seg; - + NOTRM fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); temp_seg = geteaw(); if (cpu_state.abrt) return 1; - + flags_rebuild(); if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) { @@ -41,7 +41,7 @@ static int opARPL_a32(uint32_t fetchdat) } else cpu_state.flags &= ~Z_FLAG; - + CLOCK_CYCLES(is486 ? 9 : 20); PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1); return 0; @@ -163,7 +163,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32) int dpl, valid, granularity; uint32_t addr, base, limit; uint16_t desc, sel; - uint8_t access; + uint8_t access, ar_high; switch (rmdat & 0x38) { @@ -194,10 +194,12 @@ static int op0F00_common(uint32_t fetchdat, int ea32) limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); access = readmemb(0, addr + 5); + ar_high = readmemb(0, addr + 6); granularity = readmemb(0, addr + 6) & 0x80; if (cpu_state.abrt) return 1; ldt.limit = limit; ldt.access = access; + ldt.ar_high = ar_high; if (granularity) { ldt.limit <<= 12; @@ -221,6 +223,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32) limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); access = readmemb(0, addr + 5); + ar_high = readmemb(0, addr + 6); granularity = readmemb(0, addr + 6) & 0x80; if (cpu_state.abrt) return 1; access |= 2; @@ -229,6 +232,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32) tr.seg = sel; tr.limit = limit; tr.access = access; + tr.ar_high = ar_high; if (granularity) { tr.limit <<= 12; @@ -294,7 +298,7 @@ static int op0F00_a16(uint32_t fetchdat) NOTRM fetch_ea_16(fetchdat); - + return op0F00_common(fetchdat, 0); } static int op0F00_a32(uint32_t fetchdat) @@ -302,7 +306,7 @@ static int op0F00_a32(uint32_t fetchdat) NOTRM fetch_ea_32(fetchdat); - + return op0F00_common(fetchdat, 1); } @@ -371,7 +375,7 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); if (is486 || isibm486) seteaw(msw); - else if (is386) seteaw(msw | 0xFF00); + else if (is386) seteaw(msw | /* 0xFF00 */ 0xFFE0); else seteaw(msw | 0xFFF0); CLOCK_CYCLES(2); PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); @@ -426,31 +430,31 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) static int op0F01_w_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + return op0F01_common(fetchdat, 0, 0, 0); } static int op0F01_w_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - + return op0F01_common(fetchdat, 0, 0, 1); } static int op0F01_l_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + return op0F01_common(fetchdat, 1, 0, 0); } static int op0F01_l_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - + return op0F01_common(fetchdat, 1, 0, 1); } static int op0F01_286(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + return op0F01_common(fetchdat, 0, 1, 0); } diff --git a/src/cpu/x86_ops_prefix.h b/src/cpu/x86_ops_prefix.h index 8d191103d..3029da30a 100644 --- a/src/cpu/x86_ops_prefix.h +++ b/src/cpu/x86_ops_prefix.h @@ -118,7 +118,7 @@ static int op_66_REPE(uint32_t fetchdat) /*Data size select*/ PREFETCH_PREFIX(); if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); - return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } static int op_67_REPE(uint32_t fetchdat) /*Address size select*/ { @@ -131,7 +131,7 @@ static int op_67_REPE(uint32_t fetchdat) /*Address size select*/ PREFETCH_PREFIX(); if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); - return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } static int op_66_REPNE(uint32_t fetchdat) /*Data size select*/ { @@ -144,7 +144,7 @@ static int op_66_REPNE(uint32_t fetchdat) /*Data size select*/ PREFETCH_PREFIX(); if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); - return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } static int op_67_REPNE(uint32_t fetchdat) /*Address size select*/ { @@ -157,5 +157,5 @@ static int op_67_REPNE(uint32_t fetchdat) /*Address size select*/ PREFETCH_PREFIX(); if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); - return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index efbb088ef..ffae30e09 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -3,6 +3,8 @@ static int opREP_INSB_ ## size(uint32_t fetchdat) { \ int reads = 0, writes = 0, total_cycles = 0; \ \ + addr64 = 0x00000000; \ + \ if (CNT_REG > 0) \ { \ uint8_t temp; \ @@ -10,8 +12,11 @@ static int opREP_INSB_ ## size(uint32_t fetchdat) SEG_CHECK_WRITE(&cpu_state.seg_es); \ check_io_perm(DX); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + high_page = 0; \ + do_mmut_wb(es, DEST_REG, &addr64); \ + if (cpu_state.abrt) return 1; \ temp = inb(DX); \ - writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememb_n(es, DEST_REG, addr64, temp); if (cpu_state.abrt) return 1; \ \ if (cpu_state.flags & D_FLAG) DEST_REG--; \ else DEST_REG++; \ @@ -32,6 +37,8 @@ static int opREP_INSW_ ## size(uint32_t fetchdat) { \ int reads = 0, writes = 0, total_cycles = 0; \ \ + addr64a[0] = addr64a[1] = 0x00000000; \ + \ if (CNT_REG > 0) \ { \ uint16_t temp; \ @@ -39,9 +46,12 @@ static int opREP_INSW_ ## size(uint32_t fetchdat) SEG_CHECK_WRITE(&cpu_state.seg_es); \ check_io_perm(DX); \ check_io_perm(DX+1); \ - CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + high_page = 0; \ + do_mmut_ww(es, DEST_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ temp = inw(DX); \ - writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememw_n(es, DEST_REG, addr64a, temp); if (cpu_state.abrt) return 1; \ \ if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ @@ -62,6 +72,8 @@ static int opREP_INSL_ ## size(uint32_t fetchdat) { \ int reads = 0, writes = 0, total_cycles = 0; \ \ + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ + \ if (CNT_REG > 0) \ { \ uint32_t temp; \ @@ -71,9 +83,12 @@ static int opREP_INSL_ ## size(uint32_t fetchdat) check_io_perm(DX+1); \ check_io_perm(DX+2); \ check_io_perm(DX+3); \ - CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + high_page = 0; \ + do_mmut_wl(es, DEST_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ temp = inl(DX); \ - writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememl_n(es, DEST_REG, addr64a, temp); if (cpu_state.abrt) return 1; \ \ if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ @@ -126,7 +141,7 @@ static int opREP_OUTSW_ ## size(uint32_t fetchdat) { \ uint16_t temp; \ SEG_CHECK_READ(cpu_state.ea_seg); \ - CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ check_io_perm(DX); \ check_io_perm(DX+1); \ @@ -154,7 +169,7 @@ static int opREP_OUTSL_ ## size(uint32_t fetchdat) { \ uint32_t temp; \ SEG_CHECK_READ(cpu_state.ea_seg); \ - CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ check_io_perm(DX); \ check_io_perm(DX+1); \ @@ -181,32 +196,36 @@ static int opREP_MOVSB_ ## size(uint32_t fetchdat) { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + addr64 = addr64_2 = 0x00000000; \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ if (CNT_REG > 0) \ { \ SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - } \ + } \ while (CNT_REG > 0) \ { \ uint8_t temp; \ \ CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + high_page = 0; \ + do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64) ; \ + if (cpu_state.abrt) break; \ CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ - temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + do_mmut_wb(es, DEST_REG, &addr64_2); \ + if (cpu_state.abrt) break; \ + temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); if (cpu_state.abrt) return 1; \ + writememb_n(es, DEST_REG, addr64_2, temp); if (cpu_state.abrt) return 1; \ \ if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ else { DEST_REG++; SRC_REG++; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ - ins++; \ reads++; writes++; total_cycles += is486 ? 3 : 4; \ if (cycles < cycles_end) \ break; \ } \ - ins--; \ PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ if (CNT_REG > 0) \ { \ @@ -220,32 +239,37 @@ static int opREP_MOVSW_ ## size(uint32_t fetchdat) { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + addr64a[0] = addr64a[1] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = 0x00000000; \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ if (CNT_REG > 0) \ { \ SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - } \ + } \ while (CNT_REG > 0) \ { \ uint16_t temp; \ \ - CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ - CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ - temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ + high_page = 0; \ + do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) break; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + do_mmut_ww(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) break; \ + temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + writememw_n(es, DEST_REG, addr64a_2, temp); if (cpu_state.abrt) return 1; \ \ if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ else { DEST_REG += 2; SRC_REG += 2; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ - ins++; \ reads++; writes++; total_cycles += is486 ? 3 : 4; \ if (cycles < cycles_end) \ break; \ } \ - ins--; \ PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ if (CNT_REG > 0) \ { \ @@ -259,32 +283,37 @@ static int opREP_MOVSL_ ## size(uint32_t fetchdat) { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ if (CNT_REG > 0) \ { \ SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - } \ + } \ while (CNT_REG > 0) \ { \ uint32_t temp; \ \ - CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ - CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ - temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ + high_page = 0; \ + do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) break; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + do_mmut_wl(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) break; \ + temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + writememl_n(es, DEST_REG, addr64a_2, temp); if (cpu_state.abrt) return 1; \ \ if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ else { DEST_REG += 4; SRC_REG += 4; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ - ins++; \ reads++; writes++; total_cycles += is486 ? 3 : 4; \ if (cycles < cycles_end) \ break; \ } \ - ins--; \ PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ if (CNT_REG > 0) \ { \ @@ -313,7 +342,6 @@ static int opREP_STOSB_ ## size(uint32_t fetchdat) CNT_REG--; \ cycles -= is486 ? 4 : 5; \ writes++; total_cycles += is486 ? 4 : 5; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ @@ -336,14 +364,13 @@ static int opREP_STOSW_ ## size(uint32_t fetchdat) SEG_CHECK_WRITE(&cpu_state.seg_es); \ while (CNT_REG > 0) \ { \ - CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ writes++; total_cycles += is486 ? 4 : 5; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ @@ -366,14 +393,13 @@ static int opREP_STOSL_ ## size(uint32_t fetchdat) SEG_CHECK_WRITE(&cpu_state.seg_es); \ while (CNT_REG > 0) \ { \ - CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ writes++; total_cycles += is486 ? 4 : 5; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ @@ -404,7 +430,6 @@ static int opREP_LODSB_ ## size(uint32_t fetchdat) CNT_REG--; \ cycles -= is486 ? 4 : 5; \ reads++; total_cycles += is486 ? 4 : 5; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ @@ -427,14 +452,13 @@ static int opREP_LODSW_ ## size(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); \ while (CNT_REG > 0) \ { \ - CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ else SRC_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ reads++; total_cycles += is486 ? 4 : 5; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ @@ -457,14 +481,13 @@ static int opREP_LODSL_ ## size(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); \ while (CNT_REG > 0) \ { \ - CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ else SRC_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ reads++; total_cycles += is486 ? 4 : 5; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ @@ -479,11 +502,16 @@ static int opREP_LODSL_ ## size(uint32_t fetchdat) } \ +#define CHEK_READ(a, b, c) + + #define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ static int opREP_CMPSB_ ## size(uint32_t fetchdat) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ + addr64 = addr64_2 = 0x00000000; \ + \ tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ @@ -491,9 +519,18 @@ static int opREP_CMPSB_ ## size(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_READ(&cpu_state.seg_es); \ CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + high_page = uncached = 0; \ + do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64); \ + if (cpu_state.abrt) return 1; \ CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \ - temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ - temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ + do_mmut_rb2(es, DEST_REG, &addr64_2); \ + if (cpu_state.abrt) return 1; \ + temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = old_rl2; \ + temp2 = readmemb_n(es, DEST_REG, addr64_2); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = (uintptr_t) LOOKUP_INV; \ \ if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ else { DEST_REG++; SRC_REG++; } \ @@ -516,16 +553,28 @@ static int opREP_CMPSW_ ## size(uint32_t fetchdat) { \ int reads = 0, total_cycles = 0, tempz; \ \ + addr64a[0] = addr64a[1] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = 0x00000000; \ + \ tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ uint16_t temp, temp2; \ SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_READ(&cpu_state.seg_es); \ - CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ - CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ - temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ - temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ + high_page = uncached = 0; \ + do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + do_mmut_rw2(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) return 1; \ + temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = old_rl2; \ + temp2 = readmemw_n(es, DEST_REG, addr64a_2); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = (uintptr_t) LOOKUP_INV; \ \ if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ else { DEST_REG += 2; SRC_REG += 2; } \ @@ -548,16 +597,28 @@ static int opREP_CMPSL_ ## size(uint32_t fetchdat) { \ int reads = 0, total_cycles = 0, tempz; \ \ + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \ + \ tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ uint32_t temp, temp2; \ SEG_CHECK_READ(cpu_state.ea_seg); \ SEG_CHECK_READ(&cpu_state.seg_es); \ - CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ - CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ - temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ - temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ + high_page = uncached = 0; \ + do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + do_mmut_rl2(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) return 1; \ + temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = old_rl2; \ + temp2 = readmeml_n(es, DEST_REG, addr64a_2); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = (uintptr_t) LOOKUP_INV; \ \ if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ else { DEST_REG += 4; SRC_REG += 4; } \ @@ -597,11 +658,9 @@ static int opREP_SCASB_ ## size(uint32_t fetchdat) CNT_REG--; \ cycles -= is486 ? 5 : 8; \ reads++; total_cycles += is486 ? 5 : 8; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ - ins--; \ PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ @@ -622,7 +681,7 @@ static int opREP_SCASW_ ## size(uint32_t fetchdat) SEG_CHECK_READ(&cpu_state.seg_es); \ while ((CNT_REG > 0) && (FV == tempz)) \ { \ - CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ setsub16(AX, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ @@ -631,11 +690,9 @@ static int opREP_SCASW_ ## size(uint32_t fetchdat) CNT_REG--; \ cycles -= is486 ? 5 : 8; \ reads++; total_cycles += is486 ? 5 : 8; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ - ins--; \ PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ @@ -656,7 +713,7 @@ static int opREP_SCASL_ ## size(uint32_t fetchdat) SEG_CHECK_READ(&cpu_state.seg_es); \ while ((CNT_REG > 0) && (FV == tempz)) \ { \ - CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ setsub32(EAX, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ @@ -665,11 +722,9 @@ static int opREP_SCASL_ ## size(uint32_t fetchdat) CNT_REG--; \ cycles -= is486 ? 5 : 8; \ reads++; total_cycles += is486 ? 5 : 8; \ - ins++; \ if (cycles < cycles_end) \ break; \ } \ - ins--; \ PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ @@ -700,7 +755,7 @@ static int opREPNE(uint32_t fetchdat) return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } static int opREPE(uint32_t fetchdat) -{ +{ fetchdat = fastreadl(cs + cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc++; diff --git a/src/cpu/x86_ops_rep_dyn.h b/src/cpu/x86_ops_rep_dyn.h new file mode 100644 index 000000000..e63ed32fe --- /dev/null +++ b/src/cpu/x86_ops_rep_dyn.h @@ -0,0 +1,703 @@ +#define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ +static int opREP_INSB_ ## size(uint32_t fetchdat) \ +{ \ + addr64 = 0x00000000; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + high_page = 0; \ + do_mmut_wb(es, DEST_REG, &addr64); \ + if (cpu_state.abrt) return 1; \ + temp = inb(DX); \ + writememb_n(es, DEST_REG, addr64, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= 15; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSW_ ## size(uint32_t fetchdat) \ +{ \ + addr64a[0] = addr64a[1] = 0x00000000; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + high_page = 0; \ + do_mmut_ww(es, DEST_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ + temp = inw(DX); \ + writememw_n(es, DEST_REG, addr64a, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= 15; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSL_ ## size(uint32_t fetchdat) \ +{ \ + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + high_page = 0; \ + do_mmut_wl(es, DEST_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ + temp = inl(DX); \ + writememl_n(es, DEST_REG, addr64a, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= 15; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ +{ \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + outb(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= 14; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ +{ \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + outw(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= 14; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ +{ \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + outl(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= 14; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_MOVSB_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + addr64 = addr64_2 = 0x00000000; \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + high_page = 0; \ + do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64) ; \ + if (cpu_state.abrt) break; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + do_mmut_wb(es, DEST_REG, &addr64_2); \ + if (cpu_state.abrt) break; \ + temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); if (cpu_state.abrt) return 1; \ + writememb_n(es, DEST_REG, addr64_2, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSW_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + addr64a[0] = addr64a[1] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = 0x00000000; \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ + high_page = 0; \ + do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) break; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + do_mmut_ww(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) break; \ + temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + writememw_n(es, DEST_REG, addr64a_2, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSL_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ + high_page = 0; \ + do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) break; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + do_mmut_wl(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) break; \ + temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + writememl_n(es, DEST_REG, addr64a_2, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ + \ +static int opREP_STOSB_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSW_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSL_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_LODSB_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSW_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ + AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSL_ ## size(uint32_t fetchdat) \ +{ \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ + EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + if (cycles < cycles_end) \ + break; \ + } \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + + +#define CHEK_READ(a, b, c) + + +#define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ +static int opREP_CMPSB_ ## size(uint32_t fetchdat) \ +{ \ + int tempz; \ + \ + addr64 = addr64_2 = 0x00000000; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint8_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + high_page = uncached = 0; \ + do_mmut_rb(cpu_state.ea_seg->base, SRC_REG, &addr64); \ + if (cpu_state.abrt) return 1; \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + do_mmut_rb2(es, DEST_REG, &addr64_2); \ + if (cpu_state.abrt) return 1; \ + temp = readmemb_n(cpu_state.ea_seg->base, SRC_REG, addr64); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = old_rl2; \ + temp2 = readmemb_n(es, DEST_REG, addr64_2); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = (uintptr_t) LOOKUP_INV; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + setsub8(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSW_ ## size(uint32_t fetchdat) \ +{ \ + int tempz; \ + \ + addr64a[0] = addr64a[1] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = 0x00000000; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint16_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1UL); \ + high_page = uncached = 0; \ + do_mmut_rw(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + do_mmut_rw2(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) return 1; \ + temp = readmemw_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = old_rl2; \ + temp2 = readmemw_n(es, DEST_REG, addr64a_2); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = (uintptr_t) LOOKUP_INV; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + setsub16(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSL_ ## size(uint32_t fetchdat) \ +{ \ + int tempz; \ + \ + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint32_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3UL); \ + high_page = uncached = 0; \ + do_mmut_rl(cpu_state.ea_seg->base, SRC_REG, addr64a); \ + if (cpu_state.abrt) return 1; \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + do_mmut_rl2(es, DEST_REG, addr64a_2); \ + if (cpu_state.abrt) return 1; \ + temp = readmeml_n(cpu_state.ea_seg->base, SRC_REG, addr64a); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = old_rl2; \ + temp2 = readmeml_n(es, DEST_REG, addr64a_2); if (cpu_state.abrt) return 1; \ + if (uncached) \ + readlookup2[(uint32_t)(es+DEST_REG)>>12] = (uintptr_t) LOOKUP_INV; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + setsub32(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_SCASB_ ## size(uint32_t fetchdat) \ +{ \ + int tempz; \ + int cycles_end = cycles - 1000; \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub8(AL, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + if (cycles < cycles_end) \ + break; \ + } \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASW_ ## size(uint32_t fetchdat) \ +{ \ + int tempz; \ + int cycles_end = cycles - 1000; \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ + uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub16(AX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + if (cycles < cycles_end) \ + break; \ + } \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASL_ ## size(uint32_t fetchdat) \ +{ \ + int tempz; \ + int cycles_end = cycles - 1000; \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ + uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub32(EAX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + if (cycles < cycles_end) \ + break; \ + } \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} + +REP_OPS(a16, CX, SI, DI) +REP_OPS(a32, ECX, ESI, EDI) +REP_OPS_CMPS_SCAS(a16_NE, CX, SI, DI, 0) +REP_OPS_CMPS_SCAS(a16_E, CX, SI, DI, 1) +REP_OPS_CMPS_SCAS(a32_NE, ECX, ESI, EDI, 0) +REP_OPS_CMPS_SCAS(a32_E, ECX, ESI, EDI, 1) + +static int opREPNE(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int opREPE(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index 1ebe67b9c..222eb5243 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -51,10 +51,10 @@ static int opRETF_a16(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - + CPU_BLOCK_END(); RETF_a16(0); - + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); PREFETCH_FLUSH(); return 0; @@ -62,7 +62,7 @@ static int opRETF_a16(uint32_t fetchdat) static int opRETF_a32(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - + CPU_BLOCK_END(); RETF_a32(0); @@ -99,7 +99,7 @@ static int opRETF_a32_imm(uint32_t fetchdat) static int opIRET_286(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); @@ -144,7 +144,7 @@ static int opIRET_286(uint32_t fetchdat) static int opIRET(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { if (cr4 & CR4_VME) @@ -175,7 +175,7 @@ static int opIRET(uint32_t fetchdat) } else { - x86gpf(NULL,0); + x86gpf_expected(NULL,0); return 1; } } @@ -221,10 +221,10 @@ static int opIRET(uint32_t fetchdat) static int opIRETD(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { - x86gpf(NULL,0); + x86gpf_expected(NULL,0); return 1; } if (msw & 1) @@ -264,4 +264,3 @@ static int opIRETD(uint32_t fetchdat) PREFETCH_FLUSH(); return cpu_state.abrt; } - diff --git a/src/codegen/x86_ops_shift.h b/src/cpu/x86_ops_shift.h similarity index 63% rename from src/codegen/x86_ops_shift.h rename to src/cpu/x86_ops_shift.h index 5cf44943d..5d03cb9a9 100644 --- a/src/codegen/x86_ops_shift.h +++ b/src/cpu/x86_ops_shift.h @@ -1,3 +1,235 @@ +#ifdef USE_NEW_DYNAREC +#define OP_SHIFT_b(c, ea32) \ + { \ + uint8_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + temp = (temp << (c & 7)) | (temp >> (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL8, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR b,CL*/ \ + temp = (temp >> (c & 7)) | (temp << (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR8, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL b,CL*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x18: /*RCR b,CL*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x38: /*SAR b,CL*/ \ + temp = (int8_t)temp >> c; \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR8, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + } \ + } + +#define OP_SHIFT_w(c, ea32) \ + { \ + uint16_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + temp = (temp << (c & 15)) | (temp >> (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL16, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR w,CL*/ \ + temp = (temp >> (c & 15)) | (temp << (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR16, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL w, c*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 15)) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x18: /*RCR w, c*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x38: /*SAR w, c*/ \ + temp = (int16_t)temp >> c; \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR16, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + } \ + } + +#define OP_SHIFT_l(c, ea32) \ + { \ + uint32_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + temp = (temp << c) | (temp >> (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL32, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR l,CL*/ \ + temp = (temp >> c) | (temp << (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR32, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL l, c*/ \ + temp2 = CF_SET(); \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 31)) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x18: /*RCR l, c*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x38: /*SAR l, c*/ \ + temp = (int32_t)temp >> c; \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + } \ + } +#else #define OP_SHIFT_b(c, ea32) \ { \ uint8_t temp_orig = temp; \ @@ -240,13 +472,14 @@ break; \ } \ } +#endif static int opC0_a16(uint32_t fetchdat) { int c; int tempc; uint8_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -261,7 +494,7 @@ static int opC0_a32(uint32_t fetchdat) int c; int tempc; uint8_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -276,7 +509,7 @@ static int opC1_w_a16(uint32_t fetchdat) int c; int tempc; uint16_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -291,7 +524,7 @@ static int opC1_w_a32(uint32_t fetchdat) int c; int tempc; uint16_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -306,7 +539,7 @@ static int opC1_l_a16(uint32_t fetchdat) int c; int tempc; uint32_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -321,7 +554,7 @@ static int opC1_l_a32(uint32_t fetchdat) int c; int tempc; uint32_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -337,7 +570,7 @@ static int opD0_a16(uint32_t fetchdat) int c = 1; int tempc; uint8_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -350,7 +583,7 @@ static int opD0_a32(uint32_t fetchdat) int c = 1; int tempc; uint8_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -363,7 +596,7 @@ static int opD1_w_a16(uint32_t fetchdat) int c = 1; int tempc; uint16_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -376,7 +609,7 @@ static int opD1_w_a32(uint32_t fetchdat) int c = 1; int tempc; uint16_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -389,7 +622,7 @@ static int opD1_l_a16(uint32_t fetchdat) int c = 1; int tempc; uint32_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -402,7 +635,7 @@ static int opD1_l_a32(uint32_t fetchdat) int c = 1; int tempc; uint32_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -416,7 +649,7 @@ static int opD2_a16(uint32_t fetchdat) int c; int tempc; uint8_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -430,7 +663,7 @@ static int opD2_a32(uint32_t fetchdat) int c; int tempc; uint8_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -444,7 +677,7 @@ static int opD3_w_a16(uint32_t fetchdat) int c; int tempc; uint16_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -458,7 +691,7 @@ static int opD3_w_a32(uint32_t fetchdat) int c; int tempc; uint16_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -472,7 +705,7 @@ static int opD3_l_a16(uint32_t fetchdat) int c; int tempc; uint32_t temp, temp2 = 0; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -486,7 +719,7 @@ static int opD3_l_a32(uint32_t fetchdat) int c; int tempc; uint32_t temp, temp2 = 0; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -564,7 +797,7 @@ static int opD3_l_a32(uint32_t fetchdat) if (cpu_mod != 3) \ SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = getbyte() & 31; \ - operation() \ + operation(); \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ @@ -578,7 +811,7 @@ static int opD3_l_a32(uint32_t fetchdat) if (cpu_mod != 3) \ SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = CL & 31; \ - operation() \ + operation(); \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ @@ -592,7 +825,7 @@ static int opD3_l_a32(uint32_t fetchdat) if (cpu_mod != 3) \ SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = getbyte() & 31; \ - operation() \ + operation(); \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ @@ -606,13 +839,13 @@ static int opD3_l_a32(uint32_t fetchdat) if (cpu_mod != 3) \ SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = CL & 31; \ - operation() \ + operation(); \ \ CLOCK_CYCLES(3); \ PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ return 0; \ } - + opSHxD(SHLD_w) opSHxD(SHLD_l) opSHxD(SHRD_w) diff --git a/src/cpu/x86_ops_stack.h b/src/cpu/x86_ops_stack.h index 9ca1171a0..58f24c6f9 100644 --- a/src/cpu/x86_ops_stack.h +++ b/src/cpu/x86_ops_stack.h @@ -191,7 +191,7 @@ static int opPOPA_l(uint32_t fetchdat) static int opPUSH_imm_w(uint32_t fetchdat) { - uint16_t val = getwordf(); + uint16_t val = getwordf(); PUSH_W(val); CLOCK_CYCLES(2); PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); @@ -212,7 +212,7 @@ static int opPUSH_imm_bw(uint32_t fetchdat) if (tempw & 0x80) tempw |= 0xFF00; PUSH_W(tempw); - + CLOCK_CYCLES(2); PREFETCH_RUN(2, 2, -1, 0,0,1,0, 0); return cpu_state.abrt; @@ -223,7 +223,7 @@ static int opPUSH_imm_bl(uint32_t fetchdat) if (templ & 0x80) templ |= 0xFFFFFF00; PUSH_L(templ); - + CLOCK_CYCLES(2); PREFETCH_RUN(2, 2, -1, 0,0,0,1, 0); return cpu_state.abrt; @@ -232,7 +232,7 @@ static int opPUSH_imm_bl(uint32_t fetchdat) static int opPOPW_a16(uint32_t fetchdat) { uint16_t temp; - + temp = POP_W(); if (cpu_state.abrt) return 1; fetch_ea_16(fetchdat); @@ -244,18 +244,18 @@ static int opPOPW_a16(uint32_t fetchdat) if (stack32) ESP -= 2; else SP -= 2; } - - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); - else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 0); return cpu_state.abrt; } static int opPOPW_a32(uint32_t fetchdat) { uint16_t temp; - + temp = POP_W(); if (cpu_state.abrt) return 1; - + fetch_ea_32(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -265,9 +265,9 @@ static int opPOPW_a32(uint32_t fetchdat) if (stack32) ESP -= 2; else SP -= 2; } - - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); - else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 1); return cpu_state.abrt; } @@ -278,7 +278,7 @@ static int opPOPL_a16(uint32_t fetchdat) temp = POP_L(); if (cpu_state.abrt) return 1; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(temp); @@ -287,9 +287,9 @@ static int opPOPL_a16(uint32_t fetchdat) if (stack32) ESP -= 4; else SP -= 4; } - - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); - else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 0); return cpu_state.abrt; } @@ -309,8 +309,8 @@ static int opPOPL_a32(uint32_t fetchdat) else SP -= 4; } - if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); - else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + if (is486) { CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); } + else { CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); } PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 1); return cpu_state.abrt; } @@ -321,17 +321,19 @@ static int opENTER_w(uint32_t fetchdat) uint16_t offset; int count; uint32_t tempEBP, tempESP, frame_ptr; +#ifndef IS_DYNAREC int reads = 0, writes = 1, instr_cycles = 0; +#endif uint16_t tempw; offset = getwordf(); count = (fetchdat >> 16) & 0xff; cpu_state.pc++; tempEBP = EBP; tempESP = ESP; - + PUSH_W(BP); if (cpu_state.abrt) return 1; frame_ptr = ESP; - + if (count > 0) { while (--count) @@ -342,20 +344,26 @@ static int opENTER_w(uint32_t fetchdat) PUSH_W(tempw); if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } CLOCK_CYCLES((is486) ? 3 : 4); +#ifndef IS_DYNAREC reads++; writes++; instr_cycles += (is486) ? 3 : 4; +#endif } PUSH_W(frame_ptr); if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } CLOCK_CYCLES((is486) ? 3 : 5); +#ifndef IS_DYNAREC writes++; instr_cycles += (is486) ? 3 : 5; +#endif } BP = frame_ptr; - + if (stack32) ESP -= offset; else SP -= offset; CLOCK_CYCLES((is486) ? 14 : 10); +#ifndef IS_DYNAREC instr_cycles += (is486) ? 14 : 10; PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); +#endif return 0; } static int opENTER_l(uint32_t fetchdat) @@ -363,16 +371,18 @@ static int opENTER_l(uint32_t fetchdat) uint16_t offset; int count; uint32_t tempEBP, tempESP, frame_ptr; +#ifndef IS_DYNAREC int reads = 0, writes = 1, instr_cycles = 0; +#endif uint32_t templ; offset = getwordf(); count = (fetchdat >> 16) & 0xff; cpu_state.pc++; tempEBP = EBP; tempESP = ESP; - + PUSH_L(EBP); if (cpu_state.abrt) return 1; frame_ptr = ESP; - + if (count > 0) { while (--count) @@ -383,20 +393,26 @@ static int opENTER_l(uint32_t fetchdat) PUSH_L(templ); if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } CLOCK_CYCLES((is486) ? 3 : 4); +#ifndef IS_DYNAREC reads++; writes++; instr_cycles += (is486) ? 3 : 4; +#endif } PUSH_L(frame_ptr); if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } CLOCK_CYCLES((is486) ? 3 : 5); +#ifndef IS_DYNAREC writes++; instr_cycles += (is486) ? 3 : 5; +#endif } EBP = frame_ptr; - + if (stack32) ESP -= offset; else SP -= offset; CLOCK_CYCLES((is486) ? 14 : 10); +#ifndef IS_DYNAREC instr_cycles += (is486) ? 14 : 10; PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); +#endif return 0; } @@ -406,11 +422,11 @@ static int opLEAVE_w(uint32_t fetchdat) uint32_t tempESP = ESP; uint16_t temp; - SP = BP; + SP = BP; temp = POP_W(); if (cpu_state.abrt) { ESP = tempESP; return 1; } BP = temp; - + CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); return 0; @@ -420,12 +436,12 @@ static int opLEAVE_l(uint32_t fetchdat) uint32_t tempESP = ESP; uint32_t temp; - ESP = EBP; + ESP = EBP; temp = POP_L(); if (cpu_state.abrt) { ESP = tempESP; return 1; } EBP = temp; - - CLOCK_CYCLES(4); + + CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); return 0; } @@ -446,7 +462,7 @@ static int opLEAVE_l(uint32_t fetchdat) PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ return cpu_state.abrt; \ } - + #define POP_SEG_OPS(seg, realseg) \ static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ { \ @@ -469,18 +485,17 @@ static int opLEAVE_l(uint32_t fetchdat) return cpu_state.abrt; \ } - -PUSH_SEG_OPS(CS); -PUSH_SEG_OPS(DS); -PUSH_SEG_OPS(ES); -PUSH_SEG_OPS(FS); -PUSH_SEG_OPS(GS); -PUSH_SEG_OPS(SS); -POP_SEG_OPS(DS, &cpu_state.seg_ds); -POP_SEG_OPS(ES, &cpu_state.seg_es); -POP_SEG_OPS(FS, &cpu_state.seg_fs); -POP_SEG_OPS(GS, &cpu_state.seg_gs); +PUSH_SEG_OPS(CS) +PUSH_SEG_OPS(DS) +PUSH_SEG_OPS(ES) +PUSH_SEG_OPS(FS) +PUSH_SEG_OPS(GS) +PUSH_SEG_OPS(SS) +POP_SEG_OPS(DS, &cpu_state.seg_ds) +POP_SEG_OPS(ES, &cpu_state.seg_es) +POP_SEG_OPS(FS, &cpu_state.seg_fs) +POP_SEG_OPS(GS, &cpu_state.seg_gs) static int opPOP_SS_w(uint32_t fetchdat) @@ -491,7 +506,7 @@ static int opPOP_SS_w(uint32_t fetchdat) loadseg(temp_seg, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } CLOCK_CYCLES(is486 ? 3 : 7); PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); - + cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; diff --git a/src/cpu/x86_ops_string.h b/src/cpu/x86_ops_string.h index c02725138..54a22d4b8 100644 --- a/src/cpu/x86_ops_string.h +++ b/src/cpu/x86_ops_string.h @@ -2,10 +2,20 @@ static int opMOVSB_a16(uint32_t fetchdat) { uint8_t temp; + addr64 = addr64_2 = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI); + high_page = 0; + do_mmut_rb(cpu_state.ea_seg->base, SI, &addr64); + if (cpu_state.abrt) return 1; SEG_CHECK_WRITE(&cpu_state.seg_es); - temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; - writememb(es, DI, temp); if (cpu_state.abrt) return 1; + CHECK_WRITE(&cpu_state.seg_es, DI, DI); + + do_mmut_wb(es, DI, &addr64_2); + if (cpu_state.abrt) return 1; + temp = readmemb_n(cpu_state.ea_seg->base, SI, addr64); if (cpu_state.abrt) return 1; + writememb_n(es, DI, addr64_2, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) { DI--; SI--; } else { DI++; SI++; } CLOCK_CYCLES(7); @@ -16,10 +26,19 @@ static int opMOVSB_a32(uint32_t fetchdat) { uint8_t temp; + addr64 = addr64_2 = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI); + high_page = 0; + do_mmut_rb(cpu_state.ea_seg->base, ESI, &addr64); + if (cpu_state.abrt) return 1; SEG_CHECK_WRITE(&cpu_state.seg_es); - temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; - writememb(es, EDI, temp); if (cpu_state.abrt) return 1; + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI); + do_mmut_wb(es, EDI, &addr64_2); + if (cpu_state.abrt) return 1; + temp = readmemb_n(cpu_state.ea_seg->base, ESI, addr64); if (cpu_state.abrt) return 1; + writememb_n(es, EDI, addr64_2, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } else { EDI++; ESI++; } CLOCK_CYCLES(7); @@ -31,10 +50,20 @@ static int opMOVSW_a16(uint32_t fetchdat) { uint16_t temp; + addr64a[0] = addr64a[1] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 1UL); + high_page = 0; + do_mmut_rw(cpu_state.ea_seg->base, SI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_WRITE(&cpu_state.seg_es); - temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; - writememw(es, DI, temp); if (cpu_state.abrt) return 1; + CHECK_WRITE(&cpu_state.seg_es, DI, DI + 1UL); + do_mmut_ww(es, DI, addr64a_2); + if (cpu_state.abrt) return 1; + temp = readmemw_n(cpu_state.ea_seg->base, SI, addr64a); if (cpu_state.abrt) return 1; + writememw_n(es, DI, addr64a_2, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } else { DI += 2; SI += 2; } CLOCK_CYCLES(7); @@ -45,10 +74,20 @@ static int opMOVSW_a32(uint32_t fetchdat) { uint16_t temp; + addr64a[0] = addr64a[1] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 1UL); + high_page = 0; + do_mmut_rw(cpu_state.ea_seg->base, ESI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_WRITE(&cpu_state.seg_es); - temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; - writememw(es, EDI, temp); if (cpu_state.abrt) return 1; + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 1UL); + do_mmut_ww(es, EDI, addr64a_2); + if (cpu_state.abrt) return 1; + temp = readmemw_n(cpu_state.ea_seg->base, ESI, addr64a); if (cpu_state.abrt) return 1; + writememw_n(es, EDI, addr64a_2, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } else { EDI += 2; ESI += 2; } CLOCK_CYCLES(7); @@ -60,10 +99,20 @@ static int opMOVSL_a16(uint32_t fetchdat) { uint32_t temp; + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 3UL); + high_page = 0; + do_mmut_rl(cpu_state.ea_seg->base, SI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_WRITE(&cpu_state.seg_es); - temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; - writememl(es, DI, temp); if (cpu_state.abrt) return 1; + CHECK_WRITE(&cpu_state.seg_es, DI, DI + 3UL); + do_mmut_wl(es, DI, addr64a_2); + if (cpu_state.abrt) return 1; + temp = readmeml_n(cpu_state.ea_seg->base, SI, addr64a); if (cpu_state.abrt) return 1; + writememl_n(es, DI, addr64a_2, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } else { DI += 4; SI += 4; } CLOCK_CYCLES(7); @@ -74,10 +123,20 @@ static int opMOVSL_a32(uint32_t fetchdat) { uint32_t temp; + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 3UL); + high_page = 0; + do_mmut_rl(cpu_state.ea_seg->base, ESI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_WRITE(&cpu_state.seg_es); - temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; - writememl(es, EDI, temp); if (cpu_state.abrt) return 1; + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 3UL); + do_mmut_wl(es, EDI, addr64a_2); + if (cpu_state.abrt) return 1; + temp = readmeml_n(cpu_state.ea_seg->base, ESI, addr64a); if (cpu_state.abrt) return 1; + writememl_n(es, EDI, addr64a_2, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } else { EDI += 4; ESI += 4; } CLOCK_CYCLES(7); @@ -90,10 +149,23 @@ static int opCMPSB_a16(uint32_t fetchdat) { uint8_t src, dst; + addr64 = addr64_2 = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI); + high_page = uncached = 0; + do_mmut_rb(cpu_state.ea_seg->base, SI, &addr64); + if (cpu_state.abrt) return 1; SEG_CHECK_READ(&cpu_state.seg_es); - src = readmemb(cpu_state.ea_seg->base, SI); - dst = readmemb(es, DI); if (cpu_state.abrt) return 1; + CHECK_READ(&cpu_state.seg_es, DI, DI); + do_mmut_rb2(es, DI, &addr64_2); + if (cpu_state.abrt) return 1; + src = readmemb_n(cpu_state.ea_seg->base, SI, addr64); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+DI)>>12] = old_rl2; + dst = readmemb_n(es, DI, addr64_2); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+DI)>>12] = (uintptr_t) LOOKUP_INV; setsub8(src, dst); if (cpu_state.flags & D_FLAG) { DI--; SI--; } else { DI++; SI++; } @@ -105,10 +177,23 @@ static int opCMPSB_a32(uint32_t fetchdat) { uint8_t src, dst; + addr64 = addr64_2 = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI); + high_page = uncached = 0; + do_mmut_rb(cpu_state.ea_seg->base, ESI, &addr64); + if (cpu_state.abrt) return 1; SEG_CHECK_READ(&cpu_state.seg_es); - src = readmemb(cpu_state.ea_seg->base, ESI); - dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; + CHECK_READ(&cpu_state.seg_es, EDI, EDI); + do_mmut_rb2(es, EDI, &addr64_2); + if (cpu_state.abrt) return 1; + src = readmemb_n(cpu_state.ea_seg->base, ESI, addr64); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+EDI)>>12] = old_rl2; + dst = readmemb_n(es, EDI, addr64_2); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+EDI)>>12] = (uintptr_t) LOOKUP_INV; setsub8(src, dst); if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } else { EDI++; ESI++; } @@ -121,10 +206,24 @@ static int opCMPSW_a16(uint32_t fetchdat) { uint16_t src, dst; + addr64a[0] = addr64a[1] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 1UL); + high_page = uncached = 0; + do_mmut_rw(cpu_state.ea_seg->base, SI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_READ(&cpu_state.seg_es); - src = readmemw(cpu_state.ea_seg->base, SI); - dst = readmemw(es, DI); if (cpu_state.abrt) return 1; + CHECK_READ(&cpu_state.seg_es, DI, DI + 1UL); + do_mmut_rw2(es, DI, addr64a_2); + if (cpu_state.abrt) return 1; + src = readmemw_n(cpu_state.ea_seg->base, SI, addr64a); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+DI)>>12] = old_rl2; + dst = readmemw_n(es, DI, addr64a_2); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+DI)>>12] = (uintptr_t) LOOKUP_INV; setsub16(src, dst); if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } else { DI += 2; SI += 2; } @@ -136,10 +235,24 @@ static int opCMPSW_a32(uint32_t fetchdat) { uint16_t src, dst; + addr64a[0] = addr64a[1] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 1UL); + high_page = uncached = 0; + do_mmut_rw(cpu_state.ea_seg->base, ESI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_READ(&cpu_state.seg_es); - src = readmemw(cpu_state.ea_seg->base, ESI); - dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; + CHECK_READ(&cpu_state.seg_es, EDI, EDI + 1UL); + do_mmut_rw2(es, EDI, addr64a_2); + if (cpu_state.abrt) return 1; + src = readmemw_n(cpu_state.ea_seg->base, ESI, addr64a); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+EDI)>>12] = old_rl2; + dst = readmemw_n(es, EDI, addr64a_2); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+EDI)>>12] = (uintptr_t) LOOKUP_INV; setsub16(src, dst); if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } else { EDI += 2; ESI += 2; } @@ -152,10 +265,24 @@ static int opCMPSL_a16(uint32_t fetchdat) { uint32_t src, dst; + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 3UL); + high_page = uncached = 0; + do_mmut_rl(cpu_state.ea_seg->base, SI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_READ(&cpu_state.seg_es); - src = readmeml(cpu_state.ea_seg->base, SI); - dst = readmeml(es, DI); if (cpu_state.abrt) return 1; + CHECK_READ(&cpu_state.seg_es, DI, DI + 3UL); + do_mmut_rl2(es, DI, addr64a_2); + if (cpu_state.abrt) return 1; + src = readmeml_n(cpu_state.ea_seg->base, SI, addr64a); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+DI)>>12] = old_rl2; + dst = readmeml_n(es, DI, addr64a_2); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+DI)>>12] = (uintptr_t) LOOKUP_INV; setsub32(src, dst); if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } else { DI += 4; SI += 4; } @@ -167,10 +294,24 @@ static int opCMPSL_a32(uint32_t fetchdat) { uint32_t src, dst; + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; + addr64a_2[0] = addr64a_2[1] = addr64a_2[2] = addr64a_2[3] = 0x00000000; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 3UL); + high_page = uncached = 0; + do_mmut_rl(cpu_state.ea_seg->base, ESI, addr64a); + if (cpu_state.abrt) return 1; SEG_CHECK_READ(&cpu_state.seg_es); - src = readmeml(cpu_state.ea_seg->base, ESI); - dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; + CHECK_READ(&cpu_state.seg_es, EDI, EDI + 3UL); + do_mmut_rl2(es, EDI, addr64a_2); + if (cpu_state.abrt) return 1; + src = readmeml_n(cpu_state.ea_seg->base, ESI, addr64a); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+EDI)>>12] = old_rl2; + dst = readmeml_n(es, EDI, addr64a_2); if (cpu_state.abrt) return 1; + if (uncached) + readlookup2[(uint32_t)(es+EDI)>>12] = (uintptr_t) LOOKUP_INV; setsub32(src, dst); if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } else { EDI += 4; ESI += 4; } @@ -182,6 +323,7 @@ static int opCMPSL_a32(uint32_t fetchdat) static int opSTOSB_a16(uint32_t fetchdat) { SEG_CHECK_WRITE(&cpu_state.seg_es); + CHECK_WRITE(&cpu_state.seg_es, DI, DI); writememb(es, DI, AL); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) DI--; else DI++; @@ -192,6 +334,7 @@ static int opSTOSB_a16(uint32_t fetchdat) static int opSTOSB_a32(uint32_t fetchdat) { SEG_CHECK_WRITE(&cpu_state.seg_es); + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI); writememb(es, EDI, AL); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) EDI--; else EDI++; @@ -203,6 +346,7 @@ static int opSTOSB_a32(uint32_t fetchdat) static int opSTOSW_a16(uint32_t fetchdat) { SEG_CHECK_WRITE(&cpu_state.seg_es); + CHECK_WRITE(&cpu_state.seg_es, DI, DI + 1UL); writememw(es, DI, AX); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; @@ -213,6 +357,7 @@ static int opSTOSW_a16(uint32_t fetchdat) static int opSTOSW_a32(uint32_t fetchdat) { SEG_CHECK_WRITE(&cpu_state.seg_es); + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 1UL); writememw(es, EDI, AX); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; @@ -224,6 +369,7 @@ static int opSTOSW_a32(uint32_t fetchdat) static int opSTOSL_a16(uint32_t fetchdat) { SEG_CHECK_WRITE(&cpu_state.seg_es); + CHECK_WRITE(&cpu_state.seg_es, DI, DI + 3UL); writememl(es, DI, EAX); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; @@ -234,6 +380,7 @@ static int opSTOSL_a16(uint32_t fetchdat) static int opSTOSL_a32(uint32_t fetchdat) { SEG_CHECK_WRITE(&cpu_state.seg_es); + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 3UL); writememl(es, EDI, EAX); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; @@ -248,6 +395,7 @@ static int opLODSB_a16(uint32_t fetchdat) uint8_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI); temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; AL = temp; if (cpu_state.flags & D_FLAG) SI--; @@ -261,6 +409,7 @@ static int opLODSB_a32(uint32_t fetchdat) uint8_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI); temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; AL = temp; if (cpu_state.flags & D_FLAG) ESI--; @@ -275,6 +424,7 @@ static int opLODSW_a16(uint32_t fetchdat) uint16_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 1UL); temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; AX = temp; if (cpu_state.flags & D_FLAG) SI -= 2; @@ -288,6 +438,7 @@ static int opLODSW_a32(uint32_t fetchdat) uint16_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 1UL); temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; AX = temp; if (cpu_state.flags & D_FLAG) ESI -= 2; @@ -302,6 +453,7 @@ static int opLODSL_a16(uint32_t fetchdat) uint32_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 3UL); temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; EAX = temp; if (cpu_state.flags & D_FLAG) SI -= 4; @@ -315,6 +467,7 @@ static int opLODSL_a32(uint32_t fetchdat) uint32_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 3UL); temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; EAX = temp; if (cpu_state.flags & D_FLAG) ESI -= 4; @@ -330,6 +483,7 @@ static int opSCASB_a16(uint32_t fetchdat) uint8_t temp; SEG_CHECK_READ(&cpu_state.seg_es); + CHECK_READ(&cpu_state.seg_es, DI, DI); temp = readmemb(es, DI); if (cpu_state.abrt) return 1; setsub8(AL, temp); if (cpu_state.flags & D_FLAG) DI--; @@ -343,6 +497,7 @@ static int opSCASB_a32(uint32_t fetchdat) uint8_t temp; SEG_CHECK_READ(&cpu_state.seg_es); + CHECK_READ(&cpu_state.seg_es, EDI, EDI); temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; setsub8(AL, temp); if (cpu_state.flags & D_FLAG) EDI--; @@ -357,6 +512,7 @@ static int opSCASW_a16(uint32_t fetchdat) uint16_t temp; SEG_CHECK_READ(&cpu_state.seg_es); + CHECK_READ(&cpu_state.seg_es, DI, DI + 1UL); temp = readmemw(es, DI); if (cpu_state.abrt) return 1; setsub16(AX, temp); if (cpu_state.flags & D_FLAG) DI -= 2; @@ -370,6 +526,7 @@ static int opSCASW_a32(uint32_t fetchdat) uint16_t temp; SEG_CHECK_READ(&cpu_state.seg_es); + CHECK_READ(&cpu_state.seg_es, EDI, EDI + 1UL); temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; setsub16(AX, temp); if (cpu_state.flags & D_FLAG) EDI -= 2; @@ -384,6 +541,7 @@ static int opSCASL_a16(uint32_t fetchdat) uint32_t temp; SEG_CHECK_READ(&cpu_state.seg_es); + CHECK_READ(&cpu_state.seg_es, DI, DI + 3UL); temp = readmeml(es, DI); if (cpu_state.abrt) return 1; setsub32(EAX, temp); if (cpu_state.flags & D_FLAG) DI -= 4; @@ -397,6 +555,7 @@ static int opSCASL_a32(uint32_t fetchdat) uint32_t temp; SEG_CHECK_READ(&cpu_state.seg_es); + CHECK_READ(&cpu_state.seg_es, EDI, EDI + 3UL); temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; setsub32(EAX, temp); if (cpu_state.flags & D_FLAG) EDI -= 4; @@ -410,10 +569,15 @@ static int opINSB_a16(uint32_t fetchdat) { uint8_t temp; + addr64 = 0x00000000; + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); + CHECK_WRITE(&cpu_state.seg_es, DI, DI); + high_page = 0; + do_mmut_wb(es, DI, &addr64); if (cpu_state.abrt) return 1; temp = inb(DX); - writememb(es, DI, temp); if (cpu_state.abrt) return 1; + writememb_n(es, DI, addr64, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(15); @@ -424,10 +588,15 @@ static int opINSB_a32(uint32_t fetchdat) { uint8_t temp; + addr64 = 0x00000000; + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); + high_page = 0; + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI); + do_mmut_wb(es, EDI, &addr64); if (cpu_state.abrt) return 1; temp = inb(DX); - writememb(es, EDI, temp); if (cpu_state.abrt) return 1; + writememb_n(es, EDI, addr64, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(15); @@ -439,11 +608,16 @@ static int opINSW_a16(uint32_t fetchdat) { uint16_t temp; + addr64a[0] = addr64a[1] = 0x00000000; + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); + CHECK_WRITE(&cpu_state.seg_es, DI, DI + 1UL); + high_page = 0; + do_mmut_ww(es, DI, addr64a); if (cpu_state.abrt) return 1; temp = inw(DX); - writememw(es, DI, temp); if (cpu_state.abrt) return 1; + writememw_n(es, DI, addr64a, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(15); @@ -454,11 +628,16 @@ static int opINSW_a32(uint32_t fetchdat) { uint16_t temp; + addr64a[0] = addr64a[1] = 0x00000000; + SEG_CHECK_WRITE(&cpu_state.seg_es); + high_page = 0; check_io_perm(DX); check_io_perm(DX + 1); + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 1UL); + do_mmut_ww(es, EDI, addr64a); if (cpu_state.abrt) return 1; temp = inw(DX); - writememw(es, EDI, temp); if (cpu_state.abrt) return 1; + writememw_n(es, EDI, addr64a, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(15); @@ -470,13 +649,18 @@ static int opINSL_a16(uint32_t fetchdat) { uint32_t temp; + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); check_io_perm(DX + 2); check_io_perm(DX + 3); + CHECK_WRITE(&cpu_state.seg_es, DI, DI + 3UL); + high_page = 0; + do_mmut_wl(es, DI, addr64a); if (cpu_state.abrt) return 1; temp = inl(DX); - writememl(es, DI, temp); if (cpu_state.abrt) return 1; + writememl_n(es, DI, addr64a, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(15); @@ -487,13 +671,18 @@ static int opINSL_a32(uint32_t fetchdat) { uint32_t temp; + addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); check_io_perm(DX + 2); check_io_perm(DX + 3); + CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 3UL); + high_page = 0; + do_mmut_wl(es, DI, addr64a); if (cpu_state.abrt) return 1; temp = inl(DX); - writememl(es, EDI, temp); if (cpu_state.abrt) return 1; + writememl_n(es, EDI, addr64a, temp); if (cpu_state.abrt) return 1; if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(15); @@ -506,6 +695,7 @@ static int opOUTSB_a16(uint32_t fetchdat) uint8_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI); temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); if (cpu_state.flags & D_FLAG) SI--; @@ -520,6 +710,7 @@ static int opOUTSB_a32(uint32_t fetchdat) uint8_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI); temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); if (cpu_state.flags & D_FLAG) ESI--; @@ -535,6 +726,7 @@ static int opOUTSW_a16(uint32_t fetchdat) uint16_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 1UL); temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); @@ -550,6 +742,7 @@ static int opOUTSW_a32(uint32_t fetchdat) uint16_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 1UL); temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); @@ -566,6 +759,7 @@ static int opOUTSL_a16(uint32_t fetchdat) uint32_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, SI, SI + 3UL); temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); @@ -583,6 +777,7 @@ static int opOUTSL_a32(uint32_t fetchdat) uint32_t temp; SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, ESI, ESI + 3UL); temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); diff --git a/src/cpu/x86_ops_xchg.h b/src/cpu/x86_ops_xchg.h index 6a787273e..300e97f25 100644 --- a/src/cpu/x86_ops_xchg.h +++ b/src/cpu/x86_ops_xchg.h @@ -1,7 +1,7 @@ static int opXCHG_b_a16(uint32_t fetchdat) { uint8_t temp; - + fetch_ea_16(fetchdat); if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c new file mode 100644 index 000000000..e103f0247 --- /dev/null +++ b/src/cpu/x86seg.c @@ -0,0 +1,2433 @@ +/* + * 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. + * + * x86 CPU segment emulation. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" + + +uint8_t opcode2; + +int cgate16, cgate32; +int intgatesize; + +uint32_t abrt_error; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); + +void pmodeint(int num, int soft); + +#define DPL ((segdat[2] >> 13) & 3) +#define DPL2 ((segdat2[2] >> 13) & 3) +#define DPL3 ((segdat3[2] >> 13) & 3) + + +#ifdef ENABLE_X86SEG_LOG +int x86seg_do_log = ENABLE_X86SEG_LOG; + + +static void +x86seg_log(const char *fmt, ...) +{ + va_list ap; + + if (x86seg_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x86seg_log(fmt, ...) +#endif + + +static void +seg_reset(x86seg *s) +{ + s->access = 0x82; + s->ar_high = 0x10; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; + if (s == &cpu_state.seg_cs) { + if (!cpu_inited) + fatal("seg_reset(&cpu_state.seg.cs) without an initialized CPU\n"); + if (is6117) + s->base = 0x03ff0000; + else + s->base = is286 ? (cpu_16bitbus ? 0x00ff0000 : 0xffff0000) : 0x000ffff0; + s->seg = is286 ? 0xf000 : 0xffff; + } else { + s->base = 0; + s->seg = 0; + } +} + + +void +x86seg_reset() +{ + seg_reset(&cpu_state.seg_cs); + seg_reset(&cpu_state.seg_ds); + seg_reset(&cpu_state.seg_es); + seg_reset(&cpu_state.seg_fs); + seg_reset(&cpu_state.seg_gs); + seg_reset(&cpu_state.seg_ss); +} + + +void +x86_doabrt(int x86_abrt) +{ +#ifndef USE_NEW_DYNAREC + CS = oldcs; +#endif + cpu_state.pc = cpu_state.oldpc; + cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; + cpu_state.seg_cs.ar_high = 0x10; + + if (msw & 1) + pmodeint(x86_abrt, 0); + else { + uint32_t addr = (x86_abrt << 2) + idt.base; + if (stack32) { + writememw(ss, ESP - 2, cpu_state.flags); + writememw(ss, ESP - 4, CS); + writememw(ss, ESP - 6, cpu_state.pc); + ESP -= 6; + } else { + writememw(ss, ((SP - 2) & 0xffff), cpu_state.flags); + writememw(ss, ((SP - 4) & 0xffff), CS); + writememw(ss, ((SP - 6) & 0xffff), cpu_state.pc); + SP -= 6; + } + + cpu_state.flags &= ~(I_FLAG | T_FLAG); +#ifndef USE_NEW_DYNAREC + oxpc = cpu_state.pc; +#endif + cpu_state.pc = readmemw(0, addr); + loadcs(readmemw(0, addr + 2)); + return; + } + + if (cpu_state.abrt || x86_was_reset) + return; + + if (intgatesize == 16) { + if (stack32) { + writememw(ss, ESP - 2, abrt_error); + ESP -= 2; + } else { + writememw(ss, ((SP - 2) & 0xffff), abrt_error); + SP -= 2; + } + } else { + if (stack32) { + writememl(ss, ESP - 4, abrt_error); + ESP -= 4; + } else { + writememl(ss, ((SP - 4) & 0xffff), abrt_error); + SP -= 4; + } + } +} + + +void +x86gpf(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_GPF; + abrt_error = error; +} + + +void +x86gpf_expected(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_GPF | ABRT_EXPECTED; + abrt_error = error; +} + + +void +x86ss(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_SS; + abrt_error = error; +} + + +void x86ts(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_TS; + abrt_error = error; +} + + +void +x86np(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_NP; + abrt_error = error; +} + + +static void +set_stack32(int s) +{ + stack32 = s; + + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + else + cpu_cur_status &= ~CPU_STATUS_STACK32; +} + + +static void +set_use32(int u) +{ + use32 = u ? 0x300 : 0; + + if (u) + cpu_cur_status |= CPU_STATUS_USE32; + else + cpu_cur_status &= ~CPU_STATUS_USE32; +} + + +void +do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0x000f) << 16); + if (segdat[3] & 0x0080) + s->limit = (s->limit << 12) | 0xfff; + s->base = segdat[1] | ((segdat[2] & 0x00ff) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + s->ar_high = segdat[3] & 0xff; + + if (((segdat[2] & 0x1800) != 0x1000) || !(segdat[2] & (1 << 10))) { + /* Expand-down */ + s->limit_high = s->limit; + s->limit_low = 0; + } else { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } + + if (s == &cpu_state.seg_ds) { + if ((s->base == 0) && (s->limit_low == 0) && (s->limit_high == 0xffffffff)) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) { + if ((s->base == 0) && (s->limit_low == 0) && (s->limit_high == 0xffffffff)) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } +} + + +static void +do_seg_v86_init(x86seg *s) +{ + s->access = 0xe2; + s->ar_high = 0x10; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; +} + + +static void +check_seg_valid(x86seg *s) +{ + int dpl = (s->access >> 5) & 3; + int valid = 1; + x86seg *dt = (s->seg & 0x0004) ? &ldt : &gdt; + + if (((s->seg & 0xfff8UL) + 7UL) > dt->limit) + valid = 0; + + switch (s->access & 0x1f) { + case 0x10: case 0x11: case 0x12: case 0x13: /* Data segments */ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1a: case 0x1b: /* Readable non-conforming code */ + if (((s->seg & 3) > dpl) || ((CPL) > dpl)) { + valid = 0; + break; + } + break; + + case 0x1e: case 0x1f: /* Readable conforming code */ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); +} + + +static void +read_descriptor(uint32_t addr, uint16_t *segdat, uint32_t *segdat32, int override) +{ + if (override) + cpl_override = 1; + if (cpu_16bitbus) { + segdat[0] = readmemw(0, addr); + segdat[1] = readmemw(0, addr + 2); + segdat[2] = readmemw(0, addr + 4); + segdat[3] = readmemw(0, addr + 6); + } else { + segdat32[0] = readmeml(0, addr); + segdat32[1] = readmeml(0, addr + 4); + } + if (override) + cpl_override = 0; +} + + +#ifdef USE_NEW_DYNAREC +int +#else +void +#endif +loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr, *segdat32 = (uint32_t *) segdat; + int dpl; + x86seg *dt; + + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + if (!(seg & 0xfffc)) { + if (s == &cpu_state.seg_ss) { + x86ss(NULL,0); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + s->seg = 0; + s->access = 0x80; + s->ar_high = 0x10; + s->base = -1; + if (s == &cpu_state.seg_ds) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; +#ifdef USE_NEW_DYNAREC + return 0; +#else + return; +#endif + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadseg(): Bigger than LDT limit", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + dpl = (segdat[2] >> 13) & 3; + if (s == &cpu_state.seg_ss) { + if (!(seg & 0xfffc)) { + x86gpf("loadseg(): Zero stack segment", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if ((seg & 0x0003) != CPL) { + x86gpf("loadseg(): Stack segment RPL != CPL", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if (dpl != CPL) { + x86gpf("loadseg(): Stack segment DPL != CPL", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + switch ((segdat[2] >> 8) & 0x1f) { + case 0x12: case 0x13: case 0x16: case 0x17: + /* R/W */ + break; + default: + x86gpf("loadseg(): Unknown stack segment type", seg & ~3); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if (!(segdat[2] & 0x8000)) { + x86ss(NULL, seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + set_stack32((segdat[3] & 0x40) ? 1 : 0); + } else if (s != &cpu_state.seg_cs) { + x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + x86seg_log("Seg type %03X\n",segdat[2] & 0x1f00); + switch ((segdat[2] >> 8) & 0x1f) { + case 0x10: case 0x11: case 0x12: case 0x13: /* Data segments */ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1a: case 0x1b: /* Readable non-conforming code */ + if ((seg & 0x0003) > dpl) { + x86gpf("loadseg(): Normal segment RPL > DPL", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + if ((CPL) > dpl) { + x86gpf("loadseg(): Normal segment DPL < CPL", seg& 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + break; + case 0x1e: case 0x1f: /* Readable conforming code */ + break; + default: + x86gpf("loadseg(): Unknown normal segment type", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + } + + if (!(segdat[2] & 0x8000)) { + x86np("Load data seg not present", seg & 0xfffc); +#ifdef USE_NEW_DYNAREC + return 1; +#else + return; +#endif + } + s->seg = seg; + do_seg_load(s, segdat); + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + s->checked = 0; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + } else { + s->access = 0xe2; + s->ar_high = 0x10; + s->base = seg << 4; + s->seg = seg; + s->checked = 1; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) + set_stack32(0); + } + + if (s == &cpu_state.seg_ds) { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } + +#ifdef USE_NEW_DYNAREC + return cpu_state.abrt; +#endif +} + + +void +loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr, *segdat32 = (uint32_t *) segdat; + x86seg *dt; + + x86seg_log("Load CS %04X\n", seg); + + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + if (!(seg & 0xfffc)) { + x86gpf("loadcs(): Protected mode selector is zero", 0); + return; + } + + addr = seg & 0xfff8; + dt = (seg & 0x0004)? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadcs(): Protected mode selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + if (segdat[2] & 0x1000) { + /* Normal code segment */ + if (!(segdat[2] & 0x0400)) { + /* Not conforming */ + if ((seg & 3) > CPL) { + x86gpf("loadcs(): Non-conforming RPL > CPL", seg & 0xfffc); + return; + } + if (CPL != DPL) { + x86gpf("loadcs(): Non-conforming CPL != DPL", seg & 0xfffc); + return; + } + } + if (CPL < DPL) { + x86gpf("loadcs(): CPL < DPL", seg & ~3); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x40); + CS = (seg & 0xfffc) | CPL; + do_seg_load(&cpu_state.seg_cs, segdat); + use32 = (segdat[3] & 0x40) ? 0x300 : 0; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x0100); /* Set accessed bit */ + cpl_override = 0; + } else { + /* System segment */ + if (!(segdat[2] & 0x8000)) { + x86np("Load CS system seg not present", seg & 0xfffc); + return; + } + switch (segdat[2] & 0x0f00) { + default: + x86gpf("Load CS system segment has bits 0-3 of access rights set", seg & 0xfffc); + return; + } + } + } else { + cpu_state.seg_cs.base = (seg << 4); + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.seg = seg & 0xffff; + cpu_state.seg_cs.access = (cpu_state.eflags & VM_FLAG) ? 0xe2 : 0x82; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + } +} + + +void +loadcsjmp(uint16_t seg, uint32_t old_pc) +{ + uint16_t type, seg2; + uint16_t segdat[4]; + uint32_t addr, newpc; + uint32_t *segdat32 = (uint32_t *) segdat; + x86seg *dt; + + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + if (!(seg & 0xfffc)) { + x86gpf("loadcsjmp(): Selector is zero", 0); + return; + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loacsjmp(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + x86seg_log("%04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + if (segdat[2] & 0x1000) { + /* Normal code segment */ + if (!(segdat[2] & 0x0400)) { + /* Not conforming */ + if ((seg & 0x0003) > CPL) { + x86gpf("loadcsjmp(): segment PL > CPL", seg & 0xfffc); + return; + } + if (CPL != DPL) { + x86gpf("loadcsjmp(): CPL != DPL", seg & 0xfffc); + return; + } + } + if (CPL < DPL) { + x86gpf("loadcsjmp(): CPL < DPL",seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x0040); + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x0100); /* Set accessed bit */ + cpl_override = 0; + + CS = (seg & 0xfffc) | CPL; + segdat[2] = (segdat[2] & ~(3 << 13)) | (CPL << 13); + + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + cycles -= timing_jmp_pm; + } else { /* System segment */ + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP system selector not present", seg & 0xfffc); + return; + } + type = segdat[2] & 0x0f00; + newpc = segdat[0]; + if (type & 0x0800) + newpc |= (segdat[3] << 16); + switch (type) { + case 0x0400: /* Call gate */ + case 0x0c00: + cgate32 = (type & 0x0800); + cgate16 = !cgate32; +#ifndef USE_NEW_DYNAREC + oldcs=CS; +#endif + cpu_state.oldpc = cpu_state.pc; + if (DPL < CPL) { + x86gpf("loadcsjmp(): Call gate DPL < CPL",seg & 0xfffc); + return; + } + if (DPL < (seg & 0x0003)) { + x86gpf("loadcsjmp(): Call gate DPL< RPL",seg&~3); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP call gate not present", seg & 0xfffc); + return; + } + seg2 = segdat[1]; + + if (!(seg2 & 0xfffc)) { + x86gpf("Load CS JMP call gate selector is NULL", 0); + return; + } + addr = seg2 & 0xfff8; + dt = (seg2 & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadcsjmp(): Call gate selector > DT limit", seg2 & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + + if (DPL > CPL) { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2 & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS JMP from call gate not present", seg2 & 0xfffc); + return; + } + + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if (DPL > CPL) { + x86gpf("loadcsjmp(): Non-conforming DPL > CPL", seg2 & 0xfffc); + return; + } + /*FALLTHROUGH*/ + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + break; + + default: + x86gpf("loadcsjmp(): Unknown type", seg2 & 0xfffc); + return; + } + cycles -= timing_jmp_pm_gate; + break; + + case 0x100: /* 286 Task gate */ + case 0x900: /* 386 Task gate */ + cpu_state.pc = old_pc; + optype = JMP; + cpl_override = 1; + taskswitch286(seg,segdat,segdat[2] & 0x800); + cpu_state.flags &= ~NT_FLAG; + cpl_override=0; + return; + + default: + x86gpf("Load CS JMP call gate selector unknown type", 0); + return; + } + } + } else { + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.seg = seg; + cpu_state.seg_cs.access = (cpu_state.eflags & VM_FLAG) ? 0xe2 : 0x82; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + cycles -= timing_jmp_rm; + } +} + + +void +PUSHW(uint16_t v) +{ + if (stack32) { + writememw(ss, ESP - 2, v); + if (cpu_state.abrt) + return; + ESP -= 2; + } else { + writememw(ss, ((SP - 2) & 0xffff), v); + if (cpu_state.abrt) + return; + SP -= 2; + } +} + + +void +PUSHL(uint32_t v) +{ + if (cpu_16bitbus) { + PUSHW(v >> 16); + PUSHW(v & 0xffff); + } else { + if (stack32) { + writememl(ss, ESP - 4, v); + if (cpu_state.abrt) + return; + ESP -= 4; + } else { + writememl(ss, ((SP - 4) & 0xffff), v); + if (cpu_state.abrt) + return; + SP -= 4; + } + } +} + + +uint16_t +POPW() +{ + uint16_t tempw; + if (stack32) { + tempw = readmemw(ss, ESP); + if (cpu_state.abrt) + return 0; + ESP += 2; + } else { + tempw = readmemw(ss, SP); + if (cpu_state.abrt) + return 0; + SP += 2; + } + return tempw; +} + + +uint32_t +POPL() +{ + uint32_t templ; + + if (cpu_16bitbus) { + templ = POPW(); + templ |= (POPW() << 16); + } else { + if (stack32) { + templ = readmeml(ss, ESP); + if (cpu_state.abrt) + return 0; + ESP += 4; + } else { + templ = readmeml(ss, SP); + if (cpu_state.abrt) + return 0; + SP += 4; + } + } + + return templ; +} + + +#ifdef USE_NEW_DYNAREC +void loadcscall(uint16_t seg, uint32_t old_pc) +#else +void loadcscall(uint16_t seg) +#endif +{ + uint16_t seg2, newss; + uint16_t segdat[4], segdat2[4]; + uint32_t addr, oldssbase = ss; + uint32_t oaddr, newpc; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + int count, type; + uint32_t oldss, oldsp, newsp, oldsp2; + uint16_t tempw; + x86seg *dt; + + if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) { + x86seg_log("Protected mode CS load! %04X\n", seg); + if (!(seg & 0xfffc)) { + x86gpf("loadcscall(): Protected mode selector is zero",0); + return; + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadcscall(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + type = segdat[2] & 0x0f00; + newpc = segdat[0]; + if (type & 0x0800) + newpc |= segdat[3] << 16; + + x86seg_log("Code seg call - %04X - %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2]); + if (segdat[2] & 0x1000) { + if (!(segdat[2] & 0x0400)) { /* Not conforming */ + if ((seg & 0x0003) > CPL) { + x86gpf("loadcscall(): Non-conforming RPL > CPL", seg & 0xfffc); + return; + } + if (CPL != DPL) { + x86gpf("loadcscall(): Non-conforming CPL != DPL", seg & 0xfffc); + return; + } + } + if (CPL < DPL) { + x86gpf("loadcscall(): CPL < DPL", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Load CS call not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x0040); + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + /* Conforming segments don't change CPL, so preserve existing CPL */ + if (segdat[2] & 0x0400) { + seg = (seg & 0xfffc) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } else /* On non-conforming segments, set RPL = CPL */ + seg = (seg & 0xfffc) | CPL; + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif +#ifdef ENABLE_X86SEG_LOG + x86seg_log("Complete\n"); +#endif + cycles -= timing_call_pm; + } else { + type = segdat[2] & 0x0f00; + x86seg_log("Type %03X\n", type); + switch (type) { + case 0x0400: /* Call gate */ + case 0x0c00: /* 386 Call gate */ + x86seg_log("Callgate %08X\n", cpu_state.pc); + cgate32 = (type & 0x0800); + cgate16 = !cgate32; +#ifndef USE_NEW_DYNAREC + oldcs = CS; +#endif + count = segdat[2] & 0x001f; + if (DPL < CPL) { + x86gpf("loadcscall(): ex DPL < CPL",seg & 0xfffc); + return; + } + if (DPL < (seg & 0x0003)) { + x86gpf("loadcscall(): ex DPL < RPL", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86np("Call gate not present", seg & 0xfffc); + return; + } + seg2 = segdat[1]; + + x86seg_log("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2 & 0xfffc)) { + x86gpf("loadcscall(): ex selector is NULL", 0); + return; + } + addr = seg2 & 0xfff8; + dt = (seg2 & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("loadcscall(): ex Selector > DT limit", seg2 & 0xfff8); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) + return; + + x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n", seg2, segdat[0], segdat[1], segdat[2]); + + if (DPL > CPL) { + x86gpf("loadcscall(): ex DPL > CPL", seg2 & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + x86seg_log("Call gate CS not present %04X\n", seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if (DPL < CPL) { +#ifdef USE_NEW_DYNAREC + uint16_t oldcs = CS; +#endif + oaddr = addr; + /* Load new stack */ + oldss = SS; + oldsp = oldsp2 = ESP; + cpl_override = 1; + if (tr.access & 8) { + addr = 4 + tr.base + (DPL << 3); + newss = readmemw(0, addr + 4); + if (cpu_16bitbus) { + newsp = readmemw(0, addr); + newsp |= (readmemw(0, addr + 2) << 16); + } else + newsp = readmeml(0, addr); + } else { + addr = 2 + tr.base + (DPL * 4); + newss = readmemw(0, addr + 2); + newsp = readmemw(0, addr); + } + cpl_override = 0; + if (cpu_state.abrt) + return; + x86seg_log("New stack %04X:%08X\n", newss, newsp); + if (!(newss & 0xfffc)) { + x86ts(NULL, newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + fatal("Bigger than DT limit %04X %08X %04X CSC SS\n", newss, addr, dt->limit); + x86ts(NULL, newss & ~3); + return; + } + addr += dt->base; + x86seg_log("Read stack seg\n"); + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + x86seg_log("Read stack seg done!\n"); + if (((newss & 0x0003) != DPL) || (DPL2 != DPL)) { + x86ts(NULL, newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + x86ts("Call gate loading SS unknown type", newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + x86ss("Call gate loading SS not present", newss & 0xfffc); + return; + } + if (!stack32) + oldsp &= 0xffff; + SS = newss; + set_stack32((segdat2[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + + do_seg_load(&cpu_state.seg_ss, segdat2); + + x86seg_log("Set access 1\n"); + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + cpu_state.pc = newpc; + + x86seg_log("Set access 2\n"); + + cpl_override = 1; + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + x86seg_log("Type %04X\n", type); + if (type == 0x0c00) { + PUSHL(oldss); + PUSHL(oldsp2); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + if (count) { + while (count--) { + PUSHL(readmeml(oldssbase, oldsp + (count << 2))); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + } + } + } else { + x86seg_log("Stack %04X\n", SP); + PUSHW(oldss); + x86seg_log("Write SS to %04X:%04X\n", SS, SP); + PUSHW(oldsp2); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + x86seg_log("Write SP to %04X:%04X\n", SS, SP); + if (count) { + while (count--) { + tempw = readmemw(oldssbase, (oldsp & 0xffff) + (count << 1)); + x86seg_log("PUSH %04X\n", tempw); + PUSHW(tempw); + if (cpu_state.abrt) { + SS = oldss; + ESP = oldsp2; +#ifdef USE_NEW_DYNAREC + CS = oldcs; +#endif + return; + } + } + } + } + cycles -= timing_call_pm_gate_inner; + break; + } else if (DPL > CPL) { + x86gpf("loadcscall(): Call PM Gate Inner DPL > CPL",seg2 & 0xfffc); + return; + } + /*FALLTHROUGH*/ + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + CS = seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + cpu_state.pc = newpc; + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + cycles -= timing_call_pm_gate; + break; + + default: + x86gpf("loadcscall(): Unknown subtype", seg2 & 0xfffc); + return; + } + break; + + case 0x0100: /* 286 Task gate */ + case 0x0900: /* 386 Task gate */ +#ifdef USE_NEW_DYNAREC + cpu_state.pc = old_pc; +#else + cpu_state.pc = oxpc; +#endif + cpl_override = 1; + taskswitch286(seg, segdat, segdat[2] & 0x0800); + cpl_override = 0; + break; + + default: + x86gpf("loadcscall(): Unknown type", seg & 0xfffc); + return; + } + } + } else { + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.seg = seg; + cpu_state.seg_cs.access = (cpu_state.eflags & VM_FLAG) ? 0xe2 : 0x82; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + } +} + + +void +pmoderetf(int is32, uint16_t off) +{ + uint16_t segdat[4], segdat2[4], seg,newss; + uint32_t newpc, newsp, addr, oaddr; + uint32_t oldsp = ESP; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + x86seg *dt; + + x86seg_log("RETF %i %04X:%04X %08X %04X\n", is32, CS, cpu_state.pc, cr0, cpu_state.eflags); + if (is32) { + newpc = POPL(); + seg = POPL(); + } else { + x86seg_log("PC read from %04X:%04X\n", SS, SP); + newpc = POPW(); + x86seg_log("CS read from %04X:%04X\n", SS, SP); + seg = POPW(); + } + if (cpu_state.abrt) + return; + + x86seg_log("Return to %04X:%08X\n", seg, newpc); + if ((seg & 0x0003) < CPL) { + ESP = oldsp; + x86gpf("pmoderetf(): seg < CPL", seg & 0xfffc); + return; + } + if (!(seg & 0xfffc)) { + x86gpf("pmoderetf(): seg is NULL", 0); + return; + } + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("pmoderetf(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + oaddr = addr; + + x86seg_log("CPL %i RPL %i %i\n", CPL, seg & 0x0003, is32); + + if (stack32) + ESP += off; + else + SP += off; + + if (CPL == (seg & 0x0003)) { + x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if (CPL != DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Non-conforming CPL != DPL", seg & 0xfffc); + return; + } + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if (CPL < DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Conforming CPL < DPL", seg & 0xfffc); + return; + } + break; + default: + x86gpf("pmoderetf(): Unknown type", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + ESP = oldsp; + x86np("RETF CS not present", seg & 0xfffc); + return; + } + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + cpu_state.pc = newpc; + if (segdat[2] & 0x0400) + segdat[2] = (segdat[2] & ~(3 << 13)) | ((seg & 3) << 13); + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + + cycles -= timing_retf_pm; + } else { + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if ((seg & 0x0003) != DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Non-conforming RPL != DPL", seg & 0xfffc); + return; + } + x86seg_log("RETF non-conforming, %i %i\n", seg & 0x0003, DPL); + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if ((seg & 0x0003) < DPL) { + ESP = oldsp; + x86gpf("pmoderetf(): Conforming RPL < DPL", seg & 0xfffc); + return; + } + x86seg_log("RETF conforming, %i %i\n", seg & 0x0003, DPL); + break; + default: + ESP = oldsp; + x86gpf("pmoderetf(): Unknown type", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + ESP = oldsp; + x86np("RETF CS not present", seg & 0xfffc); + return; + } + if (is32) { + newsp = POPL(); + newss = POPL(); + if (cpu_state.abrt) + return; + } else { + x86seg_log("SP read from %04X:%04X\n", SS, SP); + newsp = POPW(); + x86seg_log("SS read from %04X:%04X\n", SS, SP); + newss = POPW(); + if (cpu_state.abrt) + return; + } + x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss & 0xfffc)) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS selector is zero",newss&~3); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS selector > DT limit", newss & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); + if ((newss & 0x0003) != (seg & 0x0003)) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS RPL > CS RPL", newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS unknown type", newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + ESP = oldsp; + x86np("RETF loading SS not present", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) { + ESP = oldsp; + x86gpf("pmoderetf(): New SS DPL != CS RPL",newss & 0xfffc); + return; + } + SS = newss; + set_stack32((segdat2[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + /* Conforming segments don't change CPL, so CPL = RPL */ + if (segdat[2] & 0x0400) + segdat[2] = (segdat[2] & ~(3 << 13)) | ((seg & 3) << 13); + cpu_state.pc = newpc; + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + + if (stack32) + ESP += off; + else + SP += off; + + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); + cycles -= timing_retf_pm_outer; + } +} + + +void +pmodeint(int num, int soft) +{ + uint16_t segdat[4], segdat2[4]; + uint16_t segdat3[4]; + uint16_t newss, seg = 0; + int type, new_cpl; + uint32_t addr, oaddr; + uint32_t oldss, oldsp; + uint32_t newsp; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + uint32_t *segdat332 = (uint32_t *) segdat3; + x86seg *dt; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL != 3) && soft) { + x86seg_log("V86 banned int\n"); + x86gpf("pmodeint(): V86 banned int", 0); + return; + } + addr = (num << 3); + if ((addr + 7) > idt.limit) { + if (num == 0x08) { + /* Triple fault - reset! */ + softresetx86(); + cpu_set_edx(); + } else if (num == 0x0d) + pmodeint(8, 0); + else + x86gpf("pmodeint(): Vector > IDT limit", (num << 3) + 2 + !soft); + x86seg_log("addr >= IDT.limit\n"); + return; + } + addr += idt.base; + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) { + x86seg_log("Abrt reading from %08X\n", addr); + return; + } + oaddr = addr; + + x86seg_log("Addr %08X seg %04X %04X %04X %04X\n", addr, segdat[0], segdat[1], segdat[2], segdat[3]); + if (!(segdat[2] & 0x1f00)) { + /* This fires on all V86 interrupts in EMM386. Mark as expected to prevent code churn */ + if (cpu_state.eflags & VM_FLAG) + x86gpf_expected("pmodeint(): Expected vector descriptor with bad type", (num << 3) + 2); + else + x86gpf("pmodeint(): Vector descriptor with bad type", (num << 3) + 2); + return; + } + if ((DPL < CPL) && soft) { + x86gpf("pmodeint(): Vector DPL < CPL", (num << 3) + 2); + return; + } + type = segdat[2] & 0x1f00; + if (((type == 0x0e00) || (type == 0x0f00)) && !is386) { + x86gpf("pmodeint(): Gate type illegal on 286", seg & 0xfffc); + return; + } + switch (type) { + case 0x0600: case 0x0700: case 0x0e00: case 0x0f00: /* Interrupt and trap gates */ + intgatesize = (type >= 0x0800) ? 32 : 16; + if (!(segdat[2] & 0x8000)) { + x86np("Int gate not present", (num << 3) | 2); + return; + } + seg = segdat[1]; + new_cpl = seg & 0x0003; + + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("pmodeint(): Interrupt or trap gate selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + oaddr = addr; + + if (DPL2 > CPL) { + x86gpf("pmodeint(): Interrupt or trap gate DPL > CPL", seg & 0xfffc); + return; + } + switch (segdat2[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if (DPL2 < CPL) { + if (!(segdat2[2] & 0x8000)) { + x86np("Int gate CS not present", segdat[1] & 0xfffc); + return; + } + if ((cpu_state.eflags & VM_FLAG) && DPL2) { + x86gpf("pmodeint(): Interrupt or trap gate non-zero DPL in V86 mode", segdat[1] & 0xfffc); + return; + } + /* Load new stack */ + oldss = SS; + oldsp = ESP; + cpl_override = 1; + if (tr.access & 8) { + addr = 4 + tr.base + (DPL2 << 3); + newss = readmemw(0, addr + 4); + newsp = readmeml(0, addr); + } else { + addr = 2 + tr.base + (DPL2 << 2); + newss = readmemw(0, addr + 2); + newsp = readmemw(0, addr); + } + cpl_override = 0; + if (!(newss & 0xfffc)) { + x86ss("pmodeint(): Interrupt or trap gate stack segment is NULL", newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86ss("pmodeint(): Interrupt or trap gate stack segment > DT", newss & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat3, segdat332, 1); + if (cpu_state.abrt) + return; + if ((newss & 3) != DPL2) { + x86ss("pmodeint(): Interrupt or trap gate tack segment RPL > DPL",newss & 0xfffc); + return; + } + if (DPL3 != DPL2) { + x86ss("pmodeint(): Interrupt or trap gate tack segment DPL > DPL",newss & 0xfffc); + return; + } + if ((segdat3[2] & 0x1a00) != 0x1200) { + x86ss("pmodeint(): Interrupt or trap gate stack segment bad type", newss & 0xfffc); + return; + } + if (!(segdat3[2] & 0x8000)) { + x86np("Int gate loading SS not present", newss & 0xfffc); + return; + } + SS = newss; + set_stack32((segdat3[3] & 0x0040) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + do_seg_load(&cpu_state.seg_ss, segdat3); + + cpl_override = 1; + writememw(0, addr + 4, segdat3[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + x86seg_log("New stack %04X:%08X\n", SS, ESP); + cpl_override = 1; + if (type >= 0x0800) { + if (cpu_state.eflags & VM_FLAG) { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); + if (cpu_state.abrt) + return; + loadseg(0, &cpu_state.seg_ds); + loadseg(0, &cpu_state.seg_es); + loadseg(0, &cpu_state.seg_fs); + loadseg(0, &cpu_state.seg_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); + if (cpu_state.abrt) + return; + } else { + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); + if (cpu_state.abrt) + return; + } + cpl_override = 0; + cpu_state.seg_cs.access = 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; + break; + } else if (DPL2 != CPL) { + x86gpf("pmodeint(): DPL != CPL", seg & 0xfffc); + return; + } + /*FALLTHROUGH*/ + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if (!(segdat2[2] & 0x8000)) { + x86np("Int gate CS not present", segdat[1] & 0xfffc); + return; + } + if ((cpu_state.eflags & VM_FLAG) && (DPL2 < CPL)) { + x86gpf("pmodeint(): DPL < CPL in V86 mode", seg &~ 0xfffc); + return; + } + if (type > 0x0800) { + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); + if (cpu_state.abrt) + return; + } else { + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); + if (cpu_state.abrt) + return; + } + new_cpl = CS & 3; + break; + default: + x86gpf("pmodeint(): Unknown type", seg & 0xfffc); + return; + } + do_seg_load(&cpu_state.seg_cs, segdat2); + CS = (seg & 0xfffc) | new_cpl; + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x60) | (new_cpl << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + if (type > 0x0800) + cpu_state.pc = segdat[0] | (segdat[3] << 16); + else + cpu_state.pc = segdat[0]; + set_use32(segdat2[3] & 0x40); + + cpl_override = 1; + writememw(0, oaddr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + + cpu_state.eflags &= ~VM_FLAG; + cpu_cur_status &= ~CPU_STATUS_V86; + if (!(type & 0x100)) + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~(T_FLAG | NT_FLAG); + cycles -= timing_int_pm; + break; + + case 0x500: /* Task gate */ + seg = segdat[1]; + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86gpf("pmodeint(): Task gate selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) + return; + if (!(segdat2[2] & 0x8000)) { + x86np("Int task gate not present", segdat[1] & 0xfffc); + return; + } + optype = OPTYPE_INT; + cpl_override = 1; + taskswitch286(seg, segdat2, segdat2[2] & 0x0800); + cpl_override = 0; + break; + + default: + x86gpf("Protected mode interrupt unknown type", seg & 0xfffc); + return; + } +} + + +void +pmodeiret(int is32) +{ + uint16_t newss, seg = 0; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint32_t tempflags, flagmask; + uint32_t newpc, newsp; + uint32_t addr, oaddr; + uint32_t oldsp = ESP; + uint32_t *segdat32 = (uint32_t *) segdat; + uint32_t *segdat232 = (uint32_t *) segdat2; + x86seg *dt; + + if (is386 && (cpu_state.eflags & VM_FLAG)) { + if (IOPL != 3) { + x86gpf("Protected mode IRET: IOPL != 3", 0); + return; + } +#ifndef USE_NEW_DYNAREC + oxpc = cpu_state.pc; +#endif + if (is32) { + newpc = POPL(); + seg = POPL(); + tempflags = POPL(); + } else { + newpc = POPW(); + seg = POPW(); + tempflags = POPW(); + } + if (cpu_state.abrt) + return; + + cpu_state.pc = newpc; + cpu_state.seg_cs.base= seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.access |= 0x80; + cpu_state.seg_cs.ar_high = 0x10; + CS = seg; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xcfd5) | 2; + cycles -= timing_iret_rm; + return; + } + + if (cpu_state.flags & NT_FLAG) { + seg = readmemw(tr.base, 0); + addr = seg & 0xfff8; + if (seg & 0x0004) { + x86seg_log("TS LDT %04X %04X IRET\n", seg, gdt.limit); + x86ts("pmodeiret(): Selector points to LDT", seg & 0xfffc); + return; + } else { + if ((addr + 7) > gdt.limit) { + x86ts(NULL,seg & 0xfffc); + return; + } + addr += gdt.base; + } + cpl_override = 1; + read_descriptor(addr, segdat, segdat32, 1); + taskswitch286(seg, segdat,segdat[2] & 0x0800); + cpl_override = 0; + return; + } + +#ifndef USE_NEW_DYNAREC + oxpc=cpu_state.pc; +#endif + flagmask = 0xffff; + if (CPL != 0) + flagmask &= ~0x3000; + if (IOPL < CPL) + flagmask &= ~0x200; + if (is32) { + newpc = POPL(); + seg = POPL(); + tempflags = POPL(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + if (is386 && ((tempflags >> 16) & VM_FLAG)) { + newsp = POPL(); + newss = POPL(); + segs[0] = POPL(); + segs[1] = POPL(); + segs[2] = POPL(); + segs[3] = POPL(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + cpu_state.eflags = tempflags >> 16; + cpu_cur_status |= CPU_STATUS_V86; + loadseg(segs[0], &cpu_state.seg_es); + do_seg_v86_init(&cpu_state.seg_es); + loadseg(segs[1], &cpu_state.seg_ds); + do_seg_v86_init(&cpu_state.seg_ds); + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + loadseg(segs[2], &cpu_state.seg_fs); + do_seg_v86_init(&cpu_state.seg_fs); + loadseg(segs[3], &cpu_state.seg_gs); + do_seg_v86_init(&cpu_state.seg_gs); + + cpu_state.pc = newpc & 0xffff; + cpu_state.seg_cs.base = seg << 4; + cpu_state.seg_cs.limit = 0xffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + CS = seg; + cpu_state.seg_cs.access = 0xe2; + cpu_state.seg_cs.ar_high = 0x10; + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + + ESP = newsp; + loadseg(newss, &cpu_state.seg_ss); + do_seg_v86_init(&cpu_state.seg_ss); + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + use32 = 0; + cpu_cur_status &= ~CPU_STATUS_USE32; + cpu_state.flags = (tempflags & 0xffd5) | 2; + cycles -= timing_iret_v86; + return; + } + } else { + newpc = POPW(); + seg = POPW(); + tempflags = POPW(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + } + if (!(seg & 0xfffc)) { + ESP = oldsp; + x86gpf("pmodeiret(): Selector is NULL", 0); + return; + } + + addr = seg & 0xfff8; + dt = (seg & 0x0004) ? & ldt : &gdt; + if ((addr + 7) > dt->limit) { + ESP = oldsp; + x86gpf("pmodeiret(): Selector > DT limit", seg & 0xfffc); + return; + } + addr += dt->base; + if ((seg & 0x0003) < CPL) { + ESP = oldsp; + x86gpf("pmodeiret(): RPL < CPL", seg & 0xfffc); + return; + } + read_descriptor(addr, segdat, segdat32, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + + switch (segdat[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming code */ + if ((seg & 0x0003) != DPL) { + ESP = oldsp; + x86gpf("pmodeiret(): Non-conforming RPL != DPL", seg & 0xfffc); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /* Conforming code */ + if ((seg & 0x0003) < DPL) { + ESP = oldsp; + x86gpf("pmodeiret(): Conforming RPL < DPL",seg&~3); + return; + } + break; + default: + ESP = oldsp; + x86gpf("pmodeiret(): Unknown type", seg & 0xfffc); + return; + } + if (!(segdat[2] & 0x8000)) { + ESP = oldsp; + x86np("IRET CS not present", seg & 0xfffc); + return; + } + if ((seg & 0x0003) == CPL) { + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x60) | ((CS & 0x0003) << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x0040); + + cpl_override = 1; + writememw(0, addr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + cycles -= timing_iret_pm; + } else { /* Return to outer level */ + oaddr = addr; + x86seg_log("Outer level\n"); + if (is32) { + newsp = POPL(); + newss = POPL(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + } else { + newsp = POPW(); + newss = POPW(); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + } + + x86seg_log("IRET load stack %04X:%04X\n", newss, newsp); + + if (!(newss & 0xfffc)) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS selector is zero", newss & 0xfffc); + return; + } + addr = newss & 0xfff8; + dt = (newss & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS selector > DT limit", newss & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 1); + if (cpu_state.abrt) { + ESP = oldsp; + return; + } + if ((newss & 3) != (seg & 3)) { + SP = oldsp; + x86gpf("pmodeiret(): New SS RPL > CS RPL",newss & 0xfffc); + return; + } + if ((segdat2[2] & 0x1a00) != 0x1200) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS bad type", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 0x0003)) { + ESP = oldsp; + x86gpf("pmodeiret(): New SS DPL != CS RPL",newss & 0xfffc); + return; + } + if (!(segdat2[2] & 0x8000)) { + ESP = oldsp; + x86np("IRET loading SS not present", newss & 0xfffc); + return; + } + SS = newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) + ESP = newsp; + else + SP = newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + + cpl_override = 1; + writememw(0, addr + 4, segdat2[2] | 0x100); /* Set accessed bit */ + writememw(0, oaddr + 4, segdat[2] | 0x100); /* Set accessed bit */ + cpl_override = 0; + /* Conforming segments don't change CPL, so CPL = RPL */ + if (segdat[2] & 0x0400) + segdat[2] = (segdat[2] & ~(3 << 13)) | ((seg & 3) << 13); + + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x60) | ((CS & 3) << 5); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat[3] & 0x40); + + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); + cycles -= timing_iret_pm_outer; + } + cpu_state.pc = newpc; + cpu_state.flags = (cpu_state.flags &~ flagmask) | (tempflags & flagmask & 0xffd5) | 2; + if (is32) + cpu_state.eflags = tempflags >> 16; +} + + +void +taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint16_t tempw, new_ldt; + uint16_t new_es, new_cs, new_ss, new_ds, new_fs, new_gs; + uint16_t segdat2[4]; + uint32_t base, limit; + uint32_t templ, new_cr3 = 0; + uint32_t new_eax, new_ebx, new_ecx, new_edx, new_esp, new_ebp; + uint32_t new_esi, new_edi, new_pc, new_flags, addr; + uint32_t *segdat232 = (uint32_t *) segdat2; + x86seg *dt; + + base = segdat[1] | ((segdat[2] & 0x00ff) << 16); + limit = segdat[0]; + if (is386) { + base |= (segdat[3] >> 8) << 24; + limit |= (segdat[3] & 0x000f) << 16; + } + + if (is32) { + if (limit < 103) { + x86ts("taskswitch286(): limit < 103", seg); + return; + } + + if ((optype == JMP) || (optype == CALL) || (optype == OPTYPE_INT)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw |= 0x0200; + if (tr.seg & 0x0004) + writememw(ldt.base, (seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; + + if (optype == IRET) + cpu_state.flags &= ~NT_FLAG; + + cpu_386_flags_rebuild(); + writememl(tr.base, 0x1C, cr3); + writememl(tr.base, 0x20, cpu_state.pc); + writememl(tr.base, 0x24, cpu_state.flags | (cpu_state.eflags << 16)); + + writememl(tr.base, 0x28, EAX); + writememl(tr.base, 0x2C, ECX); + writememl(tr.base, 0x30, EDX); + writememl(tr.base, 0x34, EBX); + writememl(tr.base, 0x38, ESP); + writememl(tr.base, 0x3C, EBP); + writememl(tr.base, 0x40, ESI); + writememl(tr.base, 0x44, EDI); + + writememl(tr.base, 0x48, ES); + writememl(tr.base, 0x4C, CS); + writememl(tr.base, 0x50, SS); + writememl(tr.base, 0x54, DS); + writememl(tr.base, 0x58, FS); + writememl(tr.base, 0x5C, GS); + + if ((optype == JMP) || (optype == IRET)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (tr.seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (tr.seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw &= ~0x0200; + if (tr.seg & 0x0004) + writememw(ldt.base, (tr.seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (tr.seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; + + if ((optype == OPTYPE_INT) || (optype == CALL)) { + writememl(base, 0, tr.seg); + if (cpu_state.abrt) + return; + } + + new_cr3 = readmeml(base, 0x1C); + new_pc = readmeml(base, 0x20); + new_flags = readmeml(base, 0x24); + if ((optype == OPTYPE_INT) || (optype == CALL)) + new_flags |= NT_FLAG; + + new_eax = readmeml(base, 0x28); + new_ecx = readmeml(base, 0x2C); + new_edx = readmeml(base, 0x30); + new_ebx = readmeml(base, 0x34); + new_esp = readmeml(base, 0x38); + new_ebp = readmeml(base, 0x3C); + new_esi = readmeml(base, 0x40); + new_edi = readmeml(base, 0x44); + + new_es = readmemw(base, 0x48); + new_cs = readmemw(base, 0x4C); + new_ss = readmemw(base, 0x50); + new_ds = readmemw(base, 0x54); + new_fs = readmemw(base, 0x58); + new_gs = readmemw(base, 0x5C); + new_ldt = readmemw(base, 0x60); + + cr0 |= 8; + + cr3 = new_cr3; + flushmmucache(); + + cpu_state.pc = new_pc; + cpu_state.flags = new_flags; + cpu_state.eflags = new_flags >> 16; + cpu_386_flags_extract(); + + ldt.seg = new_ldt; + templ = (ldt.seg & ~7) + gdt.base; + ldt.limit = readmemw(0, templ); + if (readmemb(0, templ + 6) & 0x80) { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = (readmemw(0, templ + 2)) | (readmemb(0, templ + 4) << 16) | (readmemb(0, templ + 7) << 24); + + if (cpu_state.eflags & VM_FLAG) { + loadcs(new_cs); + set_use32(0); + cpu_cur_status |= CPU_STATUS_V86; + } else { + if (!(new_cs & 0xfffc)) { + x86ts("taskswitch286(): New CS selector is null", 0); + return; + } + addr = new_cs & 0xfff8; + dt = (new_cs & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86ts("taskswitch286(): New CS selector > DT limit", new_cs & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 0); + if (!(segdat2[2] & 0x8000)) { + x86np("TS loading CS not present", new_cs & 0xfffc); + return; + } + switch (segdat2[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if ((new_cs & 0x0003) != DPL2) { + x86ts("TS loading CS RPL != DPL2", new_cs & 0xfffc); + return; + } + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if ((new_cs & 0x0003) < DPL2) { + x86ts("TS loading CS RPL < DPL2", new_cs & 0xfffc); + return; + } + break; + default: + x86ts("TS loading CS unknown type", new_cs & 0xfffc); + return; + } + + CS = new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(segdat2[3] & 0x0040); + cpu_cur_status &= ~CPU_STATUS_V86; + } + + EAX = new_eax; + ECX = new_ecx; + EDX = new_edx; + EBX = new_ebx; + ESP = new_esp; + EBP = new_ebp; + ESI = new_esi; + EDI = new_edi; + + loadseg(new_es, &cpu_state.seg_es); + loadseg(new_ss, &cpu_state.seg_ss); + loadseg(new_ds, &cpu_state.seg_ds); + loadseg(new_fs, &cpu_state.seg_fs); + loadseg(new_gs, &cpu_state.seg_gs); + } else { + if (limit < 43) { + x86ts(NULL, seg); + return; + } + + if ((optype == JMP) || (optype == CALL) || (optype == OPTYPE_INT)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw |= 0x200; + if (tr.seg & 0x0004) + writememw(ldt.base, (seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; + + if (optype == IRET) + cpu_state.flags &= ~NT_FLAG; + + cpu_386_flags_rebuild(); + writememw(tr.base, 0x0e, cpu_state.pc); + writememw(tr.base, 0x10, cpu_state.flags); + + writememw(tr.base, 0x12, AX); + writememw(tr.base, 0x14, CX); + writememw(tr.base, 0x16, DX); + writememw(tr.base, 0x18, BX); + writememw(tr.base, 0x1a, SP); + writememw(tr.base, 0x1c, BP); + writememw(tr.base, 0x1e, SI); + writememw(tr.base, 0x20, DI); + + writememw(tr.base, 0x22, ES); + writememw(tr.base, 0x24, CS); + writememw(tr.base, 0x26, SS); + writememw(tr.base, 0x28, DS); + + if ((optype == JMP) || (optype == IRET)) { + if (tr.seg & 0x0004) + tempw = readmemw(ldt.base, (tr.seg & 0xfff8) + 4); + else + tempw = readmemw(gdt.base, (tr.seg & 0xfff8) + 4); + if (cpu_state.abrt) + return; + tempw &= ~0x200; + if (tr.seg & 0x0004) + writememw(ldt.base, (tr.seg & 0xfff8) + 4, tempw); + else + writememw(gdt.base, (tr.seg & 0xfff8) + 4, tempw); + } + if (cpu_state.abrt) + return; + + if ((optype == OPTYPE_INT) || (optype == CALL)) { + writememw(base, 0, tr.seg); + if (cpu_state.abrt) + return; + } + + new_pc = readmemw(base, 0x0e); + new_flags = readmemw(base, 0x10); + if ((optype == OPTYPE_INT) || (optype == CALL)) + new_flags |= NT_FLAG; + + new_eax = readmemw(base, 0x12); + new_ecx = readmemw(base, 0x14); + new_edx = readmemw(base, 0x16); + new_ebx = readmemw(base, 0x18); + new_esp = readmemw(base, 0x1a); + new_ebp = readmemw(base, 0x1c); + new_esi = readmemw(base, 0x1e); + new_edi = readmemw(base, 0x20); + + new_es = readmemw(base, 0x22); + new_cs = readmemw(base, 0x24); + new_ss = readmemw(base, 0x26); + new_ds = readmemw(base, 0x28); + new_ldt = readmemw(base, 0x2a); + + msw |= 8; + + cpu_state.pc = new_pc; + cpu_state.flags = new_flags; + cpu_386_flags_extract(); + + ldt.seg = new_ldt; + templ = (ldt.seg & 0xfff8) + gdt.base; + ldt.limit = readmemw(0, templ); + ldt.base = (readmemw(0, templ + 2)) | (readmemb(0, templ + 4) << 16); + if (is386) { + if (readmemb(0, templ + 6) & 0x80) { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base |= (readmemb(0, templ + 7) << 24); + } + + if (!(new_cs & 0xfff8)) { + x86ts(NULL, 0); + return; + } + addr = new_cs & 0xfff8; + dt = (new_cs & 0x0004) ? &ldt : &gdt; + if ((addr + 7) > dt->limit) { + x86ts(NULL, new_cs & 0xfffc); + return; + } + addr += dt->base; + read_descriptor(addr, segdat2, segdat232, 0); + if (!(segdat2[2] & 0x8000)) { + x86np("TS loading CS not present", new_cs & 0xfffc); + return; + } + switch (segdat2[2] & 0x1f00) { + case 0x1800: case 0x1900: case 0x1a00: case 0x1b00: /* Non-conforming */ + if ((new_cs & 0x0003) != DPL2) { + x86ts(NULL,new_cs & 0xfffc); + return; + } + break; + case 0x1c00: case 0x1d00: case 0x1e00: case 0x1f00: /* Conforming */ + if ((new_cs & 0x0003) < DPL2) { + x86ts(NULL,new_cs & 0xfffc); + return; + } + break; + default: + x86ts(NULL, new_cs & 0xfffc); + return; + } + + CS = new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if ((CPL == 3) && (oldcpl != 3)) + flushmmucache_cr3(); +#ifdef USE_NEW_DYNAREC + oldcpl = CPL; +#endif + set_use32(0); + + EAX = new_eax | 0xffff0000; + ECX = new_ecx | 0xffff0000; + EDX = new_edx | 0xffff0000; + EBX = new_ebx | 0xffff0000; + ESP = new_esp | 0xffff0000; + EBP = new_ebp | 0xffff0000; + ESI = new_esi | 0xffff0000; + EDI = new_edi | 0xffff0000; + + loadseg(new_es, &cpu_state.seg_es); + loadseg(new_ss, &cpu_state.seg_ss); + loadseg(new_ds, &cpu_state.seg_ds); + if (is386) { + loadseg(0, &cpu_state.seg_fs); + loadseg(0, &cpu_state.seg_gs); + } + } + + tr.seg = seg; + tr.base = base; + tr.limit = limit; + tr.access = segdat[2] >> 8; + tr.ar_high = segdat[3] & 0xff; +} + + +void +cyrix_write_seg_descriptor(uint32_t addr, x86seg *seg) +{ + uint32_t limit_raw = seg->limit; + + if (seg->ar_high & 0x80) + limit_raw >>= 12; + + writememl(0, addr, (limit_raw & 0xffff) | (seg->base << 16)); + writememl(0, addr + 4, ((seg->base >> 16) & 0xff) | (seg->access << 8) | + (limit_raw & 0xf0000) | (seg->ar_high << 16) | + (seg->base & 0xff000000)); +} + + +void +cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg) +{ + uint16_t segdat[4], selector; + + segdat[0] = readmemw(0, addr); + segdat[1] = readmemw(0, addr + 2); + segdat[2] = readmemw(0, addr + 4); + segdat[3] = readmemw(0, addr + 6); + selector = readmemw(0, addr+8); + + if (!cpu_state.abrt) { + do_seg_load(seg, segdat); + seg->seg = selector; + seg->checked = 0; + if (seg == &cpu_state.seg_ds) { + if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; +#ifdef USE_DYNAREC + codegen_flat_ds = 0; +#endif + } + if (seg == &cpu_state.seg_ss) { + if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + set_stack32((segdat[3] & 0x40) ? 1 : 0); +#ifdef USE_DYNAREC + codegen_flat_ss = 0; +#endif + } + } +} diff --git a/src/cpu/x86seg.h b/src/cpu/x86seg.h index d740f9cea..d98db1586 100644 --- a/src/cpu/x86seg.h +++ b/src/cpu/x86seg.h @@ -16,3 +16,6 @@ */ extern void do_seg_load(x86seg *s, uint16_t *segdat); + +extern void cyrix_write_seg_descriptor(uint32_t addr, x86seg *seg); +extern void cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg); diff --git a/src/cpu/x87.c b/src/cpu/x87.c index 47ab0c844..cf92788fb 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -51,7 +51,7 @@ uint16_t x87_gettag() { uint16_t ret = 0; int c; - + for (c = 0; c < 8; c++) { if (cpu_state.tag[c] == TAG_EMPTY) @@ -70,11 +70,11 @@ uint16_t x87_gettag() void x87_settag(uint16_t new_tag) { int c; - + for (c = 0; c < 8; c++) { int tag = (new_tag >> (c * 2)) & 3; - + if (tag == X87_TAG_EMPTY) cpu_state.tag[c] = TAG_EMPTY; else if (tag == 2) @@ -88,7 +88,7 @@ uint16_t x87_gettag() { uint16_t ret = 0; int c; - + for (c = 0; c < 8; c++) { if (cpu_state.tag[c] & TAG_UINT64) diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 0e0a07dd5..758546e7a 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -46,6 +46,16 @@ static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZ #define STATUS_ZERODIVIDE 4 +#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 \ { \ @@ -86,7 +96,7 @@ static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZ dst = src1 / (double)src2; \ } while (0) #endif - + static __inline void x87_checkexceptions() { } @@ -113,7 +123,7 @@ static __inline void x87_push_u64(uint64_t i) double d; uint64_t ll; } td; - + td.ll = i; #ifdef USE_NEW_DYNAREC @@ -142,10 +152,72 @@ static __inline double x87_pop() return t; } +static __inline int16_t x87_fround16(double b) +{ + int16_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int16_t)floor(b); + c = (int16_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int16_t)floor(b); + case 2: /*Up*/ + return (int16_t)ceil(b); + case 3: /*Chop*/ + return (int16_t)b; + } + + return 0; +} + +static __inline int64_t x87_fround16_64(double b) +{ + return (int64_t) x87_fround16(b); +} + +static __inline int32_t x87_fround32(double b) +{ + int32_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int32_t)floor(b); + c = (int32_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int32_t)floor(b); + case 2: /*Up*/ + return (int32_t)ceil(b); + case 3: /*Chop*/ + return (int32_t)b; + } + + return 0; +} + +static __inline int64_t x87_fround32_64(double b) +{ + return (int64_t) x87_fround32(b); +} + static __inline int64_t x87_fround(double b) { int64_t a, c; - + switch ((cpu_state.npxc >> 10) & 3) { case 0: /*Nearest*/ @@ -167,95 +239,31 @@ static __inline int64_t x87_fround(double b) return 0LL; } -#define BIAS80 16383 -#define BIAS64 1023 + +#include "x87_ops_conv.h" static __inline double x87_ld80() { - int64_t exp64; - int64_t blah; - int64_t exp64final; - int64_t mant64; - int64_t sign; - struct { - int16_t begin; - union - { - double d; - uint64_t ll; - } eind; - } test; - test.eind.ll = readmeml(easeg,cpu_state.eaaddr); - test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; - test.begin = readmemw(easeg,cpu_state.eaaddr+8); - - exp64 = (((test.begin&0x7fff) - BIAS80)); - blah = ((exp64 >0)?exp64:-exp64)&0x3ff; - exp64final = ((exp64 >0)?blah:-blah) +BIAS64; - - mant64 = (test.eind.ll >> 11) & (0xfffffffffffffll); - sign = (test.begin&0x8000)?1:0; - - if ((test.begin & 0x7fff) == 0x7fff) - exp64final = 0x7ff; - if ((test.begin & 0x7fff) == 0) - exp64final = 0; - if (test.eind.ll & 0x400) - mant64++; - - test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; - - return test.eind.d; + x87_conv_t test; + test.eind.ll = readmeml(easeg,cpu_state.eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; + test.begin = readmemw(easeg,cpu_state.eaaddr+8); + return x87_from80(&test); } static __inline void x87_st80(double d) { - int64_t sign80; - int64_t exp80; - int64_t exp80final; - int64_t mant80; - int64_t mant80final; - - struct { - int16_t begin; - union - { - double d; - uint64_t ll; - } eind; - } test; - - test.eind.d=d; - - sign80 = (test.eind.ll&(0x8000000000000000ll))?1:0; - exp80 = test.eind.ll&(0x7ff0000000000000ll); - exp80final = (exp80>>52); - mant80 = test.eind.ll&(0x000fffffffffffffll); - mant80final = (mant80 << 11); - - if (exp80final == 0x7ff) /*Infinity / Nan*/ - { - exp80final = 0x7fff; - mant80final |= (0x8000000000000000ll); - } - else if (d != 0){ /* Zero is a special case */ - /* Elvira wants the 8 and tcalc doesn't */ - mant80final |= (0x8000000000000000ll); - /* Ca-cyber doesn't like this when result is zero. */ - exp80final += (BIAS80 - BIAS64); - } - test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; - test.eind.ll = mant80final; - - writememl(easeg,cpu_state.eaaddr,test.eind.ll & 0xffffffff); - writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); - writememw(easeg,cpu_state.eaaddr+8,test.begin); + x87_conv_t test; + x87_to80(d, &test); + writememl(easeg,cpu_state.eaaddr,test.eind.ll & 0xffffffff); + writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); + writememw(easeg,cpu_state.eaaddr+8,test.begin); } static __inline void x87_st_fsave(int reg) { reg = (cpu_state.TOP + reg) & 7; - + if (cpu_state.tag[reg] & TAG_UINT64) { writememl(easeg, cpu_state.eaaddr, cpu_state.MM[reg].q & 0xffffffff); @@ -269,7 +277,7 @@ static __inline void x87_st_fsave(int reg) static __inline void x87_ld_frstor(int reg) { reg = (cpu_state.TOP + reg) & 7; - + cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr); cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8); @@ -311,7 +319,7 @@ static __inline void x87_stmmx(MMX_REG r) static __inline uint16_t x87_compare(double a, double b) { -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 +#ifdef X87_INLINE_ASM uint32_t result; double ea = a, eb = b; const uint64_t ia = 0x3fec1a6ff866a936ull; @@ -325,16 +333,16 @@ static __inline uint16_t x87_compare(double a, double b) ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) eb = ea; -#ifndef _MSC_VER +#if !defined(_MSC_VER) || defined(__clang__) /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ __asm volatile ("" : : : "memory"); - + __asm( "fldl %2\n" "fldl %1\n" "fclex\n" - "fcompp\n" + "fcompp\n" "fnstsw %0\n" : "=m" (result) : "m" (ea), "m" (eb) @@ -366,26 +374,26 @@ static __inline uint16_t x87_compare(double a, double b) result |= C3; else if (ea < eb) result |= C0; - + return result; #endif } static __inline uint16_t x87_ucompare(double a, double b) { -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 || defined __amd64__ +#ifdef X87_INLINE_ASM uint32_t result; - -#ifndef _MSC_VER + +#if !defined(_MSC_VER) || defined(__clang__) /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ - asm volatile ("" : : : "memory"); - - asm( + __asm volatile ("" : : : "memory"); + + __asm( "fldl %2\n" "fldl %1\n" "fclex\n" - "fucompp\n" + "fucompp\n" "fnstsw %0\n" : "=m" (result) : "m" (a), "m" (b) @@ -407,12 +415,12 @@ static __inline uint16_t x87_ucompare(double a, double b) /* Generic C version is known to give incorrect results in some * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; - + if (a == b) result |= C3; else if (a < b) result |= C0; - + return result; #endif } @@ -431,7 +439,6 @@ typedef union #ifdef FPU_8087 #define FP_ENTER() { \ - fpucount++; \ } #else #define FP_ENTER() do \ @@ -441,7 +448,6 @@ typedef union x86_int(7); \ return 1; \ } \ - fpucount++; \ } while (0) #endif @@ -532,7 +538,7 @@ const OpFn OP_TABLE(fpu_8087_d9)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -541,7 +547,7 @@ const OpFn OP_TABLE(fpu_8087_d9)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -550,7 +556,7 @@ const OpFn OP_TABLE(fpu_8087_d9)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -791,7 +797,7 @@ const OpFn OP_TABLE(fpu_287_d9_a16)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -800,7 +806,7 @@ const OpFn OP_TABLE(fpu_287_d9_a16)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -809,7 +815,7 @@ const OpFn OP_TABLE(fpu_287_d9_a16)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -830,7 +836,7 @@ const OpFn OP_TABLE(fpu_287_d9_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, @@ -839,7 +845,7 @@ const OpFn OP_TABLE(fpu_287_d9_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, @@ -848,7 +854,7 @@ const OpFn OP_TABLE(fpu_287_d9_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, @@ -869,7 +875,7 @@ const OpFn OP_TABLE(fpu_d9_a16)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -878,7 +884,7 @@ const OpFn OP_TABLE(fpu_d9_a16)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -887,7 +893,7 @@ const OpFn OP_TABLE(fpu_d9_a16)[256] = ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, - opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, @@ -908,7 +914,7 @@ const OpFn OP_TABLE(fpu_d9_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, @@ -917,7 +923,7 @@ const OpFn OP_TABLE(fpu_d9_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, @@ -926,7 +932,7 @@ const OpFn OP_TABLE(fpu_d9_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, - opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, diff --git a/src/cpu/x87_ops_arith.h b/src/cpu/x87_ops_arith.h index 26a414f75..5e4bfceab 100644 --- a/src/cpu/x87_ops_arith.h +++ b/src/cpu/x87_ops_arith.h @@ -11,8 +11,9 @@ static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ ST(0) += use_var; \ if ((cpu_state.npxc >> 10) & 3) \ fesetround(FE_TONEAREST); \ - FP_TAG_VALID; \ - CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix); \ + 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)); \ return 0; \ } \ static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -24,7 +25,8 @@ static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ load_var = get(); if (cpu_state.abrt) return 1; \ cpu_state.npxs &= ~(C0|C2|C3); \ cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ - CLOCK_CYCLES(x87_timings.fcom ## cycle_postfix); \ + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom ## cycle_postfix) : ((x87_timings.fcom ## cycle_postfix) * cpu_multi)); \ + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom ## cycle_postfix) : ((x87_concurrency.fcom ## cycle_postfix) * cpu_multi)); \ return 0; \ } \ static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -37,7 +39,8 @@ static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ cpu_state.npxs &= ~(C0|C2|C3); \ cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ x87_pop(); \ - CLOCK_CYCLES(x87_timings.fcom ## cycle_postfix); \ + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom ## cycle_postfix) : ((x87_timings.fcom ## cycle_postfix) * cpu_multi)); \ + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom ## cycle_postfix) : ((x87_concurrency.fcom ## cycle_postfix) * cpu_multi)); \ return 0; \ } \ static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -49,7 +52,8 @@ static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ load_var = get(); if (cpu_state.abrt) return 1; \ x87_div(ST(0), ST(0), use_var); \ FP_TAG_VALID; \ - CLOCK_CYCLES(x87_timings.fdiv ## cycle_postfix); \ + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv ## cycle_postfix) : ((x87_timings.fdiv ## cycle_postfix) * cpu_multi)); \ + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd ## cycle_postfix) : ((x87_concurrency.fadd ## cycle_postfix) * cpu_multi)); \ return 0; \ } \ static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -61,7 +65,8 @@ static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ load_var = get(); if (cpu_state.abrt) return 1; \ x87_div(ST(0), use_var, ST(0)); \ FP_TAG_VALID; \ - CLOCK_CYCLES(x87_timings.fdiv ## cycle_postfix); \ + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv ## cycle_postfix) : ((x87_timings.fdiv ## cycle_postfix) * cpu_multi)); \ + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv ## cycle_postfix) : ((x87_concurrency.fdiv ## cycle_postfix) * cpu_multi)); \ return 0; \ } \ static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -73,7 +78,8 @@ static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) *= use_var; \ FP_TAG_VALID; \ - CLOCK_CYCLES(x87_timings.fmul ## cycle_postfix); \ + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fmul ## cycle_postfix) : ((x87_timings.fmul ## cycle_postfix) * cpu_multi)); \ + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fmul ## cycle_postfix) : ((x87_concurrency.fmul ## cycle_postfix) * cpu_multi)); \ return 0; \ } \ static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -85,7 +91,8 @@ static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) -= use_var; \ FP_TAG_VALID; \ - CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix); \ + 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)); \ return 0; \ } \ static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -97,7 +104,8 @@ static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) = use_var - ST(0); \ FP_TAG_VALID; \ - CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix); \ + 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)); \ return 0; \ } @@ -127,7 +135,8 @@ static int opFADD(uint32_t fetchdat) cpu_state.pc++; ST(0) = ST(0) + ST(fetchdat & 7); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } static int opFADDr(uint32_t fetchdat) @@ -136,7 +145,8 @@ static int opFADDr(uint32_t fetchdat) cpu_state.pc++; ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); FP_TAG_VALID_F; - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } static int opFADDP(uint32_t fetchdat) @@ -146,7 +156,8 @@ static int opFADDP(uint32_t fetchdat) ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); FP_TAG_VALID_F; x87_pop(); - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } @@ -157,7 +168,8 @@ static int opFCOM(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); if (ST(0) == ST(fetchdat & 7)) cpu_state.npxs |= C3; else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0; - CLOCK_CYCLES(x87_timings.fcom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi)); return 0; } @@ -168,7 +180,8 @@ static int opFCOMP(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); x87_pop(); - CLOCK_CYCLES(x87_timings.fcom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi)); return 0; } @@ -187,7 +200,8 @@ static int opFCOMPP(uint32_t fetchdat) x87_pop(); x87_pop(); - CLOCK_CYCLES(x87_timings.fcom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -199,7 +213,8 @@ static int opFUCOMPP(uint32_t fetchdat) cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); x87_pop(); x87_pop(); - CLOCK_CYCLES(x87_timings.fucom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi)); return 0; } @@ -211,7 +226,8 @@ static int opFCOMI(uint32_t fetchdat) cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; - CLOCK_CYCLES(x87_timings.fcom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi)); return 0; } static int opFCOMIP(uint32_t fetchdat) @@ -223,7 +239,8 @@ static int opFCOMIP(uint32_t fetchdat) if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; x87_pop(); - CLOCK_CYCLES(x87_timings.fcom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi)); return 0; } #endif @@ -234,7 +251,8 @@ static int opFDIV(uint32_t fetchdat) cpu_state.pc++; x87_div(ST(0), ST(0), ST(fetchdat & 7)); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fdiv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv) : (x87_timings.fdiv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv) : (x87_concurrency.fdiv * cpu_multi)); return 0; } static int opFDIVr(uint32_t fetchdat) @@ -243,7 +261,8 @@ static int opFDIVr(uint32_t fetchdat) cpu_state.pc++; x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); FP_TAG_VALID_F; - CLOCK_CYCLES(x87_timings.fdiv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv) : (x87_timings.fdiv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv) : (x87_concurrency.fdiv * cpu_multi)); return 0; } static int opFDIVP(uint32_t fetchdat) @@ -253,7 +272,8 @@ static int opFDIVP(uint32_t fetchdat) x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); FP_TAG_VALID_F; x87_pop(); - CLOCK_CYCLES(x87_timings.fdiv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv) : (x87_timings.fdiv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv) : (x87_concurrency.fdiv * cpu_multi)); return 0; } @@ -263,7 +283,8 @@ static int opFDIVR(uint32_t fetchdat) cpu_state.pc++; x87_div(ST(0), ST(fetchdat&7), ST(0)); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fdiv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv) : (x87_timings.fdiv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv) : (x87_concurrency.fdiv * cpu_multi)); return 0; } static int opFDIVRr(uint32_t fetchdat) @@ -272,7 +293,8 @@ static int opFDIVRr(uint32_t fetchdat) cpu_state.pc++; x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); FP_TAG_VALID_F; - CLOCK_CYCLES(x87_timings.fdiv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv) : (x87_timings.fdiv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv) : (x87_concurrency.fdiv * cpu_multi)); return 0; } static int opFDIVRP(uint32_t fetchdat) @@ -282,7 +304,8 @@ static int opFDIVRP(uint32_t fetchdat) x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); FP_TAG_VALID_F; x87_pop(); - CLOCK_CYCLES(x87_timings.fdiv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fdiv) : (x87_timings.fdiv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv) : (x87_concurrency.fdiv * cpu_multi)); return 0; } @@ -292,7 +315,8 @@ static int opFMUL(uint32_t fetchdat) cpu_state.pc++; ST(0) = ST(0) * ST(fetchdat & 7); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fmul); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fmul) : (x87_timings.fmul * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fmul) : (x87_concurrency.fmul * cpu_multi)); return 0; } static int opFMULr(uint32_t fetchdat) @@ -301,7 +325,8 @@ static int opFMULr(uint32_t fetchdat) cpu_state.pc++; ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); FP_TAG_VALID_F; - CLOCK_CYCLES(x87_timings.fmul); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fmul) : (x87_timings.fmul * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fmul) : (x87_concurrency.fmul * cpu_multi)); return 0; } static int opFMULP(uint32_t fetchdat) @@ -311,7 +336,8 @@ static int opFMULP(uint32_t fetchdat) ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); FP_TAG_VALID_F; x87_pop(); - CLOCK_CYCLES(x87_timings.fmul); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fmul) : (x87_timings.fmul * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fmul) : (x87_concurrency.fmul * cpu_multi)); return 0; } @@ -321,7 +347,8 @@ static int opFSUB(uint32_t fetchdat) cpu_state.pc++; ST(0) = ST(0) - ST(fetchdat & 7); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } static int opFSUBr(uint32_t fetchdat) @@ -330,7 +357,8 @@ static int opFSUBr(uint32_t fetchdat) cpu_state.pc++; ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); FP_TAG_VALID_F; - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } static int opFSUBP(uint32_t fetchdat) @@ -340,7 +368,8 @@ static int opFSUBP(uint32_t fetchdat) ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); FP_TAG_VALID_F; x87_pop(); - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } @@ -350,7 +379,8 @@ static int opFSUBR(uint32_t fetchdat) cpu_state.pc++; ST(0) = ST(fetchdat & 7) - ST(0); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } static int opFSUBRr(uint32_t fetchdat) @@ -359,7 +389,8 @@ static int opFSUBRr(uint32_t fetchdat) cpu_state.pc++; ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); FP_TAG_VALID_F; - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } static int opFSUBRP(uint32_t fetchdat) @@ -369,7 +400,8 @@ static int opFSUBRP(uint32_t fetchdat) ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); FP_TAG_VALID_F; x87_pop(); - CLOCK_CYCLES(x87_timings.fadd); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd) : (x87_timings.fadd * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd) : (x87_concurrency.fadd * cpu_multi)); return 0; } @@ -380,7 +412,8 @@ static int opFUCOM(uint32_t fetchdat) cpu_state.pc++; cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); - CLOCK_CYCLES(x87_timings.fucom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi)); return 0; } @@ -391,7 +424,8 @@ static int opFUCOMP(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); x87_pop(); - CLOCK_CYCLES(x87_timings.fucom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi)); return 0; } @@ -403,7 +437,8 @@ static int opFUCOMI(uint32_t fetchdat) cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; - CLOCK_CYCLES(x87_timings.fucom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi)); return 0; } static int opFUCOMIP(uint32_t fetchdat) @@ -415,7 +450,8 @@ static int opFUCOMIP(uint32_t fetchdat) if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; x87_pop(); - CLOCK_CYCLES(x87_timings.fucom); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi)); return 0; } #endif diff --git a/src/cpu/x87_ops_conv.h b/src/cpu/x87_ops_conv.h new file mode 100644 index 000000000..44304c1bc --- /dev/null +++ b/src/cpu/x87_ops_conv.h @@ -0,0 +1,68 @@ +#define BIAS80 16383 +#define BIAS64 1023 + +typedef struct { + int16_t begin; + union { + double d; + uint64_t ll; + } eind; +} x87_conv_t; + +static __inline double x87_from80(x87_conv_t *test) +{ + int64_t exp64; + int64_t blah; + int64_t exp64final; + int64_t mant64; + int64_t sign; + + exp64 = (((test->begin&0x7fff) - BIAS80)); + blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + mant64 = (test->eind.ll >> 11) & (0xfffffffffffffll); + sign = (test->begin&0x8000)?1:0; + + if ((test->begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test->begin & 0x7fff) == 0) + exp64final = 0; + if (test->eind.ll & 0x400) + mant64++; + + test->eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test->eind.d; +} + +static __inline void x87_to80(double d, x87_conv_t *test) +{ + int64_t sign80; + int64_t exp80; + int64_t exp80final; + int64_t mant80; + int64_t mant80final; + + test->eind.d=d; + + sign80 = (test->eind.ll&(0x8000000000000000ll))?1:0; + exp80 = test->eind.ll&(0x7ff0000000000000ll); + exp80final = (exp80>>52); + mant80 = test->eind.ll&(0x000fffffffffffffll); + mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000ll); + } + else if (d != 0){ /* Zero is a special case */ + /* Elvira wants the 8 and tcalc doesn't */ + mant80final |= (0x8000000000000000ll); + /* Ca-cyber doesn't like this when result is zero. */ + exp80final += (BIAS80 - BIAS64); + } + test->begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test->eind.ll = mant80final; +} diff --git a/src/cpu/x87_ops_loadstore.h b/src/cpu/x87_ops_loadstore.h index 7f1cf4900..9afa6815a 100644 --- a/src/cpu/x87_ops_loadstore.h +++ b/src/cpu/x87_ops_loadstore.h @@ -23,7 +23,8 @@ static int opFILDiw_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; x87_push((double)temp); - CLOCK_CYCLES(x87_timings.fild_16); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fild_16) : (x87_timings.fild_16 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fild_16) : (x87_concurrency.fild_16 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -35,59 +36,56 @@ static int opFILDiw_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; x87_push((double)temp); - CLOCK_CYCLES(x87_timings.fild_16); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fild_16) : (x87_timings.fild_16 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fild_16) : (x87_concurrency.fild_16 * cpu_multi)); return 0; } #endif static int opFISTiw_a16(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteaw((int16_t)temp64); - CLOCK_CYCLES(x87_timings.fist_16); + seteaw(x87_fround16(ST(0))); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_16) : (x87_timings.fist_16 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_16) : (x87_concurrency.fist_16 * cpu_multi)); return cpu_state.abrt; } #ifndef FPU_8087 static int opFISTiw_a32(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteaw((int16_t)temp64); - CLOCK_CYCLES(x87_timings.fist_16); + seteaw(x87_fround16(ST(0))); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_16) : (x87_timings.fist_16 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_16) : (x87_concurrency.fist_16 * cpu_multi)); return cpu_state.abrt; } #endif static int opFISTPiw_a16(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; + seteaw(x87_fround16(ST(0))); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fist_16); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_16) : (x87_timings.fist_16 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_16) : (x87_concurrency.fist_16 * cpu_multi)); return 0; } #ifndef FPU_8087 static int opFISTPiw_a32(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; + seteaw(x87_fround16(ST(0))); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fist_16); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_16) : (x87_timings.fist_16 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_16) : (x87_concurrency.fist_16 * cpu_multi)); return 0; } #endif @@ -103,7 +101,8 @@ static int opFILDiq_a16(uint32_t fetchdat) cpu_state.MM[cpu_state.TOP&7].q = temp64; FP_TAG_DEFAULT; - CLOCK_CYCLES(x87_timings.fild_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fild_64) : (x87_timings.fild_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fild_64) : (x87_concurrency.fild_64 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -118,7 +117,8 @@ static int opFILDiq_a32(uint32_t fetchdat) cpu_state.MM[cpu_state.TOP&7].q = temp64; FP_TAG_DEFAULT; - CLOCK_CYCLES(x87_timings.fild_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fild_64) : (x87_timings.fild_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fild_64) : (x87_concurrency.fild_64 * cpu_multi)); return 0; } #endif @@ -131,7 +131,7 @@ static int FBSTP_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); tempd = ST(0); - if (tempd < 0.0) + if (tempd < 0.0) tempd = -tempd; for (c = 0; c < 9; c++) { @@ -147,7 +147,8 @@ static int FBSTP_a16(uint32_t fetchdat) if (ST(0) < 0.0) tempc |= 0x80; writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fbstp); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fbstp) : (x87_timings.fbstp * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fbstp) : (x87_concurrency.fbstp * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -159,7 +160,7 @@ static int FBSTP_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); tempd = ST(0); - if (tempd < 0.0) + if (tempd < 0.0) tempd = -tempd; for (c = 0; c < 9; c++) { @@ -175,7 +176,7 @@ static int FBSTP_a32(uint32_t fetchdat) if (ST(0) < 0.0) tempc |= 0x80; writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fbstp); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fbstp) : (x87_timings.fbstp * cpu_multi)); return 0; } #endif @@ -192,7 +193,8 @@ static int FISTPiq_a16(uint32_t fetchdat) temp64 = x87_fround(ST(0)); seteaq(temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fist_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_64) : (x87_timings.fist_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_64) : (x87_concurrency.fist_64 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -208,7 +210,8 @@ static int FISTPiq_a32(uint32_t fetchdat) temp64 = x87_fround(ST(0)); seteaq(temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fist_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_64) : (x87_timings.fist_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_64) : (x87_concurrency.fist_64 * cpu_multi)); return 0; } #endif @@ -221,7 +224,8 @@ static int opFILDil_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); templ = geteal(); if (cpu_state.abrt) return 1; x87_push((double)templ); - CLOCK_CYCLES(x87_timings.fild_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fild_32) : (x87_timings.fild_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fild_32) : (x87_concurrency.fild_32 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -233,59 +237,56 @@ static int opFILDil_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); templ = geteal(); if (cpu_state.abrt) return 1; x87_push((double)templ); - CLOCK_CYCLES(x87_timings.fild_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fild_32) : (x87_timings.fild_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fild_32) : (x87_concurrency.fild_32 * cpu_multi)); return 0; } #endif static int opFISTil_a16(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteal((int32_t)temp64); - CLOCK_CYCLES(x87_timings.fist_32); + seteal(x87_fround32(ST(0))); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_32) : (x87_timings.fist_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_32) : (x87_concurrency.fist_32 * cpu_multi)); return cpu_state.abrt; } #ifndef FPU_8087 static int opFISTil_a32(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteal((int32_t)temp64); - CLOCK_CYCLES(x87_timings.fist_32); + seteal(x87_fround32(ST(0))); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_32) : (x87_timings.fist_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_32) : (x87_concurrency.fist_32 * cpu_multi)); return cpu_state.abrt; } #endif static int opFISTPil_a16(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteal((int32_t)temp64); if (cpu_state.abrt) return 1; + seteal(x87_fround32(ST(0))); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fist_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_32) : (x87_timings.fist_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_32) : (x87_concurrency.fist_32 * cpu_multi)); return 0; } #ifndef FPU_8087 static int opFISTPil_a32(uint32_t fetchdat) { - int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); - temp64 = x87_fround(ST(0)); - seteal((int32_t)temp64); if (cpu_state.abrt) return 1; + seteal(x87_fround32(ST(0))); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fist_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fist_32) : (x87_timings.fist_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fist_32) : (x87_concurrency.fist_32 * cpu_multi)); return 0; } #endif @@ -298,7 +299,8 @@ static int opFLDe_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); t=x87_ld80(); if (cpu_state.abrt) return 1; x87_push(t); - CLOCK_CYCLES(x87_timings.fld_80); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_80) : (x87_timings.fld_80 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_80) : (x87_concurrency.fld_80 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -310,7 +312,8 @@ static int opFLDe_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); t=x87_ld80(); if (cpu_state.abrt) return 1; x87_push(t); - CLOCK_CYCLES(x87_timings.fld_80); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_80) : (x87_timings.fld_80 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_80) : (x87_concurrency.fld_80 * cpu_multi)); return 0; } #endif @@ -322,7 +325,8 @@ static int opFSTPe_a16(uint32_t fetchdat) SEG_CHECK_WRITE(cpu_state.ea_seg); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fld_80); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_80) : (x87_timings.fld_80 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_80) : (x87_concurrency.fld_80 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -333,7 +337,8 @@ static int opFSTPe_a32(uint32_t fetchdat) SEG_CHECK_WRITE(cpu_state.ea_seg); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fld_80); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_80) : (x87_timings.fld_80 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_80) : (x87_concurrency.fld_80 * cpu_multi)); return 0; } #endif @@ -346,7 +351,8 @@ static int opFLDd_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); t.i = geteaq(); if (cpu_state.abrt) return 1; x87_push(t.d); - CLOCK_CYCLES(x87_timings.fld_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_64) : (x87_timings.fld_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_64) : (x87_concurrency.fld_64 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -358,7 +364,8 @@ static int opFLDd_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); t.i = geteaq(); if (cpu_state.abrt) return 1; x87_push(t.d); - CLOCK_CYCLES(x87_timings.fld_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_64) : (x87_timings.fld_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_64) : (x87_concurrency.fld_64 * cpu_multi)); return 0; } #endif @@ -371,7 +378,8 @@ static int opFSTd_a16(uint32_t fetchdat) SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); - CLOCK_CYCLES(x87_timings.fst_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_64) : (x87_timings.fst_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_64) : (x87_concurrency.fst_64 * cpu_multi)); return cpu_state.abrt; } #ifndef FPU_8087 @@ -383,7 +391,8 @@ static int opFSTd_a32(uint32_t fetchdat) SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); - CLOCK_CYCLES(x87_timings.fst_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_64) : (x87_timings.fst_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_64) : (x87_concurrency.fst_64 * cpu_multi)); return cpu_state.abrt; } #endif @@ -397,7 +406,8 @@ static int opFSTPd_a16(uint32_t fetchdat) t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fst_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_64) : (x87_timings.fst_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_64) : (x87_concurrency.fst_64 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -410,7 +420,8 @@ static int opFSTPd_a32(uint32_t fetchdat) t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fst_64); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_64) : (x87_timings.fst_64 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_64) : (x87_concurrency.fst_64 * cpu_multi)); return 0; } #endif @@ -423,7 +434,8 @@ static int opFLDs_a16(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); ts.i = geteal(); if (cpu_state.abrt) return 1; x87_push((double)ts.s); - CLOCK_CYCLES(x87_timings.fld_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_32) : (x87_timings.fst_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_32) : (x87_concurrency.fst_32 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -435,7 +447,8 @@ static int opFLDs_a32(uint32_t fetchdat) SEG_CHECK_READ(cpu_state.ea_seg); ts.i = geteal(); if (cpu_state.abrt) return 1; x87_push((double)ts.s); - CLOCK_CYCLES(x87_timings.fld_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_32) : (x87_timings.fst_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_32) : (x87_concurrency.fst_32 * cpu_multi)); return 0; } #endif @@ -448,7 +461,8 @@ static int opFSTs_a16(uint32_t fetchdat) SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); - CLOCK_CYCLES(x87_timings.fst_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_32) : (x87_timings.fst_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_32) : (x87_concurrency.fst_32 * cpu_multi)); return cpu_state.abrt; } #ifndef FPU_8087 @@ -460,7 +474,8 @@ static int opFSTs_a32(uint32_t fetchdat) SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); - CLOCK_CYCLES(x87_timings.fst_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_32) : (x87_timings.fst_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_32) : (x87_concurrency.fst_32 * cpu_multi)); return cpu_state.abrt; } #endif @@ -474,7 +489,8 @@ static int opFSTPs_a16(uint32_t fetchdat) ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fst_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_32) : (x87_timings.fst_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_32) : (x87_concurrency.fst_32 * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -487,7 +503,8 @@ static int opFSTPs_a32(uint32_t fetchdat) ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.fst_32); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst_32) : (x87_timings.fst_32 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst_32) : (x87_concurrency.fst_32 * cpu_multi)); return 0; } #endif diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index af7be0527..7e27cc287 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -15,7 +15,8 @@ static int opFSTSW_AX(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; AX = cpu_state.npxs; - CLOCK_CYCLES(x87_timings.fstcw_sw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fstcw_sw) : (x87_timings.fstcw_sw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fstcw_sw) : (x87_concurrency.fstcw_sw * cpu_multi)); return 0; } #endif @@ -25,7 +26,8 @@ static int opFNOP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - CLOCK_CYCLES(x87_timings.fnop); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fnop) : (x87_timings.fnop * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fnop) : (x87_concurrency.fnop * cpu_multi)); return 0; } @@ -34,7 +36,8 @@ static int opFCLEX(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; cpu_state.npxs &= 0xff00; - CLOCK_CYCLES(x87_timings.fnop); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fnop) : (x87_timings.fnop * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fnop) : (x87_concurrency.fnop * cpu_multi)); return 0; } @@ -58,7 +61,8 @@ static int opFINIT(uint32_t fetchdat) #endif cpu_state.TOP = 0; cpu_state.ismmx = 0; - CLOCK_CYCLES(x87_timings.finit); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.finit) : (x87_timings.finit * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.finit) : (x87_concurrency.finit * cpu_multi)); CPU_BLOCK_END(); return 0; } @@ -73,7 +77,8 @@ static int opFFREE(uint32_t fetchdat) #else cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; #endif - CLOCK_CYCLES(x87_timings.ffree); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ffree) : (x87_timings.ffree * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ffree) : (x87_concurrency.ffree * cpu_multi)); return 0; } @@ -83,7 +88,8 @@ static int opFFREEP(uint32_t fetchdat) cpu_state.pc++; cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(x87_timings.ffree); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ffree) : (x87_timings.ffree * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ffree) : (x87_concurrency.ffree * cpu_multi)); return 0; } @@ -93,7 +99,8 @@ static int opFST(uint32_t fetchdat) cpu_state.pc++; ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; - CLOCK_CYCLES(x87_timings.fst); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst) : (x87_timings.fst * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst) : (x87_concurrency.fst * cpu_multi)); return 0; } @@ -104,7 +111,8 @@ static int opFSTP(uint32_t fetchdat) ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; x87_pop(); - CLOCK_CYCLES(x87_timings.fst); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fst) : (x87_timings.fst * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fst) : (x87_concurrency.fst * cpu_multi)); return 0; } @@ -144,7 +152,7 @@ static int FSTOR() x87_ld_frstor(5); cpu_state.eaaddr += 10; x87_ld_frstor(6); cpu_state.eaaddr += 10; x87_ld_frstor(7); - + cpu_state.ismmx = 0; /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times something like this is needed*/ @@ -160,7 +168,8 @@ static int FSTOR() #endif cpu_state.ismmx = 1; - CLOCK_CYCLES(x87_timings.frstor); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frstor) : (x87_timings.frstor * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frstor) : (x87_concurrency.frstor * cpu_multi)); return cpu_state.abrt; } static int opFSTOR_a16(uint32_t fetchdat) @@ -330,7 +339,8 @@ static int FSAVE() cpu_state.TOP = 0; cpu_state.ismmx = 0; - CLOCK_CYCLES(x87_timings.fsave); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fsave) : (x87_timings.fsave * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fsave) : (x87_concurrency.fsave * cpu_multi)); return cpu_state.abrt; } static int opFSAVE_a16(uint32_t fetchdat) @@ -358,7 +368,8 @@ static int opFSTSW_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); - CLOCK_CYCLES(x87_timings.fstcw_sw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fstcw_sw) : (x87_timings.fstcw_sw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fstcw_sw) : (x87_concurrency.fstcw_sw * cpu_multi)); return cpu_state.abrt; } #ifndef FPU_8087 @@ -368,7 +379,8 @@ static int opFSTSW_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); - CLOCK_CYCLES(x87_timings.fstcw_sw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fstcw_sw) : (x87_timings.fstcw_sw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fstcw_sw) : (x87_concurrency.fstcw_sw * cpu_multi)); return cpu_state.abrt; } #endif @@ -378,7 +390,7 @@ static int opFLD(uint32_t fetchdat) { int old_tag; uint64_t old_i64; - + FP_ENTER(); cpu_state.pc++; old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; @@ -386,7 +398,8 @@ static int opFLD(uint32_t fetchdat) x87_push(ST(fetchdat&7)); cpu_state.tag[cpu_state.TOP&7] = old_tag; cpu_state.MM[cpu_state.TOP&7].q = old_i64; - CLOCK_CYCLES(x87_timings.fld); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld) : (x87_timings.fld * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld) : (x87_concurrency.fld * cpu_multi)); return 0; } @@ -406,8 +419,9 @@ static int opFXCH(uint32_t fetchdat) old_i64 = cpu_state.MM[cpu_state.TOP&7].q; cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q = old_i64; - - CLOCK_CYCLES(x87_timings.fxch); + + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fxch) : (x87_timings.fxch * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fxch) : (x87_concurrency.fxch * cpu_multi)); return 0; } @@ -417,7 +431,8 @@ static int opFCHS(uint32_t fetchdat) cpu_state.pc++; ST(0) = -ST(0); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fchs); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fchs) : (x87_timings.fchs * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fchs) : (x87_concurrency.fchs * cpu_multi)); return 0; } @@ -427,7 +442,8 @@ static int opFABS(uint32_t fetchdat) cpu_state.pc++; ST(0) = fabs(ST(0)); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fabs); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fabs) : (x87_timings.fabs * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fabs) : (x87_concurrency.fabs * cpu_multi)); return 0; } @@ -438,7 +454,8 @@ static int opFTST(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); if (ST(0) == 0.0) cpu_state.npxs |= C3; else if (ST(0) < 0.0) cpu_state.npxs |= C0; - CLOCK_CYCLES(x87_timings.ftst); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ftst) : (x87_timings.ftst * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi)); return 0; } @@ -455,7 +472,8 @@ static int opFXAM(uint32_t fetchdat) else if (ST(0) == 0.0) cpu_state.npxs |= C3; else cpu_state.npxs |= C2; if (ST(0) < 0.0) cpu_state.npxs |= C1; - CLOCK_CYCLES(x87_timings.fxam); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fxam) : (x87_timings.fxam * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fxam) : (x87_concurrency.fxam * cpu_multi)); return 0; } @@ -464,7 +482,8 @@ static int opFLD1(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; x87_push(1.0); - CLOCK_CYCLES(x87_timings.fld_z1); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_z1) : (x87_timings.fld_z1 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_z1) : (x87_concurrency.fld_z1 * cpu_multi)); return 0; } @@ -473,7 +492,8 @@ static int opFLDL2T(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; x87_push(3.3219280948873623); - CLOCK_CYCLES(x87_timings.fld_const); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_const) : (x87_timings.fld_const * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_const) : (x87_concurrency.fld_const * cpu_multi)); return 0; } @@ -482,7 +502,8 @@ static int opFLDL2E(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; x87_push(1.4426950408889634); - CLOCK_CYCLES(x87_timings.fld_const); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_const) : (x87_timings.fld_const * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_const) : (x87_concurrency.fld_const * cpu_multi)); return 0; } @@ -491,7 +512,8 @@ static int opFLDPI(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; x87_push(3.141592653589793); - CLOCK_CYCLES(x87_timings.fld_const); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_const) : (x87_timings.fld_const * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_const) : (x87_concurrency.fld_const * cpu_multi)); return 0; } @@ -500,7 +522,8 @@ static int opFLDEG2(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; x87_push(0.3010299956639812); - CLOCK_CYCLES(x87_timings.fld_const); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_const) : (x87_timings.fld_const * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_const) : (x87_concurrency.fld_const * cpu_multi)); return 0; } @@ -509,17 +532,19 @@ static int opFLDLN2(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; x87_push_u64(0x3fe62e42fefa39f0ull); - CLOCK_CYCLES(x87_timings.fld_const); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_const) : (x87_timings.fld_const * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_const) : (x87_concurrency.fld_const * cpu_multi)); return 0; } - + static int opFLDZ(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; x87_push(0.0); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fld_z1); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fld_z1) : (x87_timings.fld_z1 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fld_z1) : (x87_concurrency.fld_z1 * cpu_multi)); return 0; } @@ -529,7 +554,8 @@ static int opF2XM1(uint32_t fetchdat) cpu_state.pc++; ST(0) = pow(2.0, ST(0)) - 1.0; FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.f2xm1); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.f2xm1) : (x87_timings.f2xm1 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.f2xm1) : (x87_concurrency.f2xm1 * cpu_multi)); return 0; } @@ -540,7 +566,8 @@ static int opFYL2X(uint32_t fetchdat) ST(1) = ST(1) * (log(ST(0)) / log(2.0)); FP_TAG_VALID_N; x87_pop(); - CLOCK_CYCLES(x87_timings.fyl2x); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fyl2x) : (x87_timings.fyl2x * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fyl2x) : (x87_concurrency.fyl2x * cpu_multi)); return 0; } @@ -551,7 +578,8 @@ static int opFYL2XP1(uint32_t fetchdat) ST(1) = ST(1) * (log1p(ST(0)) / log(2.0)); FP_TAG_VALID_N; x87_pop(); - CLOCK_CYCLES(x87_timings.fyl2xp1); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fyl2xp1) : (x87_timings.fyl2xp1 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fyl2xp1) : (x87_concurrency.fyl2xp1 * cpu_multi)); return 0; } @@ -563,7 +591,8 @@ static int opFPTAN(uint32_t fetchdat) FP_TAG_VALID; x87_push(1.0); cpu_state.npxs &= ~C2; - CLOCK_CYCLES(x87_timings.fptan); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fptan) : (x87_timings.fptan * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fptan) : (x87_concurrency.fptan * cpu_multi)); return 0; } @@ -574,7 +603,8 @@ static int opFPATAN(uint32_t fetchdat) ST(1) = atan2(ST(1), ST(0)); FP_TAG_VALID_N; x87_pop(); - CLOCK_CYCLES(x87_timings.fpatan); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fpatan) : (x87_timings.fpatan * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fpatan) : (x87_concurrency.fpatan * cpu_multi)); return 0; } @@ -587,7 +617,8 @@ static int opFDECSTP(uint32_t fetchdat) #else cpu_state.TOP = (cpu_state.TOP - 1) & 7; #endif - CLOCK_CYCLES(x87_timings.fincdecstp); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fincdecstp) : (x87_timings.fincdecstp * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fincdecstp) : (x87_concurrency.fincdecstp * cpu_multi)); return 0; } @@ -600,7 +631,8 @@ static int opFINCSTP(uint32_t fetchdat) #else cpu_state.TOP = (cpu_state.TOP + 1) & 7; #endif - CLOCK_CYCLES(x87_timings.fincdecstp); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fincdecstp) : (x87_timings.fincdecstp * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fincdecstp) : (x87_concurrency.fincdecstp * cpu_multi)); return 0; } @@ -616,7 +648,8 @@ static int opFPREM(uint32_t fetchdat) if (temp64 & 4) cpu_state.npxs|=C0; if (temp64 & 2) cpu_state.npxs|=C3; if (temp64 & 1) cpu_state.npxs|=C1; - CLOCK_CYCLES(x87_timings.fprem); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fprem) : (x87_timings.fprem * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fprem) : (x87_concurrency.fprem * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -632,7 +665,8 @@ static int opFPREM1(uint32_t fetchdat) if (temp64 & 4) cpu_state.npxs|=C0; if (temp64 & 2) cpu_state.npxs|=C3; if (temp64 & 1) cpu_state.npxs|=C1; - CLOCK_CYCLES(x87_timings.fprem1); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fprem1) : (x87_timings.fprem1 * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fprem1) : (x87_concurrency.fprem1 * cpu_multi)); return 0; } #endif @@ -643,7 +677,8 @@ static int opFSQRT(uint32_t fetchdat) cpu_state.pc++; ST(0) = sqrt(ST(0)); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fsqrt); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fsqrt) : (x87_timings.fsqrt * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fsqrt) : (x87_concurrency.fsqrt * cpu_multi)); return 0; } @@ -658,7 +693,8 @@ static int opFSINCOS(uint32_t fetchdat) FP_TAG_VALID; x87_push(cos(td)); cpu_state.npxs &= ~C2; - CLOCK_CYCLES(x87_timings.fsincos); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fsincos) : (x87_timings.fsincos * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fsincos) : (x87_concurrency.fsincos * cpu_multi)); return 0; } #endif @@ -669,7 +705,8 @@ static int opFRNDINT(uint32_t fetchdat) cpu_state.pc++; ST(0) = (double)x87_fround(ST(0)); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.frndint); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); return 0; } @@ -679,9 +716,11 @@ static int opFSCALE(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; temp64 = (int64_t)ST(1); - ST(0) = ST(0) * pow(2.0, (double)temp64); + if(ST(0) != 0.0) + ST(0) = ST(0) * pow(2.0, (double)temp64); FP_TAG_VALID; - CLOCK_CYCLES(x87_timings.fscale); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fscale) : (x87_timings.fscale * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fscale) : (x87_concurrency.fscale * cpu_multi)); return 0; } @@ -693,7 +732,8 @@ static int opFSIN(uint32_t fetchdat) ST(0) = sin(ST(0)); FP_TAG_VALID; cpu_state.npxs &= ~C2; - CLOCK_CYCLES(x87_timings.fsin_cos); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fsin_cos) : (x87_timings.fsin_cos * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fsin_cos) : (x87_concurrency.fsin_cos * cpu_multi)); return 0; } @@ -704,7 +744,8 @@ static int opFCOS(uint32_t fetchdat) ST(0) = cos(ST(0)); FP_TAG_VALID; cpu_state.npxs &= ~C2; - CLOCK_CYCLES(x87_timings.fsin_cos); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fsin_cos) : (x87_timings.fsin_cos * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fsin_cos) : (x87_concurrency.fsin_cos * cpu_multi)); return 0; } #endif @@ -732,7 +773,8 @@ static int FLDENV() cpu_state.TOP = (cpu_state.npxs >> 11) & 7; break; } - CLOCK_CYCLES(x87_timings.fldenv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fldenv) : (x87_timings.fldenv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fldenv) : (x87_concurrency.fldenv * cpu_multi)); return cpu_state.abrt; } @@ -765,7 +807,8 @@ static int opFLDCW_a16(uint32_t fetchdat) if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); - CLOCK_CYCLES(x87_timings.fldcw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fldcw) : (x87_timings.fldcw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fldcw) : (x87_concurrency.fldcw * cpu_multi)); return 0; } #ifndef FPU_8087 @@ -779,7 +822,8 @@ static int opFLDCW_a32(uint32_t fetchdat) if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); - CLOCK_CYCLES(x87_timings.fldcw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fldcw) : (x87_timings.fldcw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fldcw) : (x87_concurrency.fldcw * cpu_multi)); return 0; } #endif @@ -787,6 +831,8 @@ static int opFLDCW_a32(uint32_t fetchdat) static int FSTENV() { FP_ENTER(); + cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | ((cpu_state.TOP & 7) << 11); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ @@ -823,7 +869,8 @@ static int FSTENV() writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); break; } - CLOCK_CYCLES(x87_timings.fstenv); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fstenv) : (x87_timings.fstenv * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fstenv) : (x87_concurrency.fstenv * cpu_multi)); return cpu_state.abrt; } @@ -852,7 +899,8 @@ static int opFSTCW_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.npxc); - CLOCK_CYCLES(x87_timings.fstcw_sw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fstcw_sw) : (x87_timings.fstcw_sw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fstenv) : (x87_concurrency.fstenv * cpu_multi)); return cpu_state.abrt; } #ifndef FPU_8087 @@ -862,7 +910,8 @@ static int opFSTCW_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.npxc); - CLOCK_CYCLES(x87_timings.fstcw_sw); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fstcw_sw) : (x87_timings.fstcw_sw * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fstcw_sw) : (x87_concurrency.fstcw_sw * cpu_multi)); return cpu_state.abrt; } #endif @@ -879,7 +928,7 @@ static int opFSTCW_a32(uint32_t fetchdat) cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; \ ST(0) = ST(fetchdat & 7); \ } \ - CLOCK_CYCLES(4); \ + CLOCK_CYCLES_FPU(4); \ return 0; \ } diff --git a/src/cpu/x87_timings.c b/src/cpu/x87_timings.c index 7443aae72..ca207cc17 100644 --- a/src/cpu/x87_timings.c +++ b/src/cpu/x87_timings.c @@ -8,6 +8,7 @@ #include "x87_timings.h" x87_timings_t x87_timings; +x87_timings_t x87_concurrency; const x87_timings_t x87_timings_8087 = { @@ -313,3 +314,157 @@ const x87_timings_t x87_timings_486 = .fyl2x = (196 + 329) / 2, .fyl2xp1 = (171 + 326) / 2 }; + +/* this should be used for FPUs with no concurrency. +some pre-486DX Cyrix FPUs reportedly are like this. */ +const x87_timings_t x87_concurrency_none = +{ + .f2xm1 = 0, + .fabs = 0, + .fadd = 0, + .fadd_32 = 0, + .fadd_64 = 0, + .fbld = 0, + .fbstp = 0, + .fchs = 0, + .fclex = 0, + .fcom = 0, + .fcom_32 = 0, + .fcom_64 = 0, + .fcos = 0, + .fincdecstp = 0, + .fdisi_eni = 0, + .fdiv = 0, + .fdiv_32 = 0, + .fdiv_64 = 0, + .ffree = 0, + .fadd_i16 = 0, + .fadd_i32 = 0, + .fcom_i16 = 0, + .fcom_i32 = 0, + .fdiv_i16 = 0, + .fdiv_i32 = 0, + .fild_16 = 0, + .fild_32 = 0, + .fild_64 = 0, + .fmul_i16 = 0, + .fmul_i32 = 0, + .finit = 0, + .fist_16 = 0, + .fist_32 = 0, + .fist_64 = 0, + .fld = 0, + .fld_32 = 0, + .fld_64 = 0, + .fld_80 = 0, + .fld_z1 = 0, + .fld_const = 0, + .fldcw = 0, + .fldenv = 0, + .fmul = 0, + .fmul_32 = 0, + .fmul_64 = 0, + .fnop = 0, + .fpatan = 0, + .fprem = 0, + .fprem1 = 0, + .fptan = 0, + .frndint = 0, + .frstor = 0, + .fsave = 0, + .fscale = 0, + .fsetpm = 0, + .fsin_cos = 0, + .fsincos = 0, + .fsqrt = 0, + .fst = 0, + .fst_32 = 0, + .fst_64 = 0, + .fst_80 = 0, + .fstcw_sw = 0, + .fstenv = 0, + .ftst = 0, + .fucom = 0, + .fwait = 0, + .fxam = 0, + .fxch = 0, + .fxtract = 0, + .fyl2x = 0, + .fyl2xp1 = 0, +}; + +const x87_timings_t x87_concurrency_486 = +{ + .f2xm1 = 2, + .fabs = 0, + .fadd = 7, + .fadd_32 = 7, + .fadd_64 = 7, + .fbld = 8, + .fbstp = 0, + .fchs = 0, + .fclex = 0, + .fcom = 1, + .fcom_32 = 1, + .fcom_64 = 1, + .fcos = 2, + .fincdecstp = 0, + .fdisi_eni = 0, + .fdiv = 70, + .fdiv_32 = 70, + .fdiv_64 = 70, + .ffree = 0, + .fadd_i16 = 7, + .fadd_i32 = 7, + .fcom_i16 = 1, + .fcom_i32 = 1, + .fdiv_i16 = 70, + .fdiv_i32 = 70, + .fild_16 = 4, + .fild_32 = 4, + .fild_64 = 8, + .fmul_i16 = 8, + .fmul_i32 = 8, + .finit = 0, + .fist_16 = 0, + .fist_32 = 0, + .fist_64 = 0, + .fld = 0, + .fld_32 = 0, + .fld_64 = 0, + .fld_80 = 0, + .fld_z1 = 0, + .fld_const = 2, + .fldcw = 0, + .fldenv = 0, + .fmul = 13, + .fmul_32 = 8, + .fmul_64 = 11, + .fnop = 0, + .fpatan = 5, + .fprem = 2, + .fprem1 = 6, + .fptan = 70, + .frndint = 0, + .frstor = 0, + .fsave = 0, + .fscale = 2, + .fsetpm = 0, + .fsin_cos = 2, + .fsincos = 2, + .fsqrt = 70, + .fst = 0, + .fst_32 = 0, + .fst_64 = 0, + .fst_80 = 0, + .fstcw_sw = 0, + .fstenv = 0, + .ftst = 1, + .fucom = 1, + .fwait = 0, + .fxam = 0, + .fxch = 0, + .fxtract = 4, + .fyl2x = 13, + .fyl2xp1 = 13, +}; diff --git a/src/cpu/x87_timings.h b/src/cpu/x87_timings.h index ec4f8ceca..6396fcb06 100644 --- a/src/cpu/x87_timings.h +++ b/src/cpu/x87_timings.h @@ -53,4 +53,7 @@ extern const x87_timings_t x87_timings_287; extern const x87_timings_t x87_timings_387; extern const x87_timings_t x87_timings_486; -extern x87_timings_t x87_timings; \ No newline at end of file +extern const x87_timings_t x87_concurrency_486; + +extern x87_timings_t x87_timings; +extern x87_timings_t x87_concurrency; diff --git a/src/ddma.c b/src/ddma.c index 92ee1f4d3..2993add52 100644 --- a/src/ddma.c +++ b/src/ddma.c @@ -184,17 +184,16 @@ ddma_init(const device_t *info) return dev; } - -const device_t ddma_device = -{ - "Distributed DMA", - DEVICE_PCI, - 0, - ddma_init, - ddma_close, - NULL, - NULL, - NULL, - NULL, - NULL +const device_t ddma_device = { + .name = "Distributed DMA", + .internal_name = "ddma", + .flags = DEVICE_PCI, + .local = 0, + .init = ddma_init, + .close = ddma_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device.c b/src/device.c index 9b8cd1d68..331305f2d 100644 --- a/src/device.c +++ b/src/device.c @@ -48,6 +48,8 @@ #include <86box/config.h> #include <86box/device.h> #include <86box/machine.h> +#include <86box/mem.h> +#include <86box/rom.h> #include <86box/sound.h> @@ -90,11 +92,22 @@ device_init(void) void device_set_context(device_context_t *c, const device_t *d, int inst) { + void *sec, *single_sec; + memset(c, 0, sizeof(device_context_t)); c->dev = d; - if (inst) + if (inst) { sprintf(c->name, "%s #%i", d->name, inst); - else + + /* If this is the first instance and a numbered section is not present, but a non-numbered + section of the same name is, rename the non-numbered section to numbered. */ + if (inst == 1) { + sec = config_find_section(c->name); + single_sec = config_find_section((char *) d->name); + if ((sec == NULL) && (single_sec != NULL)) + config_rename_section(single_sec, c->name); + } + } else sprintf(c->name, "%s", d->name); } @@ -181,6 +194,16 @@ device_add_common(const device_t *d, const device_t *cd, void *p, int inst) } +char * +device_get_internal_name(const device_t *d) +{ + if (d == NULL) + return ""; + + return (char *) d->internal_name; +} + + void * device_add(const device_t *d) { @@ -308,13 +331,198 @@ device_get_priv(const device_t *d) int device_available(const device_t *d) { + device_config_t *config; + device_config_bios_t *bios; + int bf, roms_present = 0; + int i = 0; + #ifdef RELEASE_BUILD if (d->flags & DEVICE_NOT_WORKING) return(0); #endif - if (d->available != NULL) - return(d->available()); + if (d != NULL) { + config = (device_config_t *) d->config; + if (config != NULL) { + while (config->type != -1) { + if (config->type == CONFIG_BIOS) { + bios = (device_config_bios_t *) config->bios; - return(1); + /* Go through the ROM's in the device configuration. */ + while (bios->files_no != 0) { + i = 0; + for (bf = 0; bf < bios->files_no; bf++) + i += !!rom_present((char *) bios->files[bf]); + if (i == bios->files_no) + roms_present++; + bios++; + } + + return(roms_present ? -1 : 0); + } + config++; + } + } + + /* No CONFIG_BIOS field present, use the classic available(). */ + if (d->available != NULL) + return(d->available()); + else + return(1); + } + + /* A NULL device is never available. */ + return(0); +} + + +int +device_has_config(const device_t *d) +{ + int c = 0; + device_config_t *config; + + if (d == NULL) + return 0; + + if (d->config == NULL) + return 0; + + config = (device_config_t *) d->config; + + while (config->type != -1) { + if (config->type != CONFIG_MAC) + c++; + config++; + } + + return (c > 0) ? 1 : 0; +} + + +int +device_poll(const device_t *d, int x, int y, int z, int b) +{ + int c; + + for (c = 0; c < DEVICE_MAX; c++) { + if (devices[c] != NULL) { + if (devices[c] == d) { + if (devices[c]->poll) + return(devices[c]->poll(x, y, z, b, device_priv[c])); + } + } + } + + return(0); +} + + +void +device_register_pci_slot(const device_t *d, int device, int type, int inta, int intb, int intc, int intd) +{ + int c; + + for (c = 0; c < DEVICE_MAX; c++) { + if (devices[c] != NULL) { + if (devices[c] == d) { + if (devices[c]->register_pci_slot) + devices[c]->register_pci_slot(device, type, inta, intb, intc, intd, device_priv[c]); + return; + } + } + } + + return; +} + + +void +device_get_name(const device_t *d, int bus, char *name) +{ + char *sbus = NULL, *fbus; + char *tname, pbus[8] = { 0 }; + + if (d == NULL) + return; + + name[0] = 0x00; + + if (bus) { + if (d->flags & DEVICE_ISA) + sbus = (d->flags & DEVICE_AT) ? "ISA16" : "ISA"; + else if (d->flags & DEVICE_CBUS) + sbus = "C-BUS"; + else if (d->flags & DEVICE_MCA) + sbus = "MCA"; + else if (d->flags & DEVICE_EISA) + sbus = "EISA"; + else if (d->flags & DEVICE_VLB) + sbus = "VLB"; + else if (d->flags & DEVICE_PCI) + sbus = "PCI"; + else if (d->flags & DEVICE_AGP) + sbus = "AGP"; + else if (d->flags & DEVICE_AC97) + sbus = "AMR"; + else if (d->flags & DEVICE_COM) + sbus = "COM"; + else if (d->flags & DEVICE_LPT) + sbus = "LPT"; + + if (sbus != NULL) { + /* First concatenate [] before the device's name. */ + strcat(name, "["); + strcat(name, sbus); + strcat(name, "] "); + + /* Then change string from ISA16 to ISA if applicable. */ + if (!strcmp(sbus, "ISA16")) + sbus = "ISA"; + else if (!strcmp(sbus, "COM")|| !strcmp(sbus, "LPT")) { + sbus = NULL; + strcat(name, d->name); + return; + } + + /* Generate the bus string with parentheses. */ + strcat(pbus, "("); + strcat(pbus, sbus); + strcat(pbus, ")"); + + /* Allocate the temporary device name string and set it to all zeroes. */ + tname = (char *) malloc(strlen(d->name) + 1); + memset(tname, 0x00, strlen(d->name) + 1); + + /* First strip the bus string with parentheses. */ + fbus = strstr(d->name, pbus); + if (fbus == d->name) + strcat(tname, d->name + strlen(pbus) + 1); + else if (fbus == NULL) + strcat(tname, d->name); + else { + strncat(tname, d->name, fbus - d->name - 1); + strcat(tname, fbus + strlen(pbus)); + } + + /* Then also strip the bus string with parentheses. */ + 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) == '-')) + strcat(name, tname); + else { + strncat(name, tname, fbus - tname - 1); + strcat(name, fbus + strlen(sbus)); + } + + /* Free the temporary device name string. */ + free(tname); + tname = NULL; + } else + strcat(name, d->name); + } else + strcat(name, d->name); } @@ -509,27 +717,29 @@ device_set_config_mac(const char *s, int val) int -device_is_valid(const device_t *device, int mflags) +device_is_valid(const device_t *device, int m) { if (device == NULL) return(1); - if ((device->flags & DEVICE_AT) && !(mflags & MACHINE_AT)) return(0); + if ((device->flags & DEVICE_AT) && !machine_has_bus(m, MACHINE_BUS_ISA16)) return(0); - if ((device->flags & DEVICE_CBUS) && !(mflags & MACHINE_CBUS)) return(0); + if ((device->flags & DEVICE_CBUS) && !machine_has_bus(m, MACHINE_BUS_CBUS)) return(0); - if ((device->flags & DEVICE_ISA) && !(mflags & MACHINE_ISA)) return(0); + if ((device->flags & DEVICE_ISA) && !machine_has_bus(m, MACHINE_BUS_ISA)) return(0); - if ((device->flags & DEVICE_MCA) && !(mflags & MACHINE_MCA)) return(0); + if ((device->flags & DEVICE_MCA) && !machine_has_bus(m, MACHINE_BUS_MCA)) return(0); - if ((device->flags & DEVICE_EISA) && !(mflags & MACHINE_EISA)) return(0); + if ((device->flags & DEVICE_EISA) && !machine_has_bus(m, MACHINE_BUS_EISA)) return(0); - if ((device->flags & DEVICE_VLB) && !(mflags & MACHINE_VLB)) return(0); + if ((device->flags & DEVICE_VLB) && !machine_has_bus(m, MACHINE_BUS_VLB)) return(0); - if ((device->flags & DEVICE_PCI) && !(mflags & MACHINE_PCI)) return(0); + if ((device->flags & DEVICE_PCI) && !machine_has_bus(m, MACHINE_BUS_PCI)) return(0); - if ((device->flags & DEVICE_AGP) && !(mflags & MACHINE_AGP)) return(0); + if ((device->flags & DEVICE_AGP) && !machine_has_bus(m, MACHINE_BUS_AGP)) return(0); - if ((device->flags & DEVICE_PS2) && !(mflags & MACHINE_PS2)) return(0); + if ((device->flags & DEVICE_PS2) && !machine_has_bus(m, MACHINE_BUS_PS2)) return(0); + + if ((device->flags & DEVICE_AC97) && !machine_has_bus(m, MACHINE_BUS_AC97)) return(0); return(1); } diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt new file mode 100644 index 000000000..658da7280 --- /dev/null +++ b/src/device/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c + hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c + postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c + smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c + mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) + +if(ISAMEM_RAMPAGE) + target_compile_definitions(dev PRIVATE USE_ISAMEM_RAMPAGE) +endif() + +if(ISAMEM_IAB) + target_compile_definitions(dev PRIVATE USE_ISAMEM_IAB) +endif() + +if(ISAMEM_BRAT) + target_compile_definitions(dev PRIVATE USE_ISAMEM_BRAT) +endif() + +if(LASERXT) + target_compile_definitions(dev PRIVATE USE_LASERXT) +endif() diff --git a/src/device/bugger.c b/src/device/bugger.c index 492261fe2..bcea70af3 100644 --- a/src/device/bugger.c +++ b/src/device/bugger.c @@ -268,7 +268,7 @@ bug_reset(void) /* Clear both 7SEG displays. */ bug_seg1 = 0x00; bug_seg2 = 0x00; - + /* Reset the control register (updates UI.) */ bug_wctrl(CTRL_RESET); } @@ -351,15 +351,19 @@ static void bug_close(UNUSED(void *priv)) { io_removehandler(BUGGER_ADDR, BUGGER_ADDRLEN, - bug_read, NULL, NULL, bug_write, NULL, NULL, NULL); + bug_read, NULL, NULL, bug_write, NULL, NULL, NULL); } - const device_t bugger_device = { - "ISA/PCI Bus Bugger", - DEVICE_ISA | DEVICE_AT, - 0, - bug_init, bug_close, NULL, - NULL, NULL, NULL, - NULL + .name = "ISA/PCI Bus Bugger", + .internal_name = "bugger", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = bug_init, + .close = bug_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/cartridge.c b/src/device/cartridge.c new file mode 100644 index 000000000..9743c2e87 --- /dev/null +++ b/src/device/cartridge.c @@ -0,0 +1,210 @@ +/* + * 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 PCjr cartridge emulation. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/mem.h> +#include <86box/machine.h> +#include <86box/cartridge.h> + + +typedef struct +{ + uint8_t * buf; + uint32_t base; +} cart_t; + + +char cart_fns[2][512]; + + +static cart_t carts[2]; + +static mem_mapping_t cart_mappings[2]; + + +#ifdef ENABLE_CARTRIDGE_LOG +int cartridge_do_log = ENABLE_CARTRIDGE_LOG; + + +static void +cartridge_log(const char *fmt, ...) +{ + va_list ap; + + if (cartridge_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cartridge_log(fmt, ...) +#endif + + +static uint8_t +cart_read(uint32_t addr, void *priv) +{ + cart_t *dev = (cart_t *) priv; + + return dev->buf[addr - dev->base]; +} + + +static void +cart_load_error(int drive, char *fn) +{ + cartridge_log("Cartridge: could not load '%s'\n",fn); + memset(cart_fns[drive], 0, sizeof(cart_fns[drive])); + ui_sb_update_icon_state(SB_CARTRIDGE | drive, 1); +} + + +static void +cart_image_close(int drive) +{ + if (carts[drive].buf != NULL) { + free(carts[drive].buf); + carts[drive].buf = NULL; + } + + carts[drive].base = 0x00000000; + + mem_mapping_disable(&cart_mappings[drive]); +} + + +static void +cart_image_load(int drive, char *fn) +{ + FILE *f; + uint32_t size; + uint32_t base = 0x00000000; + + cart_image_close(drive); + + f = fopen(fn, "rb"); + if (fseek(f, 0, SEEK_END) == -1) + fatal("cart_image_load(): Error seeking to the end of the file\n"); + size = ftell(f); + if (size < 0x1200) { + cartridge_log("cart_image_load(): File size %i is too small\n", size); + cart_load_error(drive, fn); + return; + } + if (size & 0x00000fff) { + size -= 0x00000200; + fseek(f, 0x000001ce, SEEK_SET); + fread(&base, 1, 2, f); + base <<= 4; + fseek(f, 0x00000200, SEEK_SET); + carts[drive].buf = (uint8_t *) malloc(size); + memset(carts[drive].buf, 0x00, size); + fread(carts[drive].buf, 1, size, f); + fclose(f); + } else { + base = drive ? 0xe0000 : 0xd0000; + if (size == 32768) + base += 0x8000; + fseek(f, 0x00000000, SEEK_SET); + carts[drive].buf = (uint8_t *) malloc(size); + memset(carts[drive].buf, 0x00, size); + fread(carts[drive].buf, 1, size, f); + fclose(f); + } + + cartridge_log("cart_image_load(): %s at %08X-%08X\n", fn, base, base + size - 1); + carts[drive].base = base; + mem_mapping_set_addr(&cart_mappings[drive], base, size); + mem_mapping_set_exec(&cart_mappings[drive], carts[drive].buf); + mem_mapping_set_p(&cart_mappings[drive], &(carts[drive])); +} + + +static void +cart_load_common(int drive, char *fn, uint8_t hard_reset) +{ + FILE *f; + + cartridge_log("Cartridge: loading drive %d with '%s'\n", drive, fn); + + if (!fn) + return; + f = plat_fopen(fn, "rb"); + if (f) { + fclose(f); + strcpy(cart_fns[drive], fn); + cart_image_load(drive, cart_fns[drive]); + /* On the real PCjr, inserting a cartridge causes a reset + in order to boot from the cartridge. */ + if (!hard_reset) + resetx86(); + } else + cart_load_error(drive, fn); +} + + +void +cart_load(int drive, char *fn) +{ + cart_load_common(drive, fn, 0); +} + + +void +cart_close(int drive) +{ + cartridge_log("Cartridge: closing drive %d\n", drive); + + cart_image_close(drive); + cart_fns[drive][0] = 0; + ui_sb_update_icon_state(SB_CARTRIDGE | drive, 1); +} + + +void +cart_reset(void) +{ + int i; + + cart_image_close(1); + cart_image_close(0); + + if (!machine_has_cartridge(machine)) + return; + + for (i = 0; i < 2; i++) { + mem_mapping_add(&cart_mappings[i], 0x000d0000, 0x00002000, + cart_read,NULL,NULL, + NULL,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, NULL); + mem_mapping_disable(&cart_mappings[i]); + } + + cart_load_common(0, cart_fns[0], 1); + cart_load_common(1, cart_fns[1], 1); +} diff --git a/src/device/cassette.c b/src/device/cassette.c new file mode 100644 index 000000000..211909dcb --- /dev/null +++ b/src/device/cassette.c @@ -0,0 +1,728 @@ +/***************************************************************************** + * pce * + *****************************************************************************/ + +/***************************************************************************** + * File name: src/arch/ibmpc/cassette.c * + * Created: 2008-11-25 by Hampa Hug * + * Copyright: (C) 2008-2019 Hampa Hug * + *****************************************************************************/ + +/***************************************************************************** + * This program is free software. You can redistribute it and / or modify it * + * under the terms of the GNU General Public License version 2 as published * + * by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY, without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * + * Public License for more details. * + *****************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/cassette.h> + +// #include + + +#define CAS_CLK 1193182 + + +pc_cassette_t * cassette; + +char cassette_fname[512]; +char cassette_mode[512]; +unsigned long cassette_pos, cassette_srate; +int cassette_enable; +int cassette_append, cassette_pcm; +int cassette_ui_writeprot; + + +static int cassette_cycles = -1; + + +static void pc_cas_reset (pc_cassette_t *cas); + + +#ifdef ENABLE_CASSETTE_LOG +int cassette_do_log = ENABLE_CASSETTE_LOG; + + +static void +cassette_log(const char *fmt, ...) +{ + va_list ap; + + if (cassette_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cassette_log(fmt, ...) +#endif + + +void pc_cas_init (pc_cassette_t *cas) +{ + cas->save = 0; + cas->pcm = 0; + + cas->motor = 0; + ui_sb_update_icon(SB_CASSETTE, 0); + + cas->position = 0; + + cas->position_save = 0; + cas->position_load = 0; + + cas->data_out = 0; + cas->data_inp = 0; + + cas->pcm_out_vol = 64; + cas->pcm_out_val = 0; + + cas->cas_out_cnt = 0; + cas->cas_out_buf = 0; + + cas->cas_inp_cnt = 0; + cas->cas_inp_buf = 0; + cas->cas_inp_bit = 0; + + cas->clk = 0; + + cas->clk_pcm = 0; + + cas->clk_out = 0; + cas->clk_inp = 0; + + cas->srate = 44100; + + cas->close = 0; + cas->fname = NULL; + cas->fp = NULL; + + pc_cas_reset (cas); +} + +void pc_cas_free (pc_cassette_t *cas) +{ + free (cas->fname); + + if (cas->close) { + fclose (cas->fp); + } +} + +pc_cassette_t *pc_cas_new (void) +{ + pc_cassette_t *cas; + + cas = malloc (sizeof (pc_cassette_t)); + + if (cas == NULL) { + return (NULL); + } + + pc_cas_init (cas); + + return (cas); +} + +void pc_cas_del (pc_cassette_t *cas) +{ + if (cas != NULL) { + pc_cas_free (cas); + free (cas); + } +} + +int pc_cas_set_fname (pc_cassette_t *cas, const char *fname) +{ + unsigned n; + const char * ext; + + if (cas->close) + fclose (cas->fp); + + cas->close = 0; + cas->fp = NULL; + + free (cas->fname); + cas->fname = NULL; + + cas->position = 0; + + cas->position_save = 0; + cas->position_load = 0; + + if (fname == NULL) { + ui_sb_update_icon_state(SB_CASSETTE, 1); + return (0); + } + + cas->fp = plat_fopen (fname, "r+b"); + + if (cas->fp == NULL) + cas->fp = plat_fopen (fname, "w+b"); + + if (cas->fp == NULL) { + ui_sb_update_icon_state(SB_CASSETTE, 1); + return (1); + } + + cas->close = 1; + + pc_cas_append (cas); + + cas->position_save = cas->position; + + if (cas->save == 0) + pc_cas_set_position (cas, 0); + + n = strlen (fname); + + cas->fname = malloc ((n + 1) * sizeof(char)); + + if (cas->fname != NULL) + memcpy (cas->fname, fname, (n + 1) * sizeof(char)); + + if (n > 4) { + ext = fname + (n - 4); + + /* Has to be 44.1 kHz, mono, 8-bit. */ + if (stricmp (ext, ".pcm") == 0) + pc_cas_set_pcm (cas, 1); + else if (stricmp (ext, ".raw") == 0) + pc_cas_set_pcm (cas, 1); + else if (stricmp (ext, ".wav") == 0) + pc_cas_set_pcm (cas, 1); + else if (stricmp (ext, ".cas") == 0) + pc_cas_set_pcm (cas, 0); + } + + return (0); +} + +static +void pc_cas_reset (pc_cassette_t *cas) +{ + unsigned i; + + cas->clk_pcm = 0; + + cas->clk_out = cas->clk; + cas->clk_inp = 0; + + cas->pcm_out_val = 0; + + cas->cas_out_cnt = 0; + cas->cas_out_buf = 0; + + cas->cas_inp_cnt = 0; + cas->cas_inp_buf = 0; + cas->cas_inp_bit = 0; + + for (i = 0; i < 3; i++) { + cas->pcm_inp_fir[i] = 0; + } +} + +int pc_cas_get_mode (const pc_cassette_t *cas) +{ + return (cas->save); +} + +void pc_cas_set_mode (pc_cassette_t *cas, int save) +{ + save = (save != 0); + + if (cas->save == save) { + return; + } + + if (cas->save) { + cas->position_save = cas->position; + cas->position = cas->position_load; + } + else { + cas->position_load = cas->position; + cas->position = cas->position_save; + } + + cas->save = save; + + memset(cassette_mode, 0x00, sizeof(cassette_mode)); + if (save) + memcpy(cassette_mode, "save", strlen("save") + 1); + else + memcpy(cassette_mode, "load", strlen("load") + 1); + + if (cas->fp != NULL) { + fflush (cas->fp); + + pc_cas_set_position (cas, cas->position); + } + + pc_cas_reset (cas); +} + +int pc_cas_get_pcm (const pc_cassette_t *cas) +{ + return (cas->pcm); +} + +void pc_cas_set_pcm (pc_cassette_t *cas, int pcm) +{ + cas->pcm = (pcm != 0); + + cassette_pcm = (pcm != 0); + + pc_cas_reset (cas); +} + +unsigned long pc_cas_get_srate (const pc_cassette_t *cas) +{ + return (cas->srate); +} + +void pc_cas_set_srate (pc_cassette_t *cas, unsigned long srate) +{ + cas->srate = srate; + + pc_cas_reset (cas); +} + +void pc_cas_rewind (pc_cassette_t *cas) +{ + if (cas->fp != NULL) { + rewind (cas->fp); + cas->position = 0; + } + + pc_cas_reset (cas); +} + +void pc_cas_append (pc_cassette_t *cas) +{ + if (cas->fp != NULL) { + fseek (cas->fp, 0, SEEK_END); + cas->position = ftell (cas->fp); + } + + pc_cas_reset (cas); +} + +unsigned long pc_cas_get_position (const pc_cassette_t *cas) +{ + return (cas->position); +} + +int pc_cas_set_position (pc_cassette_t *cas, unsigned long pos) +{ + if (cas->fp == NULL) { + return (1); + } + + if (fseek (cas->fp, pos, SEEK_SET) != 0) { + return (1); + } + + cas->position = pos; + + pc_cas_reset (cas); + + return (0); +} + +static +void pc_cas_read_bit (pc_cassette_t *cas) +{ + int val; + + if (cas->cas_inp_cnt == 0) { + if (cas->fp == NULL) { + return; + } + + if (feof (cas->fp)) { + return; + } + + val = fgetc (cas->fp); + + if (val == EOF) { + cassette_log ("cassette EOF at %lu\n", cas->position); + return; + } + + cas->position += 1; + + cas->cas_inp_cnt = 8; + cas->cas_inp_buf = val; + } + + cas->cas_inp_bit = ((cas->cas_inp_buf & 0x80) != 0); + + cas->cas_inp_buf = (cas->cas_inp_buf << 1) & 0xff; + cas->cas_inp_cnt -= 1; +} + +static +int pc_cas_read_smp (pc_cassette_t *cas) +{ + int smp, *fir; + + if (feof (cas->fp)) { + return (0); + } + + smp = fgetc (cas->fp); + + if (smp == EOF) { + cassette_log ("cassette EOF at %lu\n", cas->position); + return (0); + } + + cas->position += 1; + + fir = cas->pcm_inp_fir; + + fir[0] = fir[1]; + fir[1] = fir[2]; + fir[2] = (smp & 0x80) ? (smp - 256) : smp; + + smp = (fir[0] + 2 * fir[1] + fir[2]) / 4; + + return (smp); +} + +static +void pc_cas_write_bit (pc_cassette_t *cas, unsigned char val) +{ + if (val && !cassette_ui_writeprot) { + cas->cas_out_buf |= (0x80 >> cas->cas_out_cnt); + } + + cas->cas_out_cnt += 1; + + if (cas->cas_out_cnt >= 8) { + if (cas->fp != NULL) { + if (!cassette_ui_writeprot) + fputc (cas->cas_out_buf, cas->fp); + cas->position += 1; + } + + cas->cas_out_buf = 0; + cas->cas_out_cnt = 0; + } +} + +static +void pc_cas_write_smp (pc_cassette_t *cas, int val) +{ + unsigned char smp; + + if (val < 0) { + smp = (val < -127) ? 0x80 : (val + 256); + } + else { + smp = (val > 127) ? 0x7f : val; + } + + if (!cassette_ui_writeprot) + fputc (smp, cas->fp); + + cas->position += 1; +} + +void pc_cas_set_motor (pc_cassette_t *cas, unsigned char val) +{ + unsigned i; + + val = (val != 0); + + if (val == cas->motor) { + return; + } + + if ((val == 0) && cas->save && cas->pcm) { + for (i = 0; i < (cas->srate / 16); i++) { + pc_cas_write_smp (cas, 0); + } + } + + cassette_log ("cassette %S at %lu motor %s\n", (cas->fname != NULL) ? cas->fname : "", cas->position, val ? "on" : "off"); + + cas->motor = val; + + if (cas->fp != NULL) { + fflush (cas->fp); + + pc_cas_set_position (cas, cas->position); + } + + pc_cas_reset (cas); + + if (cas->motor) + timer_set_delay_u64(&cas->timer, 8ULL * PITCONST); + else + timer_disable(&cas->timer); + + ui_sb_update_icon(SB_CASSETTE, !!val); +} + +unsigned char pc_cas_get_inp (const pc_cassette_t *cas) +{ + return (cas->data_inp); +} + +void pc_cas_set_out (pc_cassette_t *cas, unsigned char val) +{ + unsigned long clk; + + val = (val != 0); + + if (cas->motor == 0) { + cas->data_inp = val; + return; + } + + if (cas->data_out == val) { + return; + } + + cas->data_out = val; + + if (cas->pcm) { + cas->pcm_out_val = val ? -cas->pcm_out_vol : cas->pcm_out_vol; + return; + } + + if (cas->save == 0) { + return; + } + + if (val == 0) { + return; + } + + clk = cas->clk - cas->clk_out; + cas->clk_out = cas->clk; + + if (clk < (CAS_CLK / 4000)) { + ; + } + else if (clk < ((3 * CAS_CLK) / 4000)) { + pc_cas_write_bit (cas, 0); + } + else if (clk < ((5 * CAS_CLK) / 4000)) { + pc_cas_write_bit (cas, 1); + } +} + +void pc_cas_print_state (const pc_cassette_t *cas) +{ + cassette_log ("%s %s %lu %s %lu\n", (cas->fname != NULL) ? cas->fname : "", cas->pcm ? "pcm" : "cas", cas->srate, cas->save ? "save" : "load", cas->position); +} + +static +void pc_cas_clock_pcm (pc_cassette_t *cas, unsigned long cnt) +{ + unsigned long i, n; + int v = 0; + + n = cas->srate * cnt + cas->clk_pcm; + + cas->clk_pcm = n % CAS_CLK; + + n = n / CAS_CLK; + + if (n == 0) { + return; + } + + if (cas->save) { + for (i = 0; i < n; i++) { + pc_cas_write_smp (cas, cas->pcm_out_val); + } + } + else { + for (i = 0; i < n; i++) { + v = pc_cas_read_smp (cas); + } + + cas->data_inp = (v < 0) ? 0 : 1; + } +} + +void pc_cas_clock (pc_cassette_t *cas, unsigned long cnt) +{ + cas->clk += cnt; + + if (cas->motor == 0) { + return; + } + + if (cas->pcm) { + pc_cas_clock_pcm (cas, cnt); + return; + } + + if (cas->save) { + return; + } + + if (cas->clk_inp > cnt) { + cas->clk_inp -= cnt; + return; + } + + cnt -= cas->clk_inp; + + cas->data_inp = !cas->data_inp; + + if (cas->data_inp) { + pc_cas_read_bit (cas); + } + + if (cas->cas_inp_bit) { + cas->clk_inp = CAS_CLK / 2000; + } + else { + cas->clk_inp = CAS_CLK / 4000; + } + + if (cas->clk_inp > cnt) { + cas->clk_inp -= cnt; + } +} + + +void pc_cas_advance (pc_cassette_t *cas) +{ + int ticks; + cpu_s = (CPU *) &cpu_f->cpus[cpu_effective]; + + if (cas->motor == 0) + return; + + if (cassette_cycles == -1) + cassette_cycles = cycles; + if (cycles <= cassette_cycles) + ticks = (cassette_cycles - cycles); + else + ticks = (cassette_cycles + (cpu_s->rspeed / 100) - cycles); + cassette_cycles = cycles; + + pc_cas_clock(cas, ticks); +} + + +static void +cassette_close(void *p) +{ + if (cassette != NULL) { + free(cassette); + cassette = NULL; + } +} + + +static void +cassette_callback(void *p) +{ + pc_cassette_t *cas = (pc_cassette_t *) p; + + pc_cas_clock (cas, 8); + + if (cas->motor) + ui_sb_update_icon(SB_CASSETTE, 1); + + timer_advance_u64(&cas->timer, 8ULL * PITCONST); +} + + +static void * +cassette_init(const device_t *info) +{ + cassette = NULL; + + if (cassette_pcm == 1) + cassette_pcm = -1; + + cassette_log("CASSETTE: file=%s mode=%s pcm=%d srate=%lu pos=%lu append=%d\n", + (cassette_fname != NULL) ? cassette_fname : "", cassette_mode, cassette_pcm, cassette_srate, cassette_pos, cassette_append); + + cassette = pc_cas_new(); + + if (cassette == NULL) { + cassette_log("ERROR: *** alloc failed\n"); + return NULL; + } + + if (strlen(cassette_fname) == 0) { + if (pc_cas_set_fname (cassette, NULL)) { + cassette_log("ERROR: *** opening file failed (%s)\n", cassette_fname); + } + } else { + if (pc_cas_set_fname (cassette, cassette_fname)) { + cassette_log("ERROR: *** opening file failed (%s)\n", cassette_fname); + } + } + + if (strcmp (cassette_mode, "load") == 0) + pc_cas_set_mode (cassette, 0); + else if (strcmp (cassette_mode, "save") == 0) + pc_cas_set_mode (cassette, 1); + else { + cassette_log ("ERROR: *** unknown cassette mode (%s)\n", cassette_mode); + } + + if (cassette_append) + pc_cas_append (cassette); + else + pc_cas_set_position (cassette, cassette_pos); + + if (cassette_pcm >= 0) + pc_cas_set_pcm (cassette, cassette_pcm); + + pc_cas_set_srate (cassette, cassette_srate); + + timer_add(&cassette->timer, cassette_callback, cassette, 0); + + return cassette; +} + + +const device_t cassette_device = { + .name = "IBM PC/PCjr Cassette Device", + .internal_name = "cassette", + .flags = 0, + .local = 0, + .init = cassette_init, + .close = cassette_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/clock_ics9xxx.c b/src/device/clock_ics9xxx.c new file mode 100644 index 000000000..da4de6c43 --- /dev/null +++ b/src/device/clock_ics9xxx.c @@ -0,0 +1,1292 @@ +/* + * 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 the ICS9xxx series of clock generators. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/i2c.h> +#include "cpu.h" +#include <86box/clock.h> + + +#ifdef ENABLE_ICS9xxx_LOG +int ics9xxx_do_log = ENABLE_ICS9xxx_LOG; + + +static void +ics9xxx_log(const char *fmt, ...) +{ + va_list ap; + + if (ics9xxx_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#define ICS9xxx_MODEL(model) [model] = {.name = #model, +#else +#define ics9xxx_log(fmt, ...) +#define ICS9xxx_MODEL(model) [model] = { +#endif +#define ICS9xxx_MODEL_END() }, +#define agp_div ram_mult /* temporarily saves space while neither field matters */ + + + +typedef struct { + uint16_t bus: 15; + uint8_t ram_mult: 2; /* change to full float when this becomes useful */ + uint8_t pci_div: 3; +} ics9xxx_frequency_t; + +typedef struct { +#if defined(ENABLE_ICS9xxx_LOG) || defined(ENABLE_ICS9xxx_DETECT) + const char *name; /* populated by macro */ +#endif + uint8_t max_reg: 3; /* largest register index */ + uint8_t regs[7]; /* default registers */ + struct { /* for each hardware frequency select bit [FS0:FS4]: */ + uint8_t normal_reg: 3; /* which register (or -1) for non-inverted input (FSn) */ + uint8_t normal_bit: 3; /* which bit (0-7) for non-inverted input (FSn) */ + uint8_t inv_reg: 3; /* which register (or -1) for inverted input (FSn#) */ + uint8_t inv_bit: 3; /* which bit (0-7) for inverted input (FSn#) */ + } fs_regs[5]; + uint8_t normal_bits_fixed: 1; /* set to 1 if the non-inverted bits are straps (hardware select only) */ + struct { /* hardware select bit, which should be cleared for hardware select (latched inputs), or set for programming */ + uint8_t normal_reg: 3; /* which register (or -1) */ + uint8_t normal_bit: 3; /* which bit (0-7) */ + } hw_select; + + uint8_t frequencies_ref; /* which other model to use the frequency table from (or 0) */ + const ics9xxx_frequency_t *frequencies; /* frequency table, if not using another model's table */ +} ics9xxx_model_t; + +typedef struct { + uint8_t model_idx; + ics9xxx_model_t *model; + device_t *dyn_device; + + ics9xxx_frequency_t *frequencies_ptr; + uint8_t regs[7]; + int8_t addr_register: 4; + uint8_t relevant_regs: 7; + uint8_t bus_match: 5; +} ics9xxx_t; + + +static const ics9xxx_model_t ics9xxx_models[] = { +#ifdef ENABLE_ICS9xxx_DETECT + ICS9xxx_MODEL(ICS9xxx_xx) + .max_reg = 6 + ICS9xxx_MODEL_END() +#endif + ICS9xxx_MODEL(ICS9150_08) + .max_reg = 5, + .regs = {0x00, 0xff, 0xff, 0xff, 0x6f, 0xbf}, + .fs_regs = {{0, 4, 4, 7}, {0, 5, 4, 4}, {0, 6, 5, 6}, {0, 7, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 5000, .pci_div = 2}, + {.bus = 7500, .pci_div = 2}, + {.bus = 8333, .pci_div = 2}, + {.bus = 6680, .pci_div = 2}, + {.bus = 10300, .pci_div = 3}, + {.bus = 11200, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {.bus = 10020, .pci_div = 3}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_39) + .max_reg = 5, + .regs = {0x00, 0x7f, 0xff, 0xbf, 0xf5, 0xff}, + .fs_regs = {{0, 4, 3, 6}, {0, 5, 4, 3}, {0, 6, 1, 7}, {0, 7, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies_ref = ICS9250_08 + ICS9xxx_MODEL_END() +#ifdef ENABLE_ICS9xxx_DETECT + ICS9xxx_MODEL(ICS9248_81) + .max_reg = 5, + .regs = {0x82, 0xfe, 0x7f, 0xff, 0xff, 0xb7}, + .fs_regs = {{0, 4, 1, 0}, {0, 5, 2, 7}, {0, 6, 5, 6}, {0, 2, 5, 3}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 9000, .ram_mult = 1, .pci_div = 3}, + {.bus = 6670, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 9500, .ram_mult = 2.0/3.0, .pci_div = 3}, + {.bus = 10000, .ram_mult = 2.0/3.0, .pci_div = 3}, + {.bus = 10000, .ram_mult = 0.75, .pci_div = 3}, + {.bus = 11200, .ram_mult = 2.0/3.0, .pci_div = 3}, + {.bus = 12400, .ram_mult = 2.0/3.0, .pci_div = 4}, + {.bus = 13330, .ram_mult = 2.0/3.0, .pci_div = 4}, + {.bus = 6670, .ram_mult = 1, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1, .pci_div = 3}, + {.bus = 8330, .ram_mult = 1, .pci_div = 3}, + {.bus = 9500, .ram_mult = 1, .pci_div = 3}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 11200, .ram_mult = 1, .pci_div = 3}, + {.bus = 12400, .ram_mult = 1, .pci_div = 4}, + {.bus = 13330, .ram_mult = 1, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_95) + .max_reg = 5, + .regs = {0x82, 0xff, 0xff, 0xff, 0xd5, 0xff}, + .fs_regs = {{0, 4, -1, -1}, {0, 5, 4, 3}, {0, 6, -1, -1}, {0, 2, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6667, .pci_div = 2}, + {.bus = 10000, .pci_div = 3}, + {.bus = 10030, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {.bus = 10500, .pci_div = 3}, + {.bus = 13337, .pci_div = 4}, + {.bus = 13700, .pci_div = 4}, + {.bus = 7500, .pci_div = 2}, + {.bus = 10000, .pci_div = 3}, + {.bus = 9500, .pci_div = 2}, + {.bus = 9700, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {.bus = 9000, .pci_div = 3}, + {.bus = 9622, .pci_div = 3}, + {.bus = 6681, .pci_div = 2}, + {.bus = 9150, .pci_div = 3}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_98) + .max_reg = 6, + .regs = {0x00, 0x7f, 0xff, 0xbf, 0xf5, 0xff, 0x06}, + .fs_regs = {{0, 4, 3, 6}, {0, 5, 4, 3}, {0, 6, 1, 7}, {0, 7, 4, 1}, {0, 2, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 8000, .pci_div = 2}, + {.bus = 7500, .pci_div = 2}, + {.bus = 8331, .pci_div = 2}, + {.bus = 6682, .pci_div = 2}, + {.bus = 10300, .pci_div = 3}, + {.bus = 11201, .pci_div = 3}, + {.bus = 6801, .pci_div = 2}, + {.bus = 10023, .pci_div = 3}, + {.bus = 12000, .pci_div = 3}, + {.bus = 11499, .pci_div = 3}, + {.bus = 10999, .pci_div = 3}, + {.bus = 10500, .pci_div = 3}, + {.bus = 14000, .pci_div = 4}, + {.bus = 15000, .pci_div = 4}, + {.bus = 12400, .pci_div = 4}, + {.bus = 13299, .pci_div = 4}, + {.bus = 13500, .pci_div = 4}, + {.bus = 12999, .pci_div = 4}, + {.bus = 12600, .pci_div = 4}, + {.bus = 11800, .pci_div = 3}, + {.bus = 11598, .pci_div = 3}, + {.bus = 9500, .pci_div = 3}, + {.bus = 9000, .pci_div = 3}, + {.bus = 8501, .pci_div = 3}, + {.bus = 16600, .pci_div = 4}, + {.bus = 16001, .pci_div = 4}, + {.bus = 15499, .pci_div = 4}, + {.bus = 14795, .pci_div = 4}, + {.bus = 14598, .pci_div = 4}, + {.bus = 14398, .pci_div = 4}, + {.bus = 14199, .pci_div = 4}, + {.bus = 13801, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_101) + .max_reg = 5, + .regs = {0x82, 0xff, 0xff, 0xff, 0xf5, 0xff}, + .fs_regs = {{0, 4, -1, -1}, {0, 5, 4, 3}, {0, 6, -1, -1}, {0, 2, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 12400, .pci_div = 3}, + {.bus = 12000, .pci_div = 3}, + {.bus = 11499, .pci_div = 3}, + {.bus = 10999, .pci_div = 3}, + {.bus = 10500, .pci_div = 3}, + {.bus = 8331, .pci_div = 2}, + {.bus = 13700, .pci_div = 4}, + {.bus = 7500, .pci_div = 2}, + {.bus = 10000, .pci_div = 3}, + {.bus = 9500, .pci_div = 3}, + {.bus = 8331, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {.bus = 9000, .pci_div = 3}, + {.bus = 9622, .pci_div = 3}, + {.bus = 6682, .pci_div = 2}, + {.bus = 9150, .pci_div = 3}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_103) + .max_reg = 5, + .regs = {0x82, 0xff, 0xff, 0xff, 0xf5, 0xff}, + .fs_regs = {{0, 4, -1, -1}, {0, 5, 4, 3}, {0, 6, -1, -1}, {0, 2, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies_ref = ICS9248_101 + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_107) + .max_reg = 6, + .regs = {0x02, 0xff, 0xff, 0xec, 0xde, 0xff, 0x06}, + .fs_regs = {{0, 4, 4, 5}, {0, 5, 3, 4}, {0, 6, 3, 0}, {0, 7, 3, 1}, {0, 2, 4, 0}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 10300, .pci_div = 3}, + {.bus = 10000, .pci_div = 3}, + {.bus = 10045, .pci_div = 3}, + {.bus = 10090, .pci_div = 3}, + {.bus = 10710, .pci_div = 2}, + {.bus = 10900, .pci_div = 3}, + {.bus = 11200, .pci_div = 3}, + {.bus = 11400, .pci_div = 4}, + {.bus = 11600, .pci_div = 4}, + {.bus = 11800, .pci_div = 4}, + {.bus = 13330, .pci_div = 3}, + {.bus = 12000, .pci_div = 4}, + {.bus = 12200, .pci_div = 4}, + {.bus = 12500, .pci_div = 4}, + {.bus = 5000, .pci_div = 2}, + {.bus = 6670, .pci_div = 4}, + {.bus = 13330, .pci_div = 3}, + {.bus = 13390, .pci_div = 3}, + {.bus = 13800, .pci_div = 4}, + {.bus = 14200, .pci_div = 4}, + {.bus = 14600, .pci_div = 4}, + {.bus = 15000, .pci_div = 4}, + {.bus = 15300, .pci_div = 4}, + {.bus = 15600, .pci_div = 4}, + {.bus = 15910, .pci_div = 3}, + {.bus = 16200, .pci_div = 4}, + {.bus = 16670, .pci_div = 4}, + {.bus = 16800, .pci_div = 4}, + {.bus = 17100, .pci_div = 4}, + {.bus = 17400, .pci_div = 4}, + {.bus = 17700, .pci_div = 4}, + {.bus = 18000, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_112) + .max_reg = 6, + .regs = {0x02, 0x1f, 0xff, 0xff, 0xfb, 0xff, 0x06}, + .fs_regs = {{0, 4, 1, 6}, {0, 5, 4, 2}, {0, 6, 1, 5}, {0, 7, 1, 7}, {0, 2, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6680, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6800, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 10030, .ram_mult = 1, .pci_div = 3}, + {.bus = 10300, .ram_mult = 1, .pci_div = 3}, + {.bus = 13372, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14500, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13372, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13733, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14000, .ram_mult = 1, .pci_div = 2}, + {.bus = 11800, .ram_mult = 1, .pci_div = 3}, + {.bus = 12400, .ram_mult = 1, .pci_div = 3}, + {.bus = 13369, .ram_mult = 1, .pci_div = 2}, + {.bus = 13700, .ram_mult = 1, .pci_div = 2}, + {.bus = 15000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 7250, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8300, .ram_mult = 1, .pci_div = 6}, + {.bus = 11000, .ram_mult = 1, .pci_div = 2}, + {.bus = 12000, .ram_mult = 1, .pci_div = 3}, + {.bus = 12500, .ram_mult = 1, .pci_div = 2}, + {.bus = 6925, .ram_mult = 1.5, .pci_div = 1}, + {.bus = 7000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7667, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 14500, .ram_mult = 1, .pci_div = 3}, + {.bus = 6650, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 15000, .ram_mult = 1, .pci_div = 3}, + {.bus = 9975, .ram_mult = 1, .pci_div = 3}, + {.bus = 15500, .ram_mult = 1, .pci_div = 2}, + {.bus = 16650, .ram_mult = 1, .pci_div = 3}, + {.bus = 15333, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13300, .ram_mult = 0.75, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_138) + .max_reg = 6, + .regs = {0x02, 0x3f, 0x7f, 0x6f, 0xff, 0xff, 0x06}, + .fs_regs = {{0, 4, 2, 7}, {0, 5, 1, 6}, {0, 6, 1, 7}, {0, 7, 3, 4}, {0, 2, 3, 7}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6667, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6687, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6867, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7134, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 10030, .ram_mult = 1, .pci_div = 3}, + {.bus = 10300, .ram_mult = 1, .pci_div = 3}, + {.bus = 10700, .ram_mult = 1, .pci_div = 2}, + {.bus = 13333, .ram_mult = 1, .pci_div = 4}, + {.bus = 13372, .ram_mult = 1, .pci_div = 4}, + {.bus = 13733, .ram_mult = 1, .pci_div = 4}, + {.bus = 12000, .ram_mult = 1, .pci_div = 4}, + {.bus = 13333, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13372, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13733, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 12000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13600, .ram_mult = 1, .pci_div = 4}, + {.bus = 14000, .ram_mult = 1, .pci_div = 4}, + {.bus = 14266, .ram_mult = 1, .pci_div = 3}, + {.bus = 14533, .ram_mult = 1, .pci_div = 4}, + {.bus = 13600, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14266, .ram_mult = 0.75, .pci_div = 3}, + {.bus = 14533, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14666, .ram_mult = 1, .pci_div = 3}, + {.bus = 15333, .ram_mult = 1, .pci_div = 4}, + {.bus = 16000, .ram_mult = 1, .pci_div = 4}, + {.bus = 16667, .ram_mult = 1, .pci_div = 3}, + {.bus = 14666, .ram_mult = 0.75, .pci_div = 3}, + {.bus = 16000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 16667, .ram_mult = 0.75, .pci_div = 3}, + {.bus = 20000, .ram_mult = 1, .pci_div = 6}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_141) + .max_reg = 6, + .regs = {0x02, 0x6b, 0x7f, 0xff, 0xff, 0xe7, 0x06}, + .fs_regs = {{0, 4, 2, 7}, {0, 5, 5, 3}, {0, 6, 1, 7}, {0, 7, 1, 4}, {0, 2, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 9000, .pci_div = 3}, + {.bus = 9500, .pci_div = 2}, + {.bus = 10100, .pci_div = 2}, + {.bus = 10200, .pci_div = 3}, + {.bus = 10090, .pci_div = 3}, + {.bus = 10300, .pci_div = 3}, + {.bus = 10500, .pci_div = 3}, + {.bus = 10000, .pci_div = 3}, + {.bus = 10700, .pci_div = 2}, + {.bus = 10900, .pci_div = 3}, + {.bus = 11000, .pci_div = 2}, + {.bus = 11100, .pci_div = 3}, + {.bus = 11300, .pci_div = 2}, + {.bus = 11500, .pci_div = 3}, + {.bus = 11700, .pci_div = 3}, + {.bus = 13330, .pci_div = 3}, + {.bus = 12000, .pci_div = 3}, + {.bus = 12500, .pci_div = 4}, + {.bus = 13000, .pci_div = 4}, + {.bus = 13372, .pci_div = 4}, + {.bus = 13500, .pci_div = 4}, + {.bus = 13700, .pci_div = 4}, + {.bus = 13900, .pci_div = 4}, + {.bus = 10000, .pci_div = 3}, + {.bus = 14000, .pci_div = 4}, + {.bus = 14300, .pci_div = 4}, + {.bus = 14500, .pci_div = 4}, + {.bus = 14800, .pci_div = 4}, + {.bus = 15000, .pci_div = 4}, + {.bus = 15500, .pci_div = 4}, + {.bus = 16666, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_143) + .max_reg = 5, + .regs = {0x82, 0xff, 0xff, 0xff, 0xd5, 0xff}, + .fs_regs = {{0, 4, -1, -1}, {0, 5, 4, 3}, {0, 6, -1, -1}, {0, 2, 4, 1}, {-1, -1, -1, -1}}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6667, .pci_div = 2}, + {.bus = 10000, .pci_div = 3}, + {.bus = 10030, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {.bus = 10500, .pci_div = 3}, + {.bus = 13337, .pci_div = 4}, + {.bus = 13700, .pci_div = 4}, + {.bus = 7500, .pci_div = 2}, + {.bus = 10000, .pci_div = 3}, + {.bus = 9500, .pci_div = 2}, + {.bus = 9700, .pci_div = 3}, + {.bus = 13333, .pci_div = 4}, + {.bus = 9000, .pci_div = 3}, + {.bus = 9622, .pci_div = 3}, + {.bus = 6681, .pci_div = 2}, + {.bus = 9150, .pci_div = 3}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_151) + .max_reg = 6, + .regs = {0x80, 0x4f, 0xff, 0x3f, 0xff, 0xff, 0x06}, + .fs_regs = {{0, 4, -1, -1}, {0, 5, -1, -1}, {0, 6, 3, 7}, {0, 1, 1, 4}, {0, 2, 1, 5}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 20000, .pci_div = 5, .agp_div = 2.5}, + {.bus = 19000, .pci_div = 5, .agp_div = 2.5}, + {.bus = 18000, .pci_div = 5, .agp_div = 2.5}, + {.bus = 17000, .pci_div = 5, .agp_div = 2.5}, + {.bus = 16600, .pci_div = 5, .agp_div = 2.5}, + {.bus = 16000, .pci_div = 5, .agp_div = 2.5}, + {.bus = 15000, .pci_div = 4, .agp_div = 2}, + {.bus = 14500, .pci_div = 4, .agp_div = 2}, + {.bus = 14000, .pci_div = 4, .agp_div = 2}, + {.bus = 13600, .pci_div = 4, .agp_div = 2}, + {.bus = 13000, .pci_div = 4, .agp_div = 2}, + {.bus = 12400, .pci_div = 4, .agp_div = 2}, + {.bus = 6667, .pci_div = 1, .agp_div = 1}, + {.bus = 10000, .pci_div = 3, .agp_div = 1.5}, + {.bus = 11800, .pci_div = 3, .agp_div = 1.5}, + {.bus = 13333, .pci_div = 3, .agp_div = 2}, + {.bus = 6680, .pci_div = 2, .agp_div = 1}, + {.bus = 10020, .pci_div = 3, .agp_div = 1.5}, + {.bus = 11500, .pci_div = 3, .agp_div = 1.5}, + {.bus = 13340, .pci_div = 4, .agp_div = 2}, + {.bus = 6680, .pci_div = 2, .agp_div = 1}, + {.bus = 10020, .pci_div = 3, .agp_div = 1.5}, + {.bus = 11000, .pci_div = 2, .agp_div = 1.5}, + {.bus = 13340, .pci_div = 4, .agp_div = 2}, + {.bus = 10500, .pci_div = 3, .agp_div = 1.5}, + {.bus = 9000, .pci_div = 3, .agp_div = 1.5}, + {.bus = 8500, .pci_div = 3, .agp_div = 1.5}, + {.bus = 7800, .pci_div = 2, .agp_div = 1}, + {.bus = 6667, .pci_div = 1, .agp_div = 1}, + {.bus = 10000, .pci_div = 3, .agp_div = 1.5}, + {.bus = 7500, .pci_div = 2, .agp_div = 1}, + {.bus = 13333, .pci_div = 3, .agp_div = 2}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9248_192) + .max_reg = 6, + .regs = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .fs_regs = {{0, 4, -1, -1}, {0, 5, 4, 3}, {0, 6, -1, -1}, {0, 7, -1, -1}, {0, 2, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6000, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6731, .pci_div = 2}, + {.bus = 6864, .pci_div = 2}, + {.bus = 6995, .pci_div = 2}, + {.bus = 7259, .pci_div = 2}, + {.bus = 6150, .pci_div = 2}, + {.bus = 6300, .pci_div = 2}, + {.bus = 6400, .pci_div = 2}, + {.bus = 6500, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 5000, .pci_div = 2}, + {.bus = 4800, .pci_div = 2}, + {.bus = 5880, .pci_div = 2}, + {.bus = 5760, .pci_div = 2}, + {.bus = 5640, .pci_div = 2}, + {.bus = 5400, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6000, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {.bus = 6659, .pci_div = 2}, + {0} + } + ICS9xxx_MODEL_END() +#endif + ICS9xxx_MODEL(ICS9250_08) + .max_reg = 5, + .regs = {0x00, 0xff, 0xff, 0xff, 0x6d, 0xbf}, + .fs_regs = {{0, 4, 4, 7}, {0, 5, 4, 4}, {0, 6, 5, 6}, {0, 2, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 12400, .pci_div = 3}, + {.bus = 7500, .pci_div = 2}, + {.bus = 8333, .pci_div = 2}, + {.bus = 6680, .pci_div = 2}, + {.bus = 10300, .pci_div = 3}, + {.bus = 11200, .pci_div = 3}, + {.bus = 13300, .pci_div = 3}, + {.bus = 10030, .pci_div = 3}, + {.bus = 12000, .pci_div = 3}, + {.bus = 11500, .pci_div = 3}, + {.bus = 11000, .pci_div = 3}, + {.bus = 10500, .pci_div = 3}, + {.bus = 14000, .pci_div = 4}, + {.bus = 15000, .pci_div = 4}, + {.bus = 12400, .pci_div = 4}, + {.bus = 13300, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() +#ifdef ENABLE_ICS9xxx_DETECT + ICS9xxx_MODEL(ICS9250_10) + .max_reg = 5, + .regs = {0x1f, 0xff, 0xfe, 0x00, 0x00, 0x06}, + .fs_regs = {{5, 0, -1, -1}, {5, 3, -1, -1}, {5, 4, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .hw_select = {-1, -1}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6667, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7067, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7466, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8266, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6350, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6867, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7267, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8866, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 10600, .ram_mult = 1, .pci_div = 3}, + {.bus = 11200, .ram_mult = 1, .pci_div = 3}, + {.bus = 12400, .ram_mult = 1, .pci_div = 3}, + {.bus = 9525, .ram_mult = 1, .pci_div = 3}, + {.bus = 10300, .ram_mult = 1, .pci_div = 3}, + {.bus = 10900, .ram_mult = 1, .pci_div = 3}, + {.bus = 13300, .ram_mult = 1, .pci_div = 3}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_13) + .max_reg = 5, + .regs = {0x82, 0xcf, 0x7f, 0xff, 0xff, 0xf7}, + .fs_regs = {{0, 4, 1, 4}, {0, 5, 5, 7}, {0, 6, 1, 5}, {0, 2, 2, 7}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 9000, .ram_mult = 1, .pci_div = 2}, + {.bus = 8901, .ram_mult = 1, .pci_div = 2}, + {.bus = 8800, .ram_mult = 1, .pci_div = 2}, + {.bus = 8699, .ram_mult = 1, .pci_div = 2}, + {.bus = 8591, .ram_mult = 1, .pci_div = 2}, + {.bus = 8501, .ram_mult = 1, .pci_div = 2}, + {.bus = 8400, .ram_mult = 1, .pci_div = 2}, + {.bus = 8200, .ram_mult = 1, .pci_div = 2}, + {.bus = 8101, .ram_mult = 1, .pci_div = 2}, + {.bus = 8000, .ram_mult = 1, .pci_div = 2}, + {.bus = 8331, .ram_mult = 1, .pci_div = 2}, + {.bus = 6849, .ram_mult = 1, .pci_div = 2}, + {.bus = 7800, .ram_mult = 1, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1, .pci_div = 2}, + {.bus = 7199, .ram_mult = 1, .pci_div = 2}, + {.bus = 6682, .ram_mult = 1, .pci_div = 2}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_14) + .max_reg = 5, + .regs = {0x02, 0x1f, 0xff, 0xff, 0xeb, 0xff}, + .fs_regs = {{0, 4, 1, 6}, {0, 5, 4, 2}, {0, 6, 1, 5}, {0, 7, 1, 7}, {0, 2, 4, 4}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6781, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7201, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6667, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7301, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7700, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7801, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8300, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8449, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 10000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8608, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8800, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 9000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 9500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 4990, .ram_mult = 1, .pci_div = 3}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 7485, .ram_mult = 1, .pci_div = 3}, + {.bus = 6658, .ram_mult = 1, .pci_div = 3}, + {.bus = 8284, .ram_mult = 1, .pci_div = 3}, + {.bus = 8981, .ram_mult = 1, .pci_div = 3}, + {.bus = 9480, .ram_mult = 1, .pci_div = 3}, + {.bus = 10050, .ram_mult = 1, .pci_div = 3}, + {.bus = 10478, .ram_mult = 1, .pci_div = 3}, + {.bus = 11177, .ram_mult = 1, .pci_div = 3}, + {.bus = 11477, .ram_mult = 1, .pci_div = 3}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 12375, .ram_mult = 1, .pci_div = 3}, + {.bus = 13274, .ram_mult = 1, .pci_div = 3}, + {.bus = 13975, .ram_mult = 1, .pci_div = 3}, + {.bus = 14969, .ram_mult = 1, .pci_div = 3}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_16) + .max_reg = 5, + .regs = {0x1f, 0xff, 0xff, 0x00, 0x00, 0x06}, + .fs_regs = {{5, 0, -1, -1}, {5, 3, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .hw_select = {-1, -1}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6667, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7267, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7467, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 10500, .ram_mult = 1, .pci_div = 3}, + {.bus = 10900, .ram_mult = 1, .pci_div = 3}, + {.bus = 11201, .ram_mult = 1, .pci_div = 3}, + {.bus = 13334, .ram_mult = 1, .pci_div = 3}, + {.bus = 14000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 12000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 12400, .ram_mult = 1, .pci_div = 3}, + {.bus = 13334, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 15000, .ram_mult = 1, .pci_div = 4}, + {.bus = 14000, .ram_mult = 1, .pci_div = 4}, + {.bus = 13299, .ram_mult = 1, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() +#endif + ICS9xxx_MODEL(ICS9250_18) + .max_reg = 5, + .regs = {0x02, 0xff, 0xff, 0xff, 0x6d, 0xbf}, + .fs_regs = {{0, 4, 4, 7}, {0, 5, 4, 4}, {0, 6, 5, 6}, {0, 7, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 8000, .pci_div = 2}, + {.bus = 7500, .pci_div = 2}, + {.bus = 8331, .pci_div = 2}, + {.bus = 6690, .pci_div = 2}, + {.bus = 10300, .pci_div = 3}, + {.bus = 11201, .pci_div = 3}, + {.bus = 6801, .pci_div = 2}, + {.bus = 10070, .pci_div = 3}, + {.bus = 12000, .pci_div = 3}, + {.bus = 11499, .pci_div = 3}, + {.bus = 10999, .pci_div = 3}, + {.bus = 10500, .pci_div = 3}, + {.bus = 14000, .pci_div = 4}, + {.bus = 15000, .pci_div = 4}, + {.bus = 12400, .pci_div = 4}, + {.bus = 13390, .pci_div = 4}, + {.bus = 13500, .pci_div = 4}, + {.bus = 12999, .pci_div = 4}, + {.bus = 12600, .pci_div = 4}, + {.bus = 11800, .pci_div = 4}, + {.bus = 11598, .pci_div = 4}, + {.bus = 9500, .pci_div = 3}, + {.bus = 9000, .pci_div = 3}, + {.bus = 8501, .pci_div = 3}, + {.bus = 16600, .pci_div = 4}, + {.bus = 16001, .pci_div = 4}, + {.bus = 15499, .pci_div = 4}, + {.bus = 14795, .pci_div = 4}, + {.bus = 14598, .pci_div = 4}, + {.bus = 14398, .pci_div = 4}, + {.bus = 14199, .pci_div = 4}, + {.bus = 13801, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() +#ifdef ENABLE_ICS9xxx_DETECT + ICS9xxx_MODEL(ICS9250_19) + .max_reg = 5, + .regs = {0x02, 0xff, 0xff, 0xff, 0x6d, 0xbf}, + .fs_regs = {{0, 4, 4, 7}, {0, 5, 4, 4}, {0, 6, 5, 6}, {0, 7, 4, 1}, {-1, -1, -1, -1}}, + .hw_select = {0, 3}, + .frequencies_ref = ICS9250_08 + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_23) + .max_reg = 5, + .regs = {0x02, 0x1f, 0xff, 0xff, 0xeb, 0xff}, + .fs_regs = {{0, 4, 1, 6}, {0, 5, 4, 2}, {0, 6, 1, 5}, {0, 7, 1, 7}, {0, 2, 4, 4}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6900, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7100, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6690, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7200, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7660, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6800, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7400, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 14000, .ram_mult = 1, .pci_div = 4}, + {.bus = 13333, .ram_mult = 1, .pci_div = 4}, + {.bus = 15000, .ram_mult = 1, .pci_div = 4}, + {.bus = 15500, .ram_mult = 1, .pci_div = 4}, + {.bus = 16600, .ram_mult = 1, .pci_div = 4}, + {.bus = 16600, .ram_mult = 1, .pci_div = 3}, + {.bus = 11177, .ram_mult = 1, .pci_div = 3}, + {.bus = 10478, .ram_mult = 1, .pci_div = 3}, + {.bus = 10951, .ram_mult = 1, .pci_div = 3}, + {.bus = 10090, .ram_mult = 1, .pci_div = 3}, + {.bus = 11700, .ram_mult = 1, .pci_div = 3}, + {.bus = 12375, .ram_mult = 1, .pci_div = 3}, + {.bus = 13333, .ram_mult = 1, .pci_div = 3}, + {.bus = 14250, .ram_mult = 1, .pci_div = 3}, + {.bus = 13600, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14300, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13390, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14667, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14933, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 15330, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 16667, .ram_mult = 0.75, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_25) + .max_reg = 6, + .regs = {0x02, 0x1f, 0xff, 0xff, 0xeb, 0xff, 0x06}, + .fs_regs = {{0, 4, 1, 6}, {0, 5, 4, 2}, {0, 6, 1, 5}, {0, 7, 1, 7}, {0, 2, 4, 4}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 5500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6680, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6833, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7200, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7700, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8330, .ram_mult = 1, .pci_div = 3}, + {.bus = 9000, .ram_mult = 1, .pci_div = 3}, + {.bus = 10030, .ram_mult = 1, .pci_div = 3}, + {.bus = 10300, .ram_mult = 1, .pci_div = 3}, + {.bus = 11250, .ram_mult = 1, .pci_div = 3}, + {.bus = 11500, .ram_mult = 1, .pci_div = 3}, + {.bus = 12000, .ram_mult = 1, .pci_div = 3}, + {.bus = 12500, .ram_mult = 1, .pci_div = 3}, + {.bus = 12800, .ram_mult = 1, .pci_div = 4}, + {.bus = 13000, .ram_mult = 1, .pci_div = 4}, + {.bus = 13370, .ram_mult = 1, .pci_div = 4}, + {.bus = 13700, .ram_mult = 1, .pci_div = 4}, + {.bus = 14000, .ram_mult = 1, .pci_div = 4}, + {.bus = 14500, .ram_mult = 1, .pci_div = 4}, + {.bus = 15000, .ram_mult = 1, .pci_div = 4}, + {.bus = 15333, .ram_mult = 1, .pci_div = 4}, + {.bus = 12500, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13370, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13700, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14500, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 15000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 15333, .ram_mult = 0.75, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_26) + .max_reg = 5, + .regs = {0x1e, 0xff, 0xff, 0x00, 0x00, 0x06}, + .fs_regs = {{5, 0, -1, -1}, {5, 3, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .hw_select = {-1, -1}, + .frequencies_ref = ICS9250_16 + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_27) + .max_reg = 5, + .regs = {0x0f, 0xff, 0xfe, 0x00, 0x00, 0x00}, + .fs_regs = {{-1, -1, -1, -1}, {-1, -1, -1, -1}, {3, 0, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .hw_select = {-1, -1}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6666, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 13332, .ram_mult = 1, .pci_div = 4}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 13332, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 6666, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 13332, .ram_mult = 1, .pci_div = 4}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 13332, .ram_mult = 1, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_28) + .max_reg = 4, + .regs = {0x1e, 0xff, 0xfe, 0x00, 0x00}, + .fs_regs = {{-1, -1, -1, -1}, {-1, -1, -1, -1}, {3, 0, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .hw_select = {-1, -1}, + .frequencies_ref = ICS9250_27 + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_29) + .max_reg = 5, + .regs = {0x16, 0xff, 0xfe, 0x00, 0x00, 0x00}, + .fs_regs = {{-1, -1, -1, -1}, {-1, -1, -1, -1}, {3, 0, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .hw_select = {-1, -1}, + .frequencies_ref = ICS9250_27 + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_30) + .max_reg = 6, + .regs = {0x02, 0x0f, 0xff, 0xff, 0xeb, 0xff, 0x06}, + .fs_regs = {{0, 4, 1, 6}, {0, 5, 4, 2}, {0, 6, 1, 5}, {0, 7, 1, 7}, {0, 2, 4, 4}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6667, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6680, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 6833, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 7500, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8000, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 8300, .ram_mult = 1.5, .pci_div = 2}, + {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + {.bus = 9000, .ram_mult = 1, .pci_div = 3}, + {.bus = 10030, .ram_mult = 1, .pci_div = 3}, + {.bus = 10300, .ram_mult = 1, .pci_div = 3}, + {.bus = 10500, .ram_mult = 1, .pci_div = 3}, + {.bus = 11000, .ram_mult = 1, .pci_div = 3}, + {.bus = 11500, .ram_mult = 1, .pci_div = 3}, + {.bus = 20000, .ram_mult = 1, .pci_div = 6}, + {.bus = 13333, .ram_mult = 1, .pci_div = 4}, + {.bus = 16667, .ram_mult = 1, .pci_div = 4}, + {.bus = 13370, .ram_mult = 1, .pci_div = 4}, + {.bus = 13700, .ram_mult = 1, .pci_div = 4}, + {.bus = 14000, .ram_mult = 1, .pci_div = 4}, + {.bus = 14500, .ram_mult = 1, .pci_div = 4}, + {.bus = 15000, .ram_mult = 1, .pci_div = 4}, + {.bus = 16000, .ram_mult = 1, .pci_div = 4}, + {.bus = 13333, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 16667, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13370, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 13700, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 14500, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 15000, .ram_mult = 0.75, .pci_div = 4}, + {.bus = 16000, .ram_mult = 0.75, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_32) + .max_reg = 4, + .regs = {0x07, 0xff, 0xff, 0x00, 0x00}, + .fs_regs = {{-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}} + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_38) + .max_reg = 6, + .regs = {0x18, 0x07, 0xfe, 0xc7, 0xfc, 0x00, 0x80}, + .fs_regs = {{0, 0, -1, -1}, {0, 1, -1, -1}, {0, 2, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}, + .normal_bits_fixed = 1, + .frequencies = (const ics9xxx_frequency_t[]) { + {.bus = 6666, .ram_mult = 1, .pci_div = 1}, + {.bus = 10000, .ram_mult = 2.0/3.0, .pci_div = 3}, + {.bus = 20000, .ram_mult = 1.0/3.0, .pci_div = 6}, + {.bus = 13333, .ram_mult = 0.5, .pci_div = 2}, + {.bus = 6666, .ram_mult = 1, .pci_div = 1}, + {.bus = 10000, .ram_mult = 2.0/3.0, .pci_div = 3}, + {.bus = 20000, .ram_mult = 1.0/3.0, .pci_div = 6}, + {.bus = 13333, .ram_mult = 0.5, .pci_div = 2}, + {0} + } + ICS9xxx_MODEL_END() + ICS9xxx_MODEL(ICS9250_50) + .max_reg = 6, + .regs = {0x02, 0x6f, 0xff, 0xff, 0xef, 0xff, 0x06}, + .fs_regs = {{-1, -1, 1, 6}, {-1, -1, 4, 2}, {-1, -1, 1, 5}, {0, 7, 1, 7}, {0, 2, 4, 4}}, + .hw_select = {0, 3}, + .frequencies = (const ics9xxx_frequency_t[]) { + [0 ... 7] = {.bus = 6667, .ram_mult = 1.5, .pci_div = 2}, + [8 ... 15] = {.bus = 10000, .ram_mult = 1, .pci_div = 3}, + [16 ... 23] = {.bus = 13333, .ram_mult = 1, .pci_div = 4}, + [24 ... 31] = {.bus = 13333, .ram_mult = 0.75, .pci_div = 4}, + {0} + } + ICS9xxx_MODEL_END() +#endif +}; + + +/* Don't enable the detection device here. Enable it further up near logging. */ +#ifdef ENABLE_ICS9xxx_DETECT +static uint16_t detect_bus = 0; +static uint8_t detect_reg = 0; +static uint8_t discarded[ICS9xxx_MAX] = {0}; + + +static void +ics9xxx_detect_reset(void *priv) +{ + pclog("Please enter the frequency set in the BIOS (7500 for 75.00 MHz)\nAnswer 0 if unsure or set to auto, I'll ask again next reset.\n"); + scanf("%hu", &detect_bus); + if ((detect_bus > 0) && (detect_bus < 1000)) + detect_bus *= 100; + pclog("Frequency interpreted as %d\n", detect_bus); +} + + +static void +ics9xxx_detect(ics9xxx_t *dev) +{ + if (!detect_bus) { + pclog("Frequency not entered on this reset, ignoring change.\n"); + return; + } + + if ((detect_reg == 0) && (dev->regs[detect_reg] >= 0xfe)) { + pclog("Register %d set to %02X, probably not it, trying %d instead\n", detect_reg, dev->regs[detect_reg], 3); + detect_reg = 3; + dev->relevant_regs = 1 << detect_reg; + return; + } + + if (!(dev->regs[detect_reg] & 0x40)) + pclog("Bit 3 of register %d is clear, probably in hardware select mode!\n", detect_reg); + + uint8_t i = 0, matches = 0, val, bitmask; + ics9xxx_frequency_t *frequencies_ptr; + uint32_t delta; + for (uint8_t j = 0; j < ICS9xxx_MAX; j++) { + if (discarded[j]) + continue; + discarded[j] = 1; + + frequencies_ptr = (ics9xxx_frequency_t *) ics9xxx_models[ics9xxx_models[j].frequencies_ref ? ics9xxx_models[j].frequencies_ref : j].frequencies; + if (!frequencies_ptr) + continue; + + while (frequencies_ptr[i].bus) { + delta = ABS((int32_t) (detect_bus - frequencies_ptr[i].bus)); + if (delta <= 100) { + val = bitmask = 0; + for (uint8_t k = 0; k < sizeof(ics9xxx_models[j].fs_regs) / sizeof(ics9xxx_models[j].fs_regs[0]); k++) { + if (ics9xxx_models[j].fs_regs[k].normal_reg == detect_reg) { + bitmask |= 1 << k; + val |= (1 << k) * !!(dev->regs[detect_reg] & (1 << ics9xxx_models[j].fs_regs[k].normal_bit)); + } + } + if (bitmask && (val == (i & bitmask))) { + matches++; + discarded[j] = 0; + pclog("> Potential match for %s (frequency %d index %d)\n", ics9xxx_models[j].name, frequencies_ptr[i].bus, val); + } + } + + i++; + } + } + + pclog("Found a total of %d matches for register %d value %02X and bus frequency %d\n", matches, detect_reg, dev->regs[detect_reg], detect_bus); + if (matches == 0) { + pclog("Resetting list of discarded models since there were no matches.\n"); + memset(discarded, 0, sizeof(discarded)); + } +} +#endif + + +static uint8_t +ics9xxx_start(void *bus, uint8_t addr, uint8_t read, void *priv) +{ + ics9xxx_t *dev = (ics9xxx_t *) priv; + + ics9xxx_log("ICS9xxx: start()\n"); + + dev->addr_register = -2; /* -2 = command; -1 = SMBus block length; 0+ = registers */ + + return 1; +} + + +static uint8_t +ics9xxx_read(void *bus, uint8_t addr, void *priv) +{ + ics9xxx_t *dev = (ics9xxx_t *) priv; + uint8_t ret = 0xff; + + if (dev->addr_register < 0) { + dev->addr_register = -1; + ret = dev->model->max_reg + 1; + } +#if 0 + else if ((dev->model_idx == ICS9250_50) && (dev->addr_register == 0)) + ret = dev->regs[dev->addr_register] & 0x0b; /* -50 reads back revision ID instead */ +#endif + else + ret = dev->regs[dev->addr_register]; + +#ifdef ENABLE_ICS9xxx_LOG + if (dev->addr_register < 0) + ics9xxx_log("ICS9xxx: read(%s) = %02X\n", (dev->addr_register == -1) ? "blocklen" : "command", ret); + else + ics9xxx_log("ICS9xxx: read(%x) = %02X\n", dev->addr_register, ret); +#endif + if (dev->addr_register >= dev->model->max_reg) + dev->addr_register = 0; /* roll-over */ + else + dev->addr_register++; + + return ret; +} + + +static void +ics9xxx_set(ics9xxx_t *dev, uint8_t val) +{ + /* Get the active mode, which determines what to add to the static frequency bits we were passed. */ + uint8_t hw_select = (dev->model->hw_select.normal_reg < 7) && !(dev->regs[dev->model->hw_select.normal_reg] & (1 << dev->model->hw_select.normal_bit)); + if (hw_select) { + /* Hardware select mode: add strapped frequency bits. */ + val |= dev->bus_match; + } else { + /* Programmable mode: add register-defined frequency bits. */ + for (uint8_t i = 0; i < sizeof(dev->model->fs_regs) / sizeof(dev->model->fs_regs[0]); i++) { + if ((dev->model->fs_regs[i].normal_reg < 7) && (dev->regs[dev->model->fs_regs[i].normal_reg] & (1 << dev->model->fs_regs[i].normal_bit))) + val |= 1 << i; + } + } + + uint16_t bus = dev->frequencies_ptr[val].bus; + uint32_t pci = bus / dev->frequencies_ptr[val].pci_div; + cpu_set_pci_speed(pci * 10000); + + ics9xxx_log("ICS9xxx: set(%d) = hw=%d bus=%d ram=%d pci=%d\n", val, hw_select, bus, bus * dev->frequencies_ptr[val].ram_mult, pci); +} + + +static uint8_t +ics9xxx_write(void *bus, uint8_t addr, uint8_t data, void *priv) +{ + ics9xxx_t *dev = (ics9xxx_t *) priv; + +#ifdef ENABLE_ICS9xxx_LOG + if (dev->addr_register < 0) + ics9xxx_log("ICS9xxx: write(%s, %02X)\n", (dev->addr_register == -1) ? "blocklen" : "command", data); + else + ics9xxx_log("ICS9xxx: write(%x, %02X)\n", dev->addr_register, data); +#endif + + if (dev->addr_register >= 0) { + /* Preserve fixed bits. */ +#ifdef ENABLE_ICS9xxx_DETECT + if (dev->model != ICS9xxx_xx) +#endif + { + for (uint8_t i = 0; i < sizeof(dev->model->fs_regs) / sizeof(dev->model->fs_regs[0]); i++) { + if (dev->model->normal_bits_fixed && (dev->model->fs_regs[i].normal_reg == dev->addr_register)) + data = (dev->regs[dev->addr_register] & (1 << dev->model->fs_regs[i].normal_bit)) | (data & ~(1 << dev->model->fs_regs[i].normal_bit)); + if (dev->model->fs_regs[i].inv_reg == dev->addr_register) + data = (dev->regs[dev->addr_register] & (1 << dev->model->fs_regs[i].inv_bit)) | (data & ~(1 << dev->model->fs_regs[i].inv_bit)); + } + } + +#if 0 + switch (dev->addr_register) { + case 0: + if (dev->model_idx == ICS9250_38) + data = (dev->regs[dev->addr_register] & ~0xe8) | (data & 0xe8); + break; + + case 1: + if (dev->model_idx == ICS9250_38) + data = (dev->regs[dev->addr_register] & ~0xfe) | (data & 0xfe); + break; + + case 3: + if (dev->model_idx == ICS9250_32) + data ^= 0x70; + break; + + case 4: + if (dev->model_idx == ICS9250_38) + data = (dev->regs[dev->addr_register] & ~0xfc) | (data & 0xfc); + break; + + case 6: + if (dev->model_idx == ICS9250_38) /* read-only */ + data = dev->regs[dev->addr_register]; + break; + } +#endif + dev->regs[dev->addr_register] = data; + + /* Update frequency if a relevant register was written to. */ + if (dev->relevant_regs & (1 << dev->addr_register)) { + switch (dev->model_idx) { +#ifdef ENABLE_ICS9xxx_DETECT + case ICS9xxx_xx: + ics9xxx_detect(dev); + break; +#endif +#if 0 + case ICS9250_10: + ics9xxx_set(dev, (cpu_busspeed >= 100000000) * 0x08); + break; + + case ICS9250_16: + case ICS9250_26: + ics9xxx_set(dev, ((cpu_busspeed >= 120000000) * 0x08) | ((((cpu_busspeed >= 100000000) && (cpu_busspeed < 120000000)) || (cpu_busspeed == 150000000) || (cpu_busspeed == 132999999)) * 0x04)); + break; + + case ICS9250_27: + case ICS9250_28: + case ICS9250_29: + ics9xxx_set(dev, ((cpu_busspeed == 100000000) * 0x02) | ((cpu_busspeed > 100000000) * 0x01)); + break; +#endif + default: + ics9xxx_set(dev, 0x00); + break; + } + } + } + + if (dev->addr_register >= dev->model->max_reg) + dev->addr_register = 0; /* roll-over */ + else + dev->addr_register++; + + return 1; +} + + +static uint8_t +ics9xxx_find_bus_match(ics9xxx_t *dev, uint32_t bus, uint8_t preset_mask, uint8_t preset) { + uint8_t best_match = 0; + uint32_t delta, best_delta = -1; + +#ifdef ENABLE_ICS9xxx_DETECT + if (dev->model_idx == ICS9xxx_xx) + return 0; +#endif + + bus /= 10000; + uint8_t i = 0; + while (dev->frequencies_ptr[i].bus) { + if ((i & preset_mask) == preset) { + delta = ABS((int32_t) (bus - dev->frequencies_ptr[i].bus)); + if (delta < best_delta) { + best_match = i; + best_delta = delta; + } + } + + i++; + } + + ics9xxx_log("ICS9xxx: find_match(%s, %d) = match=%d bus=%d\n", dev->model->name, bus, best_match, dev->frequencies_ptr[best_match].bus); + + return best_match; +} + + +static void * +ics9xxx_init(const device_t *info) +{ + ics9xxx_t *dev = (ics9xxx_t *) malloc(sizeof(ics9xxx_t)); + memset(dev, 0, sizeof(ics9xxx_t)); + + dev->model_idx = info->local; + dev->model = (ics9xxx_model_t *) &ics9xxx_models[dev->model_idx]; + dev->dyn_device = (device_t *) info; + memcpy(&dev->regs, &dev->model->regs, dev->model->max_reg + 1); + + ics9xxx_log("ICS9xxx: init(%s)\n", dev->model->name); + + uint8_t i; +#ifdef ENABLE_ICS9xxx_DETECT + for (i = ICS9xxx_xx + 1; i < ICS9xxx_MAX; i++) { + if (ics9xxx_models[i].frequencies_ref || !ics9xxx_models[i].name) + continue; + for (uint8_t j = 0; j < i; j++) { + if (ics9xxx_models[j].frequencies_ref || !ics9xxx_models[j].name) + continue; + if (!memcmp(&ics9xxx_models[i].frequencies, &ics9xxx_models[j].frequencies, sizeof(ics9xxx_models[i].frequencies))) + pclog("Optimization warning: %s and %s have duplicate tables\n", ics9xxx_models[j].name, ics9xxx_models[i].name); + } + } + + if (dev->model_idx == ICS9xxx_xx) { /* detection device */ + dev->relevant_regs = 1 << 0; /* register 0 matters the most on the detection device */ + + ics9xxx_detect_reset(dev); + } else +#endif + { /* regular device */ + dev->frequencies_ptr = (ics9xxx_frequency_t *) (dev->model->frequencies_ref ? ics9xxx_models[dev->model->frequencies_ref].frequencies : dev->model->frequencies); + if (!dev->frequencies_ptr) + fatal("ICS9xxx: NULL frequency table\n"); + + /* Determine which frequency bits cannot be strapped (register only). */ + uint8_t register_only_bits = 0x00; + for (i = 0; i < sizeof(dev->model->fs_regs) / sizeof(dev->model->fs_regs[0]); i++) { + if (!dev->model->normal_bits_fixed && (dev->model->fs_regs[i].normal_reg < 7)) /* mark a normal, programmable bit as relevant */ + dev->relevant_regs |= 1 << dev->model->fs_regs[i].normal_reg; + if ((dev->model->fs_regs[i].normal_reg == 7) && (dev->model->fs_regs[i].inv_reg == 7)) /* mark as register only */ + register_only_bits |= 1 << i; + } + + /* Mark the hardware select bit's register as relevant, if there's one. */ + if (dev->model->hw_select.normal_reg < 7) + dev->relevant_regs |= 1 << dev->model->hw_select.normal_reg; + + /* Find bus speed match and set default register bits accordingly. */ + dev->bus_match = ics9xxx_find_bus_match(dev, cpu_busspeed, register_only_bits, 0x00); + for (i = 0; i < sizeof(dev->model->fs_regs) / sizeof(dev->model->fs_regs[0]); i++) { + if (dev->model->fs_regs[i].normal_reg < 7) { + if (dev->bus_match & (1 << i)) + dev->regs[dev->model->fs_regs[i].normal_reg] |= 1 << dev->model->fs_regs[i].normal_bit; + else + dev->regs[dev->model->fs_regs[i].normal_reg] &= ~(1 << dev->model->fs_regs[i].normal_bit); + } + if (dev->model->fs_regs[i].inv_reg < 7) { + if (dev->bus_match & (1 << i)) + dev->regs[dev->model->fs_regs[i].inv_reg] &= ~(1 << dev->model->fs_regs[i].inv_bit); + else + dev->regs[dev->model->fs_regs[i].inv_reg] |= 1 << dev->model->fs_regs[i].inv_bit; + } + } + } + + i2c_sethandler(i2c_smbus, 0x69, 1, ics9xxx_start, ics9xxx_read, ics9xxx_write, NULL, dev); + + return dev; +} + + +static void +ics9xxx_close(void *priv) +{ + ics9xxx_t *dev = (ics9xxx_t *) priv; + + ics9xxx_log("ICS9xxx: close()\n"); + + i2c_removehandler(i2c_smbus, 0x69, 1, ics9xxx_start, ics9xxx_read, ics9xxx_write, NULL, dev); + + free(dev->dyn_device); + free(dev); +} + + +device_t * +ics9xxx_get(uint8_t model) +{ + device_t *dev = (device_t *) malloc(sizeof(device_t)); + memset(dev, 0, sizeof(device_t)); + + dev->name = "ICS9xxx-xx Clock Generator"; + dev->local = model; + dev->flags = DEVICE_ISA; +#ifdef ENABLE_ICS9xxx_DETECT + if (model == ICS9xxx_xx) + dev->reset = ics9xxx_detect_reset; +#endif + dev->init = ics9xxx_init; + dev->close = ics9xxx_close; + + return dev; +} diff --git a/src/device/hasp.c b/src/device/hasp.c new file mode 100644 index 000000000..299796a6d --- /dev/null +++ b/src/device/hasp.c @@ -0,0 +1,312 @@ +/* + * 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. + * + * HASP parallel port copy protection dongle emulation. + * + * Based on the MAME driver for Savage Quest. This incomplete + * emulation is enough to satisfy that game, but not Aladdin's + * DiagnostiX utility. + * + * + * + * Author: RichardG, + * Peter Ferrie + * + * Copyright 2021 RichardG. + * Copyright Peter Ferrie. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/lpt.h> +#include <86box/device.h> + +#define HASP_BYTEARRAY(...) {__VA_ARGS__} +#define HASP_TYPE(type, password_arr, prodinfo_arr) [type] = { \ + .password = (const uint8_t[]) password_arr, \ + .prodinfo = (const uint8_t[]) prodinfo_arr, \ + .password_size = sizeof((uint8_t[]) password_arr), \ + .prodinfo_size = sizeof((uint8_t[]) prodinfo_arr) \ + }, + + +enum { + HASP_STATE_NONE = 0, + HASP_STATE_PASSWORD_BEGIN, + HASP_STATE_PASSWORD_END, + HASP_STATE_READ +}; + +enum { + HASP_TYPE_SAVQUEST = 0 +}; + + +typedef struct { + const uint8_t *password, *prodinfo; + const uint8_t password_size, prodinfo_size; +} hasp_type_t; + +typedef struct +{ + void *lpt; + const hasp_type_t *type; + + int index, state, passindex, passmode, prodindex; + uint8_t tmppass[0x29], status; +} hasp_t; + +static const hasp_type_t hasp_types[] = { + HASP_TYPE(HASP_TYPE_SAVQUEST, + HASP_BYTEARRAY(0xc3, 0xd9, 0xd3, 0xfb, 0x9d, 0x89, 0xb9, 0xa1, 0xb3, 0xc1, 0xf1, 0xcd, 0xdf, 0x9d), + HASP_BYTEARRAY(0x51, 0x4c, 0x52, 0x4d, 0x53, 0x4e, 0x53, 0x4e, 0x53, 0x49, 0x53, 0x48, 0x53, 0x4b, 0x53, 0x4a, + 0x53, 0x43, 0x53, 0x45, 0x52, 0x46, 0x53, 0x43, 0x53, 0x41, 0xac, 0x40, 0x53, 0xbc, 0x53, 0x42, + 0x53, 0x57, 0x53, 0x5d, 0x52, 0x5e, 0x53, 0x5b, 0x53, 0x59, 0xac, 0x58, 0x53, 0xa4)) +}; + + +#ifdef ENABLE_HASP_LOG +int hasp_do_log = ENABLE_HASP_LOG; + +static void +hasp_log(const char *fmt, ...) +{ + va_list ap; + + if (hasp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define hasp_log(fmt, ...) +#endif + + +static void +hasp_write_data(uint8_t val, void *priv) +{ + hasp_t *dev = (hasp_t *) priv; + + hasp_log("HASP: write_data(%02X)\n", val); + + switch (dev->index) { + case 0: + if (val == 0xc6) + dev->index++; + else + dev->index = 0; + break; + + case 1: + if (val == 0xc7) + dev->index++; + else + dev->index = 0; + break; + + case 2: + if (val == 0xc6) { + dev->index++; + } else { + dev->index = 0; + dev->state = HASP_STATE_NONE; + } + break; + + case 3: + dev->index = 0; + if (val == 0x80) { + dev->state = HASP_STATE_PASSWORD_BEGIN; + dev->passindex = 0; + return; + } + break; + } + + dev->status = 0; + + if (dev->state == HASP_STATE_READ) { + /* different passwords cause different values to be returned + but there are really only two passwords of interest + passmode 2 is used to verify that the dongle is responding correctly */ + if (dev->passmode == 2) { + switch (val) { + case 0x94: case 0x9e: case 0xa4: + case 0xb2: case 0xbe: case 0xd0: + return; + + case 0x8a: case 0x8e: case 0xca: case 0xd2: + case 0xe2: case 0xf0: case 0xfc: + /* someone with access to the actual dongle could dump the true values + I've never seen it so I just determined the relevant bits instead + from the disassembly of the software + some of the keys are verified explicitly, the others implicitly + I guessed the implicit ones with a bit of trial and error */ + dev->status = 0x20; + return; + } + } + + switch (val) { + /* in passmode 0, some values remain unknown: 8a, 8e (inconclusive), 94, 96, 9a, a4, b2, be, c4, d2, d4 (inconclusive), e2, ec, f8, fc + this is less of a concern since the contents seem to decrypt correctly */ + case 0x88: + case 0x94: case 0x98: case 0x9c: case 0x9e: + case 0xa0: case 0xa4: case 0xaa: case 0xae: + case 0xb0: case 0xb2: case 0xbc: case 0xbe: + case 0xc2: case 0xc6: case 0xc8: case 0xce: + case 0xd0: case 0xd6: case 0xd8: case 0xdc: + case 0xe0: case 0xe6: case 0xea: case 0xee: + case 0xf2: case 0xf6: + /* again, just the relevant bits instead of the true values */ + dev->status = 0x20; + break; + } + } else if (dev->state == HASP_STATE_PASSWORD_END) { + if (val & 1) { + if ((dev->passmode == 1) && (val == 0x9d)) + dev->passmode = 2; + dev->state = HASP_STATE_READ; + } else if (dev->passmode == 1) { + dev->tmppass[dev->passindex++] = val; + + if (dev->passindex == sizeof(dev->tmppass)) { + if ((dev->tmppass[0] == 0x9c) && (dev->tmppass[1] == 0x9e)) { + int i = 2; + dev->prodindex = 0; + + do { + dev->prodindex = (dev->prodindex << 1) + ((dev->tmppass[i] >> 6) & 1); + } while ((i += 3) < sizeof(dev->tmppass)); + + dev->prodindex = (dev->prodindex - 0xc08) << 4; + + hasp_log("HASP: Password prodindex = %d\n", dev->prodindex); + + if (dev->prodindex < (0x38 << 4)) + dev->passmode = 3; + } + + dev->state = HASP_STATE_READ; + } + } + } else if ((dev->state == HASP_STATE_PASSWORD_BEGIN) && (val & 1)) { + dev->tmppass[dev->passindex++] = val; + + if (dev->passindex == dev->type->password_size) { + dev->state = HASP_STATE_PASSWORD_END; + dev->passindex = 0; + dev->passmode = (int) !memcmp(dev->tmppass, dev->type->password, dev->type->password_size); + hasp_log("HASP: Password comparison result = %d\n", dev->passmode); + } + } +} + + +static uint8_t +hasp_read_status(void *priv) +{ + hasp_t *dev = (hasp_t *) priv; + + if ((dev->state == HASP_STATE_READ) && (dev->passmode == 3)) { + /* passmode 3 is used to retrieve the product(s) information + it comes in two parts: header and product + the header has this format: + offset range purpose + 00 01 header type + 01 01-05 count of used product slots, must be 2 + 02 01-05 count of unused product slots + this is assumed to be 6-(count of used slots) + but it is not enforced here + however a total of 6 structures will be checked + 03 01-02 unknown + 04 01-46 country code + 05-0f 00 reserved + the used product slots have this format: + (the unused product slots must be entirely zeroes) + 00-01 0001-000a product ID, one must be 6, the other 0a + 02 0001-0003 unknown but must be 0001 + 04 01-05 HASP plug country ID + 05 01-02 unknown but must be 01 + 06 05 unknown + 07-0a any unknown, not used + 0b ff unknown + 0c ff unknown + 0d-0f 00 reserved + the read is performed by accessing an array of 16-bit big-endian values + and returning one bit at a time into bit 5 of the result + the 16-bit value is then XORed with 0x534d and the register index */ + + if (dev->prodindex <= (dev->type->prodinfo_size * 8)) + dev->status = ((dev->type->prodinfo[(dev->prodindex - 1) >> 3] >> ((8 - dev->prodindex) & 7)) & 1) << 5; /* return defined info */ + else + dev->status = (((0x534d ^ ((dev->prodindex - 1) >> 4)) >> ((16 - dev->prodindex) & 15)) & 1) << 5; /* then just alternate between the two key values */ + + hasp_log("HASP: Reading %02X from prodindex %d\n", dev->status, dev->prodindex); + + dev->prodindex++; + } + + hasp_log("HASP: read_status() = %02X\n", dev->status); + + return dev->status; +} + + +static void * +hasp_init(void *lpt, int type) +{ + hasp_t *dev = malloc(sizeof(hasp_t)); + memset(dev, 0, sizeof(hasp_t)); + + hasp_log("HASP: init(%d)\n", type); + + dev->lpt = lpt; + dev->type = &hasp_types[type]; + + dev->status = 0x80; + + return dev; +} + + +static void * +hasp_init_savquest(void *lpt) +{ + return hasp_init(lpt, HASP_TYPE_SAVQUEST); +} + + +static void +hasp_close(void *priv) +{ + hasp_t *dev = (hasp_t *) priv; + + hasp_log("HASP: close()\n"); + + free(dev); +} + + +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 +}; diff --git a/src/device/hwm.c b/src/device/hwm.c index 7ef55b3ef..83ac74699 100644 --- a/src/device/hwm.c +++ b/src/device/hwm.c @@ -15,23 +15,26 @@ * Copyright 2020 RichardG. */ +#include +#include #include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> #include <86box/device.h> +#include "cpu.h" +#include <86box/machine.h> #include <86box/hwm.h> -hwm_values_t hwm_values; +/* Refer to specific hardware monitor implementations for the meaning of hwm_values. */ +hwm_values_t hwm_values; -void -hwm_set_values(hwm_values_t new_values) +uint16_t +hwm_get_vcore() { - hwm_values = new_values; -} - - -hwm_values_t* -hwm_get_values() -{ - return &hwm_values; + /* Determine Vcore for the active CPU. */ + return cpu_s->voltage; } diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c new file mode 100644 index 000000000..102026294 --- /dev/null +++ b/src/device/hwm_gl518sm.c @@ -0,0 +1,326 @@ +/* + * 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 the Genesys Logic GL518SM hardware monitoring chip. + * + * + * + * Author: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/i2c.h> +#include <86box/hwm.h> + + +#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a))) +/* Formulas and factors derived from Linux's gl518sm.c driver. */ +#define GL518SM_RPM_TO_REG(r, d) ((r) ? CLAMP((480000 + (r) * (d) / 2) / (r) * (d), 1, 255) : 0) +#define GL518SM_VOLTAGE_TO_REG(v) ((uint8_t) round((v) / 19.0)) +#define GL518SM_VDD_TO_REG(v) ((uint8_t) (((v) * 4) / 95.0)) + + +typedef struct { + uint32_t local; + hwm_values_t *values; + + uint16_t regs[32]; + uint8_t addr_register: 5; + + uint8_t i2c_addr: 7, i2c_state: 2, i2c_enabled: 1; +} gl518sm_t; + + +static uint8_t gl518sm_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv); +static uint8_t gl518sm_i2c_read(void *bus, uint8_t addr, void *priv); +static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg); +static uint8_t gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); +static uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val); +static void gl518sm_reset(gl518sm_t *dev); + + +#ifdef ENABLE_GL518SM_LOG +int gl518sm_do_log = ENABLE_GL518SM_LOG; + + +static void +gl518sm_log(const char *fmt, ...) +{ + va_list ap; + + if (gl518sm_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define gl518sm_log(fmt, ...) +#endif + + +static void +gl518sm_remap(gl518sm_t *dev, uint8_t addr) +{ + gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr); + + if (dev->i2c_enabled) + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); + + if (addr < 0x80) + i2c_sethandler(i2c_smbus, addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); + + dev->i2c_addr = addr & 0x7f; + dev->i2c_enabled = !(addr & 0x80); +} + + +static uint8_t +gl518sm_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv) +{ + gl518sm_t *dev = (gl518sm_t *) priv; + + dev->i2c_state = 0; + + return 1; +} + + +static uint8_t +gl518sm_i2c_read(void *bus, uint8_t addr, void *priv) +{ + gl518sm_t *dev = (gl518sm_t *) priv; + uint16_t read = gl518sm_read(dev, dev->addr_register); + uint8_t ret = 0; + + if (dev->i2c_state == 0) + dev->i2c_state = 1; + + if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */ + dev->i2c_state = 2; + ret = read >> 8; + } else { + ret = read; + dev->addr_register++; + } + + return ret; +} + + +static uint16_t +gl518sm_read(gl518sm_t *dev, uint8_t reg) +{ + uint16_t ret; + + reg &= 0x1f; + + switch (reg) { + case 0x04: /* temperature */ + ret = (dev->values->temperatures[0] + 119) & 0xff; + break; + + case 0x07: /* fan speeds */ + ret = GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8; + ret |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3)); + break; + + case 0x0d: /* VIN3 */ + ret = GL518SM_VOLTAGE_TO_REG(dev->values->voltages[2]); + break; + + case 0x13: /* VIN2 */ + ret = GL518SM_VOLTAGE_TO_REG(dev->values->voltages[1]); + break; + + case 0x14: /* VIN1 */ + ret = GL518SM_VOLTAGE_TO_REG(dev->values->voltages[0]); + break; + + case 0x15: /* VDD */ + ret = GL518SM_VDD_TO_REG(dev->values->voltages[3]); + break; + + default: /* other registers */ + ret = dev->regs[reg]; + break; + } + + gl518sm_log("GL518SM: read(%02X) = %04X\n", reg, ret); + + return ret; +} + + +static uint8_t +gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) +{ + gl518sm_t *dev = (gl518sm_t *) priv; + + switch (dev->i2c_state++) { + case 0: + dev->addr_register = data; + break; + + case 1: + gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) & 0xff00) | data); + break; + + case 2: + gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) << 8) | data); + break; + + default: + dev->i2c_state = 3; + return 0; + } + + return 1; +} + + +static uint8_t +gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val) +{ + gl518sm_log("GL518SM: write(%02X, %04X)\n", reg, val); + + switch (reg) { + case 0x00: case 0x01: case 0x04: case 0x07: case 0x0d: case 0x12: case 0x13: case 0x14: case 0x15: + /* read-only registers */ + return 0; + + case 0x0a: + dev->regs[0x13] = val & 0xff; + break; + + case 0x03: + dev->regs[reg] = val & 0xfc; + + if (val & 0x80) /* Init */ + gl518sm_reset(dev); + break; + + case 0x0f: + dev->regs[reg] = val & 0xf8; + break; + + case 0x11: + dev->regs[reg] = val & 0x7f; + break; + + default: + dev->regs[reg] = val; + break; + } + + return 1; +} + + +static void +gl518sm_reset(gl518sm_t *dev) +{ + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->regs[0x00] = 0x80; + dev->regs[0x01] = 0x80; /* revision 0x80 can read all voltages */ + dev->regs[0x05] = 0xc7; + dev->regs[0x06] = 0xc2; + dev->regs[0x08] = 0x6464; + dev->regs[0x09] = 0xdac5; + dev->regs[0x0a] = 0xdac5; + dev->regs[0x0b] = 0xdac5; + dev->regs[0x0c] = 0xdac5; + dev->regs[0x0f] = 0x00; + + gl518sm_remap(dev, dev->i2c_addr | (dev->i2c_enabled ? 0x00 : 0x80)); +} + + +static void +gl518sm_close(void *priv) +{ + gl518sm_t *dev = (gl518sm_t *) priv; + + gl518sm_remap(dev, 0); + + free(dev); +} + + +static void * +gl518sm_init(const device_t *info) +{ + gl518sm_t *dev = (gl518sm_t *) malloc(sizeof(gl518sm_t)); + memset(dev, 0, sizeof(gl518sm_t)); + + dev->local = info->local; + + /* Set default values. */ + hwm_values_t defaults = { + { /* fan speeds */ + 3000, /* usually Chassis */ + 3000 /* usually CPU */ + }, { /* temperatures */ + 30 /* usually CPU */ + }, { /* voltages */ + hwm_get_vcore(), /* Vcore */ + RESISTOR_DIVIDER(12000, 150, 47), /* +12V (15K/4.7K divider suggested in the datasheet) */ + 3300, /* +3.3V */ + 5000 /* +5V */ + } + }; + hwm_values = defaults; + dev->values = &hwm_values; + + gl518sm_reset(dev); + gl518sm_remap(dev, dev->local & 0x7f); + + return dev; +} + +/* GL518SM on SMBus address 2Ch */ +const device_t gl518sm_2c_device = { + .name = "Genesys Logic GL518SM Hardware Monitor", + .internal_name = "gl518sm_2c", + .flags = DEVICE_ISA, + .local = 0x2c, + .init = gl518sm_init, + .close = gl518sm_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +/* GL518SM on SMBus address 2Dh */ +const device_t gl518sm_2d_device = { + .name = "Genesys Logic GL518SM Hardware Monitor", + .internal_name = "gl518sm_2d", + .flags = DEVICE_ISA, + .local = 0x2d, + .init = gl518sm_init, + .close = gl518sm_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 097b62e8e..b169d8e9e 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -23,22 +23,13 @@ #include #include <86box/86box.h> #include <86box/device.h> -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/hwm.h> #define LM75_TEMP_TO_REG(t) ((t) << 8) -static uint8_t lm75_smbus_read_byte(uint8_t addr, void *priv); -static uint8_t lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static uint16_t lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv); -static void lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv); -static void lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); -static void lm75_reset(lm75_t *dev); - - #ifdef ENABLE_LM75_LOG int lm75_do_log = ENABLE_LM75_LOG; @@ -59,64 +50,14 @@ lm75_log(const char *fmt, ...) #endif -void -lm75_remap(lm75_t *dev) -{ - lm75_log("LM75: remapping to SMBus %02Xh\n", dev->smbus_addr); - - smbus_removehandler(dev->smbus_addr, 1, - lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL, - lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL, - dev); - - if (dev->smbus_addr) smbus_sethandler(dev->smbus_addr, 1, - lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL, - lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL, - dev); -} - - static uint8_t -lm75_smbus_read_byte(uint8_t addr, void *priv) +lm75_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv) { lm75_t *dev = (lm75_t *) priv; - return lm75_read(dev, dev->addr_register); -} + dev->i2c_state = 0; -static uint8_t -lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - return lm75_read(dev, cmd); -} - -static uint16_t -lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - uint8_t rethi = 0; - uint8_t retlo = 0; - - switch (cmd & 0x3) { - case 0x0: /* temperature */ - rethi = lm75_read(dev, 0x0); - retlo = lm75_read(dev, 0x1); - break; - case 0x1: /* configuration */ - rethi = retlo = lm75_read(dev, 0x2); - break; - case 0x2: /* Thyst */ - rethi = lm75_read(dev, 0x3); - retlo = lm75_read(dev, 0x4); - break; - case 0x3: /* Tos */ - rethi = lm75_read(dev, 0x5); - retlo = lm75_read(dev, 0x6); - break; - } - - return (retlo << 8) | rethi; /* byte-swapped for some reason */ + return 1; } @@ -125,13 +66,12 @@ lm75_read(lm75_t *dev, uint8_t reg) { uint8_t ret; - /* The AS99127F hardware monitor uses the addresses of its LM75 devices - to access some of its proprietary registers. Pass this operation on to - the main monitor address through an internal SMBus call, if necessary. */ - if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr)) - ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg); + if ((reg & 0x7) == 0x0) /* temperature high byte */ + ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8; + else if ((reg & 0x7) == 0x1) /* temperature low byte */ + ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]); else - ret = dev->regs[reg & 0x7]; + ret = dev->regs[reg & 0x7]; lm75_log("LM75: read(%02X) = %02X\n", reg, ret); @@ -139,47 +79,43 @@ lm75_read(lm75_t *dev, uint8_t reg) } -static void -lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) +static uint8_t +lm75_i2c_read(void *bus, uint8_t addr, void *priv) { lm75_t *dev = (lm75_t *) priv; - dev->addr_register = val; -} + uint8_t ret = 0; + if (dev->i2c_state == 0) + dev->i2c_state = 1; -static void -lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - lm75_write(dev, cmd, val); -} + /* The AS99127F hardware monitor uses its primary LM75 device's + address to access some of its proprietary registers. Pass this + operation on to the main monitor code, if necessary. */ + if ((dev->addr_register & 0x80) && dev->as99127f) { + ret = lm78_as99127f_read(dev->as99127f, dev->addr_register); + } else { + switch (dev->addr_register & 0x3) { + case 0x0: /* temperature */ + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x0 : 0x1); + break; + case 0x1: /* configuration */ + ret = lm75_read(dev, 0x2); + break; -static void -lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - uint8_t valhi = (val >> 8); - uint8_t vallo = (val & 0xff); - - switch (cmd & 0x3) { - case 0x0: /* temperature */ - lm75_write(dev, 0x0, valhi); - lm75_write(dev, 0x1, vallo); - break; - case 0x1: /* configuration */ - lm75_write(dev, 0x2, vallo); - break; - case 0x2: /* Thyst */ - lm75_write(dev, 0x3, valhi); - lm75_write(dev, 0x4, vallo); - break; - case 0x3: /* Tos */ - lm75_write(dev, 0x5, valhi); - lm75_write(dev, 0x6, vallo); - break; - break; + case 0x2: /* Thyst */ + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x3 : 0x4); + break; + case 0x3: /* Tos */ + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x5 : 0x6); + break; + } } + + if (dev->i2c_state < 2) + dev->i2c_state++; + + return ret; } @@ -188,18 +124,10 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val) { lm75_log("LM75: write(%02X, %02X)\n", reg, val); - /* The AS99127F hardware monitor uses the addresses of its LM75 devices - to access some of its proprietary registers. Pass this operation on to - the main monitor address through an internal SMBus call, if necessary. */ - if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr)) { - smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val); - return 1; - } - uint8_t reg_idx = (reg & 0x7); if ((reg_idx <= 0x1) || (reg_idx == 0x7)) - return 0; /* read-only registers */ + return 0; /* read-only registers */ dev->regs[reg_idx] = val; @@ -207,16 +135,76 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val) } +static uint8_t +lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) +{ + lm75_t *dev = (lm75_t *) priv; + + if ((dev->i2c_state > 2) || ((dev->i2c_state == 2) && ((dev->addr_register & 0x3) == 0x1))) { + return 0; + } else if (dev->i2c_state == 0) { + dev->i2c_state = 1; + /* Linux lm75.c driver relies on the address register not changing if bit 2 is set. */ + if (((dev->addr_register & 0x80) && dev->as99127f) || !(data & 0x04)) + dev->addr_register = data; + return 1; + } + + /* The AS99127F hardware monitor uses its primary LM75 device's + address to access some of its proprietary registers. Pass this + operation on to the main monitor code, if necessary. */ + if ((dev->addr_register & 0x80) && dev->as99127f) { + return lm78_as99127f_write(dev->as99127f, dev->addr_register, data); + } else { + switch (dev->addr_register & 0x3) { + case 0x0: /* temperature */ + lm75_write(dev, (dev->i2c_state == 1) ? 0x0 : 0x1, data); + break; + + case 0x1: /* configuration */ + lm75_write(dev, 0x2, data); + break; + + case 0x2: /* Thyst */ + lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data); + break; + + case 0x3: /* Tos */ + lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data); + break; + } + } + + if (dev->i2c_state == 1) + dev->i2c_state = 2; + + return 1; +} + + +void +lm75_remap(lm75_t *dev, uint8_t addr) +{ + lm75_log("LM75: remapping to SMBus %02Xh\n", addr); + + if (dev->i2c_enabled) + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); + + if (addr < 0x80) + i2c_sethandler(i2c_smbus, addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); + + dev->i2c_addr = addr & 0x7f; + dev->i2c_enabled = !(addr & 0x80); +} + + static void lm75_reset(lm75_t *dev) { - uint16_t temp = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]); - dev->regs[0x0] = (temp >> 8); - dev->regs[0x1] = temp; dev->regs[0x3] = 0x4b; dev->regs[0x5] = 0x50; - lm75_remap(dev); + lm75_remap(dev, dev->i2c_addr | (dev->i2c_enabled ? 0x00 : 0x80)); } @@ -224,6 +212,9 @@ static void lm75_close(void *priv) { lm75_t *dev = (lm75_t *) priv; + + lm75_remap(dev, 0); + free(dev); } @@ -235,10 +226,14 @@ lm75_init(const device_t *info) memset(dev, 0, sizeof(lm75_t)); dev->local = info->local; - dev->values = hwm_get_values(); - dev->smbus_addr = dev->local; - dev->as99127f_smbus_addr = 0x00; + /* Set default value. */ + if (dev->local) + hwm_values.temperatures[dev->local >> 8] = 30; + dev->values = &hwm_values; + + dev->i2c_addr = dev->local & 0x7f; + dev->i2c_enabled = 1; lm75_reset(dev); @@ -248,22 +243,32 @@ lm75_init(const device_t *info) /* LM75 on SMBus address 4Ah, reporting temperatures[1]. */ const device_t lm75_1_4a_device = { - "National Semiconductor LM75 Temperature Sensor", - DEVICE_AT, - 0x14a, - lm75_init, lm75_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor LM75 Temperature Sensor", + .internal_name = "lm75_1_4a", + .flags = DEVICE_ISA, + .local = 0x14a, + .init = lm75_init, + .close = lm75_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; /* LM75 secondary/tertiary temperature sensors built into the Winbond W83781D family. Not to be used stand-alone. */ const device_t lm75_w83781d_device = { - "Winbond W83781D Secondary Temperature Sensor", - DEVICE_AT, - 0, - lm75_init, lm75_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83781D Secondary Temperature Sensor", + .internal_name = "lm75_w83781d", + .flags = DEVICE_ISA, + .local = 0, + .init = lm75_init, + .close = lm75_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index bf474db9e..627a0e15e 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -24,50 +24,60 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include <86box/timer.h> +#include <86box/machine.h> +#include <86box/nvr.h> #include "cpu.h" -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/hwm.h> -#define LM78_SMBUS 0x10000 -#define LM78_W83781D 0x20000 -#define LM78_AS99127F_REV1 0x40000 -#define LM78_AS99127F_REV2 0x80000 -#define LM78_AS99127F (LM78_AS99127F_REV1 | LM78_AS99127F_REV2) /* special mask covering both _REV1 and _REV2 */ -#define LM78_WINBOND (LM78_W83781D | LM78_AS99127F) /* special mask covering all Winbond variants */ +#define LM78_I2C 0x010000 +#define LM78_W83781D 0x020000 +#define LM78_AS99127F_REV1 0x040000 +#define LM78_AS99127F_REV2 0x080000 +#define LM78_W83782D 0x100000 +#define LM78_P5A 0x200000 +#define LM78_AS99127F (LM78_AS99127F_REV1 | LM78_AS99127F_REV2) /* mask covering both _REV1 and _REV2 */ +#define LM78_WINBOND (LM78_W83781D | LM78_AS99127F | LM78_W83782D) /* mask covering all Winbond variants */ #define LM78_WINBOND_VENDOR_ID ((dev->local & LM78_AS99127F_REV1) ? 0x12c3 : 0x5ca3) +#define LM78_WINBOND_BANK (dev->regs[0x4e] & 0x07) #define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a))) #define LM78_RPM_TO_REG(r, d) ((r) ? CLAMP(1350000 / (r * d), 1, 255) : 0) #define LM78_VOLTAGE_TO_REG(v) ((v) >> 4) +#define LM78_NEG_VOLTAGE(v, r) (v * (604.0 / ((double) r))) /* negative voltage formula from the W83781D datasheet */ +#define LM78_NEG_VOLTAGE2(v, r) (((3600 + v) * (((double) r) / (((double) r) + 56.0))) - v) /* negative voltage formula from the W83782D datasheet */ typedef struct { - uint32_t local; - hwm_values_t *values; - device_t *lm75[2]; + uint32_t local; + hwm_values_t *values; + device_t *lm75[2]; + pc_timer_t reset_timer; - uint8_t regs[256]; - uint8_t addr_register; - uint8_t data_register; + uint8_t regs[256]; + union { + struct { + uint8_t regs[2][16]; + } w83782d; + struct { + uint8_t regs[3][128]; - uint8_t smbus_addr; - uint8_t hbacs; - uint8_t active_bank; + uint8_t nvram[1024], nvram_i2c_state: 2, nvram_updated: 1; + uint16_t nvram_addr_register: 10; + int8_t nvram_block_len: 6; + + uint8_t security_i2c_state: 1, security_addr_register: 7; + } as99127f; + }; + uint8_t addr_register, data_register; + + uint8_t i2c_addr: 7, i2c_state: 1, i2c_enabled: 1; } lm78_t; -static uint8_t lm78_isa_read(uint16_t port, void *priv); -static uint8_t lm78_smbus_read_byte(uint8_t addr, void *priv); -static uint8_t lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static uint16_t lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv); -static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank); -static void lm78_isa_write(uint16_t port, uint8_t val, void *priv); -static void lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv); -static void lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); -static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); -static void lm78_reset(lm78_t *dev, uint8_t initialization); +static void lm78_remap(lm78_t *dev, uint8_t addr); #ifdef ENABLE_LM78_LOG @@ -90,34 +100,289 @@ lm78_log(const char *fmt, ...) #endif -static void -lm78_remap(lm78_t *dev) +void +lm78_nvram(lm78_t *dev, uint8_t save) { + size_t l = strlen(machine_get_internal_name_ex(machine)) + 14; + char *nvr_path = (char *) malloc(l); + sprintf(nvr_path, "%s_as99127f.nvr", machine_get_internal_name_ex(machine)); + + FILE *f = nvr_fopen(nvr_path, save ? "wb" : "rb"); + if (f) { + if (save) + fwrite(&dev->as99127f.nvram, sizeof(dev->as99127f.nvram), 1, f); + else + fread(&dev->as99127f.nvram, sizeof(dev->as99127f.nvram), 1, f); + fclose(f); + } + + free(nvr_path); +} + + +static uint8_t +lm78_nvram_start(void *bus, uint8_t addr, uint8_t read, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + dev->as99127f.nvram_i2c_state = 0; + + return 1; +} + + +static uint8_t +lm78_nvram_read(void *bus, uint8_t addr, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + uint8_t ret = 0xff; + + switch (dev->as99127f.nvram_i2c_state) { + case 0: + dev->as99127f.nvram_i2c_state = 1; + /* fall-through */ + + case 1: + ret = dev->as99127f.regs[0][0x0b] & 0x3f; + lm78_log("LM78: nvram_read(blocklen) = %02X\n", ret); + break; + + case 2: + ret = dev->as99127f.nvram[dev->as99127f.nvram_addr_register]; + lm78_log("LM78: nvram_read(%03X) = %02X\n", dev->as99127f.nvram_addr_register, ret); + + dev->as99127f.nvram_addr_register++; + break; + + default: + lm78_log("LM78: nvram_read(unknown) = %02X\n", ret); + break; + } + + if (dev->as99127f.nvram_i2c_state < 2) + dev->as99127f.nvram_i2c_state++; + + return ret; +} + + +static uint8_t +lm78_nvram_write(void *bus, uint8_t addr, uint8_t val, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + switch (dev->as99127f.nvram_i2c_state) { + case 0: + lm78_log("LM78: nvram_write(address, %02X)\n", val); + dev->as99127f.nvram_addr_register = (addr << 8) | val; + break; + + case 1: + lm78_log("LM78: nvram_write(blocklen, %02X)\n", val); + dev->as99127f.nvram_block_len = val & 0x3f; + if (dev->as99127f.nvram_block_len <= 0) + dev->as99127f.nvram_i2c_state = 3; + break; + + case 2: + lm78_log("LM78: nvram_write(%03X, %02X)\n", dev->as99127f.nvram_addr_register, val); + dev->as99127f.nvram[dev->as99127f.nvram_addr_register++] = val; + dev->as99127f.nvram_updated = 1; + if (--dev->as99127f.nvram_block_len <= 0) + dev->as99127f.nvram_i2c_state = 3; + break; + + default: + lm78_log("LM78: nvram_write(unknown, %02X)\n", val); + break; + } + + if (dev->as99127f.nvram_i2c_state < 2) + dev->as99127f.nvram_i2c_state++; + + return dev->as99127f.nvram_i2c_state < 3; +} + + +static uint8_t +lm78_security_start(void *bus, uint8_t addr, uint8_t read, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + dev->as99127f.security_i2c_state = 0; + + return 1; +} + + +static uint8_t +lm78_security_read(void *bus, uint8_t addr, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + return dev->as99127f.regs[2][dev->as99127f.security_addr_register++]; +} + + +static uint8_t +lm78_security_write(void *bus, uint8_t addr, uint8_t val, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + if (dev->as99127f.security_i2c_state == 0) { + dev->as99127f.security_i2c_state = 1; + dev->as99127f.security_addr_register = val; + } else { + switch (dev->as99127f.security_addr_register) { + case 0xe0: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + /* read-only registers */ + return 1; + } + + dev->as99127f.regs[2][dev->as99127f.security_addr_register++] = val; + } + + return 1; +} + + +static void +lm78_reset(void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + uint8_t initialization = dev->regs[0x40] & 0x80; + + memset(dev->regs, 0, 256); + memset(dev->regs + 0xc0, 0xff, 32); /* C0-DF are 0xFF on a real AS99127F */ + + dev->regs[0x40] = 0x08; + dev->regs[0x46] = 0x40; + dev->regs[0x47] = 0x50; + if (dev->local & LM78_I2C) { + if (!initialization) { /* don't reset main I2C address if the reset was triggered by the INITIALIZATION bit */ + if (dev->local & LM78_P5A) + dev->i2c_addr = 0x77; + else + dev->i2c_addr = 0x2d; + dev->i2c_enabled = 1; + } + dev->regs[0x48] = dev->i2c_addr; + if (dev->local & LM78_WINBOND) + dev->regs[0x4a] = 0x01; + } else { + dev->regs[0x48] = 0x00; + if (dev->local & LM78_WINBOND) + dev->regs[0x4a] = 0x88; + } + if (dev->local & LM78_WINBOND) { + dev->regs[0x49] = 0x02; + dev->regs[0x4b] = 0x44; + dev->regs[0x4c] = 0x01; + dev->regs[0x4d] = 0x15; + dev->regs[0x4e] = 0x80; + dev->regs[0x4f] = LM78_WINBOND_VENDOR_ID >> 8; + dev->regs[0x57] = 0x80; + + if (dev->local & LM78_AS99127F) { + dev->regs[0x49] = 0x20; + dev->regs[0x4c] = 0x00; + dev->regs[0x56] = 0xff; + dev->regs[0x57] = 0xff; + dev->regs[0x58] = 0x31; + dev->regs[0x59] = 0x8f; + dev->regs[0x5a] = 0x8f; + dev->regs[0x5b] = 0x2a; + dev->regs[0x5c] = 0xe0; + dev->regs[0x5d] = 0x48; + dev->regs[0x5e] = 0xe2; + dev->regs[0x5f] = 0x1f; + + dev->as99127f.regs[0][0x02] = 0xff; + dev->as99127f.regs[0][0x03] = 0xff; + dev->as99127f.regs[0][0x08] = 0xff; + dev->as99127f.regs[0][0x09] = 0xff; + dev->as99127f.regs[0][0x0b] = 0x01; + + /* regs[1] and regs[2] start at 0x80 */ + dev->as99127f.regs[1][0x00] = 0x88; + dev->as99127f.regs[1][0x01] = 0x10; + dev->as99127f.regs[1][0x03] = 0x02; /* GPO, but things break if GPO16 isn't set */ + dev->as99127f.regs[1][0x04] = 0x01; + dev->as99127f.regs[1][0x05] = 0x1f; + lm78_as99127f_write(dev, 0x06, 0x2f); + + dev->as99127f.regs[2][0x60] = 0xf0; + } else if (dev->local & LM78_W83781D) { + dev->regs[0x58] = 0x10; + } else if (dev->local & LM78_W83782D) { + dev->regs[0x58] = 0x30; + } + } else { + dev->regs[0x49] = 0x40; + } + + lm78_remap(dev, dev->i2c_addr | (dev->i2c_enabled ? 0x00 : 0x80)); +} + + +static uint8_t +lm78_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + dev->i2c_state = 0; + + return 1; +} + + +static uint8_t +lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank) +{ + uint8_t ret = 0, masked_reg = reg, bankswitched = ((reg & 0xf8) == 0x50); lm75_t *lm75; - if (!(dev->local & LM78_SMBUS)) return; - - lm78_log("LM78: remapping to SMBus %02Xh\n", dev->smbus_addr); - - smbus_removehandler(dev->smbus_addr, 1, - lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL, - lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL, - dev); - - if (dev->smbus_addr) smbus_sethandler(dev->smbus_addr, 1, - lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL, - lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL, - dev); - - if (dev->local & LM78_AS99127F) { - /* Store the main SMBus address on the LM75 devices to ensure reads/writes - to the AS99127F's proprietary registers are passed through to this side. */ - for (uint8_t i = 0; i <= 1; i++) { - lm75 = device_get_priv(dev->lm75[i]); - if (lm75) - lm75->as99127f_smbus_addr = dev->smbus_addr; - } + if ((dev->local & LM78_AS99127F) && (bank == 3) && (reg != 0x4e)) { + /* AS99127F additional registers */ + if (!((dev->local & LM78_AS99127F_REV2) && ((reg == 0x80) || (reg == 0x81)))) + ret = dev->as99127f.regs[0][reg & 0x7f]; + } else if (bankswitched && ((bank == 1) || (bank == 2))) { + /* LM75 registers */ + lm75 = device_get_priv(dev->lm75[bank - 1]); + if (lm75) + ret = lm75_read(lm75, reg); + } else if (bankswitched && ((bank == 4) || (bank == 5) || (bank == 6))) { + /* W83782D additional registers */ + if (dev->local & LM78_W83782D) { + if ((bank == 5) && ((reg == 0x50) || (reg == 0x51))) /* voltages */ + ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[7 + (reg & 1)]); + else if (bank < 6) + ret = dev->w83782d.regs[bank - 4][reg & 0x0f]; + } + } else { + /* regular registers */ + if ((reg >= 0x60) && (reg <= 0x94)) /* read auto-increment value RAM registers from their non-auto-increment locations */ + masked_reg = reg & 0x3f; + if ((masked_reg >= 0x20) && (masked_reg <= 0x26)) /* voltages */ + ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[reg & 7]); + else if ((dev->local & LM78_AS99127F) && (masked_reg <= 0x05)) /* AS99127F additional voltages */ + ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[7 + masked_reg]); + else if (masked_reg == 0x27) /* temperature */ + ret = dev->values->temperatures[0]; + else if ((masked_reg >= 0x28) && (masked_reg <= 0x2a)) { /* fan speeds */ + ret = (dev->regs[((reg & 3) == 2) ? 0x4b : 0x47] >> ((reg & 3) ? 6 : 4)) & 0x03; /* bits [1:0] */ + if (dev->local & LM78_W83782D) + ret |= (dev->regs[0x5d] >> (3 + (reg & 3))) & 0x04; /* bit 2 */ + ret = LM78_RPM_TO_REG(dev->values->fans[reg & 3], 1 << ret); + } else if ((reg == 0x4f) && (dev->local & LM78_WINBOND)) /* two-byte vendor ID register */ + ret = (dev->regs[0x4e] & 0x80) ? (uint8_t) (LM78_WINBOND_VENDOR_ID >> 8) : (uint8_t) LM78_WINBOND_VENDOR_ID; + else + ret = dev->regs[masked_reg]; } + + lm78_log("LM78: read(%02X, %d) = %02X\n", reg, bank, ret); + + return ret; } @@ -128,22 +393,25 @@ lm78_isa_read(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port & 0x7) { - case 0x5: - ret = (dev->addr_register & 0x7f); - break; - case 0x6: - ret = lm78_read(dev, dev->addr_register, dev->active_bank); + case 0x5: + ret = dev->addr_register & 0x7f; + break; - if ((dev->active_bank == 0) && - ((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) || - ((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) { - /* auto-increment registers */ - dev->addr_register++; - } - break; - default: - lm78_log("LM78: Read from unknown ISA port %d\n", port & 0x7); - break; + case 0x6: + ret = lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK); + + if (((LM78_WINBOND_BANK == 0) && + ((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) || + ((dev->addr_register >= 0x60) && (dev->addr_register < 0x94)))) || + ((dev->local & LM78_W83782D) && (LM78_WINBOND_BANK == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) { + /* auto-increment registers */ + dev->addr_register++; + } + break; + + default: + lm78_log("LM78: Read from unknown ISA port %d\n", port & 0x7); + break; } return ret; @@ -151,108 +419,26 @@ lm78_isa_read(uint16_t port, void *priv) static uint8_t -lm78_smbus_read_byte(uint8_t addr, void *priv) +lm78_i2c_read(void *bus, uint8_t addr, void *priv) { lm78_t *dev = (lm78_t *) priv; - return lm78_read(dev, dev->addr_register, dev->active_bank); + + return lm78_read(dev, dev->addr_register++, LM78_WINBOND_BANK); } -static uint8_t -lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) +uint8_t +lm78_as99127f_read(void *priv, uint8_t reg) { lm78_t *dev = (lm78_t *) priv; - return lm78_read(dev, cmd, dev->active_bank); -} + uint8_t ret = dev->as99127f.regs[1][reg & 0x7f]; - -static uint16_t -lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - return (lm78_read(dev, cmd, dev->active_bank) << 8) | lm78_read(dev, cmd, dev->active_bank); -} - - -static uint8_t -lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank) -{ - uint8_t ret = 0; - lm75_t *lm75; - - if (((reg & 0xf8) == 0x50) && (bank != 0)) { - /* LM75 registers */ - lm75 = device_get_priv(dev->lm75[bank - 1]); - if (lm75) - ret = lm75_read(lm75, reg); - } else { - /* regular registers */ - if ((reg == 0x4f) && (dev->local & LM78_WINBOND)) /* special case for two-byte vendor ID register */ - ret = (dev->hbacs ? (LM78_WINBOND_VENDOR_ID >> 8) : LM78_WINBOND_VENDOR_ID); - else if ((reg >= 0x60) && (reg <= 0x7f)) /* read auto-increment value RAM registers from their non-auto-increment locations */ - ret = dev->regs[reg & 0x3f]; - else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors [0x00:0x12] to [0x80:0x92] */ - ret = dev->regs[reg & 0x7f]; - else - ret = dev->regs[reg]; - } - - lm78_log("LM78: read(%02X, %d) = %02X\n", reg, bank, ret); + lm78_log("LM78: read(%02X, AS99127F) = %02X\n", reg, ret); return ret; } -static void -lm78_isa_write(uint16_t port, uint8_t val, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - - switch (port & 0x7) { - case 0x5: - dev->addr_register = (val & 0x7f); - break; - case 0x6: - lm78_write(dev, dev->addr_register, val, dev->active_bank); - - if ((dev->active_bank == 0) && - ((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) || - ((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) { - /* auto-increment registers */ - dev->addr_register++; - } - break; - default: - lm78_log("LM78: Write %02X to unknown ISA port %d\n", val, port & 0x7); - break; - } -} - - -static void -lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - dev->addr_register = val; -} - - -static void -lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - lm78_write(dev, cmd, val, dev->active_bank); -} - - -static void -lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - lm78_write(dev, cmd, val, dev->active_bank); -} - - static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) { @@ -260,97 +446,125 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) lm78_log("LM78: write(%02X, %d, %02X)\n", reg, bank, val); - if (((reg & 0xf8) == 0x50) && (bank != 0)) { - /* LM75 registers */ - lm75 = device_get_priv(dev->lm75[bank - 1]); - if (lm75) - lm75_write(lm75, reg, val); - return 1; + if ((dev->local & LM78_AS99127F) && (bank == 3) && (reg != 0x4e)) { + /* AS99127F additional registers */ + reg &= 0x7f; + switch (reg) { + case 0x00: case 0x01: case 0x04: case 0x05: case 0x06: case 0x07: + /* read-only registers */ + return 0; + + case 0x20: + val &= 0x7f; + break; + } + + dev->as99127f.regs[0][reg] = val; + return 1; + } else if ((reg & 0xf8) == 0x50) { + if ((bank == 1) || (bank == 2)) { + /* LM75 registers */ + lm75 = device_get_priv(dev->lm75[bank - 1]); + if (lm75) + return lm75_write(lm75, reg, val); + return 1; + } else if (dev->local & LM78_W83782D) { + /* W83782D additional registers */ + if (bank == 4) { + switch (reg) { + case 0x50: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5d: case 0x5e: case 0x5f: + /* read-only registers */ + return 0; + } + + dev->w83782d.regs[0][reg & 0x0f] = val; + return 1; + } else if (bank == 5) { + switch (reg) { + case 0x50: case 0x51: case 0x52: case 0x53: case 0x58: case 0x59: case 0x5a: + case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + /* read-only registers */ + return 0; + } + + dev->w83782d.regs[1][reg & 0x0f] = val; + return 1; + } else if (bank == 6) { + return 0; + } + } } /* regular registers */ switch (reg) { - case 0x41: case 0x42: case 0x4f: case 0x58: - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: - case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: - /* read-only registers */ - return 0; - case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: - /* Winbond-only registers */ - if (!(dev->local & LM78_WINBOND)) - return 0; - break; + case 0x41: case 0x42: case 0x4f: case 0x58: + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: + /* read-only registers */ + return 0; + + case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: + /* Winbond-only registers */ + if (!(dev->local & LM78_WINBOND)) + return 0; + break; } - if ((reg >= 0x60) && (reg <= 0x7f)) /* write auto-increment value RAM registers to their non-auto-increment locations */ - dev->regs[reg & 0x3f] = val; - else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors [0x00:0x12] to [0x80:0x92] */ - dev->regs[reg & 0x7f] = val; - else - dev->regs[reg] = val; + if ((reg >= 0x60) && (reg <= 0x94)) /* write auto-increment value RAM registers to their non-auto-increment locations */ + reg &= 0x3f; + uint8_t prev = dev->regs[reg]; + dev->regs[reg] = val; switch (reg) { - case 0x40: - if (val & 0x80) { - /* INITIALIZATION bit resets all registers except main SMBus address */ - lm78_reset(dev, 1); - } - break; - case 0x47: - /* update FAN1/FAN2 values to match the new divisor */ - dev->regs[0x28] = LM78_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x47] >> 4) & 0x3)); - dev->regs[0x29] = LM78_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x47] >> 6) & 0x3)); - break; - case 0x48: - /* set main SMBus address */ - if (dev->local & LM78_SMBUS) { - dev->smbus_addr = (dev->regs[0x48] & 0x7f); - lm78_remap(dev); - } - break; - case 0x49: - if (!(dev->local & LM78_WINBOND)) { - if (val & 0x20) { - /* Chip Reset bit (LM78 only) resets all registers */ - lm78_reset(dev, 0); - } else { - dev->regs[0x49] = 0x40; - } - } else { - dev->regs[0x49] &= 0x01; - } - break; - case 0x4a: - /* set LM75 SMBus addresses (Winbond only) */ - if (dev->local & LM78_SMBUS) { - for (uint8_t i = 0; i <= 1; i++) { - lm75 = device_get_priv(dev->lm75[i]); - if (!lm75) - continue; - if (dev->regs[0x4a] & (0x08 * (0x10 * i))) /* DIS_T2 and DIS_T3 bit disable those interfaces */ - lm75->smbus_addr = 0x00; - else - lm75->smbus_addr = (0x48 + ((dev->regs[0x4a] >> (i * 4)) & 0x7)); - lm75_remap(lm75); - } - } - break; - case 0x4b: - /* update FAN3 value to match the new divisor */ - dev->regs[0x2a] = LM78_RPM_TO_REG(dev->values->fans[2], 1 << ((dev->regs[0x4b] >> 6) & 0x3)); - break; - case 0x4e: - dev->hbacs = (dev->regs[0x4e] & 0x80); - /* BANKSEL[0:2] is a bitfield according to the datasheet, but not in reality */ - dev->active_bank = (dev->regs[0x4e] & 0x07); - break; - case 0x87: - /* fixes AS99127F boards hanging after BIOS save & exit, probably a reset register */ - if ((dev->local & LM78_AS99127F) && (val == 0x01)) { - lm78_log("LM78: Reset requested through AS99127F\n"); - resetx86(); - } - break; + case 0x40: + if (val & 0x80) /* INITIALIZATION bit resets all registers except main I2C address */ + lm78_reset(dev); + break; + + case 0x48: + /* set main I2C address */ + if (dev->local & LM78_I2C) + lm78_remap(dev, dev->regs[0x48] & 0x7f); + break; + + case 0x49: + if (!(dev->local & LM78_WINBOND)) { + if (val & 0x20) /* Chip Reset bit (LM78 only) resets all registers */ + lm78_reset(dev); + else + dev->regs[0x49] = 0x40; + } else { + dev->regs[0x49] &= 0x01; + } + break; + + case 0x4a: + /* set LM75 I2C addresses (Winbond only) */ + if (dev->local & LM78_I2C) { + for (uint8_t i = 0; i <= 1; i++) { + lm75 = device_get_priv(dev->lm75[i]); + if (!lm75) + continue; + if (val & (0x08 * (0x10 * i))) /* DIS_T2 and DIS_T3 bit disable those interfaces */ + lm75_remap(lm75, 0x80); + else + lm75_remap(lm75, 0x48 + ((val >> (i * 4)) & 0x7)); + } + } + break; + + case 0x5c: + /* enable/disable AS99127F NVRAM */ + if (dev->local & LM78_AS99127F) { + if (prev & 0x01) + i2c_removehandler(i2c_smbus, (prev & 0xf8) >> 1, 4, lm78_nvram_start, lm78_nvram_read, lm78_nvram_write, NULL, dev); + if (val & 0x01) + i2c_sethandler(i2c_smbus, (val & 0xf8) >> 1, 4, lm78_nvram_start, lm78_nvram_read, lm78_nvram_write, NULL, dev); + } + break; } return 1; @@ -358,77 +572,123 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) static void -lm78_reset(lm78_t *dev, uint8_t initialization) +lm78_isa_write(uint16_t port, uint8_t val, void *priv) { - memset(dev->regs, 0, 256); - memset(dev->regs + 0xc0, 0xff, 32); /* C0-DF are 0xFF at least on the AS99127F */ + lm78_t *dev = (lm78_t *) priv; - uint8_t i; - for (i = 0; i <= 6; i++) - dev->regs[0x20 + i] = LM78_VOLTAGE_TO_REG(dev->values->voltages[i]); - dev->regs[0x27] = dev->values->temperatures[0]; - for (i = 0; i <= 2; i++) - dev->regs[0x28 + i] = LM78_RPM_TO_REG(dev->values->fans[i], 2); - dev->regs[0x40] = 0x08; - dev->regs[0x46] = 0x40; - dev->regs[0x47] = 0x50; - if (dev->local & LM78_SMBUS) { - if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */ - dev->smbus_addr = 0x2d; - dev->regs[0x48] = dev->smbus_addr; - if (dev->local & LM78_WINBOND) - dev->regs[0x4a] = 0x01; - } else { - dev->regs[0x48] = 0x00; - if (dev->local & LM78_WINBOND) - dev->regs[0x4a] = 0x88; + switch (port & 0x7) { + case 0x5: + dev->addr_register = val & 0x7f; + break; + + case 0x6: + lm78_write(dev, dev->addr_register, val, LM78_WINBOND_BANK); + + if (((LM78_WINBOND_BANK == 0) && + ((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) || + ((dev->addr_register >= 0x60) && (dev->addr_register < 0x94)))) || + ((dev->local & LM78_W83782D) && (LM78_WINBOND_BANK == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) { + /* auto-increment registers */ + dev->addr_register++; + } + break; + + default: + lm78_log("LM78: Write %02X to unknown ISA port %d\n", val, port & 0x7); + break; } - if (dev->local & LM78_WINBOND) { - dev->regs[0x49] = 0x02; - dev->regs[0x4b] = 0x44; - dev->regs[0x4c] = 0x01; - dev->regs[0x4d] = 0x15; - dev->regs[0x4e] = 0x80; - dev->hbacs = (dev->regs[0x4e] & 0x80); - dev->regs[0x4f] = (LM78_WINBOND_VENDOR_ID >> 8); - dev->regs[0x57] = 0x80; +} - /* Initialize proprietary registers on the AS99127F. The BIOS accesses some - of these on boot through read_byte_cmd on the TEMP2 address, hanging on - POST code C1 if they're defaulted to 0. There's no documentation on what - these are for. The following values were dumped from a live, initialized - AS99127F Rev. 2 on a P4B motherboard, and they seem to work well enough. */ - if (dev->local & LM78_AS99127F) { - /* 0x00 appears to mirror IN2 Low Limit */ - dev->regs[0x01] = dev->regs[0x23]; /* appears to mirror IN3 */ - dev->regs[0x02] = LM78_VOLTAGE_TO_REG(2800); /* appears to be a "maximum VCORE" of some kind; must read 2.8V on P3 boards */ - dev->regs[0x03] = 0x60; - dev->regs[0x04] = dev->regs[0x23]; /* appears to mirror IN3 */ - dev->regs[0x05] = dev->regs[0x22]; /* appears to mirror IN2 */ - dev->regs[0x07] = 0xcd; - /* 0x08 appears to mirror IN3 Low Limit */ - dev->regs[0x09] = dev->regs[0x0f] = dev->regs[0x11] = 0xf8; /* three instances of */ - dev->regs[0x0a] = dev->regs[0x10] = dev->regs[0x12] = 0xa5; /* the same word */ - dev->regs[0x0b] = 0xac; - dev->regs[0x0c] = 0x8c; - dev->regs[0x0d] = 0x68; - dev->regs[0x0e] = 0x54; - dev->regs[0x53] = dev->regs[0x54] = dev->regs[0x55] = 0xff; - dev->regs[0x58] = 0x31; - dev->regs[0x59] = dev->regs[0x5a] = 0x8f; - dev->regs[0x5c] = 0xe0; - dev->regs[0x5d] = 0x48; - dev->regs[0x5e] = 0xe2; - dev->regs[0x5f] = 0x3f; - } else { - dev->regs[0x58] = 0x10; - } - } else { - dev->regs[0x49] = 0x40; +static uint8_t +lm78_i2c_write(void *bus, uint8_t addr, uint8_t val, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + if (dev->i2c_state == 0) { + dev->i2c_state = 1; + dev->addr_register = val; + } else + lm78_write(dev, dev->addr_register++, val, LM78_WINBOND_BANK); + + return 1; +} + + +uint8_t +lm78_as99127f_write(void *priv, uint8_t reg, uint8_t val) +{ + lm78_t *dev = (lm78_t *) priv; + + lm78_log("LM78: write(%02X, AS99127F, %02X)\n", reg, val); + + reg &= 0x7f; + uint8_t prev = dev->as99127f.regs[1][reg]; + dev->as99127f.regs[1][reg] = val; + + switch (reg) { + case 0x01: + if (val & 0x40) { + dev->as99127f.regs[1][0x00] = 0x88; + dev->as99127f.regs[1][0x01] &= 0xe0; + dev->as99127f.regs[1][0x03] &= 0xf7; + dev->as99127f.regs[1][0x07] &= 0xfe; + } + if (!(val & 0x10)) { /* CUV4X-LS */ + lm78_log("LM78: Reset requested through AS99127F CLKRST\n"); + timer_set_delay_u64(&dev->reset_timer, 300000 * TIMER_USEC); + } + break; + + case 0x06: + /* security device I2C address */ + i2c_removehandler(i2c_smbus, prev & 0x7f, 1, lm78_security_start, lm78_security_read, lm78_security_write, NULL, dev); + i2c_sethandler(i2c_smbus, val & 0x7f, 1, lm78_security_start, lm78_security_read, lm78_security_write, NULL, dev); + break; + + case 0x07: + if (val & 0x01) { /* other AS99127F boards */ + lm78_log("LM78: Reset requested through AS99127F GPO15\n"); + resetx86(); + } + break; } - lm78_remap(dev); + return 1; +} + + +static void +lm78_reset_timer(void *priv) +{ + pc_reset_hard(); +} + + +static void +lm78_remap(lm78_t *dev, uint8_t addr) +{ + lm75_t *lm75; + + if (!(dev->local & LM78_I2C)) return; + + lm78_log("LM78: remapping to SMBus %02Xh\n", addr); + + if (dev->i2c_enabled) + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); + + if (addr < 0x80) + i2c_sethandler(i2c_smbus, addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); + + dev->i2c_addr = addr & 0x7f; + dev->i2c_enabled = !(addr & 0x80); + + if (dev->local & LM78_AS99127F) { + /* Store our handle on the primary LM75 device to ensure reads/writes + to the AS99127F's proprietary registers are passed through to this side. */ + if ((lm75 = device_get_priv(dev->lm75[0]))) + lm75->as99127f = dev; + } } @@ -437,9 +697,12 @@ lm78_close(void *priv) { lm78_t *dev = (lm78_t *) priv; - uint16_t isa_io = (dev->local & 0xffff); + uint16_t isa_io = dev->local & 0xffff; if (isa_io) - io_removehandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); + io_removehandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); + + if (dev->as99127f.nvram_updated) + lm78_nvram(dev, 1); free(dev); } @@ -452,72 +715,161 @@ lm78_init(const device_t *info) memset(dev, 0, sizeof(lm78_t)); dev->local = info->local; - dev->values = hwm_get_values(); - /* initialize secondary/tertiary LM75 sensors on Winbond */ - for (uint8_t i = 0; i <= 1; i++) { - if (dev->local & LM78_WINBOND) { - dev->lm75[i] = (device_t *) malloc(sizeof(device_t)); - memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t)); - dev->lm75[i]->local = ((i + 1) << 8); - if (dev->local & LM78_SMBUS) - dev->lm75[i]->local |= (0x48 + i); - device_add(dev->lm75[i]); - } else { - dev->lm75[i] = NULL; - } + /* Set global default values. */ + hwm_values_t defaults = { + { /* fan speeds */ + 3000, /* usually Chassis, sometimes CPU */ + 3000, /* usually CPU, sometimes Chassis */ + 3000 /* usually PSU, sometimes Chassis */ + }, { /* temperatures */ + 30, /* usually Board, sometimes Chassis */ + 30, /* Winbond only: usually CPU, sometimes Probe */ + 30 /* Winbond only: usually CPU when not the one above */ + }, { /* voltages */ + hwm_get_vcore(), /* Vcore */ + 0, /* sometimes Vtt, Vio or second CPU */ + 3300, /* +3.3V */ + RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ + RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ + LM78_NEG_VOLTAGE(12000, 2100), /* -12V */ + LM78_NEG_VOLTAGE(5000, 909), /* -5V */ + RESISTOR_DIVIDER(5000, 51, 75), /* W83782D/AS99127F only: +5VSB (5.1K/7.5K divider suggested in the datasheet) */ + 3000, /* W83782D/AS99127F only: Vbat */ + 2500, /* AS99127F only: +2.5V */ + 1500, /* AS99127F only: +1.5V */ + 3000, /* AS99127F only: NVRAM */ + 3300 /* AS99127F only: +3.3VSB */ + } + }; + + /* Set chip-specific default values. */ + if (dev->local & LM78_AS99127F) { + /* AS99127F: different -12V Rin value (bruteforced) */ + defaults.voltages[5] = LM78_NEG_VOLTAGE(12000, 2400); + + timer_add(&dev->reset_timer, lm78_reset_timer, dev, 0); + + lm78_nvram(dev, 0); + } else if (dev->local & LM78_W83782D) { + /* W83782D: different negative voltage formula */ + defaults.voltages[5] = LM78_NEG_VOLTAGE2(12000, 232); + defaults.voltages[6] = LM78_NEG_VOLTAGE2(5000, 120); } - lm78_reset(dev, 0); + hwm_values = defaults; + dev->values = &hwm_values; - uint16_t isa_io = (dev->local & 0xffff); + /* Initialize secondary/tertiary LM75 sensors on Winbond. */ + for (uint8_t i = 0; i <= 1; i++) { + if (dev->local & LM78_WINBOND) { + dev->lm75[i] = (device_t *) malloc(sizeof(device_t)); + memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t)); + dev->lm75[i]->local = (i + 1) << 8; + if (dev->local & LM78_I2C) + dev->lm75[i]->local |= 0x48 + i; + device_add(dev->lm75[i]); + } else { + dev->lm75[i] = NULL; + } + } + + lm78_reset(dev); + + uint16_t isa_io = dev->local & 0xffff; if (isa_io) - io_sethandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); + io_sethandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev); return dev; } - /* National Semiconductor LM78 on ISA and SMBus. */ const device_t lm78_device = { - "National Semiconductor LM78 Hardware Monitor", - DEVICE_ISA, - 0x290 | LM78_SMBUS, - lm78_init, lm78_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor LM78 Hardware Monitor", + .internal_name = "lm78", + .flags = DEVICE_ISA, + .local = 0x290 | LM78_I2C, + .init = lm78_init, + .close = lm78_close, + .reset = lm78_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -/* Winbond W83781D (or ASUS AS97127F) on ISA and SMBus. */ +/* Winbond W83781D on ISA and SMBus. */ const device_t w83781d_device = { - "Winbond W83781D Hardware Monitor", - DEVICE_ISA, - 0x290 | LM78_SMBUS | LM78_W83781D, - lm78_init, lm78_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83781D Hardware Monitor", + .internal_name = "w83781d", + .flags = DEVICE_ISA, + .local = 0x290 | LM78_I2C | LM78_W83781D, + .init = lm78_init, + .close = lm78_close, + .reset = lm78_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +/* Winbond W83781D on ISA and SMBus. */ +const device_t w83781d_p5a_device = { + .name = "Winbond W83781D Hardware Monitor (ASUS P5A)", + .internal_name = "w83781d_p5a", + .flags = DEVICE_ISA, + .local = 0x290 | LM78_I2C | LM78_W83781D | LM78_P5A, + .init = lm78_init, + .close = lm78_close, + .reset = lm78_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; -/* The ASUS AS99127F is a customized W83781D with no ISA interface (SMBus only), - added proprietary registers and different chip/vendor IDs. */ +/* The AS99127F is an ASIC manufactured by Holtek for ASUS, containing an + I2C-only W83781D clone with additional voltages, GPIOs and fan control. */ const device_t as99127f_device = { - "ASUS AS99127F Rev. 1 Hardware Monitor", - DEVICE_ISA, - LM78_SMBUS | LM78_AS99127F_REV1, - lm78_init, lm78_close, NULL, - NULL, NULL, NULL, - NULL + .name = "ASUS AS99127F Rev. 1 Hardware Monitor", + .internal_name = "as99137f", + .flags = DEVICE_ISA, + .local = LM78_I2C | LM78_AS99127F_REV1, + .init = lm78_init, + .close = lm78_close, + .reset = lm78_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -/* Rev. 2 changes the vendor ID back to Winbond's and brings some other changes. */ +/* Rev. 2 is manufactured by Winbond and differs only in GPI registers. */ const device_t as99127f_rev2_device = { - "ASUS AS99127F Rev. 2 Hardware Monitor", - DEVICE_AT, - LM78_SMBUS | LM78_AS99127F_REV2, - lm78_init, lm78_close, NULL, - NULL, NULL, NULL, - NULL + .name = "ASUS AS99127F Rev. 2 Hardware Monitor", + .internal_name = "as99127f_rev2", + .flags = DEVICE_ISA, + .local = LM78_I2C | LM78_AS99127F_REV2, + .init = lm78_init, + .close = lm78_close, + .reset = lm78_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +/* Winbond W83782D on ISA and SMBus. */ +const device_t w83782d_device = { + .name = "Winbond W83782D Hardware Monitor", + .internal_name = "w83783d", + .flags = DEVICE_ISA, + .local = 0x290 | LM78_I2C | LM78_W83782D, + .init = lm78_init, + .close = lm78_close, + .reset = lm78_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/hwm_vt82c686.c b/src/device/hwm_vt82c686.c new file mode 100644 index 000000000..83e67b66e --- /dev/null +++ b/src/device/hwm_vt82c686.c @@ -0,0 +1,219 @@ +/* + * 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 the VIA VT82C686A/B integrated hardware monitor. + * + * + * + * Author: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/hwm.h> + + +#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a))) +/* Formulas and factors derived from Linux's via686a.c driver. */ +#define VT82C686_RPM_TO_REG(r, d) ((r) ? CLAMP(1350000 / (r * d), 1, 255) : 0) +#define VT82C686_TEMP_TO_REG(t) (-1.160370e-10*(t*t*t*t*t*t) + 3.193693e-08*(t*t*t*t*t) - 1.464447e-06*(t*t*t*t) - 2.525453e-04*(t*t*t) + 1.424593e-02*(t*t) + 2.148941e+00*t + 7.275808e+01) +#define VT82C686_VOLTAGE_TO_REG(v, f) CLAMP((((v) * (2.628 / (f))) - 120.5) / 25, 0, 255) + + +typedef struct { + hwm_values_t *values; + + uint8_t enable; + uint16_t io_base; + uint8_t regs[128]; +} vt82c686_t; + + +static double voltage_factors[5] = {1.25, 1.25, 1.67, 2.6, 6.3}; + + +static void vt82c686_reset(vt82c686_t *dev, uint8_t initialization); + + +static uint8_t +vt82c686_read(uint16_t addr, void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + uint8_t ret; + + addr -= dev->io_base; + + switch (addr) { + case 0x00 ... 0x0f: case 0x50 ... 0x7f: /* undefined registers */ + /* Real 686B returns the contents of 0x40. */ + ret = dev->regs[0x40]; + break; + + case 0x1f: case 0x20: case 0x21: /* temperatures */ + ret = VT82C686_TEMP_TO_REG(dev->values->temperatures[(addr == 0x1f) ? 2 : (addr & 1)]); + break; + + case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: /* voltages */ + ret = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[addr - 0x22], voltage_factors[addr - 0x22]); + break; + + case 0x29: case 0x2a: /* fan speeds */ + ret = VT82C686_RPM_TO_REG(dev->values->fans[addr - 0x29], 1 << ((dev->regs[0x47] >> ((addr == 0x29) ? 4 : 6)) & 0x3)); + break; + + default: /* other registers */ + ret = dev->regs[addr]; + break; + } + + return ret; +} + + +static void +vt82c686_write(uint16_t port, uint8_t val, void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + uint8_t reg = port & 0x7f; + + switch (reg) { + case 0x00 ... 0x0f: + case 0x3f: case 0x41: case 0x42: case 0x4a: + case 0x4c ... 0x7f: + /* Read-only registers. */ + return; + + case 0x40: + /* Reset if requested. */ + if (val & 0x80) { + vt82c686_reset(dev, 1); + return; + } + break; + + case 0x48: + val &= 0x7f; + break; + } + + dev->regs[reg] = val; +} + + +/* Writes to hardware monitor-related configuration space registers + of the VT82C686 power management function are sent here by via_pipc.c */ +void +vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + + if (dev->io_base) + io_removehandler(dev->io_base, 128, + vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev); + + switch (addr) { + case 0x70: + dev->io_base &= 0xff00; + dev->io_base |= val & 0x80; + break; + + case 0x71: + dev->io_base &= 0x00ff; + dev->io_base |= val << 8; + break; + + case 0x74: + dev->enable = val & 0x01; + break; + } + + if (dev->enable && dev->io_base) + io_sethandler(dev->io_base, 128, + vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev); +} + + +static void +vt82c686_reset(vt82c686_t *dev, uint8_t initialization) +{ + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->regs[0x17] = 0x80; + dev->regs[0x3f] = 0xa2; + dev->regs[0x40] = 0x08; + dev->regs[0x47] = 0x50; + dev->regs[0x4b] = 0x15; + + if (!initialization) + vt82c686_hwm_write(0x74, 0x00, dev); +} + + +static void +vt82c686_close(void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + + free(dev); +} + + +static void * +vt82c686_init(const device_t *info) +{ + vt82c686_t *dev = (vt82c686_t *) malloc(sizeof(vt82c686_t)); + memset(dev, 0, sizeof(vt82c686_t)); + + /* Set default values. Since this hardware monitor has a complex voltage factor system, + the values struct contains voltage values *before* applying their respective factors. */ + hwm_values_t defaults = { + { /* fan speeds */ + 3000, /* usually CPU */ + 3000 /* usually Chassis */ + }, { /* temperatures */ + 30, /* usually CPU */ + 30, /* usually System */ + 30 + }, { /* voltages */ + hwm_get_vcore(), /* Vcore */ + 2500, /* +2.5V */ + 3300, /* +3.3V */ + 5000, /* +5V */ + 12000 /* +12V */ + } + }; + hwm_values = defaults; + dev->values = &hwm_values; + + vt82c686_reset(dev, 0); + + return dev; +} + +const device_t via_vt82c686_hwm_device = { + .name = "VIA VT82C686 Integrated Hardware Monitor", + .internal_name = "via_vt82c686_hwm", + .flags = DEVICE_ISA, + .local = 0, + .init = vt82c686_init, + .close = vt82c686_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/i2c.c b/src/device/i2c.c new file mode 100644 index 000000000..ac0e5ee83 --- /dev/null +++ b/src/device/i2c.c @@ -0,0 +1,315 @@ +/* + * 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 I2C bus and its operations. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/i2c.h> + + +#define NADDRS 128 /* I2C supports 128 addresses */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + + +typedef struct _i2c_ { + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv); + uint8_t (*read)(void *bus, uint8_t addr, void *priv); + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv); + void (*stop)(void *bus, uint8_t addr, void *priv); + + void *priv; + + struct _i2c_ *prev, *next; +} i2c_t; + +typedef struct { + char *name; + i2c_t *devices[NADDRS], *last[NADDRS]; +} i2c_bus_t; + + +void *i2c_smbus; + + +#ifdef ENABLE_I2C_LOG +int i2c_do_log = ENABLE_I2C_LOG; + + +static void +i2c_log(const char *fmt, ...) +{ + va_list ap; + + if (i2c_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i2c_log(fmt, ...) +#endif + + +void * +i2c_addbus(char *name) +{ + i2c_bus_t *bus = (i2c_bus_t *) malloc(sizeof(i2c_bus_t)); + memset(bus, 0, sizeof(i2c_bus_t)); + + bus->name = name; + + return bus; +} + + +void +i2c_removebus(void *bus_handle) +{ + int c; + i2c_t *p, *q; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle) + return; + + for (c = 0; c < NADDRS; c++) { + p = bus->devices[c]; + if (!p) + continue; + while(p) { + q = p->next; + free(p); + p = q; + } + } + + free(bus); +} + + +char * +i2c_getbusname(void *bus_handle) +{ + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle) + return(NULL); + + return(bus->name); +} + + +void +i2c_sethandler(void *bus_handle, uint8_t base, int size, + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), + void *priv) +{ + int c; + i2c_t *p, *q = NULL; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle || ((base + size) > NADDRS)) + return; + + for (c = 0; c < size; c++) { + p = bus->last[base + c]; + q = (i2c_t *) malloc(sizeof(i2c_t)); + memset(q, 0, sizeof(i2c_t)); + if (p) { + p->next = q; + q->prev = p; + } else { + bus->devices[base + c] = q; + q->prev = NULL; + } + + q->start = start; + q->read = read; + q->write = write; + q->stop = stop; + + q->priv = priv; + q->next = NULL; + + bus->last[base + c] = q; + } +} + + +void +i2c_removehandler(void *bus_handle, uint8_t base, int size, + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), + void *priv) +{ + int c; + i2c_t *p, *q; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle || ((base + size) > NADDRS)) + return; + + for (c = 0; c < size; c++) { + p = bus->devices[base + c]; + if (!p) + continue; + while(p) { + q = p->next; + if ((p->start == start) && (p->read == read) && (p->write == write) && (p->stop == stop) && (p->priv == priv)) { + if (p->prev) + p->prev->next = p->next; + else + bus->devices[base + c] = p->next; + if (p->next) + p->next->prev = p->prev; + else + bus->last[base + c] = p->prev; + free(p); + p = NULL; + break; + } + p = q; + } + } +} + + +void +i2c_handler(int set, void *bus_handle, uint8_t base, int size, + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), + void *priv) +{ + if (set) + i2c_sethandler(bus_handle, base, size, start, read, write, stop, priv); + else + i2c_removehandler(bus_handle, base, size, start, read, write, stop, priv); +} + + +uint8_t +i2c_start(void *bus_handle, uint8_t addr, uint8_t read) +{ + uint8_t ret = 0; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->start) { + ret |= p->start(bus_handle, addr, read, p->priv); + } + p = p->next; + } + } + + i2c_log("I2C %s: start(%02X) = %d\n", bus->name, addr, ret); + + return(ret); +} + + +uint8_t +i2c_read(void *bus_handle, uint8_t addr) +{ + uint8_t ret = 0; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read) { + ret = p->read(bus_handle, addr, p->priv); + break; + } + p = p->next; + } + } + + i2c_log("I2C %s: read(%02X) = %02X\n", bus->name, addr, ret); + + return(ret); +} + + +uint8_t +i2c_write(void *bus_handle, uint8_t addr, uint8_t data) +{ + uint8_t ret = 0; + i2c_t *p; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->write) { + ret |= p->write(bus_handle, addr, data, p->priv); + } + p = p->next; + } + } + + i2c_log("I2C %s: write(%02X, %02X) = %d\n", bus->name, addr, data, ret); + + return(ret); +} + + +void +i2c_stop(void *bus_handle, uint8_t addr) +{ + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + + if (!bus) + return; + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->stop) { + p->stop(bus_handle, addr, p->priv); + } + p = p->next; + } + } + + i2c_log("I2C %s: stop(%02X)\n", bus->name, addr); +} diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c new file mode 100644 index 000000000..e3902baaa --- /dev/null +++ b/src/device/i2c_gpio.c @@ -0,0 +1,190 @@ +/* + * 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 a GPIO-based I2C host controller. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/i2c.h> + + +typedef struct { + char *bus_name; + void *i2c; + uint8_t prev_scl, prev_sda, slave_sda, started, + slave_addr_received, slave_addr, slave_read, pos, byte; +} i2c_gpio_t; + + +#ifdef ENABLE_I2C_GPIO_LOG +int i2c_gpio_do_log = ENABLE_I2C_GPIO_LOG; + + +static void +i2c_gpio_log(int level, const char *fmt, ...) +{ + va_list ap; + + if (i2c_gpio_do_log >= level) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i2c_gpio_log(fmt, ...) +#endif + + +void * +i2c_gpio_init(char *bus_name) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t)); + memset(dev, 0, sizeof(i2c_gpio_t)); + + i2c_gpio_log(1, "I2C GPIO %s: init()\n", bus_name); + + dev->bus_name = bus_name; + dev->i2c = i2c_addbus(dev->bus_name); + dev->prev_scl = dev->prev_sda = dev->slave_sda = 1; + dev->slave_addr = 0xff; + + return dev; +} + + +void +i2c_gpio_close(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + + i2c_gpio_log(1, "I2C GPIO %s: close()\n", dev->bus_name); + + i2c_removebus(dev->i2c); + + free(dev); +} + + +void +i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + + i2c_gpio_log(3, "I2C GPIO %s: write scl=%d->%d sda=%d->%d read=%d\n", dev->bus_name, dev->prev_scl, scl, dev->prev_sda, sda, dev->slave_read); + + if (dev->prev_scl && scl) { + if (dev->prev_sda && !sda) { + i2c_gpio_log(2, "I2C GPIO %s: Start condition\n", dev->bus_name); + dev->started = 1; + dev->pos = 0; + dev->slave_addr = 0xff; + dev->slave_read = 2; /* start with address transfer */ + dev->slave_sda = 1; + } else if (!dev->prev_sda && sda) { + i2c_gpio_log(2, "I2C GPIO %s: Stop condition\n", dev->bus_name); + dev->started = 0; + if (dev->slave_addr != 0xff) + i2c_stop(dev->i2c, dev->slave_addr); + dev->slave_addr = 0xff; + dev->slave_sda = 1; + } + } else if (!dev->prev_scl && scl && dev->started) { + if (dev->pos++ < 8) { + if (dev->slave_read == 1) { + dev->slave_sda = !!(dev->byte & 0x80); + dev->byte <<= 1; + } else { + dev->byte <<= 1; + dev->byte |= sda; + } + + i2c_gpio_log(2, "I2C GPIO %s: Bit %d = %d\n", dev->bus_name, 8 - dev->pos, (dev->slave_read == 1) ? dev->slave_sda : sda); + } + + if (dev->pos == 8) { + i2c_gpio_log(2, "I2C GPIO %s: Byte = %02X\n", dev->bus_name, dev->byte); + + /* (N)ACKing here instead of at the 9th bit may sound odd, but is required by the Matrox Mystique Windows drivers. */ + switch (dev->slave_read) { + case 2: /* address transfer */ + dev->slave_addr = dev->byte >> 1; + dev->slave_read = dev->byte & 1; + + /* slave ACKs? */ + dev->slave_sda = !i2c_start(dev->i2c, dev->slave_addr, dev->slave_read); + i2c_gpio_log(2, "I2C GPIO %s: Slave %02X %s %sACK\n", dev->bus_name, dev->slave_addr, dev->slave_read ? "read" : "write", dev->slave_sda ? "N" : ""); + + if (!dev->slave_sda && dev->slave_read) /* read first byte on an ACKed read transfer */ + dev->byte = i2c_read(dev->i2c, dev->slave_addr); + + dev->slave_read |= 0x80; /* slave_read was overwritten; stop the master ACK read logic from running at the 9th bit if we're reading */ + break; + + case 0: /* write transfer */ + dev->slave_sda = !i2c_write(dev->i2c, dev->slave_addr, dev->byte); + i2c_gpio_log(2, "I2C GPIO %s: Write %02X %sACK\n", dev->bus_name, dev->byte, dev->slave_sda ? "N" : ""); + break; + } + } else if (dev->pos == 9) { + switch (dev->slave_read) { + case 1: /* read transfer (unless we're in an address transfer) */ + if (!sda) /* master ACKs? */ + dev->byte = i2c_read(dev->i2c, dev->slave_addr); + i2c_gpio_log(2, "I2C GPIO %s: Read %02X %sACK\n", dev->bus_name, dev->byte, sda ? "N" : ""); + break; + + default: + dev->slave_read &= 1; /* if we're in an address transfer, clear it */ + } + dev->pos = 0; /* start over */ + } + } else if (dev->prev_scl && !scl && (dev->pos != 8)) { /* keep (N)ACK computed at the 8th bit when transitioning to the 9th bit */ + dev->slave_sda = 1; + } + + dev->prev_scl = scl; + dev->prev_sda = sda; +} + + +uint8_t +i2c_gpio_get_scl(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + return dev->prev_scl; +} + + +uint8_t +i2c_gpio_get_sda(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + i2c_gpio_log(3, "I2C GPIO %s: read myscl=%d mysda=%d slavesda=%d\n", dev->bus_name, dev->prev_scl, dev->prev_sda, dev->slave_sda); + return dev->prev_sda && dev->slave_sda; +} + + +void * +i2c_gpio_get_bus(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + return dev->i2c; +} diff --git a/src/device/ibm_5161.c b/src/device/ibm_5161.c index 3e7d4845f..3da5a2797 100644 --- a/src/device/ibm_5161.c +++ b/src/device/ibm_5161.c @@ -54,15 +54,29 @@ ibm_5161_in(uint16_t port, void *priv) ret = dev->regs[port & 0x0007]; switch (port) { - case 0x211: - case 0x215: + case 0x210: /* Write to latch expansion bus data (ED0-ED7) */ + /* Read to verify expansion bus data (ED0-ED7) */ + break; + case 0x214: /* Write to latch data bus bits (DO - 07) */ + /* Read data bus bits (DO - D7) */ + break; + case 0x211: /* Read high-order address bits (A8 - A 15) */ + case 0x215: /* Read high-order address bits (A8 - A 15) */ ret = (get_last_addr() >> 8) & 0xff; break; - case 0x212: - case 0x216: + case 0x212: /* Read low-order address bits (A0 - A7) */ + case 0x216: /* Read low-order address bits (A0 - A7) */ ret = get_last_addr() & 0xff; break; - case 0x213: + case 0x213: /* Write 00 to disable expansion unit */ + /* Write 01 to enable expansion unit */ + /* Read status of expansion unit + 00 = enable/disable + 01 = wait-state request flag + 02-03 = not used + 04-07 = switch position + 1 = Off + 0 =On */ ret = dev->regs[3] & 0x01; break; } @@ -97,17 +111,16 @@ ibm_5161_init(const device_t *info) return dev; } - -const device_t ibm_5161_device = -{ - "IBM Expansion Unit (5161)", - 0, - 0, - ibm_5161_init, - ibm_5161_close, - NULL, - NULL, - NULL, - NULL, - NULL +const device_t ibm_5161_device = { + .name = "IBM Expansion Unit (5161)", + .internal_name = "ibm_5161", + .flags = DEVICE_ISA, + .local = 0, + .init = ibm_5161_init, + .close = ibm_5161_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/isamem.c b/src/device/isamem.c index b40dee6d1..4fd3e6ab2 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -68,11 +68,13 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/machine.h> #include <86box/io.h> @@ -82,6 +84,21 @@ #include <86box/plat.h> #include <86box/isamem.h> +#include "cpu.h" + +#define ISAMEM_IBMXT_CARD 0 +#define ISAMEM_GENXT_CARD 1 +#define ISAMEM_RAMCARD_CARD 2 +#define ISAMEM_SYSTEMCARD_CARD 3 +#define ISAMEM_IBMAT_CARD 4 +#define ISAMEM_GENAT_CARD 5 +#define ISAMEM_P5PAK_CARD 6 +#define ISAMEM_A6PAK_CARD 7 +#define ISAMEM_EMS5150_CARD 8 +#define ISAMEM_EV159_CARD 10 +#define ISAMEM_RAMPAGEXT_CARD 11 +#define ISAMEM_ABOVEBOARD_CARD 12 +#define ISAMEM_BRAT_CARD 13 #define ISAMEM_DEBUG 0 @@ -93,6 +110,9 @@ #define EMS_PGSIZE (16 << 10) /* one page is this big */ #define EMS_MAXPAGE 4 /* number of viewport pages */ +#define EXTRAM_CONVENTIONAL 0 +#define EXTRAM_HIGH 1 +#define EXTRAM_XMS 2 typedef struct { int8_t enabled; /* 1=ENABLED */ @@ -103,6 +123,11 @@ typedef struct { mem_mapping_t mapping; /* mapping entry for page */ } emsreg_t; +typedef struct { + uint32_t base; + uint8_t *ptr; +} ext_ram_t; + typedef struct { const char *name; uint8_t board : 6, /* board type */ @@ -125,6 +150,8 @@ typedef struct { uint8_t *ram; /* allocated RAM buffer */ + ext_ram_t ext_ram[3]; /* structures for the mappings */ + mem_mapping_t low_mapping; /* mapping for low mem */ mem_mapping_t high_mapping; /* mapping for high mem */ @@ -151,16 +178,17 @@ isamem_log(const char *fmt, ...) #endif +/* Why this convoluted setup with the mem_dev stuff when it's much simpler + to just pass the exec pointer as p as well, and then just use that. */ /* Read one byte from onboard RAM. */ static uint8_t ram_readb(uint32_t addr, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; + ext_ram_t *dev = (ext_ram_t *)priv; uint8_t ret = 0xff; /* Grab the data. */ - ret = *(uint8_t *)(dev->ram + (addr - map->base)); + ret = *(uint8_t *)(dev->ptr + (addr - dev->base)); return(ret); } @@ -170,12 +198,11 @@ ram_readb(uint32_t addr, void *priv) static uint16_t ram_readw(uint32_t addr, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; + ext_ram_t *dev = (ext_ram_t *)priv; uint16_t ret = 0xffff; /* Grab the data. */ - ret = *(uint16_t *)(dev->ram + (addr - map->base)); + ret = *(uint16_t *)(dev->ptr + (addr - dev->base)); return(ret); } @@ -185,11 +212,10 @@ ram_readw(uint32_t addr, void *priv) static void ram_writeb(uint32_t addr, uint8_t val, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; + ext_ram_t *dev = (ext_ram_t *)priv; /* Write the data. */ - *(uint8_t *)(dev->ram + (addr - map->base)) = val; + *(uint8_t *)(dev->ptr + (addr - dev->base)) = val; } @@ -197,11 +223,10 @@ ram_writeb(uint32_t addr, uint8_t val, void *priv) static void ram_writew(uint32_t addr, uint16_t val, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; + ext_ram_t *dev = (ext_ram_t *)priv; /* Write the data. */ - *(uint16_t *)(dev->ram + (addr - map->base)) = val; + *(uint16_t *)(dev->ptr + (addr - dev->base)) = val; } @@ -209,18 +234,13 @@ ram_writew(uint32_t addr, uint16_t val, void *priv) static uint8_t ems_readb(uint32_t addr, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; + memdev_t *dev = (memdev_t *)priv; uint8_t ret = 0xff; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); /* Grab the data. */ - ret = *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)); + ret = *(uint8_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)); #if ISAMEM_DEBUG - if ((addr % 4096)==0) isamem_log("EMS readb(%06x) = %02x\n",addr-map->base,ret); + if ((addr % 4096)==0) isamem_log("EMS readb(%06x) = %02x\n",addr-dev&0x3fff,ret); #endif return(ret); @@ -231,18 +251,13 @@ ems_readb(uint32_t addr, void *priv) static uint16_t ems_readw(uint32_t addr, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; + memdev_t *dev = (memdev_t *)priv; uint16_t ret = 0xffff; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); /* Grab the data. */ - ret = *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)); + ret = *(uint16_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)); #if ISAMEM_DEBUG - if ((addr % 4096)==0) isamem_log("EMS readw(%06x) = %04x\n",addr-map->base,ret); + if ((addr % 4096)==0) isamem_log("EMS readw(%06x) = %04x\n",addr-dev&0x3fff,ret); #endif return(ret); @@ -253,18 +268,13 @@ ems_readw(uint32_t addr, void *priv) static void ems_writeb(uint32_t addr, uint8_t val, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); + memdev_t *dev = (memdev_t *)priv; /* Write the data. */ #if ISAMEM_DEBUG - if ((addr % 4096)==0) isamem_log("EMS writeb(%06x, %02x)\n",addr-map->base,val); + if ((addr % 4096)==0) isamem_log("EMS writeb(%06x, %02x)\n",addr-dev&0x3fff,val); #endif - *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; + *(uint8_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)) = val; } @@ -272,18 +282,13 @@ ems_writeb(uint32_t addr, uint8_t val, void *priv) static void ems_writew(uint32_t addr, uint16_t val, void *priv) { - mem_mapping_t *map = (mem_mapping_t *)priv; - memdev_t *dev = (memdev_t *)map->dev; - int vpage; - - /* Get the viewport page number. */ - vpage = ((addr & 0xffff) / EMS_PGSIZE); + memdev_t *dev = (memdev_t *)priv; /* Write the data. */ #if ISAMEM_DEBUG - if ((addr % 4096)==0) isamem_log("EMS writew(%06x, %04x)\n",addr-map->base,val); + if ((addr % 4096)==0) isamem_log("EMS writew(%06x, %04x)\n",addr&0x3fff,val); #endif - *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; + *(uint16_t *)(dev->ems[((addr & 0xffff) >> 14)].addr + (addr & 0x3fff)) = val; } @@ -411,28 +416,33 @@ isamem_init(const device_t *info) /* Do per-board initialization. */ tot = 0; switch(dev->board) { - case 0: /* IBM PC/XT Memory Expansion Card */ - case 2: /* Paradise Systems 5-PAK */ + case ISAMEM_IBMXT_CARD: /* IBM PC/XT Memory Expansion Card */ + case ISAMEM_GENXT_CARD: /* Generic PC/XT Memory Expansion Card */ + case ISAMEM_RAMCARD_CARD: /* Microsoft RAMCard for IBM PC */ + case ISAMEM_SYSTEMCARD_CARD: /* Microsoft SystemCard */ + case ISAMEM_P5PAK_CARD: /* Paradise Systems 5-PAK */ + case ISAMEM_A6PAK_CARD: /* AST SixPakPlus */ dev->total_size = device_get_config_int("size"); dev->start_addr = device_get_config_int("start"); tot = dev->total_size; break; - case 1: /* IBM PC/AT Memory Expansion Card */ + case ISAMEM_IBMAT_CARD: /* IBM PC/AT Memory Expansion Card */ + case ISAMEM_GENAT_CARD: /* Generic PC/AT Memory Expansion Card */ dev->total_size = device_get_config_int("size"); dev->start_addr = device_get_config_int("start"); tot = dev->total_size; dev->flags |= FLAG_WIDE; break; - case 3: /* Micro Mainframe EMS-5150(T) */ + case ISAMEM_EMS5150_CARD: /* Micro Mainframe EMS-5150(T) */ dev->base_addr = device_get_config_hex16("base"); dev->total_size = device_get_config_int("size"); dev->frame_addr = 0xD0000; dev->flags |= (FLAG_EMS | FLAG_CONFIG); break; - case 10: /* Everex EV-159 RAM 3000 */ + case ISAMEM_EV159_CARD: /* Everex EV-159 RAM 3000 */ dev->base_addr = device_get_config_hex16("base"); dev->total_size = device_get_config_int("size"); dev->start_addr = device_get_config_int("start"); @@ -446,7 +456,9 @@ isamem_init(const device_t *info) dev->frame_addr = 0xE0000; break; - case 11: + case ISAMEM_RAMPAGEXT_CARD: /* AST RAMpage/XT */ + case ISAMEM_ABOVEBOARD_CARD: /* Intel AboveBoard */ + case ISAMEM_BRAT_CARD: /* BocaRAM/AT */ dev->base_addr = device_get_config_hex16("base"); dev->total_size = device_get_config_int("size"); dev->start_addr = device_get_config_int("start"); @@ -470,7 +482,7 @@ dev->frame_addr = 0xE0000; isamem_log(")\n"); /* Force (back to) 8-bit bus if needed. */ - if ((!AT) && (dev->flags & FLAG_WIDE)) { + if ((!is286) && (dev->flags & FLAG_WIDE)) { isamem_log("ISAMEM: not AT+ system, forcing 8-bit mode!\n"); dev->flags &= ~FLAG_WIDE; } @@ -509,16 +521,18 @@ dev->frame_addr = 0xE0000; t = tot; isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + dev->ext_ram[EXTRAM_CONVENTIONAL].ptr = ptr; + dev->ext_ram[EXTRAM_CONVENTIONAL].base = addr; + /* Create, initialize and enable the low-memory mapping. */ mem_mapping_add(&dev->low_mapping, addr, t, ram_readb, (dev->flags&FLAG_WIDE) ? ram_readw : NULL, NULL, - ram_writeb, + ram_writeb, (dev->flags&FLAG_WIDE) ? ram_writew : NULL, NULL, - ptr, MEM_MAPPING_EXTERNAL, &dev->low_mapping); - mem_mapping_set_dev(&dev->low_mapping, dev); + ptr, MEM_MAPPING_EXTERNAL, &dev->ext_ram[EXTRAM_CONVENTIONAL]); /* Tell the memory system this is external RAM. */ mem_set_mem_state(addr, t, @@ -542,16 +556,16 @@ dev->frame_addr = 0xE0000; isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + dev->ext_ram[EXTRAM_HIGH].ptr = ptr; + dev->ext_ram[EXTRAM_HIGH].base = addr + tot; + /* Update and enable the remap. */ - mem_mapping_del(&ram_remapped_mapping); - mem_mapping_add(&ram_remapped_mapping, + mem_mapping_set(&ram_remapped_mapping, addr + tot, t, ram_readb, ram_readw, NULL, ram_writeb, ram_writew, NULL, ptr, MEM_MAPPING_EXTERNAL, - &ram_remapped_mapping); - mem_mapping_set_exec(&ram_remapped_mapping, ptr); - mem_mapping_set_dev(&ram_remapped_mapping, dev); + &dev->ext_ram[EXTRAM_HIGH]); mem_mapping_disable(&ram_remapped_mapping); /* Tell the memory system this is external RAM. */ @@ -572,16 +586,18 @@ dev->frame_addr = 0xE0000; * real mode (so, not by DOS, for example) but it can be used in * protected mode. */ - if (AT && addr > 0 && tot > 0) { + if (is286 && addr > 0 && tot > 0) { t = tot; isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + dev->ext_ram[EXTRAM_XMS].ptr = ptr; + dev->ext_ram[EXTRAM_XMS].base = addr; + /* Create, initialize and enable the high-memory mapping. */ mem_mapping_add(&dev->high_mapping, addr, t, ram_readb, ram_readw, NULL, ram_writeb, ram_writew, NULL, - ptr, MEM_MAPPING_EXTERNAL, &dev->high_mapping); - mem_mapping_set_dev(&dev->high_mapping, dev); + ptr, MEM_MAPPING_EXTERNAL, &dev->ext_ram[EXTRAM_XMS]); /* Tell the memory system this is external RAM. */ mem_set_mem_state(addr, t, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); @@ -592,6 +608,8 @@ dev->frame_addr = 0xE0000; addr += t; } + isa_mem_size += dev->total_size - (k >> 10); + /* If EMS is enabled, use the remainder for EMS. */ if (dev->flags & FLAG_EMS) { /* EMS 3.2 cannot have more than 2048KB per board. */ @@ -621,12 +639,11 @@ dev->frame_addr = 0xE0000; ems_readb, (dev->flags&FLAG_WIDE) ? ems_readw : NULL, NULL, - ems_writeb, + ems_writeb, (dev->flags&FLAG_WIDE) ? ems_writew : NULL, NULL, ptr, MEM_MAPPING_EXTERNAL, - &dev->ems[i].mapping); - mem_mapping_set_dev(&dev->ems[i].mapping, dev); + dev); /* For now, disable it. */ mem_mapping_disable(&dev->ems[i].mapping); @@ -663,376 +680,908 @@ isamem_close(void *priv) free(dev); } - -static const device_config_t ibmxt_config[] = -{ - { - "size", "Memory Size", CONFIG_SPINNER, "", 128, - { { 0 } }, - { { 0 } }, - { 0, 512, 16 } - }, - { - "start", "Start Address", CONFIG_SPINNER, "", 256, - { { 0 } }, - { { 0 } }, - { 0, 640-64, 64 } - }, - { - "", "", -1 - } +static const device_config_t ibmxt_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 128, + .file_filter = "", + .spinner = { + .min = 0, + .max = 512, + .step = 16 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 256, + .file_filter = "", + .spinner = { + .min = 0, + .max = 576, + .step = 64 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; static const device_t ibmxt_device = { - "IBM PC/XT Memory Expansion", - DEVICE_ISA, - 0, - isamem_init, isamem_close, NULL, - NULL, NULL, NULL, - ibmxt_config + .name = "IBM PC/XT Memory Expansion", + .internal_name = "ibmxt", + .flags = DEVICE_ISA, + .local = ISAMEM_IBMXT_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ibmxt_config }; +static const device_config_t genericxt_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 16, + .file_filter = "", + .spinner = { + .min = 0, + .max = 640, + .step = 16 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { + .min = 0, + .max = 624, + .step = 16 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; -static const device_config_t ibmat_config[] = -{ - { - "size", "Memory Size", CONFIG_SPINNER, "", 512, - { { 0 } }, - { { 0 } }, - { 0, 4096, 512 } - }, - { - "start", "Start Address", CONFIG_SPINNER, "", 512, - { { 0 } }, - { { 0 } }, - { 0, 16128, 128 } - }, - { - "", "", -1 - } +static const device_t genericxt_device = { + .name = "Generic PC/XT Memory Expansion", + .internal_name = "genericxt", + .flags = DEVICE_ISA, + .local = ISAMEM_GENXT_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = genericxt_config +}; + +static const device_config_t msramcard_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 64, + .file_filter = "", + .spinner = { + .min = 0, + .max = 256, + .step = 64 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { + .min = 0, + .max = 624, + .step = 64 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_t msramcard_device = { + .name = "Microsoft RAMCard for IBM PC", + .internal_name = "msramcard", + .flags = DEVICE_ISA, + .local = ISAMEM_RAMCARD_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = msramcard_config +}; + +static const device_config_t mssystemcard_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 64, + .file_filter = "", + .spinner = { + .min = 0, + .max = 256, + .step = 64 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { + .min = 0, + .max = 624, + .step = 64 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_t mssystemcard_device = { + .name = "Microsoft SystemCard", + .internal_name = "mssystemcard", + .flags = DEVICE_ISA, + .local = ISAMEM_SYSTEMCARD_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mssystemcard_config +}; + +static const device_config_t ibmat_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { + .min = 0, + .max = 12288, + .step = 512 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { + .min = 0, + .max = 15872, + .step = 512 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; static const device_t ibmat_device = { - "IBM PC/AT Memory Expansion", - DEVICE_ISA, - 1, - isamem_init, isamem_close, NULL, - NULL, NULL, NULL, - ibmat_config + .name = "IBM PC/AT Memory Expansion", + .internal_name = "ibmat", + .flags = DEVICE_ISA, + .local = ISAMEM_IBMAT_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ibmat_config }; +static const device_config_t genericat_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { + .min = 0, + .max = 16384, + .step = 512 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { + .min = 0, + .max = 15872, + .step = 128 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; -static const device_config_t p5pak_config[] = -{ - { - "size", "Memory Size", CONFIG_SPINNER, "", 128, - { { 0 } }, - { { 0 } }, - { 0, 384, 64 } - }, - { - "start", "Start Address", CONFIG_SPINNER, "", 512, - { { 0 } }, - { { 0 } }, - { 64, 576, 64 } - }, - { - "", "", -1 - } +static const device_t genericat_device = { + .name = "Generic PC/AT Memory Expansion", + .internal_name = "genericat", + .flags = DEVICE_ISA, + .local = ISAMEM_GENAT_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = genericat_config +}; + +static const device_config_t p5pak_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 128, + .file_filter = "", + .spinner = { + .min = 0, + .max = 384, + .step = 64 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { + .min = 64, + .max = 576, + .step = 64 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; static const device_t p5pak_device = { - "Paradise Systems 5-PAK", - DEVICE_ISA, - 2, - isamem_init, isamem_close, NULL, - NULL, NULL, NULL, - p5pak_config + .name = "Paradise Systems 5-PAK", + .internal_name = "p5pak", + .flags = DEVICE_ISA, + .local = ISAMEM_P5PAK_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = p5pak_config }; -static const device_config_t ems5150_config[] = -{ - { - "size", "Memory Size", CONFIG_SPINNER, "", 256, - { { 0 } }, - { { 0 } }, - { 0, 2048, 64 } - }, - { - "base", "Address", CONFIG_HEX16, "", 0, - { - { - "Disabled", 0 - }, - { - "Board 1", 0x0208 - }, - { - "Board 2", 0x020a - }, - { - "Board 3", 0x020c - }, - { - "Board 4", 0x020e - }, - { - "" - } - }, - }, - { - "", "", -1 - } +static const device_config_t a6pak_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 64, + .file_filter = "", + .spinner = { + .min = 0, + .max = 576, + .step = 64 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 256, + .file_filter = "", + .spinner = { + .min = 64, + .max = 512, + .step = 64 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_t a6pak_device = { + .name = "AST SixPakPlus", + .internal_name = "a6pak", + .flags = DEVICE_ISA, + .local = ISAMEM_A6PAK_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = a6pak_config +}; + +static const device_config_t ems5150_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 256, + .file_filter = "", + .spinner = { + .min = 0, + .max = 2048, + .step = 64 + }, + .selection = { { 0 } } + }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0, + .file_filter = "", + .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 = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; static const device_t ems5150_device = { - "Micro Mainframe EMS-5150(T)", - DEVICE_ISA, - 3, - isamem_init, isamem_close, NULL, - NULL, NULL, NULL, - ems5150_config + .name = "Micro Mainframe EMS-5150(T)", + .internal_name = "ems5150", + .flags = DEVICE_ISA, + .local = ISAMEM_EMS5150_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ems5150_config }; - -static const device_config_t ev159_config[] = -{ - { - "size", "Memory Size", CONFIG_SPINNER, "", 512, - { { 0 } }, - { { 0 } }, - { 0, 3072, 512 } - }, - { - "start", "Start Address", CONFIG_SPINNER, "", 0, - { { 0 } }, - { { 0 } }, - { 0, 16128, 128 } - }, - { - "length", "Contiguous Size", CONFIG_SPINNER, "", 0, - { { 0 } }, - { { 0 } }, - { 0, 16384, 128 } - }, - { - "width", "I/O Width", CONFIG_SELECTION, "", 0, - { - { - "8-bit", 0 - }, - { - "16-bit", 1 - }, - { - "" - } - }, - }, - { - "speed", "Transfer Speed", CONFIG_SELECTION, "", 0, - { - { - "Standard (150ns)", 0 - }, - { - "High-Speed (120ns)", 1 - }, - { - "" - } - } - }, - { - "ems", "EMS mode", CONFIG_SELECTION, "", 0, - { - { - "Disabled", 0 - }, - { - "Enabled", 1 - }, - { - "" - } - }, - }, - { - "base", "Address", CONFIG_HEX16, "", 0x0258, - { - { - "208H", 0x0208 - }, - { - "218H", 0x0218 - }, - { - "258H", 0x0258 - }, - { - "268H", 0x0268 - }, - { - "2A8H", 0x02A8 - }, - { - "2B8H", 0x02B8 - }, - { - "2E8H", 0x02E8 - }, - { - "" - } - }, - }, - { - "", "", -1 - } +static const device_config_t ev159_config[] = { +// clang-format off + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { + .min = 0, + .max = 3072, + .step = 512 + }, + .selection = { { 0 } } + }, + { + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { + .min = 0, + .max = 16128, + .step = 128 + }, + .selection = { { 0 } } + }, + { + .name = "length", + .description = "Contiguous Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { + .min = 0, + .max = 16384, + .step = 128 + }, + .selection = { { 0 } } + }, + { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8-bit", .value = 0 }, + { .description = "16-bit", .value = 1 }, + { .description = "" } + }, + }, + { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Standard (150ns)", .value = 0 }, + { .description = "High-Speed (120ns)", .value = 1 }, + { .description = "" } + } + }, + { + .name = "ems", + .description = "EMS mode", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "Enabled", .value = 1 }, + { .description = "" } + }, + }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0258, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "208H", .value = 0x0208 }, + { .description = "218H", .value = 0x0218 }, + { .description = "258H", .value = 0x0258 }, + { .description = "268H", .value = 0x0268 }, + { .description = "2A8H", .value = 0x02A8 }, + { .description = "2B8H", .value = 0x02B8 }, + { .description = "2E8H", .value = 0x02E8 }, + { .description = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; static const device_t ev159_device = { - "Everex EV-159 RAM 3000 Deluxe", - DEVICE_ISA, - 10, - isamem_init, isamem_close, NULL, - NULL, NULL, NULL, - ev159_config + .name = "Everex EV-159 RAM 3000 Deluxe", + .internal_name = "ev159", + .flags = DEVICE_ISA, + .local = ISAMEM_EV159_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ev159_config }; - -#ifdef USE_ISAMEM_RAMPAGE -static const device_config_t rampage_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x0258, - { - { - "208H", 0x0208 - }, - { - "218H", 0x0218 - }, - { - "258H", 0x0258 - }, - { - "268H", 0x0268 - }, - { - "2A8H", 0x02A8 - }, - { - "2B8H", 0x02B8 - }, - { - "2E8H", 0x02E8 - }, - { - "" - } - }, - }, - { - "frame", "Frame Address", CONFIG_HEX20, "", 0, - { - { - "Disabled", 0x00000 - }, - { - "C000H", 0xC0000 - }, - { - "D000H", 0xD0000 - }, - { - "E000H", 0xE0000 - }, - { - "" - } - }, - }, - { - "width", "I/O Width", CONFIG_SELECTION, "", 8, - { - { - "8-bit", 8 - }, - { - "16-bit", 16 - }, - { - "" - } - }, - }, - { - "speed", "Transfer Speed", CONFIG_SELECTION, "", 0, - { - { - "Standard", 0 - }, - { - "High-Speed", 1 - }, - { - "" - } - } - }, - { - "size", "Memory Size", CONFIG_SPINNER, "", 128, - { { 0 } }, - { { 0 } }, - { 0, 8192, 128 } - }, - { - "", "", -1 - } +#if defined(DEV_BRANCH) && defined(USE_ISAMEM_BRAT) +static const device_config_t brat_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0258, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "208H", .value = 0x0208 }, + { .description = "218H", .value = 0x0218 }, + { .description = "258H", .value = 0x0258 }, + { .description = "268H", .value = 0x0268 }, + { .description = "" } + }, + }, + { + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "D000H", .value = 0xD0000 }, + { .description = "E000H", .value = 0xE0000 }, + { .description = "" } + }, + }, + { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 8, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8-bit", .value = 8 }, + { .description = "16-bit", .value = 16 }, + { .description = "" } + }, + }, + { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Standard", .value = 0 }, + { .description = "High-Speed", .value = 1 }, + { .description = "" } + } + }, + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 128, + .file_filter = "", + .spinner = { + .min = 0, + .max = 8192, + .step = 512 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -static const device_t isamem_rampage_device = { - "AST RAMpage/XT", - DEVICE_ISA, - 11, - isamem_init, isamem_close, NULL, - NULL, NULL, NULL, - rampage_config +static const device_t brat_device = { + .name = "BocaRAM/AT", + .internal_name = "brat", + .flags = DEVICE_ISA, + .local = ISAMEM_BRAT_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = brat_config }; #endif +#if defined(DEV_BRANCH) && defined(USE_ISAMEM_RAMPAGE) +static const device_config_t rampage_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0258, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "208H", .value = 0x0208 }, + { .description = "218H", .value = 0x0218 }, + { .description = "258H", .value = 0x0258 }, + { .description = "268H", .value = 0x0268 }, + { .description = "2A8H", .value = 0x02A8 }, + { .description = "2B8H", .value = 0x02B8 }, + { .description = "2E8H", .value = 0x02E8 }, + { .description = "" } + }, + }, + { + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C000H", .value = 0xC0000 }, + { .description = "D000H", .value = 0xD0000 }, + { .description = "E000H", .value = 0xE0000 }, + { .description = "" } + }, + }, + { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 8, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8-bit", .value = 8 }, + { .description = "16-bit", .value = 16 }, + { .description = "" } + }, + }, + { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Standard", .value = 0 }, + { .description = "High-Speed", .value = 1 }, + { .description = "" } + } + }, + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 128, + .file_filter = "", + .spinner = { + .min = 0, + .max = 8192, + .step = 128 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_t rampage_device = { + .name = "AST RAMpage/XT", + .internal_name = "rampage", + .flags = DEVICE_ISA, + .local = ISAMEM_RAMPAGEXT_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = rampage_config +}; +#endif + +#if defined(DEV_BRANCH) && defined(USE_ISAMEM_IAB) +static const device_config_t iab_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0258, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "208H", .value = 0x0208 }, + { .description = "218H", .value = 0x0218 }, + { .description = "258H", .value = 0x0258 }, + { .description = "268H", .value = 0x0268 }, + { .description = "2A8H", .value = 0x02A8 }, + { .description = "2B8H", .value = 0x02B8 }, + { .description = "2E8H", .value = 0x02E8 }, + { .description = "" } + }, + }, + { + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C000H", .value = 0xC0000 }, + { .description = "D000H", .value = 0xD0000 }, + { .description = "E000H", .value = 0xE0000 }, + { .description = "" } + }, + }, + { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 8, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8-bit", .value = 8 }, + { .description = "16-bit", .value = 16 }, + { .description = "" } + }, + }, + { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Standard", .value = 0 }, + { .description = "High-Speed", .value = 1 }, + { .description = "" } + } + }, + { + .name = "size", + .description = "Memory Size", + .type = CONFIG_SPINNER, + .default_string = "", + .default_int = 128, + .file_filter = "", + .spinner = { + .min = 0, + .max = 8192, + .step = 128 + }, + .selection = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_t iab_device = { + .name = "Intel AboveBoard", + .internal_name = "iab", + .flags = DEVICE_ISA, + .local = ISAMEM_ABOVEBOARD_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = iab_config +}; +#endif + +static const device_t isa_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; static const struct { - const char *internal_name; const device_t *dev; } boards[] = { - { "none", NULL }, - { "ibmxt", &ibmxt_device }, - { "ibmat", &ibmat_device }, - { "p5pak", &p5pak_device }, - { "ems5150", &ems5150_device }, - { "ev159", &ev159_device }, -#ifdef USE_ISAMEM_BRAT - { "brat", &brat_device }, +// clang-format off + { &isa_none_device }, + { &ibmxt_device }, + { &genericxt_device }, + { &msramcard_device }, + { &mssystemcard_device }, + { &ibmat_device }, + { &genericat_device }, + { &p5pak_device }, + { &a6pak_device }, + { &ems5150_device }, + { &ev159_device }, +#if defined(DEV_BRANCH) && defined(USE_ISAMEM_BRAT) + { &brat_device }, #endif -#ifdef USE_ISAMEM_RAMPAGE - { "rampage", &rampage_device }, +#if defined(DEV_BRANCH) && defined(USE_ISAMEM_RAMPAGE) + { &rampage_device }, #endif -#ifdef USE_ISAMEM_IAB - { "iab", &iab_device }, +#if defined(DEV_BRANCH) && defined(USE_ISAMEM_IAB) + { &iab_device }, #endif - { NULL, NULL } + { NULL } +// clang-format on }; - void isamem_reset(void) { int k, i; + /* We explicitly set to zero here or bad things happen */ + isa_mem_size = 0; + for (i = 0; i < ISAMEM_MAX; i++) { k = isamem_type[i]; if (k == 0) continue; @@ -1042,7 +1591,6 @@ isamem_reset(void) } } - const char * isamem_get_name(int board) { @@ -1051,22 +1599,19 @@ isamem_get_name(int board) return(boards[board].dev->name); } - const char * isamem_get_internal_name(int board) { - return(boards[board].internal_name); + return device_get_internal_name(boards[board].dev); } - - int isamem_get_from_internal_name(const char *s) { int c = 0; - while (boards[c].internal_name != NULL) { - if (! strcmp(boards[c].internal_name, s)) + while (boards[c].dev != NULL) { + if (! strcmp(boards[c].dev->internal_name, s)) return(c); c++; } @@ -1075,7 +1620,6 @@ isamem_get_from_internal_name(const char *s) return(0); } - const device_t * isamem_get_device(int board) { diff --git a/src/device/isapnp.c b/src/device/isapnp.c new file mode 100644 index 000000000..45752a3ca --- /dev/null +++ b/src/device/isapnp.c @@ -0,0 +1,1074 @@ +/* + * 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 Plug and Play. + * + * + * + * Author: Miran Grca, + * RichardG, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2021 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/isapnp.h> + + +#define CHECK_CURRENT_LD() if (!dev->current_ld) { \ + isapnp_log("ISAPnP: No logical device selected\n"); \ + break; \ + } + +#define CHECK_CURRENT_CARD() if (1) { \ + card = dev->first_card; \ + while (card) { \ + if (card->enable && (card->state == PNP_STATE_CONFIG)) \ + break; \ + card = card->next; \ + } \ + if (!card) { \ + isapnp_log("ISAPnP: No card in CONFIG state\n"); \ + break; \ + } \ + } + + +static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, + 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, + 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, + 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; +static const device_t isapnp_device; + + +#ifdef ENABLE_ISAPNP_LOG +int isapnp_do_log = ENABLE_ISAPNP_LOG; + + +static void +isapnp_log(const char *fmt, ...) +{ + va_list ap; + + if (isapnp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define isapnp_log(fmt, ...) +#endif + + +enum { + PNP_STATE_WAIT_FOR_KEY = 0, + PNP_STATE_CONFIG, + PNP_STATE_ISOLATION, + PNP_STATE_SLEEP +}; + +typedef struct _isapnp_device_ { + uint8_t number; + uint8_t regs[256]; + uint8_t mem_upperlimit, irq_types, io_16bit, io_len[8]; + const isapnp_device_config_t *defaults; + + struct _isapnp_device_ *next; +} isapnp_device_t; + +typedef struct _isapnp_card_ { + uint8_t enable, state, csn, id_checksum, serial_read, serial_read_pair, serial_read_pos, *rom; + uint16_t rom_pos, rom_size; + void *priv; + + /* ISAPnP memory and I/O addresses are awkwardly big endian, so we populate this + structure whenever something on some device changes, and pass it on instead. */ + isapnp_device_config_t config; + void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv); + void (*csn_changed)(uint8_t csn, void *priv); + uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv); + void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv); + + isapnp_device_t *first_ld; + struct _isapnp_card_ *next; +} isapnp_card_t; + +typedef struct { + uint8_t reg, key_pos: 5; + uint16_t read_data_addr; + + isapnp_card_t *first_card, *isolated_card, *current_ld_card; + isapnp_device_t *current_ld; +} isapnp_t; + + +static void +isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld) +{ + /* Ignore card if it hasn't signed up for configuration changes. */ + if (!card->config_changed) + return; + + /* Populate config structure, performing endianness conversion as needed. */ + card->config.activate = ld->regs[0x30] & 0x01; + uint8_t i, reg_base; + for (i = 0; i < 4; i++) { + reg_base = 0x40 + (8 * i); + card->config.mem[i].base = (ld->regs[reg_base] << 16) | (ld->regs[reg_base + 1] << 8); + card->config.mem[i].size = (ld->regs[reg_base + 3] << 16) | (ld->regs[reg_base + 4] << 8); + if (ld->regs[reg_base + 2] & 0x01) /* upper limit */ + card->config.mem[i].size -= card->config.mem[i].base; + } + for (i = 0; i < 4; i++) { + reg_base = (i == 0) ? 0x76 : (0x80 + (16 * i)); + card->config.mem32[i].base = (ld->regs[reg_base] << 24) | (ld->regs[reg_base + 1] << 16) | (ld->regs[reg_base + 2] << 8) | ld->regs[reg_base + 3]; + card->config.mem32[i].size = (ld->regs[reg_base + 5] << 24) | (ld->regs[reg_base + 6] << 16) | (ld->regs[reg_base + 7] << 8) | ld->regs[reg_base + 8]; + if (ld->regs[reg_base + 4] & 0x01) /* upper limit */ + card->config.mem32[i].size -= card->config.mem32[i].base; + } + for (i = 0; i < 8; i++) { + reg_base = 0x60 + (2 * i); + if (ld->regs[0x31] & 0x02) + card->config.io[i].base = 0; /* let us handle I/O range check reads */ + else + card->config.io[i].base = (ld->regs[reg_base] << 8) | ld->regs[reg_base + 1]; + } + for (i = 0; i < 2; i++) { + reg_base = 0x70 + (2 * i); + card->config.irq[i].irq = ld->regs[reg_base]; + card->config.irq[i].level = ld->regs[reg_base + 1] & 0x02; + card->config.irq[i].type = ld->regs[reg_base + 1] & 0x01; + } + for (i = 0; i < 2; i++) { + reg_base = 0x74 + i; + card->config.dma[i].dma = ld->regs[reg_base]; + } + + /* Signal the configuration change. */ + card->config_changed(ld->number, &card->config, card->priv); +} + + +static void +isapnp_reset_ld_config(isapnp_device_t *ld) +{ + /* Do nothing if there's no default configuration for this device. */ + const isapnp_device_config_t *config = ld->defaults; + if (!config) + return; + + /* Populate configuration registers. */ + ld->regs[0x30] = !!config->activate; + uint8_t i, reg_base; + uint32_t size; + for (i = 0; i < 4; i++) { + reg_base = 0x40 + (8 * i); + ld->regs[reg_base] = config->mem[i].base >> 16; + ld->regs[reg_base + 1] = config->mem[i].base >> 8; + size = config->mem[i].size; + if (ld->regs[reg_base + 2] & 0x01) /* upper limit */ + size += config->mem[i].base; + ld->regs[reg_base + 3] = size >> 16; + ld->regs[reg_base + 4] = size >> 8; + } + for (i = 0; i < 4; i++) { + reg_base = (i == 0) ? 0x76 : (0x80 + (16 * i)); + ld->regs[reg_base] = config->mem32[i].base >> 24; + ld->regs[reg_base + 1] = config->mem32[i].base >> 16; + ld->regs[reg_base + 2] = config->mem32[i].base >> 8; + ld->regs[reg_base + 3] = config->mem32[i].base; + size = config->mem32[i].size; + if (ld->regs[reg_base + 4] & 0x01) /* upper limit */ + size += config->mem32[i].base; + ld->regs[reg_base + 5] = size >> 24; + ld->regs[reg_base + 6] = size >> 16; + ld->regs[reg_base + 7] = size >> 8; + ld->regs[reg_base + 8] = size; + } + for (i = 0; i < 8; i++) { + reg_base = 0x60 + (2 * i); + ld->regs[reg_base] = config->io[i].base >> 8; + ld->regs[reg_base + 1] = config->io[i].base; + } + for (i = 0; i < 2; i++) { + reg_base = 0x70 + (2 * i); + ld->regs[reg_base] = config->irq[i].irq; + ld->regs[reg_base + 1] = (!!config->irq[i].level << 1) | !!config->irq[i].type; + } + for (i = 0; i < 2; i++) { + reg_base = 0x74 + i; + ld->regs[reg_base] = config->dma[i].dma; + } +} + + +static void +isapnp_reset_ld_regs(isapnp_device_t *ld) +{ + memset(ld->regs, 0, sizeof(ld->regs)); + + /* DMA disable uses a non-zero value. */ + ld->regs[0x74] = ld->regs[0x75] = ISAPNP_DMA_DISABLED; + + /* Set the upper limit bit on memory ranges which require it. */ + uint8_t i; + for (i = 0; i < 4; i++) + ld->regs[0x42 + (8 * i)] |= !!(ld->mem_upperlimit & (1 << i)); + ld->regs[0x7a] |= !!(ld->mem_upperlimit & (1 << 4)); + for (i = 1; i < 4; i++) + ld->regs[0x84 + (16 * i)] |= !!(ld->mem_upperlimit & (1 << (4 + i))); + + /* Set the default IRQ type bits. */ + for (i = 0; i < 2; i++) { + if (ld->irq_types & (0x1 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x02; + else if (ld->irq_types & (0x2 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x00; + else if (ld->irq_types & (0x4 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x03; + else if (ld->irq_types & (0x8 << (4 * i))) + ld->regs[0x70 + (2 * i)] = 0x01; + } + + /* Reset configuration registers to match the default configuration. */ + isapnp_reset_ld_config(ld); +} + + +static uint8_t +isapnp_read_rangecheck(uint16_t addr, void *priv) +{ + isapnp_device_t *dev = (isapnp_device_t *) priv; + return (dev->regs[0x31] & 0x01) ? 0x55 : 0xaa; +} + + +static uint8_t +isapnp_read_data(uint16_t addr, void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + uint8_t ret = 0xff, bit, next_shift; + isapnp_card_t *card; + + switch (dev->reg) { + case 0x01: /* Serial Isolation */ + card = dev->first_card; + while (card) { + if (card->enable && card->rom && (card->state == PNP_STATE_ISOLATION)) + break; + card = card->next; + } + dev->isolated_card = card; + + if (card) { + if (card->serial_read_pair) { /* second byte (aa/00) */ + card->serial_read <<= 1; + if (!card->serial_read_pos) + card->rom_pos = 0x09; + } else { /* first byte (55/00) */ + if (card->serial_read_pos < 64) { /* reading 64-bit vendor/serial */ + bit = (card->rom[card->serial_read_pos >> 3] >> (card->serial_read_pos & 0x7)) & 0x01; + next_shift = (!!(card->id_checksum & 0x02) ^ !!(card->id_checksum & 0x01) ^ bit) & 0x01; + card->id_checksum >>= 1; + card->id_checksum |= (next_shift << 7); + } else { /* reading 8-bit checksum */ + if (card->serial_read_pos == 64) /* populate ID checksum in ROM */ + card->rom[0x08] = card->id_checksum; + bit = (card->id_checksum >> (card->serial_read_pos & 0x7)) & 0x01; + } + isapnp_log("ISAPnP: Read bit %d of byte %02X (%02X) = %d\n", card->serial_read_pos & 0x7, card->serial_read_pos >> 3, card->rom[card->serial_read_pos >> 3], bit); + card->serial_read = bit ? 0x55 : 0x00; + card->serial_read_pos = (card->serial_read_pos + 1) % 72; + } + card->serial_read_pair ^= 1; + ret = card->serial_read; + } + + break; + + case 0x04: /* Resource Data */ + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Read resource data index %02X (%02X) from CSN %02X\n", card->rom_pos, card->rom[card->rom_pos], card->csn); + if (card->rom_pos >= card->rom_size) + ret = 0xff; + else + ret = card->rom[card->rom_pos++]; + + break; + + case 0x05: /* Status */ + ret = 0x00; + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Query status for CSN %02X\n", card->csn); + ret = 0x01; + + break; + + case 0x06: /* Card Select Number */ + ret = 0x00; + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Query CSN %02X\n", card->csn); + ret = card->csn; + + break; + + case 0x07: /* Logical Device Number */ + ret = 0x00; + CHECK_CURRENT_LD(); + + isapnp_log("ISAPnP: Query LDN for CSN %02X device %02X\n", dev->current_ld_card->csn, dev->current_ld->number); + ret = dev->current_ld->number; + + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X\n", dev->reg, card->csn); + + if (card->read_vendor_reg) + ret = card->read_vendor_reg(0, dev->reg, card->priv); + break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X device %02X\n", dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + if (dev->current_ld_card->read_vendor_reg) + ret = dev->current_ld_card->read_vendor_reg(dev->current_ld->number, dev->reg, dev->current_ld_card->priv); + break; + + default: + if (dev->reg >= 0x30) { + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Read register %02X from CSN %02X device %02X\n", dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + ret = dev->current_ld->regs[dev->reg]; + } + break; + } + + isapnp_log("ISAPnP: read_data(%02X) = %02X\n", dev->reg, ret); + + return ret; +} + + +static void +isapnp_set_read_data(uint16_t addr, isapnp_t *dev) +{ + /* Remove existing READ_DATA port if set. */ + if (dev->read_data_addr) { + io_removehandler(dev->read_data_addr, 1, isapnp_read_data, NULL, NULL, NULL, NULL, NULL, dev); + dev->read_data_addr = 0; + } + + /* Set new READ_DATA port if within range. */ + if ((addr >= 0x203) && (addr <= 0x3ff)) { + dev->read_data_addr = addr; + io_sethandler(dev->read_data_addr, 1, isapnp_read_data, NULL, NULL, NULL, NULL, NULL, dev); + } +} + + +static void +isapnp_write_addr(uint16_t addr, uint8_t val, void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + isapnp_card_t *card = dev->first_card; + + isapnp_log("ISAPnP: write_addr(%02X)\n", val); + + if (!card) /* don't do anything if we have no PnP cards */ + return; + + dev->reg = val; + + if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */ + /* Check written value against LFSR key. */ + if (val == pnp_init_key[dev->key_pos]) { + dev->key_pos++; + if (!dev->key_pos) { + isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n"); + while (card) { + if (card->enable && (card->enable != ISAPNP_CARD_NO_KEY) && (card->state == PNP_STATE_WAIT_FOR_KEY)) + card->state = PNP_STATE_SLEEP; + card = card->next; + } + } + } else { + dev->key_pos = 0; + } + } +} + + +static void +isapnp_write_data(uint16_t addr, uint8_t val, void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + isapnp_card_t *card; + isapnp_device_t *ld; + uint16_t io_addr, reset_cards = 0; + + isapnp_log("ISAPnP: write_data(%02X)\n", val); + + switch (dev->reg) { + case 0x00: /* Set RD_DATA Port */ + isapnp_set_read_data((val << 2) | 3, dev); + isapnp_log("ISAPnP: Read data port set to %04X\n", dev->read_data_addr); + break; + + case 0x02: /* Config Control */ + if (val & 0x01) { + isapnp_log("ISAPnP: Reset\n"); + + card = dev->first_card; + while (card) { + ld = card->first_ld; + while (ld) { + if (card->state != PNP_STATE_WAIT_FOR_KEY) { + isapnp_reset_ld_regs(ld); + isapnp_device_config_changed(card, ld); + reset_cards++; + } + ld = ld->next; + } + card = card->next; + } + + if (reset_cards != 0) { + dev->current_ld = NULL; + dev->current_ld_card = NULL; + dev->isolated_card = NULL; + } + } + if (val & 0x02) { + isapnp_log("ISAPnP: Return to WAIT_FOR_KEY\n"); + card = dev->first_card; + while (card) { + card->state = PNP_STATE_WAIT_FOR_KEY; + card = card->next; + } + } + if (val & 0x04) { + isapnp_log("ISAPnP: Reset CSN\n"); + card = dev->first_card; + while (card) { + isapnp_set_csn(card, 0); + card = card->next; + } + } + break; + + case 0x03: /* Wake[CSN] */ + isapnp_log("ISAPnP: Wake[%02X]\n", val); + card = dev->first_card; + while (card) { + if (card->csn == val) { + card->rom_pos = 0; + card->id_checksum = pnp_init_key[0]; + if (card->state == PNP_STATE_SLEEP) + card->state = (val == 0) ? PNP_STATE_ISOLATION : PNP_STATE_CONFIG; + } else { + card->state = PNP_STATE_SLEEP; + } + + card = card->next; + } + break; + + case 0x06: /* Card Select Number */ + if (dev->isolated_card) { + isapnp_log("ISAPnP: Set CSN %02X\n", val); + isapnp_set_csn(dev->isolated_card, val); + dev->isolated_card->state = PNP_STATE_CONFIG; + dev->isolated_card = NULL; + } else { + isapnp_log("ISAPnP: Set CSN %02X but no card is isolated\n", val); + } + break; + + case 0x07: /* Logical Device Number */ + CHECK_CURRENT_CARD(); + + ld = card->first_ld; + while (ld) { + if (ld->number == val) { + isapnp_log("ISAPnP: Select CSN %02X device %02X\n", card->csn, val); + dev->current_ld_card = card; + dev->current_ld = ld; + break; + } + ld = ld->next; + } + + if (!ld) + isapnp_log("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); + + break; + + case 0x30: /* Activate */ + CHECK_CURRENT_LD(); + + isapnp_log("ISAPnP: %sctivate CSN %02X device %02X\n", (val & 0x01) ? "A" : "Dea", dev->current_ld_card->csn, dev->current_ld->number); + + dev->current_ld->regs[dev->reg] = val & 0x01; + isapnp_device_config_changed(dev->current_ld_card, dev->current_ld); + + break; + + case 0x31: /* I/O Range Check */ + CHECK_CURRENT_LD(); + + for (uint8_t i = 0; i < 8; i++) { + if (!dev->current_ld->io_len[i]) + continue; + + io_addr = (dev->current_ld->regs[0x60 + (2 * i)] << 8) | dev->current_ld->regs[0x61 + (2 * i)]; + if (dev->current_ld->regs[dev->reg] & 0x02) + io_removehandler(io_addr, dev->current_ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, dev->current_ld); + if (val & 0x02) + io_sethandler(io_addr, dev->current_ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, dev->current_ld); + } + + dev->current_ld->regs[dev->reg] = val & 0x03; + isapnp_device_config_changed(dev->current_ld_card, dev->current_ld); + + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + CHECK_CURRENT_CARD(); + + isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X\n", val, dev->reg, card->csn); + + if (card->write_vendor_reg) + card->write_vendor_reg(0, dev->reg, val, card->priv); + break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X device %02X\n", val, dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + if (dev->current_ld_card->write_vendor_reg) + dev->current_ld_card->write_vendor_reg(dev->current_ld->number, dev->reg, val, dev->current_ld_card->priv); + break; + + default: + if (dev->reg >= 0x40) { + CHECK_CURRENT_LD(); + isapnp_log("ISAPnP: Write %02X to register %02X on CSN %02X device %02X\n", val, dev->reg, dev->current_ld_card->csn, dev->current_ld->number); + + switch (dev->reg) { + case 0x42: case 0x4a: case 0x52: case 0x5a: + case 0x7a: case 0x84: case 0x94: case 0xa4: + /* Read-only memory range length / upper limit bit. */ + val = (val & 0xfe) | (dev->current_ld->regs[dev->reg] & 0x01); + break; + + case 0x60: case 0x62: case 0x64: case 0x66: case 0x68: case 0x6a: case 0x6c: case 0x6e: + /* Discard upper address bits if this I/O range can only decode 10-bit. */ + if (!(dev->current_ld->io_16bit & (1 << ((dev->reg >> 1) & 0x07)))) + val &= 0x03; + break; + + case 0x71: case 0x73: + /* Limit IRQ types to supported ones. */ + if ((val & 0x01) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x0c : 0xc0))) /* level, not supported = force edge */ + val &= ~0x01; + else if (!(val & 0x01) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x03 : 0x30))) /* edge, not supported = force level */ + val |= 0x01; + + if ((val & 0x02) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x05 : 0x50))) /* high, not supported = force low */ + val &= ~0x02; + else if (!(val & 0x02) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x0a : 0xa0))) /* low, not supported = force high */ + val |= 0x02; + + break; + } + + dev->current_ld->regs[dev->reg] = val; + isapnp_device_config_changed(dev->current_ld_card, dev->current_ld); + } + break; + } +} + + +static void * +isapnp_init(const device_t *info) +{ + isapnp_t *dev = (isapnp_t *) malloc(sizeof(isapnp_t)); + memset(dev, 0, sizeof(isapnp_t)); + + io_sethandler(0x279, 1, NULL, NULL, NULL, isapnp_write_addr, NULL, NULL, dev); + io_sethandler(0xa79, 1, NULL, NULL, NULL, isapnp_write_data, NULL, NULL, dev); + + return dev; +} + + +static void +isapnp_close(void *priv) +{ + isapnp_t *dev = (isapnp_t *) priv; + isapnp_card_t *card = dev->first_card, *next_card; + isapnp_device_t *ld, *next_ld; + + while (card) { + ld = card->first_ld; + while (ld) { + next_ld = ld->next; + free(ld); + ld = next_ld; + } + + next_card = card->next; + free(card); + card = next_card; + } + + io_removehandler(0x279, 1, NULL, NULL, NULL, isapnp_write_addr, NULL, NULL, dev); + io_removehandler(0xa79, 1, NULL, NULL, NULL, isapnp_write_data, NULL, NULL, dev); + + free(dev); +} + + +void * +isapnp_add_card(uint8_t *rom, uint16_t rom_size, + void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv), + void (*csn_changed)(uint8_t csn, void *priv), + uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), + void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), + void *priv) +{ + isapnp_t *dev = (isapnp_t *) device_get_priv(&isapnp_device); + if (!dev) + dev = (isapnp_t *) device_add(&isapnp_device); + + isapnp_card_t *card = (isapnp_card_t *) malloc(sizeof(isapnp_card_t)); + memset(card, 0, sizeof(isapnp_card_t)); + + card->enable = 1; + card->priv = priv; + card->config_changed = config_changed; + card->csn_changed = csn_changed; + card->read_vendor_reg = read_vendor_reg; + card->write_vendor_reg = write_vendor_reg; + + if (!dev->first_card) { + dev->first_card = card; + } else { + isapnp_card_t *prev_card = dev->first_card; + while (prev_card->next) + prev_card = prev_card->next; + prev_card->next = card; + } + + if (rom && rom_size) + isapnp_update_card_rom(card, rom, rom_size); + + return card; +} + + +void +isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + card->rom = rom; + card->rom_size = rom_size; + + /* Parse resources in ROM to allocate logical devices, + and determine the state of read-only register bits. */ +#ifdef ENABLE_ISAPNP_LOG + uint16_t vendor = (card->rom[0] << 8) | card->rom[1]; + isapnp_log("ISAPnP: Parsing ROM resources for card %c%c%c%02X%02X (serial %08X)\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[2], card->rom[3], (card->rom[7] << 24) | (card->rom[6] << 16) | (card->rom[5] << 8) | card->rom[4]); +#endif + uint16_t i = 9, j; + uint8_t existing = 0, ldn = 0, res, in_df = 0; + uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0; + uint32_t len; + isapnp_device_t *ld = NULL, *prev_ld = NULL; + + /* Check if this is an existing card which already has logical devices. + Any new logical devices will be added to the list after existing ones. + Removed LDs are not flushed as we may end up with an invalid ROM. */ + existing = !!card->first_ld; + + /* Iterate through ROM resources. */ + while (i < card->rom_size) { + if (card->rom[i] & 0x80) { /* large resource */ + res = card->rom[i] & 0x7f; + len = (card->rom[i + 2] << 8) | card->rom[i + 1]; + + switch (res) { + case 0x01: /* memory range */ + case 0x05: /* 32-bit memory range */ + if (res == 0x01) { + if (!ld) { + isapnp_log("ISAPnP: >>%s Memory descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (mem_range > 3) { + isapnp_log("ISAPnP: >>%s Memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range++); + break; + } + + isapnp_log("ISAPnP: >>%s Memory range %d uses upper limit = ", in_df ? ">" : "", mem_range); + res = 1 << mem_range; + mem_range++; + } else { + if (!ld) { + isapnp_log("ISAPnP: >>%s 32-bit memory descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (mem_range_32 > 3) { + isapnp_log("ISAPnP: >>%s 32-bit memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range_32++); + break; + } + + isapnp_log("ISAPnP: >>%s 32-bit memory range %d uses upper limit = ", in_df ? ">" : "", mem_range_32); + res = 1 << (4 + mem_range_32); + mem_range_32++; + } + + if (card->rom[i + 3] & 0x4) { + isapnp_log("yes\n"); + ld->mem_upperlimit |= res; + } else { + isapnp_log("no\n"); + ld->mem_upperlimit &= ~res; + } + + break; + +#ifdef ENABLE_ISAPNP_LOG + case 0x02: /* ANSI identifier */ + res = card->rom[i + 3 + len]; + card->rom[i + 3 + len] = '\0'; + isapnp_log("ISAPnP: >%s ANSI identifier: \"%s\"\n", ldn ? ">" : "", &card->rom[i + 3]); + card->rom[i + 3 + len] = res; + break; + + default: + isapnp_log("ISAPnP: >%s%s Large resource %02X (length %d)\n", ldn ? ">" : "", in_df ? ">" : "", res, (card->rom[i + 2] << 8) | card->rom[i + 1]); + break; +#endif + } + + i += 3; /* header */ + } else { /* small resource */ + res = (card->rom[i] >> 3) & 0x0f; + len = card->rom[i] & 0x07; + + switch (res) { + case 0x02: +#ifdef ENABLE_ISAPNP_LOG + vendor = (card->rom[i + 1] << 8) | card->rom[i + 2]; + isapnp_log("ISAPnP: > Logical device %02X: %c%c%c%02X%02X\n", ldn, '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]); +#endif + + /* We're done with the previous logical device. */ + if (ld && !existing) + isapnp_reset_ld_regs(ld); + + /* Look for an existing logical device with this number, + and create one if none exist. */ + if (existing) { + ld = card->first_ld; + while (ld && (ld->number != ldn)) + ld = ld->next; + } + if (ld && (ld->number == ldn)) { + /* Reset some logical device state. */ + ld->mem_upperlimit = ld->io_16bit = ld->irq_types = 0; + memset(ld->io_len, 0, sizeof(ld->io_len)); + } else { + /* Create logical device. */ + ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); + memset(ld, 0, sizeof(isapnp_device_t)); + + /* Add to end of list. */ + prev_ld = card->first_ld; + if (prev_ld) { + while (prev_ld->next) + prev_ld = prev_ld->next; + prev_ld->next = ld; + } else { + card->first_ld = ld; + } + } + + /* Set and increment logical device number. */ + ld->number = ldn++; + + /* Start the position counts over. */ + irq = io = mem_range = mem_range_32 = irq_df = io_df = mem_range_df = mem_range_32_df = 0; + + break; + +#ifdef ENABLE_ISAPNP_LOG + case 0x03: /* compatible device ID */ + if (!ld) { + isapnp_log("ISAPnP: >> Compatible device ID with no logical device\n"); + break; + } + + vendor = (card->rom[i + 1] << 8) | card->rom[i + 2]; + isapnp_log("ISAPnP: >> Compatible device ID: %c%c%c%02X%02X\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]); + break; +#endif + + case 0x04: /* IRQ */ + if (!ld) { + isapnp_log("ISAPnP: >>%s IRQ descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (irq > 1) { + isapnp_log("ISAPnP: >>%s IRQ descriptor overflow (%d)\n", in_df ? ">" : "", irq++); + break; + } + + if (len == 2) /* default */ + res = 0x01; /* high true edge sensitive */ + else /* specific */ + res = card->rom[i + 3] & 0x0f; + + isapnp_log("ISAPnP: >>%s IRQ index %d interrupt types = %01X\n", in_df ? ">" : "", irq, res); + + ld->irq_types &= ~(0x0f << (4 * irq)); + ld->irq_types |= res << (4 * irq); + + irq++; + + break; + + case 0x06: /* start dependent function */ + if (!ld) { + isapnp_log("ISAPnP: >> Start dependent function with no logical device\n"); + break; + } + + isapnp_log("ISAPnP: >> Start dependent function: %s\n", (((len == 0) || (card->rom[i + 1] == 1)) ? "acceptable" : ((card->rom[i + 1] == 0) ? "good" : ((card->rom[i + 1] == 2) ? "sub-optimal" : "unknown priority")))); + + if (in_df) { + /* We're in a dependent function and this is the next one starting. + Walk positions back to the saved values. */ + irq = irq_df; + io = io_df; + mem_range = mem_range_df; + mem_range_32 = mem_range_32_df; + } else { + /* Save current positions to restore at the next DF. */ + irq_df = irq; + io_df = io; + mem_range_df = mem_range; + mem_range_32_df = mem_range_32; + in_df = 1; + } + + break; + + case 0x07: /* end dependent function */ + isapnp_log("ISAPnP: >> End dependent function\n"); + in_df = 0; + break; + + case 0x08: /* I/O port */ + if (!ld) { + isapnp_log("ISAPnP: >>%s I/O descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (io > 7) { + isapnp_log("ISAPnP: >>%s I/O descriptor overflow (%d)\n", in_df ? ">" : "", io++); + break; + } + + isapnp_log("ISAPnP: >>%s I/O range %d %d-bit decode, %d ports\n", in_df ? ">" : "", io, (card->rom[i + 1] & 0x01) ? 16 : 10, card->rom[i + 7]); + + if (card->rom[i + 1] & 0x01) + ld->io_16bit |= 1 << io; + else + ld->io_16bit &= ~(1 << io); + + if (card->rom[i + 7] > ld->io_len[io]) + ld->io_len[io] = card->rom[i + 7]; + + io++; + + break; + + case 0x0f: /* end tag */ + /* Calculate checksum. */ + res = 0x00; + for (j = 9; j <= i; j++) + res += card->rom[j]; + card->rom[i + 1] = -res; + + isapnp_log("ISAPnP: End card resources (checksum %02X)\n", card->rom[i + 1]); + + /* Stop parsing here. */ + card->rom_size = i + 2; + break; + +#ifdef ENABLE_ISAPNP_LOG + default: + isapnp_log("ISAPnP: >%s%s Small resource %02X (length %d)\n", ldn ? ">" : "", in_df ? ">" : "", res, card->rom[i] & 0x07); + break; +#endif + } + + i++; /* header */ + } + i += len; /* specified length */ + } + + /* We're done with the last logical device. */ + if (ld && !existing) + isapnp_reset_ld_regs(ld); +} + + +void +isapnp_enable_card(void *priv, uint8_t enable) +{ + isapnp_t *dev = (isapnp_t *) device_get_priv(&isapnp_device); + if (!dev) + return; + + /* Look for a matching card. */ + isapnp_card_t *card = dev->first_card; + while (card) { + if (card == priv) { + /* Enable or disable the card. */ + if (!!enable ^ !!card->enable) + card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + card->enable = enable; + + /* Invalidate other references if we're disabling this card. */ + if (!card->enable) { + if (dev->isolated_card == card) + dev->isolated_card = NULL; + if (dev->current_ld_card == card) { + dev->current_ld = NULL; + dev->current_ld_card = NULL; + } + } + + break; + } + + card = card->next; + } +} + + +void +isapnp_set_csn(void *priv, uint8_t csn) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + + card->csn = csn; + if (card->csn_changed) + card->csn_changed(card->csn, card->priv); +} + + +void +isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + isapnp_device_t *ld = card->first_ld; + + /* Look for a logical device with this number. */ + while (ld && (ld->number != ldn)) + ld = ld->next; + + if (!ld) /* none found */ + return; + + ld->defaults = config; +} + + +void +isapnp_reset_card(void *priv) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + isapnp_device_t *ld = card->first_ld; + + /* Reset all logical devices. */ + while (ld) { + /* Reset the logical device's configuration. */ + isapnp_reset_ld_config(ld); + isapnp_device_config_changed(card, ld); + + ld = ld->next; + } +} + + +void +isapnp_reset_device(void *priv, uint8_t ldn) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + isapnp_device_t *ld = card->first_ld; + + /* Look for a logical device with this number. */ + while (ld && (ld->number != ldn)) + ld = ld->next; + + if (!ld) /* none found */ + return; + + /* Reset the logical device's configuration. */ + isapnp_reset_ld_config(ld); + isapnp_device_config_changed(card, ld); +} + + +static const device_t isapnp_device = { + "ISA Plug and Play", + "isapnp", + 0, + 0, + isapnp_init, isapnp_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/device/isartc.c b/src/device/isartc.c index 632ac0b1f..dc9557e3e 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -83,6 +83,11 @@ #include <86box/isartc.h> +#define ISARTC_EV170 0 +#define ISARTC_DTK 1 +#define ISARTC_P5PAK 2 +#define ISARTC_A6PAK 3 + #define ISARTC_DEBUG 0 @@ -388,7 +393,7 @@ mm67_read(uint16_t port, void *priv) uint8_t ret = 0xff; /* This chip is directly mapped on I/O. */ - sub_cycles(ISA_CYCLES(4)); + cycles -= ISA_CYCLES(4); switch(reg) { case MM67_ISTAT: /* IRQ status (RO) */ @@ -424,7 +429,7 @@ mm67_write(uint16_t port, uint8_t val, void *priv) #endif /* This chip is directly mapped on I/O. */ - sub_cycles(ISA_CYCLES(4)); + cycles -= ISA_CYCLES(4); switch(reg) { case MM67_ISTAT: /* intr status (RO) */ @@ -493,6 +498,8 @@ static void * isartc_init(const device_t *info) { rtcdev_t *dev; + int is_at = IS_AT(machine); + is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088"); /* Create a device instance. */ dev = (rtcdev_t *)malloc(sizeof(rtcdev_t)); @@ -506,7 +513,7 @@ isartc_init(const device_t *info) /* Do per-board initialization. */ switch(dev->board) { - case 0: /* Everex EV-170 Magic I/O */ + case ISARTC_EV170: /* Everex EV-170 Magic I/O */ dev->flags |= FLAG_YEAR80; dev->base_addr = device_get_config_hex16("base"); dev->base_addrsz = 32; @@ -519,7 +526,7 @@ isartc_init(const device_t *info) dev->year = MM67_AL_DOM; /* year, NON STANDARD */ break; - case 1: /* DTK PII-147 Hexa I/O Plus */ + case ISARTC_DTK: /* DTK PII-147 Hexa I/O Plus */ dev->flags |= FLAG_YEARBCD; dev->base_addr = device_get_config_hex16("base"); dev->base_addrsz = 32; @@ -531,7 +538,8 @@ isartc_init(const device_t *info) dev->year = MM67_AL_HUNTEN; /* year, NON STANDARD */ break; - case 2: /* Paradise Systems 5PAK */ + case ISARTC_P5PAK: /* Paradise Systems 5PAK */ + case ISARTC_A6PAK: /* AST SixPakPlus */ dev->flags |= FLAG_YEAR80; dev->base_addr = 0x02c0; dev->base_addrsz = 32; @@ -559,9 +567,10 @@ isartc_init(const device_t *info) dev->f_rd,NULL,NULL, dev->f_wr,NULL,NULL, dev); /* Hook into the NVR backend. */ - dev->nvr.fn = (wchar_t *)isartc_get_internal_name(isartc_type); + dev->nvr.fn = isartc_get_internal_name(isartc_type); dev->nvr.irq = dev->irq; - nvr_init(&dev->nvr); + if (!is_at) + nvr_init(&dev->nvr); /* Let them know our device instance. */ return((void *)dev); @@ -578,141 +587,164 @@ isartc_close(void *priv) dev->f_rd,NULL,NULL, dev->f_wr,NULL,NULL, dev); if (dev->nvr.fn != NULL) - free((wchar_t *)dev->nvr.fn); + free(dev->nvr.fn); free(dev); } - static const device_config_t ev170_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x02C0, - { - { - "240H", 0x0240 - }, - { - "2C0H", 0x02c0 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", -1, - { - { - "Disabled", -1 - }, - { - "IRQ2", 2 - }, - { - "IRQ5", 5 - }, - { - "IRQ7", 7 - }, - { - "" - } - }, - }, - { - "", "", -1 - } +// clang-format off + { + "base", "Address", CONFIG_HEX16, "", 0x02C0, "", { 0 }, + { + { "240H", 0x0240 }, + { "2C0H", 0x02c0 }, + { "" } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", -1, "", { 0 }, + { + { "Disabled", -1 }, + { "IRQ2", 2 }, + { "IRQ5", 5 }, + { "IRQ7", 7 }, + { "" } + }, + }, + { "", "", -1 } +// clang-format on }; static const device_t ev170_device = { - "Everex EV-170 Magic I/O", - DEVICE_ISA, - 0, - isartc_init, isartc_close, NULL, - NULL, NULL, NULL, - ev170_config + .name = "Everex EV-170 Magic I/O", + .internal_name = "ev170", + .flags = DEVICE_ISA, + .local = ISARTC_EV170, + .init = isartc_init, + .close = isartc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ev170_config }; - static const device_config_t pii147_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x0240, - { - { - "Clock 1", 0x0240 - }, - { - "Clock 2", 0x0340 - }, - { - "" - } - }, - }, - { - "", "", -1 - } +// clang-format off + { + "base", "Address", CONFIG_HEX16, "", 0x0240, "", { 0 }, + { + { "Clock 1", 0x0240 }, + { "Clock 2", 0x0340 }, + { "" } + }, + }, + { "", "", -1 } +// clang-format on }; static const device_t pii147_device = { - "DTK PII-147 Hexa I/O Plus", - DEVICE_ISA, - 1, - isartc_init, isartc_close, NULL, - NULL, NULL, NULL, - pii147_config + .name = "DTK PII-147 Hexa I/O Plus", + .internal_name = "pii147", + .flags = DEVICE_ISA, + .local = ISARTC_DTK, + .init = isartc_init, + .close = isartc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pii147_config }; - static const device_config_t p5pak_config[] = { - { - "irq", "IRQ", CONFIG_SELECTION, "", -1, - { - { - "Disabled", -1 - }, - { - "IRQ2", 2 - }, - { - "IRQ3", 3 - }, - { - "IRQ5", 5 - }, - { - "" - } - }, - }, - { - "", "", -1 - } +// clang-format off + { + "irq", "IRQ", CONFIG_SELECTION, "", -1, "", { 0 }, + { + { "Disabled", -1 }, + { "IRQ2", 2 }, + { "IRQ3", 3 }, + { "IRQ5", 5 }, + { "" } + }, + }, + { "", "", -1 } +// clang-format on }; static const device_t p5pak_device = { - "Paradise Systems 5-PAK", - DEVICE_ISA, - 2, - isartc_init, isartc_close, NULL, - NULL, NULL, NULL, - p5pak_config + .name = "Paradise Systems 5-PAK", + .internal_name = "p5pak", + .flags = DEVICE_ISA, + .local = ISARTC_P5PAK, + .init = isartc_init, + .close = isartc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = p5pak_config }; +static const device_config_t a6pak_config[] = { +// clang-format off + { + "irq", "IRQ", CONFIG_SELECTION, "", -1, "", { 0 }, + { + { "Disabled", -1 }, + { "IRQ2", 2 }, + { "IRQ3", 3 }, + { "IRQ5", 5 }, + { "" } + }, + }, + { "", "", -1 } +// clang-format on +}; + +static const device_t a6pak_device = { + .name = "AST SixPakPlus", + .internal_name = "a6pak", + .flags = DEVICE_ISA, + .local = ISARTC_A6PAK, + .init = isartc_init, + .close = isartc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = a6pak_config +}; + +static const device_t isartc_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; static const struct { - const char *name; - const char *internal_name; const device_t *dev; } boards[] = { - { "None", "none", NULL, }, - { "Everex EV-170 Magic I/O", "ev170", &ev170_device, }, - { "DTK PII-147 Hexa I/O Plus", "pii147", &pii147_device, }, - { "Paradise Systems 5-PAK", "p5pak", &p5pak_device, }, - { "", "", NULL, }, +// clang-format off + { &isartc_none_device }, + { &ev170_device }, + { &pii147_device }, + { &p5pak_device }, + { &a6pak_device }, + { NULL }, +// clang-format on }; - void isartc_reset(void) { @@ -722,18 +754,10 @@ isartc_reset(void) device_add(boards[isartc_type].dev); } - -char * -isartc_get_name(int board) -{ - return((char *)boards[board].name); -} - - char * isartc_get_internal_name(int board) { - return((char *)boards[board].internal_name); + return device_get_internal_name(boards[board].dev); } @@ -742,8 +766,8 @@ isartc_get_from_internal_name(char *s) { int c = 0; - while (strlen((char *) boards[c].internal_name)) { - if (! strcmp(boards[c].internal_name, s)) + while (boards[c].dev != NULL) { + if (! strcmp(boards[c].dev->internal_name, s)) return(c); c++; } diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 4aa40ae40..7c1581d52 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -26,6 +26,8 @@ #include <86box/machine.h> #include <86box/keyboard.h> +#include "cpu.h" + int keyboard_scan; void (*keyboard_send)(uint16_t val); @@ -93,7 +95,8 @@ key_process(uint16_t scan, int down) scancode *codes = scan_table; int c; - if (! keyboard_scan) return; + if (!keyboard_scan || (keyboard_send == NULL)) + return; oldkey[scan] = down; if (down && codes[scan].mk[0] == 0) @@ -102,7 +105,8 @@ key_process(uint16_t scan, int down) if (!down && codes[scan].brk[0] == 0) return; - if (AT && ((keyboard_mode & 3) == 3)) { + /* TODO: The keyboard controller needs to report the AT flag to us here. */ + if (is286 && ((keyboard_mode & 3) == 3)) { if (!keyboard_set3_all_break && !down && !(keyboard_set3_flags[codes[scan].mk[0]] & 2)) return; } @@ -211,7 +215,8 @@ keyboard_do_break(uint16_t scan) { scancode *codes = scan_table; - if (AT && ((keyboard_mode & 3) == 3)) { + /* TODO: The keyboard controller needs to report the AT flag to us here. */ + if (is286 && ((keyboard_mode & 3) == 3)) { if (!keyboard_set3_all_break && !recv_key[scan] && !(keyboard_set3_flags[codes[scan].mk[0]] & 2)) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 8976ef771..40cf46161 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -13,10 +13,12 @@ * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, + * EngiNerd * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2020 EngiNerd. */ #include #include @@ -55,8 +57,6 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16 * TIMER_USEC) - #define RESET_DELAY_TIME (100 * 10) /* 600ms */ #define CCB_UNUSED 0x80 @@ -86,34 +86,33 @@ #define KBC_VEN_IBM_PS1 0x18 #define KBC_VEN_ACER 0x1c #define KBC_VEN_INTEL_AMI 0x20 +#define KBC_VEN_OLIVETTI 0x24 +#define KBC_VEN_NCR 0x28 +#define KBC_VEN_SAMSUNG 0x2c +#define KBC_VEN_ALI 0x30 #define KBC_VEN_MASK 0x3c typedef struct { - uint8_t command, status, out, secr_phase, + uint8_t command, status, old_status, out, old_out, secr_phase, mem_addr, input_port, output_port, old_output_port, - key_command, output_locked, ami_stat, initialized, - want60, wantirq, key_wantdata, refresh, first_write; + key_command, output_locked, ami_stat, want60, + wantirq, key_wantdata, ami_flags, first_write; uint8_t mem[0x100]; - int out_new, out_delayed; - int last_irq, reset_delay; + int last_irq, old_last_irq, + reset_delay, + out_new, out_delayed; uint32_t flags; - pc_timer_t refresh_time, pulse_cb; + pc_timer_t pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); pc_timer_t send_delay_timer; -#ifdef USE_NEW_STUFF - /* Custom machine-dependent keyboard stuff. */ - uint8_t (*read_func)(void *priv); - void (*write_func)(void *priv, uint8_t val); - void *func_priv; -#endif } atkbd_t; @@ -125,17 +124,14 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; -int mouse_queue_start = 0, - mouse_queue_end = 0; - static uint8_t key_ctrl_queue[16]; -static int key_ctrl_queue_start = 0, - key_ctrl_queue_end = 0; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; -static int key_queue_start = 0, - key_queue_end = 0; -static uint8_t mouse_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; +uint8_t mouse_queue[16]; +int mouse_queue_start = 0, mouse_queue_end = 0; +static uint8_t kbd_last_scan_code; static void (*mouse_write)(uint8_t val, void *priv) = NULL; static void *mouse_p = NULL; static uint8_t sc_or = 0; @@ -624,78 +620,182 @@ set_scancode_map(atkbd_t *dev) } + +static void +kbc_queue_reset(uint8_t channel) +{ + if (channel == 2) { + mouse_queue_start = mouse_queue_end = 0; + memset(mouse_queue, 0x00, sizeof(mouse_queue)); + } else if (channel == 1) { + key_queue_start = key_queue_end = 0; + memset(key_queue, 0x00, sizeof(key_queue)); + } else { + key_ctrl_queue_start = key_ctrl_queue_end = 0; + memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); + } +} + + +static void +kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + dev->status = (dev->status & 0x0f) | stat_hi; + + if (channel == 2) { + kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; + } else if (channel == 1) { + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + } else { + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + } +} + + +static void +add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + kbd_log("ATkbc: Adding %02X to front...\n", val); + dev->wantirq = 0; + if (channel == 2) { + if (dev->mem[0] & 0x02) + picint(0x1000); + if (kbc_ven != KBC_VEN_OLIVETTI) + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + if (kbc_ven != KBC_VEN_OLIVETTI) + dev->last_irq = 2; + } + dev->out = val; + if (channel == 2) + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; + else + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; + if (kbc_ven == KBC_VEN_OLIVETTI) + dev->last_irq = 0x0000; +} + + +static void +add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) +{ + if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); + return; + } + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + kbc_queue_add(dev, val, 1, 0x00); + kbd_last_scan_code = val; +} + + + +static void +add_data_kbd_direct(atkbd_t *dev, uint8_t val) +{ + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); + uint8_t send; + + if (dev->reset_delay) + return; + + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + + if (translate) + send = nont_to_t[val]; + else + send = val; + + add_data_kbd_queue(dev, 1, send); +} + + +static void +add_data_kbd_raw(atkbd_t *dev, uint8_t val) +{ + add_data_kbd_queue(dev, 1, val); +} + + static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; +#ifdef ENABLE_KEYBOARD_AT_LOG + const uint8_t channels[4] = { 1, 2, 0, 0 }; +#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd[B]: out_new = %i, out_delayed = %i, STAT_OFULL = %i, qs = %i, qe = %i, last_irq = %08X\n", - dev->out_new, dev->out_delayed, !!(dev->status & STAT_OFULL), key_ctrl_queue_start, key_ctrl_queue_end, dev->last_irq); -#endif - - if ((dev->out_new != -1) && !dev->last_irq) { + if (dev->out_new != -1 && !dev->last_irq) { dev->wantirq = 0; if (dev->out_new & 0x100) { - if (mouse_scan) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: want mouse data\n"); -#endif - if (dev->mem[0] & 0x02) - picint(0x1000); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status |= STAT_OFULL; - dev->status &= ~STAT_IFULL; - dev->status |= STAT_MFULL; - dev->last_irq = 0x1000; - } else - dev->out_new = -1; - } else { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: want keyboard data\n"); -#endif - if (dev->mem[0] & 0x01) - picint(2); + if (dev->mem[0] & 0x02) + picint(0x1000); + kbd_log("ATkbc: %02X coming from channel 2\n"); dev->out = dev->out_new & 0xff; dev->out_new = -1; - dev->status |= STAT_OFULL; - dev->status &= ~STAT_IFULL; - dev->status &= ~STAT_MFULL; + dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); + dev->last_irq = 0x1000; + } else { + if (dev->mem[0] & 0x01) + picint(2); + kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; dev->last_irq = 2; } } -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd[A]: out_new = %i, out_delayed = %i, STAT_OFULL = %i, qs = %i, qe = %i, last_irq = %08X\n", - dev->out_new, dev->out_delayed, !!(dev->status & STAT_OFULL), key_ctrl_queue_start, key_ctrl_queue_end, dev->last_irq); -#endif - - if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { + kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); dev->out_new = dev->out_delayed; dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && dev->out_delayed != -1) { - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1/* && !(dev->mem[0] & 0x20)*/ && - (mouse_queue_start != mouse_queue_end)) { + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { + kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); dev->out_new = mouse_queue[mouse_queue_start] | 0x100; mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && - !(dev->mem[0]&0x10) && (key_queue_start != key_queue_end)) { + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { + kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); dev->out_new = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; } if (dev->reset_delay) { dev->reset_delay--; - if (!dev->reset_delay) - add_data_kbd(0xaa); + if (!dev->reset_delay) { + kbd_log("ATkbc: Sending AA on keyboard reset...\n"); + add_data_kbd_direct(dev, 0xaa); + } } } @@ -703,16 +803,12 @@ kbd_poll(void *priv) static void add_data(atkbd_t *dev, uint8_t val) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: add to queue\n"); -#endif - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + kbd_log("ATkbc: add to queue\n"); - if (! (dev->out_new & 0x300)) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: delay\n"); -#endif + kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); + kbc_queue_add(dev, val, 0, 0x00); + + if (!(dev->out_new & 0x300)) { dev->out_delayed = dev->out_new; dev->out_new = -1; } @@ -745,27 +841,9 @@ add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) or = 0; } else send = val[i]; -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("%02X", send); -#endif - key_queue[key_queue_end] = send; - key_queue_end = (key_queue_end + 1) & 0xf; -#ifdef ENABLE_KEYBOARD_AT_LOG - if (i < (len - 1)) kbd_log(" "); -#endif - } -#ifdef ENABLE_KEYBOARD_AT_LOG - if (translate) { - kbd_log(" original: ("); - for (i = 0; i < len; i++) { - kbd_log("%02X", val[i]); - if (i < (len - 1)) kbd_log(" "); - } - kbd_log(")"); + add_data_kbd_queue(dev, 0, send); } - kbd_log("\n"); -#endif } @@ -777,6 +855,7 @@ add_data_kbd(uint16_t val) int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; if (dev->reset_delay) return; @@ -789,25 +868,20 @@ add_data_kbd(uint16_t val) /* Allow for scan code translation. */ if (translate && (val == 0xf0)) { -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: translate is on, F0 prefix detected\n"); -#endif sc_or = 0x80; return; } /* Skip break code if translated make code has bit 7 set. */ if (translate && (sc_or == 0x80) && (val & 0x80)) { -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); -#endif sc_or = 0; return; } /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && - ((dev->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) && + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { case 0x4f: t3100e_notify_set(0x01); break; /* End */ case 0x50: t3100e_notify_set(0x02); break; /* Down */ @@ -826,19 +900,13 @@ add_data_kbd(uint16_t val) case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ } -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); -#endif switch(val) { case FAKE_LSHIFT_ON: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("fake left shift on, scan code: "); -#endif if (num_lock) { if (shift_states) { -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (one or both shifts on)\n"); -#endif break; } else { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ @@ -854,9 +922,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); -#endif break; } } @@ -875,9 +941,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); -#endif break; } } @@ -895,28 +959,19 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); -#endif break; } } -#ifdef ENABLE_KEYBOARD_AT_LOG - if (!shift_states) - kbd_log("N/A (both shifts off)\n"); -#endif + kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); } break; case FAKE_LSHIFT_OFF: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("fake left shift on, scan code: "); -#endif if (num_lock) { if (shift_states) { -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (one or both shifts on)\n"); -#endif break; } else { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ @@ -932,9 +987,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); -#endif break; } } @@ -953,9 +1006,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); -#endif break; } } @@ -973,16 +1024,11 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); -#endif break; } } -#ifdef ENABLE_KEYBOARD_AT_LOG - if (!shift_states) - kbd_log("N/A (both shifts off)\n"); -#endif + kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); } break; @@ -998,8 +1044,7 @@ add_data_kbd(uint16_t val) kbd_log("%02X\n", val); #endif - key_queue[key_queue_end] = (translate ? (nont_to_t[val] | sc_or) : val); - key_queue_end = (key_queue_end + 1) & 0xf; + add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); break; } @@ -1011,30 +1056,41 @@ add_data_kbd(uint16_t val) static void write_output(atkbd_t *dev, uint8_t val) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write output port: %02X (old: %02X)\n", val, dev->output_port); -#endif + uint8_t old = dev->output_port; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); - if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + if ((kbc_ven != KBC_VEN_OLIVETTI) && ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF))) + val |= ((dev->mem[0] << 4) & 0x10); + + /*IRQ 12*/ + if ((old ^ val) & 0x20) { if (val & 0x20) picint(1 << 12); else picintc(1 << 12); } - if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ + + /*IRQ 1*/ + if ((old ^ val) & 0x10) { if (val & 0x10) picint(1 << 1); else picintc(1 << 1); } - if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ + + if ((old ^ val) & 0x02) { /*A20 enable change*/ mem_a20_key = val & 0x02; mem_a20_recalc(); flushmmucache(); } - if ((dev->output_port ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { + + /* 0 holds the CPU in the RESET state, 1 releases it. To simplify this, + we just do everything on release. */ + if ((old ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { /* Pin 0 selected. */ /* Pin 0 selected. */ + kbd_log("write_output(): Pulse reset!\n"); if (machines[machine].flags & MACHINE_COREBOOT) { /* The SeaBIOS hard reset code attempts a KBC reset if ACPI RESET_REG is not available. However, the KBC reset is normally a soft reset, so @@ -1045,10 +1101,14 @@ write_output(atkbd_t *dev, uint8_t val) } else { softresetx86(); /*Pulse reset!*/ cpu_set_edx(); + flushmmucache(); + if (kbc_ven == KBC_VEN_ALI) + smbase = 0x00030000; } } } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + + /* Do this here to avoid an infinite reset loop. */ dev->output_port = val; } @@ -1056,9 +1116,8 @@ write_output(atkbd_t *dev, uint8_t val) static void write_cmd(atkbd_t *dev, uint8_t val) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); -#endif + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); if ((val & 1) && (dev->status & STAT_OFULL)) dev->wantirq = 1; @@ -1075,28 +1134,26 @@ write_cmd(atkbd_t *dev, uint8_t val) keyboard_mode &= 0x93; keyboard_mode |= (val & MODE_MASK); - keyboard_scan = !(val & 0x10); -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: keyboard is now %s\n", keyboard_scan ? "enabled" : "disabled"); - kbd_log("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); -#endif + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. */ - if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || - ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI) || + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { keyboard_mode &= ~CCB_PCMODE; - mouse_scan = !(val & 0x20); -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } - kbd_log("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); -#endif + if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->output_port); } kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); } @@ -1105,6 +1162,7 @@ pulse_output(atkbd_t *dev, uint8_t mask) { if (mask != 0x0f) { dev->old_output_port = dev->output_port & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); write_output(dev, dev->output_port & (0xf0 | mask)); timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); } @@ -1116,6 +1174,7 @@ pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; + kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); write_output(dev, dev->output_port | dev->old_output_port); } @@ -1125,8 +1184,6 @@ set_enable_kbd(atkbd_t *dev, uint8_t enable) { dev->mem[0] &= 0xef; dev->mem[0] |= (enable ? 0x00 : 0x10); - - keyboard_scan = enable; } @@ -1135,8 +1192,6 @@ set_enable_mouse(atkbd_t *dev, uint8_t enable) { dev->mem[0] &= 0xdf; dev->mem[0] |= (enable ? 0x00 : 0x20); - - mouse_scan = enable; } @@ -1145,94 +1200,87 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; + switch (val) { case 0xa4: /* check if password installed */ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: check if password installed\n"); -#endif + kbd_log("ATkbc: check if password installed\n"); add_data(dev, 0xf1); return 0; } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbd: bad command A4\n"); -#endif break; case 0xa7: /* disable mouse port */ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: disable mouse port\n"); -#endif + kbd_log("ATkbc: disable mouse port\n"); set_enable_mouse(dev, 0); return 0; } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbd: bad command A7\n"); -#endif break; case 0xa8: /*Enable mouse port*/ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: enable mouse port\n"); -#endif + kbd_log("ATkbc: enable mouse port\n"); set_enable_mouse(dev, 1); return 0; } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbd: bad command A8\n"); -#endif break; case 0xa9: /*Test mouse port*/ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: test mouse port\n"); -#endif + kbd_log("ATkbc: test mouse port\n"); if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - if (mouse_write) - add_data(dev, 0x00); /* no error */ - else - add_data(dev, 0xff); /* no mouse */ + add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ return 0; } -#ifdef ENABLE_KEYBOARD_AT_LOG - else - kbd_log("ATkbd: bad command A9\n"); -#endif break; case 0xaf: /* read keyboard version */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: read keyboard version\n"); -#endif + kbd_log("ATkbc: read keyboard version\n"); add_data(dev, 0x00); return 0; case 0xc0: /* read input port */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: read input port\n"); -#endif + kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ - if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI) + if (kbc_ven == KBC_VEN_INTEL_AMI) fixed_bits |= 0x40; - if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_IBM_PS1) { + if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - add_data(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), + 0, 0x00); dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); + } else if (kbc_ven == KBC_VEN_NCR) { + /* switch settings + * bit 7: keyboard disable + * bit 6: display type (0 color, 1 mono) + * bit 5: power-on default speed (0 high, 1 low) + * bit 4: sense RAM size (0 unsupported, 1 512k on system board) + * bit 3: coprocessor detect + * bit 2: unused + * bit 1: high/auto speed + * bit 0: dma mode + */ + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, + 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); } else { if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - add_data(dev, (dev->input_port | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); +#if 0 + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); +#else + add_to_kbc_queue_front(dev, ((dev->input_port | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); +#endif else - add_data(dev, dev->input_port | fixed_bits); + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc); } @@ -1240,39 +1288,27 @@ write64_generic(void *priv, uint8_t val) case 0xd3: /* write mouse output buffer */ if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write mouse output buffer\n"); -#endif + kbd_log("ATkbc: write mouse output buffer\n"); dev->want60 = 1; return 0; } break; case 0xd4: /* write to mouse */ -#if 0 - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { -#endif -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write to mouse\n"); -#endif - dev->want60 = 1; - return 0; -#if 0 - } - break; -#endif + kbd_log("ATkbc: write to mouse\n"); + dev->want60 = 1; + return 0; case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: pulse %01X\n", val & 0x0f); -#endif + kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; } + kbd_log("ATkbc: bad command %02X\n", val); return 1; } @@ -1292,16 +1328,14 @@ write60_ami(void *priv, uint8_t val) case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbd: AMI - alias write to %08X\n", dev->command); + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); dev->mem[dev->command & 0x1f] = val; if (dev->command == 0x60) write_cmd(dev, val); return 0; case 0xaf: /* set extended controller RAM */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - set extended controller RAM\n"); -#endif + kbd_log("ATkbc: AMI - set extended controller RAM\n"); if (dev->secr_phase == 1) { dev->mem_addr = val; dev->want60 = 1; @@ -1312,10 +1346,14 @@ write60_ami(void *priv, uint8_t val) } return 0; + case 0xc1: + kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); + dev->input_port = val; + return 0; + case 0xcb: /* set keyboard mode */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - set keyboard mode\n"); -#endif + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->ami_flags = val; return 0; } @@ -1327,6 +1365,7 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; switch (val) { case 0x00: case 0x01: case 0x02: case 0x03: @@ -1337,7 +1376,7 @@ write64_ami(void *priv, uint8_t val) case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - kbd_log("ATkbd: AMI - alias read from %08X\n", val); + kbd_log("ATkbc: AMI - alias read from %08X\n", val); add_data(dev, dev->mem[val]); return 0; @@ -1349,21 +1388,31 @@ write64_ami(void *priv, uint8_t val) case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbd: AMI - alias write to %08X\n", dev->command); + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); dev->want60 = 1; return 0; + case 0xa0: /* copyright message */ + add_data(dev, 0x28); + add_data(dev, 0x00); + break; + case 0xa1: /* get controller version */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - get controller version\n"); -#endif + kbd_log("ATkbc: AMI - get controller version\n"); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (kbc_ven == KBC_VEN_ALI) + add_data(dev, 'F'); + else if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI) + add_data(dev, '5'); + else + add_data(dev, 'H'); + } else + add_data(dev, 'F'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - clear KBC lines P22 and P23\n"); -#endif + kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); write_output(dev, dev->output_port & 0xf3); add_data(dev, 0x00); return 0; @@ -1372,9 +1421,7 @@ write64_ami(void *priv, uint8_t val) case 0xa3: /* set keyboard controller lines P22/P23 */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - set KBC lines P22 and P23\n"); -#endif + kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); write_output(dev, dev->output_port | 0x0c); add_data(dev, 0x00); return 0; @@ -1383,9 +1430,7 @@ write64_ami(void *priv, uint8_t val) case 0xa4: /* write clock = low */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - write clock = low\n"); -#endif + kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; } @@ -1393,9 +1438,7 @@ write64_ami(void *priv, uint8_t val) case 0xa5: /* write clock = high */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - write clock = high\n"); -#endif + kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; } @@ -1403,9 +1446,7 @@ write64_ami(void *priv, uint8_t val) case 0xa6: /* read clock */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - read clock\n"); -#endif + kbd_log("ATkbc: AMI - read clock\n"); add_data(dev, !!(dev->ami_stat & 1)); return 0; } @@ -1413,9 +1454,7 @@ write64_ami(void *priv, uint8_t val) case 0xa7: /* write cache bad */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - write cache bad\n"); -#endif + kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; } @@ -1423,9 +1462,7 @@ write64_ami(void *priv, uint8_t val) case 0xa8: /* write cache good */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - write cache good\n"); -#endif + kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; } @@ -1433,39 +1470,43 @@ write64_ami(void *priv, uint8_t val) case 0xa9: /* read cache */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - read cache\n"); -#endif + kbd_log("ATkbc: AMI - read cache\n"); add_data(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: set extended controller RAM\n"); -#endif - dev->want60 = 1; - dev->secr_phase = 1; + if (kbc_ven == KBC_VEN_ALI) { + kbd_log("ATkbc: Award/ALi/VIA keyboard controller revision\n"); + add_to_kbc_queue_front(dev, 0x43, 0, 0x00); + } else { + kbd_log("ATkbc: set extended controller RAM\n"); + dev->want60 = 1; + dev->secr_phase = 1; + } return 0; case 0xb0: case 0xb1: case 0xb2: case 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ - if (!PCI || (val > 0xb1)) + kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); + if (!(dev->flags & DEVICE_PCI) || (val > 0xb1)) dev->input_port &= ~(1 << (val & 0x03)); add_data(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ - if (! PCI) + kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); + if (! (dev->flags & DEVICE_PCI)) write_output(dev, dev->output_port & ~(4 << (val & 0x01))); add_data(dev, 0x00); return 0; case 0xb8: case 0xb9: case 0xba: case 0xbb: /* set KBC lines P10-P13 (input port bits 0-3) high */ - if (!PCI || (val > 0xb9)) { + kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); + if (!(dev->flags & DEVICE_PCI) || (val > 0xb9)) { dev->input_port |= (1 << (val & 0x03)); add_data(dev, 0x00); } @@ -1473,19 +1514,36 @@ write64_ami(void *priv, uint8_t val) case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ - if (! PCI) + kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); + if (! (dev->flags & DEVICE_PCI)) write_output(dev, dev->output_port | (4 << (val & 0x01))); add_data(dev, 0x00); return 0; + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write input port\n"); + dev->want60 = 1; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); + dev->input_port &= 0xef; + add_data(dev, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); + dev->input_port &= 0xdf; + add_data(dev, 0x00); + return 0; + case 0xc8: /* * unblock KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - unblock KBC lines P22 and P23\n"); -#endif + kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); dev->output_locked = 1; return 0; @@ -1494,16 +1552,25 @@ write64_ami(void *priv, uint8_t val) * block KBC lines P22/P23 * (disallow command D1 from changing bits 2/3 of the port) */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - block KBC lines P22 and P23\n"); -#endif + kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); dev->output_locked = 1; return 0; + case 0xcc: + /* set KBC line P14 high */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); + dev->input_port |= 0x10; + add_data(dev, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); + dev->input_port |= 0x20; + add_data(dev, 0x00); + return 0; + case 0xef: /* ??? - sent by AMI486 */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: ??? - sent by AMI486\n"); -#endif + kbd_log("ATkbc: ??? - sent by AMI486\n"); return 0; } @@ -1518,32 +1585,26 @@ write64_ibm_mca(void *priv, uint8_t val) switch (val) { case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); -#endif + kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); -#endif + kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: bad KBC command AF\n"); -#endif + kbd_log("ATkbc: bad KBC command AF\n"); return 1; case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: - kbd_log("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); + kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; } @@ -1559,15 +1620,36 @@ write60_quadtel(void *priv, uint8_t val) switch(dev->command) { case 0xcf: /*??? - sent by MegaPC BIOS*/ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: ??? - sent by MegaPC BIOS\n"); -#endif + kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; } return 1; } +static uint8_t +write64_olivetti(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *)priv; + + switch (val) { + case 0x80: /* Olivetti-specific command */ + /* + * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) + * bits 4-6: ??? + * bit 3: fast ram check (if inactive keyboard works erratically) + * bit 2: keyboard fuse present + * bits 0-1: ??? + */ + add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); + return 0; + } + + return write64_generic(dev, val); +} + static uint8_t write64_quadtel(void *priv, uint8_t val) @@ -1576,15 +1658,11 @@ write64_quadtel(void *priv, uint8_t val) switch (val) { case 0xaf: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: bad KBC command AF\n"); -#endif + kbd_log("ATkbc: bad KBC command AF\n"); return 1; case 0xcf: /*??? - sent by MegaPC BIOS*/ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: ??? - sent by MegaPC BIOS\n"); -#endif + kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); dev->want60 = 1; return 0; } @@ -1600,6 +1678,7 @@ write60_toshiba(void *priv, uint8_t val) switch(dev->command) { case 0xb6: /* T3100e - set color/mono switch */ + kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); return 0; } @@ -1615,47 +1694,61 @@ write64_toshiba(void *priv, uint8_t val) switch (val) { case 0xaf: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: bad KBC command AF\n"); -#endif + kbd_log("ATkbc: bad KBC command AF\n"); return 1; case 0xb0: /* T3100e: Turbo on */ + kbd_log("ATkbc: T3100e: Turbo on\n"); t3100e_turbo_set(1); return 0; case 0xb1: /* T3100e: Turbo off */ + kbd_log("ATkbc: T3100e: Turbo off\n"); t3100e_turbo_set(0); return 0; case 0xb2: /* T3100e: Select external display */ + kbd_log("ATkbc: T3100e: Select external display\n"); t3100e_display_set(0x00); return 0; case 0xb3: /* T3100e: Select internal display */ + kbd_log("ATkbc: T3100e: Select internal display\n"); t3100e_display_set(0x01); return 0; case 0xb4: /* T3100e: Get configuration / status */ + kbd_log("ATkbc: T3100e: Get configuration / status\n"); add_data(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ + kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); add_data(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ + kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); dev->want60 = 1; return 0; - case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ - case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */ + case 0xb7: /* T3100e: Emulate PS/2 keyboard */ + case 0xb8: /* T3100e: Emulate AT keyboard */ + dev->flags &= ~KBC_TYPE_MASK; + if (val == 0xb7) { + kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); + dev->flags |= KBC_TYPE_PS2_NOREF; + } else { + kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); + dev->flags |= KBC_TYPE_ISA; + } return 0; case 0xbb: /* T3100e: Read 'Fn' key. Return it for right Ctrl and right Alt; on the real T3100e, these keystrokes could only be generated using 'Fn'. */ + kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ add_data(dev, 0x04); @@ -1663,13 +1756,12 @@ write64_toshiba(void *priv, uint8_t val) return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ + kbd_log("ATkbc: T3100e: Reset Fn+Key notification\n"); t3100e_notify_set(0x00); return 0; case 0xc0: /*Read input port*/ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: read input port\n"); -#endif + kbd_log("ATkbc: read input port\n"); /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ @@ -1687,19 +1779,12 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; - int i = 0; - int bad = 1; - uint8_t mask; - - if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write(%04X, %02X)\n", port, val); -#endif + int i = 0, bad = 1; + uint8_t mask, kbc_ven = dev->flags & KBC_VEN_MASK; switch (port) { case 0x60: + dev->status &= ~STAT_CD; if (dev->want60) { /* Write data to controller. */ dev->want60 = 0; @@ -1719,9 +1804,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) break; case 0xd1: /* write output port */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write output port\n"); -#endif + kbd_log("ATkbc: write output port\n"); if (dev->output_locked) { /*If keyboard controller lines P22-P23 are blocked, we force them to remain unchanged.*/ @@ -1732,33 +1815,29 @@ kbd_write(uint16_t port, uint8_t val, void *priv) break; case 0xd2: /* write to keyboard output buffer */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write to keyboard output buffer\n"); -#endif - add_data_kbd(val); + kbd_log("ATkbc: write to keyboard output buffer\n"); + add_to_kbc_queue_front(dev, val, 0, 0x00); break; case 0xd3: /* write to mouse output buffer */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write to mouse output buffer\n"); -#endif + kbd_log("ATkbc: write to mouse output buffer\n"); if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) keyboard_at_adddata_mouse(val); break; case 0xd4: /* write to mouse */ - kbd_log("ATkbd: write to mouse (%02X)\n", val); + kbd_log("ATkbc: write to mouse (%02X)\n", val); if (val == 0xbb) break; - set_enable_mouse(dev, 1); - if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - mouse_write(val, mouse_p); - else if (!mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || - ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI))) - keyboard_at_adddata_mouse(0xff); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + set_enable_mouse(dev, 1); + if (mouse_write) + mouse_write(val, mouse_p); + else + add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); + } break; default: @@ -1772,7 +1851,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) bad = dev->write60_ven(dev, val); if (bad) { - kbd_log("ATkbd: bad controller command %02x data %02x\n", dev->command, val); + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); add_data_kbd(0xfe); } } @@ -1789,27 +1868,23 @@ kbd_write(uint16_t port, uint8_t val, void *priv) * code many times. Fun! */ if (val == dev->key_command) { -#if 1 /* Respond NAK and ignore it. */ add_data_kbd(0xfe); dev->key_command = 0x00; break; -#else - goto do_command; -#endif } switch (dev->key_command) { case 0xed: /* set/reset LEDs */ - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); kbd_log("ATkbd: set LEDs [%02x]\n", val); break; case 0xf0: /* get/set scancode set */ - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); if (val == 0) { kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - add_data_kbd(keyboard_mode & 3); + add_data_kbd_direct(dev, keyboard_mode & 3); } else { if ((val <= 3) && (val != 1)) { keyboard_mode &= 0xfc; @@ -1821,23 +1896,18 @@ kbd_write(uint16_t port, uint8_t val, void *priv) break; case 0xf3: /* set typematic rate/delay */ - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); break; - + default: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); -#endif - add_data_kbd(0xfe); + add_data_kbd_direct(dev, 0xfe); break; } /* Keyboard command is now done. */ dev->key_command = 0x00; } else { -#if 0 -do_command: -#endif /* No keyboard command in progress. */ dev->key_command = 0x00; @@ -1845,101 +1915,71 @@ do_command: switch (val) { case 0x00: -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: command 00\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); break; case 0x05: /*??? - sent by NT 4.0*/ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: command 05 (NT 4.0)\n"); -#endif - add_data_kbd(0xfe); + add_data_kbd_direct(dev, 0xfe); break; /* Sent by Pentium-era AMI BIOS'es.*/ - case 0x71: - case 0x82: + case 0x71: case 0x82: kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); break; case 0xed: /* set/reset LEDs */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set/reset leds\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); dev->key_wantdata = 1; break; case 0xee: /* diagnostic echo */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: ECHO\n"); -#endif - add_data_kbd(0xee); + add_data_kbd_direct(dev, 0xee); break; case 0xef: /* NOP (reserved for future use) */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: NOP\n"); -#endif break; case 0xf0: /* get/set scan code set */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: scan code set\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); dev->key_wantdata = 1; break; case 0xf2: /* read ID */ /* Fixed as translation will be done in add_data_kbd(). */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read keyboard id\n"); -#endif - add_data_kbd(0xfa); - add_data_kbd(0xab); - add_data_kbd(0x83); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + add_data_kbd_direct(dev, 0xfa); + add_data_kbd_direct(dev, 0xab); + add_data_kbd_direct(dev, 0x83); break; case 0xf3: /* set typematic rate/delay */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set typematic rate/delay\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); dev->key_wantdata = 1; break; case 0xf4: /* enable keyboard */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: enable keyboard via keyboard\n"); -#endif - add_data_kbd(0xfa); + kbd_log("ATkbd: enable keyboard\n"); + add_data_kbd_direct(dev, 0xfa); keyboard_scan = 1; break; - case 0xf5: /* disable keyboard */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: disable keyboard via keyboard\n"); -#endif - keyboard_scan = 0; - - /* - * Disabling the keyboard also - * resets it to the default - * values. - */ - /*FALLTHROUGH*/ - + case 0xf5: /* set defaults and disable keyboard */ case 0xf6: /* set defaults */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: set defaults\n"); -#endif - dev->out_new = -1; - dev->out_delayed = -1; - add_data_kbd(0xfa); + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", + val, keyboard_scan, dev->mem[0]); + add_data_kbd_direct(dev, 0xfa); keyboard_set3_all_break = 0; keyboard_set3_all_repeat = 0; @@ -1949,51 +1989,40 @@ do_command: break; case 0xf7: /* set all keys to repeat */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to repeat\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); keyboard_set3_all_break = 1; break; case 0xf8: /* set all keys to give make/break codes */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to give make/break codes\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); keyboard_set3_all_break = 1; break; case 0xf9: /* set all keys to give make codes only */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to give make codes only\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); keyboard_set3_all_break = 0; break; case 0xfa: /* set all keys to repeat and give make/break codes */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); -#endif - add_data_kbd(0xfa); + add_data_kbd_direct(dev, 0xfa); keyboard_set3_all_repeat = 1; keyboard_set3_all_break = 1; break; case 0xfe: /* resend last scan code */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: reset last scan code\n"); -#endif - add_data_kbd(key_queue[key_queue_end]); + add_data_kbd_raw(dev, kbd_last_scan_code); break; case 0xff: /* reset */ -#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: kbd reset\n"); -#endif - key_queue_start = key_queue_end = 0; /*Clear key queue*/ - add_data_kbd(0xfa); + kbc_queue_reset(1); + kbd_last_scan_code = 0x00; + add_data_kbd_direct(dev, 0xfa); /* Set scan code set to 2. */ keyboard_mode = (keyboard_mode & 0xfc) | 0x02; @@ -2004,7 +2033,7 @@ do_command: default: kbd_log("ATkbd: bad keyboard command %02X\n", val); - add_data_kbd(0xfe); + add_data_kbd_direct(dev, 0xfe); } /* If command needs data, remember command. */ @@ -2014,27 +2043,10 @@ do_command: } break; - case 0x61: - ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - - if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) -#ifdef USE_NEW_STUFF - dev->write_func(dev->func_priv, !!(val & 0x04)); -#else - xi8088_turbo_set(!!(val & 0x04)); -#endif - break; - case 0x64: /* Controller command. */ dev->want60 = 0; + dev->status |= STAT_CD; switch (val) { /* Read data from KBC memory. */ @@ -2062,42 +2074,35 @@ do_command: break; case 0xaa: /* self-test */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: self-test\n"); -#endif - if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) + kbd_log("ATkbc: self-test\n"); + if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) dev->status |= STAT_IFULL; - if (! dev->initialized) { -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: self-test reinitialization\n"); -#endif - dev->initialized = 1; - key_ctrl_queue_start = key_ctrl_queue_end = 0; - dev->status &= ~STAT_OFULL; - dev->last_irq = 0; - dev->out_new = dev->out_delayed = -1; - } - dev->status |= STAT_SYSFLAG; - dev->mem[0] |= 0x04; - keyboard_mode |= 0x04; - set_enable_kbd(dev, 1); + write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0x00; + dev->status &= ~STAT_OFULL; + dev->last_irq = dev->old_last_irq = 0; + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - set_enable_mouse(dev, 1); - write_output(dev, 0xcf); + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); add_data(dev, 0x55); break; case 0xab: /* interface test */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: interface test\n"); -#endif + kbd_log("ATkbc: interface test\n"); add_data(dev, 0x00); /*no error*/ break; case 0xac: /* diagnostic dump */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: diagnostic dump\n"); -#endif + kbd_log("ATkbc: diagnostic dump\n"); for (i = 0; i < 16; i++) add_data(dev, dev->mem[i]); add_data(dev, (dev->input_port & 0xf0) | 0x80); @@ -2106,83 +2111,51 @@ do_command: break; case 0xad: /* disable keyboard */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: disable keyboard\n"); -#endif + kbd_log("ATkbc: disable keyboard\n"); set_enable_kbd(dev, 0); break; case 0xae: /* enable keyboard */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: enable keyboard\n"); -#endif + kbd_log("ATkbc: enable keyboard\n"); set_enable_kbd(dev, 1); break; case 0xca: /* read keyboard mode */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - read keyboard mode\n"); -#endif - add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + add_data(dev, dev->ami_flags); break; case 0xcb: /* set keyboard mode */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: AMI - set keyboard mode\n"); -#endif + kbd_log("ATkbc: AMI - set keyboard mode\n"); dev->want60 = 1; break; case 0xd0: /* read output port */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: read output port\n"); -#endif + kbd_log("ATkbc: read output port\n"); mask = 0xff; - if (!keyboard_scan) + if ((kbc_ven != KBC_VEN_OLIVETTI) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) mask &= 0xbf; - if (!mouse_scan && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - mask &= 0xf7; - add_data(dev, dev->output_port & mask); + add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); break; case 0xd1: /* write output port */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write output port\n"); -#endif + kbd_log("ATkbc: write output port\n"); dev->want60 = 1; break; case 0xd2: /* write keyboard output buffer */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: write keyboard output buffer\n"); -#endif + kbd_log("ATkbc: write keyboard output buffer\n"); dev->want60 = 1; break; -#if 0 - case 0xd4: /* dunno, but OS/2 2.00LA sends it */ - dev->want60 = 1; - break; -#endif - case 0xdd: /* disable A20 address line */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: disable A20\n"); -#endif - write_output(dev, dev->output_port & 0xfd); - break; - case 0xdf: /* enable A20 address line */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: enable A20\n"); -#endif - write_output(dev, dev->output_port | 0x02); + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); break; case 0xe0: /* read test inputs */ -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: read test inputs\n"); -#endif + kbd_log("ATkbc: read test inputs\n"); add_data(dev, 0x00); break; @@ -2197,10 +2170,7 @@ do_command: if (dev->write64_ven) bad = dev->write64_ven(dev, val); -#ifdef ENABLE_KEYBOARD_AT_LOG - if (bad) - kbd_log("ATkbd: bad controller command %02X\n", val); -#endif + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); } /* If the command needs data, remember the command. */ @@ -2216,117 +2186,88 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - sub_cycles(ISA_CYCLES(8)); - - if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; + cycles -= ISA_CYCLES(8); switch (port) { case 0x60: - ret = dev->out; - dev->status &= ~(STAT_OFULL); - if (dev->last_irq) { - picintc(dev->last_irq); - dev->last_irq = 0; - } - break; - - case 0x61: - ret = ppi.pb & ~0xe0; - if (ppispeakon) - ret |= 0x20; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { - if (dev->refresh) - ret |= 0x10; - else - ret &= ~0x10; - } - if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) { -#ifdef USE_NEW_STUFF - if (dev->read_func(dev->func_priv)) -#else - if (xi8088_turbo_get()) -#endif - ret |= 0x04; - else - ret &= ~0x04; - } + ret = dev->out; + dev->status &= ~STAT_OFULL; + picintc(dev->last_irq); + dev->last_irq = 0; break; case 0x64: - // ret = (dev->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); - // ret |= STAT_UNLOCKED; - ret = (dev->status & 0xFB); + ret = (dev->status & 0xfb); if (dev->mem[0] & STAT_SYSFLAG) ret |= STAT_SYSFLAG; - /* The transmit timeout (TTIMEOUT) flag should *NOT* be cleared, otherwise - the IBM PS/2 Model 80's BIOS gives error 8601 (mouse error). */ - dev->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + /* Only clear the transmit timeout flag on non-PS/2 controllers, as on + PS/2 controller, it is the keyboard/mouse output source bit. */ + // dev->status &= ~STAT_RTIMEOUT; + if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && + (kbc_ven != KBC_VEN_IBM_MCA)) + dev->status &= ~STAT_TTIMEOUT; break; default: - kbd_log("ATkbd: read(%04x) invalid!\n", port); + kbd_log("ATkbc: read(%04x) invalid!\n", port); break; } -#ifdef ENABLE_KEYBOARD_AT_LOG - if (port != 0x61) - kbd_log("ATkbd: read(%04X) = %02X\n", port, ret); -#endif + kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); return(ret); } -static void -kbd_refresh(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - dev->refresh = !dev->refresh; - timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); -} - - static void kbd_reset(void *priv) { atkbd_t *dev = (atkbd_t *)priv; + int i; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - dev->initialized = 0; dev->first_write = 1; - dev->status = STAT_UNLOCKED | STAT_CD; + // dev->status = STAT_UNLOCKED | STAT_CD; + dev->status = STAT_UNLOCKED; dev->mem[0] = 0x01; - // if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) - dev->mem[0] |= CCB_TRANSLATE; + dev->mem[0] |= CCB_TRANSLATE; dev->wantirq = 0; write_output(dev, 0xcf); - dev->out_new = -1; - dev->out_delayed = -1; - dev->last_irq = 0; + dev->last_irq = dev->old_last_irq = 0; dev->secr_phase = 0; dev->key_wantdata = 0; /* Set up the correct Video Type bits. */ - if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) || ((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER)) - dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; else - dev->input_port = video_is_mda() ? 0xf0 : 0xb0; - kbd_log("ATkbd: input port = %02x\n", dev->input_port); + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbc: input port = %02x\n", dev->input_port); keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); + keyboard_scan = 1; set_enable_mouse(dev, 0); + mouse_scan = 0; + + dev->out_new = dev->out_delayed = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(i); + kbd_last_scan_code = 0; sc_or = 0; memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); + + dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; } @@ -2348,7 +2289,6 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); - timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2374,15 +2314,11 @@ kbd_init(const device_t *info) video_reset(gfxcard); kbd_reset(dev); - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; - timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) - timer_add(&dev->refresh_time, kbd_refresh, dev, 1); - + timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -2391,13 +2327,20 @@ kbd_init(const device_t *info) switch(dev->flags & KBC_VEN_MASK) { case KBC_VEN_ACER: case KBC_VEN_GENERIC: + case KBC_VEN_NCR: case KBC_VEN_IBM_PS1: case KBC_VEN_XI8088: dev->write64_ven = write64_generic; break; + case KBC_VEN_OLIVETTI: + dev->write64_ven = write64_olivetti; + break; + case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: + case KBC_VEN_SAMSUNG: + case KBC_VEN_ALI: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2423,158 +2366,300 @@ kbd_init(const device_t *info) return(dev); } - const device_t keyboard_at_device = { - "PC/AT Keyboard", - 0, - KBC_TYPE_ISA | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PC/AT Keyboard", + .internal_name = "keyboard_at", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_at_ami_device = { - "PC/AT Keyboard (AMI)", - 0, - KBC_TYPE_ISA | KBC_VEN_AMI, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PC/AT Keyboard (AMI)", + .internal_name = "keyboard_at_ami", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_samsung_device = { + .name = "PC/AT Keyboard (Samsung)", + .internal_name = "keyboard_at_samsung", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_SAMSUNG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_at_toshiba_device = { - "PC/AT Keyboard (Toshiba)", - 0, - KBC_TYPE_ISA | KBC_VEN_TOSHIBA, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PC/AT Keyboard (Toshiba)", + .internal_name = "keyboard_at_toshiba", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_olivetti_device = { + .name = "PC/AT Keyboard (Olivetti)", + .internal_name = "keyboard_at_olivetti", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_OLIVETTI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_ncr_device = { + .name = "PC/AT Keyboard (NCR)", + .internal_name = "keyboard_at_ncr", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_NCR, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_ps2", + .flags = 0, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_ps1_device = { - "PS/2 Keyboard (IBM PS/1)", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard (IBM PS/1)", + .internal_name = "keyboard_ps2_ps1", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ps1_pci_device = { + .name = "PS/2 Keyboard (IBM PS/1)", + .internal_name = "keyboard_ps2_ps1_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_xi8088_device = { - "PS/2 Keyboard (Xi8088)", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_XI8088, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard (Xi8088)", + .internal_name = "keyboard_ps2_xi8088", + .flags = 0, + .local = KBC_TYPE_PS2_1 | KBC_VEN_XI8088, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_ami_device = { - "PS/2 Keyboard (AMI)", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard (AMI)", + .internal_name = "keyboard_ps2_ami", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_olivetti_device = { + .name = "PS/2 Keyboard (Olivetti)", + .internal_name = "keyboard_ps2_olivetti", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_mca_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_mca", + .flags = 0, + .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_mca_2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_mca_2", + .flags = 0, + .local = KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_quadtel_device = { - "PS/2 Keyboard (Quadtel/MegaPC)", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL, NULL + .name = "PS/2 Keyboard (Quadtel/MegaPC)", + .internal_name = "keyboard_ps2_quadtel", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_pci_device = { - "PS/2 Keyboard", - DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_ami_pci_device = { - "PS/2 Keyboard (AMI)", - DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .name = "PS/2 Keyboard (AMI)", + .internal_name = "keyboard_ps2_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ali_pci_device = { + .name = "PS/2 Keyboard (ALi M5123/M1543C)", + .internal_name = "keyboard_ps2_ali_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ALI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_intel_ami_pci_device = { - "PS/2 Keyboard (AMI)", - DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .name = "PS/2 Keyboard (AMI)", + .internal_name = "keyboard_ps2_intel_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t keyboard_ps2_acer_pci_device = { - "PS/2 Keyboard (Acer 90M002A)", - DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .name = "PS/2 Keyboard (Acer 90M002A)", + .internal_name = "keyboard_ps2_acer_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { @@ -2586,31 +2671,33 @@ keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) void keyboard_at_adddata_keyboard_raw(uint8_t val) { - key_queue[key_queue_end] = val; - key_queue_end = (key_queue_end + 1) & 0xf; + atkbd_t *dev = SavedKbd; + + add_data_kbd_queue(dev, 0, val); } void keyboard_at_adddata_mouse(uint8_t val) { - mouse_queue[mouse_queue_end] = val; - mouse_queue_end = (mouse_queue_end + 1) & 0xf; + atkbd_t *dev = SavedKbd; + + kbc_queue_add(dev, val, 2, 0x00); } -#ifdef USE_NEW_STUFF -/* Set custom machine-dependent keyboard stuff. */ void -keyboard_at_set_funcs(void *arg, uint8_t (*readfunc)(void *), void (*writefunc)(void *, uint8_t), void *priv) +keyboard_at_mouse_reset(void) { - atkbd_t *dev = (atkbd_t *)arg; - - dev->read_func = readfunc; - dev->write_func = writefunc; - dev->func_priv = priv; + kbc_queue_reset(2); +} + + +uint8_t +keyboard_at_mouse_pos(void) +{ + return ((mouse_queue_end - mouse_queue_start) & 0xf); } -#endif void @@ -2619,20 +2706,21 @@ keyboard_at_set_mouse_scan(uint8_t val) atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == mouse_scan) return; + if (temp_mouse_scan == !(dev->mem[0] & 0x20)) + return; set_enable_mouse(dev, val ? 1 : 0); -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); -#endif + kbd_log("ATkbc: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); } uint8_t keyboard_at_get_mouse_scan(void) { - return(mouse_scan ? 0x10 : 0x00); + atkbd_t *dev = SavedKbd; + + return((dev->mem[0] & 0x20) ? 0x00 : 0x10); } diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index 0ca9fa9e9..d13bab56d 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -13,15 +13,19 @@ * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, + * EngiNerd, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van kempen. + * Copyright 2020 EngiNerd. */ #include #include #include #include +#include +#define HAVE_STDARG_H #include #include <86box/86box.h> #include <86box/device.h> @@ -29,6 +33,7 @@ #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> @@ -50,9 +55,20 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 +// Keyboard Types +#define KBD_TYPE_PC81 0 +#define KBD_TYPE_PC82 1 +#define KBD_TYPE_XT82 2 +#define KBD_TYPE_XT86 3 +#define KBD_TYPE_COMPAQ 4 +#define KBD_TYPE_TANDY 5 +#define KBD_TYPE_TOSHIBA 6 +#define KBD_TYPE_VTECH 7 +#define KBD_TYPE_OLIVETTI 8 +#define KBD_TYPE_ZENITH 9 typedef struct { - int want_irq; + int want_irq; int blocked; int tandy; @@ -328,7 +344,8 @@ const scancode scancode_xt[512] = { static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; -static int is_t1x00 = 0; +static int is_tandy = 0, is_t1x00 = 0, + is_amstrad = 0; #ifdef ENABLE_KEYBOARD_XT_LOG @@ -350,6 +367,32 @@ kbd_log(const char *fmt, ...) #define kbd_log(fmt, ...) #endif +static uint8_t +get_fdd_switch_settings() { + + int i, fdd_count = 0; + + for (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() { + + 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) @@ -358,7 +401,7 @@ kbd_poll(void *priv) timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC); - if (!(kbd->pb & 0x40) && (kbd->type != 5)) + if (!(kbd->pb & 0x40) && (kbd->type != KBD_TYPE_TANDY)) return; if (kbd->want_irq) { @@ -367,11 +410,11 @@ kbd_poll(void *priv) kbd->blocked = 1; picint(2); #ifdef ENABLE_KEYBOARD_XT_LOG - kbd_log("keyboard_xt : take IRQ\n"); + kbd_log("kbd_poll(): keyboard_xt : take IRQ\n"); #endif } - if (key_queue_start != key_queue_end && !kbd->blocked) { + 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); @@ -424,41 +467,30 @@ kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) return; keyboard_get_states(NULL, &num_lock, NULL); - shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + 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 (num_lock) { - if (!shift_states) { - /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ - adddata(0x2a); - } - } else { - if (shift_states & STATE_LSHIFT) { - /* Num lock off and left shift pressed. */ - adddata(0xaa); - } - if (shift_states & STATE_RSHIFT) { - /* Num lock off and right shift pressed. */ - adddata(0xb6); - } + /* 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 (num_lock) { - if (!shift_states) { - /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ - adddata(0xaa); - } - } else { - if (shift_states & STATE_LSHIFT) { - /* Num lock off and left shift pressed. */ - adddata(0x2a); - } - if (shift_states & STATE_RSHIFT) { - /* Num lock off and right shift pressed. */ - adddata(0x36); - } + if (shift_states) { + /* Send fake shift. */ + adddata(num_lock ? 0xaa : 0x2a); } break; default: @@ -481,7 +513,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) xtkbd_t *kbd = (xtkbd_t *)priv; switch (port) { - case 0x61: + case 0x61: /* Keyboard Control Register (aka Port B) */ if (!(kbd->pb & 0x40) && (val & 0x40)) { key_queue_start = key_queue_end = 0; kbd->want_irq = 0; @@ -491,16 +523,19 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd->pb = val; ppi.pb = val; + timer_process(); + + if (((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) && (cassette != NULL)) + pc_cas_set_motor(cassette, (kbd->pb & 0x08) == 0); + speaker_update(); - if ((kbd->type <= 1) && !(kbd->pb & 0x08)) - speaker_gated = speaker_enable = 1; - else { - speaker_gated = val & 1; - speaker_enable = val & 2; - } - if (speaker_enable) + + speaker_gated = val & 1; + speaker_enable = val & 2; + + if (speaker_enable) was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); + pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1); if (val & 0x80) { kbd->pa = 0; @@ -509,14 +544,14 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } #ifdef ENABLE_KEYBOARD_XT_LOG - if (kbd->type <= 1) - kbd_log("Casette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) + kbd_log("Cassette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); #endif break; #ifdef ENABLE_KEYBOARD_XT_LOG - case 0x62: - if (kbd->type <= 1) - kbd_log("Casette IN is %i\n", !!(val & 0x10)); + case 0x62: /* Switch Register (aka Port C) */ + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) + kbd_log("Cassette IN is %i\n", !!(val & 0x10)); break; #endif } @@ -530,35 +565,72 @@ kbd_read(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port) { - case 0x60: - if ((kbd->type <= 1) && (kbd->pb & 0x80)) - ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); - else if (((kbd->type == 2) || (kbd->type == 3)) && (kbd->pb & 0x80)) - ret = 0xff; /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ - else + 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_XT82) || (kbd->type == KBD_TYPE_XT86) + || (kbd->type == KBD_TYPE_ZENITH))) { + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) + ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); + else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86)) + ret = 0xff; /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ + 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: + case 0x61: /* Keyboard Control Register (aka Port B) */ ret = kbd->pb; break; - case 0x62: - if (kbd->type == 0) - ret = 0x00; - else if (kbd->type == 1) { - if (kbd->pb & 0x04) - ret = ((mem_size-64) / 32) & 0x0f; + case 0x62: /* Switch Register (aka Port C) */ + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) { + 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-64) / 32) >> 4; + 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) + if (kbd->pb & 0x08) /* PB3 */ ret = kbd->pd >> 4; else { /* LaserXT = Always 512k RAM; LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ #if defined(DEV_BRANCH) && defined(USE_LASERXT) - if (kbd->type == 6) + if (kbd->type == KBD_TYPE_TOSHIBA) ret = ((mem_size == 512) ? 0x0d : 0x0c) | (hasfpu ? 0x02 : 0x00); else #endif @@ -569,15 +641,21 @@ kbd_read(uint16_t port, void *priv) /* 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 <= 1) - ret |= (ppispeakon ? 0x10 : 0); + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82)) { + if (cassette == NULL) + ret |= (ppispeakon ? 0x10 : 0); + else + ret |= (pc_cas_get_inp(cassette) ? 0x10 : 0); + } - if (kbd->type == 5) + if (kbd->type == KBD_TYPE_TANDY) ret |= (tandy1k_eeprom_read() ? 0x10 : 0); break; - case 0x63: - if ((kbd->type == 2) || (kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) + case 0x63: /* Keyboard Configuration Register (aka Port D) */ + if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) + || (kbd->type == KBD_TYPE_COMPAQ) + || (kbd->type == KBD_TYPE_TOSHIBA)) ret = kbd->pd; break; } @@ -603,11 +681,16 @@ kbd_reset(void *priv) } +void +keyboard_set_is_amstrad(int ams) +{ + is_amstrad = ams; +} + + static void * kbd_init(const device_t *info) { - int i, fdd_count = 0; - xtkbd_t *kbd; kbd = (xtkbd_t *)malloc(sizeof(xtkbd_t)); @@ -623,89 +706,147 @@ kbd_init(const device_t *info) video_reset(gfxcard); - if (kbd->type <= 3) { - for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; - } + if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) + || (kbd->type == KBD_TYPE_XT82) || (kbd->type <= KBD_TYPE_XT86) + || (kbd->type == KBD_TYPE_COMPAQ) + || (kbd->type == KBD_TYPE_TOSHIBA) + || (kbd->type == KBD_TYPE_OLIVETTI)) { - /* DIP switch readout: bit set = OFF, clear = ON. */ - /* Switches 7, 8 - floppy drives. */ - if (!fdd_count) - kbd->pd = 0x00; + /* 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 - kbd->pd = ((fdd_count - 1) << 6) | 0x01; - /* Switches 5, 6 - video. */ - if (video_is_mda()) - kbd->pd |= 0x30; - else if (video_is_cga()) - kbd->pd |= 0x20; /* 0x10 would be 40x25 */ - else - kbd->pd |= 0x00; - /* Switches 3, 4 - memory size. */ - if ((kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) { - 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 >= 1) { - switch (mem_size) { - case 64: - kbd->pd |= 0x00; - break; - case 128: - kbd->pd |= 0x04; - break; - case 192: - kbd->pd |= 0x08; - break; - case 256: - default: - kbd->pd |= 0x0c; - break; - } - } else { - switch (mem_size) { - case 16: - kbd->pd |= 0x00; - break; - case 32: - kbd->pd |= 0x04; - break; - case 48: - kbd->pd |= 0x08; - break; - case 64: - default: - kbd->pd |= 0x0c; - break; - } - } + /* Switches 7, 8 - floppy drives. */ + kbd->pd = get_fdd_switch_settings(); - /* Switch 2 - 8087 FPU. */ - if (hasfpu) - kbd->pd |= 0x02; + /* Siitches 5, 6 - video card type */ + kbd->pd |= get_videomode_switch_settings(); - /* Switch 1 - always off. */ - kbd->pd |= 0x01; + /* Switches 3, 4 - memory size. */ + if ((kbd->type == KBD_TYPE_XT86) + || (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) { + 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) { + case 192: /* 3x64k, not supported by stock BIOS due to bugs */ + kbd->pd |= 0x08; + break; + 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_t1x00 = (kbd->type == 6); + is_tandy = (kbd->type == KBD_TYPE_TANDY); + is_t1x00 = (kbd->type == KBD_TYPE_TOSHIBA); + + is_amstrad = 0; return(kbd); } @@ -730,85 +871,144 @@ kbd_close(void *priv) free(kbd); } - const device_t keyboard_pc_device = { - "IBM PC Keyboard (1981)", - 0, - 0, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .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 }; const device_t keyboard_pc82_device = { - "IBM PC Keyboard (1982)", - 0, - 1, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .name = "IBM PC Keyboard (1982)", + .internal_name = "keyboard_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 keyboard_xt_device = { - "XT (1982) Keyboard", - 0, - 2, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .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 = { - "XT (1986) Keyboard", - 0, - 3, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .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 = { - "Compaq Portable Keyboard", - 0, - 4, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .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 = { - "Tandy 1000 Keyboard", - 0, - 5, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .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 = { - "Toshiba T1x00 Keyboard", - 0, - 6, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .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 }; #if defined(DEV_BRANCH) && defined(USE_LASERXT) const device_t keyboard_xt_lxt3_device = { - "VTech Laser XT3 Keyboard", - 0, - 7, - kbd_init, - kbd_close, - kbd_reset, - NULL, NULL, NULL + .name = "VTech Laser XT3 Keyboard", + .internal_name = "keyboard_xt_lxt3", + .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 + +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 +}; diff --git a/src/device/mouse.c b/src/device/mouse.c index 7eb3cd8f0..4fc9b5378 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -31,7 +31,6 @@ typedef struct { - const char *internal_name; const device_t *device; } mouse_t; @@ -42,36 +41,49 @@ int mouse_x, mouse_z, mouse_buttons; - static const device_t mouse_none_device = { - "None", - 0, MOUSE_TYPE_NONE, - NULL, NULL, NULL, - NULL, NULL, NULL, - NULL -}; -static const device_t mouse_internal_device = { - "Internal Mouse", - 0, MOUSE_TYPE_INTERNAL, - NULL, NULL, NULL, - NULL, NULL, NULL, - NULL + .name = "None", + .internal_name = "none", + .flags = 0, + .local = MOUSE_TYPE_NONE, + .init = NULL, + .close = NULL, + .reset = NULL, + { .poll = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +static const device_t mouse_internal_device = { + .name = "Internal", + .internal_name = "internal", + .flags = 0, + .local = MOUSE_TYPE_INTERNAL, + .init = NULL, + .close = NULL, + .reset = NULL, + { .poll = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; static mouse_t mouse_devices[] = { - { "none", &mouse_none_device }, - { "internal", &mouse_internal_device }, - { "logibus", &mouse_logibus_device }, - { "msbus", &mouse_msinport_device }, +// clang-format off + { &mouse_none_device }, + { &mouse_internal_device }, + { &mouse_logibus_device }, + { &mouse_msinport_device }, #if 0 - { "genibus", &mouse_genibus_device }, + { &mouse_genibus_device }, #endif - { "mssystems", &mouse_mssystems_device }, - { "msserial", &mouse_msserial_device }, - { "ltserial", &mouse_ltserial_device }, - { "ps2", &mouse_ps2_device }, - { NULL, NULL } + { &mouse_mssystems_device }, + { &mouse_msserial_device }, + { &mouse_ltserial_device }, + { &mouse_ps2_device }, + { NULL } +// clang-format on }; @@ -172,9 +184,9 @@ mouse_process(void) mouse_poll(); - if ((mouse_dev_poll != NULL) || (mouse_curr->available != NULL)) { - if (mouse_curr->available != NULL) - mouse_curr->available(mouse_x,mouse_y,mouse_z,mouse_buttons, mouse_priv); + if ((mouse_dev_poll != NULL) || (mouse_curr->poll != NULL)) { + if (mouse_curr->poll != NULL) + mouse_curr->poll(mouse_x,mouse_y,mouse_z,mouse_buttons, mouse_priv); else mouse_dev_poll(mouse_x,mouse_y,mouse_z,mouse_buttons, mouse_priv); @@ -206,7 +218,7 @@ mouse_get_name(int mouse) char * mouse_get_internal_name(int mouse) { - return((char *)mouse_devices[mouse].internal_name); + return device_get_internal_name(mouse_devices[mouse].device); } @@ -215,8 +227,8 @@ mouse_get_from_internal_name(char *s) { int c = 0; - while (mouse_devices[c].internal_name != NULL) { - if (! strcmp((char *)mouse_devices[c].internal_name, s)) + while (mouse_devices[c].device != NULL) { + if (! strcmp((char *)mouse_devices[c].device->internal_name, s)) return(c); c++; } diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index c2b4afad7..2a098a22b 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -693,166 +693,164 @@ bm_init(const device_t *info) return dev; } - static const device_config_t lt_config[] = { +// clang-format off { - "base", "Address", CONFIG_HEX16, "", 0x23c, - { - { - "0x230", 0x230 - }, - { - "0x234", 0x234 - }, - { - "0x238", 0x238 - }, - { - "0x23C", 0x23c - }, - { - "" - } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x23c, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x230", .value = 0x230 }, + { .description = "0x234", .value = 0x234 }, + { .description = "0x238", .value = 0x238 }, + { .description = "0x23C", .value = 0x23c }, + { .description = "" } + } }, { - "irq", "IRQ", CONFIG_SELECTION, "", 5, { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "" - } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } }, { - "hz", "Hz", CONFIG_SELECTION, "", 45, { - { - "Non-timed (original)", 0 - }, - { - "30 Hz (JMP2 = 1)", 30 - }, - { - "45 Hz (JMP2 not populated)", 45 - }, - { - "60 Hz (JMP 2 = 2)", 60 - }, - { - "" - } - } + .name = "hz", + .description = "Hz", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 45, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Non-timed (original)", .value = 0 }, + { .description = "30 Hz (JMP2 = 1)", .value = 30 }, + { .description = "45 Hz (JMP2 not populated)", .value = 45 }, + { .description = "60 Hz (JMP 2 = 2)", .value = 60 }, + { .description = "" } + } }, { - "buttons", "Buttons", CONFIG_SELECTION, "", 2, { - { - "Two", 2 - }, - { - "Three", 3 - }, - { - "" - } - } + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; - static const device_config_t ms_config[] = { +// clang-format off { - "base", "Address", CONFIG_HEX16, "", 0x23c, - { - { - "0x230", 0x230 - }, - { - "0x234", 0x234 - }, - { - "0x238", 0x238 - }, - { - "0x23C", 0x23c - }, - { - "" - } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x23c, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x230", .value = 0x230 }, + { .description = "0x234", .value = 0x234 }, + { .description = "0x238", .value = 0x238 }, + { .description = "0x23C", .value = 0x23c }, + { .description = "" } + } }, { - "irq", "IRQ", CONFIG_SELECTION, "", 5, { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "" - } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } }, { - "buttons", "Buttons", CONFIG_SELECTION, "", 2, { - { - "Two", 2 - }, - { - "Three", 3 - }, - { - "" - } - } + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; - const device_t mouse_logibus_device = { - "Logitech/Microsoft Bus Mouse", - DEVICE_ISA, - MOUSE_TYPE_LOGIBUS, - bm_init, bm_close, NULL, - bm_poll, NULL, NULL, - lt_config + .name = "Logitech/Microsoft Bus Mouse", + .internal_name = "logibus", + .flags = DEVICE_ISA, + .local = MOUSE_TYPE_LOGIBUS, + .init = bm_init, + .close = bm_close, + .reset = NULL, + { .poll = bm_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = lt_config }; const device_t mouse_logibus_onboard_device = { - "Logitech Bus Mouse (On-Board)", - DEVICE_ISA, - MOUSE_TYPE_LOGIBUS | MOUSE_TYPE_ONBOARD, - bm_init, bm_close, NULL, - bm_poll, NULL, NULL + .name = "Logitech Bus Mouse (On-Board)", + .internal_name = "logibus_onboard", + .flags = DEVICE_ISA, + .local = MOUSE_TYPE_LOGIBUS | MOUSE_TYPE_ONBOARD, + .init = bm_init, + .close = bm_close, + .reset = NULL, + { .poll = bm_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t mouse_msinport_device = { - "Microsoft Bus Mouse (InPort)", - DEVICE_ISA, - MOUSE_TYPE_INPORT, - bm_init, bm_close, NULL, - bm_poll, NULL, NULL, - ms_config + .name = "Microsoft Bus Mouse (InPort)", + .internal_name = "msbus", + .flags = DEVICE_ISA, + .local = MOUSE_TYPE_INPORT, + .init = bm_init, + .close = bm_close, + .reset = NULL, + { .poll = bm_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ms_config }; diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 70f60c568..cd4225e11 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -96,6 +96,9 @@ ps2_write(uint8_t val, void *priv) if (dev->flags & FLAG_CTRLDAT) { dev->flags &= ~FLAG_CTRLDAT; + if (val == 0xff) + goto mouse_reset; + switch (dev->command) { case 0xe8: /* set mouse resolution */ dev->resolution = val; @@ -179,21 +182,28 @@ ps2_write(uint8_t val, void *priv) case 0xf4: /* enable */ dev->flags |= FLAG_ENABLED; + mouse_scan = 1; keyboard_at_adddata_mouse(0xfa); break; case 0xf5: /* disable */ dev->flags &= ~FLAG_ENABLED; + mouse_scan = 0; keyboard_at_adddata_mouse(0xfa); break; + case 0xf6: /* set defaults */ case 0xff: /* reset */ +mouse_reset: dev->mode = MODE_STREAM; dev->flags &= 0x88; - mouse_queue_start = mouse_queue_end = 0; + mouse_scan = 1; + keyboard_at_mouse_reset(); keyboard_at_adddata_mouse(0xfa); - keyboard_at_adddata_mouse(0xaa); - keyboard_at_adddata_mouse(0x00); + if (dev->command == 0xff) { + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); + } break; default: @@ -202,7 +212,7 @@ ps2_write(uint8_t val, void *priv) } if (dev->flags & FLAG_INTELLI) { - for (temp = 0; temp < 5; temp++) + for (temp = 0; temp < 5; temp++) dev->last_data[temp] = dev->last_data[temp + 1]; dev->last_data[5] = val; @@ -236,7 +246,7 @@ ps2_poll(int x, int y, int z, int b, void *priv) dev->y -= y; dev->z -= z; if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && - (((mouse_queue_end - mouse_queue_start) & 0x0f) < 13)) { + (keyboard_at_mouse_pos() < 13)) { dev->b = b; if (dev->x > 255) dev->x = 255; @@ -319,35 +329,39 @@ ps2_close(void *priv) free(dev); } - static const device_config_t ps2_config[] = { +// clang-format off { - "buttons", "Buttons", CONFIG_SELECTION, "", 2, { - { - "Two", 2 - }, - { - "Three", 3 - }, - { - "Wheel", 4 - }, - { - "" - } - } + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "Wheel", .value = 4 }, + { .description = "" } + } }, { - "", "", -1 + .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; - const device_t mouse_ps2_device = { - "Standard PS/2 Mouse", - DEVICE_PS2, - MOUSE_TYPE_PS2, - mouse_ps2_init, ps2_close, NULL, - ps2_poll, NULL, NULL, - ps2_config + .name = "Standard PS/2 Mouse", + .internal_name = "ps2", + .flags = DEVICE_PS2, + .local = MOUSE_TYPE_PS2, + .init = mouse_ps2_init, + .close = ps2_close, + .reset = NULL, + { .poll = ps2_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ps2_config }; diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index b89595f28..68b570565 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -173,9 +173,8 @@ sermouse_callback(struct serial_s *serial, void *priv) dev->format = 7; dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); timer_stop(&dev->command_timer); - sub_cycles(ISA_CYCLES(8)); #ifdef USE_NEW_DYNAREC - sermouse_timer_on(dev, 5000.0, 0); + sermouse_timer_on(dev, cpu_use_dynarec ? 5000.0 : dev->transmit_period, 0); #else sermouse_timer_on(dev, dev->transmit_period, 0); #endif @@ -725,7 +724,7 @@ sermouse_speed_changed(void *priv) if (dev->report_enabled) { timer_stop(&dev->report_timer); - if (dev->report_phase == REPORT_PHASE_TRANSMIT) + if (dev->report_phase == REPORT_PHASE_TRANSMIT) sermouse_timer_on(dev, dev->transmit_period, 1); else sermouse_timer_on(dev, sermouse_report_period(dev), 1); @@ -829,99 +828,117 @@ sermouse_init(const device_t *info) return(dev); } - static const device_config_t mssermouse_config[] = { +// clang-format off { - "port", "Serial Port", CONFIG_SELECTION, "", 0, { - { - "COM1", 0 - }, - { - "COM2", 1 - }, - { - "" - } - } + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "COM1", .value = 0 }, + { .description = "COM2", .value = 1 }, + { .description = "COM3", .value = 2 }, + { .description = "COM4", .value = 3 }, + { .description = "" } + } }, { - "buttons", "Buttons", CONFIG_SELECTION, "", 2, { - { - "Two", 2 - }, - { - "Three", 3 - }, - { - "Wheel", 4 - }, - { - "" - } - } + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "Wheel", .value = 4 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; - static const device_config_t ltsermouse_config[] = { +// clang-format off { - "port", "Serial Port", CONFIG_SELECTION, "", 0, { - { - "COM1", 0 - }, - { - "COM2", 1 - }, - { - "" - } - } + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "COM1", .value = 0 }, + { .description = "COM2", .value = 1 }, + { .description = "COM3", .value = 2 }, + { .description = "COM4", .value = 3 }, + { .description = "" } + } }, { - "buttons", "Buttons", CONFIG_SELECTION, "", 2, { - { - "Two", 2 - }, - { - "Three", 3 - }, - { - "" - } - } + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; - const device_t mouse_mssystems_device = { - "Mouse Systems Serial Mouse", - 0, - MOUSE_TYPE_MSYSTEMS, - sermouse_init, sermouse_close, NULL, - sermouse_poll, sermouse_speed_changed, NULL, - mssermouse_config + .name = "Mouse Systems Serial Mouse", + .internal_name = "mssystems", + .flags = DEVICE_COM, + .local = MOUSE_TYPE_MSYSTEMS, + .init = sermouse_init, + .close = sermouse_close, + .reset = NULL, + { .poll = sermouse_poll }, + .speed_changed = sermouse_speed_changed, + .force_redraw = NULL, + .config = mssermouse_config }; const device_t mouse_msserial_device = { - "Microsoft Serial Mouse", - 0, - 0, - sermouse_init, sermouse_close, NULL, - sermouse_poll, sermouse_speed_changed, NULL, - mssermouse_config + .name = "Microsoft Serial Mouse", + .internal_name = "msserial", + .flags = DEVICE_COM, + .local = 0, + .init = sermouse_init, + .close = sermouse_close, + .reset = NULL, + { .poll = sermouse_poll }, + .speed_changed = sermouse_speed_changed, + .force_redraw = NULL, + .config = mssermouse_config }; const device_t mouse_ltserial_device = { - "Logitech Serial Mouse", - 0, - 1, - sermouse_init, sermouse_close, NULL, - sermouse_poll, sermouse_speed_changed, NULL, - ltsermouse_config + .name = "Logitech Serial Mouse", + .internal_name = "ltserial", + .flags = DEVICE_COM, + .local = 1, + .init = sermouse_init, + .close = sermouse_close, + .reset = NULL, + { .poll = sermouse_poll }, + .speed_changed = sermouse_speed_changed, + .force_redraw = NULL, + .config = ltsermouse_config }; diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c new file mode 100644 index 000000000..583b77262 --- /dev/null +++ b/src/device/pci_bridge.c @@ -0,0 +1,642 @@ +/* + * 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 PCI-PCI and host-AGP bridges. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/machine.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/pci.h> + + +#define PCI_BRIDGE_DEC_21150 0x10110022 +#define AGP_BRIDGE_ALI_M5243 0x10b95243 +#define AGP_BRIDGE_ALI_M5247 0x10b95247 +#define AGP_BRIDGE_INTEL_440LX 0x80867181 +#define AGP_BRIDGE_INTEL_440BX 0x80867191 +#define AGP_BRIDGE_INTEL_440GX 0x808671a1 +#define AGP_BRIDGE_VIA_597 0x11068597 +#define AGP_BRIDGE_VIA_598 0x11068598 +#define AGP_BRIDGE_VIA_691 0x11068691 +#define AGP_BRIDGE_VIA_8601 0x11068601 + +#define AGP_BRIDGE_ALI(x) (((x) >> 16) == 0x10b9) +#define AGP_BRIDGE_INTEL(x) (((x) >> 16) == 0x8086) +#define AGP_BRIDGE_VIA(x) (((x) >> 16) == 0x1106) +#define AGP_BRIDGE(x) ((x) >= AGP_BRIDGE_ALI_M5243) + + +typedef struct +{ + uint32_t local; + uint8_t type, ctl; + + uint8_t regs[256]; + uint8_t bus_index; + int slot; +} pci_bridge_t; + + +#ifdef ENABLE_PCI_BRIDGE_LOG +int pci_bridge_do_log = ENABLE_PCI_BRIDGE_LOG; + + +static void +pci_bridge_log(const char *fmt, ...) +{ + va_list ap; + + if (pci_bridge_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pci_bridge_log(fmt, ...) +#endif + + +void +pci_bridge_set_ctl(void *priv, uint8_t ctl) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + dev->ctl = ctl; +} + + +static void +pci_bridge_write(int func, int addr, uint8_t val, void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + pci_bridge_log("PCI Bridge %d: write(%d, %02X, %02X)\n", dev->bus_index, func, addr, val); + + if (func > 0) + return; + + if ((dev->local == AGP_BRIDGE_ALI_M5247) && (addr >= 0x40)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x06: case 0x08: case 0x09: case 0x0a: + case 0x0b: case 0x0e: case 0x0f: case 0x10: + case 0x11: case 0x12: case 0x13: case 0x14: + case 0x15: case 0x16: case 0x17: case 0x1e: + case 0x34: case 0x3d: case 0x67: case 0xdc: + case 0xdd: case 0xde: case 0xdf: + return; + + case 0x04: + if (AGP_BRIDGE_INTEL(dev->local)) { + if (dev->local == AGP_BRIDGE_INTEL_440BX) + val &= 0x1f; + } else if (dev->local == AGP_BRIDGE_ALI_M5243) + val |= 0x02; + else if (dev->local == AGP_BRIDGE_ALI_M5247) + val &= 0xc3; + else + val &= 0x67; + break; + + case 0x05: + if (AGP_BRIDGE_INTEL(dev->local)) + val &= 0x01; + else if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x01; + else + val &= 0x03; + break; + + case 0x07: + if (dev->local == AGP_BRIDGE_INTEL_440LX) + dev->regs[addr] &= ~(val & 0x40); + else if (dev->local == AGP_BRIDGE_ALI_M5243) + dev->regs[addr] &= ~(val & 0xf8); + else if (dev->local == AGP_BRIDGE_ALI_M5247) + dev->regs[addr] &= ~(val & 0xc0); + return; + + case 0x0c: case 0x18: + /* Parent bus number (0x18) is always 0 on AGP bridges. */ + if (AGP_BRIDGE(dev->local)) + return; + break; + + case 0x0d: + if (AGP_BRIDGE_VIA(dev->local)) + return; + else if (AGP_BRIDGE_INTEL(dev->local)) + val &= 0xf8; + else if (AGP_BRIDGE_ALI(dev->local)) + val &= 0xf8; + break; + + case 0x19: + /* Set our bus number. */ + pci_bridge_log("PCI Bridge %d: remapping from bus %02X to %02X\n", dev->bus_index, dev->regs[addr], val); + pci_remap_bus(dev->bus_index, val); + break; + + case 0x1f: + if (AGP_BRIDGE_INTEL(dev->local)) { + if (dev->local == AGP_BRIDGE_INTEL_440LX) + dev->regs[addr] &= ~(val & 0xf1); + else if ((dev->local == AGP_BRIDGE_INTEL_440BX) || + (dev->local == AGP_BRIDGE_INTEL_440GX)) + dev->regs[addr] &= ~(val & 0xf0); + } else if (AGP_BRIDGE_ALI(dev->local)) + dev->regs[addr] &= ~(val & 0xf0); + return; + + case 0x1c: case 0x1d: case 0x20: case 0x22: + case 0x24: case 0x26: + val &= 0xf0; + break; + + case 0x3c: + if (!(dev->ctl & 0x80)) + return; + break; + + case 0x3e: + if (AGP_BRIDGE_VIA(dev->local)) + val &= 0x0c; + else if (dev->local == AGP_BRIDGE_ALI_M5247) + val &= 0x0f; + else if (dev->local == AGP_BRIDGE_ALI_M5243) + return; + else if (AGP_BRIDGE(dev->local)) { + if ((dev->local == AGP_BRIDGE_INTEL_440BX) || + (dev->local == AGP_BRIDGE_INTEL_440GX)) + val &= 0xed; + else + val &= 0x0f; + } + else if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0xef; + break; + + case 0x3f: + if (dev->local == AGP_BRIDGE_INTEL_440LX) { + dev->regs[addr] = ((dev->regs[addr] & 0x04) | (val & 0x02)) & ~(val & 0x04); + return; + } else if (dev->local == AGP_BRIDGE_ALI_M5247) + return; + else if (dev->local == AGP_BRIDGE_ALI_M5243) + val &= 0x06; + else if (AGP_BRIDGE(dev->local)) + return; + else if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0x0f; + break; + + case 0x40: + if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0x32; + break; + + case 0x41: + if (AGP_BRIDGE_VIA(dev->local)) + val &= 0x7e; + else if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0x07; + break; + + case 0x42: + if (AGP_BRIDGE_VIA(dev->local)) + val &= 0xfe; + break; + + case 0x43: + if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0x03; + break; + + case 0x64: + if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0x7e; + break; + + case 0x69: + if (dev->local == PCI_BRIDGE_DEC_21150) + val &= 0x3f; + break; + + case 0x86: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x3f; + break; + + case 0x87: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x60; + break; + + case 0x88: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x8c; + break; + + case 0x8b: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x0f; + break; + + case 0x8c: + if (AGP_BRIDGE_ALI(dev->local)) + val &= 0x83; + break; + + case 0x8d: + if (AGP_BRIDGE_ALI(dev->local)) + return; + break; + + case 0xe0: case 0xe1: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } else + return; + break; + + case 0xe2: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0x3f; + else + return; + } else + return; + break; + case 0xe3: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0xfe; + else + return; + } else + return; + break; + + case 0xe4: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0x03; + else + return; + } + break; + case 0xe5: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } + break; + + case 0xe6: + if (AGP_BRIDGE_ALI(dev->local)) { + if (dev->ctl & 0x20) + val &= 0xc0; + else + return; + } + break; + + case 0xe7: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +pci_bridge_read(int func, int addr, void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + uint8_t ret; + + if (func > 0) + ret = 0xff; + else + ret = dev->regs[addr]; + + pci_bridge_log("PCI Bridge %d: read(%d, %02X) = %02X\n", dev->bus_index, func, addr, ret); + return ret; +} + + +static void +pci_bridge_reset(void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + pci_bridge_log("PCI Bridge %d: reset()\n", dev->bus_index); + + memset(dev->regs, 0, sizeof(dev->regs)); + + /* IDs */ + dev->regs[0x00] = dev->local >> 16; + dev->regs[0x01] = dev->local >> 24; + dev->regs[0x02] = dev->local; + dev->regs[0x03] = dev->local >> 8; + + /* command and status */ + switch (dev->local) { + case PCI_BRIDGE_DEC_21150: + dev->regs[0x06] = 0x80; + dev->regs[0x07] = 0x02; + break; + + case AGP_BRIDGE_ALI_M5243: + dev->regs[0x04] = 0x06; + dev->regs[0x07] = 0x04; + dev->regs[0x0d] = 0x20; + dev->regs[0x19] = 0x01; + dev->regs[0x1b] = 0x20; + dev->regs[0x34] = 0xe0; + dev->regs[0x89] = 0x20; + dev->regs[0x8a] = 0xa0; + dev->regs[0x8e] = 0x20; + dev->regs[0x8f] = 0x20; + dev->regs[0xe0] = 0x01; + pci_remap_bus(dev->bus_index, 0x01); + break; + + case AGP_BRIDGE_ALI_M5247: + dev->regs[0x04] = 0x03; + dev->regs[0x08] = 0x01; + break; + + case AGP_BRIDGE_INTEL_440LX: + dev->regs[0x06] = 0xa0; + dev->regs[0x07] = 0x02; + dev->regs[0x08] = 0x03; + break; + + case AGP_BRIDGE_INTEL_440BX: + case AGP_BRIDGE_INTEL_440GX: + dev->regs[0x06] = 0x20; + dev->regs[0x07] = dev->regs[0x08] = 0x02; + break; + + case AGP_BRIDGE_VIA_597: + case AGP_BRIDGE_VIA_598: + case AGP_BRIDGE_VIA_691: + case AGP_BRIDGE_VIA_8601: + dev->regs[0x04] = 0x07; + dev->regs[0x06] = 0x20; + dev->regs[0x07] = 0x02; + break; + } + + /* class */ + dev->regs[0x0a] = 0x04; /* PCI-PCI bridge */ + dev->regs[0x0b] = 0x06; /* bridge device */ + dev->regs[0x0e] = 0x01; /* bridge header */ + + /* IO BARs */ + if (AGP_BRIDGE(dev->local)) + dev->regs[0x1c] = 0xf0; + else + dev->regs[0x1c] = dev->regs[0x1d] = 0x01; + + if (dev->local == AGP_BRIDGE_ALI_M5247) + dev->regs[0x1e] = 0x20; + else if (!AGP_BRIDGE_VIA(dev->local)) { + dev->regs[0x1e] = AGP_BRIDGE(dev->local) ? 0xa0 : 0x80; + dev->regs[0x1f] = 0x02; + } + + /* prefetchable memory limits */ + if (AGP_BRIDGE(dev->local)) { + dev->regs[0x20] = dev->regs[0x24] = 0xf0; + dev->regs[0x21] = dev->regs[0x25] = 0xff; + } else { + dev->regs[0x24] = dev->regs[0x26] = 0x01; + } + + /* power management */ + if (dev->local == PCI_BRIDGE_DEC_21150) { + dev->regs[0x34] = 0xdc; + dev->regs[0x43] = 0x02; + dev->regs[0xdc] = dev->regs[0xde] = 0x01; + } +} + + +static void * +pci_bridge_init(const device_t *info) +{ + uint8_t interrupts[4], interrupt_count, interrupt_mask, slot_count, i; + + pci_bridge_t *dev = (pci_bridge_t *) malloc(sizeof(pci_bridge_t)); + memset(dev, 0, sizeof(pci_bridge_t)); + + dev->local = info->local; + dev->bus_index = pci_register_bus(); + pci_bridge_log("PCI Bridge %d: init()\n", dev->bus_index); + + pci_bridge_reset(dev); + + dev->slot = pci_add_card(AGP_BRIDGE(dev->local) ? PCI_ADD_AGPBRIDGE : PCI_ADD_BRIDGE, pci_bridge_read, pci_bridge_write, dev); + + interrupt_count = sizeof(interrupts); + interrupt_mask = interrupt_count - 1; + if (dev->slot < 32) { + for (i = 0; i < interrupt_count; 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) + slot_count = 9; /* 9 bus masters */ + else + slot_count = 1; /* AGP bridges always have 1 slot */ + + for (i = 0; i < slot_count; i++) { + /* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */ + pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]); + pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, + interrupts[i & interrupt_mask], + interrupts[(i + 1) & interrupt_mask], + interrupts[(i + 2) & interrupt_mask], + interrupts[(i + 3) & interrupt_mask]); + } + + return dev; +} + +/* PCI bridges */ +const device_t dec21150_device = { + .name = "DEC 21150 PCI Bridge", + .internal_name = "dec21150", + .flags = DEVICE_PCI, + .local = PCI_BRIDGE_DEC_21150, + .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", + .internal_name = "ali5243_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_ALI_M5243, + .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 ali5247_agp_device = { + .name = "ALi M5247 AGP Bridge", + .internal_name = "ali5247_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_ALI_M5247, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i440lx_agp_device = { + .name = "Intel 82443LX/EX AGP Bridge", + .internal_name = "i440lx_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_INTEL_440LX, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i440bx_agp_device = { + .name = "Intel 82443BX/ZX AGP Bridge", + .internal_name = "i440bx_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_INTEL_440BX, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i440gx_agp_device = { + .name = "Intel 82443GX AGP Bridge", + .internal_name = "i440gx_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_INTEL_440GX, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vp3_agp_device = { + .name = "VIA Apollo VP3 AGP Bridge", + .internal_name = "via_vp3_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_VIA_597, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_mvp3_agp_device = { + .name = "VIA Apollo MVP3 AGP Bridge", + .internal_name = "via_mvp3_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_VIA_598, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_apro_agp_device = { + .name = "VIA Apollo Pro AGP Bridge", + .internal_name = "via_apro_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_VIA_691, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_vt8601_agp_device = { + .name = "VIA Apollo ProMedia AGP Bridge", + .internal_name = "via_vt8601_agp", + .flags = DEVICE_PCI, + .local = AGP_BRIDGE_VIA_8601, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/phoenix_486_jumper.c b/src/device/phoenix_486_jumper.c new file mode 100644 index 000000000..10f37c4ce --- /dev/null +++ b/src/device/phoenix_486_jumper.c @@ -0,0 +1,152 @@ +/* + * 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 Phoenix 486 Jumper Readout + * + * Copyright 2020 Tiseno100 + */ + + +#include +#include +#include +#include +#include +#include +#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/chipset.h> + +/* + Bit 7 = Super I/O chip: 1 = enabled, 0 = disabled; + Bit 6 = Graphics card: 1 = standalone, 0 = on-board; + Bit 5 = ???? (if 1, siren and hangs); + Bit 4 = ????; + Bit 3 = ????; + Bit 2 = ????; + Bit 1 = ????; + Bit 0 = ????. +*/ + +typedef struct +{ + uint8_t type, jumper; +} phoenix_486_jumper_t; + + +#ifdef ENABLE_PHOENIX_486_JUMPER_LOG +int phoenix_486_jumper_do_log = ENABLE_PHOENIX_486_JUMPER_LOG; + + +static void +phoenix_486_jumper_log(const char *fmt, ...) +{ + va_list ap; + + if (phoenix_486_jumper_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define phoenix_486_jumper_log(fmt, ...) +#endif + + +static void +phoenix_486_jumper_write(uint16_t addr, uint8_t val, void *priv) +{ + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) priv; + phoenix_486_jumper_log("Phoenix 486 Jumper: Write %02x\n", val); + if (dev->type == 1) + dev->jumper = val & 0xbf; + else + dev->jumper = val; +} + + +static uint8_t +phoenix_486_jumper_read(uint16_t addr, void *priv) +{ + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) priv; + phoenix_486_jumper_log("Phoenix 486 Jumper: Read %02x\n", dev->jumper); + return dev->jumper; +} + + +static void +phoenix_486_jumper_reset(void *priv) +{ + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) priv; + + if (dev->type == 1) + dev->jumper = 0x00; + else { + dev->jumper = 0x9f; + if (gfxcard != 0x01) + dev->jumper |= 0x40; + } +} + + +static void +phoenix_486_jumper_close(void *priv) +{ + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) priv; + + free(dev); +} + + +static void * +phoenix_486_jumper_init(const device_t *info) +{ + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) malloc(sizeof(phoenix_486_jumper_t)); + memset(dev, 0, sizeof(phoenix_486_jumper_t)); + + dev->type = info->local; + + phoenix_486_jumper_reset(dev); + + io_sethandler(0x0078, 0x0001, phoenix_486_jumper_read, NULL, NULL, phoenix_486_jumper_write, NULL, NULL, dev); + + return dev; +} + +const device_t phoenix_486_jumper_device = { + .name = "Phoenix 486 Jumper Readout", + .internal_name = "phoenix_486_jumper", + .flags = 0, + .local = 0, + .init = phoenix_486_jumper_init, + .close = phoenix_486_jumper_close, + .reset = phoenix_486_jumper_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t phoenix_486_jumper_pci_device = { + .name = "Phoenix 486 Jumper Readout (PCI machines)", + .internal_name = "phoenix_486_jumper_pci", + .flags = 0, + .local = 1, + .init = phoenix_486_jumper_init, + .close = phoenix_486_jumper_close, + .reset = phoenix_486_jumper_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/postcard.c b/src/device/postcard.c index 91eb29fcd..22598613f 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -66,21 +66,17 @@ static void postcard_setui(void) { if (!postcard_written) - sprintf(postcard_str, "POST: -- --"); + sprintf(postcard_str, "POST: -- --"); else if (postcard_written == 1) - sprintf(postcard_str, "POST: %02X --", postcard_code); + sprintf(postcard_str, "POST: %02X --", postcard_code); else - sprintf(postcard_str, "POST: %02X %02X", postcard_code, postcard_prev_code); + sprintf(postcard_str, "POST: %02X %02X", postcard_code, postcard_prev_code); ui_sb_bugui(postcard_str); if (postcard_do_log) { - /* log same string sent to the UI */ - int len = strlen(postcard_str); - postcard_str[len + 1] = '\0'; - postcard_str[len] = '\n'; - postcard_log("[%04X:%08X] ", CS, cpu_state.pc); - postcard_log(postcard_str); + /* log same string sent to the UI */ + postcard_log("[%04X:%08X] %s\n", CS, cpu_state.pc, postcard_str); } } @@ -98,13 +94,13 @@ postcard_reset(void) static void postcard_write(uint16_t port, uint8_t val, void *priv) { - if (postcard_written && val == postcard_code) - return; + if (postcard_written && (val == postcard_code)) + return; postcard_prev_code = postcard_code; postcard_code = val; if (postcard_written < 2) - postcard_written++; + postcard_written++; postcard_setui(); } @@ -115,12 +111,18 @@ postcard_init(const device_t *info) { postcard_reset(); - if (machines[machine].flags & MACHINE_MCA) - postcard_port = 0x680; /* MCA machines */ - else if (strstr(machines[machine].name, " PS/2 ")) - postcard_port = 0x90; /* ISA PS/2 machines */ + 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 ")) + 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 */ + else if (strstr(machines[machine].name, " Compaq ") && !machine_has_bus(machine, MACHINE_BUS_PCI)) + postcard_port = 0x84; /* ISA Compaq machines */ else - postcard_port = 0x80; /* AT and clone machines */ + postcard_port = 0x80; /* AT and clone machines */ postcard_log("POST card initializing on port %04Xh\n", postcard_port); if (postcard_port) io_sethandler(postcard_port, 1, @@ -137,12 +139,16 @@ postcard_close(UNUSED(void *priv)) NULL, NULL, NULL, postcard_write, NULL, NULL, NULL); } - const device_t postcard_device = { - "POST Card", - DEVICE_ISA, - 0, - postcard_init, postcard_close, NULL, - NULL, NULL, NULL, - NULL + .name = "POST Card", + .internal_name = "postcard", + .flags = DEVICE_ISA, + .local = 0, + .init = postcard_init, + .close = postcard_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/serial.c b/src/device/serial.c index 50a74d46c..3175b428d 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -128,8 +128,8 @@ serial_update_ints(serial_t *dev) dev->iir = 0; } - if (stat && ((dev->mctrl & 8) || (dev->type == SERIAL_8250_PCJR))) { - if (dev->type >= SERIAL_NS16450) + if (stat && (dev->irq != 0xff) && ((dev->mctrl & 8) || (dev->type == SERIAL_8250_PCJR))) { + if (dev->type >= SERIAL_16450) picintlevel(1 << dev->irq); else picint(1 << dev->irq); @@ -151,9 +151,9 @@ serial_clear_timeout(serial_t *dev) static void write_fifo(serial_t *dev, uint8_t dat) { - serial_log("write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); + serial_log("write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); - if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + if ((dev->type >= SERIAL_16550) && dev->fifo_enabled) { /* FIFO mode. */ timer_disable(&dev->timeout_timer); /* Indicate overrun. */ @@ -189,7 +189,7 @@ write_fifo(serial_t *dev, uint8_t dat) void serial_write_fifo(serial_t *dev, uint8_t dat) { - serial_log("serial_write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); + serial_log("serial_write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); if (!(dev->mctrl & 0x10)) write_fifo(dev, dat); @@ -364,7 +364,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_log("UART: Write %02X to port %02X\n", val, addr); - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr & 7) { case 0: @@ -380,7 +380,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) dev->int_status &= ~SERIAL_INT_TRANSMIT; serial_update_ints(dev); - if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled && (dev->xmit_fifo_pos < 16)) { + if ((dev->type >= SERIAL_16550) && dev->fifo_enabled && (dev->xmit_fifo_pos < 16)) { /* FIFO mode, begin transmitting. */ timer_on_auto(&dev->transmit_timer, dev->transmit_period); dev->transmit_enabled |= 1; /* Start moving. */ @@ -405,7 +405,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_update_ints(dev); break; case 2: - if (dev->type >= SERIAL_NS16550) { + if (dev->type >= SERIAL_16550) { if ((val ^ dev->fcr) & 0x01) serial_reset_fifo(dev); dev->fcr = val & 0xf9; @@ -493,7 +493,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) } break; case 5: - dev->lsr = val; + dev->lsr = (dev->lsr & 0xe0) | (val & 0x1f); if (dev->lsr & 0x01) dev->int_status |= SERIAL_INT_RECEIVE; if (dev->lsr & 0x1e) @@ -509,7 +509,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_update_ints(dev); break; case 7: - if (dev->type >= SERIAL_NS16450) + if (dev->type >= SERIAL_16450) dev->scratch = val; break; } @@ -522,7 +522,7 @@ serial_read(uint16_t addr, void *p) serial_t *dev = (serial_t *)p; uint8_t i, ret = 0; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr & 7) { case 0: @@ -531,7 +531,7 @@ serial_read(uint16_t addr, void *p) break; } - if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + if ((dev->type >= SERIAL_16550) && dev->fifo_enabled) { /* FIFO mode. */ serial_clear_timeout(dev); @@ -565,7 +565,7 @@ serial_read(uint16_t addr, void *p) else ret = dev->ier; break; - case 2: + case 2: ret = dev->iir; if ((ret & 0xe) == 2) { dev->int_status &= ~SERIAL_INT_TRANSMIT; @@ -624,7 +624,7 @@ serial_remove(serial_t *dev) void -serial_setup(serial_t *dev, uint16_t addr, int irq) +serial_setup(serial_t *dev, uint16_t addr, uint8_t irq) { serial_log("Adding serial port %i at %04X...\n", dev->inst, addr); @@ -693,10 +693,14 @@ serial_init(const device_t *info) dev->sd = &(serial_devices[next_inst]); dev->sd->serial = dev; serial_reset_port(dev); - if (next_inst || (info->flags & DEVICE_PCJR)) - serial_setup(dev, SERIAL2_ADDR, SERIAL2_IRQ); - else - serial_setup(dev, SERIAL1_ADDR, SERIAL1_IRQ); + if (next_inst == 3) + serial_setup(dev, COM4_ADDR, COM4_IRQ); + else if (next_inst == 2) + serial_setup(dev, COM3_ADDR, COM3_IRQ); + else if ((next_inst == 1) || (info->flags & DEVICE_PCJR)) + serial_setup(dev, COM2_ADDR, COM2_IRQ); + else if (next_inst == 0) + serial_setup(dev, COM1_ADDR, COM1_IRQ); /* Default to 1200,N,7. */ dev->dlab = 96; @@ -722,46 +726,118 @@ serial_set_next_inst(int ni) void serial_standalone_init(void) { - if (next_inst == 0) { - device_add_inst(&i8250_device, 1); - device_add_inst(&i8250_device, 2); - } else if (next_inst == 1) - device_add_inst(&i8250_device, 2); + for ( ; next_inst < SERIAL_MAX; ) + device_add_inst(&ns8250_device, next_inst + 1); }; - -const device_t i8250_device = { - "Intel 8250(-compatible) UART", - 0, - SERIAL_8250, - serial_init, serial_close, NULL, - NULL, serial_speed_changed, NULL, - NULL +const device_t ns8250_device = { + .name = "National Semiconductor 8250(-compatible) UART", + .internal_name = "ns8250", + .flags = 0, + .local = SERIAL_8250, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL }; -const device_t i8250_pcjr_device = { - "Intel 8250(-compatible) UART for PCjr", - DEVICE_PCJR, - SERIAL_8250_PCJR, - serial_init, serial_close, NULL, - NULL, serial_speed_changed, NULL, - NULL +const device_t ns8250_pcjr_device = { + .name = "National Semiconductor 8250(-compatible) UART for PCjr", + .internal_name = "ns8250_pcjr", + .flags = DEVICE_PCJR, + .local = SERIAL_8250_PCJR, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t ns16450_device = { - "National Semiconductor NS16450(-compatible) UART", - 0, - SERIAL_NS16450, - serial_init, serial_close, NULL, - NULL, serial_speed_changed, NULL, - NULL + .name = "National Semiconductor NS16450(-compatible) UART", + .internal_name = "ns16450", + .flags = 0, + .local = SERIAL_16450, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t ns16550_device = { - "National Semiconductor NS16550(-compatible) UART", - 0, - SERIAL_NS16550, - serial_init, serial_close, NULL, - NULL, serial_speed_changed, NULL, - NULL + .name = "National Semiconductor NS16550(-compatible) UART", + .internal_name = "ns16550", + .flags = 0, + .local = SERIAL_16550, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ns16650_device = { + .name = "Startech Semiconductor 16650(-compatible) UART", + .internal_name = "ns16650", + .flags = 0, + .local = SERIAL_16650, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ns16750_device = { + .name = "Texas Instruments 16750(-compatible) UART", + .internal_name = "ns16750", + .flags = 0, + .local = SERIAL_16750, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ns16850_device = { + .name = "Exar Corporation NS16850(-compatible) UART", + .internal_name = "ns16850", + .flags = 0, + .local = SERIAL_16850, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ns16950_device = { + .name = "Oxford Semiconductor NS16950(-compatible) UART", + .internal_name = "ns16950", + .flags = 0, + .local = SERIAL_16950, + .init = serial_init, + .close = serial_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = serial_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/smbus.c b/src/device/smbus.c deleted file mode 100644 index d86b167c1..000000000 --- a/src/device/smbus.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * 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. - * - * Implement SMBus (System Management Bus) and its operations. - * - * - * - * Authors: RichardG, - * - * Copyright 2020 RichardG. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/smbus.h> - - -#define NADDRS 128 /* SMBus supports 128 addresses */ -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - - -typedef struct _smbus_ { - uint8_t (*read_byte)(uint8_t addr, void *priv); - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv); - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv); - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); - - void (*write_byte)(uint8_t addr, uint8_t val, void *priv); - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); - - void *priv; - - struct _smbus_ *prev, *next; -} smbus_t; - -int smbus_initialized = 0; -smbus_t *smbus[NADDRS], *smbus_last[NADDRS]; - - -#ifdef ENABLE_SMBUS_LOG -int smbus_do_log = ENABLE_SMBUS_LOG; - - -static void -smbus_log(const char *fmt, ...) -{ - va_list ap; - - if (smbus_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define smbus_log(fmt, ...) -#endif - - -void -smbus_init(void) -{ - int c; - smbus_t *p, *q; - - if (!smbus_initialized) { - for (c=0; cprev; - free(p); - p = q; - } - p = NULL; - } - - /* smbus[c] should be NULL. */ - smbus[c] = smbus_last[c] = NULL; - } -} - - -void -smbus_sethandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv) -{ - int c; - smbus_t *p, *q = NULL; - - for (c = 0; c < size; c++) { - p = smbus_last[base + c]; - q = (smbus_t *) malloc(sizeof(smbus_t)); - memset(q, 0, sizeof(smbus_t)); - if (p) { - p->next = q; - q->prev = p; - } else { - smbus[base + c] = q; - q->prev = NULL; - } - - q->read_byte = read_byte; - q->read_byte_cmd = read_byte_cmd; - q->read_word_cmd = read_word_cmd; - q->read_block_cmd = read_block_cmd; - - q->write_byte = write_byte; - q->write_byte_cmd = write_byte_cmd; - q->write_word_cmd = write_word_cmd; - q->write_block_cmd = write_block_cmd; - - q->priv = priv; - q->next = NULL; - - smbus_last[base + c] = q; - } -} - - -void -smbus_removehandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv) -{ - int c; - smbus_t *p; - - for (c = 0; c < size; c++) { - p = smbus[base + c]; - if (!p) - continue; - while(p) { - if ((p->read_byte == read_byte) && (p->read_byte_cmd == read_byte_cmd) && - (p->read_word_cmd == read_word_cmd) && (p->read_block_cmd == read_block_cmd) && - (p->write_byte == write_byte) && (p->write_byte_cmd == write_byte_cmd) && - (p->write_word_cmd == write_word_cmd) && (p->write_block_cmd == write_block_cmd) && - (p->priv == priv)) { - if (p->prev) - p->prev->next = p->next; - else - smbus[base + c] = p->next; - if (p->next) - p->next->prev = p->prev; - else - smbus_last[base + c] = p->prev; - free(p); - p = NULL; - break; - } - p = p->next; - } - } -} - - -void -smbus_handler(int set, uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv) -{ - if (set) - smbus_sethandler(base, size, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); - else - smbus_removehandler(base, size, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); -} - - -uint8_t -smbus_has_device(uint8_t addr) -{ - return(!!smbus[addr]); -} - - -uint8_t -smbus_read_byte(uint8_t addr) -{ - uint8_t ret = 0xff; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_byte) { - ret &= p->read_byte(addr, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_byte(%02X) = %02X\n", addr, ret); - - return(ret); -} - -uint8_t -smbus_read_byte_cmd(uint8_t addr, uint8_t cmd) -{ - uint8_t ret = 0xff; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_byte_cmd) { - ret &= p->read_byte_cmd(addr, cmd, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_byte_cmd(%02X, %02X) = %02X\n", addr, cmd, ret); - - return(ret); -} - -uint16_t -smbus_read_word_cmd(uint8_t addr, uint8_t cmd) -{ - uint16_t ret = 0xffff; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_word_cmd) { - ret &= p->read_word_cmd(addr, cmd, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_word_cmd(%02X, %02X) = %04X\n", addr, cmd, ret); - - return(ret); -} - -uint8_t -smbus_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) -{ - uint8_t ret = 0; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_block_cmd) { - ret = MAX(ret, p->read_block_cmd(addr, cmd, data, len, p->priv)); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_block_cmd(%02X, %02X) = %02X\n", addr, cmd, len); - - return(ret); -} - - -void -smbus_write_byte(uint8_t addr, uint8_t val) -{ - smbus_t *p; - int found = 0; - - if (smbus[addr]) { - p = smbus[addr]; - while(p) { - if (p->write_byte) { - p->write_byte(addr, val, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_byte(%02X, %02X)\n", addr, val); - - return; -} - -void -smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val) -{ - smbus_t *p; - int found = 0; - - if (smbus[addr]) { - p = smbus[addr]; - while(p) { - if (p->write_byte_cmd) { - p->write_byte_cmd(addr, cmd, val, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_byte_cmd(%02X, %02X, %02X)\n", addr, cmd, val); - - return; -} - -void -smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val) -{ - smbus_t *p; - int found = 0; - - if (smbus[addr]) { - p = smbus[addr]; - while(p) { - if (p->write_word_cmd) { - p->write_word_cmd(addr, cmd, val, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_word_cmd(%02X, %02X, %04X)\n", addr, cmd, val); - - return; -} - -void -smbus_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) -{ - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->write_block_cmd) { - p->write_block_cmd(addr, cmd, data, len, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_block_cmd(%02X, %02X, %02X)\n", addr, cmd, len); - - return; -} diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c new file mode 100644 index 000000000..c56ecd881 --- /dev/null +++ b/src/device/smbus_ali7101.c @@ -0,0 +1,314 @@ +/* + * 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 a generic ALi M7101-compatible SMBus host + * controller. + * + * Authors: RichardG, + * Miran Grca, + * + * Copyright 2020,2021 RichardG. + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/i2c.h> +#include <86box/smbus.h> + + +#ifdef ENABLE_SMBUS_ALI7101_LOG +int smbus_ali7101_do_log = ENABLE_SMBUS_ALI7101_LOG; + + +static void +smbus_ali7101_log(const char *fmt, ...) +{ + va_list ap; + + if (smbus_ali7101_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define smbus_ali7101_log(fmt, ...) +#endif + + +static uint8_t +smbus_ali7101_read(uint16_t addr, void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + uint8_t ret = 0x00; + + switch (addr - dev->io_base) { + case 0x00: + ret = dev->stat; + break; + + case 0x03: + ret = dev->addr; + break; + + case 0x04: + ret = dev->data0; + break; + + case 0x05: + ret = dev->data1; + break; + + case 0x06: + ret = dev->data[dev->index++]; + if (dev->index >= SMBUS_ALI7101_BLOCK_DATA_SIZE) + dev->index = 0; + break; + + case 0x07: + ret = dev->cmd; + break; + } + + smbus_ali7101_log("SMBus ALI7101: read(%02X) = %02x\n", addr, ret); + + return ret; +} + + +static void +smbus_ali7101_write(uint16_t addr, uint8_t val, void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + uint8_t smbus_addr, cmd, read, prev_stat; + uint16_t timer_bytes = 0; + + smbus_ali7101_log("SMBus ALI7101: write(%02X, %02X)\n", addr, val); + + prev_stat = dev->next_stat; + dev->next_stat = 0x04; + switch (addr - dev->io_base) { + case 0x00: + dev->stat &= ~(val & 0xf2); + /* Make sure IDLE is set if we're not busy or errored. */ + if (dev->stat == 0x00) + dev->stat = 0x04; + break; + + case 0x01: + dev->ctl = val & 0xfc; + if (val & 0x04) { /* cancel an in-progress command if KILL is set */ + if (prev_stat) { /* cancel only if a command is in progress */ + timer_disable(&dev->response_timer); + dev->stat = 0x80; /* raise FAILED */ + } + } else if (val & 0x08) { /* T_OUT_CMD */ + if (prev_stat) { /* cancel only if a command is in progress */ + timer_disable(&dev->response_timer); + dev->stat = 0x20; /* raise DEVICE_ERR */ + } + } + + if (val & 0x80) + dev->index = 0; + break; + + case 0x02: + /* dispatch command if START is set */ + timer_bytes++; /* address */ + + smbus_addr = (dev->addr >> 1); + read = dev->addr & 0x01; + + cmd = (dev->ctl >> 4) & 0x7; + smbus_ali7101_log("SMBus ALI7101: addr=%02X read=%d protocol=%X cmd=%02X data0=%02X data1=%02X\n", smbus_addr, read, cmd, dev->cmd, dev->data0, dev->data1); + + /* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */ + if (!i2c_start(i2c_smbus, smbus_addr, read)) { + dev->next_stat = 0x40; + break; + } + + dev->next_stat = 0x10; /* raise INTER (command completed) by default */ + + /* Decode the command protocol. */ + switch (cmd) { + case 0x0: /* quick R/W */ + break; + + case 0x1: /* byte R/W */ + if (read) /* byte read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + else /* byte write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + + break; + + case 0x2: /* byte data R/W */ + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) /* byte read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + else /* byte write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + + break; + + case 0x3: /* word data R/W */ + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) { /* word read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + dev->data1 = i2c_read(i2c_smbus, smbus_addr); + } else { /* word write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + } + timer_bytes += 2; + + break; + + case 0x4: /* block R/W */ + timer_bytes++; /* count the SMBus length byte now */ + + /* fall-through */ + + default: /* unknown */ + dev->next_stat = 0x20; /* raise DEV_ERR */ + timer_bytes = 0; + break; + } + + /* Finish transfer. */ + i2c_stop(i2c_smbus, smbus_addr); + break; + + case 0x03: + dev->addr = val; + break; + + case 0x04: + dev->data0 = val; + break; + + case 0x05: + dev->data1 = val; + break; + + case 0x06: + dev->data[dev->index++] = val; + if (dev->index >= SMBUS_ALI7101_BLOCK_DATA_SIZE) + dev->index = 0; + break; + + case 0x07: + dev->cmd = val; + break; + } + + if (dev->next_stat != 0x04) { /* schedule dispatch of any pending status register update */ + dev->stat = 0x08; /* raise HOST_BUSY while waiting */ + timer_disable(&dev->response_timer); + /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */ + timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC); + } +} + + +static void +smbus_ali7101_response(void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + + /* Dispatch the status register update. */ + dev->stat = dev->next_stat; +} + + +void +smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint8_t enable) +{ + if (dev->io_base) + io_removehandler(dev->io_base, 0x10, smbus_ali7101_read, NULL, NULL, smbus_ali7101_write, NULL, NULL, dev); + + dev->io_base = new_io_base; + smbus_ali7101_log("SMBus ALI7101: remap to %04Xh (%sabled)\n", dev->io_base, enable ? "en" : "dis"); + + if (enable && dev->io_base) + io_sethandler(dev->io_base, 0x10, smbus_ali7101_read, NULL, NULL, smbus_ali7101_write, NULL, NULL, dev); +} + + +static void +smbus_ali7101_reset(void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + + timer_disable(&dev->response_timer); + dev->stat = 0x04; +} + + +static void * +smbus_ali7101_init(const device_t *info) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) malloc(sizeof(smbus_ali7101_t)); + memset(dev, 0, sizeof(smbus_ali7101_t)); + + dev->local = info->local; + dev->stat = 0x04; + /* We save the I2C bus handle on dev but use i2c_smbus for all operations because + dev and therefore dev->i2c will be invalidated if a device triggers a hard reset. */ + i2c_smbus = dev->i2c = i2c_addbus("smbus_ali7101"); + + timer_add(&dev->response_timer, smbus_ali7101_response, dev, 0); + + return dev; +} + + +static void +smbus_ali7101_close(void *priv) +{ + smbus_ali7101_t *dev = (smbus_ali7101_t *) priv; + + if (i2c_smbus == dev->i2c) + i2c_smbus = NULL; + i2c_removebus(dev->i2c); + + free(dev); +} + +const device_t ali7101_smbus_device = { + .name = "ALi M7101-compatible SMBus Host Controller", + .internal_name = "ali7101_smbus", + .flags = DEVICE_AT, + .local = 0, + .init = smbus_ali7101_init, + .close = smbus_ali7101_close, + .reset = smbus_ali7101_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index ad8ff64d0..c96a9fa57 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -25,9 +25,8 @@ #include <86box/io.h> #include <86box/device.h> #include <86box/timer.h> +#include <86box/i2c.h> #include <86box/smbus.h> -#include <86box/smbus_piix4.h> - #ifdef ENABLE_SMBUS_PIIX4_LOG int smbus_piix4_do_log = ENABLE_SMBUS_PIIX4_LOG; @@ -39,9 +38,9 @@ smbus_piix4_log(const char *fmt, ...) va_list ap; if (smbus_piix4_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else @@ -56,33 +55,39 @@ smbus_piix4_read(uint16_t addr, void *priv) uint8_t ret = 0x00; switch (addr - dev->io_base) { - case 0x00: - ret = dev->stat; - break; - case 0x02: - dev->index = 0; /* reading from this resets the block data index */ - ret = dev->ctl; - break; - case 0x03: - ret = dev->cmd; - break; - case 0x04: - ret = dev->addr; - break; - case 0x05: - ret = dev->data0; - break; - case 0x06: - ret = dev->data1; - break; - case 0x07: - ret = dev->data[dev->index++]; - if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) - dev->index = 0; - break; + case 0x00: + ret = dev->stat; + break; + + case 0x02: + dev->index = 0; /* reading from this resets the block data index */ + ret = dev->ctl; + break; + + case 0x03: + ret = dev->cmd; + break; + + case 0x04: + ret = dev->addr; + break; + + case 0x05: + ret = dev->data0; + break; + + case 0x06: + ret = dev->data1; + break; + + case 0x07: + ret = dev->data[dev->index++]; + if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) + dev->index = 0; + break; } - smbus_piix4_log("SMBus PIIX4: read(%02x) = %02x\n", addr, ret); + smbus_piix4_log("SMBus PIIX4: read(%02X) = %02x\n", addr, ret); return ret; } @@ -92,107 +97,223 @@ static void smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; - uint8_t smbus_addr, smbus_read, prev_stat; - uint16_t temp; + uint8_t smbus_addr, cmd, read, block_len, prev_stat; + uint16_t timer_bytes = 0, i = 0; - smbus_piix4_log("SMBus PIIX4: write(%02x, %02x)\n", addr, val); + smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); prev_stat = dev->next_stat; - dev->next_stat = 0; + dev->next_stat = 0x00; switch (addr - dev->io_base) { - case 0x00: - /* some status bits are reset by writing 1 to them */ - for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr = smbus_addr << 1) { - if (val & smbus_addr) - dev->stat = dev->stat & ~smbus_addr; - } - break; - case 0x02: - dev->ctl = val & ~(0x40); /* START always reads 0 */ - if (val & 0x02) { /* cancel an in-progress command if KILL is set */ - /* cancel only if a command is in progress */ - if (prev_stat) { - dev->stat = 0x10; /* raise FAILED */ - timer_disable(&dev->response_timer); - } - } - if (val & 0x40) { /* dispatch command if START is set */ - smbus_addr = (dev->addr >> 1); - if (!smbus_has_device(smbus_addr)) { - /* raise DEV_ERR if no device is at this address */ - dev->next_stat = 0x4; - break; - } - smbus_read = (dev->addr & 0x01); + case 0x00: + for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { /* handle clearable bits */ + if (val & smbus_addr) + dev->stat &= ~smbus_addr; + } + break; - /* decode the 3-bit command protocol */ - switch ((val >> 2) & 0x7) { - case 0x0: /* quick R/W */ - dev->next_stat = 0x2; - break; - case 0x1: /* byte R/W */ - if (smbus_read) - dev->data0 = smbus_read_byte(smbus_addr); - else - smbus_write_byte(smbus_addr, dev->data0); - dev->next_stat = 0x2; - break; - case 0x2: /* byte data R/W */ - if (smbus_read) - dev->data0 = smbus_read_byte_cmd(smbus_addr, dev->cmd); - else - smbus_write_byte_cmd(smbus_addr, dev->cmd, dev->data0); - dev->next_stat = 0x2; - break; - case 0x3: /* word data R/W */ - if (smbus_read) { - temp = smbus_read_word_cmd(smbus_addr, dev->cmd); - dev->data0 = (temp & 0xFF); - dev->data1 = (temp >> 8); - } else { - temp = (dev->data1 << 8) | dev->data0; - smbus_write_word_cmd(smbus_addr, dev->cmd, temp); - } - dev->next_stat = 0x2; - break; - case 0x5: /* block R/W */ - if (smbus_read) - dev->data0 = smbus_read_block_cmd(smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE); - else - smbus_write_block_cmd(smbus_addr, dev->cmd, dev->data, dev->data0); - dev->next_stat = 0x2; - break; - default: - /* other command protocols have undefined behavior, but raise DEV_ERR to be safe */ - dev->next_stat = 0x4; - break; - } - } - break; - case 0x03: - dev->cmd = val; - break; - case 0x04: - dev->addr = val; - break; - case 0x05: - dev->data0 = val; - break; - case 0x06: - dev->data1 = val; - break; - case 0x07: - dev->data[dev->index++] = val; - if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) - dev->index = 0; - break; + case 0x02: + dev->ctl = val & ((dev->local == SMBUS_VIA) ? 0x3f : 0x1f); + if (val & 0x02) { /* cancel an in-progress command if KILL is set */ + if (prev_stat) { /* cancel only if a command is in progress */ + timer_disable(&dev->response_timer); + dev->stat = 0x10; /* raise FAILED */ + } + } + if (val & 0x40) { /* dispatch command if START is set */ + timer_bytes++; /* address */ + + smbus_addr = dev->addr >> 1; + read = dev->addr & 0x01; + + cmd = (dev->ctl >> 2) & 0xf; + smbus_piix4_log("SMBus PIIX4: addr=%02X read=%d protocol=%X cmd=%02X data0=%02X data1=%02X\n", smbus_addr, read, cmd, dev->cmd, dev->data0, dev->data1); + + /* Raise DEV_ERR if no device is at this address, or if the device returned NAK. */ + if (!i2c_start(i2c_smbus, smbus_addr, read)) { + dev->next_stat = 0x04; + break; + } + + dev->next_stat = 0x02; /* raise INTER (command completed) by default */ + + /* Decode the command protocol. + VIA-specific modes (0x4 and [0x6:0xf]) are undocumented and required real hardware research. */ + switch (cmd) { + case 0x0: /* quick R/W */ + break; + + case 0x1: /* byte R/W */ + if (read) /* byte read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + else /* byte write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + + break; + + case 0x2: /* byte data R/W */ + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) /* byte read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + else /* byte write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + + break; + + case 0x3: /* word data R/W */ + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) { /* word read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + dev->data1 = i2c_read(i2c_smbus, smbus_addr); + } else { /* word write */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + } + timer_bytes += 2; + + break; + + case 0x4: /* process call */ + if (dev->local != SMBUS_VIA) /* VIA only */ + goto unknown_protocol; + + if (!read) { /* command write (only when writing) */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + } + + /* fall-through */ + + case 0xc: /* I2C process call */ + if (!read) { /* word write (only when writing) */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + timer_bytes += 2; + } + + /* word read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + dev->data1 = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += 2; + + break; + + case 0x5: /* block R/W */ + timer_bytes++; /* count the SMBus length byte now */ + + /* fall-through */ + + case 0xd: /* I2C block R/W */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + if (read) { + /* block read [data0] (I2C) or [first byte] (SMBus) bytes */ + if (cmd == 0x5) + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + for (i = 0; i < dev->data0; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + } else { + if (cmd == 0x5) /* send length [data0] as first byte on SMBus */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + /* block write [data0] bytes */ + for (i = 0; i < dev->data0; i++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK])) + break; + } + } + timer_bytes += i; + + break; + + case 0x6: /* I2C with 10-bit address */ + if (dev->local != SMBUS_VIA) /* VIA only */ + goto unknown_protocol; + + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + + /* fall-through */ + + case 0xe: /* I2C with 7-bit address */ + if (!read) { /* word write (only when writing) */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + timer_bytes += 2; + } + + /* block read [first byte] bytes */ + block_len = dev->data[0]; + for (i = 0; i < block_len; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += i; + + break; + + case 0xf: /* universal */ + /* block write [data0] bytes */ + for (i = 0; i < dev->data0; i++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK])) + break; /* write NAK behavior is unknown */ + } + timer_bytes += i; + + /* block read [data1] bytes */ + for (i = 0; i < dev->data1; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += i; + + break; + + default: /* unknown */ +unknown_protocol: + dev->next_stat = 0x04; /* raise DEV_ERR */ + timer_bytes = 0; + break; + } + + /* Finish transfer. */ + i2c_stop(i2c_smbus, smbus_addr); + } + break; + + case 0x03: + dev->cmd = val; + break; + + case 0x04: + dev->addr = val; + break; + + case 0x05: + dev->data0 = val; + break; + + case 0x06: + dev->data1 = val; + break; + + case 0x07: + dev->data[dev->index++] = val; + if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) + dev->index = 0; + break; } - /* if a status register update was given, dispatch it after 10ms to ensure nothing breaks */ - if (dev->next_stat) { - dev->stat = 0x1; /* raise HOST_BUSY while waiting */ - timer_disable(&dev->response_timer); - timer_set_delay_u64(&dev->response_timer, 10 * TIMER_USEC); + if (dev->next_stat) { /* schedule dispatch of any pending status register update */ + dev->stat = 0x01; /* raise HOST_BUSY while waiting */ + timer_disable(&dev->response_timer); + /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * bit period in usecs */ + timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * dev->bit_period * TIMER_USEC); } } @@ -202,7 +323,7 @@ smbus_piix4_response(void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; - /* dispatch the status register update */ + /* Dispatch the status register update. */ dev->stat = dev->next_stat; } @@ -210,26 +331,42 @@ smbus_piix4_response(void *priv) void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable) { - if (dev->io_base != 0x0000) + if (dev->io_base) io_removehandler(dev->io_base, 0x10, smbus_piix4_read, NULL, NULL, smbus_piix4_write, NULL, NULL, dev); dev->io_base = new_io_base; - smbus_piix4_log("SMBus PIIX4: remap to %04Xh\n", dev->io_base); + smbus_piix4_log("SMBus PIIX4: remap to %04Xh (%sabled)\n", dev->io_base, enable ? "en" : "dis"); - if (enable && (dev->io_base != 0x0000)) + if (enable && dev->io_base) io_sethandler(dev->io_base, 0x10, smbus_piix4_read, NULL, NULL, smbus_piix4_write, NULL, NULL, dev); } +void +smbus_piix4_setclock(smbus_piix4_t *dev, int clock) +{ + dev->clock = clock; + + /* Set the bit period in usecs. */ + dev->bit_period = 1000000.0 / dev->clock; +} + + static void * smbus_piix4_init(const device_t *info) { smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t)); memset(dev, 0, sizeof(smbus_piix4_t)); - smbus_init(); + dev->local = info->local; + /* We save the I2C bus handle on dev but use i2c_smbus for all operations because + dev and therefore dev->i2c will be invalidated if a device triggers a hard reset. */ + i2c_smbus = dev->i2c = i2c_addbus((dev->local == SMBUS_VIA) ? "smbus_vt82c686b" : "smbus_piix4"); + timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); + smbus_piix4_setclock(dev, 16384); /* default to 16.384 KHz */ + return dev; } @@ -239,15 +376,37 @@ smbus_piix4_close(void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; + if (i2c_smbus == dev->i2c) + i2c_smbus = NULL; + i2c_removebus(dev->i2c); + free(dev); } - const device_t piix4_smbus_device = { - "PIIX4-compatible SMBus Host Controller", - DEVICE_AT, - 0, - smbus_piix4_init, smbus_piix4_close, NULL, - NULL, NULL, NULL, - NULL + .name = "PIIX4-compatible SMBus Host Controller", + .internal_name = "piix4_smbus", + .flags = DEVICE_AT, + .local = SMBUS_PIIX4, + .init = smbus_piix4_init, + .close = smbus_piix4_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t via_smbus_device = { + .name = "VIA VT82C686B SMBus Host Controller", + .internal_name = "via_smbus", + .flags = DEVICE_AT, + .local = SMBUS_VIA, + .init = smbus_piix4_init, + .close = smbus_piix4_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/discord.c b/src/discord.c new file mode 100644 index 000000000..d1966a93d --- /dev/null +++ b/src/discord.c @@ -0,0 +1,196 @@ +/* + * 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. + * + * Discord integration module. + * + * + * + * Authors: David Hrdlička, + * + * Copyright 2019 David Hrdlička. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "cpu/cpu.h" +#include <86box/86box.h> +#include <86box/discord.h> +#include <86box/machine.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include + +#ifdef _WIN32 +# define PATH_DISCORD_DLL "discord_game_sdk.dll" +#elif defined __APPLE__ +# define PATH_DISCORD_DLL "discord_game_sdk.dylib" +#else +# define PATH_DISCORD_DLL "discord_game_sdk.so" +#endif + +int discord_loaded = 0; + +static void *discord_handle = NULL; +static struct IDiscordCore *discord_core = NULL; +static struct IDiscordActivityManager *discord_activities = NULL; + +static enum EDiscordResult(DISCORD_API *discord_create)(DiscordVersion version, struct DiscordCreateParams *params, struct IDiscordCore **result); + +static dllimp_t discord_imports[] = { + {"DiscordCreate", &discord_create}, + { NULL, NULL } +}; + +#ifdef ENABLE_DISCORD_LOG +int discord_do_log = 1; + +static void +discord_log(const char *fmt, ...) +{ + va_list ap; + + if (discord_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define discord_log(fmt, ...) +#endif + +void +discord_update_activity(int paused) +{ + struct DiscordActivity activity; + char cpufamily[1024]; + char *paren; + + if (discord_activities == NULL) + return; + + discord_log("discord: discord_update_activity(paused=%d)\n", paused); + + memset(&activity, 0x00, sizeof(activity)); + + strncpy(cpufamily, cpu_f->name, sizeof(cpufamily) - 1); + paren = strchr(cpufamily, '('); + if (paren) + *(paren - 1) = '\0'; + +#pragma GCC diagnostic push +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wformat-truncation" +#endif + if (strlen(vm_name) < 100) { + snprintf(activity.details, sizeof(activity.details), "Running \"%s\"", vm_name); + snprintf(activity.state, sizeof(activity.state), "%s (%s/%s)", strchr(machine_getname(), ']') + 2, cpufamily, cpu_s->name); + } else { + strncpy(activity.details, strchr(machine_getname(), ']') + 2, sizeof(activity.details) - 1); + snprintf(activity.state, sizeof(activity.state), "%s/%s", cpufamily, cpu_s->name); + } +#pragma GCC diagnostic pop + + activity.timestamps.start = time(NULL); + + /* Icon choosing for Discord based on 86Box.rc */ + +#ifdef RELEASE_BUILD + /* Icon by OBattler and laciba96 (green for release builds)*/ + strcpy(activity.assets.large_image, "86box-green"); +#elif BETA_BUILD + /* Icon by OBattler and laciba96 (yellow for beta builds done by Jenkins)*/ + strcpy(activity.assets.large_image, "86box-yellow"); +#elif ALPHA_BUILD + /* Icon by OBattler and laciba96 (red for alpha builds done by Jenkins)*/ + strcpy(activity.assets.large_image, "86box-red"); +#else + /* Icon by OBattler and laciba96 (gray for builds of branches and from the git master)*/ + strcpy(activity.assets.large_image, "86box"); +#endif + + /* End of icon choosing */ + + if (paused) { + strcpy(activity.assets.small_image, "status-paused"); + strcpy(activity.assets.small_text, "Paused"); + } else { + strcpy(activity.assets.small_image, "status-running"); + strcpy(activity.assets.small_text, "Running"); + } + + discord_activities->update_activity(discord_activities, &activity, NULL, NULL); +} + +int +discord_load() +{ + if (discord_handle != NULL) + return (1); + + // Try to load the DLL + discord_handle = dynld_module(PATH_DISCORD_DLL, discord_imports); + + if (discord_handle == NULL) { + discord_log("discord: couldn't load " PATH_DISCORD_DLL "\n"); + discord_close(); + + return (0); + } + + discord_loaded = 1; + return (1); +} + +void +discord_init() +{ + enum EDiscordResult result; + struct DiscordCreateParams params; + + if (discord_handle == NULL) + return; + + DiscordCreateParamsSetDefault(¶ms); + params.client_id = 906956844956782613; + params.flags = DiscordCreateFlags_NoRequireDiscord; + + result = discord_create(DISCORD_VERSION, ¶ms, &discord_core); + if (result != DiscordResult_Ok) { + discord_log("discord: DiscordCreate returned %d\n", result); + discord_close(); + return; + } + + discord_activities = discord_core->get_activity_manager(discord_core); + + return; +} + +void +discord_close() +{ + if (discord_core != NULL) + discord_core->destroy(discord_core); + + discord_core = NULL; + discord_activities = NULL; +} + +void +discord_run_callbacks() +{ + if (discord_core == NULL) + return; + + discord_core->run_callbacks(discord_core); +} diff --git a/src/disk/CMakeLists.txt b/src/disk/CMakeLists.txt new file mode 100644 index 000000000..34c373752 --- /dev/null +++ b/src/disk/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(hdd OBJECT hdd.c hdd_image.c hdd_table.c hdc.c hdc_st506_xt.c + hdc_st506_at.c hdc_xta.c hdc_esdi_at.c hdc_esdi_mca.c hdc_xtide.c + hdc_ide.c hdc_ide_opti611.c hdc_ide_cmd640.c hdc_ide_cmd646.c hdc_ide_sff8038i.c) + +add_library(zip OBJECT zip.c) + +add_library(mo OBJECT mo.c) + +add_subdirectory(minivhd) +target_link_libraries(86Box minivhd) diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 1bd40b88f..7ba9a0f1e 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -52,123 +52,90 @@ hdc_log(const char *fmt, ...) #define hdc_log(fmt, ...) #endif - static void * -null_init(const device_t *info) +nullhdc_init(const device_t *info) { return(NULL); } - static void -null_close(void *priv) +nullhdc_close(void *priv) { } - -static const device_t null_device = { - "Null HDC", 0, 0, - null_init, null_close, NULL, - NULL, NULL, NULL, NULL -}; - - static void * inthdc_init(const device_t *info) { return(NULL); } - static void inthdc_close(void *priv) { } - -static const device_t inthdc_device = { - "Internal Controller", 0, 0, - inthdc_init, inthdc_close, NULL, - NULL, NULL, NULL, NULL +static const device_t hdc_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = nullhdc_init, + .close = nullhdc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +static const device_t hdc_internal_device = { + .name = "Internal", + .internal_name = "internal", + .flags = 0, + .local = 0, + .init = inthdc_init, + .close = inthdc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; static const struct { - const char *name; - const char *internal_name; const device_t *device; } controllers[] = { - { "None", "none", - &null_device }, - - { "Internal Controller", "internal", - &inthdc_device }, - - { "[ISA] [MFM] IBM PC Fixed Disk Adapter", "st506_xt", - &st506_xt_xebec_device }, - - { "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "st506_xt_dtc5150x", - &st506_xt_dtc5150x_device }, - - { "[ISA] [MFM] ST-11M Fixed Disk Adapter", "st506_xt_st11_m", - &st506_xt_st11_m_device }, - - { "[ISA] [MFM] WD1002A-WX1 Fixed Disk Adapter", "st506_xt_wd1002a_wx1", - &st506_xt_wd1002a_wx1_device }, - - { "[ISA] [MFM/RLL] IBM PC/AT Fixed Disk Adapter", "st506_at", - &st506_at_wd1003_device }, - - { "[ISA] [RLL] ST-11R Fixed Disk Adapter", "st506_xt_st11_r", - &st506_xt_st11_r_device }, - - { "[ISA] [RLL] WD1002A-27X Fixed Disk Adapter", "st506_xt_wd1002a_27x", - &st506_xt_wd1002a_27x_device }, - - { "[ISA] [ESDI] PC/AT ESDI Fixed Disk Adapter", "esdi_at", - &esdi_at_wd1007vse1_device }, - - { "[ISA] [IDE] PC/AT IDE Adapter", "ide_isa", - &ide_isa_device }, - - { "[ISA] [IDE] PC/AT IDE Adapter (Dual-Channel)", "ide_isa_2ch", - &ide_isa_2ch_device }, - - { "[ISA] [IDE] PC/AT XTIDE", "xtide_at", - &xtide_at_device }, - - { "[ISA] [IDE] PS/2 AT XTIDE (1.1.5)", "xtide_at_ps2", - &xtide_at_ps2_device }, - - { "[ISA] [IDE] WDXT-150 IDE (XTA) Adapter", "xta_wdxt150", - &xta_wdxt150_device }, - - { "[ISA] [XT IDE] Acculogic XT IDE", "xtide_acculogic", - &xtide_acculogic_device }, - - { "[ISA] [XT IDE] PC/XT XTIDE", "xtide", - &xtide_device }, - - { "[MCA] [ESDI] IBM PS/2 ESDI Fixed Disk Adapter","esdi_mca", - &esdi_ps2_device }, - - { "[PCI] [IDE] PCI IDE Adapter", "ide_pci", - &ide_pci_device }, - - { "[PCI] [IDE] PCI IDE Adapter (Dual-Channel)", "ide_pci_2ch", - &ide_pci_2ch_device }, - - { "[VLB] [IDE] PC/AT IDE Adapter", "vlb_isa", - &ide_vlb_device }, - - { "[VLB] [IDE] PC/AT IDE Adapter (Dual-Channel)", "vlb_isa_2ch", - &ide_vlb_2ch_device }, - - { "", "", - NULL } +// clang-format off + { &hdc_none_device }, + { &hdc_internal_device }, + { &st506_xt_xebec_device }, + { &st506_xt_dtc5150x_device }, + { &st506_xt_st11_m_device }, + { &st506_xt_wd1002a_wx1_device }, + { &st506_xt_wd1004a_wx1_device }, + { &st506_at_wd1003_device }, + { &st506_xt_st11_r_device }, + { &st506_xt_wd1002a_27x_device }, + { &st506_xt_wd1004_27x_device }, + { &st506_xt_wd1004a_27x_device }, + { &esdi_at_wd1007vse1_device }, + { &ide_isa_device }, + { &ide_isa_2ch_device }, + { &xtide_at_device }, + { &xtide_at_386_device }, + { &xtide_at_ps2_device }, + { &xta_wdxt150_device }, + { &xtide_acculogic_device }, + { &xtide_device }, + { &esdi_ps2_device }, + { &ide_pci_device }, + { &ide_pci_2ch_device }, + { &ide_vlb_device }, + { &ide_vlb_2ch_device }, + { NULL } +// clang-format on }; - /* Initialize the 'hdc_current' value based on configured HDC name. */ void hdc_init(void) @@ -199,49 +166,25 @@ hdc_reset(void) } -char * -hdc_get_name(int hdc) -{ - return((char *) controllers[hdc].name); -} - - char * hdc_get_internal_name(int hdc) { - return((char *) controllers[hdc].internal_name); -} - - -int -hdc_get_id(char *s) -{ - int c = 0; - - while (strlen((char *) controllers[c].name)) - { - if (!strcmp((char *) controllers[c].name, s)) - return c; - c++; - } - - return 0; + return device_get_internal_name(controllers[hdc].device); } int hdc_get_from_internal_name(char *s) { - int c = 0; - - while (strlen((char *) controllers[c].internal_name)) - { - if (!strcmp((char *) controllers[c].internal_name, s)) - return c; - c++; - } - - return 0; + int c = 0; + + while (controllers[c].device != NULL) { + if (!strcmp((char *) controllers[c].device->internal_name, s)) + return c; + c++; + } + + return 0; } @@ -259,7 +202,7 @@ hdc_has_config(int hdc) if (dev == NULL) return(0); - if (dev->config == NULL) return(0); + if (!device_has_config(dev)) return(0); return(1); } diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 86f564c8d..ff284b231 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -18,8 +18,6 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #define _GNU_SOURCE #include #include @@ -44,7 +42,7 @@ #define HDC_TIME (TIMER_USEC*10LL) -#define BIOS_FILE L"roms/hdd/esdi_at/62-000279-061.bin" +#define BIOS_FILE "roms/hdd/esdi_at/62-000279-061.bin" #define STAT_ERR 0x01 #define STAT_INDEX 0x02 @@ -150,7 +148,7 @@ irq_lower(esdi_t *esdi) static __inline void irq_update(esdi_t *esdi) { - if (esdi->irqstat && !((pic2.pend | pic2.ins) & 0x40) && !(esdi->fdisk & 2)) + if (esdi->irqstat && !((pic2.irr | pic2.isr) & 0x40) && !(esdi->fdisk & 2)) picint(1 << 14); } @@ -192,7 +190,7 @@ get_sector(esdi_t *esdi, off64_t *addr) *addr = ((((off64_t)c * drive->real_hpc) + h) * drive->real_spt) + s; } - + return(0); } @@ -328,7 +326,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) esdi->command &= ~0x03; if (val & 0x02) fatal("Write with ECC\n"); - esdi->status = STAT_DRQ | STAT_DSC; + esdi->status = STAT_READY | STAT_DRQ | STAT_DSC; esdi->pos = 0; break; @@ -528,7 +526,7 @@ esdi_callback(void *priv) irq_raise(esdi); break; } - + hdd_image_read(drive->hdd_num, addr, 1, (uint8_t *)esdi->buffer); esdi->pos = 0; esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; @@ -550,7 +548,7 @@ esdi_callback(void *priv) irq_raise(esdi); break; } - + hdd_image_write(drive->hdd_num, addr, 1, (uint8_t *)esdi->buffer); irq_raise(esdi); esdi->secount = (esdi->secount - 1) & 0xff; @@ -605,7 +603,7 @@ esdi_callback(void *priv) irq_raise(esdi); break; } - + hdd_image_zero(drive->hdd_num, addr, esdi->secount); esdi->status = STAT_READY|STAT_DSC; irq_raise(esdi); @@ -744,7 +742,7 @@ esdi_callback(void *priv) static void -loadhd(esdi_t *esdi, int hdd_num, int d, const wchar_t *fn) +loadhd(esdi_t *esdi, int hdd_num, int d, const char *fn) { drive_t *drive = &esdi->drives[hdd_num]; @@ -843,13 +841,16 @@ wd1007vse1_available(void) return(rom_present(BIOS_FILE)); } - const device_t esdi_at_wd1007vse1_device = { - "Western Digital WD1007V-SE1 (ESDI)", - DEVICE_ISA | DEVICE_AT, - 0, - wd1007vse1_init, wd1007vse1_close, NULL, - wd1007vse1_available, - NULL, NULL, - NULL + .name = "Western Digital WD1007V-SE1 (ESDI)", + .internal_name = "esdi_at", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = wd1007vse1_init, + .close = wd1007vse1_close, + .reset = NULL, + { .available = wd1007vse1_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index a675b6abf..e0859697f 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -86,15 +86,15 @@ #define ESDI_IOADDR_SEC 0x3518 #define ESDI_IRQCHAN 14 -#define BIOS_FILE_L L"roms/hdd/esdi/90x8969.bin" -#define BIOS_FILE_H L"roms/hdd/esdi/90x8970.bin" +#define BIOS_FILE_L "roms/hdd/esdi/90x8969.bin" +#define BIOS_FILE_H "roms/hdd/esdi/90x8970.bin" -#define ESDI_TIME (200*TIMER_USEC) +#define ESDI_TIME 512 #define CMD_ADAPTER 0 -typedef struct esdi_drive { +typedef struct esdi_drive_t { int spt, hpc; int tracks; int sectors; @@ -102,12 +102,12 @@ typedef struct esdi_drive { int hdd_num; } drive_t; -typedef struct esdi { +typedef struct esdi_t { int8_t dma; uint32_t bios; rom_t bios_rom; - + uint8_t basic_ctrl; uint8_t status; uint8_t irq_status; @@ -129,20 +129,20 @@ typedef struct esdi { int sector_pos; int sector_count; - + int command; int cmd_state; - + int in_reset; uint64_t callback; pc_timer_t timer; - + uint32_t rba; - + struct { int req_in_progress; } cmds[3]; - + drive_t drives[2]; uint8_t pos_regs[8]; @@ -240,10 +240,10 @@ esdi_mca_set_callback(esdi_t *dev, uint64_t callback) if (callback) { dev->callback = callback; - timer_set_delay_u64(&dev->timer, dev->callback); + timer_on_auto(&dev->timer, dev->callback); } else { dev->callback = 0; - timer_disable(&dev->timer); + timer_stop(&dev->timer); } } @@ -279,8 +279,8 @@ device_not_present(esdi_t *dev) dev->status_data[3] = 0; dev->status_data[4] = 0; dev->status_data[5] = 0; - dev->status_data[6] = 0; - dev->status_data[7] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; dev->status_data[8] = 0; dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; @@ -300,8 +300,8 @@ rba_out_of_range(esdi_t *dev) dev->status_data[3] = 0; dev->status_data[4] = 0; dev->status_data[5] = 0; - dev->status_data[6] = 0; - dev->status_data[7] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; dev->status_data[8] = 0; dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; @@ -348,7 +348,7 @@ complete_command_status(esdi_t *dev) else \ drive = &dev->drives[1]; \ } while (0) - + static void esdi_callback(void *priv) @@ -393,12 +393,12 @@ esdi_callback(void *priv) dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; dev->irq_in_progress = 1; set_irq(dev); - + dev->cmd_state = 1; esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; - + case 1: if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { esdi_mca_set_callback(dev, ESDI_TIME); @@ -415,7 +415,7 @@ esdi_callback(void *priv) while (dev->data_pos < 256) { val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); - + if (val == DMA_NODATA) { esdi_mca_set_callback(dev, ESDI_TIME); return; @@ -451,7 +451,7 @@ esdi_callback(void *priv) device_not_present(dev); return; } - + switch (dev->cmd_state) { case 0: dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; @@ -468,7 +468,7 @@ esdi_callback(void *priv) dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; dev->irq_in_progress = 1; set_irq(dev); - + dev->cmd_state = 1; esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; @@ -483,7 +483,7 @@ esdi_callback(void *priv) while (dev->sector_pos < dev->sector_count) { while (dev->data_pos < 256) { val = dma_channel_read(dev->dma); - + if (val == DMA_NODATA) { esdi_mca_set_callback(dev, ESDI_TIME); return; @@ -651,7 +651,7 @@ esdi_callback(void *priv) esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; - + case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { esdi_mca_set_callback(dev, ESDI_TIME); @@ -660,7 +660,7 @@ esdi_callback(void *priv) while (dev->sector_pos < dev->sector_count) { while (dev->data_pos < 256) { val = dma_channel_read(dev->dma); - + if (val == DMA_NODATA) { esdi_mca_set_callback(dev, ESDI_TIME); return; @@ -717,7 +717,7 @@ esdi_callback(void *priv) memcpy(dev->data, dev->sector_buffer[dev->sector_pos++], 512); while (dev->data_pos < 256) { val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); - + if (val == DMA_NODATA) { esdi_mca_set_callback(dev, ESDI_TIME); return; @@ -733,7 +733,7 @@ esdi_callback(void *priv) dev->cmd_state = 2; esdi_mca_set_callback(dev, ESDI_TIME); break; - + case 2: dev->status = STATUS_IRQ; dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; @@ -766,41 +766,41 @@ esdi_callback(void *priv) device_not_present(dev); return; } - + switch (dev->cmd_state) { case 0: dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; - + dev->sector_count = dev->cmd_data[1]; - + if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { rba_out_of_range(dev); return; } - + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; dev->irq_in_progress = 1; set_irq(dev); - + dev->cmd_state = 1; esdi_mca_set_callback(dev, ESDI_TIME); break; - + case 1: if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { esdi_mca_set_callback(dev, ESDI_TIME); return; } - + hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); - + dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; esdi_mca_set_callback(dev, ESDI_TIME); break; - + case 2: complete_command_status(dev); dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; @@ -824,11 +824,11 @@ esdi_read(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port & 7) { - case 2: /*Basic status register*/ + case 2: /*Basic status register*/ ret = dev->status; break; - case 3: /*IRQ status*/ + case 3: /*IRQ status*/ dev->status &= ~STATUS_IRQ; ret = dev->irq_status; break; @@ -886,7 +886,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; break; - + default: fatal("Bad attention request %02x\n", val); } @@ -903,13 +903,13 @@ esdi_write(uint16_t port, uint8_t val, void *priv) dev->cmd_pos = 0; dev->status_pos = 0; break; - + case ATTN_EOI: dev->irq_in_progress = 0; dev->status &= ~STATUS_IRQ; clear_irq(dev); break; - + default: fatal("Bad attention request %02x\n", val); } @@ -932,7 +932,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) dev->status &= ~STATUS_IRQ; clear_irq(dev); break; - + default: fatal("Bad attention request %02x\n", val); } @@ -968,7 +968,7 @@ esdi_readw(uint16_t port, void *priv) default: fatal("esdi_readw port=%04x\n", port); } - + return(ret); } @@ -1178,10 +1178,16 @@ esdi_available(void) return(rom_present(BIOS_FILE_L) && rom_present(BIOS_FILE_H)); } - const device_t esdi_ps2_device = { - "IBM ESDI Fixed Disk Adapter (MCA)", - DEVICE_MCA, 0, - esdi_init, esdi_close, NULL, - esdi_available, NULL, NULL, NULL + .name = "IBM PS/2 ESDI Fixed Disk Adapter (MCA)", + .internal_name = "esdi_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = esdi_init, + .close = esdi_close, + .reset = NULL, + { .available = esdi_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 5c40d1b69..b49e2e926 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -17,9 +17,6 @@ * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #include #include #include @@ -39,6 +36,7 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/scsi_device.h> +#include <86box/isapnp.h> #include <86box/cdrom.h> #include <86box/plat.h> #include <86box/ui.h> @@ -46,6 +44,7 @@ #include <86box/hdc_ide.h> #include <86box/hdd.h> #include <86box/zip.h> +#include <86box/version.h> /* Bits of 'atastat' */ @@ -53,8 +52,8 @@ #define IDX_STAT 0x02 /* Index */ #define CORR_STAT 0x04 /* Corrected data */ #define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 /* Drive seek complete */ -#define SERVICE_STAT 0x10 /* ATAPI service */ +#define DSC_STAT 0x10 /* Drive seek complete */ +#define SERVICE_STAT 0x10 /* ATAPI service */ #define DWF_STAT 0x20 /* Drive write fault */ #define DRDY_STAT 0x40 /* Ready */ #define BSY_STAT 0x80 /* Busy */ @@ -74,24 +73,24 @@ #define WIN_SRST 0x08 /* ATAPI Device Reset */ #define WIN_RECAL 0x10 #define WIN_READ 0x20 /* 28-Bit Read */ -#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry */ #define WIN_WRITE 0x30 /* 28-Bit Write */ #define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write - no retry */ #define WIN_VERIFY 0x40 /* 28-Bit Verify */ #define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ #define WIN_FORMAT 0x50 #define WIN_SEEK 0x70 -#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ #define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ #define WIN_PACKETCMD 0xA0 /* Send a packet command. */ #define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ -#define WIN_READ_MULTIPLE 0xC4 -#define WIN_WRITE_MULTIPLE 0xC5 -#define WIN_SET_MULTIPLE_MODE 0xC6 -#define WIN_READ_DMA 0xC8 -#define WIN_READ_DMA_ALT 0xC9 -#define WIN_WRITE_DMA 0xCA -#define WIN_WRITE_DMA_ALT 0xCB +#define WIN_READ_MULTIPLE 0xC4 +#define WIN_WRITE_MULTIPLE 0xC5 +#define WIN_SET_MULTIPLE_MODE 0xC6 +#define WIN_READ_DMA 0xC8 +#define WIN_READ_DMA_ALT 0xC9 +#define WIN_WRITE_DMA 0xCA +#define WIN_WRITE_DMA_ALT 0xCB #define WIN_STANDBYNOW1 0xE0 #define WIN_IDLENOW1 0xE1 #define WIN_SETIDLE1 0xE3 @@ -130,6 +129,53 @@ typedef struct { static ide_board_t *ide_boards[4] = { NULL, NULL, NULL, NULL }; static ide_bm_t *ide_bm[4] = { NULL, NULL, NULL, NULL }; +static uint8_t ide_ter_pnp_rom[] = { + 0x09, 0xf8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0001, serial 0, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x0e, 0x00, 'I', 'D', 'E', ' ', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', /* ANSI identifier */ + + 0x15, 0x09, 0xf8, 0x00, 0x01, 0x00, /* logical device BOX0001 */ + 0x1c, 0x41, 0xd0, 0x06, 0x00, /* compatible device PNP0600 */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x00, 0x04, /* IRQ 10 */ + 0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ + 0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x01, 0xff, 0xff, 0x01, 0x01, /* I/O 0x100-0xFFFF, decodes 16-bit, 1-byte alignment, 1 address */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; +static uint8_t ide_qua_pnp_rom[] = { + 0x09, 0xf8, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, /* BOX0001, serial 1, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x0e, 0x00, 'I', 'D', 'E', ' ', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', /* ANSI identifier */ + + 0x15, 0x09, 0xf8, 0x00, 0x01, 0x00, /* logical device BOX0001 */ + 0x1c, 0x41, 0xd0, 0x06, 0x00, /* compatible device PNP0600 */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x00, 0x08, /* IRQ 11 */ + 0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ + 0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */ + 0x30, /* start dependent functions, acceptable */ + 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x01, 0xff, 0xff, 0x01, 0x01, /* I/O 0x100-0xFFFF, decodes 16-bit, 1-byte alignment, 1 address */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + ide_t *ide_drives[IDE_NUM]; int ide_ter_enabled = 0, ide_qua_enabled = 0; @@ -174,7 +220,7 @@ ide_get_drive(int ch) double -ide_get_period(ide_t *ide, int size) +ide_get_xfer_time(ide_t *ide, int size) { double period = (10.0 / 3.0); @@ -259,7 +305,7 @@ double ide_atapi_get_period(uint8_t channel) { ide_t *ide = ide_drives[channel]; - + ide_log("ide_atapi_get_period(%i)\n", channel); if (!ide) { @@ -267,7 +313,7 @@ ide_atapi_get_period(uint8_t channel) return -1.0; } - return ide_get_period(ide, 1); + return ide_get_xfer_time(ide, 1); } @@ -396,7 +442,7 @@ ide_get_max(ide_t *ide, int type) switch(type) { case TYPE_PIO: /* PIO */ if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 1; + return 4; return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ case TYPE_SDMA: /* SDMA */ @@ -411,7 +457,7 @@ ide_get_max(ide_t *ide, int type) return -1; case TYPE_UDMA: /* UDMA */ if (!ide_boards[ide->board]->force_ata3 && (ide_bm[ide->board] != NULL)) - return 4 /*2*/; + return 5; return -1; default: @@ -485,10 +531,11 @@ static void ide_hd_identify(ide_t *ide) ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[0] = (1 << 6); /*Fixed drive*/ ide->buffer[20] = 3; /*Buffer type*/ - ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[21] = hdd[ide->hdd_num].cache.num_segments * hdd[ide->hdd_num].cache.segment_size; /*Buffer size*/ ide->buffer[50] = 0x4000; /* Capabilities */ ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; @@ -530,12 +577,11 @@ static void ide_hd_identify(ide_t *ide) ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); } + ide->buffer[47] = hdd[ide->hdd_num].max_multiple_block | 0x8000; /*Max sectors on multiple transfer command*/ if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board]) { - ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ - ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ - ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ + ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/ + ide->buffer[81] = 0x19; /*ATA-6 revision 3a supported*/ } else { - ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/ ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ } } @@ -545,6 +591,7 @@ static void ide_identify(ide_t *ide) { int d, i, max_pio, max_sdma, max_mdma, max_udma; + ide_t *ide_other = ide_drives[ide->channel ^ 1]; ide_log("IDE IDENTIFY or IDENTIFY PACKET DEVICE on board %i (channel %i)\n", ide->board, ide->channel); @@ -571,7 +618,8 @@ ide_identify(ide_t *ide) ide->buffer[51] = ide_get_timings(ide, TIMINGS_PIO); ide->buffer[53] &= 0xfff9; ide->buffer[52] = ide->buffer[62] = ide->buffer[63] = ide->buffer[64] = 0x0000; - ide->buffer[65] = ide->buffer[66] = ide->buffer[67] = ide->buffer[68] = 0x0000; + ide->buffer[65] = ide->buffer[66] = ide_get_timings(ide, TIMINGS_DMA); + ide->buffer[67] = ide->buffer[68] = 0x0000; ide->buffer[88] = 0x0000; if (max_pio >= 3) { @@ -593,6 +641,18 @@ ide_identify(ide_t *ide) ide->buffer[53] |= 0x0004; for (i = 0; i <= max_udma; i++) ide->buffer[88] |= (1 << i); + if (max_udma >= 4) + ide->buffer[93] = 0x6000; /* Drive reports 80-conductor cable */ + + if (ide->channel & 1) + ide->buffer[93] |= 0x0b00; + else { + ide->buffer[93] |= 0x000b; + /* PDIAG- is assered by device 1, so the bit should be 1 if there's a device 1, + so it should be |= 0x001b if device 1 is present. */ + if (ide_other != NULL) + ide->buffer[93] |= 0x0010; + } } if ((max_sdma != -1) || (max_mdma != -1) || (max_udma != -1)) { @@ -631,13 +691,15 @@ ide_get_sector(ide_t *ide) uint32_t heads, sectors; if (ide->lba) - return (off64_t)ide->lba_addr + ide->skip512; + return (off64_t)ide->lba_addr; else { heads = ide->cfg_hpc; sectors = ide->cfg_spt; + uint8_t sector = ide->sector ? ide->sector : 1; + return ((((off64_t) ide->cylinder * heads) + ide->head) * - sectors) + (ide->sector - 1) + ide->skip512; + sectors) + (sector - 1); } } @@ -665,13 +727,15 @@ ide_next_sector(ide_t *ide) static void -loadhd(ide_t *ide, int d, const wchar_t *fn) +loadhd(ide_t *ide, int d, const char *fn) { if (! hdd_image_load(d)) { ide->type = IDE_NONE; return; } + hdd_preset_apply(d); + ide->spt = ide->cfg_spt = hdd[d].spt; ide->hpc = ide->cfg_hpc = hdd[d].hpc; ide->tracks = hdd[d].tracks; @@ -720,7 +784,7 @@ ide_set_features(ide_t *ide) mode = (features_data >> 3); submode = features_data & 7; - switch(mode) { + switch (mode) { case 0x00: /* PIO default */ if (submode != 0) return 0; @@ -853,17 +917,18 @@ ide_atapi_attach(ide_t *ide) void ide_set_callback(ide_t *ide, double callback) { - ide_log("ide_set_callback(%i)\n", ide->channel); if (!ide) { - ide_log("Set callback failed\n"); + ide_log("ide_set_callback(NULL): Set callback failed\n"); return; } + ide_log("ide_set_callback(%i)\n", ide->channel); + if (callback == 0.0) timer_stop(&ide->timer); else - timer_on_auto(&ide->timer, callback); + timer_on_auto(&ide->timer, callback); } @@ -872,7 +937,7 @@ ide_set_board_callback(uint8_t board, double callback) { ide_board_t *dev = ide_boards[board]; - ide_log("ide_set_callback(%i)\n", board); + ide_log("ide_set_board_callback(%i)\n", board); if (!dev) { ide_log("Set board callback failed\n"); @@ -882,7 +947,7 @@ ide_set_board_callback(uint8_t board, double callback) if (callback == 0.0) timer_stop(&dev->timer); else - timer_on_auto(&dev->timer, callback); + timer_on_auto(&dev->timer, callback); } @@ -959,7 +1024,7 @@ ide_atapi_callback(ide_t *ide) } if (ret == 0) { - if (ide->bus_master_error) + if (ide->bus_master_error) ide->bus_master_error(ide->sc); } else if (ret == 1) { if (out && ide->phase_data_out) @@ -1050,7 +1115,7 @@ ide_atapi_packet_read(ide_t *ide, int length) return 0; if (dev->packet_status == PHASE_DATA_IN) - ide_log("PHASE_DATA_IN read: %i, %i< %i, %i\n", dev->request_pos, dev->max_transfer_len, dev->pos, dev->packet_len); + ide_log("PHASE_DATA_IN read: %i, %i, %i, %i\n", dev->request_pos, dev->max_transfer_len, dev->pos, dev->packet_len); bufferw = (uint16_t *) dev->temp_buffer; bufferl = (uint32_t *) dev->temp_buffer; @@ -1164,31 +1229,41 @@ ide_write_data(ide_t *ide, uint32_t val, int length) if (ide->type == IDE_ATAPI) ide_atapi_packet_write(ide, val, length); } else { - switch(length) { - case 1: - idebufferb[ide->pos] = val & 0xff; - ide->pos++; - break; - case 2: - idebufferw[ide->pos >> 1] = val & 0xffff; - ide->pos += 2; - break; - case 4: - idebufferl[ide->pos >> 2] = val; - ide->pos += 4; - break; - default: - return; - } + switch(length) { + case 1: + idebufferb[ide->pos] = val & 0xff; + ide->pos++; + break; + case 2: + idebufferw[ide->pos >> 1] = val & 0xffff; + ide->pos += 2; + break; + case 4: + idebufferl[ide->pos >> 2] = val; + ide->pos += 4; + break; + default: + return; + } - if (ide->pos >= 512) { - ide->pos=0; - ide->atastat = BSY_STAT; - if (ide->command == WIN_WRITE_MULTIPLE) - ide_callback(ide); - else - ide_set_callback(ide, ide_get_period(ide, 512)); - } + if (ide->pos >= 512) { + ide->pos=0; + ide->atastat = BSY_STAT; + double seek_time = hdd_timing_write(&hdd[ide->hdd_num], ide_get_sector(ide), 1); + double xfer_time = ide_get_xfer_time(ide, 512); + double wait_time = seek_time + xfer_time; + if (ide->command == WIN_WRITE_MULTIPLE) { + if ((ide->blockcount+1) >= ide->blocksize || ide->secount == 1) { + ide_set_callback(ide, seek_time + xfer_time + ide->pending_delay); + ide->pending_delay = 0; + } else { + ide->pending_delay += wait_time; + ide_callback(ide); + } + } else { + ide_set_callback(ide, wait_time); + } + } } } @@ -1292,13 +1367,35 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) return; dev->diag = 0; - + if ((val & 4) && !(ide->fdisk & 4)) { /* Reset toggled from 0 to 1, initiate reset procedure. */ if (ide->type == IDE_ATAPI) ide->sc->callback = 0.0; ide_set_callback(ide, 0.0); ide_set_callback(ide_other, 0.0); + + /* We must set set the status to busy in reset mode or + some 286 and 386 machines error out. */ + if (!(ch & 1)) { + if (ide->type != IDE_NONE) { + ide->atastat = BSY_STAT; + ide->error = 1; + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->error = 1; + } + } + + if (ide_other->type != IDE_NONE) { + ide_other->atastat = BSY_STAT; + ide_other->error = 1; + if (ide_other->type == IDE_ATAPI) { + ide_other->sc->status = BSY_STAT; + ide_other->sc->error = 1; + } + } + } } else if (!(val & 4) && (ide->fdisk & 4)) { /* Reset toggled from 1 to 0. */ if (!(ch & 1)) { @@ -1326,7 +1423,7 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide->reset = 1; ide_set_callback(ide, 0.0); ide_set_callback(ide_other, 0.0); - ide_set_board_callback(ide->board, 500 * IDE_TIME); + ide_set_board_callback(ide->board, 1000.4); /* 1 ms + 400 ns, per the specification */ } else { /* Currently active device is 1, simply reset the status and the active device. */ dev_reset(ide); @@ -1488,7 +1585,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; } } - + ide->head = val & 0xF; ide->lba = val & 0x40; ide_other->head = val & 0xF; @@ -1515,11 +1612,15 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) if (ide->type == IDE_ATAPI) ide->sc->status = DRDY_STAT; else - ide->atastat = BSY_STAT; + ide->atastat = READY_STAT | BSY_STAT; - if (ide->type == IDE_ATAPI) + if (ide->type == IDE_ATAPI) { ide->sc->callback = 100.0 * IDE_TIME; - ide_set_callback(ide, 100.0 * IDE_TIME); + ide_set_callback(ide, 100.0 * IDE_TIME); + } else { + double seek_time = hdd_seek_get_time(&hdd[ide->hdd_num], ide_get_sector(ide), HDD_OP_SEEK, 0, 0.0); + ide_set_callback(ide, seek_time); + } return; } @@ -1530,7 +1631,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->sc->callback = 100.0 * IDE_TIME; } else ide->atastat = DRDY_STAT; - + ide_set_callback(ide, 100.0 * IDE_TIME); return; @@ -1541,9 +1642,6 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ ide->blockcount = 0; - /* Turn on the activity indicator *here* so that it gets turned on - less times. */ - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); /*FALLTHROUGH*/ case WIN_READ: @@ -1557,23 +1655,34 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->atastat = BSY_STAT; if (ide->type == IDE_HDD) { + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + uint32_t sec_count; + double wait_time; if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { - if (ide->secount) - ide_set_callback(ide, ide_get_period(ide, (int) ide->secount << 9)); - else - ide_set_callback(ide, ide_get_period(ide, 131072)); - } else if (val == WIN_READ_MULTIPLE) - ide_set_callback(ide, 200.0 * IDE_TIME); - else - ide_set_callback(ide, ide_get_period(ide, 512)); + // TODO make DMA timing more accurate + sec_count = ide->secount ? ide->secount : 256; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); + wait_time = seek_time > xfer_time ? seek_time : xfer_time; + } else if (val == WIN_READ_MULTIPLE) { + sec_count = (ide->secount < ide->blocksize) ? ide->secount : ide->blocksize; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); + wait_time = seek_time + xfer_time; + } else { + sec_count = 1; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); + wait_time = seek_time + xfer_time; + } + ide_set_callback(ide, wait_time); } else ide_set_callback(ide, 200.0 * IDE_TIME); ide->do_initial_read = 1; return; case WIN_WRITE_MULTIPLE: - if (!ide->blocksize && (ide->type != IDE_ATAPI)) - fatal("Write_MULTIPLE - blocksize = 0\n"); + /* Fatal removed for the same reason as for WIN_READ_MULTIPLE. */ ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on less times. */ @@ -1606,14 +1715,16 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) if ((ide->type == IDE_HDD) && ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { - if (ide->secount) - ide_set_callback(ide, ide_get_period(ide, (int) ide->secount << 9)); - else - ide_set_callback(ide, ide_get_period(ide, 131072)); + uint32_t sec_count = ide->secount ? ide->secount : 256; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); + double wait_time = seek_time > xfer_time ? seek_time : xfer_time; + ide_set_callback(ide, wait_time); } else if ((ide->type == IDE_HDD) && - ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) - ide_set_callback(ide, ide_get_period(ide, 512)); - else if (val == WIN_IDENTIFY) + ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) { + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), ide->secount); + ide_set_callback(ide, seek_time + ide_get_xfer_time(ide, 2)); + } else if (val == WIN_IDENTIFY) ide_callback(ide); else ide_set_callback(ide, 200.0 * IDE_TIME); @@ -1668,7 +1779,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->reset = 1; ide_set_callback(ide, 0.0); ide_set_callback(ide_other, 0.0); - ide_set_board_callback(ide->board, 200 * IDE_TIME); + ide_set_board_callback(ide->board, 200.0 * IDE_TIME); return; case WIN_PIDENTIFY: /* Identify Packet Device */ @@ -1780,11 +1891,21 @@ ide_read_data(ide_t *ide, int length) if (ide->secount) { ide_next_sector(ide); ide->atastat = BSY_STAT | READY_STAT | DSC_STAT; - if (ide->command == WIN_READ_MULTIPLE) - ide_callback(ide); - else - ide_set_callback(ide, ide_get_period(ide, 512)); - } else if (ide->command != WIN_READ_MULTIPLE) + if (ide->command == WIN_READ_MULTIPLE) { + if (!ide->blockcount) { + uint32_t sec_count = (ide->secount < ide->blocksize) ? ide->secount : ide->blocksize; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); + double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); + ide_set_callback(ide, seek_time + xfer_time); + } else { + ide_callback(ide); + } + } else { + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), 1); + double xfer_time = ide_get_xfer_time(ide, 512); + ide_set_callback(ide, seek_time + xfer_time); + } + } else ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); } } @@ -1797,7 +1918,11 @@ static uint8_t ide_status(ide_t *ide, ide_t *ide_other, int ch) { if ((ide->type == IDE_NONE) && ((ide_other->type == IDE_NONE) || !(ch & 1))) +#ifdef STATUS_BIT_7_PULLDOWN return 0x7F; /* Bit 7 pulled down, all other bits pulled up, per the spec. */ +#else + return 0xFF; +#endif else if ((ide->type == IDE_NONE) && (ch & 1)) return 0x00; /* On real hardware, a slave with a present master always returns a status of 0x00. */ else if (ide->type == IDE_ATAPI) @@ -2015,6 +2140,23 @@ ide_board_callback(void *priv) } +static void +atapi_error_no_ready(ide_t *ide) +{ + ide->command = 0; + if (ide->type == IDE_ATAPI) { + ide->sc->status = ERR_STAT | DSC_STAT; + ide->sc->error = ABRT_ERR; + ide->sc->pos = 0; + } else { + ide->atastat = ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + } + ide_irq_raise(ide); +} + + static void ide_callback(void *priv) { @@ -2026,8 +2168,10 @@ ide_callback(void *priv) if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { - if (ide->type != IDE_HDD) - goto abort_cmd; + if (ide->type != IDE_HDD) { + atapi_error_no_ready(ide); + return; + } if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F) && !ide->lba) { if ((ide->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || !ide->sector || (ide->sector > ide->spt)) @@ -2046,7 +2190,7 @@ ide_callback(void *priv) ide->atastat = DRDY_STAT | DSC_STAT; ide->error = 1; /*Device passed*/ ide->secount = 1; - ide->sector = 1; + ide->sector = 1; ide_set_signature(ide); @@ -2265,7 +2409,13 @@ ide_callback(void *priv) return; case WIN_WRITE_MULTIPLE: - if (ide->type == IDE_ATAPI) + /* According to the official ATA reference: + + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + if ((ide->type == IDE_ATAPI) || !ide->blocksize) goto abort_cmd; if (!ide->lba && (ide->cfg_spt == 0)) goto id_not_found; @@ -2319,7 +2469,7 @@ ide_callback(void *priv) ide->cfg_spt = ide->secount; ide->cfg_hpc = ide->head + 1; } - ide->command = 0x00; + ide->command = 0x00; ide->atastat = DRDY_STAT | DSC_STAT; ide->error = 1; ide_irq_raise(ide); @@ -2415,7 +2565,61 @@ id_not_found: } -static void +uint8_t +ide_read_ali_75(void) +{ + ide_t *ide0, *ide1; + int ch0, ch1; + uint8_t ret = 0x00; + + ch0 = ide_boards[0]->cur_dev; + ch1 = ide_boards[1]->cur_dev; + ide0 = ide_drives[ch0]; + ide1 = ide_drives[ch1]; + + if (ch1) + ret |= 0x08; + if (ch0) + ret |= 0x04; + if (ide1->irqstat) + ret |= 0x02; + if (ide0->irqstat) + ret |= 0x01; + + return ret; +} + + +uint8_t +ide_read_ali_76(void) +{ + ide_t *ide0, *ide1; + int ch0, ch1; + uint8_t ret = 0x00; + + ch0 = ide_boards[0]->cur_dev; + ch1 = ide_boards[1]->cur_dev; + ide0 = ide_drives[ch0]; + ide1 = ide_drives[ch1]; + + if (ide1->atastat & BSY_STAT) + ret |= 0x40; + if (ide1->atastat & DRQ_STAT) + ret |= 0x20; + if (ide1->atastat & ERR_STAT) + ret |= 0x10; + if (ide0->atastat & BSY_STAT) + ret |= 0x04; + if (ide0->atastat & DRQ_STAT) + ret |= 0x02; + if (ide0->atastat & ERR_STAT) + ret |= 0x01; + + return ret; +} + + +void ide_set_handlers(uint8_t board) { if (ide_boards[board] == NULL) @@ -2437,7 +2641,7 @@ ide_set_handlers(uint8_t board) } -static void +void ide_remove_handlers(uint8_t board) { if (ide_boards[board] == NULL) @@ -2676,10 +2880,54 @@ ide_board_init(int board, int irq, int base_main, int side_main, int type) } +void +ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + intptr_t board = (intptr_t) priv; + + if (ld) + return; + + if (ide_boards[board]->base_main || ide_boards[board]->side_main) { + ide_remove_handlers(board); + ide_boards[board]->base_main = ide_boards[board]->side_main = 0; + } + + ide_boards[board]->irq = -1; + + if (config->activate) { + ide_boards[board]->base_main = (config->io[0].base != ISAPNP_IO_DISABLED) ? config->io[0].base : 0x0000; + ide_boards[board]->side_main = (config->io[1].base != ISAPNP_IO_DISABLED) ? config->io[1].base : 0x0000; + + if (ide_boards[board]->base_main && ide_boards[board]->side_main) + ide_set_handlers(board); + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) + ide_boards[board]->irq = config->irq[0].irq; + } +} + + static void * ide_ter_init(const device_t *info) { - ide_board_init(2, device_get_config_int("irq"), 0x168, 0x36e, info->local); + /* Don't claim this channel again if it was already claimed. */ + if (ide_boards[2]) + return(NULL); + + int irq; + if (info->local) + irq = -2; + else + irq = device_get_config_int("irq"); + + if (irq < 0) { + ide_board_init(2, -1, 0, 0, 0); + if (irq == -1) + isapnp_add_card(ide_ter_pnp_rom, sizeof(ide_ter_pnp_rom), ide_pnp_config_changed, NULL, NULL, NULL, (void *) 2); + } else { + ide_board_init(2, irq, 0x168, 0x36e, 0); + } return(ide_boards[2]); } @@ -2696,7 +2944,23 @@ ide_ter_close(void *priv) static void * ide_qua_init(const device_t *info) { - ide_board_init(3, device_get_config_int("irq"), 0x1e8, 0x3ee, info->local); + /* Don't claim this channel again if it was already claimed. */ + if (ide_boards[3]) + return(NULL); + + int irq; + if (info->local) + irq = -2; + else + irq = device_get_config_int("irq"); + + if (irq < 0) { + ide_board_init(3, -1, 0, 0, 0); + if (irq == -1) + isapnp_add_card(ide_qua_pnp_rom, sizeof(ide_qua_pnp_rom), ide_pnp_config_changed, NULL, NULL, NULL, (void *) 3); + } else { + ide_board_init(3, irq, 0x1e8, 0x3ee, 0); + } return(ide_boards[3]); } @@ -2813,8 +3077,11 @@ ide_reset(void *p) { ide_log("Resetting IDE...\n"); - ide_board_reset(0); - ide_board_reset(1); + if (ide_boards[0] != NULL) + ide_board_reset(0); + + if (ide_boards[1] != NULL) + ide_board_reset(1); } @@ -2824,157 +3091,207 @@ ide_close(void *priv) { ide_log("Closing IDE...\n"); - ide_board_close(0); - ide_board_close(1); + if (ide_boards[0] != NULL) { + ide_board_close(0); + ide_boards[0] = NULL; + } + + if (ide_boards[1] != NULL) { + ide_board_close(1); + ide_boards[1] = NULL; + } } - const device_t ide_isa_device = { - "ISA PC/AT IDE Controller", - DEVICE_ISA | DEVICE_AT, - 0, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL + .name = "ISA PC/AT IDE Controller", + .internal_name = "ide_isa", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t ide_isa_2ch_device = { - "ISA PC/AT IDE Controller (Dual-Channel)", - DEVICE_ISA | DEVICE_AT, - 1, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL + .name = "ISA PC/AT IDE Controller (Dual-Channel)", + .internal_name = "ide_isa_2ch", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 1, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t ide_vlb_device = { - "VLB IDE Controller", - DEVICE_VLB | DEVICE_AT, - 2, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL + .name = "VLB IDE Controller", + .internal_name = "ide_vlb", + .flags = DEVICE_VLB | DEVICE_AT, + .local = 2, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t ide_vlb_2ch_device = { - "VLB IDE Controller (Dual-Channel)", - DEVICE_VLB | DEVICE_AT, - 3, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL + .name = "VLB IDE Controller (Dual-Channel)", + .internal_name = "ide_vlb_2ch", + .flags = DEVICE_VLB | DEVICE_AT, + .local = 3, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t ide_pci_device = { - "PCI IDE Controller", - DEVICE_PCI | DEVICE_AT, - 4, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL + .name = "PCI IDE Controller", + .internal_name = "ide_pci", + .flags = DEVICE_PCI | DEVICE_AT, + .local = 4, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t ide_pci_2ch_device = { - "PCI IDE Controller (Dual-Channel)", - DEVICE_PCI | DEVICE_AT, - 5, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL + .name = "PCI IDE Controller (Dual-Channel)", + .internal_name = "ide_pci_2ch", + .flags = DEVICE_PCI | DEVICE_AT, + .local = 5, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -static const device_config_t ide_ter_config[] = -{ - { - "irq", "IRQ", CONFIG_SELECTION, "", 10, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 9", 9 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "" - } - } - }, - { - "", "", -1 +// clang-format off +static const device_config_t ide_ter_config[] = { + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 10, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Plug and Play", .value = -1 }, + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "" } } + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t ide_qua_config[] = -{ - { - "irq", "IRQ", CONFIG_SELECTION, "", 11, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 9", 9 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "" - } - } - }, - { - "", "", -1 +static const device_config_t ide_qua_config[] = { + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 11, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Plug and Play", .value = -1 }, + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "" } } + }, + { .name = "", .description = "", .type = CONFIG_END } }; +// clang-format on const device_t ide_ter_device = { - "Tertiary IDE Controller", - DEVICE_AT, - 0, - ide_ter_init, ide_ter_close, NULL, - NULL, NULL, NULL, - ide_ter_config + .name = "Tertiary IDE Controller", + .internal_name = "ide_ter", + .flags = DEVICE_AT, + .local = 0, + .init = ide_ter_init, + .close = ide_ter_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ide_ter_config +}; + +const device_t ide_ter_pnp_device = { + .name = "Tertiary IDE Controller (Plug and Play only)", + .internal_name = "ide_ter_pnp", + .flags = DEVICE_AT, + .local = 1, + .init = ide_ter_init, + .close = ide_ter_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t ide_qua_device = { - "Quaternary IDE Controller", - DEVICE_AT, - 0, - ide_qua_init, ide_qua_close, NULL, - NULL, NULL, NULL, - ide_qua_config + .name = "Quaternary IDE Controller", + .internal_name = "ide_qua", + .flags = DEVICE_AT, + .local = 0, + .init = ide_qua_init, + .close = ide_qua_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ide_qua_config +}; + +const device_t ide_qua_pnp_device = { + .name = "Quaternary IDE Controller (Plug and Play only)", + .internal_name = "ide_qua_pnp", + .flags = DEVICE_AT, + .local = 1, + .init = ide_qua_init, + .close = ide_qua_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ide_qua_config }; diff --git a/src/disk/hdc_ide_cmd640.c b/src/disk/hdc_ide_cmd640.c new file mode 100644 index 000000000..79c6e4f97 --- /dev/null +++ b/src/disk/hdc_ide_cmd640.c @@ -0,0 +1,562 @@ +/* + * 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 CMD PCI-0640B controller. + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/cdrom.h> +#include <86box/scsi_device.h> +#include <86box/scsi_cdrom.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/zip.h> +#include <86box/mo.h> + + +typedef struct +{ + uint8_t vlb_idx, id, + in_cfg, single_channel, + pci, regs[256]; + uint32_t local; + int slot, irq_mode[2], + irq_pin, irq_line; +} cmd640_t; + + +static int next_id = 0; + + +#ifdef ENABLE_CMD640_LOG +int cmd640_do_log = ENABLE_CMD640_LOG; +static void +cmd640_log(const char *fmt, ...) +{ + va_list ap; + + if (cmd640_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cmd640_log(fmt, ...) +#endif + + +void +cmd640_set_irq(int channel, void *priv) +{ + cmd640_t *dev = (cmd640_t *) priv; + int irq = !!(channel & 0x40); + + if (channel & 0x01) { + if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) { + dev->regs[0x57] &= ~0x10; + dev->regs[0x57] |= (channel >> 2); + } + } else { + if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) { + dev->regs[0x50] &= ~0x04; + dev->regs[0x50] |= (channel >> 4); + } + } + + channel &= 0x01; + if (irq) { + if (dev->irq_mode[channel] == 1) + pci_set_irq(dev->slot, dev->irq_pin); + else + picint(1 << (14 + channel)); + } else { + if (dev->irq_mode[channel] == 1) + pci_clear_irq(dev->slot, dev->irq_pin); + else + picintc(1 << (14 + channel)); + } +} + + +static void +cmd640_ide_handlers(cmd640_t *dev) +{ + uint16_t main, side; + + ide_pri_disable(); + + if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) { + main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8); + side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2; + } else { + main = 0x1f0; + side = 0x3f6; + } + + ide_set_base(0, main); + ide_set_side(0, side); + + if (dev->regs[0x04] & 0x01) + ide_pri_enable(); + + if (dev->single_channel) + return; + + ide_sec_disable(); + + if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) { + main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8); + side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2; + } else { + main = 0x170; + side = 0x376; + } + + ide_set_base(1, main); + ide_set_side(1, side); + + if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08)) + ide_sec_enable(); +} + + +static void +cmd640_common_write(int addr, uint8_t val, cmd640_t *dev) +{ + switch (addr) { + case 0x51: + dev->regs[addr] = val; + cmd640_ide_handlers(dev); + break; + case 0x52: case 0x54: case 0x56: case 0x58: + case 0x59: + dev->regs[addr] = val; + break; + case 0x53: case 0x55: + dev->regs[addr] = val & 0xc0; + break; + case 0x57: + dev->regs[addr] = val & 0xdc; + break; + case 0x5b: /* Undocumented register that Linux attempts to use! */ + dev->regs[addr] = val; + break; + } +} + + +static void +cmd640_vlb_write(uint16_t addr, uint8_t val, void *priv) +{ + cmd640_t *dev = (cmd640_t *) priv; + + addr &= 0x00ff; + + switch (addr) { + case 0x0078: + if (dev->in_cfg) + dev->vlb_idx = val; + else if ((dev->regs[0x50] & 0x80) && (val == dev->id)) + dev->in_cfg = 1; + break; + case 0x007c: + cmd640_common_write(dev->vlb_idx, val, dev); + if (dev->regs[0x50] & 0x80) + dev->in_cfg = 0; + break; + } +} + + +static void +cmd640_vlb_writew(uint16_t addr, uint16_t val, void *priv) +{ + cmd640_vlb_write(addr, val & 0xff, priv); + cmd640_vlb_write(addr + 1, val >> 8, priv); +} + + +static void +cmd640_vlb_writel(uint16_t addr, uint32_t val, void *priv) +{ + cmd640_vlb_writew(addr, val & 0xffff, priv); + cmd640_vlb_writew(addr + 2, val >> 16, priv); +} + + +static uint8_t +cmd640_vlb_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + cmd640_t *dev = (cmd640_t *) priv; + + addr &= 0x00ff; + + switch (addr) { + case 0x0078: + if (dev->in_cfg) + ret = dev->vlb_idx; + break; + case 0x007c: + ret = dev->regs[dev->vlb_idx]; + if (dev->vlb_idx == 0x50) + dev->regs[0x50] &= ~0x04; + else if (dev->vlb_idx == 0x57) + dev->regs[0x57] &= ~0x10; + if (dev->regs[0x50] & 0x80) + dev->in_cfg = 0; + break; + } + + return ret; +} + + +static uint16_t +cmd640_vlb_readw(uint16_t addr, void *priv) +{ + uint16_t ret = 0xffff; + + ret = cmd640_vlb_read(addr, priv); + ret |= (cmd640_vlb_read(addr + 1, priv) << 8); + + return ret; +} + + +static uint32_t +cmd640_vlb_readl(uint16_t addr, void *priv) +{ + uint32_t ret = 0xffffffff; + + ret = cmd640_vlb_readw(addr, priv); + ret |= (cmd640_vlb_readw(addr + 2, priv) << 16); + + return ret; +} + + +static void +cmd640_pci_write(int func, int addr, uint8_t val, void *priv) +{ + cmd640_t *dev = (cmd640_t *) priv; + + cmd640_log("cmd640_pci_write(%i, %02X, %02X)\n", func, addr, val); + + if (func == 0x00) switch (addr) { + case 0x04: + dev->regs[addr] = (val & 0x41); + cmd640_ide_handlers(dev); + break; + case 0x07: + dev->regs[addr] &= ~(val & 0x80); + break; + case 0x09: + if ((dev->regs[addr] & 0x0a) == 0x0a) { + dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05); + dev->irq_mode[0] = !!(val & 0x01); + dev->irq_mode[1] = !!(val & 0x04); + cmd640_ide_handlers(dev); + } + break; + case 0x10: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x10] = (val & 0xf8) | 1; + cmd640_ide_handlers(dev); + } + break; + case 0x11: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x11] = val; + cmd640_ide_handlers(dev); + } + break; + case 0x14: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x14] = (val & 0xfc) | 1; + cmd640_ide_handlers(dev); + } + break; + case 0x15: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x15] = val; + cmd640_ide_handlers(dev); + } + break; + case 0x18: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x18] = (val & 0xf8) | 1; + cmd640_ide_handlers(dev); + } + break; + case 0x19: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x19] = val; + cmd640_ide_handlers(dev); + } + break; + case 0x1c: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x1c] = (val & 0xfc) | 1; + cmd640_ide_handlers(dev); + } + break; + case 0x1d: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x1d] = val; + cmd640_ide_handlers(dev); + } + break; + default: + cmd640_common_write(addr, val, dev); + break; + } +} + + +static uint8_t +cmd640_pci_read(int func, int addr, void *priv) +{ + cmd640_t *dev = (cmd640_t *) priv; + uint8_t ret = 0xff; + + if (func == 0x00) { + ret = dev->regs[addr]; + if (addr == 0x50) + dev->regs[0x50] &= ~0x04; + else if (addr == 0x57) + dev->regs[0x57] &= ~0x10; + } + + cmd640_log("cmd640_pci_read(%i, %02X, %02X)\n", func, addr, ret); + + return ret; +} + + +static void +cmd640_reset(void *priv) +{ + cmd640_t *dev = (cmd640_t *) priv; + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && + (cdrom[i].ide_channel < 4) && cdrom[i].priv) + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); + } + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && + (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) + zip_reset((scsi_common_t *) zip_drives[i].priv); + } + for (i = 0; i < MO_NUM; i++) { + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && + (mo_drives[i].ide_channel < 4) && mo_drives[i].priv) + mo_reset((scsi_common_t *) mo_drives[i].priv); + } + + cmd640_set_irq(0x00, priv); + cmd640_set_irq(0x01, priv); + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + dev->regs[0x50] = 0x02; /* Revision 02 */ + dev->regs[0x50] |= (dev->id << 3); /* Device ID: 00 = 60h, 01 = 61h, 10 = 62h, 11 = 63h */ + + dev->regs[0x59] = 0x40; + + if (dev->pci) { + cmd640_log("dev->local = %08X\n", dev->local); + if ((dev->local & 0xffff) == 0x0a) { + dev->regs[0x50] |= 0x40; /* Enable Base address register R/W; + If 0, they return 0 and are read-only 8 */ + } + + dev->regs[0x00] = 0x95; /* CMD */ + dev->regs[0x01] = 0x10; + dev->regs[0x02] = 0x40; /* PCI-0640B */ + dev->regs[0x03] = 0x06; + dev->regs[0x04] = 0x01; /* Apparently required by the ASUS PCI/I-P5SP4 AND PCI/I-P54SP4 */ + dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ + dev->regs[0x08] = 0x02; /* Revision 02 */ + dev->regs[0x09] = dev->local; /* Programming interface */ + dev->regs[0x0a] = 0x01; /* IDE controller */ + dev->regs[0x0b] = 0x01; /* Mass storage controller */ + + /* Base addresses (1F0, 3F4, 170, 374) */ + if (dev->regs[0x50] & 0x40) { + dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; + dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; + dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; + dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; + } + + dev->regs[0x3c] = 0x14; /* IRQ 14 */ + dev->regs[0x3d] = 0x01; /* INTA */ + + dev->irq_mode[0] = dev->irq_mode[1] = 0; + dev->irq_pin = PCI_INTA; + dev->irq_line = 14; + } else { + if ((dev->local & 0xffff) == 0x0078) + dev->regs[0x50] |= 0x20; /* 0 = 178h, 17Ch; 1 = 078h, 07Ch */ + + /* If bit 7 is 1, then device ID has to be written on port x78h before + accessing the configuration registers */ + dev->in_cfg = 1; /* Configuration registers are accessible */ + } + + cmd640_ide_handlers(dev); +} + + +static void +cmd640_close(void *priv) +{ + cmd640_t *dev = (cmd640_t *) priv; + + free(dev); + + next_id = 0; +} + + +static void * +cmd640_init(const device_t *info) +{ + cmd640_t *dev = (cmd640_t *) malloc(sizeof(cmd640_t)); + memset(dev, 0x00, sizeof(cmd640_t)); + + dev->id = next_id | 0x60; + + dev->pci = !!(info->flags & DEVICE_PCI); + dev->local = info->local; + + if (info->flags & DEVICE_PCI) { + device_add(&ide_pci_2ch_device); + + dev->slot = pci_add_card(PCI_ADD_IDE, cmd640_pci_read, cmd640_pci_write, dev); + + ide_set_bus_master(0, NULL, cmd640_set_irq, dev); + ide_set_bus_master(1, NULL, cmd640_set_irq, dev); + + /* The CMD PCI-0640B IDE controller has no DMA capability, + so set our devices IDE devices to force ATA-3 (no DMA). */ + ide_board_set_force_ata3(0, 1); + ide_board_set_force_ata3(1, 1); + + // ide_pri_disable(); + } else if (info->flags & DEVICE_VLB) { + device_add(&ide_vlb_2ch_device); + + io_sethandler(info->local & 0xffff, 0x0008, + cmd640_vlb_read, cmd640_vlb_readw, cmd640_vlb_readl, + cmd640_vlb_write, cmd640_vlb_writew, cmd640_vlb_writel, + dev); + } + + dev->single_channel = !!(info->local & 0x20000); + + next_id++; + + cmd640_reset(dev); + + return dev; +} + +const device_t ide_cmd640_vlb_device = { + .name = "CMD PCI-0640B VLB", + .internal_name = "ide_cmd640_vlb", + .flags = DEVICE_VLB, + .local = 0x0078, + .init = cmd640_init, + .close = cmd640_close, + .reset = cmd640_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_cmd640_vlb_178_device = { + .name = "CMD PCI-0640B VLB (Port 178h)", + .internal_name = "ide_cmd640_vlb_178", + .flags = DEVICE_VLB, + .local = 0x0178, + .init = cmd640_init, + .close = cmd640_close, + .reset = cmd640_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_cmd640_pci_device = { + .name = "CMD PCI-0640B PCI", + .internal_name = "ide_cmd640_pci", + .flags = DEVICE_PCI, + .local = 0x0a, + .init = cmd640_init, + .close = cmd640_close, + .reset = cmd640_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_cmd640_pci_legacy_only_device = { + .name = "CMD PCI-0640B PCI (Legacy Mode Only)", + .internal_name = "ide_cmd640_pci_legacy_only", + .flags = DEVICE_PCI, + .local = 0x00, + .init = cmd640_init, + .close = cmd640_close, + .reset = cmd640_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_cmd640_pci_single_channel_device = { + .name = "CMD PCI-0640B PCI", + .internal_name = "ide_cmd640_pci_single_channel", + .flags = DEVICE_PCI, + .local = 0x2000a, + .init = cmd640_init, + .close = cmd640_close, + .reset = cmd640_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/disk/hdc_ide_cmd646.c b/src/disk/hdc_ide_cmd646.c new file mode 100644 index 000000000..da721f3b6 --- /dev/null +++ b/src/disk/hdc_ide_cmd646.c @@ -0,0 +1,449 @@ +/* + * 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 CMD PCI-0646 controller. + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/cdrom.h> +#include <86box/scsi_device.h> +#include <86box/scsi_cdrom.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/zip.h> +#include <86box/mo.h> + + +typedef struct +{ + uint8_t vlb_idx, single_channel, + in_cfg, regs[256]; + uint32_t local; + int slot, irq_mode[2], + irq_pin; + sff8038i_t *bm[2]; +} cmd646_t; + + +#ifdef ENABLE_CMD646_LOG +int cmd646_do_log = ENABLE_CMD646_LOG; +static void +cmd646_log(const char *fmt, ...) +{ + va_list ap; + + if (cmd646_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cmd646_log(fmt, ...) +#endif + + +static void +cmd646_set_irq(int channel, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + if (channel & 0x01) { + if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) { + dev->regs[0x57] &= ~0x10; + dev->regs[0x57] |= (channel >> 2); + } + } else { + if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) { + dev->regs[0x50] &= ~0x04; + dev->regs[0x50] |= (channel >> 4); + } + } + + sff_bus_master_set_irq(channel, dev->bm[channel & 0x01]); +} + + +static int +cmd646_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + return sff_bus_master_dma(channel, data, transfer_length, out, dev->bm[channel & 0x01]); +} + + +static void +cmd646_ide_handlers(cmd646_t *dev) +{ + uint16_t main, side; + int irq_mode[2] = { 0, 0 }; + + ide_pri_disable(); + + if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) { + main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8); + side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2; + } else { + main = 0x1f0; + side = 0x3f6; + } + + ide_set_base(0, main); + ide_set_side(0, side); + + if (dev->regs[0x09] & 0x01) + irq_mode[0] = 1; + + sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]); + sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]); + + if (dev->regs[0x04] & 0x01) + ide_pri_enable(); + + if (dev->single_channel) + return; + + ide_sec_disable(); + + if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) { + main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8); + side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2; + } else { + main = 0x170; + side = 0x376; + } + + ide_set_base(1, main); + ide_set_side(1, side); + + if (dev->regs[0x09] & 0x04) + irq_mode[1] = 1; + + sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]); + sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]); + + if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08)) + ide_sec_enable(); + +} + + +static void +cmd646_ide_bm_handlers(cmd646_t *dev) +{ + uint16_t base = (dev->regs[0x20] & 0xf0) | (dev->regs[0x21] << 8); + + sff_bus_master_handler(dev->bm[0], (dev->regs[0x04] & 1), base); + sff_bus_master_handler(dev->bm[1], (dev->regs[0x04] & 1), base + 8); +} + + +static void +cmd646_pci_write(int func, int addr, uint8_t val, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + cmd646_log("[%04X:%08X] (%08X) cmd646_pci_write(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, val); + + if (func == 0x00) switch (addr) { + case 0x04: + dev->regs[addr] = (val & 0x45); + cmd646_ide_handlers(dev); + break; + case 0x07: + dev->regs[addr] &= ~(val & 0xb1); + break; + case 0x09: + if ((dev->regs[addr] & 0x0a) == 0x0a) { + dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05); + dev->irq_mode[0] = !!(val & 0x01); + dev->irq_mode[1] = !!(val & 0x04); + cmd646_ide_handlers(dev); + } + break; + case 0x10: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x10] = (val & 0xf8) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x11: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x11] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x14: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x14] = (val & 0xfc) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x15: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x15] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x18: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x18] = (val & 0xf8) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x19: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x19] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x1c: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x1c] = (val & 0xfc) | 1; + cmd646_ide_handlers(dev); + } + break; + case 0x1d: + if (dev->regs[0x50] & 0x40) { + dev->regs[0x1d] = val; + cmd646_ide_handlers(dev); + } + break; + case 0x20: + dev->regs[0x20] = (val & 0xf0) | 1; + cmd646_ide_bm_handlers(dev); + break; + case 0x21: + dev->regs[0x21] = val; + cmd646_ide_bm_handlers(dev); + break; + case 0x51: + dev->regs[addr] = val & 0xc8; + cmd646_ide_handlers(dev); + break; + case 0x52: case 0x54: case 0x56: case 0x58: + case 0x59: case 0x5b: + dev->regs[addr] = val; + break; + case 0x53: case 0x55: + dev->regs[addr] = val & 0xc0; + break; + case 0x57: + dev->regs[addr] = (dev->regs[addr] & 0x10) | (val & 0xcc); + break; + case 0x70 ... 0x77: + sff_bus_master_write(addr & 0x0f, val, dev->bm[0]); + break; + case 0x78 ... 0x7f: + sff_bus_master_write(addr & 0x0f, val, dev->bm[1]); + break; + } +} + + +static uint8_t +cmd646_pci_read(int func, int addr, void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + uint8_t ret = 0xff; + + if (func == 0x00) { + ret = dev->regs[addr]; + + if (addr == 0x50) + dev->regs[0x50] &= ~0x04; + else if (addr == 0x57) + dev->regs[0x57] &= ~0x10; + else if ((addr >= 0x70) && (addr <= 0x77)) + ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]); + else if ((addr >= 0x78) && (addr <= 0x7f)) + ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]); + } + + cmd646_log("[%04X:%08X] (%08X) cmd646_pci_read(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, ret); + + return ret; +} + + +static void +cmd646_reset(void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && + (cdrom[i].ide_channel < 4) && cdrom[i].priv) + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); + } + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && + (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) + zip_reset((scsi_common_t *) zip_drives[i].priv); + } + for (i = 0; i < MO_NUM; i++) { + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && + (mo_drives[i].ide_channel < 4) && mo_drives[i].priv) + mo_reset((scsi_common_t *) mo_drives[i].priv); + } + + cmd646_set_irq(0x00, priv); + cmd646_set_irq(0x01, priv); + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + dev->regs[0x00] = 0x95; /* CMD */ + dev->regs[0x01] = 0x10; + dev->regs[0x02] = 0x46; /* PCI-0646 */ + dev->regs[0x03] = 0x06; + dev->regs[0x04] = 0x00; + dev->regs[0x06] = 0x80; + dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ + dev->regs[0x09] = dev->local; /* Programming interface */ + dev->regs[0x0a] = 0x01; /* IDE controller */ + dev->regs[0x0b] = 0x01; /* Mass storage controller */ + + if ((dev->local & 0xffff) == 0x8a) { + dev->regs[0x50] = 0x40; /* Enable Base address register R/W; + If 0, they return 0 and are read-only 8 */ + + /* Base addresses (1F0, 3F4, 170, 374) */ + dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; + dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; + dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; + dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; + } + + dev->regs[0x20] = 0x01; + + dev->regs[0x3c] = 0x0e; /* IRQ 14 */ + dev->regs[0x3d] = 0x01; /* INTA */ + dev->regs[0x3e] = 0x02; /* Min_Gnt */ + dev->regs[0x3f] = 0x04; /* Max_Iat */ + + if (!dev->single_channel) + dev->regs[0x51] = 0x08; + + dev->regs[0x57] = 0x0c; + dev->regs[0x59] = 0x40; + + dev->irq_mode[0] = dev->irq_mode[1] = 0; + dev->irq_pin = PCI_INTA; + + cmd646_ide_handlers(dev); + cmd646_ide_bm_handlers(dev); +} + + +static void +cmd646_close(void *priv) +{ + cmd646_t *dev = (cmd646_t *) priv; + + free(dev); +} + + +static void * +cmd646_init(const device_t *info) +{ + cmd646_t *dev = (cmd646_t *) malloc(sizeof(cmd646_t)); + memset(dev, 0x00, sizeof(cmd646_t)); + + dev->local = info->local; + + device_add(&ide_pci_2ch_device); + + dev->slot = pci_add_card(PCI_ADD_IDE, cmd646_pci_read, cmd646_pci_write, dev); + + dev->single_channel = !!(info->local & 0x20000); + + dev->bm[0] = device_add_inst(&sff8038i_device, 1); + if (!dev->single_channel) + dev->bm[1] = device_add_inst(&sff8038i_device, 2); + + ide_set_bus_master(0, cmd646_bus_master_dma, cmd646_set_irq, dev); + if (!dev->single_channel) + ide_set_bus_master(1, cmd646_bus_master_dma, cmd646_set_irq, dev); + + sff_set_irq_mode(dev->bm[0], 0, 0); + sff_set_irq_mode(dev->bm[0], 1, 0); + + if (!dev->single_channel) { + sff_set_irq_mode(dev->bm[1], 0, 0); + sff_set_irq_mode(dev->bm[1], 1, 0); + } + + cmd646_reset(dev); + + return dev; +} + +const device_t ide_cmd646_device = { + .name = "CMD PCI-0646", + .internal_name = "ide_cmd646", + .flags = DEVICE_PCI, + .local = 0x8a, + .init = cmd646_init, + .close = cmd646_close, + .reset = cmd646_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_cmd646_legacy_only_device = { + .name = "CMD PCI-0646 (Legacy Mode Only)", + .internal_name = "ide_cmd646_legacy_only", + .flags = DEVICE_PCI, + .local = 0x80, + .init = cmd646_init, + .close = cmd646_close, + .reset = cmd646_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_cmd646_single_channel_device = { + .name = "CMD PCI-0646", + .internal_name = "ide_cmd646_single_channel", + .flags = DEVICE_PCI, + .local = 0x2008a, + .init = cmd646_init, + .close = cmd646_close, + .reset = cmd646_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/disk/hdc_ide_opti611.c b/src/disk/hdc_ide_opti611.c new file mode 100644 index 000000000..9a6bd9cd4 --- /dev/null +++ b/src/disk/hdc_ide_opti611.c @@ -0,0 +1,326 @@ +/* + * 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 82C611/611A VLB IDE controller. + + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#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/keyboard.h> +#include <86box/mem.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> + + +typedef struct +{ + uint8_t tries, + in_cfg, cfg_locked, + regs[19]; +} opti611_t; + + +static void opti611_ide_handler(opti611_t *dev); + + +static void +opti611_cfg_write(uint16_t addr, uint8_t val, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + addr &= 0x0007; + + switch (addr) { + case 0x0000: + case 0x0001: + dev->regs[((dev->regs[0x06] & 0x01) << 4) + addr] = val; + break; + case 0x0002: + dev->regs[0x12] = (val & 0xc1) | 0x02; + if (val & 0xc0) { + if (val & 0x40) + dev->cfg_locked = 1; + dev->in_cfg = 0; + opti611_ide_handler(dev); + } + break; + case 0x0003: + dev->regs[0x03] = (val & 0xdf); + break; + case 0x0005: + dev->regs[0x05] = (dev->regs[0x05] & 0x78) | (val & 0x87); + break; + case 0x0006: + dev->regs[0x06] = val; + break; + } +} + + +static void +opti611_cfg_writew(uint16_t addr, uint16_t val, void *priv) +{ + opti611_cfg_write(addr, val & 0xff, priv); + opti611_cfg_write(addr + 1, val >> 8, priv); +} + + +static void +opti611_cfg_writel(uint16_t addr, uint32_t val, void *priv) +{ + opti611_cfg_writew(addr, val & 0xffff, priv); + opti611_cfg_writew(addr + 2, val >> 16, priv); +} + + +static uint8_t +opti611_cfg_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + opti611_t *dev = (opti611_t *) priv; + + addr &= 0x0007; + + switch (addr) { + case 0x0000: + case 0x0001: + ret = dev->regs[((dev->regs[0x06] & 0x01) << 4) + addr]; + break; + case 0x0002: + ret = ((!!in_smm) << 7); + if (ret & 0x80) + ret |= (dev->regs[addr] & 0x7f); + break; + case 0x0003: case 0x0004: case 0x0005: case 0x0006: + ret = dev->regs[addr]; + break; + } + + return ret; +} + + +static uint16_t +opti611_cfg_readw(uint16_t addr, void *priv) +{ + uint16_t ret = 0xffff; + + ret = opti611_cfg_read(addr, priv); + ret |= (opti611_cfg_read(addr + 1, priv) << 8); + + return ret; +} + + +static uint32_t +opti611_cfg_readl(uint16_t addr, void *priv) +{ + uint32_t ret = 0xffffffff; + + ret = opti611_cfg_readw(addr, priv); + ret |= (opti611_cfg_readw(addr + 2, priv) << 16); + + return ret; +} + + +static void +opti611_ide_write(uint16_t addr, uint8_t val, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + uint8_t smia9 = (!!(addr & 0x0200)) << 5; + uint8_t smia2 = (!!(addr & 0x0004)) << 4; + uint8_t smibe = (addr & 0x0003); + + if (dev->regs[0x03] & 0x02) { + smi_raise(); + dev->regs[0x02] = smia9 | smia2 | smibe; + dev->regs[0x04] = val; + } +} + + +static void +opti611_ide_writew(uint16_t addr, uint16_t val, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + uint8_t smia9 = (!!(addr & 0x0200)) << 5; + uint8_t smia2 = (!!(addr & 0x0004)) << 4; + uint8_t smibe = (addr & 0x0002) | 0x0001; + + if (dev->regs[0x03] & 0x02) { + smi_raise(); + dev->regs[0x02] = smia9 | smia2 | smibe; + dev->regs[0x04] = 0x00; + } +} + + +static void +opti611_ide_writel(uint16_t addr, uint32_t val, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + uint8_t smia9 = (!!(addr & 0x0200)) << 5; + uint8_t smia2 = (!!(addr & 0x0004)) << 4; + + if (dev->regs[0x03] & 0x02) { + smi_raise(); + dev->regs[0x02] = smia9 | smia2 | 0x0003; + dev->regs[0x04] = 0x00; + } +} + + +static uint8_t +opti611_ide_read(uint16_t addr, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + uint8_t smia9 = (!!(addr & 0x0200)) << 5; + uint8_t smia2 = (!!(addr & 0x0004)) << 4; + uint8_t smibe = (addr & 0x0003); + + if (dev->regs[0x03] & 0x02) { + smi_raise(); + dev->regs[0x02] = smia9 | smia2 | smibe; + dev->regs[0x04] = 0x00; + } + + return 0xff; +} + + +static uint16_t +opti611_ide_readw(uint16_t addr, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + uint8_t smia9 = (!!(addr & 0x0200)) << 5; + uint8_t smia2 = (!!(addr & 0x0004)) << 4; + uint8_t smibe = (addr & 0x0002) | 0x0001; + + if ((addr & 0x0007) == 0x0001) { + dev->tries = (dev->tries + 1) & 0x01; + if ((dev->tries == 0x00) && !dev->cfg_locked) { + dev->in_cfg = 1; + opti611_ide_handler(dev); + } + } + + if (dev->regs[0x03] & 0x02) { + smi_raise(); + dev->regs[0x02] = smia9 | smia2 | smibe; + dev->regs[0x04] = 0x00; + } + + return 0xffff; +} + + +static uint32_t +opti611_ide_readl(uint16_t addr, void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + uint8_t smia9 = (!!(addr & 0x0200)) << 5; + uint8_t smia2 = (!!(addr & 0x0004)) << 4; + + if (dev->regs[0x03] & 0x02) { + smi_raise(); + dev->regs[0x02] = smia9 | smia2 | 0x0003; + dev->regs[0x04] = 0x00; + } + + return 0xffffffff; +} + + +static void +opti611_ide_handler(opti611_t *dev) +{ + ide_pri_disable(); + io_removehandler(0x01f0, 0x0007, + opti611_ide_read, opti611_ide_readw, opti611_ide_readl, + opti611_ide_write, opti611_ide_writew, opti611_ide_writel, + dev); + io_removehandler(0x01f0, 0x0007, + opti611_cfg_read, opti611_cfg_readw, opti611_cfg_readl, + opti611_cfg_write, opti611_cfg_writew, opti611_cfg_writel, + dev); + + if (dev->in_cfg && !dev->cfg_locked) { + io_sethandler(0x01f0, 0x0007, + opti611_cfg_read, opti611_cfg_readw, opti611_cfg_readl, + opti611_cfg_write, opti611_cfg_writew, opti611_cfg_writel, + dev); + } else { + if (dev->regs[0x03] & 0x01) + ide_pri_enable(); + io_sethandler(0x01f0, 0x0007, + opti611_ide_read, opti611_ide_readw, opti611_ide_readl, + opti611_ide_write, opti611_ide_writew, opti611_ide_writel, + dev); + } +} + + +static void +opti611_close(void *priv) +{ + opti611_t *dev = (opti611_t *) priv; + + free(dev); +} + + +static void * +opti611_init(const device_t *info) +{ + opti611_t *dev = (opti611_t *) malloc(sizeof(opti611_t)); + memset(dev, 0, sizeof(opti611_t)); + + dev->regs[0x12] = 0x80; + dev->regs[0x03] = 0x01; + dev->regs[0x05] = 0x20; + + device_add(&ide_vlb_device); + + opti611_ide_handler(dev); + + return dev; +} + +const device_t ide_opti611_vlb_device = { + .name = "OPTi 82C611/82C611A VLB", + .internal_name = "ide_opti611_vlb", + .flags = DEVICE_VLB, + .local = 0, + .init = opti611_init, + .close = opti611_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 6af33b4c7..f15cc6dcb 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -41,15 +41,16 @@ #include <86box/hdc_ide.h> #include <86box/hdc_ide_sff8038i.h> #include <86box/zip.h> +#include <86box/mo.h> static int next_id = 0; -static uint8_t sff_bus_master_read(uint16_t port, void *priv); +uint8_t sff_bus_master_read(uint16_t port, void *priv); static uint16_t sff_bus_master_readw(uint16_t port, void *priv); static uint32_t sff_bus_master_readl(uint16_t port, void *priv); -static void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); +void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv); static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv); @@ -111,7 +112,7 @@ sff_bus_master_next_addr(sff8038i_t *dev) } -static void +void sff_bus_master_write(uint16_t port, uint8_t val, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; @@ -137,6 +138,9 @@ sff_bus_master_write(uint16_t port, uint8_t val, void *priv) dev->command = val; break; + case 1: + dev->dma_mode = val & 0x03; + break; case 2: sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status); dev->status &= 0x07; @@ -176,6 +180,7 @@ sff_bus_master_writew(uint16_t port, uint16_t val, void *priv) switch (port & 7) { case 0: + case 1: case 2: sff_bus_master_write(port, val & 0xff, priv); break; @@ -201,6 +206,7 @@ sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) switch (port & 7) { case 0: + case 1: case 2: sff_bus_master_write(port, val & 0xff, priv); break; @@ -213,7 +219,7 @@ sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) } -static uint8_t +uint8_t sff_bus_master_read(uint16_t port, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; @@ -224,6 +230,9 @@ sff_bus_master_read(uint16_t port, void *priv) case 0: ret = dev->command; break; + case 1: + ret = dev->dma_mode & 0x03; + break; case 2: ret = dev->status & 0x67; break; @@ -256,6 +265,7 @@ sff_bus_master_readw(uint16_t port, void *priv) switch (port & 7) { case 0: + case 1: case 2: ret = (uint16_t) sff_bus_master_read(port, priv); break; @@ -282,6 +292,7 @@ sff_bus_master_readl(uint16_t port, void *priv) switch (port & 7) { case 0: + case 1: case 2: ret = (uint32_t) sff_bus_master_read(port, priv); break; @@ -296,7 +307,7 @@ sff_bus_master_readl(uint16_t port, void *priv) } -static int +int sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; @@ -310,8 +321,10 @@ sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, voi sop = out ? "Read" : "Writ"; #endif - if (!(dev->status & 1)) + if (!(dev->status & 1)) { + sff_log("DMA disabled\n"); return 2; /*DMA disabled*/ + } sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length); @@ -369,30 +382,53 @@ void sff_bus_master_set_irq(int channel, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; - dev->status &= ~4; - dev->status |= (channel >> 4); + uint8_t irq = !!(channel & 0x40); + + if (!(dev->status & 0x04) || (channel & 0x40)) { + dev->status &= ~0x04; + dev->status |= (channel >> 4); + } channel &= 0x01; - if (dev->status & 0x04) { - sff_log("SFF8038i: Channel %i IRQ raise\n", channel); - if (dev->irq_mode[channel] == 3) - picintlevel(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_set_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_set_irq(dev->slot, dev->irq_pin); - else - picint(1 << (14 + channel)); - } else { - sff_log("SFF8038i: Channel %i IRQ lower\n", channel); - if (dev->irq_mode[channel] == 3) - picintc(1 << dev->irq_line); - else if ((dev->irq_mode[channel] == 2) && channel && pci_use_mirq(0)) - pci_clear_mirq(0, 0); - else if (dev->irq_mode[channel] == 1) - pci_clear_irq(dev->slot, dev->irq_pin); - else - picintc(1 << (14 + channel)); + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + if (irq) + picint(1 << (14 + channel)); + else + picintc(1 << (14 + channel)); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + if (irq) + pci_set_irq(dev->slot, dev->irq_pin); + else + pci_clear_irq(dev->slot, dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + if (irq) + pci_set_mirq(dev->irq_mode[channel] & 1, 0); + else + pci_clear_mirq(dev->irq_mode[channel] & 1, 0); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + if (irq) + picintlevel(1 << dev->irq_line); + else + picintc(1 << dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + if (irq) + pci_set_mirq(channel + 2, dev->irq_level[channel]); + else + pci_clear_mirq(channel + 2, dev->irq_level[channel]); + break; } } @@ -440,6 +476,11 @@ sff_reset(void *p) (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) zip_reset((scsi_common_t *) zip_drives[i].priv); } + for (i = 0; i < MO_NUM; i++) { + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && + (mo_drives[i].ide_channel < 4) && mo_drives[i].priv) + mo_reset((scsi_common_t *) mo_drives[i].priv); + } sff_bus_master_set_irq(0x00, p); sff_bus_master_set_irq(0x01, p); @@ -460,10 +501,42 @@ sff_set_irq_line(sff8038i_t *dev, int irq_line) } +void +sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) +{ + dev->irq_level[channel] = 0; +} + + void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) { dev->irq_mode[channel] = irq_mode; + + switch (dev->irq_mode[channel]) { + case 0: + default: + /* Legacy IRQ mode. */ + sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); + break; + case 1: + /* Native PCI IRQ mode with interrupt pin. */ + sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); + break; + case 2: + case 5: + /* MIRQ 0 or 1. */ + sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); + break; + case 3: + /* Native PCI IRQ mode with specified interrupt line. */ + sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); + break; + case 4: + /* ALi Aladdin Native PCI INTAJ mode. */ + sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); + break; + } } @@ -500,26 +573,28 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); dev->slot = 7; - dev->irq_mode[0] = dev->irq_mode[1] = 2; + dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ + dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ dev->irq_pin = PCI_INTA; dev->irq_line = 14; + dev->irq_level[0] = dev->irq_level[1] = 0; next_id++; return dev; } - const device_t sff8038i_device = { - "SFF-8038i IDE Bus Master", - DEVICE_PCI, - 0, - sff_init, - sff_close, - sff_reset, - NULL, - NULL, - NULL, - NULL + .name = "SFF-8038i IDE Bus Master", + .internal_name = "sff8038i", + .flags = DEVICE_PCI, + .local = 0, + .init = sff_init, + .close = sff_close, + .reset = sff_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index 5fcf24dfd..aff35bc76 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -20,9 +20,6 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2017-2019 Fred N. van Kempen. */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #include #include #include @@ -125,7 +122,7 @@ static void mfm_write(uint16_t port, uint8_t val, void *priv); #ifdef ENABLE_ST506_AT_LOG -int mfm_at_do_log = ENABLE_ST506_AT_LOG; +int st506_at_do_log = ENABLE_ST506_AT_LOG; static void @@ -165,7 +162,7 @@ irq_lower(mfm_t *mfm) static void irq_update(mfm_t *mfm) { - if (mfm->irqstat && !((pic2.pend | pic2.ins) & 0x40) && !(mfm->fdisk & 2)) + if (mfm->irqstat && !((pic2.irr | pic2.isr) & 0x40) && !(mfm->fdisk & 2)) picint(1 << 14); } @@ -305,7 +302,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) mfm->command &= 0xfc; if (val & 2) fatal("WD1003: WRITE with ECC\n"); - mfm->status = STAT_DRQ|STAT_DSC; + mfm->status = STAT_READY|STAT_DRQ|STAT_DSC; mfm->pos = 0; break; @@ -692,7 +689,7 @@ do_callback(void *priv) static void -loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) +loadhd(mfm_t *mfm, int c, int d, const char *fn) { drive_t *drive = &mfm->drives[c]; @@ -725,7 +722,7 @@ mfm_init(const device_t *info) if ((hdd[d].bus == HDD_BUS_MFM) && (hdd[d].mfm_channel < MFM_NUM)) { loadhd(mfm, hdd[d].mfm_channel, d, hdd[d].fn); - st506_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn, + st506_at_log("WD1003(%d): (%s) geometry %d/%d/%d\n", c, hdd[d].fn, (int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt); if (++c >= MFM_NUM) break; @@ -742,7 +739,7 @@ mfm_init(const device_t *info) io_sethandler(0x03f6, 1, NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); - timer_add(&mfm->callback_timer, do_callback, mfm, 0); + timer_add(&mfm->callback_timer, do_callback, mfm, 0); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); @@ -759,7 +756,7 @@ mfm_close(void *priv) for (d=0; d<2; d++) { drive_t *drive = &mfm->drives[d]; - hdd_image_close(drive->hdd_num); + hdd_image_close(drive->hdd_num); } free(mfm); @@ -767,11 +764,16 @@ mfm_close(void *priv) ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); } - const device_t st506_at_wd1003_device = { - "WD1003 AT MFM/RLL Controller", - DEVICE_ISA | DEVICE_AT, - 0, - mfm_init, mfm_close, NULL, - NULL, NULL, NULL, NULL + .name = "WD1003 AT MFM/RLL Controller", + .internal_name = "st506_at", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = mfm_init, + .close = mfm_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index 15e1c2a70..e8c43fdc1 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -67,9 +67,6 @@ * Boston, MA 02111-1307 * USA. */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #include #include #include @@ -91,15 +88,18 @@ #include <86box/hdd.h> -#define XEBEC_BIOS_FILE L"roms/hdd/st506/ibm_xebec_62x0822_1985.bin" -#define DTC_BIOS_FILE L"roms/hdd/st506/dtc_cxd21a.bin" -#define ST11_BIOS_FILE_OLD L"roms/hdd/st506/st11_bios_vers_1.7.bin" -#define ST11_BIOS_FILE_NEW L"roms/hdd/st506/st11_bios_vers_2.0.bin" -#define WD1002A_WX1_BIOS_FILE L"roms/hdd/st506/wd1002a_wx1-62-000094-032.bin" +#define XEBEC_BIOS_FILE "roms/hdd/st506/ibm_xebec_62x0822_1985.bin" +#define DTC_BIOS_FILE "roms/hdd/st506/dtc_cxd21a.bin" +#define ST11_BIOS_FILE_OLD "roms/hdd/st506/st11_bios_vers_1.7.bin" +#define ST11_BIOS_FILE_NEW "roms/hdd/st506/st11_bios_vers_2.0.bin" +#define WD1002A_WX1_BIOS_FILE "roms/hdd/st506/wd1002a_wx1-62-000094-032.bin" +#define WD1004A_WX1_BIOS_FILE "roms/hdd/st506/wd1002a_wx1-62-000094-032.bin" /* SuperBIOS was for both the WX1 and 27X, users jumpers readout to determine if to use 26 sectors per track, 26 -> 17 sectors per track translation, or 17 sectors per track. */ -#define WD1002A_27X_BIOS_FILE L"roms/hdd/st506/wd1002a_27x-62-000094-032.bin" +#define WD1002A_27X_BIOS_FILE "roms/hdd/st506/wd1002a_27x-62-000094-032.bin" +#define WD1004_27X_BIOS_FILE "roms/hdd/st506/western_digital_WD1004A-27X.bin" +#define WD1004A_27X_BIOS_FILE "roms/hdd/st506/western_digital_WD1004A-27X.bin" #define ST506_TIME (250 * TIMER_USEC) @@ -369,7 +369,7 @@ get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) } *addr = ((((off64_t)dev->cylinder * drive->cfg_hpc) + dev->head) * drive->cfg_spt) + dev->sector; - + return(1); } @@ -619,7 +619,7 @@ st506_callback(void *priv) st506_complete(dev); break; } - break; + break; case CMD_GET_GEOMETRY_ST11: /* "Get geometry" is really "Read cylinder 0" */ if ((dev->type < 11) || (dev->type > 12)) { @@ -1115,7 +1115,7 @@ st506_read(uint16_t port, void *priv) dev->status = 0x00; dev->state = STATE_IDLE; break; - + case STATE_SEND_DATA: ret = dev->buff[dev->buff_pos++]; if (dev->buff_pos == dev->buff_cnt) { @@ -1305,7 +1305,7 @@ mem_read(uint32_t addr, void *priv) * standard 'rom_init' function here. */ static void -loadrom(hdc_t *dev, const wchar_t *fn) +loadrom(hdc_t *dev, const char *fn) { uint32_t size; FILE *fp; @@ -1317,8 +1317,8 @@ loadrom(hdc_t *dev, const wchar_t *fn) return; } - if ((fp = rom_fopen((wchar_t *) fn, L"rb")) == NULL) { - st506_xt_log("ST506: BIOS ROM '%ls' not found!\n", fn); + if ((fp = rom_fopen((char *) fn, "rb")) == NULL) { + st506_xt_log("ST506: BIOS ROM '%s' not found!\n", fn); return; } @@ -1349,7 +1349,7 @@ loadrom(hdc_t *dev, const wchar_t *fn) static void -loadhd(hdc_t *dev, int c, int d, const wchar_t *fn) +loadhd(hdc_t *dev, int c, int d, const char *fn) { drive_t *drive = &dev->drives[c]; @@ -1357,7 +1357,7 @@ loadhd(hdc_t *dev, int c, int d, const wchar_t *fn) drive->present = 0; return; } - + /* Make sure we can do this. */ /* Allow 31 sectors per track on RLL controllers, for the ST225R, which is 667/2/31. */ @@ -1423,7 +1423,7 @@ set_switches(hdc_t *dev) static void * st506_init(const device_t *info) { - wchar_t *fn = NULL; + char *fn = NULL; hdc_t *dev; int i, c; @@ -1531,7 +1531,7 @@ st506_init(const device_t *info) #endif for (c = 0, i = 0; i < HDD_NUM; i++) { if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) { - st506_xt_log("ST506: disk '%ls' on channel %i\n", + st506_xt_log("ST506: disk '%s' on channel %i\n", hdd[i].fn, hdd[i].mfm_channel); loadhd(dev, hdd[i].mfm_channel, i, hdd[i].fn); @@ -1614,280 +1614,452 @@ wd1002a_27x_available(void) return(rom_present(WD1002A_27X_BIOS_FILE)); } +static int +wd1004a_wx1_available(void) +{ + return(rom_present(WD1004A_WX1_BIOS_FILE)); +} +static int +wd1004_27x_available(void) +{ + return(rom_present(WD1004_27X_BIOS_FILE)); +} + +static int +wd1004a_27x_available(void) +{ + return(rom_present(WD1004A_27X_BIOS_FILE)); +} + +// clang-format off static const device_config_t dtc_config[] = { { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, - { - { - "Disabled", 0x00000 - }, - { - "C800H", 0xc8000 - }, - { - "CA00H", 0xca000 - }, - { - "D800H", 0xd8000 - }, - { - "F400H", 0xf4000 - }, - { - "" - } - } + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "F400H", .value = 0xf4000 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t st11_config[] = { { - "base", "Address", CONFIG_HEX16, "", 0x0320, - { - { - "320H", 0x0320 - }, - { - "324H", 0x0324 - }, - { - "328H", 0x0328 - }, - { - "32CH", 0x032c - }, - { - "" - } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0320, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "320H", .value = 0x0320 }, + { .description = "324H", .value = 0x0324 }, + { .description = "328H", .value = 0x0328 }, + { .description = "32CH", .value = 0x032c }, + { .description = "" } + } }, { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 2", 2 - }, - { - "IRQ 5", 5 - }, - { - "" - } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } }, { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, - { - { - "Disabled", 0x00000 - }, - { - "C800H", 0xc8000 - }, - { - "D000H", 0xd0000 - }, - { - "D800H", 0xd8000 - }, - { - "E000H", 0xe0000 - }, - { - "" - } - } + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "E000H", .value = 0xe0000 }, + { .description = "" } + } }, { - "revision", "Board Revision", CONFIG_SELECTION, "", 19, - { - { - "Rev. 05 (v1.7)", 5 - }, - { - "Rev. 19 (v2.0)", 19 - }, - { - "" - } - } + .name = "revision", + .description = "Board Revision", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 19, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Rev. 05 (v1.7)", .value = 5 }, + { .description = "Rev. 19 (v2.0)", .value = 19 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd_config[] = { { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, - { - { - "Disabled", 0x00000 - }, - { - "C800H", 0xc8000 - }, - { - "" - } - } + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "" } + } }, { - "base", "Address", CONFIG_HEX16, "", 0x0320, - { - { - "320H", 0x0320 - }, - { - "324H", 0x0324 - }, - { - "" - } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0320, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "320H", .value = 0x0320 }, + { .description = "324H", .value = 0x0324 }, + { .description = "" } + } }, { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 2", 2 - }, - { - "IRQ 5", 5 - }, - { - "" - } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd_rll_config[] = { { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, - { - { - "Disabled", 0x00000 - }, - { - "C800H", 0xc8000 - }, - { - "" - } - } + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "" } + } }, { - "base", "Address", CONFIG_HEX16, "", 0x0320, - { - { - "320H", 0x0320 - }, - { - "324H", 0x0324 - }, - { - "" - } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0320, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "320H", .value = 0x0320 }, + { .description = "324H", .value = 0x0324 }, + { .description = "" } + } }, { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 2", 2 - }, - { - "IRQ 5", 5 - }, - { - "" - } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } }, { - "translate", "Translate 26 -> 17", CONFIG_SELECTION, "", 0, - { - { - "Off", 0 - }, - { - "On", 1 - }, - { - "" - } - } + .name = "translate", + .description = "Translate 26 -> 17", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Off", .value = 0 }, + { .description = "On", .value = 1 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; +static const device_config_t wd1004a_config[] = { + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "" } + } + }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0320, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "320H", .value = 0x0320 }, + { .description = "324H", .value = 0x0324 }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t wd1004_rll_config[] = { + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "" } + } + }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0320, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "320H", .value = 0x0320 }, + { .description = "324H", .value = 0x0324 }, + { .description = "328H", .value = 0x0328 }, + { .description = "32CH", .value = 0x032c }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "" } + } + }, + { + .name = "translate", + .description = "Translate 26 -> 17", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Off", .value = 0 }, + { .description = "On", .value = 1 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +// clang-format on const device_t st506_xt_xebec_device = { - "IBM PC Fixed Disk Adapter", - DEVICE_ISA, - (HDD_BUS_MFM << 8) | 0, - st506_init, st506_close, NULL, - xebec_available, - NULL, NULL, - NULL + .name = "IBM PC Fixed Disk Adapter (MFM)", + .internal_name = "st506_xt", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 0, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = xebec_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t st506_xt_dtc5150x_device = { - "DTC 5150X Fixed Disk Adapter", - DEVICE_ISA, - (HDD_BUS_MFM << 8) | 1, - st506_init, st506_close, NULL, - dtc5150x_available, - NULL, NULL, - dtc_config + .name = "DTC 5150X MFM Fixed Disk Adapter", + .internal_name = "st506_xt_dtc5150x", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 1, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = dtc5150x_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = dtc_config }; const device_t st506_xt_st11_m_device = { - "ST-11M Fixed Disk Adapter", - DEVICE_ISA, - (HDD_BUS_MFM << 8) | 11, - st506_init, st506_close, NULL, - st11_m_available, - NULL, NULL, - st11_config + .name = "ST-11M MFM Fixed Disk Adapter", + .internal_name = "st506_xt_st11_m", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 11, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = st11_m_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = st11_config }; const device_t st506_xt_st11_r_device = { - "ST-11R RLL Fixed Disk Adapter", - DEVICE_ISA, - (HDD_BUS_MFM << 8) | 12, - st506_init, st506_close, NULL, - st11_r_available, - NULL, NULL, - st11_config + .name = "ST-11R RLL Fixed Disk Adapter", + .internal_name = "st506_xt_st11_r", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 12, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = st11_r_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = st11_config }; const device_t st506_xt_wd1002a_wx1_device = { - "WD1002A-WX1 Fixed Disk Adapter", - DEVICE_ISA, - (HDD_BUS_MFM << 8) | 21, - st506_init, st506_close, NULL, - wd1002a_wx1_available, - NULL, NULL, - wd_config + .name = "WD1002A-WX1 MFM Fixed Disk Adapter", + .internal_name = "st506_xt_wd1002a_wx1", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 21, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = wd1002a_wx1_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd_config }; const device_t st506_xt_wd1002a_27x_device = { - "WD1002A-27X RLL Fixed Disk Adapter", - DEVICE_ISA, - (HDD_BUS_MFM << 8) | 22, - st506_init, st506_close, NULL, - wd1002a_27x_available, - NULL, NULL, - wd_rll_config + .name = "WD1002A-27X RLL Fixed Disk Adapter", + .internal_name = "st506_xt_wd1002a_27x", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 22, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = wd1002a_27x_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd_rll_config +}; + +const device_t st506_xt_wd1004a_wx1_device = { + .name = "WD1004A-WX1 MFM Fixed Disk Adapter", + .internal_name = "st506_xt_wd1004a_wx1", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 21, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { wd1004a_wx1_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd1004a_config +}; + +const device_t st506_xt_wd1004_27x_device = { + .name = "WD1004-27X RLL Fixed Disk Adapter", + .internal_name = "st506_xt_wd1004_27x", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 22, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = wd1004_27x_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd1004_rll_config +}; + +const device_t st506_xt_wd1004a_27x_device = { + .name = "WD1004a-27X RLL Fixed Disk Adapter", + .internal_name = "st506_xt_wd1004a_27x", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 22, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = wd1004a_27x_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd_rll_config }; diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 18d66d898..28990bbdb 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -23,7 +23,7 @@ * disk drives for this bus commonly have an 'A' suffix to * identify them as 'ATBUS'. * - * In XTA-IDE, which is slightly older, the programming + * In XTA-IDE, which is slightly older, the programming * interface of the IBM PC/XT (which used the MFM controller * from Xebec) was kept, and, so, it uses an 8bit data path. * Disk drives for this bus commonly have the 'X' suffix to @@ -38,7 +38,7 @@ * data byte per transfer. XTIDE uses regular IDE drives, * and uses the regular ATA/IDE programming interface, just * with the extra register. - * + * * NOTE: This driver implements both the 'standard' XTA interface, * sold by Western Digital as the WDXT-140 (no BIOS) and the * WDXT-150 (with BIOS), as well as some variants customized @@ -84,9 +84,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #include #include #include @@ -110,7 +107,7 @@ #define HDC_TIME (50*TIMER_USEC) -#define WD_BIOS_FILE L"roms/hdd/xta/idexywd2.bin" +#define WD_BIOS_FILE "roms/hdd/xta/idexywd2.bin" enum { @@ -494,7 +491,7 @@ hdc_callback(void *priv) } set_intr(dev); break; - + case CMD_READ_SENSE: switch(dev->state) { case STATE_IDLE: @@ -514,7 +511,7 @@ hdc_callback(void *priv) case STATE_SDONE: set_intr(dev); } - break; + break; case CMD_READ_VERIFY: no_data = 1; @@ -584,7 +581,7 @@ do_send: } } break; - + case STATE_SDATA: if (! no_data) { /* Perform DMA. */ @@ -882,7 +879,7 @@ hdc_read(uint16_t port, void *priv) { hdc_t *dev = (hdc_t *)priv; uint8_t ret = 0xff; - + switch (port & 7) { case 0: /* DATA register */ dev->status &= ~STAT_IRQ; @@ -920,7 +917,7 @@ xta_log("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->com break; } - return(ret); + return(ret); } @@ -995,7 +992,7 @@ static void * xta_init(const device_t *info) { drive_t *drive; - wchar_t *fn = NULL; + char *fn = NULL; hdc_t *dev; int c, i; int max = XTA_NUM; @@ -1068,12 +1065,13 @@ xta_init(const device_t *info) hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); /* Load BIOS if it has one. */ - if (dev->rom_addr != 0x000000) + if (dev->rom_addr != 0x000000) { rom_init(&dev->bios_rom, fn, dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - + } + /* Create a timer for command delays. */ - timer_add(&dev->timer, hdc_callback, dev, 0); + timer_add(&dev->timer, hdc_callback, dev, 0); return(dev); } @@ -1101,71 +1099,78 @@ xta_close(void *priv) free(dev); } - static const device_config_t wdxt150_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x0320, /*W2*/ - { - { - "320H", 0x0320 - }, - { - "324H", 0x0324 - }, - { - "" - } - }, +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0320, + .file_filter = "", + .spinner = { 0 }, /*W2*/ + .selection = { + { .description = "320H", .value = 0x0320 }, + { .description = "324H", .value = 0x0324 }, + { .description = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, /*W3*/ - { - { - "IRQ 5", 5 - }, - { - "IRQ 4", 4 - }, - { - "" - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, /*W3*/ + .selection = { + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "" } }, - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xc8000, /*W1*/ - { - { - "C800H", 0xc8000 - }, - { - "CA00H", 0xca000 - }, - { - "" - } - }, + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc8000, + .file_filter = "", + .spinner = { 0 }, /*W1*/ + .selection = { + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "" } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format off }; - const device_t xta_wdxt150_device = { - "WDXT-150 Fixed Disk Controller", - DEVICE_ISA, - 0, - xta_init, xta_close, NULL, - xta_available, NULL, NULL, - wdxt150_config + .name = "WDXT-150 XTA Fixed Disk Controller", + .internal_name = "xta_wdxt150", + .flags = DEVICE_ISA, + .local = 0, + .init = xta_init, + .close = xta_close, + .reset = NULL, + { .available = xta_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wdxt150_config }; - const device_t xta_hd20_device = { - "EuroPC HD20 Fixed Disk Controller", - DEVICE_ISA, - 1, - xta_init, xta_close, NULL, - NULL, NULL, NULL, - NULL + .name = "EuroPC HD20 Fixed Disk Controller", + .internal_name = "xta_hd20", + .flags = DEVICE_ISA, + .local = 1, + .init = xta_init, + .close = xta_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index c9497e120..34805db2b 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -45,10 +45,11 @@ #include <86box/hdc_ide.h> -#define ROM_PATH_XT L"roms/hdd/xtide/ide_xt.bin" -#define ROM_PATH_AT L"roms/hdd/xtide/ide_at.bin" -#define ROM_PATH_PS2 L"roms/hdd/xtide/SIDE1V12.BIN" -#define ROM_PATH_PS2AT L"roms/hdd/xtide/ide_at_1_1_5.bin" +#define ROM_PATH_XT "roms/hdd/xtide/ide_xt.bin" +#define ROM_PATH_AT "roms/hdd/xtide/ide_at.bin" +#define ROM_PATH_PS2 "roms/hdd/xtide/SIDE1V12.BIN" +#define ROM_PATH_PS2AT "roms/hdd/xtide/ide_at_1_1_5.bin" +#define ROM_PATH_AT_386 "roms/hdd/xtide/ide_386.bin" typedef struct { @@ -161,8 +162,13 @@ xtide_at_init(const device_t *info) memset(xtide, 0x00, sizeof(xtide_t)); - rom_init(&xtide->bios_rom, ROM_PATH_AT, - 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + if (info->local == 1) { + rom_init(&xtide->bios_rom, ROM_PATH_AT_386, + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + } else { + rom_init(&xtide->bios_rom, ROM_PATH_AT, + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + } device_add(&ide_isa_2ch_device); @@ -177,6 +183,13 @@ xtide_at_available(void) } +static int +xtide_at_386_available(void) +{ + return(rom_present(ROM_PATH_AT_386)); +} + + static void * xtide_acculogic_init(const device_t *info) { @@ -246,39 +259,72 @@ xtide_at_close(void *priv) free(xtide); } - const device_t xtide_device = { - "XTIDE", - DEVICE_ISA, - 0, - xtide_init, xtide_close, NULL, - xtide_available, NULL, NULL, - NULL + .name = "PC/XT XTIDE", + .internal_name = "xtide", + .flags = DEVICE_ISA, + .local = 0, + .init = xtide_init, + .close = xtide_close, + .reset = NULL, + { .available = xtide_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t xtide_at_device = { - "XTIDE (AT)", - DEVICE_ISA | DEVICE_AT, - 0, - xtide_at_init, xtide_at_close, NULL, - xtide_at_available, NULL, NULL, - NULL + .name = "PC/AT XTIDE", + .internal_name = "xtide_at", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = xtide_at_init, + .close = xtide_at_close, + .reset = NULL, + { .available = xtide_at_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t xtide_at_386_device = { + .name = "PC/AT XTIDE (386)", + .internal_name = "xtide_at_386", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 1, + .init = xtide_at_init, + .close = xtide_at_close, + .reset = NULL, + { .available = xtide_at_386_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t xtide_acculogic_device = { - "XTIDE (Acculogic)", - DEVICE_ISA, - 0, - xtide_acculogic_init, xtide_close, NULL, - xtide_acculogic_available, NULL, NULL, - NULL + .name = "Acculogic XT IDE", + .internal_name = "xtide_acculogic", + .flags = DEVICE_ISA, + .local = 0, + .init = xtide_acculogic_init, + .close = xtide_close, + .reset = NULL, + { .available = xtide_acculogic_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t xtide_at_ps2_device = { - "XTIDE (AT) (1.1.5)", - DEVICE_AT, - 0, - xtide_at_ps2_init, xtide_at_close, NULL, - xtide_at_ps2_available, NULL, NULL, - NULL + .name = "PS/2 AT XTIDE (1.1.5)", + .internal_name = "xtide_at_ps2", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = xtide_at_ps2_init, + .close = xtide_at_close, + .reset = NULL, + { .available = xtide_at_ps2_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdd.c b/src/disk/hdd.c index f1c0f1599..d2f77a1ab 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -17,14 +17,22 @@ * Copyright 2017-2019 Fred N. van Kempen. */ #include -#include +#include #include +#include +#include +#include #include #include <86box/86box.h> #include <86box/plat.h> #include <86box/ui.h> #include <86box/hdd.h> #include <86box/cdrom.h> +#include <86box/video.h> +#include "cpu.h" + + +#define HDD_OVERHEAD_TIME 50.0 hard_disk_t hdd[HDD_NUM]; @@ -46,7 +54,7 @@ hdd_string_to_bus(char *str, int cdrom) if (! strcmp(str, "none")) return(HDD_BUS_DISABLED); - if (! strcmp(str, "mfm")) { + if (! strcmp(str, "mfm") || ! strcmp(str, "rll")) { if (cdrom) { no_cdrom: ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2130, (wchar_t *) IDS_4099); @@ -70,10 +78,10 @@ no_cdrom: return(HDD_BUS_IDE); if (! strcmp(str, "atapi_pio_only")) - return(HDD_BUS_IDE); + return(HDD_BUS_ATAPI); if (! strcmp(str, "atapi")) - return(HDD_BUS_IDE); + return(HDD_BUS_ATAPI); if (! strcmp(str, "eide")) return(HDD_BUS_IDE); @@ -88,7 +96,7 @@ no_cdrom: return(HDD_BUS_IDE); if (! strcmp(str, "atapi_pio_and_dma")) - return(HDD_BUS_IDE); + return(HDD_BUS_ATAPI); if (! strcmp(str, "scsi")) return(HDD_BUS_SCSI); @@ -120,7 +128,11 @@ hdd_bus_to_string(int bus, int cdrom) break; case HDD_BUS_IDE: - s = cdrom ? "atapi" : "ide"; + s = "ide"; + break; + + case HDD_BUS_ATAPI: + s = "atapi"; break; case HDD_BUS_SCSI: @@ -138,7 +150,7 @@ hdd_is_valid(int c) if (hdd[c].bus == HDD_BUS_DISABLED) return(0); - if (wcslen(hdd[c].fn) == 0) + if (strlen(hdd[c].fn) == 0) return(0); if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0)) @@ -146,3 +158,398 @@ hdd_is_valid(int c) return(1); } + + +double +hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time) +{ + if (!hdd->speed_preset) + return HDD_OVERHEAD_TIME; + + hdd_zone_t *zone = NULL; + for (int i = 0; i < hdd->num_zones; i++) { + zone = &hdd->zones[i]; + if (zone->end_sector >= dst_addr) + break; + } + + double continuous_times[2][2] = { { hdd->head_switch_usec, hdd->cyl_switch_usec }, + { zone->sector_time_usec, zone->sector_time_usec } }; + double times[2] = { HDD_OVERHEAD_TIME, hdd->avg_rotation_lat_usec }; + + uint32_t new_track = zone->start_track + ((dst_addr - zone->start_sector) / zone->sectors_per_track); + uint32_t new_cylinder = new_track / hdd->phy_heads; + uint32_t cylinder_diff = abs((int)hdd->cur_cylinder - (int)new_cylinder); + + bool sequential = dst_addr == hdd->cur_addr + 1; + continuous = continuous && sequential; + + double seek_time = 0.0; + if (continuous) + seek_time = continuous_times[new_track == hdd->cur_track][!!cylinder_diff]; + else { + if (!cylinder_diff) + seek_time = times[operation != HDD_OP_SEEK]; + else { + seek_time = hdd->cyl_switch_usec + (hdd->full_stroke_usec * (double)cylinder_diff / (double)hdd->phy_cyl) + + ((operation != HDD_OP_SEEK) * hdd->avg_rotation_lat_usec); + } + } + + if (!max_seek_time || seek_time <= max_seek_time) { + hdd->cur_addr = dst_addr; + hdd->cur_track = new_track; + hdd->cur_cylinder = new_cylinder; + } + + return seek_time; +} + + +static void +hdd_readahead_update(hard_disk_t *hdd) +{ + uint64_t elapsed_cycles; + double elapsed_us, seek_time; + uint32_t max_read_ahead, i; + uint32_t space_needed; + + hdd_cache_t *cache = &hdd->cache; + if (cache->ra_ongoing) { + hdd_cache_seg_t *segment = &cache->segments[cache->ra_segment]; + + elapsed_cycles = tsc - cache->ra_start_time; + elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0; + /* Do not overwrite data not yet read by host */ + max_read_ahead = (segment->host_addr + cache->segment_size) - segment->ra_addr; + + seek_time = 0.0; + + for (i = 0; i < max_read_ahead; i++) { + seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, elapsed_us - seek_time); + if (seek_time > elapsed_us) + break; + + segment->ra_addr++; + } + + if (segment->ra_addr > segment->lba_addr + cache->segment_size) { + space_needed = segment->ra_addr - (segment->lba_addr + cache->segment_size); + segment->lba_addr += space_needed; + } + } +} + + +static double +hdd_writecache_flush(hard_disk_t *hdd) +{ + double seek_time = 0.0; + + while (hdd->cache.write_pending) { + seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0); + hdd->cache.write_addr++; + hdd->cache.write_pending--; + } + + return seek_time; +} + + +static void +hdd_writecache_update(hard_disk_t *hdd) +{ + uint64_t elapsed_cycles; + double elapsed_us, seek_time; + + if (hdd->cache.write_pending) { + elapsed_cycles = tsc - hdd->cache.write_start_time; + elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0; + seek_time = 0.0; + + while (hdd->cache.write_pending) { + seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, elapsed_us - seek_time); + if (seek_time > elapsed_us) + break; + + hdd->cache.write_addr++; + hdd->cache.write_pending--; + } + } +} + + +double +hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len) +{ + double seek_time = 0.0; + uint32_t flush_needed; + + if (!hdd->speed_preset) + return HDD_OVERHEAD_TIME; + + hdd_readahead_update(hdd); + hdd_writecache_update(hdd); + + hdd->cache.ra_ongoing = 0; + + if (hdd->cache.write_pending && (addr != (hdd->cache.write_addr + hdd->cache.write_pending))) { + /* New request is not sequential to existing cache, need to flush it */ + seek_time += hdd_writecache_flush(hdd); + } + + if (!hdd->cache.write_pending) { + /* Cache is empty */ + hdd->cache.write_addr = addr; + } + + hdd->cache.write_pending += len; + if (hdd->cache.write_pending > hdd->cache.write_size) { + /* If request is bigger than free cache, flush some data first */ + flush_needed = hdd->cache.write_pending - hdd->cache.write_size; + for (uint32_t i = 0; i < flush_needed; i++) { + seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0); + hdd->cache.write_addr++; + } + } + + hdd->cache.write_start_time = tsc + (uint32_t)(seek_time * cpuclock / 1000000.0); + + return seek_time; +} + + +double +hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len) +{ + double seek_time = 0.0; + + if (!hdd->speed_preset) + return HDD_OVERHEAD_TIME; + + hdd_readahead_update(hdd); + hdd_writecache_update(hdd); + + seek_time += hdd_writecache_flush(hdd); + + hdd_cache_t *cache = &hdd->cache; + hdd_cache_seg_t *active_seg = &cache->segments[0]; + + for (uint32_t i = 0; i < cache->num_segments; i++) { + hdd_cache_seg_t *segment = &cache->segments[i]; + if (!segment->valid) { + active_seg = segment; + continue; + } + + if (segment->lba_addr <= addr && (segment->lba_addr + cache->segment_size) >= addr) { + /* Cache HIT */ + segment->host_addr = addr; + active_seg = segment; + if (addr + len > segment->ra_addr) { + uint32_t need_read = (addr + len) - segment->ra_addr; + for (uint32_t j = 0; j < need_read; j++) { + seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, 0.0); + segment->ra_addr++; + } + } + if (addr + len > segment->lba_addr + cache->segment_size) { + /* Need to erase some previously cached data */ + uint32_t space_needed = (addr + len) - (segment->lba_addr + cache->segment_size); + segment->lba_addr += space_needed; + } + goto update_lru; + } else { + if (segment->lru > active_seg->lru) + active_seg = segment; + } + } + + /* Cache MISS */ + active_seg->lba_addr = addr; + active_seg->valid = 1; + active_seg->host_addr = addr; + active_seg->ra_addr = addr; + + for (uint32_t i = 0; i < len; i++) { + seek_time += hdd_seek_get_time(hdd, active_seg->ra_addr, HDD_OP_READ, i != 0, 0.0); + active_seg->ra_addr++; + } + +update_lru: + for (uint32_t i = 0; i < cache->num_segments; i++) + cache->segments[i].lru++; + + active_seg->lru = 0; + + cache->ra_ongoing = 1; + cache->ra_segment = active_seg->id; + cache->ra_start_time = tsc + (uint32_t)(seek_time * cpuclock / 1000000.0); + + return seek_time; +} + + +static void +hdd_cache_init(hard_disk_t *hdd) +{ + hdd_cache_t *cache = &hdd->cache; + uint32_t i; + + cache->ra_segment = 0; + cache->ra_ongoing = 0; + cache->ra_start_time = 0; + + for (i = 0; i < cache->num_segments; i++) { + cache->segments[i].valid = 0; + cache->segments[i].lru = 0; + cache->segments[i].id = i; + cache->segments[i].ra_addr = 0; + cache->segments[i].host_addr = 0; + } +} + + +static void +hdd_zones_init(hard_disk_t *hdd) +{ + uint32_t lba = 0, track = 0; + uint32_t i, tracks; + double revolution_usec = 60.0 / (double)hdd->rpm * 1000000.0; + hdd_zone_t *zone; + + for (i = 0; i < hdd->num_zones; i++) { + zone = &hdd->zones[i]; + zone->start_sector = lba; + zone->start_track = track; + zone->sector_time_usec = revolution_usec / (double)zone->sectors_per_track; + tracks = zone->cylinders * hdd->phy_heads; + lba += tracks * zone->sectors_per_track; + zone->end_sector = lba - 1; + track += tracks - 1; + } +} + + +static hdd_preset_t hdd_speed_presets[] = { + { .name = "RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, + + { .name = "[1989] 3500 RPM", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, + .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 }, + + { .name = "[1992] 3600 RPM", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, + .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, + + { .name = "[1994] 4500 RPM", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, + .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 }, + + { .name = "[1996] 5400 RPM", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, + .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, + + { .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, + .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 }, + + { .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, + .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, + + { .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, + .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, +}; + + +int +hdd_preset_get_num() +{ + return sizeof(hdd_speed_presets) / sizeof(hdd_preset_t); +} + + +char * +hdd_preset_getname(int preset) +{ + return (char *)hdd_speed_presets[preset].name; +} + + +char * +hdd_preset_get_internal_name(int preset) +{ + return (char *)hdd_speed_presets[preset].internal_name; +} + + +int +hdd_preset_get_from_internal_name(char *s) +{ + int c = 0; + + for (int i = 0; i < (sizeof(hdd_speed_presets) / sizeof(hdd_preset_t)); i++) { + if (!strcmp((char *)hdd_speed_presets[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + + +void +hdd_preset_apply(int hdd_id) +{ + hard_disk_t *hd = &hdd[hdd_id]; + double revolution_usec, zone_percent; + uint32_t disk_sectors, sectors_per_surface, cylinders, cylinders_per_zone; + uint32_t total_sectors = 0, i; + uint32_t spt, zone_sectors; + + if (hd->speed_preset >= hdd_preset_get_num()) + hd->speed_preset = 0; + + hdd_preset_t *preset = &hdd_speed_presets[hd->speed_preset]; + + hd->cache.num_segments = preset->rcache_num_seg; + hd->cache.segment_size = preset->rcache_seg_size; + hd->max_multiple_block = preset->max_multiple; + + if (!hd->speed_preset) + return; + + hd->phy_heads = preset->heads; + hd->rpm = preset->rpm; + + revolution_usec = 60.0 / (double)hd->rpm * 1000000.0; + hd->avg_rotation_lat_usec = revolution_usec / 2; + hd->full_stroke_usec = preset->full_stroke_ms * 1000; + hd->head_switch_usec = preset->track_seek_ms * 1000; + hd->cyl_switch_usec = preset->track_seek_ms * 1000; + + hd->cache.write_size = 64; + + hd->num_zones = preset->zones; + + disk_sectors = hd->tracks * hd->hpc * hd->spt; + sectors_per_surface = (uint32_t)ceil((double)disk_sectors / (double)hd->phy_heads); + cylinders = (uint32_t)ceil((double)sectors_per_surface / (double)preset->avg_spt); + hd->phy_cyl = cylinders; + cylinders_per_zone = cylinders / preset->zones; + + for (i = 0; i < preset->zones; i++) { + zone_percent = i * 100 / (double)preset->zones; + + if (i < preset->zones - 1) { + /* Function for realistic zone sector density */ + double spt_percent = -0.00341684 * pow(zone_percent, 2) - 0.175811 * zone_percent + 118.48; + spt = (uint32_t)ceil((double)preset->avg_spt * spt_percent / 100); + } else + spt = (uint32_t)ceil((double)(disk_sectors - total_sectors) / (double)(cylinders_per_zone*preset->heads)); + + zone_sectors = spt * cylinders_per_zone * preset->heads; + total_sectors += zone_sectors; + + hd->zones[i].cylinders = cylinders_per_zone; + hd->zones[i].sectors_per_track = spt; + } + + hdd_zones_init(hd); + hdd_cache_init(hd); +} diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index aa8bf8509..a775ce7c9 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -16,8 +16,6 @@ * Copyright 2016-2018 Miran Grca. * Copyright 2017,2018 Fred N. van Kempen. */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #define _GNU_SOURCE #include #include @@ -29,18 +27,26 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/random.h> #include <86box/hdd.h> +#include "minivhd/minivhd.h" +#include "minivhd/minivhd_internal.h" +#define HDD_IMAGE_RAW 0 +#define HDD_IMAGE_HDI 1 +#define HDD_IMAGE_HDX 2 +#define HDD_IMAGE_VHD 3 typedef struct { - FILE *file; - uint32_t base; - uint32_t pos, last_sector; - uint8_t type; - uint8_t loaded; + FILE *file; /* Used for HDD_IMAGE_RAW, HDD_IMAGE_HDI, and HDD_IMAGE_HDX. */ + MVHDMeta* vhd; /* Used for HDD_IMAGE_VHD. */ + uint32_t base; + uint32_t pos, last_sector; + uint8_t type; /* HDD_IMAGE_RAW, HDD_IMAGE_HDI, HDD_IMAGE_HDX, or HDD_IMAGE_VHD */ + uint8_t loaded; } hdd_image_t; @@ -49,27 +55,6 @@ hdd_image_t hdd_images[HDD_NUM]; static char empty_sector[512]; static char *empty_sector_1mb; - -#define VHD_OFFSET_COOKIE 0 -#define VHD_OFFSET_FEATURES 8 -#define VHD_OFFSET_VERSION 12 -#define VHD_OFFSET_DATA_OFFSET 16 -#define VHD_OFFSET_TIMESTAMP 24 -#define VHD_OFFSET_CREATOR 28 -#define VHD_OFFSET_CREATOR_VERS 32 -#define VHD_OFFSET_CREATOR_HOST 36 -#define VHD_OFFSET_ORIG_SIZE 40 -#define VHD_OFFSET_CURR_SIZE 48 -#define VHD_OFFSET_GEOM_CYL 56 -#define VHD_OFFSET_GEOM_HEAD 58 -#define VHD_OFFSET_GEOM_SPT 59 -#define VHD_OFFSET_TYPE 60 -#define VHD_OFFSET_CHECKSUM 64 -#define VHD_OFFSET_UUID 68 -#define VHD_OFFSET_SAVED_STATE 84 -#define VHD_OFFSET_RESERVED 85 - - #ifdef ENABLE_HDD_IMAGE_LOG int hdd_image_do_log = ENABLE_HDD_IMAGE_LOG; @@ -77,885 +62,626 @@ int hdd_image_do_log = ENABLE_HDD_IMAGE_LOG; static void hdd_image_log(const char *fmt, ...) { - va_list ap; + va_list ap; - if (hdd_image_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } + if (hdd_image_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } } #else #define hdd_image_log(fmt, ...) #endif - int -image_is_hdi(const wchar_t *s) +image_is_hdi(const char *s) { - int len; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - char *ws = (char *) s; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (! wcscasecmp(ext, L".HDI")) - return 1; - else - return 0; -} - - -int -image_is_hdx(const wchar_t *s, int check_signature) -{ - int len; - FILE *f; - uint64_t filelen; - uint64_t signature; - char *ws = (char *) s; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (wcscasecmp(ext, L".HDX") == 0) { - if (check_signature) { - f = plat_fopen((wchar_t *)s, L"rb"); - if (!f) - return 0; - if (fseeko64(f, 0, SEEK_END)) - fatal("image_is_hdx(): Error while seeking"); - filelen = ftello64(f); - if (fseeko64(f, 0, SEEK_SET)) - fatal("image_is_hdx(): Error while seeking"); - if (filelen < 44) { - if (f != NULL) - fclose(f); - return 0; - } - if (fread(&signature, 1, 8, f) != 8) - fatal("image_is_hdx(): Error reading signature\n"); - fclose(f); - if (signature == 0xD778A82044445459ll) - return 1; - else - return 0; - } else + if (! strcasecmp(path_get_extension((char *) s), "HDI")) return 1; - } else - return 0; + else + return 0; } int -image_is_vhd(const wchar_t *s, int check_signature) +image_is_hdx(const char *s, int check_signature) { - int len; - FILE *f; - uint64_t filelen; - uint64_t signature; - char *ws = (char *) s; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (wcscasecmp(ext, L".VHD") == 0) { - if (check_signature) { - f = plat_fopen((wchar_t *)s, L"rb"); - if (!f) - return 0; - fseeko64(f, 0, SEEK_END); - filelen = ftello64(f); - if (fseeko64(f, -512, SEEK_END) == -1) { + FILE *f; + uint64_t filelen; + uint64_t signature; + + if (! strcasecmp(path_get_extension((char *) s), "HDX")) { + if (check_signature) { + f = plat_fopen(s, "rb"); + if (!f) + return 0; + if (fseeko64(f, 0, SEEK_END)) + fatal("image_is_hdx(): Error while seeking"); + filelen = ftello64(f); + if (fseeko64(f, 0, SEEK_SET)) + fatal("image_is_hdx(): Error while seeking"); + if (filelen < 44) { + if (f != NULL) + fclose(f); + return 0; + } + if (fread(&signature, 1, 8, f) != 8) + fatal("image_is_hdx(): Error reading signature\n"); fclose(f); - fatal("image_is_vhd(): Error seeking\n"); - } - if (filelen < 512) { - if (f != NULL) - fclose(f); - return 0; - } - if (fread(&signature, 1, 8, f) != 8) - fatal("image_is_vhd(): Error reading signature\n"); - fclose(f); - if (signature == 0x78697463656E6F63ll) + if (signature == 0xD778A82044445459ll) + return 1; + else + return 0; + } else return 1; - else - return 0; } else - return 1; - } else - return 0; + return 0; } -static uint64_t -be_to_u64(uint8_t *bytes, int start) +int +image_is_vhd(const char *s, int check_signature) { - uint64_t n = ((uint64_t) bytes[start + 7] << 0) | - ((uint64_t) bytes[start + 6] << 8) | - ((uint64_t) bytes[start + 5] << 16) | - ((uint64_t) bytes[start + 4] << 24) | - ((uint64_t) bytes[start + 3] << 32) | - ((uint64_t) bytes[start + 2] << 40) | - ((uint64_t) bytes[start + 1] << 48) | - ((uint64_t) bytes[start ] << 56); - return n; + FILE* f; + + if (! strcasecmp(path_get_extension((char *) s), "VHD")) { + if (check_signature) { + f = plat_fopen(s, "rb"); + if (!f) + return 0; + + bool is_vhd = mvhd_file_is_vhd(f); + fclose(f); + return is_vhd ? 1 : 0; + } else + return 1; + } else + return 0; } - -static uint32_t -be_to_u32(uint8_t *bytes, int start) -{ - uint32_t n = ((uint32_t) bytes[start + 3] << 0) | - ((uint32_t) bytes[start + 2] << 8) | - ((uint32_t) bytes[start + 1] << 16) | - ((uint32_t) bytes[start ] << 24); - return n; -} - - -static uint16_t -be_to_u16(uint8_t *bytes, int start) -{ - uint16_t n = ((uint16_t) bytes[start + 1] << 0) | - ((uint16_t) bytes[start ] << 8); - return n; -} - - -static uint64_t -u64_to_be(uint64_t value, int is_be) -{ - uint64_t res = 0; - if (is_be) - res = value; - else { - uint64_t mask = 0xff00000000000000; - res = ((value & (mask >> 0)) >> 56) | - ((value & (mask >> 8)) >> 40) | - ((value & (mask >> 16)) >> 24) | - ((value & (mask >> 24)) >> 8) | - ((value & (mask >> 32)) << 8) | - ((value & (mask >> 40)) << 24) | - ((value & (mask >> 48)) << 40) | - ((value & (mask >> 56)) << 56); - } - return res; -} - - -static uint32_t -u32_to_be(uint32_t value, int is_be) -{ - uint32_t res = 0; - if (is_be) - res = value; - else { - uint32_t mask = 0xff000000; - res = ((value & (mask >> 0)) >> 24) | - ((value & (mask >> 8)) >> 8) | - ((value & (mask >> 16)) << 8) | - ((value & (mask >> 24)) << 24); - } - return res; -} - - -static uint16_t -u16_to_be(uint16_t value, int is_be) -{ - uint16_t res = 0; - if (is_be) - res = value; - else - res = (value >> 8) | (value << 8); - - return res; -} - - -static void -mk_guid(uint8_t *guid) -{ - int n; - - for (n = 0; n < 16; n++) - guid[n] = random_generate(); - - guid[6] &= 0x0F; - guid[6] |= 0x40; /* Type 4 */ - guid[8] &= 0x3F; - guid[8] |= 0x80; /* Variant 1 */ -} - - -static uint32_t -calc_vhd_timestamp() -{ - time_t start_time; - time_t curr_time; - double vhd_time; - start_time = 946684800; /* 1 Jan 2000 00:00 */ - curr_time = time(NULL); - vhd_time = difftime(curr_time, start_time); - - return (uint32_t)vhd_time; -} - - -void -vhd_footer_from_bytes(vhd_footer_t *vhd, uint8_t *bytes) -{ - memcpy(vhd->cookie, bytes + VHD_OFFSET_COOKIE, sizeof(vhd->cookie)); - vhd->features = be_to_u32(bytes, VHD_OFFSET_FEATURES); - vhd->version = be_to_u32(bytes, VHD_OFFSET_VERSION); - vhd->offset = be_to_u64(bytes, VHD_OFFSET_DATA_OFFSET); - vhd->timestamp = be_to_u32(bytes, VHD_OFFSET_TIMESTAMP); - memcpy(vhd->creator, bytes + VHD_OFFSET_CREATOR, sizeof(vhd->creator)); - vhd->creator_vers = be_to_u32(bytes, VHD_OFFSET_CREATOR_VERS); - memcpy(vhd->creator_host_os, bytes + VHD_OFFSET_CREATOR_HOST, sizeof(vhd->creator_host_os)); - vhd->orig_size = be_to_u64(bytes, VHD_OFFSET_ORIG_SIZE); - vhd->curr_size = be_to_u64(bytes, VHD_OFFSET_CURR_SIZE); - vhd->geom.cyl = be_to_u16(bytes, VHD_OFFSET_GEOM_CYL); - vhd->geom.heads = bytes[VHD_OFFSET_GEOM_HEAD]; - vhd->geom.spt = bytes[VHD_OFFSET_GEOM_SPT]; - vhd->type = be_to_u32(bytes, VHD_OFFSET_TYPE); - vhd->checksum = be_to_u32(bytes, VHD_OFFSET_CHECKSUM); - memcpy(vhd->uuid, bytes + VHD_OFFSET_UUID, sizeof(vhd->uuid)); /* TODO: handle UUID's properly */ - vhd->saved_state = bytes[VHD_OFFSET_SAVED_STATE]; - memcpy(vhd->reserved, bytes + VHD_OFFSET_RESERVED, sizeof(vhd->reserved)); -} - - -void -vhd_footer_to_bytes(uint8_t *bytes, vhd_footer_t *vhd) -{ - /* Quick endian check */ - int is_be = 0; - uint8_t e = 1; - uint8_t *ep = &e; - uint16_t u16; - uint32_t u32; - uint64_t u64; - - if (ep[0] == 0) - is_be = 1; - - memcpy(bytes + VHD_OFFSET_COOKIE, vhd->cookie, sizeof(vhd->cookie)); - u32 = u32_to_be(vhd->features, is_be); - memcpy(bytes + VHD_OFFSET_FEATURES, &u32, sizeof(vhd->features)); - u32 = u32_to_be(vhd->version, is_be); - memcpy(bytes + VHD_OFFSET_VERSION, &u32, sizeof(vhd->version)); - u64 = u64_to_be(vhd->offset, is_be); - memcpy(bytes + VHD_OFFSET_DATA_OFFSET, &u64, sizeof(vhd->offset)); - u32 = u32_to_be(vhd->timestamp, is_be); - memcpy(bytes + VHD_OFFSET_TIMESTAMP, &u32, sizeof(vhd->timestamp)); - memcpy(bytes + VHD_OFFSET_CREATOR, vhd->creator, sizeof(vhd->creator)); - u32 = u32_to_be(vhd->creator_vers, is_be); - memcpy(bytes + VHD_OFFSET_CREATOR_VERS, &u32, sizeof(vhd->creator_vers)); - memcpy(bytes + VHD_OFFSET_CREATOR_HOST, vhd->creator_host_os, sizeof(vhd->creator_host_os)); - u64 = u64_to_be(vhd->orig_size, is_be); - memcpy(bytes + VHD_OFFSET_ORIG_SIZE, &u64, sizeof(vhd->orig_size)); - u64 = u64_to_be(vhd->curr_size, is_be); - memcpy(bytes + VHD_OFFSET_CURR_SIZE, &u64, sizeof(vhd->curr_size)); - u16 = u16_to_be(vhd->geom.cyl, is_be); - memcpy(bytes + VHD_OFFSET_GEOM_CYL, &u16, sizeof(vhd->geom.cyl)); - memcpy(bytes + VHD_OFFSET_GEOM_HEAD, &(vhd->geom.heads), sizeof(vhd->geom.heads)); - memcpy(bytes + VHD_OFFSET_GEOM_SPT, &(vhd->geom.spt), sizeof(vhd->geom.spt)); - u32 = u32_to_be(vhd->type, is_be); - memcpy(bytes + VHD_OFFSET_TYPE, &u32, sizeof(vhd->type)); - u32 = u32_to_be(vhd->checksum, is_be); - memcpy(bytes + VHD_OFFSET_CHECKSUM, &u32, sizeof(vhd->checksum)); - memcpy(bytes + VHD_OFFSET_UUID, vhd->uuid, sizeof(vhd->uuid)); - memcpy(bytes + VHD_OFFSET_SAVED_STATE, &(vhd->saved_state), sizeof(vhd->saved_state)); - memcpy(bytes + VHD_OFFSET_RESERVED, vhd->reserved, sizeof(vhd->reserved)); -} - - -void -new_vhd_footer(vhd_footer_t **vhd) -{ - uint8_t cookie[8] = {'c', 'o', 'n', 'e', 'c', 't', 'i', 'x'}; - uint8_t creator[4] = {'8', '6', 'b', 'x'}; - uint8_t cr_host_os[4] = {'W', 'i', '2', 'k'}; - - if (*vhd == NULL) - *vhd = (vhd_footer_t *) malloc(sizeof(vhd_footer_t)); - - memcpy((*vhd)->cookie, cookie, 8); - (*vhd)->features = 0x00000002; - (*vhd)->version = 0x00010000; - (*vhd)->offset = 0xffffffffffffffff; /* fixed disk */ - (*vhd)->timestamp = calc_vhd_timestamp(); - memcpy((*vhd)->creator, creator, 4); - (*vhd)->creator_vers = 0x00010000; - memcpy((*vhd)->creator_host_os, cr_host_os, 4); - (*vhd)->type = 2; /* fixed disk */ - mk_guid((*vhd)->uuid); - (*vhd)->saved_state = 0; - memset((*vhd)->reserved, 0, 427); -} - - -void -generate_vhd_checksum(vhd_footer_t *vhd) -{ - uint32_t chk = 0; - int i; - for (i = 0; i < sizeof(vhd_footer_t); i++) { - /* We don't include the checksum field in the checksum */ - if ((i < VHD_OFFSET_CHECKSUM) || (i >= VHD_OFFSET_UUID)) - chk += ((uint8_t*)vhd)[i]; - } - vhd->checksum = ~chk; -} - - void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size) { - /* Calculate the geometry from size (in MB), using the algorithm provided in - "Virtual Hard Disk Image Format Specification, Appendix: CHS Calculation" */ - uint64_t ts = ((uint64_t) size) << 11LL; - uint32_t spt, heads, cyl, cth; - if (ts > 65535 * 16 * 255) - ts = 65535 * 16 * 255; + /* Calculate the geometry from size (in MB), using the algorithm provided in + "Virtual Hard Disk Image Format Specification, Appendix: CHS Calculation" */ + uint64_t ts = ((uint64_t) size) << 11LL; + uint32_t spt, heads, cyl, cth; + if (ts > 65535 * 16 * 255) + ts = 65535 * 16 * 255; - if (ts >= 65535 * 16 * 63) { - spt = 255; - heads = 16; - cth = (uint32_t) (ts / spt); - } else { - spt = 17; - cth = (uint32_t) (ts / spt); - heads = (cth +1023) / 1024; - if (heads < 4) - heads = 4; - if ((cth >= (heads * 1024)) || (heads > 16)) { - spt = 31; + if (ts >= 65535 * 16 * 63) { + spt = 255; heads = 16; cth = (uint32_t) (ts / spt); - } - if (cth >= (heads * 1024)) { - spt = 63; - heads = 16; + } else { + spt = 17; cth = (uint32_t) (ts / spt); + heads = (cth +1023) / 1024; + if (heads < 4) + heads = 4; + if ((cth >= (heads * 1024)) || (heads > 16)) { + spt = 31; + heads = 16; + cth = (uint32_t) (ts / spt); + } + if (cth >= (heads * 1024)) { + spt = 63; + heads = 16; + cth = (uint32_t) (ts / spt); + } } - } - cyl = cth / heads; - *c = cyl; - *h = heads; - *s = spt; + cyl = cth / heads; + *c = cyl; + *h = heads; + *s = spt; } static int prepare_new_hard_disk(uint8_t id, uint64_t full_size) { - uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); + uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); - uint32_t size; - uint32_t t, i; + uint32_t size; + uint32_t t, i; - t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */ - size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */ + t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */ + size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */ - empty_sector_1mb = (char *) malloc(1048576); - memset(empty_sector_1mb, 0, 1048576); + empty_sector_1mb = (char *) malloc(1048576); + memset(empty_sector_1mb, 0, 1048576); - /* Temporarily switch off suppression of seen messages so that the - progress gets displayed. */ - pclog_toggle_suppr(); - pclog("Writing image sectors: ["); + /* Temporarily switch off suppression of seen messages so that the + progress gets displayed. */ + pclog_toggle_suppr(); + pclog("Writing image sectors: ["); - /* First, write all the 1 MB blocks. */ - if (t > 0) { - for (i = 0; i < t; i++) { + /* First, write all the 1 MB blocks. */ + if (t > 0) { + for (i = 0; i < t; i++) { + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); + pclog("#"); + } + } + + /* Then, write the remainder. */ + if (size > 0) { fseek(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); + fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); pclog("#"); } - } + pclog("]\n"); + /* Switch the suppression of seen messages back on. */ + pclog_toggle_suppr(); - /* Then, write the remainder. */ - if (size > 0) { - fseek(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); - pclog("#"); - } - pclog("]\n"); - /* Switch the suppression of seen messages back on. */ - pclog_toggle_suppr(); + free(empty_sector_1mb); - free(empty_sector_1mb); + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; - hdd_images[id].loaded = 1; - - return 1; + return 1; } void hdd_image_init(void) { - int i; + int i; - for (i = 0; i < HDD_NUM; i++) - memset(&hdd_images[i], 0, sizeof(hdd_image_t)); + for (i = 0; i < HDD_NUM; i++) + memset(&hdd_images[i], 0, sizeof(hdd_image_t)); } - -static void -hdd_image_gen_vft(int id, vhd_footer_t **vft, uint64_t full_size) -{ - /* Generate new footer. */ - new_vhd_footer(vft); - (*vft)->orig_size = (*vft)->curr_size = full_size; - (*vft)->geom.cyl = hdd[id].tracks; - (*vft)->geom.heads = hdd[id].hpc; - (*vft)->geom.spt = hdd[id].spt; - generate_vhd_checksum(*vft); - vhd_footer_to_bytes((uint8_t *) empty_sector, *vft); - fseeko64(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector, 1, 512, hdd_images[id].file); - free(*vft); - *vft = NULL; - hdd_images[id].type = 3; -} - - int hdd_image_load(int id) { - uint32_t sector_size = 512; - uint32_t zero = 0; - uint64_t signature = 0xD778A82044445459ll; - uint64_t full_size = 0; - uint64_t spt = 0, hpc = 0, tracks = 0; - int c, ret; - uint64_t s = 0; - wchar_t *fn = hdd[id].fn; - int is_hdx[2] = { 0, 0 }; - int is_vhd[2] = { 0, 0 }; - vhd_footer_t *vft = NULL; + uint32_t sector_size = 512; + uint32_t zero = 0; + uint64_t signature = 0xD778A82044445459ll; + uint64_t full_size = 0; + uint64_t spt = 0, hpc = 0, tracks = 0; + int c, ret; + uint64_t s = 0; + char *fn = hdd[id].fn; + int is_hdx[2] = { 0, 0 }; + int is_vhd[2] = { 0, 0 }; + int vhd_error = 0; - memset(empty_sector, 0, sizeof(empty_sector)); - - hdd_images[id].base = 0; - - if (hdd_images[id].loaded) { - if (hdd_images[id].file) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; + memset(empty_sector, 0, sizeof(empty_sector)); + if (fn) { + path_normalize(fn); } - hdd_images[id].loaded = 0; - } - is_hdx[0] = image_is_hdx(fn, 0); - is_hdx[1] = image_is_hdx(fn, 1); - is_vhd[0] = image_is_vhd(fn, 0); - is_vhd[1] = image_is_vhd(fn, 1); + hdd_images[id].base = 0; - hdd_images[id].pos = 0; - - /* Try to open existing hard disk image */ - if (fn[0] == '.') { - hdd_image_log("File name starts with .\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - hdd_images[id].file = plat_fopen(fn, L"rb+"); - if (hdd_images[id].file == NULL) { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) { - /* Failed because it does not exist, - so try to create new file */ - if (hdd[id].wp) { - hdd_image_log("A write-protected image must exist\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; + if (hdd_images[id].loaded) { + if (hdd_images[id].file) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; } - - hdd_images[id].file = plat_fopen(fn, L"wb+"); - if (hdd_images[id].file == NULL) { - hdd_image_log("Unable to open image\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } else { - if (image_is_hdi(fn)) { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].base = 0x1000; - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); - fwrite(&full_size, 1, 4, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - for (c = 0; c < 0x3f8; c++) - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = 1; - } else if (is_hdx[0]) { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].base = 0x28; - fwrite(&signature, 1, 8, hdd_images[id].file); - fwrite(&full_size, 1, 8, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = 2; - } - else - hdd_images[id].type = 0; - hdd_images[id].last_sector = 0; + else if (hdd_images[id].vhd) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; } + hdd_images[id].loaded = 0; + } - s = full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; + is_hdx[0] = image_is_hdx(fn, 0); + is_hdx[1] = image_is_hdx(fn, 1); - ret = prepare_new_hard_disk(id, full_size); + is_vhd[0] = image_is_vhd(fn, 0); + is_vhd[1] = image_is_vhd(fn, 1); - if (is_vhd[0]) { - /* VHD image. */ - hdd_image_gen_vft(id, &vft, full_size); - } + hdd_images[id].pos = 0; - return ret; - } else { - /* Failed for another reason */ - hdd_image_log("Failed for another reason\n"); + /* Try to open existing hard disk image */ + if (fn[0] == '.') { + hdd_image_log("File name starts with .\n"); memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); return 0; } - } else { - if (image_is_hdi(fn)) { - if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); - if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading base offset\n"); - if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); - full_size = 0LL; - if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading full size\n"); - if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); - if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sector size\n"); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDI: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; + hdd_images[id].file = plat_fopen(fn, "rb+"); + if (hdd_images[id].file == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + if (hdd[id].wp) { + hdd_image_log("A write-protected image must exist\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + + hdd_images[id].file = plat_fopen(fn, "wb+"); + if (hdd_images[id].file == NULL) { + hdd_image_log("Unable to open image\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } else { + if (image_is_hdi(fn)) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x1000; + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fwrite(&full_size, 1, 4, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + for (c = 0; c < 0x3f8; c++) + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = HDD_IMAGE_HDI; + } else if (is_hdx[0]) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x28; + fwrite(&signature, 1, 8, hdd_images[id].file); + fwrite(&full_size, 1, 8, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = HDD_IMAGE_HDX; + } else if (is_vhd[0]) { + fclose(hdd_images[id].file); + MVHDGeom geometry; + geometry.cyl = hdd[id].tracks; + geometry.heads = hdd[id].hpc; + geometry.spt = hdd[id].spt; + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].last_sector = (full_size >> 9LL) - 1; + + hdd_images[id].vhd = mvhd_create_fixed(fn, geometry, &vhd_error, NULL); + if (hdd_images[id].vhd == NULL) + fatal("hdd_image_load(): VHD: Could not create VHD : %s\n", mvhd_strerr(vhd_error)); + + hdd_images[id].type = HDD_IMAGE_VHD; + return 1; + } else { + hdd_images[id].type = HDD_IMAGE_RAW; + } + hdd_images[id].last_sector = 0; + } + + s = full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + + ret = prepare_new_hard_disk(id, full_size); + return ret; + } else { + /* Failed for another reason */ + hdd_image_log("Failed for another reason\n"); memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); return 0; } - if (fread(&spt, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); - if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); - if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = 1; - } else if (is_hdx[1]) { - hdd_images[id].base = 0x28; - if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) - fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); - if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) - fatal("hdd_image_load(): HDX: Error reading full size\n"); - if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) - fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); - if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDX: Error reading sector size\n"); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDX: Sector size is not 512\n"); + } else { + if (image_is_hdi(fn)) { + if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); + if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading base offset\n"); + if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); + full_size = 0LL; + if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sector size\n"); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDI: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = HDD_IMAGE_HDI; + } else if (is_hdx[1]) { + hdd_images[id].base = 0x28; + if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); + if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) + fatal("hdd_image_load(): HDX: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading sector size\n"); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDX: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = HDD_IMAGE_HDX; + } else if (is_vhd[1]) { fclose(hdd_images[id].file); hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; + hdd_images[id].vhd = mvhd_open(fn, (bool)0, &vhd_error); + if (hdd_images[id].vhd == NULL) { + if (vhd_error == MVHD_ERR_FILE) + fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn, strerror(mvhd_errno)); + else + fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn, mvhd_strerr(vhd_error)); + } + else if (vhd_error == MVHD_ERR_TIMESTAMP) { + fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn); + } + + hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; + hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; + hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].type = HDD_IMAGE_VHD; + /* If we're here, this means there is a valid VHD footer in the + image, which means that by definition, all valid sectors + are there. */ + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + return 1; + } else { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].type = HDD_IMAGE_RAW; } - if (fread(&spt, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); - if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); - if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = 2; - } else if (is_vhd[1]) { - if (fseeko64(hdd_images[id].file, -512, SEEK_END) == -1) - fatal("hdd_image_load(): VHD: Error seeking to 512 bytes before the end of file\n"); - if (fread(empty_sector, 1, 512, hdd_images[id].file) != 512) - fatal("hdd_image_load(): HDX: Error reading the footer\n"); - new_vhd_footer(&vft); - vhd_footer_from_bytes(vft, (uint8_t *) empty_sector); - if (vft->type != 2) { - /* VHD is not fixed size */ - hdd_image_log("VHD: Image is not fixed size\n"); - free(vft); - vft = NULL; - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - full_size = vft->orig_size; - hdd[id].tracks = vft->geom.cyl; - hdd[id].hpc = vft->geom.heads; - hdd[id].spt = vft->geom.spt; - free(vft); - vft = NULL; - hdd_images[id].type = 3; - /* If we're here, this means there is a valid VHD footer in the - image, which means that by definition, all valid sectors - are there. */ + } + + if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) + fatal("hdd_image_load(): Error seeking to the end of file\n"); + s = ftello64(hdd_images[id].file); + if (s < (full_size + hdd_images[id].base)) + ret = prepare_new_hard_disk(id, full_size); + else { hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; hdd_images[id].loaded = 1; - return 1; - } else { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].type = 0; + ret = 1; } - } - if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) - fatal("hdd_image_load(): Error seeking to the end of file\n"); - s = ftello64(hdd_images[id].file); - if (s < (full_size + hdd_images[id].base)) - ret = prepare_new_hard_disk(id, full_size); - else { - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].loaded = 1; - ret = 1; - } - - if (is_vhd[0]) { - if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) - fatal("hdd_image_load(): VHD: Error seeking to the end of file\n"); - s = ftello64(hdd_images[id].file); - if (s == (full_size + hdd_images[id].base)) { - /* VHD image. */ - hdd_image_gen_vft(id, &vft, full_size); - } - } - - return ret; + return ret; } void hdd_image_seek(uint8_t id, uint32_t sector) { - off64_t addr = sector; - addr = (uint64_t)sector << 9LL; + off64_t addr = sector; + addr = (uint64_t)sector << 9LL; - hdd_images[id].pos = sector; - if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) - fatal("hdd_image_seek(): Error seeking\n"); + hdd_images[id].pos = sector; + if (hdd_images[id].type != HDD_IMAGE_VHD) { + if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) + fatal("hdd_image_seek(): Error seeking\n"); + } } void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - int i; + int non_transferred_sectors; + size_t num_read; - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Read error during seek\n", id); - return; - } + if (hdd_images[id].type == HDD_IMAGE_VHD) { + non_transferred_sectors = mvhd_read_sectors(hdd_images[id].vhd, sector, count, buffer); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Read error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; - - hdd_images[id].pos = sector + i; - fread(buffer + (i << 9), 1, 512, hdd_images[id].file); - } -} - - -uint32_t -hdd_sectors(uint8_t id) -{ - fseeko64(hdd_images[id].file, 0, SEEK_END); - return (uint32_t) ((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); -} - - -int -hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); - - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; - - hdd_image_read(id, sector, transfer_sectors, buffer); - - if (count != transfer_sectors) - return 1; - return 0; -} - - -void -hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - int i; - - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Write error during seek\n", id); - return; - } - - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; - - hdd_images[id].pos = sector + i; - fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); - } -} - - -int -hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); - - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; - - hdd_image_write(id, sector, transfer_sectors, buffer); - - if (count != transfer_sectors) - return 1; - return 0; -} - - -void -hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) -{ - uint32_t i = 0; - - memset(empty_sector, 0, 512); - - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Zero error during seek\n", id); - return; - } - - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; - - hdd_images[id].pos = sector + i; - fwrite(empty_sector, 512, 1, hdd_images[id].file); - } -} - - -int -hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) -{ - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); - - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; - - hdd_image_zero(id, sector, transfer_sectors); - - if (count != transfer_sectors) - return 1; - return 0; + num_read = fread(buffer, 512, count, hdd_images[id].file); + hdd_images[id].pos = sector + num_read; + } } uint32_t hdd_image_get_last_sector(uint8_t id) { - return hdd_images[id].last_sector; + return hdd_images[id].last_sector; +} + + +uint32_t +hdd_sectors(uint8_t id) +{ + return hdd_image_get_last_sector(id) - 1; +} + + +int +hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + hdd_image_read(id, sector, transfer_sectors, buffer); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +void +hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + int non_transferred_sectors; + size_t num_write; + + if (hdd_images[id].type == HDD_IMAGE_VHD) { + non_transferred_sectors = mvhd_write_sectors(hdd_images[id].vhd, sector, count, buffer); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Write error during seek\n", id); + return; + } + + num_write = fwrite(buffer, 512, count, hdd_images[id].file); + hdd_images[id].pos = sector + num_write; + } +} + + +int +hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + hdd_image_write(id, sector, transfer_sectors, buffer); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +void +hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) +{ + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_format_sectors(hdd_images[id].vhd, sector, count); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + uint32_t i = 0; + + memset(empty_sector, 0, 512); + + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Zero error during seek\n", id); + return; + } + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; + fwrite(empty_sector, 512, 1, hdd_images[id].file); + } + } +} + + +int +hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + hdd_image_zero(id, sector, transfer_sectors); + + if (count != transfer_sectors) + return 1; + return 0; } uint32_t hdd_image_get_pos(uint8_t id) { - return hdd_images[id].pos; + return hdd_images[id].pos; } uint8_t hdd_image_get_type(uint8_t id) { - return hdd_images[id].type; + return hdd_images[id].type; } void hdd_image_unload(uint8_t id, int fn_preserve) { - if (wcslen(hdd[id].fn) == 0) - return; + if (strlen(hdd[id].fn) == 0) + return; - if (hdd_images[id].loaded) { - if (hdd_images[id].file != NULL) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; + if (hdd_images[id].loaded) { + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } else if (hdd_images[id].vhd != NULL) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } + hdd_images[id].loaded = 0; } - hdd_images[id].loaded = 0; - } - hdd_images[id].last_sector = -1; + hdd_images[id].last_sector = -1; - memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); - if (fn_preserve) - wcscpy(hdd[id].prev_fn, hdd[id].fn); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); + if (fn_preserve) + strcpy(hdd[id].prev_fn, hdd[id].fn); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); } void hdd_image_close(uint8_t id) { - hdd_image_log("hdd_image_close(%i)\n", id); + hdd_image_log("hdd_image_close(%i)\n", id); - if (!hdd_images[id].loaded) - return; + if (!hdd_images[id].loaded) + return; - if (hdd_images[id].file != NULL) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } - memset(&hdd_images[id], 0, sizeof(hdd_image_t)); - hdd_images[id].loaded = 0; + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } else if (hdd_images[id].vhd != NULL) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } + + memset(&hdd_images[id], 0, sizeof(hdd_image_t)); + hdd_images[id].loaded = 0; } diff --git a/src/disk/hdd_table.c b/src/disk/hdd_table.c index 05eae6990..a851782f3 100644 --- a/src/disk/hdd_table.c +++ b/src/disk/hdd_table.c @@ -107,7 +107,7 @@ unsigned int hdd_table[128][3] = { { 751, 8, 26 }, { 1024, 9, 17 }, { 965, 10, 17 }, - + { 969, 5, 34 }, /* 072-079 */ { 980, 10, 17 }, { 960, 5, 35 }, diff --git a/src/disk/minivhd/CMakeLists.txt b/src/disk/minivhd/CMakeLists.txt new file mode 100644 index 000000000..0cba1fb39 --- /dev/null +++ b/src/disk/minivhd/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(minivhd STATIC cwalk.c libxml2_encoding.c minivhd_convert.c + minivhd_create.c minivhd_io.c minivhd_manage.c minivhd_struct_rw.c + minivhd_util.c) diff --git a/src/disk/minivhd/CREDITS.md b/src/disk/minivhd/CREDITS.md new file mode 100644 index 000000000..c494d4e43 --- /dev/null +++ b/src/disk/minivhd/CREDITS.md @@ -0,0 +1,12 @@ +# Credits +MiniVHD Copyright (c) 2019 Sherman Perry + +MiniVHD was made possible with the help of the following projects + +### libxml2 +**Project Home:** http://www.xmlsoft.org/ +**License:** MIT (see src/libxml2_encoding.c for details) + +### cwalk +**Project Home:** https://likle.github.io/cwalk/ +**Licence:** MIT (https://github.com/likle/cwalk/blob/master/LICENSE.md) diff --git a/src/disk/minivhd/LICENSE b/src/disk/minivhd/LICENSE new file mode 100644 index 000000000..af7299185 --- /dev/null +++ b/src/disk/minivhd/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sherman Perry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/disk/minivhd/cwalk.c b/src/disk/minivhd/cwalk.c new file mode 100644 index 000000000..f0c48427c --- /dev/null +++ b/src/disk/minivhd/cwalk.c @@ -0,0 +1,1424 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "cwalk.h" +/** + * We try to default to a different path style depending on the operating + * system. So this should detect whether we should use windows or unix paths. + */ +#if defined(WIN32) || defined(_WIN32) || \ + defined(__WIN32) && !defined(__CYGWIN__) +static enum cwk_path_style path_style = CWK_STYLE_WINDOWS; +#else +static enum cwk_path_style path_style = CWK_STYLE_UNIX; +#endif + +/** + * This is a list of separators used in different styles. Windows can read + * multiple separators, but it generally outputs just a backslash. The output + * will always use the first character for the output. + */ +static const char *separators[] = {[CWK_STYLE_WINDOWS] = "\\/", + [CWK_STYLE_UNIX] = "/"}; + +/** + * A joined path represents multiple path strings which are concatenated, but + * not (necessarily) stored in contiguous memory. The joined path allows to + * iterate over the segments as if it was one piece of path. + */ +struct cwk_segment_joined +{ + struct cwk_segment segment; + const char **paths; + size_t path_index; +}; + +static size_t cwk_path_output_sized(char *buffer, size_t buffer_size, + size_t position, const char *str, size_t length) +{ + size_t amount_written; + + // First we determine the amount which we can write to the buffer. There are + // three cases. In the first case we have enough to store the whole string in + // it. In the second one we can only store a part of it, and in the third we + // have no space left. + if (buffer_size > position + length) { + amount_written = length; + } else if (buffer_size > position) { + amount_written = buffer_size - position; + } else { + amount_written = 0; + } + + // If we actually want to write out something we will do that here. We will + // always append a '\0', this way we are guaranteed to have a valid string at + // all times. + if (amount_written > 0) { + memmove(&buffer[position], str, amount_written); + } + + // Return the theoretical length which would have been written when everything + // would have fit in the buffer. + return length; +} + +static size_t cwk_path_output_current(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a "current" directory, which is a single character. This + // character is currently not style dependant. + return cwk_path_output_sized(buffer, buffer_size, position, ".", 1); +} + +static size_t cwk_path_output_back(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a "back" directory, which ahs two characters. This + // character is currently not style dependant. + return cwk_path_output_sized(buffer, buffer_size, position, "..", 2); +} + +static size_t cwk_path_output_separator(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a separator, which is a single character. + return cwk_path_output_sized(buffer, buffer_size, position, + separators[path_style], 1); +} + +static size_t cwk_path_output_dot(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a dot, which is a single character. This is used for extensions. + return cwk_path_output_sized(buffer, buffer_size, position, ".", 1); +} + +static size_t cwk_path_output(char *buffer, size_t buffer_size, size_t position, + const char *str) +{ + size_t length; + + // This just does a sized output internally, but first measuring the + // null-terminated string. + length = strlen(str); + return cwk_path_output_sized(buffer, buffer_size, position, str, length); +} + +static void cwk_path_terminate_output(char *buffer, size_t buffer_size, + size_t pos) +{ + if (buffer_size > 0) { + if (pos >= buffer_size) { + buffer[buffer_size - 1] = '\0'; + } else { + buffer[pos] = '\0'; + } + } +} + +static bool cwk_path_is_string_equal(const char *first, const char *second, + size_t n) +{ + // If the path style is UNIX, we will compare case sensitively. This can be + // done easily using strncmp. + if (path_style == CWK_STYLE_UNIX) { + return strncmp(first, second, n) == 0; + } + + // However, if this is windows we will have to compare case insensitively. + // Since there is no standard method to do that we will have to do it on our + // own. + while (*first && *second && n > 0) { + // We can consider the string to be not equal if the two lowercase + // characters are not equal. + if (tolower(*first++) != tolower(*second++)) { + return false; + } + + --n; + } + + // We can consider the string to be equal if we either reached n == 0 or both + // cursors point to a null character. + return n == 0 || (*first == '\0' && *second == '\0'); +} + +static const char *cwk_path_find_next_stop(const char *c) +{ + // We just move forward until we find a '\0' or a separator, which will be our + // next "stop". + while (*c != '\0' && !cwk_path_is_separator(c)) { + ++c; + } + + // Return the pointer of the next stop. + return c; +} + +static const char *cwk_path_find_previous_stop(const char *begin, const char *c) +{ + // We just move back until we find a separator or reach the beginning of the + // path, which will be our previous "stop". + while (c > begin && !cwk_path_is_separator(c)) { + --c; + } + + // Return the pointer to the previous stop. We have to return the first + // character after the separator, not on the separator itself. + if (cwk_path_is_separator(c)) { + return c + 1; + } else { + return c; + } +} + +static bool cwk_path_get_first_segment_without_root(const char *path, + const char *segments, struct cwk_segment *segment) +{ + // Let's remember the path. We will move the path pointer afterwards, that's + // why this has to be done first. + segment->path = path; + segment->segments = segments; + + // Now let's check whether this is an empty string. An empty string has no + // segment it could use. + if (*segments == '\0') { + return false; + } + + // If the string starts with separators, we will jump over those. If there is + // only a slash and a '\0' after it, we can't determine the first segment + // since there is none. + while (cwk_path_is_separator(segments)) { + ++segments; + if (*segments == '\0') { + return false; + } + } + + // So this is the beginning of our segment. + segment->begin = segments; + + // Now let's determine the end of the segment, which we do by moving the path + // pointer further until we find a separator. + segments = cwk_path_find_next_stop(segments); + + // And finally, calculate the size of the segment by subtracting the position + // from the end. + segment->size = segments - segment->begin; + segment->end = segments; + + // Tell the caller that we found a segment. + return true; +} + +static bool cwk_path_get_last_segment_without_root(const char *path, + struct cwk_segment *segment) +{ + // Now this is fairly similar to the normal algorithm, however, it will assume + // that there is no root in the path. So we grab the first segment at this + // position, assuming there is no root. + if (!cwk_path_get_first_segment_without_root(path, path, segment)) { + return false; + } + + // Now we find our last segment. The segment struct of the caller + // will contain the last segment, since the function we call here will not + // change the segment struct when it reaches the end. + while (cwk_path_get_next_segment(segment)) { + // We just loop until there is no other segment left. + } + + return true; +} + +static bool cwk_path_get_first_segment_joined(const char **paths, + struct cwk_segment_joined *sj) +{ + bool result; + + // Prepare the first segment. We position the joined segment on the first path + // and assign the path array to the struct. + sj->path_index = 0; + sj->paths = paths; + + // We loop through all paths until we find one which has a segment. The result + // is stored in a variable, so we can let the caller know whether we found one + // or not. + result = false; + while (paths[sj->path_index] != NULL && + (result = cwk_path_get_first_segment(paths[sj->path_index], + &sj->segment)) == false) { + ++sj->path_index; + } + + return result; +} + +static bool cwk_path_get_next_segment_joined(struct cwk_segment_joined *sj) +{ + bool result; + + if (sj->paths[sj->path_index] == NULL) { + // We reached already the end of all paths, so there is no other segment + // left. + return false; + } else if (cwk_path_get_next_segment(&sj->segment)) { + // There was another segment on the current path, so we are good to + // continue. + return true; + } + + // We try to move to the next path which has a segment available. We must at + // least move one further since the current path reached the end. + result = false; + + do { + ++sj->path_index; + + // And we obviously have to stop this loop if there are no more paths left. + if (sj->paths[sj->path_index] == NULL) { + break; + } + + // Grab the first segment of the next path and determine whether this path + // has anything useful in it. There is one more thing we have to consider + // here - for the first time we do this we want to skip the root, but + // afterwards we will consider that to be part of the segments. + result = cwk_path_get_first_segment_without_root(sj->paths[sj->path_index], + sj->paths[sj->path_index], &sj->segment); + + } while (!result); + + // Finally, report the result back to the caller. + return result; +} + +static bool cwk_path_get_previous_segment_joined(struct cwk_segment_joined *sj) +{ + bool result; + + if (*sj->paths == NULL) { + // It's possible that there is no initialized segment available in the + // struct since there are no paths. In that case we can return false, since + // there is no previous segment. + return false; + } else if (cwk_path_get_previous_segment(&sj->segment)) { + // Now we try to get the previous segment from the current path. If we can + // do that successfully, we can let the caller know that we found one. + return true; + } + + result = false; + + do { + // We are done once we reached index 0. In that case there are no more + // segments left. + if (sj->path_index == 0) { + break; + } + + // There is another path which we have to inspect. So we decrease the path + // index. + --sj->path_index; + + // If this is the first path we will have to consider that this path might + // include a root, otherwise we just treat is as a segment. + if (sj->path_index == 0) { + result = cwk_path_get_last_segment(sj->paths[sj->path_index], + &sj->segment); + } else { + result = cwk_path_get_last_segment_without_root(sj->paths[sj->path_index], + &sj->segment); + } + + } while (!result); + + return result; +} + +static bool cwk_path_segment_back_will_be_removed(struct cwk_segment_joined *sj) +{ + enum cwk_segment_type type; + int counter; + + // We are handling back segments here. We must verify how many back segments + // and how many normal segments come before this one to decide whether we keep + // or remove it. + + // The counter determines how many normal segments are our current segment, + // which will popped off before us. If the counter goes above zero it means + // that our segment will be popped as well. + counter = 0; + + // We loop over all previous segments until we either reach the beginning, + // which means our segment will not be dropped or the counter goes above zero. + while (cwk_path_get_previous_segment_joined(sj)) { + + // Now grab the type. The type determines whether we will increase or + // decrease the counter. We don't handle a CWK_CURRENT frame here since it + // has no influence. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_NORMAL) { + // This is a normal segment. The normal segment will increase the counter + // since it neutralizes one back segment. If we go above zero we can + // return immediately. + ++counter; + if (counter > 0) { + return true; + } + } else if (type == CWK_BACK) { + // A CWK_BACK segment will reduce the counter by one. We can not remove a + // back segment as long we are not above zero since we don't have the + // opposite normal segment which we would remove. + --counter; + } + } + + // We never got a count larger than zero, so we will keep this segment alive. + return false; +} + +static bool cwk_path_segment_normal_will_be_removed( + struct cwk_segment_joined *sj) +{ + enum cwk_segment_type type; + int counter; + + // The counter determines how many segments are above our current segment, + // which will popped off before us. If the counter goes below zero it means + // that our segment will be popped as well. + counter = 0; + + // We loop over all following segments until we either reach the end, which + // means our segment will not be dropped or the counter goes below zero. + while (cwk_path_get_next_segment_joined(sj)) { + + // First, grab the type. The type determines whether we will increase or + // decrease the counter. We don't handle a CWK_CURRENT frame here since it + // has no influence. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_NORMAL) { + // This is a normal segment. The normal segment will increase the counter + // since it will be removed by a "../" before us. + ++counter; + } else if (type == CWK_BACK) { + // A CWK_BACK segment will reduce the counter by one. If we are below zero + // we can return immediately. + --counter; + if (counter < 0) { + return true; + } + } + } + + // We never got a negative count, so we will keep this segment alive. + return false; +} + +static bool +cwk_path_segment_will_be_removed(const struct cwk_segment_joined *sj, + bool absolute) +{ + enum cwk_segment_type type; + struct cwk_segment_joined sjc; + + // We copy the joined path so we don't need to modify it. + sjc = *sj; + + // First we check whether this is a CWK_CURRENT or CWK_BACK segment, since + // those will always be dropped. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_CURRENT) { + return true; + } else if (type == CWK_BACK && absolute) { + return true; + } else if (type == CWK_BACK) { + return cwk_path_segment_back_will_be_removed(&sjc); + } else { + return cwk_path_segment_normal_will_be_removed(&sjc); + } +} + +static bool +cwk_path_segment_joined_skip_invisible(struct cwk_segment_joined *sj, + bool absolute) +{ + while (cwk_path_segment_will_be_removed(sj, absolute)) { + if (!cwk_path_get_next_segment_joined(sj)) { + return false; + } + } + + return true; +} + +static void cwk_path_get_root_windows(const char *path, size_t *length) +{ + const char *c; + bool is_device_path; + + // A device path is a path which starts with "\\." or "\\?". A device path can + // be a UNC path as well, in which case it will take up one more segment. + is_device_path = false; + + // We can not determine the root if this is an empty string. So we set the + // root to NULL and the length to zero and cancel the whole thing. + c = path; + *length = 0; + if (!*c) { + return; + } + + // Now we have to verify whether this is a windows network path (UNC), which + // we will consider our root. + if (cwk_path_is_separator(c)) { + ++c; + + // Check whether the path starts with a single back slash, which means this + // is not a network path - just a normal path starting with a backslash. + if (!cwk_path_is_separator(c)) { + // Okay, this is not a network path but we still use the backslash as a + // root. + ++(*length); + return; + } + + // Yes, this is a network or device path. Skip the previous separator. Now + // we need to determine whether this is a device path. We might advance one + // character here if the server name starts with a '?' or a '.', but that's + // fine since we will search for a separator afterwards anyway. + ++c; + is_device_path = (*c == '?' || *c == '.') && cwk_path_is_separator(++c); + if (is_device_path) { + // That's a device path, and the root must be either "\\.\" or "\\?\" + // which is 4 characters long. (at least that's how Windows + // GetFullPathName behaves.) + *length = 4; + return; + } + + // We will grab anything up to the next stop. The next top might be a '\0' + // or another separator. That will be the server name. + c = cwk_path_find_next_stop(c); + + // If this is a separator and not the end of a string we wil have to include + // it. However, if this is a '\0' we must not skip it. + while (cwk_path_is_separator(c)) { + ++c; + } + + // We are now skipping the shared folder name, which will end after the + // next stop. + c = cwk_path_find_next_stop(c); + + // Then there might be a separator at the end. We will include that as well, + // it will mark the path as absolute. + if (cwk_path_is_separator(c)) { + ++c; + } + + // Finally, calculate the size of the root. + *length = c - path; + return; + } + + // Move to the next and check whether this is a colon. + if (*++c == ':') { + *length = 2; + + // Now check whether this is a backslash (or slash). If it is not, we could + // assume that the next character is a '\0' if it is a valid path. However, + // we will not assume that - since ':' is not valid in a path it must be a + // mistake by the caller than. We will try to understand it anyway. + if (cwk_path_is_separator(++c)) { + *length = 3; + } + } +} + +static void cwk_path_get_root_unix(const char *path, size_t *length) +{ + // The slash of the unix path represents the root. There is no root if there + // is no slash. + if (cwk_path_is_separator(path)) { + *length = 1; + } else { + *length = 0; + } +} + +static bool cwk_path_is_root_absolute(const char *path, size_t length) +{ + // This is definitely not absolute if there is no root. + if (length == 0) { + return false; + } + + // If there is a separator at the end of the root, we can safely consider this + // to be an absolute path. + return cwk_path_is_separator(&path[length - 1]); +} + +static size_t cwk_path_join_and_normalize_multiple(const char **paths, + char *buffer, size_t buffer_size) +{ + size_t pos; + bool absolute, has_segment_output; + struct cwk_segment_joined sj; + + // We initialize the position after the root, which should get us started. + cwk_path_get_root(paths[0], &pos); + + // Determine whether the path is absolute or not. We need that to determine + // later on whether we can remove superfluous "../" or not. + absolute = cwk_path_is_root_absolute(paths[0], pos); + + // First copy the root to the output. We will not modify the root. + cwk_path_output_sized(buffer, buffer_size, 0, paths[0], pos); + + // So we just grab the first segment. If there is no segment we will always + // output a "/", since we currently only support absolute paths here. + if (!cwk_path_get_first_segment_joined(paths, &sj)) { + goto done; + } + + // Let's assume that we don't have any segment output for now. We will toggle + // this flag once there is some output. + has_segment_output = false; + + do { + // Check whether we have to drop this segment because of resolving a + // relative path or because it is a CWK_CURRENT segment. + if (cwk_path_segment_will_be_removed(&sj, absolute)) { + continue; + } + + // Remember that we have segment output, so we can handle the trailing slash + // later on. This is necessary since we might have segments but they are all + // removed. + has_segment_output = true; + + // Write out the segment but keep in mind that we need to follow the + // buffer size limitations. That's why we use the path output functions + // here. + pos += cwk_path_output_sized(buffer, buffer_size, pos, sj.segment.begin, + sj.segment.size); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&sj)); + + // Remove the trailing slash, but only if we have segment output. We don't + // want to remove anything from the root. + if (has_segment_output) { + --pos; + } else if (pos == 0) { + // This may happen if the path is absolute and all segments have been + // removed. We can not have an empty output - and empty output means we stay + // in the current directory. So we will output a ".". + assert(absolute == false); + pos += cwk_path_output_current(buffer, buffer_size, pos); + } + + // We must append a '\0' in any case, unless the buffer size is zero. If the + // buffer size is zero, which means we can not. +done: + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And finally let our caller know about the total size of the normalized + // path. + return pos; +} + +size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer, + size_t buffer_size) +{ + size_t i; + const char *paths[4]; + + // The basename should be an absolute path if the caller is using the API + // correctly. However, he might not and in that case we will append a fake + // root at the beginning. + if (cwk_path_is_absolute(base)) { + i = 0; + } else { + paths[0] = "/"; + i = 1; + } + + if (cwk_path_is_absolute(path)) { + // If the submitted path is not relative the base path becomes irrelevant. + // We will only normalize the submitted path instead. + paths[i++] = path; + paths[i] = NULL; + } else { + // Otherwise we append the relative path to the base path and normalize it. + // The result will be a new absolute path. + paths[i++] = base; + paths[i++] = path; + paths[i] = NULL; + } + + // Finally join everything together and normalize it. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +static void cwk_path_skip_segments_until_diverge(struct cwk_segment_joined *bsj, + struct cwk_segment_joined *osj, bool absolute, bool *base_available, + bool *other_available) +{ + // Now looping over all segments until they start to diverge. A path may + // diverge if two segments are not equal or if one path reaches the end. + do { + + // Check whether there is anything available after we skip everything which + // is invisible. We do that for both paths, since we want to let the caller + // know which path has some trailing segments after they diverge. + *base_available = cwk_path_segment_joined_skip_invisible(bsj, absolute); + *other_available = cwk_path_segment_joined_skip_invisible(osj, absolute); + + // We are done if one or both of those paths reached the end. They either + // diverge or both reached the end - but in both cases we can not continue + // here. + if (!*base_available || !*other_available) { + break; + } + + // Compare the content of both segments. We are done if they are not equal, + // since they diverge. + if (!cwk_path_is_string_equal(bsj->segment.begin, osj->segment.begin, + bsj->segment.size)) { + break; + } + + // We keep going until one of those segments reached the end. The next + // segment might be invisible, but we will check for that in the beginning + // of the loop once again. + *base_available = cwk_path_get_next_segment_joined(bsj); + *other_available = cwk_path_get_next_segment_joined(osj); + } while (*base_available && *other_available); +} + +size_t cwk_path_get_relative(const char *base_directory, const char *path, + char *buffer, size_t buffer_size) +{ + size_t pos, base_root_length, path_root_length; + bool absolute, base_available, other_available, has_output; + const char *base_paths[2], *other_paths[2]; + struct cwk_segment_joined bsj, osj; + + pos = 0; + + // First we compare the roots of those two paths. If the roots are not equal + // we can't continue, since there is no way to get a relative path from + // different roots. + cwk_path_get_root(base_directory, &base_root_length); + cwk_path_get_root(path, &path_root_length); + if (!cwk_path_is_string_equal(base_directory, path, base_root_length)) { + return pos; + } + + // Verify whether this is an absolute path. We need to know that since we can + // remove all back-segments if it is. + absolute = cwk_path_is_root_absolute(base_directory, base_root_length); + + // Initialize our joined segments. This will allow us to use the internal + // functions to skip until diverge and invisible. We only have one path in + // them though. + base_paths[0] = base_directory; + base_paths[1] = NULL; + other_paths[0] = path; + other_paths[1] = NULL; + cwk_path_get_first_segment_joined(base_paths, &bsj); + cwk_path_get_first_segment_joined(other_paths, &osj); + + // Okay, now we skip until the segments diverge. We don't have anything to do + // with the segments which are equal. + cwk_path_skip_segments_until_diverge(&bsj, &osj, absolute, &base_available, + &other_available); + + // Assume there is no output until we have got some. We will need this + // information later on to remove trailing slashes or alternatively output a + // current-segment. + has_output = false; + + // So if we still have some segments left in the base path we will now output + // a back segment for all of them. + if (base_available) { + do { + // Skip any invisible segment. We don't care about those and we don't need + // to navigate back because of them. + if (!cwk_path_segment_joined_skip_invisible(&bsj, absolute)) { + break; + } + + // Toggle the flag if we have output. We need to remember that, since we + // want to remove the trailing slash. + has_output = true; + + // Output the back segment and a separator. No need to worry about the + // superfluous segment since it will be removed later on. + pos += cwk_path_output_back(buffer, buffer_size, pos); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&bsj)); + } + + // And if we have some segments available of the target path we will output + // all of those. + if (other_available) { + do { + // Again, skip any invisible segments since we don't need to navigate into + // them. + if (!cwk_path_segment_joined_skip_invisible(&osj, absolute)) { + break; + } + + // Toggle the flag if we have output. We need to remember that, since we + // want to remove the trailing slash. + has_output = true; + + // Output the current segment and a separator. No need to worry about the + // superfluous segment since it will be removed later on. + pos += cwk_path_output_sized(buffer, buffer_size, pos, osj.segment.begin, + osj.segment.size); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&osj)); + } + + // If we have some output by now we will have to remove the trailing slash. We + // simply do that by moving back one character. The terminate output function + // will then place the '\0' on this position. Otherwise, if there is no + // output, we will have to output a "current directory", since the target path + // points to the base path. + if (has_output) { + --pos; + } else { + pos += cwk_path_output_current(buffer, buffer_size, pos); + } + + // Finally, we can terminate the output - which means we place a '\0' at the + // current position or at the end of the buffer. + cwk_path_terminate_output(buffer, buffer_size, pos); + + return pos; +} + +size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer, + size_t buffer_size) +{ + const char *paths[3]; + + // This is simple. We will just create an array with the two paths which we + // wish to join. + paths[0] = path_a; + paths[1] = path_b; + paths[2] = NULL; + + // And then call the join and normalize function which will do the hard work + // for us. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +size_t cwk_path_join_multiple(const char **paths, char *buffer, + size_t buffer_size) +{ + // We can just call the internal join and normalize function for this one, + // since it will handle everything. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +void cwk_path_get_root(const char *path, size_t *length) +{ + // We use a different implementation here based on the configuration of the + // library. + if (path_style == CWK_STYLE_WINDOWS) { + cwk_path_get_root_windows(path, length); + } else { + cwk_path_get_root_unix(path, length); + } +} + +size_t cwk_path_change_root(const char *path, const char *new_root, + char *buffer, size_t buffer_size) +{ + const char *tail; + size_t root_length, path_length, tail_length, new_root_length, new_path_size; + + // First we need to determine the actual size of the root which we will + // change. + cwk_path_get_root(path, &root_length); + + // Now we determine the sizes of the new root and the path. We need that to + // determine the size of the part after the root (the tail). + new_root_length = strlen(new_root); + path_length = strlen(path); + + // Okay, now we calculate the position of the tail and the length of it. + tail = path + root_length; + tail_length = path_length - root_length; + + // We first output the tail and then the new root, that's because the source + // path and the buffer may be overlapping. This way the root will not + // overwrite the tail. + cwk_path_output_sized(buffer, buffer_size, new_root_length, tail, + tail_length); + cwk_path_output_sized(buffer, buffer_size, 0, new_root, new_root_length); + + // Finally we calculate the size o the new path and terminate the output with + // a '\0'. + new_path_size = tail_length + new_root_length; + cwk_path_terminate_output(buffer, buffer_size, new_path_size); + + return new_path_size; +} + +bool cwk_path_is_absolute(const char *path) +{ + size_t length; + + // We grab the root of the path. This root does not include the first + // separator of a path. + cwk_path_get_root(path, &length); + + // Now we can determine whether the root is absolute or not. + return cwk_path_is_root_absolute(path, length); +} + +bool cwk_path_is_relative(const char *path) +{ + // The path is relative if it is not absolute. + return !cwk_path_is_absolute(path); +} + +void cwk_path_get_basename(const char *path, const char **basename, + size_t *length) +{ + struct cwk_segment segment; + + // We get the last segment of the path. The last segment will contain the + // basename if there is any. If there are no segments we will set the basename + // to NULL and the length to 0. + if (!cwk_path_get_last_segment(path, &segment)) { + *basename = NULL; + *length = 0; + return; + } + + // Now we can just output the segment contents, since that's our basename. + // There might be trailing separators after the basename, but the size does + // not include those. + *basename = segment.begin; + *length = segment.size; +} + +size_t cwk_path_change_basename(const char *path, const char *new_basename, + char *buffer, size_t buffer_size) +{ + struct cwk_segment segment; + size_t pos, root_size, new_basename_size; + + // First we try to get the last segment. We may only have a root without any + // segments, in which case we will create one. + if (!cwk_path_get_last_segment(path, &segment)) { + + // So there is no segment in this path. First we grab the root and output + // that. We are not going to modify the root in any way. + cwk_path_get_root(path, &root_size); + pos = cwk_path_output_sized(buffer, buffer_size, 0, path, root_size); + + // We have to trim the separators from the beginning of the new basename. + // This is quite easy to do. + while (cwk_path_is_separator(new_basename)) { + ++new_basename; + } + + // Now we measure the length of the new basename, this is a two step + // process. First we find the '\0' character at the end of the string. + new_basename_size = 0; + while (new_basename[new_basename_size]) { + ++new_basename_size; + } + + // And then we trim the separators at the end of the basename until we reach + // the first valid character. + while (new_basename_size > 0 && + cwk_path_is_separator(&new_basename[new_basename_size - 1])) { + --new_basename_size; + } + + // Now we will output the new basename after the root. + pos += cwk_path_output_sized(buffer, buffer_size, pos, new_basename, + new_basename_size); + + // And finally terminate the output and return the total size of the path. + cwk_path_terminate_output(buffer, buffer_size, pos); + return pos; + } + + // If there is a last segment we can just forward this call, which is fairly + // easy. + return cwk_path_change_segment(&segment, new_basename, buffer, buffer_size); +} + +void cwk_path_get_dirname(const char *path, size_t *length) +{ + struct cwk_segment segment; + + // We get the last segment of the path. The last segment will contain the + // basename if there is any. If there are no segments we will set the length + // to 0. + if (!cwk_path_get_last_segment(path, &segment)) { + *length = 0; + return; + } + + // We can now return the length from the beginning of the string up to the + // beginning of the last segment. + *length = segment.begin - path; +} + +bool cwk_path_get_extension(const char *path, const char **extension, + size_t *length) +{ + struct cwk_segment segment; + const char *c; + + // We get the last segment of the path. The last segment will contain the + // extension if there is any. + if (!cwk_path_get_last_segment(path, &segment)) { + return false; + } + + // Now we search for a dot within the segment. If there is a dot, we consider + // the rest of the segment the extension. We do this from the end towards the + // beginning, since we want to find the last dot. + for (c = segment.end; c >= segment.begin; --c) { + if (*c == '.') { + // Okay, we found an extension. We can stop looking now. + *extension = c; + *length = segment.end - c; + return true; + } + } + + // We couldn't find any extension. + return false; +} + +bool cwk_path_has_extension(const char *path) +{ + const char *extension; + size_t length; + + // We just wrap the get_extension call which will then do the work for us. + return cwk_path_get_extension(path, &extension, &length); +} + +size_t cwk_path_change_extension(const char *path, const char *new_extension, + char *buffer, size_t buffer_size) +{ + struct cwk_segment segment; + const char *c, *old_extension; + size_t pos, root_size, trail_size, new_extension_size; + + // First we try to get the last segment. We may only have a root without any + // segments, in which case we will create one. + if (!cwk_path_get_last_segment(path, &segment)) { + + // So there is no segment in this path. First we grab the root and output + // that. We are not going to modify the root in any way. If there is no + // root, this will end up with a root size 0, and nothing will be written. + cwk_path_get_root(path, &root_size); + pos = cwk_path_output_sized(buffer, buffer_size, 0, path, root_size); + + // Add a dot if the submitted value doesn't have any. + if (*new_extension != '.') { + pos += cwk_path_output_dot(buffer, buffer_size, pos); + } + + // And finally terminate the output and return the total size of the path. + pos += cwk_path_output(buffer, buffer_size, pos, new_extension); + cwk_path_terminate_output(buffer, buffer_size, pos); + return pos; + } + + // Now we seek the old extension in the last segment, which we will replace + // with the new one. If there is no old extension, it will point to the end of + // the segment. + old_extension = segment.end; + for (c = segment.begin; c < segment.end; ++c) { + if (*c == '.') { + old_extension = c; + } + } + + pos = cwk_path_output_sized(buffer, buffer_size, 0, segment.path, + old_extension - segment.path); + + // If the new extension starts with a dot, we will skip that dot. We always + // output exactly one dot before the extension. If the extension contains + // multiple dots, we will output those as part of the extension. + if (*new_extension == '.') { + ++new_extension; + } + + // We calculate the size of the new extension, including the dot, in order to + // output the trail - which is any part of the path coming after the + // extension. We must output this first, since the buffer may overlap with the + // submitted path - and it would be overridden by longer extensions. + new_extension_size = strlen(new_extension) + 1; + trail_size = cwk_path_output(buffer, buffer_size, pos + new_extension_size, + segment.end); + + // Finally we output the dot and the new extension. The new extension itself + // doesn't contain the dot anymore, so we must output that first. + pos += cwk_path_output_dot(buffer, buffer_size, pos); + pos += cwk_path_output(buffer, buffer_size, pos, new_extension); + + // Now we terminate the output with a null-terminating character, but before + // we do that we must add the size of the trail to the position which we + // output before. + pos += trail_size; + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And the position is our output size now. + return pos; +} + +size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size) +{ + const char *paths[2]; + + // Now we initialize the paths which we will normalize. Since this function + // only supports submitting a single path, we will only add that one. + paths[0] = path; + paths[1] = NULL; + + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +size_t cwk_path_get_intersection(const char *path_base, const char *path_other) +{ + bool absolute; + size_t base_root_length, other_root_length; + const char *end; + const char *paths_base[2], *paths_other[2]; + struct cwk_segment_joined base, other; + + // We first compare the two roots. We just return zero if they are not equal. + // This will also happen to return zero if the paths are mixed relative and + // absolute. + cwk_path_get_root(path_base, &base_root_length); + cwk_path_get_root(path_other, &other_root_length); + if (!cwk_path_is_string_equal(path_base, path_other, base_root_length)) { + return 0; + } + + // Configure our paths. We just have a single path in here for now. + paths_base[0] = path_base; + paths_base[1] = NULL; + paths_other[0] = path_other; + paths_other[1] = NULL; + + // So we get the first segment of both paths. If one of those paths don't have + // any segment, we will return 0. + if (!cwk_path_get_first_segment_joined(paths_base, &base) || + !cwk_path_get_first_segment_joined(paths_other, &other)) { + return base_root_length; + } + + // We now determine whether the path is absolute or not. This is required + // because if will ignore removed segments, and this behaves differently if + // the path is absolute. However, we only need to check the base path because + // we are guaranteed that both paths are either relative or absolute. + absolute = cwk_path_is_root_absolute(path_base, base_root_length); + + // We must keep track of the end of the previous segment. Initially, this is + // set to the beginning of the path. This means that 0 is returned if the + // first segment is not equal. + end = path_base + base_root_length; + + // Now we loop over both segments until one of them reaches the end or their + // contents are not equal. + do { + // We skip all segments which will be removed in each path, since we want to + // know about the true path. + if (!cwk_path_segment_joined_skip_invisible(&base, absolute) || + !cwk_path_segment_joined_skip_invisible(&other, absolute)) { + break; + } + + if (!cwk_path_is_string_equal(base.segment.begin, other.segment.begin, + base.segment.size)) { + // So the content of those two segments are not equal. We will return the + // size up to the beginning. + return end - path_base; + } + + // Remember the end of the previous segment before we go to the next one. + end = base.segment.end; + } while (cwk_path_get_next_segment_joined(&base) && + cwk_path_get_next_segment_joined(&other)); + + // Now we calculate the length up to the last point where our paths pointed to + // the same place. + return end - path_base; +} + +bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment) +{ + size_t length; + const char *segments; + + // We skip the root since that's not part of the first segment. The root is + // treated as a separate entity. + cwk_path_get_root(path, &length); + segments = path + length; + + // Now, after we skipped the root we can continue and find the actual segment + // content. + return cwk_path_get_first_segment_without_root(path, segments, segment); +} + +bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment) +{ + // We first grab the first segment. This might be our last segment as well, + // but we don't know yet. There is no last segment if there is no first + // segment, so we return false in that case. + if (!cwk_path_get_first_segment(path, segment)) { + return false; + } + + // Now we find our last segment. The segment struct of the caller + // will contain the last segment, since the function we call here will not + // change the segment struct when it reaches the end. + while (cwk_path_get_next_segment(segment)) { + // We just loop until there is no other segment left. + } + + return true; +} + +bool cwk_path_get_next_segment(struct cwk_segment *segment) +{ + const char *c; + + // First we jump to the end of the previous segment. The first character must + // be either a '\0' or a separator. + c = segment->begin + segment->size; + if (*c == '\0') { + return false; + } + + // Now we skip all separator until we reach something else. We are not yet + // guaranteed to have a segment, since the string could just end afterwards. + assert(cwk_path_is_separator(c)); + do { + ++c; + } while (cwk_path_is_separator(c)); + + // If the string ends here, we can safely assume that there is no other + // segment after this one. + if (*c == '\0') { + return false; + } + + // Now we are safe to assume there is a segment. We store the beginning of + // this segment in the segment struct of the caller. + segment->begin = c; + + // And now determine the size of this segment, and store it in the struct of + // the caller as well. + c = cwk_path_find_next_stop(c); + segment->end = c; + segment->size = c - segment->begin; + + // Tell the caller that we found a segment. + return true; +} + +bool cwk_path_get_previous_segment(struct cwk_segment *segment) +{ + const char *c; + + // The current position might point to the first character of the path, which + // means there are no previous segments available. + c = segment->begin; + if (c <= segment->segments) { + return false; + } + + // We move towards the beginning of the path until we either reached the + // beginning or the character is no separator anymore. + do { + --c; + if (c <= segment->segments) { + // So we reached the beginning here and there is no segment. So we return + // false and don't change the segment structure submitted by the caller. + return false; + } + } while (cwk_path_is_separator(c)); + + // We are guaranteed now that there is another segment, since we moved before + // the previous separator and did not reach the segment path beginning. + segment->end = c + 1; + segment->begin = cwk_path_find_previous_stop(segment->segments, c); + segment->size = segment->end - segment->begin; + + return true; +} + +enum cwk_segment_type cwk_path_get_segment_type( + const struct cwk_segment *segment) +{ + // We just make a string comparison with the segment contents and return the + // appropriate type. + if (strncmp(segment->begin, ".", segment->size) == 0) { + return CWK_CURRENT; + } else if (strncmp(segment->begin, "..", segment->size) == 0) { + return CWK_BACK; + } + + return CWK_NORMAL; +} + +bool cwk_path_is_separator(const char *str) +{ + const char *c; + + // We loop over all characters in the read symbols. + c = separators[path_style]; + while (*c) { + if (*c == *str) { + return true; + } + + ++c; + } + + return false; +} + +size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value, + char *buffer, size_t buffer_size) +{ + size_t pos, value_size, tail_size; + + // First we have to output the head, which is the whole string up to the + // beginning of the segment. This part of the path will just stay the same. + pos = cwk_path_output_sized(buffer, buffer_size, 0, segment->path, + segment->begin - segment->path); + + // In order to trip the submitted value, we will skip any separator at the + // beginning of it and behave as if it was never there. + while (cwk_path_is_separator(value)) { + ++value; + } + + // Now we determine the length of the value. In order to do that we first + // locate the '\0'. + value_size = 0; + while (value[value_size]) { + ++value_size; + } + + // Since we trim separators at the beginning and in the end of the value we + // have to subtract from the size until there are either no more characters + // left or the last character is no separator. + while (value_size > 0 && cwk_path_is_separator(&value[value_size - 1])) { + --value_size; + } + + // We also have to determine the tail size, which is the part of the string + // following the current segment. This part will not change. + tail_size = strlen(segment->end); + + // Now we output the tail. We have to do that, because if the buffer and the + // source are overlapping we would override the tail if the value is + // increasing in length. + cwk_path_output_sized(buffer, buffer_size, pos + value_size, segment->end, + tail_size); + + // Finally we can output the value in the middle of the head and the tail, + // where we have enough space to fit the whole trimmed value. + pos += cwk_path_output_sized(buffer, buffer_size, pos, value, value_size); + + // Now we add the tail size to the current position and terminate the output - + // basically, ensure that there is a '\0' at the end of the buffer. + pos += tail_size; + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And now tell the caller how long the whole path would be. + return pos; +} + +enum cwk_path_style cwk_path_guess_style(const char *path) +{ + const char *c; + size_t root_length; + struct cwk_segment segment; + + // First we determine the root. Only windows roots can be longer than a single + // slash, so if we can determine that it starts with something like "C:", we + // know that this is a windows path. + cwk_path_get_root_windows(path, &root_length); + if (root_length > 1) { + return CWK_STYLE_WINDOWS; + } + + // Next we check for slashes. Windows uses backslashes, while unix uses + // forward slashes. Windows actually supports both, but our best guess is to + // assume windows with backslashes and unix with forward slashes. + for (c = path; *c; ++c) { + if (*c == *separators[CWK_STYLE_UNIX]) { + return CWK_STYLE_UNIX; + } else if (*c == *separators[CWK_STYLE_WINDOWS]) { + return CWK_STYLE_WINDOWS; + } + } + + // This path does not have any slashes. We grab the last segment (which + // actually must be the first one), and determine whether the segment starts + // with a dot. A dot is a hidden folder or file in the UNIX world, in that + // case we assume the path to have UNIX style. + if (!cwk_path_get_last_segment(path, &segment)) { + // We couldn't find any segments, so we default to a UNIX path style since + // there is no way to make any assumptions. + return CWK_STYLE_UNIX; + } + + if (*segment.begin == '.') { + return CWK_STYLE_UNIX; + } + + // And finally we check whether the last segment contains a dot. If it + // contains a dot, that might be an extension. Windows is more likely to have + // file names with extensions, so our guess would be windows. + for (c = segment.begin; *c; ++c) { + if (*c == '.') { + return CWK_STYLE_WINDOWS; + } + } + + // All our checks failed, so we will return a default value which is currently + // UNIX. + return CWK_STYLE_UNIX; +} + +void cwk_path_set_style(enum cwk_path_style style) +{ + // We can just set the global path style variable and then the behaviour for + // all functions will change accordingly. + assert(style == CWK_STYLE_UNIX || style == CWK_STYLE_WINDOWS); + path_style = style; +} + +enum cwk_path_style cwk_path_get_style(void) +{ + // Simply return the path style which we store in a global variable. + return path_style; +} diff --git a/src/disk/minivhd/cwalk.h b/src/disk/minivhd/cwalk.h new file mode 100644 index 000000000..baa5d432d --- /dev/null +++ b/src/disk/minivhd/cwalk.h @@ -0,0 +1,457 @@ +#pragma once + +#ifndef CWK_LIBRARY_H +#define CWK_LIBRARY_H + +#include +#include + +/** + * A segment represents a single component of a path. For instance, on linux a + * path might look like this "/var/log/", which consists of two segments "var" + * and "log". + */ +struct cwk_segment +{ + const char *path; + const char *segments; + const char *begin; + const char *end; + size_t size; +}; + +/** + * The segment type can be used to identify whether a segment is a special + * segment or not. + * + * CWK_NORMAL - normal folder or file segment + * CWK_CURRENT - "./" current folder segment + * CWK_BACK - "../" relative back navigation segment + */ +enum cwk_segment_type +{ + CWK_NORMAL, + CWK_CURRENT, + CWK_BACK +}; + +/** + * @brief Determines the style which is used for the path parsing and + * generation. + */ +enum cwk_path_style +{ + CWK_STYLE_WINDOWS, + CWK_STYLE_UNIX +}; + +/** + * @brief Generates an absolute path based on a base. + * + * This function generates an absolute path based on a base path and another + * path. It is guaranteed to return an absolute path. If the second submitted + * path is absolute, it will override the base path. The result will be written + * to a buffer, which might be truncated if the buffer is not large enough to + * hold the full path. However, the truncated result will always be + * null-terminated. The returned value is the amount of characters which the + * resulting path would take if it was not truncated (excluding the + * null-terminating character). + * + * @param base The base path on which the relative path will be applied. + * @param path The relative path which will be applied on the base path. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the new absolute path. + */ +size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer, + size_t buffer_size); + +/** + * @brief Generates a relative path based on a base. + * + * This function generates a relative path based on a base path and another + * path. It determines how to get to the submitted path, starting from the base + * directory. The result will be written to a buffer, which might be truncated + * if the buffer is not large enough to hold the full path. However, the + * truncated result will always be null-terminated. The returned value is the + * amount of characters which the resulting path would take if it was not + * truncated (excluding the null-terminating character). + * + * @param base_directory The base path from which the relative path will start. + * @param path The target path where the relative path will point to. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full path. + */ +size_t cwk_path_get_relative(const char *base_directory, const char *path, + char *buffer, size_t buffer_size); + +/** + * @brief Joins two paths together. + * + * This function generates a new path by combining the two submitted paths. It + * will remove double separators, and unlike cwk_path_get_absolute it permits + * the use of two relative paths to combine. The result will be written to a + * buffer, which might be truncated if the buffer is not large enough to hold + * the full path. However, the truncated result will always be null-terminated. + * The returned value is the amount of characters which the resulting path would + * take if it was not truncated (excluding the null-terminating character). + * + * @param path_a The first path which comes first. + * @param path_b The second path which comes after the first. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full, combined path. + */ +size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer, + size_t buffer_size); + +/** + * @brief Joins multiple paths together. + * + * This function generates a new path by joining multiple paths together. It + * will remove double separators, and unlike cwk_path_get_absolute it permits + * the use of multiple relative paths to combine. The last path of the submitted + * string array must be set to NULL. The result will be written to a buffer, + * which might be truncated if the buffer is not large enough to hold the full + * path. However, the truncated result will always be null-terminated. The + * returned value is the amount of characters which the resulting path would + * take if it was not truncated (excluding the null-terminating character). + * + * @param paths An array of paths which will be joined. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full, combined path. + */ +size_t cwk_path_join_multiple(const char **paths, char *buffer, + size_t buffer_size); + +/** + * @brief Determines the root of a path. + * + * This function determines the root of a path by finding it's length. The root + * always starts at the submitted path. If the path has no root, the length will + * be set to zero. + * + * @param path The path which will be inspected. + * @param length The output of the root length. + */ +void cwk_path_get_root(const char *path, size_t *length); + +/** + * @brief Changes the root of a path. + * + * This function changes the root of a path. It does not normalize the result. + * The result will be written to a buffer, which might be truncated if the + * buffer is not large enough to hold the full path. However, the truncated + * result will always be null-terminated. The returned value is the amount of + * characters which the resulting path would take if it was not truncated + * (excluding the null-terminating character). + * + * @param path The original path which will get a new root. + * @param new_root The new root which will be placed in the path. + * @param buffer The output buffer where the result is written to. + * @param buffer_size The size of the output buffer where the result is written + * to. + * @return Returns the total amount of characters of the new path. + */ +size_t cwk_path_change_root(const char *path, const char *new_root, + char *buffer, size_t buffer_size); + +/** + * @brief Determine whether the path is absolute or not. + * + * This function checks whether the path is an absolute path or not. A path is + * considered to be absolute if the root ends with a separator. + * + * @param path The path which will be checked. + * @return Returns true if the path is absolute or false otherwise. + */ +bool cwk_path_is_absolute(const char *path); + +/** + * @brief Determine whether the path is relative or not. + * + * This function checks whether the path is a relative path or not. A path is + * considered to be relative if the root does not end with a separator. + * + * @param path The path which will be checked. + * @return Returns true if the path is relative or false otherwise. + */ +bool cwk_path_is_relative(const char *path); + +/** + * @brief Gets the basename of a file path. + * + * This function gets the basename of a file path. A pointer to the beginning of + * the basename will be returned through the basename parameter. This pointer + * will be positioned on the first letter after the separator. The length of the + * file path will be returned through the length parameter. The length will be + * set to zero and the basename to NULL if there is no basename available. + * + * @param path The path which will be inspected. + * @param basename The output of the basename pointer. + * @param length The output of the length of the basename. + */ +void cwk_path_get_basename(const char *path, const char **basename, + size_t *length); + +/** + * @brief Changes the basename of a file path. + * + * This function changes the basename of a file path. This function will not + * write out more than the specified buffer can contain. However, the generated + * string is always null-terminated - even if not the whole path is written out. + * The function returns the total number of characters the complete buffer would + * have, even if it was not written out completely. The path may be the same + * memory address as the buffer. + * + * @param path The original path which will be used for the modified path. + * @param new_basename The new basename which will replace the old one. + * @param buffer The buffer where the changed path will be written to. + * @param buffer_size The size of the result buffer where the changed path is + * written to. + * @return Returns the size which the complete new path would have if it was not + * truncated. + */ +size_t cwk_path_change_basename(const char *path, const char *new_basename, + char *buffer, size_t buffer_size); + +/** + * @brief Gets the dirname of a file path. + * + * This function determines the dirname of a file path and returns the length up + * to which character is considered to be part of it. If no dirname is found, + * the length will be set to zero. The beginning of the dirname is always equal + * to the submitted path pointer. + * + * @param path The path which will be inspected. + * @param length The length of the dirname. + */ +void cwk_path_get_dirname(const char *path, size_t *length); + +/** + * @brief Gets the extension of a file path. + * + * This function extracts the extension portion of a file path. A pointer to + * the beginning of the extension will be returned through the extension + * parameter if an extension is found and true is returned. This pointer will be + * positioned on the dot. The length of the extension name will be returned + * through the length parameter. If no extension is found both parameters won't + * be touched and false will be returned. + * + * @param path The path which will be inspected. + * @param extension The output of the extension pointer. + * @param length The output of the length of the extension. + * @return Returns true if an extension is found or false otherwise. + */ +bool cwk_path_get_extension(const char *path, const char **extension, + size_t *length); + +/** + * @brief Determines whether the file path has an extension. + * + * This function determines whether the submitted file path has an extension. + * This will evaluate to true if the last segment of the path contains a dot. + * + * @param path The path which will be inspected. + * @return Returns true if the path has an extension or false otherwise. + */ +bool cwk_path_has_extension(const char *path); + +/** + * @brief Changes the extension of a file path. + * + * This function changes the extension of a file name. The function will append + * an extension if the basename does not have an extension, or use the extension + * as a basename if the path does not have a basename. This function will not + * write out more than the specified buffer can contain. However, the generated + * string is always null-terminated - even if not the whole path is written out. + * The function returns the total number of characters the complete buffer would + * have, even if it was not written out completely. The path may be the same + * memory address as the buffer. + * + * @param path The path which will be used to make the change. + * @param new_extension The extension which will be placed within the new path. + * @param buffer The output buffer where the result will be written to. + * @param buffer_size The size of the output buffer where the result will be + * written to. + * @return Returns the total size which the output would have if it was not + * truncated. + */ +size_t cwk_path_change_extension(const char *path, const char *new_extension, + char *buffer, size_t buffer_size); + +/** + * @brief Creates a normalized version of the path. + * + * This function creates a normalized version of the path within the specified + * buffer. This function will not write out more than the specified buffer can + * contain. However, the generated string is always null-terminated - even if + * not the whole path is written out. The function returns the total number of + * characters the complete buffer would have, even if it was not written out + * completely. The path may be the same memory address as the buffer. + * + * The following will be true for the normalized path: + * 1) "../" will be resolved. + * 2) "./" will be removed. + * 3) double separators will be fixed with a single separator. + * 4) separator suffixes will be removed. + * + * @param path The path which will be normalized. + * @param buffer The buffer where the new path is written to. + * @param buffer_size The size of the buffer. + * @return The size which the complete normalized path has if it was not + * truncated. + */ +size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size); + +/** + * @brief Finds common portions in two paths. + * + * This function finds common portions in two paths and returns the number + * characters from the beginning of the base path which are equal to the other + * path. + * + * @param path_base The base path which will be compared with the other path. + * @param path_other The other path which will compared with the base path. + * @return Returns the number of characters which are common in the base path. + */ +size_t cwk_path_get_intersection(const char *path_base, const char *path_other); + +/** + * @brief Gets the first segment of a path. + * + * This function finds the first segment of a path. The position of the segment + * is set to the first character after the separator, and the length counts all + * characters until the next separator (excluding the separator). + * + * @param path The path which will be inspected. + * @param segment The segment which will be extracted. + * @return Returns true if there is a segment or false if there is none. + */ +bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment); + +/** + * @brief Gets the last segment of the path. + * + * This function gets the last segment of a path. This function may return false + * if the path doesn't contain any segments, in which case the submitted segment + * parameter is not modified. The position of the segment is set to the first + * character after the separator, and the length counts all characters until the + * end of the path (excluding the separator). + * + * @param path The path which will be inspected. + * @param segment The segment which will be extracted. + * @return Returns true if there is a segment or false if there is none. + */ +bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment); + +/** + * @brief Advances to the next segment. + * + * This function advances the current segment to the next segment. If there are + * no more segments left, the submitted segment structure will stay unchanged + * and false is returned. + * + * @param segment The current segment which will be advanced to the next one. + * @return Returns true if another segment was found or false otherwise. + */ +bool cwk_path_get_next_segment(struct cwk_segment *segment); + +/** + * @brief Moves to the previous segment. + * + * This function moves the current segment to the previous segment. If the + * current segment is the first one, the submitted segment structure will stay + * unchanged and false is returned. + * + * @param segment The current segment which will be moved to the previous one. + * @return Returns true if there is a segment before this one or false + * otherwise. + */ +bool cwk_path_get_previous_segment(struct cwk_segment *segment); + +/** + * @brief Gets the type of the submitted path segment. + * + * This function inspects the contents of the segment and determines the type of + * it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and CWK_BACK. A + * CWK_NORMAL segment is a normal folder or file entry. A CWK_CURRENT is a "./" + * and a CWK_BACK a "../" segment. + * + * @param segment The segment which will be inspected. + * @return Returns the type of the segment. + */ +enum cwk_segment_type cwk_path_get_segment_type( + const struct cwk_segment *segment); + +/** + * @brief Changes the content of a segment. + * + * This function overrides the content of a segment to the submitted value and + * outputs the whole new path to the submitted buffer. The result might require + * less or more space than before if the new value length differs from the + * original length. The output is truncated if the new path is larger than the + * submitted buffer size, but it is always null-terminated. The source of the + * segment and the submitted buffer may be the same. + * + * @param segment The segment which will be modifier. + * @param value The new content of the segment. + * @param buffer The buffer where the modified path will be written to. + * @param buffer_size The size of the output buffer. + * @return Returns the total size which would have been written if the output + * was not truncated. + */ +size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value, + char *buffer, size_t buffer_size); + +/** + * @brief Checks whether the submitted pointer points to a separator. + * + * This function simply checks whether the submitted pointer points to a + * separator, which has to be null-terminated (but not necessarily after the + * separator). The function will return true if it is a separator, or false + * otherwise. + * + * @param symbol A pointer to a string. + * @return Returns true if it is a separator, or false otherwise. + */ +bool cwk_path_is_separator(const char *str); + +/** + * @brief Guesses the path style. + * + * This function guesses the path style based on a submitted path-string. The + * guessing will look at the root and the type of slashes contained in the path + * and return the style which is more likely used in the path. + * + * @param path The path which will be inspected. + * @return Returns the style which is most likely used for the path. + */ +enum cwk_path_style cwk_path_guess_style(const char *path); + +/** + * @brief Configures which path style is used. + * + * This function configures which path style is used. The following styles are + * currently supported. + * + * CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root. + * CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root. + * + * @param style The style which will be used from now on. + */ +void cwk_path_set_style(enum cwk_path_style style); + +/** + * @brief Gets the path style configuration. + * + * This function gets the style configuration which is currently used for the + * paths. This configuration determines how paths are parsed and generated. + * + * @return Returns the current path style configuration. + */ +enum cwk_path_style cwk_path_get_style(void); + +#endif diff --git a/src/disk/minivhd/libxml2_encoding.c b/src/disk/minivhd/libxml2_encoding.c new file mode 100644 index 000000000..48c291f2f --- /dev/null +++ b/src/disk/minivhd/libxml2_encoding.c @@ -0,0 +1,447 @@ +/* + * encoding.c : implements the encoding conversion functions needed for XML + * + * Related specs: + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * rfc2781 UTF-16, an encoding of ISO 10646, P. Hoffman, F. Yergeau + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * + * Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" + * + * Adapted and abridged for MiniVHD by Sherman Perry + */ +#include + +static int xmlLittleEndian = 1; + +/* Note: extracted from original 'void xmlInitCharEncodingHandlers(void)' function */ +void xmlEncodingInit(void) +{ + unsigned short int tst = 0x1234; + unsigned char *ptr = (unsigned char *) &tst; + + if (*ptr == 0x12) xmlLittleEndian = 0; + else if (*ptr == 0x34) xmlLittleEndian = 1; +} + +/** + * UTF16LEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16LE passwd as a byte array + * @inlenb: the length of @in in UTF-16LE chars + * + * Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +int UTF16LEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend = in + inlen; + while ((in < inend) && (out - outstart + 5 < *outlen)) { + if (xmlLittleEndian) { + c= *in++; + } else { + tmp = (unsigned char *) in; + c = *tmp++; + c = c | (((unsigned int)*tmp) << 8); + in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + break; + } + if (xmlLittleEndian) { + d = *in++; + } else { + tmp = (unsigned char *) in; + d = *tmp++; + d = d | (((unsigned int)*tmp) << 8); + in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +/** + * UTF8ToUTF16LE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16LE + * block of chars out. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding failed. + */ +int UTF8ToUTF16LE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF16LE encoding has no BOM */ + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) + break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) + break; + if (xmlLittleEndian) { + *out++ = c; + } else { + tmp = (unsigned char *) out; + *tmp = c ; + *(tmp + 1) = c >> 8 ; + out++; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) + break; + c -= 0x10000; + if (xmlLittleEndian) { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } else { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp1; + *(tmp + 1) = tmp1 >> 8; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp2; + *(tmp + 1) = tmp2 >> 8; + out++; + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/** + * UTF16BEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16 passed as a byte array + * @inlenb: the length of @in in UTF-16 chars + * + * Take a block of UTF-16 ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +int UTF16BEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend= in + inlen; + while (in < inend) { + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + c = *tmp++; + c = c << 8; + c = c | (unsigned int) *tmp; + in++; + } else { + c= *in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + d = *tmp++; + d = d << 8; + d = d | (unsigned int) *tmp; + in++; + } else { + d= *in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +/** + * UTF8ToUTF16BE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16BE + * block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + */ +int UTF8ToUTF16BE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF-16BE has no BOM */ + if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) break; + if (xmlLittleEndian) { + tmp = (unsigned char *) out; + *tmp = c >> 8; + *(tmp + 1) = c; + out++; + } else { + *out++ = c; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) break; + c -= 0x10000; + if (xmlLittleEndian) { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = tmp1 >> 8; + *(tmp + 1) = (unsigned char) tmp1; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = tmp2 >> 8; + *(tmp + 1) = (unsigned char) tmp2; + out++; + } else { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/* This file is licenced under the MIT licence as follows: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ diff --git a/src/disk/minivhd/libxml2_encoding.h b/src/disk/minivhd/libxml2_encoding.h new file mode 100644 index 000000000..d86770b86 --- /dev/null +++ b/src/disk/minivhd/libxml2_encoding.h @@ -0,0 +1,12 @@ +#ifndef LIBXML2_ENCODING_H +#define LIBXML2_ENCODING_H + +#include +typedef uint16_t mvhd_utf16; + +void xmlEncodingInit(void); +int UTF16LEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb); +int UTF8ToUTF16LE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen); +int UTF16BEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb); +int UTF8ToUTF16BE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen); +#endif diff --git a/src/disk/minivhd/minivhd.h b/src/disk/minivhd/minivhd.h new file mode 100644 index 000000000..df3a24bb3 --- /dev/null +++ b/src/disk/minivhd/minivhd.h @@ -0,0 +1,269 @@ +#ifndef MINIVHD_H +#define MINIVHD_H + +#include +#include +#include + +extern int mvhd_errno; + +typedef enum MVHDError { + MVHD_ERR_MEM = -128, + MVHD_ERR_FILE, + MVHD_ERR_NOT_VHD, + MVHD_ERR_TYPE, + MVHD_ERR_FOOTER_CHECKSUM, + MVHD_ERR_SPARSE_CHECKSUM, + MVHD_ERR_UTF_TRANSCODING_FAILED, + MVHD_ERR_UTF_SIZE, + MVHD_ERR_PATH_REL, + MVHD_ERR_PATH_LEN, + MVHD_ERR_PAR_NOT_FOUND, + MVHD_ERR_INVALID_PAR_UUID, + MVHD_ERR_INVALID_GEOM, + MVHD_ERR_INVALID_SIZE, + MVHD_ERR_INVALID_BLOCK_SIZE, + MVHD_ERR_INVALID_PARAMS, + MVHD_ERR_CONV_SIZE, + MVHD_ERR_TIMESTAMP +} MVHDError; + +typedef enum MVHDType { + MVHD_TYPE_FIXED = 2, + MVHD_TYPE_DYNAMIC = 3, + MVHD_TYPE_DIFF = 4 +} MVHDType; + +typedef enum MVHDBlockSize { + MVHD_BLOCK_DEFAULT = 0, /**< 2 MB blocks */ + MVHD_BLOCK_SMALL = 1024, /**< 512 KB blocks */ + MVHD_BLOCK_LARGE = 4096 /**< 2 MB blocks */ +} MVHDBlockSize; + +typedef struct MVHDGeom { + uint16_t cyl; + uint8_t heads; + uint8_t spt; +} MVHDGeom; + +typedef void (*mvhd_progress_callback)(uint32_t current_sector, uint32_t total_sectors); + +typedef struct MVHDCreationOptions { + int type; /** MVHD_TYPE_FIXED, MVHD_TYPE_DYNAMIC, or MVHD_TYPE_DIFF */ + char* path; /** Absolute path of the new VHD file */ + char* parent_path; /** For MVHD_TYPE_DIFF, this is the absolute path of the VHD's parent. For non-diff VHDs, this should be NULL. */ + uint64_t size_in_bytes; /** Total size of the VHD's virtual disk in bytes. Must be a multiple of 512. If 0, the size is auto-calculated from the geometry field. Ignored for MVHD_TYPE_DIFF. */ + MVHDGeom geometry; /** The geometry of the VHD. If set to 0, the geometry is auto-calculated from the size_in_bytes field. */ + uint32_t block_size_in_sectors; /** MVHD_BLOCK_LARGE or MVHD_BLOCK_SMALL, or 0 for the default value. The number of sectors per block. */ + mvhd_progress_callback progress_callback; /** Optional; if not NULL, gets called to indicate progress on the creation operation. Only applies to MVHD_TYPE_FIXED. */ +} MVHDCreationOptions; + +typedef struct MVHDMeta MVHDMeta; + +/** + * \brief Output a string from a MiniVHD error number + * + * \param [in] err is the error number to return string from + * + * \return Error string + */ +const char* mvhd_strerr(MVHDError err); + +/** + * \brief A simple test to see if a given file is a VHD + * + * \param [in] f file to test + * + * \retval true if f is a VHD + * \retval false if f is not a VHD + */ +bool mvhd_file_is_vhd(FILE* f); + +/** + * \brief Open a VHD image for reading and/or writing + * + * The returned pointer contains all required values and structures (and files) to + * read and write to a VHD file. + * + * Remember to call mvhd_close() when you are finished. + * + * \param [in] Absolute path to VHD file. Relative path will cause issues when opening + * a differencing VHD file + * \param [in] readonly set this to true to open the VHD in a read only manner + * \param [out] err will be set if the VHD fails to open. Value could be one of + * MVHD_ERR_MEM, MVHD_ERR_FILE, MVHD_ERR_NOT_VHD, MVHD_ERR_FOOTER_CHECKSUM, MVHD_ERR_SPARSE_CHECKSUM, + * MVHD_ERR_TYPE, MVHD_ERR_TIMESTAMP + * If MVHD_ERR_FILE is set, mvhd_errno will be set to the appropriate system errno value + * + * \return MVHDMeta pointer. If NULL, check err. err may also be set to MVHD_ERR_TIMESTAMP if + * opening a differencing VHD. + */ +MVHDMeta* mvhd_open(const char* path, bool readonly, int* err); + +/** + * \brief Update the parent modified timestamp in the VHD file + * + * Differencing VHD's use a parent last modified timestamp to try and detect if the + * parent has been modified after the child has been created. However, this is rather + * fragile and can be broken by moving/copying the parent. Also, MS DiskPart does not + * set this timestamp in the child :( + * + * Be careful when using this function that you don't update the timestamp after the + * parent actually has been modified. + * + * \param [in] vhdm Differencing VHD to update. + * \param [out] err will be set if the timestamp could not be updated + * + * \return non-zero on error, 0 on success + */ +int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err); + +/** + * \brief Create a fixed VHD image + * + * \param [in] path is the absolute path to the image to create + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [out] err indicates what error occurred, if any + * \param [out] progress_callback optional; if not NULL, gets called to indicate progress on the creation operation + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback); + +/** + * \brief Create sparse (dynamic) VHD image. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err); + +/** + * \brief Create differencing VHD imagee. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err); + +/** + * \brief Create a VHD using the provided options + * + * Use mvhd_create_ex if you want more control over the VHD's options. For quick creation, you can use mvhd_create_fixed, mvhd_create_sparse, or mvhd_create_diff. + * + * \param [in] options the VHD creation options. + * \param [out] err indicates what error occurred, if any + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err); + +/** + * \brief Safely close a VHD image + * + * \param [in] vhdm MiniVHD data structure to close + */ +void mvhd_close(MVHDMeta* vhdm); + +/** + * \brief Calculate hard disk geometry from a provided size + * + * The VHD format uses Cylinder, Heads, Sectors per Track (CHS) when accessing the disk. + * The size of the disk can be determined from C * H * S * sector_size. + * + * Note, maximum geometry size (in bytes) is 65535 * 16 * 255 * 512, which is 127GB. + * However, the maximum VHD size is 2040GB. For VHDs larger than 127GB, the geometry size will be + * smaller than the actual VHD size. + * + * This function determines the appropriate CHS geometry from a provided size in bytes. + * The calculations used are those provided in "Appendix: CHS Calculation" from the document + * "Virtual Hard Disk Image Format Specification" provided by Microsoft. + * + * \param [in] size the desired VHD image size, in bytes + * + * \return MVHDGeom the calculated geometry. This can be used in the appropriate create functions. + */ +MVHDGeom mvhd_calculate_geometry(uint64_t size); + +/** + * \brief Convert a raw disk image to a fixed VHD image + * + * \param [in] utf8_raw_path is the path of the raw image to convert + * \param [in] utf8_vhd_path is the path of the VHD to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err); + +/** + * \brief Convert a raw disk image to a sparse VHD image + * + * \param [in] utf8_raw_path is the path of the raw image to convert + * \param [in] utf8_vhd_path is the path of the VHD to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err); + +/** + * \brief Convert a VHD image to a raw disk image + * + * \param [in] utf8_vhd_path is the path of the VHD to convert + * \param [in] utf8_raw_path is the path of the raw image to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns the raw disk image FILE pointer + */ +FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err); + +/** + * \brief Read sectors from VHD file + * + * Read num_sectors, beginning at offset from the VHD file into a buffer + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start reading from + * \param [in] num_sectors the number of sectors to read + * \param [out] out_buff the buffer to write sector data to + * + * \return the number of sectors that were not read, or zero + */ +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Write sectors to VHD file + * + * Write num_sectors, beginning at offset from a buffer VHD file into the VHD file + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start writing to + * \param [in] num_sectors the number of sectors to write + * \param [in] in_buffer the buffer to write sector data to + * + * \return the number of sectors that were not written, or zero + */ +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief Write zeroed sectors to VHD file + * + * Write num_sectors, beginning at offset, of zero data into the VHD file. + * We reuse the existing write functions, with a preallocated zero buffer as + * our source buffer. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start writing to + * \param [in] num_sectors the number of sectors to write + * + * \return the number of sectors that were not written, or zero + */ +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors); +#endif diff --git a/src/disk/minivhd/minivhd_convert.c b/src/disk/minivhd/minivhd_convert.c new file mode 100644 index 000000000..01c430300 --- /dev/null +++ b/src/disk/minivhd/minivhd_convert.c @@ -0,0 +1,108 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "minivhd_create.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd.h" + +static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err); + +static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err) { + FILE *raw_img = mvhd_fopen(utf8_raw_path, "rb", err); + if (raw_img == NULL) { + *err = MVHD_ERR_FILE; + return NULL; + } + if (geom == NULL) { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t size_bytes = (uint64_t)mvhd_ftello64(raw_img); + MVHDGeom new_geom = mvhd_calculate_geometry(size_bytes); + if (mvhd_calc_size_bytes(&new_geom) != size_bytes) { + *err = MVHD_ERR_CONV_SIZE; + return NULL; + } + geom->cyl = new_geom.cyl; + geom->heads = new_geom.heads; + geom->spt = new_geom.spt; + mvhd_fseeko64(raw_img, 0, SEEK_SET); + return raw_img; +} + +MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) { + MVHDGeom geom; + FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err); + if (raw_img == NULL) { + return NULL; + } + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, size_in_bytes, &geom, err, NULL); + if (vhdm == NULL) { + return NULL; + } + return vhdm; +} +MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) { + MVHDGeom geom; + MVHDMeta *vhdm = NULL; + FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err); + if (raw_img == NULL) { + return NULL; + } + vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err); + if (vhdm == NULL) { + goto end; + } + uint8_t buff[4096] = {0}; // 8 sectors + uint8_t empty_buff[4096] = {0}; + int total_sectors = mvhd_calc_size_sectors(&geom); + int copy_sect = 0; + for (int i = 0; i < total_sectors; i += 8) { + copy_sect = 8; + if ((i + 8) >= total_sectors) { + copy_sect = total_sectors - i; + memset(buff, 0, sizeof buff); + } + fread(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); + /* Only write data if there's data to write, to take advantage of the sparse VHD format */ + if (memcmp(buff, empty_buff, sizeof buff) != 0) { + mvhd_write_sectors(vhdm, i, copy_sect, buff); + } + } +end: + fclose(raw_img); + return vhdm; +} +FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err) { + FILE *raw_img = mvhd_fopen(utf8_raw_path, "wb", err); + if (raw_img == NULL) { + return NULL; + } + MVHDMeta *vhdm = mvhd_open(utf8_vhd_path, true, err); + if (vhdm == NULL) { + fclose(raw_img); + return NULL; + } + uint8_t buff[4096] = {0}; // 8 sectors + int total_sectors = mvhd_calc_size_sectors((MVHDGeom*)&vhdm->footer.geom); + int copy_sect = 0; + for (int i = 0; i < total_sectors; i += 8) { + copy_sect = 8; + if ((i + 8) >= total_sectors) { + copy_sect = total_sectors - i; + } + mvhd_read_sectors(vhdm, i, copy_sect, buff); + fwrite(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); + } + mvhd_close(vhdm); + mvhd_fseeko64(raw_img, 0, SEEK_SET); + return raw_img; +} diff --git a/src/disk/minivhd/minivhd_create.c b/src/disk/minivhd/minivhd_create.c new file mode 100644 index 000000000..57f748a5c --- /dev/null +++ b/src/disk/minivhd/minivhd_create.c @@ -0,0 +1,485 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "cwalk.h" +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd_struct_rw.h" +#include "minivhd_io.h" +#include "minivhd_create.h" +#include "minivhd.h" + +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off); +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors); +static int mvhd_gen_par_loc(MVHDSparseHeader* header, + const char* child_path, + const char* par_path, + uint64_t start_offset, + mvhd_utf16* w2ku_path_buff, + mvhd_utf16* w2ru_path_buff, + MVHDError* err); +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err); + +/** + * \brief Populate a VHD footer + * + * \param [in] footer to populate + * \param [in] size_in_bytes is the total size of the virtual hard disk in bytes + * \param [in] geom to use + * \param [in] type of HVD that is being created + * \param [in] sparse_header_off, an absolute file offset to the sparse header. Not used for fixed VHD images + */ +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) { + memcpy(footer->cookie, "conectix", sizeof footer->cookie); + footer->features = 0x00000002; + footer->fi_fmt_vers = 0x00010000; + footer->data_offset = (type == MVHD_TYPE_DIFF || type == MVHD_TYPE_DYNAMIC) ? sparse_header_off : 0xffffffffffffffff; + footer->timestamp = vhd_calc_timestamp(); + memcpy(footer->cr_app, "mvhd", sizeof footer->cr_app); + footer->cr_vers = 0x000e0000; + memcpy(footer->cr_host_os, "Wi2k", sizeof footer->cr_host_os); + footer->orig_sz = footer->curr_sz = size_in_bytes; + footer->geom.cyl = geom->cyl; + footer->geom.heads = geom->heads; + footer->geom.spt = geom->spt; + footer->disk_type = type; + mvhd_generate_uuid(footer->uuid); + footer->checksum = mvhd_gen_footer_checksum(footer); +} + +/** + * \brief Populate a VHD sparse header + * + * \param [in] header for sparse and differencing images + * \param [in] num_blks is the number of data blocks that the image contains + * \param [in] bat_offset is the absolute file offset for start of the Block Allocation Table + * \param [in] block_size_in_sectors is the block size in sectors. + */ +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors) { + memcpy(header->cookie, "cxsparse", sizeof header->cookie); + header->data_offset = 0xffffffffffffffff; + header->bat_offset = bat_offset; + header->head_vers = 0x00010000; + header->max_bat_ent = num_blks; + header->block_sz = block_size_in_sectors * (uint32_t)MVHD_SECTOR_SIZE; + header->checksum = mvhd_gen_sparse_checksum(header); +} + +/** + * \brief Generate parent locators for differencing VHD images + * + * \param [in] header the sparse header to populate with parent locator entries + * \param [in] child_path is the full path to the VHD being created + * \param [in] par_path is the full path to the parent image + * \param [in] start_offset is the absolute file offset from where to start storing the entries themselves. Must be sector aligned. + * \param [out] w2ku_path_buff is a buffer containing the full path to the parent, encoded as UTF16-LE + * \param [out] w2ru_path_buff is a buffer containing the relative path to the parent, encoded as UTF16-LE + * \param [out] err indicates what error occurred, if any + * + * \retval 0 if success + * \retval < 0 if an error occurrs. Check value of *err for actual error + */ +static int mvhd_gen_par_loc(MVHDSparseHeader* header, + const char* child_path, + const char* par_path, + uint64_t start_offset, + mvhd_utf16* w2ku_path_buff, + mvhd_utf16* w2ru_path_buff, + MVHDError* err) { + /* Get our paths to store in the differencing VHD. We want both the absolute path to the parent, + as well as the relative path from the child VHD */ + int rv = 0; + char* par_filename; + size_t par_fn_len; + char rel_path[MVHD_MAX_PATH_BYTES] = {0}; + char child_dir[MVHD_MAX_PATH_BYTES] = {0}; + size_t child_dir_len; + if (strlen(child_path) < sizeof child_dir) { + strcpy(child_dir, child_path); + } else { + *err = MVHD_ERR_PATH_LEN; + rv = -1; + goto end; + } + cwk_path_get_basename(par_path, (const char**)&par_filename, &par_fn_len); + cwk_path_get_dirname(child_dir, &child_dir_len); + child_dir[child_dir_len] = '\0'; + size_t rel_len = cwk_path_get_relative(child_dir, par_path, rel_path, sizeof rel_path); + if (rel_len > sizeof rel_path) { + *err = MVHD_ERR_PATH_LEN; + rv = -1; + goto end; + } + /* We have our paths, now store the parent filename directly in the sparse header. */ + int outlen = sizeof header->par_utf16_name; + int utf_ret; + utf_ret = UTF8ToUTF16BE((unsigned char*)header->par_utf16_name, &outlen, (const unsigned char*)par_filename, (int*)&par_fn_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + + /* And encode the paths to UTF16-LE */ + size_t par_path_len = strlen(par_path); + outlen = sizeof *w2ku_path_buff * MVHD_MAX_PATH_CHARS; + utf_ret = UTF8ToUTF16LE((unsigned char*)w2ku_path_buff, &outlen, (const unsigned char*)par_path, (int*)&par_path_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + int w2ku_len = utf_ret; + outlen = sizeof *w2ru_path_buff * MVHD_MAX_PATH_CHARS; + utf_ret = UTF8ToUTF16LE((unsigned char*)w2ru_path_buff, &outlen, (const unsigned char*)rel_path, (int*)&rel_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + int w2ru_len = utf_ret; + /** + * Finally populate the parent locaters in the sparse header. + * This is the information needed to find the paths saved elsewhere + * in the VHD image + */ + + /* Note about the plat_data_space field: The VHD spec says this field stores the number of sectors needed to store the locator path. + * However, Hyper-V and VPC store the number of bytes, not the number of sectors, and will refuse to open VHDs which have the + * number of sectors in this field. + * See https://stackoverflow.com/questions/40760181/mistake-in-virtual-hard-disk-image-format-specification + */ + header->par_loc_entry[0].plat_code = MVHD_DIF_LOC_W2KU; + header->par_loc_entry[0].plat_data_len = (uint32_t)w2ku_len; + header->par_loc_entry[0].plat_data_offset = (uint64_t)start_offset; + header->par_loc_entry[0].plat_data_space = ((header->par_loc_entry[0].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE; + header->par_loc_entry[1].plat_code = MVHD_DIF_LOC_W2RU; + header->par_loc_entry[1].plat_data_len = (uint32_t)w2ru_len; + header->par_loc_entry[1].plat_data_offset = (uint64_t)start_offset + ((uint64_t)header->par_loc_entry[0].plat_data_space); + header->par_loc_entry[1].plat_data_space = ((header->par_loc_entry[1].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE; + goto end; + +end: + return rv; +} + +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback) { + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_fixed_raw(path, NULL, size_in_bytes, &geom, err, progress_callback); +} + +/** + * \brief internal function that implements public mvhd_create_fixed() functionality + * + * Contains one more parameter than the public function, to allow using an existing + * raw disk image as the data source for the new fixed VHD. + * + * \param [in] raw_image file handle to a raw disk image to populate VHD + */ +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) { + uint8_t img_data[MVHD_SECTOR_SIZE] = {0}; + uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; + MVHDMeta* vhdm = calloc(1, sizeof *vhdm); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { + *err = MVHD_ERR_INVALID_GEOM; + goto cleanup_vhdm; + } + FILE* f = mvhd_fopen(path, "wb+", err); + if (f == NULL) { + goto cleanup_vhdm; + } + mvhd_fseeko64(f, 0, SEEK_SET); + uint32_t size_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t s; + if (progress_callback) + progress_callback(0, size_sectors); + if (raw_img != NULL) { + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t raw_size = (uint64_t)mvhd_ftello64(raw_img); + MVHDGeom raw_geom = mvhd_calculate_geometry(raw_size); + if (mvhd_calc_size_bytes(&raw_geom) != raw_size) { + *err = MVHD_ERR_CONV_SIZE; + goto cleanup_vhdm; + } + mvhd_gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0); + mvhd_fseeko64(raw_img, 0, SEEK_SET); + for (s = 0; s < size_sectors; s++) { + fread(img_data, sizeof img_data, 1, raw_img); + fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s + 1, size_sectors); + } + } else { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0); + for (s = 0; s < size_sectors; s++) { + fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s + 1, size_sectors); + } + } + mvhd_footer_to_buffer(&vhdm->footer, footer_buff); + fwrite(footer_buff, sizeof footer_buff, 1, f); + fclose(f); + f = NULL; + free(vhdm); + vhdm = mvhd_open(path, false, err); + goto end; + +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +end: + return vhdm; +} + +/** + * \brief Create sparse or differencing VHD image. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [in] size_in_bytes is the total size in bytes of the virtual hard disk image + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [in] block_size_in_sectors is the block size in sectors + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err) { + uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; + uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0}; + uint8_t bat_sect[MVHD_SECTOR_SIZE]; + MVHDGeom par_geom = {0}; + memset(bat_sect, 0xffffffff, sizeof bat_sect); + MVHDMeta* vhdm = NULL; + MVHDMeta* par_vhdm = NULL; + mvhd_utf16* w2ku_path_buff = NULL; + mvhd_utf16* w2ru_path_buff = NULL; + uint32_t par_mod_timestamp = 0; + if (par_path != NULL) { + par_mod_timestamp = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + goto end; + } + par_vhdm = mvhd_open(par_path, true, err); + if (par_vhdm == NULL) { + goto end; + } + } + vhdm = calloc(1, sizeof *vhdm); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto cleanup_par_vhdm; + } + if (par_vhdm != NULL) { + /* We use the geometry from the parent VHD, not what was passed in */ + par_geom.cyl = par_vhdm->footer.geom.cyl; + par_geom.heads = par_vhdm->footer.geom.heads; + par_geom.spt = par_vhdm->footer.geom.spt; + geom = &par_geom; + size_in_bytes = par_vhdm->footer.curr_sz; + } else if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { + *err = MVHD_ERR_INVALID_GEOM; + goto cleanup_vhdm; + } + + FILE* f = mvhd_fopen(path, "wb+", err); + if (f == NULL) { + goto cleanup_vhdm; + } + mvhd_fseeko64(f, 0, SEEK_SET); + /* Note, the sparse header follows the footer copy at the beginning of the file */ + if (par_path == NULL) { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE); + } else { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE); + } + mvhd_footer_to_buffer(&vhdm->footer, footer_buff); + /* As mentioned, start with a copy of the footer */ + fwrite(footer_buff, sizeof footer_buff, 1, f); + /** + * Calculate the number of (2MB or 512KB) data blocks required to store the entire + * contents of the disk image, followed by the number of sectors the + * BAT occupies in the image. Note, the BAT is sector aligned, and is padded + * to the next sector boundary + * */ + uint32_t size_in_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t num_blks = size_in_sectors / block_size_in_sectors; + if (size_in_sectors % block_size_in_sectors != 0) { + num_blks += 1; + } + uint32_t num_bat_sect = num_blks / MVHD_BAT_ENT_PER_SECT; + if (num_blks % MVHD_BAT_ENT_PER_SECT != 0) { + num_bat_sect += 1; + } + /* Storing the BAT directly following the footer and header */ + uint64_t bat_offset = MVHD_FOOTER_SIZE + MVHD_SPARSE_SIZE; + uint64_t par_loc_offset = 0; + + /** + * If creating a differencing VHD, populate the sparse header with additional + * data about the parent image, and where to find it, and it's last modified timestamp + * */ + if (par_vhdm != NULL) { + /** + * Create output buffers to encode paths into. + * The paths are not stored directly in the sparse header, hence the need to + * store them in buffers to be written to the VHD image later + */ + w2ku_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ku_path_buff); + if (w2ku_path_buff == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + w2ru_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ru_path_buff); + if (w2ru_path_buff == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + memcpy(vhdm->sparse.par_uuid, par_vhdm->footer.uuid, sizeof vhdm->sparse.par_uuid); + par_loc_offset = bat_offset + ((uint64_t)num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE); + if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path_buff, w2ru_path_buff, (MVHDError*)err) < 0) { + goto cleanup_vhdm; + } + vhdm->sparse.par_timestamp = par_mod_timestamp; + } + mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors); + mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); + fwrite(sparse_buff, sizeof sparse_buff, 1, f); + /* The BAT sectors need to be filled with 0xffffffff */ + for (uint32_t i = 0; i < num_bat_sect; i++) { + fwrite(bat_sect, sizeof bat_sect, 1, f); + } + mvhd_write_empty_sectors(f, 5); + /** + * If creating a differencing VHD, the paths to the parent image need to be written + * tp the file. Both absolute and relative paths are written + * */ + if (par_vhdm != NULL) { + uint64_t curr_pos = (uint64_t)mvhd_ftello64(f); + /* Double check my sums... */ + assert(curr_pos == par_loc_offset); + /* Fill the space required for location data with zero */ + uint8_t empty_sect[MVHD_SECTOR_SIZE] = {0}; + for (int i = 0; i < 2; i++) { + for (uint32_t j = 0; j < (vhdm->sparse.par_loc_entry[i].plat_data_space / MVHD_SECTOR_SIZE); j++) { + fwrite(empty_sect, sizeof empty_sect, 1, f); + } + } + /* Now write the location entries */ + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET); + fwrite(w2ku_path_buff, vhdm->sparse.par_loc_entry[0].plat_data_len, 1, f); + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET); + fwrite(w2ru_path_buff, vhdm->sparse.par_loc_entry[1].plat_data_len, 1, f); + /* and reset the file position to continue */ + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + vhdm->sparse.par_loc_entry[1].plat_data_space, SEEK_SET); + mvhd_write_empty_sectors(f, 5); + } + /* And finish with the footer */ + fwrite(footer_buff, sizeof footer_buff, 1, f); + fclose(f); + f = NULL; + free(vhdm); + vhdm = mvhd_open(path, false, err); + goto end; + +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +cleanup_par_vhdm: + if (par_vhdm != NULL) { + mvhd_close(par_vhdm); + } +end: + free(w2ku_path_buff); + free(w2ru_path_buff); + return vhdm; +} + +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) { + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) { + return mvhd_create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err) { + uint32_t geom_sector_size; + switch (options.type) + { + case MVHD_TYPE_FIXED: + case MVHD_TYPE_DYNAMIC: + geom_sector_size = mvhd_calc_size_sectors(&(options.geometry)); + if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0) + || (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES) + || (options.size_in_bytes == 0 && geom_sector_size == 0)) + { + *err = MVHD_ERR_INVALID_SIZE; + return NULL; + } + + if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes) + { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + + if (options.size_in_bytes == 0) + options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE; + + if (geom_sector_size == 0) + options.geometry = mvhd_calculate_geometry(options.size_in_bytes); + break; + case MVHD_TYPE_DIFF: + if (options.parent_path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + break; + default: + *err = MVHD_ERR_TYPE; + return NULL; + } + + if (options.path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + + if (options.type != MVHD_TYPE_FIXED) + { + if (options.block_size_in_sectors == MVHD_BLOCK_DEFAULT) + options.block_size_in_sectors = MVHD_BLOCK_LARGE; + + if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL) + { + *err = MVHD_ERR_INVALID_BLOCK_SIZE; + return NULL; + } + } + + switch (options.type) + { + case MVHD_TYPE_FIXED: + return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback); + case MVHD_TYPE_DYNAMIC: + return mvhd_create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err); + case MVHD_TYPE_DIFF: + return mvhd_create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err); + } + + return NULL; /* Make the compiler happy */ +} diff --git a/src/disk/minivhd/minivhd_create.h b/src/disk/minivhd/minivhd_create.h new file mode 100644 index 000000000..203834a71 --- /dev/null +++ b/src/disk/minivhd/minivhd_create.h @@ -0,0 +1,8 @@ +#ifndef MINIVHD_CREATE_H +#define MINIVHD_CREATE_H +#include +#include "minivhd.h" + +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback); + +#endif diff --git a/src/disk/minivhd/minivhd_internal.h b/src/disk/minivhd/minivhd_internal.h new file mode 100644 index 000000000..54b304830 --- /dev/null +++ b/src/disk/minivhd/minivhd_internal.h @@ -0,0 +1,96 @@ +#ifndef MINIVHD_INTERNAL_H +#define MINIVHD_INTERNAL_H +#include +#include +#include + +#define MVHD_FOOTER_SIZE 512 +#define MVHD_SPARSE_SIZE 1024 + +#define MVHD_SECTOR_SIZE 512 +#define MVHD_BAT_ENT_PER_SECT 128 + +#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000 + +#define MVHD_SPARSE_BLK 0xffffffff +/* For simplicity, we don't handle paths longer than this + * Note, this is the max path in characters, as that is what + * Windows uses + */ +#define MVHD_MAX_PATH_CHARS 260 +#define MVHD_MAX_PATH_BYTES 1040 + +#define MVHD_DIF_LOC_W2RU 0x57327275 +#define MVHD_DIF_LOC_W2KU 0x57326B75 + +typedef struct MVHDSectorBitmap { + uint8_t* curr_bitmap; + int sector_count; + int curr_block; +} MVHDSectorBitmap; + +typedef struct MVHDFooter { + uint8_t cookie[8]; + uint32_t features; + uint32_t fi_fmt_vers; + uint64_t data_offset; + uint32_t timestamp; + uint8_t cr_app[4]; + uint32_t cr_vers; + uint8_t cr_host_os[4]; + uint64_t orig_sz; + uint64_t curr_sz; + struct { + uint16_t cyl; + uint8_t heads; + uint8_t spt; + } geom; + uint32_t disk_type; + uint32_t checksum; + uint8_t uuid[16]; + uint8_t saved_st; + uint8_t reserved[427]; +} MVHDFooter; + +typedef struct MVHDSparseHeader { + uint8_t cookie[8]; + uint64_t data_offset; + uint64_t bat_offset; + uint32_t head_vers; + uint32_t max_bat_ent; + uint32_t block_sz; + uint32_t checksum; + uint8_t par_uuid[16]; + uint32_t par_timestamp; + uint32_t reserved_1; + uint8_t par_utf16_name[512]; + struct { + uint32_t plat_code; + uint32_t plat_data_space; + uint32_t plat_data_len; + uint32_t reserved; + uint64_t plat_data_offset; + } par_loc_entry[8]; + uint8_t reserved_2[256]; +} MVHDSparseHeader; + +typedef struct MVHDMeta MVHDMeta; +struct MVHDMeta { + FILE* f; + bool readonly; + char filename[MVHD_MAX_PATH_BYTES]; + struct MVHDMeta* parent; + MVHDFooter footer; + MVHDSparseHeader sparse; + uint32_t* block_offset; + int sect_per_block; + MVHDSectorBitmap bitmap; + int (*read_sectors)(MVHDMeta*, uint32_t, int, void*); + int (*write_sectors)(MVHDMeta*, uint32_t, int, void*); + struct { + uint8_t* zero_data; + int sector_count; + } format_buffer; +}; + +#endif diff --git a/src/disk/minivhd/minivhd_io.c b/src/disk/minivhd/minivhd_io.c new file mode 100644 index 000000000..74cc62883 --- /dev/null +++ b/src/disk/minivhd/minivhd_io.c @@ -0,0 +1,279 @@ +/** + * \file + * \brief Sector reading and writing implementations + */ + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include "minivhd_internal.h" +#include "minivhd_util.h" + +/* The following bit array macros adapted from + http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html */ + +#define VHD_SETBIT(A,k) ( A[(k/8)] |= (0x80 >> (k%8)) ) +#define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) ) +#define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) ) + +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect); +static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk); +static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk); +static void mvhd_create_block(MVHDMeta* vhdm, int blk); +static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm); + +/** + * \brief Check that we will not be overflowing buffers + * + * \param [in] offset The offset from which we are beginning from + * \param [in] num_sectors The number of sectors which we desire to read/write + * \param [in] total_sectors The total number of sectors available + * \param [out] transfer_sect The number of sectors to actually write. + * This may be lower than num_sectors if offset + num_sectors >= total_sectors + * \param [out] trunc_sectors The number of sectors truncated if transfer_sectors < num_sectors + */ +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect) { + *transfer_sect = num_sectors; + *trunc_sect = 0; + if ((total_sectors - offset) < (uint32_t)*transfer_sect) { + *transfer_sect = total_sectors - offset; + *trunc_sect = num_sectors - *transfer_sect; + } +} + +void mvhd_write_empty_sectors(FILE* f, int sector_count) { + uint8_t zero_bytes[MVHD_SECTOR_SIZE] = {0}; + for (int i = 0; i < sector_count; i++) { + fwrite(zero_bytes, sizeof zero_bytes, 1, f); + } +} + +/** + * \brief Read the sector bitmap for a block. + * + * If the block is sparse, the sector bitmap in memory will be + * zeroed. Otherwise, the sector bitmap is read from the VHD file. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block for which to read the sector bitmap from + */ +static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) { + if (vhdm->block_offset[blk] != MVHD_SPARSE_BLK) { + mvhd_fseeko64(vhdm->f, (uint64_t)vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET); + fread(vhdm->bitmap.curr_bitmap, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE, 1, vhdm->f); + } else { + memset(vhdm->bitmap.curr_bitmap, 0, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE); + } + vhdm->bitmap.curr_block = blk; +} + +/** + * \brief Write the current sector bitmap in memory to file + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) { + if (vhdm->bitmap.curr_block >= 0) { + int64_t abs_offset = (int64_t)vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, abs_offset, SEEK_SET); + fwrite(vhdm->bitmap.curr_bitmap, MVHD_SECTOR_SIZE, vhdm->bitmap.sector_count, vhdm->f); + } +} + +/** + * \brief Write block offset from memory into file + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block for which to write the offset for + */ +static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) { + uint64_t table_offset = vhdm->sparse.bat_offset + ((uint64_t)blk * sizeof *vhdm->block_offset); + uint32_t offset = mvhd_to_be32(vhdm->block_offset[blk]); + mvhd_fseeko64(vhdm->f, table_offset, SEEK_SET); + fwrite(&offset, sizeof offset, 1, vhdm->f); +} + +/** + * \brief Create an empty block in a sparse or differencing VHD image + * + * VHD images store data in blocks, which are typically 4096 sectors in size + * (~2MB). These blocks may be stored on disk in any order. Blocks are created + * on demand when required. + * + * This function creates new, empty blocks, by replacing the footer at the end of the file + * and then re-inserting the footer at the new file end. The BAT table entry for the + * new block is updated with the new offset. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block number to create + */ +static void mvhd_create_block(MVHDMeta* vhdm, int blk) { + uint8_t footer[MVHD_FOOTER_SIZE]; + /* Seek to where the footer SHOULD be */ + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(footer, sizeof footer, 1, vhdm->f); + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + if (!mvhd_is_conectix_str(footer)) { + /* Oh dear. We use the header instead, since something has gone wrong at the footer */ + mvhd_fseeko64(vhdm->f, 0, SEEK_SET); + fread(footer, sizeof footer, 1, vhdm->f); + mvhd_fseeko64(vhdm->f, 0, SEEK_END); + } + int64_t abs_offset = mvhd_ftello64(vhdm->f); + if (abs_offset % MVHD_SECTOR_SIZE != 0) { + /* Yikes! We're supposed to be on a sector boundary. Add some padding */ + int64_t padding_amount = (int64_t)MVHD_SECTOR_SIZE - (abs_offset % MVHD_SECTOR_SIZE); + uint8_t zero_byte = 0; + for (int i = 0; i < padding_amount; i++) { + fwrite(&zero_byte, sizeof zero_byte, 1, vhdm->f); + } + abs_offset += padding_amount; + } + uint32_t sect_offset = (uint32_t)(abs_offset / MVHD_SECTOR_SIZE); + int blk_size_sectors = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; + mvhd_write_empty_sectors(vhdm->f, vhdm->bitmap.sector_count + blk_size_sectors); + /* Add a bit of padding. That's what Windows appears to do, although it's not strictly necessary... */ + mvhd_write_empty_sectors(vhdm->f, 5); + /* And we finish with the footer */ + fwrite(footer, sizeof footer, 1, vhdm->f); + /* We no longer have a sparse block. Update that BAT! */ + vhdm->block_offset[blk] = sect_offset; + mvhd_write_bat_entry(vhdm, blk); +} + +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int64_t addr; + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + addr = (int64_t)offset * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + fread(out_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); + return truncated_sectors; +} + +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)out_buff; + int64_t addr; + uint32_t s, ls; + int blk, prev_blk, sib; + ls = offset + transfer_sectors; + prev_blk = -1; + for (s = offset; s < ls; s++) { + blk = s / vhdm->sect_per_block; + sib = s % vhdm->sect_per_block; + if (blk != prev_blk) { + prev_blk = blk; + if (vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); + } else { + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + } + } + if (VHD_TESTBIT(vhdm->bitmap.curr_bitmap, sib)) { + fread(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); + } else { + memset(buff, 0, MVHD_SECTOR_SIZE); + mvhd_fseeko64(vhdm->f, MVHD_SECTOR_SIZE, SEEK_CUR); + } + buff += MVHD_SECTOR_SIZE; + } + return truncated_sectors; +} + +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)out_buff; + MVHDMeta* curr_vhdm = vhdm; + uint32_t s, ls; + int blk, sib; + ls = offset + transfer_sectors; + for (s = offset; s < ls; s++) { + while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) { + blk = s / curr_vhdm->sect_per_block; + sib = s % curr_vhdm->sect_per_block; + if (curr_vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(curr_vhdm, blk); + } + if (!VHD_TESTBIT(curr_vhdm->bitmap.curr_bitmap, sib)) { + curr_vhdm = curr_vhdm->parent; + } else { break; } + } + /* We handle actual sector reading using the fixed or sparse functions, + as a differencing VHD is also a sparse VHD */ + if (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF || curr_vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) { + mvhd_sparse_read(curr_vhdm, s, 1, buff); + } else { + mvhd_fixed_read(curr_vhdm, s, 1, buff); + } + curr_vhdm = vhdm; + buff += MVHD_SECTOR_SIZE; + } + return truncated_sectors; +} + +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + int64_t addr; + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + addr = (int64_t)offset * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + fwrite(in_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); + return truncated_sectors; +} + +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)in_buff; + int64_t addr; + uint32_t s, ls; + int blk, prev_blk, sib; + ls = offset + transfer_sectors; + prev_blk = -1; + for (s = offset; s < ls; s++) { + blk = s / vhdm->sect_per_block; + sib = s % vhdm->sect_per_block; + if (vhdm->bitmap.curr_block != blk && prev_blk >= 0) { + /* Write the sector bitmap for the previous block, before we replace it. */ + mvhd_write_curr_sect_bitmap(vhdm); + } + if (vhdm->block_offset[blk] == MVHD_SPARSE_BLK) { + /* "read" the sector bitmap first, before creating a new block, as the bitmap will be + zero either way */ + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_create_block(vhdm, blk); + } + if (blk != prev_blk) { + if (vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); + } else { + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + } + prev_blk = blk; + } + fwrite(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); + VHD_SETBIT(vhdm->bitmap.curr_bitmap, sib); + buff += MVHD_SECTOR_SIZE; + } + /* And write the sector bitmap for the last block we visited to disk */ + mvhd_write_curr_sect_bitmap(vhdm); + return truncated_sectors; +} + +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + return 0; +} diff --git a/src/disk/minivhd/minivhd_io.h b/src/disk/minivhd/minivhd_io.h new file mode 100644 index 000000000..7ffd10f49 --- /dev/null +++ b/src/disk/minivhd/minivhd_io.h @@ -0,0 +1,132 @@ +#ifndef MINIVHD_IO_H +#define MINIVHD_IO_H +#include "minivhd.h" + +/** + * \brief Write zero filled sectors to file. + * + * Note, the caller should set the file position before calling this + * function for correct operation. + * + * \param [in] f File to write sectors to + * \param [in] sector_count The number of sectors to write + */ +void mvhd_write_empty_sectors(FILE* f, int sector_count); + +/** + * \brief Read a fixed VHD image + * + * Fixed VHD images are essentially raw image files with a footer tacked on + * the end. They are therefore straightforward to write + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Read a sparse VHD image + * + * Sparse, or dynamic images are VHD images that grow as data is written to them. + * + * This function implements the logic to read sectors from the file, taking into + * account the fact that blocks may be stored on disk in any order, and that the + * read could cross block boundaries. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Read a differencing VHD image + * + * Differencing images are a variant of a sparse image. They contain the grow-on-demand + * properties of sparse images, but also reference a parent image. Data is read from the + * child image only if it is newer than the data stored in the parent image. + * + * This function implements the logic to read sectors from the child, or a parent image. + * Differencing images may have a differencing image as a parent, creating a chain of images. + * There is no theoretical chain length limit, although I do not consider long chains to be + * advisable. Verifying the parent-child relationship is not very robust. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Write to a fixed VHD image + * + * Fixed VHD images are essentially raw image files with a footer tacked on + * the end. They are therefore straightforward to write + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief Write to a sparse or differencing VHD image + * + * Sparse, or dynamic images are VHD images that grow as data is written to them. + * + * Differencing images are a variant of a sparse image. They contain the grow-on-demand + * properties of sparse images, but also reference a parent image. Data is always written + * to the child image. This makes writing to differencing images essentially identical to + * writing to sparse images, hence they use the same function. + * + * This function implements the logic to write sectors to the file, taking into + * account the fact that blocks may be stored on disk in any order, and that the + * write operation could cross block boundaries. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief A no-op function to "write" to read-only VHD images + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +#endif diff --git a/src/disk/minivhd/minivhd_manage.c b/src/disk/minivhd/minivhd_manage.c new file mode 100644 index 000000000..f76826566 --- /dev/null +++ b/src/disk/minivhd/minivhd_manage.c @@ -0,0 +1,535 @@ +/** + * \file + * \brief VHD management functions (open, close, read write etc) + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "cwalk.h" +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_io.h" +#include "minivhd_util.h" +#include "minivhd_struct_rw.h" +#include "minivhd.h" + +int mvhd_errno = 0; +static char tmp_open_path[MVHD_MAX_PATH_BYTES] = {0}; +struct MVHDPaths { + char dir_path[MVHD_MAX_PATH_BYTES]; + char file_name[MVHD_MAX_PATH_BYTES]; + char w2ku_path[MVHD_MAX_PATH_BYTES]; + char w2ru_path[MVHD_MAX_PATH_BYTES]; + char joined_path[MVHD_MAX_PATH_BYTES]; + uint16_t tmp_src_path[MVHD_MAX_PATH_CHARS]; +}; + +static void mvhd_read_footer(MVHDMeta* vhdm); +static void mvhd_read_sparse_header(MVHDMeta* vhdm); +static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm); +static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm); +static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err); +static void mvhd_calc_sparse_values(MVHDMeta* vhdm); +static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err); + +/** + * \brief Populate data stuctures with content from a VHD footer + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_read_footer(MVHDMeta* vhdm) { + uint8_t buffer[MVHD_FOOTER_SIZE]; + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(buffer, sizeof buffer, 1, vhdm->f); + mvhd_buffer_to_footer(&vhdm->footer, buffer); +} + +/** + * \brief Populate data stuctures with content from a VHD sparse header + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_read_sparse_header(MVHDMeta* vhdm) { + uint8_t buffer[MVHD_SPARSE_SIZE]; + mvhd_fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET); + fread(buffer, sizeof buffer, 1, vhdm->f); + mvhd_buffer_to_header(&vhdm->sparse, buffer); +} + +/** + * \brief Validate VHD footer checksum + * + * This works by generating a checksum from the footer, and comparing it against the stored checksum. + * + * \param [in] vhdm MiniVHD data structure + */ +static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm) { + return vhdm->footer.checksum == mvhd_gen_footer_checksum(&vhdm->footer); +} + +/** + * \brief Validate VHD sparse header checksum + * + * This works by generating a checksum from the sparse header, and comparing it against the stored checksum. + * + * \param [in] vhdm MiniVHD data structure + */ +static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm) { + return vhdm->sparse.checksum == mvhd_gen_sparse_checksum(&vhdm->sparse); +} + +/** + * \brief Read BAT into MiniVHD data structure + * + * The Block Allocation Table (BAT) is the structure in a sparse and differencing VHD which stores + * the 4-byte sector offsets for each data block. This function allocates enough memory to contain + * the entire BAT, and then reads the contents of the BAT into the buffer. + * + * \param [in] vhdm MiniVHD data structure + * \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails + * + * \retval -1 if an error occurrs. Check value of err in this case + * \retval 0 if the function call succeeds + */ +static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) { + vhdm->block_offset = calloc(vhdm->sparse.max_bat_ent, sizeof *vhdm->block_offset); + if (vhdm->block_offset == NULL) { + *err = MVHD_ERR_MEM; + return -1; + } + mvhd_fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET); + for (uint32_t i = 0; i < vhdm->sparse.max_bat_ent; i++) { + fread(&vhdm->block_offset[i], sizeof *vhdm->block_offset, 1, vhdm->f); + vhdm->block_offset[i] = mvhd_from_be32(vhdm->block_offset[i]); + } + return 0; +} + +/** + * \brief Perform a one-time calculation of some sparse VHD values + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_calc_sparse_values(MVHDMeta* vhdm) { + vhdm->sect_per_block = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; + int bm_bytes = vhdm->sect_per_block / 8; + vhdm->bitmap.sector_count = bm_bytes / MVHD_SECTOR_SIZE; + if (bm_bytes % MVHD_SECTOR_SIZE > 0) { + vhdm->bitmap.sector_count++; + } +} + +/** + * \brief Allocate memory for a sector bitmap. + * + * Each data block is preceded by a sector bitmap. Each bit indicates whether the corresponding sector + * is considered 'clean' or 'dirty' (for sparse VHD images), or whether to read from the parent or current + * image (for differencing images). + * + * \param [in] vhdm MiniVHD data structure + * \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails + * + * \retval -1 if an error occurrs. Check value of err in this case + * \retval 0 if the function call succeeds + */ +static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err) { + vhdm->bitmap.curr_bitmap = calloc(vhdm->bitmap.sector_count, MVHD_SECTOR_SIZE); + if (vhdm->bitmap.curr_bitmap == NULL) { + *err = MVHD_ERR_MEM; + return -1; + } + vhdm->bitmap.curr_block = -1; + return 0; +} + +/** + * \brief Check if the path for a given platform code exists + * + * From the available paths, both relative and absolute, construct a full path + * and attempt to open a file at that path. + * + * Note, this function makes no attempt to verify that the path is the correct + * VHD image, or even a VHD image at all. + * + * \param [in] paths a struct containing all available paths to work with + * \param [in] the platform code to try and obtain a path for. Setting this to zero + * will try using the directory of the child image + * + * \retval true if a file is found + * \retval false if a file is not found + */ +static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) { + memset(paths->joined_path, 0, sizeof paths->joined_path); + FILE* f; + int cwk_ret, ferr; + enum cwk_path_style style = cwk_path_guess_style((const char*)paths->dir_path); + cwk_path_set_style(style); + cwk_ret = 1; + if (plat_code == MVHD_DIF_LOC_W2RU && *paths->w2ru_path) { + cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->w2ru_path, paths->joined_path, sizeof paths->joined_path); + } else if (plat_code == MVHD_DIF_LOC_W2KU && *paths->w2ku_path) { + memcpy(paths->joined_path, paths->w2ku_path, (sizeof paths->joined_path) - 1); + cwk_ret = 0; + } else if (plat_code == 0) { + cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->file_name, paths->joined_path, sizeof paths->joined_path); + } + if (cwk_ret > MVHD_MAX_PATH_BYTES) { + return false; + } + f = mvhd_fopen((const char*)paths->joined_path, "rb", &ferr); + if (f != NULL) { + /* We found a file at the requested path! */ + memcpy(tmp_open_path, paths->joined_path, (sizeof paths->joined_path) - 1); + tmp_open_path[sizeof tmp_open_path - 1] = '\0'; + fclose(f); + return true; + } else { + return false; + } +} + +/** + * \brief attempt to obtain a file path to a file that may be a valid VHD image + * + * Differential VHD images store both a UTF-16BE file name (or path), and up to + * eight "parent locator" entries. Using this information, this function tries to + * find a parent image. + * + * This function does not verify if the path returned is a valid parent image. + * + * \param [in] vhdm current MiniVHD data structure + * \param [out] err any errors that may occurr. Check this if NULL is returned + * + * \return a pointer to the global string `tmp_open_path`, or NULL if a path could + * not be found, or some error occurred + */ +static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) { + int utf_outlen, utf_inlen, utf_ret; + char* par_fp = NULL; + /* We can't resolve relative paths if we don't have an absolute + path to work with */ + if (!cwk_path_is_absolute((const char*)vhdm->filename)) { + *err = MVHD_ERR_PATH_REL; + goto end; + } + struct MVHDPaths* paths = calloc(1, sizeof *paths); + if (paths == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + size_t dirlen; + cwk_path_get_dirname((const char*)vhdm->filename, &dirlen); + if (dirlen >= sizeof paths->dir_path) { + *err = MVHD_ERR_PATH_LEN; + goto paths_cleanup; + } + memcpy(paths->dir_path, vhdm->filename, dirlen); + /* Get the filename field from the sparse header. */ + utf_outlen = (int)sizeof paths->file_name; + utf_inlen = (int)sizeof vhdm->sparse.par_utf16_name; + utf_ret = UTF16BEToUTF8((unsigned char*)paths->file_name, &utf_outlen, (const unsigned char*)vhdm->sparse.par_utf16_name, &utf_inlen); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, err); + goto paths_cleanup; + } + /* Now read the parent locator entries, both relative and absolute, if they exist */ + unsigned char* loc_path; + for (int i = 0; i < 8; i++) { + utf_outlen = MVHD_MAX_PATH_BYTES - 1; + if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2RU) { + loc_path = (unsigned char*)paths->w2ru_path; + } else if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2KU) { + loc_path = (unsigned char*)paths->w2ku_path; + } else { + continue; + } + utf_inlen = vhdm->sparse.par_loc_entry[i].plat_data_len; + if (utf_inlen > MVHD_MAX_PATH_BYTES) { + *err = MVHD_ERR_PATH_LEN; + goto paths_cleanup; + } + mvhd_fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET); + fread(paths->tmp_src_path, sizeof (uint8_t), utf_inlen, vhdm->f); + /* Note, the W2*u parent locators are UTF-16LE, unlike the filename field previously obtained, + which is UTF-16BE */ + utf_ret = UTF16LEToUTF8(loc_path, &utf_outlen, (const unsigned char*)paths->tmp_src_path, &utf_inlen); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, err); + goto paths_cleanup; + } + } + /* We have paths in UTF-8. We should have enough info to try and find the parent VHD */ + /* Does the relative path exist? */ + if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2RU)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* What about trying the child directory? */ + if (mvhd_parent_path_exists(paths, 0)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* Well, all else fails, try the stored absolute path, if it exists */ + if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2KU)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* If we reach this point, we could not find a path with a valid file */ + par_fp = NULL; + *err = MVHD_ERR_PAR_NOT_FOUND; + +paths_cleanup: + free(paths); + paths = NULL; +end: + return par_fp; +} + +/** + * \brief Attach the read/write function pointers to read/write functions + * + * Depending on the VHD type, different sector reading and writing functions are used. + * The functions are called via function pointers stored in the vhdm struct. + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_assign_io_funcs(MVHDMeta* vhdm) { + switch (vhdm->footer.disk_type) { + case MVHD_TYPE_FIXED: + vhdm->read_sectors = mvhd_fixed_read; + vhdm->write_sectors = mvhd_fixed_write; + break; + case MVHD_TYPE_DYNAMIC: + vhdm->read_sectors = mvhd_sparse_read; + vhdm->write_sectors = mvhd_sparse_diff_write; + break; + case MVHD_TYPE_DIFF: + vhdm->read_sectors = mvhd_diff_read; + vhdm->write_sectors = mvhd_sparse_diff_write; + break; + } + if (vhdm->readonly) { + vhdm->write_sectors = mvhd_noop_write; + } +} + +bool mvhd_file_is_vhd(FILE* f) { + if (f) { + uint8_t con_str[8]; + mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(con_str, sizeof con_str, 1, f); + return mvhd_is_conectix_str(con_str); + } else { + return false; + } +} + +MVHDGeom mvhd_calculate_geometry(uint64_t size) { + MVHDGeom chs; + uint32_t ts = (uint32_t)(size / MVHD_SECTOR_SIZE); + uint32_t spt, heads, cyl, cth; + if (ts > 65535 * 16 * 255) { + ts = 65535 * 16 * 255; + } + if (ts >= 65535 * 16 * 63) { + spt = 255; + heads = 16; + cth = ts / spt; + } else { + spt = 17; + cth = ts / spt; + heads = (cth + 1023) / 1024; + if (heads < 4) { + heads = 4; + } + if (cth >= (heads * 1024) || heads > 16) { + spt = 31; + heads = 16; + cth = ts / spt; + } + if (cth >= (heads * 1024)) { + spt = 63; + heads = 16; + cth = ts / spt; + } + } + cyl = cth / heads; + chs.heads = heads; + chs.spt = spt; + chs.cyl = cyl; + return chs; +} + +MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) { + MVHDError open_err; + MVHDMeta *vhdm = calloc(sizeof *vhdm, 1); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + if (strlen(path) >= sizeof vhdm->filename) { + *err = MVHD_ERR_PATH_LEN; + goto cleanup_vhdm; + } + //This is safe, as we've just checked for potential overflow above + strcpy(vhdm->filename, path); + vhdm->f = readonly ? mvhd_fopen((const char*)vhdm->filename, "rb", err) : mvhd_fopen((const char*)vhdm->filename, "rb+", err); + if (vhdm->f == NULL) { + /* note, mvhd_fopen sets err for us */ + goto cleanup_vhdm; + } + vhdm->readonly = readonly; + if (!mvhd_file_is_vhd(vhdm->f)) { + *err = MVHD_ERR_NOT_VHD; + goto cleanup_file; + } + mvhd_read_footer(vhdm); + if (!mvhd_footer_checksum_valid(vhdm)) { + *err = MVHD_ERR_FOOTER_CHECKSUM; + goto cleanup_file; + } + if (vhdm->footer.disk_type == MVHD_TYPE_DIFF || vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) { + mvhd_read_sparse_header(vhdm); + if (!mvhd_sparse_checksum_valid(vhdm)) { + *err = MVHD_ERR_SPARSE_CHECKSUM; + goto cleanup_file; + } + if (mvhd_read_bat(vhdm, &open_err) == -1) { + *err = open_err; + goto cleanup_file; + } + mvhd_calc_sparse_values(vhdm); + if (mvhd_init_sector_bitmap(vhdm, &open_err) == -1) { + *err = open_err; + goto cleanup_bat; + } + + } else if (vhdm->footer.disk_type != MVHD_TYPE_FIXED) { + *err = MVHD_ERR_TYPE; + goto cleanup_bitmap; + } + mvhd_assign_io_funcs(vhdm); + vhdm->format_buffer.zero_data = calloc(64, MVHD_SECTOR_SIZE); + if (vhdm->format_buffer.zero_data == NULL) { + *err = MVHD_ERR_MEM; + goto cleanup_bitmap; + } + vhdm->format_buffer.sector_count = 64; + if (vhdm->footer.disk_type == MVHD_TYPE_DIFF) { + char* par_path = mvhd_get_diff_parent_path(vhdm, err); + if (par_path == NULL) { + goto cleanup_format_buff; + } + uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + goto cleanup_format_buff; + } + if (vhdm->sparse.par_timestamp != par_mod_ts) { + /* The last-modified timestamp is to fragile to make this a fatal error. + Instead, we inform the caller of the potential problem. */ + *err = MVHD_ERR_TIMESTAMP; + } + vhdm->parent = mvhd_open(par_path, true, err); + if (vhdm->parent == NULL) { + goto cleanup_format_buff; + } + if (memcmp(vhdm->sparse.par_uuid, vhdm->parent->footer.uuid, sizeof vhdm->sparse.par_uuid) != 0) { + *err = MVHD_ERR_INVALID_PAR_UUID; + goto cleanup_format_buff; + } + } + /* If we've reached this point, we are good to go, so skip the cleanup steps */ + goto end; +cleanup_format_buff: + free(vhdm->format_buffer.zero_data); + vhdm->format_buffer.zero_data = NULL; +cleanup_bitmap: + free(vhdm->bitmap.curr_bitmap); + vhdm->bitmap.curr_bitmap = NULL; +cleanup_bat: + free(vhdm->block_offset); + vhdm->block_offset = NULL; +cleanup_file: + fclose(vhdm->f); + vhdm->f = NULL; +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +end: + return vhdm; +} + +void mvhd_close(MVHDMeta* vhdm) { + if (vhdm != NULL) { + if (vhdm->parent != NULL) { + mvhd_close(vhdm->parent); + } + fclose(vhdm->f); + if (vhdm->block_offset != NULL) { + free(vhdm->block_offset); + vhdm->block_offset = NULL; + } + if (vhdm->bitmap.curr_bitmap != NULL) { + free(vhdm->bitmap.curr_bitmap); + vhdm->bitmap.curr_bitmap = NULL; + } + if (vhdm->format_buffer.zero_data != NULL) { + free(vhdm->format_buffer.zero_data); + vhdm->format_buffer.zero_data = NULL; + } + free(vhdm); + vhdm = NULL; + } +} + +int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) { + uint8_t sparse_buff[1024]; + if (vhdm == NULL || err == NULL) { + *err = MVHD_ERR_INVALID_PARAMS; + return -1; + } + if (vhdm->footer.disk_type != MVHD_TYPE_DIFF) { + *err = MVHD_ERR_TYPE; + return -1; + } + char* par_path = mvhd_get_diff_parent_path(vhdm, err); + if (par_path == NULL) { + return -1; + } + uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + return -1; + } + /* Update the timestamp and sparse header checksum */ + vhdm->sparse.par_timestamp = par_mod_ts; + vhdm->sparse.checksum = mvhd_gen_sparse_checksum(&vhdm->sparse); + /* Generate and write the updated sparse header */ + mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); + mvhd_fseeko64(vhdm->f, (int64_t)vhdm->footer.data_offset, SEEK_SET); + fwrite(sparse_buff, sizeof sparse_buff, 1, vhdm->f); + return 0; +} + +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + return vhdm->read_sectors(vhdm, offset, num_sectors, out_buff); +} + +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + return vhdm->write_sectors(vhdm, offset, num_sectors, in_buff); +} + +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors) { + int num_full = num_sectors / vhdm->format_buffer.sector_count; + int remain = num_sectors % vhdm->format_buffer.sector_count; + for (int i = 0; i < num_full; i++) { + vhdm->write_sectors(vhdm, offset, vhdm->format_buffer.sector_count, vhdm->format_buffer.zero_data); + offset += vhdm->format_buffer.sector_count; + } + vhdm->write_sectors(vhdm, offset, remain, vhdm->format_buffer.zero_data); + return 0; +} diff --git a/src/disk/minivhd/minivhd_struct_rw.c b/src/disk/minivhd/minivhd_struct_rw.c new file mode 100644 index 000000000..5285f8a68 --- /dev/null +++ b/src/disk/minivhd/minivhd_struct_rw.c @@ -0,0 +1,167 @@ +/** + * \file + * \brief Header and footer serialize/deserialize functions + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "minivhd_util.h" +#include "minivhd_internal.h" + +/* Read data from footer into the struct members, swapping endian where necessary + Note: order matters here! We must read each field in the order the struct is in. + Doing this may be less elegant than performing a memcpy to a packed struct, but + it avoids potential data alignment issues, and the endian swapping allows us to + use the fields directly. */ + +static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer); +static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer); + +/** + * \brief Get the next field from a buffer and store it in a struct member, converting endian if necessary + * + * \param [out] struct_memb struct member to save the field to + * \param [in] memb_size the size of struct_memb, in bytes + * \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32) + * \param [in] buffer the buffer from which fields are read from. Will be advanced at the end of the function call + */ +static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) { + memcpy(struct_memb, *buffer, memb_size); + if (req_endian) { + switch (memb_size) { + case 2: + *(uint16_t*)(struct_memb) = mvhd_from_be16(*(uint16_t*)(struct_memb)); + break; + case 4: + *(uint32_t*)(struct_memb) = mvhd_from_be32(*(uint32_t*)(struct_memb)); + break; + case 8: + *(uint64_t*)(struct_memb) = mvhd_from_be64(*(uint64_t*)(struct_memb)); + break; + } + } + *buffer += memb_size; +} + +/** + * \brief Save a struct member into a buffer, converting endian if necessary + * + * \param [in] struct_memb struct member read from + * \param [in] memb_size the size of struct_memb, in bytes + * \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32) + * \param [out] buffer the buffer from which struct member is saved to. Will be advanced at the end of the function call + */ +static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) { + uint8_t *buf_ptr = *buffer; + memcpy(buf_ptr, struct_memb, memb_size); + if (req_endian) { + switch (memb_size) { + case 2: + *((uint16_t*)buf_ptr) = mvhd_to_be16(*(uint16_t*)(struct_memb)); + break; + case 4: + *((uint32_t*)buf_ptr) = mvhd_to_be32(*(uint32_t*)(struct_memb)); + break; + case 8: + *((uint64_t*)buf_ptr) = mvhd_to_be64(*(uint64_t*)(struct_memb)); + break; + } + } + buf_ptr += memb_size; + *buffer = buf_ptr; +} + +void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr); +} + +void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr); +} + +void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr); + mvhd_next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr); + for (int i = 0; i < 8; i++) { + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr); + } + mvhd_next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr); +} + +void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr); + mvhd_next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr); + for (int i = 0; i < 8; i++) { + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr); + } + mvhd_next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr); +} diff --git a/src/disk/minivhd/minivhd_struct_rw.h b/src/disk/minivhd/minivhd_struct_rw.h new file mode 100644 index 000000000..39441fb39 --- /dev/null +++ b/src/disk/minivhd/minivhd_struct_rw.h @@ -0,0 +1,38 @@ +#ifndef MINIVHD_STRUCT_RW_H +#define MINIVHD_STRUCT_RW_H + +#include "minivhd_internal.h" + +/** + * \brief Save the contents of a VHD footer from a buffer to a struct + * + * \param [out] footer save contents of buffer into footer + * \param [in] buffer VHD footer in raw bytes + */ +void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD sparse header from a buffer to a struct + * + * \param [out] header save contents of buffer into header + * \param [in] buffer VHD header in raw bytes + */ +void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD footer struct to a buffer + * + * \param [in] footer save contents of struct into buffer + * \param [out] buffer VHD footer in raw bytes + */ +void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD sparse header struct to a buffer + * + * \param [in] header save contents of struct into buffer + * \param [out] buffer VHD sparse header in raw bytes + */ +void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer); + +#endif diff --git a/src/disk/minivhd/minivhd_util.c b/src/disk/minivhd/minivhd_util.c new file mode 100644 index 000000000..5bfc59915 --- /dev/null +++ b/src/disk/minivhd/minivhd_util.c @@ -0,0 +1,329 @@ +/** + * \file + * \brief Utility functions + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" + +const char MVHD_CONECTIX_COOKIE[] = "conectix"; +const char MVHD_CREATOR[] = "pcem"; +const char MVHD_CREATOR_HOST_OS[] = "Wi2k"; +const char MVHD_CXSPARSE_COOKIE[] = "cxsparse"; + +uint16_t mvhd_from_be16(uint16_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint16_t ret = 0; + ret |= (uint16_t)tmp[0] << 8; + ret |= (uint16_t)tmp[1] << 0; + return ret; +} +uint32_t mvhd_from_be32(uint32_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint32_t ret = 0; + ret = (uint32_t)tmp[0] << 24; + ret |= (uint32_t)tmp[1] << 16; + ret |= (uint32_t)tmp[2] << 8; + ret |= (uint32_t)tmp[3] << 0; + return ret; +} +uint64_t mvhd_from_be64(uint64_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint64_t ret = 0; + ret = (uint64_t)tmp[0] << 56; + ret |= (uint64_t)tmp[1] << 48; + ret |= (uint64_t)tmp[2] << 40; + ret |= (uint64_t)tmp[3] << 32; + ret |= (uint64_t)tmp[4] << 24; + ret |= (uint64_t)tmp[5] << 16; + ret |= (uint64_t)tmp[6] << 8; + ret |= (uint64_t)tmp[7] << 0; + return ret; +} +uint16_t mvhd_to_be16(uint16_t val) { + uint16_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (val & 0xff00) >> 8; + tmp[1] = (val & 0x00ff) >> 0; + return ret; +} +uint32_t mvhd_to_be32(uint32_t val) { + uint32_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (val & 0xff000000) >> 24; + tmp[1] = (val & 0x00ff0000) >> 16; + tmp[2] = (val & 0x0000ff00) >> 8; + tmp[3] = (val & 0x000000ff) >> 0; + return ret; +} +uint64_t mvhd_to_be64(uint64_t val) { + uint64_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (uint8_t)((val & 0xff00000000000000) >> 56); + tmp[1] = (uint8_t)((val & 0x00ff000000000000) >> 48); + tmp[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40); + tmp[3] = (uint8_t)((val & 0x000000ff00000000) >> 32); + tmp[4] = (uint8_t)((val & 0x00000000ff000000) >> 24); + tmp[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16); + tmp[6] = (uint8_t)((val & 0x000000000000ff00) >> 8); + tmp[7] = (uint8_t)((val & 0x00000000000000ff) >> 0); + return ret; +} + +bool mvhd_is_conectix_str(const void* buffer) { + if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) { + return true; + } else { + return false; + } +} + +void mvhd_generate_uuid(uint8_t* uuid) +{ + /* We aren't doing crypto here, so using system time as seed should be good enough */ + srand((unsigned int)time(0)); + for (int n = 0; n < 16; n++) { + uuid[n] = rand(); + } + uuid[6] &= 0x0F; + uuid[6] |= 0x40; /* Type 4 */ + uuid[8] &= 0x3F; + uuid[8] |= 0x80; /* Variant 1 */ +} + +uint32_t vhd_calc_timestamp(void) +{ + time_t start_time; + time_t curr_time; + double vhd_time; + start_time = MVHD_START_TS; /* 1 Jan 2000 00:00 */ + curr_time = time(NULL); + vhd_time = difftime(curr_time, start_time); + return (uint32_t)vhd_time; +} + +uint32_t mvhd_epoch_to_vhd_ts(time_t ts) { + time_t start_time = MVHD_START_TS; + if (ts < start_time) { + return start_time; + } + double vhd_time = difftime(ts, start_time); + return (uint32_t)vhd_time; +} + +time_t vhd_get_created_time(MVHDMeta *vhdm) +{ + time_t vhd_time = (time_t)vhdm->footer.timestamp; + time_t vhd_time_unix = MVHD_START_TS + vhd_time; + return vhd_time_unix; +} + +FILE* mvhd_fopen(const char* path, const char* mode, int* err) { + FILE* f = NULL; +#ifdef _WIN32 + size_t path_len = strlen(path); + size_t mode_len = strlen(mode); + mvhd_utf16 new_path[260] = {0}; + int new_path_len = (sizeof new_path) - 2; + mvhd_utf16 mode_str[5] = {0}; + int new_mode_len = (sizeof mode_str) - 2; + int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); + int mode_res = UTF8ToUTF16LE((unsigned char*)mode_str, &new_mode_len, (const unsigned char*)mode, (int*)&mode_len); + if (path_res > 0 && mode_res > 0) { + f = _wfopen(new_path, mode_str); + if (f == NULL) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + } + } else { + if (path_res == -1 || mode_res == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (path_res == -2 || mode_res == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } + } +#else + f = fopen(path, mode); + if (f == NULL) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + } +#endif + return f; +} + +void mvhd_set_encoding_err(int encoding_retval, int* err) { + if (encoding_retval == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (encoding_retval == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } +} + +uint64_t mvhd_calc_size_bytes(MVHDGeom *geom) { + uint64_t img_size = (uint64_t)geom->cyl * (uint64_t)geom->heads * (uint64_t)geom->spt * (uint64_t)MVHD_SECTOR_SIZE; + return img_size; +} + +uint32_t mvhd_calc_size_sectors(MVHDGeom *geom) { + uint32_t sector_size = (uint32_t)geom->cyl * (uint32_t)geom->heads * (uint32_t)geom->spt; + return sector_size; +} + +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm) { + MVHDGeom geometry = { .cyl = vhdm->footer.geom.cyl, .heads = vhdm->footer.geom.heads, .spt = vhdm->footer.geom.spt }; + return geometry; +} + +uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer) { + uint32_t new_chk = 0; + uint32_t orig_chk = footer->checksum; + footer->checksum = 0; + uint8_t* footer_bytes = (uint8_t*)footer; + for (size_t i = 0; i < sizeof *footer; i++) { + new_chk += footer_bytes[i]; + } + footer->checksum = orig_chk; + return ~new_chk; +} + +uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header) { + uint32_t new_chk = 0; + uint32_t orig_chk = header->checksum; + header->checksum = 0; + uint8_t* sparse_bytes = (uint8_t*)header; + for (size_t i = 0; i < sizeof *header; i++) { + new_chk += sparse_bytes[i]; + } + header->checksum = orig_chk; + return ~new_chk; +} + +const char* mvhd_strerr(MVHDError err) { + switch (err) { + case MVHD_ERR_MEM: + return "memory allocation error"; + case MVHD_ERR_FILE: + return "file error"; + case MVHD_ERR_NOT_VHD: + return "file is not a VHD image"; + case MVHD_ERR_TYPE: + return "unsupported VHD image type"; + case MVHD_ERR_FOOTER_CHECKSUM: + return "invalid VHD footer checksum"; + case MVHD_ERR_SPARSE_CHECKSUM: + return "invalid VHD sparse header checksum"; + case MVHD_ERR_UTF_TRANSCODING_FAILED: + return "error converting path encoding"; + case MVHD_ERR_UTF_SIZE: + return "buffer size mismatch when converting path encoding"; + case MVHD_ERR_PATH_REL: + return "relative path detected where absolute path expected"; + case MVHD_ERR_PATH_LEN: + return "path length exceeds MVHD_MAX_PATH"; + case MVHD_ERR_PAR_NOT_FOUND: + return "parent VHD image not found"; + case MVHD_ERR_INVALID_PAR_UUID: + return "UUID mismatch between child and parent VHD"; + case MVHD_ERR_INVALID_GEOM: + return "invalid geometry detected"; + case MVHD_ERR_INVALID_SIZE: + return "invalid size"; + case MVHD_ERR_INVALID_BLOCK_SIZE: + return "invalid block size"; + case MVHD_ERR_INVALID_PARAMS: + return "invalid parameters passed to function"; + case MVHD_ERR_CONV_SIZE: + return "error converting image. Size mismatch detechted"; + default: + return "unknown error"; + } +} + +int64_t mvhd_ftello64(FILE* stream) +{ +#ifdef _MSC_VER + return _ftelli64(stream); +#elif defined(__MINGW32__) + return ftello64(stream); +#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */ + return ftello(stream); +#endif +} + +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin) +{ +#ifdef _MSC_VER + return _fseeki64(stream, offset, origin); +#elif defined(__MINGW32__) + return fseeko64(stream, offset, origin); +#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */ + return fseeko(stream, offset, origin); +#endif +} + +uint32_t mvhd_crc32_for_byte(uint32_t r) { + for (int j = 0; j < 8; ++j) + r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; + return r ^ (uint32_t)0xFF000000L; +} + +uint32_t mvhd_crc32(const void* data, size_t n_bytes) { + static uint32_t table[0x100]; + if (!*table) + for (size_t i = 0; i < 0x100; ++i) + table[i] = mvhd_crc32_for_byte(i); + + uint32_t crc = 0; + for (size_t i = 0; i < n_bytes; ++i) + crc = table[(uint8_t)crc ^ ((uint8_t*)data)[i]] ^ crc >> 8; + + return crc; +} + +uint32_t mvhd_file_mod_timestamp(const char* path, int *err) { + *err = 0; +#ifdef _WIN32 + struct _stat file_stat; + size_t path_len = strlen(path); + mvhd_utf16 new_path[260] = {0}; + int new_path_len = (sizeof new_path) - 2; + int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); + if (path_res > 0) { + int stat_res = _wstat(new_path, &file_stat); + if (stat_res != 0) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + return 0; + } + return mvhd_epoch_to_vhd_ts(file_stat.st_mtime); + } else { + if (path_res == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (path_res == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } + return 0; + } +#else + struct stat file_stat; + int stat_res = stat(path, &file_stat); + if (stat_res != 0) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + return 0; + } + return mvhd_epoch_to_vhd_ts(file_stat.st_mtime); +#endif +} diff --git a/src/disk/minivhd/minivhd_util.h b/src/disk/minivhd/minivhd_util.h new file mode 100644 index 000000000..227570ce2 --- /dev/null +++ b/src/disk/minivhd/minivhd_util.h @@ -0,0 +1,136 @@ +#ifndef MINIVHD_UTIL_H +#define MINIVHD_UTIL_H + +#include +#include +#include +#include "minivhd_internal.h" +#include "minivhd.h" +#define MVHD_START_TS 946684800 + +/** + * Functions to deal with endian issues + */ +uint16_t mvhd_from_be16(uint16_t val); +uint32_t mvhd_from_be32(uint32_t val); +uint64_t mvhd_from_be64(uint64_t val); +uint16_t mvhd_to_be16(uint16_t val); +uint32_t mvhd_to_be32(uint32_t val); +uint64_t mvhd_to_be64(uint64_t val); + +/** + * \brief Check if provided buffer begins with the string "conectix" + * + * \param [in] buffer The buffer to compare. Must be at least 8 bytes in length + * + * \return true if the buffer begins with "conectix" + * \return false if the buffer does not begin with "conectix" + */ +bool mvhd_is_conectix_str(const void* buffer); + +/** + * \brief Generate a raw 16 byte UUID + * + * \param [out] uuid A 16 byte buffer in which the generated UUID will be stored to + */ +void mvhd_generate_uuid(uint8_t *uuid); + +/** + * \brief Calculate a VHD formatted timestamp from the current time + */ +uint32_t vhd_calc_timestamp(void); + +/** + * \brief Convert an epoch timestamp to a VHD timestamp + * + * \param [in] ts epoch timestamp to convert. + * + * \return The adjusted timestamp, or 0 if the input timestamp is + * earlier that 1 Janurary 2000 + */ +uint32_t mvhd_epoch_to_vhd_ts(time_t ts); + +/** + * \brief Return the created time from a VHD image + * + * \param [in] vhdm Pointer to the MiniVHD metadata structure + * + * \return The created time, as a Unix timestamp + */ +time_t vhd_get_created_time(MVHDMeta *vhdm); + +/** + * \brief Cross platform, unicode filepath opening + * + * This function accounts for the fact that fopen() handles file paths differently compared to other + * operating systems. Windows version of fopen() will not handle multi byte encoded text like UTF-8. + * + * Unicode filepath support on Windows requires using the _wfopen() function, which expects UTF-16LE + * encoded path and modestring. + * + * \param [in] path The filepath to open as a UTF-8 string + * \param [in] mode The mode string to use (eg: "rb+"") + * \param [out] err The error value, if an error occurrs + * + * \return a FILE pointer if successful, NULL otherwise. If NULL, check the value of err + */ +FILE* mvhd_fopen(const char* path, const char* mode, int* err); + +void mvhd_set_encoding_err(int encoding_retval, int* err); +uint64_t mvhd_calc_size_bytes(MVHDGeom *geom); +uint32_t mvhd_calc_size_sectors(MVHDGeom *geom); +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm); + +/** + * \brief Generate VHD footer checksum + * + * \param [in] vhdm MiniVHD data structure + */ +uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer); + +/** + * \brief Generate VHD sparse header checksum + * + * \param [in] vhdm MiniVHD data structure + */ +uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header); + +/** + * \brief Get current position in file stream + * + * This is a portable version of the POSIX ftello64(). * + */ +int64_t mvhd_ftello64(FILE* stream); + +/** + * \brief Reposition the file stream's position + * + * This is a portable version of the POSIX fseeko64(). * + */ +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin); + +/** + * \brief Calculate the CRC32 of a data buffer. + * + * This function can be used for verifying data integrity. + * + * \param [in] data The data buffer + * \param [in] n_bytes The size of the data buffer in bytes + * + * \return The CRC32 of the data buffer + */ +uint32_t mvhd_crc32(const void* data, size_t n_bytes); + +/** + * \brief Calculate the file modification timestamp. + * + * This function is primarily to help protect differencing VHD's + * + * \param [in] path the UTF-8 file path + * \param [out] err The error value, if an error occurrs + * + * \return The file modified timestamp, in VHD compatible timestamp. + * 'err' will be set to non-zero on error + */ +uint32_t mvhd_file_mod_timestamp(const char* path, int *err); +#endif diff --git a/src/disk/mo.c b/src/disk/mo.c index 7df757419..d30cf9d94 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -15,7 +15,9 @@ * Miran Grca, * Fred N. van Kempen, * - * Copyright 2020 Miran Grca. + * Copyright 2020,2021 Natalia Portillo. + * Copyright 2020,2021 Miran Grca. + * Copyright 2020,2021 Fred N. van Kempen */ #include #include @@ -31,11 +33,13 @@ #include <86box/device.h> #include <86box/scsi_device.h> #include <86box/nvr.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/ui.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/mo.h> +#include <86box/version.h> #ifdef _WIN32 #include @@ -101,7 +105,7 @@ const uint8_t mo_command_flags[0x100] = IMPLEMENTED | CHECK_READY, /* 0xA8 */ 0, IMPLEMENTED | CHECK_READY, /* 0xAA */ - 0, + 0, IMPLEMENTED | CHECK_READY | NONDATA, /* 0xAC */ 0, IMPLEMENTED | CHECK_READY, /* 0xAE */ @@ -327,15 +331,28 @@ mo_load_abort(mo_t *dev) int -mo_load(mo_t *dev, wchar_t *fn) +image_is_mdi(const char *s) { - int size = 0; + if (! strcasecmp(path_get_extension((char *) s), "MDI")) + return 1; + else + return 0; +} + + +int +mo_load(mo_t *dev, char *fn) +{ + int is_mdi; + uint32_t size = 0; unsigned int i, found = 0; - dev->drv->f = plat_fopen(fn, dev->drv->read_only ? L"rb" : L"rb+"); + is_mdi = image_is_mdi(fn); + + dev->drv->f = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); if (!dev->drv->f) { if (!dev->drv->read_only) { - dev->drv->f = plat_fopen(fn, L"rb"); + dev->drv->f = plat_fopen(fn, "rb"); if (dev->drv->f) dev->drv->read_only = 1; else @@ -345,25 +362,30 @@ mo_load(mo_t *dev, wchar_t *fn) } fseek(dev->drv->f, 0, SEEK_END); - size = ftell(dev->drv->f); + size = (uint32_t) ftell(dev->drv->f); + + if (is_mdi) { + /* This is a MDI image. */ + size -= 0x1000LL; + dev->drv->base = 0x1000; + } for (i = 0; i < KNOWN_MO_TYPES; i++) { - if (size == mo_types[i].disk_size) { + if (size == (mo_types[i].sectors * mo_types[i].bytes_per_sector)) { found = 1; dev->drv->medium_size = mo_types[i].sectors; dev->drv->sector_size = mo_types[i].bytes_per_sector; break; } } - - if (!found) { + + if (!found) return mo_load_abort(dev); - } if (fseek(dev->drv->f, dev->drv->base, SEEK_SET) == -1) fatal("mo_load(): Error seeking to the beginning of the file\n"); - wcsncpy(dev->drv->image_path, fn, sizeof_w(dev->drv->image_path)); + strncpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path) - 1); return 1; } @@ -374,7 +396,7 @@ mo_disk_reload(mo_t *dev) { int ret = 0; - if (wcslen(dev->drv->prev_image_path) == 0) + if (strlen(dev->drv->prev_image_path) == 0) return; else ret = mo_load(dev, dev->drv->prev_image_path); @@ -507,7 +529,7 @@ static void mo_mode_sense_load(mo_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); if (mo_drives[dev->id].bus_type == MO_BUS_SCSI) @@ -515,12 +537,12 @@ mo_mode_sense_load(mo_t *dev) else memcpy(&dev->ms_pages_saved, &mo_mode_sense_pages_default, sizeof(mode_sense_pages_t)); - memset(file_name, 0, 512 * sizeof(wchar_t)); + memset(file_name, 0, 512); if (dev->drv->bus_type == MO_BUS_SCSI) - swprintf(file_name, 512, L"scsi_mo_%02i_mode_sense_bin", dev->id); + sprintf(file_name, "scsi_mo_%02i_mode_sense_bin", dev->id); else - swprintf(file_name, 512, L"mo_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"rb"); + sprintf(file_name, "mo_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "rb"); if (f) { /* Nothing to read, not used by MO. */ fclose(f); @@ -532,14 +554,14 @@ static void mo_mode_sense_save(mo_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); + memset(file_name, 0, 512); if (dev->drv->bus_type == MO_BUS_SCSI) - swprintf(file_name, 512, L"scsi_mo_%02i_mode_sense_bin", dev->id); + sprintf(file_name, "scsi_mo_%02i_mode_sense_bin", dev->id); else - swprintf(file_name, 512, L"mo_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"wb"); + sprintf(file_name, "mo_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "wb"); if (f) { /* Nothing to write, not used by MO. */ fclose(f); @@ -810,12 +832,13 @@ mo_sense_clear(mo_t *dev, int command) static void mo_set_phase(mo_t *dev, uint8_t phase) { - uint8_t scsi_id = dev->drv->scsi_device_id; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type != MO_BUS_SCSI) return; - scsi_devices[scsi_id].phase = phase; + scsi_devices[scsi_bus][scsi_id].phase = phase; } @@ -1022,6 +1045,7 @@ mo_format(mo_t *dev) fseek(dev->drv->f, 0, SEEK_END); size = ftell(dev->drv->f); +#ifdef _WIN32 HANDLE fh; LARGE_INTEGER liSize; @@ -1032,14 +1056,14 @@ mo_format(mo_t *dev) ret = (int)SetFilePointerEx(fh, liSize, NULL, FILE_BEGIN); - if (!ret) { + if(!ret) { mo_log("MO %i: Failed seek to start of image file\n", dev->id); return; } ret = (int)SetEndOfFile(fh); - if (!ret) { + if(!ret) { mo_log("MO %i: Failed to truncate image file to 0\n", dev->id); return; } @@ -1047,17 +1071,34 @@ mo_format(mo_t *dev) liSize.QuadPart = size; ret = (int)SetFilePointerEx(fh, liSize, NULL, FILE_BEGIN); - if (!ret) { + if(!ret) { mo_log("MO %i: Failed seek to end of image file\n", dev->id); return; } ret = (int)SetEndOfFile(fh); - if (!ret) { + if(!ret) { mo_log("MO %i: Failed to truncate image file to %llu\n", dev->id, size); return; } +#else + fd = fileno(dev->drv->f); + + ret = ftruncate(fd, 0); + + if(ret) { + mo_log("MO %i: Failed to truncate image file to 0\n", dev->id); + return; + } + + ret = ftruncate(fd, size); + + if(ret) { + mo_log("MO %i: Failed to truncate image file to %llu", dev->id, size); + return; + } +#endif } static int @@ -1101,7 +1142,7 @@ mo_erase(mo_t *dev) /*SCSI Sense Initialization*/ void mo_sense_code_ok(mo_t *dev) -{ +{ mo_sense_key = SENSE_NONE; mo_asc = 0; mo_ascq = 0; @@ -1114,7 +1155,7 @@ mo_pre_execution_check(mo_t *dev, uint8_t *cdb) int ready = 0; if (dev->drv->bus_type == MO_BUS_SCSI) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { mo_log("MO %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); mo_invalid_lun(dev); return 0; @@ -1214,12 +1255,13 @@ mo_reset(scsi_common_t *sc) dev->request_length = 0xEB14; dev->packet_status = PHASE_NONE; dev->unit_attention = 0; + dev->cur_lun = SCSI_LUN_USE_CDB; } static void mo_request_sense(mo_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) -{ +{ /*Will return 18 bytes of 0*/ if (alloc_length != 0) { memset(buffer, 0, alloc_length); @@ -1299,12 +1341,15 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) int32_t alloc_length; int size_idx, idx = 0; unsigned preamble_len; + char device_identify[9] = { '8', '6', 'B', '_', 'M', 'O', '0', '0', 0 }; int32_t blen = 0; int32_t *BufLen; uint32_t previous_pos = 0; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type == MO_BUS_SCSI) { - BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; dev->status &= ~ERR_STAT; } else { BufLen = &blen; @@ -1314,6 +1359,8 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; + device_identify[7] = dev->id + 0x30; + memcpy(dev->current_cdb, cdb, 12); if (cdb[0] != 0) { @@ -1481,7 +1528,7 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) /*TODO: Implement*/ mo_invalid_field(dev); return; - + case GPCMD_WRITE_6: case GPCMD_WRITE_10: case GPCMD_WRITE_AND_VERIFY_10: @@ -1700,9 +1747,15 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) } dev->buffer[7] |= 0x02; - ide_padstr8(dev->buffer + 8, 8, mo_drive_types[dev->drv->type].vendor); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, mo_drive_types[dev->drv->type].model); /* Product */ - ide_padstr8(dev->buffer + 32, 4, mo_drive_types[dev->drv->type].revision); /* Revision */ + if (dev->drv->type > 0) { + ide_padstr8(dev->buffer + 8, 8, mo_drive_types[dev->drv->type].vendor); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, mo_drive_types[dev->drv->type].model); /* Product */ + ide_padstr8(dev->buffer + 32, 4, mo_drive_types[dev->drv->type].revision); /* Revision */ + } else { + ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ + } idx = 36; if (max_len == 96) { @@ -1852,8 +1905,8 @@ mo_phase_data_out(scsi_common_t *sc) { mo_t *dev = (mo_t *) sc; - uint16_t block_desc_len; - uint16_t pos; + uint16_t block_desc_len, pos; + uint16_t param_list_len; uint8_t error = 0; uint8_t page, page_len; @@ -1879,10 +1932,15 @@ mo_phase_data_out(scsi_common_t *sc) break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) { hdr_len = 8; - else + param_list_len = dev->current_cdb[7]; + param_list_len <<= 8; + param_list_len |= dev->current_cdb[8]; + } else { hdr_len = 4; + param_list_len = dev->current_cdb[4]; + } if (dev->drv->bus_type == MO_BUS_SCSI) { if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { @@ -1900,7 +1958,7 @@ mo_phase_data_out(scsi_common_t *sc) pos = hdr_len + block_desc_len; while(1) { - if (pos >= dev->current_cdb[4]) { + if (pos >= param_list_len) { mo_log("MO %i: Buffer has only block descriptor\n", dev->id); break; } @@ -1978,7 +2036,7 @@ mo_get_max(int ide_has_dma, int type) ret = ide_has_dma ? 1 : -1; break; case TYPE_UDMA: - ret = ide_has_dma ? 4 /*2*/ : -1; + ret = ide_has_dma ? 5 : -1; break; } @@ -2013,17 +2071,24 @@ static void mo_do_identify(ide_t *ide, int ide_has_dma) { char model[40]; - mo_t* mo = (mo_t*)ide->sc; + + mo_t* mo = (mo_t*) ide->sc; memset(model, 0, 40); - snprintf(model, 40, "%s %s", mo_drive_types[mo_drives[mo->id].type].vendor, mo_drive_types[mo_drives[mo->id].type].model); - ide_padstr((char *) (ide->buffer + 23), mo_drive_types[mo_drives[mo->id].type].revision, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ + if (mo_drives[mo->id].type > 0) { + snprintf(model, 40, "%s %s", mo_drive_types[mo_drives[mo->id].type].vendor, mo_drive_types[mo_drives[mo->id].type].model); + ide_padstr((char *) (ide->buffer + 23), mo_drive_types[mo_drives[mo->id].type].revision, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ + } else { + snprintf(model, 40, "%s %s%02i", EMU_NAME, "86B_MO", mo->id); + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ + } if (ide_has_dma) { - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + ide->buffer[80] = 0x70; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6*/ + ide->buffer[81] = 0x19; /*Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a*/ } } @@ -2045,6 +2110,8 @@ mo_drive_reset(int c) mo_t *dev; scsi_device_t *sd; ide_t *id; + uint8_t scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = mo_drives[c].scsi_device_id & 0x0f; if (!mo_drives[c].priv) { mo_drives[c].priv = (mo_t *) malloc(sizeof(mo_t)); @@ -2054,10 +2121,11 @@ mo_drive_reset(int c) dev = (mo_t *) mo_drives[c].priv; dev->id = c; + dev->cur_lun = SCSI_LUN_USE_CDB; if (mo_drives[c].bus_type == MO_BUS_SCSI) { /* SCSI MO, attach to the SCSI bus. */ - sd = &scsi_devices[mo_drives[c].scsi_device_id]; + sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = mo_command; @@ -2096,14 +2164,24 @@ mo_hard_reset(void) { mo_t *dev; int c; + uint8_t scsi_id, scsi_bus; for (c = 0; c < MO_NUM; c++) { if ((mo_drives[c].bus_type == MO_BUS_ATAPI) || (mo_drives[c].bus_type == MO_BUS_SCSI)) { mo_log("MO hard_reset drive=%d\n", c); - /* Make sure to ignore any SCSI MO drive that has an out of range ID. */ - if ((mo_drives[c].bus_type == MO_BUS_SCSI) && (mo_drives[c].scsi_device_id >= SCSI_ID_MAX)) - continue; + if (mo_drives[c].bus_type == MO_BUS_SCSI) { + scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; + scsi_id = mo_drives[c].scsi_device_id & 0x0f; + + /* Make sure to ignore any SCSI MO drive that has an out of range SCSI Bus. */ + if (scsi_bus >= SCSI_BUS_MAX) + continue; + + /* Make sure to ignore any SCSI MO drive that has an out of range ID. */ + if (scsi_id >= SCSI_ID_MAX) + continue; + } /* Make sure to ignore any ATAPI MO drive that has an out of range IDE channel. */ if ((mo_drives[c].bus_type == MO_BUS_ATAPI) && (mo_drives[c].ide_channel > 7)) @@ -2118,7 +2196,7 @@ mo_hard_reset(void) mo_init(dev); - if (wcslen(mo_drives[c].image_path)) + if (strlen(mo_drives[c].image_path)) mo_load(dev, mo_drives[c].image_path); mo_mode_sense_load(dev); @@ -2137,10 +2215,15 @@ mo_close(void) { mo_t *dev; int c; + uint8_t scsi_id, scsi_bus; for (c = 0; c < MO_NUM; c++) { - if (mo_drives[c].bus_type == MO_BUS_SCSI) - memset(&scsi_devices[mo_drives[c].scsi_device_id], 0x00, sizeof(scsi_device_t)); + if (mo_drives[c].bus_type == MO_BUS_SCSI) { + scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; + scsi_id = mo_drives[c].scsi_device_id & 0x0f; + + memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); + } dev = (mo_t *) mo_drives[c].priv; diff --git a/src/disk/zip.c b/src/disk/zip.c index d1f89fff6..1f45e4737 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -484,14 +484,14 @@ zip_load_abort(zip_t *dev) int -zip_load(zip_t *dev, wchar_t *fn) +zip_load(zip_t *dev, char *fn) { int size = 0; - dev->drv->f = plat_fopen(fn, dev->drv->read_only ? L"rb" : L"rb+"); + dev->drv->f = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); if (!dev->drv->f) { if (!dev->drv->read_only) { - dev->drv->f = plat_fopen(fn, L"rb"); + dev->drv->f = plat_fopen(fn, "rb"); if (dev->drv->f) dev->drv->read_only = 1; else @@ -529,7 +529,7 @@ zip_load(zip_t *dev, wchar_t *fn) if (fseek(dev->drv->f, dev->drv->base, SEEK_SET) == -1) fatal("zip_load(): Error seeking to the beginning of the file\n"); - wcsncpy(dev->drv->image_path, fn, sizeof_w(dev->drv->image_path)); + strncpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path) - 1); return 1; } @@ -540,7 +540,7 @@ zip_disk_reload(zip_t *dev) { int ret = 0; - if (wcslen(dev->drv->prev_image_path) == 0) + if (strlen(dev->drv->prev_image_path) == 0) return; else ret = zip_load(dev, dev->drv->prev_image_path); @@ -673,7 +673,7 @@ static void zip_mode_sense_load(zip_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); if (dev->drv->is_250) { @@ -688,12 +688,12 @@ zip_mode_sense_load(zip_t *dev) memcpy(&dev->ms_pages_saved, &zip_mode_sense_pages_default, sizeof(mode_sense_pages_t)); } - memset(file_name, 0, 512 * sizeof(wchar_t)); + memset(file_name, 0, 512); if (dev->drv->bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", dev->id); + sprintf(file_name, "scsi_zip_%02i_mode_sense_bin", dev->id); else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"rb"); + sprintf(file_name, "zip_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "rb"); if (f) { /* Nothing to read, not used by ZIP. */ fclose(f); @@ -705,14 +705,14 @@ static void zip_mode_sense_save(zip_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); + memset(file_name, 0, 512); if (dev->drv->bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", dev->id); + sprintf(file_name, "scsi_zip_%02i_mode_sense_bin", dev->id); else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"wb"); + sprintf(file_name, "zip_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "wb"); if (f) { /* Nothing to write, not used by ZIP. */ fclose(f); @@ -1000,12 +1000,13 @@ zip_sense_clear(zip_t *dev, int command) static void zip_set_phase(zip_t *dev, uint8_t phase) { - uint8_t scsi_id = dev->drv->scsi_device_id; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type != ZIP_BUS_SCSI) return; - scsi_devices[scsi_id].phase = phase; + scsi_devices[scsi_bus][scsi_id].phase = phase; } @@ -1214,7 +1215,7 @@ zip_insert(zip_t *dev) /*SCSI Sense Initialization*/ void zip_sense_code_ok(zip_t *dev) -{ +{ zip_sense_key = SENSE_NONE; zip_asc = 0; zip_ascq = 0; @@ -1227,7 +1228,7 @@ zip_pre_execution_check(zip_t *dev, uint8_t *cdb) int ready = 0; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); zip_invalid_lun(dev); return 0; @@ -1327,12 +1328,13 @@ zip_reset(scsi_common_t *sc) dev->request_length = 0xEB14; dev->packet_status = PHASE_NONE; dev->unit_attention = 0; + dev->cur_lun = SCSI_LUN_USE_CDB; } static void zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) -{ +{ /*Will return 18 bytes of 0*/ if (alloc_length != 0) { memset(buffer, 0, alloc_length); @@ -1415,9 +1417,11 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) unsigned preamble_len; int32_t blen = 0; int32_t *BufLen; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; dev->status &= ~ERR_STAT; } else { BufLen = &blen; @@ -2081,8 +2085,8 @@ zip_phase_data_out(scsi_common_t *sc) { zip_t *dev = (zip_t *) sc; - uint16_t block_desc_len; - uint16_t pos; + uint16_t block_desc_len, pos; + uint16_t param_list_len; uint8_t error = 0; uint8_t page, page_len; @@ -2143,10 +2147,15 @@ zip_phase_data_out(scsi_common_t *sc) break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) { hdr_len = 8; - else + param_list_len = dev->current_cdb[7]; + param_list_len <<= 8; + param_list_len |= dev->current_cdb[8]; + } else { hdr_len = 4; + param_list_len = dev->current_cdb[4]; + } if (dev->drv->bus_type == ZIP_BUS_SCSI) { if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { @@ -2164,7 +2173,7 @@ zip_phase_data_out(scsi_common_t *sc) pos = hdr_len + block_desc_len; while(1) { - if (pos >= dev->current_cdb[4]) { + if (pos >= param_list_len) { zip_log("ZIP %i: Buffer has only block descriptor\n", dev->id); break; } @@ -2242,7 +2251,7 @@ zip_get_max(int ide_has_dma, int type) ret = ide_has_dma ? 1 : -1; break; case TYPE_UDMA: - ret = ide_has_dma ? 4 /*2*/ : -1; + ret = ide_has_dma ? 5 : -1; break; } @@ -2289,8 +2298,8 @@ zip_250_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ if (ide_has_dma) { - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + ide->buffer[80] = 0x70; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6*/ + ide->buffer[81] = 0x19; /*Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a*/ } } @@ -2324,6 +2333,8 @@ zip_drive_reset(int c) zip_t *dev; scsi_device_t *sd; ide_t *id; + uint8_t scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = zip_drives[c].scsi_device_id & 0x0f; if (!zip_drives[c].priv) { zip_drives[c].priv = (zip_t *) malloc(sizeof(zip_t)); @@ -2333,10 +2344,11 @@ zip_drive_reset(int c) dev = (zip_t *) zip_drives[c].priv; dev->id = c; + dev->cur_lun = SCSI_LUN_USE_CDB; if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { /* SCSI ZIP, attach to the SCSI bus. */ - sd = &scsi_devices[zip_drives[c].scsi_device_id]; + sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = zip_command; @@ -2375,14 +2387,24 @@ zip_hard_reset(void) { zip_t *dev; int c; + uint8_t scsi_id, scsi_bus; for (c = 0; c < ZIP_NUM; c++) { if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) || (zip_drives[c].bus_type == ZIP_BUS_SCSI)) { zip_log("ZIP hard_reset drive=%d\n", c); - /* Make sure to ignore any SCSI ZIP drive that has an out of range ID. */ - if ((zip_drives[c].bus_type == ZIP_BUS_SCSI) && (zip_drives[c].scsi_device_id >= SCSI_ID_MAX)) - continue; + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { + scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; + scsi_id = zip_drives[c].scsi_device_id & 0x0f; + + /* Make sure to ignore any SCSI ZIP drive that has an out of range SCSI bus. */ + if (scsi_bus >= SCSI_BUS_MAX) + continue; + + /* Make sure to ignore any SCSI ZIP drive that has an out of range ID. */ + if (scsi_id >= SCSI_ID_MAX) + continue; + } /* Make sure to ignore any ATAPI ZIP drive that has an out of range IDE channel. */ if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) && (zip_drives[c].ide_channel > 7)) @@ -2397,7 +2419,7 @@ zip_hard_reset(void) zip_init(dev); - if (wcslen(zip_drives[c].image_path)) + if (strlen(zip_drives[c].image_path)) zip_load(dev, zip_drives[c].image_path); zip_mode_sense_load(dev); @@ -2416,10 +2438,15 @@ zip_close(void) { zip_t *dev; int c; + uint8_t scsi_bus, scsi_id; for (c = 0; c < ZIP_NUM; c++) { - if (zip_drives[c].bus_type == ZIP_BUS_SCSI) - memset(&scsi_devices[zip_drives[c].scsi_device_id], 0x00, sizeof(scsi_device_t)); + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { + scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; + scsi_id = zip_drives[c].scsi_device_id & 0x0f; + + memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); + } dev = (zip_t *) zip_drives[c].priv; diff --git a/src/dma.c b/src/dma.c index bbfdf2118..5eb129860 100644 --- a/src/dma.c +++ b/src/dma.c @@ -35,23 +35,24 @@ dma_t dma[8]; uint8_t dma_e; +uint8_t dma_m; static uint8_t dmaregs[3][16]; static int dma_wp[2]; -static uint8_t dma_m; static uint8_t dma_stat; static uint8_t dma_stat_rq; static uint8_t dma_stat_rq_pc; static uint8_t dma_command[2]; static uint8_t dma_req_is_soft; static uint8_t dma_advanced; +static uint8_t dma_at; static uint8_t dma_buffer[65536]; static uint16_t dma_sg_base; static uint16_t dma16_buffer[65536]; static uint32_t dma_mask; -static struct { +static struct { int xfr_command, xfr_channel; int byte_ptr; @@ -61,6 +62,7 @@ static struct { #define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_AUTOINIT (1 << 1) #define DMA_PS2_XFER_MEM_TO_IO (1 << 2) #define DMA_PS2_XFER_IO_TO_MEM (3 << 2) #define DMA_PS2_XFER_MASK (3 << 2) @@ -166,6 +168,28 @@ dma_block_transfer(int channel) } +static void +dma_mem_to_mem_transfer(void) +{ + int i; + + if ((dma[0].mode & 0x0c) != 0x08) + fatal("DMA memory to memory transfer: channel 0 mode not read\n"); + if ((dma[1].mode & 0x0c) != 0x04) + fatal("DMA memory to memory transfer: channel 1 mode not write\n"); + + dma_req_is_soft = 1; + + for (i = 0; i <= dma[0].cb; i++) + dma_buffer[i] = dma_channel_read(0); + + for (i = 0; i <= dma[1].cb; i++) + dma_channel_write(1, dma_buffer[i]); + + dma_req_is_soft = 0; +} + + static void dma_sg_write(uint16_t port, uint8_t val, void *priv) { @@ -485,9 +509,9 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 6: /*Address registers*/ dma_wp[0] ^= 1; if (dma_wp[0]) - dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + dma[channel].ab = (dma[channel].ab & 0xffffff00 & dma_mask) | val; else - dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ab = (dma[channel].ab & 0xffff00ff & dma_mask) | (val << 8); dma[channel].ac = dma[channel].ab; return; @@ -506,14 +530,18 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 8: /*Control register*/ dma_command[0] = val; if (val & 0x01) - fatal("Memory-to-memory enable\n"); + pclog("[%08X:%04X] Memory-to-memory enable\n", CS, cpu_state.pc); return; case 9: /*Request register */ channel = (val & 3); if (val & 4) { dma_stat_rq_pc |= (1 << channel); - dma_block_transfer(channel); + if ((channel == 0) && (dma_command[0] & 0x01)) { + pclog("Memory to memory transfer start\n"); + dma_mem_to_mem_transfer(); + } else + dma_block_transfer(channel); } else dma_stat_rq_pc &= ~(1 << channel); break; @@ -595,7 +623,7 @@ dma_ps2_read(uint16_t addr, void *priv) else temp = dma_c->cc & 0xff; dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; + break; case 6: /*Read DMA status*/ if (dma_ps2.byte_ptr) { @@ -623,7 +651,6 @@ dma_ps2_read(uint16_t addr, void *priv) } break; } - return(temp); } @@ -692,7 +719,7 @@ dma_ps2_write(uint16_t addr, uint8_t val, void *priv) dma_c->cc = (dma_c->cc & 0xff00) | val; dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; dma_c->cb = dma_c->cc; - break; + break; case 7: /*Mode register*/ mode = 0; @@ -700,9 +727,11 @@ dma_ps2_write(uint16_t addr, uint8_t val, void *priv) mode |= 0x20; if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) mode |= 8; - else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) mode |= 4; dma_c->mode = (dma_c->mode & ~0x2c) | mode; + if (val & DMA_PS2_AUTOINIT) + dma_c->mode |= 0x10; dma_c->ps2_mode = val; dma_c->size = val & DMA_PS2_SIZE16; break; @@ -733,11 +762,11 @@ dma16_read(uint16_t addr, void *priv) case 6: /*Address registers*/ dma_wp[1] ^= 1; if (dma_ps2.is_ps2) { - if (dma_wp[1]) + if (dma_wp[1]) return(dma[channel].ac); return((dma[channel].ac >> 8) & 0xff); } - if (dma_wp[1]) + if (dma_wp[1]) return((dma[channel].ac >> 1) & 0xff); return((dma[channel].ac >> 9) & 0xff); @@ -778,14 +807,14 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) dma_wp[1] ^= 1; if (dma_ps2.is_ps2) { if (dma_wp[1]) - dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + dma[channel].ab = (dma[channel].ab & 0xffffff00 & dma_mask) | val; else - dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ab = (dma[channel].ab & 0xffff00ff & dma_mask) | (val << 8); } else { if (dma_wp[1]) - dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + dma[channel].ab = (dma[channel].ab & 0xfffffe00 & dma_mask) | (val << 1); else - dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); + dma[channel].ab = (dma[channel].ab & 0xfffe01ff & dma_mask) | (val << 9); } dma[channel].ac = dma[channel].ab; return; @@ -865,6 +894,11 @@ dma_page_write(uint16_t addr, uint8_t val, void *priv) { uint8_t convert[8] = CHANNELS; +#ifdef USE_DYNAREC + if ((addr == 0x84) && cpu_use_dynarec) + update_tsc(); +#endif + addr &= 0x0f; dmaregs[2][addr] = val; @@ -878,12 +912,12 @@ dma_page_write(uint16_t addr, uint8_t val, void *priv) if (addr > 4) { dma[addr].page = val & 0xfe; - dma[addr].ab = (dma[addr].ab & 0x1ffff) | (dma[addr].page << 16); - dma[addr].ac = (dma[addr].ac & 0x1ffff) | (dma[addr].page << 16); + dma[addr].ab = (dma[addr].ab & 0xff01ffff & dma_mask) | (dma[addr].page << 16); + dma[addr].ac = (dma[addr].ac & 0xff01ffff & dma_mask) | (dma[addr].page << 16); } else { - dma[addr].page = (AT) ? val : val & 0xf; - dma[addr].ab = (dma[addr].ab & 0xffff) | (dma[addr].page << 16); - dma[addr].ac = (dma[addr].ac & 0xffff) | (dma[addr].page << 16); + dma[addr].page = (dma_at) ? val : val & 0xf; + dma[addr].ab = (dma[addr].ab & 0xff00ffff & dma_mask) | (dma[addr].page << 16); + dma[addr].ac = (dma[addr].ac & 0xff00ffff & dma_mask) | (dma[addr].page << 16); } } } @@ -959,6 +993,27 @@ dma_set_params(uint8_t advanced, uint32_t mask) } +void +dma_set_mask(uint32_t mask) +{ + int i; + + dma_mask = mask; + + for (i = 0; i < 8; i++) { + dma[i].ab &= mask; + dma[i].ac &= mask; + } +} + + +void +dma_set_at(uint8_t at) +{ + dma_at = at; +} + + void dma_reset(void) { @@ -991,6 +1046,8 @@ dma_reset(void) dma_sg_base = 0x0400; dma_mask = 0x00ffffff; + + dma_at = is286; } @@ -1267,7 +1324,8 @@ _dma_write(uint32_t addr, uint8_t val, dma_t *dma_c) dma_bm_write(addr, &val, 1, dma_transfer_size(dma_c)); } else { mem_writeb_phys(addr, val); - mem_invalidate_range(addr, addr); + if (dma_at) + mem_invalidate_range(addr, addr); } } @@ -1282,7 +1340,7 @@ _dma_writew(uint32_t addr, uint16_t val, dma_t *dma_c) dma_bm_write(addr, (uint8_t *) &val, 2, dma_transfer_size(dma_c)); } else { _dma_write(addr, val & 0xff, dma_c); - _dma_write(addr + 1, val >> 8, dma_c); + _dma_write(addr + 1, val >> 8, dma_c); } } @@ -1343,7 +1401,7 @@ dma_channel_read(int channel) if ((dma_c->mode & 0xC) != 8) return(DMA_NODATA); - if (!AT && !channel) + if (!dma_at && !channel) refreshread(); if (! dma_c->size) { @@ -1355,14 +1413,14 @@ dma_channel_read(int channel) else if (dma_advanced) dma_retreat(dma_c); else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xffff0000 & dma_mask) | ((dma_c->ac - 1) & 0xffff); } else { if (dma_ps2.is_ps2) dma_c->ac++; else if (dma_advanced) dma_advance(dma_c); else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xffff0000 & dma_mask) | ((dma_c->ac + 1) & 0xffff); } } else { temp = _dma_readw(dma_c->ac, dma_c); @@ -1373,14 +1431,14 @@ dma_channel_read(int channel) else if (dma_advanced) dma_retreat(dma_c); else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfffe0000 & dma_mask) | ((dma_c->ac - 2) & 0x1ffff); } else { if (dma_ps2.is_ps2) dma_c->ac += 2; else if (dma_advanced) dma_advance(dma_c); else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfffe0000 & dma_mask) | ((dma_c->ac + 2) & 0x1ffff); } } @@ -1443,14 +1501,14 @@ dma_channel_write(int channel, uint16_t val) else if (dma_advanced) dma_retreat(dma_c); else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xffff0000 & dma_mask) | ((dma_c->ac - 1) & 0xffff); } else { if (dma_ps2.is_ps2) dma_c->ac++; else if (dma_advanced) dma_advance(dma_c); else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xffff0000 & dma_mask) | ((dma_c->ac + 1) & 0xffff); } } else { _dma_writew(dma_c->ac, val, dma_c); @@ -1461,15 +1519,15 @@ dma_channel_write(int channel, uint16_t val) else if (dma_advanced) dma_retreat(dma_c); else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfffe0000 & dma_mask) | ((dma_c->ac - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfffe0000 & dma_mask) | ((dma_c->ac - 2) & 0x1ffff); } else { if (dma_ps2.is_ps2) dma_c->ac += 2; else if (dma_advanced) dma_advance(dma_c); else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfffe0000 & dma_mask) | ((dma_c->ac + 2) & 0x1ffff); } } @@ -1644,4 +1702,7 @@ dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, memcpy(bytes, (void *) &(DataWrite[n]), n2); mem_write_phys((void *) bytes, PhysAddress + n, TransferSize); } + + if (dma_at) + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); } diff --git a/src/fifo8.c b/src/fifo8.c new file mode 100644 index 000000000..a6f7f1e0e --- /dev/null +++ b/src/fifo8.c @@ -0,0 +1,115 @@ +/* + * Generic FIFO component, implemented as a circular buffer. + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/fifo8.h> + +void fifo8_create(Fifo8 *fifo, uint32_t capacity) +{ + fifo->data = (uint8_t *)malloc(capacity); + memset(fifo->data, 0, capacity); + fifo->capacity = capacity; + fifo->head = 0; + fifo->num = 0; +} + +void fifo8_destroy(Fifo8 *fifo) +{ + if (fifo->data) { + free(fifo->data); + fifo->data = NULL; + } +} + +void fifo8_push(Fifo8 *fifo, uint8_t data) +{ + assert(fifo->num < fifo->capacity); + fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; + fifo->num++; +} + +void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num) +{ + uint32_t start, avail; + + assert(fifo->num + num <= fifo->capacity); + + start = (fifo->head + fifo->num) % fifo->capacity; + + if (start + num <= fifo->capacity) { + memcpy(&fifo->data[start], data, num); + } else { + avail = fifo->capacity - start; + memcpy(&fifo->data[start], data, avail); + memcpy(&fifo->data[0], &data[avail], num - avail); + } + + fifo->num += num; +} + +uint8_t fifo8_pop(Fifo8 *fifo) +{ + uint8_t ret; + + assert(fifo->num > 0); + ret = fifo->data[fifo->head++]; + fifo->head %= fifo->capacity; + fifo->num--; + return ret; +} + +const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num) +{ + uint8_t *ret; + + assert(max > 0 && max <= fifo->num); + *num = MIN(fifo->capacity - fifo->head, max); + ret = &fifo->data[fifo->head]; + fifo->head += *num; + fifo->head %= fifo->capacity; + fifo->num -= *num; + return ret; +} + +void fifo8_reset(Fifo8 *fifo) +{ + fifo->num = 0; + fifo->head = 0; +} + +int fifo8_is_empty(Fifo8 *fifo) +{ + return (fifo->num == 0); +} + +int fifo8_is_full(Fifo8 *fifo) +{ + return (fifo->num == fifo->capacity); +} + +uint32_t fifo8_num_free(Fifo8 *fifo) +{ + return fifo->capacity - fifo->num; +} + +uint32_t fifo8_num_used(Fifo8 *fifo) +{ + return fifo->num; +} diff --git a/src/floppy/CMakeLists.txt b/src/floppy/CMakeLists.txt new file mode 100644 index 000000000..a30bebd71 --- /dev/null +++ b/src/floppy/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(fdd OBJECT fdd.c fdc.c fdc_magitronic.c fdc_pii15xb.c fdi2raw.c fdd_common.c + fdd_86f.c fdd_fdi.c fdd_imd.c fdd_img.c fdd_json.c fdd_mfm.c fdd_td0.c) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 44bea7b25..a1165f14b 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -41,7 +41,7 @@ extern uint64_t motoron[FDD_NUM]; -const int command_has_drivesel[256] = { +const uint8_t command_has_drivesel[32] = { 0, 0, 1, /* READ TRACK */ 0, @@ -61,24 +61,11 @@ const int command_has_drivesel[256] = { 1, /* SCAN EQUAL */ 0, 0, 0, 0, 1, /* VERIFY */ - 0, 0, 0, + 0, 0, 1, /* SCAN LOW OR EQUAL */ 0, 0, 0, 1, /* SCAN HIGH OR EQUAL */ - 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0 }; @@ -114,20 +101,37 @@ fdc_log(const char *fmt, ...) #endif +const device_t fdc_internal_device = { + .name = "Internal", + .internal_name = "internal", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + + typedef const struct { - const char *name; - const char *internal_name; const device_t *device; } fdc_cards_t; /* All emulated machines have at least one integrated FDC controller */ static fdc_cards_t fdc_cards[] = { - { "Internal controller", "internal", NULL, }, - { "DTK PII-151B", "dtk_pii151b", &fdc_pii151b_device, }, - { "DTK PII-158B", "dtk_pii158b", &fdc_pii158b_device, }, - { "", "", NULL, }, +// clang-format off + { &fdc_internal_device }, + { &fdc_b215_device }, + { &fdc_pii151b_device }, + { &fdc_pii158b_device }, + { NULL } +// clang-format on }; + int fdc_card_available(int card) { @@ -138,13 +142,6 @@ fdc_card_available(int card) } -char * -fdc_card_getname(int card) -{ - return((char *) fdc_cards[card].name); -} - - const device_t * fdc_card_getdevice(int card) { @@ -157,14 +154,14 @@ fdc_card_has_config(int card) { if (! fdc_cards[card].device) return(0); - return(fdc_cards[card].device->config ? 1 : 0); + return(device_has_config(fdc_cards[card].device) ? 1 : 0); } char * fdc_card_get_internal_name(int card) { - return((char *) fdc_cards[card].internal_name); + return device_get_internal_name(fdc_cards[card].device); } @@ -173,12 +170,12 @@ fdc_card_get_from_internal_name(char *s) { int c = 0; - while (strlen((char *) fdc_cards[c].internal_name)) { - if (!strcmp((char *) fdc_cards[c].internal_name, s)) + while (fdc_cards[c].device != NULL) { + if (!strcmp((char *) fdc_cards[c].device->internal_name, s)) return(c); c++; } - + return(0); } @@ -210,7 +207,6 @@ fdc_ctrl_reset(void *p) fdc->st0 = 0; fdc->lock = 0; fdc->head = 0; - fdc->abort = 0; fdc->step = 0; if (!(fdc->flags & FDC_FLAG_AT)) fdc->rate = 2; @@ -318,8 +314,10 @@ fdc_request_next_sector_id(fdc_t *fdc) { if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat = 0xf0; - else + else { + dma_set_drq(fdc->dma_ch, 1); fdc->stat = 0xd0; + } } @@ -636,8 +634,10 @@ static void fdc_rate(fdc_t *fdc, int drive) { fdc_update_rate(fdc, drive); - fdc_log("FDD %c: Setting rate: %i, %i, %i (%i, %i)\n", 0x41 + drive, fdc->drvrate[drive], fdc->rate, fdc_get_densel(fdc, drive), fdc->rwc[drive], fdc->densel_force); + // fdc_log("FDD %c: Setting rate: %i, %i, %i (%i, %i)\n", 0x41 + drive, fdc->drvrate[drive], fdc->rate, fdc_get_densel(fdc, drive), fdc->rwc[drive], fdc->densel_force); + fdc_log("FDD %c: [%i] Setting rate: %i, %i, %i (%i, %i, %i)\n", 0x41 + drive, fdc->enh_mode, fdc->drvrate[drive], fdc->rate, fdc_get_densel(fdc, drive), fdc->rwc[drive], fdc->densel_force, fdc->densel_polarity); fdd_set_densel(fdc_get_densel(fdc, drive)); + fdc_log("FDD %c: [%i] Densel: %i\n", 0x41 + drive, fdc->enh_mode, fdc_get_densel(fdc, drive)); } @@ -659,18 +659,6 @@ fdc_seek(fdc_t *fdc, int drive, int params) } -void -fdc_implied_seek(fdc_t *fdc) -{ - if (fdc->config & 0x40) { - if (fdc->params[1] != fdc->pcn[fdc->params[0] & 3]) { - fdc_seek(fdc, fdc->drive, ((int) fdc->params[1]) - ((int) fdc->pcn[fdc->params[0] & 3])); - fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - } - } -} - - static void fdc_bad_command(fdc_t *fdc) { @@ -683,6 +671,17 @@ fdc_bad_command(fdc_t *fdc) static void fdc_io_command_phase1(fdc_t *fdc, int out) { +#if 0 + int i; + + pclog_toggle_suppr(); + pclog("%02X ", fdc->processed_cmd); + for (i = 0; i < fdc->pnum; i++) + pclog("%02X ", fdc->params[i]); + pclog("\n"); + pclog_toggle_suppr(); +#endif + fdc_reset_fifo_buf(fdc); fdc_rate(fdc, fdc->drive); fdc->head = fdc->params[2]; @@ -691,16 +690,24 @@ fdc_io_command_phase1(fdc_t *fdc, int out) fdc->eot[fdc->drive] = fdc->params[5]; fdc->gap = fdc->params[6]; fdc->dtl = fdc->params[7]; - fdc_implied_seek(fdc); fdc->rw_track = fdc->params[1]; + + if (fdc->config & 0x40) { + if (fdc->rw_track != fdc->pcn[fdc->params[0] & 3]) { + fdc_seek(fdc, fdc->drive, ((int) fdc->rw_track) - ((int) fdc->pcn[fdc->params[0] & 3])); + fdc->pcn[fdc->params[0] & 3] = fdc->rw_track; + } + } + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); fdc->stat = out ? 0x90 : 0x50; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat |= 0x20; - if (out) { - fdc->written = 0; + else + dma_set_drq(fdc->dma_ch, 1); + if (out) fdc->pos = 0; - } else + else fdc->inread = 1; } @@ -724,7 +731,7 @@ fdc_sis(fdc_t *fdc) fdc->reset_stat--; } else { if (fdc->fintr) { - fdc->res[9] = (fdc->st0 & ~0x04) | (fdd_get_head(fdc->drive & 0x03) ? 4 : 0); + fdc->res[9] = (fdc->st0 & ~0x04) | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0); fdc->fintr = 0; } else { fdc->res[10] = 0x80; @@ -749,7 +756,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Write FDC %04X %02X\n", addr, val); - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr&7) { case 0: @@ -805,11 +812,9 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } drive_num = real_drive(fdc, val & 0x03); current_drive = drive_num; - fdc->st0 &= ~0x07; - fdc->st0 |= real_drive(fdc, drive_num); - fdc->st0 |= (fdd_get_head(drive_num) ? 4 : 0); + fdc->st0 = (fdc->st0 & 0xf8) | (val & 0x03) | (fdd_get_head(drive_num) ? 4 : 0); } - fdc->dor=val; + fdc->dor = val; return; case 3: /* TDR */ if (fdc->enh_mode) { @@ -853,6 +858,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->command = val; fdc->stat |= 0x10; fdc_log("Starting FDC command %02X\n",fdc->command); + fdc->error = 0; if (((fdc->command & 0x1f) == 0x02) || ((fdc->command & 0x1f) == 0x05) || ((fdc->command & 0x1f) == 0x06) || ((fdc->command & 0x1f) == 0x0a) || @@ -924,6 +930,12 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pos = 0; fdc->mfm = (fdc->command&0x40)?1:0; break; + case 0x17: /*Powerdown mode*/ + if (!(fdc->flags & FDC_FLAG_ALI)) { + fdc_bad_command(fdc); + break; + } + /*FALLTHROUGH*/ case 0x07: /*Recalibrate*/ fdc->pnum=0; fdc->ptot=1; @@ -965,7 +977,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (!(fdc->flags & FDC_FLAG_NSC)) { fdc_bad_command(fdc); break; - } + } + /*FALLTHROUGH*/ case 0x10: /*Get version*/ case 0x14: /*Unlock*/ case 0x94: /*Lock*/ @@ -1031,7 +1044,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) break; case 0x07: /* Recalibrate */ case 0x0f: /* Seek */ - timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); + if (fdc->flags & FDC_FLAG_PCJR) + timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); + else + timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); break; default: timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); @@ -1056,6 +1072,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->specify[0] = fdc->params[0]; fdc->specify[1] = fdc->params[1]; fdc->dma = (fdc->specify[1] & 1) ^ 1; + if (!fdc->dma) + dma_set_drq(fdc->dma_ch, 0); break; case 0x04: /*Sense drive status*/ fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); @@ -1099,7 +1117,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - + case 0x07: /* Recalibrate */ fdc->rw_drive = fdc->params[0] & 3; fdc->stat = (1 << real_drive(fdc, fdc->drive)); @@ -1134,7 +1152,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) break; case 0x0a: /* Read sector ID */ fdc_rate(fdc, fdc->drive); - fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdc->head = (fdc->params[0] & 4) ? 1 : 0; fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); @@ -1151,7 +1169,6 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->head = (fdc->params[0] & 4) ? 1 : 0; fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); fdc->gap = fdc->params[3]; - fdc->dtl = 4000000; fdc->format_sectors = fdc->params[2]; fdc->format_n = fdc->params[1]; fdc->format_state = 1; @@ -1256,7 +1273,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } return; case 7: - if (!(fdc->flags & FDC_FLAG_TOSHIBA) && !(fdc->flags & FDC_FLAG_AT)) + if (!(fdc->flags & FDC_FLAG_TOSHIBA) && !(fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_UMC)) return; fdc->rate = val & 0x03; if (fdc->flags & FDC_FLAG_PS1) @@ -1273,7 +1290,7 @@ fdc_read(uint16_t addr, void *priv) uint8_t ret; int drive; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr & 7) { case 0: /* STA */ @@ -1282,7 +1299,6 @@ fdc_read(uint16_t addr, void *priv) ret = 0x00; /* TODO: Bit 2: INDEX (best return always 0 as it goes by very fast) - Bit 6: DRQ */ if (fdc->seek_dir) /* nDIRECTION */ ret |= 0x01; @@ -1294,6 +1310,8 @@ fdc_read(uint16_t addr, void *priv) ret |= 0x10; if (fdc->step) /* STEP */ ret |= 0x20; + if (dma_get_drq(fdc->dma_ch)) /* DRQ */ + ret |= 0x40; if (fdc->fintr || fdc->reset_stat) /* INTR */ ret |= 0x80; } else @@ -1305,7 +1323,7 @@ fdc_read(uint16_t addr, void *priv) ret = 0x00; /* -Drive 2 Installed */ if (!fdd_get_type(1)) - ret |= 80; + ret |= 0x80; /* -Drive Select 1,0 */ switch (drive) { case 0: @@ -1324,6 +1342,12 @@ fdc_read(uint16_t addr, void *priv) } else { if (is486 || !fdc->enable_3f1) ret = 0xff; + else{ + if(fdc->flags & FDC_FLAG_UMC) + { + drive = real_drive(fdc, fdc->dor & 1); + ret = !fdd_is_dd(drive) ? ((fdc->dor & 1) ? 2 : 1) : 0; + } else { ret = 0x70; @@ -1339,6 +1363,7 @@ fdc_read(uint16_t addr, void *priv) if (fdc->dor & 0x20) ret |= 2; } + } } break; case 2: @@ -1436,7 +1461,8 @@ fdc_read(uint16_t addr, void *priv) default: ret = 0xFF; } - fdc_log("Read FDC %04X %02X\n", addr, ret); + // fdc_log("Read FDC %04X %02X\n", addr, ret); + fdc_log("[%04X:%08X] Read FDC %04X %02X [%i:%02X]\n", CS, cpu_state.pc, addr, ret, drive, fdc->dor & (0x10 << drive)); return ret; } @@ -1450,6 +1476,13 @@ fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; fdc->res[5] = st5; fdc->res[6] = 0; + if (fdc->error) { + fdc->error = 0; + fdc->st0 |= 0x40; + fdc->res[4] |= 0x40; + fdc->res[5] |= fdc->st5; + fdc->res[6] |= fdc->st6; + } if (fdc->wrong_am) { fdc->res[6] |= 0x40; fdc->wrong_am = 0; @@ -1484,12 +1517,16 @@ fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) fdc_log("Read/write finish (%02X %02X %02X %02X %02X %02X %02X)\n" , fdc->res[4], fdc->res[5], fdc->res[6], fdc->res[7], fdc->res[8], fdc->res[9], fdc->res[10]); ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; + dma_set_drq(fdc->dma_ch, 0); } static void fdc_poll_readwrite_finish(fdc_t *fdc, int compare) { + if ((fdc->interrupt == 5) || (fdc->interrupt == 9)) + fdd_do_writeback(real_drive(fdc, fdc->drive)); + fdc->inread = 0; fdc->interrupt = -2; @@ -1544,8 +1581,10 @@ fdc_callback(void *priv) fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_NEXT, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat = 0x70; - else + else { + dma_set_drq(fdc->dma_ch, 1); fdc->stat = 0x50; + } } fdc->inread = 1; return; @@ -1661,8 +1700,10 @@ fdc_callback(void *priv) fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat = 0xb0; - else + else { + dma_set_drq(fdc->dma_ch, 1); fdc->stat = 0x90; + } break; case 6: case 0xC: @@ -1670,8 +1711,10 @@ fdc_callback(void *priv) fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat = 0x70; - else + else { + dma_set_drq(fdc->dma_ch, 1); fdc->stat = 0x50; + } break; case 0x11: case 0x19: @@ -1679,8 +1722,10 @@ fdc_callback(void *priv) fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat = 0xb0; - else + else { + dma_set_drq(fdc->dma_ch, 1); fdc->stat = 0x90; + } break; } fdc->inread = 1; @@ -1714,10 +1759,10 @@ fdc_callback(void *priv) fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; fdc->res[5] = fdc->res[6] = 0; - fdc->res[7] = fdc->pcn[fdc->params[0] & 3]; - fdc->res[8] = fdd_get_head(real_drive(fdc, fdc->drive)); - fdc->res[9] = fdc->format_dat[fdc->pos - 2] + 1; - fdc->res[10] = fdc->params[4]; + fdc->res[7] = fdc->format_sector_id.id.c; + fdc->res[8] = fdc->format_sector_id.id.h; + fdc->res[9] = fdc->format_sector_id.id.r; + fdc->res[10] = fdc->format_sector_id.id.n; fdc->paramstogo = 7; fdc->format_state = 0; return; @@ -1757,6 +1802,12 @@ fdc_callback(void *priv) fdc->paramstogo = 1; fdc->interrupt = 0; return; + case 0x17: /*Powerdown mode*/ + fdc->stat = (fdc->stat & 0xf) | 0xd0; + fdc->res[10] = fdc->params[0]; + fdc->paramstogo = 1; + fdc->interrupt = 0; + return; case 0x13: /*Configure*/ fdc->config = fdc->params[1]; fdc->pretrk = fdc->params[2]; @@ -1786,6 +1837,8 @@ fdc_callback(void *priv) void fdc_error(fdc_t *fdc, int st5, int st6) { + dma_set_drq(fdc->dma_ch, 0); +#if 1 timer_disable(&fdc->timer); fdc_int(fdc, 1); @@ -1822,6 +1875,48 @@ fdc_error(fdc_t *fdc, int st5, int st6) } ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; +#else + switch(fdc->interrupt) { + case 0x02: + case 0x05: + case 0x06: + case 0x09: + case 0x0C: + case 0x11: + case 0x16: + case 0x19: + case 0x1D: + fdc->error = 1; + fdc->st5 = st5; + fdc->st6 = st6; + fdc->tc = 1; + fdc->stat = 0x10; + fdc_callback(fdc); + break; + default: + timer_disable(&fdc->timer); + + fdc_int(fdc, 1); + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; + fdc->stat = 0xD0; + fdc->st0 = fdc->res[4] = 0x40 | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; + if (fdc->head && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) + fdc->st0 |= 0x08; + fdc->res[5] = st5; + fdc->res[6] = st6; + fdc_log("FDC Error: %02X %02X %02X\n", fdc->res[4], fdc->res[5], fdc->res[6]); + + fdc->res[7]=0; + fdc->res[8]=0; + fdc->res[9]=0; + fdc->res[10]=0; + + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); + fdc->paramstogo = 7; + break; + } +#endif } @@ -1842,9 +1937,10 @@ fdc_is_verify(fdc_t *fdc) int -fdc_data(fdc_t *fdc, uint8_t data) +fdc_data(fdc_t *fdc, uint8_t data, int last) { - int result = 0; + int i, result = 0; + int n; if (fdc->deleted & 2) { /* We're in a VERIFY command, so return with 0. */ @@ -1874,27 +1970,47 @@ fdc_data(fdc_t *fdc, uint8_t data) } } } else { - result = dma_channel_write(fdc->dma_ch, data); - if (fdc->tc) return -1; - if (result & DMA_OVER) { - fdc->data_ready = 1; - fdc->stat = 0xd0; - fdc->tc = 1; - return -1; - } - if (!fdc->fifo || (fdc->tfifo < 1)) { fdc->data_ready = 1; fdc->stat = 0xd0; + dma_set_drq(fdc->dma_ch, 1); + + fdc->fifobufpos = 0; + + result = dma_channel_write(fdc->dma_ch, data); + + if (result & DMA_OVER) { + dma_set_drq(fdc->dma_ch, 0); + fdc->tc = 1; + return -1; + } + dma_set_drq(fdc->dma_ch, 0); } else { - fdc_fifo_buf_advance(fdc); - if (fdc->fifobufpos == 0) { + /* FIFO enabled */ + fdc_fifo_buf_write(fdc, data); + if (last || (fdc->fifobufpos == 0)) { /* We have wrapped around, means FIFO is over */ fdc->data_ready = 1; fdc->stat = 0xd0; + dma_set_drq(fdc->dma_ch, 1); + + n = (fdc->fifobufpos > 0) ? (fdc->fifobufpos - 1) : fdc->tfifo; + if (fdc->fifobufpos > 0) + fdc->fifobufpos = 0; + + for (i = 0; i <= n; i++) { + result = dma_channel_write(fdc->dma_ch, fdc->fifobuf[i]); + + if (result & DMA_OVER) { + dma_set_drq(fdc->dma_ch, 0); + fdc->tc = 1; + return -1; + } + } + dma_set_drq(fdc->dma_ch, 0); } } } @@ -1906,7 +2022,7 @@ fdc_data(fdc_t *fdc, uint8_t data) void fdc_finishread(fdc_t *fdc) { - fdc->inread = 0; + fdc->inread = 0; } @@ -1924,7 +2040,8 @@ void fdc_sector_finishcompare(fdc_t *fdc, int satisfying) { fdc->stat = 0x10; - fdc->satisfying_sectors++; + if (satisfying) + fdc->satisfying_sectors++; fdc->inread = 0; fdc_callback(fdc); } @@ -2006,14 +2123,10 @@ fdc_writeprotect(fdc_t *fdc) int fdc_getdata(fdc_t *fdc, int last) { - int data; + int i, data = 0; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) { - if (fdc->written) { - fdc_overrun(fdc); - return -1; - } - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo || (fdc->tfifo < 1)) { data = fdc->dat; if (!last) @@ -2025,23 +2138,41 @@ int fdc_getdata(fdc_t *fdc, int last) fdc->stat = 0xb0; } } else { - data = dma_channel_read(fdc->dma_ch); + if (!fdc->fifo || (fdc->tfifo < 1)) { + data = dma_channel_read(fdc->dma_ch); + dma_set_drq(fdc->dma_ch, 0); - if (!fdc->fifo) { - if (!last) + if (data & DMA_OVER) + fdc->tc = 1; + + if (!last) { fdc->stat = 0x90; + dma_set_drq(fdc->dma_ch, 1); + } } else { - fdc_fifo_buf_advance(fdc); + if (fdc->fifobufpos == 0) { + for (i = 0; i <= fdc->tfifo; i++) { + data = dma_channel_read(fdc->dma_ch); + fdc->fifobuf[i] = data; - if (!last && (fdc->fifobufpos == 0)) + if (data & DMA_OVER) { + dma_set_drq(fdc->dma_ch, 0); + fdc->tc = 1; + break; + } + } + dma_set_drq(fdc->dma_ch, 0); + } + + data = fdc_fifo_buf_read(fdc); + + if (!last && (fdc->fifobufpos == 0)) { + dma_set_drq(fdc->dma_ch, 1); fdc->stat = 0x90; + } } - - if (data & DMA_OVER) - fdc->tc = 1; } - fdc->written = 0; return data & 0xff; } @@ -2060,6 +2191,7 @@ fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t si fdc->res[10] = size; ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; + dma_set_drq(fdc->dma_ch, 0); } @@ -2115,11 +2247,23 @@ fdc_set_irq(fdc_t *fdc, int irq) } +void +fdc_set_dma_ch(fdc_t *fdc, int dma_ch) +{ + fdc->dma_ch = dma_ch; +} + + void fdc_set_base(fdc_t *fdc, int base) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); + if (fdc->flags & FDC_FLAG_NSC) { + io_sethandler(base + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); @@ -2127,13 +2271,16 @@ fdc_set_base(fdc_t *fdc, int base) if (fdc->flags & FDC_FLAG_PCJR) io_sethandler(base, 0x0010, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); else { + if(fdc->flags & FDC_FLAG_UMC) + io_sethandler(base + 0x0001, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); io_sethandler(base + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); - if (fdc->flags & FDC_FLAG_TOSHIBA) + if ((fdc->flags & FDC_FLAG_TOSHIBA) || (fdc->flags & FDC_FLAG_UMC)) io_sethandler(base + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } } + } fdc->base_address = base; fdc_log("FDC Base address set%s (%04X)\n", super_io ? " for Super I/O" : "", fdc->base_address); } @@ -2145,6 +2292,11 @@ fdc_remove(fdc_t *fdc) int super_io = (fdc->flags & FDC_FLAG_SUPERIO); fdc_log("FDC Removed (%04X)\n", fdc->base_address); + if (fdc->flags & FDC_FLAG_NSC) { + io_removehandler(fdc->base_address + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); @@ -2152,14 +2304,17 @@ fdc_remove(fdc_t *fdc) if (fdc->flags & FDC_FLAG_PCJR) io_removehandler(fdc->base_address, 0x0010, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); else { + if(fdc->flags & FDC_FLAG_UMC) + io_removehandler(fdc->base_address + 0x0001, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); io_removehandler(fdc->base_address + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); io_removehandler(fdc->base_address + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); - if (fdc->flags & FDC_FLAG_TOSHIBA) + if ((fdc->flags & FDC_FLAG_TOSHIBA) || (fdc->flags & FDC_FLAG_UMC)) io_removehandler(fdc->base_address + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } } } +} void @@ -2215,7 +2370,7 @@ fdc_reset(void *priv) fdc->max_track = (fdc->flags & FDC_FLAG_MORE_TRACKS) ? 85 : 79; fdc_remove(fdc); - fdc_set_base(fdc, (fdc->flags & FDC_FLAG_PCJR) ? 0x00f0 : 0x03f0); + fdc_set_base(fdc, (fdc->flags & FDC_FLAG_PCJR) ? FDC_PRIMARY_PCJR_ADDR : FDC_PRIMARY_ADDR); current_drive = 0; @@ -2246,12 +2401,12 @@ fdc_init(const device_t *info) fdc->flags = info->local; - fdc->irq = 6; + fdc->irq = FDC_PRIMARY_IRQ; if (fdc->flags & FDC_FLAG_PCJR) timer_add(&fdc->watchdog_timer, fdc_watchdog_poll, fdc, 0); else - fdc->dma_ch = 2; + fdc->dma_ch = FDC_PRIMARY_DMA; fdc_log("FDC added: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); @@ -2276,114 +2431,198 @@ fdc_3f1_enable(fdc_t *fdc, int enable) fdc->enable_3f1 = enable; } - const device_t fdc_xt_device = { - "PC/XT Floppy Drive Controller", - 0, - 0, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/XT Floppy Drive Controller", + .internal_name = "fdc_xt", + .flags = 0, + .local = 0, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_xt_t1x00_device = { - "PC/XT Floppy Drive Controller (Toshiba)", - 0, - FDC_FLAG_TOSHIBA, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/XT Floppy Drive Controller (Toshiba)", + .internal_name = "fdc_xt_t1x00", + .flags = 0, + .local = FDC_FLAG_TOSHIBA, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_xt_amstrad_device = { - "PC/XT Floppy Drive Controller (Amstrad)", - 0, - FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AMSTRAD, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/XT Floppy Drive Controller (Amstrad)", + .internal_name = "fdc_xt_amstrad", + .flags = 0, + .local = FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AMSTRAD, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +const device_t fdc_xt_tandy_device = { + .name = "PC/XT Floppy Drive Controller (Tandy)", + .internal_name = "fdc_xt_tandy", + .flags = 0, + .local = FDC_FLAG_AMSTRAD, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; const device_t fdc_pcjr_device = { - "PCjr Floppy Drive Controller", - 0, - FDC_FLAG_PCJR, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PCjr Floppy Drive Controller", + .internal_name = "fdc_pcjr", + .flags = 0, + .local = FDC_FLAG_PCJR, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_at_device = { - "PC/AT Floppy Drive Controller", - 0, - FDC_FLAG_AT, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/AT Floppy Drive Controller", + .internal_name = "fdc_at", + .flags = 0, + .local = FDC_FLAG_AT, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_at_actlow_device = { - "PC/AT Floppy Drive Controller (Active low)", - 0, - FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AT, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/AT Floppy Drive Controller (Active low)", + .internal_name = "fdc_at_actlow", + .flags = 0, + .local = FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AT, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_at_ps1_device = { - "PC/AT Floppy Drive Controller (PS/1, PS/2 ISA)", - 0, - FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AT | FDC_FLAG_PS1, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/AT Floppy Drive Controller (PS/1, PS/2 ISA)", + .internal_name = "fdc_at_ps1", + .flags = 0, + .local = FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AT | FDC_FLAG_PS1, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_at_smc_device = { - "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)", - 0, - FDC_FLAG_AT | FDC_FLAG_SUPERIO, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)", + .internal_name = "fdc_at_smc", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_SUPERIO, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc_at_ali_device = { + .name = "PC/AT Floppy Drive Controller (ALi M512x/M1543C)", + .internal_name = "fdc_at_ali", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_SUPERIO | FDC_FLAG_ALI, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_at_winbond_device = { - "PC/AT Floppy Drive Controller (Winbond W83x77F)", - 0, - FDC_FLAG_AT | FDC_FLAG_SUPERIO | FDC_FLAG_START_RWC_1 | FDC_FLAG_MORE_TRACKS, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/AT Floppy Drive Controller (Winbond W83x77F)", + .internal_name = "fdc_at_winbond", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_SUPERIO | FDC_FLAG_START_RWC_1 | FDC_FLAG_MORE_TRACKS, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_at_nsc_device = { - "PC/AT Floppy Drive Controller (NSC PC8730x)", - 0, - FDC_FLAG_AT | FDC_FLAG_MORE_TRACKS | FDC_FLAG_NSC, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "PC/AT Floppy Drive Controller (NSC PC8730x)", + .internal_name = "fdc_at_nsc", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_MORE_TRACKS | FDC_FLAG_NSC, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc_dp8473_device = { - "NS DP8473 Floppy Drive Controller", - 0, - FDC_FLAG_NSDP, - fdc_init, - fdc_close, - fdc_reset, - NULL, NULL, NULL + .name = "NS DP8473 Floppy Drive Controller", + .internal_name = "fdc_dp8473", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_NSC, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc_um8398_device = { + .name = "UMC UM8398 Floppy Drive Controller", + .internal_name = "fdc_um8398", + .flags = 0, + .local = FDC_FLAG_UMC, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/floppy/fdc_magitronic.c b/src/floppy/fdc_magitronic.c new file mode 100644 index 000000000..2250c9a4b --- /dev/null +++ b/src/floppy/fdc_magitronic.c @@ -0,0 +1,146 @@ +/* + * 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 Magitronic B215 XT-FDC Controller. + * + * Authors: Tiseno100 + * + * Copyright 2021 Tiseno100 + * + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> + +#define ROM_B215 "roms/floppy/magitronic/Magitronic B215 - BIOS ROM.bin" +#define ROM_ADDR (uint32_t)(device_get_config_hex20("bios_addr") & 0x000fffff) + +#define DRIVE_SELECT (int)(real_drive(dev->fdc_controller, i)) +typedef struct +{ + fdc_t *fdc_controller; + rom_t rom; +} b215_t; + +static uint8_t +b215_read(uint16_t addr, void *priv) +{ + b215_t *dev = (b215_t *)priv; + + /* + Register 3F0h + + Bit (3-2) for Drive B: + Bit (1-0) for Drive A: + 0: 360KB + 1: 1.2MB + 2: 720KB + 3: 1.44MB + 4: +*/ + int drive_spec[2]; + + for (int i = 0; i <= 1; i++) + { + if (fdd_is_525(DRIVE_SELECT)) + { + if (!fdd_is_dd(DRIVE_SELECT)) + drive_spec[i] = 1; + else if (fdd_doublestep_40(DRIVE_SELECT)) + drive_spec[i] = 2; + else + drive_spec[i] = 0; + } + else + { + if (fdd_is_dd(DRIVE_SELECT) && !fdd_is_double_sided(DRIVE_SELECT)) + drive_spec[i] = 0; + else if (fdd_is_dd(DRIVE_SELECT) && fdd_is_double_sided(DRIVE_SELECT)) + drive_spec[i] = 2; + else + drive_spec[i] = 3; + } + } + + return ((drive_spec[1] << 2) | drive_spec[0]) & 0x0f; +} + +static void +b215_close(void *priv) +{ + b215_t *dev = (b215_t *)priv; + + free(dev); +} + +static void * +b215_init(const device_t *info) +{ + b215_t *dev = (b215_t *)malloc(sizeof(b215_t)); + memset(dev, 0, sizeof(b215_t)); + + rom_init(&dev->rom, ROM_B215, ROM_ADDR, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + + dev->fdc_controller = device_add(&fdc_um8398_device); + io_sethandler(FDC_PRIMARY_ADDR, 1, b215_read, NULL, NULL, NULL, NULL, NULL, dev); + + return dev; +} + +static int b215_available(void) +{ + return rom_present(ROM_B215); +} + +static const device_config_t b215_config[] = { +// clang-format off + { + .name = "bios_addr", + .description = "BIOS Address:", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xca000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +const device_t fdc_b215_device = { + .name = "Magitronic B215", + .internal_name = "b215", + .flags = DEVICE_ISA, + .local = 0, + .init = b215_init, + .close = b215_close, + .reset = NULL, + { .available = b215_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = b215_config +}; diff --git a/src/floppy/fdc_pii15xb.c b/src/floppy/fdc_pii15xb.c index 55dd55460..42b72885f 100644 --- a/src/floppy/fdc_pii15xb.c +++ b/src/floppy/fdc_pii15xb.c @@ -1,55 +1,63 @@ /* * VARCem Virtual ARchaeological Computer EMulator. * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly * spanning the era between 1981 and 1995. * * This file is part of the VARCem Project. * - * Implementation of the DTK PII-151B and PII-158B cards. + * Implementation of the DTK MiniMicro series of Floppy Disk Controllers. + * Original code from VARCem. Fully rewritten, fixed and improved for 86Box. * - * These are DP8473-based floppy controller ISA cards for XT - * class systems, and allow usage of standard and high-density - * drives on them. They have their own BIOS which takes over - * from the standard system BIOS. - * - * Author: Fred N. van Kempen, + * Author: Fred N. van Kempen, , + * Tiseno100 * * Copyright 2019 Fred N. van Kempen. + * Copyright 2021 Tiseno100 * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the * following conditions are met: * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. * * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define _GNU_SOURCE + +/* +Notes: +VARCem uses the DP8473 for both floppy disk controllers. The statement though is wrong. + +MiniMicro 4 uses a Zilog Z0765A08PSC(Clone of the NEC 765) +MiniMicro 1 uses a National Semiconductor DP8473(Clone of the NEC 765 with additional NSC commands) + +Issues: +MiniMicro 4 works only with a few XT machines. This statement has to be confirmed by someone with the real card itself. +MiniMicro 4 also won't work with the XT FDC which the Zilog claims to be. +*/ + #include #include #include @@ -61,57 +69,23 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> -#include <86box/pic.h> #include <86box/rom.h> #include <86box/machine.h> #include <86box/timer.h> -#include <86box/plat.h> -#include <86box/ui.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> -#define ROM_PII_151B L"roms/floppy/dtk/pii-151b.rom" -#define ROM_PII_158B L"roms/floppy/dtk/pii-158b.rom" +#define DTK_VARIANT ((info->local == 158) ? ROM_PII_158B : ROM_PII_151B) +#define DTK_CHIP ((info->local == 158) ? &fdc_xt_device : &fdc_dp8473_device) +#define BIOS_ADDR (uint32_t)(device_get_config_hex20("bios_addr") & 0x000fffff) +#define ROM_PII_151B "roms/floppy/dtk/pii-151b.rom" +#define ROM_PII_158B "roms/floppy/dtk/pii-158b.rom" -typedef struct { - const char *name; - int type; - - uint32_t bios_addr, - bios_size; - rom_t bios_rom; - - fdc_t *fdc; -} pii_t; - - -/* Load and enable a BIOS ROM if we have one, and is enabled. */ -static void -set_bios(pii_t *dev, wchar_t *fn) +typedef struct { - uint32_t temp; - FILE *fp; - - /* Only do this if needed. */ - if ((fn == NULL) || (dev->bios_addr == 0)) return; - - if ((fp = rom_fopen(fn, L"rb")) == NULL) return; - - (void)fseek(fp, 0L, SEEK_END); - temp = ftell(fp); - (void)fclose(fp); - - /* Assume 128K, then go down. */ - dev->bios_size = 0x020000; - while (temp < dev->bios_size) - dev->bios_size >>= 1; - - /* Create a memory mapping for the space. */ - rom_init(&dev->bios_rom, fn, dev->bios_addr, - dev->bios_size, dev->bios_size-1, 0, MEM_MAPPING_EXTERNAL); -} - + rom_t bios_rom; +} pii_t; static void pii_close(void *priv) @@ -121,36 +95,20 @@ pii_close(void *priv) free(dev); } - static void * pii_init(const device_t *info) { pii_t *dev; dev = (pii_t *)malloc(sizeof(pii_t)); - memset(dev, 0x00, sizeof(pii_t)); - dev->type = info->local; + memset(dev, 0, sizeof(pii_t)); - dev->bios_addr = device_get_config_hex20("bios_addr"); + if (BIOS_ADDR != 0) + rom_init(&dev->bios_rom, DTK_VARIANT, BIOS_ADDR, 0x2000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); - if (dev->bios_addr != 0x000000) { - switch (dev->type) { - case 151: - set_bios(dev, ROM_PII_151B); - break; - case 158: - set_bios(dev, ROM_PII_158B); - break; - } - } + device_add(DTK_CHIP); - /* Attach the DP8473 chip. */ - dev->fdc = device_add(&fdc_at_device); - - //pclog("FDC: %s (I/O=%04X, flags=%08x)\n", - // info->name, dev->fdc->base_address, dev->fdc->flags); - - return(dev); + return dev; } static int pii_151b_available(void) @@ -164,45 +122,51 @@ static int pii_158_available(void) } static const device_config_t pii_config[] = { +// clang-format off { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0x0ce000, - { - { - "Disabled", 0 - }, - { - "CA00H", 0x0ca000 - }, - { - "CC00H", 0x0cc000 - }, - { - "CE00H", 0x0ce000 - }, - { - "" - } - } + .name = "bios_addr", + .description = "BIOS Address:", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xce000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; const device_t fdc_pii151b_device = { - "DTK PII-151B (MiniMicro) Floppy Drive Controller", - DEVICE_ISA, - 151, - pii_init, pii_close, NULL, - pii_151b_available, NULL, NULL, - pii_config + .name = "DTK PII-151B (MiniMicro) Floppy Drive Controller", + .internal_name = "dtk_pii151b", + .flags = DEVICE_ISA, + .local = 151, + .init = pii_init, + .close = pii_close, + .reset = NULL, + { .available = pii_151b_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pii_config }; const device_t fdc_pii158b_device = { - "DTK PII-158B (MiniMicro4) Floppy Drive Controller", - DEVICE_ISA, - 158, - pii_init, pii_close, NULL, - pii_158_available, NULL, NULL, - pii_config + .name = "DTK PII-158B (MiniMicro4) Floppy Drive Controller", + .internal_name = "dtk_pii158b", + .flags = DEVICE_ISA, + .local = 158, + .init = pii_init, + .close = pii_close, + .reset = NULL, + { .available = pii_158_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pii_config }; diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index a2a5342af..0ac6e31c3 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/ui.h> #include <86box/fdd.h> @@ -77,7 +78,7 @@ typedef struct { fdd_t fdd[FDD_NUM]; -wchar_t floppyfns[FDD_NUM][512]; +char floppyfns[FDD_NUM][512]; pc_timer_t fdd_poll_time[FDD_NUM]; @@ -99,44 +100,44 @@ d86f_handler_t d86f_handler[FDD_NUM]; static const struct { - wchar_t *ext; - void (*load)(int drive, wchar_t *fn); + char *ext; + void (*load)(int drive, char *fn); void (*close)(int drive); int size; } loaders[]= { - {L"001", img_load, img_close, -1}, - {L"002", img_load, img_close, -1}, - {L"003", img_load, img_close, -1}, - {L"004", img_load, img_close, -1}, - {L"005", img_load, img_close, -1}, - {L"006", img_load, img_close, -1}, - {L"007", img_load, img_close, -1}, - {L"008", img_load, img_close, -1}, - {L"009", img_load, img_close, -1}, - {L"010", img_load, img_close, -1}, - {L"12", img_load, img_close, -1}, - {L"144", img_load, img_close, -1}, - {L"360", img_load, img_close, -1}, - {L"720", img_load, img_close, -1}, - {L"86F", d86f_load, d86f_close, -1}, - {L"BIN", img_load, img_close, -1}, - {L"CQ", img_load, img_close, -1}, - {L"CQM", img_load, img_close, -1}, - {L"DDI", img_load, img_close, -1}, - {L"DSK", img_load, img_close, -1}, - {L"FDI", fdi_load, fdi_close, -1}, - {L"FDF", img_load, img_close, -1}, - {L"FLP", img_load, img_close, -1}, - {L"HDM", img_load, img_close, -1}, - {L"IMA", img_load, img_close, -1}, - {L"IMD", imd_load, imd_close, -1}, - {L"IMG", img_load, img_close, -1}, - {L"JSON", json_load, json_close, -1}, - {L"MFM", mfm_load, mfm_close, -1}, - {L"TD0", td0_load, td0_close, -1}, - {L"VFD", img_load, img_close, -1}, - {L"XDF", img_load, img_close, -1}, + {"001", img_load, img_close, -1}, + {"002", img_load, img_close, -1}, + {"003", img_load, img_close, -1}, + {"004", img_load, img_close, -1}, + {"005", img_load, img_close, -1}, + {"006", img_load, img_close, -1}, + {"007", img_load, img_close, -1}, + {"008", img_load, img_close, -1}, + {"009", img_load, img_close, -1}, + {"010", img_load, img_close, -1}, + {"12", img_load, img_close, -1}, + {"144", img_load, img_close, -1}, + {"360", img_load, img_close, -1}, + {"720", img_load, img_close, -1}, + {"86F", d86f_load, d86f_close, -1}, + {"BIN", img_load, img_close, -1}, + {"CQ", img_load, img_close, -1}, + {"CQM", img_load, img_close, -1}, + {"DDI", img_load, img_close, -1}, + {"DSK", img_load, img_close, -1}, + {"FDI", fdi_load, fdi_close, -1}, + {"FDF", img_load, img_close, -1}, + {"FLP", img_load, img_close, -1}, + {"HDM", img_load, img_close, -1}, + {"IMA", img_load, img_close, -1}, + {"IMD", imd_load, imd_close, -1}, + {"IMG", img_load, img_close, -1}, + {"JSON", json_load, json_close, -1}, + {"MFM", mfm_load, mfm_close, -1}, + {"TD0", td0_load, td0_close, -1}, + {"VFD", img_load, img_close, -1}, + {"XDF", img_load, img_close, -1}, {0, 0, 0, 0} }; @@ -313,7 +314,7 @@ fdd_set_densel(int densel) { int i = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < FDD_NUM; i++) { if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) fdd[i].densel = densel ^ 1; else @@ -482,44 +483,44 @@ fdd_get_densel(int drive) void -fdd_load(int drive, wchar_t *fn) +fdd_load(int drive, char *fn) { int c = 0, size; - wchar_t *p; + char *p; FILE *f; - fdd_log("FDD: loading drive %d with '%ls'\n", drive, fn); + fdd_log("FDD: loading drive %d with '%s'\n", drive, fn); if (!fn) return; - p = plat_get_extension(fn); + p = path_get_extension(fn); if (!p) return; - f = plat_fopen(fn, L"rb"); - if (!f) - return; - if (fseek(f, -1, SEEK_END) == -1) - fatal("fdd_load(): Error seeking to the end of the file\n"); - size = ftell(f) + 1; - fclose(f); - while (loaders[c].ext) { - if (!wcscasecmp(p, (wchar_t *) loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { - driveloaders[drive] = c; - memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); - d86f_setup(drive); - loaders[c].load(drive, floppyfns[drive]); - drive_empty[drive] = 0; - fdd_forced_seek(drive, 0); - fdd_changed[drive] = 1; - return; + f = plat_fopen(fn, "rb"); + if (f) { + if (fseek(f, -1, SEEK_END) == -1) + fatal("fdd_load(): Error seeking to the end of the file\n"); + size = ftell(f) + 1; + fclose(f); + while (loaders[c].ext) { + if (!strcasecmp(p, (char *) loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { + driveloaders[drive] = c; + if (floppyfns[drive] != fn) strcpy(floppyfns[drive], fn); + d86f_setup(drive); + loaders[c].load(drive, floppyfns[drive]); + drive_empty[drive] = 0; + fdd_forced_seek(drive, 0); + fdd_changed[drive] = 1; + return; + } + c++; } - c++; } - fdd_log("FDD: could not load '%ls' %s\n",fn,p); + fdd_log("FDD: could not load '%s' %s\n",fn,p); drive_empty[drive] = 1; fdd_set_head(drive, 0); memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); - ui_sb_update_icon_state(drive, 1); + ui_sb_update_icon_state(SB_FLOPPY | drive, 1); } @@ -545,7 +546,7 @@ fdd_close(int drive) drives[drive].byteperiod = NULL; drives[drive].stop = NULL; d86f_destroy(drive); - ui_sb_update_icon_state(drive, 1); + ui_sb_update_icon_state(SB_FLOPPY | drive, 1); } @@ -559,7 +560,7 @@ fdd_hole(int drive) } -uint64_t +static __inline uint64_t fdd_byteperiod(int drive) { if (!fdd_get_turbo(drive) && drives[drive].byteperiod) @@ -634,7 +635,7 @@ fdd_reset(void) { int i; - for (i = 0; i < 4; i++) { + for (i = 0; i < FDD_NUM; i++) { drives[i].id = i; timer_add(&(fdd_poll_time[i]), fdd_poll, &drives[i], 0); } @@ -709,7 +710,7 @@ fdd_init(void) { int i; - for (i = 0; i < 4; i++) { + for (i = 0; i < FDD_NUM; i++) { drives[i].poll = 0; drives[i].seek = 0; drives[i].readsector = 0; @@ -721,8 +722,14 @@ fdd_init(void) imd_init(); json_init(); - fdd_load(0, floppyfns[0]); - fdd_load(1, floppyfns[1]); - fdd_load(2, floppyfns[2]); - fdd_load(3, floppyfns[3]); + for (i = 0; i < FDD_NUM; i++) { + fdd_load(i, floppyfns[i]); + } +} + + +void +fdd_do_writeback(int drive) +{ + d86f_handler[drive].writeback(drive); } diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index ddcc515f0..ac4de1ee4 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -103,10 +103,6 @@ enum { /* 1 11 01 ??? */ STATE_0D_SPIN_TO_INDEX = 0xE8, /* FORMAT TRACK */ STATE_0D_FORMAT_TRACK, - - /* 1 11 11 ??? */ - STATE_0D_NOP_SPIN_TO_INDEX = 0xF8, /* FORMAT TRACK */ - STATE_0D_NOP_FORMAT_TRACK }; enum { @@ -138,9 +134,9 @@ typedef struct { } sliding_buffer_t; typedef struct { - uint32_t sync_marks; uint32_t bits_obtained; - uint32_t bytes_obtained; + uint16_t bytes_obtained; + uint16_t sync_marks; uint32_t sync_pos; } find_t; @@ -181,48 +177,35 @@ typedef struct { */ typedef struct { FILE *f; - uint16_t version; - uint16_t disk_flags; - int32_t extra_bit_cells[2]; + uint8_t state, fill, sector_count, format_state, + error_condition, id_found; + uint16_t version, disk_flags, satisfying_bytes, turbo_pos; + uint16_t cur_track; uint16_t track_encoded_data[2][53048]; uint16_t *track_surface_data[2]; uint16_t thin_track_encoded_data[2][2][53048]; uint16_t *thin_track_surface_data[2][2]; uint16_t side_flags[2]; + uint16_t preceding_bit[2]; + uint16_t current_byte[2]; + uint16_t current_bit[2]; + uint16_t last_word[2]; +#ifdef D86F_COMPRESS + int is_compressed; +#endif + int32_t extra_bit_cells[2]; + uint32_t file_size, index_count, track_pos, datac, + id_pos, dma_over; uint32_t index_hole_pos[2]; uint32_t track_offset[512]; - uint32_t file_size; - sector_id_t format_sector_id; sector_id_t last_sector; sector_id_t req_sector; - uint32_t index_count; - uint8_t state; - uint8_t fill; - uint32_t track_pos; - uint32_t datac; - uint32_t id_pos; - uint16_t last_word[2]; find_t id_find; find_t data_find; crc_t calc_crc; crc_t track_crc; - uint8_t sector_count; - uint8_t format_state; - uint16_t satisfying_bytes; - uint16_t preceding_bit[2]; - uint16_t current_byte[2]; - uint16_t current_bit[2]; - int cur_track; - uint32_t error_condition; -#ifdef D86F_COMPRESS - int is_compressed; -#endif - int id_found; - wchar_t original_file_name[2048]; - uint8_t *filebuf; - uint8_t *outbuf; - uint32_t dma_over; - int turbo_pos; + char original_file_name[2048]; + uint8_t *filebuf, *outbuf; sector_t *last_side_sector[2]; } d86f_t; @@ -252,7 +235,6 @@ static d86f_t *d86f[FDD_NUM]; static uint16_t CRCTable[256]; static fdc_t *d86f_fdc; uint64_t poly = 0x42F0E1EBA9EA3693ll; /* ECMA normal */ -uint64_t table[256]; uint16_t d86f_side_flags(int drive); @@ -834,16 +816,14 @@ uint32_t d86f_get_data_len(int drive) { d86f_t *dev = d86f[drive]; + uint32_t i, ret = 128; - if (dev->req_sector.id.n) { - if (dev->req_sector.id.n == 8) return 32768; - return (128 << ((uint32_t) dev->req_sector.id.n)); - } else { - if (fdc_get_dtl(d86f_fdc) < 128) - return fdc_get_dtl(d86f_fdc); - else - return (128 << ((uint32_t) dev->req_sector.id.n)); - } + if (dev->req_sector.id.n) + ret = (uint32_t)128 << dev->req_sector.id.n; + else if ((i = fdc_get_dtl(d86f_fdc)) < 128) + ret = i; + + return ret; } @@ -974,7 +954,8 @@ d86f_encode_byte(int drive, int sync, decoded_t b, decoded_t prev_b) uint8_t bits3210 = b.nibbles.nibble0; uint16_t encoded_7654, encoded_3210, result; - if (encoding > 1) return 0xff; + if (encoding > 1) + return 0xffff; if (sync) { result = d86f_encode_get_data(b.byte); @@ -1476,7 +1457,7 @@ d86f_read_sector_id(int drive, int side, int match) } else { /* CRC is valid. */ dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; - dev->id_found++; + dev->id_found |= 1; if ((dev->last_sector.dword == dev->req_sector.dword) || !match) { d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); if (dev->state == STATE_02_READ_ID) { @@ -1517,10 +1498,15 @@ uint8_t d86f_get_data(int drive, int base) { d86f_t *dev = d86f[drive]; - int data; + int data, byte_count; - if (dev->data_find.bytes_obtained < (d86f_get_data_len(drive) + base)) { - data = fdc_getdata(d86f_fdc, dev->data_find.bytes_obtained == (d86f_get_data_len(drive) + base - 1)); + if (fdd_get_turbo(drive) && (dev->version == 0x0063)) + byte_count = dev->turbo_pos; + else + byte_count = dev->data_find.bytes_obtained; + + if (byte_count < (d86f_get_data_len(drive) + base)) { + data = fdc_getdata(d86f_fdc, byte_count == (d86f_get_data_len(drive) + base - 1)); if ((data & DMA_OVER) || (data == -1)) { dev->dma_over++; if (data == -1) @@ -1596,7 +1582,7 @@ d86f_read_sector_data(int drive, int side) } else { if (dev->data_find.bytes_obtained < d86f_get_data_len(drive)) { if (dev->state != STATE_16_VERIFY_DATA) { - read_status = fdc_data(d86f_fdc, data); + read_status = fdc_data(d86f_fdc, data, dev->data_find.bytes_obtained == (d86f_get_data_len(drive) - 1)); if (read_status == -1) dev->dma_over++; } @@ -1627,7 +1613,9 @@ d86f_read_sector_data(int drive, int side) dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; dev->error_condition = 0; dev->state = STATE_IDLE; - if (dev->state == STATE_11_SCAN_DATA) + if (dev->state == STATE_02_READ_DATA) + fdc_track_finishread(d86f_fdc, dev->error_condition); + else if (dev->state == STATE_11_SCAN_DATA) fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); else fdc_sector_finishread(d86f_fdc); @@ -1730,7 +1718,6 @@ d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; dev->error_condition = 0; dev->state = STATE_IDLE; - d86f_handler[drive].writeback(drive); fdc_sector_finishread(d86f_fdc); return; } @@ -1781,7 +1768,7 @@ d86f_spin_to_index(int drive, int side) d86f_advance_bit(drive, side); if (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) { - if ((dev->state == STATE_0D_SPIN_TO_INDEX) || (dev->state == STATE_0D_NOP_SPIN_TO_INDEX)) { + if (dev->state == STATE_0D_SPIN_TO_INDEX) { /* When starting format, reset format state to the beginning. */ dev->preceding_bit[side] = 1; dev->format_state = FMT_PRETRK_GAP0; @@ -1956,7 +1943,7 @@ d86f_format_track(int drive, int side, int do_write) data &= 0xff; if ((data == -1) && (dev->datac < 3)) data = 0; - dev->format_sector_id.byte_array[dev->datac] = data & 0xff; + d86f_fdc->format_sector_id.byte_array[dev->datac] = data & 0xff; if (dev->datac == 3) fdc_stop_id_request(d86f_fdc); } @@ -2001,11 +1988,11 @@ d86f_format_track(int drive, int side, int do_write) case FMT_SECTOR_ID: max_len = 4; if (do_write) { - d86f_write_direct(drive, side, dev->format_sector_id.byte_array[dev->datac], 0); - d86f_calccrc(dev, dev->format_sector_id.byte_array[dev->datac]); + d86f_write_direct(drive, side, d86f_fdc->format_sector_id.byte_array[dev->datac], 0); + d86f_calccrc(dev, d86f_fdc->format_sector_id.byte_array[dev->datac]); } else { if (dev->datac == 3) { - d86f_handler[drive].set_sector(drive, side, dev->format_sector_id.id.c, dev->format_sector_id.id.h, dev->format_sector_id.id.r, dev->format_sector_id.id.n); + d86f_handler[drive].set_sector(drive, side, d86f_fdc->format_sector_id.id.c, d86f_fdc->format_sector_id.id.h, d86f_fdc->format_sector_id.id.r, d86f_fdc->format_sector_id.id.n); } } break; @@ -2101,22 +2088,6 @@ d86f_format_track(int drive, int side, int do_write) } -void -d86f_format_track_normal(int drive, int side) -{ - d86f_t *dev = d86f[drive]; - - d86f_format_track(drive, side, (dev->version == D86FVER)); -} - - -void -d86f_format_track_nop(int drive, int side) -{ - d86f_format_track(drive, side, 0); -} - - void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n) { @@ -2164,40 +2135,44 @@ d86f_turbo_read(int drive, int side) dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos); else dat = (random_generate() & 0xff); - dev->turbo_pos++; if (dev->state == STATE_11_SCAN_DATA) { /* Scan/compare command. */ recv_data = d86f_get_data(drive, 0); d86f_compare_byte(drive, recv_data, dat); } else { - if (dev->data_find.bytes_obtained < (128UL << dev->last_sector.id.n)) { + if (dev->turbo_pos < (128UL << dev->req_sector.id.n)) { if (dev->state != STATE_16_VERIFY_DATA) { - read_status = fdc_data(d86f_fdc, dat); + read_status = fdc_data(d86f_fdc, dat, dev->turbo_pos == ((128UL << dev->req_sector.id.n) - 1)); if (read_status == -1) dev->dma_over++; } } } - if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) { + dev->turbo_pos++; + + if (dev->turbo_pos >= (128UL << dev->req_sector.id.n)) { dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; if ((flags & SECTOR_CRC_ERROR) && (dev->state != STATE_02_READ_DATA)) { #ifdef ENABLE_D86F_LOG - d86f_log("86F: Data CRC error in turbo mode\n"); + d86f_log("86F: Data CRC error in turbo mode (%02X)\n", dev->state); #endif dev->error_condition = 0; dev->state = STATE_IDLE; fdc_finishread(d86f_fdc); fdc_datacrcerror(d86f_fdc); - } else if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state == STATE_02_READ_DATA)) { + } else if ((flags & SECTOR_CRC_ERROR) && (dev->state == STATE_02_READ_DATA)) { +#ifdef ENABLE_D86F_LOG + d86f_log("86F: Data CRC error in turbo mode at READ TRACK command\n"); +#endif dev->error_condition |= 2; /* Mark that there was a data error. */ dev->state = STATE_IDLE; fdc_track_finishread(d86f_fdc, dev->error_condition); } else { /* CRC is valid. */ #ifdef ENABLE_D86F_LOG - d86f_log("86F: Data CRC OK error in turbo mode\n"); + d86f_log("86F: Data CRC OK in turbo mode\n"); #endif dev->error_condition = 0; dev->state = STATE_IDLE; @@ -2250,10 +2225,10 @@ d86f_turbo_format(int drive, int side, int nop) dat &= 0xff; if ((dat == -1) && (dev->datac < 3)) dat = 0; - dev->format_sector_id.byte_array[dev->datac] = dat & 0xff; + d86f_fdc->format_sector_id.byte_array[dev->datac] = dat & 0xff; if (dev->datac == 3) { fdc_stop_id_request(d86f_fdc); - d86f_handler[drive].set_sector(drive, side, dev->format_sector_id.id.c, dev->format_sector_id.id.h, dev->format_sector_id.id.r, dev->format_sector_id.id.n); + d86f_handler[drive].set_sector(drive, side, d86f_fdc->format_sector_id.id.c, d86f_fdc->format_sector_id.id.h, d86f_fdc->format_sector_id.id.r, d86f_fdc->format_sector_id.id.n); } } else if (dev->datac == 4) { if (! nop) { @@ -2318,7 +2293,6 @@ d86f_turbo_poll(int drive, int side) switch(dev->state) { case STATE_0D_SPIN_TO_INDEX: - case STATE_0D_NOP_SPIN_TO_INDEX: dev->sector_count = 0; dev->datac = 5; /*FALLTHROUGH*/ @@ -2413,11 +2387,7 @@ d86f_turbo_poll(int drive, int side) break; case STATE_0D_FORMAT_TRACK: - d86f_turbo_format(drive, side, 0); - return; - - case STATE_0D_NOP_FORMAT_TRACK: - d86f_turbo_format(drive, side, 1); + d86f_turbo_format(drive, side, (side && (d86f_get_sides(drive) != 2))); return; case STATE_IDLE: @@ -2461,7 +2431,6 @@ d86f_poll(int drive) switch(dev->state) { case STATE_02_SPIN_TO_INDEX: case STATE_0D_SPIN_TO_INDEX: - case STATE_0D_NOP_SPIN_TO_INDEX: d86f_spin_to_index(drive, side); return; @@ -2548,12 +2517,7 @@ d86f_poll(int drive) case STATE_0D_FORMAT_TRACK: if (! (dev->track_pos & 15)) - d86f_format_track_normal(drive, side); - return; - - case STATE_0D_NOP_FORMAT_TRACK: - if (! (dev->track_pos & 15)) - d86f_format_track_nop(drive, side); + d86f_format_track(drive, side, (!side || (d86f_get_sides(drive) == 2)) && (dev->version == D86FVER)); return; case STATE_IDLE: @@ -2963,9 +2927,9 @@ d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, ui } else fseek(dev->f, dev->track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET); array_size = d86f_get_array_size(drive, side, 0); + fread(da, 1, array_size, dev->f); if (d86f_has_surface_desc(drive)) fread(sa, 1, array_size, dev->f); - fread(da, 1, array_size, dev->f); } else { if (! thin_track) { switch((dev->disk_flags >> 1) & 3) { @@ -3060,10 +3024,10 @@ d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) fwrite(&index_hole_pos, 1, 4, *f); + fwrite(da0, 1, array_size, *f); + if (d86f_has_surface_desc(drive)) fwrite(sa0, 1, array_size, *f); - - fwrite(da0, 1, array_size, *f); } @@ -3100,7 +3064,7 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) fdd_side = fdd_get_head(drive); sides = d86f_get_sides(drive); - if (track_table) + if (track_table != NULL) tbl = track_table; if (!fdd_doublestep_40(drive)) { @@ -3433,10 +3397,7 @@ d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) dev->index_count = dev->error_condition = dev->satisfying_bytes = dev->sector_count = 0; dev->dma_over = 0; - if (!side || (d86f_get_sides(drive) == 2)) - dev->state = STATE_0D_SPIN_TO_INDEX; - else - dev->state = STATE_0D_NOP_SPIN_TO_INDEX; + dev->state = STATE_0D_SPIN_TO_INDEX; } @@ -3469,7 +3430,7 @@ d86f_common_handlers(int drive) int -d86f_export(int drive, wchar_t *fn) +d86f_export(int drive, char *fn) { uint32_t tt[512]; d86f_t *dev = d86f[drive]; @@ -3484,7 +3445,7 @@ d86f_export(int drive, wchar_t *fn) memset(tt, 0, 512 * sizeof(uint32_t)); - f = plat_fopen(fn, L"wb"); + f = plat_fopen(fn, "wb"); if (!f) return 0; @@ -3514,7 +3475,7 @@ d86f_export(int drive, wchar_t *fn) fclose(f); - f = plat_fopen(fn, L"rb+"); + f = plat_fopen(fn, "rb+"); fseek(f, 8, SEEK_SET); fwrite(tt, 1, ((d86f_get_sides(drive) == 2) ? 2048 : 1024), f); @@ -3532,14 +3493,14 @@ d86f_export(int drive, wchar_t *fn) void -d86f_load(int drive, wchar_t *fn) +d86f_load(int drive, char *fn) { d86f_t *dev = d86f[drive]; uint32_t magic = 0; uint32_t len = 0; int i = 0, j = 0; #ifdef D86F_COMPRESS - wchar_t temp_file_name[2048]; + char temp_file_name[2048]; uint16_t temp = 0; FILE *tf; #endif @@ -3548,9 +3509,9 @@ d86f_load(int drive, wchar_t *fn) writeprot[drive] = 0; - dev->f = plat_fopen(fn, L"rb+"); + dev->f = plat_fopen(fn, "rb+"); if (! dev->f) { - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (! dev->f) { memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); free(dev); @@ -3661,13 +3622,13 @@ d86f_load(int drive, wchar_t *fn) #ifdef D86F_COMPRESS if (dev->is_compressed) { - memcpy(temp_file_name, drive ? nvr_path(L"TEMP$$$1.$$$") : nvr_path(L"TEMP$$$0.$$$"), 256); - memcpy(dev->original_file_name, fn, (wcslen(fn) << 1) + 2); + memcpy(temp_file_name, drive ? nvr_path("TEMP$$$1.$$$") : nvr_path("TEMP$$$0.$$$"), 256); + memcpy(dev->original_file_name, fn, strlen(fn) + 1); fclose(dev->f); dev->f = NULL; - dev->f = plat_fopen(temp_file_name, L"wb"); + dev->f = plat_fopen(temp_file_name, "wb"); if (! dev->f) { d86f_log("86F: Unable to create temporary decompressed file\n"); memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); @@ -3675,7 +3636,7 @@ d86f_load(int drive, wchar_t *fn) return; } - tf = plat_fopen(fn, L"rb"); + tf = plat_fopen(fn, "rb"); for (i = 0; i < 8; i++) { fread(&temp, 1, 2, tf); @@ -3704,7 +3665,7 @@ d86f_load(int drive, wchar_t *fn) return; } - dev->f = plat_fopen(temp_file_name, L"rb+"); + dev->f = plat_fopen(temp_file_name, "rb+"); } #endif @@ -3747,10 +3708,10 @@ d86f_load(int drive, wchar_t *fn) #ifdef D86F_COMPRESS if (dev->is_compressed) - dev->f = plat_fopen(temp_file_name, L"rb"); + dev->f = plat_fopen(temp_file_name, "rb"); else #endif - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); } /* OK, set the drive data, other code needs it. */ @@ -3879,13 +3840,13 @@ d86f_close(int drive) { int i, j; - wchar_t temp_file_name[2048]; + char temp_file_name[2048]; d86f_t *dev = d86f[drive]; /* Make sure the drive is alive. */ if (dev == NULL) return; - memcpy(temp_file_name, drive ? nvr_path(L"TEMP$$$1.$$$") : nvr_path(L"TEMP$$$0.$$$"), 26); + memcpy(temp_file_name, drive ? nvr_path("TEMP$$$1.$$$") : nvr_path("TEMP$$$0.$$$"), 26); if (d86f_has_surface_desc(drive)) { for (i = 0; i < 2; i++) { diff --git a/src/floppy/fdd_fdi.c b/src/floppy/fdd_fdi.c index 51891e227..897fcfcdf 100644 --- a/src/floppy/fdd_fdi.c +++ b/src/floppy/fdd_fdi.c @@ -320,7 +320,7 @@ fdi_seek(int drive, int track) void -fdi_load(int drive, wchar_t *fn) +fdi_load(int drive, char *fn) { char header[26]; fdi_t *dev; @@ -339,7 +339,7 @@ fdi_load(int drive, wchar_t *fn) d86f_unregister(drive); - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (fread(header, 1, 25, dev->f) != 25) fatal("fdi_load(): Error reading header\n"); if (fseek(dev->f, 0, SEEK_SET) == -1) diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index 608805b3d..cd76e6204 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -148,8 +148,6 @@ track_is_xdf(int drive, int side, int track) int max_high_id, expected_high_count, expected_low_count; uint8_t *r_map; uint8_t *n_map; - char *data_base; - char *cur_data; effective_sectors = xdf_sectors = high_sectors = low_sectors = 0; @@ -162,7 +160,6 @@ track_is_xdf(int drive, int side, int track) (dev->tracks[track][side].params[3] != 19)) return(0); r_map = (uint8_t *)(dev->buffer + dev->tracks[track][side].r_map_offs); - data_base = dev->buffer + dev->tracks[track][side].data_offs; if (! track) { if (dev->tracks[track][side].params[4] != 2) return(0); @@ -197,7 +194,6 @@ track_is_xdf(int drive, int side, int track) n_map = (uint8_t *) (dev->buffer + dev->tracks[track][side].n_map_offs); - cur_data = data_base; for (i = 0; i < dev->tracks[track][side].params[3]; i++) { effective_sectors++; if (!(r_map[i]) && !(n_map[i])) @@ -207,7 +203,6 @@ track_is_xdf(int drive, int side, int track) xdf_sectors++; dev->xdf_ordered_pos[(int) r_map[i]][side] = i; } - cur_data += (128 << ((uint32_t) n_map[i])); } if ((effective_sectors == 3) && (xdf_sectors == 3)) { @@ -268,14 +263,17 @@ sector_to_buffer(int drive, int track, int side, uint8_t *buffer, int sector, in { imd_t *dev = imd[drive]; int type = dev->buffer[dev->tracks[track][side].sector_data_offs[sector]]; + uint8_t fill_char; if (type == 0) memset(buffer, 0x00, len); else { if (type & 1) memcpy(buffer, &(dev->buffer[dev->tracks[track][side].sector_data_offs[sector] + 1]), len); - else - memset(buffer, dev->buffer[dev->tracks[track][side].sector_data_offs[sector] + 1], len); + else { + fill_char = dev->buffer[dev->tracks[track][side].sector_data_offs[sector] + 1]; + memset(buffer, fill_char, len); + } } } @@ -328,12 +326,15 @@ imd_seek(int drive, int track) d86f_destroy_linked_lists(drive, 0); d86f_destroy_linked_lists(drive, 1); - if (track > dev->track_count) { - d86f_zero_track(drive); + d86f_zero_track(drive); + + if (track > dev->track_count) return; - } for (side = 0; side < dev->sides; side++) { + if (!dev->tracks[track][side].is_present) + continue; + track_rate = dev->current_side_flags[side] & 7; if (!track_rate && (dev->current_side_flags[side] & 0x20)) track_rate = 4; @@ -395,6 +396,7 @@ imd_seek(int drive, int track) ssize = 128 << ((uint32_t) id[3]); sector_to_buffer(drive, track, side, data, actual_sector, ssize); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, 22, track_gap3, flags); track_buf_pos[side] += ssize; @@ -414,11 +416,11 @@ imd_seek(int drive, int track) data = dev->track_buffer[side] + track_buf_pos[side]; type = dev->buffer[dev->tracks[track][side].sector_data_offs[ordered_pos]]; - type = (type >> 1) & 7; + type = ((type - 1) >> 1) & 7; flags = 0x00; - if ((type == 2) || (type == 4)) + if (type & 0x01) flags |= SECTOR_DELETED_DATA; - if ((type == 3) || (type == 4)) + if (type & 0x02) flags |= SECTOR_CRC_ERROR; if (((flags & 0x02) || (id[3] > dev->tracks[track][side].max_sector_size)) && !fdd_get_turbo(drive)) @@ -548,9 +550,12 @@ poll_read_data(int drive, int side, uint16_t pos) imd_t *dev = imd[drive]; int type = dev->current_data[side][0]; - if (! (type & 1)) return(0xf6); /* Should never happen. */ + if ((type == 0) || (type > 8)) return(0xf6); /* Should never happen. */ - return(dev->current_data[side][pos + 1]); + if (type & 1) + return(dev->current_data[side][pos + 1]); + else + return(dev->current_data[side][1]); } @@ -562,7 +567,7 @@ poll_write_data(int drive, int side, uint16_t pos, uint8_t data) if (writeprot[drive]) return; - if (! (type & 1)) return; /* Should never happen. */ + if ((type & 1) || (type == 0) || (type > 8)) return; /* Should never happen. */ dev->current_data[side][pos + 1] = data; } @@ -591,7 +596,7 @@ imd_init(void) void -imd_load(int drive, wchar_t *fn) +imd_load(int drive, char *fn) { uint32_t magic = 0; uint32_t fsize = 0; @@ -624,9 +629,9 @@ imd_load(int drive, wchar_t *fn) dev = (imd_t *)malloc(sizeof(imd_t)); memset(dev, 0x00, sizeof(imd_t)); - dev->f = plat_fopen(fn, L"rb+"); + dev->f = plat_fopen(fn, "rb+"); if (dev->f == NULL) { - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (dev->f == NULL) { memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); free(dev); @@ -733,7 +738,7 @@ imd_load(int drive, wchar_t *fn) dev->tracks[track][side].max_sector_size = 5; if (!mfm) dev->tracks[track][side].max_sector_size--; - /* imd_log("Side flags for (%02i)(%01i): %02X\n", track, side, dev->tracks[track][side].side_flags); */ + imd_log("Side flags for (%02i)(%01i): %02X\n", track, side, dev->tracks[track][side].side_flags); dev->tracks[track][side].is_present = 1; dev->tracks[track][side].file_offs = (buffer2 - buffer); memcpy(dev->tracks[track][side].params, buffer2, 5); @@ -750,7 +755,12 @@ imd_load(int drive, wchar_t *fn) last_offset += track_spt; } - if (sector_size == 0xFF) { + if (track_spt == 0x00) { + dev->tracks[track][side].n_map_offs = last_offset; + buffer2 = buffer + last_offset; + last_offset += track_spt; + dev->tracks[track][side].is_present = 0; + } else if (sector_size == 0xFF) { dev->tracks[track][side].n_map_offs = last_offset; buffer2 = buffer + last_offset; last_offset += track_spt; @@ -762,17 +772,29 @@ imd_load(int drive, wchar_t *fn) data_size = 128 << data_size; dev->tracks[track][side].sector_data_offs[i] = last_offset; dev->tracks[track][side].sector_data_size[i] = 1; + if (dev->buffer[dev->tracks[track][side].sector_data_offs[i]] > 0x08) { + /* Invalid sector data type, possibly a malformed HxC IMG image (it outputs data errored + sectors with a variable amount of bytes, against the specification). */ + imd_log("IMD: Invalid sector data type %02X\n", dev->buffer[dev->tracks[track][side].sector_data_offs[i]]); + fclose(dev->f); + free(dev); + imd[drive] = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } if (buffer[dev->tracks[track][side].sector_data_offs[i]] != 0) dev->tracks[track][side].sector_data_size[i] += (buffer[dev->tracks[track][side].sector_data_offs[i]] & 1) ? data_size : 1; last_offset += dev->tracks[track][side].sector_data_size[i]; if (!(buffer[dev->tracks[track][side].sector_data_offs[i]] & 1)) fwriteprot[drive] = writeprot[drive] = 1; type = dev->buffer[dev->tracks[track][side].sector_data_offs[i]]; - type = (type >> 1) & 7; - if ((type == 3) || (type == 4) || (data_size > (128 << dev->tracks[track][side].max_sector_size))) - track_total += (pre_sector + 3); - else - track_total += (pre_sector + data_size + 2); + if (type != 0x00) { + type = ((type - 1) >> 1) & 7; + if (data_size > (128 << dev->tracks[track][side].max_sector_size)) + track_total += (pre_sector + 3); + else + track_total += (pre_sector + data_size + 2); + } } } else { dev->tracks[track][side].data_offs = last_offset; @@ -782,19 +804,32 @@ imd_load(int drive, wchar_t *fn) data_size = 128 << data_size; dev->tracks[track][side].sector_data_offs[i] = last_offset; dev->tracks[track][side].sector_data_size[i] = 1; + if (dev->buffer[dev->tracks[track][side].sector_data_offs[i]] > 0x08) { + /* Invalid sector data type, possibly a malformed HxC IMG image (it outputs data errored + sectors with a variable amount of bytes, against the specification). */ + imd_log("IMD: Invalid sector data type %02X\n", dev->buffer[dev->tracks[track][side].sector_data_offs[i]]); + fclose(dev->f); + free(dev); + imd[drive] = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } if (buffer[dev->tracks[track][side].sector_data_offs[i]] != 0) dev->tracks[track][side].sector_data_size[i] += (buffer[dev->tracks[track][side].sector_data_offs[i]] & 1) ? data_size : 1; last_offset += dev->tracks[track][side].sector_data_size[i]; if (!(buffer[dev->tracks[track][side].sector_data_offs[i]] & 1)) fwriteprot[drive] = writeprot[drive] = 1; type = dev->buffer[dev->tracks[track][side].sector_data_offs[i]]; - type = (type >> 1) & 7; - if ((type == 3) || (type == 4) || (sector_size > dev->tracks[track][side].max_sector_size)) - track_total += (pre_sector + 3); - else - track_total += (pre_sector + data_size + 2); + if (type != 0x00) { + type = ((type - 1) >> 1) & 7; + if (data_size > (128 << dev->tracks[track][side].max_sector_size)) + track_total += (pre_sector + 3); + else + track_total += (pre_sector + data_size + 2); + } } } + buffer2 = buffer + last_offset; /* Leaving even GAP4: 80 : 40 */ @@ -810,7 +845,7 @@ imd_load(int drive, wchar_t *fn) else converted_rate = dev->tracks[track][side].side_flags & 0x03; - if (gap3_sizes[converted_rate][sector_size][track_spt] == 0x00) { + if ((track_spt != 0x00) && (gap3_sizes[converted_rate][sector_size][track_spt] == 0x00)) { size_diff = raw_tsize - track_total; gap_sum = minimum_gap3 + minimum_gap4; if (size_diff < gap_sum) { @@ -831,7 +866,7 @@ imd_load(int drive, wchar_t *fn) } dev->tracks[track][side].gap3_len = (size_diff - minimum_gap4) / track_spt; - } else if (gap3_sizes[converted_rate][sector_size][track_spt] != 0x00) + } else if ((track_spt == 0x00) || (gap3_sizes[converted_rate][sector_size][track_spt] != 0x00)) dev->tracks[track][side].gap3_len = gap3_sizes[converted_rate][sector_size][track_spt]; /* imd_log("GAP3 length for (%02i)(%01i): %i bytes\n", track, side, dev->tracks[track][side].gap3_len); */ @@ -839,7 +874,8 @@ imd_load(int drive, wchar_t *fn) if (track > dev->track_count) dev->track_count = track; - if (last_offset >= fsize) break; + if (last_offset >= fsize) + break; } /* If more than 43 tracks, then the tracks are thin (96 tpi). */ diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 2c008f7f9..722a25af9 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -33,6 +33,7 @@ #include <86box/86box.h> #include <86box/timer.h> #include <86box/config.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/fdd.h> #include <86box/fdd_86f.h> @@ -54,8 +55,8 @@ typedef struct { uint8_t gap3_size; uint16_t disk_flags; uint16_t track_flags; - uint8_t sector_pos_side[2][256]; - uint16_t sector_pos[2][256]; + uint8_t sector_pos_side[256][256]; + uint16_t sector_pos[256][256]; uint8_t current_sector_pos_side; uint16_t current_sector_pos; uint8_t *disk_data; @@ -70,7 +71,7 @@ static img_t *img[FDD_NUM]; static fdc_t *img_fdc; static double bit_rate_300; -static wchar_t *ext; +static char *ext; static uint8_t first_byte, second_byte, third_byte, @@ -398,7 +399,7 @@ write_back(int drive) if (dev->f == NULL) return; if (dev->disk_at_once) return; - + if (fseek(dev->f, dev->base + (dev->track * dev->sectors * ssize * dev->sides), SEEK_SET) == -1) pclog("IMG write_back(): Error seeking to the beginning of the file\n"); for (side = 0; side < dev->sides; side++) { @@ -621,7 +622,7 @@ is_divisible(uint16_t total, uint8_t what) void -img_load(int drive, wchar_t *fn) +img_load(int drive, char *fn) { uint16_t bpb_bps; uint16_t bpb_total; @@ -644,7 +645,7 @@ img_load(int drive, wchar_t *fn) int size; int i; - ext = plat_get_extension(fn); + ext = path_get_extension(fn); d86f_unregister(drive); @@ -654,9 +655,9 @@ img_load(int drive, wchar_t *fn) dev = (img_t *)malloc(sizeof(img_t)); memset(dev, 0x00, sizeof(img_t)); - dev->f = plat_fopen(fn, L"rb+"); + dev->f = plat_fopen(fn, "rb+"); if (dev->f == NULL) { - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (dev->f == NULL) { free(dev); memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); @@ -673,13 +674,13 @@ img_load(int drive, wchar_t *fn) dev->interleave = dev->skew = 0; - if (! wcscasecmp(ext, L"DDI")) { + if (! strcasecmp(ext, "DDI")) { ddi = 1; dev->base = 0x2400; } else dev->base = 0; - if (! wcscasecmp(ext, L"FDI")) { + if (! strcasecmp(ext, "FDI")) { /* This is a Japanese FDI image, so let's read the header */ img_log("img_load(): File is a Japanese FDI image...\n"); fseek(dev->f, 0x10, SEEK_SET); @@ -721,7 +722,7 @@ img_load(int drive, wchar_t *fn) img_log("img_load(): File is a FDF image...\n"); fwriteprot[drive] = writeprot[drive] = 1; fclose(dev->f); - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); fdf = 1; cqm = 0; @@ -861,7 +862,7 @@ img_load(int drive, wchar_t *fn) img_log("img_load(): File is a CopyQM image...\n"); fwriteprot[drive] = writeprot[drive] = 1; fclose(dev->f); - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); fseek(dev->f, 0x03, SEEK_SET); fread(&bpb_bps, 1, 2, dev->f); diff --git a/src/floppy/fdd_json.c b/src/floppy/fdd_json.c index abdcc28f6..69252e1c8 100644 --- a/src/floppy/fdd_json.c +++ b/src/floppy/fdd_json.c @@ -108,6 +108,7 @@ typedef struct { static json_t *images[FDD_NUM]; +#define ENABLE_JSON_LOG 1 #ifdef ENABLE_JSON_LOG int json_do_log = ENABLE_JSON_LOG; @@ -247,9 +248,9 @@ load_image(json_t *dev) switch(state) { case 0: /* read level header */ dev->dmf = 1; - if (c != '[') { + if ((c != '[') && (c != '{') && (c != '\r') && (c != '\n')) { state = unexpect(c, state, level); - } else { + } else if (c == '[') { if (++level == 3) state++; } @@ -522,7 +523,7 @@ json_init(void) void -json_load(int drive, wchar_t *fn) +json_load(int drive, char *fn) { double bit_rate; int temp_rate; @@ -538,10 +539,10 @@ json_load(int drive, wchar_t *fn) memset(dev, 0x00, sizeof(json_t)); /* Open the image file. */ - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (dev->f == NULL) { free(dev); - memset(fn, 0x00, sizeof(wchar_t)); + memset(fn, 0x00, sizeof(char)); return; } @@ -557,11 +558,11 @@ json_load(int drive, wchar_t *fn) (void)fclose(dev->f); free(dev); images[drive] = NULL; - memset(fn, 0x00, sizeof(wchar_t)); + memset(fn, 0x00, sizeof(char)); return; } - json_log("JSON(%d): %ls (%i tracks, %i sides, %i sectors)\n", + json_log("JSON(%d): %s (%i tracks, %i sides, %i sectors)\n", drive, fn, dev->tracks, dev->sides, dev->spt[0][0]); /* @@ -623,7 +624,7 @@ json_load(int drive, wchar_t *fn) dev->f = NULL; free(dev); images[drive] = NULL; - memset(fn, 0x00, sizeof(wchar_t)); + memset(fn, 0x00, sizeof(char)); return; } @@ -645,7 +646,7 @@ json_load(int drive, wchar_t *fn) dev->f = NULL; free(dev); images[drive] = NULL; - memset(fn, 0x00, sizeof(wchar_t)); + memset(fn, 0x00, sizeof(char)); return; } diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c index 0bf7d47a9..a16314ba2 100644 --- a/src/floppy/fdd_mfm.c +++ b/src/floppy/fdd_mfm.c @@ -398,7 +398,7 @@ mfm_seek(int drive, int track) void -mfm_load(int drive, wchar_t *fn) +mfm_load(int drive, char *fn) { mfm_t *dev; double dbr; @@ -410,7 +410,7 @@ mfm_load(int drive, wchar_t *fn) dev = (mfm_t *)malloc(sizeof(mfm_t)); memset(dev, 0x00, sizeof(mfm_t)); - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (dev->f == NULL) { free(dev); memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index 118471185..6fa4ab96d 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -1121,6 +1121,7 @@ td0_seek(int drive, int track) id[1] = dev->sects[track][side][actual_sector].head; id[2] = real_sector; id[3] = dev->sects[track][side][actual_sector].size; + pclog("track %i, side %i, %i,%i,%i,%i %i\n", track, side, id[0], id[1], id[2], id[3], dev->sects[track][side][actual_sector].flags); fm = dev->sects[track][side][actual_sector].fm; if (((dev->sects[track][side][actual_sector].flags & 0x42) || (id[3] > (dev->max_sector_size - fm))) && !fdd_get_turbo(drive)) ssize = 3; @@ -1190,7 +1191,7 @@ td0_abort(int drive) void -td0_load(int drive, wchar_t *fn) +td0_load(int drive, char *fn) { td0_t *dev; uint32_t i; @@ -1203,7 +1204,7 @@ td0_load(int drive, wchar_t *fn) memset(dev, 0x00, sizeof(td0_t)); td0[drive] = dev; - dev->f = plat_fopen(fn, L"rb"); + dev->f = plat_fopen(fn, "rb"); if (dev->f == NULL) { memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); return; diff --git a/src/floppy/fdi2raw.c b/src/floppy/fdi2raw.c index ffa722d74..04c422d21 100644 --- a/src/floppy/fdi2raw.c +++ b/src/floppy/fdi2raw.c @@ -2209,4 +2209,3 @@ int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int trac } return outlen; } - diff --git a/src/floppy/lzf/LICENSE b/src/floppy/lzf/LICENSE index ee54ff717..b3a284d08 100644 --- a/src/floppy/lzf/LICENSE +++ b/src/floppy/lzf/LICENSE @@ -24,4 +24,3 @@ OF THE POSSIBILITY OF SUCH DAMAGE. Alternatively, the following files carry an additional notice that explicitly allows relicensing under the GPLv2: lzf.c lzf.h lzfP.h lzf_c.c lzf_d.c - diff --git a/src/floppy/lzf/README b/src/floppy/lzf/README index 0734ebe06..ebfd97e07 100644 --- a/src/floppy/lzf/README +++ b/src/floppy/lzf/README @@ -25,5 +25,3 @@ DESCRIPTION AUTHOR This library was written by Marc Lehmann (See also http://software.schmorp.de/pkg/liblzf). - - diff --git a/src/floppy/lzf/crc32.h b/src/floppy/lzf/crc32.h index cf8f6d409..5a88cd5ff 100644 --- a/src/floppy/lzf/crc32.h +++ b/src/floppy/lzf/crc32.h @@ -62,4 +62,3 @@ static const u32 crc_32_tab[] = #define crc32(crc,byte) (crc_32_tab[(u8)(crc) ^ (u8)(byte)] ^ ((crc) >> 8)) #endif - diff --git a/src/floppy/lzf/lzf.c b/src/floppy/lzf/lzf.c index bedfdb6fe..657bc4b04 100644 --- a/src/floppy/lzf/lzf.c +++ b/src/floppy/lzf/lzf.c @@ -1,16 +1,16 @@ /* * Copyright (c) 2006 Stefan Traby - * + * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -534,4 +534,3 @@ main (int argc, char *argv[]) exit (rc ? 1 : 0); } - diff --git a/src/floppy/lzf/lzf.h b/src/floppy/lzf/lzf.h index 919b6e6be..061d4cea9 100644 --- a/src/floppy/lzf/lzf.h +++ b/src/floppy/lzf/lzf.h @@ -1,16 +1,16 @@ /* * Copyright (c) 2000-2008 Marc Alexander Lehmann - * + * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -73,7 +73,7 @@ * and lzf_c.c. * */ -unsigned int +unsigned int lzf_compress (const void *const in_data, unsigned int in_len, void *out_data, unsigned int out_len); @@ -92,9 +92,8 @@ lzf_compress (const void *const in_data, unsigned int in_len, * * This function is very fast, about as fast as a copying loop. */ -unsigned int +unsigned int lzf_decompress (const void *const in_data, unsigned int in_len, void *out_data, unsigned int out_len); #endif - diff --git a/src/floppy/lzf/lzfP.h b/src/floppy/lzf/lzfP.h index 11c965ca3..6bb81d562 100644 --- a/src/floppy/lzf/lzfP.h +++ b/src/floppy/lzf/lzfP.h @@ -1,16 +1,16 @@ /* * Copyright (c) 2000-2007 Marc Alexander Lehmann - * + * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -182,4 +182,3 @@ typedef LZF_HSLOT LZF_STATE[1 << (HLOG)]; #endif #endif - diff --git a/src/floppy/lzf/lzf_c.c b/src/floppy/lzf/lzf_c.c index 8ba4d0b84..8a52d68c0 100644 --- a/src/floppy/lzf/lzf_c.c +++ b/src/floppy/lzf/lzf_c.c @@ -1,16 +1,16 @@ /* * Copyright (c) 2000-2010 Marc Alexander Lehmann - * + * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -290,4 +290,3 @@ lzf_compress (const void *const in_data, unsigned int in_len, return op - (u8 *)out_data; } - diff --git a/src/floppy/lzf/lzf_d.c b/src/floppy/lzf/lzf_d.c index 8433b8f1f..f838ba674 100644 --- a/src/floppy/lzf/lzf_d.c +++ b/src/floppy/lzf/lzf_d.c @@ -1,16 +1,16 @@ /* * Copyright (c) 2000-2010 Marc Alexander Lehmann - * + * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -52,7 +52,7 @@ #endif #endif -unsigned int +unsigned int lzf_decompress (const void *const in_data, unsigned int in_len, void *out_data, unsigned int out_len) { @@ -182,4 +182,3 @@ lzf_decompress (const void *const in_data, unsigned int in_len, return op - (u8 *)out_data; } - diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt new file mode 100644 index 000000000..ee78c2650 --- /dev/null +++ b/src/game/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(game OBJECT gameport.c joystick_standard.c + joystick_ch_flightstick_pro.c joystick_sw_pad.c joystick_tm_fcs.c) diff --git a/src/game/gameport.c b/src/game/gameport.c index b9b418eeb..5f845b485 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 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 VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of a generic Game Port. * @@ -12,27 +12,11 @@ * * Authors: Miran Grca, * Sarah Walker, + * RichardG, * * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2021 RichardG. */ #include #include @@ -45,289 +29,686 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/timer.h> +#include <86box/isapnp.h> #include <86box/gameport.h> #include <86box/joystick_ch_flightstick_pro.h> #include <86box/joystick_standard.h> #include <86box/joystick_sw_pad.h> #include <86box/joystick_tm_fcs.h> - typedef struct { pc_timer_t timer; int axis_nr; - struct _gameport_ *gameport; + struct _joystick_instance_ *joystick; } g_axis_t; typedef struct _gameport_ { - uint8_t state; - - g_axis_t axis[4]; - - const joystick_if_t *joystick; - void *joystick_dat; + uint16_t addr; + uint8_t len; + struct _joystick_instance_ *joystick; + struct _gameport_ *next; } gameport_t; +typedef struct _joystick_instance_ { + uint8_t state; + g_axis_t axis[4]; -int joystick_type; + const joystick_if_t *intf; + void *dat; +} joystick_instance_t; +int joystick_type = 0; static const joystick_if_t joystick_none = { - "No joystick", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0 + .name = "None", + .internal_name = "none", + .init = NULL, + .close = NULL, + .read = NULL, + .write = NULL, + .read_axis = NULL, + .a0_over = NULL, + .axis_count = 0, + .button_count = 0, + .pov_count = 0, + .max_joysticks = 0, + .axis_names = { NULL }, + .button_names = { NULL }, + .pov_names = { NULL } }; - -static const joystick_if_t *joystick_list[] = { - &joystick_standard, - &joystick_standard_4button, - &joystick_standard_6button, - &joystick_standard_8button, - &joystick_4axis_4button, - &joystick_ch_flightstick_pro, - &joystick_sw_pad, - &joystick_tm_fcs, - &joystick_none, - NULL +static const struct { + const joystick_if_t *joystick; +} joysticks[] = { + { &joystick_none }, + { &joystick_2axis_2button }, + { &joystick_2axis_4button }, + { &joystick_2axis_6button }, + { &joystick_2axis_8button }, + { &joystick_3axis_2button }, + { &joystick_3axis_4button }, + { &joystick_4axis_4button }, + { &joystick_ch_flightstick_pro }, + { &joystick_sw_pad }, + { &joystick_tm_fcs }, + { NULL } }; -static gameport_t *gameport_global = NULL; +static joystick_instance_t *joystick_instance = NULL; + +static uint8_t gameport_pnp_rom[] = { + 0x09, 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0002, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x09, 0x00, 'G', 'a', 'm', 'e', ' ', 'P', 'o', 'r', 't', /* ANSI identifier */ + + 0x15, 0x09, 0xf8, 0x00, 0x02, 0x01, /* logical device BOX0002, can participate in boot */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; +static const isapnp_device_config_t gameport_pnp_defaults[] = { + { + .activate = 1, + .io = { { .base = 0x200 }, } + } +}; + +const device_t *standalone_gameport_type; +int gameport_instance_id = 0; +/* Linked list of active game ports. Only the top port responds to reads + or writes, and ports at the standard 200h location are prioritized. */ +static gameport_t *active_gameports = NULL; char * joystick_get_name(int js) { - if (! joystick_list[js]) - return(NULL); - return((char *)joystick_list[js]->name); + if (!joysticks[js].joystick) + return NULL; + return (char *) joysticks[js].joystick->name; } +char * +joystick_get_internal_name(int js) +{ + if (joysticks[js].joystick == NULL) + return ""; + + return (char *) joysticks[js].joystick->internal_name; +} + +int +joystick_get_from_internal_name(char *s) +{ + int c = 0; + + while (joysticks[c].joystick != NULL) { + if (!strcmp((char *) joysticks[c].joystick->internal_name, s)) + return c; + c++; + } + + return 0; +} int joystick_get_max_joysticks(int js) { - return(joystick_list[js]->max_joysticks); + return joysticks[js].joystick->max_joysticks; } - int joystick_get_axis_count(int js) { - return(joystick_list[js]->axis_count); + return joysticks[js].joystick->axis_count; } - int joystick_get_button_count(int js) { - return(joystick_list[js]->button_count); + return joysticks[js].joystick->button_count; } - int joystick_get_pov_count(int js) { - return(joystick_list[js]->pov_count); + return joysticks[js].joystick->pov_count; } - char * joystick_get_axis_name(int js, int id) { - return((char *)joystick_list[js]->axis_names[id]); + return (char *) joysticks[js].joystick->axis_names[id]; } - char * joystick_get_button_name(int js, int id) { - return((char *)joystick_list[js]->button_names[id]); + return (char *) joysticks[js].joystick->button_names[id]; } - char * joystick_get_pov_name(int js, int id) { - return (char *)joystick_list[js]->pov_names[id]; + return (char *) joysticks[js].joystick->pov_names[id]; } - static void -gameport_time(gameport_t *gameport, int nr, int axis) +gameport_time(joystick_instance_t *joystick, int nr, int axis) { if (axis == AXIS_NOT_PRESENT) - timer_disable(&gameport->axis[nr].timer); + timer_disable(&joystick->axis[nr].timer); else { + /* Convert axis value to 555 timing. */ axis += 32768; - axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 100) / 65; /* axis now in ohms */ axis = (axis * 11) / 1000; - timer_set_delay_u64(&gameport->axis[nr].timer, TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/ + timer_set_delay_u64(&joystick->axis[nr].timer, TIMER_USEC * (axis + 24)); /* max = 11.115 ms */ } } - static void gameport_write(uint16_t addr, uint8_t val, void *priv) { - gameport_t *p = (gameport_t *)priv; + gameport_t *dev = (gameport_t *) priv; + joystick_instance_t *joystick = dev->joystick; - p->state |= 0x0f; + /* Respond only if a joystick is present and this port is at the top of the active ports list. */ + if (!joystick || (active_gameports != dev)) + return; - gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0)); - gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1)); - gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2)); - gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3)); - - p->joystick->write(p->joystick_dat); + /* Read all axes. */ + joystick->state |= 0x0f; - sub_cycles(ISA_CYCLES(8)); + gameport_time(joystick, 0, joystick->intf->read_axis(joystick->dat, 0)); + gameport_time(joystick, 1, joystick->intf->read_axis(joystick->dat, 1)); + gameport_time(joystick, 2, joystick->intf->read_axis(joystick->dat, 2)); + gameport_time(joystick, 3, joystick->intf->read_axis(joystick->dat, 3)); + + /* Notify the interface. */ + joystick->intf->write(joystick->dat); + + cycles -= ISA_CYCLES(8); } - static uint8_t gameport_read(uint16_t addr, void *priv) { - gameport_t *p = (gameport_t *)priv; - uint8_t ret; + gameport_t *dev = (gameport_t *) priv; + joystick_instance_t *joystick = dev->joystick; - ret = p->state | p->joystick->read(p->joystick_dat); + /* Respond only if a joystick is present and this port is at the top of the active ports list. */ + if (!joystick || (active_gameports != dev)) + return 0xff; - sub_cycles(ISA_CYCLES(8)); + /* Merge axis state with button state. */ + uint8_t ret = joystick->state | joystick->intf->read(joystick->dat); - return(ret); + cycles -= ISA_CYCLES(8); + + return ret; } - static void timer_over(void *priv) { - g_axis_t *axis = (g_axis_t *)priv; - gameport_t *p = axis->gameport; + g_axis_t *axis = (g_axis_t *) priv; - p->state &= ~(1 << axis->axis_nr); + axis->joystick->state &= ~(1 << axis->axis_nr); - if (axis == &p->axis[0]) - p->joystick->a0_over(p->joystick_dat); + /* Notify the joystick when the first axis' period is finished. */ + if (axis == &axis->joystick->axis[0]) + axis->joystick->intf->a0_over(axis->joystick->dat); } - -static void * -init_common(void) -{ - gameport_t *p = malloc(sizeof(gameport_t)); - - memset(p, 0x00, sizeof(gameport_t)); - - p->axis[0].gameport = p; - p->axis[1].gameport = p; - p->axis[2].gameport = p; - p->axis[3].gameport = p; - - p->axis[0].axis_nr = 0; - p->axis[1].axis_nr = 1; - p->axis[2].axis_nr = 2; - p->axis[3].axis_nr = 3; - - timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0); - timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0); - timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0); - timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0); - - p->joystick = joystick_list[joystick_type]; - p->joystick_dat = p->joystick->init(); - - gameport_global = p; - - return(p); -} - - void gameport_update_joystick_type(void) { - gameport_t *p = gameport_global; + /* Add a standalone game port if a joystick is enabled but no other game ports exist. */ + if (standalone_gameport_type) + gameport_add(standalone_gameport_type); - if (p != NULL) { - p->joystick->close(p->joystick_dat); - p->joystick = joystick_list[joystick_type]; - p->joystick_dat = p->joystick->init(); + /* Reset the joystick interface. */ + if (joystick_instance) { + joystick_instance->intf->close(joystick_instance->dat); + joystick_instance->intf = joysticks[joystick_type].joystick; + joystick_instance->dat = joystick_instance->intf->init(); } } +void +gameport_remap(void *priv, uint16_t address) +{ + gameport_t *dev = (gameport_t *) priv, *other_dev; + + if (dev->addr) { + /* Remove this port from the active ports list. */ + if (active_gameports == dev) { + active_gameports = dev->next; + dev->next = NULL; + } else { + other_dev = active_gameports; + while (other_dev) { + if (other_dev->next == dev) { + other_dev->next = dev->next; + dev->next = NULL; + break; + } + other_dev = other_dev->next; + } + } + + io_removehandler(dev->addr, dev->len, + gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); + } + + dev->addr = address; + + if (dev->addr) { + /* Add this port to the active ports list. */ + if (!active_gameports || ((dev->addr & 0xfff8) == 0x200)) { + /* No ports have been added yet, or port within 200-207h: add to top. */ + dev->next = active_gameports; + active_gameports = dev; + } else { + /* Port at other addresses: add to bottom. */ + other_dev = active_gameports; + while (other_dev->next) + other_dev = other_dev->next; + other_dev->next = dev; + } + + io_sethandler(dev->addr, dev->len, + gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); + } +} + +static void +gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld > 0) + return; + + gameport_t *dev = (gameport_t *) priv; + + /* Remap the game port to the specified address, or disable it. */ + gameport_remap(dev, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); +} + +void * +gameport_add(const device_t *gameport_type) +{ + /* Prevent a standalone game port from being added later on, unless this + is an unused Super I/O game port (no MACHINE_GAMEPORT machine flag). */ + if (!(gameport_type->local & GAMEPORT_SIO) || machine_has_flags(machine, MACHINE_GAMEPORT)) + standalone_gameport_type = NULL; + + /* Add game port device. */ + return device_add_inst(gameport_type, gameport_instance_id++); +} static void * gameport_init(const device_t *info) { - gameport_t *p = NULL; + gameport_t *dev = NULL; - if (joystick_type == JOYSTICK_TYPE_NONE) { - p = NULL; - return(p); + dev = malloc(sizeof(gameport_t)); + memset(dev, 0x00, sizeof(gameport_t)); + + /* Allocate global instance. */ + if (!joystick_instance && joystick_type) { + joystick_instance = malloc(sizeof(joystick_instance_t)); + memset(joystick_instance, 0x00, sizeof(joystick_instance_t)); + + joystick_instance->axis[0].joystick = joystick_instance; + joystick_instance->axis[1].joystick = joystick_instance; + joystick_instance->axis[2].joystick = joystick_instance; + joystick_instance->axis[3].joystick = joystick_instance; + + joystick_instance->axis[0].axis_nr = 0; + joystick_instance->axis[1].axis_nr = 1; + joystick_instance->axis[2].axis_nr = 2; + joystick_instance->axis[3].axis_nr = 3; + + timer_add(&joystick_instance->axis[0].timer, timer_over, &joystick_instance->axis[0], 0); + timer_add(&joystick_instance->axis[1].timer, timer_over, &joystick_instance->axis[1], 0); + timer_add(&joystick_instance->axis[2].timer, timer_over, &joystick_instance->axis[2], 0); + timer_add(&joystick_instance->axis[3].timer, timer_over, &joystick_instance->axis[3], 0); + + joystick_instance->intf = joysticks[joystick_type].joystick; + joystick_instance->dat = joystick_instance->intf->init(); } - p = init_common(); + dev->joystick = joystick_instance; - io_sethandler(0x0200, 8, - gameport_read,NULL,NULL, gameport_write,NULL,NULL, p); + /* Map game port to the default address. Not applicable on PnP-only ports. */ + dev->len = (info->local >> 16) & 0xff; + gameport_remap(dev, info->local & 0xffff); - return(p); + /* Register ISAPnP if this is a standard game port card. */ + if ((info->local & 0xffff) == 0x200) + isapnp_set_device_defaults(isapnp_add_card(gameport_pnp_rom, sizeof(gameport_pnp_rom), gameport_pnp_config_changed, NULL, NULL, NULL, dev), 0, gameport_pnp_defaults); + + return dev; } - static void * -gameport_201_init(const device_t *info) +tmacm_init(const device_t *info) { - gameport_t *p; + uint16_t port = 0x0000; + gameport_t *dev = NULL; - if (joystick_type == JOYSTICK_TYPE_NONE) { - p = NULL; - return(p); + dev = malloc(sizeof(gameport_t)); + memset(dev, 0x00, sizeof(gameport_t)); + + port = device_get_config_hex16("port1_addr"); + switch(port) { + case 0x201: + dev = gameport_add(&gameport_201_device); + break; + case 0x203: + dev = gameport_add(&gameport_203_device); + break; + case 0x205: + dev = gameport_add(&gameport_205_device); + break; + case 0x207: + dev = gameport_add(&gameport_207_device); + break; + default: + break; } - p = init_common(); + port = device_get_config_hex16("port2_addr"); + switch(port) { + case 0x201: + dev = gameport_add(&gameport_209_device); + break; + case 0x203: + dev = gameport_add(&gameport_20b_device); + break; + case 0x205: + dev = gameport_add(&gameport_20d_device); + break; + case 0x207: + dev = gameport_add(&gameport_20f_device); + break; + default: + break; + } - io_sethandler(0x0201, 1, - gameport_read,NULL,NULL, gameport_write,NULL,NULL, p); - - return(p); + return dev; } - static void gameport_close(void *priv) { - gameport_t *p = (gameport_t *)priv; + gameport_t *dev = (gameport_t *) priv; - if (p == NULL) return; + /* If this port was active, remove it from the active ports list. */ + gameport_remap(dev, 0); - p->joystick->close(p->joystick_dat); + /* Free the global instance here, if it wasn't already freed. */ + if (joystick_instance) { + joystick_instance->intf->close(joystick_instance->dat); - gameport_global = NULL; + free(joystick_instance); + joystick_instance = NULL; + } - free(p); + free(dev); } - const device_t gameport_device = { - "Game port", - 0, 0, - gameport_init, - gameport_close, - NULL, NULL, NULL, - NULL + .name = "Game port", + .internal_name = "gameport", + .flags = 0, + .local = 0x080200, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t gameport_201_device = { - "Game port (port 201h only)", - 0, 0, - gameport_201_init, - gameport_close, - NULL, NULL, NULL, - NULL + .name = "Game port (Port 201h only)", + .internal_name = "gameport_201", + .flags = 0, + .local = 0x010201, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_203_device = { + .name = "Game port (Port 203h only)", + .internal_name = "gameport_203", + .flags = 0, + .local = 0x010203, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_205_device = { + .name = "Game port (Port 205h only)", + .internal_name = "gameport_205", + .flags = 0, + .local = 0x010205, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_207_device = { + .name = "Game port (Port 207h only)", + .internal_name = "gameport_207", + .flags = 0, + .local = 0x010207, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_208_device = { + .name = "Game port (Port 208h-20fh)", + .internal_name = "gameport_208", + .flags = 0, + .local = 0x080208, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_209_device = { + .name = "Game port (Port 209h only)", + .internal_name = "gameport_209", + .flags = 0, + .local = 0x010209, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_20b_device = { + .name = "Game port (Port 20Bh only)", + .internal_name = "gameport_20b", + .flags = 0, + .local = 0x01020B, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_20d_device = { + .name = "Game port (Port 20Dh only)", + .internal_name = "gameport_20d", + .flags = 0, + .local = 0x01020D, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_20f_device = { + .name = "Game port (Port 20Fh only)", + .internal_name = "gameport_20f", + .flags = 0, + .local = 0x01020F, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +static const device_config_t tmacm_config[] = { + { + .name = "port1_addr", + .description = "Port 1 Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0201, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "201h", .value = 0x0201 }, + { .description = "203h", .value = 0x0203 }, + { .description = "205h", .value = 0x0205 }, + { .description = "207h", .value = 0x0207 }, + { .description = "Disabled", .value = 0x0000 }, + { "" } + } + }, + { + .name = "port2_addr", + .description = "Port 2 Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0209, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "209h", .value = 0x0209 }, + { .description = "20Bh", .value = 0x020B }, + { .description = "20Dh", .value = 0x020D }, + { .description = "20Fh", .value = 0x020F }, + { .description = "Disabled", .value = 0x0000 }, + { "" } + } + }, + { "", "", -1 } +}; + +const device_t gameport_tm_acm_device = { + .name = "Game port (ThrustMaster ACM)", + .internal_name = "gameport_tmacm", + .flags = DEVICE_ISA, + .local = 0, + .init = tmacm_init, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = tmacm_config +}; + +const device_t gameport_pnp_device = { + .name = "Game port (Plug and Play only)", + .internal_name = "gameport_pnp", + .flags = 0, + .local = 0x080000, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_pnp_6io_device = { + .name = "Game port (Plug and Play only, 6 I/O ports)", + .internal_name = "gameport_pnp_6io", + .flags = 0, + .local = 0x060000, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_sio_device = { + .name = "Game port (Super I/O)", + .internal_name = "gameport_sio", + .flags = 0, + .local = 0x1080000, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t gameport_sio_1io_device = { + .name = "Game port (Super I/O, 1 I/O port)", + .internal_name = "gameport_sio", + .flags = 0, + .local = 0x1010000, + .init = gameport_init, + .close = gameport_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/game/joystick_ch_flightstick_pro.c b/src/game/joystick_ch_flightstick_pro.c index 0faffa7c0..5be3ce50f 100644 --- a/src/game/joystick_ch_flightstick_pro.c +++ b/src/game/joystick_ch_flightstick_pro.c @@ -58,7 +58,7 @@ static void ch_flightstick_pro_close(void *p) static uint8_t ch_flightstick_pro_read(void *p) { uint8_t ret = 0xf0; - + if (JOYSTICK_PRESENT(0)) { if (joystick_state[0].button[0]) @@ -115,18 +115,19 @@ static void ch_flightstick_pro_a0_over(void *p) const joystick_if_t joystick_ch_flightstick_pro = { - "CH Flightstick Pro", - ch_flightstick_pro_init, - ch_flightstick_pro_close, - ch_flightstick_pro_read, - ch_flightstick_pro_write, - ch_flightstick_pro_read_axis, - ch_flightstick_pro_a0_over, - 3, - 4, - 1, - 1, - {"X axis", "Y axis", "Throttle"}, - {"Button 1", "Button 2", "Button 3", "Button 4"}, - {"POV"} + .name = "CH Flightstick Pro", + .internal_name = "ch_flightstick_pro", + .init = ch_flightstick_pro_init, + .close = ch_flightstick_pro_close, + .read = ch_flightstick_pro_read, + .write = ch_flightstick_pro_write, + .read_axis = ch_flightstick_pro_read_axis, + .a0_over = ch_flightstick_pro_a0_over, + .axis_count = 3, + .button_count = 4, + .pov_count = 1, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Throttle" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { "POV" } }; diff --git a/src/game/joystick_standard.c b/src/game/joystick_standard.c index e72d066cb..ce2a72664 100644 --- a/src/game/joystick_standard.c +++ b/src/game/joystick_standard.c @@ -58,7 +58,7 @@ static void joystick_standard_close(void *p) static uint8_t joystick_standard_read(void *p) { uint8_t ret = 0xf0; - + if (JOYSTICK_PRESENT(0)) { if (joystick_state[0].button[0]) @@ -73,14 +73,14 @@ static uint8_t joystick_standard_read(void *p) if (joystick_state[1].button[1]) ret &= ~0x80; } - + return ret; } static uint8_t joystick_standard_read_4button(void *p) { uint8_t ret = 0xf0; - + if (JOYSTICK_PRESENT(0)) { if (joystick_state[0].button[0]) @@ -92,7 +92,7 @@ static uint8_t joystick_standard_read_4button(void *p) if (joystick_state[0].button[3]) ret &= ~0x80; } - + return ret; } @@ -145,6 +145,26 @@ static int joystick_standard_read_axis_4button(void *p, int axis) } } +static int joystick_standard_read_axis_3axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return joystick_state[0].axis[2]; + case 3: + return 0; + default: + return 0; + } +} + static int joystick_standard_read_axis_4axis(void *p, int axis) { if (!JOYSTICK_PRESENT(0)) @@ -198,13 +218,13 @@ static int joystick_standard_read_axis_8button(void *p, int axis) case 2: if (joystick_state[0].button[4]) return -32767; - if (joystick_state[0].button[6]) + if (joystick_state[0].button[6]) return 32768; return 0; case 3: if (joystick_state[0].button[5]) return -32767; - if (joystick_state[0].button[7]) + if (joystick_state[0].button[7]) return 32768; return 0; default: @@ -216,83 +236,128 @@ static void joystick_standard_a0_over(void *p) { } -const joystick_if_t joystick_standard = -{ - "Standard 2-button joystick(s)", - joystick_standard_init, - joystick_standard_close, - joystick_standard_read, - joystick_standard_write, - joystick_standard_read_axis, - joystick_standard_a0_over, - 2, - 2, - 0, - 2, - {"X axis", "Y axis"}, - {"Button 1", "Button 2"} +const joystick_if_t joystick_2axis_2button = { + .name = "2-axis, 2-button joystick(s)", + .internal_name = "2axis_2button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 2, + .pov_count = 0, + .max_joysticks = 2, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2" }, + .pov_names = { NULL } }; -const joystick_if_t joystick_standard_4button = -{ - "Standard 4-button joystick", - joystick_standard_init, - joystick_standard_close, - joystick_standard_read_4button, - joystick_standard_write, - joystick_standard_read_axis_4button, - joystick_standard_a0_over, - 2, - 4, - 0, - 1, - {"X axis", "Y axis"}, - {"Button 1", "Button 2", "Button 3", "Button 4"} + +const joystick_if_t joystick_2axis_4button = { + .name = "2-axis, 4-button joystick", + .internal_name = "2axis_4button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_4button, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } }; -const joystick_if_t joystick_4axis_4button = -{ - "4-axis 4-button joystick", - joystick_standard_init, - joystick_standard_close, - joystick_standard_read_4button, - joystick_standard_write, - joystick_standard_read_axis_4axis, - joystick_standard_a0_over, - 4, - 4, - 0, - 1, - {"X axis", "Y axis", "Z axis", "zX axis"}, - {"Button 1", "Button 2", "Button 3", "Button 4"} + +const joystick_if_t joystick_3axis_2button = { + .name = "3-axis, 2-button joystick", + .internal_name = "3axis_2button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_3axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 3, + .button_count = 2, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Z axis" }, + .button_names = { "Button 1", "Button 2" }, + .pov_names = { NULL } }; -const joystick_if_t joystick_standard_6button = -{ - "Standard 6-button joystick", - joystick_standard_init, - joystick_standard_close, - joystick_standard_read_4button, - joystick_standard_write, - joystick_standard_read_axis_6button, - joystick_standard_a0_over, - 2, - 6, - 0, - 1, - {"X axis", "Y axis"}, - {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"} + +const joystick_if_t joystick_3axis_4button = { + .name = "3-axis, 4-button joystick", + .internal_name = "3axis_4button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_3axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 3, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Z axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } }; -const joystick_if_t joystick_standard_8button = -{ - "Standard 8-button joystick", - joystick_standard_init, - joystick_standard_close, - joystick_standard_read_4button, - joystick_standard_write, - joystick_standard_read_axis_8button, - joystick_standard_a0_over, - 2, - 8, - 0, - 1, - {"X axis", "Y axis"}, - {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8"} + +const joystick_if_t joystick_4axis_4button = { + .name = "4-axis, 4-button joystick", + .internal_name = "4axis_4button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_4axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 4, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Z axis", "zX axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } +}; + +const joystick_if_t joystick_2axis_6button = { + .name = "2-axis, 6-button joystick", + .internal_name = "2axis_6button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_6button, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 6, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6" }, + .pov_names = { NULL } +}; + +const joystick_if_t joystick_2axis_8button = { + .name = "2-axis, 8-button joystick", + .internal_name = "2axis_8button", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_8button, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 8, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8" }, + .pov_names = { NULL } }; diff --git a/src/game/joystick_sw_pad.c b/src/game/joystick_sw_pad.c index b42f0d55a..718eefbb4 100644 --- a/src/game/joystick_sw_pad.c +++ b/src/game/joystick_sw_pad.c @@ -15,7 +15,7 @@ * connected * - Packet preceeded by high data (currently 50us), and * followed by low data (currently 160us) - timings are - * probably wrong, but good enoughfor everything I've tried + * probably wrong, but good enough for everything I've tried * - Analog inputs are only used to time ID packet request. * If A0 timing out is followed after ~64us by another 0x201 * write then an ID packet is triggered @@ -74,7 +74,7 @@ typedef struct int poll_clock; uint64_t poll_data; int poll_mode; - + pc_timer_t trigger_timer; int data_mode; } sw_data; @@ -82,7 +82,7 @@ typedef struct static void sw_timer_over(void *p) { sw_data *sw = (sw_data *)p; - + sw->poll_clock = !sw->poll_clock; if (sw->poll_clock) @@ -109,13 +109,13 @@ static void sw_trigger_timer_over(void *p) static int sw_parity(uint16_t data) { int bits_set = 0; - + while (data) { bits_set++; data &= (data - 1); } - + return bits_set & 1; } @@ -133,7 +133,7 @@ static void *sw_init(void) static void sw_close(void *p) { sw_data *sw = (sw_data *)p; - + free(sw); } @@ -146,10 +146,10 @@ static uint8_t sw_read(void *p) return 0xff; if (timer_is_enabled(&sw->poll_timer)) - { + { if (sw->poll_clock) temp |= 0x10; - + if (sw->poll_mode) temp |= (sw->poll_data & 7) << 5; else @@ -172,19 +172,19 @@ static void sw_write(void *p) if (!JOYSTICK_PRESENT(0)) return; - + timer_process(); if (!sw->poll_left) { sw->poll_clock = 1; timer_set_delay_u64(&sw->poll_timer, TIMER_USEC * 50); - + if (time_since_last > 9900 && time_since_last < 9940) { sw->poll_mode = 0; sw->poll_left = 49; - sw->poll_data = 0x2400ull | (0x1830ull << 15) | (0x19b0ull << 30); + sw->poll_data = 0x2400ull | (0x1830ull << 15) | (0x19b0ull << 30); } else { @@ -192,7 +192,7 @@ static void sw_write(void *p) sw->poll_mode = sw->data_mode; sw->data_mode = !sw->data_mode; - + if (sw->poll_mode) { sw->poll_left = 1; @@ -208,7 +208,7 @@ static void sw_write(void *p) { uint16_t data = 0x3fff; int b; - + if (!JOYSTICK_PRESENT(c)) break; @@ -243,7 +243,7 @@ static void sw_write(void *p) } } } - + timer_disable(&sw->trigger_timer); } @@ -251,7 +251,7 @@ static int sw_read_axis(void *p, int axis) { if (!JOYSTICK_PRESENT(0)) return AXIS_NOT_PRESENT; - + return 0; /*No analogue support on Sidewinder game pad*/ } @@ -259,22 +259,23 @@ static void sw_a0_over(void *p) { sw_data *sw = (sw_data *)p; - timer_set_delay_u64(&sw->trigger_timer, TIMER_USEC * 10000); + timer_set_delay_u64(&sw->trigger_timer, TIMER_USEC * 10000); } - -const joystick_if_t joystick_sw_pad = -{ - "Microsoft SideWinder Pad", - sw_init, - sw_close, - sw_read, - sw_write, - sw_read_axis, - sw_a0_over, - 2, - 10, - 0, - 4, - {"X axis", "Y axis"}, - {"A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M"} + +const joystick_if_t joystick_sw_pad = { + .name = "Microsoft SideWinder Pad", + .internal_name = "sidewinder_pad", + .init = sw_init, + .close = sw_close, + .read = sw_read, + .write = sw_write, + .read_axis = sw_read_axis, + .a0_over = sw_a0_over, + .axis_count = 2, + .button_count = 10, + .pov_count = 0, + .max_joysticks = 4, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M" }, + .pov_names = { NULL } }; diff --git a/src/game/joystick_tm_fcs.c b/src/game/joystick_tm_fcs.c index 9d949f3c3..ee83c5ad2 100644 --- a/src/game/joystick_tm_fcs.c +++ b/src/game/joystick_tm_fcs.c @@ -58,7 +58,7 @@ static void tm_fcs_close(void *p) static uint8_t tm_fcs_read(void *p) { uint8_t ret = 0xf0; - + if (JOYSTICK_PRESENT(0)) { if (joystick_state[0].button[0]) @@ -114,18 +114,19 @@ static void tm_fcs_a0_over(void *p) const joystick_if_t joystick_tm_fcs = { - "Thrustmaster Flight Control System", - tm_fcs_init, - tm_fcs_close, - tm_fcs_read, - tm_fcs_write, - tm_fcs_read_axis, - tm_fcs_a0_over, - 2, - 4, - 1, - 1, - {"X axis", "Y axis"}, - {"Button 1", "Button 2", "Button 3", "Button 4"}, - {"POV"} + .name = "Thrustmaster Flight Control System", + .internal_name = "thrustmaster_fcs", + .init = tm_fcs_init, + .close = tm_fcs_close, + .read = tm_fcs_read, + .write = tm_fcs_write, + .read_axis = tm_fcs_read_axis, + .a0_over = tm_fcs_a0_over, + .axis_count = 2, + .button_count = 4, + .pov_count = 1, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { "POV" } }; diff --git a/src/gdbstub.c b/src/gdbstub.c new file mode 100644 index 000000000..5140d6c54 --- /dev/null +++ b/src/gdbstub.c @@ -0,0 +1,1786 @@ +/* + * 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. + * + * GDB stub server for remote debugging. + * + * + * + * Authors: RichardG, + * + * Copyright 2022 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +#endif +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86seg.h" +#include "x87.h" +#include "x87_ops_conv.h" +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/gdbstub.h> + +#define FAST_RESPONSE(s) \ + strcpy(client->response, s); \ + client->response_pos = sizeof(s) - 1; +#define FAST_RESPONSE_HEX(s) gdbstub_client_respond_hex(client, (uint8_t *) s, sizeof(s)); + +enum { + GDB_SIGINT = 2, + GDB_SIGTRAP = 5 +}; + +enum { + GDB_REG_EAX = 0, + GDB_REG_ECX, + GDB_REG_EDX, + GDB_REG_EBX, + GDB_REG_ESP, + GDB_REG_EBP, + GDB_REG_ESI, + GDB_REG_EDI, + GDB_REG_EIP, + GDB_REG_EFLAGS, + GDB_REG_CS, + GDB_REG_SS, + GDB_REG_DS, + GDB_REG_ES, + GDB_REG_FS, + GDB_REG_GS, + GDB_REG_FS_BASE, + GDB_REG_GS_BASE, + GDB_REG_CR0, + GDB_REG_CR2, + GDB_REG_CR3, + GDB_REG_CR4, + GDB_REG_EFER, + GDB_REG_ST0, + GDB_REG_ST1, + GDB_REG_ST2, + GDB_REG_ST3, + GDB_REG_ST4, + GDB_REG_ST5, + GDB_REG_ST6, + GDB_REG_ST7, + GDB_REG_FCTRL, + GDB_REG_FSTAT, + GDB_REG_FTAG, + GDB_REG_FISEG, + GDB_REG_FIOFF, + GDB_REG_FOSEG, + GDB_REG_FOOFF, + GDB_REG_FOP, + GDB_REG_MM0, + GDB_REG_MM1, + GDB_REG_MM2, + GDB_REG_MM3, + GDB_REG_MM4, + GDB_REG_MM5, + GDB_REG_MM6, + GDB_REG_MM7, + GDB_REG_MAX +}; + +enum { + GDB_MODE_BASE10 = 0, + GDB_MODE_HEX, + GDB_MODE_OCT, + GDB_MODE_BIN +}; + +typedef struct _gdbstub_client_ { + int socket; + struct sockaddr_in addr; + + char packet[16384], response[16384]; + int has_packet, waiting_stop, packet_pos, response_pos; + + event_t *processed_event, *response_event; + + uint16_t last_io_base, last_io_len, last_io_value; + + struct _gdbstub_client_ *next; +} gdbstub_client_t; + +typedef struct _gdbstub_breakpoint_ { + uint32_t addr; + union { + uint8_t orig_val; + uint32_t end; + }; + + struct _gdbstub_breakpoint_ *next; +} gdbstub_breakpoint_t; + +#define ENABLE_GDBSTUB_LOG 1 +#ifdef ENABLE_GDBSTUB_LOG +int gdbstub_do_log = ENABLE_GDBSTUB_LOG; + +static void +gdbstub_log(const char *fmt, ...) +{ + va_list ap; + + if (gdbstub_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define gdbstub_log(fmt, ...) +#endif + +static x86seg *segment_regs[] = { &cpu_state.seg_cs, &cpu_state.seg_ss, &cpu_state.seg_ds, &cpu_state.seg_es, &cpu_state.seg_fs, &cpu_state.seg_gs }; +static uint32_t *cr_regs[] = { &cpu_state.CR0.l, &cr2, &cr3, &cr4 }; +static void *fpu_regs[] = { &cpu_state.npxc, &cpu_state.npxs, NULL, &x87_pc_seg, &x87_pc_off, &x87_op_seg, &x87_op_off }; +static const char target_xml[] = /* QEMU gdb-xml/i386-32bit.xml with modifications (described in comments) */ + // clang-format off + "" + "" + "" + "i8086" /* start in 16-bit mode to work around known GDB bug preventing 32->16 switching */ + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; +// clang-format on + +#ifdef _WIN32 +static WSADATA wsa; +#endif +static int gdbstub_socket = -1, stop_reason_len = 0, in_gdbstub = 0; +static uint32_t watch_addr; +static char stop_reason[2048]; + +static gdbstub_client_t *first_client = NULL, *last_client = NULL; +static mutex_t *client_list_mutex; + +static void (*cpu_exec_shadow)(int cycs); +static gdbstub_breakpoint_t *first_swbreak = NULL, *first_hwbreak = NULL, + *first_rwatch = NULL, *first_wwatch = NULL, *first_awatch = NULL; + +int gdbstub_step = 0, gdbstub_next_asap = 0; +uint64_t gdbstub_watch_pages[(((uint32_t) -1) >> (MEM_GRANULARITY_BITS + 6)) + 1]; + +static void +gdbstub_break() +{ + /* Pause CPU execution as soon as possible. */ + if (gdbstub_step <= GDBSTUB_EXEC) + gdbstub_step = GDBSTUB_BREAK; +} + +static void +gdbstub_jump(uint32_t new_pc) +{ + /* Nasty hack; qemu always uses the full 32-bit EIP internally... */ + if (cpu_state.op32 || ((new_pc >= cs) && (new_pc < (cs + 65536)))) { + cpu_state.pc = new_pc - cs; + } else { + loadseg((new_pc >> 4) & 0xf000, &cpu_state.seg_cs); + cpu_state.pc = new_pc & 0xffff; + } + flushmmucache(); +} + +static inline int +gdbstub_hex_decode(int c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + else if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + else if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + else + return 0; +} + +static inline int +gdbstub_hex_encode(int c) +{ + if (c < 10) + return c + '0'; + else + return c - 10 + 'a'; +} + +static int +gdbstub_num_decode(char *p, int *dest, int mode) +{ + /* Stop if the pointer is invalid. */ + if (!p) + return 0; + + /* Read sign. */ + int sign = 1; + if ((p[0] == '+') || (p[0] == '-')) { + if (p[0] == '-') + sign = -1; + p++; + } + + /* Read type identifer if present (0x/0o/0b/0n) */ + if (p[0] == '0') { + switch (p[1]) { + case 'x': + mode = GDB_MODE_HEX; + break; + + case '0' ... '7': + p -= 1; + /* fall-through */ + + case 'o': + mode = GDB_MODE_OCT; + break; + + case 'b': + mode = GDB_MODE_BIN; + break; + + case 'n': + mode = GDB_MODE_BASE10; + break; + + default: + p -= 2; + break; + } + p += 2; + } + + /* Parse each character. */ + *dest = 0; + while (*p) { + switch (mode) { + case GDB_MODE_BASE10: + if ((*p >= '0') && (*p <= '9')) + *dest = ((*dest) * 10) + ((*p) - '0'); + else + return 0; + break; + + case GDB_MODE_HEX: + if (((*p >= '0') && (*p <= '9')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= 'a') && (*p <= 'f'))) + *dest = ((*dest) << 4) | gdbstub_hex_decode(*p); + else + return 0; + break; + + case GDB_MODE_OCT: + if ((*p >= '0') && (*p <= '7')) + *dest = ((*dest) << 3) | ((*p) - '0'); + else + return 0; + break; + + case GDB_MODE_BIN: + if ((*p == '0') || (*p == '1')) + *dest = ((*dest) << 1) | ((*p) - '0'); + else + return 0; + break; + } + p++; + } + + /* Apply sign. */ + if (sign < 0) + *dest = -(*dest); + + /* Return success. */ + return 1; +} + +static int +gdbstub_client_read_word(gdbstub_client_t *client, int *dest) +{ + char *p = &client->packet[client->packet_pos], *q = p; + while (((*p >= '0') && (*p <= '9')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= 'a') && (*p <= 'f'))) + *dest = ((*dest) << 4) | gdbstub_hex_decode(*p++); + return p - q; +} + +static int +gdbstub_client_read_hex(gdbstub_client_t *client, uint8_t *buf, int size) +{ + int pp = client->packet_pos; + while (size-- && (pp < (sizeof(client->packet) - 2))) { + *buf = gdbstub_hex_decode(client->packet[pp++]) << 4; + *buf++ |= gdbstub_hex_decode(client->packet[pp++]); + } + return pp - client->packet_pos; +} + +static int +gdbstub_client_read_string(gdbstub_client_t *client, char *buf, int size, char terminator) +{ + int pp = client->packet_pos; + char c; + while (size-- && (pp < (sizeof(client->packet) - 1))) { + c = client->packet[pp]; + if ((c == terminator) || (c == '\0')) { + *buf = '\0'; + break; + } + pp++; + *buf++ = c; + } + return pp - client->packet_pos; +} + +static int +gdbstub_client_write_reg(int index, uint8_t *buf) +{ + int width = 4; + switch (index) { + case GDB_REG_EAX ... GDB_REG_EDI: + cpu_state.regs[index - GDB_REG_EAX].l = *((uint32_t *) buf); + break; + + case GDB_REG_EIP: + gdbstub_jump(*((uint32_t *) buf)); + break; + + case GDB_REG_EFLAGS: + cpu_state.flags = *((uint16_t *) &buf[0]); + cpu_state.eflags = *((uint16_t *) &buf[2]); + break; + + case GDB_REG_CS ... GDB_REG_GS: + width = 2; + loadseg(*((uint16_t *) buf), segment_regs[index - GDB_REG_CS]); + flushmmucache(); + break; + + case GDB_REG_FS_BASE ... GDB_REG_GS_BASE: + /* Do what qemu does and just load the base. */ + segment_regs[(index - 16) + (GDB_REG_FS - GDB_REG_CS)]->base = *((uint32_t *) buf); + break; + + case GDB_REG_CR0 ... GDB_REG_CR4: + *cr_regs[index - GDB_REG_CR0] = *((uint32_t *) buf); + flushmmucache(); + break; + + case GDB_REG_EFER: + msr.amd_efer = *((uint64_t *) buf); + break; + + case GDB_REG_ST0 ... GDB_REG_ST7: + width = 10; + x87_conv_t conv = { + .eind = { .ll = *((uint64_t *) &buf[0]) }, + .begin = *((uint16_t *) &buf[8]) + }; + cpu_state.ST[(cpu_state.TOP + (index - GDB_REG_ST0)) & 7] = x87_from80(&conv); + break; + + case GDB_REG_FCTRL: + case GDB_REG_FISEG: + case GDB_REG_FOSEG: + width = 2; + *((uint16_t *) fpu_regs[index - GDB_REG_FCTRL]) = *((uint16_t *) buf); + if (index >= GDB_REG_FISEG) + flushmmucache(); + break; + + case GDB_REG_FSTAT: + case GDB_REG_FOP: + width = 2; + break; + + case GDB_REG_FTAG: + width = 2; + x87_settag(*((uint16_t *) buf)); + break; + + case GDB_REG_FIOFF: + case GDB_REG_FOOFF: + *((uint32_t *) fpu_regs[index - GDB_REG_FCTRL]) = *((uint32_t *) buf); + break; + + case GDB_REG_MM0 ... GDB_REG_MM7: + width = 8; + cpu_state.MM[index - GDB_REG_MM0].q = *((uint64_t *) buf); + break; + + default: + width = 0; + } + +#ifdef ENABLE_GDBSTUB_LOG + char logbuf[256], *p = logbuf + sprintf(logbuf, "GDB Stub: Setting register %d to ", index); + for (int i = width - 1; i >= 0; i--) + p += sprintf(p, "%02X", buf[i]); + sprintf(p, "\n"); + gdbstub_log(logbuf); +#endif + + return width; +} + +static void +gdbstub_client_respond(gdbstub_client_t *client) +{ + /* Calculate checksum. */ + int checksum = 0, i; + for (i = 0; i < client->response_pos; i++) + checksum += client->response[i]; + + /* Send response packet. */ + client->response[client->response_pos] = '\0'; +#ifdef ENABLE_GDBSTUB_LOG + i = client->response[995]; /* pclog_ex buffer too small */ + client->response[995] = '\0'; + gdbstub_log("GDB Stub: Sending response: %s\n", client->response); + client->response[995] = i; +#endif + send(client->socket, "$", 1, 0); + send(client->socket, client->response, client->response_pos, 0); + char response_cksum[3] = { '#', gdbstub_hex_encode((checksum >> 4) & 0x0f), gdbstub_hex_encode(checksum & 0x0f) }; + send(client->socket, response_cksum, sizeof(response_cksum), 0); +} + +static void +gdbstub_client_respond_partial(gdbstub_client_t *client) +{ + /* Send response. */ + gdbstub_client_respond(client); + + /* Wait for the response to be acknowledged. */ + thread_wait_event(client->response_event, -1); + thread_reset_event(client->response_event); +} + +static void +gdbstub_client_respond_hex(gdbstub_client_t *client, uint8_t *buf, int size) +{ + while (size-- && (client->response_pos < (sizeof(client->response) - 2))) { + client->response[client->response_pos++] = gdbstub_hex_encode((*buf) >> 4); + client->response[client->response_pos++] = gdbstub_hex_encode((*buf++) & 0x0f); + } +} + +static int +gdbstub_client_read_reg(int index, uint8_t *buf) +{ + int width = 4; + switch (index) { + case GDB_REG_EAX ... GDB_REG_EDI: + *((uint32_t *) buf) = cpu_state.regs[index].l; + break; + + case GDB_REG_EIP: + *((uint32_t *) buf) = cs + cpu_state.pc; + break; + + case GDB_REG_EFLAGS: + *((uint16_t *) &buf[0]) = cpu_state.flags; + *((uint16_t *) &buf[2]) = cpu_state.eflags; + break; + + case GDB_REG_CS ... GDB_REG_GS: + *((uint16_t *) buf) = segment_regs[index - GDB_REG_CS]->seg; + break; + + case GDB_REG_FS_BASE ... GDB_REG_GS_BASE: + *((uint32_t *) buf) = segment_regs[(index - 16) + (GDB_REG_FS - GDB_REG_CS)]->base; + break; + + case GDB_REG_CR0 ... GDB_REG_CR4: + *((uint32_t *) buf) = *cr_regs[index - GDB_REG_CR0]; + break; + + case GDB_REG_EFER: + *((uint64_t *) buf) = msr.amd_efer; + break; + + case GDB_REG_ST0 ... GDB_REG_ST7: + width = 10; + x87_conv_t conv; + x87_to80(cpu_state.ST[(cpu_state.TOP + (index - GDB_REG_ST0)) & 7], &conv); + *((uint64_t *) &buf[0]) = conv.eind.ll; + *((uint16_t *) &buf[8]) = conv.begin; + break; + + case GDB_REG_FCTRL ... GDB_REG_FSTAT: + case GDB_REG_FISEG: + case GDB_REG_FOSEG: + width = 2; + *((uint16_t *) buf) = *((uint16_t *) fpu_regs[index - GDB_REG_FCTRL]); + break; + + case GDB_REG_FTAG: + width = 2; + *((uint16_t *) buf) = x87_gettag(); + break; + + case GDB_REG_FIOFF: + case GDB_REG_FOOFF: + *((uint32_t *) buf) = *((uint32_t *) fpu_regs[index - GDB_REG_FCTRL]); + break; + + case GDB_REG_FOP: + width = 2; + *((uint16_t *) buf) = 0; /* we don't store the FPU opcode */ + break; + + case GDB_REG_MM0 ... GDB_REG_MM7: + width = 8; + *((uint64_t *) buf) = cpu_state.MM[index - GDB_REG_MM0].q; + break; + + default: + width = 0; + } + + return width; +} + +static void +gdbstub_client_packet(gdbstub_client_t *client) +{ +#ifdef GDBSTUB_CHECK_CHECKSUM /* msys2 gdb 11.1 transmits qSupported and H with invalid checksum... */ + uint8_t rcv_checksum = 0, checksum = 0; +#endif + int i, j = 0, k = 0, l; + uint8_t buf[10] = { 0 }; + char *p; + + /* Validate checksum. */ + client->packet_pos -= 2; +#ifdef GDBSTUB_CHECK_CHECKSUM + gdbstub_client_read_hex(client, &rcv_checksum, 1); +#endif + *((uint16_t *) &client->packet[--client->packet_pos]) = 0; +#ifdef GDBSTUB_CHECK_CHECKSUM + for (i = 0; i < client->packet_pos; i++) + checksum += client->packet[i]; + + if (checksum != rcv_checksum) { + /* Send negative acknowledgement. */ +# ifdef ENABLE_GDBSTUB_LOG + i = client->packet[953]; /* pclog_ex buffer too small */ + client->packet[953] = '\0'; + gdbstub_log("GDB Stub: Received packet with invalid checksum (expected %02X got %02X): %s\n", checksum, rcv_checksum, client->packet); + client->packet[953] = i; +# endif + send(client->socket, "-", 1, 0); + return; + } +#endif + + /* Send positive acknowledgement. */ +#ifdef ENABLE_GDBSTUB_LOG + i = client->packet[996]; /* pclog_ex buffer too small */ + client->packet[996] = '\0'; + gdbstub_log("GDB Stub: Received packet: %s\n", client->packet); + client->packet[996] = i; +#endif + send(client->socket, "+", 1, 0); + + /* Block other responses from being written while this one (if any is produced) isn't acknowledged. */ + if ((client->packet[0] != 'c') && (client->packet[0] != 's') && (client->packet[0] != 'v')) { + thread_wait_event(client->response_event, -1); + thread_reset_event(client->response_event); + } + client->response_pos = 0; + client->packet_pos = 1; + + /* Parse command. */ + switch (client->packet[0]) { + case '?': /* stop reason */ + /* Respond with a stop reply packet if one is present. */ + if (stop_reason_len) { + strcpy(client->response, stop_reason); + client->response_pos = strlen(client->response); + } + break; + + case 'c': /* continue */ + case 's': /* step */ + /* Flag that the client is waiting for a stop reason. */ + client->waiting_stop = 1; + + /* Jump to address if specified. */ + if (client->packet[1] && gdbstub_client_read_word(client, &j)) + gdbstub_jump(j); + + /* Resume CPU. */ + gdbstub_step = gdbstub_next_asap = (client->packet[0] == 's') ? GDBSTUB_SSTEP : GDBSTUB_EXEC; + return; + + case 'D': /* detach */ + /* Resume emulation. */ + gdbstub_step = GDBSTUB_EXEC; + + /* Respond positively. */ +ok: + FAST_RESPONSE("OK"); + break; + + case 'g': /* read all registers */ + /* Output the values of all registers. */ + for (i = 0; i < GDB_REG_MAX; i++) + gdbstub_client_respond_hex(client, buf, gdbstub_client_read_reg(i, buf)); + break; + + case 'G': /* write all registers */ + /* Write the values of all registers. */ + for (i = 0; i < GDB_REG_MAX; i++) { + if (i == GDB_REG_MAX) + goto e22; + if (!gdbstub_client_read_hex(client, buf, sizeof(buf))) + break; + client->packet_pos += gdbstub_client_write_reg(i, buf) << 1; + } + + /* Respond positively. */ + goto ok; + + case 'H': /* set thread */ + /* Read operation type and thread ID. */ + if ((client->packet[1] == '\0') || (client->packet[2] == '\0')) { +e22: + FAST_RESPONSE("E22"); + break; + } + + /* Respond positively only on thread 1. */ + if ((client->packet[2] == '1') && !client->packet[3]) + goto ok; + else + goto e22; + + case 'm': /* read memory */ + /* Read address and length. */ + if (!(i = gdbstub_client_read_word(client, &j))) + goto e22; + client->packet_pos += i + 1; + gdbstub_client_read_word(client, &k); + if (!k) + goto e22; + + /* Clamp length. */ + if (k >= (sizeof(client->response) >> 1)) + k = (sizeof(client->response) >> 1) - 1; + + /* Read by qwords, then by dwords, then by words, then by bytes. */ + i = 0; + if (is386) { + for (; i < (k & ~7); i += 8) { + *((uint64_t *) buf) = readmemql(j); + j += 8; + gdbstub_client_respond_hex(client, buf, 8); + } + for (; i < (k & ~3); i += 4) { + *((uint32_t *) buf) = readmemll(j); + j += 4; + gdbstub_client_respond_hex(client, buf, 4); + } + } + for (; i < (k & ~1); i += 2) { + *((uint16_t *) buf) = readmemwl(j); + j += 2; + gdbstub_client_respond_hex(client, buf, 2); + } + for (; i < k; i++) { + buf[0] = readmembl(j++); + gdbstub_client_respond_hex(client, buf, 1); + } + break; + + case 'M': /* write memory */ + case 'X': /* write memory binary */ + /* Read address and length. */ + if (!(i = gdbstub_client_read_word(client, &j))) + goto e22; + client->packet_pos += i + 1; + client->packet_pos += gdbstub_client_read_word(client, &k) + 1; + if (!k) + goto e22; + + /* Clamp length. */ + if (k >= ((sizeof(client->response) >> 1) - client->packet_pos)) + k = (sizeof(client->response) >> 1) - client->packet_pos - 1; + + /* Decode the data. */ + if (client->packet[0] == 'M') { /* hex encoded */ + gdbstub_client_read_hex(client, (uint8_t *) client->packet, k); + } else { /* binary encoded */ + i = 0; + while (i < k) { + if (client->packet[client->packet_pos] == '}') { + client->packet_pos++; + client->packet[i++] = client->packet[client->packet_pos++] ^ 0x20; + } else { + client->packet[i++] = client->packet[client->packet_pos++]; + } + } + } + + /* Write by qwords, then by dwords, then by words, then by bytes. */ + p = client->packet; + i = 0; + if (is386) { + for (; i < (k & ~7); i += 8) { + writememql(j, *((uint64_t *) p)); + j += 8; + p += 8; + } + for (; i < (k & ~3); i += 4) { + writememll(j, *((uint32_t *) p)); + j += 4; + p += 4; + } + } + for (; i < (k & ~1); i += 2) { + writememwl(j, *((uint16_t *) p)); + j += 2; + p += 2; + } + for (; i < k; i++) { + writemembl(j++, p[0]); + p++; + } + + /* Respond positively. */ + goto ok; + + case 'p': /* read register */ + /* Read register index. */ + if (!gdbstub_client_read_word(client, &j)) { +e14: + FAST_RESPONSE("E14"); + break; + } + + /* Read the register's value. */ + if (!(i = gdbstub_client_read_reg(j, buf))) + goto e14; + + /* Return value. */ + gdbstub_client_respond_hex(client, buf, i); + break; + + case 'P': /* write register */ + /* Read register index and value. */ + if (!(i = gdbstub_client_read_word(client, &j))) + goto e14; + client->packet_pos += i + 1; + if (!gdbstub_client_read_hex(client, buf, sizeof(buf))) + goto e14; + + /* Write the value to the register. */ + if (!gdbstub_client_write_reg(j, buf)) + goto e14; + + /* Respond positively. */ + goto ok; + + case 'q': /* query */ + /* Erase response, as we'll use it as a scratch buffer. */ + memset(client->response, 0, sizeof(client->response)); + + /* Read the query type. */ + client->packet_pos += gdbstub_client_read_string(client, client->response, sizeof(client->response) - 1, + (client->packet[1] == 'R') ? ',' : ':') + + 1; + + /* Perform the query. */ + if (!strcmp(client->response, "Supported")) { + /* Go through the feature list and negate ones we don't support. */ + while ((client->response_pos < (sizeof(client->response) - 1)) && (i = gdbstub_client_read_string(client, &client->response[client->response_pos], sizeof(client->response) - client->response_pos - 1, ';'))) { + client->packet_pos += i + 1; + if (strncmp(&client->response[client->response_pos], "PacketSize", 10) && strcmp(&client->response[client->response_pos], "swbreak") && strcmp(&client->response[client->response_pos], "hwbreak") && strncmp(&client->response[client->response_pos], "xmlRegisters", 12) && strcmp(&client->response[client->response_pos], "qXfer:features:read")) { + gdbstub_log("GDB Stub: Feature \"%s\" is not supported\n", &client->response[client->response_pos]); + client->response_pos += i; + client->response[client->response_pos++] = '-'; + client->response[client->response_pos++] = ';'; + } else { + gdbstub_log("GDB Stub: Feature \"%s\" is supported\n", &client->response[client->response_pos]); + } + } + + /* Add our supported features to the end. */ + if (client->response_pos < (sizeof(client->response) - 1)) + client->response_pos += snprintf(&client->response[client->response_pos], sizeof(client->response) - client->response_pos, + "PacketSize=%lX;swbreak+;hwbreak+;qXfer:features:read+", sizeof(client->packet) - 1); + break; + } else if (!strcmp(client->response, "Xfer")) { + /* Read the transfer object. */ + client->packet_pos += gdbstub_client_read_string(client, client->response, sizeof(client->response) - 1, ':') + 1; + if (!strcmp(client->response, "features")) { + /* Read the transfer operation. */ + client->packet_pos += gdbstub_client_read_string(client, client->response, sizeof(client->response) - 1, ':') + 1; + if (!strcmp(client->response, "read")) { + /* Read the transfer annex. */ + client->packet_pos += gdbstub_client_read_string(client, client->response, sizeof(client->response) - 1, ':') + 1; + if (!strcmp(client->response, "target.xml")) + p = (char *) target_xml; + else + p = NULL; + + /* Stop if the file wasn't found. */ + if (!p) { +e00: + FAST_RESPONSE("E00"); + break; + } + + /* Read offset and length. */ + if (!(i = gdbstub_client_read_word(client, &j))) + goto e22; + client->packet_pos += i + 1; + client->packet_pos += gdbstub_client_read_word(client, &k) + 1; + if (!k) + goto e22; + + /* Check if the offset is valid. */ + l = strlen(p); + if (j > l) + goto e00; + p += j; + + /* Return the more/less flag while also clamping the length. */ + if (k >= ((sizeof(client->response) >> 1) - 2)) + k = (sizeof(client->response) >> 1) - 3; + if (k < (l - j)) { + client->response[client->response_pos++] = 'm'; + } else { + client->response[client->response_pos++] = 'l'; + k = l - j; + } + + /* Encode the data. */ + while (k--) { + i = *p++; + if ((i == '\0') || (i == '#') || (i == '$') || (i == '*') || (i == '}')) { + client->response[client->response_pos++] = '}'; + client->response[client->response_pos++] = i ^ 0x20; + } else { + client->response[client->response_pos++] = i; + } + } + break; + } + } + } else if (!strncmp(client->response, "Attached", 8)) { + FAST_RESPONSE("1"); + } else if (!strcmp(client->response, "C")) { + FAST_RESPONSE("QC1"); + } else if (!strcmp(client->response, "fThreadInfo")) { + FAST_RESPONSE("m 1"); + } else if (!strcmp(client->response, "sThreadInfo")) { + FAST_RESPONSE("l"); + } else if (!strcmp(client->response, "Rcmd")) { + /* Read and decode command in-place. */ + i = gdbstub_client_read_hex(client, (uint8_t *) client->packet, strlen(client->packet) - client->packet_pos); + client->packet[i] = 0; + gdbstub_log("GDB Stub: Monitor command: %s\n", client->packet); + + /* Parse the command name. */ + char *strtok_save; + p = strtok_r(client->packet, " ", &strtok_save); + if (!p) + goto ok; + i = strlen(p) - 1; /* get last character offset */ + + /* Interpret the command. */ + if (p[0] == 'i') { + /* Read I/O operation width. */ + l = (i < 1) ? '\0' : p[i]; + + /* Read optional I/O port. */ + if (!(p = strtok_r(NULL, " ", &strtok_save)) || !gdbstub_num_decode(p, &j, GDB_MODE_HEX) || (j < 0) || (j >= 65536)) + j = client->last_io_base; + else + client->last_io_base = j; + + /* Read optional length. */ + if (!(p = strtok_r(NULL, " ", &strtok_save)) || !gdbstub_num_decode(p, &k, GDB_MODE_BASE10)) + k = client->last_io_len; + else + client->last_io_len = k; + + /* Clamp length. */ + if (k < 1) + k = 1; + if (k > (65536 - j)) + k = 65536 - j; + + /* Read ports. */ + i = 0; + while (i < k) { + if ((i % 16) == 0) { + if (i) { + client->packet[client->packet_pos++] = '\n'; + + /* Provide partial response with the last line. */ + client->response_pos = 0; + client->response[client->response_pos++] = 'O'; + gdbstub_client_respond_hex(client, (uint8_t *) client->packet, client->packet_pos); + gdbstub_client_respond_partial(client); + } + client->packet_pos = sprintf(client->packet, "%04X:", j + i); + } + /* Act according to I/O operation width. */ + switch (l) { + case 'd': + case 'l': + client->packet_pos += sprintf(&client->packet[client->packet_pos], " %08X", inl(j + i)); + i += 4; + break; + + case 'w': + client->packet_pos += sprintf(&client->packet[client->packet_pos], " %04X", inw(j + i)); + i += 2; + break; + + case 'b': + case '\0': + client->packet_pos += sprintf(&client->packet[client->packet_pos], " %02X", inb(j + i)); + i++; + break; + + default: + goto unknown; + } + } + client->packet[client->packet_pos++] = '\n'; + + /* Respond with the final line. */ + client->response_pos = 0; + gdbstub_client_respond_hex(client, (uint8_t *) &client->packet, client->packet_pos); + break; + } else if (p[0] == 'o') { + /* Read I/O operation width. */ + l = (i < 1) ? '\0' : p[i]; + + /* Read optional I/O port. */ + if (!(p = strtok_r(NULL, " ", &strtok_save)) || !gdbstub_num_decode(p, &j, GDB_MODE_HEX) || (j < 0) || (j >= 65536)) + j = -1; + + /* Read optional value. */ + if (!(p = strtok_r(NULL, " ", &strtok_save)) || !gdbstub_num_decode(p, &k, GDB_MODE_HEX)) { + if (j == -1) + k = client->last_io_value; + else + k = j; /* only one specified = treat as value on last port */ + j = -1; + } + if (j == -1) + j = client->last_io_base; + else + client->last_io_base = j; + client->last_io_value = k; + + /* Write port. */ + switch (l) { + case 'd': + case 'l': + outl(j, k); + break; + + case 'w': + outw(j, k); + break; + + case 'b': + case 't': + case '\0': + outb(j, k); + break; + + default: + goto unknown; + } + } else if (p[0] == 'r') { + pc_reset_hard(); + } else if ((p[0] == '?') || !strcmp(p, "help")) { + FAST_RESPONSE_HEX( + "Commands:\n" + "- ib/iw/il [port [length]] - Read {length} (default 1) I/O ports starting from {port} (default last)\n" + "- ob/ow/ol [[port] value] - Write {value} to I/O {port} (both default last)\n" + "- r - Hard reset the emulated machine\n"); + break; + } else { +unknown: + FAST_RESPONSE_HEX("Unknown command\n"); + break; + } + + goto ok; + } + break; + + case 'z': /* remove break/watchpoint */ + case 'Z': /* insert break/watchpoint */ + gdbstub_breakpoint_t *breakpoint, *prev_breakpoint = NULL, **first_breakpoint; + + /* Parse breakpoint type. */ + switch (client->packet[1]) { + case '0': /* software breakpoint */ + first_breakpoint = &first_swbreak; + break; + + case '1': /* hardware breakpoint */ + first_breakpoint = &first_hwbreak; + break; + + case '2': /* write watchpoint */ + first_breakpoint = &first_wwatch; + break; + + case '3': /* read watchpoint */ + first_breakpoint = &first_rwatch; + break; + + case '4': /* access watchpoint */ + first_breakpoint = &first_awatch; + break; + + default: /* unknown type */ + client->packet[2] = '\0'; /* force address check to fail */ + break; + } + + /* Read address. */ + if (client->packet[2] != ',') + break; + client->packet_pos = 3; + if (!(i = gdbstub_client_read_word(client, &j))) + break; + client->packet_pos += i; + if (client->packet[client->packet_pos++] == ',') + gdbstub_client_read_word(client, &k); + else + k = 1; + + /* Test writability of software breakpoint. */ + if (client->packet[1] == '0') { + buf[0] = readmembl(j); + writemembl(j, 0xcc); + buf[1] = readmembl(j); + writemembl(j, buf[0]); + if (buf[1] != 0xcc) + goto end; + } + + /* Find an existing breakpoint with this address. */ + breakpoint = *first_breakpoint; + while (breakpoint) { + if (breakpoint->addr == j) + break; + prev_breakpoint = breakpoint; + breakpoint = breakpoint->next; + } + + /* Check if the breakpoint is already present (when inserting) or not found (when removing). */ + if ((!!breakpoint) ^ (client->packet[0] == 'z')) + goto e22; + + /* Insert or remove the breakpoint. */ + if (client->packet[0] != 'z') { + /* Allocate a new breakpoint. */ + breakpoint = malloc(sizeof(gdbstub_breakpoint_t)); + breakpoint->addr = j; + breakpoint->end = j + k; + breakpoint->next = NULL; + + /* Add the new breakpoint to the list. */ + if (!(*first_breakpoint)) + *first_breakpoint = breakpoint; + else if (prev_breakpoint) + prev_breakpoint->next = breakpoint; + } else { + /* Remove breakpoint from the list. */ + if (breakpoint == *first_breakpoint) + *first_breakpoint = breakpoint->next; + else if (prev_breakpoint) + prev_breakpoint->next = breakpoint->next; + + /* De-allocate breakpoint. */ + free(breakpoint); + } + + /* Update the page watchpoint map if we're dealing with a watchpoint. */ + if (client->packet[1] >= '2') { + /* Clear this watchpoint's corresponding page map groups, + as everything is going to be recomputed soon anyway. */ + memset(&gdbstub_watch_pages[j >> (MEM_GRANULARITY_BITS + 6)], 0, + (((k - 1) >> (MEM_GRANULARITY_BITS + 6)) + 1) * sizeof(gdbstub_watch_pages[0])); + + /* Go through all watchpoint lists. */ + l = 0; + breakpoint = first_rwatch; + while (1) { + if (breakpoint) { + /* Flag this watchpoint's corresponding pages as having a watchpoint. */ + k = (breakpoint->end - 1) >> MEM_GRANULARITY_BITS; + for (i = breakpoint->addr >> MEM_GRANULARITY_BITS; i <= k; i++) + gdbstub_watch_pages[i >> 6] |= (1 << (i & 63)); + + breakpoint = breakpoint->next; + } else { + /* Jump from list to list as a shortcut. */ + if (l == 0) + breakpoint = first_wwatch; + else if (l == 1) + breakpoint = first_awatch; + else + break; + l++; + } + } + } + + /* Respond positively. */ + goto ok; + } +end: + /* Send response. */ + gdbstub_client_respond(client); +} + +static void +gdbstub_cpu_exec(int cycs) +{ + /* Flag that we're now in the debugger context to avoid triggering watchpoints. */ + in_gdbstub = 1; + + /* Handle CPU execution if it isn't paused. */ + if (gdbstub_step <= GDBSTUB_SSTEP) { + /* Swap in any software breakpoints. */ + gdbstub_breakpoint_t *swbreak = first_swbreak; + while (swbreak) { + /* Swap the INT 3 opcode into the address. */ + swbreak->orig_val = readmembl(swbreak->addr); + writemembl(swbreak->addr, 0xcc); + swbreak = swbreak->next; + } + + /* Call the original cpu_exec function outside the debugger context. */ + if ((gdbstub_step == GDBSTUB_SSTEP) && ((cycles + cycs) <= 0)) + cycs += -(cycles + cycs) + 1; + in_gdbstub = 0; + cpu_exec_shadow(cycs); + in_gdbstub = 1; + + /* Swap out any software breakpoints. */ + swbreak = first_swbreak; + while (swbreak) { + if (readmembl(swbreak->addr) == 0xcc) + writemembl(swbreak->addr, swbreak->orig_val); + swbreak = swbreak->next; + } + } + + /* Populate stop reason if we have stopped. */ + stop_reason_len = 0; + if (gdbstub_step > GDBSTUB_EXEC) { + /* Assemble stop reason manually, avoiding sprintf and friends for performance. */ + stop_reason[stop_reason_len++] = 'T'; + stop_reason[stop_reason_len++] = '0'; + stop_reason[stop_reason_len++] = '0' + ((gdbstub_step == GDBSTUB_BREAK) ? GDB_SIGINT : GDB_SIGTRAP); + + /* Add extended break reason. */ + if (gdbstub_step >= GDBSTUB_BREAK_RWATCH) { + if (gdbstub_step != GDBSTUB_BREAK_WWATCH) + stop_reason[stop_reason_len++] = (gdbstub_step == GDBSTUB_BREAK_RWATCH) ? 'r' : 'a'; + stop_reason[stop_reason_len++] = 'w'; + stop_reason[stop_reason_len++] = 'a'; + stop_reason[stop_reason_len++] = 't'; + stop_reason[stop_reason_len++] = 'c'; + stop_reason[stop_reason_len++] = 'h'; + stop_reason[stop_reason_len++] = ':'; + stop_reason_len += sprintf(&stop_reason[stop_reason_len], "%X;", watch_addr); + } else if (gdbstub_step >= GDBSTUB_BREAK_SW) { + stop_reason[stop_reason_len++] = (gdbstub_step == GDBSTUB_BREAK_SW) ? 's' : 'h'; + stop_reason[stop_reason_len++] = 'w'; + stop_reason[stop_reason_len++] = 'b'; + stop_reason[stop_reason_len++] = 'r'; + stop_reason[stop_reason_len++] = 'e'; + stop_reason[stop_reason_len++] = 'a'; + stop_reason[stop_reason_len++] = 'k'; + stop_reason[stop_reason_len++] = ':'; + stop_reason[stop_reason_len++] = ';'; + } + + /* Add register dump. */ + uint8_t buf[10] = { 0 }; + int i, j, k; + for (i = 0; i < GDB_REG_MAX; i++) { + if (i >= 0x10) + stop_reason[stop_reason_len++] = gdbstub_hex_encode(i >> 4); + stop_reason[stop_reason_len++] = gdbstub_hex_encode(i & 0x0f); + stop_reason[stop_reason_len++] = ':'; + j = gdbstub_client_read_reg(i, buf); + for (k = 0; k < j; k++) { + stop_reason[stop_reason_len++] = gdbstub_hex_encode(buf[k] >> 4); + stop_reason[stop_reason_len++] = gdbstub_hex_encode(buf[k] & 0x0f); + } + stop_reason[stop_reason_len++] = ';'; + } + + /* Don't execute the CPU any further if single-stepping. */ + gdbstub_step = GDBSTUB_BREAK; + } + + /* Return the framerate to normal. */ + gdbstub_next_asap = 0; + + /* Process client packets. */ + thread_wait_mutex(client_list_mutex); + gdbstub_client_t *client = first_client; + while (client) { + /* Report stop reason if the client is waiting for one. */ + if (client->waiting_stop && stop_reason_len) { + client->waiting_stop = 0; + + /* Wait for any pending responses to be acknowledged. */ + if (!thread_wait_event(client->response_event, -1)) { + /* Block other responses from being written while this one isn't acknowledged. */ + thread_reset_event(client->response_event); + + /* Write stop reason response. */ + strcpy(client->response, stop_reason); + client->response_pos = stop_reason_len; + gdbstub_client_respond(client); + } else { + gdbstub_log("GDB Stub: Timed out waiting for client %s:%d\n", inet_ntoa(client->addr.sin_addr), client->addr.sin_port); + } + } + + if (client->has_packet) { + gdbstub_client_packet(client); + client->has_packet = client->packet_pos = 0; + thread_set_event(client->processed_event); + } + +#ifdef GDBSTUB_ALLOW_MULTI_CLIENTS + client = client->next; +#else + break; +#endif + } + thread_release_mutex(client_list_mutex); + + /* Flag that we're now out of the debugger context. */ + in_gdbstub = 0; +} + +static void +gdbstub_client_thread(void *priv) +{ + gdbstub_client_t *client = (gdbstub_client_t *) priv; + uint8_t buf[256]; + ssize_t bytes_read; + int i; + + gdbstub_log("GDB Stub: New connection from %s:%d\n", inet_ntoa(client->addr.sin_addr), client->addr.sin_port); + + /* Allow packets to be processed. */ + thread_set_event(client->processed_event); + + /* Read data from client. */ + while ((bytes_read = recv(client->socket, (char *) buf, sizeof(buf), 0)) > 0) { + for (i = 0; i < bytes_read; i++) { + switch (buf[i]) { + case '$': /* packet start */ + /* Wait for any existing packets to be processed. */ + thread_wait_event(client->processed_event, -1); + + client->packet_pos = 0; + break; + + case '-': /* negative acknowledgement */ + /* Retransmit the current response. */ + gdbstub_client_respond(client); + break; + + case '+': /* positive acknowledgement */ + /* Allow another response to be written. */ + thread_set_event(client->response_event); + break; + + case 0x03: /* break */ + /* Wait for any existing packets to be processed. */ + thread_wait_event(client->processed_event, -1); + + /* Break immediately. */ + gdbstub_log("GDB Stub: Break requested\n"); + gdbstub_break(); + break; + + default: + /* Wait for any existing packets to be processed, just in case. */ + thread_wait_event(client->processed_event, -1); + + if (client->packet_pos < (sizeof(client->packet) - 1)) { + /* Append byte to the packet. */ + client->packet[client->packet_pos++] = buf[i]; + + /* Check if we're at the end of a packet. */ + if ((client->packet_pos >= 3) && (client->packet[client->packet_pos - 3] == '#')) { /* packet checksum start */ + /* Small hack to speed up IDA instruction trace mode. */ + if (*((uint32_t *) client->packet) == ('H' | ('c' << 8) | ('1' << 16) | ('#' << 24))) { + /* Send pre-computed response. */ + send(client->socket, "+$OK#9A", 7, 0); + + /* Skip processing. */ + continue; + } + + /* Flag that a packet should be processed. */ + client->packet[client->packet_pos] = '\0'; + thread_reset_event(client->processed_event); + gdbstub_next_asap = client->has_packet = 1; + } + } + break; + } + } + } + + gdbstub_log("GDB Stub: Connection with %s:%d broken\n", inet_ntoa(client->addr.sin_addr), client->addr.sin_port); + + /* Close socket. */ + if (client->socket != -1) { + close(client->socket); + client->socket = -1; + } + + /* Unblock anyone waiting on the response event. */ + thread_set_event(client->response_event); + + /* Remove this client from the list. */ + thread_wait_mutex(client_list_mutex); +#ifdef GDBSTUB_ALLOW_MULTI_CLIENTS + if (client == first_client) { +#endif + first_client = client->next; + if (first_client == NULL) { + last_client = NULL; + gdbstub_step = GDBSTUB_EXEC; /* unpause CPU when all clients are disconnected */ + } +#ifdef GDBSTUB_ALLOW_MULTI_CLIENTS + } else { + other_client = first_client; + while (other_client) { + if (other_client->next == client) { + if (last_client == client) + last_client = other_client; + other_client->next = client->next; + break; + } + other_client = other_client->next; + } + } +#endif + + free(client); + thread_release_mutex(client_list_mutex); +} + +static void +gdbstub_server_thread(void *priv) +{ + /* Listen on GDB socket. */ + listen(gdbstub_socket, 1); + + /* Accept connections. */ + gdbstub_client_t *client; + socklen_t sl = sizeof(struct sockaddr_in); + while (1) { + /* Allocate client structure. */ + client = malloc(sizeof(gdbstub_client_t)); + memset(client, 0, sizeof(gdbstub_client_t)); + client->processed_event = thread_create_event(); + client->response_event = thread_create_event(); + + /* Accept connection. */ + client->socket = accept(gdbstub_socket, (struct sockaddr *) &client->addr, &sl); + if (client->socket < 0) + break; + + /* Add to client list. */ + thread_wait_mutex(client_list_mutex); + if (first_client) { +#ifdef GDBSTUB_ALLOW_MULTI_CLIENTS + last_client->next = client; + last_client = client; +#else + first_client->next = last_client = client; + close(first_client->socket); +#endif + } else { + first_client = last_client = client; + } + thread_release_mutex(client_list_mutex); + + /* Pause CPU execution. */ + gdbstub_break(); + + /* Start client thread. */ + thread_create(gdbstub_client_thread, client); + } + + /* Deallocate the redundant client structure. */ + thread_destroy_event(client->processed_event); + thread_destroy_event(client->response_event); + free(client); +} + +void +gdbstub_cpu_init() +{ + /* Replace cpu_exec with our own function if the GDB stub is active. */ + if ((gdbstub_socket != -1) && (cpu_exec != gdbstub_cpu_exec)) { + cpu_exec_shadow = cpu_exec; + cpu_exec = gdbstub_cpu_exec; + } +} + +int +gdbstub_instruction() +{ + /* Check hardware breakpoints if any are present. */ + gdbstub_breakpoint_t *breakpoint = first_hwbreak; + if (breakpoint) { + /* Calculate the current instruction's address. */ + uint32_t wanted_addr = cs + cpu_state.pc; + + /* Go through the list of software breakpoints. */ + do { + /* Check if the breakpoint coincides with this address. */ + if (breakpoint->addr == wanted_addr) { + gdbstub_log("GDB Stub: Hardware breakpoint at %08X\n", wanted_addr); + + /* Flag that we're in a hardware breakpoint. */ + gdbstub_step = GDBSTUB_BREAK_HW; + + /* Pause execution. */ + return 1; + } + + breakpoint = breakpoint->next; + } while (breakpoint); + } + + /* No breakpoint found, continue execution or stop if execution is paused. */ + return gdbstub_step - GDBSTUB_EXEC; +} + +int +gdbstub_int3() +{ + /* Check software breakpoints if any are present. */ + gdbstub_breakpoint_t *breakpoint = first_swbreak; + if (breakpoint) { + /* Calculate the breakpoint instruction's address. */ + uint32_t new_pc = cpu_state.pc - 1; + if (cpu_state.op32) + new_pc &= 0xffff; + uint32_t wanted_addr = cs + new_pc; + + /* Go through the list of software breakpoints. */ + do { + /* Check if the breakpoint coincides with this address. */ + if (breakpoint->addr == wanted_addr) { + gdbstub_log("GDB Stub: Software breakpoint at %08X\n", wanted_addr); + + /* Move EIP back to where the break instruction was. */ + cpu_state.pc = new_pc; + + /* Flag that we're in a software breakpoint. */ + gdbstub_step = GDBSTUB_BREAK_SW; + + /* Abort INT 3 execution. */ + return 1; + } + + breakpoint = breakpoint->next; + } while (breakpoint); + } + + /* No breakpoint found, continue INT 3 execution as normal. */ + return 0; +} + +void +gdbstub_mem_access(uint32_t *addrs, int access) +{ + /* Stop if we're in the debugger context. */ + if (in_gdbstub) + return; + + int width = access & (GDBSTUB_MEM_WRITE - 1), i; + + /* Go through the lists of watchpoints for this type of access. */ + gdbstub_breakpoint_t *watchpoint = (access & GDBSTUB_MEM_WRITE) ? first_wwatch : first_rwatch; + while (1) { + if (watchpoint) { + /* Check if any component of this address is within the breakpoint's range. */ + for (i = 0; i < width; i++) { + if ((addrs[i] >= watchpoint->addr) && (addrs[i] < watchpoint->end)) + break; + } + if (i < width) { + gdbstub_log("GDB Stub: %s watchpoint at %08X\n", (access & GDBSTUB_MEM_AWATCH) ? "Access" : ((access & GDBSTUB_MEM_WRITE) ? "Write" : "Read"), watch_addr); + + /* Flag that we're in a read/write watchpoint. */ + gdbstub_step = (access & GDBSTUB_MEM_AWATCH) ? GDBSTUB_BREAK_AWATCH : ((access & GDBSTUB_MEM_WRITE) ? GDBSTUB_BREAK_WWATCH : GDBSTUB_BREAK_RWATCH); + + /* Stop looking. */ + return; + } + + watchpoint = watchpoint->next; + } else { + /* Jump from list to list as a shortcut. */ + if (access & GDBSTUB_MEM_AWATCH) { + break; + } else { + watchpoint = first_awatch; + access |= GDBSTUB_MEM_AWATCH; + } + } + } +} + +void +gdbstub_init() +{ +#ifdef _WIN32 + WSAStartup(MAKEWORD(2, 2), &wsa); +#endif + + /* Create GDB server socket. */ + if ((gdbstub_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + pclog("GDB Stub: Failed to create socket\n"); + return; + } + + /* Bind GDB server socket. */ + int port = 12345; + struct sockaddr_in bind_addr = { + .sin_family = AF_INET, + .sin_addr = { .s_addr = INADDR_ANY }, + .sin_port = htons(port) + }; + if (bind(gdbstub_socket, (struct sockaddr *) &bind_addr, sizeof(bind_addr)) == -1) { + pclog("GDB Stub: Failed to bind on port %d (%d)\n", port, +#ifdef _WIN32 + WSAGetLastError() +#else + errno +#endif + ); + gdbstub_socket = -1; + return; + } + + /* Create client list mutex. */ + client_list_mutex = thread_create_mutex(); + + /* Clear watchpoint page map. */ + memset(gdbstub_watch_pages, 0, sizeof(gdbstub_watch_pages)); + + /* Start server thread. */ + pclog("GDB Stub: Listening on port %d\n", port); + thread_create(gdbstub_server_thread, NULL); + + /* Start the CPU paused. */ + gdbstub_step = GDBSTUB_BREAK; +} + +void +gdbstub_close() +{ + /* Stop if the GDB server hasn't initialized. */ + if (gdbstub_socket < 0) + return; + + /* Close GDB server socket. */ + close(gdbstub_socket); + + /* Clear client list. */ + thread_wait_mutex(client_list_mutex); + gdbstub_client_t *client = first_client; + int socket; + while (client) { + socket = client->socket; + client->socket = -1; + close(socket); + client = client->next; + } + thread_release_mutex(client_list_mutex); + thread_close_mutex(client_list_mutex); +} diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index bbb37895e..3d2806ce7 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -15,64 +15,51 @@ * * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #ifndef EMU_86BOX_H # define EMU_86BOX_H /* Configuration values. */ -#define SERIAL_MAX 2 -#define PARALLEL_MAX 1 +#define SERIAL_MAX 4 +#define PARALLEL_MAX 4 #define SCREEN_RES_X 640 #define SCREEN_RES_Y 480 -/* Version info. */ -#define EMU_NAME "86Box" -#define EMU_NAME_W L"86Box" -#ifdef RELEASE_BUILD -#define EMU_VERSION "2.07" -#define EMU_VERSION_W L"2.07" -#define EMU_VERSION_MAJ 2 -#define EMU_VERSION_MIN 7 -#else -#define EMU_VERSION "2.10" -#define EMU_VERSION_W L"2.10" -#define EMU_VERSION_MAJ 2 -#define EMU_VERSION_MIN 10 -#endif -#define COPYRIGHT_YEAR "2020" - -/* Web URL info. */ -#define EMU_SITE L"86box.github.io" -#define EMU_ROMS_URL L"https://github.com/86Box/roms/releases/latest" - /* Filename and pathname info. */ -#define CONFIG_FILE L"86box.cfg" -#define NVR_PATH L"nvr" -#define SCREENSHOT_PATH L"screenshots" +#define CONFIG_FILE "86box.cfg" +#define NVR_PATH "nvr" +#define SCREENSHOT_PATH "screenshots" -#if defined(ENABLE_BUSLOGIC_LOG) || \ - defined(ENABLE_CDROM_LOG) || \ - defined(ENABLE_D86F_LOG) || \ - defined(ENABLE_FDC_LOG) || \ - defined(ENABLE_IDE_LOG) || \ - defined(ENABLE_NIC_LOG) -# define ENABLE_LOG_TOGGLES 1 +/* Default language 0xFFFF = from system, 0x409 = en-US */ +#define DEFAULT_LANGUAGE 0x0409 + +#ifdef MIN +#undef MIN +#endif +#ifdef MAX +#undef MAX +#endif +#ifdef ABS +#undef ABS #endif -#if defined(ENABLE_LOG_BREAKPOINT) || defined(ENABLE_VRAM_DUMP) -# define ENABLE_LOG_COMMANDS 1 -#endif - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define ABS(x) ((x) > 0 ? (x) : -(x)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define ABS(x) ((x) > 0 ? (x) : -(x)) +#define BCD8(x) ((((x) / 10) << 4) | ((x) % 10)) +#define BCD16(x) ((((x) / 1000) << 12) | (((x) / 100) << 8) | BCD8(x)) +#define BCD32(x) ((((x) / 10000000) << 28) | (((x) / 1000000) << 24) | (((x) / 100000) << 20) | (((x) / 10000) << 16) | BCD16(x)) #ifdef __cplusplus extern "C" { #endif /* Global variables. */ +extern uint32_t lang_sys; /* (-) system language code */ + extern int dump_on_exit; /* (O) dump regs on exit*/ extern int do_dump_config; /* (O) dump cfg after load */ extern int start_in_fullscreen; /* (O) start in fullscreen */ @@ -83,21 +70,28 @@ extern int force_debug; /* (O) force debug output */ extern int video_fps; /* (O) render speed in fps */ #endif extern int settings_only; /* (O) show only the settings dialog */ -extern int no_quit_confirm; /* (O) do not ask for confirmation on quit */ +extern int confirm_exit_cmdl; /* (O) do not ask for confirmation on quit if set to 0 */ #ifdef _WIN32 extern uint64_t unique_id; extern uint64_t source_hwnd; #endif -extern wchar_t log_path[1024]; /* (O) full path of logfile */ +extern char rom_path[1024]; /* (O) full path to ROMs */ +extern char log_path[1024]; /* (O) full path of logfile */ +extern char vm_name[1024]; /* (O) display name of the VM */ -extern int window_w, window_h, /* (C) window size and */ - window_x, window_y, /* position info */ - window_remember, +#define window_x monitor_settings[0].mon_window_x +#define window_y monitor_settings[0].mon_window_y +#define window_w monitor_settings[0].mon_window_w +#define window_h monitor_settings[0].mon_window_h +extern int window_remember, vid_resize, /* (C) allow resizing */ invert_display, /* (C) invert the display */ suppress_overscan; /* (C) suppress overscans */ +extern uint32_t lang_id; /* (C) language code identifier */ +extern char icon_set[256]; /* (C) iconset identifier */ extern int scale; /* (C) screen scale factor */ +extern int dpi_scale; /* (C) DPI scaling of the emulated screen */ extern int vid_api; /* (C) video renderer */ extern int vid_cga_contrast, /* (C) video */ video_fullscreen, /* (C) video */ @@ -105,7 +99,11 @@ extern int vid_cga_contrast, /* (C) video */ video_fullscreen_scale, /* (C) video */ enable_overscan, /* (C) video */ force_43, /* (C) video */ + video_filter_method, /* (C) video */ + video_vsync, /* (C) video */ + video_framerate, /* (C) video */ gfxcard; /* (C) graphics/video card */ +extern char video_shader[512]; /* (C) video */ extern int serial_enabled[], /* (C) enable serial ports */ bugger_enabled, /* (C) enable ISAbugger */ postcard_enabled, /* (C) enable POST card */ @@ -115,10 +113,12 @@ extern int sound_is_float, /* (C) sound uses FP values */ GAMEBLASTER, /* (C) sound option */ GUS, GUSMAX, /* (C) sound option */ SSI2001, /* (C) sound option */ - voodoo_enabled; /* (C) video option */ -extern uint32_t mem_size; /* (C) memory size */ -extern int cpu_manufacturer, /* (C) cpu manufacturer */ - cpu, /* (C) cpu type */ + voodoo_enabled, /* (C) video option */ + ibm8514_enabled, /* (C) video option */ + xga_enabled; /* (C) video option */ +extern uint32_t mem_size; /* (C) memory size (Installed on system board) */ +extern uint32_t isa_mem_size; /* (C) memory size (ISA Memory Cards) */ +extern int cpu, /* (C) cpu type */ cpu_use_dynarec, /* (C) cpu uses/needs Dyna */ fpu_type; /* (C) fpu type */ extern int time_sync; /* (C) enable time sync */ @@ -126,51 +126,46 @@ extern int network_type; /* (C) net provider type */ extern int network_card; /* (C) net interface num */ extern char network_host[522]; /* (C) host network intf */ extern int hdd_format_type; /* (C) hard disk file format */ -#ifdef USE_DISCORD +extern int confirm_reset, /* (C) enable reset confirmation */ + confirm_exit, /* (C) enable exit confirmation */ + confirm_save; /* (C) enable save confirmation */ extern int enable_discord; /* (C) enable Discord integration */ -#endif -extern int enable_crashdump; /* (C) enable crash dump */ extern int is_pentium; /* TODO: Move back to cpu/cpu.h when it's figured out, how to remove that hack from the ET4000/W32p. */ +extern int fixed_size_x, fixed_size_y; +extern double mouse_sensitivity; /* (C) Mouse sensitivity scale */ +extern int pit_mode; /* (C) force setting PIT mode */ +extern int fm_driver; /* (C) select FM sound driver */ - -#ifdef ENABLE_LOG_TOGGLES -extern int buslogic_do_log; -extern int cdrom_do_log; -extern int d86f_do_log; -extern int fdc_do_log; -extern int ide_do_log; -extern int serial_do_log; -extern int nic_do_log; -#endif - -extern wchar_t exe_path[2048]; /* path (dir) of executable */ -extern wchar_t usr_path[1024]; /* path (dir) of user data */ -extern wchar_t cfg_path[1024]; /* full path of config file */ +extern char exe_path[2048]; /* path (dir) of executable */ +extern char usr_path[1024]; /* path (dir) of user data */ +extern char cfg_path[1024]; /* full path of config file */ #ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ #endif -extern int scrnsz_x, /* current screen size, X */ - scrnsz_y; /* current screen size, Y */ -extern int efscrnsz_y; extern int config_changed; /* config has changed */ /* Function prototypes. */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list); +extern void fatal_ex(const char *fmt, va_list); #endif extern void pclog_toggle_suppr(void); extern void pclog(const char *fmt, ...); extern void fatal(const char *fmt, ...); extern void set_screen_size(int x, int y); +extern void set_screen_size_monitor(int x, int y, int monitor_index); +extern void reset_screen_size(void); +extern void reset_screen_size_monitor(int monitor_index); extern void set_screen_size_natural(void); +extern void update_mouse_msg(); #if 0 extern void pc_reload(wchar_t *fn); #endif extern int pc_init_modules(void); -extern int pc_init(int argc, wchar_t *argv[]); +extern int pc_init(int argc, char *argv[]); extern void pc_close(void *threadid); extern void pc_reset_hard_close(void); extern void pc_reset_hard_init(void); @@ -180,7 +175,7 @@ extern void pc_speed_changed(void); extern void pc_send_cad(void); extern void pc_send_cae(void); extern void pc_send_cab(void); -extern void pc_thread(void *param); +extern void pc_run(void); extern void pc_start(void); extern void pc_onesec(void); @@ -190,9 +185,12 @@ extern uint16_t get_last_addr(void); should be in cpu.c but I put it here to avoid having to include cpu.c everywhere. */ extern void sub_cycles(int c); +extern void resub_cycles(int old_cycles); extern double isa_timing; -extern int io_delay; +extern int io_delay, framecountx; + +extern volatile int cpu_thread_run; #ifdef __cplusplus } diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index fa10aaa2f..94b2cd0fe 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -27,6 +27,9 @@ extern "C" { #define RSM_STS (1 << 15) #define PWRBTN_STS (1 << 8) +#define GBL_STS (1 << 5) +#define BM_STS (1 << 4) +#define TMROF_STS (1 << 0) #define RTC_EN (1 << 10) #define PWRBTN_EN (1 << 8) @@ -36,62 +39,95 @@ extern "C" { #define SCI_EN (1 << 0) #define SUS_EN (1 << 13) +#define SUS_POWER_OFF (1 << 0) +#define SUS_SUSPEND (1 << 1) +#define SUS_NVR (1 << 2) +#define SUS_RESET_CPU (1 << 3) +#define SUS_RESET_CACHE (1 << 4) +#define SUS_RESET_PCI (1 << 5) + #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -#define VEN_INTEL 0x8086 -#define VEN_VIA 0x1106 +#define VEN_ALI 0x010b9 +#define VEN_INTEL 0x08086 +#define VEN_SIS 0x01039 +#define VEN_SMC 0x01055 +#define VEN_VIA 0x01106 +#define VEN_VIA_596B 0x11106 typedef struct { - uint8_t plvl2, plvl3, + uint8_t acpitst, auxen, auxsts, plvl2, plvl3, smicmd, gpio_dir, - gpio_val, extsmi_val, - timer32, - gpireg[3], gporeg[4]; + gpio_val, muxcntrl, ali_soft_smi, + timer32, smireg, + gpireg[3], gporeg[4], + extiotrapsts, extiotrapen; uint16_t pmsts, pmen, - pmcntrl, gpsts, - gpen, io_base, - gpscien, gpsmien, - pscntrl, gpo_val, - gpi_val; - int slot, irq_mode, - irq_pin, smi_lock, - smi_active; - uint32_t pcntrl, glbsts, + pmcntrl, gpsts, gpsts1, + gpen, gpen1, gpscien, + gpcntrl, gplvl, gpmux, + gpsel, gpsmien, pscntrl, + gpscists; + int smi_lock, smi_active; + uint32_t pcntrl, p2cntrl, glbsts, devsts, glben, glbctl, devctl, padsts, paden, - gptren, timer_val; - uint64_t tmr_overflow_time; + gptren, gptimer, + gpo_val, gpi_val, + extsmi_val, pad0; } acpi_regs_t; typedef struct { acpi_regs_t regs; - uint8_t gporeg_default[4]; - int vendor; - pc_timer_t timer; + uint8_t gpireg2_default, pad[3], + gporeg_default[4], + suspend_types[8]; + uint16_t io_base, aux_io_base; + int vendor, + slot, irq_mode, + irq_pin, irq_line, + mirq_is_level; + pc_timer_t timer, resume_timer; nvr_t *nvr; apm_t *apm; + void *i2c, + (*trap_update)(void *priv), *trap_priv; } acpi_t; /* Global variables. */ +extern int acpi_rtc_status; + +extern const device_t acpi_ali_device; extern const device_t acpi_intel_device; +extern const device_t acpi_smc_device; extern const device_t acpi_via_device; +extern const device_t acpi_via_596b_device; -/* Functions. */ +/* Functions */ +extern void acpi_update_irq(acpi_t *dev); +extern void acpi_raise_smi(void *priv, int do_smi); extern void acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en); +extern void acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en); extern void acpi_init_gporeg(acpi_t *dev, uint8_t val0, uint8_t val1, uint8_t val2, uint8_t val3); extern void acpi_set_timer32(acpi_t *dev, uint8_t timer32); extern void acpi_set_slot(acpi_t *dev, int slot); extern void acpi_set_irq_mode(acpi_t *dev, int irq_mode); extern void acpi_set_irq_pin(acpi_t *dev, int irq_pin); +extern void acpi_set_irq_line(acpi_t *dev, int irq_line); +extern void acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level); +extern void acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default); extern void acpi_set_nvr(acpi_t *dev, nvr_t *nvr); +extern void acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv); +extern uint8_t acpi_ali_soft_smi_status_read(acpi_t *dev); +extern void acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi); #ifdef __cplusplus } diff --git a/src/include/86box/bswap.h b/src/include/86box/bswap.h index a49c4f1bc..9683c395d 100644 --- a/src/include/86box/bswap.h +++ b/src/include/86box/bswap.h @@ -34,8 +34,9 @@ * Boston, MA 02111-1307 * USA. */ + #ifndef BSWAP_H -#define BSWAP_H +# define BSWAP_H #include @@ -72,20 +73,32 @@ ) #endif /*HAVE_BYTESWAP_H*/ +#if defined __has_builtin && __has_builtin(__builtin_bswap16) +#define bswap16(x) __builtin_bswap16(x) +#else static __inline uint16_t bswap16(uint16_t x) { return bswap_16(x); } +#endif +#if defined __has_builtin && __has_builtin(__builtin_bswap32) +#define bswap32(x) __builtin_bswap32(x) +#else static __inline uint32_t bswap32(uint32_t x) { return bswap_32(x); } +#endif +#if defined __has_builtin && __has_builtin(__builtin_bswap64) +#define bswap64(x) __builtin_bswap64(x) +#else static __inline uint64_t bswap64(uint64_t x) { return bswap_64(x); } +#endif static __inline void bswap16s(uint16_t *s) { @@ -228,4 +241,4 @@ static __inline void cpu_to_be32wu(uint32_t *p, uint32_t v) #undef le_bswaps #undef be_bswaps -#endif /* BSWAP_H */ +#endif /*BSWAP_H*/ diff --git a/src/include/86box/cartridge.h b/src/include/86box/cartridge.h new file mode 100644 index 000000000..390604e79 --- /dev/null +++ b/src/include/86box/cartridge.h @@ -0,0 +1,40 @@ +/* + * 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. + * + * Definitions for the PCjr cartridge emulation. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#ifndef EMU_CARTRIDGE_H +# define EMU_CARTRIDGE_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern char cart_fns[2][512]; + + +extern void cart_load(int drive, char *fn); +extern void cart_close(int drive); + +extern void cart_reset(void); + + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_CARTRIDGE_H*/ diff --git a/src/include/86box/cassette.h b/src/include/86box/cassette.h new file mode 100644 index 000000000..524c5d055 --- /dev/null +++ b/src/include/86box/cassette.h @@ -0,0 +1,173 @@ +/***************************************************************************** + * pce * + *****************************************************************************/ + +/***************************************************************************** + * File name: src/ibmpc/cassette.h * + * Created: 2008-11-25 by Hampa Hug * + * Copyright: (C) 2008-2019 Hampa Hug * + *****************************************************************************/ + +/***************************************************************************** + * This program is free software. You can redistribute it and / or modify it * + * under the terms of the GNU General Public License version 2 as published * + * by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY, without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * + * Public License for more details. * + *****************************************************************************/ + + +#ifndef PCE_IBMPC_CASSETTE_H +# define PCE_IBMPC_CASSETTE_H 1 + + +#include + + +typedef struct { + char save; + char pcm; + + unsigned char motor; + + unsigned long position; + + unsigned long position_save; + unsigned long position_load; + + unsigned char data_out; + unsigned char data_inp; + + int pcm_out_vol; + int pcm_out_val; + + unsigned cas_out_cnt; + unsigned char cas_out_buf; + + unsigned cas_inp_cnt; + unsigned char cas_inp_buf; + unsigned char cas_inp_bit; + + int pcm_inp_fir[3]; + + unsigned long clk; + + unsigned long clk_pcm; + + unsigned long clk_out; + unsigned long clk_inp; + + unsigned long srate; + + char close; + char *fname; + FILE *fp; + pc_timer_t timer; +} pc_cassette_t; + + +void pc_cas_init (pc_cassette_t *cas); +void pc_cas_free (pc_cassette_t *cas); + +pc_cassette_t *pc_cas_new (void); +void pc_cas_del (pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Set the cassette file + * @return True on error, false otherwise + *****************************************************************************/ +int pc_cas_set_fname (pc_cassette_t *cas, const char *fname); + +/*!*************************************************************************** + * @short Get the cassette mode + * @return True if in save mode, false if in load mode + *****************************************************************************/ +int pc_cas_get_mode (const pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Set the cassette mode + * @param save If true set save mode, otherwise set load mode + *****************************************************************************/ +void pc_cas_set_mode (pc_cassette_t *cas, int save); + +/*!*************************************************************************** + * @short Get the cassette pcm mode + * @return True if in pcm mode, false if in binary mode + *****************************************************************************/ +int pc_cas_get_pcm (const pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Set the cassette pcm mode + * @param pcm If true set pcm mode, otherwise set binary mode + *****************************************************************************/ +void pc_cas_set_pcm (pc_cassette_t *cas, int pcm); + +/*!*************************************************************************** + * @short Get the pcm sample rate + * @return The sample rate in Hz + *****************************************************************************/ +unsigned long pc_cas_get_srate (const pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Set the pcm sample rate + * @param pcm The sample rate in Hz + *****************************************************************************/ +void pc_cas_set_srate (pc_cassette_t *cas, unsigned long srate); + +/*!*************************************************************************** + * @short Rewind the cassette + *****************************************************************************/ +void pc_cas_rewind (pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Fast forward to the end of the cassette + *****************************************************************************/ +void pc_cas_append (pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Get the current load/save position + *****************************************************************************/ +unsigned long pc_cas_get_position (const pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Set the current load/save position + *****************************************************************************/ +int pc_cas_set_position (pc_cassette_t *cas, unsigned long pos); + +/*!*************************************************************************** + * @short Set the cassette motor status + *****************************************************************************/ +void pc_cas_set_motor (pc_cassette_t *cas, unsigned char val); + +/*!*************************************************************************** + * @short Get the current input from the cassette + *****************************************************************************/ +unsigned char pc_cas_get_inp (const pc_cassette_t *cas); + +/*!*************************************************************************** + * @short Set the current output to the cassette + *****************************************************************************/ +void pc_cas_set_out (pc_cassette_t *cas, unsigned char val); + +void pc_cas_print_state (const pc_cassette_t *cas); + +void pc_cas_clock (pc_cassette_t *cas, unsigned long cnt); +void pc_cas_advance (pc_cassette_t *cas); + + +extern pc_cassette_t * cassette; + +extern char cassette_fname[512]; +extern char cassette_mode[512]; +extern unsigned long cassette_pos, cassette_srate; +extern int cassette_enable; +extern int cassette_append, cassette_pcm; +extern int cassette_ui_writeprot; + +extern const device_t cassette_device; + + +#endif /*PCE_IBMPC_CASSETTE_H*/ diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 0df5d9c77..f9040a4ed 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -8,14 +8,12 @@ * * Generic CD-ROM drive core header. * - * - * * Author: Miran Grca, * * Copyright 2016-2019 Miran Grca. */ #ifndef EMU_CDROM_H -#define EMU_CDROM_H +# define EMU_CDROM_H #define CDROM_NUM 4 @@ -56,7 +54,7 @@ extern "C" { enum { CDROM_BUS_DISABLED = 0, - CDROM_BUS_ATAPI = 4, + CDROM_BUS_ATAPI = 5, CDROM_BUS_SCSI, CDROM_BUS_USB }; @@ -67,52 +65,57 @@ struct cdrom; typedef struct { - uint8_t attr, track, - index, - abs_m, abs_s, abs_f, - rel_m, rel_s, rel_f; + uint8_t attr, track, + index, + abs_m, abs_s, abs_f, + rel_m, rel_s, rel_f; } subchannel_t; typedef struct { - int number; - uint8_t attr, m, s, f; + int number; + uint8_t attr, m, s, f; } track_info_t; /* Define the various CD-ROM drive operations (ops). */ typedef struct { - void (*get_tracks)(struct cdrom *dev, int *first, int *last); - void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti); - void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); - int (*sector_size)(struct cdrom *dev, uint32_t lba); - int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba); - int (*track_type)(struct cdrom *dev, uint32_t lba); - void (*exit)(struct cdrom *dev); + void (*get_tracks)(struct cdrom *dev, int *first, int *last); + void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti); + void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); + int (*is_track_pre)(struct cdrom *dev, uint32_t lba); + int (*sector_size)(struct cdrom *dev, uint32_t lba); + int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba); + int (*track_type)(struct cdrom *dev, uint32_t lba); + void (*exit)(struct cdrom *dev); } cdrom_ops_t; typedef struct cdrom { - uint8_t id, - res, res0, /* Reserved for other ID's. */ - res1, - ide_channel, scsi_device_id, - bus_type, /* 0 = ATAPI, 1 = SCSI */ - bus_mode, /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - cd_status, /* Struct variable reserved for - media status. */ - speed, cur_speed; + uint8_t id; + + union { + uint8_t res, res0, /* Reserved for other ID's. */ + res1, + ide_channel, scsi_device_id; + }; + + uint8_t bus_type, /* 0 = ATAPI, 1 = SCSI */ + bus_mode, /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + cd_status, /* Struct variable reserved for + media status. */ + speed, cur_speed; FILE* img_fp; void *priv; - wchar_t image_path[1024], - prev_image_path[1024]; + char image_path[1024], + prev_image_path[1024]; uint32_t sound_on, cdrom_capacity, - pad, seek_pos, - seek_diff, cd_end; + pad, seek_pos, + seek_diff, cd_end; int host_drive, prev_host_drive, - cd_buflen, noplay; + cd_buflen, noplay; const cdrom_ops_t *ops; @@ -132,6 +135,7 @@ extern cdrom_t cdrom[CDROM_NUM]; extern int cdrom_lba_to_msf_accurate(int lba); extern double cdrom_seek_time(cdrom_t *dev); extern void cdrom_stop(cdrom_t *dev); +extern int cdrom_is_pre(cdrom_t *dev, uint32_t lba); extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len); extern uint8_t cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf); extern uint8_t cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit); @@ -141,6 +145,7 @@ extern uint8_t cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf); extern uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b); extern int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_track, int msf, int max_len); +extern void cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf); extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); extern void cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type); @@ -152,7 +157,7 @@ extern void cdrom_insert(uint8_t id); extern void cdrom_eject(uint8_t id); extern void cdrom_reload(uint8_t id); -extern int cdrom_image_open(cdrom_t *dev, const wchar_t *fn); +extern int cdrom_image_open(cdrom_t *dev, const char *fn); extern void cdrom_image_close(cdrom_t *dev); extern void cdrom_image_reset(cdrom_t *dev); diff --git a/src/include/86box/cdrom_image.h b/src/include/86box/cdrom_image.h index 415956e56..ea3ca18a8 100644 --- a/src/include/86box/cdrom_image.h +++ b/src/include/86box/cdrom_image.h @@ -1,8 +1,22 @@ -/* Copyright holders: RichardG867, Tenshi - see COPYING for more details -*/ +/* + * 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. + * + * CD-ROM image file handling module header, translated to C + * from cdrom_dosbox.h. + * + * Authors: RichardG, + * Miran Grca, + * + * Copyright 2016-2022 RichardG. + * Copyright 2016-2022 Miran Grca. + */ #ifndef CDROM_IMAGE_H -#define CDROM_IMAGE_H +# define CDROM_IMAGE_H /* this header file lists the functions provided by various platform specific cdrom-ioctl files */ @@ -23,4 +37,4 @@ extern void cdrom_set_null_handler(uint8_t id); } #endif -#endif /* ! CDROM_IMAGE_H */ +#endif /*CDROM_IMAGE_H*/ diff --git a/src/include/86box/cdrom_image_backend.h b/src/include/86box/cdrom_image_backend.h index 837a7459d..6fe26d1e3 100644 --- a/src/include/86box/cdrom_image_backend.h +++ b/src/include/86box/cdrom_image_backend.h @@ -9,8 +9,6 @@ * CD-ROM image file handling module header , translated to C * from cdrom_dosbox.h. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * The DOSBox Team, @@ -20,7 +18,7 @@ * Copyright 2002-2020 The DOSBox Team. */ #ifndef CDROM_IMAGE_BACKEND_H -#define CDROM_IMAGE_BACKEND_H +# define CDROM_IMAGE_BACKEND_H #define RAW_SECTOR_SIZE 2352 #define COOKED_SECTOR_SIZE 2048 @@ -41,55 +39,55 @@ typedef struct SMSF { - uint16_t min; - uint8_t sec; - uint8_t fr; + uint16_t min; + uint8_t sec; + uint8_t fr; } TMSF; /* Track file struct. */ typedef struct { - int (*read)(void *p, uint8_t *buffer, uint64_t seek, size_t count); - uint64_t (*get_length)(void *p); - void (*close)(void *p); + int (*read)(void *p, uint8_t *buffer, uint64_t seek, size_t count); + uint64_t (*get_length)(void *p); + void (*close)(void *p); - wchar_t fn[260]; - FILE *file; + char fn[260]; + FILE *file; } track_file_t; typedef struct { - int number, track_number, attr, sector_size, - mode2, form; - uint64_t start, length, - skip; - track_file_t *file; + int number, track_number, attr, sector_size, + mode2, form, pre, pad; + uint64_t start, length, + skip; + track_file_t *file; } track_t; typedef struct { - int tracks_num; - track_t *tracks; + int tracks_num; + track_t *tracks; } cd_img_t; /* Binary file functions. */ -extern void cdi_close(cd_img_t *cdi); -extern int cdi_set_device(cd_img_t *cdi, const wchar_t *path); -extern int cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out); -extern int cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out); -extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr); -extern int cdi_get_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, uint32_t *start, uint8_t *attr); -extern int cdi_get_track(cd_img_t *cdi, uint32_t sector); -extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); -extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); -extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num); -extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); -extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector); -extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector); -extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector); -extern int cdi_load_iso(cd_img_t *cdi, const wchar_t *filename); -extern int cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile); -extern int cdi_has_data_track(cd_img_t *cdi); -extern int cdi_has_audio_track(cd_img_t *cdi); +extern void cdi_close(cd_img_t *cdi); +extern int cdi_set_device(cd_img_t *cdi, const char *path); +extern int cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out); +extern int cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out); +extern int cdi_get_audio_track_pre(cd_img_t *cdi, int track); +extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr); +extern int cdi_get_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, uint32_t *start, uint8_t *attr); +extern int cdi_get_track(cd_img_t *cdi, uint32_t sector); +extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); +extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); +extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num); +extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); +extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector); +extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector); +extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector); +extern int cdi_load_iso(cd_img_t *cdi, const char *filename); +extern int cdi_load_cue(cd_img_t *cdi, const char *cuefile); +extern int cdi_has_data_track(cd_img_t *cdi); +extern int cdi_has_audio_track(cd_img_t *cdi); - -#endif /* ! CDROM_IMAGE_BACKEND_H */ +#endif /*CDROM_IMAGE_BACKEND_H*/ diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index a94564e68..eddb37bff 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -21,23 +21,57 @@ /* ACC */ extern const device_t acc2168_device; -/* Acer M3A and V35N */ -extern const device_t acerm3a_device; - /* ALi */ +extern const device_t ali1217_device; extern const device_t ali1429_device; +extern const device_t ali1429g_device; +extern const device_t ali1489_device; +extern const device_t ali1531_device; +extern const device_t ali1541_device; +extern const device_t ali1543_device; +extern const device_t ali1543c_device; +extern const device_t ali1621_device; +extern const device_t ali6117d_device; + +/* AMD */ +extern const device_t amd640_device; + +/* Contaq/Cypress */ +extern const device_t contaq_82c596a_device; +extern const device_t contaq_82c597_device; + +/* C&T */ +extern const device_t ct_82c100_device; +extern const device_t neat_device; +extern const device_t scat_device; +extern const device_t scat_4_device; +extern const device_t scat_sx_device; +extern const device_t cs8230_device; +extern const device_t cs4031_device; + +/* G2 */ +extern const device_t gc100_device; +extern const device_t gc100a_device; /* Headland */ -extern const device_t headland_device; -extern const device_t headland_386_device; +extern const device_t headland_gc10x_device; +extern const device_t headland_ht18a_device; +extern const device_t headland_ht18b_device; +extern const device_t headland_ht18c_device; -/* Intel 4x0xX */ +/* IMS */ +extern const device_t ims8848_device; + +/* Intel */ +extern const device_t intel_82335_device; extern const device_t i420ex_device; +extern const device_t i420ex_ide_device; extern const device_t i420tx_device; extern const device_t i420zx_device; extern const device_t i430lx_device; extern const device_t i430nx_device; extern const device_t i430fx_device; +extern const device_t i430fx_old_device; extern const device_t i430fx_rev02_device; extern const device_t i430hx_device; extern const device_t i430vx_device; @@ -46,15 +80,19 @@ extern const device_t i440fx_device; extern const device_t i440lx_device; extern const device_t i440ex_device; extern const device_t i440bx_device; +extern const device_t i440bx_no_agp_device; extern const device_t i440gx_device; extern const device_t i440zx_device; +extern const device_t i450kx_device; extern const device_t sio_device; extern const device_t sio_zb_device; extern const device_t piix_device; +extern const device_t piix_old_device; extern const device_t piix_rev02_device; extern const device_t piix3_device; +extern const device_t piix3_ioapic_device; extern const device_t piix4_device; extern const device_t piix4e_device; extern const device_t slc90e66_device; @@ -62,38 +100,73 @@ extern const device_t slc90e66_device; extern const device_t ioapic_device; /* OPTi */ +extern const device_t opti283_device; +extern const device_t opti291_device; +extern const device_t opti493_device; extern const device_t opti495_device; -extern const device_t opti5x7_device; +extern const device_t opti802g_device; +extern const device_t opti822_device; +extern const device_t opti895_device; -/* C&T */ -extern const device_t neat_device; -extern const device_t scat_device; -extern const device_t scat_4_device; -extern const device_t scat_sx_device; -extern const device_t cs8230_device; +extern const device_t opti5x7_device; /* SiS */ extern const device_t rabbit_device; +extern const device_t sis_85c401_device; +extern const device_t sis_85c460_device; +extern const device_t sis_85c461_device; extern const device_t sis_85c471_device; extern const device_t sis_85c496_device; -#if defined(DEV_BRANCH) && defined(USE_SIS_85C50X) +extern const device_t sis_85c496_ls486e_device; extern const device_t sis_85c50x_device; -#endif +extern const device_t sis_5511_device; +extern const device_t sis_5571_device; + +/* ST */ +extern const device_t stpc_client_device; +extern const device_t stpc_consumer2_device; +extern const device_t stpc_elite_device; +extern const device_t stpc_atlas_device; +extern const device_t stpc_serial_device; +extern const device_t stpc_lpt_device; + +/* UMC */ +extern const device_t umc_8886f_device; +extern const device_t umc_8886af_device; +extern const device_t umc_hb4_device; /* VIA */ +extern const device_t via_vt82c49x_device; +extern const device_t via_vt82c49x_pci_device; +extern const device_t via_vt82c49x_pci_ide_device; +extern const device_t via_vt82c505_device; extern const device_t via_vpx_device; extern const device_t via_vp3_device; extern const device_t via_mvp3_device; extern const device_t via_apro_device; - +extern const device_t via_apro133_device; +extern const device_t via_apro133a_device; +extern const device_t via_vt8601_device; extern const device_t via_vt82c586b_device; +extern const device_t via_vt82c596a_device; extern const device_t via_vt82c596b_device; +extern const device_t via_vt82c686a_device; +extern const device_t via_vt82c686b_device; +extern const device_t via_vt8231_device; /* VLSI */ +extern const device_t vl82c480_device; +extern const device_t vl82c486_device; extern const device_t vlsi_scamp_device; /* WD */ extern const device_t wd76c10_device; +/* Miscellaneous Hardware */ +extern const device_t phoenix_486_jumper_device; +extern const device_t phoenix_486_jumper_pci_device; +#if defined(DEV_BRANCH) && defined(USE_OLIVETTI) +extern const device_t olivetti_eva_device; +#endif #endif /*EMU_CHIPSET_H*/ diff --git a/src/include/86box/clock.h b/src/include/86box/clock.h new file mode 100644 index 000000000..7d2be9f05 --- /dev/null +++ b/src/include/86box/clock.h @@ -0,0 +1,62 @@ +/* + * 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. + * + * Definitions for clock generator chips. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#ifndef EMU_CLOCK_H +# define EMU_CLOCK_H + +/* clock_ics9xxx.c */ +enum { + ICS9xxx_xx, + ICS9150_08, + ICS9248_39, + ICS9248_81, + ICS9248_95, + ICS9248_98, + ICS9248_101, + ICS9248_103, + ICS9248_107, + ICS9248_112, + ICS9248_138, + ICS9248_141, + ICS9248_143, + ICS9248_151, + ICS9248_192, + ICS9250_08, + ICS9250_10, + ICS9250_13, + ICS9250_14, + ICS9250_16, + ICS9250_18, + ICS9250_19, + ICS9250_23, + ICS9250_25, + ICS9250_26, + ICS9250_27, + ICS9250_28, + ICS9250_29, + ICS9250_30, + ICS9250_32, + ICS9250_38, + ICS9250_50, + ICS9xxx_MAX +}; + + +/* clock_ics9xxx.c */ +extern device_t *ics9xxx_get(uint8_t model); + + +#endif /*EMU_CLOCK_H*/ diff --git a/src/include/86box/config.h b/src/include/86box/config.h index 1a82a0879..41c9900ed 100644 --- a/src/include/86box/config.h +++ b/src/include/86box/config.h @@ -75,7 +75,6 @@ typedef struct { /* Machine cateogory */ int machine, /* Machine */ - cpu_manufacturer, /* CPU manufacturer */ cpu, /* CPU */ #ifdef USE_DYNAREC cpu_use_dynarec, /* CPU recompiler enabled */ @@ -109,12 +108,12 @@ typedef struct { char network_host[520]; /* PCap device */ /* Ports category */ - char parallel_devices[3][32]; /* LPT device names */ + char parallel_devices[PARALLEL_MAX][32]; /* LPT device names */ #ifdef USE_SERIAL_DEVICES - char serial_devices[2][32]; /* Serial device names */ + char serial_devices[SERIAL_MAX][32]; /* Serial device names */ #endif - int serial_enabled[2], /* Serial ports 1 and 2 enabled */ - parallel_enabled[3]; /* LPT1, LPT2, LPT3 enabled */ + int serial_enabled[SERIAL_MAX], /* Serial ports 1, 2, 3, 4 enabled */ + parallel_enabled[PARALLEL_MAX]; /* LPT1, LPT2, LPT3, LPT4 enabled */ /* Other peripherals category */ int fdc_type, /* Floppy disk controller type */ @@ -140,23 +139,28 @@ typedef struct { extern void config_load(void); extern void config_save(void); -extern void config_write(wchar_t *fn); +extern void config_write(char *fn); extern void config_dump(void); extern void config_delete_var(char *head, char *name); extern int config_get_int(char *head, char *name, int def); +extern double config_get_double(char *head, char *name, double def); extern int config_get_hex16(char *head, char *name, int def); extern int config_get_hex20(char *head, char *name, int def); extern int config_get_mac(char *head, char *name, int def); extern char *config_get_string(char *head, char *name, char *def); extern wchar_t *config_get_wstring(char *head, char *name, wchar_t *def); extern void config_set_int(char *head, char *name, int val); +extern void config_set_double(char *head, char *name, double val); extern void config_set_hex16(char *head, char *name, int val); extern void config_set_hex20(char *head, char *name, int val); extern void config_set_mac(char *head, char *name, int val); extern void config_set_string(char *head, char *name, char *val); extern void config_set_wstring(char *head, char *name, wchar_t *val); +extern void * config_find_section(char *name); +extern void config_rename_section(void *priv, char *name); + #ifdef __cplusplus } #endif diff --git a/src/include/86box/device.h b/src/include/86box/device.h index ecfb5bc59..20a4babc5 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -40,31 +40,36 @@ # define EMU_DEVICE_H -#define CONFIG_STRING 0 -#define CONFIG_INT 1 -#define CONFIG_BINARY 2 -#define CONFIG_SELECTION 3 -#define CONFIG_MIDI 4 -#define CONFIG_FNAME 5 -#define CONFIG_SPINNER 6 -#define CONFIG_HEX16 7 -#define CONFIG_HEX20 8 -#define CONFIG_MAC 9 -#define CONFIG_MIDI_IN 10 +#define CONFIG_END -1 +#define CONFIG_STRING 0 +#define CONFIG_INT 1 +#define CONFIG_BINARY 2 +#define CONFIG_SELECTION 3 +#define CONFIG_MIDI_OUT 4 +#define CONFIG_FNAME 5 +#define CONFIG_SPINNER 6 +#define CONFIG_HEX16 7 +#define CONFIG_HEX20 8 +#define CONFIG_MAC 9 +#define CONFIG_MIDI_IN 10 +#define CONFIG_BIOS 11 enum { DEVICE_NOT_WORKING = 1, /* does not currently work correctly and will be disabled in a release build */ DEVICE_PCJR = 2, /* requires an IBM PCjr */ - DEVICE_AT = 4, /* requires an AT-compatible system */ - DEVICE_PS2 = 8, /* requires a PS/1 or PS/2 system */ + DEVICE_AT = 4, /* requires an AT-compatible system */ + DEVICE_PS2 = 8, /* requires a PS/1 or PS/2 system */ DEVICE_ISA = 0x10, /* requires the ISA bus */ DEVICE_CBUS = 0x20, /* requires the C-BUS bus */ DEVICE_MCA = 0x40, /* requires the MCA bus */ DEVICE_EISA = 0x80, /* requires the EISA bus */ DEVICE_VLB = 0x100, /* requires the PCI bus */ DEVICE_PCI = 0x200, /* requires the VLB bus */ - DEVICE_AGP = 0x400 /* requires the AGP bus */ + DEVICE_AGP = 0x400, /* requires the AGP bus */ + DEVICE_AC97 = 0x800, /* requires the AC'97 bus */ + DEVICE_COM = 0x1000, /* requires a serial port */ + DEVICE_LPT = 0x2000 /* requires a parallel port */ }; @@ -74,14 +79,17 @@ typedef struct { } device_config_selection_t; typedef struct { - const char *description; - const char *extensions[5]; -} device_config_file_filter_t; + const char *name; + const char *internal_name; + int bios_type; + int files_no; + const char **files; +} device_config_bios_t; typedef struct { - int min; - int max; - int step; + int16_t min; + int16_t max; + int16_t step; } device_config_spinner_t; typedef struct { @@ -90,20 +98,26 @@ typedef struct { int type; const char *default_string; int default_int; - device_config_selection_t selection[16]; - device_config_file_filter_t file_filter[16]; - device_config_spinner_t spinner; + const char *file_filter; + const device_config_spinner_t spinner; + const device_config_selection_t selection[16]; + const device_config_bios_t *bios; } device_config_t; typedef struct _device_ { const char *name; + const char *internal_name; uint32_t flags; /* system flags */ uint32_t local; /* flags local to device */ void *(*init)(const struct _device_ *); void (*close)(void *priv); void (*reset)(void *priv); - int (*available)(/*void*/); + union { + int (*available)(void); + int (*poll)(int x, int y, int z, int b, void *priv); + void (*register_pci_slot)(int device, int type, int inta, int intb, int intc, int intd, void *priv); + }; void (*speed_changed)(void *priv); void (*force_redraw)(void *priv); @@ -138,10 +152,14 @@ extern void device_reset_all(void); extern void device_reset_all_pci(void); extern void *device_get_priv(const device_t *d); extern int device_available(const device_t *d); +extern int device_poll(const device_t *d, int x, int y, int z, int b); +extern void device_register_pci_slot(const device_t *d, int device, int type, int inta, int intb, int intc, int intd); extern void device_speed_changed(void); extern void device_force_redraw(void); +extern void device_get_name(const device_t *d, int bus, char *name); +extern int device_has_config(const device_t *d); -extern int device_is_valid(const device_t *, int machine_flags); +extern int device_is_valid(const device_t *, int m); extern int device_get_config_int(const char *name); extern int device_get_config_int_ex(const char *s, int dflt_int); @@ -153,6 +171,9 @@ extern void device_set_config_hex16(const char *s, int val); extern void device_set_config_hex20(const char *s, int val); extern void device_set_config_mac(const char *s, int val); extern const char *device_get_config_string(const char *name); +#define device_get_config_bios device_get_config_string + +extern char * device_get_internal_name(const device_t *d); extern int machine_get_config_int(char *s); extern char *machine_get_config_string(char *s); diff --git a/src/include/86box/win_discord.h b/src/include/86box/discord.h similarity index 90% rename from src/include/86box/win_discord.h rename to src/include/86box/discord.h index 9e56b9a32..90621e16d 100644 --- a/src/include/86box/win_discord.h +++ b/src/include/86box/discord.h @@ -17,6 +17,11 @@ #ifndef WIN_DISCORD_H # define WIN_DISCORD_H +#ifdef __cplusplus +extern "C" +{ +#endif + extern int discord_loaded; extern int discord_load(); @@ -25,4 +30,8 @@ extern void discord_close(); extern void discord_update_activity(int paused); extern void discord_run_callbacks(); -#endif \ No newline at end of file +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/86box/dma.h b/src/include/86box/dma.h index d5ee9fcb3..585d77e95 100644 --- a/src/include/86box/dma.h +++ b/src/include/86box/dma.h @@ -66,6 +66,7 @@ typedef struct { extern dma_t dma[8]; extern uint8_t dma_e; +extern uint8_t dma_m; extern void dma_init(void); @@ -96,8 +97,11 @@ extern void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalS extern void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize); void dma_set_params(uint8_t advanced, uint32_t mask); -void dma_ext_mode_init(void); +void dma_set_mask(uint32_t mask); +void dma_set_at(uint8_t at); + +void dma_ext_mode_init(void); void dma_high_page_init(void); void dma_remove_sg(void); diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index 56249069b..fa763b0ef 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -24,6 +24,22 @@ extern int fdc_type; +#define FDC_PRIMARY_ADDR 0x03f0 +#define FDC_PRIMARY_IRQ 6 +#define FDC_PRIMARY_DMA 2 +#define FDC_PRIMARY_PCJR_ADDR 0x00f0 +#define FDC_PRIMARY_PCJR_IRQ 6 +#define FDC_PRIMARY_PCJR_DMA 2 +#define FDC_SECONDARY_ADDR 0x0370 +#define FDC_SECONDARY_IRQ 6 +#define FDC_SECONDARY_DMA 2 +#define FDC_TERTIARY_ADDR 0x0360 +#define FDC_TERTIARY_IRQ 6 +#define FDC_TERTIARY_DMA 2 +#define FDC_QUATERNARY_ADDR 0x03e0 +#define FDC_QUATERNARY_IRQ 6 +#define FDC_QUATERNARY_DMA 2 + #define FDC_FLAG_PCJR 0x01 /* PCjr */ #define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */ #define FDC_FLAG_AT 0x04 /* AT+, PS/x */ @@ -34,30 +50,29 @@ extern int fdc_type; #define FDC_FLAG_NSC 0x80 /* PC87306, PC87309 */ #define FDC_FLAG_TOSHIBA 0x100 /* T1000, T1200 */ #define FDC_FLAG_AMSTRAD 0x200 /* Non-AT Amstrad machines */ -#define FDC_FLAG_NSDP 0x400 /* DP8473N, DP8473V */ +#define FDC_FLAG_UMC 0x400 /* UMC UM8398 */ +#define FDC_FLAG_ALI 0x800 /* ALi M512x / M1543C */ typedef struct { - uint8_t dor, stat, command, processed_cmd, dat, st0, swap; - uint8_t swwp, disable_write; - uint8_t params[256], res[256]; - uint8_t specify[256], format_dat[256]; + uint8_t dor, stat, command, processed_cmd, dat, st0, swap, dtl; + uint8_t swwp, disable_write, st5, st6, error; + uint8_t params[8], res[11]; + uint8_t specify[2]; uint8_t config, pretrk; uint8_t fifobuf[16]; uint16_t base_address; int head, sector, drive, lastdrive; - int pcn[4], eot[256]; + int pcn[4], eot[4]; int rw_track, pos; int pnum, ptot; int rate, reset_stat; int lock, perp; - int abort; int format_state, format_n; - int tc, written; int step, seek_dir; - int noprec; + int tc, noprec; int data_ready, inread; int bitcell_period, enh_mode; @@ -67,7 +82,7 @@ typedef struct { int fifo, tfifo; int fifobufpos, drv2en; - int gap, dtl; + int gap; int enable_3f1, format_sectors; int max_track, mfm; int deleted, wrong_am; @@ -82,11 +97,11 @@ typedef struct { int bit_rate; /* Should be 250 at start. */ int paramstogo; - sector_id_t read_track_sector; + sector_id_t read_track_sector, format_sector_id; - uint64_t watchdog_count; - - pc_timer_t timer, watchdog_timer; + uint64_t watchdog_count; + + pc_timer_t timer, watchdog_timer; } fdc_t; @@ -157,8 +172,9 @@ extern int fdc_is_verify(fdc_t *fdc); extern void fdc_overrun(fdc_t *fdc); extern void fdc_set_base(fdc_t *fdc, int base); extern void fdc_set_irq(fdc_t *fdc, int irq); +extern void fdc_set_dma_ch(fdc_t *fdc, int dma_ch); extern int fdc_getdata(fdc_t *fdc, int last); -extern int fdc_data(fdc_t *fdc, uint8_t data); +extern int fdc_data(fdc_t *fdc, uint8_t data, int last); extern void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, @@ -172,15 +188,18 @@ extern uint8_t fdc_get_current_drive(void); #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device; extern const device_t fdc_xt_t1x00_device; +extern const device_t fdc_xt_tandy_device; extern const device_t fdc_xt_amstrad_device; extern const device_t fdc_pcjr_device; extern const device_t fdc_at_device; extern const device_t fdc_at_actlow_device; extern const device_t fdc_at_ps1_device; extern const device_t fdc_at_smc_device; +extern const device_t fdc_at_ali_device; extern const device_t fdc_at_winbond_device; extern const device_t fdc_at_nsc_device; extern const device_t fdc_dp8473_device; +extern const device_t fdc_um8398_device; #endif #endif /*EMU_FDC_H*/ diff --git a/src/include/86box/fdc_ext.h b/src/include/86box/fdc_ext.h index 1e10e4b7a..c87786dc0 100644 --- a/src/include/86box/fdc_ext.h +++ b/src/include/86box/fdc_ext.h @@ -27,12 +27,12 @@ extern int fdc_type; /* Controller types. */ #define FDC_INTERNAL 0 +extern const device_t fdc_b215_device; extern const device_t fdc_pii151b_device; extern const device_t fdc_pii158b_device; extern void fdc_card_init(void); -extern char *fdc_card_getname(int card); extern char *fdc_card_get_internal_name(int card); extern int fdc_card_get_from_internal_name(char *s); extern const device_t *fdc_card_getdevice(int card); diff --git a/src/include/86box/fdd.h b/src/include/86box/fdd.h index ccd420924..cdb00063c 100644 --- a/src/include/86box/fdd.h +++ b/src/include/86box/fdd.h @@ -87,7 +87,7 @@ typedef struct { extern DRIVE drives[FDD_NUM]; -extern wchar_t floppyfns[FDD_NUM][512]; +extern char floppyfns[FDD_NUM][512]; extern pc_timer_t fdd_poll_time[FDD_NUM]; extern int ui_writeprot[FDD_NUM]; @@ -97,7 +97,7 @@ extern int fdd_time; extern int64_t floppytime; -extern void fdd_load(int drive, wchar_t *fn); +extern void fdd_load(int drive, char *fn); extern void fdd_new(int drive, char *fn); extern void fdd_close(int drive); extern void fdd_init(void); @@ -113,6 +113,7 @@ extern void fdd_readaddress(int drive, int side, int density); extern void fdd_format(int drive, int side, int density, uint8_t fill); extern int fdd_hole(int drive); extern void fdd_stop(int drive); +extern void fdd_do_writeback(int drive); extern int motorspin; extern uint64_t motoron[FDD_NUM]; diff --git a/src/include/86box/fdd_86f.h b/src/include/86box/fdd_86f.h index 0b8e5c76c..da7e7b819 100644 --- a/src/include/86box/fdd_86f.h +++ b/src/include/86box/fdd_86f.h @@ -43,7 +43,7 @@ #else #define pre_gap1 0 #endif - + #define pre_track pre_gap1 + length_gap1 #define pre_gap length_sync + length_am + 4 + length_crc #define pre_data length_sync + length_am @@ -54,7 +54,7 @@ extern d86f_handler_t d86f_handler[FDD_NUM]; extern void d86f_init(void); -extern void d86f_load(int drive, wchar_t *fn); +extern void d86f_load(int drive, char *fn); extern void d86f_close(int drive); extern void d86f_seek(int drive, int track); extern int d86f_hole(int drive); @@ -81,7 +81,7 @@ extern uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t * int data_len, int gap2, int gap3, int flags); extern void d86f_setup(int drive); extern void d86f_destroy(int drive); -extern int d86f_export(int drive, wchar_t *fn); +extern int d86f_export(int drive, char *fn); extern void d86f_unregister(int drive); extern void d86f_common_handlers(int drive); extern void d86f_set_version(int drive, uint16_t version); diff --git a/src/include/86box/fdd_fdi.h b/src/include/86box/fdd_fdi.h index 80c5be202..e6d75c664 100644 --- a/src/include/86box/fdd_fdi.h +++ b/src/include/86box/fdd_fdi.h @@ -24,7 +24,7 @@ extern void fdi_seek(int drive, int track); -extern void fdi_load(int drive, wchar_t *fn); +extern void fdi_load(int drive, char *fn); extern void fdi_close(int drive); diff --git a/src/include/86box/fdd_imd.h b/src/include/86box/fdd_imd.h index 23c346d9d..3c20025d2 100644 --- a/src/include/86box/fdd_imd.h +++ b/src/include/86box/fdd_imd.h @@ -39,7 +39,7 @@ extern void imd_init(void); -extern void imd_load(int drive, wchar_t *fn); +extern void imd_load(int drive, char *fn); extern void imd_close(int drive); diff --git a/src/include/86box/fdd_img.h b/src/include/86box/fdd_img.h index cbfff4d3a..bb39fed09 100644 --- a/src/include/86box/fdd_img.h +++ b/src/include/86box/fdd_img.h @@ -24,7 +24,7 @@ extern void img_init(void); -extern void img_load(int drive, wchar_t *fn); +extern void img_load(int drive, char *fn); extern void img_close(int drive); diff --git a/src/include/86box/fdd_json.h b/src/include/86box/fdd_json.h index 8ae1c7094..4a62c089b 100644 --- a/src/include/86box/fdd_json.h +++ b/src/include/86box/fdd_json.h @@ -49,7 +49,7 @@ extern void json_init(void); -extern void json_load(int drive, wchar_t *fn); +extern void json_load(int drive, char *fn); extern void json_close(int drive); diff --git a/src/include/86box/fdd_mfm.h b/src/include/86box/fdd_mfm.h index 9ed2a333e..5fd664b05 100644 --- a/src/include/86box/fdd_mfm.h +++ b/src/include/86box/fdd_mfm.h @@ -19,7 +19,7 @@ extern void mfm_seek(int drive, int track); -extern void mfm_load(int drive, wchar_t *fn); +extern void mfm_load(int drive, char *fn); extern void mfm_close(int drive); diff --git a/src/include/86box/fdd_td0.h b/src/include/86box/fdd_td0.h index 305968517..6dd79a8ce 100644 --- a/src/include/86box/fdd_td0.h +++ b/src/include/86box/fdd_td0.h @@ -21,7 +21,7 @@ extern void td0_init(void); -extern void td0_load(int drive, wchar_t *fn); +extern void td0_load(int drive, char *fn); extern void td0_close(int drive); diff --git a/src/include/86box/fifo8.h b/src/include/86box/fifo8.h new file mode 100644 index 000000000..d1c32fdd7 --- /dev/null +++ b/src/include/86box/fifo8.h @@ -0,0 +1,149 @@ +#ifndef EMU_FIFO8_H +#define EMU_FIFO8_H + + +typedef struct { + /* All fields are private */ + uint8_t *data; + uint32_t capacity; + uint32_t head; + uint32_t num; +} Fifo8; + +/** + * fifo8_create: + * @fifo: struct Fifo8 to initialise with new FIFO + * @capacity: capacity of the newly created FIFO + * + * Create a FIFO of the specified size. Clients should call fifo8_destroy() + * when finished using the fifo. The FIFO is initially empty. + */ + +extern void fifo8_create(Fifo8 *fifo, uint32_t capacity); + +/** + * fifo8_destroy: + * @fifo: FIFO to cleanup + * + * Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO + *storage. The FIFO is no longer usable after this has been called. + */ + +extern void fifo8_destroy(Fifo8 *fifo); + +/** + * fifo8_push: + * @fifo: FIFO to push to + * @data: data byte to push + * + * Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full. + * Clients are responsible for checking for fullness using fifo8_is_full(). + */ + +extern void fifo8_push(Fifo8 *fifo, uint8_t data); + +/** + * fifo8_push_all: + * @fifo: FIFO to push to + * @data: data to push + * @size: number of bytes to push + * + * Push a byte array to the FIFO. Behaviour is undefined if the FIFO is full. + * Clients are responsible for checking the space left in the FIFO using + * fifo8_num_free(). + */ + +extern void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num); + +/** + * fifo8_pop: + * @fifo: fifo to pop from + * + * Pop a data byte from the FIFO. Behaviour is undefined if the FIFO is empty. + * Clients are responsible for checking for emptyness using fifo8_is_empty(). + * + * Returns: The popped data byte. + */ + +extern uint8_t fifo8_pop(Fifo8 *fifo); + +/** + * fifo8_pop_buf: + * @fifo: FIFO to pop from + * @max: maximum number of bytes to pop + * @num: actual number of returned bytes + * + * Pop a number of elements from the FIFO up to a maximum of max. The buffer + * containing the popped data is returned. This buffer points directly into + * the FIFO backing store and data is invalidated once any of the fifo8_* APIs + * are called on the FIFO. + * + * The function may return fewer bytes than requested when the data wraps + * around in the ring buffer; in this case only a contiguous part of the data + * is returned. + * + * The number of valid bytes returned is populated in *num; will always return + * at least 1 byte. max must not be 0 or greater than the number of bytes in + * the FIFO. + * + * Clients are responsible for checking the availability of requested data + * using fifo8_num_used(). + * + * Returns: A pointer to popped data. + */ +extern const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num); + +/** + * fifo8_reset: + * @fifo: FIFO to reset + * + * Reset a FIFO. All data is discarded and the FIFO is emptied. + */ + +extern void fifo8_reset(Fifo8 *fifo); + +/** + * fifo8_is_empty: + * @fifo: FIFO to check + * + * Check if a FIFO is empty. + * + * Returns: True if the fifo is empty, false otherwise. + */ + +extern int fifo8_is_empty(Fifo8 *fifo); + +/** + * fifo8_is_full: + * @fifo: FIFO to check + * + * Check if a FIFO is full. + * + * Returns: True if the fifo is full, false otherwise. + */ + +extern int fifo8_is_full(Fifo8 *fifo); + +/** + * fifo8_num_free: + * @fifo: FIFO to check + * + * Return the number of free bytes in the FIFO. + * + * Returns: Number of free bytes. + */ + +extern uint32_t fifo8_num_free(Fifo8 *fifo); + +/** + * fifo8_num_used: + * @fifo: FIFO to check + * + * Return the number of used bytes in the FIFO. + * + * Returns: Number of used bytes. + */ + +extern uint32_t fifo8_num_used(Fifo8 *fifo); + +#endif /* EMU_FIFO8_H */ diff --git a/src/include/86box/filters.h b/src/include/86box/filters.h index 95354176e..65885d4d7 100644 --- a/src/include/86box/filters.h +++ b/src/include/86box/filters.h @@ -1,184 +1,6 @@ -#define NCoef 2 +#ifndef EMU_FILTERS_H +# define EMU_FILTERS_H -/* fc=350Hz */ -static inline float low_iir(int i, float NewSample) { - float ACoef[NCoef+1] = { - 0.00049713569693400649, - 0.00099427139386801299, - 0.00049713569693400649 - }; - - float BCoef[NCoef+1] = { - 1.00000000000000000000, - -1.93522955470669530000, - 0.93726236021404663000 - }; - - static float y[2][NCoef+1]; /* output samples */ - static float x[2][NCoef+1]; /* input samples */ - int n; - - /* shift the old samples */ - for(n=NCoef; n>0; n--) { - x[i][n] = x[i][n-1]; - y[i][n] = y[i][n-1]; - } - - /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; - for(n=1; n<=NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - - return y[i][0]; -} - -/* fc=350Hz */ -static inline float low_cut_iir(int i, float NewSample) { - float ACoef[NCoef+1] = { - 0.96839970114733542000, - -1.93679940229467080000, - 0.96839970114733542000 - }; - - float BCoef[NCoef+1] = { - 1.00000000000000000000, - -1.93522955471202770000, - 0.93726236021916731000 - }; - - static float y[2][NCoef+1]; /* output samples */ - static float x[2][NCoef+1]; /* input samples */ - int n; - - /* shift the old samples */ - for(n=NCoef; n>0; n--) { - x[i][n] = x[i][n-1]; - y[i][n] = y[i][n-1]; - } - - /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; - for(n=1; n<=NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - - return y[i][0]; -} - -/* fc=3.5kHz */ -static inline float high_iir(int i, float NewSample) { - float ACoef[NCoef+1] = { - 0.72248704753064896000, - -1.44497409506129790000, - 0.72248704753064896000 - }; - - float BCoef[NCoef+1] = { - 1.00000000000000000000, - -1.36640781670578510000, - 0.52352474706139873000 - }; - static float y[2][NCoef+1]; /* output samples */ - static float x[2][NCoef+1]; /* input samples */ - int n; - - /* shift the old samples */ - for(n=NCoef; n>0; n--) { - x[i][n] = x[i][n-1]; - y[i][n] = y[i][n-1]; - } - - /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; - for(n=1; n<=NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - - return y[i][0]; -} - -/* fc=3.5kHz */ -static inline float high_cut_iir(int i, float NewSample) { - float ACoef[NCoef+1] = { - 0.03927726802250377400, - 0.07855453604500754700, - 0.03927726802250377400 - }; - - float BCoef[NCoef+1] = { - 1.00000000000000000000, - -1.36640781666419950000, - 0.52352474703279628000 - }; - static float y[2][NCoef+1]; /* output samples */ - static float x[2][NCoef+1]; /* input samples */ - int n; - - /* shift the old samples */ - for(n=NCoef; n>0; n--) { - x[i][n] = x[i][n-1]; - y[i][n] = y[i][n-1]; - } - - /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; - for(n=1; n<=NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - - return y[i][0]; -} - - -#undef NCoef -#define NCoef 2 - -/* fc=3.2kHz */ -static inline float sb_iir(int i, float NewSample) { - float ACoef[NCoef+1] = { - 0.03356837051492005100, - 0.06713674102984010200, - 0.03356837051492005100 - }; - - float BCoef[NCoef+1] = { - 1.00000000000000000000, - -1.41898265221812010000, - 0.55326988968868285000 - }; - -/* float ACoef[NCoef+1] = { - 0.17529642630084405000, - 0.17529642630084405000 - }; - - float BCoef[NCoef+1] = { - 1.00000000000000000000, - -0.64940759319751051000 - };*/ - static float y[2][NCoef+1]; /* output samples */ - static float x[2][NCoef+1]; /* input samples */ - int n; - - /* shift the old samples */ - for(n=NCoef; n>0; n--) { - x[i][n] = x[i][n-1]; - y[i][n] = y[i][n-1]; - } - - /* Calculate the new output */ - x[i][0] = NewSample; - y[i][0] = ACoef[0] * x[i][0]; - for(n=1; n<=NCoef; n++) - y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - - return y[i][0]; -} - - - -#undef NCoef #define NCoef 2 /* fc=150Hz */ @@ -210,7 +32,7 @@ static inline float adgold_highpass_iir(int i, float NewSample) { y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - + return y[i][0]; } @@ -243,7 +65,7 @@ static inline float adgold_lowpass_iir(int i, float NewSample) { y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - + return y[i][0]; } @@ -276,7 +98,7 @@ static inline float adgold_pseudo_stereo_iir(float NewSample) { y[0] = ACoef[0] * x[0]; for(n=1; n<=NCoef; n++) y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; - + return y[0]; } @@ -293,7 +115,7 @@ static inline float dss_iir(float NewSample) { -1.41898265221812010000, 0.55326988968868285000 }; - + static float y[NCoef+1]; /* output samples */ static float x[NCoef+1]; /* input samples */ int n; @@ -342,36 +164,243 @@ static inline float dac_iir(int i, float NewSample) { y[i][0] = ACoef[0] * x[i][0]; for(n=1; n<=NCoef; n++) y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; - + return y[i][0]; } +#undef NCoef +#define NCoef 2 + +/* fc=350Hz */ +static inline double low_iir(int c, int i, double NewSample) { + double ACoef[NCoef+1] = { + 0.00049713569693400649, + 0.00099427139386801299, + 0.00049713569693400649 + }; + + double BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955470669530000, + 0.93726236021404663000 + }; + + static double y[2][2][NCoef+1]; /* output samples */ + static double x[2][2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[c][i][n] = x[c][i][n-1]; + y[c][i][n] = y[c][i][n-1]; + } + + /* Calculate the new output */ + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; + for(n=1; n<=NCoef; n++) + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; + + return y[c][i][0]; +} + +/* fc=350Hz */ +static inline double low_cut_iir(int c, int i, double NewSample) { + double ACoef[NCoef+1] = { + 0.96839970114733542000, + -1.93679940229467080000, + 0.96839970114733542000 + }; + + double BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955471202770000, + 0.93726236021916731000 + }; + + static double y[2][2][NCoef+1]; /* output samples */ + static double x[2][2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[c][i][n] = x[c][i][n-1]; + y[c][i][n] = y[c][i][n-1]; + } + + /* Calculate the new output */ + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; + for(n=1; n<=NCoef; n++) + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; + + return y[c][i][0]; +} + +/* fc=3.5kHz */ +static inline double high_iir(int c, int i, double NewSample) { + double ACoef[NCoef+1] = { + 0.72248704753064896000, + -1.44497409506129790000, + 0.72248704753064896000 + }; + + double BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781670578510000, + 0.52352474706139873000 + }; + static double y[2][2][NCoef+1]; /* output samples */ + static double x[2][2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[c][i][n] = x[c][i][n-1]; + y[c][i][n] = y[c][i][n-1]; + } + + /* Calculate the new output */ + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; + for(n=1; n<=NCoef; n++) + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; + + return y[c][i][0]; +} + +/* fc=3.5kHz */ +static inline double high_cut_iir(int c, int i, double NewSample) { + double ACoef[NCoef+1] = { + 0.03927726802250377400, + 0.07855453604500754700, + 0.03927726802250377400 + }; + + double BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781666419950000, + 0.52352474703279628000 + }; + static double y[2][2][NCoef+1]; /* output samples */ + static double x[2][2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[c][i][n] = x[c][i][n-1]; + y[c][i][n] = y[c][i][n-1]; + } + + /* Calculate the new output */ + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; + for(n=1; n<=NCoef; n++) + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; + + return y[c][i][0]; +} + +/* fc=5.283kHz, gain=-9.477dB, width=0.4845 */ +static inline double deemph_iir(int i, double NewSample) { + double ACoef[NCoef+1] = { + 0.46035077886318842566, + -0.28440821191249848754, + 0.03388877229118691936 + }; + + double BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.05429146278569141337, + 0.26412280202756849290 + }; + static double y[2][NCoef+1]; /* output samples */ + static double x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +#undef NCoef +#define NCoef 2 + +/* fc=3.2kHz */ +static inline double sb_iir(int c, int i, double NewSample) { + double ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + double BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + }; + + static double y[2][2][NCoef+1]; /* output samples */ + static double x[2][2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[c][i][n] = x[c][i][n-1]; + y[c][i][n] = y[c][i][n-1]; + } + + /* Calculate the new output */ + x[c][i][0] = NewSample; + y[c][i][0] = ACoef[0] * x[c][i][0]; + for(n=1; n<=NCoef; n++) + y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; + + return y[c][i][0]; +} + + + +#undef NCoef +#define NCoef 1 #define SB16_NCoef 51 -extern float low_fir_sb16_coef[SB16_NCoef]; +extern double low_fir_sb16_coef[2][SB16_NCoef]; -static inline float low_fir_sb16(int i, float NewSample) +static inline double low_fir_sb16(int c, int i, double NewSample) { - static float x[2][SB16_NCoef+1]; //input samples - static int pos = 0; - float out = 0.0; + static double x[2][2][SB16_NCoef+1]; //input samples + static int pos[2] = { 0, 0 }; + double out = 0.0; int n; /* Calculate the new output */ - x[i][pos] = NewSample; + x[c][i][pos[c]] = NewSample; - for (n = 0; n < ((SB16_NCoef+1)-pos) && n < SB16_NCoef; n++) - out += low_fir_sb16_coef[n] * x[i][n+pos]; + for (n = 0; n < ((SB16_NCoef+1)-pos[c]) && n < SB16_NCoef; n++) + out += low_fir_sb16_coef[c][n] * x[c][i][n+pos[c]]; for (; n < SB16_NCoef; n++) - out += low_fir_sb16_coef[n] * x[i][(n+pos) - (SB16_NCoef+1)]; + out += low_fir_sb16_coef[c][n] * x[c][i][(n+pos[c]) - (SB16_NCoef+1)]; if (i == 1) { - pos++; - if (pos > SB16_NCoef) - pos = 0; + pos[c]++; + if (pos[c] > SB16_NCoef) + pos[c] = 0; } - + return out; } + +#endif /*EMU_FILTERS_H*/ diff --git a/src/include/86box/sst_flash.h b/src/include/86box/flash.h similarity index 51% rename from src/include/86box/sst_flash.h rename to src/include/86box/flash.h index f473d4d33..531cc7037 100644 --- a/src/include/86box/sst_flash.h +++ b/src/include/86box/flash.h @@ -1,20 +1,33 @@ -/* - * 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 an SST flash chip. - * - * - * - * Author: Melissa Goad, - * Copyright 2020 Melissa Goad. - */ - -extern const device_t sst_flash_29ee010_device; -extern const device_t sst_flash_29ee020_device; -extern const device_t sst_flash_39sf010_device; -extern const device_t sst_flash_39sf020_device; +/* + * 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. + * + * Handling of the emulated flash devices. + * + * + * + * Author: Miran Grca, + * Copyright 2020 Miran Grca. + */ + +#ifndef EMU_FLASH_H +# define EMU_FLASH_H + +extern const device_t catalyst_flash_device; + +extern const device_t intel_flash_bxt_ami_device; +extern const device_t intel_flash_bxt_device; +extern const device_t intel_flash_bxb_device; + +extern const device_t sst_flash_29ee010_device; +extern const device_t sst_flash_29ee020_device; +extern const device_t winbond_flash_w29c020_device; +extern const device_t sst_flash_39sf010_device; +extern const device_t sst_flash_39sf020_device; +extern const device_t sst_flash_39sf040_device; + +#endif /*EMU_FLASH_H*/ diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index a91a26232..65fdee996 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -1,40 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 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 VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the generic game port handlers. * - * NOTE: This module needs a good cleanup someday. - * * * * Authors: Miran Grca, * Sarah Walker, + * RichardG, * * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2017 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2021 RichardG. */ #ifndef EMU_GAMEPORT_H # define EMU_GAMEPORT_H @@ -48,10 +30,10 @@ #define SLIDER 0x20000000 #define AXIS_NOT_PRESENT -99999 -#define JOYSTICK_TYPE_NONE 8 #define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) +#define GAMEPORT_SIO 0x1000000 typedef struct { char name[260]; @@ -101,6 +83,7 @@ typedef struct { typedef struct { const char *name; + const char *internal_name; void *(*init)(void); void (*close)(void *p); @@ -126,8 +109,23 @@ extern "C" { #ifdef EMU_DEVICE_H extern const device_t gameport_device; extern const device_t gameport_201_device; -#endif +extern const device_t gameport_203_device; +extern const device_t gameport_205_device; +extern const device_t gameport_207_device; +extern const device_t gameport_208_device; +extern const device_t gameport_209_device; +extern const device_t gameport_20b_device; +extern const device_t gameport_20d_device; +extern const device_t gameport_20f_device; +extern const device_t gameport_tm_acm_device; +extern const device_t gameport_pnp_device; +extern const device_t gameport_pnp_6io_device; +extern const device_t gameport_sio_device; +extern const device_t gameport_sio_1io_device; +extern const device_t *standalone_gameport_type; +#endif +extern int gameport_instance_id; extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; extern joystick_t joystick_state[MAX_JOYSTICKS]; extern int joysticks_present; @@ -140,6 +138,8 @@ extern void joystick_close(void); extern void joystick_process(void); extern char *joystick_get_name(int js); +extern char *joystick_get_internal_name(int js); +extern int joystick_get_from_internal_name(char *s); extern int joystick_get_max_joysticks(int js); extern int joystick_get_axis_count(int js); extern int joystick_get_button_count(int js); @@ -149,6 +149,8 @@ extern char *joystick_get_button_name(int js, int id); extern char *joystick_get_pov_name(int js, int id); extern void gameport_update_joystick_type(void); +extern void gameport_remap(void *priv, uint16_t address); +extern void *gameport_add(const device_t *gameport_type); #ifdef __cplusplus } diff --git a/src/include/86box/gdbstub.h b/src/include/86box/gdbstub.h new file mode 100644 index 000000000..4b2f8630a --- /dev/null +++ b/src/include/86box/gdbstub.h @@ -0,0 +1,79 @@ +/* + * 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. + * + * Definitions for the GDB stub server. + * + * + * + * Authors: RichardG, + * + * Copyright 2022 RichardG. + */ +#ifndef EMU_GDBSTUB_H +#define EMU_GDBSTUB_H +#include +#include <86box/mem.h> + +#define GDBSTUB_MEM_READ 0 +#define GDBSTUB_MEM_WRITE 16 +#define GDBSTUB_MEM_AWATCH 32 + +enum { + GDBSTUB_EXEC = 0, + GDBSTUB_SSTEP, + GDBSTUB_BREAK, + GDBSTUB_BREAK_SW, + GDBSTUB_BREAK_HW, + GDBSTUB_BREAK_RWATCH, + GDBSTUB_BREAK_WWATCH, + GDBSTUB_BREAK_AWATCH +}; + +#ifdef USE_GDBSTUB + +# define GDBSTUB_MEM_ACCESS(addr, access, width) \ + uint32_t gdbstub_page = addr >> MEM_GRANULARITY_BITS; \ + if (gdbstub_watch_pages[gdbstub_page >> 6] & (1 << (gdbstub_page & 63))) { \ + uint32_t gdbstub_addrs[width]; \ + for (int gdbstub_i = 0; gdbstub_i < width; gdbstub_i++) \ + gdbstub_addrs[gdbstub_i] = addr + gdbstub_i; \ + gdbstub_mem_access(gdbstub_addrs, access | width); \ + } + +# define GDBSTUB_MEM_ACCESS_FAST(addrs, access, width) \ + uint32_t gdbstub_page = addr >> MEM_GRANULARITY_BITS; \ + if (gdbstub_watch_pages[gdbstub_page >> 6] & (1 << (gdbstub_page & 63))) \ + gdbstub_mem_access(addrs, access | width); + +extern int gdbstub_step, gdbstub_next_asap; +extern uint64_t gdbstub_watch_pages[(((uint32_t) -1) >> (MEM_GRANULARITY_BITS + 6)) + 1]; + +extern void gdbstub_cpu_init(); +extern int gdbstub_instruction(); +extern int gdbstub_int3(); +extern void gdbstub_mem_access(uint32_t *addrs, int access); +extern void gdbstub_init(); +extern void gdbstub_close(); + +#else + +# define GDBSTUB_MEM_ACCESS(addr, access, width) +# define GDBSTUB_MEM_ACCESS_FAST(addrs, access, width) + +# define gdbstub_step 0 +# define gdbstub_next_asap 0 + +# define gdbstub_cpu_init() +# define gdbstub_instruction() 0 +# define gdbstub_int3() 0 +# define gdbstub_init() +# define gdbstub_close() + +#endif + +#endif diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 10bf2885a..3f8426dea 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -13,8 +13,8 @@ * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #ifndef EMU_HDC_H # define EMU_HDC_H @@ -24,6 +24,7 @@ #define ESDI_NUM 2 /* 2 drives per controller supported */ #define XTA_NUM 2 /* 2 drives per controller supported */ #define IDE_NUM 10 /* 8 drives per AT IDE + 2 for XT IDE */ +#define ATAPI_NUM 8 /* 8 drives per AT IDE */ #define SCSI_NUM 16 /* theoretically the controller can have at * least 7 devices, with each device being * able to support 8 units, but hey... */ @@ -38,6 +39,9 @@ extern const device_t st506_xt_st11_r_device; /* st506_xt_st11_m */ extern const device_t st506_xt_wd1002a_wx1_device; /* st506_xt_wd1002a_wx1 */ extern const device_t st506_xt_wd1002a_27x_device; /* st506_xt_wd1002a_27x */ extern const device_t st506_at_wd1003_device; /* st506_at_wd1003 */ +extern const device_t st506_xt_wd1004a_wx1_device; /* st506_xt_wd1004a_wx1 */ +extern const device_t st506_xt_wd1004_27x_device; /* st506_xt_wd1004_27x */ +extern const device_t st506_xt_wd1004a_27x_device; /* st506_xt_wd1004a_27x */ extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */ @@ -50,14 +54,28 @@ extern const device_t ide_vlb_2ch_device; /* vlb_ide_2ch */ extern const device_t ide_pci_device; /* pci_ide */ extern const device_t ide_pci_2ch_device; /* pci_ide_2ch */ +extern const device_t ide_cmd640_vlb_device; /* CMD PCI-640B VLB */ +extern const device_t ide_cmd640_vlb_178_device; /* CMD PCI-640B VLB (Port 178h) */ +extern const device_t ide_cmd640_pci_device; /* CMD PCI-640B PCI */ +extern const device_t ide_cmd640_pci_legacy_only_device; /* CMD PCI-640B PCI (Legacy Mode Only) */ +extern const device_t ide_cmd640_pci_single_channel_device; /* CMD PCI-640B PCI (Only primary channel) */ +extern const device_t ide_cmd646_device; /* CMD PCI-646 */ +extern const device_t ide_cmd646_legacy_only_device; /* CMD PCI-646 (Legacy Mode Only) */ +extern const device_t ide_cmd646_single_channel_device; /* CMD PCI-646 (Only primary channel) */ + +extern const device_t ide_opti611_vlb_device; /* OPTi 82c611/611A VLB */ + extern const device_t ide_ter_device; +extern const device_t ide_ter_pnp_device; extern const device_t ide_qua_device; +extern const device_t ide_qua_pnp_device; extern const device_t xta_wdxt150_device; /* xta_wdxt150 */ extern const device_t xta_hd20_device; /* EuroPC internal */ extern const device_t xtide_device; /* xtide_xt */ extern const device_t xtide_at_device; /* xtide_at */ +extern const device_t xtide_at_386_device; /* xtide_at_386 */ extern const device_t xtide_acculogic_device; /* xtide_ps2 */ extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ @@ -65,9 +83,7 @@ extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ extern void hdc_init(void); extern void hdc_reset(void); -extern char *hdc_get_name(int hdc); extern char *hdc_get_internal_name(int hdc); -extern int hdc_get_id(char *s); extern int hdc_get_from_internal_name(char *s); extern int hdc_has_config(int hdc); extern const device_t *hdc_get_device(int hdc); diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 48b7c8939..9e2539359 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -19,6 +19,18 @@ #ifndef EMU_IDE_H # define EMU_IDE_H +#define HDC_PRIMARY_BASE 0x01F0 +#define HDC_PRIMARY_SIDE 0x03F6 +#define HDC_PRIMARY_IRQ 14 +#define HDC_SECONDARY_BASE 0x0170 +#define HDC_SECONDARY_SIDE 0x0376 +#define HDC_SECONDARY_IRQ 15 +#define HDC_TERTIARY_BASE 0x0168 +#define HDC_TERTIARY_SIDE 0x036E +#define HDC_TERTIARY_IRQ 10 +#define HDC_QUATERNARY_BASE 0x01E8 +#define HDC_QUATERNARY_SIDE 0x03EE +#define HDC_QUATERNARY_IRQ 11 enum { @@ -37,7 +49,7 @@ typedef struct ide_s { blocksize, blockcount, hdd_num, channel, pos, sector_pos, - lba, skip512, + lba, reset, mdma_mode, do_initial_read; uint32_t secount, sector, @@ -55,6 +67,7 @@ typedef struct ide_s { /* Stuff mostly used by ATAPI */ scsi_common_t *sc; int interrupt_drq; + double pending_delay; int (*get_max)(int ide_has_dma, int type); int (*get_timings)(int ide_has_dma, int type); @@ -130,12 +143,18 @@ extern void win_cdrom_reload(uint8_t id); extern void ide_set_base(int board, uint16_t port); extern void ide_set_side(int board, uint16_t port); +extern void ide_set_handlers(uint8_t board); +extern void ide_remove_handlers(uint8_t board); + extern void ide_pri_enable(void); extern void ide_pri_disable(void); extern void ide_sec_enable(void); extern void ide_sec_disable(void); extern void ide_board_set_force_ata3(int board, int force_ata3); +#ifdef EMU_ISAPNP_H +extern void ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); +#endif extern double ide_atapi_get_period(uint8_t channel); #ifdef SCSI_DEVICE_H @@ -150,5 +169,8 @@ extern int (*ide_bus_master_dma)(int channel, uint8_t *data, int transfer_length extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; +extern uint8_t ide_read_ali_75(void); +extern uint8_t ide_read_ali_76(void); + #endif /*EMU_IDE_H*/ diff --git a/src/include/86box/hdc_ide_sff8038i.h b/src/include/86box/hdc_ide_sff8038i.h index 43288aa99..1c058772c 100644 --- a/src/include/86box/hdc_ide_sff8038i.h +++ b/src/include/86box/hdc_ide_sff8038i.h @@ -16,17 +16,22 @@ * Copyright 2016-2020 Miran Grca. */ +#ifndef EMU_HDC_IDE_SFF8038I_H +# define EMU_HDC_IDE_SFF8038I_H + typedef struct { uint8_t command, status, - ptr0, enabled; - uint16_t base, pad; + ptr0, enabled, + dma_mode, pad, + pad0, pad1; + uint16_t base, pad2; uint32_t ptr, ptr_cur, addr; int count, eot, slot, - irq_mode[2], irq_pin, - irq_line; + irq_mode[2], irq_level[2], + irq_pin, irq_line; } sff8038i_t; @@ -39,6 +44,11 @@ extern int sff_bus_master_dma_write(int channel, uint8_t *data, int transfer_len extern void sff_bus_master_set_irq(int channel, void *priv); +extern int sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv); + +extern void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); +extern uint8_t sff_bus_master_read(uint16_t port, void *priv); + extern void sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base); extern void sff_set_slot(sff8038i_t *dev, int slot); @@ -47,3 +57,7 @@ extern void sff_set_irq_line(sff8038i_t *dev, int irq_line); extern void sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode); extern void sff_set_irq_pin(sff8038i_t *dev, int irq_pin); + +extern void sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level); + +#endif /*EMU_HDC_IDE_SFF8038I_H*/ diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index 08f3a4c77..a1c552e1e 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -19,7 +19,7 @@ # define EMU_HDD_H -#define HDD_NUM 30 /* total of 30 images supported */ +#define HDD_NUM 88 /* total of 88 images supported */ /* Hard Disk bus types. */ @@ -66,20 +66,81 @@ enum { HDD_BUS_XTA, HDD_BUS_ESDI, HDD_BUS_IDE, + HDD_BUS_ATAPI, HDD_BUS_SCSI, HDD_BUS_USB }; #endif +enum { + HDD_OP_SEEK = 0, + HDD_OP_READ, + HDD_OP_WRITE +}; + +#define HDD_MAX_ZONES 16 +#define HDD_MAX_CACHE_SEG 16 + +typedef struct { + const char *name; + const char *internal_name; + uint32_t zones; + uint32_t avg_spt; + uint32_t heads; + uint32_t rpm; + uint32_t rcache_num_seg; + uint32_t rcache_seg_size; + uint32_t max_multiple; + double full_stroke_ms; + double track_seek_ms; +} hdd_preset_t; + +typedef struct { + uint32_t id; + uint32_t lba_addr; + uint32_t ra_addr; + uint32_t host_addr; + uint8_t lru; + uint8_t valid; +} hdd_cache_seg_t; + +typedef struct { + // Read cache + hdd_cache_seg_t segments[HDD_MAX_CACHE_SEG]; + uint32_t num_segments; + uint32_t segment_size; + uint32_t ra_segment; + uint8_t ra_ongoing; + uint64_t ra_start_time; + + // Write cache + uint32_t write_addr; + uint32_t write_pending; + uint32_t write_size; + uint64_t write_start_time; +} hdd_cache_t; + +typedef struct { + uint32_t cylinders; + uint32_t sectors_per_track; + double sector_time_usec; + uint32_t start_sector; + uint32_t end_sector; + uint32_t start_track; +} hdd_zone_t; /* Define the virtual Hard Disk. */ typedef struct { uint8_t id; - uint8_t mfm_channel; /* Should rename and/or unionize */ - uint8_t esdi_channel; - uint8_t xta_channel; - uint8_t ide_channel; - uint8_t scsi_id; + union { + uint8_t channel; /* Needed for Settings to reduce the number of if's */ + + uint8_t mfm_channel; /* Should rename and/or unionize */ + uint8_t esdi_channel; + uint8_t xta_channel; + uint8_t ide_channel; + uint8_t scsi_id; + }; uint8_t bus, res; /* Reserved for bus mode */ uint8_t wp; /* Disk has been mounted READ-ONLY */ @@ -87,7 +148,7 @@ typedef struct { void *priv; - wchar_t fn[1024], /* Name of current image file */ + char fn[1024], /* Name of current image file */ prev_fn[1024]; /* Name of previous image file */ uint32_t res0, pad1, @@ -95,38 +156,31 @@ typedef struct { spt, hpc, /* Physical geometry parameters */ tracks; + + hdd_zone_t zones[HDD_MAX_ZONES]; + uint32_t num_zones; + hdd_cache_t cache; + uint32_t phy_cyl; + uint32_t phy_heads; + uint32_t rpm; + uint8_t max_multiple_block; + + uint32_t cur_cylinder; + uint32_t cur_track; + uint32_t cur_addr; + + uint32_t speed_preset; + + double avg_rotation_lat_usec; + double full_stroke_usec; + double head_switch_usec; + double cyl_switch_usec; } hard_disk_t; extern hard_disk_t hdd[HDD_NUM]; extern unsigned int hdd_table[128][3]; - -typedef struct vhd_footer_t -{ - uint8_t cookie[8]; - uint32_t features; - uint32_t version; - uint64_t offset; - uint32_t timestamp; - uint8_t creator[4]; - uint32_t creator_vers; - uint8_t creator_host_os[4]; - uint64_t orig_size; - uint64_t curr_size; - struct { - uint16_t cyl; - uint8_t heads; - uint8_t spt; - } geom; - uint32_t type; - uint32_t checksum; - uint8_t uuid[16]; - uint8_t saved_state; - uint8_t reserved[427]; -} vhd_footer_t; - - extern int hdd_init(void); extern int hdd_string_to_bus(char *str, int cdrom); extern char *hdd_bus_to_string(int bus, int cdrom); @@ -148,14 +202,17 @@ extern void hdd_image_unload(uint8_t id, int fn_preserve); extern void hdd_image_close(uint8_t id); extern void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size); -extern void vhd_footer_from_bytes(vhd_footer_t *vhd, uint8_t *bytes); -extern void vhd_footer_to_bytes(uint8_t *bytes, vhd_footer_t *vhd); -extern void new_vhd_footer(vhd_footer_t **vhd); -extern void generate_vhd_checksum(vhd_footer_t *vhd); - -extern int image_is_hdi(const wchar_t *s); -extern int image_is_hdx(const wchar_t *s, int check_signature); -extern int image_is_vhd(const wchar_t *s, int check_signature); +extern int image_is_hdi(const char *s); +extern int image_is_hdx(const char *s, int check_signature); +extern int image_is_vhd(const char *s, int check_signature); +extern double hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len); +extern double hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len); +extern double hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time); +int hdd_preset_get_num(); +char * hdd_preset_getname(int preset); +extern char *hdd_preset_get_internal_name(int preset); +extern int hdd_preset_get_from_internal_name(char *s); +extern void hdd_preset_apply(int hdd_id); #endif /*EMU_HDD_H*/ diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index 0cae77dbb..ef5621da6 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -16,45 +16,63 @@ */ #ifndef EMU_HWM_H # define EMU_HWM_H +# include #define RESISTOR_DIVIDER(v, r1, r2) (((v) * (r2)) / ((r1) + (r2))) -typedef struct _hwm_values_ { +typedef struct { uint16_t fans[4]; uint8_t temperatures[4]; - uint16_t voltages[8]; + uint16_t voltages[13]; } hwm_values_t; typedef struct { - uint32_t local; + uint32_t local; hwm_values_t *values; + void *as99127f; - uint8_t regs[8]; - uint8_t addr_register; - uint8_t temp_idx; - uint8_t smbus_addr; - - uint8_t as99127f_smbus_addr; + uint8_t regs[8]; + uint8_t addr_register; + uint8_t i2c_addr: 7, i2c_state: 2; + uint8_t i2c_enabled: 1; } lm75_t; -extern void hwm_set_values(hwm_values_t new_values); -extern hwm_values_t* hwm_get_values(); +/* hwm.c */ +extern uint16_t hwm_get_vcore(); -extern void lm75_remap(lm75_t *dev); +/* hwm_lm75.c */ +extern void lm75_remap(lm75_t *dev, uint8_t addr); extern uint8_t lm75_read(lm75_t *dev, uint8_t reg); extern uint8_t lm75_write(lm75_t *dev, uint8_t reg, uint8_t val); +/* hwm_lm78.c */ +extern uint8_t lm78_as99127f_read(void *priv, uint8_t reg); +extern uint8_t lm78_as99127f_write(void *priv, uint8_t reg, uint8_t val); + +/* hwm_vt82c686.c */ +extern void vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv); + + +/* Refer to specific hardware monitor implementations for the meaning of hwm_values. */ +extern hwm_values_t hwm_values; extern const device_t lm75_1_4a_device; extern const device_t lm75_w83781d_device; extern const device_t lm78_device; extern const device_t w83781d_device; +extern const device_t w83781d_p5a_device; extern const device_t as99127f_device; extern const device_t as99127f_rev2_device; +extern const device_t w83782d_device; + +extern const device_t gl518sm_2c_device; +extern const device_t gl518sm_2d_device; + +extern const device_t via_vt82c686_hwm_device; #endif /*EMU_HWM_H*/ diff --git a/src/include/86box/i2c.h b/src/include/86box/i2c.h new file mode 100644 index 000000000..b47754d64 --- /dev/null +++ b/src/include/86box/i2c.h @@ -0,0 +1,70 @@ +/* + * 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. + * + * Definitions for the I2C handler. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#ifndef EMU_I2C_H +# define EMU_I2C_H + + +/* i2c.c */ +extern void *i2c_smbus; + + +/* i2c.c */ +extern void *i2c_addbus(char *name); +extern void i2c_removebus(void *bus_handle); +extern char *i2c_getbusname(void *bus_handle); + +extern void i2c_sethandler(void *bus_handle, uint8_t base, int size, + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), + void *priv); + +extern void i2c_removehandler(void *bus_handle, uint8_t base, int size, + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), + void *priv); + +extern void i2c_handler(int set, void *bus_handle, uint8_t base, int size, + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), + void *priv); + +extern uint8_t i2c_start(void *bus_handle, uint8_t addr, uint8_t read); +extern uint8_t i2c_read(void *bus_handle, uint8_t addr); +extern uint8_t i2c_write(void *bus_handle, uint8_t addr, uint8_t data); +extern void i2c_stop(void *bus_handle, uint8_t addr); + +/* i2c_eeprom.c */ +extern uint8_t log2i(uint32_t i); +extern void *i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable); +extern void i2c_eeprom_close(void *dev_handle); + +/* i2c_gpio.c */ +extern void *i2c_gpio_init(char *bus_name); +extern void i2c_gpio_close(void *dev_handle); +extern void i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda); +extern uint8_t i2c_gpio_get_scl(void *dev_handle); +extern uint8_t i2c_gpio_get_sda(void *dev_handle); +extern void *i2c_gpio_get_bus(); + + +#endif /*EMU_I2C_H*/ diff --git a/src/include/86box/i82335.h b/src/include/86box/i82335.h index 7cb4c4ef3..705f1b085 100644 --- a/src/include/86box/i82335.h +++ b/src/include/86box/i82335.h @@ -1 +1,6 @@ +#ifndef EMU_I82335_H +# define EMU_I82335_H + extern void i82335_init(void); + +#endif /*EMU_I82335_H*/ diff --git a/src/include/86box/ibm_5161.h b/src/include/86box/ibm_5161.h index 69f9d23a8..858c18786 100644 --- a/src/include/86box/ibm_5161.h +++ b/src/include/86box/ibm_5161.h @@ -12,4 +12,9 @@ * Copyright 2016-2018 Miran Grca. */ +#ifndef EMU_IBM_5161_H +# define EMU_IBM_5161_H + extern const device_t ibm_5161_device; + +#endif /*EMU_IBM_5151_H*/ diff --git a/src/include/86box/io.h b/src/include/86box/io.h index 7ec808abf..c483819ce 100644 --- a/src/include/86box/io.h +++ b/src/include/86box/io.h @@ -23,6 +23,33 @@ extern void io_init(void); +extern void io_sethandler_common(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step); + +extern void io_removehandler_common(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step); + +extern void io_handler_common(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step); + extern void io_sethandler(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), @@ -50,7 +77,6 @@ extern void io_handler(int set, uint16_t base, int size, void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv); -#ifdef PC98 extern void io_sethandler_interleaved(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), @@ -68,7 +94,15 @@ extern void io_removehandler_interleaved(uint16_t base, int size, void (*outw)(uint16_t addr, uint16_t val, void *priv), void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv); -#endif + +extern void io_handler_interleaved(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); extern uint8_t inb(uint16_t port); extern void outb(uint16_t port, uint8_t val); @@ -77,5 +111,10 @@ extern void outw(uint16_t port, uint16_t val); extern uint32_t inl(uint16_t port); extern void outl(uint16_t port, uint32_t val); +extern void *io_trap_add(void (*func)(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv), + void *priv); +extern void io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size); +extern void io_trap_remove(void *handle); + #endif /*EMU_IO_H*/ diff --git a/src/include/86box/isamem.h b/src/include/86box/isamem.h index 90d7666ec..b02c27374 100644 --- a/src/include/86box/isamem.h +++ b/src/include/86box/isamem.h @@ -44,8 +44,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ISAMEM_H -# define ISAMEM_H + +#ifndef EMU_ISAMEM_H +# define EMU_ISAMEM_H #define ISAMEM_MAX 4 /* max #cards in system */ @@ -74,4 +75,4 @@ extern const device_t *isamem_get_device(int t); #endif -#endif /*ISAMEM_H*/ +#endif /*EMU_ISAMEM_H*/ diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h new file mode 100644 index 000000000..3b2aa1859 --- /dev/null +++ b/src/include/86box/isapnp.h @@ -0,0 +1,71 @@ +/* + * 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. + * + * Definitions for ISA Plug and Play. + * + * + * + * Author: RichardG, + * + * Copyright 2021 RichardG. + */ + +#ifndef EMU_ISAPNP_H +# define EMU_ISAPNP_H +# include + + +#define ISAPNP_MEM_DISABLED 0 +#define ISAPNP_IO_DISABLED 0 +#define ISAPNP_IRQ_DISABLED 0 +#define ISAPNP_DMA_DISABLED 4 + + +enum { + ISAPNP_CARD_DISABLE = 0, + ISAPNP_CARD_ENABLE = 1, + ISAPNP_CARD_FORCE_CONFIG, /* cheat code for UMC UM8669F */ + ISAPNP_CARD_NO_KEY /* cheat code for Crystal CS423x */ +}; + + +typedef struct { + uint8_t activate; + struct { + uint32_t base: 24, size: 24; + } mem[4]; + struct { + uint32_t base, size; + } mem32[4]; + struct { + uint16_t base; + } io[8]; + struct { + uint8_t irq: 4, level: 1, type: 1; + } irq[2]; + struct { + uint8_t dma: 3; + } dma[2]; +} isapnp_device_config_t; + + +void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, + void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv), + void (*csn_changed)(uint8_t csn, void *priv), + uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), + void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), + void *priv); +void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); +void isapnp_enable_card(void *priv, uint8_t enable); +void isapnp_set_csn(void *priv, uint8_t csn); +void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); +void isapnp_reset_card(void *priv); +void isapnp_reset_device(void *priv, uint8_t ld); + + +#endif /*EMU_ISAPNP_H*/ diff --git a/src/include/86box/isartc.h b/src/include/86box/isartc.h index 0d5147251..391b9f642 100644 --- a/src/include/86box/isartc.h +++ b/src/include/86box/isartc.h @@ -44,8 +44,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ISARTC_H -# define ISARTC_H + +#ifndef EMU_ISARTC_H +# define EMU_ISARTC_H #ifdef __cplusplus @@ -58,8 +59,7 @@ extern "C" { /* Functions. */ extern void isartc_reset(void); -extern char *isartc_get_name(int t); -extern char *isartc_get_internal_name(int t); +extern char *isartc_get_internal_name(int t); extern int isartc_get_from_internal_name(char *s); extern const device_t *isartc_get_device(int t); @@ -68,4 +68,4 @@ extern const device_t *isartc_get_device(int t); #endif -#endif /*ISARTC_H*/ +#endif /*EMU_ISARTC_H*/ diff --git a/src/include/86box/joystick_ch_flightstick_pro.h b/src/include/86box/joystick_ch_flightstick_pro.h index 1358f9d69..bd2984438 100644 --- a/src/include/86box/joystick_ch_flightstick_pro.h +++ b/src/include/86box/joystick_ch_flightstick_pro.h @@ -35,4 +35,9 @@ * USA. */ +#ifndef EMU_JOYSTICK_CH_FLIGHTSTICK_PRO_H +# define EMU_JOYSTICK_CH_FLIGHTSTICK_PRO_H + extern const joystick_if_t joystick_ch_flightstick_pro; + +#endif /*EMU_JOYSTICK_CH_FLIGHTSTICK_PRO_H*/ diff --git a/src/include/86box/joystick_standard.h b/src/include/86box/joystick_standard.h index eb35c384b..c60828afb 100644 --- a/src/include/86box/joystick_standard.h +++ b/src/include/86box/joystick_standard.h @@ -35,8 +35,15 @@ * USA. */ -extern const joystick_if_t joystick_standard; -extern const joystick_if_t joystick_standard_4button; +#ifndef EMU_JOYSTICK_STANDARD_H +# define EMU_JOYSTICK_STANDARD_H + +extern const joystick_if_t joystick_2axis_2button; +extern const joystick_if_t joystick_2axis_4button; +extern const joystick_if_t joystick_3axis_2button; +extern const joystick_if_t joystick_3axis_4button; extern const joystick_if_t joystick_4axis_4button; -extern const joystick_if_t joystick_standard_6button; -extern const joystick_if_t joystick_standard_8button; +extern const joystick_if_t joystick_2axis_6button; +extern const joystick_if_t joystick_2axis_8button; + +#endif /*EMU_JOYSTICK_STANDARD_H*/ diff --git a/src/include/86box/joystick_sw_pad.h b/src/include/86box/joystick_sw_pad.h index 2f62aab19..daa671028 100644 --- a/src/include/86box/joystick_sw_pad.h +++ b/src/include/86box/joystick_sw_pad.h @@ -35,4 +35,9 @@ * USA. */ +#ifndef EMU_JOYSTICK_SW_PAD_H +# define EMU_JOYSTICK_SW_PAD_H + extern const joystick_if_t joystick_sw_pad; + +#endif /*EMU_JOYSTICK_SW_PAD_H*/ diff --git a/src/include/86box/joystick_tm_fcs.h b/src/include/86box/joystick_tm_fcs.h index 60067d88a..78b85e9a0 100644 --- a/src/include/86box/joystick_tm_fcs.h +++ b/src/include/86box/joystick_tm_fcs.h @@ -35,4 +35,9 @@ * USA. */ +#ifndef EMU_JOYSTICK_TM_FCS_H +# define EMU_JOYSTICK_TM_FCS_H + extern const joystick_if_t joystick_tm_fcs; + +#endif /*EMU_JOYSTICK_TM_FCS_H*/ diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index e09ca2844..29ea8e5fb 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -18,6 +18,7 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ + #ifndef EMU_KEYBOARD_H # define EMU_KEYBOARD_H @@ -40,6 +41,94 @@ typedef struct { #define RSHIFT_OFF 0x105 +/* KBC #define's */ +#define KBC_UNKNOWN 0x0000 /* As yet unknown keyboard */ + +/* IBM-style controllers */ +#define KBC_IBM_PC_XT 0x0000 /* IBM PC/XT */ +#define KBC_IBM_PCJR 0x0001 /* IBM PCjr */ +#define KBC_IBM_TYPE_1 0x0002 /* IBM AT / PS/2 Type 1 */ +#define KBC_IBM_TYPE_2 0x0003 /* IBM PS/2 Type 2 */ +#define KBC_AMI_ACCESS_METHODS 0x0004 /* Access Methods AMI */ +#define KBC_JU_JET 0x0005 /* Ju-Jet */ +/* OEM proprietary */ +#define KBC_TANDY 0x0011 /* Tandy 1000/1000HX */ +#define KBC_TANDY_SL2 0x0012 /* Tandy 1000SL2 */ +#define KBC_AMSTRAD 0x0013 /* Amstrad */ +#define KBC_OLIVETTI_XT 0x0014 /* Olivetti XT */ +#define KBC_OLIVETTI 0x0015 /* Olivetti AT */ +#define KBC_TOSHIBA 0x0016 /* Toshiba AT */ +#define KBC_COMPAQ 0x0017 /* Compaq */ +#define KBC_NCR 0x0018 /* NCR */ +#define KBC_QUADTEL 0x0019 /* Quadtel */ +#define KBC_SIEMENS 0x001A /* Siemens */ +/* Phoenix MultiKey/42 */ +#define PHOENIX_MK42_105 0x0521 /* Phoenix MultiKey/42 1.05 */ +#define PHOENIX_MK42_129 0x2921 /* Phoenix MultiKey/42 1.29 */ +#define PHOENIX_MK42_138 0x3821 /* Phoenix MultiKey/42 1.38 */ +#define PHOENIX_MK42_140 0x3821 /* Phoenix MultiKey/42 1.40 */ +#define PHOENIX_MKC42_214 0x1422 /* Phoenix MultiKey/C42 2.14 */ +#define PHOENIX_MK42I_416 0x1624 /* Phoenix MultiKey/42i 4.16 */ +#define PHOENIX_MK42I_419 0x1924 /* Phoenix MultiKey/42i 4.19 */ +/* AMI 0x3x */ +#define KBC_ACER_V30 0x0030 /* Acer (0xA1 returns nothing, 0xAF returns 0x00) */ +#define KBC_AMI_MEGAKEY_SUPER_IO 0x0035 /* AMI '5' MegaKey 1994 NSC (and SM(S)C?) */ +#define KBC_AMI_8 0x0038 /* AMI '8' */ +/* AMI 0x4x */ +#define KBC_AMI_B 0x0042 /* AMI 'B' */ +#define KBC_AMI_D 0x0044 /* AMI 'D' */ +#define KBC_AMI_E 0x0045 /* AMI 'E' */ +#define KBC_AMIKEY 0x0046 /* AMI 'F'/AMIKEY */ +#define KBC_AMIKEY_2 0x0048 /* AMI 'H'/AMIEY-2 */ +#define KBC_MR 0x004D /* MR 'M' - Temporary classification until we get a dump */ +/* AMI 0x5x */ +#define KBC_AMI_MEGAKEY_1993 0x0050 /* AMI 'P' MegaKey 1993 */ +#define KBC_AMI_MEGAKEY_1994 0x0052 /* AMI 'R' MegaKey 1994 - 0xA0 returns 1993 copyright */ +#define KBC_AMI_TRIGEM 0x005A /* TriGem AMI 'Z' (1990 AMI copyright) */ +/* AMI 0x6x */ +#define KBC_TANDON 0x0061 /* Tandon 'a' - Temporary classification until we get a dump */ +/* Holtek */ +#define KBC_HT_REGIONAL_6542 0x1046 /* Holtek 'F' (Regional 6542) */ +#define KBC_HT_HT6542B_BESTKEY 0x1048 /* Holtek 'H' (Holtek HT6542B, BestKey) */ +/* AMI 0x0x clone without command 0xA0 */ +#define KBC_UNK_00 0x2000 /* Unknown 0x00 */ +#define KBC_UNK_01 0x2001 /* Unknown 0x01 */ +/* AMI 0x3x clone without command 0xA0 */ +#define KBC_UNK_7 0x2037 /* Unknown '7' - Temporary classification until we get a dump */ +#define KBC_UNK_9 0x2037 /* Unknown '9' - Temporary classification until we get a dump */ +#define KBC_JETKEY_NO_VER 0x2038 /* No-version JetKey '8' */ +/* AMI 0x4x clone without command 0xA0 */ +#define KBC_UNK_A 0x2041 /* Unknown 'A' - Temporary classification until we get a dump */ +#define KBC_JETKEY_5_W83C42 0x2046 /* JetKey 5.0 'F' and Winbond W83C42 */ +#define KBC_UNK_G 0x2047 /* Unknown 'G' - Temporary classification until we get a dump */ +#define KBC_MB_300E_SIS 0x2048 /* MB-300E Non-VIA 'H' and SiS 5582/559x */ +#define KBC_UNK_L 0x204C /* Unknown 'L' - Temporary classification until we get a dump */ +/* AMI 0x0x clone with command 0xA0 (Get Copyright String) only returning 0x00 */ +#define KBC_VPC_2007 0x3000 /* Microsoft Virtual PC 2007 - everything returns 0x00 */ +/* AMI 0x4x clone with command 0xA0 (Get Copyright String) only returning 0x00 */ +#define KBC_ALI_M148X 0x3045 /* ALi M148x 'E'/'U' (0xA1 actually returns 'F' but BIOS shows 'E' or 'U') */ +#define KBC_LANCE_UTRON 0x3046 /* Lance LT38C41 'F', Utron */ +/* AMI 0x5x clone with command 0xA0 (Get Copyright String) only returning 0x00 */ +#define KBC_SARC_6042 0x3055 /* SARC 6042 'U' */ +/* Award and clones */ +#define KBC_AWARD 0x4200 /* Award (0xA1 returns 0x00) - Temporary classification until we get + the real 0xAF return */ +#define KBC_VIA_VT82C4XN 0x4246 /* VIA VT82C41N, VT82C4N (0xA1 returns 'F') */ +#define KBC_VIA_VT82C586A 0x4346 /* VIA VT82C586A (0xA1 returns 'F') */ +#define KBC_VIA_VT82C586B 0x4446 /* VIA VT82C586B (0xA1 returns 'F') */ +#define KBC_VIA_VT82C686B 0x4546 /* VIA VT82C686B (0xA1 returns 'F') */ +/* UMC */ +#define KBC_UMC_UM8886 0x5048 /* UMC UM8886 'H' */ +/* IBM-style controllers with inverted P1 video type bit polarity */ +#define KBC_IBM_TYPE_1_XI8088 0x8000 /* Xi8088: IBM Type 1 */ +/* AMI (this is the 0xA1 revision byte) with inverted P1 video type bit polarity */ +#define KBC_ACER_V30_INV 0x8030 /* Acer (0xA1 returns nothing, 0xAF returns 0x00) */ +/* Holtek with inverted P1 video type bit polarity */ +#define KBC_HT_HT6542B_XI8088 0x9048 /* Xi8088: Holtek 'H' (Holtek HT6542B, BestKey) */ +/* Award and clones with inverted P1 video type bit polarity */ +#define KBC_VIA_VT82C4XN_XI8088 0xC246 /* Xi8088: VIA VT82C41N, VT82C4N (0xA1 returns 'F') */ + + #ifdef __cplusplus extern "C" { #endif @@ -68,14 +157,20 @@ extern const device_t keyboard_tandy_device; #if defined(DEV_BRANCH) && defined(USE_LASERXT) extern const device_t keyboard_xt_lxt3_device; #endif +extern const device_t keyboard_xt_olivetti_device; +extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; +extern const device_t keyboard_at_samsung_device; extern const device_t keyboard_at_toshiba_device; +extern const device_t keyboard_at_olivetti_device; +extern const device_t keyboard_at_ncr_device; extern const device_t keyboard_ps2_device; extern const device_t keyboard_ps2_ps1_device; -extern const device_t keyboard_ps2_ps2_device; +extern const device_t keyboard_ps2_ps1_pci_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; +extern const device_t keyboard_ps2_olivetti_device; extern const device_t keyboard_ps2_mca_device; extern const device_t keyboard_ps2_mca_2_device; extern const device_t keyboard_ps2_quadtel_device; @@ -83,6 +178,7 @@ extern const device_t keyboard_ps2_pci_device; extern const device_t keyboard_ps2_ami_pci_device; extern const device_t keyboard_ps2_intel_ami_pci_device; extern const device_t keyboard_ps2_acer_pci_device; +extern const device_t keyboard_ps2_ali_pci_device; #endif extern void keyboard_init(void); @@ -99,11 +195,17 @@ extern void keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl); extern int keyboard_recv(uint16_t key); extern int keyboard_isfsexit(void); extern int keyboard_ismsexit(void); +extern void keyboard_set_is_amstrad(int ams); -extern void keyboard_at_adddata_keyboard_raw(uint8_t val); extern void keyboard_at_adddata_mouse(uint8_t val); +extern void keyboard_at_adddata_mouse_direct(uint8_t val); +extern void keyboard_at_adddata_mouse_cmd(uint8_t val); +extern void keyboard_at_mouse_reset(void); +extern uint8_t keyboard_at_mouse_pos(void); +extern int keyboard_at_fixed_channel(void); extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); extern void keyboard_at_set_a20_key(int state); +extern void keyboard_at_set_mode(int ps2); extern uint8_t keyboard_at_get_mouse_scan(void); extern void keyboard_at_set_mouse_scan(uint8_t val); extern void keyboard_at_reset(void); diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 0e603e92f..6090ee611 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -16,6 +16,7 @@ * * Copyright 2017,2018 Fred N. van Kempen. */ + #ifndef LANG_UAGE_H # define LANG_UAGE_H @@ -24,8 +25,8 @@ #define IDS_STRINGS 2048 // "86Box" #define IDS_2049 2049 // "Error" #define IDS_2050 2050 // "Fatal error" -#define IDS_2051 2051 // "Are you sure you want to save..." -#define IDS_2052 2052 // "Press CTRL+ALT+PAGE DOWN..." +#define IDS_2051 2051 // " - PAUSED" +#define IDS_2052 2052 // "Press Ctrl+Alt+PgDn..." #define IDS_2053 2053 // "Speed" #define IDS_2054 2054 // "ZIP %i (%03i): %ls" #define IDS_2055 2055 // "ZIP images (*.IM?)\0*.IM..." @@ -36,19 +37,19 @@ #define IDS_2060 2060 // "On" #define IDS_2061 2061 // "Off" #define IDS_2062 2062 // "All floppy images (*.DSK..." -#define IDS_2063 2063 // "Machine ""%S"" is not..." -#define IDS_2064 2064 // "Video card ""%S"" is not..." +#define IDS_2063 2063 // "Machine ""%hs"" is not..." +#define IDS_2064 2064 // "Video card ""%hs"" is not..." #define IDS_2065 2065 // "Machine" #define IDS_2066 2066 // "Display" #define IDS_2067 2067 // "Input devices" #define IDS_2068 2068 // "Sound" #define IDS_2069 2069 // "Network" #define IDS_2070 2070 // "Ports (COM & LPT)" -#define IDS_2071 2071 // "Other peripherals" +#define IDS_2071 2071 // "Storage controllers" #define IDS_2072 2072 // "Hard disks" -#define IDS_2073 2073 // "Floppy drives" +#define IDS_2073 2073 // "Floppy and CD-ROM drives" #define IDS_2074 2074 // "Other removable devices" -#define IDS_2075 2075 // "CD-ROM images (*.ISO;*.CU.." +#define IDS_2075 2075 // "Other peripherals" #define IDS_2076 2076 // "Surface-based images (*.8.." #define IDS_2077 2077 // "Click to capture mouse" #define IDS_2078 2078 // "Press F12-F8 to release mouse" @@ -94,11 +95,11 @@ #define IDS_2118 2118 // "Internal controller" #define IDS_2119 2119 // "Exit" #define IDS_2120 2120 // "No ROMs found" -#define IDS_2121 2121 // "Save changes\nThis will hard..." -#define IDS_2122 2122 // "Discard changes\nAll changes..." -#define IDS_2123 2123 // "Cancel\nGo back to the..." -#define IDS_2124 2124 // "About " EMU_NAME -#define IDS_2125 2125 // EMU_NAME " v" EMU_VERSION +#define IDS_2121 2121 // "Do you want to save the settings?" +#define IDS_2122 2122 // "This will hard reset the emulated..." +#define IDS_2123 2123 // "Save" +#define IDS_2124 2124 // "About 86Box" +#define IDS_2125 2125 // "86Box v" EMU_VERSION #define IDS_2126 2126 // "An emulator of old computers..." #define IDS_2127 2127 // "OK" #define IDS_2128 2128 // "Hardware not available" @@ -109,9 +110,31 @@ #define IDS_2133 2133 // LIB_NAME_FLUIDSYNTH " is required..." #define IDS_2134 2134 // "Entering fullscreen mode" #define IDS_2135 2135 // "Don't show this message again" -#define IDS_2136 2136 // "Don't Exit" +#define IDS_2136 2136 // "Don't exit" #define IDS_2137 2137 // "Reset" -#define IDS_2138 2138 // "Don't Reset" +#define IDS_2138 2138 // "Don't reset" +#define IDS_2139 2139 // "MO images (*.IM?)\0*.IM?..." +#define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.." +#define IDS_2141 2141 // "%hs Device Configuration" +#define IDS_2142 2142 // "Monitor in sleep mode" +#define IDS_2143 2143 // "OpenGL Shaders (*.GLSL)..." +#define IDS_2144 2144 // "OpenGL options" +#define IDS_2145 2145 // "You are loading an unsupported..." +#define IDS_2146 2146 // "CPU type filtering based on..." +#define IDS_2147 2147 // "Continue" +#define IDS_2148 2148 // "Cassette: %s" +#define IDS_2149 2149 // "Cassette images (*.PCM;*.RAW;*..." +#define IDS_2150 2150 // "Cartridge %i: %ls" +#define IDS_2151 2151 // "Cartridge images (*.JRC)\0*.JRC\0..." +#define IDS_2152 2152 // "Error initializing renderer" +#define IDS_2153 2153 // "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +#define IDS_2154 2154 // "Resume execution" +#define IDS_2155 2155 // "Pause execution" +#define IDS_2156 2156 // "Press Ctrl+Alt+Del" +#define IDS_2157 2157 // "Press Ctrl+Alt+Esc" +#define IDS_2158 2158 // "Hard reset" +#define IDS_2159 2159 // "ACPI shutdown" +#define IDS_2160 2160 // "Settings" #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -138,23 +161,35 @@ #define IDS_4118 4118 // "The selected file will be..." #define IDS_4119 4119 // "Unsupported disk image" #define IDS_4120 4120 // "Overwrite" -#define IDS_4121 4121 // "Don't Overwrite" +#define IDS_4121 4121 // "Don't overwrite" +#define IDS_4122 4122 // "Raw image (.img)" +#define IDS_4123 4123 // "HDI image (.hdi)" +#define IDS_4124 4124 // "HDX image (.hdx)" +#define IDS_4125 4125 // "Fixed-size VHD (.vhd)" +#define IDS_4126 4126 // "Dynamic-size VHD (.vhd)" +#define IDS_4127 4127 // "Differencing VHD (.vhd)" +#define IDS_4128 4128 // "Large blocks (2 MB)" +#define IDS_4129 4129 // "Small blocks (512 KB)" +#define IDS_4130 4130 // "VHD files (*.VHD)\0*.VHD\0All..." +#define IDS_4131 4131 // "Select the parent VHD" +#define IDS_4132 4132 // "This could mean that the parent..." +#define IDS_4133 4133 // "Parent and child disk timestamps..." +#define IDS_4134 4134 // "Could not fix VHD timestamp." +#define IDS_4135 4135 // "%01i:%02i" #define IDS_4352 4352 // "MFM/RLL" #define IDS_4353 4353 // "XT IDE" #define IDS_4354 4354 // "ESDI" -#define IDS_4355 4355 // "IDE (PIO-only)" -#define IDS_4356 4356 // "IDE (PIO+DMA)" +#define IDS_4355 4355 // "IDE" +#define IDS_4356 4356 // "ATAPI" #define IDS_4357 4357 // "SCSI" -#define IDS_4358 4358 // "SCSI (removable)" #define IDS_4608 4608 // "MFM/RLL (%01i:%01i)" #define IDS_4609 4609 // "XT IDE (%01i:%01i)" #define IDS_4610 4610 // "ESDI (%01i:%01i)" -#define IDS_4611 4611 // "IDE (PIO-only) (%01i:%01i)" -#define IDS_4612 4612 // "IDE (PIO+DMA) (%01i:%01i)" +#define IDS_4611 4611 // "IDE (%01i:%01i)" +#define IDS_4612 4612 // "ATAPI (%01i:%01i)" #define IDS_4613 4613 // "SCSI (%02i:%02i)" -#define IDS_4614 4614 // "SCSI (removable) (%02i:%02i)" #define IDS_5120 5120 // "CD-ROM %i (%s): %s" @@ -162,16 +197,16 @@ #define IDS_5377 5377 // #define IDS_5378 5378 // #define IDS_5379 5379 // -#define IDS_5380 5380 // "ATAPI (PIO-only)" -#define IDS_5381 5381 // "ATAPI (PIO and DMA)" +#define IDS_5380 5380 // +#define IDS_5381 5381 // "ATAPI" #define IDS_5382 5382 // "SCSI" #define IDS_5632 5632 // "Disabled" #define IDS_5633 5633 // #define IDS_5634 5634 // #define IDS_5635 5635 // -#define IDS_5636 5636 // "ATAPI (PIO-only) (%01i:%01i)" -#define IDS_5637 5637 // "ATAPI (PIO and DMA) (%01i:%01i)" +#define IDS_5636 5636 // +#define IDS_5637 5637 // "ATAPI (%01i:%01i)" #define IDS_5638 5638 // "SCSI (%02i:%02i)" #define IDS_5888 5888 // "160 kB" @@ -188,25 +223,35 @@ #define IDS_5899 5899 // "2.88 MB" #define IDS_5900 5900 // "ZIP 100" #define IDS_5901 5901 // "ZIP 250" +#define IDS_5902 5902 // "3.5\" 128 MB (ISO 10090)" +#define IDS_5903 5903 // "3.5\" 230 MB (ISO 13963)" +#define IDS_5904 5904 // "3.5\" 540 MB (ISO 15498)" +#define IDS_5905 5905 // "3.5\" 640 MB (ISO 15498)" +#define IDS_5906 5906 // "3.5\" 1.3 GB (GigaMO)" +#define IDS_5907 5907 // "3.5\" 2.3 GB (GigaMO 2)" +#define IDS_5908 5908 // "5.25\" 600 MB" +#define IDS_5909 5909 // "5.25\" 650 MB" +#define IDS_5910 5910 // "5.25\" 1 GB" +#define IDS_5911 5911 // "5.25\" 1.3 GB" #define IDS_6144 6144 // "Perfect RPM" #define IDS_6145 6145 // "1%% below perfect RPM" #define IDS_6146 6146 // "1.5%% below perfect RPM" #define IDS_6147 6147 // "2%% below perfect RPM" -#define IDS_7168 7168 // "English (United States)" +#define IDS_7168 7168 // "(System Default)" #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 71 +#define STR_NUM_2048 106 #define STR_NUM_3072 11 -#define STR_NUM_4096 18 -#define STR_NUM_4352 7 -#define STR_NUM_4608 7 +#define STR_NUM_4096 40 +#define STR_NUM_4352 6 +#define STR_NUM_4608 6 #define STR_NUM_5120 1 #define STR_NUM_5376 7 #define STR_NUM_5632 7 -#define STR_NUM_5888 14 +#define STR_NUM_5888 24 #define STR_NUM_6144 4 #define STR_NUM_7168 1 diff --git a/src/include/86box/log.h b/src/include/86box/log.h new file mode 100644 index 000000000..3b4235b2c --- /dev/null +++ b/src/include/86box/log.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * Main include file for the application. + * + * + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2021 Miran Grca. + * Copyright 2021 Fred N. van Kempen. + */ + +#ifndef EMU_LOG_H +# define EMU_LOG_H + +#ifndef RELEASE_BUILD + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function prototypes. */ +extern void log_set_suppr_seen(void *priv, int suppr_seen); +extern void log_set_dev_name(void *priv, char *dev_name); +#ifdef HAVE_STDARG_H +extern void log_out(void *priv, const char *fmt, va_list); +extern void log_fatal(void *priv, const char *fmt, ...); +#endif +extern void * log_open(char *dev_name); +extern void log_close(void *priv); + +#ifdef __cplusplus +} +#endif + +#else +#define log_fatal(priv, fmt, ...) fatal(fmt, ...) +#endif /*RELEASE_BUILD*/ + +#endif /*EMU_LOG_H*/ diff --git a/src/include/86box/lpt.h b/src/include/86box/lpt.h index 43a91a09a..8ddf2c805 100644 --- a/src/include/86box/lpt.h +++ b/src/include/86box/lpt.h @@ -1,6 +1,26 @@ +#ifndef EMU_LPT_H +# define EMU_LPT_H + +#define LPT1_ADDR 0x0378 +#define LPT1_IRQ 7 +#define LPT2_ADDR 0x0278 +#define LPT2_IRQ 5 +// LPT 1 on machines when installed +#define LPT_MDA_ADDR 0x03bc +#define LPT_MDA_IRQ 7 +#define LPT4_ADDR 0x0268 +#define LPT4_IRQ 5 +/* +#define LPT5_ADDR 0x027c +#define LPT5_IRQ 7 +#define LPT6_ADDR 0x026c +#define LPT6_IRQ 5 +*/ + typedef struct { const char *name; + const char *internal_name; void * (*init)(void *lpt); void (*close)(void *p); @@ -18,15 +38,31 @@ extern void lpt_port_irq(int i, uint8_t irq); extern void lpt_port_remove(int i); extern void lpt1_remove_ams(void); -#define lpt1_init(a) lpt_port_init(0, a); -#define lpt1_irq(a) lpt_port_irq(0, a); -#define lpt1_remove() lpt_port_remove(0); -#define lpt2_init(a) lpt_port_init(1, a); -#define lpt2_irq(a) lpt_port_irq(1, a); -#define lpt2_remove() lpt_port_remove(1); -#define lpt3_init(a) lpt_port_init(2, a); -#define lpt3_irq(a) lpt_port_irq(2, a); -#define lpt3_remove() lpt_port_remove(2); +#define lpt1_init(a) lpt_port_init(0, a) +#define lpt1_irq(a) lpt_port_irq(0, a) +#define lpt1_remove() lpt_port_remove(0) + +#define lpt2_init(a) lpt_port_init(1, a) +#define lpt2_irq(a) lpt_port_irq(1, a) +#define lpt2_remove() lpt_port_remove(1) + +#define lpt3_init(a) lpt_port_init(2, a) +#define lpt3_irq(a) lpt_port_irq(2, a) +#define lpt3_remove() lpt_port_remove(2) + +#define lpt4_init(a) lpt_port_init(3, a) +#define lpt4_irq(a) lpt_port_irq(3, a) +#define lpt4_remove() lpt_port_remove(3) + +/* +#define lpt5_init(a) lpt_port_init(4, a) +#define lpt5_irq(a) lpt_port_irq(4, a) +#define lpt5_remove() lpt_port_remove(4) + +#define lpt6_init(a) lpt_port_init(5, a) +#define lpt6_irq(a) lpt_port_irq(5, a) +#define lpt6_remove() lpt_port_remove(5) +*/ void lpt_devices_init(void); @@ -42,7 +78,7 @@ typedef struct { void * priv; } lpt_port_t; -extern lpt_port_t lpt_ports[3]; +extern lpt_port_t lpt_ports[PARALLEL_MAX]; extern void lpt_write(uint16_t port, uint8_t val, void *priv); extern uint8_t lpt_read(uint16_t port, void *priv); @@ -58,3 +94,7 @@ extern const lpt_device_t lpt_dac_device; extern const lpt_device_t lpt_dac_stereo_device; extern const lpt_device_t dss_device; + +extern const lpt_device_t lpt_hasp_savquest_device; + +#endif /*EMU_LPT_H*/ diff --git a/src/include/86box/m_amstrad.h b/src/include/86box/m_amstrad.h index b190ab0a5..d498be6c3 100644 --- a/src/include/86box/m_amstrad.h +++ b/src/include/86box/m_amstrad.h @@ -16,6 +16,10 @@ * * Copyright 2008-2019 Sarah Walker. */ + +#ifndef MACHINE_AMSTRAD_H +# define MACHINE_AMSTRAD_H + extern int amstrad_latch; enum @@ -24,3 +28,5 @@ enum AMSTRAD_SW9, AMSTRAD_SW10 }; + +#endif /*MACHINE_AMSTRAD.H*/ diff --git a/src/include/86box/m_at_t3100e.h b/src/include/86box/m_at_t3100e.h index 216f490e2..8943f7f2f 100644 --- a/src/include/86box/m_at_t3100e.h +++ b/src/include/86box/m_at_t3100e.h @@ -36,6 +36,7 @@ * Boston, MA 02111-1307 * USA. */ + #ifndef MACHINE_T3100E_H # define MACHINE_T3100E_H diff --git a/src/include/86box/m_xt_t1000.h b/src/include/86box/m_xt_t1000.h index 8945b24e8..4220f1548 100644 --- a/src/include/86box/m_xt_t1000.h +++ b/src/include/86box/m_xt_t1000.h @@ -36,6 +36,7 @@ * Boston, MA 02111-1307 * USA. */ + #ifndef MACHINE_T1000_H # define MACHINE_T1000_H diff --git a/src/include/86box/m_xt_xi8088.h b/src/include/86box/m_xt_xi8088.h index f263e385d..e2421fa0a 100644 --- a/src/include/86box/m_xt_xi8088.h +++ b/src/include/86box/m_xt_xi8088.h @@ -1,3 +1,6 @@ +#ifndef MACHINE_XI80888_H +# define MACHINE_XI80888_H + #include <86box/device.h> extern const device_t xi8088_device; @@ -6,3 +9,5 @@ uint8_t xi8088_turbo_get(); void xi8088_turbo_set(uint8_t value); void xi8088_bios_128kb_set(int val); int xi8088_bios_128kb(); + +#endif /*MACHINE_XI80888_H*/ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index da0fdb638..0f3dc86d9 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -18,62 +18,140 @@ * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. */ + #ifndef EMU_MACHINE_H # define EMU_MACHINE_H - /* Machine feature flags. */ -#ifdef NEW_FLAGS -#define MACHINE_PC 0x000000 /* PC architecture */ -#define MACHINE_AT 0x000001 /* PC/AT architecture */ -#define MACHINE_PS2 0x000002 /* PS/2 architecture */ -#define MACHINE_ISA 0x000010 /* sys has ISA bus */ -#define MACHINE_CBUS 0x000020 /* sys has C-BUS bus */ -#define MACHINE_EISA 0x000040 /* sys has EISA bus */ -#define MACHINE_VLB 0x000080 /* sys has VL bus */ -#define MACHINE_MCA 0x000100 /* sys has MCA bus */ -#define MACHINE_PCI 0x000200 /* sys has PCI bus */ -#define MACHINE_AGP 0x000400 /* sys has AGP bus */ -#define MACHINE_HDC 0x001000 /* sys has int HDC */ -#define MACHINE_VIDEO 0x002000 /* sys has int video */ -#define MACHINE_VIDEO_FIXED 0x004000 /* sys has ONLY int video */ -#define MACHINE_MOUSE 0x008000 /* sys has int mouse */ -#define MACHINE_SOUND 0x010000 /* sys has int sound */ -#define MACHINE_NONMI 0x020000 /* sys does not have NMI's */ -#define MACHINE_FDC 0x040000 /* sys has int FDC */ -#define MACHINE_COREBOOT 0x080000 /* sys has coreboot BIOS */ +#define MACHINE_BUS_NONE 0x00000000 /* sys has no bus */ +/* Feature flags for BUS'es. */ +#define MACHINE_BUS_ISA 0x00000001 /* sys has ISA bus */ +#define MACHINE_BUS_CARTRIDGE 0x00000002 /* sys has two cartridge bays */ +#define MACHINE_BUS_ISA16 0x00000004 /* sys has ISA16 bus - PC/AT architecture */ +#define MACHINE_BUS_CBUS 0x00000008 /* sys has C-BUS bus */ +#define MACHINE_BUS_PS2 0x00000010 /* system has PS/2 keyboard and mouse ports */ +#define MACHINE_BUS_EISA 0x00000020 /* sys has EISA bus */ +#define MACHINE_BUS_VLB 0x00000040 /* sys has VL bus */ +#define MACHINE_BUS_MCA 0x00000080 /* sys has MCA bus */ +#define MACHINE_BUS_PCI 0x00000100 /* sys has PCI bus */ +#define MACHINE_BUS_PCMCIA 0x00000200 /* sys has PCMCIA bus */ +#define MACHINE_BUS_AGP 0x00000400 /* sys has AGP bus */ +#define MACHINE_BUS_AC97 0x00000800 /* sys has AC97 bus (ACR/AMR/CNR slot) */ +/* Aliases. */ +#define MACHINE_CARTRIDGE (MACHINE_BUS_CARTRIDGE) /* sys has two cartridge bays */ +/* Combined flags. */ +#define MACHINE_PC (MACHINE_BUS_ISA) /* sys is PC/XT-compatible (ISA) */ +#define MACHINE_AT (MACHINE_BUS_ISA | MACHINE_BUS_ISA16) /* sys is AT-compatible (ISA + ISA16) */ +#define MACHINE_PC98 (MACHINE_BUS_CBUS) /* sys is NEC PC-98x1 series */ +#define MACHINE_EISA (MACHINE_BUS_EISA | MACHINE_AT) /* sys is AT-compatible with EISA */ +#define MACHINE_VLB (MACHINE_BUS_VLB | MACHINE_AT) /* sys is AT-compatible with VLB */ +#define MACHINE_VLB98 (MACHINE_BUS_VLB | MACHINE_PC98) /* sys is NEC PC-98x1 series with VLB (did that even exist?) */ +#define MACHINE_VLBE (MACHINE_BUS_VLB | MACHINE_EISA) /* sys is AT-compatible with EISA and VLB */ +#define MACHINE_MCA (MACHINE_BUS_MCA) /* sys is MCA */ +#define MACHINE_PCI (MACHINE_BUS_PCI | MACHINE_AT) /* sys is AT-compatible with PCI */ +#define MACHINE_PCI98 (MACHINE_BUS_PCI | MACHINE_PC98) /* sys is NEC PC-98x1 series with PCI */ +#define MACHINE_PCIE (MACHINE_BUS_PCI | MACHINE_EISA) /* sys is AT-compatible with PCI, and EISA */ +#define MACHINE_PCIV (MACHINE_BUS_PCI | MACHINE_VLB) /* sys is AT-compatible with PCI and VLB */ +#define MACHINE_PCIVE (MACHINE_BUS_PCI | MACHINE_VLBE) /* sys is AT-compatible with PCI, VLB, and EISA */ +#define MACHINE_PCMCIA (MACHINE_BUS_PCMCIA | MACHINE_AT) /* sys is AT-compatible laptop with PCMCIA */ +#define MACHINE_AGP (MACHINE_BUS_AGP | MACHINE_PCI) /* sys is AT-compatible with AGP */ +#define MACHINE_AGP98 (MACHINE_BUS_AGP | MACHINE_PCI98) /* sys is NEC PC-98x1 series with AGP (did that even exist?) */ + +#define MACHINE_PCJR (MACHINE_PC | MACHINE_CARTRIDGE) /* sys is PCjr */ +#define MACHINE_PS2 (MACHINE_AT | MACHINE_BUS_PS2) /* sys is PS/2 */ +#define MACHINE_PS2_MCA (MACHINE_MCA | MACHINE_BUS_PS2) /* sys is MCA PS/2 */ +#define MACHINE_PS2_VLB (MACHINE_VLB | MACHINE_BUS_PS2) /* sys is VLB PS/2 */ +#define MACHINE_PS2_PCI (MACHINE_PCI | MACHINE_BUS_PS2) /* sys is PCI PS/2 */ +#define MACHINE_PS2_PCIV (MACHINE_PCIV | MACHINE_BUS_PS2) /* sys is VLB/PCI PS/2 */ +#define MACHINE_PS2_AGP (MACHINE_AGP | MACHINE_BUS_PS2) /* sys is AGP PS/2 */ +#define MACHINE_PS2_A97 (MACHINE_PS2_AGP | MACHINE_BUS_AC97) /* sys is AGP/AC97 PS/2 */ +#define MACHINE_PS2_NOISA (MACHINE_PS2_AGP & ~MACHINE_AT) /* sys is AGP PS/2 without ISA */ +#define MACHINE_PS2_NOI97 (MACHINE_PS2_A97 & ~MACHINE_AT) /* sys is AGP/AC97 PS/2 without ISA */ +/* Feature flags for miscellaneous internal devices. */ +#define MACHINE_FLAGS_NONE 0x00000000 /* sys has no int devices */ +#define MACHINE_VIDEO 0x00000001 /* sys has int video */ +#define MACHINE_VIDEO_ONLY 0x00000002 /* sys has fixed video */ +#define MACHINE_MOUSE 0x00000004 /* sys has int mouse */ +#define MACHINE_FDC 0x00000008 /* sys has int FDC */ +#define MACHINE_LPT_PRI 0x00000010 /* sys has int pri LPT */ +#define MACHINE_LPT_SEC 0x00000020 /* sys has int sec LPT */ +#define MACHINE_UART_PRI 0x00000040 /* sys has int pri UART */ +#define MACHINE_UART_SEC 0x00000080 /* sys has int sec UART */ +#define MACHINE_UART_TER 0x00000100 /* sys has int ter UART */ +#define MACHINE_UART_QUA 0x00000200 /* sys has int qua UART */ +#define MACHINE_GAMEPORT 0x00000400 /* sys has int game port */ +#define MACHINE_SOUND 0x00000800 /* sys has int sound */ +#define MACHINE_NIC 0x00001000 /* sys has int NIC */ +#define MACHINE_MODEM 0x00002000 /* sys has int modem */ +/* Feature flags for advanced devices. */ +#define MACHINE_APM 0x00004000 /* sys has APM */ +#define MACHINE_ACPI 0x00008000 /* sys has ACPI */ +#define MACHINE_HWM 0x00010000 /* sys has hw monitor */ +/* Combined flags. */ +#define MACHINE_VIDEO_FIXED (MACHINE_VIDEO | MACHINE_VIDEO_ONLY) /* sys has fixed int video */ +#define MACHINE_SUPER_IO (MACHINE_FDC | MACHINE_LPT_PRI | MACHINE_UART_PRI | MACHINE_UART_SEC) +#define MACHINE_SUPER_IO_GAME (MACHINE_SUPER_IO | MACHINE_GAMEPORT) +#define MACHINE_SUPER_IO_DUAL (MACHINE_SUPER_IO | MACHINE_LPT_SEC | MACHINE_UART_TER | MACHINE_UART_QUA) +#define MACHINE_AV (MACHINE_VIDEO | MACHINE_SOUND) /* sys has video and sound */ +#define MACHINE_AG (MACHINE_SOUND | MACHINE_GAMEPORT) /* sys has sound and game port */ +/* Feature flags for internal storage controllers. */ +#define MACHINE_HDC 0x03FE0000 /* sys has int HDC */ +#define MACHINE_MFM 0x00020000 /* sys has int MFM/RLL */ +#define MACHINE_XTA 0x00040000 /* sys has int XTA */ +#define MACHINE_ESDI 0x00080000 /* sys has int ESDI */ +#define MACHINE_IDE_PRI 0x00100000 /* sys has int pri IDE/ATAPI */ +#define MACHINE_IDE_SEC 0x00200000 /* sys has int sec IDE/ATAPI */ +#define MACHINE_IDE_TER 0x00400000 /* sys has int ter IDE/ATAPI */ +#define MACHINE_IDE_QUA 0x00800000 /* sys has int qua IDE/ATAPI */ +#define MACHINE_SCSI_PRI 0x01000000 /* sys has int pri SCSI */ +#define MACHINE_SCSI_SEC 0x02000000 /* sys has int sec SCSI */ +#define MACHINE_USB_PRI 0x04000000 /* sys has int pri USB */ +#define MACHINE_USB_SEC 0x08000000 /* sys has int sec USB */ +#define MACHINE_COREBOOT 0x10000000 /* sys has coreboot BIOS */ + +/* Combined flags. */ +#define MACHINE_IDE (MACHINE_IDE_PRI) /* sys has int single IDE/ATAPI - mark as pri IDE/ATAPI */ +#define MACHINE_IDE_DUAL (MACHINE_IDE_PRI | MACHINE_IDE_SEC) /* sys has int dual IDE/ATAPI - mark as both pri and sec IDE/ATAPI */ +#define MACHINE_IDE_DUALTQ (MACHINE_IDE_TER | MACHINE_IDE_QUA) +#define MACHINE_IDE_QUAD (MACHINE_IDE_DUAL | MACHINE_IDE_DUALTQ) /* sys has int quad IDE/ATAPI - mark as dual + both ter and and qua IDE/ATAPI */ +#define MACHINE_SCSI (MACHINE_SCSI_PRI) /* sys has int single SCSI - mark as pri SCSI */ +#define MACHINE_SCSI_DUAL (MACHINE_SCSI_PRI | MACHINE_SCSI_SEC) /* sys has int dual SCSI - mark as both pri and sec SCSI */ +#define MACHINE_USB (MACHINE_USB_PRI) +#define MACHINE_USB_DUAL (MACHINE_USB_PRI | MACHINE_USB_SEC) +/* Special combined flags. */ +#define MACHINE_PIIX (MACHINE_IDE_DUAL) +#define MACHINE_PIIX3 (MACHINE_PIIX | MACHINE_USB) +/* TODO: ACPI flag. */ +#define MACHINE_PIIX4 (MACHINE_PIIX3 | MACHINE_ACPI) + +#define IS_ARCH(m, a) ((machines[m].bus_flags & (a)) ? 1 : 0) +#define IS_AT(m) (((machines[m].bus_flags & (MACHINE_BUS_ISA16 | MACHINE_BUS_EISA | MACHINE_BUS_VLB | MACHINE_BUS_MCA | MACHINE_BUS_PCI | MACHINE_BUS_PCMCIA | MACHINE_BUS_AGP | MACHINE_BUS_AC97)) && !(machines[m].bus_flags & MACHINE_PC98)) ? 1 : 0) + +#define CPU_BLOCK(...) (const uint8_t[]) {__VA_ARGS__, 0} +#define MACHINE_MULTIPLIER_FIXED -1 + +#define CPU_BLOCK_NONE 0 + +/* Make sure it's always an invalid value to avoid misdetections. */ +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) +#define MACHINE_AVAILABLE 0xffffffffffffffffULL #else -#define MACHINE_PC 0x000000 /* PC architecture */ -#define MACHINE_AT 0x000001 /* PC/AT architecture */ -#define MACHINE_PS2 0x000002 /* PS/2 architecture */ -#define MACHINE_ISA 0x000010 /* sys has ISA bus */ -#define MACHINE_CBUS 0x000020 /* sys has C-BUS bus */ -#define MACHINE_EISA 0x000040 /* sys has EISA bus */ -#define MACHINE_VLB 0x000080 /* sys has VL bus */ -#define MACHINE_MCA 0x000100 /* sys has MCA bus */ -#define MACHINE_PCI 0x000200 /* sys has PCI bus */ -#define MACHINE_AGP 0x000400 /* sys has AGP bus */ -#define MACHINE_HDC 0x001000 /* sys has int HDC */ -#define MACHINE_VIDEO 0x002000 /* sys has int video */ -#define MACHINE_VIDEO_FIXED 0x004000 /* sys has ONLY int video */ -#define MACHINE_MOUSE 0x008000 /* sys has int mouse */ -#define MACHINE_SOUND 0x010000 /* sys has int sound */ -#define MACHINE_NONMI 0x020000 /* sys does not have NMI's */ -#define MACHINE_FDC 0x040000 /* sys has int FDC */ -#define MACHINE_COREBOOT 0x080000 /* sys has coreboot BIOS */ +#define MACHINE_AVAILABLE 0xffffffff #endif -#define IS_ARCH(m, a) (machines[(m)].flags & (a)) ? 1 : 0; - - enum { MACHINE_TYPE_NONE = 0, MACHINE_TYPE_8088, MACHINE_TYPE_8086, MACHINE_TYPE_286, MACHINE_TYPE_386SX, + MACHINE_TYPE_486SLC, MACHINE_TYPE_386DX, + MACHINE_TYPE_386DX_486, MACHINE_TYPE_486, + MACHINE_TYPE_486_S2, + MACHINE_TYPE_486_S3, + MACHINE_TYPE_486_MISC, MACHINE_TYPE_SOCKET4, MACHINE_TYPE_SOCKET5, MACHINE_TYPE_SOCKET7_3V, @@ -81,80 +159,164 @@ enum { MACHINE_TYPE_SOCKETS7, MACHINE_TYPE_SOCKET8, MACHINE_TYPE_SLOT1, + MACHINE_TYPE_SLOT1_2, + MACHINE_TYPE_SLOT1_370, MACHINE_TYPE_SLOT2, MACHINE_TYPE_SOCKET370, + MACHINE_TYPE_MISC, MACHINE_TYPE_MAX }; +enum { + MACHINE_CHIPSET_NONE = 0, + MACHINE_CHIPSET_DISCRETE, + MACHINE_CHIPSET_PROPRIETARY, + MACHINE_CHIPSET_GC100A, + MACHINE_CHIPSET_GC103, + MACHINE_CHIPSET_HT18, + MACHINE_CHIPSET_ACC_2168, + MACHINE_CHIPSET_ALI_M1217, + MACHINE_CHIPSET_ALI_M6117, + MACHINE_CHIPSET_ALI_M1409, + MACHINE_CHIPSET_ALI_M1429, + MACHINE_CHIPSET_ALI_M1429G, + MACHINE_CHIPSET_ALI_M1489, + MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS, + MACHINE_CHIPSET_ALI_ALADDIN_V, + MACHINE_CHIPSET_ALI_ALADDIN_PRO_II, + MACHINE_CHIPSET_SCAT, + MACHINE_CHIPSET_NEAT, + MACHINE_CHIPSET_CT_386, + MACHINE_CHIPSET_CT_CS4031, + MACHINE_CHIPSET_CONTAQ_82C596, + MACHINE_CHIPSET_CONTAQ_82C597, + MACHINE_CHIPSET_IMS_8848, + MACHINE_CHIPSET_INTEL_82335, + MACHINE_CHIPSET_INTEL_420TX, + MACHINE_CHIPSET_INTEL_420ZX, + MACHINE_CHIPSET_INTEL_420EX, + MACHINE_CHIPSET_INTEL_430LX, + MACHINE_CHIPSET_INTEL_430NX, + MACHINE_CHIPSET_INTEL_430FX, + MACHINE_CHIPSET_INTEL_430HX, + MACHINE_CHIPSET_INTEL_430VX, + MACHINE_CHIPSET_INTEL_430TX, + MACHINE_CHIPSET_INTEL_450KX, + MACHINE_CHIPSET_INTEL_440FX, + MACHINE_CHIPSET_INTEL_440EX, + MACHINE_CHIPSET_INTEL_440LX, + MACHINE_CHIPSET_INTEL_440BX, + MACHINE_CHIPSET_INTEL_440ZX, + MACHINE_CHIPSET_INTEL_440GX, + MACHINE_CHIPSET_OPTI_283, + MACHINE_CHIPSET_OPTI_291, + MACHINE_CHIPSET_OPTI_493, + MACHINE_CHIPSET_OPTI_495, + MACHINE_CHIPSET_OPTI_499, + MACHINE_CHIPSET_OPTI_895_802G, + MACHINE_CHIPSET_OPTI_547_597, + MACHINE_CHIPSET_SARC_RC2016A, + MACHINE_CHIPSET_SIS_310, + MACHINE_CHIPSET_SIS_401, + MACHINE_CHIPSET_SIS_460, + MACHINE_CHIPSET_SIS_461, + MACHINE_CHIPSET_SIS_471, + MACHINE_CHIPSET_SIS_496, + MACHINE_CHIPSET_SIS_501, + MACHINE_CHIPSET_SIS_5511, + MACHINE_CHIPSET_SIS_5571, + MACHINE_CHIPSET_SMSC_VICTORYBX_66, + MACHINE_CHIPSET_STPC_CLIENT, + MACHINE_CHIPSET_STPC_CONSUMER_II, + MACHINE_CHIPSET_STPC_ELITE, + MACHINE_CHIPSET_STPC_ATLAS, + MACHINE_CHIPSET_SYMPHONY_SL82C460, + MACHINE_CHIPSET_UMC_UM82C480, + MACHINE_CHIPSET_UMC_UM82C491, + MACHINE_CHIPSET_UMC_UM8881, + MACHINE_CHIPSET_UMC_UM8890BF, + MACHINE_CHIPSET_VIA_VT82C495, + MACHINE_CHIPSET_VIA_VT82C496G, + MACHINE_CHIPSET_VIA_APOLLO_VPX, + MACHINE_CHIPSET_VIA_APOLLO_VP3, + MACHINE_CHIPSET_VIA_APOLLO_MVP3, + MACHINE_CHIPSET_VIA_APOLLO_PRO, + MACHINE_CHIPSET_VIA_APOLLO_PRO_133, + MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, + MACHINE_CHIPSET_VLSI_SCAMP, + MACHINE_CHIPSET_VLSI_VL82C480, + MACHINE_CHIPSET_VLSI_VL82C481, + MACHINE_CHIPSET_VLSI_VL82C486, + MACHINE_CHIPSET_WD76C10, + MACHINE_CHIPSET_MAX +}; -typedef struct _machine_type_ { +typedef struct _machine_filter_ { const char *name; const char id; -} machine_type_t; +} machine_filter_t; +typedef struct _machine_cpu_ { + uint32_t package; + const uint8_t *block; + uint32_t min_bus; + uint32_t max_bus; + uint16_t min_voltage; + uint16_t max_voltage; + float min_multi; + float max_multi; +} machine_cpu_t; + +typedef struct _machine_memory_ { + uint32_t min, max; + int step; +} machine_memory_t; -#ifdef NEW_STRUCT typedef struct _machine_ { - const char *name; - const char *internal_name; - const char type; + const char *name; + const char *internal_name; + uint32_t type; + uint32_t chipset; + int (*init)(const struct _machine_ *); + uintptr_t pad, pad0, pad1, pad2; + const machine_cpu_t cpu; + uintptr_t bus_flags; + uintptr_t flags; + const machine_memory_t ram; + int ram_granularity; + int nvrmask; + uint16_t kbc; + /* Bits: + 7-0 Set bits are forced set on P1 (no forced set = 0x00); + 15-8 Clear bits are forced clear on P1 (no foced clear = 0xff). */ + uint16_t kbc_p1; + uint32_t gpio; + uint32_t gpio_acpi; #ifdef EMU_DEVICE_H - const device_t *device; + const device_t *device; + const device_t *vid_device; + const device_t *snd_device; + const device_t *net_device; #else - void *device; -#endif - struct { - const char *name; -#ifdef EMU_CPU_H - CPU *cpus; -#else - void *cpus; -#endif - } cpu[5]; - int flags; - uint32_t min_ram, max_ram; - int ram_granularity; - int nvrmask; -} machine_t; -#else -typedef struct _machine_ { - const char *name; - const char *internal_name; - const char type; - struct { - const char *name; -#ifdef EMU_CPU_H - CPU *cpus; -#else - void *cpus; -#endif - } cpu[5]; - int flags; - uint32_t min_ram, max_ram; - int ram_granularity; - int nvrmask; - int (*init)(const struct _machine_ *); -#ifdef EMU_DEVICE_H - const device_t *(*get_device)(void); -#else - void *get_device; + void *device; + void *vid_device; + void *snd_device; + void *net_device; #endif } machine_t; -#endif - /* Global variables. */ -extern const machine_type_t machine_types[]; -extern const machine_t machines[]; -extern int bios_only; -extern int machine; -extern int AT, PCI; - +extern const machine_filter_t machine_types[], + machine_chipsets[]; +extern const machine_t machines[]; +extern int bios_only; +extern int machine; /* Core functions. */ extern int machine_count(void); extern int machine_available(int m); extern char *machine_getname(void); +extern char *machine_getname_ex(int m); extern char *machine_get_internal_name(void); extern int machine_get_machine_from_internal_name(char *s); extern void machine_init(void); @@ -162,9 +324,21 @@ extern void machine_init(void); extern const device_t *machine_getdevice(int m); #endif extern char *machine_get_internal_name_ex(int m); -extern int machine_get_nvrmask(int m); -extern void machine_close(void); +extern int machine_get_nvrmask(int m); +extern int machine_has_flags(int m, int flags); +extern int machine_has_bus(int m, int bus_flags); +extern int machine_has_cartridge(int m); +extern int machine_get_min_ram(int m); +extern int machine_get_max_ram(int m); +extern int machine_get_ram_granularity(int m); +extern int machine_get_type(int m); +extern void machine_close(void); +extern uint8_t machine_get_p1(void); +extern void machine_load_p1(int m); +extern uint32_t machine_get_gpi(void); +extern void machine_load_gpi(int m); +extern void machine_set_gpi(uint32_t gpi); /* Initialization functions for boards and systems. */ extern void machine_common_init(const machine_t *); @@ -177,15 +351,6 @@ extern int machine_ppc512_init(const machine_t *); extern int machine_pc2086_init(const machine_t *); extern int machine_pc3086_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *pc1512_get_device(void); -extern const device_t *pc1640_get_device(void); -extern const device_t *pc200_get_device(void); -extern const device_t *ppc512_get_device(void); -extern const device_t *pc2086_get_device(void); -extern const device_t *pc3086_get_device(void); -#endif - /* m_at.c */ extern void machine_at_common_init_ex(const machine_t *, int type); extern void machine_at_common_init(const machine_t *); @@ -205,18 +370,13 @@ extern int machine_at_ibmatquadtel_init(const machine_t *); // IBM AT with Quadt extern int machine_at_ibmxt286_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_SIEMENS) extern int machine_at_siemens_init(const machine_t *); //Siemens PCD-2L. N82330 discrete machine. It segfaults in some places -#endif #if defined(DEV_BRANCH) && defined(USE_OPEN_AT) -extern int machine_at_open_at_init(const machine_t *); +extern int machine_at_openat_init(const machine_t *); #endif /* m_at_286_386sx.c */ -#if defined(DEV_BRANCH) && defined(USE_AMI386SX) -extern int machine_at_headland_init(const machine_t *); -#endif extern int machine_at_tg286m_init(const machine_t *); extern int machine_at_ama932j_init(const machine_t *); extern int machine_at_px286_init(const machine_t *); @@ -226,7 +386,7 @@ extern int machine_at_mr286_init(const machine_t *); extern int machine_at_neat_init(const machine_t *); extern int machine_at_neat_ami_init(const machine_t *); -extern int machine_at_goldstar386_init(const machine_t *); +extern int machine_at_quadt386sx_init(const machine_t *); extern int machine_at_award286_init(const machine_t *); extern int machine_at_gdc212m_init(const machine_t *); @@ -234,26 +394,53 @@ extern int machine_at_gw286ct_init(const machine_t *); extern int machine_at_super286tr_init(const machine_t *); extern int machine_at_spc4200p_init(const machine_t *); extern int machine_at_spc4216p_init(const machine_t *); +extern int machine_at_spc4620p_init(const machine_t *); extern int machine_at_kmxc02_init(const machine_t *); extern int machine_at_deskmaster286_init(const machine_t *); -extern int machine_at_commodore_sl386sx_init(const machine_t *); -extern int machine_at_wd76c10_init(const machine_t *); +extern int machine_at_pc8_init(const machine_t *); +extern int machine_at_3302_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_ama932j_get_device(void); -extern const device_t *at_commodore_sl386sx_get_device(void); +#if defined(DEV_BRANCH) && defined(USE_OLIVETTI) +extern int machine_at_m290_init(const machine_t *); #endif -/* m_at_386dx_486.c */ +extern int machine_at_shuttle386sx_init(const machine_t *); +extern int machine_at_adi386sx_init(const machine_t *); +extern int machine_at_cmdsl386sx16_init(const machine_t *); +extern int machine_at_cmdsl386sx25_init(const machine_t *); +extern int machine_at_dataexpert386sx_init(const machine_t *); +extern int machine_at_spc6033p_init(const machine_t *); +extern int machine_at_wd76c10_init(const machine_t *); +extern int machine_at_arb1374_init(const machine_t *); +extern int machine_at_sbc350a_init(const machine_t *); +extern int machine_at_flytech386_init(const machine_t *); +extern int machine_at_mr1217_init(const machine_t *); +extern int machine_at_pja511m_init(const machine_t *); +extern int machine_at_prox1332_init(const machine_t *); +extern int machine_at_awardsx_init(const machine_t *); + +extern int machine_at_pc916sx_init(const machine_t *); + +/* m_at_386dx_486.c */ extern int machine_at_acc386_init(const machine_t *); extern int machine_at_asus386_init(const machine_t *); -extern int machine_at_ecs386_init(const machine_t *); +extern int machine_at_ecs386_init(const machine_t *); +extern int machine_at_spc6000a_init(const machine_t *); extern int machine_at_micronics386_init(const machine_t *); +extern int machine_at_rycleopardlx_init(const machine_t *); + +extern int machine_at_486vchd_init(const machine_t *); + +extern int machine_at_cs4031_init(const machine_t *); + extern int machine_at_pb410a_init(const machine_t *); +extern int machine_at_decpclpv_init(const machine_t *); +extern int machine_at_acerv10_init(const machine_t *); + extern int machine_at_acera1g_init(const machine_t *); extern int machine_at_ali1429_init(const machine_t *); extern int machine_at_winbios1429_init(const machine_t *); @@ -262,24 +449,62 @@ extern int machine_at_opti495_init(const machine_t *); extern int machine_at_opti495_ami_init(const machine_t *); extern int machine_at_opti495_mr_init(const machine_t *); +extern int machine_at_vect486vl_init(const machine_t *); +extern int machine_at_d824_init(const machine_t *); + +extern int machine_at_403tg_init(const machine_t *); +extern int machine_at_403tg_d_init(const machine_t *); +extern int machine_at_403tg_d_mr_init(const machine_t *); +extern int machine_at_pc330_6573_init(const machine_t *); +extern int machine_at_mvi486_init(const machine_t *); + +extern int machine_at_sis401_init(const machine_t *); +extern int machine_at_isa486_init(const machine_t *); +extern int machine_at_av4_init(const machine_t *); +extern int machine_at_valuepoint433_init(const machine_t *); + extern int machine_at_vli486sv2g_init(const machine_t *); extern int machine_at_ami471_init(const machine_t *); extern int machine_at_dtk486_init(const machine_t *); extern int machine_at_px471_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_WIN471) extern int machine_at_win471_init(const machine_t *); -#endif +extern int machine_at_vi15g_init(const machine_t *); +extern int machine_at_greenb_init(const machine_t *); extern int machine_at_r418_init(const machine_t *); extern int machine_at_ls486e_init(const machine_t *); extern int machine_at_4dps_init(const machine_t *); +extern int machine_at_4saw2_init(const machine_t *); +extern int machine_at_m4li_init(const machine_t *); extern int machine_at_alfredo_init(const machine_t *); +extern int machine_at_ninja_init(const machine_t *); +extern int machine_at_486sp3_init(const machine_t *); +extern int machine_at_486sp3c_init(const machine_t *); extern int machine_at_486sp3g_init(const machine_t *); extern int machine_at_486ap4_init(const machine_t *); +extern int machine_at_g486vpa_init(const machine_t *); +extern int machine_at_486vipio2_init(const machine_t *); +extern int machine_at_abpb4_init(const machine_t *); +extern int machine_at_win486pci_init(const machine_t *); +extern int machine_at_ms4145_init(const machine_t *); +extern int machine_at_sbc490_init(const machine_t *); +extern int machine_at_tf486_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_acera1g_get_device(void); -#endif +extern int machine_at_pci400cb_init(const machine_t *); +extern int machine_at_g486ip_init(const machine_t *); + +extern int machine_at_itoxstar_init(const machine_t *); +extern int machine_at_arb1423c_init(const machine_t *); +extern int machine_at_arb1479_init(const machine_t *); +extern int machine_at_pcm9340_init(const machine_t *); +extern int machine_at_pcm5330_init(const machine_t *); + +extern int machine_at_ecs486_init(const machine_t *); +extern int machine_at_hot433_init(const machine_t *); +extern int machine_at_atc1415_init(const machine_t *); +extern int machine_at_actionpc2600_init(const machine_t *); +extern int machine_at_m919_init(const machine_t *); +extern int machine_at_spc7700plw_init(const machine_t *); /* m_at_commodore.c */ extern int machine_at_cmdpc_init(const machine_t *); @@ -288,90 +513,138 @@ extern int machine_at_cmdpc_init(const machine_t *); extern int machine_at_portableii_init(const machine_t *); extern int machine_at_portableiii_init(const machine_t *); extern int machine_at_portableiii386_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_cpqiii_get_device(void); +#if defined(DEV_BRANCH) && defined(USE_DESKPRO386) +extern int machine_at_deskpro386_init(const machine_t *); #endif -/* m_at_socket4_5.c */ -extern int machine_at_excalibur_init(const machine_t *); +/* m_at_socket4.c */ +extern void machine_at_premiere_common_init(const machine_t *, int); +extern void machine_at_award_common_init(const machine_t *); -extern int machine_at_batman_init(const machine_t *); +extern void machine_at_sp4_common_init(const machine_t *model); + +extern int machine_at_excaliburpci_init(const machine_t *); +extern int machine_at_p5mp3_init(const machine_t *); +extern int machine_at_dellxp60_init(const machine_t *); +extern int machine_at_opti560l_init(const machine_t *); extern int machine_at_ambradp60_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_VPP60) extern int machine_at_valuepointp60_init(const machine_t *); -#endif +extern int machine_at_revenge_init(const machine_t *); extern int machine_at_586mc1_init(const machine_t *); +extern int machine_at_pb520r_init(const machine_t *); +extern int machine_at_excalibur_init(const machine_t *); + +extern int machine_at_p5vl_init(const machine_t *); + +extern int machine_at_excaliburpci2_init(const machine_t *); +extern int machine_at_p5sp4_init(const machine_t *); + +/* m_at_socket5.c */ extern int machine_at_plato_init(const machine_t *); extern int machine_at_ambradp90_init(const machine_t *); extern int machine_at_430nx_init(const machine_t *); -extern int machine_at_p54tp4xe_init(const machine_t *); -extern int machine_at_endeavor_init(const machine_t *); -extern int machine_at_zappa_init(const machine_t *); -extern int machine_at_gw2kzp_init(const machine_t *); -extern int machine_at_mb500n_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_VECTRA54) -extern int machine_at_vectra54_init(const machine_t *); -#endif -extern int machine_at_powermate_v_init(const machine_t *); extern int machine_at_acerv30_init(const machine_t *); +extern int machine_at_apollo_init(const machine_t *); +extern int machine_at_exp8551_init(const machine_t *); +extern int machine_at_zappa_init(const machine_t *); +extern int machine_at_powermatev_init(const machine_t *); +extern int machine_at_mb500n_init(const machine_t *); +extern int machine_at_hawk_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_endeavor_get_device(void); -#endif +extern int machine_at_pat54pv_init(const machine_t *); -/* m_at_socket7_s7.c */ -extern int machine_at_chariot_init(const machine_t *); -extern int machine_at_mr586_init(const machine_t *); -extern int machine_at_thor_init(const machine_t *); +extern int machine_at_hot543_init(const machine_t *); + +extern int machine_at_p54sp4_init(const machine_t *); +extern int machine_at_sq588_init(const machine_t *); + + +/* m_at_socket7_3v.c */ +extern int machine_at_p54tp4xe_init(const machine_t *); +extern int machine_at_p54tp4xe_mr_init(const machine_t *); extern int machine_at_gw2katx_init(const machine_t *); +extern int machine_at_thor_init(const machine_t *); extern int machine_at_mrthor_init(const machine_t *); +extern int machine_at_endeavor_init(const machine_t *); +extern int machine_at_ms5119_init(const machine_t *); extern int machine_at_pb640_init(const machine_t *); +extern int machine_at_fmb_init(const machine_t *); extern int machine_at_acerm3a_init(const machine_t *); -extern int machine_at_acerv35n_init(const machine_t *); extern int machine_at_ap53_init(const machine_t *); -extern int machine_at_p55t2p4_init(const machine_t *); +extern int machine_at_8500tuc_init(const machine_t *); extern int machine_at_p55t2s_init(const machine_t *); + +extern int machine_at_p5vxb_init(const machine_t *); +extern int machine_at_gw2kte_init(const machine_t *); + +extern int machine_at_ap5s_init(const machine_t *); +extern int machine_at_vectra54_init(const machine_t *); + +/* m_at_socket7.c */ +extern int machine_at_acerv35n_init(const machine_t *); +extern int machine_at_p55t2p4_init(const machine_t *); extern int machine_at_m7shi_init(const machine_t *); extern int machine_at_tc430hx_init(const machine_t *); extern int machine_at_equium5200_init(const machine_t *); +extern int machine_at_pcv90_init(const machine_t *); extern int machine_at_p65up5_cp55t2d_init(const machine_t *); +extern int machine_at_ap5vm_init(const machine_t *); extern int machine_at_p55tvp4_init(const machine_t *); -extern int machine_at_p55va_init(const machine_t *); -extern int machine_at_i430vx_init(const machine_t *); -extern int machine_at_brio80xx_init(const machine_t *); +extern int machine_at_5ivg_init(const machine_t *); extern int machine_at_8500tvxa_init(const machine_t *); +extern int machine_at_presario2240_init(const machine_t *); +extern int machine_at_presario4500_init(const machine_t *); +extern int machine_at_p55va_init(const machine_t *); +extern int machine_at_brio80xx_init(const machine_t *); extern int machine_at_pb680_init(const machine_t *); +extern int machine_at_mb520n_init(const machine_t *); +extern int machine_at_i430vx_init(const machine_t *); extern int machine_at_nupro592_init(const machine_t *); extern int machine_at_tx97_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_AN430TX) +extern int machine_at_an430tx_init(const machine_t *); +#endif extern int machine_at_ym430tx_init(const machine_t *); extern int machine_at_mb540n_init(const machine_t *); +extern int machine_at_56a5_init(const machine_t *); extern int machine_at_p5mms98_init(const machine_t *); extern int machine_at_ficva502_init(const machine_t *); extern int machine_at_ficpa2012_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_pb640_get_device(void); -#endif +extern int machine_at_r534f_init(const machine_t *); +extern int machine_at_ms5146_init(const machine_t *); + +extern int machine_at_m560_init(const machine_t *); +extern int machine_at_ms5164_init(const machine_t *); + +/* m_at_sockets7.c */ +extern int machine_at_p5a_init(const machine_t *); +extern int machine_at_m579_init(const machine_t *); +extern int machine_at_5aa_init(const machine_t *); +extern int machine_at_5ax_init(const machine_t *); -/* m_at_super7_ss7.c */ extern int machine_at_ax59pro_init(const machine_t *); extern int machine_at_mvp3_init(const machine_t *); +extern int machine_at_ficva503a_init(const machine_t *); +extern int machine_at_5emapro_init(const machine_t *); /* m_at_socket8.c */ +extern int machine_at_p6rp4_init(const machine_t *); +extern int machine_at_aurora_init(const machine_t *); + extern int machine_at_686nx_init(const machine_t *); -extern int machine_at_v60n_init(const machine_t *); +extern int machine_at_acerv60n_init(const machine_t *); extern int machine_at_vs440fx_init(const machine_t *); -extern int machine_at_gw2kvs_init(const machine_t *); extern int machine_at_ap440fx_init(const machine_t *); extern int machine_at_mb600n_init(const machine_t *); -extern int machine_at_8500ttc_init(const machine_t *); +extern int machine_at_8600ttc_init(const machine_t *); extern int machine_at_m6mi_init(const machine_t *); #ifdef EMU_DEVICE_H extern void machine_at_p65up5_common_init(const machine_t *, const device_t *northbridge); @@ -379,10 +652,13 @@ extern void machine_at_p65up5_common_init(const machine_t *, const device_t *nor extern int machine_at_p65up5_cp6nd_init(const machine_t *); /* m_at_slot1.c */ +extern int machine_at_m729_init(const machine_t *); + extern int machine_at_p65up5_cpknd_init(const machine_t *); extern int machine_at_kn97_init(const machine_t *); extern int machine_at_lx6_init(const machine_t *); +extern int machine_at_spitfire_init(const machine_t *); extern int machine_at_p6i440e2_init(const machine_t *); @@ -391,25 +667,41 @@ extern int machine_at_p3bf_init(const machine_t *); extern int machine_at_bf6_init(const machine_t *); extern int machine_at_ax6bc_init(const machine_t *); extern int machine_at_atc6310bxii_init(const machine_t *); -extern int machine_at_tsunamiatx_init(const machine_t *); +extern int machine_at_686bx_init(const machine_t *); +extern int machine_at_s1846_init(const machine_t *); extern int machine_at_p6sba_init(const machine_t *); +extern int machine_at_ficka6130_init(const machine_t *); +extern int machine_at_p3v133_init(const machine_t *); +extern int machine_at_p3v4x_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *at_tsunamiatx_get_device(void); -#endif +extern int machine_at_vei8_init(const machine_t *); + +extern int machine_at_borapro_init(const machine_t *); +extern int machine_at_ms6168_init(const machine_t *); /* m_at_slot2.c */ extern int machine_at_6gxu_init(const machine_t *); extern int machine_at_s2dge_init(const machine_t *); +extern int machine_at_fw6400gx_init(const machine_t *); /* m_at_socket370.c */ extern int machine_at_s370slm_init(const machine_t *); extern int machine_at_cubx_init(const machine_t *); extern int machine_at_atc7020bxii_init(const machine_t *); -extern int machine_at_63a_init(const machine_t *); +extern int machine_at_ambx133_init(const machine_t *); +extern int machine_at_awo671r_init(const machine_t *); +extern int machine_at_63a1_init(const machine_t *); extern int machine_at_s370sba_init(const machine_t *); extern int machine_at_apas3_init(const machine_t *); +extern int machine_at_gt694va_init(const machine_t *); +extern int machine_at_cuv4xls_init(const machine_t *); +extern int machine_at_6via90ap_init(const machine_t *); +extern int machine_at_s1857_init(const machine_t *); +extern int machine_at_p6bap_init(const machine_t *); + +/* m_at_misc.c */ +extern int machine_at_vpc2007_init(const machine_t *); /* m_at_t3100e.c */ extern int machine_at_t3100e_init(const machine_t *); @@ -420,22 +712,17 @@ extern int machine_europc_init(const machine_t *); extern const device_t europc_device; #endif -/* m_oivetti_m24.c */ -extern int machine_olim24_init(const machine_t *); +/* m_xt_olivetti.c */ +extern int machine_xt_m24_init(const machine_t *); +extern int machine_xt_m240_init(const machine_t *); +extern int machine_xt_m19_init(const machine_t *); /* m_pcjr.c */ extern int machine_pcjr_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *pcjr_get_device(void); -#endif - /* m_ps1.c */ extern int machine_ps1_m2011_init(const machine_t *); extern int machine_ps1_m2121_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_PS1M2133) -extern int machine_ps1_m2133_init(const machine_t *); -#endif /* m_ps1_hdc.c */ #ifdef EMU_DEVICE_H @@ -444,16 +731,16 @@ extern const device_t ps1_hdc_device; #endif /* m_ps2_isa.c */ -extern int machine_ps2_m30_286_init(const machine_t *); +extern int machine_ps2_m30_286_init(const machine_t *); /* m_ps2_mca.c */ -extern int machine_ps2_model_50_init(const machine_t *); -extern int machine_ps2_model_55sx_init(const machine_t *); -extern int machine_ps2_model_70_type3_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) -extern int machine_ps2_model_70_type4_init(const machine_t *); -#endif -extern int machine_ps2_model_80_init(const machine_t *); +extern int machine_ps2_model_50_init(const machine_t *); +extern int machine_ps2_model_60_init(const machine_t *); +extern int machine_ps2_model_55sx_init(const machine_t *); +extern int machine_ps2_model_65sx_init(const machine_t *); +extern int machine_ps2_model_70_type3_init(const machine_t *); +extern int machine_ps2_model_80_init(const machine_t *); +extern int machine_ps2_model_80_axx_init(const machine_t *); /* m_tandy.c */ extern int tandy1k_eeprom_read(void); @@ -461,10 +748,8 @@ extern int machine_tandy_init(const machine_t *); extern int machine_tandy1000hx_init(const machine_t *); extern int machine_tandy1000sl2_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *tandy1k_get_device(void); -extern const device_t *tandy1k_hx_get_device(void); -#endif +/* m_v86p.c */ +extern int machine_v86p_init(const machine_t *); /* m_xt.c */ extern int machine_pc_init(const machine_t *); @@ -475,16 +760,32 @@ extern int machine_genxt_init(const machine_t *); extern int machine_xt86_init(const machine_t *); +extern int machine_xt_americxt_init(const machine_t *); extern int machine_xt_amixt_init(const machine_t *); extern int machine_xt_dtk_init(const machine_t *); extern int machine_xt_jukopc_init(const machine_t *); -extern int machine_xt_open_xt_init(const machine_t *); +extern int machine_xt_openxt_init(const machine_t *); +extern int machine_xt_pcxt_init(const machine_t *); extern int machine_xt_pxxt_init(const machine_t *); +extern int machine_xt_pc4i_init(const machine_t *); +extern int machine_xt_mpc1600_init(const machine_t *); +extern int machine_xt_pcspirit_init(const machine_t *); +extern int machine_xt_pc700_init(const machine_t *); +extern int machine_xt_pc500_init(const machine_t *); +extern int machine_xt_vendex_init(const machine_t *); +extern int machine_xt_znic_init(const machine_t *); +extern int machine_xt_super16t_init(const machine_t *); +extern int machine_xt_super16te_init(const machine_t *); +extern int machine_xt_top88_init(const machine_t *); +extern int machine_xt_kaypropc_init(const machine_t *); +extern int machine_xt_sansx16_init(const machine_t *); +extern int machine_xt_bw230_init(const machine_t *); -extern int machine_xt_hed919_init(const machine_t *); +extern int machine_xt_iskra3104_init(const machine_t *); /* m_xt_compaq.c */ -extern int machine_xt_compaq_init(const machine_t *); +extern int machine_xt_compaq_deskpro_init(const machine_t *); +extern int machine_xt_compaq_portable_init(const machine_t *); /* m_xt_laserxt.c */ #if defined(DEV_BRANCH) && defined(USE_LASERXT) @@ -492,24 +793,20 @@ extern int machine_xt_laserxt_init(const machine_t *); extern int machine_xt_lxt3_init(const machine_t *); #endif +/* m_xt_philips.c */ +extern int machine_xt_p3105_init(const machine_t *); +extern int machine_xt_p3120_init(const machine_t *); /* m_xt_t1000.c */ extern int machine_xt_t1000_init(const machine_t *); extern int machine_xt_t1200_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *t1000_get_device(void); -extern const device_t *t1200_get_device(void); -#endif /* m_xt_zenith.c */ -extern int machine_xt_zenith_init(const machine_t *); +extern int machine_xt_z184_init(const machine_t *); +extern int machine_xt_z151_init(const machine_t *); +extern int machine_xt_z159_init(const machine_t *); /* m_xt_xi8088.c */ extern int machine_xt_xi8088_init(const machine_t *); -#ifdef EMU_DEVICE_H -extern const device_t *xi8088_get_device(void); -#endif - - #endif /*EMU_MACHINE_H*/ diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h new file mode 100644 index 000000000..2afed078e --- /dev/null +++ b/src/include/86box/machine_status.h @@ -0,0 +1,32 @@ +#ifndef EMU_MACHINE_STATUS_H +#define EMU_MACHINE_STATUS_H + +typedef struct { + atomic_bool_t empty; + atomic_bool_t active; +} dev_status_empty_active_t; + +typedef struct { + atomic_bool_t active; +} dev_status_active_t; + +typedef struct { + atomic_bool_t empty; +} dev_status_empty_t; + +typedef struct { + dev_status_empty_active_t fdd[FDD_NUM]; + dev_status_empty_active_t cdrom[CDROM_NUM]; + dev_status_empty_active_t zip[ZIP_NUM]; + dev_status_empty_active_t mo[MO_NUM]; + dev_status_empty_active_t cassette; + dev_status_active_t hdd[HDD_BUS_USB]; + dev_status_active_t net; + dev_status_empty_t cartridge[2]; +} machine_status_t; + +extern machine_status_t machine_status; + +extern void machine_status_init(); + +#endif /*EMU_MACHINE_STATUS_H*/ \ No newline at end of file diff --git a/src/include/86box/mca.h b/src/include/86box/mca.h index e0def3fe5..f41eda9cf 100644 --- a/src/include/86box/mca.h +++ b/src/include/86box/mca.h @@ -1,9 +1,16 @@ +#ifndef EMU_MCA_H +# define EMU_MCA_H + extern void mca_init(int nr_cards); extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void (*reset)(void *priv), void *priv); extern void mca_set_index(int index); extern uint8_t mca_read(uint16_t port); +extern uint8_t mca_read_index(uint16_t port, int index); extern void mca_write(uint16_t port, uint8_t val); extern uint8_t mca_feedb(void); +extern int mca_get_nr_cards(void); extern void mca_reset(void); -extern void ps2_cache_clean(void); \ No newline at end of file +extern void ps2_cache_clean(void); + +#endif /*EMU_MCA_H*/ diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index a6dfaea32..7aa2fb741 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -18,70 +18,111 @@ * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2016-2020 Miran Grca. */ + #ifndef EMU_MEM_H # define EMU_MEM_H -#define MEM_MAPPING_EXTERNAL 1 /* on external bus (ISA/PCI) */ -#define MEM_MAPPING_INTERNAL 2 /* on internal bus (RAM) */ -#define MEM_MAPPING_ROM 4 /* Executing from ROM may involve - * additional wait states. */ -#define MEM_MAPPING_ROMCS 8 /* respond to ROMCS* */ -#define MEM_MAPPING_SMRAM 16 /* on internal bus (RAM) but SMRAM */ - #define MEM_MAP_TO_SHADOW_RAM_MASK 1 #define MEM_MAP_TO_RAM_ADDR_MASK 2 -/* _mem_state layout: - Bits 0 - 7: Normal write - Bits 8 -15: Normal read - Bits 16 -23: SMM write - Bits 24 -31: SMM read -*/ +#define STATE_CPU 0 +#define STATE_BUS 2 -#define MEM_READ_ANY 0x0000 -#define MEM_READ_INTERNAL 0x0100 -#define MEM_READ_EXTERNAL 0x0200 -#define MEM_READ_DISABLED 0x0300 -#define MEM_READ_NORMAL 0x0400 /* SMM only - means use the non-SMM state */ -#define MEM_READ_EXTERNAL_EX 0x0500 /* External but with internal exec - needed by the VIA Apollo Pro */ -#define MEM_READ_ROMCS 0x0600 /* EXTERNAL type + ROMC flag */ -#define MEM_READ_EXTANY 0x0700 /* Any EXTERNAL type */ -#define MEM_READ_SMRAM 0x1000 -#define MEM_READ_SMRAM_EX 0x2000 -#define MEM_READ_DISABLED_EX 0x4000 -#define MEM_READ_MASK 0xff00 +#define ACCESS_CPU 1 /* Update CPU non-SMM access. */ +#define ACCESS_CPU_SMM 2 /* Update CPU SMM access. */ +#define ACCESS_BUS 4 /* Update bus access. */ +#define ACCESS_BUS_SMM 8 /* Update bus SMM access. */ +#define ACCESS_NORMAL 5 /* Update CPU and bus non-SMM accesses. */ +#define ACCESS_SMM 10 /* Update CPU and bus SMM accesses. */ +#define ACCESS_CPU_BOTH 3 /* Update CPU non-SMM and SMM accesses. */ +#define ACCESS_BUS_BOTH 12 /* Update bus non-SMM and SMM accesses. */ +#define ACCESS_ALL 15 /* Update all accesses. */ -#define MEM_WRITE_ANY 0x0000 -#define MEM_WRITE_INTERNAL 0x0001 -#define MEM_WRITE_EXTERNAL 0x0002 -#define MEM_WRITE_DISABLED 0x0003 -#define MEM_WRITE_NORMAL 0x0004 /* SMM only - means use the non-SMM state */ -#define MEM_WRITE_EXTERNAL_EX 0x0005 -#define MEM_WRITE_ROMCS 0x0006 /* EXTERNAL type + ROMC flag */ -#define MEM_WRITE_EXTANY 0x0007 /* Any EXTERNAL type */ -#define MEM_WRITE_SMRAM 0x0010 -#define MEM_WRITE_SMRAM_EX 0x0020 -#define MEM_WRITE_DISABLED_EX 0x0040 -#define MEM_WRITE_MASK 0x00ff +#define ACCESS_INTERNAL 1 +#define ACCESS_ROMCS 2 +#define ACCESS_SMRAM 4 +#define ACCESS_CACHE 8 +#define ACCESS_DISABLED 16 -#define MEM_STATE_SMM_SHIFT 16 +#define ACCESS_X_INTERNAL 1 +#define ACCESS_X_ROMCS 2 +#define ACCESS_X_SMRAM 4 +#define ACCESS_X_CACHE 8 +#define ACCESS_X_DISABLED 16 +#define ACCESS_W_INTERNAL 32 +#define ACCESS_W_ROMCS 64 +#define ACCESS_W_SMRAM 128 +#define ACCESS_W_CACHE 256 +#define ACCESS_W_DISABLED 512 +#define ACCESS_R_INTERNAL 1024 +#define ACCESS_R_ROMCS 2048 +#define ACCESS_R_SMRAM 4096 +#define ACCESS_R_CACHE 8192 +#define ACCESS_R_DISABLED 16384 -/* #define's for memory granularity, currently 16k, but may - change in the future - 4k works, less does not because of - internal 4k pages. */ -#ifdef DEFAULT_GRANULARITY -#define MEM_GRANULARITY_BITS 14 -#define MEM_GRANULARITY_SIZE (1 << MEM_GRANULARITY_BITS) -#define MEM_GRANULARITY_HBOUND (MEM_GRANULARITY_SIZE - 2) -#define MEM_GRANULARITY_QBOUND (MEM_GRANULARITY_SIZE - 4) -#define MEM_GRANULARITY_MASK (MEM_GRANULARITY_SIZE - 1) -#define MEM_GRANULARITY_HMASK ((1 << (MEM_GRANULARITY_BITS - 1)) - 1) -#define MEM_GRANULARITY_QMASK ((1 << (MEM_GRANULARITY_BITS - 2)) - 1) -#define MEM_GRANULARITY_PMASK ((1 << (MEM_GRANULARITY_BITS - 3)) - 1) -#define MEM_MAPPINGS_NO ((0x100000 >> MEM_GRANULARITY_BITS) << 12) -#define MEM_GRANULARITY_PAGE (MEM_GRANULARITY_MASK & ~0xfff) -#else +#define ACCESS_EXECUTE 0 +#define ACCESS_READ 1 +#define ACCESS_WRITE 2 + +#define ACCESS_SMRAM_OFF 0 +#define ACCESS_SMRAM_X 1 +#define ACCESS_SMRAM_W 2 +#define ACCESS_SMRAM_WX 3 +#define ACCESS_SMRAM_R 4 +#define ACCESS_SMRAM_RX 5 +#define ACCESS_SMRAM_RW 6 +#define ACCESS_SMRAM_RWX 7 + +/* Conversion #define's - we need these to seamlessly convert the old mem_set_mem_state() calls to + the new stuff in order to make this a drop in replacement. + + Read here includes execute access since the old code also used read access for execute access, + with some exceptions. */ + +#define MEM_READ_DISABLED (ACCESS_X_DISABLED | ACCESS_R_DISABLED) +#define MEM_READ_INTERNAL (ACCESS_X_INTERNAL | ACCESS_R_INTERNAL) +#define MEM_READ_EXTERNAL 0 +/* These two are going to be identical - on real hardware, chips that don't care about ROMCS#, + are not magically disabled. */ +#define MEM_READ_ROMCS (ACCESS_X_ROMCS | ACCESS_R_ROMCS) +#define MEM_READ_EXTANY MEM_READ_ROMCS +/* Internal execute access, external read access. */ +#define MEM_READ_EXTERNAL_EX 0 +#define MEM_READ_SMRAM (ACCESS_X_SMRAM | ACCESS_R_SMRAM) +#define MEM_READ_CACHE (ACCESS_X_CACHE | ACCESS_R_CACHE) +#define MEM_READ_SMRAM_EX (ACCESS_X_SMRAM) +#define MEM_EXEC_SMRAM MEM_READ_SMRAM_EX +#define MEM_READ_SMRAM_2 (ACCESS_R_SMRAM) +/* Theese two are going to be identical. */ +#define MEM_READ_DISABLED_EX MEM_READ_DISABLED +#define MEM_READ_MASK 0x7c1f + +#define MEM_WRITE_DISABLED (ACCESS_W_DISABLED) +#define MEM_WRITE_INTERNAL (ACCESS_W_INTERNAL) +#define MEM_WRITE_EXTERNAL 0 +/* These two are going to be identical - on real hardware, chips that don't care about ROMCS#, + are not magically disabled. */ +#define MEM_WRITE_ROMCS (ACCESS_W_ROMCS) +#define MEM_WRITE_EXTANY (ACCESS_W_ROMCS) +#define MEM_WRITE_SMRAM (ACCESS_W_SMRAM) +#define MEM_WRITE_CACHE (ACCESS_W_CACHE) +/* Theese two are going to be identical. */ +#define MEM_WRITE_DISABLED_EX MEM_READ_DISABLED +#define MEM_WRITE_MASK 0x03e0 + +#define MEM_MAPPING_EXTERNAL 1 /* On external bus (ISA/PCI). */ +#define MEM_MAPPING_INTERNAL 2 /* On internal bus (RAM). */ +#define MEM_MAPPING_ROM_WS 4 /* Executing from ROM may involve additional wait states. */ +#define MEM_MAPPING_IS_ROM 8 /* Responds to ROMCS#. */ +#define MEM_MAPPING_ROM (MEM_MAPPING_ROM_WS | MEM_MAPPING_IS_ROM) +#define MEM_MAPPING_ROMCS 16 /* If it responds to ROMCS#, it requires ROMCS# asserted. */ +#define MEM_MAPPING_SMRAM 32 /* On internal bus (RAM) but SMRAM. */ +#define MEM_MAPPING_CACHE 64 /* Cache or MTRR - please avoid such mappings unless + stricly necessary (eg. for CoreBoot). */ + +/* #define's for memory granularity, currently 4k, less does + not work because of internal 4k pages. */ #define MEM_GRANULARITY_BITS 12 #define MEM_GRANULARITY_SIZE (1 << MEM_GRANULARITY_BITS) #define MEM_GRANULARITY_HBOUND (MEM_GRANULARITY_SIZE - 2) @@ -92,16 +133,47 @@ #define MEM_GRANULARITY_PMASK ((1 << (MEM_GRANULARITY_BITS - 3)) - 1) #define MEM_MAPPINGS_NO ((0x100000 >> MEM_GRANULARITY_BITS) << 12) #define MEM_GRANULARITY_PAGE (MEM_GRANULARITY_MASK & ~0xfff) -#endif +#define MEM_GRANULARITY_BASE (~MEM_GRANULARITY_MASK) -#define mem_set_mem_state_common(smm, base, size, state) mem_set_state(!!smm, 0, base, size, state) -#define mem_set_mem_state(base, size, state) mem_set_state(0, 0, base, size, state) -#define mem_set_mem_state_smm(base, size, state) mem_set_state(1, 0, base, size, state) -#define mem_set_mem_state_both(base, size, state) mem_set_state(2, 0, base, size, state) -#define mem_set_mem_state_smram(smm, base, size, is_smram) mem_set_state(!!smm, 1, base, size, is_smram) -#define mem_set_mem_state_smram_ex(smm, base, size, is_smram) mem_set_state(!!smm, 2, base, size, is_smram) +/* Compatibility #defines. */ +#define mem_set_state(smm, mode, base, size, access) \ + mem_set_access((smm ? ACCESS_SMM : ACCESS_NORMAL), mode, base, size, access) +#define mem_set_mem_state_common(smm, base, size, access) \ + mem_set_access((smm ? ACCESS_SMM : ACCESS_NORMAL), 0, base, size, access) +#define mem_set_mem_state(base, size, access) \ + mem_set_access(ACCESS_NORMAL, 0, base, size, access) +#define mem_set_mem_state_smm(base, size, access) \ + mem_set_access(ACCESS_SMM, 0, base, size, access) +#define mem_set_mem_state_both(base, size, access) \ + mem_set_access(ACCESS_ALL, 0, base, size, access) +#define mem_set_mem_state_cpu_both(base, size, access) \ + mem_set_access(ACCESS_CPU_BOTH, 0, base, size, access) +#define mem_set_mem_state_bus_both(base, size, access) \ + mem_set_access(ACCESS_BUS_BOTH, 0, base, size, access) +#define mem_set_mem_state_smram(smm, base, size, is_smram) \ + mem_set_access((smm ? ACCESS_SMM : ACCESS_NORMAL), 1, base, size, is_smram) +#define mem_set_mem_state_smram_ex(smm, base, size, is_smram) \ + mem_set_access((smm ? ACCESS_SMM : ACCESS_NORMAL), 2, base, size, is_smram) +#define mem_set_access_smram_cpu(smm, base, size, is_smram) \ + mem_set_access((smm ? ACCESS_CPU_SMM : ACCESS_CPU), 1, base, size, is_smram) +#define mem_set_access_smram_bus(smm, base, size, is_smram) \ + mem_set_access((smm ? ACCESS_BUS_SMM : ACCESS_BUS), 1, base, size, is_smram) +#define flushmmucache_cr3 \ + flushmmucache_nopc +typedef struct { + uint16_t x :5, + w :5, + r :5, + pad :1; +} state_t; + +typedef union { + uint16_t vals[4]; + state_t states[4]; +} mem_state_t; + typedef struct _mem_mapping_ { struct _mem_mapping_ *prev, *next; @@ -110,6 +182,8 @@ typedef struct _mem_mapping_ { uint32_t base; uint32_t size; + uint32_t mask; + uint8_t (*read_b)(uint32_t addr, void *priv); uint16_t (*read_w)(uint32_t addr, void *priv); uint32_t (*read_l)(uint32_t addr, void *priv); @@ -121,9 +195,9 @@ typedef struct _mem_mapping_ { uint32_t flags; - void *p; /* backpointer to mapping or device */ - - void *dev; /* backpointer to memory device */ + /* There is never a needed to pass a pointer to the mapping itself, it is much preferable to + prepare a structure with the requires data (usually, the base address and mask) instead. */ + void *p; /* backpointer to device */ } mem_mapping_t; #ifdef USE_NEW_DYNAREC @@ -183,39 +257,30 @@ typedef struct _page_ { #endif -typedef struct -{ - uint32_t size, - host_base, - ram_base; -} smram_t; - - extern uint8_t *ram, *ram2; extern uint32_t rammask; extern uint8_t *rom; extern uint32_t biosmask, biosaddr; -extern int readlookup[256], - readlookupp[256]; +extern int readlookup[256]; extern uintptr_t * readlookup2; +extern uintptr_t old_rl2; +extern uint8_t uncached; extern int readlnext; -extern int writelookup[256], - writelookupp[256]; -extern uintptr_t *writelookup2; +extern int writelookup[256]; +extern uintptr_t * writelookup2; extern int writelnext; extern uint32_t ram_mapped_addr[64]; +extern uint8_t page_ff[4096]; -extern mem_mapping_t base_mapping, - ram_low_mapping, +extern mem_mapping_t ram_low_mapping, #if 1 ram_mid_mapping, #endif ram_remapped_mapping, ram_high_mapping, ram_2gb_mapping, - ram_smram_mapping[2], bios_mapping, bios_high_mapping; @@ -225,7 +290,6 @@ extern page_t *pages, **page_lookup; extern uint32_t get_phys_virt, get_phys_phys; -extern smram_t smram[2]; extern int shadowbios, shadowbios_write; @@ -234,39 +298,38 @@ extern int readlnum, extern int memspeed[11]; -extern int mmu_perm, - use_phys_exec; +extern int mmu_perm; +extern uint8_t high_page; /* if a high (> 4 gb) page was detected */ + +extern uint32_t pages_sz; /* #pages in table */ extern int mem_a20_state, mem_a20_alt, mem_a20_key; -#ifndef USE_NEW_DYNAREC -#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) -#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +extern uint8_t read_mem_b(uint32_t addr); +extern uint16_t read_mem_w(uint32_t addr); +extern void write_mem_b(uint32_t addr, uint8_t val); +extern void write_mem_w(uint32_t addr, uint16_t val); extern uint8_t readmembl(uint32_t addr); extern void writemembl(uint32_t addr, uint8_t val); -extern uint8_t readmemb386l(uint32_t seg, uint32_t addr); -extern void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); -extern uint16_t readmemwl(uint32_t seg, uint32_t addr); -extern void writememwl(uint32_t seg, uint32_t addr, uint16_t val); -extern uint32_t readmemll(uint32_t seg, uint32_t addr); -extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); -extern uint64_t readmemql(uint32_t seg, uint32_t addr); -extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); -#else -uint8_t readmembl(uint32_t addr); -void writemembl(uint32_t addr, uint8_t val); -uint16_t readmemwl(uint32_t addr); -void writememwl(uint32_t addr, uint16_t val); -uint32_t readmemll(uint32_t addr); -void writememll(uint32_t addr, uint32_t val); -uint64_t readmemql(uint32_t addr); -void writememql(uint32_t addr, uint64_t val); -#endif +extern uint16_t readmemwl(uint32_t addr); +extern void writememwl(uint32_t addr, uint16_t val); +extern uint32_t readmemll(uint32_t addr); +extern void writememll(uint32_t addr, uint32_t val); +extern uint64_t readmemql(uint32_t addr); +extern void writememql(uint32_t addr, uint64_t val); + +extern uint8_t readmembl_no_mmut(uint32_t addr, uint32_t a64); +extern void writemembl_no_mmut(uint32_t addr, uint32_t a64, uint8_t val); +extern uint16_t readmemwl_no_mmut(uint32_t addr, uint32_t *a64); +extern void writememwl_no_mmut(uint32_t addr, uint32_t *a64, uint16_t val); +extern uint32_t readmemll_no_mmut(uint32_t addr, uint32_t *a64); +extern void writememll_no_mmut(uint32_t addr, uint32_t *a64, uint32_t val); + +extern void do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write); extern uint8_t *getpccache(uint32_t a); extern uint64_t mmutranslatereal(uint32_t addr, int rw); @@ -274,11 +337,21 @@ extern uint32_t mmutranslatereal32(uint32_t addr, int rw); extern void addreadlookup(uint32_t virt, uint32_t phys); extern void addwritelookup(uint32_t virt, uint32_t phys); -extern void mem_mapping_del(mem_mapping_t *); - +extern void mem_mapping_set(mem_mapping_t *, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p); extern void mem_mapping_add(mem_mapping_t *, - uint32_t base, - uint32_t size, + uint32_t base, + uint32_t size, uint8_t (*read_b)(uint32_t addr, void *p), uint16_t (*read_w)(uint32_t addr, void *p), uint32_t (*read_l)(uint32_t addr, void *p), @@ -299,16 +372,15 @@ extern void mem_mapping_set_handler(mem_mapping_t *, extern void mem_mapping_set_p(mem_mapping_t *, void *p); -extern void mem_mapping_set_dev(mem_mapping_t *, void *dev); - extern void mem_mapping_set_addr(mem_mapping_t *, uint32_t base, uint32_t size); extern void mem_mapping_set_exec(mem_mapping_t *, uint8_t *exec); +extern void mem_mapping_set_mask(mem_mapping_t *, uint32_t mask); extern void mem_mapping_disable(mem_mapping_t *); extern void mem_mapping_enable(mem_mapping_t *); extern void mem_mapping_recalc(uint64_t base, uint64_t size); -extern void mem_set_state(int smm, int mode, uint32_t base, uint32_t size, uint32_t state); +extern void mem_set_access(uint8_t bitmap, int mode, uint32_t base, uint32_t size, uint16_t access); extern uint8_t mem_readb_phys(uint32_t addr); extern uint16_t mem_readw_phys(uint32_t addr); @@ -326,20 +398,12 @@ extern void mem_write_ram(uint32_t addr, uint8_t val, void *priv); extern void mem_write_ramw(uint32_t addr, uint16_t val, void *priv); extern void mem_write_raml(uint32_t addr, uint32_t val, void *priv); -extern uint8_t mem_read_smram(uint32_t addr, void *priv); -extern uint16_t mem_read_smramw(uint32_t addr, void *priv); -extern uint32_t mem_read_smraml(uint32_t addr, void *priv); -extern void mem_write_smram(uint32_t addr, uint8_t val, void *priv); -extern void mem_write_smramw(uint32_t addr, uint16_t val, void *priv); -extern void mem_write_smraml(uint32_t addr, uint32_t val, void *priv); - -extern uint8_t mem_read_bios(uint32_t addr, void *priv); -extern uint16_t mem_read_biosw(uint32_t addr, void *priv); -extern uint32_t mem_read_biosl(uint32_t addr, void *priv); - -extern void mem_write_null(uint32_t addr, uint8_t val, void *p); -extern void mem_write_nullw(uint32_t addr, uint16_t val, void *p); -extern void mem_write_nulll(uint32_t addr, uint32_t val, void *p); +extern uint8_t mem_read_ram_2gb(uint32_t addr, void *priv); +extern uint16_t mem_read_ram_2gbw(uint32_t addr, void *priv); +extern uint32_t mem_read_ram_2gbl(uint32_t addr, void *priv); +extern void mem_write_ram_2gb(uint32_t addr, uint8_t val, void *priv); +extern void mem_write_ram_2gbw(uint32_t addr, uint16_t val, void *priv); +extern void mem_write_ram_2gbl(uint32_t addr, uint32_t val, void *priv); extern int mem_addr_is_ram(uint32_t addr); @@ -355,18 +419,14 @@ extern void mem_flush_write_page(uint32_t addr, uint32_t virt); extern void mem_reset_page_blocks(void); extern void flushmmucache(void); -extern void flushmmucache_cr3(void); extern void flushmmucache_nopc(void); extern void mmu_invalidate(uint32_t addr); extern void mem_a20_init(void); extern void mem_a20_recalc(void); -extern void mem_add_upper_bios(void); -extern void mem_add_bios(void); - extern void mem_init(void); - +extern void mem_close(void); extern void mem_reset(void); extern void mem_remap_top(int kb); @@ -384,7 +444,7 @@ static __inline uint32_t get_phys(uint32_t addr) return get_phys_phys | (addr & 0xfff); get_phys_virt = addr; - + if (!(cr0 >> 31)) { get_phys_phys = (addr & rammask) & ~0xfff; return addr & rammask; diff --git a/src/include/86box/midi.h b/src/include/86box/midi.h index a41f369da..01ec88881 100644 --- a/src/include/86box/midi.h +++ b/src/include/86box/midi.h @@ -1,110 +1,104 @@ #ifndef EMU_SOUND_MIDI_H -# define EMU_SOUND_MIDI_H - +#define EMU_SOUND_MIDI_H #define SYSEX_SIZE 8192 extern uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; extern uint8_t MIDI_evt_len[256]; -extern int midi_device_current; +extern int midi_output_device_current; extern int midi_input_device_current; -extern void (*input_msg)(void *p, uint8_t *msg); +extern void (*input_msg)(void *p, uint8_t *msg, uint32_t len); extern int (*input_sysex)(void *p, uint8_t *buf, uint32_t len, int abort); extern void *midi_in_p; -int midi_device_available(int card); -int midi_in_device_available(int card); -char *midi_device_getname(int card); -char *midi_in_device_getname(int card); +extern int midi_out_device_available(int card); +extern int midi_in_device_available(int card); #ifdef EMU_DEVICE_H -const device_t *midi_device_getdevice(int card); +const device_t *midi_out_device_getdevice(int card); const device_t *midi_in_device_getdevice(int card); #endif -int midi_device_has_config(int card); -int midi_in_device_has_config(int card); -char *midi_device_get_internal_name(int card); -char *midi_in_device_get_internal_name(int card); -int midi_device_get_from_internal_name(char *s); -int midi_in_device_get_from_internal_name(char *s); -void midi_device_init(); -void midi_in_device_init(); +extern int midi_out_device_has_config(int card); +extern int midi_in_device_has_config(int card); +extern char *midi_out_device_get_internal_name(int card); +extern char *midi_in_device_get_internal_name(int card); +extern int midi_out_device_get_from_internal_name(char *s); +extern int midi_in_device_get_from_internal_name(char *s); +extern void midi_out_device_init(); +extern void midi_in_device_init(); - -typedef struct midi_device_t -{ +typedef struct midi_device_t { void (*play_sysex)(uint8_t *sysex, unsigned int len); void (*play_msg)(uint8_t *msg); void (*poll)(); int (*write)(uint8_t val); } midi_device_t; -typedef struct midi_in_handler_t -{ +typedef struct midi_in_handler_t { uint8_t *buf; - int cnt; + int cnt; uint32_t len; - void (*msg)(void *p, uint8_t *msg); + void (*msg)(void *p, uint8_t *msg, uint32_t len); int (*sysex)(void *p, uint8_t *buffer, uint32_t len, int abort); struct midi_in_handler_t *p; struct midi_in_handler_t *prev, *next; } midi_in_handler_t; -typedef struct midi_t -{ +typedef struct midi_t { uint8_t midi_rt_buf[8], midi_cmd_buf[8], - midi_status, midi_sysex_data[SYSEX_SIZE]; + midi_status, midi_sysex_data[SYSEX_SIZE]; int midi_cmd_pos, midi_cmd_len, midi_cmd_r, - midi_realtime, thruchan, midi_clockout; + midi_realtime, thruchan, midi_clockout; unsigned int midi_sysex_start, midi_sysex_delay, - midi_pos; - midi_device_t *m_out_device, *m_in_device; + midi_pos; + midi_device_t *m_out_device, *m_in_device; } midi_t; -extern midi_t *midi, *midi_in; +extern midi_t *midi_out, *midi_in; -extern void midi_init(midi_device_t* device); -extern void midi_in_init(midi_device_t* device, midi_t **mididev); -extern void midi_close(); -extern void midi_in_close(void); -extern void midi_raw_out_rt_byte(uint8_t val); -extern void midi_raw_out_thru_rt_byte(uint8_t val); -extern void midi_raw_out_byte(uint8_t val); -extern void midi_clear_buffer(void); -extern void midi_poll(); +extern void midi_out_init(midi_device_t *device); +extern void midi_in_init(midi_device_t *device, midi_t **mididev); +extern void midi_out_close(); +extern void midi_in_close(void); +extern void midi_raw_out_rt_byte(uint8_t val); +extern void midi_raw_out_thru_rt_byte(uint8_t val); +extern void midi_raw_out_byte(uint8_t val); +extern void midi_clear_buffer(void); +extern void midi_poll(); -extern void midi_in_handler(int set, void (*msg)(void *p, uint8_t *msg), int (*sysex)(void *p, uint8_t *buffer, uint32_t len, int abort), void *p); -extern void midi_in_handlers_clear(void); -extern void midi_in_msg(uint8_t *msg); -extern void midi_in_sysex(uint8_t *buffer, uint32_t len); +extern void midi_in_handler(int set, void (*msg)(void *p, uint8_t *msg, uint32_t len), int (*sysex)(void *p, uint8_t *buffer, uint32_t len, int abort), void *p); +extern void midi_in_handlers_clear(void); +extern void midi_in_msg(uint8_t *msg, uint32_t len); +extern void midi_in_sysex(uint8_t *buffer, uint32_t len); #if 0 -#ifdef _WIN32 -#define SYSTEM_MIDI_NAME "Windows MIDI" -#define SYSTEM_MIDI_INTERNAL_NAME "windows_midi" +# ifdef _WIN32 +# define SYSTEM_MIDI_NAME "Windows MIDI" +# define SYSTEM_MIDI_INTERNAL_NAME "windows_midi" +# else +# define SYSTEM_MIDI_NAME "System MIDI" +# define SYSTEM_MIDI_INTERNAL_NAME "system_midi" +# endif #else -#define SYSTEM_MIDI_NAME "System MIDI" -#define SYSTEM_MIDI_INTERNAL_NAME "system_midi" -#endif -#else -#define SYSTEM_MIDI_NAME "System MIDI" -#define SYSTEM_MIDI_INTERNAL_NAME "system_midi" +# define SYSTEM_MIDI_NAME "System MIDI" +# define SYSTEM_MIDI_INTERNAL_NAME "system_midi" #endif -#define MIDI_INPUT_NAME "MIDI Input Device" +#define MIDI_INPUT_NAME "MIDI Input Device" #define MIDI_INPUT_INTERNAL_NAME "midi_in" #ifdef EMU_DEVICE_H -extern const device_t system_midi_device; -#ifdef USE_FLUIDSYNTH +extern const device_t rtmidi_output_device; +extern const device_t rtmidi_input_device; +# ifdef USE_FLUIDSYNTH extern const device_t fluidsynth_device; -#endif -#ifdef USE_MUNT +# endif +# ifdef USE_MUNT extern const device_t mt32_device; extern const device_t cm32l_device; -#endif +# endif #endif -#endif /*EMU_SOUND_MIDI_H*/ +#endif /*EMU_SOUND_MIDI_H*/ diff --git a/src/include/86box/midi_input.h b/src/include/86box/midi_input.h deleted file mode 100644 index 163d6fa91..000000000 --- a/src/include/86box/midi_input.h +++ /dev/null @@ -1 +0,0 @@ -extern const device_t midi_input_device; diff --git a/src/include/86box/midi_rtmidi.h b/src/include/86box/midi_rtmidi.h new file mode 100644 index 000000000..fb2074302 --- /dev/null +++ b/src/include/86box/midi_rtmidi.h @@ -0,0 +1,17 @@ +#ifndef EMU_SOUND_RTMIDI_H +#define EMU_SOUND_RTMIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtmidi_out_get_num_devs(void); +extern void rtmidi_out_get_dev_name(int num, char *s); +extern int rtmidi_in_get_num_devs(void); +extern void rtmidi_in_get_dev_name(int num, char *s); + +#ifdef __cplusplus +} +#endif + +#endif /*EMU_SOUND_RTMIDI*/ diff --git a/src/include/86box/midi_system.h b/src/include/86box/midi_system.h deleted file mode 100644 index b79bbf96f..000000000 --- a/src/include/86box/midi_system.h +++ /dev/null @@ -1 +0,0 @@ -extern const device_t system_midi_device; diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 39587394d..7d0eed904 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -17,9 +17,9 @@ * * Copyright 2020 Miran Grca. */ -#ifndef EMU_MO_H -#define EMU_MO_H +#ifndef EMU_MO_H +# define EMU_MO_H #define MO_NUM 4 @@ -31,35 +31,34 @@ typedef struct { uint32_t sectors; uint16_t bytes_per_sector; - int64_t disk_size; - char name[255]; } mo_type_t; #define KNOWN_MO_TYPES 10 static const mo_type_t mo_types[KNOWN_MO_TYPES] = { // 3.5" standard M.O. disks - { 248826, 512, 127398912, "3.5\" 128Mb M.O. (ISO 10090)" }, - { 446325, 512, 228518400, "3.5\" 230Mb M.O. (ISO 13963)" }, - { 1041500, 512, 533248000, "3.5\" 540Mb M.O. (ISO 15498)" }, - { 310352, 2048, 635600896, "3.5\" 640Mb M.O. (ISO 15498)" }, - { 605846, 2048, 1240772608, "3.5\" 1.3Gb M.O. (GigaMO)" }, - { 1063146, 2048, 2177323008, "3.5\" 2.3Gb M.O. (GigaMO 2)" }, + { 248826, 512 }, + { 446325, 512 }, + { 1041500, 512 }, + { 310352, 2048 }, + { 605846, 2048 }, + { 1063146, 2048 }, // 5.25" M.O. disks - {573624, 512, 293695488, "5.25\" 600Mb M.O."}, - {314568, 1024, 322117632, "5.25\" 650Mb M.O."}, - {904995, 512, 463357440, "5.25\" 1Gb M.O."}, - {637041, 1024, 652329984, "5.25\" 1.3Gb M.O."}, + {573624, 512 }, + {314568, 1024 }, + {904995, 512 }, + {637041, 1024 }, }; typedef struct { - char vendor[8]; - char model[16]; - char revision[4]; + const char vendor[9]; + const char model[16]; + const char revision[5]; int8_t supported_media[KNOWN_MO_TYPES]; } mo_drive_type_t; -static const mo_drive_type_t mo_drive_types[22] = { +#define KNOWN_MO_DRIVE_TYPES 22 +static const mo_drive_type_t mo_drive_types[KNOWN_MO_DRIVE_TYPES] = { {"86BOX", "MAGNETO OPTICAL", "1.00",{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {"FUJITSU", "M2512A", "1314",{1, 1, 0, 0, 0, 0, 0, 0, 0}}, {"FUJITSU", "M2513-MCC3064SS", "1.00",{1, 1, 1, 1, 0, 0, 0, 0, 0, 0}}, @@ -86,66 +85,65 @@ static const mo_drive_type_t mo_drive_types[22] = { enum { MO_BUS_DISABLED = 0, - MO_BUS_ATAPI = 4, + MO_BUS_ATAPI = 5, MO_BUS_SCSI, MO_BUS_USB }; typedef struct { - uint8_t id, - res, res0, /* Reserved for other ID's. */ - res1, - ide_channel, scsi_device_id, - bus_type, /* 0 = ATAPI, 1 = SCSI */ + uint8_t id; + + union { + uint8_t res, res0, /* Reserved for other ID's. */ + res1, + ide_channel, scsi_device_id; + }; + + uint8_t bus_type, /* 0 = ATAPI, 1 = SCSI */ bus_mode, /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ read_only, /* Struct variable reserved for media status. */ pad, pad0; - uint32_t medium_size, - base; - uint16_t sector_size; - uint8_t type; - + FILE *f; void *priv; - FILE *f; - - wchar_t image_path[1024], + char image_path[1024], prev_image_path[1024]; + + uint32_t type, medium_size, + base; + uint16_t sector_size; + } mo_drive_t; typedef struct { - uint8_t id, - error, status, - phase, - features, - is_dma, - do_page_save, - unit_attention; + mode_sense_pages_t ms_pages_saved; - mo_drive_t *drv; + mo_drive_t *drv; - uint16_t request_length, - max_transfer_len; + uint8_t *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; - int requested_blocks, packet_status, - request_pos, old_len, - total_length; + uint8_t status, phase, + error, id, + features, cur_lun, + pad0, pad1; - uint32_t sector_pos, sector_len, - packet_len, pos, - seek_pos; + uint16_t request_length, max_transfer_len; - double callback; + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention, request_pos, + old_len, pad3; - mode_sense_pages_t ms_pages_saved; + uint32_t sector_pos, sector_len, + packet_len, pos; - uint8_t *buffer, - atapi_cdb[16], - current_cdb[16], - sense[256]; + double callback; } mo_t; @@ -172,7 +170,7 @@ extern void mo_global_init(void); extern void mo_hard_reset(void); extern void mo_reset(scsi_common_t *sc); -extern int mo_load(mo_t *dev, wchar_t *fn); +extern int mo_load(mo_t *dev, char *fn); extern void mo_close(); #ifdef __cplusplus diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index a3e192c46..a5519139a 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -16,10 +16,10 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ + #ifndef EMU_MOUSE_H # define EMU_MOUSE_H - #define MOUSE_TYPE_NONE 0 /* no mouse configured */ #define MOUSE_TYPE_INTERNAL 1 /* machine has internal mouse */ #define MOUSE_TYPE_LOGIBUS 2 /* Logitech/ATI Bus Mouse */ diff --git a/src/include/86box/net_3c503.h b/src/include/86box/net_3c503.h index 6cc656b9f..4f3a2b20e 100644 --- a/src/include/86box/net_3c503.h +++ b/src/include/86box/net_3c503.h @@ -3,5 +3,4 @@ extern const device_t threec503_device; - #endif /*NET_3C503_H*/ diff --git a/src/include/86box/net_dp8390.h b/src/include/86box/net_dp8390.h index 02c9763fa..027bce576 100644 --- a/src/include/86box/net_dp8390.h +++ b/src/include/86box/net_dp8390.h @@ -16,6 +16,7 @@ * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Bochs project. */ + #ifndef NET_DP8390_H # define NET_DP8390_H @@ -180,7 +181,7 @@ typedef struct { int mem_size, mem_start, mem_end; int tx_timer_index; - int tx_timer_active; + int tx_timer_active; void *priv; @@ -196,7 +197,7 @@ extern void dp8390_chipmem_write(dp8390_t *dev, uint32_t addr, uint32_t val, uns extern uint32_t dp8390_read_cr(dp8390_t *dev); extern void dp8390_write_cr(dp8390_t *dev, uint32_t val); -extern void dp8390_rx(void *priv, uint8_t *buf, int io_len); +extern int dp8390_rx(void *priv, uint8_t *buf, int io_len); extern uint32_t dp8390_page0_read(dp8390_t *dev, uint32_t off, unsigned int len); extern void dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); diff --git a/src/include/86box/net_ne2000.h b/src/include/86box/net_ne2000.h index c7e466080..23870b989 100644 --- a/src/include/86box/net_ne2000.h +++ b/src/include/86box/net_ne2000.h @@ -32,6 +32,7 @@ * Boston, MA 02111-1307 * USA. */ + #ifndef NET_NE2000_H # define NET_NE2000_H @@ -40,7 +41,7 @@ enum { NE2K_NONE = 0, NE2K_NE1000 = 1, /* 8-bit ISA NE1000 */ NE2K_NE2000 = 2, /* 16-bit ISA NE2000 */ - NE2K_ETHERNEXT_MC = 3, /* 16-bit MCA EtherNext/MC */ + NE2K_ETHERNEXT_MC = 3, /* 16-bit MCA EtherNext/MC */ NE2K_RTL8019AS = 4, /* 16-bit ISA PnP Realtek 8019AS */ NE2K_RTL8029AS = 5 /* 32-bit PCI Realtek 8029AS */ }; diff --git a/src/include/86box/net_pcnet.h b/src/include/86box/net_pcnet.h index cab123c83..e6ae84eff 100644 --- a/src/include/86box/net_pcnet.h +++ b/src/include/86box/net_pcnet.h @@ -16,6 +16,7 @@ * Copyright 2004-2019 Antony T Curtis * Copyright 2016-2019 Miran Grca. */ + #ifndef NET_PCNET_H # define NET_PCNET_H @@ -24,14 +25,16 @@ enum { DEV_AM79C960 = 1, /* PCnet-ISA (ISA, 10 Mbps, NE2100/NE1500T compatible) */ DEV_AM79C960_EB = 2, /* PCnet-ISA (ISA, 10 Mbps, Racal InterLan EtherBlaster compatible) */ DEV_AM79C960_VLB = 3, /* PCnet-VLB (VLB, 10 Mbps, NE2100/NE1500T compatible) */ - DEV_AM79C970A = 4, /* PCnet-PCI II (PCI, 10 Mbps) */ - DEV_AM79C973 = 5 /* PCnet-FAST III (PCI, 10/100 Mbps) */ + DEV_AM79C961 = 4, /* PCnet-ISA+ (ISA, 10 Mbps, NE2100/NE1500T compatible, Plug and Play) */ + DEV_AM79C970A = 5, /* PCnet-PCI II (PCI, 10 Mbps) */ + DEV_AM79C973 = 6 /* PCnet-FAST III (PCI, 10/100 Mbps) */ }; extern const device_t pcnet_am79c960_device; extern const device_t pcnet_am79c960_eb_device; extern const device_t pcnet_am79c960_vlb_device; +extern const device_t pcnet_am79c961_device; extern const device_t pcnet_am79c970a_device; extern const device_t pcnet_am79c973_device; diff --git a/src/include/86box/net_plip.h b/src/include/86box/net_plip.h new file mode 100644 index 000000000..69cb80da0 --- /dev/null +++ b/src/include/86box/net_plip.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Definitions for the PLIP parallel port network device. + * + * + * + * Author: RichardG, + * Copyright 2020 RichardG. + */ + +#ifndef NET_PLIP_H +# define NET_PLIP_H +# include <86box/device.h> +# include <86box/lpt.h> + +extern const lpt_device_t lpt_plip_device; +extern const device_t plip_device; + +#endif /*NET_PLIP_H*/ diff --git a/src/include/86box/net_wd8003.h b/src/include/86box/net_wd8003.h index 5b6e2113e..08bd901fe 100644 --- a/src/include/86box/net_wd8003.h +++ b/src/include/86box/net_wd8003.h @@ -40,6 +40,7 @@ * Boston, MA 02111-1307 * USA. */ + #ifndef NET_WD8003_H # define NET_WD8003_H @@ -49,7 +50,8 @@ enum { WD8003EB, /* WD8003EB : 8-bit ISA, 5x3 interface chip */ WD8013EBT, /* WD8013EBT : 16-bit ISA, no interface chip */ WD8003ETA, /* WD8003ET/A: 16-bit MCA, no interface chip */ - WD8003EA /* WD8003E/A : 16-bit MCA, 5x3 interface chip */ + WD8003EA, /* WD8003E/A : 16-bit MCA, 5x3 interface chip */ + WD8013EPA }; extern const device_t wd8003e_device; @@ -57,5 +59,6 @@ extern const device_t wd8003eb_device; extern const device_t wd8013ebt_device; extern const device_t wd8003eta_device; extern const device_t wd8003ea_device; +extern const device_t wd8013epa_device; #endif /*NET_WD8003_H*/ diff --git a/src/include/86box/network.h b/src/include/86box/network.h index f4e653a33..8e23e671f 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -44,6 +44,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef EMU_NETWORK_H # define EMU_NETWORK_H # include @@ -64,7 +65,7 @@ enum { }; -typedef void (*NETRXCB)(void *, uint8_t *, int); +typedef int (*NETRXCB)(void *, uint8_t *, int); typedef int (*NETWAITCB)(void *); typedef int (*NETSETLINKSTATE)(void *); @@ -78,8 +79,6 @@ typedef struct netpkt { } netpkt_t; typedef struct { - const char *name; - const char *internal_name; const device_t *device; void *priv; int (*poll)(void *); @@ -101,14 +100,12 @@ extern "C" { /* Global variables. */ extern int nic_do_log; /* config */ extern int network_ndev; +extern int network_rx_pause; extern netdev_t network_devs[32]; /* Function prototypes. */ extern void network_wait(uint8_t wait); -extern void network_poll(void); -extern void network_busy(uint8_t set); -extern void network_end(void); extern void network_init(void); extern void network_attach(void *, uint8_t *, NETRXCB, NETWAITCB, NETSETLINKSTATE); @@ -116,7 +113,6 @@ extern void network_close(void); extern void network_reset(void); extern int network_available(void); extern void network_tx(uint8_t *, int); -extern void network_do_tx(void); extern int network_tx_queue_check(void); extern int net_pcap_prepare(netdev_t *); @@ -132,7 +128,6 @@ extern void net_slirp_in(uint8_t *, int); extern int network_dev_to_id(char *); extern int network_card_available(int); -extern char *network_card_getname(int); extern int network_card_has_config(int); extern char *network_card_get_internal_name(int); extern int network_card_get_from_internal_name(char *); @@ -141,6 +136,8 @@ extern const device_t *network_card_getdevice(int); extern void network_set_wait(int wait); extern int network_get_wait(void); +extern void network_timer_stop(void); + extern void network_queue_put(int tx, void *priv, uint8_t *data, int len); #ifdef __cplusplus diff --git a/src/include/86box/nmi.h b/src/include/86box/nmi.h index 72c2f507f..b2378af93 100644 --- a/src/include/86box/nmi.h +++ b/src/include/86box/nmi.h @@ -1,6 +1,10 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ + +#ifndef EMU_NMI_H +# define EMU_NMI_H + extern int nmi_mask; extern int nmi; extern int nmi_auto_clear; @@ -9,3 +13,5 @@ extern int nmi_auto_clear; extern void nmi_init(void); extern void nmi_write(uint16_t port, uint8_t val, void *p); + +#endif /*EMU_NMI_H*/ diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 1b0088f0b..1788fc91b 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -1,124 +1,133 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Definitions for the generic NVRAM/CMOS driver. - * - * - * - * Author: Fred N. van Kempen, , - * David Hrdlička, - * - * Copyright 2017-2020 Fred N. van Kempen. - * Copyright 2018-2020 David Hrdlička. - * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef EMU_NVR_H -# define EMU_NVR_H - - -#define NVR_MAXSIZE 512 /* max size of NVR data */ - -/* Conversion from BCD to Binary and vice versa. */ -#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4)) -#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) -#define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y) - -/* Time sync options */ -#define TIME_SYNC_DISABLED 0 -#define TIME_SYNC_ENABLED 1 -#define TIME_SYNC_UTC 2 - - -/* Define a generic RTC/NVRAM device. */ -typedef struct _nvr_ { - wchar_t *fn; /* pathname of image file */ - uint16_t size; /* device configuration */ - int8_t irq; - - uint8_t onesec_cnt; - pc_timer_t onesec_time; - - void *data; /* local data */ - - /* Hooks to device functions. */ - void (*reset)(struct _nvr_ *); - void (*start)(struct _nvr_ *); - void (*tick)(struct _nvr_ *); - void (*ven_save)(void); - - uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ -} nvr_t; - - -extern int nvr_dosave; -#ifdef EMU_DEVICE_H -extern const device_t at_nvr_old_device; -extern const device_t at_nvr_device; -extern const device_t ps_nvr_device; -extern const device_t amstrad_nvr_device; -extern const device_t ibmat_nvr_device; -extern const device_t piix4_nvr_device; -extern const device_t ls486e_nvr_device; -extern const device_t via_nvr_device; -#endif - - -extern void rtc_tick(void); - -extern void nvr_init(nvr_t *); -extern wchar_t *nvr_path(wchar_t *str); -extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); -extern int nvr_load(void); -extern void nvr_close(void); -extern void nvr_set_ven_save(void (*ven_save)(void)); -extern int nvr_save(void); - -extern int nvr_is_leap(int year); -extern int nvr_get_days(int month, int year); -extern void nvr_time_get(struct tm *); -extern void nvr_time_set(struct tm *); - -extern void nvr_reg_write(uint16_t reg, uint8_t val, void *priv); -extern void nvr_at_handler(int set, uint16_t base, nvr_t *nvr); -extern void nvr_at_sec_handler(int set, uint16_t base, nvr_t *nvr); -extern void nvr_read_addr_set(int set, nvr_t *nvr); -extern void nvr_wp_set(int set, int h, nvr_t *nvr); -extern void nvr_bank_set(int base, uint8_t bank, nvr_t *nvr); -extern void nvr_lock_set(int base, int size, int lock, nvr_t *nvr); - - -#endif /*EMU_NVR_H*/ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the generic NVRAM/CMOS driver. + * + * + * + * Author: Fred N. van Kempen, , + * David Hrdlička, + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2018-2020 David Hrdlička. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMU_NVR_H +# define EMU_NVR_H + + +#define NVR_MAXSIZE 512 /* max size of NVR data */ + +/* Conversion from BCD to Binary and vice versa. */ +#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4)) +#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) +#define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y) + +/* Time sync options */ +#define TIME_SYNC_DISABLED 0 +#define TIME_SYNC_ENABLED 1 +#define TIME_SYNC_UTC 2 + + +/* Define a generic RTC/NVRAM device. */ +typedef struct _nvr_ { + char *fn; /* pathname of image file */ + uint16_t size; /* device configuration */ + int8_t irq, is_new; + + uint8_t onesec_cnt; + pc_timer_t onesec_time; + + void *data; /* local data */ + + /* Hooks to device functions. */ + void (*reset)(struct _nvr_ *); + void (*start)(struct _nvr_ *); + void (*tick)(struct _nvr_ *); + void (*ven_save)(void); + + uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ +} nvr_t; + + +extern int nvr_dosave; +#ifdef EMU_DEVICE_H +extern const device_t at_nvr_old_device; +extern const device_t at_nvr_device; +extern const device_t ps_nvr_device; +extern const device_t amstrad_nvr_device; +extern const device_t ibmat_nvr_device; +extern const device_t piix4_nvr_device; +extern const device_t ps_no_nmi_nvr_device; +extern const device_t amstrad_no_nmi_nvr_device; +extern const device_t ami_1992_nvr_device; +extern const device_t ami_1994_nvr_device; +extern const device_t ami_1995_nvr_device; +extern const device_t via_nvr_device; +extern const device_t p6rp4_nvr_device; +#endif + + +extern void rtc_tick(void); + +extern void nvr_init(nvr_t *); +extern char *nvr_path(char *str); +extern FILE *nvr_fopen(char *str, char *mode); +extern int nvr_load(void); +extern void nvr_close(void); +extern void nvr_set_ven_save(void (*ven_save)(void)); +extern int nvr_save(void); + +extern int nvr_is_leap(int year); +extern int nvr_get_days(int month, int year); +extern void nvr_time_sync(); +extern void nvr_time_get(struct tm *); +extern void nvr_time_set(struct tm *); + +extern void nvr_reg_write(uint16_t reg, uint8_t val, void *priv); +extern void nvr_at_handler(int set, uint16_t base, nvr_t *nvr); +extern void nvr_at_sec_handler(int set, uint16_t base, nvr_t *nvr); +extern void nvr_read_addr_set(int set, nvr_t *nvr); +extern void nvr_wp_set(int set, int h, nvr_t *nvr); +extern void nvr_via_wp_set(int set, int reg, nvr_t *nvr); +extern void nvr_bank_set(int base, uint8_t bank, nvr_t *nvr); +extern void nvr_lock_set(int base, int size, int lock, nvr_t *nvr); +extern void nvr_irq_set(int irq, nvr_t *nvr); + + +#endif /*EMU_NVR_H*/ diff --git a/src/include/86box/nvr_ps2.h b/src/include/86box/nvr_ps2.h index f0058d9b1..0287cdd57 100644 --- a/src/include/86box/nvr_ps2.h +++ b/src/include/86box/nvr_ps2.h @@ -34,11 +34,13 @@ * Boston, MA 02111-1307 * USA. */ + #ifndef EMU_NVRPS2_H # define EMU_NVRPS2_H -extern const device_t ps2_nvr_device; +extern const device_t ps2_nvr_device; +extern const device_t ps2_nvr_55ls_device; #endif /*EMU_NVRPS2_H*/ diff --git a/src/include/86box/path.h b/src/include/86box/path.h new file mode 100644 index 000000000..85cb0814d --- /dev/null +++ b/src/include/86box/path.h @@ -0,0 +1,7 @@ +extern void path_get_dirname(char *dest, const char *path); +extern char *path_get_filename(char *s); +extern char *path_get_extension(char *s); +extern void path_append_filename(char *dest, const char *s1, const char *s2); +extern void path_slash(char *path); +extern void path_normalize(char *path); +extern int path_abs(char *path); \ No newline at end of file diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index edb6a5e57..7908ea558 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -18,16 +18,18 @@ * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2008-2020 Sarah Walker. */ + #ifndef EMU_PCI_H # define EMU_PCI_H - #define PCI_REG_COMMAND 0x04 #define PCI_COMMAND_IO 0x01 #define PCI_COMMAND_MEM 0x02 #define PCI_NO_IRQ_STEERING 0x8000 +#define PCI_CAN_SWITCH_TYPE 0x10000 +#define PCI_NO_BRIDGES 0x20000 #define PCI_CONFIG_TYPE_1 1 #define PCI_CONFIG_TYPE_2 2 @@ -42,26 +44,48 @@ #define PCI_MIRQ0 0 #define PCI_MIRQ1 1 #define PCI_MIRQ2 2 +#define PCI_MIRQ3 3 +#define PCI_MIRQ4 4 +#define PCI_MIRQ5 5 +#define PCI_MIRQ6 6 +#define PCI_MIRQ7 7 #define PCI_IRQ_DISABLED -1 +#define PCI_ADD_STRICT 0x80 + enum { PCI_CARD_NORTHBRIDGE = 0, + PCI_CARD_AGPBRIDGE, PCI_CARD_SOUTHBRIDGE, - PCI_CARD_NORMAL, - PCI_CARD_ONBOARD, + PCI_CARD_SOUTHBRIDGE_IDE, + PCI_CARD_SOUTHBRIDGE_PMU, + PCI_CARD_SOUTHBRIDGE_USB, + PCI_CARD_AGP = 0x0f, + PCI_CARD_NORMAL = 0x10, + PCI_CARD_VIDEO, PCI_CARD_SCSI, PCI_CARD_SOUND, - PCI_CARD_SPECIAL + PCI_CARD_IDE, + PCI_CARD_NETWORK, + PCI_CARD_BRIDGE, }; enum { - PCI_ADD_NORTHBRIDGE = 0x80, + PCI_ADD_NORTHBRIDGE = 0, + PCI_ADD_AGPBRIDGE, PCI_ADD_SOUTHBRIDGE, - PCI_ADD_NORMAL, + PCI_ADD_SOUTHBRIDGE_IDE, + PCI_ADD_SOUTHBRIDGE_PMU, + PCI_ADD_SOUTHBRIDGE_USB, + PCI_ADD_AGP = 0x0f, + PCI_ADD_NORMAL = 0x10, PCI_ADD_VIDEO, PCI_ADD_SCSI, - PCI_ADD_SOUND + PCI_ADD_SOUND, + PCI_ADD_IDE, + PCI_ADD_NETWORK, + PCI_ADD_BRIDGE }; typedef union { @@ -70,8 +94,8 @@ typedef union { } bar_t; -extern int pci_burst_time, - pci_nonburst_time; +extern int pci_burst_time, agp_burst_time, + pci_nonburst_time, agp_nonburst_time; extern void pci_set_irq_routing(int pci_int, int irq); @@ -80,19 +104,24 @@ extern void pci_set_irq_level(int pci_int, int level); extern void pci_enable_mirq(int mirq); extern void pci_set_mirq_routing(int mirq, int irq); -extern uint8_t pci_use_mirq(uint8_t mirq); - extern int pci_irq_is_level(int irq); extern void pci_set_mirq(uint8_t mirq, int level); extern void pci_set_irq(uint8_t card, uint8_t pci_int); extern void pci_clear_mirq(uint8_t mirq, int level); extern void pci_clear_irq(uint8_t card, uint8_t pci_int); +extern uint8_t pci_get_int(uint8_t card, uint8_t pci_int); extern void pci_reset(void); extern void pci_init(int type); +extern uint8_t pci_register_bus(); +extern void pci_set_pmc(uint8_t pmc); +extern void pci_remap_bus(uint8_t bus_index, uint8_t bus_number); +extern void pci_relocate_slot(int type, int new_slot); extern void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd); +extern void pci_register_bus_slot(int bus, int card, int type, + int inta, int intb, int intc, int intd); extern void pci_close(void); extern uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); @@ -101,7 +130,24 @@ extern void trc_init(void); extern uint8_t trc_read(uint16_t port, void *priv); extern void trc_write(uint16_t port, uint8_t val, void *priv); -extern void pci_elcr_set_enabled(int enabled); +extern void pci_bridge_set_ctl(void *priv, uint8_t ctl); + +extern void pci_pic_reset(void); + + +#ifdef EMU_DEVICE_H +extern const device_t dec21150_device; + +extern const device_t ali5243_agp_device; +extern const device_t ali5247_agp_device; +extern const device_t i440lx_agp_device; +extern const device_t i440bx_agp_device; +extern const device_t i440gx_agp_device; +extern const device_t via_vp3_agp_device; +extern const device_t via_mvp3_agp_device; +extern const device_t via_apro_agp_device; +extern const device_t via_vt8601_agp_device; +#endif #endif /*EMU_PCI_H*/ diff --git a/src/include/86box/pci_dummy.h b/src/include/86box/pci_dummy.h index 45e1299bc..a2ae4b8d0 100644 --- a/src/include/86box/pci_dummy.h +++ b/src/include/86box/pci_dummy.h @@ -1 +1,6 @@ +#ifndef EMU_PCI_DUMMY_H +# define EMU_PCI_DUMMY_H + extern void pci_dummy_init(void); + +#endif /*EMU_PCI_DUMMY_H*/ diff --git a/src/include/86box/pic.h b/src/include/86box/pic.h index 10684958a..3720f17d1 100644 --- a/src/include/86box/pic.h +++ b/src/include/86box/pic.h @@ -1,29 +1,65 @@ +/* + * 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. + * + * Header of the implementation of the Intel PIC chip emulation, + * partially ported from reenigne's XTCE. + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2020 Andrew Jenner. + * Copyright 2016-2020 Miran Grca. + */ + #ifndef EMU_PIC_H # define EMU_PIC_H - -typedef struct PIC { - uint8_t icw1, icw3, icw4, mask, ins, pend, mask2, vector, ocw2, ocw3; - int icw, read; -} PIC; +typedef struct pic { + uint8_t icw1, icw2, icw3, icw4, + imr, isr, irr, ocw2, + ocw3, int_pending, is_master, elcr, + state, ack_bytes, priority, special_mask_mode, + auto_eoi_rotate, interrupt, lines, data_bus; + uint32_t at; + struct pic *slaves[8]; +} pic_t; -extern PIC pic, pic2; -extern int pic_intpending; +extern pic_t pic, pic2; +extern void pic_reset_smi_irq_mask(void); +extern void pic_set_smi_irq_mask(int irq, int set); +extern uint16_t pic_get_smi_irq_status(void); +extern void pic_clear_smi_irq_status(int irq); + +extern int pic_elcr_get_enabled(void); +extern void pic_elcr_set_enabled(int enabled); +extern void pic_elcr_io_handler(int set); +extern void pic_elcr_write(uint16_t port, uint8_t val, void *priv); +extern uint8_t pic_elcr_read(uint16_t port, void *priv); + extern void pic_set_shadow(int sh); +extern void pic_set_pci_flag(int pci); +extern void pic_set_pci(void); extern void pic_init(void); extern void pic_init_pcjr(void); extern void pic2_init(void); extern void pic_reset(void); +extern int picint_is_level(int irq); +extern void picint_common(uint16_t num, int level, int set); extern void picint(uint16_t num); extern void picintlevel(uint16_t num); extern void picintc(uint16_t num); extern int picinterrupt(void); -extern void picclear(int num); -extern void dumppic(void); + +extern uint8_t pic_irq_ack(void); #endif /*EMU_PIC_H*/ diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index 4684c9632..95541014b 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -14,6 +14,7 @@ * Author: Miran Grca, * Copyright 2019,2020 Miran Grca. */ + #ifndef EMU_PIT_H # define EMU_PIT_H @@ -21,13 +22,25 @@ typedef struct { uint8_t m, ctrl, read_status, latch, - s1_det, l_det; + s1_det, l_det, + bcd, pad; uint16_t rl; int rm, wm, gate, out, - newcount, count, using_timer, latched, - state, null_count, do_read_status, clock; + newcount, clock, using_timer, latched, + state, null_count, do_read_status; + + union { + int count; + struct { + int units :4; + int tens :4; + int hundreds :4; + int thousands :4; + int myriads :4; + }; + }; uint32_t l; @@ -45,11 +58,35 @@ typedef struct PIT { uint8_t ctrl; } pit_t; +enum { + PIT_8253 = 0, + PIT_8254, + PIT_8253_FAST, + PIT_8254_FAST +}; -extern pit_t *pit, - *pit2; +typedef struct { + uint8_t (*read)(uint16_t addr, void *priv); + void (*write)(uint16_t addr, uint8_t val, void *priv); + /* Gets a counter's count. */ + uint16_t (*get_count)(void *data, int counter_id); + /* Sets a counter's GATE input. */ + void (*set_gate)(void *data, int counter_id, int gate); + /* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */ + void(*set_using_timer)(void *data, int counter_id, int using_timer); + /* Sets a counter's OUT output handler. */ + void (*set_out_func)(void *data, int counter_id, void (*func)(int new_out, int old_out)); + /* Sets a counter's load count handler. */ + void (*set_load_func)(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count)); + void (*ctr_clock)(void *data, int counter_id); + void *data; +} pit_intf_t; -extern double SYSCLK, PCICLK; +extern pit_intf_t pit_devs[2]; +extern const pit_intf_t pit_classic_intf; + + +extern double SYSCLK, PCICLK, AGPCLK; extern uint64_t PITCONST, ISACONST, CGACONST, @@ -57,28 +94,17 @@ extern uint64_t PITCONST, ISACONST, HERCCONST, VGACONST1, VGACONST2, - RTCCONST, ACPICONST; + RTCCONST; +extern int refresh_at_enable; -/* Gets a counter's count. */ -extern uint16_t pit_ctr_get_count(ctr_t *ctr); -/* Sets a counter's load count handler. */ -extern void pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count)); -/* Sets a counter's OUT output handler. */ -extern void pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out)); -/* Sets a counter's GATE input. */ -extern void pit_ctr_set_gate(ctr_t *ctr, int gate); /* Sets a counter's CLOCK input. */ extern void pit_ctr_set_clock(ctr_t *ctr, int clock); -/* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */ -extern void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer); extern pit_t * pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out)); -extern pit_t * pit_ps2_init(void); +extern pit_t * pit_ps2_init(int type); extern void pit_reset(pit_t *dev); -extern void pit_irq0_timer(int new_out, int old_out); -extern void pit_irq0_timer_pcjr(int new_out, int old_out); extern void pit_irq0_timer_ps2(int new_out, int old_out); extern void pit_refresh_timer_xt(int new_out, int old_out); @@ -95,6 +121,7 @@ extern void pit_handler(int set, uint16_t base, int size, void *priv); #ifdef EMU_DEVICE_H extern const device_t i8253_device; extern const device_t i8254_device; +extern const device_t i8254_sec_device; extern const device_t i8254_ext_io_device; extern const device_t i8254_ps2_device; #endif diff --git a/src/include/86box/pit_fast.h b/src/include/86box/pit_fast.h new file mode 100644 index 000000000..bc09174fb --- /dev/null +++ b/src/include/86box/pit_fast.h @@ -0,0 +1,72 @@ +/* + * 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. + * + * Header of the implementation of the Intel 8253/8254 + * Programmable Interval Timer. + * + * + * + * Author: Miran Grca, + * Copyright 2019,2020 Miran Grca. + */ + +#ifndef EMU_PIT_FAST_H +#define EMU_PIT_FAST_H + +typedef struct { + uint8_t m, ctrl, + read_status, latch, bcd; + + uint16_t rl; + + int rm, wm, gate, out, + newcount, clock, using_timer, latched, + do_read_status; + int enabled; + int disabled; + int initial; + int thit; + int running; + int rereadlatch; + + union { + int count; + struct { + int units : 4; + int tens : 4; + int hundreds : 4; + int thousands : 4; + int myriads : 4; + }; + }; + + uint32_t l; + pc_timer_t timer; + + void (*load_func)(uint8_t new_m, int new_count); + void (*out_func)(int new_out, int old_out); +} ctrf_t; + +typedef struct { + int flags; + ctrf_t counters[3]; + + uint8_t ctrl; +} pitf_t; + +extern const pit_intf_t pit_fast_intf; + +#ifdef EMU_DEVICE_H +extern const device_t i8253_fast_device; +extern const device_t i8254_fast_device; +extern const device_t i8254_sec_fast_device; +extern const device_t i8254_ext_io_fast_device; +extern const device_t i8254_ps2_fast_device; +#endif + +#endif /*EMU_PIT_FAST_H*/ diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 2033ef02f..70926fadc 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -15,10 +15,16 @@ * * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ + #ifndef EMU_PLAT_H # define EMU_PLAT_H +#include +#include +#include "86box/device.h" +#include "86box/machine.h" #ifndef GLOBAL # define GLOBAL extern #endif @@ -30,9 +36,13 @@ #ifdef _WIN32 # define wcscasecmp _wcsicmp # define strcasecmp _stricmp +#else +/* Declare these functions to avoid warnings. They will redirect to strcasecmp and strncasecmp respectively. */ +extern int stricmp(const char* s1, const char* s2); +extern int strnicmp(const char* s1, const char* s2, size_t n); #endif -#if defined(UNIX) && defined(FREEBSD) +#if (defined(__HAIKU__) || defined(__unix__) || defined(__APPLE__)) && !defined(__linux__) /* FreeBSD has largefile by default. */ # define fopen64 fopen # define fseeko64 fseeko @@ -58,44 +68,50 @@ #ifdef __cplusplus +#include +#define atomic_flag_t std::atomic_flag +#define atomic_bool_t std::atomic_bool extern "C" { +#else +#include +#define atomic_flag_t atomic_flag +#define atomic_bool_t atomic_bool #endif /* Global variables residing in the platform module. */ extern int dopause, /* system is paused */ - doresize, /* screen resize requested */ - quited, /* system exit requested */ mouse_capture; /* mouse is captured in app */ +extern volatile int is_quit; /* system exit requested */ + +#ifdef MTR_ENABLED +extern int tracing_on; +#endif + extern uint64_t timer_freq; extern int infocus; extern char emu_version[200]; /* version ID string */ extern int rctrl_is_lalt; extern int update_icons; -extern int unscaled_size_x, /* current unscaled size X */ - unscaled_size_y; /* current unscaled size Y */ +extern int kbd_req_capture, hide_status_bar, hide_tool_bar; /* System-related functions. */ -extern wchar_t *fix_exe_path(wchar_t *str); -extern FILE *plat_fopen(wchar_t *path, wchar_t *mode); -extern FILE *plat_fopen64(const wchar_t *path, const wchar_t *mode); -extern void plat_remove(wchar_t *path); -extern int plat_getcwd(wchar_t *bufp, int max); -extern int plat_chdir(wchar_t *path); -extern void plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix); -extern void plat_get_exe_name(wchar_t *s, int size); -extern wchar_t *plat_get_basename(const wchar_t *path); -extern void plat_get_dirname(wchar_t *dest, const wchar_t *path); -extern wchar_t *plat_get_filename(wchar_t *s); -extern wchar_t *plat_get_extension(wchar_t *s); -extern void plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2); -extern void plat_put_backslash(wchar_t *s); -extern void plat_path_slash(wchar_t *path); -extern int plat_path_abs(wchar_t *path); -extern int plat_dir_check(wchar_t *path); -extern int plat_dir_create(wchar_t *path); +extern char *fix_exe_path(char *str); +extern FILE *plat_fopen(const char *path, const char *mode); +extern FILE *plat_fopen64(const char *path, const char *mode); +extern void plat_remove(char *path); +extern int plat_getcwd(char *bufp, int max); +extern int plat_chdir(char *path); +extern void plat_tempfile(char *bufp, char *prefix, char *suffix); +extern void plat_get_exe_name(char *s, int size); +extern void plat_init_rom_paths(); +extern int plat_dir_check(char *path); +extern int plat_dir_create(char *path); +extern void *plat_mmap(size_t size, uint8_t executable); +extern void plat_munmap(void *ptr, size_t size); extern uint64_t plat_timer_read(void); extern uint32_t plat_get_ticks(void); +extern uint32_t plat_get_micro_ticks(void); extern void plat_delay_ms(uint32_t count); extern void plat_pause(int p); extern void plat_mouse_capture(int on); @@ -104,12 +120,17 @@ extern char *plat_vidapi_name(int api); extern int plat_setvid(int api); extern void plat_vidsize(int x, int y); extern void plat_setfullscreen(int on); -extern void plat_resize(int x, int y); +extern void plat_resize_monitor(int x, int y, int monitor_index); +extern void plat_resize_request(int x, int y, int monitor_index); +extern void plat_resize(int x, int y); extern void plat_vidapi_enable(int enabled); - +extern void plat_vidapi_reload(void); +extern void plat_vid_reload_options(void); +extern uint32_t plat_language_code(char* langcode); +extern void plat_language_code_r(uint32_t lcid, char* outbuf, int len); /* Resource management. */ -extern void set_language(int id); +extern void set_language(uint32_t id); extern wchar_t *plat_get_string(int id); @@ -118,47 +139,43 @@ extern void do_start(void); extern void do_stop(void); +/* Power off. */ +extern void plat_power_off(void); + + /* Platform-specific device support. */ -extern void floppy_mount(uint8_t id, wchar_t *fn, uint8_t wp); +extern void cassette_mount(char *fn, uint8_t wp); +extern void cassette_eject(void); +extern void cartridge_mount(uint8_t id, char *fn, uint8_t wp); +extern void cartridge_eject(uint8_t id); +extern void floppy_mount(uint8_t id, char *fn, uint8_t wp); extern void floppy_eject(uint8_t id); -extern void cdrom_mount(uint8_t id, wchar_t *fn); +extern void cdrom_mount(uint8_t id, char *fn); extern void plat_cdrom_ui_update(uint8_t id, uint8_t reload); extern void zip_eject(uint8_t id); -extern void zip_mount(uint8_t id, wchar_t *fn, uint8_t wp); +extern void zip_mount(uint8_t id, char *fn, uint8_t wp); extern void zip_reload(uint8_t id); extern void mo_eject(uint8_t id); -extern void mo_mount(uint8_t id, wchar_t *fn, uint8_t wp); +extern void mo_mount(uint8_t id, char *fn, uint8_t wp); extern void mo_reload(uint8_t id); extern int ioctl_open(uint8_t id, char d); extern void ioctl_reset(uint8_t id); extern void ioctl_close(uint8_t id); - -/* Thread support. */ -typedef void thread_t; -typedef void event_t; -typedef void mutex_t; - -extern thread_t *thread_create(void (*thread_func)(void *param), void *param); -extern void thread_kill(thread_t *arg); -extern int thread_wait(thread_t *arg, int timeout); -extern event_t *thread_create_event(void); -extern void thread_set_event(event_t *arg); -extern void thread_reset_event(event_t *arg); -extern int thread_wait_event(event_t *arg, int timeout); -extern void thread_destroy_event(event_t *arg); - -extern mutex_t *thread_create_mutex(void); -extern void thread_close_mutex(mutex_t *arg); -extern int thread_wait_mutex(mutex_t *arg); -extern int thread_release_mutex(mutex_t *mutex); - - /* Other stuff. */ extern void startblit(void); extern void endblit(void); extern void take_screenshot(void); +/* Conversion between UTF-8 and UTF-16. */ +extern size_t mbstoc16s(uint16_t dst[], const char src[], int len); +extern size_t c16stombs(char dst[], const uint16_t src[], int len); + +#ifdef MTR_ENABLED +extern void init_trace(void); +extern void shutdown_trace(void); +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/86box/plat_dir.h b/src/include/86box/plat_dir.h index 948db8c84..46b57ee34 100644 --- a/src/include/86box/plat_dir.h +++ b/src/include/86box/plat_dir.h @@ -13,10 +13,10 @@ * Author: Fred N. van Kempen, * Copyright 2017 Fred N. van Kempen. */ + #ifndef PLAT_DIR_H # define PLAT_DIR_H - #ifdef _MAX_FNAME # define MAXNAMLEN _MAX_FNAME #else @@ -25,7 +25,7 @@ # define MAXDIRLEN 127 -struct direct { +struct dirent { long d_ino; unsigned short d_reclen; unsigned short d_off; @@ -49,7 +49,7 @@ typedef struct { #else char dir[MAXDIRLEN+1]; /* open dir */ #endif - struct direct dent; /* actual directory entry */ + struct dirent dent; /* actual directory entry */ } DIR; @@ -60,12 +60,8 @@ typedef struct { /* Function prototypes. */ -#ifdef UNICODE -extern DIR *opendirw(const wchar_t *); -#else extern DIR *opendir(const char *); -#endif -extern struct direct *readdir(DIR *); +extern struct dirent *readdir(DIR *); extern long telldir(DIR *); extern void seekdir(DIR *, long); extern int closedir(DIR *); diff --git a/src/include/86box/plat_dynld.h b/src/include/86box/plat_dynld.h index 0eb8f33c2..b4be8d09e 100644 --- a/src/include/86box/plat_dynld.h +++ b/src/include/86box/plat_dynld.h @@ -13,10 +13,10 @@ * Author: Fred N. van Kempen, * Copyright 2017 Fred N. van Kempen */ + #ifndef PLAT_DYNLD_H # define PLAT_DYNLD_H - typedef struct { const char *name; void *func; diff --git a/src/include/86box/plat_midi.h b/src/include/86box/plat_midi.h deleted file mode 100644 index 933e49ee6..000000000 --- a/src/include/86box/plat_midi.h +++ /dev/null @@ -1,15 +0,0 @@ -extern void plat_midi_init(void); -extern void plat_midi_close(void); - -extern void plat_midi_play_msg(uint8_t *msg); -extern void plat_midi_play_sysex(uint8_t *sysex, unsigned int len); -extern int plat_midi_write(uint8_t val); - -extern int plat_midi_get_num_devs(void); -extern void plat_midi_get_dev_name(int num, char *s); - -extern void plat_midi_input_init(void); -extern void plat_midi_input_close(void); - -extern int plat_midi_in_get_num_devs(void); -extern void plat_midi_in_get_dev_name(int num, char *s); diff --git a/src/include/86box/png_struct.h b/src/include/86box/png_struct.h index 694fcfc20..0bb0e5e1b 100644 --- a/src/include/86box/png_struct.h +++ b/src/include/86box/png_struct.h @@ -44,6 +44,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef EMU_PNG_STRUCT_H # define EMU_PNG_STRUCT_H @@ -52,10 +53,10 @@ extern "C" { #endif -extern int png_write_gray(wchar_t *path, int invert, +extern int png_write_gray(char *path, int invert, uint8_t *pix, int16_t w, int16_t h); -extern void png_write_rgb(wchar_t *fn, +extern void png_write_rgb(char *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol); #ifdef __cplusplus diff --git a/src/include/86box/port_6x.h b/src/include/86box/port_6x.h new file mode 100644 index 000000000..a478e8390 --- /dev/null +++ b/src/include/86box/port_6x.h @@ -0,0 +1,38 @@ +/* + * 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. + * + * Header for the implementation of Port 6x used by various + * machines. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ + +#ifndef EMU_PORT_6X_H +# define EMU_PORT_6X_H + +#ifdef _TIMER_H_ +typedef struct +{ + uint8_t refresh, flags; + + pc_timer_t refresh_timer; +} port_6x_t; +#endif + + +extern const device_t port_6x_device; +extern const device_t port_6x_xi8088_device; +extern const device_t port_6x_ps2_device; +extern const device_t port_6x_olivetti_device; + + +#endif /*EMU_PORT_6X_H*/ diff --git a/src/include/86box/port_92.h b/src/include/86box/port_92.h index 52812edb8..78e0a0002 100644 --- a/src/include/86box/port_92.h +++ b/src/include/86box/port_92.h @@ -15,6 +15,7 @@ * * Copyright 2019 Miran Grca. */ + #ifndef EMU_PORT_92_H # define EMU_PORT_92_H diff --git a/src/include/86box/postcard.h b/src/include/86box/postcard.h index 8cf1d1c54..ee179eb3d 100644 --- a/src/include/86box/postcard.h +++ b/src/include/86box/postcard.h @@ -14,10 +14,10 @@ * * Copyright 2020 RichardG. */ + #ifndef POSTCARD_H # define POSTCARD_H - #ifdef __cplusplus extern "C" { #endif diff --git a/src/include/86box/printer.h b/src/include/86box/printer.h index 44dfa6371..4cd5e898d 100644 --- a/src/include/86box/printer.h +++ b/src/include/86box/printer.h @@ -44,18 +44,18 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef PRINTER_H # define PRINTER_H +#define FONT_FILE_DOTMATRIX "dotmatrix.ttf" -#define FONT_FILE_DOTMATRIX L"dotmatrix.ttf" - -#define FONT_FILE_ROMAN L"roman.ttf" -#define FONT_FILE_SANSSERIF L"sansserif.ttf" -#define FONT_FILE_COURIER L"courier.ttf" -#define FONT_FILE_SCRIPT L"script.ttf" -#define FONT_FILE_OCRA L"ocra.ttf" -#define FONT_FILE_OCRB L"ocra.ttf" +#define FONT_FILE_ROMAN "roman.ttf" +#define FONT_FILE_SANSSERIF "sansserif.ttf" +#define FONT_FILE_COURIER "courier.ttf" +#define FONT_FILE_SCRIPT "script.ttf" +#define FONT_FILE_OCRA "ocra.ttf" +#define FONT_FILE_OCRB "ocra.ttf" extern void diff --git a/src/include/86box/prt_devs.h b/src/include/86box/prt_devs.h index 7ef25e5cd..e8d56fe24 100644 --- a/src/include/86box/prt_devs.h +++ b/src/include/86box/prt_devs.h @@ -1,3 +1,8 @@ +#ifndef EMU_PRT_DEVS_H +# define EMU_PRT_DEVS_H + extern const lpt_device_t lpt_prt_text_device; extern const lpt_device_t lpt_prt_escp_device; -extern const lpt_device_t lpt_prt_ps_device; \ No newline at end of file +extern const lpt_device_t lpt_prt_ps_device; + +#endif /*EMU_PRT_DEVS_H*/ diff --git a/src/include/86box/random.h b/src/include/86box/random.h index 75ceb4c13..bf123375f 100644 --- a/src/include/86box/random.h +++ b/src/include/86box/random.h @@ -14,12 +14,11 @@ * Author: Miran Grca, * Copyright 2016,2017 Miran Grca. */ + #ifndef EMU_RANDOM_H # define EMU_RANDOM_H - extern uint8_t random_generate(void); extern void random_init(void); - #endif /*EMU_RANDOM_H*/ diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index afcb33e5b..f0dd948ae 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -18,89 +18,141 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2018,2019 David Hrdlička. + * Copyright 2021-2022 Jasmine Iwanek. */ + #ifndef WIN_RESOURCE_H # define WIN_RESOURCE_H - /* Dialog IDs. */ -#define DLG_ABOUT 101 /* top-level dialog */ -#define DLG_STATUS 102 /* top-level dialog */ -#define DLG_SND_GAIN 103 /* top-level dialog */ -#define DLG_NEW_FLOPPY 104 /* top-level dialog */ -#define DLG_CONFIG 110 /* top-level dialog */ -#define DLG_CFG_MACHINE 111 /* sub-dialog of config */ -#define DLG_CFG_VIDEO 112 /* sub-dialog of config */ -#define DLG_CFG_INPUT 113 /* sub-dialog of config */ -#define DLG_CFG_SOUND 114 /* sub-dialog of config */ -#define DLG_CFG_NETWORK 115 /* sub-dialog of config */ -#define DLG_CFG_PORTS 116 /* sub-dialog of config */ -#define DLG_CFG_PERIPHERALS 117 /* sub-dialog of config */ -#define DLG_CFG_HARD_DISKS 118 /* sub-dialog of config */ -#define DLG_CFG_HARD_DISKS_ADD 119 /* sub-dialog of config */ -#define DLG_CFG_FLOPPY_DRIVES 120 /* sub-dialog of config */ -#define DLG_CFG_OTHER_REMOVABLE_DEVICES 121 /* sub-dialog of config */ +#define DLG_ABOUT 101 /* top-level dialog */ +#define DLG_STATUS 102 /* top-level dialog */ +#define DLG_SND_GAIN 103 /* top-level dialog */ +#define DLG_NEW_FLOPPY 104 /* top-level dialog */ +#define DLG_SPECIFY_DIM 105 /* top-level dialog */ +#define DLG_PREFERENCES 106 /* top-level dialog */ +#define DLG_CONFIG 110 /* top-level dialog */ +#define DLG_CFG_MACHINE 111 /* sub-dialog of config */ +#define DLG_CFG_VIDEO 112 /* sub-dialog of config */ +#define DLG_CFG_INPUT 113 /* sub-dialog of config */ +#define DLG_CFG_SOUND 114 /* sub-dialog of config */ +#define DLG_CFG_NETWORK 115 /* sub-dialog of config */ +#define DLG_CFG_PORTS 116 /* sub-dialog of config */ +#define DLG_CFG_STORAGE 117 /* sub-dialog of config */ +#define DLG_CFG_HARD_DISKS 118 /* sub-dialog of config */ +#define DLG_CFG_HARD_DISKS_ADD 119 /* sub-dialog of config */ +#define DLG_CFG_FLOPPY_AND_CDROM_DRIVES 120 /* sub-dialog of config */ +#define DLG_CFG_OTHER_REMOVABLE_DEVICES 121 /* sub-dialog of config */ +#define DLG_CFG_PERIPHERALS 122 /* sub-dialog of config */ /* Static text label IDs. */ -#define IDT_1700 1700 /* Language: */ -#define IDT_1701 1701 /* Machine: */ -#define IDT_1702 1702 /* CPU type: */ -#define IDT_1703 1703 /* Wait states: */ -#define IDT_1704 1704 /* CPU: */ -#define IDT_1705 1705 /* MB == IDC_TEXT_MB */ -#define IDT_1706 1706 /* Memory: */ -#define IDT_1707 1707 /* Video: */ -#define IDT_1708 1708 /* Machine type: */ -#define IDT_1709 1709 /* Mouse: */ -#define IDT_1710 1710 /* Joystick: */ -#define IDT_1711 1711 /* Sound card: */ -#define IDT_1712 1712 /* MIDI Out Device: */ -#define IDT_1713 1713 /* MIDI In Device: */ -#define IDT_1714 1714 /* Network type: */ -#define IDT_1715 1715 /* PCap device: */ -#define IDT_1716 1716 /* Network adapter: */ -#define IDT_1717 1717 /* SCSI Controller: */ -#define IDT_1718 1718 /* HD Controller: */ -#define IDT_1719 1719 -#define IDT_1720 1720 /* Hard disks: */ -#define IDT_1721 1721 /* Bus: */ -#define IDT_1722 1722 /* Channel: */ -#define IDT_1723 1723 /* ID: */ -#define IDT_1724 1724 /* LUN: */ -#define IDT_1726 1726 /* Sectors: */ -#define IDT_1727 1727 /* Heads: */ -#define IDT_1728 1728 /* Cylinders: */ -#define IDT_1729 1729 /* Size (MB): */ -#define IDT_1730 1730 /* Type: */ -#define IDT_1731 1731 /* File name: */ -#define IDT_1737 1737 /* Floppy drives: */ -#define IDT_1738 1738 /* Type: */ -#define IDT_1739 1739 /* CD-ROM drives: */ -#define IDT_1740 1740 /* Bus: */ -#define IDT_1741 1741 /* ID: */ -#define IDT_1742 1742 /* LUN: */ -#define IDT_1743 1743 /* Channel: */ -#define IDT_STEXT 1744 /* text in status window */ -#define IDT_SDEVICE 1745 /* text in status window */ -#define IDT_1746 1746 /* Gain */ -#define IDT_1749 1749 /* File name: */ -#define IDT_1750 1750 /* Disk size: */ -#define IDT_1751 1751 /* RPM mode: */ -#define IDT_1752 1752 /* Progress: */ -#define IDT_1753 1753 /* Bus: */ -#define IDT_1754 1754 /* ID: */ -#define IDT_1755 1755 /* LUN: */ -#define IDT_1756 1756 /* Channel: */ -#define IDT_1757 1757 /* Progress: */ -#define IDT_1758 1758 /* Speed: */ -#define IDT_1759 1759 /* ZIP drives: */ -#define IDT_1763 1763 /* Board #1: */ -#define IDT_1764 1764 /* Board #2: */ -#define IDT_1765 1765 /* Board #3: */ -#define IDT_1766 1766 /* Board #4: */ -#define IDT_1767 1767 /* ISA RTC: */ -#define IDT_1768 1768 /* Ext FD Controller: */ +/* DLG_SND_GAIN */ +#define IDT_GAIN 1700 /* Gain */ + +/* DLG_NEW_FLOPPY */ +#define IDT_FLP_FILE_NAME 1701 /* File name: */ +#define IDT_FLP_DISK_SIZE 1702 /* Disk size: */ +#define IDT_FLP_RPM_MODE 1703 /* RPM mode: */ +#define IDT_FLP_PROGRESS 1704 /* Progress: */ + +/* DLG_SPECIFY_DIM */ +#define IDT_WIDTH 1705 /* ??? */ +#define IDT_HEIGHT 1706 /* ??? */ + +/* DLG_CFG_MACHINE */ +#define IDT_MACHINE_TYPE 1707 /* Machine type: */ +#define IDT_MACHINE 1708 /* Machine: */ +#define IDT_CPU_TYPE 1709 /* CPU type: */ +#define IDT_CPU_SPEED 1710 /* CPU speed: */ +#define IDT_FPU 1711 /* FPU: */ +#define IDT_WAIT_STATES 1712 /* Wait states: */ +#define IDT_MB 1713 /* MB == IDC_TEXT_MB */ +#define IDT_MEMORY 1714 /* Memory: */ + +/* DLG_CFG_VIDEO */ +#define IDT_VIDEO 1715 /* Video: */ + +/* DLG_CFG_INPUT */ +#define IDT_MOUSE 1716 /* Mouse: */ +#define IDT_JOYSTICK 1717 /* Joystick: */ + +/* DLG_CFG_SOUND */ +#define IDT_SOUND 1718 /* Sound card: */ +#define IDT_MIDI_OUT 1719 /* MIDI Out Device: */ +#define IDT_MIDI_IN 1720 /* MIDI In Device: */ + +/* DLG_CFG_NETWORK */ +#define IDT_NET_TYPE 1721 /* Network type: */ +#define IDT_PCAP 1722 /* PCap device: */ +#define IDT_NET 1723 /* Network adapter: */ + +/* DLG_CFG_PORTS */ +#define IDT_COM1 1724 /* COM1 Device: */ +#define IDT_COM2 1725 /* COM1 Device: */ +#define IDT_COM3 1726 /* COM1 Device: */ +#define IDT_COM4 1727 /* COM1 Device: */ + +#define IDT_LPT1 1728 /* LPT1 Device: */ +#define IDT_LPT2 1729 /* LPT2 Device: */ +#define IDT_LPT3 1730 /* LPT3 Device: */ +#define IDT_LPT4 1731 /* LPT4 Device: */ + +/* DLG_CFG_STORAGE */ +#define IDT_HDC 1732 /* HD Controller: */ +#define IDT_FDC 1733 /* Ext FD Controller: */ +#define IDT_SCSI_1 1734 /* SCSI Board #1: */ +#define IDT_SCSI_2 1735 /* SCSI Board #2: */ +#define IDT_SCSI_3 1736 /* SCSI Board #3: */ +#define IDT_SCSI_4 1737 /* SCSI Board #4: */ + +/* DLG_CFG_HARD_DISKS */ +#define IDT_HDD 1738 /* Hard disks: */ +#define IDT_BUS 1739 /* Bus: */ +#define IDT_CHANNEL 1740 /* Channel: */ +#define IDT_ID 1741 /* ID: */ +#define IDT_LUN 1742 /* LUN: */ + +/* DLG_CFG_HARD_DISKS_ADD */ +#define IDT_SECTORS 1743 /* Sectors: */ +#define IDT_HEADS 1744 /* Heads: */ +#define IDT_CYLS 1745 /* Cylinders: */ +#define IDT_SIZE_MB 1746 /* Size (MB): */ +#define IDT_TYPE 1747 /* Type: */ +#define IDT_FILE_NAME 1748 /* File name: */ +#define IDT_IMG_FORMAT 1749 /* Image Format: */ +#define IDT_BLOCK_SIZE 1750 /* Block Size: */ +#define IDT_PROGRESS 1751 /* Progress: */ + +/* DLG_CFG_FLOPPY_AND_CDROM_DRIVES */ +#define IDT_FLOPPY_DRIVES 1752 /* Floppy drives: */ +#define IDT_FDD_TYPE 1753 /* Type: */ +#define IDT_CD_DRIVES 1754 /* CD-ROM drives: */ +#define IDT_CD_BUS 1755 /* Bus: */ +#define IDT_CD_ID 1756 /* ID: */ +#define IDT_CD_LUN 1757 /* LUN: */ +#define IDT_CD_CHANNEL 1758 /* Channel: */ +#define IDT_CD_SPEED 1759 /* Speed: */ + +/* DLG_CFG_OTHER_REMOVABLE_DEVICES */ +#define IDT_MO_DRIVES 1760 /* MO drives: */ +#define IDT_MO_BUS 1761 /* Bus: */ +#define IDT_MO_ID 1762 /* ID: */ +#define IDT_MO_CHANNEL 1763 /* Channel */ +#define IDT_MO_TYPE 1764 /* Type: */ + +#define IDT_ZIP_DRIVES 1765 /* ZIP drives: */ +#define IDT_ZIP_BUS 1766 /* Bus: */ +#define IDT_ZIP_ID 1767 /* ID: */ +#define IDT_ZIP_LUN 1768 /* LUN: */ +#define IDT_ZIP_CHANNEL 1769 /* Channel: */ + +/* DLG_CFG_PERIPHERALS */ +#define IDT_ISARTC 1770 /* ISA RTC: */ +#define IDT_ISAMEM_1 1771 /* ISAMEM Board #1: */ +#define IDT_ISAMEM_2 1772 /* ISAMEM Board #2: */ +#define IDT_ISAMEM_3 1773 /* ISAMEM Board #3: */ +#define IDT_ISAMEM_4 1774 /* ISAMEM Board #4: */ /* * To try to keep these organized, we now group the @@ -113,16 +165,12 @@ #define IDC_RADIO_TS_DISABLED 1006 #define IDC_RADIO_TS_LOCAL 1007 #define IDC_RADIO_TS_UTC 1008 -/* Leave this as is until we finally get into localization in 86Box 3.00(?). */ -#if 0 -#define IDC_COMBO_LANG 1009 -#endif #define IDC_COMBO_MACHINE_TYPE 1010 #define IDC_COMBO_MACHINE 1011 /* machine/cpu config */ #define IDC_CONFIGURE_MACHINE 1012 #define IDC_COMBO_CPU_TYPE 1013 -#define IDC_COMBO_CPU 1014 +#define IDC_COMBO_CPU_SPEED 1014 #define IDC_COMBO_FPU 1015 #define IDC_COMBO_WS 1016 #ifdef USE_DYNAREC @@ -130,117 +178,147 @@ #endif #define IDC_MEMTEXT 1018 #define IDC_MEMSPIN 1019 -#define IDC_TEXT_MB IDT_1705 +#define IDC_TEXT_MB IDT_MB -#define IDC_VIDEO 1030 /* video config */ -#define IDC_COMBO_VIDEO 1031 -#define IDC_CHECK_VOODOO 1032 -#define IDC_BUTTON_VOODOO 1033 +#define IDC_VIDEO 1020 /* video config */ +#define IDC_COMBO_VIDEO 1021 +#define IDC_CHECK_VOODOO 1022 +#define IDC_BUTTON_VOODOO 1023 +#define IDC_CHECK_IBM8514 1024 +#define IDC_CHECK_XGA 1025 +#define IDC_BUTTON_XGA 1026 -#define IDC_INPUT 1050 /* input config */ -#define IDC_COMBO_MOUSE 1051 -#define IDC_COMBO_JOYSTICK 1052 -#define IDC_COMBO_JOY 1053 -#define IDC_CONFIGURE_MOUSE 1054 +#define IDC_INPUT 1030 /* input config */ +#define IDC_COMBO_MOUSE 1031 +#define IDC_COMBO_JOYSTICK 1032 +#define IDC_COMBO_JOY 1033 +#define IDC_CONFIGURE_MOUSE 1034 -#define IDC_SOUND 1070 /* sound config */ -#define IDC_COMBO_SOUND 1071 -#define IDC_CHECK_SSI 1072 -#define IDC_CHECK_CMS 1073 -#define IDC_CHECK_GUS 1074 -#define IDC_COMBO_MIDI 1075 -#define IDC_CHECK_MPU401 1076 -#define IDC_CONFIGURE_MPU401 1077 -#define IDC_CHECK_FLOAT 1078 -#define IDC_CONFIGURE_GUS 1079 -#define IDC_COMBO_MIDI_IN 1080 +#define IDC_SOUND 1040 /* sound config */ +#define IDC_COMBO_SOUND 1041 +#define IDC_CHECK_SSI 1042 +#define IDC_CHECK_CMS 1043 +#define IDC_CHECK_GUS 1044 +#define IDC_COMBO_MIDI_OUT 1045 +#define IDC_CHECK_MPU401 1046 +#define IDC_CONFIGURE_MPU401 1047 +#define IDC_CHECK_FLOAT 1048 +#define IDC_CONFIGURE_GUS 1049 +#define IDC_COMBO_MIDI_IN 1050 +#define IDC_CONFIGURE_CMS 1051 +#define IDC_CONFIGURE_SSI 1052 +#define IDC_FM_DRIVER 1053 +#define IDC_RADIO_FM_DRV_NUKED 1054 +#define IDC_RADIO_FM_DRV_YMFM 1055 -#define IDC_COMBO_NET_TYPE 1090 /* network config */ -#define IDC_COMBO_PCAP 1091 -#define IDC_COMBO_NET 1092 +#define IDC_COMBO_NET_TYPE 1060 /* network config */ +#define IDC_COMBO_PCAP 1061 +#define IDC_COMBO_NET 1062 -#define IDC_COMBO_LPT1 1110 /* ports config */ -#define IDC_COMBO_LPT2 1111 -#define IDC_COMBO_LPT3 1112 -#define IDC_CHECK_SERIAL1 1113 -#define IDC_CHECK_SERIAL2 1114 -#define IDC_CHECK_PARALLEL1 1115 -#define IDC_CHECK_PARALLEL2 1116 -#define IDC_CHECK_PARALLEL3 1117 +#define IDC_COMBO_LPT1 1070 /* ports config */ +#define IDC_COMBO_LPT2 1071 +#define IDC_COMBO_LPT3 1072 +#define IDC_COMBO_LPT4 1073 +#define IDC_CHECK_SERIAL1 1074 +#define IDC_CHECK_SERIAL2 1075 +#define IDC_CHECK_SERIAL3 1076 +#define IDC_CHECK_SERIAL4 1077 +#define IDC_CHECK_PARALLEL1 1078 +#define IDC_CHECK_PARALLEL2 1079 +#define IDC_CHECK_PARALLEL3 1080 +#define IDC_CHECK_PARALLEL4 1081 -#define IDC_OTHER_PERIPH 1120 /* other periph config */ -#define IDC_COMBO_SCSI 1121 -#define IDC_CONFIGURE_SCSI 1122 -#define IDC_COMBO_HDC 1123 -#define IDC_CONFIGURE_HDC 1124 -#define IDC_CHECK_IDE_TER 1125 -#define IDC_BUTTON_IDE_TER 1126 -#define IDC_CHECK_IDE_QUA 1127 -#define IDC_BUTTON_IDE_QUA 1128 -#define IDC_CHECK_BUGGER 1129 -#define IDC_CHECK_POSTCARD 1130 -#define IDC_COMBO_ISARTC 1131 -#define IDC_CONFIGURE_ISARTC 1132 -#define IDC_COMBO_FDC 1133 -#define IDC_CONFIGURE_FDC 1134 -#define IDC_GROUP_ISAMEM 1140 -#define IDC_COMBO_ISAMEM_1 1141 -#define IDC_COMBO_ISAMEM_2 1142 -#define IDC_COMBO_ISAMEM_3 1143 -#define IDC_COMBO_ISAMEM_4 1144 -#define IDC_CONFIGURE_ISAMEM_1 1145 -#define IDC_CONFIGURE_ISAMEM_2 1146 -#define IDC_CONFIGURE_ISAMEM_3 1147 -#define IDC_CONFIGURE_ISAMEM_4 1148 +#define IDC_OTHER_PERIPH 1082 /* storage controllers config */ +#define IDC_COMBO_HDC 1083 +#define IDC_CONFIGURE_HDC 1084 +#define IDC_CHECK_IDE_TER 1085 +#define IDC_BUTTON_IDE_TER 1086 +#define IDC_CHECK_IDE_QUA 1087 +#define IDC_BUTTON_IDE_QUA 1088 +#define IDC_GROUP_SCSI 1089 +#define IDC_COMBO_SCSI_1 1090 +#define IDC_COMBO_SCSI_2 1091 +#define IDC_COMBO_SCSI_3 1092 +#define IDC_COMBO_SCSI_4 1093 +#define IDC_CONFIGURE_SCSI_1 1094 +#define IDC_CONFIGURE_SCSI_2 1095 +#define IDC_CONFIGURE_SCSI_3 1096 +#define IDC_CONFIGURE_SCSI_4 1097 +#define IDC_CHECK_CASSETTE 1098 -#define IDC_HARD_DISKS 1150 /* hard disk config */ -#define IDC_LIST_HARD_DISKS 1151 -#define IDC_BUTTON_HDD_ADD_NEW 1152 -#define IDC_BUTTON_HDD_ADD 1153 -#define IDC_BUTTON_HDD_REMOVE 1154 -#define IDC_COMBO_HD_BUS 1155 -#define IDC_COMBO_HD_CHANNEL 1156 -#define IDC_COMBO_HD_ID 1157 -#define IDC_COMBO_HD_LUN 1158 -#define IDC_COMBO_HD_CHANNEL_IDE 1159 +#define IDC_HARD_DISKS 1100 /* hard disks config */ +#define IDC_LIST_HARD_DISKS 1101 +#define IDC_BUTTON_HDD_ADD_NEW 1102 +#define IDC_BUTTON_HDD_ADD 1103 +#define IDC_BUTTON_HDD_REMOVE 1104 +#define IDC_COMBO_HD_BUS 1105 +#define IDC_COMBO_HD_CHANNEL 1106 +#define IDC_COMBO_HD_ID 1107 +#define IDC_COMBO_HD_LUN 1108 +#define IDC_COMBO_HD_CHANNEL_IDE 1109 -#define IDC_EDIT_HD_FILE_NAME 1160 /* add hard disk dialog */ -#define IDC_EDIT_HD_SPT 1161 -#define IDC_EDIT_HD_HPC 1162 -#define IDC_EDIT_HD_CYL 1163 -#define IDC_EDIT_HD_SIZE 1164 -#define IDC_COMBO_HD_TYPE 1165 -#define IDC_PBAR_IMG_CREATE 1166 +#define IDC_EDIT_HD_FILE_NAME 1110 /* add hard disk dialog */ +#define IDC_EDIT_HD_SPT 1111 +#define IDC_EDIT_HD_HPC 1112 +#define IDC_EDIT_HD_CYL 1113 +#define IDC_EDIT_HD_SIZE 1114 +#define IDC_COMBO_HD_TYPE 1115 +#define IDC_PBAR_IMG_CREATE 1116 +#define IDC_COMBO_HD_IMG_FORMAT 1117 +#define IDC_COMBO_HD_BLOCK_SIZE 1118 -#define IDC_REMOV_DEVICES 1170 /* removable dev config */ -#define IDC_LIST_FLOPPY_DRIVES 1171 -#define IDC_COMBO_FD_TYPE 1172 -#define IDC_CHECKTURBO 1173 -#define IDC_CHECKBPB 1174 -#define IDC_LIST_CDROM_DRIVES 1175 -#define IDC_COMBO_CD_BUS 1176 -#define IDC_COMBO_CD_ID 1177 -#define IDC_COMBO_CD_LUN 1178 -#define IDC_COMBO_CD_CHANNEL_IDE 1179 -#define IDC_LIST_ZIP_DRIVES 1180 -#define IDC_COMBO_ZIP_BUS 1181 -#define IDC_COMBO_ZIP_ID 1182 -#define IDC_COMBO_ZIP_LUN 1183 -#define IDC_COMBO_ZIP_CHANNEL_IDE 1184 -#define IDC_CHECK250 1185 -#define IDC_COMBO_CD_SPEED 1186 -#define IDC_LIST_MO_DRIVES 1187 -#define IDC_COMBO_MO_BUS 1188 -#define IDC_COMBO_MO_ID 1189 -#define IDC_COMBO_MO_LUN 1191 -#define IDC_COMBO_MO_CHANNEL_IDE 1192 +#define IDC_REMOV_DEVICES 1120 /* floppy and cd-rom drives config */ +#define IDC_LIST_FLOPPY_DRIVES 1121 +#define IDC_COMBO_FD_TYPE 1122 +#define IDC_CHECKTURBO 1123 +#define IDC_CHECKBPB 1124 +#define IDC_LIST_CDROM_DRIVES 1125 +#define IDC_COMBO_CD_BUS 1126 +#define IDC_COMBO_CD_ID 1127 +#define IDC_COMBO_CD_LUN 1128 +#define IDC_COMBO_CD_CHANNEL_IDE 1129 -#define IDC_SLIDER_GAIN 1190 /* sound gain dialog */ +#define IDC_LIST_ZIP_DRIVES 1130 /* other removable devices config */ +#define IDC_COMBO_ZIP_BUS 1131 +#define IDC_COMBO_ZIP_ID 1132 +#define IDC_COMBO_ZIP_LUN 1133 +#define IDC_COMBO_ZIP_CHANNEL_IDE 1134 +#define IDC_CHECK250 1135 +#define IDC_COMBO_CD_SPEED 1136 +#define IDC_LIST_MO_DRIVES 1137 +#define IDC_COMBO_MO_BUS 1138 +#define IDC_COMBO_MO_ID 1139 +#define IDC_COMBO_MO_LUN 1140 +#define IDC_COMBO_MO_CHANNEL_IDE 1141 +#define IDC_COMBO_MO_TYPE 1142 + +#define IDC_CHECK_BUGGER 1150 /* other periph config */ +#define IDC_CHECK_POSTCARD 1151 +#define IDC_COMBO_ISARTC 1152 +#define IDC_CONFIGURE_ISARTC 1153 +#define IDC_COMBO_FDC 1154 +#define IDC_CONFIGURE_FDC 1155 +#define IDC_GROUP_ISAMEM 1156 +#define IDC_COMBO_ISAMEM_1 1157 +#define IDC_COMBO_ISAMEM_2 1158 +#define IDC_COMBO_ISAMEM_3 1159 +#define IDC_COMBO_ISAMEM_4 1160 +#define IDC_CONFIGURE_ISAMEM_1 1161 +#define IDC_CONFIGURE_ISAMEM_2 1162 +#define IDC_CONFIGURE_ISAMEM_3 1163 +#define IDC_CONFIGURE_ISAMEM_4 1164 + +#define IDC_SLIDER_GAIN 1170 /* sound gain dialog */ #define IDC_EDIT_FILE_NAME 1200 /* new floppy image dialog */ #define IDC_COMBO_DISK_SIZE 1201 #define IDC_COMBO_RPM_MODE 1202 +#define IDC_COMBO_LANG 1009 /* change language dialog */ +#define IDC_COMBO_ICON 1010 +#define IDC_CHECKBOX_GLOBAL 1300 +#define IDC_BUTTON_DEFAULT 1302 +#define IDC_BUTTON_DEFICON 1304 /* For the DeviceConfig code, re-do later. */ #define IDC_CONFIG_BASE 1300 @@ -252,7 +330,7 @@ #define IDC_CONFIGURE_BUSLOGIC 1305 #define IDC_CONFIGURE_PCAP 1306 #define IDC_CONFIGURE_NET 1307 -#define IDC_CONFIGURE_MIDI 1308 +#define IDC_CONFIGURE_MIDI_OUT 1308 #define IDC_CONFIGURE_MIDI_IN 1309 #define IDC_JOY1 1310 #define IDC_JOY2 1311 @@ -262,36 +340,52 @@ #define IDC_RENDER 1381 #define IDC_STATUS 1382 +#define IDC_EDIT_WIDTH 1400 /* specify main window dimensions dialog */ +#define IDC_WIDTHSPIN 1401 +#define IDC_EDIT_HEIGHT 1402 +#define IDC_HEIGHTSPIN 1403 +#define IDC_CHECK_LOCK_SIZE 1404 #define IDM_ABOUT 40001 #define IDC_ABOUT_ICON 65535 -#define IDM_ACTION_RCTRL_IS_LALT 40010 -#define IDM_ACTION_SCREENSHOT 40011 -#define IDM_ACTION_HRESET 40012 -#define IDM_ACTION_RESET_CAD 40013 -#define IDM_ACTION_EXIT 40014 -#define IDM_ACTION_CTRL_ALT_ESC 40015 -#define IDM_ACTION_PAUSE 40016 +#define IDM_ACTION_KBD_REQ_CAPTURE 40010 +#define IDM_ACTION_RCTRL_IS_LALT 40011 +#define IDM_ACTION_SCREENSHOT 40012 +#define IDM_ACTION_HRESET 40013 +#define IDM_ACTION_RESET_CAD 40014 +#define IDM_ACTION_EXIT 40015 +#define IDM_ACTION_CTRL_ALT_ESC 40016 +#define IDM_ACTION_PAUSE 40017 +#ifdef MTR_ENABLED +#define IDM_ACTION_BEGIN_TRACE 40018 +#define IDM_ACTION_END_TRACE 40019 +#define IDM_ACTION_TRACE 40020 +#endif #define IDM_CONFIG 40020 -#define IDM_CONFIG_LOAD 40021 -#define IDM_CONFIG_SAVE 40022 +#define IDM_VID_HIDE_STATUS_BAR 40021 +#define IDM_VID_HIDE_TOOLBAR 40022 #define IDM_UPDATE_ICONS 40030 +#define IDM_SND_GAIN 40031 #define IDM_VID_RESIZE 40040 #define IDM_VID_REMEMBER 40041 #define IDM_VID_SDL_SW 40050 #define IDM_VID_SDL_HW 40051 +#define IDM_VID_SDL_OPENGL 40052 +#define IDM_VID_OPENGL_CORE 40053 #ifdef USE_VNC -#define IDM_VID_VNC 40052 +#define IDM_VID_VNC 40054 #endif #define IDM_VID_SCALE_1X 40055 #define IDM_VID_SCALE_2X 40056 #define IDM_VID_SCALE_3X 40057 #define IDM_VID_SCALE_4X 40058 +#define IDM_VID_HIDPI 40059 #define IDM_VID_FULLSCREEN 40060 #define IDM_VID_FS_FULL 40061 #define IDM_VID_FS_43 40062 #define IDM_VID_FS_KEEPRATIO 40063 #define IDM_VID_FS_INT 40064 +#define IDM_VID_SPECIFY_DIM 40065 #define IDM_VID_FORCE43 40066 #define IDM_VID_OVERSCAN 40067 #define IDM_VID_INVERT 40069 @@ -304,52 +398,66 @@ #define IDM_VID_GRAY_AMBER 40082 #define IDM_VID_GRAY_GREEN 40083 #define IDM_VID_GRAY_WHITE 40084 +#define IDM_VID_FILTER_NEAREST 40085 +#define IDM_VID_FILTER_LINEAR 40086 -#define IDM_MEDIA 40085 +#define IDM_MEDIA 40087 +#define IDM_DOCS 40088 -#ifdef USE_DISCORD #define IDM_DISCORD 40090 -#endif -#define IDM_LOG_BREAKPOINT 51201 -#define IDM_DUMP_VRAM 51202 // should be an Action +#define IDM_PREFERENCES 40091 -#define IDM_LOG_SERIAL 51211 -#define IDM_LOG_D86F 51212 -#define IDM_LOG_FDC 51213 -#define IDM_LOG_IDE 51214 -#define IDM_LOG_CDROM 51215 -#define IDM_LOG_NIC 51216 -#define IDM_LOG_BUSLOGIC 51217 +#define IDM_VID_GL_FPS_BLITTER 40100 +#define IDM_VID_GL_FPS_25 40101 +#define IDM_VID_GL_FPS_30 40102 +#define IDM_VID_GL_FPS_50 40103 +#define IDM_VID_GL_FPS_60 40104 +#define IDM_VID_GL_FPS_75 40105 +#define IDM_VID_GL_VSYNC 40106 +#define IDM_VID_GL_SHADER 40107 +#define IDM_VID_GL_NOSHADER 40108 /* * We need 7 bits for CDROM (2 bits ID and 5 bits for host drive), * and 5 bits for Removable Disks (5 bits for ID), so we use an * 8bit (256 entries) space for these devices. */ -#define IDM_FLOPPY_IMAGE_NEW 0x1200 -#define IDM_FLOPPY_IMAGE_EXISTING 0x1300 -#define IDM_FLOPPY_IMAGE_EXISTING_WP 0x1400 -#define IDM_FLOPPY_EXPORT_TO_86F 0x1500 -#define IDM_FLOPPY_EJECT 0x1600 +#define IDM_CASSETTE_IMAGE_NEW 0x1200 +#define IDM_CASSETTE_IMAGE_EXISTING 0x1300 +#define IDM_CASSETTE_IMAGE_EXISTING_WP 0x1400 +#define IDM_CASSETTE_RECORD 0x1500 +#define IDM_CASSETTE_PLAY 0x1600 +#define IDM_CASSETTE_REWIND 0x1700 +#define IDM_CASSETTE_FAST_FORWARD 0x1800 +#define IDM_CASSETTE_EJECT 0x1900 -#define IDM_CDROM_MUTE 0x2200 -#define IDM_CDROM_EMPTY 0x2300 -#define IDM_CDROM_RELOAD 0x2400 -#define IDM_CDROM_IMAGE 0x2500 -#define IDM_CDROM_HOST_DRIVE 0x2600 +#define IDM_CARTRIDGE_IMAGE 0x2200 +#define IDM_CARTRIDGE_EJECT 0x2300 -#define IDM_ZIP_IMAGE_NEW 0x3200 -#define IDM_ZIP_IMAGE_EXISTING 0x3300 -#define IDM_ZIP_IMAGE_EXISTING_WP 0x3400 -#define IDM_ZIP_EJECT 0x3500 -#define IDM_ZIP_RELOAD 0x3600 +#define IDM_FLOPPY_IMAGE_NEW 0x3200 +#define IDM_FLOPPY_IMAGE_EXISTING 0x3300 +#define IDM_FLOPPY_IMAGE_EXISTING_WP 0x3400 +#define IDM_FLOPPY_EXPORT_TO_86F 0x3500 +#define IDM_FLOPPY_EJECT 0x3600 -#define IDM_MO_IMAGE_NEW 0x4200 -#define IDM_MO_IMAGE_EXISTING 0x4300 -#define IDM_MO_IMAGE_EXISTING_WP 0x4400 -#define IDM_MO_EJECT 0x4500 -#define IDM_MO_RELOAD 0x4600 +#define IDM_CDROM_MUTE 0x4200 +#define IDM_CDROM_EMPTY 0x4300 +#define IDM_CDROM_RELOAD 0x4400 +#define IDM_CDROM_IMAGE 0x4500 +#define IDM_CDROM_HOST_DRIVE 0x4600 + +#define IDM_ZIP_IMAGE_NEW 0x5200 +#define IDM_ZIP_IMAGE_EXISTING 0x5300 +#define IDM_ZIP_IMAGE_EXISTING_WP 0x5400 +#define IDM_ZIP_EJECT 0x5500 +#define IDM_ZIP_RELOAD 0x5600 + +#define IDM_MO_IMAGE_NEW 0x6200 +#define IDM_MO_IMAGE_EXISTING 0x6300 +#define IDM_MO_IMAGE_EXISTING_WP 0x6400 +#define IDM_MO_EJECT 0x6500 +#define IDM_MO_RELOAD 0x6600 /* Next default values for new objects */ diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index d102d210d..30c7c0561 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -13,10 +13,10 @@ * Author: Fred N. van Kempen, * Copyright 2018,2019 Fred N. van Kempen. */ + #ifndef EMU_ROM_H # define EMU_ROM_H - #define FLAG_INT 1 #define FLAG_INV 2 #define FLAG_AUX 4 @@ -41,31 +41,51 @@ typedef struct { } rom_t; +typedef struct rom_path_t { + char path[1024]; + struct rom_path_t* next; +} rom_path_t; + +extern rom_path_t rom_paths; + +extern void rom_add_path(const char* path); + extern uint8_t rom_read(uint32_t addr, void *p); extern uint16_t rom_readw(uint32_t addr, void *p); extern uint32_t rom_readl(uint32_t addr, void *p); -extern FILE *rom_fopen(wchar_t *fn, wchar_t *mode); -extern int rom_getfile(wchar_t *fn, wchar_t *s, int size); -extern int rom_present(wchar_t *fn); +extern FILE *rom_fopen(char *fn, char *mode); +extern int rom_getfile(char *fn, char *s, int size); +extern int rom_present(char *fn); -extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, +extern int rom_load_linear_oddeven(char *fn, uint32_t addr, int sz, + int off, uint8_t *ptr); +extern int rom_load_linear(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr); -extern int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, +extern int rom_load_interleaved(char *fnl, char *fnh, uint32_t addr, int sz, int off, uint8_t *ptr); -extern int bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, - int off, int flags); -extern int bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, - int sz, int off); -extern int bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, - wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, - int sz, int off); +extern uint8_t bios_read(uint32_t addr, void *priv); +extern uint16_t bios_readw(uint32_t addr, void *priv); +extern uint32_t bios_readl(uint32_t addr, void *priv); -extern int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, +extern int bios_load(char *fn1, char *fn2, uint32_t addr, int sz, + int off, int flags); +extern int bios_load_linear_combined(char *fn1, char *fn2, + int sz, int off); +extern int bios_load_linear_combined2(char *fn1, char *fn2, + char *fn3, char *fn4, char *fn5, + int sz, int off); +extern int bios_load_linear_combined2_ex(char *fn1, char *fn2, + char *fn3, char *fn4, char *fn5, + int sz, int off); + +extern int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); -extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, - wchar_t *fn_high, uint32_t address, +extern int rom_init_oddeven(rom_t *rom, char *fn, uint32_t address, int size, + int mask, int file_offset, uint32_t flags); +extern int rom_init_interleaved(rom_t *rom, char *fn_low, + char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); diff --git a/src/include/86box/scsi.h b/src/include/86box/scsi.h index 364c2c60a..03de1a4ac 100644 --- a/src/include/86box/scsi.h +++ b/src/include/86box/scsi.h @@ -19,12 +19,11 @@ * Copyright 2017,2018 Fred N. van Kempen. */ #ifndef EMU_SCSI_H -#define EMU_SCSI_H +# define EMU_SCSI_H -extern int scsi_card_current; +extern int scsi_card_current[4]; extern int scsi_card_available(int card); -extern char *scsi_card_getname(int card); #ifdef EMU_DEVICE_H extern const device_t *scsi_card_getdevice(int card); #endif diff --git a/src/include/86box/scsi_aha154x.h b/src/include/86box/scsi_aha154x.h index e7b3d62c0..6a98d100e 100644 --- a/src/include/86box/scsi_aha154x.h +++ b/src/include/86box/scsi_aha154x.h @@ -5,9 +5,9 @@ extern const device_t aha154xa_device; extern const device_t aha154xb_device; extern const device_t aha154xc_device; extern const device_t aha154xcf_device; +extern const device_t aha154xcp_device; extern const device_t aha1640_device; extern void aha_device_reset(void *p); - - + #endif /*SCSI_AHA154X_H*/ diff --git a/src/include/86box/scsi_buslogic.h b/src/include/86box/scsi_buslogic.h index 203e45e12..fa075d964 100644 --- a/src/include/86box/scsi_buslogic.h +++ b/src/include/86box/scsi_buslogic.h @@ -19,15 +19,15 @@ #ifndef SCSI_BUSLOGIC_H # define SCSI_BUSLOGIC_H - -extern const device_t buslogic_542b_1991_device; -extern const device_t buslogic_device; +extern const device_t buslogic_542b_device; extern const device_t buslogic_545s_device; +extern const device_t buslogic_542bh_device; +extern const device_t buslogic_545c_device; extern const device_t buslogic_640a_device; extern const device_t buslogic_445s_device; -extern const device_t buslogic_pci_device; +extern const device_t buslogic_445c_device; +extern const device_t buslogic_958d_pci_device; extern void BuslogicDeviceReset(void *p); - - + #endif /*SCSI_BUSLOGIC_H*/ diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index 00f263ad6..fac93eada 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -15,10 +15,10 @@ * * Copyright 2018,2019 Miran Grca. */ + #ifndef EMU_SCSI_CDROM_H #define EMU_SCSI_CDROM_H - #define CDROM_TIME 10.0 @@ -36,8 +36,8 @@ typedef struct { uint8_t status, phase, error, id, - features, pad0, - pad1, pad2; + features, cur_lun, + pad0, pad1; uint16_t request_length, max_transfer_len; diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index d9b39ffe2..6b6600d8e 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -16,14 +16,18 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ + #ifndef SCSI_DEVICE_H # define SCSI_DEVICE_H - /* Configuration. */ +#define SCSI_BUS_MAX 4 /* currently we support up to 4 controllers */ + #define SCSI_ID_MAX 16 /* 16 on wide buses */ #define SCSI_LUN_MAX 8 /* always 8 */ +#define SCSI_LUN_USE_CDB 0xff + #ifdef WALTJE #define SCSI_TIME 50.0 #else @@ -193,8 +197,8 @@ #define CD_FRAMES 75 /* frames per second */ #define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ #define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) -#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) - +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + /* Event notification classes for GET EVENT STATUS NOTIFICATION */ #define GESN_NO_EVENTS 0 #define GESN_OPERATIONAL_CHANGE 1 @@ -320,7 +324,7 @@ typedef struct scsi_common_s { uint8_t status, phase, error, id, - features, pad, + features, cur_lun, pad0, pad1; uint16_t request_length, max_transfer_len; @@ -336,7 +340,7 @@ typedef struct scsi_common_s { double callback; } scsi_common_t; -typedef struct { +typedef struct { int32_t buffer_length; uint8_t status, phase; @@ -357,7 +361,7 @@ typedef struct { #define SCSI_REMOVABLE_DISK 0x8000 #define SCSI_REMOVABLE_CDROM 0x8005 -extern scsi_device_t scsi_devices[SCSI_ID_MAX]; +extern scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX]; extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); @@ -378,7 +382,11 @@ extern int scsi_device_cdb_length(scsi_device_t *dev); extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb); extern void scsi_device_command_phase1(scsi_device_t *dev); extern void scsi_device_command_stop(scsi_device_t *dev); +extern void scsi_device_identify(scsi_device_t *dev, uint8_t lun); extern void scsi_device_close_all(void); extern void scsi_device_init(void); +extern void scsi_reset(void); +extern uint8_t scsi_get_bus(void); + #endif /*SCSI_DEVICE_H*/ diff --git a/src/include/86box/scsi_disk.h b/src/include/86box/scsi_disk.h index 86245f625..bb782a098 100644 --- a/src/include/86box/scsi_disk.h +++ b/src/include/86box/scsi_disk.h @@ -12,6 +12,8 @@ * Copyright 2017,2018 Miran Grca. */ +#ifndef SCSI_DISK_H +# define SCSI_DISK_H typedef struct { mode_sense_pages_t ms_pages_saved; @@ -26,8 +28,8 @@ typedef struct { uint8_t status, phase, error, id, - pad0, pad1, - pad2, pad3; + pad0, cur_lun, + pad1, pad2; uint16_t request_length, pad4; @@ -48,3 +50,5 @@ extern scsi_disk_t *scsi_disk[HDD_NUM]; extern void scsi_disk_hard_reset(void); extern void scsi_disk_close(void); + +#endif /*SCSI_DISK_H*/ diff --git a/src/include/86box/scsi_ncr5380.h b/src/include/86box/scsi_ncr5380.h index aa1f4ad89..5f6ded14b 100644 --- a/src/include/86box/scsi_ncr5380.h +++ b/src/include/86box/scsi_ncr5380.h @@ -20,16 +20,18 @@ * Copyright 2017-2018 TheCollector1995. * Copyright 2017,2018 Fred N. van Kempen. */ + #ifndef SCSI_NCR5380_H # define SCSI_NCR5380_H - extern const device_t scsi_lcs6821n_device; extern const device_t scsi_rt1000b_device; +extern const device_t scsi_rt1000mc_device; +extern const device_t scsi_t128_device; extern const device_t scsi_t130b_device; +extern const device_t scsi_ls2000_device; #if defined(DEV_BRANCH) && defined(USE_SUMO) extern const device_t scsi_scsiat_device; #endif - #endif /*SCSI_NCR5380_H*/ diff --git a/src/include/86box/scsi_ncr53c8xx.h b/src/include/86box/scsi_ncr53c8xx.h index 423f8648e..ee5dcb58f 100644 --- a/src/include/86box/scsi_ncr53c8xx.h +++ b/src/include/86box/scsi_ncr53c8xx.h @@ -21,15 +21,17 @@ * Copyright 2009-2018 Artyom Tarasenko. * Copyright 2017,2018 Miran Grca. */ + #ifndef SCSI_NCR53C8XX_H # define SCSI_NCR53C8XX_H - extern const device_t ncr53c810_pci_device; extern const device_t ncr53c810_onboard_pci_device; +extern const device_t ncr53c815_pci_device; +extern const device_t ncr53c820_pci_device; extern const device_t ncr53c825a_pci_device; extern const device_t ncr53c860_pci_device; extern const device_t ncr53c875_pci_device; - + #endif /*SCSI_NCR53C8XX_H*/ diff --git a/src/include/86box/scsi_pcscsi.h b/src/include/86box/scsi_pcscsi.h new file mode 100644 index 000000000..e188f8f0e --- /dev/null +++ b/src/include/86box/scsi_pcscsi.h @@ -0,0 +1,31 @@ +/* + * 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 AMD PCscsi and Tekram DC-390 SCSI + * controllers using the NCR 53c9x series of chips. + * + * + * + * + * Authors: Fabrice Bellard (QEMU) + * Herve Poussineau (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2005-2018 Fabrice Bellard. + * Copyright 2012-2018 Herve Poussineau. + * Copyright 2017,2018 Miran Grca. + */ + +#ifndef SCSI_PCSCSI_H +# define SCSI_PCSCSI_H + +extern const device_t dc390_pci_device; +extern const device_t ncr53c90_mca_device; + +#endif /*SCSI_BUSLOGIC_H*/ diff --git a/src/include/86box/scsi_spock.h b/src/include/86box/scsi_spock.h index 959fe3d04..7f9c24b78 100644 --- a/src/include/86box/scsi_spock.h +++ b/src/include/86box/scsi_spock.h @@ -17,9 +17,10 @@ * Copyright 2020 Sarah Walker. * Copyright 2020 TheCollector1995. */ + #ifndef SCSI_SPOCK_H # define SCSI_SPOCK_H extern const device_t spock_device; - -#endif /*SCSI_SPOCK_H*/ \ No newline at end of file + +#endif /*SCSI_SPOCK_H*/ diff --git a/src/include/86box/scsi_x54x.h b/src/include/86box/scsi_x54x.h index 6c8164902..468436a34 100644 --- a/src/include/86box/scsi_x54x.h +++ b/src/include/86box/scsi_x54x.h @@ -20,9 +20,9 @@ * Copyright 2016-2018 Miran Grca. * Copyright 2017,2018 Fred N. van Kempen. */ -#ifndef SCSI_X54X_H -#define SCSI_X54X_H +#ifndef SCSI_X54X_H +# define SCSI_X54X_H #define SCSI_DELAY_TM 1 /* was 50 */ @@ -367,6 +367,7 @@ typedef struct { #define X54X_LBA_BIOS 4 #define X54X_INT_GEOM_WRITABLE 8 #define X54X_MBX_24BIT 16 +#define X54X_ISAPNP 32 typedef struct { /* 32 bytes */ @@ -381,7 +382,7 @@ typedef struct { uint8_t callback_phase :4, callback_sub_phase :4, - scsi_cmd_phase, pad, + scsi_cmd_phase, bus, sync, parity, shram_mode, Geometry, Control, @@ -401,7 +402,8 @@ typedef struct { CmdBuf[128], DataBuf[65536], shadow_ram[128], - dma_buffer[128]; + dma_buffer[128], + cmd_33_buf[4096]; /* 16 bytes */ char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ @@ -415,7 +417,11 @@ typedef struct { rom_ioaddr, /* offset in BIOS of I/O addr */ rom_shram, /* index to shared RAM */ rom_shramsz, /* size of shared RAM */ - rom_fwhigh; /* offset in BIOS of ver ID */ + rom_fwhigh, /* offset in BIOS of ver ID */ + pnp_len, /* length of the PnP ROM */ + pnp_offset, /* offset in the microcode ROM of the PnP ROM */ + cmd_33_len, /* length of the SCSISelect code decompressor program */ + cmd_33_offset; /* offset in the microcode ROM of the SCSISelect code decompressor program */ /* 16 + 20 + 52 = 88 bytes */ volatile int @@ -423,7 +429,7 @@ typedef struct { PendingInterrupt, Lock, target_data_len, pad0; - uint32_t Base, fdc_address, rom_addr, /* address of BIOS ROM */ + uint32_t Base, fdc_address, rom_addr, /* address of BIOS ROM */ CmdParamLeft, Outgoing, transfer_size; @@ -435,7 +441,7 @@ typedef struct { BIOSMailboxInit, BIOSMailboxCount, BIOSMailboxOutAddr, BIOSMailboxOutPosCur, BIOSMailboxReq, - Residue, bus; /* Basically a copy of device flags */ + Residue, card_bus; /* Basically a copy of device flags */ /* 8 bytes */ uint64_t temp_period; @@ -444,7 +450,8 @@ typedef struct { double media_period, ha_bps; /* bytes per second */ /* 8 bytes */ - wchar_t *bios_path, /* path to BIOS image file */ + char *bios_path, /* path to BIOS image file */ + *mcode_path, /* path to microcode image file, needed by the AHA-1542CP */ *nvr_path; /* path to NVR image file */ /* 56 bytes */ @@ -486,7 +493,7 @@ typedef struct { pc_timer_t timer, ResetCB; Req_t Req; - + fdc_t *fdc; } x54x_t; @@ -504,5 +511,4 @@ extern void *x54x_init(const device_t *info); extern void x54x_close(void *priv); extern void x54x_device_reset(void *priv); - #endif diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index 90159cfae..3378a91b5 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -6,7 +6,8 @@ * * This file is part of the 86Box distribution. * - * Definitions for the NS8250/16450/16550 UART emulation. + * Definitions for the NS8250/16450/16550/16650/16750/16850/16950 + * UART emulation. * * * @@ -18,20 +19,30 @@ * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. */ + #ifndef EMU_SERIAL_H # define EMU_SERIAL_H - -#define SERIAL_8250 0 +#define SERIAL_8250 0 #define SERIAL_8250_PCJR 1 -#define SERIAL_NS16450 2 -#define SERIAL_NS16550 3 +#define SERIAL_16450 2 +#define SERIAL_16550 3 +#define SERIAL_16650 4 +#define SERIAL_16750 5 +#define SERIAL_16850 6 +#define SERIAL_16950 7 + +#define SERIAL_FIFO_SIZE 16 /* Default settings for the standard ports. */ -#define SERIAL1_ADDR 0x03f8 -#define SERIAL1_IRQ 4 -#define SERIAL2_ADDR 0x02f8 -#define SERIAL2_IRQ 3 +#define COM1_ADDR 0x03f8 +#define COM1_IRQ 4 +#define COM2_ADDR 0x02f8 +#define COM2_IRQ 3 +#define COM3_ADDR 0x03e8 +#define COM3_IRQ 4 +#define COM4_ADDR 0x02e8 +#define COM4_IRQ 3 struct serial_device_s; @@ -50,7 +61,7 @@ typedef struct serial_s uint8_t rcvr_fifo_pos, xmit_fifo_pos, pad0, pad1, - rcvr_fifo[16], xmit_fifo[16]; + rcvr_fifo[SERIAL_FIFO_SIZE], xmit_fifo[SERIAL_FIFO_SIZE]; pc_timer_t transmit_timer, timeout_timer; double clock_src, transmit_period; @@ -73,17 +84,21 @@ extern serial_t * serial_attach(int port, void *priv); extern void serial_remove(serial_t *dev); extern void serial_set_type(serial_t *dev, int type); -extern void serial_setup(serial_t *dev, uint16_t addr, int irq); +extern void serial_setup(serial_t *dev, uint16_t addr, uint8_t irq); extern void serial_clear_fifo(serial_t *dev); extern void serial_write_fifo(serial_t *dev, uint8_t dat); extern void serial_set_next_inst(int ni); extern void serial_standalone_init(void); extern void serial_set_clock_src(serial_t *dev, double clock_src); +extern void serial_reset_port(serial_t *dev); -extern const device_t i8250_device; -extern const device_t i8250_pcjr_device; +extern const device_t ns8250_device; +extern const device_t ns8250_pcjr_device; extern const device_t ns16450_device; extern const device_t ns16550_device; - +extern const device_t ns16650_device; +extern const device_t ns16750_device; +extern const device_t ns16850_device; +extern const device_t ns16950_device; #endif /*EMU_SERIAL_H*/ diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 6e64742b6..e0cf20fe0 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -11,34 +11,78 @@ * Author: Fred N. van Kempen, * Copyright 2017-2020 Fred N. van Kempen. */ + #ifndef EMU_SIO_H # define EMU_SIO_H +extern void vt82c686_sio_write(uint8_t addr, uint8_t val, void *priv); + extern const device_t acc3221_device; +extern const device_t ali5123_device; extern const device_t f82c710_device; +extern const device_t f82c606_device; +extern const device_t fdc37c651_device; +extern const device_t fdc37c651_ide_device; +extern const device_t fdc37c661_device; extern const device_t fdc37c663_device; +extern const device_t fdc37c663_ide_device; extern const device_t fdc37c665_device; +extern const device_t fdc37c665_ide_device; extern const device_t fdc37c666_device; +extern const device_t fdc37c67x_device; extern const device_t fdc37c669_device; +extern const device_t fdc37c669_370_device; +extern const device_t fdc37c931apm_device; +extern const device_t fdc37c931apm_compaq_device; extern const device_t fdc37c932fr_device; extern const device_t fdc37c932qf_device; extern const device_t fdc37c935_device; +extern const device_t fdc37m60x_device; +extern const device_t fdc37m60x_370_device; +extern const device_t it8661f_device; +extern const device_t i82091aa_device; +extern const device_t i82091aa_398_device; +extern const device_t i82091aa_ide_pri_device; +extern const device_t i82091aa_ide_device; extern const device_t pc87306_device; extern const device_t pc87307_device; +extern const device_t pc87307_15c_device; +extern const device_t pc87307_both_device; extern const device_t pc87309_device; +extern const device_t pc87309_15c_device; +extern const device_t pc87310_device; +extern const device_t pc87310_ide_device; +extern const device_t pc87311_device; +extern const device_t pc87311_ide_device; extern const device_t pc87332_device; +extern const device_t pc87332_398_device; +extern const device_t pc87332_398_ide_device; +extern const device_t pc87332_398_ide_sec_device; +extern const device_t pc87332_398_ide_fdcon_device; extern const device_t pc97307_device; +extern const device_t prime3b_device; +extern const device_t prime3b_ide_device; +extern const device_t prime3c_device; +extern const device_t prime3c_ide_device; +extern const device_t ps1_m2133_sio; +#if defined(DEV_BRANCH) && defined(USE_SIO_DETECT) extern const device_t sio_detect_device; +#endif extern const device_t um8669f_device; +extern const device_t via_vt82c686_sio_device; extern const device_t w83787f_device; +extern const device_t w83787f_ide_device; +extern const device_t w83787f_ide_en_device; +extern const device_t w83787f_ide_sec_device; extern const device_t w83877f_device; extern const device_t w83877f_president_device; extern const device_t w83877tf_device; extern const device_t w83877tf_acorp_device; extern const device_t w83977f_device; +extern const device_t w83977f_370_device; extern const device_t w83977tf_device; extern const device_t w83977ef_device; - +extern const device_t w83977ef_370_device; #endif /*EMU_SIO_H*/ diff --git a/src/include/86box/smbus.h b/src/include/86box/smbus.h index 6923a7edb..2a4d4f0ee 100644 --- a/src/include/86box/smbus.h +++ b/src/include/86box/smbus.h @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Definitions for the SMBus handler. + * Definitions for the SMBus host controllers. * * * @@ -14,54 +14,56 @@ * * Copyright 2020 RichardG. */ -#ifndef EMU_SMBUS_H -# define EMU_SMBUS_H + +#ifndef EMU_SMBUS_PIIX4_H +# define EMU_SMBUS_PIIX4_H -extern void smbus_init(void); +#define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 +#define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1) -extern void smbus_sethandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv); - -extern void smbus_removehandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv); - -extern void smbus_handler(int set, uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv); - -extern uint8_t smbus_has_device(uint8_t addr); -extern uint8_t smbus_read_byte(uint8_t addr); -extern uint8_t smbus_read_byte_cmd(uint8_t addr, uint8_t cmd); -extern uint16_t smbus_read_word_cmd(uint8_t addr, uint8_t cmd); -extern uint8_t smbus_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); -extern void smbus_write_byte(uint8_t addr, uint8_t val); -extern void smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val); -extern void smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val); -extern void smbus_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); +#define SMBUS_ALI7101_BLOCK_DATA_SIZE 32 +#define SMBUS_ALI7101_BLOCK_DATA_MASK (SMBUS_ALI7101_BLOCK_DATA_SIZE - 1) -#endif /*EMU_SMBUS_H*/ +enum { + SMBUS_PIIX4 = 0, + SMBUS_VIA +}; + +typedef struct { + uint32_t local; + uint16_t io_base; + int clock; + double bit_period; + uint8_t stat, next_stat, ctl, cmd, addr, + data0, data1, + index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; + pc_timer_t response_timer; + void *i2c; +} smbus_piix4_t; + +typedef struct { + uint32_t local; + uint16_t io_base; + uint8_t stat, next_stat, ctl, cmd, addr, + data0, data1, + index, data[SMBUS_ALI7101_BLOCK_DATA_SIZE]; + pc_timer_t response_timer; + void *i2c; +} smbus_ali7101_t; + +extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); +extern void smbus_piix4_setclock(smbus_piix4_t *dev, int clock); + +extern void smbus_ali7101_remap(smbus_ali7101_t *dev, uint16_t new_io_base, uint8_t enable); + + +#ifdef EMU_DEVICE_H +extern const device_t piix4_smbus_device; +extern const device_t via_smbus_device; + +extern const device_t ali7101_smbus_device; +#endif + +#endif /*EMU_SMBUS_PIIX4_H*/ diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus_piix4.h deleted file mode 100644 index b9f776a5a..000000000 --- a/src/include/86box/smbus_piix4.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * Definitions for the generic PIIX4-compatible SMBus host controller. - * - * - * - * Authors: RichardG, - * - * Copyright 2020 RichardG. - */ -#ifndef EMU_SMBUS_PIIX4_H -# define EMU_SMBUS_PIIX4_H - - -#define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 - - -typedef struct -{ - uint16_t io_base; - uint8_t stat, next_stat, ctl, cmd, addr, - data0, data1, - index, - data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; - pc_timer_t response_timer; -} smbus_piix4_t; - - -extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); - - -#ifdef EMU_DEVICE_H -extern const device_t piix4_smbus_device; -#endif - - -#endif /*EMU_SMBUS_PIIX4_H*/ diff --git a/src/include/86box/smram.h b/src/include/86box/smram.h new file mode 100644 index 000000000..7cc2e1a05 --- /dev/null +++ b/src/include/86box/smram.h @@ -0,0 +1,65 @@ +/* + * 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. + * + * Definitions for the SMRAM interface. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2016-2020 Miran Grca. + */ + +#ifndef EMU_SMRAM_H +# define EMU_SMRAM_H + +typedef struct _smram_ +{ + struct _smram_ *prev, *next; + + mem_mapping_t mapping; + + uint32_t host_base, ram_base, + size, + old_host_base, old_size; +} smram_t; + + +/* Make a backup copy of host_base and size of all the SMRAM structs, needed so that if + the SMRAM mappings change while in SMM, they will be recalculated on return. */ +extern void smram_backup_all(void); +/* Recalculate any mappings, including the backup if returning from SMM. */ +extern void smram_recalc_all(int ret); +/* Delete a SMRAM mapping. */ +extern void smram_del(smram_t *smr); +/* Add a SMRAM mapping. */ +extern smram_t *smram_add(void); +/* Set memory state in the specified model (normal or SMM) according to the specified flags, + separately for bus and CPU. */ +extern void smram_map_ex(int bus, int smm, uint32_t addr, uint32_t size, int is_smram); +/* Set memory state in the specified model (normal or SMM) according to the specified flags. */ +extern void smram_map(int smm, uint32_t addr, uint32_t size, int is_smram); +/* Disable a specific SMRAM mapping. */ +extern void smram_disable(smram_t *smr); +/* Disable all SMRAM mappings. */ +extern void smram_disable_all(void); +/* Enable SMRAM mappings according to flags for both normal and SMM modes, separately for bus + and CPU. */ +extern void smram_enable_ex(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, + int flags_normal, int flags_normal_bus, int flags_smm, int flags_smm_bus); +/* Enable SMRAM mappings according to flags for both normal and SMM modes. */ +extern void smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, + int flags_normal, int flags_smm); +/* Checks if a SMRAM mapping is enabled or not. */ +extern int smram_enabled(smram_t *smr); +/* Changes the SMRAM state. */ +extern void smram_state_change(smram_t *smr, int smm, int flags); +/* Enables or disables the use of a separate SMRAM for addresses below A0000. */ +extern void smram_set_separate_smram(uint8_t set); + +#endif /*EMU_SMRAM_H*/ diff --git a/src/include/86box/snd_ac97.h b/src/include/86box/snd_ac97.h new file mode 100644 index 000000000..600dd84d8 --- /dev/null +++ b/src/include/86box/snd_ac97.h @@ -0,0 +1,151 @@ +/* + * 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. + * + * Definitions for AC'97 audio emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + */ +#ifndef SOUND_AC97_H +#define SOUND_AC97_H + +#define AC97_VENDOR_ID(f, s, t, dev) ((((f) &0xff) << 24) | (((s) &0xff) << 16) | (((t) &0xff) << 8) | ((dev) &0xff)) + +/* Misc support bits (misc_flags). Most of these are not part of any + registers, but control enabling/disabling of registers and bits. */ +#define AC97_MASTER_6B (1 << 0) /* register 02 bits [13,5] (ML5/MR5) */ +#define AC97_AUXOUT (1 << 1) /* register 04 */ +#define AC97_AUXOUT_6B (1 << 2) /* register 04 bits [13,5] (ML5/MR5) */ +#define AC97_MONOOUT (1 << 3) /* register 06 */ +#define AC97_MONOOUT_6B (1 << 4) /* register 06 bit 5 (MM5) */ +#define AC97_PCBEEP (1 << 5) /* register 0A */ +#define AC97_PCBEEP_GEN (1 << 6) /* register 0A bits [12:5] (F[7:0]) */ +#define AC97_PHONE (1 << 9) /* register 0C */ +#define AC97_VIDEO (1 << 10) /* register 14 */ +#define AC97_AUXIN (1 << 11) /* register 16 */ +#define AC97_POP (1 << 15) /* register 20 bit 15 (POP) - definition shared with General Purpose bits */ +#define AC97_MS (1 << 8) /* register 20 bit 8 (MS) - definition shared with General Purpose bits */ +#define AC97_LPBK (1 << 7) /* register 20 bit 7 (LPBK) - definition shared with General Purpose bits */ +#define AC97_DSA (1 << 12) /* register 28 bits [5:4] (DSA[1:0]) */ +#define AC97_LFE_6B (1 << 13) /* register 36 bit 13 (LFE5) */ +#define AC97_CENTER_6B (1 << 14) /* register 36 bit 5 (CNT5) */ +#define AC97_SURR_6B (1 << 16) /* register 38 bits [13,5] (LSR5/RSR5) */ + +/* Reset bits (reset_flags), register 00. */ +#define AC97_MICPCM (1 << 0) +#define AC97_MODEMLINE (1 << 1) +#define AC97_TONECTL (1 << 2) +#define AC97_SIMSTEREO (1 << 3) +#define AC97_HPOUT (1 << 4) +#define AC97_LOUDNESS (1 << 5) +#define AC97_DAC_18B (1 << 6) +#define AC97_DAC_20B (1 << 7) +#define AC97_ADC_18B (1 << 8) +#define AC97_ADC_20B (1 << 9) +#define AC97_3D_SHIFT 10 + +/* Extended Audio ID bits (extid_flags), register 28. */ +#define AC97_VRA (1 << 0) +#define AC97_DRA (1 << 1) +#define AC97_SPDIF (1 << 2) +#define AC97_VRM (1 << 3) +#define AC97_CDAC (1 << 6) +#define AC97_SDAC (1 << 7) +#define AC97_LDAC (1 << 8) +#define AC97_AMAP (1 << 9) +#define AC97_REV_2_1 (0 << 10) +#define AC97_REV_2_2 (1 << 10) +#define AC97_REV_2_3 (2 << 10) +#define AC97_REV_MASK (3 << 10) + +/* Volume bits. */ +#define AC97_MUTE (1 << 15) +#define AC97_MUTE_L (1 << 15) +#define AC97_MUTE_R (1 << 7) + +/* General Purpose bits, register 20. */ +/* POP already defined */ +#define AC97_ST (1 << 14) +#define AC97_3D (1 << 13) +#define AC97_LD (1 << 12) +#define AC97_DRSS_MASK (3 << 10) +#define AC97_MIX (1 << 9) +/* MS already defined */ +/* LPBK already defined */ + +/* Extended Audio Status/Control bits, register 2A. */ +#define AC97_SPSA_SHIFT 4 +#define AC97_SPSA_MASK 3 +#define AC97_MADC (1 << 9) +#define AC97_SPCV (1 << 10) +#define AC97_PRI (1 << 11) +#define AC97_PRJ (1 << 12) +#define AC97_PRK (1 << 13) +#define AC97_PRL (1 << 14) + +/* New codecs should be added to the end of this enum to avoid breaking configs. */ +enum { + AC97_CODEC_AD1881 = 0, + AC97_CODEC_ALC100, + AC97_CODEC_CS4297, + AC97_CODEC_CS4297A, + AC97_CODEC_WM9701A, + AC97_CODEC_STAC9708, + AC97_CODEC_STAC9721, + AC97_CODEC_AK4540 +}; + +typedef struct { + const uint16_t index, value, write_mask; +} ac97_vendor_reg_t; + +typedef struct { + uint32_t vendor_id, min_rate, max_rate, misc_flags; + uint16_t reset_flags, extid_flags, + powerdown_mask, regs[64]; + uint8_t codec_id, vendor_reg_page_max; + const ac97_vendor_reg_t *vendor_regs; + uint16_t *vendor_reg_pages; +} ac97_codec_t; + +extern uint16_t ac97_codec_readw(ac97_codec_t *dev, uint8_t reg); +extern void ac97_codec_writew(ac97_codec_t *dev, uint8_t reg, uint16_t val); +extern void ac97_codec_reset(void *priv); +extern void ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r); +extern uint32_t ac97_codec_getrate(void *priv, uint8_t reg); +extern const device_t *ac97_codec_get(int model); + +extern void ac97_via_set_slot(void *priv, int slot, int irq_pin); +extern uint8_t ac97_via_read_status(void *priv, uint8_t modem); +extern void ac97_via_write_control(void *priv, uint8_t modem, uint8_t val); +extern void ac97_via_remap_audio_sgd(void *priv, uint16_t new_io_base, uint8_t enable); +extern void ac97_via_remap_modem_sgd(void *priv, uint16_t new_io_base, uint8_t enable); +extern void ac97_via_remap_audio_codec(void *priv, uint16_t new_io_base, uint8_t enable); +extern void ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable); + +extern ac97_codec_t **ac97_codec, **ac97_modem_codec; +extern int ac97_codec_count, ac97_modem_codec_count, + ac97_codec_id, ac97_modem_codec_id; + +#ifdef EMU_DEVICE_H +extern const device_t ad1881_device; +extern const device_t ak4540_device; +extern const device_t alc100_device; +extern const device_t cs4297_device; +extern const device_t cs4297a_device; +extern const device_t stac9708_device; +extern const device_t stac9721_device; +extern const device_t wm9701a_device; + +extern const device_t ac97_via_device; +#endif + +#endif /*SOUND_AC97_H*/ diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 9c71f084b..f9f73a60c 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -1,42 +1,72 @@ -#define AD1848_TYPE_DEFAULT 0 -#define AD1848_TYPE_CS4248 1 -#define AD1848_TYPE_CS4231 2 +/* + * 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. + * + * Definitions for AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * RichardG, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + * Copyright 2021 RichardG. + */ -typedef struct ad1848_t -{ - int index; - uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ - uint8_t status; - - int trd; - int mce; - - int count; - - int16_t out_l, out_r; - - int enable; +#ifndef SOUND_AD1848_H +#define SOUND_AD1848_H - int irq, dma; - - int freq; - - pc_timer_t timer_count; - uint64_t timer_latch; +enum { + AD1848_TYPE_DEFAULT = 0, + AD1848_TYPE_CS4248, + AD1848_TYPE_CS4231, + AD1848_TYPE_CS4235, + AD1848_TYPE_CS4236 +}; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; - - int type; +typedef struct { + uint8_t type, index, xindex, regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ + + int count; + uint8_t trd, mce, wten : 1; + + int16_t out_l, out_r; + double cd_vol_l, cd_vol_r; + int fm_vol_l, fm_vol_r; + uint8_t fmt_mask, wave_vol_mask; + + uint8_t enable : 1, irq : 4, dma : 3, adpcm_ref; + int8_t adpcm_step; + int freq, adpcm_data, adpcm_pos; + + pc_timer_t timer_count; + uint64_t timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + + void *cram_priv, + (*cram_write)(uint16_t addr, uint8_t val, void *priv); + uint8_t (*cram_read)(uint16_t addr, void *priv); } ad1848_t; -void ad1848_setirq(ad1848_t *ad1848, int irq); -void ad1848_setdma(ad1848_t *ad1848, int dma); +extern void ad1848_setirq(ad1848_t *ad1848, int irq); +extern void ad1848_setdma(ad1848_t *ad1848, int dma); +extern void ad1848_updatevolmask(ad1848_t *ad1848); -uint8_t ad1848_read(uint16_t addr, void *p); -void ad1848_write(uint16_t addr, uint8_t val, void *p); +extern uint8_t ad1848_read(uint16_t addr, void *priv); +extern void ad1848_write(uint16_t addr, uint8_t val, void *priv); -void ad1848_update(ad1848_t *ad1848); -void ad1848_speed_changed(ad1848_t *ad1848); +extern void ad1848_update(ad1848_t *ad1848); +extern void ad1848_speed_changed(ad1848_t *ad1848); +extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv); -void ad1848_init(ad1848_t *ad1848, int type); +extern void ad1848_init(ad1848_t *ad1848, uint8_t type); + +#endif /*SOUND_AD1848_H*/ diff --git a/src/include/86box/snd_azt2316a.h b/src/include/86box/snd_azt2316a.h index 852de6c92..63a0ff243 100644 --- a/src/include/86box/snd_azt2316a.h +++ b/src/include/86box/snd_azt2316a.h @@ -1 +1,6 @@ -extern void azt2316a_enable_wss(uint8_t enable, void *p); \ No newline at end of file +#ifndef SOUND_AZT2316A_H +#define SOUND_AZT2316A_H + +extern void azt2316a_enable_wss(uint8_t enable, void *p); + +#endif /*SOUND_AZT2316A*/ diff --git a/src/include/86box/snd_cms.h b/src/include/86box/snd_cms.h new file mode 100644 index 000000000..0da6fcdab --- /dev/null +++ b/src/include/86box/snd_cms.h @@ -0,0 +1,33 @@ +#ifndef SOUND_CMS_H +#define SOUND_CMS_H + +#include <86box/sound.h> +#include + +#define MASTER_CLOCK 7159090 + +typedef struct cms_t { + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; + + uint8_t latched_data; + + int16_t buffer[SOUNDBUFLEN * 2]; + + int pos; +} cms_t; + +extern void cms_update(cms_t *cms); +extern void cms_write(uint16_t addr, uint8_t val, void *p); +extern uint8_t cms_read(uint16_t addr, void *p); + +#endif /*SOUND_CMS_H*/ diff --git a/src/include/86box/snd_emu8k.h b/src/include/86box/snd_emu8k.h index 16323a13b..a163bdeaf 100644 --- a/src/include/86box/snd_emu8k.h +++ b/src/include/86box/snd_emu8k.h @@ -1,40 +1,42 @@ +#ifndef SOUND_EMU8K_H +#define SOUND_EMU8K_H /* All these defines are in samples, not in bytes. */ -#define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF -#define EMU8K_RAM_MEM_START 0x200000 -#define EMU8K_FM_MEM_ADDRESS 0xFFFFE0 -#define EMU8K_RAM_POINTERS_MASK 0x3F -#define EMU8K_LFOCHORUS_SIZE 0x4000 +#define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF +#define EMU8K_RAM_MEM_START 0x200000 +#define EMU8K_FM_MEM_ADDRESS 0xFFFFE0 +#define EMU8K_RAM_POINTERS_MASK 0x3F +#define EMU8K_LFOCHORUS_SIZE 0x4000 /* * Everything in this file assumes little endian */ /* used for the increment of oscillator position*/ typedef struct emu8k_mem_internal_t { - union { - uint64_t addr; - struct { - uint16_t fract_lw_address; - uint16_t fract_address; - uint32_t int_address; - }; + union { + uint64_t addr; + struct { + uint16_t fract_lw_address; + uint16_t fract_address; + uint32_t int_address; }; + }; } emu8k_mem_internal_t; /* used for access to ram pointers from oscillator position. */ typedef struct emu8k_mem_pointers_t { - union { - uint32_t addr; - struct { - uint16_t lw_address; - uint8_t hb_address; - uint8_t unused_address; - }; + union { + uint32_t addr; + struct { + uint16_t lw_address; + uint8_t hb_address; + uint8_t unused_address; }; + }; } emu8k_mem_pointers_t; /* * From the Soundfount 2.0 fileformat Spec.: - * + * An envelope generates a control signal in six phases. When key-on occurs, a delay period begins during which the envelope value is zero. The envelope then rises in a convex curve to a value of one during the attack phase. @@ -44,25 +46,25 @@ typedef struct emu8k_mem_pointers_t { When a value of one is reached, the envelope enters a hold phase during which it remains at one. When the hold phase ends, the envelope enters a decay phase during which its value decreases linearly to a sustain level. " For the Volume Envelope, the decay phase linearly ramps toward the sustain level, causing a constant dB change for each time unit. " - When the sustain level is reached, the envelope enters sustain phase, during which the envelope stays at the sustain level. - + When the sustain level is reached, the envelope enters sustain phase, during which the envelope stays at the sustain level. + Whenever a key-off occurs, the envelope immediately enters a release phase during which the value linearly ramps from the current value to zero. " For the Volume Envelope, the release phase linearly ramps toward zero from the current level, causing a constant dB change for each time unit" When zero is reached, the envelope value remains at zero. - + Modulation of pitch and filter cutoff are in octaves, semitones, and cents. These parameters can be modulated to varying degree, either positively or negatively, by the modulation envelope. The degree of modulation is specified in cents for the full-scale attack peak. - + The volume envelope operates in dB, with the attack peak providing a full scale output, appropriately scaled by the initial volume. The zero value, however, is actually zero gain. The implementation in the EMU8000 provides for 96 dB of amplitude control. - When 96 dB of attenuation is reached in the final gain amplifier, an abrupt jump to zero gain + When 96 dB of attenuation is reached in the final gain amplifier, an abrupt jump to zero gain (infinite dB of attenuation) occurs. In a 16-bit system, this jump is inaudible */ /* It seems that the envelopes don't really have a decay/release stage, - * but instead they have a volume ramper that can be triggered + * but instead they have a volume ramper that can be triggered * automatically (after hold period), or manually (by activating release) * and the "sustain" value is the target of any of both cases. * Some programs like cubic player and AWEAmp use this, and it was @@ -75,51 +77,48 @@ typedef struct emu8k_mem_pointers_t { * contains the destination volume, and the lower byte contains the ramp time. */ -/* attack_amount is linear amplitude (added directly to value). +/* attack_amount is linear amplitude (added directly to value). * ramp_amount_db is linear dB (added directly to value too, but needs conversion to get linear amplitude). - * value range is 21bits for both, linear amplitude being 1<<21 = 0dBFS and 0 = -96dBFS (which is shortcut to silence), + * value range is 21bits for both, linear amplitude being 1<<21 = 0dBFS and 0 = -96dBFS (which is shortcut to silence), * and db amplutide being 0 = 0dBFS and -(1<<21) = -96dBFS (which is shortcut to silence). * This allows to operate db values by simply adding them. */ typedef struct emu8k_envelope_t { - int state; - int32_t delay_samples, hold_samples, attack_samples; - int32_t value_amp_hz, value_db_oct; - int32_t sustain_value_db_oct; - int32_t attack_amount_amp_hz, ramp_amount_db_oct; + int state; + int32_t delay_samples, hold_samples, attack_samples; + int32_t value_amp_hz, value_db_oct; + int32_t sustain_value_db_oct; + int32_t attack_amount_amp_hz, ramp_amount_db_oct; } emu8k_envelope_t; - - typedef struct emu8k_chorus_eng_t { - int32_t write; - int32_t feedback; - int32_t delay_samples_central; - double lfodepth_multip; - double delay_offset_samples_right; - emu8k_mem_internal_t lfo_inc; - emu8k_mem_internal_t lfo_pos; - - int32_t chorus_left_buffer[EMU8K_LFOCHORUS_SIZE]; - int32_t chorus_right_buffer[EMU8K_LFOCHORUS_SIZE]; + int32_t write; + int32_t feedback; + int32_t delay_samples_central; + double lfodepth_multip; + double delay_offset_samples_right; + emu8k_mem_internal_t lfo_inc; + emu8k_mem_internal_t lfo_pos; + + int32_t chorus_left_buffer[EMU8K_LFOCHORUS_SIZE]; + int32_t chorus_right_buffer[EMU8K_LFOCHORUS_SIZE]; } emu8k_chorus_eng_t; /* 32 * 242. 32 comes from the "right" room resso case.*/ #define MAX_REFL_SIZE 7744 - /* Reverb parameters description, extracted from AST sources. - Mix level - Decay - Link return amp + Mix level + Decay + Link return amp Link type Switches between normal or panned Room reso ( ms) L&R (Ref 6 +1) - Ref 1 x2 (11 ms)R - Ref 2 x4 (22 ms)R - Ref 3 x8 (44 ms)L - Ref 4 x13(71 ms)R - Ref 5 x19(105ms)L + Ref 1 x2 (11 ms)R + Ref 2 x4 (22 ms)R + Ref 3 x8 (44 ms)L + Ref 4 x13(71 ms)R + Ref 5 x19(105ms)L Ref 6 x ( ms)R (multiplier changes with room reso) Ref 1-6 filter L&R Ref 1-6 amp L&R @@ -129,266 +128,260 @@ typedef struct emu8k_chorus_eng_t { Ref 4 feedback L&R Ref 5 feedback L&R Ref 6 feedback L&R -*/ +*/ typedef struct emu8k_reverb_combfilter_t { - int read_pos; - int32_t reflection[MAX_REFL_SIZE]; - float output_gain; - float feedback; - float damp1; - float damp2; - int bufsize; - int32_t filterstore; + int read_pos; + int32_t reflection[MAX_REFL_SIZE]; + float output_gain; + float feedback; + float damp1; + float damp2; + int bufsize; + int32_t filterstore; } emu8k_reverb_combfilter_t; typedef struct emu8k_reverb_eng_t { - int16_t out_mix; - int16_t link_return_amp; /* tail part output gain ? */ - int8_t link_return_type; + int16_t out_mix; + int16_t link_return_amp; /* tail part output gain ? */ + int8_t link_return_type; - uint8_t refl_in_amp; + uint8_t refl_in_amp; - emu8k_reverb_combfilter_t reflections[6]; - emu8k_reverb_combfilter_t allpass[8]; - emu8k_reverb_combfilter_t tailL; - emu8k_reverb_combfilter_t tailR; - - emu8k_reverb_combfilter_t damper; + emu8k_reverb_combfilter_t reflections[6]; + emu8k_reverb_combfilter_t allpass[8]; + emu8k_reverb_combfilter_t tailL; + emu8k_reverb_combfilter_t tailR; + + emu8k_reverb_combfilter_t damper; } emu8k_reverb_eng_t; typedef struct emu8k_slide_t { - int32_t last; + int32_t last; } emu8k_slide_t; +typedef struct emu8k_voice_t { + union { + uint32_t cpf; + struct { + uint16_t cpf_curr_frac_addr; /* fractional part of the playing cursor. */ + uint16_t cpf_curr_pitch; /* 0x4000 = no shift. Linear increment */ + }; + }; + union { + uint32_t ptrx; + struct { + uint8_t ptrx_pan_aux; + uint8_t ptrx_revb_send; + uint16_t ptrx_pit_target; /* target pitch to which slide at curr_pitch speed. */ + }; + }; + union { + uint32_t cvcf; + struct { + uint16_t cvcf_curr_filt_ctoff; + uint16_t cvcf_curr_volume; + }; + }; + emu8k_slide_t volumeslide; + union { + uint32_t vtft; + struct { + uint16_t vtft_filter_target; + uint16_t vtft_vol_target; /* written to by the envelope engine. */ + }; + }; + /* These registers are used at least by the Windows drivers, and seem to be resetting + * something, similarly to targets and current, but... of what? + * what is curious is that if they are already zero, they are not written to, so it really + * looks like they are information about the status of the channel. (lfo position maybe?) */ + uint32_t unknown_data0_4; + uint32_t unknown_data0_5; + union { + uint32_t psst; + struct { + uint16_t psst_lw_address; + uint8_t psst_hw_address; + uint8_t psst_pan; + }; +#define PSST_LOOP_START_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ + }; + union { + uint32_t csl; + struct { + uint16_t csl_lw_address; + uint8_t csl_hw_address; + uint8_t csl_chor_send; + }; +#define CSL_LOOP_END_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ + }; + union { + uint32_t ccca; + struct { + uint16_t ccca_lw_addr; + uint8_t ccca_hb_addr; + uint8_t ccca_qcontrol; + }; + }; +#define CCCA_FILTQ_GET(ccca) (ccca >> 28) +#define CCCA_FILTQ_SET(ccca, q) ccca = (ccca & 0x0FFFFFFF) | (q << 28) +/* Bit 27 should always be zero */ +#define CCCA_DMA_ACTIVE(ccca) (ccca & 0x04000000) +#define CCCA_DMA_WRITE_MODE(ccca) (ccca & 0x02000000) +#define CCCA_DMA_WRITE_RIGHT(ccca) (ccca & 0x01000000) -typedef struct emu8k_voice_t -{ - union { - uint32_t cpf; - struct { - uint16_t cpf_curr_frac_addr; /* fractional part of the playing cursor. */ - uint16_t cpf_curr_pitch; /* 0x4000 = no shift. Linear increment */ - }; - }; - union { - uint32_t ptrx; - struct { - uint8_t ptrx_pan_aux; - uint8_t ptrx_revb_send; - uint16_t ptrx_pit_target; /* target pitch to which slide at curr_pitch speed. */ - }; - }; - union { - uint32_t cvcf; - struct { - uint16_t cvcf_curr_filt_ctoff; - uint16_t cvcf_curr_volume; - }; - }; - emu8k_slide_t volumeslide; - union { - uint32_t vtft; - struct { - uint16_t vtft_filter_target; - uint16_t vtft_vol_target; /* written to by the envelope engine. */ - }; - }; - /* These registers are used at least by the Windows drivers, and seem to be resetting - * something, similarly to targets and current, but... of what? - * what is curious is that if they are already zero, they are not written to, so it really - * looks like they are information about the status of the channel. (lfo position maybe?) */ - uint32_t unknown_data0_4; - uint32_t unknown_data0_5; - union { - uint32_t psst; - struct { - uint16_t psst_lw_address; - uint8_t psst_hw_address; - uint8_t psst_pan; - }; - #define PSST_LOOP_START_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ - }; - union { - uint32_t csl; - struct { - uint16_t csl_lw_address; - uint8_t csl_hw_address; - uint8_t csl_chor_send; - }; - #define CSL_LOOP_END_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ - }; - union { - uint32_t ccca; - struct { - uint16_t ccca_lw_addr; - uint8_t ccca_hb_addr; - uint8_t ccca_qcontrol; - }; - }; - #define CCCA_FILTQ_GET(ccca) (ccca>>28) - #define CCCA_FILTQ_SET(ccca,q) ccca = (ccca&0x0FFFFFFF) | (q<<28) - /* Bit 27 should always be zero */ - #define CCCA_DMA_ACTIVE(ccca) (ccca&0x04000000) - #define CCCA_DMA_WRITE_MODE(ccca) (ccca&0x02000000) - #define CCCA_DMA_WRITE_RIGHT(ccca) (ccca&0x01000000) - - uint16_t envvol; - #define ENVVOL_NODELAY(envol) (envvol&0x8000) - /* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ - #define ENVVOL_TO_EMU_SAMPLES(envvol) (envvol&0x8000) ? 0 : ((0x8000-(envvol&0x7FFF)) <<5) - - uint16_t dcysusv; - #define DCYSUSV_IS_RELEASE(dcysusv) (dcysusv&0x8000) - #define DCYSUSV_GENERATOR_ENGINE_ON(dcysusv) !(dcysusv&0x0080) - #define DCYSUSV_SUSVALUE_GET(dcysusv) ((dcysusv>>8)&0x7F) - /* Inverting the range compared to documentation because the envelope runs from 0dBFS = 0 to -96dBFS = (1 <<21) */ - #define DCYSUSV_SUS_TO_ENV_RANGE(susvalue) (((0x7F-susvalue) << 21)/0x7F) - #define DCYSUSV_DECAYRELEASE_GET(dcysusv) (dcysusv&0x7F) - - uint16_t envval; - #define ENVVAL_NODELAY(enval) (envval&0x8000) - /* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ - #define ENVVAL_TO_EMU_SAMPLES(envval)(envval&0x8000) ? 0 : ((0x8000-(envval&0x7FFF)) <<5) - - uint16_t dcysus; - #define DCYSUS_IS_RELEASE(dcysus) (dcysus&0x8000) - #define DCYSUS_SUSVALUE_GET(dcysus) ((dcysus>>8)&0x7F) - #define DCYSUS_SUS_TO_ENV_RANGE(susvalue) ((susvalue << 21)/0x7F) - #define DCYSUS_DECAYRELEASE_GET(dcysus) (dcysus&0x7F) - - uint16_t atkhldv; - #define ATKHLDV_TRIGGER(atkhldv) !(atkhldv&0x8000) - #define ATKHLDV_HOLD(atkhldv) ((atkhldv>>8)&0x7F) - #define ATKHLDV_HOLD_TO_EMU_SAMPLES(atkhldv) (4096*(0x7F-((atkhldv>>8)&0x7F))) - #define ATKHLDV_ATTACK(atkhldv) (atkhldv&0x7F) - - uint16_t lfo1val, lfo2val; - #define LFOxVAL_NODELAY(lfoxval) (lfoxval&0x8000) - #define LFOxVAL_TO_EMU_SAMPLES(lfoxval) (lfoxval&0x8000) ? 0 : ((0x8000-(lfoxval&0x7FFF)) <<5) - - uint16_t atkhld; - #define ATKHLD_TRIGGER(atkhld) !(atkhld&0x8000) - #define ATKHLD_HOLD(atkhld) ((atkhld>>8)&0x7F) - #define ATKHLD_HOLD_TO_EMU_SAMPLES(atkhld) (4096*(0x7F-((atkhld>>8)&0x7F))) - #define ATKHLD_ATTACK(atkhld) (atkhld&0x7F) - - - uint16_t ip; - #define INTIAL_PITCH_CENTER 0xE000 - #define INTIAL_PITCH_OCTAVE 0x1000 - - union { - uint16_t ifatn; - struct{ - uint8_t ifatn_attenuation; - uint8_t ifatn_init_filter; - }; - }; - union { - uint16_t pefe; - struct { - int8_t pefe_modenv_filter_height; - int8_t pefe_modenv_pitch_height; - }; - }; - union { - uint16_t fmmod; - struct { - int8_t fmmod_lfo1_filt_mod; - int8_t fmmod_lfo1_vibrato; - }; - }; - union { - uint16_t tremfrq; - struct { - uint8_t tremfrq_lfo1_freq; - int8_t tremfrq_lfo1_tremolo; - }; - }; - union { - uint16_t fm2frq2; - struct { - uint8_t fm2frq2_lfo2_freq; - int8_t fm2frq2_lfo2_vibrato; - }; - }; - - int env_engine_on; - - emu8k_mem_internal_t addr, loop_start, loop_end; - - int32_t initial_att; - int32_t initial_filter; + uint16_t envvol; +#define ENVVOL_NODELAY(envol) (envvol & 0x8000) +/* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ +#define ENVVOL_TO_EMU_SAMPLES(envvol) (envvol & 0x8000) ? 0 : ((0x8000 - (envvol & 0x7FFF)) << 5) - emu8k_envelope_t vol_envelope; - emu8k_envelope_t mod_envelope; - - int64_t lfo1_speed, lfo2_speed; - emu8k_mem_internal_t lfo1_count, lfo2_count; - int32_t lfo1_delay_samples, lfo2_delay_samples; - int vol_l, vol_r; + uint16_t dcysusv; +#define DCYSUSV_IS_RELEASE(dcysusv) (dcysusv & 0x8000) +#define DCYSUSV_GENERATOR_ENGINE_ON(dcysusv) !(dcysusv & 0x0080) +#define DCYSUSV_SUSVALUE_GET(dcysusv) ((dcysusv >> 8) & 0x7F) +/* Inverting the range compared to documentation because the envelope runs from 0dBFS = 0 to -96dBFS = (1 <<21) */ +#define DCYSUSV_SUS_TO_ENV_RANGE(susvalue) (((0x7F - susvalue) << 21) / 0x7F) +#define DCYSUSV_DECAYRELEASE_GET(dcysusv) (dcysusv & 0x7F) - int16_t fixed_modenv_filter_height; - int16_t fixed_modenv_pitch_height; - int16_t fixed_lfo1_filt_mod; - int16_t fixed_lfo1_vibrato; - int16_t fixed_lfo1_tremolo; - int16_t fixed_lfo2_vibrato; + uint16_t envval; +#define ENVVAL_NODELAY(enval) (envval & 0x8000) +/* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ +#define ENVVAL_TO_EMU_SAMPLES(envval) (envval & 0x8000) ? 0 : ((0x8000 - (envval & 0x7FFF)) << 5) - /* filter internal data. */ - int filterq_idx; - int32_t filt_att; - int64_t filt_buffer[5]; + uint16_t dcysus; +#define DCYSUS_IS_RELEASE(dcysus) (dcysus & 0x8000) +#define DCYSUS_SUSVALUE_GET(dcysus) ((dcysus >> 8) & 0x7F) +#define DCYSUS_SUS_TO_ENV_RANGE(susvalue) ((susvalue << 21) / 0x7F) +#define DCYSUS_DECAYRELEASE_GET(dcysus) (dcysus & 0x7F) + + uint16_t atkhldv; +#define ATKHLDV_TRIGGER(atkhldv) !(atkhldv & 0x8000) +#define ATKHLDV_HOLD(atkhldv) ((atkhldv >> 8) & 0x7F) +#define ATKHLDV_HOLD_TO_EMU_SAMPLES(atkhldv) (4096 * (0x7F - ((atkhldv >> 8) & 0x7F))) +#define ATKHLDV_ATTACK(atkhldv) (atkhldv & 0x7F) + + uint16_t lfo1val, lfo2val; +#define LFOxVAL_NODELAY(lfoxval) (lfoxval & 0x8000) +#define LFOxVAL_TO_EMU_SAMPLES(lfoxval) (lfoxval & 0x8000) ? 0 : ((0x8000 - (lfoxval & 0x7FFF)) << 5) + + uint16_t atkhld; +#define ATKHLD_TRIGGER(atkhld) !(atkhld & 0x8000) +#define ATKHLD_HOLD(atkhld) ((atkhld >> 8) & 0x7F) +#define ATKHLD_HOLD_TO_EMU_SAMPLES(atkhld) (4096 * (0x7F - ((atkhld >> 8) & 0x7F))) +#define ATKHLD_ATTACK(atkhld) (atkhld & 0x7F) + + uint16_t ip; +#define INTIAL_PITCH_CENTER 0xE000 +#define INTIAL_PITCH_OCTAVE 0x1000 + + union { + uint16_t ifatn; + struct { + uint8_t ifatn_attenuation; + uint8_t ifatn_init_filter; + }; + }; + union { + uint16_t pefe; + struct { + int8_t pefe_modenv_filter_height; + int8_t pefe_modenv_pitch_height; + }; + }; + union { + uint16_t fmmod; + struct { + int8_t fmmod_lfo1_filt_mod; + int8_t fmmod_lfo1_vibrato; + }; + }; + union { + uint16_t tremfrq; + struct { + uint8_t tremfrq_lfo1_freq; + int8_t tremfrq_lfo1_tremolo; + }; + }; + union { + uint16_t fm2frq2; + struct { + uint8_t fm2frq2_lfo2_freq; + int8_t fm2frq2_lfo2_vibrato; + }; + }; + + int env_engine_on; + + emu8k_mem_internal_t addr, loop_start, loop_end; + + int32_t initial_att; + int32_t initial_filter; + + emu8k_envelope_t vol_envelope; + emu8k_envelope_t mod_envelope; + + int64_t lfo1_speed, lfo2_speed; + emu8k_mem_internal_t lfo1_count, lfo2_count; + int32_t lfo1_delay_samples, lfo2_delay_samples; + int vol_l, vol_r; + + int16_t fixed_modenv_filter_height; + int16_t fixed_modenv_pitch_height; + int16_t fixed_lfo1_filt_mod; + int16_t fixed_lfo1_vibrato; + int16_t fixed_lfo1_tremolo; + int16_t fixed_lfo2_vibrato; + + /* filter internal data. */ + int filterq_idx; + int32_t filt_att; + int64_t filt_buffer[5]; } emu8k_voice_t; -typedef struct emu8k_t -{ - emu8k_voice_t voice[32]; +typedef struct emu8k_t { + emu8k_voice_t voice[32]; - uint16_t hwcf1, hwcf2, hwcf3; - uint32_t hwcf4, hwcf5, hwcf6, hwcf7; + uint16_t hwcf1, hwcf2, hwcf3; + uint32_t hwcf4, hwcf5, hwcf6, hwcf7; - uint16_t init1[32], init2[32], init3[32], init4[32]; - - uint32_t smalr, smarr, smalw, smarw; - uint16_t smld_buffer, smrd_buffer; + uint16_t init1[32], init2[32], init3[32], init4[32]; - uint16_t wc; - - uint16_t id; + uint32_t smalr, smarr, smalw, smarw; + uint16_t smld_buffer, smrd_buffer; - /* The empty block is used to act as an unallocated memory returning zero. */ - int16_t *ram, *rom, *empty; + uint16_t wc; - /* RAM pointers are a way to avoid checking ram boundaries on read */ - int16_t *ram_pointers[0x100]; - uint32_t ram_end_addr; + uint16_t id; - int cur_reg, cur_voice; - - int16_t out_l, out_r; - - emu8k_chorus_eng_t chorus_engine; - int32_t chorus_in_buffer[SOUNDBUFLEN]; - emu8k_reverb_eng_t reverb_engine; - int32_t reverb_in_buffer[SOUNDBUFLEN]; - - int pos; - int32_t buffer[SOUNDBUFLEN * 2]; + /* The empty block is used to act as an unallocated memory returning zero. */ + int16_t *ram, *rom, *empty; + + /* RAM pointers are a way to avoid checking ram boundaries on read */ + int16_t *ram_pointers[0x100]; + uint32_t ram_end_addr; + + int cur_reg, cur_voice; + + int16_t out_l, out_r; + + emu8k_chorus_eng_t chorus_engine; + int32_t chorus_in_buffer[SOUNDBUFLEN]; + emu8k_reverb_eng_t reverb_engine; + int32_t reverb_in_buffer[SOUNDBUFLEN]; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; + + uint16_t addr; } emu8k_t; - - +void emu8k_change_addr(emu8k_t *emu8k, uint16_t emu_addr); void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram); void emu8k_close(emu8k_t *emu8k); void emu8k_update(emu8k_t *emu8k); - - - /* Section E - Introduction to the EMU8000 Chip @@ -445,7 +438,7 @@ Section E - Introduction to the EMU8000 Chip Amplifier The amplifier determines the loudness of an audio signal. - + LFO1 An LFO, or Low Frequency Oscillator, is normally used to periodically modulate, that is, change a sound parameter, @@ -454,11 +447,11 @@ Section E - Introduction to the EMU8000 Chip modulation). It operates at sub-audio frequency from 0.042 Hz to 10.71 Hz. The LFO1 in the EMU8000 modulates the pitch, volume and filter cutoff simultaneously. - + LFO2 The LFO2 is similar to the LFO1, except that it modulates the pitch of the audio signal only. - + Resonance A filter alone would be like an equalizer, making a bright audio signal duller, but the addition of resonance @@ -467,7 +460,7 @@ Section E - Introduction to the EMU8000 Chip signals at the cutoff frequency, giving the audio signal a subtle wah-wah, that is, imagine a siren sound going from bright to dull to bright again periodically. - + LFO1 to Volume (Tremolo) The LFO1's output is routed to the amplifier, with the depth of oscillation determined by LFO1 to Volume. LFO1 @@ -481,7 +474,7 @@ Section E - Introduction to the EMU8000 Chip oscillating). An example of a GM instrument that makes use of LFO1 to Volume is instrument number 45, Tremolo Strings. - + LFO1 to Filter Cutoff (Wah-Wah) The LFO1's output is routed to the filter, with the depth of oscillation determined by LFO1 to Filter. LFO1 to @@ -499,7 +492,7 @@ Section E - Introduction to the EMU8000 Chip oscillator, producing a vibrato effect. An example of a GM instrument that makes use of LFO1 to Pitch is instrument number 57, Trumpet. - + LFO2 to Pitch (Vibrato) The LFO1 in the EMU8000 can simultaneously modulate pitch, volume and filter. LFO2, on the other hand, @@ -508,7 +501,7 @@ Section E - Introduction to the EMU8000 Chip periodic fluctuation in the pitch of the oscillator, producing a vibrato effect. When this is coupled with LFO1 to Pitch, a complex vibrato effect can be achieved. - + Volume Envelope The character of a musical instrument is largely determined by its volume envelope, the way in which the @@ -534,7 +527,7 @@ Section E - Introduction to the EMU8000 Chip as a key is held down. Release The time it takes the envelope to fall to the zero level after the key is released. - + Using these six parameters can yield very realistic reproduction of the volume envelope characteristics of many musical instruments. @@ -555,14 +548,14 @@ Section E - Introduction to the EMU8000 Chip useful in creating synthetic sci-fi sound textures. An example of a GM instrument that makes use of the filter envelope is instrument number 86, Pad 8 (Sweep). - + Pitch/Filter Envelope Modulation These two parameters determine the modulation depth of the pitch and filter envelope. In the wind instrument example above, a small amount of pitch envelope modulation is desirable to simulate its natural pitch characteristics. - + This rich modulation capability of the EMU8000 is fully exploited by the SB AWE32 MIDI drivers. The driver also provides you with a means to change these parameters over @@ -616,9 +609,9 @@ Section E - Introduction to the EMU8000 Chip Short Delay (feed back) This chorus variation simulates a short delay repeated (feedback) many times. - - - + + + Registers to write the Chorus Parameters to (all are 16-bit, unless noted): (codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) ( 3409 = register 3, port A20, voice 9) @@ -651,12 +644,12 @@ Short Delay Short Delay + Feedback // Chorus Params typedef struct { - WORD FbkLevel; // Feedback Level (0xE600-0xE6FF) - WORD Delay; // Delay (0-0x0DA3) [1/44100 sec] - WORD LfoDepth; // LFO Depth (0xBC00-0xBCFF) - DWORD DelayR; // Right Delay (0-0xFFFFFFFF) [1/256/44100 sec] - DWORD LfoFreq; // LFO Frequency (0-0xFFFFFFFF) - } CHORUS_TYPE; + WORD FbkLevel; // Feedback Level (0xE600-0xE6FF) + WORD Delay; // Delay (0-0x0DA3) [1/44100 sec] + WORD LfoDepth; // LFO Depth (0xBC00-0xBCFF) + DWORD DelayR; // Right Delay (0-0xFFFFFFFF) [1/256/44100 sec] + DWORD LfoFreq; // LFO Frequency (0-0xFFFFFFFF) + } CHORUS_TYPE; Registers to write the Reverb Parameters to (they are all 16-bit): @@ -697,16 +690,16 @@ Hall 1: 0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, 0x842B,0x852B,0x842B,0x852B,0x842A,0x852A,0x842A,0x852A, 0x8429,0x8529,0x8429,0x8529 - + Hall 2: - + 0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7254,0x7234, 0x7224,0x7254,0x7264,0x7294,0x44C3,0x45C3,0xA404,0xA504, 0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, -0x8428,0x8528,0x8428,0x8528 +0x8428,0x8528,0x8428,0x8528 Plate: - + 0xB4FF,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7234,0x7234, 0x7234,0x7234,0x7234,0x7234,0x4448,0x4548,0xA440,0xA540, 0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, @@ -773,3 +766,5 @@ Treble Parameters: 0xD308 0xD308 0xD308 0xD308 0xD308 0xD308 0xD3019 0xD32A 0xD34C 0xD36E 0xD36E 0xD36E 0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 */ + +#endif /*SOUND_EMU8K_H*/ diff --git a/src/include/86box/snd_mpu401.h b/src/include/86box/snd_mpu401.h index 75eeb8261..96143b251 100644 --- a/src/include/86box/snd_mpu401.h +++ b/src/include/86box/snd_mpu401.h @@ -20,28 +20,29 @@ * Copyright 2016-2020 TheCollector1995. */ -#define MPU401_VERSION 0x15 -#define MPU401_REVISION 0x01 -#define MPU401_QUEUE 64 -#define MPU401_INPUT_QUEUE 1024 -#define MPU401_TIMECONSTANT (60000000/1000.0f) -#define MPU401_RESETBUSY 27.0f +#ifndef SOUND_MPU401_H +#define SOUND_MPU401_H + +#define MPU401_VERSION 0x15 +#define MPU401_REVISION 0x01 +#define MPU401_QUEUE 64 +#define MPU401_INPUT_QUEUE 1024 +#define MPU401_TIMECONSTANT (60000000 / 1000.0f) +#define MPU401_RESETBUSY 27.0f /*helpers*/ -#define M_GETKEY key[key/32]&(1<<(key%32)) -#define M_SETKEY key[key/32]|=(1<<(key%32)) -#define M_DELKEY key[key/32]&=~(1<<(key%32)) +#define M_GETKEY key[key / 32] & (1 << (key % 32)) +#define M_SETKEY key[key / 32] |= (1 << (key % 32)) +#define M_DELKEY key[key / 32] &= ~(1 << (key % 32)) -typedef enum MpuMode -{ +typedef enum MpuMode { M_UART, M_INTELLIGENT } MpuMode; #define M_MCA 0x10 -typedef enum MpuDataType -{ +typedef enum MpuDataType { T_OVERFLOW, T_MARK, T_MIDI_SYS, @@ -49,114 +50,114 @@ typedef enum MpuDataType T_COMMAND } MpuDataType; -typedef enum RecState -{ - M_RECOFF, - M_RECSTB, - M_RECON +typedef enum RecState { + M_RECOFF, + M_RECSTB, + M_RECON } RecState; /* Messages sent to MPU-401 from host */ -#define MSG_EOX 0xf7 -#define MSG_OVERFLOW 0xf8 -#define MSG_MARK 0xfc +#define MSG_EOX 0xf7 +#define MSG_OVERFLOW 0xf8 +#define MSG_MARK 0xfc /* Messages sent to host from MPU-401 */ -#define MSG_MPU_OVERFLOW 0xf8 -#define MSG_MPU_COMMAND_REQ 0xf9 -#define MSG_MPU_END 0xfc -#define MSG_MPU_CLOCK 0xfd -#define MSG_MPU_ACK 0xfe +#define MSG_MPU_OVERFLOW 0xf8 +#define MSG_MPU_COMMAND_REQ 0xf9 +#define MSG_MPU_END 0xfc +#define MSG_MPU_CLOCK 0xfd +#define MSG_MPU_ACK 0xfe -typedef struct mpu_t -{ +typedef struct mpu_t { uint16_t addr; - int uart_mode, intelligent, - irq, midi_thru, - queue_pos, queue_used; + int uart_mode, intelligent, + irq, midi_thru, + queue_pos, queue_used; uint8_t rx_data, is_mca, - status, - queue[MPU401_QUEUE], pos_regs[8]; - MpuMode mode; - uint8_t rec_queue[MPU401_INPUT_QUEUE]; - int rec_queue_pos, rec_queue_used; - uint32_t ch_toref[16]; - struct track - { - int counter; - uint8_t value[3], sys_val, - vlength,length; - MpuDataType type; + status, + queue[MPU401_QUEUE], pos_regs[8]; + MpuMode mode; + uint8_t rec_queue[MPU401_INPUT_QUEUE]; + int rec_queue_pos, rec_queue_used; + uint32_t ch_toref[16]; + struct track { + int counter; + uint8_t value[3], sys_val, + vlength, length; + MpuDataType type; } playbuf[8], condbuf; struct { - int conductor, cond_req, - cond_set, block_ack, - playing, reset, - wsd, wsm, wsd_start, - run_irq, irq_pending, - track_req, - send_now, eoi_scheduled, - data_onoff, clock_to_host, - sync_in, sysex_in_finished, - rec_copy; - RecState rec; - uint8_t tmask, cmask, - amask, - last_rtcmd; - uint16_t midi_mask, req_mask; - uint32_t command_byte, cmd_pending, - track, old_track; + int conductor, cond_req, + cond_set, block_ack, + playing, reset, + wsd, wsm, wsd_start, + run_irq, irq_pending, + track_req, + send_now, eoi_scheduled, + data_onoff, clock_to_host, + sync_in, sysex_in_finished, + rec_copy; + RecState rec; + uint8_t tmask, cmask, + amask, + last_rtcmd; + uint16_t midi_mask, req_mask; + uint32_t command_byte, cmd_pending, + track, old_track; } state; struct { - uint8_t timebase, old_timebase, - tempo, old_tempo, - tempo_rel, old_tempo_rel, - tempo_grad, cth_rate[4], - cth_mode, midimetro, - metromeas; - uint32_t cth_counter, cth_old, - rec_counter; - int32_t measure_counter, meas_old, - freq; - int ticks_in, active; - float freq_mod; + uint8_t timebase, old_timebase, + tempo, old_tempo, + tempo_rel, old_tempo_rel, + tempo_grad, cth_rate[4], + cth_mode, midimetro, + metromeas; + uint32_t cth_counter, cth_old, + rec_counter; + int32_t measure_counter, meas_old, + freq; + int ticks_in, active; + float freq_mod; } clock; - struct { - int all_thru, midi_thru, - sysex_thru, commonmsgs_thru, - modemsgs_in, commonmsgs_in, - bender_in, sysex_in, - allnotesoff_out, rt_affection, - rt_out, rt_in, - timing_in_stop, data_in_stop, - rec_measure_end; - uint8_t prchg_buf[16]; - uint16_t prchg_mask; - } filter; - struct { - int on; - uint8_t chan, trmask; - uint32_t key[4]; - } chanref[5], inputref[16]; - pc_timer_t mpu401_event_callback, mpu401_eoi_callback, - mpu401_reset_callback; - void (*ext_irq_update)(void *priv, int set); - int (*ext_irq_pending)(void *priv); - void *priv; + struct { + int all_thru, midi_thru, + sysex_thru, commonmsgs_thru, + modemsgs_in, commonmsgs_in, + bender_in, sysex_in, + allnotesoff_out, rt_affection, + rt_out, rt_in, + timing_in_stop, data_in_stop, + rec_measure_end; + uint8_t prchg_buf[16]; + uint16_t prchg_mask; + } filter; + struct { + int on; + uint8_t chan, trmask; + uint32_t key[4]; + } chanref[5], inputref[16]; + pc_timer_t mpu401_event_callback, mpu401_eoi_callback, + mpu401_reset_callback; + void (*ext_irq_update)(void *priv, int set); + int (*ext_irq_pending)(void *priv); + void *priv; } mpu_t; -extern int mpu401_standalone_enable, mpu401_already_loaded; +extern int mpu401_standalone_enable, mpu401_already_loaded; -extern const device_t mpu401_device; -extern const device_t mpu401_mca_device; +extern const device_t mpu401_device; +extern const device_t mpu401_mca_device; +extern uint8_t MPU401_ReadData(mpu_t *mpu); +extern void mpu401_write(uint16_t addr, uint8_t val, void *priv); +extern uint8_t mpu401_read(uint16_t addr, void *priv); +extern void mpu401_setirq(mpu_t *mpu, int irq); +extern void mpu401_change_addr(mpu_t *mpu, uint16_t addr); +extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input); +extern void mpu401_device_add(void); +extern void mpu401_irq_attach(mpu_t *mpu, void (*ext_irq_update)(void *priv, int set), int (*ext_irq_pending)(void *priv), void *priv); -extern uint8_t MPU401_ReadData(mpu_t *mpu); -extern void mpu401_setirq(mpu_t *mpu, int irq); -extern void mpu401_change_addr(mpu_t *mpu, uint16_t addr); -extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input); -extern void mpu401_device_add(void); -extern void mpu401_irq_attach(mpu_t *mpu, void (*ext_irq_update)(void *priv, int set), int (*ext_irq_pending)(void *priv), void *priv); +extern int MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort); +extern void MPU401_InputMsg(void *p, uint8_t *msg, uint32_t len); -extern int MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort); -extern void MPU401_InputMsg(void *p, uint8_t *msg); +#endif /*SOUND_MPU401_H*/ diff --git a/src/include/86box/snd_opl.h b/src/include/86box/snd_opl.h index aff429e77..a2e8dd521 100644 --- a/src/include/86box/snd_opl.h +++ b/src/include/86box/snd_opl.h @@ -1,32 +1,56 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -typedef struct opl_t -{ - int pos, chip_nr[2]; +/* + * 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. + * + * Definitions for the OPL interface. + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + */ +#ifndef SOUND_OPL_H +#define SOUND_OPL_H - int32_t filtbuf[2], - buffer[SOUNDBUFLEN * 2], - buffer2[SOUNDBUFLEN * 2]; +enum fm_type { + FM_YM3812 = 0, + FM_YMF262, + FM_YMF289B, + FM_MAX +}; - pc_timer_t timers[2][2]; -} opl_t; +enum fm_driver { + FM_DRV_NUKED = 0, + FM_DRV_YMFM, + FM_DRV_MAX +}; +typedef struct { + uint8_t (*read)(uint16_t port, void *priv); + void (*write)(uint16_t port, uint8_t val, void *priv); + int32_t * (*update)(void *priv); + void (*reset_buffer)(void *priv); + void (*set_do_cycles)(void *priv, int8_t do_cycles); + void *priv; +} fm_drv_t; -extern uint8_t opl2_read(uint16_t a, void *priv); -extern void opl2_write(uint16_t a, uint8_t v, void *priv); -extern uint8_t opl2_l_read(uint16_t a, void *priv); -extern void opl2_l_write(uint16_t a, uint8_t v, void *priv); -extern uint8_t opl2_r_read(uint16_t a, void *priv); -extern void opl2_r_write(uint16_t a, uint8_t v, void *priv); -extern uint8_t opl3_read(uint16_t a, void *priv); -extern void opl3_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t fm_driver_get(int chip_id, fm_drv_t *drv); -extern void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); -extern void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +extern const fm_drv_t nuked_opl_drv; +extern const fm_drv_t ymfm_drv; -extern void opl2_init(opl_t *opl); -extern void opl3_init(opl_t *opl); +#ifdef EMU_DEVICE_H +extern const device_t ym3812_nuked_device; +extern const device_t ymf262_nuked_device; -extern void opl2_update2(opl_t *opl); -extern void opl3_update2(opl_t *opl); +extern const device_t ym3812_ymfm_device; +extern const device_t ymf262_ymfm_device; +extern const device_t ymf289b_ymfm_device; +#endif + +#endif /*SOUND_OPL_H*/ diff --git a/src/include/86box/snd_opl_backend.h b/src/include/86box/snd_opl_backend.h deleted file mode 100644 index 24120d036..000000000 --- a/src/include/86box/snd_opl_backend.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#ifdef __cplusplus -extern "C" { -#endif - void opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3); - void opl_write(int nr, uint16_t addr, uint8_t val); - uint8_t opl_read(int nr, uint16_t addr); - void opl_timer_over(int nr, int timer); - void opl2_update(int nr, int32_t *buffer, int samples); - void opl3_update(int nr, int32_t *buffer, int samples); - - extern int opl_type; -#ifdef __cplusplus -} -#endif diff --git a/src/include/86box/intel_flash.h b/src/include/86box/snd_opl_nuked.h similarity index 56% rename from src/include/86box/intel_flash.h rename to src/include/86box/snd_opl_nuked.h index fd14f03f5..93ea4ba35 100644 --- a/src/include/86box/intel_flash.h +++ b/src/include/86box/snd_opl_nuked.h @@ -6,16 +6,19 @@ * * This file is part of the 86Box distribution. * - * Implementation of the Intel 1 Mbit 8-bit flash devices. + * Definitions for the NukedOPL3 driver. * + * Version: @(#)snd_opl_nuked.h 1.0.5 2020/07/16 * - * - * Author: Sarah Walker, + * Authors: Fred N. van Kempen, * Miran Grca, - * Copyright 2008-2019 Sarah Walker. + * + * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2016-2019 Miran Grca. */ -extern const device_t intel_flash_bxt_ami_device; -extern const device_t intel_flash_bxt_device; -extern const device_t intel_flash_bxb_device; +#ifndef SOUND_OPL_NUKED_H +#define SOUND_OPL_NUKED_H + + +#endif /*SOUND_OPL_NUKED_H*/ diff --git a/src/include/86box/snd_resid.h b/src/include/86box/snd_resid.h index 402ee0ceb..b8763ad15 100644 --- a/src/include/86box/snd_resid.h +++ b/src/include/86box/snd_resid.h @@ -1,12 +1,17 @@ +#ifndef SOUND_RESID_H +#define SOUND_RESID_H + #ifdef __cplusplus extern "C" { #endif - void *sid_init(); - void sid_close(void *p); - void sid_reset(void *p); - uint8_t sid_read(uint16_t addr, void *p); - void sid_write(uint16_t addr, uint8_t val, void *p); - void sid_fillbuf(int16_t *buf, int len, void *p); +void *sid_init(); +void sid_close(void *p); +void sid_reset(void *p); +uint8_t sid_read(uint16_t addr, void *p); +void sid_write(uint16_t addr, uint8_t val, void *p); +void sid_fillbuf(int16_t *buf, int len, void *p); #ifdef __cplusplus } #endif + +#endif /*SOUND_RESID_H*/ diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 5b33adcf5..bf44d4d6d 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -1,141 +1,166 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Sound Blaster emulation. + * Sound Blaster emulation. * - * Authors: Sarah Walker, - * Miran Grca, - * TheCollector1995, + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ -#ifndef SOUND_SND_SB_H -# define SOUND_SND_SB_H +#ifndef SOUND_SND_SB_H +#define SOUND_SND_SB_H + +#include <86box/snd_cms.h> #include <86box/snd_emu8k.h> #include <86box/snd_mpu401.h> #include <86box/snd_opl.h> #include <86box/snd_sb_dsp.h> -#define SADLIB 1 /* No DSP */ -#define SB1 2 /* DSP v1.05 */ -#define SB15 3 /* DSP v2.00 */ -#define SB2 4 /* DSP v2.01 - needed for high-speed DMA */ -#define SBPRO 5 /* DSP v3.00 */ -#define SBPRO2 6 /* DSP v3.02 + OPL3 */ -#define SB16 7 /* DSP v4.05 + OPL3 */ -#define SADGOLD 8 /* AdLib Gold */ -#define SND_WSS 9 /* Windows Sound System */ -#define SND_PAS16 10 /* Pro Audio Spectrum 16 */ +#define SADLIB 1 /* No DSP */ +#define SB1 2 /* DSP v1.05 */ +#define SB15 3 /* DSP v2.00 */ +#define SB2 4 /* DSP v2.01 - needed for high-speed DMA */ +#define SBPRO 5 /* DSP v3.00 */ +#define SBPRO2 6 /* DSP v3.02 + OPL3 */ +#define SB16 7 /* DSP v4.05 + OPL3 */ +#define SBAWE32 8 /* DSP v4.13 + OPL3 */ +#define SBAWE64 9 /* DSP v4.16 + OPL3 */ /* SB 2.0 CD version */ -typedef struct sb_ct1335_mixer_t -{ - int32_t master; - int32_t voice; - int32_t fm; - int32_t cd; +typedef struct sb_ct1335_mixer_t { + double master; + double voice; + double fm; + double cd; - uint8_t index; - uint8_t regs[256]; + uint8_t index; + uint8_t regs[256]; } sb_ct1335_mixer_t; + /* SB PRO */ -typedef struct sb_ct1345_mixer_t -{ - int32_t master_l, master_r; - int32_t voice_l, voice_r; - int32_t fm_l, fm_r; - int32_t cd_l, cd_r; - int32_t line_l, line_r; - int32_t mic; - /*see sb_ct1745_mixer for values for input selector*/ - int32_t input_selector; - - int input_filter; - int in_filter_freq; - int output_filter; - - int stereo; - int stereo_isleft; - - uint8_t index; - uint8_t regs[256]; - +typedef struct sb_ct1345_mixer_t { + double master_l, + master_r; + double voice_l, + voice_r; + double fm_l, + fm_r; + double cd_l, + cd_r; + double line_l, + line_r; + double mic; + /*see sb_ct1745_mixer for values for input selector*/ + int32_t input_selector; + + int input_filter; + int in_filter_freq; + int output_filter; + + int stereo; + int stereo_isleft; + + uint8_t index; + uint8_t regs[256]; + } sb_ct1345_mixer_t; + /* SB16 and AWE32 */ -typedef struct sb_ct1745_mixer_t -{ - int32_t master_l, master_r; - int32_t voice_l, voice_r; - int32_t fm_l, fm_r; - int32_t cd_l, cd_r; - int32_t line_l, line_r; - int32_t mic; - int32_t speaker; +typedef struct sb_ct1745_mixer_t { + double master_l, + master_r; + double voice_l, + voice_r; + double fm_l, + fm_r; + double cd_l, + cd_r; + double line_l, + line_r; + double mic; + double speaker; - int bass_l, bass_r; - int treble_l, treble_r; - - int output_selector; - #define OUTPUT_MIC 1 - #define OUTPUT_CD_R 2 - #define OUTPUT_CD_L 4 - #define OUTPUT_LINE_R 8 - #define OUTPUT_LINE_L 16 + int bass_l, + bass_r; + int treble_l, + treble_r; - int input_selector_left; - int input_selector_right; - #define INPUT_MIC 1 - #define INPUT_CD_R 2 - #define INPUT_CD_L 4 - #define INPUT_LINE_R 8 - #define INPUT_LINE_L 16 - #define INPUT_MIDI_R 32 - #define INPUT_MIDI_L 64 + int output_selector; +#define OUTPUT_MIC 1 +#define OUTPUT_CD_R 2 +#define OUTPUT_CD_L 4 +#define OUTPUT_LINE_R 8 +#define OUTPUT_LINE_L 16 - int mic_agc; - - int32_t input_gain_L; - int32_t input_gain_R; - int32_t output_gain_L; - int32_t output_gain_R; - - uint8_t index; - uint8_t regs[256]; + int input_selector_left; + int input_selector_right; +#define INPUT_MIC 1 +#define INPUT_CD_R 2 +#define INPUT_CD_L 4 +#define INPUT_LINE_R 8 +#define INPUT_LINE_L 16 +#define INPUT_MIDI_R 32 +#define INPUT_MIDI_L 64 + + int mic_agc; + + int32_t input_gain_L; + int32_t input_gain_R; + double output_gain_L; + double output_gain_R; + + uint8_t index; + uint8_t regs[256]; + + int output_filter; /* for clones */ } sb_ct1745_mixer_t; -typedef struct sb_t -{ - uint8_t opl_enabled; - opl_t opl; - sb_dsp_t dsp; - union { - sb_ct1335_mixer_t mixer_sb2; - sb_ct1345_mixer_t mixer_sbpro; - sb_ct1745_mixer_t mixer_sb16; - }; - mpu_t *mpu; - emu8k_t emu8k; +typedef struct sb_t { + uint8_t cms_enabled, + opl_enabled, + mixer_enabled; + cms_t cms; + fm_drv_t opl, + opl2; + sb_dsp_t dsp; + union { + sb_ct1335_mixer_t mixer_sb2; + sb_ct1345_mixer_t mixer_sbpro; + sb_ct1745_mixer_t mixer_sb16; + }; + mpu_t *mpu; + emu8k_t emu8k; + void *gameport; - int pos; - - uint8_t pos_regs[8]; - - int opl_emu; + int pos; + + uint8_t pos_regs[8], + pnp_rom[512]; + + uint16_t opl_pnp_addr; } sb_t; -extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); +extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); -extern void sb_ct1345_mixer_reset(sb_t* sb); +extern void sb_ct1345_mixer_reset(sb_t *sb); + +extern void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p); +extern uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p); +extern void sb_ct1745_mixer_reset(sb_t* sb); extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); +extern void sbpro_filter_cd_audio(int channel, double *buffer, void *p); +extern void sb16_awe32_filter_cd_audio(int channel, double *buffer, void *p); extern void sb_close(void *p); extern void sb_speed_changed(void *p); -#endif /*SOUND_SND_SB_H*/ +#endif /*SOUND_SND_SB_H*/ diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index 263897711..2f3607176 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -7,96 +7,107 @@ #define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /*Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone*/ /* aztech-related */ -#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) /* check for future AZT cards here */ -#define AZTECH_EEPROM_SIZE 16 +#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) /* check for future AZT cards here */ +#define AZTECH_EEPROM_SIZE 16 -typedef struct sb_dsp_t -{ - int sb_type; - int sb_subtype; /* which clone */ - void *parent; /* "sb_t *" if default subtype, "azt2316a_t *" if aztech. */ +typedef struct sb_dsp_t { + int sb_type; + int sb_subtype; /* which clone */ + void *parent; /* "sb_t *" if default subtype, "azt2316a_t *" if aztech. */ - int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; - int sb_8_dmanum; - int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; - int sb_16_dmanum; - int sb_pausetime; + int sb_8_length, sb_8_origlength, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; + int sb_8_dmanum; + int sb_16_length, sb_16_origlength, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; + int sb_16_dmanum; + int sb_pausetime; + int (*dma_readb)(void *priv), + (*dma_readw)(void *priv), + (*dma_writeb)(void *priv, uint8_t val), + (*dma_writew)(void *priv, uint16_t val); + void *dma_priv; - uint8_t sb_read_data[256]; - int sb_read_wp, sb_read_rp; - int sb_speaker; - int muted; + uint8_t sb_read_data[256]; + int sb_read_wp, sb_read_rp; + int sb_speaker; + int muted; - int sb_data_stat; + int sb_data_stat; - int midi_in_sysex; - int midi_in_poll; - int uart_midi; - int uart_irq; - int onebyte_midi; - int midi_in_timestamp; + int midi_in_sysex; + int midi_in_poll; + int uart_midi; + int uart_irq; + int onebyte_midi; + int midi_in_timestamp; - int sb_irqnum; + int sb_irqnum; + void (*irq_update)(void *priv, int set), + *irq_priv; - uint8_t sbe2; - int sbe2count; + uint8_t sbe2; + int sbe2count; - uint8_t sb_data[8]; + uint8_t sb_data[8]; - int sb_freq; - - int16_t sbdat; - int sbdat2; - int16_t sbdatl, sbdatr; + int sb_freq; - uint8_t sbref; - int8_t sbstep; + int16_t sbdat; + int sbdat2; + int16_t sbdatl, sbdatr; - int sbdacpos; + uint8_t sbref; + int8_t sbstep; - int sbleftright; + int sbdacpos; - int sbreset; - uint8_t sbreaddat; - uint8_t sb_command; - uint8_t sb_test; - int sb_timei, sb_timeo; + int sbleftright, sbleftright_default; - int sb_irq8, sb_irq16, sb_irq401; - int sb_irqm8, sb_irqm16, sb_irqm401; + int sbreset; + uint8_t sbreaddat; + uint8_t sb_command; + uint8_t sb_test; + int sb_timei, sb_timeo; - uint8_t sb_asp_regs[256]; - - int sbenable, sb_enable_i; - - pc_timer_t output_timer, input_timer; - - uint64_t sblatcho, sblatchi; + int sb_irq8, sb_irq16, sb_irq401; + int sb_irqm8, sb_irqm16, sb_irqm401; - uint16_t sb_addr; + uint8_t sb_asp_regs[256]; + uint8_t sb_asp_mode; - int stereo; + uint8_t sb_asp_ram[2048]; + int sb_asp_ram_index; - int asp_data_len; + uint8_t sb_8051_ram[256]; - pc_timer_t wb_timer; - int wb_full; + int sbenable, sb_enable_i; - int busy_count; + pc_timer_t output_timer, input_timer; - int record_pos_read; - int record_pos_write; - int16_t record_buffer[0xFFFF]; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; + double sblatcho, sblatchi; - uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; /* the eeprom in the Aztech cards is attached to the DSP */ + uint16_t sb_addr; - mpu_t *mpu; + int stereo; + + int asp_data_len; + + pc_timer_t wb_timer; + int wb_full; + + int busy_count; + + int record_pos_read; + int record_pos_write; + int16_t record_buffer[0xFFFF]; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + + uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; /* the eeprom in the Aztech cards is attached to the DSP */ + + mpu_t *mpu; } sb_dsp_t; - -void sb_dsp_input_msg(void *p, uint8_t *msg); +void sb_dsp_input_msg(void *p, uint8_t *msg, uint32_t len); int sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort); @@ -117,6 +128,14 @@ void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); void sb_dsp_update(sb_dsp_t *dsp); -void sb_update_irq(sb_dsp_t *dsp); +void sb_update_mask(sb_dsp_t *dsp, int irqm8, int irqm16, int irqm401); -#endif /* SOUND_SND_SB_DSP_H */ \ No newline at end of file +void sb_dsp_irq_attach(sb_dsp_t *dsp, void (*irq_update)(void *priv, int set), void *priv); +void sb_dsp_dma_attach(sb_dsp_t *dsp, + int (*dma_readb)(void *priv), + int (*dma_readw)(void *priv), + int (*dma_writeb)(void *priv, uint8_t val), + int (*dma_writew)(void *priv, uint16_t val), + void *priv); + +#endif /* SOUND_SND_SB_DSP_H */ diff --git a/src/include/86box/snd_sn76489.h b/src/include/86box/snd_sn76489.h index 01d19e0e5..c8a3a567c 100644 --- a/src/include/86box/snd_sn76489.h +++ b/src/include/86box/snd_sn76489.h @@ -1,8 +1,10 @@ -enum -{ - SN76496, - NCR8496, - PSSJ +#ifndef SOUND_SN76489_H +#define SOUND_SN76489_H + +enum { + SN76496, + NCR8496, + PSSJ }; extern const device_t sn76489_device; @@ -10,24 +12,25 @@ extern const device_t ncr8496_device; extern int sn76489_mute; -typedef struct sn76489_t -{ - int stat[4]; - int latch[4], count[4]; - int freqlo[4], freqhi[4]; - int vol[4]; - uint32_t shift; - uint8_t noise; - int lasttone; - uint8_t firstdat; - int type; - int extra_divide; - - int16_t buffer[SOUNDBUFLEN]; - int pos; - - double psgconst; +typedef struct sn76489_t { + int stat[4]; + int latch[4], count[4]; + int freqlo[4], freqhi[4]; + int vol[4]; + uint32_t shift; + uint8_t noise; + int lasttone; + uint8_t firstdat; + int type; + int extra_divide; + + int16_t buffer[SOUNDBUFLEN]; + int pos; + + double psgconst; } sn76489_t; void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq); void sn74689_set_extra_divide(sn76489_t *sn76489, int enable); + +#endif /*SOUND_SN76489_H*/ diff --git a/src/include/86box/snd_speaker.h b/src/include/86box/snd_speaker.h index 91e3edfe3..0b368268e 100644 --- a/src/include/86box/snd_speaker.h +++ b/src/include/86box/snd_speaker.h @@ -16,13 +16,18 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ -extern int speaker_mute; -extern int speaker_gated; -extern int speaker_enable, was_speaker_enable; +#ifndef SOUND_SPEAKER_H +#define SOUND_SPEAKER_H +extern int speaker_mute; -extern void speaker_init(); +extern int speaker_gated; +extern int speaker_enable, was_speaker_enable; -extern void speaker_set_count(uint8_t new_m, int new_count); -extern void speaker_update(void); +extern void speaker_init(); + +extern void speaker_set_count(uint8_t new_m, int new_count); +extern void speaker_update(void); + +#endif /*SOUND_SPEAKER_H*/ diff --git a/src/include/86box/snd_ym7128.h b/src/include/86box/snd_ym7128.h index f71aa2f86..4d5400f34 100644 --- a/src/include/86box/snd_ym7128.h +++ b/src/include/86box/snd_ym7128.h @@ -1,25 +1,29 @@ -typedef struct ym7128_t -{ - int a0, sci; - uint8_t dat; - - int reg_sel; - uint8_t regs[32]; - - int gl[8], gr[8]; - int vm, vc, vl, vr; - int c0, c1; - int t[9]; - - int16_t filter_dat; - int16_t prev_l, prev_r; - - int16_t delay_buffer[2400]; - int delay_pos; - - int16_t last_samp; +#ifndef SOUND_YM7128_H +#define SOUND_YM7128_H + +typedef struct ym7128_t { + int a0, sci; + uint8_t dat; + + int reg_sel; + uint8_t regs[32]; + + int gl[8], gr[8]; + int vm, vc, vl, vr; + int c0, c1; + int t[9]; + + int16_t filter_dat; + int16_t prev_l, prev_r; + + int16_t delay_buffer[2400]; + int delay_pos; + + int16_t last_samp; } ym7128_t; void ym7128_init(ym7128_t *ym7128); void ym7128_write(ym7128_t *ym7128, uint8_t val); void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len); + +#endif /*SOUND_YM7128_H*/ diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index a47d97191..71d4942d0 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -1,77 +1,76 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Sound emulation core. + * Sound emulation core. * * * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Sarah Walker, + * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ -#ifndef EMU_SOUND_H -# define EMU_SOUND_H +#ifndef EMU_SOUND_H +#define EMU_SOUND_H extern int sound_gain; -#define SOUNDBUFLEN (48000/50) - -#define CD_FREQ 44100 -#define CD_BUFLEN (CD_FREQ / 10) +#define SOUNDBUFLEN (48000 / 50) +#define CD_FREQ 44100 +#define CD_BUFLEN (CD_FREQ / 10) enum { SOUND_NONE = 0, SOUND_INTERNAL }; +extern int ppispeakon; +extern int gated, + speakval, + speakon; -extern int ppispeakon; -extern int gated, - speakval, - speakon; +extern int sound_pos_global; +extern int sound_card_current; -extern int sound_pos_global; -extern int sound_card_current; +extern void sound_add_handler(void (*get_buffer)(int32_t *buffer, + int len, void *p), + void *p); +extern void sound_set_cd_audio_filter(void (*filter)(int channel, + double *buffer, void *p), + void *p); - -extern void sound_add_handler(void (*get_buffer)(int32_t *buffer, \ - int len, void *p), void *p); - -extern int sound_card_available(int card); -extern char *sound_card_getname(int card); +extern int sound_card_available(int card); #ifdef EMU_DEVICE_H -extern const device_t *sound_card_getdevice(int card); +extern const device_t *sound_card_getdevice(int card); #endif -extern int sound_card_has_config(int card); -extern char *sound_card_get_internal_name(int card); -extern int sound_card_get_from_internal_name(char *s); -extern void sound_card_init(void); -extern void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); +extern int sound_card_has_config(int card); +extern char *sound_card_get_internal_name(int card); +extern int sound_card_get_from_internal_name(char *s); +extern void sound_card_init(void); +extern void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); -extern void sound_speed_changed(void); +extern void sound_speed_changed(void); -extern void sound_init(void); -extern void sound_reset(void); +extern void sound_init(void); +extern void sound_reset(void); -extern void sound_card_reset(void); +extern void sound_card_reset(void); -extern void sound_cd_thread_end(void); -extern void sound_cd_thread_reset(void); - -extern void closeal(void); -extern void inital(void); -extern void givealbuffer(void *buf); -extern void givealbuffer_cd(void *buf); +extern void sound_cd_thread_end(void); +extern void sound_cd_thread_reset(void); +extern void closeal(void); +extern void inital(void); +extern void givealbuffer(void *buf); +extern void givealbuffer_cd(void *buf); #ifdef EMU_DEVICE_H /* AdLib and AdLib Gold */ @@ -93,13 +92,20 @@ extern const device_t cms_device; /* Gravis UltraSound and UltraSound Max */ extern const device_t gus_device; -#if defined(DEV_BRANCH) && defined(USE_PAS16) +# if defined(DEV_BRANCH) && defined(USE_PAS16) /* Pro Audio Spectrum 16 */ extern const device_t pas16_device; -#endif +# endif -/* PSSJ - What is this device? */ +/* IBM PS/1 Audio Card */ +extern const device_t ps1snd_device; + +/* Tandy PSSJ */ extern const device_t pssj_device; +# if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +extern const device_t pssj_isa_device; +extern const device_t tndy_device; +# endif /* Creative Labs Sound Blaster */ extern const device_t sb_1_device; @@ -109,8 +115,18 @@ extern const device_t sb_2_device; extern const device_t sb_pro_v1_device; extern const device_t sb_pro_v2_device; extern const device_t sb_pro_mcv_device; +extern const device_t sb_pro_compat_device; extern const device_t sb_16_device; +extern const device_t sb_16_pnp_device; +extern const device_t sb_16_compat_device; +extern const device_t sb_16_compat_nompu_device; +extern const device_t sb_16_reply_mca_device; +extern const device_t sb_32_pnp_device; extern const device_t sb_awe32_device; +extern const device_t sb_awe32_pnp_device; +extern const device_t sb_awe64_value_device; +extern const device_t sb_awe64_device; +extern const device_t sb_awe64_gold_device; /* Innovation SSI-2001 */ extern const device_t ssi2001_device; @@ -118,6 +134,20 @@ extern const device_t ssi2001_device; /* Windows Sound System */ extern const device_t wss_device; extern const device_t ncr_business_audio_device; + +/* Crystal CS423x */ +extern const device_t cs4235_device; +extern const device_t cs4235_onboard_device; +extern const device_t cs4236b_device; +extern const device_t cs4237b_device; +extern const device_t cs4238b_device; + +/* C-Media CMI8x38 */ +extern const device_t cmi8338_device; +extern const device_t cmi8338_onboard_device; +extern const device_t cmi8738_device; +extern const device_t cmi8738_onboard_device; +extern const device_t cmi8738_6ch_onboard_device; #endif -#endif /*EMU_SOUND_H*/ +#endif /*EMU_SOUND_H*/ diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index 098fb3ed7..76a336d8b 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -14,10 +14,10 @@ * * Copyright 2020 RichardG. */ + #ifndef EMU_SPD_H # define EMU_SPD_H - #define SPD_BASE_ADDR 0x50 #define SPD_MAX_SLOTS 8 #define SPD_DATA_SIZE 256 @@ -47,17 +47,7 @@ #define SPD_SDR_ATTR_VCC_HI_5 0x20 -typedef struct _spd_ { - const device_t *info; - uint8_t slot; - uint16_t size; - uint16_t row1; - uint16_t row2; - - uint8_t addr_register; -} spd_t; - -typedef struct _spd_edo_ { +typedef struct { uint8_t bytes_used, spd_size, mem_type, row_bits, col_bits, banks, data_width_lsb, data_width_msb, @@ -75,7 +65,7 @@ typedef struct _spd_edo_ { checksum2; } spd_edo_t; -typedef struct _spd_sdram_ { +typedef struct { uint8_t bytes_used, spd_size, mem_type, row_bits, col_bits, rows, data_width_lsb, data_width_msb, @@ -99,11 +89,25 @@ typedef struct _spd_sdram_ { checksum2; } spd_sdram_t; +typedef struct { + uint8_t slot; + uint16_t size; + uint16_t row1; + uint16_t row2; -extern spd_t *spd_devices[SPD_MAX_SLOTS]; + union { + uint8_t data[SPD_DATA_SIZE]; + spd_edo_t edo_data; + spd_sdram_t sdram_data; + }; + void *eeprom; +} spd_t; extern void spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size); - +extern void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); +extern void spd_write_drbs_with_ext(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); +extern void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); +extern void spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max); #endif /*EMU_SPD_H*/ diff --git a/src/include/86box/thread.h b/src/include/86box/thread.h new file mode 100644 index 000000000..a34dbefb5 --- /dev/null +++ b/src/include/86box/thread.h @@ -0,0 +1,46 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __APPLE__ +#define thread_t plat_thread_t +#define event_t plat_event_t +#define mutex_t plat_mutex_t + +#define thread_create plat_thread_create +#define thread_wait plat_thread_wait +#define thread_create_event plat_thread_create_event +#define thread_set_event plat_thread_set_event +#define thread_reset_event plat_thread_reset_event +#define thread_wait_event plat_thread_wait_event +#define thread_destroy_event plat_thread_destroy_event + +#define thread_create_mutex plat_thread_create_mutex +#define thread_create_mutex_with_spin_count plat_thread_create_mutex_with_spin_count +#define thread_close_mutex plat_thread_close_mutex +#define thread_wait_mutex plat_thread_wait_mutex +#define thread_release_mutex plat_thread_release_mutex +#endif + +/* Thread support. */ +typedef void thread_t; +typedef void event_t; +typedef void mutex_t; + +extern thread_t *thread_create(void (*thread_func)(void *param), void *param); +extern int thread_wait(thread_t *arg); +extern event_t *thread_create_event(void); +extern void thread_set_event(event_t *arg); +extern void thread_reset_event(event_t *arg); +extern int thread_wait_event(event_t *arg, int timeout); +extern void thread_destroy_event(event_t *arg); + +extern mutex_t *thread_create_mutex(void); +extern void thread_close_mutex(mutex_t *arg); +extern int thread_test_mutex(mutex_t *arg); +extern int thread_wait_mutex(mutex_t *arg); +extern int thread_release_mutex(mutex_t *mutex); + +#ifdef __cplusplus +} +#endif diff --git a/src/include/86box/timer.h b/src/include/86box/timer.h index f75dc1727..afbcec140 100644 --- a/src/include/86box/timer.h +++ b/src/include/86box/timer.h @@ -30,7 +30,7 @@ typedef union 32:32 fixed point format, with the integer part compared against the TSC. The fractional part is used when advancing the timestamp to ensure a more accurate period. - + As the timer only stores 32 bits of integer timestamp, and the TSC is 64 bits, the timer period can only be at most 0x7fffffff CPU cycles. To allow room for (optimistic) CPU frequency growth, timer period must be at most 1 second. @@ -56,6 +56,10 @@ typedef struct pc_timer_t struct pc_timer_t *prev, *next; } pc_timer_t; +#ifdef __cplusplus +extern "C" { +#endif + /*Timestamp of nearest enabled timer. CPU emulation must call timer_process() when TSC matches or exceeds this.*/ extern uint32_t timer_target; @@ -80,17 +84,9 @@ extern void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int extern uint64_t TIMER_USEC; /*True if timer a expires before timer b*/ -#if 0 -#define TIMER_LESS_THAN(a, b) ((int32_t)((a)->ts_integer - (b)->ts_integer) <= 0) -#else #define TIMER_LESS_THAN(a, b) ((int64_t)((a)->ts.ts64 - (b)->ts.ts64) <= 0) -#endif /*True if timer a expires before 32 bit integer timestamp b*/ -#if 0 -#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts_integer - (b)) <= 0) -#else #define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts.ts32.integer - (b)) <= 0) -#endif /*True if 32 bit integer timestamp a expires before 32 bit integer timestamp b*/ #define TIMER_VAL_LESS_THAN_VAL(a, b) ((int32_t)((a) - (b)) <= 0) @@ -100,17 +96,7 @@ extern uint64_t TIMER_USEC; static __inline void timer_advance_u64(pc_timer_t *timer, uint64_t delay) { -#if 0 - uint32_t int_delay = delay >> 32; - uint32_t frac_delay = delay & 0xffffffff; - - if ((frac_delay + timer->ts_frac) < frac_delay) - timer->ts_integer++; - timer->ts_frac += frac_delay; - timer->ts_integer += int_delay; -#else timer->ts.ts64 += delay; -#endif timer_enable(timer); } @@ -121,17 +107,9 @@ timer_advance_u64(pc_timer_t *timer, uint64_t delay) static __inline void timer_set_delay_u64(pc_timer_t *timer, uint64_t delay) { -#if 0 - uint32_t int_delay = delay >> 32; - uint32_t frac_delay = delay & 0xffffffff; - - timer->ts_frac = frac_delay; - timer->ts_integer = int_delay + (uint32_t)tsc; -#else timer->ts.ts64 = 0ULL; timer->ts.ts32.integer = tsc; timer->ts.ts64 += delay; -#endif timer_enable(timer); } @@ -149,11 +127,7 @@ timer_is_enabled(pc_timer_t *timer) static __inline uint32_t timer_get_ts_int(pc_timer_t *timer) { -#if 0 - return timer->ts_integer; -#else return timer->ts.ts32.integer; -#endif } @@ -165,11 +139,7 @@ timer_get_remaining_us(pc_timer_t *timer) int64_t remaining; if (timer->flags & TIMER_ENABLED) { -#if 0 - remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); -#else remaining = (int64_t) (timer->ts.ts64 - (uint64_t)(tsc << 32)); -#endif if (remaining < 0) return 0; @@ -188,11 +158,7 @@ timer_get_remaining_u64(pc_timer_t *timer) int64_t remaining; if (timer->flags & TIMER_ENABLED) { -#if 0 - remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); -#else remaining = (int64_t) (timer->ts.ts64 - (uint64_t)(tsc << 32)); -#endif if (remaining < 0) return 0; @@ -225,4 +191,58 @@ extern void timer_advance_ex(pc_timer_t *timer, int start); extern void timer_on(pc_timer_t *timer, double period, int start); extern void timer_on_auto(pc_timer_t *timer, double period); +extern void timer_remove_head(void); + + +extern pc_timer_t * timer_head; +extern int timer_inited; + + +static __inline void +timer_remove_head_inline(void) +{ + pc_timer_t *timer; + + if (timer_inited && timer_head) { + timer = timer_head; + timer_head = timer->next; + if (timer_head) { + timer_head->prev = NULL; + timer->next->prev = NULL; + } + timer->next = timer->prev = NULL; + timer->flags &= ~TIMER_ENABLED; + } +} + + +static __inline void +timer_process_inline(void) +{ + pc_timer_t *timer; + + if (!timer_inited || !timer_head) + return; + + while(1) { + timer = timer_head; + + if (!TIMER_LESS_THAN_VAL(timer, (uint32_t)tsc)) + break; + + timer_remove_head_inline(); + + if (timer->flags & TIMER_SPLIT) + timer_advance_ex(timer, 0); /* We're splitting a > 1 s period into multiple <= 1 s periods. */ + else if (timer->callback != NULL) /* Make sure it's no NULL, so that we can have a NULL callback when no operation is needed. */ + timer->callback(timer->p); + } + + timer_target = timer_head->ts.ts32.integer; +} + +#ifdef __cplusplus +} +#endif + #endif /*_TIMER_H_*/ diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index f497fb857..adfb84581 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -19,7 +19,6 @@ #ifndef EMU_UI_H # define EMU_UI_H - #ifdef __cplusplus extern "C" { #endif @@ -34,7 +33,10 @@ extern "C" { #define MBX_ERROR 2 #define MBX_QUESTION 3 #define MBX_QUESTION_YN 4 -#define MBX_FATAL 0x20 +#define MBX_QUESTION_OK 8 +#define MBX_QMARK 0x10 +#define MBX_WARNING 0x20 +#define MBX_FATAL 0x40 #define MBX_ANSI 0x80 #define MBX_LINKS 0x100 #define MBX_DONTASK 0x200 @@ -47,31 +49,36 @@ extern void ui_check_menu_item(int id, int checked); /* Status Bar functions. */ #define SB_ICON_WIDTH 24 -#define SB_FLOPPY 0x00 -#define SB_CDROM 0x10 -#define SB_ZIP 0x20 -#define SB_MO 0x30 -#define SB_HDD 0x40 -#define SB_NETWORK 0x50 -#define SB_SOUND 0x60 -#define SB_TEXT 0x70 +#define SB_CASSETTE 0x00 +#define SB_CARTRIDGE 0x10 +#define SB_FLOPPY 0x20 +#define SB_CDROM 0x30 +#define SB_ZIP 0x40 +#define SB_MO 0x50 +#define SB_HDD 0x60 +#define SB_NETWORK 0x70 +#define SB_SOUND 0x80 +#define SB_TEXT 0x90 extern wchar_t *ui_window_title(wchar_t *s); extern void ui_status_update(void); +extern void ui_init_monitor(int monitor_index); +extern void ui_deinit_monitor(int monitor_index); extern int ui_sb_find_part(int tag); extern void ui_sb_set_ready(int ready); extern void ui_sb_update_panes(void); +extern void ui_sb_update_text(void); extern void ui_sb_update_tip(int meaning); extern void ui_sb_timer_callback(int pane); -extern void ui_sb_update_icon(int tag, int val); -extern void ui_sb_update_icon_state(int tag, int active); +extern void ui_sb_update_icon(int tag, int active); +extern void ui_sb_update_icon_state(int tag, int state); extern void ui_sb_set_text_w(wchar_t *wstr); extern void ui_sb_set_text(char *str); extern void ui_sb_bugui(char *str); +extern void ui_sb_mt32lcd(char *str); #ifdef __cplusplus } #endif - #endif /*EMU_UI_H*/ diff --git a/src/include/86box/unix_sdl.h b/src/include/86box/unix_sdl.h new file mode 100644 index 000000000..24214ec31 --- /dev/null +++ b/src/include/86box/unix_sdl.h @@ -0,0 +1,14 @@ +#ifndef _UNIX_SDL_H +# define _UNIX_SDL_H + +extern void sdl_close(void); +extern int sdl_inits(); +extern int sdl_inith(); +extern int sdl_initho(); +extern int sdl_pause(void); +extern void sdl_resize(int x, int y); +extern void sdl_enable(int enable); +extern void sdl_set_fs(int fs); +extern void sdl_reload(void); + +#endif /*_UNIX_SDL_H*/ diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index aced538c8..68c1fc88a 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -14,6 +14,7 @@ * * Copyright 2020 Miran Grca. */ + #ifndef USB_H # define USB_H @@ -24,7 +25,7 @@ extern "C" { typedef struct { - uint8_t ohci_mmio[4096]; + uint8_t uhci_io[32], ohci_mmio[4096]; uint16_t uhci_io_base; int uhci_enable, ohci_enable; uint32_t ohci_mem_base; @@ -44,5 +45,4 @@ extern void ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, u } #endif - #endif /*USB_H*/ diff --git a/src/include/86box/version.h.in b/src/include/86box/version.h.in new file mode 100644 index 000000000..b8cd9ed97 --- /dev/null +++ b/src/include/86box/version.h.in @@ -0,0 +1,58 @@ +/* + * 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. + * + * Definitions for project version, branding, and external links. + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ + +#define _LSTR(s) L ## s +#define LSTR(s) _LSTR(s) + +/* Version info. */ +#define EMU_NAME "@CMAKE_PROJECT_NAME@" +#define EMU_NAME_W LSTR(EMU_NAME) + +#define EMU_VERSION "@CMAKE_PROJECT_VERSION@" +#define EMU_VERSION_W LSTR(EMU_VERSION) +#define EMU_VERSION_EX "3.50" /* frozen due to IDE re-detection behavior on Windows */ +#define EMU_VERSION_MAJ @CMAKE_PROJECT_VERSION_MAJOR@ +#define EMU_VERSION_MIN @CMAKE_PROJECT_VERSION_MINOR@ +#define EMU_VERSION_PATCH @CMAKE_PROJECT_VERSION_PATCH@ + +#cmakedefine EMU_BUILD "@EMU_BUILD@" +#define EMU_BUILD_NUM @EMU_BUILD_NUM@ +#cmakedefine EMU_GIT_HASH "@EMU_GIT_HASH@" + +#ifdef EMU_BUILD +# define EMU_BUILD_W LSTR(EMU_BUILD) +# define EMU_VERSION_FULL EMU_VERSION " [" EMU_BUILD "]" +# define EMU_VERSION_FULL_W EMU_VERSION_W L" [" EMU_BUILD_W L"]" +#else +# define EMU_VERSION_FULL EMU_VERSION +# define EMU_VERSION_FULL_W EMU_VERSION_W +#endif +#ifdef EMU_GIT_HASH +# define EMU_GIT_HASH_W LSTR(EMU_GIT_HASH) +#endif + +#define COPYRIGHT_YEAR "@EMU_COPYRIGHT_YEAR@" + +/* Web URL info. */ +#define EMU_SITE "86box.net" +#define EMU_SITE_W LSTR(EMU_SITE) +#define EMU_ROMS_URL "https://github.com/86Box/roms/releases/latest" +#define EMU_ROMS_URL_W LSTR(EMU_ROMS_URL) +#ifdef RELEASE_BUILD +# define EMU_DOCS_URL "https://86box.readthedocs.io/en/v@CMAKE_PROJECT_VERSION_MAJOR@.@CMAKE_PROJECT_VERSION_MINOR@/" +#else +# define EMU_DOCS_URL "https://86box.readthedocs.io" +#endif +#define EMU_DOCS_URL_W LSTR(EMU_DOCS_URL) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h new file mode 100644 index 000000000..a9816ac4a --- /dev/null +++ b/src/include/86box/vid_8514a.h @@ -0,0 +1,112 @@ +/* + * 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 the 8514/A card from IBM for the MCA bus and + * generic ISA bus clones without vendor extensions. + * + * + * + * Authors: TheCollector1995 + * + * Copyright 2022 TheCollector1995. + */ + +#ifndef VIDEO_8514A_H +# define VIDEO_8514A_H + +typedef struct ibm8514_t +{ + uint8_t pos_regs[8]; + + int force_old_addr; + int type; + + uint32_t vram_size; + uint32_t vram_mask; + + PALETTE vgapal; + uint8_t dac_mask, dac_status; + uint32_t *map8; + int dac_addr, dac_pos, dac_r, dac_g; + + struct { + uint16_t subsys_cntl; + uint16_t setup_md; + uint8_t advfunc_cntl, ext_advfunc_cntl; + uint16_t cur_y, cur_y_bitres; + uint16_t cur_x, cur_x_bitres; + int16_t desty_axstp; + int16_t destx_distp; + int16_t err_term; + int16_t maj_axis_pcnt; + uint16_t cmd, cmd_back; + uint16_t short_stroke; + uint16_t bkgd_color; + uint16_t frgd_color; + uint16_t wrt_mask; + uint16_t rd_mask; + uint16_t color_cmp; + uint16_t bkgd_mix; + uint16_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + int16_t clip_left, clip_top; + uint8_t pix_trans[2]; + int poly_draw; + int ssv_state; + int x1, x2, y1, y2; + int sys_cnt, sys_cnt2; + int temp_cnt; + int16_t cx, cy, oldcy; + int16_t sx, sy; + int16_t dx, dy; + int16_t err; + uint32_t src, dest; + uint32_t newsrc_blt, newdest_blt; + uint32_t newdest_in, newdest_out; + uint8_t *writemono, *nibbleset; + int x_count, xx_count, y_count; + int input, output; + + uint16_t cur_x_bit12, cur_y_bit12; + int ssv_len; + uint8_t ssv_dir; + uint8_t ssv_draw; + int odd_in, odd_out; + + uint16_t scratch; + int fill_state, xdir, ydir; + } accel; + + uint16_t test; + + int v_total, dispend, v_syncstart, split, + h_disp, h_disp_old, h_total, h_disp_time, rowoffset, + dispon, hdisp_on, linecountff, + vc, linepos, oddeven, cursoron, blink, scrollcache, + firstline, lastline, firstline_draw, lastline_draw, + displine, fullchange, x_add, y_add; + uint32_t ma, maback; + + uint8_t *vram, *changedvram, linedbl; + + uint8_t data_available, data_available2; + uint8_t scanmodulos, rowcount; + int htotal, hdisp, vtadj, vdadj, vsadj, sc, + vtb, vdb, vsb, vsyncstart, vsyncwidth; + int vtotal, vdisp; + int disp_cntl, interlace; + uint8_t subsys_cntl, subsys_stat; + + volatile int force_busy, force_busy2; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} ibm8514_t; +#endif /*VIDEO_8514A_H*/ diff --git a/src/include/86box/vid_ati_eeprom.h b/src/include/86box/vid_ati_eeprom.h index 786ae0c8b..bb2114739 100644 --- a/src/include/86box/vid_ati_eeprom.h +++ b/src/include/86box/vid_ati_eeprom.h @@ -1,6 +1,38 @@ +#ifndef VIDEO_ATI_EEPROM_H +# define VIDEO_ATI_EEPROM_H + /* Copyright holders: Sarah Walker see COPYING for more details */ + +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + + typedef struct ati_eeprom_t { uint16_t data[256]; @@ -10,10 +42,13 @@ typedef struct ati_eeprom_t int wp; uint32_t dat; int type; + int address; - wchar_t fn[256]; + char fn[256]; } ati_eeprom_t; -void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type); +void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type); void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); int ati_eeprom_read(ati_eeprom_t *eeprom); + +#endif /*VIDEO_ATI_EEPROM_H*/ diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 708879fdd..d36872e18 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -16,15 +16,18 @@ * Copyright 2016-2018 Miran Grca. */ +#ifndef VIDEO_CGA_H +# define VIDEO_CGA_H + typedef struct cga_t { mem_mapping_t mapping; - + int crtcreg; uint8_t crtc[32]; - + uint8_t cgastat; - + uint8_t cgamode, cgacol; int fontbase; @@ -38,13 +41,15 @@ typedef struct cga_t uint64_t dispontime, dispofftime; pc_timer_t timer; - + int firstline, lastline; - + int drawcursor; - + + int fullchange; + uint8_t *vram; - + uint8_t charbuffer[256]; int revision; @@ -65,3 +70,5 @@ void cga_poll(void *p); extern const device_config_t cga_config[]; extern const device_t cga_device; #endif + +#endif /*VIDEO_CGA_H*/ diff --git a/src/include/86box/vid_cga_comp.h b/src/include/86box/vid_cga_comp.h index 5ce52e61a..b221e96a4 100644 --- a/src/include/86box/vid_cga_comp.h +++ b/src/include/86box/vid_cga_comp.h @@ -17,6 +17,9 @@ * Copyright 2015-2018 Miran Grca. */ +#ifndef VIDEO_CGA_COMP_H +# define VIDEO_CGA_COMP_H + #define Bit8u uint8_t #define Bit32u uint32_t #define Bitu unsigned int @@ -25,3 +28,5 @@ void update_cga16_color(uint8_t cgamode); void cga_comp_init(int revision); Bit32u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit32u *TempLine); + +#endif /*VIDEO_CGA_COMP_H*/ diff --git a/src/include/86box/vid_colorplus.h b/src/include/86box/vid_colorplus.h index 07a96ff4f..8466a3e43 100644 --- a/src/include/86box/vid_colorplus.h +++ b/src/include/86box/vid_colorplus.h @@ -1,3 +1,6 @@ +#ifndef VIDEO_COLORPLUS_H +# define VIDEO_COLORPLUS_H + typedef struct colorplus_t { cga_t cga; @@ -13,3 +16,5 @@ void colorplus_recalctimings(colorplus_t *colorplus); void colorplus_poll(void *p); extern const device_t colorplus_device; + +#endif /*VIDEO_COLORPLUS_H*/ diff --git a/src/include/86box/vid_ddc.h b/src/include/86box/vid_ddc.h new file mode 100644 index 000000000..297ad65bf --- /dev/null +++ b/src/include/86box/vid_ddc.h @@ -0,0 +1,26 @@ +/* + * 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. + * + * DDC monitor emulation definitions. + * + * + * + * Authors: Sarah Walker, + * RichardG, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2020 RichardG. + */ + +#ifndef EMU_VID_DDC_H +# define EMU_VID_DDC_H + +extern void *ddc_init(void *i2c); +extern void ddc_close(void *eeprom); + +#endif /*EMU_VID_DDC_H*/ diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index caa7c0822..f1ba7e417 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -17,6 +17,7 @@ * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. */ + #ifndef VIDEO_EGA_H # define VIDEO_EGA_H @@ -45,14 +46,14 @@ typedef struct ega_t { readmode, writemode, readplane, vrammask, chain4, chain2_read, chain2_write, con, oddeven_page, oddeven_chain, vc, sc, - dispon, hdisp_on, cursoron, blink, + dispon, hdisp_on, cursoron, blink, fullchange, linepos, vslines, linecountff, oddeven, lowres, interlace, linedbl, lindebl, rowcount, vtotal, dispend, vsyncstart, split, hdisp, hdisp_old, htotal, hdisp_time, rowoffset, vblankstart, scrollcache, firstline, lastline, firstline_draw, lastline_draw, x_add, y_add, - displine, video_res_x, video_res_y, video_bpp, index; + displine, res_x, res_y, bpp, index; uint32_t charseta, charsetb, ma_latch, ma, maback, ca, vram_limit, overscan_color; @@ -64,6 +65,9 @@ typedef struct ega_t { double clock; + int remap_required; + uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr); + void (*render)(struct ega_t *svga); void *eeprom; @@ -76,6 +80,8 @@ extern const device_t ega_device; extern const device_t cpqega_device; extern const device_t sega_device; extern const device_t atiega_device; +extern const device_t iskra_ega_device; +extern const device_t et2000_device; #endif extern int update_overscan; @@ -91,6 +97,7 @@ extern int update_overscan; #if defined(EMU_MEM_H) && defined(EMU_ROM_H) extern void ega_init(ega_t *ega, int monitor_type, int is_mono); extern void ega_recalctimings(struct ega_t *ega); +extern void ega_recalc_remap_func(struct ega_t *ega); #endif extern void ega_out(uint16_t addr, uint8_t val, void *p); @@ -127,5 +134,4 @@ void ega_render_4bpp_lowres(ega_t *ega); void ega_render_4bpp_highres(ega_t *ega); #endif - #endif /*VIDEO_EGA_H*/ diff --git a/src/include/86box/vid_ega_render_remap.h b/src/include/86box/vid_ega_render_remap.h new file mode 100644 index 000000000..cae9a2b1d --- /dev/null +++ b/src/include/86box/vid_ega_render_remap.h @@ -0,0 +1,111 @@ +#ifndef VIDEO_EGA_RENDER_REMAP_H +# define VIDEO_EGA_RENDER_REMAP_H + +#define VAR_BYTE_MODE (0 << 0) +#define VAR_WORD_MODE_MA13 (1 << 0) +#define VAR_WORD_MODE_MA15 (2 << 0) +#define VAR_DWORD_MODE (3 << 0) +#define VAR_MODE_MASK (3 << 0) +#define VAR_ROW0_MA13 (1 << 2) +#define VAR_ROW1_MA14 (1 << 3) + +#define ADDRESS_REMAP_FUNC(nr) \ + static uint32_t address_remap_func_ ## nr(ega_t *ega, uint32_t in_addr) \ + { \ + uint32_t out_addr; \ + \ + switch (nr & VAR_MODE_MASK) \ + { \ + case VAR_BYTE_MODE: \ + out_addr = in_addr; \ + break; \ + \ + case VAR_WORD_MODE_MA13: \ + out_addr = ((in_addr << 1) & 0x1fff8) | \ + ((in_addr >> 13) & 0x4) | \ + (in_addr & ~0x1ffff); \ + break; \ + \ + case VAR_WORD_MODE_MA15: \ + out_addr = ((in_addr << 1) & 0x1fff8) | \ + ((in_addr >> 15) & 0x4) | \ + (in_addr & ~0x1ffff); \ + break; \ + \ + case VAR_DWORD_MODE: \ + out_addr = ((in_addr << 2) & 0x3fff0) | \ + ((in_addr >> 14) & 0xc) | \ + (in_addr & ~0x3ffff); \ + break; \ + } \ + \ + if (nr & VAR_ROW0_MA13) \ + out_addr = (out_addr & ~0x8000) | \ + ((ega->sc & 1) ? 0x8000 : 0); \ + if (nr & VAR_ROW1_MA14) \ + out_addr = (out_addr & ~0x10000) | \ + ((ega->sc & 2) ? 0x10000 : 0); \ + \ + return out_addr; \ + } + +ADDRESS_REMAP_FUNC(0) +ADDRESS_REMAP_FUNC(1) +ADDRESS_REMAP_FUNC(2) +ADDRESS_REMAP_FUNC(3) +ADDRESS_REMAP_FUNC(4) +ADDRESS_REMAP_FUNC(5) +ADDRESS_REMAP_FUNC(6) +ADDRESS_REMAP_FUNC(7) +ADDRESS_REMAP_FUNC(8) +ADDRESS_REMAP_FUNC(9) +ADDRESS_REMAP_FUNC(10) +ADDRESS_REMAP_FUNC(11) +ADDRESS_REMAP_FUNC(12) +ADDRESS_REMAP_FUNC(13) +ADDRESS_REMAP_FUNC(14) +ADDRESS_REMAP_FUNC(15) + +static uint32_t (*address_remap_funcs[16])(ega_t *ega, uint32_t in_addr) = +{ + address_remap_func_0, + address_remap_func_1, + address_remap_func_2, + address_remap_func_3, + address_remap_func_4, + address_remap_func_5, + address_remap_func_6, + address_remap_func_7, + address_remap_func_8, + address_remap_func_9, + address_remap_func_10, + address_remap_func_11, + address_remap_func_12, + address_remap_func_13, + address_remap_func_14, + address_remap_func_15 +}; + +void ega_recalc_remap_func(ega_t *ega) +{ + int func_nr; + + if (ega->crtc[0x14] & 0x40) + func_nr = VAR_DWORD_MODE; + else if (ega->crtc[0x17] & 0x40) + func_nr = VAR_BYTE_MODE; + else if (ega->crtc[0x17] & 0x20) + func_nr = VAR_WORD_MODE_MA15; + else + func_nr = VAR_WORD_MODE_MA13; + + if (!(ega->crtc[0x17] & 0x01)) + func_nr |= VAR_ROW0_MA13; + if (!(ega->crtc[0x17] & 0x02)) + func_nr |= VAR_ROW1_MA14; + + ega->remap_required = (func_nr != 0); + ega->remap_func = address_remap_funcs[func_nr]; +} + +#endif /*VIDEO_RENDER_REMAP_H*/ diff --git a/src/include/86box/vid_hercules.h b/src/include/86box/vid_hercules.h new file mode 100644 index 000000000..93785d9be --- /dev/null +++ b/src/include/86box/vid_hercules.h @@ -0,0 +1,68 @@ +/* + * 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 the Hercules graphics cards. + * + * + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2021 Jasmine Iwanek. + */ + +#ifndef VIDEO_HERCULES_H +# define VIDEO_HERCULES_H + +typedef struct { + mem_mapping_t mapping; + + uint8_t crtc[32], charbuffer[4096]; + int crtcreg; + + uint8_t ctrl, + ctrl2, + stat; + + uint64_t dispontime, + dispofftime; + pc_timer_t timer; + + int firstline, + lastline; + + int linepos, + displine; + int vc, + sc; + uint16_t ma, + maback; + int con, coff, + cursoron; + int dispon, + blink; + int vsynctime; + int vadj; + + int lp_ff; + int fullchange; + + int cols[256][2][2]; + + uint8_t *vram; + int monitor_index; + int prev_monitor_index; +} hercules_t; + +#define VIDEO_MONITOR_PROLOGUE() { dev->prev_monitor_index = monitor_index_global; monitor_index_global = dev->monitor_index; } +#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = dev->prev_monitor_index; } + +static void *hercules_init(const device_t *info); + +#endif /*VIDEO_HERCULES_H*/ diff --git a/src/include/86box/vid_mda.h b/src/include/86box/vid_mda.h index 82a8f5e19..3e32ef848 100644 --- a/src/include/86box/vid_mda.h +++ b/src/include/86box/vid_mda.h @@ -1,18 +1,22 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ + +#ifndef VIDEO_MDA_H +# define VIDEO_MDA_H + typedef struct mda_t { mem_mapping_t mapping; - + uint8_t crtc[32]; int crtcreg; - + uint8_t ctrl, stat; - + uint64_t dispontime, dispofftime; pc_timer_t timer; - + int firstline, lastline; int linepos, displine; @@ -21,11 +25,16 @@ typedef struct mda_t int con, coff, cursoron; int dispon, blink; int vsynctime; - int vadj; + int vadj; + int monitor_index; + int prev_monitor_index; uint8_t *vram; } mda_t; +#define VIDEO_MONITOR_PROLOGUE() { mda->prev_monitor_index = monitor_index_global; monitor_index_global = mda->monitor_index; } +#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = mda->prev_monitor_index; } + void mda_init(mda_t *mda); void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink); void mda_out(uint16_t addr, uint8_t val, void *p); @@ -38,3 +47,5 @@ void mda_poll(void *p); #ifdef EMU_DEVICE_H extern const device_t mda_device; #endif + +#endif /*VIDEO_MDA_H*/ diff --git a/src/include/86box/vid_nga.h b/src/include/86box/vid_nga.h new file mode 100644 index 000000000..8aa096604 --- /dev/null +++ b/src/include/86box/vid_nga.h @@ -0,0 +1,53 @@ +/* + * 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 the Olivetti OGC 8-bit ISA (GO708) and + * M21/M24/M28 16-bit bus (GO317/318/380/709) video cards. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ + +#ifndef VIDEO_NGA_H +# define VIDEO_NGA_H + +typedef struct nga_t { + cga_t cga; + /* unused in OGC, required for M19 video card structure idiom */ + uint32_t base; + int lineff; + int page; + uint8_t *vram_64k; + mem_mapping_t mapping_64k; +} nga_t; + +void nga_recalctimings(nga_t *ogc); +void nga_out(uint16_t addr, uint8_t val, void *priv); +uint8_t nga_in(uint16_t addr, void *priv); +void nga_write(uint32_t addr, uint8_t val, void *priv); +uint8_t nga_read(uint32_t addr, void *priv); +void nga_poll(void *priv); +void nga_close(void *priv); +void nga_mdaattr_rebuild(); + + +#ifdef EMU_DEVICE_H +extern const device_config_t nga_config[]; +extern const device_t nga_device; +#endif + +#endif /*VIDEO_NGA_H*/ diff --git a/src/include/86box/vid_ogc.h b/src/include/86box/vid_ogc.h new file mode 100644 index 000000000..20ac4996e --- /dev/null +++ b/src/include/86box/vid_ogc.h @@ -0,0 +1,53 @@ +/* + * 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 the Olivetti OGC 8-bit ISA (GO708) and + * M21/M24/M28 16-bit bus (GO317/318/380/709) video cards. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ + +#ifndef VIDEO_OGC_H +# define VIDEO_OGC_H + +typedef struct ogc_t { + cga_t cga; + /* unused in OGC, required for M19 video card structure idiom */ + uint8_t ctrl_3dd; + uint8_t ctrl_3de; + uint32_t base; + int lineff; + int mono_display; +} ogc_t; + +void ogc_recalctimings(ogc_t *ogc); +void ogc_out(uint16_t addr, uint8_t val, void *priv); +uint8_t ogc_in(uint16_t addr, void *priv); +void ogc_write(uint32_t addr, uint8_t val, void *priv); +uint8_t ogc_read(uint32_t addr, void *priv); +void ogc_poll(void *priv); +void ogc_close(void *priv); +void ogc_mdaattr_rebuild(); + + +#ifdef EMU_DEVICE_H +extern const device_config_t ogc_config[]; +extern const device_t ogc_device; +#endif + +#endif /*VIDEO_OGC_H*/ diff --git a/src/include/86box/vid_pgc.h b/src/include/86box/vid_pgc.h index 1a179a775..1bf0adf95 100644 --- a/src/include/86box/vid_pgc.h +++ b/src/include/86box/vid_pgc.h @@ -19,7 +19,6 @@ #ifndef VID_PGC_H # define VID_PGC_H - #define PGC_ERROR_RANGE 0x01 #define PGC_ERROR_INTEGER 0x02 #define PGC_ERROR_MEMORY 0x03 @@ -49,7 +48,7 @@ typedef struct pgc_cmd { uint8_t hex; void (*handler)(struct pgc *); int (*parser) (struct pgc *, pgc_cl_t *, int); - int p; + int p; } pgc_cmd_t; typedef struct pgc { @@ -99,7 +98,7 @@ typedef struct pgc { int waiting_error_fifo; int ascii_mode; int result_count; - + int fontbase; int linepos, displine; @@ -117,7 +116,7 @@ typedef struct pgc { int drawcursor; - int (*inputbyte)(struct pgc *, uint8_t *result); + int (*inputbyte)(struct pgc *, uint8_t *result); } pgc_t; @@ -133,6 +132,7 @@ extern void pgc_wake(pgc_t *); extern void pgc_sleep(pgc_t *); extern void pgc_setdisplay(pgc_t *, int cga); extern void pgc_speed_changed(void *priv); +extern void pgc_close_common(void *priv); extern void pgc_close(void *priv); extern void pgc_init(pgc_t *, int maxw, int maxh, int visw, int vish, @@ -180,5 +180,4 @@ extern int pgc_result_coord(pgc_t *, int32_t val); extern void pgc_hndl_lut8(pgc_t *); extern void pgc_hndl_lut8rd(pgc_t *); - #endif /*VID_PGC_H*/ diff --git a/src/include/86box/vid_pgc_palette.h b/src/include/86box/vid_pgc_palette.h index ccc9ac2bd..8f2a96a5a 100644 --- a/src/include/86box/vid_pgc_palette.h +++ b/src/include/86box/vid_pgc_palette.h @@ -16,6 +16,7 @@ * Copyright 2019 Fred N. van Kempen. * Copyright 2019 John Elliott. */ + #ifndef VID_PGC_PALETTE_H # define VID_PGC_PALETTE_H @@ -1575,5 +1576,4 @@ makecol(0x00,0x00,0x00), }, - #endif /*VID_PGC_PALETTE_H*/ diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index acdea041c..530ea648d 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -13,19 +13,29 @@ * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ +#include <86box/thread.h> +#include <86box/vid_8514a.h> +#include <86box/vid_xga.h> + +#ifndef VIDEO_SVGA_H +# define VIDEO_SVGA_H #define FLAG_EXTRA_BANKS 1 #define FLAG_ADDR_BY8 2 -#define FLAG_LATCH8 4 - +#define FLAG_EXT_WRITE 4 +#define FLAG_LATCH8 8 +#define FLAG_NOSKEW 16 +#define FLAG_ADDR_BY16 32 +#define FLAG_RAMDAC_SHIFT 64 +#define FLAG_128K_MASK 128 typedef struct { int ena, - x, y, xoff, yoff, xsize, ysize, + x, y, xoff, yoff, cur_xsize, cur_ysize, v_acc, h_acc; uint32_t addr, pitch; } hwcursor_t; @@ -39,6 +49,8 @@ typedef union { typedef struct svga_t { + ibm8514_t dev8514; + xga_t xga; mem_mapping_t mapping; uint8_t fast, chain4, chain2_write, chain2_read, @@ -46,7 +58,8 @@ typedef struct svga_t lowres, interlace, linedbl, rowcount, set_reset_disabled, bpp, ramdac_type, fb_only, readmode, writemode, readplane, - hwcursor_oddeven, dac_hwcursor_oddeven, overlay_oddeven; + hwcursor_oddeven, dac_hwcursor_oddeven, overlay_oddeven, + fcr, hblank_overscan; int dac_addr, dac_pos, dac_r, dac_g, vtotal, dispend, vsyncstart, split, vblankstart, @@ -56,8 +69,9 @@ typedef struct svga_t con, cursoron, blink, scrollcache, char_width, firstline, lastline, firstline_draw, lastline_draw, displine, fullchange, x_add, y_add, pan, - vram_display_mask, vidclock, - hwcursor_on, dac_hwcursor_on, overlay_on; + vram_display_mask, vidclock, dots_per_clock, hblank_ext, + hwcursor_on, dac_hwcursor_on, overlay_on, set_override, + hblankstart, hblankend, hblank_sub, hblank_end_val, hblank_end_len; /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : 0MB-1MB - VRAM @@ -77,7 +91,7 @@ typedef struct svga_t extra_banks[2], banked_mask, ca, overscan_color, - *map8, pallook[256]; + *map8, pallook[512]; PALETTE vgapal; @@ -112,7 +126,7 @@ typedef struct svga_t /* Called when VC=R18 and friends. If this returns zero then MA resetting is skipped. Matrox Mystique in Power mode reuses this counter for vertical line interrupt*/ - int (*line_compare)(struct svga_t *svga); + int (*line_compare)(struct svga_t *svga); /*Called at the start of vertical sync*/ void (*vsync_callback)(struct svga_t *svga); @@ -123,7 +137,7 @@ typedef struct svga_t int override; void *p; - uint8_t crtc[128], gdcreg[64], attrregs[32], seqregs[64], + uint8_t crtc[256], gdcreg[256], attrregs[32], seqregs[256], egapal[16], *vram, *changedvram; @@ -133,21 +147,41 @@ typedef struct svga_t plane_mask, writemask, colourcompare, colournocare, dac_mask, dac_status, + dpms, dpms_ui, ksc5601_sbyte_mask, ksc5601_udc_area_msb[2]; int ksc5601_swap_mode; uint16_t ksc5601_english_font_type; int vertical_linedbl; - + /*Used to implement CRTC[0x17] bit 2 hsync divisor*/ int hsync_divisor; + /*Tseng-style chain4 mode - CRTC dword mode is the same as byte mode, chain4 + addresses are shifted to match*/ + int packed_chain4; + + /*Force CRTC to dword mode, regardless of CR14/CR17. Required for S3 enhanced mode*/ + int force_dword_mode; + + int force_old_addr; + + int remap_required; + uint32_t (*remap_func)(struct svga_t *svga, uint32_t in_addr); + void *ramdac, *clock_gen; } svga_t; +extern int vga_on, ibm8514_on; -extern int svga_init(const device_t *info, svga_t *svga, void *p, int memsize, +extern void ibm8514_poll(ibm8514_t *dev, svga_t *svga); +extern void ibm8514_recalctimings(svga_t *svga); + +extern void xga_poll(xga_t *xga, svga_t *svga); +extern void xga_recalctimings(svga_t *svga); + +extern int svga_init(const device_t *info, svga_t *svga, void *p, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), void (*video_out)(uint16_t addr, uint8_t val, void *p), @@ -187,7 +221,7 @@ void svga_close(svga_t *svga); uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); -void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); +void svga_doblit(int wx, int wy, svga_t *svga); enum { @@ -205,9 +239,11 @@ extern void ati68860_ramdac_set_render(void *p, svga_t *svga); extern void ati68860_ramdac_set_pallook(void *p, int i, uint32_t col); extern void ati68860_hwcursor_draw(svga_t *svga, int displine); -extern void att49x_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga); -extern uint8_t att49x_ramdac_in(uint16_t addr, void *p, svga_t *svga); +extern void att49x_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga); +extern uint8_t att49x_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga); +extern void att498_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga); +extern uint8_t att498_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga); extern float av9194_getclock(int clock, void *p); extern void bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t *svga); @@ -215,6 +251,11 @@ extern uint8_t bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t extern void bt48x_recalctimings(void *p, svga_t *svga); extern void bt48x_hwcursor_draw(svga_t *svga, int displine); +extern void ibm_rgb528_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga); +extern uint8_t ibm_rgb528_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga); +extern void ibm_rgb528_recalctimings(void *p, svga_t *svga); +extern void ibm_rgb528_hwcursor_draw(svga_t *svga, int displine); + extern void icd2061_write(void *p, int val); extern float icd2061_getclock(int clock, void *p); @@ -222,10 +263,15 @@ extern float icd2061_getclock(int clock, void *p); #define ics9161_write icd2061_write #define ics9161_getclock icd2061_getclock +extern float ics2494_getclock(int clock, void *p); + extern void ics2595_write(void *p, int strobe, int dat); extern double ics2595_getclock(void *p); extern void ics2595_setclock(void *p, double clock); +extern void sc1148x_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga); +extern uint8_t sc1148x_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga); + extern void sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga); extern uint8_t sc1502x_ramdac_in(uint16_t addr, void *p, svga_t *svga); @@ -240,11 +286,18 @@ extern float stg_getclock(int clock, void *p); extern void tkd8001_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga); extern uint8_t tkd8001_ramdac_in(uint16_t addr, void *p, svga_t *svga); +extern void tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t *svga); +extern uint8_t tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga); +extern void tvp3026_recalctimings(void *p, svga_t *svga); +extern void tvp3026_hwcursor_draw(svga_t *svga, int displine); +extern float tvp3026_getclock(int clock, void *p); #ifdef EMU_DEVICE_H extern const device_t ati68860_ramdac_device; extern const device_t att490_ramdac_device; +extern const device_t att491_ramdac_device; extern const device_t att492_ramdac_device; +extern const device_t att498_ramdac_device; extern const device_t av9194_device; extern const device_t bt484_ramdac_device; extern const device_t att20c504_ramdac_device; @@ -252,11 +305,22 @@ extern const device_t bt485_ramdac_device; extern const device_t att20c505_ramdac_device; extern const device_t bt485a_ramdac_device; extern const device_t gendac_ramdac_device; +extern const device_t ibm_rgb528_ramdac_device; +extern const device_t ics2494an_305_device; extern const device_t ics2595_device; extern const device_t icd2061_device; extern const device_t ics9161_device; +extern const device_t sc11483_ramdac_device; +extern const device_t sc11487_ramdac_device; +extern const device_t sc11486_ramdac_device; +extern const device_t sc11484_nors2_ramdac_device; extern const device_t sc1502x_ramdac_device; extern const device_t sdac_ramdac_device; extern const device_t stg_ramdac_device; extern const device_t tkd8001_ramdac_device; +extern const device_t tseng_ics5301_ramdac_device; +extern const device_t tseng_ics5341_ramdac_device; +extern const device_t tvp3026_ramdac_device; #endif + +#endif /*VIDEO_SVGA_H*/ diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 6b8b50613..e480e81f7 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -16,6 +16,9 @@ * Copyright 2016-2018 Miran Grca. */ +#ifndef VIDEO_SVGA_RENDER_H +# define VIDEO_SVGA_RENDER_H + extern int firstline_draw, lastline_draw; extern int displine; extern int sc; @@ -27,6 +30,9 @@ extern int scrollcache; extern uint8_t edatlookup[4][4]; +void svga_recalc_remap_func(svga_t *svga); + +void svga_render_null(svga_t *svga); void svga_render_blank(svga_t *svga); void svga_render_overscan_left(svga_t *svga); void svga_render_overscan_right(svga_t *svga); @@ -36,10 +42,13 @@ void svga_render_text_80_ksc5601(svga_t *svga); void svga_render_2bpp_lowres(svga_t *svga); void svga_render_2bpp_highres(svga_t *svga); +void svga_render_2bpp_headland_highres(svga_t *svga); void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); +void svga_render_8bpp_tseng_lowres(svga_t *svga); +void svga_render_8bpp_tseng_highres(svga_t *svga); void svga_render_8bpp_gs_lowres(svga_t *svga); void svga_render_8bpp_gs_highres(svga_t *svga); void svga_render_8bpp_rgb_lowres(svga_t *svga); @@ -60,3 +69,5 @@ void svga_render_RGBA8888_lowres(svga_t *svga); void svga_render_RGBA8888_highres(svga_t *svga); extern void (*svga_render)(svga_t *svga); + +#endif /*VID_SVGA_RENDER_H*/ diff --git a/src/include/86box/vid_svga_render_remap.h b/src/include/86box/vid_svga_render_remap.h new file mode 100644 index 000000000..1077cbc69 --- /dev/null +++ b/src/include/86box/vid_svga_render_remap.h @@ -0,0 +1,131 @@ +/*Variables : + byte/word/doubleword mode + word has MA13/MA15->MA0 + ET4000 treats doubleword as byte + row 0 -> MA13 + row 1 -> MA14 +*/ + +#ifndef VIDEO_SVGA_RENDER_REMAP_H +# define VIDEO_SVGA_RENDER_REMAP_H + +//S3 - enhanced mode mappings CR31.3 can force doubleword mode +//Cirrus Logic handles SVGA writes seperately +//S3, CL, TGUI blitters need checking + +//CL, S3, Mach64, ET4000, Banshee, TGUI all okay +//Still to check - ViRGE, HT216 +#define VAR_BYTE_MODE (0 << 0) +#define VAR_WORD_MODE_MA13 (1 << 0) +#define VAR_WORD_MODE_MA15 (2 << 0) +#define VAR_DWORD_MODE (3 << 0) +#define VAR_MODE_MASK (3 << 0) +#define VAR_ROW0_MA13 (1 << 2) +#define VAR_ROW1_MA14 (1 << 3) + +#define ADDRESS_REMAP_FUNC(nr) \ + static uint32_t address_remap_func_ ## nr(svga_t *svga, uint32_t in_addr) \ + { \ + uint32_t out_addr; \ + \ + switch (nr & VAR_MODE_MASK) \ + { \ + case VAR_BYTE_MODE: \ + out_addr = in_addr; \ + break; \ + \ + case VAR_WORD_MODE_MA13: \ + out_addr = ((in_addr << 1) & 0x1fff8) | \ + ((in_addr >> 13) & 0x4) | \ + (in_addr & ~0x1ffff); \ + break; \ + \ + case VAR_WORD_MODE_MA15: \ + out_addr = ((in_addr << 1) & 0x1fff8) | \ + ((in_addr >> 15) & 0x4) | \ + (in_addr & ~0x1ffff); \ + break; \ + \ + case VAR_DWORD_MODE: \ + out_addr = ((in_addr << 2) & 0x3fff0) | \ + ((in_addr >> 14) & 0xc) | \ + (in_addr & ~0x3ffff); \ + break; \ + } \ + \ + if (nr & VAR_ROW0_MA13) \ + out_addr = (out_addr & ~0x8000) | \ + ((svga->sc & 1) ? 0x8000 : 0); \ + if (nr & VAR_ROW1_MA14) \ + out_addr = (out_addr & ~0x10000) | \ + ((svga->sc & 2) ? 0x10000 : 0); \ + \ + return out_addr; \ + } + +ADDRESS_REMAP_FUNC(0) +ADDRESS_REMAP_FUNC(1) +ADDRESS_REMAP_FUNC(2) +ADDRESS_REMAP_FUNC(3) +ADDRESS_REMAP_FUNC(4) +ADDRESS_REMAP_FUNC(5) +ADDRESS_REMAP_FUNC(6) +ADDRESS_REMAP_FUNC(7) +ADDRESS_REMAP_FUNC(8) +ADDRESS_REMAP_FUNC(9) +ADDRESS_REMAP_FUNC(10) +ADDRESS_REMAP_FUNC(11) +ADDRESS_REMAP_FUNC(12) +ADDRESS_REMAP_FUNC(13) +ADDRESS_REMAP_FUNC(14) +ADDRESS_REMAP_FUNC(15) + +static uint32_t (*address_remap_funcs[16])(svga_t *svga, uint32_t in_addr) = +{ + address_remap_func_0, + address_remap_func_1, + address_remap_func_2, + address_remap_func_3, + address_remap_func_4, + address_remap_func_5, + address_remap_func_6, + address_remap_func_7, + address_remap_func_8, + address_remap_func_9, + address_remap_func_10, + address_remap_func_11, + address_remap_func_12, + address_remap_func_13, + address_remap_func_14, + address_remap_func_15 +}; + +void svga_recalc_remap_func(svga_t *svga) +{ + int func_nr; + + if (svga->fb_only) + func_nr = 0; + else { + if (svga->force_dword_mode) + func_nr = VAR_DWORD_MODE; + else if (svga->crtc[0x14] & 0x40) + func_nr = svga->packed_chain4 ? VAR_BYTE_MODE : VAR_DWORD_MODE; + else if (svga->crtc[0x17] & 0x40) + func_nr = VAR_BYTE_MODE; + else if (svga->crtc[0x17] & 0x20) + func_nr = VAR_WORD_MODE_MA15; + else + func_nr = VAR_WORD_MODE_MA13; + + if (!(svga->crtc[0x17] & 0x01)) + func_nr |= VAR_ROW0_MA13; + if (!(svga->crtc[0x17] & 0x02)) + func_nr |= VAR_ROW1_MA14; + } + + svga->remap_required = (func_nr != 0); + svga->remap_func = address_remap_funcs[func_nr]; +} + +#endif /*VIDEO_RENDER_REMAP_H*/ diff --git a/src/include/86box/vid_vga.h b/src/include/86box/vid_vga.h new file mode 100644 index 000000000..3ef627c43 --- /dev/null +++ b/src/include/86box/vid_vga.h @@ -0,0 +1,35 @@ +/* + * 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 the IBM MDA + VGA graphics cards. + * + * + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2021 Jasmine Iwanek. + */ + +#ifndef VIDEO_VGA_H +# define VIDEO_VGA_H + +typedef struct vga_t +{ + svga_t svga; + + rom_t bios_rom; +} vga_t; + +static video_timings_t timing_vga = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + +void vga_out(uint16_t addr, uint8_t val, void *p); +uint8_t vga_in(uint16_t addr, void *p); + +#endif /*VIDEO_VGA_H*/ diff --git a/src/include/86box/vid_voodoo_banshee.h b/src/include/86box/vid_voodoo_banshee.h new file mode 100644 index 000000000..b56caac88 --- /dev/null +++ b/src/include/86box/vid_voodoo_banshee.h @@ -0,0 +1,23 @@ +/* + * 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. + * + * Voodoo Banshee and 3 specific emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_BANSHEE_H +# define VIDEO_VOODOO_BANSHEE_H + +void banshee_set_overlay_addr(void *p, uint32_t addr); + +#endif /*VIDEO_VOODOO_BANSHEE_H*/ diff --git a/src/include/86box/vid_voodoo_banshee_blitter.h b/src/include/86box/vid_voodoo_banshee_blitter.h new file mode 100644 index 000000000..ad4d68218 --- /dev/null +++ b/src/include/86box/vid_voodoo_banshee_blitter.h @@ -0,0 +1,23 @@ +/* + * 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. + * + * Voodoo Banshee and 3 specific emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_BANSHEE_BLITTER_H +# define VIDEO_VOODOO_BANSHEE_BLITTER_H + +void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val); + +#endif /*VIDEO_VOODOO_BANSHEE_BLITTER_H*/ diff --git a/src/include/86box/vid_voodoo_blitter.h b/src/include/86box/vid_voodoo_blitter.h new file mode 100644 index 000000000..20d845874 --- /dev/null +++ b/src/include/86box/vid_voodoo_blitter.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_BLITTER_H +# define VIDEO_VOODOO_BLITTER_H + +void voodoo_v2_blit_start(voodoo_t *voodoo); +void voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data); +void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params); + +#endif /*VIDEO_VOODOO_BLITTER_H*/ diff --git a/src/include/86box/vid_voodoo_codegen_x86-64.h b/src/include/86box/vid_voodoo_codegen_x86-64.h index cecf3a539..632eacfb4 100644 --- a/src/include/86box/vid_voodoo_codegen_x86-64.h +++ b/src/include/86box/vid_voodoo_codegen_x86-64.h @@ -1,20 +1,18 @@ /*Registers : - + alphaMode fbzMode & 0x1f3fff fbzColorPath */ -#ifdef __linux__ -# include -# include -#endif -#if WIN64 -# include -#endif +#ifndef VIDEO_VOODOO_CODEGEN_X86_64_H +# define VIDEO_VOODOO_CODEGEN_X86_64_H +#ifdef _MSC_VER #include +#else #include +#endif #define BLOCK_NUM 8 #define BLOCK_MASK (BLOCK_NUM-1) @@ -22,6 +20,11 @@ #define LOD_MASK (LOD_TMIRROR_S | LOD_TMIRROR_T) +/* Suppress a false positive warning on gcc that causes excessive build log spam */ +#if __GNUC__ >= 10 +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + typedef struct voodoo_x86_data_t { uint8_t code_block[BLOCK_SIZE]; @@ -32,44 +35,51 @@ typedef struct voodoo_x86_data_t uint32_t fbzColorPath; uint32_t textureMode[2]; uint32_t tLOD[2]; - uint32_t trexInit1; + uint32_t trexInit1; + int is_tiled; } voodoo_x86_data_t; //static voodoo_x86_data_t voodoo_x86_data[2][BLOCK_NUM]; -static int last_block[2] = {0, 0}; -static int next_block_to_write[2] = {0, 0}; +static int last_block[4] = {0, 0}; +static int next_block_to_write[4] = {0, 0}; -#define addbyte(val) \ - code_block[block_pos++] = val; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addbyte(val) \ + do { \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addword(val) \ - *(uint16_t *)&code_block[block_pos] = val; \ - block_pos += 2; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addword(val) \ + do { \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addlong(val) \ - *(uint32_t *)&code_block[block_pos] = val; \ - block_pos += 4; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addlong(val) \ + do { \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addquad(val) \ - *(uint64_t *)&code_block[block_pos] = val; \ - block_pos += 8; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addquad(val) \ + do { \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) static __m128i xmm_01_w;// = 0x0001000100010001ull; static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; static __m128i xmm_ff_b;// = 0x00000000ffffffffull; -static uint32_t zero = 0; - static __m128i alookup[257], aminuslookup[256]; static __m128i minus_254;// = 0xff02ff02ff02ff02ull; static __m128i bilinear_lookup[256*2]; @@ -156,10 +166,11 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x89); /*MOV state->tex_s, EBX*/ addbyte(0x9f); addlong(offsetof(voodoo_state_t, tex_s)); - addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ + addbyte(0x41); /*MOVZX EAX, R9(logtable)[RAX]*/ + addbyte(0x0f); addbyte(0xb6); - addbyte(0x80); - addlong((uint32_t)(uintptr_t)logtable); + addbyte(0x04); + addbyte(0x01); addbyte(0x09); /*OR EAX, EDX*/ addbyte(0xd0); addbyte(0x03); /*ADD EAX, state->lod*/ @@ -181,7 +192,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addlong(offsetof(voodoo_state_t, lod_max[tmu])); addbyte(0xc1); /*SHR EAX, 8*/ addbyte(0xe8); - addbyte(8); + addbyte(8); addbyte(0x89); /*MOV state->lod, EAX*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, lod)); @@ -213,7 +224,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addlong(offsetof(voodoo_state_t, tex_s)); addbyte(0xc1); /*SHR EBX, 8*/ addbyte(0xeb); - addbyte(8); + addbyte(8); addbyte(0x48); /*MOV state->tex_t, RCX*/ addbyte(0x89); addbyte(0x8f); @@ -333,11 +344,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(1); if (state->clamp_t[tmu]) { - addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x41); /*CMOVS EDX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x14); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x12); addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ addbyte(0x96); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -347,11 +357,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); addbyte(0x85); /*TEST EBX,EBX*/ addbyte(0xdb); - addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x41); /*CMOVS EBX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x1a); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -394,11 +403,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x8b); /*MOV ebp_store2, RSI*/ addbyte(0xb7); addlong(offsetof(voodoo_state_t, ebp_store)); - addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x41); /*CMOVS EAX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x02); addbyte(0x78); /*JS + - clamp on 0*/ addbyte(2+3+2+ 5+5+2); addbyte(0x3b); /*CMP EAX, EBP*/ @@ -549,7 +557,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); addbyte(0x67); addbyte(0xc0); - + addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); addbyte(0xfe); @@ -557,7 +565,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x66); /*MOV EAX, XMM0*/ addbyte(0x0f); addbyte(0x7e); - addbyte(0xc0); + addbyte(0xc0); } else { @@ -609,11 +617,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v { addbyte(0x85); /*TEST EAX, EAX*/ addbyte(0xc0); - addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x41); /*CMOVS EAX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x02); addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ addbyte(0x84); addbyte(0x8e); @@ -636,11 +643,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v { addbyte(0x85); /*TEST EBX, EBX*/ addbyte(0xdb); - addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x41); /*CMOVS EBX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x1a); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ addbyte(0x9c); addbyte(0x8e); @@ -676,7 +682,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v } static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) -{ +{ int block_pos = 0; int z_skip_pos = 0; int a_skip_pos = 0; @@ -706,12 +712,49 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x57); /*PUSH RDI*/ addbyte(0x56); /*PUSH RSI*/ addbyte(0x53); /*PUSH RBX*/ + addbyte(0x41); /*PUSH R12*/ + addbyte(0x54); + addbyte(0x41); /*PUSH R13*/ + addbyte(0x55); addbyte(0x41); /*PUSH R14*/ addbyte(0x56); addbyte(0x41); /*PUSH R15*/ addbyte(0x57); - -#if WIN64 + + addbyte(0x49); /*MOV R15, xmm_01_w*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&xmm_01_w); + addbyte(0x66); /*MOVDQA XMM8, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (0 << 3)); + addbyte(0x49); /*MOV R15, xmm_ff_w*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&xmm_ff_w); + addbyte(0x66); /*MOVDQA XMM9, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (1 << 3)); + addbyte(0x49); /*MOV R15, xmm_ff_b*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&xmm_ff_b); + addbyte(0x66); /*MOVDQA XMM10, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (2 << 3)); + addbyte(0x49); /*MOV R15, minus_254*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&minus_254); + addbyte(0x66); /*MOVDQA XMM11, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (3 << 3)); + +#if _WIN64 addbyte(0x48); /*MOV RDI, RCX (voodoo_state)*/ addbyte(0x89); addbyte(0xcf); @@ -722,17 +765,56 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x89); addbyte(0xce); #else - addbyte(0x49); /*MOV R9, RCX (real_y)*/ + addbyte(0x49); /*MOV R14, RCX (real_y)*/ addbyte(0x89); - addbyte(0xc9); + addbyte(0xce); addbyte(0x49); /*MOV R15, RSI (voodoo_state)*/ addbyte(0x89); addbyte(0xf7); #endif + + addbyte(0x49); /*MOV R9, logtable*/ + addbyte(0xb8 | (9 & 7)); + addquad((uint64_t)(uintptr_t)&logtable); + addbyte(0x49); /*MOV R10, alookup*/ + addbyte(0xb8 | (10 & 7)); + addquad((uint64_t)(uintptr_t)&alookup); + addbyte(0x49); /*MOV R11, aminuslookup*/ + addbyte(0xb8 | (11 & 7)); + addquad((uint64_t)(uintptr_t)&aminuslookup); + addbyte(0x49); /*MOV R12, xmm_00_ff_w*/ + addbyte(0xb8 | (12 & 7)); + addquad((uint64_t)(uintptr_t)&xmm_00_ff_w); + addbyte(0x49); /*MOV R13, i_00_ff_w*/ + addbyte(0xb8 | (13 & 7)); + addquad((uint64_t)(uintptr_t)&i_00_ff_w); + loop_jump_pos = block_pos; addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); addbyte(0xfe); + if (params->col_tiled || params->aux_tiled) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 63*/ + addbyte(0xe0); + addbyte(63); + addbyte(0xc1); /*SHR EBX, 6*/ + addbyte(0xeb); + addbyte(6); + addbyte(0xc1); /*SHL EBX, 11 - tile is 128*32, << 12, div 2 because word index*/ + addbyte(0xe3); + addbyte(11); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + addbyte(0x89); /*MOV state->x_tiled[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x_tiled)); + } addbyte(0x66); /*PXOR XMM2, XMM2*/ addbyte(0x0f); addbyte(0xef); @@ -803,7 +885,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; if (depth_jump_pos) *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; - + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) { addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ @@ -837,7 +919,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ addbyte(0x86); - addlong(offsetof(voodoo_params_t, zaColor)); + addlong(offsetof(voodoo_params_t, zaColor)); addbyte(0x25); /*AND EAX, 0xffff*/ addlong(0xffff); } @@ -850,7 +932,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ addbyte(0x9f); - addlong(offsetof(voodoo_state_t, x)); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ addbyte(0x8b); addbyte(0x8f); @@ -920,14 +1005,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo /*XMM0 = colour*/ /*XMM2 = 0 (for unpacking*/ - + /*EDI = state, ESI = params*/ if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) { /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); - + addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); @@ -943,7 +1028,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { /*TMU0 in pass-through mode, only sample TMU1*/ block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); - + addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); @@ -1074,27 +1159,26 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) { - addbyte(0x66); /*PXOR XMM0, xmm_00_ff_w[EBX]*/ - addbyte(0x0f); - addbyte(0xef); - addbyte(0x83); - addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); - } - else if (!tc_reverse_blend_1) - { - addbyte(0x66); /*PXOR XMM0, xmm_ff_w*/ + addbyte(0x66); /*PXOR XMM0, R12(xmm_00_ff_w)[EBX]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x1c); } - addbyte(0x66); /*PADDW XMM0, xmm_01_w*/ + else if (!tc_reverse_blend_1) + { + addbyte(0x66); /*PXOR XMM0, XMM9(xmm_ff_w)*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc1); + } + addbyte(0x66); /*PADDW XMM0, XMM8(xmm_01_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xc0); addbyte(0xf3); /*MOVQ XMM1, XMM2*/ addbyte(0x0f); addbyte(0x7e); @@ -1212,10 +1296,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) { - addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ - addbyte(0x04); + addbyte(0x41); /*XOR EAX, R13(i_00_ff_w)[ECX*4]*/ + addbyte(0x33); + addbyte(0x44); addbyte(0x8d); - addlong((uint32_t)(uintptr_t)i_00_ff_w); + addbyte(0); } else if (!tc_reverse_blend_1) { @@ -1251,7 +1336,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd8); addbyte(3); } - + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); addbyte(0x66); /*MOVD XMM0, EAX*/ @@ -1262,7 +1347,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x6e); addbyte(0xf8); - + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) { addbyte(0x8b); /*MOV EAX, state->lod*/ @@ -1398,27 +1483,26 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) { - addbyte(0x66); /*PXOR XMM4, xmm_00_ff_w[EBX]*/ - addbyte(0x0f); - addbyte(0xef); - addbyte(0xa3); - addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); - } - else if (!tc_reverse_blend) - { - addbyte(0x66); /*PXOR XMM4, FF*/ + addbyte(0x66); /*PXOR XMM4, R12(xmm_00_ff_w)[EBX]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x1c); } - addbyte(0x66); /*PADDW XMM4, 1*/ + else if (!tc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM4, XMM9(xmm_ff_w)*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe1); + } + addbyte(0x66); /*PADDW XMM4, XMM8(xmm_01_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xe0); addbyte(0xf3); /*MOVQ XMM5, XMM1*/ addbyte(0x0f); addbyte(0x7e); @@ -1482,13 +1566,13 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (tc_invert_output) { - addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x66); /*PXOR XMM1, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); - addbyte(0x0d); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xc9); } - + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ addbyte(0x0f); addbyte(0x67); @@ -1501,7 +1585,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x67); addbyte(0xc9); - + if (tca_zero_other) { addbyte(0x31); /*XOR EAX, EAX*/ @@ -1580,10 +1664,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) { - addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ - addbyte(0x1c); + addbyte(0x41); /*XOR EBX, R13(i_00_ff_w)[ECX*4]*/ + addbyte(0x33); + addbyte(0x5c); addbyte(0x8d); - addlong((uint32_t)(uintptr_t)i_00_ff_w); + addbyte(0); } else if (!tca_reverse_blend) { @@ -1650,10 +1735,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & FBZ_CHROMAKEY)) { - addbyte(0x66); /*MOVD EAX, XMM0*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0xc0); + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + case CC_LOCALSELECT_COLOR1: + addbyte(0x8b); /*MOV EAX, params->color1[RSI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + break; + case CC_LOCALSELECT_TEX: + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + } addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, chromaKey)); @@ -1734,7 +1853,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x8f); addlong(offsetof(voodoo_state_t, ia)); addbyte(0x31); /*XOR EAX, EAX*/ - addbyte(0xc0); + addbyte(0xc0); addbyte(0xba); /*MOV EDX, 0xff*/ addlong(0xff); addbyte(0xc1);/*SAR ECX, 12*/ @@ -1763,7 +1882,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (a_sel != A_SEL_ITER_A) { addbyte(0x31); /*XOR EAX, EAX*/ - addbyte(0xc0); + addbyte(0xc0); addbyte(0xba); /*MOV EDX, 0xff*/ addlong(0xff); } @@ -1779,7 +1898,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x47); addbyte(0xca); break; - + default: addbyte(0xb9); /*MOV ECX, 0xff*/ addlong(0xff); @@ -1796,7 +1915,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x89); /*MOV EDX, EBX*/ addbyte(0xda); } - + if (cca_sub_clocal) { addbyte(0x29); /*SUB EDX, ECX*/ @@ -2013,7 +2132,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x31); /*XOR EAX, EAX*/ addbyte(0xc0); } - + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) { /*Copy a_other to XMM3 before it gets modified*/ @@ -2027,7 +2146,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xdb); addbyte(0x00); } - + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) { addbyte(0x01); /*ADD EDX, ECX*/ @@ -2122,7 +2241,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xef); addbyte(0xdb); - break; + break; } addbyte(0xf3); /*MOV XMM4, XMM0*/ addbyte(0x0f); @@ -2130,19 +2249,17 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xe0); if (!cc_reverse_blend) { - addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x66); /*PXOR XMM3, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xd9); } - addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x66); /*PADDW XMM3, XMM8(xmm_01_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xd8); addbyte(0x66); /*PMULLW XMM0, XMM3*/ addbyte(0x0f); addbyte(0xd5); @@ -2165,7 +2282,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x6b); addbyte(0xc0); } - + if (cc_add == 1) { addbyte(0x66); /*PADDW XMM0, XMM1*/ @@ -2181,18 +2298,17 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (cc_invert_output) { - addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x66); /*PXOR XMM0, XMM10(xmm_ff_b)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_b); + addbyte(0xc2); } if (params->fogMode & FOG_ENABLE) { - if (params->fogMode & FOG_CONSTANT) - { + if (params->fogMode & FOG_CONSTANT) + { addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ addbyte(0x0f); addbyte(0x6e); @@ -2202,15 +2318,15 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xdc); addbyte(0xc3); - } - else - { + } + else + { addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ addbyte(0x0f); addbyte(0x60); addbyte(0xc2); - if (!(params->fogMode & FOG_ADD)) + if (!(params->fogMode & FOG_ADD)) { addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ addbyte(0x0f); @@ -2221,7 +2337,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x60); addbyte(0xda); - } + } else { addbyte(0x66); /*PXOR XMM3, XMM3*/ @@ -2229,7 +2345,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xef); addbyte(0xdb); } - + if (!(params->fogMode & FOG_MULT)) { addbyte(0x66); /*PSUBW XMM3, XMM0*/ @@ -2283,7 +2399,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo fog_a = params->fogTable[fog_idx].fog; fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ break; - + case FOG_Z: addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ addbyte(0x87); @@ -2295,7 +2411,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addlong(0xff); // fog_a = (z >> 20) & 0xff; break; - + case FOG_ALPHA: addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ addbyte(0x87); @@ -2317,7 +2433,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc3); // fog_a = CLAMP(ia >> 12); break; - + case FOG_W: addbyte(0x8b); /*MOV EAX, state->w[EDI]+4*/ addbyte(0x87); @@ -2343,11 +2459,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc0); addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); - addbyte(0x1c); - addbyte(0xc5); - addlong(((uintptr_t)alookup) + 16); + addbyte(0x5c); + addbyte(0xc2); + addbyte(16); addbyte(0x66); /*PSRAW XMM3, 7*/ addbyte(0x0f); addbyte(0x71); @@ -2428,7 +2545,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0xC3); /*RET*/ } - + if (params->alphaMode & (1 << 4)) { addbyte(0x49); /*MOV R8, rgb565*/ @@ -2436,7 +2553,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addquad((uintptr_t)rgb565); addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x48); /*MOV RBP, fb_mem*/ addbyte(0x8b); addbyte(0xaf); @@ -2466,7 +2586,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0xf4); - + switch (dest_afunc) { case AFUNC_AZERO: @@ -2476,22 +2596,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xe4); break; case AFUNC_ASRC_ALPHA: - addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM4, R10(alookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x24); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xd2); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xec); - addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2516,12 +2636,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0xec); - addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2542,22 +2662,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo case AFUNC_AONE: break; case AFUNC_AOMSRC_ALPHA: - addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM4, R11(aminuslookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x24); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xd3); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xec); - addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2574,12 +2694,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(8); break; case AFUNC_AOM_COLOR: - addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0xf3); /*MOVQ XMM5, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0x7e); - addbyte(0x2c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xe9); addbyte(0x66); /*PSUBW XMM5, XMM0*/ addbyte(0x0f); addbyte(0xf9); @@ -2593,11 +2712,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x7e); addbyte(0xec); addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2620,22 +2739,21 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xe4); break; case AFUNC_ASATURATE: - addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x66); /*PMULLW XMM4, XMM11(minus_254)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); - addbyte(0x24); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)&minus_254); + addbyte(0xe3); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xec); addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2661,22 +2779,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc0); break; case AFUNC_ASRC_ALPHA: - addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM0, R10(alookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x04); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xd2); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); - addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM0, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2701,12 +2819,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); - addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM0, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2727,22 +2845,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo case AFUNC_AONE: break; case AFUNC_AOMSRC_ALPHA: - addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM0, R11(aminuslookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x04); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xd3); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2759,12 +2877,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(8); break; case AFUNC_AOM_COLOR: - addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0xf3); /*MOVQ XMM5, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0x7e); - addbyte(0x2c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xe9); addbyte(0x66); /*PSUBW XMM5, XMM6*/ addbyte(0x0f); addbyte(0xf9); @@ -2778,11 +2895,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x7e); addbyte(0xe8); addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2807,7 +2924,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo case AFUNC_ACOLORBEFOREFOG: break; } - + addbyte(0x66); /*PADDW XMM0, XMM4*/ addbyte(0x0f); addbyte(0xfd); @@ -2821,13 +2938,16 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); - + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x66); /*MOV EAX, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xc0); - + if (params->fbzMode & FBZ_RGB_WMASK) { if (dither) @@ -2888,7 +3008,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); + if (voodoo->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x4c); /*ADD RSI, R8*/ addbyte(0x01); addbyte(0xc6); @@ -2974,6 +3097,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x66); /*MOV AX, new_depth*/ addbyte(0x8b); addbyte(0x87); @@ -3018,7 +3147,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x6f); addbyte(0x86); - addlong(offsetof(voodoo_params_t, dBdX)); + addlong(offsetof(voodoo_params_t, dBdX)); addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ addbyte(0x86); addlong(offsetof(voodoo_params_t, dZdX)); @@ -3080,7 +3209,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc7); addbyte(0x01); /*ADD state->z[EDI], EAX*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, z)); + addlong(offsetof(voodoo_state_t, z)); } else { @@ -3098,7 +3227,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc7); addbyte(0x29); /*SUB state->z[EDI], EAX*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, z)); + addlong(offsetof(voodoo_state_t, z)); } if (voodoo->dual_tmus) @@ -3166,7 +3295,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfb); addbyte(0xe6); } - + addbyte(0xf3); /*MOVDQU state->tmu1_s, XMM3*/ addbyte(0x0f); addbyte(0x7f); @@ -3178,7 +3307,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xa7); addlong(offsetof(voodoo_state_t, tmu1_w)); } - + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, pixel_count)); @@ -3200,13 +3329,13 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x87); addlong(offsetof(voodoo_state_t, texel_count)); addbyte(2); - } + } } addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, x)); - + if (state->xdir > 0) { addbyte(0x83); /*ADD state->x[EDI], 1*/ @@ -3230,28 +3359,32 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addlong(loop_jump_pos - (block_pos + 4)); addbyte(0x41); /*POP R15*/ - addbyte(0x5f); + addbyte(0x5f); addbyte(0x41); /*POP R14*/ addbyte(0x5e); - addbyte(0x5b); /*POP RBX*/ + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5b); /*POP RBX*/ addbyte(0x5e); /*POP RSI*/ addbyte(0x5f); /*POP RDI*/ addbyte(0x5d); /*POP RBP*/ - + addbyte(0xC3); /*RET*/ } -static int voodoo_recomp = 0; +int voodoo_recomp = 0; static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) { int c; int b = last_block[odd_even]; voodoo_x86_data_t *voodoo_x86_data = voodoo->codegen_data; voodoo_x86_data_t *data; - + for (c = 0; c < 8; c++) { - data = &voodoo_x86_data[odd_even + c*2]; //&voodoo_x86_data[odd_even][b]; - + data = &voodoo_x86_data[odd_even + c*4]; //&voodoo_x86_data[odd_even][b]; + if (state->xdir == data->xdir && params->alphaMode == data->alphaMode && params->fbzMode == data->fbzMode && @@ -3261,18 +3394,19 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, params->textureMode[0] == data->textureMode[0] && params->textureMode[1] == data->textureMode[1] && (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && - (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + (params->tLOD[1] & LOD_MASK) == data->tLOD[1] && + ((params->col_tiled || params->aux_tiled) ? 1 : 0) == data->is_tiled) { last_block[odd_even] = b; return data->code_block; } - + b = (b + 1) & 7; } voodoo_recomp++; - data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*2]; + data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*4]; // code_block = data->code_block; - + voodoo_generate(data->code_block, voodoo, params, state, depth_op); data->xdir = state->xdir; @@ -3285,44 +3419,25 @@ voodoo_recomp++; data->textureMode[1] = params->textureMode[1]; data->tLOD[0] = params->tLOD[0] & LOD_MASK; data->tLOD[1] = params->tLOD[1] & LOD_MASK; + data->is_tiled = (params->col_tiled || params->aux_tiled) ? 1 : 0; next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; - + return data->code_block; } -static void voodoo_codegen_init(voodoo_t *voodoo) +void voodoo_codegen_init(voodoo_t *voodoo) { int c; -#ifdef __linux__ - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif -#if WIN64 - voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else - voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2); -#endif - -#ifdef __linux__ - start = (void *)((long)voodoo->codegen_data & pagemask); - len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2) + pagesize) & pagemask; - if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - { - perror("mprotect"); - exit(-1); - } -#endif + voodoo->codegen_data = plat_mmap(sizeof(voodoo_x86_data_t) * BLOCK_NUM*4, 1); for (c = 0; c < 256; c++) { int d[4]; int _ds = c & 0xf; int dt = c >> 4; - + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); @@ -3339,12 +3454,9 @@ static void voodoo_codegen_init(voodoo_t *voodoo) xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); } -static void voodoo_codegen_close(voodoo_t *voodoo) +void voodoo_codegen_close(voodoo_t *voodoo) { -#if WIN64 - VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); -#else - free(voodoo->codegen_data); -#endif + plat_munmap(voodoo->codegen_data, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4); } +#endif /*VIDEO_VOODOO_CODEGEN_X86_64_H*/ diff --git a/src/include/86box/vid_voodoo_codegen_x86.h b/src/include/86box/vid_voodoo_codegen_x86.h index 6cf2562d0..6bde2c0c6 100644 --- a/src/include/86box/vid_voodoo_codegen_x86.h +++ b/src/include/86box/vid_voodoo_codegen_x86.h @@ -1,20 +1,18 @@ /*Registers : - + alphaMode fbzMode & 0x1f3fff fbzColorPath */ -#ifdef __linux__ -# include -# include -#endif -#if defined WIN32 || defined _WIN32 || defined _WIN32 -# include -#endif +#ifndef VIDEO_VOODOO_CODEGEN_X86_H +# define VIDEO_VOODOO_CODEGEN_X86_H +#ifdef _MSC_VER #include +#else #include +#endif #define BLOCK_NUM 8 #define BLOCK_MASK (BLOCK_NUM-1) @@ -22,6 +20,11 @@ #define LOD_MASK (LOD_TMIRROR_S | LOD_TMIRROR_T) +/* Suppress a false positive warning on gcc that causes excessive build log spam */ +#if __GNUC__ >= 10 +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + typedef struct voodoo_x86_data_t { uint8_t code_block[BLOCK_SIZE]; @@ -32,34 +35,43 @@ typedef struct voodoo_x86_data_t uint32_t fbzColorPath; uint32_t textureMode[2]; uint32_t tLOD[2]; - uint32_t trexInit1; + uint32_t trexInit1; + int is_tiled; } voodoo_x86_data_t; -static int last_block[2] = {0, 0}; -static int next_block_to_write[2] = {0, 0}; +static int last_block[4] = {0, 0}; +static int next_block_to_write[4] = {0, 0}; -#define addbyte(val) \ - code_block[block_pos++] = val; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addbyte(val) \ + do { \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addword(val) \ - *(uint16_t *)&code_block[block_pos] = val; \ - block_pos += 2; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addword(val) \ + do { \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addlong(val) \ - *(uint32_t *)&code_block[block_pos] = val; \ - block_pos += 4; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addlong(val) \ + do { \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addquad(val) \ - *(uint64_t *)&code_block[block_pos] = val; \ - block_pos += 8; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addquad(val) \ + do { \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) static __m128i xmm_01_w;// = 0x0001000100010001ull; @@ -195,7 +207,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0xd8); addbyte(0xc1); /*SHR EAX, 8*/ addbyte(0xe8); - addbyte(8); + addbyte(8); addbyte(0x66); /*MOVQ state->tex_s, XMM4*/ addbyte(0x0f); addbyte(0xd6); @@ -411,7 +423,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x7e); addbyte(0x0c); addbyte(0x82); - + if (state->clamp_s[tmu]) { addbyte(0xeb); /*JMP +*/ @@ -485,7 +497,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); addbyte(0x60); addbyte(0xca); - + addbyte(0x81); /*ADD ESI, bilinear_lookup*/ addbyte(0xc6); addlong((uint32_t)bilinear_lookup); @@ -525,7 +537,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x0f); addbyte(0x67); addbyte(0xc0); - + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ addbyte(0x74); addbyte(0x24); @@ -534,7 +546,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x66); /*MOV EAX, XMM0*/ addbyte(0x0f); addbyte(0x7e); - addbyte(0xc0); + addbyte(0xc0); } else { @@ -653,7 +665,7 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v } static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) -{ +{ int block_pos = 0; int z_skip_pos = 0; int a_skip_pos = 0; @@ -683,7 +695,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x57); /*PUSH EDI*/ addbyte(0x56); /*PUSH ESI*/ addbyte(0x53); /*PUSH EBX*/ - + addbyte(0x8b); /*MOV EDI, [ESP+4]*/ addbyte(0x7c); addbyte(0x24); @@ -693,6 +705,28 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x74); addbyte(0x24); addbyte(8+16); + if (params->col_tiled || params->aux_tiled) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 63*/ + addbyte(0xe0); + addbyte(63); + addbyte(0xc1); /*SHR EBX, 6*/ + addbyte(0xeb); + addbyte(6); + addbyte(0xc1); /*SHL EBX, 11 - tile is 128*32, << 12, div 2 because word index*/ + addbyte(0xe3); + addbyte(11); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + addbyte(0x89); /*MOV state->x_tiled[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x_tiled)); + } addbyte(0x66); /*PXOR XMM2, XMM2*/ addbyte(0x0f); addbyte(0xef); @@ -762,7 +796,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; if (depth_jump_pos) *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; - + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) { addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ @@ -791,13 +825,13 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x47); addbyte(0xc3); } - + if (params->fbzMode & FBZ_DEPTH_BIAS) { addbyte(0x0f); /*MOVSX EDX, params->zaColor[ESI]*/ addbyte(0xbf); addbyte(0x96); - addlong(offsetof(voodoo_params_t, zaColor)); + addlong(offsetof(voodoo_params_t, zaColor)); if (params->fbzMode & FBZ_W_BUFFER) { addbyte(0xbb); /*MOV EBX, 0xffff*/ @@ -825,7 +859,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ addbyte(0x9f); - addlong(offsetof(voodoo_state_t, x)); + if (voodoo->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x8b);/*MOV ECX, aux_mem[EDI]*/ addbyte(0x8f); addlong(offsetof(voodoo_state_t, aux_mem)); @@ -903,14 +940,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo // voodoo_combine = &code_block[block_pos]; /*XMM0 = colour*/ /*XMM2 = 0 (for unpacking*/ - + /*EDI = state, ESI = params*/ if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) { /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); - + addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); @@ -926,7 +963,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { /*TMU0 in pass-through mode, only sample TMU1*/ block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); - + addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); @@ -1236,7 +1273,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd8); addbyte(3); } - + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); addbyte(0x66); /*MOVD XMM0, EAX*/ @@ -1247,7 +1284,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x6e); addbyte(0xf8); - + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) { addbyte(0x8b); /*MOV EAX, state->lod*/ @@ -1443,7 +1480,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xeb); addbyte(24); } - + if (tc_add_clocal) { addbyte(0x66); /*PADDW XMM1, XMM0*/ @@ -1463,7 +1500,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0xcc); } - + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ addbyte(0x0f); addbyte(0x67); @@ -1484,7 +1521,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0d); addlong((uint32_t)&xmm_ff_b); } - + if (tca_zero_other) { addbyte(0x31); /*XOR EAX, EAX*/ @@ -1633,10 +1670,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & FBZ_CHROMAKEY)) { - addbyte(0x66); /*MOVD EAX, XMM0*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0xc0); + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + case CC_LOCALSELECT_COLOR1: + addbyte(0x8b); /*MOV EAX, params->color1[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + break; + case CC_LOCALSELECT_TEX: + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + } addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, chromaKey)); @@ -1717,7 +1788,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x8f); addlong(offsetof(voodoo_state_t, ia)); addbyte(0x31); /*XOR EAX, EAX*/ - addbyte(0xc0); + addbyte(0xc0); addbyte(0xba); /*MOV EDX, 0xff*/ addlong(0xff); addbyte(0xc1);/*SAR ECX, 12*/ @@ -1746,7 +1817,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (a_sel != A_SEL_ITER_A) { addbyte(0x31); /*XOR EAX, EAX*/ - addbyte(0xc0); + addbyte(0xc0); addbyte(0xba); /*MOV EDX, 0xff*/ addlong(0xff); } @@ -1762,7 +1833,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x47); addbyte(0xca); break; - + default: addbyte(0xb9); /*MOV ECX, 0xff*/ addlong(0xff); @@ -1779,7 +1850,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x89); /*MOV EDX, EBX*/ addbyte(0xda); } - + if (cca_sub_clocal) { addbyte(0x29); /*SUB EDX, ECX*/ @@ -1995,7 +2066,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x31); /*XOR EAX, EAX*/ addbyte(0xc0); } - + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) { /*Copy a_other to XMM3 before it gets modified*/ @@ -2009,13 +2080,13 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xdb); addbyte(0x00); } - + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) { addbyte(0x01); /*ADD EDX, ECX*/ addbyte(0xca); } - + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) { addbyte(0x85); /*TEST EDX, EDX*/ @@ -2146,7 +2217,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x6b); addbyte(0xc0); } - + if (cc_add == 1) { addbyte(0x66); /*PADDW XMM0, XMM1*/ @@ -2176,8 +2247,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo // addlong(offsetof(voodoo_state_t, out)); if (params->fogMode & FOG_ENABLE) { - if (params->fogMode & FOG_CONSTANT) - { + if (params->fogMode & FOG_CONSTANT) + { addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ addbyte(0x0f); addbyte(0x6e); @@ -2187,20 +2258,20 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0xdc); addbyte(0xc3); -/* src_r += params->fogColor.r; - src_g += params->fogColor.g; +/* src_r += params->fogColor.r; + src_g += params->fogColor.g; src_b += params->fogColor.b; */ - } - else - { + } + else + { /*int fog_r, fog_g, fog_b, fog_a; */ - + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ addbyte(0x0f); addbyte(0x60); addbyte(0xc2); - if (!(params->fogMode & FOG_ADD)) + if (!(params->fogMode & FOG_ADD)) { addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ addbyte(0x0f); @@ -2211,7 +2282,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x60); addbyte(0xda); - } + } else { addbyte(0x66); /*PXOR XMM3, XMM3*/ @@ -2219,7 +2290,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xef); addbyte(0xdb); } - + if (!(params->fogMode & FOG_MULT)) { addbyte(0x66); /*PSUBW XMM3, XMM0*/ @@ -2274,7 +2345,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo fog_a = params->fogTable[fog_idx].fog; fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ break; - + case FOG_Z: addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ addbyte(0x87); @@ -2286,7 +2357,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addlong(0xff); // fog_a = (z >> 20) & 0xff; break; - + case FOG_ALPHA: addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ addbyte(0x87); @@ -2308,7 +2379,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc3); // fog_a = CLAMP(ia >> 12); break; - + case FOG_W: addbyte(0x8b); /*MOV EAX, state->w[EDI]+4*/ addbyte(0x87); @@ -2430,12 +2501,15 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0xC3); /*RET*/ } - + if (params->alphaMode & (1 << 4)) { addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x8b); /*MOV EBP, fb_mem*/ addbyte(0xaf); addlong(offsetof(voodoo_state_t, fb_mem)); @@ -2464,7 +2538,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0xf4); - + switch (dest_afunc) { case AFUNC_AZERO: @@ -2793,7 +2867,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo case AFUNC_ACOLORBEFOREFOG: break; } - + addbyte(0x66); /*PADDW XMM0, XMM4*/ addbyte(0x0f); addbyte(0xfd); @@ -2804,7 +2878,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x67); addbyte(0xc0); } -//#endif +//#endif // addbyte(0x8b); /*MOV EDX, x (ESP+12)*/ // addbyte(0x54); @@ -2814,19 +2888,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); - + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x66); /*MOV EAX, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xc0); - + if (params->fbzMode & FBZ_RGB_WMASK) { // addbyte(0x89); /*MOV state->rgb_out[EDI], EAX*/ // addbyte(0x87); // addlong(offsetof(voodoo_state_t, rgb_out)); - + if (dither) { addbyte(0x8b); /*MOV ESI, real_y (ESP+16)*/ @@ -2883,7 +2960,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); if (dither2x2) { addbyte(0xc1); /*SHL ECX, 2*/ @@ -2967,6 +3047,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x66); /*MOV AX, new_depth*/ addbyte(0x8b); addbyte(0x87); @@ -3068,7 +3154,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x6f); addbyte(0x86); - addlong(offsetof(voodoo_params_t, dBdX)); + addlong(offsetof(voodoo_params_t, dBdX)); addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ addbyte(0x86); addlong(offsetof(voodoo_params_t, dZdX)); @@ -3130,7 +3216,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc7); addbyte(0x01); /*ADD state->z[EDI], EAX*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, z)); + addlong(offsetof(voodoo_state_t, z)); } else { @@ -3148,7 +3234,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc7); addbyte(0x29); /*SUB state->z[EDI], EAX*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, z)); + addlong(offsetof(voodoo_state_t, z)); } addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ @@ -3166,7 +3252,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xd6); addbyte(0x87); addlong(offsetof(voodoo_state_t, w)); - + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, pixel_count)); @@ -3188,12 +3274,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x87); addlong(offsetof(voodoo_state_t, texel_count)); addbyte(2); - } + } } addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); addlong(offsetof(voodoo_state_t, x)); - + if (state->xdir > 0) { addbyte(0x83); /*ADD state->x[EDI], 1*/ @@ -3215,18 +3301,18 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); /*JNZ loop_jump_pos*/ addbyte(0x85); addlong(loop_jump_pos - (block_pos + 4)); - - addbyte(0x5b); /*POP EBX*/ + + addbyte(0x5b); /*POP EBX*/ addbyte(0x5e); /*POP ESI*/ addbyte(0x5f); /*POP EDI*/ addbyte(0x5d); /*POP EBP*/ - + addbyte(0xC3); /*RET*/ - + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) cs = cs; } -static int voodoo_recomp = 0; +int voodoo_recomp = 0; static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) { @@ -3234,11 +3320,11 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, int b = last_block[odd_even]; voodoo_x86_data_t *data; voodoo_x86_data_t *codegen_data = voodoo->codegen_data; - + for (c = 0; c < 8; c++) { - data = &codegen_data[odd_even + b*2]; - + data = &codegen_data[odd_even + b*4]; + if (state->xdir == data->xdir && params->alphaMode == data->alphaMode && params->fbzMode == data->fbzMode && @@ -3248,18 +3334,19 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, params->textureMode[0] == data->textureMode[0] && params->textureMode[1] == data->textureMode[1] && (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && - (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + (params->tLOD[1] & LOD_MASK) == data->tLOD[1] && + ((params->col_tiled || params->aux_tiled) ? 1 : 0) == data->is_tiled) { last_block[odd_even] = b; return data->code_block; } - + b = (b + 1) & 7; } voodoo_recomp++; - data = &codegen_data[odd_even + next_block_to_write[odd_even]*2]; + data = &codegen_data[odd_even + next_block_to_write[odd_even]*4]; // code_block = data->code_block; - + voodoo_generate(data->code_block, voodoo, params, state, depth_op); data->xdir = state->xdir; @@ -3272,44 +3359,25 @@ voodoo_recomp++; data->textureMode[1] = params->textureMode[1]; data->tLOD[0] = params->tLOD[0] & LOD_MASK; data->tLOD[1] = params->tLOD[1] & LOD_MASK; + data->is_tiled = (params->col_tiled || params->aux_tiled) ? 1 : 0; next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; - + return data->code_block; } -static void voodoo_codegen_init(voodoo_t *voodoo) +void voodoo_codegen_init(voodoo_t *voodoo) { int c; -#ifdef __linux__ - void *start; - size_t len; - long pagesize = sysconf(_SC_PAGESIZE); - long pagemask = ~(pagesize - 1); -#endif -#if defined WIN32 || defined _WIN32 || defined _WIN32 - voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM*2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else - voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM*2); -#endif - -#ifdef __linux__ - start = (void *)((long)voodoo->codegen_data & pagemask); - len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM*2) + pagesize) & pagemask; - if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - { - perror("mprotect"); - exit(-1); - } -#endif + voodoo->codegen_data = plat_mmap(sizeof(voodoo_x86_data_t) * BLOCK_NUM*4, 1); for (c = 0; c < 256; c++) { int d[4]; int _ds = c & 0xf; int dt = c >> 4; - + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); @@ -3326,11 +3394,9 @@ static void voodoo_codegen_init(voodoo_t *voodoo) xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); } -static void voodoo_codegen_close(voodoo_t *voodoo) +void voodoo_codegen_close(voodoo_t *voodoo) { -#if defined WIN32 || defined _WIN32 || defined _WIN32 - VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); -#else - free(voodoo->codegen_data); -#endif + plat_munmap(voodoo->codegen_data, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4); } + +#endif /*VIDEO_VOODOO_CODEGEN_X86_H*/ diff --git a/src/include/86box/vid_voodoo_common.h b/src/include/86box/vid_voodoo_common.h new file mode 100644 index 000000000..6af42e9ec --- /dev/null +++ b/src/include/86box/vid_voodoo_common.h @@ -0,0 +1,535 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_COMMON_H +# define VIDEO_VOODOO_COMMON_H + +#ifdef CLAMP +#undef CLAMP +#endif + +#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) +#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) + + +#define LOD_MAX 8 + +#define TEX_DIRTY_SHIFT 10 + +#define TEX_CACHE_MAX 64 + +enum +{ + VOODOO_1 = 0, + VOODOO_SB50, + VOODOO_2, + VOODOO_BANSHEE, + VOODOO_3 +}; + +typedef union int_float +{ + uint32_t i; + float f; +} int_float; + +typedef struct rgbvoodoo_t +{ + uint8_t b, g, r; + uint8_t pad; +} rgbvoodoo_t; +typedef struct rgba8_t +{ + uint8_t b, g, r, a; +} rgba8_t; + +typedef union rgba_u +{ + struct + { + uint8_t b, g, r, a; + } rgba; + uint32_t u; +} rgba_u; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx) +#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE-4) +#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITEL_REG = (0x01 << 24), + FIFO_WRITEW_FB = (0x02 << 24), + FIFO_WRITEL_FB = (0x03 << 24), + FIFO_WRITEL_TEX = (0x04 << 24), + FIFO_WRITEL_2DREG = (0x05 << 24) +}; + +#define PARAM_SIZE 1024 +#define PARAM_MASK (PARAM_SIZE - 1) +#define PARAM_ENTRY_SIZE (1 << 31) + +#define PARAM_ENTRIES(x) (voodoo->params_write_idx - voodoo->params_read_idx[x]) +#define PARAM_FULL(x) ((voodoo->params_write_idx - voodoo->params_read_idx[x]) >= PARAM_SIZE) +#define PARAM_EMPTY(x) (voodoo->params_read_idx[x] == voodoo->params_write_idx) + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct voodoo_params_t +{ + int command; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t startR, startG, startB, startZ, startA; + + int32_t dBdX, dGdX, dRdX, dAdX, dZdX; + + int32_t dBdY, dGdY, dRdY, dAdY, dZdY; + + int64_t startW, dWdX, dWdY; + + struct + { + int64_t startS, startT, startW, p1; + int64_t dSdX, dTdX, dWdX, p2; + int64_t dSdY, dTdY, dWdY, p3; + } tmu[2]; + + uint32_t color0, color1; + + uint32_t fbzMode; + uint32_t fbzColorPath; + + uint32_t fogMode; + rgbvoodoo_t fogColor; + struct + { + uint8_t fog, dfog; + } fogTable[64]; + + uint32_t alphaMode; + + uint32_t zaColor; + + int chromaKey_r, chromaKey_g, chromaKey_b; + uint32_t chromaKey; + + uint32_t textureMode[2]; + uint32_t tLOD[2]; + + uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; + + uint32_t tex_base[2][LOD_MAX+2]; + uint32_t tex_end[2][LOD_MAX+2]; + int tex_width[2]; + int tex_w_mask[2][LOD_MAX+2]; + int tex_w_nmask[2][LOD_MAX+2]; + int tex_h_mask[2][LOD_MAX+2]; + int tex_shift[2][LOD_MAX+2]; + int tex_lod[2][LOD_MAX+2]; + int tex_entry[2]; + int detail_max[2], detail_bias[2], detail_scale[2]; + + uint32_t draw_offset, aux_offset; + + int tformat[2]; + + int clipLeft, clipRight, clipLowY, clipHighY; + int clipLeft1, clipRight1, clipLowY1, clipHighY1; + + int sign; + + uint32_t front_offset; + + uint32_t swapbufferCMD; + + uint32_t stipple; + + int col_tiled, aux_tiled; + int row_width, aux_row_width; +} voodoo_params_t; + +typedef struct texture_t +{ + uint32_t base; + uint32_t tLOD; + volatile int refcount, refcount_r[4]; + int is16; + uint32_t palette_checksum; + uint32_t addr_start[4], addr_end[4]; + uint32_t *data; +} texture_t; + +typedef struct vert_t +{ + float sVx, sVy; + float sRed, sGreen, sBlue, sAlpha; + float sVz, sWb; + float sW0, sS0, sT0; + float sW1, sS1, sT1; +} vert_t; + +typedef struct clip_t +{ + int x_min, x_max; + int y_min, y_max; +} clip_t; + +typedef struct voodoo_t +{ + mem_mapping_t mapping; + + int pci_enable; + + uint8_t dac_data[8]; + int dac_reg, dac_reg_ff; + uint8_t dac_readdata; + uint16_t dac_pll_regs[16]; + + float pixel_clock; + uint64_t line_time; + + voodoo_params_t params; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/ + + uint32_t initEnable; + + uint32_t lfbMode; + + uint32_t memBaseAddr; + + int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy; + + uint32_t front_offset, back_offset; + + uint32_t fb_read_offset, fb_write_offset; + + int row_width, aux_row_width; + int block_width; + + int col_tiled, aux_tiled; + + uint8_t *fb_mem, *tex_mem[2]; + uint16_t *tex_mem_w[2]; + + int rgb_sel; + + uint32_t trexInit1[2]; + + uint32_t tmuConfig; + + mutex_t *swap_mutex; + int swap_count; + + int disp_buffer, draw_buffer; + pc_timer_t timer; + + int line; + svga_t *svga; + + uint32_t backPorch; + uint32_t videoDimensions; + uint32_t hSync, vSync; + + int h_total, v_total, v_disp; + int h_disp; + int v_retrace; + + struct + { + uint32_t y[4], i[4], q[4]; + } nccTable[2][2]; + + rgba_u palette[2][256]; + + rgba_u ncc_lookup[2][2][256]; + int ncc_dirty[2]; + + thread_t *fifo_thread; + thread_t *render_thread[4]; + event_t *wake_fifo_thread; + event_t *wake_main_thread; + event_t *fifo_not_full_event; + event_t *render_not_full_event[4]; + event_t *wake_render_thread[4]; + + int voodoo_busy; + int render_voodoo_busy[4]; + + int render_threads; + int odd_even_mask; + + int pixel_count[4], texel_count[4], tri_count, frame_count; + int pixel_count_old[4], texel_count_old[4]; + int wr_count, rd_count, tex_count; + + int retrace_count; + int swap_interval; + uint32_t swap_offset; + int swap_pending; + + int bilinear_enabled; + int dithersub_enabled; + + int fb_size; + uint32_t fb_mask; + + int texture_size; + uint32_t texture_mask; + + int dual_tmus; + int type; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + volatile int cmd_read, cmd_written, cmd_written_fifo; + + voodoo_params_t params_buffer[PARAM_SIZE]; + volatile int params_read_idx[4], params_write_idx; + + uint32_t cmdfifo_base, cmdfifo_end, cmdfifo_size; + int cmdfifo_rp, cmdfifo_ret_addr; + int cmdfifo_in_sub; + volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; + volatile int cmdfifo_enabled; + uint32_t cmdfifo_amin, cmdfifo_amax; + int cmdfifo_holecount; + + uint32_t sSetupMode; + vert_t verts[4]; + unsigned int vertex_ages[3]; + unsigned int vertex_next_age; + int num_verticies; + int cull_pingpong; + + int flush; + + int scrfilter; + int scrfilterEnabled; + int scrfilterThreshold; + int scrfilterThresholdOld; + + uint32_t last_write_addr; + + uint32_t fbiPixelsIn; + uint32_t fbiChromaFail; + uint32_t fbiZFuncFail; + uint32_t fbiAFuncFail; + uint32_t fbiPixelsOut; + + uint32_t bltSrcBaseAddr; + uint32_t bltDstBaseAddr; + int bltSrcXYStride, bltDstXYStride; + uint32_t bltSrcChromaRange, bltDstChromaRange; + int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB; + int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB; + int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB; + int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB; + + int bltClipRight, bltClipLeft; + int bltClipHighY, bltClipLowY; + + int bltSrcX, bltSrcY; + int bltDstX, bltDstY; + int bltSizeX, bltSizeY; + int bltRop[4]; + uint16_t bltColorFg, bltColorBg; + + uint32_t bltCommand; + + uint32_t leftOverlayBuf; + + struct + { + int dst_x, dst_y; + int cur_x; + int size_x, size_y; + int x_dir, y_dir; + int dst_stride; + } blt; + + struct + { + uint32_t bresError0, bresError1; + uint32_t clip0Min, clip0Max; + uint32_t clip1Min, clip1Max; + uint32_t colorBack, colorFore; + uint32_t command, commandExtra; + uint32_t dstBaseAddr; + uint32_t dstFormat; + uint32_t dstSize; + uint32_t dstXY; + uint32_t lineStipple; + uint32_t lineStyle; + uint32_t rop; + uint32_t srcBaseAddr; + uint32_t srcFormat; + uint32_t srcSize; + uint32_t srcXY; + + uint32_t colorPattern[64]; + + int bres_error_0, bres_error_1; + uint32_t colorPattern8[64], colorPattern16[64], colorPattern24[64]; + int cur_x, cur_y; + uint32_t dstBaseAddr_tiled; + uint32_t dstColorkeyMin, dstColorkeyMax; + int dstSizeX, dstSizeY; + int dstX, dstY; + int dst_stride; + int patoff_x, patoff_y; + uint8_t rops[4]; + uint32_t srcBaseAddr_tiled; + uint32_t srcColorkeyMin, srcColorkeyMax; + int srcSizeX, srcSizeY; + int srcX, srcY; + int src_stride; + int old_srcX; + + /*Used for handling packed 24bpp host data*/ + int host_data_remainder; + uint32_t old_host_data; + + /*Polyfill coordinates*/ + int lx[2], rx[2]; + int ly[2], ry[2]; + + /*Polyfill state*/ + int error[2]; + int dx[2], dy[2]; + int x_inc[2]; /*y_inc is always 1 for polyfill*/ + int lx_cur, rx_cur; + + clip_t clip[2]; + + uint8_t host_data[16384]; + int host_data_count; + int host_data_size_src, host_data_size_dest; + int src_stride_src, src_stride_dest; + + int src_bpp; + + int line_pix_pos, line_bit_pos; + int line_rep_cnt, line_bit_mask_size; + } banshee_blt; + + struct + { + uint32_t vidOverlayStartCoords; + uint32_t vidOverlayEndScreenCoords; + uint32_t vidOverlayDudx, vidOverlayDudxOffsetSrcWidth; + uint32_t vidOverlayDvdy, vidOverlayDvdyOffset; + //uint32_t vidDesktopOverlayStride; + + int start_x, start_y; + int end_x, end_y; + int size_x, size_y; + int overlay_bytes; + + unsigned int src_y; + } overlay; + + rgbvoodoo_t clutData[33]; + int clutData_dirty; + rgbvoodoo_t clutData256[256]; + uint32_t video_16to32[0x10000]; + + uint8_t dirty_line[2048]; + int dirty_line_low, dirty_line_high; + + int fb_write_buffer, fb_draw_buffer; + int buffer_cutoff; + + uint32_t tile_base, tile_stride; + int tile_stride_shift, tile_x, tile_x_real; + + int y_origin_swap; + + int read_time, write_time, burst_time; + + pc_timer_t wake_timer; + + /* screen filter tables */ + uint8_t thefilter[256][256]; + uint8_t thefilterg[256][256]; + uint8_t thefilterb[256][256]; + uint16_t purpleline[256][3]; + + texture_t texture_cache[2][TEX_CACHE_MAX]; + uint8_t texture_present[2][16384]; + int texture_last_removed; + + uint32_t palette_checksum[2]; + int palette_dirty[2]; + + uint64_t time; + int render_time[4]; + + int force_blit_count; + int can_blit; + mutex_t* force_blit_mutex; + + int use_recompiler; + void *codegen_data; + + struct voodoo_set_t *set; + + uint8_t fifo_thread_run, render_thread_run[4]; + + uint8_t *vram, *changedvram; + + void *p; +} voodoo_t; + +typedef struct voodoo_set_t +{ + voodoo_t *voodoos[2]; + + mem_mapping_t snoop_mapping; + + int nr_cards; +} voodoo_set_t; + + +extern rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; + + +void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg); + +void voodoo_recalc(voodoo_t *voodoo); +void voodoo_update_ncc(voodoo_t *voodoo, int tmu); + +void *voodoo_2d3d_card_init(int type); +void voodoo_card_close(voodoo_t *voodoo); + +#endif /*VIDEO_VOODOO_COMMON_H*/ diff --git a/src/include/86box/vid_voodoo_display.h b/src/include/86box/vid_voodoo_display.h new file mode 100644 index 000000000..522584e3f --- /dev/null +++ b/src/include/86box/vid_voodoo_display.h @@ -0,0 +1,29 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_DISPLAY_H +# define VIDEO_VOODOO_DISPLAY_H + +void voodoo_update_ncc(voodoo_t *voodoo, int tmu); +void voodoo_pixelclock_update(voodoo_t *voodoo); +void voodoo_generate_filter_v1(voodoo_t *voodoo); +void voodoo_generate_filter_v2(voodoo_t *voodoo); +void voodoo_threshold_check(voodoo_t *voodoo); +void voodoo_callback(void *p); + +#endif /*VIDEO_VOODOO_DISPLAY_H*/ diff --git a/src/include/86box/vid_voodoo_dither.h b/src/include/86box/vid_voodoo_dither.h index 21baf772b..1b95e7e80 100644 --- a/src/include/86box/vid_voodoo_dither.h +++ b/src/include/86box/vid_voodoo_dither.h @@ -1,4 +1,25 @@ -uint8_t dither_rb[256][4][4] = +/* + * 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. + * + * Voodoo Graphics and 2 specific emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_DITHER_H +# define VIDEO_VOODOO_DITHER_H + +static const uint8_t dither_rb[256][4][4] = { { {0, 0, 0, 0}, @@ -1538,7 +1559,7 @@ uint8_t dither_rb[256][4][4] = }, }; -uint8_t dither_g[256][4][4] = +static const uint8_t dither_g[256][4][4] = { { {0, 0, 0, 0}, @@ -3078,7 +3099,7 @@ uint8_t dither_g[256][4][4] = }, }; -uint8_t dither_rb2x2[256][2][2] = +static const uint8_t dither_rb2x2[256][2][2] = { { {0, 0}, @@ -4106,7 +4127,7 @@ uint8_t dither_rb2x2[256][2][2] = }, }; -uint8_t dither_g2x2[256][2][2] = +static const uint8_t dither_g2x2[256][2][2] = { { {0, 0}, @@ -5134,3 +5155,5141 @@ uint8_t dither_g2x2[256][2][2] = }, }; +/* Dither subtraction */ +static const uint8_t dithersub_rb[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {9, 5, 8, 4}, + {3, 7, 2, 6}, + {7, 3, 8, 4}, + {1, 5, 2, 6}, + }, + { + {10, 6, 9, 5}, + {4, 8, 3, 7}, + {8, 4, 9, 5}, + {2, 6, 3, 7}, + }, + { + {11, 7, 10, 6}, + {5, 9, 4, 8}, + {9, 5, 10, 6}, + {3, 7, 4, 8}, + }, + { + {12, 8, 11, 7}, + {6, 10, 5, 9}, + {10, 6, 11, 7}, + {4, 8, 5, 9}, + }, + { + {13, 9, 12, 8}, + {7, 11, 6, 10}, + {11, 7, 12, 8}, + {5, 9, 6, 10}, + }, + { + {14, 10, 13, 9}, + {8, 12, 7, 11}, + {12, 8, 13, 9}, + {6, 10, 7, 11}, + }, + { + {15, 11, 14, 10}, + {9, 13, 8, 12}, + {13, 9, 14, 10}, + {7, 11, 8, 12}, + }, + { + {16, 12, 15, 11}, + {10, 14, 9, 13}, + {14, 10, 15, 11}, + {8, 12, 9, 13}, + }, + { + {17, 13, 16, 12}, + {11, 15, 10, 14}, + {15, 11, 16, 12}, + {9, 13, 10, 14}, + }, + { + {18, 14, 17, 13}, + {12, 16, 11, 15}, + {16, 12, 17, 13}, + {10, 14, 11, 15}, + }, + { + {19, 15, 18, 14}, + {13, 17, 12, 16}, + {17, 13, 18, 14}, + {11, 15, 12, 16}, + }, + { + {20, 16, 19, 15}, + {14, 18, 13, 17}, + {18, 14, 19, 15}, + {12, 16, 13, 17}, + }, + { + {21, 17, 20, 16}, + {15, 19, 14, 18}, + {19, 15, 20, 16}, + {13, 17, 14, 18}, + }, + { + {22, 18, 21, 17}, + {16, 20, 15, 19}, + {20, 16, 21, 17}, + {14, 18, 15, 19}, + }, + { + {23, 19, 22, 18}, + {17, 21, 16, 20}, + {21, 17, 22, 18}, + {15, 19, 16, 20}, + }, + { + {24, 20, 23, 19}, + {18, 22, 17, 21}, + {22, 18, 23, 19}, + {16, 20, 17, 21}, + }, + { + {25, 21, 24, 20}, + {19, 23, 18, 22}, + {23, 19, 24, 20}, + {17, 21, 18, 22}, + }, + { + {26, 22, 25, 21}, + {20, 24, 19, 23}, + {24, 20, 25, 21}, + {18, 22, 19, 23}, + }, + { + {27, 23, 26, 22}, + {21, 25, 20, 24}, + {25, 21, 26, 22}, + {19, 23, 20, 24}, + }, + { + {28, 24, 27, 23}, + {22, 26, 21, 25}, + {26, 22, 27, 23}, + {20, 24, 21, 25}, + }, + { + {29, 25, 28, 24}, + {23, 27, 22, 26}, + {27, 23, 28, 24}, + {21, 25, 22, 26}, + }, + { + {30, 26, 29, 25}, + {24, 28, 23, 27}, + {28, 24, 29, 25}, + {22, 26, 23, 27}, + }, + { + {31, 27, 30, 26}, + {25, 29, 24, 28}, + {29, 25, 30, 26}, + {23, 27, 24, 28}, + }, + { + {32, 28, 31, 27}, + {26, 30, 25, 29}, + {30, 26, 31, 27}, + {24, 28, 25, 29}, + }, + { + {33, 29, 32, 28}, + {27, 31, 26, 30}, + {31, 27, 32, 28}, + {25, 29, 26, 30}, + }, + { + {34, 30, 33, 29}, + {28, 32, 27, 31}, + {32, 28, 33, 29}, + {26, 30, 27, 31}, + }, + { + {35, 31, 34, 30}, + {29, 33, 28, 32}, + {33, 29, 34, 30}, + {27, 31, 28, 32}, + }, + { + {36, 32, 35, 31}, + {30, 34, 29, 33}, + {34, 30, 35, 31}, + {28, 32, 29, 33}, + }, + { + {37, 33, 36, 32}, + {31, 35, 30, 34}, + {35, 31, 36, 32}, + {29, 33, 30, 34}, + }, + { + {38, 34, 37, 33}, + {32, 36, 31, 35}, + {36, 32, 37, 33}, + {30, 34, 31, 35}, + }, + { + {39, 35, 38, 34}, + {33, 37, 32, 36}, + {37, 33, 38, 34}, + {31, 35, 32, 36}, + }, + { + {40, 36, 39, 35}, + {34, 38, 33, 37}, + {38, 34, 39, 35}, + {32, 36, 33, 37}, + }, + { + {41, 37, 40, 36}, + {35, 39, 34, 38}, + {39, 35, 40, 36}, + {33, 37, 34, 38}, + }, + { + {42, 38, 41, 37}, + {36, 40, 35, 39}, + {40, 36, 41, 37}, + {34, 38, 35, 39}, + }, + { + {43, 39, 42, 38}, + {37, 41, 36, 40}, + {41, 37, 42, 38}, + {35, 39, 36, 40}, + }, + { + {44, 40, 43, 39}, + {38, 42, 37, 41}, + {42, 38, 43, 39}, + {36, 40, 37, 41}, + }, + { + {45, 41, 44, 40}, + {39, 43, 38, 42}, + {43, 39, 44, 40}, + {37, 41, 38, 42}, + }, + { + {46, 42, 45, 41}, + {40, 44, 39, 43}, + {44, 40, 45, 41}, + {38, 42, 39, 43}, + }, + { + {47, 43, 46, 42}, + {41, 45, 40, 44}, + {45, 41, 46, 42}, + {39, 43, 40, 44}, + }, + { + {48, 44, 47, 43}, + {42, 46, 41, 45}, + {46, 42, 47, 43}, + {40, 44, 41, 45}, + }, + { + {49, 45, 48, 44}, + {43, 47, 42, 46}, + {47, 43, 48, 44}, + {41, 45, 42, 46}, + }, + { + {50, 46, 49, 45}, + {44, 48, 43, 47}, + {48, 44, 49, 45}, + {42, 46, 43, 47}, + }, + { + {51, 47, 50, 46}, + {45, 49, 44, 48}, + {49, 45, 50, 46}, + {43, 47, 44, 48}, + }, + { + {52, 48, 51, 47}, + {46, 50, 45, 49}, + {50, 46, 51, 47}, + {44, 48, 45, 49}, + }, + { + {53, 49, 52, 48}, + {47, 51, 46, 50}, + {51, 47, 52, 48}, + {45, 49, 46, 50}, + }, + { + {54, 50, 53, 49}, + {48, 52, 47, 51}, + {52, 48, 53, 49}, + {46, 50, 47, 51}, + }, + { + {55, 51, 54, 50}, + {49, 53, 48, 52}, + {53, 49, 54, 50}, + {47, 51, 48, 52}, + }, + { + {56, 52, 55, 51}, + {50, 54, 49, 53}, + {54, 50, 55, 51}, + {48, 52, 49, 53}, + }, + { + {57, 53, 56, 52}, + {51, 55, 50, 54}, + {55, 51, 56, 52}, + {49, 53, 50, 54}, + }, + { + {58, 54, 57, 53}, + {52, 56, 51, 55}, + {56, 52, 57, 53}, + {50, 54, 51, 55}, + }, + { + {59, 55, 58, 54}, + {53, 57, 52, 56}, + {57, 53, 58, 54}, + {51, 55, 52, 56}, + }, + { + {60, 56, 59, 55}, + {54, 58, 53, 57}, + {58, 54, 59, 55}, + {52, 56, 53, 57}, + }, + { + {61, 57, 60, 56}, + {55, 59, 54, 58}, + {59, 55, 60, 56}, + {53, 57, 54, 58}, + }, + { + {62, 58, 61, 57}, + {56, 60, 55, 59}, + {60, 56, 61, 57}, + {54, 58, 55, 59}, + }, + { + {63, 59, 62, 58}, + {57, 61, 56, 60}, + {61, 57, 62, 58}, + {55, 59, 56, 60}, + }, + { + {64, 60, 63, 59}, + {58, 62, 57, 61}, + {62, 58, 63, 59}, + {56, 60, 57, 61}, + }, + { + {65, 61, 64, 60}, + {59, 63, 58, 62}, + {63, 59, 64, 60}, + {57, 61, 58, 62}, + }, + { + {66, 62, 65, 61}, + {60, 64, 59, 63}, + {64, 60, 65, 61}, + {58, 62, 59, 63}, + }, + { + {67, 63, 66, 62}, + {61, 65, 60, 64}, + {65, 61, 66, 62}, + {59, 63, 60, 64}, + }, + { + {68, 64, 67, 63}, + {62, 66, 61, 65}, + {66, 62, 67, 63}, + {60, 64, 61, 65}, + }, + { + {69, 65, 68, 64}, + {63, 67, 62, 66}, + {67, 63, 68, 64}, + {61, 65, 62, 66}, + }, + { + {70, 66, 69, 65}, + {64, 68, 63, 67}, + {68, 64, 69, 65}, + {62, 66, 63, 67}, + }, + { + {71, 67, 70, 66}, + {65, 69, 64, 68}, + {69, 65, 70, 66}, + {63, 67, 64, 68}, + }, + { + {72, 68, 71, 67}, + {66, 70, 65, 69}, + {70, 66, 71, 67}, + {64, 68, 65, 69}, + }, + { + {73, 69, 72, 68}, + {67, 71, 66, 70}, + {71, 67, 72, 68}, + {65, 69, 66, 70}, + }, + { + {74, 70, 73, 69}, + {68, 72, 67, 71}, + {72, 68, 73, 69}, + {66, 70, 67, 71}, + }, + { + {75, 71, 74, 70}, + {69, 73, 68, 72}, + {73, 69, 74, 70}, + {67, 71, 68, 72}, + }, + { + {76, 72, 75, 71}, + {70, 74, 69, 73}, + {74, 70, 75, 71}, + {68, 72, 69, 73}, + }, + { + {77, 73, 76, 72}, + {71, 75, 70, 74}, + {75, 71, 76, 72}, + {69, 73, 70, 74}, + }, + { + {78, 74, 77, 73}, + {72, 76, 71, 75}, + {76, 72, 77, 73}, + {70, 74, 71, 75}, + }, + { + {79, 75, 78, 74}, + {73, 77, 72, 76}, + {77, 73, 78, 74}, + {71, 75, 72, 76}, + }, + { + {80, 76, 79, 75}, + {74, 78, 73, 77}, + {78, 74, 79, 75}, + {72, 76, 73, 77}, + }, + { + {81, 77, 80, 76}, + {75, 79, 74, 78}, + {79, 75, 80, 76}, + {73, 77, 74, 78}, + }, + { + {82, 78, 81, 77}, + {76, 80, 75, 79}, + {80, 76, 81, 77}, + {74, 78, 75, 79}, + }, + { + {83, 79, 82, 78}, + {77, 81, 76, 80}, + {81, 77, 82, 78}, + {75, 79, 76, 80}, + }, + { + {84, 80, 83, 79}, + {78, 82, 77, 81}, + {82, 78, 83, 79}, + {76, 80, 77, 81}, + }, + { + {85, 81, 84, 80}, + {79, 83, 78, 82}, + {83, 79, 84, 80}, + {77, 81, 78, 82}, + }, + { + {86, 82, 85, 81}, + {80, 84, 79, 83}, + {84, 80, 85, 81}, + {78, 82, 79, 83}, + }, + { + {87, 83, 86, 82}, + {81, 85, 80, 84}, + {85, 81, 86, 82}, + {79, 83, 80, 84}, + }, + { + {88, 84, 87, 83}, + {82, 86, 81, 85}, + {86, 82, 87, 83}, + {80, 84, 81, 85}, + }, + { + {89, 85, 88, 84}, + {83, 87, 82, 86}, + {87, 83, 88, 84}, + {81, 85, 82, 86}, + }, + { + {90, 86, 89, 85}, + {84, 88, 83, 87}, + {88, 84, 89, 85}, + {82, 86, 83, 87}, + }, + { + {91, 87, 90, 86}, + {85, 89, 84, 88}, + {89, 85, 90, 86}, + {83, 87, 84, 88}, + }, + { + {92, 88, 91, 87}, + {86, 90, 85, 89}, + {90, 86, 91, 87}, + {84, 88, 85, 89}, + }, + { + {93, 89, 92, 88}, + {87, 91, 86, 90}, + {91, 87, 92, 88}, + {85, 89, 86, 90}, + }, + { + {94, 90, 93, 89}, + {88, 92, 87, 91}, + {92, 88, 93, 89}, + {86, 90, 87, 91}, + }, + { + {95, 91, 94, 90}, + {89, 93, 88, 92}, + {93, 89, 94, 90}, + {87, 91, 88, 92}, + }, + { + {96, 92, 95, 91}, + {90, 94, 89, 93}, + {94, 90, 95, 91}, + {88, 92, 89, 93}, + }, + { + {97, 93, 96, 92}, + {91, 95, 90, 94}, + {95, 91, 96, 92}, + {89, 93, 90, 94}, + }, + { + {98, 94, 97, 93}, + {92, 96, 91, 95}, + {96, 92, 97, 93}, + {90, 94, 91, 95}, + }, + { + {99, 95, 98, 94}, + {93, 97, 92, 96}, + {97, 93, 98, 94}, + {91, 95, 92, 96}, + }, + { + {100, 96, 99, 95}, + {94, 98, 93, 97}, + {98, 94, 99, 95}, + {92, 96, 93, 97}, + }, + { + {101, 97, 100, 96}, + {95, 99, 94, 98}, + {99, 95, 100, 96}, + {93, 97, 94, 98}, + }, + { + {102, 98, 101, 97}, + {96, 100, 95, 99}, + {100, 96, 101, 97}, + {94, 98, 95, 99}, + }, + { + {103, 99, 102, 98}, + {97, 101, 96, 100}, + {101, 97, 102, 98}, + {95, 99, 96, 100}, + }, + { + {104, 100, 103, 99}, + {98, 102, 97, 101}, + {102, 98, 103, 99}, + {96, 100, 97, 101}, + }, + { + {105, 101, 104, 100}, + {99, 103, 98, 102}, + {103, 99, 104, 100}, + {97, 101, 98, 102}, + }, + { + {106, 102, 105, 101}, + {100, 104, 99, 103}, + {104, 100, 105, 101}, + {98, 102, 99, 103}, + }, + { + {107, 103, 106, 102}, + {101, 105, 100, 104}, + {105, 101, 106, 102}, + {99, 103, 100, 104}, + }, + { + {108, 104, 107, 103}, + {102, 106, 101, 105}, + {106, 102, 107, 103}, + {100, 104, 101, 105}, + }, + { + {109, 105, 108, 104}, + {103, 107, 102, 106}, + {107, 103, 108, 104}, + {101, 105, 102, 106}, + }, + { + {110, 106, 109, 105}, + {104, 108, 103, 107}, + {108, 104, 109, 105}, + {102, 106, 103, 107}, + }, + { + {111, 107, 110, 106}, + {105, 109, 104, 108}, + {109, 105, 110, 106}, + {103, 107, 104, 108}, + }, + { + {112, 108, 111, 107}, + {106, 110, 105, 109}, + {110, 106, 111, 107}, + {104, 108, 105, 109}, + }, + { + {113, 109, 112, 108}, + {107, 111, 106, 110}, + {111, 107, 112, 108}, + {105, 109, 106, 110}, + }, + { + {114, 110, 113, 109}, + {108, 112, 107, 111}, + {112, 108, 113, 109}, + {106, 110, 107, 111}, + }, + { + {115, 111, 114, 110}, + {109, 113, 108, 112}, + {113, 109, 114, 110}, + {107, 111, 108, 112}, + }, + { + {116, 112, 115, 111}, + {110, 114, 109, 113}, + {114, 110, 115, 111}, + {108, 112, 109, 113}, + }, + { + {117, 113, 116, 112}, + {111, 115, 110, 114}, + {115, 111, 116, 112}, + {109, 113, 110, 114}, + }, + { + {118, 114, 117, 113}, + {112, 116, 111, 115}, + {116, 112, 117, 113}, + {110, 114, 111, 115}, + }, + { + {119, 115, 118, 114}, + {113, 117, 112, 116}, + {117, 113, 118, 114}, + {111, 115, 112, 116}, + }, + { + {120, 116, 119, 115}, + {114, 118, 113, 117}, + {118, 114, 119, 115}, + {112, 116, 113, 117}, + }, + { + {121, 117, 120, 116}, + {115, 119, 114, 118}, + {119, 115, 120, 116}, + {113, 117, 114, 118}, + }, + { + {122, 118, 121, 117}, + {116, 120, 115, 119}, + {120, 116, 121, 117}, + {114, 118, 115, 119}, + }, + { + {123, 119, 122, 118}, + {117, 121, 116, 120}, + {121, 117, 122, 118}, + {115, 119, 116, 120}, + }, + { + {124, 120, 123, 119}, + {118, 122, 117, 121}, + {122, 118, 123, 119}, + {116, 120, 117, 121}, + }, + { + {125, 121, 124, 120}, + {119, 123, 118, 122}, + {123, 119, 124, 120}, + {117, 121, 118, 122}, + }, + { + {126, 122, 125, 121}, + {120, 124, 119, 123}, + {124, 120, 125, 121}, + {118, 122, 119, 123}, + }, + { + {127, 123, 126, 122}, + {121, 125, 120, 124}, + {125, 121, 126, 122}, + {119, 123, 120, 124}, + }, + { + {128, 124, 127, 123}, + {122, 126, 121, 125}, + {126, 122, 127, 123}, + {120, 124, 121, 125}, + }, + { + {129, 125, 128, 124}, + {123, 127, 122, 126}, + {127, 123, 128, 124}, + {121, 125, 122, 126}, + }, + { + {130, 126, 129, 125}, + {124, 128, 123, 127}, + {128, 124, 129, 125}, + {122, 126, 123, 127}, + }, + { + {131, 127, 130, 126}, + {125, 129, 124, 128}, + {129, 125, 130, 126}, + {123, 127, 124, 128}, + }, + { + {132, 128, 131, 127}, + {126, 130, 125, 129}, + {130, 126, 131, 127}, + {124, 128, 125, 129}, + }, + { + {133, 129, 132, 128}, + {127, 131, 126, 130}, + {131, 127, 132, 128}, + {125, 129, 126, 130}, + }, + { + {134, 130, 133, 129}, + {128, 132, 127, 131}, + {132, 128, 133, 129}, + {126, 130, 127, 131}, + }, + { + {135, 131, 134, 130}, + {129, 133, 128, 132}, + {133, 129, 134, 130}, + {127, 131, 128, 132}, + }, + { + {136, 132, 135, 131}, + {130, 134, 129, 133}, + {134, 130, 135, 131}, + {128, 132, 129, 133}, + }, + { + {137, 133, 136, 132}, + {131, 135, 130, 134}, + {135, 131, 136, 132}, + {129, 133, 130, 134}, + }, + { + {138, 134, 137, 133}, + {132, 136, 131, 135}, + {136, 132, 137, 133}, + {130, 134, 131, 135}, + }, + { + {139, 135, 138, 134}, + {133, 137, 132, 136}, + {137, 133, 138, 134}, + {131, 135, 132, 136}, + }, + { + {140, 136, 139, 135}, + {134, 138, 133, 137}, + {138, 134, 139, 135}, + {132, 136, 133, 137}, + }, + { + {141, 137, 140, 136}, + {135, 139, 134, 138}, + {139, 135, 140, 136}, + {133, 137, 134, 138}, + }, + { + {142, 138, 141, 137}, + {136, 140, 135, 139}, + {140, 136, 141, 137}, + {134, 138, 135, 139}, + }, + { + {143, 139, 142, 138}, + {137, 141, 136, 140}, + {141, 137, 142, 138}, + {135, 139, 136, 140}, + }, + { + {144, 140, 143, 139}, + {138, 142, 137, 141}, + {142, 138, 143, 139}, + {136, 140, 137, 141}, + }, + { + {145, 141, 144, 140}, + {139, 143, 138, 142}, + {143, 139, 144, 140}, + {137, 141, 138, 142}, + }, + { + {146, 142, 145, 141}, + {140, 144, 139, 143}, + {144, 140, 145, 141}, + {138, 142, 139, 143}, + }, + { + {147, 143, 146, 142}, + {141, 145, 140, 144}, + {145, 141, 146, 142}, + {139, 143, 140, 144}, + }, + { + {148, 144, 147, 143}, + {142, 146, 141, 145}, + {146, 142, 147, 143}, + {140, 144, 141, 145}, + }, + { + {149, 145, 148, 144}, + {143, 147, 142, 146}, + {147, 143, 148, 144}, + {141, 145, 142, 146}, + }, + { + {150, 146, 149, 145}, + {144, 148, 143, 147}, + {148, 144, 149, 145}, + {142, 146, 143, 147}, + }, + { + {151, 147, 150, 146}, + {145, 149, 144, 148}, + {149, 145, 150, 146}, + {143, 147, 144, 148}, + }, + { + {152, 148, 151, 147}, + {146, 150, 145, 149}, + {150, 146, 151, 147}, + {144, 148, 145, 149}, + }, + { + {153, 149, 152, 148}, + {147, 151, 146, 150}, + {151, 147, 152, 148}, + {145, 149, 146, 150}, + }, + { + {154, 150, 153, 149}, + {148, 152, 147, 151}, + {152, 148, 153, 149}, + {146, 150, 147, 151}, + }, + { + {155, 151, 154, 150}, + {149, 153, 148, 152}, + {153, 149, 154, 150}, + {147, 151, 148, 152}, + }, + { + {156, 152, 155, 151}, + {150, 154, 149, 153}, + {154, 150, 155, 151}, + {148, 152, 149, 153}, + }, + { + {157, 153, 156, 152}, + {151, 155, 150, 154}, + {155, 151, 156, 152}, + {149, 153, 150, 154}, + }, + { + {158, 154, 157, 153}, + {152, 156, 151, 155}, + {156, 152, 157, 153}, + {150, 154, 151, 155}, + }, + { + {159, 155, 158, 154}, + {153, 157, 152, 156}, + {157, 153, 158, 154}, + {151, 155, 152, 156}, + }, + { + {160, 156, 159, 155}, + {154, 158, 153, 157}, + {158, 154, 159, 155}, + {152, 156, 153, 157}, + }, + { + {161, 157, 160, 156}, + {155, 159, 154, 158}, + {159, 155, 160, 156}, + {153, 157, 154, 158}, + }, + { + {162, 158, 161, 157}, + {156, 160, 155, 159}, + {160, 156, 161, 157}, + {154, 158, 155, 159}, + }, + { + {163, 159, 162, 158}, + {157, 161, 156, 160}, + {161, 157, 162, 158}, + {155, 159, 156, 160}, + }, + { + {164, 160, 163, 159}, + {158, 162, 157, 161}, + {162, 158, 163, 159}, + {156, 160, 157, 161}, + }, + { + {165, 161, 164, 160}, + {159, 163, 158, 162}, + {163, 159, 164, 160}, + {157, 161, 158, 162}, + }, + { + {166, 162, 165, 161}, + {160, 164, 159, 163}, + {164, 160, 165, 161}, + {158, 162, 159, 163}, + }, + { + {167, 163, 166, 162}, + {161, 165, 160, 164}, + {165, 161, 166, 162}, + {159, 163, 160, 164}, + }, + { + {168, 164, 167, 163}, + {162, 166, 161, 165}, + {166, 162, 167, 163}, + {160, 164, 161, 165}, + }, + { + {169, 165, 168, 164}, + {163, 167, 162, 166}, + {167, 163, 168, 164}, + {161, 165, 162, 166}, + }, + { + {170, 166, 169, 165}, + {164, 168, 163, 167}, + {168, 164, 169, 165}, + {162, 166, 163, 167}, + }, + { + {171, 167, 170, 166}, + {165, 169, 164, 168}, + {169, 165, 170, 166}, + {163, 167, 164, 168}, + }, + { + {172, 168, 171, 167}, + {166, 170, 165, 169}, + {170, 166, 171, 167}, + {164, 168, 165, 169}, + }, + { + {173, 169, 172, 168}, + {167, 171, 166, 170}, + {171, 167, 172, 168}, + {165, 169, 166, 170}, + }, + { + {174, 170, 173, 169}, + {168, 172, 167, 171}, + {172, 168, 173, 169}, + {166, 170, 167, 171}, + }, + { + {175, 171, 174, 170}, + {169, 173, 168, 172}, + {173, 169, 174, 170}, + {167, 171, 168, 172}, + }, + { + {176, 172, 175, 171}, + {170, 174, 169, 173}, + {174, 170, 175, 171}, + {168, 172, 169, 173}, + }, + { + {177, 173, 176, 172}, + {171, 175, 170, 174}, + {175, 171, 176, 172}, + {169, 173, 170, 174}, + }, + { + {178, 174, 177, 173}, + {172, 176, 171, 175}, + {176, 172, 177, 173}, + {170, 174, 171, 175}, + }, + { + {179, 175, 178, 174}, + {173, 177, 172, 176}, + {177, 173, 178, 174}, + {171, 175, 172, 176}, + }, + { + {180, 176, 179, 175}, + {174, 178, 173, 177}, + {178, 174, 179, 175}, + {172, 176, 173, 177}, + }, + { + {181, 177, 180, 176}, + {175, 179, 174, 178}, + {179, 175, 180, 176}, + {173, 177, 174, 178}, + }, + { + {182, 178, 181, 177}, + {176, 180, 175, 179}, + {180, 176, 181, 177}, + {174, 178, 175, 179}, + }, + { + {183, 179, 182, 178}, + {177, 181, 176, 180}, + {181, 177, 182, 178}, + {175, 179, 176, 180}, + }, + { + {184, 180, 183, 179}, + {178, 182, 177, 181}, + {182, 178, 183, 179}, + {176, 180, 177, 181}, + }, + { + {185, 181, 184, 180}, + {179, 183, 178, 182}, + {183, 179, 184, 180}, + {177, 181, 178, 182}, + }, + { + {186, 182, 185, 181}, + {180, 184, 179, 183}, + {184, 180, 185, 181}, + {178, 182, 179, 183}, + }, + { + {187, 183, 186, 182}, + {181, 185, 180, 184}, + {185, 181, 186, 182}, + {179, 183, 180, 184}, + }, + { + {188, 184, 187, 183}, + {182, 186, 181, 185}, + {186, 182, 187, 183}, + {180, 184, 181, 185}, + }, + { + {189, 185, 188, 184}, + {183, 187, 182, 186}, + {187, 183, 188, 184}, + {181, 185, 182, 186}, + }, + { + {190, 186, 189, 185}, + {184, 188, 183, 187}, + {188, 184, 189, 185}, + {182, 186, 183, 187}, + }, + { + {191, 187, 190, 186}, + {185, 189, 184, 188}, + {189, 185, 190, 186}, + {183, 187, 184, 188}, + }, + { + {192, 188, 191, 187}, + {186, 190, 185, 189}, + {190, 186, 191, 187}, + {184, 188, 185, 189}, + }, + { + {193, 189, 192, 188}, + {187, 191, 186, 190}, + {191, 187, 192, 188}, + {185, 189, 186, 190}, + }, + { + {194, 190, 193, 189}, + {188, 192, 187, 191}, + {192, 188, 193, 189}, + {186, 190, 187, 191}, + }, + { + {195, 191, 194, 190}, + {189, 193, 188, 192}, + {193, 189, 194, 190}, + {187, 191, 188, 192}, + }, + { + {196, 192, 195, 191}, + {190, 194, 189, 193}, + {194, 190, 195, 191}, + {188, 192, 189, 193}, + }, + { + {197, 193, 196, 192}, + {191, 195, 190, 194}, + {195, 191, 196, 192}, + {189, 193, 190, 194}, + }, + { + {198, 194, 197, 193}, + {192, 196, 191, 195}, + {196, 192, 197, 193}, + {190, 194, 191, 195}, + }, + { + {199, 195, 198, 194}, + {193, 197, 192, 196}, + {197, 193, 198, 194}, + {191, 195, 192, 196}, + }, + { + {200, 196, 199, 195}, + {194, 198, 193, 197}, + {198, 194, 199, 195}, + {192, 196, 193, 197}, + }, + { + {201, 197, 200, 196}, + {195, 199, 194, 198}, + {199, 195, 200, 196}, + {193, 197, 194, 198}, + }, + { + {202, 198, 201, 197}, + {196, 200, 195, 199}, + {200, 196, 201, 197}, + {194, 198, 195, 199}, + }, + { + {203, 199, 202, 198}, + {197, 201, 196, 200}, + {201, 197, 202, 198}, + {195, 199, 196, 200}, + }, + { + {204, 200, 203, 199}, + {198, 202, 197, 201}, + {202, 198, 203, 199}, + {196, 200, 197, 201}, + }, + { + {205, 201, 204, 200}, + {199, 203, 198, 202}, + {203, 199, 204, 200}, + {197, 201, 198, 202}, + }, + { + {206, 202, 205, 201}, + {200, 204, 199, 203}, + {204, 200, 205, 201}, + {198, 202, 199, 203}, + }, + { + {207, 203, 206, 202}, + {201, 205, 200, 204}, + {205, 201, 206, 202}, + {199, 203, 200, 204}, + }, + { + {208, 204, 207, 203}, + {202, 206, 201, 205}, + {206, 202, 207, 203}, + {200, 204, 201, 205}, + }, + { + {209, 205, 208, 204}, + {203, 207, 202, 206}, + {207, 203, 208, 204}, + {201, 205, 202, 206}, + }, + { + {210, 206, 209, 205}, + {204, 208, 203, 207}, + {208, 204, 209, 205}, + {202, 206, 203, 207}, + }, + { + {211, 207, 210, 206}, + {205, 209, 204, 208}, + {209, 205, 210, 206}, + {203, 207, 204, 208}, + }, + { + {212, 208, 211, 207}, + {206, 210, 205, 209}, + {210, 206, 211, 207}, + {204, 208, 205, 209}, + }, + { + {213, 209, 212, 208}, + {207, 211, 206, 210}, + {211, 207, 212, 208}, + {205, 209, 206, 210}, + }, + { + {214, 210, 213, 209}, + {208, 212, 207, 211}, + {212, 208, 213, 209}, + {206, 210, 207, 211}, + }, + { + {215, 211, 214, 210}, + {209, 213, 208, 212}, + {213, 209, 214, 210}, + {207, 211, 208, 212}, + }, + { + {216, 212, 215, 211}, + {210, 214, 209, 213}, + {214, 210, 215, 211}, + {208, 212, 209, 213}, + }, + { + {217, 213, 216, 212}, + {211, 215, 210, 214}, + {215, 211, 216, 212}, + {209, 213, 210, 214}, + }, + { + {218, 214, 217, 213}, + {212, 216, 211, 215}, + {216, 212, 217, 213}, + {210, 214, 211, 215}, + }, + { + {219, 215, 218, 214}, + {213, 217, 212, 216}, + {217, 213, 218, 214}, + {211, 215, 212, 216}, + }, + { + {220, 216, 219, 215}, + {214, 218, 213, 217}, + {218, 214, 219, 215}, + {212, 216, 213, 217}, + }, + { + {221, 217, 220, 216}, + {215, 219, 214, 218}, + {219, 215, 220, 216}, + {213, 217, 214, 218}, + }, + { + {222, 218, 221, 217}, + {216, 220, 215, 219}, + {220, 216, 221, 217}, + {214, 218, 215, 219}, + }, + { + {223, 219, 222, 218}, + {217, 221, 216, 220}, + {221, 217, 222, 218}, + {215, 219, 216, 220}, + }, + { + {224, 220, 223, 219}, + {218, 222, 217, 221}, + {222, 218, 223, 219}, + {216, 220, 217, 221}, + }, + { + {225, 221, 224, 220}, + {219, 223, 218, 222}, + {223, 219, 224, 220}, + {217, 221, 218, 222}, + }, + { + {226, 222, 225, 221}, + {220, 224, 219, 223}, + {224, 220, 225, 221}, + {218, 222, 219, 223}, + }, + { + {227, 223, 226, 222}, + {221, 225, 220, 224}, + {225, 221, 226, 222}, + {219, 223, 220, 224}, + }, + { + {228, 224, 227, 223}, + {222, 226, 221, 225}, + {226, 222, 227, 223}, + {220, 224, 221, 225}, + }, + { + {229, 225, 228, 224}, + {223, 227, 222, 226}, + {227, 223, 228, 224}, + {221, 225, 222, 226}, + }, + { + {230, 226, 229, 225}, + {224, 228, 223, 227}, + {228, 224, 229, 225}, + {222, 226, 223, 227}, + }, + { + {231, 227, 230, 226}, + {225, 229, 224, 228}, + {229, 225, 230, 226}, + {223, 227, 224, 228}, + }, + { + {232, 228, 231, 227}, + {226, 230, 225, 229}, + {230, 226, 231, 227}, + {224, 228, 225, 229}, + }, + { + {233, 229, 232, 228}, + {227, 231, 226, 230}, + {231, 227, 232, 228}, + {225, 229, 226, 230}, + }, + { + {234, 230, 233, 229}, + {228, 232, 227, 231}, + {232, 228, 233, 229}, + {226, 230, 227, 231}, + }, + { + {235, 231, 234, 230}, + {229, 233, 228, 232}, + {233, 229, 234, 230}, + {227, 231, 228, 232}, + }, + { + {236, 232, 235, 231}, + {230, 234, 229, 233}, + {234, 230, 235, 231}, + {228, 232, 229, 233}, + }, + { + {237, 233, 236, 232}, + {231, 235, 230, 234}, + {235, 231, 236, 232}, + {229, 233, 230, 234}, + }, + { + {238, 234, 237, 233}, + {232, 236, 231, 235}, + {236, 232, 237, 233}, + {230, 234, 231, 235}, + }, + { + {239, 235, 238, 234}, + {233, 237, 232, 236}, + {237, 233, 238, 234}, + {231, 235, 232, 236}, + }, + { + {240, 236, 239, 235}, + {234, 238, 233, 237}, + {238, 234, 239, 235}, + {232, 236, 233, 237}, + }, + { + {241, 237, 240, 236}, + {235, 239, 234, 238}, + {239, 235, 240, 236}, + {233, 237, 234, 238}, + }, + { + {242, 238, 241, 237}, + {236, 240, 235, 239}, + {240, 236, 241, 237}, + {234, 238, 235, 239}, + }, + { + {243, 239, 242, 238}, + {237, 241, 236, 240}, + {241, 237, 242, 238}, + {235, 239, 236, 240}, + }, + { + {244, 240, 243, 239}, + {238, 242, 237, 241}, + {242, 238, 243, 239}, + {236, 240, 237, 241}, + }, + { + {245, 241, 244, 240}, + {239, 243, 238, 242}, + {243, 239, 244, 240}, + {237, 241, 238, 242}, + }, + { + {246, 242, 245, 241}, + {240, 244, 239, 243}, + {244, 240, 245, 241}, + {238, 242, 239, 243}, + }, + { + {247, 243, 246, 242}, + {241, 245, 240, 244}, + {245, 241, 246, 242}, + {239, 243, 240, 244}, + }, + { + {248, 244, 247, 243}, + {242, 246, 241, 245}, + {246, 242, 247, 243}, + {240, 244, 241, 245}, + }, + { + {249, 245, 248, 244}, + {243, 247, 242, 246}, + {247, 243, 248, 244}, + {241, 245, 242, 246}, + }, + { + {250, 246, 249, 245}, + {244, 248, 243, 247}, + {248, 244, 249, 245}, + {242, 246, 243, 247}, + }, + { + {251, 247, 250, 246}, + {245, 249, 244, 248}, + {249, 245, 250, 246}, + {243, 247, 244, 248}, + }, + { + {252, 248, 251, 247}, + {246, 250, 245, 249}, + {250, 246, 251, 247}, + {244, 248, 245, 249}, + }, + { + {253, 249, 252, 248}, + {247, 251, 246, 250}, + {251, 247, 252, 248}, + {245, 249, 246, 250}, + }, + { + {254, 250, 253, 249}, + {248, 252, 247, 251}, + {252, 248, 253, 249}, + {246, 250, 247, 251}, + }, + { + {255, 251, 254, 250}, + {249, 253, 248, 252}, + {253, 249, 254, 250}, + {247, 251, 248, 252}, + }, + { + {255, 252, 255, 251}, + {250, 254, 249, 253}, + {254, 250, 255, 251}, + {248, 252, 249, 253}, + }, + { + {255, 253, 255, 252}, + {251, 255, 250, 254}, + {255, 251, 255, 252}, + {249, 253, 250, 254}, + }, + { + {255, 254, 255, 253}, + {252, 255, 251, 255}, + {255, 252, 255, 253}, + {250, 254, 251, 255}, + }, + { + {255, 255, 255, 254}, + {253, 255, 252, 255}, + {255, 253, 255, 254}, + {251, 255, 252, 255}, + }, + { + {255, 255, 255, 255}, + {254, 255, 253, 255}, + {255, 254, 255, 255}, + {252, 255, 253, 255}, + }, +}; + +static const uint8_t dithersub_g[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {5, 3, 4, 2}, + {2, 4, 1, 3}, + {4, 2, 4, 2}, + {1, 3, 1, 3}, + }, + { + {6, 4, 5, 3}, + {3, 5, 2, 4}, + {5, 3, 5, 3}, + {2, 4, 2, 4}, + }, + { + {7, 5, 6, 4}, + {4, 6, 3, 5}, + {6, 4, 6, 4}, + {3, 5, 3, 5}, + }, + { + {8, 6, 7, 5}, + {5, 7, 4, 6}, + {7, 5, 7, 5}, + {4, 6, 4, 6}, + }, + { + {9, 7, 8, 6}, + {6, 8, 5, 7}, + {8, 6, 8, 6}, + {5, 7, 5, 7}, + }, + { + {10, 8, 9, 7}, + {7, 9, 6, 8}, + {9, 7, 9, 7}, + {6, 8, 6, 8}, + }, + { + {11, 9, 10, 8}, + {8, 10, 7, 9}, + {10, 8, 10, 8}, + {7, 9, 7, 9}, + }, + { + {12, 10, 11, 9}, + {9, 11, 8, 10}, + {11, 9, 11, 9}, + {8, 10, 8, 10}, + }, + { + {13, 11, 12, 10}, + {10, 12, 9, 11}, + {12, 10, 12, 10}, + {9, 11, 9, 11}, + }, + { + {14, 12, 13, 11}, + {11, 13, 10, 12}, + {13, 11, 13, 11}, + {10, 12, 10, 12}, + }, + { + {15, 13, 14, 12}, + {12, 14, 11, 13}, + {14, 12, 14, 12}, + {11, 13, 11, 13}, + }, + { + {16, 14, 15, 13}, + {13, 15, 12, 14}, + {15, 13, 15, 13}, + {12, 14, 12, 14}, + }, + { + {17, 15, 16, 14}, + {14, 16, 13, 15}, + {16, 14, 16, 14}, + {13, 15, 13, 15}, + }, + { + {18, 16, 17, 15}, + {15, 17, 14, 16}, + {17, 15, 17, 15}, + {14, 16, 14, 16}, + }, + { + {19, 17, 18, 16}, + {16, 18, 15, 17}, + {18, 16, 18, 16}, + {15, 17, 15, 17}, + }, + { + {20, 18, 19, 17}, + {17, 19, 16, 18}, + {19, 17, 19, 17}, + {16, 18, 16, 18}, + }, + { + {21, 19, 20, 18}, + {18, 20, 17, 19}, + {20, 18, 20, 18}, + {17, 19, 17, 19}, + }, + { + {22, 20, 21, 19}, + {19, 21, 18, 20}, + {21, 19, 21, 19}, + {18, 20, 18, 20}, + }, + { + {23, 21, 22, 20}, + {20, 22, 19, 21}, + {22, 20, 22, 20}, + {19, 21, 19, 21}, + }, + { + {24, 22, 23, 21}, + {21, 23, 20, 22}, + {23, 21, 23, 21}, + {20, 22, 20, 22}, + }, + { + {25, 23, 24, 22}, + {22, 24, 21, 23}, + {24, 22, 24, 22}, + {21, 23, 21, 23}, + }, + { + {26, 24, 25, 23}, + {23, 25, 22, 24}, + {25, 23, 25, 23}, + {22, 24, 22, 24}, + }, + { + {27, 25, 26, 24}, + {24, 26, 23, 25}, + {26, 24, 26, 24}, + {23, 25, 23, 25}, + }, + { + {28, 26, 27, 25}, + {25, 27, 24, 26}, + {27, 25, 27, 25}, + {24, 26, 24, 26}, + }, + { + {29, 27, 28, 26}, + {26, 28, 25, 27}, + {28, 26, 28, 26}, + {25, 27, 25, 27}, + }, + { + {30, 28, 29, 27}, + {27, 29, 26, 28}, + {29, 27, 29, 27}, + {26, 28, 26, 28}, + }, + { + {31, 29, 30, 28}, + {28, 30, 27, 29}, + {30, 28, 30, 28}, + {27, 29, 27, 29}, + }, + { + {32, 30, 31, 29}, + {29, 31, 28, 30}, + {31, 29, 31, 29}, + {28, 30, 28, 30}, + }, + { + {33, 31, 32, 30}, + {30, 32, 29, 31}, + {32, 30, 32, 30}, + {29, 31, 29, 31}, + }, + { + {34, 32, 33, 31}, + {31, 33, 30, 32}, + {33, 31, 33, 31}, + {30, 32, 30, 32}, + }, + { + {35, 33, 34, 32}, + {32, 34, 31, 33}, + {34, 32, 34, 32}, + {31, 33, 31, 33}, + }, + { + {36, 34, 35, 33}, + {33, 35, 32, 34}, + {35, 33, 35, 33}, + {32, 34, 32, 34}, + }, + { + {37, 35, 36, 34}, + {34, 36, 33, 35}, + {36, 34, 36, 34}, + {33, 35, 33, 35}, + }, + { + {38, 36, 37, 35}, + {35, 37, 34, 36}, + {37, 35, 37, 35}, + {34, 36, 34, 36}, + }, + { + {39, 37, 38, 36}, + {36, 38, 35, 37}, + {38, 36, 38, 36}, + {35, 37, 35, 37}, + }, + { + {40, 38, 39, 37}, + {37, 39, 36, 38}, + {39, 37, 39, 37}, + {36, 38, 36, 38}, + }, + { + {41, 39, 40, 38}, + {38, 40, 37, 39}, + {40, 38, 40, 38}, + {37, 39, 37, 39}, + }, + { + {42, 40, 41, 39}, + {39, 41, 38, 40}, + {41, 39, 41, 39}, + {38, 40, 38, 40}, + }, + { + {43, 41, 42, 40}, + {40, 42, 39, 41}, + {42, 40, 42, 40}, + {39, 41, 39, 41}, + }, + { + {44, 42, 43, 41}, + {41, 43, 40, 42}, + {43, 41, 43, 41}, + {40, 42, 40, 42}, + }, + { + {45, 43, 44, 42}, + {42, 44, 41, 43}, + {44, 42, 44, 42}, + {41, 43, 41, 43}, + }, + { + {46, 44, 45, 43}, + {43, 45, 42, 44}, + {45, 43, 45, 43}, + {42, 44, 42, 44}, + }, + { + {47, 45, 46, 44}, + {44, 46, 43, 45}, + {46, 44, 46, 44}, + {43, 45, 43, 45}, + }, + { + {48, 46, 47, 45}, + {45, 47, 44, 46}, + {47, 45, 47, 45}, + {44, 46, 44, 46}, + }, + { + {49, 47, 48, 46}, + {46, 48, 45, 47}, + {48, 46, 48, 46}, + {45, 47, 45, 47}, + }, + { + {50, 48, 49, 47}, + {47, 49, 46, 48}, + {49, 47, 49, 47}, + {46, 48, 46, 48}, + }, + { + {51, 49, 50, 48}, + {48, 50, 47, 49}, + {50, 48, 50, 48}, + {47, 49, 47, 49}, + }, + { + {52, 50, 51, 49}, + {49, 51, 48, 50}, + {51, 49, 51, 49}, + {48, 50, 48, 50}, + }, + { + {53, 51, 52, 50}, + {50, 52, 49, 51}, + {52, 50, 52, 50}, + {49, 51, 49, 51}, + }, + { + {54, 52, 53, 51}, + {51, 53, 50, 52}, + {53, 51, 53, 51}, + {50, 52, 50, 52}, + }, + { + {55, 53, 54, 52}, + {52, 54, 51, 53}, + {54, 52, 54, 52}, + {51, 53, 51, 53}, + }, + { + {56, 54, 55, 53}, + {53, 55, 52, 54}, + {55, 53, 55, 53}, + {52, 54, 52, 54}, + }, + { + {57, 55, 56, 54}, + {54, 56, 53, 55}, + {56, 54, 56, 54}, + {53, 55, 53, 55}, + }, + { + {58, 56, 57, 55}, + {55, 57, 54, 56}, + {57, 55, 57, 55}, + {54, 56, 54, 56}, + }, + { + {59, 57, 58, 56}, + {56, 58, 55, 57}, + {58, 56, 58, 56}, + {55, 57, 55, 57}, + }, + { + {60, 58, 59, 57}, + {57, 59, 56, 58}, + {59, 57, 59, 57}, + {56, 58, 56, 58}, + }, + { + {61, 59, 60, 58}, + {58, 60, 57, 59}, + {60, 58, 60, 58}, + {57, 59, 57, 59}, + }, + { + {62, 60, 61, 59}, + {59, 61, 58, 60}, + {61, 59, 61, 59}, + {58, 60, 58, 60}, + }, + { + {63, 61, 62, 60}, + {60, 62, 59, 61}, + {62, 60, 62, 60}, + {59, 61, 59, 61}, + }, + { + {64, 62, 63, 61}, + {61, 63, 60, 62}, + {63, 61, 63, 61}, + {60, 62, 60, 62}, + }, + { + {65, 63, 64, 62}, + {62, 64, 61, 63}, + {64, 62, 64, 62}, + {61, 63, 61, 63}, + }, + { + {66, 64, 65, 63}, + {63, 65, 62, 64}, + {65, 63, 65, 63}, + {62, 64, 62, 64}, + }, + { + {67, 65, 66, 64}, + {64, 66, 63, 65}, + {66, 64, 66, 64}, + {63, 65, 63, 65}, + }, + { + {68, 66, 67, 65}, + {65, 67, 64, 66}, + {67, 65, 67, 65}, + {64, 66, 64, 66}, + }, + { + {69, 67, 68, 66}, + {66, 68, 65, 67}, + {68, 66, 68, 66}, + {65, 67, 65, 67}, + }, + { + {70, 68, 69, 67}, + {67, 69, 66, 68}, + {69, 67, 69, 67}, + {66, 68, 66, 68}, + }, + { + {71, 69, 70, 68}, + {68, 70, 67, 69}, + {70, 68, 70, 68}, + {67, 69, 67, 69}, + }, + { + {72, 70, 71, 69}, + {69, 71, 68, 70}, + {71, 69, 71, 69}, + {68, 70, 68, 70}, + }, + { + {73, 71, 72, 70}, + {70, 72, 69, 71}, + {72, 70, 72, 70}, + {69, 71, 69, 71}, + }, + { + {74, 72, 73, 71}, + {71, 73, 70, 72}, + {73, 71, 73, 71}, + {70, 72, 70, 72}, + }, + { + {75, 73, 74, 72}, + {72, 74, 71, 73}, + {74, 72, 74, 72}, + {71, 73, 71, 73}, + }, + { + {76, 74, 75, 73}, + {73, 75, 72, 74}, + {75, 73, 75, 73}, + {72, 74, 72, 74}, + }, + { + {77, 75, 76, 74}, + {74, 76, 73, 75}, + {76, 74, 76, 74}, + {73, 75, 73, 75}, + }, + { + {78, 76, 77, 75}, + {75, 77, 74, 76}, + {77, 75, 77, 75}, + {74, 76, 74, 76}, + }, + { + {79, 77, 78, 76}, + {76, 78, 75, 77}, + {78, 76, 78, 76}, + {75, 77, 75, 77}, + }, + { + {80, 78, 79, 77}, + {77, 79, 76, 78}, + {79, 77, 79, 77}, + {76, 78, 76, 78}, + }, + { + {81, 79, 80, 78}, + {78, 80, 77, 79}, + {80, 78, 80, 78}, + {77, 79, 77, 79}, + }, + { + {82, 80, 81, 79}, + {79, 81, 78, 80}, + {81, 79, 81, 79}, + {78, 80, 78, 80}, + }, + { + {83, 81, 82, 80}, + {80, 82, 79, 81}, + {82, 80, 82, 80}, + {79, 81, 79, 81}, + }, + { + {84, 82, 83, 81}, + {81, 83, 80, 82}, + {83, 81, 83, 81}, + {80, 82, 80, 82}, + }, + { + {85, 83, 84, 82}, + {82, 84, 81, 83}, + {84, 82, 84, 82}, + {81, 83, 81, 83}, + }, + { + {86, 84, 85, 83}, + {83, 85, 82, 84}, + {85, 83, 85, 83}, + {82, 84, 82, 84}, + }, + { + {87, 85, 86, 84}, + {84, 86, 83, 85}, + {86, 84, 86, 84}, + {83, 85, 83, 85}, + }, + { + {88, 86, 87, 85}, + {85, 87, 84, 86}, + {87, 85, 87, 85}, + {84, 86, 84, 86}, + }, + { + {89, 87, 88, 86}, + {86, 88, 85, 87}, + {88, 86, 88, 86}, + {85, 87, 85, 87}, + }, + { + {90, 88, 89, 87}, + {87, 89, 86, 88}, + {89, 87, 89, 87}, + {86, 88, 86, 88}, + }, + { + {91, 89, 90, 88}, + {88, 90, 87, 89}, + {90, 88, 90, 88}, + {87, 89, 87, 89}, + }, + { + {92, 90, 91, 89}, + {89, 91, 88, 90}, + {91, 89, 91, 89}, + {88, 90, 88, 90}, + }, + { + {93, 91, 92, 90}, + {90, 92, 89, 91}, + {92, 90, 92, 90}, + {89, 91, 89, 91}, + }, + { + {94, 92, 93, 91}, + {91, 93, 90, 92}, + {93, 91, 93, 91}, + {90, 92, 90, 92}, + }, + { + {95, 93, 94, 92}, + {92, 94, 91, 93}, + {94, 92, 94, 92}, + {91, 93, 91, 93}, + }, + { + {96, 94, 95, 93}, + {93, 95, 92, 94}, + {95, 93, 95, 93}, + {92, 94, 92, 94}, + }, + { + {97, 95, 96, 94}, + {94, 96, 93, 95}, + {96, 94, 96, 94}, + {93, 95, 93, 95}, + }, + { + {98, 96, 97, 95}, + {95, 97, 94, 96}, + {97, 95, 97, 95}, + {94, 96, 94, 96}, + }, + { + {99, 97, 98, 96}, + {96, 98, 95, 97}, + {98, 96, 98, 96}, + {95, 97, 95, 97}, + }, + { + {100, 98, 99, 97}, + {97, 99, 96, 98}, + {99, 97, 99, 97}, + {96, 98, 96, 98}, + }, + { + {101, 99, 100, 98}, + {98, 100, 97, 99}, + {100, 98, 100, 98}, + {97, 99, 97, 99}, + }, + { + {102, 100, 101, 99}, + {99, 101, 98, 100}, + {101, 99, 101, 99}, + {98, 100, 98, 100}, + }, + { + {103, 101, 102, 100}, + {100, 102, 99, 101}, + {102, 100, 102, 100}, + {99, 101, 99, 101}, + }, + { + {104, 102, 103, 101}, + {101, 103, 100, 102}, + {103, 101, 103, 101}, + {100, 102, 100, 102}, + }, + { + {105, 103, 104, 102}, + {102, 104, 101, 103}, + {104, 102, 104, 102}, + {101, 103, 101, 103}, + }, + { + {106, 104, 105, 103}, + {103, 105, 102, 104}, + {105, 103, 105, 103}, + {102, 104, 102, 104}, + }, + { + {107, 105, 106, 104}, + {104, 106, 103, 105}, + {106, 104, 106, 104}, + {103, 105, 103, 105}, + }, + { + {108, 106, 107, 105}, + {105, 107, 104, 106}, + {107, 105, 107, 105}, + {104, 106, 104, 106}, + }, + { + {109, 107, 108, 106}, + {106, 108, 105, 107}, + {108, 106, 108, 106}, + {105, 107, 105, 107}, + }, + { + {110, 108, 109, 107}, + {107, 109, 106, 108}, + {109, 107, 109, 107}, + {106, 108, 106, 108}, + }, + { + {111, 109, 110, 108}, + {108, 110, 107, 109}, + {110, 108, 110, 108}, + {107, 109, 107, 109}, + }, + { + {112, 110, 111, 109}, + {109, 111, 108, 110}, + {111, 109, 111, 109}, + {108, 110, 108, 110}, + }, + { + {113, 111, 112, 110}, + {110, 112, 109, 111}, + {112, 110, 112, 110}, + {109, 111, 109, 111}, + }, + { + {114, 112, 113, 111}, + {111, 113, 110, 112}, + {113, 111, 113, 111}, + {110, 112, 110, 112}, + }, + { + {115, 113, 114, 112}, + {112, 114, 111, 113}, + {114, 112, 114, 112}, + {111, 113, 111, 113}, + }, + { + {116, 114, 115, 113}, + {113, 115, 112, 114}, + {115, 113, 115, 113}, + {112, 114, 112, 114}, + }, + { + {117, 115, 116, 114}, + {114, 116, 113, 115}, + {116, 114, 116, 114}, + {113, 115, 113, 115}, + }, + { + {118, 116, 117, 115}, + {115, 117, 114, 116}, + {117, 115, 117, 115}, + {114, 116, 114, 116}, + }, + { + {119, 117, 118, 116}, + {116, 118, 115, 117}, + {118, 116, 118, 116}, + {115, 117, 115, 117}, + }, + { + {120, 118, 119, 117}, + {117, 119, 116, 118}, + {119, 117, 119, 117}, + {116, 118, 116, 118}, + }, + { + {121, 119, 120, 118}, + {118, 120, 117, 119}, + {120, 118, 120, 118}, + {117, 119, 117, 119}, + }, + { + {122, 120, 121, 119}, + {119, 121, 118, 120}, + {121, 119, 121, 119}, + {118, 120, 118, 120}, + }, + { + {123, 121, 122, 120}, + {120, 122, 119, 121}, + {122, 120, 122, 120}, + {119, 121, 119, 121}, + }, + { + {124, 122, 123, 121}, + {121, 123, 120, 122}, + {123, 121, 123, 121}, + {120, 122, 120, 122}, + }, + { + {125, 123, 124, 122}, + {122, 124, 121, 123}, + {124, 122, 124, 122}, + {121, 123, 121, 123}, + }, + { + {126, 124, 125, 123}, + {123, 125, 122, 124}, + {125, 123, 125, 123}, + {122, 124, 122, 124}, + }, + { + {127, 125, 126, 124}, + {124, 126, 123, 125}, + {126, 124, 126, 124}, + {123, 125, 123, 125}, + }, + { + {128, 126, 127, 125}, + {125, 127, 124, 126}, + {127, 125, 127, 125}, + {124, 126, 124, 126}, + }, + { + {129, 127, 128, 126}, + {126, 128, 125, 127}, + {128, 126, 128, 126}, + {125, 127, 125, 127}, + }, + { + {130, 128, 129, 127}, + {127, 129, 126, 128}, + {129, 127, 129, 127}, + {126, 128, 126, 128}, + }, + { + {131, 129, 130, 128}, + {128, 130, 127, 129}, + {130, 128, 130, 128}, + {127, 129, 127, 129}, + }, + { + {132, 130, 131, 129}, + {129, 131, 128, 130}, + {131, 129, 131, 129}, + {128, 130, 128, 130}, + }, + { + {133, 131, 132, 130}, + {130, 132, 129, 131}, + {132, 130, 132, 130}, + {129, 131, 129, 131}, + }, + { + {134, 132, 133, 131}, + {131, 133, 130, 132}, + {133, 131, 133, 131}, + {130, 132, 130, 132}, + }, + { + {135, 133, 134, 132}, + {132, 134, 131, 133}, + {134, 132, 134, 132}, + {131, 133, 131, 133}, + }, + { + {136, 134, 135, 133}, + {133, 135, 132, 134}, + {135, 133, 135, 133}, + {132, 134, 132, 134}, + }, + { + {137, 135, 136, 134}, + {134, 136, 133, 135}, + {136, 134, 136, 134}, + {133, 135, 133, 135}, + }, + { + {138, 136, 137, 135}, + {135, 137, 134, 136}, + {137, 135, 137, 135}, + {134, 136, 134, 136}, + }, + { + {139, 137, 138, 136}, + {136, 138, 135, 137}, + {138, 136, 138, 136}, + {135, 137, 135, 137}, + }, + { + {140, 138, 139, 137}, + {137, 139, 136, 138}, + {139, 137, 139, 137}, + {136, 138, 136, 138}, + }, + { + {141, 139, 140, 138}, + {138, 140, 137, 139}, + {140, 138, 140, 138}, + {137, 139, 137, 139}, + }, + { + {142, 140, 141, 139}, + {139, 141, 138, 140}, + {141, 139, 141, 139}, + {138, 140, 138, 140}, + }, + { + {143, 141, 142, 140}, + {140, 142, 139, 141}, + {142, 140, 142, 140}, + {139, 141, 139, 141}, + }, + { + {144, 142, 143, 141}, + {141, 143, 140, 142}, + {143, 141, 143, 141}, + {140, 142, 140, 142}, + }, + { + {145, 143, 144, 142}, + {142, 144, 141, 143}, + {144, 142, 144, 142}, + {141, 143, 141, 143}, + }, + { + {146, 144, 145, 143}, + {143, 145, 142, 144}, + {145, 143, 145, 143}, + {142, 144, 142, 144}, + }, + { + {147, 145, 146, 144}, + {144, 146, 143, 145}, + {146, 144, 146, 144}, + {143, 145, 143, 145}, + }, + { + {148, 146, 147, 145}, + {145, 147, 144, 146}, + {147, 145, 147, 145}, + {144, 146, 144, 146}, + }, + { + {149, 147, 148, 146}, + {146, 148, 145, 147}, + {148, 146, 148, 146}, + {145, 147, 145, 147}, + }, + { + {150, 148, 149, 147}, + {147, 149, 146, 148}, + {149, 147, 149, 147}, + {146, 148, 146, 148}, + }, + { + {151, 149, 150, 148}, + {148, 150, 147, 149}, + {150, 148, 150, 148}, + {147, 149, 147, 149}, + }, + { + {152, 150, 151, 149}, + {149, 151, 148, 150}, + {151, 149, 151, 149}, + {148, 150, 148, 150}, + }, + { + {153, 151, 152, 150}, + {150, 152, 149, 151}, + {152, 150, 152, 150}, + {149, 151, 149, 151}, + }, + { + {154, 152, 153, 151}, + {151, 153, 150, 152}, + {153, 151, 153, 151}, + {150, 152, 150, 152}, + }, + { + {155, 153, 154, 152}, + {152, 154, 151, 153}, + {154, 152, 154, 152}, + {151, 153, 151, 153}, + }, + { + {156, 154, 155, 153}, + {153, 155, 152, 154}, + {155, 153, 155, 153}, + {152, 154, 152, 154}, + }, + { + {157, 155, 156, 154}, + {154, 156, 153, 155}, + {156, 154, 156, 154}, + {153, 155, 153, 155}, + }, + { + {158, 156, 157, 155}, + {155, 157, 154, 156}, + {157, 155, 157, 155}, + {154, 156, 154, 156}, + }, + { + {159, 157, 158, 156}, + {156, 158, 155, 157}, + {158, 156, 158, 156}, + {155, 157, 155, 157}, + }, + { + {160, 158, 159, 157}, + {157, 159, 156, 158}, + {159, 157, 159, 157}, + {156, 158, 156, 158}, + }, + { + {161, 159, 160, 158}, + {158, 160, 157, 159}, + {160, 158, 160, 158}, + {157, 159, 157, 159}, + }, + { + {162, 160, 161, 159}, + {159, 161, 158, 160}, + {161, 159, 161, 159}, + {158, 160, 158, 160}, + }, + { + {163, 161, 162, 160}, + {160, 162, 159, 161}, + {162, 160, 162, 160}, + {159, 161, 159, 161}, + }, + { + {164, 162, 163, 161}, + {161, 163, 160, 162}, + {163, 161, 163, 161}, + {160, 162, 160, 162}, + }, + { + {165, 163, 164, 162}, + {162, 164, 161, 163}, + {164, 162, 164, 162}, + {161, 163, 161, 163}, + }, + { + {166, 164, 165, 163}, + {163, 165, 162, 164}, + {165, 163, 165, 163}, + {162, 164, 162, 164}, + }, + { + {167, 165, 166, 164}, + {164, 166, 163, 165}, + {166, 164, 166, 164}, + {163, 165, 163, 165}, + }, + { + {168, 166, 167, 165}, + {165, 167, 164, 166}, + {167, 165, 167, 165}, + {164, 166, 164, 166}, + }, + { + {169, 167, 168, 166}, + {166, 168, 165, 167}, + {168, 166, 168, 166}, + {165, 167, 165, 167}, + }, + { + {170, 168, 169, 167}, + {167, 169, 166, 168}, + {169, 167, 169, 167}, + {166, 168, 166, 168}, + }, + { + {171, 169, 170, 168}, + {168, 170, 167, 169}, + {170, 168, 170, 168}, + {167, 169, 167, 169}, + }, + { + {172, 170, 171, 169}, + {169, 171, 168, 170}, + {171, 169, 171, 169}, + {168, 170, 168, 170}, + }, + { + {173, 171, 172, 170}, + {170, 172, 169, 171}, + {172, 170, 172, 170}, + {169, 171, 169, 171}, + }, + { + {174, 172, 173, 171}, + {171, 173, 170, 172}, + {173, 171, 173, 171}, + {170, 172, 170, 172}, + }, + { + {175, 173, 174, 172}, + {172, 174, 171, 173}, + {174, 172, 174, 172}, + {171, 173, 171, 173}, + }, + { + {176, 174, 175, 173}, + {173, 175, 172, 174}, + {175, 173, 175, 173}, + {172, 174, 172, 174}, + }, + { + {177, 175, 176, 174}, + {174, 176, 173, 175}, + {176, 174, 176, 174}, + {173, 175, 173, 175}, + }, + { + {178, 176, 177, 175}, + {175, 177, 174, 176}, + {177, 175, 177, 175}, + {174, 176, 174, 176}, + }, + { + {179, 177, 178, 176}, + {176, 178, 175, 177}, + {178, 176, 178, 176}, + {175, 177, 175, 177}, + }, + { + {180, 178, 179, 177}, + {177, 179, 176, 178}, + {179, 177, 179, 177}, + {176, 178, 176, 178}, + }, + { + {181, 179, 180, 178}, + {178, 180, 177, 179}, + {180, 178, 180, 178}, + {177, 179, 177, 179}, + }, + { + {182, 180, 181, 179}, + {179, 181, 178, 180}, + {181, 179, 181, 179}, + {178, 180, 178, 180}, + }, + { + {183, 181, 182, 180}, + {180, 182, 179, 181}, + {182, 180, 182, 180}, + {179, 181, 179, 181}, + }, + { + {184, 182, 183, 181}, + {181, 183, 180, 182}, + {183, 181, 183, 181}, + {180, 182, 180, 182}, + }, + { + {185, 183, 184, 182}, + {182, 184, 181, 183}, + {184, 182, 184, 182}, + {181, 183, 181, 183}, + }, + { + {186, 184, 185, 183}, + {183, 185, 182, 184}, + {185, 183, 185, 183}, + {182, 184, 182, 184}, + }, + { + {187, 185, 186, 184}, + {184, 186, 183, 185}, + {186, 184, 186, 184}, + {183, 185, 183, 185}, + }, + { + {188, 186, 187, 185}, + {185, 187, 184, 186}, + {187, 185, 187, 185}, + {184, 186, 184, 186}, + }, + { + {189, 187, 188, 186}, + {186, 188, 185, 187}, + {188, 186, 188, 186}, + {185, 187, 185, 187}, + }, + { + {190, 188, 189, 187}, + {187, 189, 186, 188}, + {189, 187, 189, 187}, + {186, 188, 186, 188}, + }, + { + {191, 189, 190, 188}, + {188, 190, 187, 189}, + {190, 188, 190, 188}, + {187, 189, 187, 189}, + }, + { + {192, 190, 191, 189}, + {189, 191, 188, 190}, + {191, 189, 191, 189}, + {188, 190, 188, 190}, + }, + { + {193, 191, 192, 190}, + {190, 192, 189, 191}, + {192, 190, 192, 190}, + {189, 191, 189, 191}, + }, + { + {194, 192, 193, 191}, + {191, 193, 190, 192}, + {193, 191, 193, 191}, + {190, 192, 190, 192}, + }, + { + {195, 193, 194, 192}, + {192, 194, 191, 193}, + {194, 192, 194, 192}, + {191, 193, 191, 193}, + }, + { + {196, 194, 195, 193}, + {193, 195, 192, 194}, + {195, 193, 195, 193}, + {192, 194, 192, 194}, + }, + { + {197, 195, 196, 194}, + {194, 196, 193, 195}, + {196, 194, 196, 194}, + {193, 195, 193, 195}, + }, + { + {198, 196, 197, 195}, + {195, 197, 194, 196}, + {197, 195, 197, 195}, + {194, 196, 194, 196}, + }, + { + {199, 197, 198, 196}, + {196, 198, 195, 197}, + {198, 196, 198, 196}, + {195, 197, 195, 197}, + }, + { + {200, 198, 199, 197}, + {197, 199, 196, 198}, + {199, 197, 199, 197}, + {196, 198, 196, 198}, + }, + { + {201, 199, 200, 198}, + {198, 200, 197, 199}, + {200, 198, 200, 198}, + {197, 199, 197, 199}, + }, + { + {202, 200, 201, 199}, + {199, 201, 198, 200}, + {201, 199, 201, 199}, + {198, 200, 198, 200}, + }, + { + {203, 201, 202, 200}, + {200, 202, 199, 201}, + {202, 200, 202, 200}, + {199, 201, 199, 201}, + }, + { + {204, 202, 203, 201}, + {201, 203, 200, 202}, + {203, 201, 203, 201}, + {200, 202, 200, 202}, + }, + { + {205, 203, 204, 202}, + {202, 204, 201, 203}, + {204, 202, 204, 202}, + {201, 203, 201, 203}, + }, + { + {206, 204, 205, 203}, + {203, 205, 202, 204}, + {205, 203, 205, 203}, + {202, 204, 202, 204}, + }, + { + {207, 205, 206, 204}, + {204, 206, 203, 205}, + {206, 204, 206, 204}, + {203, 205, 203, 205}, + }, + { + {208, 206, 207, 205}, + {205, 207, 204, 206}, + {207, 205, 207, 205}, + {204, 206, 204, 206}, + }, + { + {209, 207, 208, 206}, + {206, 208, 205, 207}, + {208, 206, 208, 206}, + {205, 207, 205, 207}, + }, + { + {210, 208, 209, 207}, + {207, 209, 206, 208}, + {209, 207, 209, 207}, + {206, 208, 206, 208}, + }, + { + {211, 209, 210, 208}, + {208, 210, 207, 209}, + {210, 208, 210, 208}, + {207, 209, 207, 209}, + }, + { + {212, 210, 211, 209}, + {209, 211, 208, 210}, + {211, 209, 211, 209}, + {208, 210, 208, 210}, + }, + { + {213, 211, 212, 210}, + {210, 212, 209, 211}, + {212, 210, 212, 210}, + {209, 211, 209, 211}, + }, + { + {214, 212, 213, 211}, + {211, 213, 210, 212}, + {213, 211, 213, 211}, + {210, 212, 210, 212}, + }, + { + {215, 213, 214, 212}, + {212, 214, 211, 213}, + {214, 212, 214, 212}, + {211, 213, 211, 213}, + }, + { + {216, 214, 215, 213}, + {213, 215, 212, 214}, + {215, 213, 215, 213}, + {212, 214, 212, 214}, + }, + { + {217, 215, 216, 214}, + {214, 216, 213, 215}, + {216, 214, 216, 214}, + {213, 215, 213, 215}, + }, + { + {218, 216, 217, 215}, + {215, 217, 214, 216}, + {217, 215, 217, 215}, + {214, 216, 214, 216}, + }, + { + {219, 217, 218, 216}, + {216, 218, 215, 217}, + {218, 216, 218, 216}, + {215, 217, 215, 217}, + }, + { + {220, 218, 219, 217}, + {217, 219, 216, 218}, + {219, 217, 219, 217}, + {216, 218, 216, 218}, + }, + { + {221, 219, 220, 218}, + {218, 220, 217, 219}, + {220, 218, 220, 218}, + {217, 219, 217, 219}, + }, + { + {222, 220, 221, 219}, + {219, 221, 218, 220}, + {221, 219, 221, 219}, + {218, 220, 218, 220}, + }, + { + {223, 221, 222, 220}, + {220, 222, 219, 221}, + {222, 220, 222, 220}, + {219, 221, 219, 221}, + }, + { + {224, 222, 223, 221}, + {221, 223, 220, 222}, + {223, 221, 223, 221}, + {220, 222, 220, 222}, + }, + { + {225, 223, 224, 222}, + {222, 224, 221, 223}, + {224, 222, 224, 222}, + {221, 223, 221, 223}, + }, + { + {226, 224, 225, 223}, + {223, 225, 222, 224}, + {225, 223, 225, 223}, + {222, 224, 222, 224}, + }, + { + {227, 225, 226, 224}, + {224, 226, 223, 225}, + {226, 224, 226, 224}, + {223, 225, 223, 225}, + }, + { + {228, 226, 227, 225}, + {225, 227, 224, 226}, + {227, 225, 227, 225}, + {224, 226, 224, 226}, + }, + { + {229, 227, 228, 226}, + {226, 228, 225, 227}, + {228, 226, 228, 226}, + {225, 227, 225, 227}, + }, + { + {230, 228, 229, 227}, + {227, 229, 226, 228}, + {229, 227, 229, 227}, + {226, 228, 226, 228}, + }, + { + {231, 229, 230, 228}, + {228, 230, 227, 229}, + {230, 228, 230, 228}, + {227, 229, 227, 229}, + }, + { + {232, 230, 231, 229}, + {229, 231, 228, 230}, + {231, 229, 231, 229}, + {228, 230, 228, 230}, + }, + { + {233, 231, 232, 230}, + {230, 232, 229, 231}, + {232, 230, 232, 230}, + {229, 231, 229, 231}, + }, + { + {234, 232, 233, 231}, + {231, 233, 230, 232}, + {233, 231, 233, 231}, + {230, 232, 230, 232}, + }, + { + {235, 233, 234, 232}, + {232, 234, 231, 233}, + {234, 232, 234, 232}, + {231, 233, 231, 233}, + }, + { + {236, 234, 235, 233}, + {233, 235, 232, 234}, + {235, 233, 235, 233}, + {232, 234, 232, 234}, + }, + { + {237, 235, 236, 234}, + {234, 236, 233, 235}, + {236, 234, 236, 234}, + {233, 235, 233, 235}, + }, + { + {238, 236, 237, 235}, + {235, 237, 234, 236}, + {237, 235, 237, 235}, + {234, 236, 234, 236}, + }, + { + {239, 237, 238, 236}, + {236, 238, 235, 237}, + {238, 236, 238, 236}, + {235, 237, 235, 237}, + }, + { + {240, 238, 239, 237}, + {237, 239, 236, 238}, + {239, 237, 239, 237}, + {236, 238, 236, 238}, + }, + { + {241, 239, 240, 238}, + {238, 240, 237, 239}, + {240, 238, 240, 238}, + {237, 239, 237, 239}, + }, + { + {242, 240, 241, 239}, + {239, 241, 238, 240}, + {241, 239, 241, 239}, + {238, 240, 238, 240}, + }, + { + {243, 241, 242, 240}, + {240, 242, 239, 241}, + {242, 240, 242, 240}, + {239, 241, 239, 241}, + }, + { + {244, 242, 243, 241}, + {241, 243, 240, 242}, + {243, 241, 243, 241}, + {240, 242, 240, 242}, + }, + { + {245, 243, 244, 242}, + {242, 244, 241, 243}, + {244, 242, 244, 242}, + {241, 243, 241, 243}, + }, + { + {246, 244, 245, 243}, + {243, 245, 242, 244}, + {245, 243, 245, 243}, + {242, 244, 242, 244}, + }, + { + {247, 245, 246, 244}, + {244, 246, 243, 245}, + {246, 244, 246, 244}, + {243, 245, 243, 245}, + }, + { + {248, 246, 247, 245}, + {245, 247, 244, 246}, + {247, 245, 247, 245}, + {244, 246, 244, 246}, + }, + { + {249, 247, 248, 246}, + {246, 248, 245, 247}, + {248, 246, 248, 246}, + {245, 247, 245, 247}, + }, + { + {250, 248, 249, 247}, + {247, 249, 246, 248}, + {249, 247, 249, 247}, + {246, 248, 246, 248}, + }, + { + {251, 249, 250, 248}, + {248, 250, 247, 249}, + {250, 248, 250, 248}, + {247, 249, 247, 249}, + }, + { + {252, 250, 251, 249}, + {249, 251, 248, 250}, + {251, 249, 251, 249}, + {248, 250, 248, 250}, + }, + { + {253, 251, 252, 250}, + {250, 252, 249, 251}, + {252, 250, 252, 250}, + {249, 251, 249, 251}, + }, + { + {254, 252, 253, 251}, + {251, 253, 250, 252}, + {253, 251, 253, 251}, + {250, 252, 250, 252}, + }, + { + {255, 253, 254, 252}, + {252, 254, 251, 253}, + {254, 252, 254, 252}, + {251, 253, 251, 253}, + }, + { + {255, 254, 255, 253}, + {253, 255, 252, 254}, + {255, 253, 255, 253}, + {252, 254, 252, 254}, + }, + { + {255, 255, 255, 254}, + {254, 255, 253, 255}, + {255, 254, 255, 254}, + {253, 255, 253, 255}, + }, + { + {255, 255, 255, 255}, + {255, 255, 254, 255}, + {255, 255, 255, 255}, + {254, 255, 254, 255}, + }, +}; + +static const uint8_t dithersub_g2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {4, 2}, + {1, 3}, + }, + { + {5, 3}, + {2, 4}, + }, + { + {6, 4}, + {3, 5}, + }, + { + {7, 5}, + {4, 6}, + }, + { + {8, 6}, + {5, 7}, + }, + { + {9, 7}, + {6, 8}, + }, + { + {10, 8}, + {7, 9}, + }, + { + {11, 9}, + {8, 10}, + }, + { + {12, 10}, + {9, 11}, + }, + { + {13, 11}, + {10, 12}, + }, + { + {14, 12}, + {11, 13}, + }, + { + {15, 13}, + {12, 14}, + }, + { + {16, 14}, + {13, 15}, + }, + { + {17, 15}, + {14, 16}, + }, + { + {18, 16}, + {15, 17}, + }, + { + {19, 17}, + {16, 18}, + }, + { + {20, 18}, + {17, 19}, + }, + { + {21, 19}, + {18, 20}, + }, + { + {22, 20}, + {19, 21}, + }, + { + {23, 21}, + {20, 22}, + }, + { + {24, 22}, + {21, 23}, + }, + { + {25, 23}, + {22, 24}, + }, + { + {26, 24}, + {23, 25}, + }, + { + {27, 25}, + {24, 26}, + }, + { + {28, 26}, + {25, 27}, + }, + { + {29, 27}, + {26, 28}, + }, + { + {30, 28}, + {27, 29}, + }, + { + {31, 29}, + {28, 30}, + }, + { + {32, 30}, + {29, 31}, + }, + { + {33, 31}, + {30, 32}, + }, + { + {34, 32}, + {31, 33}, + }, + { + {35, 33}, + {32, 34}, + }, + { + {36, 34}, + {33, 35}, + }, + { + {37, 35}, + {34, 36}, + }, + { + {38, 36}, + {35, 37}, + }, + { + {39, 37}, + {36, 38}, + }, + { + {40, 38}, + {37, 39}, + }, + { + {41, 39}, + {38, 40}, + }, + { + {42, 40}, + {39, 41}, + }, + { + {43, 41}, + {40, 42}, + }, + { + {44, 42}, + {41, 43}, + }, + { + {45, 43}, + {42, 44}, + }, + { + {46, 44}, + {43, 45}, + }, + { + {47, 45}, + {44, 46}, + }, + { + {48, 46}, + {45, 47}, + }, + { + {49, 47}, + {46, 48}, + }, + { + {50, 48}, + {47, 49}, + }, + { + {51, 49}, + {48, 50}, + }, + { + {52, 50}, + {49, 51}, + }, + { + {53, 51}, + {50, 52}, + }, + { + {54, 52}, + {51, 53}, + }, + { + {55, 53}, + {52, 54}, + }, + { + {56, 54}, + {53, 55}, + }, + { + {57, 55}, + {54, 56}, + }, + { + {58, 56}, + {55, 57}, + }, + { + {59, 57}, + {56, 58}, + }, + { + {60, 58}, + {57, 59}, + }, + { + {61, 59}, + {58, 60}, + }, + { + {62, 60}, + {59, 61}, + }, + { + {63, 61}, + {60, 62}, + }, + { + {64, 62}, + {61, 63}, + }, + { + {65, 63}, + {62, 64}, + }, + { + {66, 64}, + {63, 65}, + }, + { + {67, 65}, + {64, 66}, + }, + { + {68, 66}, + {65, 67}, + }, + { + {69, 67}, + {66, 68}, + }, + { + {70, 68}, + {67, 69}, + }, + { + {71, 69}, + {68, 70}, + }, + { + {72, 70}, + {69, 71}, + }, + { + {73, 71}, + {70, 72}, + }, + { + {74, 72}, + {71, 73}, + }, + { + {75, 73}, + {72, 74}, + }, + { + {76, 74}, + {73, 75}, + }, + { + {77, 75}, + {74, 76}, + }, + { + {78, 76}, + {75, 77}, + }, + { + {79, 77}, + {76, 78}, + }, + { + {80, 78}, + {77, 79}, + }, + { + {81, 79}, + {78, 80}, + }, + { + {82, 80}, + {79, 81}, + }, + { + {83, 81}, + {80, 82}, + }, + { + {84, 82}, + {81, 83}, + }, + { + {85, 83}, + {82, 84}, + }, + { + {86, 84}, + {83, 85}, + }, + { + {87, 85}, + {84, 86}, + }, + { + {88, 86}, + {85, 87}, + }, + { + {89, 87}, + {86, 88}, + }, + { + {90, 88}, + {87, 89}, + }, + { + {91, 89}, + {88, 90}, + }, + { + {92, 90}, + {89, 91}, + }, + { + {93, 91}, + {90, 92}, + }, + { + {94, 92}, + {91, 93}, + }, + { + {95, 93}, + {92, 94}, + }, + { + {96, 94}, + {93, 95}, + }, + { + {97, 95}, + {94, 96}, + }, + { + {98, 96}, + {95, 97}, + }, + { + {99, 97}, + {96, 98}, + }, + { + {100, 98}, + {97, 99}, + }, + { + {101, 99}, + {98, 100}, + }, + { + {102, 100}, + {99, 101}, + }, + { + {103, 101}, + {100, 102}, + }, + { + {104, 102}, + {101, 103}, + }, + { + {105, 103}, + {102, 104}, + }, + { + {106, 104}, + {103, 105}, + }, + { + {107, 105}, + {104, 106}, + }, + { + {108, 106}, + {105, 107}, + }, + { + {109, 107}, + {106, 108}, + }, + { + {110, 108}, + {107, 109}, + }, + { + {111, 109}, + {108, 110}, + }, + { + {112, 110}, + {109, 111}, + }, + { + {113, 111}, + {110, 112}, + }, + { + {114, 112}, + {111, 113}, + }, + { + {115, 113}, + {112, 114}, + }, + { + {116, 114}, + {113, 115}, + }, + { + {117, 115}, + {114, 116}, + }, + { + {118, 116}, + {115, 117}, + }, + { + {119, 117}, + {116, 118}, + }, + { + {120, 118}, + {117, 119}, + }, + { + {121, 119}, + {118, 120}, + }, + { + {122, 120}, + {119, 121}, + }, + { + {123, 121}, + {120, 122}, + }, + { + {124, 122}, + {121, 123}, + }, + { + {125, 123}, + {122, 124}, + }, + { + {126, 124}, + {123, 125}, + }, + { + {127, 125}, + {124, 126}, + }, + { + {128, 126}, + {125, 127}, + }, + { + {129, 127}, + {126, 128}, + }, + { + {130, 128}, + {127, 129}, + }, + { + {131, 129}, + {128, 130}, + }, + { + {132, 130}, + {129, 131}, + }, + { + {133, 131}, + {130, 132}, + }, + { + {134, 132}, + {131, 133}, + }, + { + {135, 133}, + {132, 134}, + }, + { + {136, 134}, + {133, 135}, + }, + { + {137, 135}, + {134, 136}, + }, + { + {138, 136}, + {135, 137}, + }, + { + {139, 137}, + {136, 138}, + }, + { + {140, 138}, + {137, 139}, + }, + { + {141, 139}, + {138, 140}, + }, + { + {142, 140}, + {139, 141}, + }, + { + {143, 141}, + {140, 142}, + }, + { + {144, 142}, + {141, 143}, + }, + { + {145, 143}, + {142, 144}, + }, + { + {146, 144}, + {143, 145}, + }, + { + {147, 145}, + {144, 146}, + }, + { + {148, 146}, + {145, 147}, + }, + { + {149, 147}, + {146, 148}, + }, + { + {150, 148}, + {147, 149}, + }, + { + {151, 149}, + {148, 150}, + }, + { + {152, 150}, + {149, 151}, + }, + { + {153, 151}, + {150, 152}, + }, + { + {154, 152}, + {151, 153}, + }, + { + {155, 153}, + {152, 154}, + }, + { + {156, 154}, + {153, 155}, + }, + { + {157, 155}, + {154, 156}, + }, + { + {158, 156}, + {155, 157}, + }, + { + {159, 157}, + {156, 158}, + }, + { + {160, 158}, + {157, 159}, + }, + { + {161, 159}, + {158, 160}, + }, + { + {162, 160}, + {159, 161}, + }, + { + {163, 161}, + {160, 162}, + }, + { + {164, 162}, + {161, 163}, + }, + { + {165, 163}, + {162, 164}, + }, + { + {166, 164}, + {163, 165}, + }, + { + {167, 165}, + {164, 166}, + }, + { + {168, 166}, + {165, 167}, + }, + { + {169, 167}, + {166, 168}, + }, + { + {170, 168}, + {167, 169}, + }, + { + {171, 169}, + {168, 170}, + }, + { + {172, 170}, + {169, 171}, + }, + { + {173, 171}, + {170, 172}, + }, + { + {174, 172}, + {171, 173}, + }, + { + {175, 173}, + {172, 174}, + }, + { + {176, 174}, + {173, 175}, + }, + { + {177, 175}, + {174, 176}, + }, + { + {178, 176}, + {175, 177}, + }, + { + {179, 177}, + {176, 178}, + }, + { + {180, 178}, + {177, 179}, + }, + { + {181, 179}, + {178, 180}, + }, + { + {182, 180}, + {179, 181}, + }, + { + {183, 181}, + {180, 182}, + }, + { + {184, 182}, + {181, 183}, + }, + { + {185, 183}, + {182, 184}, + }, + { + {186, 184}, + {183, 185}, + }, + { + {187, 185}, + {184, 186}, + }, + { + {188, 186}, + {185, 187}, + }, + { + {189, 187}, + {186, 188}, + }, + { + {190, 188}, + {187, 189}, + }, + { + {191, 189}, + {188, 190}, + }, + { + {192, 190}, + {189, 191}, + }, + { + {193, 191}, + {190, 192}, + }, + { + {194, 192}, + {191, 193}, + }, + { + {195, 193}, + {192, 194}, + }, + { + {196, 194}, + {193, 195}, + }, + { + {197, 195}, + {194, 196}, + }, + { + {198, 196}, + {195, 197}, + }, + { + {199, 197}, + {196, 198}, + }, + { + {200, 198}, + {197, 199}, + }, + { + {201, 199}, + {198, 200}, + }, + { + {202, 200}, + {199, 201}, + }, + { + {203, 201}, + {200, 202}, + }, + { + {204, 202}, + {201, 203}, + }, + { + {205, 203}, + {202, 204}, + }, + { + {206, 204}, + {203, 205}, + }, + { + {207, 205}, + {204, 206}, + }, + { + {208, 206}, + {205, 207}, + }, + { + {209, 207}, + {206, 208}, + }, + { + {210, 208}, + {207, 209}, + }, + { + {211, 209}, + {208, 210}, + }, + { + {212, 210}, + {209, 211}, + }, + { + {213, 211}, + {210, 212}, + }, + { + {214, 212}, + {211, 213}, + }, + { + {215, 213}, + {212, 214}, + }, + { + {216, 214}, + {213, 215}, + }, + { + {217, 215}, + {214, 216}, + }, + { + {218, 216}, + {215, 217}, + }, + { + {219, 217}, + {216, 218}, + }, + { + {220, 218}, + {217, 219}, + }, + { + {221, 219}, + {218, 220}, + }, + { + {222, 220}, + {219, 221}, + }, + { + {223, 221}, + {220, 222}, + }, + { + {224, 222}, + {221, 223}, + }, + { + {225, 223}, + {222, 224}, + }, + { + {226, 224}, + {223, 225}, + }, + { + {227, 225}, + {224, 226}, + }, + { + {228, 226}, + {225, 227}, + }, + { + {229, 227}, + {226, 228}, + }, + { + {230, 228}, + {227, 229}, + }, + { + {231, 229}, + {228, 230}, + }, + { + {232, 230}, + {229, 231}, + }, + { + {233, 231}, + {230, 232}, + }, + { + {234, 232}, + {231, 233}, + }, + { + {235, 233}, + {232, 234}, + }, + { + {236, 234}, + {233, 235}, + }, + { + {237, 235}, + {234, 236}, + }, + { + {238, 236}, + {235, 237}, + }, + { + {239, 237}, + {236, 238}, + }, + { + {240, 238}, + {237, 239}, + }, + { + {241, 239}, + {238, 240}, + }, + { + {242, 240}, + {239, 241}, + }, + { + {243, 241}, + {240, 242}, + }, + { + {244, 242}, + {241, 243}, + }, + { + {245, 243}, + {242, 244}, + }, + { + {246, 244}, + {243, 245}, + }, + { + {247, 245}, + {244, 246}, + }, + { + {248, 246}, + {245, 247}, + }, + { + {249, 247}, + {246, 248}, + }, + { + {250, 248}, + {247, 249}, + }, + { + {251, 249}, + {248, 250}, + }, + { + {252, 250}, + {249, 251}, + }, + { + {253, 251}, + {250, 252}, + }, + { + {254, 252}, + {251, 253}, + }, + { + {255, 253}, + {252, 254}, + }, + { + {255, 254}, + {253, 255}, + }, + { + {255, 255}, + {254, 255}, + }, +}; + +static const uint8_t dithersub_rb2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {8, 4}, + {2, 6}, + }, + { + {9, 5}, + {3, 7}, + }, + { + {10, 6}, + {4, 8}, + }, + { + {11, 7}, + {5, 9}, + }, + { + {12, 8}, + {6, 10}, + }, + { + {13, 9}, + {7, 11}, + }, + { + {14, 10}, + {8, 12}, + }, + { + {15, 11}, + {9, 13}, + }, + { + {16, 12}, + {10, 14}, + }, + { + {17, 13}, + {11, 15}, + }, + { + {18, 14}, + {12, 16}, + }, + { + {19, 15}, + {13, 17}, + }, + { + {20, 16}, + {14, 18}, + }, + { + {21, 17}, + {15, 19}, + }, + { + {22, 18}, + {16, 20}, + }, + { + {23, 19}, + {17, 21}, + }, + { + {24, 20}, + {18, 22}, + }, + { + {25, 21}, + {19, 23}, + }, + { + {26, 22}, + {20, 24}, + }, + { + {27, 23}, + {21, 25}, + }, + { + {28, 24}, + {22, 26}, + }, + { + {29, 25}, + {23, 27}, + }, + { + {30, 26}, + {24, 28}, + }, + { + {31, 27}, + {25, 29}, + }, + { + {32, 28}, + {26, 30}, + }, + { + {33, 29}, + {27, 31}, + }, + { + {34, 30}, + {28, 32}, + }, + { + {35, 31}, + {29, 33}, + }, + { + {36, 32}, + {30, 34}, + }, + { + {37, 33}, + {31, 35}, + }, + { + {38, 34}, + {32, 36}, + }, + { + {39, 35}, + {33, 37}, + }, + { + {40, 36}, + {34, 38}, + }, + { + {41, 37}, + {35, 39}, + }, + { + {42, 38}, + {36, 40}, + }, + { + {43, 39}, + {37, 41}, + }, + { + {44, 40}, + {38, 42}, + }, + { + {45, 41}, + {39, 43}, + }, + { + {46, 42}, + {40, 44}, + }, + { + {47, 43}, + {41, 45}, + }, + { + {48, 44}, + {42, 46}, + }, + { + {49, 45}, + {43, 47}, + }, + { + {50, 46}, + {44, 48}, + }, + { + {51, 47}, + {45, 49}, + }, + { + {52, 48}, + {46, 50}, + }, + { + {53, 49}, + {47, 51}, + }, + { + {54, 50}, + {48, 52}, + }, + { + {55, 51}, + {49, 53}, + }, + { + {56, 52}, + {50, 54}, + }, + { + {57, 53}, + {51, 55}, + }, + { + {58, 54}, + {52, 56}, + }, + { + {59, 55}, + {53, 57}, + }, + { + {60, 56}, + {54, 58}, + }, + { + {61, 57}, + {55, 59}, + }, + { + {62, 58}, + {56, 60}, + }, + { + {63, 59}, + {57, 61}, + }, + { + {64, 60}, + {58, 62}, + }, + { + {65, 61}, + {59, 63}, + }, + { + {66, 62}, + {60, 64}, + }, + { + {67, 63}, + {61, 65}, + }, + { + {68, 64}, + {62, 66}, + }, + { + {69, 65}, + {63, 67}, + }, + { + {70, 66}, + {64, 68}, + }, + { + {71, 67}, + {65, 69}, + }, + { + {72, 68}, + {66, 70}, + }, + { + {73, 69}, + {67, 71}, + }, + { + {74, 70}, + {68, 72}, + }, + { + {75, 71}, + {69, 73}, + }, + { + {76, 72}, + {70, 74}, + }, + { + {77, 73}, + {71, 75}, + }, + { + {78, 74}, + {72, 76}, + }, + { + {79, 75}, + {73, 77}, + }, + { + {80, 76}, + {74, 78}, + }, + { + {81, 77}, + {75, 79}, + }, + { + {82, 78}, + {76, 80}, + }, + { + {83, 79}, + {77, 81}, + }, + { + {84, 80}, + {78, 82}, + }, + { + {85, 81}, + {79, 83}, + }, + { + {86, 82}, + {80, 84}, + }, + { + {87, 83}, + {81, 85}, + }, + { + {88, 84}, + {82, 86}, + }, + { + {89, 85}, + {83, 87}, + }, + { + {90, 86}, + {84, 88}, + }, + { + {91, 87}, + {85, 89}, + }, + { + {92, 88}, + {86, 90}, + }, + { + {93, 89}, + {87, 91}, + }, + { + {94, 90}, + {88, 92}, + }, + { + {95, 91}, + {89, 93}, + }, + { + {96, 92}, + {90, 94}, + }, + { + {97, 93}, + {91, 95}, + }, + { + {98, 94}, + {92, 96}, + }, + { + {99, 95}, + {93, 97}, + }, + { + {100, 96}, + {94, 98}, + }, + { + {101, 97}, + {95, 99}, + }, + { + {102, 98}, + {96, 100}, + }, + { + {103, 99}, + {97, 101}, + }, + { + {104, 100}, + {98, 102}, + }, + { + {105, 101}, + {99, 103}, + }, + { + {106, 102}, + {100, 104}, + }, + { + {107, 103}, + {101, 105}, + }, + { + {108, 104}, + {102, 106}, + }, + { + {109, 105}, + {103, 107}, + }, + { + {110, 106}, + {104, 108}, + }, + { + {111, 107}, + {105, 109}, + }, + { + {112, 108}, + {106, 110}, + }, + { + {113, 109}, + {107, 111}, + }, + { + {114, 110}, + {108, 112}, + }, + { + {115, 111}, + {109, 113}, + }, + { + {116, 112}, + {110, 114}, + }, + { + {117, 113}, + {111, 115}, + }, + { + {118, 114}, + {112, 116}, + }, + { + {119, 115}, + {113, 117}, + }, + { + {120, 116}, + {114, 118}, + }, + { + {121, 117}, + {115, 119}, + }, + { + {122, 118}, + {116, 120}, + }, + { + {123, 119}, + {117, 121}, + }, + { + {124, 120}, + {118, 122}, + }, + { + {125, 121}, + {119, 123}, + }, + { + {126, 122}, + {120, 124}, + }, + { + {127, 123}, + {121, 125}, + }, + { + {128, 124}, + {122, 126}, + }, + { + {129, 125}, + {123, 127}, + }, + { + {130, 126}, + {124, 128}, + }, + { + {131, 127}, + {125, 129}, + }, + { + {132, 128}, + {126, 130}, + }, + { + {133, 129}, + {127, 131}, + }, + { + {134, 130}, + {128, 132}, + }, + { + {135, 131}, + {129, 133}, + }, + { + {136, 132}, + {130, 134}, + }, + { + {137, 133}, + {131, 135}, + }, + { + {138, 134}, + {132, 136}, + }, + { + {139, 135}, + {133, 137}, + }, + { + {140, 136}, + {134, 138}, + }, + { + {141, 137}, + {135, 139}, + }, + { + {142, 138}, + {136, 140}, + }, + { + {143, 139}, + {137, 141}, + }, + { + {144, 140}, + {138, 142}, + }, + { + {145, 141}, + {139, 143}, + }, + { + {146, 142}, + {140, 144}, + }, + { + {147, 143}, + {141, 145}, + }, + { + {148, 144}, + {142, 146}, + }, + { + {149, 145}, + {143, 147}, + }, + { + {150, 146}, + {144, 148}, + }, + { + {151, 147}, + {145, 149}, + }, + { + {152, 148}, + {146, 150}, + }, + { + {153, 149}, + {147, 151}, + }, + { + {154, 150}, + {148, 152}, + }, + { + {155, 151}, + {149, 153}, + }, + { + {156, 152}, + {150, 154}, + }, + { + {157, 153}, + {151, 155}, + }, + { + {158, 154}, + {152, 156}, + }, + { + {159, 155}, + {153, 157}, + }, + { + {160, 156}, + {154, 158}, + }, + { + {161, 157}, + {155, 159}, + }, + { + {162, 158}, + {156, 160}, + }, + { + {163, 159}, + {157, 161}, + }, + { + {164, 160}, + {158, 162}, + }, + { + {165, 161}, + {159, 163}, + }, + { + {166, 162}, + {160, 164}, + }, + { + {167, 163}, + {161, 165}, + }, + { + {168, 164}, + {162, 166}, + }, + { + {169, 165}, + {163, 167}, + }, + { + {170, 166}, + {164, 168}, + }, + { + {171, 167}, + {165, 169}, + }, + { + {172, 168}, + {166, 170}, + }, + { + {173, 169}, + {167, 171}, + }, + { + {174, 170}, + {168, 172}, + }, + { + {175, 171}, + {169, 173}, + }, + { + {176, 172}, + {170, 174}, + }, + { + {177, 173}, + {171, 175}, + }, + { + {178, 174}, + {172, 176}, + }, + { + {179, 175}, + {173, 177}, + }, + { + {180, 176}, + {174, 178}, + }, + { + {181, 177}, + {175, 179}, + }, + { + {182, 178}, + {176, 180}, + }, + { + {183, 179}, + {177, 181}, + }, + { + {184, 180}, + {178, 182}, + }, + { + {185, 181}, + {179, 183}, + }, + { + {186, 182}, + {180, 184}, + }, + { + {187, 183}, + {181, 185}, + }, + { + {188, 184}, + {182, 186}, + }, + { + {189, 185}, + {183, 187}, + }, + { + {190, 186}, + {184, 188}, + }, + { + {191, 187}, + {185, 189}, + }, + { + {192, 188}, + {186, 190}, + }, + { + {193, 189}, + {187, 191}, + }, + { + {194, 190}, + {188, 192}, + }, + { + {195, 191}, + {189, 193}, + }, + { + {196, 192}, + {190, 194}, + }, + { + {197, 193}, + {191, 195}, + }, + { + {198, 194}, + {192, 196}, + }, + { + {199, 195}, + {193, 197}, + }, + { + {200, 196}, + {194, 198}, + }, + { + {201, 197}, + {195, 199}, + }, + { + {202, 198}, + {196, 200}, + }, + { + {203, 199}, + {197, 201}, + }, + { + {204, 200}, + {198, 202}, + }, + { + {205, 201}, + {199, 203}, + }, + { + {206, 202}, + {200, 204}, + }, + { + {207, 203}, + {201, 205}, + }, + { + {208, 204}, + {202, 206}, + }, + { + {209, 205}, + {203, 207}, + }, + { + {210, 206}, + {204, 208}, + }, + { + {211, 207}, + {205, 209}, + }, + { + {212, 208}, + {206, 210}, + }, + { + {213, 209}, + {207, 211}, + }, + { + {214, 210}, + {208, 212}, + }, + { + {215, 211}, + {209, 213}, + }, + { + {216, 212}, + {210, 214}, + }, + { + {217, 213}, + {211, 215}, + }, + { + {218, 214}, + {212, 216}, + }, + { + {219, 215}, + {213, 217}, + }, + { + {220, 216}, + {214, 218}, + }, + { + {221, 217}, + {215, 219}, + }, + { + {222, 218}, + {216, 220}, + }, + { + {223, 219}, + {217, 221}, + }, + { + {224, 220}, + {218, 222}, + }, + { + {225, 221}, + {219, 223}, + }, + { + {226, 222}, + {220, 224}, + }, + { + {227, 223}, + {221, 225}, + }, + { + {228, 224}, + {222, 226}, + }, + { + {229, 225}, + {223, 227}, + }, + { + {230, 226}, + {224, 228}, + }, + { + {231, 227}, + {225, 229}, + }, + { + {232, 228}, + {226, 230}, + }, + { + {233, 229}, + {227, 231}, + }, + { + {234, 230}, + {228, 232}, + }, + { + {235, 231}, + {229, 233}, + }, + { + {236, 232}, + {230, 234}, + }, + { + {237, 233}, + {231, 235}, + }, + { + {238, 234}, + {232, 236}, + }, + { + {239, 235}, + {233, 237}, + }, + { + {240, 236}, + {234, 238}, + }, + { + {241, 237}, + {235, 239}, + }, + { + {242, 238}, + {236, 240}, + }, + { + {243, 239}, + {237, 241}, + }, + { + {244, 240}, + {238, 242}, + }, + { + {245, 241}, + {239, 243}, + }, + { + {246, 242}, + {240, 244}, + }, + { + {247, 243}, + {241, 245}, + }, + { + {248, 244}, + {242, 246}, + }, + { + {249, 245}, + {243, 247}, + }, + { + {250, 246}, + {244, 248}, + }, + { + {251, 247}, + {245, 249}, + }, + { + {252, 248}, + {246, 250}, + }, + { + {253, 249}, + {247, 251}, + }, + { + {254, 250}, + {248, 252}, + }, + { + {255, 251}, + {249, 253}, + }, + { + {255, 252}, + {250, 254}, + }, + { + {255, 253}, + {251, 255}, + }, + { + {255, 254}, + {252, 255}, + }, + { + {255, 255}, + {253, 255}, + }, +}; + +#endif /* VIDEO_VOODOO_DITHER_H*/ diff --git a/src/include/86box/vid_voodoo_fb.h b/src/include/86box/vid_voodoo_fb.h new file mode 100644 index 000000000..6acf624aa --- /dev/null +++ b/src/include/86box/vid_voodoo_fb.h @@ -0,0 +1,27 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_FB_H +# define VIDEO_VOODOO_FB_H + +uint16_t voodoo_fb_readw(uint32_t addr, void *p); +uint32_t voodoo_fb_readl(uint32_t addr, void *p); +void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p); +void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p); + +#endif /*VIDEO_VOODOO_FB_H*/ diff --git a/src/include/86box/vid_voodoo_fifo.h b/src/include/86box/vid_voodoo_fifo.h new file mode 100644 index 000000000..54b6567e8 --- /dev/null +++ b/src/include/86box/vid_voodoo_fifo.h @@ -0,0 +1,31 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_FIFO_H +# define VIDEO_VOODOO_FIFO_H + +void voodoo_wake_fifo_thread(voodoo_t *voodoo); +void voodoo_wake_fifo_thread_now(voodoo_t *voodoo); +void voodoo_wake_timer(void *p); +void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val); +void voodoo_flush(voodoo_t *voodoo); +void voodoo_wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo); +void voodoo_wait_for_swap_complete(voodoo_t *voodoo); +void voodoo_fifo_thread(void *param); + +#endif /*VIDEO_VOODOO_FIFO_H*/ diff --git a/src/include/86box/vid_voodoo_reg.h b/src/include/86box/vid_voodoo_reg.h new file mode 100644 index 000000000..c535c7a18 --- /dev/null +++ b/src/include/86box/vid_voodoo_reg.h @@ -0,0 +1,24 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_REG_H +# define VIDEO_VOODOO_REG_H + +void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p); + +#endif /*VIDEO_VOODOO_REG_H*/ diff --git a/src/include/86box/vid_voodoo_regs.h b/src/include/86box/vid_voodoo_regs.h new file mode 100644 index 000000000..2f488fabd --- /dev/null +++ b/src/include/86box/vid_voodoo_regs.h @@ -0,0 +1,698 @@ +#ifndef VIDEO_VOODOO_REGS_H +# define VIDEO_VOODOO_REGS_H + +enum +{ + SST_status = 0x000, + SST_intrCtrl = 0x004, + + SST_vertexAx = 0x008, + SST_vertexAy = 0x00c, + SST_vertexBx = 0x010, + SST_vertexBy = 0x014, + SST_vertexCx = 0x018, + SST_vertexCy = 0x01c, + + SST_startR = 0x0020, + SST_startG = 0x0024, + SST_startB = 0x0028, + SST_startZ = 0x002c, + SST_startA = 0x0030, + SST_startS = 0x0034, + SST_startT = 0x0038, + SST_startW = 0x003c, + + SST_dRdX = 0x0040, + SST_dGdX = 0x0044, + SST_dBdX = 0x0048, + SST_dZdX = 0x004c, + SST_dAdX = 0x0050, + SST_dSdX = 0x0054, + SST_dTdX = 0x0058, + SST_dWdX = 0x005c, + + SST_dRdY = 0x0060, + SST_dGdY = 0x0064, + SST_dBdY = 0x0068, + SST_dZdY = 0x006c, + SST_dAdY = 0x0070, + SST_dSdY = 0x0074, + SST_dTdY = 0x0078, + SST_dWdY = 0x007c, + + SST_triangleCMD = 0x0080, + + SST_fvertexAx = 0x088, + SST_fvertexAy = 0x08c, + SST_fvertexBx = 0x090, + SST_fvertexBy = 0x094, + SST_fvertexCx = 0x098, + SST_fvertexCy = 0x09c, + + SST_fstartR = 0x00a0, + SST_fstartG = 0x00a4, + SST_fstartB = 0x00a8, + SST_fstartZ = 0x00ac, + SST_fstartA = 0x00b0, + SST_fstartS = 0x00b4, + SST_fstartT = 0x00b8, + SST_fstartW = 0x00bc, + + SST_fdRdX = 0x00c0, + SST_fdGdX = 0x00c4, + SST_fdBdX = 0x00c8, + SST_fdZdX = 0x00cc, + SST_fdAdX = 0x00d0, + SST_fdSdX = 0x00d4, + SST_fdTdX = 0x00d8, + SST_fdWdX = 0x00dc, + + SST_fdRdY = 0x00e0, + SST_fdGdY = 0x00e4, + SST_fdBdY = 0x00e8, + SST_fdZdY = 0x00ec, + SST_fdAdY = 0x00f0, + SST_fdSdY = 0x00f4, + SST_fdTdY = 0x00f8, + SST_fdWdY = 0x00fc, + + SST_ftriangleCMD = 0x0100, + + SST_fbzColorPath = 0x104, + SST_fogMode = 0x108, + + SST_alphaMode = 0x10c, + SST_fbzMode = 0x110, + SST_lfbMode = 0x114, + + SST_clipLeftRight = 0x118, + SST_clipLowYHighY = 0x11c, + + SST_nopCMD = 0x120, + SST_fastfillCMD = 0x124, + SST_swapbufferCMD = 0x128, + + SST_fogColor = 0x12c, + SST_zaColor = 0x130, + SST_chromaKey = 0x134, + + SST_userIntrCMD = 0x13c, + SST_stipple = 0x140, + SST_color0 = 0x144, + SST_color1 = 0x148, + + SST_fbiPixelsIn = 0x14c, + SST_fbiChromaFail = 0x150, + SST_fbiZFuncFail = 0x154, + SST_fbiAFuncFail = 0x158, + SST_fbiPixelsOut = 0x15c, + + SST_fogTable00 = 0x160, + SST_fogTable01 = 0x164, + SST_fogTable02 = 0x168, + SST_fogTable03 = 0x16c, + SST_fogTable04 = 0x170, + SST_fogTable05 = 0x174, + SST_fogTable06 = 0x178, + SST_fogTable07 = 0x17c, + SST_fogTable08 = 0x180, + SST_fogTable09 = 0x184, + SST_fogTable0a = 0x188, + SST_fogTable0b = 0x18c, + SST_fogTable0c = 0x190, + SST_fogTable0d = 0x194, + SST_fogTable0e = 0x198, + SST_fogTable0f = 0x19c, + SST_fogTable10 = 0x1a0, + SST_fogTable11 = 0x1a4, + SST_fogTable12 = 0x1a8, + SST_fogTable13 = 0x1ac, + SST_fogTable14 = 0x1b0, + SST_fogTable15 = 0x1b4, + SST_fogTable16 = 0x1b8, + SST_fogTable17 = 0x1bc, + SST_fogTable18 = 0x1c0, + SST_fogTable19 = 0x1c4, + SST_fogTable1a = 0x1c8, + SST_fogTable1b = 0x1cc, + SST_fogTable1c = 0x1d0, + SST_fogTable1d = 0x1d4, + SST_fogTable1e = 0x1d8, + SST_fogTable1f = 0x1dc, + + SST_cmdFifoBaseAddr = 0x1e0, + SST_cmdFifoBump = 0x1e4, + SST_cmdFifoRdPtr = 0x1e8, + SST_cmdFifoAMin = 0x1ec, + SST_cmdFifoAMax = 0x1f0, + SST_cmdFifoDepth = 0x1f4, + SST_cmdFifoHoles = 0x1f8, + + SST_colBufferAddr = 0x1ec, /*Banshee*/ + SST_colBufferStride = 0x1f0, /*Banshee*/ + SST_auxBufferAddr = 0x1f4, /*Banshee*/ + SST_auxBufferStride = 0x1f8, /*Banshee*/ + + SST_clipLeftRight1 = 0x200, /*Banshee*/ + SST_clipTopBottom1 = 0x204, /*Banshee*/ + + SST_fbiInit4 = 0x200, + SST_vRetrace = 0x204, + SST_backPorch = 0x208, + SST_videoDimensions = 0x20c, + SST_fbiInit0 = 0x210, + SST_fbiInit1 = 0x214, + SST_fbiInit2 = 0x218, + SST_fbiInit3 = 0x21c, + SST_hSync = 0x220, + SST_vSync = 0x224, + SST_clutData = 0x228, + SST_dacData = 0x22c, + + SST_scrFilter = 0x230, + + SST_hvRetrace = 0x240, + SST_fbiInit5 = 0x244, + SST_fbiInit6 = 0x248, + SST_fbiInit7 = 0x24c, + + SST_swapPending = 0x24c, /*Banshee*/ + SST_leftOverlayBuf = 0x250, /*Banshee*/ + + SST_sSetupMode = 0x260, + SST_sVx = 0x264, + SST_sVy = 0x268, + SST_sARGB = 0x26c, + SST_sRed = 0x270, + SST_sGreen = 0x274, + SST_sBlue = 0x278, + SST_sAlpha = 0x27c, + SST_sVz = 0x280, + SST_sWb = 0x284, + SST_sW0 = 0x288, + SST_sS0 = 0x28c, + SST_sT0 = 0x290, + SST_sW1 = 0x294, + SST_sS1 = 0x298, + SST_sT1 = 0x29c, + + SST_sDrawTriCMD = 0x2a0, + SST_sBeginTriCMD = 0x2a4, + + SST_bltSrcBaseAddr = 0x2c0, + SST_bltDstBaseAddr = 0x2c4, + SST_bltXYStrides = 0x2c8, + SST_bltSrcChromaRange = 0x2cc, + SST_bltDstChromaRange = 0x2d0, + SST_bltClipX = 0x2d4, + SST_bltClipY = 0x2d8, + + SST_bltSrcXY = 0x2e0, + SST_bltDstXY = 0x2e4, + SST_bltSize = 0x2e8, + SST_bltRop = 0x2ec, + SST_bltColor = 0x2f0, + + SST_bltCommand = 0x2f8, + SST_bltData = 0x2fc, + + SST_textureMode = 0x300, + SST_tLOD = 0x304, + SST_tDetail = 0x308, + SST_texBaseAddr = 0x30c, + SST_texBaseAddr1 = 0x310, + SST_texBaseAddr2 = 0x314, + SST_texBaseAddr38 = 0x318, + + SST_trexInit1 = 0x320, + + SST_nccTable0_Y0 = 0x324, + SST_nccTable0_Y1 = 0x328, + SST_nccTable0_Y2 = 0x32c, + SST_nccTable0_Y3 = 0x330, + SST_nccTable0_I0 = 0x334, + SST_nccTable0_I1 = 0x338, + SST_nccTable0_I2 = 0x33c, + SST_nccTable0_I3 = 0x340, + SST_nccTable0_Q0 = 0x344, + SST_nccTable0_Q1 = 0x348, + SST_nccTable0_Q2 = 0x34c, + SST_nccTable0_Q3 = 0x350, + + SST_nccTable1_Y0 = 0x354, + SST_nccTable1_Y1 = 0x358, + SST_nccTable1_Y2 = 0x35c, + SST_nccTable1_Y3 = 0x360, + SST_nccTable1_I0 = 0x364, + SST_nccTable1_I1 = 0x368, + SST_nccTable1_I2 = 0x36c, + SST_nccTable1_I3 = 0x370, + SST_nccTable1_Q0 = 0x374, + SST_nccTable1_Q1 = 0x378, + SST_nccTable1_Q2 = 0x37c, + SST_nccTable1_Q3 = 0x380, + + SST_remap_status = 0x000 | 0x400, + + SST_remap_vertexAx = 0x008 | 0x400, + SST_remap_vertexAy = 0x00c | 0x400, + SST_remap_vertexBx = 0x010 | 0x400, + SST_remap_vertexBy = 0x014 | 0x400, + SST_remap_vertexCx = 0x018 | 0x400, + SST_remap_vertexCy = 0x01c | 0x400, + + SST_remap_startR = 0x0020 | 0x400, + SST_remap_startG = 0x002c | 0x400, + SST_remap_startB = 0x0038 | 0x400, + SST_remap_startZ = 0x0044 | 0x400, + SST_remap_startA = 0x0050 | 0x400, + SST_remap_startS = 0x005c | 0x400, + SST_remap_startT = 0x0068 | 0x400, + SST_remap_startW = 0x0074 | 0x400, + + SST_remap_dRdX = 0x0024 | 0x400, + SST_remap_dGdX = 0x0030 | 0x400, + SST_remap_dBdX = 0x003c | 0x400, + SST_remap_dZdX = 0x0048 | 0x400, + SST_remap_dAdX = 0x0054 | 0x400, + SST_remap_dSdX = 0x0060 | 0x400, + SST_remap_dTdX = 0x006c | 0x400, + SST_remap_dWdX = 0x0078 | 0x400, + + SST_remap_dRdY = 0x0028 | 0x400, + SST_remap_dGdY = 0x0034 | 0x400, + SST_remap_dBdY = 0x0040 | 0x400, + SST_remap_dZdY = 0x004c | 0x400, + SST_remap_dAdY = 0x0058 | 0x400, + SST_remap_dSdY = 0x0064 | 0x400, + SST_remap_dTdY = 0x0070 | 0x400, + SST_remap_dWdY = 0x007c | 0x400, + + SST_remap_triangleCMD = 0x0080 | 0x400, + + SST_remap_fvertexAx = 0x088 | 0x400, + SST_remap_fvertexAy = 0x08c | 0x400, + SST_remap_fvertexBx = 0x090 | 0x400, + SST_remap_fvertexBy = 0x094 | 0x400, + SST_remap_fvertexCx = 0x098 | 0x400, + SST_remap_fvertexCy = 0x09c | 0x400, + + SST_remap_fstartR = 0x00a0 | 0x400, + SST_remap_fstartG = 0x00ac | 0x400, + SST_remap_fstartB = 0x00b8 | 0x400, + SST_remap_fstartZ = 0x00c4 | 0x400, + SST_remap_fstartA = 0x00d0 | 0x400, + SST_remap_fstartS = 0x00dc | 0x400, + SST_remap_fstartT = 0x00e8 | 0x400, + SST_remap_fstartW = 0x00f4 | 0x400, + + SST_remap_fdRdX = 0x00a4 | 0x400, + SST_remap_fdGdX = 0x00b0 | 0x400, + SST_remap_fdBdX = 0x00bc | 0x400, + SST_remap_fdZdX = 0x00c8 | 0x400, + SST_remap_fdAdX = 0x00d4 | 0x400, + SST_remap_fdSdX = 0x00e0 | 0x400, + SST_remap_fdTdX = 0x00ec | 0x400, + SST_remap_fdWdX = 0x00f8 | 0x400, + + SST_remap_fdRdY = 0x00a8 | 0x400, + SST_remap_fdGdY = 0x00b4 | 0x400, + SST_remap_fdBdY = 0x00c0 | 0x400, + SST_remap_fdZdY = 0x00cc | 0x400, + SST_remap_fdAdY = 0x00d8 | 0x400, + SST_remap_fdSdY = 0x00e4 | 0x400, + SST_remap_fdTdY = 0x00f0 | 0x400, + SST_remap_fdWdY = 0x00fc | 0x400, +}; + +enum +{ + LFB_WRITE_FRONT = 0x0000, + LFB_WRITE_BACK = 0x0010, + LFB_WRITE_MASK = 0x0030 +}; + +enum +{ + LFB_READ_FRONT = 0x0000, + LFB_READ_BACK = 0x0040, + LFB_READ_AUX = 0x0080, + LFB_READ_MASK = 0x00c0 +}; + +enum +{ + LFB_FORMAT_RGB565 = 0, + LFB_FORMAT_RGB555 = 1, + LFB_FORMAT_ARGB1555 = 2, + LFB_FORMAT_ARGB8888 = 5, + LFB_FORMAT_DEPTH = 15, + LFB_FORMAT_MASK = 15 +}; + +enum +{ + LFB_WRITE_COLOUR = 1, + LFB_WRITE_DEPTH = 2 +}; + +enum +{ + FBZ_CHROMAKEY = (1 << 1), + FBZ_W_BUFFER = (1 << 3), + FBZ_DEPTH_ENABLE = (1 << 4), + + FBZ_DITHER = (1 << 8), + FBZ_RGB_WMASK = (1 << 9), + FBZ_DEPTH_WMASK = (1 << 10), + FBZ_DITHER_2x2 = (1 << 11), + + FBZ_DRAW_FRONT = 0x0000, + FBZ_DRAW_BACK = 0x4000, + FBZ_DRAW_MASK = 0xc000, + + FBZ_DEPTH_BIAS = (1 << 16), + FBZ_DITHER_SUB = (1 << 19), + + FBZ_DEPTH_SOURCE = (1 << 20), + + FBZ_PARAM_ADJUST = (1 << 26) +}; + +enum +{ + TEX_RGB332 = 0x0, + TEX_Y4I2Q2 = 0x1, + TEX_A8 = 0x2, + TEX_I8 = 0x3, + TEX_AI8 = 0x4, + TEX_PAL8 = 0x5, + TEX_APAL8 = 0x6, + TEX_ARGB8332 = 0x8, + TEX_A8Y4I2Q2 = 0x9, + TEX_R5G6B5 = 0xa, + TEX_ARGB1555 = 0xb, + TEX_ARGB4444 = 0xc, + TEX_A8I8 = 0xd, + TEX_APAL88 = 0xe +}; + +enum +{ + TEXTUREMODE_NCC_SEL = (1 << 5), + TEXTUREMODE_TCLAMPS = (1 << 6), + TEXTUREMODE_TCLAMPT = (1 << 7), + TEXTUREMODE_TRILINEAR = (1 << 30) +}; + +enum +{ + FBIINIT0_VGA_PASS = 1, + FBIINIT0_GRAPHICS_RESET = (1 << 1) +}; + +enum +{ + FBIINIT1_MULTI_SST = (1 << 2), /*Voodoo Graphics only*/ + FBIINIT1_VIDEO_RESET = (1 << 8), + FBIINIT1_SLI_ENABLE = (1 << 23) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_MASK = (3 << 9) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_DAC_VSYNC = (0 << 9), + FBIINIT2_SWAP_ALGORITHM_DAC_DATA = (1 << 9), + FBIINIT2_SWAP_ALGORITHM_PCI_FIFO_STALL = (2 << 9), + FBIINIT2_SWAP_ALGORITHM_SLI_SYNC = (3 << 9) +}; + +enum +{ + FBIINIT3_REMAP = 1 +}; + +enum +{ + FBIINIT5_MULTI_CVG = (1 << 14) +}; + +enum +{ + FBIINIT7_CMDFIFO_ENABLE = (1 << 8) +}; + +enum +{ + CC_LOCALSELECT_ITER_RGB = 0, + CC_LOCALSELECT_TEX = 1, + CC_LOCALSELECT_COLOR1 = 2, + CC_LOCALSELECT_LFB = 3 +}; + +enum +{ + CCA_LOCALSELECT_ITER_A = 0, + CCA_LOCALSELECT_COLOR0 = 1, + CCA_LOCALSELECT_ITER_Z = 2 +}; + +enum +{ + C_SEL_ITER_RGB = 0, + C_SEL_TEX = 1, + C_SEL_COLOR1 = 2, + C_SEL_LFB = 3 +}; + +enum +{ + A_SEL_ITER_A = 0, + A_SEL_TEX = 1, + A_SEL_COLOR1 = 2, + A_SEL_LFB = 3 +}; + +enum +{ + CC_MSELECT_ZERO = 0, + CC_MSELECT_CLOCAL = 1, + CC_MSELECT_AOTHER = 2, + CC_MSELECT_ALOCAL = 3, + CC_MSELECT_TEX = 4, + CC_MSELECT_TEXRGB = 5 +}; + +enum +{ + CCA_MSELECT_ZERO = 0, + CCA_MSELECT_ALOCAL = 1, + CCA_MSELECT_AOTHER = 2, + CCA_MSELECT_ALOCAL2 = 3, + CCA_MSELECT_TEX = 4 +}; + +enum +{ + TC_MSELECT_ZERO = 0, + TC_MSELECT_CLOCAL = 1, + TC_MSELECT_AOTHER = 2, + TC_MSELECT_ALOCAL = 3, + TC_MSELECT_DETAIL = 4, + TC_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + TCA_MSELECT_ZERO = 0, + TCA_MSELECT_CLOCAL = 1, + TCA_MSELECT_AOTHER = 2, + TCA_MSELECT_ALOCAL = 3, + TCA_MSELECT_DETAIL = 4, + TCA_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + CC_ADD_CLOCAL = 1, + CC_ADD_ALOCAL = 2 +}; + +enum +{ + CCA_ADD_CLOCAL = 1, + CCA_ADD_ALOCAL = 2 +}; + +enum +{ + AFUNC_AZERO = 0x0, + AFUNC_ASRC_ALPHA = 0x1, + AFUNC_A_COLOR = 0x2, + AFUNC_ADST_ALPHA = 0x3, + AFUNC_AONE = 0x4, + AFUNC_AOMSRC_ALPHA = 0x5, + AFUNC_AOM_COLOR = 0x6, + AFUNC_AOMDST_ALPHA = 0x7, + AFUNC_ASATURATE = 0xf +}; + +enum +{ + AFUNC_ACOLORBEFOREFOG = 0xf +}; + +enum +{ + AFUNC_NEVER = 0, + AFUNC_LESSTHAN = 1, + AFUNC_EQUAL = 2, + AFUNC_LESSTHANEQUAL = 3, + AFUNC_GREATERTHAN = 4, + AFUNC_NOTEQUAL = 5, + AFUNC_GREATERTHANEQUAL = 6, + AFUNC_ALWAYS = 7 +}; + +enum +{ + DEPTHOP_NEVER = 0, + DEPTHOP_LESSTHAN = 1, + DEPTHOP_EQUAL = 2, + DEPTHOP_LESSTHANEQUAL = 3, + DEPTHOP_GREATERTHAN = 4, + DEPTHOP_NOTEQUAL = 5, + DEPTHOP_GREATERTHANEQUAL = 6, + DEPTHOP_ALWAYS = 7 +}; + +enum +{ + FOG_ENABLE = 0x01, + FOG_ADD = 0x02, + FOG_MULT = 0x04, + FOG_ALPHA = 0x08, + FOG_Z = 0x10, + FOG_W = 0x18, + FOG_CONSTANT = 0x20 +}; + +enum +{ + LOD_ODD = (1 << 18), + LOD_SPLIT = (1 << 19), + LOD_S_IS_WIDER = (1 << 20), + LOD_TMULTIBASEADDR = (1 << 24), + LOD_TMIRROR_S = (1 << 28), + LOD_TMIRROR_T = (1 << 29) +}; +enum +{ + CMD_INVALID = 0, + CMD_DRAWTRIANGLE, + CMD_FASTFILL, + CMD_SWAPBUF +}; + +enum +{ + FBZCP_TEXTURE_ENABLED = (1 << 27) +}; + +enum +{ + BLTCMD_SRC_TILED = (1 << 14), + BLTCMD_DST_TILED = (1 << 15) +}; + +enum +{ + INITENABLE_SLI_MASTER_SLAVE = (1 << 11) +}; + +enum +{ + SETUPMODE_RGB = (1 << 0), + SETUPMODE_ALPHA = (1 << 1), + SETUPMODE_Z = (1 << 2), + SETUPMODE_Wb = (1 << 3), + SETUPMODE_W0 = (1 << 4), + SETUPMODE_S0_T0 = (1 << 5), + SETUPMODE_W1 = (1 << 6), + SETUPMODE_S1_T1 = (1 << 7), + + SETUPMODE_STRIP_MODE = (1 << 16), + SETUPMODE_CULLING_ENABLE = (1 << 17), + SETUPMODE_CULLING_SIGN = (1 << 18), + SETUPMODE_DISABLE_PINGPONG = (1 << 19) +}; + +#define TEXTUREMODE_MASK 0x3ffff000 +#define TEXTUREMODE_PASSTHROUGH 0 + +#define TEXTUREMODE_LOCAL_MASK 0x00643000 +#define TEXTUREMODE_LOCAL 0x00241000 + + +#define SLI_ENABLED (voodoo->fbiInit1 & FBIINIT1_SLI_ENABLE) +#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400) + + +#define _rgb_sel ( params->fbzColorPath & 3) +#define a_sel ( (params->fbzColorPath >> 2) & 3) +#define cc_localselect ( params->fbzColorPath & (1 << 4)) +#define cca_localselect ( (params->fbzColorPath >> 5) & 3) +#define cc_localselect_override ( params->fbzColorPath & (1 << 7)) +#define cc_zero_other ( params->fbzColorPath & (1 << 8)) +#define cc_sub_clocal ( params->fbzColorPath & (1 << 9)) +#define cc_mselect ( (params->fbzColorPath >> 10) & 7) +#define cc_reverse_blend ( params->fbzColorPath & (1 << 13)) +#define cc_add ( (params->fbzColorPath >> 14) & 3) +#define cc_add_alocal ( params->fbzColorPath & (1 << 15)) +#define cc_invert_output ( params->fbzColorPath & (1 << 16)) +#define cca_zero_other ( params->fbzColorPath & (1 << 17)) +#define cca_sub_clocal ( params->fbzColorPath & (1 << 18)) +#define cca_mselect ( (params->fbzColorPath >> 19) & 7) +#define cca_reverse_blend ( params->fbzColorPath & (1 << 22)) +#define cca_add ( (params->fbzColorPath >> 23) & 3) +#define cca_invert_output ( params->fbzColorPath & (1 << 25)) +#define tc_zero_other (params->textureMode[0] & (1 << 12)) +#define tc_sub_clocal (params->textureMode[0] & (1 << 13)) +#define tc_mselect ((params->textureMode[0] >> 14) & 7) +#define tc_reverse_blend (params->textureMode[0] & (1 << 17)) +#define tc_add_clocal (params->textureMode[0] & (1 << 18)) +#define tc_add_alocal (params->textureMode[0] & (1 << 19)) +#define tc_invert_output (params->textureMode[0] & (1 << 20)) +#define tca_zero_other (params->textureMode[0] & (1 << 21)) +#define tca_sub_clocal (params->textureMode[0] & (1 << 22)) +#define tca_mselect ((params->textureMode[0] >> 23) & 7) +#define tca_reverse_blend (params->textureMode[0] & (1 << 26)) +#define tca_add_clocal (params->textureMode[0] & (1 << 27)) +#define tca_add_alocal (params->textureMode[0] & (1 << 28)) +#define tca_invert_output (params->textureMode[0] & (1 << 29)) + +#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13)) +#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7) +#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17)) +#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18)) +#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19)) +#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22)) +#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7) +#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26)) +#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27)) +#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28)) + +#define src_afunc ( (params->alphaMode >> 8) & 0xf) +#define dest_afunc ( (params->alphaMode >> 12) & 0xf) +#define alpha_func ( (params->alphaMode >> 1) & 7) +#define a_ref ( params->alphaMode >> 24) +#define depth_op ( (params->fbzMode >> 5) & 7) +#define dither ( params->fbzMode & FBZ_DITHER) +#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) +#define dithersub (params->fbzMode & FBZ_DITHER_SUB) + +#endif /*VIDEO_VOODOO_REGS_H*/ diff --git a/src/include/86box/vid_voodoo_render.h b/src/include/86box/vid_voodoo_render.h new file mode 100644 index 000000000..5fb10d231 --- /dev/null +++ b/src/include/86box/vid_voodoo_render.h @@ -0,0 +1,343 @@ +#ifndef VIDEO_VOODOO_RENDER_H +# define VIDEO_VOODOO_RENDER_H + +#if !(defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined __amd64__ || defined _M_X64) +#define NO_CODEGEN +#endif + +#ifndef NO_CODEGEN +void voodoo_codegen_init(voodoo_t *voodoo); +void voodoo_codegen_close(voodoo_t *voodoo); +#endif + +#define DEPTH_TEST(comp_depth) \ + do \ + { \ + switch (depth_op) \ + { \ + case DEPTHOP_NEVER: \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + case DEPTHOP_LESSTHAN: \ + if (!(comp_depth < old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_EQUAL: \ + if (!(comp_depth == old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_LESSTHANEQUAL: \ + if (!(comp_depth <= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHAN: \ + if (!(comp_depth > old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_NOTEQUAL: \ + if (!(comp_depth != old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHANEQUAL: \ + if (!(comp_depth >= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_ALWAYS: \ + break; \ + } \ + } while (0) + +#define APPLY_FOG(src_r, src_g, src_b, z, ia, w) \ + do \ + { \ + if (params->fogMode & FOG_CONSTANT) \ + { \ + src_r += params->fogColor.r; \ + src_g += params->fogColor.g; \ + src_b += params->fogColor.b; \ + } \ + else \ + { \ + int fog_r, fog_g, fog_b, fog_a = 0; \ + int fog_idx; \ + \ + if (!(params->fogMode & FOG_ADD)) \ + { \ + fog_r = params->fogColor.r; \ + fog_g = params->fogColor.g; \ + fog_b = params->fogColor.b; \ + } \ + else \ + fog_r = fog_g = fog_b = 0; \ + \ + if (!(params->fogMode & FOG_MULT)) \ + { \ + fog_r -= src_r; \ + fog_g -= src_g; \ + fog_b -= src_b; \ + } \ + \ + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \ + { \ + case 0: \ + fog_idx = (w_depth >> 10) & 0x3f; \ + \ + fog_a = params->fogTable[fog_idx].fog; \ + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \ + break; \ + case FOG_Z: \ + fog_a = (z >> 20) & 0xff; \ + break; \ + case FOG_ALPHA: \ + fog_a = CLAMP(ia >> 12); \ + break; \ + case FOG_W: \ + fog_a = CLAMP((w >> 32) & 0xff); \ + break; \ + } \ + fog_a++; \ + \ + fog_r = (fog_r * fog_a) >> 8; \ + fog_g = (fog_g * fog_a) >> 8; \ + fog_b = (fog_b * fog_a) >> 8; \ + \ + if (params->fogMode & FOG_MULT) \ + { \ + src_r = fog_r; \ + src_g = fog_g; \ + src_b = fog_b; \ + } \ + else \ + { \ + src_r += fog_r; \ + src_g += fog_g; \ + src_b += fog_b; \ + } \ + } \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while (0) + +#define ALPHA_TEST(src_a) \ + do \ + { \ + switch (alpha_func) \ + { \ + case AFUNC_NEVER: \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + case AFUNC_LESSTHAN: \ + if (!(src_a < a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_EQUAL: \ + if (!(src_a == a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_LESSTHANEQUAL: \ + if (!(src_a <= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHAN: \ + if (!(src_a > a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_NOTEQUAL: \ + if (!(src_a != a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHANEQUAL: \ + if (!(src_a >= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_ALWAYS: \ + break; \ + } \ + } while (0) + +#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \ + do \ + { \ + int _a; \ + int newdest_r = 0, newdest_g = 0, newdest_b = 0; \ + \ + switch (dest_afunc) \ + { \ + case AFUNC_AZERO: \ + newdest_r = newdest_g = newdest_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + newdest_r = (dest_r * src_a) / 255; \ + newdest_g = (dest_g * src_a) / 255; \ + newdest_b = (dest_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + newdest_r = (dest_r * src_r) / 255; \ + newdest_g = (dest_g * src_g) / 255; \ + newdest_b = (dest_b * src_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + newdest_r = (dest_r * dest_a) / 255; \ + newdest_g = (dest_g * dest_a) / 255; \ + newdest_b = (dest_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + newdest_r = dest_r; \ + newdest_g = dest_g; \ + newdest_b = dest_b; \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + newdest_r = (dest_r * (255-src_a)) / 255; \ + newdest_g = (dest_g * (255-src_a)) / 255; \ + newdest_b = (dest_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + newdest_r = (dest_r * (255-src_r)) / 255; \ + newdest_g = (dest_g * (255-src_g)) / 255; \ + newdest_b = (dest_b * (255-src_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + newdest_r = (dest_r * (255-dest_a)) / 255; \ + newdest_g = (dest_g * (255-dest_a)) / 255; \ + newdest_b = (dest_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ASATURATE: \ + _a = MIN(src_a, 1-dest_a); \ + newdest_r = (dest_r * _a) / 255; \ + newdest_g = (dest_g * _a) / 255; \ + newdest_b = (dest_b * _a) / 255; \ + break; \ + } \ + \ + switch (src_afunc) \ + { \ + case AFUNC_AZERO: \ + src_r = src_g = src_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + src_r = (src_r * src_a) / 255; \ + src_g = (src_g * src_a) / 255; \ + src_b = (src_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + src_r = (src_r * dest_r) / 255; \ + src_g = (src_g * dest_g) / 255; \ + src_b = (src_b * dest_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + src_r = (src_r * dest_a) / 255; \ + src_g = (src_g * dest_a) / 255; \ + src_b = (src_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + src_r = (src_r * (255-src_a)) / 255; \ + src_g = (src_g * (255-src_a)) / 255; \ + src_b = (src_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + src_r = (src_r * (255-dest_r)) / 255; \ + src_g = (src_g * (255-dest_g)) / 255; \ + src_b = (src_b * (255-dest_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + src_r = (src_r * (255-dest_a)) / 255; \ + src_g = (src_g * (255-dest_a)) / 255; \ + src_b = (src_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ACOLORBEFOREFOG: \ + fatal("AFUNC_ACOLORBEFOREFOG\n"); \ + break; \ + } \ + \ + src_r += newdest_r; \ + src_g += newdest_g; \ + src_b += newdest_b; \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while(0) + + + +void voodoo_render_thread_1(void *param); +void voodoo_render_thread_2(void *param); +void voodoo_render_thread_3(void *param); +void voodoo_render_thread_4(void *param); +void voodoo_queue_triangle(voodoo_t *voodoo, voodoo_params_t *params); + +extern int voodoo_recomp; +extern int tris; + +static __inline void voodoo_wake_render_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/ + if (voodoo->render_threads >= 2) + thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/ + if (voodoo->render_threads == 4) + { + thread_set_event(voodoo->wake_render_thread[2]); /*Wake up render thread if moving from idle*/ + thread_set_event(voodoo->wake_render_thread[3]); /*Wake up render thread if moving from idle*/ + } +} + +static __inline void voodoo_wait_for_render_thread_idle(voodoo_t *voodoo) +{ + while (!PARAM_EMPTY(0) || (voodoo->render_threads >= 2 && !PARAM_EMPTY(1)) || + (voodoo->render_threads == 4 && (!PARAM_EMPTY(2) || !PARAM_EMPTY(3))) || + voodoo->render_voodoo_busy[0] || (voodoo->render_threads >= 2 && voodoo->render_voodoo_busy[1]) || + (voodoo->render_threads == 4 && (voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3]))) + { + voodoo_wake_render_thread(voodoo); + if (!PARAM_EMPTY(0) || voodoo->render_voodoo_busy[0]) + thread_wait_event(voodoo->render_not_full_event[0], 1); + if (voodoo->render_threads >= 2 && (!PARAM_EMPTY(1) || voodoo->render_voodoo_busy[1])) + thread_wait_event(voodoo->render_not_full_event[1], 1); + if (voodoo->render_threads == 4 && (!PARAM_EMPTY(2) || voodoo->render_voodoo_busy[2])) + thread_wait_event(voodoo->render_not_full_event[2], 1); + if (voodoo->render_threads == 4 && (!PARAM_EMPTY(3) || voodoo->render_voodoo_busy[3])) + thread_wait_event(voodoo->render_not_full_event[3], 1); + } +} + +#endif /*VIDEO_VOODOO_RENDER_H*/ diff --git a/src/include/86box/vid_voodoo_setup.h b/src/include/86box/vid_voodoo_setup.h new file mode 100644 index 000000000..047118701 --- /dev/null +++ b/src/include/86box/vid_voodoo_setup.h @@ -0,0 +1,24 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_SETUP_H +# define VIDEO_VOODOO_SETUP_H + +void voodoo_triangle_setup(voodoo_t *voodoo); + +#endif /*VIDEO_VOODOO_SETUP_H*/ diff --git a/src/include/86box/vid_voodoo_texture.h b/src/include/86box/vid_voodoo_texture.h new file mode 100644 index 000000000..cc2b13201 --- /dev/null +++ b/src/include/86box/vid_voodoo_texture.h @@ -0,0 +1,42 @@ +/* + * 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. + * + * Voodoo Graphics, 2, Banshee, 3 emulation. + * + * + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2020 Sarah Walker. + */ + +#ifndef VIDEO_VOODOO_TEXTURE_H +# define VIDEO_VOODOO_TEXTURE_H + +static const uint32_t texture_offset[LOD_MAX+3] = +{ + 0, + 256*256, + 256*256 + 128*128, + 256*256 + 128*128 + 64*64, + 256*256 + 128*128 + 64*64 + 32*32, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1 +}; + +void voodoo_recalc_tex(voodoo_t *voodoo, int tmu); +void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu); +void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p); +void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu); + +#endif /* VIDEO_VOODOO_TEXTURE_H*/ diff --git a/src/include/86box/vid_xga.h b/src/include/86box/vid_xga.h new file mode 100644 index 000000000..5890b5cad --- /dev/null +++ b/src/include/86box/vid_xga.h @@ -0,0 +1,164 @@ +/* + * 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. + * + * IBM XGA emulation. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022 TheCollector1995. + */ + +#ifndef VIDEO_XGA_H +# define VIDEO_XGA_H + +#include <86box/rom.h> + +typedef struct { + int ena; + int x, y, xoff, yoff, cur_xsize, cur_ysize; + uint32_t addr; +} xga_hwcursor_t; + +typedef struct xga_t +{ + mem_mapping_t memio_mapping; + mem_mapping_t linear_mapping; + mem_mapping_t video_mapping; + rom_t bios_rom; + xga_hwcursor_t hwcursor, hwcursor_latch; + PALETTE extpal; + + uint8_t test, atest[2], testpixel;; + uint8_t pos_regs[8]; + uint8_t disp_addr; + uint8_t cfg_reg; + uint8_t instance; + uint8_t op_mode; + uint8_t aperture_cntl; + uint8_t ap_idx; + uint8_t access_mode; + uint8_t regs[0x100]; + uint8_t regs_idx; + uint8_t hwc_hotspot_x; + uint8_t hwc_hotspot_y; + uint8_t disp_cntl_1, disp_cntl_2; + uint8_t clk_sel_1, clk_sel_2; + uint8_t hwc_control; + uint8_t bus_arb; + uint8_t select_pos_isa; + uint8_t hwcursor_oddeven; + uint8_t cfg_reg_instance; + uint8_t rowcount; + uint8_t pal_idx, pal_idx_prefetch; + uint8_t pal_seq; + uint8_t pal_mask; + uint8_t pal_r, pal_r_prefetch; + uint8_t pal_g, pal_g_prefetch; + uint8_t pal_b, pal_b_prefetch; + uint8_t sprite_data[1024]; + uint8_t scrollcache; + uint8_t direct_color; + uint8_t *vram, *changedvram; + + int16_t hwc_pos_x; + int16_t hwc_pos_y; + + uint16_t pos_idx; + uint16_t htotal; + uint16_t sprite_idx, sprite_idx_prefetch; + uint16_t hdisp; + uint16_t vtotal; + uint16_t vdispend; + uint16_t vblankstart; + uint16_t vsyncstart; + uint16_t linecmp; + uint16_t pix_map_width; + uint16_t sprite_pal_addr_idx, old_pal_addr_idx; + uint16_t sprite_pal_addr_idx_prefetch; + + int v_total, dispend, v_syncstart, split, v_blankstart, + h_disp, h_disp_old, h_total, h_disp_time, rowoffset, + dispon, h_disp_on, vc, sc, linepos, oddeven, firstline, lastline, + firstline_draw, lastline_draw, displine, fullchange, interlace, + char_width, hwcursor_on; + int pal_pos, pal_pos_prefetch; + int on; + int op_mode_reset, linear_endian_reverse; + int sprite_pos, sprite_pos_prefetch, cursor_data_on; + int pal_test; + int type, bus; + + uint32_t linear_base, linear_size, banked_mask; + uint32_t base_addr_1mb; + uint32_t hwc_color0, hwc_color1; + uint32_t disp_start_addr; + uint32_t ma_latch; + uint32_t vram_size; + uint32_t vram_mask; + uint32_t rom_addr; + uint32_t ma, maback; + uint32_t extpallook[256]; + uint32_t read_bank, write_bank; + uint32_t px_map_base; + + uint64_t dispontime, dispofftime; + + struct + { + uint8_t control; + uint8_t px_map_idx; + uint8_t frgd_mix, bkgd_mix; + uint8_t cc_cond; + uint8_t octant; + uint8_t draw_mode; + uint8_t mask_mode; + uint8_t short_stroke_vector1; + uint8_t short_stroke_vector2; + uint8_t short_stroke_vector3; + uint8_t short_stroke_vector4; + + int16_t bres_err_term; + int16_t bres_k1, bres_k2; + + uint16_t blt_width; + uint16_t blt_height; + uint16_t mask_map_origin_x_off; + uint16_t mask_map_origin_y_off; + uint16_t src_map_x, src_map_y; + uint16_t dst_map_x, dst_map_y; + uint16_t pat_map_x, pat_map_y; + + int ssv_state; + int pat_src; + int src_map; + int dst_map; + int bkgd_src; + int fore_src; + int x, y, sx, sy, dx, dy, px, py; + int pattern; + int command_len; + + uint32_t short_stroke; + uint32_t color_cmp; + uint32_t carry_chain; + uint32_t plane_mask; + uint32_t frgd_color, bkgd_color; + uint32_t command; + uint32_t dir_cmd; + + uint8_t px_map_format[4]; + uint16_t px_map_width[4]; + uint16_t px_map_height[4]; + uint32_t px_map_base[4]; + } accel; + + volatile int force_busy; +} xga_t; +#endif /*VIDEO_XGA_H*/ diff --git a/src/include/86box/vid_xga_device.h b/src/include/86box/vid_xga_device.h new file mode 100644 index 000000000..37893e0d5 --- /dev/null +++ b/src/include/86box/vid_xga_device.h @@ -0,0 +1,22 @@ +/* + * 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. + * + * IBM XGA emulation. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022 TheCollector1995. + */ + +#ifndef VIDEO_XGA_DEVICE_H +# define VIDEO_XGA_DEVICE_H +extern const device_t xga_device; +extern const device_t xga_isa_device; +#endif /*VIDEO_XGA_DEVICE_H*/ diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 018b877a3..fd402186a 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -18,9 +18,17 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ + #ifndef EMU_VIDEO_H # define EMU_VIDEO_H +#ifdef __cplusplus +#include +using atomic_bool = std::atomic_bool; +using atomic_int = std::atomic_int; +#else +#include +#endif #define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) #define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) @@ -48,7 +56,8 @@ enum { VIDEO_ISA = 0, VIDEO_MCA, VIDEO_BUS, - VIDEO_PCI + VIDEO_PCI, + VIDEO_AGP }; #define VIDEO_FLAG_TYPE_CGA 0 @@ -77,22 +86,93 @@ typedef struct { uint8_t chr[32]; } dbcs_font_t; +struct blit_data_struct; + +typedef struct monitor_t +{ + char name[512]; + int mon_xsize; + int mon_ysize; + int mon_scrnsz_x; + int mon_scrnsz_y; + int mon_efscrnsz_y; + int mon_unscaled_size_x; + int mon_unscaled_size_y; + int mon_res_x; + int mon_res_y; + int mon_bpp; + bitmap_t* target_buffer; + int mon_video_timing_read_b, + mon_video_timing_read_w, + mon_video_timing_read_l; + int mon_video_timing_write_b, + mon_video_timing_write_w, + mon_video_timing_write_l; + int mon_overscan_x; + int mon_overscan_y; + int mon_force_resize; + int mon_fullchange; + int mon_changeframecount; + atomic_int mon_screenshots; + uint32_t* mon_pal_lookup; + int* mon_cga_palette; + int mon_pal_lookup_static; /* Whether it should not be freed by the API. */ + int mon_cga_palette_static; /* Whether it should not be freed by the API. */ + const video_timings_t* mon_vid_timings; + int mon_vid_type; + struct blit_data_struct* mon_blit_data_ptr; +} monitor_t; + +typedef struct monitor_settings_t { + int mon_window_x; /* (C) window size and position info. */ + int mon_window_y; + int mon_window_w; + int mon_window_h; +} monitor_settings_t; + +#define MONITORS_NUM 2 +extern monitor_t monitors[MONITORS_NUM]; +extern monitor_settings_t monitor_settings[MONITORS_NUM]; +extern atomic_bool doresize_monitors[MONITORS_NUM]; +extern int monitor_index_global; +extern int gfxcard_2; +extern int show_second_monitors; + typedef rgb_t PALETTE[256]; -extern int egareads, - egawrites; -extern int changeframecount; +//extern int changeframecount; extern volatile int screenshots; -extern bitmap_t *buffer32, *render_buffer; +//extern bitmap_t *buffer32; +#define buffer32 (monitors[monitor_index_global].target_buffer) +#define pal_lookup (monitors[monitor_index_global].mon_pal_lookup) +#define overscan_x (monitors[monitor_index_global].mon_overscan_x) +#define overscan_y (monitors[monitor_index_global].mon_overscan_y) +#define video_timing_read_b (monitors[monitor_index_global].mon_video_timing_read_b) +#define video_timing_read_l (monitors[monitor_index_global].mon_video_timing_read_l) +#define video_timing_read_w (monitors[monitor_index_global].mon_video_timing_read_w) +#define video_timing_write_b (monitors[monitor_index_global].mon_video_timing_write_b) +#define video_timing_write_l (monitors[monitor_index_global].mon_video_timing_write_l) +#define video_timing_write_w (monitors[monitor_index_global].mon_video_timing_write_w) +#define video_res_x (monitors[monitor_index_global].mon_res_x) +#define video_res_y (monitors[monitor_index_global].mon_res_y) +#define video_bpp (monitors[monitor_index_global].mon_bpp) +#define xsize (monitors[monitor_index_global].mon_xsize) +#define ysize (monitors[monitor_index_global].mon_ysize) +#define cga_palette (*monitors[monitor_index_global].mon_cga_palette) +#define changeframecount (monitors[monitor_index_global].mon_changeframecount) +#define scrnsz_x (monitors[monitor_index_global].mon_scrnsz_x) +#define scrnsz_y (monitors[monitor_index_global].mon_scrnsz_y) +#define efscrnsz_y (monitors[monitor_index_global].mon_efscrnsz_y) +#define unscaled_size_x (monitors[monitor_index_global].mon_unscaled_size_x) +#define unscaled_size_y (monitors[monitor_index_global].mon_unscaled_size_y) extern PALETTE cgapal, cgapal_mono[6]; -extern uint32_t pal_lookup[256]; +//extern uint32_t pal_lookup[256]; extern int video_fullscreen, video_fullscreen_scale, - video_fullscreen_first; -extern int fullchange; + video_fullscreen_first; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; extern uint8_t fontdatw[512][32]; @@ -104,24 +184,11 @@ extern uint32_t *video_6to8, *video_8togs, *video_8to32, *video_15to32, - *video_16to32; -extern int xsize,ysize; + *video_16to32; extern int enable_overscan; -extern int overscan_x, - overscan_y; extern int force_43; -extern int video_timing_read_b, - video_timing_read_w, - video_timing_read_l; -extern int video_timing_write_b, - video_timing_write_w, - video_timing_write_l; -extern int video_res_x, - video_res_y, - video_bpp; extern int vid_resize; -extern int cga_palette, - herc_blend; +extern int herc_blend; extern int vid_cga_contrast; extern int video_grayscale; extern int video_graytype; @@ -134,64 +201,96 @@ extern int readflash; /* Function handler pointers. */ extern void (*video_recalctimings)(void); +extern void video_screenshot_monitor(uint32_t *buf, int start_x, int start_y, int row_len, int monitor_index); +extern void video_screenshot(uint32_t *buf, int start_x, int start_y, int row_len); + +#ifdef _WIN32 +extern void * __cdecl (*video_copy)(void *_Dst, const void *_Src, size_t _Size); +extern void * __cdecl video_transform_copy(void *_Dst, const void *_Src, size_t _Size); +#else +extern void * (*video_copy)(void *__restrict _Dst, const void *__restrict _Src, size_t _Size); +extern void * video_transform_copy(void *__restrict _Dst, const void *__restrict _Src, size_t _Size); +#endif /* Table functions. */ extern int video_card_available(int card); -extern char *video_card_getname(int card); #ifdef EMU_DEVICE_H extern const device_t *video_card_getdevice(int card); #endif extern int video_card_has_config(int card); -extern int video_card_getid(char *s); extern char *video_get_internal_name(int card); extern int video_get_video_from_internal_name(char *s); +extern int video_card_get_flags(int card); extern int video_is_mda(void); extern int video_is_cga(void); extern int video_is_ega_vga(void); -extern void video_inform(int type, const video_timings_t *ptr); -extern int video_get_type(void); +extern void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index); +extern int video_get_type_monitor(int monitor_index); -extern void video_setblit(void(*blit)(int,int,int,int,int,int)); +extern void video_setblit(void(*blit)(int,int,int,int,int)); extern void video_blend(int x, int y); -extern void video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h); -extern void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); -extern void video_blit_complete(void); -extern void video_wait_for_blit(void); -extern void video_wait_for_buffer(void); +extern void video_blit_memtoscreen_8(int x, int y, int w, int h); +extern void video_blend_monitor(int x, int y, int monitor_index); +extern void video_blit_memtoscreen_8_monitor(int x, int y, int w, int h, int monitor_index); +extern void video_blit_memtoscreen_monitor(int x, int y, int w, int h, int monitor_index); +extern void video_blit_complete_monitor(int monitor_index); +extern void video_wait_for_blit_monitor(int monitor_index); +extern void video_wait_for_buffer_monitor(int monitor_index); extern bitmap_t *create_bitmap(int w, int h); extern void destroy_bitmap(bitmap_t *b); -extern void cgapal_rebuild(void); +extern void cgapal_rebuild_monitor(int monitor_index); extern void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col); extern void updatewindowsize(int x, int y); +extern void video_monitor_init(int); +extern void video_monitor_close(int); extern void video_init(void); extern void video_close(void); extern void video_reset_close(void); +extern void video_pre_reset(int card); extern void video_reset(int card); -extern uint8_t video_force_resize_get(void); -extern void video_force_resize_set(uint8_t res); +extern uint8_t video_force_resize_get_monitor(int monitor_index); +extern void video_force_resize_set_monitor(uint8_t res, int monitor_index); extern void video_update_timing(void); -extern void loadfont(wchar_t *s, int format); +extern void loadfont_ex(char *s, int format, int offset); +extern void loadfont(char *s, int format); extern int get_actual_size_x(void); extern int get_actual_size_y(void); -#ifdef ENABLE_VRAM_DUMP -extern void svga_dump_vram(void); -#endif - extern uint32_t video_color_transform(uint32_t color); +extern void agpgart_set_aperture(void *handle, uint32_t base, uint32_t size, int enable); +extern void agpgart_set_gart(void *handle, uint32_t base); + +#define video_inform(type, video_timings_ptr) video_inform_monitor(type, video_timings_ptr, monitor_index_global) +#define video_get_type() video_get_type_monitor(0) +#define video_blend(x, y) video_blend_monitor(x, y, monitor_index_global) +#define video_blit_memtoscreen(x, y, w, h) video_blit_memtoscreen_monitor(x, y, w, h, monitor_index_global) +#define video_blit_memtoscreen_8(x, y, w, h) video_blit_memtoscreen_8_monitor(x, y, w, h, monitor_index_global) +#define video_blit_complete() video_blit_complete_monitor(monitor_index_global) +#define video_wait_for_blit() video_wait_for_blit_monitor(monitor_index_global) +#define video_wait_for_buffer() video_wait_for_buffer_monitor(monitor_index_global) +#define cgapal_rebuild() cgapal_rebuild_monitor(monitor_index_global) +#define video_force_resize_get() video_force_resize_get_monitor(monitor_index_global) +#define video_force_resize_set(val) video_force_resize_set_monitor(val, monitor_index_global) + #ifdef __cplusplus } #endif #ifdef EMU_DEVICE_H +/* IBM XGA */ +extern void xga_device_add(void); + +/* IBM 8514/A and generic clones*/ +extern void ibm8514_device_add(void); + /* ATi Mach64 */ extern const device_t mach64gx_isa_device; extern const device_t mach64gx_vlb_device; @@ -199,37 +298,46 @@ extern const device_t mach64gx_pci_device; extern const device_t mach64vt2_device; /* ATi 18800 */ +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) extern const device_t ati18800_wonder_device; +#endif extern const device_t ati18800_vga88_device; extern const device_t ati18800_device; /* ATi 28800 */ extern const device_t ati28800_device; extern const device_t ati28800k_device; +extern const device_t ati28800k_spc4620p_device; +extern const device_t ati28800k_spc6033p_device; extern const device_t compaq_ati28800_device; #if defined(DEV_BRANCH) && defined(USE_XL24) extern const device_t ati28800_wonderxl24_device; #endif -/* Cirrus Logic CL-GD 54xx */ +/* Cirrus Logic GD54xx */ extern const device_t gd5401_isa_device; extern const device_t gd5402_isa_device; extern const device_t gd5402_onboard_device; extern const device_t gd5420_isa_device; -#if defined(DEV_BRANCH) && defined(USE_CL5422) extern const device_t gd5422_isa_device; extern const device_t gd5424_vlb_device; -#endif +extern const device_t gd5426_isa_device; +extern const device_t gd5426_diamond_speedstar_pro_a1_isa_device; extern const device_t gd5426_vlb_device; +extern const device_t gd5426_onboard_device; extern const device_t gd5428_isa_device; extern const device_t gd5428_vlb_device; +extern const device_t gd5428_diamond_speedstar_pro_b1_vlb_device; extern const device_t gd5428_mca_device; -extern const device_t gd5428_a1g_device; +extern const device_t gd5426_mca_device; +extern const device_t gd5428_onboard_device; extern const device_t gd5429_isa_device; extern const device_t gd5429_vlb_device; -extern const device_t gd5430_vlb_device; +extern const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device; extern const device_t gd5430_pci_device; extern const device_t gd5434_isa_device; +extern const device_t gd5434_diamond_speedstar_64_a3_isa_device; +extern const device_t gd5434_onboard_pci_device; extern const device_t gd5434_vlb_device; extern const device_t gd5434_pci_device; extern const device_t gd5436_pci_device; @@ -243,16 +351,40 @@ extern const device_t gd5480_pci_device; extern const device_t compaq_cga_device; extern const device_t compaq_cga_2_device; +/* Olivetti OGC */ +extern const device_t ogc_device; +extern const device_t ogc_m24_device; + +/* Chips & Technologies 82C425 */ +extern const device_t f82c425_video_device; + +/* NCR NGA */ +extern const device_t nga_device; + +/* Tseng ET3000AX */ +extern const device_t et3000_isa_device; + /* Tseng ET4000AX */ +extern const device_t et4000_tc6058af_isa_device; extern const device_t et4000_isa_device; extern const device_t et4000k_isa_device; extern const device_t et4000k_tg286_isa_device; extern const device_t et4000_kasan_isa_device; extern const device_t et4000_mca_device; -/* Tseng ET4000-W32p */ +/* Tseng ET4000-W32x */ +extern const device_t et4000w32_device; +extern const device_t et4000w32_onboard_device; +extern const device_t et4000w32i_isa_device; +extern const device_t et4000w32i_vlb_device; +extern const device_t et4000w32p_videomagic_revb_vlb_device; +extern const device_t et4000w32p_videomagic_revb_pci_device; +extern const device_t et4000w32p_revc_vlb_device; +extern const device_t et4000w32p_revc_pci_device; extern const device_t et4000w32p_vlb_device; extern const device_t et4000w32p_pci_device; +extern const device_t et4000w32p_noncardex_vlb_device; +extern const device_t et4000w32p_noncardex_pci_device; extern const device_t et4000w32p_cardex_vlb_device; extern const device_t et4000w32p_cardex_pci_device; @@ -267,14 +399,18 @@ extern const device_t incolor_device; /* Headland GC-2xx/HT-2xx */ extern const device_t g2_gc205_device; extern const device_t v7_vga_1024i_device; +extern const device_t radius_svga_multiview_isa_device; +extern const device_t radius_svga_multiview_mca_device; extern const device_t ht216_32_pb410a_device; +extern const device_t ht216_32_standalone_device; /* Professional Graphics Controller */ extern const device_t im1024_device; extern const device_t pgc_device; #if defined(DEV_BRANCH) && defined(USE_MGA) -/* Matrox Mystique */ +/* Matrox MGA */ +extern const device_t millennium_device; extern const device_t mystique_device; extern const device_t mystique_220_device; #endif @@ -287,6 +423,7 @@ extern const device_t oti067_ama932j_device; extern const device_t oti077_device; /* Paradise/WD (S)VGA */ +extern const device_t paradise_pvga1a_ncr3302_device; extern const device_t paradise_pvga1a_pc2086_device; extern const device_t paradise_pvga1a_pc3086_device; extern const device_t paradise_pvga1a_device; @@ -294,11 +431,22 @@ extern const device_t paradise_wd90c11_megapc_device; extern const device_t paradise_wd90c11_device; extern const device_t paradise_wd90c30_device; +/* Realtek (S)VGA */ +extern const device_t realtek_rtg3106_device; + /* S3 9XX/8XX/Vision/Trio */ extern const device_t s3_orchid_86c911_isa_device; -extern const device_t s3_metheus_premier_86c928_isa_device; -extern const device_t s3_metheus_premier_86c928_vlb_device; -extern const device_t s3_v7mirage_86c801_isa_device; +extern const device_t s3_diamond_stealth_vram_isa_device; +extern const device_t s3_ami_86c924_isa_device; +extern const device_t s3_metheus_86c928_isa_device; +extern const device_t s3_metheus_86c928_vlb_device; +extern const device_t s3_spea_mercury_lite_86c928_pci_device; +extern const device_t s3_spea_mirage_86c801_isa_device; +extern const device_t s3_86c805_onboard_vlb_device; +extern const device_t s3_spea_mirage_86c805_vlb_device; +extern const device_t s3_mirocrystal_8s_805_vlb_device; +extern const device_t s3_mirocrystal_10sd_805_vlb_device; +extern const device_t s3_phoenix_86c801_isa_device; extern const device_t s3_phoenix_86c805_vlb_device; extern const device_t s3_bahamas64_vlb_device; extern const device_t s3_bahamas64_pci_device; @@ -306,25 +454,50 @@ extern const device_t s3_9fx_vlb_device; extern const device_t s3_9fx_pci_device; extern const device_t s3_phoenix_trio32_vlb_device; extern const device_t s3_phoenix_trio32_pci_device; +extern const device_t s3_diamond_stealth_se_vlb_device; +extern const device_t s3_diamond_stealth_se_pci_device; +extern const device_t s3_spea_mirage_p64_vlb_device; extern const device_t s3_phoenix_trio64_vlb_device; extern const device_t s3_phoenix_trio64_onboard_pci_device; extern const device_t s3_phoenix_trio64_pci_device; +extern const device_t s3_phoenix_trio64vplus_pci_device; +extern const device_t s3_phoenix_trio64vplus_onboard_pci_device; +extern const device_t s3_mirocrystal_20sv_964_vlb_device; +extern const device_t s3_mirocrystal_20sv_964_pci_device; +extern const device_t s3_mirocrystal_20sd_864_vlb_device; extern const device_t s3_phoenix_vision864_pci_device; extern const device_t s3_phoenix_vision864_vlb_device; +extern const device_t s3_9fx_531_pci_device; +extern const device_t s3_phoenix_vision868_pci_device; +extern const device_t s3_phoenix_vision868_vlb_device; extern const device_t s3_diamond_stealth64_pci_device; extern const device_t s3_diamond_stealth64_vlb_device; extern const device_t s3_diamond_stealth64_964_pci_device; extern const device_t s3_diamond_stealth64_964_vlb_device; +extern const device_t s3_mirovideo_40sv_ergo_968_pci_device; +extern const device_t s3_9fx_771_pci_device; +extern const device_t s3_phoenix_vision968_pci_device; +extern const device_t s3_phoenix_vision968_vlb_device; +extern const device_t s3_spea_mercury_p64v_pci_device; +extern const device_t s3_elsa_winner2000_pro_x_964_pci_device; +extern const device_t s3_elsa_winner2000_pro_x_pci_device; +extern const device_t s3_trio64v2_dx_pci_device; +extern const device_t s3_trio64v2_dx_onboard_pci_device; /* S3 ViRGE */ -extern const device_t s3_virge_vlb_device; -extern const device_t s3_virge_pci_device; -extern const device_t s3_virge_988_vlb_device; -extern const device_t s3_virge_988_pci_device; -extern const device_t s3_virge_375_vlb_device; +extern const device_t s3_virge_325_pci_device; +extern const device_t s3_diamond_stealth_2000_pci_device; +extern const device_t s3_diamond_stealth_3000_pci_device; +extern const device_t s3_stb_velocity_3d_pci_device; extern const device_t s3_virge_375_pci_device; -extern const device_t s3_virge_375_4_vlb_device; -extern const device_t s3_virge_375_4_pci_device; +extern const device_t s3_diamond_stealth_2000pro_pci_device; +extern const device_t s3_virge_385_pci_device; +extern const device_t s3_virge_357_pci_device; +extern const device_t s3_virge_357_agp_device; +extern const device_t s3_diamond_stealth_4000_pci_device; +extern const device_t s3_diamond_stealth_4000_agp_device; +extern const device_t s3_trio3d2x_pci_device; +extern const device_t s3_trio3d2x_agp_device; /* Sigma Color 400 */ extern const device_t sigma_device; @@ -333,6 +506,9 @@ extern const device_t sigma_device; extern const device_t tgui9400cxi_device; extern const device_t tgui9440_vlb_device; extern const device_t tgui9440_pci_device; +extern const device_t tgui9440_onboard_pci_device; +extern const device_t tgui9660_pci_device; +extern const device_t tgui9680_pci_device; /* IBM PS/1 (S)VGA */ extern const device_t ibm_ps1_2121_device; @@ -340,6 +516,7 @@ extern const device_t ibm_ps1_2121_device; /* Trident TVGA 8900 */ extern const device_t tvga8900b_device; extern const device_t tvga8900d_device; +extern const device_t tvga9000b_device; /* IBM VGA */ extern const device_t vga_device; @@ -348,10 +525,20 @@ extern const device_t ps1vga_mca_device; /* 3DFX Voodoo Graphics */ extern const device_t voodoo_device; +extern const device_t voodoo_banshee_device; +extern const device_t creative_voodoo_banshee_device; +extern const device_t voodoo_3_2000_device; +extern const device_t voodoo_3_2000_agp_device; +extern const device_t voodoo_3_2000_agp_onboard_8m_device; +extern const device_t voodoo_3_3000_device; +extern const device_t voodoo_3_3000_agp_device; +extern const device_t velocity_100_agp_device; /* Wyse 700 */ extern const device_t wy700_device; + +/* AGP GART */ +extern const device_t agpgart_device; #endif - #endif /*EMU_VIDEO_H*/ diff --git a/src/include/86box/vnc.h b/src/include/86box/vnc.h index 2d3dea3cd..1e0ddebba 100644 --- a/src/include/86box/vnc.h +++ b/src/include/86box/vnc.h @@ -14,6 +14,7 @@ * * Copyright 2017 Fred N. van Kempen. */ + #ifndef EMU_VNC_H # define EMU_VNC_H @@ -35,5 +36,4 @@ extern void vnc_take_screenshot(wchar_t *fn); } #endif - #endif /*EMU_VNC_H*/ diff --git a/src/include/86box/win.h b/src/include/86box/win.h index f73956656..bb5a78990 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -17,7 +17,9 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ + #ifndef PLAT_WIN_H # define PLAT_WIN_H @@ -33,6 +35,19 @@ # include "resource.h" # undef BITMAP +/* DPI Awareness Context, copied from MinGW-w64 windef.h */ +#ifndef _DPI_AWARENESS_CONTEXTS_ +DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); +#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1) +#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2) +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3) +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) +#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5) +#endif + +#ifndef WM_DPICHANGED_AFTERPARENT +#define WM_DPICHANGED_AFTERPARENT 0x02E3 +#endif /* Class names and such. */ #define CLASS_NAME L"86BoxMainWnd" @@ -42,12 +57,18 @@ #define SB_CLASS_NAME L"86BoxStatusBar" #define SB_MENU_NAME L"StatusBarMenu" #define FS_CLASS_NAME L"86BoxFullScreen" +#define SDL_CLASS_NAME L"86BoxSDLWnd" +#define SDL_SUB_CLASS_NAME L"86BoxSDLSubWnd" +#define CASSETTE_SUBMENU_NAME L"CassetteSubmenu" +#define CARTRIDGE_SUBMENU_NAME L"CartridgeSubmenu" #define FLOPPY_SUBMENU_NAME L"FloppySubmenu" #define CDROM_SUBMENU_NAME L"CdromSubmenu" #define ZIP_SUBMENU_NAME L"ZIPSubmenu" #define MO_SUBMENU_NAME L"MOSubmenu" +#define VID_GL_SUBMENU L"VidGLSubMenu" + /* Application-specific window messages. A dialog sends 0x8895 with WPARAM = 1 followed by 0x8896 with WPARAM = 1 on open, @@ -70,9 +91,9 @@ #define WM_HAS_SHUTDOWN 0x8897 #ifdef USE_VNC -#define RENDERERS_NUM 3 +#define RENDERERS_NUM 5 #else -#define RENDERERS_NUM 2 +#define RENDERERS_NUM 4 #endif @@ -84,8 +105,11 @@ extern HINSTANCE hinstance; extern HWND hwndMain, hwndRender; extern HANDLE ghMutex; -extern LCID lang_id; extern HICON hIcon[256]; +extern int dpi; +extern RECT oldclip; +extern int sbar_height, tbar_height, user_resize; +extern int acp_utf8; // extern int status_is_open; @@ -95,16 +119,15 @@ extern WCHAR wopenfilestring[512]; extern uint8_t filterindex; -extern void InitCrashDump(void); - -extern HICON LoadIconEx(PCTSTR pszIconName); +extern void ResizeWindowByClientArea(HWND hwnd, int width, int height); /* Emulator start/stop support functions. */ extern void do_start(void); extern void do_stop(void); /* Internal platform support functions. */ -extern void set_language(int id); +extern int has_language_changed(uint32_t id); +extern void set_language(uint32_t id); extern int get_vidpause(void); extern void show_cursor(int); @@ -119,9 +142,16 @@ extern void win_joystick_handle(PRAWINPUT raw); extern void win_notify_dlg_open(void); extern void win_notify_dlg_closed(void); +extern int win_get_dpi(HWND hwnd); +extern int win_get_system_metrics(int i, int dpi); extern LPARAM win_get_string(int id); +extern void win_clear_icon_set(); +extern void win_system_icon_set(); +extern void win_load_icon_set(); +extern void win_get_icons_path(char* path_root); + extern intptr_t fdd_type_to_icon(int type); #ifdef EMU_DEVICE_H @@ -139,7 +169,6 @@ extern int hard_disk_was_added(void); /* Platform UI support functions. */ extern int ui_init(int nCmdShow); -extern void plat_set_input(HWND h); /* Functions in win_about.c: */ @@ -154,6 +183,13 @@ extern void SoundGainDialogCreate(HWND hwnd); extern void NewFloppyDialogCreate(HWND hwnd, int id, int part); +/* Functions in win_specify_dim.c: */ +extern void SpecifyDimensionsDialogCreate(HWND hwnd); + +/* Functions in win_preferences.c: */ +extern void PreferencesDlgCreate(HWND hwnd); + + /* Functions in win_settings.c: */ #define SETTINGS_PAGE_MACHINE 0 #define SETTINGS_PAGE_VIDEO 1 @@ -161,10 +197,11 @@ extern void NewFloppyDialogCreate(HWND hwnd, int id, int part); #define SETTINGS_PAGE_SOUND 3 #define SETTINGS_PAGE_NETWORK 4 #define SETTINGS_PAGE_PORTS 5 -#define SETTINGS_PAGE_PERIPHERALS 6 +#define SETTINGS_PAGE_STORAGE 6 #define SETTINGS_PAGE_HARD_DISKS 7 -#define SETTINGS_PAGE_FLOPPY_DRIVES 8 +#define SETTINGS_PAGE_FLOPPY_AND_CDROM_DRIVES 8 #define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9 +#define SETTINGS_PAGE_PERIPHERALS 10 extern void win_settings_open(HWND hwnd); extern void win_settings_open_ex(HWND hwnd, int category); @@ -176,12 +213,20 @@ extern void StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst extern int MediaMenuHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +/* Functions in win_toolbar.c */ +extern HWND hwndRebar; +extern void ToolBarCreate(HWND hwndParent, HINSTANCE hInst); +extern void ToolBarLoadIcons(); +extern void ToolBarUpdatePause(int paused); + + /* Functions in win_dialog.c: */ -extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save); -extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save); -extern int file_dlg_mb(HWND hwnd, char *f, char *fn, int save); -extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save); -extern int file_dlg_st(HWND hwnd, int i, char *fn, int save); +/* Pass NULL in the title param to use the default title. */ +extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, WCHAR *title, int save); +extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, char *title, int save); +extern int file_dlg_mb(HWND hwnd, char *f, char *fn, char *title, int save); +extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, char *title, int save); +extern int file_dlg_st(HWND hwnd, int i, char *fn, char *title, int save); extern wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title); @@ -190,19 +235,25 @@ extern wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title); extern void media_menu_init(); extern void media_menu_reset(); extern int media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +extern HMENU media_menu_get_cassette(void); +extern HMENU media_menu_get_cartridge(int id); extern HMENU media_menu_get_floppy(int id); extern HMENU media_menu_get_cdrom(int id); extern HMENU media_menu_get_zip(int id); extern HMENU media_menu_get_mo(int id); +extern void media_menu_update_cassette(void); +extern void media_menu_update_cartridge(int id); extern void media_menu_update_floppy(int id); extern void media_menu_update_cdrom(int id); extern void media_menu_update_zip(int id); extern void media_menu_update_mo(int id); +/* Functions in win_ui.c */ +extern HMENU menuMain; +extern void ResetAllMenus(); #ifdef __cplusplus } #endif - #endif /*PLAT_WIN_H*/ diff --git a/src/include/86box/win_opengl.h b/src/include/86box/win_opengl.h new file mode 100644 index 000000000..e05e99eb4 --- /dev/null +++ b/src/include/86box/win_opengl.h @@ -0,0 +1,29 @@ +/* + * 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. + * + * Header file for OpenGL rendering module + * + * Authors: Teemu Korhonen + * + * Copyright 2021 Teemu Korhonen + */ + +#ifndef WIN_OPENGL_H +#define WIN_OPENGL_H + +#define UNICODE +#include + +extern int opengl_init(HWND hwnd); +extern int opengl_pause(void); +extern void opengl_close(void); +extern void opengl_set_fs(int fs); +extern void opengl_resize(int w, int h); +extern void opengl_reload(void); + +#endif /*!WIN_OPENGL_H*/ diff --git a/src/include/86box/win_opengl_glslp.h b/src/include/86box/win_opengl_glslp.h new file mode 100644 index 000000000..9faf20705 --- /dev/null +++ b/src/include/86box/win_opengl_glslp.h @@ -0,0 +1,24 @@ +/* + * 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. + * + * Header file for shader file parser. + * + * Authors: Teemu Korhonen + * + * Copyright 2021 Teemu Korhonen + */ + +#ifndef WIN_OPENGL_GLSLP_H +#define WIN_OPENGL_GLSLP_H + +#include + +GLuint load_custom_shaders(const char* path); +GLuint load_default_shaders(); + +#endif /*!WIN_OPENGL_GLSLP_H*/ diff --git a/src/include/86box/win_sdl.h b/src/include/86box/win_sdl.h index c157c6f59..bd510dbf1 100644 --- a/src/include/86box/win_sdl.h +++ b/src/include/86box/win_sdl.h @@ -11,10 +11,10 @@ * * * Authors: Fred N. van Kempen, - * Michael Dring, + * Michael Drüing, * * Copyright 2018,2019 Fred N. van Kempen. - * Copyright 2018,2019 Michael Dring. + * Copyright 2018,2019 Michael Drüing. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -46,6 +46,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef WIN_SDL_H # define WIN_SDL_H @@ -53,11 +54,11 @@ extern void sdl_close(void); extern int sdl_inits(HWND h); extern int sdl_inith(HWND h); -extern int sdl_inits_fs(HWND h); -extern int sdl_inith_fs(HWND h); +extern int sdl_initho(HWND h); extern int sdl_pause(void); extern void sdl_resize(int x, int y); extern void sdl_enable(int enable); - +extern void sdl_set_fs(int fs); +extern void sdl_reload(void); #endif /*WIN_SDL_H*/ diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index e0f577762..722d51d91 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -15,10 +15,10 @@ * * Copyright 2018,2019 Miran Grca. */ + #ifndef EMU_ZIP_H #define EMU_ZIP_H - #define ZIP_NUM 4 #define BUF_SIZE 32768 @@ -32,18 +32,22 @@ enum { ZIP_BUS_DISABLED = 0, - ZIP_BUS_ATAPI = 4, + ZIP_BUS_ATAPI = 5, ZIP_BUS_SCSI, ZIP_BUS_USB }; typedef struct { - uint8_t id, - res, res0, /* Reserved for other ID's. */ - res1, - ide_channel, scsi_device_id, - bus_type, /* 0 = ATAPI, 1 = SCSI */ + uint8_t id; + + union { + uint8_t res, res0, /* Reserved for other ID's. */ + res1, + ide_channel, scsi_device_id; + }; + + uint8_t bus_type, /* 0 = ATAPI, 1 = SCSI */ bus_mode, /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ read_only, /* Struct variable reserved for @@ -53,7 +57,7 @@ typedef struct { FILE *f; void *priv; - wchar_t image_path[1024], + char image_path[1024], prev_image_path[1024]; uint32_t is_250, medium_size, @@ -72,8 +76,8 @@ typedef struct { uint8_t status, phase, error, id, - features, pad0, - pad1, pad2; + features, cur_lun, + pad0, pad1; uint16_t request_length, max_transfer_len; @@ -112,12 +116,11 @@ extern void zip_global_init(void); extern void zip_hard_reset(void); extern void zip_reset(scsi_common_t *sc); -extern int zip_load(zip_t *dev, wchar_t *fn); +extern int zip_load(zip_t *dev, char *fn); extern void zip_close(); #ifdef __cplusplus } #endif - #endif /*EMU_ZIP_H*/ diff --git a/src/include/FAudio_compat.h b/src/include/FAudio_compat.h new file mode 100644 index 000000000..dd76dea3d --- /dev/null +++ b/src/include/FAudio_compat.h @@ -0,0 +1,106 @@ +/* map xaudio2 API to faudio API */ +typedef uint32_t HRESULT; +typedef uint32_t UINT32; +typedef uint32_t DWORD; +typedef uint8_t BOOL; + +#define WINAPI FAUDIOCALL + +#define TRUE 1 +#define FALSE 0 + +#define S_OK 0 +#define XAUDIO2_E_INVALID_CALL FAUDIO_E_INVALID_CALL + +#define XAUDIO2_DEFAULT_PROCESSOR FAUDIO_DEFAULT_PROCESSOR +#define XAUDIO2_COMMIT_NOW FAUDIO_COMMIT_NOW +#define XAUDIO2_END_OF_STREAM FAUDIO_END_OF_STREAM + +#define WAVE_FORMAT_PCM FAUDIO_FORMAT_PCM +#define WAVE_FORMAT_IEEE_FLOAT FAUDIO_FORMAT_IEEE_FLOAT + +#define AudioCategory_GameEffects FAudioStreamCategory_GameEffects + +#define GlobalDefaultDevice FAudioGlobalDefaultDevice +#define NotDefaultDevice FAudioNotDefaultDevice + +#define XAudio2Create FAudioCreate + +typedef FAudioBuffer XAUDIO2_BUFFER; +typedef FAudioDeviceDetails XAUDIO2_DEVICE_DETAILS; +typedef FAudioEffectChain XAUDIO2_EFFECT_CHAIN; +typedef FAudioEffectDescriptor XAUDIO2_EFFECT_DESCRIPTOR; +typedef FAudioVoiceDetails XAUDIO2_VOICE_DETAILS; +typedef FAudioVoiceDetails XAUDIO27_VOICE_DETAILS; +typedef FAudioVoiceState XAUDIO2_VOICE_STATE; +typedef FAudioWaveFormatEx WAVEFORMATEX; +typedef FAudioPerformanceData XAUDIO2_PERFORMANCE_DATA; + +typedef FAudioEngineCallback IXAudio2EngineCallback; +typedef FAudioVoiceCallback IXAudio2VoiceCallback; + +typedef FAPO IXAPO; + +typedef FAudio IXAudio27; +#define IXAudio27_CreateMasteringVoice FAudio_CreateMasteringVoice +#define IXAudio27_CreateSourceVoice FAudio_CreateSourceVoice +#define IXAudio27_CreateSubmixVoice FAudio_CreateSubmixVoice +#define IXAudio27_GetDeviceCount FAudio_GetDeviceCount +#define IXAudio27_GetDeviceDetails FAudio_GetDeviceDetails +#define IXAudio27_GetPerformanceData FAudio_GetPerformanceData +#define IXAudio27_Initialize FAudio_Initialize +#define IXAudio27_RegisterForCallbacks FAudio_RegisterForCallbacks +#define IXAudio27_Release FAudio_Release +#define IXAudio27_StartEngine FAudio_StartEngine +#define IXAudio27_StopEngine FAudio_StopEngine +#define IXAudio27_UnregisterForCallbacks FAudio_UnregisterForCallbacks + +typedef FAudio IXAudio2; +#define IXAudio2_CreateMasteringVoice FAudio_CreateMasteringVoice8 +#define IXAudio2_CreateSourceVoice FAudio_CreateSourceVoice +#define IXAudio2_CreateSubmixVoice FAudio_CreateSubmixVoice +#define IXAudio2_GetPerformanceData FAudio_GetPerformanceData +#define IXAudio2_RegisterForCallbacks FAudio_RegisterForCallbacks +#define IXAudio2_Release FAudio_Release +#define IXAudio2_StartEngine FAudio_StartEngine +#define IXAudio2_StopEngine FAudio_StopEngine +#define IXAudio2_UnregisterForCallbacks FAudio_UnregisterForCallbacks + +typedef FAudioMasteringVoice IXAudio2MasteringVoice; +#define IXAudio2MasteringVoice_DestroyVoice FAudioVoice_DestroyVoice +#define IXAudio2MasteringVoice_GetChannelMask FAudioMasteringVoice_GetChannelMask +#define IXAudio2MasteringVoice_SetEffectChain FAudioVoice_SetEffectChain +#define IXAudio2MasteringVoice_SetVolume FAudioVoice_SetVolume + +typedef FAudioSourceVoice IXAudio27SourceVoice; +#define IXAudio27SourceVoice_DestroyVoice FAudioVoice_DestroyVoice +#define IXAudio27SourceVoice_ExitLoop FAudioSourceVoice_ExitLoop +#define IXAudio27SourceVoice_FlushSourceBuffers FAudioSourceVoice_FlushSourceBuffers +#define IXAudio27SourceVoice_GetState(a,b) FAudioSourceVoice_GetState(a,b,0) +#define IXAudio27SourceVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio27SourceVoice_SetChannelVolumes FAudioVoice_SetChannelVolumes +#define IXAudio27SourceVoice_SetSourceSampleRate FAudioSourceVoice_SetSourceSampleRate +#define IXAudio27SourceVoice_Start FAudioSourceVoice_Start +#define IXAudio27SourceVoice_Stop FAudioSourceVoice_Stop +#define IXAudio27SourceVoice_SubmitSourceBuffer FAudioSourceVoice_SubmitSourceBuffer + +typedef FAudioSourceVoice IXAudio2SourceVoice; +#define IXAudio2SourceVoice_DestroyVoice FAudioVoice_DestroyVoice +#define IXAudio2SourceVoice_ExitLoop FAudioSourceVoice_ExitLoop +#define IXAudio2SourceVoice_FlushSourceBuffers FAudioSourceVoice_FlushSourceBuffers +#define IXAudio2SourceVoice_GetState FAudioSourceVoice_GetState +#define IXAudio2SourceVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio2SourceVoice_SetChannelVolumes FAudioVoice_SetChannelVolumes +#define IXAudio2SourceVoice_SetSourceSampleRate FAudioSourceVoice_SetSourceSampleRate +#define IXAudio2SourceVoice_SetVolume FAudioVoice_SetVolume +#define IXAudio2SourceVoice_Start FAudioSourceVoice_Start +#define IXAudio2SourceVoice_Stop FAudioSourceVoice_Stop +#define IXAudio2SourceVoice_SubmitSourceBuffer FAudioSourceVoice_SubmitSourceBuffer + +typedef FAudioSubmixVoice IXAudio27SubmixVoice; +#define IXAudio27SubmixVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio27SubmixVoice_DestroyVoice FAudioVoice_DestroyVoice + +typedef FAudioSubmixVoice IXAudio2SubmixVoice; +#define IXAudio2SubmixVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio2SubmixVoice_DestroyVoice FAudioVoice_DestroyVoice diff --git a/src/include/KHR/khrplatform.h b/src/include/KHR/khrplatform.h new file mode 100644 index 000000000..01646449c --- /dev/null +++ b/src/include/KHR/khrplatform.h @@ -0,0 +1,311 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/src/include/discord_game_sdk.h b/src/include/discord_game_sdk.h index 50aa13736..62ea8418e 100644 --- a/src/include/discord_game_sdk.h +++ b/src/include/discord_game_sdk.h @@ -1,4 +1,4 @@ -/* +/* * This file is distributed as a part of the Discord Game SDK. * Downloading, accessing, or using the API or SDK is bound by * the Discord Developer Terms of Service: @@ -8,6 +8,23 @@ #ifndef _DISCORD_GAME_SDK_H_ #define _DISCORD_GAME_SDK_H_ +#ifdef _WIN32 +#include +#include +#endif + +#ifdef _WIN32 +# ifdef _WIN64 +# define DISCORD_API +# else +# define DISCORD_API __stdcall +# endif +#else +# define DISCORD_API +#endif + +#define DISCORD_CALLBACK DISCORD_API + #ifdef __cplusplus extern "C" { #endif @@ -18,7 +35,7 @@ extern "C" { #include #endif -#define DISCORD_VERSION 2 +#define DISCORD_VERSION 3 #define DISCORD_APPLICATION_MANAGER_VERSION 1 #define DISCORD_USER_MANAGER_VERSION 1 #define DISCORD_IMAGE_MANAGER_VERSION 1 @@ -26,7 +43,7 @@ extern "C" { #define DISCORD_RELATIONSHIP_MANAGER_VERSION 1 #define DISCORD_LOBBY_MANAGER_VERSION 1 #define DISCORD_NETWORK_MANAGER_VERSION 1 -#define DISCORD_OVERLAY_MANAGER_VERSION 1 +#define DISCORD_OVERLAY_MANAGER_VERSION 2 #define DISCORD_STORAGE_MANAGER_VERSION 1 #define DISCORD_STORE_MANAGER_VERSION 1 #define DISCORD_VOICE_MANAGER_VERSION 1 @@ -77,6 +94,7 @@ enum EDiscordResult { DiscordResult_InvalidGiftCode = 41, DiscordResult_PurchaseError = 42, DiscordResult_TransactionAborted = 43, + DiscordResult_DrawingInitFailed = 44, }; enum EDiscordCreateFlags { @@ -109,6 +127,11 @@ enum EDiscordImageType { DiscordImageType_User, }; +enum EDiscordActivityPartyPrivacy { + DiscordActivityPartyPrivacy_Private = 0, + DiscordActivityPartyPrivacy_Public = 1, +}; + enum EDiscordActivityType { DiscordActivityType_Playing, DiscordActivityType_Streaming, @@ -121,6 +144,12 @@ enum EDiscordActivityActionType { DiscordActivityActionType_Spectate, }; +enum EDiscordActivitySupportedPlatformFlags { + DiscordActivitySupportedPlatformFlags_Desktop = 1, + DiscordActivitySupportedPlatformFlags_Android = 2, + DiscordActivitySupportedPlatformFlags_iOS = 4, +}; + enum EDiscordActivityJoinRequestReply { DiscordActivityJoinRequestReply_No, DiscordActivityJoinRequestReply_Yes, @@ -169,6 +198,18 @@ enum EDiscordLobbySearchDistance { DiscordLobbySearchDistance_Global, }; +enum EDiscordKeyVariant { + DiscordKeyVariant_Normal, + DiscordKeyVariant_Right, + DiscordKeyVariant_Left, +}; + +enum EDiscordMouseButton { + DiscordMouseButton_Left, + DiscordMouseButton_Middle, + DiscordMouseButton_Right, +}; + enum EDiscordEntitlementType { DiscordEntitlementType_Purchase = 1, DiscordEntitlementType_PremiumSubscription, @@ -204,6 +245,18 @@ typedef char DiscordMetadataKey[256]; typedef char DiscordMetadataValue[4096]; typedef uint64_t DiscordNetworkPeerId; typedef uint8_t DiscordNetworkChannelId; +#ifdef __APPLE__ +typedef void IDXGISwapChain; +#endif +#ifdef __linux__ +typedef void IDXGISwapChain; +#endif +#ifdef __APPLE__ +typedef void MSG; +#endif +#ifdef __linux__ +typedef void MSG; +#endif typedef char DiscordPath[4096]; typedef char DiscordDateTime[64]; @@ -252,6 +305,7 @@ struct DiscordPartySize { struct DiscordActivityParty { char id[128]; struct DiscordPartySize size; + enum EDiscordActivityPartyPrivacy privacy; }; struct DiscordActivitySecrets { @@ -271,6 +325,7 @@ struct DiscordActivity { struct DiscordActivityParty party; struct DiscordActivitySecrets secrets; bool instance; + uint32_t supported_platforms; }; struct DiscordPresence { @@ -293,6 +348,21 @@ struct DiscordLobby { bool locked; }; +struct DiscordImeUnderline { + int32_t from; + int32_t to; + uint32_t color; + uint32_t background_color; + bool thick; +}; + +struct DiscordRect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +}; + struct DiscordFileStat { char filename[260]; uint64_t size; @@ -330,265 +400,278 @@ struct DiscordUserAchievement { }; struct IDiscordLobbyTransaction { - enum EDiscordResult (*set_type)(struct IDiscordLobbyTransaction* lobby_transaction, enum EDiscordLobbyType type); - enum EDiscordResult (*set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordUserId owner_id); - enum EDiscordResult (*set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction, uint32_t capacity); - enum EDiscordResult (*set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key, DiscordMetadataValue value); - enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key); - enum EDiscordResult (*set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, bool locked); + enum EDiscordResult (DISCORD_API *set_type)(struct IDiscordLobbyTransaction* lobby_transaction, enum EDiscordLobbyType type); + enum EDiscordResult (DISCORD_API *set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordUserId owner_id); + enum EDiscordResult (DISCORD_API *set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction, uint32_t capacity); + enum EDiscordResult (DISCORD_API *set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key, DiscordMetadataValue value); + enum EDiscordResult (DISCORD_API *delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key); + enum EDiscordResult (DISCORD_API *set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, bool locked); }; struct IDiscordLobbyMemberTransaction { - enum EDiscordResult (*set_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key, DiscordMetadataValue value); - enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key); + enum EDiscordResult (DISCORD_API *set_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key, DiscordMetadataValue value); + enum EDiscordResult (DISCORD_API *delete_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key); }; struct IDiscordLobbySearchQuery { - enum EDiscordResult (*filter)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchComparison comparison, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); - enum EDiscordResult (*sort)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); - enum EDiscordResult (*limit)(struct IDiscordLobbySearchQuery* lobby_search_query, uint32_t limit); - enum EDiscordResult (*distance)(struct IDiscordLobbySearchQuery* lobby_search_query, enum EDiscordLobbySearchDistance distance); + enum EDiscordResult (DISCORD_API *filter)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchComparison comparison, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); + enum EDiscordResult (DISCORD_API *sort)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); + enum EDiscordResult (DISCORD_API *limit)(struct IDiscordLobbySearchQuery* lobby_search_query, uint32_t limit); + enum EDiscordResult (DISCORD_API *distance)(struct IDiscordLobbySearchQuery* lobby_search_query, enum EDiscordLobbySearchDistance distance); }; typedef void* IDiscordApplicationEvents; struct IDiscordApplicationManager { - void (*validate_or_exit)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale); - void (*get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch); - void (*get_oauth2_token)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordOAuth2Token* oauth2_token)); - void (*get_ticket)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, const char* data)); + void (DISCORD_API *validate_or_exit)(struct IDiscordApplicationManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale); + void (DISCORD_API *get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch); + void (DISCORD_API *get_oauth2_token)(struct IDiscordApplicationManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, struct DiscordOAuth2Token* oauth2_token)); + void (DISCORD_API *get_ticket)(struct IDiscordApplicationManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, const char* data)); }; struct IDiscordUserEvents { - void (*on_current_user_update)(void* event_data); + void (DISCORD_API *on_current_user_update)(void* event_data); }; struct IDiscordUserManager { - enum EDiscordResult (*get_current_user)(struct IDiscordUserManager* manager, struct DiscordUser* current_user); - void (*get_user)(struct IDiscordUserManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordUser* user)); - enum EDiscordResult (*get_current_user_premium_type)(struct IDiscordUserManager* manager, enum EDiscordPremiumType* premium_type); - enum EDiscordResult (*current_user_has_flag)(struct IDiscordUserManager* manager, enum EDiscordUserFlag flag, bool* has_flag); + enum EDiscordResult (DISCORD_API *get_current_user)(struct IDiscordUserManager* manager, struct DiscordUser* current_user); + void (DISCORD_API *get_user)(struct IDiscordUserManager* manager, DiscordUserId user_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, struct DiscordUser* user)); + enum EDiscordResult (DISCORD_API *get_current_user_premium_type)(struct IDiscordUserManager* manager, enum EDiscordPremiumType* premium_type); + enum EDiscordResult (DISCORD_API *current_user_has_flag)(struct IDiscordUserManager* manager, enum EDiscordUserFlag flag, bool* has_flag); }; typedef void* IDiscordImageEvents; struct IDiscordImageManager { - void (*fetch)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, bool refresh, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordImageHandle handle_result)); - enum EDiscordResult (*get_dimensions)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, struct DiscordImageDimensions* dimensions); - enum EDiscordResult (*get_data)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, uint8_t* data, uint32_t data_length); + void (DISCORD_API *fetch)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, bool refresh, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, struct DiscordImageHandle handle_result)); + enum EDiscordResult (DISCORD_API *get_dimensions)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, struct DiscordImageDimensions* dimensions); + enum EDiscordResult (DISCORD_API *get_data)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, uint8_t* data, uint32_t data_length); }; struct IDiscordActivityEvents { - void (*on_activity_join)(void* event_data, const char* secret); - void (*on_activity_spectate)(void* event_data, const char* secret); - void (*on_activity_join_request)(void* event_data, struct DiscordUser* user); - void (*on_activity_invite)(void* event_data, enum EDiscordActivityActionType type, struct DiscordUser* user, struct DiscordActivity* activity); + void (DISCORD_API *on_activity_join)(void* event_data, const char* secret); + void (DISCORD_API *on_activity_spectate)(void* event_data, const char* secret); + void (DISCORD_API *on_activity_join_request)(void* event_data, struct DiscordUser* user); + void (DISCORD_API *on_activity_invite)(void* event_data, enum EDiscordActivityActionType type, struct DiscordUser* user, struct DiscordActivity* activity); }; struct IDiscordActivityManager { - enum EDiscordResult (*register_command)(struct IDiscordActivityManager* manager, const char* command); - enum EDiscordResult (*register_steam)(struct IDiscordActivityManager* manager, uint32_t steam_id); - void (*update_activity)(struct IDiscordActivityManager* manager, struct DiscordActivity* activity, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*clear_activity)(struct IDiscordActivityManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*send_request_reply)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityJoinRequestReply reply, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*send_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityActionType type, const char* content, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*accept_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *register_command)(struct IDiscordActivityManager* manager, const char* command); + enum EDiscordResult (DISCORD_API *register_steam)(struct IDiscordActivityManager* manager, uint32_t steam_id); + void (DISCORD_API *update_activity)(struct IDiscordActivityManager* manager, struct DiscordActivity* activity, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *clear_activity)(struct IDiscordActivityManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *send_request_reply)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityJoinRequestReply reply, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *send_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityActionType type, const char* content, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *accept_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); }; struct IDiscordRelationshipEvents { - void (*on_refresh)(void* event_data); - void (*on_relationship_update)(void* event_data, struct DiscordRelationship* relationship); + void (DISCORD_API *on_refresh)(void* event_data); + void (DISCORD_API *on_relationship_update)(void* event_data, struct DiscordRelationship* relationship); }; struct IDiscordRelationshipManager { - void (*filter)(struct IDiscordRelationshipManager* manager, void* filter_data, bool (*filter)(void* filter_data, struct DiscordRelationship* relationship)); - enum EDiscordResult (*count)(struct IDiscordRelationshipManager* manager, int32_t* count); - enum EDiscordResult (*get)(struct IDiscordRelationshipManager* manager, DiscordUserId user_id, struct DiscordRelationship* relationship); - enum EDiscordResult (*get_at)(struct IDiscordRelationshipManager* manager, uint32_t index, struct DiscordRelationship* relationship); + void (DISCORD_API *filter)(struct IDiscordRelationshipManager* manager, void* filter_data, bool (DISCORD_API *filter)(void* filter_data, struct DiscordRelationship* relationship)); + enum EDiscordResult (DISCORD_API *count)(struct IDiscordRelationshipManager* manager, int32_t* count); + enum EDiscordResult (DISCORD_API *get)(struct IDiscordRelationshipManager* manager, DiscordUserId user_id, struct DiscordRelationship* relationship); + enum EDiscordResult (DISCORD_API *get_at)(struct IDiscordRelationshipManager* manager, uint32_t index, struct DiscordRelationship* relationship); }; struct IDiscordLobbyEvents { - void (*on_lobby_update)(void* event_data, int64_t lobby_id); - void (*on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason); - void (*on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id); - void (*on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id); - void (*on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id); - void (*on_lobby_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t* data, uint32_t data_length); - void (*on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking); - void (*on_network_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); + void (DISCORD_API *on_lobby_update)(void* event_data, int64_t lobby_id); + void (DISCORD_API *on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason); + void (DISCORD_API *on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (DISCORD_API *on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id); + void (DISCORD_API *on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (DISCORD_API *on_lobby_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t* data, uint32_t data_length); + void (DISCORD_API *on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking); + void (DISCORD_API *on_network_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); }; struct IDiscordLobbyManager { - enum EDiscordResult (*get_lobby_create_transaction)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction** transaction); - enum EDiscordResult (*get_lobby_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction** transaction); - enum EDiscordResult (*get_member_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction** transaction); - void (*create_lobby)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); - void (*update_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*delete_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*connect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); - void (*connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbySecret activity_secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); - void (*disconnect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - enum EDiscordResult (*get_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct DiscordLobby* lobby); - enum EDiscordResult (*get_lobby_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret* secret); - enum EDiscordResult (*get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordMetadataKey key, DiscordMetadataValue* value); - enum EDiscordResult (*get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordMetadataKey* key); - enum EDiscordResult (*lobby_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); - enum EDiscordResult (*member_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); - enum EDiscordResult (*get_member_user_id)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordUserId* user_id); - enum EDiscordResult (*get_member_user)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct DiscordUser* user); - enum EDiscordResult (*get_member_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, DiscordMetadataKey key, DiscordMetadataValue* value); - enum EDiscordResult (*get_member_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t index, DiscordMetadataKey* key); - enum EDiscordResult (*member_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t* count); - void (*update_member)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*send_lobby_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - enum EDiscordResult (*get_search_query)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery** query); - void (*search)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery* query, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count); - enum EDiscordResult (*get_lobby_id)(struct IDiscordLobbyManager* manager, int32_t index, DiscordLobbyId* lobby_id); - void (*connect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*disconnect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - enum EDiscordResult (*connect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); - enum EDiscordResult (*disconnect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); - enum EDiscordResult (*flush_network)(struct IDiscordLobbyManager* manager); - enum EDiscordResult (*open_network_channel)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t channel_id, bool reliable); - enum EDiscordResult (*send_network_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); + enum EDiscordResult (DISCORD_API *get_lobby_create_transaction)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (DISCORD_API *get_lobby_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (DISCORD_API *get_member_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction** transaction); + void (DISCORD_API *create_lobby)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (DISCORD_API *update_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *delete_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *connect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret secret, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (DISCORD_API *connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbySecret activity_secret, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (DISCORD_API *disconnect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *get_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct DiscordLobby* lobby); + enum EDiscordResult (DISCORD_API *get_lobby_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret* secret); + enum EDiscordResult (DISCORD_API *get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordMetadataKey key, DiscordMetadataValue* value); + enum EDiscordResult (DISCORD_API *get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordMetadataKey* key); + enum EDiscordResult (DISCORD_API *lobby_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); + enum EDiscordResult (DISCORD_API *member_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); + enum EDiscordResult (DISCORD_API *get_member_user_id)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordUserId* user_id); + enum EDiscordResult (DISCORD_API *get_member_user)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct DiscordUser* user); + enum EDiscordResult (DISCORD_API *get_member_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, DiscordMetadataKey key, DiscordMetadataValue* value); + enum EDiscordResult (DISCORD_API *get_member_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t index, DiscordMetadataKey* key); + enum EDiscordResult (DISCORD_API *member_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t* count); + void (DISCORD_API *update_member)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction* transaction, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *send_lobby_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t* data, uint32_t data_length, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *get_search_query)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery** query); + void (DISCORD_API *search)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery* query, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count); + enum EDiscordResult (DISCORD_API *get_lobby_id)(struct IDiscordLobbyManager* manager, int32_t index, DiscordLobbyId* lobby_id); + void (DISCORD_API *connect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *disconnect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *connect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); + enum EDiscordResult (DISCORD_API *disconnect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); + enum EDiscordResult (DISCORD_API *flush_network)(struct IDiscordLobbyManager* manager); + enum EDiscordResult (DISCORD_API *open_network_channel)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t channel_id, bool reliable); + enum EDiscordResult (DISCORD_API *send_network_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); }; struct IDiscordNetworkEvents { - void (*on_message)(void* event_data, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); - void (*on_route_update)(void* event_data, const char* route_data); + void (DISCORD_API *on_message)(void* event_data, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); + void (DISCORD_API *on_route_update)(void* event_data, const char* route_data); }; struct IDiscordNetworkManager { /** * Get the local peer ID for this process. */ - void (*get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id); + void (DISCORD_API *get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id); /** * Send pending network messages. */ - enum EDiscordResult (*flush)(struct IDiscordNetworkManager* manager); + enum EDiscordResult (DISCORD_API *flush)(struct IDiscordNetworkManager* manager); /** * Open a connection to a remote peer. */ - enum EDiscordResult (*open_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); + enum EDiscordResult (DISCORD_API *open_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); /** * Update the route data for a connected peer. */ - enum EDiscordResult (*update_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); + enum EDiscordResult (DISCORD_API *update_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); /** * Close the connection to a remote peer. */ - enum EDiscordResult (*close_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id); + enum EDiscordResult (DISCORD_API *close_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id); /** * Open a message channel to a connected peer. */ - enum EDiscordResult (*open_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, bool reliable); + enum EDiscordResult (DISCORD_API *open_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, bool reliable); /** * Close a message channel to a connected peer. */ - enum EDiscordResult (*close_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id); + enum EDiscordResult (DISCORD_API *close_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id); /** * Send a message to a connected peer over an opened message channel. */ - enum EDiscordResult (*send_message)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); + enum EDiscordResult (DISCORD_API *send_message)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); }; struct IDiscordOverlayEvents { - void (*on_toggle)(void* event_data, bool locked); + void (DISCORD_API *on_toggle)(void* event_data, bool locked); }; struct IDiscordOverlayManager { - void (*is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled); - void (*is_locked)(struct IDiscordOverlayManager* manager, bool* locked); - void (*set_locked)(struct IDiscordOverlayManager* manager, bool locked, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*open_activity_invite)(struct IDiscordOverlayManager* manager, enum EDiscordActivityActionType type, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*open_guild_invite)(struct IDiscordOverlayManager* manager, const char* code, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*open_voice_settings)(struct IDiscordOverlayManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled); + void (DISCORD_API *is_locked)(struct IDiscordOverlayManager* manager, bool* locked); + void (DISCORD_API *set_locked)(struct IDiscordOverlayManager* manager, bool locked, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *open_activity_invite)(struct IDiscordOverlayManager* manager, enum EDiscordActivityActionType type, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *open_guild_invite)(struct IDiscordOverlayManager* manager, const char* code, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *open_voice_settings)(struct IDiscordOverlayManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *init_drawing_dxgi)(struct IDiscordOverlayManager* manager, IDXGISwapChain* swapchain, bool use_message_forwarding); + void (DISCORD_API *on_present)(struct IDiscordOverlayManager* manager); + void (DISCORD_API *forward_message)(struct IDiscordOverlayManager* manager, MSG* message); + void (DISCORD_API *key_event)(struct IDiscordOverlayManager* manager, bool down, const char* key_code, enum EDiscordKeyVariant variant); + void (DISCORD_API *char_event)(struct IDiscordOverlayManager* manager, const char* character); + void (DISCORD_API *mouse_button_event)(struct IDiscordOverlayManager* manager, uint8_t down, int32_t click_count, enum EDiscordMouseButton which, int32_t x, int32_t y); + void (DISCORD_API *mouse_motion_event)(struct IDiscordOverlayManager* manager, int32_t x, int32_t y); + void (DISCORD_API *ime_commit_text)(struct IDiscordOverlayManager* manager, const char* text); + void (DISCORD_API *ime_set_composition)(struct IDiscordOverlayManager* manager, const char* text, struct DiscordImeUnderline* underlines, uint32_t underlines_length, int32_t from, int32_t to); + void (DISCORD_API *ime_cancel_composition)(struct IDiscordOverlayManager* manager); + void (DISCORD_API *set_ime_composition_range_callback)(struct IDiscordOverlayManager* manager, void* on_ime_composition_range_changed_data, void (DISCORD_API *on_ime_composition_range_changed)(void* on_ime_composition_range_changed_data, int32_t from, int32_t to, struct DiscordRect* bounds, uint32_t bounds_length)); + void (DISCORD_API *set_ime_selection_bounds_callback)(struct IDiscordOverlayManager* manager, void* on_ime_selection_bounds_changed_data, void (DISCORD_API *on_ime_selection_bounds_changed)(void* on_ime_selection_bounds_changed_data, struct DiscordRect anchor, struct DiscordRect focus, bool is_anchor_first)); + bool (DISCORD_API *is_point_inside_click_zone)(struct IDiscordOverlayManager* manager, int32_t x, int32_t y); }; typedef void* IDiscordStorageEvents; struct IDiscordStorageManager { - enum EDiscordResult (*read)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, uint32_t* read); - void (*read_async)(struct IDiscordStorageManager* manager, const char* name, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); - void (*read_async_partial)(struct IDiscordStorageManager* manager, const char* name, uint64_t offset, uint64_t length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); - enum EDiscordResult (*write)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length); - void (*write_async)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - enum EDiscordResult (*delete_)(struct IDiscordStorageManager* manager, const char* name); - enum EDiscordResult (*exists)(struct IDiscordStorageManager* manager, const char* name, bool* exists); - void (*count)(struct IDiscordStorageManager* manager, int32_t* count); - enum EDiscordResult (*stat)(struct IDiscordStorageManager* manager, const char* name, struct DiscordFileStat* stat); - enum EDiscordResult (*stat_at)(struct IDiscordStorageManager* manager, int32_t index, struct DiscordFileStat* stat); - enum EDiscordResult (*get_path)(struct IDiscordStorageManager* manager, DiscordPath* path); + enum EDiscordResult (DISCORD_API *read)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, uint32_t* read); + void (DISCORD_API *read_async)(struct IDiscordStorageManager* manager, const char* name, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); + void (DISCORD_API *read_async_partial)(struct IDiscordStorageManager* manager, const char* name, uint64_t offset, uint64_t length, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); + enum EDiscordResult (DISCORD_API *write)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length); + void (DISCORD_API *write_async)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *delete_)(struct IDiscordStorageManager* manager, const char* name); + enum EDiscordResult (DISCORD_API *exists)(struct IDiscordStorageManager* manager, const char* name, bool* exists); + void (DISCORD_API *count)(struct IDiscordStorageManager* manager, int32_t* count); + enum EDiscordResult (DISCORD_API *stat)(struct IDiscordStorageManager* manager, const char* name, struct DiscordFileStat* stat); + enum EDiscordResult (DISCORD_API *stat_at)(struct IDiscordStorageManager* manager, int32_t index, struct DiscordFileStat* stat); + enum EDiscordResult (DISCORD_API *get_path)(struct IDiscordStorageManager* manager, DiscordPath* path); }; struct IDiscordStoreEvents { - void (*on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement); - void (*on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement); + void (DISCORD_API *on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement); + void (DISCORD_API *on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement); }; struct IDiscordStoreManager { - void (*fetch_skus)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*count_skus)(struct IDiscordStoreManager* manager, int32_t* count); - enum EDiscordResult (*get_sku)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, struct DiscordSku* sku); - enum EDiscordResult (*get_sku_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordSku* sku); - void (*fetch_entitlements)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count); - enum EDiscordResult (*get_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake entitlement_id, struct DiscordEntitlement* entitlement); - enum EDiscordResult (*get_entitlement_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordEntitlement* entitlement); - enum EDiscordResult (*has_sku_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, bool* has_entitlement); - void (*start_purchase)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *fetch_skus)(struct IDiscordStoreManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *count_skus)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (DISCORD_API *get_sku)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, struct DiscordSku* sku); + enum EDiscordResult (DISCORD_API *get_sku_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordSku* sku); + void (DISCORD_API *fetch_entitlements)(struct IDiscordStoreManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (DISCORD_API *get_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake entitlement_id, struct DiscordEntitlement* entitlement); + enum EDiscordResult (DISCORD_API *get_entitlement_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordEntitlement* entitlement); + enum EDiscordResult (DISCORD_API *has_sku_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, bool* has_entitlement); + void (DISCORD_API *start_purchase)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); }; struct IDiscordVoiceEvents { - void (*on_settings_update)(void* event_data); + void (DISCORD_API *on_settings_update)(void* event_data); }; struct IDiscordVoiceManager { - enum EDiscordResult (*get_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode* input_mode); - void (*set_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode input_mode, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - enum EDiscordResult (*is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute); - enum EDiscordResult (*set_self_mute)(struct IDiscordVoiceManager* manager, bool mute); - enum EDiscordResult (*is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf); - enum EDiscordResult (*set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf); - enum EDiscordResult (*is_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool* mute); - enum EDiscordResult (*set_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool mute); - enum EDiscordResult (*get_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t* volume); - enum EDiscordResult (*set_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t volume); + enum EDiscordResult (DISCORD_API *get_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode* input_mode); + void (DISCORD_API *set_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode input_mode, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (DISCORD_API *is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute); + enum EDiscordResult (DISCORD_API *set_self_mute)(struct IDiscordVoiceManager* manager, bool mute); + enum EDiscordResult (DISCORD_API *is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf); + enum EDiscordResult (DISCORD_API *set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf); + enum EDiscordResult (DISCORD_API *is_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool* mute); + enum EDiscordResult (DISCORD_API *set_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool mute); + enum EDiscordResult (DISCORD_API *get_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t* volume); + enum EDiscordResult (DISCORD_API *set_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t volume); }; struct IDiscordAchievementEvents { - void (*on_user_achievement_update)(void* event_data, struct DiscordUserAchievement* user_achievement); + void (DISCORD_API *on_user_achievement_update)(void* event_data, struct DiscordUserAchievement* user_achievement); }; struct IDiscordAchievementManager { - void (*set_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake achievement_id, uint8_t percent_complete, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*fetch_user_achievements)(struct IDiscordAchievementManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); - void (*count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count); - enum EDiscordResult (*get_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake user_achievement_id, struct DiscordUserAchievement* user_achievement); - enum EDiscordResult (*get_user_achievement_at)(struct IDiscordAchievementManager* manager, int32_t index, struct DiscordUserAchievement* user_achievement); + void (DISCORD_API *set_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake achievement_id, uint8_t percent_complete, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *fetch_user_achievements)(struct IDiscordAchievementManager* manager, void* callback_data, void (DISCORD_API *callback)(void* callback_data, enum EDiscordResult result)); + void (DISCORD_API *count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count); + enum EDiscordResult (DISCORD_API *get_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake user_achievement_id, struct DiscordUserAchievement* user_achievement); + enum EDiscordResult (DISCORD_API *get_user_achievement_at)(struct IDiscordAchievementManager* manager, int32_t index, struct DiscordUserAchievement* user_achievement); }; typedef void* IDiscordCoreEvents; struct IDiscordCore { - void (*destroy)(struct IDiscordCore* core); - enum EDiscordResult (*run_callbacks)(struct IDiscordCore* core); - void (*set_log_hook)(struct IDiscordCore* core, enum EDiscordLogLevel min_level, void* hook_data, void (*hook)(void* hook_data, enum EDiscordLogLevel level, const char* message)); - struct IDiscordApplicationManager* (*get_application_manager)(struct IDiscordCore* core); - struct IDiscordUserManager* (*get_user_manager)(struct IDiscordCore* core); - struct IDiscordImageManager* (*get_image_manager)(struct IDiscordCore* core); - struct IDiscordActivityManager* (*get_activity_manager)(struct IDiscordCore* core); - struct IDiscordRelationshipManager* (*get_relationship_manager)(struct IDiscordCore* core); - struct IDiscordLobbyManager* (*get_lobby_manager)(struct IDiscordCore* core); - struct IDiscordNetworkManager* (*get_network_manager)(struct IDiscordCore* core); - struct IDiscordOverlayManager* (*get_overlay_manager)(struct IDiscordCore* core); - struct IDiscordStorageManager* (*get_storage_manager)(struct IDiscordCore* core); - struct IDiscordStoreManager* (*get_store_manager)(struct IDiscordCore* core); - struct IDiscordVoiceManager* (*get_voice_manager)(struct IDiscordCore* core); - struct IDiscordAchievementManager* (*get_achievement_manager)(struct IDiscordCore* core); + void (DISCORD_API *destroy)(struct IDiscordCore* core); + enum EDiscordResult (DISCORD_API *run_callbacks)(struct IDiscordCore* core); + void (DISCORD_API *set_log_hook)(struct IDiscordCore* core, enum EDiscordLogLevel min_level, void* hook_data, void (DISCORD_API *hook)(void* hook_data, enum EDiscordLogLevel level, const char* message)); + struct IDiscordApplicationManager* (DISCORD_API *get_application_manager)(struct IDiscordCore* core); + struct IDiscordUserManager* (DISCORD_API *get_user_manager)(struct IDiscordCore* core); + struct IDiscordImageManager* (DISCORD_API *get_image_manager)(struct IDiscordCore* core); + struct IDiscordActivityManager* (DISCORD_API *get_activity_manager)(struct IDiscordCore* core); + struct IDiscordRelationshipManager* (DISCORD_API *get_relationship_manager)(struct IDiscordCore* core); + struct IDiscordLobbyManager* (DISCORD_API *get_lobby_manager)(struct IDiscordCore* core); + struct IDiscordNetworkManager* (DISCORD_API *get_network_manager)(struct IDiscordCore* core); + struct IDiscordOverlayManager* (DISCORD_API *get_overlay_manager)(struct IDiscordCore* core); + struct IDiscordStorageManager* (DISCORD_API *get_storage_manager)(struct IDiscordCore* core); + struct IDiscordStoreManager* (DISCORD_API *get_store_manager)(struct IDiscordCore* core); + struct IDiscordVoiceManager* (DISCORD_API *get_voice_manager)(struct IDiscordCore* core); + struct IDiscordAchievementManager* (DISCORD_API *get_achievement_manager)(struct IDiscordCore* core); }; struct DiscordCreateParams { @@ -644,10 +727,10 @@ void DiscordCreateParamsSetDefault(struct DiscordCreateParams* params) params->achievement_version = DISCORD_ACHIEVEMENT_MANAGER_VERSION; } -enum EDiscordResult DiscordCreate(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result); +enum EDiscordResult DISCORD_API DiscordCreate(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/src/include/glad/glad.h b/src/include/glad/glad.h new file mode 100644 index 000000000..0b4d36656 --- /dev/null +++ b/src/include/glad/glad.h @@ -0,0 +1,1803 @@ +/* + + OpenGL loader generated by glad 0.1.34 on Sat Dec 4 18:46:02 2021. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.0 + Profile: core + Extensions: + GL_ARB_buffer_storage, + GL_ARB_debug_output, + GL_ARB_sync + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="core" --api="gl=3.0" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_debug_output,GL_ARB_sync" + Online: + https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.0&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_debug_output&extensions=GL_ARB_sync +*/ + + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl_h_ +#error OpenGL header already included, remove this include, glad already provides it +#endif +#define __gl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define APIENTRY __stdcall +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(_WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI struct gladGLversionStruct GLVersion; + +GLAPI int gladLoadGL(void); + +GLAPI int gladLoadGLLoader(GLADloadproc); + +#include +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +typedef khronos_intptr_t GLintptr; +typedef khronos_intptr_t GLintptrARB; +typedef khronos_ssize_t GLsizeiptr; +typedef khronos_ssize_t GLsizeiptrARB; +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (APIENTRY *GLVULKANPROCNV)(void); +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_REPEAT 0x2901 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DOUBLE 0x140A +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(void); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(void); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 +GLAPI int GLAD_GL_ARB_buffer_storage; +typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage; +#define glBufferStorage glad_glBufferStorage +#endif +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +GLAPI int GLAD_GL_ARB_debug_output; +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB; +#define glDebugMessageControlARB glad_glDebugMessageControlARB +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB; +#define glDebugMessageInsertARB glad_glDebugMessageInsertARB +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void *userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB; +#define glDebugMessageCallbackARB glad_glDebugMessageCallbackARB +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB; +#define glGetDebugMessageLogARB glad_glGetDebugMessageLogARB +#endif +#ifndef GL_ARB_sync +#define GL_ARB_sync 1 +GLAPI int GLAD_GL_ARB_sync; +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/lzf.h b/src/include/lzf.h index 919b6e6be..98e038f31 100644 --- a/src/include/lzf.h +++ b/src/include/lzf.h @@ -1,16 +1,16 @@ /* * Copyright (c) 2000-2008 Marc Alexander Lehmann - * + * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -73,7 +73,7 @@ * and lzf_c.c. * */ -unsigned int +unsigned int lzf_compress (const void *const in_data, unsigned int in_len, void *out_data, unsigned int out_len); @@ -92,7 +92,7 @@ lzf_compress (const void *const in_data, unsigned int in_len, * * This function is very fast, about as fast as a copying loop. */ -unsigned int +unsigned int lzf_decompress (const void *const in_data, unsigned int in_len, void *out_data, unsigned int out_len); diff --git a/src/include/minitrace/minitrace.h b/src/include/minitrace/minitrace.h new file mode 100644 index 000000000..2047eedb7 --- /dev/null +++ b/src/include/minitrace/minitrace.h @@ -0,0 +1,270 @@ +// Minitrace +// +// Copyright 2014 by Henrik Rydgård +// http://www.github.com/hrydgard/minitrace +// Released under the MIT license. +// +// Ultra-light dependency free library for performance tracing C/C++ applications. +// Produces traces compatible with Google Chrome's trace viewer. +// Simply open "about:tracing" in Chrome and load the produced JSON. +// +// This contains far less template magic than the original libraries from Chrome +// because this is meant to be usable from C. +// +// See README.md for a tutorial. +// +// The trace format is documented here: +// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit +// More: +// http://www.altdevblogaday.com/2012/08/21/using-chrometracing-to-view-your-inline-profiling-data/ + +#ifndef MINITRACE_H +#define MINITRACE_H + +#include + +// If MTR_ENABLED is not defined, Minitrace does nothing and has near zero overhead. +// Preferably, set this flag in your build system. If you can't just uncomment this line. +// #define MTR_ENABLED + +// By default, will collect up to 1000000 events, then you must flush. +// It's recommended that you simply call mtr_flush on a background thread +// occasionally. It's safe...ish. +#define INTERNAL_MINITRACE_BUFFER_SIZE 1000000 + +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes Minitrace. Must be called very early during startup of your executable, +// before any MTR_ statements. +void mtr_init(const char *json_file); +// Same as above, but allows passing in a custom stream (FILE *), as returned by +// fopen(). It should be opened for writing, preferably in binary mode to avoid +// processing of line endings (i.e. the "wb" mode). +void mtr_init_from_stream(void *stream); + +// Shuts down minitrace cleanly, flushing the trace buffer. +void mtr_shutdown(void); + +// Lets you enable and disable Minitrace at runtime. +// May cause strange discontinuities in the output. +// Minitrace is enabled on startup by default. +void mtr_start(void); +void mtr_stop(void); + +// Flushes the collected data to disk, clearing the buffer for new data. +void mtr_flush(void); + +// Returns the current time in seconds. Used internally by Minitrace. No caching. +double mtr_time_s(void); + +// Registers a handler that will flush the trace on Ctrl+C. +// Works on Linux and MacOSX, and in Win32 console applications. +void mtr_register_sigint_handler(void); + +// Utility function that should rarely be used. +// If str is semi dynamic, store it permanently in a small pool so we don't need to malloc it. +// The pool fills up fast though and performance isn't great. +// Returns a fixed string if the pool is full. +const char *mtr_pool_string(const char *str); + +// Commented-out types will be supported in the future. +typedef enum { + MTR_ARG_TYPE_NONE = 0, + MTR_ARG_TYPE_INT = 1, // I + // MTR_ARG_TYPE_FLOAT = 2, // TODO + // MTR_ARG_TYPE_DOUBLE = 3, // TODO + MTR_ARG_TYPE_STRING_CONST = 8, // C + MTR_ARG_TYPE_STRING_COPY = 9, + // MTR_ARG_TYPE_JSON_COPY = 10, +} mtr_arg_type; + +// TODO: Add support for more than one argument (metadata) per event +// Having more costs speed and memory. +#define MTR_MAX_ARGS 1 + +// Only use the macros to call these. +void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id); +void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value); + +#ifdef MTR_ENABLED + +// c - category. Can be filtered by in trace viewer (or at least that's the intention). +// A good use is to pass __FILE__, there are macros further below that will do it for you. +// n - name. Pass __FUNCTION__ in most cases, unless you are marking up parts of one. + +// Scopes. In C++, use MTR_SCOPE. In C, always match them within the same scope. +#define MTR_BEGIN(c, n) internal_mtr_raw_event(c, n, 'B', 0) +#define MTR_END(c, n) internal_mtr_raw_event(c, n, 'E', 0) +#define MTR_SCOPE(c, n) MTRScopedTrace ____mtr_scope(c, n) +#define MTR_SCOPE_LIMIT(c, n, l) MTRScopedTraceLimit ____mtr_scope(c, n, l) + +// Async events. Can span threads. ID identifies which events to connect in the view. +#define MTR_START(c, n, id) internal_mtr_raw_event(c, n, 'S', (void *)(id)) +#define MTR_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 'T', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step)) +#define MTR_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'F', (void *)(id)) + +// Flow events. Like async events, but displayed in a more fancy way in the viewer. +#define MTR_FLOW_START(c, n, id) internal_mtr_raw_event(c, n, 's', (void *)(id)) +#define MTR_FLOW_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 't', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step)) +#define MTR_FLOW_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'f', (void *)(id)) + +// The same macros, but with a single named argument which shows up as metadata in the viewer. +// _I for int. +// _C is for a const string arg. +// _S will copy the string, freeing on flush (expensive but sometimes necessary). +// but required if the string was generated dynamically. + +// Note that it's fine to match BEGIN_S with END and BEGIN with END_S, etc. +#define MTR_BEGIN_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) +#define MTR_END_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) +#define MTR_SCOPE_C(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) + +#define MTR_BEGIN_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) +#define MTR_END_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) +#define MTR_SCOPE_S(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) + +#define MTR_BEGIN_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) +#define MTR_END_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) +#define MTR_SCOPE_I(c, n, aname, aintval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) + +// Instant events. For things with no duration. +#define MTR_INSTANT(c, n) internal_mtr_raw_event(c, n, 'I', 0) +#define MTR_INSTANT_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) +#define MTR_INSTANT_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_INT, aname, (void *)(aintval)) + +// Counters (can't do multi-value counters yet) +#define MTR_COUNTER(c, n, val) internal_mtr_raw_event_arg(c, n, 'C', 0, MTR_ARG_TYPE_INT, n, (void *)(intptr_t)(val)) + +// Metadata. Call at the start preferably. Must be const strings. + +#define MTR_META_PROCESS_NAME(n) internal_mtr_raw_event_arg("", "process_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n)) +#define MTR_META_THREAD_NAME(n) internal_mtr_raw_event_arg("", "thread_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n)) +#define MTR_META_THREAD_SORT_INDEX(i) internal_mtr_raw_event_arg("", "thread_sort_index", 'M', 0, MTR_ARG_TYPE_INT, "sort_index", (void *)(i)) + +#else + +#define MTR_BEGIN(c, n) +#define MTR_END(c, n) +#define MTR_SCOPE(c, n) +#define MTR_START(c, n, id) +#define MTR_STEP(c, n, id, step) +#define MTR_FINISH(c, n, id) +#define MTR_FLOW_START(c, n, id) +#define MTR_FLOW_STEP(c, n, id, step) +#define MTR_FLOW_FINISH(c, n, id) +#define MTR_INSTANT(c, n) + +#define MTR_BEGIN_C(c, n, aname, astrval) +#define MTR_END_C(c, n, aname, astrval) +#define MTR_SCOPE_C(c, n, aname, astrval) + +#define MTR_BEGIN_S(c, n, aname, astrval) +#define MTR_END_S(c, n, aname, astrval) +#define MTR_SCOPE_S(c, n, aname, astrval) + +#define MTR_BEGIN_I(c, n, aname, aintval) +#define MTR_END_I(c, n, aname, aintval) +#define MTR_SCOPE_I(c, n, aname, aintval) + +#define MTR_INSTANT(c, n) +#define MTR_INSTANT_C(c, n, aname, astrval) +#define MTR_INSTANT_I(c, n, aname, aintval) + +// Counters (can't do multi-value counters yet) +#define MTR_COUNTER(c, n, val) + +// Metadata. Call at the start preferably. Must be const strings. + +#define MTR_META_PROCESS_NAME(n) + +#define MTR_META_THREAD_NAME(n) +#define MTR_META_THREAD_SORT_INDEX(i) + +#endif + +// Shortcuts for simple function timing with automatic categories and names. + +#define MTR_BEGIN_FUNC() MTR_BEGIN(__FILE__, __FUNCTION__) +#define MTR_END_FUNC() MTR_END(__FILE__, __FUNCTION__) +#define MTR_SCOPE_FUNC() MTR_SCOPE(__FILE__, __FUNCTION__) +#define MTR_INSTANT_FUNC() MTR_INSTANT(__FILE__, __FUNCTION__) +#define MTR_SCOPE_FUNC_LIMIT_S(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, l) +#define MTR_SCOPE_FUNC_LIMIT_MS(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, (double)l * 0.000001) + +// Same, but with a single argument of the usual types. +#define MTR_BEGIN_FUNC_S(aname, arg) MTR_BEGIN_S(__FILE__, __FUNCTION__, aname, arg) +#define MTR_END_FUNC_S(aname, arg) MTR_END_S(__FILE__, __FUNCTION__, aname, arg) +#define MTR_SCOPE_FUNC_S(aname, arg) MTR_SCOPE_S(__FILE__, __FUNCTION__, aname, arg) + +#define MTR_BEGIN_FUNC_C(aname, arg) MTR_BEGIN_C(__FILE__, __FUNCTION__, aname, arg) +#define MTR_END_FUNC_C(aname, arg) MTR_END_C(__FILE__, __FUNCTION__, aname, arg) +#define MTR_SCOPE_FUNC_C(aname, arg) MTR_SCOPE_C(__FILE__, __FUNCTION__, aname, arg) + +#define MTR_BEGIN_FUNC_I(aname, arg) MTR_BEGIN_I(__FILE__, __FUNCTION__, aname, arg) +#define MTR_END_FUNC_I(aname, arg) MTR_END_I(__FILE__, __FUNCTION__, aname, arg) +#define MTR_SCOPE_FUNC_I(aname, arg) MTR_SCOPE_I(__FILE__, __FUNCTION__, aname, arg) + +#ifdef __cplusplus +} + +#ifdef MTR_ENABLED +// These are optimized to use X events (combined B and E). Much easier to do in C++ than in C. +class MTRScopedTrace { +public: + MTRScopedTrace(const char *category, const char *name) + : category_(category), name_(name) { + start_time_ = mtr_time_s(); + } + ~MTRScopedTrace() { + internal_mtr_raw_event(category_, name_, 'X', &start_time_); + } + +private: + const char *category_; + const char *name_; + double start_time_; +}; + +// Only outputs a block if execution time exceeded the limit. +// TODO: This will effectively call mtr_time_s twice at the end, which is bad. +class MTRScopedTraceLimit { +public: + MTRScopedTraceLimit(const char *category, const char *name, double limit_s) + : category_(category), name_(name), limit_(limit_s) { + start_time_ = mtr_time_s(); + } + ~MTRScopedTraceLimit() { + double end_time = mtr_time_s(); + if (end_time - start_time_ >= limit_) { + internal_mtr_raw_event(category_, name_, 'X', &start_time_); + } + } + +private: + const char *category_; + const char *name_; + double start_time_; + double limit_; +}; + +class MTRScopedTraceArg { +public: + MTRScopedTraceArg(const char *category, const char *name, mtr_arg_type arg_type, const char *arg_name, void *arg_value) + : category_(category), name_(name) { + internal_mtr_raw_event_arg(category, name, 'B', 0, arg_type, arg_name, arg_value); + } + ~MTRScopedTraceArg() { + internal_mtr_raw_event(category_, name_, 'E', 0); + } + +private: + const char *category_; + const char *name_; +}; +#endif + +#endif + +#endif diff --git a/src/include/nukedopl.h b/src/include/nukedopl.h deleted file mode 100644 index 6b3f09228..000000000 --- a/src/include/nukedopl.h +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// Nuked OPL3 emulator. -// Thanks: -// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): -// Feedback and Rhythm part calculation information. -// forums.submarine.org.uk(carbon14, opl3): -// Tremolo and phase generator calculation information. -// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): -// OPL2 ROMs. -// siliconpr0n.org(John McMaster, digshadow): -// YMF262 and VRC VII decaps and die shots. -// -// version: 1.8 -// - -#ifndef NUKEDOPL_H -#define NUKEDOPL_H -#define OPL_WRITEBUF_SIZE 1024 -#define OPL_WRITEBUF_DELAY 1 - -//#include "dosbox.h" -#include -typedef signed int Bits; -typedef unsigned int Bitu; -typedef int8_t Bit8s; -typedef uint8_t Bit8u; -typedef int16_t Bit16s; -typedef uint16_t Bit16u; -typedef int32_t Bit32s; -typedef uint32_t Bit32u; -typedef int64_t Bit64s; -typedef uint64_t Bit64u; - -struct opl3_slot; -struct opl3_channel; -struct opl3_writebuf; -struct opl3_chip; - -struct opl3_slot { - struct opl3_channel *channel; - struct opl3_chip *chip; - Bit16s out; - Bit16s fbmod; - Bit16s *mod; - Bit16s prout; - Bit16s eg_rout; - Bit16s eg_out; - Bit8u eg_inc; - Bit8u eg_gen; - Bit8u eg_rate; - Bit8u eg_ksl; - Bit8u *trem; - Bit8u reg_vib; - Bit8u reg_type; - Bit8u reg_ksr; - Bit8u reg_mult; - Bit8u reg_ksl; - Bit8u reg_tl; - Bit8u reg_ar; - Bit8u reg_dr; - Bit8u reg_sl; - Bit8u reg_rr; - Bit8u reg_wf; - Bit8u key; - Bit32u pg_reset; - Bit32u pg_phase; - Bit16u pg_phase_out; - Bit8u slot_num; -}; - -struct opl3_channel { - struct opl3_slot *slots[2]; - struct opl3_channel *pair; - struct opl3_chip *chip; - Bit16s *out[4]; - Bit8u chtype; - Bit16u f_num; - Bit8u block; - Bit8u fb; - Bit8u con; - Bit8u alg; - Bit8u ksv; - Bit16u cha, chb; - Bit8u ch_num; -}; - -struct opl3_writebuf { - Bit64u time; - Bit16u reg; - Bit8u data; -}; - -struct opl3_chip { - struct opl3_channel channel[18]; - struct opl3_slot slot[36]; - Bit16u timer; - Bit64u eg_timer; - Bit8u eg_timerrem; - Bit8u eg_state; - Bit8u eg_add; - Bit8u newm; - Bit8u nts; - Bit8u rhy; - Bit8u vibpos; - Bit8u vibshift; - Bit8u tremolo; - Bit8u tremolopos; - Bit8u tremoloshift; - Bit32u noise; - Bit16s zeromod; - Bit32s mixbuff[2]; - Bit8u rm_hh_bit2; - Bit8u rm_hh_bit3; - Bit8u rm_hh_bit7; - Bit8u rm_hh_bit8; - Bit8u rm_tc_bit3; - Bit8u rm_tc_bit5; - //OPL3L - Bit32s rateratio; - Bit32s samplecnt; - Bit16s oldsamples[2]; - Bit16s samples[2]; - - Bit64u writebuf_samplecnt; - Bit32u writebuf_cur; - Bit32u writebuf_last; - Bit64u writebuf_lasttime; - struct opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; -}; - -void OPL3_Generate(struct opl3_chip *chip, Bit16s *buf); -void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf); -void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate); -Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val); -void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples); -#endif diff --git a/src/include/slirp/bootp.h b/src/include/slirp/bootp.h deleted file mode 100644 index b2ee26e95..000000000 --- a/src/include/slirp/bootp.h +++ /dev/null @@ -1,121 +0,0 @@ -/* bootp/dhcp defines */ - -#define BOOTP_SERVER 67 -#define BOOTP_CLIENT 68 - -#define BOOTP_REQUEST 1 -#define BOOTP_REPLY 2 - -#define RFC1533_COOKIE 99, 130, 83, 99 -#define RFC1533_PAD 0 -#define RFC1533_NETMASK 1 -#define RFC1533_TIMEOFFSET 2 -#define RFC1533_GATEWAY 3 -#define RFC1533_TIMESERVER 4 -#define RFC1533_IEN116NS 5 -#define RFC1533_DNS 6 -#define RFC1533_LOGSERVER 7 -#define RFC1533_COOKIESERVER 8 -#define RFC1533_LPRSERVER 9 -#define RFC1533_IMPRESSSERVER 10 -#define RFC1533_RESOURCESERVER 11 -#define RFC1533_HOSTNAME 12 -#define RFC1533_BOOTFILESIZE 13 -#define RFC1533_MERITDUMPFILE 14 -#define RFC1533_DOMAINNAME 15 -#define RFC1533_SWAPSERVER 16 -#define RFC1533_ROOTPATH 17 -#define RFC1533_EXTENSIONPATH 18 -#define RFC1533_IPFORWARDING 19 -#define RFC1533_IPSOURCEROUTING 20 -#define RFC1533_IPPOLICYFILTER 21 -#define RFC1533_IPMAXREASSEMBLY 22 -#define RFC1533_IPTTL 23 -#define RFC1533_IPMTU 24 -#define RFC1533_IPMTUPLATEAU 25 -#define RFC1533_INTMTU 26 -#define RFC1533_INTLOCALSUBNETS 27 -#define RFC1533_INTBROADCAST 28 -#define RFC1533_INTICMPDISCOVER 29 -#define RFC1533_INTICMPRESPOND 30 -#define RFC1533_INTROUTEDISCOVER 31 -#define RFC1533_INTROUTESOLICIT 32 -#define RFC1533_INTSTATICROUTES 33 -#define RFC1533_LLTRAILERENCAP 34 -#define RFC1533_LLARPCACHETMO 35 -#define RFC1533_LLETHERNETENCAP 36 -#define RFC1533_TCPTTL 37 -#define RFC1533_TCPKEEPALIVETMO 38 -#define RFC1533_TCPKEEPALIVEGB 39 -#define RFC1533_NISDOMAIN 40 -#define RFC1533_NISSERVER 41 -#define RFC1533_NTPSERVER 42 -#define RFC1533_VENDOR 43 -#define RFC1533_NBNS 44 -#define RFC1533_NBDD 45 -#define RFC1533_NBNT 46 -#define RFC1533_NBSCOPE 47 -#define RFC1533_XFS 48 -#define RFC1533_XDM 49 - -#define RFC2132_REQ_ADDR 50 -#define RFC2132_LEASE_TIME 51 -#define RFC2132_MSG_TYPE 53 -#define RFC2132_SRV_ID 54 -#define RFC2132_PARAM_LIST 55 -#define RFC2132_MAX_SIZE 57 -#define RFC2132_RENEWAL_TIME 58 -#define RFC2132_REBIND_TIME 59 - -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPACK 5 - -#define RFC1533_VENDOR_MAJOR 0 -#define RFC1533_VENDOR_MINOR 0 - -#define RFC1533_VENDOR_MAGIC 128 -#define RFC1533_VENDOR_ADDPARM 129 -#define RFC1533_VENDOR_ETHDEV 130 -#define RFC1533_VENDOR_HOWTO 132 -#define RFC1533_VENDOR_MNUOPTS 160 -#define RFC1533_VENDOR_SELECTION 176 -#define RFC1533_VENDOR_MOTD 184 -#define RFC1533_VENDOR_NUMOFMOTD 8 -#define RFC1533_VENDOR_IMG 192 -#define RFC1533_VENDOR_NUMOFIMG 16 - -#define RFC1533_END 255 -#define BOOTP_VENDOR_LEN 64 -#define DHCP_OPT_LEN 312 - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct bootp_t { - struct ip ip; - struct udphdr udp; - uint8_t bp_op; - uint8_t bp_htype; - uint8_t bp_hlen; - uint8_t bp_hops; - uint32_t bp_xid; - uint16_t bp_secs; - uint16_t unused; - struct in_addr bp_ciaddr; - struct in_addr bp_yiaddr; - struct in_addr bp_siaddr; - struct in_addr bp_giaddr; - uint8_t bp_hwaddr[16]; - uint8_t bp_sname[64]; - uint8_t bp_file[128]; - uint8_t bp_vend[DHCP_OPT_LEN]; -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -void bootp_input(struct SLIRPmbuf *m); diff --git a/src/include/slirp/config-host.h b/src/include/slirp/config-host.h deleted file mode 100644 index 2983fc727..000000000 --- a/src/include/slirp/config-host.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Automatically generated by configure - do not modify */ -#define CONFIG_QEMU_SHAREDIR "/c/Program Files/Qemu" -#define HOST_I386 1 -#define HOST_LONG_BITS 32 -#define CONFIG_WIN32 1 -#define CONFIG_GDBSTUB 1 -#define CONFIG_SLIRP 1 -#define QEMU_VERSION "0.9.0" -#define CONFIG_UNAME_RELEASE "" diff --git a/src/include/slirp/config.h b/src/include/slirp/config.h deleted file mode 100644 index d9043ae85..000000000 --- a/src/include/slirp/config.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Automatically generated by configure - do not modify */ -#include "config-host.h" -#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386" -#define TARGET_ARCH "i386" -#define TARGET_I386 1 -#define USE_KQEMU 1 -#define CONFIG_SOFTMMU 1 -#define CONFIG_SDL 1 -#define HAVE_STRDUP 1 diff --git a/src/include/slirp/ctl.h b/src/include/slirp/ctl.h deleted file mode 100644 index 4a8576dc1..000000000 --- a/src/include/slirp/ctl.h +++ /dev/null @@ -1,7 +0,0 @@ -#define CTL_CMD 0 -#define CTL_EXEC 1 -#define CTL_ALIAS 2 -#define CTL_DNS 3 - -#define CTL_SPECIAL "10.0.2.0" -#define CTL_LOCAL "10.0.2.15" diff --git a/src/include/slirp/debug.h b/src/include/slirp/debug.h deleted file mode 100644 index a1eafa130..000000000 --- a/src/include/slirp/debug.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#define PRN_STDERR 1 -#define PRN_SPRINTF 2 - -extern FILE *dfd; -extern FILE *lfd; -extern int dostats; -extern int slirp_debug; - -#define DBG_CALL 0x1 -#define DBG_MISC 0x2 -#define DBG_ERROR 0x4 -#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR - -#ifdef SLIRP_DEBUG -#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } -#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } -#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } -#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } -#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } - - -#else - -#define DEBUG_CALL(x) -#define DEBUG_ARG(x, y) -#define DEBUG_ARGS(x) -#define DEBUG_MISC(x) -#define DEBUG_ERROR(x) - -#endif - -void debug_init _P((char *, int)); -void allttystats _P((void)); -void ipstats _P((void)); -void vjstats _P((void)); -void tcpstats _P((void)); -void udpstats _P((void)); -void icmpstats _P((void)); -void mbufstats _P((void)); -void sockstats _P((void)); -void slirp_exit _P((int)); - diff --git a/src/include/slirp/icmp_var.h b/src/include/slirp/icmp_var.h deleted file mode 100644 index 9af222fb7..000000000 --- a/src/include/slirp/icmp_var.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 - * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp - */ - -#ifndef _NETINET_ICMP_VAR_H_ -#define _NETINET_ICMP_VAR_H_ - -/* - * Variables related to this implementation - * of the internet control message protocol. - */ -struct icmpstat { -/* statistics related to input messages processed */ - u_long icps_received; /* #ICMP packets received */ - u_long icps_tooshort; /* packet < ICMP_MINLEN */ - u_long icps_checksum; /* bad checksum */ - u_long icps_notsupp; /* #ICMP packets not supported */ - u_long icps_badtype; /* #with bad type feild */ - u_long icps_reflect; /* number of responses */ -}; - -/* - * Names for ICMP sysctl objects - */ -#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ -#define ICMPCTL_STATS 2 /* statistics (read-only) */ -#define ICMPCTL_MAXID 3 - -#define ICMPCTL_NAMES { \ - { 0, 0 }, \ - { "maskrepl", CTLTYPE_INT }, \ - { "stats", CTLTYPE_STRUCT }, \ -} - -extern struct icmpstat icmpstat; - -#endif diff --git a/src/include/slirp/if.h b/src/include/slirp/if.h deleted file mode 100644 index 85a5a96d2..000000000 --- a/src/include/slirp/if.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _IF_H_ -#define _IF_H_ - -#define IF_COMPRESS 0x01 /* We want compression */ -#define IF_NOCOMPRESS 0x02 /* Do not do compression */ -#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ -#define IF_NOCIDCOMP 0x08 /* CID compression */ - -/* Needed for FreeBSD */ -#undef if_mtu -extern int if_mtu; -extern int if_mru; /* MTU and MRU */ -extern int if_comp; /* Flags for compression */ -extern int if_maxlinkhdr; -extern int if_queued; /* Number of packets queued so far */ -extern int if_thresh; /* Number of packets queued before we start sending - * (to prevent allocing too many SLIRPmbufs) */ - -extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ -extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ -extern struct SLIRPmbuf *next_m; - -#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) - -/* Interface statistics */ -struct slirp_ifstats { - u_int out_pkts; /* Output packets */ - u_int out_bytes; /* Output bytes */ - u_int out_errpkts; /* Output Error Packets */ - u_int out_errbytes; /* Output Error Bytes */ - u_int in_pkts; /* Input packets */ - u_int in_bytes; /* Input bytes */ - u_int in_errpkts; /* Input Error Packets */ - u_int in_errbytes; /* Input Error Bytes */ - - u_int bytes_saved; /* Number of bytes that compression "saved" */ - /* ie: number of bytes that didn't need to be sent over the link - * because of compression */ - - u_int in_mbad; /* Bad incoming packets */ -}; - -#endif diff --git a/src/include/slirp/ip.h b/src/include/slirp/ip.h deleted file mode 100644 index f21178360..000000000 --- a/src/include/slirp/ip.h +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip.h 8.1 (Berkeley) 6/10/93 - * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp - */ - -#ifndef _IP_H_ -#define _IP_H_ - -#ifdef WORDS_BIGENDIAN -# ifndef NTOHL -# define NTOHL(d) -# endif -# ifndef NTOHS -# define NTOHS(d) -# endif -# ifndef HTONL -# define HTONL(d) -# endif -# ifndef HTONS -# define HTONS(d) -# endif -#else -# ifndef NTOHL -# define NTOHL(d) ((d) = ntohl((d))) -# endif -# ifndef NTOHS -# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) -# endif -# ifndef HTONL -# define HTONL(d) ((d) = htonl((d))) -# endif -# ifndef HTONS -# define HTONS(d) ((d) = htons((u_int16_t)(d))) -# endif -#endif - -typedef u_int32_t n_long; /* long as received from the net */ - -/* - * Definitions for internet protocol version 4. - * Per RFC 791, September 1981. - */ -#define IPVERSION 4 - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif - -/* - * Structure of an internet header, naked of options. - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct ip { -#ifdef WORDS_BIGENDIAN - u_char ip_v:4, /* version */ - ip_hl:4; /* header length */ -#else - u_char ip_hl:4, /* header length */ - ip_v:4; /* version */ -#endif - u_int8_t ip_tos; /* type of service */ - u_int16_t ip_len; /* total length */ - u_int16_t ip_id; /* identification */ - u_int16_t ip_off; /* fragment offset field */ -#define IP_DF 0x4000 /* don't fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - u_int8_t ip_ttl; /* time to live */ - u_int8_t ip_p; /* protocol */ - u_int16_t ip_sum; /* checksum */ - struct in_addr ip_src,ip_dst; /* source and dest address */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) //WAS 0 -#endif - -#define IP_MAXPACKET 65535 /* maximum packet size */ - -/* - * Definitions for IP type of service (ip_tos) - */ -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 - -/* - * Definitions for options. - */ -#define IPOPT_COPIED(o) ((o)&0x80) -#define IPOPT_CLASS(o) ((o)&0x60) -#define IPOPT_NUMBER(o) ((o)&0x1f) - -#define IPOPT_CONTROL 0x00 -#define IPOPT_RESERVED1 0x20 -#define IPOPT_DEBMEAS 0x40 -#define IPOPT_RESERVED2 0x60 - -#define IPOPT_EOL 0 /* end of option list */ -#define IPOPT_NOP 1 /* no operation */ - -#define IPOPT_RR 7 /* record packet route */ -#define IPOPT_TS 68 /* timestamp */ -#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ -#define IPOPT_LSRR 131 /* loose source route */ -#define IPOPT_SATID 136 /* satnet id */ -#define IPOPT_SSRR 137 /* strict source route */ - -/* - * Offsets to fields in options other than EOL and NOP. - */ -#define IPOPT_OPTVAL 0 /* option ID */ -#define IPOPT_OLEN 1 /* option length */ -#define IPOPT_OFFSET 2 /* offset within option */ -#define IPOPT_MINOFF 4 /* min value of above */ - -/* - * Time stamp option structure. - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct ip_timestamp { - u_int8_t ipt_code; /* IPOPT_TS */ - u_int8_t ipt_len; /* size of structure (variable) */ - u_int8_t ipt_ptr; /* index of current entry */ -#ifdef WORDS_BIGENDIAN - u_char ipt_oflw:4, /* overflow counter */ - ipt_flg:4; /* flags, see below */ -#else - u_char ipt_flg:4, /* flags, see below */ - ipt_oflw:4; /* overflow counter */ -#endif - union ipt_timestamp { - n_long ipt_time[1]; - struct ipt_ta { - struct in_addr ipt_addr; - n_long ipt_time; - } ipt_ta[1]; - } ipt_timestamp; -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -/* flag bits for ipt_flg */ -#define IPOPT_TS_TSONLY 0 /* timestamps only */ -#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define IPOPT_TS_PRESPEC 3 /* specified modules only */ - -/* bits for security (not byte swapped) */ -#define IPOPT_SECUR_UNCLASS 0x0000 -#define IPOPT_SECUR_CONFID 0xf135 -#define IPOPT_SECUR_EFTO 0x789a -#define IPOPT_SECUR_MMMM 0xbc4d -#define IPOPT_SECUR_RESTR 0xaf13 -#define IPOPT_SECUR_SECRET 0xd788 -#define IPOPT_SECUR_TOPSECRET 0x6bc5 - -/* - * Internet implementation parameters. - */ -#define MAXTTL 255 /* maximum time to live (seconds) */ -#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ -#define IPFRAGTTL 60 /* time to live for frags, slowhz */ -#define IPTTLDEC 1 /* subtracted when forwarding */ - -#define IP_MSS 576 /* default maximum segment size */ - -#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ -#include -#else -#if SIZEOF_CHAR_P == 4 -typedef SLIRPcaddr_t caddr32_t; -#else -typedef u_int32_t caddr32_t; -#endif -#endif - -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t ipqp_32; -typedef uintptr_t ipasfragp_32; -#else -#if SIZEOF_CHAR_P == 4 -typedef struct ipq *ipqp_32; -typedef struct ipasfrag *ipasfragp_32; -#else -typedef caddr32_t ipqp_32; -typedef caddr32_t ipasfragp_32; -#endif -#endif - -/* - * Overlay for ip header used by other protocols (tcp, udp). - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct ipovly { -#if defined(__amd64__) || defined(__aarch64__) - uintptr_t ih_next, ih_prev; /* for protocol sequence q's */ -#else - caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ -#endif - u_int8_t ih_x1; /* (unused) */ - u_int8_t ih_pr; /* protocol */ - u_int16_t ih_len; /* protocol length */ - struct in_addr ih_src; /* source internet address */ - struct in_addr ih_dst; /* destination internet address */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -#if defined(_MSC_VER) -#pragma pack(pop) -#endif - -/* - * Ip reassembly queue structure. Each fragment - * being reassembled is attached to one of these structures. - * They are timed out after ipq_ttl drops to 0, and may also - * be reclaimed if memory becomes tight. - * size 28 bytes - */ -struct ipq { -#if defined(__amd64__) || defined(__aarch64__) - uintptr_t next,prev; /* to other reass headers */ -#else - ipqp_32 next,prev; /* to other reass headers */ -#endif - u_int8_t ipq_ttl; /* time for reass q to live */ - u_int8_t ipq_p; /* protocol of this fragment */ - u_int16_t ipq_id; /* sequence id for reassembly */ - ipasfragp_32 ipq_next,ipq_prev; - /* to ip headers of fragments */ - struct in_addr ipq_src,ipq_dst; -}; - -/* - * Ip header, when holding a fragment. - * - * Note: ipf_next must be at same offset as ipq_next above - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct ipasfrag { -#ifdef WORDS_BIGENDIAN - u_char ip_v:4, - ip_hl:4; -#else - u_char ip_hl:4, - ip_v:4; -#endif - /* BUG : u_int changed to u_int8_t. - * sizeof(u_int)==4 on linux 2.0 - */ - u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit - * to avoid destroying tos (PPPDTRuu); - * copied from (ip_off&IP_MF) */ - u_int16_t ip_len; - u_int16_t ip_id; - u_int16_t ip_off; - u_int8_t ip_ttl; - u_int8_t ip_p; - u_int16_t ip_sum; - ipasfragp_32 ipf_next; /* next fragment */ - ipasfragp_32 ipf_prev; /* previous fragment */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) //WAS 0 -#endif - -/* - * Structure stored in mbuf in inpcb.ip_options - * and passed to ip_output when ip options are in use. - * The actual length of the options (including ipopt_dst) - * is in m_len. - */ -#define MAX_IPOPTLEN 40 - -struct ipoption { - struct in_addr ipopt_dst; /* first-hop dst if source routed */ - int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ -}; - -/* - * Structure attached to inpcb.ip_moptions and - * passed to ip_output when IP multicast options are in use. - */ - -struct ipstat { - u_long ips_total; /* total packets received */ - u_long ips_badsum; /* checksum bad */ - u_long ips_tooshort; /* packet too short */ - u_long ips_toosmall; /* not enough data */ - u_long ips_badhlen; /* ip header length < data size */ - u_long ips_badlen; /* ip length < ip header length */ - u_long ips_fragments; /* fragments received */ - u_long ips_fragdropped; /* frags dropped (dups, out of space) */ - u_long ips_fragtimeout; /* fragments timed out */ - u_long ips_forward; /* packets forwarded */ - u_long ips_cantforward; /* packets rcvd for unreachable dest */ - u_long ips_redirectsent; /* packets forwarded on same net */ - u_long ips_noproto; /* unknown or unsupported protocol */ - u_long ips_delivered; /* datagrams delivered to upper level*/ - u_long ips_localout; /* total ip packets generated here */ - u_long ips_odropped; /* lost packets due to nobufs, etc. */ - u_long ips_reassembled; /* total packets reassembled ok */ - u_long ips_fragmented; /* datagrams successfully fragmented */ - u_long ips_ofragments; /* output fragments created */ - u_long ips_cantfrag; /* don't fragment flag was set, etc. */ - u_long ips_badoptions; /* error in option processing */ - u_long ips_noroute; /* packets discarded due to no route */ - u_long ips_badvers; /* ip version != 4 */ - u_long ips_rawout; /* total raw ip packets generated */ - u_long ips_unaligned; /* times the ip packet was not aligned */ -}; - -extern struct ipstat ipstat; -extern struct ipq ipq; /* ip reass. queue */ -extern u_int16_t ip_id; /* ip packet ctr, for ids */ -extern int ip_defttl; /* default IP ttl */ - -#endif diff --git a/src/include/slirp/ip_icmp.h b/src/include/slirp/ip_icmp.h deleted file mode 100644 index 20fcda1bd..000000000 --- a/src/include/slirp/ip_icmp.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 - * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp - */ - -#ifndef _NETINET_IP_ICMP_H_ -#define _NETINET_IP_ICMP_H_ - -/* - * Interface Control Message Protocol Definitions. - * Per RFC 792, September 1981. - */ - -typedef u_int32_t n_time; - -/* - * Structure of an icmp header. - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct icmp { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ - union { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - u_short icd_id; - u_short icd_seq; - } ih_idseq; - int ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu { - u_short ipm_void; - u_short ipm_nextmtu; - } ih_pmtu; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu - union { - struct id_ts { - n_time its_otime; - n_time its_rtime; - n_time its_ttime; - } id_ts; - struct id_ip { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - uint32_t id_mask; - char id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(0) -#endif - -/* - * Lower bounds on packet lengths for various types. - * For the error advice packets must first insure that the - * packet is large enought to contain the returned ip header. - * Only then can we do the check to see if 64 bits of packet - * data have been returned, since we need to check the returned - * ip header length. - */ -#define ICMP_MINLEN 8 /* abs minimum */ -#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ -#define ICMP_MASKLEN 12 /* address mask */ -#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ -#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) - /* N.B.: must separately check that ip_hl >= 5 */ - -/* - * Definition of type and code field values. - */ -#define ICMP_ECHOREPLY 0 /* echo reply */ -#define ICMP_UNREACH 3 /* dest unreachable, codes: */ -#define ICMP_UNREACH_NET 0 /* bad net */ -#define ICMP_UNREACH_HOST 1 /* bad host */ -#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ -#define ICMP_UNREACH_PORT 3 /* bad port */ -#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ -#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ -#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ -#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ -#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ -#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ -#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ -#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ -#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ -#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ -#define ICMP_REDIRECT 5 /* shorter route, codes: */ -#define ICMP_REDIRECT_NET 0 /* for network */ -#define ICMP_REDIRECT_HOST 1 /* for host */ -#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ -#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ -#define ICMP_ECHO 8 /* echo service */ -#define ICMP_ROUTERADVERT 9 /* router advertisement */ -#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ -#define ICMP_TIMXCEED 11 /* time exceeded, code: */ -#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ -#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ -#define ICMP_PARAMPROB 12 /* ip header bad */ -#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ -#define ICMP_TSTAMP 13 /* timestamp request */ -#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ -#define ICMP_IREQ 15 /* information request */ -#define ICMP_IREQREPLY 16 /* information reply */ -#define ICMP_MASKREQ 17 /* address mask request */ -#define ICMP_MASKREPLY 18 /* address mask reply */ - -#define ICMP_MAXTYPE 18 - -#define ICMP_INFOTYPE(type) \ - ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ - (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ - (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ - (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ - (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) - -void icmp_input _P((struct SLIRPmbuf *, int)); -void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *)); -void icmp_reflect _P((struct SLIRPmbuf *)); - -#endif diff --git a/src/include/slirp/libslirp-version.h b/src/include/slirp/libslirp-version.h new file mode 100644 index 000000000..1599206a5 --- /dev/null +++ b/src/include/slirp/libslirp-version.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef LIBSLIRP_VERSION_H_ +#define LIBSLIRP_VERSION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SLIRP_MAJOR_VERSION 4 +#define SLIRP_MINOR_VERSION 3 +#define SLIRP_MICRO_VERSION 1 +#define SLIRP_VERSION_STRING "4.3.1-git-86Box" + +#define SLIRP_CHECK_VERSION(major,minor,micro) \ + (SLIRP_MAJOR_VERSION > (major) || \ + (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \ + (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \ + SLIRP_MICRO_VERSION >= (micro))) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LIBSLIRP_VERSION_H_ */ diff --git a/src/include/slirp/libslirp.h b/src/include/slirp/libslirp.h index 8a1aa31e6..7c4340390 100644 --- a/src/include/slirp/libslirp.h +++ b/src/include/slirp/libslirp.h @@ -1,41 +1,186 @@ -#ifndef _LIBSLIRP_H -#define _LIBSLIRP_H +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef LIBSLIRP_H +#define LIBSLIRP_H + +#include +#include +#include #ifdef _WIN32 #include -int inet_aton(const char *cp, struct in_addr *ia); +#include #else -#include +#include #include #endif +#include "libslirp-version.h" + +/* Windows does not define ssize_t, so we need to define it here. */ +#ifndef _SSIZE_T_DEFINED +# define _SSIZE_T_DEFINED +# undef ssize_t +# ifdef _WIN64 +# define ssize_t int64_t +# else +# define ssize_t int32_t +# endif +#endif + #ifdef __cplusplus extern "C" { #endif -int slirp_init(void); +typedef struct Slirp Slirp; -int slirp_select_fill(int *pnfds, - fd_set *readfds, fd_set *writefds, fd_set *xfds); +enum { + SLIRP_POLL_IN = 1 << 0, + SLIRP_POLL_OUT = 1 << 1, + SLIRP_POLL_PRI = 1 << 2, + SLIRP_POLL_ERR = 1 << 3, + SLIRP_POLL_HUP = 1 << 4, +}; -void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); +typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque); +typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque); +typedef void (*SlirpTimerCb)(void *opaque); +typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque); +typedef int (*SlirpGetREventsCb)(int idx, void *opaque); -void slirp_input(const uint8 *pkt, int pkt_len); +/* + * Callbacks from slirp + */ +typedef struct SlirpCb { + /* + * Send an ethernet frame to the guest network. The opaque + * parameter is the one given to slirp_init(). The function + * doesn't need to send all the data and may return -#endif - -#define TOWRITEMAX 512 - -extern struct timeval tt; -extern int link_up; -extern int slirp_socket; -extern int slirp_socket_unit; -extern int slirp_socket_port; -extern u_int32_t slirp_socket_addr; -extern char *slirp_socket_passwd; -extern int ctty_closed; - -/* - * Get the difference in 2 times from updtim() - * Allow for wraparound times, "just in case" - * x is the greater of the 2 (current time) and y is - * what it's being compared against. - */ -#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) - -extern char *slirp_tty; -extern char *exec_shell; -extern u_int curtime; -extern fd_set *global_readfds, *global_writefds, *global_xfds; -extern struct in_addr ctl_addr; -extern struct in_addr special_addr; -extern struct in_addr alias_addr; -extern struct in_addr our_addr; -extern struct in_addr loopback_addr; -extern struct in_addr dns_addr; -extern char *username; -extern char *socket_path; -extern int towrite_max; -extern int ppp_exit; -extern int so_options; -extern int tcp_keepintvl; -extern uint8_t client_ethaddr[6]; - -#define PROTO_SLIP 0x1 -#ifdef USE_PPP -#define PROTO_PPP 0x2 -#endif - -void if_encap(const uint8_t *ip_data, int ip_data_len); diff --git a/src/include/slirp/mbuf.h b/src/include/slirp/mbuf.h deleted file mode 100644 index 4921506b5..000000000 --- a/src/include/slirp/mbuf.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 - * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp - */ - -#ifndef _MBUF_H_ -#define _MBUF_H_ - -#define m_freem m_free - - -#define MINCSIZE 4096 /* Amount to increase mbuf if too small */ - -/* - * Macros for type conversion - * mtod(m,t) - convert mbuf pointer to data pointer of correct type - * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) - */ -#define mtod(m,t) ((t)(m)->m_data) -/* #define dtom(x) ((struct SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */ - -/* XXX About mbufs for slirp: - * Only one mbuf is ever used in a chain, for each "cell" of data. - * m_nextpkt points to the next packet, if fragmented. - * If the data is too large, the M_EXT is used, and a larger block - * is alloced. Therefore, m_free[m] must check for M_EXT and if set - * free the m_ext. This is inefficient memory-wise, but who cares. - */ - -/* XXX should union some of these! */ -/* header at beginning of each mbuf: */ -struct m_hdr { - struct SLIRPmbuf *mh_next; /* Linked list of mbufs */ - struct SLIRPmbuf *mh_prev; - struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */ - struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */ - int mh_flags; /* Misc flags */ - - size_t mh_size; /* Size of data */ - struct SLIRPsocket *mh_so; - - SLIRPcaddr_t mh_data; /* Location of data */ - int32_t mh_len; /* Amount of data in this mbuf */ -}; - -/* - * How much room is in the mbuf, from m_data to the end of the mbuf - */ -#define M_ROOM(m) ((m->m_flags & M_EXT)? \ - (((m)->m_ext + (m)->m_size) - (m)->m_data) \ - : \ - (((m)->m_dat + (m)->m_size) - (m)->m_data)) - -/* - * How much free room there is - */ -#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) -#define M_TRAILINGSPACE M_FREEROOM - -struct SLIRPmbuf { - struct m_hdr m_hdr; - union M_dat { - char m_dat_[1]; /* ANSI don't like 0 sized arrays */ - char *m_ext_; - } M_dat; -}; - -#define m_next m_hdr.mh_next -#define m_prev m_hdr.mh_prev -#define m_nextpkt m_hdr.mh_nextpkt -#define m_prevpkt m_hdr.mh_prevpkt -#define m_flags m_hdr.mh_flags -#define m_len m_hdr.mh_len -#define m_data m_hdr.mh_data -#define m_size m_hdr.mh_size -#define m_dat M_dat.m_dat_ -#define m_ext M_dat.m_ext_ -#define m_so m_hdr.mh_so - -#define ifq_prev m_prev -#define ifq_next m_next -#define ifs_prev m_prevpkt -#define ifs_next m_nextpkt -#define ifq_so m_so - -#define M_EXT 0x01 /* m_ext points to more (malloced) data */ -#define M_FREELIST 0x02 /* mbuf is on free list */ -#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ -#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() - * it rather than putting it on the free list */ - -/* - * Mbuf statistics. XXX - */ - -struct mbstat { - int mbs_alloced; /* Number of mbufs allocated */ - -}; - -extern struct mbstat mbstat; -extern int mbuf_alloced; -extern struct SLIRPmbuf m_freelist, m_usedlist; -extern int mbuf_max; - -void m_init _P((void)); -void msize_init _P((void)); -struct SLIRPmbuf * m_get _P((void)); -void m_free _P((struct SLIRPmbuf *)); -void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *)); -void m_inc _P((struct SLIRPmbuf *, int)); -void m_adj _P((struct SLIRPmbuf *, int)); -int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int)); -struct SLIRPmbuf * dtom _P((void *)); - -#endif diff --git a/src/include/slirp/misc.h b/src/include/slirp/misc.h deleted file mode 100644 index c509deb92..000000000 --- a/src/include/slirp/misc.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _MISC_H_ -#define _MISC_H_ - -struct ex_list { - int ex_pty; /* Do we want a pty? */ - int ex_addr; /* The last byte of the address */ - int ex_fport; /* Port to telnet to */ - char *ex_exec; /* Command line of what to exec */ - struct ex_list *ex_next; -}; - -extern struct ex_list *exec_list; -extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; - -extern int (*lprint_print) _P((void *, const char *, va_list)); -extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; -extern struct sbuf *lprint_sb; - -#ifndef HAVE_STRDUP -char *strdup _P((const char *)); -#endif - -void do_wait _P((int)); - -#define EMU_NONE 0x0 - -/* TCP emulations */ -#define EMU_CTL 0x1 -#define EMU_FTP 0x2 -#define EMU_KSH 0x3 -#define EMU_IRC 0x4 -#define EMU_REALAUDIO 0x5 -#define EMU_RLOGIN 0x6 -#define EMU_IDENT 0x7 -#define EMU_RSH 0x8 - -#define EMU_NOCONNECT 0x10 /* Don't connect */ - -/* UDP emulations */ -#define EMU_TALK 0x1 -#define EMU_NTALK 0x2 -#define EMU_CUSEEME 0x3 - -struct tos_t { - u_int16_t lport; - u_int16_t fport; - u_int8_t tos; - u_int8_t emu; -}; - -struct emu_t { - u_int16_t lport; - u_int16_t fport; - u_int8_t tos; - u_int8_t emu; - struct emu_t *next; -}; - -extern struct emu_t *tcpemu; - -extern int x_port, x_server, x_display; - -int show_x _P((char *, struct SLIRPsocket *)); -void redir_x _P((u_int32_t, int, int, int)); -void getouraddr _P((void)); -void slirp_insque _P((void *, void *)); -void slirp_remque _P((void *)); -int add_exec _P((struct ex_list **, int, char *, int, int)); -int slirp_openpty _P((int *, int *)); -int fork_exec _P((struct SLIRPsocket *, char *, int)); -void snooze_hup _P((int)); -void snooze _P((void)); -void relay _P((int)); -void add_emu _P((char *)); -void u_sleep _P((int)); -void fd_nonblock _P((int)); -void fd_block _P((int)); -int rsh_exec _P((struct SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *)); - -#endif diff --git a/src/include/slirp/queue.h b/src/include/slirp/queue.h deleted file mode 100644 index 786950ab7..000000000 --- a/src/include/slirp/queue.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * File: queue.h - * Author: Robert I. Pitts - * Last Modified: March 9, 2000 - * Topic: Queue - Array Implementation - * ---------------------------------------------------------------- - */ - -#ifndef _QUEUE_H -#define _QUEUE_H - -/* - * Constants - * --------- - * ERROR_* These signal error conditions in queue functions - * and are used as exit codes for the program. - */ -#define ERROR_QUEUE 2 -#define ERROR_MEMORY 3 - -/* - * Type: queueElementT - * ------------------- - * This is the type of objects held in the queue. - */ - -/*typedef char queueElementT; -typedef unsigned char *queueElementT; -*/ - -struct queuepacket{ - int len; - unsigned char data[2000]; -}; -typedef struct queuepacket *queueElementT; - -/* - * Type: queueADT - * -------------- - * The actual implementation of a queue is completely - * hidden. Client will work with queueADT which is a - * pointer to underlying queueCDT. - */ - -/* - * NOTE: need word struct below so that the compiler - * knows at least that a queueCDT will be some sort - * of struct. - */ - -typedef struct queueCDT *queueADT; - -/* - * Function: QueueCreate - * Usage: queue = QueueCreate(); - * ------------------------- - * A new empty queue is created and returned. - */ - -queueADT QueueCreate(void); - -/* Function: QueueDestroy - * Usage: QueueDestroy(queue); - * ----------------------- - * This function frees all memory associated with - * the queue. "queue" may not be used again unless - * queue = QueueCreate() is called first. - */ - -void QueueDestroy(queueADT queue); - -/* - * Functions: QueueEnter, QueueDelete - * Usage: QueueEnter(queue, element); - * element = QueueDelete(queue); - * -------------------------------------------- - * These are the fundamental queue operations that enter - * elements in and delete elements from the queue. A call - * to QueueDelete() on an empty queue or to QueueEnter() - * on a full queue is an error. Make use of QueueIsFull() - * and QueueIsEmpty() (see below) to avoid these errors. - */ - -void QueueEnter(queueADT queue, queueElementT element); -queueElementT QueueDelete(queueADT queue); - - -/* - * Functions: QueueIsEmpty, QueueIsFull - * Usage: if (QueueIsEmpty(queue)) ... - * ----------------------------------- - * These return a true/false value based on whether - * the queue is empty or full, respectively. - */ - -int QueueIsEmpty(queueADT queue); -int QueueIsFull(queueADT queue); - -int QueuePeek(queueADT queue); - -#endif /* not defined _QUEUE_H */ diff --git a/src/include/slirp/sbuf.h b/src/include/slirp/sbuf.h deleted file mode 100644 index aa4724df7..000000000 --- a/src/include/slirp/sbuf.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _SBUF_H_ -#define _SBUF_H_ - -#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) -#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) - -struct sbuf { - u_int sb_cc; /* actual chars in buffer */ - u_int sb_datalen; /* Length of data */ - char *sb_wptr; /* write pointer. points to where the next - * bytes should be written in the sbuf */ - char *sb_rptr; /* read pointer. points to where the next - * byte should be read from the sbuf */ - char *sb_data; /* Actual data */ -}; - -void sbfree _P((struct sbuf *)); -void sbdrop _P((struct sbuf *, int)); -void sbreserve _P((struct sbuf *, int)); -void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *)); -void sbcopy _P((struct sbuf *, int, int, char *)); - -#endif diff --git a/src/include/slirp/slirp.h b/src/include/slirp/slirp.h deleted file mode 100644 index b78dc93a8..000000000 --- a/src/include/slirp/slirp.h +++ /dev/null @@ -1,441 +0,0 @@ -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#define SLIRP_VERSION "Cockatrice special" - -#define CONFIG_QEMU - -#ifndef CONFIG_QEMU -#include "version.h" -#endif -#include "config.h" -#include "slirp_config.h" - -#ifdef _WIN32 -#ifdef __GNUC__ /* MINGW? */ -# include -typedef uint8_t u_int8_t; -typedef uint16_t u_int16_t; -typedef uint32_t u_int32_t; -typedef uint64_t u_int64_t; -typedef char *SLIRPcaddr_t; -typedef int socklen_t; -typedef unsigned long ioctlsockopt_t; -#else -typedef unsigned char u_int8_t; -typedef char int8_t; -typedef unsigned char uint8_t; -typedef unsigned short u_int16_t; -typedef unsigned short uint16_t; -typedef short int16_t; -typedef unsigned int u_int32_t; -typedef unsigned int uint32_t; -typedef int int32_t; - -typedef unsigned __int64 u_int64_t; -typedef char *SLIRPcaddr_t; -typedef int socklen_t; -typedef unsigned long ioctlsockopt_t; - -#endif - -# include /* needs to be on top otherwise, it'll pull in winsock1 */ -# include - -# include -# include - -# define USE_FIONBIO 1 -#ifndef EWOULDBLOCK -# define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef EINPROGRESS -# define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef ENOTCONN -# define ENOTCONN WSAENOTCONN -#endif -#ifndef EHOSTUNREACH -# define EHOSTUNREACH WSAEHOSTUNREACH -#endif -#ifndef ENETUNREACH -# define ENETUNREACH WSAENETUNREACH -#endif -#ifndef ECONNREFUSED -# define ECONNREFUSED WSAECONNREFUSED -#endif - -/* Basilisk II Router defines those */ -# define udp_read_completion slirp_udp_read_completion -# define write_udp slirp_write_udp -# define init_udp slirp_init_udp -# define final_udp slirp_final_udp -#else -# include -# define HAVE_STDINT_H -# define HAVE_STDLIB_H -# define HAVE_STRING_H -# define HAVE_UNISTD_H -# define HAVE_INET_ATON -typedef uint8_t u_int8_t; -typedef uint16_t u_int16_t; -typedef uint32_t u_int32_t; -typedef uint64_t u_int64_t; -typedef char *SLIRPcaddr_t; -typedef int ioctlsockopt_t; -# define ioctlsocket ioctl -# define closesocket(s) close(s) -# define O_BINARY 0 -#endif - -#include -#ifdef HAVE_SYS_BITYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif - -#ifndef _MSC_VER -#include -#else -#include -#endif - -#ifdef NEED_TYPEDEFS -typedef char int8_t; -typedef unsigned char u_int8_t; - -# if SIZEOF_SHORT == 2 - typedef short int16_t; - typedef unsigned short u_int16_t; -# else -# if SIZEOF_INT == 2 - typedef int int16_t; - typedef unsigned int u_int16_t; -# else - #error Cannot find a type with sizeof() == 2 -# endif -# endif - -# if SIZEOF_SHORT == 4 - typedef short int32_t; - typedef unsigned short u_int32_t; -# else -# if SIZEOF_INT == 4 - typedef int int32_t; - typedef unsigned int u_int32_t; -# else - #error Cannot find a type with sizeof() == 4 -# endif -# endif -#endif /* NEED_TYPEDEFS */ - -/* Basilisk II types glue */ -typedef u_int8_t uint8; -typedef u_int16_t uint16; -typedef u_int32_t uint32; - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifdef HAVE_STDLIB_H -# include -#endif - -#include -#include - -#ifndef HAVE_MEMMOVE -#define memmove(x, y, z) bcopy(y, x, z) -#endif - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#ifdef HAVE_STRING_H -# include -#else -#ifndef _MSC_VER -# include -#else -#include -#endif -#endif - -#ifndef _WIN32 -#include -#endif - -#ifndef _P -#ifndef NO_PROTOTYPES -# define _P(x) x -#else -# define _P(x) () -#endif -#endif - -#ifndef _WIN32 -#include -#include -#endif - -#ifdef GETTIMEOFDAY_ONE_ARG -#define gettimeofday(x, y) gettimeofday(x) -#endif - -/* Systems lacking strdup() definition in . */ -#if defined(ultrix) -char *strdup _P((const char *)); -#endif - -/* Systems lacking malloc() definition in . */ -#if defined(ultrix) || defined(hcx) -void *malloc _P((size_t arg)); -void free _P((void *ptr)); -#endif - -#ifndef HAVE_INET_ATON -int inet_aton _P((const char *cp, struct in_addr *ia)); -#endif - -#include -#ifndef NO_UNIX_SOCKETS -#include -#endif -#include -#ifdef HAVE_SYS_SIGNAL_H -# include -#endif -#ifndef _WIN32 -#include -#endif - -#if defined(HAVE_SYS_IOCTL_H) -# include -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -#ifdef HAVE_SYS_FILIO_H -# include -#endif - -#ifdef USE_PPP -#include -#endif - -#ifdef __STDC__ -#include -#else -#include -#endif - -#include - -/* Avoid conflicting with the libc insque() and remque(), which - have different prototypes. */ -#define insque slirp_insque -#define remque slirp_remque - -#ifdef HAVE_SYS_STROPTS_H -#include -#endif - -#include "debug.h" - -#if defined __GNUC__ -#define PACKED__ __attribute__ ((packed)) -#elif defined __sgi -#define PRAGMA_PACK_SUPPORTED 1 -#define PACK_END 0 -#define PACKED__ -#elif _MSC_VER -#define PACKED__ -#else -#error "Packed attribute or pragma shall be supported" -#endif - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif - -#include "ip.h" -#include "tcp.h" -#include "tcp_timer.h" -#include "tcp_var.h" -#include "tcpip.h" -#include "udp.h" -#include "icmp_var.h" -#include "mbuf.h" -#include "sbuf.h" -#include "socket.h" -#include "if.h" -#include "main.h" -#include "misc.h" -#include "ctl.h" -#ifdef USE_PPP -#include "ppp/pppd.h" -#include "ppp/ppp.h" -#endif - -#include "bootp.h" -#include "tftp.h" -#include "libslirp.h" - -extern struct ttys *ttys_unit[MAX_INTERFACES]; - -#ifndef NULL -#define NULL (void *)0 -#endif - -#ifndef FULL_BOLT -void if_start _P((void)); -#else -void if_start _P((struct ttys *)); -#endif - -#ifdef BAD_SPRINTF -# define vsprintf vsprintf_len -# define sprintf sprintf_len - extern int vsprintf_len _P((char *, const char *, va_list)); - extern int sprintf_len _P((char *, const char *, ...)); -#endif - -#ifdef DECLARE_SPRINTF -# ifndef BAD_SPRINTF - extern int vsprintf _P((char *, const char *, va_list)); -# endif - extern int vfprintf _P((FILE *, const char *, va_list)); -#endif - -#ifndef HAVE_STRERROR -#ifndef _MSC_VER - extern char *strerror _P((int error)); - #define HAVE_STRERROR -#endif -#endif - -#ifndef HAVE_INDEX - char *index _P((const char *, int)); -#endif - -#ifndef HAVE_GETHOSTID - long gethostid _P((void)); -#endif - -void lprint _P((const char *, ...)); - -extern int do_echo; - -#ifdef _MSC_VER -#define __inline -#endif - -#if SIZEOF_CHAR_P == 4 -# define insque_32 insque -# define remque_32 remque -#else -# ifdef NEED_QUE32_INLINE -extern __inline void insque_32 _P((void *, void *)); -extern __inline void remque_32 _P((void *)); -# else -extern void insque_32 _P((void *, void *)); -extern void remque_32 _P((void *)); -# endif -#endif - -#ifndef _WIN32 -#include -#endif - -#define DEFAULT_BAUD 115200 - -/* cksum.c */ -int cksum(struct SLIRPmbuf *m, int len); - -/* if.c */ -void if_init _P((void)); -void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); - -/* ip_input.c */ -void ip_init _P((void)); -void ip_input _P((struct SLIRPmbuf *)); -struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); -void ip_freef _P((struct ipq *)); -void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); -void ip_deq _P((register struct ipasfrag *)); -void ip_slowtimo _P((void)); -void ip_stripoptions _P((register struct SLIRPmbuf *, struct SLIRPmbuf *)); - -/* ip_output.c */ -int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); - -/* tcp_input.c */ -int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *)); -void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *)); -void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); -void tcp_xmit_timer _P((register struct tcpcb *, int)); -int tcp_mss _P((register struct tcpcb *, u_int)); - -/* tcp_output.c */ -int tcp_output _P((register struct tcpcb *)); -void tcp_setpersist _P((register struct tcpcb *)); - -/* tcp_subr.c */ -void tcp_init _P((void)); -void tcp_template _P((struct tcpcb *)); -void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct SLIRPmbuf *, tcp_seq, tcp_seq, int)); -struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *)); -struct tcpcb * tcp_close _P((register struct tcpcb *)); -void tcp_drain _P((void)); -void tcp_sockclosed _P((struct tcpcb *)); -int tcp_fconnect _P((struct SLIRPsocket *)); -void tcp_connect _P((struct SLIRPsocket *)); -int tcp_attach _P((struct SLIRPsocket *)); -u_int8_t tcp_tos _P((struct SLIRPsocket *)); -int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -int tcp_ctl _P((struct SLIRPsocket *)); -struct tcpcb *tcp_drop(struct tcpcb *tp, int err); - - -#if defined(_MSC_VER) -#pragma pack(pop) -#endif - -#ifdef USE_PPP -#define MIN_MRU MINMRU -#define MAX_MRU MAXMRU -#else -#define MIN_MRU 128 -#define MAX_MRU 16384 -#endif - -#ifndef _WIN32 -#define min(x,y) ((x) < (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) -#endif - -#ifdef _WIN32 -#undef errno -#define errno (WSAGetLastError()) -#endif - -#define PROBE_CONN - -#endif diff --git a/src/include/slirp/slirp_config.h b/src/include/slirp/slirp_config.h deleted file mode 100644 index e583dcc80..000000000 --- a/src/include/slirp/slirp_config.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * User definable configuration options - */ - -/* Undefine if you don't want talk emulation */ -#undef EMULATE_TALK - -/* Define if you want the connection to be probed */ -/* XXX Not working yet, so ignore this for now */ -#undef PROBE_CONN - -/* Define to 1 if you want KEEPALIVE timers */ -#define DO_KEEPALIVE 0 - -/* Define to MAX interfaces you expect to use at once */ -/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ -/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ -#define MAX_INTERFACES 1 -#define MAX_PPP_INTERFACES 1 - -/* Define if you want slirp's socket in /tmp */ -/* XXXXXX Do this in ./configure */ -#undef USE_TMPSOCKET - -/* Define if you want slirp to use cfsetXspeed() on the terminal */ -#undef DO_CFSETSPEED - -/* Define this if you want slirp to write to the tty as fast as it can */ -/* This should only be set if you are using load-balancing, slirp does a */ -/* pretty good job on single modems already, and seting this will make */ -/* interactive sessions less responsive */ -/* XXXXX Talk about having fast modem as unit 0 */ -#undef FULL_BOLT - -/* - * Define if you want slirp to use less CPU - * You will notice a small lag in interactive sessions, but it's not that bad - * Things like Netscape/ftp/etc. are completely unaffected - * This is mainly for sysadmins who have many slirp users - */ -#undef USE_LOWCPU - -/* Define this if your compiler doesn't like prototypes */ -#ifndef __STDC__ -#define NO_PROTOTYPES -#endif - -/*********************************************************/ -/* - * Autoconf defined configuration options - * You shouldn't need to touch any of these - */ - -/* Ignore this */ -#undef DUMMY_PPP - -/* XXX: Define according to how time.h should be included */ -#undef TIME_WITH_SYS_TIME -#define TIME_WITH_SYS_TIME 0 -#undef HAVE_SYS_TIME_H - -/* Define if your sprintf returns char * instead of int */ -#undef BAD_SPRINTF - -/* Define if you have readv */ -#undef HAVE_READV - -/* Define if iovec needs to be declared */ -#undef DECLARE_IOVEC -#ifdef _WIN32 -#define DECLARE_IOVEC -#endif - -/* Define if a declaration of sprintf/fprintf is needed */ -#undef DECLARE_SPRINTF - -/* Define if you have sys/stropts.h */ -#undef HAVE_SYS_STROPTS_H - -/* Define if your compiler doesn't like prototypes */ -#undef NO_PROTOTYPES - -/* Define if you don't have u_int32_t etc. typedef'd */ -#undef NEED_TYPEDEFS -#ifdef __sun__ -#define NEED_TYPEDEFS -#endif - -/* Define to sizeof(char *) */ -#define SIZEOF_CHAR_P SIZEOF_VOID_P - -/* Define if you have random() */ -#undef HAVE_RANDOM - -/* Define if you have srandom() */ -#undef HAVE_SRANDOM - -/* Define if you have setenv */ -#undef HAVE_SETENV - -/* Define if you have index() */ -#undef HAVE_INDEX - -/* Define if you have bcmp() */ -#undef HAVE_BCMP - -/* Define if you have drand48 */ -#undef HAVE_DRAND48 - -/* Define if you have memmove */ -#define HAVE_MEMMOVE - -/* Define if you have gethostid */ -#undef HAVE_GETHOSTID - -/* Define if you DON'T have unix-domain sockets */ -#undef NO_UNIX_SOCKETS -#ifdef _WIN32 -#define NO_UNIX_SOCKETS -#endif - -/* Define if gettimeofday only takes one argument */ -#undef GETTIMEOFDAY_ONE_ARG - -/* Define if you have revoke() */ -#undef HAVE_REVOKE - -/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ -#undef HAVE_GRANTPT - -/* Define if you have fchmod */ -#undef HAVE_FCHMOD - -/* Define if you have */ -#undef HAVE_SYS_TYPES32_H diff --git a/src/include/slirp/socket.h b/src/include/slirp/socket.h deleted file mode 100644 index 3a777934a..000000000 --- a/src/include/slirp/socket.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -/* MINE */ - -#ifndef _SLIRP_SOCKET_H_ -#define _SLIRP_SOCKET_H_ - -#define SO_EXPIRE 240000 -#define SO_EXPIREFAST 10000 - -/* - * Our socket structure - */ - -struct SLIRPsocket { - struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */ - - int s; /* The actual socket */ - - /* XXX union these with not-yet-used sbuf params */ - struct SLIRPmbuf *so_m; /* Pointer to the original SYN packet, - * for non-blocking connect()'s, and - * PING reply's */ - struct tcpiphdr *so_ti; /* Pointer to the original ti within - * so_mconn, for non-blocking connections */ - int so_urgc; - struct in_addr so_faddr; /* foreign host table entry */ - struct in_addr so_laddr; /* local host table entry */ - u_int16_t so_fport; /* foreign port */ - u_int16_t so_lport; /* local port */ - - u_int8_t so_iptos; /* Type of service */ - u_int8_t so_emu; /* Is the socket emulated? */ - - u_char so_type; /* Type of socket, UDP or TCP */ - int so_state; /* internal state flags SS_*, below */ - - struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ - u_int so_expire; /* When the socket will expire */ - - int so_queued; /* Number of packets queued from this socket */ - int so_nqueued; /* Number of packets queued in a row - * Used to determine when to "downgrade" a session - * from fastq to batchq */ - - struct sbuf so_rcv; /* Receive buffer */ - struct sbuf so_snd; /* Send buffer */ - void * extra; /* Extra pointer */ -}; - - -/* - * Socket state bits. (peer means the host on the Internet, - * local host means the host on the other end of the modem) - */ -#define SS_NOFDREF 0x001 /* No fd reference */ - -#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ -#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ -#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ -#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ -/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ -#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ - -#define SS_CTL 0x080 -#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ -#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ - -extern struct SLIRPsocket tcb; - - -#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) -struct iovec { - char *iov_base; - size_t iov_len; -}; -#endif - -void so_init _P((void)); -struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int)); -struct SLIRPsocket * socreate _P((void)); -void sofree _P((struct SLIRPsocket *)); -int soread _P((struct SLIRPsocket *)); -void sorecvoob _P((struct SLIRPsocket *)); -int sosendoob _P((struct SLIRPsocket *)); -int sowrite _P((struct SLIRPsocket *)); -void sorecvfrom _P((struct SLIRPsocket *)); -int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int)); -void sorwakeup _P((struct SLIRPsocket *)); -void sowwakeup _P((struct SLIRPsocket *)); -void soisfconnecting _P((register struct SLIRPsocket *)); -void soisfconnected _P((register struct SLIRPsocket *)); -void sofcantrcvmore _P((struct SLIRPsocket *)); -void sofcantsendmore _P((struct SLIRPsocket *)); -void soisfdisconnected _P((struct SLIRPsocket *)); -void sofwdrain _P((struct SLIRPsocket *)); - -#endif /* _SOCKET_H_ */ diff --git a/src/include/slirp/tcp.h b/src/include/slirp/tcp.h deleted file mode 100644 index 5df25a8f0..000000000 --- a/src/include/slirp/tcp.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp.h 8.1 (Berkeley) 6/10/93 - * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp - */ - -#ifndef _TCP_H_ -#define _TCP_H_ - -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t tcp_seq; -#else -typedef u_int32_t tcp_seq; -#endif - -#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ -#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ - -extern int tcp_rcvspace; -extern int tcp_sndspace; -extern struct SLIRPsocket *tcp_last_so; - -#define TCP_SNDSPACE 8192 -#define TCP_RCVSPACE 8192 - -/* - * TCP header. - * Per RFC 793, September, 1981. - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct tcphdr { - u_int16_t th_sport; /* source port */ - u_int16_t th_dport; /* destination port */ - tcp_seq th_seq; /* sequence number */ - tcp_seq th_ack; /* acknowledgement number */ -#ifdef WORDS_BIGENDIAN - u_char th_off:4, /* data offset */ - th_x2:4; /* (unused) */ -#else - u_char th_x2:4, /* (unused) */ - th_off:4; /* data offset */ -#endif - u_int8_t th_flags; -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 - u_int16_t th_win; /* window */ - u_int16_t th_sum; /* checksum */ - u_int16_t th_urp; /* urgent pointer */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -#include "tcp_var.h" - -#define TCPOPT_EOL 0 -#define TCPOPT_NOP 1 -#define TCPOPT_MAXSEG 2 -#define TCPOLEN_MAXSEG 4 -#define TCPOPT_WINDOW 3 -#define TCPOLEN_WINDOW 3 -#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ -#define TCPOLEN_SACK_PERMITTED 2 -#define TCPOPT_SACK 5 /* Experimental */ -#define TCPOPT_TIMESTAMP 8 -#define TCPOLEN_TIMESTAMP 10 -#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ - -#define TCPOPT_TSTAMP_HDR \ - (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) - -/* - * Default maximum segment size for TCP. - * With an IP MSS of 576, this is 536, - * but 512 is probably more convenient. - * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). - * - * We make this 1460 because we only care about Ethernet in the qemu context. - */ -#define TCP_MSS 1460 - -#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ - -#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ - -/* - * User-settable options (used with setsockopt). - * - * We don't use the system headers on unix because we have conflicting - * local structures. We can't avoid the system definitions on Windows, - * so we undefine them. - */ -#undef TCP_NODELAY -#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -#undef TCP_MAXSEG -/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ - -/* - * TCP FSM state definitions. - * Per RFC793, September, 1981. - */ - -#define TCP_NSTATES 11 - -#define TCPS_CLOSED 0 /* closed */ -#define TCPS_LISTEN 1 /* listening for connection */ -#define TCPS_SYN_SENT 2 /* active, have sent syn */ -#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ -/* states < TCPS_ESTABLISHED are those where connections not established */ -#define TCPS_ESTABLISHED 4 /* established */ -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -/* states > TCPS_CLOSE_WAIT are those where user has closed */ -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ - -#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) -#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) -#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) - -/* - * TCP sequence numbers are 32 bit integers operated - * on with modular arithmetic. These macros can be - * used to compare such integers. - */ -#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) -#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) -#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) - -/* - * Macros to initialize tcp sequence numbers for - * send and receive from initial send and receive - * sequence numbers. - */ -#define tcp_rcvseqinit(tp) \ - (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 - -#define tcp_sendseqinit(tp) \ - (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss - -#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ - -extern tcp_seq tcp_iss; /* tcp initial send seq # */ - -extern char *tcpstates[]; - -#endif diff --git a/src/include/slirp/tcp_timer.h b/src/include/slirp/tcp_timer.h deleted file mode 100644 index 0bc438c76..000000000 --- a/src/include/slirp/tcp_timer.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 - * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp - */ - -#ifndef _TCP_TIMER_H_ -#define _TCP_TIMER_H_ - -/* - * Definitions of the TCP timers. These timers are counted - * down PR_SLOWHZ times a second. - */ -#define TCPT_NTIMERS 4 - -#define TCPT_REXMT 0 /* retransmit */ -#define TCPT_PERSIST 1 /* retransmit persistence */ -#define TCPT_KEEP 2 /* keep alive */ -#define TCPT_2MSL 3 /* 2*msl quiet time timer */ - -/* - * The TCPT_REXMT timer is used to force retransmissions. - * The TCP has the TCPT_REXMT timer set whenever segments - * have been sent for which ACKs are expected but not yet - * received. If an ACK is received which advances tp->snd_una, - * then the retransmit timer is cleared (if there are no more - * outstanding segments) or reset to the base value (if there - * are more ACKs expected). Whenever the retransmit timer goes off, - * we retransmit one unacknowledged segment, and do a backoff - * on the retransmit timer. - * - * The TCPT_PERSIST timer is used to keep window size information - * flowing even if the window goes shut. If all previous transmissions - * have been acknowledged (so that there are no retransmissions in progress), - * and the window is too small to bother sending anything, then we start - * the TCPT_PERSIST timer. When it expires, if the window is nonzero, - * we go to transmit state. Otherwise, at intervals send a single byte - * into the peer's window to force him to update our window information. - * We do this at most as often as TCPT_PERSMIN time intervals, - * but no more frequently than the current estimate of round-trip - * packet time. The TCPT_PERSIST timer is cleared whenever we receive - * a window update from the peer. - * - * The TCPT_KEEP timer is used to keep connections alive. If an - * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, - * but not yet established, then we drop the connection. Once the connection - * is established, if the connection is idle for TCPTV_KEEP_IDLE time - * (and keepalives have been enabled on the socket), we begin to probe - * the connection. We force the peer to send us a segment by sending: - * - * This segment is (deliberately) outside the window, and should elicit - * an ack segment in response from the peer. If, despite the TCPT_KEEP - * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE - * amount of time probing, then we drop the connection. - */ - -/* - * Time constants. - */ -#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ - -#define TCPTV_SRTTBASE 0 /* base roundtrip time; - if 0, no idea yet */ -#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ - -#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ -#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ - -#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ -#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ -#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ -#define TCPTV_KEEPCNT 8 /* max probes before drop */ - -#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ -/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ -#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ - -#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ - -#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ - - -#ifdef TCPTIMERS -char *tcptimers[] = - { "REXMT", "PERSIST", "KEEP", "2MSL" }; -#endif - -/* - * Force a time value to be in a certain range. - */ -#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ - (tv) = (value); \ - if ((tv) < (tvmin)) \ - (tv) = (tvmin); \ - else if ((tv) > (tvmax)) \ - (tv) = (tvmax); \ -} - -extern int tcp_keepidle; /* time before keepalive probes begin */ -extern int tcp_keepintvl; /* time between keepalive probes */ -extern int tcp_maxidle; /* time to drop after starting probes */ -extern int tcp_ttl; /* time to live for TCP segs */ -extern int tcp_backoff[]; - -struct tcpcb; - -void tcp_fasttimo _P((void)); -void tcp_slowtimo _P((void)); -void tcp_canceltimers _P((struct tcpcb *)); -struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); - -#endif diff --git a/src/include/slirp/tcp_var.h b/src/include/slirp/tcp_var.h deleted file mode 100644 index a9606c276..000000000 --- a/src/include/slirp/tcp_var.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 - * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp - */ - -#ifndef _TCP_VAR_H_ -#define _TCP_VAR_H_ - -#include "tcpip.h" -#include "tcp_timer.h" - -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t tcpiphdrp_32; -#else -#if SIZEOF_CHAR_P == 4 - typedef struct tcpiphdr *tcpiphdrp_32; -#else - typedef u_int32_t tcpiphdrp_32; -#endif -#endif - -/* - * Tcp control block, one per tcp; fields: - */ -struct tcpcb { - tcpiphdrp_32 seg_next; /* sequencing queue */ - tcpiphdrp_32 seg_prev; - short t_state; /* state of this connection */ - short t_timer[TCPT_NTIMERS]; /* tcp timers */ - short t_rxtshift; /* log(2) of rexmt exp. backoff */ - short t_rxtcur; /* current retransmit value */ - short t_dupacks; /* consecutive dup acks recd */ - u_short t_maxseg; /* maximum segment size */ - char t_force; /* 1 if forcing out a byte */ - u_short t_flags; -#define TF_ACKNOW 0x0001 /* ack peer immediately */ -#define TF_DELACK 0x0002 /* ack, but try to delay it */ -#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ -#define TF_NOOPT 0x0008 /* don't use tcp options */ -#define TF_SENTFIN 0x0010 /* have sent FIN */ -#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ -#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ -#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ -#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ -#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ - - /* Make it static for now */ -/* struct tcpiphdr *t_template; / * skeletal packet for transmit */ - struct tcpiphdr t_template; - - struct SLIRPsocket *t_socket; /* back pointer to socket */ -/* - * The following fields are used as in the protocol specification. - * See RFC783, Dec. 1981, page 21. - */ -/* send sequence variables */ - tcp_seq snd_una; /* send unacknowledged */ - tcp_seq snd_nxt; /* send next */ - tcp_seq snd_up; /* send urgent pointer */ - tcp_seq snd_wl1; /* window update seg seq number */ - tcp_seq snd_wl2; /* window update seg ack number */ - tcp_seq iss; /* initial send sequence number */ - u_int32_t snd_wnd; /* send window */ -/* receive sequence variables */ - u_int32_t rcv_wnd; /* receive window */ - tcp_seq rcv_nxt; /* receive next */ - tcp_seq rcv_up; /* receive urgent pointer */ - tcp_seq irs; /* initial receive sequence number */ -/* - * Additional variables for this implementation. - */ -/* receive variables */ - tcp_seq rcv_adv; /* advertised window */ -/* retransmit variables */ - tcp_seq snd_max; /* highest sequence number sent; - * used to recognize retransmits - */ -/* congestion control (for slow start, source quench, retransmit after loss) */ - u_int32_t snd_cwnd; /* congestion-controlled window */ - u_int32_t snd_ssthresh; /* snd_cwnd size threshold for - * for slow start exponential to - * linear switch - */ -/* - * transmit timing stuff. See below for scale of srtt and rttvar. - * "Variance" is actually smoothed difference. - */ - short t_idle; /* inactivity time */ - short t_rtt; /* round trip time */ - tcp_seq t_rtseq; /* sequence number being timed */ - short t_srtt; /* smoothed round-trip time */ - short t_rttvar; /* variance in round-trip time */ - u_short t_rttmin; /* minimum rtt allowed */ - u_int32_t max_sndwnd; /* largest window peer has offered */ - -/* out-of-band data */ - char t_oobflags; /* have some */ - char t_iobc; /* input character */ -#define TCPOOB_HAVEDATA 0x01 -#define TCPOOB_HADDATA 0x02 - short t_softerror; /* possible error not yet reported */ - -/* RFC 1323 variables */ - u_char snd_scale; /* window scaling for send window */ - u_char rcv_scale; /* window scaling for recv window */ - u_char request_r_scale; /* pending window scaling */ - u_char requested_s_scale; - u_int32_t ts_recent; /* timestamp echo data */ - u_int32_t ts_recent_age; /* when last updated */ - tcp_seq last_ack_sent; - -}; - -#define sototcpcb(so) ((so)->so_tcpcb) - -/* - * The smoothed round-trip time and estimated variance - * are stored as fixed point numbers scaled by the values below. - * For convenience, these scales are also used in smoothing the average - * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). - * With these scales, srtt has 3 bits to the right of the binary point, - * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the - * binary point, and is smoothed with an ALPHA of 0.75. - */ -#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ -#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ -#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ -#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ - -/* - * The initial retransmission should happen at rtt + 4 * rttvar. - * Because of the way we do the smoothing, srtt and rttvar - * will each average +1/2 tick of bias. When we compute - * the retransmit timer, we want 1/2 tick of rounding and - * 1 extra tick because of +-1/2 tick uncertainty in the - * firing of the timer. The bias will give us exactly the - * 1.5 tick we need. But, because the bias is - * statistical, we have to test that we don't drop below - * the minimum feasible timer (which is 2 ticks). - * This macro assumes that the value of TCP_RTTVAR_SCALE - * is the same as the multiplier for rttvar. - */ -#define TCP_REXMTVAL(tp) \ - (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) - -/* XXX - * We want to avoid doing m_pullup on incoming packets but that - * means avoiding dtom on the tcp reassembly code. That in turn means - * keeping an mbuf pointer in the reassembly queue (since we might - * have a cluster). As a quick hack, the source & destination - * port numbers (which are no longer needed once we've located the - * tcpcb) are overlayed with an mbuf pointer. - */ -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t mbufp_32; -#else -#if SIZEOF_CHAR_P == 4 -typedef struct SLIRPmbuf *mbufp_32; -#else -typedef u_int32_t mbufp_32; -#endif -#endif -#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) - -/* - * TCP statistics. - * Many of these should be kept per connection, - * but that's inconvenient at the moment. - */ -struct tcpstat { - u_long tcps_connattempt; /* connections initiated */ - u_long tcps_accepts; /* connections accepted */ - u_long tcps_connects; /* connections established */ - u_long tcps_drops; /* connections dropped */ - u_long tcps_conndrops; /* embryonic connections dropped */ - u_long tcps_closed; /* conn. closed (includes drops) */ - u_long tcps_segstimed; /* segs where we tried to get rtt */ - u_long tcps_rttupdated; /* times we succeeded */ - u_long tcps_delack; /* delayed acks sent */ - u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ - u_long tcps_rexmttimeo; /* retransmit timeouts */ - u_long tcps_persisttimeo; /* persist timeouts */ - u_long tcps_keeptimeo; /* keepalive timeouts */ - u_long tcps_keepprobe; /* keepalive probes sent */ - u_long tcps_keepdrops; /* connections dropped in keepalive */ - - u_long tcps_sndtotal; /* total packets sent */ - u_long tcps_sndpack; /* data packets sent */ - u_long tcps_sndbyte; /* data bytes sent */ - u_long tcps_sndrexmitpack; /* data packets retransmitted */ - u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ - u_long tcps_sndacks; /* ack-only packets sent */ - u_long tcps_sndprobe; /* window probes sent */ - u_long tcps_sndurg; /* packets sent with URG only */ - u_long tcps_sndwinup; /* window update-only packets sent */ - u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ - - u_long tcps_rcvtotal; /* total packets received */ - u_long tcps_rcvpack; /* packets received in sequence */ - u_long tcps_rcvbyte; /* bytes received in sequence */ - u_long tcps_rcvbadsum; /* packets received with ccksum errs */ - u_long tcps_rcvbadoff; /* packets received with bad offset */ -/* u_long tcps_rcvshort; */ /* packets received too short */ - u_long tcps_rcvduppack; /* duplicate-only packets received */ - u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ - u_long tcps_rcvpartduppack; /* packets with some duplicate data */ - u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ - u_long tcps_rcvoopack; /* out-of-order packets received */ - u_long tcps_rcvoobyte; /* out-of-order bytes received */ - u_long tcps_rcvpackafterwin; /* packets with data after window */ - u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ - u_long tcps_rcvafterclose; /* packets rcvd after "close" */ - u_long tcps_rcvwinprobe; /* rcvd window probe packets */ - u_long tcps_rcvdupack; /* rcvd duplicate acks */ - u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ - u_long tcps_rcvackpack; /* rcvd ack packets */ - u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ - u_long tcps_rcvwinupd; /* rcvd window update packets */ -/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ - u_long tcps_predack; /* times hdr predict ok for acks */ - u_long tcps_preddat; /* times hdr predict ok for data pkts */ - u_long tcps_socachemiss; /* tcp_last_so misses */ - u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ -}; - -extern struct tcpstat tcpstat; /* tcp statistics */ -extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ - -#endif diff --git a/src/include/slirp/tcpip.h b/src/include/slirp/tcpip.h deleted file mode 100644 index dff5a3c96..000000000 --- a/src/include/slirp/tcpip.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 - * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp - */ - -#ifndef _TCPIP_H_ -#define _TCPIP_H_ - -/* - * Tcp+ip header, after ip options removed. - */ -struct tcpiphdr { - struct ipovly ti_i; /* overlaid ip structure */ - struct tcphdr ti_t; /* tcp header */ -}; -#define ti_next ti_i.ih_next -#define ti_prev ti_i.ih_prev -#define ti_x1 ti_i.ih_x1 -#define ti_pr ti_i.ih_pr -#define ti_len ti_i.ih_len -#define ti_src ti_i.ih_src -#define ti_dst ti_i.ih_dst -#define ti_sport ti_t.th_sport -#define ti_dport ti_t.th_dport -#define ti_seq ti_t.th_seq -#define ti_ack ti_t.th_ack -#define ti_x2 ti_t.th_x2 -#define ti_off ti_t.th_off -#define ti_flags ti_t.th_flags -#define ti_win ti_t.th_win -#define ti_sum ti_t.th_sum -#define ti_urp ti_t.th_urp - -/* - * Just a clean way to get to the first byte - * of the packet - */ -struct tcpiphdr_2 { - struct tcpiphdr dummy; - char first_char; -}; - -#endif diff --git a/src/include/slirp/tftp.h b/src/include/slirp/tftp.h deleted file mode 100644 index ba4174115..000000000 --- a/src/include/slirp/tftp.h +++ /dev/null @@ -1,40 +0,0 @@ -/* tftp defines */ - -#define TFTP_SESSIONS_MAX 3 - -#define TFTP_SERVER 69 - -#define TFTP_RRQ 1 -#define TFTP_WRQ 2 -#define TFTP_DATA 3 -#define TFTP_ACK 4 -#define TFTP_ERROR 5 - -#define TFTP_FILENAME_MAX 512 - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct tftp_t { - struct ip ip; - struct udphdr udp; - u_int16_t tp_op; - union { - struct { - u_int16_t tp_block_nr; - u_int8_t tp_buf[512]; - } tp_data; - struct { - u_int16_t tp_error_code; - u_int8_t tp_msg[512]; - } tp_error; - u_int8_t tp_buf[512 + 2]; - } x; -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -void tftp_input(struct SLIRPmbuf *m); diff --git a/src/include/slirp/udp.h b/src/include/slirp/udp.h deleted file mode 100644 index 2f6b1e483..000000000 --- a/src/include/slirp/udp.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)udp.h 8.1 (Berkeley) 6/10/93 - * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp - */ - -#ifndef _UDP_H_ -#define _UDP_H_ - -#define UDP_TTL 0x60 -#define UDP_UDPDATALEN 16192 - -extern struct SLIRPsocket *udp_last_so; - -/* - * Udp protocol header. - * Per RFC 768, September, 1981. - */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct udphdr { - u_int16_t uh_sport; /* source port */ - u_int16_t uh_dport; /* destination port */ - int16_t uh_ulen; /* udp length */ - u_int16_t uh_sum; /* udp checksum */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -/* - * UDP kernel structures and variables. - */ -struct udpiphdr { - struct ipovly ui_i; /* overlaid ip structure */ - struct udphdr ui_u; /* udp header */ -}; -#define ui_next ui_i.ih_next -#define ui_prev ui_i.ih_prev -#define ui_x1 ui_i.ih_x1 -#define ui_pr ui_i.ih_pr -#define ui_len ui_i.ih_len -#define ui_src ui_i.ih_src -#define ui_dst ui_i.ih_dst -#define ui_sport ui_u.uh_sport -#define ui_dport ui_u.uh_dport -#define ui_ulen ui_u.uh_ulen -#define ui_sum ui_u.uh_sum - -struct udpstat { - /* input statistics: */ - u_long udps_ipackets; /* total input packets */ - u_long udps_hdrops; /* packet shorter than header */ - u_long udps_badsum; /* checksum error */ - u_long udps_badlen; /* data length larger than packet */ - u_long udps_noport; /* no socket on port */ - u_long udps_noportbcast; /* of above, arrived as broadcast */ - u_long udps_fullsock; /* not delivered, input socket full */ - u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ - /* output statistics: */ - u_long udps_opackets; /* total output packets */ -}; - -/* - * Names for UDP sysctl objects - */ -#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ -#define UDPCTL_MAXID 2 - -extern struct udpstat udpstat; -extern struct SLIRPsocket udb; -struct SLIRPmbuf; - -void udp_init _P((void)); -void udp_input _P((register struct SLIRPmbuf *, int)); -int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *)); -int udp_attach _P((struct SLIRPsocket *)); -void udp_detach _P((struct SLIRPsocket *)); -u_int8_t udp_tos _P((struct SLIRPsocket *)); -void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int)); -int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, - struct sockaddr_in *saddr, struct sockaddr_in *daddr, - int iptos); -#endif diff --git a/src/include/tinyglib.h b/src/include/tinyglib.h new file mode 100644 index 000000000..202bf2d7a --- /dev/null +++ b/src/include/tinyglib.h @@ -0,0 +1,200 @@ +/* + * 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. + * + * Minimal reimplementation of GLib for libslirp. + * + * + * + * Author: RichardG, + * + * Copyright 2020 RichardG. + */ +#ifndef TINYGLIB_H +# define TINYGLIB_H + +/* Define this to bypass TinyGLib and use full GLib instead. */ +#ifdef TINYGLIB_USE_GLIB +#include +#else + +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> + + +/* Definitions */ + +#define G_LITTLE_ENDIAN 1234 +#define G_BIG_ENDIAN 4321 +#define G_PDP_ENDIAN 3412 +#ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define G_BYTE_ORDER G_LITTLE_ENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define G_BYTE_ORDER G_BIG_ENDIAN +# elif __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__ +# define G_BYTE_ORDER G_PDP_ENDIAN +# endif +#endif +#ifndef G_BYTE_ORDER +/* Safe to assume LE for MSVC, as Windows is LE on all architectures. */ +# define G_BYTE_ORDER G_LITTLE_ENDIAN +#endif + +#ifdef _WIN32 +# define G_OS_WIN32 1 +#else +# define G_OS_UNIX 1 +#endif + +#define G_SPAWN_SEARCH_PATH 0 + +#if defined(__LP64__) || defined(__LLP64__) || defined(_WIN64) +# define GLIB_SIZEOF_VOID_P 8 +# if defined(__LLP64__) || defined(_WIN64) +# define GLIB_SIZEOF_LONG 4 +# else +# define GLIB_SIZEOF_LONG 8 +# endif +# define GLIB_SIZEOF_SIZE_T 8 +# define GLIB_SIZEOF_SSIZE_T 8 +#else +# define GLIB_SIZEOF_VOID_P 4 +# define GLIB_SIZEOF_LONG 4 +# define GLIB_SIZEOF_SIZE_T 4 +# define GLIB_SIZEOF_SSIZE_T 4 +#endif + + +/* Types */ + +/* Windows does not define ssize_t, so we need to define it here. */ +#ifndef _SSIZE_T_DEFINED +# define _SSIZE_T_DEFINED +# undef ssize_t +# ifdef _WIN64 +# define ssize_t int64_t +# else +# define ssize_t int32_t +# endif +#endif + +#define gboolean int +#define gchar char +#define gint int +#define gint16 int16_t +#define gint32 int32_t +#define gint64 int64_t +#define glong long +#define GPid void * +#define gpointer void * +#define gsize size_t +#define GSpawnFlags void * +#define GSpawnChildSetupFunc void * +#define gssize ssize_t +#define GString char +#define GStrv char ** +#define guint unsigned int +#define guint16 uint16_t +#define guint32 uint32_t +#define guint64 uint64_t + +typedef struct _GDebugKey { + char key[32]; + int val; +} GDebugKey; + +typedef struct _GError { + char message[1]; +} GError; + +typedef struct _GRand { + uint8_t dummy; +} GRand; + + +/* Functions */ +extern gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv, + gchar **envp, GSpawnFlags flags, + GSpawnChildSetupFunc child_setup, + gpointer user_data, GPid *child_pid, gint stdin_fd, + gint stdout_fd, gint stderr_fd, GError **error); +extern GString *g_string_new(gchar *base); +extern gchar *g_string_free(GString *string, gboolean free_segment); +extern gchar *g_strstr_len(const gchar *haystack, gssize haystack_len, const gchar *needle); +extern guint g_strv_length(gchar **str_array); + + +/* Macros */ +#define tinyglib_pclog(f, s, ...) pclog("TinyGLib " f "(): " s "\n", ##__VA_ARGS__) + +#define GLIB_CHECK_VERSION(a, b, c) 1 +#ifdef __GNUC__ +# define G_GNUC_PRINTF(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#else +# define G_GNUC_PRINTF(format_idx, arg_idx) +#endif +#define G_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) +#define G_STATIC_ASSERT(e) /* this should probably do something */ +#define G_UNLIKELY(e) (e) + +#define g_assert(e) do { if (!(e)) fatal("TinyGLib g_assert(" #e ")\n"); } while (0) +#ifdef __GNUC__ +# define g_assert_not_reached __builtin_unreachable +#else +# ifdef _MSC_VER +# define g_assert_not_reached() __assume(0) +# else +# define g_assert_not_reached() +# endif +#endif +#define g_critical(s, ...) fatal("TinyGLib g_critical(): " s "\n", ##__VA_ARGS__) +#ifdef TINYGLIB_DEBUG +# define g_debug(s, ...) tinyglib_pclog("g_debug", s, ##__VA_ARGS__) +#else +# define g_debug(s, ...) +#endif +#define g_error(s, ...) tinyglib_pclog("g_error", s, ##__VA_ARGS__) +#define g_error_free(err) +#define g_malloc0(s) calloc(1, s) +#define g_new(t, n) (t *) malloc(sizeof(t) * n) +#define g_new0(t, n) (t *) calloc(n, sizeof(t)) +#ifdef TINYGLIB_DEBUG +# define g_parse_debug_string(s, k, n) ((!!sizeof(k)) * -1) /* unimplemented; always enables all debug flags */ +#else +# define g_parse_debug_string(s, k, n) (!sizeof(k)) +#endif +#define g_rand_int_range(r, min, max) (rand() % (max + 1 - min) + min) +#define g_rand_new() calloc(1, sizeof(GRand)) +#define g_return_val_if_fail(e, v) if (!(e)) return (v) +#define g_shell_parse_argv(a, b, c, d) !!(sizeof(b)) /* unimplemented */ +#define g_strdup(str) ((str) ? strdup(str) : NULL) +#define g_warn_if_fail(e) do { if (!(e)) pclog("TinyGLib g_warn_if_fail(" #e ")\n"); } while (0) +#define g_warn_if_reached() pclog("TinyGLib g_warn_if_reached()\n") +#define g_warning(s, ...) tinyglib_pclog("g_warning", s, ##__VA_ARGS__) + + +/* Remapped functions */ +#define g_free free +#define g_getenv getenv +#define g_malloc malloc +#define g_rand_free free +#define g_realloc realloc +#define g_snprintf snprintf +#define g_strerror strerror +#define g_strfreev free +#define g_string_append_printf sprintf /* unimplemented */ +#define g_vsnprintf vsnprintf + + +#endif + +#endif diff --git a/src/include_make/86box/version.h b/src/include_make/86box/version.h new file mode 100644 index 000000000..63e675c1e --- /dev/null +++ b/src/include_make/86box/version.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * Definitions for project version, branding, and external links. + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ + +#define _LSTR(s) L ## s +#define LSTR(s) _LSTR(s) + +/* Version info. */ +#define EMU_NAME "86Box" +#define EMU_NAME_W LSTR(EMU_NAME) + +#define EMU_VERSION "3.6" +#define EMU_VERSION_W LSTR(EMU_VERSION) +#define EMU_VERSION_EX "3.50" /* frozen due to IDE re-detection behavior on Windows */ +#define EMU_VERSION_MAJ 3 +#define EMU_VERSION_MIN 6 +#define EMU_VERSION_PATCH 0 + +#define EMU_BUILD_NUM 0 + +#define EMU_VERSION_FULL EMU_VERSION +#define EMU_VERSION_FULL_W EMU_VERSION_W + +#define COPYRIGHT_YEAR "2022" + +/* Web URL info. */ +#define EMU_SITE "86box.net" +#define EMU_SITE_W LSTR(EMU_SITE) +#define EMU_ROMS_URL "https://github.com/86Box/roms/releases/latest" +#define EMU_ROMS_URL_W LSTR(EMU_ROMS_URL) +#ifdef RELEASE_BUILD +# define EMU_DOCS_URL "https://86box.readthedocs.io/en/v3.6/" +#else +# define EMU_DOCS_URL "https://86box.readthedocs.io" +#endif +#define EMU_DOCS_URL_W LSTR(EMU_DOCS_URL) diff --git a/src/io.c b/src/io.c index b09624064..268305e1a 100644 --- a/src/io.c +++ b/src/io.c @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> +#include <86box/timer.h> #include "cpu.h" #include <86box/m_amstrad.h> @@ -34,19 +35,26 @@ typedef struct _io_ { - uint8_t (*inb)(uint16_t addr, void *priv); - uint16_t (*inw)(uint16_t addr, void *priv); - uint32_t (*inl)(uint16_t addr, void *priv); + uint8_t (*inb)(uint16_t addr, void *priv); + uint16_t (*inw)(uint16_t addr, void *priv); + uint32_t (*inl)(uint16_t addr, void *priv); - void (*outb)(uint16_t addr, uint8_t val, void *priv); - void (*outw)(uint16_t addr, uint16_t val, void *priv); - void (*outl)(uint16_t addr, uint32_t val, void *priv); + void (*outb)(uint16_t addr, uint8_t val, void *priv); + void (*outw)(uint16_t addr, uint16_t val, void *priv); + void (*outl)(uint16_t addr, uint32_t val, void *priv); - void *priv; + void *priv; - struct _io_ *prev, *next; + struct _io_ *prev, *next; } io_t; +typedef struct { + uint8_t enable; + uint16_t base, size; + void (*func)(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv), + *priv; +} io_trap_t; + int initialized = 0; io_t *io[NPORTS], *io_last[NPORTS]; @@ -103,19 +111,19 @@ io_init(void) void -io_sethandler(uint16_t base, int size, +io_sethandler_common(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), uint32_t (*inl)(uint16_t addr, void *priv), void (*outb)(uint16_t addr, uint8_t val, void *priv), void (*outw)(uint16_t addr, uint16_t val, void *priv), void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) + void *priv, int step) { int c; io_t *p, *q = NULL; - for (c = 0; c < size; c++) { + for (c = 0; c < size; c += step) { p = io_last[base + c]; q = (io_t *) malloc(sizeof(io_t)); memset(q, 0, sizeof(io_t)); @@ -144,19 +152,19 @@ io_sethandler(uint16_t base, int size, void -io_removehandler(uint16_t base, int size, - uint8_t (*inb)(uint16_t addr, void *priv), - uint16_t (*inw)(uint16_t addr, void *priv), - uint32_t (*inl)(uint16_t addr, void *priv), - void (*outb)(uint16_t addr, uint8_t val, void *priv), - void (*outw)(uint16_t addr, uint16_t val, void *priv), - void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) +io_removehandler_common(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step) { int c; io_t *p, *q; - for (c = 0; c < size; c++) { + for (c = 0; c < size; c += step) { p = io[base + c]; if (!p) continue; @@ -185,7 +193,52 @@ io_removehandler(uint16_t base, int size, void -io_handler(int set, uint16_t base, int size, +io_handler_common(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step) +{ + if (set) + io_sethandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, step); + else + io_removehandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, step); +} + + +void +io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + io_sethandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 1); +} + + +void +io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + io_removehandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 1); +} + + +void +io_handler(int set, uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), uint32_t (*inl)(uint16_t addr, void *priv), @@ -194,118 +247,84 @@ io_handler(int set, uint16_t base, int size, void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv) { - if (set) - io_sethandler(base, size, inb, inw, inl, outb, outw, outl, priv); - else - io_removehandler(base, size, inb, inw, inl, outb, outw, outl, priv); + io_handler_common(set, base, size, inb, inw, inl, outb, outw, outl, priv, 1); } -#ifdef PC98 void io_sethandler_interleaved(uint16_t base, int size, - uint8_t (*inb)(uint16_t addr, void *priv), - uint16_t (*inw)(uint16_t addr, void *priv), - uint32_t (*inl)(uint16_t addr, void *priv), - void (*outb)(uint16_t addr, uint8_t val, void *priv), - void (*outw)(uint16_t addr, uint16_t val, void *priv), - void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) { - int c; - io_t *p, *q; - - size <<= 2; - for (c=0; cnext = q; - q->prev = p; - } else { - io[base + c] = q; - q->prev = NULL; - } - - q->inb = inb; - q->inw = inw; - q->inl = inl; - - q->outb = outb; - q->outw = outw; - q->outl = outl; - - q->priv = priv; - } + io_sethandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 2); } void io_removehandler_interleaved(uint16_t base, int size, - uint8_t (*inb)(uint16_t addr, void *priv), - uint16_t (*inw)(uint16_t addr, void *priv), - uint32_t (*inl)(uint16_t addr, void *priv), - void (*outb)(uint16_t addr, uint8_t val, void *priv), - void (*outw)(uint16_t addr, uint16_t val, void *priv), - void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) { - int c; - io_t *p, *q; - - size <<= 2; - for (c = 0; c < size; c += 2) { - p = io[base + c]; - if (!p) - return; - while(p) { - q = p->next; - if ((p->inb == inb) && (p->inw == inw) && - (p->inl == inl) && (p->outb == outb) && - (p->outw == outw) && (p->outl == outl) && - (p->priv == priv)) { - if (p->prev) - p->prev->next = p->next; - if (p->next) - p->next->prev = p->prev; - free(p); - break; - } - p = q; - } - } + io_removehandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 2); +} + + +void +io_handler_interleaved(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + io_handler_common(set, base, size, inb, inw, inl, outb, outw, outl, priv, 2); } -#endif uint8_t inb(uint16_t port) { uint8_t ret = 0xff; - io_t *p; + io_t *p, *q; int found = 0; int qfound = 0; p = io[port]; while(p) { + q = p->next; if (p->inb) { ret &= p->inb(port, p->priv); found |= 1; qfound++; } - p = p->next; + p = q; } if (port & 0x80) amstrad_latch = AMSTRAD_NOLATCH; - else if (port & 0x4000) + else if (port & 0x4000) amstrad_latch = AMSTRAD_SW10; else amstrad_latch = AMSTRAD_SW9; if (!found) - sub_cycles(io_delay); + cycles -= io_delay; + + /* TriGem 486-BIOS MHz output. */ + if (port == 0x1ed) + ret = 0xfe; io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); @@ -316,22 +335,23 @@ inb(uint16_t port) void outb(uint16_t port, uint8_t val) { - io_t *p; + io_t *p, *q; int found = 0; int qfound = 0; p = io[port]; while(p) { + q = p->next; if (p->outb) { p->outb(port, val, p->priv); found |= 1; qfound++; } - p = p->next; + p = q; } - + if (!found) { - sub_cycles(io_delay); + cycles -= io_delay; #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); @@ -347,7 +367,7 @@ outb(uint16_t port, uint8_t val) uint16_t inw(uint16_t port) { - io_t *p; + io_t *p, *q; uint16_t ret = 0xffff; int found = 0; int qfound = 0; @@ -356,38 +376,40 @@ inw(uint16_t port) p = io[port]; while(p) { + q = p->next; if (p->inw) { ret &= p->inw(port, p->priv); found |= 2; qfound++; } - p = p->next; + p = q; } ret8[0] = ret & 0xff; ret8[1] = (ret >> 8) & 0xff; for (i = 0; i < 2; i++) { - p = io[port + i]; + p = io[(port + i) & 0xffff]; while(p) { + q = p->next; if (p->inb && !p->inw) { ret8[i] &= p->inb(port + i, p->priv); found |= 1; qfound++; } - p = p->next; + p = q; } } ret = (ret8[1] << 8) | ret8[0]; if (port & 0x80) amstrad_latch = AMSTRAD_NOLATCH; - else if (port & 0x4000) + else if (port & 0x4000) amstrad_latch = AMSTRAD_SW10; else amstrad_latch = AMSTRAD_SW9; if (!found) - sub_cycles(io_delay); + cycles -= io_delay; io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); @@ -398,35 +420,37 @@ inw(uint16_t port) void outw(uint16_t port, uint16_t val) { - io_t *p; + io_t *p, *q; int found = 0; int qfound = 0; int i = 0; p = io[port]; while(p) { + q = p->next; if (p->outw) { p->outw(port, val, p->priv); found |= 2; qfound++; } - p = p->next; + p = q; } for (i = 0; i < 2; i++) { - p = io[port + i]; + p = io[(port + i) & 0xffff]; while(p) { + q = p->next; if (p->outb && !p->outw) { p->outb(port + i, val >> (i << 3), p->priv); found |= 1; qfound++; } - p = p->next; + p = q; } } if (!found) { - sub_cycles(io_delay); + cycles -= io_delay; #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); @@ -442,7 +466,7 @@ outw(uint16_t port, uint16_t val) uint32_t inl(uint16_t port) { - io_t *p; + io_t *p, *q; uint32_t ret = 0xffffffff; uint16_t ret16[2]; uint8_t ret8[4]; @@ -452,25 +476,27 @@ inl(uint16_t port) p = io[port]; while(p) { + q = p->next; if (p->inl) { ret &= p->inl(port, p->priv); found |= 4; qfound++; } - p = p->next; + p = q; } ret16[0] = ret & 0xffff; ret16[1] = (ret >> 16) & 0xffff; for (i = 0; i < 4; i += 2) { - p = io[port + i]; + p = io[(port + i) & 0xffff]; while(p) { + q = p->next; if (p->inw && !p->inl) { ret16[i >> 1] &= p->inw(port + i, p->priv); found |= 2; qfound++; } - p = p->next; + p = q; } } ret = (ret16[1] << 16) | ret16[0]; @@ -480,27 +506,28 @@ inl(uint16_t port) ret8[2] = (ret >> 16) & 0xff; ret8[3] = (ret >> 24) & 0xff; for (i = 0; i < 4; i++) { - p = io[port + i]; + p = io[(port + i) & 0xffff]; while(p) { + q = p->next; if (p->inb && !p->inw && !p->inl) { ret8[i] &= p->inb(port + i, p->priv); found |= 1; qfound++; } - p = p->next; + p = q; } } ret = (ret8[3] << 24) | (ret8[2] << 16) | (ret8[1] << 8) | ret8[0]; if (port & 0x80) amstrad_latch = AMSTRAD_NOLATCH; - else if (port & 0x4000) + else if (port & 0x4000) amstrad_latch = AMSTRAD_SW10; else amstrad_latch = AMSTRAD_SW9; if (!found) - sub_cycles(io_delay); + cycles -= io_delay; io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); @@ -511,7 +538,7 @@ inl(uint16_t port) void outl(uint16_t port, uint32_t val) { - io_t *p; + io_t *p, *q; int found = 0; int qfound = 0; int i = 0; @@ -519,42 +546,44 @@ outl(uint16_t port, uint32_t val) p = io[port]; if (p) { while(p) { + q = p->next; if (p->outl) { p->outl(port, val, p->priv); found |= 4; qfound++; - // return; } - p = p->next; + p = q; } } for (i = 0; i < 4; i += 2) { - p = io[port + i]; + p = io[(port + i) & 0xffff]; while(p) { + q = p->next; if (p->outw && !p->outl) { p->outw(port + i, val >> (i << 3), p->priv); found |= 2; qfound++; } - p = p->next; + p = q; } } for (i = 0; i < 4; i++) { - p = io[port + i]; + p = io[(port + i) & 0xffff]; while(p) { + q = p->next; if (p->outb && !p->outw && !p->outl) { p->outb(port + i, val >> (i << 3), p->priv); found |= 1; qfound++; } - p = p->next; + p = q; } } if (!found) { - sub_cycles(io_delay); + cycles -= io_delay; #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); @@ -565,3 +594,116 @@ outl(uint16_t port, uint32_t val) return; } + + +static uint8_t +io_trap_readb(uint16_t addr, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(1, addr, 0, 0, trap->priv); + return 0xff; +} + + +static uint16_t +io_trap_readw(uint16_t addr, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(2, addr, 0, 0, trap->priv); + return 0xffff; +} + + +static uint32_t +io_trap_readl(uint16_t addr, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(4, addr, 0, 0, trap->priv); + return 0xffffffff; +} + + +static void +io_trap_writeb(uint16_t addr, uint8_t val, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(1, addr, 1, val, trap->priv); +} + + +static void +io_trap_writew(uint16_t addr, uint16_t val, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(2, addr, 1, val, trap->priv); +} + + +static void +io_trap_writel(uint16_t addr, uint32_t val, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(4, addr, 1, val, trap->priv); +} + + +void * +io_trap_add(void (*func)(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv), + void *priv) +{ + /* Instantiate new I/O trap. */ + io_trap_t *trap = (io_trap_t *) malloc(sizeof(io_trap_t)); + trap->enable = 0; + trap->base = trap->size = 0; + trap->func = func; + trap->priv = priv; + + return trap; +} + + +void +io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size) +{ + io_trap_t *trap = (io_trap_t *) handle; + if (!trap) + return; + + io_log("I/O: Remapping trap from %04X-%04X (enable %d) to %04X-%04X (enable %d)\n", + trap->base, trap->base + trap->size - 1, trap->enable, addr, addr + size - 1, enable); + + /* Remove old I/O mapping. */ + if (trap->enable && trap->size) { + io_removehandler(trap->base, trap->size, + io_trap_readb, io_trap_readw, io_trap_readl, + io_trap_writeb, io_trap_writew, io_trap_writel, + trap); + } + + /* Set trap enable flag, base address and size. */ + trap->enable = !!enable; + trap->base = addr; + trap->size = size; + + /* Add new I/O mapping. */ + if (trap->enable && trap->size) { + io_sethandler(trap->base, trap->size, + io_trap_readb, io_trap_readw, io_trap_readl, + io_trap_writeb, io_trap_writew, io_trap_writel, + trap); + } +} + + +void +io_trap_remove(void *handle) +{ + io_trap_t *trap = (io_trap_t *) handle; + if (!trap) + return; + + /* Unmap I/O trap before freeing it. */ + io_trap_remap(trap, 0, 0, 0); + + free(trap); +} diff --git a/src/ioapic.c b/src/ioapic.c index a45ad14c7..e308b9a1c 100644 --- a/src/ioapic.c +++ b/src/ioapic.c @@ -7,7 +7,7 @@ * This file is part of the 86Box distribution. * * Skeleton I/O APIC implementation, currently housing the MPS - * table patcher for machines that require it. + * table patcher for machines that require it. * * * @@ -121,10 +121,15 @@ ioapic_init(const device_t *info) const device_t ioapic_device = { - "I/O Advanced Programmable Interrupt Controller", - DEVICE_AT, - 0, - ioapic_init, ioapic_close, NULL, - NULL, NULL, NULL, - NULL + .name = "I/O Advanced Programmable Interrupt Controller", + .internal_name = "ioapic", + .flags = DEVICE_AT, + .local = 0, + .init = ioapic_init, + .close = ioapic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/log.c b/src/log.c new file mode 100644 index 000000000..99bab97a5 --- /dev/null +++ b/src/log.c @@ -0,0 +1,165 @@ +/* + * 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. + * + * The handler of the new logging system. + * + * + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2021 Miran Grca. + * Copyright 2021 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/mem.h> +#include "cpu.h" +#include <86box/plat.h> +#include <86box/version.h> +#include <86box/log.h> + + +#ifndef RELEASE_BUILD +typedef struct +{ + char buff[1024], *dev_name; + int seen, suppr_seen; +} log_t; + + +extern FILE *stdlog; /* file to log output to */ + + +void +log_set_suppr_seen(void *priv, int suppr_seen) +{ + log_t *log = (log_t *) priv; + + log->suppr_seen = suppr_seen; +} + + +void +log_set_dev_name(void *priv, char *dev_name) +{ + log_t *log = (log_t *) priv; + + log->dev_name = dev_name; +} + + +static void +log_copy(log_t *log, char *dest, const char *src, size_t dest_size) +{ + memset(dest, 0x00, dest_size * sizeof(char)); + if (log && log->dev_name && strcmp(log->dev_name, "")) { + strcat(dest, log->dev_name); + strcat(dest, ": "); + } + strcat(dest, src); +} + + +/* + * Log something to the logfile or stdout. + * + * To avoid excessively-large logfiles because some + * module repeatedly logs, we keep track of what is + * being logged, and catch repeating entries. + */ +void +log_out(void *priv, const char *fmt, va_list ap) +{ + log_t *log = (log_t *) priv; + char temp[1024], fmt2[1024]; + + if (log == NULL) + return; + + if (strcmp(fmt, "") == 0) + return; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + if (log->suppr_seen && ! strcmp(log->buff, temp)) + log->seen++; + else { + if (log->suppr_seen && log->seen) { + log_copy(log, fmt2, "*** %d repeats ***\n", 1024); + fprintf(stdlog, fmt2, log->seen); + } + log->seen = 0; + strcpy(log->buff, temp); + log_copy(log, fmt2, temp, 1024); + fprintf(stdlog, fmt2, ap); + } + + fflush(stdlog); +} + + +void +log_fatal(void *priv, const char *fmt, ...) +{ + log_t *log = (log_t *) priv; + char temp[1024], fmt2[1024]; + va_list ap; + + if (log == NULL) + return; + + va_start(ap, fmt); + log_copy(log, fmt2, fmt, 1024); + vsprintf(temp, fmt2, ap); + fatal_ex(fmt2, ap); + va_end(ap); + exit(-1); +} + + +void * +log_open(char *dev_name) +{ + log_t *log = malloc(sizeof(log_t)); + + memset(log, 0, sizeof(log_t)); + + log->dev_name = dev_name; + log->suppr_seen = 1; + + return (void *) log; +} + + +void +log_close(void *priv) +{ + log_t *log = (log_t *) priv; + + free(log); +} +#endif diff --git a/src/lpt.c b/src/lpt.c index 9d1228082..df8276ae1 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -11,57 +11,68 @@ #include <86box/pic.h> #include <86box/sound.h> #include <86box/prt_devs.h> +#include <86box/net_plip.h> -lpt_port_t lpt_ports[3]; +lpt_port_t lpt_ports[PARALLEL_MAX]; - -static const struct -{ - const char *name; - const char *internal_name; - const lpt_device_t *device; -} lpt_devices[] = -{ - {"None", "none", NULL}, - {"Disney Sound Source", "dss", &dss_device}, - {"LPT DAC / Covox Speech Thing", "lpt_dac", &lpt_dac_device}, - {"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device}, - {"Generic Text Printer", "text_prt", &lpt_prt_text_device}, - {"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device}, - {"Generic PostScript Printer", "postscript", &lpt_prt_ps_device}, - {"", "", NULL} +const lpt_device_t lpt_none_device = { + .name = "None", + .internal_name = "none", + .init = NULL, + .close = NULL, + .write_data = NULL, + .write_ctrl = NULL, + .read_data = NULL, + .read_status = NULL, + .read_ctrl = NULL }; +static const struct { + const char *internal_name; + const lpt_device_t *device; +} lpt_devices[] = { +// clang-format off + {"none", &lpt_none_device }, + {"dss", &dss_device }, + {"lpt_dac", &lpt_dac_device }, + {"lpt_dac_stereo", &lpt_dac_stereo_device }, + {"text_prt", &lpt_prt_text_device }, + {"dot_matrix", &lpt_prt_escp_device }, + {"postscript", &lpt_prt_ps_device }, + {"plip", &lpt_plip_device }, + {"dongle_savquest", &lpt_hasp_savquest_device }, + {"", NULL } +// clang-format on +}; char * lpt_device_get_name(int id) { - if (strlen((char *) lpt_devices[id].name) == 0) - return NULL; - - return (char *) lpt_devices[id].name; + if (strlen((char *) lpt_devices[id].internal_name) == 0) + return NULL; + if (!lpt_devices[id].device) + return "None"; + return (char *) lpt_devices[id].device->name; } - char * lpt_device_get_internal_name(int id) { if (strlen((char *) lpt_devices[id].internal_name) == 0) - return NULL; + return NULL; return (char *) lpt_devices[id].internal_name; } - int lpt_device_get_from_internal_name(char *s) { int c = 0; while (strlen((char *) lpt_devices[c].internal_name) != 0) { - if (strcmp(lpt_devices[c].internal_name, s) == 0) - return c; - c++; + if (strcmp(lpt_devices[c].internal_name, s) == 0) + return c; + c++; } return 0; @@ -73,10 +84,10 @@ lpt_devices_init(void) { int i = 0; - for (i = 0; i < 3; i++) { + for (i = 0; i < PARALLEL_MAX; i++) { lpt_ports[i].dt = (lpt_device_t *) lpt_devices[lpt_ports[i].device].device; - if (lpt_ports[i].dt) + if (lpt_ports[i].dt && lpt_ports[i].dt->init) lpt_ports[i].priv = lpt_ports[i].dt->init(&lpt_ports[i]); } } @@ -88,11 +99,11 @@ lpt_devices_close(void) int i = 0; lpt_port_t *dev; - for (i = 0; i < 3; i++) { + for (i = 0; i < PARALLEL_MAX; i++) { dev = &lpt_ports[i]; - if (dev->dt) - dev->dt->close(dev->priv); + if (lpt_ports[i].dt && lpt_ports[i].dt->close) + dev->dt->close(dev->priv); dev->dt = NULL; } @@ -106,7 +117,7 @@ lpt_write(uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: - if (dev->dt && dev->dt->write_data) + if (dev->dt && dev->dt->write_data && dev->priv) dev->dt->write_data(val, dev->priv); dev->dat = val; break; @@ -115,7 +126,7 @@ lpt_write(uint16_t port, uint8_t val, void *priv) break; case 2: - if (dev->dt && dev->dt->write_ctrl) + if (dev->dt && dev->dt->write_ctrl && dev->priv) dev->dt->write_ctrl(val, dev->priv); dev->ctrl = val; dev->enable_irq = val & 0x10; @@ -132,21 +143,21 @@ lpt_read(uint16_t port, void *priv) switch (port & 3) { case 0: - if (dev->dt && dev->dt->read_data) + if (dev->dt && dev->dt->read_data && dev->priv) ret = dev->dt->read_data(dev->priv); else ret = dev->dat; break; case 1: - if (dev->dt && dev->dt->read_status) - ret = dev->dt->read_status(dev->priv) | 0x0f; + if (dev->dt && dev->dt->read_status && dev->priv) + ret = dev->dt->read_status(dev->priv) | 0x07; else ret = 0xdf; break; case 2: - if (dev->dt && dev->dt->read_ctrl) + if (dev->dt && dev->dt->read_ctrl && dev->priv) ret = (dev->dt->read_ctrl(dev->priv) & 0xef) | dev->enable_irq; else ret = 0xe0 | dev->ctrl | dev->enable_irq; @@ -175,10 +186,10 @@ void lpt_init(void) { int i; - uint16_t default_ports[3] = { 0x378, 0x278, 0x3bc }; - uint8_t default_irqs[3] = { 7, 5, 7 }; + uint16_t default_ports[PARALLEL_MAX] = { LPT1_ADDR, LPT2_ADDR, LPT_MDA_ADDR, LPT4_ADDR }; + uint8_t default_irqs[PARALLEL_MAX] = { LPT1_IRQ, LPT2_IRQ, LPT_MDA_IRQ, LPT4_IRQ }; - for (i = 0; i < 3; i++) { + for (i = 0; i < PARALLEL_MAX; i++) { lpt_ports[i].addr = 0xffff; lpt_ports[i].irq = 0xff; lpt_ports[i].enable_irq = 0x10; diff --git a/src/mac/CMakeLists.txt b/src/mac/CMakeLists.txt new file mode 100644 index 000000000..2fdc2363a --- /dev/null +++ b/src/mac/CMakeLists.txt @@ -0,0 +1,53 @@ +# +# 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. +# +# CMake build script. +# +# Authors: dob205, +# Jerome Vernet +# David Hrdlička, +# +# Copyright 2021 dob205. +# Copyright 2021 Jerome Vernet. +# Copyright 2021 David Hrdlička. +# + +# Pick the bundle icon depending on the release channel +if(RELEASE_BUILD) + set(APP_ICON_MACOSX icons/release/86Box.icns) +elseif(BETA_BUILD) + set(APP_ICON_MACOSX icons/beta/86Box.icns) +elseif(ALPHA_BUILD) + set(APP_ICON_MACOSX icons/dev/86Box.icns) +else() + set(APP_ICON_MACOSX icons/branch/86Box.icns) +endif() + +target_link_libraries(86Box "-framework AppKit") +target_sources(86Box PRIVATE ${APP_ICON_MACOSX}) + +# Make sure the icon is copied to the bundle +set_source_files_properties(${APP_ICON_MACOSX} + TARGET_DIRECTORY 86Box + PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + +# Prepare long version string +if(EMU_BUILD) + set(LONG_VER_STRING "${CMAKE_PROJECT_VERSION} [${EMU_BUILD}]") +else() + set(LONG_VER_STRING "${CMAKE_PROJECT_VERSION}") +endif() + +# Generate Info.plist +configure_file(Info.plist.in Info.plist @ONLY) +set_target_properties(86Box + PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) + +#set(XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "YES") +#set(XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-") +#set(XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/mac/codesign/dev/app.entitlements) diff --git a/src/mac/Info.plist.in b/src/mac/Info.plist.in new file mode 100644 index 000000000..2f2080460 --- /dev/null +++ b/src/mac/Info.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + An emulator of old computers + CFBundleIconFile + 86Box.icns + CFBundleIdentifier + net.86Box.86Box + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + @LONG_VER_STRING@ + CFBundleName + 86Box + CFBundlePackageType + APPL + CFBundleShortVersionString + @CMAKE_PROJECT_VERSION@ + CFBundleSignature + ???? + CFBundleVersion + @CMAKE_PROJECT_VERSION_MAJOR@.@CMAKE_PROJECT_VERSION_MINOR@.@CMAKE_PROJECT_VERSION_PATCH@.@EMU_BUILD_NUM@ + CSResourcesFileMapped + + NSHumanReadableCopyright + © 2007-@EMU_COPYRIGHT_YEAR@ 86Box contributors + NSPrincipalClass + NSApplication + NSHighResolutionCapable + True + + diff --git a/src/mac/icons/beta/86Box.icns b/src/mac/icons/beta/86Box.icns new file mode 100644 index 000000000..0068beeda Binary files /dev/null and b/src/mac/icons/beta/86Box.icns differ diff --git a/src/mac/icons/branch/86Box.icns b/src/mac/icons/branch/86Box.icns new file mode 100644 index 000000000..a2631c66e Binary files /dev/null and b/src/mac/icons/branch/86Box.icns differ diff --git a/src/mac/icons/dev/86Box.icns b/src/mac/icons/dev/86Box.icns new file mode 100644 index 000000000..5ff137b55 Binary files /dev/null and b/src/mac/icons/dev/86Box.icns differ diff --git a/src/mac/icons/release/86Box.icns b/src/mac/icons/release/86Box.icns new file mode 100644 index 000000000..4f15661ed Binary files /dev/null and b/src/mac/icons/release/86Box.icns differ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt new file mode 100644 index 000000000..62bd5c61f --- /dev/null +++ b/src/machine/CMakeLists.txt @@ -0,0 +1,42 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c + m_xt_philips.c + m_xt_t1000.c m_xt_t1000_vid.c m_xt_xi8088.c m_xt_zenith.c m_pcjr.c + m_amstrad.c m_europc.c m_xt_olivetti.c m_tandy.c m_v86p.c + m_at.c m_at_commodore.c + m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c + m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c + m_at_socket4.c m_at_socket5.c m_at_socket7_3v.c m_at_socket7.c + m_at_sockets7.c m_at_socket8.c m_at_slot1.c m_at_slot2.c m_at_socket370.c + m_at_misc.c) + +if(AN430TX) + target_compile_definitions(mch PRIVATE USE_AN430TX) +endif() + +if(DESKPRO386) + target_compile_definitions(mch PRIVATE USE_DESKPRO386) +endif() + +if(LASERXT) + target_sources(mch PRIVATE m_xt_laserxt.c) + target_compile_definitions(mch PRIVATE USE_LASERXT) +endif() + +if(OPEN_AT) + target_compile_definitions(mch PRIVATE USE_OPEN_AT) +endif() diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 46cf9a215..3b0235d51 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -108,7 +108,8 @@ typedef struct { stat; uint8_t plane_write, /* 1512/200 */ plane_read, /* 1512/200 */ - border; /* 1512/200 */ + border, /* 1512/200 */ + invert; /* 512/640 */ int fontbase; /* 1512/200 */ int linepos, displine; @@ -118,6 +119,7 @@ typedef struct { cursoron, cgablink; int vsynctime; + int fullchange; int vadj; uint16_t ma, maback; int dispon; @@ -228,6 +230,9 @@ vid_out_1512(uint16_t addr, uint8_t val, void *priv) amsvid_t *vid = (amsvid_t *)priv; uint8_t old; + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + switch (addr) { case 0x03d4: vid->crtcreg = val & 31; @@ -238,7 +243,7 @@ vid_out_1512(uint16_t addr, uint8_t val, void *priv) vid->crtc[vid->crtcreg] = val & crtc_mask[vid->crtcreg]; if (old != val) { if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; recalc_timings_1512(vid); } } @@ -277,6 +282,9 @@ vid_in_1512(uint16_t addr, void *priv) amsvid_t *vid = (amsvid_t *)priv; uint8_t ret = 0xff; + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + switch (addr) { case 0x03d4: ret = vid->crtcreg; @@ -300,8 +308,7 @@ vid_write_1512(uint32_t addr, uint8_t val, void *priv) { amsvid_t *vid = (amsvid_t *)priv; - egawrites++; - sub_cycles(12); + cycles -= 12; addr &= 0x3fff; if ((vid->cgamode & 0x12) == 0x12) { @@ -319,8 +326,7 @@ vid_read_1512(uint32_t addr, void *priv) { amsvid_t *vid = (amsvid_t *)priv; - egareads++; - sub_cycles(12); + cycles -= 12; addr &= 0x3fff; if ((vid->cgamode & 0x12) == 0x12) @@ -383,7 +389,7 @@ vid_poll_1512(void *priv) if (vid->cgamode & 0x20) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { cols[1] = (attr & 15) + 16; @@ -412,7 +418,7 @@ vid_poll_1512(void *priv) if (vid->cgamode & 0x20) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; - if ((vid->blink & 16) && (attr & 0x80)) + if ((vid->blink & 16) && (attr & 0x80)) cols[1] = cols[0]; } else { cols[1] = (attr & 15) + 16; @@ -429,9 +435,9 @@ vid_poll_1512(void *priv) } } else { for (c = 0; c < 8; c++) { - buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = - buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } @@ -499,13 +505,13 @@ vid_poll_1512(void *priv) if (vid->vsynctime) vid->stat |= 8; vid->displine++; - if (vid->displine >= 360) + if (vid->displine >= 360) vid->displine = 0; } else { timer_advance_u64(&vid->timer, vid->dispontime); - if ((vid->lastline - vid->firstline) == 199) + if ((vid->lastline - vid->firstline) == 199) vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ - if (vid->dispon) + if (vid->dispon) vid->stat &= ~1; vid->linepos = 0; if (vid->vsynctime) { @@ -513,9 +519,9 @@ vid_poll_1512(void *priv) if (! vid->vsynctime) vid->stat &= ~8; } - if (vid->sc == (vid->crtc[11] & 31)) { - vid->con = 0; - vid->coff = 1; + if (vid->sc == (vid->crtc[11] & 31)) { + vid->con = 0; + vid->coff = 1; } if (vid->vadj) { vid->sc++; @@ -572,10 +578,10 @@ vid_poll_1512(void *priv) } if (enable_overscan) { - video_blit_memtoscreen_8(0, (vid->firstline - 4) << 1, 0, ((vid->lastline - vid->firstline) + 8) << 1, + video_blit_memtoscreen_8(0, (vid->firstline - 4) << 1, xsize, ((vid->lastline - vid->firstline) + 8) << 1); } else { - video_blit_memtoscreen_8(8, vid->firstline << 1, 0, (vid->lastline - vid->firstline) << 1, + video_blit_memtoscreen_8(8, vid->firstline << 1, xsize, (vid->lastline - vid->firstline) << 1); } } @@ -664,96 +670,73 @@ vid_speed_change_1512(void *priv) recalc_timings_1512(vid); } - -device_config_t vid_1512_config[] = -{ - { - "display_type", "Display type", CONFIG_SELECTION, "", 0, - { - { - "PC-CM (Colour)", 0 - }, - { - "PC-MM (Monochrome)", 3 - }, - { - "" - } - } - }, - { - "codepage", "Hardware font", CONFIG_SELECTION, "", 3, - { - { - "US English", 3 - }, - { - "Danish", 1 - }, - { - "Greek", 0 - }, - { - "" - } - } - }, - { - "language", "BIOS language", CONFIG_SELECTION, "", 7, - { - { - "English", 7 - }, - { - "German", 6 - }, - { - "French", 5 - }, - { - "Spanish", 4 - }, - { - "Danish", 3 - }, - { - "Swedish", 2 - }, - { - "Italian", 1 - }, - { - "Diagnostic mode", 0 - }, - { - "" - } - } - }, - { - "", "", -1 - } +const device_config_t vid_1512_config[] = { + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "PC-CM (Colour)", .value = 0 }, + { .description = "PC-MM (Monochrome)", .value = 3 }, + { .description = "" } + } + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "US English", .value = 3 }, + { .description = "Danish", .value = 1 }, + { .description = "Greek", .value = 0 }, + { .description = "" } + } + }, + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "English", .value = 7 }, + { .description = "German", .value = 6 }, + { .description = "French", .value = 5 }, + { .description = "Spanish", .value = 4 }, + { .description = "Danish", .value = 3 }, + { .description = "Swedish", .value = 2 }, + { .description = "Italian", .value = 1 }, + { .description = "Diagnostic mode", .value = 0 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; - -static const device_t vid_1512_device = { - "Amstrad PC1512 (video)", - 0, 0, - NULL, vid_close_1512, NULL, - NULL, - vid_speed_change_1512, - NULL, - vid_1512_config +const device_t vid_1512_device = { + .name = "Amstrad PC1512 (video)", + .internal_name = "vid_1512", + .flags = 0, + .local = 0, + .init = NULL, + .close = vid_close_1512, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_change_1512, + .force_redraw = NULL, + .config = vid_1512_config }; - -const device_t * -pc1512_get_device(void) -{ - return(&vid_1512_device); -} - - static void recalc_timings_1640(amsvid_t *vid) { @@ -844,7 +827,7 @@ vid_init_1640(amstrad_t *ams) vid = (amsvid_t *)malloc(sizeof(amsvid_t)); memset(vid, 0x00, sizeof(amsvid_t)); - rom_init(&vid->bios_rom, L"roms/machines/pc1640/40100", + rom_init(&vid->bios_rom, "roms/machines/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); ega_init(&vid->ega, 9, 0); @@ -892,62 +875,44 @@ vid_speed_changed_1640(void *priv) recalc_timings_1640(vid); } - -device_config_t vid_1640_config[] = -{ - { - "language", "BIOS language", CONFIG_SELECTION, "", 7, - { - { - "English", 7 - }, - { - "German", 6 - }, - { - "French", 5 - }, - { - "Spanish", 4 - }, - { - "Danish", 3 - }, - { - "Swedish", 2 - }, - { - "Italian", 1 - }, - { - "Diagnostic mode", 0 - }, - { - "" - } - } - }, - { - "", "", -1 +const device_config_t vid_1640_config[] = { + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "English", .value = 7 }, + { .description = "German", .value = 6 }, + { .description = "French", .value = 5 }, + { .description = "Spanish", .value = 4 }, + { .description = "Danish", .value = 3 }, + { .description = "Swedish", .value = 2 }, + { .description = "Italian", .value = 1 }, + { .description = "Diagnostic mode", .value = 0 }, + { .description = "" } } + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_t vid_1640_device = { - "Amstrad PC1640 (video)", - 0, 0, - NULL, vid_close_1640, NULL, - NULL, - vid_speed_changed_1640, - NULL, - vid_1640_config +const device_t vid_1640_device = { + .name = "Amstrad PC1640 (video)", + .internal_name = "vid_1640", + .flags = 0, + .local = 0, + .init = NULL, + .close = vid_close_1640, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed_1640, + .force_redraw = NULL, + .config = vid_1640_config }; -const device_t * -pc1640_get_device(void) -{ - return(&vid_1640_device); -} - /* Display type */ #define PC200_CGA 0 /* CGA monitor */ #define PC200_MDA 1 /* MDA monitor */ @@ -990,7 +955,7 @@ vid_speed_changed_200(void *priv) /* LCD colour mappings - * + * * 0 => solid green * 1 => blue on green * 2 => green on blue @@ -1052,13 +1017,13 @@ static void set_lcd_cols(uint8_t mode_reg) break; case 1: - lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][0][0] = lcdcols[c][1][0] = lcdcols[c][1][1] = green; lcdcols[c][0][1] = blue; break; case 2: - lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][0][0] = lcdcols[c][1][0] = lcdcols[c][1][1] = blue; lcdcols[c][0][1] = green; break; @@ -1083,7 +1048,7 @@ vid_in_200(uint16_t addr, void *priv) switch (addr) { case 0x03b8: return(mda->ctrl); - + case 0x03d8: return(cga->cgamode); @@ -1128,7 +1093,7 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) if (!(vid->operation_ctrl & 0x40) && mda->crtcreg <= 11) { vid->crtc_index = 0x20 | (mda->crtcreg & 0x1f); if (vid->operation_ctrl & 0x80) - nmi = 1; + nmi_raise(); vid->reg_3df = val; return; } @@ -1136,7 +1101,7 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) mda->crtc[mda->crtcreg] = val & crtc_mask[mda->crtcreg]; if (old != val) { if (mda->crtcreg < 0xe || mda->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; mda_recalctimings(mda); } } @@ -1149,18 +1114,18 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) vid->crtc_index &= 0x1F; vid->crtc_index |= 0x80; if (vid->operation_ctrl & 0x80) - nmi = 1; + nmi_raise(); return; -/* CGA writes ============================================================== */ +/* CGA writes ============================================================== */ case 0x03d1: case 0x03d3: case 0x03d5: case 0x03d7: if (!(vid->operation_ctrl & 0x40) && cga->crtcreg <= 11) { vid->crtc_index = 0x20 | (cga->crtcreg & 0x1f); - if (vid->operation_ctrl & 0x80) - nmi = 1; + if (vid->operation_ctrl & 0x80) + nmi_raise(); vid->reg_3df = val; return; } @@ -1168,7 +1133,7 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) cga->crtc[cga->crtcreg] = val & crtc_mask[cga->crtcreg]; if (old != val) { if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; cga_recalctimings(cga); } } @@ -1182,7 +1147,7 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) vid->crtc_index &= 0x1f; vid->crtc_index |= 0x80; if (vid->operation_ctrl & 0x80) - nmi = 1; + nmi_raise(); else set_lcd_cols(val); return; @@ -1191,12 +1156,12 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) case 0x03de: vid->crtc_index = 0x1f; /* NMI only seems to be triggered if the value being written has the high - * bit set (enable NMI). So it only protects writes to this port if you + * bit set (enable NMI). So it only protects writes to this port if you * let it? */ if (val & 0x80) { vid->operation_ctrl = val; vid->crtc_index |= 0x40; - nmi = 1; + nmi_raise(); return; } timer_disable(&vid->cga.timer); @@ -1219,12 +1184,12 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) timer_advance_u64(&vid->timer, 1); /* Bit 2 disables the IDA. We don't support dynamic enabling - * and disabling of the IDA (instead, PCEM disconnects the - * IDA from the bus altogether) so don't implement this */ + * and disabling of the IDA (instead, PCEM disconnects the + * IDA from the bus altogether) so don't implement this */ - /* Enable the appropriate memory ranges depending whether + /* Enable the appropriate memory ranges depending whether * the IDA is configured as MDA or CGA */ - if (vid->emulation == PC200_MDA || + if (vid->emulation == PC200_MDA || vid->emulation == PC200_LCDM) { mem_mapping_disable(&vid->cga.mapping); mem_mapping_enable(&vid->mda.mapping); @@ -1244,8 +1209,8 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) } -static void -lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, +static void +lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, uint8_t attr, int drawcursor, int blink, int sc, int mode160, uint8_t control) { @@ -1255,8 +1220,8 @@ lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, uint16_t mask; if (attr & 8) { /* bright */ - /* The brightness algorithm appears to be: replace any bit sequence 011 - * with 001 (assuming an extra 0 to the left of the byte). + /* The brightness algorithm appears to be: replace any bit sequence 011 + * with 001 (assuming an extra 0 to the left of the byte). */ bright = bits; for (c = 0, mask = 0x100; c < 7; c++, mask >>= 1) { @@ -1278,8 +1243,8 @@ lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, } -static void -lcd_draw_char_40(amsvid_t *vid, uint32_t *buffer, uint8_t chr, +static void +lcd_draw_char_40(amsvid_t *vid, uint32_t *buffer, uint8_t chr, uint8_t attr, int drawcursor, int blink, int sc, uint8_t control) { @@ -1303,7 +1268,7 @@ lcd_draw_char_40(amsvid_t *vid, uint32_t *buffer, uint8_t chr, } -static void +static void lcdm_poll(amsvid_t *vid) { mda_t *mda = &vid->mda; @@ -1320,7 +1285,7 @@ lcdm_poll(amsvid_t *vid) mda->stat |= 1; mda->linepos = 1; oldsc = mda->sc; - if ((mda->crtc[8] & 3) == 3) + if ((mda->crtc[8] & 3) == 3) mda->sc = (mda->sc << 1) & 7; if (mda->dispon) { if (mda->displine < mda->firstline) @@ -1340,7 +1305,7 @@ lcdm_poll(amsvid_t *vid) if (mda->vc == mda->crtc[7] && !mda->sc) mda->stat |= 8; mda->displine++; - if (mda->displine >= 500) + if (mda->displine >= 500) mda->displine=0; } else { timer_advance_u64(&vid->timer, mda->dispontime); @@ -1352,8 +1317,8 @@ lcdm_poll(amsvid_t *vid) mda->stat&=~8; } if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) { - mda->con = 0; - mda->coff = 1; + mda->con = 0; + mda->coff = 1; } if (mda->vadj) { mda->sc++; @@ -1371,7 +1336,7 @@ lcdm_poll(amsvid_t *vid) oldvc = mda->vc; mda->vc++; mda->vc &= 127; - if (mda->vc == mda->crtc[6]) + if (mda->vc == mda->crtc[6]) mda->dispon=0; if (oldvc == mda->crtc[4]) { mda->vc = 0; @@ -1398,7 +1363,7 @@ lcdm_poll(amsvid_t *vid) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen(0, mda->firstline, 0, ysize, xsize, ysize); + video_blit_memtoscreen(0, mda->firstline, xsize, ysize); frames++; video_res_x = mda->crtc[1]; video_res_y = mda->crtc[6]; @@ -1419,7 +1384,7 @@ lcdm_poll(amsvid_t *vid) } -static void +static void lcdc_poll(amsvid_t *vid) { cga_t *cga = &vid->cga; @@ -1439,7 +1404,7 @@ lcdc_poll(amsvid_t *vid) cga->cgastat |= 1; cga->linepos = 1; oldsc = cga->sc; - if ((cga->crtc[8] & 3) == 3) + if ((cga->crtc[8] & 3) == 3) cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; if (cga->cgadispon) { if (cga->displine < cga->firstline) { @@ -1496,7 +1461,7 @@ lcdc_poll(amsvid_t *vid) if (cga->vc == cga->crtc[7] && !cga->sc) cga->cgastat |= 8; cga->displine++; - if (cga->displine >= 360) + if (cga->displine >= 360) cga->displine = 0; } else { timer_advance_u64(&vid->timer, cga->dispontime); @@ -1507,8 +1472,8 @@ lcdc_poll(amsvid_t *vid) cga->cgastat &= ~8; } if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) { - cga->con = 0; - cga->coff = 1; + cga->con = 0; + cga->coff = 1; } if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) cga->maback = cga->ma; @@ -1529,7 +1494,7 @@ lcdc_poll(amsvid_t *vid) cga->vc++; cga->vc &= 127; - if (cga->vc == cga->crtc[6]) + if (cga->vc == cga->crtc[6]) cga->cgadispon = 0; if (oldvc == cga->crtc[4]) { @@ -1566,7 +1531,7 @@ lcdc_poll(amsvid_t *vid) video_force_resize_set(0); } - video_blit_memtoscreen(0, cga->firstline << 1, 0, (cga->lastline - cga->firstline) << 1, + video_blit_memtoscreen(0, cga->firstline << 1, xsize, (cga->lastline - cga->firstline) << 1); } @@ -1600,7 +1565,7 @@ lcdc_poll(amsvid_t *vid) } if (cga->cgadispon) cga->cgastat &= ~1; - if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) cga->con = 1; if (cga->cgadispon && (cga->cgamode & 1)) { for (x = 0; x < (cga->crtc[1] << 1); x++) @@ -1610,7 +1575,7 @@ lcdc_poll(amsvid_t *vid) } -static void +static void vid_poll_200(void *p) { amsvid_t *vid = (amsvid_t *)p; @@ -1619,7 +1584,7 @@ vid_poll_200(void *p) case PC200_LCDM: lcdm_poll(vid); return; - case PC200_LCDC: + case PC200_LCDC: lcdc_poll(vid); return; } @@ -1638,11 +1603,9 @@ vid_init_200(amstrad_t *ams) memset(vid, 0x00, sizeof(amsvid_t)); vid->emulation = device_get_config_int("video_emulation"); - cga_palette = (device_get_config_int("display_type") << 1); - ams_inform(vid); /* Default to CGA */ - vid->dipswitches = 0x10; + vid->dipswitches = 0x10; vid->type = ams->type; if (ams->type == AMS_PC200) switch (vid->emulation) { @@ -1672,17 +1635,20 @@ vid_init_200(amstrad_t *ams) cga_init(cga); mda_init(mda); + cga_palette = (device_get_config_int("display_type") << 1); + ams_inform(vid); + /* Attribute 8 is white on black (on a real MDA it's black on black) */ mda_setcol(0x08, 0, 1, 15); mda_setcol(0x88, 0, 1, 15); /* Attribute 64 is black on black (on a real MDA it's white on black) */ mda_setcol(0x40, 0, 1, 0); - mda_setcol(0xC0, 0, 1, 0); + mda_setcol(0xC0, 0, 1, 0); cga->fontbase = (device_get_config_int("codepage") & 3) * 256; timer_add(&vid->timer, vid_poll_200, vid, 1); - mem_mapping_add(&vid->mda.mapping, 0xb0000, 0x08000, + mem_mapping_add(&vid->mda.mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, mda); mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); @@ -1691,8 +1657,17 @@ vid_init_200(amstrad_t *ams) overscan_x = overscan_y = 16; - green = makecol(0x1C, 0x71, 0x31); - blue = makecol(0x0f, 0x21, 0x3f); + if (ams->type == AMS_PC200) + vid->invert = 0; + else + vid->invert = device_get_config_int("invert"); + if (vid->invert) { + blue = makecol(0x1C, 0x71, 0x31); + green = makecol(0x0f, 0x21, 0x3f); + } else { + green = makecol(0x1C, 0x71, 0x31); + blue = makecol(0x0f, 0x21, 0x3f); + } cgapal_rebuild(); set_lcd_cols(0); @@ -1715,337 +1690,270 @@ vid_close_200(void *priv) { amsvid_t *vid = (amsvid_t *)priv; - free(vid->cga.vram); - free(vid->mda.vram); + if (vid->cga.vram != vid->mda.vram) { + free(vid->cga.vram); + free(vid->mda.vram); + } else + free(vid->cga.vram); + + vid->cga.vram = vid->mda.vram = NULL; free(vid); } -device_config_t vid_200_config[] = -{ - /* TODO: Should have options here for: - * - * > Display port (TTL or RF) - */ - { - "video_emulation", "Display type", CONFIG_SELECTION, "", PC200_CGA, - { - { - "CGA monitor", PC200_CGA - }, - { - "MDA monitor", PC200_MDA - }, - { - "Television", PC200_TV - }, - { - "" - } - } - }, - { - "display_type", "Monitor type", CONFIG_SELECTION, "", 0, - { - { - "RGB", 0 - }, - { - "RGB (no brown)", 4 - }, - { - "Green Monochrome", 1 - }, - { - "Amber Monochrome", 2 - }, - { - "White Monochrome", 3 - }, - { - "" - } - } +const device_config_t vid_200_config[] = { + /* TODO: Should have options here for: + * + * > Display port (TTL or RF) + */ + { + .name = "video_emulation", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = PC200_CGA, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "CGA monitor", .value = PC200_CGA }, + { .description = "MDA monitor", .value = PC200_MDA }, + { .description = "Television", .value = PC200_TV }, + { .description = "" } + } + }, + { + .name = "display_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = 0 }, + { .description = "RGB (no brown)", .value = 4 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "White Monochrome", .value = 3 }, + { .description = "" } + } + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "US English", .value = 3 }, + { .description = "Portugese", .value = 2 }, + { .description = "Norwegian", .value = 1 }, + { .description = "Greek", .value = 0 }, + { .description = "" } + } + }, + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "English", .value = 7 }, + { .description = "German", .value = 6 }, + { .description = "French", .value = 5 }, + { .description = "Spanish", .value = 4 }, + { .description = "Danish", .value = 3 }, + { .description = "Swedish", .value = 2 }, + { .description = "Italian", .value = 1 }, + { .description = "Diagnostic mode", .value = 0 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +const device_t vid_200_device = { + .name = "Amstrad PC200 (video)", + .internal_name = "vid_200", + .flags = 0, + .local = 0, + .init = NULL, + .close = vid_close_200, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed_200, + .force_redraw = NULL, + .config = vid_200_config +}; + +const device_config_t vid_ppc512_config[] = { + /* TODO: Should have options here for: + * + * > Display port (TTL or RF) + */ + { + .name = "video_emulation", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = PC200_LCDC, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "CGA monitor", .value = PC200_CGA }, + { .description = "MDA monitor", .value = PC200_MDA }, + { .description = "LCD (CGA mode)", .value = PC200_LCDC }, + { .description = "LCD (MDA mode)", .value = PC200_LCDM }, + { .description = "" } }, - { - "codepage", "Hardware font", CONFIG_SELECTION, "", 3, - { - { - "US English", 3 - }, - { - "Portugese", 2 - }, - { - "Norwegian", 1 - }, - { - "Greek", 0 - }, - { - "" - } - } - }, - { - "language", "BIOS language", CONFIG_SELECTION, "", 7, - { - { - "English", 7 - }, - { - "German", 6 - }, - { - "French", 5 - }, - { - "Spanish", 4 - }, - { - "Danish", 3 - }, - { - "Swedish", 2 - }, - { - "Italian", 1 - }, - { - "Diagnostic mode", 0 - }, - { - "" - } - } - }, - { - "", "", -1 - } -}; - - -static const device_t vid_200_device = { - "Amstrad PC200 (video)", - 0, 0, - NULL, vid_close_200, NULL, - NULL, - vid_speed_changed_200, - NULL, - vid_200_config -}; - - -const device_t * -pc200_get_device(void) -{ - return(&vid_200_device); -} - - -device_config_t vid_ppc512_config[] = -{ - /* TODO: Should have options here for: - * - * > Display port (TTL or RF) - */ - { - "video_emulation", "Display type", CONFIG_SELECTION, "", PC200_LCDC, - { - { - "CGA monitor", PC200_CGA - }, - { - "MDA monitor", PC200_MDA - }, - { - "LCD (CGA mode)", PC200_LCDC - }, - { - "LCD (MDA mode)", PC200_LCDM - }, - { - "" - } - }, - }, - { - "display_type", "Monitor type", CONFIG_SELECTION, "", 0, - { - { - "RGB", 0 - }, - { - "RGB (no brown)", 4 - }, - { - "Green Monochrome", 1 - }, - { - "Amber Monochrome", 2 - }, - { - "White Monochrome", 3 - }, - { - "" - } - }, + }, + { + .name = "display_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = 0 }, + { .description = "RGB (no brown)", .value = 4 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "White Monochrome", .value = 3 }, + { .description = "" } }, - { - "codepage", "Hardware font", CONFIG_SELECTION, "", 3, - { - { - "US English", 3 - }, - { - "Portugese", 2 - }, - { - "Norwegian",1 - }, - { - "Greek", 0 - }, - { - "" - } - }, + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "US English", .value = 3 }, + { .description = "Portugese", .value = 2 }, + { .description = "Norwegian", .value = 1 }, + { .description = "Greek", .value = 0 }, + { .description = "" } }, - { - "language", "BIOS language", CONFIG_SELECTION, "", 7, - { - { - "English", 7 - }, - { - "German", 6 - }, - { - "French", 5 - }, - { - "Spanish", 4 - }, - { - "Danish", 3 - }, - { - "Swedish", 2 - }, - { - "Italian", 1 - }, - { - "Diagnostic mode", 0 - }, - { - "" - } - } - }, - { - "", "", -1 + }, + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "English", .value = 7 }, + { .description = "German", .value = 6 }, + { .description = "French", .value = 5 }, + { .description = "Spanish", .value = 4 }, + { .description = "Danish", .value = 3 }, + { .description = "Swedish", .value = 2 }, + { .description = "Italian", .value = 1 }, + { .description = "Diagnostic mode", .value = 0 }, + { .description = "" } } + }, + { + .name = "invert", + .description = "Invert LCD colors", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_t vid_ppc512_device = { - "Amstrad PPC512 (video)", - 0, 0, - NULL, vid_close_200, NULL, - NULL, - vid_speed_changed_200, - NULL, - vid_ppc512_config +const device_t vid_ppc512_device = { + .name = "Amstrad PPC512 (video)", + .internal_name = "vid_ppc512", + .flags = 0, + .local = 0, + .init = NULL, + .close = vid_close_200, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed_200, + .force_redraw = NULL, + .config = vid_ppc512_config }; - -const device_t * -ppc512_get_device(void) -{ - return(&vid_ppc512_device); -} - - -device_config_t vid_pc2086_config[] = -{ - { - "language", "BIOS language", CONFIG_SELECTION, "", 7, - { - { - "English", 7 - }, - { - "Diagnostic mode", 0 - }, - { - "" - } - } - }, - { - "", "", -1 +const device_config_t vid_pc2086_config[] = { + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "English", .value = 7 }, + { .description = "Diagnostic mode", .value = 0 }, + { .description = "" } } + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_t vid_pc2086_device = { - "Amstrad PC2086", - 0, 0, - NULL, NULL, NULL, - NULL, - NULL, - NULL, - vid_pc2086_config +const device_t vid_pc2086_device = { + .name = "Amstrad PC2086", + .internal_name = "vid_pc2086", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = vid_pc2086_config }; - -const device_t * -pc2086_get_device(void) -{ - return(&vid_pc2086_device); -} - - -device_config_t vid_pc3086_config[] = -{ - { - "language", "BIOS language", CONFIG_SELECTION, "", 7, - { - { - "English", 7 - }, - { - "Diagnostic mode", 3 - }, - { - "" - } - } - }, - { - "", "", -1 +const device_config_t vid_pc3086_config[] = { + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "English", .value = 7 }, + { .description = "Diagnostic mode", .value = 3 }, + { .description = "" } } + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_t vid_pc3086_device = { - "Amstrad PC3086", - 0, 0, - NULL, NULL, NULL, - NULL, - NULL, - NULL, - vid_pc3086_config +const device_t vid_pc3086_device = { + .name = "Amstrad PC3086", + .internal_name = "vid_pc3086", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = vid_pc3086_config }; - -const device_t * -pc3086_get_device(void) -{ - return(&vid_pc3086_device); -} - - static void ms_write(uint16_t addr, uint8_t val, void *priv) { @@ -2111,8 +2019,7 @@ kbd_adddata(uint16_t val) static void kbd_adddata_ex(uint16_t val) { - kbd_adddata(val); - // kbd_adddata_process(val, kbd_adddata); + kbd_adddata_process(val, kbd_adddata); } @@ -2150,9 +2057,9 @@ kbd_write(uint16_t port, uint8_t val, void *priv) speaker_update(); speaker_gated = val & 0x01; speaker_enable = val & 0x02; - if (speaker_enable) + if (speaker_enable) was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 0x01); + pit_devs[0].set_gate(pit_devs[0].data, 2, val & 0x01); if (val & 0x80) { /* Keyboard enabled, so enable PA reading. */ @@ -2221,9 +2128,9 @@ kbd_read(uint16_t port, void *priv) else { ams->key_waiting = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; - ams->wantirq = 1; + ams->wantirq = 1; } - } + } break; case 0x61: @@ -2403,7 +2310,16 @@ machine_amstrad_init(const machine_t *model, int type) memset(ams, 0x00, sizeof(amstrad_t)); ams->type = type; - device_add(&amstrad_nvr_device); + switch(type) { + case AMS_PC200: + case AMS_PPC512: + device_add(&amstrad_no_nmi_nvr_device); + break; + + default: + device_add(&amstrad_nvr_device); + break; + } machine_common_init(model); @@ -2433,27 +2349,29 @@ machine_amstrad_init(const machine_t *model, int type) ams->language = 7; + video_reset(gfxcard); + if (gfxcard == VID_INTERNAL) switch(type) { case AMS_PC1512: - loadfont(L"roms/machines/pc1512/40078", 8); + loadfont("roms/machines/pc1512/40078", 8); device_context(&vid_1512_device); ams->language = device_get_config_int("language"); vid_init_1512(ams); device_context_restore(); device_add_ex(&vid_1512_device, ams->vid); break; - + case AMS_PPC512: - loadfont(L"roms/machines/ppc512/40109", 1); + loadfont("roms/machines/ppc512/40109", 1); device_context(&vid_ppc512_device); ams->language = device_get_config_int("language"); vid_init_200(ams); device_context_restore(); device_add_ex(&vid_ppc512_device, ams->vid); break; - + case AMS_PC1640: - loadfont(L"roms/video/mda/mda.rom", 0); + loadfont("roms/video/mda/mda.rom", 0); device_context(&vid_1640_device); ams->language = device_get_config_int("language"); vid_init_1640(ams); @@ -2462,7 +2380,7 @@ machine_amstrad_init(const machine_t *model, int type) break; case AMS_PC200: - loadfont(L"roms/machines/pc200/40109", 1); + loadfont("roms/machines/pc200/40109", 1); device_context(&vid_200_device); ams->language = device_get_config_int("language"); vid_init_200(ams); @@ -2495,6 +2413,7 @@ machine_amstrad_init(const machine_t *model, int type) keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; keyboard_scan = 1; + keyboard_set_is_amstrad(((type == AMS_PC1512) || (type == AMS_PC1640)) ? 0 : 1); io_sethandler(0x0078, 2, ms_read, NULL, NULL, ms_write, NULL, NULL, ams); @@ -2507,8 +2426,7 @@ machine_amstrad_init(const machine_t *model, int type) mouse_set_poll(ms_poll, ams); } - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } @@ -2517,10 +2435,10 @@ machine_pc1512_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/pc1512/40044", - L"roms/machines/pc1512/40043", + ret = bios_load_interleaved("roms/machines/pc1512/40044", + "roms/machines/pc1512/40043", 0x000fc000, 16384, 0); - ret &= rom_present(L"roms/machines/pc1512/40078"); + ret &= rom_present("roms/machines/pc1512/40078"); if (bios_only || !ret) return ret; @@ -2536,10 +2454,10 @@ machine_pc1640_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/pc1640/40044.v3", - L"roms/machines/pc1640/40043.v3", + ret = bios_load_interleaved("roms/machines/pc1640/40044.v3", + "roms/machines/pc1640/40043.v3", 0x000fc000, 16384, 0); - ret &= rom_present(L"roms/machines/pc1640/40100"); + ret &= rom_present("roms/machines/pc1640/40100"); if (bios_only || !ret) return ret; @@ -2555,10 +2473,10 @@ machine_pc200_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/pc200/pc20v2.1", - L"roms/machines/pc200/pc20v2.0", + ret = bios_load_interleaved("roms/machines/pc200/pc20v2.1", + "roms/machines/pc200/pc20v2.0", 0x000fc000, 16384, 0); - ret &= rom_present(L"roms/machines/pc200/40109"); + ret &= rom_present("roms/machines/pc200/40109"); if (bios_only || !ret) return ret; @@ -2574,10 +2492,10 @@ machine_ppc512_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ppc512/40107.v2", - L"roms/machines/ppc512/40108.v2", + ret = bios_load_interleaved("roms/machines/ppc512/40107.v2", + "roms/machines/ppc512/40108.v2", 0x000fc000, 16384, 0); - ret &= rom_present(L"roms/machines/ppc512/40109"); + ret &= rom_present("roms/machines/ppc512/40109"); if (bios_only || !ret) return ret; @@ -2593,10 +2511,10 @@ machine_pc2086_init(const machine_t *model) { int ret; - ret = bios_load_interleavedr(L"roms/machines/pc2086/40179.ic129", - L"roms/machines/pc2086/40180.ic132", + ret = bios_load_interleavedr("roms/machines/pc2086/40179.ic129", + "roms/machines/pc2086/40180.ic132", 0x000fc000, 65536, 0); - ret &= rom_present(L"roms/machines/pc2086/40186.ic171"); + ret &= rom_present("roms/machines/pc2086/40186.ic171"); if (bios_only || !ret) return ret; @@ -2612,9 +2530,9 @@ machine_pc3086_init(const machine_t *model) { int ret; - ret = bios_load_linearr(L"roms/machines/pc3086/fc00.bin", + ret = bios_load_linearr("roms/machines/pc3086/fc00.bin", 0x000fc000, 65536, 0); - ret &= rom_present(L"roms/machines/pc3086/c000.bin"); + ret &= rom_present("roms/machines/pc3086/c000.bin"); if (bios_only || !ret) return ret; diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 7adc98ecd..df3c4bd8b 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -56,6 +56,7 @@ #include <86box/lpt.h> #include <86box/rom.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/machine.h> @@ -64,17 +65,21 @@ machine_at_common_init_ex(const machine_t *model, int type) { machine_common_init(model); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); + refresh_at_enable = 1; + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_at); pic2_init(); dma16_init(); + if (!(type & 4)) + device_add(&port_6x_device); + type &= 3; + if (type == 1) device_add(&ibmat_nvr_device); else if (type == 0) device_add(&at_nvr_device); - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } @@ -158,8 +163,8 @@ machine_at_ibm_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmat/62x0820.u27", - L"roms/machines/ibmat/62x0821.u47", + ret = bios_load_interleaved("roms/machines/ibmat/62x0820.u27", + "roms/machines/ibmat/62x0821.u47", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -170,14 +175,15 @@ machine_at_ibm_init(const machine_t *model) return ret; } -//IBM AT machines with custom BIOSes + +/* IBM AT machines with custom BIOSes */ int machine_at_ibmatquadtel_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmatquadtel/BIOS_30MAR90_U27_QUADTEL_ENH_286_BIOS_3.05.01_27256.BIN", - L"roms/machines/ibmatquadtel/BIOS_30MAR90_U47_QUADTEL_ENH_286_BIOS_3.05.01_27256.BIN", + ret = bios_load_interleaved("roms/machines/ibmatquadtel/BIOS_30MAR90_U27_QUADTEL_ENH_286_BIOS_3.05.01_27256.BIN", + "roms/machines/ibmatquadtel/BIOS_30MAR90_U47_QUADTEL_ENH_286_BIOS_3.05.01_27256.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -188,13 +194,14 @@ machine_at_ibmatquadtel_init(const machine_t *model) return ret; } + int machine_at_ibmatami_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmatami/BIOS_5170_30APR89_U27_AMI_27256.BIN", - L"roms/machines/ibmatami/BIOS_5170_30APR89_U47_AMI_27256.BIN", + ret = bios_load_interleaved("roms/machines/ibmatami/BIOS_5170_30APR89_U27_AMI_27256.BIN", + "roms/machines/ibmatami/BIOS_5170_30APR89_U47_AMI_27256.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -205,13 +212,14 @@ machine_at_ibmatami_init(const machine_t *model) return ret; } + int machine_at_ibmatpx_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmatpx/BIOS ROM - PhoenixBIOS A286 - Version 1.01 - Even.bin", - L"roms/machines/ibmatpx/BIOS ROM - PhoenixBIOS A286 - Version 1.01 - Odd.bin", + ret = bios_load_interleaved("roms/machines/ibmatpx/BIOS ROM - PhoenixBIOS A286 - Version 1.01 - Even.bin", + "roms/machines/ibmatpx/BIOS ROM - PhoenixBIOS A286 - Version 1.01 - Odd.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -222,13 +230,14 @@ machine_at_ibmatpx_init(const machine_t *model) return ret; } + int machine_at_ibmxt286_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", - L"roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", + ret = bios_load_interleaved("roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", + "roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -239,13 +248,12 @@ machine_at_ibmxt286_init(const machine_t *model) return ret; } -#if defined(DEV_BRANCH) && defined(USE_SIEMENS) int machine_at_siemens_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/siemens/286BIOS.BIN", + ret = bios_load_linear("roms/machines/siemens/286BIOS.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -255,15 +263,15 @@ machine_at_siemens_init(const machine_t *model) return ret; } -#endif + #if defined(DEV_BRANCH) && defined(USE_OPEN_AT) int -machine_at_open_at_init(const machine_t *model) +machine_at_openat_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/open_at/bios.bin", + ret = bios_load_linear("roms/machines/openat/bios.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 6b6e00e52..295c2fd82 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -12,9 +12,11 @@ * * Authors: Sarah Walker, * Miran Grca, + * EngiNerd * * Copyright 2010-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. + * Copyright 2020 EngiNerd. */ #include #include @@ -33,9 +35,14 @@ #include <86box/rom.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/fdc_ext.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/sio.h> +#include <86box/serial.h> #include <86box/video.h> +#include <86box/vid_cga.h> +#include <86box/flash.h> #include <86box/machine.h> int @@ -43,8 +50,8 @@ machine_at_mr286_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/mr286/V000B200-1", - L"roms/machines/mr286/V000B200-2", + ret = bios_load_interleaved("roms/machines/mr286/V000B200-1", + "roms/machines/mr286/V000B200-2", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -52,6 +59,8 @@ machine_at_mr286_init(const machine_t *model) machine_at_common_ide_init(model); device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); return ret; @@ -62,42 +71,22 @@ static void machine_at_headland_common_init(int ht386) { device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); if (ht386) - device_add(&headland_386_device); + device_add(&headland_ht18b_device); else - device_add(&headland_device); + device_add(&headland_gc10x_device); } - -#if defined(DEV_BRANCH) && defined(USE_AMI386SX) -int -machine_at_headland_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/ami386/ami386.bin", - 0x000f0000, 65536, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_ide_init(model); - - machine_at_headland_common_init(1); - - return ret; -} -#endif - - int machine_at_tg286m_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/tg286m/ami.bin", + ret = bios_load_linear("roms/machines/tg286m/ami.bin", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -110,20 +99,12 @@ machine_at_tg286m_init(const machine_t *model) return ret; } - -const device_t * -at_ama932j_get_device(void) -{ - return &oti067_ama932j_device; -} - - int machine_at_ama932j_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ama932j/ami.bin", + ret = bios_load_linear("roms/machines/ama932j/ami.bin", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -131,40 +112,69 @@ machine_at_ama932j_init(const machine_t *model) machine_at_common_ide_init(model); - machine_at_headland_common_init(1); - if (gfxcard == VID_INTERNAL) device_add(&oti067_ama932j_device); + machine_at_headland_common_init(1); + return ret; } + int machine_at_quadt286_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/quadt286/QUADT89L.ROM", - L"roms/machines/quadt286/QUADT89H.ROM", + ret = bios_load_interleaved("roms/machines/quadt286/QUADT89L.ROM", + "roms/machines/quadt286/QUADT89H.ROM", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); - device_add(&keyboard_at_device); + machine_at_common_init(model); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - device_add(&headland_device); + + device_add(&headland_gc10x_device); return ret; } + +int +machine_at_quadt386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/quadt386sx/QTC-SXM-EVEN-U3-05-07.BIN", + "roms/machines/quadt386sx/QTC-SXM-ODD-U3-05-07.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&headland_gc10x_device); + + return ret; +} + + int machine_at_neat_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/dtk386/3cto001.bin", + ret = bios_load_linear("roms/machines/dtk386/3cto001.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -173,6 +183,8 @@ machine_at_neat_init(const machine_t *model) machine_at_init(model); device_add(&neat_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); return ret; @@ -184,7 +196,7 @@ machine_at_neat_ami_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ami286/amic206.bin", + ret = bios_load_linear("roms/machines/ami286/AMIC206.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -193,6 +205,8 @@ machine_at_neat_ami_init(const machine_t *model) machine_at_common_init(model); device_add(&neat_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); device_add(&keyboard_at_ami_device); @@ -200,12 +214,13 @@ machine_at_neat_ami_init(const machine_t *model) return ret; } + int machine_at_px286_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/px286/KENITEC.BIN", + ret = bios_load_linear("roms/machines/px286/KENITEC.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -213,58 +228,42 @@ machine_at_px286_init(const machine_t *model) machine_at_common_init(model); device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - device_add(&neat_device); - - return ret; -} - - -int -machine_at_goldstar386_init(const machine_t *model) -{ - int ret; - - ret = bios_load_interleaved(L"roms/machines/goldstar386/386-Goldstar-E.BIN", - L"roms/machines/goldstar386/386-Goldstar-O.BIN", - 0x000f0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_init(model); device_add(&neat_device); - device_add(&fdc_at_device); return ret; } + int machine_at_micronics386_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/micronics386/386-Micronics-09-00021-EVEN.BIN", - L"roms/machines/micronics386/386-Micronics-09-00021-ODD.BIN", - 0x000f0000, 131072, 0); + ret = bios_load_interleaved("roms/machines/micronics386/386-Micronics-09-00021-EVEN.BIN", + "roms/machines/micronics386/386-Micronics-09-00021-ODD.BIN", + 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_init(model); - device_add(&neat_device); - device_add(&fdc_at_device); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); return ret; } + static void machine_at_scat_init(const machine_t *model, int is_v4) { - machine_at_init(model); - device_add(&fdc_at_device); + machine_at_common_init(model); + device_add(&keyboard_at_ami_device); if (is_v4) device_add(&scat_4_device); @@ -279,6 +278,8 @@ machine_at_scatsx_init(const machine_t *model) machine_at_common_init(model); device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); device_add(&scat_sx_device); @@ -290,7 +291,7 @@ machine_at_award286_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/award286/award.bin", + ret = bios_load_linear("roms/machines/award286/award.bin", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -298,6 +299,9 @@ machine_at_award286_init(const machine_t *model) machine_at_scat_init(model, 0); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + return ret; } @@ -306,7 +310,7 @@ machine_at_gdc212m_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/gdc212m/gdc212m_72h.bin", + ret = bios_load_linear("roms/machines/gdc212m/gdc212m_72h.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -314,6 +318,11 @@ machine_at_gdc212m_init(const machine_t *model) machine_at_scat_init(model, 0); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&ide_isa_device); + return ret; } @@ -322,7 +331,7 @@ machine_at_gw286ct_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/gw286ct/2ctc001.bin", + ret = bios_load_linear("roms/machines/gw286ct/2ctc001.bin", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -330,7 +339,12 @@ machine_at_gw286ct_init(const machine_t *model) device_add(&f82c710_device); - machine_at_scat_init(model, 1); + machine_at_common_init(model); + device_add(&keyboard_at_device); + + device_add(&scat_4_device); + + device_add(&ide_isa_device); return ret; } @@ -341,7 +355,7 @@ machine_at_super286tr_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/super286tr/hyundai_award286.bin", + ret = bios_load_linear("roms/machines/super286tr/hyundai_award286.bin", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -349,6 +363,9 @@ machine_at_super286tr_init(const machine_t *model) machine_at_scat_init(model, 0); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + return ret; } @@ -358,7 +375,7 @@ machine_at_spc4200p_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/spc4200p/u8.01", + ret = bios_load_linear("roms/machines/spc4200p/u8.01", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -366,6 +383,9 @@ machine_at_spc4200p_init(const machine_t *model) machine_at_scat_init(model, 0); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + return ret; } @@ -375,8 +395,8 @@ machine_at_spc4216p_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/spc4216p/7101.u8", - L"roms/machines/spc4216p/ac64.u10", + ret = bios_load_interleaved("roms/machines/spc4216p/7101.U8", + "roms/machines/spc4216p/AC64.U10", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -384,6 +404,32 @@ machine_at_spc4216p_init(const machine_t *model) machine_at_scat_init(model, 1); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + +int +machine_at_spc4620p_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/spc4620p/31005h.u8", + "roms/machines/spc4620p/31005h.u10", + 0x000f0000, 131072, 0x8000); + + if (bios_only || !ret) + return ret; + + if (gfxcard == VID_INTERNAL) + device_add(&ati28800k_spc4620p_device); + + machine_at_scat_init(model, 1); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + return ret; } @@ -393,7 +439,7 @@ machine_at_kmxc02_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/kmxc02/3ctm005.bin", + ret = bios_load_linear("roms/machines/kmxc02/3ctm005.bin", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -404,12 +450,13 @@ machine_at_kmxc02_init(const machine_t *model) return ret; } + int machine_at_deskmaster286_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/deskmaster286/SAMSUNG-DESKMASTER-28612-ROM.BIN", + ret = bios_load_linear("roms/machines/deskmaster286/SAMSUNG-DESKMASTER-28612-ROM.BIN", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -417,46 +464,93 @@ machine_at_deskmaster286_init(const machine_t *model) machine_at_scat_init(model, 0); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + return ret; } + +int +machine_at_shuttle386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/shuttle386sx/386-Shuttle386SX-Even.BIN", + "roms/machines/shuttle386sx/386-Shuttle386SX-Odd.BIN", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&intel_82335_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_adi386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/adi386sx/3iip001l.bin", + "roms/machines/adi386sx/3iip001h.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&intel_82335_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + int machine_at_wd76c10_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/megapc/41651-bios lo.u18", - L"roms/machines/megapc/211253-bios hi.u19", + ret = bios_load_interleaved("roms/machines/megapc/41651-bios lo.u18", + "roms/machines/megapc/211253-bios hi.u19", 0x000f0000, 65536, 0x08000); if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); + machine_at_common_init(model); + + if (gfxcard == VID_INTERNAL) + device_add(¶dise_wd90c11_megapc_device); device_add(&keyboard_ps2_quadtel_device); device_add(&wd76c10_device); - if (gfxcard == VID_INTERNAL) - device_add(¶dise_wd90c11_megapc_device); - return ret; } -const device_t * -at_commodore_sl386sx_get_device(void) -{ - return &gd5402_onboard_device; -} int -machine_at_commodore_sl386sx_init(const machine_t *model) +machine_at_cmdsl386sx16_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/cbm_sl386sx25/cbm-sl386sx-bios-lo-v1.04-390914-04.bin", - L"roms/machines/cbm_sl386sx25/cbm-sl386sx-bios-hi-v1.04-390915-04.bin", + ret = bios_load_interleaved("roms/machines/cmdsl386sx16/cbm-sl386sx-bios-lo-v1.04-390914-04.bin", + "roms/machines/cmdsl386sx16/cbm-sl386sx-bios-hi-v1.04-390915-04.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -465,11 +559,380 @@ machine_at_commodore_sl386sx_init(const machine_t *model) machine_at_common_ide_init(model); device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); + + device_add(&neat_device); + /* Two serial ports - on the real hardware SL386SX-16, they are on the single UMC UM82C452. */ + device_add_inst(&ns16450_device, 1); + device_add_inst(&ns16450_device, 2); + + return ret; +} + + +static void +machine_at_scamp_common_init(const machine_t *model, int is_ps2) +{ + machine_at_common_ide_init(model); + + if (is_ps2) + device_add(&keyboard_ps2_ami_device); + else + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + device_add(&vlsi_scamp_device); +} + + +const device_t * +at_cmdsl386sx25_get_device(void) +{ + return &gd5402_onboard_device; +} + + +int +machine_at_cmdsl386sx25_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/cmdsl386sx25/f000.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; if (gfxcard == VID_INTERNAL) device_add(&gd5402_onboard_device); + machine_at_scamp_common_init(model, 1); + return ret; } + + +int +machine_at_dataexpert386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/dataexpert386sx/5e9f20e5ef967717086346.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scamp_common_init(model, 0); + + return ret; +} + + +const device_t * +at_spc6033p_get_device(void) +{ + return &ati28800k_spc6033p_device; +} + + +int +machine_at_spc6033p_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/spc6033p/phoenix.BIN", + 0x000f0000, 65536, 0x10000); + + if (bios_only || !ret) + return ret; + + if (gfxcard == VID_INTERNAL) + device_add(&ati28800k_spc6033p_device); + + machine_at_scamp_common_init(model, 1); + + return ret; +} + + +int +machine_at_awardsx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/awardsx/Unknown 386SX OPTi291 - Award (original).BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); + + device_add(&opti291_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_arb1374_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/arb1374/1374s.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&ali1217_device); + device_add(&w83787f_ide_en_device); + device_add(&keyboard_ps2_ami_device); + + return ret; +} + + +int +machine_at_sbc350a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sbc350a/350a.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&ali1217_device); + device_add(&fdc37c665_ide_device); + device_add(&keyboard_at_device); + + return ret; +} + + +int +machine_at_flytech386_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/flytech386/FLYTECH.BIO", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&ali1217_device); + device_add(&w83787f_ide_en_device); + + if (gfxcard == VID_INTERNAL) + device_add(&tvga8900d_device); + + device_add(&keyboard_ps2_device); + + return ret; +} + + +const device_t * +at_flytech386_get_device(void) +{ + return &tvga8900d_device; +} + + +int +machine_at_mr1217_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mr1217/mrbios.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&ali1217_device); + device_add(&fdc_at_device); + device_add(&ide_isa_device); + device_add(&keyboard_ps2_device); + + return ret; +} + + +int +machine_at_pja511m_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pja511m/2006915102435734.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add_inst(&fdc37c669_device, 1); + device_add_inst(&fdc37c669_device, 2); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ali6117d_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_prox1332_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/prox1332/D30B3AC1.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&fdc37c669_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ali6117d_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +/* + * Current bugs: + * - ctrl-alt-del produces an 8042 error + */ +int +machine_at_pc8_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/pc8/ncr_35117_u127_vers.4-2.bin", + "roms/machines/pc8/ncr_35116_u113_vers.4-2.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&keyboard_at_ncr_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +/* + * Current bugs: + * - ctrl-alt-del produces an 8042 error + */ +int +machine_at_3302_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/3302/f000-flex_drive_test.bin", + 0x000f0000, 65536, 0); + + if (ret) { + bios_load_aux_linear("roms/machines/3302/f800-setup_ncr3.5-013190.bin", + 0x000f8000, 32768, 0); + } + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + device_add(&neat_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + if (gfxcard == VID_INTERNAL) + device_add(¶dise_pvga1a_ncr3302_device); + + device_add(&keyboard_at_ncr_device); + + return ret; +} + + +/* + * Current bugs: + * - soft-reboot after saving CMOS settings/pressing ctrl-alt-del produces an 8042 error + */ +int +machine_at_pc916sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/pc916sx/ncr_386sx_u46-17_7.3.bin", + "roms/machines/pc916sx/ncr_386sx_u12-19_7.3.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&keyboard_at_ncr_device); + mem_remap_top(384); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_OLIVETTI) +int +machine_at_m290_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m290/m290_pep3_1.25.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 4); + device_add(&keyboard_at_olivetti_device); + device_add(&port_6x_olivetti_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&olivetti_eva_device); + + return ret; +} +#endif diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 21cb0971c..7baa85ed3 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -32,23 +32,30 @@ #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> +#include <86box/dma.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/gameport.h> +#include <86box/pic.h> +#include <86box/pit.h> #include <86box/rom.h> #include <86box/sio.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/video.h> -#include <86box/intel_flash.h> -#include <86box/sst_flash.h> +#include <86box/flash.h> #include <86box/scsi_ncr53c8xx.h> +#include <86box/hwm.h> #include <86box/machine.h> + int machine_at_acc386_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/acc386/acc386.BIN", + ret = bios_load_linear("roms/machines/acc386/acc386.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -57,17 +64,20 @@ machine_at_acc386_init(const machine_t *model) machine_at_common_init(model); device_add(&acc2168_device); device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); return ret; } + int machine_at_asus386_init(const machine_t *model) { int ret; -ret = bios_load_linear(L"roms/machines/asus386/ASUS_ISA-386C_BIOS.bin", + ret = bios_load_linear("roms/machines/asus386/ASUS_ISA-386C_BIOS.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -76,18 +86,113 @@ ret = bios_load_linear(L"roms/machines/asus386/ASUS_ISA-386C_BIOS.bin", machine_at_common_init(model); device_add(&rabbit_device); device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); return ret; } + +static void +machine_at_sis401_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + device_add(&sis_85c401_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); +} + + +int +machine_at_sis401_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sis401/SIS401-2.AMI", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis401_common_init(model); + + return ret; +} + + +int +machine_at_isa486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/isa486/ISA-486.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis401_common_init(model); + + return ret; +} + + +int +machine_at_av4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/av4/amibios_486dx_isa_bios_aa4025963.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + device_add(&sis_85c460_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 mouse +{ + int ret; + + ret = bios_load_linear("roms/machines/valuepoint433/$IMAGEP.FLH", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + device_add(&sis_85c461_device); + if (gfxcard == VID_INTERNAL) + device_add(&et4000w32_onboard_device); + + device_add(&keyboard_ps2_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + int machine_at_ecs386_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ecs386/AMI BIOS for ECS-386_32 motherboard - L chip.bin", - L"roms/machines/ecs386/AMI BIOS for ECS-386_32 motherboard - H chip.bin", + ret = bios_load_interleaved("roms/machines/ecs386/AMI BIOS for ECS-386_32 motherboard - L chip.bin", + "roms/machines/ecs386/AMI BIOS for ECS-386_32 motherboard - H chip.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -95,18 +200,114 @@ machine_at_ecs386_init(const machine_t *model) machine_at_common_init(model); device_add(&cs8230_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_spc6000a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/spc6000a/3c80.u27", + "roms/machines/spc6000a/9f80.u26", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 1); + device_add(&cs8230_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&keyboard_at_samsung_device); + + return ret; +} + + +int +machine_at_rycleopardlx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/rycleopardlx/486-RYC-Leopard-LX.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti283_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); return ret; } + +int +machine_at_486vchd_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/486vchd/486-4386-VC-HD.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&via_vt82c49x_device); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_cs4031_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/cs4031/CHIPS_1.AMI", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&cs4031_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + int machine_at_pb410a_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/pb410a/pb410a.080337.4abf.u25.bin", + ret = bios_load_linear("roms/machines/pb410a/pb410a.080337.4abf.u25.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -119,51 +320,152 @@ machine_at_pb410a_init(const machine_t *model) device_add(&acc3221_device); device_add(&acc2168_device); + device_add(&phoenix_486_jumper_device); + if (gfxcard == VID_INTERNAL) device_add(&ht216_32_pb410a_device); return ret; } + +int +machine_at_vect486vl_init(const machine_t *model) // has HDC problems +{ + int ret; + + ret = bios_load_linear("roms/machines/vect486vl/aa0500.ami", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&vl82c480_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5428_onboard_device); + + device_add(&keyboard_ps2_ami_device); + device_add(&fdc37c651_ide_device); + + return ret; +} + +int +machine_at_d824_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/d824/fts-biosupdated824noflashbiosepromv320-320334-160.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&vl82c480_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5428_onboard_device); + + device_add(&keyboard_ps2_device); + device_add(&fdc37c651_device); + + return ret; +} + int machine_at_acera1g_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/acera1g/4alo001.bin", + ret = bios_load_linear("roms/machines/acera1g/4alo001.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); + machine_at_common_init(model); + device_add(&ali1429g_device); if (gfxcard == VID_INTERNAL) - device_add(&gd5428_a1g_device); + device_add(&gd5428_onboard_device); - device_add(&ali1429_device); device_add(&keyboard_ps2_acer_pci_device); - device_add(&fdc_at_device); - device_add(&ide_isa_device); + device_add(&ide_isa_2ch_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); return ret; } -const device_t * -at_acera1g_get_device(void) +int +machine_at_acerv10_init(const machine_t *model) { - return &gd5428_a1g_device; + int ret; + + ret = bios_load_linear("roms/machines/acerv10/ALL.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&sis_85c461_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_isa_2ch_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; } +int +machine_at_decpclpv_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/decpclpv/bios.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&sis_85c461_device); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_86c805_onboard_vlb_device); + + /* TODO: Phoenix MultiKey KBC */ + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_isa_2ch_device); + device_add(&fdc37c663_ide_device); + + return ret; +} + static void -machine_at_ali1429_common_init(const machine_t *model) +machine_at_ali1429_common_init(const machine_t *model, int is_green) { machine_at_common_ide_init(model); - device_add(&ali1429_device); + if (is_green) + device_add(&ali1429g_device); + else + device_add(&ali1429_device); device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); } @@ -173,13 +475,13 @@ machine_at_ali1429_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ami486/ami486.bin", + ret = bios_load_linear("roms/machines/ali1429/ami486.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; - machine_at_ali1429_common_init(model); + machine_at_ali1429_common_init(model, 0); return ret; } @@ -190,13 +492,13 @@ machine_at_winbios1429_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/win486/ali1429g.amw", + ret = bios_load_linear("roms/machines/win486/ali1429g.amw", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; - machine_at_ali1429_common_init(model); + machine_at_ali1429_common_init(model, 1); return ret; } @@ -207,7 +509,7 @@ machine_at_opti495_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/award495/opt495s.awa", + ret = bios_load_linear("roms/machines/award495/opt495s.awa", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -218,6 +520,8 @@ machine_at_opti495_init(const machine_t *model) device_add(&opti495_device); device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); return ret; @@ -232,6 +536,8 @@ machine_at_opti495_ami_common_init(const machine_t *model) device_add(&opti495_device); device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); } @@ -241,7 +547,7 @@ machine_at_opti495_ami_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ami495/opt495sx.ami", + ret = bios_load_linear("roms/machines/ami495/opt495sx.ami", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -258,7 +564,7 @@ machine_at_opti495_mr_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/mr495/opt495sx.mr", + ret = bios_load_linear("roms/machines/mr495/opt495sx.mr", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -270,11 +576,130 @@ machine_at_opti495_mr_init(const machine_t *model) } +static void +machine_at_403tg_common_init(const machine_t *model, int nvr_hack) +{ + if (nvr_hack) { + machine_at_common_init_ex(model, 2); + device_add(&ami_1994_nvr_device); + } else + machine_at_common_init(model); + + device_add(&opti895_device); + + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); +} + + +int +machine_at_403tg_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/403tg/403TG.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_403tg_common_init(model, 0); + + return ret; +} + + +int +machine_at_403tg_d_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/403tg_d/J403TGRevD.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_403tg_common_init(model, 1); + + return ret; +} + + +int +machine_at_403tg_d_mr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/403tg_d/MRBiosOPT895.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_403tg_common_init(model, 0); + + return ret; +} + + +int +machine_at_pc330_6573_init(const machine_t *model) /* doesn't like every CPU other than the iDX4 and the Intel OverDrive, hangs without a PS/2 mouse */ +{ + int ret; + + ret = bios_load_linear("roms/machines/pc330_6573/$IMAGES.USF", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&opti802g_device); + device_add(&opti822_device); + device_add(&keyboard_ps2_device); + device_add(&fdc37c665_device); + device_add(&ide_opti611_vlb_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_mvi486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mvi486/MVI627.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti895_device); + device_add(&keyboard_at_device); + device_add(&pc87311_ide_device); + + return ret; +} + static void machine_at_sis_85c471_common_init(const machine_t *model) { - machine_at_common_ide_init(model); - device_add(&fdc_at_device); + machine_at_common_init(model); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); device_add(&sis_85c471_device); } @@ -285,47 +710,52 @@ machine_at_ami471_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ami471/SIS471BE.AMI", + ret = bios_load_linear("roms/machines/ami471/SIS471BE.AMI", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_sis_85c471_common_init(model); + device_add(&ide_vlb_device); device_add(&keyboard_at_ami_device); return ret; } + int machine_at_vli486sv2g_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/vli486sv2g/0402.001", + ret = bios_load_linear("roms/machines/vli486sv2g/0402.001", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_sis_85c471_common_init(model); - device_add(&keyboard_at_device); + device_add(&ide_vlb_2ch_device); + device_add(&keyboard_ps2_ami_device); return ret; } + int machine_at_dtk486_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/dtk486/4siw005.bin", + ret = bios_load_linear("roms/machines/dtk486/4siw005.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_sis_85c471_common_init(model); + device_add(&ide_vlb_device); device_add(&keyboard_at_device); return ret; @@ -337,37 +767,80 @@ machine_at_px471_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/px471/SIS471A1.PHO", + ret = bios_load_linear("roms/machines/px471/SIS471A1.PHO", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_sis_85c471_common_init(model); + device_add(&ide_vlb_device); device_add(&keyboard_at_device); return ret; } -#if defined(DEV_BRANCH) && defined(USE_WIN471) int machine_at_win471_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/win471/486-SiS_AC0360136.BIN", + ret = bios_load_linear("roms/machines/win471/486-SiS_AC0360136.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; machine_at_sis_85c471_common_init(model); + device_add(&ide_vlb_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_vi15g_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/vi15g/vi15gr23.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&ide_vlb_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_greenb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/greenb/4gpv31-ami-1993-8273517.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&contaq_82c597_device); + device_add(&keyboard_at_ami_device); return ret; } -#endif static void @@ -377,16 +850,11 @@ machine_at_sis_85c496_common_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x05, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - - device_add(&sis_85c496_device); } @@ -395,15 +863,19 @@ machine_at_r418_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/r418/r418i.bin", + ret = bios_load_linear("roms/machines/r418/r418i.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_device); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&fdc37c665_device); @@ -413,21 +885,51 @@ machine_at_r418_init(const machine_t *model) } +int +machine_at_m4li_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m4li/M4LI.04S", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_device); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_pci_device); + + return ret; +} + + int machine_at_ls486e_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ls486e/LS486E RevC.BIN", + ret = bios_load_linear("roms/machines/ls486e/LS486E RevC.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; machine_at_common_init_ex(model, 2); - device_add(&ls486e_nvr_device); machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_ls486e_device); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&fdc37c665_device); @@ -442,20 +944,83 @@ machine_at_4dps_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/4dps/4DPS172G.BIN", + ret = bios_load_linear("roms/machines/4dps/4DPS172G.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_device); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&w83787f_device); + device_add(&keyboard_ps2_ami_device); + + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_486sp3c_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/486sp3c/SI4I0306.AWD", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_device); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_ami_pci_device); + + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_4saw2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/4saw2/4saw0911.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_device); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&w83787f_device); device_add(&keyboard_ps2_pci_device); + device_add(&intel_flash_bxt_device); + return ret; } @@ -465,8 +1030,8 @@ machine_at_alfredo_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined(L"roms/machines/alfredo/1010AQ0_.BIO", - L"roms/machines/alfredo/1010AQ0_.BI1", 0x1c000, 128); + ret = bios_load_linear_combined("roms/machines/alfredo/1010AQ0_.BIO", + "roms/machines/alfredo/1010AQ0_.BI1", 0x1c000, 128); if (bios_only || !ret) return ret; @@ -476,12 +1041,12 @@ machine_at_alfredo_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_pci_device); device_add(&sio_device); device_add(&fdc37c663_device); device_add(&intel_flash_bxt_ami_device); @@ -493,31 +1058,155 @@ machine_at_alfredo_init(const machine_t *model) int -machine_at_486sp3g_init(const machine_t *model) +machine_at_ninja_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/486sp3g/PCI-I-486SP3G_0306.001 (Beta).bin", + ret = bios_load_linear_combined("roms/machines/ninja/1008AY0_.BIO", + "roms/machines/ninja/1008AY0_.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x05, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 2, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 1, 2, 1); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&intel_flash_bxt_ami_device); + + device_add(&i420ex_device); + device_add(&i82091aa_device); + + return ret; +} + + +int +machine_at_486sp3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/486sp3/awsi2737.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; machine_at_common_init(model); - device_add(&ide_pci_2ch_device); + device_add(&ide_isa_device); pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SCSI, 1, 2, 3, 4); /* 01 = SCSI */ pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ - pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */ - device_add(&sio_device); /* Site says it has a ZB, but the BIOS is designed for an IB. */ - device_add(&pc87332_device); + device_add(&sio_device); + device_add(&fdc37c663_ide_device); + device_add(&sst_flash_29ee010_device); + + device_add(&i420tx_device); + device_add(&ncr53c810_onboard_pci_device); + + return ret; +} + + +int +machine_at_pci400cb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pci400cb/032295.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&ami_1994_nvr_device); + device_add(&ide_isa_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 3, 2, 1); /* 0F = Slot 1 */ + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 0E = Slot 2 */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 0D = Slot 3 */ + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 0C = Slot 4 */ + device_add(&keyboard_ps2_ami_pci_device); /* Assume AMI Megakey 1993 standalone ('P') + because of the Tekram machine below. */ + + device_add(&ims8848_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_g486ip_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/g486ip/G486IP.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&ami_1992_nvr_device); + device_add(&ide_isa_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 03 = Slot 1 */ + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 05 = Slot 3 */ + device_add(&keyboard_ps2_ami_pci_device); /* AMI Megakey 1993 stanalone ('P') */ + + device_add(&ims8848_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_486sp3g_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/486sp3g/PCI-I-486SP3G_0306.001 (Beta).bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_isa_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SCSI, 1, 2, 3, 4); /* 01 = SCSI */ + pci_register_slot(0x06, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 06 = Slot 1 */ + pci_register_slot(0x05, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 05 = Slot 2 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 04 = Slot 3 */ + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */ + device_add(&sio_zb_device); + device_add(&pc87332_398_ide_device); device_add(&sst_flash_29ee010_device); device_add(&i420zx_device); @@ -532,7 +1221,7 @@ machine_at_486ap4_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/486ap4/0205.002", + ret = bios_load_linear("roms/machines/486ap4/0205.002", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -548,9 +1237,547 @@ machine_at_486ap4_init(const machine_t *model) pci_register_slot(0x0b, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 0b = Slot 3 */ pci_register_slot(0x0c, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 0c = Slot 4 */ device_add(&keyboard_ps2_ami_pci_device); /* Uses the AMIKEY KBC */ - device_add(&fdc_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); device_add(&i420ex_device); return ret; } + + +int +machine_at_g486vpa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/g486vpa/3.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&via_vt82c49x_pci_ide_device); + device_add(&via_vt82c505_device); + device_add(&pc87332_398_ide_sec_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_486vipio2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/486vipio2/1175G701.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&via_vt82c49x_pci_ide_device); + device_add(&via_vt82c505_device); + device_add(&w83787f_ide_sec_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_abpb4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/abpb4/486-AB-PB4.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CAN_SWITCH_TYPE); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&ali1489_device); + device_add(&w83787f_device); + device_add(&keyboard_at_device); + // device_add(&intel_flash_bxt_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_win486pci_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/win486pci/v1hj3.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&ali1489_device); + device_add(&prime3b_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_ms4145_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms4145/AG56S.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&ali1489_device); + device_add(&w83787f_device); + device_add(&keyboard_at_ami_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_sbc490_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sbc490/07159589.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_VIDEO, 4, 1, 2, 3); + + device_add(&ali1489_device); + device_add(&fdc37c665_device); + + if (gfxcard == VID_INTERNAL) + device_add(&tgui9440_onboard_pci_device); + + device_add(&keyboard_ps2_ami_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + +int +machine_at_tf486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/tf486/tf486v10.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&ali1489_device); + device_add(&w83977ef_device); + device_add(&keyboard_ps2_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_itoxstar_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/itoxstar/STARA.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x0B, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&w83977f_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&stpc_client_device); + device_add(&sst_flash_29ee020_device); + device_add(&w83781d_device); /* fans: Chassis, CPU, unused; temperatures: Chassis, CPU, unused */ + hwm_values.fans[2] = 0; /* unused */ + hwm_values.temperatures[2] = 0; /* unused */ + hwm_values.voltages[0] = 0; /* Vcore unused */ + + return ret; +} + + +int +machine_at_arb1423c_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/arb1423c/A1423C.v12", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x0B, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 1, 0, 0, 0); + pci_register_slot(0x1E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x1D, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&w83977f_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&stpc_consumer2_device); + device_add(&winbond_flash_w29c020_device); + + return ret; +} + + +int +machine_at_arb1479_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/arb1479/1479A.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x0B, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 1, 0, 0, 0); + pci_register_slot(0x1E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x1D, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&w83977f_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&stpc_consumer2_device); + device_add(&winbond_flash_w29c020_device); + + return ret; +} + + +int +machine_at_pcm9340_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pcm9340/9340v110.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x0B, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x1D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x1E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 2, 3, 4, 1); + device_add_inst(&w83977f_device, 1); + device_add_inst(&w83977f_device, 2); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&stpc_elite_device); + device_add(&sst_flash_29ee020_device); + + return ret; +} + + +int +machine_at_pcm5330_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pcm5330/5330_13b.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x0B, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&stpc_serial_device); + device_add(&w83977f_370_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&stpc_atlas_device); + device_add(&sst_flash_29ee020_device); + + return ret; +} + + +int +machine_at_ecs486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ecs486/8810AIO.32J", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886f_device); + device_add(&ide_cmd640_pci_legacy_only_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_hot433_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hot433/433AUS33.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8669f_device); + // device_add(&intel_flash_bxt_device); + device_add(&sst_flash_29ee010_device); + // device_add(&keyboard_at_ami_device); + device_add(&keyboard_ps2_ami_device); + + return ret; +} + + +int +machine_at_atc1415_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/atc1415/1415V330.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_actionpc2600_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/actionpc2600/action2600.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_m919_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m919/9190914s.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8669f_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_spc7700plw_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/spc7700plw/77LW13FH.P24", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + device_add(&keyboard_at_ami_device); + + return ret; +} diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index 51f8e56b4..f9afdd1ef 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -45,6 +45,7 @@ #include <86box/timer.h> #include <86box/io.h> #include <86box/mem.h> +#include <86box/fdc_ext.h> #include <86box/lpt.h> #include <86box/rom.h> #include <86box/serial.h> @@ -64,22 +65,22 @@ cbm_io_write(uint16_t port, uint8_t val, void *p) switch (val & 3) { case 1: - lpt1_init(0x3bc); + lpt1_init(LPT_MDA_ADDR); break; case 2: - lpt1_init(0x378); + lpt1_init(LPT1_ADDR); break; case 3: - lpt1_init(0x278); + lpt1_init(LPT2_ADDR); break; } switch (val & 0xc) { case 0x4: - serial_setup(cmd_uart, 0x2f8, 3); + serial_setup(cmd_uart, COM2_ADDR, COM2_IRQ); break; case 0x8: - serial_setup(cmd_uart, 0x3f8, 4); + serial_setup(cmd_uart, COM1_ADDR, COM1_IRQ); break; } } @@ -97,8 +98,8 @@ machine_at_cmdpc_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", - L"roms/machines/cmdpc30/commodore pc 30 iii odd.bin", + ret = bios_load_interleaved("roms/machines/cmdpc30/commodore pc 30 iii even.bin", + "roms/machines/cmdpc30/commodore pc 30 iii odd.bin", 0x000f8000, 32768, 0); if (bios_only || !ret) @@ -108,8 +109,10 @@ machine_at_cmdpc_init(const machine_t *model) mem_remap_top(384); + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - cmd_uart = device_add(&i8250_device); + + cmd_uart = device_add(&ns8250_device); cbm_io_init(); diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index aed26a6f6..686032493 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -70,24 +70,24 @@ static uint32_t normcols[256][2]; * * Bit 3: Disable built-in video (for add-on card) * Bit 2: Thin font - * Bits 0,1: Font set (not currently implemented) - */ + * Bits 0,1: Font set (not currently implemented) + */ static int8_t cpq_st_display_internal = -1; -static void +static void compaq_plasma_display_set(uint8_t internal) { cpq_st_display_internal = internal; } -static uint8_t +static uint8_t compaq_plasma_display_get(void) { return cpq_st_display_internal; } -typedef struct compaq_plasma_t +typedef struct compaq_plasma_t { mem_mapping_t plasma_mapping; cga_t cga; @@ -97,10 +97,10 @@ typedef struct compaq_plasma_t int linepos, displine; uint8_t *vram; uint64_t dispontime, dispofftime; - int dispon; + int dispon, fullchange; } compaq_plasma_t; -static uint8_t cga_crtcmask[32] = +static uint8_t cga_crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -112,7 +112,7 @@ static mem_mapping_t ram_mapping; static void compaq_plasma_recalcattrs(compaq_plasma_t *self); -static void +static void compaq_plasma_recalctimings(compaq_plasma_t *self) { double _dispontime, _dispofftime, disptime; @@ -150,7 +150,7 @@ compaq_plasma_read(uint32_t addr, void *priv) } /* Draw a row of text in 80-column mode */ -static void +static void compaq_plasma_text80(compaq_plasma_t *self) { uint32_t cols[2]; @@ -184,9 +184,9 @@ compaq_plasma_text80(compaq_plasma_t *self) (attr & 0x80) && !drawcursor); if (self->cga.cgamode & 0x20) { /* Blink */ - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; - if (blink) + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; } else { cols[1] = normcols[attr][1]; @@ -238,9 +238,9 @@ compaq_plasma_text40(compaq_plasma_t *self) (attr & 0x80) && !drawcursor); if (self->cga.cgamode & 0x20) { /* Blink */ - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; - if (blink) + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; } else { cols[1] = normcols[attr][1]; @@ -248,12 +248,12 @@ compaq_plasma_text40(compaq_plasma_t *self) } if (drawcursor) { for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[self->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[self->displine])[(x << 4) + c*2] = ((uint32_t *)buffer32->line[self->displine])[(x << 4) + c*2 + 1] = cols[(fontdatm[chr][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); } } else { for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[self->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[self->displine])[(x << 4) + c*2] = ((uint32_t *)buffer32->line[self->displine])[(x << 4) + c*2+1] = cols[(fontdatm[chr][sc] & (1 << (c ^ 7))) ? 1 : 0]; } } @@ -263,7 +263,7 @@ compaq_plasma_text40(compaq_plasma_t *self) /* Draw a line in CGA 640x200 or Compaq Plasma 640x400 mode */ -static void +static void compaq_plasma_cgaline6(compaq_plasma_t *self) { int x, c; @@ -300,7 +300,7 @@ compaq_plasma_cgaline6(compaq_plasma_t *self) /* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to * dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */ -static void +static void compaq_plasma_cgaline4(compaq_plasma_t *self) { int x, c; @@ -309,7 +309,7 @@ compaq_plasma_cgaline4(compaq_plasma_t *self) uint16_t addr; uint16_t ma = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x7fff; - + /* 320*200 */ addr = ((self->displine >> 1) & 1) * 0x2000 + (self->displine >> 2) * 80 + @@ -321,7 +321,7 @@ compaq_plasma_cgaline4(compaq_plasma_t *self) for (c = 0; c < 4; c++) { pattern = (dat & 0xC0) >> 6; - if (!(self->cga.cgamode & 8)) + if (!(self->cga.cgamode & 8)) pattern = 0; switch (pattern & 3) { @@ -366,21 +366,21 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) self->cga.crtc[self->cga.crtcreg] = val & cga_crtcmask[self->cga.crtcreg]; /* Register 0x12 controls the attribute mappings for the - * plasma screen. */ + * plasma screen. */ if (self->cga.crtcreg == 0x12) { - self->attrmap = val; + self->attrmap = val; compaq_plasma_recalcattrs(self); break; } - + if (old != val) { if (self->cga.crtcreg < 0xe || self->cga.crtcreg > 0x10) { - fullchange = changeframecount; + self->fullchange = changeframecount; compaq_plasma_recalctimings(self); } } break; - + case 0x3d8: self->cga.cgamode = val; break; @@ -395,7 +395,7 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) else compaq_plasma_display_set(0); break; - + case 0x23c6: self->port_23c6 = val; if (val & 8) /* Disable internal CGA */ @@ -430,7 +430,7 @@ compaq_plasma_in(uint16_t addr, void *priv) case 0x3da: ret = self->cga.cgastat; break; - + case 0x13c6: if (compaq_plasma_display_get()) ret = 8; @@ -450,7 +450,7 @@ static void compaq_plasma_poll(void *p) { compaq_plasma_t *self = (compaq_plasma_t *)p; - + /* Switch between internal plasma and external CRT display. */ if (cpq_st_display_internal != -1 && cpq_st_display_internal != self->internal_monitor) { self->internal_monitor = cpq_st_display_internal; @@ -460,8 +460,8 @@ compaq_plasma_poll(void *p) if (!self->internal_monitor && !(self->port_23c6 & 1)) { cga_poll(&self->cga); return; - } - + } + if (!self->linepos) { timer_advance_u64(&self->cga.timer, self->dispofftime); self->cga.cgastat |= 1; @@ -474,7 +474,7 @@ compaq_plasma_poll(void *p) if (self->cga.cgamode & 0x02) { if (self->cga.cgamode & 0x10) compaq_plasma_cgaline6(self); - else + else compaq_plasma_cgaline4(self); } else if (self->cga.cgamode & 0x01) /* High-res text */ @@ -505,16 +505,16 @@ compaq_plasma_poll(void *p) if ((640 != xsize) || (400 != ysize) || video_force_resize_get()) { xsize = 640; ysize = 400; - if (xsize < 64) + if (xsize < 64) xsize = 656; - if (ysize < 32) + if (ysize < 32) ysize = 200; set_screen_size(xsize, ysize); if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + video_blit_memtoscreen(0, 0, xsize, ysize); frames++; /* Fixed 640x400 resolution */ @@ -524,26 +524,26 @@ compaq_plasma_poll(void *p) if (self->cga.cgamode & 0x02) { if (self->cga.cgamode & 0x10) video_bpp = 1; - else + else video_bpp = 2; - } else + } else video_bpp = 0; self->cga.cgablink++; } } } -static void +static void compaq_plasma_recalcattrs(compaq_plasma_t *self) { int n; /* val behaves as follows: - * Bit 0: Attributes 01-06, 08-0E are inverse video - * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are inverse video + * are inverse video * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF * are bold */ @@ -554,15 +554,15 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) /* Initialise the attribute mapping. Start by defaulting everything * to black on amber, and with bold set by bit 3 */ for (n = 0; n < 256; n++) { - blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][0] = normcols[n][0] = amber; blinkcols[n][1] = normcols[n][1] = black; } - /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the - * passed value. Exclude x0 and x8, which are always black on + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always black on * amber. */ for (n = 0x11; n <= 0xFF; n++) { - if ((n & 7) == 0) + if ((n & 7) == 0) continue; if (self->attrmap & 4) { /* Inverse */ blinkcols[n][0] = normcols[n][0] = amber; @@ -572,10 +572,10 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) blinkcols[n][1] = normcols[n][1] = amber; } } - /* Set up the 01-0E range, controlled by bits 0 and 1 of the + /* Set up the 01-0E range, controlled by bits 0 and 1 of the * passed value. When blinking is enabled this also affects 81-8E. */ for (n = 0x01; n <= 0x0E; n++) { - if (n == 7) + if (n == 7) continue; if (self->attrmap & 1) { blinkcols[n][0] = normcols[n][0] = amber; @@ -589,7 +589,7 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) blinkcols[n+128][1] = amber; } } - /* Colours 07 and 0F are always amber on black. If blinking is + /* Colours 07 and 0F are always amber on black. If blinking is * enabled so are 87 and 8F. */ for (n = 0x07; n <= 0x0F; n += 8) { blinkcols[n][0] = normcols[n][0] = black; @@ -616,7 +616,7 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) } static void * -compaq_plasma_init(const device_t *info) +compaq_plasma_init(const device_t *info) { int display_type; compaq_plasma_t *self = malloc(sizeof(compaq_plasma_t)); @@ -648,7 +648,7 @@ compaq_plasma_init(const device_t *info) self->cga.rgb_type = device_get_config_int("rgb_type"); cga_palette = (self->cga.rgb_type << 1); cgapal_rebuild(); - + return self; } @@ -658,6 +658,7 @@ compaq_plasma_close(void *p) compaq_plasma_t *self = (compaq_plasma_t *)p; free(self->vram); + free(self); } @@ -669,76 +670,67 @@ compaq_plasma_speed_changed(void *p) compaq_plasma_recalctimings(self); } -const device_config_t compaq_plasma_config[] = -{ - { - "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, - { - { - "RGB", CGA_RGB - }, - { - "Composite", CGA_COMPOSITE - }, - { - "" - } - } - }, - { - "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, - { - { - "Old", COMPOSITE_OLD - }, - { - "New", COMPOSITE_NEW - }, - { - "" - } - } - }, - { - "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, - { - { - "Color", 0 - }, - { - "Green Monochrome", 1 - }, - { - "Amber Monochrome", 2 - }, - { - "Gray Monochrome", 3 - }, - { - "Color (no brown)", 4 - }, - { - "" - } - } - }, - { - "", "", -1 +const device_config_t compaq_plasma_config[] = { + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = CGA_RGB, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = CGA_RGB }, + { .description = "Composite", .value = CGA_COMPOSITE }, + { .description = "" } } + }, + { + .name = "composite_type", + .description = "Composite type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = COMPOSITE_OLD, + .file_filter = "", + .spinner = { 0 }, + { + { .description = "Old", .value = COMPOSITE_OLD }, + { .description = "New", .value = COMPOSITE_NEW }, + { .description = "" } + } + }, + { + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "Color (no brown)", .value = 4 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; - -static const device_t compaq_plasma_device = -{ - "Compaq Plasma", - 0, 0, - compaq_plasma_init, - compaq_plasma_close, - NULL, - NULL, - compaq_plasma_speed_changed, - NULL, - compaq_plasma_config +const device_t compaq_plasma_device = { + .name = "Compaq Plasma", + .internal_name = "compaq_plasma", + .flags = 0, + .local = 0, + .init = compaq_plasma_init, + .close = compaq_plasma_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = compaq_plasma_speed_changed, + .force_redraw = NULL, + .config = compaq_plasma_config }; static uint8_t @@ -800,21 +792,13 @@ write_raml(uint32_t addr, uint32_t val, void *priv) mem_write_raml_page(addr, val, &pages[addr >> 12]); } -const device_t * -at_cpqiii_get_device(void) -{ - return &compaq_plasma_device; -} - static void machine_at_compaq_init(const machine_t *model, int type) { - machine_at_init(model); - if (type != COMPAQ_DESKPRO386) mem_remap_top(384); - - if (fdc_type == FDC_INTERNAL) + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); mem_mapping_add(&ram_mapping, 0xfa0000, 0x60000, @@ -822,6 +806,8 @@ machine_at_compaq_init(const machine_t *model, int type) write_ram, write_ramw, write_raml, 0xa0000+ram, MEM_MAPPING_INTERNAL, NULL); + video_reset(gfxcard); + switch(type) { case COMPAQ_PORTABLEII: break; @@ -843,6 +829,8 @@ machine_at_compaq_init(const machine_t *model, int type) device_add(&ide_isa_device); break; } + + machine_at_init(model); } @@ -851,8 +839,8 @@ machine_at_portableii_init(const machine_t *model) { int ret; - ret = bios_load_interleavedr(L"roms/machines/portableii/109740-001.rom", - L"roms/machines/portableii/109739-001.rom", + ret = bios_load_interleavedr("roms/machines/portableii/109740-001.rom", + "roms/machines/portableii/109739-001.rom", 0x000f8000, 65536, 0); if (bios_only || !ret) @@ -869,8 +857,8 @@ machine_at_portableiii_init(const machine_t *model) { int ret; - ret = bios_load_interleavedr(L"roms/machines/portableiii/Compaq Portable III - BIOS - 106779-002 - Even.bin", - L"roms/machines/portableiii/Compaq Portable III - BIOS - 106778-002 - Odd.bin", + ret = bios_load_interleavedr("roms/machines/portableiii/Compaq Portable III - BIOS - 106779-002 - Even.bin", + "roms/machines/portableiii/Compaq Portable III - BIOS - 106778-002 - Odd.bin", 0x000f8000, 65536, 0); if (bios_only || !ret) @@ -887,8 +875,8 @@ machine_at_portableiii386_init(const machine_t *model) { int ret; - ret = bios_load_interleavedr(L"roms/machines/portableiii/Compaq Portable III - BIOS - 106779-002 - Even.bin", - L"roms/machines/portableiii/Compaq Portable III - BIOS - 106778-002 - Odd.bin", + ret = bios_load_interleavedr("roms/machines/portableiii/Compaq Portable III - BIOS - 106779-002 - Even.bin", + "roms/machines/portableiii/Compaq Portable III - BIOS - 106778-002 - Odd.bin", 0x000f8000, 65536, 0); if (bios_only || !ret) @@ -898,3 +886,21 @@ machine_at_portableiii386_init(const machine_t *model) return ret; } + +#if defined(DEV_BRANCH) && defined(USE_DESKPRO386) +int +machine_at_deskpro386_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linearr("roms/machines/deskpro386/1986-09-04-HI.json.bin", + 0x000fc000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_DESKPRO386); + + return ret; +} +#endif diff --git a/src/machine/m_at_misc.c b/src/machine/m_at_misc.c new file mode 100644 index 000000000..b41735d74 --- /dev/null +++ b/src/machine/m_at_misc.c @@ -0,0 +1,74 @@ +/* + * 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 Miscellaneous, Fake, Hypervisor machines. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/sio.h> +#include <86box/hwm.h> +#include <86box/spd.h> +#include <86box/video.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/sound.h> + +int +machine_at_vpc2007_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/vpc2007/13500.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + is_vpc = 1; + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i440bx_no_agp_device); + device_add(&piix4e_device); + device_add(&w83977f_370_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); /* real VPC provides invalid SPD data */ + + return ret; +} diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index b9ffbf658..2ada979c0 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -1,522 +1,733 @@ -/* - * 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 Slot 1 machines. - * - * - * - * Authors: Miran Grca, - * - * Copyright 2016-2019 Miran Grca. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> -#include <86box/device.h> -#include <86box/chipset.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/keyboard.h> -#include <86box/intel_flash.h> -#include <86box/sio.h> -#include <86box/sst_flash.h> -#include <86box/hwm.h> -#include <86box/spd.h> -#include <86box/video.h> -#include "cpu.h" -#include <86box/machine.h> -#include <86box/sound.h> - -int -machine_at_p65up5_cpknd_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/p65up5/ndkn0218.awd", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_p65up5_common_init(model, &i440fx_device); - - return ret; -} - - -int -machine_at_kn97_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/kn97/0116I.001", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - device_add(&i440fx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83877f_device); - device_add(&intel_flash_bxt_device); - - hwm_values_t machine_hwm = { - { /* fan speeds (incorrect divisor for some reason) */ - 6000, /* Chassis */ - 6000, /* CPU */ - 6000 /* Power */ - }, { /* temperatures */ - 30 /* MB */ - }, { /* voltages */ - 2800, /* VCORE (2.8V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - hwm_set_values(machine_hwm); - device_add(&lm78_device); - - return ret; -} - - -int -machine_at_lx6_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/lx6/LX6C_PZ.B00", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - device_add(&i440lx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977tf_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0xF, 256); - - return ret; -} - - -int -machine_at_p6i440e2_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/p6i440e2/E2_v14sl.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440ex_device); - device_add(&piix4_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977tf_device); - device_add(&sst_flash_29ee010_device); - spd_register(SPD_TYPE_SDRAM, 0x03, 256); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000 /* Power */ - }, { /* temperatures */ - 30, /* MB */ - 0, /* unused */ - 27 /* CPU */ - }, { /* voltages */ - 2050, /* VCORE (2.05V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - - return ret; -} - - -int -machine_at_p2bls_init(const machine_t *model) -{ - int ret; - - if (model->flags & MACHINE_COREBOOT) - ret = bios_load_linear(L"roms/machines/p2bls/coreboot.rom", - 0x000c0000, 262144, 0); - else - ret = bios_load_linear(L"roms/machines/p2bls/1014ls.003", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977ef_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0xF, 256); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000 /* Power */ - }, { /* temperatures */ - 30, /* MB */ - 0, /* unused */ - 27 /* CPU */ - }, { /* voltages */ - 2050, /* VCORE (2.05V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - - return ret; -} - - -int -machine_at_p3bf_init(const machine_t *model) -{ - int ret; - - if (model->flags & MACHINE_COREBOOT) - ret = bios_load_linear(L"roms/machines/p3bf/coreboot.rom", - 0x000c0000, 262144, 0); - else - ret = bios_load_linear(L"roms/machines/p3bf/bx3f1006.awd", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977ef_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0xF, 256); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000 /* Power */ - }, { /* temperatures */ - 30, /* MB */ - 30, /* JTPWR */ - 30 /* CPU */ - }, { /* voltages */ - 2050, /* VCORE (2.05V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 3, 1), /* +12V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 59, 20), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ - else if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_CYRIX3S) - machine_hwm.voltages[0] = 2800; /* P3B-F specific issue: it believes the Cyrix III is a Klamath, and therefore expects a toasty 2.8V */ - hwm_set_values(machine_hwm); - device_add(&as99127f_device); - - return ret; -} - - -int -machine_at_bf6_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/bf6/Beh_70.bin", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 3, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 1, 4, 3); - pci_register_slot(0x08, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977ef_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - return ret; -} - - -int -machine_at_ax6bc_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/ax6bc/AX6BC_R2.59.bin", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977tf_device); - device_add(&sst_flash_29ee020_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - return ret; -} - - -int -machine_at_atc6310bxii_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/atc6310bxii/6310s102.bin", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&slc90e66_device); - device_add(&keyboard_ps2_pci_device); - device_add(&w83977ef_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - return ret; -} - - -int -machine_at_p6sba_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/p6sba/SBAB21.ROM", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&w83977tf_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&intel_flash_bxt_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* CPU1 */ - 0, /* CPU2 */ - 3000 /* Thermal Control */ - }, { /* temperatures */ - 0, /* unused */ - 30, /* CPU1 */ - 0 /* unused (CPU2?) */ - }, { /* voltages */ - 2050, /* CPU1 (2.05V by default) */ - 0, /* CPU2 */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - - return ret; -} - - -int -machine_at_tsunamiatx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/tsunamiatx/bx46200f.rom", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0F, PCI_CARD_SOUND, 1, 0, 0, 0); - pci_register_slot(0x10, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - - if (sound_card_current == SOUND_INTERNAL) - device_add(&es1371_onboard_device); - - device_add(&pc87309_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&intel_flash_bxt_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - return ret; -} - - -const device_t * -at_tsunamiatx_get_device(void) -{ - return &es1371_onboard_device; -} +/* + * 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 Slot 1 machines. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/pci.h> +#include <86box/chipset.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/sio.h> +#include <86box/hwm.h> +#include <86box/spd.h> +#include <86box/video.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/sound.h> +#include <86box/clock.h> +#include <86box/snd_ac97.h> + +int +machine_at_p65up5_cpknd_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p65up5/NDKN0218.AWD", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_p65up5_common_init(model, &i440fx_device); + + return ret; +} + + +int +machine_at_kn97_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/kn97/0116I.001", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_device); + device_add(&intel_flash_bxt_device); + device_add(&lm78_device); /* fans: Chassis, CPU, Power; temperature: MB */ + for (uint8_t i = 0; i < 3; i++) + hwm_values.fans[i] *= 2; /* BIOS reports fans with the wrong divisor for some reason */ + + return ret; +} + + +int +machine_at_lx6_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/lx6/LX6C_PZ.B00", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440lx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977tf_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + + return ret; +} + + +int +machine_at_spitfire_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/spitfire/SPIHM.02", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 1, 2, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440lx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c935_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + device_add(&lm78_device); /* no reporting in BIOS */ + + return ret; +} + + +int +machine_at_p6i440e2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p6i440e2/E2_v14sl.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440ex_device); + device_add(&piix4_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977tf_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x03, 256); + device_add(&w83781d_device); /* fans: CPU, CHS, PS; temperatures: unused, CPU, System */ + hwm_values.temperatures[0] = 0; /* unused */ + hwm_values.voltages[1] = 1500; /* CPUVTT */ + + return ret; +} + + +int +machine_at_p2bls_init(const machine_t *model) +{ + int ret; + + if (model->flags & MACHINE_COREBOOT) + ret = bios_load_linear("roms/machines/p2bls/coreboot.rom", + 0x000c0000, 262144, 0); + else + ret = bios_load_linear("roms/machines/p2bls/1014ls.003", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* SCSI */ + pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); /* LAN */ + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977ef_device); + //device_add(ics9xxx_get(ICS9150_08)); /* setting proper speeds requires some interaction with the AS97127F ASIC */ + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + device_add(&w83781d_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ + hwm_values.temperatures[1] = 0; /* unused */ + hwm_values.temperatures[2] -= 3; /* CPU offset */ + + return ret; +} + + +int +machine_at_p3bf_init(const machine_t *model) +{ + int ret; + + if (model->flags & MACHINE_COREBOOT) + ret = bios_load_linear("roms/machines/p3bf/coreboot.rom", + 0x000c0000, 262144, 0); + else +// ret = bios_load_linear("roms/machines/p3bf/bx3f1006.awd", + ret = bios_load_linear("roms/machines/p3bf/1008f.004", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977ef_device); + device_add(ics9xxx_get(ICS9250_08)); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */ + hwm_values.voltages[4] = hwm_values.voltages[5]; /* +12V reading not in line with other boards; appears to be close to the -12V reading */ + + return ret; +} + + +int +machine_at_bf6_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/bf6/Beh_70.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 1, 4, 3); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 3, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83977ef_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} + + +int +machine_at_ax6bc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ax6bc/AX6BC_R2.59.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977tf_device); + device_add(&sst_flash_29ee020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + device_add(&gl518sm_2d_device); /* fans: System, CPU; temperature: CPU; no reporting in BIOS */ + + return ret; +} + + +int +machine_at_atc6310bxii_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/atc6310bxii/6310s102.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&slc90e66_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83977ef_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} + + +int +machine_at_686bx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/686bx/6BX.F2a", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977tf_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + device_add(&w83781d_device); /* fans: CPU, unused, unused; temperatures: unused, CPU, unused */ + hwm_values.temperatures[0] = 0; /* unused */ + hwm_values.temperatures[1] += 4; /* CPU offset */ + hwm_values.temperatures[2] = 0; /* unused */ + hwm_values.fans[1] = 0; /* unused */ + hwm_values.fans[2] = 0; /* unused */ + + return ret; +} + + +int +machine_at_p6sba_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p6sba/SBAB21.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&w83977tf_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + device_add(&w83781d_device); /* fans: CPU1, CPU2, Thermal Control; temperatures: unused, CPU1, CPU2? */ + hwm_values.fans[1] = 0; /* no CPU2 fan */ + hwm_values.temperatures[0] = 0; /* unused */ + hwm_values.temperatures[2] = 0; /* CPU2? */ + /* no CPU2 voltage */ + + return ret; +} + + +int +machine_at_s1846_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/s1846/bx46200f.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUND, 1, 0, 0, 0); + pci_register_slot(0x10, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&pc87309_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + if (sound_card_current == SOUND_INTERNAL) { + device_add(&es1371_onboard_device); + device_add(&cs4297_device); /* found on other Tyan boards around the same time */ + } + + return ret; +} + +int +machine_at_ficka6130_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ficka6130/qa4163.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro_device); + device_add(&via_vt82c596a_device); + device_add(&w83877tf_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_29ee020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} + + +int +machine_at_p3v133_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p3v133/1003.002", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro133_device); + device_add(&via_vt82c596b_device); + device_add(&w83977ef_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(ics9xxx_get(ICS9248_39)); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + device_add(&w83781d_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ + hwm_values.temperatures[1] = 0; /* unused */ + hwm_values.temperatures[2] -= 3; /* CPU offset */ + + return ret; +} + + +int +machine_at_p3v4x_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p3v4x/1006.004", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro133a_device); + device_add(&via_vt82c596b_device); + device_add(&w83977ef_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(ics9xxx_get(ICS9250_18)); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 512); + device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */ + + return ret; +} + + +int +machine_at_vei8_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/vei8/QHW1001.BIN", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&fdc37m60x_370_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(ics9xxx_get(ICS9250_08)); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 512); + device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */ + + return ret; +} + + +static void +machine_at_ms6168_common_init(const machine_t *model) +{ + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_SOUND, 3, 4, 1, 2); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440zx_device); + device_add(&piix4e_device); + device_add(&w83977ef_device); + + if (gfxcard == VID_INTERNAL) + device_add(&voodoo_3_2000_agp_onboard_8m_device); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + + if (sound_card_current == SOUND_INTERNAL) { + device_add(&es1371_onboard_device); + device_add(&cs4297_device); + } +} + + +const device_t * +at_ms6168_get_device(void) +{ + return &voodoo_3_2000_agp_onboard_8m_device; +} + + +int +machine_at_borapro_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/borapro/MS6168V2.50", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ms6168_common_init(model); + + return ret; +} + + +int +machine_at_ms6168_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms6168/w6168ims.130", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ms6168_common_init(model); + + return ret; +} + + +int +machine_at_m729_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m729/M729NEW.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1621_device); + device_add(&ali1543c_device); /* +0 */ + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} diff --git a/src/machine/m_at_slot2.c b/src/machine/m_at_slot2.c index 8ed78a000..359b94f60 100644 --- a/src/machine/m_at_slot2.c +++ b/src/machine/m_at_slot2.c @@ -9,7 +9,8 @@ * Implementation of Slot 2 machines. * * Slot 2 is quite a rare type of Slot. Used mostly by Pentium II & III Xeons - * These boards were also capable to take Slot 1 CPU's using Slot 2 to 1 adapters. + * + * * * Authors: Miran Grca, * @@ -30,12 +31,12 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/keyboard.h> -#include <86box/intel_flash.h> -#include <86box/sst_flash.h> +#include <86box/flash.h> #include <86box/sio.h> #include <86box/hwm.h> #include <86box/spd.h> #include <86box/video.h> +#include <86box/clock.h> #include "cpu.h" #include <86box/machine.h> @@ -44,7 +45,7 @@ machine_at_6gxu_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/6gxu/6gxu.f1c", + ret = bios_load_linear("roms/machines/6gxu/6gxu.f1c", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -55,44 +56,23 @@ machine_at_6gxu_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); /* On-Board SCSI. Not emulated at the moment */ - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); /* On-Board SCSI. Not emulated at the moment */ + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440gx_device); device_add(&piix4e_device); device_add(&keyboard_ps2_pci_device); device_add(&w83977ef_device); device_add(&sst_flash_39sf020_device); spd_register(SPD_TYPE_SDRAM, 0xF, 512); + device_add(&w83782d_device); /* fans: CPU, Power, System; temperatures: System, CPU, unused */ + hwm_values.temperatures[2] = 0; /* unused */ + hwm_values.voltages[1] = 1500; /* VGTL */ - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000 /* Power */ - }, { /* temperatures */ - 30, /* MB */ - 0, /* unused */ - 27 /* CPU */ - }, { /* voltages */ - 2050, /* VCORE (2.05V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - return ret; } @@ -101,7 +81,7 @@ machine_at_s2dge_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/s2dge/2gu7301.rom", + ret = bios_load_linear("roms/machines/s2dge/2gu7301.rom", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -111,45 +91,63 @@ machine_at_s2dge_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + device_add(&i440gx_device); device_add(&piix4e_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&w83977tf_device); device_add(&intel_flash_bxt_device); - spd_register(SPD_TYPE_SDRAM, 0xF, 256); + spd_register(SPD_TYPE_SDRAM, 0xF, 512); + device_add(&w83781d_device); /* fans: CPU1, CPU2, Thermal Control; temperatures: unused, CPU1, CPU2? */ + hwm_values.fans[1] = 0; /* no CPU2 fan */ + hwm_values.temperatures[0] = 0; /* unused */ + hwm_values.temperatures[2] = 0; /* CPU2? */ + + return ret; +} + +int +machine_at_fw6400gx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/fw6400gx/FWGX1211.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + + device_add(&i440gx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87309_15c_device); + device_add(ics9xxx_get(ICS9250_08)); + device_add(&sst_flash_29ee020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 512); + device_add(&w83781d_device); /* fans: Chassis, Power, CPU; temperatures: System, CPU, unused */ + hwm_values.temperatures[3] = 0; /* unused */ + hwm_values.voltages[1] = 1500; /* Vtt */ - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* CPU1 */ - 0, /* CPU2 */ - 3000 /* Thermal Control */ - }, { /* temperatures */ - 0, /* unused */ - 30, /* CPU1 */ - 20 /* unused (CPU2?) */ - }, { /* voltages */ - 2050, /* CPU1 (2.05V by default) */ - 0, /* CPU2 */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */ - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - return ret; } diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index 5642cc74f..9daec8609 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -29,21 +29,24 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/keyboard.h> -#include <86box/intel_flash.h> +#include <86box/flash.h> #include <86box/sio.h> -#include <86box/sst_flash.h> #include <86box/hwm.h> #include <86box/spd.h> #include <86box/video.h> #include "cpu.h" #include <86box/machine.h> +#include <86box/clock.h> +#include <86box/sound.h> +#include <86box/snd_ac97.h> + int machine_at_s370slm_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/s370slm/3LM1202.rom", + ret = bios_load_linear("roms/machines/s370slm/3LM1202.rom", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -54,51 +57,103 @@ machine_at_s370slm_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440lx_device); device_add(&piix4e_device); device_add(&w83977tf_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); + device_add(&w83781d_device); /* fans: CPU, Fan 2, Chassis; temperatures: unused, CPU, unused */ + hwm_values.temperatures[0] = 0; /* unused */ + hwm_values.temperatures[2] = 0; /* unused */ - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* CPU */ - 3000, /* Fan 2 */ - 3000 /* Chassis */ - }, { /* temperatures */ - 0, /* unused */ - 30, /* CPU */ - 0 /* unused */ - }, { /* voltages */ - 2050, /* CPU1 (2.05V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - return ret; } + +int +machine_at_s1857_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/s1857/BX57200A.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUND, 1, 0, 0, 0); + pci_register_slot(0x10, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977ef_370_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + if (sound_card_current == SOUND_INTERNAL) { + device_add(&es1371_onboard_device); + device_add(&cs4297_device); /* found on other Tyan boards around the same time */ + } + + return ret; +} + + +int +machine_at_p6bap_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p6bap/bapa14a.BIN", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x12, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro133a_device); /* Rebranded as ET82C693A */ + device_add(&via_vt82c596b_device); /* Rebranded as ET82C696B */ + device_add(&w83977ef_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} + + int machine_at_cubx_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/cubx/1008cu.004", + ret = bios_load_linear("roms/machines/cubx/1008cu.004", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -108,52 +163,34 @@ machine_at_cubx_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_IDE, 2, 3, 4, 1); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440bx_device); device_add(&piix4e_device); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); device_add(&w83977ef_device); + device_add(ics9xxx_get(ICS9250_08)); device_add(&sst_flash_39sf020_device); spd_register(SPD_TYPE_SDRAM, 0xF, 256); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000 /* Power */ - }, { /* temperatures */ - 30, /* MB */ - 30, /* JTPWR */ - 30 /* CPU */ - }, { /* voltages */ - 2050, /* VCORE (2.05V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 59, 20), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - hwm_set_values(machine_hwm); - device_add(&as99127f_device); + device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */ return ret; } + int machine_at_atc7020bxii_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/atc7020bxii/7020s102.bin", + ret = bios_load_linear("roms/machines/atc7020bxii/7020s102.bin", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -163,13 +200,13 @@ machine_at_atc7020bxii_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440bx_device); device_add(&slc90e66_device); device_add(&keyboard_ps2_pci_device); @@ -177,16 +214,16 @@ machine_at_atc7020bxii_init(const machine_t *model) device_add(&sst_flash_39sf020_device); spd_register(SPD_TYPE_SDRAM, 0xF, 256); - return ret; + return ret; } int -machine_at_63a_init(const machine_t *model) +machine_at_ambx133_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/63a1/63a-q3.bin", + ret = bios_load_linear("roms/machines/ambx133/mkbx2vg2.bin", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -196,17 +233,88 @@ machine_at_63a_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&w83977ef_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + device_add(&gl518sm_2d_device); /* fans: CPUFAN1, CPUFAN2; temperature: CPU */ + hwm_values.fans[1] += 500; + hwm_values.temperatures[0] += 4; /* CPU offset */ + hwm_values.voltages[1] = RESISTOR_DIVIDER(12000, 10, 2); /* different 12V divider in BIOS (10K/2K?) */ + + return ret; +} + + +int +machine_at_awo671r_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/awo671r/a08139c.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add_inst(&w83977ef_device, 1); + device_add_inst(&w83977ef_device, 2); + device_add(&keyboard_ps2_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + + return ret; +} + + +int +machine_at_63a1_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/63a1/63a-q3.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); // Integrated Sound? - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); /* Integrated Sound? */ + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440zx_device); device_add(&piix4e_device); device_add(&w83977tf_device); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 256); @@ -219,7 +327,7 @@ machine_at_apas3_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/apas3/V0218SAG.BIN", + ret = bios_load_linear("roms/machines/apas3/V0218SAG.BIN", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -229,18 +337,139 @@ machine_at_apas3_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 0, 0); pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&via_apro_device); device_add(&via_vt82c586b_device); device_add(&fdc37c669_device); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); device_add(&sst_flash_39sf020_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); return ret; } + + +int +machine_at_gt694va_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/gt694va/21071100.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 3, 4); + pci_register_slot(0x0D, PCI_CARD_SOUND, 4, 1, 2, 3); /* assumed */ + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro133a_device); + device_add(&via_vt82c596b_device); + device_add(&w83977ef_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 1024); + device_add(&w83782d_device); /* fans: CPU, unused, unused; temperatures: System, CPU1, unused */ + hwm_values.voltages[1] = 1500; /* IN1 (unknown purpose, assumed Vtt) */ + hwm_values.fans[0] = 4500; /* BIOS does not display <4411 RPM */ + hwm_values.fans[1] = 0; /* unused */ + hwm_values.fans[2] = 0; /* unused */ + hwm_values.temperatures[2] = 0; /* unused */ + + if (sound_card_current == SOUND_INTERNAL) { + device_add(&es1371_onboard_device); + device_add(&cs4297_device); /* assumed */ + } + + return ret; +} + + +int +machine_at_cuv4xls_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/cuv4xls/1005LS.001", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 4, 1, 2, 3); + pci_register_slot(0x05, PCI_CARD_SOUND, 3, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_NORMAL, 2, 3, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro133a_device); + device_add(&via_vt82c686b_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(ics9xxx_get(ICS9250_18)); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 1024); + device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */ + + if (sound_card_current == SOUND_INTERNAL) + device_add(&cmi8738_onboard_device); + + return ret; +} + +int +machine_at_6via90ap_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/6via90ap/90ap10.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_apro133a_device); + device_add(&via_vt82c686b_device); /* fans: CPU1, CPU2; temperatures: CPU, System, unused */ + device_add(&keyboard_ps2_ami_pci_device); + device_add(ics9xxx_get(ICS9250_18)); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 1024); + hwm_values.temperatures[0] += 2; /* CPU offset */ + hwm_values.temperatures[1] += 2; /* System offset */ + hwm_values.temperatures[2] = 0; /* unused */ + + if (sound_card_current == SOUND_INTERNAL) + device_add(&alc100_device); /* ALC100P identified on similar Acorp boards (694TA, 6VIA90A1) */ + + return ret; +} diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c new file mode 100644 index 000000000..1dd74971d --- /dev/null +++ b/src/machine/m_at_socket4.c @@ -0,0 +1,464 @@ +/* + * 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 Socket 4 machines. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/fdc_ext.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/nvr.h> +#include <86box/scsi_ncr53c8xx.h> +#include <86box/sio.h> +#include <86box/video.h> +#include <86box/machine.h> + + +void +machine_at_premiere_common_init(const machine_t *model, int pci_switch) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | pci_switch); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); +} + + +void +machine_at_award_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ + pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + // device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); +} + + +void +machine_at_sp4_common_init(const machine_t *model) +{ + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + /* Excluded: 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 10, 11, 12, 13, 14 */ + pci_register_slot(0x0D, PCI_CARD_IDE, 1, 2, 3, 4); + /* Excluded: 02, 03*, 04*, 05*, 06*, 07*, 08* */ + /* Slots: 09 (04), 0A (03), 0B (02), 0C (07) */ + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&sis_85c50x_device); + device_add(&ide_cmd640_pci_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); +} + + +int +machine_at_excaliburpci_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/excaliburpci/S701P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_cmd640_pci_legacy_only_device); + + device_add(&i430lx_device); + device_add(&sio_zb_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_p5mp3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5mp3/0205.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x05, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 05 = Slot 1 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x03, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 03 = Slot 3 */ + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&fdc_at_device); + device_add(&keyboard_ps2_pci_device); + + device_add(&sio_zb_device); + device_add(&catalyst_flash_device); + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_dellxp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/dellxp60/XP60-A08.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + /* Not: 00, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F. */ + /* Yes: 01, 10, 11, 12, 13, 14. */ + pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 4, 4, 3, 3); + pci_register_slot(0x05, PCI_CARD_NORMAL, 1, 4, 3, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430lx_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_opti560l_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/opti560l/560L_A06.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 4, 4, 3, 3); + pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 4, 3, 2); + pci_register_slot(0x08, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430lx_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&sio_zb_device); + device_add(&i82091aa_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_ambradp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/ambradp60/1004AF1P.BIO", + "roms/machines/ambradp60/1004AF1P.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model, 0); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_valuepointp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/valuepointp60/1006AV0M.BIO", + "roms/machines/valuepointp60/1006AV0M.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ps1_pci_device); + device_add(&sio_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_revenge_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/revenge/1009af2_.bio", + "roms/machines/revenge/1009af2_.bi1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model, 0); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_586mc1_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/586mc1/IS.34", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&sio_device); + device_add(&intel_flash_bxt_device); + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_pb520r_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/pb520r/1009bc0r.bio", + "roms/machines/pb520r/1009bc0r.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_VIDEO, 3, 3, 3, 3); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430lx_device); + device_add(&ide_cmd640_pci_single_channel_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5434_onboard_pci_device); + + device_add(&keyboard_ps2_pci_device); + device_add(&sio_zb_device); + device_add(&i82091aa_ide_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + +int +machine_at_excalibur_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/excalibur/S75P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti5x7_device); + device_add(&ide_opti611_vlb_device); + device_add(&fdc37c661_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + + return ret; +} + + +int +machine_at_p5vl_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5vl/SM507.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&opti5x7_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_ami_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_excaliburpci2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_inverted("roms/machines/excaliburpci2/S722P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&ami_1994_nvr_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&fdc37c665_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_cmd640_pci_legacy_only_device); + + device_add(&sis_85c50x_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_p5sp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5sp4/0106.001", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sp4_common_init(model); + + return ret; +} diff --git a/src/machine/m_at_socket4_5.c b/src/machine/m_at_socket5.c similarity index 52% rename from src/machine/m_at_socket4_5.c rename to src/machine/m_at_socket5.c index eb311d587..4fc7441bb 100644 --- a/src/machine/m_at_socket4_5.c +++ b/src/machine/m_at_socket5.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of Socket 4 and 5 machines. + * Implementation of Socket 5 machines. * * * @@ -28,158 +28,19 @@ #include <86box/pci.h> #include <86box/device.h> #include <86box/chipset.h> +#include <86box/fdc_ext.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/timer.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/keyboard.h> -#include <86box/intel_flash.h> -#include <86box/sst_flash.h> +#include <86box/flash.h> #include <86box/nvr.h> +#include <86box/scsi_ncr53c8xx.h> #include <86box/sio.h> #include <86box/video.h> #include <86box/machine.h> -int -machine_at_excalibur_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_inverted(L"roms/machines/excalibur/S75P.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - device_add(&ide_vlb_device); - device_add(&opti5x7_device); - device_add(&fdc37c663_device); - device_add(&keyboard_at_ami_device); - - return ret; -} - - -static void -machine_at_premiere_common_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&ide_pci_2ch_device); - - pci_init(PCI_CONFIG_TYPE_2); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&sio_zb_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_ami_device); -} - - -static void -machine_at_award_common_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&ide_pci_2ch_device); - - pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ - pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ - pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ - pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ - pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&fdc_at_device); - device_add(&keyboard_ps2_pci_device); - device_add(&sio_device); - device_add(&intel_flash_bxt_device); -} - - -int -machine_at_batman_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined(L"roms/machines/revenge/1009af2_.bio", - L"roms/machines/revenge/1009af2_.bi1", 0x1c000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_premiere_common_init(model); - - device_add(&i430lx_device); - - return ret; -} - - -int -machine_at_ambradp60_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined(L"roms/machines/ambradp60/1004AF1P.BIO", - L"roms/machines/ambradp60/1004AF1P.BI1", 0x1c000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_premiere_common_init(model); - - device_add(&i430lx_device); - - return ret; -} - - -#if defined(DEV_BRANCH) && defined(USE_VPP60) -int -machine_at_valuepointp60_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined(L"roms/machines/valuepointp60/1006AV0M.BIO", - L"roms/machines/valuepointp60/1006AV0M.BI1", 0x1d000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_premiere_common_init(model); - - device_add(&i430lx_device); - - return ret; -} -#endif - - -int -machine_at_586mc1_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/586mc1/IS.34", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_award_common_init(model); - - device_add(&i430lx_device); - - return ret; -} int @@ -187,13 +48,13 @@ machine_at_plato_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined(L"roms/machines/plato/1016ax1_.bio", - L"roms/machines/plato/1016ax1_.bi1", 0x1d000, 128); + ret = bios_load_linear_combined("roms/machines/plato/1016ax1_.bio", + "roms/machines/plato/1016ax1_.bi1", 0x1d000, 128); if (bios_only || !ret) return ret; - machine_at_premiere_common_init(model); + machine_at_premiere_common_init(model, PCI_CAN_SWITCH_TYPE); device_add(&i430nx_device); @@ -206,13 +67,13 @@ machine_at_ambradp90_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined(L"roms/machines/ambradp90/1002AX1P.BIO", - L"roms/machines/ambradp90/1002AX1P.BI1", 0x1d000, 128); + ret = bios_load_linear_combined("roms/machines/ambradp90/1002AX1P.BIO", + "roms/machines/ambradp90/1002AX1P.BI1", 0x1d000, 128); if (bios_only || !ret) return ret; - machine_at_premiere_common_init(model); + machine_at_premiere_common_init(model, PCI_CAN_SWITCH_TYPE); device_add(&i430nx_device); @@ -225,7 +86,7 @@ machine_at_430nx_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/430nx/IP.20", + ret = bios_load_linear("roms/machines/430nx/IP.20", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -233,6 +94,8 @@ machine_at_430nx_init(const machine_t *model) machine_at_award_common_init(model); + device_add(&sio_device); + device_add(&intel_flash_bxt_device); device_add(&i430nx_device); return ret; @@ -240,11 +103,11 @@ machine_at_430nx_init(const machine_t *model) int -machine_at_p54tp4xe_init(const machine_t *model) +machine_at_acerv30_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/p54tp4xe/t15i0302.awd", + ret = bios_load_linear("roms/machines/acerv30/V30R01N9.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -252,18 +115,49 @@ machine_at_p54tp4xe_init(const machine_t *model) machine_at_common_init(model); - /* Award BIOS, SMC FDC37C665. */ pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_pci_device); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&i430fx_device); device_add(&piix_device); + device_add(&keyboard_ps2_acer_pci_device); device_add(&fdc37c665_device); + + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_apollo_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/apollo/S728P.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&ami_1995_nvr_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87332_398_device); device_add(&intel_flash_bxt_device); return ret; @@ -271,12 +165,12 @@ machine_at_p54tp4xe_init(const machine_t *model) int -machine_at_endeavor_init(const machine_t *model) +machine_at_exp8551_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined(L"roms/machines/endeavor/1006cb0_.bio", - L"roms/machines/endeavor/1006cb0_.bi1", 0x1d000, 128); + ret = bios_load_linear("roms/machines/exp8551/AMI20.BIO", + 0x000e0000, 131072, 0); if (bios_only || !ret) return ret; @@ -285,40 +179,28 @@ machine_at_endeavor_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - - if (gfxcard == VID_INTERNAL) - device_add(&s3_phoenix_trio64_onboard_pci_device); - - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_ami_pci_device); device_add(&i430fx_device); device_add(&piix_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); + device_add(&w83787f_device); + device_add(&sst_flash_29ee010_device); return ret; } -const device_t * -at_endeavor_get_device(void) -{ - return &s3_phoenix_trio64_onboard_pci_device; -} - - int machine_at_zappa_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined(L"roms/machines/zappa/1006bs0_.bio", - L"roms/machines/zappa/1006bs0_.bi1", 0x20000, 128); + ret = bios_load_linear_combined("roms/machines/zappa/1006bs0_.bio", + "roms/machines/zappa/1006bs0_.bi1", 0x20000, 128); if (bios_only || !ret) return ret; @@ -342,101 +224,11 @@ machine_at_zappa_init(const machine_t *model) int -machine_at_gw2kzp_init(const machine_t *model) +machine_at_powermatev_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined(L"roms/machines/gw2k_zp/1011bs0t.bio", - L"roms/machines/gw2k_zp/1011bs0t.bi1", 0x20000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); - - return ret; -} - - -int -machine_at_mb500n_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/mb500n/031396s.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_pci_device); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -#if defined(DEV_BRANCH) && defined(USE_VECTRA54) -int -machine_at_vectra54_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/vectra54/GT0724.22", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&fdc37c932qf_device); - device_add(&intel_flash_bxt_device); - - return ret; -} -#endif - - -int -machine_at_powermate_v_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/powermate_v/BIOS.ROM", + ret = bios_load_linear("roms/machines/powermatev/BIOS.ROM", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -461,11 +253,11 @@ machine_at_powermate_v_init(const machine_t *model) int -machine_at_acerv30_init(const machine_t *model) +machine_at_mb500n_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/acerv30/V30R01N9.BIN", + ret = bios_load_linear("roms/machines/mb500n/031396s.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -475,16 +267,146 @@ machine_at_acerv30_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&keyboard_ps2_pci_device); device_add(&i430fx_device); device_add(&piix_device); - device_add(&keyboard_ps2_acer_pci_device); device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + return ret; +} + + +int +machine_at_hawk_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hawk/HAWK.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&ami_1994_nvr_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_pat54pv_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pat54pv/PAT54PV.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti5x7_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_hot543_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/hot543/543_R21.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&opti5x7_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_p54sp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p54sp4/SI5I0204.AWD", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sp4_common_init(model); + + return ret; +} + + +int +machine_at_sq588_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sq588/sq588b03.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + /* Correct: 0D (01), 0F (02), 11 (03), 13 (04) */ + pci_register_slot(0x02, PCI_CARD_IDE, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&sis_85c50x_device); + device_add(&ide_cmd640_pci_single_channel_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_ide_device); device_add(&sst_flash_29ee010_device); return ret; diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7.c similarity index 61% rename from src/machine/m_at_socket7_s7.c rename to src/machine/m_at_socket7.c index 41ca9aa55..2856a599c 100644 --- a/src/machine/m_at_socket7_s7.c +++ b/src/machine/m_at_socket7.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of Socket 7 machines. + * Implementation of Socket 7 (Dual Voltage) machines. * * * @@ -33,218 +33,18 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/keyboard.h> -#include <86box/intel_flash.h> +#include <86box/flash.h> #include <86box/sio.h> -#include <86box/sst_flash.h> #include <86box/hwm.h> #include <86box/video.h> #include <86box/spd.h> #include "cpu.h" #include <86box/machine.h> - -int -machine_at_chariot_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/chariot/P5IV183.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 3, 2, 1); - - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -int -machine_at_mr586_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/mr586/TRITON.BIO", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -static void -machine_at_thor_common_init(const machine_t *model, int mr) -{ - machine_at_common_init_ex(model, mr); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); -} - - -int -machine_at_thor_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined(L"roms/machines/thor/1006cn0_.bio", - L"roms/machines/thor/1006cn0_.bi1", 0x20000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_thor_common_init(model, 0); - - return ret; -} - - -int -machine_at_gw2katx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined(L"roms/machines/gw2katx/1003cn0t.bio", - L"roms/machines/gw2katx/1003cn0t.bi1", 0x20000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_thor_common_init(model, 0); - - return ret; -} - - -int -machine_at_mrthor_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/mrthor/mr_atx.bio", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_thor_common_init(model, 1); - - return ret; -} - - -int -machine_at_pb640_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined(L"roms/machines/pb640/1007CP0R.BIO", - L"roms/machines/pb640/1007CP0R.BI1", 0x1d000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430fx_rev02_device); - device_add(&piix_rev02_device); - - if (gfxcard == VID_INTERNAL) - device_add(&gd5440_onboard_pci_device); - - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); - - return ret; -} - -const device_t * -at_pb640_get_device(void) -{ - return &gd5440_onboard_pci_device; -} - - -int -machine_at_acerm3a_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/acerm3a/r01-b3.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_pci_device); - device_add(&fdc37c932fr_device); - device_add(&acerm3a_device); - - device_add(&sst_flash_29ee010_device); - - return ret; -} +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/nvr.h> +#include <86box/scsi_ncr53c8xx.h> int @@ -252,7 +52,7 @@ machine_at_acerv35n_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/acerv35n/v35nd1s1.bin", + ret = bios_load_linear("roms/machines/acerv35n/v35nd1s1.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -272,7 +72,6 @@ machine_at_acerv35n_init(const machine_t *model) device_add(&piix3_device); device_add(&keyboard_ps2_pci_device); device_add(&fdc37c932fr_device); - device_add(&acerm3a_device); device_add(&sst_flash_29ee010_device); @@ -281,11 +80,11 @@ machine_at_acerv35n_init(const machine_t *model) int -machine_at_ap53_init(const machine_t *model) +machine_at_ap5vm_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ap53/ap53r2c0.rom", + ret = bios_load_linear("roms/machines/ap5vm/AP5V270.ROM", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -295,16 +94,20 @@ machine_at_ap53_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + /* It seems there were plans for an on-board NCR 53C810 according to some clues + left in the manual, but were latter scrapped. The BIOS still support that + PCI device, though, so why not. */ + pci_register_slot(0x06, PCI_CARD_SCSI, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); - device_add(&i430hx_device); + device_add(&i430vx_device); device_add(&piix3_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c669_device); + device_add(&fdc37c665_device); + device_add(&ncr53c810_onboard_pci_device); device_add(&intel_flash_bxt_device); return ret; @@ -316,7 +119,7 @@ machine_at_p55t2p4_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/p55t2p4/0207_j2.bin", + ret = bios_load_linear("roms/machines/p55t2p4/0207_j2.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -341,41 +144,12 @@ machine_at_p55t2p4_init(const machine_t *model) } -int -machine_at_p55t2s_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/p55t2s/s6y08t.rom", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - int machine_at_m7shi_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/m7shi/m7shi2n.rom", + ret = bios_load_linear("roms/machines/m7shi/m7shi2n.rom", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -399,16 +173,17 @@ machine_at_m7shi_init(const machine_t *model) return ret; } + int machine_at_tc430hx_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined2(L"roms/machines/tc430hx/1007dh0_.bio", - L"roms/machines/tc430hx/1007dh0_.bi1", - L"roms/machines/tc430hx/1007dh0_.bi2", - L"roms/machines/tc430hx/1007dh0_.bi3", - L"roms/machines/tc430hx/1007dh0_.rcv", + ret = bios_load_linear_combined2("roms/machines/tc430hx/1007DH0_.BIO", + "roms/machines/tc430hx/1007DH0_.BI1", + "roms/machines/tc430hx/1007DH0_.BI2", + "roms/machines/tc430hx/1007DH0_.BI3", + "roms/machines/tc430hx/1007DH0_.RCV", 0x3a000, 128); if (bios_only || !ret) @@ -418,7 +193,78 @@ machine_at_tc430hx_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +/* Information about that machine on machine.h */ +int +machine_at_equium5200_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2("roms/machines/equium5200/1003DK08.BIO", + "roms/machines/equium5200/1003DK08.BI1", + "roms/machines/equium5200/1003DK08.BI2", + "roms/machines/equium5200/1003DK08.BI3", + "roms/machines/equium5200/1003DK08.RCV", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 0, 0, 0); // riser + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_pcv90_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2("roms/machines/pcv90/1010DD04.BIO", + "roms/machines/pcv90/1010DD04.BI1", + "roms/machines/pcv90/1010DD04.BI2", + "roms/machines/pcv90/1010DD04.BI3", + "roms/machines/pcv90/1010DD04.RCV", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); @@ -434,46 +280,12 @@ machine_at_tc430hx_init(const machine_t *model) } -int -machine_at_equium5200_init(const machine_t *model) // Information about that machine on machine.h -{ - int ret; - - ret = bios_load_linear_combined2(L"roms/machines/equium5200/1003DK08.BIO", - L"roms/machines/equium5200/1003DK08.BI1", - L"roms/machines/equium5200/1003DK08.BI2", - L"roms/machines/equium5200/1003DK08.BI3", - L"roms/machines/equium5200/1003DK08.RCV", - 0x3a000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 0, 0, 0); // riser - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); - - return ret; -} - int machine_at_p65up5_cp55t2d_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/p65up5/td5i0201.awd", + ret = bios_load_linear("roms/machines/p65up5/TD5I0201.AWD", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -484,12 +296,13 @@ machine_at_p65up5_cp55t2d_init(const machine_t *model) return ret; } + int machine_at_p55tvp4_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/p55tvp4/0204_128.BIN", + ret = bios_load_linear("roms/machines/p55tvp4/0204_128.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -513,12 +326,13 @@ machine_at_p55tvp4_init(const machine_t *model) return ret; } + int -machine_at_i430vx_init(const machine_t *model) +machine_at_5ivg_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/430vx/55xwuq0e.bin", + ret = bios_load_linear("roms/machines/5ivg/5IVG.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -530,82 +344,24 @@ machine_at_i430vx_init(const machine_t *model) pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); device_add(&keyboard_ps2_pci_device); - device_add(&um8669f_device); + device_add(&prime3c_device); device_add(&intel_flash_bxt_device); return ret; } -int -machine_at_p55va_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/p55va/va021297.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_pci_device); - device_add(&fdc37c932fr_device); - device_add(&intel_flash_bxt_device); - - return ret; -} - -int -machine_at_brio80xx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/brio80xx/Hf0705.rom", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&fdc37c935_device); - device_add(&sst_flash_29ee020_device); - - return ret; -} int machine_at_8500tvxa_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/8500tvxa/tvx0619b.rom", + ret = bios_load_linear("roms/machines/8500tvxa/tvx0619b.rom", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -629,16 +385,141 @@ machine_at_8500tvxa_init(const machine_t *model) return ret; } + +int +machine_at_presario2240_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/presario2240/B0184008.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_VIDEO, 3, 0, 0, 0); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_trio64v2_dx_onboard_pci_device); + + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c932qf_device); + device_add(&sst_flash_29ee020_device); + + return ret; +} + + +int +machine_at_presario4500_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/presario4500/B013300I.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_VIDEO, 3, 0, 0, 0); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_trio64v2_dx_onboard_pci_device); + + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c931apm_compaq_device); + device_add(&sst_flash_29ee020_device); + + return ret; +} + + +int +machine_at_p55va_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p55va/va021297.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c932fr_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_brio80xx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/brio80xx/Hf0705.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c935_device); + device_add(&sst_flash_29ee020_device); + + return ret; +} + + int machine_at_pb680_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined2(L"roms/machines/pb680/1012DN0R.BIO", - L"roms/machines/pb680/1012DN0R.BI1", - L"roms/machines/pb680/1012DN0R.BI2", - L"roms/machines/pb680/1012DN0R.BI3", - L"roms/machines/pb680/1012DN0R.RCV", + ret = bios_load_linear_combined2("roms/machines/pb680/1012DN0R.BIO", + "roms/machines/pb680/1012DN0R.BI1", + "roms/machines/pb680/1012DN0R.BI2", + "roms/machines/pb680/1012DN0R.BI3", + "roms/machines/pb680/1012DN0R.RCV", 0x3a000, 128); if (bios_only || !ret) @@ -648,7 +529,7 @@ machine_at_pb680_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); @@ -663,12 +544,72 @@ machine_at_pb680_init(const machine_t *model) } +int +machine_at_mb520n_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mb520n/520n503s.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_i430vx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/430vx/55XWUQ0E.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + int machine_at_nupro592_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/nupro592/np590b10.bin", + ret = bios_load_linear("roms/machines/nupro592/np590b10.bin", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -683,59 +624,30 @@ machine_at_nupro592_init(const machine_t *model) pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x14, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); /*Strongly suspect these are on-board slots*/ - pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); /* PIIX4 */ device_add(&i430tx_device); device_add(&piix4_device); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); device_add(&w83977ef_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000, /* Power */ - 0 - }, { /* temperatures */ - 30, /* MB */ - 0, /* unused */ - 27, /* CPU */ - 0 - }, { /* voltages */ - 3300, /* VCORE (3.3V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2), /* -5V (divider values bruteforced) */ - 0 - } - }; - /* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V). - Pentium MMX: 2.8 V. - AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233. - AMD K6 Model 7: 2.2 V. */ - if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMMMX) - machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Pentium MMX */ - else if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_K6) - machine_hwm.voltages[0] = 2200; /* set higher VCORE (2.8V) for Pentium MMX */ - else if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_K6_2) - machine_hwm.voltages[0] = 2200; /* set higher VCORE (2.8V) for Pentium MMX */ - hwm_set_values(machine_hwm); - device_add(&w83781d_device); - + device_add(&w83781d_device); /* fans: CPU1, unused, unused; temperatures: System, CPU1, unused */ + hwm_values.temperatures[2] = 0; /* unused */ + hwm_values.fans[1] = 0; /* unused */ + hwm_values.fans[2] = 0; /* unused */ + /* -5V is not reported by the BIOS, but leave it set */ + return ret; } + int machine_at_tx97_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/tx97/0112.001", + ret = bios_load_linear("roms/machines/tx97/0112.001", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -754,56 +666,75 @@ machine_at_tx97_init(const machine_t *model) pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); device_add(&i430tx_device); device_add(&piix4_device); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_ami_pci_device); device_add(&w83877tf_acorp_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Chassis */ - 3000, /* CPU */ - 3000 /* Power */ - }, { /* temperatures */ - 30, /* MB */ - 0, /* unused */ - 8 /* CPU */ - }, { /* voltages */ - 3300, /* VCORE (3.3V by default) */ - 0, /* unused */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - /* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V). - Pentium MMX: 2.8 V. - AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233. - AMD K6 Model 7: 2.2 V. */ - switch (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) { - case CPU_PENTIUMMMX: - machine_hwm.voltages[0] = 2800; - break; - case CPU_K6: - case CPU_K6_2: - machine_hwm.voltages[0] = 2200; - break; - } - hwm_set_values(machine_hwm); - device_add(&w83781d_device); + device_add(&w83781d_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ + hwm_values.temperatures[1] = 0; /* unused */ + /* CPU offset */ + if (hwm_values.temperatures[2] < 32) /* prevent underflow */ + hwm_values.temperatures[2] = 0; + else + hwm_values.temperatures[2] -= 32; return ret; } +#if defined(DEV_BRANCH) && defined(USE_AN430TX) +int +machine_at_an430tx_init(const machine_t *model) +{ + int ret; + +#if 1 + ret = bios_load_linear_combined2("roms/machines/an430tx/P10-0095.BIO", + "roms/machines/an430tx/P10-0095.BI1", + "roms/machines/an430tx/P10-0095.BI2", + "roms/machines/an430tx/P10-0095.BI3", + "roms/machines/an430tx/P10-0095.RCV", + 0x3a000, 160); +#else + ret = bios_load_linear_combined2("roms/machines/an430tx/P06-0062.BIO", + "roms/machines/an430tx/P06-0062.BI1", + "roms/machines/an430tx/P06-0062.BI2", + "roms/machines/an430tx/P06-0062.BI3", + "roms/machines/an430tx/P10-0095.RCV", + 0x3a000, 160); +#endif + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ + // pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&i430tx_device); + device_add(&piix4_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87307_both_device); + device_add(&intel_flash_bxt_ami_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} +#endif + + int machine_at_ym430tx_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ym430tx/YM430TX.003", + ret = bios_load_linear("roms/machines/ym430tx/YM430TX.003", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -836,7 +767,7 @@ machine_at_mb540n_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/mb540n/Tx0720ug.bin", + ret = bios_load_linear("roms/machines/mb540n/Tx0720ug.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -861,13 +792,43 @@ machine_at_mb540n_init(const machine_t *model) return ret; } +int +machine_at_56a5_init(const machine_t* model) +{ + int ret; + + ret = bios_load_linear("roms/machines/56a5/54p5b6b.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ + pci_register_slot(0x10, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i430tx_device); + device_add(&piix4_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} int machine_at_p5mms98_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/p5mms98/s981182.rom", + ret = bios_load_linear("roms/machines/p5mms98/s981182.rom", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -888,41 +849,8 @@ machine_at_p5mms98_init(const machine_t *model) device_add(&w83977tf_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); - - hwm_values_t machine_hwm = { - { /* fan speeds */ - 3000, /* Thermal */ - 3000, /* CPU */ - 3000 /* Chassis */ - }, { /* temperatures */ - 0, /* unused */ - 30 /* CPU */ - }, { /* voltages */ - 3300, /* VCORE (3.3V by default) */ - 3300, /* VIO (3.3V) */ - 3300, /* +3.3V */ - RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */ - RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */ - RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */ - RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */ - } - }; - /* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V). - Pentium MMX: 2.8 V. - AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233. - AMD K6 Model 7: 2.2 V. */ - switch (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) { - case CPU_PENTIUMMMX: - machine_hwm.voltages[0] = 2800; - break; - case CPU_K6: - case CPU_K6_2: - machine_hwm.voltages[0] = 2200; - break; - } - hwm_set_values(machine_hwm); - device_add(&lm78_device); - device_add(&lm75_1_4a_device); + device_add(&lm78_device); /* fans: Thermal, CPU, Chassis; temperature: unused */ + device_add(&lm75_1_4a_device); /* temperature: CPU */ return ret; } @@ -933,7 +861,7 @@ machine_at_ficva502_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ficva502/VA502bp.BIN", + ret = bios_load_linear("roms/machines/ficva502/VA502bp.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -951,8 +879,9 @@ machine_at_ficva502_init(const machine_t *model) device_add(&via_vpx_device); device_add(&via_vt82c586b_device); device_add(&keyboard_ps2_pci_device); - device_add(&fdc37c669_device); + device_add(&fdc37c669_370_device); device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); return ret; } @@ -963,7 +892,7 @@ machine_at_ficpa2012_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ficpa2012/113jb16.awd", + ret = bios_load_linear("roms/machines/ficpa2012/113jb16.awd", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -973,16 +902,145 @@ machine_at_ficpa2012_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_vp3_device); device_add(&via_vt82c586b_device); device_add(&keyboard_ps2_pci_device); device_add(&w83877f_device); - device_add(&sst_flash_39sf010_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + + +int +machine_at_r534f_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/r534f/r534f008.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&sis_5571_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_ms5146_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms5146/A546MS11.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&sis_5571_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_m560_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m560/5600410s.ami", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&ali1531_device); + device_add(&ali1543_device); /* -5 */ + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + + return ret; +} + + +int +machine_at_ms5164_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms5164/W564MS43.005", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_SOUTHBRIDGE_IDE, 5, 6, 0, 0); + pci_register_slot(0x0C, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&ali1531_device); + device_add(&ali1543_device); /* -5 */ + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); return ret; } diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c new file mode 100644 index 000000000..c63d02347 --- /dev/null +++ b/src/machine/m_at_socket7_3v.c @@ -0,0 +1,556 @@ +/* + * 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 Socket 7 (Single Voltage) machines. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * + * Copyright 2010-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/io.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/keyboard.h> +#include <86box/flash.h> +#include <86box/sio.h> +#include <86box/hwm.h> +#include <86box/video.h> +#include <86box/spd.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/nvr.h> + + +static void +machine_at_thor_common_init(const machine_t *model, int mr) +{ + machine_at_common_init_ex(model, mr); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64vplus_onboard_pci_device); + + // device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); +} + + +static void +machine_at_p54tp4xe_common_init(const machine_t *model) +{ + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); +} + + +int +machine_at_p54tp4xe_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p54tp4xe/t15i0302.awd", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_p54tp4xe_common_init(model); + + return ret; +} + + +int +machine_at_p54tp4xe_mr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p54tp4xe/TRITON.BIO", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_p54tp4xe_common_init(model); + + return ret; +} + + +int +machine_at_gw2katx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/gw2katx/1003CN0T.BIO", + "roms/machines/gw2katx/1003CN0T.BI1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 0); + + return ret; +} + + +int +machine_at_thor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/thor/1006cn0_.bio", + "roms/machines/thor/1006cn0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 0); + + return ret; +} + +int +machine_at_mrthor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mrthor/mr_atx.bio", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 1); + + return ret; +} + + +int +machine_at_endeavor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/endeavor/1006cb0_.bio", + "roms/machines/endeavor/1006cb0_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); + + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + +int +machine_at_ms5119_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ms5119/A37E.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0d, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0e, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0f, PCI_CARD_NORMAL, 3, 4, 1, 2); + + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83787f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_pb640_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/pb640/1007CP0R.BIO", + "roms/machines/pb640/1007CP0R.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430fx_rev02_device); + device_add(&piix_rev02_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5440_onboard_pci_device); + + device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + +int +machine_at_fmb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/fmb/P5IV183.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 3, 2, 1); + + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83787f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_acerm3a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/acerm3a/r01-b3.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_ap53_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ap53/ap53r2c0.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_VIDEO, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_8500tuc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/8500tuc/Tuc0221b.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55t2s_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p55t2s/s6y08t.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p5vxb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p5vxb/P5VXB10.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x05, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x06, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x08, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877f_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_gw2kte_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2("roms/machines/gw2kte/1008CY1T.BIO", + "roms/machines/gw2kte/1008CY1T.BI1", + "roms/machines/gw2kte/1008CY1T.BI2", + "roms/machines/gw2kte/1008CY1T.BI3", + "roms/machines/gw2kte/1008CY1T.RCV", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c932fr_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_ap5s_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ap5s/AP5S150.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 3, 2, 1); + + device_add(&sis_5511_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} + + +int +machine_at_vectra54_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/vectra54/GT0724.22", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_VIDEO, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x08, PCI_CARD_NORMAL, 3, 4, 1, 2); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c931apm_device); + device_add(&sst_flash_29ee010_device); + + return ret; +} diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 95dfa2e14..00545eff9 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -29,22 +29,58 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/keyboard.h> -#include <86box/intel_flash.h> -#include <86box/sst_flash.h> +#include <86box/flash.h> +#include <86box/timer.h> +#include <86box/nvr.h> #include <86box/sio.h> -#include <86box/sst_flash.h> #include <86box/hwm.h> #include <86box/spd.h> #include <86box/video.h> #include "cpu.h" #include <86box/machine.h> + +int +machine_at_p6rp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p6rp4/OR6I0106.SMC", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + device_add(&p6rp4_nvr_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x19, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_AGPBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x06, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x04, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&i450kx_device); + device_add(&sio_zb_device); + device_add(&ide_cmd646_device); + /* Input port bit 2 must be 1 or CMOS Setup is disabled. */ + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + int machine_at_686nx_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/686nx/6nx.140", + ret = bios_load_linear("roms/machines/686nx/6nx.140", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -74,7 +110,7 @@ machine_at_mb600n_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/mb600n/60915cs.rom", + ret = bios_load_linear("roms/machines/mb600n/60915cs.rom", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -85,7 +121,7 @@ machine_at_mb600n_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); @@ -99,11 +135,11 @@ machine_at_mb600n_init(const machine_t *model) } int -machine_at_v60n_init(const machine_t *model) +machine_at_acerv60n_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/v60n/V60NE5.BIN", + ret = bios_load_linear("roms/machines/acerv60n/V60NE5.BIN", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -123,7 +159,6 @@ machine_at_v60n_init(const machine_t *model) device_add(&piix3_device); device_add(&keyboard_ps2_pci_device); device_add(&fdc37c935_device); - device_add(&acerm3a_device); device_add(&sst_flash_29ee010_device); return ret; @@ -134,11 +169,11 @@ machine_at_vs440fx_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined2(L"roms/machines/vs440fx/1018CS1_.bio", - L"roms/machines/vs440fx/1018CS1_.bi1", - L"roms/machines/vs440fx/1018CS1_.bi2", - L"roms/machines/vs440fx/1018CS1_.bi3", - L"roms/machines/vs440fx/1018CS1_.rcv", + ret = bios_load_linear_combined2("roms/machines/vs440fx/1018CS1_.BIO", + "roms/machines/vs440fx/1018CS1_.BI1", + "roms/machines/vs440fx/1018CS1_.BI2", + "roms/machines/vs440fx/1018CS1_.BI3", + "roms/machines/vs440fx/1018CS1_.RCV", 0x3a000, 128); if (bios_only || !ret) @@ -163,50 +198,16 @@ machine_at_vs440fx_init(const machine_t *model) return ret; } -int -machine_at_gw2kvs_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined2(L"roms/machines/gw2kvs/1011CS1T.bio", - L"roms/machines/gw2kvs/1011CS1T.bi1", - L"roms/machines/gw2kvs/1011CS1T.bi2", - L"roms/machines/gw2kvs/1011CS1T.bi3", - L"roms/machines/gw2kvs/1011CS1T.rcv", - 0x3a000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i440fx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&pc87307_device); - - device_add(&intel_flash_bxt_ami_device); - - return ret; -} - int machine_at_ap440fx_init(const machine_t *model) { int ret; - ret = bios_load_linear_combined2(L"roms/machines/ap440fx/1011CT1_.bio", - L"roms/machines/ap440fx/1011CT1_.bi1", - L"roms/machines/ap440fx/1011CT1_.bi2", - L"roms/machines/ap440fx/1011CT1_.bi3", - L"roms/machines/ap440fx/1011CT1_.rcv", + ret = bios_load_linear_combined2("roms/machines/ap440fx/1011CT1_.BIO", + "roms/machines/ap440fx/1011CT1_.BI1", + "roms/machines/ap440fx/1011CT1_.BI2", + "roms/machines/ap440fx/1011CT1_.BI3", + "roms/machines/ap440fx/1011CT1_.RCV", 0x3a000, 128); if (bios_only || !ret) @@ -216,7 +217,7 @@ machine_at_ap440fx_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 3, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 3, 0, 0, 0); pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 3, 2, 4); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); @@ -231,11 +232,11 @@ machine_at_ap440fx_init(const machine_t *model) } int -machine_at_8500ttc_init(const machine_t *model) +machine_at_8600ttc_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/8500ttc/TTC0715B.ROM", + ret = bios_load_linear("roms/machines/8600ttc/TTC0715B.ROM", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -246,7 +247,7 @@ machine_at_8500ttc_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); @@ -264,7 +265,7 @@ machine_at_m6mi_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/m6mi/M6MI05.ROM", + ret = bios_load_linear("roms/machines/m6mi/M6MI05.ROM", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -275,7 +276,7 @@ machine_at_m6mi_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); @@ -302,10 +303,10 @@ machine_at_p65up5_common_init(const machine_t *model, const device_t *northbridg pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(northbridge); - device_add(&piix3_device); + device_add(&piix3_ioapic_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&w83877f_device); - device_add(&intel_flash_bxt_device); + device_add(&sst_flash_29ee010_device); device_add(&ioapic_device); } @@ -314,7 +315,7 @@ machine_at_p65up5_cp6nd_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/p65up5/nd6i0218.awd", + ret = bios_load_linear("roms/machines/p65up5/ND6I0218.AWD", 0x000e0000, 131072, 0); if (bios_only || !ret) diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index ebaaa49ee..a32bf3883 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -33,21 +33,24 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/keyboard.h> -#include <86box/intel_flash.h> +#include <86box/flash.h> #include <86box/sio.h> -#include <86box/sst_flash.h> #include <86box/spd.h> #include <86box/hwm.h> #include <86box/video.h> #include "cpu.h" #include <86box/machine.h> +#include <86box/sound.h> +#include <86box/snd_ac97.h> +#include <86box/clock.h> + int -machine_at_ax59pro_init(const machine_t *model) +machine_at_p5a_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ax59pro/AX59P236.BIN", + ret = bios_load_linear("roms/machines/p5a/1011.005", 0x000c0000, 262144, 0); if (bios_only || !ret) @@ -57,18 +60,153 @@ machine_at_ax59pro_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1541_device); + device_add(&ali1543c_device); /* +0 */ + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + device_add(&w83781d_p5a_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */ + + return ret; +} + + +int +machine_at_m579_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m579/MS6260S_Socket7_ALi_M1542_AMI.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&ali1541_device); + device_add(&ali1543c_device); /* +0 */ + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + + +int +machine_at_5aa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/5aa/GA-5AA.F7b", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + device_add(&ali1541_device); + device_add(&ali1543c_device); /* +0 */ + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + + +int +machine_at_5ax_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/5ax/5AX.F4", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4); + pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&ali1541_device); + device_add(&ali1543c_device); /* +0 */ + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + + +int +machine_at_ax59pro_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ax59pro/AX59P236.BIN", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 0, 0); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_mvp3_device); device_add(&via_vt82c586b_device); device_add(&keyboard_ps2_pci_device); device_add(&w83877tf_device); device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0xF, 256); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); return ret; } @@ -79,7 +217,7 @@ machine_at_mvp3_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ficva503p/je4333.bin", + ret = bios_load_linear("roms/machines/ficva503p/je4333.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -89,16 +227,93 @@ machine_at_mvp3_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0a, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x01, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&via_mvp3_device); device_add(&via_vt82c586b_device); device_add(&keyboard_ps2_pci_device); device_add(&w83877tf_device); device_add(&sst_flash_39sf010_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + + return ret; +} + + +int +machine_at_ficva503a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ficva503a/jn4116.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + device_add(&via_mvp3_device); + device_add(&via_vt82c686a_device); /* fans: CPU1, Chassis; temperatures: CPU, System, unused */ + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + hwm_values.temperatures[0] += 2; /* CPU offset */ + hwm_values.temperatures[1] += 2; /* System offset */ + hwm_values.temperatures[2] = 0; /* unused */ + + if (sound_card_current == SOUND_INTERNAL) + device_add(&wm9701a_device); /* on daughtercard */ + + return ret; +} + + +int +machine_at_5emapro_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/5emapro/5emo1aa2.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + device_add(&via_mvp3_device); /* Rebranded as EQ82C6638 */ + device_add(&via_vt82c686a_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sst_flash_39sf010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + device_add(&via_vt82c686_hwm_device); /* fans: CPU1, Chassis; temperatures: CPU, System, unused */ + hwm_values.temperatures[0] += 2; /* CPU offset */ + hwm_values.temperatures[1] += 2; /* System offset */ + hwm_values.temperatures[2] = 0; /* unused */ return ret; } diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index a5a7b9903..afeea0a57 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -15,7 +15,7 @@ * * Memory management * ~~~~~~~~~~~~~~~~~ - * + * * Motherboard memory is divided into: * - Conventional memory: Either 512k or 640k * - Upper memory: Either 512k or 384k, depending on @@ -25,7 +25,7 @@ * The BIOS setup screen allows some or * all of this to be used as EMS; the * remainder is XMS. - * + * * Additional memory (either EMS or XMS) can also be provided * by ISA expansion cards. * @@ -40,7 +40,7 @@ * Bit 6: Always 1 } These bits select which motherboard * Bit 5: Always 0 } function to access. * Bit 4: Set to treat upper RAM as XMS - * Bit 3: Enable external RAM boards? + * Bit 3: Enable external RAM boards? * Bit 2: Set for 640k conventional memory, clear for 512k * Bit 1: Enable RAM beyond 1Mb. * Bit 0: Enable EMS. @@ -69,7 +69,7 @@ * OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000. * OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000. * etc. - * + * * To use EMS from DOS, you will need the Toshiba EMS driver * (TOSHEMM.ZIP). This supports the above system, plus further * ranges of ports at 0x_2A8, 0x_2B8, 0x_2C8. @@ -104,7 +104,7 @@ * 01 0 => 3, 4, 5 * 01 1 => 3, 5, 4 * 10 0 => 4, -, 3 - * 10 1 => 3, -, 4 + * 10 1 => 3, -, 4 * 010 => set memory mappings * bit 4 set if upper RAM is XMS * bit 3 enable add-on memory boards beyond 5Mb? @@ -163,6 +163,7 @@ #include "cpu.h" #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/fdc_ext.h> #include <86box/machine.h> #include <86box/m_at_t3100e.h> @@ -236,7 +237,7 @@ t3100e_log(const char *fmt, ...) #endif -/* Given a memory address (which ought to be in the page frame at 0xD0000), +/* Given a memory address (which ought to be in the page frame at 0xD0000), * which page does it relate to? */ static int addr_to_page(uint32_t addr) { @@ -247,7 +248,7 @@ static int addr_to_page(uint32_t addr) return -1; } -/* And vice versa: Given a page slot, which memory address does it +/* And vice versa: Given a page slot, which memory address does it * correspond to? */ static uint32_t page_to_addr(int pg) { @@ -255,7 +256,7 @@ static uint32_t page_to_addr(int pg) } /* Given an EMS page ID, return its physical address in RAM. */ -uint32_t t3100e_ems_execaddr(struct t3100e_ems_regs *regs, +uint32_t t3100e_ems_execaddr(struct t3100e_ems_regs *regs, int pg, uint16_t val) { uint32_t addr; @@ -295,14 +296,14 @@ static int port_to_page(uint16_t addr) { switch (addr) { - case 0x208: return 0; - case 0x4208: return 1; - case 0x8208: return 2; - case 0xC208: return 3; - case 0x218: return 4; - case 0x4218: return 5; - case 0x8218: return 6; - case 0xC218: return 7; + case 0x208: return 0; + case 0x4208: return 1; + case 0x8208: return 2; + case 0xC208: return 3; + case 0x218: return 4; + case 0x4218: return 5; + case 0x8218: return 6; + case 0xC218: return 7; case 0x258: return 8; case 0x4258: return 9; case 0x8258: return 10; @@ -330,12 +331,12 @@ void dump_mappings() if (mm == &ram_mid_mapping ) name = "MID "; if (mm == &ram_high_mapping) name = "HIGH"; if (mm == &t3100e_ems.upper_mapping) name = "UPPR"; - if (mm == &t3100e_ems.mapping[0]) + if (mm == &t3100e_ems.mapping[0]) { name = "EMS0"; offset = t3100e_ems.page_exec[0]; } - if (mm == &t3100e_ems.mapping[1]) + if (mm == &t3100e_ems.mapping[1]) { name = "EMS1"; offset = t3100e_ems.page_exec[1]; @@ -345,14 +346,14 @@ void dump_mappings() name = "EMS2"; offset = t3100e_ems.page_exec[2]; } - if (mm == &t3100e_ems.mapping[3]) + if (mm == &t3100e_ems.mapping[3]) { name = "EMS3"; offset = t3100e_ems.page_exec[3]; } - t3100e_log(" %p | base=%05x size=%05x %c @ %06x %s\n", mm, - mm->base, mm->size, mm->enable ? 'Y' : 'N', + t3100e_log(" %p | base=%05x size=%05x %c @ %06x %s\n", mm, + mm->base, mm->size, mm->enable ? 'Y' : 'N', offset, name); mm = mm->next; @@ -364,21 +365,23 @@ void t3100e_map_ram(uint8_t val) int n; int32_t upper_len; - t3100e_log("OUT 0x8084, %02x [ set memory mapping :", val | 0x40); +#ifdef ENABLE_T3100E_LOG + t3100e_log("OUT 0x8084, %02x [ set memory mapping :", val | 0x40); if (val & 1) t3100e_log("ENABLE_EMS "); if (val & 2) t3100e_log("ENABLE_XMS "); if (val & 4) t3100e_log("640K "); if (val & 8) t3100e_log("X8X "); if (val & 16) t3100e_log("UPPER_IS_XMS "); t3100e_log("\n"); +#endif /* Bit 2 controls size of conventional memory */ - if (val & 4) + if (val & 4) { t3100e_ems.upper_base = 0xA0000; t3100e_ems.upper_pages = 24; } - else + else { t3100e_ems.upper_base = 0x80000; t3100e_ems.upper_pages = 32; @@ -399,7 +402,7 @@ void t3100e_map_ram(uint8_t val) mem_mapping_disable(&ram_high_mapping); } - /* Bit 4 set if upper RAM is mapped to high memory + /* Bit 4 set if upper RAM is mapped to high memory * (and bit 1 set if XMS enabled) */ if ((val & 0x12) == 0x12) { @@ -416,7 +419,7 @@ void t3100e_map_ram(uint8_t val) /* Recalculate EMS mappings */ for (n = 0; n < 4; n++) { - t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n], + t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n], &t3100e_ems); } @@ -458,7 +461,7 @@ uint8_t t3100e_sys_in(uint16_t addr, void *p) { struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - /* The low 4 bits always seem to be 0x0C. The high 4 are a + /* The low 4 bits always seem to be 0x0C. The high 4 are a * notification sent by the keyboard controller when it detects * an [Fn] key combination */ t3100e_log("IN 0x8084\n"); @@ -475,10 +478,10 @@ void t3100e_sys_out(uint16_t addr, uint8_t val, void *p) switch (val & 0xE0) { case 0x00: /* Set serial port IRQs. Not implemented */ - t3100e_log("OUT 0x8084, %02x [ set serial port IRQs]\n", val); + t3100e_log("OUT 0x8084, %02x [ set serial port IRQs]\n", val); break; case 0x40: /* Set RAM mappings. */ - t3100e_map_ram(val & 0x1F); + t3100e_map_ram(val & 0x1F); break; case 0x80: /* Set video options. */ @@ -518,7 +521,7 @@ uint8_t t3100e_config_get(void) prt_switch = (type_b ? 2 : 0); switch(type_a) { -/* Since a T3100e cannot have an internal 5.25" drive, mark 5.25" A: drive as +/* Since a T3100e cannot have an internal 5.25" drive, mark 5.25" A: drive as * being external, and set the internal type based on type_b. */ case 1: /* 360k */ case 2: /* 1.2Mb */ @@ -533,7 +536,7 @@ uint8_t t3100e_config_get(void) } break; case 4: value |= 0x01; /* 720k */ - if (type_a == type_b) + if (type_a == type_b) { value &= (~8); /* Two internal drives */ prt_switch = 0; /* No external drive */ @@ -541,7 +544,7 @@ uint8_t t3100e_config_get(void) break; case 5: /* 1.4M */ case 7: /* 2.8M */ - if (type_a == type_b) + if (type_a == type_b) { value &= (~8); /* Two internal drives */ prt_switch = 0; /* No external drive */ @@ -549,7 +552,7 @@ uint8_t t3100e_config_get(void) break; case 6: /* 3-mode */ value |= 0x10; - if (type_a == type_b) + if (type_a == type_b) { value &= (~8); /* Two internal drives */ prt_switch = 0; /* No external drive */ @@ -570,7 +573,7 @@ uint8_t t3100e_config_get(void) uint8_t t3100e_ems_in(uint16_t addr, void *p) { struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - + int page = port_to_page(addr); if (page >= 0) return regs->page[page]; @@ -620,7 +623,7 @@ static uint8_t ems_read_ram(uint32_t addr, void *priv) if (pg < 0) return 0xFF; addr = regs->page_exec[pg] + (addr & 0x3FFF); - return ram[addr]; + return ram[addr]; } @@ -631,11 +634,11 @@ static uint16_t ems_read_ramw(uint32_t addr, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; int pg = addr_to_page(addr); - if (pg < 0) return 0xFF; + if (pg < 0) return 0xFFFF; //t3100e_log("ems_read_ramw addr=%05x ", addr); addr = regs->page_exec[pg] + (addr & 0x3FFF); - //t3100e_log("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); - return *(uint16_t *)&ram[addr]; + //t3100e_log("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); + return *(uint16_t *)&ram[addr]; } @@ -644,9 +647,9 @@ static uint32_t ems_read_raml(uint32_t addr, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; int pg = addr_to_page(addr); - if (pg < 0) return 0xFF; + if (pg < 0) return 0xFFFFFFFF; addr = regs->page_exec[pg] + (addr & 0x3FFF); - return *(uint32_t *)&ram[addr]; + return *(uint32_t *)&ram[addr]; } /* Write RAM in the EMS page frame */ @@ -657,7 +660,7 @@ static void ems_write_ram(uint32_t addr, uint8_t val, void *priv) if (pg < 0) return; addr = regs->page_exec[pg] + (addr & 0x3FFF); - ram[addr] = val; + ram[addr] = val; } @@ -671,7 +674,7 @@ static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv) addr = regs->page_exec[pg] + (addr & 0x3FFF); //t3100e_log("-> %06x val=%04x\n", addr, val); - *(uint16_t *)&ram[addr] = val; + *(uint16_t *)&ram[addr] = val; } @@ -682,19 +685,19 @@ static void ems_write_raml(uint32_t addr, uint32_t val, void *priv) if (pg < 0) return; addr = regs->page_exec[pg] + (addr & 0x3FFF); - *(uint32_t *)&ram[addr] = val; + *(uint32_t *)&ram[addr] = val; } -/* Read RAM in the upper area. This is basically what the 'remapped' +/* Read RAM in the upper area. This is basically what the 'remapped' * mapping in mem.c does, except that the upper area can move around */ static uint8_t upper_read_ram(uint32_t addr, void *priv) { struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; addr = (addr - (1024 * mem_size)) + regs->upper_base; - return ram[addr]; + return ram[addr]; } static uint16_t upper_read_ramw(uint32_t addr, void *priv) @@ -702,7 +705,7 @@ static uint16_t upper_read_ramw(uint32_t addr, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; addr = (addr - (1024 * mem_size)) + regs->upper_base; - return *(uint16_t *)&ram[addr]; + return *(uint16_t *)&ram[addr]; } static uint32_t upper_read_raml(uint32_t addr, void *priv) @@ -710,7 +713,7 @@ static uint32_t upper_read_raml(uint32_t addr, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; addr = (addr - (1024 * mem_size)) + regs->upper_base; - return *(uint32_t *)&ram[addr]; + return *(uint32_t *)&ram[addr]; } @@ -719,7 +722,7 @@ static void upper_write_ram(uint32_t addr, uint8_t val, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; addr = (addr - (1024 * mem_size)) + regs->upper_base; - ram[addr] = val; + ram[addr] = val; } @@ -728,7 +731,7 @@ static void upper_write_ramw(uint32_t addr, uint16_t val, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; addr = (addr - (1024 * mem_size)) + regs->upper_base; - *(uint16_t *)&ram[addr] = val; + *(uint16_t *)&ram[addr] = val; } @@ -738,7 +741,7 @@ static void upper_write_raml(uint32_t addr, uint32_t val, void *priv) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; addr = (addr - (1024 * mem_size)) + regs->upper_base; - *(uint32_t *)&ram[addr] = val; + *(uint32_t *)&ram[addr] = val; } @@ -748,7 +751,7 @@ int machine_at_t3100e_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/t3100e/t3100e.rom", + ret = bios_load_linear("roms/machines/t3100e/t3100e.rom", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -757,34 +760,38 @@ int machine_at_t3100e_init(const machine_t *model) int pg; memset(&t3100e_ems, 0, sizeof(t3100e_ems)); - + machine_at_common_ide_init(model); device_add(&keyboard_at_toshiba_device); + + if (fdc_type == FDC_INTERNAL) + { device_add(&fdc_at_device); + } /* Hook up system control port */ - io_sethandler(0x8084, 0x0001, + io_sethandler(0x8084, 0x0001, t3100e_sys_in, NULL, NULL, t3100e_sys_out, NULL, NULL, &t3100e_ems); /* Start monitoring all 16 EMS registers */ - for (pg = 0; pg < 16; pg++) + for (pg = 0; pg < 16; pg++) { - io_sethandler(t3100e_ems_page_reg[pg], 0x0001, + io_sethandler(t3100e_ems_page_reg[pg], 0x0001, t3100e_ems_in, NULL, NULL, - t3100e_ems_out, NULL, NULL, &t3100e_ems); + t3100e_ems_out, NULL, NULL, &t3100e_ems); } /* Map the EMS page frame */ for (pg = 0; pg < 4; pg++) { t3100e_log("Adding memory map at %x for page %d\n", page_to_addr(pg), pg); - mem_mapping_add(&t3100e_ems.mapping[pg], - page_to_addr(pg), 16384, + mem_mapping_add(&t3100e_ems.mapping[pg], + page_to_addr(pg), 16384, ems_read_ram, ems_read_ramw, ems_read_raml, ems_write_ram, ems_write_ramw, ems_write_raml, - NULL, MEM_MAPPING_EXTERNAL, + NULL, MEM_MAPPING_EXTERNAL, &t3100e_ems); /* Start them all off disabled */ mem_mapping_disable(&t3100e_ems.mapping[pg]); diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c index ecfef4437..88aaabdec 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/machine/m_at_t3100e_vid.c @@ -14,7 +14,7 @@ * Selecting a character height of 3 seems to be sufficient to * convert the 640x200 graphics mode to 640x400 (and, by * analogy, 320x200 to 320x400). - * + * * Horiz-----> Vert------> I ch * 38 28 2D 0A 1F 06 19 1C 02 07 06 07 CO40 * 71 50 5A 0A 1F 06 19 1C 02 07 06 07 CO80 @@ -86,7 +86,7 @@ static uint32_t normcols[256][2]; * * Bit 3: Disable built-in video (for add-on card) * Bit 2: Thin font - * Bits 0,1: Font set (not currently implemented) + * Bits 0,1: Font set (not currently implemented) */ static uint8_t st_video_options; static int8_t st_display_internal = -1; @@ -111,7 +111,7 @@ typedef struct t3100e_t { mem_mapping_t mapping; - cga_t cga; /* The CGA is used for the external + cga_t cga; /* The CGA is used for the external * display; most of its registers are * ignored by the plasma display. */ @@ -121,7 +121,7 @@ typedef struct t3100e_t uint8_t attrmap; /* Attribute mapping register */ uint64_t dispontime, dispofftime; - + int linepos, displine; int vc; int dispon; @@ -154,12 +154,12 @@ void t3100e_out(uint16_t addr, uint8_t val, void *p) case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: /* Register 0x12 controls the attribute mappings for the * plasma screen. */ - if (t3100e->cga.crtcreg == 0x12) + if (t3100e->cga.crtcreg == 0x12) { - t3100e->attrmap = val; + t3100e->attrmap = val; t3100e_recalcattrs(t3100e); return; - } + } cga_out(addr, val, &t3100e->cga); t3100e_recalctimings(t3100e); @@ -191,7 +191,7 @@ uint8_t t3100e_in(uint16_t addr, void *p) return val; } } - + return cga_in(addr, &t3100e->cga); } @@ -201,19 +201,17 @@ uint8_t t3100e_in(uint16_t addr, void *p) void t3100e_write(uint32_t addr, uint8_t val, void *p) { t3100e_t *t3100e = (t3100e_t *)p; - egawrites++; t3100e->vram[addr & 0x7fff] = val; - sub_cycles(4); + cycles -= 4; } - + uint8_t t3100e_read(uint32_t addr, void *p) { t3100e_t *t3100e = (t3100e_t *)p; - egareads++; - sub_cycles(4); + cycles -= 4; return t3100e->vram[addr & 0x7fff]; } @@ -284,8 +282,8 @@ void t3100e_text_row80(t3100e_t *t3100e) if (t3100e->cga.cgamode & 0x20) /* Blink */ { - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; if (blink) cols[1] = cols[0]; } else @@ -354,8 +352,8 @@ void t3100e_text_row40(t3100e_t *t3100e) if (t3100e->cga.cgamode & 0x20) /* Blink */ { - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; if (blink) cols[1] = cols[0]; } else @@ -367,7 +365,7 @@ void t3100e_text_row40(t3100e_t *t3100e) { for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); } } @@ -375,7 +373,7 @@ void t3100e_text_row40(t3100e_t *t3100e) { for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2+1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; } } @@ -463,7 +461,7 @@ void t3100e_cgaline4(t3100e_t *t3100e) switch (pattern & 3) { case 0: ink0 = ink1 = black; break; - case 1: if (t3100e->displine & 1) + case 1: if (t3100e->displine & 1) { ink0 = black; ink1 = black; } @@ -472,7 +470,7 @@ void t3100e_cgaline4(t3100e_t *t3100e) ink0 = amber; ink1 = black; } break; - case 2: if (t3100e->displine & 1) + case 2: if (t3100e->displine & 1) { ink0 = black; ink1 = amber; } @@ -539,20 +537,20 @@ void t3100e_poll(void *p) } /* Graphics */ - if (t3100e->cga.cgamode & 0x02) + if (t3100e->cga.cgamode & 0x02) { if (t3100e->cga.cgamode & 0x10) t3100e_cgaline6(t3100e); else t3100e_cgaline4(t3100e); } - else + else if (t3100e->cga.cgamode & 0x01) /* High-res text */ { - t3100e_text_row80(t3100e); + t3100e_text_row80(t3100e); } else { - t3100e_text_row40(t3100e); + t3100e_text_row40(t3100e); } } t3100e->displine++; @@ -592,14 +590,14 @@ void t3100e_poll(void *p) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + video_blit_memtoscreen(0, 0, xsize, ysize); frames++; /* Fixed 640x400 resolution */ video_res_x = T3100E_XSIZE; video_res_y = T3100E_YSIZE; - if (t3100e->cga.cgamode & 0x02) + if (t3100e->cga.cgamode & 0x02) { if (t3100e->cga.cgamode & 0x10) video_bpp = 1; @@ -619,10 +617,10 @@ void t3100e_recalcattrs(t3100e_t *t3100e) int n; /* val behaves as follows: - * Bit 0: Attributes 01-06, 08-0E are inverse video - * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are inverse video + * are inverse video * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF * are bold */ @@ -635,12 +633,12 @@ void t3100e_recalcattrs(t3100e_t *t3100e) for (n = 0; n < 256; n++) { boldcols[n] = (n & 8) != 0; - blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][0] = normcols[n][0] = amber; blinkcols[n][1] = normcols[n][1] = black; } - /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the - * passed value. Exclude x0 and x8, which are always black on + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always black on * amber. */ for (n = 0x11; n <= 0xFF; n++) { @@ -657,7 +655,7 @@ void t3100e_recalcattrs(t3100e_t *t3100e) } if (t3100e->attrmap & 8) boldcols[n] = 1; /* Bold */ } - /* Set up the 01-0E range, controlled by bits 0 and 1 of the + /* Set up the 01-0E range, controlled by bits 0 and 1 of the * passed value. When blinking is enabled this also affects 81-8E. */ for (n = 0x01; n <= 0x0E; n++) { @@ -678,7 +676,7 @@ void t3100e_recalcattrs(t3100e_t *t3100e) } if (t3100e->attrmap & 2) boldcols[n] = 1; } - /* Colours 07 and 0F are always amber on black. If blinking is + /* Colours 07 and 0F are always amber on black. If blinking is * enabled so are 87 and 8F. */ for (n = 0x07; n <= 0x0F; n += 8) { @@ -715,7 +713,7 @@ void *t3100e_init(const device_t *info) { t3100e_t *t3100e = malloc(sizeof(t3100e_t)); memset(t3100e, 0, sizeof(t3100e_t)); - loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5); + loadfont("roms/machines/t3100e/t3100e_font.bin", 5); cga_init(&t3100e->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t3100e); @@ -755,19 +753,20 @@ void t3100e_close(void *p) void t3100e_speed_changed(void *p) { t3100e_t *t3100e = (t3100e_t *)p; - + t3100e_recalctimings(t3100e); } -const device_t t3100e_device = -{ - "Toshiba T3100e", - 0, - 0, - t3100e_init, - t3100e_close, - NULL, - NULL, - t3100e_speed_changed, - NULL +const device_t t3100e_device = { + .name = "Toshiba T3100e", + .internal_name = "t3100e", + .flags = 0, + .local = 0, + .init = t3100e_init, + .close = t3100e_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = t3100e_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 1ce423ee7..905515225 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -23,7 +23,7 @@ * f000:db3e 0x8..0xc * f000:d7f8 * f000:db5f - * f000:e172 + * f000:e172 * f000:ecc5 801a video setup error * f000:d6c9 copyright output * f000:e1b7 @@ -58,7 +58,7 @@ * read low 4 nibble at jim 0xa * read low 4 nibble at jim 0xa * return first nibble<<4|second nibble in ah - * f000:f046 seldom compares ret + * f000:f046 seldom compares ret * f000:fe87 0 -> ds * * Memory: @@ -67,7 +67,7 @@ * 0000:046a: 00 jim 250 01 jim 350 * * WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK. - * + * * * * Author: Fred N. van Kempen, @@ -615,7 +615,7 @@ europc_boot(const device_t *info) mouse_bus_set_irq(sys->mouse, 2); /* Configure the port for (Bus Mouse Compatible) Mouse. */ b |= 0x01; - } else if (joystick_type != JOYSTICK_TYPE_NONE) + } else if (joystick_type) b |= 0x02; /* enable port as joysticks */ sys->nvr.regs[MRTC_CONF_C] = b; @@ -666,37 +666,38 @@ europc_close(void *priv) free(nvr->fn); } - static const device_config_t europc_config[] = { { - "js9", "JS9 Jumper (JIM)", CONFIG_INT, "", 0, - { - { - "Disabled (250h)", 0 - }, - { - "Enabled (350h)", 1 - }, - { - "" - } - }, + .name = "js9", + .description = "JS9 Jumper (JIM)", + .type = CONFIG_INT, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled (250h)", .value = 0 }, + { .description = "Enabled (350h)", .value = 1 }, + { .description = "" } + }, }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; - const device_t europc_device = { - "EuroPC System Board", - 0, 0, - europc_boot, europc_close, NULL, - NULL, NULL, NULL, - europc_config + .name = "EuroPC System Board", + .internal_name = "europc", + .flags = 0, + .local = 0, + .init = europc_boot, + .close = europc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = europc_config }; - /* * This function sets up the Scheider EuroPC machine. * @@ -710,14 +711,14 @@ machine_europc_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/europc/50145", + ret = bios_load_linear("roms/machines/europc/50145", 0x000f8000, 32768, 0); if (bios_only || !ret) return ret; machine_common_init(model); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); nmi_init(); diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c deleted file mode 100644 index 8d8c94229..000000000 --- a/src/machine/m_olivetti_m24.c +++ /dev/null @@ -1,904 +0,0 @@ -/* - * 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 the Olivetti M24. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/timer.h> -#include <86box/io.h> -#include <86box/pic.h> -#include <86box/pit.h> -#include <86box/ppi.h> -#include <86box/nmi.h> -#include <86box/mem.h> -#include <86box/device.h> -#include <86box/nvr.h> -#include <86box/keyboard.h> -#include <86box/mouse.h> -#include <86box/rom.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/gameport.h> -#include <86box/sound.h> -#include <86box/snd_speaker.h> -#include <86box/video.h> -#include <86box/machine.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 - - -typedef struct { - /* Video stuff. */ - mem_mapping_t mapping; - uint8_t crtc[32]; - int crtcreg; - uint8_t monitor_type, port_23c6; - uint8_t *vram; - uint8_t charbuffer[256]; - uint8_t ctrl; - uint32_t base; - uint8_t cgamode, cgacol; - uint8_t stat; - int linepos, displine; - int sc, vc; - int con, coff, cursoron, blink; - int vsynctime; - int vadj; - int lineff; - uint16_t ma, maback; - int dispon; - uint64_t dispontime, dispofftime; - pc_timer_t timer; - int firstline, lastline; - - /* Keyboard stuff. */ - int wantirq; - uint8_t command; - uint8_t status; - uint8_t out; - uint8_t output_port; - int param, - param_total; - uint8_t params[16]; - uint8_t scan[7]; - - /* Mouse stuff. */ - int mouse_mode; - int x, y, b; - pc_timer_t send_delay_timer; -} olim24_t; - -static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32}; - - -static uint8_t crtcmask[32] = { - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static uint8_t key_queue[16]; -static int key_queue_start = 0, - key_queue_end = 0; - - - -#ifdef ENABLE_M24VID_LOG -int m24vid_do_log = ENABLE_M24VID_LOG; - - -static void -m24_log(const char *fmt, ...) -{ - va_list ap; - - if (m24vid_do_log) { - va_start(ap, fmt); - vfprintf(stdlog, fmt, ap); - va_end(ap); - fflush(stdlog); - } -} -#else -#define m24_log(fmt, ...) -#endif - - -static void -recalc_timings(olim24_t *m24) -{ - double _dispontime, _dispofftime, disptime; - - if (m24->cgamode & 1) { - disptime = m24->crtc[0] + 1; - _dispontime = m24->crtc[1]; - } else { - disptime = (m24->crtc[0] + 1) << 1; - _dispontime = m24->crtc[1] << 1; - } - - _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST / 2; - _dispofftime *= CGACONST / 2; - m24->dispontime = (uint64_t)(_dispontime); - m24->dispofftime = (uint64_t)(_dispofftime); -} - - -static void -vid_out(uint16_t addr, uint8_t val, void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - uint8_t old; - - switch (addr) { - case 0x3d4: - m24->crtcreg = val & 31; - break; - - case 0x3d5: - old = m24->crtc[m24->crtcreg]; - m24->crtc[m24->crtcreg] = val & crtcmask[m24->crtcreg]; - if (old != val) { - if (m24->crtcreg < 0xe || m24->crtcreg > 0x10) { - fullchange = changeframecount; - recalc_timings(m24); - } - } - break; - - case 0x3d8: - m24->cgamode = val; - break; - - case 0x3d9: - m24->cgacol = val; - break; - - case 0x3de: - m24->ctrl = val; - m24->base = (val & 0x08) ? 0x4000 : 0; - break; - - case 0x13c6: - m24->monitor_type = val; - break; - - case 0x23c6: - m24->port_23c6 = val; - break; - } -} - - -static uint8_t -vid_in(uint16_t addr, void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - uint8_t ret = 0xff; - - switch (addr) { - case 0x3d4: - ret = m24->crtcreg; - break; - - case 0x3d5: - ret = m24->crtc[m24->crtcreg]; - break; - - case 0x3da: - ret = m24->stat; - break; - - case 0x13c6: - ret = m24->monitor_type; - break; - - case 0x23c6: - ret = m24->port_23c6; - break; - } - - return(ret); -} - - -static void -vid_write(uint32_t addr, uint8_t val, void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - int offset; - - m24->vram[addr & 0x7FFF]=val; - offset = ((timer_get_remaining_u64(&m24->timer) / CGACONST) * 4) & 0xfc; - m24->charbuffer[offset] = m24->vram[addr & 0x7fff]; - m24->charbuffer[offset | 1] = m24->vram[addr & 0x7fff]; -} - - -static uint8_t -vid_read(uint32_t addr, void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - - return(m24->vram[addr & 0x7FFF]); -} - - -static void -vid_poll(void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x, c, xs_temp, ys_temp; - int oldvc; - uint8_t chr, attr; - uint16_t dat, dat2; - int cols[4]; - int col; - int oldsc; - - if (!m24->linepos) { - timer_advance_u64(&m24->timer, m24->dispofftime); - m24->stat |= 1; - m24->linepos = 1; - oldsc = m24->sc; - if ((m24->crtc[8] & 3) == 3) - m24->sc = (m24->sc << 1) & 7; - if (m24->dispon) { - if (m24->displine < m24->firstline) { - m24->firstline = m24->displine; - } - m24->lastline = m24->displine; - for (c = 0; c < 8; c++) - { - if ((m24->cgamode & 0x12) == 0x12) { - ((uint32_t *)buffer32->line[m24->displine])[c] = 0; - if (m24->cgamode & 1) - ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = 0; - else - ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = 0; - } else { - ((uint32_t *)buffer32->line[m24->displine])[c] = (m24->cgacol & 15) + 16; - if (m24->cgamode & 1) - ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16; - else - ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; - } - } - if (m24->cgamode & 1) { - for (x = 0; x < m24->crtc[1]; x++) { - chr = m24->charbuffer[ x << 1]; - attr = m24->charbuffer[(x << 1) + 1]; - drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); - if (m24->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if ((m24->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - if (drawcursor) { - for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; - } else { - for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; - } - m24->ma++; - } - } else if (!(m24->cgamode & 2)) { - for (x = 0; x < m24->crtc[1]; x++) { - chr = m24->vram[((m24->ma << 1) & 0x3fff) + m24->base]; - attr = m24->vram[(((m24->ma << 1) + 1) & 0x3fff) + m24->base]; - drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); - if (m24->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if ((m24->blink & 16) && (attr & 0x80)) - cols[1] = cols[0]; - } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - m24->ma++; - if (drawcursor) { - for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; - } else { - for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; - } - } - } else if (!(m24->cgamode & 16)) { - cols[0] = (m24->cgacol & 15) | 16; - col = (m24->cgacol & 16) ? 24 : 16; - if (m24->cgamode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } else if (m24->cgacol & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; - } - for (x = 0; x < m24->crtc[1]; x++) { - dat = (m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + m24->base] << 8) | - m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base]; - m24->ma++; - for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; - dat <<= 2; - } - } - } else { - if (m24->ctrl & 1 || ((m24->monitor_type & 8) && (m24->port_23c6 & 1))) { - dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000); - cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16; - } else { - dat2 = (m24->sc & 1) * 0x2000; - cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16; - } - - for (x = 0; x < m24->crtc[1]; x++) { - dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1]; - m24->ma++; - for (c = 0; c < 16; c++) { - ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + c + 8] = cols[dat >> 15]; - dat <<= 1; - } - } - } - } else { - cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16; - if (m24->cgamode & 1) hline(buffer32, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); - else hline(buffer32, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); - } - - if (m24->cgamode & 1) - x = (m24->crtc[1] << 3) + 16; - else - x = (m24->crtc[1] << 4) + 16; - - m24->sc = oldsc; - if (m24->vc == m24->crtc[7] && !m24->sc) - m24->stat |= 8; - m24->displine++; - if (m24->displine >= 720) m24->displine = 0; - } else { - timer_advance_u64(&m24->timer, m24->dispontime); - if (m24->dispon) m24->stat &= ~1; - m24->linepos = 0; - m24->lineff ^= 1; - if (m24->lineff) { - m24->ma = m24->maback; - } else { - if (m24->vsynctime) { - m24->vsynctime--; - if (!m24->vsynctime) - m24->stat &= ~8; - } - if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1))) { - m24->con = 0; - m24->coff = 1; - } - if (m24->vadj) { - m24->sc++; - m24->sc &= 31; - m24->ma = m24->maback; - m24->vadj--; - if (!m24->vadj) { - m24->dispon = 1; - m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; - m24->sc = 0; - } - } else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1))) { - m24->maback = m24->ma; - m24->sc = 0; - oldvc = m24->vc; - m24->vc++; - m24->vc &= 127; - - if (m24->vc == m24->crtc[6]) - m24->dispon=0; - - if (oldvc == m24->crtc[4]) { - m24->vc = 0; - m24->vadj = m24->crtc[5]; - if (!m24->vadj) m24->dispon = 1; - if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; - if ((m24->crtc[10] & 0x60) == 0x20) - m24->cursoron = 0; - else - m24->cursoron = m24->blink & 16; - } - - if (m24->vc == m24->crtc[7]) { - m24->dispon = 0; - m24->displine = 0; - m24->vsynctime = (m24->crtc[3] >> 4) + 1; - if (m24->crtc[7]) { - if (m24->cgamode & 1) - x = (m24->crtc[1] << 3) + 16; - else - x = (m24->crtc[1] << 4) + 16; - m24->lastline++; - - xs_temp = x; - ys_temp = (m24->lastline - m24->firstline); - - if ((xs_temp > 0) && (ys_temp > 0)) { - if (xsize < 64) xs_temp = 656; - if (ysize < 32) ys_temp = 200; - if (!enable_overscan) - xs_temp -= 16; - - if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { - xsize = xs_temp; - ysize = ys_temp; - set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - if (enable_overscan) { - video_blit_memtoscreen_8(0, m24->firstline - 8, 0, (m24->lastline - m24->firstline) + 16, - xsize, (m24->lastline - m24->firstline) + 16); - } else - video_blit_memtoscreen_8(8, m24->firstline, 0, (m24->lastline - m24->firstline), - xsize, (m24->lastline - m24->firstline)); - } - - frames++; - - video_res_x = xsize; - video_res_y = ysize; - if (m24->cgamode & 1) { - video_res_x /= 8; - video_res_y /= (m24->crtc[9] + 1) * 2; - video_bpp = 0; - } else if (!(m24->cgamode & 2)) { - video_res_x /= 16; - video_res_y /= (m24->crtc[9] + 1) * 2; - video_bpp = 0; - } else if (!(m24->cgamode & 16)) { - video_res_x /= 2; - video_res_y /= 2; - video_bpp = 2; - } else if (!(m24->ctrl & 1)) { - video_res_y /= 2; - video_bpp = 1; - } - } - m24->firstline = 1000; - m24->lastline = 0; - m24->blink++; - } - } else { - m24->sc++; - m24->sc &= 31; - m24->ma = m24->maback; - } - if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1)))) - m24->con = 1; - } - if (m24->dispon && (m24->cgamode & 1)) { - for (x = 0; x < (m24->crtc[1] << 1); x++) - m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base]; - } - } -} - - -static void -speed_changed(void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - - recalc_timings(m24); -} - - -static void -kbd_poll(void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - - timer_advance_u64(&m24->send_delay_timer, 1000 * TIMER_USEC); - if (m24->wantirq) { - m24->wantirq = 0; - picint(2); -#if ENABLE_KEYBOARD_LOG - m24_log("M24: take IRQ\n"); -#endif - } - - if (!(m24->status & STAT_OFULL) && key_queue_start != key_queue_end) { -#if ENABLE_KEYBOARD_LOG - m24_log("Reading %02X from the key queue at %i\n", - m24->out, key_queue_start); -#endif - m24->out = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - m24->status |= STAT_OFULL; - m24->status &= ~STAT_IFULL; - m24->wantirq = 1; - } -} - - -static void -kbd_adddata(uint16_t val) -{ - key_queue[key_queue_end] = val; - key_queue_end = (key_queue_end + 1) & 0xf; -} - - -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) -{ - olim24_t *m24 = (olim24_t *)priv; - -#if ENABLE_KEYBOARD_LOG - m24_log("M24: write %04X %02X\n", port, val); -#endif - -#if 0 - if (ram[8] == 0xc3) { - output = 3; - } -#endif - switch (port) { - case 0x60: - if (m24->param != m24->param_total) { - m24->params[m24->param++] = val; - if (m24->param == m24->param_total) { - switch (m24->command) { - case 0x11: - m24->mouse_mode = 0; - m24->scan[0] = m24->params[0]; - m24->scan[1] = m24->params[1]; - m24->scan[2] = m24->params[2]; - m24->scan[3] = m24->params[3]; - m24->scan[4] = m24->params[4]; - m24->scan[5] = m24->params[5]; - m24->scan[6] = m24->params[6]; - break; - - case 0x12: - m24->mouse_mode = 1; - m24->scan[0] = m24->params[0]; - m24->scan[1] = m24->params[1]; - m24->scan[2] = m24->params[2]; - break; - - default: - m24_log("M24: bad keyboard command complete %02X\n", m24->command); - } - } - } else { - m24->command = val; - switch (val) { - case 0x01: /*Self-test*/ - break; - - case 0x05: /*Read ID*/ - kbd_adddata(0x00); - break; - - case 0x11: - m24->param = 0; - m24->param_total = 9; - break; - - case 0x12: - m24->param = 0; - m24->param_total = 4; - break; - - default: - m24_log("M24: bad keyboard command %02X\n", val); - } - } - break; - - case 0x61: - ppi.pb = val; - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - break; - } -} - - -static uint8_t -kbd_read(uint16_t port, void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - uint8_t ret = 0xff; - - switch (port) { - case 0x60: - ret = m24->out; - if (key_queue_start == key_queue_end) { - m24->status &= ~STAT_OFULL; - m24->wantirq = 0; - } else { - m24->out = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - m24->status |= STAT_OFULL; - m24->status &= ~STAT_IFULL; - m24->wantirq = 1; - } - break; - - case 0x61: - ret = ppi.pb; - break; - - case 0x64: - ret = m24->status; - m24->status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); - break; - - default: - m24_log("\nBad M24 keyboard read %04X\n", port); - } - - return(ret); -} - - -static int -ms_poll(int x, int y, int z, int b, void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - - m24->x += x; - m24->y += y; - - if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); - - if ((b & 1) && !(m24->b & 1)) - kbd_adddata(m24->scan[0]); - if (!(b & 1) && (m24->b & 1)) - kbd_adddata(m24->scan[0] | 0x80); - m24->b = (m24->b & ~1) | (b & 1); - - if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); - - if ((b & 2) && !(m24->b & 2)) - kbd_adddata(m24->scan[2]); - if (!(b & 2) && (m24->b & 2)) - kbd_adddata(m24->scan[2] | 0x80); - m24->b = (m24->b & ~2) | (b & 2); - - if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); - - if ((b & 4) && !(m24->b & 4)) - kbd_adddata(m24->scan[1]); - if (!(b & 4) && (m24->b & 4)) - kbd_adddata(m24->scan[1] | 0x80); - m24->b = (m24->b & ~4) | (b & 4); - - if (m24->mouse_mode) { - if (((key_queue_end - key_queue_start) & 0xf) > 12) return(0xff); - - if (!m24->x && !m24->y) return(0xff); - - m24->y = -m24->y; - - if (m24->x < -127) m24->x = -127; - if (m24->x > 127) m24->x = 127; - if (m24->x < -127) m24->x = 0x80 | ((-m24->x) & 0x7f); - - if (m24->y < -127) m24->y = -127; - if (m24->y > 127) m24->y = 127; - if (m24->y < -127) m24->y = 0x80 | ((-m24->y) & 0x7f); - - kbd_adddata(0xfe); - kbd_adddata(m24->x); - kbd_adddata(m24->y); - - m24->x = m24->y = 0; - } else { - while (m24->x < -4) { - if (((key_queue_end - key_queue_start) & 0xf) > 14) - return(0xff); - m24->x += 4; - kbd_adddata(m24->scan[3]); - } - while (m24->x > 4) { - if (((key_queue_end - key_queue_start) & 0xf) > 14) - return(0xff); - m24->x -= 4; - kbd_adddata(m24->scan[4]); - } - while (m24->y < -4) { - if (((key_queue_end - key_queue_start) & 0xf) > 14) - return(0xff); - m24->y += 4; - kbd_adddata(m24->scan[5]); - } - while (m24->y > 4) { - if (((key_queue_end - key_queue_start) & 0xf) > 14) - return(0xff); - m24->y -= 4; - kbd_adddata(m24->scan[6]); - } - } - - return(0); -} - - -static uint8_t -m24_read(uint16_t port, void *priv) -{ - switch (port) { - case 0x66: - return 0x00; - case 0x67: - return 0x20 | 0x40 | 0x0C; - } - - return(0xff); -} - -static void -vid_close(void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - - free(m24->vram); - - free(m24); -} - -const device_t m24_device = { - "Olivetti M24", - 0, 0, - NULL, vid_close, NULL, - NULL, - speed_changed, - NULL, - NULL -}; - - -static void -kbd_reset(void *priv) -{ - olim24_t *m24 = (olim24_t *)priv; - - /* Initialize the keyboard. */ - m24->status = STAT_LOCK | STAT_CD; - m24->wantirq = 0; - keyboard_scan = 1; - m24->param = m24->param_total = 0; - m24->mouse_mode = 0; - m24->scan[0] = 0x1c; - m24->scan[1] = 0x53; - m24->scan[2] = 0x01; - m24->scan[3] = 0x4b; - m24->scan[4] = 0x4d; - m24->scan[5] = 0x48; - m24->scan[6] = 0x50; -} - - -int -machine_olim24_init(const machine_t *model) -{ - int ret; - - ret = bios_load_interleaved(L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_low.bin", - L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_high.bin", - 0x000fc000, 16384, 0); - - if (bios_only || !ret) - return ret; - - olim24_t *m24; - - m24 = (olim24_t *)malloc(sizeof(olim24_t)); - memset(m24, 0x00, sizeof(olim24_t)); - - machine_common_init(model); - device_add(&fdc_xt_device); - - io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, m24); - - /* Initialize the video adapter. */ - // loadfont(L"roms/machines/olivetti_m24/ATT-FONT-DUMPED-VERIFIED.BIN", 1); - loadfont(L"roms/machines/olivetti_m24/m24 graphics board go380 258 pqbq.bin", 1); - m24->vram = malloc(0x8000); - overscan_x = overscan_y = 16; - mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, - vid_write, NULL, NULL, NULL, 0, m24); - io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - timer_add(&m24->timer, vid_poll, m24, 1); - device_add_ex(&m24_device, m24); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_m24); - cga_palette = 0; - cgapal_rebuild(); - - /* Initialize the keyboard. */ - io_sethandler(0x0060, 2, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); - io_sethandler(0x0064, 1, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); - keyboard_send = kbd_adddata_ex; - kbd_reset(m24); - timer_add(&m24->send_delay_timer, kbd_poll, m24, 1); - - /* Tell mouse driver about our internal mouse. */ - mouse_reset(); - mouse_set_poll(ms_poll, m24); - - keyboard_set_table(scancode_xt); - - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); - - /* FIXME: make sure this is correct?? */ - device_add(&at_nvr_device); - - nmi_init(); - - return ret; -} diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 5d3c77525..2665ea164 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -29,6 +29,8 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/timer.h> +#include <86box/device.h> +#include <86box/cassette.h> #include <86box/io.h> #include <86box/nmi.h> #include <86box/pic.h> @@ -79,6 +81,7 @@ typedef struct { int dispon; int con, coff, cursoron, blink; int vsynctime; + int fullchange; int vadj; uint16_t ma, maback; uint64_t dispontime, dispofftime; @@ -160,7 +163,7 @@ vid_out(uint16_t addr, uint8_t val, void *p) pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; if (old != val) { if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { - fullchange = changeframecount; + pcjr->fullchange = changeframecount; recalc_timings(pcjr); } } @@ -221,7 +224,6 @@ vid_write(uint32_t addr, uint8_t val, void *p) if (pcjr->memctrl == -1) return; - egawrites++; pcjr->b8000[addr & 0x3fff] = val; } @@ -232,8 +234,7 @@ vid_read(uint32_t addr, void *p) pcjr_t *pcjr = (pcjr_t *)p; if (pcjr->memctrl == -1) return(0xff); - - egareads++; + return(pcjr->b8000[addr & 0x3fff]); } @@ -256,7 +257,7 @@ vid_poll(void *p) pcjr->stat &= ~1; pcjr->linepos = 1; oldsc = pcjr->sc; - if ((pcjr->crtc[8] & 3) == 3) + if ((pcjr->crtc[8] & 3) == 3) pcjr->sc = (pcjr->sc << 1) & 7; if (pcjr->dispon) { uint16_t offset = 0; @@ -294,7 +295,7 @@ vid_poll(void *p) switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { case 0x13: /*320x200x16*/ for (x = 0; x < pcjr->crtc[1]; x++) { - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; buffer32->line[(pcjr->displine << 1)][(x << 3) + 8] = buffer32->line[(pcjr->displine << 1)][(x << 3) + 9] = @@ -313,7 +314,7 @@ vid_poll(void *p) break; case 0x12: /*160x200x16*/ for (x = 0; x < pcjr->crtc[1]; x++) { - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; buffer32->line[(pcjr->displine << 1)][(x << 4) + 8] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 9] = @@ -360,7 +361,7 @@ vid_poll(void *p) if (pcjr->array[3] & 4) { cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; - if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; @@ -395,7 +396,7 @@ vid_poll(void *p) if (pcjr->array[3] & 4) { cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; - if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; @@ -404,9 +405,9 @@ vid_poll(void *p) pcjr->ma++; if (pcjr->sc & 8) { for (c = 0; c < 8; c++) { - buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = - buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[0]; } } else { @@ -432,7 +433,7 @@ vid_poll(void *p) cols[2] = pcjr->array[2 + 16] + 16; cols[3] = pcjr->array[3 + 16] + 16; for (x = 0; x < pcjr->crtc[1]; x++) { - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; for (c = 0; c < 8; c++) { @@ -491,11 +492,11 @@ vid_poll(void *p) pcjr->stat |= 8; } pcjr->displine++; - if (pcjr->displine >= 360) + if (pcjr->displine >= 360) pcjr->displine = 0; } else { timer_advance_u64(&pcjr->timer, pcjr->dispontime); - if (pcjr->dispon) + if (pcjr->dispon) pcjr->stat |= 1; pcjr->linepos = 0; if (pcjr->vsynctime) { @@ -504,9 +505,9 @@ vid_poll(void *p) pcjr->stat &= ~8; } } - if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) { - pcjr->con = 0; - pcjr->coff = 1; + if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) { + pcjr->con = 0; + pcjr->coff = 1; } if (pcjr->vadj) { pcjr->sc++; @@ -524,14 +525,14 @@ vid_poll(void *p) oldvc = pcjr->vc; pcjr->vc++; pcjr->vc &= 127; - if (pcjr->vc == pcjr->crtc[6]) + if (pcjr->vc == pcjr->crtc[6]) pcjr->dispon = 0; if (oldvc == pcjr->crtc[4]) { pcjr->vc = 0; pcjr->vadj = pcjr->crtc[5]; - if (!pcjr->vadj) + if (!pcjr->vadj) pcjr->dispon = 1; - if (!pcjr->vadj) + if (!pcjr->vadj) pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; if ((pcjr->crtc[10] & 0x60) == 0x20) pcjr->cursoron = 0; else pcjr->cursoron = pcjr->blink & 16; @@ -565,18 +566,18 @@ vid_poll(void *p) } if (enable_overscan) { - if (pcjr->composite) - video_blit_memtoscreen(0, (pcjr->firstline - 4) << 1, 0, ((pcjr->lastline - pcjr->firstline) + 8) << 1, + if (pcjr->composite) + video_blit_memtoscreen(0, (pcjr->firstline - 4) << 1, xsize, ((pcjr->lastline - pcjr->firstline) + 8) << 1); else - video_blit_memtoscreen_8(0, (pcjr->firstline - 4) << 1, 0, ((pcjr->lastline - pcjr->firstline) + 8) << 1, + video_blit_memtoscreen_8(0, (pcjr->firstline - 4) << 1, xsize, ((pcjr->lastline - pcjr->firstline) + 8) << 1); } else { - if (pcjr->composite) - video_blit_memtoscreen(8, pcjr->firstline << 1, 0, (pcjr->lastline - pcjr->firstline) << 1, + if (pcjr->composite) + video_blit_memtoscreen(8, pcjr->firstline << 1, xsize, (pcjr->lastline - pcjr->firstline) << 1); else - video_blit_memtoscreen_8(8, pcjr->firstline << 1, 0, (pcjr->lastline - pcjr->firstline) << 1, + video_blit_memtoscreen_8(8, pcjr->firstline << 1, xsize, (pcjr->lastline - pcjr->firstline) << 1); } } @@ -594,7 +595,7 @@ vid_poll(void *p) pcjr->sc &= 31; pcjr->ma = pcjr->maback; } - if ((pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1)))) + if ((pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1)))) pcjr->con = 1; } } @@ -616,12 +617,17 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x61: pcjr->pb = val; + timer_process(); + + if (cassette != NULL) + pc_cas_set_motor(cassette, (pcjr->pb & 0x08) == 0); + speaker_update(); speaker_gated = val & 1; speaker_enable = val & 2; - if (speaker_enable) + if (speaker_enable) was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); + pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1); sn76489_mute = speaker_mute = 1; switch (val & 0x60) { case 0x00: @@ -636,7 +642,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0xa0: nmi_mask = val & 0x80; - pit_ctr_set_using_timer(&pit->counters[1], !(val & 0x20)); + pit_devs[0].set_using_timer(pit_devs[0].data, 1, !(val & 0x20)); break; } } @@ -655,21 +661,25 @@ kbd_read(uint16_t port, void *priv) case 0x60: ret = pcjr->pa; break; - + case 0x61: ret = pcjr->pb; break; - + case 0x62: ret = (pcjr->latched ? 1 : 0); ret |= 0x02; /*Modem card not installed*/ + if ((pcjr->pb & 0x08) || (cassette == NULL)) + ret |= (ppispeakon ? 0x10 : 0); + else + ret |= (pc_cas_get_inp(cassette) ? 0x10 : 0); ret |= (ppispeakon ? 0x10 : 0); ret |= (ppispeakon ? 0x20 : 0); ret |= (pcjr->data ? 0x40: 0); if (pcjr->data) ret |= 0x40; break; - + case 0xa0: pcjr->latched = 0; ret = 0; @@ -760,46 +770,50 @@ speed_changed(void *priv) recalc_timings(pcjr); } +void +pit_irq0_timer_pcjr(int new_out, int old_out) +{ + if (new_out && !old_out) { + picint(1); + pit_devs[0].ctr_clock(pit_devs[0].data, 1); + } + + if (!new_out) + picintc(1); +} static const device_config_t pcjr_config[] = { { - "display_type", "Display type", CONFIG_SELECTION, "", PCJR_RGB, - { - { - "RGB", PCJR_RGB - }, - { - "Composite", PCJR_COMPOSITE - }, - { - "" - } - } + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = PCJR_RGB, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = PCJR_RGB }, + { .description = "Composite", .value = PCJR_COMPOSITE }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; - -static const device_t pcjr_device = { +const device_t pcjr_device = { "IBM PCjr", - 0, 0, - NULL, NULL, NULL, + "pcjr", + 0, + 0, NULL, + NULL, + NULL, + { NULL }, speed_changed, NULL, pcjr_config }; - -const device_t * -pcjr_get_device(void) -{ - return &pcjr_device; -} - - int machine_pcjr_init(const machine_t *model) { @@ -808,7 +822,7 @@ machine_pcjr_init(const machine_t *model) int ret; - ret = bios_load_linear(L"roms/machines/ibmpcjr/bios.rom", + ret = bios_load_linear("roms/machines/ibmpcjr/bios.rom", 0x000f0000, 65536, 0); if (bios_only || !ret) @@ -826,7 +840,8 @@ machine_pcjr_init(const machine_t *model) cpu_set(); /* Initialize the video controller. */ - loadfont(L"roms/video/mda/mda.rom", 0); + video_reset(gfxcard); + loadfont("roms/video/mda/mda.rom", 0); mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, pcjr); @@ -849,15 +864,15 @@ machine_pcjr_init(const machine_t *model) keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; - /* Technically it's the SN76496N, but the NCR 8496 is a drop-in replacement for it. */ - device_add(&ncr8496_device); + /* Technically it's the SN76496N, but the SN76489 is identical to the SN76496N. */ + device_add(&sn76489_device); nmi_mask = 0x80; device_add(&fdc_pcjr_device); - device_add(&i8250_pcjr_device); - serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + device_add(&ns8250_pcjr_device); + serial_set_next_inst(SERIAL_MAX); /* So that serial_standalone_init() won't do anything. */ return ret; } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 9295b5b7b..19abb00bf 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Emulation of the IBM PS/1 models 2011, 2121 and 2133. + * Emulation of the IBM PS/1 models 2011, 2121. * * Model 2011: The initial model, using a 10MHz 80286. * @@ -48,6 +48,8 @@ #include <86box/nmi.h> #include <86box/rom.h> #include <86box/device.h> +#include <86box/chipset.h> +#include <86box/sio.h> #include <86box/nvr.h> #include <86box/gameport.h> #include <86box/lpt.h> @@ -57,30 +59,16 @@ #include <86box/hdc_ide.h> #include <86box/fdd.h> #include <86box/fdc.h> -#include <86box/sound.h> -#include <86box/snd_sn76489.h> +#include <86box/port_6x.h> #include <86box/video.h> #include <86box/machine.h> +#include <86box/sound.h> -typedef struct { - sn76489_t sn76489; - uint8_t status, ctrl; - uint64_t timer_latch; - pc_timer_t timer_count; - int timer_enable; - uint8_t fifo[2048]; - int fifo_read_idx, fifo_write_idx; - int fifo_threshold; - uint8_t dac_val; - int16_t buffer[SOUNDBUFLEN]; - int pos; -} ps1snd_t; - typedef struct { int model; - rom_t high_rom; + rom_t mid_rom, high_rom; uint8_t ps1_91, ps1_92, @@ -97,178 +85,6 @@ typedef struct { } ps1_t; -static void -update_irq_status(ps1snd_t *snd) -{ - if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01)) - picint(1 << 7); - else - picintc(1 << 7); -} - - -static uint8_t -snd_read(uint16_t port, void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - uint8_t ret = 0xff; - - switch (port & 7) { - case 0: /* ADC data */ - snd->status &= ~0x10; - update_irq_status(snd); - ret = 0; - break; - - case 2: /* status */ - ret = snd->status; - ret |= (snd->ctrl & 0x01); - if ((snd->fifo_write_idx - snd->fifo_read_idx) >= 2048) - ret |= 0x08; /* FIFO full */ - if (snd->fifo_read_idx == snd->fifo_write_idx) - ret |= 0x04; /* FIFO empty */ - break; - - case 3: /* FIFO timer */ - /* - * The PS/1 Technical Reference says this should return - * thecurrent value, but the PS/1 BIOS and Stunt Island - * expect it not to change. - */ - ret = snd->timer_latch; - break; - - case 4: - case 5: - case 6: - case 7: - ret = 0; - } - - return(ret); -} - - -static void -snd_write(uint16_t port, uint8_t val, void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - - switch (port & 7) { - case 0: /* DAC output */ - if ((snd->fifo_write_idx - snd->fifo_read_idx) < 2048) { - snd->fifo[snd->fifo_write_idx & 2047] = val; - snd->fifo_write_idx++; - } - break; - - case 2: /* control */ - snd->ctrl = val; - if (! (val & 0x02)) - snd->status &= ~0x02; - update_irq_status(snd); - break; - - case 3: /* timer reload value */ - snd->timer_latch = val; - if (val) - timer_set_delay_u64(&snd->timer_count, ((0xff-val) * TIMER_USEC)); - else - timer_disable(&snd->timer_count); - break; - - case 4: /* almost empty */ - snd->fifo_threshold = val * 4; - break; - } -} - - -static void -snd_update(ps1snd_t *snd) -{ - for (; snd->pos < sound_pos_global; snd->pos++) - snd->buffer[snd->pos] = (int8_t)(snd->dac_val ^ 0x80) * 0x20; -} - - -static void -snd_callback(void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - - snd_update(snd); - - if (snd->fifo_read_idx != snd->fifo_write_idx) { - snd->dac_val = snd->fifo[snd->fifo_read_idx & 2047]; - snd->fifo_read_idx++; - } - - if ((snd->fifo_write_idx - snd->fifo_read_idx) == snd->fifo_threshold) - snd->status |= 0x02; /*FIFO almost empty*/ - - snd->status |= 0x10; /*ADC data ready*/ - update_irq_status(snd); - - timer_advance_u64(&snd->timer_count, snd->timer_latch * TIMER_USEC); -} - - -static void -snd_get_buffer(int32_t *buffer, int len, void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - int c; - - snd_update(snd); - - for (c = 0; c < len * 2; c++) - buffer[c] += snd->buffer[c >> 1]; - - snd->pos = 0; -} - - -static void * -snd_init(const device_t *info) -{ - ps1snd_t *snd; - - snd = malloc(sizeof(ps1snd_t)); - memset(snd, 0x00, sizeof(ps1snd_t)); - - sn76489_init(&snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); - - io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); - io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); - - timer_add(&snd->timer_count, snd_callback, snd, 0); - - sound_add_handler(snd_get_buffer, snd); - - return(snd); -} - - -static void -snd_close(void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - - free(snd); -} - - -static const device_t snd_device = { - "PS/1 Audio Card", - 0, 0, - snd_init, snd_close, NULL, - NULL, - NULL, - NULL -}; - - static void recalc_memory(ps1_t *ps) { @@ -300,7 +116,7 @@ ps1_write(uint16_t port, uint8_t val, void *priv) } ps->ps1_92 = val & ~1; } else { - ps->ps1_92 = val; + ps->ps1_92 = val; } mem_a20_alt = val & 2; mem_a20_recalc(); @@ -324,25 +140,31 @@ ps1_write(uint16_t port, uint8_t val, void *priv) break; case 0x0102: - lpt1_remove(); - if (val & 0x04) - serial_setup(ps->uart, SERIAL1_ADDR, SERIAL1_IRQ); - else + if (!(ps->ps1_94 & 0x80)) { + lpt1_remove(); serial_remove(ps->uart); - if (val & 0x10) { - switch ((val >> 5) & 3) { - case 0: - lpt1_init(0x03bc); - break; - case 1: - lpt1_init(0x0378); - break; - case 2: - lpt1_init(0x0278); - break; + if (val & 0x04) { + if (val & 0x08) + serial_setup(ps->uart, COM1_ADDR, COM1_IRQ); + else + serial_setup(ps->uart, COM2_ADDR, COM2_IRQ); } + if (val & 0x10) { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(LPT_MDA_ADDR); + break; + case 1: + lpt1_init(LPT1_ADDR); + break; + case 2: + lpt1_init(LPT2_ADDR); + break; + } + } + ps->ps1_102 = val; } - ps->ps1_102 = val; break; case 0x0103: @@ -448,18 +270,22 @@ ps1_setup(int model) ps->uart = device_add_inst(&ns16450_device, 1); lpt1_remove(); - lpt1_init(0x3bc); + lpt1_init(LPT_MDA_ADDR); + + mem_remap_top(384); + + device_add(&ps_nvr_device); if (model == 2011) { rom_init(&ps->high_rom, - L"roms/machines/ibmps1es/f80000.bin", + "roms/machines/ibmps1es/f80000.bin", 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); lpt2_remove(); - device_add(&snd_device); + device_add(&ps1snd_device); - device_add(&fdc_at_actlow_device); + device_add(&fdc_at_ps1_device); /* Enable the builtin HDC. */ if (hdc_current == 1) { @@ -467,17 +293,21 @@ ps1_setup(int model) ps1_hdc_inform(priv, &ps->ps1_91); } - } - if (model == 2121) { + /* Enable the PS/1 VGA controller. */ + device_add(&ps1vga_device); + } else if (model == 2121) { io_sethandler(0x00e0, 2, ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); -#if 0 + if (rom_present("roms/machines/ibmps1_2121/F80000.BIN")) { + rom_init(&ps->mid_rom, + "roms/machines/ibmps1_2121/F80000.BIN", + 0xf80000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); + } rom_init(&ps->high_rom, - L"roms/machines/ibmps1_2121/fc0000.bin", - 0xfc0000, 0x20000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); -#endif + "roms/machines/ibmps1_2121/FC0000.BIN", + 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); /* Initialize the video controller. */ if (gfxcard == VID_INTERNAL) @@ -487,44 +317,26 @@ ps1_setup(int model) device_add(&ide_isa_device); - device_add(&snd_device); + device_add(&ps1snd_device); } - -#if defined(DEV_BRANCH) && defined(USE_PS1M2133) - if (model == 2133) { - device_add(&fdc_at_device); - - device_add(&ide_isa_device); - } -#endif - - /* Enable the PS/1 VGA controller. */ - if (model == 2011) - device_add(&ps1vga_device); - else - device_add(&ibm_ps1_2121_device); } - static void ps1_common_init(const machine_t *model) { machine_common_init(model); - mem_remap_top(384); - - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); + refresh_at_enable = 1; + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_at); dma16_init(); pic2_init(); - device_add(&ps_nvr_device); - device_add(&keyboard_ps2_ps1_device); + device_add(&port_6x_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_201_device); + standalone_gameport_type = &gameport_201_device; } @@ -533,7 +345,7 @@ machine_ps1_m2011_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ibmps1es/f80000.bin", + ret = bios_load_linear("roms/machines/ibmps1es/f80000.bin", 0x000e0000, 131072, 0x60000); if (bios_only || !ret) @@ -552,7 +364,7 @@ machine_ps1_m2121_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ibmps1_2121/fc0000.bin", + ret = bios_load_linear("roms/machines/ibmps1_2121/FC0000.BIN", 0x000e0000, 131072, 0x20000); if (bios_only || !ret) @@ -564,26 +376,3 @@ machine_ps1_m2121_init(const machine_t *model) return ret; } - - -#if defined(DEV_BRANCH) && defined(USE_PS1M2133) -int -machine_ps1_m2133_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear(L"roms/machines/ibmps1_2133/ps1_2133_52g2974_rom.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - ps1_common_init(model); - - ps1_setup(2133); - - nmi_mask = 0x80; - - return ret; -} -#endif diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index 7bea2ef7a..e7cff2478 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -23,7 +23,7 @@ * disk drives for this bus commonly have an 'A' suffix to * identify them as 'ATBUS'. * - * In XTA-IDE, which is slightly older, the programming + * In XTA-IDE, which is slightly older, the programming * interface of the IBM PC/XT (which used the MFM controller * from Xebec) was kept, and, so, it uses an 8bit data path. * Disk drives for this bus commonly have the 'X' suffix to @@ -38,7 +38,7 @@ * data byte per transfer. XTIDE uses regular IDE drives, * and uses the regular ATA/IDE programming interface, just * with the extra register. - * + * * NOTE: We should probably find a nicer way to integrate our Disk * Type table with the main code, so the user can only select * items from that list... @@ -82,9 +82,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE #include #include #include @@ -847,7 +844,7 @@ do_send: } } break; - + case STATE_SDATA: if (! no_data) { /* Perform DMA. */ @@ -1040,7 +1037,7 @@ do_recv: case CMD_FORMAT_TRACK: do_format(dev, drive, ccb); break; - + case CMD_SEEK: if (! drive->present) { dev->ssb.not_ready = 1; @@ -1150,7 +1147,7 @@ hdc_read(uint16_t port, void *priv) break; } - return(ret); + return(ret); } @@ -1349,17 +1346,20 @@ ps1_hdc_close(void *priv) free(dev); } - const device_t ps1_hdc_device = { - "PS/1 2011 Fixed Disk Controller", - DEVICE_ISA | DEVICE_PS2, - 0, - ps1_hdc_init, ps1_hdc_close, NULL, - NULL, NULL, NULL, - NULL + .name = "PS/1 2011 Fixed Disk Controller", + .internal_name = "ps1_hdc", + .flags = DEVICE_ISA | DEVICE_PS2, + .local = 0, + .init = ps1_hdc_init, + .close = ps1_hdc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - /* * Very nasty. * diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 9300d05d4..094fc8a5f 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include <86box/86box.h> @@ -15,6 +16,7 @@ #include <86box/nvr.h> #include <86box/keyboard.h> #include <86box/lpt.h> +#include <86box/port_6x.h> #include <86box/port_92.h> #include <86box/serial.h> #include <86box/hdc.h> @@ -24,174 +26,194 @@ #include <86box/machine.h> -static uint8_t ps2_91, ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; -static serial_t *ps2_uart; +typedef struct { + int model; + int cpu_type; + + uint8_t ps2_91, + ps2_92, + ps2_94, + ps2_102, + ps2_103, + ps2_104, + ps2_105, + ps2_190; + + serial_t *uart; +} ps2_isa_t; -static struct +static void +ps2_write(uint16_t port, uint8_t val, void *priv) { - uint8_t status, int_status; - uint8_t attention, ctrl; -} ps2_hd; + ps2_isa_t *ps2 = (ps2_isa_t *)priv; + switch (port) { + case 0x0094: + ps2->ps2_94 = val; + break; -static uint8_t ps2_read(uint16_t port, void *p) -{ - uint8_t temp; - - switch (port) - { - case 0x91: - temp = ps2_91; - ps2_91 = 0; - return temp; - case 0x94: - return ps2_94; - case 0x102: - return ps2_102 | 8; - case 0x103: - return ps2_103; - case 0x104: - return ps2_104; - case 0x105: - return ps2_105; - case 0x190: - return ps2_190; - -#ifdef FIXME - case 0x322: - temp = ps2_hd.status; - break; - case 0x324: - temp = ps2_hd.int_status; - ps2_hd.int_status &= ~0x02; - break; -#endif - - default: - temp = 0xff; - break; - } - - return temp; -} - -static void ps2_write(uint16_t port, uint8_t val, void *p) -{ - switch (port) - { - case 0x94: - ps2_94 = val; - break; - case 0x102: + case 0x0102: + if (!(ps2->ps2_94 & 0x80)) { lpt1_remove(); - if (val & 0x04) - serial_setup(ps2_uart, SERIAL1_ADDR, SERIAL1_IRQ); - else - serial_remove(ps2_uart); - if (val & 0x10) - { - switch ((val >> 5) & 3) - { - case 0: - lpt1_init(0x3bc); - break; - case 1: - lpt1_init(0x378); - break; - case 2: - lpt1_init(0x278); - break; - } + serial_remove(ps2->uart); + if (val & 0x04) { + if (val & 0x08) + serial_setup(ps2->uart, COM1_ADDR, COM1_IRQ); + else + serial_setup(ps2->uart, COM2_ADDR, COM2_IRQ); } - ps2_102 = val; - break; - case 0x103: - ps2_103 = val; - break; - case 0x104: - ps2_104 = val; - break; - case 0x105: - ps2_105 = val; - break; - case 0x190: - ps2_190 = val; - break; + if (val & 0x10) { + switch ((val >> 5) & 3) { + case 0: + lpt1_init(LPT_MDA_ADDR); + break; + case 1: + lpt1_init(LPT1_ADDR); + break; + case 2: + lpt1_init(LPT2_ADDR); + break; + } + } + ps2->ps2_102 = val; + } + break; -#ifdef FIXME - case 0x322: - ps2_hd.ctrl = val; - if (val & 0x80) - ps2_hd.status |= 0x02; - break; - case 0x324: - ps2_hd.attention = val & 0xf0; - if (ps2_hd.attention) - ps2_hd.status = 0x14; - break; -#endif - } + case 0x0103: + ps2->ps2_103 = val; + break; + + case 0x0104: + ps2->ps2_104 = val; + break; + + case 0x0105: + ps2->ps2_105 = val; + break; + + case 0x0190: + ps2->ps2_190 = val; + break; + } } -static void ps2board_init(void) +static uint8_t +ps2_read(uint16_t port, void *priv) { - io_sethandler(0x0091, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - io_sethandler(0x0094, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - io_sethandler(0x0102, 0x0004, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - io_sethandler(0x0190, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); -#ifdef FIXME - io_sethandler(0x0320, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - io_sethandler(0x0322, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - io_sethandler(0x0324, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); -#endif + ps2_isa_t *ps2 = (ps2_isa_t *)priv; + uint8_t temp = 0xff; + + switch (port) { + case 0x0091: + temp = ps2->ps2_91; + ps2->ps2_91 = 0; + break; + + case 0x0094: + temp = ps2->ps2_94; + break; + + case 0x0102: + temp = ps2->ps2_102 | 0x08; + break; + + case 0x0103: + temp = ps2->ps2_103; + break; + + case 0x0104: + temp = ps2->ps2_104; + break; + + case 0x0105: + temp = ps2->ps2_105; + break; + + case 0x0190: + temp = ps2->ps2_190; + break; + } + + return temp; +} + + +static void +ps2_isa_setup(int model, int cpu_type) +{ + ps2_isa_t *ps2; + void *priv; + + ps2 = (ps2_isa_t *)malloc(sizeof(ps2_isa_t)); + memset(ps2, 0x00, sizeof(ps2_isa_t)); + ps2->model = model; + ps2->cpu_type = cpu_type; + + + io_sethandler(0x0091, 1, + ps2_read, NULL, NULL, ps2_write, NULL, NULL, ps2); + io_sethandler(0x0094, 1, + ps2_read, NULL, NULL, ps2_write, NULL, NULL, ps2); + io_sethandler(0x0102, 4, + ps2_read, NULL, NULL, ps2_write, NULL, NULL, ps2); + io_sethandler(0x0190, 1, + ps2_read, NULL, NULL, ps2_write, NULL, NULL, ps2); + + ps2->uart = device_add_inst(&ns16450_device, 1); + + lpt1_remove(); + lpt1_init(LPT_MDA_ADDR); device_add(&port_92_device); - ps2_190 = 0; + mem_remap_top(384); - ps2_uart = device_add_inst(&ns16450_device, 1); + device_add(&ps_nvr_device); - lpt1_init(0x3bc); - - memset(&ps2_hd, 0, sizeof(ps2_hd)); + device_add(&fdc_at_ps1_device); + + /* Enable the builtin HDC. */ + if (hdc_current == 1) { + priv = device_add(&ps1_hdc_device); + ps1_hdc_inform(priv, &ps2->ps2_91); + } + + device_add(&ps1vga_device); +} + + +static void +ps2_isa_common_init(const machine_t *model) +{ + machine_common_init(model); + + refresh_at_enable = 1; + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_at); + + dma16_init(); + pic2_init(); + + device_add(&keyboard_ps2_device); + device_add(&port_6x_ps2_device); } int machine_ps2_m30_286_init(const machine_t *model) { - void *priv; + int ret; - int ret; + ret = bios_load_linear("roms/machines/ibmps2_m30_286/33f5381a.bin", + 0x000e0000, 131072, 0); - ret = bios_load_linear(L"roms/machines/ibmps2_m30_286/33f5381a.bin", - 0x000e0000, 131072, 0); + if (bios_only || !ret) + return ret; - if (bios_only || !ret) - return ret; + ps2_isa_common_init(model); - machine_common_init(model); + ps2_isa_setup(30, 286); - mem_remap_top(384); - - device_add(&fdc_at_ps1_device); - - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); - dma16_init(); - device_add(&keyboard_ps2_ps2_device); - device_add(&ps_nvr_device); - pic2_init(); - ps2board_init(); - device_add(&ps1vga_device); - - /* Enable the builtin HDC. */ - if (hdc_current == 1) { - priv = device_add(&ps1_hdc_device); - - ps1_hdc_inform(priv, &ps2_91); - } - - return ret; + return ret; } diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 5a1bf3fd5..665d42972 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -57,11 +57,13 @@ #include <86box/device.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/fdc_ext.h> #include <86box/nvr.h> #include <86box/nvr_ps2.h> #include <86box/keyboard.h> #include <86box/lpt.h> #include <86box/mouse.h> +#include <86box/port_6x.h> #include <86box/port_92.h> #include <86box/serial.h> #include <86box/video.h> @@ -76,27 +78,27 @@ static struct uint8_t setup; uint8_t sys_ctrl_port_a; uint8_t subaddr_lo, subaddr_hi; - + uint8_t memory_bank[8]; - + uint8_t io_id; - - mem_mapping_t shadow_mapping; + uint16_t planar_id; + mem_mapping_t split_mapping; mem_mapping_t expansion_mapping; mem_mapping_t cache_mapping; - + uint8_t (*planar_read)(uint16_t port); void (*planar_write)(uint16_t port, uint8_t val); - + uint8_t mem_regs[3]; - + uint32_t split_addr, split_size; uint32_t split_phys; - + uint8_t mem_pos_regs[8]; uint8_t mem_2mb_pos_regs[8]; - + int pending_cache_miss; serial_t *uart; @@ -104,7 +106,7 @@ static struct /*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any proper cache emulation, it's faked a bit here. - + Port E2 is used for cache diagnostics. Bit 7 seems to be set on a cache miss, toggling bit 2 seems to clear this. The BIOS performs at least the following tests : @@ -122,7 +124,7 @@ static struct This behaviour is required to pass the timer interrupt test on the 486 version - the BIOS uses a fixed length loop that will terminate too early on a 486/25 if it executes from internal cache. - + To handle this, 86Box uses some basic heuristics : - If cache is enabled but RAM is disabled, accesses to low memory go directly to cache memory. @@ -200,7 +202,7 @@ static uint32_t ps2_read_cache_raml(uint32_t addr, void *priv) } static void ps2_write_cache_ram(uint32_t addr, uint8_t val, void *priv) { - ps2_mca_log("ps2_write_cache_ram: addr=%08x val=%02x %04x:%04x %i\n", addr, val, CS,cpu_state.pc, ins); + ps2_mca_log("ps2_write_cache_ram: addr=%08x val=%02x %04x:%04x %i\n", addr, val, CS,cpu_state.pc); ps2_cache[addr] = val; } @@ -209,37 +211,6 @@ void ps2_cache_clean(void) memset(ps2_cache_valid, 0, sizeof(ps2_cache_valid)); } -static uint8_t ps2_read_shadow_ram(uint32_t addr, void *priv) -{ - addr = (addr & 0x1ffff) + 0xe0000; - return mem_read_ram(addr, priv); -} -static uint16_t ps2_read_shadow_ramw(uint32_t addr, void *priv) -{ - addr = (addr & 0x1ffff) + 0xe0000; - return mem_read_ramw(addr, priv); -} -static uint32_t ps2_read_shadow_raml(uint32_t addr, void *priv) -{ - addr = (addr & 0x1ffff) + 0xe0000; - return mem_read_raml(addr, priv); -} -static void ps2_write_shadow_ram(uint32_t addr, uint8_t val, void *priv) -{ - addr = (addr & 0x1ffff) + 0xe0000; - mem_write_ram(addr, val, priv); -} -static void ps2_write_shadow_ramw(uint32_t addr, uint16_t val, void *priv) -{ - addr = (addr & 0x1ffff) + 0xe0000; - mem_write_ramw(addr, val, priv); -} -static void ps2_write_shadow_raml(uint32_t addr, uint32_t val, void *priv) -{ - addr = (addr & 0x1ffff) + 0xe0000; - mem_write_raml(addr, val, priv); -} - static uint8_t ps2_read_split_ram(uint32_t addr, void *priv) { addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; @@ -282,9 +253,9 @@ static uint8_t model_50_read(uint16_t port) switch (port) { case 0x100: - return 0xff; + return ps2.planar_id & 0xff; case 0x101: - return 0xfb; + return ps2.planar_id >> 8; case 0x102: return ps2.option[0]; case 0x103: @@ -306,9 +277,9 @@ static uint8_t model_55sx_read(uint16_t port) switch (port) { case 0x100: - return 0xff; + return ps2.planar_id & 0xff; case 0x101: - return 0xfb; + return ps2.planar_id >> 8; case 0x102: return ps2.option[0]; case 0x103: @@ -330,9 +301,9 @@ static uint8_t model_70_type3_read(uint16_t port) switch (port) { case 0x100: - return 0xff; + return ps2.planar_id & 0xff; case 0x101: - return 0xf9; + return ps2.planar_id >> 8; case 0x102: return ps2.option[0]; case 0x103: @@ -354,9 +325,9 @@ static uint8_t model_80_read(uint16_t port) switch (port) { case 0x100: - return 0xff; + return ps2.planar_id & 0xff; case 0x101: - return 0xfd; + return ps2.planar_id >> 8; case 0x102: return ps2.option[0]; case 0x103: @@ -388,22 +359,22 @@ static void model_50_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); else - serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); } if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(0x3bc); + lpt1_init(LPT_MDA_ADDR); break; case 1: - lpt1_init(0x378); + lpt1_init(LPT1_ADDR); break; case 2: - lpt1_init(0x278); + lpt1_init(LPT2_ADDR); break; } } @@ -427,6 +398,92 @@ static void model_50_write(uint16_t port, uint8_t val) } } + +static void model_55sx_mem_recalc(void) +{ + int i, j, state; +#ifdef ENABLE_PS2_MCA_LOG + int enabled_mem = 0; +#endif + int base = 0, remap_size = (ps2.option[3] & 0x10) ? 384 : 256; + int bit_mask = 0x00, max_rows = 4; + int bank_to_rows[16] = { 4, 2, 1, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 2, 1, 0 }; + + ps2_mca_log("%02X %02X\n", ps2.option[1], ps2.option[3]); + + mem_remap_top(remap_size); + mem_set_mem_state(0x00000000, (mem_size + 384) * 1024, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x000e0000, 0x00020000, MEM_READ_EXTANY | MEM_WRITE_DISABLED); + + for (i = 0; i < 2; i++) + { + max_rows = bank_to_rows[(ps2.memory_bank[i] >> 4) & 0x0f]; + + if (max_rows == 0) + continue; + + for (j = 0; j < max_rows; j++) + { + if (ps2.memory_bank[i] & (1 << j)) { + ps2_mca_log("Set memory at %06X-%06X to internal\n", (base * 1024), (base * 1024) + (((base > 0) ? 1024 : 640) * 1024) - 1); + mem_set_mem_state(base * 1024, ((base > 0) ? 1024 : 640) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +#ifdef ENABLE_PS2_MCA_LOG + enabled_mem += 1024; +#endif + bit_mask |= (1 << (j + (i << 2))); + } + base += 1024; + } + } + +#ifdef ENABLE_PS2_MCA_LOG + ps2_mca_log("Enabled memory: %i kB (%02X)\n", enabled_mem, bit_mask); +#endif + + if (ps2.option[3] & 0x10) + { + /* Enable ROM. */ + ps2_mca_log("Enable ROM\n"); + state = MEM_READ_EXTANY; + } + else + { + /* Disable ROM. */ + if ((ps2.option[1] & 1) && !(ps2.option[3] & 0x20) && (bit_mask & 0x01)) + { + /* Disable RAM between 640 kB and 1 MB. */ + ps2_mca_log("Disable ROM, enable RAM\n"); + state = MEM_READ_INTERNAL; + } + else + { + ps2_mca_log("Disable ROM, disable RAM\n"); + state = MEM_READ_DISABLED; + } + } + + /* Write always disabled. */ + state |= MEM_WRITE_DISABLED; + + mem_set_mem_state(0xe0000, 0x20000, state); + + /* if (!(ps2.option[3] & 0x08)) + { + ps2_mca_log("Memory not yet configured\n"); + return; + } */ + + ps2_mca_log("Enable shadow mapping at %06X-%06X\n", (mem_size * 1024), (mem_size * 1024) + (remap_size * 1024) - 1); + + if ((ps2.option[1] & 1) && !(ps2.option[3] & 0x20) && (bit_mask & 0x01)) { + ps2_mca_log("Set memory at %06X-%06X to internal\n", (mem_size * 1024), (mem_size * 1024) + (remap_size * 1024) - 1); + mem_set_mem_state(mem_size * 1024, remap_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + + flushmmucache_nopc(); +} + + static void model_55sx_write(uint16_t port, uint8_t val) { switch (port) @@ -442,56 +499,42 @@ static void model_55sx_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); else - serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); } if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(0x3bc); + lpt1_init(LPT_MDA_ADDR); break; case 1: - lpt1_init(0x378); + lpt1_init(LPT1_ADDR); break; case 2: - lpt1_init(0x278); + lpt1_init(LPT2_ADDR); break; } } ps2.option[0] = val; break; case 0x103: + ps2_mca_log("Write POS1: %02X\n", val); ps2.option[1] = val; - break; + model_55sx_mem_recalc(); + break; case 0x104: ps2.memory_bank[ps2.option[3] & 7] &= ~0xf; ps2.memory_bank[ps2.option[3] & 7] |= (val & 0xf); - ps2_mca_log("Write memory bank %i %02x\n", ps2.option[3] & 7, val); + ps2_mca_log("Write memory bank %i: %02X\n", ps2.option[3] & 7, val); + model_55sx_mem_recalc(); break; case 0x105: - ps2_mca_log("Write POS3 %02x\n", val); + ps2_mca_log("Write POS3: %02X\n", val); ps2.option[3] = val; - shadowbios = !(val & 0x10); - shadowbios_write = val & 0x10; - - if (shadowbios) - { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - mem_mapping_disable(&ps2.shadow_mapping); - } - else - { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - mem_mapping_enable(&ps2.shadow_mapping); - } - - if ((ps2.option[1] & 1) && !(ps2.option[3] & 0x20)) - mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - else - mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + model_55sx_mem_recalc(); break; case 0x106: ps2.subaddr_lo = val; @@ -516,27 +559,35 @@ static void model_70_type3_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); else - serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); } if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(0x3bc); + lpt1_init(LPT_MDA_ADDR); break; case 1: - lpt1_init(0x378); + lpt1_init(LPT1_ADDR); break; case 2: - lpt1_init(0x278); + lpt1_init(LPT2_ADDR); break; } } ps2.option[0] = val; break; + case 0x103: + if (ps2.planar_id == 0xfff9) + ps2.option[1] = (ps2.option[1] & 0x0f) | (val & 0xf0); + break; + case 0x104: + if (ps2.planar_id == 0xfff9) + ps2.option[2] = val; + break; case 0x105: ps2.option[3] = val; break; @@ -564,22 +615,22 @@ static void model_80_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); else - serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); } if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(0x3bc); + lpt1_init(LPT_MDA_ADDR); break; case 1: - lpt1_init(0x378); + lpt1_init(LPT1_ADDR); break; case 2: - lpt1_init(0x278); + lpt1_init(LPT2_ADDR); break; } } @@ -652,7 +703,7 @@ uint8_t ps2_mca_read(uint16_t port, void *p) temp = ps2.planar_read(port); else if (!(ps2.setup & PS2_SETUP_VGA)) temp = ps2.pos_vga; - else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) temp = mca_read(port); else temp = 0xff; @@ -697,7 +748,7 @@ uint8_t ps2_mca_read(uint16_t port, void *p) else temp = 0xff; break; - + default: temp = 0xff; break; @@ -778,16 +829,17 @@ static void ps2_mca_write(uint16_t port, uint8_t val, void *p) static void ps2_mca_board_common_init() { - io_sethandler(0x0091, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - io_sethandler(0x0094, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0091, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - device_add(&port_92_device); + device_add(&port_6x_ps2_device); + device_add(&port_92_device); - ps2.setup = 0xff; - - lpt1_init(0x3bc); + ps2.setup = 0xff; + + lpt1_init(LPT_MDA_ADDR); } static uint8_t ps2_mem_expansion_read(int port, void *p) @@ -817,13 +869,8 @@ static void ps2_mca_mem_fffc_init(int start_mb) { uint32_t planar_size, expansion_start; - if (start_mb == 2) { - planar_size = 0x160000; - expansion_start = 0x260000; - } else { - planar_size = (start_mb - 1) << 20; - expansion_start = start_mb << 20; - } + planar_size = (start_mb - 1) << 20; + expansion_start = start_mb << 20; mem_mapping_set_addr(&ram_high_mapping, 0x100000, planar_size); @@ -874,12 +921,42 @@ static void ps2_mca_mem_fffc_init(int start_mb) mem_mapping_disable(&ps2.expansion_mapping); } -static void ps2_mca_board_model_50_init() -{ +static void ps2_mca_mem_d071_init(int start_mb) +{ + uint32_t planar_size, expansion_start; + + planar_size = (start_mb - 1) << 20; + expansion_start = start_mb << 20; + + mem_mapping_set_addr(&ram_high_mapping, 0x100000, planar_size); + + ps2.mem_pos_regs[0] = 0xd0; + ps2.mem_pos_regs[1] = 0x71; + ps2.mem_pos_regs[4] = (mem_size / 1024) - start_mb; + + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, ps2_mem_expansion_feedb, NULL, NULL); + mem_mapping_add(&ps2.expansion_mapping, + expansion_start, + (mem_size - (start_mb << 10)) << 10, + mem_read_ram, + mem_read_ramw, + mem_read_raml, + mem_write_ram, + mem_write_ramw, + mem_write_raml, + &ram[expansion_start], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.expansion_mapping); +} + + +static void ps2_mca_board_model_50_init(int slots) +{ ps2_mca_board_common_init(); mem_remap_top(384); - mca_init(4); + mca_init(slots); device_add(&keyboard_ps2_mca_2_device); ps2.planar_read = model_50_read; @@ -891,31 +968,18 @@ static void ps2_mca_board_model_50_init() ps2_mca_mem_fffc_init(2); } - if (gfxcard == VID_INTERNAL) + if (gfxcard == VID_INTERNAL) device_add(&ps1vga_mca_device); } -static void ps2_mca_board_model_55sx_init() -{ +static void ps2_mca_board_model_55sx_init(int has_sec_nvram, int slots) +{ ps2_mca_board_common_init(); - - mem_mapping_add(&ps2.shadow_mapping, - (mem_size+256) * 1024, - 128*1024, - ps2_read_shadow_ram, - ps2_read_shadow_ramw, - ps2_read_shadow_raml, - ps2_write_shadow_ram, - ps2_write_shadow_ramw, - ps2_write_shadow_raml, - &ram[0xe0000], - MEM_MAPPING_INTERNAL, - NULL); - - mem_remap_top(256); + ps2.option[1] = 0x00; + ps2.option[2] = 0x00; ps2.option[3] = 0x10; - + memset(ps2.memory_bank, 0xf0, 8); switch (mem_size/1024) { @@ -949,24 +1013,38 @@ static void ps2_mca_board_model_55sx_init() ps2.memory_bank[0] = 0x01; ps2.memory_bank[1] = 0x01; break; - } - - mca_init(4); + } + + mca_init(slots); device_add(&keyboard_ps2_mca_device); - ps2.planar_read = model_55sx_read; - ps2.planar_write = model_55sx_write; + if (has_sec_nvram == 1) + device_add(&ps2_nvr_55ls_device); + else if (has_sec_nvram == 2) + device_add(&ps2_nvr_device); + + ps2.planar_read = model_55sx_read; + ps2.planar_write = model_55sx_write; if (gfxcard == VID_INTERNAL) device_add(&ps1vga_mca_device); + + model_55sx_mem_recalc(); } -static void mem_encoding_update() +static void mem_encoding_update(void) { mem_mapping_disable(&ps2.split_mapping); - + + if (ps2.split_size > 0) + mem_set_mem_state(ps2.split_addr, ps2.split_size << 10, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + if (((mem_size << 10) - (1 << 20)) > 0) + mem_set_mem_state(1 << 20, (mem_size << 10) - (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + ps2.split_addr = ((uint32_t) (ps2.mem_regs[0] & 0xf)) << 20; - + if (!ps2.split_addr) + ps2.split_addr = 1 << 20; + if (ps2.mem_regs[1] & 2) { mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); ps2_mca_log("PS/2 Model 80-111: ROM space enabled\n"); @@ -993,12 +1071,17 @@ static void mem_encoding_update() ps2.split_phys = 0xa0000; } + mem_set_mem_state(ps2.split_addr, ps2.split_size << 10, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_mapping_set_exec(&ps2.split_mapping, &ram[ps2.split_phys]); mem_mapping_set_addr(&ps2.split_mapping, ps2.split_addr, ps2.split_size << 10); ps2_mca_log("PS/2 Model 80-111: Split memory block enabled at %08X\n", ps2.split_addr); - } else + } else { + ps2.split_size = 0; ps2_mca_log("PS/2 Model 80-111: Split memory block disabled\n"); + } + + flushmmucache_nopc(); } static uint8_t mem_encoding_read(uint16_t addr, void *p) @@ -1043,7 +1126,7 @@ static uint8_t mem_encoding_read_cached(uint16_t addr, void *p) static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p) { uint8_t old; - + switch (addr) { case 0xe0: @@ -1072,9 +1155,9 @@ static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p) #if 1 // FIXME: Look into this!!! if (val & 0x01) - ram_mid_mapping.flags |= MEM_MAPPING_ROM; + ram_mid_mapping.flags |= MEM_MAPPING_ROM_WS; else - ram_mid_mapping.flags &= ~MEM_MAPPING_ROM; + ram_mid_mapping.flags &= ~MEM_MAPPING_ROM_WS; #endif break; } @@ -1094,19 +1177,19 @@ static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p) } } -static void ps2_mca_board_model_70_type34_init(int is_type4) -{ +static void ps2_mca_board_model_70_type34_init(int is_type4, int slots) +{ ps2_mca_board_common_init(); ps2.split_addr = mem_size * 1024; - mca_init(4); + mca_init(slots); device_add(&keyboard_ps2_mca_device); ps2.planar_read = model_70_type3_read; ps2.planar_write = model_70_type3_write; - + device_add(&ps2_nvr_device); - + io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL); ps2.mem_regs[1] = 2; @@ -1131,12 +1214,12 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) ps2.option[2] = 0x02; break; } - + if (is_type4) ps2.option[2] |= 0x04; /*486 CPU*/ mem_mapping_add(&ps2.split_mapping, - (mem_size+256) * 1024, + (mem_size+256) * 1024, 256*1024, ps2_read_split_ram, ps2_read_split_ramw, @@ -1150,8 +1233,8 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) mem_mapping_disable(&ps2.split_mapping); mem_mapping_add(&ps2.cache_mapping, - 0, - is_type4 ? (8 * 1024) : (64 * 1024), + 0, + (is_type4) ? (8 * 1024) : (64 * 1024), ps2_read_cache_ram, ps2_read_cache_ramw, ps2_read_cache_raml, @@ -1163,31 +1246,47 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) NULL); mem_mapping_disable(&ps2.cache_mapping); - if (mem_size > 8192) - { - /* Only 8 MB supported on planar, create a memory expansion card for the rest */ - ps2_mca_mem_fffc_init(8); - } + if (ps2.planar_id == 0xfff9) { + if (mem_size > 4096) + { + /* Only 4 MB supported on planar, create a memory expansion card for the rest */ + if (mem_size > 12288) { + ps2_mca_mem_d071_init(4); + } else { + ps2_mca_mem_fffc_init(4); + } + } + } else { + if (mem_size > 8192) + { + /* Only 8 MB supported on planar, create a memory expansion card for the rest */ + if (mem_size > 16384) + ps2_mca_mem_d071_init(8); + else { + ps2_mca_mem_fffc_init(8); + } + } + } - if (gfxcard == VID_INTERNAL) + if (gfxcard == VID_INTERNAL) device_add(&ps1vga_mca_device); } static void ps2_mca_board_model_80_type2_init(int is486) -{ +{ ps2_mca_board_common_init(); ps2.split_addr = mem_size * 1024; mca_init(8); device_add(&keyboard_ps2_mca_device); - + ps2.planar_read = model_80_read; ps2.planar_write = model_80_write; - + device_add(&ps2_nvr_device); - + io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write, NULL, NULL, NULL); - + ps2.mem_regs[1] = 2; /* Note by Kotori: I rewrote this because the original code was using @@ -1221,7 +1320,7 @@ static void ps2_mca_board_model_80_type2_init(int is486) ps2.mem_regs[0] |= ((mem_size/1024) & 0x0f); mem_mapping_add(&ps2.split_mapping, - (mem_size+256) * 1024, + (mem_size+256) * 1024, 256*1024, ps2_read_split_ram, ps2_read_split_ramw, @@ -1233,15 +1332,21 @@ static void ps2_mca_board_model_80_type2_init(int is486) MEM_MAPPING_INTERNAL, NULL); mem_mapping_disable(&ps2.split_mapping); - + if ((mem_size > 4096) && !is486) { - /* Only 4 MB supported on planar, create a memory expansion card for the rest */ - ps2_mca_mem_fffc_init(4); + /* Only 4 MB supported on planar, create a memory expansion card for the rest */ + if (mem_size > 12288) + ps2_mca_mem_d071_init(4); + else { + ps2_mca_mem_fffc_init(4); + } } - if (gfxcard == VID_INTERNAL) + if (gfxcard == VID_INTERNAL) device_add(&ps1vga_mca_device); + + ps2.split_size = 0; } @@ -1249,14 +1354,17 @@ static void machine_ps2_common_init(const machine_t *model) { machine_common_init(model); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); dma16_init(); ps2_dma_init(); - device_add(&ps_nvr_device); + device_add(&ps_no_nmi_nvr_device); pic2_init(); - pit_ps2_init(); + int pit_type = ((pit_mode == -1 && is486) || pit_mode == 1) ? PIT_8254_FAST : PIT_8254; + pit_ps2_init(pit_type); nmi_mask = 0x80; @@ -1269,11 +1377,11 @@ machine_ps2_model_50_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmps2_m50/90x7420.zm13", - L"roms/machines/ibmps2_m50/90x7429.zm18", + ret = bios_load_interleaved("roms/machines/ibmps2_m50/90x7420.zm13", + "roms/machines/ibmps2_m50/90x7429.zm18", 0x000f0000, 131072, 0); - ret &= bios_load_aux_interleaved(L"roms/machines/ibmps2_m50/90x7423.zm14", - L"roms/machines/ibmps2_m50/90x7426.zm16", + ret &= bios_load_aux_interleaved("roms/machines/ibmps2_m50/90x7423.zm14", + "roms/machines/ibmps2_m50/90x7426.zm16", 0x000e0000, 65536, 0); if (bios_only || !ret) @@ -1281,7 +1389,31 @@ machine_ps2_model_50_init(const machine_t *model) machine_ps2_common_init(model); - ps2_mca_board_model_50_init(); + ps2.planar_id = 0xfbff; + ps2_mca_board_model_50_init(4); + + return ret; +} + +int +machine_ps2_model_60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/ibmps2_m50/90x7420.zm13", + "roms/machines/ibmps2_m50/90x7429.zm18", + 0x000f0000, 131072, 0); + ret &= bios_load_aux_interleaved("roms/machines/ibmps2_m50/90x7423.zm14", + "roms/machines/ibmps2_m50/90x7426.zm16", + 0x000e0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_ps2_common_init(model); + + ps2.planar_id = 0xf7ff; + ps2_mca_board_model_50_init(8); return ret; } @@ -1292,8 +1424,8 @@ machine_ps2_model_55sx_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmps2_m55sx/33f8146.zm41", - L"roms/machines/ibmps2_m55sx/33f8145.zm40", + ret = bios_load_interleaved("roms/machines/ibmps2_m55sx/33f8146.zm41", + "roms/machines/ibmps2_m55sx/33f8145.zm40", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -1301,19 +1433,40 @@ machine_ps2_model_55sx_init(const machine_t *model) machine_ps2_common_init(model); - ps2_mca_board_model_55sx_init(); + ps2.planar_id = 0xfffb; + ps2_mca_board_model_55sx_init(0, 4); return ret; } +int +machine_ps2_model_65sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/ibmps2_m65sx/64F3608.BIN", + "roms/machines/ibmps2_m65sx/64F3611.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_ps2_common_init(model); + + ps2.planar_id = 0xe3ff; + ps2_mca_board_model_55sx_init(1, 8); + + return ret; +} + int machine_ps2_model_70_type3_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmps2_m70_type3/70-a_even.bin", - L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", + ret = bios_load_interleaved("roms/machines/ibmps2_m70_type3/70-a_even.bin", + "roms/machines/ibmps2_m70_type3/70-a_odd.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -1321,41 +1474,41 @@ machine_ps2_model_70_type3_init(const machine_t *model) machine_ps2_common_init(model); - ps2_mca_board_model_70_type34_init(0); + ps2.planar_id = 0xf9ff; + + ps2_mca_board_model_70_type34_init(0, 4); return ret; } -#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) -int -machine_ps2_model_70_type4_init(const machine_t *model) -{ - int ret; - - ret = bios_load_interleaved(L"roms/machines/ibmps2_m70_type4/70-b_even.bin", - L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_ps2_common_init(model); - - ps2_mca_board_model_70_type34_init(1); - - return ret; -} -#endif - - int machine_ps2_model_80_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/ibmps2_m80/15f6637.bin", - L"roms/machines/ibmps2_m80/15f6639.bin", + ret = bios_load_interleaved("roms/machines/ibmps2_m80/15f6637.bin", + "roms/machines/ibmps2_m80/15f6639.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_ps2_common_init(model); + + ps2.planar_id = 0xfdff; + ps2_mca_board_model_80_type2_init(0); + + return ret; +} + +int +machine_ps2_model_80_axx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/ibmps2_m80/64f4356.bin", + "roms/machines/ibmps2_m80/64f4355.bin", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -1363,7 +1516,9 @@ machine_ps2_model_80_init(const machine_t *model) machine_ps2_common_init(model); - ps2_mca_board_model_80_type2_init(0); + ps2.planar_id = 0xfff9; + + ps2_mca_board_model_70_type34_init(0, 8); return ret; } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 26777dc77..d6c628a90 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -91,6 +91,7 @@ typedef struct { int con, coff, cursoron, blink; + int fullchange; int vsynctime; int vadj; uint16_t ma, maback; @@ -105,7 +106,7 @@ typedef struct { } t1kvid_t; typedef struct { - wchar_t *path; + char *path; int state; int count; @@ -298,11 +299,11 @@ static const scancode scancode_tandy[512] = { { {0}, {0} }, { {0}, {0} }, /*140*/ { {0}, {0} }, { {0}, {0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*144*/ - { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, - { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*148*/ - { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0x29, 0}, {0xa9, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0}, {0} }, { {0x2b, 0}, {0xab, 0} }, /*148*/ + { {0}, {0} }, { {0x4e, 0}, {0xce, 0} }, { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*14c*/ - { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x4a, 0}, {0xca, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*150*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*154*/ @@ -520,6 +521,9 @@ vid_out(uint16_t addr, uint8_t val, void *priv) t1kvid_t *vid = dev->vid; uint8_t old; + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + switch (addr) { case 0x03d4: vid->crtcreg = val & 0x1f; @@ -533,7 +537,7 @@ vid_out(uint16_t addr, uint8_t val, void *priv) vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; if (old != val) { if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; recalc_timings(dev); } } @@ -554,7 +558,7 @@ vid_out(uint16_t addr, uint8_t val, void *priv) break; case 0x03de: - if (vid->array_index & 16) + if (vid->array_index & 16) val &= 0xf; vid->array[vid->array_index & 0x1f] = val; if (dev->is_sl2) { @@ -589,6 +593,9 @@ vid_in(uint16_t addr, void *priv) t1kvid_t *vid = dev->vid; uint8_t ret = 0xff; + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + switch (addr) { case 0x03d4: ret = vid->crtcreg; @@ -615,7 +622,6 @@ vid_write(uint32_t addr, uint8_t val, void *priv) if (vid->memctrl == -1) return; - egawrites++; if (dev->is_sl2) { if (vid->array[5] & 1) vid->b8000[addr & 0xffff] = val; @@ -637,7 +643,6 @@ vid_read(uint32_t addr, void *priv) if (vid->memctrl == -1) return(0xff); - egareads++; if (dev->is_sl2) { if (vid->array[5] & 1) return(vid->b8000[addr & 0xffff]); @@ -671,7 +676,7 @@ vid_poll(void *priv) vid->stat |= 1; vid->linepos = 1; oldsc = vid->sc; - if ((vid->crtc[8] & 3) == 3) + if ((vid->crtc[8] & 3) == 3) vid->sc = (vid->sc << 1) & 7; if (vid->dispon) { if (vid->displine < vid->firstline) { @@ -712,7 +717,7 @@ vid_poll(void *priv) } if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ for (x = 0; x < vid->crtc[1]*2; x++) { - dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | + dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | vid->vram[((vid->ma << 1) + 1) & 0xffff]; vid->ma++; buffer32->line[(vid->displine << 1)][(x << 2) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 8] = @@ -726,7 +731,7 @@ vid_poll(void *priv) } } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; vid->ma++; buffer32->line[(vid->displine << 1)][(x << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8] = @@ -745,10 +750,10 @@ vid_poll(void *priv) } else if (vid->array[3] & 0x10) { /*160x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { if (dev->is_sl2) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; } else { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; } vid->ma++; @@ -794,7 +799,7 @@ vid_poll(void *priv) if (vid->mode & 0x20) { cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; @@ -807,8 +812,13 @@ vid_poll(void *priv) } } else { for (c = 0; c < 8; c++) { - buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = - cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (vid->sc == 8) { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } } if (drawcursor) { @@ -827,7 +837,7 @@ vid_poll(void *priv) if (vid->mode & 0x20) { cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; @@ -840,9 +850,15 @@ vid_poll(void *priv) cols[0]; } else { for (c = 0; c < 8; c++) { - buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = - buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = - cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (vid->sc == 8) { + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } } if (drawcursor) { @@ -873,7 +889,7 @@ vid_poll(void *priv) cols[2] = vid->array[(cols[2] & vid->array[1]) + 16] + 16; cols[3] = vid->array[(cols[3] & vid->array[1]) + 16] + 16; for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 8; c++) { @@ -884,7 +900,7 @@ vid_poll(void *priv) } } } else { - cols[0] = 0; + cols[0] = 0; cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | @@ -930,11 +946,11 @@ vid_poll(void *priv) if (vid->vc == vid->crtc[7] && !vid->sc) vid->stat |= 8; vid->displine++; - if (vid->displine >= 360) + if (vid->displine >= 360) vid->displine = 0; } else { timer_advance_u64(&vid->timer, vid->dispontime); - if (vid->dispon) + if (vid->dispon) vid->stat &= ~1; vid->linepos = 0; if (vid->vsynctime) { @@ -942,9 +958,9 @@ vid_poll(void *priv) if (! vid->vsynctime) vid->stat &= ~8; } - if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { - vid->con = 0; - vid->coff = 1; + if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { + vid->con = 0; + vid->coff = 1; } if (vid->vadj) { vid->sc++; @@ -968,12 +984,12 @@ vid_poll(void *priv) vid->vc &= 255; else vid->vc &= 127; - if (vid->vc == vid->crtc[6]) + if (vid->vc == vid->crtc[6]) vid->dispon = 0; if (oldvc == vid->crtc[4]) { vid->vc = 0; vid->vadj = vid->crtc[5]; - if (! vid->vadj) + if (! vid->vadj) vid->dispon = 1; if (! vid->vadj) { if (dev->is_sl2 && (vid->array[5] & 1)) @@ -1016,18 +1032,18 @@ vid_poll(void *priv) } if (enable_overscan) { - if (!dev->is_sl2 && vid->composite) - video_blit_memtoscreen(0, (vid->firstline - 4) << 1, 0, ((vid->lastline - vid->firstline) + 8) << 1, + if (!dev->is_sl2 && vid->composite) + video_blit_memtoscreen(0, (vid->firstline - 4) << 1, xsize, ((vid->lastline - vid->firstline) + 8) << 1); else - video_blit_memtoscreen_8(0, (vid->firstline - 4) << 1, 0, ((vid->lastline - vid->firstline) + 8) << 1, + video_blit_memtoscreen_8(0, (vid->firstline - 4) << 1, xsize, ((vid->lastline - vid->firstline) + 8) << 1); } else { - if (!dev->is_sl2 && vid->composite) - video_blit_memtoscreen(8, vid->firstline << 1, 0, (vid->lastline - vid->firstline) << 1, + if (!dev->is_sl2 && vid->composite) + video_blit_memtoscreen(8, vid->firstline << 1, xsize, (vid->lastline - vid->firstline) << 1); else - video_blit_memtoscreen_8(8, vid->firstline << 1, 0, (vid->lastline - vid->firstline) << 1, + video_blit_memtoscreen_8(8, vid->firstline << 1, xsize, (vid->lastline - vid->firstline) << 1); } } @@ -1068,7 +1084,7 @@ vid_poll(void *priv) vid->sc &= 31; vid->ma = vid->maback; } - if ((vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1)))) + if ((vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1)))) vid->con = 1; } } @@ -1127,72 +1143,66 @@ vid_init(tandy_t *dev) } -static const device_config_t vid_config[] = { +const device_config_t vid_config[] = { { - "display_type", "Display type", CONFIG_SELECTION, "", TANDY_RGB, - { - { - "RGB", TANDY_RGB - }, - { - "Composite", TANDY_COMPOSITE - }, - { - "" - } - } + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = TANDY_RGB, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = TANDY_RGB }, + { .description = "Composite", .value = TANDY_COMPOSITE }, + { .description = "" } + } }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; - -static const device_t vid_device = { - "Tandy 1000", - 0, 0, - NULL, vid_close, NULL, - NULL, - vid_speed_changed, - NULL, - vid_config +const device_t vid_device = { + .name = "Tandy 1000", + .internal_name = "tandy1000_video", + .flags = 0, + .local = 0, + .init = NULL, + .close = vid_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed, + .force_redraw = NULL, + .config = vid_config }; -static const device_t vid_device_hx = { - "Tandy 1000 HX", - 0, 0, - NULL, vid_close, NULL, - NULL, - vid_speed_changed, - NULL, - vid_config +const device_t vid_device_hx = { + .name = "Tandy 1000 HX", + .internal_name = "tandy1000_hx_video", + .flags = 0, + .local = 0, + .init = NULL, + .close = vid_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed, + .force_redraw = NULL, + .config = vid_config }; -static const device_t vid_device_sl = { - "Tandy 1000SL2", - 0, 1, - NULL, vid_close, NULL, - NULL, - vid_speed_changed, - NULL, - NULL +const device_t vid_device_sl = { + .name = "Tandy 1000SL2", + .internal_name = "tandy1000_sl_video", + .flags = 0, + .local = 1, + .init = NULL, + .close = vid_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed, + .force_redraw = NULL, + .config = NULL }; - -const device_t * -tandy1k_get_device(void) -{ - return &vid_device; -} - - -const device_t * -tandy1k_hx_get_device(void) -{ - return &vid_device_hx; -} - - static void eep_write(uint16_t addr, uint8_t val, void *priv) { @@ -1282,21 +1292,22 @@ eep_init(const device_t *info) switch (info->local) { case TYPE_TANDY1000HX: - eep->path = L"tandy1000hx.bin"; + eep->path = "tandy1000hx.bin"; break; case TYPE_TANDY1000SL2: - eep->path = L"tandy1000sl2.bin"; + eep->path = "tandy1000sl2.bin"; break; } - f = nvr_fopen(eep->path, L"rb"); + f = nvr_fopen(eep->path, "rb"); if (f != NULL) { if (fread(eep->store, 1, 128, f) != 128) fatal("eep_init(): Error reading Tandy EEPROM\n"); (void)fclose(f); - } + } else + memset(eep->store, 0x00, 128); io_sethandler(0x037c, 1, NULL,NULL,NULL, eep_write,NULL,NULL, eep); @@ -1310,7 +1321,7 @@ eep_close(void *priv) t1keep_t *eep = (t1keep_t *)priv; FILE *f = NULL; - f = nvr_fopen(eep->path, L"wb"); + f = nvr_fopen(eep->path, "wb"); if (f != NULL) { (void)fwrite(eep->store, 128, 1, f); (void)fclose(f); @@ -1319,25 +1330,34 @@ eep_close(void *priv) free(eep); } - static const device_t eep_1000hx_device = { - "Tandy 1000HX EEPROM", - 0, TYPE_TANDY1000HX, - eep_init, eep_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Tandy 1000HX EEPROM", + .internal_name = "eep_1000hx", + .flags = 0, + .local = TYPE_TANDY1000HX, + .init = eep_init, + .close = eep_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - static const device_t eep_1000sl2_device = { - "Tandy 1000SL2 EEPROM", - 0, TYPE_TANDY1000SL2, - eep_init, eep_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Tandy 1000SL2 EEPROM", + .internal_name = "eep_1000sl2", + .flags = 0, + .local = TYPE_TANDY1000SL2, + .init = eep_init, + .close = eep_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - static void tandy_write(uint16_t addr, uint8_t val, void *priv) { @@ -1447,8 +1467,8 @@ init_rom(tandy_t *dev) dev->rom = (uint8_t *)malloc(0x80000); #if 1 - if (! rom_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", - L"roms/machines/tandy1000sl2/8079048.hu2", + if (! rom_load_interleaved("roms/machines/tandy1000sl2/8079047.hu1", + "roms/machines/tandy1000sl2/8079048.hu2", 0x000000, 0x80000, 0, dev->rom)) { tandy_log("TANDY: unable to load BIOS for 1000/SL2 !\n"); free(dev->rom); @@ -1456,8 +1476,8 @@ init_rom(tandy_t *dev) return; } #else - f = rom_fopen(L"roms/machines/tandy1000sl2/8079047.hu1", L"rb"); - ff = rom_fopen(L"roms/machines/tandy1000sl2/8079048.hu2", L"rb"); + f = rom_fopen("roms/machines/tandy1000sl2/8079047.hu1", "rb"); + ff = rom_fopen("roms/machines/tandy1000sl2/8079048.hu2", "rb"); for (c = 0x0000; c < 0x80000; c += 2) { dev->rom[c] = getc(f); dev->rom[c + 1] = getc(ff); @@ -1494,13 +1514,15 @@ machine_tandy1k_init(const machine_t *model, int type) mem_mapping_set_addr(&ram_low_mapping, 0, dev->base); device_add(&keyboard_tandy_device); - keyboard_set_table(scancode_tandy); - if (fdc_type == FDC_INTERNAL) - device_add(&fdc_xt_device); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_tandy_device); + + video_reset(gfxcard); switch(type) { case TYPE_TANDY: + keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); vid_init(dev); @@ -1509,6 +1531,7 @@ machine_tandy1k_init(const machine_t *model, int type) break; case TYPE_TANDY1000HX: + keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); vid_init(dev); @@ -1529,8 +1552,7 @@ machine_tandy1k_init(const machine_t *model, int type) break; } - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; eep_data_out = 0x0000; } @@ -1548,7 +1570,7 @@ machine_tandy_init(const machine_t *model) { int ret; - ret = bios_load_linearr(L"roms/machines/tandy/tandy1t1.020", + ret = bios_load_linearr("roms/machines/tandy/tandy1t1.020", 0x000f0000, 131072, 0); if (bios_only || !ret) @@ -1565,7 +1587,7 @@ machine_tandy1000hx_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/tandy1000hx/v020000.u12", + ret = bios_load_linear("roms/machines/tandy1000hx/v020000.u12", 0x000e0000, 131072, 0); if (bios_only || !ret) @@ -1582,8 +1604,8 @@ machine_tandy1000sl2_init(const machine_t *model) { int ret; - ret = bios_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", - L"roms/machines/tandy1000sl2/8079048.hu2", + ret = bios_load_interleaved("roms/machines/tandy1000sl2/8079047.hu1", + "roms/machines/tandy1000sl2/8079048.hu2", 0x000f0000, 65536, 0x18000); if (bios_only || !ret) diff --git a/src/machine/m_v86p.c b/src/machine/m_v86p.c new file mode 100644 index 000000000..022c9baec --- /dev/null +++ b/src/machine/m_v86p.c @@ -0,0 +1,96 @@ +/* + * 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. + * + * Victor V86P portable computer emulation. + * + * Author: Lubomir Rintel, + * + * Copyright 2021 Lubomir Rintel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/rom.h> +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/keyboard.h> +#include <86box/chipset.h> +#include <86box/sio.h> +#include <86box/video.h> + +int +machine_v86p_init(const machine_t *model) +{ + int ret, rom = 0; + + ret = bios_load_interleavedr("roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_122089_Even.rom", + "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_122089_Odd.rom", + 0x000f8000, 65536, 0); + + if (!ret) { + /* Try an older version of the BIOS. */ + rom = 1; + ret = bios_load_interleavedr("roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_090489_Even.rom", + "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_090489_Odd.rom", + 0x000f8000, 65536, 0); + } + + if (!ret) { + /* Try JVERNET's BIOS. */ + rom = 2; + ret = bios_load_linear("roms/machines/v86p/V86P.ROM", + 0x000f0000, 65536, 0); + } + + if (bios_only || !ret) + return ret; + + if (rom == 2) + loadfont("roms/machines/v86p/V86P.FON", 8); + else + loadfont("roms/machines/v86p/v86pfont.rom", 8); + + machine_common_init(model); + + device_add(&ct_82c100_device); + device_add(&f82c606_device); + + device_add(&keyboard_xt_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + + if (gfxcard == VID_INTERNAL) + device_add(&f82c425_video_device); + + return ret; +} diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 2f55040e6..5b31920c5 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -11,26 +11,26 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> +#include <86box/hdc.h> #include <86box/gameport.h> #include <86box/ibm_5161.h> #include <86box/keyboard.h> #include <86box/rom.h> #include <86box/machine.h> - +#include <86box/chipset.h> static void machine_xt_common_init(const machine_t *model) { machine_common_init(model); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); - if (fdc_type == FDC_INTERNAL) - device_add(&fdc_xt_device); - nmi_init(); - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } @@ -39,16 +39,16 @@ machine_pc_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ibmpc/BIOS_5150_24APR81_U33.BIN", + ret = bios_load_linear("roms/machines/ibmpc/BIOS_5150_24APR81_U33.BIN", 0x000fe000, 40960, 0); if (ret) { - bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U29 - 5700019.bin", + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U29 - 5700019.bin", 0x000f6000, 8192, 0); - bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U30 - 5700027.bin", + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U30 - 5700027.bin", 0x000f8000, 8192, 0); - bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U31 - 5700035.bin", + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U31 - 5700035.bin", 0x000fa000, 8192, 0); - bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U32 - 5700043.bin", + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U32 - 5700043.bin", 0x000fc000, 8192, 0); } @@ -68,19 +68,19 @@ machine_pc82_init(const machine_t *model) { int ret, ret2; - ret = bios_load_linear(L"roms/machines/ibmpc82/pc102782.bin", + ret = bios_load_linear("roms/machines/ibmpc82/pc102782.bin", 0x000fe000, 40960, 0); if (ret) { - ret2 = bios_load_aux_linear(L"roms/machines/ibmpc82/ibm-basic-1.10.rom", + ret2 = bios_load_aux_linear("roms/machines/ibmpc82/ibm-basic-1.10.rom", 0x000f6000, 32768, 0); if (!ret2) { - bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.f6", + bios_load_aux_linear("roms/machines/ibmpc82/basicc11.f6", 0x000f6000, 8192, 0); - bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.f8", + bios_load_aux_linear("roms/machines/ibmpc82/basicc11.f8", 0x000f8000, 8192, 0); - bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.fa", + bios_load_aux_linear("roms/machines/ibmpc82/basicc11.fa", 0x000fa000, 8192, 0); - bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.fc", + bios_load_aux_linear("roms/machines/ibmpc82/basicc11.fc", 0x000fc000, 8192, 0); } } @@ -111,15 +111,15 @@ machine_xt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ibmxt/xt.rom", + ret = bios_load_linear("roms/machines/ibmxt/xt.rom", 0x000f0000, 65536, 0); if (!ret) { - ret = bios_load_linear(L"roms/machines/ibmxt/1501512.u18", + ret = bios_load_linear("roms/machines/ibmxt/1501512.u18", 0x000fe000, 65536, 0x6000); if (ret) { - bios_load_aux_linear(L"roms/machines/ibmxt/1501512.u18", + bios_load_aux_linear("roms/machines/ibmxt/1501512.u18", 0x000f8000, 24576, 0); - bios_load_aux_linear(L"roms/machines/ibmxt/5000027.u19", + bios_load_aux_linear("roms/machines/ibmxt/5000027.u19", 0x000f0000, 32768, 0); } } @@ -140,7 +140,7 @@ machine_genxt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/genxt/pcxt.rom", + ret = bios_load_linear("roms/machines/genxt/pcxt.rom", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -151,18 +151,17 @@ machine_genxt_init(const machine_t *model) return ret; } - int machine_xt86_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + ret = bios_load_linear("roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", 0x000fe000, 65536, 0x6000); if (ret) { - (void) bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + (void) bios_load_aux_linear("roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", 0x000f8000, 24576, 0); - (void) bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", + (void) bios_load_aux_linear("roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", 0x000f0000, 32768, 0); } @@ -186,13 +185,44 @@ machine_xt_clone_init(const machine_t *model) machine_xt_common_init(model); } +int +machine_xt_americxt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/americxt/AMERICXT.ROM", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} int machine_xt_amixt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/amixt/ami_8088_bios_31jan89.bin", + ret = bios_load_linear("roms/machines/amixt/ami_8088_bios_31jan89.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + +int +machine_xt_znic_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/znic/ibmzen.rom", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -209,7 +239,7 @@ machine_xt_dtk_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/dtk/dtk_erso_2.42_2764.bin", + ret = bios_load_linear("roms/machines/dtk/dtk_erso_2.42_2764.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -226,7 +256,7 @@ machine_xt_jukopc_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/jukopc/000o001.bin", + ret = bios_load_linear("roms/machines/jukopc/000o001.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -239,11 +269,11 @@ machine_xt_jukopc_init(const machine_t *model) int -machine_xt_open_xt_init(const machine_t *model) +machine_xt_openxt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/open_xt/pcxt31.bin", + ret = bios_load_linear("roms/machines/openxt/pcxt31.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -254,31 +284,34 @@ machine_xt_open_xt_init(const machine_t *model) return ret; } + int -machine_xt_hed919_init(const machine_t *model) +machine_xt_pcxt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/hed919/Hedaka_HED-919_bios_version_3.28f.bin", - 0x000fe000, 8192, 0); + ret = bios_load_linear("roms/machines/pcxt/u18.rom", + 0x000f8000, 65536, 0); + if (ret) { + bios_load_aux_linear("roms/machines/pcxt/u19.rom", + 0x000f0000, 32768, 0); + } if (bios_only || !ret) return ret; machine_xt_clone_init(model); - if (mem_size > 640) - mem_remap_top(mem_size - 640); - return ret; } + int machine_xt_pxxt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/pxxt/000p001.bin", + ret = bios_load_linear("roms/machines/pxxt/000p001.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -286,5 +319,245 @@ machine_xt_pxxt_init(const machine_t *model) machine_xt_clone_init(model); - return 1; + return ret; +} + + +int +machine_xt_iskra3104_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/iskra3104/198.bin", + "roms/machines/iskra3104/199.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_pc4i_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pc4i/NCR_PC4i_BIOSROM_1985.BIN", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_mpc1600_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/mpc1600/mpc4.34_merged.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_pc82_device); + + machine_xt_common_init(model); + + return ret; +} + + +int +machine_xt_pcspirit_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pcspirit/u1101.bin", + 0x000fe000, 16384, 0); + + if (ret) { + bios_load_aux_linear("roms/machines/pcspirit/u1103.bin", + 0x000fc000, 8192, 0); + } + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_pc82_device); + + machine_xt_common_init(model); + + return ret; +} + + +int +machine_xt_pc700_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pc700/multitech pc-700 3.1.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_pc_device); + + machine_xt_common_init(model); + + return ret; +} + + +int +machine_xt_pc500_init(const machine_t* model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pc500/rom404.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_pc_device); + + machine_xt_common_init(model); + + return ret; +} + +int +machine_xt_vendex_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/vendex/Vendex Turbo 888 XT - ROM BIOS - VER 2.03C.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + +int +machine_xt_super16t_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/super16t/Hyundai SUPER-16T - System BIOS HEA v1.12Ta (16k)(MBM27128)(1986).BIN", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + /* On-board FDC cannot be disabled */ + device_add(&fdc_xt_device); + + return ret; +} + +int +machine_xt_super16te_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/super16te/Hyundai SUPER-16TE - System BIOS v2.00Id (16k)(D27128A)(1989).BIN", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + /* On-board FDC cannot be disabled */ + device_add(&fdc_xt_device); + + return ret; +} + +int +machine_xt_top88_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/top88/Hyosung Topstar 88T - BIOS version 3.0.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + /* On-board FDC cannot be disabled */ + device_add(&fdc_xt_device); + + return ret; +} + +int +machine_xt_kaypropc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/kaypropc/Kaypro_v2.03K.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + +int +machine_xt_sansx16_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/sansx16/tmm27128ad.bin.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + /* On-board FDC cannot be disabled */ + device_add(&fdc_xt_device); + + return ret; +} + +int +machine_xt_bw230_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/bw230/bondwell.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; } diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 1b84a10de..a705f0e2b 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -37,13 +37,12 @@ #include <86box/lpt.h> #include <86box/machine.h> - int -machine_xt_compaq_init(const machine_t *model) +machine_xt_compaq_deskpro_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", + ret = bios_load_linear("roms/machines/deskpro/Compaq - BIOS - Revision J - 106265-002.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -51,17 +50,45 @@ machine_xt_compaq_init(const machine_t *model) machine_common_init(model); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_compaq_device); if (fdc_type == FDC_INTERNAL) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; lpt1_remove(); - lpt1_init(0x03bc); + lpt1_init(LPT_MDA_ADDR); + + return ret; +} + + +int +machine_xt_compaq_portable_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_common_init(model); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + device_add(&keyboard_xt_compaq_device); + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + nmi_init(); + if (joystick_type) + device_add(&gameport_device); + + lpt1_remove(); + lpt1_init(LPT_MDA_ADDR); return ret; } diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index d0b0fdf81..21681a5c2 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -16,6 +16,7 @@ #include <86box/timer.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/fdc_ext.h> #include <86box/gameport.h> #include <86box/keyboard.h> @@ -139,7 +140,7 @@ machine_xt_laserxt_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/ltxt/27c64.bin", + ret = bios_load_linear("roms/machines/ltxt/27c64.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -158,7 +159,7 @@ machine_xt_lxt3_init(const machine_t *model) { int ret; - ret = bios_load_linear(L"roms/machines/lxt3/27c64d.bin", + ret = bios_load_linear("roms/machines/lxt3/27c64d.bin", 0x000fe000, 8192, 0); if (bios_only || !ret) @@ -166,13 +167,14 @@ machine_xt_lxt3_init(const machine_t *model) machine_common_init(model); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_lxt3_device); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; laserxt_init(1); diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c new file mode 100644 index 000000000..62fcda138 --- /dev/null +++ b/src/machine/m_xt_olivetti.c @@ -0,0 +1,866 @@ +/* + * 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 the Olivetti XT-compatible machines. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ + +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/ppi.h> +#include <86box/nmi.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/nvr.h> +#include <86box/keyboard.h> +#include <86box/mouse.h> +#include <86box/rom.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/gameport.h> +#include <86box/port_6x.h> +#include <86box/sound.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> +#include <86box/machine.h> +#include <86box/vid_cga.h> +#include <86box/vid_ogc.h> +#include <86box/vid_colorplus.h> +#include <86box/vid_cga_comp.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 + +#define PLANTRONICS_MODE 1 +#define OLIVETTI_OGC_MODE 0 + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +typedef struct { + /* Keyboard stuff. */ + int wantirq; + uint8_t command; + uint8_t status; + uint8_t out; + uint8_t output_port; + int param, + param_total; + uint8_t params[16]; + uint8_t scan[7]; + + /* Mouse stuff. */ + int mouse_mode; + int x, y, b; + pc_timer_t send_delay_timer; +} m24_kbd_t; + +typedef struct { + ogc_t ogc; + colorplus_t colorplus; + int mode; +} m19_vid_t; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; + +video_timings_t timing_m19_vid = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + +const device_t m19_vid_device; + + +#ifdef ENABLE_M24VID_LOG +int m24vid_do_log = ENABLE_M24VID_LOG; + + +static void +m24_log(const char *fmt, ...) +{ + va_list ap; + + if (m24vid_do_log) { + va_start(ap, fmt); + vfprintf(stdlog, fmt, ap); + va_end(ap); + fflush(stdlog); + } +} +#else +#define m24_log(fmt, ...) +#endif + + +static void +m24_kbd_poll(void *priv) +{ + m24_kbd_t *m24_kbd = (m24_kbd_t *)priv; + + timer_advance_u64(&m24_kbd->send_delay_timer, 1000 * TIMER_USEC); + if (m24_kbd->wantirq) { + m24_kbd->wantirq = 0; + picint(2); +#if ENABLE_KEYBOARD_LOG + m24_log("M24: take IRQ\n"); +#endif + } + + if (!(m24_kbd->status & STAT_OFULL) && key_queue_start != key_queue_end) { +#if ENABLE_KEYBOARD_LOG + m24_log("Reading %02X from the key queue at %i\n", + m24_kbd->out, key_queue_start); +#endif + m24_kbd->out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + m24_kbd->status |= STAT_OFULL; + m24_kbd->status &= ~STAT_IFULL; + m24_kbd->wantirq = 1; + } +} + + +static void +m24_kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +static void +m24_kbd_adddata_ex(uint16_t val) +{ + kbd_adddata_process(val, m24_kbd_adddata); +} + + +static void +m24_kbd_write(uint16_t port, uint8_t val, void *priv) +{ + m24_kbd_t *m24_kbd = (m24_kbd_t *)priv; + +#if ENABLE_KEYBOARD_LOG + m24_log("M24: write %04X %02X\n", port, val); +#endif + +#if 0 + if (ram[8] == 0xc3) + output = 3; +#endif + switch (port) { + case 0x60: + if (m24_kbd->param != m24_kbd->param_total) { + m24_kbd->params[m24_kbd->param++] = val; + if (m24_kbd->param == m24_kbd->param_total) { + switch (m24_kbd->command) { + case 0x11: + m24_kbd->mouse_mode = 0; + m24_kbd->scan[0] = m24_kbd->params[0]; + m24_kbd->scan[1] = m24_kbd->params[1]; + m24_kbd->scan[2] = m24_kbd->params[2]; + m24_kbd->scan[3] = m24_kbd->params[3]; + m24_kbd->scan[4] = m24_kbd->params[4]; + m24_kbd->scan[5] = m24_kbd->params[5]; + m24_kbd->scan[6] = m24_kbd->params[6]; + break; + + case 0x12: + m24_kbd->mouse_mode = 1; + m24_kbd->scan[0] = m24_kbd->params[0]; + m24_kbd->scan[1] = m24_kbd->params[1]; + m24_kbd->scan[2] = m24_kbd->params[2]; + break; + + default: + m24_log("M24: bad keyboard command complete %02X\n", m24_kbd->command); + } + } + } else { + m24_kbd->command = val; + switch (val) { + case 0x01: /*Self-test*/ + break; + + case 0x05: /*Read ID*/ + m24_kbd_adddata(0x00); + break; + + case 0x11: + m24_kbd->param = 0; + m24_kbd->param_total = 9; + break; + + case 0x12: + m24_kbd->param = 0; + m24_kbd->param_total = 4; + break; + + default: + m24_log("M24: bad keyboard command %02X\n", val); + } + } + break; + + case 0x61: + ppi.pb = val; + + 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); + break; + } +} + + +static uint8_t +m24_kbd_read(uint16_t port, void *priv) +{ + m24_kbd_t *m24_kbd = (m24_kbd_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + ret = m24_kbd->out; + if (key_queue_start == key_queue_end) { + m24_kbd->status &= ~STAT_OFULL; + m24_kbd->wantirq = 0; + } else { + m24_kbd->out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + m24_kbd->status |= STAT_OFULL; + m24_kbd->status &= ~STAT_IFULL; + m24_kbd->wantirq = 1; + } + break; + + case 0x61: + ret = ppi.pb; + break; + + case 0x64: + ret = m24_kbd->status; + m24_kbd->status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); + break; + + default: + m24_log("\nBad M24 keyboard read %04X\n", port); + } + + return(ret); +} + + +static void +m24_kbd_close(void *priv) +{ + m24_kbd_t *kbd = (m24_kbd_t *)priv; + + /* Stop the timer. */ + timer_disable(&kbd->send_delay_timer); + + /* Disable scanning. */ + keyboard_scan = 0; + + keyboard_send = NULL; + + io_removehandler(0x0060, 2, + m24_kbd_read, NULL, NULL, m24_kbd_write, NULL, NULL, kbd); + io_removehandler(0x0064, 1, + m24_kbd_read, NULL, NULL, m24_kbd_write, NULL, NULL, kbd); + + free(kbd); +} + + +static void +m24_kbd_reset(void *priv) +{ + m24_kbd_t *m24_kbd = (m24_kbd_t *)priv; + + /* Initialize the keyboard. */ + m24_kbd->status = STAT_LOCK | STAT_CD; + m24_kbd->wantirq = 0; + keyboard_scan = 1; + m24_kbd->param = m24_kbd->param_total = 0; + m24_kbd->mouse_mode = 0; + m24_kbd->scan[0] = 0x1c; + m24_kbd->scan[1] = 0x53; + m24_kbd->scan[2] = 0x01; + m24_kbd->scan[3] = 0x4b; + m24_kbd->scan[4] = 0x4d; + m24_kbd->scan[5] = 0x48; + m24_kbd->scan[6] = 0x50; +} + + +static int +ms_poll(int x, int y, int z, int b, void *priv) +{ + m24_kbd_t *m24_kbd = (m24_kbd_t *)priv; + + m24_kbd->x += x; + m24_kbd->y += y; + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); + + if ((b & 1) && !(m24_kbd->b & 1)) + m24_kbd_adddata(m24_kbd->scan[0]); + if (!(b & 1) && (m24_kbd->b & 1)) + m24_kbd_adddata(m24_kbd->scan[0] | 0x80); + m24_kbd->b = (m24_kbd->b & ~1) | (b & 1); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); + + if ((b & 2) && !(m24_kbd->b & 2)) + m24_kbd_adddata(m24_kbd->scan[2]); + if (!(b & 2) && (m24_kbd->b & 2)) + m24_kbd_adddata(m24_kbd->scan[2] | 0x80); + m24_kbd->b = (m24_kbd->b & ~2) | (b & 2); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); + + if ((b & 4) && !(m24_kbd->b & 4)) + m24_kbd_adddata(m24_kbd->scan[1]); + if (!(b & 4) && (m24_kbd->b & 4)) + m24_kbd_adddata(m24_kbd->scan[1] | 0x80); + m24_kbd->b = (m24_kbd->b & ~4) | (b & 4); + + if (m24_kbd->mouse_mode) { + if (((key_queue_end - key_queue_start) & 0xf) > 12) return(0xff); + + if (!m24_kbd->x && !m24_kbd->y) return(0xff); + + m24_kbd->y = -m24_kbd->y; + + if (m24_kbd->x < -127) m24_kbd->x = -127; + if (m24_kbd->x > 127) m24_kbd->x = 127; + if (m24_kbd->x < -127) m24_kbd->x = 0x80 | ((-m24_kbd->x) & 0x7f); + + if (m24_kbd->y < -127) m24_kbd->y = -127; + if (m24_kbd->y > 127) m24_kbd->y = 127; + if (m24_kbd->y < -127) m24_kbd->y = 0x80 | ((-m24_kbd->y) & 0x7f); + + m24_kbd_adddata(0xfe); + m24_kbd_adddata(m24_kbd->x); + m24_kbd_adddata(m24_kbd->y); + + m24_kbd->x = m24_kbd->y = 0; + } else { + while (m24_kbd->x < -4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24_kbd->x += 4; + m24_kbd_adddata(m24_kbd->scan[3]); + } + while (m24_kbd->x > 4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24_kbd->x -= 4; + m24_kbd_adddata(m24_kbd->scan[4]); + } + while (m24_kbd->y < -4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24_kbd->y += 4; + m24_kbd_adddata(m24_kbd->scan[5]); + } + while (m24_kbd->y > 4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24_kbd->y -= 4; + m24_kbd_adddata(m24_kbd->scan[6]); + } + } + + return(0); +} + + +static void +m24_kbd_init(m24_kbd_t *kbd) +{ + + /* Initialize the keyboard. */ + io_sethandler(0x0060, 2, + m24_kbd_read, NULL, NULL, m24_kbd_write, NULL, NULL, kbd); + io_sethandler(0x0064, 1, + m24_kbd_read, NULL, NULL, m24_kbd_write, NULL, NULL, kbd); + keyboard_send = m24_kbd_adddata_ex; + m24_kbd_reset(kbd); + timer_add(&kbd->send_delay_timer, m24_kbd_poll, kbd, 1); + + /* Tell mouse driver about our internal mouse. */ + mouse_reset(); + mouse_set_poll(ms_poll, kbd); + + keyboard_set_table(scancode_xt); + keyboard_set_is_amstrad(0); +} + + +static void +m19_vid_out(uint16_t addr, uint8_t val, void *priv) +{ + m19_vid_t *vid = (m19_vid_t *)priv; + int oldmode = vid->mode; + + /* activating plantronics mode */ + if (addr == 0x3dd) { + /* already in graphics mode */ + if ((val & 0x30) && (vid->ogc.cga.cgamode & 0x2)) + vid->mode = PLANTRONICS_MODE; + else + vid->mode = OLIVETTI_OGC_MODE; + /* setting graphics mode */ + } else if (addr == 0x3d8) { + if ((val & 0x2) && (vid->colorplus.control & 0x30)) + vid->mode = PLANTRONICS_MODE; + else + vid->mode = OLIVETTI_OGC_MODE; + } + /* video mode changed */ + if (oldmode != vid->mode) { + /* activate Plantronics emulation */ + if (vid->mode == PLANTRONICS_MODE){ + timer_disable(&vid->ogc.cga.timer); + timer_set_delay_u64(&vid->colorplus.cga.timer, 0); + /* return to OGC mode */ + } else { + timer_disable(&vid->colorplus.cga.timer); + timer_set_delay_u64(&vid->ogc.cga.timer, 0); + } + + colorplus_recalctimings(&vid->colorplus); + ogc_recalctimings(&vid->ogc); + } + + colorplus_out(addr, val, &vid->colorplus); + ogc_out(addr, val, &vid->ogc); +} + + +static uint8_t +m19_vid_in(uint16_t addr, void *priv) +{ + m19_vid_t *vid = (m19_vid_t *)priv; + + if (vid->mode == PLANTRONICS_MODE) + return colorplus_in(addr, &vid->colorplus); + else + return ogc_in(addr, &vid->ogc); +} + + +static uint8_t +m19_vid_read(uint32_t addr, void *priv) +{ + m19_vid_t *vid = (m19_vid_t *)priv; + + vid->colorplus.cga.mapping = vid->ogc.cga.mapping; + if (vid->mode == PLANTRONICS_MODE) + return colorplus_read(addr, &vid->colorplus); + else + return ogc_read(addr, &vid->ogc); +} + + +static void +m19_vid_write(uint32_t addr, uint8_t val, void *priv) +{ + m19_vid_t *vid = (m19_vid_t *)priv; + + colorplus_write(addr, val, &vid->colorplus); + ogc_write(addr, val, &vid->ogc); +} + + +static void +m19_vid_close(void *priv) +{ + m19_vid_t *vid = (m19_vid_t *)priv; + + free(vid->ogc.cga.vram); + free(vid->colorplus.cga.vram); + free(vid); +} + + +static void +m19_vid_speed_changed(void *priv) +{ + m19_vid_t *vid = (m19_vid_t *)priv; + + colorplus_recalctimings(&vid->colorplus); + ogc_recalctimings(&vid->ogc); +} + + +static void +m19_vid_init(m19_vid_t *vid) +{ + device_context(&m19_vid_device); + + /* int display_type; */ + vid->mode = OLIVETTI_OGC_MODE; + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_m19_vid); + + /* display_type = device_get_config_int("display_type"); */ + + /* OGC emulation part begin */ + loadfont_ex("roms/machines/m19/BIOS.BIN", 1, 90); + /* composite is not working yet */ + vid->ogc.cga.composite = 0; // (display_type != CGA_RGB); + vid->ogc.cga.revision = device_get_config_int("composite_type"); + vid->ogc.cga.snow_enabled = device_get_config_int("snow_enabled"); + + vid->ogc.cga.vram = malloc(0x8000); + + /* cga_comp_init(vid->ogc.cga.revision); */ + + vid->ogc.cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (vid->ogc.cga.rgb_type << 1); + cgapal_rebuild(); + ogc_mdaattr_rebuild(); + + /* color display */ + if (device_get_config_int("rgb_type")==0 || device_get_config_int("rgb_type") == 4) + vid->ogc.mono_display = 0; + else + vid->ogc.mono_display = 1; + /* OGC emulation part end */ + + /* Plantronics emulation part begin*/ + /* composite is not working yet */ + vid->colorplus.cga.composite = 0; //(display_type != CGA_RGB); + /* vid->colorplus.cga.snow_enabled = device_get_config_int("snow_enabled"); */ + + vid->colorplus.cga.vram = malloc(0x8000); + + /* vid->colorplus.cga.cgamode = 0x1; */ + /* Plantronics emulation part end*/ + + timer_add(&vid->ogc.cga.timer, ogc_poll, &vid->ogc, 1); + timer_add(&vid->colorplus.cga.timer, colorplus_poll, &vid->colorplus, 1); + timer_disable(&vid->colorplus.cga.timer); + mem_mapping_add(&vid->ogc.cga.mapping, 0xb8000, 0x08000, m19_vid_read, NULL, NULL, m19_vid_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, vid); + io_sethandler(0x03d0, 0x0010, m19_vid_in, NULL, NULL, m19_vid_out, NULL, NULL, vid); + + vid->mode = OLIVETTI_OGC_MODE; + + device_context_restore(); +} + +const device_t m24_kbd_device = { + .name = "Olivetti M24 keyboard and mouse", + .internal_name = "m24_kbd", + .flags = 0, + .local = 0, + .init = NULL, + .close = m24_kbd_close, + .reset = m24_kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_config_t m19_vid_config[] = { + { + /* Olivetti / ATT compatible displays */ + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = CGA_RGB, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "" } + } + }, + { + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1, + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +const device_t m19_vid_device = { + .name = "Olivetti M19 graphics card", + .internal_name = "m19_vid", + .flags = 0, + .local = 0, + .init = NULL, + .close = m19_vid_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = m19_vid_speed_changed, + .force_redraw = NULL, + .config = m19_vid_config +}; + +static uint8_t +m24_read(uint16_t port, void *priv) +{ + uint8_t ret = 0x00; + int i, fdd_count = 0; + + switch (port) { + /* + * port 66: + * DIPSW-0 on mainboard (off=present=1) + * bit 7 - 2764 (off) / 2732 (on) ROM (BIOS < 1.36) + * bit 7 - Use (off) / do not use (on) memory bank 1 (BIOS >= 1.36) + * bit 6 - n/a + * bit 5 - 8530 (off) / 8250 (on) SCC + * bit 4 - 8087 present + * bits 3-0 - installed memory + */ + case 0x66: + /* Switch 5 - 8087 present */ + if (hasfpu) + ret |= 0x10; + /* + * Switches 1, 2, 3, 4 - installed memory + * Switch 8 - Use memory bank 1 + */ + switch (mem_size) { + case 128: + ret |= 0x1; + break; + case 256: + ret |= 0x2|0x80; + break; + case 384: + ret |= 0x1|0x2|0x80; + break; + case 512: + ret |= 0x8; + break; + case 640: + default: + ret |= 0x1|0x8|0x80; + break; + } + /* + * port 67: + * DIPSW-1 on mainboard (off=present=1) + * bits 7-6 - number of drives + * bits 5-4 - display adapter + * bit 3 - video scroll CPU (on) / slow scroll (off) + * bit 2 - BIOS HD on mainboard (on) / on controller (off) + * bit 1 - FDD fast (off) / slow (on) start drive + * bit 0 - 96 TPI (720 KB 3.5") (off) / 48 TPI (360 KB 5.25") FDD drive + * + * Display adapter: + * off off 80x25 mono + * off on 40x25 color + * on off 80x25 color + * on on EGA/VGA (works only for BIOS ROM 1.43) + */ + case 0x67: + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + + /* Switches 7, 8 - floppy drives. */ + if (!fdd_count) + ret |= 0x00; + else + ret |= ((fdd_count - 1) << 6); + + /* Switches 5, 6 - monitor type */ + if (video_is_mda()) + ret |= 0x30; + else if (video_is_cga()) + ret |= 0x20; /* 0x10 would be 40x25 */ + else + ret |= 0x0; + + /* Switch 3 - Disable internal BIOS HD */ + ret |= 0x4; + + /* Switch 2 - Set fast startup */ + ret |= 0x2; + } + + return(ret); +} + +int +machine_xt_m24_init(const machine_t *model) +{ + int ret; + m24_kbd_t *m24_kbd; + + ret = bios_load_interleaved("roms/machines/m24/olivetti_m24_bios_version_1.44_low_even.bin", + "roms/machines/m24/olivetti_m24_bios_version_1.44_high_odd.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + m24_kbd = (m24_kbd_t *) malloc(sizeof(m24_kbd_t)); + memset(m24_kbd, 0x00, sizeof(m24_kbd_t)); + + machine_common_init(model); + + /* On-board FDC can be disabled only on M24SP */ + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + + /* Address 66-67 = mainboard dip-switch settings */ + io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, NULL); + + /* FIXME: make sure this is correct?? */ + device_add(&at_nvr_device); + + standalone_gameport_type = &gameport_device; + + nmi_init(); + + video_reset(gfxcard); + + if (gfxcard == VID_INTERNAL) + device_add(&ogc_m24_device); + + m24_kbd_init(m24_kbd); + device_add_ex(&m24_kbd_device, m24_kbd); + + return ret; +} + +/* + * Current bugs: + * - handles only 360kb floppy drives (drive type and capacity selectable with jumpers mapped to unknown memory locations) + */ +int +machine_xt_m240_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/m240/olivetti_m240_pch6_2.04_low.bin", + "roms/machines/m240/olivetti_m240_pch5_2.04_high.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_common_init(model); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + /* Address 66-67 = mainboard dip-switch settings */ + io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, NULL); + + /* + * port 60: should return jumper settings only under unknown conditions + * SWB on mainboard (off=1) + * bit 7 - use BIOS HD on mainboard (on) / on controller (off) + * bit 6 - use OCG/CGA display adapter (on) / other display adapter (off) + */ + device_add(&keyboard_at_olivetti_device); + device_add(&port_6x_olivetti_device); + + /* FIXME: make sure this is correct?? */ + device_add(&at_nvr_device); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + + if (joystick_type) + device_add(&gameport_device); + + nmi_init(); + + return ret; +} + + +/* + * Current bugs: + * - 640x400x2 graphics mode not supported (bit 0 of register 0x3de cannot be set) + * - optional mouse emulation missing + * - setting CPU speed at 4.77MHz sometimes throws a timer error. If the machine is hard-resetted, the error disappears. + */ +int +machine_xt_m19_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m19/BIOS.BIN", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + m19_vid_t *vid; + + /* Do not move memory allocation elsewhere. */ + vid = (m19_vid_t *) malloc(sizeof(m19_vid_t)); + memset(vid, 0x00, sizeof(m19_vid_t)); + + machine_common_init(model); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + /* On-board FDC cannot be disabled */ + device_add(&fdc_xt_device); + + nmi_init(); + + video_reset(gfxcard); + + m19_vid_init(vid); + device_add_ex(&m19_vid_device, vid); + + device_add(&keyboard_xt_olivetti_device); + + pit_set_clock(14318184.0); + + return ret; +} diff --git a/src/machine/m_xt_philips.c b/src/machine/m_xt_philips.c new file mode 100644 index 000000000..b10e3a37e --- /dev/null +++ b/src/machine/m_xt_philips.c @@ -0,0 +1,206 @@ +/* + * 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 the Philips XT-compatible machines. + * + * + * + * Authors: EngiNerd + * + * Copyright 2020-2021 EngiNerd. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/nmi.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/hdc.h> +#include <86box/gameport.h> +#include <86box/ibm_5161.h> +#include <86box/keyboard.h> +#include <86box/rom.h> +#include <86box/machine.h> +#include <86box/chipset.h> +#include <86box/io.h> +#include <86box/video.h> + + +typedef struct +{ + uint8_t reg; +} philips_t; + + +#ifdef ENABLE_PHILIPS_LOG +int philips_do_log = ENABLE_PHILIPS_LOG; +static void +philips_log(const char *fmt, ...) +{ + va_list ap; + + if (philips_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define philips_log(fmt, ...) +#endif + +static void +philips_write(uint16_t port, uint8_t val, void *priv) +{ + philips_t *dev = (philips_t *) priv; + + switch (port) { + /* port 0xc0 + * bit 7: turbo + * bits 4-5: rtc read/set (I2C Bus SDA/SCL?) + * bit 2: parity disabled + */ + case 0xc0: + dev->reg = val; + if (val & 0x80) + cpu_dynamic_switch(cpu); + else + cpu_dynamic_switch(0); + break; + } + + philips_log("Philips XT Mainboard: Write %02x at %02x\n", val, port); + +} + +static uint8_t +philips_read(uint16_t port, void *priv) +{ + philips_t *dev = (philips_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + /* port 0xc0 + * bit 7: turbo + * bits 4-5: rtc read/set + * bit 2: parity disabled + */ + case 0xc0: + ret = dev->reg; + break; + } + + philips_log("Philips XT Mainboard: Read %02x at %02x\n", ret, port); + + return ret; +} + + +static void +philips_close(void *priv) +{ + philips_t *dev = (philips_t *) priv; + + free(dev); +} + +static void * +philips_init(const device_t *info) +{ + philips_t *dev = (philips_t *) malloc(sizeof(philips_t)); + memset(dev, 0, sizeof(philips_t)); + + dev->reg = 0x40; + + io_sethandler(0x0c0, 0x01, philips_read, NULL, NULL, philips_write, NULL, NULL, dev); + + return dev; +} + +const device_t philips_device = { + .name = "Philips XT Mainboard", + .internal_name = "philips", + .flags = 0, + .local = 0, + .init = philips_init, + .close = philips_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +void +machine_xt_philips_common_init(const machine_t *model) +{ + machine_common_init(model); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + nmi_init(); + + standalone_gameport_type = &gameport_device; + + device_add(&keyboard_pc_device); + + device_add(&philips_device); + + device_add(&xta_hd20_device); + +} + +int +machine_xt_p3105_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p3105/philipsnms9100.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_philips_common_init(model); + + /* On-board FDC cannot be disabled */ + device_add(&fdc_xt_device); + + return ret; +} + +int +machine_xt_p3120_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/p3120/philips_p3120.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_philips_common_init(model); + + device_add(&gc100a_device); + + device_add(&fdc_at_device); + + return ret; +} diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index bf31be9f7..ba96b74e7 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -9,16 +9,16 @@ * Implementation of the Toshiba T1000 and T1200 portables. * * The T1000 is the T3100e's little brother -- a real laptop - * with a rechargeable battery. + * with a rechargeable battery. * * Features: 80C88 at 4.77MHz * - 512k system RAM * - 640x200 monochrome LCD - * - 82-key keyboard + * - 82-key keyboard * - Real-time clock. Not the normal 146818, but a TC8521, * which is a 4-bit chip. * - A ROM drive (128k, 256k or 512k) which acts as a mini - * hard drive and contains a copy of DOS 2.11. + * hard drive and contains a copy of DOS 2.11. * - 160 bytes of non-volatile RAM for the CONFIG.SYS used * when booting from the ROM drive. Possibly physically * located in the keyboard controller RAM. @@ -40,7 +40,7 @@ * and programming level. * * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] - * or 0Dh [10Mb]. + * or 0Dh [10Mb]. * * The hard drive is a 20MB (615/2/26) RLL 3.5" drive. * @@ -154,7 +154,7 @@ typedef struct { uint8_t turbo; /* NVRAM control */ - uint8_t nvr_c0; + uint8_t nvr_c0; uint8_t nvr_tick; int nvr_addr; uint8_t nvr_active; @@ -239,8 +239,7 @@ tc8521_time_get(uint8_t *regs, struct tm *tm) else tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); -//FIXME: wday - tm->tm_wday = 1; /* Dummy value so it is not uninitialized. */ + tm->tm_wday = regs[TC8521_WEEKDAY]; tm->tm_mday = nibbles(TC8521_DAY); tm->tm_mon = (nibbles(TC8521_MONTH) - 1); tm->tm_year = (nibbles(TC8521_YEAR) + 1980); @@ -358,7 +357,7 @@ static uint32_t ems_execaddr(t1000_t *sys, int pg, uint16_t val) { if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */ - if (!sys->ems_pages) return(0); /* No EMS available: all used by + if (!sys->ems_pages) return(0); /* No EMS available: all used by * HardRAM or conventional RAM */ val &= 0x7f; @@ -455,7 +454,7 @@ ems_set_port(t1000_t *sys, uint8_t val) #endif if (sys->ems_port) { for (n = 0; n <= 0xc000; n += 0x4000) { - io_removehandler(sys->ems_port+n, 1, + io_removehandler(sys->ems_port+n, 1, ems_in,NULL,NULL, ems_out,NULL,NULL, sys); } sys->ems_port = 0; @@ -469,7 +468,7 @@ ems_set_port(t1000_t *sys, uint8_t val) } else { sys->ems_port = 0x208 | (val << 4); for (n = 0; n <= 0xc000; n += 0x4000) { - io_sethandler(sys->ems_port+n, 1, + io_sethandler(sys->ems_port+n, 1, ems_in,NULL,NULL, ems_out,NULL,NULL, sys); } sys->ems_port = 0; @@ -498,7 +497,7 @@ ems_read_ram(uint32_t addr, void *priv) if (pg < 0) return(0xff); addr = sys->page_exec[pg] + (addr & 0x3fff); - return(ram[addr]); + return(ram[addr]); } @@ -569,7 +568,7 @@ ems_write_ramw(uint32_t addr, uint16_t val, void *priv) t1000_log("-> %06x val=%04x\n", addr, val); #endif - if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; + if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; *(uint16_t *)&ram[addr] = val; } @@ -584,7 +583,7 @@ ems_write_raml(uint32_t addr, uint32_t val, void *priv) if (pg < 0) return; addr = sys->page_exec[pg] + (addr & 0x3fff); - if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; + if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; *(uint32_t *)&ram[addr] = val; } @@ -621,7 +620,7 @@ read_ctl(uint16_t addr, void *priv) break; default: - ret = (sys->sys_ctl[addr & 0x0f]); + ret = (sys->sys_ctl[addr & 0x0f]); } return(ret); @@ -664,8 +663,8 @@ write_ctl(uint16_t addr, uint8_t val, void *priv) { t1000_video_enable(val & 0x01 ? 0 : 1); } - break; - + break; + case 0x0f: /* EMS control */ switch (sys->sys_ctl[0x0e]) { case 0x50: @@ -735,7 +734,7 @@ t1000_write_nvram(uint16_t addr, uint8_t val, void *priv) case 0xc1: /* Write next byte to NVRAM */ if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) { - if (sys->t1000_nvram[sys->nvr_addr] != val) + if (sys->t1000_nvram[sys->nvr_addr] != val) nvr_dosave = 1; sys->t1000_nvram[sys->nvr_addr] = val; } @@ -774,7 +773,7 @@ static void write_t1200_nvram(uint32_t addr, uint8_t value, void *priv) { t1000_t *sys = (t1000_t *)priv; - if (sys->t1200_nvram[addr & 0x7FF] != value) + if (sys->t1200_nvram[addr & 0x7FF] != value) nvr_dosave = 1; sys->t1200_nvram[addr & 0x7FF] = value; @@ -802,9 +801,9 @@ t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); - mem_mapping_enable(&sys->rom_mapping); + mem_mapping_enable(&sys->rom_mapping); } else { - mem_mapping_disable(&sys->rom_mapping); + mem_mapping_disable(&sys->rom_mapping); } } @@ -842,14 +841,6 @@ t1000_read_roml(uint32_t addr, void *priv) return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); } - -const device_t * -t1000_get_device(void) -{ - return(&t1000_video_device); -} - - int machine_xt_t1000_init(const machine_t *model) { @@ -858,7 +849,7 @@ machine_xt_t1000_init(const machine_t *model) int ret; - ret = bios_load_linear(L"roms/machines/t1000/t1000.rom", + ret = bios_load_linear("roms/machines/t1000/t1000.rom", 0x000f8000, 32768, 0); if (bios_only || !ret) @@ -870,7 +861,7 @@ machine_xt_t1000_init(const machine_t *model) t1000.ems_port_index = 7; /* EMS disabled */ /* Load the T1000 CGA Font ROM. */ - loadfont(L"roms/machines/t1000/t1000font.rom", 2); + loadfont("roms/machines/t1000/t1000font.bin", 2); /* * The ROM drive is optional. @@ -878,7 +869,7 @@ machine_xt_t1000_init(const machine_t *model) * If the file is missing, continue to boot; the BIOS will * complain 'No ROM drive' but boot normally from floppy. */ - f = rom_fopen(L"roms/machines/t1000/t1000dos.rom", L"rb"); + f = rom_fopen("roms/machines/t1000/t1000dos.rom", "rb"); if (f != NULL) { t1000.romdrive = malloc(T1000_ROMSIZE); if (t1000.romdrive) { @@ -890,7 +881,7 @@ machine_xt_t1000_init(const machine_t *model) } mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000, t1000_read_rom,t1000_read_romw,t1000_read_roml, - NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + NULL,NULL,NULL, NULL, MEM_MAPPING_EXTERNAL, &t1000); mem_mapping_disable(&t1000.rom_mapping); /* Map the EMS page frame */ @@ -920,7 +911,7 @@ machine_xt_t1000_init(const machine_t *model) machine_common_init(model); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_device); t1000.fdc = device_add(&fdc_xt_device); nmi_init(); @@ -951,7 +942,7 @@ machine_xt_t1200_init(const machine_t *model) int ret; - ret = bios_load_linear(L"roms/machines/t1200/t1200_019e.ic15.bin", + ret = bios_load_linear("roms/machines/t1200/t1200_019e.ic15.bin", 0x000f8000, 32768, 0); if (bios_only || !ret) @@ -961,13 +952,13 @@ machine_xt_t1200_init(const machine_t *model) t1000.is_t1200 = 1; t1000.ems_port_index = 7; /* EMS disabled */ - /* Load the T1200 CGA Font ROM. */ - loadfont(L"roms/machines/t1200/t1000font.bin", 2); + /* Load the T1000 CGA Font ROM. */ + loadfont("roms/machines/t1000/t1000font.bin", 2); /* Map the EMS page frame */ for (pg = 0; pg < 4; pg++) { - mem_mapping_add(&t1000.mapping[pg], - 0xd0000 + (0x4000 * pg), 16384, + mem_mapping_add(&t1000.mapping[pg], + 0xd0000 + (0x4000 * pg), 16384, ems_read_ram,ems_read_ramw,ems_read_raml, ems_write_ram,ems_write_ramw,ems_write_raml, NULL, MEM_MAPPING_EXTERNAL, &t1000); @@ -985,10 +976,10 @@ machine_xt_t1200_init(const machine_t *model) mem_mapping_add(&t1000.nvr_mapping, 0x000f0000, 2048, read_t1200_nvram, NULL, NULL, - write_t1200_nvram, NULL, NULL, - NULL, 0, &t1000); + write_t1200_nvram, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, &t1000); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_device); t1000.fdc = device_add(&fdc_xt_t1x00_device); nmi_init(); @@ -1021,7 +1012,7 @@ t1000_configsys_load(void) int size; memset(t1000.t1000_nvram, 0x1a, sizeof(t1000.t1000_nvram)); - f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb"); + f = plat_fopen(nvr_path("t1000_config.nvr"), "rb"); if (f != NULL) { size = sizeof(t1000.t1000_nvram); if (fread(t1000.t1000_nvram, 1, size, f) != size) @@ -1037,7 +1028,7 @@ t1000_configsys_save(void) FILE *f; int size; - f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb"); + f = plat_fopen(nvr_path("t1000_config.nvr"), "wb"); if (f != NULL) { size = sizeof(t1000.t1000_nvram); if (fwrite(t1000.t1000_nvram, 1, size, f) != size) @@ -1054,7 +1045,7 @@ t1200_state_load(void) int size; memset(t1000.t1200_nvram, 0, sizeof(t1000.t1200_nvram)); - f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"rb"); + f = plat_fopen(nvr_path("t1200_state.nvr"), "rb"); if (f != NULL) { size = sizeof(t1000.t1200_nvram); if (fread(t1000.t1200_nvram, 1, size, f) != size) @@ -1070,7 +1061,7 @@ t1200_state_save(void) FILE *f; int size; - f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"wb"); + f = plat_fopen(nvr_path("t1200_state.nvr"), "wb"); if (f != NULL) { size = sizeof(t1000.t1200_nvram); if (fwrite(t1000.t1200_nvram, 1, size, f) != size) @@ -1087,7 +1078,7 @@ t1000_emsboard_load(void) FILE *f; if (mem_size > 512) { - f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); + f = plat_fopen(nvr_path("t1000_ems.nvr"), "rb"); if (f != NULL) { fread(&ram[512 * 1024], 1024, (mem_size - 512), f); fclose(f); @@ -1102,7 +1093,7 @@ t1000_emsboard_save(void) FILE *f; if (mem_size > 512) { - f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); + f = plat_fopen(nvr_path("t1000_ems.nvr"), "wb"); if (f != NULL) { fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f); fclose(f); diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c index 7b298d330..817b54042 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/machine/m_xt_t1000_vid.c @@ -103,7 +103,7 @@ typedef struct t1000_t { mem_mapping_t mapping; - cga_t cga; /* The CGA is used for the external + cga_t cga; /* The CGA is used for the external * display; most of its registers are * ignored by the plasma display. */ @@ -113,12 +113,13 @@ typedef struct t1000_t uint8_t attrmap; /* Attribute mapping register */ uint64_t dispontime, dispofftime; - + int linepos, displine; int vc; int dispon; int vsynctime; uint8_t video_options; + uint8_t backlight, invert; uint8_t *vram; } t1000_t; @@ -144,12 +145,12 @@ static void t1000_out(uint16_t addr, uint8_t val, void *p) case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: /* Register 0x12 controls the attribute mappings for the * LCD screen. */ - if (t1000->cga.crtcreg == 0x12) + if (t1000->cga.crtcreg == 0x12) { - t1000->attrmap = val; + t1000->attrmap = val; t1000_recalcattrs(t1000); return; - } + } cga_out(addr, val, &t1000->cga); t1000_recalctimings(t1000); @@ -181,7 +182,7 @@ static uint8_t t1000_in(uint16_t addr, void *p) return val; } } - + return cga_in(addr, &t1000->cga); } @@ -191,17 +192,15 @@ static uint8_t t1000_in(uint16_t addr, void *p) static void t1000_write(uint32_t addr, uint8_t val, void *p) { t1000_t *t1000 = (t1000_t *)p; - egawrites++; t1000->vram[addr & 0x3fff] = val; - sub_cycles(4); + cycles -= 4; } - + static uint8_t t1000_read(uint32_t addr, void *p) { t1000_t *t1000 = (t1000_t *)p; - egareads++; - sub_cycles(4); + cycles -= 4; return t1000->vram[addr & 0x3fff]; } @@ -272,8 +271,8 @@ static void t1000_text_row80(t1000_t *t1000) if (t1000->cga.cgamode & 0x20) /* Blink */ { - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; if (blink) cols[1] = cols[0]; } else @@ -344,8 +343,8 @@ static void t1000_text_row40(t1000_t *t1000) if (t1000->cga.cgamode & 0x20) /* Blink */ { - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; if (blink) cols[1] = cols[0]; } else @@ -357,7 +356,7 @@ static void t1000_text_row40(t1000_t *t1000) { for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); } } @@ -365,7 +364,7 @@ static void t1000_text_row40(t1000_t *t1000) { for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2+1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; } } @@ -433,7 +432,7 @@ static void t1000_cgaline4(t1000_t *t1000) { default: case 0: ink0 = ink1 = grey; break; - case 1: if (t1000->displine & 1) + case 1: if (t1000->displine & 1) { ink0 = grey; ink1 = grey; } @@ -442,7 +441,7 @@ static void t1000_cgaline4(t1000_t *t1000) ink0 = blue; ink1 = grey; } break; - case 2: if (t1000->displine & 1) + case 2: if (t1000->displine & 1) { ink0 = grey; ink1 = blue; } @@ -473,10 +472,10 @@ static void t1000_poll(void *p) /* Set the font used for the external display */ t1000->cga.fontbase = ((t1000->video_options & 3) * 256); - + if (t1000->enabled) /* Disable internal chipset */ mem_mapping_enable(&t1000->mapping); - else + else mem_mapping_disable(&t1000->mapping); } /* Switch between internal plasma and external CRT display. */ @@ -504,20 +503,20 @@ static void t1000_poll(void *p) } /* Graphics */ - if (t1000->cga.cgamode & 0x02) + if (t1000->cga.cgamode & 0x02) { if (t1000->cga.cgamode & 0x10) t1000_cgaline6(t1000); else t1000_cgaline4(t1000); } - else + else if (t1000->cga.cgamode & 0x01) /* High-res text */ { - t1000_text_row80(t1000); + t1000_text_row80(t1000); } else { - t1000_text_row40(t1000); + t1000_text_row40(t1000); } } t1000->displine++; @@ -557,14 +556,14 @@ static void t1000_poll(void *p) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + video_blit_memtoscreen(0, 0, xsize, ysize); frames++; /* Fixed 640x200 resolution */ video_res_x = T1000_XSIZE; video_res_y = T1000_YSIZE; - if (t1000->cga.cgamode & 0x02) + if (t1000->cga.cgamode & 0x02) { if (t1000->cga.cgamode & 0x10) video_bpp = 1; @@ -582,28 +581,43 @@ static void t1000_recalcattrs(t1000_t *t1000) int n; /* val behaves as follows: - * Bit 0: Attributes 01-06, 08-0E are inverse video - * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are inverse video + * are inverse video * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF * are bold */ /* Set up colours */ - blue = makecol(0x2D, 0x39, 0x5A); - grey = makecol(0x85, 0xa0, 0xD6); + if (t1000->invert) { + if (t1000->backlight) { + grey = makecol(0x2D, 0x39, 0x5A); + blue = makecol(0x85, 0xa0, 0xD6); + } else { + grey = makecol(0x0f, 0x21, 0x3f); + blue = makecol(0x1C, 0x71, 0x31); + } + } else { + if (t1000->backlight) { + blue = makecol(0x2D, 0x39, 0x5A); + grey = makecol(0x85, 0xa0, 0xD6); + } else { + blue = makecol(0x0f, 0x21, 0x3f); + grey = makecol(0x1C, 0x71, 0x31); + } + } /* Initialise the attribute mapping. Start by defaulting everything * to grey on blue, and with bold set by bit 3 */ for (n = 0; n < 256; n++) { boldcols[n] = (n & 8) != 0; - blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][0] = normcols[n][0] = blue; blinkcols[n][1] = normcols[n][1] = grey; } - /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the - * passed value. Exclude x0 and x8, which are always grey on + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always grey on * blue. */ for (n = 0x11; n <= 0xFF; n++) { @@ -620,7 +634,7 @@ static void t1000_recalcattrs(t1000_t *t1000) } if (t1000->attrmap & 8) boldcols[n] = 1; /* Bold */ } - /* Set up the 01-0E range, controlled by bits 0 and 1 of the + /* Set up the 01-0E range, controlled by bits 0 and 1 of the * passed value. When blinking is enabled this also affects 81-8E. */ for (n = 0x01; n <= 0x0E; n++) { @@ -641,7 +655,7 @@ static void t1000_recalcattrs(t1000_t *t1000) } if (t1000->attrmap & 2) boldcols[n] = 1; } - /* Colours 07 and 0F are always blue on grey. If blinking is + /* Colours 07 and 0F are always blue on grey. If blinking is * enabled so are 87 and 8F. */ for (n = 0x07; n <= 0x0F; n += 8) { @@ -678,12 +692,15 @@ static void *t1000_init(const device_t *info) { t1000_t *t1000 = malloc(sizeof(t1000_t)); memset(t1000, 0, sizeof(t1000_t)); - loadfont(L"roms/machines/t1000/t1000font.bin", 8); + loadfont("roms/machines/t1000/t1000font.bin", 8); cga_init(&t1000->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t1000); t1000->internal = 1; + t1000->backlight = device_get_config_int("backlight"); + t1000->invert = device_get_config_int("invert"); + /* 16k video RAM */ t1000->vram = malloc(0x4000); @@ -719,52 +736,62 @@ static void t1000_close(void *p) static void t1000_speed_changed(void *p) { t1000_t *t1000 = (t1000_t *)p; - + t1000_recalctimings(t1000); } -static const device_config_t t1000_config[] = -{ - { - .name = "display_language", - .description = "Language", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "USA", - .value = 0 - }, - { - .description = "Danish", - .value = 1 - } - }, - .default_int = 0 - }, - { - .type = -1 - } +static const device_config_t t1000_config[] = { + { + .name = "display_language", + .description = "Language", + .type = CONFIG_SELECTION, + .selection = { + { .description = "USA", .value = 0 }, + { .description = "Danish", .value = 1 } + }, + .default_int = 0 + }, + { + .name = "backlight", + .description = "Enable backlight", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "invert", + .description = "Invert colors", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; - const device_t t1000_video_device = { - "Toshiba T1000 Video", - 0, 0, - t1000_init, t1000_close, NULL, - NULL, - t1000_speed_changed, - NULL, - t1000_config + .name = "Toshiba T1000 Video", + .internal_name = "t1000_video", + .flags = 0, + .local = 0, + .init = t1000_init, + .close = t1000_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = t1000_speed_changed, + .force_redraw = NULL, + .config = t1000_config }; - const device_t t1200_video_device = { - "Toshiba T1200 Video", - 0, 0, - t1000_init, t1000_close, NULL, - NULL, - t1000_speed_changed, - NULL, - t1000_config + .name = "Toshiba T1200 Video", + .internal_name = "t1200_video", + .flags = 0, + .local = 0, + .init = t1000_init, + .close = t1000_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = t1000_speed_changed, + .force_redraw = NULL, + .config = t1000_config }; diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index 875a2ba11..2a6187570 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -11,13 +11,16 @@ #include <86box/device.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/fdc_ext.h> #include <86box/nmi.h> #include <86box/nvr.h> #include <86box/gameport.h> #include <86box/keyboard.h> +#include <86box/flash.h> #include <86box/lpt.h> #include <86box/rom.h> #include <86box/hdc.h> +#include <86box/port_6x.h> #include <86box/video.h> #include <86box/machine.h> #include "cpu.h" @@ -72,97 +75,126 @@ xi8088_bios_128kb(void) static void * xi8088_init(const device_t *info) { - /* even though the bios by default turns the turbo off when controlling by hotkeys, pcem always starts at full speed */ xi8088.turbo = 1; xi8088.turbo_setting = device_get_config_int("turbo_setting"); xi8088.bios_128kb = device_get_config_int("bios_128kb"); + mem_set_mem_state(0x0a0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state(0x0c0000, 0x08000, device_get_config_int("umb_c0000h_c7fff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state(0x0c8000, 0x08000, device_get_config_int("umb_c8000h_cffff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state(0x0d0000, 0x08000, device_get_config_int("umb_d0000h_d7fff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state(0x0d8000, 0x08000, device_get_config_int("umb_d8000h_dffff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state(0x0e0000, 0x08000, device_get_config_int("umb_e0000h_e7fff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state(0x0e8000, 0x08000, device_get_config_int("umb_e8000h_effff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); + mem_set_mem_state(0x0f0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + return &xi8088; } - -static const device_config_t xi8088_config[] = -{ - { - .name = "turbo_setting", - .description = "Turbo", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Always at selected speed", - .value = 0 - }, - { - .description = "Hotkeys (starts off)", - .value = 1 - } - }, - .default_int = 0 +static const device_config_t xi8088_config[] = { + { + .name = "turbo_setting", + .description = "Turbo", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "Always at selected speed", + .value = 0 + }, + { + .description = "BIOS setting + Hotkeys (off during POST)", + .value = 1 + } }, - { - .name = "bios_128kb", - .description = "BIOS size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "64KB", - .value = 0 - }, - { - .description = "128KB", - .value = 1 - } - }, - .default_int = 1 + .default_int = 0 + }, + { + .name = "bios_128kb", + .description = "BIOS size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "64KB starting from 0xF0000", + .value = 0 + }, + { + .description = "128KB starting from 0xE0000 (address MSB inverted, last 64KB first)", + .value = 1 + } }, - { - .type = -1 - } + .default_int = 1 + }, + { + .name = "umb_c0000h_c7fff", + .description = "Map 0xc0000-0xc7fff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_c8000h_cffff", + .description = "Map 0xc8000-0xcffff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_d0000h_d7fff", + .description = "Map 0xd0000-0xd7fff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_d8000h_dffff", + .description = "Map 0xd8000-0xdffff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_e0000h_e7fff", + .description = "Map 0xe0000-0xe7fff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_e8000h_effff", + .description = "Map 0xe8000-0xeffff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; - -const device_t xi8088_device = -{ - "Xi8088", - 0, - 0, - xi8088_init, - NULL, - NULL, - NULL, - NULL, - NULL, - xi8088_config +const device_t xi8088_device = { + .name = "Xi8088", + .internal_name = "xi8088", + .flags = 0, + .local = 0, + .init = xi8088_init, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = xi8088_config }; - -const device_t * -xi8088_get_device(void) -{ - return &xi8088_device; -} - - int machine_xt_xi8088_init(const machine_t *model) { int ret; if (bios_only) { - ret = bios_load_linear_inverted(L"roms/machines/xi8088/bios-xi8088-128k.bin", + ret = bios_load_linear_inverted("roms/machines/xi8088/bios-xi8088-128k.bin", 0x000e0000, 131072, 0); - ret |= bios_load_linear(L"roms/machines/xi8088/bios-xi8088.bin", + ret |= bios_load_linear("roms/machines/xi8088/bios-xi8088.bin", 0x000f0000, 65536, 0); } else { device_add(&xi8088_device); if (xi8088_bios_128kb()) { - ret = bios_load_linear_inverted(L"roms/machines/xi8088/bios-xi8088-128k.bin", + ret = bios_load_linear_inverted("roms/machines/xi8088/bios-xi8088-128k.bin", 0x000e0000, 131072, 0); } else { - ret = bios_load_linear(L"roms/machines/xi8088/bios-xi8088.bin", + ret = bios_load_linear("roms/machines/xi8088/bios-xi8088.bin", 0x000f0000, 65536, 0); } } @@ -170,15 +202,18 @@ machine_xt_xi8088_init(const machine_t *model) if (bios_only || !ret) return ret; - /* TODO: set UMBs? See if PCem always sets when we have > 640KB ram and avoids conflicts when a peripheral uses the same memory space */ machine_common_init(model); + + if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); + device_add(&keyboard_ps2_xi8088_device); + device_add(&port_6x_xi8088_device); nmi_init(); device_add(&ibmat_nvr_device); pic2_init(); - if (joystick_type != JOYSTICK_TYPE_NONE) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; + device_add(&sst_flash_39sf010_device); return ret; } diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index c0448bd09..6eab9aee2 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -14,9 +14,11 @@ * Authors: Sarah Walker, * Miran Grca, * TheCollector1995, + * EngiNerd * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. + * Copyright 2020 EngiNerd. */ #include #include @@ -42,6 +44,8 @@ #include <86box/lpt.h> #include <86box/serial.h> #include <86box/machine.h> +#include <86box/io.h> +#include <86box/vid_cga.h> typedef struct { @@ -72,20 +76,20 @@ zenith_scratchpad_init(const device_t *info) zenith_t *dev; dev = (zenith_t *)malloc(sizeof(zenith_t)); - memset(dev, 0x00, sizeof(zenith_t)); - + memset(dev, 0x00, sizeof(zenith_t)); + dev->scratchpad_ram = malloc(0x4000); - + mem_mapping_add(&dev->scratchpad_mapping, 0xf0000, 0x4000, zenith_scratchpad_read, NULL, NULL, zenith_scratchpad_write, NULL, NULL, dev->scratchpad_ram, MEM_MAPPING_EXTERNAL, dev); - + return dev; } -static void +static void zenith_scratchpad_close(void *p) { zenith_t *dev = (zenith_t *)p; @@ -94,42 +98,106 @@ zenith_scratchpad_close(void *p) free(dev); } - static const device_t zenith_scratchpad_device = { - "Zenith scratchpad RAM", - 0, 0, - zenith_scratchpad_init, zenith_scratchpad_close, NULL, - NULL, - NULL, - NULL + .name = "Zenith scratchpad RAM", + .internal_name = "zenith_scratchpad", + .flags = 0, + .local = 0, + .init = zenith_scratchpad_init, + .close = zenith_scratchpad_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +void +machine_zenith_init(const machine_t *model){ + machine_common_init(model); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + + device_add(&zenith_scratchpad_device); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + device_add(&keyboard_xt_zenith_device); + + nmi_init(); + +} + +/* + * Current bugs and limitations: + * - missing NVRAM implementation + */ int -machine_xt_zenith_init(const machine_t *model) -{ +machine_xt_z184_init(const machine_t *model) +{ int ret; - ret = bios_load_linear(L"roms/machines/zdsupers/z184m v3.1d.10d", + ret = bios_load_linear("roms/machines/zdsupers/z184m v3.1d.10d", 0x000f8000, 32768, 0); if (bios_only || !ret) - return ret; + return ret; + + machine_zenith_init(model); - machine_common_init(model); - - if (fdc_type == FDC_INTERNAL) - device_add(&fdc_xt_device); - lpt1_remove(); /* only one parallel port */ lpt2_remove(); lpt1_init(0x278); - device_add(&i8250_device); - serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ - device_add(&zenith_scratchpad_device); - pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); - device_add(&keyboard_xt_compaq_device); - nmi_init(); + device_add(&ns8250_device); + serial_set_next_inst(SERIAL_MAX); /* So that serial_standalone_init() won't do anything. */ + + device_add(&cga_device); + + return ret; +} + +int +machine_xt_z151_init(const machine_t *model) +{ + int ret; + ret = bios_load_linear("roms/machines/zdsz151/444-229-18.bin", + 0x000fc000, 32768, 0); + if (ret) { + bios_load_aux_linear("roms/machines/zdsz151/444-260-18.bin", + 0x000f8000, 16384, 0); + } + + if (bios_only || !ret) + return ret; + + machine_zenith_init(model); + + return ret; +} + +/* + * Current bugs and limitations: + * - Memory board support for EMS currently missing + */ +int +machine_xt_z159_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/zdsz159/z159m v2.9e.10d", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_zenith_init(model); + + /* parallel port is on the memory board */ + lpt1_remove(); /* only one parallel port */ + lpt2_remove(); + lpt1_init(0x278); return ret; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 7f91ff3c5..774b972c2 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -27,6 +27,8 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/timer.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> #include <86box/dma.h> #include <86box/pic.h> #include <86box/pit.h> @@ -34,14 +36,16 @@ #include <86box/rom.h> #include <86box/lpt.h> #include <86box/serial.h> +#include <86box/gameport.h> #include "cpu.h" #include <86box/video.h> #include <86box/machine.h> +#include <86box/isamem.h> int bios_only = 0; int machine; -int AT, PCI; +// int AT, PCI; #ifdef ENABLE_MACHINE_LOG @@ -71,18 +75,39 @@ machine_init_ex(int m) int ret = 0; if (!bios_only) { - machine_log("Initializing as \"%s\"\n", machine_getname_ex(m)); + machine_log("Initializing as \"%s\"\n", machine_getname()); + + is_vpc = 0; + standalone_gameport_type = NULL; + gameport_instance_id = 0; /* Set up the architecture flags. */ - AT = IS_ARCH(machine, MACHINE_AT); - PCI = IS_ARCH(machine, MACHINE_PCI); + // AT = IS_AT(machine); + // PCI = IS_ARCH(machine, MACHINE_BUS_PCI); - /* Resize the memory. */ + cpu_set(); + pc_speed_changed(); + + /* Reset the memory state. */ mem_reset(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; lpt_init(); - smbase = 0x30000; + if (cassette_enable) + device_add(&cassette_device); + + cart_reset(); + + /* Prepare some video-related things if we're using internal + or no video. */ + video_pre_reset(gfxcard); + + /* Reset any ISA memory cards. */ + isamem_reset(); + + /* Reset the fast off stuff. */ + cpu_fast_off_reset(); } /* All good, boot the machine! */ @@ -92,6 +117,14 @@ machine_init_ex(int m) if (bios_only || !ret) return ret; + if (gfxcard != VID_NONE) { + if (ibm8514_enabled) { + ibm8514_device_add(); + } + if (xga_enabled) + xga_device_add(); + } + /* Reset the graphics card (or do nothing if it was already done by the machine's init function). */ video_reset(gfxcard); @@ -112,15 +145,32 @@ int machine_available(int m) { int ret; + device_t *d = (device_t *) machine_getdevice(m); bios_only = 1; - ret = machine_init_ex(m); + + ret = device_available(d); + /* Do not check via machine_init_ex() if the device is not NULL and + it has a CONFIG_BIOS field. */ + if ((d == NULL) || (ret != -1)) + ret = machine_init_ex(m); bios_only = 0; - return ret; + + return !!ret; } +void +pit_irq0_timer(int new_out, int old_out) +{ + if (new_out && !old_out) + picint(1); + + if (!new_out) + picintc(1); +} + void machine_common_init(const machine_t *model) { @@ -128,7 +178,10 @@ machine_common_init(const machine_t *model) pic_init(); dma_init(); - cpu_set(); + int pit_type = IS_AT(machine) ? PIT_8254 : PIT_8253; + /* Select fast PIT if needed */ + if ((pit_mode == -1 && is486) || pit_mode == 1) + pit_type += 2; - pit_common_init(!!AT, pit_irq0_timer, NULL); + pit_common_init(pit_type, pit_irq0_timer, NULL); } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index a66014c1f..7194ca2d9 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1,25 +1,25 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Handling of the emulated machines. + * Handling of the emulated machines. * - * NOTES: OpenAT wip for 286-class machine with open BIOS. - * PS2_M80-486 wip, pending receipt of TRM's for machine. + * NOTES: OpenAT wip for 286-class machine with open BIOS. + * PS2_M80-486 wip, pending receipt of TRM's for machine. * * * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -31,363 +31,11012 @@ #include <86box/rom.h> #include <86box/device.h> #include <86box/machine.h> +#include <86box/keyboard.h> +#include <86box/sound.h> +#include <86box/video.h> +// Temporarily here till we move everything out into the right files +extern const device_t pcjr_device; +extern const device_t m19_vid_device; +extern const device_t vid_device; +extern const device_t vid_device_hx; +extern const device_t t1000_video_device; +extern const device_t xi8088_device; +extern const device_t cga_device; +extern const device_t vid_1512_device; +extern const device_t vid_1640_device; +extern const device_t vid_pc2086_device; +extern const device_t vid_pc3086_device; +extern const device_t vid_200_device; +extern const device_t vid_ppc512_device; +extern const device_t vid_device_sl; +extern const device_t t1200_video_device; +extern const device_t compaq_plasma_device; -#if defined(DEV_BRANCH) && defined(USE_AMD_K5) -#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) -#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"Cyrix", cpus_6x863V}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73VCH {{ "Intel", cpus_Pentium3V}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_SS7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip_SS7}, {"AMD", cpus_K56_SS7}, {"Cyrix", cpus_6x86SS7}, {"", NULL}} -#else -#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73VCH {{ "Intel", cpus_Pentium3V}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_SS7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip_SS7}, {"AMD", cpus_K56_SS7}, {"", NULL}, {"", NULL}} -#endif -#else -#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) -#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x863V}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73VCH {{ "Intel", cpus_Pentium3V}, {"", NULL }, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_SS7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip_SS7}, {"AMD", cpus_K56_SS7}, {"Cyrix", cpus_6x86SS7}, {"", NULL}} -#else -#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S73VCH {{ "Intel", cpus_Pentium3V}, {"", NULL }, {"", NULL}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_S7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"", NULL}, {"", NULL}} -#define MACHINE_CPUS_PENTIUM_SS7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip_SS7}, {"AMD", cpus_K56_SS7}, {"", NULL}, {"", NULL}} -#endif -#endif - - -const machine_type_t machine_types[] = { - { "None", MACHINE_TYPE_NONE }, - { "8088", MACHINE_TYPE_8088 }, - { "8086", MACHINE_TYPE_8086 }, - { "80286", MACHINE_TYPE_286 }, - { "i386SX", MACHINE_TYPE_386SX }, - { "i386DX", MACHINE_TYPE_386DX }, - { "i486", MACHINE_TYPE_486 }, - { "Socket 4", MACHINE_TYPE_SOCKET4 }, - { "Socket 5", MACHINE_TYPE_SOCKET5 }, - { "Socket 7-3V", MACHINE_TYPE_SOCKET7_3V }, - { "Socket 7", MACHINE_TYPE_SOCKET7 }, - { "Super Socket 7", MACHINE_TYPE_SOCKETS7 }, - { "Socket 8", MACHINE_TYPE_SOCKET8 }, - { "Slot 1", MACHINE_TYPE_SLOT1 }, - { "Slot 2", MACHINE_TYPE_SLOT2 }, - { "Socket 370", MACHINE_TYPE_SOCKET370 }, +const machine_filter_t machine_types[] = { + { "None", MACHINE_TYPE_NONE }, + { "8088", MACHINE_TYPE_8088 }, + { "8086", MACHINE_TYPE_8086 }, + { "80286", MACHINE_TYPE_286 }, + { "i386SX", MACHINE_TYPE_386SX }, + { "486SLC", MACHINE_TYPE_486SLC }, + { "i386DX", MACHINE_TYPE_386DX }, + { "i386DX/i486", MACHINE_TYPE_386DX_486 }, + { "i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, + { "i486 (Socket 2)", MACHINE_TYPE_486_S2 }, + { "i486 (Socket 3)", MACHINE_TYPE_486_S3 }, + { "i486 (Miscellaneous)", MACHINE_TYPE_486_MISC }, + { "Socket 4", MACHINE_TYPE_SOCKET4 }, + { "Socket 5", MACHINE_TYPE_SOCKET5 }, + { "Socket 7 (Single Voltage)", MACHINE_TYPE_SOCKET7_3V }, + { "Socket 7 (Dual Voltage)", MACHINE_TYPE_SOCKET7 }, + { "Super Socket 7", MACHINE_TYPE_SOCKETS7 }, + { "Socket 8", MACHINE_TYPE_SOCKET8 }, + { "Slot 1", MACHINE_TYPE_SLOT1 }, + { "Slot 1/2", MACHINE_TYPE_SLOT1_2 }, + { "Slot 1/Socket 370", MACHINE_TYPE_SLOT1_370 }, + { "Slot 2", MACHINE_TYPE_SLOT2 }, + { "Socket 370", MACHINE_TYPE_SOCKET370 }, + { "Miscellaneous", MACHINE_TYPE_MISC } }; +const machine_filter_t machine_chipsets[] = { + { "None", MACHINE_CHIPSET_NONE }, + { "Discrete", MACHINE_CHIPSET_DISCRETE }, + { "Proprietary", MACHINE_CHIPSET_PROPRIETARY }, + { "Headland GC100A", MACHINE_CHIPSET_GC100A }, + { "Headland GC103", MACHINE_CHIPSET_GC103 }, + { "Headland HT18", MACHINE_CHIPSET_HT18 }, + { "ACC 2168", MACHINE_CHIPSET_ACC_2168 }, + { "ALi M1217", MACHINE_CHIPSET_ALI_M1217 }, + { "ALi M6117", MACHINE_CHIPSET_ALI_M6117 }, + { "ALi M1409", MACHINE_CHIPSET_ALI_M1409 }, + { "ALi M1429", MACHINE_CHIPSET_ALI_M1429 }, + { "ALi M1429G", MACHINE_CHIPSET_ALI_M1429G }, + { "ALi M1489", MACHINE_CHIPSET_ALI_M1489 }, + { "ALi ALADDiN IV+", MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS }, + { "ALi ALADDiN V", MACHINE_CHIPSET_ALI_ALADDIN_V }, + { "ALi ALADDiN-PRO II", MACHINE_CHIPSET_ALI_ALADDIN_PRO_II }, + { "C&T 82C235 SCAT", MACHINE_CHIPSET_SCAT }, + { "C&T CS8121 NEAT", MACHINE_CHIPSET_NEAT }, + { "C&T 386", MACHINE_CHIPSET_CT_386 }, + { "C&T CS4031", MACHINE_CHIPSET_CT_CS4031 }, + { "Contaq 82C596", MACHINE_CHIPSET_CONTAQ_82C596 }, + { "Contaq 82C597", MACHINE_CHIPSET_CONTAQ_82C597 }, + { "IMS 8848", MACHINE_CHIPSET_IMS_8848 }, + { "Intel 82335", MACHINE_CHIPSET_INTEL_82335 }, + { "Intel 420TX", MACHINE_CHIPSET_INTEL_420TX }, + { "Intel 420ZX", MACHINE_CHIPSET_INTEL_420ZX }, + { "Intel 420EX", MACHINE_CHIPSET_INTEL_420EX }, + { "Intel 430LX", MACHINE_CHIPSET_INTEL_430LX }, + { "Intel 430NX", MACHINE_CHIPSET_INTEL_430NX }, + { "Intel 430FX", MACHINE_CHIPSET_INTEL_430FX }, + { "Intel 430HX", MACHINE_CHIPSET_INTEL_430HX }, + { "Intel 430VX", MACHINE_CHIPSET_INTEL_430VX }, + { "Intel 430TX", MACHINE_CHIPSET_INTEL_430TX }, + { "Intel 450KX", MACHINE_CHIPSET_INTEL_450KX }, + { "Intel 440FX", MACHINE_CHIPSET_INTEL_440FX }, + { "Intel 440LX", MACHINE_CHIPSET_INTEL_440LX }, + { "Intel 440EX", MACHINE_CHIPSET_INTEL_440EX }, + { "Intel 440BX", MACHINE_CHIPSET_INTEL_440BX }, + { "Intel 440ZX", MACHINE_CHIPSET_INTEL_440ZX }, + { "Intel 440GX", MACHINE_CHIPSET_INTEL_440GX }, + { "OPTi 283", MACHINE_CHIPSET_OPTI_283 }, + { "OPTi 291", MACHINE_CHIPSET_OPTI_291 }, + { "OPTi 493", MACHINE_CHIPSET_OPTI_493 }, + { "OPTi 495", MACHINE_CHIPSET_OPTI_495 }, + { "OPTi 499", MACHINE_CHIPSET_OPTI_499 }, + { "OPTi 895/802G", MACHINE_CHIPSET_OPTI_895_802G }, + { "OPTi 547/597", MACHINE_CHIPSET_OPTI_547_597 }, + { "SARC RC2016A", MACHINE_CHIPSET_SARC_RC2016A }, + { "SiS 310", MACHINE_CHIPSET_SIS_310 }, + { "SiS 401", MACHINE_CHIPSET_SIS_401 }, + { "SiS 460", MACHINE_CHIPSET_SIS_460 }, + { "SiS 461", MACHINE_CHIPSET_SIS_461 }, + { "SiS 471", MACHINE_CHIPSET_SIS_471 }, + { "SiS 496", MACHINE_CHIPSET_SIS_496 }, + { "SiS 501", MACHINE_CHIPSET_SIS_501 }, + { "SiS 5511", MACHINE_CHIPSET_SIS_5511 }, + { "SiS 5571", MACHINE_CHIPSET_SIS_5571 }, + { "SMSC VictoryBX-66", MACHINE_CHIPSET_SMSC_VICTORYBX_66 }, + { "STPC Client", MACHINE_CHIPSET_STPC_CLIENT }, + { "STPC Consumer-II", MACHINE_CHIPSET_STPC_CONSUMER_II }, + { "STPC Elite", MACHINE_CHIPSET_STPC_ELITE }, + { "STPC Atlas", MACHINE_CHIPSET_STPC_ATLAS }, + { "Symphony SL82C460 Haydn II", MACHINE_CHIPSET_SYMPHONY_SL82C460 }, + { "UMC UM82C480", MACHINE_CHIPSET_UMC_UM82C480 }, + { "UMC UM82C491", MACHINE_CHIPSET_UMC_UM82C491 }, + { "UMC UM8881", MACHINE_CHIPSET_UMC_UM8881 }, + { "UMC UM8890BF", MACHINE_CHIPSET_UMC_UM8890BF }, + { "VIA VT82C495", MACHINE_CHIPSET_VIA_VT82C495 }, + { "VIA VT82C496G", MACHINE_CHIPSET_VIA_VT82C496G }, + { "VIA Apollo VPX", MACHINE_CHIPSET_VIA_APOLLO_VPX }, + { "VIA Apollo VP3", MACHINE_CHIPSET_VIA_APOLLO_VP3 }, + { "VIA Apollo MVP3", MACHINE_CHIPSET_VIA_APOLLO_MVP3 }, + { "VIA Apollo Pro", MACHINE_CHIPSET_VIA_APOLLO_PRO }, + { "VIA Apollo Pro 133", MACHINE_CHIPSET_VIA_APOLLO_PRO_133 }, + { "VIA Apollo Pro 133A", MACHINE_CHIPSET_VIA_APOLLO_PRO_133A }, + { "VLSI SCAMP", MACHINE_CHIPSET_VLSI_SCAMP }, + { "VLSI VL82C480", MACHINE_CHIPSET_VLSI_VL82C480 }, + { "VLSI VL82C481", MACHINE_CHIPSET_VLSI_VL82C481 }, + { "VLSI VL82C486", MACHINE_CHIPSET_VLSI_VL82C486 }, + { "WD76C10", MACHINE_CHIPSET_WD76C10 } +}; + +/* Machines to add before machine freeze: + - PCChips M773 (440BX + SMSC with AMI BIOS); + - TMC Mycomp PCI54ST; + - Zeos Quadtel 486. + + NOTE: The AMI MegaKey tests were done on a real Intel Advanced/ATX + (thanks, MrKsoft for running my AMIKEY.COM on it), but the + technical specifications of the other Intel machines confirm + that the other boards also have the MegaKey. + + NOTE: The later (ie. not AMI Color) Intel AMI BIOS'es execute a + sequence of commands (B8, BA, BB) during one of the very first + phases of POST, in a way that is only valid on the AMIKey-3 + KBC firmware, that includes the Classic PCI/ED (Ninja) BIOS + which otherwise does not execute any AMI KBC commands, which + indicates that the sequence is a leftover of whatever AMI + BIOS (likely a laptop one since the AMIKey-3 is a laptop KBC + firmware!) Intel forked. + + NOTE: The VIA VT82C42N returns 0x46 ('F') in command 0xA1 (so it + emulates the AMI KF/AMIKey KBC firmware), and 0x42 ('B') in + command 0xAF. + The version on the VIA VT82C686B southbridge also returns + 'F' in command 0xA1, but 0x45 ('E') in command 0xAF. + The version on the VIA VT82C586B southbridge also returns + 'F' in command 0xA1, but 0x44 ('D') in command 0xAF. + The version on the VIA VT82C586A southbridge also returns + 'F' in command 0xA1, but 0x43 ('C') in command 0xAF. + + NOTE: The AMI MegaKey commands blanked in the technical reference + are CC and and C4, which are Set P14 High and Set P14 Low, + respectively. Also, AMI KBC command C1, mysteriously missing + from the technical references of AMI MegaKey and earlier, is + Write Input Port, same as on AMIKey-3. +*/ + const machine_t machines[] = { /* 8088 Machines */ - { "[8088] IBM PC (1981)", "ibmpc", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 16, 64, 16, 0, machine_pc_init, NULL }, - { "[8088] IBM PC (1982)", "ibmpc82", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 256, 256, 0, machine_pc82_init, NULL }, - { "[8088] IBM PCjr", "ibmpcjr", MACHINE_TYPE_8088, {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, - { "[8088] IBM XT (1982)", "ibmxt", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 256, 64, 0, machine_xt_init, NULL }, - { "[8088] IBM XT (1986)", "ibmxt86", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 64, 0, machine_xt86_init, NULL }, - { "[8088] AMI XT clone", "amixt", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, - { "[8088] Tandy 1000", "tandy", MACHINE_TYPE_8088, {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_tandy_init, tandy1k_get_device }, - { "[8088] Tandy 1000 HX", "tandy1000hx", MACHINE_TYPE_8088, {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 256, 640, 128, 0, machine_tandy1000hx_init, tandy1k_hx_get_device }, - { "[8088] Compaq Portable", "portable", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, - { "[8088] Generic XT clone", "genxt", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_genxt_init, NULL }, - { "[8088] DTK XT clone", "dtk", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, - { "[8088] Juko XT clone", "jukopc", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, - { "[8088] OpenXT", "open_xt", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_open_xt_init, NULL }, - { "[8088] Phoenix XT clone", "pxxt", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_pxxt_init, NULL }, - { "[8088] Schneider EuroPC", "europc", MACHINE_TYPE_8088, {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_HDC | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, - { "[8088] Toshiba T1000", "t1000", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, t1000_get_device }, + { + .name = "[8088] IBM PC (1981)", + .internal_name = "ibmpc", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_pc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 16, + .max = 64, + .step = 16 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] IBM PC (1982)", + .internal_name = "ibmpc82", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_pc82_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 256, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] IBM PCjr", + .internal_name = "ibmpcjr", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_pcjr_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 4772728, + .max_bus = 4772728, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCJR, + .flags = MACHINE_VIDEO_FIXED, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PCJR, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &pcjr_device, + .vid_device = NULL + }, + { + .name = "[8088] IBM XT (1982)", + .internal_name = "ibmxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 256, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] IBM XT (1986)", + .internal_name = "ibmxt86", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt86_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] American XT Computer", + .internal_name = "americxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_americxt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] AMI XT clone", + .internal_name = "amixt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_amixt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Columbia Data Products MPC-1600", + .internal_name = "mpc1600", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_mpc1600_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 512, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Compaq Portable", + .internal_name = "portable", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_compaq_portable_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] DTK PIM-TB10-Z", + .internal_name = "dtk", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_dtk_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Eagle PC Spirit", + .internal_name = "pcspirit", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_pcspirit_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Generic XT clone", + .internal_name = "genxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_genxt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Juko ST", + .internal_name = "jukopc", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_jukopc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Kaypro PC", + .internal_name = "kaypropc", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_kaypropc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0, + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 64, + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Multitech PC-500", + .internal_name = "pc500", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_pc500_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Multitech PC-700", + .internal_name = "pc700", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_pc700_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] NCR PC4i", + .internal_name = "pc4i", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_pc4i_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 640, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Olivetti M19", + .internal_name = "m19", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_m19_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 4772728, + .max_bus = 7159092, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED, + .ram = { + .min = 256, + .max = 640, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_OLIVETTI_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &m19_vid_device, + .vid_device = NULL + }, + { + .name = "[8088] OpenXT", + .internal_name = "openxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_openxt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Philips P3105/NMS9100", + .internal_name = "p3105", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_p3105_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_XTA, + .ram = { + .min = 256, + .max = 768, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Phoenix XT clone", + .internal_name = "pxxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_pxxt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Schneider EuroPC", + .internal_name = "europc", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_europc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088_EUROPC, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_XTA | MACHINE_MOUSE, + .ram = { + .min = 512, + .max = 640, + .step = 128 + }, + .nvrmask = 15, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Super PC/Turbo XT", + .internal_name = "pcxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_pcxt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Tandy 1000", + .internal_name = "tandy", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_tandy_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088_EUROPC, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_TANDY, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_device, + .vid_device = NULL + }, + { + .name = "[8088] Tandy 1000 HX", + .internal_name = "tandy1000hx", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_tandy1000hx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088_EUROPC, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED, + .ram = { + .min = 256, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_TANDY, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_device_hx, + .vid_device = NULL + }, + { + .name = "[8088] Toshiba T1000", + .internal_name = "t1000", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_t1000_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO, + .ram = { + .min = 512, + .max = 1280, + .step = 768 + }, + .nvrmask = 63, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &t1000_video_device, + .vid_device = NULL + }, + { + .name = "[8088] Vendex HeadStart Turbo 888-XT", + .internal_name = "vendex", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_vendex_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 768, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8088] VTech Laser Turbo XT", "ltxt", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, -#endif - { "[8088] Xi8088", "xi8088", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, - { "[8088] Zenith Data SupersPort", "zdsupers", MACHINE_TYPE_8088, {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, - - /* 8086 Machines */ - { "[8086] Amstrad PC1512", "pc1512", MACHINE_TYPE_8086, {{"Intel", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 512, 640, 128, 63, machine_pc1512_init, pc1512_get_device }, - { "[8086] Amstrad PC1640", "pc1640", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc1640_init, pc1640_get_device }, - { "[8086] Amstrad PC2086", "pc2086", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc2086_init, pc2086_get_device }, - { "[8086] Amstrad PC3086", "pc3086", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc3086_init, pc3086_get_device }, - { "[8086] Amstrad PC20(0)", "pc200", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_pc200_init, pc200_get_device }, - { "[8086] Amstrad PPC512/640", "ppc512", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, - { "[8086] Olivetti M24", "olivetti_m24", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, - { "[8086] Tandy 1000 SL/2", "tandy1000sl2", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, NULL }, - { "[8086] Toshiba T1200", "t1200", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, t1200_get_device }, -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8086] VTech Laser XT3", "lxt3", MACHINE_TYPE_8086, {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, + { + .name = "[8088] VTech Laser Turbo XT", + .internal_name = "ltxt", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_laserxt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 640, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, #endif + /* Has a standard PS/2 KBC (so, use IBM PS/2 Type 1). */ + { + .name = "[8088] Xi8088", + .internal_name = "xi8088", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_xi8088_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 1024, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_VIA_VT82C4XN_XI8088, + .kbc_p1 = 0xff04, + .gpio = 0xffffffff, + .device = &xi8088_device, + .vid_device = NULL + }, + { + .name = "[8088] Z-NIX PC-1600", + .internal_name = "znic", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_znic_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Zenith Data Systems Z-151/152/161", + .internal_name = "zdsz151", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_z151_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Zenith Data Systems Z-159", + .internal_name = "zdsz159", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_z159_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 64 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8088] Zenith Data Systems SupersPort (Z-184)", + .internal_name = "zdsupers", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_z184_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &cga_device, + .vid_device = NULL + }, + { + .name = "[GC100A] Philips P3120", + .internal_name = "p3120", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_GC100A, + .init = machine_xt_p3120_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_XTA, + .ram = { + .min = 256, + .max = 768, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, - /* 286 XT machines */ - { "[Citygate D30 XT] Hedaka HED-919", "hed919", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 1024, 64, 0, machine_xt_hed919_init, NULL }, + /* 8086 Machines */ + { + .name = "[8086] Amstrad PC1512", + .internal_name = "pc1512", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_pc1512_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 8000000, + .max_bus = 8000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED | MACHINE_MOUSE, + .ram = { + .min = 512, + .max = 640, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_AMSTRAD, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_1512_device, + .vid_device = NULL + }, + { + .name = "[8086] Amstrad PC1640", + .internal_name = "pc1640", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_pc1640_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO | MACHINE_MOUSE, + .ram = { + .min = 640, + .max = 640, + .step = 640 + }, + .nvrmask = 63, + .kbc = KBC_AMSTRAD, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_1640_device, + .vid_device = NULL + }, + { + .name = "[8086] Amstrad PC2086", + .internal_name = "pc2086", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_pc2086_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED | MACHINE_MOUSE, + .ram = { + .min = 640, + .max = 640, + .step = 640 + }, + .nvrmask = 63, + .kbc = KBC_AMSTRAD, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_pc2086_device, + .vid_device = NULL + }, + { + .name = "[8086] Amstrad PC3086", + .internal_name = "pc3086", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_pc3086_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED | MACHINE_MOUSE, + .ram = { + .min = 640, + .max = 640, + .step = 640 + }, + .nvrmask = 63, + .kbc = KBC_AMSTRAD, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_pc3086_device, + .vid_device = NULL + }, + { + .name = "[8086] Amstrad PC20(0)", + .internal_name = "pc200", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_pc200_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO | MACHINE_MOUSE, + .ram = { + .min = 512, + .max = 640, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_AMSTRAD, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_200_device, + .vid_device = NULL + }, + { + .name = "[8086] Amstrad PPC512/640", + .internal_name = "ppc512", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ppc512_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO | MACHINE_MOUSE, + .ram = { + .min = 512, + .max = 640, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_AMSTRAD, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_ppc512_device, + .vid_device = NULL + }, + { + .name = "[8086] Compaq Deskpro", + .internal_name = "deskpro", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_compaq_deskpro_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8086] Olivetti M21/24/24SP", + .internal_name = "m24", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_m24_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO | MACHINE_MOUSE, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_OLIVETTI_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &ogc_m24_device, + .vid_device = NULL + }, + /* Has Olivetti KBC firmware. */ + { + .name = "[8086] Olivetti M240", + .internal_name = "m240", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_m240_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_OLIVETTI, + .kbc_p1 = 0xff04, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8086] Schetmash Iskra-3104", + .internal_name = "iskra3104", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_iskra3104_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 128, + .max = 640, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8086] Tandy 1000 SL/2", + .internal_name = "tandy1000sl2", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_tandy1000sl2_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED, + .ram = { + .min = 512, + .max = 768, + .step = 128 + }, + .nvrmask = 0, + .kbc = KBC_TANDY_SL2, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &vid_device_sl, + .vid_device = NULL + }, + { + .name = "[8086] Victor V86P", + .internal_name = "v86p", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_v86p_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO, + .ram = { + .min = 512, + .max = 1024, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[8086] Toshiba T1200", + .internal_name = "t1200", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_xt_t1200_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 2048, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = &t1200_video_device, + .vid_device = NULL + }, + +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { + .name = "[8086] VTech Laser XT3", + .internal_name = "lxt3", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_lxt3_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 640, + .step = 256 + }, + .nvrmask = 0, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL + }, +#endif /* 286 AT machines */ - { "[ISA] IBM AT", "ibmat", MACHINE_TYPE_286, {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, - { "[ISA] AMI IBM AT", "ibmatami", MACHINE_TYPE_286, {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatami_init, NULL }, - { "[ISA] Quadtel IBM AT", "ibmatquadtel", MACHINE_TYPE_286, {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatquadtel_init, NULL }, - { "[ISA] Phoenix IBM AT", "ibmatpx", MACHINE_TYPE_286, {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatpx_init, NULL }, - { "[ISA] IBM PS/1 model 2011", "ibmps1es", MACHINE_TYPE_286, {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, - { "[ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", MACHINE_TYPE_286, {{"Intel", cpus_ps2_m30_286}, {"IBM",cpus_IBM486SLC},{"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, - { "[ISA] IBM XT Model 286", "ibmxt286", MACHINE_TYPE_286, {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibmxt286_init, NULL }, - { "[ISA] Commodore PC 30 III", "cmdpc30", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, - { "[ISA] Compaq Portable II", "portableii", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_portableii_init, NULL }, - { "[ISA] Compaq Portable III", "portableiii", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO, 640,16384, 128, 127, machine_at_portableiii_init, at_cpqiii_get_device }, - { "[NEAT] AMI 286 clone", "ami286", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, - { "[NEAT] Phoenix 286 clone", "px286", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_px286_init, NULL }, - { "[SCAT] Award 286 clone", "award286", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_award286_init, NULL }, - { "[SCAT] GW-286CT GEAR", "gw286ct", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_gw286ct_init, NULL }, - { "[SCAT] Goldstar GDC-212M", "gdc212m", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2, 512, 4096, 512, 127, machine_at_gdc212m_init, NULL }, - { "[SCAT] Hyundai Super-286TR", "super286tr", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_super286tr_init, NULL }, - { "[SCAT] Samsung SPC-4200P", "spc4200p", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, - { "[SCAT] Samsung SPC-4216P", "spc4216p", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_spc4216p_init, NULL }, - { "[SCAT] Samsung Deskmaster 286", "deskmaster286", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_deskmaster286_init, NULL }, - { "[HT18] Quadtel 286 clone", "quadt286", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_quadt286_init, NULL }, - { "[HT18] Trigem 286M", "tg286m", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, - { "[ISA] MR 286 clone", "mr286", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_mr286_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_SIEMENS) - { "[ISA] Siemens PCD-2L", "siemens", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_siemens_init, NULL }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] IBM AT", + .internal_name = "ibmat", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_ibm_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 8000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[ISA] IBM PS/1 model 2011", + .internal_name = "ibmps1es", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps1_m2011_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 10000000, + .max_bus = 10000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_XTA | MACHINE_VIDEO_FIXED, + .ram = { + .min = 512, + .max = 16384, + .step = 512 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[ISA] IBM PS/2 model 30-286", + .internal_name = "ibmps2_m30_286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_m30_286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286 | CPU_PKG_486SLC_IBM, + .block = CPU_BLOCK_NONE, + .min_bus = 10000000, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_XTA | MACHINE_VIDEO_FIXED, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] IBM XT Model 286", + .internal_name = "ibmxt286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_ibmxt286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 6000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* AMI BIOS for a chipset-less machine, most likely has AMI 'F' KBC firmware. */ + { + .name = "[ISA] AMI IBM AT", + .internal_name = "ibmatami", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_ibmatami_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 8000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to the + IBM AT KBC firmware unless evidence emerges of any proprietary commands. */ + { + .name = "[ISA] Commodore PC 30 III", + .internal_name = "cmdpc30", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_at_cmdpc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses Compaq KBC firmware. */ + { + .name = "[ISA] Compaq Portable II", + .internal_name = "portableii", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_at_portableii_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses Compaq KBC firmware. */ + { + .name = "[ISA] Compaq Portable III", + .internal_name = "portableiii", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_at_portableiii_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_VIDEO, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &compaq_plasma_device, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] MR BIOS 286 clone", + .internal_name = "mr286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_mr286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] NCR PC8/810/710/3390/3392", + .internal_name = "pc8", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_pc8_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, +#if defined(DEV_BRANCH) && defined(USE_OLIVETTI) + /* Has Olivetti KBC firmware. */ + { + .name = "[ISA] Olivetti M290", + .internal_name = "m290", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_at_m290_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, #endif #if defined(DEV_BRANCH) && defined(USE_OPEN_AT) - { "[ISA] OpenAT", "open_at", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_open_at_init, NULL }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] OpenAT", + .internal_name = "openat", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_openat_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, #endif - { "[ISA] Toshiba T3100e", "t3100e", MACHINE_TYPE_286, {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] Phoenix IBM AT", + .internal_name = "ibmatpx", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_ibmatpx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 8000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has Quadtel KBC firmware. */ + { + .name = "[ISA] Quadtel IBM AT", + .internal_name = "ibmatquadtel", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_ibmatquadtel_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 8000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has a Siemens proprietary KBC which is completely undocumented. */ + { + .name = "[ISA] Siemens PCD-2L", + .internal_name = "siemens", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_siemens_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 15872, + .step = 128 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has Toshiba's proprietary KBC, which is already implemented. */ + { + .name = "[ISA] Toshiba T3100e", + .internal_name = "t3100e", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_at_t3100e_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE | MACHINE_VIDEO_FIXED, + .ram = { + .min = 1024, + .max = 5120, + .step = 256 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has Quadtel KBC firmware. */ + { + .name = "[GC103] Quadtel 286 clone", + .internal_name = "quadt286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_GC103, + .init = machine_at_quadt286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Most likely has AMI 'F' KBC firmware. */ + { + .name = "[GC103] TriGem 286M", + .internal_name = "tg286m", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_GC103, + .init = machine_at_tg286m_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has "AMI KEYBOARD BIOS", most likely 'F'. */ + { + .name = "[NEAT] DataExpert 286", + .internal_name = "ami286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_neat_ami_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[NEAT] NCR 3302", + .internal_name = "3302", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_3302_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_VIDEO, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[NEAT] Phoenix 286 clone", + .internal_name = "px286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_px286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has Chips & Technologies KBC firmware. */ + { + .name = "[SCAT] GW-286CT GEAR", + .internal_name = "gw286ct", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_gw286ct_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[SCAT] Goldstar GDC-212M", + .internal_name = "gdc212m", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_gdc212m_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 512, + .max = 4096, + .step = 512 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a VIA VT82C42N KBC. */ + { + .name = "[SCAT] Hyundai Solomon 286KP", + .internal_name = "award286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_award286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a VIA VT82C42N KBC. */ + { + .name = "[SCAT] Hyundai Super-286TR", + .internal_name = "super286tr", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_super286tr_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[SCAT] Samsung SPC-4200P", + .internal_name = "spc4200p", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_spc4200p_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 2048, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[SCAT] Samsung SPC-4216P", + .internal_name = "spc4216p", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_spc4216p_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 5120, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[SCAT] Samsung SPC-4620P", + .internal_name = "spc4620p", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_spc4620p_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 5120, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[SCAT] Samsung Deskmaster 286", + .internal_name = "deskmaster286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_deskmaster286_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 286 machines that utilize the MCA bus */ - { "[MCA] IBM PS/2 model 50", "ibmps2_m50", MACHINE_TYPE_286, {{"Intel", cpus_ps2_m30_286}, {"IBM",cpus_IBM486SLC},{"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + /* Has IBM PS/2 Type 2 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 50", + .internal_name = "ibmps2_m50", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_50_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286 | CPU_PKG_486SLC_IBM, + .block = CPU_BLOCK_NONE, + .min_bus = 10000000, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 10240, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 2 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 60", + .internal_name = "ibmps2_m60", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_60_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_286 | CPU_PKG_486SLC_IBM, + .block = CPU_BLOCK_NONE, + .min_bus = 10000000, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 10240, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 386SX machines */ - { "[ISA] IBM PS/1 model 2121", "ibmps1_2121", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 2, 6, 1, 63, machine_ps1_m2121_init, NULL }, - { "[ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 2, 6, 1, 63, machine_ps1_m2121_init, NULL }, - { "[HT18] AMA-932J", "ama932j", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, -#if defined(DEV_BRANCH) && defined(USE_AMI386SX) - { "[HT18] AMI Unknown 386SX", "ami386", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, -#endif - { "[WD76C10] Amstrad MegaPC", "megapc", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, - { "[SCAMP] Commodore SL386SX", "cbm_sl386sx25", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1024, 8192, 512, 127,machine_at_commodore_sl386sx_init, at_commodore_sl386sx_get_device }, - { "[NEAT] DTK 386SX clone", "dtk386", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, - { "[NEAT] Goldstar 386", "goldstar386", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_goldstar386_init, NULL }, - { "[SCAT] KMX-C-02", "kmxc02", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_kmxc02_init, NULL }, + /* ISA slots available because an official IBM expansion for that existed. */ + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[ISA] IBM PS/1 model 2121", + .internal_name = "ibmps1_2121", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps1_m2121_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 6144, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] NCR PC916SX", + .internal_name = "pc916sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_pc916sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has Quadtel KBC firmware. */ + { + .name = "[ISA] QTC-SXM KT X20T02/HI", + .internal_name = "quadt386sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_quadt386sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[ALi M1217] Acrosser AR-B1374", + .internal_name = "arb1374", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M1217, + .init = machine_at_arb1374_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the AMIKey KBC firmware, which is an updated 'F' type. */ + { + .name = "[ALi M1217] AAEON SBC-350A", + .internal_name = "sbc350a", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M1217, + .init = machine_at_sbc350a_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has an AMI KBC firmware, the only photo of this is too low resolution + for me to read what's on the KBC chip, so I'm going to assume AMI 'F' + based on the other known HT18 AMI BIOS strings. */ + { + .name = "[ALi M1217] Flytech 386", + .internal_name = "flytech386", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M1217, + .init = machine_at_flytech386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &tvga8900d_device, + .vid_device = NULL + }, + /* I'm going to assume this has a standard/generic IBM-compatible AT KBC + firmware until the board is identified. */ + { + .name = "[ALi M1217] MR BIOS 386SX clone", + .internal_name = "mr1217", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M1217, + .init = machine_at_mr1217_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[ALi M6117] Acrosser PJ-A511M", + .internal_name = "pja511m", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M6117, + .init = machine_at_pja511m_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_M6117, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[ALi M6117] Protech ProX-1332", + .internal_name = "prox1332", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ALI_M6117, + .init = machine_at_prox1332_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_M6117, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has an AMI KBC firmware, the only photo of this is too low resolution + for me to read what's on the KBC chip, so I'm going to assume AMI 'F' + based on the other known HT18 AMI BIOS strings. */ + { + .name = "[HT18] AMA-932J", + .internal_name = "ama932j", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_HT18, + .init = machine_at_ama932j_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &oti067_ama932j_device, + .vid_device = NULL + }, + /* Has an unknown KBC firmware with commands B8 and BB in the style of + Phoenix MultiKey and AMIKey-3(!), but also commands E1 and EA with + unknown functions. */ + { + .name = "[Intel 82335] ADI 386SX", + .internal_name = "adi386sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_INTEL_82335, + .init = machine_at_adi386sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ + { .name = "[Intel 82335] Shuttle 386SX", + .internal_name = "shuttle386sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_INTEL_82335, + .init = machine_at_shuttle386sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to + the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any + proprietary commands. */ + { + .name = "[NEAT] Commodore SL386SX-16", + .internal_name = "cmdsl386sx16", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_cmdsl386sx16_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 8192, + .step = 512 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[NEAT] DTK 386SX clone", + .internal_name = "dtk386", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_neat_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[OPTi 291] DTK PPM-3333P", + .internal_name = "awardsx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_OPTI_291, + .init = machine_at_awardsx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses Commodore (CBM) KBC firmware, to be implemented as identical to + the IBM PS/2 Type 1 KBC firmware unless evidence emerges of any + proprietary commands. */ + { + .name = "[SCAMP] Commodore SL386SX-25", + .internal_name = "cmdsl386sx25", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_VLSI_SCAMP, + .init = machine_at_cmdsl386sx25_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 8192, + .step = 512 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &gd5402_onboard_device, + .vid_device = NULL + }, + /* The closest BIOS string I find to this one's, differs only in one part, + and ends in -8, so I'm going to assume that this, too, has an AMI '8' + (AMI Keyboard BIOS Plus) KBC firmware. */ + { + .name = "[SCAMP] DataExpert 386SX", + .internal_name = "dataexpert386sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_VLSI_SCAMP, + .init = machine_at_dataexpert386sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 10000000, + .max_bus = 25000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[SCAMP] Samsung SPC-6033P", + .internal_name = "spc6033p", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_VLSI_SCAMP, + .init = machine_at_spc6033p_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 12288, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &ati28800k_spc6033p_device, + .vid_device = NULL + }, + /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a + photo or real hardware BIOS string is found. */ + { + .name = "[SCAT] KMX-C-02", + .internal_name = "kmxc02", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_SCAT, + .init = machine_at_kmxc02_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 16384, + .step = 512 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has Quadtel KBC firmware. */ + { + .name = "[WD76C10] Amstrad MegaPC", + .internal_name = "megapc", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_WD76C10, + .init = machine_at_wd76c10_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 386SX machines which utilize the MCA bus */ - { "[MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", MACHINE_TYPE_386SX, {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"IBM",cpus_IBM486SLC},{"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 55SX", + .internal_name = "ibmps2_m55sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_55sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 8192, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 65SX", + .internal_name = "ibmps2_m65sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_65sx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 8192, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* 486SLC machines */ + /* 486SLC machines with just the ISA slot */ + /* Has AMIKey H KBC firmware. */ + { + .name = "[OPTi 283] RYC Leopard LX", + .internal_name = "rycleopardlx", + .type = MACHINE_TYPE_486SLC, + .chipset = MACHINE_CHIPSET_OPTI_283, + .init = machine_at_rycleopardlx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_486SLC_IBM, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 386DX machines */ - { "[ACC 2168] AMI 386DX clone", "acc386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 16384, 128, 127, machine_at_acc386_init, NULL }, - { "[SiS Rabbit] ASUS ISA-386C", "asus386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 16384, 128, 127, machine_at_asus386_init, NULL }, - { "[ISA] Compaq Portable III (386)", "portableiii386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_portableiii386_init, at_cpqiii_get_device }, - { "[ISA] Micronics 386 clone", "micronics386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, - { "[C&T 386] ECS 386/32", "ecs386", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 1, 16, 1, 127, machine_at_ecs386_init, NULL }, - - /* 386DX machines which utilize the VLB bus */ - { "[OPTi 495] Award 386DX clone", "award386dx", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, - { "[OPTi 495] Dataexpert SX495 (386DX)", "ami386dx", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_ami_init, NULL }, - { "[OPTi 495] MR 386DX clone", "mr386dx", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, + { + .name = "[ACC 2168] AMI 386DX clone", + .internal_name = "acc386", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_ACC_2168, + .init = machine_at_acc386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ + { + .name = "[C&T 386] ECS 386/32", + .internal_name = "ecs386", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_CT_386, + .init = machine_at_ecs386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[C&T 386] Samsung SPC-6000A", + .internal_name = "spc6000a", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_CT_386, + .init = machine_at_spc6000a_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses Compaq KBC firmware. */ +#if defined(DEV_BRANCH) && defined(USE_DESKPRO386) + { + .name = "[ISA] Compaq Deskpro 386", + .internal_name = "deskpro386", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_deskpro386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 14336, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, +#endif + { + .name = "[ISA] Compaq Portable III (386)", + .internal_name = "portableiii386", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_portableiii386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 14336, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &compaq_plasma_device, + .vid_device = NULL + }, + /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] Micronics 09-00021", + .internal_name = "micronics386", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_micronics386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[SiS 310] ASUS ISA-386C", + .internal_name = "asus386", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_SIS_310, + .init = machine_at_asus386_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 386DX machines which utilize the MCA bus */ - { "[MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"IBM",cpus_IBM486BL},{"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, - { "[MCA] IBM PS/2 model 80", "ibmps2_m80", MACHINE_TYPE_386DX, {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"IBM",cpus_IBM486BL},{"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 80 (type 2)", + .internal_name = "ibmps2_m80", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_80_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_486BL, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* 386DX/486 machines */ + /* The BIOS sends commands C9 without a parameter and D5, both of which are + Phoenix MultiKey commands. */ + { + .name = "[OPTi 495] Award 486 clone", + .internal_name = "award495", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_OPTI_495, + .init = machine_at_opti495_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[OPTi 495] DataExpert SX495", + .internal_name = "ami495", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_OPTI_495, + .init = machine_at_opti495_ami_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware (it's just the MR BIOS for the above machine). */ + { + .name = "[OPTi 495] DataExpert SX495 (MR BIOS)", + .internal_name = "mr495", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_OPTI_495, + .init = machine_at_opti495_mr_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 70 (type 3)", + .internal_name = "ibmps2_m70_type3", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_70_type3_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_486BL | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 65536, + .step = 2048 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[MCA] IBM PS/2 model 80 (type 3)", + .internal_name = "ibmps2_m80_type3", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps2_model_80_axx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_486BL | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 65536, + .step = 2048 + }, + .nvrmask = 63, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* 486 machines - Socket 1 */ + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. + It also has those Ex commands also seen on the VIA VT82C42N (the BIOS + supposedly sends command EF. + The board was also seen in 2003 with a -H string - perhaps someone swapped + the KBC? */ + { + .name = "[ALi M1429] Olystar LIL1429", + .internal_name = "ali1429", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_ALI_M1429, + .init = machine_at_ali1429_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has JetKey 5 KBC Firmware - but the BIOS string ends in a hardcoded -F, and + the BIOS also explicitly expects command A1 to return a 'F', so it looks like + the JetKey 5 is a clone of AMIKey type F. */ + { + .name = "[CS4031] AMI 486 CS4031", + .internal_name = "cs4031", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_CT_CS4031, + .init = machine_at_cs4031_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses some variant of Phoenix MultiKey/42 as the Intel 8242 chip has a Phoenix + copyright. */ + { + .name = "[OPTi 895] Mylex MVI486", + .internal_name = "mvi486", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .init = machine_at_mvi486_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMI KF KBC firmware. */ + { + .name = "[SiS 401] ASUS ISA-486", + .internal_name = "isa486", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_SIS_401, + .init = machine_at_isa486_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey H KBC firmware, per the screenshot in "How computers & MS-DOS work". */ + { + .name = "[SiS 401] Chaintech 433SC", + .internal_name = "sis401", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_SIS_401, + .init = machine_at_sis401_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware, per a photo of a monitor with the BIOS screen on + eBay. */ + { + .name = "[SiS 460] ABIT AV4", + .internal_name = "av4", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_SIS_460, + .init = machine_at_av4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a MR (!) KBC firmware, which is a clone of the standard IBM PS/2 KBC firmware. */ + { + .name = "[SiS 471] SiS VL-BUS 471 REV. A1", + .internal_name = "px471", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_px471_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The chip is a Lance LT38C41, a clone of the Intel 8041, and the BIOS sends + commands BC, BD, and C9 which exist on both AMIKey and Phoenix MultiKey/42, + but it does not write a byte after C9, which is consistent with AMIKey, so + this must have some form of AMIKey. */ + { + .name = "[VIA VT82C495] FIC 486-VC-HD", + .internal_name = "486vchd", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_VIA_VT82C495, + .init = machine_at_486vchd_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 64512, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to Deksor on the Win3x.org forum, the BIOS string ends in a -0, + indicating an unknown KBC firmware. But it does send the AMIKey get version + command, so it must expect an AMIKey. */ + { + .name = "[VLSI 82C480] HP Vectra 486VL", + .internal_name = "vect486vl", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_VLSI_VL82C480, + .init = machine_at_vect486vl_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 32768, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &gd5428_onboard_device, + .vid_device = NULL + }, + /* Has a standard IBM PS/2 KBC firmware or a clone thereof. */ + { + .name = "[VLSI 82C481] Siemens Nixdorf D824", + .internal_name = "d824", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_VLSI_VL82C481, + .init = machine_at_d824_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 32768, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &gd5428_onboard_device, + .vid_device = NULL + }, + + /* 486 machines - Socket 2 */ /* 486 machines with just the ISA slot */ - { "[ACC 2168] Packard Bell PB410A", "pb410a", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 4, 36, 1, 127, machine_at_pb410a_init, NULL }, + /* Uses some variant of Phoenix MultiKey/42 as the BIOS sends keyboard controller + command C7 (OR input byte with received data byte). */ + { + .name = "[ACC 2168] Packard Bell PB410A", + .internal_name = "pb410a", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_ACC_2168, + .init = machine_at_pb410a_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 4096, + .max = 36864, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V4.01H). */ + { + .name = "[ALi M1429G] Acer A1G", + .internal_name = "acera1g", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_ALI_M1429G, + .init = machine_at_acera1g_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 4096, + .max = 36864, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &gd5428_onboard_device, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[ALi M1429G] Kaimei SA-486 VL-BUS M.B.", + .internal_name = "win486", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_ALI_M1429G, + .init = machine_at_winbios1429_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Uses an Intel KBC with Phoenix MultiKey KBC firmware. */ + { + .name = "[SiS 461] DEC DECpc LPV", + .internal_name = "decpclpv", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_SIS_461, + .init = machine_at_decpclpv_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_86c805_onboard_vlb_device, + .vid_device = NULL + }, + /* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */ + { + .name = "[SiS 461] Acer V10", + .internal_name = "acerv10", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_SIS_461, + .init = machine_at_acerv10_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS does not send any non-standard keyboard controller commands and wants + a PS/2 mouse, so it's an IBM PS/2 KBC (Type 1) firmware. */ + { + .name = "[SiS 461] IBM PS/ValuePoint 433DX/Si", + .internal_name = "valuepoint433", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_SIS_461, + .init = machine_at_valuepoint433_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS string ends in -U, unless command 0xA1 (AMIKey get version) returns an + 'F', in which case, it ends in -F, so it has an AMIKey F KBC firmware. + The photo of the board shows an AMIKey KBC which is indeed F. */ + { + .name = "[SiS 471] ABit AB-AH4", + .internal_name = "win471", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_win471_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, - /* 486 machines */ - { "[OPTi 495] Award 486 clone", "award486", MACHINE_TYPE_486, {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, - { "[OPTi 495] MR 486 clone", "mr486", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, - { "[OPTi 495] Dataexpert SX495 (486)", "ami486", MACHINE_TYPE_486, {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_ami_init, NULL }, - { "[SiS 471] ASUS VL/I-486SV2G (GX4)", "vli486sv2g", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_vli486sv2g_init, NULL }, - { "[SiS 471] AMI 486 Clone", "ami471", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ami471_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_WIN471) - { "[SiS 471] AMI WinBIOS 486 clone", "win471", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_win471_init, NULL }, -#endif - { "[SiS 471] DTK PKM-0038S E-2", "dtk486", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_dtk486_init, NULL }, - { "[SiS 471] Phoenix SiS 471", "px471", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_px471_init, NULL }, - { "[ALi M1429G] Acer A1G", "acera1g", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO | MACHINE_PS2, 4, 36, 1, 127, machine_at_acera1g_init, at_acera1g_get_device }, - { "[ALi M1429] Olystar LIL1429", "ali1429", MACHINE_TYPE_486, {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_ali1429_init, NULL }, - { "[ALi M1429] AMI WinBIOS 486", "win486", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_winbios1429_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_PS1M2133) - { "[VLB] IBM PS/1 model 2133", "ibmps1_2133", MACHINE_TYPE_486, {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_NONMI, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, -#endif - - /* 486 machines with utilize the MCA bus */ -#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) - { "[MCA] IBM PS/2 model 70 (type 4)", "ibmps2_m70_type4", MACHINE_TYPE_486, {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, -#endif + /* 486 machines - Socket 3 */ + /* 486 machines with just the ISA slot */ + /* Has AMI MegaKey KBC firmware. */ + { + .name = "[Contaq 82C597] Green-B", + .internal_name = "greenb", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_CONTAQ_82C597, + .init = machine_at_greenb_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a VIA VT82C42N KBC. */ + { + .name = "[OPTi 895] Jetway J-403TG", + .internal_name = "403tg", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .init = machine_at_403tg_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { + .name = "[OPTi 895] Jetway J-403TG Rev D", + .internal_name = "403tg_d", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .init = machine_at_403tg_d_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { + .name = "[OPTi 895] Jetway J-403TG Rev D (MR BIOS)", + .internal_name = "403tg_d_mr", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .init = machine_at_403tg_d_mr_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey H keyboard BIOS. */ + { + .name = "[SiS 471] AOpen Vi15G", + .internal_name = "vi15g", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_vi15g_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[SiS 471] ASUS VL/I-486SV2G (GX4)", + .internal_name = "vli486sv2g", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_vli486sv2g_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_VLB, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has JetKey 5 KBC Firmware which looks like it is a clone of AMIKey type F. */ + { + .name = "[SiS 471] DTK PKM-0038S E-2", + .internal_name = "dtk486", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_dtk486_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Unknown Epox VLB Socket 3 board, has AMIKey F keyboard BIOS. */ + { + .name = "[SiS 471] Epox 486SX/DX Green", + .internal_name = "ami471", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_ami471_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 486 machines which utilize the PCI bus */ - { "[i420EX] ASUS PVI-486AP4", "486ap4", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_486ap4_init, NULL }, - { "[i420ZX] ASUS PCI/I-486SP3G", "486sp3g", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_486sp3g_init, NULL }, - { "[i420TX] Intel Classic/PCI", "alfredo", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_alfredo_init, NULL }, - { "[SiS 496] Lucky Star LS-486E", "ls486e", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_ls486e_init, NULL }, - { "[SiS 496] Rise Computer R418", "r418", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, - { "[SiS 496] Zida Tomato 4DP", "4dps", MACHINE_TYPE_486, {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_4dps_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[ALi M1489] AAEON SBC-490", + .internal_name = "sbc490", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_ALI_M1489, + .init = machine_at_sbc490_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &tgui9440_onboard_pci_device, + .vid_device = NULL + }, + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. */ + { + .name = "[ALi M1489] ABIT AB-PB4", + .internal_name = "abpb4", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_ALI_M1489, + .init = machine_at_abpb4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. + The BIOS string always ends in -U, but the BIOS will send AMIKey commands 0xCA + and 0xCB if command 0xA1 returns a letter in the 0x5x or 0x7x ranges, so I'm + going to give it an AMI 'U' KBC. */ + { + .name = "[ALi M1489] AMI WinBIOS 486 PCI", + .internal_name = "win486pci", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_ALI_M1489, + .init = machine_at_win486pci_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the ALi M1487/9's on-chip keyboard controller which clones a standard AT + KBC. + The known BIOS string ends in -E, and the BIOS returns whatever command 0xA1 + returns (but only if command 0xA1 is instant response), so said ALi keyboard + controller likely returns 'E'. */ + { + .name = "[ALi M1489] MSI MS-4145", + .internal_name = "ms4145", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_ALI_M1489, + .init = machine_at_ms4145_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has an ALi M5042 keyboard controller with Phoenix MultiKey/42 v1.40 firmware. */ + { + .name = "[ALi M1489] ESA TF-486", + .internal_name = "tf486", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_ALI_M1489, + .init = machine_at_tf486_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[OPTi 802G] IBM PC 330 (type 6573)", + .internal_name = "pc330_6573", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .init = machine_at_pc330_6573_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3_PC330, + .block = CPU_BLOCK_NONE, + .min_bus = 25000000, + .max_bus = 33333333, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 2.0, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[i420EX] ASUS PVI-486AP4", + .internal_name = "486ap4", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_INTEL_420EX, + .init = machine_at_486ap4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCIV, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i420EX] Intel Classic/PCI ED", + .internal_name = "ninja", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_INTEL_420EX, + .init = machine_at_ninja_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* I'm going to assume this as an AMIKey-2 like the other two 486SP3's. */ + { + .name = "[i420TX] ASUS PCI/I-486SP3", + .internal_name = "486sp3", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_INTEL_420TX, + .init = machine_at_486sp3_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_SCSI, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i420TX] Intel Classic/PCI", + .internal_name = "alfredo", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_INTEL_420TX, + .init = machine_at_alfredo_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. Also has a + SST 29EE010 Flash chip. */ + { + .name = "[i420ZX] ASUS PCI/I-486SP3G", + .internal_name = "486sp3g", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_INTEL_420ZX, + .init = machine_at_486sp3g_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_SCSI, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This most likely has a standalone AMI Megakey 1993, which is type 'P', like the below Tekram board. */ + { + .name = "[IMS 8848] J-Bond PCI400C-B", + .internal_name = "pci400cb", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_IMS_8848, + .init = machine_at_pci400cb_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has a standalone AMI Megakey 1993, which is type 'P'. */ + { + .name = "[IMS 8848] Tekram G486IP", + .internal_name = "g486ip", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_IMS_8848, + .init = machine_at_g486ip_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[SiS 496] ASUS PVI-486SP3C", + .internal_name = "486sp3c", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_486sp3c_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCIV, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 261120, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[SiS 496] Lucky Star LS-486E", + .internal_name = "ls486e", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_ls486e_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS does not send a single non-standard KBC command, so it has a standard PS/2 KBC. */ + { + .name = "[SiS 496] Micronics M4Li", + .internal_name = "m4li", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_m4li_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a BestKey KBC which clones AMI type 'H'. */ + { + .name = "[SiS 496] Rise Computer R418", + .internal_name = "r418", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_r418_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 261120, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ + { + .name = "[SiS 496] Soyo 4SAW2", + .internal_name = "4saw2", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_4saw2_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCIV, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 261120, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to MrKsoft, his real 4DPS has an AMIKey-2, which is an updated version + of type 'H'. */ + { + .name = "[SiS 496] Zida Tomato 4DP", + .internal_name = "4dps", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_4dps_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 261120, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the UMC 88xx on-chip KBC. */ + { + .name = "[UMC 8881] A-Trend ATC-1415", + .internal_name = "atc1415", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_atc1415_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[UMC 8881] ECS Elite UM8810PAIO", + .internal_name = "ecs486", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_ecs486_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey Z(!) KBC firmware. */ + { + .name = "[UMC 8881] Epson Action PC 2600", + .internal_name = "actionpc2600", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_actionpc2600_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 262144, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the UMC 88xx on-chip KBC. All the copies of the BIOS string I can find, end in + in -H, so the UMC on-chip KBC likely emulates the AMI 'H' KBC firmware. */ + { + .name = "[UMC 8881] PC Chips M919", + .internal_name = "m919", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_m919_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCIV, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. Uses a mysterious I/O port C05. */ + { + .name = "[UMC 8881] Samsung SPC7700P-LW", + .internal_name = "spc7700plw", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_spc7700plw_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has a Holtek KBC. */ + { + .name = "[UMC 8881] Shuttle HOT-433A", + .internal_name = "hot433", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_hot433_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 262144, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ + { + .name = "[VIA VT82C496G] DFI G486VPA", + .internal_name = "g486vpa", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_VIA_VT82C496G, + .init = machine_at_g486vpa_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCIV, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a VIA VT82C42N KBC. */ + { + .name = "[VIA VT82C496G] FIC VIP-IO2", + .internal_name = "486vipio2", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_VIA_VT82C496G, + .init = machine_at_486vipio2_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCIV, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* 486 machines - Miscellaneous */ + /* 486 machines which utilize the PCI bus */ + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[STPC Client] ITOX STAR", + .internal_name = "itoxstar", + .type = MACHINE_TYPE_486_MISC, + .chipset = MACHINE_CHIPSET_STPC_CLIENT, + .init = machine_at_itoxstar_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_STPC, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 75000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 1.0, + .max_multi = 1.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[STPC Consumer-II] Acrosser AR-B1423C", + .internal_name = "arb1423c", + .type = MACHINE_TYPE_486_MISC, + .chipset = MACHINE_CHIPSET_STPC_CONSUMER_II, + .init = machine_at_arb1423c_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_STPC, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 2.0, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 163840, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[STPC Consumer-II] Acrosser AR-B1479", + .internal_name = "arb1479", + .type = MACHINE_TYPE_486_MISC, + .chipset = MACHINE_CHIPSET_STPC_CONSUMER_II, + .init = machine_at_arb1479_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_STPC, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 2.0, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 163840, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[STPC Elite] Advantech PCM-9340", + .internal_name = "pcm9340", + .type = MACHINE_TYPE_486_MISC, + .chipset = MACHINE_CHIPSET_STPC_ELITE, + .init = machine_at_pcm9340_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_STPC, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 2.0, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 98304, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[STPC Atlas] AAEON PCM-5330", + .internal_name = "pcm5330", + .type = MACHINE_TYPE_486_MISC, + .chipset = MACHINE_CHIPSET_STPC_ATLAS, + .init = machine_at_pcm5330_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_STPC, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 2.0, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 32768, + .max = 131072, + .step = 32768 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* Socket 4 machines */ - /* OPTi 596/597 */ - { "[OPTi Python] AMI Excalibur VLB", "excalibur", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_excalibur_init, NULL }, - /* 430LX */ - { "[i430LX] IBM Ambra DP60 PCI", "ambradp60", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp60_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_VPP60) - { "[i430LX] IBM PS/ValuePoint P60", "valuepointp60", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_valuepointp60_init, NULL }, -#endif - { "[i430LX] Intel Premiere/PCI", "revenge", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, - { "[i430LX] Micro Star 586MC1", "586mc1", MACHINE_TYPE_SOCKET4, {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_586mc1_init, NULL }, + /* Has AMIKey H KBC firmware (AMIKey-2), per POST screen with BIOS string + shown in the manual. Has PS/2 mouse support with serial-style (DB9) + connector. + The boot block for BIOS recovery requires an unknown bit on port 805h + to be clear. */ + { + .name = "[i430LX] AMI Excalibur PCI Pentium", + .internal_name = "excaliburpci", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_excaliburpci_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware (AMIKey). */ + { + .name = "[i430LX] ASUS P/I-P5MP3", + .internal_name = "p5mp3", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_p5mp3_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE, + .ram = { + .min = 2048, + .max = 196608, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[i430LX] Dell Dimension XPS P60", + .internal_name = "dellxp60", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_dellxp60_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[i430LX] Dell OptiPlex 560/L", + .internal_name = "opti560l", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_opti560l_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the Phoenix MultiKey KBC firmware. + This is basically an Intel Batman (*NOT* Batman's Revenge) with a fancier + POST screen */ + { + .name = "[i430LX] AMBRA DP60 PCI", + .internal_name = "ambradp60", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_ambradp60_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has IBM PS/2 Type 1 KBC firmware. */ + { + .name = "[i430LX] IBM PS/ValuePoint P60", + .internal_name = "valuepointp60", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_valuepointp60_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i430LX] Intel Premiere/PCI", + .internal_name = "revenge", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_revenge_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMI MegaKey KBC firmware. */ + { + .name = "[i430LX] Micro Star 586MC1", + .internal_name = "586mc1", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_586mc1_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i430LX] Packard Bell PB520R", + .internal_name = "pb520r", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_INTEL_430LX, + .init = machine_at_pb520r_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 139264, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &gd5434_onboard_pci_device, + .vid_device = NULL + }, + + /* OPTi 596/597 */ + /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the + PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF + (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ + { + .name = "[OPTi 597] AMI Excalibur VLB", + .internal_name = "excalibur", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_OPTI_547_597, + .init = machine_at_excalibur_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 60000000, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_VLB, + .flags = MACHINE_IDE, + .ram = { + .min = 2048, + .max = 65536, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* OPTi 596/597/822 */ + /* This has AMIKey 'F' KBC firmware. */ + { + .name = "[OPTi 597] Supermicro P5VL-PCI", + .internal_name = "p5vl", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_OPTI_547_597, + .init = machine_at_p5vl_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PCIV, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* SiS 50x */ + /* This has some form of AMI MegaKey as it uses keyboard controller command 0xCC. */ + { + .name = "[SiS 501] AMI Excalibur PCI-II Pentium ISA", + .internal_name = "excaliburpci2", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_SIS_501, + .init = machine_at_excaliburpci2_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[SiS 501] ASUS PCI/I-P5SP4", + .internal_name = "p5sp4", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_SIS_501, + .init = machine_at_p5sp4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Socket 5 machines */ /* 430NX */ - { "[i430NX] Intel Premiere/PCI II", "plato", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, - { "[i430NX] IBM Ambra DP90 PCI", "ambradp90", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp90_init, NULL }, - { "[i430NX] Gigabyte GA-586IP", "430nx", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_430nx_init, NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i430NX] Intel Premiere/PCI II", + .internal_name = "plato", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430NX, + .init = machine_at_plato_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 1.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the Phoenix MultiKey KBC firmware. + This is basically an Intel Premiere/PCI II with a fancier POST screen. */ + { + .name = "[i430NX] AMBRA DP90 PCI", + .internal_name = "ambradp90", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430NX, + .init = machine_at_ambradp90_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 1.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMI MegaKey KBC firmware. */ + { + .name = "[i430NX] Gigabyte GA-586IP", + .internal_name = "430nx", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430NX, + .init = machine_at_430nx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 1.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 2048, + .max = 131072, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 430FX */ - { "[i430FX] Acer V30", "acerv30", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_acerv30_init, NULL }, - { "[i430FX] Gateway 2000 Zappa", "gw2kzp", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_gw2kzp_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_VECTRA54) - { "[i430FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2, 8, 128, 8, 511, machine_at_vectra54_init, NULL }, -#endif - { "[i430FX] Intel Advanced/ZP", "zappa", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, - { "[i430FX] NEC PowerMate V", "powermate_v", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_powermate_v_init, NULL }, - { "[i430FX] PC Partner MB500N", "mb500n", MACHINE_TYPE_SOCKET5, MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + /* Uses an ACER/NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware (V5.0). */ + { + .name = "[i430FX] Acer V30", + .internal_name = "acerv30", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_acerv30_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[i430FX] AMI Apollo", + .internal_name = "apollo", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_apollo_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey H KBC firmware. */ + { + .name = "[i430FX] DataExpert EXP8551", + .internal_name = "exp8551", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_exp8551_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_GAMEPORT, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430FX] Intel Advanced/ZP", + .internal_name = "zappa", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_zappa_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS sends KBC command B3 which indicates an AMI (or VIA VT82C42N) KBC. */ + { + .name = "[i430FX] NEC PowerMate V", + .internal_name = "powermatev", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_powermatev_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a VIA VT82C42N KBC. */ + { + .name = "[i430FX] PC Partner MB500N", + .internal_name = "mb500n", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_mb500n_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey Z(!) KBC firmware. */ + { + .name = "[i430FX] TriGem Hawk", + .internal_name = "hawk", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_hawk_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, - /* Socket 7 machines */ + /* OPTi 596/597 */ + /* This uses an AMI KBC firmware in PS/2 mode (it sends command A5 with the + PS/2 "Load Security" meaning), most likely MegaKey as it sends command AF + (Set Extended Controller RAM) just like the later Intel AMI BIOS'es. */ + { + .name = "[OPTi 597] TMC PAT54PV", + .internal_name = "pat54pv", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_OPTI_547_597, + .init = machine_at_pat54pv_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_K5, CPU_5K86), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 1.5 + }, + .bus_flags = MACHINE_VLB, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 2048, + .max = 65536, + .step = 2048 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* OPTi 596/597/822 */ + { + .name = "[OPTi 597] Shuttle HOT-543", + .internal_name = "hot543", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_OPTI_547_597, + .init = machine_at_hot543_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PCIV, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* SiS 85C50x */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[SiS 501] ASUS PCI/I-P54SP4", + .internal_name = "p54sp4", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_SIS_501, + .init = machine_at_p54sp4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_K5, CPU_5K86), + .min_bus = 40000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 1.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[SiS 501] BCM SQ-588", + .internal_name = "sq588", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_SIS_501, + .init = machine_at_sq588_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + CPU_BLOCK(CPU_PENTIUMMMX), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 1.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* Socket 7 (Single Voltage) machines */ /* 430FX */ - { "[i430FX-3V] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, - { "[i430FX-3V] Gateway 2000 Thor", "gw2katx", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_gw2katx_init, NULL }, - { "[i430FX-3V] Intel Advanced/ATX", "thor", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, - { "[i430FX-3V] Intel Advanced/EV", "endeavor", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, - { "[i430FX-3V] MR 430FX clone", "mr586", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2, 8, 128, 8, 127, machine_at_mr586_init, NULL }, - { "[i430FX-3V] MR Intel Advanced/ATX", "mrthor", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_mrthor_init, NULL }, - { "[i430FX-3V] Packard Bell PB640", "pb640", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, at_pb640_get_device }, - { "[i430FX-3V] QDI Chariot", "chariot", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73VCH, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_chariot_init, NULL }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[i430FX] ASUS P/I-P54TP4XE", + .internal_name = "p54tp4xe", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_p54tp4xe_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3600, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[i430FX] ASUS P/I-P54TP4XE (MR BIOS)", + .internal_name = "p54tp4xe_mr", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_p54tp4xe_mr_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3600, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430FX] Gateway 2000 Thor", + .internal_name = "gw2katx", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_gw2katx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O + chip with on-chip KBC and AMI MegaKey KBC firmware. */ + { + .name = "[i430FX] HP Vectra VL 5 Series 4", + .internal_name = "vectra54", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_vectra54_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 511, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_phoenix_trio64_onboard_pci_device, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430FX] Intel Advanced/ATX", + .internal_name = "thor", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_thor_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_phoenix_trio64vplus_onboard_pci_device, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430FX] Intel Advanced/ATX (MR BIOS)", + .internal_name = "mrthor", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_mrthor_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_phoenix_trio64vplus_onboard_pci_device, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430FX] Intel Advanced/EV", + .internal_name = "endeavor", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_endeavor_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_phoenix_trio64_onboard_pci_device, + .vid_device = NULL + }, + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[i430FX] MSI MS-5119", + .internal_name = "ms5119", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_ms5119_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This most likely uses AMI MegaKey KBC firmware as well due to having the same + Super I/O chip (that has the KBC firmware on it) as eg. the Advanced/EV. */ + { + .name = "[i430FX] Packard Bell PB640", + .internal_name = "pb640", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_pb640_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &gd5440_onboard_pci_device, + .vid_device = NULL + }, + /* Has an AMI 'H' KBC firmware (1992). */ + { + .name = "[i430FX] QDI FMB", + .internal_name = "fmb", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_fmb_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2, CPU_Cx6x86, CPU_Cx6x86L, CPU_Cx6x86MX), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 430HX */ - { "[i430HX-3V] Acer M3a", "acerm3a", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, - { "[i430HX-3V] AOpen AP53", "ap53", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, - { "[i430HX-3V] SuperMicro Super P55T2S", "p55t2s", MACHINE_TYPE_SOCKET7_3V, MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - - { "[i430HX] Acer V35n", "acerv35n", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, - { "[i430HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 127, machine_at_p55t2p4_init, NULL }, - { "[i430HX] Micronics M7S-Hi", "m7shi", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 511, machine_at_m7shi_init, NULL }, - { "[i430HX] Intel TC430HX", "tc430hx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 255, machine_at_tc430hx_init, NULL }, - { "[i430HX] Toshiba Equium 5200D", "equium5200", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_equium5200_init, NULL }, - { "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", "p65up5_cp55t2d", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p65up5_cp55t2d_init, NULL }, + /* I can't determine what KBC firmware this has, but given that the Acer V35N and + V60 have Phoenix MultiKey KBC firmware on the chip, I'm going to assume so + does the M3A. */ + { + .name = "[i430HX] Acer M3A", + .internal_name = "acerm3a", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_acerm3a_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3300, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 196608, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[i430HX] AOpen AP53", + .internal_name = "ap53", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_ap53_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3450, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* [TEST] Has a VIA 82C42N KBC, with AMIKey F KBC firmware. */ + { + .name = "[i430HX] Biostar MB-8500TUC", + .internal_name = "8500tuc", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_8500tuc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* [TEST] Unable to determine what KBC this has. A list on a Danish site shows + the BIOS as having a -0 string, indicating non-AMI KBC firmware. */ + { + .name = "[i430HX] Supermicro P55T2S", + .internal_name = "p55t2s", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_p55t2s_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3300, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 430VX */ - { "[i430VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, - { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, - { "[i430VX] Epox P55-VA", "p55va", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, - { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_brio80xx_init, NULL }, - { "[i430VX] Biostar 8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, {{ "Intel", cpus_Pentium}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_8500tvxa_init, NULL }, - { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_pb680_init, NULL }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { + .name = "[i430VX] ECS P5VX-B", + .internal_name = "p5vxb", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_p5vxb_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430VX] Gateway 2000 Tigereye", + .internal_name = "gw2kte", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_gw2kte_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* SiS 5511 */ + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { + .name = "[SiS 5511] AOpen AP5S", + .internal_name = "ap5s", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_SIS_5511, + .init = machine_at_ap5s_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* Socket 7 (Dual Voltage) machines */ + /* 430HX */ + /* Has SST flash and the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ + { + .name = "[i430HX] Acer V35N", + .internal_name = "acerv35n", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_acerv35n_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_Cx6x86MX), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 196608, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { + .name = "[i430HX] ASUS P/I-P55T2P4", + .internal_name = "p55t2p4", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_p55t2p4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 83333333, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ + { + .name = "[i430HX] Micronics M7S-Hi", + .internal_name = "m7shi", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_m7shi_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 511, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430HX] Intel TC430HX", + .internal_name = "tc430hx", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_tc430hx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430HX] Toshiba Equium 5200D", + .internal_name = "equium5200", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_equium5200_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 196608, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . + Yes, this is an Intel AMI BIOS with a fancy splash screen. */ + { + .name = "[i430HX] Sony Vaio PCV-90", + .internal_name = "pcv90", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_pcv90_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 196608, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ + { + .name = "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", + .internal_name = "p65up5_cp55t2d", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_p65up5_cp55t2d_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* 430VX */ + /* This has the VIA VT82C42N KBC. */ + { + .name = "[i430VX] AOpen AP5VM", + .internal_name = "ap5vm", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_ap5vm_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2600, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_SCSI, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has AMIKey H KBC firmware (AMIKey-2). */ + { + .name = "[i430VX] ASUS P/I-P55TVP4", + .internal_name = "p55tvp4", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_p55tvp4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS does not send a single non-standard KBC command, so it must have a standard IBM + PS/2 KBC firmware or a clone thereof. */ + { + .name = "[i430VX] Azza PT-5IV", + .internal_name = "5ivg", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_5ivg_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* [TEST] Has AMIKey 'F' KBC firmware. */ + { + .name = "[i430VX] Biostar MB-8500TVX-A", + .internal_name = "8500tvxa", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_8500tvxa_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2600, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS does not send a single non-standard KBC command, but the board has a SMC Super I/O + chip with on-chip KBC and AMI MegaKey KBC firmware. */ + { + .name = "[i430VX] Compaq Presario 2240", + .internal_name = "presario2240", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_presario2240_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_trio64v2_dx_onboard_pci_device, + .vid_device = NULL + }, + /* This most likely has AMI MegaKey as above. */ + { + .name = "[i430VX] Compaq Presario 4500", + .internal_name = "presario4500", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_presario4500_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &s3_trio64v2_dx_onboard_pci_device, + .vid_device = NULL + }, + /* The BIOS sends KBC command CB which is an AMI KBC command, so it has an AMI KBC firmware. */ + { + .name = "[i430VX] Epox P55-VA", + .internal_name = "p55va", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_p55va_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS does not send a single non-standard KBC command. */ + { + .name = "[i430VX] HP Brio 80xx", + .internal_name = "brio80xx", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_brio80xx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 2200, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i430VX] Packard Bell PB680", + .internal_name = "pb680", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_pb680_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the AMIKey 'H' firmware, possibly AMIKey-2. Photos show it with a BestKey, so it + likely clones the behavior of AMIKey 'H'. */ + { + .name = "[i430VX] PC Partner MB520N", + .internal_name = "mb520n", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_mb520n_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2600, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ + { + .name = "[i430VX] Shuttle HOT-557", + .internal_name = "430vx", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430VX, + .init = machine_at_i430vx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_GAMEPORT, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 430TX */ - { "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 255, machine_at_nupro592_init, NULL }, - { "[i430TX] ASUS TX97", "tx97", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 255, machine_at_tx97_init, NULL }, - { "[i430TX] Intel YM430TX", "ym430tx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 255, machine_at_ym430tx_init, NULL }, - { "[i430TX] PC Partner MB540N", "mb540n", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 255, machine_at_mb540n_init, NULL }, - { "[i430TX] SuperMicro Super P5MMS98", "p5mms98", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 255, machine_at_p5mms98_init, NULL }, + /* The BIOS sends KBC command B8, CA, and CB, so it has an AMI KBC firmware. */ + { + .name = "[i430TX] ADLink NuPRO-592", + .internal_name = "nupro592", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_nupro592_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 1900, + .max_voltage = 2800, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has the AMIKey KBC firmware, which is an updated 'F' type (YM430TX is based on the TX97). */ + { + .name = "[i430TX] ASUS TX97", + .internal_name = "tx97", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_tx97_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 75000000, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, +#if defined(DEV_BRANCH) && defined(USE_AN430TX) + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i430TX] Intel AN430TX", + .internal_name = "an430tx", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_an430tx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, +#endif + /* This has the AMIKey KBC firmware, which is an updated 'F' type. */ + { + .name = "[i430TX] Intel YM430TX", + .internal_name = "ym430tx", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_ym430tx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. */ + { + .name = "[i430TX] PC Partner MB540N", + .internal_name = "mb540n", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_mb540n_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2700, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Award BIOS, PS2, EDO, SDRAM, 4 PCI, 4 ISA, VIA VT82C42N KBC */ + { + .name = "[i430TX] Soltek SL-56A5", + .internal_name = "56a5", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_56a5_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 55000000, + .max_bus = 75000000, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5, + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* [TEST] Has AMIKey 'H' KBC firmware. */ + { + .name = "[i430TX] Supermicro P5MMS98", + .internal_name = "p5mms98", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_p5mms98_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* Apollo VPX */ - { "[VIA VPX] FIC VA-502", "ficva502", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ficva502_init, NULL }, + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA VPX] FIC VA-502", + .internal_name = "ficva502", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_VPX, + .init = machine_at_ficva502_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 75000000, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* Apollo VP3 */ - { "[VIA VP3] FIC PA-2012", "ficpa2012", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_ficpa2012_init, NULL }, - + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA VP3] FIC PA-2012", + .internal_name = "ficpa2012", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_VP3, + .init = machine_at_ficpa2012_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 55000000, + .max_bus = 75000000, + .min_voltage = 2100, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* SiS 5571 */ + /* Has the SiS 5571 chipset with on-chip KBC. */ + { + .name = "[SiS 5571] Rise R534F", + .internal_name = "r534f", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_SIS_5571, + .init = machine_at_r534f_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 55000000, + .max_bus = 83333333, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 393216, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the SiS 5571 chipset with on-chip KBC. */ + { + .name = "[SiS 5571] MSI MS-5146", + .internal_name = "ms5146", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_SIS_5571, + .init = machine_at_ms5146_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 75000000, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* ALi ALADDiN IV+ */ + /* Has the ALi M1543 southbridge with on-chip KBC. */ + { + .name = "[ALi ALADDiN IV+] PC Chips M560", + .internal_name = "m560", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS, + .init = machine_at_m560_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 83333333, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the ALi M1543 southbridge with on-chip KBC. */ + { + .name = "[ALi ALADDiN IV+] MSI MS-5164", + .internal_name = "ms5164", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS, + .init = machine_at_ms5164_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 83333333, + .min_voltage = 2100, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Super Socket 7 machines */ + /* ALi ALADDiN V */ + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { + .name = "[ALi ALADDiN V] ASUS P5A", + .internal_name = "p5a", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, + .init = machine_at_p5a_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 120000000, + .min_voltage = 2000, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Is the exact same as the Matsonic MS6260S. Has the ALi M1543C southbridge + with on-chip KBC. */ + { + .name = "[ALi ALADDiN V] PC Chips M579", + .internal_name = "m579", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, + .init = machine_at_m579_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 2000, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { + .name = "[ALi ALADDiN V] Gigabyte GA-5AA", + .internal_name = "5aa", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, + .init = machine_at_5aa_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 140000000, + .min_voltage = 1300, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { + .name = "[ALi ALADDiN V] Gigabyte GA-5AX", + .internal_name = "5ax", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_V, + .init = machine_at_5ax_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 140000000, + .min_voltage = 1300, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Apollo MVP3 */ - { "[VIA MVP3] AOpen AX59 Pro", "ax59pro", MACHINE_TYPE_SOCKETS7, MACHINE_CPUS_PENTIUM_SS7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_ax59pro_init, NULL }, - { "[VIA MVP3] FIC VA-503+", "ficva503p", MACHINE_TYPE_SOCKETS7, MACHINE_CPUS_PENTIUM_SS7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 255, machine_at_mvp3_init, NULL }, + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA MVP3] AOpen AX59 Pro", + .internal_name = "ax59pro", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_MVP3, + .init = machine_at_ax59pro_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 124242424, + .min_voltage = 1300, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA MVP3] FIC VA-503+", + .internal_name = "ficva503p", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_MVP3, + .init = machine_at_mvp3_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 124242424, + .min_voltage = 2000, + .max_voltage = 3200, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA MVP3] FIC VA-503A", + .internal_name = "ficva503a", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_MVP3, + .init = machine_at_ficva503a_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 124242424, + .min_voltage = 1800, + .max_voltage = 3100, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_A97, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the VIA VT82C686A southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA MVP3] Soyo 5EMA PRO", + .internal_name = "5emapro", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_MVP3, + .init = machine_at_5emapro_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 124242424, + .min_voltage = 2000, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* Socket 8 machines */ + /* 450KX */ + /* This has an AMIKey-2, which is an updated version of type 'H'. */ + { + .name = "[i450KX] ASUS P/I-P6RP4", + .internal_name = "p6rp4", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_450KX, + .init = machine_at_p6rp4_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* 440FX */ - { "[i440FX] ASUS P/I-P65UP5 (C-P6ND)", "p65up5_cp6nd", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_p65up5_cp6nd_init, NULL }, - { "[i440FX] Biostar MB-8500ttc", "8500ttc", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_8500ttc_init, NULL }, - { "[i440FX] Gateway 2000 Venus", "gw2kvs", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_gw2kvs_init, NULL }, - { "[i440FX] Gigabyte GA-686NX", "686nx", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_686nx_init, NULL }, - { "[i440FX] Acer V60N", "v60n", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_v60n_init, NULL }, - { "[i440FX] Intel AP440FX", "ap440fx", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_ap440fx_init, NULL }, - { "[i440FX] Intel VS440FX", "vs440fx", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_vs440fx_init, NULL }, - { "[i440FX] Micronics M6MI", "m6mi", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_m6mi_init, NULL }, - { "[i440FX] PC Partner MB600N", "mb600n", MACHINE_TYPE_SOCKET8, {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_mb600n_init, NULL }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ + { + .name = "[i440FX] Acer V60N", + .internal_name = "acerv60n", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_acerv60n_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ + { + .name = "[i440FX] ASUS P/I-P65UP5 (C-P6ND)", + .internal_name = "p65up5_cp6nd", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_p65up5_cp6nd_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* The MB-8600TTX has an AMIKey 'F' KBC firmware, so I'm going to assume so does + the MB-8600TTC until someone can actually identify it. */ + { + .name = "[i440FX] Biostar MB-8600TTC", + .internal_name = "8600ttc", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_8600ttc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2900, + .max_voltage = 3300, + .min_multi = 2.0, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + { + .name = "[i440FX] Gigabyte GA-686NX", + .internal_name = "686nx", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_686nx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i440FX] Intel AP440FX", + .internal_name = "ap440fx", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_ap440fx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 3.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the + PC87306 Super I/O chip, command 0xA1 returns '5'. + Command 0xA0 copyright string: (C)1994 AMI . */ + { + .name = "[i440FX] Intel VS440FX", + .internal_name = "vs440fx", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_vs440fx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 3.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */ + { + .name = "[i440FX] Micronics M6Mi", + .internal_name = "m6mi", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_m6mi_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2900, + .max_voltage = 3300, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* I found a BIOS string of it that ends in -S, but it could be a typo for -5 + (there's quite a few AMI BIOS strings around with typo'd KBC codes), so I'm + going to give it an AMI MegaKey. */ + { + .name = "[i440FX] PC Partner MB600N", + .internal_name = "mb600n", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_mb600n_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* Slot 1 machines */ - /* 440FX */ - { "[i440FX] ASUS P/I-P65UP5 (C-PKND)", "p65up5_cpknd", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII66}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_p65up5_cpknd_init, NULL }, - { "[i440FX] ASUS KN97", "kn97", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII66}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_kn97_init, NULL }, + /* ALi ALADDiN V */ + /* Has the ALi M1543C southbridge with on-chip KBC. */ + { + .name = "[ALi ALADDiN-PRO II] PC Chips M729", + .internal_name = "m729", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_ALI_ALADDIN_PRO_II, + .init = machine_at_m729_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 1024, + .max = 1572864, + .step = 8192 + }, + 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, - /* 440LX */ - { "[i440LX] ABIT LX6", "lx6", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII66}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_lx6_init, NULL }, + /* 440FX */ + /* The base board has AMIKey-2 (updated 'H') KBC firmware. */ + { + .name = "[i440FX] ASUS P/I-P65UP5 (C-PKND)", + .internal_name = "p65up5_cpknd", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_p65up5_cpknd_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it + must be an ASIC that clones the standard IBM PS/2 KBC. */ + { + .name = "[i440FX] ASUS KN97", + .internal_name = "kn97", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_kn97_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 83333333, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 127, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* 440LX */ + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440LX] ABIT LX6", + .internal_name = "lx6", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440LX, + .init = machine_at_lx6_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 100000000, + .min_voltage = 1500, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix + MultiKey KBC firmware. */ + { + .name = "[i440LX] Micronics Spitfire", + .internal_name = "spitfire", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440LX, + .init = machine_at_spitfire_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 440EX */ - { "[i440EX] QDI EXCELLENT II", "p6i440e2", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII66}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 255, machine_at_p6i440e2_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440EX] QDI EXCELLENT II", + .internal_name = "p6i440e2", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440EX, + .init = machine_at_p6i440e2_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 83333333, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 3.0, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 440BX */ - { "[i440BX] ASUS P2B-LS", "p2bls", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_p2bls_init, NULL }, - { "[i440BX] ASUS P2B-LS (coreboot BIOS)", "p2bls_cb", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_COREBOOT, 8, 1024, 8, 255, machine_at_p2bls_init, NULL }, - { "[i440BX] ASUS P3B-F", "p3bf", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_p3bf_init, NULL }, - { "[i440BX] ASUS P3B-F (coreboot BIOS)", "p3bf_cb", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_COREBOOT, 8, 1024, 8, 255, machine_at_p3bf_init, NULL }, - { "[i440BX] ABIT BF6", "bf6", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_bf6_init, NULL }, - { "[i440BX] AOpen AX6BC", "ax6bc", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_ax6bc_init, NULL }, - { "[i440BX] A-Trend ATC6310BXII", "atc6310bxii", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"VIA", cpus_Cyrix3},{"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_atc6310bxii_init, NULL }, - { "[i440BX] Tyan Tsunami ATX", "tsunamiatx", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_SOUND, 8, 1024, 8, 255, machine_at_tsunamiatx_init, at_tsunamiatx_get_device }, - { "[i440BX] Supermicro P6SBA", "p6sba", MACHINE_TYPE_SLOT1, {{"Intel", cpus_PentiumII}, {"Intel/PGA370", cpus_Celeron},{"", NULL}, {"", NULL},{"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_p6sba_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] ASUS P2B-LS", + .internal_name = "p2bls", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_p2bls_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 112121212, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] ASUS P3B-F", + .internal_name = "p3bf", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_p3bf_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] ABIT BF6", + .internal_name = "bf6", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_bf6_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] AOpen AX6BC", + .internal_name = "ax6bc", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_ax6bc_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 112121212, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] Gigabyte GA-686BX", + .internal_name = "686bx", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_686bx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a SM(S)C FDC37M60x Super I/O chip with on-chip KBC with most likely + AMIKey-2 KBC firmware. */ + { + .name = "[i440BX] HP Vectra VEi 8", + .internal_name = "vei8", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_vei8_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC + with most likely AMIKey-2 KBC firmware. */ + { + .name = "[i440BX] Tyan Tsunami ATX", + .internal_name = "s1846", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_s1846_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 112121212, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &es1371_onboard_device, + .vid_device = NULL + }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] Supermicro P6SBA", + .internal_name = "p6sba", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_p6sba_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, - /* Slot 2 machines(Including Slot 1/2 Hybrids) */ + /* 440ZX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440ZX] MSI MS-6168", + .internal_name = "ms6168", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440ZX, + .init = machine_at_ms6168_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL | MACHINE_AV, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &voodoo_3_2000_agp_onboard_8m_device, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440ZX] Packard Bell Bora Pro", + .internal_name = "borapro", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440ZX, + .init = machine_at_borapro_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL | MACHINE_AV, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &voodoo_3_2000_agp_onboard_8m_device, + .vid_device = NULL + }, + + /* SMSC VictoryBX-66 */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[SMSC VictoryBX-66] A-Trend ATC6310BXII", + .internal_name = "atc6310bxii", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_SMSC_VICTORYBX_66, + .init = machine_at_atc6310bxii_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* VIA Apollo Pro */ + /* Has the VIA VT82C596B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA Apollo Pro] FIC KA-6130", + .internal_name = "ficka6130", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO, + .init = machine_at_ficka6130_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[VIA Apollo Pro 133] ASUS P3V133", + .internal_name = "p3v133", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133, + .init = machine_at_p3v133_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[VIA Apollo Pro 133A] ASUS P3V4X", + .internal_name = "p3v4x", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, + .init = machine_at_p3v4x_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 2097152, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* Slot 1/2 machines */ /* 440GX */ - { "[i440GX] Gigabyte GA-6GXU", "6gxu", MACHINE_TYPE_SLOT2, {{"Intel", cpus_Xeon}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 16, 2048, 16, 511, machine_at_6gxu_init, NULL }, - { "[i440GX] Supermicro S2DGE", "s2dge", MACHINE_TYPE_SLOT2, {{"Intel", cpus_Xeon}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 16, 2048, 16, 511, machine_at_s2dge_init, NULL }, + /* Has a National Semiconductors PC87309 Super I/O chip with on-chip KBC + with most likely AMIKey-2 KBC firmware. */ + { + .name = "[i440GX] Freeway FW-6400GX", + .internal_name = "fw6400gx", + .type = MACHINE_TYPE_SLOT1_2, + .chipset = MACHINE_CHIPSET_INTEL_440GX, + .init = machine_at_fw6400gx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1 | CPU_PKG_SLOT2, + .block = CPU_BLOCK_NONE, + .min_bus = 100000000, + .max_bus = 150000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 3.0, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_NOISA, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 16384, + .max = 2080768, + .step = 16384 + }, + .nvrmask = 511, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* Slot 1/Socket 370 machines */ + /* 440BX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] Tyan Trinity 371", + .internal_name = "s1857", + .type = MACHINE_TYPE_SLOT1_370, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_s1857_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1 | CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &es1371_onboard_device, + .vid_device = NULL + }, + + /* Slot 2 machines */ + /* 440GX */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440GX] Gigabyte GA-6GXU", + .internal_name = "6gxu", + .type = MACHINE_TYPE_SLOT2, + .chipset = MACHINE_CHIPSET_INTEL_440GX, + .init = machine_at_6gxu_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT2, + .block = CPU_BLOCK_NONE, + .min_bus = 100000000, + .max_bus = 133333333, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 16384, + .max = 2097152, + .step = 16384 + }, + .nvrmask = 511, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440GX] Supermicro S2DGE", + .internal_name = "s2dge", + .type = MACHINE_TYPE_SLOT2, + .chipset = MACHINE_CHIPSET_INTEL_440GX, + .init = machine_at_s2dge_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT2, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 16384, + .max = 2097152, + .step = 16384 + }, + .nvrmask = 511, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* PGA370 machines */ /* 440LX */ - { "[i440LX] Supermicro 370SLM", "s370slm", MACHINE_TYPE_SOCKET370, {{"Intel", cpus_Celeron}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 255, machine_at_s370slm_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440LX] Supermicro 370SLM", + .internal_name = "s370slm", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_INTEL_440LX, + .init = machine_at_s370slm_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED, + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 440BX */ - { "[i440BX] ASUS CUBX", "cubx", MACHINE_TYPE_SOCKET370, {{"Intel", cpus_Celeron}, {"VIA", cpus_Cyrix3}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_cubx_init, NULL }, - { "[i440BX] A-Trend ATC7020BXII", "atc7020bxii", MACHINE_TYPE_SOCKET370, {{"Intel", cpus_Celeron}, {"VIA", cpus_Cyrix3}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_atc7020bxii_init, NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] AEWIN AW-O671R", + .internal_name = "awo671r", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_awo671r_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 /* limits assumed */ + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] ASUS CUBX", + .internal_name = "cubx", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_cubx_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] AmazePC AM-BX133", + .internal_name = "ambx133", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_ambx133_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 /* limits assumed */ + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* 440ZX */ - { "[i440ZX] Soltek SL-63A1", "63a", MACHINE_TYPE_SOCKET370, {{"Intel", cpus_Celeron}, {"VIA", cpus_Cyrix3}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 255, machine_at_63a_init, NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440ZX] Soltek SL-63A1", + .internal_name = "63a1", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_INTEL_440ZX, + .init = machine_at_63a1_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + /* SMSC VictoryBX-66 */ + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[SMSC VictoryBX-66] A-Trend ATC7020BXII", + .internal_name = "atc7020bxii", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_SMSC_VICTORYBX_66, + .init = machine_at_atc7020bxii_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, /* VIA Apollo Pro */ - { "[VIA Apollo Pro] PC Partner APAS3", "apas3", MACHINE_TYPE_SOCKET370, {{"Intel", cpus_Celeron}, {"VIA", cpus_Cyrix3}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 255, machine_at_apas3_init, NULL }, + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA Apollo Pro] PC Partner APAS3", + .internal_name = "apas3", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO, + .init = machine_at_apas3_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[VIA Apollo Pro 133] ECS P6BAP", + .internal_name = "p6bap", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133, + .init = machine_at_p6bap_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1572864, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA Apollo Pro 133A] Acorp 6VIA90AP", + .internal_name = "6via90ap", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, + .init = machine_at_6via90ap_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED, + }, + .bus_flags = MACHINE_PS2_A97, + .flags = MACHINE_IDE_DUAL | MACHINE_AG, + .ram = { + .min = 16384, + .max = 3145728, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + /* Has the VIA VT82C686B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA Apollo Pro 133A] ASUS CUV4X-LS", + .internal_name = "cuv4xls", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, + .init = machine_at_cuv4xls_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 150000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_NOI97, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND, + .ram = { + .min = 16384, + .max = 4194304, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &cmi8738_onboard_device, + .vid_device = NULL + }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[VIA Apollo Pro 133A] BCM GT694VA", + .internal_name = "gt694va", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, + .init = machine_at_gt694va_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND, + .ram = { + .min = 16384, + .max = 3145728, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &es1371_onboard_device, + .vid_device = NULL + }, - { NULL, NULL, MACHINE_TYPE_NONE, {{"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}}, 0, 0, 0, 0, 0, NULL, NULL } + /* Miscellaneous/Fake/Hypervisor machines */ + /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] Microsoft Virtual PC 2007", + .internal_name = "vpc2007", + .type = MACHINE_TYPE_MISC, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_vpc2007_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), + .min_bus = 0, + .max_bus = 66666667, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + }, + + { + .name = NULL, + .internal_name = NULL, + .type = MACHINE_TYPE_NONE, + .chipset = MACHINE_CHIPSET_NONE, + .init = NULL, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = 0, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_BUS_NONE, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 0, + .max = 0, + .step = 0 + }, + .nvrmask = 0, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = NULL, + .vid_device = NULL + } }; +/* Saved copies - jumpers get applied to these. + We use also machine_gpio to store IBM PC/XT jumpers as they need more than one byte. */ +static uint16_t machine_p1; +static uint32_t machine_gpio; + +uint8_t +machine_get_p1(void) +{ + return machine_p1; +} + +void +machine_load_p1(int m) +{ + machine_p1 = machines[machine].kbc_p1; +} + +uint32_t +machine_get_gpio(void) +{ + return machine_gpio; +} + +void +machine_load_gpio(int m) +{ + machine_gpio = machines[machine].gpio; +} + +void +machine_set_gpio(uint32_t gpio) +{ + machine_gpio = gpio; +} int machine_count(void) { - return((sizeof(machines) / sizeof(machine)) - 1); + return((sizeof(machines) / sizeof(machine_t)) - 1); } - char * machine_getname(void) { return((char *)machines[machine].name); } - char * machine_getname_ex(int m) { return((char *)machines[m].name); } - const device_t * machine_getdevice(int m) { - if (machines[m].get_device) - return(machines[m].get_device()); + if (machines[m].device) + return(machines[m].device); return(NULL); } +const device_t * +machine_getviddevice(int m) +{ + if (machines[m].vid_device) + return(machines[m].vid_device); + + return(NULL); +} char * machine_get_internal_name(void) @@ -395,20 +11044,63 @@ machine_get_internal_name(void) return((char *)machines[machine].internal_name); } - char * machine_get_internal_name_ex(int m) { return((char *)machines[m].internal_name); } - int machine_get_nvrmask(int m) { return(machines[m].nvrmask); } +int +machine_has_flags(int m, int flags) +{ + return(machines[m].flags & flags); +} + +int +machine_has_bus(int m, int bus_flags) +{ + return(machines[m].bus_flags & bus_flags); +} + +int +machine_has_cartridge(int m) +{ + return(machine_has_bus(m, MACHINE_CARTRIDGE) ? 1 : 0); +} + +int +machine_get_min_ram(int m) +{ + return(machines[m].ram.min); +} + +int +machine_get_max_ram(int m) +{ +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + return MIN(((int) machines[m].ram.max), 2097152); +#else + return MIN(((int) machines[m].ram.max), 3145728); +#endif +} + +int +machine_get_ram_granularity(int m) +{ + return(machines[m].ram.step); +} + +int +machine_get_type(int m) +{ + return(machines[m].type); +} int machine_get_machine_from_internal_name(char *s) @@ -416,9 +11108,9 @@ machine_get_machine_from_internal_name(char *s) int c = 0; while (machines[c].init != NULL) { - if (!strcmp(machines[c].internal_name, (const char *)s)) - return(c); - c++; + if (!strcmp(machines[c].internal_name, (const char *)s)) + return(c); + c++; } return(0); diff --git a/src/machine_status.c b/src/machine_status.c new file mode 100644 index 000000000..258c16821 --- /dev/null +++ b/src/machine_status.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/hdc.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/cartridge.h> +#include <86box/cassette.h> +#include <86box/cdrom.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/hdd.h> +#include <86box/machine_status.h> + +machine_status_t machine_status; + +void +machine_status_init() { + for (size_t i = 0; i < FDD_NUM; ++i) { + machine_status.fdd[i].empty = (strlen(floppyfns[i]) == 0); + machine_status.fdd[i].active = false; + } + for (size_t i = 0; i < CDROM_NUM; ++i) { + machine_status.cdrom[i].empty = cdrom[i].host_drive != 200 || (strlen(cdrom[i].image_path) == 0); + machine_status.cdrom[i].active = false; + } + for (size_t i = 0; i < ZIP_NUM; i++) { + machine_status.zip[i].empty = (strlen(zip_drives[i].image_path) == 0); + machine_status.zip[i].active = false; + } + for (size_t i = 0; i < MO_NUM; i++) { + machine_status.mo[i].empty = (strlen(mo_drives[i].image_path) == 0); + machine_status.mo[i].active = false; + } + + machine_status.cassette.empty = (strlen(cassette_fname) == 0); + + for (size_t i = 0; i < HDD_BUS_USB; i++) { + machine_status.hdd[i].active = false; + } + + machine_status.net.active = false; +} \ No newline at end of file diff --git a/src/mca.c b/src/mca.c index f067d7cdc..4ef00318d 100644 --- a/src/mca.c +++ b/src/mca.c @@ -26,7 +26,7 @@ void mca_init(int nr_cards) mca_card_reset[c] = NULL; mca_priv[c] = NULL; } - + mca_index = 0; mca_nr_cards = nr_cards; } @@ -45,6 +45,20 @@ uint8_t mca_read(uint16_t port) return mca_card_read[mca_index](port, mca_priv[mca_index]); } +uint8_t mca_read_index(uint16_t port, int index) +{ + if (mca_index >= mca_nr_cards) + return 0xff; + if (!mca_card_read[index]) + return 0xff; + return mca_card_read[index](port, mca_priv[index]); +} + +int mca_get_nr_cards(void) +{ + return mca_nr_cards; +} + void mca_write(uint16_t port, uint8_t val) { if (mca_index >= mca_nr_cards) diff --git a/src/mem/CMakeLists.txt b/src/mem/CMakeLists.txt new file mode 100644 index 000000000..9eae342fd --- /dev/null +++ b/src/mem/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(mem OBJECT catalyst_flash.c i2c_eeprom.c intel_flash.c mem.c rom.c + smram.c spd.c sst_flash.c) diff --git a/src/mem/catalyst_flash.c b/src/mem/catalyst_flash.c new file mode 100644 index 000000000..0a7fe2cdf --- /dev/null +++ b/src/mem/catalyst_flash.c @@ -0,0 +1,257 @@ +/* + * 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 Intel 1 Mbit and 2 Mbit, 8-bit and + * 16-bit flash devices. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/machine.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/plat.h> + + +#define FLAG_WORD 4 +#define FLAG_BXB 2 +#define FLAG_INV_A16 1 + + +enum +{ + BLOCK_MAIN1, + BLOCK_MAIN2, + BLOCK_DATA1, + BLOCK_DATA2, + BLOCK_BOOT, + BLOCKS_NUM +}; + +enum +{ + CMD_SET_READ = 0x00, + CMD_READ_SIGNATURE = 0x90, + CMD_ERASE = 0x20, + CMD_ERASE_CONFIRM = 0x20, + CMD_ERASE_VERIFY = 0xA0, + CMD_PROGRAM = 0x40, + CMD_PROGRAM_VERIFY = 0xC0, + CMD_RESET = 0xFF +}; + + +typedef struct flash_t +{ + uint8_t command, pad, + pad0, pad1, + *array; + + mem_mapping_t mapping, mapping_h[2]; +} flash_t; + + +static char flash_path[1024]; + + +static uint8_t +flash_read(uint32_t addr, void *p) +{ + flash_t *dev = (flash_t *) p; + uint8_t ret = 0xff; + + addr &= biosmask; + + switch (dev->command) { + case CMD_ERASE_VERIFY: + case CMD_PROGRAM_VERIFY: + case CMD_RESET: + case CMD_SET_READ: + ret = dev->array[addr]; + break; + + case CMD_READ_SIGNATURE: + if (addr == 0x00000) + ret = 0x31; /* CATALYST */ + else if (addr == 0x00001) + ret = 0xB4; /* 28F010 */ + break; + } + + return ret; +} + + +static uint16_t +flash_readw(uint32_t addr, void *p) +{ + flash_t *dev = (flash_t *)p; + uint16_t *q; + + addr &= biosmask; + + q = (uint16_t *)&(dev->array[addr]); + + return *q; +} + + +static uint32_t +flash_readl(uint32_t addr, void *p) +{ + flash_t *dev = (flash_t *)p; + uint32_t *q; + + addr &= biosmask; + + q = (uint32_t *)&(dev->array[addr]); + + return *q; +} + + +static void +flash_write(uint32_t addr, uint8_t val, void *p) +{ + flash_t *dev = (flash_t *) p; + + addr &= biosmask; + + switch (dev->command) { + case CMD_ERASE: + if (val == CMD_ERASE_CONFIRM) + memset(dev->array, 0xff, biosmask + 1); + break; + + case CMD_PROGRAM: + dev->array[addr] = val; + break; + + default: + dev->command = val; + break; + } +} + + +static void +flash_writew(uint32_t addr, uint16_t val, void *p) +{ +} + + +static void +flash_writel(uint32_t addr, uint32_t val, void *p) +{ +} + + +static void +catalyst_flash_add_mappings(flash_t *dev) +{ + memcpy(dev->array, rom, biosmask + 1); + + mem_mapping_add(&dev->mapping, 0xe0000, 0x20000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); + + mem_mapping_add(&(dev->mapping_h[0]), 0xfffc0000, 0x20000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); + mem_mapping_add(&(dev->mapping_h[1]), 0xfffe0000, 0x20000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); +} + + +static void +catalyst_flash_reset(void *priv) +{ + flash_t *dev = (flash_t *) priv; + + dev->command = CMD_RESET; +} + + +static void * +catalyst_flash_init(const device_t *info) +{ + FILE *f; + flash_t *dev; + + dev = malloc(sizeof(flash_t)); + memset(dev, 0, sizeof(flash_t)); + + sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); + + mem_mapping_disable(&bios_mapping); + mem_mapping_disable(&bios_high_mapping); + + dev->array = (uint8_t *) malloc(0x20000); + memset(dev->array, 0xff, 0x20000); + + catalyst_flash_add_mappings(dev); + + dev->command = CMD_RESET; + + f = nvr_fopen(flash_path, "rb"); + if (f) { + fread(dev->array, 0x20000, 1, f); + fclose(f); + } + + return dev; +} + + +static void +catalyst_flash_close(void *p) +{ + FILE *f; + flash_t *dev = (flash_t *)p; + + f = nvr_fopen(flash_path, "wb"); + fwrite(dev->array, 0x20000, 1, f); + fclose(f); + + free(dev->array); + dev->array = NULL; + + free(dev); +} + + +const device_t catalyst_flash_device = { + .name = "Catalyst 28F010-D Flash BIOS", + .internal_name = "catalyst_flash", + .flags = DEVICE_PCI, + .local = 0, + .init = catalyst_flash_init, + .close = catalyst_flash_close, + .reset = catalyst_flash_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/mem/i2c_eeprom.c b/src/mem/i2c_eeprom.c new file mode 100644 index 000000000..dceac93a5 --- /dev/null +++ b/src/mem/i2c_eeprom.c @@ -0,0 +1,172 @@ +/* + * 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 the 24Cxx series of I2C EEPROMs. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/i2c.h> + + +typedef struct { + void *i2c; + uint8_t addr, *data, writable; + + uint32_t addr_mask, addr_register; + uint8_t addr_len, addr_pos; +} i2c_eeprom_t; + + +#ifdef ENABLE_I2C_EEPROM_LOG +int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG; + + +static void +i2c_eeprom_log(const char *fmt, ...) +{ + va_list ap; + + if (i2c_eeprom_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i2c_eeprom_log(fmt, ...) +#endif + + +static uint8_t +i2c_eeprom_start(void *bus, uint8_t addr, uint8_t read, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + + i2c_eeprom_log("I2C EEPROM %s %02X: start()\n", i2c_getbusname(dev->i2c), dev->addr); + + if (!read) { + dev->addr_pos = 0; + dev->addr_register = (addr << dev->addr_len) & dev->addr_mask; + } + + return 1; +} + + +static uint8_t +i2c_eeprom_read(void *bus, uint8_t addr, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + uint8_t ret = dev->data[dev->addr_register]; + + i2c_eeprom_log("I2C EEPROM %s %02X: read(%06X) = %02X\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register, ret); + dev->addr_register++; + dev->addr_register &= dev->addr_mask; /* roll-over */ + + return ret; +} + + +static uint8_t +i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + + if (dev->addr_pos < dev->addr_len) { + dev->addr_register <<= 8; + dev->addr_register |= data; + dev->addr_register &= (1 << dev->addr_len) - 1; + dev->addr_register |= addr << dev->addr_len; + dev->addr_register &= dev->addr_mask; + i2c_eeprom_log("I2C EEPROM %s %02X: write(address, %06X)\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register); + dev->addr_pos += 8; + } else { + i2c_eeprom_log("I2C EEPROM %s %02X: write(%06X, %02X) = %d\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register, data, !!dev->writable); + if (dev->writable) + dev->data[dev->addr_register] = data; + dev->addr_register++; + dev->addr_register &= dev->addr_mask; /* roll-over */ + return dev->writable; + } + + return 1; +} + + +static void +i2c_eeprom_stop(void *bus, uint8_t addr, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + + i2c_eeprom_log("I2C EEPROM %s %02X: stop()\n", i2c_getbusname(dev->i2c), dev->addr); + + dev->addr_pos = 0; +} + + +uint8_t +log2i(uint32_t i) +{ + uint8_t ret = 0; + while ((i >>= 1)) + ret++; + return ret; +} + + +void * +i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); + memset(dev, 0, sizeof(i2c_eeprom_t)); + + /* Round size up to the next power of 2. */ + uint32_t pow_size = 1 << log2i(size); + if (pow_size < size) + size = pow_size << 1; + size &= 0x7fffff; /* address space limit of 8 MB = 7 bits from I2C address + 16 bits */ + + i2c_eeprom_log("I2C EEPROM %s %02X: init(%d, %d)\n", i2c_getbusname(i2c), addr, size, writable); + + dev->i2c = i2c; + dev->addr = addr; + dev->data = data; + dev->writable = writable; + + dev->addr_len = (size >= 4096) ? 16 : 8; /* use 16-bit addresses on 24C32 and above */ + dev->addr_mask = size - 1; + + i2c_sethandler(dev->i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, i2c_eeprom_stop, dev); + + return dev; +} + + +void +i2c_eeprom_close(void *dev_handle) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle; + + i2c_eeprom_log("I2C EEPROM %s %02X: close()\n", i2c_getbusname(dev->i2c), dev->addr); + + i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, i2c_eeprom_stop, dev); + + free(dev); +} diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index 28ea1e8d4..66c59914d 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -14,8 +14,8 @@ * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -40,6 +40,8 @@ enum { BLOCK_MAIN1, BLOCK_MAIN2, + BLOCK_MAIN3, + BLOCK_MAIN4, BLOCK_DATA1, BLOCK_DATA2, BLOCK_BOOT, @@ -72,11 +74,11 @@ typedef struct flash_t block_start[BLOCKS_NUM], block_end[BLOCKS_NUM], block_len[BLOCKS_NUM]; - mem_mapping_t mapping[4], mapping_h[8]; + mem_mapping_t mapping[4], mapping_h[16]; } flash_t; -static wchar_t flash_path[1024]; +static char flash_path[1024]; static uint8_t @@ -136,7 +138,7 @@ flash_readw(uint32_t addr, void *p) case CMD_IID: if (addr & 2) ret = dev->flash_id; - else + else ret = 0x0089; break; @@ -171,7 +173,9 @@ flash_write(uint32_t addr, uint8_t val, void *p) flash_t *dev = (flash_t *) p; int i; uint32_t bb_mask = biosmask & 0xffffe000; - if (biosmask == 0x3ffff) + if (biosmask == 0x7ffff) + bb_mask &= 0xffff8000; + else if (biosmask == 0x3ffff) bb_mask &= 0xffffc000; if (dev->flags & FLAG_INV_A16) @@ -181,8 +185,8 @@ flash_write(uint32_t addr, uint8_t val, void *p) switch (dev->command) { case CMD_ERASE_SETUP: if (val == CMD_ERASE_CONFIRM) { - for (i = 0; i < 3; i++) { - if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + for (i = 0; i < 6; i++) { + if ((i == dev->program_addr) && (addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]); } @@ -193,7 +197,7 @@ flash_write(uint32_t addr, uint8_t val, void *p) case CMD_PROGRAM_SETUP: case CMD_PROGRAM_SETUP_ALT: - if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr)) + if (((addr & bb_mask) != (dev->block_start[6] & bb_mask)) && (addr == dev->program_addr)) dev->array[addr] = val; dev->command = CMD_READ_STATUS; dev->status = 0x80; @@ -205,6 +209,12 @@ flash_write(uint32_t addr, uint8_t val, void *p) case CMD_CLEAR_STATUS: dev->status = 0; break; + case CMD_ERASE_SETUP: + for (i = 0; i < 7; i++) { + if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + dev->program_addr = i; + } + break; case CMD_PROGRAM_SETUP: case CMD_PROGRAM_SETUP_ALT: dev->program_addr = addr; @@ -220,7 +230,9 @@ flash_writew(uint32_t addr, uint16_t val, void *p) flash_t *dev = (flash_t *) p; int i; uint32_t bb_mask = biosmask & 0xffffe000; - if (biosmask == 0x3ffff) + if (biosmask == 0x7ffff) + bb_mask &= 0xffff8000; + else if (biosmask == 0x3ffff) bb_mask &= 0xffffc000; if (dev->flags & FLAG_INV_A16) @@ -230,8 +242,8 @@ flash_writew(uint32_t addr, uint16_t val, void *p) if (dev->flags & FLAG_WORD) switch (dev->command) { case CMD_ERASE_SETUP: if (val == CMD_ERASE_CONFIRM) { - for (i = 0; i < 3; i++) { - if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + for (i = 0; i < 6; i++) { + if ((i == dev->program_addr) && (addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]); } @@ -242,7 +254,7 @@ flash_writew(uint32_t addr, uint16_t val, void *p) case CMD_PROGRAM_SETUP: case CMD_PROGRAM_SETUP_ALT: - if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr)) + if (((addr & bb_mask) != (dev->block_start[6] & bb_mask)) && (addr == dev->program_addr)) *(uint16_t *) (&dev->array[addr]) = val; dev->command = CMD_READ_STATUS; dev->status = 0x80; @@ -254,6 +266,12 @@ flash_writew(uint32_t addr, uint16_t val, void *p) case CMD_CLEAR_STATUS: dev->status = 0; break; + case CMD_ERASE_SETUP: + for (i = 0; i < 7; i++) { + if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + dev->program_addr = i; + } + break; case CMD_PROGRAM_SETUP: case CMD_PROGRAM_SETUP_ALT: dev->program_addr = addr; @@ -280,17 +298,23 @@ intel_flash_add_mappings(flash_t *dev) uint32_t base, fbase; uint32_t sub = 0x20000; - if (biosmask == 0x3ffff) { + if (biosmask == 0x7ffff) { + sub = 0x80000; + max = 8; + } else if (biosmask == 0x3ffff) { sub = 0x40000; max = 4; } for (i = 0; i < max; i++) { - if (biosmask == 0x3ffff) + if (biosmask == 0x7ffff) + base = 0x80000 + (i << 16); + else if (biosmask == 0x3ffff) base = 0xc0000 + (i << 16); else base = 0xe0000 + (i << 16); - fbase = base & biosmask; + + fbase = base & biosmask; if (dev->flags & FLAG_INV_A16) fbase ^= 0x10000; @@ -300,16 +324,16 @@ intel_flash_add_mappings(flash_t *dev) mem_mapping_add(&(dev->mapping[i]), base, 0x10000, flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, - dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); } mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000) - sub, 0x10000, flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, - dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); - mem_mapping_add(&(dev->mapping_h[i + 4]), (base | 0xfff00000), 0x10000, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); + mem_mapping_add(&(dev->mapping_h[i + max]), (base | 0xfff00000), 0x10000, flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, - dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); } } @@ -328,25 +352,13 @@ static void * intel_flash_init(const device_t *info) { FILE *f; - int l; flash_t *dev; - wchar_t *machine_name, *flash_name; uint8_t type = info->local & 0xff; dev = malloc(sizeof(flash_t)); memset(dev, 0, sizeof(flash_t)); - l = strlen(machine_get_internal_name_ex(machine))+1; - machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); - mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); - l = wcslen(machine_name)+5; - flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); - swprintf(flash_name, l, L"%ls.bin", machine_name); - - if (wcslen(flash_name) <= 1024) - wcscpy(flash_path, flash_name); - else - wcsncpy(flash_path, flash_name, 1024); + sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); dev->flags = info->local & 0xff; @@ -356,75 +368,147 @@ intel_flash_init(const device_t *info) dev->array = (uint8_t *) malloc(biosmask + 1); memset(dev->array, 0xff, biosmask + 1); - if (biosmask == 0x3ffff) { - if (dev->flags & FLAG_WORD) - dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274; - else - dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C; + switch (biosmask) { + case 0x7ffff: + if (dev->flags & FLAG_WORD) + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x4471 : 0x4470; + else + dev->flash_id =(dev->flags & FLAG_BXB) ? 0x8A : 0x89; - /* The block lengths are the same both flash types. */ - dev->block_len[BLOCK_MAIN1] = 0x20000; - dev->block_len[BLOCK_MAIN2] = 0x18000; - dev->block_len[BLOCK_DATA1] = 0x02000; - dev->block_len[BLOCK_DATA2] = 0x02000; - dev->block_len[BLOCK_BOOT] = 0x04000; + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x20000; + dev->block_len[BLOCK_MAIN2] = 0x20000; + dev->block_len[BLOCK_MAIN3] = 0x20000; + dev->block_len[BLOCK_MAIN4] = 0x18000; + dev->block_len[BLOCK_DATA1] = 0x02000; + dev->block_len[BLOCK_DATA2] = 0x02000; + dev->block_len[BLOCK_BOOT] = 0x04000; - if (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */ - dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x3ffff; - dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0x1ffff; - dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x07fff; - dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x05fff; - dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x03fff; - } else { /* 28F002BX-T/28F200BX-T */ - dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x1ffff; - dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0x37fff; - dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x39fff; - dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x3bfff; - dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x3ffff; - } - } else { - dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94; + if (dev->flags & FLAG_BXB) { /* 28F004BX-T/28F400BX-B */ + dev->block_start[BLOCK_BOOT] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_BOOT] = 0x1ffff; + dev->block_start[BLOCK_DATA2] = 0x20000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_DATA2] = 0x3ffff; + dev->block_start[BLOCK_DATA1] = 0x40000; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_DATA1] = 0x5ffff; + dev->block_start[BLOCK_MAIN4] = 0x60000; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0x77fff; + dev->block_start[BLOCK_MAIN3] = 0x78000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_MAIN3] = 0x79fff; + dev->block_start[BLOCK_MAIN2] = 0x7a000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_MAIN2] = 0x7bfff; + dev->block_start[BLOCK_MAIN1] = 0x7c000; /* BOOT BLOCK */ + dev->block_end[BLOCK_MAIN1] = 0x7ffff; + } else { + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x3ffff; + dev->block_start[BLOCK_MAIN3] = 0x40000; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0x5ffff; + dev->block_start[BLOCK_MAIN4] = 0x60000; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0x77fff; + dev->block_start[BLOCK_DATA1] = 0x78000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x79fff; + dev->block_start[BLOCK_DATA2] = 0x7a000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x7bfff; + dev->block_start[BLOCK_BOOT] = 0x7c000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x7ffff; + } + break; - /* The block lengths are the same both flash types. */ - dev->block_len[BLOCK_MAIN1] = 0x1c000; - dev->block_len[BLOCK_MAIN2] = 0x00000; - dev->block_len[BLOCK_DATA1] = 0x01000; - dev->block_len[BLOCK_DATA2] = 0x01000; - dev->block_len[BLOCK_BOOT] = 0x02000; + case 0x3ffff: + if (dev->flags & FLAG_WORD) + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274; + else + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C; - if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */ - dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x1ffff; - dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0xfffff; - dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x02fff; - dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x03fff; - dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x01fff; - } else { /* 28F001BX-T/28F100BX-T */ - dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x1bfff; - dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0xfffff; - dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x1cfff; - dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x1dfff; - dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x1ffff; - } + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x20000; + dev->block_len[BLOCK_MAIN2] = 0x18000; + dev->block_len[BLOCK_MAIN3] = 0x00000; + dev->block_len[BLOCK_MAIN4] = 0x00000; + dev->block_len[BLOCK_DATA1] = 0x02000; + dev->block_len[BLOCK_DATA2] = 0x02000; + dev->block_len[BLOCK_BOOT] = 0x04000; + + if (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x3ffff; + dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x1ffff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x07fff; + dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x05fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x03fff; + } else { /* 28F002BX-T/28F200BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x37fff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x39fff; + dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x3bfff; + dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x3ffff; + } + break; + + default: + dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94; + + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x1c000; + dev->block_len[BLOCK_MAIN2] = 0x00000; + dev->block_len[BLOCK_MAIN3] = 0x00000; + dev->block_len[BLOCK_MAIN4] = 0x00000; + dev->block_len[BLOCK_DATA1] = 0x01000; + dev->block_len[BLOCK_DATA2] = 0x01000; + dev->block_len[BLOCK_BOOT] = 0x02000; + + if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x02fff; + dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x03fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x01fff; + } else { /* 28F001BX-T/28F100BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1bfff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x1cfff; + dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x1dfff; + dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x1ffff; + } + break; } intel_flash_add_mappings(dev); @@ -432,19 +516,21 @@ intel_flash_init(const device_t *info) dev->command = CMD_READ_ARRAY; dev->status = 0; - f = nvr_fopen(flash_path, L"rb"); + f = nvr_fopen(flash_path, "rb"); if (f) { fread(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f); if (dev->block_len[BLOCK_MAIN2]) fread(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f); + if (dev->block_len[BLOCK_MAIN3]) + fread(&(dev->array[dev->block_start[BLOCK_MAIN3]]), dev->block_len[BLOCK_MAIN3], 1, f); + if (dev->block_len[BLOCK_MAIN4]) + fread(&(dev->array[dev->block_start[BLOCK_MAIN4]]), dev->block_len[BLOCK_MAIN4], 1, f); + fread(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f); fread(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f); fclose(f); } - free(flash_name); - free(machine_name); - return dev; } @@ -455,48 +541,64 @@ intel_flash_close(void *p) FILE *f; flash_t *dev = (flash_t *)p; - f = nvr_fopen(flash_path, L"wb"); + f = nvr_fopen(flash_path, "wb"); fwrite(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f); if (dev->block_len[BLOCK_MAIN2]) fwrite(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f); + if (dev->block_len[BLOCK_MAIN3]) + fwrite(&(dev->array[dev->block_start[BLOCK_MAIN3]]), dev->block_len[BLOCK_MAIN3], 1, f); + if (dev->block_len[BLOCK_MAIN4]) + fwrite(&(dev->array[dev->block_start[BLOCK_MAIN4]]), dev->block_len[BLOCK_MAIN4], 1, f); + fwrite(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f); fwrite(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f); fclose(f); + free(dev->array); + dev->array = NULL; + free(dev); } - /* For AMI BIOS'es - Intel 28F001BXT with A16 pin inverted. */ -const device_t intel_flash_bxt_ami_device = -{ - "Intel 28F001BXT/28F002BXT Flash BIOS", - DEVICE_PCI, - FLAG_INV_A16, - intel_flash_init, - intel_flash_close, - intel_flash_reset, - NULL, NULL, NULL, NULL +const device_t intel_flash_bxt_ami_device = { + .name = "Intel 28F001BXT/28F002BXT/28F004BXT Flash BIOS", + .internal_name = "intel_flash_bxt_ami", + .flags = DEVICE_PCI, + .local = FLAG_INV_A16, + .init = intel_flash_init, + .close = intel_flash_close, + .reset = intel_flash_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t intel_flash_bxt_device = -{ - "Intel 28F001BXT/28F002BXT Flash BIOS", - DEVICE_PCI, 0, - intel_flash_init, - intel_flash_close, - intel_flash_reset, - NULL, NULL, NULL, NULL +const device_t intel_flash_bxt_device = { + .name = "Intel 28F001BXT/28F002BXT/28F004BXT Flash BIOS", + .internal_name = "intel_flash_bxt", + .flags = DEVICE_PCI, + .local = 0, + .init = intel_flash_init, + .close = intel_flash_close, + .reset = intel_flash_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t intel_flash_bxb_device = -{ - "Intel 28F001BXB/28F002BXB Flash BIOS", - DEVICE_PCI, FLAG_BXB, - intel_flash_init, - intel_flash_close, - intel_flash_reset, - NULL, NULL, NULL, NULL +const device_t intel_flash_bxb_device = { + .name = "Intel 28F001BXB/28F002BXB/28F004BXB Flash BIOS", + .internal_name = "intel_flash_bxb", + .flags = DEVICE_PCI, + .local = FLAG_BXB, + .init = intel_flash_init, + .close = intel_flash_close, + .reset = intel_flash_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/mem/mem.c b/src/mem/mem.c index 091a07770..e005772a5 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -8,12 +8,6 @@ * * Memory handling and MMU. * - * NOTE: Experimenting with dynamically allocated lookup tables; - * the DYNAMIC_TABLES=1 enables this. Will eventually go - * away, either way... - * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, @@ -31,6 +25,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/version.h> #include "cpu.h" #include "x86_ops.h" #include "x86.h" @@ -39,7 +34,9 @@ #include <86box/config.h> #include <86box/io.h> #include <86box/mem.h> +#include <86box/plat.h> #include <86box/rom.h> +#include <86box/gdbstub.h> #ifdef USE_DYNAREC # include "codegen_public.h" #else @@ -58,21 +55,13 @@ #endif -#define FIXME 0 -#define DYNAMIC_TABLES 0 /* experimental */ - - -mem_mapping_t base_mapping, - ram_low_mapping, /* 0..640K mapping */ -#if 1 +mem_mapping_t ram_low_mapping, /* 0..640K mapping */ ram_mid_mapping, -#endif ram_remapped_mapping, /* 640..1024K mapping */ ram_high_mapping, /* 1024K+ mapping */ ram_2gb_mapping, /* 1024M+ mapping */ ram_remapped_mapping, ram_split_mapping, - ram_smram_mapping[2], bios_mapping, bios_high_mapping; @@ -81,6 +70,7 @@ page_t *pages, /* RAM page table */ uint32_t pages_sz; /* #pages in table */ uint8_t *ram, *ram2; /* the virtual RAM */ +uint8_t page_ff[4096]; uint32_t rammask; uint8_t *rom; /* the virtual ROM */ @@ -90,12 +80,12 @@ uint32_t pccache; uint8_t *pccache2; int readlnext; -int readlookup[256], - readlookupp[256]; +int readlookup[256]; uintptr_t *readlookup2; +uintptr_t old_rl2; +uint8_t uncached = 0; int writelnext; -int writelookup[256], - writelookupp[256]; +int writelookup[256]; uintptr_t *writelookup2; uint32_t mem_logical_addr; @@ -109,8 +99,6 @@ int cachesize = 256; uint32_t get_phys_virt, get_phys_phys; -smram_t smram[2] = { { 0x000a0000, 0x000a0000 }, { 0x000a0000, 0x000a0000 } }; - int mem_a20_key = 0, mem_a20_alt = 0, mem_a20_state = 0; @@ -118,31 +106,34 @@ int mem_a20_key = 0, int mmuflush = 0; int mmu_perm = 4; +#ifdef USE_NEW_DYNAREC uint64_t *byte_dirty_mask; uint64_t *byte_code_present_mask; uint32_t purgable_page_list_head = 0; int purgeable_page_count = 0; +#endif -int use_phys_exec = 0; +uint8_t high_page = 0; /* if a high (> 4 gb) page was detected */ /* FIXME: re-do this with a 'mem_ops' struct. */ +static uint8_t *page_lookupp; /* pagetable mmu_perm lookup */ +static uint8_t *readlookupp; +static uint8_t *writelookupp; +static mem_mapping_t *base_mapping, *last_mapping; static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO]; static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *read_mapping_bus[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping_bus[MEM_MAPPINGS_NO]; static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; -static uint32_t _mem_state[MEM_MAPPINGS_NO]; -static uint8_t *mtrr_areas[MEM_MAPPINGS_NO]; -static uint8_t mtrr_area_refcounts[MEM_MAPPINGS_NO]; - -#if FIXME -#if (MEM_GRANULARITY_BITS >= 12) -static uint8_t ff_array[MEM_GRANULARITY_SIZE]; -#else -static uint8_t ff_array[4096]; /* Must be at least one page. */ -#endif -#else static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; +static mem_state_t _mem_state[MEM_MAPPINGS_NO]; +static uint32_t remap_start_addr; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) +static size_t ram_size = 0, ram2_size = 0; +#else +static size_t ram_size = 0; #endif @@ -180,17 +171,8 @@ resetreadlookup(void) { int c; - /* This is NULL after app startup, when mem_init() has not yet run. */ -#if DYNAMIC_TABLES -mem_log("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, page_lookup, pages_sz); -#endif - /* Initialize the page lookup table. */ -#if DYNAMIC_TABLES - memset(page_lookup, 0x00, pages_sz*sizeof(page_t *)); -#else memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *)); -#endif /* Initialize the tables for lower (<= 1024K) RAM. */ for (c = 0; c < 256; c++) { @@ -199,17 +181,16 @@ mem_log("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, pa } /* Initialize the tables for high (> 1024K) RAM. */ -#if DYNAMIC_TABLES - memset(readlookup2, 0xff, pages_sz*sizeof(uintptr_t)); - memset(writelookup2, 0xff, pages_sz*sizeof(uintptr_t)); -#else memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t)); + memset(readlookupp, 0x04, (1<<20)*sizeof(uint8_t)); + memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t)); -#endif + memset(writelookupp, 0x04, (1<<20)*sizeof(uint8_t)); readlnext = 0; writelnext = 0; pccache = 0xffffffff; + high_page = 0; } @@ -220,12 +201,15 @@ flushmmucache(void) for (c = 0; c < 256; c++) { if (readlookup[c] != (int) 0xffffffff) { - readlookup2[readlookup[c]] = -1; + readlookup2[readlookup[c]] = LOOKUP_INV; + readlookupp[readlookup[c]] = 4; readlookup[c] = 0xffffffff; } if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; - writelookup2[writelookup[c]] = -1; + page_lookupp[writelookup[c]] = 4; + writelookup2[writelookup[c]] = LOOKUP_INV; + writelookupp[writelookup[c]] = 4; writelookup[c] = 0xffffffff; } } @@ -247,31 +231,15 @@ flushmmucache_nopc(void) for (c = 0; c < 256; c++) { if (readlookup[c] != (int) 0xffffffff) { - readlookup2[readlookup[c]] = -1; + readlookup2[readlookup[c]] = LOOKUP_INV; + readlookupp[readlookup[c]] = 4; readlookup[c] = 0xffffffff; } if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; - writelookup2[writelookup[c]] = -1; - writelookup[c] = 0xffffffff; - } - } -} - - -void -flushmmucache_cr3(void) -{ - int c; - - for (c = 0; c < 256; c++) { - if (readlookup[c] != (int) 0xffffffff) { - readlookup2[readlookup[c]] = -1; - readlookup[c] = 0xffffffff; - } - if (writelookup[c] != (int) 0xffffffff) { - page_lookup[writelookup[c]] = NULL; - writelookup2[writelookup[c]] = -1; + page_lookupp[writelookup[c]] = 4; + writelookup2[writelookup[c]] = LOOKUP_INV; + writelookupp[writelookup[c]] = 4; writelookup[c] = 0xffffffff; } } @@ -283,10 +251,15 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) { page_t *page_target = &pages[addr >> 12]; int c; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) uint32_t a; +#endif for (c = 0; c < 256; c++) { if (writelookup[c] != (int) 0xffffffff) { +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; +#else a = (uintptr_t)(addr & ~0xfff) - (virt & ~0xfff); uintptr_t target; @@ -294,9 +267,10 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) target = (uintptr_t)&ram2[a - (1 << 30)]; else target = (uintptr_t)&ram[a]; +#endif if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { - writelookup2[writelookup[c]] = -1; + writelookup2[writelookup[c]] = LOOKUP_INV; page_lookup[writelookup[c]] = NULL; writelookup[c] = 0xffffffff; } @@ -310,10 +284,11 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) #define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] #define rammap64(x) ((uint64_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 3) & MEM_GRANULARITY_PMASK] -static uint64_t + +static __inline uint64_t mmutranslatereal_normal(uint32_t addr, int rw) { - uint32_t temp,temp2,temp3; + uint32_t temp, temp2, temp3; uint32_t addr2; if (cpu_state.abrt) @@ -333,7 +308,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) if ((temp & 0x80) && (cr4 & CR4_PSE)) { /*4MB page*/ - if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) @@ -347,18 +322,20 @@ mmutranslatereal_normal(uint32_t addr, int rw) } mmu_perm = temp & 4; - rammap(addr2) |= 0x20; + rammap(addr2) |= (rw ? 0x60 : 0x20); return (temp & ~0x3fffff) + (addr & 0x3fffff); } temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); temp3 = temp & temp2; - if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; - if (CPL == 3) temp |= 4; - if (rw) temp |= 2; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; cpu_state.abrt = ABRT_PF; abrt_error = temp; return 0xffffffffffffffffULL; @@ -366,17 +343,17 @@ mmutranslatereal_normal(uint32_t addr, int rw) mmu_perm = temp & 4; rammap(addr2) |= 0x20; - rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20); + rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw ? 0x60 : 0x20); - return (uint64_t) ((temp&~0xfff)+(addr&0xfff)); + return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff)); } -static uint64_t +static __inline uint64_t mmutranslatereal_pae(uint32_t addr, int rw) { - uint64_t temp,temp2,temp3,temp4; - uint64_t addr2,addr3,addr4; + uint64_t temp, temp2, temp3, temp4; + uint64_t addr2, addr3, addr4; if (cpu_state.abrt) return 0xffffffffffffffffULL; @@ -421,7 +398,7 @@ mmutranslatereal_pae(uint32_t addr, int rw) return 0xffffffffffffffffULL; } mmu_perm = temp & 4; - rammap64(addr3) |= 0x20; + rammap64(addr3) |= (rw ? 0x60 : 0x20); return ((temp & ~0x1fffffULL) + (addr & 0x1fffffULL)) & 0x000000ffffffffffULL; } @@ -441,7 +418,7 @@ mmutranslatereal_pae(uint32_t addr, int rw) mmu_perm = temp & 4; rammap64(addr3) |= 0x20; - rammap64(addr4) |= (rw? 0x60 : 0x20); + rammap64(addr4) |= (rw ? 0x60 : 0x20); return ((temp & ~0xfffULL) + ((uint64_t) (addr & 0xfff))) & 0x000000ffffffffffULL; } @@ -450,6 +427,10 @@ mmutranslatereal_pae(uint32_t addr, int rw) uint64_t mmutranslatereal(uint32_t addr, int rw) { + /* Fast path to return invalid without any call if an exception has occurred beforehand. */ + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + if (cr4 & CR4_PAE) return mmutranslatereal_pae(addr, rw); else @@ -461,17 +442,21 @@ mmutranslatereal(uint32_t addr, int rw) uint32_t mmutranslatereal32(uint32_t addr, int rw) { + /* Fast path to return invalid without any call if an exception has occurred beforehand. */ + if (cpu_state.abrt) + return (uint32_t) 0xffffffffffffffffULL; + return (uint32_t) mmutranslatereal(addr, rw); } -static uint64_t +static __inline uint64_t mmutranslate_noabrt_normal(uint32_t addr, int rw) { uint32_t temp,temp2,temp3; uint32_t addr2; - if (cpu_state.abrt) + if (cpu_state.abrt) return 0xffffffffffffffffULL; addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); @@ -498,13 +483,13 @@ mmutranslate_noabrt_normal(uint32_t addr, int rw) } -static uint64_t +static __inline uint64_t mmutranslate_noabrt_pae(uint32_t addr, int rw) { uint64_t temp,temp2,temp3,temp4; uint64_t addr2,addr3,addr4; - if (cpu_state.abrt) + if (cpu_state.abrt) return 0xffffffffffffffffULL; addr2 = (cr3 & ~0x1f) + ((addr >> 27) & 0x18); @@ -542,6 +527,10 @@ mmutranslate_noabrt_pae(uint32_t addr, int rw) uint64_t mmutranslate_noabrt(uint32_t addr, int rw) { + /* Fast path to return invalid without any call if an exception has occurred beforehand. */ + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + if (cr4 & CR4_PAE) return mmutranslate_noabrt_pae(addr, rw); else @@ -580,34 +569,45 @@ mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) void addreadlookup(uint32_t virt, uint32_t phys) { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) uint32_t a; +#endif if (virt == 0xffffffff) return; - if (readlookup2[virt>>12] != (uintptr_t) -1) return; + if (readlookup2[virt>>12] != (uintptr_t) LOOKUP_INV) return; - if (readlookup[readlnext] != (int) 0xffffffff) - readlookup2[readlookup[readlnext]] = -1; + if (readlookup[readlnext] != (int) 0xffffffff) { + if ((readlookup[readlnext] == ((es + DI) >> 12)) || (readlookup[readlnext] == ((es + EDI) >> 12))) + uncached = 1; + readlookup2[readlookup[readlnext]] = LOOKUP_INV; + } - a = (uintptr_t)(phys & ~0xfff) - (uintptr_t)(virt & ~0xfff); +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; +#else + a = ((uint32_t)(phys & ~0xfff) - (uint32_t)(virt & ~0xfff)); if ((phys & ~0xfff) >= (1 << 30)) readlookup2[virt>>12] = (uintptr_t)&ram2[a - (1 << 30)]; else readlookup2[virt>>12] = (uintptr_t)&ram[a]; +#endif + readlookupp[virt>>12] = mmu_perm; - readlookupp[readlnext] = mmu_perm; readlookup[readlnext++] = virt >> 12; readlnext &= (cachesize-1); - sub_cycles(9); + cycles -= 9; } void addwritelookup(uint32_t virt, uint32_t phys) { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) uint32_t a; +#endif if (virt == 0xffffffff) return; @@ -615,37 +615,42 @@ addwritelookup(uint32_t virt, uint32_t phys) if (writelookup[writelnext] != -1) { page_lookup[writelookup[writelnext]] = NULL; - writelookup2[writelookup[writelnext]] = -1; + writelookup2[writelookup[writelnext]] = LOOKUP_INV; } #ifdef USE_NEW_DYNAREC #ifdef USE_DYNAREC - if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) + if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) { #else - if (pages[phys >> 12].block) + if (pages[phys >> 12].block) { #endif #else #ifdef USE_DYNAREC - if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) { #else - if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) { #endif #endif page_lookup[virt >> 12] = &pages[phys >> 12]; - else { - a = (uintptr_t)(phys & ~0xfff) - (uintptr_t)(virt & ~0xfff); + page_lookupp[virt >> 12] = mmu_perm; + } else { +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; +#else + a = ((uint32_t)(phys & ~0xfff) - (uint32_t)(virt & ~0xfff)); if ((phys & ~0xfff) >= (1 << 30)) writelookup2[virt>>12] = (uintptr_t)&ram2[a - (1 << 30)]; else writelookup2[virt>>12] = (uintptr_t)&ram[a]; +#endif } + writelookupp[virt>>12] = mmu_perm; - writelookupp[writelnext] = mmu_perm; writelookup[writelnext++] = virt >> 12; writelnext &= (cachesize - 1); - sub_cycles(9); + cycles -= 9; } @@ -666,50 +671,136 @@ getpccache(uint32_t a) if (_mem_exec[a64 >> MEM_GRANULARITY_BITS]) { if (is286) { - if (read_mapping[a64 >> MEM_GRANULARITY_BITS] && (read_mapping[a64 >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM)) + if (read_mapping[a64 >> MEM_GRANULARITY_BITS] && (read_mapping[a64 >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM_WS)) cpu_prefetch_cycles = cpu_rom_prefetch_cycles; else cpu_prefetch_cycles = cpu_mem_prefetch_cycles; } - + return &_mem_exec[a64 >> MEM_GRANULARITY_BITS][(uintptr_t)(a64 & MEM_GRANULARITY_PAGE) - (uintptr_t)(a2 & ~0xfff)]; } - mem_log("Bad getpccache %08X%08X\n", (uint32_t) (a >> 32), (uint32_t) (a & 0xffffffff)); + mem_log("Bad getpccache %08X%08X\n", (uint32_t) (a64 >> 32), (uint32_t) (a64 & 0xffffffffULL)); -#if FIXME - return &ff_array[0-(uintptr_t)(a2 & ~0xfff)]; -#else return (uint8_t *)&ff_pccache; -#endif +} + + +uint8_t +read_mem_b(uint32_t addr) +{ + mem_mapping_t *map; + uint8_t ret = 0xff; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + ret = map->read_b(addr, map->p); + + resub_cycles(old_cycles); + + return ret; +} + + +uint16_t +read_mem_w(uint32_t addr) +{ + mem_mapping_t *map; + uint16_t ret = 0xffff; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + if (addr & 1) + ret = read_mem_b(addr) | (read_mem_b(addr + 1) << 8); + else { + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_w) + ret = map->read_w(addr, map->p); + else if (map && map->read_b) + ret = map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); + } + + resub_cycles(old_cycles); + + return ret; +} + + +void +write_mem_b(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); + + resub_cycles(old_cycles); +} + + +void +write_mem_w(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + if (addr & 1) { + write_mem_b(addr, val); + write_mem_b(addr + 1, val >> 8); + } else { + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->write_w) + map->write_w(addr, val, map->p); + else if (map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + } + } + } + + resub_cycles(old_cycles); } uint8_t readmembl(uint32_t addr) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + uint64_t a; + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1); + + addr64 = (uint64_t) addr; mem_logical_addr = addr; + high_page = 0; + if (cr0 >> 31) { - addr64 = mmutranslate_read(addr); - if (addr64 == 0xffffffffffffffffULL) - return 0xff; - if (addr64 > 0xffffffffULL) + a = mmutranslate_read(addr); + addr64 = (uint32_t) a; + + if (a > 0xffffffffULL) return 0xff; } addr = (uint32_t) (addr64 & rammask); - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return mtrr[addr & MEM_GRANULARITY_MASK]; - - map = read_mapping[page]; + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->read_b) return map->read_b(addr, map->p); @@ -720,86 +811,148 @@ readmembl(uint32_t addr) void writemembl(uint32_t addr, uint8_t val) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + uint64_t a; + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1); + + addr64 = (uint64_t) addr; mem_logical_addr = addr; + high_page = 0; + if (page_lookup[addr>>12] && page_lookup[addr>>12]->write_b) { page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); return; } if (cr0 >> 31) { - addr64 = mmutranslate_write(addr); - if (addr64 == 0xffffffffffffffffULL) - return; - if (addr64 > 0xffffffffULL) + a = mmutranslate_write(addr); + addr64 = (uint32_t) a; + + if (a > 0xffffffffULL) return; } addr = (uint32_t) (addr64 & rammask); - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr & MEM_GRANULARITY_MASK] = val; - return; - } - - map = write_mapping[page]; + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->write_b) map->write_b(addr, val, map->p); } -#ifdef USE_NEW_DYNAREC -uint16_t -readmemwl(uint32_t addr) +/* Read a byte from memory without MMU translation - result of previous MMU translation passed as value. */ +uint8_t +readmembl_no_mmut(uint32_t addr, uint32_t a64) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1); + mem_logical_addr = addr; - if (addr64 & 1) { - if (!cpu_cyrix_alignment || (addr64 & 7) == 7) - sub_cycles(timing_misaligned); - if ((addr64 & 0xfff) > 0xffe) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xff; + + addr = a64 & rammask; + } else + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); + + return 0xff; +} + + +/* Write a byte to memory without MMU translation - result of previous MMU translation passed as value. */ +void +writemembl_no_mmut(uint32_t addr, uint32_t a64, uint8_t val) +{ + mem_mapping_t *map; + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1); + + mem_logical_addr = addr; + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_b) { + page_lookup[addr >> 12]->write_b(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + + addr = a64 & rammask; + } else + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); +} + + +uint16_t +readmemwl(uint32_t addr) +{ + mem_mapping_t *map; + int i; + uint64_t a; + + addr64a[0] = addr; + addr64a[1] = addr + 1; + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 2); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { if (cr0 >> 31) { - if (mmutranslate_read(addr) == 0xffffffffffffffffULL) - return 0xffff; - if (mmutranslate_read(addr+1) == 0xffffffffffffffffULL) - return 0xffff; + for (i = 0; i < 2; i++) { + a = mmutranslate_read(addr + i); + addr64a[i] = (uint32_t) a; + + if (a > 0xffffffffULL) + return 0xffff; + } } - return readmembl(addr)|(readmembl(addr+1)<<8); - } else if (readlookup2[addr >> 12] != -1) + + return readmembl_no_mmut(addr, addr64a[0]) | + (((uint16_t) readmembl_no_mmut(addr + 1, addr64a[1])) << 8); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; return *(uint16_t *)(readlookup2[addr >> 12] + addr); - } - if (cr0>>31) { - addr64 = mmutranslate_read(addr); - if (addr64 == 0xffffffffffffffffULL) - return 0xffff; - if (addr64 > 0xffffffffULL) - return 0xffff; + } } - addr = (uint32_t) (addr64 & rammask); + if (cr0 >> 31) { + a = mmutranslate_read(addr); + addr64a[0] = (uint32_t) a; - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return mtrr[addr & MEM_GRANULARITY_MASK] | ((uint16_t) (mtrr[(addr + 1) & MEM_GRANULARITY_MASK]) << 8); + if (a > 0xffffffffULL) + return 0xffff; + } else + addr64a[0] = (uint64_t) addr; - map = read_mapping[page]; + addr = addr64a[0] & rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->read_w) return map->read_w(addr, map->p); - if (map && map->read_b) - return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); + if (map && map->read_b) { + return map->read_b(addr, map->p) | + ((uint16_t) (map->read_b(addr + 1, map->p)) << 8); + } return 0xffff; } @@ -808,118 +961,261 @@ readmemwl(uint32_t addr) void writememwl(uint32_t addr, uint16_t val) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + int i; + uint64_t a; + + addr64a[0] = addr; + addr64a[1] = addr + 1; + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 2); mem_logical_addr = addr; + high_page = 0; + if (addr & 1) { if (!cpu_cyrix_alignment || (addr & 7) == 7) - sub_cycles(timing_misaligned); - if ((addr & 0xFFF) > 0xFFE) { + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { if (cr0 >> 31) { - if (mmutranslate_write(addr) == 0xffffffff) - return; - if (mmutranslate_write(addr+1) == 0xffffffff) - return; + for (i = 0; i < 2; i++) { + /* Do not translate a page that has a valid lookup, as that is by definition valid + and the whole purpose of the lookup is to avoid repeat identical translations. */ + if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) { + a = mmutranslate_write(addr + i); + addr64a[i] = (uint32_t) a; + + if (a > 0xffffffffULL) + return; + } + } } - writemembl(addr,val); - writemembl(addr+1,val>>8); + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + writemembl_no_mmut(addr, addr64a[0], val); + writemembl_no_mmut(addr + 1, addr64a[1], val >> 8); return; - } else if (writelookup2[addr >> 12] != -1) { + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; *(uint16_t *)(writelookup2[addr >> 12] + addr) = val; return; } } - if (page_lookup[addr>>12] && page_lookup[addr>>12]->write_w) { - page_lookup[addr>>12]->write_w(addr, val, page_lookup[addr>>12]); + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) { + page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]); + mmu_perm = page_lookupp[addr >> 12]; return; } - if (cr0>>31) { - addr64 = mmutranslate_write(addr); - if (addr64 == 0xffffffffffffffffULL) - return; - if (addr64 > 0xffffffffULL) + + if (cr0 >> 31) { + a = mmutranslate_write(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) return; } - addr = (uint32_t) (addr64 & rammask); + addr = addr64a[0] & rammask; - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr & MEM_GRANULARITY_MASK] = val; - mtrr[(addr + 1) & MEM_GRANULARITY_MASK] = val >> 8; - return; + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_w) { + map->write_w(addr, val, map->p); + return; } - map = write_mapping[page]; - if (map) { - if (map->write_w) - map->write_w(addr, val, map->p); - else if (map->write_b) { - map->write_b(addr, val, map->p); - map->write_b(addr + 1, val >> 8, map->p); + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + return; + } +} + + +/* Read a word from memory without MMU translation - results of previous MMU translation passed as array. */ +uint16_t +readmemwl_no_mmut(uint32_t addr, uint32_t *a64) +{ + mem_mapping_t *map; + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 2); + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffff; + } + + return readmembl_no_mmut(addr, a64[0]) | + (((uint16_t) readmembl_no_mmut(addr + 1, a64[1])) << 8); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint16_t *)(readlookup2[addr >> 12] + addr); } } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffff; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_w) + return map->read_w(addr, map->p); + + if (map && map->read_b) { + return map->read_b(addr, map->p) | + ((uint16_t) (map->read_b(addr + 1, map->p)) << 8); + } + + return 0xffff; +} + + +/* Write a word to memory without MMU translation - results of previous MMU translation passed as array. */ +void +writememwl_no_mmut(uint32_t addr, uint32_t *a64, uint16_t val) +{ + mem_mapping_t *map; + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 2); + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + } + + writemembl_no_mmut(addr, a64[0], val); + writemembl_no_mmut(addr + 1, a64[1], val >> 8); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint16_t *)(writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_w) { + map->write_w(addr, val, map->p); + return; + } + + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + return; + } } uint32_t readmemll(uint32_t addr) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + for (i = 0; i < 4; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 4); mem_logical_addr = addr; + high_page = 0; + if (addr & 3) { if (!cpu_cyrix_alignment || (addr & 7) > 4) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr & 0xfff) > 0xffc) { - if (cr0>>31) { - if (mmutranslate_read(addr) == 0xffffffffffffffffULL) - return 0xffffffff; - if (mmutranslate_read(addr+3) == 0xffffffffffffffffULL) - return 0xffffffff; + if (cr0 >> 31) { + for (i = 0; i < 4; i++) { + if (i == 0) { + a = mmutranslate_read(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_read(addr + 3); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (a > 0xffffffffULL) + return 0xffff; + } } - return readmemwl(addr)|(readmemwl(addr+2)<<16); - } else if (readlookup2[addr >> 12] != -1) + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + return readmemwl_no_mmut(addr, addr64a) | + (((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; return *(uint32_t *)(readlookup2[addr >> 12] + addr); + } } if (cr0 >> 31) { - addr64 = mmutranslate_read(addr); - if (addr64 == 0xffffffffffffffffULL) - return 0xffffffff; - if (addr64 > 0xffffffffULL) + a = mmutranslate_read(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) return 0xffffffff; } - addr = (uint32_t) (addr64 & rammask); + addr = addr64a[0] & rammask; - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return mtrr[addr & MEM_GRANULARITY_MASK] | ((uint32_t) (mtrr[(addr + 1) & MEM_GRANULARITY_MASK]) << 8) | ((uint32_t) (mtrr[(addr + 2) & MEM_GRANULARITY_MASK]) << 16) | ((uint32_t) (mtrr[(addr + 3) & MEM_GRANULARITY_MASK]) << 24); + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - map = read_mapping[page]; - if (map) { - if (map->read_l) - return map->read_l(addr, map->p); + if (map && map->read_l) + return map->read_l(addr, map->p); - if (map->read_w) - return map->read_w(addr, map->p) | (map->read_w(addr + 2, map->p) << 16); + if (map && map->read_w) + return map->read_w(addr, map->p) | + ((uint32_t) (map->read_w(addr + 2, map->p)) << 16); - if (map->read_b) - return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8) | - (map->read_b(addr + 2, map->p) << 16) | (map->read_b(addr + 3, map->p) << 24); - } + if (map && map->read_b) + return map->read_b(addr, map->p) | + ((uint32_t) (map->read_b(addr + 1, map->p)) << 8) | + ((uint32_t) (map->read_b(addr + 2, map->p)) << 16) | + ((uint32_t) (map->read_b(addr + 3, map->p)) << 24); return 0xffffffff; } @@ -928,68 +1224,211 @@ readmemll(uint32_t addr) void writememll(uint32_t addr, uint32_t val) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + for (i = 0; i < 4; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 4); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + for (i = 0; i < 4; i++) { + /* Do not translate a page that has a valid lookup, as that is by definition valid + and the whole purpose of the lookup is to avoid repeat identical translations. */ + if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) { + if (i == 0) { + a = mmutranslate_write(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_write(addr + 3); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (a > 0xffffffffULL) + return; + } + } + } + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + writememwl_no_mmut(addr, &(addr64a[0]), val); + writememwl_no_mmut(addr + 2, &(addr64a[2]), val >> 16); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint32_t *)(writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + a = mmutranslate_write(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) + return; + } + + addr = addr64a[0] & rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr, val, map->p); + return; + } + if (map && map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + return; + } + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + return; + } +} + + +/* Read a long from memory without MMU translation - results of previous MMU translation passed as array. */ +uint32_t +readmemll_no_mmut(uint32_t addr, uint32_t *a64) +{ + mem_mapping_t *map; + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 4); mem_logical_addr = addr; if (addr & 3) { if (!cpu_cyrix_alignment || (addr & 7) > 4) - sub_cycles(timing_misaligned); - if ((addr & 0xFFF) > 0xFFC) { - if (cr0>>31) { - if (mmutranslate_write(addr) == 0xffffffffffffffffULL) - return; - if (mmutranslate_write(addr+3) == 0xffffffffffffffffULL) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffffffff; + } + + return readmemwl_no_mmut(addr, a64) | + ((uint32_t) (readmemwl_no_mmut(addr + 2, &(a64[2]))) << 16); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint32_t *)(readlookup2[addr >> 12] + addr); + } + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffffffff; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_l) + return map->read_l(addr, map->p); + + if (map && map->read_w) + return map->read_w(addr, map->p) | + ((uint32_t) (map->read_w(addr + 2, map->p)) << 16); + + if (map && map->read_b) + return map->read_b(addr, map->p) | + ((uint32_t) (map->read_b(addr + 1, map->p)) << 8) | + ((uint32_t) (map->read_b(addr + 2, map->p)) << 16) | + ((uint32_t) (map->read_b(addr + 3, map->p)) << 24); + + return 0xffffffff; +} + + +/* Write a long to memory without MMU translation - results of previous MMU translation passed as array. */ +void +writememll_no_mmut(uint32_t addr, uint32_t *a64, uint32_t val) +{ + mem_mapping_t *map; + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 4); + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) return; } - writememwl(addr,val); - writememwl(addr+2,val>>16); + + writememwl_no_mmut(addr, &(a64[0]), val); + writememwl_no_mmut(addr + 2, &(a64[2]), val >> 16); return; - } else if (writelookup2[addr >> 12] != -1) { + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; *(uint32_t *)(writelookup2[addr >> 12] + addr) = val; return; } } - if (page_lookup[addr>>12] && page_lookup[addr>>12]->write_l) { - page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); return; } - if (cr0>>31) { - addr64 = mmutranslate_write(addr); - if (addr64 == 0xffffffffffffffffULL) - return; - if (addr64 > 0xffffffffULL) + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) return; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr, val, map->p); + return; } - - addr = (uint32_t) (addr64 & rammask); - - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr & MEM_GRANULARITY_MASK] = val; - mtrr[(addr + 1) & MEM_GRANULARITY_MASK] = val >> 8; - mtrr[(addr + 2) & MEM_GRANULARITY_MASK] = val >> 16; - mtrr[(addr + 3) & MEM_GRANULARITY_MASK] = val >> 24; - return; + if (map && map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + return; } - - map = write_mapping[page]; - if (map) { - if (map->write_l) - map->write_l(addr, val, map->p); - else if (map->write_w) { - map->write_w(addr, val, map->p); - map->write_w(addr + 2, val >> 16, map->p); - } else if (map->write_b) { - map->write_b(addr, val, map->p); - map->write_b(addr + 1, val >> 8, map->p); - map->write_b(addr + 2, val >> 16, map->p); - map->write_b(addr + 3, val >> 24, map->p); - } + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + return; } } @@ -997,607 +1436,280 @@ writememll(uint32_t addr, uint32_t val) uint64_t readmemql(uint32_t addr) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + for (i = 0; i < 8; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 8); mem_logical_addr = addr; + high_page = 0; + if (addr & 7) { - sub_cycles(timing_misaligned); - if ((addr & 0xFFF) > 0xFF8) { - if (cr0>>31) { - if (mmutranslate_read(addr) == 0xffffffffffffffffULL) - return 0xffffffffffffffffULL; - if (mmutranslate_read(addr+7) == 0xffffffffffffffffULL) - return 0xffffffffffffffffULL; + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xff8) { + if (cr0 >> 31) { + for (i = 0; i < 8; i++) { + if (i == 0) { + a = mmutranslate_read(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_read(addr + 7); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (a > 0xffffffffULL) + return 0xffff; + } } - return readmemll(addr)|((uint64_t)readmemll(addr+4)<<32); - } else if (readlookup2[addr >> 12] != -1) + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + return readmemll_no_mmut(addr, addr64a) | + (((uint64_t) readmemll_no_mmut(addr + 4, &(addr64a[4]))) << 32); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; return *(uint64_t *)(readlookup2[addr >> 12] + addr); + } } - if (cr0>>31) { - addr64 = mmutranslate_read(addr); - if (addr64 == 0xffffffffffffffffULL) - return 0xffffffffffffffffULL; - if (addr64 > 0xffffffffULL) + if (cr0 >> 31) { + a = mmutranslate_read(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) return 0xffffffffffffffffULL; } - addr = (uint32_t) (addr64 & rammask); + addr = addr64a[0] & rammask; - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32); - - map = read_mapping[page]; + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->read_l) return map->read_l(addr, map->p) | ((uint64_t)map->read_l(addr + 4, map->p) << 32); - return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32); + return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32); } void writememql(uint32_t addr, uint64_t val) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + for (i = 0; i < 8; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 8); mem_logical_addr = addr; + high_page = 0; + if (addr & 7) { - sub_cycles(timing_misaligned); - if ((addr & 0xFFF) > 0xFF8) { - if (cr0>>31) { - if (mmutranslate_write(addr) == 0xffffffffffffffffULL) - return; - if (mmutranslate_write(addr+7) == 0xffffffffffffffffULL) - return; + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xff8) { + if (cr0 >> 31) { + for (i = 0; i < 8; i++) { + /* Do not translate a page that has a valid lookup, as that is by definition valid + and the whole purpose of the lookup is to avoid repeat identical translations. */ + if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) { + if (i == 0) { + a = mmutranslate_write(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_write(addr + 7); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (addr64a[i] > 0xffffffffULL) + return; + } + } } - writememll(addr, val); - writememll(addr+4, val >> 32); + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + writememll_no_mmut(addr, addr64a, val); + writememll_no_mmut(addr + 4, &(addr64a[4]), val >> 32); return; - } else if (writelookup2[addr >> 12] != -1) { + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; *(uint64_t *)(writelookup2[addr >> 12] + addr) = val; return; } } - if (page_lookup[addr>>12] && page_lookup[addr>>12]->write_l) { - page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); - page_lookup[addr>>12]->write_l(addr + 4, val >> 32, page_lookup[addr>>12]); - return; - } - if (cr0>>31) { - addr64 = mmutranslate_write(addr); - if (addr64 == 0xffffffffffffffffULL) - return; - if (addr64 > 0xffffffffULL) - return; - } - addr = (uint32_t) (addr64 & rammask); - - page = (addr >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr & MEM_GRANULARITY_MASK] = val; - mtrr[(addr + 1) & MEM_GRANULARITY_MASK] = val >> 8; - mtrr[(addr + 2) & MEM_GRANULARITY_MASK] = val >> 16; - mtrr[(addr + 3) & MEM_GRANULARITY_MASK] = val >> 24; - mtrr[(addr + 4) & MEM_GRANULARITY_MASK] = val >> 32; - mtrr[(addr + 5) & MEM_GRANULARITY_MASK] = val >> 40; - mtrr[(addr + 6) & MEM_GRANULARITY_MASK] = val >> 48; - mtrr[(addr + 7) & MEM_GRANULARITY_MASK] = val >> 56; - return; - } - - map = write_mapping[page]; - if (map) { - if (map->write_l) { - map->write_l(addr, val, map->p); - map->write_l(addr + 4, val >> 32, map->p); - } else if (map->write_w) { - map->write_w(addr, val, map->p); - map->write_w(addr + 2, val >> 16, map->p); - map->write_w(addr + 4, val >> 32, map->p); - map->write_w(addr + 6, val >> 48, map->p); - } else if (map->write_b) { - map->write_b(addr, val, map->p); - map->write_b(addr + 1, val >> 8, map->p); - map->write_b(addr + 2, val >> 16, map->p); - map->write_b(addr + 3, val >> 24, map->p); - map->write_b(addr + 4, val >> 32, map->p); - map->write_b(addr + 5, val >> 40, map->p); - map->write_b(addr + 6, val >> 48, map->p); - map->write_b(addr + 7, val >> 56, map->p); - } - } -} -#else -uint8_t -readmemb386l(uint32_t seg, uint32_t addr) -{ - return readmembl(addr + seg); -} - - -void -writememb386l(uint32_t seg, uint32_t addr, uint8_t val) -{ - writemembl(addr + seg, val); -} - - -uint16_t -readmemwl(uint32_t seg, uint32_t addr) -{ - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; - mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (addr2 & 1) { - if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - sub_cycles(timing_misaligned); - if ((addr2 & 0xfff) > 0xffe) { - if (cr0 >> 31) { - if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) - return 0xffff; - if (mmutranslate_read(addr2+1) == 0xffffffffffffffffULL) - return 0xffff; - } - if (is386) return readmemb386l(seg,addr)|(((uint16_t) readmemb386l(seg,addr+1))<<8); - else return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8); - } - else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) - return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); - } - - if (cr0 >> 31) { - addr64 = mmutranslate_read(addr2); - if (addr64 == 0xffffffffffffffffULL) - return 0xffff; - if (addr64 > 0xffffffffULL) - return 0xffff; - } else - addr64 = (uint64_t) addr2; - - addr2 = (uint32_t) (addr64 & rammask); - - page = (addr2 >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return mtrr[addr2 & MEM_GRANULARITY_MASK] | ((uint16_t) (mtrr[(addr2 + 1) & MEM_GRANULARITY_MASK]) << 8); - - map = read_mapping[page]; - - if (map && map->read_w) - return map->read_w(addr2, map->p); - - if (map && map->read_b) { - if (AT) - return map->read_b(addr2, map->p) | - ((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8); - else - return map->read_b(addr2, map->p) | - ((uint16_t) (map->read_b(seg + ((addr + 1) & 0xffff), map->p)) << 8); - } - - return 0xffff; -} - - -void -writememwl(uint32_t seg, uint32_t addr, uint16_t val) -{ - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; - mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (addr2 & 1) { - if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - sub_cycles(timing_misaligned); - if ((addr2 & 0xFFF) > 0xffe) { - if (cr0 >> 31) { - if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; - if (mmutranslate_write(addr2+1) == 0xffffffffffffffffULL) return; - } - if (is386) { - writememb386l(seg,addr,val); - writememb386l(seg,addr+1,val>>8); - } else { - writemembl(seg+addr,val); - writemembl(seg+addr+1,val>>8); - } - return; - } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { - *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; - return; - } - } - - if (page_lookup[addr2>>12] && page_lookup[addr2>>12]->write_w) { - page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); + page_lookup[addr >> 12]->write_l(addr + 4, val >> 32, page_lookup[addr >> 12]); return; } if (cr0 >> 31) { - addr64 = mmutranslate_write(addr2); - if (addr64 == 0xffffffffffffffffULL) + addr64a[0] = mmutranslate_write(addr); + if (addr64a[0] > 0xffffffffULL) return; - if (addr64 > 0xffffffffULL) - return; - } else - addr64 = (uint64_t) addr2; - - addr2 = (uint32_t) (addr64 & rammask); - - page = (addr2 >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr2 & MEM_GRANULARITY_MASK] = val; - mtrr[(addr2 + 1) & MEM_GRANULARITY_MASK] = val >> 8; - return; } - map = write_mapping[page]; + addr = addr64a[0] & rammask; - if (map && map->write_w) { - map->write_w(addr2, val, map->p); - return; - } - - if (map && map->write_b) { - map->write_b(addr2, val, map->p); - map->write_b(addr2 + 1, val >> 8, map->p); - return; - } -} - - -uint32_t -readmemll(uint32_t seg, uint32_t addr) -{ - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; - mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (addr2 & 3) { - if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - sub_cycles(timing_misaligned); - if ((addr2 & 0xfff) > 0xffc) { - if (cr0 >> 31) { - if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffff; - if (mmutranslate_read(addr2+3) == 0xffffffffffffffffULL) return 0xffffffff; - } - return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); - } else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) - return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); - } - - if (cr0 >> 31) { - addr64 = mmutranslate_read(addr2); - if (addr64 == 0xffffffffffffffffULL) - return 0xffffffff; - if (addr64 > 0xffffffffULL) - return 0xffffffff; - } else - addr64 = (uint64_t) addr2; - - addr2 = (uint32_t) (addr64 & rammask); - - page = (addr2 >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return mtrr[addr2 & MEM_GRANULARITY_MASK] | ((uint32_t) (mtrr[(addr2 + 1) & MEM_GRANULARITY_MASK]) << 8) | ((uint32_t) (mtrr[(addr2 + 2) & MEM_GRANULARITY_MASK]) << 16) | ((uint32_t) (mtrr[(addr2 + 3) & MEM_GRANULARITY_MASK]) << 24); - - map = read_mapping[page]; - - if (map && map->read_l) - return map->read_l(addr2, map->p); - - if (map && map->read_w) - return map->read_w(addr2, map->p) | - ((uint32_t) (map->read_w(addr2 + 2, map->p)) << 16); - - if (map && map->read_b) - return map->read_b(addr2, map->p) | - ((uint32_t) (map->read_b(addr2 + 1, map->p)) << 8) | - ((uint32_t) (map->read_b(addr2 + 2, map->p)) << 16) | - ((uint32_t) (map->read_b(addr2 + 3, map->p)) << 24); - - return 0xffffffff; -} - - -void -writememll(uint32_t seg, uint32_t addr, uint32_t val) -{ - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; - mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (addr2 & 3) { - if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - sub_cycles(timing_misaligned); - if ((addr2 & 0xfff) > 0xffc) { - if (cr0 >> 31) { - if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; - if (mmutranslate_write(addr2+3) == 0xffffffffffffffffULL) return; - } - writememwl(seg,addr,val); - writememwl(seg,addr+2,val>>16); - return; - } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { - *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; - return; - } - } - - if (page_lookup[addr2>>12] && page_lookup[addr2>>12]->write_l) { - page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); - return; - } - - if (cr0 >> 31) { - addr64 = mmutranslate_write(addr2); - if (addr64 == 0xffffffffffffffffULL) - return; - if (addr64 > 0xffffffffULL) - return; - } else - addr64 = (uint32_t) addr2; - - addr2 = (uint32_t) (addr64 & rammask); - - page = (addr2 >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr2 & MEM_GRANULARITY_MASK] = val; - mtrr[(addr2 + 1) & MEM_GRANULARITY_MASK] = val >> 8; - mtrr[(addr2 + 2) & MEM_GRANULARITY_MASK] = val >> 16; - mtrr[(addr2 + 3) & MEM_GRANULARITY_MASK] = val >> 24; - return; - } - - map = write_mapping[page]; + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->write_l) { - map->write_l(addr2, val, map->p); + map->write_l(addr, val, map->p); + map->write_l(addr + 4, val >> 32, map->p); return; } if (map && map->write_w) { - map->write_w(addr2, val, map->p); - map->write_w(addr2 + 2, val >> 16, map->p); + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + map->write_w(addr + 4, val >> 32, map->p); + map->write_w(addr + 6, val >> 48, map->p); return; } if (map && map->write_b) { - map->write_b(addr2, val, map->p); - map->write_b(addr2 + 1, val >> 8, map->p); - map->write_b(addr2 + 2, val >> 16, map->p); - map->write_b(addr2 + 3, val >> 24, map->p); + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + map->write_b(addr + 4, val >> 32, map->p); + map->write_b(addr + 5, val >> 40, map->p); + map->write_b(addr + 6, val >> 48, map->p); + map->write_b(addr + 7, val >> 56, map->p); return; } } -uint64_t -readmemql(uint32_t seg, uint32_t addr) -{ - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; - mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (addr2 & 7) { - sub_cycles(timing_misaligned); - if ((addr2 & 0xfff) > 0xff8) { - if (cr0 >> 31) { - if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL; - if (mmutranslate_read(addr2+7) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL; - } - return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); - } else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) - return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); - } - - if (cr0 >> 31) { - addr64 = mmutranslate_read(addr2); - if (addr64 == 0xffffffffffffffffULL) - return 0xffffffffffffffffULL; - if (addr64 > 0xffffffffULL) - return 0xffffffffffffffffULL; - } else - addr64 = (uint64_t) addr2; - - addr2 = (uint32_t) (addr64 & rammask); - - page = (addr2 >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) - return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); - - map = read_mapping[page]; - if (map && map->read_l) - return map->read_l(addr2, map->p) | ((uint64_t)map->read_l(addr2 + 4, map->p) << 32); - - return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); -} - - void -writememql(uint32_t seg, uint32_t addr, uint64_t val) +do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write) { - uint64_t addr64 = (uint64_t) addr; - uint32_t page; - uint8_t *mtrr; - mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + int i, cond = 1; + uint32_t last_addr = addr + (num - 1); + uint64_t a = 0x0000000000000000ULL; - if (addr2 & 7) { - sub_cycles(timing_misaligned); - if ((addr2 & 0xfff) > 0xff8) { - if (cr0 >> 31) { - if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; - if (mmutranslate_write(addr2+7) == 0xffffffffffffffffULL) return; - } - writememll(seg, addr, val); - writememll(seg, addr+4, val >> 32); - return; - } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { - *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; - return; + for (i = 0; i < num; i++) + a64[i] = (uint64_t) addr; + + for (i = 0; i < num; i++) { + if (cr0 >> 31) { + if (write && ((i == 0) || !(addr & 0xfff))) + cond = (!page_lookup[addr >> 12] || !page_lookup[addr >> 12]->write_b); + + if (cond) { + /* If we have encountered at least one page fault, mark all subsequent addresses as + having page faulted, prevents false negatives in readmem*l_no_mmut. */ + if ((i > 0) && cpu_state.abrt && !high_page) + a64[i] = a64[i - 1]; + /* If we are on the same page, there is no need to translate again, as we can just + reuse the previous result. */ + else if (i == 0) { + a = mmutranslatereal(addr, write); + a64[i] = (uint32_t) a; + + high_page = high_page || (!cpu_state.abrt && (a > 0xffffffffULL)); + } else if (!(addr & 0xfff)) { + a = mmutranslatereal(last_addr, write); + a64[i] = (uint32_t) a; + + high_page = high_page || (!cpu_state.abrt && (a64[i] > 0xffffffffULL)); + + if (!cpu_state.abrt) { + a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); + a64[i] = (uint32_t) a; + } + } else { + a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); + a64[i] = (uint32_t) a; + } + } else + mmu_perm = page_lookupp[addr >> 12]; } + + addr++; } - - if (page_lookup[addr2>>12] && page_lookup[addr2>>12]->write_l) { - page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); - page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]); - return; - } - - if (cr0 >> 31) { - addr64 = mmutranslate_write(addr2); - if (addr64 == 0xffffffffffffffffULL) - return; - if (addr64 > 0xffffffffULL) - return; - } else - addr64 = (uint64_t) addr2; - - addr2 = (uint32_t) (addr64 & rammask); - - page = (addr2 >> MEM_GRANULARITY_BITS); - mtrr = mtrr_areas[page]; - if (mtrr) { - mtrr[addr2 & MEM_GRANULARITY_MASK] = val; - mtrr[(addr2 + 1) & MEM_GRANULARITY_MASK] = val >> 8; - mtrr[(addr2 + 2) & MEM_GRANULARITY_MASK] = val >> 16; - mtrr[(addr2 + 3) & MEM_GRANULARITY_MASK] = val >> 24; - mtrr[(addr2 + 4) & MEM_GRANULARITY_MASK] = val >> 32; - mtrr[(addr2 + 5) & MEM_GRANULARITY_MASK] = val >> 40; - mtrr[(addr2 + 6) & MEM_GRANULARITY_MASK] = val >> 48; - mtrr[(addr2 + 7) & MEM_GRANULARITY_MASK] = val >> 56; - return; - } - - map = write_mapping[page]; - - if (map && map->write_l) { - map->write_l(addr2, val, map->p); - map->write_l(addr2+4, val >> 32, map->p); - return; - } - if (map && map->write_w) { - map->write_w(addr2, val, map->p); - map->write_w(addr2 + 2, val >> 16, map->p); - map->write_w(addr2 + 4, val >> 32, map->p); - map->write_w(addr2 + 6, val >> 48, map->p); - return; - } - if (map && map->write_b) { - map->write_b(addr2, val, map->p); - map->write_b(addr2 + 1, val >> 8, map->p); - map->write_b(addr2 + 2, val >> 16, map->p); - map->write_b(addr2 + 3, val >> 24, map->p); - map->write_b(addr2 + 4, val >> 32, map->p); - map->write_b(addr2 + 5, val >> 40, map->p); - map->write_b(addr2 + 6, val >> 48, map->p); - map->write_b(addr2 + 7, val >> 56, map->p); - return; - } -} -#endif - - -int -mem_mapping_is_romcs(uint32_t addr, int write) -{ - mem_mapping_t *map; - - if (write) - map = write_mapping[addr >> MEM_GRANULARITY_BITS]; - else - map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - - if (map) - return !!(map->flags & MEM_MAPPING_ROMCS); - else - return 0; } uint8_t mem_readb_phys(uint32_t addr) { - mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint8_t ret = 0xff; mem_logical_addr = 0xffffffff; - if (use_phys_exec && _mem_exec[addr >> MEM_GRANULARITY_BITS]) - return _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]; - else if (map && map->read_b) - return map->read_b(addr, map->p); - else - return 0xff; + if (map) { + if (map->exec) + ret = map->exec[(addr - map->base) & map->mask]; + else if (map->read_b) + ret = map->read_b(addr, map->p); + } + + return ret; } uint16_t mem_readw_phys(uint32_t addr) { - mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - uint16_t temp, *p; + mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint16_t ret, *p; mem_logical_addr = 0xffffffff; - if (use_phys_exec && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (_mem_exec[addr >> MEM_GRANULARITY_BITS])) { - p = (uint16_t *) &(_mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]); - return *p; + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->exec)) { + p = (uint16_t *) &(map->exec[(addr - map->base) & map->mask]); + ret = *p; } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->read_w)) - return map->read_w(addr, map->p); + ret = map->read_w(addr, map->p); else { - temp = mem_readb_phys(addr + 1) << 8; - temp |= mem_readb_phys(addr); + ret = mem_readb_phys(addr + 1) << 8; + ret |= mem_readb_phys(addr); } - return temp; + return ret; } uint32_t mem_readl_phys(uint32_t addr) { - mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - uint32_t temp, *p; + mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint32_t ret, *p; mem_logical_addr = 0xffffffff; - if (use_phys_exec && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (_mem_exec[addr >> MEM_GRANULARITY_BITS])) { - p = (uint32_t *) &(_mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]); - return *p; + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->exec)) { + p = (uint32_t *) &(map->exec[(addr - map->base) & map->mask]); + ret = *p; } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->read_l)) - return map->read_l(addr, map->p); + ret = map->read_l(addr, map->p); else { - temp = mem_readw_phys(addr + 2) << 16; - temp |= mem_readw_phys(addr); + ret = mem_readw_phys(addr + 2) << 16; + ret |= mem_readw_phys(addr); } - return temp; + return ret; } @@ -1624,30 +1736,32 @@ mem_read_phys(void *dest, uint32_t addr, int transfer_size) void mem_writeb_phys(uint32_t addr, uint8_t val) { - mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS]; mem_logical_addr = 0xffffffff; - if (use_phys_exec && _mem_exec[addr >> MEM_GRANULARITY_BITS]) - _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK] = val; - else if (map && map->write_b) - map->write_b(addr, val, map->p); + if (map) { + if (map->exec) + map->exec[(addr - map->base) & map->mask] = val; + else if (map->write_b) + map->write_b(addr, val, map->p); + } } void mem_writew_phys(uint32_t addr, uint16_t val) { - mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS]; uint16_t *p; mem_logical_addr = 0xffffffff; - if (use_phys_exec && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (_mem_exec[addr >> MEM_GRANULARITY_BITS])) { - p = (uint16_t *) &(_mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]); + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->exec)) { + p = (uint16_t *) &(map->exec[(addr - map->base) & map->mask]); *p = val; } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->write_w)) - map->write_w(addr, val, map->p); + map->write_w(addr, val, map->p); else { mem_writeb_phys(addr, val & 0xff); mem_writeb_phys(addr + 1, (val >> 8) & 0xff); @@ -1658,16 +1772,16 @@ mem_writew_phys(uint32_t addr, uint16_t val) void mem_writel_phys(uint32_t addr, uint32_t val) { - mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS]; uint32_t *p; mem_logical_addr = 0xffffffff; - if (use_phys_exec && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (_mem_exec[addr >> MEM_GRANULARITY_BITS])) { - p = (uint32_t *) &(_mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]); + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->exec)) { + p = (uint32_t *) &(map->exec[(addr - map->base) & map->mask]); *p = val; } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->write_l)) - map->write_l(addr, val, map->p); + map->write_l(addr, val, map->p); else { mem_writew_phys(addr, val & 0xffff); mem_writew_phys(addr + 2, (val >> 16) & 0xffff); @@ -1703,7 +1817,8 @@ mem_read_ram(uint32_t addr, void *priv) mem_log("Read B %02X from %08X\n", ram[addr], addr); #endif - addreadlookup(mem_logical_addr, addr); + if (is286) + addreadlookup(mem_logical_addr, addr); return ram[addr]; } @@ -1717,7 +1832,8 @@ mem_read_ramw(uint32_t addr, void *priv) mem_log("Read W %04X from %08X\n", *(uint16_t *)&ram[addr], addr); #endif - addreadlookup(mem_logical_addr, addr); + if (is286) + addreadlookup(mem_logical_addr, addr); return *(uint16_t *)&ram[addr]; } @@ -1731,7 +1847,8 @@ mem_read_raml(uint32_t addr, void *priv) mem_log("Read L %08X from %08X\n", *(uint32_t *)&ram[addr], addr); #endif - addreadlookup(mem_logical_addr, addr); + if (is286) + addreadlookup(mem_logical_addr, addr); return *(uint32_t *)&ram[addr]; } @@ -1779,45 +1896,6 @@ mem_read_ram_2gbl(uint32_t addr, void *priv) } -uint8_t -mem_read_smram(uint32_t addr, void *priv) -{ - smram_t *dev = (smram_t *) priv; - uint32_t new_addr = addr - dev->host_base + dev->ram_base; - - if (new_addr >= (1 << 30)) - return mem_read_ram_2gb(new_addr, priv); - else - return mem_read_ram(new_addr, priv); -} - - -uint16_t -mem_read_smramw(uint32_t addr, void *priv) -{ - smram_t *dev = (smram_t *) priv; - uint32_t new_addr = addr - dev->host_base + dev->ram_base; - - if (new_addr >= (1 << 30)) - return mem_read_ram_2gbw(new_addr, priv); - else - return mem_read_ramw(new_addr, priv); -} - - -uint32_t -mem_read_smraml(uint32_t addr, void *priv) -{ - smram_t *dev = (smram_t *) priv; - uint32_t new_addr = addr - dev->host_base + dev->ram_base; - - if (new_addr >= (1 << 30)) - return mem_read_ram_2gbl(new_addr, priv); - else - return mem_read_raml(new_addr, priv); -} - - #ifdef USE_NEW_DYNAREC static inline int page_index(page_t *p) @@ -1856,10 +1934,13 @@ page_remove_from_evict_list(page_t *p) void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) { + if (p == NULL) + return; + #ifdef USE_DYNAREC - if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if (val != p->mem[addr & 0xfff]) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; @@ -1879,10 +1960,13 @@ mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) { + if (p == NULL) + return; + #ifdef USE_DYNAREC - if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if (val != *(uint16_t *)&p->mem[addr & 0xfff]) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; @@ -1912,10 +1996,13 @@ mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) { + if (p == NULL) + return; + #ifdef USE_DYNAREC - if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if (val != *(uint32_t *)&p->mem[addr & 0xfff]) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; @@ -1941,10 +2028,13 @@ mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) { + if (p == NULL) + return; + #ifdef USE_DYNAREC - if ((p == NULL) || (p->mem == NULL) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if ((p == NULL) || (p->mem == NULL) || (val != p->mem[addr & 0xfff])) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; @@ -1956,10 +2046,13 @@ mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) { + if (p == NULL) + return; + #ifdef USE_DYNAREC - if ((p == NULL) || (p->mem == NULL) || (val != *(uint16_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if ((p == NULL) || (p->mem == NULL) || (val != *(uint16_t *)&p->mem[addr & 0xfff])) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); if ((addr & 0xf) == 0xf) @@ -1973,10 +2066,13 @@ mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) { + if (p == NULL) + return; + #ifdef USE_DYNAREC - if ((p == NULL) || (p->mem == NULL) || (val != *(uint32_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff]) || codegen_in_recompile) { #else - if ((p == NULL) || (p->mem == NULL) || (val != *(uint32_t *)&p->mem[addr & 0xfff])) { + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *)&p->mem[addr & 0xfff])) { #endif uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); if ((addr & 0xf) >= 0xd) @@ -1995,8 +2091,11 @@ mem_write_ram(uint32_t addr, uint8_t val, void *priv) if ((addr >= 0xa0000) && (addr <= 0xbffff)) mem_log("Write B %02X to %08X\n", val, addr); #endif - addwritelookup(mem_logical_addr, addr); - mem_write_ramb_page(addr, val, &pages[addr >> 12]); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); + } else + ram[addr] = val; } @@ -2007,8 +2106,11 @@ mem_write_ramw(uint32_t addr, uint16_t val, void *priv) if ((addr >= 0xa0000) && (addr <= 0xbffff)) mem_log("Write W %04X to %08X\n", val, addr); #endif - addwritelookup(mem_logical_addr, addr); - mem_write_ramw_page(addr, val, &pages[addr >> 12]); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); + } else + *(uint16_t *)&ram[addr] = val; } @@ -2019,47 +2121,20 @@ mem_write_raml(uint32_t addr, uint32_t val, void *priv) if ((addr >= 0xa0000) && (addr <= 0xbffff)) mem_log("Write L %08X to %08X\n", val, addr); #endif - addwritelookup(mem_logical_addr, addr); - mem_write_raml_page(addr, val, &pages[addr >> 12]); -} - - -void -mem_write_smram(uint32_t addr, uint8_t val, void *priv) -{ - smram_t *dev = (smram_t *) priv; - uint32_t new_addr = addr - dev->host_base + dev->ram_base; - - mem_write_ram(new_addr, val, priv); -} - - -void -mem_write_smramw(uint32_t addr, uint16_t val, void *priv) -{ - smram_t *dev = (smram_t *) priv; - uint32_t new_addr = addr - dev->host_base + dev->ram_base; - - mem_write_ramw(new_addr, val, priv); -} - - -void -mem_write_smraml(uint32_t addr, uint32_t val, void *priv) -{ - smram_t *dev = (smram_t *) priv; - uint32_t new_addr = addr - dev->host_base + dev->ram_base; - - mem_write_raml(new_addr, val, priv); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); + } else + *(uint32_t *)&ram[addr] = val; } static uint8_t mem_read_remapped(uint32_t addr, void *priv) { - if ((addr >= (mem_size * 1024)) && (addr < ((mem_size + 384) * 1024))) - addr = 0xA0000 + (addr - (mem_size * 1024)); - addreadlookup(mem_logical_addr, addr); + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) + addreadlookup(mem_logical_addr, addr); return ram[addr]; } @@ -2067,9 +2142,9 @@ mem_read_remapped(uint32_t addr, void *priv) static uint16_t mem_read_remappedw(uint32_t addr, void *priv) { - if ((addr >= (mem_size * 1024)) && (addr < ((mem_size + 384) * 1024))) - addr = 0xA0000 + (addr - (mem_size * 1024)); - addreadlookup(mem_logical_addr, addr); + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) + addreadlookup(mem_logical_addr, addr); return *(uint16_t *)&ram[addr]; } @@ -2077,9 +2152,9 @@ mem_read_remappedw(uint32_t addr, void *priv) static uint32_t mem_read_remappedl(uint32_t addr, void *priv) { - if ((addr >= (mem_size * 1024)) && (addr < ((mem_size + 384) * 1024))) - addr = 0xA0000 + (addr - (mem_size * 1024)); - addreadlookup(mem_logical_addr, addr); + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) + addreadlookup(mem_logical_addr, addr); return *(uint32_t *)&ram[addr]; } @@ -2088,10 +2163,12 @@ static void mem_write_remapped(uint32_t addr, uint8_t val, void *priv) { uint32_t oldaddr = addr; - if ((addr >= (mem_size * 1024)) && (addr < ((mem_size + 384) * 1024))) - addr = 0xA0000 + (addr - (mem_size * 1024)); - addwritelookup(mem_logical_addr, addr); - mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); + } else + ram[addr] = val; } @@ -2099,10 +2176,12 @@ static void mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) { uint32_t oldaddr = addr; - if ((addr >= (mem_size * 1024)) && (addr < ((mem_size + 384) * 1024))) - addr = 0xA0000 + (addr - (mem_size * 1024)); - addwritelookup(mem_logical_addr, addr); - mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint16_t *)&ram[addr] = val; } @@ -2110,212 +2189,83 @@ static void mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) { uint32_t oldaddr = addr; - if ((addr >= (mem_size * 1024)) && (addr < ((mem_size + 384) * 1024))) - addr = 0xA0000 + (addr - (mem_size * 1024)); - addwritelookup(mem_logical_addr, addr); - mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); -} - - -uint8_t -mem_read_bios(uint32_t addr, void *priv) -{ - uint8_t ret = 0xff; - - addr &= 0x000fffff; - - if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) - ret = rom[addr - biosaddr]; - - return ret; -} - - -uint16_t -mem_read_biosw(uint32_t addr, void *priv) -{ - uint16_t ret = 0xffff; - - addr &= 0x000fffff; - - if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) - ret = *(uint16_t *)&rom[addr - biosaddr]; - - return ret; -} - - -uint32_t -mem_read_biosl(uint32_t addr, void *priv) -{ - uint32_t ret = 0xffffffff; - - addr &= 0x000fffff; - - if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) - ret = *(uint32_t *)&rom[addr - biosaddr]; - - return ret; -} - - -void -mem_write_null(uint32_t addr, uint8_t val, void *p) -{ -} - - -void -mem_write_nullw(uint32_t addr, uint16_t val, void *p) -{ -} - - -void -mem_write_nulll(uint32_t addr, uint32_t val, void *p) -{ + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint32_t *)&ram[addr] = val; } void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) { - uint64_t mask; #ifdef USE_NEW_DYNAREC page_t *p; start_addr &= ~PAGE_MASK_MASK; - end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { + for (; start_addr <= end_addr; start_addr += 0x1000) { if ((start_addr >> 12) >= pages_sz) continue; - mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - p = &pages[start_addr >> 12]; + if (p) { + p->dirty_mask = 0xffffffffffffffffULL; - p->dirty_mask |= mask; - if ((p->code_present_mask & mask) && !page_in_evict_list(p)) - page_add_to_evict_list(p); + if (p->byte_dirty_mask) + memset(p->byte_dirty_mask, 0xff, 64 * sizeof(uint64_t)); + + if (!page_in_evict_list(p)) + page_add_to_evict_list(p); + } } #else uint32_t cur_addr; start_addr &= ~PAGE_MASK_MASK; - end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - - for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { - mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + for (; start_addr <= end_addr; start_addr += 0x1000) { /* Do nothing if the pages array is empty or DMA reads/writes to/from PCI device memory addresses may crash the emulator. */ cur_addr = (start_addr >> 12); if (cur_addr < pages_sz) - pages[cur_addr].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + memset(pages[cur_addr].dirty_mask, 0xff, sizeof(pages[cur_addr].dirty_mask)); } #endif } static __inline int -mem_mapping_read_allowed(uint32_t flags, uint32_t state, int exec) +mem_mapping_access_allowed(uint32_t flags, uint16_t access) { - uint32_t smm_state = state >> MEM_STATE_SMM_SHIFT; - uint32_t state_masked; int ret = 0; - if (in_smm && ((smm_state & MEM_READ_MASK) != MEM_READ_NORMAL)) - state = smm_state; + if (!(access & ACCESS_DISABLED)) { + if (access & ACCESS_CACHE) + ret = (flags & MEM_MAPPING_CACHE); + else if (access & ACCESS_SMRAM) + ret = (flags & MEM_MAPPING_SMRAM); + else if (!(access & ACCESS_INTERNAL)) { + if (flags & MEM_MAPPING_IS_ROM) { + if (access & ACCESS_ROMCS) + ret = (flags & MEM_MAPPING_ROMCS); + else + ret = !(flags & MEM_MAPPING_ROMCS); + } else + ret = 1; - state_masked = (state & MEM_READ_MASK); - - if (state_masked & MEM_READ_SMRAM) - ret = (flags & MEM_MAPPING_SMRAM); - else if ((state_masked & MEM_READ_SMRAM_EX) && exec) - ret = (flags & MEM_MAPPING_SMRAM); - else if (!(state_masked & MEM_READ_DISABLED_EX)) switch (state_masked) { - case MEM_READ_ANY: - ret = !(flags & MEM_MAPPING_SMRAM); - break; - - /* On external and 0 mappings without ROMCS. */ - case MEM_READ_EXTERNAL: - ret = !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_ROMCS) && !(flags & MEM_MAPPING_SMRAM); - break; - - /* On external and 0 mappings with ROMCS. */ - case MEM_READ_ROMCS: - ret = !(flags & MEM_MAPPING_INTERNAL) && (flags & MEM_MAPPING_ROMCS) && !(flags & MEM_MAPPING_SMRAM); - break; - - /* On any external mappings. */ - case MEM_READ_EXTANY: - ret = !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM); - break; - - case MEM_READ_EXTERNAL_EX: - if (exec) - ret = !(flags & MEM_MAPPING_EXTERNAL) && !(flags & MEM_MAPPING_SMRAM); - else - ret = !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM); - break; - - case MEM_READ_INTERNAL: + ret = ret && !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM); + } else ret = !(flags & MEM_MAPPING_EXTERNAL) && !(flags & MEM_MAPPING_SMRAM); - break; - - default: - if (state_masked != MEM_READ_DISABLED) - fatal("mem_mapping_read_allowed : bad state %x\n", state_masked); - break; - } - - return ret; -} - - -static __inline int -mem_mapping_write_allowed(uint32_t flags, uint32_t state) -{ - uint32_t smm_state = state >> MEM_STATE_SMM_SHIFT; - uint32_t state_masked; - int ret = 0; - - if (in_smm && ((smm_state & MEM_WRITE_MASK) != MEM_WRITE_NORMAL)) - state = smm_state; - - state_masked = (state & MEM_WRITE_MASK); - - if (state_masked & MEM_WRITE_SMRAM) - ret = (flags & MEM_MAPPING_SMRAM); - else if (!(state_masked & MEM_WRITE_DISABLED_EX)) switch (state_masked) { - case MEM_WRITE_ANY: - ret = !(flags & MEM_MAPPING_SMRAM); - break; - - /* On external and 0 mappings without ROMCS. */ - case MEM_WRITE_EXTERNAL: - ret = !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_ROMCS) && !(flags & MEM_MAPPING_SMRAM); - break; - - /* On external and 0 mappings with ROMCS. */ - case MEM_WRITE_ROMCS: - ret = !(flags & MEM_MAPPING_INTERNAL) && (flags & MEM_MAPPING_ROMCS) && !(flags & MEM_MAPPING_SMRAM); - break; - - /* On any external mappings. */ - case MEM_WRITE_EXTANY: - ret = !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM); - break; - - case MEM_WRITE_INTERNAL: - ret = !(flags & MEM_MAPPING_EXTERNAL) && !(flags & MEM_MAPPING_SMRAM); - break; - - default: - if (state_masked != MEM_WRITE_DISABLED) - fatal("mem_mapping_write_allowed : bad state %x\n", state_masked); - break; + } else { + /* Still allow SMRAM if access is DISABLED but also has CACHE and/or SMRAM flags set. */ + if (access & ACCESS_CACHE) + ret = (flags & MEM_MAPPING_CACHE); + else if (access & ACCESS_SMRAM) + ret = (flags & MEM_MAPPING_SMRAM); } return ret; @@ -2325,52 +2275,56 @@ mem_mapping_write_allowed(uint32_t flags, uint32_t state) void mem_mapping_recalc(uint64_t base, uint64_t size) { - mem_mapping_t *map = base_mapping.next; + mem_mapping_t *map; + int n; uint64_t c; - if (! size) return; + if (!size || (base_mapping == NULL)) + return; + + map = base_mapping; /* Clear out old mappings. */ for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) { - read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; - write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping_bus[c >> MEM_GRANULARITY_BITS] = NULL; + read_mapping_bus[c >> MEM_GRANULARITY_BITS] = NULL; } /* Walk mapping list. */ while (map != NULL) { - /*In range?*/ - if (map->enable && (uint64_t)map->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)map->base + (uint64_t)map->size) > (uint64_t)base) { + /* In range? */ + if (map->enable && (uint64_t)map->base < ((uint64_t)base + (uint64_t)size) && + ((uint64_t)map->base + (uint64_t)map->size) > (uint64_t)base) { uint64_t start = (map->base < base) ? map->base : base; - uint64_t end = (((uint64_t)map->base + (uint64_t)map->size) < (base + size)) ? ((uint64_t)map->base + (uint64_t)map->size) : (base + size); + uint64_t end = (((uint64_t)map->base + (uint64_t)map->size) < (base + size)) ? + ((uint64_t)map->base + (uint64_t)map->size) : (base + size); if (start < map->base) start = map->base; for (c = start; c < end; c += MEM_GRANULARITY_SIZE) { - if ((map->read_b || map->read_w || map->read_l) && - mem_mapping_read_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS], 0)) { -#ifdef ENABLE_MEM_LOG - if ((start >= 0xa0000) && (start <= 0xbffff)) - mem_log("Read allowed: %08X (mapping for %08X)\n", map, start); -#endif - read_mapping[c >> MEM_GRANULARITY_BITS] = map; - } + /* CPU */ + n = !!in_smm; if (map->exec && - mem_mapping_read_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS], 1)) { -#ifdef ENABLE_MEM_LOG - if ((start >= 0xa0000) && (start <= 0xbffff)) - mem_log("Exec allowed: %08X (mapping for %08X)\n", map, start); -#endif + mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].x)) _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->base); - } if ((map->write_b || map->write_w || map->write_l) && - mem_mapping_write_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) { -#ifdef ENABLE_MEM_LOG - if ((start >= 0xa0000) && (start <= 0xbffff)) - mem_log("Write allowed: %08X (mapping for %08X)\n", map, start); -#endif + mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w)) write_mapping[c >> MEM_GRANULARITY_BITS] = map; - } + if ((map->read_b || map->read_w || map->read_l) && + mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r)) + read_mapping[c >> MEM_GRANULARITY_BITS] = map; + + /* Bus */ + n |= STATE_BUS; + if ((map->write_b || map->write_w || map->write_l) && + mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w)) + write_mapping_bus[c >> MEM_GRANULARITY_BITS] = map; + if ((map->read_b || map->read_w || map->read_l) && + mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r)) + read_mapping_bus[c >> MEM_GRANULARITY_BITS] = map; } } map = map->next; @@ -2381,27 +2335,9 @@ mem_mapping_recalc(uint64_t base, uint64_t size) void -mem_mapping_del(mem_mapping_t *map) -{ - mem_mapping_t *ptr; - - /* Disable the entry. */ - mem_mapping_disable(map); - - /* Zap it from the list. */ - for (ptr = &base_mapping; ptr->next != NULL; ptr = ptr->next) { - if (ptr->next == map) { - ptr->next = map->next; - break; - } - } -} - - -void -mem_mapping_add(mem_mapping_t *map, - uint32_t base, - uint32_t size, +mem_mapping_set(mem_mapping_t *map, + uint32_t base, + uint32_t size, uint8_t (*read_b)(uint32_t addr, void *p), uint16_t (*read_w)(uint32_t addr, void *p), uint32_t (*read_l)(uint32_t addr, void *p), @@ -2412,20 +2348,13 @@ mem_mapping_add(mem_mapping_t *map, uint32_t fl, void *p) { - mem_mapping_t *dest = &base_mapping; - - /* Add mapping to the end of the list.*/ - while (dest->next) - dest = dest->next; - dest->next = map; - map->prev = dest; - - if (size) + if (size != 0x00000000) map->enable = 1; - else + else map->enable = 0; map->base = base; map->size = size; + map->mask = (map->size ? 0xffffffff : 0x00000000); map->read_b = read_b; map->read_w = read_w; map->read_l = read_l; @@ -2435,10 +2364,59 @@ mem_mapping_add(mem_mapping_t *map, map->exec = exec; map->flags = fl; map->p = p; - map->dev = NULL; map->next = NULL; + mem_log("mem_mapping_add(): Linked list structure: %08X -> %08X -> %08X\n", map->prev, map, map->next); - mem_mapping_recalc(map->base, map->size); + /* If the mapping is disabled, there is no need to recalc anything. */ + if (size != 0x00000000) + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_add(mem_mapping_t *map, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t fl, + void *p) +{ + /* Do a sanity check */ + if ((base_mapping == NULL) && (last_mapping != NULL)) { + fatal("mem_mapping_add(): NULL base mapping with non-NULL last mapping\n"); + return; + } else if ((base_mapping != NULL) && (last_mapping == NULL)) { + fatal("mem_mapping_add(): Non-NULL base mapping with NULL last mapping\n"); + return; + } else if ((base_mapping != NULL) && (base_mapping->prev != NULL)) { + fatal("mem_mapping_add(): Base mapping with a preceding mapping\n"); + return; + } else if ((last_mapping != NULL) && (last_mapping->next != NULL)) { + fatal("mem_mapping_add(): Last mapping with a following mapping\n"); + return; + } + + /* Add mapping to the beginning of the list if necessary.*/ + if (base_mapping == NULL) + base_mapping = map; + + /* Add mapping to the end of the list.*/ + if (last_mapping == NULL) + map->prev = NULL; + else { + map->prev = last_mapping; + last_mapping->next = map; + } + last_mapping = map; + + mem_mapping_set(map, base, size, read_b, read_w, read_l, + write_b, write_w, write_l, exec, fl, p); } @@ -2495,16 +2473,18 @@ mem_mapping_set_exec(mem_mapping_t *map, uint8_t *exec) void -mem_mapping_set_p(mem_mapping_t *map, void *p) +mem_mapping_set_mask(mem_mapping_t *map, uint32_t mask) { - map->p = p; + map->mask = mask; + + mem_mapping_recalc(map->base, map->size); } void -mem_mapping_set_dev(mem_mapping_t *map, void *p) +mem_mapping_set_p(mem_mapping_t *map, void *p) { - map->dev = p; + map->p = p; } @@ -2527,47 +2507,49 @@ mem_mapping_enable(mem_mapping_t *map) void -mem_set_state(int smm, int mode, uint32_t base, uint32_t size, uint32_t state) +mem_set_access(uint8_t bitmap, int mode, uint32_t base, uint32_t size, uint16_t access) { - uint32_t c, mask_l, mask_h, smstate = 0x0000; + uint32_t c; + uint16_t mask, smstate = 0x0000; + const uint16_t smstates[4] = { 0x0000, (MEM_READ_SMRAM | MEM_WRITE_SMRAM), + MEM_READ_SMRAM_EX, (MEM_READ_DISABLED_EX | MEM_WRITE_DISABLED_EX) }; - if (mode) { - mask_l = 0xffff0f0f; - mask_h = 0x0f0fffff; - } else { - mask_l = 0xfffff0f0; - mask_h = 0xf0f0ffff; - } + int i; + + if (mode) + mask = 0x2d6b; + else + mask = 0x1084; if (mode) { if (mode == 1) - state = !!state; + access = !!access; - switch (state & 0x03) { - case 0x00: - smstate = 0x0000; - break; - case 0x01: - smstate = (MEM_READ_SMRAM | MEM_WRITE_SMRAM); - break; - case 0x02: - smstate = MEM_READ_SMRAM_EX; - break; - case 0x03: - smstate = (MEM_READ_DISABLED_EX | MEM_WRITE_DISABLED_EX); - break; - } + if (mode == 3) { + if (access & ACCESS_SMRAM_X) + smstate |= MEM_EXEC_SMRAM; + if (access & ACCESS_SMRAM_R) + smstate |= MEM_READ_SMRAM_2; + if (access & ACCESS_SMRAM_W) + smstate |= MEM_WRITE_SMRAM; + } else + smstate = smstates[access & 0x07]; } else - smstate = state & 0x0f0f; + smstate = access & 0x6f7b; for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) { - if (smm != 0) - _mem_state[(c + base) >> MEM_GRANULARITY_BITS] = (_mem_state[(c + base) >> MEM_GRANULARITY_BITS] & mask_h) | (smstate << MEM_STATE_SMM_SHIFT); - if (smm != 1) - _mem_state[(c + base) >> MEM_GRANULARITY_BITS] = (_mem_state[(c + base) >> MEM_GRANULARITY_BITS] & mask_l) | smstate; + for (i = 0; i < 4; i++) { + if (bitmap & (1 << i)) { + _mem_state[(c + base) >> MEM_GRANULARITY_BITS].vals[i] = + (_mem_state[(c + base) >> MEM_GRANULARITY_BITS].vals[i] & mask) | smstate; + } + } + #ifdef ENABLE_MEM_LOG - if (((c + base) >= 0xa0000) && ((c + base) <= 0xbffff)) - mem_log("Set mem state for block at %08X to %02X\n", c + base, smstate); + if (((c + base) >= 0xa0000) && ((c + base) <= 0xbffff)) { + mem_log("Set mem state for block at %08X to %04X with bitmap %02X\n", + c + base, smstate, bitmap); + } #endif } @@ -2575,52 +2557,13 @@ mem_set_state(int smm, int mode, uint32_t base, uint32_t size, uint32_t state) } -void -mem_add_bios(void) -{ - int temp_cpu_type, temp_cpu_16bitbus = 1; - - if (AT) { - temp_cpu_type = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type; - temp_cpu_16bitbus = (temp_cpu_type == CPU_286 || temp_cpu_type == CPU_386SX || temp_cpu_type == CPU_486SLC || temp_cpu_type == CPU_IBM386SLC || temp_cpu_type == CPU_IBM486SLC ); - } - - if (biosmask > 0x1ffff) { - /* 256k+ BIOS'es only have low mappings at E0000-FFFFF. */ - mem_mapping_add(&bios_mapping, 0xe0000, 0x20000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - &rom[0x20000], MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); - - mem_set_mem_state_both(0x0e0000, 0x20000, - MEM_READ_ROMCS | MEM_WRITE_ROMCS); - } else { - mem_mapping_add(&bios_mapping, biosaddr, biosmask + 1, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); - - mem_set_mem_state_both(biosaddr, biosmask + 1, - MEM_READ_ROMCS | MEM_WRITE_ROMCS); - } - - if (AT) { - mem_mapping_add(&bios_high_mapping, biosaddr | (temp_cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); - - mem_set_mem_state_both(biosaddr | (temp_cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, - MEM_READ_ROMCS | MEM_WRITE_ROMCS); - } -} - - void mem_a20_init(void) { - if (AT) { + if (is286) { rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + if (is6117) + rammask |= 0x03000000; flushmmucache(); mem_a20_state = mem_a20_key | mem_a20_alt; } else { @@ -2631,32 +2574,115 @@ mem_a20_init(void) } +/* Close all the memory mappings. */ +void +mem_close(void) +{ + mem_mapping_t *map = base_mapping, *next; + + while (map != NULL) { + next = map->next; + map->prev = map->next = NULL; + map = next; + } + + base_mapping = last_mapping = 0; +} + + +static void +mem_add_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + mem_mapping_add(mapping, base, size, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + base, MEM_MAPPING_INTERNAL, NULL); +} + + +static void +mem_init_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + mem_set_mem_state_both(base, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_add_ram_mapping(mapping, base, size); +} + + /* Reset the memory state. */ void mem_reset(void) { - uint32_t c, m, m2; + uint32_t c, m; + + memset(page_ff, 0xff, sizeof(page_ff)); + +#ifdef USE_NEW_DYNAREC + if (byte_dirty_mask) { + free(byte_dirty_mask); + byte_dirty_mask = NULL; + } + + if (byte_code_present_mask) { + free(byte_code_present_mask); + byte_code_present_mask = NULL; + } +#endif + + /* Free the old pages array, if necessary. */ + if (pages) { + free(pages); + pages = NULL; + } + + if (ram != NULL) { + plat_munmap(ram, ram_size); + ram = NULL; + ram_size = 0; + } +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (ram2 != NULL) { + plat_munmap(ram2, ram2_size); + ram2 = NULL; + ram2_size = 0; + } + + if (mem_size > 2097152) + mem_size = 2097152; +#endif m = 1024UL * mem_size; - if (ram != NULL) { - free(ram); - ram = NULL; - } - if (ram2 != NULL) { - free(ram2); - ram2 = NULL; - } - if (mem_size > 2097152) - fatal("Attempting to use more than 2 GB of guest RAM\n"); +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (mem_size > 1048576) { - ram = (uint8_t *)malloc(1 << 30); /* allocate and clear the RAM block of the first 1 GB */ - memset(ram, 0x00, 1 << 30); - ram2 = (uint8_t *)malloc(m - (1 << 30)); /* allocate and clear the RAM block above 1 GB */ - memset(ram2, 0x00, m - (1 << 30)); - } else { - ram = (uint8_t *)malloc(m); /* allocate and clear the RAM block */ - memset(ram, 0x00, m); + ram_size = 1 << 30; + ram = (uint8_t *) plat_mmap(ram_size, 0); /* allocate and clear the RAM block of the first 1 GB */ + if (ram == NULL) { + fatal("Failed to allocate primary RAM block. Make sure you have enough RAM available.\n"); + return; + } + memset(ram, 0x00, ram_size); + ram2_size = m - (1 << 30); + ram2 = (uint8_t *) plat_mmap(ram2_size, 0); /* allocate and clear the RAM block above 1 GB */ + if (ram2 == NULL) { + if (config_changed == 2) + fatal(EMU_NAME " must be restarted for the memory amount change to be applied.\n"); + else + fatal("Failed to allocate secondary RAM block. Make sure you have enough RAM available.\n"); + return; + } + memset(ram2, 0x00, ram2_size); + } else +#endif + { + ram_size = m; + ram = (uint8_t *) plat_mmap(ram_size, 0); /* allocate and clear the RAM block */ + if (ram == NULL) { + fatal("Failed to allocate RAM block. Make sure you have enough RAM available.\n"); + return; + } + memset(ram, 0x00, ram_size); + if (mem_size > 1048576) + ram2 = &(ram[1 << 30]); } /* @@ -2664,12 +2690,15 @@ mem_reset(void) * We re-allocate the table on each (hard) reset, as the * memory amount could have changed. */ - if (AT) { + if (is286) { if (cpu_16bitbus) { - /* 80186/286; maximum address space is 16MB. */ + /* 80286/386SX; maximum address space is 16MB. */ m = 4096; + /* ALi M6117; maximum address space is 64MB. */ + if (is6117) + m <<= 2; } else { - /* 80386+; maximum address space is 4GB. */ + /* 80386DX+; maximum address space is 4GB. */ m = 1048576; } } else { @@ -2677,105 +2706,45 @@ mem_reset(void) m = 256; } - /* Calculate the amount of pages used by RAM, so that we can - give all the pages above this amount NULL write handlers. */ - m2 = (mem_size + 384) >> 2; - if ((m2 << 2) < (mem_size + 384)) - m2++; - if (m2 < 4096) - m2 = 4096; - /* * Allocate and initialize the (new) page table. - * We only do this if the size of the page table has changed. */ -#if DYNAMIC_TABLES -mem_log("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); -#endif - if (pages_sz != m) { - pages_sz = m; - if (pages) { - free(pages); - pages = NULL; - } - pages = (page_t *)malloc(m*sizeof(page_t)); -#if DYNAMIC_TABLES -mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); -#endif + pages_sz = m; + pages = (page_t *)malloc(m*sizeof(page_t)); -#if DYNAMIC_TABLES - /* Allocate the (new) lookup tables. */ - if (page_lookup != NULL) free(page_lookup); - page_lookup = (page_t **)malloc(pages_sz*sizeof(page_t *)); - - if (readlookup2 != NULL) free(readlookup2); - readlookup2 = malloc(pages_sz*sizeof(uintptr_t)); - - if (writelookup2 != NULL) free(writelookup2); - writelookup2 = malloc(pages_sz*sizeof(uintptr_t)); - -#endif - } - -#if DYNAMIC_TABLES - memset(page_lookup, 0x00, pages_sz * sizeof(page_t *)); -#else memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); -#endif + memset(page_lookupp, 0x04, (1 << 20) * sizeof(uint8_t)); memset(pages, 0x00, pages_sz*sizeof(page_t)); - for (c = 0; c < MEM_MAPPINGS_NO; c++) { - if (mtrr_areas[c]) { - free(mtrr_areas[c]); - mtrr_areas[c] = 0; - } - mtrr_area_refcounts[c] = 0; - } - #ifdef USE_NEW_DYNAREC - if (machines[machine].flags & MACHINE_COREBOOT) { - /* coreboot executes code from the BIOS area, thus - requiring byte_*_mask for the entire address space, - which significantly increases memory usage. */ - c = ((uint64_t) (pages_sz) * MEM_GRANULARITY_SIZE) / 8; - } else { - c = (mem_size * 1024) / 8; - } + byte_dirty_mask = malloc((mem_size * 1024) / 8); + memset(byte_dirty_mask, 0, (mem_size * 1024) / 8); - if (byte_dirty_mask) { - free(byte_dirty_mask); - byte_dirty_mask = NULL; - } - byte_dirty_mask = malloc(c); - memset(byte_dirty_mask, 0, c); - - if (byte_code_present_mask) { - free(byte_code_present_mask); - byte_code_present_mask = NULL; - } - byte_code_present_mask = malloc(c); - memset(byte_code_present_mask, 0, c); + byte_code_present_mask = malloc((mem_size * 1024) / 8); + memset(byte_code_present_mask, 0, (mem_size * 1024) / 8); #endif for (c = 0; c < pages_sz; c++) { - if (mem_size > 1048576) { - if ((c << 12) < (1 << 30)) + if ((c << 12) >= (mem_size << 10)) + pages[c].mem = page_ff; + else { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (mem_size > 1048576) { + if ((c << 12) < (1 << 30)) + pages[c].mem = &ram[c << 12]; + else + pages[c].mem = &ram2[(c << 12) - (1 << 30)]; + } else pages[c].mem = &ram[c << 12]; - else - pages[c].mem = &ram2[(c << 12) - (1 << 30)]; - } else +#else pages[c].mem = &ram[c << 12]; +#endif + } if (c < m) { pages[c].write_b = mem_write_ramb_page; pages[c].write_w = mem_write_ramw_page; pages[c].write_l = mem_write_raml_page; - } else { - /* Make absolute sure non-RAM pages have NULL handlers so the - memory read/write handlers know to ignore them. */ - pages[c].write_b = NULL; - pages[c].write_w = NULL; - pages[c].write_l = NULL; } #ifdef USE_NEW_DYNAREC pages[c].evict_prev = EVICT_NOT_IN_LIST; @@ -2784,41 +2753,29 @@ mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); #endif } - memset(_mem_exec, 0x00, sizeof(_mem_exec)); + memset(_mem_exec, 0x00, sizeof(_mem_exec)); + memset(write_mapping, 0x00, sizeof(write_mapping)); + memset(read_mapping, 0x00, sizeof(read_mapping)); + memset(write_mapping_bus, 0x00, sizeof(write_mapping_bus)); + memset(read_mapping_bus, 0x00, sizeof(read_mapping_bus)); - memset(&base_mapping, 0x00, sizeof(base_mapping)); + base_mapping = last_mapping = NULL; + /* Set the entire memory space as external. */ memset(_mem_state, 0x00, sizeof(_mem_state)); - mem_set_mem_state_both(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_set_mem_state_both(0x0a0000, 0x60000, - MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - - mem_mapping_add(&ram_low_mapping, 0x00000, - (mem_size > 640) ? 0xa0000 : mem_size * 1024, - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram, MEM_MAPPING_INTERNAL, NULL); + /* Set the low RAM space as internal. */ + mem_init_ram_mapping(&ram_low_mapping, 0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024); if (mem_size > 1024) { - if (cpu_16bitbus && mem_size > 16256) { - mem_set_mem_state_both(0x100000, (16256 - 1024) * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_high_mapping, 0x100000, - ((16256 - 1024) * 1024), - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); - } else { + if (cpu_16bitbus && !is6117 && mem_size > 16256) + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (16256 - 1024) * 1024); + else if (cpu_16bitbus && is6117 && mem_size > 65408) + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (65408 - 1024) * 1024); + else { if (mem_size > 1048576) { - mem_set_mem_state_both(0x100000, (1048576 - 1024) * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_high_mapping, 0x100000, - ((1048576 - 1024) * 1024), - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (1048576 - 1024) * 1024); + mem_set_mem_state_both((1 << 30), (mem_size - 1048576) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_mapping_add(&ram_2gb_mapping, (1 << 30), @@ -2826,46 +2783,21 @@ mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); mem_read_ram_2gb,mem_read_ram_2gbw,mem_read_ram_2gbl, mem_write_ram,mem_write_ramw,mem_write_raml, ram2, MEM_MAPPING_INTERNAL, NULL); - } else { - mem_set_mem_state_both(0x100000, (mem_size - 1024) * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_high_mapping, 0x100000, - ((mem_size - 1024) * 1024), - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); - } + } else + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024); } } - if (mem_size > 768) { - mem_mapping_add(&ram_mid_mapping, 0xa0000, 0x60000, - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); - } - - mem_mapping_add(&ram_smram_mapping[0], 0xa0000, 0x60000, - mem_read_smram,mem_read_smramw,mem_read_smraml, - mem_write_smram,mem_write_smramw,mem_write_smraml, - ram + 0xa0000, MEM_MAPPING_SMRAM, &(smram[0])); - mem_mapping_add(&ram_smram_mapping[1], 0xa0000, 0x60000, - mem_read_smram,mem_read_smramw,mem_read_smraml, - mem_write_smram,mem_write_smramw,mem_write_smraml, - ram + 0xa0000, MEM_MAPPING_SMRAM, &(smram[1])); - mem_mapping_disable(&ram_smram_mapping[0]); - mem_mapping_disable(&ram_smram_mapping[1]); + if (mem_size > 768) + mem_add_ram_mapping(&ram_mid_mapping, 0xa0000, 0x60000); mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 1024, mem_read_remapped,mem_read_remappedw,mem_read_remappedl, mem_write_remapped,mem_write_remappedw,mem_write_remappedl, ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); mem_mapping_disable(&ram_remapped_mapping); - - mem_a20_init(); - smram[0].host_base = smram[0].ram_base = smram[0].size = 0x00000000; - smram[1].host_base = smram[1].ram_base = smram[1].size = 0x00000000; + mem_a20_init(); #ifdef USE_NEW_DYNAREC purgable_page_list_head = 0; @@ -2881,28 +2813,14 @@ mem_init(void) ram = rom = NULL; ram2 = NULL; pages = NULL; -#if DYNAMIC_TABLES - page_lookup = NULL; - readlookup2 = NULL; - writelookup2 = NULL; -#else /* Allocate the lookup tables. */ page_lookup = (page_t **)malloc((1<<20)*sizeof(page_t *)); - + page_lookupp = (uint8_t *)malloc((1<<20)*sizeof(uint8_t)); readlookup2 = malloc((1<<20)*sizeof(uintptr_t)); - + readlookupp = malloc((1<<20)*sizeof(uint8_t)); writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); -#endif - - memset(mtrr_areas, 0x00, MEM_MAPPINGS_NO*sizeof(uint8_t *)); - -#if FIXME - memset(ff_array, 0xff, sizeof(ff_array)); -#endif - - /* Reset the memory state. */ - mem_reset(); + writelookupp = malloc((1<<20)*sizeof(uint8_t)); } @@ -2912,26 +2830,29 @@ mem_remap_top(int kb) uint32_t c; uint32_t start = (mem_size >= 1024) ? mem_size : 1024; int offset, size = mem_size - 640; + int set = 1; + static int old_kb = 0; mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size); if (mem_size <= 640) return; if (kb == 0) { - /* Called to disable the mapping. */ - mem_mapping_disable(&ram_remapped_mapping); + kb = old_kb; + set = 0; + } else + old_kb = kb; - return; - } - if (size > kb) size = kb; + remap_start_addr = start << 10; + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) { offset = c - ((start * 1024) >> 12); - pages[c].mem = &ram[0xA0000 + (offset << 12)]; - pages[c].write_b = mem_write_ramb_page; - pages[c].write_w = mem_write_ramw_page; - pages[c].write_l = mem_write_raml_page; + pages[c].mem = set ? &ram[0xa0000 + (offset << 12)] : page_ff; + pages[c].write_b = set ? mem_write_ramb_page : NULL; + pages[c].write_w = set ? mem_write_ramw_page : NULL; + pages[c].write_l = set ? mem_write_raml_page : NULL; #ifdef USE_NEW_DYNAREC pages[c].evict_prev = EVICT_NOT_IN_LIST; pages[c].byte_dirty_mask = &byte_dirty_mask[offset * 64]; @@ -2939,10 +2860,14 @@ mem_remap_top(int kb) #endif } - mem_set_mem_state_both(start * 1024, size * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); - mem_mapping_set_exec(&ram_remapped_mapping, ram + (start * 1024)); + mem_set_mem_state_both(start * 1024, size * 1024, set ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : + (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + + if (set) { + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + 0xa0000); + } else + mem_mapping_disable(&ram_remapped_mapping); flushmmucache(); } @@ -2962,9 +2887,11 @@ mem_reset_page_blocks(void) #ifdef USE_NEW_DYNAREC pages[c].block = BLOCK_INVALID; pages[c].block_2 = BLOCK_INVALID; + pages[c].head = BLOCK_INVALID; #else pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL; pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL; + pages[c].head = NULL; #endif } } @@ -2975,7 +2902,7 @@ mem_a20_recalc(void) { int state; - if (! AT) { + if (! is286) { rammask = 0xfffff; flushmmucache(); mem_a20_key = mem_a20_alt = mem_a20_state = 0; @@ -2985,127 +2912,16 @@ mem_a20_recalc(void) state = mem_a20_key | mem_a20_alt; if (state && !mem_a20_state) { - rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; + rammask = (cpu_16bitbus) ? 0xffffff : 0xffffffff; + if (is6117) + rammask |= 0x03000000; flushmmucache(); } else if (!state && mem_a20_state) { - rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; + rammask = (cpu_16bitbus) ? 0xefffff : 0xffefffff; + if (is6117) + rammask |= 0x03000000; flushmmucache(); } mem_a20_state = state; } - - -void -mem_add_mtrr(uint64_t base, uint64_t mask, uint8_t type) -{ - uint64_t size = ((~mask) & 0xffffffff) + 1; - uint64_t page_base, page, addr; - uint8_t *mtrr; - - mem_log("Adding MTRR base=%08llx mask=%08llx size=%08llx type=%d\n", base, mask, size, type); - - if (size > 0x8000) { - mem_log("Ignoring MTRR, size too big\n"); - return; - } - - if (mem_addr_is_ram(base)) { - mem_log("Ignoring MTRR, base is in RAM\n"); - return; - } - - for (page_base = base; page_base < base + size; page_base += MEM_GRANULARITY_SIZE) { - page = (page_base >> MEM_GRANULARITY_BITS); - if (mtrr_areas[page]) { - /* area already allocated, increase refcount and don't allocate it again */ - mtrr_area_refcounts[page]++; - continue; - } - - /* allocate area */ - mtrr = malloc(MEM_GRANULARITY_SIZE); - if (!mtrr) - fatal("Failed to allocate page for MTRR page %08llx (errno=%d)\n", page_base, errno); - - - /* populate area with data from RAM */ - for (addr = 0; addr < MEM_GRANULARITY_SIZE; addr++) { - mtrr[addr] = readmembl(page_base | addr); - } - - /* enable area */ - mtrr_areas[page] = mtrr; - } -} - - -void -mem_del_mtrr(uint64_t base, uint64_t mask) -{ - uint64_t size = ((~mask) & 0xffffffff) + 1; - uint64_t page_base, page; - - mem_log("Deleting MTRR base=%08llx mask=%08llx size=%08llx\n", base, mask, size); - - if (size > 0x8000) { - mem_log("Ignoring MTRR, size too big\n"); - return; - } - - if (mem_addr_is_ram(base)) { - mem_log("Ignoring MTRR, base is in RAM\n"); - return; - } - - for (page_base = base; page_base < base + size; page_base += MEM_GRANULARITY_SIZE) { - page = (page_base >> MEM_GRANULARITY_BITS); - if (mtrr_areas[page]) { - /* decrease reference count */ - if (mtrr_area_refcounts[page] > 0) - mtrr_area_refcounts[page]--; - - /* if no references are left, de-allocate area */ - if (mtrr_area_refcounts[page] == 0) { - free(mtrr_areas[page]); - mtrr_areas[page] = 0; - } - } - } -} - - -void -mem_invalidate_mtrr(uint8_t wb) -{ - uint64_t page, page_base, addr; - uint8_t *mtrr; - - mem_log("Invalidating cache (writeback=%d)\n", wb); - for (page = 0; page < MEM_MAPPINGS_NO; page++) { - mtrr = mtrr_areas[page]; - if (mtrr) { - page_base = (page << MEM_GRANULARITY_BITS); - if (!mem_addr_is_ram(page_base)) - continue; /* don't invalidate pages not backed by RAM (hack?) */ - - /* temporarily set area aside */ - mtrr_areas[page] = 0; - - /* write data back to memory if requested */ - if (wb && write_mapping[page]) { /* don't write back to a page which can't be written to */ - for (addr = 0; addr < MEM_GRANULARITY_SIZE; addr++) { - writemembl(page_base | addr, mtrr[addr]); - } - } - - /* re-populate area with data from memory */ - for (addr = 0; addr < MEM_GRANULARITY_SIZE; addr++) { - mtrr[addr] = readmembl(page_base | addr); - } - - /* re-enable area */ - mtrr_areas[page] = mtrr; - } - } -} diff --git a/src/mem/rom.c b/src/mem/rom.c index d05f69ae5..debdf5c39 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -30,8 +30,10 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/mem.h> #include <86box/rom.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/machine.h> #include <86box/m_xt_xi8088.h> @@ -56,51 +58,102 @@ rom_log(const char *fmt, ...) #define rom_log(fmt, ...) #endif - -FILE * -rom_fopen(wchar_t *fn, wchar_t *mode) +void +rom_add_path(const char* path) { - wchar_t temp[1024]; + char cwd[1024] = { 0 }; - if (wcslen(exe_path) <= 1024) - wcscpy(temp, exe_path); - else - wcsncpy(temp, exe_path, 1024); - plat_put_backslash(temp); - wcscat(temp, fn); + rom_path_t* rom_path = &rom_paths; - return(plat_fopen(temp, mode)); -} + if (rom_paths.path[0] != '\0') + { + // Iterate to the end of the list. + while (rom_path->next != NULL) { + rom_path = rom_path->next; + } - -int -rom_getfile(wchar_t *fn, wchar_t *s, int size) -{ - FILE *f; - - wcscpy(s, exe_path); - plat_put_backslash(s); - wcscat(s, fn); - - f = plat_fopen(s, L"rb"); - if (f != NULL) { - (void)fclose(f); - return(1); + // Allocate the new entry. + rom_path = rom_path->next = calloc(1, sizeof(rom_path_t)); } - return(0); + // Save the path, turning it into absolute if needed. + if (!path_abs((char*) path)) { + plat_getcwd(cwd, sizeof(cwd)); + path_slash(cwd); + snprintf(rom_path->path, sizeof(rom_path->path), "%s%s", cwd, path); + } else { + snprintf(rom_path->path, sizeof(rom_path->path), "%s", path); + } + + // Ensure the path ends with a separator. + path_slash(rom_path->path); +} + + +FILE * +rom_fopen(char *fn, char *mode) +{ + char temp[1024]; + rom_path_t *rom_path; + FILE *fp = NULL; + + if (strstr(fn, "roms/") == fn) { + /* Relative path */ + for (rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { + path_append_filename(temp, rom_path->path, fn + 5); + + if ((fp = plat_fopen(temp, mode)) != NULL) { + return fp; + } + } + + return fp; + } else { + /* Absolute path */ + return plat_fopen(fn, mode); + } } int -rom_present(wchar_t *fn) +rom_getfile(char *fn, char *s, int size) +{ + char temp[1024]; + rom_path_t *rom_path; + + if (strstr(fn, "roms/") == fn) { + /* Relative path */ + for (rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { + path_append_filename(temp, rom_path->path, fn + 5); + + if (rom_present(temp)) { + strncpy(s, temp, size); + return 1; + } + } + + return 0; + } else { + /* Absolute path */ + if (rom_present(fn)) { + strncpy(s, fn, size); + return 1; + } + + return 0; + } +} + + +int +rom_present(char *fn) { FILE *f; - f = rom_fopen(fn, L"rb"); + f = rom_fopen(fn, "rb"); if (f != NULL) { - (void)fclose(f); - return(1); + (void)fclose(f); + return(1); } return(0); @@ -161,14 +214,50 @@ rom_readl(uint32_t addr, void *priv) } +int +rom_load_linear_oddeven(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr) +{ + FILE *f = rom_fopen(fn, "rb"); + int i; + + if (f == NULL) { + rom_log("ROM: image '%s' not found\n", fn); + return(0); + } + + /* Make sure we only look at the base-256K offset. */ + if (addr >= 0x40000) + addr = 0; + else + addr &= 0x03ffff; + + if (ptr != NULL) { + if (fseek(f, off, SEEK_SET) == -1) + fatal("rom_load_linear(): Error seeking to the beginning of the file\n"); + for (i = 0; i < (sz >> 1); i++) { + if (fread(ptr + (addr + (i << 1)), 1, 1, f) != 1) + fatal("rom_load_linear(): Error reading even data\n"); + } + for (i = 0; i < (sz >> 1); i++) { + if (fread(ptr + (addr + (i << 1) + 1), 1, 1, f) != 1) + fatal("rom_load_linear(): Error reading od data\n"); + } + } + + (void)fclose(f); + + return(1); +} + + /* Load a ROM BIOS from its chips, interleaved mode. */ int -rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) +rom_load_linear(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { - FILE *f = rom_fopen(fn, L"rb"); - + FILE *f = rom_fopen(fn, "rb"); + if (f == NULL) { - rom_log("ROM: image '%ls' not found\n", fn); + rom_log("ROM: image '%s' not found\n", fn); return(0); } @@ -193,12 +282,12 @@ rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) /* Load a ROM BIOS from its chips, linear mode with high bit flipped. */ int -rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) +rom_load_linear_inverted(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { - FILE *f = rom_fopen(fn, L"rb"); - + FILE *f = rom_fopen(fn, "rb"); + if (f == NULL) { - rom_log("ROM: image '%ls' not found\n", fn); + rom_log("ROM: image '%s' not found\n", fn); return(0); } @@ -235,16 +324,16 @@ rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *p /* Load a ROM BIOS from its chips, interleaved mode. */ int -rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, uint8_t *ptr) +rom_load_interleaved(char *fnl, char *fnh, uint32_t addr, int sz, int off, uint8_t *ptr) { - FILE *fl = rom_fopen(fnl, L"rb"); - FILE *fh = rom_fopen(fnh, L"rb"); + FILE *fl = rom_fopen(fnl, "rb"); + FILE *fh = rom_fopen(fnh, "rb"); int c; if (fl == NULL || fh == NULL) { - if (fl == NULL) rom_log("ROM: image '%ls' not found\n", fnl); + if (fl == NULL) rom_log("ROM: image '%s' not found\n", fnl); else (void)fclose(fl); - if (fh == NULL) rom_log("ROM: image '%ls' not found\n", fnh); + if (fh == NULL) rom_log("ROM: image '%s' not found\n", fnh); else (void)fclose(fh); return(0); @@ -316,9 +405,103 @@ rom_reset(uint32_t addr, int sz) } +uint8_t +bios_read(uint32_t addr, void *priv) +{ + uint8_t ret = 0xff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = rom[addr - biosaddr]; + + return ret; +} + + +uint16_t +bios_readw(uint32_t addr, void *priv) +{ + uint16_t ret = 0xffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint16_t *)&rom[addr - biosaddr]; + + return ret; +} + + +uint32_t +bios_readl(uint32_t addr, void *priv) +{ + uint32_t ret = 0xffffffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint32_t *)&rom[addr - biosaddr]; + + return ret; +} + + +static void +bios_add(void) +{ + int temp_cpu_type, temp_cpu_16bitbus = 1; + int temp_is286 = 0, temp_is6117 = 0; + + if (/*AT && */cpu_s) { + temp_cpu_type = cpu_s->cpu_type; + temp_cpu_16bitbus = (temp_cpu_type == CPU_286 || temp_cpu_type == CPU_386SX || temp_cpu_type == CPU_486SLC || temp_cpu_type == CPU_IBM386SLC || temp_cpu_type == CPU_IBM486SLC ); + temp_is286 = (temp_cpu_type >= CPU_286); + temp_is6117 = !strcmp(cpu_f->manufacturer, "ALi"); + } + + if (biosmask > 0x1ffff) { + /* 256k+ BIOS'es only have low mappings at E0000-FFFFF. */ + mem_mapping_add(&bios_mapping, 0xe0000, 0x20000, + bios_read,bios_readw,bios_readl, + NULL,NULL,NULL, + &rom[0x20000], MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state_both(0x0e0000, 0x20000, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } else { + mem_mapping_add(&bios_mapping, biosaddr, biosmask + 1, + bios_read,bios_readw,bios_readl, + NULL,NULL,NULL, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state_both(biosaddr, biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } + + if (temp_is6117) { + mem_mapping_add(&bios_high_mapping, biosaddr | 0x03f00000, biosmask + 1, + bios_read,bios_readw,bios_readl, + NULL,NULL,NULL, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state_both(biosaddr | 0x03f00000, biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } else if (temp_is286) { + mem_mapping_add(&bios_high_mapping, biosaddr | (temp_cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + bios_read,bios_readw,bios_readl, + NULL,NULL,NULL, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state_both(biosaddr | (temp_cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } +} + + /* These four are for loading the BIOS. */ int -bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, int off, int flags) +bios_load(char *fn1, char *fn2, uint32_t addr, int sz, int off, int flags) { uint8_t ret = 0; uint8_t *ptr = NULL; @@ -359,14 +542,14 @@ bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, int off, int flags) } if (!bios_only && ret && !(flags & FLAG_AUX)) - mem_add_bios(); + bios_add(); return ret; } int -bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, int sz, int off) +bios_load_linear_combined(char *fn1, char *fn2, int sz, int off) { uint8_t ret = 0; @@ -378,7 +561,7 @@ bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, int sz, int off) int -bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, int sz, int off) +bios_load_linear_combined2(char *fn1, char *fn2, char *fn3, char *fn4, char *fn5, int sz, int off) { uint8_t ret = 0; @@ -386,14 +569,31 @@ bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, wchar_t *fn3, wchar_t *fn ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, off); ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, off); ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, off); - ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, off); + if (fn5 != NULL) + ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, 0); return ret; } int -rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags) +bios_load_linear_combined2_ex(char *fn1, char *fn2, char *fn3, char *fn4, char *fn5, int sz, int off) +{ + uint8_t ret = 0; + + ret = bios_load_linear(fn3, 0x000e0000, 262144, off); + ret &= bios_load_aux_linear(fn1, 0x000c0000, 65536, off); + ret &= bios_load_aux_linear(fn2, 0x000d0000, 65536, off); + ret &= bios_load_aux_linear(fn4, 0x000f0000, sz - 196608, off); + if (fn5 != NULL) + ret &= bios_load_aux_linear(fn5, 0x000fc000, 16384, 0); + + return ret; +} + + +int +rom_init(rom_t *rom, char *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags) { rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags); @@ -415,15 +615,45 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint mem_mapping_add(&rom->mapping, addr, sz, rom_read, rom_readw, rom_readl, - mem_write_null, mem_write_nullw, mem_write_nulll, - rom->rom, flags | MEM_MAPPING_ROM, rom); + NULL, NULL, NULL, + rom->rom, flags | MEM_MAPPING_ROM_WS, rom); return(0); } int -rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags) +rom_init_oddeven(rom_t *rom, char *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags) +{ + rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags); + + /* Allocate a buffer for the image. */ + rom->rom = malloc(sz); + memset(rom->rom, 0xff, sz); + + /* Load the image file into the buffer. */ + if (! rom_load_linear_oddeven(fn, addr, sz, off, rom->rom)) { + /* Nope.. clean up. */ + free(rom->rom); + rom->rom = NULL; + return(-1); + } + + rom->sz = sz; + rom->mask = mask; + + mem_mapping_add(&rom->mapping, + addr, sz, + rom_read, rom_readw, rom_readl, + NULL, NULL, NULL, + rom->rom, flags | MEM_MAPPING_ROM_WS, rom); + + return(0); +} + + +int +rom_init_interleaved(rom_t *rom, char *fnl, char *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags) { /* Allocate a buffer for the image. */ rom->rom = malloc(sz); @@ -443,8 +673,8 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int mem_mapping_add(&rom->mapping, addr, sz, rom_read, rom_readw, rom_readl, - mem_write_null, mem_write_nullw, mem_write_nulll, - rom->rom, flags | MEM_MAPPING_ROM, rom); + NULL, NULL, NULL, + rom->rom, flags | MEM_MAPPING_ROM_WS, rom); return(0); } diff --git a/src/mem/smram.c b/src/mem/smram.c new file mode 100644 index 000000000..9333264d9 --- /dev/null +++ b/src/mem/smram.c @@ -0,0 +1,429 @@ +/* + * 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. + * + * SMRAM handling. + * + * Authors: Miran Grca, + * + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include "x86_ops.h" +#include "x86.h" +#include <86box/config.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/smram.h> + + +static smram_t *base_smram, *last_smram; + +static uint8_t use_separate_smram = 0; +static uint8_t smram[0x40000]; + + +#ifdef ENABLE_SMRAM_LOG +int smram_do_log = ENABLE_SMRAM_LOG; + + +static void +smram_log(const char *fmt, ...) +{ + va_list ap; + + if (smram_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define smram_log(fmt, ...) +#endif + + +static uint8_t +smram_read(uint32_t addr, void *priv) +{ + smram_t *dev = (smram_t *) priv; + uint32_t new_addr = addr - dev->host_base + dev->ram_base; + + if (new_addr >= (1 << 30)) + return mem_read_ram_2gb(new_addr, priv); + else if (!use_separate_smram || (new_addr >= 0xa0000)) + return mem_read_ram(new_addr, priv); + else + return dev->mapping.exec[addr - dev->host_base]; +} + + +static uint16_t +smram_readw(uint32_t addr, void *priv) +{ + smram_t *dev = (smram_t *) priv; + uint32_t new_addr = addr - dev->host_base + dev->ram_base; + + if (new_addr >= (1 << 30)) + return mem_read_ram_2gbw(new_addr, priv); + else if (!use_separate_smram || (new_addr >= 0xa0000)) + return mem_read_ramw(new_addr, priv); + else + return *(uint16_t *) &(dev->mapping.exec[addr - dev->host_base]); +} + + +static uint32_t +smram_readl(uint32_t addr, void *priv) +{ + smram_t *dev = (smram_t *) priv; + uint32_t new_addr = addr - dev->host_base + dev->ram_base; + + if (new_addr >= (1 << 30)) + return mem_read_ram_2gbl(new_addr, priv); + else if (!use_separate_smram || (new_addr >= 0xa0000)) + return mem_read_raml(new_addr, priv); + else + return *(uint32_t *) &(dev->mapping.exec[addr - dev->host_base]); +} + + +static void +smram_write(uint32_t addr, uint8_t val, void *priv) +{ + smram_t *dev = (smram_t *) priv; + uint32_t new_addr = addr - dev->host_base + dev->ram_base; + + if (!use_separate_smram || (new_addr >= 0xa0000)) + mem_write_ram(new_addr, val, priv); + else + dev->mapping.exec[addr - dev->host_base] = val; +} + + +static void +smram_writew(uint32_t addr, uint16_t val, void *priv) +{ + smram_t *dev = (smram_t *) priv; + uint32_t new_addr = addr - dev->host_base + dev->ram_base; + + if (!use_separate_smram || (new_addr >= 0xa0000)) + mem_write_ramw(new_addr, val, priv); + else + *(uint16_t *) &(dev->mapping.exec[addr - dev->host_base]) = val; +} + + +static void +smram_writel(uint32_t addr, uint32_t val, void *priv) +{ + smram_t *dev = (smram_t *) priv; + uint32_t new_addr = addr - dev->host_base + dev->ram_base; + + if (!use_separate_smram || (new_addr >= 0xa0000)) + mem_write_raml(new_addr, val, priv); + else + *(uint32_t *) &(dev->mapping.exec[addr - dev->host_base]) = val; +} + + +/* Make a backup copy of host_base and size of all the SMRAM structs, needed so that if + the SMRAM mappings change while in SMM, they will be recalculated on return. */ +void +smram_backup_all(void) +{ + smram_t *temp_smram = base_smram, *next; + + while (temp_smram != NULL) { + temp_smram->old_host_base = temp_smram->host_base; + temp_smram->old_size = temp_smram->size; + + next = temp_smram->next; + temp_smram = next; + } +} + + +/* Recalculate any mappings, including the backup if returning from SMM. */ +void +smram_recalc_all(int ret) +{ + smram_t *temp_smram = base_smram, *next; + + if (base_smram == NULL) + return; + + if (ret) { + while (temp_smram != NULL) { + if (temp_smram->old_size != 0x00000000) + mem_mapping_recalc(temp_smram->old_host_base, temp_smram->old_size); + temp_smram->old_host_base = temp_smram->old_size = 0x00000000; + + next = temp_smram->next; + temp_smram = next; + } + } + + temp_smram = base_smram; + + while (temp_smram != NULL) { + if (temp_smram->size != 0x00000000) + mem_mapping_recalc(temp_smram->host_base, temp_smram->size); + + next = temp_smram->next; + temp_smram = next; + } + + flushmmucache(); +} + + +/* Delete a SMRAM mapping. */ +void +smram_del(smram_t *smr) +{ + /* Do a sanity check */ + if ((base_smram == NULL) && (last_smram != NULL)) { + fatal("smram_del(): NULL base SMRAM with non-NULL last SMRAM\n"); + return; + } else if ((base_smram != NULL) && (last_smram == NULL)) { + fatal("smram_del(): Non-NULL base SMRAM with NULL last SMRAM\n"); + return; + } else if ((base_smram != NULL) && (base_smram->prev != NULL)) { + fatal("smram_del(): Base SMRAM with a preceding SMRAM\n"); + return; + } else if ((last_smram != NULL) && (last_smram->next != NULL)) { + fatal("smram_del(): Last SMRAM with a following SMRAM\n"); + return; + } + + if (smr == NULL) { + fatal("smram_del(): Invalid SMRAM mapping\n"); + return; + } + + /* Disable the entry. */ + smram_disable(smr); + + /* Zap it from the list. */ + if (smr->prev != NULL) + smr->prev->next = smr->next; + if (smr->next != NULL) + smr->next->prev = smr->prev; + + /* Check if it's the first or the last mapping. */ + if (base_smram == smr) + base_smram = smr->next; + if (last_smram == smr) + last_smram = smr->prev; + + free(smr); +} + + +/* Add a SMRAM mapping. */ +smram_t * +smram_add(void) +{ + smram_t *temp_smram; + + /* Do a sanity check */ + if ((base_smram == NULL) && (last_smram != NULL)) { + fatal("smram_add(): NULL base SMRAM with non-NULL last SMRAM\n"); + return NULL; + } else if ((base_smram != NULL) && (last_smram == NULL)) { + fatal("smram_add(): Non-NULL base SMRAM with NULL last SMRAM\n"); + return NULL; + } else if ((base_smram != NULL) && (base_smram->prev != NULL)) { + fatal("smram_add(): Base SMRAM with a preceding SMRAM\n"); + return NULL; + } else if ((last_smram != NULL) && (last_smram->next != NULL)) { + fatal("smram_add(): Last SMRAM with a following SMRAM\n"); + return NULL; + } + + temp_smram = (smram_t *) malloc(sizeof(smram_t)); + if (temp_smram == NULL) { + fatal("smram_add(): temp_smram malloc failed\n"); + return NULL; + } + memset(temp_smram, 0x00, sizeof(smram_t)); + memset(&(temp_smram->mapping), 0x00, sizeof(mem_mapping_t)); + + /* Add struct to the beginning of the list if necessary.*/ + if (base_smram == NULL) + base_smram = temp_smram; + + /* Add struct to the end of the list.*/ + if (last_smram == NULL) + temp_smram->prev = NULL; + else { + temp_smram->prev = last_smram; + last_smram->next = temp_smram; + } + last_smram = temp_smram; + + mem_mapping_add(&(temp_smram->mapping), 0x00000000, 0x00000000, + smram_read,smram_readw,smram_readl, + smram_write,smram_writew,smram_writel, + ram, MEM_MAPPING_SMRAM, temp_smram); + + smram_set_separate_smram(0); + + return temp_smram; +} + + +/* Set memory state in the specified model (normal or SMM) according to the specified flags, + separately for bus and CPU. */ +void +smram_map_ex(int bus, int smm, uint32_t addr, uint32_t size, int is_smram) +{ + if (bus) + mem_set_access_smram_bus(smm, addr, size, is_smram); + else + mem_set_access_smram_cpu(smm, addr, size, is_smram); +} + + +/* Set memory state in the specified model (normal or SMM) according to the specified flags. */ +void +smram_map(int smm, uint32_t addr, uint32_t size, int is_smram) +{ + smram_map_ex(0, smm, addr, size, is_smram); + smram_map_ex(1, smm, addr, size, is_smram); +} + + +/* Disable a specific SMRAM mapping. */ +void +smram_disable(smram_t *smr) +{ + if (smr == NULL) { + fatal("smram_disable(): Invalid SMRAM mapping\n"); + return; + } + + if (smr->size != 0x00000000) { + smram_map(0, smr->host_base, smr->size, 0); + smram_map(1, smr->host_base, smr->size, 0); + + smr->host_base = smr->ram_base = 0x00000000; + smr->size = 0x00000000; + + mem_mapping_disable(&(smr->mapping)); + } +} + + +/* Disable all SMRAM mappings. */ +void +smram_disable_all(void) +{ + smram_t *temp_smram = base_smram, *next; + + while (temp_smram != NULL) { + smram_disable(temp_smram); + + next = temp_smram->next; + temp_smram = next; + } +} + + +/* Enable SMRAM mappings according to flags for both normal and SMM modes, separately for bus + and CPU. */ +void +smram_enable_ex(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, + int flags_normal, int flags_normal_bus, int flags_smm, int flags_smm_bus) +{ + if (smr == NULL) { + fatal("smram_add(): Invalid SMRAM mapping\n"); + return; + } + + if ((size != 0x00000000) && (flags_normal || flags_smm)) { + smr->host_base = host_base; + smr->ram_base = ram_base, + smr->size = size; + + mem_mapping_set_addr(&(smr->mapping), smr->host_base, smr->size); + if (!use_separate_smram || (smr->ram_base >= 0x000a0000)) { + if (smr->ram_base < (1 << 30)) + mem_mapping_set_exec(&(smr->mapping), ram + smr->ram_base); + else + mem_mapping_set_exec(&(smr->mapping), ram2 + smr->ram_base - (1 << 30)); + } else { + if (smr->ram_base == 0x00030000) + mem_mapping_set_exec(&(smr->mapping), smram); + else if (smr->ram_base == 0x00040000) + mem_mapping_set_exec(&(smr->mapping), smram + 0x10000); + else if (smr->ram_base == 0x00060000) + mem_mapping_set_exec(&(smr->mapping), smram + 0x20000); + else if (smr->ram_base == 0x00070000) + mem_mapping_set_exec(&(smr->mapping), smram + 0x30000); + } + + smram_map_ex(0, 0, host_base, size, flags_normal); + smram_map_ex(1, 0, host_base, size, flags_normal_bus); + smram_map_ex(0, 1, host_base, size, flags_smm); + smram_map_ex(1, 1, host_base, size, flags_smm_bus); + } else + smram_disable(smr); +} + + +/* Enable SMRAM mappings according to flags for both normal and SMM modes. */ +void +smram_enable(smram_t *smr, uint32_t host_base, uint32_t ram_base, uint32_t size, int flags_normal, int flags_smm) +{ + smram_enable_ex(smr, host_base, ram_base, size, flags_normal, flags_normal, flags_smm, flags_smm); +} + + +/* Checks if a SMRAM mapping is enabled or not. */ +int +smram_enabled(smram_t *smr) +{ + int ret = 0; + + if (smr == NULL) + ret = 0; + else + ret = (smr->size != 0x00000000); + + return ret; +} + + +/* Changes the SMRAM state. */ +void +smram_state_change(smram_t *smr, int smm, int flags) +{ + if (smr == NULL) { + fatal("smram_tate_change(): Invalid SMRAM mapping\n"); + return; + } + + smram_map(smm, smr->host_base, smr->size, flags); +} + + +void +smram_set_separate_smram(uint8_t set) +{ + use_separate_smram = set; +} diff --git a/src/mem/spd.c b/src/mem/spd.c index 84ba3eb84..acc7ced9f 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -23,21 +23,19 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/spd.h> +#include <86box/version.h> +#include <86box/machine.h> -#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define SPD_ROLLUP(x) ((x) >= 16 ? ((x) - 15) : (x)) -spd_t *spd_devices[SPD_MAX_SLOTS]; -uint8_t spd_data[SPD_MAX_SLOTS][SPD_DATA_SIZE]; +int spd_present = 0; +spd_t *spd_modules[SPD_MAX_SLOTS]; - -static uint8_t spd_read_byte(uint8_t addr, void *priv); -static uint8_t spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static void spd_write_byte(uint8_t addr, uint8_t val, void *priv); +static const device_t spd_device; #ifdef ENABLE_SPD_LOG @@ -50,9 +48,9 @@ spd_log(const char *fmt, ...) va_list ap; if (spd_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else @@ -60,89 +58,33 @@ spd_log(const char *fmt, ...) #endif -uint8_t -spd_read_byte(uint8_t addr, void *priv) -{ - spd_t *dev = (spd_t *) priv; - return spd_read_byte_cmd(addr, dev->addr_register, priv); -} - - -uint8_t -spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) -{ - spd_t *dev = (spd_t *) priv; - uint8_t ret = *(spd_data[dev->slot] + cmd); - spd_log("SPD: read(%02X, %02X) = %02X\n", addr, cmd, ret); - return ret; -} - - -uint16_t -spd_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) -{ - return (spd_read_byte_cmd(addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(addr, cmd, priv); -} - - -uint8_t -spd_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) -{ - uint8_t read = 0; - for (uint8_t i = cmd; i < len && i < SPD_DATA_SIZE; i++) { - data[read++] = spd_read_byte_cmd(addr, i, priv); - } - return read; -} - - -void -spd_write_byte(uint8_t addr, uint8_t val, void *priv) -{ - spd_t *dev = (spd_t *) priv; - dev->addr_register = val; -} - - static void spd_close(void *priv) { - spd_t *dev = (spd_t *) priv; + spd_log("SPD: close()\n"); - spd_log("SPD: closing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot); + for (uint8_t i = 0; i < SPD_MAX_SLOTS; i++) { + if (spd_modules[i]) + i2c_eeprom_close(spd_modules[i]->eeprom); + } - smbus_removehandler(SPD_BASE_ADDR + dev->slot, 1, - spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, - spd_write_byte, NULL, NULL, NULL, - dev); - - free(dev); + spd_present = 0; } static void * spd_init(const device_t *info) { - spd_t *dev = spd_devices[info->local]; + spd_log("SPD: init()\n"); - spd_log("SPD: initializing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot); + for (uint8_t i = 0; i < SPD_MAX_SLOTS; i++) { + if (spd_modules[i]) + spd_modules[i]->eeprom = i2c_eeprom_init(i2c_smbus, SPD_BASE_ADDR + i, spd_modules[i]->data, sizeof(spd_modules[i]->data), 0); + } - smbus_sethandler(SPD_BASE_ADDR + dev->slot, 1, - spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, - spd_write_byte, NULL, NULL, NULL, - dev); + spd_present = 1; - return dev; -} - - -uint8_t -log2_ui16(uint16_t i) -{ - uint8_t ret = 0; - while ((i >>= 1)) - ret++; - return ret; + return &spd_modules; } @@ -155,229 +97,496 @@ comp_ui16_rev(const void *elem1, const void *elem2) } +void +spd_populate(uint16_t *rows, uint8_t slot_count, uint16_t total_size, uint16_t min_module_size, uint16_t max_module_size, uint8_t enable_asym) +{ + uint8_t row, next_empty_row, split, i; + uint16_t asym; + + /* Populate rows with modules in power-of-2 capacities. */ + memset(rows, 0, SPD_MAX_SLOTS << 1); + for (row = 0; row < slot_count && total_size; row++) { + /* populate slot */ + rows[row] = 1 << log2i(MIN(total_size, max_module_size)); + if (total_size >= rows[row]) { + spd_log("SPD: Initial row %d = %d MB\n", row, rows[row]); + total_size -= rows[row]; + } else { + rows[row] = 0; + break; + } + } + + /* Did we populate all the RAM? */ + if (total_size) { + /* Work backwards to add the missing RAM as asymmetric modules if possible. */ + if (enable_asym) { + row = slot_count - 1; + do { + asym = (1 << log2i(MIN(total_size, rows[row]))); + if (rows[row] + asym <= max_module_size) { + rows[row] += asym; + total_size -= asym; + } + } while ((row-- > 0) && total_size); + } + + if (total_size) /* still not enough */ + spd_log("SPD: Not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size); + } + + /* Populate empty rows by splitting modules... */ + split = (total_size == 0); /* ...if possible. */ + while (split) { + /* Look for a module to split. */ + split = 0; + for (row = 0; row < slot_count; row++) { + if ((rows[row] < (min_module_size << 1)) || (rows[row] != (1 << log2i(rows[row])))) + continue; /* no module here, module is too small to be split, or asymmetric module */ + + /* Find next empty row. */ + next_empty_row = 0; + for (i = row + 1; i < slot_count && !next_empty_row; i++) { + if (!rows[i]) + next_empty_row = i; + } + if (!next_empty_row) + break; /* no empty rows left */ + + /* Split the module into its own row and the next empty row. */ + spd_log("SPD: splitting row %d (%d MB) into %d and %d (%d MB each)\n", row, rows[row], row, next_empty_row, rows[row] >> 1); + rows[row] = rows[next_empty_row] = rows[row] >> 1; + split = 1; + break; + } + + /* Sort rows by descending capacity if any were split. */ + if (split) + qsort(rows, slot_count, sizeof(uint16_t), comp_ui16_rev); + } +} + + +static int +spd_write_part_no(char *part_no, char *type, uint16_t size) +{ + char size_unit; + + if (size >= 1024) { + size_unit = 'G'; + size >>= 10; + } else { + size_unit = 'M'; + } + + return sprintf(part_no, EMU_NAME "-%s-%03d%c", type, size, size_unit); +} + + void spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) { - uint8_t slot, slot_count, vslot, next_empty_vslot, i, split; - uint16_t min_module_size, total_size, vslots[SPD_MAX_SLOTS], asym; - device_t *info; + uint8_t slot, slot_count, row, i; + uint16_t min_module_size, rows[SPD_MAX_SLOTS], asym; spd_edo_t *edo_data; spd_sdram_t *sdram_data; - /* determine the minimum module size for this RAM type */ + /* Determine the minimum module size for this RAM type. */ switch (ram_type) { - case SPD_TYPE_FPM: - case SPD_TYPE_EDO: - min_module_size = SPD_MIN_SIZE_EDO; - break; + case SPD_TYPE_FPM: + case SPD_TYPE_EDO: + min_module_size = SPD_MIN_SIZE_EDO; + break; - case SPD_TYPE_SDRAM: - min_module_size = SPD_MIN_SIZE_SDRAM; - break; + case SPD_TYPE_SDRAM: + min_module_size = SPD_MIN_SIZE_SDRAM; + break; default: - spd_log("SPD: unknown RAM type 0x%02X\n", ram_type); - return; + spd_log("SPD: unknown RAM type %02X\n", ram_type); + return; } - /* count how many (real) slots are enabled */ + /* Count how many slots are enabled. */ slot_count = 0; for (slot = 0; slot < SPD_MAX_SLOTS; slot++) { - vslots[slot] = 0; - if (slot_mask & (1 << slot)) { - slot_count++; - } + rows[slot] = 0; + if (slot_mask & (1 << slot)) + slot_count++; } - /* populate vslots with modules in power-of-2 capacities */ - total_size = (mem_size >> 10); - for (vslot = 0; vslot < slot_count && total_size; vslot++) { - /* populate slot */ - vslots[vslot] = (1 << log2_ui16(MIN(total_size, max_module_size))); - if (total_size >= vslots[vslot]) { - spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]); - total_size -= vslots[vslot]; - } else { - vslots[vslot] = 0; - break; - } + /* Populate rows. */ + spd_populate(rows, slot_count, (mem_size >> 10), min_module_size, max_module_size, 1); + + /* Register SPD devices and populate their data according to the rows. */ + row = 0; + for (slot = 0; (slot < SPD_MAX_SLOTS) && rows[row]; slot++) { + if (!(slot_mask & (1 << slot))) + continue; /* slot disabled */ + + spd_modules[slot] = (spd_t *) malloc(sizeof(spd_t)); + memset(spd_modules[slot], 0, sizeof(spd_t)); + spd_modules[slot]->slot = slot; + spd_modules[slot]->size = rows[row]; + + /* Determine the second row size, from which the first row size can be obtained. */ + asym = rows[row] - (1 << log2i(rows[row])); /* separate the powers of 2 */ + if (!asym) /* is the module asymmetric? */ + asym = rows[row] >> 1; /* symmetric, therefore divide by 2 */ + + spd_modules[slot]->row1 = rows[row] - asym; + spd_modules[slot]->row2 = asym; + + spd_log("SPD: Registering slot %d = row %d = %d MB (%d/%d)\n", slot, row, rows[row], spd_modules[slot]->row1, spd_modules[slot]->row2); + + switch (ram_type) { + case SPD_TYPE_FPM: + case SPD_TYPE_EDO: + edo_data = &spd_modules[slot]->edo_data; + + /* EDO SPD is specified by JEDEC and present in some modules, but + most utilities cannot interpret it correctly. SIV32 at least gets + the module capacities right, so it was used as a reference here. */ + edo_data->bytes_used = 0x80; + edo_data->spd_size = 0x08; + edo_data->mem_type = ram_type; + edo_data->row_bits = SPD_ROLLUP(7 + log2i(spd_modules[slot]->row1)); /* first row */ + edo_data->col_bits = 9; + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + edo_data->row_bits |= SPD_ROLLUP(7 + log2i(spd_modules[slot]->row2)) << 4; /* second row, if different from first */ + edo_data->col_bits |= 9 << 4; /* same as first row, but just in case */ + } + edo_data->banks = 2; + edo_data->data_width_lsb = 64; + edo_data->signal_level = SPD_SIGNAL_LVTTL; + edo_data->trac = 50; + edo_data->tcac = 13; + edo_data->refresh_rate = SPD_REFRESH_NORMAL; + edo_data->dram_width = 8; + + edo_data->spd_rev = 0x12; + for (i = spd_write_part_no(edo_data->part_no, (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", rows[row]); + i < sizeof(edo_data->part_no); i++) + edo_data->part_no[i] = ' '; /* part number should be space-padded */ + edo_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); + edo_data->rev_code[1] = BCD8(EMU_VERSION_MIN); + edo_data->mfg_year = 20; + edo_data->mfg_week = 17; + + for (i = 0; i < 63; i++) + edo_data->checksum += spd_modules[slot]->data[i]; + for (i = 0; i < 129; i++) + edo_data->checksum2 += spd_modules[slot]->data[i]; + break; + + case SPD_TYPE_SDRAM: + sdram_data = &spd_modules[slot]->sdram_data; + + sdram_data->bytes_used = 0x80; + sdram_data->spd_size = 0x08; + sdram_data->mem_type = ram_type; + sdram_data->row_bits = SPD_ROLLUP(6 + log2i(spd_modules[slot]->row1)); /* first row */ + sdram_data->col_bits = 9; + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + sdram_data->row_bits |= SPD_ROLLUP(6 + log2i(spd_modules[slot]->row2)) << 4; /* second row, if different from first */ + sdram_data->col_bits |= 9 << 4; /* same as first row, but just in case */ + } + sdram_data->rows = 2; + sdram_data->data_width_lsb = 64; + sdram_data->signal_level = SPD_SIGNAL_LVTTL; + sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */ + sdram_data->tac = 0x10; + sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL; + sdram_data->sdram_width = 8; + sdram_data->tccd = 1; + sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8; + sdram_data->banks = 4; + sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */ + sdram_data->cslat = sdram_data->we = 0x7f; + sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST; + sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */ + sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */ + sdram_data->tac2 = sdram_data->tac3 = 0x10; + sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1; + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { + /* Utilities interpret bank_density a bit differently on asymmetric modules. */ + sdram_data->bank_density = 1 << (log2i(spd_modules[slot]->row1 >> 1) - 2); /* first row */ + sdram_data->bank_density |= 1 << (log2i(spd_modules[slot]->row2 >> 1) - 2); /* second row */ + } else { + sdram_data->bank_density = 1 << (log2i(spd_modules[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */ + } + sdram_data->ca_setup = sdram_data->data_setup = 0x15; + sdram_data->ca_hold = sdram_data->data_hold = 0x08; + + sdram_data->spd_rev = 0x12; + for (i = spd_write_part_no(sdram_data->part_no, "SDR", rows[row]); + i < sizeof(sdram_data->part_no); i++) + sdram_data->part_no[i] = ' '; /* part number should be space-padded */ + sdram_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); + sdram_data->rev_code[1] = BCD8(EMU_VERSION_MIN); + sdram_data->mfg_year = 20; + sdram_data->mfg_week = 13; + + sdram_data->freq = 100; + sdram_data->features = 0xFF; + + for (i = 0; i < 63; i++) + sdram_data->checksum += spd_modules[slot]->data[i]; + for (i = 0; i < 129; i++) + sdram_data->checksum2 += spd_modules[slot]->data[i]; + break; + } + + row++; } - /* did we populate all the RAM? */ - if (total_size) { - /* work backwards to add the missing RAM as asymmetric modules */ - vslot = slot_count - 1; - do { - asym = (1 << log2_ui16(MIN(total_size, vslots[vslot]))); - if (vslots[vslot] + asym <= max_module_size) { - vslots[vslot] += asym; - total_size -= asym; - } - } while (vslot-- > 0 && total_size); + device_add(&spd_device); +} - if (total_size) /* still not enough */ - spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size); + +void +spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) +{ + uint8_t row, dimm, drb, apollo = 0; + uint16_t size, rows[SPD_MAX_SLOTS]; + + /* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */ + if (reg_max < reg_min) { + apollo = reg_max; + reg_max = reg_min + 7; } - /* populate empty vslots by splitting modules... */ - split = (total_size == 0); /* ...if possible */ - while (split) { - /* look for a module to split */ - split = 0; - for (vslot = 0; vslot < slot_count; vslot++) { - if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot])))) - continue; /* no module here, module is too small to be split, or asymmetric module */ - - /* find next empty vslot */ - next_empty_vslot = 0; - for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) { - if (!vslots[i]) - next_empty_vslot = i; - } - if (!next_empty_vslot) - break; /* no empty vslots left */ - - /* split the module into its own vslot and the next empty vslot */ - spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, (vslots[vslot] >> 1)); - vslots[vslot] = vslots[next_empty_vslot] = (vslots[vslot] >> 1); - split = 1; - } - - /* re-sort vslots by descending capacity if any modules were split */ - if (split) - qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev); + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, drb_unit, 1 << (log2i((machines[machine].ram.max >> 10) / dimm)), 0); } - /* register SPD devices and populate their data according to the vslots */ - vslot = 0; - for (slot = 0; slot < SPD_MAX_SLOTS && vslots[vslot]; slot++) { - if (!(slot_mask & (1 << slot))) - continue; /* slot disabled */ + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (row = 0; row <= (reg_max - reg_min); row++) { + dimm = (row >> 1); + size = 0; - info = (device_t *) malloc(sizeof(device_t)); - memset(info, 0, sizeof(device_t)); - info->name = "Serial Presence Detect ROM"; - info->local = slot; - info->init = spd_init; - info->close = spd_close; + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + if (spd_modules[dimm]) { + if (spd_modules[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + size = (row & 1) ? 0 : drb_unit; + else + size = (row & 1) ? spd_modules[dimm]->row2 : spd_modules[dimm]->row1; + } + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } - spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t)); - memset(spd_devices[slot], 0, sizeof(spd_t)); - spd_devices[slot]->info = info; - spd_devices[slot]->slot = slot; - spd_devices[slot]->size = vslots[vslot]; + /* Determine the DRB register to write. */ + drb = reg_min + row; + if (apollo && ((drb & 0xf) < 0xa)) + drb = apollo + (drb & 0xf); - /* determine the second row size, from which the first row size can be obtained */ - asym = (vslots[vslot] - (1 << log2_ui16(vslots[vslot]))); /* separate the powers of 2 */ - if (!asym) /* is the module asymmetric? */ - asym = (vslots[vslot] >> 1); /* symmetric, therefore divide by 2 */ - - spd_devices[slot]->row1 = (vslots[vslot] - asym); - spd_devices[slot]->row2 = asym; - - spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2); - - switch (ram_type) { - case SPD_TYPE_FPM: - case SPD_TYPE_EDO: - edo_data = (spd_edo_t *) &spd_data[slot]; - memset(edo_data, 0, sizeof(spd_edo_t)); - - /* EDO SPD is specified by JEDEC and present in some modules, but - most utilities cannot interpret it correctly. SIV32 at least gets - the module capacities right, so it was used as a reference here. */ - edo_data->bytes_used = 0x80; - edo_data->spd_size = 0x08; - edo_data->mem_type = ram_type; - edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */ - edo_data->col_bits = 9; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ - edo_data->row_bits |= (SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */ - edo_data->col_bits |= (9 << 4); /* same as first row, but just in case */ - } - edo_data->banks = 2; - edo_data->data_width_lsb = 64; - edo_data->signal_level = SPD_SIGNAL_LVTTL; - edo_data->trac = 50; - edo_data->tcac = 13; - edo_data->refresh_rate = SPD_REFRESH_NORMAL; - edo_data->dram_width = 8; - - edo_data->spd_rev = 0x12; - sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]); - for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++) - edo_data->part_no[i] = ' '; /* part number should be space-padded */ - edo_data->rev_code[0] = EMU_VERSION_MAJ; - edo_data->rev_code[1] = (((EMU_VERSION_MIN / 10) << 4) | (EMU_VERSION_MIN % 10)); - edo_data->mfg_year = 20; - edo_data->mfg_week = 17; - - for (i = 0; i < 63; i++) - edo_data->checksum += spd_data[slot][i]; - for (i = 0; i < 129; i++) - edo_data->checksum2 += spd_data[slot][i]; - break; - - case SPD_TYPE_SDRAM: - sdram_data = (spd_sdram_t *) &spd_data[slot]; - memset(sdram_data, 0, sizeof(spd_sdram_t)); - - sdram_data->bytes_used = 0x80; - sdram_data->spd_size = 0x08; - sdram_data->mem_type = ram_type; - sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */ - sdram_data->col_bits = 9; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ - sdram_data->row_bits |= (SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */ - sdram_data->col_bits |= (9 << 4); /* same as first row, but just in case */ - } - sdram_data->rows = 2; - sdram_data->data_width_lsb = 64; - sdram_data->signal_level = SPD_SIGNAL_LVTTL; - sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */ - sdram_data->tac = 0x10; - sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL; - sdram_data->sdram_width = 8; - sdram_data->tccd = 1; - sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8; - sdram_data->banks = 4; - sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */ - sdram_data->cslat = sdram_data->we = 0x7f; - sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST; - sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */ - sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */ - sdram_data->tac2 = sdram_data->tac3 = 0x10; - sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { - /* Utilities interpret bank_density a bit differently on asymmetric modules. */ - sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2)); /* first row */ - sdram_data->bank_density |= (1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2)); /* second row */ - } else { - sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1)); /* symmetric module = only one bit is set */ - } - sdram_data->ca_setup = sdram_data->data_setup = 0x15; - sdram_data->ca_hold = sdram_data->data_hold = 0x08; - - sdram_data->spd_rev = 0x12; - sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]); - for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++) - sdram_data->part_no[i] = ' '; /* part number should be space-padded */ - sdram_data->rev_code[0] = EMU_VERSION_MAJ; - sdram_data->rev_code[1] = (((EMU_VERSION_MIN / 10) << 4) | (EMU_VERSION_MIN % 10)); - sdram_data->mfg_year = 20; - sdram_data->mfg_week = 13; - - sdram_data->freq = 100; - sdram_data->features = 0xFF; - - for (i = 0; i < 63; i++) - sdram_data->checksum += spd_data[slot][i]; - for (i = 0; i < 129; i++) - sdram_data->checksum2 += spd_data[slot][i]; - break; - } - - device_add(info); - vslot++; + /* Write DRB register, adding the previous DRB's value. */ + if (row == 0) + regs[drb] = 0; + else if ((apollo) && (drb == apollo)) + regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */ + else + regs[drb] = regs[drb - 1]; + if (size) + regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); } } + + +/* Needed for 430LX. */ +void +spd_write_drbs_with_ext(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) +{ + uint8_t row, dimm, drb; + uint16_t size, row_val = 0, rows[SPD_MAX_SLOTS]; + int shift; + + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, drb_unit, 1 << (log2i((machines[machine].ram.max >> 10) / dimm)), 0); + } + + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (row = 0; row <= (reg_max - reg_min); row++) { + dimm = (row >> 1); + size = 0; + + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + if (spd_modules[dimm]) { + if (spd_modules[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + size = (row & 1) ? 0 : drb_unit; + else + size = (row & 1) ? spd_modules[dimm]->row2 : spd_modules[dimm]->row1; + } + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } + + /* Determine the DRB register to write. */ + drb = reg_min + row; + + /* Write DRB register, adding the previous DRB's value. */ + if (row == 0) + row_val = 0; + if (size) + row_val += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ + regs[drb] = row_val & 0xff; + drb = reg_min + 8 + (row >> 1); + shift = (row & 0x01) << 3; + regs[drb] = (((row_val & 0xfff) >> 8) << shift); + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); + } +} + + +/* Used by ALi M1531 and M1541/2. */ +void +spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) +{ + uint8_t row, dimm; + uint8_t drb; + uint16_t size, size_acc = 0; + uint16_t rows[SPD_MAX_SLOTS]; + + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 2; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, drb_unit, 1 << (log2i((machines[machine].ram.max >> 10) / dimm)), 0); + } + + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (row = 0; row <= (reg_max - reg_min); row += 2) { + dimm = (row >> 2); + size = 0; + + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + if (spd_modules[dimm]) { + if (spd_modules[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + size = ((row >> 1) & 1) ? 0 : drb_unit; + else + size = ((row >> 1) & 1) ? spd_modules[dimm]->row2 : spd_modules[dimm]->row1; + } + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } + + /* Determine the DRB register to write. */ + drb = reg_min + row; + + /* Calculate previous and new size. */ + if (row == 0) + size_acc = 0; + else + size_acc += (size / drb_unit); + + /* Write DRB register, adding the previous DRB's value. */ + regs[drb] = size_acc & 0xff; + regs[drb + 1] = (regs[drb + 1] & 0xf0) | ((size_acc >> 8) & 0x0f); + + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row >> 1, size, regs[drb]); + } +} + + +/* This is needed because the ALi M1621 does this stuff completely differently, + as it has DRAM bank registers instead of DRAM row boundary registers. */ +void +spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max) +{ + uint8_t dimm, drb; + uint16_t size; + uint16_t rows[SPD_MAX_SLOTS]; + + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 2; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, 4, 1 << (log2i((machines[machine].ram.max >> 10) / dimm)), 0); + } + + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (dimm = 0; dimm <= ((reg_max - reg_min) >> 2); dimm++) { + size = 0; + drb = reg_min + (dimm << 2); + + regs[drb] = 0xff; + regs[drb + 1] = 0xff; + regs[drb + 2] = 0x00; + regs[drb + 3] = 0xf0; + + if (spd_modules[dimm] == NULL) + continue; + + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + size = (spd_modules[dimm]->row1 + spd_modules[dimm]->row2) >> 1; + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } + + if (spd_modules[dimm]->row1) + regs[drb + 3] |= 0x06; + + switch (size) { + case 4: + default: + regs[drb + 2] = 0x00; + break; + case 8: + regs[drb + 2] = 0x10; + break; + case 16: + regs[drb + 2] = 0x20; + break; + case 32: + regs[drb + 2] = 0x30; + break; + case 64: + regs[drb + 2] = 0x40; + break; + case 128: + regs[drb + 2] = 0x50; + break; + case 256: + regs[drb + 2] = 0x60; + break; + } + + if (spd_modules[dimm]->row2) { + regs[drb + 3] |= 0x01; + regs[drb + 2] |= 0x80; + } + + spd_log("SPD: DIMM %i: %02X %02X %02X %02X\n", regs[drb], regs[drb + 1], regs[drb + 2], regs[drb + 3]); + } +} + + +static const device_t spd_device = { + .name = "Serial Presence Detect ROMs", + .internal_name = "spd", + .flags = DEVICE_ISA, + .local = 0, + .init = spd_init, + .close = spd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index 6acd4440b..9aa0d4345 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -30,19 +30,23 @@ #include <86box/timer.h> #include <86box/nvr.h> #include <86box/plat.h> +#include <86box/m_xt_xi8088.h> typedef struct sst_t { - uint8_t id, is_39, page_bytes, sdp; + uint8_t manufacturer, id, has_bbp, is_39, + page_bytes, sdp, bbp_first_8k, bbp_last_8k; int command_state, id_mode, dirty; uint32_t size, mask, - page_mask, page_base; - - uint8_t page_buffer[128]; + page_mask, page_base, + last_addr; + + uint8_t page_buffer[128], + page_dirty[128]; uint8_t *array; mem_mapping_t mapping[8], mapping_h[8]; @@ -51,12 +55,13 @@ typedef struct sst_t } sst_t; -static wchar_t flash_path[1024]; +static char flash_path[1024]; #define SST_CHIP_ERASE 0x10 /* Both 29 and 39, 6th cycle */ #define SST_SDP_DISABLE 0x20 /* Only 29, Software data protect disable and write - treat as write */ #define SST_SECTOR_ERASE 0x30 /* Only 39, 6th cycle */ +#define W_BOOT_BLOCK_PROT 0x40 /* Only W29C020 */ #define SST_SET_ID_MODE_ALT 0x60 /* Only 29, 6th cycle */ #define SST_ERASE 0x80 /* Both 29 and 39 */ /* With data 60h on 6th cycle, it's alt. ID */ @@ -65,21 +70,36 @@ static wchar_t flash_path[1024]; #define SST_CLEAR_ID_MODE 0xf0 /* Both 29 and 39 */ /* 1st cycle variant only on 39 */ -#define SST_ID_MANUFACTURER 0xbf /* SST Manufacturer's ID */ -#define SST_ID_SST29EE010 0x07 -#define SST_ID_SST29LE_VE010 0x08 -#define SST_ID_SST29EE020 0x10 -#define SST_ID_SST29LE_VE020 0x12 -#define SST_ID_SST39SF512 0xb4 -#define SST_ID_SST39SF010 0xb5 -#define SST_ID_SST39SF020 0xb6 -#define SST_ID_SST39SF040 0xb7 +#define SST 0xbf /* SST Manufacturer's ID */ +#define SST29EE010 0x0700 +#define SST29LE_VE010 0x0800 +#define SST29EE020 0x1000 +#define SST29LE_VE020 0x1200 +#define SST39SF512 0xb400 +#define SST39SF010 0xb500 +#define SST39SF020 0xb600 +#define SST39SF040 0xb700 + +#define WINBOND 0xda /* Winbond Manufacturer's ID */ +#define W29C020 0x4500 + +#define SIZE_512K 0x010000 +#define SIZE_1M 0x020000 +#define SIZE_2M 0x040000 +#define SIZE_4M 0x080000 static void sst_sector_erase(sst_t *dev, uint32_t addr) { - memset(&dev->array[addr & (dev->mask & ~0xfff)], 0xff, 4096); + uint32_t base = addr & (dev->mask & ~0xfff); + + if ((base < 0x2000) && (dev->bbp_first_8k & 0x01)) + return; + else if ((base >= (dev->size - 0x2000)) && (dev->bbp_last_8k & 0x01)) + return; + + memset(&dev->array[base], 0xff, 4096); dev->dirty = 1; } @@ -87,9 +107,19 @@ sst_sector_erase(sst_t *dev, uint32_t addr) static void sst_new_command(sst_t *dev, uint32_t addr, uint8_t val) { + uint32_t base = 0x00000, size = dev->size; + if (dev->command_state == 5) switch (val) { case SST_CHIP_ERASE: - memset(dev->array, 0xff, 0x20000); + if (dev->bbp_first_8k & 0x01) { + base += 0x2000; + size -= 0x2000; + } + + if (dev->bbp_last_8k & 0x01) + size -= 0x2000; + + memset(&(dev->array[base]), 0xff, size); dev->command_state = 0; break; @@ -125,13 +155,20 @@ sst_new_command(sst_t *dev, uint32_t addr, uint8_t val) case SST_BYTE_PROGRAM: if (!dev->is_39) { + dev->sdp = 1; memset(dev->page_buffer, 0xff, 128); + memset(dev->page_dirty, 0x00, 128); dev->page_bytes = 0; + dev->last_addr = 0xffffffff; timer_on_auto(&dev->page_write_timer, 210.0); } dev->command_state = 6; break; + case W_BOOT_BLOCK_PROT: + dev->command_state = dev->has_bbp ? 8 : 0; + break; + case SST_CLEAR_ID_MODE: dev->id_mode = 0; dev->command_state = 0; @@ -148,11 +185,25 @@ static void sst_page_write(void *priv) { sst_t *dev = (sst_t *) priv; + int i; - memcpy(&(dev->array[dev->page_base]), dev->page_buffer, 128); - dev->dirty = 1; + if (dev->last_addr != 0xffffffff) { + dev->page_base = dev->last_addr & dev->page_mask; + for (i = 0; i < 128; i++) { + if (dev->page_dirty[i]) { + if (((dev->page_base + i) < 0x2000) && (dev->bbp_first_8k & 0x01)) + continue; + else if (((dev->page_base + i) >= (dev->size - 0x2000)) && (dev->bbp_last_8k & 0x01)) + continue; + + dev->array[dev->page_base + i] = dev->page_buffer[i]; + dev->dirty |= 1; + } + } + } dev->page_bytes = 0; dev->command_state = 0; + timer_disable(&dev->page_write_timer); } @@ -160,13 +211,26 @@ static uint8_t sst_read_id(uint32_t addr, void *p) { sst_t *dev = (sst_t *) p; + uint8_t ret = 0x00; if ((addr & 0xffff) == 0) - return SST_ID_MANUFACTURER; /* SST */ + ret = dev->manufacturer; else if ((addr & 0xffff) == 1) - return dev->id; - else - return 0xff; + ret = dev->id; +#ifdef UNKNOWN_FLASH + else if ((addr & 0xffff) == 0x100) + ret = 0x1c; + else if ((addr & 0xffff) == 0x101) + ret = 0x92; +#endif + else if (dev->has_bbp) { + if (addr == 0x00002) + ret = dev->bbp_first_8k; + else if (addr == 0x3fff2) + ret = dev->bbp_last_8k; + } + + return ret; } @@ -174,12 +238,13 @@ static void sst_buf_write(sst_t *dev, uint32_t addr, uint8_t val) { dev->page_buffer[addr & 0x0000007f] = val; - timer_disable(&dev->page_write_timer); + dev->page_dirty[addr & 0x0000007f] = 1; dev->page_bytes++; - if (dev->page_bytes >= 128) + dev->last_addr = addr; + if (dev->page_bytes >= 128) { sst_page_write(dev); - else - timer_set_delay_u64(&dev->page_write_timer, 210 * TIMER_USEC); + } else + timer_on_auto(&dev->page_write_timer, 210.0); } @@ -201,11 +266,13 @@ sst_write(uint32_t addr, uint8_t val, void *p) else { if (!dev->is_39 && !dev->sdp && (dev->command_state == 0)) { /* 29 series, software data protection off, start loading the page. */ - dev->page_base = addr & dev->page_mask; /* First byte, A7 onwards of its address are the page mask. */ + memset(dev->page_buffer, 0xff, 128); + memset(dev->page_dirty, 0x00, 128); + dev->page_bytes = 0; dev->command_state = 7; sst_buf_write(dev, addr, val); - } - dev->command_state = 0; + } else + dev->command_state = 0; } break; case 1: @@ -219,7 +286,10 @@ sst_write(uint32_t addr, uint8_t val, void *p) case 2: case 5: /* 3rd and 6th Bus Write Cycle */ - if ((addr & 0x7fff) == 0x5555) + if ((dev->command_state == 5) && (val == SST_SECTOR_ERASE)) { + /* Sector erase - can be on any address. */ + sst_new_command(dev, addr, val); + } else if ((addr & 0x7fff) == 0x5555) sst_new_command(dev, addr, val); else dev->command_state = 0; @@ -227,19 +297,26 @@ sst_write(uint32_t addr, uint8_t val, void *p) case 6: /* Page Load Cycle (29) / Data Write Cycle (39SF) */ if (dev->is_39) { - dev->array[addr & dev->mask] = val; dev->command_state = 0; + + dev->array[addr & dev->mask] = val; dev->dirty = 1; } else { - dev->page_base = addr & dev->page_mask; /* First byte, A7 onwards of its address are the page mask. */ dev->command_state++; sst_buf_write(dev, addr, val); - } + } break; case 7: - if (!dev->is_39 && ((addr & dev->page_mask) == dev->page_base)) + if (!dev->is_39) sst_buf_write(dev, addr, val); break; + case 8: + if ((addr == 0x00000) && (val == 0x00)) + dev->bbp_first_8k = 0xff; + else if ((addr == 0x3ffff) && (val == 0xff)) + dev->bbp_last_8k = 0xff; + dev->command_state = 0; + break; } } @@ -313,7 +390,7 @@ sst_add_mappings(sst_t *dev) for (i = 0; i < count; i++) { base = root_base + (i << 16); - fbase = base & biosmask; + fbase = base & biosmask; memcpy(&dev->array[fbase], &rom[base & biosmask], 0x10000); @@ -321,12 +398,19 @@ sst_add_mappings(sst_t *dev) mem_mapping_add(&(dev->mapping[i]), base, 0x10000, sst_read, sst_readw, sst_readl, sst_write, NULL, NULL, - dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); + } + if (is6117) { + mem_mapping_add(&(dev->mapping_h[i]), (base | 0x3f00000), 0x10000, + sst_read, sst_readw, sst_readl, + sst_write, NULL, NULL, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); + } else { + mem_mapping_add(&(dev->mapping_h[i]), (base | (cpu_16bitbus ? 0xf00000 : 0xfff00000)), 0x10000, + sst_read, sst_readw, sst_readl, + sst_write, NULL, NULL, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); } - mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000), 0x10000, - sst_read, sst_readw, sst_readl, - sst_write, NULL, NULL, - dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); } } @@ -338,17 +422,7 @@ sst_init(const device_t *info) sst_t *dev = malloc(sizeof(sst_t)); memset(dev, 0, sizeof(sst_t)); - size_t l = strlen(machine_get_internal_name_ex(machine))+1; - wchar_t *machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); - mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); - l = wcslen(machine_name)+5; - wchar_t *flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); - swprintf(flash_name, l, L"%ls.bin", machine_name); - - if (wcslen(flash_name) <= 1024) - wcscpy(flash_path, flash_name); - else - wcsncpy(flash_path, flash_name, 1024); + sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); mem_mapping_disable(&bios_mapping); mem_mapping_disable(&bios_high_mapping); @@ -356,34 +430,30 @@ sst_init(const device_t *info) dev->array = (uint8_t *) malloc(biosmask + 1); memset(dev->array, 0xff, biosmask + 1); - dev->id = info->local; - dev->is_39 = (dev->id >= SST_ID_SST39SF512); + dev->manufacturer = info->local & 0xff; + dev->id = (info->local >> 8) & 0xff; + dev->has_bbp = (dev->manufacturer == WINBOND) && ((info->local & 0xff00) >= W29C020); + dev->is_39 = (dev->manufacturer == SST) && ((info->local & 0xff00) >= SST39SF512); - if (dev->id == SST_ID_SST39SF512) + dev->size = info->local & 0xffff0000; + if ((dev->size == 0x20000) && (strstr(machine_get_internal_name_ex(machine), "xi8088")) && !xi8088_bios_128kb()) dev->size = 0x10000; - else if ((dev->id == SST_ID_SST29EE020) || (dev->id == SST_ID_SST29LE_VE020) || (dev->id == SST_ID_SST39SF020)) - dev->size = 0x40000; - else if (dev->id == SST_ID_SST39SF040) - dev->size = 0x80000; - else - dev->size = 0x20000; + dev->mask = dev->size - 1; dev->page_mask = dev->mask & 0xffffff80; /* Filter out A0-A6. */ dev->sdp = 1; + dev->bbp_first_8k = dev->bbp_last_8k = 0xfe; sst_add_mappings(dev); - f = nvr_fopen(flash_path, L"rb"); + f = nvr_fopen(flash_path, "rb"); if (f) { if (fread(&(dev->array[0x00000]), 1, dev->size, f) != dev->size) - fatal("Less than %i bytes read from the SST Flash ROM file\n", dev->size); + pclog("Less than %i bytes read from the SST Flash ROM file\n", dev->size); fclose(f); } else dev->dirty = 1; /* It is by definition dirty on creation. */ - free(flash_name); - free(machine_name); - if (!dev->is_39) timer_add(&dev->page_write_timer, sst_page_write, dev, 0); @@ -398,9 +468,11 @@ sst_close(void *p) sst_t *dev = (sst_t *)p; if (dev->dirty) { - f = nvr_fopen(flash_path, L"wb"); - fwrite(&(dev->array[0x00000]), dev->size, 1, f); - fclose(f); + f = nvr_fopen(flash_path, "wb"); + if (f != NULL) { + fwrite(&(dev->array[0x00000]), dev->size, 1, f); + fclose(f); + } } free(dev->array); @@ -409,50 +481,86 @@ sst_close(void *p) free(dev); } - -const device_t sst_flash_29ee010_device = -{ - "SST 29EE010 Flash BIOS", - 0, - SST_ID_SST29EE010, - sst_init, - sst_close, - NULL, - NULL, NULL, NULL, NULL +const device_t sst_flash_29ee010_device = { + .name = "SST 29EE010 Flash BIOS", + .internal_name = "sst_flash_29ee010", + .flags = 0, + .local = SST | SST29EE010 | SIZE_1M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t sst_flash_29ee020_device = -{ - "SST 29EE020 Flash BIOS", - 0, - SST_ID_SST29EE020, - sst_init, - sst_close, - NULL, - NULL, NULL, NULL, NULL +const device_t sst_flash_29ee020_device = { + .name = "SST 29EE020 Flash BIOS", + .internal_name = "sst_flash_29ee020", + .flags = 0, + .local = SST | SST29EE020 | SIZE_2M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t sst_flash_39sf010_device = -{ - "SST 39SF010 Flash BIOS", - 0, - SST_ID_SST39SF010, - sst_init, - sst_close, - NULL, - NULL, NULL, NULL, NULL +const device_t winbond_flash_w29c020_device = { + .name = "Winbond W29C020 Flash BIOS", + .internal_name = "winbond_flash_w29c020", + .flags = 0, + .local = WINBOND | W29C020 | SIZE_2M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t sst_flash_39sf020_device = -{ - "SST 39SF020 Flash BIOS", - 0, - SST_ID_SST39SF020, - sst_init, - sst_close, - NULL, - NULL, NULL, NULL, NULL +const device_t sst_flash_39sf010_device = { + .name = "SST 39SF010 Flash BIOS", + .internal_name = "sst_flash_39sf010", + .flags = 0, + .local = SST | SST39SF010 | SIZE_1M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sst_flash_39sf020_device = { + .name = "SST 39SF020 Flash BIOS", + .internal_name = "sst_flash_39sf020", + .flags = 0, + .local = SST | SST39SF020 | SIZE_2M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sst_flash_39sf040_device = { + .name = "SST 39SF040 Flash BIOS", + .internal_name = "sst_flash_39sf040", + .flags = 0, + .local = SST | SST39SF040 | SIZE_4M, + .init = sst_init, + .close = sst_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/minitrace/minitrace.c b/src/minitrace/minitrace.c new file mode 100644 index 000000000..89f12d6a8 --- /dev/null +++ b/src/minitrace/minitrace.c @@ -0,0 +1,564 @@ +// minitrace +// Copyright 2014 by Henrik Rydgård +// http://www.github.com/hrydgard/minitrace +// Released under the MIT license. + +// See minitrace.h for basic documentation. + +#include +#include +#include + +#ifdef _WIN32 +#pragma warning (disable:4996) +#define WIN32_LEAN_AND_MEAN +#include +#ifndef __MINGW32__ +#define __thread __declspec(thread) +#endif +#define pthread_cond_t CONDITION_VARIABLE +#define pthread_cond_init(a) InitializeConditionVariable(a) +#define pthread_cond_wait(a, b) SleepConditionVariableCS(a, b, INFINITE) +#define pthread_cond_signal(a) WakeConditionVariable(a) +#define pthread_mutex_t CRITICAL_SECTION +#define pthread_mutex_init(a, b) InitializeCriticalSection(a) +#define pthread_mutex_lock(a) EnterCriticalSection(a) +#define pthread_mutex_unlock(a) LeaveCriticalSection(a) +#define pthread_mutex_destroy(a) DeleteCriticalSection(a) +#else +#include +#include +#include +#include +#include +#endif + +#include + +#ifdef __GNUC__ +#define ATTR_NORETURN __attribute__((noreturn)) +#else +#define ATTR_NORETURN +#endif + +#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0]) +#define TRUE 1 +#define FALSE 0 + +// Ugh, this struct is already pretty heavy. +// Will probably need to move arguments to a second buffer to support more than one. +typedef struct raw_event { + const char *name; + const char *cat; + void *id; + int64_t ts; + uint32_t pid; + uint32_t tid; + char ph; + mtr_arg_type arg_type; + const char *arg_name; + union { + const char *a_str; + int a_int; + double a_double; + }; +} raw_event_t; + +static raw_event_t *event_buffer; +static raw_event_t *flush_buffer; +static volatile int event_count; +static __attribute__ ((aligned (32))) atomic_long is_tracing = FALSE; +static __attribute__ ((aligned (32))) atomic_long stop_flushing_requested = FALSE; +static int is_flushing = FALSE; +static int events_in_progress = 0; +static int64_t time_offset; +static int first_line = 1; +static FILE *f; +static __thread int cur_thread_id; // Thread local storage +static int cur_process_id; +static pthread_mutex_t mutex; +static pthread_mutex_t event_mutex; +static pthread_cond_t buffer_not_full_cond; +static pthread_cond_t buffer_full_cond; + +#define STRING_POOL_SIZE 100 +static char *str_pool[100]; + +// forward declaration +void mtr_flush_with_state(int); + +// Tiny portability layer. +// Exposes: +// get_cur_thread_id() +// get_cur_process_id() +// mtr_time_s() +// pthread basics +#ifdef _WIN32 + +static int get_cur_thread_id() { + return (int)GetCurrentThreadId(); +} +static int get_cur_process_id() { + return (int)GetCurrentProcessId(); +} + +static uint64_t _frequency = 0; +static uint64_t _starttime = 0; +double mtr_time_s() { + if (_frequency == 0) { + QueryPerformanceFrequency((LARGE_INTEGER*)&_frequency); + QueryPerformanceCounter((LARGE_INTEGER*)&_starttime); + } + __int64 time; + QueryPerformanceCounter((LARGE_INTEGER*)&time); + return ((double) (time - _starttime) / (double) _frequency); +} + +// Ctrl+C handling for Windows console apps +static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) { + if (atomic_load(&is_tracing) && fdwCtrlType == CTRL_C_EVENT) { + printf("Ctrl-C detected! Flushing trace and shutting down.\n\n"); + mtr_flush(); + mtr_shutdown(); + } + ExitProcess(1); +} + +void mtr_register_sigint_handler() { + // For console apps: + SetConsoleCtrlHandler(&CtrlHandler, TRUE); +} + +HANDLE thread_handle; + +static DWORD WINAPI thread_flush_proc(void* param) { + while(TRUE) { + mtr_flush_with_state(FALSE); + if(atomic_load(&stop_flushing_requested)) { + break; + } + } + return 0; +} + +static void init_flushing_thread(void) { + pthread_mutex_lock(&mutex); + is_flushing = FALSE; + pthread_mutex_unlock(&mutex); + thread_handle = CreateThread(NULL, 0, thread_flush_proc, (void*)0, 0, NULL); +} + +static void join_flushing_thread(void) { + WaitForSingleObject(thread_handle, INFINITE); +} + +#else + +static inline int get_cur_thread_id() { + return (int)(intptr_t)pthread_self(); +} +static inline int get_cur_process_id() { + return (int)getpid(); +} + +static pthread_t thread_handle = 0; +static void* thread_flush_proc(void* param) { + while(1) { + mtr_flush_with_state(0); + if(atomic_load(&stop_flushing_requested)) { + break; + } + } + return 0; +} +static void init_flushing_thread(void) { + pthread_mutex_lock(&mutex); + is_flushing = FALSE; + pthread_mutex_unlock(&mutex); + if (pthread_create(&thread_handle, NULL, thread_flush_proc, NULL) != 0) + { + thread_handle = 0; + } +} + +static void join_flushing_thread(void) { + if (thread_handle) pthread_join(thread_handle, NULL); + thread_handle = 0; +} + +#if defined(BLACKBERRY) +double mtr_time_s() { + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); // Linux must use CLOCK_MONOTONIC_RAW due to time warps + return time.tv_sec + time.tv_nsec / 1.0e9; +} +#else +double mtr_time_s() { + static time_t start; + struct timeval tv; + gettimeofday(&tv, NULL); + if (start == 0) { + start = tv.tv_sec; + } + tv.tv_sec -= start; + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} +#endif // !BLACKBERRY + +static void termination_handler(int signum) ATTR_NORETURN; +static void termination_handler(int signum) { + (void) signum; + if (is_tracing) { + printf("Ctrl-C detected! Flushing trace and shutting down.\n\n"); + mtr_flush(); + fwrite("\n]}\n", 1, 4, f); + fclose(f); + } + exit(1); +} + +void mtr_register_sigint_handler() { +#ifndef MTR_ENABLED + return; +#endif + // Avoid altering set-to-be-ignored handlers while registering. + if (signal(SIGINT, &termination_handler) == SIG_IGN) + signal(SIGINT, SIG_IGN); +} + +#endif + +void mtr_init_from_stream(void *stream) { +#ifndef MTR_ENABLED + return; +#endif + event_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t)); + flush_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t)); + event_count = 0; + f = (FILE *)stream; + const char *header = "{\"traceEvents\":[\n"; + fwrite(header, 1, strlen(header), f); + time_offset = (uint64_t)(mtr_time_s() * 1000000); + first_line = 1; + pthread_mutex_init(&mutex, 0); + pthread_mutex_init(&event_mutex, 0); +} + +void mtr_init(const char *json_file) { +#ifndef MTR_ENABLED + return; +#endif + mtr_init_from_stream(fopen(json_file, "wb")); +} + +void mtr_shutdown() { + int i; +#ifndef MTR_ENABLED + return; +#endif + + mtr_flush_with_state(TRUE); + + fwrite("\n]}\n", 1, 4, f); + fclose(f); + pthread_mutex_destroy(&mutex); + pthread_mutex_destroy(&event_mutex); + f = 0; + free(event_buffer); + event_buffer = 0; + for (i = 0; i < STRING_POOL_SIZE; i++) { + if (str_pool[i]) { + free(str_pool[i]); + str_pool[i] = 0; + } + } +} + +const char *mtr_pool_string(const char *str) { + int i; + for (i = 0; i < STRING_POOL_SIZE; i++) { + if (!str_pool[i]) { + str_pool[i] = (char*)malloc(strlen(str) + 1); + strcpy(str_pool[i], str); + return str_pool[i]; + } else { + if (!strcmp(str, str_pool[i])) + return str_pool[i]; + } + } + return "string pool full"; +} + +void mtr_start() { +#ifndef MTR_ENABLED + return; +#endif + pthread_cond_init(&buffer_not_full_cond, NULL); + pthread_cond_init(&buffer_full_cond, NULL); + atomic_store(&is_tracing, TRUE); + init_flushing_thread(); +} + +void mtr_stop() { +#ifndef MTR_ENABLED + return; +#endif + atomic_store(&is_tracing, FALSE); + atomic_store(&stop_flushing_requested, TRUE); + pthread_cond_signal(&buffer_not_full_cond); + pthread_cond_signal(&buffer_full_cond); + join_flushing_thread(); + atomic_store(&stop_flushing_requested, FALSE); +} + +// TODO: fwrite more than one line at a time. +// Flushing is thread safe and process async +// using double-buffering mechanism. +// Aware: only one flushing process may be +// running at any point of time +void mtr_flush_with_state(int is_last) { +#ifndef MTR_ENABLED + return; +#endif + int i = 0; + char linebuf[1024]; + char arg_buf[1024]; + char id_buf[256]; + int event_count_copy = 0; + int events_in_progress_copy = 1; + raw_event_t *event_buffer_tmp = NULL; + + // small critical section to swap buffers + // - no any new events can be spawn while + // swapping since they tied to the same mutex + // - checks for any flushing in process + pthread_mutex_lock(&mutex); + // if not flushing already + if (is_flushing) { + pthread_mutex_unlock(&mutex); + return; + } + is_flushing = TRUE; + if(!is_last) { + while(event_count < INTERNAL_MINITRACE_BUFFER_SIZE && atomic_load(&is_tracing)) { + pthread_cond_wait(&buffer_full_cond, &mutex); + } + } + event_count_copy = event_count; + event_buffer_tmp = flush_buffer; + flush_buffer = event_buffer; + event_buffer = event_buffer_tmp; + event_count = 0; + // waiting for any unfinished events before swap + while (events_in_progress_copy != 0) { + pthread_mutex_lock(&event_mutex); + events_in_progress_copy = events_in_progress; + pthread_mutex_unlock(&event_mutex); + } + pthread_mutex_unlock(&mutex); + pthread_cond_signal(&buffer_not_full_cond); + + for (i = 0; i < event_count_copy; i++) { + raw_event_t *raw = &flush_buffer[i]; + int len; + switch (raw->arg_type) { + case MTR_ARG_TYPE_INT: + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":%i", raw->arg_name, raw->a_int); + break; + case MTR_ARG_TYPE_STRING_CONST: + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str); + break; + case MTR_ARG_TYPE_STRING_COPY: + if (strlen(raw->a_str) > 700) { + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%.*s\"", raw->arg_name, 700, raw->a_str); + } else { + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str); + } + break; + case MTR_ARG_TYPE_NONE: + arg_buf[0] = '\0'; + break; + } + if (raw->id) { + switch (raw->ph) { + case 'S': + case 'T': + case 'F': + // TODO: Support full 64-bit pointers + snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"id\":\"0x%08x\"", (uint32_t)(uintptr_t)raw->id); + break; + case 'X': + snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"dur\":%i", (int)raw->a_double); + break; + } + } else { + id_buf[0] = 0; + } + const char *cat = raw->cat; +#ifdef _WIN32 + // On Windows, we often end up with backslashes in category. + char temp[256]; + { + int len = (int)strlen(cat); + int i; + if (len > 255) len = 255; + for (i = 0; i < len; i++) { + temp[i] = cat[i] == '\\' ? '/' : cat[i]; + } + temp[len] = 0; + cat = temp; + } +#endif + + len = snprintf(linebuf, ARRAY_SIZE(linebuf), "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ",\"ph\":\"%c\",\"name\":\"%s\",\"args\":{%s}%s}", + first_line ? "" : ",\n", + cat, raw->pid, raw->tid, raw->ts - time_offset, raw->ph, raw->name, arg_buf, id_buf); + fwrite(linebuf, 1, len, f); + first_line = 0; + + if (raw->arg_type == MTR_ARG_TYPE_STRING_COPY) { + free((void*)raw->a_str); + } + #ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME + free(raw->name); + free(raw->cat); + #endif + } + + pthread_mutex_lock(&mutex); + is_flushing = is_last; + pthread_mutex_unlock(&mutex); +} + +void mtr_flush() { + mtr_flush_with_state(FALSE); +} + +void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id) { +#ifndef MTR_ENABLED + return; +#endif + + if (!atomic_load(&is_tracing)) { + return; + } + pthread_mutex_lock(&mutex); + while(event_count >= INTERNAL_MINITRACE_BUFFER_SIZE && atomic_load(&is_tracing)) { + pthread_cond_wait(&buffer_not_full_cond, &mutex); + } + raw_event_t *ev = &event_buffer[event_count]; + ++event_count; + pthread_mutex_lock(&event_mutex); + ++events_in_progress; + pthread_mutex_unlock(&event_mutex); + int local_event_count = event_count; + pthread_mutex_unlock(&mutex); + if(local_event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) { + pthread_cond_signal(&buffer_full_cond); + } + + double ts = mtr_time_s(); + + if (!cur_thread_id) { + cur_thread_id = get_cur_thread_id(); + } + if (!cur_process_id) { + cur_process_id = get_cur_process_id(); + } + +#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME + const size_t category_len = strlen(category); + ev->cat = malloc(category_len + 1); + strcpy(ev->cat, category); + + const size_t name_len = strlen(name); + ev->name = malloc(name_len + 1); + strcpy(ev->name, name); + +#else + ev->cat = category; + ev->name = name; +#endif + + ev->id = id; + ev->ph = ph; + if (ev->ph == 'X') { + double x; + memcpy(&x, id, sizeof(double)); + ev->ts = (int64_t)(x * 1000000); + ev->a_double = (ts - x) * 1000000; + } else { + ev->ts = (int64_t)(ts * 1000000); + } + ev->tid = cur_thread_id; + ev->pid = cur_process_id; + ev->arg_type = MTR_ARG_TYPE_NONE; + + pthread_mutex_lock(&event_mutex); + --events_in_progress; + pthread_mutex_unlock(&event_mutex); +} + +void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value) { +#ifndef MTR_ENABLED + return; +#endif + if (!atomic_load(&is_tracing)) { + return; + } + pthread_mutex_lock(&mutex); + while(event_count >= INTERNAL_MINITRACE_BUFFER_SIZE && atomic_load(&is_tracing)) { + pthread_cond_wait(&buffer_not_full_cond, &mutex); + } + raw_event_t *ev = &event_buffer[event_count]; + ++event_count; + pthread_mutex_lock(&event_mutex); + ++events_in_progress; + pthread_mutex_unlock(&event_mutex); + int local_event_count = event_count; + pthread_mutex_unlock(&mutex); + if(local_event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) { + pthread_cond_signal(&buffer_full_cond); + } + + + if (!cur_thread_id) { + cur_thread_id = get_cur_thread_id(); + } + if (!cur_process_id) { + cur_process_id = get_cur_process_id(); + } + double ts = mtr_time_s(); + +#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME + const size_t category_len = strlen(category); + ev->cat = malloc(category_len + 1); + strcpy(ev->cat, category); + + const size_t name_len = strlen(name); + ev->name = malloc(name_len + 1); + strcpy(ev->name, name); + +#else + ev->cat = category; + ev->name = name; +#endif + + ev->id = id; + ev->ts = (int64_t)(ts * 1000000); + ev->ph = ph; + ev->tid = cur_thread_id; + ev->pid = cur_process_id; + ev->arg_type = arg_type; + ev->arg_name = arg_name; + switch (arg_type) { + case MTR_ARG_TYPE_INT: ev->a_int = (int)(uintptr_t)arg_value; break; + case MTR_ARG_TYPE_STRING_CONST: ev->a_str = (const char*)arg_value; break; + case MTR_ARG_TYPE_STRING_COPY: ev->a_str = strdup((const char*)arg_value); break; + case MTR_ARG_TYPE_NONE: break; + } + + pthread_mutex_lock(&event_mutex); + --events_in_progress; + pthread_mutex_unlock(&event_mutex); +} diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt new file mode 100644 index 000000000..e5a03a8ce --- /dev/null +++ b/src/network/CMakeLists.txt @@ -0,0 +1,37 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(net OBJECT network.c net_pcap.c net_slirp.c net_dp8390.c net_3c503.c + net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c) + +option(SLIRP_EXTERNAL "Link against the system-provided libslirp library" OFF) +mark_as_advanced(SLIRP_EXTERNAL) + +if(SLIRP_EXTERNAL) + find_package(PkgConfig REQUIRED) + pkg_check_modules(SLIRP REQUIRED IMPORTED_TARGET slirp) + target_link_libraries(86Box PkgConfig::SLIRP) + + if(WIN32) + target_link_libraries(PkgConfig::SLIRP INTERFACE wsock32 ws2_32 iphlpapi iconv) + endif() +else() + add_subdirectory(slirp) + target_link_libraries(86Box slirp) +endif() + +if (HAIKU) + target_link_libraries(86Box network) +endif() diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index c75c07353..bb2ed1628 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -129,7 +129,7 @@ threec503_interrupt(void *priv, int set) case 5: dev->regs.idcfr = 0x80; break; - } + } if (set) picint(1 << dev->base_irq); @@ -177,7 +177,7 @@ threec503_set_drq(threec503_t *dev) case 3: dev->regs.idcfr = 4; break; - } + } } @@ -195,7 +195,7 @@ threec503_reset(void *priv) memset(&dev->regs, 0, sizeof(dev->regs)); - dev->regs.ctrl = 0x0a; + dev->regs.ctrl = 0x0a; } @@ -399,7 +399,7 @@ threec503_nic_hi_read(uint16_t addr, void *priv) if (!(dev->regs.ctrl & 0x80)) return 0xff; - threec503_set_drq(dev); + threec503_set_drq(dev); return dp8390_chipmem_read(dev->dp8390, dev->regs.da++, 1); } @@ -529,7 +529,7 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) if (!(dev->regs.ctrl & 0x80)) return; - threec503_set_drq(dev); + threec503_set_drq(dev); dp8390_chipmem_write(dev->dp8390, dev->regs.da++, val, 1); break; @@ -542,7 +542,7 @@ threec503_nic_ioset(threec503_t *dev, uint16_t addr) { io_sethandler(addr, 0x10, threec503_nic_lo_read, NULL, NULL, - threec503_nic_lo_write, NULL, NULL, dev); + threec503_nic_lo_write, NULL, NULL, dev); io_sethandler(addr+0x400, 0x10, threec503_nic_hi_read, NULL, NULL, @@ -575,7 +575,7 @@ threec503_nic_init(const device_t *info) * PnP and PCI devices start with address spaces inactive. */ threec503_nic_ioset(dev, dev->base_address); - + /* Set up our BIA. */ if (mac & 0xff000000) { /* Generate new local MAC. */ @@ -597,7 +597,7 @@ threec503_nic_init(const device_t *info) dev->dp8390->interrupt = threec503_interrupt; dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); dp8390_mem_alloc(dev->dp8390, 0x2000, 0x2000); - + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); threec503_log("I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -635,134 +635,101 @@ threec503_nic_close(void *priv) free(dev); } - -static const device_config_t threec503_config[] = -{ +static const device_config_t threec503_config[] = { +// clang-format off { - "base", "Address", CONFIG_HEX16, "", 0x300, - { - { - "0x250", 0x250 - }, - { - "0x280", 0x280 - }, - { - "0x2a0", 0x2a0 - }, - { - "0x2e0", 0x2e0 - }, - { - "0x300", 0x300 - }, - { - "0x310", 0x310 - }, - { - "0x330", 0x330 - }, - { - "0x350", 0x350 - }, - { - "", 0 - } - }, - { { NULL, { NULL } } }, - { 0, 0, 0 } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x300, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x250", .value = 0x250 }, + { .description = "0x280", .value = 0x280 }, + { .description = "0x2a0", .value = 0x2a0 }, + { .description = "0x2e0", .value = 0x2e0 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x310", .value = 0x310 }, + { .description = "0x330", .value = 0x330 }, + { .description = "0x350", .value = 0x350 }, + { .description = "", .value = 0 } + }, }, { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "", 0 - } - }, - { { NULL, { NULL } } }, - { 0, 0, 0 } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "", .value = 0 } + }, }, { - "dma", "DMA", CONFIG_SELECTION, "", 3, - { - { - "DMA 1", 1 - }, - { - "DMA 2", 2 - }, - { - "DMA 3", 3 - }, - { - "", 0 - } - }, - { { NULL, { NULL } } }, - { 0, 0, 0 } + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 2", .value = 2 }, + { .description = "DMA 3", .value = 3 }, + { .description = "", .value = 0 } + }, }, { - "mac", "MAC Address", CONFIG_MAC, "", -1, - { - { - "", 0 - } - }, - { { NULL, { NULL } } }, - { 0, 0, 0 } + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "", .value = 0 } + }, }, { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xCC000, - { - { - "DC00", 0xDC000 - }, - { - "D800", 0xD8000 - }, - { - "C800", 0xC8000 - }, - { - "CC00", 0xCC000 - }, - { - "", 0 - } - }, - { { NULL, { NULL } } }, - { 0, 0, 0 } + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xCC000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DC00", .value = 0xDC000 }, + { .description = "D800", .value = 0xD8000 }, + { .description = "C800", .value = 0xC8000 }, + { .description = "CC00", .value = 0xCC000 }, + { .description = "", .value = 0 } + }, }, - { - "", "", -1, "", -1, - { - { - "", 0 - } - }, - { { NULL, { NULL } } }, - { 0, 0, 0 } - } + { .name = "", .description = "", .type = CONFIG_END } +// clang-format off }; - const device_t threec503_device = { - "3Com EtherLink II", - DEVICE_ISA, - 0, - threec503_nic_init, threec503_nic_close, NULL, - NULL, NULL, NULL, - threec503_config + .name = "3Com EtherLink II", + .internal_name = "3c503", + .flags = DEVICE_ISA, + .local = 0, + .init = threec503_nic_init, + .close = threec503_nic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = threec503_config }; diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index 892101976..a5f26b69f 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -30,7 +30,8 @@ static void dp8390_tx(dp8390_t *dev, uint32_t val); -void dp8390_rx(void *priv, uint8_t *buf, int io_len); +static int dp8390_rx_common(void *priv, uint8_t *buf, int io_len); +int dp8390_rx(void *priv, uint8_t *buf, int io_len); #ifdef ENABLE_DP8390_LOG @@ -41,11 +42,11 @@ dp8390_log(const char *fmt, ...) { va_list ap; - if (dp8390_do_log >= lvl) { +// if (dp8390_do_log >= lvl) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); - } +// } } #else #define dp8390_log(lvl, fmt, ...) @@ -96,8 +97,8 @@ dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len) uint32_t retval = 0; #ifdef ENABLE_DP8390_LOG - if ((len > 1) && (addr & (len - 1)) - dp3890_log("DP8390: unaligned chipmem word read\n"); + if ((len > 1) && (addr & (len - 1))) + dp8390_log("DP8390: unaligned chipmem word read\n"); #endif dp8390_log("DP8390: Chipmem Read Address=%04x\n", addr); @@ -125,7 +126,7 @@ dp8390_chipmem_write(dp8390_t *dev, uint32_t addr, uint32_t val, unsigned len) int i; #ifdef ENABLE_DP8390_LOG - if ((len > 1) && (addr & (len - 1)) + if ((len > 1) && (addr & (len - 1))) dp8390_log("DP8390: unaligned chipmem word write\n"); #endif @@ -198,13 +199,13 @@ dp8390_write_cr(dp8390_t *dev, uint32_t val) dev->remote_start = dev->remote_dma = dev->bound_ptr * 256; dev->remote_bytes = (uint16_t) dp8390_chipmem_read(dev, dev->bound_ptr * 256 + 2, 2); dp8390_log("DP8390: sending buffer #x%x length %d\n", - dev->dp8390.remote_start, dev->dp8390.remote_bytes); + dev->remote_start, dev->remote_bytes); } /* Check for start-tx */ if ((val & 0x04) && dev->TCR.loop_cntl) { if (dev->TCR.loop_cntl) { - dp8390_rx(dev, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], + dp8390_rx_common(dev, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); } } else if (val & 0x04) { @@ -223,7 +224,7 @@ dp8390_write_cr(dp8390_t *dev, uint32_t val) /* Send the packet to the system driver */ dev->CR.tx_packet = 1; - + network_tx(&dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); /* some more debug */ @@ -270,8 +271,8 @@ dp8390_tx(dp8390_t *dev, uint32_t val) * if it should be accepted, and if the RX ring has enough room, * it is copied into it and the receive process is updated. */ -void -dp8390_rx(void *priv, uint8_t *buf, int io_len) +static int +dp8390_rx_common(void *priv, uint8_t *buf, int io_len) { dp8390_t *dev = (dp8390_t *)priv; static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; @@ -282,9 +283,10 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) int endbytes; if (io_len != 60) - dp8390_log("%s: rx_frame with length %d\n", dev->name, io_len); + dp8390_log("rx_frame with length %d\n", io_len); - if ((dev->CR.stop != 0) || (dev->page_start == 0)) return; + if ((dev->CR.stop != 0) || (dev->page_start == 0)) + return 0; /* * Add the pkt header + CRC to the length, and work @@ -312,7 +314,7 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) dp8390_log("DP8390: no space\n"); #endif - return; + return 0; } if ((io_len < 40/*60*/) && !dev->RCR.runts_ok) { @@ -320,7 +322,7 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) dp8390_log("DP8390: rejected small packet, length %d\n", io_len); #endif - return; + return 1; } /* Some computers don't care... */ @@ -341,7 +343,7 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) #ifdef ENABLE_DP8390_LOG dp8390_log("DP8390: RX BC disabled\n"); #endif - return; + return 1; } } @@ -352,7 +354,7 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) #ifdef ENABLE_DP8390_LOG dp8390_log("DP8390: RX MC disabled\n"); #endif - return; + return 1; } /* Are we listening to this multicast address? */ @@ -361,12 +363,13 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) #ifdef ENABLE_DP8390_LOG dp8390_log("DP8390: RX MC not listed\n"); #endif - return; + return 1; } } /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->physaddr, 6)) return; + else if (memcmp(buf, dev->physaddr, 6)) + return 1; } else { #ifdef ENABLE_DP8390_LOG dp8390_log("DP8390: RX promiscuous receive\n"); @@ -407,6 +410,20 @@ dp8390_rx(void *priv, uint8_t *buf, int io_len) if (dev->IMR.rx_inte && dev->interrupt) dev->interrupt(dev->priv, 1); + + return 1; +} + + +int +dp8390_rx(void *priv, uint8_t *buf, int io_len) +{ + dp8390_t *dev = (dp8390_t *)priv; + + if ((dev->DCR.loop == 0) || (dev->TCR.loop_cntl != 0)) + return 0; + + return dp8390_rx_common(priv, buf, io_len); } @@ -689,7 +706,7 @@ dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) dev->DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ dev->DCR.loop = ((val & 0x08) == 0x08); dev->DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->DCR.fifo_size = (val & 0x50) >> 5; + dev->DCR.fifo_size = (val & 0x60) >> 5; break; case 0x0f: /* IMR */ @@ -784,9 +801,9 @@ dp8390_page1_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) dev->physaddr[off - 1] = val; if (off == 6) dp8390_log("DP8390: Physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->dp8390->physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390->physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390->physaddr[4], dev->dp8390.physaddr[5]); + dev->physaddr[0], dev->physaddr[1], + dev->physaddr[2], dev->physaddr[3], + dev->physaddr[4], dev->physaddr[5]); break; case 0x07: /* CURR */ @@ -818,7 +835,7 @@ dp8390_page2_read(dp8390_t *dev, uint32_t off, unsigned int len) { dp8390_log("DP8390: Page2 read from register 0x%02x, len=%u\n", off, len); - + switch(off) { case 0x01: /* PSTART */ return(dev->page_start); @@ -1093,11 +1110,16 @@ dp8390_close(void *priv) } } - -const device_t dp8390_device = -{ - "DP8390 Network Interface Controller", - 0, 0, - dp8390_init, dp8390_close, - NULL, NULL, NULL, NULL +const device_t dp8390_device = { + .name = "DP8390 Network Interface Controller", + .internal_name = "dp8390", + .flags = 0, + .local = 0, + .init = dp8390_init, + .close = dp8390_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index c4f0ccf8b..5c0a7ba61 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -65,33 +65,33 @@ #include <86box/net_dp8390.h> #include <86box/net_ne2000.h> #include <86box/bswap.h> +#include <86box/isapnp.h> -enum { - PNP_PHASE_WAIT_FOR_KEY = 0, - PNP_PHASE_CONFIG, - PNP_PHASE_ISOLATION, - PNP_PHASE_SLEEP -}; - /* ROM BIOS file paths. */ -#define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom" -#define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom" -#define ROM_PATH_RTL8019 L"roms/network/rtl8019as/rtl8019as.rom" -#define ROM_PATH_RTL8029 L"roms/network/rtl8029as/rtl8029as.rom" +#define ROM_PATH_NE1000 "roms/network/ne1000/ne1000.rom" +#define ROM_PATH_NE2000 "roms/network/ne2000/ne2000.rom" +#define ROM_PATH_RTL8019 "roms/network/rtl8019as/rtl8019as.rom" +#define ROM_PATH_RTL8029 "roms/network/rtl8029as/rtl8029as.rom" /* PCI info. */ -#define PNP_VENDID 0x4a8c /* Realtek, Inc */ #define PCI_VENDID 0x10ec /* Realtek, Inc */ -#define PNP_DEVID 0x8019 /* RTL8029AS */ #define PCI_DEVID 0x8029 /* RTL8029AS */ #define PCI_REGSIZE 256 /* size of PCI space */ -uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, - 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, - 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, - 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; +static uint8_t rtl8019as_pnp_rom[] = { + 0x4a, 0x8c, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, /* RTL8019, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x22, 0x00, 'R', 'E', 'A', 'L', 'T', 'E', 'K', ' ', 'P', 'L', 'U', 'G', ' ', '&', ' ', 'P', 'L', 'A', 'Y', ' ', 'E', 'T', 'H', 'E', 'R', 'N', 'E', 'T', ' ', 'C', 'A', 'R', 'D', 0x00, /* ANSI identifier */ + + 0x16, 0x4a, 0x8c, 0x80, 0x19, 0x02, 0x00, /* logical device RTL8019 */ + 0x1c, 0x41, 0xd0, 0x80, 0xd6, /* compatible device PNP80D6 */ + 0x47, 0x00, 0x20, 0x02, 0x80, 0x03, 0x20, 0x20, /* I/O 0x220-0x380, decodes 10-bit, 32-byte alignment, 32 addresses */ + 0x23, 0x38, 0x9e, 0x01, /* IRQ 3/4/5/9/10/11/12/15, high true edge sensitive */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; typedef struct { @@ -106,27 +106,13 @@ typedef struct { bios_mask; int card; /* PCI card slot */ int has_bios, pad; - uint8_t pnp_regs[256]; - uint8_t pnp_res_data[256]; bar_t pci_bar[2]; uint8_t pci_regs[PCI_REGSIZE]; uint8_t eeprom[128]; /* for RTL8029AS */ rom_t bios_rom; - uint8_t pnp_phase; - uint8_t pnp_magic_count; - uint8_t pnp_address; - uint8_t pnp_res_pos; - uint8_t pnp_csn; - uint8_t pnp_activate; - uint8_t pnp_io_check; + void *pnp_card; uint8_t pnp_csnsav; - uint8_t pnp_id_checksum; - uint8_t pnp_serial_read_pos; - uint8_t pnp_serial_read_pair; - uint8_t pnp_serial_read; uint8_t maclocal[6]; /* configured MAC (local) address */ - uint16_t pnp_read; - uint64_t pnp_id; /* RTL8019AS/RTL8029AS registers */ uint8_t config0, config2, config3; @@ -138,15 +124,15 @@ typedef struct { } nic_t; -#ifdef ENABLE_NIC_LOG -int nic_do_log = ENABLE_NIC_LOG; +#ifdef ENABLE_NE2K_LOG +int ne2k_do_log = ENABLE_NE2K_LOG; static void nelog(int lvl, const char *fmt, ...) { va_list ap; - if (nic_do_log >= lvl) { + if (ne2k_do_log >= lvl) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); @@ -317,8 +303,8 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) case 0x0f: /* Reset register */ /* end of reset pulse */ - break; - + break; + default: /* this is invalid, but happens under win95 device detection */ nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", dev->name, (unsigned)off); @@ -330,7 +316,7 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) /* Writes to this page are illegal. */ static uint32_t page3_read(nic_t *dev, uint32_t off, unsigned int len) -{ +{ if (dev->board >= NE2K_RTL8019AS) switch(off) { case 0x1: /* 9346CR */ return(dev->_9346cr); @@ -348,10 +334,14 @@ page3_read(nic_t *dev, uint32_t off, unsigned int len) return((dev->board == NE2K_RTL8019AS) ? dev->pnp_csnsav : 0x00); case 0xe: /* 8029ASID0 */ - return(0x29); + if (dev->board == NE2K_RTL8029AS) + return(0x29); + break; case 0xf: /* 8029ASID1 */ - return(0x08); + if (dev->board == NE2K_RTL8029AS) + return(0x80); + break; default: break; @@ -508,338 +498,84 @@ nic_writel(uint16_t addr, uint32_t val, void *priv) } -static void nic_iocheckset(nic_t *dev, uint16_t addr); -static void nic_iocheckremove(nic_t *dev, uint16_t addr); static void nic_ioset(nic_t *dev, uint16_t addr); static void nic_ioremove(nic_t *dev, uint16_t addr); -static uint8_t -nic_pnp_io_check_readb(uint16_t addr, void *priv) +static void +nic_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld) + return; + + nic_t *dev = (nic_t *) priv; + + if (dev->base_address) { + nic_ioremove(dev, dev->base_address); + dev->base_address = 0; + } + + dev->base_address = config->io[0].base; + dev->base_irq = config->irq[0].irq; + + if (config->activate && (dev->base_address != ISAPNP_IO_DISABLED)) + nic_ioset(dev, dev->base_address); +} + + +static void +nic_pnp_csn_changed(uint8_t csn, void *priv) { nic_t *dev = (nic_t *) priv; - return((dev->pnp_io_check & 0x01) ? 0x55 : 0xAA); + dev->pnp_csnsav = csn; } static uint8_t -nic_pnp_readb(uint16_t addr, void *priv) +nic_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) { + if (ld != 0) + return 0x00; + nic_t *dev = (nic_t *) priv; - uint8_t bit, next_shift; - uint8_t ret = 0xFF; - /* Plug and Play Registers */ - switch(dev->pnp_address) { - /* Card Control Registers */ - case 0x01: /* Serial Isolation */ - if (dev->pnp_phase != PNP_PHASE_ISOLATION) { - ret = 0x00; - break; - } - if (dev->pnp_serial_read_pair) { - dev->pnp_serial_read <<= 1; - /* TODO: Support for multiple PnP devices. - if (pnp_get_bus_data() != dev->pnp_serial_read) - dev->pnp_phase = PNP_PHASE_SLEEP; - } else { - */ - if (!dev->pnp_serial_read_pos) { - dev->pnp_res_pos = 0x1B; - dev->pnp_phase = PNP_PHASE_CONFIG; - nelog(1, "\nASSIGN CSN phase\n"); - } - } else { - if (dev->pnp_serial_read_pos < 64) { - bit = (dev->pnp_id >> dev->pnp_serial_read_pos) & 0x01; - next_shift = (!!(dev->pnp_id_checksum & 0x02) ^ !!(dev->pnp_id_checksum & 0x01) ^ bit) & 0x01; - dev->pnp_id_checksum >>= 1; - dev->pnp_id_checksum |= (next_shift << 7); - } else { - if (dev->pnp_serial_read_pos == 64) - dev->eeprom[0x1A] = dev->pnp_id_checksum; - bit = (dev->pnp_id_checksum >> (dev->pnp_serial_read_pos & 0x07)) & 0x01; - } - dev->pnp_serial_read = bit ? 0x55 : 0x00; - dev->pnp_serial_read_pos = (dev->pnp_serial_read_pos + 1) % 72; - } - dev->pnp_serial_read_pair ^= 1; - ret = dev->pnp_serial_read; - break; - case 0x04: /* Resource Data */ - ret = dev->eeprom[dev->pnp_res_pos]; - dev->pnp_res_pos++; - break; - case 0x05: /* Status */ - ret = 0x01; - break; - case 0x06: /* Card Select Number (CSN) */ - nelog(1, "Card Select Number (CSN)\n"); - ret = dev->pnp_csn; - break; - case 0x07: /* Logical Device Number */ - nelog(1, "Logical Device Number\n"); - ret = 0x00; - break; - case 0x30: /* Activate */ - nelog(1, "Activate\n"); - ret = dev->pnp_activate; - break; - case 0x31: /* I/O Range Check */ - nelog(1, "I/O Range Check\n"); - ret = dev->pnp_io_check; - break; + switch (reg) { + case 0xF0: + return dev->config0; - /* Logical Device Configuration Registers */ - /* Memory Configuration Registers - We currently force them to stay 0x00 because we currently do not - support a RTL8019AS BIOS. */ - case 0x40: /* BROM base address bits[23:16] */ - case 0x41: /* BROM base address bits[15:0] */ - case 0x42: /* Memory Control */ - ret = 0x00; - break; + case 0xF2: + return dev->config2; - /* I/O Configuration Registers */ - case 0x60: /* I/O base address bits[15:8] */ - ret = (dev->base_address >> 8); - break; - case 0x61: /* I/O base address bits[7:0] */ - ret = (dev->base_address & 0xFF); - break; + case 0xF3: + return dev->config3; - /* Interrupt Configuration Registers */ - case 0x70: /* IRQ level */ - ret = dev->base_irq; - break; - case 0x71: /* IRQ type */ - ret = 0x02; /* high, edge */ - break; - - /* DMA Configuration Registers */ - case 0x74: /* DMA channel select 0 */ - case 0x75: /* DMA channel select 1 */ - ret = 0x04; /* indicating no DMA channel is needed */ - break; - - /* Vendor Defined Registers */ - case 0xF0: /* CONFIG0 */ - case 0xF1: /* CONFIG1 */ - ret = 0x00; - break; - case 0xF2: /* CONFIG2 */ - ret = (dev->config2 & 0xe0); - break; - case 0xF3: /* CONFIG3 */ - ret = (dev->config3 & 0x46); - break; - case 0xF5: /* CSNSAV */ - ret = (dev->pnp_csnsav); - break; + case 0xF5: + return dev->pnp_csnsav; } - nelog(1, "nic_pnp_readb(%04X) = %02X\n", addr, ret); - return(ret); -} - - -static void nic_pnp_io_set(nic_t *dev, uint16_t read_addr); -static void nic_pnp_io_remove(nic_t *dev); - - -static void -nic_pnp_writeb(uint16_t addr, uint8_t val, void *priv) -{ - nic_t *dev = (nic_t *) priv; - uint16_t new_addr = 0; - - nelog(1, "nic_pnp_writeb(%04X, %02X)\n", addr, val); - - /* Plug and Play Registers */ - switch(dev->pnp_address) { - /* Card Control Registers */ - case 0x00: /* Set RD_DATA port */ - new_addr = val; - new_addr <<= 2; - new_addr |= 3; - nic_pnp_io_remove(dev); - nic_pnp_io_set(dev, new_addr); - nelog(1, "PnP read data address now: %04X\n", new_addr); - break; - case 0x02: /* Config Control */ - if (val & 0x01) { - /* Reset command */ - nic_pnp_io_remove(dev); - memset(dev->pnp_regs, 0, 256); - nelog(1, "All logical devices reset\n"); - } - if (val & 0x02) { - /* Wait for Key command */ - dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY; - nelog(1, "WAIT FOR KEY phase\n"); - } - if (val & 0x04) { - /* PnP Reset CSN command */ - dev->pnp_csn = dev->pnp_csnsav = 0; - nelog(1, "CSN reset\n"); - } - break; - case 0x03: /* Wake[CSN] */ - nelog(1, "Wake[%02X]\n", val); - if (val == dev->pnp_csn) { - dev->pnp_res_pos = 0x12; - dev->pnp_id_checksum = 0x6A; - if (dev->pnp_phase == PNP_PHASE_SLEEP) { - dev->pnp_phase = val ? PNP_PHASE_CONFIG : PNP_PHASE_ISOLATION; - } - } else { - if ((dev->pnp_phase == PNP_PHASE_CONFIG) || (dev->pnp_phase == PNP_PHASE_ISOLATION)) - dev->pnp_phase = PNP_PHASE_SLEEP; - } - break; - case 0x06: /* Card Select Number (CSN) */ - dev->pnp_csn = dev->pnp_csnsav = val; - dev->pnp_phase = PNP_PHASE_CONFIG; - nelog(1, "CSN set to %02X\n", dev->pnp_csn); - break; - case 0x30: /* Activate */ - if ((dev->pnp_activate ^ val) & 0x01) { - nic_ioremove(dev, dev->base_address); - if (val & 0x01) - nic_ioset(dev, dev->base_address); - - nelog(1, "I/O range %sabled\n", val & 0x02 ? "en" : "dis"); - } - dev->pnp_activate = val; - break; - case 0x31: /* I/O Range Check */ - if ((dev->pnp_io_check ^ val) & 0x02) { - nic_iocheckremove(dev, dev->base_address); - if (val & 0x02) - nic_iocheckset(dev, dev->base_address); - - nelog(1, "I/O range check %sabled\n", val & 0x02 ? "en" : "dis"); - } - dev->pnp_io_check = val; - break; - - /* Logical Device Configuration Registers */ - /* Memory Configuration Registers - We currently force them to stay 0x00 because we currently do not - support a RTL8019AS BIOS. */ - - /* I/O Configuration Registers */ - case 0x60: /* I/O base address bits[15:8] */ - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioremove(dev, dev->base_address); - dev->base_address &= 0x00ff; - dev->base_address |= (((uint16_t) val) << 8); - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioset(dev, dev->base_address); - nelog(1, "Base address now: %04X\n", dev->base_address); - break; - case 0x61: /* I/O base address bits[7:0] */ - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioremove(dev, dev->base_address); - dev->base_address &= 0xff00; - dev->base_address |= val; - if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) - nic_ioset(dev, dev->base_address); - nelog(1, "Base address now: %04X\n", dev->base_address); - break; - - /* Interrupt Configuration Registers */ - case 0x70: /* IRQ level */ - dev->base_irq = val; - nelog(1, "IRQ now: %02i\n", dev->base_irq); - break; - - /* Vendor Defined Registers */ - case 0xF6: /* Vendor Control */ - dev->pnp_csn = 0; - break; - } - return; + return 0x00; } static void -nic_pnp_io_set(nic_t *dev, uint16_t read_addr) -{ - if ((read_addr >= 0x0200) && (read_addr <= 0x03FF)) { - io_sethandler(read_addr, 1, - nic_pnp_readb, NULL, NULL, - NULL, NULL, NULL, dev); - } - dev->pnp_read = read_addr; -} - - -static void -nic_pnp_io_remove(nic_t *dev) -{ - if ((dev->pnp_read >= 0x0200) && (dev->pnp_read <= 0x03FF)) { - io_removehandler(dev->pnp_read, 1, - nic_pnp_readb, NULL, NULL, - NULL, NULL, NULL, dev); - } -} - - -static void -nic_pnp_address_writeb(uint16_t addr, uint8_t val, void *priv) +nic_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) { nic_t *dev = (nic_t *) priv; - /* nelog(1, "nic_pnp_address_writeb(%04X, %02X)\n", addr, val); */ - - switch(dev->pnp_phase) { - case PNP_PHASE_WAIT_FOR_KEY: - if (val == pnp_init_key[dev->pnp_magic_count]) { - dev->pnp_magic_count = (dev->pnp_magic_count + 1) & 0x1f; - if (!dev->pnp_magic_count) - dev->pnp_phase = PNP_PHASE_SLEEP; - } else - dev->pnp_magic_count = 0; - break; - default: - dev->pnp_address = val; - break; + if ((ld == 0) && (reg == 0xf6) && (val & 0x04)) { + uint8_t csn = dev->pnp_csnsav; + isapnp_set_csn(dev->pnp_card, 0); + dev->pnp_csnsav = csn; } - return; -} - - -static void -nic_iocheckset(nic_t *dev, uint16_t addr) -{ - io_sethandler(addr, 32, - nic_pnp_io_check_readb, NULL, NULL, - NULL, NULL, NULL, dev); -} - - -static void -nic_iocheckremove(nic_t *dev, uint16_t addr) -{ - io_removehandler(addr, 32, - nic_pnp_io_check_readb, NULL, NULL, - NULL, NULL, NULL, dev); } static void nic_ioset(nic_t *dev, uint16_t addr) -{ +{ if (dev->is_pci) { - io_sethandler(addr, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_sethandler(addr+16, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_sethandler(addr+0x1f, 1, + io_sethandler(addr, 32, nic_readb, nic_readw, nic_readl, nic_writeb, nic_writew, nic_writel, dev); } else { @@ -855,9 +591,6 @@ nic_ioset(nic_t *dev, uint16_t addr) nic_readb, nic_readw, NULL, nic_writeb, nic_writew, NULL, dev); } - io_sethandler(addr+0x1f, 1, - nic_readb, NULL, NULL, - nic_writeb, NULL, NULL, dev); } } @@ -866,13 +599,7 @@ static void nic_ioremove(nic_t *dev, uint16_t addr) { if (dev->is_pci) { - io_removehandler(addr, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_removehandler(addr+16, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_removehandler(addr+0x1f, 1, + io_removehandler(addr, 32, nic_readb, nic_readw, nic_readl, nic_writeb, nic_writew, nic_writel, dev); } else { @@ -888,9 +615,6 @@ nic_ioremove(nic_t *dev, uint16_t addr) nic_readb, nic_readw, NULL, nic_writeb, nic_writew, NULL, dev); } - io_removehandler(addr+0x1f, 1, - nic_readb, NULL, NULL, - nic_writeb, NULL, NULL, dev); } } @@ -899,14 +623,14 @@ static void nic_update_bios(nic_t *dev) { int reg_bios_enable; - + reg_bios_enable = 1; if (! dev->has_bios) return; if (dev->is_pci) reg_bios_enable = dev->pci_bar[1].addr_regs[0] & 0x01; - + /* PCI BIOS stuff, just enable_disable. */ if (reg_bios_enable) { mem_mapping_set_addr(&dev->bios_rom.mapping, @@ -1085,7 +809,7 @@ nic_pci_write(int func, int addr, uint8_t val, void *priv) static void -nic_rom_init(nic_t *dev, wchar_t *s) +nic_rom_init(nic_t *dev, char *s) { uint32_t temp; FILE *f; @@ -1094,7 +818,7 @@ nic_rom_init(nic_t *dev, wchar_t *s) if (dev->bios_addr == 0) return; - if ((f = rom_fopen(s, L"rb")) != NULL) { + if ((f = rom_fopen(s, "rb")) != NULL) { fseek(f, 0L, SEEK_END); temp = ftell(f); fclose(f); @@ -1147,7 +871,7 @@ nic_mca_write(int port, uint8_t val, void *priv) /* Save the MCA register value. */ dev->pos_regs[port & 7] = val; - nic_ioremove(dev, dev->base_address); + nic_ioremove(dev, dev->base_address); /* This is always necessary so that the old handler doesn't remain. */ /* Get the new assigned I/O base address. */ @@ -1170,13 +894,13 @@ nic_mca_write(int port, uint8_t val, void *priv) /* Initialize the device if fully configured. */ if (dev->pos_regs[2] & 0x01) { /* Card enabled; register (new) I/O handler. */ - + nic_ioset(dev, dev->base_address); - + nic_reset(dev); - + nelog(2, "EtherNext/MC: Port=%04x, IRQ=%d\n", dev->base_address, dev->base_irq); - + } } @@ -1194,20 +918,8 @@ static void * nic_init(const device_t *info) { uint32_t mac; - wchar_t *rom; + char *rom; nic_t *dev; -#ifdef ENABLE_NIC_LOG - int i; -#endif - int c; - char *ansi_id = "REALTEK PLUG & PLAY ETHERNET CARD"; - uint64_t *eeprom_pnp_id; - - /* Get the desired debug level. */ -#ifdef ENABLE_NIC_LOG - i = device_get_config_int("debug"); - if (i > 0) nic_do_log = i; -#endif dev = malloc(sizeof(nic_t)); memset(dev, 0x00, sizeof(nic_t)); @@ -1235,10 +947,10 @@ nic_init(const device_t *info) } else { dev->bios_addr = 0x00000; dev->has_bios = 0; - } + } } else { - mca_add(nic_mca_read, nic_mca_write, nic_mca_feedb, NULL, dev); + mca_add(nic_mca_read, nic_mca_write, nic_mca_feedb, NULL, dev); } } @@ -1285,7 +997,7 @@ nic_init(const device_t *info) DP8390_FLAG_CLEAR_IRQ); dp8390_mem_alloc(dev->dp8390, 0x4000, 0x4000); break; - + case NE2K_ETHERNEXT_MC: dev->maclocal[0] = 0x00; /* 00:00:D8 (Networth Inc. OID) */ dev->maclocal[1] = 0x00; @@ -1378,15 +1090,6 @@ nic_init(const device_t *info) /* Add device to the PCI bus, keep its slot number. */ dev->card = pci_add_card(PCI_ADD_NORMAL, nic_pci_read, nic_pci_write, dev); - } else { - io_sethandler(0x0279, 1, - NULL, NULL, NULL, - nic_pnp_address_writeb, NULL, NULL, dev); - - dev->pnp_id = PNP_DEVID; - dev->pnp_id <<= 32LL; - dev->pnp_id |= PNP_VENDID; - dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY; } /* Initialize the RTL8029 EEPROM. */ @@ -1400,67 +1103,15 @@ nic_init(const device_t *info) dev->eeprom[0x7E] = (PCI_DEVID&0xff); dev->eeprom[0x77] = dev->eeprom[0x7B] = - dev->eeprom[0x7F] = (dev->board == NE2K_RTL8019AS) ? (PNP_DEVID>>8) : (PCI_DEVID>>8); + dev->eeprom[0x7F] = (PCI_DEVID>>8); dev->eeprom[0x78] = dev->eeprom[0x7C] = (PCI_VENDID&0xff); dev->eeprom[0x79] = dev->eeprom[0x7D] = (PCI_VENDID>>8); } else { - eeprom_pnp_id = (uint64_t *) &dev->eeprom[0x12]; - *eeprom_pnp_id = dev->pnp_id; + memcpy(&dev->eeprom[0x12], rtl8019as_pnp_rom, sizeof(rtl8019as_pnp_rom)); - /* TAG: Plug and Play Version Number. */ - dev->eeprom[0x1B] = 0x0A; /* Item byte */ - dev->eeprom[0x1C] = 0x10; /* PnP version */ - dev->eeprom[0x1D] = 0x10; /* Vendor version */ - - /* TAG: ANSI Identifier String. */ - dev->eeprom[0x1E] = 0x82; /* Item byte */ - dev->eeprom[0x1F] = 0x22; /* Length bits 7-0 */ - dev->eeprom[0x20] = 0x00; /* Length bits 15-8 */ - memcpy(&dev->eeprom[0x21], ansi_id, 0x22); - - /* TAG: Logical Device ID. */ - dev->eeprom[0x43] = 0x16; /* Item byte */ - dev->eeprom[0x44] = 0x4A; /* Logical device ID0 */ - dev->eeprom[0x45] = 0x8C; /* Logical device ID1 */ - dev->eeprom[0x46] = 0x80; /* Logical device ID2 */ - dev->eeprom[0x47] = 0x19; /* Logical device ID3 */ - dev->eeprom[0x48] = 0x02; /* Flag0 (02=BROM/disabled) */ - dev->eeprom[0x49] = 0x00; /* Flag 1 */ - - /* TAG: Compatible Device ID (NE2000) */ - dev->eeprom[0x4A] = 0x1C; /* Item byte */ - dev->eeprom[0x4B] = 0x41; /* Compatible ID0 */ - dev->eeprom[0x4C] = 0xD0; /* Compatible ID1 */ - dev->eeprom[0x4D] = 0x80; /* Compatible ID2 */ - dev->eeprom[0x4E] = 0xD6; /* Compatible ID3 */ - - /* TAG: I/O Format */ - dev->eeprom[0x4F] = 0x47; /* Item byte */ - dev->eeprom[0x50] = 0x00; /* I/O information */ - dev->eeprom[0x51] = 0x20; /* Min. I/O base bits 7-0 */ - dev->eeprom[0x52] = 0x02; /* Min. I/O base bits 15-8 */ - dev->eeprom[0x53] = 0x80; /* Max. I/O base bits 7-0 */ - dev->eeprom[0x54] = 0x03; /* Max. I/O base bits 15-8 */ - dev->eeprom[0x55] = 0x20; /* Base alignment */ - dev->eeprom[0x56] = 0x20; /* Range length */ - - /* TAG: IRQ Format. */ - dev->eeprom[0x57] = 0x23; /* Item byte */ - dev->eeprom[0x58] = 0x38; /* IRQ mask bits 7-0 */ - dev->eeprom[0x59] = 0x9E; /* IRQ mask bits 15-8 */ - dev->eeprom[0x5A] = 0x01; /* IRQ information */ - - /* TAG: END Tag */ - dev->eeprom[0x5B] = 0x79; /* Item byte */ - for (c = 0x1b; c < 0x5c; c++) /* Checksum (2's compl) */ - dev->eeprom[0x5C] += dev->eeprom[c]; - dev->eeprom[0x5C] = -dev->eeprom[0x5C]; - - io_sethandler(0x0A79, 1, - NULL, NULL, NULL, - nic_pnp_writeb, NULL, NULL, dev); + dev->pnp_card = isapnp_add_card(&dev->eeprom[0x12], sizeof(rtl8019as_pnp_rom), nic_pnp_config_changed, nic_pnp_csn_changed, nic_pnp_read_vendor_reg, nic_pnp_write_vendor_reg, dev); } } @@ -1488,227 +1139,224 @@ nic_close(void *priv) free(dev); } - -static const device_config_t ne1000_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x300, - { - { - "0x280", 0x280 - }, - { - "0x300", 0x300 - }, - { - "0x320", 0x320 - }, - { - "0x340", 0x340 - }, - { - "0x360", 0x360 - }, - { - "0x380", 0x380 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +// clang-format off +static const device_config_t ne1000_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x300, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x280", .value = 0x280 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x320", .value = 0x320 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x360", .value = 0x360 }, + { .description = "0x380", .value = 0x380 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t ne2000_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x300, - { - { - "0x280", 0x280 - }, - { - "0x300", 0x300 - }, - { - "0x320", 0x320 - }, - { - "0x340", 0x340 - }, - { - "0x360", 0x360 - }, - { - "0x380", 0x380 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 10, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "bios_addr", "BIOS address", CONFIG_HEX20, "", 0, - { - { - "Disabled", 0x00000 - }, - { - "D000", 0xD0000 - }, - { - "D800", 0xD8000 - }, - { - "C800", 0xC8000 - }, - { - "" - } - }, - }, - { - "", "", -1 - } +static const device_config_t ne2000_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x300, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x280", .value = 0x280 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x320", .value = 0x320 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x360", .value = 0x360 }, + { .description = "0x380", .value = 0x380 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 10, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, + { .description = "D000", .value = 0xD0000 }, + { .description = "D800", .value = 0xD8000 }, + { .description = "C800", .value = 0xC8000 }, + { .description = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t rtl8019as_config[] = -{ - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t rtl8019as_config[] = { + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t rtl8029as_config[] = -{ - { - "bios", "Enable BIOS", CONFIG_BINARY, "", 0 - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t rtl8029as_config[] = { + { + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t mca_mac_config[] = -{ - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t mca_mac_config[] = { + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; - - +// clang-format on const device_t ne1000_device = { - "Novell NE1000", - DEVICE_ISA, - NE2K_NE1000, - nic_init, nic_close, NULL, - NULL, NULL, NULL, - ne1000_config + .name = "Novell NE1000", + .internal_name = "ne1k", + .flags = DEVICE_ISA, + .local = NE2K_NE1000, + .init = nic_init, + .close = nic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ne1000_config }; const device_t ne2000_device = { - "Novell NE2000", - DEVICE_ISA | DEVICE_AT, - NE2K_NE2000, - nic_init, nic_close, NULL, - NULL, NULL, NULL, - ne2000_config + .name = "Novell NE2000", + .internal_name = "ne2k", + .flags = DEVICE_ISA | DEVICE_AT, + .local = NE2K_NE2000, + .init = nic_init, + .close = nic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ne2000_config }; const device_t ethernext_mc_device = { - "NetWorth EtherNext/MC", - DEVICE_MCA, - NE2K_ETHERNEXT_MC, - nic_init, nic_close, NULL, - NULL, NULL, NULL, - mca_mac_config + .name = "NetWorth EtherNext/MC", + .internal_name = "ethernextmc", + .flags = DEVICE_MCA, + .local = NE2K_ETHERNEXT_MC, + .init = nic_init, + .close = nic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mca_mac_config }; const device_t rtl8019as_device = { - "Realtek RTL8019AS", - DEVICE_ISA | DEVICE_AT, - NE2K_RTL8019AS, - nic_init, nic_close, NULL, - NULL, NULL, NULL, - rtl8019as_config + .name = "Realtek RTL8019AS", + .internal_name = "ne2kpnp", + .flags = DEVICE_ISA | DEVICE_AT, + .local = NE2K_RTL8019AS, + .init = nic_init, + .close = nic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = rtl8019as_config }; const device_t rtl8029as_device = { - "Realtek RTL8029AS", - DEVICE_PCI, - NE2K_RTL8029AS, - nic_init, nic_close, NULL, - NULL, NULL, NULL, - rtl8029as_config + .name = "Realtek RTL8029AS", + .internal_name = "ne2kpci", + .flags = DEVICE_PCI, + .local = NE2K_RTL8029AS, + .init = nic_init, + .close = nic_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = rtl8029as_config }; diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 7068443cd..c76b62581 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -55,11 +55,12 @@ #include <86box/device.h> #include <86box/plat.h> #include <86box/plat_dynld.h> +#include <86box/thread.h> #include <86box/network.h> -typedef int bpf_int32; -typedef unsigned int bpf_u_int32; +typedef int bpf_int32; +typedef unsigned int bpf_u_int32; /* * The instruction data structure. @@ -79,27 +80,27 @@ struct bpf_program { struct bpf_insn *bf_insns; }; -typedef struct pcap_if pcap_if_t; +typedef struct pcap_if pcap_if_t; -typedef struct timeval { +typedef struct net_timeval { long tv_sec; long tv_usec; -} timeval; +} net_timeval; #define PCAP_ERRBUF_SIZE 256 struct pcap_pkthdr { - struct timeval ts; + struct net_timeval ts; bpf_u_int32 caplen; bpf_u_int32 len; }; struct pcap_if { - struct pcap_if *next; - char *name; - char *description; - void *addresses; - unsigned int flags; + struct pcap_if *next; + char *name; + char *description; + void *addresses; + unsigned int flags; }; @@ -122,6 +123,7 @@ static const unsigned char *(*f_pcap_next)(void *,void *); static int (*f_pcap_sendpacket)(void *,const unsigned char *,int); static void (*f_pcap_close)(void *); +static int (*f_pcap_setnonblock)(void*, int, char*); static dllimp_t pcap_imports[] = { { "pcap_lib_version", &f_pcap_lib_version }, { "pcap_findalldevs", &f_pcap_findalldevs }, @@ -132,6 +134,7 @@ static dllimp_t pcap_imports[] = { { "pcap_next", &f_pcap_next }, { "pcap_sendpacket", &f_pcap_sendpacket }, { "pcap_close", &f_pcap_close }, + { "pcap_setnonblock", &f_pcap_setnonblock }, { NULL, NULL }, }; @@ -172,6 +175,7 @@ poll_thread(void *arg) thread_set_event(poll_state); /* Create a waitable event. */ + pcap_log("PCAP: Creating event...\n"); evt = thread_create_event(); /* As long as the channel is open.. */ @@ -179,14 +183,11 @@ poll_thread(void *arg) /* Request ownership of the device. */ network_wait(1); - /* Wait for a poll request. */ - network_poll(); - - if (pcap == NULL) + if (pcap == NULL) { + network_wait(0); break; + } - /* Wait for the next packet to arrive. */ - tx = network_tx_queue_check(); if (network_get_wait() || (poll_card->set_link_state && poll_card->set_link_state(poll_card->priv)) || (poll_card->wait && poll_card->wait(poll_card->priv))) data = NULL; else @@ -200,24 +201,23 @@ poll_thread(void *arg) mac_cmp32[1] = *(uint32_t *)mac; mac_cmp16[1] = *(uint16_t *)(mac+4); if ((mac_cmp32[0] != mac_cmp32[1]) || - (mac_cmp16[0] != mac_cmp16[1])) { - + (mac_cmp16[0] != mac_cmp16[1])) network_queue_put(0, poll_card->priv, data, h.caplen); - } else { + else { /* Mark as invalid packet. */ data = NULL; } } - if (tx) - network_do_tx(); - - /* If we did not get anything, wait a while. */ - if ((data == NULL) && !tx) - thread_wait_event(evt, 10); + /* Wait for the next packet to arrive - network_do_tx() is called from there. */ + tx = network_tx_queue_check(); /* Release ownership of the device. */ network_wait(0); + + /* If we did not get anything, wait a while. */ + if (!tx) + thread_wait_event(evt, 10); } /* No longer needed. */ @@ -225,7 +225,8 @@ poll_thread(void *arg) thread_destroy_event(evt); pcap_log("PCAP: polling stopped.\n"); - thread_set_event(poll_state); + if (poll_state != NULL) + thread_set_event(poll_state); } @@ -249,6 +250,8 @@ net_pcap_prepare(netdev_t *list) /* Try loading the DLL. */ #ifdef _WIN32 pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#elif defined __APPLE__ + pcap_handle = dynld_module("libpcap.dylib", pcap_imports); #else pcap_handle = dynld_module("libpcap.so", pcap_imports); #endif @@ -261,17 +264,21 @@ net_pcap_prepare(netdev_t *list) } for (dev=devlist; dev!=NULL; dev=dev->next) { - if (strlen(dev->name) <= 127) - strcpy(list->device, dev->name); - else - strncpy(list->device, dev->name, 127); - if (dev->description) { - if (strlen(dev->description) <= 127) - strcpy(list->description, dev->description); - else - strncpy(list->description, dev->description, 127); - } else + /** + * we initialize the strings to NULL first for strncpy + */ + + memset(list->device, '\0', sizeof(list->device)); memset(list->description, '\0', sizeof(list->description)); + + strncpy(list->device, dev->name, sizeof(list->device) - 1); + if (dev->description) { + strncpy(list->description, dev->description, sizeof(list->description) - 1); + } else { + /* if description is NULL, set the name. This allows pcap to display *something* useful under WINE */ + strncpy(list->description, dev->name, sizeof(list->description) - 1); + } + list++; i++; } @@ -334,8 +341,6 @@ net_pcap_close(void) /* Tell the thread to terminate. */ if (poll_tid != NULL) { - network_busy(0); - /* Wait for the thread to finish. */ pcap_log("PCAP: waiting for thread to end...\n"); thread_wait_event(poll_state, -1); @@ -380,6 +385,9 @@ net_pcap_reset(const netcard_t *card, uint8_t *mac) pcap_log(" Unable to open device: %s!\n", network_host); return(-1); } + if (f_pcap_setnonblock((void*)pcap, 1, errbuf) != 0) + pcap_log("PCAP: failed nonblock %s\n", errbuf); + pcap_log("PCAP: interface: %s\n", network_host); /* Create a MAC address based packet filter. */ diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 5b9ea8dc6..b4c56af53 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -40,6 +40,7 @@ #include <86box/pic.h> #include <86box/random.h> #include <86box/device.h> +#include <86box/isapnp.h> #include <86box/network.h> #include <86box/net_pcnet.h> #include <86box/bswap.h> @@ -80,7 +81,7 @@ typedef struct RTNETETHERHDR #define BCR_LED1 5 #define BCR_LED2 6 #define BCR_LED3 7 -#define BCR_RESERVED8 8 +#define BCR_SWCONFIG 8 #define BCR_FDC 9 /* 10 - 15 = reserved */ #define BCR_IOBASEL 16 /* Reserved */ @@ -189,13 +190,28 @@ typedef struct RTNETETHERHDR #define PHYSADDR(S,A) ((A) | (S)->GCUpperPhys) +static const uint8_t am79c961_pnp_rom[] = { + 0x04, 0x96, 0x55, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* ADV55AA, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x00, /* PnP version 1.0, vendor version 0.0 */ + 0x82, 0x1c, 0x00, 'A', 'M', 'D', ' ', 'E', 't', 'h', 'e', 'r', 'n', 'e', 't', ' ', 'N', 'e', 't', 'w', 'o', 'r', 'k', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r', /* ANSI identifier */ + + 0x16, 0x04, 0x96, 0x55, 0xaa, 0x00, 0xbd, /* logical device ADV55AA, supports vendor-specific registers 0x38/0x3A/0x3B/0x3C/0x3D/0x3F */ + 0x1c, 0x41, 0xd0, 0x82, 0x8c, /* compatible device PNP828C */ + 0x47, 0x00, 0x00, 0x02, 0xe0, 0x03, 0x20, 0x18, /* I/O 0x200-0x3E0, decodes 10-bit, 32-byte alignment, 24 addresses */ + 0x2a, 0xe8, 0x02, /* DMA 3/5/6/7, compatibility, no count by word, no count by byte, not bus master, 16-bit only */ + 0x23, 0x38, 0x9e, 0x09, /* IRQ 3/4/5/9/10/11/12/15, low true level sensitive, high true edge sensitive */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + + typedef struct { mem_mapping_t mmio_mapping; const char *name; int board; int is_pci, is_vlb, is_isa; int PCIBase; - int MMIOBase; + int MMIOBase; uint32_t base_address; int base_irq; int dma_channel; @@ -211,7 +227,7 @@ typedef struct { uint32_t GCRDRA; /** Address of the TX descriptor table (ring). Loaded at init. */ uint32_t GCTDRA; - uint8_t aPROM[16]; + uint8_t aPROM[256]; uint16_t aCSR[CSR_MAX_REG]; uint16_t aBCR[BCR_MAX_RAP]; uint16_t aMII[MII_MAX_REG]; @@ -242,7 +258,7 @@ typedef struct { uint32_t cMsLinkUpDelay; int transfer_size; uint8_t maclocal[6]; /* configured MAC (local) address */ - pc_timer_t timer_soft_int, timer_restore; + pc_timer_t timer, timer_soft_int, timer_restore; } nic_t; /** @todo All structs: big endian? */ @@ -370,7 +386,6 @@ static uint8_t pcnet_pci_regs[PCI_REGSIZE]; static void pcnetAsyncTransmit(nic_t *dev); static void pcnetPollRxTx(nic_t *dev); -static void pcnetPollTimer(nic_t *dev); static void pcnetUpdateIrq(nic_t *dev); static uint16_t pcnet_bcr_readw(nic_t *dev, uint16_t rap); static void pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val); @@ -410,7 +425,7 @@ pcnet_do_irq(nic_t *dev, int issue) picint(1<base_irq); else picintc(1<base_irq); - } + } } /** @@ -441,15 +456,11 @@ pcnetTmdLoad(nic_t *dev, TMD *tmd, uint32_t addr, int fRetIfNotOwn) uint16_t xda[4]; uint32_t xda32[4]; - use_phys_exec = 1; - if (BCR_SWSTYLE(dev) == 0) { dma_bm_read(addr, (uint8_t *) bytes, 4, dev->transfer_size); ownbyte = bytes[3]; - if (!(ownbyte & 0x80) && fRetIfNotOwn) { - use_phys_exec = 0; + if (!(ownbyte & 0x80) && fRetIfNotOwn) return 0; - } dma_bm_read(addr, (uint8_t*)&xda[0], sizeof(xda), dev->transfer_size); ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16); ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16); @@ -458,18 +469,14 @@ pcnetTmdLoad(nic_t *dev, TMD *tmd, uint32_t addr, int fRetIfNotOwn) } else if (BCR_SWSTYLE(dev) != 3) { dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size); ownbyte = bytes[3]; - if (!(ownbyte & 0x80) && fRetIfNotOwn) { - use_phys_exec = 0; + if (!(ownbyte & 0x80) && fRetIfNotOwn) return 0; - } dma_bm_read(addr, (uint8_t*)tmd, 16, dev->transfer_size); } else { dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size); ownbyte = bytes[3]; - if (!(ownbyte & 0x80) && fRetIfNotOwn) { - use_phys_exec = 0; + if (!(ownbyte & 0x80) && fRetIfNotOwn) return 0; - } dma_bm_read(addr, (uint8_t*)&xda32[0], sizeof(xda32), dev->transfer_size); ((uint32_t *)tmd)[0] = xda32[2]; ((uint32_t *)tmd)[1] = xda32[1]; @@ -482,8 +489,6 @@ pcnetTmdLoad(nic_t *dev, TMD *tmd, uint32_t addr, int fRetIfNotOwn) if (!(ownbyte & 0x80)) tmd->tmd1.own = 0; - use_phys_exec = 0; - return !!tmd->tmd1.own; } @@ -498,8 +503,6 @@ pcnetTmdStorePassHost(nic_t *dev, TMD *tmd, uint32_t addr) uint16_t xda[4]; uint32_t xda32[3]; - use_phys_exec = 1; - if (BCR_SWSTYLE(dev) == 0) { xda[0] = ((uint32_t *)tmd)[0] & 0xffff; xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00); @@ -529,8 +532,6 @@ pcnetTmdStorePassHost(nic_t *dev, TMD *tmd, uint32_t addr) xda32[1] &= ~0x80000000; dma_bm_write(addr, (uint8_t*)&xda32[0], sizeof(xda32), dev->transfer_size); } - - use_phys_exec = 0; } @@ -550,15 +551,11 @@ pcnetRmdLoad(nic_t *dev, RMD *rmd, uint32_t addr, int fRetIfNotOwn) uint16_t rda[4]; uint32_t rda32[4]; - use_phys_exec = 1; - if (BCR_SWSTYLE(dev) == 0) { dma_bm_read(addr, (uint8_t *) bytes, 4, dev->transfer_size); ownbyte = bytes[3]; - if (!(ownbyte & 0x80) && fRetIfNotOwn) { - use_phys_exec = 0; + if (!(ownbyte & 0x80) && fRetIfNotOwn) return 0; - } dma_bm_read(addr, (uint8_t*)&rda[0], sizeof(rda), dev->transfer_size); ((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16); ((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16); @@ -567,18 +564,14 @@ pcnetRmdLoad(nic_t *dev, RMD *rmd, uint32_t addr, int fRetIfNotOwn) } else if (BCR_SWSTYLE(dev) != 3) { dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size); ownbyte = bytes[3]; - if (!(ownbyte & 0x80) && fRetIfNotOwn) { - use_phys_exec = 0; + if (!(ownbyte & 0x80) && fRetIfNotOwn) return 0; - } dma_bm_read(addr, (uint8_t*)rmd, 16, dev->transfer_size); } else { dma_bm_read(addr + 4, (uint8_t *) bytes, 4, dev->transfer_size); ownbyte = bytes[3]; - if (!(ownbyte & 0x80) && fRetIfNotOwn) { - use_phys_exec = 0; + if (!(ownbyte & 0x80) && fRetIfNotOwn) return 0; - } dma_bm_read(addr, (uint8_t*)&rda32[0], sizeof(rda32), dev->transfer_size); ((uint32_t *)rmd)[0] = rda32[2]; ((uint32_t *)rmd)[1] = rda32[1]; @@ -588,12 +581,10 @@ pcnetRmdLoad(nic_t *dev, RMD *rmd, uint32_t addr, int fRetIfNotOwn) /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */ if (rmd->rmd1.own == 1 && !(ownbyte & 0x80)) pcnetlog(3, "%s: pcnetRmdLoad: own bit flipped while reading!!\n", dev->name); - + if (!(ownbyte & 0x80)) rmd->rmd1.own = 0; - use_phys_exec = 0; - return !!rmd->rmd1.own; } @@ -608,8 +599,6 @@ pcnetRmdStorePassHost(nic_t *dev, RMD *rmd, uint32_t addr) uint16_t rda[4]; uint32_t rda32[3]; - use_phys_exec = 1; - if (BCR_SWSTYLE(dev) == 0) { rda[0] = ((uint32_t *)rmd)[0] & 0xffff; rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00); @@ -639,8 +628,6 @@ pcnetRmdStorePassHost(nic_t *dev, RMD *rmd, uint32_t addr) rda32[1] &= ~0x80000000; dma_bm_write(addr, (uint8_t*)&rda32[0], sizeof(rda32), dev->transfer_size); } - - use_phys_exec = 0; } @@ -672,7 +659,7 @@ struct ether_header /** @todo Use RTNETETHERHDR */ #define MULTICAST_FILTER_LEN 8 -static __inline uint32_t +static __inline uint32_t lnc_mchash(const uint8_t *ether_addr) { #define LNC_POLYNOMIAL 0xEDB88320UL @@ -786,7 +773,7 @@ padr_match(nic_t *dev, const uint8_t *buf, int size) hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], padr[0],padr[1],padr[2],padr[3],padr[4],padr[5], result); - + return result; } @@ -802,7 +789,7 @@ padr_bcast(nic_t *dev, const uint8_t *buf, size_t size) } -static int +static int ladr_match(nic_t *dev, const uint8_t *buf, size_t size) { struct ether_header *hdr = (struct ether_header *)buf; @@ -827,7 +814,7 @@ ladr_match(nic_t *dev, const uint8_t *buf, size_t size) /** * Get the receive descriptor ring address with a given index. */ -static __inline uint32_t +static __inline uint32_t pcnetRdraAddr(nic_t *dev, int idx) { return dev->GCRDRA + ((CSR_RCVRL(dev) - idx) << dev->iLog2DescSize); @@ -837,23 +824,23 @@ pcnetRdraAddr(nic_t *dev, int idx) /** * Get the transmit descriptor ring address with a given index. */ -static __inline uint32_t +static __inline uint32_t pcnetTdraAddr(nic_t *dev, int idx) { return dev->GCTDRA + ((CSR_XMTRL(dev) - idx) << dev->iLog2DescSize); } -static void +static void pcnetSoftReset(nic_t *dev) { pcnetlog(3, "%s: pcnetSoftReset\n", dev->name); - + dev->u32Lnkst = 0x40; dev->GCRDRA = 0; dev->GCTDRA = 0; dev->u32RAP = 0; - + dev->aCSR[0] = 0x0004; dev->aCSR[3] = 0x0000; dev->aCSR[4] = 0x0115; @@ -885,6 +872,7 @@ pcnetSoftReset(nic_t *dev) case DEV_AM79C960: case DEV_AM79C960_EB: case DEV_AM79C960_VLB: + case DEV_AM79C961: dev->aCSR[88] = 0x3003; dev->aCSR[89] = 0x0262; break; @@ -904,10 +892,10 @@ static void pcnetUpdateIrq(nic_t *dev) { int iISR = 0; - uint16_t csr0; + uint16_t csr0; csr0 = dev->aCSR[0]; - + csr0 &= ~0x0080; /* clear INTR */ if (((csr0 & ~dev->aCSR[3]) & 0x5f00) || @@ -916,7 +904,7 @@ pcnetUpdateIrq(nic_t *dev) iISR = !!(csr0 & 0x0040); /* CSR_INEA */ csr0 |= 0x0080; /* set INTR */ } - + if (dev->aCSR[4] & 0x0080) { /* UINTCMD */ dev->aCSR[4] &= ~0x0080; /* clear UINTCMD */ dev->aCSR[4] |= 0x0040; /* set UINT */ @@ -927,25 +915,25 @@ pcnetUpdateIrq(nic_t *dev) csr0 |= 0x0080; /* set INTR */ iISR = 1; } - + if (((dev->aCSR[5]>>1) & dev->aCSR[5]) & 0x0500) { iISR = 1; csr0 |= 0x0080; /* set INTR */ } - + if ((dev->aCSR[7] & 0x0c00) == 0x0c00) /* STINT + STINTE */ iISR = 1; - + dev->aCSR[0] = csr0; - + pcnetlog(2, "%s: pcnetUpdateIrq: iISR=%d\n", dev->name, iISR); - + pcnet_do_irq(dev, iISR); dev->iISR = iISR; } -static void +static void pcnetInit(nic_t *dev) { int i; @@ -954,10 +942,8 @@ pcnetInit(nic_t *dev) /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement! * Software is allowed to write these registers directly. */ #define PCNET_INIT() do { \ - use_phys_exec = 1; \ dma_bm_read(PHYSADDR(dev, CSR_IADR(dev)), \ (uint8_t *)&initblk, sizeof(initblk), dev->transfer_size); \ - use_phys_exec = 0; \ dev->aCSR[15] = le16_to_cpu(initblk.mode); \ CSR_RCVRL(dev) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ CSR_XMTRL(dev) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ @@ -1036,7 +1022,7 @@ pcnetInit(nic_t *dev) /** * Start RX/TX operation. */ -static void +static void pcnetStart(nic_t *dev) { pcnetlog(3, "%s: pcnetStart: Poll timer\n", dev->name); @@ -1050,22 +1036,22 @@ pcnetStart(nic_t *dev) if (!CSR_DRX(dev)) dev->aCSR[0] |= 0x0020; /* set RXON */ dev->aCSR[0] &= ~0x0004; /* clear STOP bit */ - dev->aCSR[0] |= 0x0002; /* STRT */ - pcnetPollTimer(dev); + dev->aCSR[0] |= 0x0002; /* STRT */ + timer_set_delay_u64(&dev->timer, 2000 * TIMER_USEC); } /** * Stop RX/TX operation. */ -static void +static void pcnetStop(nic_t *dev) { pcnetlog(3, "%s: pcnetStop: Poll timer\n", dev->name); dev->aCSR[0] = 0x0004; dev->aCSR[4] &= ~0x02c2; dev->aCSR[5] &= ~0x0011; - pcnetPollTimer(dev); + timer_disable(&dev->timer); } @@ -1075,7 +1061,7 @@ pcnetStop(nic_t *dev) * by the host (the guest driver) anymore. Well, it could but the results are undefined by * definition. */ -static void +static void pcnetRdtePoll(nic_t *dev) { /* assume lack of a next receive descriptor */ @@ -1153,7 +1139,7 @@ pcnetRdtePoll(nic_t *dev) * Poll Transmit Descriptor Table Entry * @return true if transmit descriptors available */ -static int +static int pcnetTdtePoll(nic_t *dev, TMD *tmd) { if (dev->GCTDRA) { @@ -1191,7 +1177,7 @@ pcnetTdtePoll(nic_t *dev, TMD *tmd) * Poll Transmit Descriptor Table Entry * @return true if transmit descriptors available */ -static int +static int pcnetCalcPacketLen(nic_t *dev, int cb) { TMD tmd; @@ -1238,7 +1224,7 @@ pcnetCalcPacketLen(nic_t *dev, int cb) /** * Write data into guest receive buffers. */ -static void +static int pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) { nic_t *dev = (nic_t *)priv; @@ -1248,7 +1234,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) uint8_t buf1[60]; if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev) || !size) - return; + return 0; /* if too small buffer, then expand it */ if (size < 60) { @@ -1257,12 +1243,12 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) buf = buf1; size = 60; } - + /* * Drop packets if the cable is not connected */ if (!pcnetIsLinkUp(dev)) - return; + return 0; pcnetlog(1, "%s: pcnetReceiveNoSync: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", dev->name, buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], @@ -1282,7 +1268,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) if (HOST_IS_OWNER(CSR_CRST(dev))) { /* Not owned by controller. This should not be possible as - * we already called pcnetCanReceive(). */ + * we already called pcnetCanReceive(). */ const unsigned cb = 1 << dev->iLog2DescSize; uint32_t GCPhys = dev->GCRDRA; iRxDesc = CSR_RCVRL(dev); @@ -1303,7 +1289,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) uint32_t crda = CSR_CRDA(dev); uint32_t next_crda; RMD rmd, next_rmd; - + /* * Ethernet framing considers these two octets to be * payload type; 802.3 framing considers them to be @@ -1317,7 +1303,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) if (len_802_3 < 46 && CSR_ASTRP_RCV(dev)) { size = MIN(sizeof(RTNETETHERHDR) + len_802_3, size); fStrip = 1; - } + } memcpy(src, buf, size); @@ -1328,7 +1314,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) if (!CSR_LOOP(dev)) while (size < 60) src[size++] = 0; - + uint32_t fcs = UINT32_MAX; uint8_t *p = src; @@ -1340,7 +1326,7 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) size += 4; } - cbPacket = (int)size; + cbPacket = (int)size; pcnetRmdLoad(dev, &rmd, PHYSADDR(dev, crda), 0); /* if (!CSR_LAPPEN(dev)) */ @@ -1363,14 +1349,12 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) * - we don't cache any register state beyond this point */ - use_phys_exec = 1; dma_bm_write(rbadr, src, cbBuf, dev->transfer_size); - use_phys_exec = 0; - + /* RX disabled in the meantime? If so, abort RX. */ if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev)) { pcnetlog(3, "%s: RX disabled 1\n", dev->name); - return; + return 0; } /* Was the register modified in the meantime? If so, don't touch the @@ -1408,14 +1392,12 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) /* We have to leave the critical section here or we risk deadlocking * with EMT when the write is to an unallocated page or has an access * handler associated with it. See above for additional comments. */ - use_phys_exec = 1; dma_bm_write(rbadr2, src, cbBuf, dev->transfer_size); - use_phys_exec = 0; /* RX disabled in the meantime? If so, abort RX. */ if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev)) { pcnetlog(3, "%s: RX disabled 2\n", dev->name); - return; + return 0; } /* Was the register modified in the meantime? If so, don't touch the @@ -1452,13 +1434,15 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) dev->aCSR[0] |= 0x0400; pcnetlog(1, "%s: RINT set, RCVRC=%d CRDA=%#010x\n", dev->name, CSR_RCVRC(dev), PHYSADDR(dev, CSR_CRDA(dev))); - + /* guest driver is owner: force repoll of current and next RDTEs */ CSR_CRST(dev) = 0; } } pcnetUpdateIrq(dev); + + return 1; } /** @@ -1489,7 +1473,7 @@ pcnetXmitFailTMDGeneric(nic_t *dev, TMD *pTmd) * * @threads TX or EMT. */ -static void +static void pcnetAsyncTransmit(nic_t *dev) { /* @@ -1517,7 +1501,7 @@ pcnetAsyncTransmit(nic_t *dev) break; pcnetlog(3, "%s: TMDLOAD %#010x\n", dev->name, PHYSADDR(dev, CSR_CXDA(dev))); - + int fLoopback = CSR_LOOP(dev); /* @@ -1525,28 +1509,26 @@ pcnetAsyncTransmit(nic_t *dev) */ if (tmd.tmd1.stp && tmd.tmd1.enp) { const int cb = 4096 - tmd.tmd1.bcnt; - pcnetlog("%s: pcnetAsyncTransmit: stp&enp: cb=%d xmtrc=%#x\n", dev->name, cb, CSR_XMTRC(dev)); + pcnetlog("%s: pcnetAsyncTransmit: stp&enp: cb=%d xmtrc=%#x\n", dev->name, cb, CSR_XMTRC(dev)); if ((pcnetIsLinkUp(dev) || fLoopback)) { - + /* From the manual: ``A zero length buffer is acceptable as * long as it is not the last buffer in a chain (STP = 0 and * ENP = 1).'' That means that the first buffer might have a * zero length if it is not the last one in the chain. */ if (cb <= MAX_FRAME) { dev->xmit_pos = cb; - use_phys_exec = 1; dma_bm_read(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb, dev->transfer_size); - use_phys_exec = 0; if (fLoopback) { if (HOST_IS_OWNER(CSR_CRST(dev))) pcnetRdtePoll(dev); - pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); + pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); } else { pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf stp and enp, xmit pos = %d\n", dev->name, dev->xmit_pos); - network_tx(dev->abLoopBuf, dev->xmit_pos); + network_tx(dev->abLoopBuf, dev->xmit_pos); } } else if (cb == 4096) { /* The Windows NT4 pcnet driver sometimes marks the first @@ -1554,13 +1536,13 @@ pcnetAsyncTransmit(nic_t *dev) * passing it back). Do not update the ring counter in this * case (otherwise that driver becomes even more confused, * which causes transmit to stall for about 10 seconds). - * This is just a workaround, not a final solution. + * This is just a workaround, not a final solution. */ /* r=frank: IMHO this is the correct implementation. The * manual says: ``If the OWN bit is set and the buffer * length is 0, the OWN bit will be cleared. In the C-LANCE * the buffer length of 0 is interpreted as a 4096-byte - * buffer.'' + * buffer.'' */ /* r=michaln: Perhaps not quite right. The C-LANCE (Am79C90) * datasheet explains that the old LANCE (Am7990) ignored @@ -1603,9 +1585,7 @@ pcnetAsyncTransmit(nic_t *dev) */ unsigned cb = 4096 - tmd.tmd1.bcnt; dev->xmit_pos = pcnetCalcPacketLen(dev, cb); - use_phys_exec = 1; dma_bm_read(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb, dev->transfer_size); - use_phys_exec = 0; for (;;) { /* @@ -1644,9 +1624,7 @@ pcnetAsyncTransmit(nic_t *dev) if (dev->xmit_pos + cb <= MAX_FRAME) { /** @todo this used to be ... + cb < MAX_FRAME. */ int off = dev->xmit_pos; dev->xmit_pos = cb + off; - use_phys_exec = 1; dma_bm_read(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf + off, cb, dev->transfer_size); - use_phys_exec = 0; } /* @@ -1658,12 +1636,12 @@ pcnetAsyncTransmit(nic_t *dev) pcnetRdtePoll(dev); pcnetlog(3, "%s: pcnetAsyncTransmit: receive loopback enp\n", dev->name); - pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); + pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); } else { pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf enp\n", dev->name); network_tx(dev->abLoopBuf, dev->xmit_pos); } - + /* Write back the TMD, pass it to the host */ pcnetTmdStorePassHost(dev, &tmd, PHYSADDR(dev, CSR_CXDA(dev))); @@ -1688,20 +1666,20 @@ pcnetAsyncTransmit(nic_t *dev) if (--cMax == 0) break; } while (CSR_TXON(dev)); /* transfer on */ - + if (cFlushIrq) { dev->aCSR[0] |= 0x0200; /* set TINT */ /* Don't allow the guest to clear TINT before reading it */ dev->u16CSR0LastSeenByGuest &= ~0x0200; pcnetUpdateIrq(dev); - } + } } /** * Poll for changes in RX and TX descriptor rings. */ -static void +static void pcnetPollRxTx(nic_t *dev) { if (CSR_RXON(dev)) { @@ -1720,8 +1698,12 @@ pcnetPollRxTx(nic_t *dev) static void -pcnetPollTimer(nic_t *dev) +pcnetPollTimer(void *p) { + nic_t *dev = (nic_t *)p; + + timer_advance_u64(&dev->timer, 2000 * TIMER_USEC); + if (CSR_TDMD(dev)) pcnetAsyncTransmit(dev); @@ -1748,10 +1730,6 @@ pcnetHardReset(nic_t *dev) dev->aBCR[BCR_LED1] = 0x0084; dev->aBCR[BCR_LED2] = 0x0088; dev->aBCR[BCR_LED3] = 0x0090; - - /* For ISA PnP cards, BCR8 reports IRQ/DMA (e.g. 0x0035 means IRQ 3, DMA 5). */ - if (dev->is_isa) - dev->aBCR[8] = dev->dma_channel | (dev->base_irq << 4); dev->aBCR[BCR_FDC] = 0x0000; dev->aBCR[BCR_BSBC] = 0x9001; @@ -1767,13 +1745,13 @@ pcnetHardReset(nic_t *dev) dev->aBCR[BCR_PCISVID] = 0x1022; /* Reset the error counter. */ - dev->uCntBadRMD = 0; + dev->uCntBadRMD = 0; pcnetSoftReset(dev); } -static void +static void pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val) { pcnetlog(1, "%s: pcnet_csr_writew: rap=%d val=%#06x\n", dev->name, rap, val); @@ -1781,7 +1759,7 @@ pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val) case 0: { uint16_t csr0 = dev->aCSR[0]; - /* Clear any interrupt flags. + /* Clear any interrupt flags. * Don't clear an interrupt flag which was not seen by the guest yet. */ csr0 &= ~(val & 0x7f00 & dev->u16CSR0LastSeenByGuest); csr0 = (csr0 & ~0x0040) | (val & 0x0048); @@ -1864,12 +1842,12 @@ pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val) break; case 4: /* Test and Features Control */ dev->aCSR[4] &= ~(val & 0x026a); - val &= ~0x026a; + val &= ~0x026a; val |= dev->aCSR[4] & 0x026a; break; case 5: /* Extended Control and Interrupt 1 */ dev->aCSR[5] &= ~(val & 0x0a90); - val &= ~0x0a90; + val &= ~0x0a90; val |= dev->aCSR[5] & 0x0a90; break; case 7: /* Extended Control and Interrupt 2 */ @@ -1921,12 +1899,12 @@ pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val) dev->GCTDRA = (dev->GCTDRA & 0xffff0000) | (val & 0x0000ffff); else dev->GCTDRA = (dev->GCTDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16); - + pcnetlog(3, "%s: WRITE CSR%d, %#06x => GCTDRA=%08x (alt init)\n", dev->name, rap, val, dev->GCTDRA); if (dev->GCTDRA & (dev->iLog2DescSize - 1)) pcnetlog(1, "%s: Warning: Misaligned TDRA (GCTDRA=%#010x)\n", dev->name, dev->GCTDRA); - break; + break; case 58: /* Software Style */ pcnet_bcr_writew(dev,BCR_SWS,val); break; @@ -1950,7 +1928,7 @@ pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val) * HACK ALERT! Set the counter registers too. */ dev->aCSR[rap - 4] = val; - break; + break; default: return; } @@ -1995,11 +1973,6 @@ pcnet_csr_readw(nic_t *dev, uint16_t rap) return pcnet_bcr_readw(dev,BCR_SWS); case 68: /* Custom register to pass link speed to driver */ return pcnetLinkSpd(dev->u32LinkSpeed); - case 88: - val = dev->aCSR[89]; - val <<= 16; - val |= dev->aCSR[88]; - break; default: val = dev->aCSR[rap]; break; @@ -2060,22 +2033,22 @@ pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val) if (dev->board == DEV_AM79C973) timer_set_delay_u64(&dev->timer_soft_int, (12.8 * val) * TIMER_USEC); break; - + case BCR_MIIMDR: dev->aMII[dev->aBCR[BCR_MIIADDR] & 0x1f] = val; break; - + default: break; } } -static uint16_t +static uint16_t pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) { uint16_t val; int autoneg, duplex, fast, isolate; - + /* If the DANAS (BCR32.7) bit is set, the MAC does not do any * auto-negotiation and the PHY must be set up explicitly. DANAS * effectively disables most other BCR32 bits. @@ -2089,10 +2062,10 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) duplex = (dev->aBCR[BCR_MIICAS] & 0x10) != 0; fast = (dev->aBCR[BCR_MIICAS] & 0x08) != 0; } - + /* Electrically isolating the PHY mostly disables it. */ isolate = (dev->aMII[0] & 0x400) != 0; - + switch (miiaddr) { case 0: /* MII basic mode control register. */ @@ -2132,17 +2105,17 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) val &= ~0x6000; /* 10 Mbps forced */ } break; - + case 2: /* PHY identifier 1. */ val = 0x22; /* Am79C874/AC101 PHY */ break; - + case 3: /* PHY identifier 2. */ val = 0x561b; /* Am79C874/AC101 PHY */ break; - + case 4: /* Advertisement control register. */ val = 0x01e0 /* Try 100mbps FD/HD and 10mbps FD/HD. */ @@ -2174,13 +2147,13 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) dev->cLinkDownReported++; } break; - + case 18: /* Diagnostic Register (FreeBSD pcn/ac101 driver reads this). */ if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) { val = 0x1000 /* Receive PLL locked. */ | 0x0200; /* Signal detected. */ - + if (autoneg) { val |= 0x0400 /* 100Mbps rate. */ | 0x0800; /* Full duplex. */ @@ -2195,16 +2168,16 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) dev->cLinkDownReported++; } break; - + default: val = 0; break; } - + return val; } -static uint16_t +static uint16_t pcnet_bcr_readw(nic_t *dev, uint16_t rap) { uint16_t val; @@ -2222,14 +2195,22 @@ pcnet_bcr_readw(nic_t *dev, uint16_t rap) } val |= (val & 0x017f & dev->u32Lnkst) ? 0x8000 : 0; break; - - case BCR_MIIADDR: + + case BCR_MIIMDR: if ((dev->board == DEV_AM79C973) && (((dev->aBCR[BCR_MIIADDR] >> 5) & 0x1f) == 0)) { uint16_t miiaddr = dev->aBCR[BCR_MIIADDR] & 0x1f; val = pcnet_mii_readw(dev, miiaddr); } else val = 0xffff; break; + + case BCR_SWCONFIG: + if (dev->board == DEV_AM79C961) + val = ((dev->base_irq & 0x0f) << 4) | (dev->dma_channel & 0x07); + else + val = 0xffff; + break; + default: val = rap < BCR_MAX_RAP ? dev->aBCR[rap] : 0; break; @@ -2248,7 +2229,7 @@ pcnet_word_write(nic_t *dev, uint32_t addr, uint16_t val) if (!BCR_DWIO(dev)) { switch (addr & 0x0f) { case 0x00: /* RDP */ - pcnetPollTimer(dev); + timer_set_delay_u64(&dev->timer, 2000 * TIMER_USEC); pcnet_csr_writew(dev, dev->u32RAP, val); pcnetUpdateIrq(dev); break; @@ -2262,10 +2243,30 @@ pcnet_word_write(nic_t *dev, uint32_t addr, uint16_t val) } } +static uint8_t +pcnet_byte_read(nic_t *dev, uint32_t addr) +{ + uint8_t val = 0xff; + + if (!BCR_DWIO(dev)) { + switch (addr & 0x0f) { + case 0x04: + pcnetSoftReset(dev); + val = 0; + break; + } + } + + pcnetUpdateIrq(dev); + + pcnetlog(3, "%s: pcnet_word_read: addr = %04x, val = %04x, DWIO not set = %04x\n", dev->name, addr & 0x0f, val, !BCR_DWIO(dev)); + + return(val); +} static uint16_t pcnet_word_read(nic_t *dev, uint32_t addr) -{ +{ uint16_t val = 0xffff; if (!BCR_DWIO(dev)) { @@ -2274,8 +2275,8 @@ pcnet_word_read(nic_t *dev, uint32_t addr) /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */ /** Polling is then useless here and possibly expensive. */ if (!CSR_DPOLL(dev)) - pcnetPollTimer(dev); - + timer_set_delay_u64(&dev->timer, 2000 * TIMER_USEC); + val = pcnet_csr_readw(dev, dev->u32RAP); if (dev->u32RAP == 0) goto skip_update_irq; @@ -2302,13 +2303,13 @@ skip_update_irq: } -static void +static void pcnet_dword_write(nic_t *dev, uint32_t addr, uint32_t val) { if (BCR_DWIO(dev)) { switch (addr & 0x0f) { case 0x00: /* RDP */ - pcnetPollTimer(dev); + timer_set_delay_u64(&dev->timer, 2000 * TIMER_USEC); pcnet_csr_writew(dev, dev->u32RAP, val & 0xffff); pcnetUpdateIrq(dev); break; @@ -2329,14 +2330,14 @@ pcnet_dword_write(nic_t *dev, uint32_t addr, uint32_t val) static uint32_t pcnet_dword_read(nic_t *dev, uint32_t addr) -{ +{ uint32_t val = 0xffffffff; if (BCR_DWIO(dev)) { switch (addr & 0x0f) { case 0x00: /* RDP */ if (!CSR_DPOLL(dev)) - pcnetPollTimer(dev); + timer_set_delay_u64(&dev->timer, 2000 * TIMER_USEC); val = pcnet_csr_readw(dev, dev->u32RAP); if (dev->u32RAP == 0) goto skip_update_irq; @@ -2362,7 +2363,7 @@ skip_update_irq: } -static void +static void pcnet_aprom_writeb(nic_t *dev, uint32_t addr, uint32_t val) { /* Check APROMWE bit to enable write access */ @@ -2371,7 +2372,7 @@ pcnet_aprom_writeb(nic_t *dev, uint32_t addr, uint32_t val) } -static uint32_t +static uint32_t pcnet_aprom_readb(nic_t *dev, uint32_t addr) { uint32_t val = dev->aPROM[addr & 15]; @@ -2447,7 +2448,9 @@ pcnet_read(nic_t *dev, uint32_t addr, int len) (pcnet_aprom_readb(dev, addr + 2) << 16) | (pcnet_aprom_readb(dev, addr + 3) << 24); } } else { - if (len == 2) + if (len == 1) + retval = pcnet_byte_read(dev, addr); + else if (len == 2) retval = pcnet_word_read(dev, addr); else if (len == 4) retval = pcnet_dword_read(dev, addr); @@ -2547,7 +2550,7 @@ pcnet_mem_disable(nic_t *dev) static void pcnet_ioremove(nic_t *dev, uint16_t addr, int len) -{ +{ if (dev->is_pci || dev->is_vlb) { io_removehandler(addr, len, pcnet_readb, pcnet_readw, pcnet_readl, @@ -2562,7 +2565,7 @@ pcnet_ioremove(nic_t *dev, uint16_t addr, int len) static void pcnet_ioset(nic_t *dev, uint16_t addr, int len) -{ +{ pcnet_ioremove(dev, addr, len); if (dev->is_pci || dev->is_vlb) { @@ -2572,7 +2575,7 @@ pcnet_ioset(nic_t *dev, uint16_t addr, int len) } else { io_sethandler(addr, len, pcnet_readb, pcnet_readw, NULL, - pcnet_writeb, pcnet_writew, NULL, dev); + pcnet_writeb, pcnet_writew, NULL, dev); } } @@ -2643,10 +2646,10 @@ pcnet_pci_write(int func, int addr, uint8_t val, void *p) if (dev->MMIOBase != 0) pcnet_mem_set_addr(dev, dev->MMIOBase); } - return; + return; case 0x3C: - dev->base_irq = val; + dev->base_irq = val; pcnet_pci_regs[addr] = val; return; } @@ -2726,6 +2729,65 @@ pcnet_pci_read(int func, int addr, void *p) return(0); } +static void +pcnet_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld) + return; + + nic_t *dev = (nic_t *) priv; + + dev->base_address = 0; + dev->base_irq = 0; + dev->dma_channel = -1; + + if (dev->base_address) { + pcnet_ioremove(dev, dev->base_address, 0x20); + dev->base_address = 0; + } + + if (config->activate) { + dev->base_address = config->io[0].base; + if (dev->base_address != ISAPNP_IO_DISABLED) + pcnet_ioset(dev, dev->base_address, 0x20); + + dev->base_irq = config->irq[0].irq; + dev->dma_channel = config->dma[0].dma; + if (dev->dma_channel == ISAPNP_DMA_DISABLED) + dev->dma_channel = -1; + + /* Update PnP register mirrors in ROM. */ + dev->aPROM[32] = dev->base_address >> 8; + dev->aPROM[33] = dev->base_address; + dev->aPROM[34] = dev->base_irq; + dev->aPROM[35] = (config->irq[0].level << 1) | config->irq[0].type; + dev->aPROM[36] = (dev->dma_channel == -1) ? ISAPNP_DMA_DISABLED : dev->dma_channel; + } +} + +static uint8_t +pcnet_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) +{ + nic_t *dev = (nic_t *) priv; + + if (!ld && (reg == 0xf0)) + return dev->aPROM[50]; + else + return 0x00; +} + +static void +pcnet_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) +{ + if (ld) + return; + + nic_t *dev = (nic_t *) priv; + + if (reg == 0xf0) + dev->aPROM[50] = val & 0x1f; +} + /** * Takes down the link temporarily if it's current status is up. * @@ -2737,7 +2799,7 @@ pcnet_pci_read(int func, int addr, void *p) * * @param pThis The PCnet shared instance data. */ -static void +static void pcnetTempLinkDown(nic_t *dev) { if (dev->fLinkUp) { @@ -2793,12 +2855,12 @@ pcnetSetLinkState(void *priv) { nic_t *dev = (nic_t *) priv; int fLinkUp; - + if (dev->fLinkTempDown) { pcnetTempLinkDown(dev); return 1; } - + fLinkUp = (dev->fLinkUp && !dev->fLinkTempDown); if (dev->fLinkUp != fLinkUp) { dev->fLinkUp = fLinkUp; @@ -2812,7 +2874,7 @@ pcnetSetLinkState(void *priv) dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */ } } - + return 0; } @@ -2830,7 +2892,7 @@ static void pcnetTimerRestore(void *priv) { nic_t *dev = (nic_t *) priv; - + if (dev->cLinkDownReported <= PCNET_MAX_LINKDOWN_REPORTED) { timer_advance_u64(&dev->timer_restore, 1500000 * TIMER_USEC); } else { @@ -2846,18 +2908,9 @@ pcnet_init(const device_t *info) { uint32_t mac; nic_t *dev; -#ifdef ENABLE_NIC_LOG - int i; -#endif int c; uint16_t checksum; - /* Get the desired debug level. */ -#ifdef ENABLE_NIC_LOG - i = device_get_config_int("debug"); - if (i > 0) pcnet_do_log = i; -#endif - dev = malloc(sizeof(nic_t)); memset(dev, 0x00, sizeof(nic_t)); dev->name = info->name; @@ -2876,10 +2929,10 @@ pcnet_init(const device_t *info) pcnet_mem_init(dev, 0x0fffff00); pcnet_mem_disable(dev); } - + dev->fLinkUp = 1; dev->cMsLinkUpDelay = 5000; - + if (dev->board == DEV_AM79C960_EB) { dev->maclocal[0] = 0x02; /* 02:07:01 (Racal OID) */ dev->maclocal[1] = 0x07; @@ -2923,6 +2976,8 @@ pcnet_init(const device_t *info) dev->aPROM[9] = 0x11; else if (dev->is_vlb) dev->aPROM[9] = 0x10; + else if (dev->board == DEV_AM79C961) + dev->aPROM[9] = 0x01; else dev->aPROM[9] = 0x00; @@ -2935,7 +2990,7 @@ pcnet_init(const device_t *info) } else { /* Must be ASCII W (57h) if compatibility to AMD driver software is desired */ - dev->aPROM[14] = dev->aPROM[15] = 0x57; + dev->aPROM[14] = dev->aPROM[15] = 0x57; } for (c = 0, checksum = 0; c < 16; c++) @@ -2962,6 +3017,18 @@ pcnet_init(const device_t *info) /* Add device to the PCI bus, keep its slot number. */ dev->card = pci_add_card(PCI_ADD_NORMAL, pcnet_pci_read, pcnet_pci_write, dev); + } else if (dev->board == DEV_AM79C961) { + dev->dma_channel = -1; + + /* Weird secondary checksum. The datasheet isn't clear on what + role it might play with the PnP register mirrors before it. */ + for (c = 0, checksum = 0; c < 54; c++) + checksum += dev->aPROM[c]; + + dev->aPROM[51] = checksum; + + memcpy(&dev->aPROM[0x40], am79c961_pnp_rom, sizeof(am79c961_pnp_rom)); + isapnp_add_card(&dev->aPROM[0x40], sizeof(am79c961_pnp_rom), pcnet_pnp_config_changed, NULL, pcnet_pnp_read_vendor_reg, pcnet_pnp_write_vendor_reg, dev); } else { dev->base_address = device_get_config_hex16("base"); dev->base_irq = device_get_config_int("irq"); @@ -2986,6 +3053,8 @@ pcnet_init(const device_t *info) /* Attach ourselves to the network module. */ network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState); + timer_add(&dev->timer, pcnetPollTimer, dev, 0); + if (dev->board == DEV_AM79C973) timer_add(&dev->timer_soft_int, pcnetTimerSoftInt, dev, 0); @@ -3001,190 +3070,212 @@ pcnet_close(void *priv) nic_t *dev = (nic_t *)priv; pcnetlog(1, "%s: closed\n", dev->name); - + /* Make sure the platform layer is shut down. */ network_close(); - + if (dev) { free(dev); dev = NULL; - + } } - -static const device_config_t pcnet_pci_config[] = -{ - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +// clang-format off +static const device_config_t pcnet_pci_config[] = { + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; - -static const device_config_t pcnet_isa_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x300, - { - { - "0x300", 0x300 - }, - { - "0x320", 0x320 - }, - { - "0x340", 0x340 - }, - { - "0x360", 0x360 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 9", 9 - }, - { - "" - } - }, - }, - { - "dma", "DMA channel", CONFIG_SELECTION, "", 5, - { - { - "DMA 3", 3 - }, - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t pcnet_isa_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x300, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x300", .value = 0x300 }, + { .description = "0x320", .value = 0x320 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x360", .value = 0x360 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 9", .value = 9 }, + { .description = "" } + }, + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 3", .value = 3 }, + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t pcnet_vlb_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x300, - { - { - "0x300", 0x300 - }, - { - "0x320", 0x320 - }, - { - "0x340", 0x340 - }, - { - "0x360", 0x360 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 9", 9 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t pcnet_vlb_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x300, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x300", .value = 0x300 }, + { .description = "0x320", .value = 0x320 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x360", .value = 0x360 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 9", .value = 9 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; +// clang-format on const device_t pcnet_am79c960_device = { - "AMD Am79c960 (PCnet-ISA) ", - DEVICE_AT | DEVICE_ISA, - DEV_AM79C960, - pcnet_init, pcnet_close, NULL, - NULL, NULL, NULL, - pcnet_isa_config + .name = "AMD PCnet-ISA", + .internal_name = "pcnetisa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = DEV_AM79C960, + .init = pcnet_init, + .close = pcnet_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pcnet_isa_config }; const device_t pcnet_am79c960_eb_device = { - "AMD Am79c960EB (PCnet-ISA) ", - DEVICE_AT | DEVICE_ISA, - DEV_AM79C960_EB, - pcnet_init, pcnet_close, NULL, - NULL, NULL, NULL, - pcnet_isa_config + .name = "Racal Interlan EtherBlaster", + .internal_name = "pcnetracal", + .flags = DEVICE_AT | DEVICE_ISA, + .local = DEV_AM79C960_EB, + .init = pcnet_init, + .close = pcnet_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pcnet_isa_config }; const device_t pcnet_am79c960_vlb_device = { - "AMD Am79c960 (PCnet-VL) ", - DEVICE_VLB, - DEV_AM79C960_VLB, - pcnet_init, pcnet_close, NULL, - NULL, NULL, NULL, - pcnet_vlb_config + .name = "AMD PCnet-VL", + .internal_name = "pcnetvlb", + .flags = DEVICE_VLB, + .local = DEV_AM79C960_VLB, + .init = pcnet_init, + .close = pcnet_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pcnet_vlb_config +}; + +const device_t pcnet_am79c961_device = { + .name = "AMD PCnet-ISA+", + .internal_name = "pcnetisaplus", + .flags = DEVICE_AT | DEVICE_ISA, + .local = DEV_AM79C961, + .init = pcnet_init, + .close = pcnet_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pcnet_pci_config }; const device_t pcnet_am79c970a_device = { - "AMD Am79c970a (PCnet-PCI II)", - DEVICE_PCI, - DEV_AM79C970A, - pcnet_init, pcnet_close, NULL, - NULL, NULL, NULL, - pcnet_pci_config + .name = "AMD PCnet-PCI II", + .internal_name = "pcnetpci", + .flags = DEVICE_PCI, + .local = DEV_AM79C970A, + .init = pcnet_init, + .close = pcnet_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pcnet_pci_config }; const device_t pcnet_am79c973_device = { - "AMD Am79c973 (PCnet-FAST)", - DEVICE_PCI, - DEV_AM79C973, - pcnet_init, pcnet_close, NULL, - NULL, NULL, NULL, - pcnet_pci_config + .name = "AMD PCnet-FAST III", + .internal_name = "pcnetfast", + .flags = DEVICE_PCI, + .local = DEV_AM79C973, + .init = pcnet_init, + .close = pcnet_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pcnet_pci_config }; diff --git a/src/network/net_plip.c b/src/network/net_plip.c new file mode 100644 index 000000000..6da355632 --- /dev/null +++ b/src/network/net_plip.c @@ -0,0 +1,517 @@ +/* + * 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 a PLIP parallel port network device. + * + * Tested against the Linux plip.c driver and the DOS plip.com + * packet driver. PLIP is not particularly fast, as it's a 4-bit + * half-duplex protocol operating over SPP. + * + * + * + * Author: RichardG, + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/language.h> +#include <86box/lpt.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/device.h> +#include <86box/network.h> +#include <86box/net_plip.h> + + +enum { + PLIP_START = 0x00, + PLIP_TX_LEN_LSB_LOW = 0x10, + PLIP_TX_LEN_LSB_HIGH, + PLIP_TX_LEN_MSB_LOW, + PLIP_TX_LEN_MSB_HIGH, + PLIP_TX_DATA_LOW, + PLIP_TX_DATA_HIGH, + PLIP_TX_CHECKSUM_LOW, + PLIP_TX_CHECKSUM_HIGH, + PLIP_RX_LEN_LSB_LOW = 0x20, + PLIP_RX_LEN_LSB_HIGH, + PLIP_RX_LEN_MSB_LOW, + PLIP_RX_LEN_MSB_HIGH, + PLIP_RX_DATA_LOW, + PLIP_RX_DATA_HIGH, + PLIP_RX_CHECKSUM_LOW, + PLIP_RX_CHECKSUM_HIGH, + PLIP_END = 0x40 +}; + +typedef struct +{ + uint8_t mac[6]; + + void *lpt; + pc_timer_t rx_timer; + pc_timer_t timeout_timer; + uint8_t status, ctrl; + + uint8_t state, ack, tx_checksum, tx_checksum_calc, *tx_pkt; + uint16_t tx_len, tx_ptr; + + uint8_t *rx_pkt, rx_checksum, rx_return_state; + uint16_t rx_len, rx_ptr; +} plip_t; + + +static void plip_receive_packet(plip_t *dev); + +plip_t *instance; + + +#ifdef ENABLE_PLIP_LOG +int plip_do_log = ENABLE_PLIP_LOG; + +static void +plip_log(uint8_t lvl, const char *fmt, ...) +{ + va_list ap; + + if (plip_do_log >= lvl) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define plip_log(lvl, fmt, ...) +#endif + + +static void +timeout_timer(void *priv) +{ + plip_t *dev = (plip_t *) priv; + + plip_log(1, "PLIP: timeout at state %d status %02X\n", dev->state, dev->status); + + /* Throw everything out the window. */ + dev->state = PLIP_START; + dev->status = 0x80; + + if (dev->tx_pkt) { + free(dev->tx_pkt); + dev->tx_pkt = NULL; + } + if (dev->rx_pkt) { + free(dev->rx_pkt); + dev->rx_pkt = NULL; + } + + network_rx_pause = 0; + + timer_disable(&dev->timeout_timer); +} + + +static void +plip_write_data(uint8_t val, void *priv) +{ + plip_t *dev = (plip_t *) priv; + + plip_log(3, "PLIP: write_data(%02X)\n", val); + + switch (dev->state) { + case PLIP_START: + if (val == 0x08) { /* D3/ACK wakes us up */ + plip_log(2, "PLIP: ACK wakeup\n"); + dev->state = PLIP_TX_LEN_LSB_LOW; + dev->status = 0x08; + break; + } + return; + + case PLIP_TX_LEN_LSB_LOW: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + dev->tx_len = val & 0xf; + plip_log(2, "PLIP: tx_len = %04X (1/4)\n", dev->tx_len); + dev->state = PLIP_TX_LEN_LSB_HIGH; + dev->status &= ~0x88; + break; + + case PLIP_TX_LEN_LSB_HIGH: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + dev->tx_len |= (val & 0xf) << 4; + plip_log(2, "PLIP: tx_len = %04X (2/4)\n", dev->tx_len); + dev->state = PLIP_TX_LEN_MSB_LOW; + dev->status |= 0x80; + break; + + case PLIP_TX_LEN_MSB_LOW: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + dev->tx_len |= (val & 0xf) << 8; + plip_log(2, "PLIP: tx_len = %04X (3/4)\n", dev->tx_len); + dev->state = PLIP_TX_LEN_MSB_HIGH; + dev->status &= ~0x80; + break; + + case PLIP_TX_LEN_MSB_HIGH: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + dev->tx_len |= (val & 0xf) << 12; + plip_log(2, "PLIP: tx_len = %04X (4/4)\n", dev->tx_len); + + /* We have the length, allocate a packet. */ + if (!(dev->tx_pkt = malloc(dev->tx_len))) /* unlikely */ + fatal("PLIP: unable to allocate tx_pkt\n"); + dev->tx_ptr = 0; + dev->tx_checksum_calc = 0; + + dev->state = PLIP_TX_DATA_LOW; + dev->status |= 0x80; + break; + + case PLIP_TX_DATA_LOW: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + dev->tx_pkt[dev->tx_ptr] = val & 0x0f; + plip_log(2, "PLIP: tx_pkt[%d] = %02X (1/2)\n", dev->tx_ptr, dev->tx_pkt[dev->tx_ptr]); + dev->state = PLIP_TX_DATA_HIGH; + dev->status &= ~0x80; + break; + + case PLIP_TX_DATA_HIGH: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + dev->tx_pkt[dev->tx_ptr] |= (val & 0x0f) << 4; + plip_log(2, "PLIP: tx_pkt[%d] = %02X (2/2)\n", dev->tx_ptr, dev->tx_pkt[dev->tx_ptr]); + dev->tx_checksum_calc += dev->tx_pkt[dev->tx_ptr++]; + + /* Are we done yet? */ + if (dev->tx_ptr < dev->tx_len) /* no, receive another byte */ + dev->state = PLIP_TX_DATA_LOW; + else /* yes, move on to checksum */ + dev->state = PLIP_TX_CHECKSUM_LOW; + dev->status |= 0x80; + break; + + case PLIP_TX_CHECKSUM_LOW: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + dev->tx_checksum = val & 0x0f; + plip_log(2, "PLIP: tx_checksum = %02X (1/2)\n", dev->tx_checksum); + dev->state = PLIP_TX_CHECKSUM_HIGH; + dev->status &= ~0x80; + break; + + case PLIP_TX_CHECKSUM_HIGH: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + dev->tx_checksum |= (val & 0x0f) << 4; + plip_log(2, "PLIP: tx_checksum = %02X (2/2)\n", dev->tx_checksum); + + /* Verify checksum. */ + if (dev->tx_checksum_calc == dev->tx_checksum) { + /* Make sure we know the other end's MAC address. */ + memcpy(dev->mac, dev->tx_pkt + 6, 6); + + /* Transmit packet. */ + plip_log(2, "PLIP: transmitting %d-byte packet\n", dev->tx_len); + network_tx(dev->tx_pkt, dev->tx_len); + } else { + plip_log(1, "PLIP: checksum error: expected %02X, got %02X\n", dev->tx_checksum_calc, dev->tx_checksum); + } + + /* We're done with this packet. */ + free(dev->tx_pkt); + dev->tx_pkt = NULL; + dev->tx_len = 0; + + dev->state = PLIP_END; + dev->status |= 0x80; + break; + + case PLIP_RX_LEN_LSB_LOW: + if (!(val & 0x01)) + return; /* D3/ACK not high yet */ + plip_log(2, "PLIP: rx_len = %04X (1/4)\n", dev->rx_len); + dev->status = (dev->rx_len & 0x0f) << 3; + dev->state = PLIP_RX_LEN_LSB_HIGH; + break; + + case PLIP_RX_LEN_LSB_HIGH: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + plip_log(2, "PLIP: rx_len = %04X (2/4)\n", dev->rx_len); + dev->status = ((dev->rx_len >> 4) & 0x0f) << 3; + dev->status |= 0x80; + dev->state = PLIP_RX_LEN_MSB_LOW; + break; + + case PLIP_RX_LEN_MSB_LOW: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + plip_log(2, "PLIP: rx_len = %04X (3/4)\n", dev->rx_len); + dev->status = ((dev->rx_len >> 8) & 0x0f) << 3; + dev->state = PLIP_RX_LEN_MSB_HIGH; + break; + + case PLIP_RX_LEN_MSB_HIGH: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + plip_log(2, "PLIP: rx_len = %04X (4/4)\n", dev->rx_len); + dev->status = ((dev->rx_len >> 12) & 0x0f) << 3; + dev->status |= 0x80; + + dev->rx_ptr = 0; + dev->rx_checksum = 0; + dev->state = PLIP_RX_DATA_LOW; + break; + + case PLIP_RX_DATA_LOW: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + plip_log(2, "PLIP: rx_pkt[%d] = %02X (1/2)\n", dev->rx_ptr, dev->rx_pkt[dev->rx_ptr]); + dev->status = (dev->rx_pkt[dev->rx_ptr] & 0x0f) << 3; + dev->state = PLIP_RX_DATA_HIGH; + break; + + case PLIP_RX_DATA_HIGH: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + plip_log(2, "PLIP: rx_pkt[%d] = %02X (2/2)\n", dev->rx_ptr, dev->rx_pkt[dev->rx_ptr]); + dev->status = ((dev->rx_pkt[dev->rx_ptr] >> 4) & 0x0f) << 3; + dev->status |= 0x80; + dev->rx_checksum += dev->rx_pkt[dev->rx_ptr++]; + + /* Are we done yet? */ + if (dev->rx_ptr < dev->rx_len) /* no, send another byte */ + dev->state = PLIP_RX_DATA_LOW; + else /* yes, move on to checksum */ + dev->state = PLIP_RX_CHECKSUM_LOW; + break; + + case PLIP_RX_CHECKSUM_LOW: + if (val & 0x10) + return; /* D4/BUSY not low yet */ + plip_log(2, "PLIP: rx_checksum = %02X (1/2)\n", dev->rx_checksum); + dev->status = (dev->rx_checksum & 0x0f) << 3; + dev->state = PLIP_RX_CHECKSUM_HIGH; + break; + + case PLIP_RX_CHECKSUM_HIGH: + if (!(val & 0x10)) + return; /* D4/BUSY not high yet */ + plip_log(2, "PLIP: rx_checksum = %02X (2/2)\n", dev->rx_checksum); + dev->status = ((dev->rx_checksum >> 4) & 0x0f) << 3; + dev->status |= 0x80; + + /* We're done with this packet. */ + free(dev->rx_pkt); + dev->rx_pkt = NULL; + dev->rx_len = 0; + + dev->state = PLIP_END; + break; + + case PLIP_END: + if (val == 0x00) { /* written after TX or RX is done */ + plip_log(2, "PLIP: end\n"); + dev->status = 0x80; + dev->state = PLIP_START; + + timer_set_delay_u64(&dev->rx_timer, ISACONST); /* for DOS */ + } + + /* Disengage timeout timer. */ + timer_disable(&dev->timeout_timer); + return; + } + + /* Engage timeout timer unless otherwise specified. */ + timer_set_delay_u64(&dev->timeout_timer, 1000000 * TIMER_USEC); +} + + +static void +plip_write_ctrl(uint8_t val, void *priv) +{ + plip_t *dev = (plip_t *) priv; + + plip_log(3, "PLIP: write_ctrl(%02X)\n", val); + + dev->ctrl = val; + + if (val & 0x10) /* for Linux */ + timer_set_delay_u64(&dev->rx_timer, ISACONST); +} + + +static uint8_t +plip_read_status(void *priv) +{ + plip_t *dev = (plip_t *) priv; + + plip_log(3, "PLIP: read_status() = %02X\n", dev->status); + + return dev->status; +} + + +static void +plip_receive_packet(plip_t *dev) +{ + /* At least the Linux driver supports being interrupted + in the PLIP_TX_LEN_LSB_LOW state, but let's be safe. */ + if (dev->state > PLIP_START) { + plip_log(3, "PLIP: cannot receive, operation already in progress\n"); + return; + } + + if (!dev->rx_pkt || !dev->rx_len) { /* unpause RX queue if there's no packet to receive */ + network_rx_pause = 0; + return; + } + + if (!(dev->ctrl & 0x10)) { /* checking this is essential to avoid collisions */ + plip_log(3, "PLIP: cannot receive, interrupts are off\n"); + return; + } + + plip_log(2, "PLIP: receiving %d-byte packet\n", dev->rx_len); + + /* Set up to receive a packet. */ + dev->status = 0xc7; /* DOS expects exactly 0xc7, while Linux masks the 7 off */ + dev->state = PLIP_RX_LEN_LSB_LOW; + + /* Engage timeout timer. */ + timer_set_delay_u64(&dev->timeout_timer, 1000000 * TIMER_USEC); + + /* Wake the other end up. */ + lpt_irq(dev->lpt, 1); +} + + +/* This timer defers a call to plip_receive_packet to + the next ISA clock, in order to avoid IRQ weirdness. */ +static void +rx_timer(void *priv) +{ + plip_t *dev = (plip_t *) priv; + + plip_receive_packet(dev); + + timer_disable(&dev->rx_timer); +} + + +static int +plip_rx(void *priv, uint8_t *buf, int io_len) +{ + plip_t *dev = (plip_t *) priv; + + plip_log(2, "PLIP: incoming %d-byte packet\n", io_len); + + if (dev->rx_pkt) { /* shouldn't really happen with the RX queue paused */ + plip_log(3, "PLIP: already have a packet to receive"); + return 0; + } + + if (!(dev->rx_pkt = malloc(io_len))) /* unlikely */ + fatal("PLIP: unable to allocate rx_pkt\n"); + + network_rx_pause = 1; /* make sure we don't get any more packets while processing this one */ + + /* Copy this packet to our buffer. */ + dev->rx_len = io_len; + memcpy(dev->rx_pkt, buf, dev->rx_len); + + /* Dispatch this packet immediately if we're doing nothing. */ + plip_receive_packet(dev); + + return 1; +} + + +static void * +plip_lpt_init(void *lpt) +{ + plip_t *dev = (plip_t *) malloc(sizeof(plip_t)); + memset(dev, 0, sizeof(plip_t)); + + plip_log(1, "PLIP: lpt_init()\n"); + + dev->lpt = lpt; + memset(dev->mac, 0xfc, 6); /* static MAC used by Linux; just a placeholder */ + + dev->status = 0x80; + + timer_add(&dev->rx_timer, rx_timer, dev, 0); + timer_add(&dev->timeout_timer, timeout_timer, dev, 0); + + instance = dev; + + return dev; +} + + +static void * +plip_net_init(const device_t *info) +{ + plip_log(1, "PLIP: net_init()"); + + if (!instance) { + plip_log(1, " (not attached to LPT)\n"); + return NULL; + } + + plip_log(1, " (attached to LPT)\n"); + network_attach(instance, instance->mac, plip_rx, NULL, NULL); + + return instance; +} + + +static void +plip_close(void *priv) +{ + free(priv); +} + +const lpt_device_t lpt_plip_device = { + .name = "Parallel Line Internet Protocol", + .internal_name = "plip", + .init = plip_lpt_init, + .close = plip_close, + .write_data = plip_write_data, + .write_ctrl = plip_write_ctrl, + .read_data = NULL, + .read_status = plip_read_status, + .read_ctrl = NULL +}; + +const device_t plip_device = { + .name = "Parallel Line Internet Protocol", + .internal_name = "plip", + .flags = DEVICE_LPT, + .local = 0, + .init = plip_net_init, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index aef813f6d..bc7c68783 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -1,48 +1,23 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 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 VARCem Project. + * This file is part of the 86Box distribution. * * Handle SLiRP library processing. * + * Some of the code was borrowed from libvdeslirp + * * * - * Author: Fred N. van Kempen, + * + * Authors: Fred N. van Kempen, + * RichardG, * * Copyright 2017-2019 Fred N. van Kempen. - * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Copyright 2020 RichardG. */ #include #include @@ -50,19 +25,50 @@ #include #include #include +#include #define HAVE_STDARG_H -#include -#include #include <86box/86box.h> #include <86box/device.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/network.h> +#include <86box/machine.h> +#include <86box/timer.h> +#include <86box/config.h> -static volatile queueADT slirpq; /* SLiRP library handle */ -static volatile thread_t *poll_tid; -static const netcard_t *poll_card; /* netcard attached to us */ -static event_t *poll_state; +/* SLiRP can use poll() or select() for socket polling. + poll() is best on *nix but slow and limited on Windows. */ +#ifndef _WIN32 +# define SLIRP_USE_POLL 1 +#endif +#ifdef SLIRP_USE_POLL +# ifdef _WIN32 +# include +# define poll WSAPoll +# else +# include +# endif +#endif + + +typedef struct { + Slirp *slirp; + void *mac; + const netcard_t *card; /* netcard attached to us */ + volatile thread_t *poll_tid; + event_t *poll_state; + uint8_t stop; +#ifdef SLIRP_USE_POLL + uint32_t pfd_len, pfd_size; + struct pollfd *pfd; +#else + uint32_t nfds; + fd_set rfds, wfds, xfds; +#endif +} slirp_t; + +static slirp_t *slirp; #ifdef ENABLE_SLIRP_LOG @@ -86,110 +92,311 @@ slirp_log(const char *fmt, ...) static void -slirp_tic(void) +net_slirp_guest_error(const char *msg, void *opaque) { - int ret2, nfds; - struct timeval tv; - fd_set rfds, wfds, xfds; - int tmo; + slirp_log("SLiRP: guest_error(): %s\n", msg); +} + + +static int64_t +net_slirp_clock_get_ns(void *opaque) +{ + return (TIMER_USEC ? (tsc / (TIMER_USEC / 1000)) : 0); +} + + +static void * +net_slirp_timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque) +{ + pc_timer_t *timer = malloc(sizeof(pc_timer_t)); + timer_add(timer, cb, cb_opaque, 0); + return timer; +} + + +static void +net_slirp_timer_free(void *timer, void *opaque) +{ + timer_stop(timer); +} + + +static void +net_slirp_timer_mod(void *timer, int64_t expire_timer, void *opaque) +{ + timer_set_delay_u64(timer, expire_timer); +} + + +static void +net_slirp_register_poll_fd(int fd, void *opaque) +{ + (void) fd; + (void) opaque; +} + + +static void +net_slirp_unregister_poll_fd(int fd, void *opaque) +{ + (void) fd; + (void) opaque; +} + + +static void +net_slirp_notify(void *opaque) +{ + (void) opaque; +} + + +ssize_t +net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) +{ + slirp_t *slirp = (slirp_t *) opaque; + uint8_t *mac = slirp->mac; + uint32_t mac_cmp32[2]; + uint16_t mac_cmp16[2]; + + if (!(slirp->card->set_link_state && slirp->card->set_link_state(slirp->card->priv)) && !(slirp->card->wait && slirp->card->wait(slirp->card->priv))) { + slirp_log("SLiRP: received %d-byte packet\n", pkt_len); + + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6); + mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10); + + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *) mac; + mac_cmp16[1] = *(uint16_t *) (mac + 4); + if ((mac_cmp32[0] != mac_cmp32[1]) || + (mac_cmp16[0] != mac_cmp16[1])) { + network_queue_put(0, slirp->card->priv, (uint8_t *) qp, pkt_len); + } + + return pkt_len; + } else { + slirp_log("SLiRP: ignored %d-byte packet\n", pkt_len); + } + + return 0; +} + + +static int +net_slirp_add_poll(int fd, int events, void *opaque) +{ + slirp_t *slirp = (slirp_t *) opaque; +#ifdef SLIRP_USE_POLL + if (slirp->pfd_len >= slirp->pfd_size) { + int newsize = slirp->pfd_size + 16; + struct pollfd *new = realloc(slirp->pfd, newsize * sizeof(struct pollfd)); + if (new) { + slirp->pfd = new; + slirp->pfd_size = newsize; + } + } + if ((slirp->pfd_len < slirp->pfd_size)) { + int idx = slirp->pfd_len++; + slirp->pfd[idx].fd = fd; + int pevents = 0; + if (events & SLIRP_POLL_IN) pevents |= POLLIN; + if (events & SLIRP_POLL_OUT) pevents |= POLLOUT; +# ifndef _WIN32 + /* Windows does not support some events. */ + if (events & SLIRP_POLL_ERR) pevents |= POLLERR; + if (events & SLIRP_POLL_PRI) pevents |= POLLPRI; + if (events & SLIRP_POLL_HUP) pevents |= POLLHUP; +# endif + slirp->pfd[idx].events = pevents; + return idx; + } else + return -1; +#else + if (events & SLIRP_POLL_IN) + FD_SET(fd, &slirp->rfds); + if (events & SLIRP_POLL_OUT) + FD_SET(fd, &slirp->wfds); + if (events & SLIRP_POLL_PRI) + FD_SET(fd, &slirp->xfds); + if (fd > slirp->nfds) + slirp->nfds = fd; + return fd; +#endif +} + + +static int +net_slirp_get_revents(int idx, void *opaque) +{ + slirp_t *slirp = (slirp_t *) opaque; + int ret = 0; +#ifdef SLIRP_USE_POLL + int events = slirp->pfd[idx].revents; + if (events & POLLIN) ret |= SLIRP_POLL_IN; + if (events & POLLOUT) ret |= SLIRP_POLL_OUT; + if (events & POLLPRI) ret |= SLIRP_POLL_PRI; + if (events & POLLERR) ret |= SLIRP_POLL_ERR; + if (events & POLLHUP) ret |= SLIRP_POLL_HUP; +#else + if (FD_ISSET(idx, &slirp->rfds)) + ret |= SLIRP_POLL_IN; + if (FD_ISSET(idx, &slirp->wfds)) + ret |= SLIRP_POLL_OUT; + if (FD_ISSET(idx, &slirp->xfds)) + ret |= SLIRP_POLL_PRI; +#endif + return ret; +} + + +static void +slirp_tic(slirp_t *slirp) +{ + int ret; + uint32_t tmo; /* Let SLiRP create a list of all open sockets. */ - nfds = -1; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - tmo = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); /* this can crash */ +#ifdef SLIRP_USE_POLL + tmo = -1; + slirp->pfd_len = 0; +#else + slirp->nfds = -1; + FD_ZERO(&slirp->rfds); + FD_ZERO(&slirp->wfds); + FD_ZERO(&slirp->xfds); +#endif + slirp_pollfds_fill(slirp->slirp, &tmo, net_slirp_add_poll, slirp); + + /* Now wait for something to happen, or at most 'tmo' usec. */ +#ifdef SLIRP_USE_POLL + ret = poll(slirp->pfd, slirp->pfd_len, tmo); +#else if (tmo < 0) tmo = 500; + struct timeval tv; tv.tv_sec = 0; tv.tv_usec = tmo; - /* Now wait for something to happen, or at most 'tmo' usec. */ - ret2 = select(nfds+1, &rfds, &wfds, &xfds, &tv); + ret = select(slirp->nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv); +#endif /* If something happened, let SLiRP handle it. */ - if (ret2 >= 0) - slirp_select_poll(&rfds, &wfds, &xfds); + slirp_pollfds_poll(slirp->slirp, (ret <= 0), net_slirp_get_revents, slirp); } +static const SlirpCb slirp_cb = { + .send_packet = net_slirp_send_packet, + .guest_error = net_slirp_guest_error, + .clock_get_ns = net_slirp_clock_get_ns, + .timer_new = net_slirp_timer_new, + .timer_free = net_slirp_timer_free, + .timer_mod = net_slirp_timer_mod, + .register_poll_fd = net_slirp_register_poll_fd, + .unregister_poll_fd = net_slirp_unregister_poll_fd, + .notify = net_slirp_notify +}; + + /* Handle the receiving of frames. */ static void poll_thread(void *arg) { - uint8_t *mac = (uint8_t *)arg; - struct queuepacket *qp; - uint32_t mac_cmp32[2]; - uint16_t mac_cmp16[2]; + slirp_t *slirp = (slirp_t *) arg; event_t *evt; - int data_valid = 0; int tx; + slirp_log("SLiRP: initializing...\n"); + + /* Set the IP addresses to use. */ + struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ + struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ + struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ + struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ + struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ + struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */ + + /* Initialize SLiRP. */ + slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, arg); + if (!slirp->slirp) { + slirp_log("SLiRP: initialization failed\n"); + return; + } + + /* Set up port forwarding. */ + int udp, external, internal, i = 0; + char *category = "SLiRP Port Forwarding"; + char key[20]; + while (1) { + sprintf(key, "%d_protocol", i); + udp = strcmp(config_get_string(category, key, "tcp"), "udp") == 0; + sprintf(key, "%d_external", i); + external = config_get_int(category, key, 0); + sprintf(key, "%d_internal", i); + internal = config_get_int(category, key, 0); + if ((external <= 0) && (internal <= 0)) + break; + else if (internal <= 0) + internal = external; + else if (external <= 0) + external = internal; + + if (slirp_add_hostfwd(slirp->slirp, udp, bind, external, dhcp, internal) == 0) + pclog("SLiRP: Forwarded %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal); + else + pclog("SLiRP: Failed to forward %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal); + + i++; + } + + /* Start polling. */ slirp_log("SLiRP: polling started.\n"); - thread_set_event(poll_state); + thread_set_event(slirp->poll_state); /* Create a waitable event. */ evt = thread_create_event(); - while (slirpq != NULL) { + while (!slirp->stop) { /* Request ownership of the queue. */ network_wait(1); - /* Wait for a poll request. */ - network_poll(); - - /* See if there is any work. */ - slirp_tic(); - - /* Our queue may have been nuked.. */ - if (slirpq == NULL) break; - - /* Wait for the next packet to arrive. */ - tx = network_tx_queue_check(); - data_valid = 0; - - if ((!network_get_wait() && !(poll_card->set_link_state && poll_card->set_link_state(poll_card->priv)) && !(poll_card->wait && poll_card->wait(poll_card->priv))) && (QueuePeek(slirpq) != 0)) { - /* Grab a packet from the queue. */ - qp = QueueDelete(slirpq); - slirp_log("SLiRP: inQ:%d got a %dbyte packet @%08lx\n", - QueuePeek(slirpq), qp->len, qp); - - /* Received MAC. */ - mac_cmp32[0] = *(uint32_t *)(((uint8_t *)qp->data)+6); - mac_cmp16[0] = *(uint16_t *)(((uint8_t *)qp->data)+10); - - /* Local MAC. */ - mac_cmp32[1] = *(uint32_t *)mac; - mac_cmp16[1] = *(uint16_t *)(mac+4); - if ((mac_cmp32[0] != mac_cmp32[1]) || - (mac_cmp16[0] != mac_cmp16[1])) { - - network_queue_put(0, poll_card->priv, (uint8_t *)qp->data, qp->len); - data_valid = 1; - } - - /* Done with this one. */ - free(qp); + /* Stop processing if asked to. */ + if (slirp->stop) { + network_wait(0); + break; } - if (tx) - network_do_tx(); + /* See if there is any work. */ + slirp_tic(slirp); - /* If we did not get anything, wait a while. */ - if (!data_valid && !tx) - thread_wait_event(evt, 10); + /* Wait for the next packet to arrive - network_do_tx() is called from there. */ + tx = network_tx_queue_check(); /* Release ownership of the queue. */ network_wait(0); + + /* If we did not get anything, wait a while. */ + if (!tx) + thread_wait_event(evt, 10); } /* No longer needed. */ - if (evt != NULL) + if (evt) thread_destroy_event(evt); slirp_log("SLiRP: polling stopped.\n"); - thread_set_event(poll_state); + thread_set_event(slirp->poll_state); + + /* Destroy event here to avoid a crash. */ + slirp_log("SLiRP: thread ended\n"); + thread_destroy_event(slirp->poll_state); + /* Free here instead of immediately freeing the global slirp on the main + thread to avoid a race condition. */ + slirp_cleanup(slirp->slirp); + free(slirp); } @@ -197,20 +404,7 @@ poll_thread(void *arg) int net_slirp_init(void) { - slirp_log("SLiRP: initializing..\n"); - - if (slirp_init() != 0) { - slirp_log("SLiRP could not be initialized!\n"); - return(-1); - } - - slirpq = QueueCreate(); - - poll_tid = NULL; - poll_state = NULL; - poll_card = NULL; - - return(0); + return 0; } @@ -218,49 +412,48 @@ net_slirp_init(void) int net_slirp_reset(const netcard_t *card, uint8_t *mac) { + slirp_t *new_slirp = malloc(sizeof(slirp_t)); + memset(new_slirp, 0, sizeof(slirp_t)); + new_slirp->mac = mac; + new_slirp->card = card; +#ifdef SLIRP_USE_POLL + new_slirp->pfd_size = 16 * sizeof(struct pollfd); + new_slirp->pfd = malloc(new_slirp->pfd_size); + memset(new_slirp->pfd, 0, new_slirp->pfd_size); +#endif + /* Save the callback info. */ - poll_card = card; + slirp = new_slirp; - slirp_log("SLiRP: creating thread..\n"); - poll_state = thread_create_event(); - poll_tid = thread_create(poll_thread, mac); - thread_wait_event(poll_state, -1); + slirp_log("SLiRP: creating thread...\n"); + slirp->poll_state = thread_create_event(); + slirp->poll_tid = thread_create(poll_thread, new_slirp); + thread_wait_event(slirp->poll_state, -1); - return(0); + return 0; } void net_slirp_close(void) { - queueADT sl; - - if (slirpq == NULL) + if (!slirp) return; - slirp_log("SLiRP: closing.\n"); + slirp_log("SLiRP: closing\n"); /* Tell the polling thread to shut down. */ - sl = slirpq; slirpq = NULL; + slirp->stop = 1; /* Tell the thread to terminate. */ - if (poll_tid != NULL) { - network_busy(0); - + if (slirp->poll_tid) { /* Wait for the thread to finish. */ slirp_log("SLiRP: waiting for thread to end...\n"); - thread_wait_event(poll_state, -1); - slirp_log("SLiRP: thread ended\n"); - thread_destroy_event(poll_state); - - poll_tid = NULL; - poll_state = NULL; - poll_card = NULL; + thread_wait_event(slirp->poll_state, -1); } - /* OK, now shut down SLiRP itself. */ - QueueDestroy(sl); - slirp_exit(0); + /* Shutdown work is done by the thread on its local copy of slirp. */ + slirp = NULL; } @@ -268,31 +461,27 @@ net_slirp_close(void) void net_slirp_in(uint8_t *pkt, int pkt_len) { - if (slirpq == NULL) + if (!slirp || !slirp->slirp) return; - slirp_input((const uint8_t *)pkt, pkt_len); + slirp_log("SLiRP: sending %d-byte packet\n", pkt_len); + + slirp_input(slirp->slirp, (const uint8_t *) pkt, pkt_len); } -/* Needed by SLiRP library. */ -void -slirp_output(const uint8_t *pkt, int pkt_len) -{ - struct queuepacket *qp; - - if (slirpq != NULL) { - qp = (struct queuepacket *)malloc(sizeof(struct queuepacket)); - qp->len = pkt_len; - memcpy(qp->data, pkt, pkt_len); - QueueEnter(slirpq, qp); - } -} - - -/* Needed by SLiRP library. */ -int -slirp_can_output(void) -{ - return((slirpq != NULL)?1:0); -} +/* Stubs to stand in for the parts of libslirp we skip compiling. */ +void ncsi_input(void *slirp, const uint8_t *pkt, int pkt_len) {} +void ip6_init(void *slirp) {} +void ip6_cleanup(void *slirp) {} +void ip6_input(void *m) {} +int ip6_output(void *so, void *m, int fast) { return 0; } +void in6_compute_ethaddr(struct in6_addr ip, uint8_t *eth) {} +bool in6_equal(const void *a, const void *b) { return 0; } +const struct in6_addr in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; +const struct in6_addr in6addr_loopback = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; +int udp6_output(void *so, void *m, void *saddr, void *daddr) { return 0; } +void icmp6_send_error(void *m, uint8_t type, uint8_t code) {} +void ndp_send_ns(void *slirp, struct in6_addr addr) {} +bool ndp_table_search(void *slirp, struct in6_addr ip_addr, uint8_t *out_ethaddr) { return 0; } +void tftp_input(void *srcsas, void *m) {} diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 7eeb4d136..81429fe19 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -63,6 +63,8 @@ #include <86box/net_wd8003.h> #include <86box/bswap.h> +#include "cpu.h" + /* Board type codes in card ID */ #define WE_TYPE_WD8003 0x01 #define WE_TYPE_WD8003S 0x02 @@ -118,7 +120,7 @@ typedef struct { #ifdef ENABLE_WD_LOG -int WE_do_log = ENABLE_WD_LOG; +int wd_do_log = ENABLE_WD_LOG; static void wdlog(const char *fmt, ...) @@ -179,7 +181,7 @@ static uint8_t wd_ram_read(uint32_t addr, void *priv) { wd_t *dev = (wd_t *)priv; - + wdlog("WD80x3: RAM Read: addr=%06x, val=%02x\n", addr & (dev->ram_size - 1), dev->dp8390->mem[addr & (dev->ram_size - 1)]); return dev->dp8390->mem[addr & (dev->ram_size - 1)]; } @@ -188,7 +190,7 @@ static void wd_ram_write(uint32_t addr, uint8_t val, void *priv) { wd_t *dev = (wd_t *)priv; - + dev->dp8390->mem[addr & (dev->ram_size - 1)] = val; wdlog("WD80x3: RAM Write: addr=%06x, val=%02x\n", addr & (dev->ram_size - 1), val); } @@ -244,7 +246,7 @@ wd_smc_read(wd_t *dev, uint32_t off) if (dev->board_chip & WE_ID_SOFT_CONFIG) retval = dev->laar; break; - + case 0x07: if (dev->board_chip & WE_ID_SOFT_CONFIG) retval = dev->if_chip; @@ -252,32 +254,32 @@ wd_smc_read(wd_t *dev, uint32_t off) case 0x08: retval = dev->dp8390->physaddr[0]; - break; - + break; + case 0x09: retval = dev->dp8390->physaddr[1]; - break; - + break; + case 0x0a: retval = dev->dp8390->physaddr[2]; - break; - + break; + case 0x0b: retval = dev->dp8390->physaddr[3]; - break; - + break; + case 0x0c: retval = dev->dp8390->physaddr[4]; break; - + case 0x0d: retval = dev->dp8390->physaddr[5]; break; - + case 0x0e: retval = dev->board_chip; break; - + case 0x0f: /*This has to return the byte that adds up to 0xFF*/ checksum = (dev->dp8390->physaddr[0] + dev->dp8390->physaddr[1] + dev->dp8390->physaddr[2] + @@ -352,7 +354,7 @@ wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) wdlog("WD80x3: Memory now %sabled (addr = %08X)\n", (val & WE_MSR_ENABLE_RAM) ? "en" : "dis", dev->ram_addr); } break; - + /* Bit 1: 0 = 8-bit slot, 1 = 16-bit slot; Bit 3: 0 = 8k RAM, 1 = 32k RAM (only on revision < 2). */ case 0x01: @@ -361,7 +363,7 @@ wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) else dev->icr = val; break; - + /* Bit 5: Bit 0 of encoded IRQ; Bit 6: Bit 1 of encoded IRQ; Bit 7: Enable interrupts. */ @@ -388,7 +390,7 @@ wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) if (dev->board_chip & WE_ID_SOFT_CONFIG) dev->if_chip = val; break; - + default: /* This is invalid, but happens under win95 device detection: maybe some clone cards implement writing for some other @@ -413,7 +415,7 @@ wd_read(uint16_t addr, void *priv, int len) if (off == 0x10) retval = dp8390_read_cr(dev->dp8390); else if ((off >= 0x00) && (off <= 0x0f)) - retval = wd_smc_read(dev, off); + retval = wd_smc_read(dev, off); else { switch(dev->dp8390->CR.pgsel) { case 0x00: @@ -429,7 +431,7 @@ wd_read(uint16_t addr, void *priv, int len) wdlog("%s: unknown value of pgsel in read - %d\n", dev->name, dev->dp8390->CR.pgsel); break; - } + } } return(retval); @@ -465,7 +467,7 @@ wd_write(uint16_t addr, uint8_t val, void *priv, unsigned int len) if (off == 0x10) dp8390_write_cr(dev->dp8390, val); else if ((off >= 0x00) && (off <= 0x0f)) - wd_smc_write(dev, off, val); + wd_smc_write(dev, off, val); else { switch(dev->dp8390->CR.pgsel) { case 0x00: @@ -478,7 +480,7 @@ wd_write(uint16_t addr, uint8_t val, void *priv, unsigned int len) wdlog("%s: unknown value of pgsel in write - %d\n", dev->name, dev->dp8390->CR.pgsel); break; - } + } } } @@ -499,7 +501,7 @@ wd_writew(uint16_t addr, uint16_t val, void *priv) static void wd_io_set(wd_t *dev, uint16_t addr) -{ +{ if (dev->bit16 & 1) { io_sethandler(addr, 0x20, wd_readb, wd_readw, NULL, @@ -514,7 +516,7 @@ wd_io_set(wd_t *dev, uint16_t addr) static void wd_io_remove(wd_t *dev, uint16_t addr) -{ +{ if (dev->bit16 & 1) { io_removehandler(addr, 0x20, wd_readb, wd_readw, NULL, @@ -538,7 +540,6 @@ wd_mca_read(int port, void *priv) #define MCA_6FC0_IRQS { 3, 4, 10, 15 } - static void wd_mca_write(int port, uint8_t val, void *priv) { @@ -580,6 +581,68 @@ wd_mca_write(int port, uint8_t val, void *priv) dev->base_address, dev->irq, dev->ram_addr); } +static void +wd_8013epa_mca_write(int port, uint8_t val, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + if (dev->base_address) + wd_io_remove(dev, dev->base_address); + + dev->base_address = 0x800 + ((dev->pos_regs[2] & 0xf0) << 8); + + switch (dev->pos_regs[5] & 0x0c) { + case 0: + dev->irq = 3; + break; + case 4: + dev->irq = 4; + break; + case 8: + dev->irq = 10; + break; + case 0x0c: + dev->irq = 14; + break; + } + + if (dev->pos_regs[3] & 0x10) + dev->ram_size = 0x4000; + else + dev->ram_size = 0x2000; + + dev->ram_addr = ((dev->pos_regs[3] & 0x0f) << 13) + 0xc0000; + if (dev->pos_regs[3] & 0x80) + dev->ram_addr += 0xf00000; + + /* Initialize the device if fully configured. */ + /* Register (new) I/O handler. */ + if (dev->pos_regs[2] & 0x01) + wd_io_set(dev, dev->base_address); + + mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); + + mem_mapping_disable(&dev->ram_mapping); + if ((dev->msr & WE_MSR_ENABLE_RAM) && (dev->pos_regs[2] & 0x01)) + mem_mapping_enable(&dev->ram_mapping); + + wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->irq, dev->ram_addr); +} + static uint8_t wd_mca_feedb(void *priv) @@ -594,12 +657,6 @@ wd_init(const device_t *info) uint32_t mac; wd_t *dev; - /* Get the desired debug level. */ -#ifdef ENABLE_NIC_LOG - i = device_get_config_int("debug"); - if (i > 0) WE_do_log = i; -#endif - dev = malloc(sizeof(wd_t)); memset(dev, 0x00, sizeof(wd_t)); dev->name = info->name; @@ -628,9 +685,12 @@ wd_init(const device_t *info) dev->maclocal[5] = (mac & 0xff); } - if ((dev->board == WD8003ETA) || (dev->board == WD8003EA)) - mca_add(wd_mca_read, wd_mca_write, wd_mca_feedb, NULL, dev); - else { + if ((dev->board == WD8003ETA) || (dev->board == WD8003EA) || dev->board == WD8013EPA) { + if (dev->board == WD8013EPA) + mca_add(wd_mca_read, wd_8013epa_mca_write, wd_mca_feedb, NULL, dev); + else + mca_add(wd_mca_read, wd_mca_write, wd_mca_feedb, NULL, dev); + } else { dev->base_address = device_get_config_hex16("base"); dev->irq = device_get_config_int("irq"); dev->ram_addr = device_get_config_hex20("ram_addr"); @@ -668,7 +728,7 @@ wd_init(const device_t *info) dev->board_chip |= WE_ID_EXTRA_RAM; dev->bit16 = 2; - if (AT) + if (is286) dev->bit16 |= 1; else { dev->bit16 |= 0; @@ -683,12 +743,20 @@ wd_init(const device_t *info) dev->board_chip = WE_ID_SOFT_CONFIG; /* Ethernet, MCA, no interface chip, RAM 16k */ case WD8003ETA: - dev->board_chip |= 0x05 | WE_ID_BUS_MCA; + dev->board_chip |= WE_TYPE_WD8013EBT | WE_ID_BUS_MCA; dev->ram_size = 0x4000; dev->pos_regs[0] = 0xC0; dev->pos_regs[1] = 0x6F; dev->bit16 = 3; break; + + case WD8013EPA: + dev->board_chip = WE_TYPE_WD8013EP | WE_ID_BUS_MCA; + dev->ram_size = device_get_config_int("ram_size"); + dev->pos_regs[0] = 0xC8; + dev->pos_regs[1] = 0x61; + dev->bit16 = 3; + break; } dev->irr |= WE_IRR_ENABLE_IRQ; @@ -715,14 +783,14 @@ wd_init(const device_t *info) wd_ram_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->ram_mapping); + mem_mapping_disable(&dev->ram_mapping); /* Attach ourselves to the network module. */ network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); if (!(dev->board_chip & WE_ID_BUS_MCA)) { wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, - dev->base_address, dev->irq, dev->ram_addr); + dev->base_address, dev->irq, dev->ram_addr); } return(dev); @@ -739,377 +807,357 @@ wd_close(void *priv) free(dev); } - -static const device_config_t wd8003_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x300, - { - { - "0x240", 0x240 - }, - { - "0x280", 0x280 - }, - { - "0x300", 0x300 - }, - { - "0x380", 0x380 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "" - } - }, - }, - { - "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, - { - { - "C800", 0xC8000 - }, - { - "CC00", 0xCC000 - }, - { - "D000", 0xD0000 - }, - { - "D400", 0xD4000 - }, - { - "D800", 0xD8000 - }, - { - "DC00", 0xDC000 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +// clang-format off +static const device_config_t wd8003_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x300, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x240", .value = 0x240 }, + { .description = "0x280", .value = 0x280 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x380", .value = 0x380 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + }, + { + .name = "ram_addr", + .description = "RAM address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD0000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "C800", .value = 0xC8000 }, + { .description = "CC00", .value = 0xCC000 }, + { .description = "D000", .value = 0xD0000 }, + { .description = "D400", .value = 0xD4000 }, + { .description = "D800", .value = 0xD8000 }, + { .description = "DC00", .value = 0xDC000 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t wd8003eb_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x280, - { - { - "0x200", 0x200 - }, - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "0x260", 0x260 - }, - { - "0x280", 0x280 - }, - { - "0x2A0", 0x2A0 - }, - { - "0x2C0", 0x2C0 - }, - { - "0x300", 0x300 - }, - { - "0x340", 0x340 - }, - { - "0x380", 0x380 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 2/9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 7", 7 - }, - { - "" - } - }, - }, - { - "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, - { - { - "C000", 0xC0000 - }, - { - "C400", 0xC4000 - }, - { - "C800", 0xC8000 - }, - { - "CC00", 0xCC000 - }, - { - "D000", 0xD0000 - }, - { - "D400", 0xD4000 - }, - { - "D800", 0xD8000 - }, - { - "DC00", 0xDC000 - }, - { - "" - } - }, - }, - { - "ram_size", "RAM size", CONFIG_SELECTION, "", 8192, - { - { - "8 kB", 8192 - }, - { - "32 kB", 32768 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t wd8003eb_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x280, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x200", .value = 0x200 }, + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x260", .value = 0x260 }, + { .description = "0x280", .value = 0x280 }, + { .description = "0x2A0", .value = 0x2A0 }, + { .description = "0x2C0", .value = 0x2C0 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x380", .value = 0x380 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2/9", .value = 9 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + }, + { + .name = "ram_addr", + .description = "RAM address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD0000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "C000", .value = 0xC0000 }, + { .description = "C400", .value = 0xC4000 }, + { .description = "C800", .value = 0xC8000 }, + { .description = "CC00", .value = 0xCC000 }, + { .description = "D000", .value = 0xD0000 }, + { .description = "D400", .value = 0xD4000 }, + { .description = "D800", .value = 0xD8000 }, + { .description = "DC00", .value = 0xDC000 }, + { .description = "" } + }, + }, + { + .name = "ram_size", + .description = "RAM size", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 8192, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8 kB", .value = 8192 }, + { .description = "32 kB", .value = 32768 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; /* WD8013EBT configuration and defaults set according to this site: http://www.stack.nl/~marcolz/network/wd80x3.html#WD8013EBT */ -static const device_config_t wd8013_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x280, - { - { - "0x200", 0x200 - }, - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "0x260", 0x260 - }, - { - "0x280", 0x280 - }, - { - "0x2A0", 0x2A0 - }, - { - "0x2C0", 0x2C0 - }, - { - "0x300", 0x300 - }, - { - "0x340", 0x340 - }, - { - "0x380", 0x380 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 3, - { - { - "IRQ 2/9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 15", 15 - }, - { - "" - } - }, - }, - { - "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, - { - { - "C000", 0xC0000 - }, - { - "C400", 0xC4000 - }, - { - "C800", 0xC8000 - }, - { - "CC00", 0xCC000 - }, - { - "D000", 0xD0000 - }, - { - "D400", 0xD4000 - }, - { - "D800", 0xD8000 - }, - { - "DC00", 0xDC000 - }, - { - "" - } - }, - }, - { - "ram_size", "RAM size", CONFIG_SELECTION, "", 16384, - { - { - "16 kB", 16384 - }, - { - "64 kB", 65536 - }, - { - "" - } - }, - }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t wd8013_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x280, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x200", .value = 0x200 }, + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x260", .value = 0x260 }, + { .description = "0x280", .value = 0x280 }, + { .description = "0x2A0", .value = 0x2A0 }, + { .description = "0x2C0", .value = 0x2C0 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x380", .value = 0x380 }, + { .description = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2/9", .value = 9 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 15", .value = 15 }, + { .description = "" } + }, + }, + { + .name = "ram_addr", + .description = "RAM address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD0000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "C000", .value = 0xC0000 }, + { .description = "C400", .value = 0xC4000 }, + { .description = "C800", .value = 0xC8000 }, + { .description = "CC00", .value = 0xCC000 }, + { .description = "D000", .value = 0xD0000 }, + { .description = "D400", .value = 0xD4000 }, + { .description = "D800", .value = 0xD8000 }, + { .description = "DC00", .value = 0xDC000 }, + { .description = "" } + }, + }, + { + .name = "ram_size", + .description = "RAM size", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 16384, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "16 kB", .value = 16384 }, + { .description = "64 kB", .value = 65536 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t mca_mac_config[] = -{ - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, - { - "", "", -1 - } +static const device_config_t wd8013epa_config[] = { + { + .name = "ram_size", + .description = "Initial RAM size", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 16384, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8 kB", .value = 8192 }, + { .description = "16 kB", .value = 16384 }, + { .description = "" } + }, + }, + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; +static const device_config_t mca_mac_config[] = { + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on const device_t wd8003e_device = { - "Western Digital WD8003E", - DEVICE_ISA, - WD8003E, - wd_init, wd_close, NULL, - NULL, NULL, NULL, - wd8003_config + .name = "Western Digital WD8003E", + .internal_name = "wd8003e", + .flags = DEVICE_ISA, + .local = WD8003E, + .init = wd_init, + .close = wd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd8003_config }; const device_t wd8003eb_device = { - "Western Digital WD8003EB", - DEVICE_ISA, - WD8003EB, - wd_init, wd_close, NULL, - NULL, NULL, NULL, - wd8003eb_config + .name = "Western Digital WD8003EB", + .internal_name = "wd8003eb", + .flags = DEVICE_ISA, + .local = WD8003EB, + .init = wd_init, + .close = wd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd8003eb_config }; const device_t wd8013ebt_device = { - "Western Digital WD8013EBT", - DEVICE_ISA, - WD8013EBT, - wd_init, wd_close, NULL, - NULL, NULL, NULL, - wd8013_config + .name = "Western Digital WD8013EBT", + .internal_name = "wd8013ebt", + .flags = DEVICE_ISA, + .local = WD8013EBT, + .init = wd_init, + .close = wd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd8013_config }; const device_t wd8003eta_device = { - "Western Digital WD8003ET/A", - DEVICE_MCA, - WD8003ETA, - wd_init, wd_close, NULL, - NULL, NULL, NULL, - mca_mac_config + .name = "Western Digital WD8003ET/A", + .internal_name = "wd8003eta", + .flags = DEVICE_MCA, + .local = WD8003ETA, + .init = wd_init, + .close = wd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mca_mac_config }; const device_t wd8003ea_device = { - "Western Digital WD8003E/A", - DEVICE_MCA, - WD8003EA, - wd_init, wd_close, NULL, - NULL, NULL, NULL, - mca_mac_config + .name = "Western Digital WD8003E/A", + .internal_name = "wd8003ea", + .flags = DEVICE_MCA, + .local = WD8003EA, + .init = wd_init, + .close = wd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mca_mac_config +}; + +const device_t wd8013epa_device = { + .name = "Western Digital WD8013EP/A", + .internal_name = "wd8013epa", + .flags = DEVICE_MCA, + .local = WD8013EPA, + .init = wd_init, + .close = wd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = wd8013epa_config }; diff --git a/src/network/network.c b/src/network/network.c index 77fbfa1ae..6a7fbdfa5 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -49,61 +49,67 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include #include #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/timer.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/ui.h> #include <86box/network.h> #include <86box/net_3c503.h> #include <86box/net_ne2000.h> #include <86box/net_pcnet.h> +#include <86box/net_plip.h> #include <86box/net_wd8003.h> +static const device_t net_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = NET_TYPE_NONE, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + + static netcard_t net_cards[] = { - { "None", "none", NULL, - NULL }, - { "[ISA] 3Com EtherLink II (3C503)","3c503", &threec503_device, - NULL }, - { "[ISA] AMD PCnet-ISA", "pcnetisa", &pcnet_am79c960_device, - NULL }, - { "[ISA] Novell NE1000", "ne1k", &ne1000_device, - NULL }, - { "[ISA] Novell NE2000", "ne2k", &ne2000_device, - NULL }, - { "[ISA] Racal Interlan EtherBlaster", "pcnetracal", &pcnet_am79c960_eb_device, - NULL }, - { "[ISA] Realtek RTL8019AS", "ne2kpnp", &rtl8019as_device, - NULL }, - { "[ISA] Western Digital WD8003E", "wd8003e", &wd8003e_device, - NULL }, - { "[ISA] Western Digital WD8003EB", "wd8003eb", &wd8003eb_device, - NULL }, - { "[ISA] Western Digital WD8013EBT","wd8013ebt", &wd8013ebt_device, - NULL }, - { "[MCA] NetWorth Ethernet/MC", "ethernextmc", ðernext_mc_device, - NULL }, - { "[MCA] Western Digital WD8003ET/A","wd8003eta", &wd8003eta_device, - NULL }, - { "[MCA] Western Digital WD8003E/A", "wd8003ea", &wd8003ea_device, - NULL }, - { "[PCI] AMD PCnet-FAST III", "pcnetfast", &pcnet_am79c973_device, - NULL }, - { "[PCI] AMD PCnet-PCI II", "pcnetpci", &pcnet_am79c970a_device, - NULL }, - { "[PCI] Realtek RTL8029AS", "ne2kpci", &rtl8029as_device, - NULL }, - { "[VLB] AMD PCnet-VL", "pcnetvlb", &pcnet_am79c960_vlb_device, - NULL }, - { "", "", NULL, - NULL } +// clang-format off + { &net_none_device, NULL }, + { &threec503_device, NULL }, + { &pcnet_am79c960_device, NULL }, + { &pcnet_am79c961_device, NULL }, + { &ne1000_device, NULL }, + { &ne2000_device, NULL }, + { &pcnet_am79c960_eb_device, NULL }, + { &rtl8019as_device, NULL }, + { &wd8003e_device, NULL }, + { &wd8003eb_device, NULL }, + { &wd8013ebt_device, NULL }, + { &plip_device, NULL }, + { ðernext_mc_device, NULL }, + { &wd8003eta_device, NULL }, + { &wd8003ea_device, NULL }, + { &wd8013epa_device, NULL }, + { &pcnet_am79c973_device, NULL }, + { &pcnet_am79c970a_device, NULL }, + { &rtl8029as_device, NULL }, + { &pcnet_am79c960_vlb_device, NULL }, + { NULL, NULL } +// clang-format off }; @@ -113,32 +119,25 @@ int network_ndev; int network_card; char network_host[522]; netdev_t network_devs[32]; -#ifdef ENABLE_NIC_LOG -int nic_do_log = ENABLE_NIC_LOG; -#endif +int network_rx_pause = 0, + network_tx_pause = 0; /* Local variables. */ -static volatile int net_wait = 0; +static volatile atomic_int net_wait = 0; static mutex_t *network_mutex; static uint8_t *network_mac; +static uint8_t network_timer_active = 0; static pc_timer_t network_rx_queue_timer; -static netpkt_t *first_pkt[2] = { NULL, NULL }, - *last_pkt[2] = { NULL, NULL }; - - -static struct { - volatile int busy, - queue_in_use; - - event_t *wake_poll_thread, - *poll_complete, - *queue_not_in_use; -} poll_data; +static netpkt_t *first_pkt[3] = { NULL, NULL, NULL }, + *last_pkt[3] = { NULL, NULL, NULL }; +static netpkt_t queued_pkt; #ifdef ENABLE_NETWORK_LOG int network_do_log = ENABLE_NETWORK_LOG; +static FILE *network_dump = NULL; +static mutex_t *network_dump_mutex; static void @@ -152,8 +151,43 @@ network_log(const char *fmt, ...) va_end(ap); } } + + +static void +network_dump_packet(netpkt_t *pkt) +{ + if (!network_dump) + return; + + struct timeval tv; + gettimeofday(&tv, NULL); + struct { + uint32_t ts_sec, ts_usec, incl_len, orig_len; + } pcap_packet_hdr = { + tv.tv_sec, tv.tv_usec, pkt->len, pkt->len + }; + + if (network_dump_mutex) + thread_wait_mutex(network_dump_mutex); + + size_t written; + if ((written = fwrite(&pcap_packet_hdr, 1, sizeof(pcap_packet_hdr), network_dump)) < sizeof(pcap_packet_hdr)) { + network_log("NETWORK: failed to write dump packet header\n"); + fseek(network_dump, -written, SEEK_CUR); + } else { + if ((written = fwrite(pkt->data, 1, pkt->len, network_dump)) < pkt->len) { + network_log("NETWORK: failed to write dump packet data\n"); + fseek(network_dump, -written - sizeof(pcap_packet_hdr), SEEK_CUR); + } + fflush(network_dump); + } + + if (network_dump_mutex) + thread_release_mutex(network_dump_mutex); +} #else #define network_log(fmt, ...) +#define network_dump_packet(pkt) #endif @@ -167,33 +201,6 @@ network_wait(uint8_t wait) } -void -network_poll(void) -{ - while (poll_data.busy) - thread_wait_event(poll_data.wake_poll_thread, -1); - - thread_reset_event(poll_data.wake_poll_thread); -} - - -void -network_busy(uint8_t set) -{ - poll_data.busy = !!set; - - if (! set) - thread_set_event(poll_data.wake_poll_thread); -} - - -void -network_end(void) -{ - thread_set_event(poll_data.poll_complete); -} - - /* * Initialize the configured network cards. * @@ -219,6 +226,25 @@ network_init(void) i = net_pcap_prepare(&network_devs[network_ndev]); if (i > 0) network_ndev += i; + +#ifdef ENABLE_NETWORK_LOG + /* Start packet dump. */ + network_dump = fopen("network.pcap", "wb"); + + struct { + uint32_t magic_number; + uint16_t version_major, version_minor; + int32_t thiszone; + uint32_t sigfigs, snaplen, network; + } pcap_hdr = { + 0xa1b2c3d4, + 2, 4, + 0, + 0, 65535, 1 + }; + fwrite(&pcap_hdr, sizeof(pcap_hdr), 1, network_dump); + fflush(network_dump); +#endif } @@ -227,8 +253,7 @@ network_queue_put(int tx, void *priv, uint8_t *data, int len) { netpkt_t *temp; - temp = (netpkt_t *) malloc(sizeof(netpkt_t)); - memset(temp, 0, sizeof(netpkt_t)); + temp = (netpkt_t *) calloc(sizeof(netpkt_t), 1); temp->priv = priv; memcpy(temp->data, data, len); temp->len = len; @@ -245,17 +270,29 @@ network_queue_put(int tx, void *priv, uint8_t *data, int len) static void -network_queue_get(int tx, netpkt_t **pkt) +network_queue_get(int tx, netpkt_t *pkt) { + netpkt_t *temp; + + temp = first_pkt[tx]; + + if (temp == NULL) { + memset(pkt, 0x00, sizeof(netpkt_t)); + return; + } + + memcpy(pkt, temp, sizeof(netpkt_t)); + + first_pkt[tx] = temp->next; + free(temp); + if (first_pkt[tx] == NULL) - *pkt = NULL; - else - *pkt = first_pkt[tx]; + last_pkt[tx] = NULL; } static void -network_queue_advance(int tx) +network_queue_transmit(int tx) { netpkt_t *temp; @@ -264,6 +301,20 @@ network_queue_advance(int tx) if (temp == NULL) return; + if (temp->len > 0) { + network_dump_packet(temp); + /* Why on earth is this not a function pointer?! */ + switch(network_type) { + case NET_TYPE_PCAP: + net_pcap_in(temp->data, temp->len); + break; + + case NET_TYPE_SLIRP: + net_slirp_in(temp->data, temp->len); + break; + } + } + first_pkt[tx] = temp->next; free(temp); @@ -272,6 +323,38 @@ network_queue_advance(int tx) } +static void +network_queue_copy(int dest, int src) +{ + netpkt_t *temp, *temp2; + + temp = first_pkt[src]; + + if (temp == NULL) + return; + + temp2 = (netpkt_t *) calloc(sizeof(netpkt_t), 1); + temp2->priv = temp->priv; + memcpy(temp2->data, temp->data, temp->len); + temp2->len = temp->len; + temp2->prev = last_pkt[dest]; + temp2->next = NULL; + + if (last_pkt[dest] != NULL) + last_pkt[dest]->next = temp2; + last_pkt[dest] = temp2; + + if (first_pkt[dest] == NULL) + first_pkt[dest] = temp2; + + first_pkt[src] = temp->next; + free(temp); + + if (first_pkt[src] == NULL) + last_pkt[src] = NULL; +} + + static void network_queue_clear(int tx) { @@ -293,22 +376,27 @@ network_queue_clear(int tx) static void network_rx_queue(void *priv) { - netpkt_t *pkt = NULL; + int ret = 1; - network_busy(1); - - network_queue_get(0, &pkt); - if ((pkt != NULL) && (pkt->len > 0)) { - net_cards[network_card].rx(pkt->priv, pkt->data, pkt->len); - if (pkt->len >= 128) - timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * ((double) pkt->len)); - else - timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * 128.0); - } else + if (network_rx_pause || !thread_test_mutex(network_mutex)) { timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * 128.0); - network_queue_advance(0); + return; + } - network_busy(0); + if (queued_pkt.len == 0) + network_queue_get(0, &queued_pkt); + if (queued_pkt.len > 0) { + network_dump_packet(&queued_pkt); + ret = net_cards[network_card].rx(queued_pkt.priv, queued_pkt.data, queued_pkt.len); + } + timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * ((queued_pkt.len >= 128) ? ((double) queued_pkt.len) : 128.0)); + if (ret) + queued_pkt.len = 0; + + /* Transmission. */ + network_queue_copy(1, 2); + + network_wait(0); } @@ -333,10 +421,6 @@ network_attach(void *dev, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKST network_set_wait(0); - /* Create the network events. */ - poll_data.wake_poll_thread = thread_create_event(); - poll_data.poll_complete = thread_create_event(); - /* Activate the platform module. */ switch(network_type) { case NET_TYPE_PCAP: @@ -348,12 +432,26 @@ network_attach(void *dev, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKST break; } - first_pkt[0] = first_pkt[1] = NULL; - last_pkt[0] = last_pkt[1] = NULL; + first_pkt[0] = first_pkt[1] = first_pkt[2] = NULL; + last_pkt[0] = last_pkt[1] = last_pkt[2] = NULL; + memset(&queued_pkt, 0x00, sizeof(netpkt_t)); memset(&network_rx_queue_timer, 0x00, sizeof(pc_timer_t)); timer_add(&network_rx_queue_timer, network_rx_queue, NULL, 0); /* 10 mbps. */ timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0); + network_timer_active = 1; +} + + +/* Stop the network timer. */ +void +network_timer_stop(void) +{ + if (network_timer_active) { + timer_stop(&network_rx_queue_timer); + memset(&network_rx_queue_timer, 0x00, sizeof(pc_timer_t)); + network_timer_active = 0; + } } @@ -361,7 +459,7 @@ network_attach(void *dev, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKST void network_close(void) { - timer_stop(&network_rx_queue_timer); + network_timer_stop(); /* If already closed, do nothing. */ if (network_mutex == NULL) return; @@ -371,21 +469,15 @@ network_close(void) /* Force-close the SLIRP module. */ net_slirp_close(); - - /* Close the network events. */ - if (poll_data.wake_poll_thread != NULL) { - thread_destroy_event(poll_data.wake_poll_thread); - poll_data.wake_poll_thread = NULL; - } - if (poll_data.poll_complete != NULL) { - thread_destroy_event(poll_data.poll_complete); - poll_data.poll_complete = NULL; - } /* Close the network thread mutex. */ thread_close_mutex(network_mutex); network_mutex = NULL; network_mac = NULL; +#ifdef ENABLE_NETWORK_LOG + thread_close_mutex(network_dump_mutex); + network_dump_mutex = NULL; +#endif /* Here is where we clear the queues. */ network_queue_clear(0); @@ -408,13 +500,9 @@ network_reset(void) { int i = -1; -#ifdef ENABLE_NIC_LOG - network_log("NETWORK: reset (type=%d, card=%d) debug=%d\n", - network_type, network_card, nic_do_log); -#else network_log("NETWORK: reset (type=%d, card=%d)\n", network_type, network_card); -#endif + ui_sb_update_icon(SB_NETWORK, 0); /* Just in case.. */ @@ -424,6 +512,9 @@ network_reset(void) if ((network_type==NET_TYPE_NONE) || (network_card==0)) return; network_mutex = thread_create_mutex(); +#ifdef ENABLE_NETWORK_LOG + network_dump_mutex = thread_create_mutex(); +#endif /* Initialize the platform module. */ switch(network_type) { @@ -452,12 +543,12 @@ network_reset(void) network_log("NETWORK: set up for %s, card='%s'\n", (network_type==NET_TYPE_SLIRP)?"SLiRP":"Pcap", - net_cards[network_card].name); + net_cards[network_card].device->name); /* Add the (new?) card to the I/O system. */ if (net_cards[network_card].device) { network_log("NETWORK: adding device '%s'\n", - net_cards[network_card].name); + net_cards[network_card].device->name); device_add(net_cards[network_card].device); } } @@ -467,46 +558,25 @@ network_reset(void) void network_tx(uint8_t *bufp, int len) { - network_busy(1); - ui_sb_update_icon(SB_NETWORK, 1); - network_queue_put(1, NULL, bufp, len); + network_queue_put(2, NULL, bufp, len); ui_sb_update_icon(SB_NETWORK, 0); - - network_busy(0); } /* Actually transmit the packet. */ -void -network_do_tx(void) -{ - netpkt_t *pkt = NULL; - - network_queue_get(1, &pkt); - if ((pkt != NULL) && (pkt->len > 0)) { - switch(network_type) { - case NET_TYPE_PCAP: - net_pcap_in(pkt->data, pkt->len); - break; - - case NET_TYPE_SLIRP: - net_slirp_in(pkt->data, pkt->len); - break; - } - } - network_queue_advance(1); -} - - int network_tx_queue_check(void) { if ((first_pkt[1] == NULL) && (last_pkt[1] == NULL)) return 0; + if (network_tx_pause) + return 1; + + network_queue_transmit(1); return 1; } @@ -548,14 +618,6 @@ network_card_available(int card) } -/* UI */ -char * -network_card_getname(int card) -{ - return((char *)net_cards[card].name); -} - - /* UI */ const device_t * network_card_getdevice(int card) @@ -570,7 +632,7 @@ network_card_has_config(int card) { if (! net_cards[card].device) return(0); - return(net_cards[card].device->config ? 1 : 0); + return(device_has_config(net_cards[card].device) ? 1 : 0); } @@ -578,7 +640,7 @@ network_card_has_config(int card) char * network_card_get_internal_name(int card) { - return((char *)net_cards[card].internal_name); + return device_get_internal_name(net_cards[card].device); } @@ -587,23 +649,21 @@ int network_card_get_from_internal_name(char *s) { int c = 0; - - while (strlen((char *)net_cards[c].internal_name)) { - if (! strcmp((char *)net_cards[c].internal_name, s)) - return(c); + + while (net_cards[c].device != NULL) { + if (! strcmp((char *)net_cards[c].device->internal_name, s)) + return(c); c++; } - - return(-1); + + return 0; } void network_set_wait(int wait) { - network_wait(1); net_wait = wait; - network_wait(0); } @@ -612,8 +672,6 @@ network_get_wait(void) { int ret; - network_wait(1); ret = net_wait; - network_wait(0); return ret; } diff --git a/src/network/pcap_if.c b/src/network/pcap_if.c index 7f08b723d..384b11746 100644 --- a/src/network/pcap_if.c +++ b/src/network/pcap_if.c @@ -69,12 +69,14 @@ static pcap_t *(*f_pcap_open_live)(const char *,int,int,int,char *); static int (*f_pcap_next_ex)(pcap_t*,struct pcap_pkthdr**,const unsigned char**); static void (*f_pcap_close)(pcap_t *); static dllimp_t pcap_imports[] = { - { "pcap_findalldevs", &f_pcap_findalldevs }, - { "pcap_freealldevs", &f_pcap_freealldevs }, - { "pcap_open_live", &f_pcap_open_live }, - { "pcap_next_ex", &f_pcap_next_ex }, - { "pcap_close", &f_pcap_close }, - { NULL, NULL }, +// clang-format off + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_next_ex", &f_pcap_next_ex }, + { "pcap_close", &f_pcap_close }, + { NULL, NULL }, +// clang-format on }; @@ -210,7 +212,7 @@ start_cap(char *dev) now = hdr->ts.tv_sec; ltime = localtime(&now); strftime(temp, sizeof(temp), "%H:%M:%S", ltime); - + /* Process and print the packet. */ printf("\n<< %s,%.6ld len=%u\n", temp, hdr->ts.tv_usec, hdr->len); @@ -269,6 +271,8 @@ main(int argc, char **argv) /* Try loading the DLL. */ #ifdef _WIN32 pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#elif defined __APPLE__ + pcap_handle = dynld_module("libpcap.dylib", pcap_imports); #else pcap_handle = dynld_module("libpcap.so", pcap_imports); #endif diff --git a/src/network/slirp/CMakeLists.txt b/src/network/slirp/CMakeLists.txt new file mode 100644 index 000000000..f3fa9348b --- /dev/null +++ b/src/network/slirp/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(slirp STATIC arp_table.c bootp.c cksum.c dnssearch.c if.c ip_icmp.c + ip_input.c ip_output.c mbuf.c misc.c sbuf.c slirp.c socket.c tcp_input.c + tcp_output.c tcp_subr.c tcp_timer.c udp.c util.c version.c) + +if(WIN32) + target_link_libraries(slirp wsock32 iphlpapi) +endif() + +# tinyglib conflicts with the real GLib used by Qt, let's just be safe +if(QT AND UNIX AND NOT APPLE) + set(SLIRP_TINYGLIB OFF) +endif() + +option(SLIRP_TINYGLIB "Use a minimal GLib stub (`tinyglib`) with SLiRP" ON) + +if(SLIRP_TINYGLIB) + target_sources(slirp PRIVATE tinyglib.c) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) + target_link_libraries(slirp PkgConfig::GLIB) + + target_compile_definitions(slirp PRIVATE TINYGLIB_USE_GLIB) +endif() diff --git a/src/network/slirp/COPYRIGHT.txt b/src/network/slirp/COPYRIGHT.txt deleted file mode 100644 index 62ccebae1..000000000 --- a/src/network/slirp/COPYRIGHT.txt +++ /dev/null @@ -1,61 +0,0 @@ -Slirp was written by Danny Gasparovski. -Copyright (c), 1995,1996 All Rights Reserved. - -Slirp is maintained by Kelly Price - -Slirp is free software; "free" as in you don't have to pay for it, and you -are free to do whatever you want with it. I do not accept any donations, -monetary or otherwise, for Slirp. Instead, I would ask you to pass this -potential donation to your favorite charity. In fact, I encourage -*everyone* who finds Slirp useful to make a small donation to their -favorite charity (for example, GreenPeace). This is not a requirement, but -a suggestion from someone who highly values the service they provide. - -The copyright terms and conditions: - ----BEGIN--- - - Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----END--- - -This basically means you can do anything you want with the software, except -1) call it your own, and 2) claim warranty on it. There is no warranty for -this software. None. Nada. If you lose a million dollars while using -Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. - -If these conditions cannot be met due to legal restrictions (E.g. where it -is against the law to give out Software without warranty), you must cease -using the software and delete all copies you have. - -Slirp uses code that is copyrighted by the following people/organizations: - -Juha Pirkola. -Gregory M. Christy. -The Regents of the University of California. -Carnegie Mellon University. -The Australian National University. -RSA Data Security, Inc. - -Please read the top of each source file for the details on the various -copyrights. \ No newline at end of file diff --git a/src/network/slirp/VERSION.txt b/src/network/slirp/VERSION.txt deleted file mode 100644 index 0dd1c2b2b..000000000 --- a/src/network/slirp/VERSION.txt +++ /dev/null @@ -1 +0,0 @@ -qemu 0.9.0 (2007/02/05) \ No newline at end of file diff --git a/src/network/slirp/arp_table.c b/src/network/slirp/arp_table.c new file mode 100644 index 000000000..959e5b9ec --- /dev/null +++ b/src/network/slirp/arp_table.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: MIT */ +/* + * ARP table + * + * Copyright (c) 2011 AdaCore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "slirp.h" + +#include + +void arp_table_add(Slirp *slirp, uint32_t ip_addr, + const uint8_t ethaddr[ETH_ALEN]) +{ + const uint32_t broadcast_addr = + ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr; + ArpTable *arptbl = &slirp->arp_table; + int i; + + DEBUG_CALL("arp_table_add"); + DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr })); + DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1], + ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]); + + if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) { + /* Do not register broadcast addresses */ + return; + } + + /* Search for an entry */ + for (i = 0; i < ARP_TABLE_SIZE; i++) { + if (arptbl->table[i].ar_sip == ip_addr) { + /* Update the entry */ + memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN); + return; + } + } + + /* No entry found, create a new one */ + arptbl->table[arptbl->next_victim].ar_sip = ip_addr; + memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN); + arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE; +} + +bool arp_table_search(Slirp *slirp, uint32_t ip_addr, + uint8_t out_ethaddr[ETH_ALEN]) +{ + const uint32_t broadcast_addr = + ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr; + ArpTable *arptbl = &slirp->arp_table; + int i; + + DEBUG_CALL("arp_table_search"); + DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr })); + + /* If broadcast address */ + if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) { + /* return Ethernet broadcast address */ + memset(out_ethaddr, 0xff, ETH_ALEN); + return 1; + } + + for (i = 0; i < ARP_TABLE_SIZE; i++) { + if (arptbl->table[i].ar_sip == ip_addr) { + memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN); + DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x", + out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], + out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); + return 1; + } + } + + return 0; +} diff --git a/src/network/slirp/bootp.c b/src/network/slirp/bootp.c index 9cbca7520..46e96810a 100644 --- a/src/network/slirp/bootp.c +++ b/src/network/slirp/bootp.c @@ -1,8 +1,9 @@ +/* SPDX-License-Identifier: MIT */ /* * QEMU BOOTP/DHCP server - * + * * Copyright (c) 2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -23,76 +24,92 @@ */ #include "slirp.h" +#if defined(_WIN32) +/* Windows ntohl() returns an u_long value. + * Add a type cast to match the format strings. */ +#define ntohl(n) ((uint32_t)ntohl(n)) +#endif + /* XXX: only DHCP is supported */ -#define NB_ADDR 16 - -#define START_ADDR 15 - #define LEASE_TIME (24 * 3600) -typedef struct { - uint8_t allocated; - uint8_t macaddr[6]; -} BOOTPClient; - -BOOTPClient bootp_clients[NB_ADDR]; - static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; -static BOOTPClient *get_new_addr(struct in_addr *paddr) +#define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__) + +static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr, + const uint8_t *macaddr) { BOOTPClient *bc; int i; - for(i = 0; i < NB_ADDR; i++) { - if (!bootp_clients[i].allocated) + for (i = 0; i < NB_BOOTP_CLIENTS; i++) { + bc = &slirp->bootp_clients[i]; + if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) goto found; } return NULL; - found: - bc = &bootp_clients[i]; +found: + bc = &slirp->bootp_clients[i]; bc->allocated = 1; - paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i); return bc; } -static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) +static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr, + const uint8_t *macaddr) +{ + uint32_t req_addr = ntohl(paddr->s_addr); + uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr); + BOOTPClient *bc; + + if (req_addr >= dhcp_addr && req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) { + bc = &slirp->bootp_clients[req_addr - dhcp_addr]; + if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) { + bc->allocated = 1; + return bc; + } + } + return NULL; +} + +static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr, + const uint8_t *macaddr) { BOOTPClient *bc; int i; - for(i = 0; i < NB_ADDR; i++) { - if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) + for (i = 0; i < NB_BOOTP_CLIENTS; i++) { + if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6)) goto found; } return NULL; - found: - bc = &bootp_clients[i]; +found: + bc = &slirp->bootp_clients[i]; bc->allocated = 1; - paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i); return bc; } -static void dhcp_decode(const uint8_t *buf, int size, - int *pmsg_type) +static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, + struct in_addr *preq_addr) { const uint8_t *p, *p_end; int len, tag; - *pmsg_type = 0; + *pmsg_type = 0; + preq_addr->s_addr = htonl(0L); - p = buf; - p_end = buf + size; - if (size < 5) - return; + p = bp->bp_vend; + p_end = p + DHCP_OPT_LEN; if (memcmp(p, rfc1533_cookie, 4) != 0) return; p += 4; while (p < p_end) { tag = p[0]; if (tag == RFC1533_PAD) { - p++; + p++; } else if (tag == RFC1533_END) { break; } else { @@ -100,57 +117,99 @@ static void dhcp_decode(const uint8_t *buf, int size, if (p >= p_end) break; len = *p++; + if (p + len > p_end) { + break; + } + DPRINTF("dhcp: tag=%d len=%d\n", tag, len); - switch(tag) { + switch (tag) { case RFC2132_MSG_TYPE: if (len >= 1) *pmsg_type = p[0]; break; + case RFC2132_REQ_ADDR: + if (len >= 4) { + memcpy(&(preq_addr->s_addr), p, 4); + } + break; default: break; } p += len; } } + if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) && + bp->bp_ciaddr.s_addr) { + memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4); + } } -static void bootp_reply(struct bootp_t *bp) +static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) { - BOOTPClient *bc; - struct SLIRPmbuf *m; + BOOTPClient *bc = NULL; + struct mbuf *m; struct bootp_t *rbp; struct sockaddr_in saddr, daddr; - struct in_addr dns_addr; + struct in_addr preq_addr; int dhcp_msg_type, val; uint8_t *q; + uint8_t *end; + uint8_t client_ethaddr[ETH_ALEN]; /* extract exact DHCP msg type */ - dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); - + dhcp_decode(bp, &dhcp_msg_type, &preq_addr); + DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type); + if (preq_addr.s_addr != htonl(0L)) + DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); + else { + DPRINTF("\n"); + } + if (dhcp_msg_type == 0) dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ - - if (dhcp_msg_type != DHCPDISCOVER && - dhcp_msg_type != DHCPREQUEST) + + if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST) return; - /* XXX: this is a hack to get the client mac address */ - memcpy(client_ethaddr, bp->bp_hwaddr, 6); - - if ((m = m_get()) == NULL) + + /* Get client's hardware address from bootp request */ + memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN); + + m = m_get(slirp); + if (!m) { return; - m->m_data += if_maxlinkhdr; + } + m->m_data += IF_MAXLINKHDR; rbp = (struct bootp_t *)m->m_data; m->m_data += sizeof(struct udpiphdr); memset(rbp, 0, sizeof(struct bootp_t)); if (dhcp_msg_type == DHCPDISCOVER) { - new_addr: - bc = get_new_addr(&daddr.sin_addr); - if (!bc) - return; - memcpy(bc->macaddr, client_ethaddr, 6); + if (preq_addr.s_addr != htonl(0L)) { + bc = request_addr(slirp, &preq_addr, client_ethaddr); + if (bc) { + daddr.sin_addr = preq_addr; + } + } + if (!bc) { + new_addr: + bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr); + if (!bc) { + DPRINTF("no address left\n"); + return; + } + } + memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); + } else if (preq_addr.s_addr != htonl(0L)) { + bc = request_addr(slirp, &preq_addr, client_ethaddr); + if (bc) { + daddr.sin_addr = preq_addr; + memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); + } else { + /* DHCPNAKs should be sent to broadcast */ + daddr.sin_addr.s_addr = 0xffffffff; + } } else { - bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); + bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr); if (!bc) { /* if never assigned, behaves as if it was already assigned (windows fix because it remembers its address) */ @@ -158,7 +217,10 @@ static void bootp_reply(struct bootp_t *bp) } } - saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); + /* Update ARP table for this IP address */ + arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr); + + saddr.sin_addr = slirp->vhost_addr; saddr.sin_port = htons(BOOTP_SERVER); daddr.sin_port = htons(BOOTP_CLIENT); @@ -167,27 +229,36 @@ static void bootp_reply(struct bootp_t *bp) rbp->bp_xid = bp->bp_xid; rbp->bp_htype = 1; rbp->bp_hlen = 6; - memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); + memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN); rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ q = rbp->bp_vend; + end = (uint8_t *)&rbp[1]; memcpy(q, rfc1533_cookie, 4); q += 4; - if (dhcp_msg_type == DHCPDISCOVER) { - *q++ = RFC2132_MSG_TYPE; - *q++ = 1; - *q++ = DHCPOFFER; - } else if (dhcp_msg_type == DHCPREQUEST) { - *q++ = RFC2132_MSG_TYPE; - *q++ = 1; - *q++ = DHCPACK; - } - - if (dhcp_msg_type == DHCPDISCOVER || - dhcp_msg_type == DHCPREQUEST) { + if (bc) { + DPRINTF("%s addr=%08" PRIx32 "\n", + (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed", + ntohl(daddr.sin_addr.s_addr)); + + if (dhcp_msg_type == DHCPDISCOVER) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPOFFER; + } else /* DHCPREQUEST */ { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPACK; + } + + if (slirp->bootp_filename) { + g_assert(strlen(slirp->bootp_filename) < sizeof(rbp->bp_file)); + strcpy(rbp->bp_file, slirp->bootp_filename); + } + *q++ = RFC2132_SRV_ID; *q++ = 4; memcpy(q, &saddr.sin_addr, 4); @@ -195,48 +266,104 @@ static void bootp_reply(struct bootp_t *bp) *q++ = RFC1533_NETMASK; *q++ = 4; - *q++ = 0xff; - *q++ = 0xff; - *q++ = 0xff; - *q++ = 0x00; - - *q++ = RFC1533_GATEWAY; - *q++ = 4; - memcpy(q, &saddr.sin_addr, 4); - q += 4; - - *q++ = RFC1533_DNS; - *q++ = 4; - dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); - memcpy(q, &dns_addr, 4); + memcpy(q, &slirp->vnetwork_mask, 4); q += 4; + if (!slirp->restricted) { + *q++ = RFC1533_GATEWAY; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_DNS; + *q++ = 4; + memcpy(q, &slirp->vnameserver_addr, 4); + q += 4; + } + *q++ = RFC2132_LEASE_TIME; *q++ = 4; val = htonl(LEASE_TIME); memcpy(q, &val, 4); q += 4; - if (*slirp_hostname) { - val = strlen(slirp_hostname); - *q++ = RFC1533_HOSTNAME; - *q++ = val; - memcpy(q, slirp_hostname, val); - q += val; + if (*slirp->client_hostname) { + val = strlen(slirp->client_hostname); + if (q + val + 2 >= end) { + g_warning("DHCP packet size exceeded, " + "omitting host name option."); + } else { + *q++ = RFC1533_HOSTNAME; + *q++ = val; + memcpy(q, slirp->client_hostname, val); + q += val; + } } + + if (slirp->vdomainname) { + val = strlen(slirp->vdomainname); + if (q + val + 2 >= end) { + g_warning("DHCP packet size exceeded, " + "omitting domain name option."); + } else { + *q++ = RFC1533_DOMAINNAME; + *q++ = val; + memcpy(q, slirp->vdomainname, val); + q += val; + } + } + + if (slirp->tftp_server_name) { + val = strlen(slirp->tftp_server_name); + if (q + val + 2 >= end) { + g_warning("DHCP packet size exceeded, " + "omitting tftp-server-name option."); + } else { + *q++ = RFC2132_TFTP_SERVER_NAME; + *q++ = val; + memcpy(q, slirp->tftp_server_name, val); + q += val; + } + } + + if (slirp->vdnssearch) { + val = slirp->vdnssearch_len; + if (q + val >= end) { + g_warning("DHCP packet size exceeded, " + "omitting domain-search option."); + } else { + memcpy(q, slirp->vdnssearch, val); + q += val; + } + } + } else { + static const char nak_msg[] = "requested address not available"; + + DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); + + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPNAK; + + *q++ = RFC2132_MESSAGE; + *q++ = sizeof(nak_msg) - 1; + memcpy(q, nak_msg, sizeof(nak_msg) - 1); + q += sizeof(nak_msg) - 1; } - *q++ = RFC1533_END; - - m->m_len = sizeof(struct bootp_t) - - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + assert(q < end); + *q = RFC1533_END; + + daddr.sin_addr.s_addr = 0xffffffffu; + + m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr); + udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); } -void bootp_input(struct SLIRPmbuf *m) +void bootp_input(struct mbuf *m) { struct bootp_t *bp = mtod(m, struct bootp_t *); if (bp->bp_op == BOOTP_REQUEST) { - bootp_reply(bp); + bootp_reply(m->slirp, bp); } } diff --git a/src/network/slirp/bootp.h b/src/network/slirp/bootp.h index b2ee26e95..a57fa51bc 100644 --- a/src/network/slirp/bootp.h +++ b/src/network/slirp/bootp.h @@ -1,98 +1,101 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* bootp/dhcp defines */ -#define BOOTP_SERVER 67 -#define BOOTP_CLIENT 68 +#ifndef SLIRP_BOOTP_H +#define SLIRP_BOOTP_H -#define BOOTP_REQUEST 1 -#define BOOTP_REPLY 2 +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 -#define RFC1533_COOKIE 99, 130, 83, 99 -#define RFC1533_PAD 0 -#define RFC1533_NETMASK 1 -#define RFC1533_TIMEOFFSET 2 -#define RFC1533_GATEWAY 3 -#define RFC1533_TIMESERVER 4 -#define RFC1533_IEN116NS 5 -#define RFC1533_DNS 6 -#define RFC1533_LOGSERVER 7 -#define RFC1533_COOKIESERVER 8 -#define RFC1533_LPRSERVER 9 -#define RFC1533_IMPRESSSERVER 10 -#define RFC1533_RESOURCESERVER 11 -#define RFC1533_HOSTNAME 12 -#define RFC1533_BOOTFILESIZE 13 -#define RFC1533_MERITDUMPFILE 14 -#define RFC1533_DOMAINNAME 15 -#define RFC1533_SWAPSERVER 16 -#define RFC1533_ROOTPATH 17 -#define RFC1533_EXTENSIONPATH 18 -#define RFC1533_IPFORWARDING 19 -#define RFC1533_IPSOURCEROUTING 20 -#define RFC1533_IPPOLICYFILTER 21 -#define RFC1533_IPMAXREASSEMBLY 22 -#define RFC1533_IPTTL 23 -#define RFC1533_IPMTU 24 -#define RFC1533_IPMTUPLATEAU 25 -#define RFC1533_INTMTU 26 -#define RFC1533_INTLOCALSUBNETS 27 -#define RFC1533_INTBROADCAST 28 -#define RFC1533_INTICMPDISCOVER 29 -#define RFC1533_INTICMPRESPOND 30 +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 #define RFC1533_INTROUTEDISCOVER 31 -#define RFC1533_INTROUTESOLICIT 32 -#define RFC1533_INTSTATICROUTES 33 -#define RFC1533_LLTRAILERENCAP 34 -#define RFC1533_LLARPCACHETMO 35 -#define RFC1533_LLETHERNETENCAP 36 -#define RFC1533_TCPTTL 37 -#define RFC1533_TCPKEEPALIVETMO 38 -#define RFC1533_TCPKEEPALIVEGB 39 -#define RFC1533_NISDOMAIN 40 -#define RFC1533_NISSERVER 41 -#define RFC1533_NTPSERVER 42 -#define RFC1533_VENDOR 43 -#define RFC1533_NBNS 44 -#define RFC1533_NBDD 45 -#define RFC1533_NBNT 46 -#define RFC1533_NBSCOPE 47 -#define RFC1533_XFS 48 -#define RFC1533_XDM 49 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 -#define RFC2132_REQ_ADDR 50 -#define RFC2132_LEASE_TIME 51 -#define RFC2132_MSG_TYPE 53 -#define RFC2132_SRV_ID 54 -#define RFC2132_PARAM_LIST 55 -#define RFC2132_MAX_SIZE 57 -#define RFC2132_RENEWAL_TIME 58 -#define RFC2132_REBIND_TIME 59 +#define RFC2132_REQ_ADDR 50 +#define RFC2132_LEASE_TIME 51 +#define RFC2132_MSG_TYPE 53 +#define RFC2132_SRV_ID 54 +#define RFC2132_PARAM_LIST 55 +#define RFC2132_MESSAGE 56 +#define RFC2132_MAX_SIZE 57 +#define RFC2132_RENEWAL_TIME 58 +#define RFC2132_REBIND_TIME 59 +#define RFC2132_TFTP_SERVER_NAME 66 -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPACK 5 +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPACK 5 +#define DHCPNAK 6 -#define RFC1533_VENDOR_MAJOR 0 -#define RFC1533_VENDOR_MINOR 0 +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 -#define RFC1533_VENDOR_MAGIC 128 -#define RFC1533_VENDOR_ADDPARM 129 -#define RFC1533_VENDOR_ETHDEV 130 -#define RFC1533_VENDOR_HOWTO 132 -#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#define RFC1533_VENDOR_ETHDEV 130 +#define RFC1533_VENDOR_HOWTO 132 +#define RFC1533_VENDOR_MNUOPTS 160 #define RFC1533_VENDOR_SELECTION 176 -#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_MOTD 184 #define RFC1533_VENDOR_NUMOFMOTD 8 -#define RFC1533_VENDOR_IMG 192 -#define RFC1533_VENDOR_NUMOFIMG 16 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 -#define RFC1533_END 255 -#define BOOTP_VENDOR_LEN 64 -#define DHCP_OPT_LEN 312 - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 +#define DHCP_OPT_LEN 312 struct bootp_t { struct ip ip; @@ -110,12 +113,17 @@ struct bootp_t { struct in_addr bp_giaddr; uint8_t bp_hwaddr[16]; uint8_t bp_sname[64]; - uint8_t bp_file[128]; + char bp_file[128]; uint8_t bp_vend[DHCP_OPT_LEN]; -} PACKED__; +}; + +typedef struct { + uint16_t allocated; + uint8_t macaddr[6]; +} BOOTPClient; + +#define NB_BOOTP_CLIENTS 16 + +void bootp_input(struct mbuf *m); -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) #endif - -void bootp_input(struct SLIRPmbuf *m); diff --git a/src/network/slirp/cksum.c b/src/network/slirp/cksum.c index eb0ae547f..4d08380a4 100644 --- a/src/network/slirp/cksum.c +++ b/src/network/slirp/cksum.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1988, 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -37,101 +38,142 @@ * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. - * - * XXX Since we will never span more than 1 SLIRPmbuf, we can optimise this + * + * XXX Since we will never span more than 1 mbuf, we can optimise this */ -#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) -#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} +#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) +#define REDUCE \ + { \ + l_util.l = sum; \ + sum = l_util.s[0] + l_util.s[1]; \ + (void)ADDCARRY(sum); \ + } -int cksum(struct SLIRPmbuf *m, int len) +int cksum(struct mbuf *m, int len) { - register u_int16_t *w; - register int sum = 0; - register int mlen = 0; - int byte_swapped = 0; + register uint16_t *w; + register int sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + union { + uint8_t c[2]; + uint16_t s; + } s_util; + union { + uint16_t s[2]; + uint32_t l; + } l_util; + + if (m->m_len == 0) + goto cont; + w = mtod(m, uint16_t *); + + mlen = m->m_len; + + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to even boundary. + */ + if ((1 & (uintptr_t)w) && (mlen > 0)) { + REDUCE; + sum <<= 8; + s_util.c[0] = *(uint8_t *)w; + w = (uint16_t *)((int8_t *)w + 1); + mlen--; + byte_swapped = 1; + } + /* + * Unroll the loop to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + sum += w[0]; + sum += w[1]; + sum += w[2]; + sum += w[3]; + sum += w[4]; + sum += w[5]; + sum += w[6]; + sum += w[7]; + sum += w[8]; + sum += w[9]; + sum += w[10]; + sum += w[11]; + sum += w[12]; + sum += w[13]; + sum += w[14]; + sum += w[15]; + w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + sum += w[0]; + sum += w[1]; + sum += w[2]; + sum += w[3]; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + goto cont; + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + + if (byte_swapped) { + REDUCE; + sum <<= 8; + if (mlen == -1) { + s_util.c[1] = *(uint8_t *)w; + sum += s_util.s; + mlen = 0; + } else + + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(uint8_t *)w; - union { - u_int8_t c[2]; - u_int16_t s; - } s_util; - union { - u_int16_t s[2]; - u_int32_t l; - } l_util; - - if (m->m_len == 0) - goto cont; - w = mtod(m, u_int16_t *); - - mlen = m->m_len; - - if (len < mlen) - mlen = len; - len -= mlen; - /* - * Force to even boundary. - */ - if ((1 & (intptr_t) w) && (mlen > 0)) { - REDUCE; - sum <<= 8; - s_util.c[0] = *(u_int8_t *)w; - w = (u_int16_t *)((int8_t *)w + 1); - mlen--; - byte_swapped = 1; - } - /* - * Unroll the loop to make overhead from - * branches &c small. - */ - while ((mlen -= 32) >= 0) { - sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; - sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; - sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; - sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; - w += 16; - } - mlen += 32; - while ((mlen -= 8) >= 0) { - sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; - w += 4; - } - mlen += 8; - if (mlen == 0 && byte_swapped == 0) - goto cont; - REDUCE; - while ((mlen -= 2) >= 0) { - sum += *w++; - } - - if (byte_swapped) { - REDUCE; - sum <<= 8; - byte_swapped = 0; - if (mlen == -1) { - s_util.c[1] = *(u_int8_t *)w; - sum += s_util.s; - mlen = 0; - } else - - mlen = -1; - } else if (mlen == -1) - s_util.c[0] = *(u_int8_t *)w; - cont: -#ifdef SLIRP_DEBUG - if (len) { - DEBUG_ERROR((dfd, "cksum: out of data\n")); - DEBUG_ERROR((dfd, " len = %d\n", len)); - } -#endif - if (mlen == -1) { - /* The last SLIRPmbuf has odd # of bytes. Follow the - standard (the odd byte may be shifted left by 8 bits - or not as determined by endian-ness of the machine) */ - s_util.c[1] = 0; - sum += s_util.s; - } - REDUCE; - return (~sum & 0xffff); + if (len) { + DEBUG_ERROR("cksum: out of data"); + DEBUG_ERROR(" len = %d", len); + } + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} + +int ip6_cksum(struct mbuf *m) +{ + /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum + * separately from the mbuf */ + struct ip6 save_ip, *ip = mtod(m, struct ip6 *); + struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *); + int sum; + + save_ip = *ip; + + ih->ih_src = save_ip.ip_src; + ih->ih_dst = save_ip.ip_dst; + ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl)); + ih->ih_zero_hi = 0; + ih->ih_zero_lo = 0; + ih->ih_nh = save_ip.ip_nh; + + sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl)); + + *ip = save_ip; + + return sum; } diff --git a/src/network/slirp/config-host.h b/src/network/slirp/config-host.h deleted file mode 100644 index 2983fc727..000000000 --- a/src/network/slirp/config-host.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Automatically generated by configure - do not modify */ -#define CONFIG_QEMU_SHAREDIR "/c/Program Files/Qemu" -#define HOST_I386 1 -#define HOST_LONG_BITS 32 -#define CONFIG_WIN32 1 -#define CONFIG_GDBSTUB 1 -#define CONFIG_SLIRP 1 -#define QEMU_VERSION "0.9.0" -#define CONFIG_UNAME_RELEASE "" diff --git a/src/network/slirp/config.h b/src/network/slirp/config.h deleted file mode 100644 index d9043ae85..000000000 --- a/src/network/slirp/config.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Automatically generated by configure - do not modify */ -#include "config-host.h" -#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386" -#define TARGET_ARCH "i386" -#define TARGET_I386 1 -#define USE_KQEMU 1 -#define CONFIG_SOFTMMU 1 -#define CONFIG_SDL 1 -#define HAVE_STRDUP 1 diff --git a/src/network/slirp/ctl.h b/src/network/slirp/ctl.h deleted file mode 100644 index 4a8576dc1..000000000 --- a/src/network/slirp/ctl.h +++ /dev/null @@ -1,7 +0,0 @@ -#define CTL_CMD 0 -#define CTL_EXEC 1 -#define CTL_ALIAS 2 -#define CTL_DNS 3 - -#define CTL_SPECIAL "10.0.2.0" -#define CTL_LOCAL "10.0.2.15" diff --git a/src/network/slirp/debug.c b/src/network/slirp/debug.c deleted file mode 100644 index eef2c7de1..000000000 --- a/src/network/slirp/debug.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) 1995 Danny Gasparovski. - * Portions copyright (c) 2000 Kelly Price. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. - */ - -#ifndef _WIN32 -# include -#endif -#include "slirp.h" - -FILE *dfd = NULL; -#ifdef SLIRP_DEBUG -int dostats = 1; -#else -int dostats = 0; -#endif -int slirp_debug = 0; - -#ifndef _MSC_VER -extern char *strerror _P((int)); -#endif - -/* Carry over one item from main.c so that the tty's restored. - * Only done when the tty being used is /dev/tty --RedWolf */ -extern struct termios slirp_tty_settings; -extern int slirp_tty_restore; - - -void -debug_init(file, dbg) - char *file; - int dbg; -{ - /* Close the old debugging file */ - if (dfd) - fclose(dfd); - - dfd = fopen(file,"w"); - if (dfd != NULL) { -#if 1 - fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); -#endif - fprintf(dfd,"Debugging Started level %i.\r\n",dbg); - fflush(dfd); - slirp_debug = dbg; - } else { - lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", - file, strerror(errno)); - } -} - -/* - * Dump a packet in the same format as tcpdump -x - */ -#ifdef SLIRP_DEBUG -void -dump_packet(dat, n) - void *dat; - int n; -{ - u_char *pptr = (u_char *)dat; - int j,k; - - n /= 16; - n++; - DEBUG_MISC((dfd, "PACKET DUMPED: \n")); - for(j = 0; j < n; j++) { - for(k = 0; k < 6; k++) - DEBUG_MISC((dfd, "%02x ", *pptr++)); - DEBUG_MISC((dfd, "\n")); - fflush(dfd); - } -} -#endif - -#if 0 -/* - * Statistic routines - * - * These will print statistics to the screen, the debug file (dfd), or - * a buffer, depending on "type", so that the stats can be sent over - * the link as well. - */ - -void -ttystats(ttyp) - struct ttys *ttyp; -{ - struct slirp_ifstats *is = &ttyp->ifstats; - char buff[512]; - - lprint(" \r\n"); - - if (if_comp & IF_COMPRESS) - strcpy(buff, "on"); - else if (if_comp & IF_NOCOMPRESS) - strcpy(buff, "off"); - else - strcpy(buff, "off (for now)"); - lprint("Unit %d:\r\n", ttyp->unit); - lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( -#ifdef USE_PPP - ttyp->proto==PROTO_PPP?"PPP": -#endif - "SLIP"), buff); - lprint(" %d baudrate\r\n", ttyp->baud); - lprint(" interface is %s\r\n", ttyp->up?"up":"down"); - lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); -#ifndef FULL_BOLT - lprint(" towrite is %d bytes\r\n", ttyp->towrite); -#endif - if (ttyp->zeros) - lprint(" %d zeros have been typed\r\n", ttyp->zeros); - else if (ttyp->ones) - lprint(" %d ones have been typed\r\n", ttyp->ones); - lprint("Interface stats:\r\n"); - lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); - lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); - lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); - lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); - lprint(" %6d bad input packets\r\n", is->in_mbad); -} - -void -allttystats() -{ - struct ttys *ttyp; - - for (ttyp = ttys; ttyp; ttyp = ttyp->next) - ttystats(ttyp); -} -#endif - -void -ipstats() -{ - lprint(" \r\n"); - - lprint("IP stats:\r\n"); - lprint(" %6d total packets received (%d were unaligned)\r\n", - ipstat.ips_total, ipstat.ips_unaligned); - lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); - lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); - lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); - lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); - lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); - lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); - lprint(" %6d fragments received\r\n", ipstat.ips_fragments); - lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); - lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); - lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); - lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); - lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); - lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); - lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); -} - -#if 0 -void -vjstats() -{ - lprint(" \r\n"); - - lprint("VJ compression stats:\r\n"); - - lprint(" %6d outbound packets (%d compressed)\r\n", - comp_s.sls_packets, comp_s.sls_compressed); - lprint(" %6d searches for connection stats (%d misses)\r\n", - comp_s.sls_searches, comp_s.sls_misses); - lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); - lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); - lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); - lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); -} -#endif - -void -tcpstats() -{ - lprint(" \r\n"); - - lprint("TCP stats:\r\n"); - - lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); - lprint(" %6d data packets (%d bytes)\r\n", - tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); - lprint(" %6d data packets retransmitted (%d bytes)\r\n", - tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); - lprint(" %6d ack-only packets (%d delayed)\r\n", - tcpstat.tcps_sndacks, tcpstat.tcps_delack); - lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); - lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); - lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); - lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); - lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); - - lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); - lprint(" %6d acks (for %d bytes)\r\n", - tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); - lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); - lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); - lprint(" %6d packets received in sequence (%d bytes)\r\n", - tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); - lprint(" %6d completely duplicate packets (%d bytes)\r\n", - tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); - - lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", - tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); - lprint(" %6d out-of-order packets (%d bytes)\r\n", - tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); - lprint(" %6d packets of data after window (%d bytes)\r\n", - tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); - lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); - lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); - lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); - lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); - lprint(" %6d discarded for bad header offset fields\r\n", - tcpstat.tcps_rcvbadoff); - - lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); - lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); - lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); - lprint(" %6d connections closed (including %d drop)\r\n", - tcpstat.tcps_closed, tcpstat.tcps_drops); - lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); - lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", - tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); - lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); - lprint(" %6d connections dropped by rxmt timeout\r\n", - tcpstat.tcps_timeoutdrop); - lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); - lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); - lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); - lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); - lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); - lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); - lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); - - -/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ -/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ - -} - -void -udpstats() -{ - lprint(" \r\n"); - - lprint("UDP stats:\r\n"); - lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); - lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); - lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); - lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); - lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); - lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); -} - -void -icmpstats() -{ - lprint(" \r\n"); - lprint("ICMP stats:\r\n"); - lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); - lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); - lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); - lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); - lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); - lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); -} - -void -mbufstats() -{ - struct SLIRPmbuf *m; - int i; - - lprint(" \r\n"); - - lprint("Mbuf stats:\r\n"); - - lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); - - i = 0; - for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next) - i++; - lprint(" %6d mbufs on free list\r\n", i); - - i = 0; - for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) - i++; - lprint(" %6d mbufs on used list\r\n", i); - lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); -} - - -void sockstats(void) -{ - char buff[256]; - int n; - struct SLIRPsocket *so; - - lprint(" \r\n"); - - lprint( - "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); - - for (so = tcb.so_next; so != &tcb; so = so->so_next) { - - n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); - while (n < 17) - buff[n++] = ' '; - buff[17] = 0; - lprint("%s %3d %15s %5d ", - buff, so->s, - inet_ntoa(so->so_laddr), ntohs(so->so_lport)); - lprint("%15s %5d %5d %5d\r\n", - inet_ntoa(so->so_faddr), ntohs(so->so_fport), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - - } - - for (so = udb.so_next; so != &udb; so = so->so_next) { - - n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); - while (n < 17) - buff[n++] = ' '; - buff[17] = 0; - lprint("%s %3d %15s %5d ", - buff, so->s, - inet_ntoa(so->so_laddr), ntohs(so->so_lport)); - lprint("%15s %5d %5d %5d\r\n", - inet_ntoa(so->so_faddr), ntohs(so->so_fport), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - } -} - - - -void printf_sockstats(void) -{ - char buff[256]; - int n; - struct SLIRPsocket *so; - - printf(" \r\n"); - - printf( - "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); - - for (so = tcb.so_next; so != &tcb; so = so->so_next) { - - n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); - while (n < 17) - buff[n++] = ' '; - buff[17] = 0; - printf("%s %3d %15s %5d ", - buff, so->s, - inet_ntoa(so->so_laddr), ntohs(so->so_lport)); - printf("%15s %5d %5d %5d\r\n", - inet_ntoa(so->so_faddr), ntohs(so->so_fport), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - - } - - for (so = udb.so_next; so != &udb; so = so->so_next) { - - n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); - while (n < 17) - buff[n++] = ' '; - buff[17] = 0; - printf("%s %3d %15s %5d ", - buff, so->s, - inet_ntoa(so->so_laddr), ntohs(so->so_lport)); - printf("%15s %5d %5d %5d\r\n", - inet_ntoa(so->so_faddr), ntohs(so->so_fport), - so->so_rcv.sb_cc, so->so_snd.sb_cc); - } -printf("\n\n"); -} - -//Simple code to purge and close open sockets. -//This way we can open/close/open/close.. -void purgesocks(void) -{ - struct SLIRPsocket *so; - - for (so = tcb.so_next; so != &tcb; so = so->so_next) { - - closesocket(so->s); //close the socket - } -} - -#if 1 -void -slirp_exit(exit_status) - int exit_status; -{ -// struct ttys *ttyp; - - DEBUG_CALL("slirp_exit"); - DEBUG_ARG("exit_status = %d", exit_status); - - if (dostats) { - lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; - if (!dfd) - debug_init("slirp_stats", 0xf); - lprint_arg = (char **)&dfd; - - ipstats(); - tcpstats(); - udpstats(); - icmpstats(); - mbufstats(); - sockstats(); - fclose(dfd); -// allttystats(); -// vjstats(); - } - -// for (ttyp = ttys; ttyp; ttyp = ttyp->next) -// tty_detached(ttyp, 1); - -// if (slirp_forked) { -// /* Menendez time */ -// if (kill(getppid(), SIGQUIT) < 0) -// lprint("Couldn't kill parent process %ld!\n", -// (long) getppid()); -// } - - /* Restore the terminal if we gotta */ -// if(slirp_tty_restore) -// tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ -// exit(exit_status); - - //This will iterate though the sockets, and close them all (think redirects) - //PCem will have SLiRP open, close several times, which trips up SLiRP - //So for now I go through the sockets and close them - purgesocks(); - -} -#endif diff --git a/src/network/slirp/debug.h b/src/network/slirp/debug.h index a1eafa130..47712bd78 100644 --- a/src/network/slirp/debug.h +++ b/src/network/slirp/debug.h @@ -1,49 +1,51 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#define PRN_STDERR 1 -#define PRN_SPRINTF 2 +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#define DBG_CALL (1 << 0) +#define DBG_MISC (1 << 1) +#define DBG_ERROR (1 << 2) +#define DBG_TFTP (1 << 3) -extern FILE *dfd; -extern FILE *lfd; -extern int dostats; extern int slirp_debug; -#define DBG_CALL 0x1 -#define DBG_MISC 0x2 -#define DBG_ERROR 0x4 -#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR +#define DEBUG_CALL(fmt, ...) \ + do { \ + if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \ + g_debug(fmt "...", ##__VA_ARGS__); \ + } \ + } while (0) -#ifdef SLIRP_DEBUG -#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } -#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } -#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } -#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } -#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } +#define DEBUG_ARG(fmt, ...) \ + do { \ + if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \ + g_debug(" " fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DEBUG_MISC(fmt, ...) \ + do { \ + if (G_UNLIKELY(slirp_debug & DBG_MISC)) { \ + g_debug(fmt, ##__VA_ARGS__); \ + } \ + } while (0) -#else +#define DEBUG_ERROR(fmt, ...) \ + do { \ + if (G_UNLIKELY(slirp_debug & DBG_ERROR)) { \ + g_debug(fmt, ##__VA_ARGS__); \ + } \ + } while (0) -#define DEBUG_CALL(x) -#define DEBUG_ARG(x, y) -#define DEBUG_ARGS(x) -#define DEBUG_MISC(x) -#define DEBUG_ERROR(x) - -#endif - -void debug_init _P((char *, int)); -void allttystats _P((void)); -void ipstats _P((void)); -void vjstats _P((void)); -void tcpstats _P((void)); -void udpstats _P((void)); -void icmpstats _P((void)); -void mbufstats _P((void)); -void sockstats _P((void)); -void slirp_exit _P((int)); +#define DEBUG_TFTP(fmt, ...) \ + do { \ + if (G_UNLIKELY(slirp_debug & DBG_TFTP)) { \ + g_debug(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#endif /* DEBUG_H_ */ diff --git a/src/network/slirp/dhcpv6.c b/src/network/slirp/dhcpv6.c new file mode 100644 index 000000000..77b451b91 --- /dev/null +++ b/src/network/slirp/dhcpv6.c @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * SLIRP stateless DHCPv6 + * + * We only support stateless DHCPv6, e.g. for network booting. + * See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details. + * + * Copyright 2016 Thomas Huth, Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "slirp.h" +#include "dhcpv6.h" + +/* DHCPv6 message types */ +#define MSGTYPE_REPLY 7 +#define MSGTYPE_INFO_REQUEST 11 + +/* DHCPv6 option types */ +#define OPTION_CLIENTID 1 +#define OPTION_IAADDR 5 +#define OPTION_ORO 6 +#define OPTION_DNS_SERVERS 23 +#define OPTION_BOOTFILE_URL 59 + +struct requested_infos { + uint8_t *client_id; + int client_id_len; + bool want_dns; + bool want_boot_url; +}; + +/** + * Analyze the info request message sent by the client to see what data it + * provided and what it wants to have. The information is gathered in the + * "requested_infos" struct. Note that client_id (if provided) points into + * the odata region, thus the caller must keep odata valid as long as it + * needs to access the requested_infos struct. + */ +static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen, + struct requested_infos *ri) +{ + int i, req_opt; + + while (olen > 4) { + /* Parse one option */ + int option = odata[0] << 8 | odata[1]; + int len = odata[2] << 8 | odata[3]; + + if (len + 4 > olen) { + slirp->cb->guest_error("Guest sent bad DHCPv6 packet!", + slirp->opaque); + return -E2BIG; + } + + switch (option) { + case OPTION_IAADDR: + /* According to RFC3315, we must discard requests with IA option */ + return -EINVAL; + case OPTION_CLIENTID: + if (len > 256) { + /* Avoid very long IDs which could cause problems later */ + return -E2BIG; + } + ri->client_id = odata + 4; + ri->client_id_len = len; + break; + case OPTION_ORO: /* Option request option */ + if (len & 1) { + return -EINVAL; + } + /* Check which options the client wants to have */ + for (i = 0; i < len; i += 2) { + req_opt = odata[4 + i] << 8 | odata[4 + i + 1]; + switch (req_opt) { + case OPTION_DNS_SERVERS: + ri->want_dns = true; + break; + case OPTION_BOOTFILE_URL: + ri->want_boot_url = true; + break; + default: + DEBUG_MISC("dhcpv6: Unsupported option request %d", + req_opt); + } + } + break; + default: + DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option, + len); + } + + odata += len + 4; + olen -= len + 4; + } + + return 0; +} + + +/** + * Handle information request messages + */ +static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas, + uint32_t xid, uint8_t *odata, int olen) +{ + struct requested_infos ri = { NULL }; + struct sockaddr_in6 sa6, da6; + struct mbuf *m; + uint8_t *resp; + + if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) { + return; + } + + m = m_get(slirp); + if (!m) { + return; + } + memset(m->m_data, 0, m->m_size); + m->m_data += IF_MAXLINKHDR; + resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr); + + /* Fill in response */ + *resp++ = MSGTYPE_REPLY; + *resp++ = (uint8_t)(xid >> 16); + *resp++ = (uint8_t)(xid >> 8); + *resp++ = (uint8_t)xid; + + if (ri.client_id) { + *resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */ + *resp++ = OPTION_CLIENTID; /* option-code low byte */ + *resp++ = ri.client_id_len >> 8; /* option-len high byte */ + *resp++ = ri.client_id_len; /* option-len low byte */ + memcpy(resp, ri.client_id, ri.client_id_len); + resp += ri.client_id_len; + } + if (ri.want_dns) { + *resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */ + *resp++ = OPTION_DNS_SERVERS; /* option-code low byte */ + *resp++ = 0; /* option-len high byte */ + *resp++ = 16; /* option-len low byte */ + memcpy(resp, &slirp->vnameserver_addr6, 16); + resp += 16; + } + if (ri.want_boot_url) { + uint8_t *sa = slirp->vhost_addr6.s6_addr; + int slen, smaxlen; + + *resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */ + *resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */ + smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2); + slen = slirp_fmt((char *)resp + 2, smaxlen, + "tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s", + sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7], + sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14], + sa[15], slirp->bootp_filename); + *resp++ = slen >> 8; /* option-len high byte */ + *resp++ = slen; /* option-len low byte */ + resp += slen; + } + + sa6.sin6_addr = slirp->vhost_addr6; + sa6.sin6_port = DHCPV6_SERVER_PORT; + da6.sin6_addr = srcsas->sin6_addr; + da6.sin6_port = srcsas->sin6_port; + m->m_data += sizeof(struct ip6) + sizeof(struct udphdr); + m->m_len = resp - (uint8_t *)m->m_data; + udp6_output(NULL, m, &sa6, &da6); +} + +/** + * Handle DHCPv6 messages sent by the client + */ +void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m) +{ + uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr); + int data_len = m->m_len - sizeof(struct udphdr); + uint32_t xid; + + if (data_len < 4) { + return; + } + + xid = ntohl(*(uint32_t *)data) & 0xffffff; + + switch (data[0]) { + case MSGTYPE_INFO_REQUEST: + dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4); + break; + default: + DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]); + } +} diff --git a/src/network/slirp/dhcpv6.h b/src/network/slirp/dhcpv6.h new file mode 100644 index 000000000..d12c49b36 --- /dev/null +++ b/src/network/slirp/dhcpv6.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Definitions and prototypes for SLIRP stateless DHCPv6 + * + * Copyright 2016 Thomas Huth, Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SLIRP_DHCPV6_H +#define SLIRP_DHCPV6_H + +#define DHCPV6_SERVER_PORT 547 + +#define ALLDHCP_MULTICAST \ + { \ + .s6_addr = { \ + 0xff, \ + 0x02, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x01, \ + 0x00, \ + 0x02 \ + } \ + } + +#define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST) + +void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m); + +#endif diff --git a/src/network/slirp/dnssearch.c b/src/network/slirp/dnssearch.c new file mode 100644 index 000000000..55497e860 --- /dev/null +++ b/src/network/slirp/dnssearch.c @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Domain search option for DHCP (RFC 3397) + * + * Copyright (c) 2012 Klaus Stengel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "slirp.h" + +static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119; +static const uint8_t MAX_OPT_LEN = 255; +static const uint8_t OPT_HEADER_LEN = 2; +static const uint8_t REFERENCE_LEN = 2; + +struct compact_domain; + +typedef struct compact_domain { + struct compact_domain *self; + struct compact_domain *refdom; + uint8_t *labels; + size_t len; + size_t common_octets; +} CompactDomain; + +static size_t domain_suffix_diffoff(const CompactDomain *a, + const CompactDomain *b) +{ + size_t la = a->len, lb = b->len; + uint8_t *da = a->labels + la, *db = b->labels + lb; + size_t i, lm = (la < lb) ? la : lb; + + for (i = 0; i < lm; i++) { + da--; + db--; + if (*da != *db) { + break; + } + } + return i; +} + +static int domain_suffix_ord(const void *cva, const void *cvb) +{ + const CompactDomain *a = cva, *b = cvb; + size_t la = a->len, lb = b->len; + size_t doff = domain_suffix_diffoff(a, b); + uint8_t ca = a->labels[la - doff]; + uint8_t cb = b->labels[lb - doff]; + + if (ca < cb) { + return -1; + } + if (ca > cb) { + return 1; + } + if (la < lb) { + return -1; + } + if (la > lb) { + return 1; + } + return 0; +} + +static size_t domain_common_label(CompactDomain *a, CompactDomain *b) +{ + size_t res, doff = domain_suffix_diffoff(a, b); + uint8_t *first_eq_pos = a->labels + (a->len - doff); + uint8_t *label = a->labels; + + while (*label && label < first_eq_pos) { + label += *label + 1; + } + res = a->len - (label - a->labels); + /* only report if it can help to reduce the packet size */ + return (res > REFERENCE_LEN) ? res : 0; +} + +static void domain_fixup_order(CompactDomain *cd, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + CompactDomain *cur = cd + i, *next = cd[i].self; + + while (!cur->common_octets) { + CompactDomain *tmp = next->self; /* backup target value */ + + next->self = cur; + cur->common_octets++; + + cur = next; + next = tmp; + } + } +} + +static void domain_mklabels(CompactDomain *cd, const char *input) +{ + uint8_t *len_marker = cd->labels; + uint8_t *output = len_marker; /* pre-incremented */ + const char *in = input; + char cur_chr; + size_t len = 0; + + if (cd->len == 0) { + goto fail; + } + cd->len++; + + do { + cur_chr = *in++; + if (cur_chr == '.' || cur_chr == '\0') { + len = output - len_marker; + if ((len == 0 && cur_chr == '.') || len >= 64) { + goto fail; + } + *len_marker = len; + + output++; + len_marker = output; + } else { + output++; + *output = cur_chr; + } + } while (cur_chr != '\0'); + + /* ensure proper zero-termination */ + if (len != 0) { + *len_marker = 0; + cd->len++; + } + return; + +fail: + g_warning("failed to parse domain name '%s'\n", input); + cd->len = 0; +} + +static void domain_mkxrefs(CompactDomain *doms, CompactDomain *last, + size_t depth) +{ + CompactDomain *i = doms, *target = doms; + + do { + if (i->labels < target->labels) { + target = i; + } + } while (i++ != last); + + for (i = doms; i != last; i++) { + CompactDomain *group_last; + size_t next_depth; + + if (i->common_octets == depth) { + continue; + } + + next_depth = -1; + for (group_last = i; group_last != last; group_last++) { + size_t co = group_last->common_octets; + if (co <= depth) { + break; + } + if (co < next_depth) { + next_depth = co; + } + } + domain_mkxrefs(i, group_last, next_depth); + + i = group_last; + if (i == last) { + break; + } + } + + if (depth == 0) { + return; + } + + i = doms; + do { + if (i != target && i->refdom == NULL) { + i->refdom = target; + i->common_octets = depth; + } + } while (i++ != last); +} + +static size_t domain_compactify(CompactDomain *domains, size_t n) +{ + uint8_t *start = domains->self->labels, *outptr = start; + size_t i; + + for (i = 0; i < n; i++) { + CompactDomain *cd = domains[i].self; + CompactDomain *rd = cd->refdom; + + if (rd != NULL) { + size_t moff = (rd->labels - start) + (rd->len - cd->common_octets); + if (moff < 0x3FFFu) { + cd->len -= cd->common_octets - 2; + cd->labels[cd->len - 1] = moff & 0xFFu; + cd->labels[cd->len - 2] = 0xC0u | (moff >> 8); + } + } + + if (cd->labels != outptr) { + memmove(outptr, cd->labels, cd->len); + cd->labels = outptr; + } + outptr += cd->len; + } + return outptr - start; +} + +int translate_dnssearch(Slirp *s, const char **names) +{ + size_t blocks, bsrc_start, bsrc_end, bdst_start; + size_t i, num_domains, memreq = 0; + uint8_t *result = NULL, *outptr; + CompactDomain *domains = NULL; + + num_domains = g_strv_length((GStrv)(void *)names); + if (num_domains == 0) { + return -2; + } + + domains = g_malloc(num_domains * sizeof(*domains)); + + for (i = 0; i < num_domains; i++) { + size_t nlen = strlen(names[i]); + memreq += nlen + 2; /* 1 zero octet + 1 label length octet */ + domains[i].self = domains + i; + domains[i].len = nlen; + domains[i].common_octets = 0; + domains[i].refdom = NULL; + } + + /* reserve extra 2 header bytes for each 255 bytes of output */ + memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN; + result = g_malloc(memreq * sizeof(*result)); + + outptr = result; + for (i = 0; i < num_domains; i++) { + domains[i].labels = outptr; + domain_mklabels(domains + i, names[i]); + outptr += domains[i].len; + } + + if (outptr == result) { + g_free(domains); + g_free(result); + return -1; + } + + qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord); + domain_fixup_order(domains, num_domains); + + for (i = 1; i < num_domains; i++) { + size_t cl = domain_common_label(domains + i - 1, domains + i); + domains[i - 1].common_octets = cl; + } + + domain_mkxrefs(domains, domains + num_domains - 1, 0); + memreq = domain_compactify(domains, num_domains); + + blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN); + bsrc_end = memreq; + bsrc_start = (blocks - 1) * MAX_OPT_LEN; + bdst_start = bsrc_start + blocks * OPT_HEADER_LEN; + memreq += blocks * OPT_HEADER_LEN; + + while (blocks--) { + size_t len = bsrc_end - bsrc_start; + memmove(result + bdst_start, result + bsrc_start, len); + result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH; + result[bdst_start - 1] = len; + bsrc_end = bsrc_start; + bsrc_start -= MAX_OPT_LEN; + bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN; + } + + g_free(domains); + s->vdnssearch = result; + s->vdnssearch_len = memreq; + return 0; +} diff --git a/src/network/slirp/icmp_var.h b/src/network/slirp/icmp_var.h deleted file mode 100644 index 9af222fb7..000000000 --- a/src/network/slirp/icmp_var.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 - * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp - */ - -#ifndef _NETINET_ICMP_VAR_H_ -#define _NETINET_ICMP_VAR_H_ - -/* - * Variables related to this implementation - * of the internet control message protocol. - */ -struct icmpstat { -/* statistics related to input messages processed */ - u_long icps_received; /* #ICMP packets received */ - u_long icps_tooshort; /* packet < ICMP_MINLEN */ - u_long icps_checksum; /* bad checksum */ - u_long icps_notsupp; /* #ICMP packets not supported */ - u_long icps_badtype; /* #with bad type feild */ - u_long icps_reflect; /* number of responses */ -}; - -/* - * Names for ICMP sysctl objects - */ -#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ -#define ICMPCTL_STATS 2 /* statistics (read-only) */ -#define ICMPCTL_MAXID 3 - -#define ICMPCTL_NAMES { \ - { 0, 0 }, \ - { "maskrepl", CTLTYPE_INT }, \ - { "stats", CTLTYPE_STRUCT }, \ -} - -extern struct icmpstat icmpstat; - -#endif diff --git a/src/network/slirp/if.c b/src/network/slirp/if.c index 24f1b9947..23190b559 100644 --- a/src/network/slirp/if.c +++ b/src/network/slirp/if.c @@ -1,322 +1,213 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ #include "slirp.h" -int if_mtu, if_mru; -int if_comp; -int if_maxlinkhdr; -int if_queued = 0; /* Number of packets queued so far */ -int if_thresh = 10; /* Number of packets queued before we start sending - * (to prevent allocing too many SLIRPmbufs) */ - -struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ -struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ -struct SLIRPmbuf *next_m; /* Pointer to next SLIRPmbuf to output */ - -#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) - -void -ifs_insque(ifm, ifmhead) - struct SLIRPmbuf *ifm, *ifmhead; +static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead) { - ifm->ifs_next = ifmhead->ifs_next; - ifmhead->ifs_next = ifm; - ifm->ifs_prev = ifmhead; - ifm->ifs_next->ifs_prev = ifm; + ifm->ifs_next = ifmhead->ifs_next; + ifmhead->ifs_next = ifm; + ifm->ifs_prev = ifmhead; + ifm->ifs_next->ifs_prev = ifm; } -void -ifs_remque(ifm) - struct SLIRPmbuf *ifm; +static void ifs_remque(struct mbuf *ifm) { - ifm->ifs_prev->ifs_next = ifm->ifs_next; - ifm->ifs_next->ifs_prev = ifm->ifs_prev; + ifm->ifs_prev->ifs_next = ifm->ifs_next; + ifm->ifs_next->ifs_prev = ifm->ifs_prev; } -void -if_init() +void if_init(Slirp *slirp) { -#if 0 - /* - * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, - * and 8 bytes for PPP, but need to have it on an 8byte boundary - */ -#ifdef USE_PPP - if_maxlinkhdr = 48; -#else - if_maxlinkhdr = 40; -#endif -#else - /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ - if_maxlinkhdr = 2 + 14 + 40; -#endif - if_mtu = 1500; - if_mru = 1500; - if_comp = IF_AUTOCOMP; - if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; - if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; - // sl_compress_init(&comp_s); - next_m = &if_batchq; + slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq; + slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq; } -#if 0 -/* - * This shouldn't be needed since the modem is blocking and - * we don't expect any signals, but what the hell.. - */ -inline int -writen(fd, bptr, n) - int fd; - char *bptr; - int n; -{ - int ret; - int total; - - /* This should succeed most of the time */ - ret = send(fd, bptr, n,0); - if (ret == n || ret <= 0) - return ret; - - /* Didn't write everything, go into the loop */ - total = ret; - while (n > total) { - ret = send(fd, bptr+total, n-total,0); - if (ret <= 0) - return ret; - total += ret; - } - return total; -} - -/* - * if_input - read() the tty, do "top level" processing (ie: check for any escapes), - * and pass onto (*ttyp->if_input) - * - * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. - */ -#define INBUFF_SIZE 2048 /* XXX */ -void -if_input(ttyp) - struct ttys *ttyp; -{ - u_char if_inbuff[INBUFF_SIZE]; - int if_n; - - DEBUG_CALL("if_input"); - DEBUG_ARG("ttyp = %lx", (long)ttyp); - - if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); - - DEBUG_MISC((dfd, " read %d bytes\n", if_n)); - - if (if_n <= 0) { - if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { - if (ttyp->up) - link_up--; - tty_detached(ttyp, 0); - } - return; - } - if (if_n == 1) { - if (*if_inbuff == '0') { - ttyp->ones = 0; - if (++ttyp->zeros >= 5) - slirp_exit(0); - return; - } - if (*if_inbuff == '1') { - ttyp->zeros = 0; - if (++ttyp->ones >= 5) - tty_detached(ttyp, 0); - return; - } - } - ttyp->ones = ttyp->zeros = 0; - - (*ttyp->if_input)(ttyp, if_inbuff, if_n); -} -#endif - /* * if_output: Queue packet into an output queue. - * There are 2 output queue's, if_fastq and if_batchq. + * There are 2 output queue's, if_fastq and if_batchq. * Each output queue is a doubly linked list of double linked lists - * of SLIRPmbufs, each list belonging to one "session" (socket). This + * of mbufs, each list belonging to one "session" (socket). This * way, we can output packets fairly by sending one packet from each * session, instead of all the packets from one session, then all packets - * from the next session, etc. Packets on the if_fastq get absolute + * from the next session, etc. Packets on the if_fastq get absolute * priority, but if one session hogs the link, it gets "downgraded" * to the batchq until it runs out of packets, then it'll return * to the fastq (eg. if the user does an ls -alR in a telnet session, * it'll temporarily get downgraded to the batchq) */ -void -if_output(so, ifm) - struct SLIRPsocket *so; - struct SLIRPmbuf *ifm; +void if_output(struct socket *so, struct mbuf *ifm) { - struct SLIRPmbuf *ifq; - int on_fastq = 1; - - DEBUG_CALL("if_output"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("ifm = %lx", (long)ifm); - - /* - * First remove the SLIRPmbuf from m_usedlist, - * since we're gonna use m_next and m_prev ourselves - * XXX Shouldn't need this, gotta change dtom() etc. - */ - if (ifm->m_flags & M_USEDLIST) { - remque(ifm); - ifm->m_flags &= ~M_USEDLIST; - } - - /* - * See if there's already a batchq list for this session. - * This can include an interactive session, which should go on fastq, - * but gets too greedy... hence it'll be downgraded from fastq to batchq. - * We mustn't put this packet back on the fastq (or we'll send it out of order) - * XXX add cache here? - */ - for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { - if (so == ifq->ifq_so) { - /* A match! */ - ifm->ifq_so = so; - ifs_insque(ifm, ifq->ifs_prev); - goto diddit; - } - } - - /* No match, check which queue to put it on */ - if (so && (so->so_iptos & IPTOS_LOWDELAY)) { - ifq = if_fastq.ifq_prev; - on_fastq = 1; - /* - * Check if this packet is a part of the last - * packet's session - */ - if (ifq->ifq_so == so) { - ifm->ifq_so = so; - ifs_insque(ifm, ifq->ifs_prev); - goto diddit; - } - } else - ifq = if_batchq.ifq_prev; - - /* Create a new doubly linked list for this session */ - ifm->ifq_so = so; - ifs_init(ifm); - insque(ifm, ifq); - -diddit: - ++if_queued; - - if (so) { - /* Update *_queued */ - so->so_queued++; - so->so_nqueued++; - /* - * Check if the interactive session should be downgraded to - * the batchq. A session is downgraded if it has queued 6 - * packets without pausing, and at least 3 of those packets - * have been sent over the link - * (XXX These are arbitrary numbers, probably not optimal..) - */ - if (on_fastq && ((so->so_nqueued >= 6) && - (so->so_nqueued - so->so_queued) >= 3)) { - - /* Remove from current queue... */ - remque(ifm->ifs_next); - - /* ...And insert in the new. That'll teach ya! */ - insque(ifm->ifs_next, &if_batchq); - } - } + Slirp *slirp = ifm->slirp; + struct mbuf *ifq; + int on_fastq = 1; -#ifndef FULL_BOLT - /* - * This prevents us from malloc()ing too many SLIRPmbufs - */ - if (link_up) { - /* if_start will check towrite */ - if_start(); - } -#endif + DEBUG_CALL("if_output"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("ifm = %p", ifm); + + /* + * First remove the mbuf from m_usedlist, + * since we're gonna use m_next and m_prev ourselves + * XXX Shouldn't need this, gotta change dtom() etc. + */ + if (ifm->m_flags & M_USEDLIST) { + remque(ifm); + ifm->m_flags &= ~M_USEDLIST; + } + + /* + * See if there's already a batchq list for this session. + * This can include an interactive session, which should go on fastq, + * but gets too greedy... hence it'll be downgraded from fastq to batchq. + * We mustn't put this packet back on the fastq (or we'll send it out of + * order) + * XXX add cache here? + */ + if (so) { + for (ifq = (struct mbuf *)slirp->if_batchq.qh_rlink; + (struct quehead *)ifq != &slirp->if_batchq; ifq = ifq->ifq_prev) { + if (so == ifq->ifq_so) { + /* A match! */ + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } + } + + /* No match, check which queue to put it on */ + if (so && (so->so_iptos & IPTOS_LOWDELAY)) { + ifq = (struct mbuf *)slirp->if_fastq.qh_rlink; + on_fastq = 1; + /* + * Check if this packet is a part of the last + * packet's session + */ + if (ifq->ifq_so == so) { + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } else { + ifq = (struct mbuf *)slirp->if_batchq.qh_rlink; + } + + /* Create a new doubly linked list for this session */ + ifm->ifq_so = so; + ifs_init(ifm); + insque(ifm, ifq); + +diddit: + if (so) { + /* Update *_queued */ + so->so_queued++; + so->so_nqueued++; + /* + * Check if the interactive session should be downgraded to + * the batchq. A session is downgraded if it has queued 6 + * packets without pausing, and at least 3 of those packets + * have been sent over the link + * (XXX These are arbitrary numbers, probably not optimal..) + */ + if (on_fastq && + ((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) { + /* Remove from current queue... */ + remque(ifm->ifs_next); + + /* ...And insert in the new. That'll teach ya! */ + insque(ifm->ifs_next, &slirp->if_batchq); + } + } + + /* + * This prevents us from malloc()ing too many mbufs + */ + if_start(ifm->slirp); } /* - * Send a packet - * We choose a packet based on it's position in the output queues; + * Send one packet from each session. * If there are packets on the fastq, they are sent FIFO, before - * everything else. Otherwise we choose the first packet from the - * batchq and send it. the next packet chosen will be from the session - * after this one, then the session after that one, and so on.. So, - * for example, if there are 3 ftp session's fighting for bandwidth, + * everything else. Then we choose the first packet from each + * batchq session (socket) and send it. + * For example, if there are 3 ftp sessions fighting for bandwidth, * one packet will be sent from the first session, then one packet - * from the second session, then one packet from the third, then back - * to the first, etc. etc. + * from the second session, then one packet from the third. */ -void -if_start(void) +void if_start(Slirp *slirp) { - struct SLIRPmbuf *ifm, *ifqt; - - DEBUG_CALL("if_start"); - - if (if_queued == 0) - return; /* Nothing to do */ - - again: - /* check if we can really output */ - if (!slirp_can_output()) - return; + uint64_t now = slirp->cb->clock_get_ns(slirp->opaque); + bool from_batchq = false; + struct mbuf *ifm, *ifm_next, *ifqt; - /* - * See which queue to get next packet from - * If there's something in the fastq, select it immediately - */ - if (if_fastq.ifq_next != &if_fastq) { - ifm = if_fastq.ifq_next; - } else { - /* Nothing on fastq, see if next_m is valid */ - if (next_m != &if_batchq) - ifm = next_m; - else - ifm = if_batchq.ifq_next; - - /* Set which packet to send on next iteration */ - next_m = ifm->ifq_next; - } - /* Remove it from the queue */ - ifqt = ifm->ifq_prev; - remque(ifm); - --if_queued; - - /* If there are more packets for this session, re-queue them */ - if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { - insque(ifm->ifs_next, ifqt); - ifs_remque(ifm); - } - - /* Update so_queued */ - if (ifm->ifq_so) { - if (--ifm->ifq_so->so_queued == 0) - /* If there's no more queued, reset nqueued */ - ifm->ifq_so->so_nqueued = 0; - } - - /* Encapsulate the packet for sending */ - if_encap((uint8_t*)ifm->m_data, ifm->m_len); + DEBUG_CALL("if_start"); - m_free(ifm); + if (slirp->if_start_busy) { + return; + } + slirp->if_start_busy = true; - if (if_queued) - goto again; + struct mbuf *batch_head = NULL; + if (slirp->if_batchq.qh_link != &slirp->if_batchq) { + batch_head = (struct mbuf *)slirp->if_batchq.qh_link; + } + + if (slirp->if_fastq.qh_link != &slirp->if_fastq) { + ifm_next = (struct mbuf *)slirp->if_fastq.qh_link; + } else if (batch_head) { + /* Nothing on fastq, pick up from batchq */ + ifm_next = batch_head; + from_batchq = true; + } else { + ifm_next = NULL; + } + + while (ifm_next) { + ifm = ifm_next; + + ifm_next = ifm->ifq_next; + if ((struct quehead *)ifm_next == &slirp->if_fastq) { + /* No more packets in fastq, switch to batchq */ + ifm_next = batch_head; + from_batchq = true; + } + if ((struct quehead *)ifm_next == &slirp->if_batchq) { + /* end of batchq */ + ifm_next = NULL; + } + + /* Try to send packet unless it already expired */ + if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) { + /* Packet is delayed due to pending ARP or NDP resolution */ + continue; + } + + /* Remove it from the queue */ + ifqt = ifm->ifq_prev; + remque(ifm); + + /* If there are more packets for this session, re-queue them */ + if (ifm->ifs_next != ifm) { + struct mbuf *next = ifm->ifs_next; + + insque(next, ifqt); + ifs_remque(ifm); + if (!from_batchq) { + ifm_next = next; + } + } + + /* Update so_queued */ + if (ifm->ifq_so && --ifm->ifq_so->so_queued == 0) { + /* If there's no more queued, reset nqueued */ + ifm->ifq_so->so_nqueued = 0; + } + + m_free(ifm); + } + + slirp->if_start_busy = false; } diff --git a/src/network/slirp/if.h b/src/network/slirp/if.h index 85a5a96d2..7cf9d2750 100644 --- a/src/network/slirp/if.h +++ b/src/network/slirp/if.h @@ -1,50 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#ifndef _IF_H_ -#define _IF_H_ +#ifndef IF_H +#define IF_H -#define IF_COMPRESS 0x01 /* We want compression */ -#define IF_NOCOMPRESS 0x02 /* Do not do compression */ -#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ -#define IF_NOCIDCOMP 0x08 /* CID compression */ +#define IF_COMPRESS 0x01 /* We want compression */ +#define IF_NOCOMPRESS 0x02 /* Do not do compression */ +#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ +#define IF_NOCIDCOMP 0x08 /* CID compression */ -/* Needed for FreeBSD */ -#undef if_mtu -extern int if_mtu; -extern int if_mru; /* MTU and MRU */ -extern int if_comp; /* Flags for compression */ -extern int if_maxlinkhdr; -extern int if_queued; /* Number of packets queued so far */ -extern int if_thresh; /* Number of packets queued before we start sending - * (to prevent allocing too many SLIRPmbufs) */ +#define IF_MTU_DEFAULT 1500 +#define IF_MTU_MIN 68 +#define IF_MTU_MAX 65521 +#define IF_MRU_DEFAULT 1500 +#define IF_MRU_MIN 68 +#define IF_MRU_MAX 65521 +#define IF_COMP IF_AUTOCOMP /* Flags for compression */ -extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ -extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ -extern struct SLIRPmbuf *next_m; - -#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) - -/* Interface statistics */ -struct slirp_ifstats { - u_int out_pkts; /* Output packets */ - u_int out_bytes; /* Output bytes */ - u_int out_errpkts; /* Output Error Packets */ - u_int out_errbytes; /* Output Error Bytes */ - u_int in_pkts; /* Input packets */ - u_int in_bytes; /* Input bytes */ - u_int in_errpkts; /* Input Error Packets */ - u_int in_errbytes; /* Input Error Bytes */ - - u_int bytes_saved; /* Number of bytes that compression "saved" */ - /* ie: number of bytes that didn't need to be sent over the link - * because of compression */ - - u_int in_mbad; /* Bad incoming packets */ -}; +/* 2 for alignment, 14 for ethernet */ +#define IF_MAXLINKHDR (2 + ETH_HLEN) #endif diff --git a/src/network/slirp/ip.h b/src/network/slirp/ip.h index f21178360..fba3defa1 100644 --- a/src/network/slirp/ip.h +++ b/src/network/slirp/ip.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -30,223 +31,200 @@ * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp */ -#ifndef _IP_H_ -#define _IP_H_ +#ifndef IP_H +#define IP_H -#ifdef WORDS_BIGENDIAN -# ifndef NTOHL -# define NTOHL(d) -# endif -# ifndef NTOHS -# define NTOHS(d) -# endif -# ifndef HTONL -# define HTONL(d) -# endif -# ifndef HTONS -# define HTONS(d) -# endif +#include + +#if G_BYTE_ORDER == G_BIG_ENDIAN +#undef NTOHL +#undef NTOHS +#undef HTONL +#undef HTONS +#define NTOHL(d) +#define NTOHS(d) +#define HTONL(d) +#define HTONS(d) #else -# ifndef NTOHL -# define NTOHL(d) ((d) = ntohl((d))) -# endif -# ifndef NTOHS -# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) -# endif -# ifndef HTONL -# define HTONL(d) ((d) = htonl((d))) -# endif -# ifndef HTONS -# define HTONS(d) ((d) = htons((u_int16_t)(d))) -# endif +#ifndef NTOHL +#define NTOHL(d) ((d) = ntohl((d))) +#endif +#ifndef NTOHS +#define NTOHS(d) ((d) = ntohs((uint16_t)(d))) +#endif +#ifndef HTONL +#define HTONL(d) ((d) = htonl((d))) +#endif +#ifndef HTONS +#define HTONS(d) ((d) = htons((uint16_t)(d))) +#endif #endif -typedef u_int32_t n_long; /* long as received from the net */ +typedef uint32_t n_long; /* long as received from the net */ /* * Definitions for internet protocol version 4. * Per RFC 791, September 1981. */ -#define IPVERSION 4 - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif +#define IPVERSION 4 /* * Structure of an internet header, naked of options. */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) #endif - struct ip { -#ifdef WORDS_BIGENDIAN - u_char ip_v:4, /* version */ - ip_hl:4; /* header length */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint8_t ip_v : 4, /* version */ + ip_hl : 4; /* header length */ #else - u_char ip_hl:4, /* header length */ - ip_v:4; /* version */ + uint8_t ip_hl : 4, /* header length */ + ip_v : 4; /* version */ #endif - u_int8_t ip_tos; /* type of service */ - u_int16_t ip_len; /* total length */ - u_int16_t ip_id; /* identification */ - u_int16_t ip_off; /* fragment offset field */ -#define IP_DF 0x4000 /* don't fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - u_int8_t ip_ttl; /* time to live */ - u_int8_t ip_p; /* protocol */ - u_int16_t ip_sum; /* checksum */ - struct in_addr ip_src,ip_dst; /* source and dest address */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) //WAS 0 + uint8_t ip_tos; /* type of service */ + uint16_t ip_len; /* total length */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + struct in_addr ip_src, ip_dst; /* source and dest address */ +} SLIRP_PACKED; +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(pop) #endif -#define IP_MAXPACKET 65535 /* maximum packet size */ +#define IP_MAXPACKET 65535 /* maximum packet size */ /* * Definitions for IP type of service (ip_tos) */ -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 /* * Definitions for options. */ -#define IPOPT_COPIED(o) ((o)&0x80) -#define IPOPT_CLASS(o) ((o)&0x60) -#define IPOPT_NUMBER(o) ((o)&0x1f) +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) -#define IPOPT_CONTROL 0x00 -#define IPOPT_RESERVED1 0x20 -#define IPOPT_DEBMEAS 0x40 -#define IPOPT_RESERVED2 0x60 +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 -#define IPOPT_EOL 0 /* end of option list */ -#define IPOPT_NOP 1 /* no operation */ +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ -#define IPOPT_RR 7 /* record packet route */ -#define IPOPT_TS 68 /* timestamp */ -#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ -#define IPOPT_LSRR 131 /* loose source route */ -#define IPOPT_SATID 136 /* satnet id */ -#define IPOPT_SSRR 137 /* strict source route */ +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ /* * Offsets to fields in options other than EOL and NOP. */ -#define IPOPT_OPTVAL 0 /* option ID */ -#define IPOPT_OLEN 1 /* option length */ -#define IPOPT_OFFSET 2 /* offset within option */ -#define IPOPT_MINOFF 4 /* min value of above */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ /* * Time stamp option structure. */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) #endif - -struct ip_timestamp { - u_int8_t ipt_code; /* IPOPT_TS */ - u_int8_t ipt_len; /* size of structure (variable) */ - u_int8_t ipt_ptr; /* index of current entry */ -#ifdef WORDS_BIGENDIAN - u_char ipt_oflw:4, /* overflow counter */ - ipt_flg:4; /* flags, see below */ +struct ip_timestamp { + uint8_t ipt_code; /* IPOPT_TS */ + uint8_t ipt_len; /* size of structure (variable) */ + uint8_t ipt_ptr; /* index of current entry */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint8_t ipt_oflw : 4, /* overflow counter */ + ipt_flg : 4; /* flags, see below */ #else - u_char ipt_flg:4, /* flags, see below */ - ipt_oflw:4; /* overflow counter */ + uint8_t ipt_flg : 4, /* flags, see below */ + ipt_oflw : 4; /* overflow counter */ #endif - union ipt_timestamp { - n_long ipt_time[1]; - struct ipt_ta { - struct in_addr ipt_addr; - n_long ipt_time; - } ipt_ta[1]; - } ipt_timestamp; -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +} SLIRP_PACKED; +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(pop) #endif /* flag bits for ipt_flg */ -#define IPOPT_TS_TSONLY 0 /* timestamps only */ -#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define IPOPT_TS_PRESPEC 3 /* specified modules only */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ /* bits for security (not byte swapped) */ -#define IPOPT_SECUR_UNCLASS 0x0000 -#define IPOPT_SECUR_CONFID 0xf135 -#define IPOPT_SECUR_EFTO 0x789a -#define IPOPT_SECUR_MMMM 0xbc4d -#define IPOPT_SECUR_RESTR 0xaf13 -#define IPOPT_SECUR_SECRET 0xd788 -#define IPOPT_SECUR_TOPSECRET 0x6bc5 +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 /* * Internet implementation parameters. */ -#define MAXTTL 255 /* maximum time to live (seconds) */ -#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ -#define IPFRAGTTL 60 /* time to live for frags, slowhz */ -#define IPTTLDEC 1 /* subtracted when forwarding */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ -#define IP_MSS 576 /* default maximum segment size */ +#define IP_MSS 576 /* default maximum segment size */ -#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ -#include -#else -#if SIZEOF_CHAR_P == 4 -typedef SLIRPcaddr_t caddr32_t; -#else -typedef u_int32_t caddr32_t; +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) #endif -#endif - -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t ipqp_32; -typedef uintptr_t ipasfragp_32; +#if GLIB_SIZEOF_VOID_P == 4 +struct mbuf_ptr { + struct mbuf *mptr; + uint32_t dummy; +} SLIRP_PACKED; #else -#if SIZEOF_CHAR_P == 4 -typedef struct ipq *ipqp_32; -typedef struct ipasfrag *ipasfragp_32; -#else -typedef caddr32_t ipqp_32; -typedef caddr32_t ipasfragp_32; +struct mbuf_ptr { + struct mbuf *mptr; +} SLIRP_PACKED; #endif +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(pop) #endif +struct qlink { + void *next, *prev; +}; /* * Overlay for ip header used by other protocols (tcp, udp). */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) #endif - struct ipovly { -#if defined(__amd64__) || defined(__aarch64__) - uintptr_t ih_next, ih_prev; /* for protocol sequence q's */ -#else - caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ -#endif - u_int8_t ih_x1; /* (unused) */ - u_int8_t ih_pr; /* protocol */ - u_int16_t ih_len; /* protocol length */ - struct in_addr ih_src; /* source internet address */ - struct in_addr ih_dst; /* destination internet address */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif - -#if defined(_MSC_VER) + struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ + uint8_t ih_x1; /* (unused) */ + uint8_t ih_pr; /* protocol */ + uint16_t ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +} SLIRP_PACKED; +#if defined(_MSC_VER) && !defined (__clang__) #pragma pack(pop) #endif @@ -258,105 +236,31 @@ struct ipovly { * size 28 bytes */ struct ipq { -#if defined(__amd64__) || defined(__aarch64__) - uintptr_t next,prev; /* to other reass headers */ -#else - ipqp_32 next,prev; /* to other reass headers */ -#endif - u_int8_t ipq_ttl; /* time for reass q to live */ - u_int8_t ipq_p; /* protocol of this fragment */ - u_int16_t ipq_id; /* sequence id for reassembly */ - ipasfragp_32 ipq_next,ipq_prev; - /* to ip headers of fragments */ - struct in_addr ipq_src,ipq_dst; + struct qlink frag_link; /* to ip headers of fragments */ + struct qlink ip_link; /* to other reass headers */ + uint8_t ipq_ttl; /* time for reass q to live */ + uint8_t ipq_p; /* protocol of this fragment */ + uint16_t ipq_id; /* sequence id for reassembly */ + struct in_addr ipq_src, ipq_dst; }; /* * Ip header, when holding a fragment. * - * Note: ipf_next must be at same offset as ipq_next above + * Note: ipf_link must be at same offset as frag_link above */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - -struct ipasfrag { -#ifdef WORDS_BIGENDIAN - u_char ip_v:4, - ip_hl:4; -#else - u_char ip_hl:4, - ip_v:4; -#endif - /* BUG : u_int changed to u_int8_t. - * sizeof(u_int)==4 on linux 2.0 - */ - u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit - * to avoid destroying tos (PPPDTRuu); - * copied from (ip_off&IP_MF) */ - u_int16_t ip_len; - u_int16_t ip_id; - u_int16_t ip_off; - u_int8_t ip_ttl; - u_int8_t ip_p; - u_int16_t ip_sum; - ipasfragp_32 ipf_next; /* next fragment */ - ipasfragp_32 ipf_prev; /* previous fragment */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) //WAS 0 -#endif - -/* - * Structure stored in mbuf in inpcb.ip_options - * and passed to ip_output when ip options are in use. - * The actual length of the options (including ipopt_dst) - * is in m_len. - */ -#define MAX_IPOPTLEN 40 - -struct ipoption { - struct in_addr ipopt_dst; /* first-hop dst if source routed */ - int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ +struct ipasfrag { + struct qlink ipf_link; + struct ip ipf_ip; }; -/* - * Structure attached to inpcb.ip_moptions and - * passed to ip_output when IP multicast options are in use. - */ +G_STATIC_ASSERT(offsetof(struct ipq, frag_link) == + offsetof(struct ipasfrag, ipf_link)); -struct ipstat { - u_long ips_total; /* total packets received */ - u_long ips_badsum; /* checksum bad */ - u_long ips_tooshort; /* packet too short */ - u_long ips_toosmall; /* not enough data */ - u_long ips_badhlen; /* ip header length < data size */ - u_long ips_badlen; /* ip length < ip header length */ - u_long ips_fragments; /* fragments received */ - u_long ips_fragdropped; /* frags dropped (dups, out of space) */ - u_long ips_fragtimeout; /* fragments timed out */ - u_long ips_forward; /* packets forwarded */ - u_long ips_cantforward; /* packets rcvd for unreachable dest */ - u_long ips_redirectsent; /* packets forwarded on same net */ - u_long ips_noproto; /* unknown or unsupported protocol */ - u_long ips_delivered; /* datagrams delivered to upper level*/ - u_long ips_localout; /* total ip packets generated here */ - u_long ips_odropped; /* lost packets due to nobufs, etc. */ - u_long ips_reassembled; /* total packets reassembled ok */ - u_long ips_fragmented; /* datagrams successfully fragmented */ - u_long ips_ofragments; /* output fragments created */ - u_long ips_cantfrag; /* don't fragment flag was set, etc. */ - u_long ips_badoptions; /* error in option processing */ - u_long ips_noroute; /* packets discarded due to no route */ - u_long ips_badvers; /* ip version != 4 */ - u_long ips_rawout; /* total raw ip packets generated */ - u_long ips_unaligned; /* times the ip packet was not aligned */ -}; - -extern struct ipstat ipstat; -extern struct ipq ipq; /* ip reass. queue */ -extern u_int16_t ip_id; /* ip packet ctr, for ids */ -extern int ip_defttl; /* default IP ttl */ +#define ipf_off ipf_ip.ip_off +#define ipf_tos ipf_ip.ip_tos +#define ipf_len ipf_ip.ip_len +#define ipf_next ipf_link.next +#define ipf_prev ipf_link.prev #endif diff --git a/src/network/slirp/ip6.h b/src/network/slirp/ip6.h new file mode 100644 index 000000000..7210964d4 --- /dev/null +++ b/src/network/slirp/ip6.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. + */ + +#ifndef SLIRP_IP6_H +#define SLIRP_IP6_H + +#include +#include + +#define ALLNODES_MULTICAST \ + { \ + .s6_addr = { \ + 0xff, \ + 0x02, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x01 \ + } \ + } + +#define SOLICITED_NODE_PREFIX \ + { \ + .s6_addr = { \ + 0xff, \ + 0x02, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x01, \ + 0xff, \ + 0x00, \ + 0x00, \ + 0x00 \ + } \ + } + +#define LINKLOCAL_ADDR \ + { \ + .s6_addr = { \ + 0xfe, \ + 0x80, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x02 \ + } \ + } + +#define ZERO_ADDR \ + { \ + .s6_addr = { \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00, \ + 0x00 \ + } \ + } + +static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b) +{ + return memcmp(a, b, sizeof(*a)) == 0; +} + +static inline bool in6_equal_net(const struct in6_addr *a, + const struct in6_addr *b, int prefix_len) +{ + if (memcmp(a, b, prefix_len / 8) != 0) { + return 0; + } + + if (prefix_len % 8 == 0) { + return 1; + } + + return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)) == + b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)); +} + +static inline bool in6_equal_mach(const struct in6_addr *a, + const struct in6_addr *b, int prefix_len) +{ + if (memcmp(&(a->s6_addr[DIV_ROUND_UP(prefix_len, 8)]), + &(b->s6_addr[DIV_ROUND_UP(prefix_len, 8)]), + 16 - DIV_ROUND_UP(prefix_len, 8)) != 0) { + return 0; + } + + if (prefix_len % 8 == 0) { + return 1; + } + + return (a->s6_addr[prefix_len / 8] & + ((1U << (8 - (prefix_len % 8))) - 1)) == + (b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1)); +} + + +#define in6_equal_router(a) \ + ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \ + in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len)) || \ + (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \ + in6_equal_mach(a, &slirp->vhost_addr6, 64))) + +#define in6_equal_dns(a) \ + ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \ + in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len)) || \ + (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64) && \ + in6_equal_mach(a, &slirp->vnameserver_addr6, 64))) + +#define in6_equal_host(a) (in6_equal_router(a) || in6_equal_dns(a)) + +#define in6_solicitednode_multicast(a) \ + (in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104)) + +#define in6_zero(a) (in6_equal(a, &(struct in6_addr)ZERO_ADDR)) + +/* Compute emulated host MAC address from its ipv6 address */ +static inline void in6_compute_ethaddr(struct in6_addr ip, + uint8_t eth[ETH_ALEN]) +{ + eth[0] = 0x52; + eth[1] = 0x56; + memcpy(ð[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2); +} + +/* + * Definitions for internet protocol version 6. + * Per RFC 2460, December 1998. + */ +#define IP6VERSION 6 +#define IP6_HOP_LIMIT 255 + +/* + * Structure of an internet header, naked of options. + */ +struct ip6 { +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint32_t ip_v : 4, /* version */ + ip_tc_hi : 4, /* traffic class */ + ip_tc_lo : 4, ip_fl_hi : 4, /* flow label */ + ip_fl_lo : 16; +#else + uint32_t ip_tc_hi : 4, ip_v : 4, ip_fl_hi : 4, ip_tc_lo : 4, ip_fl_lo : 16; +#endif + uint16_t ip_pl; /* payload length */ + uint8_t ip_nh; /* next header */ + uint8_t ip_hl; /* hop limit */ + struct in6_addr ip_src, ip_dst; /* source and dest address */ +}; + +/* + * IPv6 pseudo-header used by upper-layer protocols + */ +struct ip6_pseudohdr { + struct in6_addr ih_src; /* source internet address */ + struct in6_addr ih_dst; /* destination internet address */ + uint32_t ih_pl; /* upper-layer packet length */ + uint16_t ih_zero_hi; /* zero */ + uint8_t ih_zero_lo; /* zero */ + uint8_t ih_nh; /* next header */ +}; + +/* + * We don't want to mark these ip6 structs as packed as they are naturally + * correctly aligned; instead assert that there is no stray padding. + * If we marked the struct as packed then we would be unable to take + * the address of any of the fields in it. + */ +G_STATIC_ASSERT(sizeof(struct ip6) == 40); +G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40); + +#endif diff --git a/src/network/slirp/ip6_icmp.c b/src/network/slirp/ip6_icmp.c new file mode 100644 index 000000000..d9c872bc9 --- /dev/null +++ b/src/network/slirp/ip6_icmp.c @@ -0,0 +1,433 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. + */ + +#include "slirp.h" +#include "ip6_icmp.h" + +#define NDP_Interval \ + g_rand_int_range(slirp->grand, NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval) + +static void ra_timer_handler(void *opaque) +{ + Slirp *slirp = opaque; + + slirp->cb->timer_mod(slirp->ra_timer, + slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + + NDP_Interval, + slirp->opaque); + ndp_send_ra(slirp); +} + +void icmp6_init(Slirp *slirp) +{ + if (!slirp->in6_enabled) { + return; + } + + slirp->ra_timer = + slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque); + slirp->cb->timer_mod(slirp->ra_timer, + slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + + NDP_Interval, + slirp->opaque); +} + +void icmp6_cleanup(Slirp *slirp) +{ + if (!slirp->in6_enabled) { + return; + } + + slirp->cb->timer_free(slirp->ra_timer, slirp->opaque); +} + +static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip, + struct icmp6 *icmp) +{ + struct mbuf *t = m_get(slirp); + t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl); + memcpy(t->m_data, m->m_data, t->m_len); + + /* IPv6 Packet */ + struct ip6 *rip = mtod(t, struct ip6 *); + rip->ip_dst = ip->ip_src; + rip->ip_src = ip->ip_dst; + + /* ICMPv6 packet */ + t->m_data += sizeof(struct ip6); + struct icmp6 *ricmp = mtod(t, struct icmp6 *); + ricmp->icmp6_type = ICMP6_ECHO_REPLY; + ricmp->icmp6_cksum = 0; + + /* Checksum */ + t->m_data -= sizeof(struct ip6); + ricmp->icmp6_cksum = ip6_cksum(t); + + ip6_output(NULL, t, 0); +} + +void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code) +{ + Slirp *slirp = m->slirp; + struct mbuf *t; + struct ip6 *ip = mtod(m, struct ip6 *); + char addrstr[INET6_ADDRSTRLEN]; + + DEBUG_CALL("icmp6_send_error"); + DEBUG_ARG("type = %d, code = %d", type, code); + + if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || in6_zero(&ip->ip_src)) { + /* TODO icmp error? */ + return; + } + + t = m_get(slirp); + + /* IPv6 packet */ + struct ip6 *rip = mtod(t, struct ip6 *); + rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR; + rip->ip_dst = ip->ip_src; + inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN); + DEBUG_ARG("target = %s", addrstr); + + rip->ip_nh = IPPROTO_ICMPV6; + const int error_data_len = MIN( + m->m_len, slirp->if_mtu - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN)); + rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len); + t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl); + + /* ICMPv6 packet */ + t->m_data += sizeof(struct ip6); + struct icmp6 *ricmp = mtod(t, struct icmp6 *); + ricmp->icmp6_type = type; + ricmp->icmp6_code = code; + ricmp->icmp6_cksum = 0; + + switch (type) { + case ICMP6_UNREACH: + case ICMP6_TIMXCEED: + ricmp->icmp6_err.unused = 0; + break; + case ICMP6_TOOBIG: + ricmp->icmp6_err.mtu = htonl(slirp->if_mtu); + break; + case ICMP6_PARAMPROB: + /* TODO: Handle this case */ + break; + default: + g_assert_not_reached(); + } + t->m_data += ICMP6_ERROR_MINLEN; + memcpy(t->m_data, m->m_data, error_data_len); + + /* Checksum */ + t->m_data -= ICMP6_ERROR_MINLEN; + t->m_data -= sizeof(struct ip6); + ricmp->icmp6_cksum = ip6_cksum(t); + + ip6_output(NULL, t, 0); +} + +/* + * Send NDP Router Advertisement + */ +void ndp_send_ra(Slirp *slirp) +{ + DEBUG_CALL("ndp_send_ra"); + + /* Build IPv6 packet */ + struct mbuf *t = m_get(slirp); + struct ip6 *rip = mtod(t, struct ip6 *); + size_t pl_size = 0; + struct in6_addr addr; + uint32_t scope_id; + + rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR; + rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST; + rip->ip_nh = IPPROTO_ICMPV6; + + /* Build ICMPv6 packet */ + t->m_data += sizeof(struct ip6); + struct icmp6 *ricmp = mtod(t, struct icmp6 *); + ricmp->icmp6_type = ICMP6_NDP_RA; + ricmp->icmp6_code = 0; + ricmp->icmp6_cksum = 0; + + /* NDP */ + ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit; + ricmp->icmp6_nra.M = NDP_AdvManagedFlag; + ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag; + ricmp->icmp6_nra.reserved = 0; + ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime); + ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime); + ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime); + t->m_data += ICMP6_NDP_RA_MINLEN; + pl_size += ICMP6_NDP_RA_MINLEN; + + /* Source link-layer address (NDP option) */ + struct ndpopt *opt = mtod(t, struct ndpopt *); + opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE; + opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; + in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer); + t->m_data += NDPOPT_LINKLAYER_LEN; + pl_size += NDPOPT_LINKLAYER_LEN; + + /* Prefix information (NDP option) */ + struct ndpopt *opt2 = mtod(t, struct ndpopt *); + opt2->ndpopt_type = NDPOPT_PREFIX_INFO; + opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8; + opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len; + opt2->ndpopt_prefixinfo.L = 1; + opt2->ndpopt_prefixinfo.A = 1; + opt2->ndpopt_prefixinfo.reserved1 = 0; + opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime); + opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime); + opt2->ndpopt_prefixinfo.reserved2 = 0; + opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6; + t->m_data += NDPOPT_PREFIXINFO_LEN; + pl_size += NDPOPT_PREFIXINFO_LEN; + + /* Prefix information (NDP option) */ + if (get_dns6_addr(&addr, &scope_id) >= 0) { + /* Host system does have an IPv6 DNS server, announce our proxy. */ + struct ndpopt *opt3 = mtod(t, struct ndpopt *); + opt3->ndpopt_type = NDPOPT_RDNSS; + opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8; + opt3->ndpopt_rdnss.reserved = 0; + opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval); + opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6; + t->m_data += NDPOPT_RDNSS_LEN; + pl_size += NDPOPT_RDNSS_LEN; + } + + rip->ip_pl = htons(pl_size); + t->m_data -= sizeof(struct ip6) + pl_size; + t->m_len = sizeof(struct ip6) + pl_size; + + /* ICMPv6 Checksum */ + ricmp->icmp6_cksum = ip6_cksum(t); + + ip6_output(NULL, t, 0); +} + +/* + * Send NDP Neighbor Solitication + */ +void ndp_send_ns(Slirp *slirp, struct in6_addr addr) +{ + char addrstr[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN); + + DEBUG_CALL("ndp_send_ns"); + DEBUG_ARG("target = %s", addrstr); + + /* Build IPv6 packet */ + struct mbuf *t = m_get(slirp); + struct ip6 *rip = mtod(t, struct ip6 *); + rip->ip_src = slirp->vhost_addr6; + rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX; + memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3); + rip->ip_nh = IPPROTO_ICMPV6; + rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN); + t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl); + + /* Build ICMPv6 packet */ + t->m_data += sizeof(struct ip6); + struct icmp6 *ricmp = mtod(t, struct icmp6 *); + ricmp->icmp6_type = ICMP6_NDP_NS; + ricmp->icmp6_code = 0; + ricmp->icmp6_cksum = 0; + + /* NDP */ + ricmp->icmp6_nns.reserved = 0; + ricmp->icmp6_nns.target = addr; + + /* Build NDP option */ + t->m_data += ICMP6_NDP_NS_MINLEN; + struct ndpopt *opt = mtod(t, struct ndpopt *); + opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE; + opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; + in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer); + + /* ICMPv6 Checksum */ + t->m_data -= ICMP6_NDP_NA_MINLEN; + t->m_data -= sizeof(struct ip6); + ricmp->icmp6_cksum = ip6_cksum(t); + + ip6_output(NULL, t, 1); +} + +/* + * Send NDP Neighbor Advertisement + */ +static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp) +{ + /* Build IPv6 packet */ + struct mbuf *t = m_get(slirp); + struct ip6 *rip = mtod(t, struct ip6 *); + rip->ip_src = icmp->icmp6_nns.target; + if (in6_zero(&ip->ip_src)) { + rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST; + } else { + rip->ip_dst = ip->ip_src; + } + rip->ip_nh = IPPROTO_ICMPV6; + rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN + NDPOPT_LINKLAYER_LEN); + t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl); + + /* Build ICMPv6 packet */ + t->m_data += sizeof(struct ip6); + struct icmp6 *ricmp = mtod(t, struct icmp6 *); + ricmp->icmp6_type = ICMP6_NDP_NA; + ricmp->icmp6_code = 0; + ricmp->icmp6_cksum = 0; + + /* NDP */ + ricmp->icmp6_nna.R = NDP_IsRouter; + ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst); + ricmp->icmp6_nna.O = 1; + ricmp->icmp6_nna.reserved_hi = 0; + ricmp->icmp6_nna.reserved_lo = 0; + ricmp->icmp6_nna.target = icmp->icmp6_nns.target; + + /* Build NDP option */ + t->m_data += ICMP6_NDP_NA_MINLEN; + struct ndpopt *opt = mtod(t, struct ndpopt *); + opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET; + opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8; + in6_compute_ethaddr(ricmp->icmp6_nna.target, opt->ndpopt_linklayer); + + /* ICMPv6 Checksum */ + t->m_data -= ICMP6_NDP_NA_MINLEN; + t->m_data -= sizeof(struct ip6); + ricmp->icmp6_cksum = ip6_cksum(t); + + ip6_output(NULL, t, 0); +} + +/* + * Process a NDP message + */ +static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip, + struct icmp6 *icmp) +{ + m->m_len += ETH_HLEN; + m->m_data -= ETH_HLEN; + struct ethhdr *eth = mtod(m, struct ethhdr *); + m->m_len -= ETH_HLEN; + m->m_data += ETH_HLEN; + + switch (icmp->icmp6_type) { + case ICMP6_NDP_RS: + DEBUG_CALL(" type = Router Solicitation"); + if (ip->ip_hl == 255 && icmp->icmp6_code == 0 && + ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) { + /* Gratuitous NDP */ + ndp_table_add(slirp, ip->ip_src, eth->h_source); + + ndp_send_ra(slirp); + } + break; + + case ICMP6_NDP_RA: + DEBUG_CALL(" type = Router Advertisement"); + slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't", + slirp->opaque); + break; + + case ICMP6_NDP_NS: + DEBUG_CALL(" type = Neighbor Solicitation"); + if (ip->ip_hl == 255 && icmp->icmp6_code == 0 && + !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target) && + ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN && + (!in6_zero(&ip->ip_src) || + in6_solicitednode_multicast(&ip->ip_dst))) { + if (in6_equal_host(&icmp->icmp6_nns.target)) { + /* Gratuitous NDP */ + ndp_table_add(slirp, ip->ip_src, eth->h_source); + ndp_send_na(slirp, ip, icmp); + } + } + break; + + case ICMP6_NDP_NA: + DEBUG_CALL(" type = Neighbor Advertisement"); + if (ip->ip_hl == 255 && icmp->icmp6_code == 0 && + ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN && + !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target) && + (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst) || icmp->icmp6_nna.S == 0)) { + ndp_table_add(slirp, ip->ip_src, eth->h_source); + } + break; + + case ICMP6_NDP_REDIRECT: + DEBUG_CALL(" type = Redirect"); + slirp->cb->guest_error( + "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque); + break; + } +} + +/* + * Process a received ICMPv6 message. + */ +void icmp6_input(struct mbuf *m) +{ + struct icmp6 *icmp; + struct ip6 *ip = mtod(m, struct ip6 *); + Slirp *slirp = m->slirp; + int hlen = sizeof(struct ip6); + + DEBUG_CALL("icmp6_input"); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("m_len = %d", m->m_len); + + if (ntohs(ip->ip_pl) < ICMP6_MINLEN) { + goto end; + } + + if (ip6_cksum(m)) { + goto end; + } + + m->m_len -= hlen; + m->m_data += hlen; + icmp = mtod(m, struct icmp6 *); + m->m_len += hlen; + m->m_data -= hlen; + + DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type); + switch (icmp->icmp6_type) { + case ICMP6_ECHO_REQUEST: + if (in6_equal_host(&ip->ip_dst)) { + icmp6_send_echoreply(m, slirp, ip, icmp); + } else { + /* TODO */ + g_critical("external icmpv6 not supported yet"); + } + break; + + case ICMP6_NDP_RS: + case ICMP6_NDP_RA: + case ICMP6_NDP_NS: + case ICMP6_NDP_NA: + case ICMP6_NDP_REDIRECT: + ndp_input(m, slirp, ip, icmp); + break; + + case ICMP6_UNREACH: + case ICMP6_TOOBIG: + case ICMP6_TIMXCEED: + case ICMP6_PARAMPROB: + /* XXX? report error? close socket? */ + default: + break; + } + +end: + m_free(m); +} diff --git a/src/network/slirp/ip6_icmp.h b/src/network/slirp/ip6_icmp.h new file mode 100644 index 000000000..77772a76b --- /dev/null +++ b/src/network/slirp/ip6_icmp.h @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. + */ + +#ifndef SLIRP_IP6_ICMP_H +#define SLIRP_IP6_ICMP_H + +/* + * Interface Control Message Protocol version 6 Definitions. + * Per RFC 4443, March 2006. + * + * Network Discover Protocol Definitions. + * Per RFC 4861, September 2007. + */ + +struct icmp6_echo { /* Echo Messages */ + uint16_t id; + uint16_t seq_num; +}; + +union icmp6_error_body { + uint32_t unused; + uint32_t pointer; + uint32_t mtu; +}; + +/* + * NDP Messages + */ +struct ndp_rs { /* Router Solicitation Message */ + uint32_t reserved; +}; + +struct ndp_ra { /* Router Advertisement Message */ + uint8_t chl; /* Cur Hop Limit */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint8_t M : 1, O : 1, reserved : 6; +#else + uint8_t reserved : 6, O : 1, M : 1; +#endif + uint16_t lifetime; /* Router Lifetime */ + uint32_t reach_time; /* Reachable Time */ + uint32_t retrans_time; /* Retrans Timer */ +}; + +G_STATIC_ASSERT(sizeof(struct ndp_ra) == 12); + +struct ndp_ns { /* Neighbor Solicitation Message */ + uint32_t reserved; + struct in6_addr target; /* Target Address */ +}; + +G_STATIC_ASSERT(sizeof(struct ndp_ns) == 20); + +struct ndp_na { /* Neighbor Advertisement Message */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint32_t R : 1, /* Router Flag */ + S : 1, /* Solicited Flag */ + O : 1, /* Override Flag */ + reserved_hi : 5, reserved_lo : 24; +#else + uint32_t reserved_hi : 5, O : 1, S : 1, R : 1, reserved_lo : 24; +#endif + struct in6_addr target; /* Target Address */ +}; + +G_STATIC_ASSERT(sizeof(struct ndp_na) == 20); + +struct ndp_redirect { + uint32_t reserved; + struct in6_addr target; /* Target Address */ + struct in6_addr dest; /* Destination Address */ +}; + +G_STATIC_ASSERT(sizeof(struct ndp_redirect) == 36); + +/* + * Structure of an icmpv6 header. + */ +struct icmp6 { + uint8_t icmp6_type; /* type of message, see below */ + uint8_t icmp6_code; /* type sub code */ + uint16_t icmp6_cksum; /* ones complement cksum of struct */ + union { + union icmp6_error_body error_body; + struct icmp6_echo echo; + struct ndp_rs ndp_rs; + struct ndp_ra ndp_ra; + struct ndp_ns ndp_ns; + struct ndp_na ndp_na; + struct ndp_redirect ndp_redirect; + } icmp6_body; +#define icmp6_err icmp6_body.error_body +#define icmp6_echo icmp6_body.echo +#define icmp6_nrs icmp6_body.ndp_rs +#define icmp6_nra icmp6_body.ndp_ra +#define icmp6_nns icmp6_body.ndp_ns +#define icmp6_nna icmp6_body.ndp_na +#define icmp6_redirect icmp6_body.ndp_redirect +}; + +G_STATIC_ASSERT(sizeof(struct icmp6) == 40); + +#define ICMP6_MINLEN 4 +#define ICMP6_ERROR_MINLEN 8 +#define ICMP6_ECHO_MINLEN 8 +#define ICMP6_NDP_RS_MINLEN 8 +#define ICMP6_NDP_RA_MINLEN 16 +#define ICMP6_NDP_NS_MINLEN 24 +#define ICMP6_NDP_NA_MINLEN 24 +#define ICMP6_NDP_REDIRECT_MINLEN 40 + +/* + * NDP Options + */ +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) +#endif +struct ndpopt { + uint8_t ndpopt_type; /* Option type */ + uint8_t ndpopt_len; /* /!\ In units of 8 octets */ + union { + unsigned char linklayer_addr[6]; /* Source/Target Link-layer */ +#define ndpopt_linklayer ndpopt_body.linklayer_addr + struct prefixinfo { /* Prefix Information */ + uint8_t prefix_length; +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint8_t L : 1, A : 1, reserved1 : 6; +#else + uint8_t reserved1 : 6, A : 1, L : 1; +#endif + uint32_t valid_lt; /* Valid Lifetime */ + uint32_t pref_lt; /* Preferred Lifetime */ + uint32_t reserved2; + struct in6_addr prefix; + } SLIRP_PACKED prefixinfo; +#define ndpopt_prefixinfo ndpopt_body.prefixinfo + struct rdnss { + uint16_t reserved; + uint32_t lifetime; + struct in6_addr addr; + } SLIRP_PACKED rdnss; +#define ndpopt_rdnss ndpopt_body.rdnss + } ndpopt_body; +} SLIRP_PACKED; +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(pop) +#endif + +/* NDP options type */ +#define NDPOPT_LINKLAYER_SOURCE 1 /* Source Link-Layer Address */ +#define NDPOPT_LINKLAYER_TARGET 2 /* Target Link-Layer Address */ +#define NDPOPT_PREFIX_INFO 3 /* Prefix Information */ +#define NDPOPT_RDNSS 25 /* Recursive DNS Server Address */ + +/* NDP options size, in octets. */ +#define NDPOPT_LINKLAYER_LEN 8 +#define NDPOPT_PREFIXINFO_LEN 32 +#define NDPOPT_RDNSS_LEN 24 + +/* + * Definition of type and code field values. + * Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml + * Last Updated 2012-11-12 + */ + +/* Errors */ +#define ICMP6_UNREACH 1 /* Destination Unreachable */ +#define ICMP6_UNREACH_NO_ROUTE 0 /* no route to dest */ +#define ICMP6_UNREACH_DEST_PROHIB 1 /* com with dest prohibited */ +#define ICMP6_UNREACH_SCOPE 2 /* beyond scope of src addr */ +#define ICMP6_UNREACH_ADDRESS 3 /* address unreachable */ +#define ICMP6_UNREACH_PORT 4 /* port unreachable */ +#define ICMP6_UNREACH_SRC_FAIL 5 /* src addr failed */ +#define ICMP6_UNREACH_REJECT_ROUTE 6 /* reject route to dest */ +#define ICMP6_UNREACH_SRC_HDR_ERROR 7 /* error in src routing header */ +#define ICMP6_TOOBIG 2 /* Packet Too Big */ +#define ICMP6_TIMXCEED 3 /* Time Exceeded */ +#define ICMP6_TIMXCEED_INTRANS 0 /* hop limit exceeded in transit */ +#define ICMP6_TIMXCEED_REASS 1 /* ttl=0 in reass */ +#define ICMP6_PARAMPROB 4 /* Parameter Problem */ +#define ICMP6_PARAMPROB_HDR_FIELD 0 /* err header field */ +#define ICMP6_PARAMPROB_NXTHDR_TYPE 1 /* unrecognized Next Header type */ +#define ICMP6_PARAMPROB_IPV6_OPT 2 /* unrecognized IPv6 option */ + +/* Informational Messages */ +#define ICMP6_ECHO_REQUEST 128 /* Echo Request */ +#define ICMP6_ECHO_REPLY 129 /* Echo Reply */ +#define ICMP6_NDP_RS 133 /* Router Solicitation (NDP) */ +#define ICMP6_NDP_RA 134 /* Router Advertisement (NDP) */ +#define ICMP6_NDP_NS 135 /* Neighbor Solicitation (NDP) */ +#define ICMP6_NDP_NA 136 /* Neighbor Advertisement (NDP) */ +#define ICMP6_NDP_REDIRECT 137 /* Redirect Message (NDP) */ + +/* + * Router Configuration Variables (rfc4861#section-6) + */ +#define NDP_IsRouter 1 +#define NDP_AdvSendAdvertisements 1 +#define NDP_MaxRtrAdvInterval 600000 +#define NDP_MinRtrAdvInterval \ + ((NDP_MaxRtrAdvInterval >= 9) ? NDP_MaxRtrAdvInterval / 3 : \ + NDP_MaxRtrAdvInterval) +#define NDP_AdvManagedFlag 0 +#define NDP_AdvOtherConfigFlag 0 +#define NDP_AdvLinkMTU 0 +#define NDP_AdvReachableTime 0 +#define NDP_AdvRetransTime 0 +#define NDP_AdvCurHopLimit 64 +#define NDP_AdvDefaultLifetime ((3 * NDP_MaxRtrAdvInterval) / 1000) +#define NDP_AdvValidLifetime 86400 +#define NDP_AdvOnLinkFlag 1 +#define NDP_AdvPrefLifetime 14400 +#define NDP_AdvAutonomousFlag 1 + +void icmp6_init(Slirp *slirp); +void icmp6_cleanup(Slirp *slirp); +void icmp6_input(struct mbuf *); +void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code); +void ndp_send_ra(Slirp *slirp); +void ndp_send_ns(Slirp *slirp, struct in6_addr addr); + +#endif diff --git a/src/network/slirp/ip6_input.c b/src/network/slirp/ip6_input.c new file mode 100644 index 000000000..a83e4f8e3 --- /dev/null +++ b/src/network/slirp/ip6_input.c @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. + */ + +#include "slirp.h" +#include "ip6_icmp.h" + +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void ip6_init(Slirp *slirp) +{ + icmp6_init(slirp); +} + +void ip6_cleanup(Slirp *slirp) +{ + icmp6_cleanup(slirp); +} + +void ip6_input(struct mbuf *m) +{ + struct ip6 *ip6; + Slirp *slirp = m->slirp; + + if (!slirp->in6_enabled) { + goto bad; + } + + DEBUG_CALL("ip6_input"); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("m_len = %d", m->m_len); + + if (m->m_len < sizeof(struct ip6)) { + goto bad; + } + + ip6 = mtod(m, struct ip6 *); + + if (ip6->ip_v != IP6VERSION) { + goto bad; + } + + if (ntohs(ip6->ip_pl) + sizeof(struct ip6) > slirp->if_mtu) { + icmp6_send_error(m, ICMP6_TOOBIG, 0); + goto bad; + } + + // Check if the message size is big enough to hold what's + // set in the payload length header. If not this is an invalid + // packet + if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) { + goto bad; + } + + /* check ip_ttl for a correct ICMP reply */ + if (ip6->ip_hl == 0) { + icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); + goto bad; + } + + /* + * Switch out to protocol's input routine. + */ + switch (ip6->ip_nh) { + case IPPROTO_TCP: + NTOHS(ip6->ip_pl); + tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6); + break; + case IPPROTO_UDP: + udp6_input(m); + break; + case IPPROTO_ICMPV6: + icmp6_input(m); + break; + default: + m_free(m); + } + return; +bad: + m_free(m); +} diff --git a/src/network/slirp/ip6_output.c b/src/network/slirp/ip6_output.c new file mode 100644 index 000000000..b86110662 --- /dev/null +++ b/src/network/slirp/ip6_output.c @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. + */ + +#include "slirp.h" + +/* Number of packets queued before we start sending + * (to prevent allocing too many mbufs) */ +#define IF6_THRESH 10 + +/* + * IPv6 output. The packet in mbuf chain m contains a IP header + */ +int ip6_output(struct socket *so, struct mbuf *m, int fast) +{ + struct ip6 *ip = mtod(m, struct ip6 *); + + DEBUG_CALL("ip6_output"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m = %p", m); + + /* Fill IPv6 header */ + ip->ip_v = IP6VERSION; + ip->ip_hl = IP6_HOP_LIMIT; + ip->ip_tc_hi = 0; + ip->ip_tc_lo = 0; + ip->ip_fl_hi = 0; + ip->ip_fl_lo = 0; + + if (fast) { + if_encap(m->slirp, m); + } else { + if_output(so, m); + } + + return 0; +} diff --git a/src/network/slirp/ip_icmp.c b/src/network/slirp/ip_icmp.c index 7bd787863..13a0e5508 100644 --- a/src/network/slirp/ip_icmp.c +++ b/src/network/slirp/ip_icmp.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -33,334 +34,459 @@ #include "slirp.h" #include "ip_icmp.h" -struct icmpstat icmpstat; +#ifndef WITH_ICMP_ERROR_MSG +#define WITH_ICMP_ERROR_MSG 0 +#endif /* The message sent when emulating PING */ -/* Be nice and tell them it's just a psuedo-ping packet */ -char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; +/* Be nice and tell them it's just a pseudo-ping packet */ +static const char icmp_ping_msg[] = + "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST " + "packets.\n"; -/* list of actions for icmp_error() on RX of an icmp message */ -static int icmp_flush[19] = { -/* ECHO REPLY (0) */ 0, - 1, - 1, -/* DEST UNREACH (3) */ 1, -/* SOURCE QUENCH (4)*/ 1, -/* REDIRECT (5) */ 1, - 1, - 1, -/* ECHO (8) */ 0, -/* ROUTERADVERT (9) */ 1, -/* ROUTERSOLICIT (10) */ 1, -/* TIME EXCEEDED (11) */ 1, -/* PARAMETER PROBLEM (12) */ 1, -/* TIMESTAMP (13) */ 0, -/* TIMESTAMP REPLY (14) */ 0, -/* INFO (15) */ 0, -/* INFO REPLY (16) */ 0, -/* ADDR MASK (17) */ 0, -/* ADDR MASK REPLY (18) */ 0 +/* list of actions for icmp_send_error() on RX of an icmp message */ +static const int icmp_flush[19] = { + /* ECHO REPLY (0) */ 0, + 1, + 1, + /* DEST UNREACH (3) */ 1, + /* SOURCE QUENCH (4)*/ 1, + /* REDIRECT (5) */ 1, + 1, + 1, + /* ECHO (8) */ 0, + /* ROUTERADVERT (9) */ 1, + /* ROUTERSOLICIT (10) */ 1, + /* TIME EXCEEDED (11) */ 1, + /* PARAMETER PROBLEM (12) */ 1, + /* TIMESTAMP (13) */ 0, + /* TIMESTAMP REPLY (14) */ 0, + /* INFO (15) */ 0, + /* INFO REPLY (16) */ 0, + /* ADDR MASK (17) */ 0, + /* ADDR MASK REPLY (18) */ 0 }; +void icmp_init(Slirp *slirp) +{ + slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp; + slirp->icmp_last_so = &slirp->icmp; +} + +void icmp_cleanup(Slirp *slirp) +{ + struct socket *so, *so_next; + + for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { + so_next = so->so_next; + icmp_detach(so); + } +} + +static int icmp_send(struct socket *so, struct mbuf *m, int hlen) +{ + struct ip *ip = mtod(m, struct ip *); + struct sockaddr_in addr; + + so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + if (so->s == -1) { + return -1; + } + + if (slirp_bind_outbound(so, AF_INET) != 0) { + // bind failed - close socket + closesocket(so->s); + so->s = -1; + return -1; + } + + so->so_m = m; + so->so_faddr = ip->ip_dst; + so->so_laddr = ip->ip_src; + so->so_iptos = ip->ip_tos; + so->so_type = IPPROTO_ICMP; + so->so_state = SS_ISFCONNECTED; + so->so_expire = curtime + SO_EXPIRE; + + addr.sin_family = AF_INET; + addr.sin_addr = so->so_faddr; + + insque(so, &so->slirp->icmp); + + if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) { + DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s", errno, + strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); + icmp_detach(so); + } + + return 0; +} + +void icmp_detach(struct socket *so) +{ + so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); + closesocket(so->s); + sofree(so); +} + /* * Process a received ICMP message. */ -void -icmp_input(m, hlen) - struct SLIRPmbuf *m; - int hlen; +void icmp_input(struct mbuf *m, int hlen) { - register struct icmp *icp; - register struct ip *ip=mtod(m, struct ip *); - int icmplen=ip->ip_len; - /* int code; */ - - DEBUG_CALL("icmp_input"); - DEBUG_ARG("m = %lx", (long )m); - DEBUG_ARG("m_len = %d", m->m_len); + register struct icmp *icp; + register struct ip *ip = mtod(m, struct ip *); + int icmplen = ip->ip_len; + Slirp *slirp = m->slirp; - icmpstat.icps_received++; - - /* - * Locate icmp structure in SLIRPmbuf, and check - * that its not corrupted and of at least minimum length. - */ - if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ - icmpstat.icps_tooshort++; - freeit: - m_freem(m); - goto end_error; - } + DEBUG_CALL("icmp_input"); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("m_len = %d", m->m_len); - m->m_len -= hlen; - m->m_data += hlen; - icp = mtod(m, struct icmp *); - if (cksum(m, icmplen)) { - icmpstat.icps_checksum++; - goto freeit; - } - m->m_len += hlen; - m->m_data -= hlen; - - /* icmpstat.icps_inhist[icp->icmp_type]++; */ - /* code = icp->icmp_code; */ + /* + * Locate icmp structure in mbuf, and check + * that its not corrupted and of at least minimum length. + */ + if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ + freeit: + m_free(m); + goto end_error; + } - DEBUG_ARG("icmp_type = %d", icp->icmp_type); - switch (icp->icmp_type) { - case ICMP_ECHO: - icp->icmp_type = ICMP_ECHOREPLY; - ip->ip_len += hlen; /* since ip_input subtracts this */ - if (ip->ip_dst.s_addr == alias_addr.s_addr) { - icmp_reflect(m); - } else { - struct SLIRPsocket *so; - struct sockaddr_in addr; - if ((so = socreate()) == NULL) goto freeit; - if(udp_attach(so) == -1) { - DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", - errno,strerror(errno))); - sofree(so); - m_free(m); - goto end_error; - } - so->so_m = m; - so->so_faddr = ip->ip_dst; - so->so_fport = htons(7); - so->so_laddr = ip->ip_src; - so->so_lport = htons(9); - so->so_iptos = ip->ip_tos; - so->so_type = IPPROTO_ICMP; - so->so_state = SS_ISFCONNECTED; - - /* Send the packet */ - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { - /* It's an alias */ - switch(ntohl(so->so_faddr.s_addr) & 0xff) { - case CTL_DNS: - addr.sin_addr = dns_addr; - break; - case CTL_ALIAS: - default: - addr.sin_addr = loopback_addr; - break; - } - } else { - addr.sin_addr = so->so_faddr; - } - addr.sin_port = so->so_fport; - if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, - (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", - errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); - udp_detach(so); - } - } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ - break; - case ICMP_UNREACH: - /* XXX? report error? close socket? */ - case ICMP_TIMXCEED: - case ICMP_PARAMPROB: - case ICMP_SOURCEQUENCH: - case ICMP_TSTAMP: - case ICMP_MASKREQ: - case ICMP_REDIRECT: - icmpstat.icps_notsupp++; - m_freem(m); - break; - - default: - icmpstat.icps_badtype++; - m_freem(m); - } /* swith */ + m->m_len -= hlen; + m->m_data += hlen; + icp = mtod(m, struct icmp *); + if (cksum(m, icmplen)) { + goto freeit; + } + m->m_len += hlen; + m->m_data -= hlen; + + DEBUG_ARG("icmp_type = %d", icp->icmp_type); + switch (icp->icmp_type) { + case ICMP_ECHO: + ip->ip_len += hlen; /* since ip_input subtracts this */ + if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr || + ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) { + icmp_reflect(m); + } else if (slirp->restricted) { + goto freeit; + } else { + struct socket *so; + struct sockaddr_storage addr; + so = socreate(slirp); + if (icmp_send(so, m, hlen) == 0) { + return; + } + if (udp_attach(so, AF_INET) == -1) { + DEBUG_MISC("icmp_input udp_attach errno = %d-%s", errno, + strerror(errno)); + sofree(so); + m_free(m); + goto end_error; + } + so->so_m = m; + so->so_ffamily = AF_INET; + so->so_faddr = ip->ip_dst; + so->so_fport = htons(7); + so->so_lfamily = AF_INET; + so->so_laddr = ip->ip_src; + so->so_lport = htons(9); + so->so_iptos = ip->ip_tos; + so->so_type = IPPROTO_ICMP; + so->so_state = SS_ISFCONNECTED; + + /* Send the packet */ + addr = so->fhost.ss; + if (sotranslate_out(so, &addr) < 0) { + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, + strerror(errno)); + udp_detach(so); + return; + } + + if (sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, + (struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) { + DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s", errno, + strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, + strerror(errno)); + udp_detach(so); + } + } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ + break; + case ICMP_UNREACH: + /* XXX? report error? close socket? */ + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + case ICMP_SOURCEQUENCH: + case ICMP_TSTAMP: + case ICMP_MASKREQ: + case ICMP_REDIRECT: + m_free(m); + break; + + default: + m_free(m); + } /* swith */ end_error: - /* m is m_free()'d xor put in a socket xor or given to ip_send */ - return; + /* m is m_free()'d xor put in a socket xor or given to ip_send */ + return; } /* * Send an ICMP message in response to a situation * - * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). - * MUST NOT change this header information. - * MUST NOT reply to a multicast/broadcast IP address. - * MUST NOT reply to a multicast/broadcast MAC address. - * MUST reply to only the first fragment. + * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. + *MAY send more (we do). MUST NOT change this header information. MUST NOT reply + *to a multicast/broadcast IP address. MUST NOT reply to a multicast/broadcast + *MAC address. MUST reply to only the first fragment. */ /* * Send ICMP_UNREACH back to the source regarding msrc. - * SLIRPmbuf *msrc is used as a template, but is NOT m_free()'d. + * mbuf *msrc is used as a template, but is NOT m_free()'d. * It is reported as the bad ip packet. The header should * be fully correct and in host byte order. - * ICMP fragmentation is illegal. All machines must accept 576 bytes in one + * ICMP fragmentation is illegal. All machines must accept 576 bytes in one * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 */ -#define ICMP_MAXDATALEN (IP_MSS-28) -void -icmp_error(struct SLIRPmbuf *msrc, u_char type, u_char code, int minsize, char *message) +#define ICMP_MAXDATALEN (IP_MSS - 28) +void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize, + const char *message) { - unsigned hlen, shlen, s_ip_len; - register struct ip *ip; - register struct icmp *icp; - register struct SLIRPmbuf *m; + unsigned hlen, shlen, s_ip_len; + register struct ip *ip; + register struct icmp *icp; + register struct mbuf *m; - DEBUG_CALL("icmp_error"); - DEBUG_ARG("msrc = %lx", (long )msrc); - DEBUG_ARG("msrc_len = %d", msrc->m_len); + DEBUG_CALL("icmp_send_error"); + DEBUG_ARG("msrc = %p", msrc); + DEBUG_ARG("msrc_len = %d", msrc->m_len); - if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; + if (type != ICMP_UNREACH && type != ICMP_TIMXCEED) + goto end_error; - /* check msrc */ - if(!msrc) goto end_error; - ip = mtod(msrc, struct ip *); -#if SLIRP_DEBUG - { char bufa[20], bufb[20]; - strcpy(bufa, inet_ntoa(ip->ip_src)); - strcpy(bufb, inet_ntoa(ip->ip_dst)); - DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); - } -#endif - if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ + /* check msrc */ + if (!msrc) + goto end_error; + ip = mtod(msrc, struct ip *); + if (slirp_debug & DBG_MISC) { + char bufa[20], bufb[20]; + slirp_pstrcpy(bufa, sizeof(bufa), inet_ntoa(ip->ip_src)); + slirp_pstrcpy(bufb, sizeof(bufb), inet_ntoa(ip->ip_dst)); + DEBUG_MISC(" %.16s to %.16s", bufa, bufb); + } + if (ip->ip_off & IP_OFFMASK) + goto end_error; /* Only reply to fragment 0 */ - shlen=ip->ip_hl << 2; - s_ip_len=ip->ip_len; - if(ip->ip_p == IPPROTO_ICMP) { - icp = (struct icmp *)((char *)ip + shlen); - /* - * Assume any unknown ICMP type is an error. This isn't - * specified by the RFC, but think about it.. - */ - if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; - } + /* Do not reply to source-only IPs */ + if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) { + goto end_error; + } - /* make a copy */ - if(!(m=m_get())) goto end_error; /* get SLIRPmbuf */ - { u_int new_m_size; - new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; - if(new_m_size>m->m_size) m_inc(m, new_m_size); - } - memcpy(m->m_data, msrc->m_data, msrc->m_len); - m->m_len = msrc->m_len; /* copy msrc to m */ + shlen = ip->ip_hl << 2; + s_ip_len = ip->ip_len; + if (ip->ip_p == IPPROTO_ICMP) { + icp = (struct icmp *)((char *)ip + shlen); + /* + * Assume any unknown ICMP type is an error. This isn't + * specified by the RFC, but think about it.. + */ + if (icp->icmp_type > 18 || icmp_flush[icp->icmp_type]) + goto end_error; + } - /* make the header of the reply packet */ - ip = mtod(m, struct ip *); - hlen= sizeof(struct ip ); /* no options in reply */ - - /* fill in icmp */ - m->m_data += hlen; - m->m_len -= hlen; + /* make a copy */ + m = m_get(msrc->slirp); + if (!m) { + goto end_error; + } - icp = mtod(m, struct icmp *); + { + int new_m_size; + new_m_size = + sizeof(struct ip) + ICMP_MINLEN + msrc->m_len + ICMP_MAXDATALEN; + if (new_m_size > m->m_size) + m_inc(m, new_m_size); + } + memcpy(m->m_data, msrc->m_data, msrc->m_len); + m->m_len = msrc->m_len; /* copy msrc to m */ - if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ - else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ - s_ip_len=ICMP_MAXDATALEN; + /* make the header of the reply packet */ + ip = mtod(m, struct ip *); + hlen = sizeof(struct ip); /* no options in reply */ - m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ + /* fill in icmp */ + m->m_data += hlen; + m->m_len -= hlen; - /* min. size = 8+sizeof(struct ip)+8 */ + icp = mtod(m, struct icmp *); - icp->icmp_type = type; - icp->icmp_code = code; - icp->icmp_id = 0; - icp->icmp_seq = 0; + if (minsize) + s_ip_len = shlen + ICMP_MINLEN; /* return header+8b only */ + else if (s_ip_len > ICMP_MAXDATALEN) /* maximum size */ + s_ip_len = ICMP_MAXDATALEN; - memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ - HTONS(icp->icmp_ip.ip_len); - HTONS(icp->icmp_ip.ip_id); - HTONS(icp->icmp_ip.ip_off); + m->m_len = ICMP_MINLEN + s_ip_len; /* 8 bytes ICMP header */ -#if SLIRP_DEBUG - if(message) { /* DEBUG : append message to ICMP packet */ - int message_len; - char *cpnt; - message_len=strlen(message); - if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; - cpnt=(char *)m->m_data+m->m_len; - memcpy(cpnt, message, message_len); - m->m_len+=message_len; - } -#endif + /* min. size = 8+sizeof(struct ip)+8 */ - icp->icmp_cksum = 0; - icp->icmp_cksum = cksum(m, m->m_len); + icp->icmp_type = type; + icp->icmp_code = code; + icp->icmp_id = 0; + icp->icmp_seq = 0; - m->m_data -= hlen; - m->m_len += hlen; + memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ + HTONS(icp->icmp_ip.ip_len); + HTONS(icp->icmp_ip.ip_id); + HTONS(icp->icmp_ip.ip_off); - /* fill in ip */ - ip->ip_hl = hlen >> 2; - ip->ip_len = (u_int16_t)m->m_len; - - ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ + if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */ + int message_len; + char *cpnt; + message_len = strlen(message); + if (message_len > ICMP_MAXDATALEN) + message_len = ICMP_MAXDATALEN; + cpnt = (char *)m->m_data + m->m_len; + memcpy(cpnt, message, message_len); + m->m_len += message_len; + } - ip->ip_ttl = MAXTTL; - ip->ip_p = IPPROTO_ICMP; - ip->ip_dst = ip->ip_src; /* ip adresses */ - ip->ip_src = alias_addr; + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, m->m_len); - (void ) ip_output((struct SLIRPsocket *)NULL, m); - - icmpstat.icps_reflect++; + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + ip->ip_hl = hlen >> 2; + ip->ip_len = m->m_len; + + ip->ip_tos = ((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ + + ip->ip_ttl = MAXTTL; + ip->ip_p = IPPROTO_ICMP; + ip->ip_dst = ip->ip_src; /* ip addresses */ + ip->ip_src = m->slirp->vhost_addr; + + (void)ip_output((struct socket *)NULL, m); end_error: - return; + return; } #undef ICMP_MAXDATALEN /* * Reflect the ip packet back to the source */ -void -icmp_reflect(m) - struct SLIRPmbuf *m; +void icmp_reflect(struct mbuf *m) { - register struct ip *ip = mtod(m, struct ip *); - int hlen = ip->ip_hl << 2; - int optlen = hlen - sizeof(struct ip ); - register struct icmp *icp; + register struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + int optlen = hlen - sizeof(struct ip); + register struct icmp *icp; - /* - * Send an icmp packet back to the ip level, - * after supplying a checksum. - */ - m->m_data += hlen; - m->m_len -= hlen; - icp = mtod(m, struct icmp *); - - icp->icmp_cksum = 0; - icp->icmp_cksum = cksum(m, ip->ip_len - hlen); - - m->m_data -= hlen; - m->m_len += hlen; - - /* fill in ip */ - if (optlen > 0) { /* - * Strip out original options by copying rest of first - * SLIRPmbuf's data back, and adjust the IP length. + * Send an icmp packet back to the ip level, + * after supplying a checksum. */ - memmove((SLIRPcaddr_t)(ip + 1), (SLIRPcaddr_t)ip + hlen, - (unsigned )(m->m_len - hlen)); - hlen -= optlen; - ip->ip_hl = hlen >> 2; - ip->ip_len -= optlen; - m->m_len -= optlen; - } + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); - ip->ip_ttl = MAXTTL; - { /* swap */ - struct in_addr icmp_dst; - icmp_dst = ip->ip_dst; - ip->ip_dst = ip->ip_src; - ip->ip_src = icmp_dst; - } + icp->icmp_type = ICMP_ECHOREPLY; + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, ip->ip_len - hlen); - (void ) ip_output((struct SLIRPsocket *)NULL, m); + m->m_data -= hlen; + m->m_len += hlen; - icmpstat.icps_reflect++; + /* fill in ip */ + if (optlen > 0) { + /* + * Strip out original options by copying rest of first + * mbuf's data back, and adjust the IP length. + */ + memmove((char *)(ip + 1), (char *)ip + hlen, + (unsigned)(m->m_len - hlen)); + hlen -= optlen; + ip->ip_hl = hlen >> 2; + ip->ip_len -= optlen; + m->m_len -= optlen; + } + + ip->ip_ttl = MAXTTL; + { /* swap */ + struct in_addr icmp_dst; + icmp_dst = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = icmp_dst; + } + + (void)ip_output((struct socket *)NULL, m); +} + +void icmp_receive(struct socket *so) +{ + struct mbuf *m = so->so_m; + struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + uint8_t error_code; + struct icmp *icp; + int id, len; + + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + + id = icp->icmp_id; + len = recv(so->s, icp, M_ROOM(m), 0); + /* + * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent + * between host OSes. On Linux, only the ICMP header and payload is + * included. On macOS/Darwin, the socket acts like a raw socket and + * includes the IP header as well. On other BSDs, SOCK_DGRAM+IPPROTO_ICMP + * sockets aren't supported at all, so we treat them like raw sockets. It + * isn't possible to detect this difference at runtime, so we must use an + * #ifdef to determine if we need to remove the IP header. + */ +#ifdef CONFIG_BSD + if (len >= sizeof(struct ip)) { + struct ip *inner_ip = mtod(m, struct ip *); + int inner_hlen = inner_ip->ip_hl << 2; + if (inner_hlen > len) { + len = -1; + errno = -EINVAL; + } else { + len -= inner_hlen; + memmove(icp, (unsigned char *)icp + inner_hlen, len); + } + } else { + len = -1; + errno = -EINVAL; + } +#endif + icp->icmp_id = id; + + m->m_data -= hlen; + m->m_len += hlen; + + if (len == -1 || len == 0) { + if (errno == ENETUNREACH) { + error_code = ICMP_UNREACH_NET; + } else { + error_code = ICMP_UNREACH_HOST; + } + DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno)); + icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); + } else { + icmp_reflect(so->so_m); + so->so_m = NULL; /* Don't m_free() it again! */ + } + icmp_detach(so); } diff --git a/src/network/slirp/ip_icmp.h b/src/network/slirp/ip_icmp.h index 20fcda1bd..84707db24 100644 --- a/src/network/slirp/ip_icmp.h +++ b/src/network/slirp/ip_icmp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -30,139 +31,136 @@ * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp */ -#ifndef _NETINET_IP_ICMP_H_ -#define _NETINET_IP_ICMP_H_ +#ifndef NETINET_IP_ICMP_H +#define NETINET_IP_ICMP_H /* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ -typedef u_int32_t n_time; +typedef uint32_t n_time; /* * Structure of an icmp header. */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - struct icmp { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ - union { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - u_short icd_id; - u_short icd_seq; - } ih_idseq; - int ih_void; + uint8_t icmp_type; /* type of message, see below */ + uint8_t icmp_code; /* type sub code */ + uint16_t icmp_cksum; /* ones complement cksum of struct */ + union { + uint8_t ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + int ih_void; - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu { - u_short ipm_void; - u_short ipm_nextmtu; - } ih_pmtu; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu - union { - struct id_ts { - n_time its_otime; - n_time its_rtime; - n_time its_ttime; - } id_ts; - struct id_ip { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - uint32_t id_mask; - char id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(0) -#endif + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + uint32_t id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; /* * Lower bounds on packet lengths for various types. - * For the error advice packets must first insure that the - * packet is large enought to contain the returned ip header. + * For the error advice packets must first ensure that the + * packet is large enough to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. */ -#define ICMP_MINLEN 8 /* abs minimum */ -#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ -#define ICMP_MASKLEN 12 /* address mask */ -#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ -#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) - /* N.B.: must separately check that ip_hl >= 5 */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof(n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) /* min */ +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) +/* N.B.: must separately check that ip_hl >= 5 */ /* * Definition of type and code field values. */ -#define ICMP_ECHOREPLY 0 /* echo reply */ -#define ICMP_UNREACH 3 /* dest unreachable, codes: */ -#define ICMP_UNREACH_NET 0 /* bad net */ -#define ICMP_UNREACH_HOST 1 /* bad host */ -#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ -#define ICMP_UNREACH_PORT 3 /* bad port */ -#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ -#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ -#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ -#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ -#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ -#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ -#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ -#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ -#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ -#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ -#define ICMP_REDIRECT 5 /* shorter route, codes: */ -#define ICMP_REDIRECT_NET 0 /* for network */ -#define ICMP_REDIRECT_HOST 1 /* for host */ -#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ -#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ -#define ICMP_ECHO 8 /* echo service */ -#define ICMP_ROUTERADVERT 9 /* router advertisement */ -#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ -#define ICMP_TIMXCEED 11 /* time exceeded, code: */ -#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ -#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ -#define ICMP_PARAMPROB 12 /* ip header bad */ -#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ -#define ICMP_TSTAMP 13 /* timestamp request */ -#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ -#define ICMP_IREQ 15 /* information request */ -#define ICMP_IREQREPLY 16 /* information reply */ -#define ICMP_MASKREQ 17 /* address mask request */ -#define ICMP_MASKREPLY 18 /* address mask reply */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ -#define ICMP_MAXTYPE 18 +#define ICMP_MAXTYPE 18 -#define ICMP_INFOTYPE(type) \ - ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ - (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ - (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ - (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ - (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) -void icmp_input _P((struct SLIRPmbuf *, int)); -void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *)); -void icmp_reflect _P((struct SLIRPmbuf *)); +void icmp_init(Slirp *slirp); +void icmp_cleanup(Slirp *slirp); +void icmp_input(struct mbuf *, int); +void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize, + const char *message); +void icmp_reflect(struct mbuf *); +void icmp_receive(struct socket *so); +void icmp_detach(struct socket *so); #endif diff --git a/src/network/slirp/ip_input.c b/src/network/slirp/ip_input.c index c2337f883..e04d1506d 100644 --- a/src/network/slirp/ip_input.c +++ b/src/network/slirp/ip_input.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -33,405 +34,383 @@ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#include #include "slirp.h" #include "ip_icmp.h" +#include -int ip_defttl; -struct ipstat ipstat; -struct ipq ipq; +static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp); +static void ip_freef(Slirp *slirp, struct ipq *fp); +static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev); +static void ip_deq(register struct ipasfrag *p); /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ -void -ip_init() +void ip_init(Slirp *slirp) { - ipq.next = ipq.prev = (ipqp_32)&ipq; - ip_id = tt.tv_sec & 0xffff; - udp_init(); - tcp_init(); - ip_defttl = IPDEFTTL; + slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link; + udp_init(slirp); + tcp_init(slirp); + icmp_init(slirp); +} + +void ip_cleanup(Slirp *slirp) +{ + udp_cleanup(slirp); + tcp_cleanup(slirp); + icmp_cleanup(slirp); } /* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ -void -ip_input(m) - struct SLIRPmbuf *m; +void ip_input(struct mbuf *m) { - register struct ip *ip; - u_int hlen; - - DEBUG_CALL("ip_input"); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("m_len = %d", m->m_len); + Slirp *slirp = m->slirp; + register struct ip *ip; + int hlen; - ipstat.ips_total++; - - if (m->m_len < sizeof (struct ip)) { - ipstat.ips_toosmall++; - return; - } - - ip = mtod(m, struct ip *); - - if (ip->ip_v != IPVERSION) { - ipstat.ips_badvers++; - goto bad; - } + if (!slirp->in_enabled) { + goto bad; + } - hlen = ip->ip_hl << 2; - if (hlenm->m_len) {/* min header length */ - ipstat.ips_badhlen++; /* or packet too short */ - goto bad; - } + DEBUG_CALL("ip_input"); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("m_len = %d", m->m_len); - /* keep ip header intact for ICMP reply - * ip->ip_sum = cksum(m, hlen); - * if (ip->ip_sum) { - */ - if(cksum(m,hlen)) { - ipstat.ips_badsum++; - goto bad; - } + if (m->m_len < sizeof(struct ip)) { + goto bad; + } - /* - * Convert fields to host representation. - */ - NTOHS(ip->ip_len); - if (ip->ip_len < hlen) { - ipstat.ips_badlen++; - goto bad; - } - NTOHS(ip->ip_id); - NTOHS(ip->ip_off); + ip = mtod(m, struct ip *); - /* - * Check that the amount of data in the buffers - * is as at least much as the IP header would have us expect. - * Trim SLIRPmbufs if longer than we expect. - * Drop packet if shorter than we expect. - */ - if (m->m_len < ip->ip_len) { - ipstat.ips_tooshort++; - goto bad; - } - /* Should drop packet if SLIRPmbuf too long? hmmm... */ - if (m->m_len > ip->ip_len) - m_adj(m, ip->ip_len - m->m_len); + if (ip->ip_v != IPVERSION) { + goto bad; + } - /* check ip_ttl for a correct ICMP reply */ - if(ip->ip_ttl==0 || ip->ip_ttl==1) { - icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); - goto bad; - } + hlen = ip->ip_hl << 2; + if (hlen < sizeof(struct ip) || hlen > m->m_len) { /* min header length */ + goto bad; /* or packet too short */ + } - /* - * Process options and, if not destined for us, - * ship it on. ip_dooptions returns 1 when an - * error was detected (causing an icmp message - * to be sent and the original packet to be freed). - */ -/* We do no IP options */ -/* if (hlen > sizeof (struct ip) && ip_dooptions(m)) - * goto next; - */ - /* - * If offset or IP_MF are set, must reassemble. - * Otherwise, nothing need be done. - * (We could look in the reassembly queue to see - * if the packet was previously fragmented, - * but it's not worth the time; just let them time out.) - * - * XXX This should fail, don't fragment yet - */ - if (ip->ip_off &~ IP_DF) { - register struct ipq *fp; - /* - * Look for queue of fragments - * of this datagram. - */ - for (fp = (struct ipq *) ipq.next; fp != &ipq; - fp = (struct ipq *) fp->next) - if (ip->ip_id == fp->ipq_id && - ip->ip_src.s_addr == fp->ipq_src.s_addr && - ip->ip_dst.s_addr == fp->ipq_dst.s_addr && - ip->ip_p == fp->ipq_p) - goto found; - fp = 0; - found: + /* keep ip header intact for ICMP reply + * ip->ip_sum = cksum(m, hlen); + * if (ip->ip_sum) { + */ + if (cksum(m, hlen)) { + goto bad; + } - /* - * Adjust ip_len to not reflect header, - * set ip_mff if more fragments are expected, - * convert offset of this to bytes. - */ - ip->ip_len -= hlen; - if (ip->ip_off & IP_MF) - ((struct ipasfrag *)ip)->ipf_mff |= 1; - else - ((struct ipasfrag *)ip)->ipf_mff &= ~1; + /* + * Convert fields to host representation. + */ + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) { + goto bad; + } + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); - ip->ip_off <<= 3; + /* + * Check that the amount of data in the buffers + * is as at least much as the IP header would have us expect. + * Trim mbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_len < ip->ip_len) { + goto bad; + } - /* - * If datagram marked as having more fragments - * or if this is not the first fragment, - * attempt reassembly; if it succeeds, proceed. - */ - if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { - ipstat.ips_fragments++; - ip = ip_reass((struct ipasfrag *)ip, fp); - if (ip == 0) - return; - ipstat.ips_reassembled++; - m = dtom(ip); - } else - if (fp) - ip_freef(fp); + /* Should drop packet if mbuf too long? hmmm... */ + if (m->m_len > ip->ip_len) + m_adj(m, ip->ip_len - m->m_len); - } else - ip->ip_len -= hlen; + /* check ip_ttl for a correct ICMP reply */ + if (ip->ip_ttl == 0) { + icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl"); + goto bad; + } - /* - * Switch out to protocol's input routine. - */ - ipstat.ips_delivered++; - switch (ip->ip_p) { - case IPPROTO_TCP: - tcp_input(m, hlen, (struct SLIRPsocket *)NULL); - break; - case IPPROTO_UDP: - udp_input(m, hlen); - break; - case IPPROTO_ICMP: - icmp_input(m, hlen); - break; - default: - ipstat.ips_noproto++; - m_free(m); - } - return; + /* + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) + * + * XXX This should fail, don't fragment yet + */ + if (ip->ip_off & ~IP_DF) { + register struct ipq *fp; + struct qlink *l; + /* + * Look for queue of fragments + * of this datagram. + */ + for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link; + l = l->next) { + fp = container_of(l, struct ipq, ip_link); + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + } + fp = NULL; + found: + + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + if (ip->ip_off & IP_MF) + ip->ip_tos |= 1; + else + ip->ip_tos &= ~1; + + ip->ip_off <<= 3; + + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (ip->ip_tos & 1 || ip->ip_off) { + ip = ip_reass(slirp, ip, fp); + if (ip == NULL) + return; + m = dtom(slirp, ip); + } else if (fp) + ip_freef(slirp, fp); + + } else + ip->ip_len -= hlen; + + /* + * Switch out to protocol's input routine. + */ + switch (ip->ip_p) { + case IPPROTO_TCP: + tcp_input(m, hlen, (struct socket *)NULL, AF_INET); + break; + case IPPROTO_UDP: + udp_input(m, hlen); + break; + case IPPROTO_ICMP: + icmp_input(m, hlen); + break; + default: + m_free(m); + } + return; bad: - m_freem(m); - return; + m_free(m); } +#define iptofrag(P) ((struct ipasfrag *)(((char *)(P)) - sizeof(struct qlink))) +#define fragtoip(P) ((struct ip *)(((char *)(P)) + sizeof(struct qlink))) /* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */ -struct ip * -ip_reass(ip, fp) - register struct ipasfrag *ip; - register struct ipq *fp; +static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp) { - register struct SLIRPmbuf *m = dtom(ip); - register struct ipasfrag *q; - int hlen = ip->ip_hl << 2; - int i, next; - - DEBUG_CALL("ip_reass"); - DEBUG_ARG("ip = %lx", (long)ip); - DEBUG_ARG("fp = %lx", (long)fp); - DEBUG_ARG("m = %lx", (long)m); + register struct mbuf *m = dtom(slirp, ip); + register struct ipasfrag *q; + int hlen = ip->ip_hl << 2; + int i, next; - /* - * Presence of header sizes in SLIRPmbufs - * would confuse code below. - * Fragment m_data is concatenated. - */ - m->m_data += hlen; - m->m_len -= hlen; + DEBUG_CALL("ip_reass"); + DEBUG_ARG("ip = %p", ip); + DEBUG_ARG("fp = %p", fp); + DEBUG_ARG("m = %p", m); - /* - * If first fragment to arrive, create a reassembly queue. - */ - if (fp == 0) { - struct SLIRPmbuf *t; - if ((t = m_get()) == NULL) goto dropfrag; - fp = mtod(t, struct ipq *); - insque_32(fp, &ipq); - fp->ipq_ttl = IPFRAGTTL; - fp->ipq_p = ip->ip_p; - fp->ipq_id = ip->ip_id; - fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; - fp->ipq_src = ((struct ip *)ip)->ip_src; - fp->ipq_dst = ((struct ip *)ip)->ip_dst; - q = (struct ipasfrag *)fp; - goto insert; - } - - /* - * Find a segment which begins after this one does. - */ - for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; - q = (struct ipasfrag *)q->ipf_next) - if (q->ip_off > ip->ip_off) - break; + /* + * Presence of header sizes in mbufs + * would confuse code below. + * Fragment m_data is concatenated. + */ + m->m_data += hlen; + m->m_len -= hlen; - /* - * If there is a preceding segment, it may provide some of - * our data already. If so, drop the data from the incoming - * segment. If it provides all of our data, drop us. - */ - if (q->ipf_prev != (ipasfragp_32)fp) { - i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + - ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; - if (i > 0) { - if (i >= ip->ip_len) - goto dropfrag; - m_adj(dtom(ip), i); - ip->ip_off += i; - ip->ip_len -= i; - } - } + /* + * If first fragment to arrive, create a reassembly queue. + */ + if (fp == NULL) { + struct mbuf *t = m_get(slirp); - /* - * While we overlap succeeding segments trim them or, - * if they are completely covered, dequeue them. - */ - while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { - i = (ip->ip_off + ip->ip_len) - q->ip_off; - if (i < q->ip_len) { - q->ip_len -= i; - q->ip_off += i; - m_adj(dtom(q), i); - break; - } - q = (struct ipasfrag *) q->ipf_next; - m_freem(dtom((struct ipasfrag *) q->ipf_prev)); - ip_deq((struct ipasfrag *) q->ipf_prev); - } + if (t == NULL) { + goto dropfrag; + } + fp = mtod(t, struct ipq *); + insque(&fp->ip_link, &slirp->ipq.ip_link); + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->frag_link.next = fp->frag_link.prev = &fp->frag_link; + fp->ipq_src = ip->ip_src; + fp->ipq_dst = ip->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; + q = q->ipf_next) + if (q->ipf_off > ip->ip_off) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (q->ipf_prev != &fp->frag_link) { + struct ipasfrag *pq = q->ipf_prev; + i = pq->ipf_off + pq->ipf_len - ip->ip_off; + if (i > 0) { + if (i >= ip->ip_len) + goto dropfrag; + m_adj(dtom(slirp, ip), i); + ip->ip_off += i; + ip->ip_len -= i; + } + } + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct ipasfrag *)&fp->frag_link && + ip->ip_off + ip->ip_len > q->ipf_off) { + struct ipasfrag *prev; + i = (ip->ip_off + ip->ip_len) - q->ipf_off; + if (i < q->ipf_len) { + q->ipf_len -= i; + q->ipf_off += i; + m_adj(dtom(slirp, q), i); + break; + } + prev = q; + q = q->ipf_next; + ip_deq(prev); + m_free(dtom(slirp, prev)); + } insert: - /* - * Stick new segment in its place; - * check for complete reassembly. - */ - ip_enq(ip, (struct ipasfrag *) q->ipf_prev); - next = 0; - for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; - q = (struct ipasfrag *) q->ipf_next) { - if (q->ip_off != next) - return (0); - next += q->ip_len; - } - if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) - return (0); + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(iptofrag(ip), q->ipf_prev); + next = 0; + for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; + q = q->ipf_next) { + if (q->ipf_off != next) + return NULL; + next += q->ipf_len; + } + if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1) + return NULL; - /* - * Reassembly is complete; concatenate fragments. - */ - q = (struct ipasfrag *) fp->ipq_next; - m = dtom(q); + /* + * Reassembly is complete; concatenate fragments. + */ + q = fp->frag_link.next; + m = dtom(slirp, q); + int delta = (char *)q - (m->m_flags & M_EXT ? m->m_ext : m->m_dat); - q = (struct ipasfrag *) q->ipf_next; - while (q != (struct ipasfrag *)fp) { - struct SLIRPmbuf *t; - t = dtom(q); - q = (struct ipasfrag *) q->ipf_next; - m_cat(m, t); - } + q = (struct ipasfrag *)q->ipf_next; + while (q != (struct ipasfrag *)&fp->frag_link) { + struct mbuf *t = dtom(slirp, q); + q = (struct ipasfrag *)q->ipf_next; + m_cat(m, t); + } - /* - * Create header for new ip packet by - * modifying header of first packet; - * dequeue and discard fragment reassembly header. - * Make header visible. - */ - ip = (struct ipasfrag *) fp->ipq_next; + /* + * Create header for new ip packet by + * modifying header of first packet; + * dequeue and discard fragment reassembly header. + * Make header visible. + */ + q = fp->frag_link.next; - /* - * If the fragments concatenated to an SLIRPmbuf that's - * bigger than the total size of the fragment, then and - * m_ext buffer was alloced. But fp->ipq_next points to - * the old buffer (in the SLIRPmbuf), so we must point ip - * into the new buffer. - */ - if (m->m_flags & M_EXT) { - int delta; - delta = (char *)ip - m->m_dat; - ip = (struct ipasfrag *)(m->m_ext + delta); - } + /* + * If the fragments concatenated to an mbuf that's bigger than the total + * size of the fragment and the mbuf was not already using an m_ext buffer, + * then an m_ext buffer was alloced. But fp->ipq_next points to the old + * buffer (in the mbuf), so we must point ip into the new buffer. + */ + if (m->m_flags & M_EXT) { + q = (struct ipasfrag *)(m->m_ext + delta); + } - /* DEBUG_ARG("ip = %lx", (long)ip); - * ip=(struct ipasfrag *)m->m_data; */ + ip = fragtoip(q); + ip->ip_len = next; + ip->ip_tos &= ~1; + ip->ip_src = fp->ipq_src; + ip->ip_dst = fp->ipq_dst; + remque(&fp->ip_link); + (void)m_free(dtom(slirp, fp)); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); - ip->ip_len = next; - ip->ipf_mff &= ~1; - ((struct ip *)ip)->ip_src = fp->ipq_src; - ((struct ip *)ip)->ip_dst = fp->ipq_dst; - remque_32(fp); - (void) m_free(dtom(fp)); - m = dtom(ip); - m->m_len += (ip->ip_hl << 2); - m->m_data -= (ip->ip_hl << 2); - - return ((struct ip *)ip); + return ip; dropfrag: - ipstat.ips_fragdropped++; - m_freem(m); - return (0); + m_free(m); + return NULL; } /* * Free a fragment reassembly header and all * associated datagrams. */ -void -ip_freef(fp) - struct ipq *fp; +static void ip_freef(Slirp *slirp, struct ipq *fp) { - register struct ipasfrag *q, *p; + register struct ipasfrag *q, *p; - for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; - q = p) { - p = (struct ipasfrag *) q->ipf_next; - ip_deq(q); - m_freem(dtom(q)); - } - remque_32(fp); - (void) m_free(dtom(fp)); + for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; + q = p) { + p = q->ipf_next; + ip_deq(q); + m_free(dtom(slirp, q)); + } + remque(&fp->ip_link); + (void)m_free(dtom(slirp, fp)); } /* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */ -void -ip_enq(p, prev) - register struct ipasfrag *p, *prev; +static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev) { - DEBUG_CALL("ip_enq"); - DEBUG_ARG("prev = %lx", (long)prev); - p->ipf_prev = (ipasfragp_32) prev; - p->ipf_next = prev->ipf_next; - ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; - prev->ipf_next = (ipasfragp_32) p; + DEBUG_CALL("ip_enq"); + DEBUG_ARG("prev = %p", prev); + p->ipf_prev = prev; + p->ipf_next = prev->ipf_next; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p; + prev->ipf_next = p; } /* * To ip_enq as remque is to insque. */ -void -ip_deq(p) - register struct ipasfrag *p; +static void ip_deq(register struct ipasfrag *p) { - ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; - ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; + ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; + ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; } /* @@ -439,234 +418,26 @@ ip_deq(p) * if a timer expires on a reassembly * queue, discard it. */ -void -ip_slowtimo() +void ip_slowtimo(Slirp *slirp) { - register struct ipq *fp; - - DEBUG_CALL("ip_slowtimo"); - - fp = (struct ipq *) ipq.next; - if (fp == 0) - return; + struct qlink *l; - while (fp != &ipq) { - --fp->ipq_ttl; - fp = (struct ipq *) fp->next; - if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { - ipstat.ips_fragtimeout++; - ip_freef((struct ipq *) fp->prev); - } - } + DEBUG_CALL("ip_slowtimo"); + + l = slirp->ipq.ip_link.next; + + if (l == NULL) + return; + + while (l != &slirp->ipq.ip_link) { + struct ipq *fp = container_of(l, struct ipq, ip_link); + l = l->next; + if (--fp->ipq_ttl == 0) { + ip_freef(slirp, fp); + } + } } -/* - * Do option processing on a datagram, - * possibly discarding it if bad options are encountered, - * or forwarding it if source-routed. - * Returns 1 if packet has been forwarded/freed, - * 0 if the packet should be processed further. - */ - -#ifdef notdef - -int -ip_dooptions(m) - struct SLIRPmbuf *m; -{ - register struct ip *ip = mtod(m, struct ip *); - register u_char *cp; - register struct ip_timestamp *ipt; - register struct in_ifaddr *ia; -/* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ - int opt, optlen, cnt, off, code, type, forward = 0; - struct in_addr *sin, dst; -typedef u_int32_t n_time; - n_time ntime; - - dst = ip->ip_dst; - cp = (u_char *)(ip + 1); - cnt = (ip->ip_hl << 2) - sizeof (struct ip); - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) - optlen = 1; - else { - optlen = cp[IPOPT_OLEN]; - if (optlen <= 0 || optlen > cnt) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - } - switch (opt) { - - default: - break; - - /* - * Source routing with record. - * Find interface with current destination address. - * If none on this machine then drop if strictly routed, - * or do nothing if loosely routed. - * Record interface address and bring up next address - * component. If strictly routed make sure next - * address is on directly accessible net. - */ - case IPOPT_LSRR: - case IPOPT_SSRR: - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - ipaddr.sin_addr = ip->ip_dst; - ia = (struct in_ifaddr *) - ifa_ifwithaddr((struct sockaddr *)&ipaddr); - if (ia == 0) { - if (opt == IPOPT_SSRR) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - /* - * Loose routing, and not at next destination - * yet; nothing to do except forward. - */ - break; - } - off--; / * 0 origin * / - if (off > optlen - sizeof(struct in_addr)) { - /* - * End of source route. Should be for us. - */ - save_rte(cp, ip->ip_src); - break; - } - /* - * locate outgoing interface - */ - bcopy((SLIRPcaddr_t)(cp + off), (SLIRPcaddr_t)&ipaddr.sin_addr, - sizeof(ipaddr.sin_addr)); - if (opt == IPOPT_SSRR) { -#define INA struct in_ifaddr * -#define SA struct sockaddr * - if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) - ia = (INA)ifa_ifwithnet((SA)&ipaddr); - } else - ia = ip_rtaddr(ipaddr.sin_addr); - if (ia == 0) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - ip->ip_dst = ipaddr.sin_addr; - bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), - (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - /* - * Let ip_intr's mcast routing check handle mcast pkts - */ - forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); - break; - - case IPOPT_RR: - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - /* - * If no space remains, ignore. - */ - off--; * 0 origin * - if (off > optlen - sizeof(struct in_addr)) - break; - bcopy((SLIRPcaddr_t)(&ip->ip_dst), (SLIRPcaddr_t)&ipaddr.sin_addr, - sizeof(ipaddr.sin_addr)); - /* - * locate outgoing interface; if we're the destination, - * use the incoming interface (should be same). - */ - if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && - (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_HOST; - goto bad; - } - bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), - (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - break; - - case IPOPT_TS: - code = cp - (u_char *)ip; - ipt = (struct ip_timestamp *)cp; - if (ipt->ipt_len < 5) - goto bad; - if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { - if (++ipt->ipt_oflw == 0) - goto bad; - break; - } - sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); - switch (ipt->ipt_flg) { - - case IPOPT_TS_TSONLY: - break; - - case IPOPT_TS_TSANDADDR: - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; - ipaddr.sin_addr = dst; - ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, - m->m_pkthdr.rcvif); - if (ia == 0) - continue; - bcopy((SLIRPcaddr_t)&IA_SIN(ia)->sin_addr, - (SLIRPcaddr_t)sin, sizeof(struct in_addr)); - ipt->ipt_ptr += sizeof(struct in_addr); - break; - - case IPOPT_TS_PRESPEC: - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; - bcopy((SLIRPcaddr_t)sin, (SLIRPcaddr_t)&ipaddr.sin_addr, - sizeof(struct in_addr)); - if (ifa_ifwithaddr((SA)&ipaddr) == 0) - continue; - ipt->ipt_ptr += sizeof(struct in_addr); - break; - - default: - goto bad; - } - ntime = iptime(); - bcopy((SLIRPcaddr_t)&ntime, (SLIRPcaddr_t)cp + ipt->ipt_ptr - 1, - sizeof(n_time)); - ipt->ipt_ptr += sizeof(n_time); - } - } - if (forward) { - ip_forward(m, 1); - return (1); - } - } - } - return (0); -bad: - /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ - -/* Not yet */ - icmp_error(m, type, code, 0, 0); - - ipstat.ips_badoptions++; - return (1); -} - -#endif /* notdef */ - /* * Strip out IP options, at higher * level protocol in the kernel. @@ -674,21 +445,18 @@ bad: * will be moved, and return value is their length. * (XXX) should be deleted; last arg currently ignored. */ -void -ip_stripoptions(m, mopt) - struct SLIRPmbuf *m; - struct SLIRPmbuf *mopt; +void ip_stripoptions(register struct mbuf *m, struct mbuf *mopt) { - register int i; - struct ip *ip = mtod(m, struct ip *); - register SLIRPcaddr_t opts; - int olen; + register int i; + struct ip *ip = mtod(m, struct ip *); + register char *opts; + int olen; - olen = (ip->ip_hl<<2) - sizeof (struct ip); - opts = (SLIRPcaddr_t)(ip + 1); - i = m->m_len - (sizeof (struct ip) + olen); - memcpy(opts, opts + olen, (unsigned)i); - m->m_len -= olen; - - ip->ip_hl = sizeof(struct ip) >> 2; + olen = (ip->ip_hl << 2) - sizeof(struct ip); + opts = (char *)(ip + 1); + i = m->m_len - (sizeof(struct ip) + olen); + memmove(opts, opts + olen, (unsigned)i); + m->m_len -= olen; + + ip->ip_hl = sizeof(struct ip) >> 2; } diff --git a/src/network/slirp/ip_output.c b/src/network/slirp/ip_output.c index c3f243e76..22916a37d 100644 --- a/src/network/slirp/ip_output.c +++ b/src/network/slirp/ip_output.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -33,170 +34,136 @@ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ #include "slirp.h" -u_int16_t ip_id; +/* Number of packets queued before we start sending + * (to prevent allocing too many mbufs) */ +#define IF_THRESH 10 /* - * IP output. The packet in SLIRPmbuf chain m contains a skeletal IP + * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). - * The SLIRPmbuf chain containing the packet will be freed. - * The SLIRPmbuf opt, if present, will not be freed. + * The mbuf chain containing the packet will be freed. + * The mbuf opt, if present, will not be freed. */ -int -ip_output(so, m0) - struct SLIRPsocket *so; - struct SLIRPmbuf *m0; +int ip_output(struct socket *so, struct mbuf *m0) { - struct ip *ip; - struct SLIRPmbuf *m = m0; - u_int hlen = sizeof(struct ip ); - u_int len, off; - int error = 0; + Slirp *slirp = m0->slirp; + register struct ip *ip; + register struct mbuf *m = m0; + register int hlen = sizeof(struct ip); + int len, off, error = 0; - DEBUG_CALL("ip_output"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m0 = %lx", (long)m0); - - /* We do no options */ -/* if (opt) { - * m = ip_insertoptions(m, opt, &len); - * hlen = len; - * } - */ - ip = mtod(m, struct ip *); - /* - * Fill in IP header. - */ - ip->ip_v = IPVERSION; - ip->ip_off &= IP_DF; - ip->ip_id = htons(ip_id++); - ip->ip_hl = hlen >> 2; - ipstat.ips_localout++; + DEBUG_CALL("ip_output"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m0 = %p", m0); - /* - * Verify that we have any chance at all of being able to queue - * the packet or packet fragments - */ - /* XXX Hmmm... */ -/* if (if_queued > if_thresh && towrite <= 0) { - * error = ENOBUFS; - * goto bad; - * } - */ - - /* - * If small enough for interface, can just send directly. - */ - if ((u_int16_t)ip->ip_len <= if_mtu) { - ip->ip_len = htons((u_int16_t)ip->ip_len); - ip->ip_off = htons((u_int16_t)ip->ip_off); - ip->ip_sum = 0; - ip->ip_sum = cksum(m, hlen); + ip = mtod(m, struct ip *); + /* + * Fill in IP header. + */ + ip->ip_v = IPVERSION; + ip->ip_off &= IP_DF; + ip->ip_id = htons(slirp->ip_id++); + ip->ip_hl = hlen >> 2; - if_output(so, m); - goto done; - } + /* + * If small enough for interface, can just send directly. + */ + if ((uint16_t)ip->ip_len <= slirp->if_mtu) { + ip->ip_len = htons((uint16_t)ip->ip_len); + ip->ip_off = htons((uint16_t)ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); - /* - * Too large for interface; fragment if possible. - * Must be able to put at least 8 bytes per fragment. - */ - if (ip->ip_off & IP_DF) { - error = -1; - ipstat.ips_cantfrag++; - goto bad; - } - - len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ - if (len < 8) { - error = -1; - goto bad; - } + if_output(so, m); + goto done; + } + + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = -1; + goto bad; + } + + len = (slirp->if_mtu - hlen) & ~7; /* ip databytes per packet */ + if (len < 8) { + error = -1; + goto bad; + } { - int mhlen, firstlen = len; - struct SLIRPmbuf **mnext = &m->m_nextpkt; + int mhlen, firstlen = len; + struct mbuf **mnext = &m->m_nextpkt; - /* - * Loop through length of segment after first fragment, - * make new header and copy data of each part and link onto chain. - */ - m0 = m; - mhlen = sizeof (struct ip); - for (off = hlen + len; off < ip->ip_len; off += len) { - struct ip *mhip; - m = m_get(); - if (m == 0) { - error = -1; - ipstat.ips_odropped++; - goto sendorfree; - } - m->m_data += if_maxlinkhdr; - mhip = mtod(m, struct ip *); - *mhip = *ip; - - /* No options */ -/* if (hlen > sizeof (struct ip)) { - * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); - * mhip->ip_hl = mhlen >> 2; - * } - */ - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); - if (ip->ip_off & IP_MF) - mhip->ip_off |= IP_MF; - if (off + len >= (u_int16_t)ip->ip_len) - len = (u_int16_t)ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons((u_int16_t)(len + mhlen)); - - if (m_copy(m, m0, off, len) < 0) { - error = -1; - goto sendorfree; - } - - mhip->ip_off = htons((u_int16_t)mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = cksum(m, mhlen); - *mnext = m; - mnext = &m->m_nextpkt; - ipstat.ips_ofragments++; - } - /* - * Update first fragment by trimming what's been copied out - * and updating header, then send each fragment (in order). - */ - m = m0; - m_adj(m, hlen + firstlen - ip->ip_len); - ip->ip_len = htons((u_int16_t)m->m_len); - ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); - ip->ip_sum = 0; - ip->ip_sum = cksum(m, hlen); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_nextpkt; - m->m_nextpkt = 0; - if (error == 0) - if_output(so, m); - else - m_freem(m); - } + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof(struct ip); + for (off = hlen + len; off < (uint16_t)ip->ip_len; off += len) { + register struct ip *mhip; + m = m_get(slirp); + if (m == NULL) { + error = -1; + goto sendorfree; + } + m->m_data += IF_MAXLINKHDR; + mhip = mtod(m, struct ip *); + *mhip = *ip; - if (error == 0) - ipstat.ips_fragmented++; + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= (uint16_t)ip->ip_len) + len = (uint16_t)ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((uint16_t)(len + mhlen)); + + if (m_copy(m, m0, off, len) < 0) { + error = -1; + goto sendorfree; + } + + mhip->ip_off = htons((uint16_t)mhip->ip_off); + mhip->ip_sum = 0; + mhip->ip_sum = cksum(m, mhlen); + *mnext = m; + mnext = &m->m_nextpkt; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m = m0; + m_adj(m, hlen + firstlen - (uint16_t)ip->ip_len); + ip->ip_len = htons((uint16_t)m->m_len); + ip->ip_off = htons((uint16_t)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); + sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = NULL; + if (error == 0) + if_output(so, m); + else + m_free(m); + } } done: - return (error); + return (error); bad: - m_freem(m0); - goto done; + m_free(m0); + goto done; } diff --git a/src/network/slirp/libslirp-version.h b/src/network/slirp/libslirp-version.h new file mode 100644 index 000000000..1599206a5 --- /dev/null +++ b/src/network/slirp/libslirp-version.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef LIBSLIRP_VERSION_H_ +#define LIBSLIRP_VERSION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SLIRP_MAJOR_VERSION 4 +#define SLIRP_MINOR_VERSION 3 +#define SLIRP_MICRO_VERSION 1 +#define SLIRP_VERSION_STRING "4.3.1-git-86Box" + +#define SLIRP_CHECK_VERSION(major,minor,micro) \ + (SLIRP_MAJOR_VERSION > (major) || \ + (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION > (minor)) || \ + (SLIRP_MAJOR_VERSION == (major) && SLIRP_MINOR_VERSION == (minor) && \ + SLIRP_MICRO_VERSION >= (micro))) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LIBSLIRP_VERSION_H_ */ diff --git a/src/network/slirp/libslirp.h b/src/network/slirp/libslirp.h index 8a1aa31e6..7c4340390 100644 --- a/src/network/slirp/libslirp.h +++ b/src/network/slirp/libslirp.h @@ -1,41 +1,186 @@ -#ifndef _LIBSLIRP_H -#define _LIBSLIRP_H +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef LIBSLIRP_H +#define LIBSLIRP_H + +#include +#include +#include #ifdef _WIN32 #include -int inet_aton(const char *cp, struct in_addr *ia); +#include #else -#include +#include #include #endif +#include "libslirp-version.h" + +/* Windows does not define ssize_t, so we need to define it here. */ +#ifndef _SSIZE_T_DEFINED +# define _SSIZE_T_DEFINED +# undef ssize_t +# ifdef _WIN64 +# define ssize_t int64_t +# else +# define ssize_t int32_t +# endif +#endif + #ifdef __cplusplus extern "C" { #endif -int slirp_init(void); +typedef struct Slirp Slirp; -int slirp_select_fill(int *pnfds, - fd_set *readfds, fd_set *writefds, fd_set *xfds); +enum { + SLIRP_POLL_IN = 1 << 0, + SLIRP_POLL_OUT = 1 << 1, + SLIRP_POLL_PRI = 1 << 2, + SLIRP_POLL_ERR = 1 << 3, + SLIRP_POLL_HUP = 1 << 4, +}; -void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); +typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque); +typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque); +typedef void (*SlirpTimerCb)(void *opaque); +typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque); +typedef int (*SlirpGetREventsCb)(int idx, void *opaque); -void slirp_input(const uint8 *pkt, int pkt_len); +/* + * Callbacks from slirp + */ +typedef struct SlirpCb { + /* + * Send an ethernet frame to the guest network. The opaque + * parameter is the one given to slirp_init(). The function + * doesn't need to send all the data and may return -#endif +#ifndef SLIRP_MAIN_H +#define SLIRP_MAIN_H -#define TOWRITEMAX 512 - -extern struct timeval tt; -extern int link_up; -extern int slirp_socket; -extern int slirp_socket_unit; -extern int slirp_socket_port; -extern u_int32_t slirp_socket_addr; -extern char *slirp_socket_passwd; -extern int ctty_closed; - -/* - * Get the difference in 2 times from updtim() - * Allow for wraparound times, "just in case" - * x is the greater of the 2 (current time) and y is - * what it's being compared against. - */ -#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) - -extern char *slirp_tty; -extern char *exec_shell; -extern u_int curtime; -extern fd_set *global_readfds, *global_writefds, *global_xfds; -extern struct in_addr ctl_addr; -extern struct in_addr special_addr; -extern struct in_addr alias_addr; -extern struct in_addr our_addr; +extern unsigned curtime; extern struct in_addr loopback_addr; -extern struct in_addr dns_addr; -extern char *username; -extern char *socket_path; -extern int towrite_max; -extern int ppp_exit; -extern int so_options; -extern int tcp_keepintvl; -extern uint8_t client_ethaddr[6]; +extern unsigned long loopback_mask; + +int if_encap(Slirp *slirp, struct mbuf *ifm); +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags); -#define PROTO_SLIP 0x1 -#ifdef USE_PPP -#define PROTO_PPP 0x2 #endif - -void if_encap(const uint8_t *ip_data, int ip_data_len); diff --git a/src/network/slirp/mbuf.c b/src/network/slirp/mbuf.c index c7f3f3fe8..e59db76d8 100644 --- a/src/network/slirp/mbuf.c +++ b/src/network/slirp/mbuf.c @@ -1,8 +1,6 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ /* @@ -10,209 +8,190 @@ * FreeBSD. They are fixed size, determined by the MTU, * so that one whole packet can fit. Mbuf's cannot be * chained together. If there's more data than the mbuf - * could hold, an external malloced buffer is pointed to + * could hold, an external g_malloced buffer is pointed to * by m_ext (and the data pointers) and M_EXT is set in * the flags */ -#include #include "slirp.h" +#include -struct mbuf *mbutl; -char *mclrefcnt; -int mbuf_alloced = 0; -struct SLIRPmbuf m_freelist, m_usedlist; -int mbuf_thresh = 30; -int mbuf_max = 0; -size_t msize; +#define MBUF_THRESH 30 -void -m_init() +/* + * Find a nice value for msize + */ +#define SLIRP_MSIZE(mtu) \ + (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + (mtu)) + +void m_init(Slirp *slirp) { - m_freelist.m_next = m_freelist.m_prev = &m_freelist; - m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; - msize_init(); + slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist; + slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist; } -void msize_init() +void m_cleanup(Slirp *slirp) { - /* - * Find a nice value for msize - * XXX if_maxlinkhdr already in mtu - */ - msize = (if_mtu>if_mru?if_mtu:if_mru) + - if_maxlinkhdr + sizeof(struct m_hdr ) + 6; + struct mbuf *m, *next; + + m = (struct mbuf *)slirp->m_usedlist.qh_link; + while ((struct quehead *)m != &slirp->m_usedlist) { + next = m->m_next; + if (m->m_flags & M_EXT) { + g_free(m->m_ext); + } + g_free(m); + m = next; + } + m = (struct mbuf *)slirp->m_freelist.qh_link; + while ((struct quehead *)m != &slirp->m_freelist) { + next = m->m_next; + g_free(m); + m = next; + } } /* * Get an mbuf from the free list, if there are none - * malloc one - * + * allocate one + * * Because fragmentation can occur if we alloc new mbufs and * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, - * which tells m_free to actually free() it + * which tells m_free to actually g_free() it */ -struct SLIRPmbuf * m_get() +struct mbuf *m_get(Slirp *slirp) { - struct SLIRPmbuf *m; - int flags = 0; - - DEBUG_CALL("m_get"); - - if (m_freelist.m_next == &m_freelist) { - m = (struct SLIRPmbuf *)malloc(msize); - if (m == NULL) goto end_error; - mbuf_alloced++; - if (mbuf_alloced > mbuf_thresh) - flags = M_DOFREE; - if (mbuf_alloced > mbuf_max) - mbuf_max = mbuf_alloced; - } else { - m = m_freelist.m_next; - remque(m); - } - - /* Insert it in the used list */ - insque(m,&m_usedlist); - m->m_flags = (flags | M_USEDLIST); - - /* Initialise it */ - m->m_size = msize - sizeof(struct m_hdr); - m->m_data = m->m_dat; - m->m_len = 0; - m->m_nextpkt = 0; - m->m_prevpkt = 0; -end_error: - DEBUG_ARG("m = %lx", (long )m); - return m; + register struct mbuf *m; + int flags = 0; + + DEBUG_CALL("m_get"); + + if (slirp->m_freelist.qh_link == &slirp->m_freelist) { + m = g_malloc(SLIRP_MSIZE(slirp->if_mtu)); + slirp->mbuf_alloced++; + if (slirp->mbuf_alloced > MBUF_THRESH) + flags = M_DOFREE; + m->slirp = slirp; + } else { + m = (struct mbuf *)slirp->m_freelist.qh_link; + remque(m); + } + + /* Insert it in the used list */ + insque(m, &slirp->m_usedlist); + m->m_flags = (flags | M_USEDLIST); + + /* Initialise it */ + m->m_size = SLIRP_MSIZE(slirp->if_mtu) - offsetof(struct mbuf, m_dat); + m->m_data = m->m_dat; + m->m_len = 0; + m->m_nextpkt = NULL; + m->m_prevpkt = NULL; + m->resolution_requested = false; + m->expiration_date = (uint64_t)-1; + DEBUG_ARG("m = %p", m); + return m; } -//For some reason this fails in GDB saying tehre is no m_flags member -void -m_free(m) - struct SLIRPmbuf *m; +void m_free(struct mbuf *m) { - - DEBUG_CALL("m_free"); - DEBUG_ARG("m = %lx", (long )m); - - if(m) { - /* Remove from m_usedlist */ - if (m->m_flags & M_USEDLIST) - remque(m); + DEBUG_CALL("m_free"); + DEBUG_ARG("m = %p", m); + if (m) { + /* Remove from m_usedlist */ + if (m->m_flags & M_USEDLIST) + remque(m); - - /* If it's M_EXT, free() it */ - if (m->m_flags & M_EXT) - free(m->m_ext); - - /* - * Either free() it or put it on the free list - */ - if (m->m_flags & M_DOFREE) { - free(m); - mbuf_alloced--; - } else if ((m->m_flags & M_FREELIST) == 0) { - insque(m,&m_freelist); - m->m_flags = M_FREELIST; /* Clobber other flags */ - } - } /* if(m) */ + /* If it's M_EXT, free() it */ + if (m->m_flags & M_EXT) { + g_free(m->m_ext); + } + /* + * Either free() it or put it on the free list + */ + if (m->m_flags & M_DOFREE) { + m->slirp->mbuf_alloced--; + g_free(m); + } else if ((m->m_flags & M_FREELIST) == 0) { + insque(m, &m->slirp->m_freelist); + m->m_flags = M_FREELIST; /* Clobber other flags */ + } + } /* if(m) */ } /* * Copy data from one mbuf to the end of - * the other.. if result is too big for one mbuf, malloc() + * the other.. if result is too big for one mbuf, allocate * an M_EXT data segment */ -void -m_cat(m, n) - struct SLIRPmbuf *m, *n; +void m_cat(struct mbuf *m, struct mbuf *n) { - /* - * If there's no room, realloc - */ - if (M_FREEROOM(m) < n->m_len) - m_inc(m,m->m_size+MINCSIZE); - - memcpy(m->m_data+m->m_len, n->m_data, n->m_len); - m->m_len += n->m_len; + /* + * If there's no room, realloc + */ + if (M_FREEROOM(m) < n->m_len) + m_inc(m, m->m_len + n->m_len); - m_free(n); + memcpy(m->m_data + m->m_len, n->m_data, n->m_len); + m->m_len += n->m_len; + + m_free(n); } -/* make m size bytes large */ -void -m_inc(m, size) - struct SLIRPmbuf *m; - int size; +/* make m 'size' bytes large from m_data */ +void m_inc(struct mbuf *m, int size) { - int datasize; + int gapsize; - /* some compiles throw up on gotos. This one we can fake. */ - if(m->m_size>size) return; + /* some compilers throw up on gotos. This one we can fake. */ + if (M_ROOM(m) > size) { + return; + } - if (m->m_flags & M_EXT) { - datasize = m->m_data - m->m_ext; - m->m_ext = (char *)realloc(m->m_ext,size); -/* if (m->m_ext == NULL) - * return (struct SLIRPmbuf *)NULL; - */ - m->m_data = m->m_ext + datasize; - } else { - char *dat; - datasize = m->m_data - m->m_dat; - dat = (char *)malloc(size); -/* if (dat == NULL) - * return (struct SLIRPmbuf *)NULL; - */ - memcpy(dat, m->m_dat, m->m_size); - - m->m_ext = dat; - m->m_data = m->m_ext + datasize; - m->m_flags |= M_EXT; - } - - m->m_size = size; + if (m->m_flags & M_EXT) { + gapsize = m->m_data - m->m_ext; + m->m_ext = g_realloc(m->m_ext, size + gapsize); + } else { + gapsize = m->m_data - m->m_dat; + m->m_ext = g_malloc(size + gapsize); + memcpy(m->m_ext, m->m_dat, m->m_size); + m->m_flags |= M_EXT; + } + m->m_data = m->m_ext + gapsize; + m->m_size = size + gapsize; } - -void -m_adj(m, len) - struct SLIRPmbuf *m; - int len; +void m_adj(struct mbuf *m, int len) { - if (m == NULL) - return; - if (len >= 0) { - /* Trim from head */ - m->m_data += len; - m->m_len -= len; - } else { - /* Trim from tail */ - len = -len; - m->m_len -= len; - } + if (m == NULL) + return; + if (len >= 0) { + /* Trim from head */ + m->m_data += len; + m->m_len -= len; + } else { + /* Trim from tail */ + len = -len; + m->m_len -= len; + } } /* * Copy len bytes from m, starting off bytes into n */ -int -m_copy(n, m, off, len) - struct SLIRPmbuf *n, *m; - int off, len; +int m_copy(struct mbuf *n, struct mbuf *m, int off, int len) { - if (len > M_FREEROOM(n)) - return -1; + if (len > M_FREEROOM(n)) + return -1; - memcpy((n->m_data + n->m_len), (m->m_data + off), len); - n->m_len += len; - return 0; + memcpy((n->m_data + n->m_len), (m->m_data + off), len); + n->m_len += len; + return 0; } @@ -221,28 +200,26 @@ m_copy(n, m, off, len) * XXX This is a kludge, I should eliminate the need for it * Fortunately, it's not used often */ -struct SLIRPmbuf * -dtom(dat) - void *dat; +struct mbuf *dtom(Slirp *slirp, void *dat) { - struct SLIRPmbuf *m; - - DEBUG_CALL("dtom"); - DEBUG_ARG("dat = %lx", (long )dat); + struct mbuf *m; - /* bug corrected for M_EXT buffers */ - for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { - if (m->m_flags & M_EXT) { - if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) - return m; - } else { - if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) - return m; - } - } - - DEBUG_ERROR((dfd, "dtom failed")); - - return (struct SLIRPmbuf *)0; + DEBUG_CALL("dtom"); + DEBUG_ARG("dat = %p", dat); + + /* bug corrected for M_EXT buffers */ + for (m = (struct mbuf *)slirp->m_usedlist.qh_link; + (struct quehead *)m != &slirp->m_usedlist; m = m->m_next) { + if (m->m_flags & M_EXT) { + if ((char *)dat >= m->m_ext && (char *)dat < (m->m_ext + m->m_size)) + return m; + } else { + if ((char *)dat >= m->m_dat && (char *)dat < (m->m_dat + m->m_size)) + return m; + } + } + + DEBUG_ERROR("dtom failed"); + + return (struct mbuf *)0; } - diff --git a/src/network/slirp/mbuf.h b/src/network/slirp/mbuf.h index 4921506b5..546e7852c 100644 --- a/src/network/slirp/mbuf.h +++ b/src/network/slirp/mbuf.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -30,21 +31,14 @@ * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp */ -#ifndef _MBUF_H_ -#define _MBUF_H_ - -#define m_freem m_free - - -#define MINCSIZE 4096 /* Amount to increase mbuf if too small */ +#ifndef MBUF_H +#define MBUF_H /* * Macros for type conversion * mtod(m,t) - convert mbuf pointer to data pointer of correct type - * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) */ -#define mtod(m,t) ((t)(m)->m_data) -/* #define dtom(x) ((struct SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */ +#define mtod(m, t) ((t)(m)->m_data) /* XXX About mbufs for slirp: * Only one mbuf is ever used in a chain, for each "cell" of data. @@ -54,90 +48,80 @@ * free the m_ext. This is inefficient memory-wise, but who cares. */ -/* XXX should union some of these! */ -/* header at beginning of each mbuf: */ -struct m_hdr { - struct SLIRPmbuf *mh_next; /* Linked list of mbufs */ - struct SLIRPmbuf *mh_prev; - struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */ - struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */ - int mh_flags; /* Misc flags */ +/* + * mbufs allow to have a gap between the start of the allocated buffer (m_ext if + * M_EXT is set, m_dat otherwise) and the in-use data: + * + * |--gapsize----->|---m_len-------> + * |----------m_size------------------------------> + * |----M_ROOM--------------------> + * |-M_FREEROOM--> + * + * ^ ^ ^ + * m_dat/m_ext m_data end of buffer + */ - size_t mh_size; /* Size of data */ - struct SLIRPsocket *mh_so; - - SLIRPcaddr_t mh_data; /* Location of data */ - int32_t mh_len; /* Amount of data in this mbuf */ -}; - -/* +/* * How much room is in the mbuf, from m_data to the end of the mbuf */ -#define M_ROOM(m) ((m->m_flags & M_EXT)? \ - (((m)->m_ext + (m)->m_size) - (m)->m_data) \ - : \ - (((m)->m_dat + (m)->m_size) - (m)->m_data)) +#define M_ROOM(m) \ + ((m->m_flags & M_EXT) ? (((m)->m_ext + (m)->m_size) - (m)->m_data) : \ + (((m)->m_dat + (m)->m_size) - (m)->m_data)) /* * How much free room there is */ #define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) -#define M_TRAILINGSPACE M_FREEROOM -struct SLIRPmbuf { - struct m_hdr m_hdr; - union M_dat { - char m_dat_[1]; /* ANSI don't like 0 sized arrays */ - char *m_ext_; - } M_dat; +struct mbuf { + /* XXX should union some of these! */ + /* header at beginning of each mbuf: */ + struct mbuf *m_next; /* Linked list of mbufs */ + struct mbuf *m_prev; + struct mbuf *m_nextpkt; /* Next packet in queue/record */ + struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */ + int m_flags; /* Misc flags */ + + int m_size; /* Size of mbuf, from m_dat or m_ext */ + struct socket *m_so; + + char *m_data; /* Current location of data */ + int m_len; /* Amount of data in this mbuf, from m_data */ + + Slirp *slirp; + bool resolution_requested; + uint64_t expiration_date; + char *m_ext; + /* start of dynamic buffer area, must be last element */ + char m_dat[]; }; -#define m_next m_hdr.mh_next -#define m_prev m_hdr.mh_prev -#define m_nextpkt m_hdr.mh_nextpkt -#define m_prevpkt m_hdr.mh_prevpkt -#define m_flags m_hdr.mh_flags -#define m_len m_hdr.mh_len -#define m_data m_hdr.mh_data -#define m_size m_hdr.mh_size -#define m_dat M_dat.m_dat_ -#define m_ext M_dat.m_ext_ -#define m_so m_hdr.mh_so - #define ifq_prev m_prev #define ifq_next m_next #define ifs_prev m_prevpkt #define ifs_next m_nextpkt #define ifq_so m_so -#define M_EXT 0x01 /* m_ext points to more (malloced) data */ -#define M_FREELIST 0x02 /* mbuf is on free list */ -#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ -#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() - * it rather than putting it on the free list */ +#define M_EXT 0x01 /* m_ext points to more (malloced) data */ +#define M_FREELIST 0x02 /* mbuf is on free list */ +#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ +#define M_DOFREE \ + 0x08 /* when m_free is called on the mbuf, free() \ + * it rather than putting it on the free list */ -/* - * Mbuf statistics. XXX - */ +void m_init(Slirp *); +void m_cleanup(Slirp *slirp); +struct mbuf *m_get(Slirp *); +void m_free(struct mbuf *); +void m_cat(register struct mbuf *, register struct mbuf *); +void m_inc(struct mbuf *, int); +void m_adj(struct mbuf *, int); +int m_copy(struct mbuf *, struct mbuf *, int, int); +struct mbuf *dtom(Slirp *, void *); -struct mbstat { - int mbs_alloced; /* Number of mbufs allocated */ - -}; - -extern struct mbstat mbstat; -extern int mbuf_alloced; -extern struct SLIRPmbuf m_freelist, m_usedlist; -extern int mbuf_max; - -void m_init _P((void)); -void msize_init _P((void)); -struct SLIRPmbuf * m_get _P((void)); -void m_free _P((struct SLIRPmbuf *)); -void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *)); -void m_inc _P((struct SLIRPmbuf *, int)); -void m_adj _P((struct SLIRPmbuf *, int)); -int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int)); -struct SLIRPmbuf * dtom _P((void *)); +static inline void ifs_init(struct mbuf *ifm) +{ + ifm->ifs_next = ifm->ifs_prev = ifm; +} #endif diff --git a/src/network/slirp/misc.c b/src/network/slirp/misc.c index ae86bb3be..3bea32ac1 100644 --- a/src/network/slirp/misc.c +++ b/src/network/slirp/misc.c @@ -1,972 +1,397 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#define WANT_SYS_IOCTL_H -#include -#ifndef _WIN32 -# include -#endif #include "slirp.h" - -u_int curtime, time_fasttimo, last_slowtimo, detach_time; -u_int detach_wait = 600000; /* 10 minutes */ - -#if 0 -int x_port = -1; -int x_display = 0; -int x_screen = 0; - -int -show_x(buff, inso) - char *buff; - struct SLIRPsocket *inso; -{ - if (x_port < 0) { - lprint("X Redir: X not being redirected.\r\n"); - } else { - lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n", - inet_ntoa(our_addr), x_port, x_screen); - lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n", - inet_ntoa(our_addr), x_port, x_screen); - if (x_display) - lprint("X Redir: Redirecting to display %d\r\n", x_display); - } - - return CFG_OK; -} - - -/* - * XXX Allow more than one X redirection? - */ -void -redir_x(inaddr, start_port, display, screen) - u_int32_t inaddr; - int start_port; - int display; - int screen; -{ - int i; - - if (x_port >= 0) { - lprint("X Redir: X already being redirected.\r\n"); - show_x(0, 0); - } else { - for (i = 6001 + (start_port-1); i <= 6100; i++) { - if (solisten(htons(i), inaddr, htons(6000 + display), 0)) { - /* Success */ - x_port = i - 6000; - x_display = display; - x_screen = screen; - show_x(0, 0); - return; - } - } - lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n"); - } -} -#endif - -#ifndef HAVE_INET_ATON -int -inet_aton(cp, ia) - const char *cp; - struct in_addr *ia; -{ - u_int32_t addr = inet_addr(cp); - if (addr == 0xffffffff) - return 0; - ia->s_addr = addr; - return 1; -} -#endif - - -extern void pclog(char *fmt, ...); - - -/* - * Get our IP address and put it in our_addr - */ -void -getouraddr() -{ - char buff[512]; - struct hostent *he = NULL; -#define ANCIENT -#ifdef ANCIENT - if (gethostname(buff,500) == 0) - he = gethostbyname(buff); - if (he) - our_addr = *(struct in_addr *)he->h_addr; - if (our_addr.s_addr == 0) - our_addr.s_addr = loopback_addr.s_addr; +#include +#ifdef G_OS_UNIX +#include +#include +#ifdef BSD +#define g_strlcpy strlcpy #else - if (gethostname(buff,256) == 0) - { - struct addrinfo hints = { 0 }; - hints.ai_flags = AI_NUMERICHOST; - hints.ai_family = AF_INET; - struct addrinfo* ai; - if (getaddrinfo(buff, NULL, &hints, &ai) == 0) - { - our_addr = *(struct in_addr *)ai->ai_addr->sa_data; - freeaddrinfo(ai); - } - } - if (our_addr.s_addr == 0) - our_addr.s_addr = loopback_addr.s_addr; +extern gsize g_strlcpy(gchar* dest, const gchar* src, gsize dest_size); #endif -#undef ANCIENT - pclog(" Our IP address: %s (%s)\n", inet_ntoa(our_addr), buff); -} - -//#if SIZEOF_CHAR_P == 8 -//what?! - -struct quehead_32 { - uintptr_t qh_link; - uintptr_t qh_rlink; -}; - -inline void -insque_32(a, b) - void *a; - void *b; -{ - register struct quehead_32 *element = (struct quehead_32 *) a; - register struct quehead_32 *head = (struct quehead_32 *) b; - element->qh_link = head->qh_link; - head->qh_link = (uintptr_t)element; - element->qh_rlink = (uintptr_t)head; - ((struct quehead_32 *)(element->qh_link))->qh_rlink - = (uintptr_t)element; -} - -inline void -remque_32(a) - void *a; -{ - register struct quehead_32 *element = (struct quehead_32 *) a; - ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; - ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -//#endif /* SIZEOF_CHAR_P == 8 */ -//Should be for 64bit - -struct quehead { - struct quehead *qh_link; - struct quehead *qh_rlink; -}; - -void -insque(a, b) - void *a, *b; -{ - register struct quehead *element = (struct quehead *) a; - register struct quehead *head = (struct quehead *) b; - element->qh_link = head->qh_link; - head->qh_link = (struct quehead *)element; - element->qh_rlink = (struct quehead *)head; - ((struct quehead *)(element->qh_link))->qh_rlink - = (struct quehead *)element; -} - -void -remque(a) - void *a; -{ - register struct quehead *element = (struct quehead *) a; - ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; - ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; - element->qh_rlink = NULL; - /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ -} - -/* #endif */ - - -int -add_exec(ex_ptr, do_pty, exec, addr, port) - struct ex_list **ex_ptr; - int do_pty; - char *exec; - int addr; - int port; -{ - struct ex_list *tmp_ptr; - - /* First, check if the port is "bound" */ - for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { - if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) - return -1; - } - - tmp_ptr = *ex_ptr; - *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); - (*ex_ptr)->ex_fport = port; - (*ex_ptr)->ex_addr = addr; - (*ex_ptr)->ex_pty = do_pty; - (*ex_ptr)->ex_exec = strdup(exec); - (*ex_ptr)->ex_next = tmp_ptr; - return 0; -} - -#ifndef HAVE_STRERROR - -/* - * For systems with no strerror - */ -char * -SLIRPstrerror(error) - int error; -{ - if (error < sys_nerr) - return sys_errlist[error]; - else - return "Unknown error."; -} - #endif - -#ifdef _WIN32 - -int -fork_exec(so, ex, do_pty) - struct SLIRPsocket *so; - char *ex; - int do_pty; +extern inline void insque(void *a, void *b) { - /* not implemented */ - return 0; + register struct quehead *element = (struct quehead *)a; + register struct quehead *head = (struct quehead *)b; + element->qh_link = head->qh_link; + head->qh_link = (struct quehead *)element; + element->qh_rlink = (struct quehead *)head; + ((struct quehead *)(element->qh_link))->qh_rlink = + (struct quehead *)element; } -#else - -int -slirp_openpty(amaster, aslave) - int *amaster, *aslave; +extern inline void remque(void *a) { - register int master, slave; - -#ifdef HAVE_GRANTPT - char *ptr; - - if ((master = open("/dev/ptmx", O_RDWR)) < 0 || - grantpt(master) < 0 || - unlockpt(master) < 0 || - (ptr = ptsname(master)) == NULL) { - close(master); - return -1; - } - - if ((slave = open(ptr, O_RDWR)) < 0 || - ioctl(slave, I_PUSH, "ptem") < 0 || - ioctl(slave, I_PUSH, "ldterm") < 0 || - ioctl(slave, I_PUSH, "ttcompat") < 0) { - close(master); - close(slave); - return -1; - } - - *amaster = master; - *aslave = slave; - return 0; - -#else - - static char line[] = "/dev/ptyXX"; - register const char *cp1, *cp2; - - for (cp1 = "pqrsPQRS"; *cp1; cp1++) { - line[8] = *cp1; - for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { - line[9] = *cp2; - if ((master = open(line, O_RDWR, 0)) == -1) { - if (errno == ENOENT) - return (-1); /* out of ptys */ - } else { - line[5] = 't'; - /* These will fail */ - (void) chown(line, getuid(), 0); - (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); -#ifdef HAVE_REVOKE - (void) revoke(line); -#endif - if ((slave = open(line, O_RDWR, 0)) != -1) { - *amaster = master; - *aslave = slave; - return 0; - } - (void) close(master); - line[5] = 'p'; - } - } - } - errno = ENOENT; /* out of ptys */ - return (-1); -#endif + register struct quehead *element = (struct quehead *)a; + ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = NULL; } -/* - * XXX This is ugly - * We create and bind a socket, then fork off to another - * process, which connects to this socket, after which we - * exec the wanted program. If something (strange) happens, - * the accept() call could block us forever. - * - * do_pty = 0 Fork/exec inetd style - * do_pty = 1 Fork/exec using slirp.telnetd - * do_ptr = 2 Fork/exec using pty - */ -int -fork_exec(so, ex, do_pty) - struct SLIRPsocket *so; - char *ex; - int do_pty; +/* TODO: IPv6 */ +struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb, + void *opaque, struct in_addr addr, int port) { - int s; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int opt; - int master; - char *argv[256]; -#if 0 - char buff[256]; -#endif - /* don't want to clobber the original */ - char *bptr; - char *curarg; - int c, i, ret; - - DEBUG_CALL("fork_exec"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("ex = %lx", (long)ex); - DEBUG_ARG("do_pty = %lx", (long)do_pty); - - if (do_pty == 2) { - if (slirp_openpty(&master, &s) == -1) { - lprint("Error: openpty failed: %s\n", strerror(errno)); - return 0; - } - } else { - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = INADDR_ANY; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || - bind(s, (struct sockaddr *)&addr, addrlen) < 0 || - listen(s, 1) < 0) { - lprint("Error: inet socket: %s\n", strerror(errno)); - closesocket(s); - - return 0; - } - } - - switch(fork()) { - case -1: - lprint("Error: fork failed: %s\n", strerror(errno)); - close(s); - if (do_pty == 2) - close(master); - return 0; - - case 0: - /* Set the DISPLAY */ - if (do_pty == 2) { - (void) close(master); -#ifdef TIOCSCTTY /* XXXXX */ - (void) setsid(); - ioctl(s, TIOCSCTTY, (char *)NULL); -#endif - } else { - getsockname(s, (struct sockaddr *)&addr, &addrlen); - close(s); - /* - * Connect to the socket - * XXX If any of these fail, we're in trouble! - */ - s = socket(AF_INET, SOCK_STREAM, 0); - addr.sin_addr = loopback_addr; - do { - ret = connect(s, (struct sockaddr *)&addr, addrlen); - } while (ret < 0 && errno == EINTR); - } - -#if 0 - if (x_port >= 0) { -#ifdef HAVE_SETENV - sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); - setenv("DISPLAY", buff, 1); -#else - sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); - putenv(buff); -#endif - } -#endif - dup2(s, 0); - dup2(s, 1); - dup2(s, 2); - for (s = 3; s <= 255; s++) - close(s); - - i = 0; - bptr = strdup(ex); /* No need to free() this */ - if (do_pty == 1) { - /* Setup "slirp.telnetd -x" */ - argv[i++] = "slirp.telnetd"; - argv[i++] = "-x"; - argv[i++] = bptr; - } else - do { - /* Change the string into argv[] */ - curarg = bptr; - while (*bptr != ' ' && *bptr != (char)0) - bptr++; - c = *bptr; - *bptr++ = (char)0; - argv[i++] = strdup(curarg); - } while (c); - - argv[i] = 0; - execvp(argv[0], argv); - - /* Ooops, failed, let's tell the user why */ - { - char buff[256]; - - sprintf(buff, "Error: execvp of %s failed: %s\n", - argv[0], strerror(errno)); - write(2, buff, strlen(buff)+1); - } - close(0); close(1); close(2); /* XXX */ - exit(1); - - default: - if (do_pty == 2) { - close(s); - so->s = master; - } else { - /* - * XXX this could block us... - * XXX Should set a timer here, and if accept() doesn't - * return after X seconds, declare it a failure - * The only reason this will block forever is if socket() - * of connect() fail in the child process - */ - do { - so->s = accept(s, (struct sockaddr *)&addr, &addrlen); - } while (so->s < 0 && errno == EINTR); - closesocket(s); - opt = 1; - setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); - opt = 1; - setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); - } - fd_nonblock(so->s); - - /* Append the telnet options now */ - if (so->so_m != 0 && do_pty == 1) { - sbappend(so, so->so_m); - so->so_m = 0; - } - - return 1; - } -} -#endif + struct gfwd_list *f = g_new0(struct gfwd_list, 1); -#ifndef HAVE_STRDUP -char * strdup(char *str) -{ - char *bptr; - - bptr = (char *)malloc(strlen(str)+1); - strcpy(bptr, str); - - return bptr; -} -#endif + f->write_cb = write_cb; + f->opaque = opaque; + f->ex_fport = port; + f->ex_addr = addr; + f->ex_next = *ex_ptr; + *ex_ptr = f; -#if 0 -void -snooze_hup(num) - int num; -{ - int s, ret; -#ifndef NO_UNIX_SOCKETS - struct sockaddr_un sock_un; -#endif - struct sockaddr_in sock_in; - char buff[256]; - - ret = -1; - if (slirp_socket_passwd) { - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - slirp_exit(1); - sock_in.sin_family = AF_INET; - sock_in.sin_addr.s_addr = slirp_socket_addr; - sock_in.sin_port = htons(slirp_socket_port); - if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) - slirp_exit(1); /* just exit...*/ - sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); - write(s, buff, strlen(buff)+1); - } -#ifndef NO_UNIX_SOCKETS - else { - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) - slirp_exit(1); - sock_un.sun_family = AF_UNIX; - strcpy(sock_un.sun_path, socket_path); - if (connect(s, (struct sockaddr *)&sock_un, - sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) - slirp_exit(1); - sprintf(buff, "kill none:%d", slirp_socket_unit); - write(s, buff, strlen(buff)+1); - } -#endif - slirp_exit(0); -} - - -void -snooze() -{ - sigset_t s; - int i; - - /* Don't need our data anymore */ - /* XXX This makes SunOS barf */ -/* brk(0); */ - - /* Close all fd's */ - for (i = 255; i >= 0; i--) - close(i); - - signal(SIGQUIT, slirp_exit); - signal(SIGHUP, snooze_hup); - sigemptyset(&s); - - /* Wait for any signal */ - sigsuspend(&s); - - /* Just in case ... */ - exit(255); + return f; } -void -relay(s) - int s; +struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline, + struct in_addr addr, int port) { - char buf[8192]; - int n; - fd_set readfds; - struct ttys *ttyp; - - /* Don't need our data anymore */ - /* XXX This makes SunOS barf */ -/* brk(0); */ - - signal(SIGQUIT, slirp_exit); - signal(SIGHUP, slirp_exit); - signal(SIGINT, slirp_exit); - signal(SIGTERM, slirp_exit); - - /* Fudge to get term_raw and term_restore to work */ - if (NULL == (ttyp = tty_attach (0, slirp_tty))) { - lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); - slirp_exit (1); + struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port); + + f->ex_exec = g_strdup(cmdline); + + return f; +} + +struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock, + struct in_addr addr, int port) +{ + struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port); + + f->ex_unix = g_strdup(unixsock); + + return f; +} + +int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port) +{ + for (; *ex_ptr != NULL; ex_ptr = &((*ex_ptr)->ex_next)) { + struct gfwd_list *f = *ex_ptr; + if (f->ex_addr.s_addr == addr.s_addr && f->ex_fport == port) { + *ex_ptr = f->ex_next; + g_free(f->ex_exec); + g_free(f); + return 0; + } } - ttyp->fd = 0; - ttyp->flags |= TTY_CTTY; - term_raw(ttyp); - - while (1) { - FD_ZERO(&readfds); - - FD_SET(0, &readfds); - FD_SET(s, &readfds); - - n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); - - if (n <= 0) - slirp_exit(0); - - if (FD_ISSET(0, &readfds)) { - n = read(0, buf, 8192); - if (n <= 0) - slirp_exit(0); - n = writen(s, buf, n); - if (n <= 0) - slirp_exit(0); - } - - if (FD_ISSET(s, &readfds)) { - n = read(s, buf, 8192); - if (n <= 0) - slirp_exit(0); - n = writen(0, buf, n); - if (n <= 0) - slirp_exit(0); - } - } - - /* Just in case.... */ - exit(1); + return -1; +} + +static int slirp_socketpair_with_oob(int sv[2]) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = 0, + .sin_addr.s_addr = INADDR_ANY, + }; + socklen_t addrlen = sizeof(addr); + int ret, s; + + sv[1] = -1; + s = slirp_socket(AF_INET, SOCK_STREAM, 0); + if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || + listen(s, 1) < 0 || + getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) { + goto err; + } + + sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0); + if (sv[1] < 0) { + goto err; + } + /* + * This connect won't block because we've already listen()ed on + * the server end (even though we won't accept() the connection + * until later on). + */ + do { + ret = connect(sv[1], (struct sockaddr *)&addr, addrlen); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + goto err; + } + + do { + sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen); + } while (sv[0] < 0 && errno == EINTR); + if (sv[0] < 0) { + goto err; + } + + closesocket(s); + return 0; + +err: + g_critical("slirp_socketpair(): %s", strerror(errno)); + if (s >= 0) { + closesocket(s); + } + if (sv[1] >= 0) { + closesocket(sv[1]); + } + return -1; +} + +static void fork_exec_child_setup(gpointer data) +{ +#ifndef _WIN32 + setsid(); +#endif +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#if !GLIB_CHECK_VERSION(2, 58, 0) +typedef struct SlirpGSpawnFds { + GSpawnChildSetupFunc child_setup; + gpointer user_data; + gint stdin_fd; + gint stdout_fd; + gint stderr_fd; +} SlirpGSpawnFds; + +static inline void slirp_gspawn_fds_setup(gpointer user_data) +{ + SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data; + + dup2(q->stdin_fd, 0); + dup2(q->stdout_fd, 1); + dup2(q->stderr_fd, 2); + q->child_setup(q->user_data); } #endif -int (*lprint_print) _P((void *, const char *, va_list)); -char *lprint_ptr, *lprint_ptr2, **lprint_arg; - -#ifdef _MSC_VER //aren't we -#define __STDC__ -#endif - -void -#ifdef __STDC__ -lprint(const char *format, ...) +static inline gboolean +g_spawn_async_with_fds_slirp(const gchar *working_directory, gchar **argv, + gchar **envp, GSpawnFlags flags, + GSpawnChildSetupFunc child_setup, + gpointer user_data, GPid *child_pid, gint stdin_fd, + gint stdout_fd, gint stderr_fd, GError **error) +{ +#if GLIB_CHECK_VERSION(2, 58, 0) + return g_spawn_async_with_fds(working_directory, argv, envp, flags, + child_setup, user_data, child_pid, stdin_fd, + stdout_fd, stderr_fd, error); #else -lprint(va_alist) va_dcl + SlirpGSpawnFds setup = { + .child_setup = child_setup, + .user_data = user_data, + .stdin_fd = stdin_fd, + .stdout_fd = stdout_fd, + .stderr_fd = stderr_fd, + }; + + return g_spawn_async(working_directory, argv, envp, flags, + slirp_gspawn_fds_setup, &setup, child_pid, error); #endif +} + +#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \ + g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) + +#pragma GCC diagnostic pop + +int fork_exec(struct socket *so, const char *ex) { - va_list args; - -#ifdef __STDC__ - va_start(args, format); + GError *err = NULL; + gint argc = 0; + gchar **argv = NULL; + int opt, sp[2]; + + DEBUG_CALL("fork_exec"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("ex = %p", ex); + + if (slirp_socketpair_with_oob(sp) < 0) { + return 0; + } + + if (!g_shell_parse_argv(ex, &argc, &argv, &err)) { + g_critical("fork_exec invalid command: %s\nerror: %s", ex, err->message); + g_error_free(err); + return 0; + } + + g_spawn_async_with_fds(NULL /* cwd */, argv, NULL /* env */, + G_SPAWN_SEARCH_PATH, fork_exec_child_setup, + NULL /* data */, NULL /* child_pid */, sp[1], sp[1], + sp[1], &err); + g_strfreev(argv); + + if (err) { + g_critical("fork_exec: %s", err->message); + g_error_free(err); + closesocket(sp[0]); + closesocket(sp[1]); + return 0; + } + + so->s = sp[0]; + closesocket(sp[1]); + slirp_socket_set_fast_reuse(so->s); + opt = 1; + setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); + slirp_set_nonblock(so->s); + so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); + return 1; +} + +int open_unix(struct socket *so, const char *unixpath) +{ +#ifdef G_OS_UNIX + struct sockaddr_un sa; + int s; + + DEBUG_CALL("open_unix"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("unixpath = %s", unixpath); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + if (g_strlcpy(sa.sun_path, unixpath, sizeof(sa.sun_path)) >= sizeof(sa.sun_path)) { + g_critical("Bad unix path: %s", unixpath); + return 0; + } + + s = slirp_socket(PF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + g_critical("open_unix(): %s", strerror(errno)); + return 0; + } + + if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + g_critical("open_unix(): %s", strerror(errno)); + closesocket(s); + return 0; + } + + so->s = s; + slirp_set_nonblock(so->s); + so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); + + return 1; #else - char *format; - va_start(args); - format = va_arg(args, char *); -#endif -#if 0 - /* If we're printing to an sbuf, make sure there's enough room */ - /* XXX +100? */ - if (lprint_sb) { - if ((lprint_ptr - lprint_sb->sb_wptr) >= - (lprint_sb->sb_datalen - (strlen(format) + 100))) { - int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; - int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; - int deltap = lprint_ptr - lprint_sb->sb_data; - - lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, - lprint_sb->sb_datalen + TCP_SNDSPACE); - - /* Adjust all values */ - lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; - lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; - lprint_ptr = lprint_sb->sb_data + deltap; - - lprint_sb->sb_datalen += TCP_SNDSPACE; - } - } -#endif - if (lprint_print) - lprint_ptr += (*lprint_print)(*lprint_arg, format, args); - - /* Check if they want output to be logged to file as well */ - if (lfd) { - /* - * Remove \r's - * otherwise you'll get ^M all over the file - */ - int len = strlen(format); - char *bptr1, *bptr2; - - bptr1 = bptr2 = strdup(format); - - while (len--) { - if (*bptr1 == '\r') - memcpy(bptr1, bptr1+1, len+1); - else - bptr1++; - } - vfprintf(lfd, bptr2, args); - free(bptr2); - } - va_end(args); -} - -void -add_emu(buff) - char *buff; -{ - u_int lport, fport; - u_int8_t tos = 0, emu = 0; - char buff1[256], buff2[256], buff4[128]; - char *buff3 = buff4; - struct emu_t *emup; - struct SLIRPsocket *so; - - if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { - lprint("Error: Bad arguments\r\n"); - return; - } - - if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { - lport = 0; - if (sscanf(buff1, "%d", &fport) != 1) { - lprint("Error: Bad first argument\r\n"); - return; - } - } - - if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { - buff3 = 0; - if (sscanf(buff2, "%256s", buff1) != 1) { - lprint("Error: Bad second argument\r\n"); - return; - } - } - - if (buff3) { - if (strcmp(buff3, "lowdelay") == 0) - tos = IPTOS_LOWDELAY; - else if (strcmp(buff3, "throughput") == 0) - tos = IPTOS_THROUGHPUT; - else { - lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); - return; - } - } - - if (strcmp(buff1, "ftp") == 0) - emu = EMU_FTP; - else if (strcmp(buff1, "irc") == 0) - emu = EMU_IRC; - else if (strcmp(buff1, "none") == 0) - emu = EMU_NONE; /* ie: no emulation */ - else { - lprint("Error: Unknown service\r\n"); - return; - } - - /* First, check that it isn't already emulated */ - for (emup = tcpemu; emup; emup = emup->next) { - if (emup->lport == lport && emup->fport == fport) { - lprint("Error: port already emulated\r\n"); - return; - } - } - - /* link it */ - emup = (struct emu_t *)malloc(sizeof (struct emu_t)); - emup->lport = (u_int16_t)lport; - emup->fport = (u_int16_t)fport; - emup->tos = tos; - emup->emu = emu; - emup->next = tcpemu; - tcpemu = emup; - - /* And finally, mark all current sessions, if any, as being emulated */ - for (so = tcb.so_next; so != &tcb; so = so->so_next) { - if ((lport && lport == ntohs(so->so_lport)) || - (fport && fport == ntohs(so->so_fport))) { - if (emu) - so->so_emu = emu; - if (tos) - so->so_iptos = tos; - } - } - - lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); -} - -#ifdef BAD_SPRINTF - -#undef vsprintf -#undef sprintf - -/* - * Some BSD-derived systems have a sprintf which returns char * - */ - -int -vsprintf_len(string, format, args) - char *string; - const char *format; - va_list args; -{ - vsprintf(string, format, args); - return strlen(string); -} - -int -#ifdef __STDC__ -sprintf_len(char *string, const char *format, ...) -#else -sprintf_len(va_alist) va_dcl -#endif -{ - va_list args; -#ifdef __STDC__ - va_start(args, format); -#else - char *string; - char *format; - va_start(args); - string = va_arg(args, char *); - format = va_arg(args, char *); -#endif - vsprintf(string, format, args); - return strlen(string); -} - -#endif - -void -u_sleep(usec) - int usec; -{ - struct timeval t; - fd_set fdset; - - FD_ZERO(&fdset); - - t.tv_sec = 0; - t.tv_usec = usec * 1000; - - select(0, &fdset, &fdset, &fdset, &t); -} - -/* - * Set fd blocking and non-blocking - */ - -void -fd_nonblock(fd) - int fd; -{ -#if defined USE_FIONBIO && defined FIONBIO - ioctlsockopt_t opt = 1; - - ioctlsocket(fd, FIONBIO, &opt); -#else - int opt; - - opt = fcntl(fd, F_GETFL, 0); - opt |= O_NONBLOCK; - fcntl(fd, F_SETFL, opt); + g_assert_not_reached(); #endif } -void -fd_block(fd) - int fd; +char *slirp_connection_info(Slirp *slirp) { -#if defined USE_FIONBIO && defined FIONBIO - ioctlsockopt_t opt = 0; - - ioctlsocket(fd, FIONBIO, &opt); -#else - int opt; - - opt = fcntl(fd, F_GETFL, 0); - opt &= ~O_NONBLOCK; - fcntl(fd, F_SETFL, opt); -#endif -} + GString *str = g_string_new(NULL); + const char *const tcpstates[] = { + [TCPS_CLOSED] = "CLOSED", [TCPS_LISTEN] = "LISTEN", + [TCPS_SYN_SENT] = "SYN_SENT", [TCPS_SYN_RECEIVED] = "SYN_RCVD", + [TCPS_ESTABLISHED] = "ESTABLISHED", [TCPS_CLOSE_WAIT] = "CLOSE_WAIT", + [TCPS_FIN_WAIT_1] = "FIN_WAIT_1", [TCPS_CLOSING] = "CLOSING", + [TCPS_LAST_ACK] = "LAST_ACK", [TCPS_FIN_WAIT_2] = "FIN_WAIT_2", + [TCPS_TIME_WAIT] = "TIME_WAIT", + }; + struct in_addr dst_addr; + struct sockaddr_in src; + socklen_t src_len; + uint16_t dst_port; + struct socket *so; + const char *state; + char buf[20]; + g_string_append_printf(str, + " Protocol[State] FD Source Address Port " + "Dest. Address Port RecvQ SendQ\n"); -#if 0 -/* - * invoke RSH - */ -int -rsh_exec(so,ns, user, host, args) - struct SLIRPsocket *so; - struct SLIRPsocket *ns; - char *user; - char *host; - char *args; -{ - int fd[2]; - int fd0[2]; - int s; - char buff[256]; - - DEBUG_CALL("rsh_exec"); - DEBUG_ARG("so = %lx", (long)so); - - if (pipe(fd)<0) { - lprint("Error: pipe failed: %s\n", strerror(errno)); - return 0; - } -/* #ifdef HAVE_SOCKETPAIR */ -#if 1 - if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { - close(fd[0]); - close(fd[1]); - lprint("Error: openpty failed: %s\n", strerror(errno)); - return 0; + /* TODO: IPv6 */ + + for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { + if (so->so_state & SS_HOSTFWD) { + state = "HOST_FORWARD"; + } else if (so->so_tcpcb) { + state = tcpstates[so->so_tcpcb->t_state]; + } else { + state = "NONE"; } -#else - if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { - close(fd[0]); - close(fd[1]); - lprint("Error: openpty failed: %s\n", strerror(errno)); - return 0; + if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) { + src_len = sizeof(src); + getsockname(so->s, (struct sockaddr *)&src, &src_len); + dst_addr = so->so_laddr; + dst_port = so->so_lport; + } else { + src.sin_addr = so->so_laddr; + src.sin_port = so->so_lport; + dst_addr = so->so_faddr; + dst_port = so->so_fport; } -#endif - - switch(fork()) { - case -1: - lprint("Error: fork failed: %s\n", strerror(errno)); - close(fd[0]); - close(fd[1]); - close(fd0[0]); - close(fd0[1]); - return 0; - - case 0: - close(fd[0]); - close(fd0[0]); - - /* Set the DISPLAY */ - if (x_port >= 0) { -#ifdef HAVE_SETENV - sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); - setenv("DISPLAY", buff, 1); -#else - sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); - putenv(buff); -#endif - } - - dup2(fd0[1], 0); - dup2(fd0[1], 1); - dup2(fd[1], 2); - for (s = 3; s <= 255; s++) - close(s); - - execlp("rsh","rsh","-l", user, host, args, NULL); - - /* Ooops, failed, let's tell the user why */ - - sprintf(buff, "Error: execlp of %s failed: %s\n", - "rsh", strerror(errno)); - write(2, buff, strlen(buff)+1); - close(0); close(1); close(2); /* XXX */ - exit(1); - - default: - close(fd[1]); - close(fd0[1]); - ns->s=fd[0]; - so->s=fd0[0]; - - return 1; - } + slirp_fmt0(buf, sizeof(buf), " TCP[%s]", state); + g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s, + src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : + "*", + ntohs(src.sin_port)); + g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr), + ntohs(dst_port), so->so_rcv.sb_cc, + so->so_snd.sb_cc); + } + + for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) { + if (so->so_state & SS_HOSTFWD) { + slirp_fmt0(buf, sizeof(buf), " UDP[HOST_FORWARD]"); + src_len = sizeof(src); + getsockname(so->s, (struct sockaddr *)&src, &src_len); + dst_addr = so->so_laddr; + dst_port = so->so_lport; + } else { + slirp_fmt0(buf, sizeof(buf), " UDP[%d sec]", + (so->so_expire - curtime) / 1000); + src.sin_addr = so->so_laddr; + src.sin_port = so->so_lport; + dst_addr = so->so_faddr; + dst_port = so->so_fport; + } + g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s, + src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : + "*", + ntohs(src.sin_port)); + g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr), + ntohs(dst_port), so->so_rcv.sb_cc, + so->so_snd.sb_cc); + } + + for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) { + slirp_fmt0(buf, sizeof(buf), " ICMP[%d sec]", + (so->so_expire - curtime) / 1000); + src.sin_addr = so->so_laddr; + dst_addr = so->so_faddr; + g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s, + src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : + "*"); + g_string_append_printf(str, "%15s - %5d %5d\n", inet_ntoa(dst_addr), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } + + return g_string_free(str, false); +} + +int slirp_bind_outbound(struct socket *so, unsigned short af) +{ + int ret = 0; + struct sockaddr *addr = NULL; + int addr_size = 0; + + if (af == AF_INET && so->slirp->outbound_addr != NULL) { + addr = (struct sockaddr *)so->slirp->outbound_addr; + addr_size = sizeof(struct sockaddr_in); + } else if (af == AF_INET6 && so->slirp->outbound_addr6 != NULL) { + addr = (struct sockaddr *)so->slirp->outbound_addr6; + addr_size = sizeof(struct sockaddr_in6); + } + + if (addr != NULL) { + ret = bind(so->s, addr, addr_size); + } + return ret; } -#endif diff --git a/src/network/slirp/misc.h b/src/network/slirp/misc.h index c509deb92..81b370cfb 100644 --- a/src/network/slirp/misc.h +++ b/src/network/slirp/misc.h @@ -1,34 +1,23 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#ifndef _MISC_H_ -#define _MISC_H_ +#ifndef MISC_H +#define MISC_H -struct ex_list { - int ex_pty; /* Do we want a pty? */ - int ex_addr; /* The last byte of the address */ - int ex_fport; /* Port to telnet to */ - char *ex_exec; /* Command line of what to exec */ - struct ex_list *ex_next; +#include "libslirp.h" + +struct gfwd_list { + SlirpWriteCb write_cb; + void *opaque; + struct in_addr ex_addr; /* Server address */ + int ex_fport; /* Port to telnet to */ + char *ex_exec; /* Command line of what to exec */ + char *ex_unix; /* unix socket */ + struct gfwd_list *ex_next; }; -extern struct ex_list *exec_list; -extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; - -extern int (*lprint_print) _P((void *, const char *, va_list)); -extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; -extern struct sbuf *lprint_sb; - -#ifndef HAVE_STRDUP -char *strdup _P((const char *)); -#endif - -void do_wait _P((int)); - #define EMU_NONE 0x0 /* TCP emulations */ @@ -39,49 +28,45 @@ void do_wait _P((int)); #define EMU_REALAUDIO 0x5 #define EMU_RLOGIN 0x6 #define EMU_IDENT 0x7 -#define EMU_RSH 0x8 -#define EMU_NOCONNECT 0x10 /* Don't connect */ - -/* UDP emulations */ -#define EMU_TALK 0x1 -#define EMU_NTALK 0x2 -#define EMU_CUSEEME 0x3 +#define EMU_NOCONNECT 0x10 /* Don't connect */ struct tos_t { - u_int16_t lport; - u_int16_t fport; - u_int8_t tos; - u_int8_t emu; + uint16_t lport; + uint16_t fport; + uint8_t tos; + uint8_t emu; }; struct emu_t { - u_int16_t lport; - u_int16_t fport; - u_int8_t tos; - u_int8_t emu; - struct emu_t *next; + uint16_t lport; + uint16_t fport; + uint8_t tos; + uint8_t emu; + struct emu_t *next; }; -extern struct emu_t *tcpemu; +struct slirp_quehead { + struct slirp_quehead *qh_link; + struct slirp_quehead *qh_rlink; +}; -extern int x_port, x_server, x_display; +void slirp_insque(void *, void *); +void slirp_remque(void *); +int fork_exec(struct socket *so, const char *ex); +int open_unix(struct socket *so, const char *unixsock); -int show_x _P((char *, struct SLIRPsocket *)); -void redir_x _P((u_int32_t, int, int, int)); -void getouraddr _P((void)); -void slirp_insque _P((void *, void *)); -void slirp_remque _P((void *)); -int add_exec _P((struct ex_list **, int, char *, int, int)); -int slirp_openpty _P((int *, int *)); -int fork_exec _P((struct SLIRPsocket *, char *, int)); -void snooze_hup _P((int)); -void snooze _P((void)); -void relay _P((int)); -void add_emu _P((char *)); -void u_sleep _P((int)); -void fd_nonblock _P((int)); -void fd_block _P((int)); -int rsh_exec _P((struct SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *)); +struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb, + void *opaque, struct in_addr addr, int port); + +struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline, + struct in_addr addr, int port); + +struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock, + struct in_addr addr, int port); + +int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port); + +int slirp_bind_outbound(struct socket *so, unsigned short af); #endif diff --git a/src/network/slirp/ncsi-pkt.h b/src/network/slirp/ncsi-pkt.h new file mode 100644 index 000000000..7795ad83e --- /dev/null +++ b/src/network/slirp/ncsi-pkt.h @@ -0,0 +1,445 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright Gavin Shan, IBM Corporation 2016. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NCSI_PKT_H +#define NCSI_PKT_H + +/* from linux/net/ncsi/ncsi-pkt.h */ +#define __be32 uint32_t +#define __be16 uint16_t + +struct ncsi_pkt_hdr { + unsigned char mc_id; /* Management controller ID */ + unsigned char revision; /* NCSI version - 0x01 */ + unsigned char reserved; /* Reserved */ + unsigned char id; /* Packet sequence number */ + unsigned char type; /* Packet type */ + unsigned char channel; /* Network controller ID */ + __be16 length; /* Payload length */ + __be32 reserved1[2]; /* Reserved */ +}; + +struct ncsi_cmd_pkt_hdr { + struct ncsi_pkt_hdr common; /* Common NCSI packet header */ +}; + +struct ncsi_rsp_pkt_hdr { + struct ncsi_pkt_hdr common; /* Common NCSI packet header */ + __be16 code; /* Response code */ + __be16 reason; /* Response reason */ +}; + +struct ncsi_aen_pkt_hdr { + struct ncsi_pkt_hdr common; /* Common NCSI packet header */ + unsigned char reserved2[3]; /* Reserved */ + unsigned char type; /* AEN packet type */ +}; + +/* NCSI common command packet */ +struct ncsi_cmd_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be32 checksum; /* Checksum */ + unsigned char pad[26]; +}; + +struct ncsi_rsp_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Select Package */ +struct ncsi_cmd_sp_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + unsigned char reserved[3]; /* Reserved */ + unsigned char hw_arbitration; /* HW arbitration */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Disable Channel */ +struct ncsi_cmd_dc_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + unsigned char reserved[3]; /* Reserved */ + unsigned char ald; /* Allow link down */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Reset Channel */ +struct ncsi_cmd_rc_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be32 reserved; /* Reserved */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* AEN Enable */ +struct ncsi_cmd_ae_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + unsigned char reserved[3]; /* Reserved */ + unsigned char mc_id; /* MC ID */ + __be32 mode; /* AEN working mode */ + __be32 checksum; /* Checksum */ + unsigned char pad[18]; +}; + +/* Set Link */ +struct ncsi_cmd_sl_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be32 mode; /* Link working mode */ + __be32 oem_mode; /* OEM link mode */ + __be32 checksum; /* Checksum */ + unsigned char pad[18]; +}; + +/* Set VLAN Filter */ +struct ncsi_cmd_svf_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be16 reserved; /* Reserved */ + __be16 vlan; /* VLAN ID */ + __be16 reserved1; /* Reserved */ + unsigned char index; /* VLAN table index */ + unsigned char enable; /* Enable or disable */ + __be32 checksum; /* Checksum */ + unsigned char pad[14]; +}; + +/* Enable VLAN */ +struct ncsi_cmd_ev_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + unsigned char reserved[3]; /* Reserved */ + unsigned char mode; /* VLAN filter mode */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Set MAC Address */ +struct ncsi_cmd_sma_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + unsigned char mac[6]; /* MAC address */ + unsigned char index; /* MAC table index */ + unsigned char at_e; /* Addr type and operation */ + __be32 checksum; /* Checksum */ + unsigned char pad[18]; +}; + +/* Enable Broadcast Filter */ +struct ncsi_cmd_ebf_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be32 mode; /* Filter mode */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Enable Global Multicast Filter */ +struct ncsi_cmd_egmf_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be32 mode; /* Global MC mode */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Set NCSI Flow Control */ +struct ncsi_cmd_snfc_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + unsigned char reserved[3]; /* Reserved */ + unsigned char mode; /* Flow control mode */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* Get Link Status */ +struct ncsi_rsp_gls_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 status; /* Link status */ + __be32 other; /* Other indications */ + __be32 oem_status; /* OEM link status */ + __be32 checksum; + unsigned char pad[10]; +}; + +/* Get Version ID */ +struct ncsi_rsp_gvi_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 ncsi_version; /* NCSI version */ + unsigned char reserved[3]; /* Reserved */ + unsigned char alpha2; /* NCSI version */ + unsigned char fw_name[12]; /* f/w name string */ + __be32 fw_version; /* f/w version */ + __be16 pci_ids[4]; /* PCI IDs */ + __be32 mf_id; /* Manufacture ID */ + __be32 checksum; +}; + +/* Get Capabilities */ +struct ncsi_rsp_gc_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 cap; /* Capabilities */ + __be32 bc_cap; /* Broadcast cap */ + __be32 mc_cap; /* Multicast cap */ + __be32 buf_cap; /* Buffering cap */ + __be32 aen_cap; /* AEN cap */ + unsigned char vlan_cnt; /* VLAN filter count */ + unsigned char mixed_cnt; /* Mix filter count */ + unsigned char mc_cnt; /* MC filter count */ + unsigned char uc_cnt; /* UC filter count */ + unsigned char reserved[2]; /* Reserved */ + unsigned char vlan_mode; /* VLAN mode */ + unsigned char channel_cnt; /* Channel count */ + __be32 checksum; /* Checksum */ +}; + +/* Get Parameters */ +struct ncsi_rsp_gp_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + unsigned char mac_cnt; /* Number of MAC addr */ + unsigned char reserved[2]; /* Reserved */ + unsigned char mac_enable; /* MAC addr enable flags */ + unsigned char vlan_cnt; /* VLAN tag count */ + unsigned char reserved1; /* Reserved */ + __be16 vlan_enable; /* VLAN tag enable flags */ + __be32 link_mode; /* Link setting */ + __be32 bc_mode; /* BC filter mode */ + __be32 valid_modes; /* Valid mode parameters */ + unsigned char vlan_mode; /* VLAN mode */ + unsigned char fc_mode; /* Flow control mode */ + unsigned char reserved2[2]; /* Reserved */ + __be32 aen_mode; /* AEN mode */ + unsigned char mac[6]; /* Supported MAC addr */ + __be16 vlan; /* Supported VLAN tags */ + __be32 checksum; /* Checksum */ +}; + +/* Get Controller Packet Statistics */ +struct ncsi_rsp_gcps_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 cnt_hi; /* Counter cleared */ + __be32 cnt_lo; /* Counter cleared */ + __be32 rx_bytes; /* Rx bytes */ + __be32 tx_bytes; /* Tx bytes */ + __be32 rx_uc_pkts; /* Rx UC packets */ + __be32 rx_mc_pkts; /* Rx MC packets */ + __be32 rx_bc_pkts; /* Rx BC packets */ + __be32 tx_uc_pkts; /* Tx UC packets */ + __be32 tx_mc_pkts; /* Tx MC packets */ + __be32 tx_bc_pkts; /* Tx BC packets */ + __be32 fcs_err; /* FCS errors */ + __be32 align_err; /* Alignment errors */ + __be32 false_carrier; /* False carrier detection */ + __be32 runt_pkts; /* Rx runt packets */ + __be32 jabber_pkts; /* Rx jabber packets */ + __be32 rx_pause_xon; /* Rx pause XON frames */ + __be32 rx_pause_xoff; /* Rx XOFF frames */ + __be32 tx_pause_xon; /* Tx XON frames */ + __be32 tx_pause_xoff; /* Tx XOFF frames */ + __be32 tx_s_collision; /* Single collision frames */ + __be32 tx_m_collision; /* Multiple collision frames */ + __be32 l_collision; /* Late collision frames */ + __be32 e_collision; /* Excessive collision frames */ + __be32 rx_ctl_frames; /* Rx control frames */ + __be32 rx_64_frames; /* Rx 64-bytes frames */ + __be32 rx_127_frames; /* Rx 65-127 bytes frames */ + __be32 rx_255_frames; /* Rx 128-255 bytes frames */ + __be32 rx_511_frames; /* Rx 256-511 bytes frames */ + __be32 rx_1023_frames; /* Rx 512-1023 bytes frames */ + __be32 rx_1522_frames; /* Rx 1024-1522 bytes frames */ + __be32 rx_9022_frames; /* Rx 1523-9022 bytes frames */ + __be32 tx_64_frames; /* Tx 64-bytes frames */ + __be32 tx_127_frames; /* Tx 65-127 bytes frames */ + __be32 tx_255_frames; /* Tx 128-255 bytes frames */ + __be32 tx_511_frames; /* Tx 256-511 bytes frames */ + __be32 tx_1023_frames; /* Tx 512-1023 bytes frames */ + __be32 tx_1522_frames; /* Tx 1024-1522 bytes frames */ + __be32 tx_9022_frames; /* Tx 1523-9022 bytes frames */ + __be32 rx_valid_bytes; /* Rx valid bytes */ + __be32 rx_runt_pkts; /* Rx error runt packets */ + __be32 rx_jabber_pkts; /* Rx error jabber packets */ + __be32 checksum; /* Checksum */ +}; + +/* Get NCSI Statistics */ +struct ncsi_rsp_gns_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 rx_cmds; /* Rx NCSI commands */ + __be32 dropped_cmds; /* Dropped commands */ + __be32 cmd_type_errs; /* Command type errors */ + __be32 cmd_csum_errs; /* Command checksum errors */ + __be32 rx_pkts; /* Rx NCSI packets */ + __be32 tx_pkts; /* Tx NCSI packets */ + __be32 tx_aen_pkts; /* Tx AEN packets */ + __be32 checksum; /* Checksum */ +}; + +/* Get NCSI Pass-through Statistics */ +struct ncsi_rsp_gnpts_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 tx_pkts; /* Tx packets */ + __be32 tx_dropped; /* Tx dropped packets */ + __be32 tx_channel_err; /* Tx channel errors */ + __be32 tx_us_err; /* Tx undersize errors */ + __be32 rx_pkts; /* Rx packets */ + __be32 rx_dropped; /* Rx dropped packets */ + __be32 rx_channel_err; /* Rx channel errors */ + __be32 rx_us_err; /* Rx undersize errors */ + __be32 rx_os_err; /* Rx oversize errors */ + __be32 checksum; /* Checksum */ +}; + +/* Get package status */ +struct ncsi_rsp_gps_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + __be32 status; /* Hardware arbitration status */ + __be32 checksum; +}; + +/* Get package UUID */ +struct ncsi_rsp_gpuuid_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Response header */ + unsigned char uuid[16]; /* UUID */ + __be32 checksum; +}; + +/* AEN: Link State Change */ +struct ncsi_aen_lsc_pkt { + struct ncsi_aen_pkt_hdr aen; /* AEN header */ + __be32 status; /* Link status */ + __be32 oem_status; /* OEM link status */ + __be32 checksum; /* Checksum */ + unsigned char pad[14]; +}; + +/* AEN: Configuration Required */ +struct ncsi_aen_cr_pkt { + struct ncsi_aen_pkt_hdr aen; /* AEN header */ + __be32 checksum; /* Checksum */ + unsigned char pad[22]; +}; + +/* AEN: Host Network Controller Driver Status Change */ +struct ncsi_aen_hncdsc_pkt { + struct ncsi_aen_pkt_hdr aen; /* AEN header */ + __be32 status; /* Status */ + __be32 checksum; /* Checksum */ + unsigned char pad[18]; +}; + +/* NCSI packet revision */ +#define NCSI_PKT_REVISION 0x01 + +/* NCSI packet commands */ +#define NCSI_PKT_CMD_CIS 0x00 /* Clear Initial State */ +#define NCSI_PKT_CMD_SP 0x01 /* Select Package */ +#define NCSI_PKT_CMD_DP 0x02 /* Deselect Package */ +#define NCSI_PKT_CMD_EC 0x03 /* Enable Channel */ +#define NCSI_PKT_CMD_DC 0x04 /* Disable Channel */ +#define NCSI_PKT_CMD_RC 0x05 /* Reset Channel */ +#define NCSI_PKT_CMD_ECNT 0x06 /* Enable Channel Network Tx */ +#define NCSI_PKT_CMD_DCNT 0x07 /* Disable Channel Network Tx */ +#define NCSI_PKT_CMD_AE 0x08 /* AEN Enable */ +#define NCSI_PKT_CMD_SL 0x09 /* Set Link */ +#define NCSI_PKT_CMD_GLS 0x0a /* Get Link */ +#define NCSI_PKT_CMD_SVF 0x0b /* Set VLAN Filter */ +#define NCSI_PKT_CMD_EV 0x0c /* Enable VLAN */ +#define NCSI_PKT_CMD_DV 0x0d /* Disable VLAN */ +#define NCSI_PKT_CMD_SMA 0x0e /* Set MAC address */ +#define NCSI_PKT_CMD_EBF 0x10 /* Enable Broadcast Filter */ +#define NCSI_PKT_CMD_DBF 0x11 /* Disable Broadcast Filter */ +#define NCSI_PKT_CMD_EGMF 0x12 /* Enable Global Multicast Filter */ +#define NCSI_PKT_CMD_DGMF 0x13 /* Disable Global Multicast Filter */ +#define NCSI_PKT_CMD_SNFC 0x14 /* Set NCSI Flow Control */ +#define NCSI_PKT_CMD_GVI 0x15 /* Get Version ID */ +#define NCSI_PKT_CMD_GC 0x16 /* Get Capabilities */ +#define NCSI_PKT_CMD_GP 0x17 /* Get Parameters */ +#define NCSI_PKT_CMD_GCPS 0x18 /* Get Controller Packet Statistics */ +#define NCSI_PKT_CMD_GNS 0x19 /* Get NCSI Statistics */ +#define NCSI_PKT_CMD_GNPTS 0x1a /* Get NCSI Pass-throu Statistics */ +#define NCSI_PKT_CMD_GPS 0x1b /* Get package status */ +#define NCSI_PKT_CMD_OEM 0x50 /* OEM */ +#define NCSI_PKT_CMD_PLDM 0x51 /* PLDM request over NCSI over RBT */ +#define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */ + +/* NCSI packet responses */ +#define NCSI_PKT_RSP_CIS (NCSI_PKT_CMD_CIS + 0x80) +#define NCSI_PKT_RSP_SP (NCSI_PKT_CMD_SP + 0x80) +#define NCSI_PKT_RSP_DP (NCSI_PKT_CMD_DP + 0x80) +#define NCSI_PKT_RSP_EC (NCSI_PKT_CMD_EC + 0x80) +#define NCSI_PKT_RSP_DC (NCSI_PKT_CMD_DC + 0x80) +#define NCSI_PKT_RSP_RC (NCSI_PKT_CMD_RC + 0x80) +#define NCSI_PKT_RSP_ECNT (NCSI_PKT_CMD_ECNT + 0x80) +#define NCSI_PKT_RSP_DCNT (NCSI_PKT_CMD_DCNT + 0x80) +#define NCSI_PKT_RSP_AE (NCSI_PKT_CMD_AE + 0x80) +#define NCSI_PKT_RSP_SL (NCSI_PKT_CMD_SL + 0x80) +#define NCSI_PKT_RSP_GLS (NCSI_PKT_CMD_GLS + 0x80) +#define NCSI_PKT_RSP_SVF (NCSI_PKT_CMD_SVF + 0x80) +#define NCSI_PKT_RSP_EV (NCSI_PKT_CMD_EV + 0x80) +#define NCSI_PKT_RSP_DV (NCSI_PKT_CMD_DV + 0x80) +#define NCSI_PKT_RSP_SMA (NCSI_PKT_CMD_SMA + 0x80) +#define NCSI_PKT_RSP_EBF (NCSI_PKT_CMD_EBF + 0x80) +#define NCSI_PKT_RSP_DBF (NCSI_PKT_CMD_DBF + 0x80) +#define NCSI_PKT_RSP_EGMF (NCSI_PKT_CMD_EGMF + 0x80) +#define NCSI_PKT_RSP_DGMF (NCSI_PKT_CMD_DGMF + 0x80) +#define NCSI_PKT_RSP_SNFC (NCSI_PKT_CMD_SNFC + 0x80) +#define NCSI_PKT_RSP_GVI (NCSI_PKT_CMD_GVI + 0x80) +#define NCSI_PKT_RSP_GC (NCSI_PKT_CMD_GC + 0x80) +#define NCSI_PKT_RSP_GP (NCSI_PKT_CMD_GP + 0x80) +#define NCSI_PKT_RSP_GCPS (NCSI_PKT_CMD_GCPS + 0x80) +#define NCSI_PKT_RSP_GNS (NCSI_PKT_CMD_GNS + 0x80) +#define NCSI_PKT_RSP_GNPTS (NCSI_PKT_CMD_GNPTS + 0x80) +#define NCSI_PKT_RSP_GPS (NCSI_PKT_CMD_GPS + 0x80) +#define NCSI_PKT_RSP_OEM (NCSI_PKT_CMD_OEM + 0x80) +#define NCSI_PKT_RSP_PLDM (NCSI_PKT_CMD_PLDM + 0x80) +#define NCSI_PKT_RSP_GPUUID (NCSI_PKT_CMD_GPUUID + 0x80) + +/* NCSI response code/reason */ +#define NCSI_PKT_RSP_C_COMPLETED 0x0000 /* Command Completed */ +#define NCSI_PKT_RSP_C_FAILED 0x0001 /* Command Failed */ +#define NCSI_PKT_RSP_C_UNAVAILABLE 0x0002 /* Command Unavailable */ +#define NCSI_PKT_RSP_C_UNSUPPORTED 0x0003 /* Command Unsupported */ +#define NCSI_PKT_RSP_R_NO_ERROR 0x0000 /* No Error */ +#define NCSI_PKT_RSP_R_INTERFACE 0x0001 /* Interface not ready */ +#define NCSI_PKT_RSP_R_PARAM 0x0002 /* Invalid Parameter */ +#define NCSI_PKT_RSP_R_CHANNEL 0x0003 /* Channel not Ready */ +#define NCSI_PKT_RSP_R_PACKAGE 0x0004 /* Package not Ready */ +#define NCSI_PKT_RSP_R_LENGTH 0x0005 /* Invalid payload length */ +#define NCSI_PKT_RSP_R_UNKNOWN 0x7fff /* Command type unsupported */ + +/* NCSI AEN packet type */ +#define NCSI_PKT_AEN 0xFF /* AEN Packet */ +#define NCSI_PKT_AEN_LSC 0x00 /* Link status change */ +#define NCSI_PKT_AEN_CR 0x01 /* Configuration required */ +#define NCSI_PKT_AEN_HNCDSC 0x02 /* HNC driver status change */ + +#endif /* NCSI_PKT_H */ diff --git a/src/network/slirp/ncsi.c b/src/network/slirp/ncsi.c new file mode 100644 index 000000000..3c1dfef1f --- /dev/null +++ b/src/network/slirp/ncsi.c @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * NC-SI (Network Controller Sideband Interface) "echo" model + * + * Copyright (C) 2016-2018 IBM Corp. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "slirp.h" + +#include "ncsi-pkt.h" + +static uint32_t ncsi_calculate_checksum(uint16_t *data, int len) +{ + uint32_t checksum = 0; + int i; + + /* + * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet + * payload interpreted as a series of 16-bit unsigned integer values. + */ + for (i = 0; i < len / 2; i++) { + checksum += htons(data[i]); + } + + checksum = (~checksum + 1); + return checksum; +} + +/* Get Capabilities */ +static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh) +{ + struct ncsi_rsp_gc_pkt *rsp = (struct ncsi_rsp_gc_pkt *)rnh; + + rsp->cap = htonl(~0); + rsp->bc_cap = htonl(~0); + rsp->mc_cap = htonl(~0); + rsp->buf_cap = htonl(~0); + rsp->aen_cap = htonl(~0); + rsp->vlan_mode = 0xff; + rsp->uc_cnt = 2; + return 0; +} + +/* Get Link status */ +static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh) +{ + struct ncsi_rsp_gls_pkt *rsp = (struct ncsi_rsp_gls_pkt *)rnh; + + rsp->status = htonl(0x1); + return 0; +} + +/* Get Parameters */ +static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh) +{ + struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *)rnh; + + /* no MAC address filters or VLAN filters on the channel */ + rsp->mac_cnt = 0; + rsp->mac_enable = 0; + rsp->vlan_cnt = 0; + rsp->vlan_enable = 0; + + return 0; +} + +static const struct ncsi_rsp_handler { + unsigned char type; + int payload; + int (*handler)(struct ncsi_rsp_pkt_hdr *rnh); +} ncsi_rsp_handlers[] = { { NCSI_PKT_RSP_CIS, 4, NULL }, + { NCSI_PKT_RSP_SP, 4, NULL }, + { NCSI_PKT_RSP_DP, 4, NULL }, + { NCSI_PKT_RSP_EC, 4, NULL }, + { NCSI_PKT_RSP_DC, 4, NULL }, + { NCSI_PKT_RSP_RC, 4, NULL }, + { NCSI_PKT_RSP_ECNT, 4, NULL }, + { NCSI_PKT_RSP_DCNT, 4, NULL }, + { NCSI_PKT_RSP_AE, 4, NULL }, + { NCSI_PKT_RSP_SL, 4, NULL }, + { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls }, + { NCSI_PKT_RSP_SVF, 4, NULL }, + { NCSI_PKT_RSP_EV, 4, NULL }, + { NCSI_PKT_RSP_DV, 4, NULL }, + { NCSI_PKT_RSP_SMA, 4, NULL }, + { NCSI_PKT_RSP_EBF, 4, NULL }, + { NCSI_PKT_RSP_DBF, 4, NULL }, + { NCSI_PKT_RSP_EGMF, 4, NULL }, + { NCSI_PKT_RSP_DGMF, 4, NULL }, + { NCSI_PKT_RSP_SNFC, 4, NULL }, + { NCSI_PKT_RSP_GVI, 40, NULL }, + { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc }, + { NCSI_PKT_RSP_GP, 40, ncsi_rsp_handler_gp }, + { NCSI_PKT_RSP_GCPS, 172, NULL }, + { NCSI_PKT_RSP_GNS, 172, NULL }, + { NCSI_PKT_RSP_GNPTS, 172, NULL }, + { NCSI_PKT_RSP_GPS, 8, NULL }, + { NCSI_PKT_RSP_OEM, 0, NULL }, + { NCSI_PKT_RSP_PLDM, 0, NULL }, + { NCSI_PKT_RSP_GPUUID, 20, NULL } }; + +/* + * packet format : ncsi header + payload + checksum + */ +#define NCSI_MAX_PAYLOAD 172 +#define NCSI_MAX_LEN (sizeof(struct ncsi_pkt_hdr) + NCSI_MAX_PAYLOAD + 4) + +void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) +{ + const struct ncsi_pkt_hdr *nh = + (const struct ncsi_pkt_hdr *)(pkt + ETH_HLEN); + uint8_t ncsi_reply[ETH_HLEN + NCSI_MAX_LEN]; + struct ethhdr *reh = (struct ethhdr *)ncsi_reply; + struct ncsi_rsp_pkt_hdr *rnh = + (struct ncsi_rsp_pkt_hdr *)(ncsi_reply + ETH_HLEN); + const struct ncsi_rsp_handler *handler = NULL; + int i; + int ncsi_rsp_len = sizeof(*nh); + uint32_t checksum; + uint32_t *pchecksum; + + memset(ncsi_reply, 0, sizeof(ncsi_reply)); + + memset(reh->h_dest, 0xff, ETH_ALEN); + memset(reh->h_source, 0xff, ETH_ALEN); + reh->h_proto = htons(ETH_P_NCSI); + + for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) { + if (ncsi_rsp_handlers[i].type == nh->type + 0x80) { + handler = &ncsi_rsp_handlers[i]; + break; + } + } + + rnh->common.mc_id = nh->mc_id; + rnh->common.revision = NCSI_PKT_REVISION; + rnh->common.id = nh->id; + rnh->common.type = nh->type + 0x80; + rnh->common.channel = nh->channel; + + if (handler) { + rnh->common.length = htons(handler->payload); + rnh->code = htons(NCSI_PKT_RSP_C_COMPLETED); + rnh->reason = htons(NCSI_PKT_RSP_R_NO_ERROR); + + if (handler->handler) { + /* TODO: handle errors */ + handler->handler(rnh); + } + ncsi_rsp_len += handler->payload; + } else { + rnh->common.length = 0; + rnh->code = htons(NCSI_PKT_RSP_C_UNAVAILABLE); + rnh->reason = htons(NCSI_PKT_RSP_R_UNKNOWN); + } + + /* Add the optional checksum at the end of the frame. */ + checksum = ncsi_calculate_checksum((uint16_t *)rnh, ncsi_rsp_len); + pchecksum = (uint32_t *)((void *)rnh + ncsi_rsp_len); + *pchecksum = htonl(checksum); + ncsi_rsp_len += 4; + + slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len); +} diff --git a/src/network/slirp/ndp_table.c b/src/network/slirp/ndp_table.c new file mode 100644 index 000000000..110d6ea0e --- /dev/null +++ b/src/network/slirp/ndp_table.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne. + */ + +#include "slirp.h" + +void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr, + uint8_t ethaddr[ETH_ALEN]) +{ + char addrstr[INET6_ADDRSTRLEN]; + NdpTable *ndp_table = &slirp->ndp_table; + int i; + + inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN); + + DEBUG_CALL("ndp_table_add"); + DEBUG_ARG("ip = %s", addrstr); + DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1], + ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]); + + if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) { + /* Do not register multicast or unspecified addresses */ + DEBUG_CALL(" abort: do not register multicast or unspecified address"); + return; + } + + /* Search for an entry */ + for (i = 0; i < NDP_TABLE_SIZE; i++) { + if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) { + DEBUG_CALL(" already in table: update the entry"); + /* Update the entry */ + memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN); + return; + } + } + + /* No entry found, create a new one */ + DEBUG_CALL(" create new entry"); + ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr; + memcpy(ndp_table->table[ndp_table->next_victim].eth_addr, ethaddr, + ETH_ALEN); + ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE; +} + +bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr, + uint8_t out_ethaddr[ETH_ALEN]) +{ + char addrstr[INET6_ADDRSTRLEN]; + NdpTable *ndp_table = &slirp->ndp_table; + int i; + + inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN); + + DEBUG_CALL("ndp_table_search"); + DEBUG_ARG("ip = %s", addrstr); + + assert(!in6_zero(&ip_addr)); + + /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */ + if (IN6_IS_ADDR_MULTICAST(&ip_addr)) { + out_ethaddr[0] = 0x33; + out_ethaddr[1] = 0x33; + out_ethaddr[2] = ip_addr.s6_addr[12]; + out_ethaddr[3] = ip_addr.s6_addr[13]; + out_ethaddr[4] = ip_addr.s6_addr[14]; + out_ethaddr[5] = ip_addr.s6_addr[15]; + DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x", + out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], + out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); + return 1; + } + + for (i = 0; i < NDP_TABLE_SIZE; i++) { + if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) { + memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN); + DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x", + out_ethaddr[0], out_ethaddr[1], out_ethaddr[2], + out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]); + return 1; + } + } + + DEBUG_CALL(" ip not found in table"); + return 0; +} diff --git a/src/network/slirp/queue.c b/src/network/slirp/queue.c deleted file mode 100644 index d91004ad4..000000000 --- a/src/network/slirp/queue.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * File: queue.c - * Author: Robert I. Pitts - * Last Modified: March 9, 2000 - * Topic: Queue - Array Implementation - * ---------------------------------------------------------------- - */ - -#include -#include -#include "queue.h" - -/* - * Constants - * --------- - * MAX_QUEUE_SIZE = Largest number of items queue can hold. - */ - -#define MAX_QUEUE_SIZE 100 - -/* - * struct queueCDT gives the implementation of a queue. - * It holds the information that we need for each queue. - */ -typedef struct queueCDT { - queueElementT contents[MAX_QUEUE_SIZE]; - int front; - int count; -} queueCDT; - -queueADT QueueCreate(void) -{ - queueADT queue; - - queue = (queueADT)malloc(sizeof(queueCDT)); - - if (queue == NULL) { - fprintf(stderr, "Insufficient Memory for new Queue.\n"); - exit(ERROR_MEMORY); /* Exit program, returning error code. */ - } - - queue->front = 0; - queue->count = 0; - - return queue; -} - -void QueueDestroy(queueADT queue) -{ - free(queue); -} - -void QueueEnter(queueADT queue, queueElementT element) -{ - int newElementIndex; - - if (queue->count >= MAX_QUEUE_SIZE) { -// fprintf(stderr, "QueueEnter on Full Queue.\n"); -// exit(ERROR_QUEUE); /* Exit program, returning error code. */ - return; - } - - /* - * Calculate index at which to put - * next element. - */ - newElementIndex = (queue->front + queue->count) - % MAX_QUEUE_SIZE; - queue->contents[newElementIndex] = element; -//printf("element %d, pointer to %d, [%s]\n",newElementIndex,element,element); - - queue->count++; -} - -int QueuePeek(queueADT queue) -{ -return queue->count; -} - -queueElementT QueueDelete(queueADT queue) -{ - queueElementT oldElement; - - if (queue->count <= 0) { - //fprintf(stderr, "QueueDelete on Empty Queue.\n"); - //exit(ERROR_QUEUE); /* Exit program, returning error code. */ - return NULL; - } - - /* Save the element so we can return it. */ - oldElement = queue->contents[queue->front]; - - /* - * Advance the index of the front, - * making sure it wraps around the - * array properly. - */ - queue->front++; - queue->front %= MAX_QUEUE_SIZE; - -//printf("dequing @%d [%s]\n",oldElement,oldElement); - - queue->count--; - - return oldElement; -} - -int QueueIsEmpty(queueADT queue) -{ - return queue->count <= 0; -} - -int QueueIsFull(queueADT queue) -{ - return queue->count >= MAX_QUEUE_SIZE; -} diff --git a/src/network/slirp/queue.h b/src/network/slirp/queue.h deleted file mode 100644 index 786950ab7..000000000 --- a/src/network/slirp/queue.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * File: queue.h - * Author: Robert I. Pitts - * Last Modified: March 9, 2000 - * Topic: Queue - Array Implementation - * ---------------------------------------------------------------- - */ - -#ifndef _QUEUE_H -#define _QUEUE_H - -/* - * Constants - * --------- - * ERROR_* These signal error conditions in queue functions - * and are used as exit codes for the program. - */ -#define ERROR_QUEUE 2 -#define ERROR_MEMORY 3 - -/* - * Type: queueElementT - * ------------------- - * This is the type of objects held in the queue. - */ - -/*typedef char queueElementT; -typedef unsigned char *queueElementT; -*/ - -struct queuepacket{ - int len; - unsigned char data[2000]; -}; -typedef struct queuepacket *queueElementT; - -/* - * Type: queueADT - * -------------- - * The actual implementation of a queue is completely - * hidden. Client will work with queueADT which is a - * pointer to underlying queueCDT. - */ - -/* - * NOTE: need word struct below so that the compiler - * knows at least that a queueCDT will be some sort - * of struct. - */ - -typedef struct queueCDT *queueADT; - -/* - * Function: QueueCreate - * Usage: queue = QueueCreate(); - * ------------------------- - * A new empty queue is created and returned. - */ - -queueADT QueueCreate(void); - -/* Function: QueueDestroy - * Usage: QueueDestroy(queue); - * ----------------------- - * This function frees all memory associated with - * the queue. "queue" may not be used again unless - * queue = QueueCreate() is called first. - */ - -void QueueDestroy(queueADT queue); - -/* - * Functions: QueueEnter, QueueDelete - * Usage: QueueEnter(queue, element); - * element = QueueDelete(queue); - * -------------------------------------------- - * These are the fundamental queue operations that enter - * elements in and delete elements from the queue. A call - * to QueueDelete() on an empty queue or to QueueEnter() - * on a full queue is an error. Make use of QueueIsFull() - * and QueueIsEmpty() (see below) to avoid these errors. - */ - -void QueueEnter(queueADT queue, queueElementT element); -queueElementT QueueDelete(queueADT queue); - - -/* - * Functions: QueueIsEmpty, QueueIsFull - * Usage: if (QueueIsEmpty(queue)) ... - * ----------------------------------- - * These return a true/false value based on whether - * the queue is empty or full, respectively. - */ - -int QueueIsEmpty(queueADT queue); -int QueueIsFull(queueADT queue); - -int QueuePeek(queueADT queue); - -#endif /* not defined _QUEUE_H */ diff --git a/src/network/slirp/sbuf.c b/src/network/slirp/sbuf.c index b9baa4181..2fb917614 100644 --- a/src/network/slirp/sbuf.c +++ b/src/network/slirp/sbuf.c @@ -1,69 +1,42 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#include #include "slirp.h" -/* Done as a macro in socket.h */ -/* int - * sbspace(struct sockbuff *sb) - * { - * return SB_DATALEN - sb->sb_cc; - * } - */ +static void sbappendsb(struct sbuf *sb, struct mbuf *m); -void -sbfree(sb) - struct sbuf *sb; +void sbfree(struct sbuf *sb) { - free(sb->sb_data); + g_free(sb->sb_data); } -void -sbdrop(sb, num) - struct sbuf *sb; - int num; +bool sbdrop(struct sbuf *sb, size_t num) { - /* - * We can only drop how much we have - * This should never succeed - */ - if(num > sb->sb_cc) - num = sb->sb_cc; - sb->sb_cc -= num; - sb->sb_rptr += num; - if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) - sb->sb_rptr -= sb->sb_datalen; - + int limit = sb->sb_datalen / 2; + + g_warn_if_fail(num <= sb->sb_cc); + if (num > sb->sb_cc) + num = sb->sb_cc; + + sb->sb_cc -= num; + sb->sb_rptr += num; + if (sb->sb_rptr >= sb->sb_data + sb->sb_datalen) + sb->sb_rptr -= sb->sb_datalen; + + if (sb->sb_cc < limit && sb->sb_cc + num >= limit) { + return true; + } + + return false; } -void -sbreserve(sb, size) - struct sbuf *sb; - int size; +void sbreserve(struct sbuf *sb, size_t size) { - if (sb->sb_data) { - /* Already alloced, realloc if necessary */ - if (sb->sb_datalen != size) { - sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); - sb->sb_cc = 0; - if (sb->sb_wptr) - sb->sb_datalen = size; - else - sb->sb_datalen = 0; - } - } else { - sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); - sb->sb_cc = 0; - if (sb->sb_wptr) - sb->sb_datalen = size; - else - sb->sb_datalen = 0; - } + sb->sb_wptr = sb->sb_rptr = sb->sb_data = g_realloc(sb->sb_data, size); + sb->sb_cc = 0; + sb->sb_datalen = size; } /* @@ -72,100 +45,97 @@ sbreserve(sb, size) * this prevents an unnecessary copy of the data * (the socket is non-blocking, so we won't hang) */ -void -sbappend(so, m) - struct SLIRPsocket *so; - struct SLIRPmbuf *m; +void sbappend(struct socket *so, struct mbuf *m) { - int ret = 0; - - DEBUG_CALL("sbappend"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("m->m_len = %d", m->m_len); - - /* Shouldn't happen, but... e.g. foreign host closes connection */ - if (m->m_len <= 0) { - m_free(m); - return; - } - - /* - * If there is urgent data, call sosendoob - * if not all was sent, sowrite will take care of the rest - * (The rest of this function is just an optimisation) - */ - if (so->so_urgc) { - sbappendsb(&so->so_rcv, m); - m_free(m); - sosendoob(so); - return; - } - - /* - * We only write if there's nothing in the buffer, - * ottherwise it'll arrive out of order, and hence corrupt - */ - if (!so->so_rcv.sb_cc) - ret = send(so->s, m->m_data, m->m_len, 0); - - if (ret <= 0) { - /* - * Nothing was written - * It's possible that the socket has closed, but - * we don't need to check because if it has closed, - * it will be detected in the normal way by soread() - */ - sbappendsb(&so->so_rcv, m); - } else if (ret != m->m_len) { - /* - * Something was written, but not everything.. - * sbappendsb the rest - */ - m->m_len -= ret; - m->m_data += ret; - sbappendsb(&so->so_rcv, m); - } /* else */ - /* Whatever happened, we free the SLIRPmbuf */ - m_free(m); + int ret = 0; + + DEBUG_CALL("sbappend"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("m->m_len = %d", m->m_len); + + /* Shouldn't happen, but... e.g. foreign host closes connection */ + if (m->m_len <= 0) { + m_free(m); + return; + } + + /* + * If there is urgent data, call sosendoob + * if not all was sent, sowrite will take care of the rest + * (The rest of this function is just an optimisation) + */ + if (so->so_urgc) { + sbappendsb(&so->so_rcv, m); + m_free(m); + (void)sosendoob(so); + return; + } + + /* + * We only write if there's nothing in the buffer, + * ottherwise it'll arrive out of order, and hence corrupt + */ + if (!so->so_rcv.sb_cc) + ret = slirp_send(so, m->m_data, m->m_len, 0); + + if (ret <= 0) { + /* + * Nothing was written + * It's possible that the socket has closed, but + * we don't need to check because if it has closed, + * it will be detected in the normal way by soread() + */ + sbappendsb(&so->so_rcv, m); + } else if (ret != m->m_len) { + /* + * Something was written, but not everything.. + * sbappendsb the rest + */ + m->m_len -= ret; + m->m_data += ret; + sbappendsb(&so->so_rcv, m); + } /* else */ + /* Whatever happened, we free the mbuf */ + m_free(m); } /* * Copy the data from m into sb * The caller is responsible to make sure there's enough room */ -void -sbappendsb(sb, m) - struct sbuf *sb; - struct SLIRPmbuf *m; +static void sbappendsb(struct sbuf *sb, struct mbuf *m) { - int len, n, nn; - - len = m->m_len; + int len, n, nn; - if (sb->sb_wptr < sb->sb_rptr) { - n = sb->sb_rptr - sb->sb_wptr; - if (n > len) n = len; - memcpy(sb->sb_wptr, m->m_data, n); - } else { - /* Do the right edge first */ - n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; - if (n > len) n = len; - memcpy(sb->sb_wptr, m->m_data, n); - len -= n; - if (len) { - /* Now the left edge */ - nn = sb->sb_rptr - sb->sb_data; - if (nn > len) nn = len; - memcpy(sb->sb_data,m->m_data+n,nn); - n += nn; - } - } + len = m->m_len; - sb->sb_cc += n; - sb->sb_wptr += n; - if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) - sb->sb_wptr -= sb->sb_datalen; + if (sb->sb_wptr < sb->sb_rptr) { + n = sb->sb_rptr - sb->sb_wptr; + if (n > len) + n = len; + memcpy(sb->sb_wptr, m->m_data, n); + } else { + /* Do the right edge first */ + n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; + if (n > len) + n = len; + memcpy(sb->sb_wptr, m->m_data, n); + len -= n; + if (len) { + /* Now the left edge */ + nn = sb->sb_rptr - sb->sb_data; + if (nn > len) + nn = len; + memcpy(sb->sb_data, m->m_data + n, nn); + n += nn; + } + } + + sb->sb_cc += n; + sb->sb_wptr += n; + if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) + sb->sb_wptr -= sb->sb_datalen; } /* @@ -173,30 +143,26 @@ sbappendsb(sb, m) * Don't update the sbuf rptr, this will be * done in sbdrop when the data is acked */ -void -sbcopy(sb, off, len, to) - struct sbuf *sb; - int off; - int len; - char *to; +void sbcopy(struct sbuf *sb, size_t off, size_t len, char *to) { - char *from; - - from = sb->sb_rptr + off; - if (from >= sb->sb_data + sb->sb_datalen) - from -= sb->sb_datalen; + char *from; - if (from < sb->sb_wptr) { - if (len > sb->sb_cc) len = sb->sb_cc; - memcpy(to,from,len); - } else { - /* re-use off */ - off = (sb->sb_data + sb->sb_datalen) - from; - if (off > len) off = len; - memcpy(to,from,off); - len -= off; - if (len) - memcpy(to+off,sb->sb_data,len); - } + g_assert(len + off <= sb->sb_cc); + + from = sb->sb_rptr + off; + if (from >= sb->sb_data + sb->sb_datalen) + from -= sb->sb_datalen; + + if (from < sb->sb_wptr) { + memcpy(to, from, len); + } else { + /* re-use off */ + off = (sb->sb_data + sb->sb_datalen) - from; + if (off > len) + off = len; + memcpy(to, from, off); + len -= off; + if (len) + memcpy(to + off, sb->sb_data, len); + } } - diff --git a/src/network/slirp/sbuf.h b/src/network/slirp/sbuf.h index aa4724df7..01886fbd0 100644 --- a/src/network/slirp/sbuf.h +++ b/src/network/slirp/sbuf.h @@ -1,31 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#ifndef _SBUF_H_ -#define _SBUF_H_ +#ifndef SBUF_H +#define SBUF_H -#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) struct sbuf { - u_int sb_cc; /* actual chars in buffer */ - u_int sb_datalen; /* Length of data */ - char *sb_wptr; /* write pointer. points to where the next - * bytes should be written in the sbuf */ - char *sb_rptr; /* read pointer. points to where the next - * byte should be read from the sbuf */ - char *sb_data; /* Actual data */ + uint32_t sb_cc; /* actual chars in buffer */ + uint32_t sb_datalen; /* Length of data */ + char *sb_wptr; /* write pointer. points to where the next + * bytes should be written in the sbuf */ + char *sb_rptr; /* read pointer. points to where the next + * byte should be read from the sbuf */ + char *sb_data; /* Actual data */ }; -void sbfree _P((struct sbuf *)); -void sbdrop _P((struct sbuf *, int)); -void sbreserve _P((struct sbuf *, int)); -void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *)); -void sbcopy _P((struct sbuf *, int, int, char *)); +void sbfree(struct sbuf *sb); +bool sbdrop(struct sbuf *sb, size_t len); +void sbreserve(struct sbuf *sb, size_t size); +void sbappend(struct socket *sb, struct mbuf *mb); +void sbcopy(struct sbuf *sb, size_t off, size_t len, char *p); #endif diff --git a/src/network/slirp/slirp.c b/src/network/slirp/slirp.c index 5ade8ae30..021324cdb 100644 --- a/src/network/slirp/slirp.c +++ b/src/network/slirp/slirp.c @@ -1,49 +1,87 @@ +/* SPDX-License-Identifier: MIT */ +/* + * libslirp glue + * + * Copyright (c) 2004-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "slirp.h" -/* Our actual addresses. */ -char slirp_hostname[33]; -struct in_addr our_addr; /* host IP address */ -struct in_addr dns_addr; /* host DNS server */ -struct in_addr loopback_addr; /* host loopback address */ +#ifndef _WIN32 +#include +#endif -/* Our SLiRP virtual addresses. */ -struct in_addr special_addr; /* virtual IP address */ -struct in_addr alias_addr; /* virtual address alias for host */ -const uint8_t special_ethaddr[6] = { - 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 /* virtual MAC address. */ -}; +/* https://gitlab.freedesktop.org/slirp/libslirp/issues/18 */ +#if defined(__NetBSD__) && defined(if_mtu) +#undef if_mtu +#endif -uint8_t client_ethaddr[6]; /* guest's MAC address */ +int slirp_debug; -int do_slowtimo; -int link_up; -struct timeval tt; -FILE *lfd; -struct ex_list *exec_list; +/* Define to 1 if you want KEEPALIVE timers */ +bool slirp_do_keepalive; -/* XXX: suppress those select globals */ -fd_set *global_readfds, *global_writefds, *global_xfds; +/* host loopback address */ +struct in_addr loopback_addr; +/* host loopback network mask */ +unsigned long loopback_mask; +/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */ +static const uint8_t special_ethaddr[ETH_ALEN] = { 0x52, 0x55, 0x00, + 0x00, 0x00, 0x00 }; -extern void pclog(const char *, ...); -extern int config_get_int(char *, char *, int); +unsigned curtime; -#define printf pclog +static struct in_addr dns_addr; +#ifndef _WIN32 +static struct in6_addr dns6_addr; +#endif +static unsigned dns_addr_time; +#ifndef _WIN32 +static unsigned dns6_addr_time; +#endif +#define TIMEOUT_FAST 2 /* milliseconds */ +#define TIMEOUT_SLOW 499 /* milliseconds */ +/* for the aging of certain requests like DNS */ +#define TIMEOUT_DEFAULT 1000 /* milliseconds */ #ifdef _WIN32 -static int get_dns_addr(struct in_addr *pdns_addr) + +int get_dns_addr(struct in_addr *pdns_addr) { - FIXED_INFO *FixedInfo=NULL; - ULONG BufLen; - DWORD ret; + FIXED_INFO *FixedInfo = NULL; + ULONG BufLen; + DWORD ret; IP_ADDR_STRING *pIPAddr; struct in_addr tmp_addr; - + + if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) { + *pdns_addr = dns_addr; + return 0; + } + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); BufLen = sizeof(FIXED_INFO); - + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { if (FixedInfo) { GlobalFree(FixedInfo); @@ -51,24 +89,21 @@ static int get_dns_addr(struct in_addr *pdns_addr) } FixedInfo = GlobalAlloc(GPTR, BufLen); } - + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { - printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); + printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret); if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; } return -1; } - + pIPAddr = &(FixedInfo->DnsServerList); inet_aton(pIPAddr->IpAddress.String, &tmp_addr); *pdns_addr = tmp_addr; - printf( " DNS Servers:\n" ); - while ( pIPAddr ) { - printf( " Address: %s\n", pIPAddr ->IpAddress.String ); - pIPAddr = pIPAddr ->Next; - } + dns_addr = tmp_addr; + dns_addr_time = curtime; if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; @@ -76,37 +111,91 @@ static int get_dns_addr(struct in_addr *pdns_addr) return 0; } +int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) +{ + return -1; +} + +static void winsock_cleanup(void) +{ + WSACleanup(); +} + #else -static int get_dns_addr(struct in_addr *pdns_addr) +static int get_dns_addr_cached(void *pdns_addr, void *cached_addr, + socklen_t addrlen, struct stat *cached_stat, + unsigned *cached_time) +{ + struct stat old_stat; + if (curtime - *cached_time < TIMEOUT_DEFAULT) { + memcpy(pdns_addr, cached_addr, addrlen); + return 0; + } + old_stat = *cached_stat; + if (stat("/etc/resolv.conf", cached_stat) != 0) { + return -1; + } + if (cached_stat->st_dev == old_stat.st_dev && + cached_stat->st_ino == old_stat.st_ino && + cached_stat->st_size == old_stat.st_size && + cached_stat->st_mtime == old_stat.st_mtime) { + memcpy(pdns_addr, cached_addr, addrlen); + return 0; + } + return 1; +} + +static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr, + socklen_t addrlen, uint32_t *scope_id, + unsigned *cached_time) { char buff[512]; - char buff2[256]; + char buff2[257]; FILE *f; int found = 0; - struct in_addr tmp_addr; - + void *tmp_addr = alloca(addrlen); + unsigned if_index; + f = fopen("/etc/resolv.conf", "r"); if (!f) return -1; - lprint("IP address of your DNS(s): "); + DEBUG_MISC("IP address of your DNS(s):"); while (fgets(buff, 512, f) != NULL) { if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { - if (!inet_aton(buff2, &tmp_addr)) + char *c = strchr(buff2, '%'); + if (c) { + if_index = if_nametoindex(c + 1); + *c = '\0'; + } else { + if_index = 0; + } + + if (!inet_pton(af, buff2, tmp_addr)) { continue; - if (tmp_addr.s_addr == loopback_addr.s_addr) - tmp_addr = our_addr; + } /* If it's the first one, set it to dns_addr */ - if (!found) - *pdns_addr = tmp_addr; - else - lprint(", "); + if (!found) { + memcpy(pdns_addr, tmp_addr, addrlen); + memcpy(cached_addr, tmp_addr, addrlen); + if (scope_id) { + *scope_id = if_index; + } + *cached_time = curtime; + } + if (++found > 3) { - lprint("(more)"); + DEBUG_MISC(" (more)"); break; - } else - lprint("%s", inet_ntoa(tmp_addr)); + } else if (slirp_debug & DBG_MISC) { + char s[INET6_ADDRSTRLEN]; + const char *res = inet_ntop(af, tmp_addr, s, sizeof(s)); + if (!res) { + res = " (string conversion error)"; + } + DEBUG_MISC(" %s", res); + } } } fclose(f); @@ -114,466 +203,596 @@ static int get_dns_addr(struct in_addr *pdns_addr) return -1; return 0; } -#endif - -#ifdef _WIN32 -void slirp_cleanup(void) +int get_dns_addr(struct in_addr *pdns_addr) { - WSACleanup(); -} -#endif + static struct stat dns_addr_stat; - -int -slirp_init(void) -{ - char* category = "SLiRP Port Forwarding"; - char key[32]; - struct in_addr myaddr; - int i = 0, udp, from, to; - int rc; - - pclog("%s initializing..\n", category); - -#ifdef SLIRP_DEBUG - // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); - // debug_init("slirplog.txt",DEBUG_DEFAULT); - //debug_init("slirplog.txt",DBG_CALL); -debug_init("slirplog.txt",DEBUG_DEFAULT); -#endif - -#ifdef _WIN32 - { - WSADATA Data; - WSAStartup(MAKEWORD(2,0), &Data); - atexit(slirp_cleanup); + if (dns_addr.s_addr != 0) { + int ret; + ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr), + &dns_addr_stat, &dns_addr_time); + if (ret <= 0) { + return ret; + } } + return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr, + sizeof(dns_addr), NULL, &dns_addr_time); +} + +int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) +{ + static struct stat dns6_addr_stat; + + if (!in6_zero(&dns6_addr)) { + int ret; + ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr), + &dns6_addr_stat, &dns6_addr_time); + if (ret <= 0) { + return ret; + } + } + return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr, + sizeof(dns6_addr), scope_id, + &dns6_addr_time); +} + #endif - link_up = 1; +static void slirp_init_once(void) +{ + static int initialized; + const char *debug; +#ifdef _WIN32 + WSADATA Data; +#endif - if_init(); - ip_init(); + if (initialized) { + return; + } + initialized = 1; - /* Initialise mbufs *after* setting the MTU */ - m_init(); +#ifdef _WIN32 + WSAStartup(MAKEWORD(2, 0), &Data); + atexit(winsock_cleanup); +#endif - /* set default addresses */ - inet_aton("127.0.0.1", &loopback_addr); + loopback_addr.s_addr = htonl(INADDR_LOOPBACK); + loopback_mask = htonl(IN_CLASSA_NET); - if (get_dns_addr(&dns_addr) < 0) - return -1; + debug = g_getenv("SLIRP_DEBUG"); + if (debug) { + const GDebugKey keys[] = { + { "call", DBG_CALL }, + { "misc", DBG_MISC }, + { "error", DBG_ERROR }, + { "tftp", DBG_TFTP }, + }; + slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys)); + } +} - inet_aton(CTL_SPECIAL, &special_addr); - alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); - getouraddr(); - inet_aton(CTL_LOCAL, &myaddr); +Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque) +{ + Slirp *slirp; - while (1) { - sprintf(key, "%d_udp", i); - udp = config_get_int(category, key, 0); - sprintf(key, "%d_from", i); - from = config_get_int(category, key, 0); - if (from < 1) - break; - sprintf(key, "%d_to", i); - to = config_get_int(category, key, from); + g_return_val_if_fail(cfg != NULL, NULL); + g_return_val_if_fail(cfg->version >= SLIRP_CONFIG_VERSION_MIN, NULL); + g_return_val_if_fail(cfg->version <= SLIRP_CONFIG_VERSION_MAX, NULL); + g_return_val_if_fail(cfg->if_mtu >= IF_MTU_MIN || cfg->if_mtu == 0, NULL); + g_return_val_if_fail(cfg->if_mtu <= IF_MTU_MAX, NULL); + g_return_val_if_fail(cfg->if_mru >= IF_MRU_MIN || cfg->if_mru == 0, NULL); + g_return_val_if_fail(cfg->if_mru <= IF_MRU_MAX, NULL); + g_return_val_if_fail(!cfg->bootfile || + (strlen(cfg->bootfile) < + G_SIZEOF_MEMBER(struct bootp_t, bp_file)), NULL); - rc = slirp_redir(udp, from, myaddr, to); - if (rc == 0) - pclog("slirp redir %d -> %d successful\n", from, to); - else - pclog("slirp redir %d -> %d failed (%d)\n", from, to, rc); + slirp = g_malloc0(sizeof(Slirp)); - i++; + slirp_init_once(); + + slirp->opaque = opaque; + slirp->cb = callbacks; + slirp->grand = g_rand_new(); + slirp->restricted = cfg->restricted; + + slirp->in_enabled = cfg->in_enabled; + slirp->in6_enabled = cfg->in6_enabled; + + if_init(slirp); + ip_init(slirp); + ip6_init(slirp); + + m_init(slirp); + + slirp->vnetwork_addr = cfg->vnetwork; + slirp->vnetwork_mask = cfg->vnetmask; + slirp->vhost_addr = cfg->vhost; + slirp->vprefix_addr6 = cfg->vprefix_addr6; + slirp->vprefix_len = cfg->vprefix_len; + slirp->vhost_addr6 = cfg->vhost6; + if (cfg->vhostname) { + slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname), + cfg->vhostname); + } + slirp->tftp_prefix = g_strdup(cfg->tftp_path); + slirp->bootp_filename = g_strdup(cfg->bootfile); + slirp->vdomainname = g_strdup(cfg->vdomainname); + slirp->vdhcp_startaddr = cfg->vdhcp_start; + slirp->vnameserver_addr = cfg->vnameserver; + slirp->vnameserver_addr6 = cfg->vnameserver6; + slirp->tftp_server_name = g_strdup(cfg->tftp_server_name); + + if (cfg->vdnssearch) { + translate_dnssearch(slirp, cfg->vdnssearch); + } + slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu; + slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru; + slirp->disable_host_loopback = cfg->disable_host_loopback; + slirp->enable_emu = cfg->enable_emu; + + if (cfg->version >= 2) { + slirp->outbound_addr = cfg->outbound_addr; + slirp->outbound_addr6 = cfg->outbound_addr6; + } else { + slirp->outbound_addr = NULL; + slirp->outbound_addr6 = NULL; } - return 0; + if (cfg->version >= 3) { + slirp->disable_dns = cfg->disable_dns; + } else { + slirp->disable_dns = false; + } + + return slirp; } -#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) -#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) -#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) - -/* - * curtime kept to an accuracy of 1ms - */ -#ifdef _WIN32 -static void updtime(void) +Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork, + struct in_addr vnetmask, struct in_addr vhost, + bool in6_enabled, struct in6_addr vprefix_addr6, + uint8_t vprefix_len, struct in6_addr vhost6, + const char *vhostname, const char *tftp_server_name, + const char *tftp_path, const char *bootfile, + struct in_addr vdhcp_start, struct in_addr vnameserver, + struct in6_addr vnameserver6, const char **vdnssearch, + const char *vdomainname, const SlirpCb *callbacks, + void *opaque) { - struct _timeb tb; - - _ftime(&tb); - curtime = (u_int)tb.time * (u_int)1000; - curtime += (u_int)tb.millitm; + SlirpConfig cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.version = 1; + cfg.restricted = restricted; + cfg.in_enabled = in_enabled; + cfg.vnetwork = vnetwork; + cfg.vnetmask = vnetmask; + cfg.vhost = vhost; + cfg.in6_enabled = in6_enabled; + cfg.vprefix_addr6 = vprefix_addr6; + cfg.vprefix_len = vprefix_len; + cfg.vhost6 = vhost6; + cfg.vhostname = vhostname; + cfg.tftp_server_name = tftp_server_name; + cfg.tftp_path = tftp_path; + cfg.bootfile = bootfile; + cfg.vdhcp_start = vdhcp_start; + cfg.vnameserver = vnameserver; + cfg.vnameserver6 = vnameserver6; + cfg.vdnssearch = vdnssearch; + cfg.vdomainname = vdomainname; + return slirp_new(&cfg, callbacks, opaque); } -#else -static void updtime(void) + +void slirp_cleanup(Slirp *slirp) { - gettimeofday(&tt, 0); - - curtime = (u_int)tt.tv_sec * (u_int)1000; - curtime += (u_int)tt.tv_usec / (u_int)1000; - - if ((tt.tv_usec % 1000) >= 500) - curtime++; + struct gfwd_list *e, *next; + + for (e = slirp->guestfwd_list; e; e = next) { + next = e->ex_next; + g_free(e->ex_exec); + g_free(e->ex_unix); + g_free(e); + } + + ip_cleanup(slirp); + ip6_cleanup(slirp); + m_cleanup(slirp); + + g_rand_free(slirp->grand); + + g_free(slirp->vdnssearch); + g_free(slirp->tftp_prefix); + g_free(slirp->bootp_filename); + g_free(slirp->vdomainname); + g_free(slirp); } -#endif -int slirp_select_fill(int *pnfds, - fd_set *readfds, fd_set *writefds, fd_set *xfds) +#define CONN_CANFSEND(so) \ + (((so)->so_state & (SS_FCANTSENDMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define CONN_CANFRCV(so) \ + (((so)->so_state & (SS_FCANTRCVMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED) + +static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout) { - struct SLIRPsocket *so, *so_next; - int nfds; - int timeout, tmp_time; + uint32_t t; - /* fail safe */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; - - nfds = *pnfds; - /* - * First, TCP sockets - */ - do_slowtimo = 0; - if (link_up) { - /* - * *_slowtimo needs calling if there are IP fragments - * in the fragment queue, or there are TCP connections active - */ - do_slowtimo = ((tcb.so_next != &tcb) || - ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); - - for (so = tcb.so_next; (so != &tcb); so = so_next) { - so_next = so->so_next; + if (*timeout <= TIMEOUT_FAST) { + return; + } + t = MIN(1000, *timeout); - /* - * See if we need a tcp_fasttimo - */ - if(so->so_tcpcb!=0x0){ //This is to prevent a common lockup. - if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) - time_fasttimo = curtime; } /* Flag when we want a fasttimo */ - - - /* - * NOFDREF can include still connecting to local-host, - * newly socreated() sockets etc. Don't want to select these. - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; - - /* - * Set for reading sockets which are accepting - */ - if (so->so_state & SS_FACCEPTCONN) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - continue; - } - - /* - * Set for writing sockets which are connecting - */ - if (so->so_state & SS_ISFCONNECTING) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - continue; - } - - /* - * Set for writing if we are connected, can send more, and - * we have something to send - */ - if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - } - - /* - * Set for reading (and urgent data) if we are connected, can - * receive more, and we have room for it XXX /2 ? - */ - if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { - FD_SET(so->s, readfds); - FD_SET(so->s, xfds); - UPD_NFDS(so->s); - } - } - - /* - * UDP sockets - */ - for (so = udb.so_next; so != &udb; so = so_next) { - so_next = so->so_next; - - /* - * See if it's timed out - */ - if (so->so_expire) { - if (so->so_expire <= curtime) { - udp_detach(so); - continue; - } else - do_slowtimo = 1; /* Let socket expire */ - } - - /* - * When UDP packets are received from over the - * link, they're sendto()'d straight away, so - * no need for setting for writing - * Limit the number of packets queued by this session - * to 4. Note that even though we try and limit this - * to 4 packets, the session could have more queued - * if the packets needed to be fragmented - * (XXX <= 4 ?) - */ - if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - } - } - } - - /* - * Setup timeout to use minimum CPU usage, especially when idle - */ + /* If we have tcp timeout with slirp, then we will fill @timeout with + * more precise value. + */ + if (slirp->time_fasttimo) { + *timeout = TIMEOUT_FAST; + return; + } + if (slirp->do_slowtimo) { + t = MIN(TIMEOUT_SLOW, t); + } + *timeout = t; +} - timeout = -1; - - /* - * If a slowtimo is needed, set timeout to 5ms from the last - * slow timeout. If a fast timeout is needed, set timeout within - * 2ms of when it was requested. - */ -# define SLOW_TIMO 5 -# define FAST_TIMO 2 - if (do_slowtimo) { - timeout = (SLOW_TIMO - (curtime - last_slowtimo)) * 1000; - if (timeout < 0) - timeout = 0; - else if (timeout > (SLOW_TIMO * 1000)) - timeout = SLOW_TIMO * 1000; - - /* Can only fasttimo if we also slowtimo */ - if (time_fasttimo) { - tmp_time = (FAST_TIMO - (curtime - time_fasttimo)) * 1000; - if (tmp_time < 0) - tmp_time = 0; - - /* Choose the smallest of the 2 */ - if (tmp_time < timeout) - timeout = tmp_time; - } - } - *pnfds = nfds; - - /* - * Adjust the timeout to make the minimum timeout - * 2ms (XXX?) to lessen the CPU load - */ - if (timeout < (FAST_TIMO * 1000)) - timeout = FAST_TIMO * 1000; - - return timeout; -} - -void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) +void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout, + SlirpAddPollCb add_poll, void *opaque) { - struct SLIRPsocket *so, *so_next; - int ret; - - global_readfds = readfds; - global_writefds = writefds; - global_xfds = xfds; - - /* Update time */ - updtime(); + struct socket *so, *so_next; /* - * See if anything has timed out + * First, TCP sockets */ - if (link_up) { - if (time_fasttimo && ((curtime - time_fasttimo) >= FAST_TIMO)) { - tcp_fasttimo(); - time_fasttimo = 0; - } - if (do_slowtimo && ((curtime - last_slowtimo) >= SLOW_TIMO)) { - ip_slowtimo(); - tcp_slowtimo(); - last_slowtimo = curtime; - } + /* + * *_slowtimo needs calling if there are IP fragments + * in the fragment queue, or there are TCP connections active + */ + slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) || + (&slirp->ipq.ip_link != slirp->ipq.ip_link.next)); + + for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { + int events = 0; + + so_next = so->so_next; + + so->pollfds_idx = -1; + + /* + * See if we need a tcp_fasttimo + */ + if (slirp->time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) { + slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */ + } + + /* + * NOFDREF can include still connecting to local-host, + * newly socreated() sockets etc. Don't want to select these. + */ + if (so->so_state & SS_NOFDREF || so->s == -1) { + continue; + } + + /* + * Set for reading sockets which are accepting + */ + if (so->so_state & SS_FACCEPTCONN) { + so->pollfds_idx = add_poll( + so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); + continue; + } + + /* + * Set for writing sockets which are connecting + */ + if (so->so_state & SS_ISFCONNECTING) { + so->pollfds_idx = + add_poll(so->s, SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque); + continue; + } + + /* + * Set for writing if we are connected, can send more, and + * we have something to send + */ + if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { + events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR; + } + + /* + * Set for reading (and urgent data) if we are connected, can + * receive more, and we have room for it XXX /2 ? + */ + if (CONN_CANFRCV(so) && + (so->so_snd.sb_cc < (so->so_snd.sb_datalen / 2))) { + events |= SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR | + SLIRP_POLL_PRI; + } + + if (events) { + so->pollfds_idx = add_poll(so->s, events, opaque); + } } - ret = 0; + /* + * UDP sockets + */ + for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { + so_next = so->so_next; + + so->pollfds_idx = -1; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + udp_detach(so); + continue; + } else { + slirp->do_slowtimo = true; /* Let socket expire */ + } + } + + /* + * When UDP packets are received from over the + * link, they're sendto()'d straight away, so + * no need for setting for writing + * Limit the number of packets queued by this session + * to 4. Note that even though we try and limit this + * to 4 packets, the session could have more queued + * if the packets needed to be fragmented + * (XXX <= 4 ?) + */ + if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { + so->pollfds_idx = add_poll( + so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); + } + } + + /* + * ICMP sockets + */ + for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { + so_next = so->so_next; + + so->pollfds_idx = -1; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + icmp_detach(so); + continue; + } else { + slirp->do_slowtimo = true; /* Let socket expire */ + } + } + + if (so->so_state & SS_ISFCONNECTED) { + so->pollfds_idx = add_poll( + so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); + } + } + + slirp_update_timeout(slirp, timeout); +} + +void slirp_pollfds_poll(Slirp *slirp, int select_error, + SlirpGetREventsCb get_revents, void *opaque) +{ + struct socket *so, *so_next; + int ret; + + curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS; + + /* + * See if anything has timed out + */ + if (slirp->time_fasttimo && + ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) { + tcp_fasttimo(slirp); + slirp->time_fasttimo = 0; + } + if (slirp->do_slowtimo && + ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) { + ip_slowtimo(slirp); + tcp_slowtimo(slirp); + slirp->last_slowtimo = curtime; + } /* * Check sockets */ - if (link_up) { - /* - * Check TCP sockets - */ - for (so = tcb.so_next; so != &tcb; so = so_next) { - so_next = so->so_next; + if (!select_error) { + /* + * Check TCP sockets + */ + for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { + int revents; - /* - * FD_ISSET is meaningless on these sockets - * (and they can crash the program) - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; + so_next = so->so_next; - /* - * Check for URG data - * This will soread as well, so no need to - * test for readfds below if this succeeds - */ - if (FD_ISSET(so->s, xfds)) - sorecvoob(so); - /* - * Check sockets for reading - */ - else if (FD_ISSET(so->s, readfds)) { - /* - * Check for incoming connections - */ - if (so->so_state & SS_FACCEPTCONN) { - tcp_connect(so); - continue; - } - ret = soread(so); - - /* Output it if we read something */ - if (ret > 0) - tcp_output(sototcpcb(so)); - } + revents = 0; + if (so->pollfds_idx != -1) { + revents = get_revents(so->pollfds_idx, opaque); + } - /* - * Check sockets for writing - */ - if (FD_ISSET(so->s, writefds)) { - /* - * Check for non-blocking, still-connecting sockets - */ - if (so->so_state & SS_ISFCONNECTING) { - /* Connected */ - so->so_state &= ~SS_ISFCONNECTING; + if (so->so_state & SS_NOFDREF || so->s == -1) { + continue; + } - ret = send(so->s, (char *)&ret, 0, 0); - if (ret < 0) { - /* XXXXX Must fix, zero bytes is a NOP */ - if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || (errno == ENOTCONN)) - continue; + /* + * Check for URG data + * This will soread as well, so no need to + * test for SLIRP_POLL_IN below if this succeeds + */ + if (revents & SLIRP_POLL_PRI) { + ret = sorecvoob(so); + if (ret < 0) { + /* Socket error might have resulted in the socket being + * removed, do not try to do anything more with it. */ + continue; + } + } + /* + * Check sockets for reading + */ + else if (revents & + (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) { + /* + * Check for incoming connections + */ + if (so->so_state & SS_FACCEPTCONN) { + tcp_connect(so); + continue; + } /* else */ + ret = soread(so); - /* else failed */ - so->so_state = SS_NOFDREF; - } + /* Output it if we read something */ + if (ret > 0) { + tcp_output(sototcpcb(so)); + } + if (ret < 0) { + /* Socket error might have resulted in the socket being + * removed, do not try to do anything more with it. */ + continue; + } + } - /* - * Continue tcp_input - */ - tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip), so); - } else - ret = sowrite(so); - } - } + /* + * Check sockets for writing + */ + if (!(so->so_state & SS_NOFDREF) && + (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) { + /* + * Check for non-blocking, still-connecting sockets + */ + if (so->so_state & SS_ISFCONNECTING) { + /* Connected */ + so->so_state &= ~SS_ISFCONNECTING; - /* - * Now UDP sockets. - * Incoming packets are sent straight away, they're not buffered. - * Incoming UDP data isn't buffered either. - */ - for (so = udb.so_next; so != &udb; so = so_next) { - so_next = so->so_next; + ret = send(so->s, (const void *)&ret, 0, 0); + if (ret < 0) { + /* XXXXX Must fix, zero bytes is a NOP */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) { + continue; + } - if (so->s != -1 && FD_ISSET(so->s, readfds)) - sorecvfrom(so); - } + /* else failed */ + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; + } + /* else so->so_state &= ~SS_ISFCONNECTING; */ + + /* + * Continue tcp_input + */ + tcp_input((struct mbuf *)NULL, sizeof(struct ip), so, + so->so_ffamily); + /* continue; */ + } else { + ret = sowrite(so); + if (ret > 0) { + /* Call tcp_output in case we need to send a window + * update to the guest, otherwise it will be stuck + * until it sends a window probe. */ + tcp_output(sototcpcb(so)); + } + } + } + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. + */ + for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { + int revents; + + so_next = so->so_next; + + revents = 0; + if (so->pollfds_idx != -1) { + revents = get_revents(so->pollfds_idx, opaque); + } + + if (so->s != -1 && + (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) { + sorecvfrom(so); + } + } + + /* + * Check incoming ICMP relies. + */ + for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { + int revents; + + so_next = so->so_next; + + revents = 0; + if (so->pollfds_idx != -1) { + revents = get_revents(so->pollfds_idx, opaque); + } + + if (so->s != -1 && + (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) { + icmp_receive(so); + } + } } - /* - * See if we can start outputting - */ - if (if_queued && link_up) - if_start(); - - /* clear global file descriptor sets. - * these reside on the stack in vl.c - * so they're unusable if we're not in - * slirp_select_fill or slirp_select_poll. - */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; + if_start(slirp); } -#define ETH_ALEN 6 -#define ETH_HLEN 14 - -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ - -#define ARPOP_REQUEST 1 /* ARP request */ -#define ARPOP_REPLY 2 /* ARP reply */ - -struct ethhdr +static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ -}; - -struct arphdr -{ - unsigned short ar_hrd; /* format of hardware address */ - unsigned short ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - unsigned short ar_op; /* ARP opcode (command) */ - - /* - * Ethernet looks like this : This bit is variable sized however... - */ - unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ - unsigned char ar_sip[4]; /* sender IP address */ - unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -}; - -void arp_input(const uint8_t *pkt, int pkt_len) -{ - struct ethhdr *eh = (struct ethhdr *)pkt; - struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); - uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; + const struct slirp_arphdr *ah = + (const struct slirp_arphdr *)(pkt + ETH_HLEN); + uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)]; struct ethhdr *reh = (struct ethhdr *)arp_reply; - struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); + struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN); int ar_op; - struct ex_list *ex_ptr; + struct gfwd_list *ex_ptr; + + if (!slirp->in_enabled) { + return; + } ar_op = ntohs(ah->ar_op); - switch(ar_op) { + switch (ar_op) { case ARPOP_REQUEST: - if (!memcmp(ah->ar_tip, &special_addr, 3)) { - if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + if (ah->ar_tip == ah->ar_sip) { + /* Gratuitous ARP */ + arp_table_add(slirp, ah->ar_sip, ah->ar_sha); + return; + } + + if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) == + slirp->vnetwork_addr.s_addr) { + if (ah->ar_tip == slirp->vnameserver_addr.s_addr || + ah->ar_tip == slirp->vhost_addr.s_addr) goto arp_ok; - for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if (ex_ptr->ex_addr == ah->ar_tip[3]) + /* TODO: IPv6 */ + for (ex_ptr = slirp->guestfwd_list; ex_ptr; + ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_addr.s_addr == ah->ar_tip) goto arp_ok; } return; arp_ok: - /* XXX: make an ARP request to have the client address */ - memcpy(client_ethaddr, eh->h_source, ETH_ALEN); + memset(arp_reply, 0, sizeof(arp_reply)); + + arp_table_add(slirp, ah->ar_sip, ah->ar_sha); /* ARP request for alias/dns mac address */ memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); - memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); - reh->h_source[5] = ah->ar_tip[3]; + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); + memcpy(&reh->h_source[2], &ah->ar_tip, 4); reh->h_proto = htons(ETH_P_ARP); rah->ar_hrd = htons(1); @@ -582,77 +801,392 @@ void arp_input(const uint8_t *pkt, int pkt_len) rah->ar_pln = 4; rah->ar_op = htons(ARPOP_REPLY); memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); - memcpy(rah->ar_sip, ah->ar_tip, 4); + rah->ar_sip = ah->ar_tip; memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); - memcpy(rah->ar_tip, ah->ar_sip, 4); - slirp_output(arp_reply, sizeof(arp_reply)); + rah->ar_tip = ah->ar_sip; + slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply)); } break; + case ARPOP_REPLY: + arp_table_add(slirp, ah->ar_sip, ah->ar_sha); + break; default: break; } } -void slirp_input(const uint8_t *pkt, int pkt_len) +void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) { - struct SLIRPmbuf *m; + struct mbuf *m; int proto; if (pkt_len < ETH_HLEN) return; - - proto = (pkt[12] << 8) | pkt[13]; - switch(proto) { + + proto = (((uint16_t)pkt[12]) << 8) + pkt[13]; + switch (proto) { case ETH_P_ARP: - arp_input(pkt, pkt_len); + arp_input(slirp, pkt, pkt_len); break; case ETH_P_IP: - m = m_get(); + case ETH_P_IPV6: + m = m_get(slirp); if (!m) return; - /* Note: we add to align the IP header */ - m->m_len = pkt_len + 2; - memcpy(m->m_data + 2, pkt, pkt_len); + /* Note: we add 2 to align the IP header on 4 bytes, + * and add the margin for the tcpiphdr overhead */ + if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) { + m_inc(m, pkt_len + TCPIPHDR_DELTA + 2); + } + m->m_len = pkt_len + TCPIPHDR_DELTA + 2; + memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len); - m->m_data += 2 + ETH_HLEN; - m->m_len -= 2 + ETH_HLEN; + m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN; + m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN; - ip_input(m); + if (proto == ETH_P_IP) { + ip_input(m); + } else if (proto == ETH_P_IPV6) { + ip6_input(m); + } break; + + case ETH_P_NCSI: + ncsi_input(slirp, pkt, pkt_len); + break; + default: break; } } -/* output the IP packet to the ethernet device */ -void if_encap(const uint8_t *ip_data, int ip_data_len) +/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no + * packet should be sent, 0 if the packet must be re-queued, 2 if the packet + * is ready to go. + */ +static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, + uint8_t ethaddr[ETH_ALEN]) { - uint8_t buf[1600]; - struct ethhdr *eh = (struct ethhdr *)buf; + const struct ip *iph = (const struct ip *)ifm->m_data; - if (ip_data_len + ETH_HLEN > sizeof(buf)) - return; + if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) { + uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)]; + struct ethhdr *reh = (struct ethhdr *)arp_req; + struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN); - memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); - memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); - /* XXX: not correct */ - eh->h_source[5] = CTL_ALIAS; - eh->h_proto = htons(ETH_P_IP); - memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); - slirp_output(buf, ip_data_len + ETH_HLEN); + if (!ifm->resolution_requested) { + /* If the client addr is not known, send an ARP request */ + memset(reh->h_dest, 0xff, ETH_ALEN); + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); + memcpy(&reh->h_source[2], &slirp->vhost_addr, 4); + reh->h_proto = htons(ETH_P_ARP); + rah->ar_hrd = htons(1); + rah->ar_pro = htons(ETH_P_IP); + rah->ar_hln = ETH_ALEN; + rah->ar_pln = 4; + rah->ar_op = htons(ARPOP_REQUEST); + + /* source hw addr */ + memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4); + memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4); + + /* source IP */ + rah->ar_sip = slirp->vhost_addr.s_addr; + + /* target hw addr (none) */ + memset(rah->ar_tha, 0, ETH_ALEN); + + /* target IP */ + rah->ar_tip = iph->ip_dst.s_addr; + slirp->client_ipaddr = iph->ip_dst; + slirp_send_packet_all(slirp, arp_req, sizeof(arp_req)); + ifm->resolution_requested = true; + + /* Expire request and drop outgoing packet after 1 second */ + ifm->expiration_date = + slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL; + } + return 0; + } else { + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4); + /* XXX: not correct */ + memcpy(&eh->h_source[2], &slirp->vhost_addr, 4); + eh->h_proto = htons(ETH_P_IP); + + /* Send this */ + return 2; + } } -int slirp_redir(int is_udp, int host_port, - struct in_addr guest_addr, int guest_port) +/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no + * packet should be sent, 0 if the packet must be re-queued, 2 if the packet + * is ready to go. + */ +static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, + uint8_t ethaddr[ETH_ALEN]) { + const struct ip6 *ip6h = mtod(ifm, const struct ip6 *); + if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) { + if (!ifm->resolution_requested) { + ndp_send_ns(slirp, ip6h->ip_dst); + ifm->resolution_requested = true; + ifm->expiration_date = + slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL; + } + return 0; + } else { + eh->h_proto = htons(ETH_P_IPV6); + in6_compute_ethaddr(ip6h->ip_src, eh->h_source); + + /* Send this */ + return 2; + } +} + +/* Output the IP packet to the ethernet device. Returns 0 if the packet must be + * re-queued. + */ +int if_encap(Slirp *slirp, struct mbuf *ifm) +{ + uint8_t buf[IF_MTU_MAX + 100]; + struct ethhdr *eh = (struct ethhdr *)buf; + uint8_t ethaddr[ETH_ALEN]; + const struct ip *iph = (const struct ip *)ifm->m_data; + int ret; + + if (ifm->m_len + ETH_HLEN > sizeof(buf)) { + return 1; + } + + switch (iph->ip_v) { + case IPVERSION: + ret = if_encap4(slirp, ifm, eh, ethaddr); + if (ret < 2) { + return ret; + } + break; + + case IP6VERSION: + ret = if_encap6(slirp, ifm, eh, ethaddr); + if (ret < 2) { + return ret; + } + break; + + default: + g_assert_not_reached(); + } + + memcpy(eh->h_dest, ethaddr, ETH_ALEN); + DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_source[0], + eh->h_source[1], eh->h_source[2], eh->h_source[3], + eh->h_source[4], eh->h_source[5]); + DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_dest[0], + eh->h_dest[1], eh->h_dest[2], eh->h_dest[3], eh->h_dest[4], + eh->h_dest[5]); + memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len); + slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN); + return 1; +} + +/* Drop host forwarding rule, return 0 if found. */ +/* TODO: IPv6 */ +int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, + int host_port) +{ + struct socket *so; + struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb); + struct sockaddr_in addr; + int port = htons(host_port); + socklen_t addr_len; + + for (so = head->so_next; so != head; so = so->so_next) { + addr_len = sizeof(addr); + if ((so->so_state & SS_HOSTFWD) && + getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 && + addr.sin_addr.s_addr == host_addr.s_addr && addr.sin_port == port) { + so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); + closesocket(so->s); + sofree(so); + return 0; + } + } + + return -1; +} + +/* TODO: IPv6 */ +int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, + int host_port, struct in_addr guest_addr, int guest_port) +{ + if (!guest_addr.s_addr) { + guest_addr = slirp->vdhcp_startaddr; + } if (is_udp) { - if (!udp_listen(htons(host_port), guest_addr.s_addr, - htons(guest_port), 0)) + if (!udp_listen(slirp, host_addr.s_addr, htons(host_port), + guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) return -1; } else { - if (!solisten(htons(host_port), guest_addr.s_addr, - htons(guest_port), 0)) + if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port), + guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) return -1; } return 0; } + +/* TODO: IPv6 */ +static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, + int guest_port) +{ + struct gfwd_list *tmp_ptr; + + if (!guest_addr->s_addr) { + guest_addr->s_addr = slirp->vnetwork_addr.s_addr | + (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr); + } + if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) != + slirp->vnetwork_addr.s_addr || + guest_addr->s_addr == slirp->vhost_addr.s_addr || + guest_addr->s_addr == slirp->vnameserver_addr.s_addr) { + return false; + } + + /* check if the port is "bound" */ + for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { + if (guest_port == tmp_ptr->ex_fport && + guest_addr->s_addr == tmp_ptr->ex_addr.s_addr) + return false; + } + + return true; +} + +int slirp_add_exec(Slirp *slirp, const char *cmdline, + struct in_addr *guest_addr, int guest_port) +{ + if (!check_guestfwd(slirp, guest_addr, guest_port)) { + return -1; + } + + add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port)); + return 0; +} + +int slirp_add_unix(Slirp *slirp, const char *unixsock, + struct in_addr *guest_addr, int guest_port) +{ +#ifdef G_OS_UNIX + if (!check_guestfwd(slirp, guest_addr, guest_port)) { + return -1; + } + + add_unix(&slirp->guestfwd_list, unixsock, *guest_addr, htons(guest_port)); + return 0; +#else + g_warn_if_reached(); + return -1; +#endif +} + +int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque, + struct in_addr *guest_addr, int guest_port) +{ + if (!check_guestfwd(slirp, guest_addr, guest_port)) { + return -1; + } + + add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr, + htons(guest_port)); + return 0; +} + +int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr, + int guest_port) +{ + return remove_guestfwd(&slirp->guestfwd_list, guest_addr, + htons(guest_port)); +} + +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) +{ + if (so->s == -1 && so->guestfwd) { + /* XXX this blocks entire thread. Rewrite to use + * qemu_chr_fe_write and background I/O callbacks */ + so->guestfwd->write_cb(buf, len, so->guestfwd->opaque); + return len; + } + + if (so->s == -1) { + /* + * This should in theory not happen but it is hard to be + * sure because some code paths will end up with so->s == -1 + * on a failure but don't dispose of the struct socket. + * Check specifically, so we don't pass -1 to send(). + */ + errno = EBADF; + return -1; + } + + return send(so->s, buf, len, flags); +} + +struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, + int guest_port) +{ + struct socket *so; + + /* TODO: IPv6 */ + for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { + if (so->so_faddr.s_addr == guest_addr.s_addr && + htons(so->so_fport) == guest_port) { + return so; + } + } + return NULL; +} + +size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, + int guest_port) +{ + struct iovec iov[2]; + struct socket *so; + + so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); + + if (!so || so->so_state & SS_NOFDREF) { + return 0; + } + + if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen / 2)) { + return 0; + } + + return sopreprbuf(so, iov, NULL); +} + +void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, + const uint8_t *buf, int size) +{ + int ret; + struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); + + if (!so) + return; + + ret = soreadbuf(so, (const char *)buf, size); + + if (ret > 0) + tcp_output(sototcpcb(so)); +} + +void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len) +{ + ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque); + + if (ret < 0) { + g_critical("Failed to send packet, ret: %ld", (long)ret); + } else if (ret < len) { + DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu", (long)ret, + (unsigned long)len); + } +} diff --git a/src/network/slirp/slirp.h b/src/network/slirp/slirp.h index b78dc93a8..d996b53ed 100644 --- a/src/network/slirp/slirp.h +++ b/src/network/slirp/slirp.h @@ -1,441 +1,291 @@ -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#define SLIRP_VERSION "Cockatrice special" - -#define CONFIG_QEMU - -#ifndef CONFIG_QEMU -#include "version.h" -#endif -#include "config.h" -#include "slirp_config.h" +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef SLIRP_H +#define SLIRP_H #ifdef _WIN32 -#ifdef __GNUC__ /* MINGW? */ -# include -typedef uint8_t u_int8_t; -typedef uint16_t u_int16_t; -typedef uint32_t u_int32_t; -typedef uint64_t u_int64_t; -typedef char *SLIRPcaddr_t; -typedef int socklen_t; -typedef unsigned long ioctlsockopt_t; + +/* as defined in sdkddkver.h */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 /* Vista */ +#endif +/* reduces the number of implicitly included headers */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#include +#include +#include + #else -typedef unsigned char u_int8_t; -typedef char int8_t; -typedef unsigned char uint8_t; -typedef unsigned short u_int16_t; -typedef unsigned short uint16_t; -typedef short int16_t; -typedef unsigned int u_int32_t; -typedef unsigned int uint32_t; -typedef int int32_t; - -typedef unsigned __int64 u_int64_t; -typedef char *SLIRPcaddr_t; -typedef int socklen_t; -typedef unsigned long ioctlsockopt_t; - -#endif - -# include /* needs to be on top otherwise, it'll pull in winsock1 */ -# include - -# include -# include - -# define USE_FIONBIO 1 -#ifndef EWOULDBLOCK -# define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef EINPROGRESS -# define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef ENOTCONN -# define ENOTCONN WSAENOTCONN -#endif -#ifndef EHOSTUNREACH -# define EHOSTUNREACH WSAEHOSTUNREACH -#endif -#ifndef ENETUNREACH -# define ENETUNREACH WSAENETUNREACH -#endif -#ifndef ECONNREFUSED -# define ECONNREFUSED WSAECONNREFUSED -#endif - -/* Basilisk II Router defines those */ -# define udp_read_completion slirp_udp_read_completion -# define write_udp slirp_write_udp -# define init_udp slirp_init_udp -# define final_udp slirp_final_udp -#else -# include -# define HAVE_STDINT_H -# define HAVE_STDLIB_H -# define HAVE_STRING_H -# define HAVE_UNISTD_H -# define HAVE_INET_ATON -typedef uint8_t u_int8_t; -typedef uint16_t u_int16_t; -typedef uint32_t u_int32_t; -typedef uint64_t u_int64_t; -typedef char *SLIRPcaddr_t; -typedef int ioctlsockopt_t; -# define ioctlsocket ioctl -# define closesocket(s) close(s) -# define O_BINARY 0 -#endif - -#include -#ifdef HAVE_SYS_BITYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif - -#ifndef _MSC_VER -#include -#else -#include -#endif - -#ifdef NEED_TYPEDEFS -typedef char int8_t; -typedef unsigned char u_int8_t; - -# if SIZEOF_SHORT == 2 - typedef short int16_t; - typedef unsigned short u_int16_t; -# else -# if SIZEOF_INT == 2 - typedef int int16_t; - typedef unsigned int u_int16_t; -# else - #error Cannot find a type with sizeof() == 2 -# endif -# endif - -# if SIZEOF_SHORT == 4 - typedef short int32_t; - typedef unsigned short u_int32_t; -# else -# if SIZEOF_INT == 4 - typedef int int32_t; - typedef unsigned int u_int32_t; -# else - #error Cannot find a type with sizeof() == 4 -# endif -# endif -#endif /* NEED_TYPEDEFS */ - -/* Basilisk II types glue */ -typedef u_int8_t uint8; -typedef u_int16_t uint16; -typedef u_int32_t uint32; - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifdef HAVE_STDLIB_H -# include -#endif - -#include -#include - -#ifndef HAVE_MEMMOVE -#define memmove(x, y, z) bcopy(y, x, z) -#endif - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#ifdef HAVE_STRING_H -# include -#else -#ifndef _MSC_VER -# include -#else -#include +#if !defined(__HAIKU__) +#define O_BINARY 0 #endif #endif #ifndef _WIN32 #include -#endif - -#ifndef _P -#ifndef NO_PROTOTYPES -# define _P(x) x -#else -# define _P(x) () -#endif -#endif - -#ifndef _WIN32 #include #include -#endif - -#ifdef GETTIMEOFDAY_ONE_ARG -#define gettimeofday(x, y) gettimeofday(x) -#endif - -/* Systems lacking strdup() definition in . */ -#if defined(ultrix) -char *strdup _P((const char *)); -#endif - -/* Systems lacking malloc() definition in . */ -#if defined(ultrix) || defined(hcx) -void *malloc _P((size_t arg)); -void free _P((void *ptr)); -#endif - -#ifndef HAVE_INET_ATON -int inet_aton _P((const char *cp, struct in_addr *ia)); -#endif - -#include -#ifndef NO_UNIX_SOCKETS -#include -#endif -#include -#ifdef HAVE_SYS_SIGNAL_H -# include -#endif -#ifndef _WIN32 #include +#include #endif -#if defined(HAVE_SYS_IOCTL_H) -# include +#ifdef __APPLE__ +#include #endif -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -#ifdef HAVE_SYS_FILIO_H -# include -#endif - -#ifdef USE_PPP -#include -#endif - -#ifdef __STDC__ -#include -#else -#include -#endif - -#include - /* Avoid conflicting with the libc insque() and remque(), which have different prototypes. */ #define insque slirp_insque #define remque slirp_remque - -#ifdef HAVE_SYS_STROPTS_H -#include -#endif +#define quehead slirp_quehead #include "debug.h" +#include "util.h" -#if defined __GNUC__ -#define PACKED__ __attribute__ ((packed)) -#elif defined __sgi -#define PRAGMA_PACK_SUPPORTED 1 -#define PACK_END 0 -#define PACKED__ -#elif _MSC_VER -#define PACKED__ -#else -#error "Packed attribute or pragma shall be supported" -#endif - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif - +#include "libslirp.h" #include "ip.h" +#include "ip6.h" #include "tcp.h" #include "tcp_timer.h" #include "tcp_var.h" #include "tcpip.h" #include "udp.h" -#include "icmp_var.h" +#include "ip_icmp.h" +#include "ip6_icmp.h" #include "mbuf.h" #include "sbuf.h" #include "socket.h" #include "if.h" #include "main.h" #include "misc.h" -#include "ctl.h" -#ifdef USE_PPP -#include "ppp/pppd.h" -#include "ppp/ppp.h" -#endif #include "bootp.h" #include "tftp.h" -#include "libslirp.h" -extern struct ttys *ttys_unit[MAX_INTERFACES]; +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ -#ifndef NULL -#define NULL (void *)0 +struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ +}; + +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) +#endif +struct slirp_arphdr { + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + uint32_t ar_sip; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + uint32_t ar_tip; /* target IP address */ +} SLIRP_PACKED; +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(pop) #endif -#ifndef FULL_BOLT -void if_start _P((void)); -#else -void if_start _P((struct ttys *)); -#endif +#define ARP_TABLE_SIZE 16 -#ifdef BAD_SPRINTF -# define vsprintf vsprintf_len -# define sprintf sprintf_len - extern int vsprintf_len _P((char *, const char *, va_list)); - extern int sprintf_len _P((char *, const char *, ...)); -#endif +typedef struct ArpTable { + struct slirp_arphdr table[ARP_TABLE_SIZE]; + int next_victim; +} ArpTable; -#ifdef DECLARE_SPRINTF -# ifndef BAD_SPRINTF - extern int vsprintf _P((char *, const char *, va_list)); -# endif - extern int vfprintf _P((FILE *, const char *, va_list)); -#endif +void arp_table_add(Slirp *slirp, uint32_t ip_addr, + const uint8_t ethaddr[ETH_ALEN]); -#ifndef HAVE_STRERROR -#ifndef _MSC_VER - extern char *strerror _P((int error)); - #define HAVE_STRERROR -#endif -#endif +bool arp_table_search(Slirp *slirp, uint32_t ip_addr, + uint8_t out_ethaddr[ETH_ALEN]); -#ifndef HAVE_INDEX - char *index _P((const char *, int)); -#endif +struct ndpentry { + unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */ + struct in6_addr ip_addr; /* sender IP address */ +}; -#ifndef HAVE_GETHOSTID - long gethostid _P((void)); -#endif +#define NDP_TABLE_SIZE 16 -void lprint _P((const char *, ...)); +typedef struct NdpTable { + struct ndpentry table[NDP_TABLE_SIZE]; + int next_victim; +} NdpTable; -extern int do_echo; +void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr, + uint8_t ethaddr[ETH_ALEN]); +bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr, + uint8_t out_ethaddr[ETH_ALEN]); -#ifdef _MSC_VER -#define __inline -#endif +struct Slirp { + unsigned time_fasttimo; + unsigned last_slowtimo; + bool do_slowtimo; -#if SIZEOF_CHAR_P == 4 -# define insque_32 insque -# define remque_32 remque -#else -# ifdef NEED_QUE32_INLINE -extern __inline void insque_32 _P((void *, void *)); -extern __inline void remque_32 _P((void *)); -# else -extern void insque_32 _P((void *, void *)); -extern void remque_32 _P((void *)); -# endif -#endif + bool in_enabled, in6_enabled; + + /* virtual network configuration */ + struct in_addr vnetwork_addr; + struct in_addr vnetwork_mask; + struct in_addr vhost_addr; + struct in6_addr vprefix_addr6; + uint8_t vprefix_len; + struct in6_addr vhost_addr6; + struct in_addr vdhcp_startaddr; + struct in_addr vnameserver_addr; + struct in6_addr vnameserver_addr6; + + struct in_addr client_ipaddr; + char client_hostname[33]; + + int restricted; + struct gfwd_list *guestfwd_list; + + int if_mtu; + int if_mru; + + bool disable_host_loopback; + + /* mbuf states */ + struct quehead m_freelist; + struct quehead m_usedlist; + int mbuf_alloced; + + /* if states */ + struct quehead if_fastq; /* fast queue (for interactive data) */ + struct quehead if_batchq; /* queue for non-interactive data */ + bool if_start_busy; /* avoid if_start recursion */ + + /* ip states */ + struct ipq ipq; /* ip reass. queue */ + uint16_t ip_id; /* ip packet ctr, for ids */ + + /* bootp/dhcp states */ + BOOTPClient bootp_clients[NB_BOOTP_CLIENTS]; + char *bootp_filename; + size_t vdnssearch_len; + uint8_t *vdnssearch; + char *vdomainname; + + /* tcp states */ + struct socket tcb; + struct socket *tcp_last_so; + tcp_seq tcp_iss; /* tcp initial send seq # */ + uint32_t tcp_now; /* for RFC 1323 timestamps */ + + /* udp states */ + struct socket udb; + struct socket *udp_last_so; + + /* icmp states */ + struct socket icmp; + struct socket *icmp_last_so; + + /* tftp states */ + char *tftp_prefix; + struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; + char *tftp_server_name; + + ArpTable arp_table; + NdpTable ndp_table; + + GRand *grand; + void *ra_timer; + + bool enable_emu; + + const SlirpCb *cb; + void *opaque; + + struct sockaddr_in *outbound_addr; + struct sockaddr_in6 *outbound_addr6; + bool disable_dns; /* slirp will not redirect/serve any DNS packet */ +}; + +void if_start(Slirp *); + +int get_dns_addr(struct in_addr *pdns_addr); +int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id); + +/* ncsi.c */ +void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len); #ifndef _WIN32 #include #endif -#define DEFAULT_BAUD 115200 + +extern bool slirp_do_keepalive; + +#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL) + +/* dnssearch.c */ +int translate_dnssearch(Slirp *s, const char **names); /* cksum.c */ -int cksum(struct SLIRPmbuf *m, int len); +int cksum(struct mbuf *m, int len); +int ip6_cksum(struct mbuf *m); /* if.c */ -void if_init _P((void)); -void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +void if_init(Slirp *); +void if_output(struct socket *, struct mbuf *); /* ip_input.c */ -void ip_init _P((void)); -void ip_input _P((struct SLIRPmbuf *)); -struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); -void ip_freef _P((struct ipq *)); -void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); -void ip_deq _P((register struct ipasfrag *)); -void ip_slowtimo _P((void)); -void ip_stripoptions _P((register struct SLIRPmbuf *, struct SLIRPmbuf *)); +void ip_init(Slirp *); +void ip_cleanup(Slirp *); +void ip_input(struct mbuf *); +void ip_slowtimo(Slirp *); +void ip_stripoptions(register struct mbuf *, struct mbuf *); /* ip_output.c */ -int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +int ip_output(struct socket *, struct mbuf *); + +/* ip6_input.c */ +void ip6_init(Slirp *); +void ip6_cleanup(Slirp *); +void ip6_input(struct mbuf *); + +/* ip6_output */ +int ip6_output(struct socket *, struct mbuf *, int fast); /* tcp_input.c */ -int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *)); -void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *)); -void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); -void tcp_xmit_timer _P((register struct tcpcb *, int)); -int tcp_mss _P((register struct tcpcb *, u_int)); +void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af); +int tcp_mss(register struct tcpcb *, unsigned); /* tcp_output.c */ -int tcp_output _P((register struct tcpcb *)); -void tcp_setpersist _P((register struct tcpcb *)); +int tcp_output(register struct tcpcb *); +void tcp_setpersist(register struct tcpcb *); /* tcp_subr.c */ -void tcp_init _P((void)); -void tcp_template _P((struct tcpcb *)); -void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct SLIRPmbuf *, tcp_seq, tcp_seq, int)); -struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *)); -struct tcpcb * tcp_close _P((register struct tcpcb *)); -void tcp_drain _P((void)); -void tcp_sockclosed _P((struct tcpcb *)); -int tcp_fconnect _P((struct SLIRPsocket *)); -void tcp_connect _P((struct SLIRPsocket *)); -int tcp_attach _P((struct SLIRPsocket *)); -u_int8_t tcp_tos _P((struct SLIRPsocket *)); -int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -int tcp_ctl _P((struct SLIRPsocket *)); +void tcp_init(Slirp *); +void tcp_cleanup(Slirp *); +void tcp_template(struct tcpcb *); +void tcp_respond(struct tcpcb *, register struct tcpiphdr *, + register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short); +struct tcpcb *tcp_newtcpcb(struct socket *); +struct tcpcb *tcp_close(register struct tcpcb *); +void tcp_sockclosed(struct tcpcb *); +int tcp_fconnect(struct socket *, unsigned short af); +void tcp_connect(struct socket *); +void tcp_attach(struct socket *); +uint8_t tcp_tos(struct socket *); +int tcp_emu(struct socket *, struct mbuf *); +int tcp_ctl(struct socket *); struct tcpcb *tcp_drop(struct tcpcb *tp, int err); +struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, + int guest_port); -#if defined(_MSC_VER) -#pragma pack(pop) -#endif - -#ifdef USE_PPP -#define MIN_MRU MINMRU -#define MAX_MRU MAXMRU -#else -#define MIN_MRU 128 -#define MAX_MRU 16384 -#endif - -#ifndef _WIN32 -#define min(x,y) ((x) < (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) -#endif - -#ifdef _WIN32 -#undef errno -#define errno (WSAGetLastError()) -#endif - -#define PROBE_CONN +void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len); #endif diff --git a/src/network/slirp/slirp_config.h b/src/network/slirp/slirp_config.h deleted file mode 100644 index e583dcc80..000000000 --- a/src/network/slirp/slirp_config.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * User definable configuration options - */ - -/* Undefine if you don't want talk emulation */ -#undef EMULATE_TALK - -/* Define if you want the connection to be probed */ -/* XXX Not working yet, so ignore this for now */ -#undef PROBE_CONN - -/* Define to 1 if you want KEEPALIVE timers */ -#define DO_KEEPALIVE 0 - -/* Define to MAX interfaces you expect to use at once */ -/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ -/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ -#define MAX_INTERFACES 1 -#define MAX_PPP_INTERFACES 1 - -/* Define if you want slirp's socket in /tmp */ -/* XXXXXX Do this in ./configure */ -#undef USE_TMPSOCKET - -/* Define if you want slirp to use cfsetXspeed() on the terminal */ -#undef DO_CFSETSPEED - -/* Define this if you want slirp to write to the tty as fast as it can */ -/* This should only be set if you are using load-balancing, slirp does a */ -/* pretty good job on single modems already, and seting this will make */ -/* interactive sessions less responsive */ -/* XXXXX Talk about having fast modem as unit 0 */ -#undef FULL_BOLT - -/* - * Define if you want slirp to use less CPU - * You will notice a small lag in interactive sessions, but it's not that bad - * Things like Netscape/ftp/etc. are completely unaffected - * This is mainly for sysadmins who have many slirp users - */ -#undef USE_LOWCPU - -/* Define this if your compiler doesn't like prototypes */ -#ifndef __STDC__ -#define NO_PROTOTYPES -#endif - -/*********************************************************/ -/* - * Autoconf defined configuration options - * You shouldn't need to touch any of these - */ - -/* Ignore this */ -#undef DUMMY_PPP - -/* XXX: Define according to how time.h should be included */ -#undef TIME_WITH_SYS_TIME -#define TIME_WITH_SYS_TIME 0 -#undef HAVE_SYS_TIME_H - -/* Define if your sprintf returns char * instead of int */ -#undef BAD_SPRINTF - -/* Define if you have readv */ -#undef HAVE_READV - -/* Define if iovec needs to be declared */ -#undef DECLARE_IOVEC -#ifdef _WIN32 -#define DECLARE_IOVEC -#endif - -/* Define if a declaration of sprintf/fprintf is needed */ -#undef DECLARE_SPRINTF - -/* Define if you have sys/stropts.h */ -#undef HAVE_SYS_STROPTS_H - -/* Define if your compiler doesn't like prototypes */ -#undef NO_PROTOTYPES - -/* Define if you don't have u_int32_t etc. typedef'd */ -#undef NEED_TYPEDEFS -#ifdef __sun__ -#define NEED_TYPEDEFS -#endif - -/* Define to sizeof(char *) */ -#define SIZEOF_CHAR_P SIZEOF_VOID_P - -/* Define if you have random() */ -#undef HAVE_RANDOM - -/* Define if you have srandom() */ -#undef HAVE_SRANDOM - -/* Define if you have setenv */ -#undef HAVE_SETENV - -/* Define if you have index() */ -#undef HAVE_INDEX - -/* Define if you have bcmp() */ -#undef HAVE_BCMP - -/* Define if you have drand48 */ -#undef HAVE_DRAND48 - -/* Define if you have memmove */ -#define HAVE_MEMMOVE - -/* Define if you have gethostid */ -#undef HAVE_GETHOSTID - -/* Define if you DON'T have unix-domain sockets */ -#undef NO_UNIX_SOCKETS -#ifdef _WIN32 -#define NO_UNIX_SOCKETS -#endif - -/* Define if gettimeofday only takes one argument */ -#undef GETTIMEOFDAY_ONE_ARG - -/* Define if you have revoke() */ -#undef HAVE_REVOKE - -/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ -#undef HAVE_GRANTPT - -/* Define if you have fchmod */ -#undef HAVE_FCHMOD - -/* Define if you have */ -#undef HAVE_SYS_TYPES32_H diff --git a/src/network/slirp/socket.c b/src/network/slirp/socket.c index a930c502d..36d005192 100644 --- a/src/network/slirp/socket.c +++ b/src/network/slirp/socket.c @@ -1,55 +1,38 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#define WANT_SYS_IOCTL_H -#include -#ifndef _WIN32 -# include -#endif #include "slirp.h" #include "ip_icmp.h" -#include "main.h" #ifdef __sun__ #include #endif -#ifndef FIONREAD -#include -#endif +static void sofcantrcvmore(struct socket *so); +static void sofcantsendmore(struct socket *so); -void -so_init() +struct socket *solookup(struct socket **last, struct socket *head, + struct sockaddr_storage *lhost, + struct sockaddr_storage *fhost) { - /* Nothing yet */ -} + struct socket *so = *last; + /* Optimisation */ + if (so != head && sockaddr_equal(&(so->lhost.ss), lhost) && + (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { + return so; + } -struct SLIRPsocket * -solookup(head, laddr, lport, faddr, fport) - struct SLIRPsocket *head; - struct in_addr laddr; - u_int lport; - struct in_addr faddr; - u_int fport; -{ - struct SLIRPsocket *so; - - for (so = head->so_next; so != head; so = so->so_next) { - if (so->so_lport == lport && - so->so_laddr.s_addr == laddr.s_addr && - so->so_faddr.s_addr == faddr.s_addr && - so->so_fport == fport) - break; - } - - if (so == head) - return (struct SLIRPsocket *)NULL; - return so; - + for (so = head->so_next; so != head; so = so->so_next) { + if (sockaddr_equal(&(so->lhost.ss), lhost) && + (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { + *last = so; + return so; + } + } + + return (struct socket *)NULL; } /* @@ -57,43 +40,124 @@ solookup(head, laddr, lport, faddr, fport) * It is the responsibility of the caller to * insque() it into the correct linked-list */ -struct SLIRPsocket * -socreate() +struct socket *socreate(Slirp *slirp) { - struct SLIRPsocket *so; - - so = (struct SLIRPsocket *)malloc(sizeof(struct SLIRPsocket)); - if(so) { - memset(so, 0, sizeof(struct SLIRPsocket)); + struct socket *so = g_new(struct socket, 1); + + memset(so, 0, sizeof(struct socket)); so->so_state = SS_NOFDREF; so->s = -1; - } - return(so); + so->slirp = slirp; + so->pollfds_idx = -1; + + return so; +} + +/* + * Remove references to so from the given message queue. + */ +static void soqfree(struct socket *so, struct quehead *qh) +{ + struct mbuf *ifq; + + for (ifq = (struct mbuf *)qh->qh_link; (struct quehead *)ifq != qh; + ifq = ifq->ifq_next) { + if (ifq->ifq_so == so) { + struct mbuf *ifm; + ifq->ifq_so = NULL; + for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) { + ifm->ifq_so = NULL; + } + } + } } /* * remque and free a socket, clobber cache */ -void -sofree(so) - struct SLIRPsocket *so; +void sofree(struct socket *so) { - if (so->so_emu==EMU_RSH && so->extra) { - sofree(so->extra); - so->extra=NULL; - } - if (so == tcp_last_so) - tcp_last_so = &tcb; - else if (so == udp_last_so) - udp_last_so = &udb; + Slirp *slirp = so->slirp; - if(so->so_m!=NULL) + soqfree(so, &slirp->if_fastq); + soqfree(so, &slirp->if_batchq); + + if (so == slirp->tcp_last_so) { + slirp->tcp_last_so = &slirp->tcb; + } else if (so == slirp->udp_last_so) { + slirp->udp_last_so = &slirp->udb; + } else if (so == slirp->icmp_last_so) { + slirp->icmp_last_so = &slirp->icmp; + } m_free(so->so_m); - - if(so->so_next && so->so_prev) - remque(so); /* crashes if so is not in a queue */ - free(so); + if (so->so_next && so->so_prev) + remque(so); /* crashes if so is not in a queue */ + + if (so->so_tcpcb) { + g_free(so->so_tcpcb); + } + g_free(so); +} + +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np) +{ + int n, lss, total; + struct sbuf *sb = &so->so_snd; + int len = sb->sb_datalen - sb->sb_cc; + int mss = so->so_tcpcb->t_maxseg; + + DEBUG_CALL("sopreprbuf"); + DEBUG_ARG("so = %p", so); + + if (len <= 0) + return 0; + + iov[0].iov_base = sb->sb_wptr; + iov[1].iov_base = NULL; + iov[1].iov_len = 0; + if (sb->sb_wptr < sb->sb_rptr) { + iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len % mss; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_rptr - sb->sb_data; + if (iov[1].iov_len > len) + iov[1].iov_len = len; + total = iov[0].iov_len + iov[1].iov_len; + if (total > mss) { + lss = total % mss; + if (iov[1].iov_len > lss) { + iov[1].iov_len -= lss; + n = 2; + } else { + lss -= iov[1].iov_len; + iov[0].iov_len -= lss; + n = 1; + } + } else + n = 2; + } else { + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len % mss; + n = 1; + } + } + if (np) + *np = n; + + return iov[0].iov_len + (n - 1) * iov[1].iov_len; } /* @@ -101,549 +165,596 @@ sofree(so) * NOTE: This will only be called if it is select()ed for reading, so * a read() of 0 (or less) means it's disconnected */ -int -soread(so) - struct SLIRPsocket *so; +int soread(struct socket *so) { - int n, nn, lss, total; - struct sbuf *sb = &so->so_snd; - int len = sb->sb_datalen - sb->sb_cc; - struct iovec iov[2]; - int mss; - if(!so->so_tcpcb) - return 0; + int n = 0, nn; + size_t buf_len; + struct sbuf *sb = &so->so_snd; + struct iovec iov[2] = {{0, 0}, {0, 0}}; - mss = so->so_tcpcb->t_maxseg; - - DEBUG_CALL("soread"); - DEBUG_ARG("so = %lx", (long )so); - - /* - * No need to check if there's enough room to read. - * soread wouldn't have been called if there weren't - */ - - len = sb->sb_datalen - sb->sb_cc; - - iov[0].iov_base = sb->sb_wptr; - if (sb->sb_wptr < sb->sb_rptr) { - iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; - /* Should never succeed, but... */ - if (iov[0].iov_len > len) - iov[0].iov_len = len; - if (iov[0].iov_len > mss) - iov[0].iov_len -= iov[0].iov_len%mss; - n = 1; - } else { - iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; - /* Should never succeed, but... */ - if (iov[0].iov_len > len) iov[0].iov_len = len; - len -= iov[0].iov_len; - if (len) { - iov[1].iov_base = sb->sb_data; - iov[1].iov_len = sb->sb_rptr - sb->sb_data; - if(iov[1].iov_len > len) - iov[1].iov_len = len; - total = iov[0].iov_len + iov[1].iov_len; - if (total > mss) { - lss = total%mss; - if (iov[1].iov_len > lss) { - iov[1].iov_len -= lss; - n = 2; - } else { - lss -= iov[1].iov_len; - iov[0].iov_len -= lss; - n = 1; - } - } else - n = 2; - } else { - if (iov[0].iov_len > mss) - iov[0].iov_len -= iov[0].iov_len%mss; - n = 1; - } - } - -#ifdef HAVE_READV - nn = readv(so->s, (struct iovec *)iov, n); - DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); -#else - nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); -#endif - if (nn <= 0) { - if (nn < 0 && (errno == EINTR || errno == EAGAIN)) - return 0; - else { - DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); - sofcantrcvmore(so); - tcp_sockclosed(sototcpcb(so)); - return -1; - } - } - -#ifndef HAVE_READV - /* - * If there was no error, try and read the second time round - * We read again if n = 2 (ie, there's another part of the buffer) - * and we read as much as we could in the first read - * We don't test for <= 0 this time, because there legitimately - * might not be any more data (since the socket is non-blocking), - * a close will be detected on next iteration. - * A return of -1 wont (shouldn't) happen, since it didn't happen above - */ - if (n == 2 && nn == iov[0].iov_len) { - int ret; - ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); - if (ret > 0) - nn += ret; + DEBUG_CALL("soread"); + DEBUG_ARG("so = %p", so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + buf_len = sopreprbuf(so, iov, &n); + assert(buf_len != 0); + + nn = recv(so->s, iov[0].iov_base, iov[0].iov_len, 0); + if (nn <= 0) { + if (nn < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + else { + int err; + socklen_t elen = sizeof err; + struct sockaddr_storage addr; + struct sockaddr *paddr = (struct sockaddr *)&addr; + socklen_t alen = sizeof addr; + + err = errno; + if (nn == 0) { + int shutdown_wr = so->so_state & SS_FCANTSENDMORE; + + if (!shutdown_wr && getpeername(so->s, paddr, &alen) < 0) { + err = errno; + } else { + getsockopt(so->s, SOL_SOCKET, SO_ERROR, &err, &elen); + } + } + + DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s", nn, + errno, strerror(errno)); + sofcantrcvmore(so); + + if (err == ECONNRESET || err == ECONNREFUSED || err == ENOTCONN || + err == EPIPE) { + tcp_drop(sototcpcb(so), err); + } else { + tcp_sockclosed(sototcpcb(so)); + } + return -1; } - - DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); -#endif - - /* Update fields */ - sb->sb_cc += nn; - sb->sb_wptr += nn; - if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) - sb->sb_wptr -= sb->sb_datalen; - return nn; + } + + /* + * If there was no error, try and read the second time round + * We read again if n = 2 (ie, there's another part of the buffer) + * and we read as much as we could in the first read + * We don't test for <= 0 this time, because there legitimately + * might not be any more data (since the socket is non-blocking), + * a close will be detected on next iteration. + * A return of -1 won't (shouldn't) happen, since it didn't happen above + */ + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = recv(so->s, iov[1].iov_base, iov[1].iov_len, 0); + if (ret > 0) + nn += ret; + } + + DEBUG_MISC(" ... read nn = %d bytes", nn); + + /* Update fields */ + sb->sb_cc += nn; + sb->sb_wptr += nn; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return nn; } - + +int soreadbuf(struct socket *so, const char *buf, int size) +{ + int n, nn, copy = size; + struct sbuf *sb = &so->so_snd; + struct iovec iov[2] = {{0, 0}, {0, 0}}; + + DEBUG_CALL("soreadbuf"); + DEBUG_ARG("so = %p", so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + assert(size > 0); + if (sopreprbuf(so, iov, &n) < size) + goto err; + + nn = MIN(iov[0].iov_len, copy); + memcpy(iov[0].iov_base, buf, nn); + + copy -= nn; + buf += nn; + + if (copy == 0) + goto done; + + memcpy(iov[1].iov_base, buf, copy); + +done: + /* Update fields */ + sb->sb_cc += size; + sb->sb_wptr += size; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return size; +err: + + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + g_critical("soreadbuf buffer too small"); + return -1; +} + /* * Get urgent data - * + * * When the socket is created, we set it SO_OOBINLINE, * so when OOB data arrives, we soread() it and everything * in the send buffer is sent as urgent data */ -void -sorecvoob(so) - struct SLIRPsocket *so; +int sorecvoob(struct socket *so) { - struct tcpcb *tp = sototcpcb(so); + struct tcpcb *tp = sototcpcb(so); + int ret; - DEBUG_CALL("sorecvoob"); - DEBUG_ARG("so = %lx", (long)so); - - /* - * We take a guess at how much urgent data has arrived. - * In most situations, when urgent data arrives, the next - * read() should get all the urgent data. This guess will - * be wrong however if more data arrives just after the - * urgent data, or the read() doesn't return all the - * urgent data. - */ - soread(so); - tp->snd_up = tp->snd_una + so->so_snd.sb_cc; - tp->t_force = 1; - tcp_output(tp); - tp->t_force = 0; + DEBUG_CALL("sorecvoob"); + DEBUG_ARG("so = %p", so); + + /* + * We take a guess at how much urgent data has arrived. + * In most situations, when urgent data arrives, the next + * read() should get all the urgent data. This guess will + * be wrong however if more data arrives just after the + * urgent data, or the read() doesn't return all the + * urgent data. + */ + ret = soread(so); + if (ret > 0) { + tp->snd_up = tp->snd_una + so->so_snd.sb_cc; + tp->t_force = 1; + tcp_output(tp); + tp->t_force = 0; + } + + return ret; } /* * Send urgent data * There's a lot duplicated code here, but... */ -int -sosendoob(so) - struct SLIRPsocket *so; +int sosendoob(struct socket *so) { - struct sbuf *sb = &so->so_rcv; - char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ - - int n, len; - - DEBUG_CALL("sosendoob"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); - - if (so->so_urgc > 2048) - so->so_urgc = 2048; /* XXXX */ - - if (sb->sb_rptr < sb->sb_wptr) { - /* We can send it directly */ - n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ - so->so_urgc -= n; - - DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); - } else { - /* - * Since there's no sendv or sendtov like writev, - * we must copy all data to a linear buffer then - * send it all - */ - len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; - if (len > so->so_urgc) len = so->so_urgc; - memcpy(buff, sb->sb_rptr, len); - so->so_urgc -= len; - if (so->so_urgc) { - n = sb->sb_wptr - sb->sb_data; - if (n > so->so_urgc) n = so->so_urgc; - memcpy((buff + len), sb->sb_data, n); - so->so_urgc -= n; - len += n; - } - n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ -#ifdef SLIRP_DEBUG - if (n != len) - DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); -#endif - DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); - } - - sb->sb_cc -= n; - sb->sb_rptr += n; - if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) - sb->sb_rptr -= sb->sb_datalen; - - return n; + struct sbuf *sb = &so->so_rcv; + char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ + + int n; + + DEBUG_CALL("sosendoob"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); + + if (so->so_urgc > 2048) + so->so_urgc = 2048; /* XXXX */ + + if (sb->sb_rptr < sb->sb_wptr) { + /* We can send it directly */ + n = slirp_send(so, sb->sb_rptr, so->so_urgc, + (MSG_OOB)); /* |MSG_DONTWAIT)); */ + } else { + /* + * Since there's no sendv or sendtov like writev, + * we must copy all data to a linear buffer then + * send it all + */ + uint32_t urgc = so->so_urgc; + int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (len > urgc) { + len = urgc; + } + memcpy(buff, sb->sb_rptr, len); + urgc -= len; + if (urgc) { + n = sb->sb_wptr - sb->sb_data; + if (n > urgc) { + n = urgc; + } + memcpy((buff + len), sb->sb_data, n); + len += n; + } + n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ +#ifdef DEBUG + if (n != len) { + DEBUG_ERROR("Didn't send all data urgently XXXXX"); + } +#endif + } + + if (n < 0) { + return n; + } + so->so_urgc -= n; + DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n, + so->so_urgc); + + sb->sb_cc -= n; + sb->sb_rptr += n; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + return n; } /* - * Write data from so_rcv to so's socket, + * Write data from so_rcv to so's socket, * updating all sbuf field as necessary */ -int -sowrite(so) - struct SLIRPsocket *so; +int sowrite(struct socket *so) { - int n,nn; - struct sbuf *sb = &so->so_rcv; - int len = sb->sb_cc; - struct iovec iov[2]; - - DEBUG_CALL("sowrite"); - DEBUG_ARG("so = %lx", (long)so); - - if (so->so_urgc) { - sosendoob(so); - if (sb->sb_cc == 0) - return 0; - } + int n, nn; + struct sbuf *sb = &so->so_rcv; + int len = sb->sb_cc; + struct iovec iov[2] = {{0, 0}, {0, 0}}; - /* - * No need to check if there's something to write, - * sowrite wouldn't have been called otherwise - */ - - len = sb->sb_cc; - - iov[0].iov_base = sb->sb_rptr; - if (sb->sb_rptr < sb->sb_wptr) { - iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; - /* Should never succeed, but... */ - if (iov[0].iov_len > len) iov[0].iov_len = len; - n = 1; - } else { - iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; - if (iov[0].iov_len > len) iov[0].iov_len = len; - len -= iov[0].iov_len; - if (len) { - iov[1].iov_base = sb->sb_data; - iov[1].iov_len = sb->sb_wptr - sb->sb_data; - if (iov[1].iov_len > len) iov[1].iov_len = len; - n = 2; - } else - n = 1; - } - /* Check if there's urgent data to send, and if so, send it */ + DEBUG_CALL("sowrite"); + DEBUG_ARG("so = %p", so); -#ifdef HAVE_READV - nn = writev(so->s, (const struct iovec *)iov, n); - - DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); -#else - nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); -#endif - /* This should never happen, but people tell me it does *shrug* */ - if (nn < 0 && (errno == EAGAIN || errno == EINTR)) - return 0; - - if (nn <= 0) { - DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", - so->so_state, errno)); - sofcantsendmore(so); - tcp_sockclosed(sototcpcb(so)); - return -1; - } - -#ifndef HAVE_READV - if (n == 2 && nn == iov[0].iov_len) { - int ret; - ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); - if (ret > 0) - nn += ret; + if (so->so_urgc) { + uint32_t expected = so->so_urgc; + if (sosendoob(so) < expected) { + /* Treat a short write as a fatal error too, + * rather than continuing on and sending the urgent + * data as if it were non-urgent and leaving the + * so_urgc count wrong. + */ + goto err_disconnected; } - DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); -#endif - - /* Update sbuf */ - sb->sb_cc -= nn; - sb->sb_rptr += nn; - if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) - sb->sb_rptr -= sb->sb_datalen; - - /* - * If in DRAIN mode, and there's no more data, set - * it CANTSENDMORE - */ - if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) - sofcantsendmore(so); - - return nn; + if (sb->sb_cc == 0) + return 0; + } + + /* + * No need to check if there's something to write, + * sowrite wouldn't have been called otherwise + */ + + iov[0].iov_base = sb->sb_rptr; + iov[1].iov_base = NULL; + iov[1].iov_len = 0; + if (sb->sb_rptr < sb->sb_wptr) { + iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (iov[0].iov_len > len) + iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_wptr - sb->sb_data; + if (iov[1].iov_len > len) + iov[1].iov_len = len; + n = 2; + } else + n = 1; + } + /* Check if there's urgent data to send, and if so, send it */ + + nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len, 0); + /* This should never happen, but people tell me it does *shrug* */ + if (nn < 0 && (errno == EAGAIN || errno == EINTR)) + return 0; + + if (nn <= 0) { + goto err_disconnected; + } + + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len, 0); + if (ret > 0) + nn += ret; + } + DEBUG_MISC(" ... wrote nn = %d bytes", nn); + + /* Update sbuf */ + sb->sb_cc -= nn; + sb->sb_rptr += nn; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + /* + * If in DRAIN mode, and there's no more data, set + * it CANTSENDMORE + */ + if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) + sofcantsendmore(so); + + return nn; + +err_disconnected: + DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d", + so->so_state, errno); + sofcantsendmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; } /* * recvfrom() a UDP socket */ -void -sorecvfrom(so) - struct SLIRPsocket *so; +void sorecvfrom(struct socket *so) { - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - - DEBUG_CALL("sorecvfrom"); - DEBUG_ARG("so = %lx", (long)so); - - if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ - char buff[256]; - int len; - - len = recvfrom(so->s, buff, 256, 0, - (struct sockaddr *)&addr, &addrlen); - /* XXX Check if reply is "correct"? */ - - if(len == -1 || len == 0) { - u_char code=ICMP_UNREACH_PORT; + struct sockaddr_storage addr; + struct sockaddr_storage saddr, daddr; + socklen_t addrlen = sizeof(struct sockaddr_storage); - if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; - else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; - - DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", - errno,strerror(errno))); - icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); - } else { - icmp_reflect(so->so_m); - so->so_m = 0; /* Don't m_free() it again! */ - } - /* No need for this socket anymore, udp_detach it */ - udp_detach(so); - } else { /* A "normal" UDP packet */ - struct SLIRPmbuf *m; - int len; - ioctlsockopt_t n; + DEBUG_CALL("sorecvfrom"); + DEBUG_ARG("so = %p", so); - if (!(m = m_get())) return; - m->m_data += if_maxlinkhdr; - - /* - * XXX Shouldn't FIONREAD packets destined for port 53, - * but I don't know the max packet size for DNS lookups - */ - len = M_FREEROOM(m); - /* if (so->so_fport != htons(53)) { */ - ioctlsocket(so->s, FIONREAD, &n); - - if (n > len) { - n = (m->m_data - m->m_dat) + m->m_len + n + 1; - m_inc(m, n); - len = M_FREEROOM(m); - } - /* } */ - - m->m_len = recvfrom(so->s, m->m_data, len, 0, - (struct sockaddr *)&addr, &addrlen); - DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", - m->m_len, errno,strerror(errno))); - if(m->m_len<0) { - u_char code=ICMP_UNREACH_PORT; + if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ + char buff[256]; + int len; - if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; - else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; - - DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); - icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); - m_free(m); - } else { - /* - * Hack: domain name lookup will be used the most for UDP, - * and since they'll only be used once there's no need - * for the 4 minute (or whatever) timeout... So we time them - * out much quicker (10 seconds for now...) - */ - if (so->so_expire) { - if (so->so_fport == htons(53)) - so->so_expire = curtime + SO_EXPIREFAST; - else - so->so_expire = curtime + SO_EXPIRE; - } + len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen); + /* XXX Check if reply is "correct"? */ - /* if (m->m_len == len) { - * m_inc(m, MINCSIZE); - * m->m_len = 0; - * } - */ - - /* - * If this packet was destined for CTL_ADDR, - * make it look like that's where it came from, done by udp_output - */ - udp_output(so, m, &addr); - } /* rx error */ - } /* if ping packet */ + if (len == -1 || len == 0) { + uint8_t code = ICMP_UNREACH_PORT; + + if (errno == EHOSTUNREACH) + code = ICMP_UNREACH_HOST; + else if (errno == ENETUNREACH) + code = ICMP_UNREACH_NET; + + DEBUG_MISC(" udp icmp rx errno = %d-%s", errno, strerror(errno)); + icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); + } else { + icmp_reflect(so->so_m); + so->so_m = NULL; /* Don't m_free() it again! */ + } + /* No need for this socket anymore, udp_detach it */ + udp_detach(so); + } else { /* A "normal" UDP packet */ + struct mbuf *m; + int len; +#ifdef _WIN32 + unsigned long n; +#else + int n; +#endif + + if (ioctlsocket(so->s, FIONREAD, &n) != 0) { + DEBUG_MISC(" ioctlsocket errno = %d-%s\n", errno, strerror(errno)); + return; + } + if (n == 0) { + return; + } + + m = m_get(so->slirp); + if (!m) { + return; + } + switch (so->so_ffamily) { + case AF_INET: + m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr); + break; + case AF_INET6: + m->m_data += + IF_MAXLINKHDR + sizeof(struct ip6) + sizeof(struct udphdr); + break; + default: + g_assert_not_reached(); + } + + /* + * XXX Shouldn't FIONREAD packets destined for port 53, + * but I don't know the max packet size for DNS lookups + */ + len = M_FREEROOM(m); + /* if (so->so_fport != htons(53)) { */ + + if (n > len) { + n = (m->m_data - m->m_dat) + m->m_len + n + 1; + m_inc(m, n); + len = M_FREEROOM(m); + } + /* } */ + + m->m_len = recvfrom(so->s, m->m_data, len, 0, (struct sockaddr *)&addr, + &addrlen); + DEBUG_MISC(" did recvfrom %d, errno = %d-%s", m->m_len, errno, + strerror(errno)); + if (m->m_len < 0) { + /* Report error as ICMP */ + switch (so->so_lfamily) { + uint8_t code; + case AF_INET: + code = ICMP_UNREACH_PORT; + + if (errno == EHOSTUNREACH) { + code = ICMP_UNREACH_HOST; + } else if (errno == ENETUNREACH) { + code = ICMP_UNREACH_NET; + } + + DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code); + icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, + strerror(errno)); + break; + case AF_INET6: + code = ICMP6_UNREACH_PORT; + + if (errno == EHOSTUNREACH) { + code = ICMP6_UNREACH_ADDRESS; + } else if (errno == ENETUNREACH) { + code = ICMP6_UNREACH_NO_ROUTE; + } + + DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code); + icmp6_send_error(so->so_m, ICMP6_UNREACH, code); + break; + default: + g_assert_not_reached(); + } + m_free(m); + } else { + /* + * Hack: domain name lookup will be used the most for UDP, + * and since they'll only be used once there's no need + * for the 4 minute (or whatever) timeout... So we time them + * out much quicker (10 seconds for now...) + */ + if (so->so_expire) { + if (so->so_fport == htons(53)) + so->so_expire = curtime + SO_EXPIREFAST; + else + so->so_expire = curtime + SO_EXPIRE; + } + + /* + * If this packet was destined for CTL_ADDR, + * make it look like that's where it came from + */ + saddr = addr; + sotranslate_in(so, &saddr); + daddr = so->lhost.ss; + + switch (so->so_ffamily) { + case AF_INET: + udp_output(so, m, (struct sockaddr_in *)&saddr, + (struct sockaddr_in *)&daddr, so->so_iptos); + break; + case AF_INET6: + udp6_output(so, m, (struct sockaddr_in6 *)&saddr, + (struct sockaddr_in6 *)&daddr); + break; + default: + g_assert_not_reached(); + } + } /* rx error */ + } /* if ping packet */ } /* * sendto() a socket */ -int -sosendto(so, m) - struct SLIRPsocket *so; - struct SLIRPmbuf *m; +int sosendto(struct socket *so, struct mbuf *m) { - int ret; - struct sockaddr_in addr; + int ret; + struct sockaddr_storage addr; - DEBUG_CALL("sosendto"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { - /* It's an alias */ - switch(ntohl(so->so_faddr.s_addr) & 0xff) { - case CTL_DNS: - addr.sin_addr = dns_addr; - break; - case CTL_ALIAS: - default: - addr.sin_addr = loopback_addr; - break; - } - } else - addr.sin_addr = so->so_faddr; - addr.sin_port = so->so_fport; + DEBUG_CALL("sosendto"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m = %p", m); - DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); - - /* Don't care what port we get */ - ret = sendto(so->s, m->m_data, m->m_len, 0, - (struct sockaddr *)&addr, sizeof (struct sockaddr)); - if (ret < 0) - return -1; - - /* - * Kill the socket if there's no reply in 4 minutes, - * but only if it's an expirable socket - */ - if (so->so_expire) - so->so_expire = curtime + SO_EXPIRE; - so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ - return 0; + addr = so->fhost.ss; + DEBUG_CALL(" sendto()ing)"); + if (sotranslate_out(so, &addr) < 0) { + return -1; + } + + /* Don't care what port we get */ + ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr, + sockaddr_size(&addr)); + if (ret < 0) + return -1; + + /* + * Kill the socket if there's no reply in 4 minutes, + * but only if it's an expirable socket + */ + if (so->so_expire) + so->so_expire = curtime + SO_EXPIRE; + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */ + return 0; } /* - * XXX This should really be tcp_listen + * Listen for incoming TCP connections */ -struct SLIRPsocket * -solisten(port, laddr, lport, flags) - u_int port; - u_int32_t laddr; - u_int lport; - int flags; +struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, + uint32_t laddr, unsigned lport, int flags) { - struct sockaddr_in addr; - struct SLIRPsocket *so; - int s; - socklen_t addrlen = sizeof(addr); - int opt = 1; + /* TODO: IPv6 */ + struct sockaddr_in addr; + struct socket *so; + int s, opt = 1; + socklen_t addrlen = sizeof(addr); + memset(&addr, 0, addrlen); - DEBUG_CALL("solisten"); - DEBUG_ARG("port = %d", port); - DEBUG_ARG("laddr = %x", laddr); - DEBUG_ARG("lport = %d", lport); - DEBUG_ARG("flags = %x", flags); - - if ((so = socreate()) == NULL) { - /* free(so); Not sofree() ??? free(NULL) == NOP */ - return NULL; - } - - /* Don't tcp_attach... we don't need so_snd nor so_rcv */ - if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { - free(so); - return NULL; - } - insque(so,&tcb); - - /* - * SS_FACCEPTONCE sockets must time out. - */ - if (flags & SS_FACCEPTONCE) - so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; - - so->so_state = (SS_FACCEPTCONN|flags); - so->so_lport = lport; /* Kept in network format */ - so->so_laddr.s_addr = laddr; /* Ditto */ - - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = port; - - if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || - (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || - (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || - (listen(s,1) < 0)) { - int tmperrno = errno; /* Don't clobber the real reason we failed */ - - close(s); - sofree(so); - /* Restore the real errno */ + DEBUG_CALL("tcp_listen"); + DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){ .s_addr = haddr })); + DEBUG_ARG("hport = %d", ntohs(hport)); + DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){ .s_addr = laddr })); + DEBUG_ARG("lport = %d", ntohs(lport)); + DEBUG_ARG("flags = %x", flags); + + so = socreate(slirp); + + /* Don't tcp_attach... we don't need so_snd nor so_rcv */ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { + g_free(so); + return NULL; + } + insque(so, &slirp->tcb); + + /* + * SS_FACCEPTONCE sockets must time out. + */ + if (flags & SS_FACCEPTONCE) + so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT * 2; + + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= (SS_FACCEPTCONN | flags); + so->so_lfamily = AF_INET; + so->so_lport = lport; /* Kept in network format */ + so->so_laddr.s_addr = laddr; /* Ditto */ + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = haddr; + addr.sin_port = hport; + + if (((s = slirp_socket(AF_INET, SOCK_STREAM, 0)) < 0) || + (slirp_socket_set_fast_reuse(s) < 0) || + (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) || + (listen(s, 1) < 0)) { + int tmperrno = errno; /* Don't clobber the real reason we failed */ + + if (s >= 0) { + closesocket(s); + } + sofree(so); + /* Restore the real errno */ #ifdef _WIN32 - WSASetLastError(tmperrno); + WSASetLastError(tmperrno); #else - errno = tmperrno; + errno = tmperrno; #endif - return NULL; - } - setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); - - getsockname(s,(struct sockaddr *)&addr,&addrlen); - so->so_fport = addr.sin_port; - if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) - so->so_faddr = alias_addr; - else - so->so_faddr = addr.sin_addr; + return NULL; + } + setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); + opt = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int)); - so->s = s; - return so; -} + getsockname(s, (struct sockaddr *)&addr, &addrlen); + so->so_ffamily = AF_INET; + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || + addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = slirp->vhost_addr; + else + so->so_faddr = addr.sin_addr; -/* - * Data is available in so_rcv - * Just write() the data to the socket - * XXX not yet... - */ -void -sorwakeup(so) - struct SLIRPsocket *so; -{ -/* sowrite(so); */ -/* FD_CLR(so->s,&writefds); */ -} - -/* - * Data has been freed in so_snd - * We have room for a read() if we want to - * For now, don't read, it'll be done in the main loop - */ -void -sowwakeup(so) - struct SLIRPsocket *so; -{ - /* Nothing, yet */ + so->s = s; + return so; } /* @@ -652,83 +763,192 @@ sowwakeup(so) * The socket state stuff needs work, these often get call 2 or 3 * times each when only 1 was needed */ -void -soisfconnecting(so) - register struct SLIRPsocket *so; +void soisfconnecting(struct socket *so) { - so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| - SS_FCANTSENDMORE|SS_FWDRAIN); - so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ + so->so_state &= ~(SS_NOFDREF | SS_ISFCONNECTED | SS_FCANTRCVMORE | + SS_FCANTSENDMORE | SS_FWDRAIN); + so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ } -void -soisfconnected(so) - register struct SLIRPsocket *so; +void soisfconnected(struct socket *so) { - so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); - so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ + so->so_state &= ~(SS_ISFCONNECTING | SS_FWDRAIN | SS_NOFDREF); + so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ } -void -sofcantrcvmore(so) - struct SLIRPsocket *so; +static void sofcantrcvmore(struct socket *so) { - if ((so->so_state & SS_NOFDREF) == 0) { - shutdown(so->s,0); - if(global_writefds) { - FD_CLR(so->s,global_writefds); - } - } - so->so_state &= ~(SS_ISFCONNECTING); - if (so->so_state & SS_FCANTSENDMORE) - so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ - else - so->so_state |= SS_FCANTRCVMORE; + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s, 0); + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTSENDMORE) { + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; /* Don't select it */ + } else { + so->so_state |= SS_FCANTRCVMORE; + } } -void -sofcantsendmore(so) - struct SLIRPsocket *so; +static void sofcantsendmore(struct socket *so) { - if ((so->so_state & SS_NOFDREF) == 0) { - shutdown(so->s,1); /* send FIN to fhost */ - if (global_readfds) { - FD_CLR(so->s,global_readfds); - } - if (global_xfds) { - FD_CLR(so->s,global_xfds); - } - } - so->so_state &= ~(SS_ISFCONNECTING); - if (so->so_state & SS_FCANTRCVMORE) - so->so_state = SS_NOFDREF; /* as above */ - else - so->so_state |= SS_FCANTSENDMORE; -} - -void -soisfdisconnected(so) - struct SLIRPsocket *so; -{ -/* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ -/* close(so->s); */ -/* so->so_state = SS_ISFDISCONNECTED; */ - /* - * XXX Do nothing ... ? - */ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s, 1); /* send FIN to fhost */ + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTRCVMORE) { + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; /* as above */ + } else { + so->so_state |= SS_FCANTSENDMORE; + } } /* * Set write drain mode * Set CANTSENDMORE once all data has been write()n */ -void -sofwdrain(so) - struct SLIRPsocket *so; +void sofwdrain(struct socket *so) { - if (so->so_rcv.sb_cc) - so->so_state |= SS_FWDRAIN; - else - sofcantsendmore(so); + if (so->so_rcv.sb_cc) + so->so_state |= SS_FWDRAIN; + else + sofcantsendmore(so); } +static bool sotranslate_out4(Slirp *s, struct socket *so, struct sockaddr_in *sin) +{ + if (!s->disable_dns && so->so_faddr.s_addr == s->vnameserver_addr.s_addr) { + return so->so_fport == htons(53) && get_dns_addr(&sin->sin_addr) >= 0; + } + + if (so->so_faddr.s_addr == s->vhost_addr.s_addr || + so->so_faddr.s_addr == 0xffffffff) { + if (s->disable_host_loopback) { + return false; + } + + sin->sin_addr = loopback_addr; + } + + return true; +} + +static bool sotranslate_out6(Slirp *s, struct socket *so, struct sockaddr_in6 *sin) +{ + if (!s->disable_dns && in6_equal(&so->so_faddr6, &s->vnameserver_addr6)) { + uint32_t scope_id; + if (so->so_fport == htons(53) && get_dns6_addr(&sin->sin6_addr, &scope_id) >= 0) { + sin->sin6_scope_id = scope_id; + return true; + } + return false; + } + + if (in6_equal_net(&so->so_faddr6, &s->vprefix_addr6, s->vprefix_len) || + in6_equal(&so->so_faddr6, &(struct in6_addr)ALLNODES_MULTICAST)) { + if (s->disable_host_loopback) { + return false; + } + + sin->sin6_addr = in6addr_loopback; + } + + return true; +} + + +/* + * Translate addr in host addr when it is a virtual address + */ +int sotranslate_out(struct socket *so, struct sockaddr_storage *addr) +{ + bool ok = true; + + switch (addr->ss_family) { + case AF_INET: + ok = sotranslate_out4(so->slirp, so, (struct sockaddr_in *)addr); + break; + case AF_INET6: + ok = sotranslate_out6(so->slirp, so, (struct sockaddr_in6 *)addr); + break; + } + + if (!ok) { + errno = EPERM; + return -1; + } + + return 0; +} + +void sotranslate_in(struct socket *so, struct sockaddr_storage *addr) +{ + Slirp *slirp = so->slirp; + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; + + switch (addr->ss_family) { + case AF_INET: + if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == + slirp->vnetwork_addr.s_addr) { + uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; + + if ((so->so_faddr.s_addr & inv_mask) == inv_mask) { + sin->sin_addr = slirp->vhost_addr; + } else if (sin->sin_addr.s_addr == loopback_addr.s_addr || + so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { + sin->sin_addr = so->so_faddr; + } + } + break; + + case AF_INET6: + if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, + slirp->vprefix_len)) { + if (in6_equal(&sin6->sin6_addr, &in6addr_loopback) || + !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) { + sin6->sin6_addr = so->so_faddr6; + } + } + break; + + default: + break; + } +} + +/* + * Translate connections from localhost to the real hostname + */ +void sotranslate_accept(struct socket *so) +{ + Slirp *slirp = so->slirp; + + switch (so->so_ffamily) { + case AF_INET: + if (so->so_faddr.s_addr == INADDR_ANY || + (so->so_faddr.s_addr & loopback_mask) == + (loopback_addr.s_addr & loopback_mask)) { + so->so_faddr = slirp->vhost_addr; + } + break; + + case AF_INET6: + if (in6_equal(&so->so_faddr6, &in6addr_any) || + in6_equal(&so->so_faddr6, &in6addr_loopback)) { + so->so_faddr6 = slirp->vhost_addr6; + } + break; + + default: + break; + } +} + +void sodrop(struct socket *s, int num) +{ + if (sbdrop(&s->so_snd, num)) { + s->slirp->cb->notify(s->slirp->opaque); + } +} diff --git a/src/network/slirp/socket.h b/src/network/slirp/socket.h index 3a777934a..a6a1e5e21 100644 --- a/src/network/slirp/socket.h +++ b/src/network/slirp/socket.h @@ -1,14 +1,12 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -/* MINE */ +#ifndef SLIRP_SOCKET_H +#define SLIRP_SOCKET_H -#ifndef _SLIRP_SOCKET_H_ -#define _SLIRP_SOCKET_H_ +#include "misc.h" #define SO_EXPIRE 240000 #define SO_EXPIREFAST 10000 @@ -17,40 +15,59 @@ * Our socket structure */ -struct SLIRPsocket { - struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */ +union slirp_sockaddr { + struct sockaddr_storage ss; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; - int s; /* The actual socket */ +struct socket { + struct socket *so_next, *so_prev; /* For a linked list of sockets */ - /* XXX union these with not-yet-used sbuf params */ - struct SLIRPmbuf *so_m; /* Pointer to the original SYN packet, - * for non-blocking connect()'s, and - * PING reply's */ - struct tcpiphdr *so_ti; /* Pointer to the original ti within - * so_mconn, for non-blocking connections */ - int so_urgc; - struct in_addr so_faddr; /* foreign host table entry */ - struct in_addr so_laddr; /* local host table entry */ - u_int16_t so_fport; /* foreign port */ - u_int16_t so_lport; /* local port */ - - u_int8_t so_iptos; /* Type of service */ - u_int8_t so_emu; /* Is the socket emulated? */ - - u_char so_type; /* Type of socket, UDP or TCP */ - int so_state; /* internal state flags SS_*, below */ - - struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ - u_int so_expire; /* When the socket will expire */ - - int so_queued; /* Number of packets queued from this socket */ - int so_nqueued; /* Number of packets queued in a row - * Used to determine when to "downgrade" a session - * from fastq to batchq */ - - struct sbuf so_rcv; /* Receive buffer */ - struct sbuf so_snd; /* Send buffer */ - void * extra; /* Extra pointer */ + int s; /* The actual socket */ + struct gfwd_list *guestfwd; + + int pollfds_idx; /* GPollFD GArray index */ + + Slirp *slirp; /* managing slirp instance */ + + /* XXX union these with not-yet-used sbuf params */ + struct mbuf *so_m; /* Pointer to the original SYN packet, + * for non-blocking connect()'s, and + * PING reply's */ + struct tcpiphdr *so_ti; /* Pointer to the original ti within + * so_mconn, for non-blocking connections */ + uint32_t so_urgc; + union slirp_sockaddr fhost; /* Foreign host */ +#define so_faddr fhost.sin.sin_addr +#define so_fport fhost.sin.sin_port +#define so_faddr6 fhost.sin6.sin6_addr +#define so_fport6 fhost.sin6.sin6_port +#define so_ffamily fhost.ss.ss_family + + union slirp_sockaddr lhost; /* Local host */ +#define so_laddr lhost.sin.sin_addr +#define so_lport lhost.sin.sin_port +#define so_laddr6 lhost.sin6.sin6_addr +#define so_lport6 lhost.sin6.sin6_port +#define so_lfamily lhost.ss.ss_family + + uint8_t so_iptos; /* Type of service */ + uint8_t so_emu; /* Is the socket emulated? */ + + uint8_t so_type; /* Type of socket, UDP or TCP */ + int32_t so_state; /* internal state flags SS_*, below */ + + struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ + unsigned so_expire; /* When the socket will expire */ + + int so_queued; /* Number of packets queued from this socket */ + int so_nqueued; /* Number of packets queued in a row + * Used to determine when to "downgrade" a session + * from fastq to batchq */ + + struct sbuf so_rcv; /* Receive buffer */ + struct sbuf so_snd; /* Send buffer */ }; @@ -58,47 +75,90 @@ struct SLIRPsocket { * Socket state bits. (peer means the host on the Internet, * local host means the host on the other end of the modem) */ -#define SS_NOFDREF 0x001 /* No fd reference */ +#define SS_NOFDREF 0x001 /* No fd reference */ -#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ -#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ -#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ -#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ -/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ -#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ +#define SS_ISFCONNECTING \ + 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ +#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ +#define SS_FCANTRCVMORE \ + 0x008 /* Socket can't receive more from peer (for half-closes) */ +#define SS_FCANTSENDMORE \ + 0x010 /* Socket can't send more to peer (for half-closes) */ +#define SS_FWDRAIN \ + 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ -#define SS_CTL 0x080 -#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ -#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ +#define SS_CTL 0x080 +#define SS_FACCEPTCONN \ + 0x100 /* Socket is accepting connections from a host on the internet */ +#define SS_FACCEPTONCE \ + 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ -extern struct SLIRPsocket tcb; +#define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */ +#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */ +#define SS_INCOMING \ + 0x2000 /* Connection was initiated by a host on the internet */ + +static inline int sockaddr_equal(struct sockaddr_storage *a, + struct sockaddr_storage *b) +{ + if (a->ss_family != b->ss_family) { + return 0; + } + + switch (a->ss_family) { + case AF_INET: { + struct sockaddr_in *a4 = (struct sockaddr_in *)a; + struct sockaddr_in *b4 = (struct sockaddr_in *)b; + return a4->sin_addr.s_addr == b4->sin_addr.s_addr && + a4->sin_port == b4->sin_port; + } + case AF_INET6: { + struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)a; + struct sockaddr_in6 *b6 = (struct sockaddr_in6 *)b; + return (in6_equal(&a6->sin6_addr, &b6->sin6_addr) && + a6->sin6_port == b6->sin6_port); + } + default: + g_assert_not_reached(); + } + + return 0; +} + +static inline socklen_t sockaddr_size(struct sockaddr_storage *a) +{ + switch (a->ss_family) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + g_assert_not_reached(); + } +} + +struct socket *solookup(struct socket **, struct socket *, + struct sockaddr_storage *, struct sockaddr_storage *); +struct socket *socreate(Slirp *); +void sofree(struct socket *); +int soread(struct socket *); +int sorecvoob(struct socket *); +int sosendoob(struct socket *); +int sowrite(struct socket *); +void sorecvfrom(struct socket *); +int sosendto(struct socket *, struct mbuf *); +struct socket *tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int); +void soisfconnecting(register struct socket *); +void soisfconnected(register struct socket *); +void sofwdrain(struct socket *); +struct iovec; /* For win32 */ +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np); +int soreadbuf(struct socket *so, const char *buf, int size); + +int sotranslate_out(struct socket *, struct sockaddr_storage *); +void sotranslate_in(struct socket *, struct sockaddr_storage *); +void sotranslate_accept(struct socket *); +void sodrop(struct socket *, int num); -#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) -struct iovec { - char *iov_base; - size_t iov_len; -}; -#endif - -void so_init _P((void)); -struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int)); -struct SLIRPsocket * socreate _P((void)); -void sofree _P((struct SLIRPsocket *)); -int soread _P((struct SLIRPsocket *)); -void sorecvoob _P((struct SLIRPsocket *)); -int sosendoob _P((struct SLIRPsocket *)); -int sowrite _P((struct SLIRPsocket *)); -void sorecvfrom _P((struct SLIRPsocket *)); -int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int)); -void sorwakeup _P((struct SLIRPsocket *)); -void sowwakeup _P((struct SLIRPsocket *)); -void soisfconnecting _P((register struct SLIRPsocket *)); -void soisfconnected _P((register struct SLIRPsocket *)); -void sofcantrcvmore _P((struct SLIRPsocket *)); -void sofcantsendmore _P((struct SLIRPsocket *)); -void soisfdisconnected _P((struct SLIRPsocket *)); -void sofwdrain _P((struct SLIRPsocket *)); - -#endif /* _SOCKET_H_ */ +#endif /* SLIRP_SOCKET_H */ diff --git a/src/network/slirp/state.c b/src/network/slirp/state.c new file mode 100644 index 000000000..22af77b25 --- /dev/null +++ b/src/network/slirp/state.c @@ -0,0 +1,379 @@ +/* SPDX-License-Identifier: MIT */ +/* + * libslirp + * + * Copyright (c) 2004-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "slirp.h" +#include "vmstate.h" +#include "stream.h" + +static int slirp_tcp_post_load(void *opaque, int version) +{ + tcp_template((struct tcpcb *)opaque); + + return 0; +} + +static const VMStateDescription vmstate_slirp_tcp = { + .name = "slirp-tcp", + .version_id = 0, + .post_load = slirp_tcp_post_load, + .fields = (VMStateField[]){ VMSTATE_INT16(t_state, struct tcpcb), + VMSTATE_INT16_ARRAY(t_timer, struct tcpcb, + TCPT_NTIMERS), + VMSTATE_INT16(t_rxtshift, struct tcpcb), + VMSTATE_INT16(t_rxtcur, struct tcpcb), + VMSTATE_INT16(t_dupacks, struct tcpcb), + VMSTATE_UINT16(t_maxseg, struct tcpcb), + VMSTATE_UINT8(t_force, struct tcpcb), + VMSTATE_UINT16(t_flags, struct tcpcb), + VMSTATE_UINT32(snd_una, struct tcpcb), + VMSTATE_UINT32(snd_nxt, struct tcpcb), + VMSTATE_UINT32(snd_up, struct tcpcb), + VMSTATE_UINT32(snd_wl1, struct tcpcb), + VMSTATE_UINT32(snd_wl2, struct tcpcb), + VMSTATE_UINT32(iss, struct tcpcb), + VMSTATE_UINT32(snd_wnd, struct tcpcb), + VMSTATE_UINT32(rcv_wnd, struct tcpcb), + VMSTATE_UINT32(rcv_nxt, struct tcpcb), + VMSTATE_UINT32(rcv_up, struct tcpcb), + VMSTATE_UINT32(irs, struct tcpcb), + VMSTATE_UINT32(rcv_adv, struct tcpcb), + VMSTATE_UINT32(snd_max, struct tcpcb), + VMSTATE_UINT32(snd_cwnd, struct tcpcb), + VMSTATE_UINT32(snd_ssthresh, struct tcpcb), + VMSTATE_INT16(t_idle, struct tcpcb), + VMSTATE_INT16(t_rtt, struct tcpcb), + VMSTATE_UINT32(t_rtseq, struct tcpcb), + VMSTATE_INT16(t_srtt, struct tcpcb), + VMSTATE_INT16(t_rttvar, struct tcpcb), + VMSTATE_UINT16(t_rttmin, struct tcpcb), + VMSTATE_UINT32(max_sndwnd, struct tcpcb), + VMSTATE_UINT8(t_oobflags, struct tcpcb), + VMSTATE_UINT8(t_iobc, struct tcpcb), + VMSTATE_INT16(t_softerror, struct tcpcb), + VMSTATE_UINT8(snd_scale, struct tcpcb), + VMSTATE_UINT8(rcv_scale, struct tcpcb), + VMSTATE_UINT8(request_r_scale, struct tcpcb), + VMSTATE_UINT8(requested_s_scale, struct tcpcb), + VMSTATE_UINT32(ts_recent, struct tcpcb), + VMSTATE_UINT32(ts_recent_age, struct tcpcb), + VMSTATE_UINT32(last_ack_sent, struct tcpcb), + VMSTATE_END_OF_LIST() } +}; + +/* The sbuf has a pair of pointers that are migrated as offsets; + * we calculate the offsets and restore the pointers using + * pre_save/post_load on a tmp structure. + */ +struct sbuf_tmp { + struct sbuf *parent; + uint32_t roff, woff; +}; + +static int sbuf_tmp_pre_save(void *opaque) +{ + struct sbuf_tmp *tmp = opaque; + tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data; + tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data; + + return 0; +} + +static int sbuf_tmp_post_load(void *opaque, int version) +{ + struct sbuf_tmp *tmp = opaque; + uint32_t requested_len = tmp->parent->sb_datalen; + + /* Allocate the buffer space used by the field after the tmp */ + sbreserve(tmp->parent, tmp->parent->sb_datalen); + + if (tmp->woff >= requested_len || tmp->roff >= requested_len) { + g_critical("invalid sbuf offsets r/w=%u/%u len=%u", tmp->roff, + tmp->woff, requested_len); + return -EINVAL; + } + + tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff; + tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff; + + return 0; +} + + +static const VMStateDescription vmstate_slirp_sbuf_tmp = { + .name = "slirp-sbuf-tmp", + .post_load = sbuf_tmp_post_load, + .pre_save = sbuf_tmp_pre_save, + .version_id = 0, + .fields = (VMStateField[]){ VMSTATE_UINT32(woff, struct sbuf_tmp), + VMSTATE_UINT32(roff, struct sbuf_tmp), + VMSTATE_END_OF_LIST() } +}; + +static const VMStateDescription vmstate_slirp_sbuf = { + .name = "slirp-sbuf", + .version_id = 0, + .fields = (VMStateField[]){ VMSTATE_UINT32(sb_cc, struct sbuf), + VMSTATE_UINT32(sb_datalen, struct sbuf), + VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp, + vmstate_slirp_sbuf_tmp), + VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0, + NULL, sb_datalen), + VMSTATE_END_OF_LIST() } +}; + +static bool slirp_older_than_v4(void *opaque, int version_id) +{ + return version_id < 4; +} + +static bool slirp_family_inet(void *opaque, int version_id) +{ + union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque; + return ssa->ss.ss_family == AF_INET; +} + +static int slirp_socket_pre_load(void *opaque) +{ + struct socket *so = opaque; + + tcp_attach(so); + /* Older versions don't load these fields */ + so->so_ffamily = AF_INET; + so->so_lfamily = AF_INET; + return 0; +} + +#ifndef _WIN32 +#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t) +#else +/* Win uses u_long rather than uint32_t - but it's still 32bits long */ +#define VMSTATE_SIN4_ADDR(f, s, t) \ + VMSTATE_SINGLE_TEST(f, s, t, 0, slirp_vmstate_info_uint32, u_long) +#endif + +/* The OS provided ss_family field isn't that portable; it's size + * and type varies (16/8 bit, signed, unsigned) + * and the values it contains aren't fully portable. + */ +typedef struct SS_FamilyTmpStruct { + union slirp_sockaddr *parent; + uint16_t portable_family; +} SS_FamilyTmpStruct; + +#define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */ +#define SS_FAMILY_MIG_IPV6 10 /* Linux */ +#define SS_FAMILY_MIG_OTHER 0xffff + +static int ss_family_pre_save(void *opaque) +{ + SS_FamilyTmpStruct *tss = opaque; + + tss->portable_family = SS_FAMILY_MIG_OTHER; + + if (tss->parent->ss.ss_family == AF_INET) { + tss->portable_family = SS_FAMILY_MIG_IPV4; + } else if (tss->parent->ss.ss_family == AF_INET6) { + tss->portable_family = SS_FAMILY_MIG_IPV6; + } + + return 0; +} + +static int ss_family_post_load(void *opaque, int version_id) +{ + SS_FamilyTmpStruct *tss = opaque; + + switch (tss->portable_family) { + case SS_FAMILY_MIG_IPV4: + tss->parent->ss.ss_family = AF_INET; + break; + case SS_FAMILY_MIG_IPV6: + case 23: /* compatibility: AF_INET6 from mingw */ + case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */ + tss->parent->ss.ss_family = AF_INET6; + break; + default: + g_critical("invalid ss_family type %x", tss->portable_family); + return -EINVAL; + } + + return 0; +} + +static const VMStateDescription vmstate_slirp_ss_family = { + .name = "slirp-socket-addr/ss_family", + .pre_save = ss_family_pre_save, + .post_load = ss_family_post_load, + .fields = + (VMStateField[]){ VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct), + VMSTATE_END_OF_LIST() } +}; + +static const VMStateDescription vmstate_slirp_socket_addr = { + .name = "slirp-socket-addr", + .version_id = 4, + .fields = + (VMStateField[]){ + VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct, + vmstate_slirp_ss_family), + VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr, + slirp_family_inet), + VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr, + slirp_family_inet), + +#if 0 + /* Untested: Needs checking by someone with IPv6 test */ + VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr, + slirp_family_inet6), + VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr, + slirp_family_inet6), + VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr, + slirp_family_inet6), + VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr, + slirp_family_inet6), +#endif + + VMSTATE_END_OF_LIST() } +}; + +static const VMStateDescription vmstate_slirp_socket = { + .name = "slirp-socket", + .version_id = 4, + .pre_load = slirp_socket_pre_load, + .fields = + (VMStateField[]){ + VMSTATE_UINT32(so_urgc, struct socket), + /* Pre-v4 versions */ + VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket, + slirp_older_than_v4), + VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket, + slirp_older_than_v4), + VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4), + VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4), + /* v4 and newer */ + VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr, + union slirp_sockaddr), + VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr, + union slirp_sockaddr), + + VMSTATE_UINT8(so_iptos, struct socket), + VMSTATE_UINT8(so_emu, struct socket), + VMSTATE_UINT8(so_type, struct socket), + VMSTATE_INT32(so_state, struct socket), + VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf, + struct sbuf), + VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf, + struct sbuf), + VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp, + struct tcpcb), + VMSTATE_END_OF_LIST() } +}; + +static const VMStateDescription vmstate_slirp_bootp_client = { + .name = "slirp_bootpclient", + .fields = (VMStateField[]){ VMSTATE_UINT16(allocated, BOOTPClient), + VMSTATE_BUFFER(macaddr, BOOTPClient), + VMSTATE_END_OF_LIST() } +}; + +static const VMStateDescription vmstate_slirp = { + .name = "slirp", + .version_id = 4, + .fields = (VMStateField[]){ VMSTATE_UINT16_V(ip_id, Slirp, 2), + VMSTATE_STRUCT_ARRAY( + bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3, + vmstate_slirp_bootp_client, BOOTPClient), + VMSTATE_END_OF_LIST() } +}; + +void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque) +{ + struct gfwd_list *ex_ptr; + SlirpOStream f = { + .write_cb = write_cb, + .opaque = opaque, + }; + + for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->write_cb) { + struct socket *so; + so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr, + ntohs(ex_ptr->ex_fport)); + if (!so) { + continue; + } + + slirp_ostream_write_u8(&f, 42); + slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so); + } + slirp_ostream_write_u8(&f, 0); + + slirp_vmstate_save_state(&f, &vmstate_slirp, slirp); +} + + +int slirp_state_load(Slirp *slirp, int version_id, SlirpReadCb read_cb, + void *opaque) +{ + struct gfwd_list *ex_ptr; + SlirpIStream f = { + .read_cb = read_cb, + .opaque = opaque, + }; + + while (slirp_istream_read_u8(&f)) { + int ret; + struct socket *so = socreate(slirp); + + ret = + slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id); + if (ret < 0) { + return ret; + } + + if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) != + slirp->vnetwork_addr.s_addr) { + return -EINVAL; + } + for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->write_cb && + so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr && + so->so_fport == ex_ptr->ex_fport) { + break; + } + } + if (!ex_ptr) { + return -EINVAL; + } + + so->guestfwd = ex_ptr; + } + + return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id); +} + +int slirp_state_version(void) +{ + return 4; +} diff --git a/src/network/slirp/stream.c b/src/network/slirp/stream.c new file mode 100644 index 000000000..541986e6c --- /dev/null +++ b/src/network/slirp/stream.c @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: MIT */ +/* + * libslirp io streams + * + * Copyright (c) 2018 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "stream.h" +#include + +bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size) +{ + return f->read_cb(buf, size, f->opaque) == size; +} + +bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size) +{ + return f->write_cb(buf, size, f->opaque) == size; +} + +uint8_t slirp_istream_read_u8(SlirpIStream *f) +{ + uint8_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return b; + } + + return 0; +} + +bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b) +{ + return slirp_ostream_write(f, &b, sizeof(b)); +} + +uint16_t slirp_istream_read_u16(SlirpIStream *f) +{ + uint16_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GUINT16_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b) +{ + b = GUINT16_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} + +uint32_t slirp_istream_read_u32(SlirpIStream *f) +{ + uint32_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GUINT32_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b) +{ + b = GUINT32_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} + +int16_t slirp_istream_read_i16(SlirpIStream *f) +{ + int16_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GINT16_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b) +{ + b = GINT16_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} + +int32_t slirp_istream_read_i32(SlirpIStream *f) +{ + int32_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GINT32_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b) +{ + b = GINT32_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} diff --git a/src/network/slirp/stream.h b/src/network/slirp/stream.h new file mode 100644 index 000000000..08bb5b661 --- /dev/null +++ b/src/network/slirp/stream.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#ifndef STREAM_H_ +#define STREAM_H_ + +#include "libslirp.h" + +typedef struct SlirpIStream { + SlirpReadCb read_cb; + void *opaque; +} SlirpIStream; + +typedef struct SlirpOStream { + SlirpWriteCb write_cb; + void *opaque; +} SlirpOStream; + +bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size); +bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size); + +uint8_t slirp_istream_read_u8(SlirpIStream *f); +bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b); + +uint16_t slirp_istream_read_u16(SlirpIStream *f); +bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b); + +uint32_t slirp_istream_read_u32(SlirpIStream *f); +bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b); + +int16_t slirp_istream_read_i16(SlirpIStream *f); +bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b); + +int32_t slirp_istream_read_i32(SlirpIStream *f); +bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b); + +#endif /* STREAM_H_ */ diff --git a/src/network/slirp/tcp.h b/src/network/slirp/tcp.h index 5df25a8f0..9c4a6b693 100644 --- a/src/network/slirp/tcp.h +++ b/src/network/slirp/tcp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -30,92 +31,81 @@ * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp */ -#ifndef _TCP_H_ -#define _TCP_H_ +#ifndef TCP_H +#define TCP_H -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t tcp_seq; -#else -typedef u_int32_t tcp_seq; -#endif +#include -#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ -#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ +typedef uint32_t tcp_seq; -extern int tcp_rcvspace; -extern int tcp_sndspace; -extern struct SLIRPsocket *tcp_last_so; +#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ +#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ -#define TCP_SNDSPACE 8192 -#define TCP_RCVSPACE 8192 +#define TCP_SNDSPACE 1024 * 128 +#define TCP_RCVSPACE 1024 * 128 +#define TCP_MAXSEG_MAX 32768 /* * TCP header. * Per RFC 793, September, 1981. */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - +#define tcphdr slirp_tcphdr struct tcphdr { - u_int16_t th_sport; /* source port */ - u_int16_t th_dport; /* destination port */ - tcp_seq th_seq; /* sequence number */ - tcp_seq th_ack; /* acknowledgement number */ -#ifdef WORDS_BIGENDIAN - u_char th_off:4, /* data offset */ - th_x2:4; /* (unused) */ + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + uint8_t th_off : 4, /* data offset */ + th_x2 : 4; /* (unused) */ #else - u_char th_x2:4, /* (unused) */ - th_off:4; /* data offset */ -#endif - u_int8_t th_flags; -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 - u_int16_t th_win; /* window */ - u_int16_t th_sum; /* checksum */ - u_int16_t th_urp; /* urgent pointer */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) + uint8_t th_x2 : 4, /* (unused) */ + th_off : 4; /* data offset */ #endif + uint8_t th_flags; + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +}; #include "tcp_var.h" -#define TCPOPT_EOL 0 -#define TCPOPT_NOP 1 -#define TCPOPT_MAXSEG 2 -#define TCPOLEN_MAXSEG 4 -#define TCPOPT_WINDOW 3 -#define TCPOLEN_WINDOW 3 -#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ -#define TCPOLEN_SACK_PERMITTED 2 -#define TCPOPT_SACK 5 /* Experimental */ -#define TCPOPT_TIMESTAMP 8 -#define TCPOLEN_TIMESTAMP 10 -#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ +#ifndef TH_FIN +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#endif -#define TCPOPT_TSTAMP_HDR \ - (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) +#ifndef TCPOPT_EOL +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOPT_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 -/* - * Default maximum segment size for TCP. - * With an IP MSS of 576, this is 536, - * but 512 is probably more convenient. - * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). - * - * We make this 1460 because we only care about Ethernet in the qemu context. - */ -#define TCP_MSS 1460 +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP << 24 | TCPOPT_NOP << 16 | TCPOPT_TIMESTAMP << 8 | \ + TCPOLEN_TIMESTAMP) +#endif -#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ +#ifndef TCPOLEN_MAXSEG +#define TCPOLEN_MAXSEG 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP + 2) /* appendix A */ +#endif -#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ +#undef TCP_MAXWIN +#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ + +#undef TCP_MAX_WINSHIFT +#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ /* * User-settable options (used with setsockopt). @@ -125,61 +115,55 @@ struct tcphdr { * so we undefine them. */ #undef TCP_NODELAY -#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ #undef TCP_MAXSEG -/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ /* * TCP FSM state definitions. * Per RFC793, September, 1981. */ -#define TCP_NSTATES 11 +#define TCP_NSTATES 11 -#define TCPS_CLOSED 0 /* closed */ -#define TCPS_LISTEN 1 /* listening for connection */ -#define TCPS_SYN_SENT 2 /* active, have sent syn */ -#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ /* states < TCPS_ESTABLISHED are those where connections not established */ -#define TCPS_ESTABLISHED 4 /* established */ -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ /* states > TCPS_CLOSE_WAIT are those where user has closed */ -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ /* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ -#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) #define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) -#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) /* * TCP sequence numbers are 32 bit integers operated * on with modular arithmetic. These macros can be * used to compare such integers. */ -#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) -#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) -#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) +#define SEQ_LT(a, b) ((int)((a) - (b)) < 0) +#define SEQ_LEQ(a, b) ((int)((a) - (b)) <= 0) +#define SEQ_GT(a, b) ((int)((a) - (b)) > 0) +#define SEQ_GEQ(a, b) ((int)((a) - (b)) >= 0) /* * Macros to initialize tcp sequence numbers for * send and receive from initial send and receive * sequence numbers. */ -#define tcp_rcvseqinit(tp) \ - (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 +#define tcp_rcvseqinit(tp) (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 #define tcp_sendseqinit(tp) \ (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss -#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ - -extern tcp_seq tcp_iss; /* tcp initial send seq # */ - -extern char *tcpstates[]; +#define TCP_ISSINCR (125 * 1024) /* increment for tcp_iss each second */ #endif diff --git a/src/network/slirp/tcp_input.c b/src/network/slirp/tcp_input.c index 97187788d..d55b0c81d 100644 --- a/src/network/slirp/tcp_input.c +++ b/src/network/slirp/tcp_input.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -33,26 +34,18 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#include + #include "slirp.h" #include "ip_icmp.h" -struct SLIRPsocket tcb; +#define TCPREXMTTHRESH 3 -int tcprexmtthresh = 3; -struct SLIRPsocket *tcp_last_so = &tcb; - -tcp_seq tcp_iss; /* tcp initial send seq # */ - -#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) +#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) /* for modulo comparisons of timestamps */ -#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) -#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) +#define TSTMP_LT(a, b) ((int)((a) - (b)) < 0) +#define TSTMP_GEQ(a, b) ((int)((a) - (b)) >= 0) /* * Insert segment ti into reassembly queue of tcp with @@ -64,1615 +57,1427 @@ tcp_seq tcp_iss; /* tcp initial send seq # */ * Set DELACK for segments received in order, but ack immediately * when segments are out of order (so fast retransmit can work). */ -#ifdef TCP_ACK_HACK -#define TCP_REASS(tp, ti, m, so, flags) {\ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (tcpiphdrp_32)(tp) && \ - (tp)->t_state == TCPS_ESTABLISHED) {\ - if (ti->ti_flags & TH_PUSH) \ - tp->t_flags |= TF_ACKNOW; \ - else \ - tp->t_flags |= TF_DELACK; \ - (tp)->rcv_nxt += (ti)->ti_len; \ - flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ - if (so->so_emu) { \ - if (tcp_emu((so),(m))) sbappend((so), (m)); \ - } else \ - sbappend((so), (m)); \ -/* sorwakeup(so); */ \ - } else {\ - (flags) = tcp_reass((tp), (ti), (m)); \ - tp->t_flags |= TF_ACKNOW; \ - } \ -} -#else -#define TCP_REASS(tp, ti, m, so, flags) { \ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (tcpiphdrp_32)(tp) && \ - (tp)->t_state == TCPS_ESTABLISHED) { \ - tp->t_flags |= TF_DELACK; \ - (tp)->rcv_nxt += (ti)->ti_len; \ - flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ - if (so->so_emu) { \ - if (tcp_emu((so),(m))) sbappend(so, (m)); \ - } else \ - sbappend((so), (m)); \ -/* sorwakeup(so); */ \ - } else { \ - (flags) = tcp_reass((tp), (ti), (m)); \ - tp->t_flags |= TF_ACKNOW; \ - } \ -} -#endif +#define TCP_REASS(tp, ti, m, so, flags) \ + { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && tcpfrag_list_empty(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + if (so->so_emu) { \ + if (tcp_emu((so), (m))) \ + sbappend(so, (m)); \ + } else \ + sbappend((so), (m)); \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ + } -int -tcp_reass(tp, ti, m) - struct tcpcb *tp; - struct tcpiphdr *ti; - struct SLIRPmbuf *m; +static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt, + struct tcpiphdr *ti); +static void tcp_xmit_timer(register struct tcpcb *tp, int rtt); + +static int tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti, + struct mbuf *m) { - struct tcpiphdr *q; - struct SLIRPsocket *so = tp->t_socket; - int flags; - - /* - * Call with ti==0 after become established to - * force pre-ESTABLISHED data up to user socket. - */ - if (ti == 0) - goto present; + register struct tcpiphdr *q; + struct socket *so = tp->t_socket; + int flags; - /* - * Find a segment which begins after this one does. - */ - for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; - q = (struct tcpiphdr *)q->ti_next) - if (SEQ_GT(q->ti_seq, ti->ti_seq)) - break; + /* + * Call with ti==NULL after become established to + * force pre-ESTABLISHED data up to user socket. + */ + if (ti == NULL) + goto present; - /* - * If there is a preceding segment, it may provide some of - * our data already. If so, drop the data from the incoming - * segment. If it provides all of our data, drop us. - */ - if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { - int i; - q = (struct tcpiphdr *)q->ti_prev; - /* conversion to int (in i) handles seq wraparound */ - i = q->ti_seq + q->ti_len - ti->ti_seq; - if (i > 0) { - if (i >= ti->ti_len) { - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += ti->ti_len; - m_freem(m); - /* - * Try to present any queued data - * at the left window edge to the user. - * This is needed after the 3-WHS - * completes. - */ - goto present; /* ??? */ - } - m_adj(m, i); - ti->ti_len -= i; - ti->ti_seq += i; - } - q = (struct tcpiphdr *)(q->ti_next); - } - tcpstat.tcps_rcvoopack++; - tcpstat.tcps_rcvoobyte += ti->ti_len; - REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + /* + * Find a segment which begins after this one does. + */ + for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp); + q = tcpiphdr_next(q)) + if (SEQ_GT(q->ti_seq, ti->ti_seq)) + break; - /* - * While we overlap succeeding segments trim them or, - * if they are completely covered, dequeue them. - */ - while (q != (struct tcpiphdr *)tp) { - int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; - if (i <= 0) - break; - if (i < q->ti_len) { - q->ti_seq += i; - q->ti_len -= i; - m_adj((struct SLIRPmbuf *) REASS_MBUF(q), i); - break; - } - q = (struct tcpiphdr *)q->ti_next; - m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); - remque_32((void *)(q->ti_prev)); - m_freem(m); - } + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) { + register int i; + q = tcpiphdr_prev(q); + /* conversion to int (in i) handles seq wraparound */ + i = q->ti_seq + q->ti_len - ti->ti_seq; + if (i > 0) { + if (i >= ti->ti_len) { + m_free(m); + /* + * Try to present any queued data + * at the left window edge to the user. + * This is needed after the 3-WHS + * completes. + */ + goto present; /* ??? */ + } + m_adj(m, i); + ti->ti_len -= i; + ti->ti_seq += i; + } + q = tcpiphdr_next(q); + } + ti->ti_mbuf = m; - /* - * Stick new segment in its place. - */ - insque_32(ti, (void *)(q->ti_prev)); + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (!tcpfrag_list_end(q, tp)) { + register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; + if (i < q->ti_len) { + q->ti_seq += i; + q->ti_len -= i; + m_adj(q->ti_mbuf, i); + break; + } + q = tcpiphdr_next(q); + m = tcpiphdr_prev(q)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(q))); + m_free(m); + } + + /* + * Stick new segment in its place. + */ + insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q))); present: - /* - * Present data to user, advancing rcv_nxt through - * completed sequence space. - */ - if (!TCPS_HAVEESTABLISHED(tp->t_state)) - return (0); - ti = (struct tcpiphdr *) tp->seg_next; - if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) - return (0); - if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) - return (0); - do { - tp->rcv_nxt += ti->ti_len; - flags = ti->ti_flags & TH_FIN; - remque_32(ti); - m = (struct SLIRPmbuf *) REASS_MBUF(ti); /* XXX */ - ti = (struct tcpiphdr *)ti->ti_next; -/* if (so->so_state & SS_FCANTRCVMORE) */ - if (so->so_state & SS_FCANTSENDMORE) - m_freem(m); - else { - if (so->so_emu) { - if (tcp_emu(so,m)) sbappend(so, m); - } else - sbappend(so, m); - } - } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); -/* sorwakeup(so); */ - return (flags); + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = tcpfrag_list_first(tp); + if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt) + return (0); + if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) + return (0); + do { + tp->rcv_nxt += ti->ti_len; + flags = ti->ti_flags & TH_FIN; + remque(tcpiphdr2qlink(ti)); + m = ti->ti_mbuf; + ti = tcpiphdr_next(ti); + if (so->so_state & SS_FCANTSENDMORE) + m_free(m); + else { + if (so->so_emu) { + if (tcp_emu(so, m)) + sbappend(so, m); + } else + sbappend(so, m); + } + } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); + return (flags); } /* * TCP input routine, follows pages 65-76 of the * protocol specification dated September, 1981 very closely. */ -void -tcp_input(m, iphlen, inso) - struct SLIRPmbuf *m; - int iphlen; - struct SLIRPsocket *inso; +void tcp_input(struct mbuf *m, int iphlen, struct socket *inso, + unsigned short af) { - struct ip save_ip, *ip; - struct tcpiphdr *ti; - SLIRPcaddr_t optp = NULL; - int optlen = 0; - int len, tlen, off; - struct tcpcb *tp = 0; - int tiflags; - struct SLIRPsocket *so = 0; - int todrop, acked, ourfinisacked, needoutput = 0; -/* int dropsocket = 0; */ - int iss = 0; - u_long tiwin; - int ret; -/* int ts_present = 0; */ + struct ip save_ip, *ip; + struct ip6 save_ip6, *ip6; + register struct tcpiphdr *ti; + char *optp = NULL; + int optlen = 0; + int len, tlen, off; + register struct tcpcb *tp = NULL; + register int tiflags; + struct socket *so = NULL; + int todrop, acked, ourfinisacked, needoutput = 0; + int iss = 0; + uint32_t tiwin; + int ret; + struct sockaddr_storage lhost, fhost; + struct sockaddr_in *lhost4, *fhost4; + struct sockaddr_in6 *lhost6, *fhost6; + struct gfwd_list *ex_ptr; + Slirp *slirp; - DEBUG_CALL("tcp_input"); - DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", - (long )m, iphlen, (long )inso )); - - /* - * If called with m == 0, then we're continuing the connect - */ - if (m == NULL) { - so = inso; - - /* Re-set a few variables */ - tp = sototcpcb(so); - m = so->so_m; - so->so_m = 0; - ti = so->so_ti; - tiwin = ti->ti_win; - tiflags = ti->ti_flags; - - goto cont_conn; - } - - - tcpstat.tcps_rcvtotal++; - /* - * Get IP and TCP header together in first SLIRPmbuf. - * Note: IP leaves IP header in first SLIRPmbuf. - */ - ti = mtod(m, struct tcpiphdr *); - if (iphlen > sizeof(struct ip )) { - ip_stripoptions(m, (struct SLIRPmbuf *)0); - iphlen=sizeof(struct ip ); - } - /* XXX Check if too short */ - + DEBUG_CALL("tcp_input"); + DEBUG_ARG("m = %p iphlen = %2d inso = %p", m, iphlen, inso); - /* - * Save a copy of the IP header in case we want restore it - * for sending an ICMP error message in response. - */ - ip=mtod(m, struct ip *); - save_ip = *ip; - save_ip.ip_len+= iphlen; + /* + * If called with m == 0, then we're continuing the connect + */ + if (m == NULL) { + so = inso; + slirp = so->slirp; - /* - * Checksum extended TCP header and data. - */ - tlen = ((struct ip *)ti)->ip_len; - ti->ti_next = ti->ti_prev = 0; - ti->ti_x1 = 0; - ti->ti_len = htons((u_int16_t)tlen); - len = sizeof(struct ip ) + tlen; - /* keep checksum for ICMP reply - * ti->ti_sum = cksum(m, len); - * if (ti->ti_sum) { */ - if(cksum(m, len)) { - tcpstat.tcps_rcvbadsum++; - goto drop; - } + /* Re-set a few variables */ + tp = sototcpcb(so); + m = so->so_m; + so->so_m = NULL; + ti = so->so_ti; + tiwin = ti->ti_win; + tiflags = ti->ti_flags; - /* - * Check that TCP offset makes sense, - * pull out TCP options and adjust length. XXX - */ - off = ti->ti_off << 2; - if (off < sizeof (struct tcphdr) || off > tlen) { - tcpstat.tcps_rcvbadoff++; - goto drop; - } - tlen -= off; - ti->ti_len = tlen; - if (off > sizeof (struct tcphdr)) { - optlen = off - sizeof (struct tcphdr); - optp = mtod(m, SLIRPcaddr_t) + sizeof (struct tcpiphdr); + goto cont_conn; + } + slirp = m->slirp; - /* - * Do quick retrieval of timestamp options ("options - * prediction?"). If timestamp is the only option and it's - * formatted as recommended in RFC 1323 appendix A, we - * quickly get the values now and not bother calling - * tcp_dooptions(), etc. - */ -/* if ((optlen == TCPOLEN_TSTAMP_APPA || - * (optlen > TCPOLEN_TSTAMP_APPA && - * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && - * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && - * (ti->ti_flags & TH_SYN) == 0) { - * ts_present = 1; - * ts_val = ntohl(*(u_int32_t *)(optp + 4)); - * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); - * optp = NULL; / * we've parsed the options * / - * } - */ - } - tiflags = ti->ti_flags; - - /* - * Convert TCP protocol specific fields to host format. - */ - NTOHL(ti->ti_seq); - NTOHL(ti->ti_ack); - NTOHS(ti->ti_win); - NTOHS(ti->ti_urp); + ip = mtod(m, struct ip *); + ip6 = mtod(m, struct ip6 *); + + switch (af) { + case AF_INET: + if (iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); + } + /* XXX Check if too short */ - /* - * Drop TCP, IP headers and TCP options. - */ - m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - - /* - * Locate pcb for segment. - */ -findso: - so = tcp_last_so; - if (so->so_fport != ti->ti_dport || - so->so_lport != ti->ti_sport || - so->so_laddr.s_addr != ti->ti_src.s_addr || - so->so_faddr.s_addr != ti->ti_dst.s_addr) { - so = solookup(&tcb, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport); - if (so) - tcp_last_so = so; - ++tcpstat.tcps_socachemiss; - } - /* - * If the state is CLOSED (i.e., TCB does not exist) then - * all data in the incoming segment is discarded. - * If the TCB exists but is in CLOSED state, it is embryonic, - * but should either do a listen or a connect soon. - * - * state == CLOSED means we've done socreate() but haven't - * attached it to a protocol yet... - * - * XXX If a TCB does not exist, and the TH_SYN flag is - * the only flag set, then create a session, mark it - * as if it was LISTENING, and continue... - */ - if (so == 0) { - if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) - goto dropwithreset; - - if ((so = socreate()) == NULL) - goto dropwithreset; - if (tcp_attach(so) < 0) { - free(so); /* Not sofree (if it failed, it's not insqued) */ - goto dropwithreset; - } - - sbreserve(&so->so_snd, tcp_sndspace); - sbreserve(&so->so_rcv, tcp_rcvspace); - - /* tcp_last_so = so; */ /* XXX ? */ - /* tp = sototcpcb(so); */ - - so->so_laddr = ti->ti_src; - so->so_lport = ti->ti_sport; - so->so_faddr = ti->ti_dst; - so->so_fport = ti->ti_dport; - - if ((so->so_iptos = tcp_tos(so)) == 0) - so->so_iptos = ((struct ip *)ti)->ip_tos; - - tp = sototcpcb(so); - tp->t_state = TCPS_LISTEN; - } - /* - * If this is a still-connecting socket, this probably - * a retransmit of the SYN. Whether it's a retransmit SYN - * or something else, we nuke it. + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. */ - if (so->so_state & SS_ISFCONNECTING) + save_ip = *ip; + save_ip.ip_len += iphlen; + + /* + * Get IP and TCP header together in first mbuf. + * Note: IP leaves IP header in first mbuf. + */ + m->m_data -= + sizeof(struct tcpiphdr) - sizeof(struct ip) - sizeof(struct tcphdr); + m->m_len += + sizeof(struct tcpiphdr) - sizeof(struct ip) - sizeof(struct tcphdr); + ti = mtod(m, struct tcpiphdr *); + + /* + * Checksum extended TCP header and data. + */ + tlen = ip->ip_len; + tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL; + memset(&ti->ih_mbuf, 0, sizeof(struct mbuf_ptr)); + memset(&ti->ti, 0, sizeof(ti->ti)); + ti->ti_x0 = 0; + ti->ti_src = save_ip.ip_src; + ti->ti_dst = save_ip.ip_dst; + ti->ti_pr = save_ip.ip_p; + ti->ti_len = htons((uint16_t)tlen); + break; + + case AF_INET6: + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip6 = *ip6; + /* + * Get IP and TCP header together in first mbuf. + * Note: IP leaves IP header in first mbuf. + */ + m->m_data -= sizeof(struct tcpiphdr) - + (sizeof(struct ip6) + sizeof(struct tcphdr)); + m->m_len += sizeof(struct tcpiphdr) - + (sizeof(struct ip6) + sizeof(struct tcphdr)); + ti = mtod(m, struct tcpiphdr *); + + tlen = ip6->ip_pl; + tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL; + memset(&ti->ih_mbuf, 0, sizeof(struct mbuf_ptr)); + memset(&ti->ti, 0, sizeof(ti->ti)); + ti->ti_x0 = 0; + ti->ti_src6 = save_ip6.ip_src; + ti->ti_dst6 = save_ip6.ip_dst; + ti->ti_nh6 = save_ip6.ip_nh; + ti->ti_len = htons((uint16_t)tlen); + break; + + default: + g_assert_not_reached(); + } + + len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen); + if (cksum(m, len)) { + goto drop; + } + + /* + * Check that TCP offset makes sense, + * pull out TCP options and adjust length. XXX + */ + off = ti->ti_off << 2; + if (off < sizeof(struct tcphdr) || off > tlen) { + goto drop; + } + tlen -= off; + ti->ti_len = tlen; + if (off > sizeof(struct tcphdr)) { + optlen = off - sizeof(struct tcphdr); + optp = mtod(m, char *) + sizeof(struct tcpiphdr); + } + tiflags = ti->ti_flags; + + /* + * Convert TCP protocol specific fields to host format. + */ + NTOHL(ti->ti_seq); + NTOHL(ti->ti_ack); + NTOHS(ti->ti_win); + NTOHS(ti->ti_urp); + + /* + * Drop TCP, IP headers and TCP options. + */ + m->m_data += sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); + + /* + * Locate pcb for segment. + */ +findso: + lhost.ss_family = af; + fhost.ss_family = af; + switch (af) { + case AF_INET: + lhost4 = (struct sockaddr_in *)&lhost; + lhost4->sin_addr = ti->ti_src; + lhost4->sin_port = ti->ti_sport; + fhost4 = (struct sockaddr_in *)&fhost; + fhost4->sin_addr = ti->ti_dst; + fhost4->sin_port = ti->ti_dport; + break; + case AF_INET6: + lhost6 = (struct sockaddr_in6 *)&lhost; + lhost6->sin6_addr = ti->ti_src6; + lhost6->sin6_port = ti->ti_sport; + fhost6 = (struct sockaddr_in6 *)&fhost; + fhost6->sin6_addr = ti->ti_dst6; + fhost6->sin6_port = ti->ti_dport; + break; + default: + g_assert_not_reached(); + } + + so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost); + + /* + * If the state is CLOSED (i.e., TCB does not exist) then + * all data in the incoming segment is discarded. + * If the TCB exists but is in CLOSED state, it is embryonic, + * but should either do a listen or a connect soon. + * + * state == CLOSED means we've done socreate() but haven't + * attached it to a protocol yet... + * + * XXX If a TCB does not exist, and the TH_SYN flag is + * the only flag set, then create a session, mark it + * as if it was LISTENING, and continue... + */ + if (so == NULL) { + /* TODO: IPv6 */ + if (slirp->restricted) { + /* Any hostfwds will have an existing socket, so we only get here + * for non-hostfwd connections. These should be dropped, unless it + * happens to be a guestfwd. + */ + for (ex_ptr = slirp->guestfwd_list; ex_ptr; + ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_fport == ti->ti_dport && + ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) { + break; + } + } + if (!ex_ptr) { + goto dropwithreset; + } + } + + if ((tiflags & (TH_SYN | TH_FIN | TH_RST | TH_URG | TH_ACK)) != TH_SYN) + goto dropwithreset; + + so = socreate(slirp); + tcp_attach(so); + + sbreserve(&so->so_snd, TCP_SNDSPACE); + sbreserve(&so->so_rcv, TCP_RCVSPACE); + + so->lhost.ss = lhost; + so->fhost.ss = fhost; + + so->so_iptos = tcp_tos(so); + if (so->so_iptos == 0) { + switch (af) { + case AF_INET: + so->so_iptos = ((struct ip *)ti)->ip_tos; + break; + case AF_INET6: + break; + default: + g_assert_not_reached(); + } + } + + tp = sototcpcb(so); + tp->t_state = TCPS_LISTEN; + } + + /* + * If this is a still-connecting socket, this probably + * a retransmit of the SYN. Whether it's a retransmit SYN + * or something else, we nuke it. + */ + if (so->so_state & SS_ISFCONNECTING) + goto drop; + + tp = sototcpcb(so); + + /* XXX Should never fail */ + if (tp == NULL) + goto dropwithreset; + if (tp->t_state == TCPS_CLOSED) + goto drop; + + tiwin = ti->ti_win; + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + if (slirp_do_keepalive) + tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL; + else + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE; + + /* + * Process options if not in LISTEN state, + * else do it below (after getting remote address). + */ + if (optp && tp->t_state != TCPS_LISTEN) + tcp_dooptions(tp, (uint8_t *)optp, optlen, ti); + + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * + * XXX Some of these tests are not needed + * eg: the tiwin == tp->snd_wnd prevents many more + * predictions.. with no *real* advantage.. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (tiflags & (TH_SYN | TH_FIN | TH_RST | TH_URG | TH_ACK)) == TH_ACK && + ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd && + tp->snd_nxt == tp->snd_max) { + if (ti->ti_len == 0) { + if (SEQ_GT(ti->ti_ack, tp->snd_una) && + SEQ_LEQ(ti->ti_ack, tp->snd_max) && + tp->snd_cwnd >= tp->snd_wnd) { + /* + * this is a pure ack for outstanding data. + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtt); + acked = ti->ti_ack - tp->snd_una; + sodrop(so, acked); + tp->snd_una = ti->ti_ack; + m_free(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ + if (tp->snd_una == tp->snd_max) + tp->t_timer[TCPT_REXMT] = 0; + else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + /* + * This is called because sowwakeup might have + * put data into so_snd. Since we don't so sowwakeup, + * we don't need this.. XXX??? + */ + if (so->so_snd.sb_cc) + (void)tcp_output(tp); + + return; + } + } else if (ti->ti_ack == tp->snd_una && tcpfrag_list_empty(tp) && + ti->ti_len <= sbspace(&so->so_rcv)) { + /* + * this is a pure, in-sequence data packet + * with nothing on the reassembly queue and + * we have enough buffer space to take it. + */ + tp->rcv_nxt += ti->ti_len; + /* + * Add data to socket buffer. + */ + if (so->so_emu) { + if (tcp_emu(so, m)) + sbappend(so, m); + } else + sbappend(so, m); + + /* + * If this is a short packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * It is better to not delay acks at all to maximize + * TCP throughput. See RFC 2581. + */ + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); + return; + } + } /* header prediction */ + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + { + int win; + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + } + + switch (tp->t_state) { + /* + * If the state is LISTEN then ignore segment if it contains an RST. + * If the segment contains an ACK then it is bad and send a RST. + * If it does not contain a SYN then it is not interesting; drop it. + * Don't bother responding if the destination was a broadcast. + * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial + * tp->iss, and send a segment: + * + * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. + * Fill in remote peer address fields if not previously specified. + * Enter SYN_RECEIVED state, and process any other fields of this + * segment in this state. + */ + case TCPS_LISTEN: { + if (tiflags & TH_RST) + goto drop; + if (tiflags & TH_ACK) + goto dropwithreset; + if ((tiflags & TH_SYN) == 0) + goto drop; + + /* + * This has way too many gotos... + * But a bit of spaghetti code never hurt anybody :) + */ + + /* + * If this is destined for the control address, then flag to + * tcp_ctl once connected, otherwise connect + */ + /* TODO: IPv6 */ + if (af == AF_INET && + (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == + slirp->vnetwork_addr.s_addr) { + if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr && + so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) { + /* May be an add exec */ + for (ex_ptr = slirp->guestfwd_list; ex_ptr; + ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_fport == so->so_fport && + so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) { + so->so_state |= SS_CTL; + break; + } + } + if (so->so_state & SS_CTL) { + goto cont_input; + } + } + /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ + } + + if (so->so_emu & EMU_NOCONNECT) { + so->so_emu &= ~EMU_NOCONNECT; + goto cont_input; + } + + if ((tcp_fconnect(so, so->so_ffamily) == -1) && (errno != EAGAIN) && + (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { + uint8_t code; + DEBUG_MISC(" tcp fconnect errno = %d-%s", errno, strerror(errno)); + if (errno == ECONNREFUSED) { + /* ACK the SYN, send RST to refuse the connection */ + tcp_respond(tp, ti, m, ti->ti_seq + 1, (tcp_seq)0, + TH_RST | TH_ACK, af); + } else { + switch (af) { + case AF_INET: + code = ICMP_UNREACH_NET; + if (errno == EHOSTUNREACH) { + code = ICMP_UNREACH_HOST; + } + break; + case AF_INET6: + code = ICMP6_UNREACH_NO_ROUTE; + if (errno == EHOSTUNREACH) { + code = ICMP6_UNREACH_ADDRESS; + } + break; + default: + g_assert_not_reached(); + } + HTONL(ti->ti_seq); /* restore tcp header */ + HTONL(ti->ti_ack); + HTONS(ti->ti_win); + HTONS(ti->ti_urp); + m->m_data -= + sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); + m->m_len += + sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); + switch (af) { + case AF_INET: + m->m_data += sizeof(struct tcpiphdr) - sizeof(struct ip) - + sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct ip) - + sizeof(struct tcphdr); + *ip = save_ip; + icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno)); + break; + case AF_INET6: + m->m_data += sizeof(struct tcpiphdr) - + (sizeof(struct ip6) + sizeof(struct tcphdr)); + m->m_len -= sizeof(struct tcpiphdr) - + (sizeof(struct ip6) + sizeof(struct tcphdr)); + *ip6 = save_ip6; + icmp6_send_error(m, ICMP6_UNREACH, code); + break; + default: + g_assert_not_reached(); + } + } + tcp_close(tp); + m_free(m); + } else { + /* + * Haven't connected yet, save the current mbuf + * and ti, and return + * XXX Some OS's don't tell us whether the connect() + * succeeded or not. So we must time it out. + */ + so->so_m = m; + so->so_ti = ti; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->t_state = TCPS_SYN_RECEIVED; + /* + * Initialize receive sequence numbers now so that we can send a + * valid RST if the remote end rejects our connection. + */ + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + tcp_template(tp); + } + return; + + cont_conn: + /* m==NULL + * Check if the connect succeeded + */ + if (so->so_state & SS_NOFDREF) { + tp = tcp_close(tp); + goto dropwithreset; + } + cont_input: + tcp_template(tp); + + if (optp) + tcp_dooptions(tp, (uint8_t *)optp, optlen, ti); + + if (iss) + tp->iss = iss; + else + tp->iss = slirp->tcp_iss; + slirp->tcp_iss += TCP_ISSINCR / 2; + tp->irs = ti->ti_seq; + tcp_sendseqinit(tp); + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + tp->t_state = TCPS_SYN_RECEIVED; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + goto trimthenstep6; + } /* case TCPS_LISTEN */ + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((tiflags & TH_ACK) && + (SEQ_LEQ(ti->ti_ack, tp->iss) || SEQ_GT(ti->ti_ack, tp->snd_max))) + goto dropwithreset; + + if (tiflags & TH_RST) { + if (tiflags & TH_ACK) { + tcp_drop(tp, 0); /* XXX Check t_softerror! */ + } + goto drop; + } + + if ((tiflags & TH_SYN) == 0) + goto drop; + if (tiflags & TH_ACK) { + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + } + + tp->t_timer[TCPT_REXMT] = 0; + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { + soisfconnected(so); + tp->t_state = TCPS_ESTABLISHED; + + (void)tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); + /* + * if we didn't have to retransmit the SYN, + * use its rtt as our initial srtt & rtt var. + */ + if (tp->t_rtt) + tcp_xmit_timer(tp, tp->t_rtt); + } else + tp->t_state = TCPS_SYN_RECEIVED; + + trimthenstep6: + /* + * Advance ti->ti_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + ti->ti_seq++; + if (ti->ti_len > tp->rcv_wnd) { + todrop = ti->ti_len - tp->rcv_wnd; + m_adj(m, -todrop); + ti->ti_len = tp->rcv_wnd; + tiflags &= ~TH_FIN; + } + tp->snd_wl1 = ti->ti_seq - 1; + tp->rcv_up = ti->ti_seq; + goto step6; + } /* switch tp->t_state */ + /* + * States other than LISTEN or SYN_SENT. + * Check that at least some bytes of segment are within + * receive window. If segment begins before rcv_nxt, + * drop leading data (and SYN); if nothing left, just ack. + */ + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { + if (tiflags & TH_SYN) { + tiflags &= ~TH_SYN; + ti->ti_seq++; + if (ti->ti_urp > 1) + ti->ti_urp--; + else + tiflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > ti->ti_len || + (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + tiflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = ti->ti_len; + } + m_adj(m, todrop); + ti->ti_seq += todrop; + ti->ti_len -= todrop; + if (ti->ti_urp > todrop) + ti->ti_urp -= todrop; + else { + tiflags &= ~TH_URG; + ti->ti_urp = 0; + } + } + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && + ti->ti_len) { + tp = tcp_close(tp); + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (ti->ti_seq + ti->ti_len) - (tp->rcv_nxt + tp->rcv_wnd); + if (todrop > 0) { + if (todrop >= ti->ti_len) { + /* + * If a new connection request is received + * while in TIME_WAIT, drop the old connection + * and start over if the sequence numbers + * are above the previous ones. + */ + if (tiflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && + SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { + iss = tp->rcv_nxt + TCP_ISSINCR; + tp = tcp_close(tp); + goto findso; + } + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + } else { + goto dropafterack; + } + } + m_adj(m, -todrop); + ti->ti_len -= todrop; + tiflags &= ~(TH_PUSH | TH_FIN); + } + + /* + * If the RST bit is set examine the state: + * SYN_RECEIVED STATE: + * If passive open, return to LISTEN state. + * If active open, inform user that connection was refused. + * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: + * Inform user that connection was reset, and close tcb. + * CLOSING, LAST_ACK, TIME_WAIT STATES + * Close the tcb. + */ + if (tiflags & TH_RST) + switch (tp->t_state) { + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_CLOSED; + tcp_close(tp); + goto drop; + + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + tcp_close(tp); + goto drop; + } + + /* + * If a SYN is in the window, then this is an + * error and we send an RST and drop the connection. + */ + if (tiflags & TH_SYN) { + tp = tcp_drop(tp, 0); + goto dropwithreset; + } + + /* + * If the ACK bit is off we drop the segment and return. + */ + if ((tiflags & TH_ACK) == 0) + goto drop; + + /* + * Ack processing. + */ + switch (tp->t_state) { + /* + * In SYN_RECEIVED state if the ack ACKs our SYN then enter + * ESTABLISHED state and continue processing, otherwise + * send an RST. una<=ack<=max + */ + case TCPS_SYN_RECEIVED: + + if (SEQ_GT(tp->snd_una, ti->ti_ack) || SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + tp->t_state = TCPS_ESTABLISHED; + /* + * The sent SYN is ack'ed with our sequence number +1 + * The first data byte already in the buffer will get + * lost if no correction is made. This is only needed for + * SS_CTL since the buffer is empty otherwise. + * tp->snd_una++; or: + */ + tp->snd_una = ti->ti_ack; + if (so->so_state & SS_CTL) { + /* So tcp_ctl reports the right state */ + ret = tcp_ctl(so); + if (ret == 1) { + soisfconnected(so); + so->so_state &= ~SS_CTL; /* success XXX */ + } else if (ret == 2) { + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; /* CTL_CMD */ + } else { + needoutput = 1; + tp->t_state = TCPS_FIN_WAIT_1; + } + } else { + soisfconnected(so); + } + + (void)tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); + tp->snd_wl1 = ti->ti_seq - 1; + /* Avoid ack processing; snd_una==ti_ack => dup ack */ + goto synrx_to_est; + /* fall into ... */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < ti->ti_ack <= tp->snd_max + * then advance tp->snd_una to ti->ti_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + + if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { + if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { + DEBUG_MISC(" dup ack m = %p so = %p", m, so); + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change), the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * network (they're now cached at the receiver) + * so bump cwnd by the amount in the receiver + * to keep a constant cwnd packets in the + * network. + */ + if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks == TCPREXMTTHRESH) { + tcp_seq onxt = tp->snd_nxt; + unsigned win = + MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + + if (win < 2) + win = 2; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rtt = 0; + tp->snd_nxt = ti->ti_ack; + tp->snd_cwnd = tp->t_maxseg; + (void)tcp_output(tp); + tp->snd_cwnd = + tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (tp->t_dupacks > TCPREXMTTHRESH) { + tp->snd_cwnd += tp->t_maxseg; + (void)tcp_output(tp); + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + synrx_to_est: + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tp->t_dupacks > TCPREXMTTHRESH && tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { + goto dropafterack; + } + acked = ti->ti_ack - tp->snd_una; + + /* + * If transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtt); + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (ti->ti_ack == tp->snd_max) { + tp->t_timer[TCPT_REXMT] = 0; + needoutput = 1; + } else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet). + */ + { + register unsigned cw = tp->snd_cwnd; + register unsigned incr = tp->t_maxseg; + + if (cw > tp->snd_ssthresh) + incr = incr * incr / cw; + tp->snd_cwnd = MIN(cw + incr, TCP_MAXWIN << tp->snd_scale); + } + if (acked > so->so_snd.sb_cc) { + tp->snd_wnd -= so->so_snd.sb_cc; + sodrop(so, (int)so->so_snd.sb_cc); + ourfinisacked = 1; + } else { + sodrop(so, acked); + tp->snd_wnd -= acked; + ourfinisacked = 0; + } + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + */ + if (so->so_state & SS_FCANTRCVMORE) { + tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE; + } + tp->t_state = TCPS_FIN_WAIT_2; + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + tcp_close(tp); goto drop; + } + break; - tp = sototcpcb(so); - - /* XXX Should never fail */ - if (tp == 0) - goto dropwithreset; - if (tp->t_state == TCPS_CLOSED) - goto drop; - - /* Unscale the window into a 32-bit value. */ -/* if ((tiflags & TH_SYN) == 0) - * tiwin = ti->ti_win << tp->snd_scale; - * else - */ - tiwin = ti->ti_win; - - /* - * Segment received on connection. - * Reset idle time and keep-alive timer. - */ - tp->t_idle = 0; - if (so_options) - tp->t_timer[TCPT_KEEP] = tcp_keepintvl; - else - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - - /* - * Process options if not in LISTEN state, - * else do it below (after getting remote address). - */ - if (optp && tp->t_state != TCPS_LISTEN) - tcp_dooptions(tp, (u_char *)optp, optlen, ti); -/* , */ -/* &ts_present, &ts_val, &ts_ecr); */ - - /* - * Header prediction: check for the two common cases - * of a uni-directional data xfer. If the packet has - * no control flags, is in-sequence, the window didn't - * change and we're not retransmitting, it's a - * candidate. If the length is zero and the ack moved - * forward, we're the sender side of the xfer. Just - * free the data acked & wake any higher level process - * that was blocked waiting for space. If the length - * is non-zero and the ack didn't move, we're the - * receiver side. If we're getting packets in-order - * (the reassembly queue is empty), add the data to - * the socket buffer and note that we need a delayed ack. - * - * XXX Some of these tests are not needed - * eg: the tiwin == tp->snd_wnd prevents many more - * predictions.. with no *real* advantage.. - */ - if (tp->t_state == TCPS_ESTABLISHED && - (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && -/* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ - ti->ti_seq == tp->rcv_nxt && - tiwin && tiwin == tp->snd_wnd && - tp->snd_nxt == tp->snd_max) { - /* - * If last ACK falls within this segment's sequence numbers, - * record the timestamp. - */ -/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && - * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { - * tp->ts_recent_age = tcp_now; - * tp->ts_recent = ts_val; - * } - */ - if (ti->ti_len == 0) { - if (SEQ_GT(ti->ti_ack, tp->snd_una) && - SEQ_LEQ(ti->ti_ack, tp->snd_max) && - tp->snd_cwnd >= tp->snd_wnd) { - /* - * this is a pure ack for outstanding data. - */ - ++tcpstat.tcps_predack; -/* if (ts_present) - * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); - * else - */ if (tp->t_rtt && - SEQ_GT(ti->ti_ack, tp->t_rtseq)) - tcp_xmit_timer(tp, tp->t_rtt); - acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; - sbdrop(&so->so_snd, acked); - tp->snd_una = ti->ti_ack; - m_freem(m); - - /* - * If all outstanding data are acked, stop - * retransmit timer, otherwise restart timer - * using current (possibly backed-off) value. - * If process is waiting for space, - * wakeup/selwakeup/signal. If data - * are ready to send, let tcp_output - * decide between more output or persist. - */ - if (tp->snd_una == tp->snd_max) - tp->t_timer[TCPT_REXMT] = 0; - else if (tp->t_timer[TCPT_PERSIST] == 0) - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - - /* - * There's room in so_snd, sowwakup will read() - * from the socket if we can - */ -/* if (so->so_snd.sb_flags & SB_NOTIFY) - * sowwakeup(so); - */ - /* - * This is called because sowwakeup might have - * put data into so_snd. Since we don't so sowwakeup, - * we don't need this.. XXX??? - */ - if (so->so_snd.sb_cc) - (void) tcp_output(tp); - - return; - } - } else if (ti->ti_ack == tp->snd_una && - tp->seg_next == (tcpiphdrp_32)tp && - ti->ti_len <= sbspace(&so->so_rcv)) { - /* - * this is a pure, in-sequence data packet - * with nothing on the reassembly queue and - * we have enough buffer space to take it. - */ - ++tcpstat.tcps_preddat; - tp->rcv_nxt += ti->ti_len; - tcpstat.tcps_rcvpack++; - tcpstat.tcps_rcvbyte += ti->ti_len; - /* - * Add data to socket buffer. - */ - if (so->so_emu) { - if (tcp_emu(so,m)) sbappend(so, m); - } else - sbappend(so, m); - - /* - * XXX This is called when data arrives. Later, check - * if we can actually write() to the socket - * XXX Need to check? It's be NON_BLOCKING - */ -/* sorwakeup(so); */ - - /* - * If this is a short packet, then ACK now - with Nagel - * congestion avoidance sender won't send more until - * he gets an ACK. - * - * It is better to not delay acks at all to maximize - * TCP throughput. See RFC 2581. - */ - tp->t_flags |= TF_ACKNOW; - tcp_output(tp); - return; - } - } /* header prediction */ - /* - * Calculate amount of space in receive window, - * and then do TCP input processing. - * Receive window is amount of space in rcv queue, - * but not less than advertised window. - */ - { int win; - win = sbspace(&so->so_rcv); - if (win < 0) - win = 0; - tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); - } - - switch (tp->t_state) { - - /* - * If the state is LISTEN then ignore segment if it contains an RST. - * If the segment contains an ACK then it is bad and send a RST. - * If it does not contain a SYN then it is not interesting; drop it. - * Don't bother responding if the destination was a broadcast. - * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial - * tp->iss, and send a segment: - * - * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. - * Fill in remote peer address fields if not previously specified. - * Enter SYN_RECEIVED state, and process any other fields of this - * segment in this state. - */ - case TCPS_LISTEN: { - - if (tiflags & TH_RST) - goto drop; - if (tiflags & TH_ACK) - goto dropwithreset; - if ((tiflags & TH_SYN) == 0) - goto drop; - - /* - * This has way too many gotos... - * But a bit of spaghetti code never hurt anybody :) - */ - - /* - * If this is destined for the control address, then flag to - * tcp_ctl once connected, otherwise connect - */ - if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) { - int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff; - if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) { -#if 0 - if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { - /* Command or exec adress */ - so->so_state |= SS_CTL; - } else -#endif - { - /* May be an add exec */ - struct ex_list *ex_ptr; - for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if(ex_ptr->ex_fport == so->so_fport && - lastbyte == ex_ptr->ex_addr) { - so->so_state |= SS_CTL; - break; - } - } - } - if(so->so_state & SS_CTL) goto cont_input; - } - /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ - } - - if (so->so_emu & EMU_NOCONNECT) { - so->so_emu &= ~EMU_NOCONNECT; - goto cont_input; - } - - if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { - u_char code=ICMP_UNREACH_NET; - DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", - errno,strerror(errno))); - if(errno == ECONNREFUSED) { - /* ACK the SYN, send RST to refuse the connection */ - tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, - TH_RST|TH_ACK); - } else { - if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; - HTONL(ti->ti_seq); /* restore tcp header */ - HTONL(ti->ti_ack); - HTONS(ti->ti_win); - HTONS(ti->ti_urp); - m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - *ip=save_ip; - icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); - } - tp = tcp_close(tp); - m_free(m); - } else { - /* - * Haven't connected yet, save the current SLIRPmbuf - * and ti, and return - * XXX Some OS's don't tell us whether the connect() - * succeeded or not. So we must time it out. - */ - so->so_m = m; - so->so_ti = ti; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->t_state = TCPS_SYN_RECEIVED; - } - return; - - cont_conn: - /* m==NULL - * Check if the connect succeeded - */ - if (so->so_state & SS_NOFDREF) { - tp = tcp_close(tp); - goto dropwithreset; - } - cont_input: - tcp_template(tp); - - if (optp) - tcp_dooptions(tp, (u_char *)optp, optlen, ti); - /* , */ - /* &ts_present, &ts_val, &ts_ecr); */ - - if (iss) - tp->iss = iss; - else - tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR/2; - tp->irs = ti->ti_seq; - tcp_sendseqinit(tp); - tcp_rcvseqinit(tp); - tp->t_flags |= TF_ACKNOW; - tp->t_state = TCPS_SYN_RECEIVED; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tcpstat.tcps_accepts++; - goto trimthenstep6; - } /* case TCPS_LISTEN */ - - /* - * If the state is SYN_SENT: - * if seg contains an ACK, but not for our SYN, drop the input. - * if seg contains a RST, then drop the connection. - * if seg does not contain SYN, then drop it. - * Otherwise this is an acceptable SYN segment - * initialize tp->rcv_nxt and tp->irs - * if seg contains ack then advance tp->snd_una - * if SYN has been acked change to ESTABLISHED else SYN_RCVD state - * arrange for segment to be acked (eventually) - * continue processing rest of data/controls, beginning with URG - */ - case TCPS_SYN_SENT: - if ((tiflags & TH_ACK) && - (SEQ_LEQ(ti->ti_ack, tp->iss) || - SEQ_GT(ti->ti_ack, tp->snd_max))) - goto dropwithreset; - - if (tiflags & TH_RST) { - if (tiflags & TH_ACK) - tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ - goto drop; - } - - if ((tiflags & TH_SYN) == 0) - goto drop; - if (tiflags & TH_ACK) { - tp->snd_una = ti->ti_ack; - if (SEQ_LT(tp->snd_nxt, tp->snd_una)) - tp->snd_nxt = tp->snd_una; - } - - tp->t_timer[TCPT_REXMT] = 0; - tp->irs = ti->ti_seq; - tcp_rcvseqinit(tp); - tp->t_flags |= TF_ACKNOW; - if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { - tcpstat.tcps_connects++; - soisfconnected(so); - tp->t_state = TCPS_ESTABLISHED; - - /* Do window scaling on this connection? */ -/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - * (TF_RCVD_SCALE|TF_REQ_SCALE)) { - * tp->snd_scale = tp->requested_s_scale; - * tp->rcv_scale = tp->request_r_scale; - * } - */ - (void) tcp_reass(tp, (struct tcpiphdr *)0, - (struct SLIRPmbuf *)0); - /* - * if we didn't have to retransmit the SYN, - * use its rtt as our initial srtt & rtt var. - */ - if (tp->t_rtt) - tcp_xmit_timer(tp, tp->t_rtt); - } else - tp->t_state = TCPS_SYN_RECEIVED; - -trimthenstep6: - /* - * Advance ti->ti_seq to correspond to first data byte. - * If data, trim to stay within window, - * dropping FIN if necessary. - */ - ti->ti_seq++; - if (ti->ti_len > tp->rcv_wnd) { - todrop = ti->ti_len - tp->rcv_wnd; - m_adj(m, -todrop); - ti->ti_len = tp->rcv_wnd; - tiflags &= ~TH_FIN; - tcpstat.tcps_rcvpackafterwin++; - tcpstat.tcps_rcvbyteafterwin += todrop; - } - tp->snd_wl1 = ti->ti_seq - 1; - tp->rcv_up = ti->ti_seq; - goto step6; - } /* switch tp->t_state */ - /* - * States other than LISTEN or SYN_SENT. - * First check timestamp, if present. - * Then check that at least some bytes of segment are within - * receive window. If segment begins before rcv_nxt, - * drop leading data (and SYN); if nothing left, just ack. - * - * RFC 1323 PAWS: If we have a timestamp reply on this segment - * and it's less than ts_recent, drop it. - */ -/* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && - * TSTMP_LT(ts_val, tp->ts_recent)) { - * - */ /* Check to see if ts_recent is over 24 days old. */ -/* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { - */ /* - * * Invalidate ts_recent. If this segment updates - * * ts_recent, the age will be reset later and ts_recent - * * will get a valid value. If it does not, setting - * * ts_recent to zero will at least satisfy the - * * requirement that zero be placed in the timestamp - * * echo reply when ts_recent isn't valid. The - * * age isn't reset until we get a valid ts_recent - * * because we don't want out-of-order segments to be - * * dropped when ts_recent is old. - * */ -/* tp->ts_recent = 0; - * } else { - * tcpstat.tcps_rcvduppack++; - * tcpstat.tcps_rcvdupbyte += ti->ti_len; - * tcpstat.tcps_pawsdrop++; - * goto dropafterack; - * } - * } - */ - - todrop = tp->rcv_nxt - ti->ti_seq; - if (todrop > 0) { - if (tiflags & TH_SYN) { - tiflags &= ~TH_SYN; - ti->ti_seq++; - if (ti->ti_urp > 1) - ti->ti_urp--; - else - tiflags &= ~TH_URG; - todrop--; - } - /* - * Following if statement from Stevens, vol. 2, p. 960. - */ - if (todrop > ti->ti_len - || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { - /* - * Any valid FIN must be to the left of the window. - * At this point the FIN must be a duplicate or out - * of sequence; drop it. - */ - tiflags &= ~TH_FIN; - - /* - * Send an ACK to resynchronize and drop any data. - * But keep on processing for RST or ACK. - */ - tp->t_flags |= TF_ACKNOW; - todrop = ti->ti_len; - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += todrop; - } else { - tcpstat.tcps_rcvpartduppack++; - tcpstat.tcps_rcvpartdupbyte += todrop; - } - m_adj(m, todrop); - ti->ti_seq += todrop; - ti->ti_len -= todrop; - if (ti->ti_urp > todrop) - ti->ti_urp -= todrop; - else { - tiflags &= ~TH_URG; - ti->ti_urp = 0; - } - } - /* - * If new data are received on a connection after the - * user processes are gone, then RST the other end. - */ - if ((so->so_state & SS_NOFDREF) && - tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { - tp = tcp_close(tp); - tcpstat.tcps_rcvafterclose++; - goto dropwithreset; - } - - /* - * If segment ends after window, drop trailing data - * (and PUSH and FIN); if nothing left, just ACK. - */ - todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); - if (todrop > 0) { - tcpstat.tcps_rcvpackafterwin++; - if (todrop >= ti->ti_len) { - tcpstat.tcps_rcvbyteafterwin += ti->ti_len; - /* - * If a new connection request is received - * while in TIME_WAIT, drop the old connection - * and start over if the sequence numbers - * are above the previous ones. - */ - if (tiflags & TH_SYN && - tp->t_state == TCPS_TIME_WAIT && - SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { - iss = tp->rcv_nxt + TCP_ISSINCR; - tp = tcp_close(tp); - goto findso; - } - /* - * If window is closed can only take segments at - * window edge, and have to drop data and PUSH from - * incoming segments. Continue processing, but - * remember to ack. Otherwise, drop segment - * and ack. - */ - if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { - tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_rcvwinprobe++; - } else - goto dropafterack; - } else - tcpstat.tcps_rcvbyteafterwin += todrop; - m_adj(m, -todrop); - ti->ti_len -= todrop; - tiflags &= ~(TH_PUSH|TH_FIN); - } - - /* - * If last ACK falls within this segment's sequence numbers, - * record its timestamp. - */ -/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && - * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + - * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { - * tp->ts_recent_age = tcp_now; - * tp->ts_recent = ts_val; - * } - */ - - /* - * If the RST bit is set examine the state: - * SYN_RECEIVED STATE: - * If passive open, return to LISTEN state. - * If active open, inform user that connection was refused. - * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: - * Inform user that connection was reset, and close tcb. - * CLOSING, LAST_ACK, TIME_WAIT STATES - * Close the tcb. - */ - if (tiflags&TH_RST) switch (tp->t_state) { - - case TCPS_SYN_RECEIVED: -/* so->so_error = ECONNREFUSED; */ - goto close; - - case TCPS_ESTABLISHED: - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - case TCPS_CLOSE_WAIT: -/* so->so_error = ECONNRESET; */ - close: - tp->t_state = TCPS_CLOSED; - tcpstat.tcps_drops++; - tp = tcp_close(tp); - goto drop; - - case TCPS_CLOSING: - case TCPS_LAST_ACK: - case TCPS_TIME_WAIT: - tp = tcp_close(tp); - goto drop; - } - - /* - * If a SYN is in the window, then this is an - * error and we send an RST and drop the connection. - */ - if (tiflags & TH_SYN) { - tp = tcp_drop(tp,0); - goto dropwithreset; - } - - /* - * If the ACK bit is off we drop the segment and return. - */ - if ((tiflags & TH_ACK) == 0) goto drop; - - /* - * Ack processing. - */ - switch (tp->t_state) { - /* - * In SYN_RECEIVED state if the ack ACKs our SYN then enter - * ESTABLISHED state and continue processing, otherwise - * send an RST. una<=ack<=max - */ - case TCPS_SYN_RECEIVED: - - if (SEQ_GT(tp->snd_una, ti->ti_ack) || - SEQ_GT(ti->ti_ack, tp->snd_max)) - goto dropwithreset; - tcpstat.tcps_connects++; - tp->t_state = TCPS_ESTABLISHED; - /* - * The sent SYN is ack'ed with our sequence number +1 - * The first data byte already in the buffer will get - * lost if no correction is made. This is only needed for - * SS_CTL since the buffer is empty otherwise. - * tp->snd_una++; or: - */ - tp->snd_una=ti->ti_ack; - if (so->so_state & SS_CTL) { - /* So tcp_ctl reports the right state */ - ret = tcp_ctl(so); - if (ret == 1) { - soisfconnected(so); - so->so_state &= ~SS_CTL; /* success XXX */ - } else if (ret == 2) { - so->so_state = SS_NOFDREF; /* CTL_CMD */ - } else { - needoutput = 1; - tp->t_state = TCPS_FIN_WAIT_1; - } - } else { - soisfconnected(so); - } - - /* Do window scaling? */ -/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - * (TF_RCVD_SCALE|TF_REQ_SCALE)) { - * tp->snd_scale = tp->requested_s_scale; - * tp->rcv_scale = tp->request_r_scale; - * } - */ - (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct SLIRPmbuf *)0); - tp->snd_wl1 = ti->ti_seq - 1; - /* Avoid ack processing; snd_una==ti_ack => dup ack */ - goto synrx_to_est; - /* fall into ... */ - - /* - * In ESTABLISHED state: drop duplicate ACKs; ACK out of range - * ACKs. If the ack is in the range - * tp->snd_una < ti->ti_ack <= tp->snd_max - * then advance tp->snd_una to ti->ti_ack and drop - * data from the retransmission queue. If this ACK reflects - * more up to date window information we update our window information. - */ - case TCPS_ESTABLISHED: - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - case TCPS_CLOSE_WAIT: - case TCPS_CLOSING: - case TCPS_LAST_ACK: - case TCPS_TIME_WAIT: - - if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { - if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { - tcpstat.tcps_rcvdupack++; - DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", - (long )m, (long )so)); - /* - * If we have outstanding data (other than - * a window probe), this is a completely - * duplicate ack (ie, window info didn't - * change), the ack is the biggest we've - * seen and we've seen exactly our rexmt - * threshold of them, assume a packet - * has been dropped and retransmit it. - * Kludge snd_nxt & the congestion - * window so we send only this one - * packet. - * - * We know we're losing at the current - * window size so do congestion avoidance - * (set ssthresh to half the current window - * and pull our congestion window back to - * the new ssthresh). - * - * Dup acks mean that packets have left the - * network (they're now cached at the receiver) - * so bump cwnd by the amount in the receiver - * to keep a constant cwnd packets in the - * network. - */ - if (tp->t_timer[TCPT_REXMT] == 0 || - ti->ti_ack != tp->snd_una) - tp->t_dupacks = 0; - else if (++tp->t_dupacks == tcprexmtthresh) { - tcp_seq onxt = tp->snd_nxt; - u_int win = - min(tp->snd_wnd, tp->snd_cwnd) / 2 / - tp->t_maxseg; - - if (win < 2) - win = 2; - tp->snd_ssthresh = win * tp->t_maxseg; - tp->t_timer[TCPT_REXMT] = 0; - tp->t_rtt = 0; - tp->snd_nxt = ti->ti_ack; - tp->snd_cwnd = tp->t_maxseg; - (void) tcp_output(tp); - tp->snd_cwnd = tp->snd_ssthresh + - tp->t_maxseg * tp->t_dupacks; - if (SEQ_GT(onxt, tp->snd_nxt)) - tp->snd_nxt = onxt; - goto drop; - } else if (tp->t_dupacks > tcprexmtthresh) { - tp->snd_cwnd += tp->t_maxseg; - (void) tcp_output(tp); - goto drop; - } - } else - tp->t_dupacks = 0; - break; - } - synrx_to_est: - /* - * If the congestion window was inflated to account - * for the other side's cached packets, retract it. - */ - if (tp->t_dupacks > tcprexmtthresh && - tp->snd_cwnd > tp->snd_ssthresh) - tp->snd_cwnd = tp->snd_ssthresh; - tp->t_dupacks = 0; - if (SEQ_GT(ti->ti_ack, tp->snd_max)) { - tcpstat.tcps_rcvacktoomuch++; - goto dropafterack; - } - acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; - - /* - * If we have a timestamp reply, update smoothed - * round trip time. If no timestamp is present but - * transmit timer is running and timed sequence - * number was acked, update smoothed round trip time. - * Since we now have an rtt measurement, cancel the - * timer backoff (cf., Phil Karn's retransmit alg.). - * Recompute the initial retransmit timer. - */ -/* if (ts_present) - * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); - * else - */ - if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) - tcp_xmit_timer(tp,tp->t_rtt); - - /* - * If all outstanding data is acked, stop retransmit - * timer and remember to restart (more output or persist). - * If there is more data to be acked, restart retransmit - * timer, using current (possibly backed-off) value. - */ - if (ti->ti_ack == tp->snd_max) { - tp->t_timer[TCPT_REXMT] = 0; - needoutput = 1; - } else if (tp->t_timer[TCPT_PERSIST] == 0) - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - /* - * When new data is acked, open the congestion window. - * If the window gives us less than ssthresh packets - * in flight, open exponentially (maxseg per packet). - * Otherwise open linearly: maxseg per window - * (maxseg^2 / cwnd per packet). - */ - { - u_int cw = tp->snd_cwnd; - u_int incr = tp->t_maxseg; - - if (cw > tp->snd_ssthresh) - incr = incr * incr / cw; - tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); - } - if (acked > so->so_snd.sb_cc) { - tp->snd_wnd -= so->so_snd.sb_cc; - sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); - ourfinisacked = 1; - } else { - sbdrop(&so->so_snd, acked); - tp->snd_wnd -= acked; - ourfinisacked = 0; - } - /* - * XXX sowwakup is called when data is acked and there's room for - * for more data... it should read() the socket - */ -/* if (so->so_snd.sb_flags & SB_NOTIFY) - * sowwakeup(so); - */ - tp->snd_una = ti->ti_ack; - if (SEQ_LT(tp->snd_nxt, tp->snd_una)) - tp->snd_nxt = tp->snd_una; - - switch (tp->t_state) { - - /* - * In FIN_WAIT_1 STATE in addition to the processing - * for the ESTABLISHED state if our FIN is now acknowledged - * then enter FIN_WAIT_2. - */ - case TCPS_FIN_WAIT_1: - if (ourfinisacked) { - /* - * If we can't receive any more - * data, then closing user can proceed. - * Starting the timer is contrary to the - * specification, but if we don't get a FIN - * we'll hang forever. - */ - if (so->so_state & SS_FCANTRCVMORE) { - soisfdisconnected(so); - tp->t_timer[TCPT_2MSL] = tcp_maxidle; - } - tp->t_state = TCPS_FIN_WAIT_2; - } - break; - - /* - * In CLOSING STATE in addition to the processing for - * the ESTABLISHED state if the ACK acknowledges our FIN - * then enter the TIME-WAIT state, otherwise ignore - * the segment. - */ - case TCPS_CLOSING: - if (ourfinisacked) { - tp->t_state = TCPS_TIME_WAIT; - tcp_canceltimers(tp); - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - soisfdisconnected(so); - } - break; - - /* - * In LAST_ACK, we may still be waiting for data to drain - * and/or to be acked, as well as for the ack of our FIN. - * If our FIN is now acknowledged, delete the TCB, - * enter the closed state and return. - */ - case TCPS_LAST_ACK: - if (ourfinisacked) { - tp = tcp_close(tp); - goto drop; - } - break; - - /* - * In TIME_WAIT state the only thing that should arrive - * is a retransmission of the remote FIN. Acknowledge - * it and restart the finack timer. - */ - case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - goto dropafterack; - } - } /* switch(tp->t_state) */ + /* + * In TIME_WAIT state the only thing that should arrive + * is a retransmission of the remote FIN. Acknowledge + * it and restart the finack timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + goto dropafterack; + } + } /* switch(tp->t_state) */ step6: - /* - * Update window information. - * Don't look at window if no ACK: TAC's send garbage on first SYN. - */ - if ((tiflags & TH_ACK) && - (SEQ_LT(tp->snd_wl1, ti->ti_seq) || - (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || - (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { - /* keep track of pure window updates */ - if (ti->ti_len == 0 && - tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) - tcpstat.tcps_rcvwinupd++; - tp->snd_wnd = tiwin; - tp->snd_wl1 = ti->ti_seq; - tp->snd_wl2 = ti->ti_ack; - if (tp->snd_wnd > tp->max_sndwnd) - tp->max_sndwnd = tp->snd_wnd; - needoutput = 1; - } + /* + * Update window information. + * Don't look at window if no ACK: TAC's send garbage on first SYN. + */ + if ((tiflags & TH_ACK) && + (SEQ_LT(tp->snd_wl1, ti->ti_seq) || + (tp->snd_wl1 == ti->ti_seq && + (SEQ_LT(tp->snd_wl2, ti->ti_ack) || + (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { + tp->snd_wnd = tiwin; + tp->snd_wl1 = ti->ti_seq; + tp->snd_wl2 = ti->ti_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } - /* - * Process segments with URG. - */ - if ((tiflags & TH_URG) && ti->ti_urp && - TCPS_HAVERCVDFIN(tp->t_state) == 0) { - /* - * This is a kludge, but if we receive and accept - * random urgent pointers, we'll crash in - * soreceive. It's hard to imagine someone - * actually wanting to send this much urgent data. - */ - if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { - ti->ti_urp = 0; - tiflags &= ~TH_URG; - goto dodata; - } - /* - * If this segment advances the known urgent pointer, - * then mark the data stream. This should not happen - * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since - * a FIN has been received from the remote side. - * In these states we ignore the URG. - * - * According to RFC961 (Assigned Protocols), - * the urgent pointer points to the last octet - * of urgent data. We continue, however, - * to consider it to indicate the first octet - * of data past the urgent section as the original - * spec states (in one of two places). - */ - if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { - tp->rcv_up = ti->ti_seq + ti->ti_urp; - so->so_urgc = so->so_rcv.sb_cc + - (tp->rcv_up - tp->rcv_nxt); /* -1; */ - tp->rcv_up = ti->ti_seq + ti->ti_urp; - - } - } else - /* - * If no out of band data is expected, - * pull receive urgent pointer along - * with the receive window. - */ - if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) - tp->rcv_up = tp->rcv_nxt; + /* + * Process segments with URG. + */ + if ((tiflags & TH_URG) && ti->ti_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { + ti->ti_urp = 0; + tiflags &= ~TH_URG; + goto dodata; + } + /* + * If this segment advances the known urgent pointer, + * then mark the data stream. This should not happen + * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since + * a FIN has been received from the remote side. + * In these states we ignore the URG. + * + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section as the original + * spec states (in one of two places). + */ + if (SEQ_GT(ti->ti_seq + ti->ti_urp, tp->rcv_up)) { + tp->rcv_up = ti->ti_seq + ti->ti_urp; + so->so_urgc = + so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt); /* -1; */ + tp->rcv_up = ti->ti_seq + ti->ti_urp; + } + } else + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; dodata: - /* - * Process the segment text, merging it into the TCP sequencing queue, - * and arranging for acknowledgment of receipt if necessary. - * This process logically involves adjusting tp->rcv_wnd as data - * is presented to the user (this happens in tcp_usrreq.c, - * case PRU_RCVD). If a FIN has already been received on this - * connection then we just ignore the text. - */ - if ((ti->ti_len || (tiflags&TH_FIN)) && - TCPS_HAVERCVDFIN(tp->t_state) == 0) { - TCP_REASS(tp, ti, m, so, tiflags); - /* - * Note the amount of data that peer has sent into - * our window, in order to estimate the sender's - * buffer size. - */ - len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); - } else { - m_free(m); - tiflags &= ~TH_FIN; - } + /* + * If this is a small packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + */ + if (ti->ti_len && (unsigned)ti->ti_len <= 5 && + ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { + tp->t_flags |= TF_ACKNOW; + } - /* - * If FIN is received ACK the FIN and let the user know - * that the connection is closing. - */ - if (tiflags & TH_FIN) { - if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { - /* - * If we receive a FIN we can't send more data, - * set it SS_FDRAIN - * Shutdown the socket if there is no rx data in the - * buffer. - * soread() is called on completion of shutdown() and - * will got to TCPS_LAST_ACK, and use tcp_output() - * to send the FIN. - */ -/* sofcantrcvmore(so); */ - sofwdrain(so); - - tp->t_flags |= TF_ACKNOW; - tp->rcv_nxt++; - } - switch (tp->t_state) { + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((ti->ti_len || (tiflags & TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + TCP_REASS(tp, ti, m, so, tiflags); + } else { + m_free(m); + tiflags &= ~TH_FIN; + } - /* - * In SYN_RECEIVED and ESTABLISHED STATES - * enter the CLOSE_WAIT state. - */ - case TCPS_SYN_RECEIVED: - case TCPS_ESTABLISHED: - if(so->so_emu == EMU_CTL) /* no shutdown on socket */ - tp->t_state = TCPS_LAST_ACK; - else - tp->t_state = TCPS_CLOSE_WAIT; - break; + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * If we receive a FIN we can't send more data, + * set it SS_FDRAIN + * Shutdown the socket if there is no rx data in the + * buffer. + * soread() is called on completion of shutdown() and + * will got to TCPS_LAST_ACK, and use tcp_output() + * to send the FIN. + */ + sofwdrain(so); - /* - * If still in FIN_WAIT_1 STATE FIN has not been acked so - * enter the CLOSING state. - */ - case TCPS_FIN_WAIT_1: - tp->t_state = TCPS_CLOSING; - break; + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + if (so->so_emu == EMU_CTL) /* no shutdown on socket */ + tp->t_state = TCPS_LAST_ACK; + else + tp->t_state = TCPS_CLOSE_WAIT; + break; - /* - * In FIN_WAIT_2 state enter the TIME_WAIT state, - * starting the time-wait timer, turning off the other - * standard timers. - */ - case TCPS_FIN_WAIT_2: - tp->t_state = TCPS_TIME_WAIT; - tcp_canceltimers(tp); - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - soisfdisconnected(so); - break; + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tp->t_state = TCPS_CLOSING; + break; - /* - * In TIME_WAIT state restart the 2 MSL time_wait timer. - */ - case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - break; - } - } + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; - /* - * If this is a small packet, then ACK now - with Nagel - * congestion avoidance sender won't send more until - * he gets an ACK. - * - * See above. - */ -/* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { - */ -/* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && - * (so->so_iptos & IPTOS_LOWDELAY) == 0) || - * ((so->so_iptos & IPTOS_LOWDELAY) && - * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { - */ - if (ti->ti_len && (unsigned)ti->ti_len <= 5 && - ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { - tp->t_flags |= TF_ACKNOW; - } + /* + * In TIME_WAIT state restart the 2 MSL time_wait timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; + } + } - /* - * Return any desired output. - */ - if (needoutput || (tp->t_flags & TF_ACKNOW)) { - (void) tcp_output(tp); - } - return; + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) { + (void)tcp_output(tp); + } + return; dropafterack: - /* - * Generate an ACK dropping incoming segment if it occupies - * sequence space, where the ACK reflects our state. - */ - if (tiflags & TH_RST) - goto drop; - m_freem(m); - tp->t_flags |= TF_ACKNOW; - (void) tcp_output(tp); - return; + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + */ + if (tiflags & TH_RST) + goto drop; + m_free(m); + tp->t_flags |= TF_ACKNOW; + (void)tcp_output(tp); + return; dropwithreset: - /* reuses m if m!=NULL, m_free() unnecessary */ - if (tiflags & TH_ACK) - tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); - else { - if (tiflags & TH_SYN) ti->ti_len++; - tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, - TH_RST|TH_ACK); - } + /* reuses m if m!=NULL, m_free() unnecessary */ + if (tiflags & TH_ACK) + tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST, af); + else { + if (tiflags & TH_SYN) + ti->ti_len++; + tcp_respond(tp, ti, m, ti->ti_seq + ti->ti_len, (tcp_seq)0, + TH_RST | TH_ACK, af); + } - return; + return; drop: - /* - * Drop space held by incoming segment and return. - */ - m_free(m); - - return; + /* + * Drop space held by incoming segment and return. + */ + m_free(m); } - /* , ts_present, ts_val, ts_ecr) */ -/* int *ts_present; - * u_int32_t *ts_val, *ts_ecr; - */ -void -tcp_dooptions(tp, cp, cnt, ti) - struct tcpcb *tp; - u_char *cp; - int cnt; - struct tcpiphdr *ti; +static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt, + struct tcpiphdr *ti) { - u_int16_t mss; - int opt, optlen; + uint16_t mss; + int opt, optlen; - DEBUG_CALL("tcp_dooptions"); - DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); + DEBUG_CALL("tcp_dooptions"); + DEBUG_ARG("tp = %p cnt=%i", tp, cnt); - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[0]; - if (opt == TCPOPT_EOL) - break; - if (opt == TCPOPT_NOP) - optlen = 1; - else { - optlen = cp[1]; - if (optlen <= 0) - break; - } - switch (opt) { + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else { + optlen = cp[1]; + if (optlen <= 0) + break; + } + switch (opt) { + default: + continue; - default: - continue; - - case TCPOPT_MAXSEG: - if (optlen != TCPOLEN_MAXSEG) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); - NTOHS(mss); - (void) tcp_mss(tp, mss); /* sets t_maxseg */ - break; - -/* case TCPOPT_WINDOW: - * if (optlen != TCPOLEN_WINDOW) - * continue; - * if (!(ti->ti_flags & TH_SYN)) - * continue; - * tp->t_flags |= TF_RCVD_SCALE; - * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); - * break; - */ -/* case TCPOPT_TIMESTAMP: - * if (optlen != TCPOLEN_TIMESTAMP) - * continue; - * *ts_present = 1; - * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); - * NTOHL(*ts_val); - * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); - * NTOHL(*ts_ecr); - * - */ /* - * * A timestamp received in a SYN makes - * * it ok to send timestamp requests and replies. - * */ -/* if (ti->ti_flags & TH_SYN) { - * tp->t_flags |= TF_RCVD_TSTMP; - * tp->ts_recent = *ts_val; - * tp->ts_recent_age = tcp_now; - * } - */ break; - } - } + case TCPOPT_MAXSEG: + if (optlen != TCPOLEN_MAXSEG) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + memcpy((char *)&mss, (char *)cp + 2, sizeof(mss)); + NTOHS(mss); + (void)tcp_mss(tp, mss); /* sets t_maxseg */ + break; + } + } } - -/* - * Pull out of band byte out of a segment so - * it doesn't appear in the user's data queue. - * It is still reflected in the segment length for - * sequencing purposes. - */ - -#ifdef notdef - -void -tcp_pulloutofband(so, ti, m) - struct SLIRPsocket *so; - struct tcpiphdr *ti; - struct SLIRPmbuf *m; -{ - int cnt = ti->ti_urp - 1; - - while (cnt >= 0) { - if (m->m_len > cnt) { - char *cp = mtod(m, SLIRPcaddr_t) + cnt; - struct tcpcb *tp = sototcpcb(so); - - tp->t_iobc = *cp; - tp->t_oobflags |= TCPOOB_HAVEDATA; - memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); - m->m_len--; - return; - } - cnt -= m->m_len; - m = m->m_next; /* XXX WRONG! Fix it! */ - if (m == 0) - break; - } - panic("tcp_pulloutofband"); -} - -#endif /* notdef */ - /* * Collect new round-trip time estimate * and update averages and current timeout. */ -void -tcp_xmit_timer(tp, rtt) - struct tcpcb *tp; - int rtt; +static void tcp_xmit_timer(register struct tcpcb *tp, int rtt) { - short delta; + register short delta; - DEBUG_CALL("tcp_xmit_timer"); - DEBUG_ARG("tp = %lx", (long)tp); - DEBUG_ARG("rtt = %d", rtt); - - tcpstat.tcps_rttupdated++; - if (tp->t_srtt != 0) { - /* - * srtt is stored as fixed point with 3 bits after the - * binary point (i.e., scaled by 8). The following magic - * is equivalent to the smoothing algorithm in rfc793 with - * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed - * point). Adjust rtt to origin 0. - */ - delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); - if ((tp->t_srtt += delta) <= 0) - tp->t_srtt = 1; - /* - * We accumulate a smoothed rtt variance (actually, a - * smoothed mean difference), then set the retransmit - * timer to smoothed rtt + 4 times the smoothed variance. - * rttvar is stored as fixed point with 2 bits after the - * binary point (scaled by 4). The following is - * equivalent to rfc793 smoothing with an alpha of .75 - * (rttvar = rttvar*3/4 + |delta| / 4). This replaces - * rfc793's wired-in beta. - */ - if (delta < 0) - delta = -delta; - delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); - if ((tp->t_rttvar += delta) <= 0) - tp->t_rttvar = 1; - } else { - /* - * No rtt measurement yet - use the unsmoothed rtt. - * Set the variance to half the rtt (so our first - * retransmit happens at 3*rtt). - */ - tp->t_srtt = rtt << TCP_RTT_SHIFT; - tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); - } - tp->t_rtt = 0; - tp->t_rxtshift = 0; + DEBUG_CALL("tcp_xmit_timer"); + DEBUG_ARG("tp = %p", tp); + DEBUG_ARG("rtt = %d", rtt); - /* - * the retransmit should happen at rtt + 4 * rttvar. - * Because of the way we do the smoothing, srtt and rttvar - * will each average +1/2 tick of bias. When we compute - * the retransmit timer, we want 1/2 tick of rounding and - * 1 extra tick because of +-1/2 tick uncertainty in the - * firing of the timer. The bias will give us exactly the - * 1.5 tick we need. But, because the bias is - * statistical, we have to test that we don't drop below - * the minimum feasible timer (which is 2 ticks). - */ - TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), - (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ - - /* - * We received an ack for a packet that wasn't retransmitted; - * it is probably safe to discard any error indications we've - * received recently. This isn't quite right, but close enough - * for now (a route might have failed after we sent a segment, - * and the return path might not be symmetrical). - */ - tp->t_softerror = 0; + if (tp->t_srtt != 0) { + /* + * srtt is stored as fixed point with 3 bits after the + * binary point (i.e., scaled by 8). The following magic + * is equivalent to the smoothing algorithm in rfc793 with + * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed + * point). Adjust rtt to origin 0. + */ + delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); + if ((tp->t_srtt += delta) <= 0) + tp->t_srtt = 1; + /* + * We accumulate a smoothed rtt variance (actually, a + * smoothed mean difference), then set the retransmit + * timer to smoothed rtt + 4 times the smoothed variance. + * rttvar is stored as fixed point with 2 bits after the + * binary point (scaled by 4). The following is + * equivalent to rfc793 smoothing with an alpha of .75 + * (rttvar = rttvar*3/4 + |delta| / 4). This replaces + * rfc793's wired-in beta. + */ + if (delta < 0) + delta = -delta; + delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); + if ((tp->t_rttvar += delta) <= 0) + tp->t_rttvar = 1; + } else { + /* + * No rtt measurement yet - use the unsmoothed rtt. + * Set the variance to half the rtt (so our first + * retransmit happens at 3*rtt). + */ + tp->t_srtt = rtt << TCP_RTT_SHIFT; + tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); + } + tp->t_rtt = 0; + tp->t_rxtshift = 0; + + /* + * the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + */ + TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), (short)tp->t_rttmin, + TCPTV_REXMTMAX); /* XXX */ + + /* + * We received an ack for a packet that wasn't retransmitted; + * it is probably safe to discard any error indications we've + * received recently. This isn't quite right, but close enough + * for now (a route might have failed after we sent a segment, + * and the return path might not be symmetrical). + */ + tp->t_softerror = 0; } /* @@ -1680,8 +1485,8 @@ tcp_xmit_timer(tp, rtt) * If the route is known, check route for mtu. * If none, use an mss that can be handled on the outgoing * interface without forcing IP to fragment; if bigger than - * an SLIRPmbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES - * to utilize large SLIRPmbufs. If no route is found, route has no mtu, + * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES + * to utilize large mbufs. If no route is found, route has no mtu, * or the destination isn't local, use a default, hopefully conservative * size (usually 512 or the default IP max size, but no more than the mtu * of the interface), as we can't discover anything about intervening @@ -1691,31 +1496,44 @@ tcp_xmit_timer(tp, rtt) * parameters from pre-set or cached values in the routing entry. */ -int -tcp_mss(tp, offer) - struct tcpcb *tp; - u_int offer; +int tcp_mss(struct tcpcb *tp, unsigned offer) { - struct SLIRPsocket *so = tp->t_socket; - int mss; - - DEBUG_CALL("tcp_mss"); - DEBUG_ARG("tp = %lx", (long)tp); - DEBUG_ARG("offer = %d", offer); - - mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); - if (offer) - mss = min(mss, offer); - mss = max(mss, 32); - if (mss < tp->t_maxseg || offer != 0) - tp->t_maxseg = mss; - - tp->snd_cwnd = mss; - - sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); - sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); - - DEBUG_MISC((dfd, " returning mss = %d\n", mss)); - - return mss; + struct socket *so = tp->t_socket; + int mss; + + DEBUG_CALL("tcp_mss"); + DEBUG_ARG("tp = %p", tp); + DEBUG_ARG("offer = %d", offer); + + switch (so->so_ffamily) { + case AF_INET: + mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) - + sizeof(struct tcphdr) - sizeof(struct ip); + break; + case AF_INET6: + mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) - + sizeof(struct tcphdr) - sizeof(struct ip6); + break; + default: + g_assert_not_reached(); + } + + if (offer) + mss = MIN(mss, offer); + mss = MAX(mss, 32); + if (mss < tp->t_maxseg || offer != 0) + tp->t_maxseg = MIN(mss, TCP_MAXSEG_MAX); + + tp->snd_cwnd = mss; + + sbreserve(&so->so_snd, + TCP_SNDSPACE + + ((TCP_SNDSPACE % mss) ? (mss - (TCP_SNDSPACE % mss)) : 0)); + sbreserve(&so->so_rcv, + TCP_RCVSPACE + + ((TCP_RCVSPACE % mss) ? (mss - (TCP_RCVSPACE % mss)) : 0)); + + DEBUG_MISC(" returning mss = %d", mss); + + return mss; } diff --git a/src/network/slirp/tcp_output.c b/src/network/slirp/tcp_output.c index 7d75b64b2..383fe31dc 100644 --- a/src/network/slirp/tcp_output.c +++ b/src/network/slirp/tcp_output.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -33,569 +34,483 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ #include "slirp.h" -/* - * Since this is only used in "stats socket", we give meaning - * names instead of the REAL names - */ -char *tcpstates[] = { -/* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ - "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", - "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", - "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", -}; - -u_char tcp_outflags[TCP_NSTATES] = { - TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, - TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, - TH_FIN|TH_ACK, TH_ACK, TH_ACK, +static const uint8_t tcp_outflags[TCP_NSTATES] = { + TH_RST | TH_ACK, 0, TH_SYN, TH_SYN | TH_ACK, + TH_ACK, TH_ACK, TH_FIN | TH_ACK, TH_FIN | TH_ACK, + TH_FIN | TH_ACK, TH_ACK, TH_ACK, }; -#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ +#undef MAX_TCPOPTLEN +#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ /* * Tcp output routine: figure out what should be sent and send it. */ -int -tcp_output(tp) - struct tcpcb *tp; +int tcp_output(struct tcpcb *tp) { - struct SLIRPsocket *so = tp->t_socket; - register long len, win; - int off, flags, error; - struct SLIRPmbuf *m; - struct tcpiphdr *ti; - u_char opt[MAX_TCPOPTLEN]; - unsigned optlen, hdrlen; - int idle, sendalot; - - DEBUG_CALL("tcp_output"); - DEBUG_ARG("tp = %lx", (long )tp); - - /* - * Determine length of data that should be transmitted, - * and flags that will be used. - * If there is some data or critical controls (SYN, RST) - * to send, then transmit; otherwise, investigate further. - */ - idle = (tp->snd_max == tp->snd_una); - if (idle && tp->t_idle >= tp->t_rxtcur) - /* - * We have been idle for "a while" and no acks are - * expected to clock out any data we send -- - * slow start to get ack "clock" running again. - */ - tp->snd_cwnd = tp->t_maxseg; + register struct socket *so = tp->t_socket; + register long len, win; + int off, flags, error; + register struct mbuf *m; + register struct tcpiphdr *ti, tcpiph_save; + struct ip *ip; + struct ip6 *ip6; + uint8_t opt[MAX_TCPOPTLEN]; + unsigned optlen, hdrlen; + int idle, sendalot; + + DEBUG_CALL("tcp_output"); + DEBUG_ARG("tp = %p", tp); + + /* + * Determine length of data that should be transmitted, + * and flags that will be used. + * If there is some data or critical controls (SYN, RST) + * to send, then transmit; otherwise, investigate further. + */ + idle = (tp->snd_max == tp->snd_una); + if (idle && tp->t_idle >= tp->t_rxtcur) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tp->snd_cwnd = tp->t_maxseg; again: - sendalot = 0; - off = tp->snd_nxt - tp->snd_una; - win = min(tp->snd_wnd, tp->snd_cwnd); + sendalot = 0; + off = tp->snd_nxt - tp->snd_una; + win = MIN(tp->snd_wnd, tp->snd_cwnd); - flags = tcp_outflags[tp->t_state]; - - DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); - - /* - * If in persist timeout with window of 0, send 1 byte. - * Otherwise, if window is small but nonzero - * and timer expired, we will send what we can - * and go to transmit state. - */ - if (tp->t_force) { - if (win == 0) { - /* - * If we still have some data to send, then - * clear the FIN bit. Usually this would - * happen below when it realizes that we - * aren't sending all the data. However, - * if we have exactly 1 byte of unset data, - * then it won't clear the FIN bit below, - * and if we are in persist state, we wind - * up sending the packet without recording - * that we sent the FIN bit. - * - * We can't just blindly clear the FIN bit, - * because if we don't have any more data - * to send then the probe will be the FIN - * itself. - */ - if (off < so->so_snd.sb_cc) - flags &= ~TH_FIN; - win = 1; - } else { - tp->t_timer[TCPT_PERSIST] = 0; - tp->t_rxtshift = 0; - } - } + flags = tcp_outflags[tp->t_state]; - len = min(so->so_snd.sb_cc, win) - off; + DEBUG_MISC(" --- tcp_output flags = 0x%x", flags); - if (len < 0) { - /* - * If FIN has been sent but not acked, - * but we haven't been called to retransmit, - * len will be -1. Otherwise, window shrank - * after we sent into it. If window shrank to 0, - * cancel pending retransmit and pull snd_nxt - * back to (closed) window. We will enter persist - * state below. If the window didn't close completely, - * just wait for an ACK. - */ - len = 0; - if (win == 0) { - tp->t_timer[TCPT_REXMT] = 0; - tp->snd_nxt = tp->snd_una; - } - } - - if (len > tp->t_maxseg) { - len = tp->t_maxseg; - sendalot = 1; - } - if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) - flags &= ~TH_FIN; + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ + if (tp->t_force) { + if (win == 0) { + /* + * If we still have some data to send, then + * clear the FIN bit. Usually this would + * happen below when it realizes that we + * aren't sending all the data. However, + * if we have exactly 1 byte of unset data, + * then it won't clear the FIN bit below, + * and if we are in persist state, we wind + * up sending the packet without recording + * that we sent the FIN bit. + * + * We can't just blindly clear the FIN bit, + * because if we don't have any more data + * to send then the probe will be the FIN + * itself. + */ + if (off < so->so_snd.sb_cc) + flags &= ~TH_FIN; + win = 1; + } else { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } - win = sbspace(&so->so_rcv); + len = MIN(so->so_snd.sb_cc, win) - off; - /* - * Sender silly window avoidance. If connection is idle - * and can send all data, a maximum segment, - * at least a maximum default-size segment do it, - * or are forced, do it; otherwise don't bother. - * If peer's buffer is tiny, then send - * when window is at least half open. - * If retransmitting (possibly after persist timer forced us - * to send into a small window), then must resend. - */ - if (len) { - if (len == tp->t_maxseg) - goto send; - if ((1 || idle || tp->t_flags & TF_NODELAY) && - len + off >= so->so_snd.sb_cc) - goto send; - if (tp->t_force) - goto send; - if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) - goto send; - if (SEQ_LT(tp->snd_nxt, tp->snd_max)) - goto send; - } + if (len < 0) { + /* + * If FIN has been sent but not acked, + * but we haven't been called to retransmit, + * len will be -1. Otherwise, window shrank + * after we sent into it. If window shrank to 0, + * cancel pending retransmit and pull snd_nxt + * back to (closed) window. We will enter persist + * state below. If the window didn't close completely, + * just wait for an ACK. + */ + len = 0; + if (win == 0) { + tp->t_timer[TCPT_REXMT] = 0; + tp->snd_nxt = tp->snd_una; + } + } - /* - * Compare available window to amount of window - * known to peer (as advertised window less - * next expected input). If the difference is at least two - * max size segments, or at least 50% of the maximum possible - * window, then want to send a window update to peer. - */ - if (win > 0) { - /* - * "adv" is the amount we can increase the window, - * taking into account that we are limited by - * TCP_MAXWIN << tp->rcv_scale. - */ - long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - - (tp->rcv_adv - tp->rcv_nxt); + if (len > tp->t_maxseg) { + len = tp->t_maxseg; + sendalot = 1; + } + if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) + flags &= ~TH_FIN; - if (adv >= (long) (2 * tp->t_maxseg)) - goto send; - if (2 * adv >= (long) so->so_rcv.sb_datalen) - goto send; - } + win = sbspace(&so->so_rcv); - /* - * Send if we owe peer an ACK. - */ - if (tp->t_flags & TF_ACKNOW) - goto send; - if (flags & (TH_SYN|TH_RST)) - goto send; - if (SEQ_GT(tp->snd_up, tp->snd_una)) - goto send; - /* - * If our state indicates that FIN should be sent - * and we have not yet done so, or we're retransmitting the FIN, - * then we need to send. - */ - if (flags & TH_FIN && - ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) - goto send; + /* + * Sender silly window avoidance. If connection is idle + * and can send all data, a maximum segment, + * at least a maximum default-size segment do it, + * or are forced, do it; otherwise don't bother. + * If peer's buffer is tiny, then send + * when window is at least half open. + * If retransmitting (possibly after persist timer forced us + * to send into a small window), then must resend. + */ + if (len) { + if (len == tp->t_maxseg) + goto send; + if ((1 || idle || tp->t_flags & TF_NODELAY) && + len + off >= so->so_snd.sb_cc) + goto send; + if (tp->t_force) + goto send; + if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) + goto send; + if (SEQ_LT(tp->snd_nxt, tp->snd_max)) + goto send; + } - /* - * TCP window updates are not reliable, rather a polling protocol - * using ``persist'' packets is used to insure receipt of window - * updates. The three ``states'' for the output side are: - * idle not doing retransmits or persists - * persisting to move a small or zero window - * (re)transmitting and thereby not persisting - * - * tp->t_timer[TCPT_PERSIST] - * is set when we are in persist state. - * tp->t_force - * is set when we are called to send a persist packet. - * tp->t_timer[TCPT_REXMT] - * is set when we are retransmitting - * The output side is idle when both timers are zero. - * - * If send window is too small, there is data to transmit, and no - * retransmit or persist is pending, then go to persist state. - * If nothing happens soon, send when timer expires: - * if window is nonzero, transmit what we can, - * otherwise force out a byte. - */ - if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && - tp->t_timer[TCPT_PERSIST] == 0) { - tp->t_rxtshift = 0; - tcp_setpersist(tp); - } + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input). If the difference is at least two + * max size segments, or at least 50% of the maximum possible + * window, then want to send a window update to peer. + */ + if (win > 0) { + /* + * "adv" is the amount we can increase the window, + * taking into account that we are limited by + * TCP_MAXWIN << tp->rcv_scale. + */ + long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) - + (tp->rcv_adv - tp->rcv_nxt); - /* - * No reason to send a segment, just return. - */ - tcpstat.tcps_didnuttin++; - - return (0); + if (adv >= (long)(2 * tp->t_maxseg)) + goto send; + if (2 * adv >= (long)so->so_rcv.sb_datalen) + goto send; + } + + /* + * Send if we owe peer an ACK. + */ + if (tp->t_flags & TF_ACKNOW) + goto send; + if (flags & (TH_SYN | TH_RST)) + goto send; + if (SEQ_GT(tp->snd_up, tp->snd_una)) + goto send; + /* + * If our state indicates that FIN should be sent + * and we have not yet done so, or we're retransmitting the FIN, + * then we need to send. + */ + if (flags & TH_FIN && + ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) + goto send; + + /* + * TCP window updates are not reliable, rather a polling protocol + * using ``persist'' packets is used to insure receipt of window + * updates. The three ``states'' for the output side are: + * idle not doing retransmits or persists + * persisting to move a small or zero window + * (re)transmitting and thereby not persisting + * + * tp->t_timer[TCPT_PERSIST] + * is set when we are in persist state. + * tp->t_force + * is set when we are called to send a persist packet. + * tp->t_timer[TCPT_REXMT] + * is set when we are retransmitting + * The output side is idle when both timers are zero. + * + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise force out a byte. + */ + if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_rxtshift = 0; + tcp_setpersist(tp); + } + + /* + * No reason to send a segment, just return. + */ + return (0); send: - /* - * Before ESTABLISHED, force sending of initial options - * unless TCP set not to do any options. - * NOTE: we assume that the IP/TCP header plus TCP options - * always fit in a single SLIRPmbuf, leaving room for a maximum - * link header, i.e. - * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN - */ - optlen = 0; - hdrlen = sizeof (struct tcpiphdr); - if (flags & TH_SYN) { - tp->snd_nxt = tp->iss; - if ((tp->t_flags & TF_NOOPT) == 0) { - u_int16_t mss; + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set not to do any options. + * NOTE: we assume that the IP/TCP header plus TCP options + * always fit in a single mbuf, leaving room for a maximum + * link header, i.e. + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + */ + optlen = 0; + hdrlen = sizeof(struct tcpiphdr); + if (flags & TH_SYN) { + tp->snd_nxt = tp->iss; + if ((tp->t_flags & TF_NOOPT) == 0) { + uint16_t mss; - opt[0] = TCPOPT_MAXSEG; - opt[1] = 4; - mss = htons((u_int16_t) tcp_mss(tp, 0)); - memcpy((SLIRPcaddr_t)(opt + 2), (SLIRPcaddr_t)&mss, sizeof(mss)); - optlen = 4; - -/* if ((tp->t_flags & TF_REQ_SCALE) && - * ((flags & TH_ACK) == 0 || - * (tp->t_flags & TF_RCVD_SCALE))) { - * *((u_int32_t *) (opt + optlen)) = htonl( - * TCPOPT_NOP << 24 | - * TCPOPT_WINDOW << 16 | - * TCPOLEN_WINDOW << 8 | - * tp->request_r_scale); - * optlen += 4; - * } - */ - } - } - - /* - * Send a timestamp and echo-reply if this is a SYN and our side - * wants to use timestamps (TF_REQ_TSTMP is set) or both our side - * and our peer have sent timestamps in our SYN's. - */ -/* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && - * (flags & TH_RST) == 0 && - * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || - * (tp->t_flags & TF_RCVD_TSTMP))) { - * u_int32_t *lp = (u_int32_t *)(opt + optlen); - * - * / * Form timestamp option as shown in appendix A of RFC 1323. * / - * *lp++ = htonl(TCPOPT_TSTAMP_HDR); - * *lp++ = htonl(tcp_now); - * *lp = htonl(tp->ts_recent); - * optlen += TCPOLEN_TSTAMP_APPA; - * } - */ - hdrlen += optlen; - - /* - * Adjust data length if insertion of options will - * bump the packet length beyond the t_maxseg length. - */ - if (len > tp->t_maxseg - optlen) { - len = tp->t_maxseg - optlen; - sendalot = 1; - } - - /* - * Grab a header SLIRPmbuf, attaching a copy of data to - * be transmitted, and initialize the header from - * the template for sends on this connection. - */ - if (len) { - if (tp->t_force && len == 1) - tcpstat.tcps_sndprobe++; - else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { - tcpstat.tcps_sndrexmitpack++; - tcpstat.tcps_sndrexmitbyte += len; - } else { - tcpstat.tcps_sndpack++; - tcpstat.tcps_sndbyte += len; - } - - m = m_get(); - if (m == NULL) { -/* error = ENOBUFS; */ - error = 1; - goto out; - } - m->m_data += if_maxlinkhdr; - m->m_len = hdrlen; - - /* - * This will always succeed, since we make sure our SLIRPmbufs - * are big enough to hold one MSS packet + header + ... etc. - */ -/* if (len <= MHLEN - hdrlen - max_linkhdr) { */ - - sbcopy(&so->so_snd, off, (int) len, mtod(m, SLIRPcaddr_t) + hdrlen); - m->m_len += len; - -/* } else { - * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); - * if (m->m_next == 0) - * len = 0; - * } - */ - /* - * If we're sending everything we've got, set PUSH. - * (This will keep happy those implementations which only - * give data to the user when a buffer fills or - * a PUSH comes in.) - */ - if (off + len == so->so_snd.sb_cc) - flags |= TH_PUSH; - } else { - if (tp->t_flags & TF_ACKNOW) - tcpstat.tcps_sndacks++; - else if (flags & (TH_SYN|TH_FIN|TH_RST)) - tcpstat.tcps_sndctrl++; - else if (SEQ_GT(tp->snd_up, tp->snd_una)) - tcpstat.tcps_sndurg++; - else - tcpstat.tcps_sndwinup++; - - m = m_get(); - if (m == NULL) { -/* error = ENOBUFS; */ - error = 1; - goto out; - } - m->m_data += if_maxlinkhdr; - m->m_len = hdrlen; - } - - ti = mtod(m, struct tcpiphdr *); - - memcpy((SLIRPcaddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); - - /* - * Fill in fields, remembering maximum advertised - * window for use in delaying messages about window sizes. - * If resending a FIN, be sure not to use a new sequence number. - */ - if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && - tp->snd_nxt == tp->snd_max) - tp->snd_nxt--; - /* - * If we are doing retransmissions, then snd_nxt will - * not reflect the first unsent octet. For ACK only - * packets, we do not want the sequence number of the - * retransmitted packet, we want the sequence number - * of the next unsent octet. So, if there is no data - * (and no SYN or FIN), use snd_max instead of snd_nxt - * when filling in ti_seq. But if we are in persist - * state, snd_max might reflect one byte beyond the - * right edge of the window, so use snd_nxt in that - * case, since we know we aren't doing a retransmission. - * (retransmit and persist are mutually exclusive...) - */ - if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) - ti->ti_seq = htonl(tp->snd_nxt); - else - ti->ti_seq = htonl(tp->snd_max); - ti->ti_ack = htonl(tp->rcv_nxt); - if (optlen) { - memcpy((SLIRPcaddr_t)(ti + 1), (SLIRPcaddr_t)opt, optlen); - ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; - } - ti->ti_flags = flags; - /* - * Calculate receive window. Don't shrink window, - * but avoid silly window syndrome. - */ - if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) - win = 0; - if (win > (long)TCP_MAXWIN << tp->rcv_scale) - win = (long)TCP_MAXWIN << tp->rcv_scale; - if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) - win = (long)(tp->rcv_adv - tp->rcv_nxt); - ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); - - if (SEQ_GT(tp->snd_up, tp->snd_una)) { - ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); -#ifdef notdef - if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { - ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); -#endif - ti->ti_flags |= TH_URG; - } else - /* - * If no urgent pointer to send, then we pull - * the urgent pointer to the left edge of the send window - * so that it doesn't drift into the send window on sequence - * number wraparound. - */ - tp->snd_up = tp->snd_una; /* drag it along */ - - /* - * Put TCP length in extended header, and then - * checksum extended header and data. - */ - if (len + optlen) - ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + - optlen + len)); - ti->ti_sum = cksum(m, (int)(hdrlen + len)); - - /* - * In transmit state, time the transmission and arrange for - * the retransmit. In persist state, just set snd_max. - */ - if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { - tcp_seq startseq = tp->snd_nxt; - - /* - * Advance snd_nxt over sequence space of this segment. - */ - if (flags & (TH_SYN|TH_FIN)) { - if (flags & TH_SYN) - tp->snd_nxt++; - if (flags & TH_FIN) { - tp->snd_nxt++; - tp->t_flags |= TF_SENTFIN; - } - } - tp->snd_nxt += len; - if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { - tp->snd_max = tp->snd_nxt; - /* - * Time this transmission if not a retransmission and - * not currently timing anything. - */ - if (tp->t_rtt == 0) { - tp->t_rtt = 1; - tp->t_rtseq = startseq; - tcpstat.tcps_segstimed++; - } - } - - /* - * Set retransmit timer if not currently set, - * and not doing an ack or a keep-alive probe. - * Initial value for retransmit timer is smoothed - * round-trip time + 2 * round-trip time variance. - * Initialize shift counter which is used for backoff - * of retransmit time. - */ - if (tp->t_timer[TCPT_REXMT] == 0 && - tp->snd_nxt != tp->snd_una) { - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - if (tp->t_timer[TCPT_PERSIST]) { - tp->t_timer[TCPT_PERSIST] = 0; - tp->t_rxtshift = 0; - } - } - } else - if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) - tp->snd_max = tp->snd_nxt + len; - - /* - * Fill in IP length and desired time to live and - * send to IP level. There should be a better way - * to handle ttl and tos; we could keep them in - * the template, but need a way to checksum without them. - */ - m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ - - { - - ((struct ip *)ti)->ip_len = m->m_len; - - ((struct ip *)ti)->ip_ttl = ip_defttl; - ((struct ip *)ti)->ip_tos = so->so_iptos; - -/* #if BSD >= 43 */ - /* Don't do IP options... */ -/* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, - * so->so_options & SO_DONTROUTE, 0); - */ - error = ip_output(so, m); - -/* #else - * error = ip_output(m, (struct SLIRPmbuf *)0, &tp->t_inpcb->inp_route, - * so->so_options & SO_DONTROUTE); - * #endif - */ + opt[0] = TCPOPT_MAXSEG; + opt[1] = 4; + mss = htons((uint16_t)tcp_mss(tp, 0)); + memcpy((char *)(opt + 2), (char *)&mss, sizeof(mss)); + optlen = 4; + } } - if (error) { -out: -/* if (error == ENOBUFS) { - * tcp_quench(tp->t_inpcb, 0); - * return (0); - * } - */ -/* if ((error == EHOSTUNREACH || error == ENETDOWN) - * && TCPS_HAVERCVDSYN(tp->t_state)) { - * tp->t_softerror = error; - * return (0); - * } - */ - return (error); - } - tcpstat.tcps_sndtotal++; - /* - * Data sent (as far as we can tell). - * If this advertises a larger window than any other segment, - * then remember the size of the advertised window. - * Any pending ACK has now been sent. - */ - if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) - tp->rcv_adv = tp->rcv_nxt + win; - tp->last_ack_sent = tp->rcv_nxt; - tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); - if (sendalot) - goto again; + hdrlen += optlen; - return (0); + /* + * Adjust data length if insertion of options will + * bump the packet length beyond the t_maxseg length. + */ + if (len > tp->t_maxseg - optlen) { + len = tp->t_maxseg - optlen; + sendalot = 1; + } + + /* + * Grab a header mbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ + if (len) { + m = m_get(so->slirp); + if (m == NULL) { + error = 1; + goto out; + } + m->m_data += IF_MAXLINKHDR; + m->m_len = hdrlen; + + sbcopy(&so->so_snd, off, (int)len, mtod(m, char *) + hdrlen); + m->m_len += len; + + /* + * If we're sending everything we've got, set PUSH. + * (This will keep happy those implementations which only + * give data to the user when a buffer fills or + * a PUSH comes in.) + */ + if (off + len == so->so_snd.sb_cc) + flags |= TH_PUSH; + } else { + m = m_get(so->slirp); + if (m == NULL) { + error = 1; + goto out; + } + m->m_data += IF_MAXLINKHDR; + m->m_len = hdrlen; + } + + ti = mtod(m, struct tcpiphdr *); + + memcpy((char *)ti, &tp->t_template, sizeof(struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + * If resending a FIN, be sure not to use a new sequence number. + */ + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + tp->snd_nxt == tp->snd_max) + tp->snd_nxt--; + /* + * If we are doing retransmissions, then snd_nxt will + * not reflect the first unsent octet. For ACK only + * packets, we do not want the sequence number of the + * retransmitted packet, we want the sequence number + * of the next unsent octet. So, if there is no data + * (and no SYN or FIN), use snd_max instead of snd_nxt + * when filling in ti_seq. But if we are in persist + * state, snd_max might reflect one byte beyond the + * right edge of the window, so use snd_nxt in that + * case, since we know we aren't doing a retransmission. + * (retransmit and persist are mutually exclusive...) + */ + if (len || (flags & (TH_SYN | TH_FIN)) || tp->t_timer[TCPT_PERSIST]) + ti->ti_seq = htonl(tp->snd_nxt); + else + ti->ti_seq = htonl(tp->snd_max); + ti->ti_ack = htonl(tp->rcv_nxt); + if (optlen) { + memcpy((char *)(ti + 1), (char *)opt, optlen); + ti->ti_off = (sizeof(struct tcphdr) + optlen) >> 2; + } + ti->ti_flags = flags; + /* + * Calculate receive window. Don't shrink window, + * but avoid silly window syndrome. + */ + if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) + win = 0; + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) + win = (long)(tp->rcv_adv - tp->rcv_nxt); + ti->ti_win = htons((uint16_t)(win >> tp->rcv_scale)); + + if (SEQ_GT(tp->snd_up, tp->snd_una)) { + ti->ti_urp = htons((uint16_t)(tp->snd_up - ntohl(ti->ti_seq))); + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_up = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len + optlen) + ti->ti_len = htons((uint16_t)(sizeof(struct tcphdr) + optlen + len)); + ti->ti_sum = cksum(m, (int)(hdrlen + len)); + + /* + * In transmit state, time the transmission and arrange for + * the retransmit. In persist state, just set snd_max. + */ + if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { + tcp_seq startseq = tp->snd_nxt; + + /* + * Advance snd_nxt over sequence space of this segment. + */ + if (flags & (TH_SYN | TH_FIN)) { + if (flags & TH_SYN) + tp->snd_nxt++; + if (flags & TH_FIN) { + tp->snd_nxt++; + tp->t_flags |= TF_SENTFIN; + } + } + tp->snd_nxt += len; + if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { + tp->snd_max = tp->snd_nxt; + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = startseq; + } + } + + /* + * Set retransmit timer if not currently set, + * and not doing an ack or a keep-alive probe. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + } else if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) + tp->snd_max = tp->snd_nxt + len; + + /* + * Fill in IP length and desired time to live and + * send to IP level. There should be a better way + * to handle ttl and tos; we could keep them in + * the template, but need a way to checksum without them. + */ + m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ + tcpiph_save = *mtod(m, struct tcpiphdr *); + + switch (so->so_ffamily) { + case AF_INET: + m->m_data += + sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip); + m->m_len -= + sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip); + ip = mtod(m, struct ip *); + + ip->ip_len = m->m_len; + ip->ip_dst = tcpiph_save.ti_dst; + ip->ip_src = tcpiph_save.ti_src; + ip->ip_p = tcpiph_save.ti_pr; + + ip->ip_ttl = IPDEFTTL; + ip->ip_tos = so->so_iptos; + error = ip_output(so, m); + break; + + case AF_INET6: + m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - + sizeof(struct ip6); + m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - + sizeof(struct ip6); + ip6 = mtod(m, struct ip6 *); + + ip6->ip_pl = tcpiph_save.ti_len; + ip6->ip_dst = tcpiph_save.ti_dst6; + ip6->ip_src = tcpiph_save.ti_src6; + ip6->ip_nh = tcpiph_save.ti_nh6; + + error = ip6_output(so, m, 0); + break; + + default: + g_assert_not_reached(); + } + + if (error) { + out: + return (error); + } + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertised window. + * Any pending ACK has now been sent. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt + win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->last_ack_sent = tp->rcv_nxt; + tp->t_flags &= ~(TF_ACKNOW | TF_DELACK); + if (sendalot) + goto again; + + return (0); } -void -tcp_setpersist(tp) - struct tcpcb *tp; +void tcp_setpersist(struct tcpcb *tp) { int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; -/* if (tp->t_timer[TCPT_REXMT]) - * panic("tcp_output REXMT"); - */ - /* - * Start/restart persistence timer. - */ - TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], - t * tcp_backoff[tp->t_rxtshift], - TCPTV_PERSMIN, TCPTV_PERSMAX); - if (tp->t_rxtshift < TCP_MAXRXTSHIFT) - tp->t_rxtshift++; + /* + * Start/restart persistence timer. + */ + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], t * tcp_backoff[tp->t_rxtshift], + TCPTV_PERSMIN, TCPTV_PERSMAX); + if (tp->t_rxtshift < TCP_MAXRXTSHIFT) + tp->t_rxtshift++; } diff --git a/src/network/slirp/tcp_subr.c b/src/network/slirp/tcp_subr.c index 5f04b0730..a1016d90d 100644 --- a/src/network/slirp/tcp_subr.c +++ b/src/network/slirp/tcp_subr.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -33,41 +34,29 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the - * terms and conditions of the copyright. */ -#define WANT_SYS_IOCTL_H -#include -#ifndef _WIN32 -# include -#endif #include "slirp.h" /* patchable/settable parameters for tcp */ -int tcp_mssdflt = TCP_MSS; -int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; -int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ -int tcp_rcvspace; /* You may want to change this */ -int tcp_sndspace; /* Keep small if you have an error prone link */ +/* Don't do rfc1323 performance enhancements */ +#define TCP_DO_RFC1323 0 /* * Tcp initialization */ -void -tcp_init() +void tcp_init(Slirp *slirp) { - tcp_iss = 1; /* wrong */ - tcb.so_next = tcb.so_prev = &tcb; - - /* tcp_rcvspace = our Window we advertise to the remote */ - tcp_rcvspace = TCP_RCVSPACE; - tcp_sndspace = TCP_SNDSPACE; - - /* Make sure tcp_sndspace is at least 2*MSS */ - if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) - tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); + slirp->tcp_iss = 1; /* wrong */ + slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb; + slirp->tcp_last_so = &slirp->tcb; +} + +void tcp_cleanup(Slirp *slirp) +{ + while (slirp->tcb.so_next != &slirp->tcb) { + tcp_close(sototcpcb(slirp->tcb.so_next)); + } } /* @@ -76,31 +65,45 @@ tcp_init() * in a skeletal tcp/ip header, minimizing the amount of work * necessary when the connection is used. */ -/* struct tcpiphdr * */ -void -tcp_template(tp) - struct tcpcb *tp; +void tcp_template(struct tcpcb *tp) { - struct SLIRPsocket *so = tp->t_socket; - struct tcpiphdr *n = &tp->t_template; + struct socket *so = tp->t_socket; + register struct tcpiphdr *n = &tp->t_template; - n->ti_next = n->ti_prev = 0; - n->ti_x1 = 0; - n->ti_pr = IPPROTO_TCP; - n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - n->ti_src = so->so_faddr; - n->ti_dst = so->so_laddr; - n->ti_sport = so->so_fport; - n->ti_dport = so->so_lport; - - n->ti_seq = 0; - n->ti_ack = 0; - n->ti_x2 = 0; - n->ti_off = 5; - n->ti_flags = 0; - n->ti_win = 0; - n->ti_sum = 0; - n->ti_urp = 0; + n->ti_mbuf = NULL; + memset(&n->ti, 0, sizeof(n->ti)); + n->ti_x0 = 0; + switch (so->so_ffamily) { + case AF_INET: + n->ti_pr = IPPROTO_TCP; + n->ti_len = htons(sizeof(struct tcphdr)); + n->ti_src = so->so_faddr; + n->ti_dst = so->so_laddr; + n->ti_sport = so->so_fport; + n->ti_dport = so->so_lport; + break; + + case AF_INET6: + n->ti_nh6 = IPPROTO_TCP; + n->ti_len = htons(sizeof(struct tcphdr)); + n->ti_src6 = so->so_faddr6; + n->ti_dst6 = so->so_laddr6; + n->ti_sport = so->so_fport6; + n->ti_dport = so->so_lport6; + break; + + default: + g_assert_not_reached(); + } + + n->ti_seq = 0; + n->ti_ack = 0; + n->ti_x2 = 0; + n->ti_off = 5; + n->ti_flags = 0; + n->ti_win = 0; + n->ti_sum = 0; + n->ti_urp = 0; } /* @@ -110,85 +113,137 @@ tcp_template(tp) * This is used to force keep alive messages out using the TCP * template for a connection tp->t_template. If flags are given * then we send a message back to the TCP which originated the - * segment ti, and discard the SLIRPmbuf containing it and any other - * attached SLIRPmbufs. + * segment ti, and discard the mbuf containing it and any other + * attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. */ -void -tcp_respond(tp, ti, m, ack, seq, flags) - struct tcpcb *tp; - struct tcpiphdr *ti; - struct SLIRPmbuf *m; - tcp_seq ack, seq; - int flags; +void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, + tcp_seq ack, tcp_seq seq, int flags, unsigned short af) { - register int tlen; - int win = 0; + register int tlen; + int win = 0; - DEBUG_CALL("tcp_respond"); - DEBUG_ARG("tp = %lx", (long)tp); - DEBUG_ARG("ti = %lx", (long)ti); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("ack = %u", ack); - DEBUG_ARG("seq = %u", seq); - DEBUG_ARG("flags = %x", flags); - - if (tp) - win = sbspace(&tp->t_socket->so_rcv); - if (m == 0) { - if ((m = m_get()) == NULL) - return; -#ifdef TCP_COMPAT_42 - tlen = 1; -#else - tlen = 0; -#endif - m->m_data += if_maxlinkhdr; - *mtod(m, struct tcpiphdr *) = *ti; - ti = mtod(m, struct tcpiphdr *); - flags = TH_ACK; - } else { - /* - * ti points into m so the next line is just making - * the SLIRPmbuf point to ti - */ - m->m_data = (SLIRPcaddr_t)ti; - - m->m_len = sizeof (struct tcpiphdr); - tlen = 0; -#define xchg(a,b,type) { type t; t=a; a=b; b=t; } - xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); - xchg(ti->ti_dport, ti->ti_sport, u_int16_t); + DEBUG_CALL("tcp_respond"); + DEBUG_ARG("tp = %p", tp); + DEBUG_ARG("ti = %p", ti); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("ack = %u", ack); + DEBUG_ARG("seq = %u", seq); + DEBUG_ARG("flags = %x", flags); + + if (tp) + win = sbspace(&tp->t_socket->so_rcv); + if (m == NULL) { + if (!tp || (m = m_get(tp->t_socket->slirp)) == NULL) + return; + tlen = 0; + m->m_data += IF_MAXLINKHDR; + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + switch (af) { + case AF_INET: + ti->ti.ti_i4.ih_x1 = 0; + break; + case AF_INET6: + ti->ti.ti_i6.ih_x1 = 0; + break; + default: + g_assert_not_reached(); + } + flags = TH_ACK; + } else { + /* + * ti points into m so the next line is just making + * the mbuf point to ti + */ + m->m_data = (char *)ti; + + m->m_len = sizeof(struct tcpiphdr); + tlen = 0; +#define xchg(a, b, type) \ + { \ + type t; \ + t = a; \ + a = b; \ + b = t; \ + } + switch (af) { + case AF_INET: + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t); + xchg(ti->ti_dport, ti->ti_sport, uint16_t); + break; + case AF_INET6: + xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr); + xchg(ti->ti_dport, ti->ti_sport, uint16_t); + break; + default: + g_assert_not_reached(); + } #undef xchg - } - ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); - tlen += sizeof (struct tcpiphdr); - m->m_len = tlen; + } + ti->ti_len = htons((uint16_t)(sizeof(struct tcphdr) + tlen)); + tlen += sizeof(struct tcpiphdr); + m->m_len = tlen; - ti->ti_next = ti->ti_prev = 0; - ti->ti_x1 = 0; - ti->ti_seq = htonl(seq); - ti->ti_ack = htonl(ack); - ti->ti_x2 = 0; - ti->ti_off = sizeof (struct tcphdr) >> 2; - ti->ti_flags = flags; - if (tp) - ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); - else - ti->ti_win = htons((u_int16_t)win); - ti->ti_urp = 0; - ti->ti_sum = 0; - ti->ti_sum = cksum(m, tlen); - ((struct ip *)ti)->ip_len = tlen; + ti->ti_mbuf = NULL; + ti->ti_x0 = 0; + ti->ti_seq = htonl(seq); + ti->ti_ack = htonl(ack); + ti->ti_x2 = 0; + ti->ti_off = sizeof(struct tcphdr) >> 2; + ti->ti_flags = flags; + if (tp) + ti->ti_win = htons((uint16_t)(win >> tp->rcv_scale)); + else + ti->ti_win = htons((uint16_t)win); + ti->ti_urp = 0; + ti->ti_sum = 0; + ti->ti_sum = cksum(m, tlen); - if(flags & TH_RST) - ((struct ip *)ti)->ip_ttl = MAXTTL; - else - ((struct ip *)ti)->ip_ttl = ip_defttl; - - (void) ip_output((struct SLIRPsocket *)0, m); + struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *)); + struct ip *ip; + struct ip6 *ip6; + + switch (af) { + case AF_INET: + m->m_data += + sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip); + m->m_len -= + sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - sizeof(struct ip); + ip = mtod(m, struct ip *); + ip->ip_len = m->m_len; + ip->ip_dst = tcpiph_save.ti_dst; + ip->ip_src = tcpiph_save.ti_src; + ip->ip_p = tcpiph_save.ti_pr; + + if (flags & TH_RST) { + ip->ip_ttl = MAXTTL; + } else { + ip->ip_ttl = IPDEFTTL; + } + + ip_output(NULL, m); + break; + + case AF_INET6: + m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - + sizeof(struct ip6); + m->m_len -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr) - + sizeof(struct ip6); + ip6 = mtod(m, struct ip6 *); + ip6->ip_pl = tcpiph_save.ti_len; + ip6->ip_dst = tcpiph_save.ti_dst6; + ip6->ip_src = tcpiph_save.ti_src6; + ip6->ip_nh = tcpiph_save.ti_nh6; + + ip6_output(NULL, m, 0); + break; + + default: + g_assert_not_reached(); + } } /* @@ -196,43 +251,43 @@ tcp_respond(tp, ti, m, ack, seq, flags) * empty reassembly queue and hooking it to the argument * protocol control block. */ -struct tcpcb * -tcp_newtcpcb(so) - struct SLIRPsocket *so; +struct tcpcb *tcp_newtcpcb(struct socket *so) { - struct tcpcb *tp; - - tp = (struct tcpcb *)malloc(sizeof(*tp)); - if (tp == NULL) - return ((struct tcpcb *)0); - - memset((char *) tp, 0, sizeof(struct tcpcb)); - tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; - tp->t_maxseg = tcp_mssdflt; - - tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; - tp->t_socket = so; - - /* - * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no - * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives - * reasonable initial retransmit time. - */ - tp->t_srtt = TCPTV_SRTTBASE; - tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; - tp->t_rttmin = TCPTV_MIN; + register struct tcpcb *tp; - TCPT_RANGESET(tp->t_rxtcur, - ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, - TCPTV_MIN, TCPTV_REXMTMAX); + tp = g_new0(struct tcpcb, 1); + tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; + /* + * 40: length of IPv4 header (20) + TCP header (20) + * 60: length of IPv6 header (40) + TCP header (20) + */ + tp->t_maxseg = + MIN(so->slirp->if_mtu - ((so->so_ffamily == AF_INET) ? 40 : 60), + TCP_MAXSEG_MAX); - tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->t_state = TCPS_CLOSED; - - so->so_tcpcb = tp; + tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE | TF_REQ_TSTMP) : 0; + tp->t_socket = so; - return (tp); + /* + * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no + * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives + * reasonable initial retransmit time. + */ + tp->t_srtt = TCPTV_SRTTBASE; + tp->t_rttvar = TCPTV_SRTTDFLT << 2; + tp->t_rttmin = TCPTV_MIN; + + TCPT_RANGESET(tp->t_rxtcur, + ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, + TCPTV_MIN, TCPTV_REXMTMAX); + + tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->t_state = TCPS_CLOSED; + + so->so_tcpcb = tp; + + return (tp); } /* @@ -240,29 +295,17 @@ tcp_newtcpcb(so) * the specified error. If connection is synchronized, * then send a RST to peer. */ -struct tcpcb *tcp_drop(struct tcpcb *tp, int err) +struct tcpcb *tcp_drop(struct tcpcb *tp, int err) { -/* tcp_drop(tp, errno) - struct tcpcb *tp; - int errno; -{ -*/ + DEBUG_CALL("tcp_drop"); + DEBUG_ARG("tp = %p", tp); + DEBUG_ARG("errno = %d", errno); - DEBUG_CALL("tcp_drop"); - DEBUG_ARG("tp = %lx", (long)tp); - DEBUG_ARG("errno = %d", errno); - - if (TCPS_HAVERCVDSYN(tp->t_state)) { - tp->t_state = TCPS_CLOSED; - (void) tcp_output(tp); - tcpstat.tcps_drops++; - } else - tcpstat.tcps_conndrops++; -/* if (errno == ETIMEDOUT && tp->t_softerror) - * errno = tp->t_softerror; - */ -/* so->so_error = errno; */ - return (tcp_close(tp)); + if (TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_state = TCPS_CLOSED; + (void)tcp_output(tp); + } + return (tcp_close(tp)); } /* @@ -271,70 +314,37 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err) * discard internet protocol block * wake up any sleepers */ -struct tcpcb * -tcp_close(tp) - struct tcpcb *tp; +struct tcpcb *tcp_close(struct tcpcb *tp) { - struct tcpiphdr *t; - struct SLIRPsocket *so = tp->t_socket; - struct SLIRPmbuf *m; + register struct tcpiphdr *t; + struct socket *so = tp->t_socket; + Slirp *slirp = so->slirp; + register struct mbuf *m; - DEBUG_CALL("tcp_close"); - DEBUG_ARG("tp = %lx", (long )tp); - - /* free the reassembly queue, if any */ - t = (struct tcpiphdr *) tp->seg_next; - while (t != (struct tcpiphdr *)tp) { - t = (struct tcpiphdr *)t->ti_next; - m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); - remque_32((struct tcpiphdr *) t->ti_prev); - m_freem(m); - } - /* It's static */ -/* if (tp->t_template) - * (void) m_free(dtom(tp->t_template)); - */ -/* free(tp, M_PCB); */ - free(tp); - so->so_tcpcb = 0; - soisfdisconnected(so); - /* clobber input socket cache if we're closing the cached connection */ - if (so == tcp_last_so) - tcp_last_so = &tcb; - closesocket(so->s); - sbfree(&so->so_rcv); - sbfree(&so->so_snd); - sofree(so); - tcpstat.tcps_closed++; - return ((struct tcpcb *)0); + DEBUG_CALL("tcp_close"); + DEBUG_ARG("tp = %p", tp); + + /* free the reassembly queue, if any */ + t = tcpfrag_list_first(tp); + while (!tcpfrag_list_end(t, tp)) { + t = tcpiphdr_next(t); + m = tcpiphdr_prev(t)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(t))); + m_free(m); + } + g_free(tp); + so->so_tcpcb = NULL; + /* clobber input socket cache if we're closing the cached connection */ + if (so == slirp->tcp_last_so) + slirp->tcp_last_so = &slirp->tcb; + so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); + closesocket(so->s); + sbfree(&so->so_rcv); + sbfree(&so->so_snd); + sofree(so); + return ((struct tcpcb *)0); } -void -tcp_drain() -{ - /* XXX */ -} - -/* - * When a source quench is received, close congestion window - * to one segment. We will gradually open it again as we proceed. - */ - -#ifdef notdef - -void -tcp_quench(i, errno) - - int errno; -{ - struct tcpcb *tp = intotcpcb(inp); - - if (tp) - tp->snd_cwnd = tp->t_maxseg; -} - -#endif /* notdef */ - /* * TCP protocol interface to socket abstraction. */ @@ -349,898 +359,585 @@ tcp_quench(i, errno) * for peer to send FIN or not respond to keep-alives, etc. * We can let the user exit from the close as soon as the FIN is acked. */ -void -tcp_sockclosed(tp) - struct tcpcb *tp; +void tcp_sockclosed(struct tcpcb *tp) { + DEBUG_CALL("tcp_sockclosed"); + DEBUG_ARG("tp = %p", tp); - DEBUG_CALL("tcp_sockclosed"); - DEBUG_ARG("tp = %lx", (long)tp); - - switch (tp->t_state) { + if (!tp) { + return; + } - case TCPS_CLOSED: - case TCPS_LISTEN: - case TCPS_SYN_SENT: - tp->t_state = TCPS_CLOSED; - tp = tcp_close(tp); - break; + switch (tp->t_state) { + case TCPS_CLOSED: + case TCPS_LISTEN: + case TCPS_SYN_SENT: + tp->t_state = TCPS_CLOSED; + tcp_close(tp); + return; - case TCPS_SYN_RECEIVED: - case TCPS_ESTABLISHED: - tp->t_state = TCPS_FIN_WAIT_1; - break; + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + tp->t_state = TCPS_FIN_WAIT_1; + break; - case TCPS_CLOSE_WAIT: - tp->t_state = TCPS_LAST_ACK; - break; - } -/* soisfdisconnecting(tp->t_socket); */ - if (tp && tp->t_state >= TCPS_FIN_WAIT_2) - soisfdisconnected(tp->t_socket); - if (tp) - tcp_output(tp); + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + break; + } + tcp_output(tp); } -/* +/* * Connect to a host on the Internet * Called by tcp_input * Only do a connect, the tcp fields will be set in tcp_input * return 0 if there's a result of the connect, * else return -1 means we're still connecting * The return value is almost always -1 since the socket is - * nonblocking. Connect returns after the SYN is sent, and does + * nonblocking. Connect returns after the SYN is sent, and does * not wait for ACK+SYN. */ -int tcp_fconnect(so) - struct SLIRPsocket *so; +int tcp_fconnect(struct socket *so, unsigned short af) { - int ret=0; - - DEBUG_CALL("tcp_fconnect"); - DEBUG_ARG("so = %lx", (long )so); + int ret = 0; - if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { - int opt, s=so->s; - struct sockaddr_in addr; - memset(&addr, 0, sizeof(struct sockaddr_in)); + DEBUG_CALL("tcp_fconnect"); + DEBUG_ARG("so = %p", so); - fd_nonblock(s); - opt = 1; - setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); - opt = 1; - setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); - - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { - /* It's an alias */ - switch(ntohl(so->so_faddr.s_addr) & 0xff) { - case CTL_DNS: - addr.sin_addr = dns_addr; - break; - case CTL_ALIAS: - default: - addr.sin_addr = loopback_addr; - break; - } - } else - addr.sin_addr = so->so_faddr; - addr.sin_port = so->so_fport; - - DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " - "addr.sin_addr.s_addr=%.16s\n", - ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); - /* We don't care what port we get */ - ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); - - /* - * If it's not in progress, it failed, so we just return 0, - * without clearing SS_NOFDREF - */ - soisfconnecting(so); - } + ret = so->s = slirp_socket(af, SOCK_STREAM, 0); + if (ret >= 0) { + ret = slirp_bind_outbound(so, af); + if (ret < 0) { + // bind failed - close socket + closesocket(so->s); + so->s = -1; + return (ret); + } + } - return(ret); + if (ret >= 0) { + int opt, s = so->s; + struct sockaddr_storage addr; + + slirp_set_nonblock(s); + so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); + slirp_socket_set_fast_reuse(s); + opt = 1; + setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); + opt = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + + addr = so->fhost.ss; + DEBUG_CALL(" connect()ing"); + if (sotranslate_out(so, &addr) < 0) { + return -1; + } + + /* We don't care what port we get */ + ret = connect(s, (struct sockaddr *)&addr, sockaddr_size(&addr)); + + /* + * If it's not in progress, it failed, so we just return 0, + * without clearing SS_NOFDREF + */ + soisfconnecting(so); + } + + return (ret); } /* * Accept the socket and connect to the local-host - * + * * We have a problem. The correct thing to do would be * to first connect to the local-host, and only if the * connection is accepted, then do an accept() here. - * But, a) we need to know who's trying to connect + * But, a) we need to know who's trying to connect * to the socket to be able to SYN the local-host, and * b) we are already connected to the foreign host by * the time it gets to accept(), so... We simply accept * here and SYN the local-host. - */ -void -tcp_connect(inso) - struct SLIRPsocket *inso; -{ - struct SLIRPsocket *so; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - struct tcpcb *tp; - int s, opt; - - DEBUG_CALL("tcp_connect"); - DEBUG_ARG("inso = %lx", (long)inso); - - /* - * If it's an SS_ACCEPTONCE socket, no need to socreate() - * another socket, just use the accept() socket. - */ - if (inso->so_state & SS_FACCEPTONCE) { - /* FACCEPTONCE already have a tcpcb */ - so = inso; - } else { - if ((so = socreate()) == NULL) { - /* If it failed, get rid of the pending connection */ - closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); - return; - } - if (tcp_attach(so) < 0) { - free(so); /* NOT sofree */ - return; - } - so->so_laddr = inso->so_laddr; - so->so_lport = inso->so_lport; - } - - (void) tcp_mss(sototcpcb(so), 0); - - if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { - tcp_close(sototcpcb(so)); /* This will sofree() as well */ - return; - } - fd_nonblock(s); - opt = 1; - setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); - opt = 1; - setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); - opt = 1; - setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); - - so->so_fport = addr.sin_port; - so->so_faddr = addr.sin_addr; - /* Translate connections from localhost to the real hostname */ - if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) - so->so_faddr = alias_addr; - - /* Close the accept() socket, set right state */ - if (inso->so_state & SS_FACCEPTONCE) { - closesocket(so->s); /* If we only accept once, close the accept() socket */ - so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ - /* if it's not FACCEPTONCE, it's already NOFDREF */ - } - so->s = s; - - so->so_iptos = tcp_tos(so); - tp = sototcpcb(so); - - tcp_template(tp); - - /* Compute window scaling to request. */ -/* while (tp->request_r_scale < TCP_MAX_WINSHIFT && - * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) - * tp->request_r_scale++; */ +void tcp_connect(struct socket *inso) +{ + Slirp *slirp = inso->slirp; + struct socket *so; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(struct sockaddr_storage); + struct tcpcb *tp; + int s, opt; -/* soisconnecting(so); */ /* NOFDREF used instead */ - tcpstat.tcps_connattempt++; - - tp->t_state = TCPS_SYN_SENT; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR/2; - tcp_sendseqinit(tp); - tcp_output(tp); + DEBUG_CALL("tcp_connect"); + DEBUG_ARG("inso = %p", inso); + + /* + * If it's an SS_ACCEPTONCE socket, no need to socreate() + * another socket, just use the accept() socket. + */ + if (inso->so_state & SS_FACCEPTONCE) { + /* FACCEPTONCE already have a tcpcb */ + so = inso; + } else { + so = socreate(slirp); + tcp_attach(so); + so->lhost = inso->lhost; + so->so_ffamily = inso->so_ffamily; + } + + tcp_mss(sototcpcb(so), 0); + + s = accept(inso->s, (struct sockaddr *)&addr, &addrlen); + if (s < 0) { + tcp_close(sototcpcb(so)); /* This will sofree() as well */ + return; + } + slirp_set_nonblock(s); + so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); + slirp_socket_set_fast_reuse(s); + opt = 1; + setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); + slirp_socket_set_nodelay(s); + + so->fhost.ss = addr; + sotranslate_accept(so); + + /* Close the accept() socket, set right state */ + if (inso->so_state & SS_FACCEPTONCE) { + /* If we only accept once, close the accept() socket */ + so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); + closesocket(so->s); + + /* Don't select it yet, even though we have an FD */ + /* if it's not FACCEPTONCE, it's already NOFDREF */ + so->so_state = SS_NOFDREF; + } + so->s = s; + so->so_state |= SS_INCOMING; + + so->so_iptos = tcp_tos(so); + tp = sototcpcb(so); + + tcp_template(tp); + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = slirp->tcp_iss; + slirp->tcp_iss += TCP_ISSINCR / 2; + tcp_sendseqinit(tp); + tcp_output(tp); } /* * Attach a TCPCB to a socket. */ -int -tcp_attach(so) - struct SLIRPsocket *so; +void tcp_attach(struct socket *so) { - if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) - return -1; - - insque(so, &tcb); - - return 0; + so->so_tcpcb = tcp_newtcpcb(so); + insque(so, &so->slirp->tcb); } /* * Set the socket's type of service field */ -struct tos_t tcptos[] = { - {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ - {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ - {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ - {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ - {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ - {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ - {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ - {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ - {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ - {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ - {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ - {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ - {0, 0, 0, 0} +static const struct tos_t tcptos[] = { + { 0, 20, IPTOS_THROUGHPUT, 0 }, /* ftp data */ + { 21, 21, IPTOS_LOWDELAY, EMU_FTP }, /* ftp control */ + { 0, 23, IPTOS_LOWDELAY, 0 }, /* telnet */ + { 0, 80, IPTOS_THROUGHPUT, 0 }, /* WWW */ + { 0, 513, IPTOS_LOWDELAY, EMU_RLOGIN | EMU_NOCONNECT }, /* rlogin */ + { 0, 544, IPTOS_LOWDELAY, EMU_KSH }, /* kshell */ + { 0, 543, IPTOS_LOWDELAY, 0 }, /* klogin */ + { 0, 6667, IPTOS_THROUGHPUT, EMU_IRC }, /* IRC */ + { 0, 6668, IPTOS_THROUGHPUT, EMU_IRC }, /* IRC undernet */ + { 0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ + { 0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ + { 0, 0, 0, 0 } }; -struct emu_t *tcpemu = 0; - /* * Return TOS according to the above table */ -u_int8_t -tcp_tos(so) - struct SLIRPsocket *so; +uint8_t tcp_tos(struct socket *so) { - int i = 0; - struct emu_t *emup; - - while(tcptos[i].tos) { - if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || - (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { - so->so_emu = tcptos[i].emu; - return tcptos[i].tos; - } - i++; - } - - /* Nope, lets see if there's a user-added one */ - for (emup = tcpemu; emup; emup = emup->next) { - if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || - (emup->lport && (ntohs(so->so_lport) == emup->lport))) { - so->so_emu = emup->emu; - return emup->tos; - } - } - - return 0; -} + int i = 0; -int do_echo = -1; + while (tcptos[i].tos) { + if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || + (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { + if (so->slirp->enable_emu) + so->so_emu = tcptos[i].emu; + return tcptos[i].tos; + } + i++; + } + return 0; +} /* * Emulate programs that try and connect to us * This includes ftp (the data connection is * initiated by the server) and IRC (DCC CHAT and * DCC SEND) for now - * + * * NOTE: It's possible to crash SLiRP by sending it * unstandard strings to emulate... if this is a problem, * more checks are needed here * * XXX Assumes the whole command came in one packet - * + * XXX If there is more than one command in the packet, the others may + * be truncated. + * XXX If the command is too long, it may be truncated. + * * XXX Some ftp clients will have their TOS set to * LOWDELAY and so Nagel will kick in. Because of this, * we'll get the first letter, followed by the rest, so * we simply scan for ORT instead of PORT... * DCC doesn't have this problem because there's other stuff * in the packet before the DCC command. - * - * Return 1 if the SLIRPmbuf m is still valid and should be + * + * Return 1 if the mbuf m is still valid and should be * sbappend()ed - * - * NOTE: if you return 0 you MUST m_free() the SLIRPmbuf! + * + * NOTE: if you return 0 you MUST m_free() the mbuf! */ -int -tcp_emu(so, m) - struct SLIRPsocket *so; - struct SLIRPmbuf *m; +int tcp_emu(struct socket *so, struct mbuf *m) { - u_int n1, n2, n3, n4, n5, n6; - char buff[256]; - u_int32_t laddr; - u_int lport; - char *bptr; - - DEBUG_CALL("tcp_emu"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - - switch(so->so_emu) { - int x, i; - - case EMU_IDENT: - /* - * Identification protocol as per rfc-1413 - */ - - { - struct SLIRPsocket *tmpso; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - struct sbuf *so_rcv = &so->so_rcv; - - memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); - so_rcv->sb_wptr += m->m_len; - so_rcv->sb_rptr += m->m_len; - m->m_data[m->m_len] = 0; /* NULL terminate */ - if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { - if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { - HTONS(n1); - HTONS(n2); - /* n2 is the one on our host */ - for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { - if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && - tmpso->so_lport == n2 && - tmpso->so_faddr.s_addr == so->so_faddr.s_addr && - tmpso->so_fport == n1) { - if (getsockname(tmpso->s, - (struct sockaddr *)&addr, &addrlen) == 0) - n2 = ntohs(addr.sin_port); - break; - } - } - } - so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); - so_rcv->sb_rptr = so_rcv->sb_data; - so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; - } - m_free(m); - return 0; - } - -#if 0 - case EMU_RLOGIN: - /* - * Rlogin emulation - * First we accumulate all the initial option negotiation, - * then fork_exec() rlogin according to the options - */ - { - int i, i2, n; - char *ptr; - char args[100]; - char term[100]; - struct sbuf *so_snd = &so->so_snd; - struct sbuf *so_rcv = &so->so_rcv; - - /* First check if they have a priveladged port, or too much data has arrived */ - if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || - (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { - memcpy(so_snd->sb_wptr, "Permission denied\n", 18); - so_snd->sb_wptr += 18; - so_snd->sb_cc += 18; - tcp_sockclosed(sototcpcb(so)); - m_free(m); - return 0; - } - - /* Append the current data */ - memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); - so_rcv->sb_wptr += m->m_len; - so_rcv->sb_rptr += m->m_len; - m_free(m); - - /* - * Check if we have all the initial options, - * and build argument list to rlogin while we're here - */ - n = 0; - ptr = so_rcv->sb_data; - args[0] = 0; - term[0] = 0; - while (ptr < so_rcv->sb_wptr) { - if (*ptr++ == 0) { - n++; - if (n == 2) { - sprintf(args, "rlogin -l %s %s", - ptr, inet_ntoa(so->so_faddr)); - } else if (n == 3) { - i2 = so_rcv->sb_wptr - ptr; - for (i = 0; i < i2; i++) { - if (ptr[i] == '/') { - ptr[i] = 0; -#ifdef HAVE_SETENV - sprintf(term, "%s", ptr); -#else - sprintf(term, "TERM=%s", ptr); -#endif - ptr[i] = '/'; - break; - } - } - } - } - } - - if (n != 4) - return 0; - - /* We have it, set our term variable and fork_exec() */ -#ifdef HAVE_SETENV - setenv("TERM", term, 1); -#else - putenv(term); -#endif - fork_exec(so, args, 2); - term[0] = 0; - so->so_emu = 0; - - /* And finally, send the client a 0 character */ - so_snd->sb_wptr[0] = 0; - so_snd->sb_wptr++; - so_snd->sb_cc++; - - return 0; - } - - case EMU_RSH: - /* - * rsh emulation - * First we accumulate all the initial option negotiation, - * then rsh_exec() rsh according to the options - */ - { - int n; - char *ptr; - char *user; - char *args; - struct sbuf *so_snd = &so->so_snd; - struct sbuf *so_rcv = &so->so_rcv; - - /* First check if they have a priveladged port, or too much data has arrived */ - if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || - (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { - memcpy(so_snd->sb_wptr, "Permission denied\n", 18); - so_snd->sb_wptr += 18; - so_snd->sb_cc += 18; - tcp_sockclosed(sototcpcb(so)); - m_free(m); - return 0; - } - - /* Append the current data */ - memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); - so_rcv->sb_wptr += m->m_len; - so_rcv->sb_rptr += m->m_len; - m_free(m); - - /* - * Check if we have all the initial options, - * and build argument list to rlogin while we're here - */ - n = 0; - ptr = so_rcv->sb_data; - user=""; - args=""; - if (so->extra==NULL) { - struct SLIRPsocket *ns; - struct tcpcb* tp; - int port=atoi(ptr); - if (port <= 0) return 0; - if (port > 1023 || port < 512) { - memcpy(so_snd->sb_wptr, "Permission denied\n", 18); - so_snd->sb_wptr += 18; - so_snd->sb_cc += 18; - tcp_sockclosed(sototcpcb(so)); - return 0; + Slirp *slirp = so->slirp; + unsigned n1, n2, n3, n4, n5, n6; + char buff[257]; + uint32_t laddr; + unsigned lport; + char *bptr; + + DEBUG_CALL("tcp_emu"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m = %p", m); + + switch (so->so_emu) { + int x, i; + + /* TODO: IPv6 */ + case EMU_IDENT: + /* + * Identification protocol as per rfc-1413 + */ + + { + struct socket *tmpso; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + char *eol = g_strstr_len(m->m_data, m->m_len, "\r\n"); + + if (!eol) { + return 1; + } + + *eol = '\0'; + if (sscanf(m->m_data, "%u%*[ ,]%u", &n1, &n2) == 2) { + HTONS(n1); + HTONS(n2); + /* n2 is the one on our host */ + for (tmpso = slirp->tcb.so_next; tmpso != &slirp->tcb; + tmpso = tmpso->so_next) { + if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && + tmpso->so_lport == n2 && + tmpso->so_faddr.s_addr == so->so_faddr.s_addr && + tmpso->so_fport == n1) { + if (getsockname(tmpso->s, (struct sockaddr *)&addr, + &addrlen) == 0) + n2 = addr.sin_port; + break; + } } - if ((ns=socreate()) == NULL) - return 0; - if (tcp_attach(ns)<0) { - free(ns); - return 0; - } + NTOHS(n1); + NTOHS(n2); + m_inc(m, g_snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1); + m->m_len = slirp_fmt(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); + } else { + *eol = '\r'; + } - ns->so_laddr=so->so_laddr; - ns->so_lport=htons(port); + return 1; + } - (void) tcp_mss(sototcpcb(ns), 0); + case EMU_FTP: /* ftp */ + m_inc(m, m->m_len + 1); + *(m->m_data + m->m_len) = 0; /* NUL terminate for strstr */ + if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { + /* + * Need to emulate the PORT command + */ + x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]", &n1, &n2, + &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; - ns->so_faddr=so->so_faddr; - ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); - if (ns->so_faddr.s_addr == 0 || - ns->so_faddr.s_addr == loopback_addr.s_addr) - ns->so_faddr = alias_addr; + if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr, lport, + SS_FACCEPTONCE)) == NULL) { + return 1; + } + n6 = ntohs(so->so_fport); - ns->so_iptos = tcp_tos(ns); - tp = sototcpcb(ns); - - tcp_template(tp); - - /* Compute window scaling to request. */ - /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && - * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) - * tp->request_r_scale++; - */ + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; - /*soisfconnecting(ns);*/ + laddr = ntohl(so->so_faddr.s_addr); - tcpstat.tcps_connattempt++; - - tp->t_state = TCPS_SYN_SENT; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR/2; - tcp_sendseqinit(tp); - tcp_output(tp); - so->extra=ns; - } - while (ptr < so_rcv->sb_wptr) { - if (*ptr++ == 0) { - n++; - if (n == 2) { - user=ptr; - } else if (n == 3) { - args=ptr; + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "ORT %d,%d,%d,%d,%d,%d\r\n%s", + n1, n2, n3, n4, n5, n6, x == 7 ? buff : ""); + return 1; + } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { + /* + * Need to emulate the PASV response + */ + x = sscanf( + bptr, + "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr, lport, + SS_FACCEPTONCE)) == NULL) { + return 1; + } + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x == 7 ? buff : ""); + return 1; + } + + return 1; + + case EMU_KSH: + /* + * The kshell (Kerberos rsh) and shell services both pass + * a local port port number to carry signals to the server + * and stderr to the client. It is passed at the beginning + * of the connection as a NUL-terminated decimal ASCII string. + */ + so->so_emu = 0; + for (lport = 0, i = 0; i < m->m_len - 1; ++i) { + if (m->m_data[i] < '0' || m->m_data[i] > '9') + return 1; /* invalid number */ + lport *= 10; + lport += m->m_data[i] - '0'; + } + if (m->m_data[m->m_len - 1] == '\0' && lport != 0 && + (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr, + htons(lport), SS_FACCEPTONCE)) != NULL) + m->m_len = slirp_fmt0(m->m_data, M_ROOM(m), + "%d", ntohs(so->so_fport)); + return 1; + + case EMU_IRC: + /* + * Need to emulate DCC CHAT, DCC SEND and DCC MOVE + */ + m_inc(m, m->m_len + 1); + *(m->m_data + m->m_len) = 0; /* NULL terminate the string for strstr */ + if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) + return 1; + + /* The %256s is for the broken mIRC */ + if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { + if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr), + htons(lport), SS_FACCEPTONCE)) == NULL) { + return 1; + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); + } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, + &n1) == 4) { + if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr), + htons(lport), SS_FACCEPTONCE)) == NULL) { + return 1; + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "DCC SEND %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, + &n1) == 4) { + if ((so = tcp_listen(slirp, INADDR_ANY, 0, htonl(laddr), + htons(lport), SS_FACCEPTONCE)) == NULL) { + return 1; + } + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += slirp_fmt(bptr, M_FREEROOM(m), + "DCC MOVE %s %lu %u %u%c\n", buff, + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } + return 1; + + case EMU_REALAUDIO: + /* + * RealAudio emulation - JP. We must try to parse the incoming + * data and try to find the two characters that contain the + * port number. Then we redirect an udp port and replace the + * number with the real port we got. + * + * The 1.0 beta versions of the player are not supported + * any more. + * + * A typical packet for player version 1.0 (release version): + * + * 0000:50 4E 41 00 05 + * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P + * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH + * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v + * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB + * + * Now the port number 0x1BD7 is found at offset 0x04 of the + * Now the port number 0x1BD7 is found at offset 0x04 of the + * second packet. This time we received five bytes first and + * then the rest. You never know how many bytes you get. + * + * A typical packet for player version 2.0 (beta): + * + * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............. + * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0 + * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ + * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas + * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B + * + * Port number 0x1BC1 is found at offset 0x0d. + * + * This is just a horrible switch statement. Variable ra tells + * us where we're going. + */ + + bptr = m->m_data; + while (bptr < m->m_data + m->m_len) { + uint16_t p; + static int ra = 0; + char ra_tbl[4]; + + ra_tbl[0] = 0x50; + ra_tbl[1] = 0x4e; + ra_tbl[2] = 0x41; + ra_tbl[3] = 0; + + switch (ra) { + case 0: + case 2: + case 3: + if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; } - } - } - - if (n != 4) - return 0; - - rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); - so->so_emu = 0; - so->extra=NULL; - - /* And finally, send the client a 0 character */ - so_snd->sb_wptr[0] = 0; - so_snd->sb_wptr++; - so_snd->sb_cc++; - - return 0; - } + break; - case EMU_CTL: - { - int num; - struct sbuf *so_snd = &so->so_snd; - struct sbuf *so_rcv = &so->so_rcv; - - /* - * If there is binary data here, we save it in so->so_m - */ - if (!so->so_m) { - int rxlen; - char *rxdata; - rxdata=mtod(m, char *); - for (rxlen=m->m_len; rxlen; rxlen--) { - if (*rxdata++ & 0x80) { - so->so_m = m; - return 0; - } - } - } /* if(so->so_m==NULL) */ - - /* - * Append the line - */ - sbappendsb(so_rcv, m); - - /* To avoid going over the edge of the buffer, we reset it */ - if (so_snd->sb_cc == 0) - so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; - - /* - * A bit of a hack: - * If the first packet we get here is 1 byte long, then it - * was done in telnet character mode, therefore we must echo - * the characters as they come. Otherwise, we echo nothing, - * because in linemode, the line is already echoed - * XXX two or more control connections won't work - */ - if (do_echo == -1) { - if (m->m_len == 1) do_echo = 1; - else do_echo = 0; - } - if (do_echo) { - sbappendsb(so_snd, m); - m_free(m); - tcp_output(sototcpcb(so)); /* XXX */ - } else - m_free(m); - - num = 0; - while (num < so->so_rcv.sb_cc) { - if (*(so->so_rcv.sb_rptr + num) == '\n' || - *(so->so_rcv.sb_rptr + num) == '\r') { - int n; - - *(so_rcv->sb_rptr + num) = 0; - if (ctl_password && !ctl_password_ok) { - /* Need a password */ - if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { - if (strcmp(buff, ctl_password) == 0) { - ctl_password_ok = 1; - n = sprintf(so_snd->sb_wptr, - "Password OK.\r\n"); - goto do_prompt; - } - } - n = sprintf(so_snd->sb_wptr, - "Error: Password required, log on with \"pass PASSWORD\"\r\n"); - goto do_prompt; - } - cfg_quitting = 0; - n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); - if (!cfg_quitting) { - /* Register the printed data */ -do_prompt: - so_snd->sb_cc += n; - so_snd->sb_wptr += n; - /* Add prompt */ - n = sprintf(so_snd->sb_wptr, "Slirp> "); - so_snd->sb_cc += n; - so_snd->sb_wptr += n; - } - /* Drop so_rcv data */ - so_rcv->sb_cc = 0; - so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; - tcp_output(sototcpcb(so)); /* Send the reply */ - } - num++; - } - return 0; - } -#endif - case EMU_FTP: /* ftp */ - *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ - if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { - /* - * Need to emulate the PORT command - */ - x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", - &n1, &n2, &n3, &n4, &n5, &n6, buff); - if (x < 6) - return 1; - - laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); - lport = htons((n5 << 8) | (n6)); - - if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) - return 1; - - n6 = ntohs(so->so_fport); - - n5 = (n6 >> 8) & 0xff; - n6 &= 0xff; - - laddr = ntohl(so->so_faddr.s_addr); - - n1 = ((laddr >> 24) & 0xff); - n2 = ((laddr >> 16) & 0xff); - n3 = ((laddr >> 8) & 0xff); - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - return 1; - } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { - /* - * Need to emulate the PASV response - */ - x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", - &n1, &n2, &n3, &n4, &n5, &n6, buff); - if (x < 6) - return 1; - - laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); - lport = htons((n5 << 8) | (n6)); - - if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) - return 1; - - n6 = ntohs(so->so_fport); - - n5 = (n6 >> 8) & 0xff; - n6 &= 0xff; - - laddr = ntohl(so->so_faddr.s_addr); - - n1 = ((laddr >> 24) & 0xff); - n2 = ((laddr >> 16) & 0xff); - n3 = ((laddr >> 8) & 0xff); - n4 = (laddr & 0xff); - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", - n1, n2, n3, n4, n5, n6, x==7?buff:""); - - return 1; - } - - return 1; - - case EMU_KSH: - /* - * The kshell (Kerberos rsh) and shell services both pass - * a local port port number to carry signals to the server - * and stderr to the client. It is passed at the beginning - * of the connection as a NUL-terminated decimal ASCII string. - */ - so->so_emu = 0; - for (lport = 0, i = 0; i < m->m_len-1; ++i) { - if (m->m_data[i] < '0' || m->m_data[i] > '9') - return 1; /* invalid number */ - lport *= 10; - lport += m->m_data[i] - '0'; - } - if (m->m_data[m->m_len-1] == '\0' && lport != 0 && - (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) - m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; - return 1; - - case EMU_IRC: - /* - * Need to emulate DCC CHAT, DCC SEND and DCC MOVE - */ - *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ - if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) - return 1; - - /* The %256s is for the broken mIRC */ - if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { - if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) - return 1; - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", - (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), 1); - } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { - if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) - return 1; - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", - buff, (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); - } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { - if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) - return 1; - - m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", - buff, (unsigned long)ntohl(so->so_faddr.s_addr), - ntohs(so->so_fport), n1, 1); - } - return 1; + case 1: + /* + * We may get 0x50 several times, ignore them + */ + if (*bptr == 0x50) { + ra = 1; + bptr++; + continue; + } else if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; - case EMU_REALAUDIO: - /* - * RealAudio emulation - JP. We must try to parse the incoming - * data and try to find the two characters that contain the - * port number. Then we redirect an udp port and replace the - * number with the real port we got. - * - * The 1.0 beta versions of the player are not supported - * any more. - * - * A typical packet for player version 1.0 (release version): - * - * 0000:50 4E 41 00 05 - * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .......glc..P - * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH - * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v - * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB - * - * Now the port number 0x1BD7 is found at offset 0x04 of the - * Now the port number 0x1BD7 is found at offset 0x04 of the - * second packet. This time we received five bytes first and - * then the rest. You never know how many bytes you get. - * - * A typical packet for player version 2.0 (beta): - * - * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............ - * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxc..Win2.0.0 - * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ - * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas - * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B - * - * Port number 0x1BC1 is found at offset 0x0d. - * - * This is just a horrible switch statement. Variable ra tells - * us where we're going. - */ - - bptr = m->m_data; - while (bptr < m->m_data + m->m_len) { - u_short p; - static int ra = 0; - char ra_tbl[4]; - - ra_tbl[0] = 0x50; - ra_tbl[1] = 0x4e; - ra_tbl[2] = 0x41; - ra_tbl[3] = 0; - - switch (ra) { - case 0: - case 2: - case 3: - if (*bptr++ != ra_tbl[ra]) { - ra = 0; - continue; - } - break; - - case 1: - /* - * We may get 0x50 several times, ignore them - */ - if (*bptr == 0x50) { - ra = 1; - bptr++; - continue; - } else if (*bptr++ != ra_tbl[ra]) { - ra = 0; - continue; - } - break; - - case 4: - /* - * skip version number - */ - bptr++; - break; - - case 5: - /* - * The difference between versions 1.0 and - * 2.0 is here. For future versions of - * the player this may need to be modified. - */ - if (*(bptr + 1) == 0x02) - bptr += 8; - else - bptr += 4; - break; - - case 6: - /* This is the field containing the port - * number that RA-player is listening to. - */ - lport = (((u_char*)bptr)[0] << 8) - + ((u_char *)bptr)[1]; - if (lport < 6970) - lport += 256; /* don't know why */ - if (lport < 6970 || lport > 7170) - return 1; /* failed */ - - /* try to get udp port between 6970 - 7170 */ - for (p = 6970; p < 7071; p++) { - if (udp_listen( htons(p), - so->so_laddr.s_addr, - htons(lport), - SS_FACCEPTONCE)) { - break; - } - } - if (p == 7071) - p = 0; - *(u_char *)bptr++ = (p >> 8) & 0xff; - *(u_char *)bptr++ = p & 0xff; - ra = 0; - return 1; /* port redirected, we're done */ - break; - - default: - ra = 0; - } - ra++; - } - return 1; - - default: - /* Ooops, not emulated, won't call tcp_emu again */ - so->so_emu = 0; - return 1; - } + case 4: + /* + * skip version number + */ + bptr++; + break; + + case 5: + if (bptr == m->m_data + m->m_len - 1) + return 1; /* We need two bytes */ + + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of + * the player this may need to be modified. + */ + if (*(bptr + 1) == 0x02) + bptr += 8; + else + bptr += 4; + break; + + case 6: + /* This is the field containing the port + * number that RA-player is listening to. + */ + + if (bptr == m->m_data + m->m_len - 1) + return 1; /* We need two bytes */ + + lport = (((uint8_t *)bptr)[0] << 8) + ((uint8_t *)bptr)[1]; + if (lport < 6970) + lport += 256; /* don't know why */ + if (lport < 6970 || lport > 7170) + return 1; /* failed */ + + /* try to get udp port between 6970 - 7170 */ + for (p = 6970; p < 7071; p++) { + if (udp_listen(slirp, INADDR_ANY, htons(p), + so->so_laddr.s_addr, htons(lport), + SS_FACCEPTONCE)) { + break; + } + } + if (p == 7071) + p = 0; + *(uint8_t *)bptr++ = (p >> 8) & 0xff; + *(uint8_t *)bptr = p & 0xff; + ra = 0; + return 1; /* port redirected, we're done */ + break; + + default: + ra = 0; + } + ra++; + } + return 1; + + default: + /* Ooops, not emulated, won't call tcp_emu again */ + so->so_emu = 0; + return 1; + } } /* @@ -1248,80 +945,36 @@ do_prompt: * Return 0 if this connections is to be closed, 1 otherwise, * return 2 if this is a command-line connection */ -int -tcp_ctl(so) - struct SLIRPsocket *so; +int tcp_ctl(struct socket *so) { - struct sbuf *sb = &so->so_snd; - int command; - struct ex_list *ex_ptr; - int do_pty; - // struct SLIRPsocket *tmpso; - - DEBUG_CALL("tcp_ctl"); - DEBUG_ARG("so = %lx", (long )so); - -#if 0 - /* - * Check if they're authorised - */ - if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { - sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); - sb->sb_wptr += sb->sb_cc; - return 0; - } -#endif - command = (ntohl(so->so_faddr.s_addr) & 0xff); - - switch(command) { - default: /* Check for exec's */ - - /* - * Check if it's pty_exec - */ - for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if (ex_ptr->ex_fport == so->so_fport && - command == ex_ptr->ex_addr) { - do_pty = ex_ptr->ex_pty; - goto do_exec; - } - } - - /* - * Nothing bound.. - */ - /* tcp_fconnect(so); */ - - /* FALLTHROUGH */ - case CTL_ALIAS: - sb->sb_cc = sprintf(sb->sb_wptr, - "Error: No application configured.\r\n"); - sb->sb_wptr += sb->sb_cc; - return(0); + Slirp *slirp = so->slirp; + struct sbuf *sb = &so->so_snd; + struct gfwd_list *ex_ptr; - do_exec: - DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); - return(fork_exec(so, ex_ptr->ex_exec, do_pty)); - -#if 0 - case CTL_CMD: - for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { - if (tmpso->so_emu == EMU_CTL && - !(tmpso->so_tcpcb? - (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) - :0)) { - /* Ooops, control connection already active */ - sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); - sb->sb_wptr += sb->sb_cc; - return 0; - } - } - so->so_emu = EMU_CTL; - ctl_password_ok = 0; - sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); - sb->sb_wptr += sb->sb_cc; - do_echo=-1; - return(2); -#endif - } + DEBUG_CALL("tcp_ctl"); + DEBUG_ARG("so = %p", so); + + /* TODO: IPv6 */ + if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { + /* Check if it's pty_exec */ + for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_fport == so->so_fport && + so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) { + if (ex_ptr->write_cb) { + so->s = -1; + so->guestfwd = ex_ptr; + return 1; + } + DEBUG_MISC(" executing %s", ex_ptr->ex_exec); + if (ex_ptr->ex_unix) + return open_unix(so, ex_ptr->ex_unix); + else + return fork_exec(so, ex_ptr->ex_exec); + } + } + } + sb->sb_cc = slirp_fmt(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data), + "Error: No application configured.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; } diff --git a/src/network/slirp/tcp_timer.c b/src/network/slirp/tcp_timer.c index 892b222c7..102023e7c 100644 --- a/src/network/slirp/tcp_timer.c +++ b/src/network/slirp/tcp_timer.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -32,35 +33,27 @@ #include "slirp.h" -int tcp_keepidle = TCPTV_KEEP_IDLE; -int tcp_keepintvl = TCPTV_KEEPINTVL; -int tcp_maxidle; -int so_options = DO_KEEPALIVE; - -struct tcpstat tcpstat; /* tcp statistics */ -u_int32_t tcp_now; /* for RFC 1323 timestamps */ +static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer); /* * Fast timeout routine for processing delayed acks */ -void -tcp_fasttimo() +void tcp_fasttimo(Slirp *slirp) { - register struct SLIRPsocket *so; - register struct tcpcb *tp; + register struct socket *so; + register struct tcpcb *tp; - DEBUG_CALL("tcp_fasttimo"); - - so = tcb.so_next; - if (so) - for (; so != &tcb; so = so->so_next) - if ((tp = (struct tcpcb *)so->so_tcpcb) && - (tp->t_flags & TF_DELACK)) { - tp->t_flags &= ~TF_DELACK; - tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_delack++; - (void) tcp_output(tp); - } + DEBUG_CALL("tcp_fasttimo"); + + so = slirp->tcb.so_next; + if (so) + for (; so != &slirp->tcb; so = so->so_next) + if ((tp = (struct tcpcb *)so->so_tcpcb) && + (tp->t_flags & TF_DELACK)) { + tp->t_flags &= ~TF_DELACK; + tp->t_flags |= TF_ACKNOW; + (void)tcp_output(tp); + } } /* @@ -68,255 +61,226 @@ tcp_fasttimo() * Updates the timers in all active tcb's and * causes finite state machine actions if timers expire. */ -void -tcp_slowtimo() +void tcp_slowtimo(Slirp *slirp) { - register struct SLIRPsocket *ip, *ipnxt; - register struct tcpcb *tp; - register int i; + register struct socket *ip, *ipnxt; + register struct tcpcb *tp; + register int i; - DEBUG_CALL("tcp_slowtimo"); - - tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; - /* - * Search through tcb's and update active timers. - */ - ip = tcb.so_next; - if (ip == 0) - return; - for (; ip != &tcb; ip = ipnxt) { - ipnxt = ip->so_next; - tp = sototcpcb(ip); - if (tp == 0) - continue; - for (i = 0; i < TCPT_NTIMERS; i++) { - if (tp->t_timer[i] && --tp->t_timer[i] == 0) { - tcp_timers(tp,i); - if (ipnxt->so_prev != ip) - goto tpgone; - } - } - tp->t_idle++; - if (tp->t_rtt) - tp->t_rtt++; -tpgone: - ; - } - tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ -#ifdef TCP_COMPAT_42 - if ((int)tcp_iss < 0) - tcp_iss = 0; /* XXX */ -#endif - tcp_now++; /* for timestamps */ + DEBUG_CALL("tcp_slowtimo"); + + /* + * Search through tcb's and update active timers. + */ + ip = slirp->tcb.so_next; + if (ip == NULL) { + return; + } + for (; ip != &slirp->tcb; ip = ipnxt) { + ipnxt = ip->so_next; + tp = sototcpcb(ip); + if (tp == NULL) { + continue; + } + for (i = 0; i < TCPT_NTIMERS; i++) { + if (tp->t_timer[i] && --tp->t_timer[i] == 0) { + tcp_timers(tp, i); + if (ipnxt->so_prev != ip) + goto tpgone; + } + } + tp->t_idle++; + if (tp->t_rtt) + tp->t_rtt++; + tpgone:; + } + slirp->tcp_iss += TCP_ISSINCR / PR_SLOWHZ; /* increment iss */ + slirp->tcp_now++; /* for timestamps */ } /* * Cancel all timers for TCP tp. */ -void -tcp_canceltimers(tp) - struct tcpcb *tp; +void tcp_canceltimers(struct tcpcb *tp) { - register int i; + register int i; - for (i = 0; i < TCPT_NTIMERS; i++) - tp->t_timer[i] = 0; + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; } -int tcp_backoff[TCP_MAXRXTSHIFT + 1] = - { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; +const int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, + 64, 64, 64, 64, 64, 64 }; /* * TCP timer processing. */ -struct tcpcb * -tcp_timers(tp, timer) - struct tcpcb *tp; - int timer; +static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer) { - int rexmt; - - DEBUG_CALL("tcp_timers"); - - switch (timer) { + register int rexmt; - /* - * 2 MSL timeout in shutdown went off. If we're closed but - * still waiting for peer to close and connection has been idle - * too long, or if 2MSL time is up from TIME_WAIT, delete connection - * control block. Otherwise, check again in a bit. - */ - case TCPT_2MSL: - if (tp->t_state != TCPS_TIME_WAIT && - tp->t_idle <= tcp_maxidle) - tp->t_timer[TCPT_2MSL] = tcp_keepintvl; - else - tp = tcp_close(tp); - break; + DEBUG_CALL("tcp_timers"); - /* - * Retransmission timer went off. Message has not - * been acked within retransmit interval. Back off - * to a longer retransmit interval and retransmit one segment. - */ - case TCPT_REXMT: - - /* - * XXXXX If a packet has timed out, then remove all the queued - * packets for that session. - */ - - if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { - /* - * This is a hack to suit our terminal server here at the uni of canberra - * since they have trouble with zeroes... It usually lets them through - * unharmed, but under some conditions, it'll eat the zeros. If we - * keep retransmitting it, it'll keep eating the zeroes, so we keep - * retransmitting, and eventually the connection dies... - * (this only happens on incoming data) - * - * So, if we were gonna drop the connection from too many retransmits, - * don't... instead halve the t_maxseg, which might break up the NULLs and - * let them through - * - * *sigh* - */ - - tp->t_maxseg >>= 1; - if (tp->t_maxseg < 32) { - /* - * We tried our best, now the connection must die! - */ - tp->t_rxtshift = TCP_MAXRXTSHIFT; - tcpstat.tcps_timeoutdrop++; - tp = tcp_drop(tp, tp->t_softerror); - /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ - return (tp); /* XXX */ - } - - /* - * Set rxtshift to 6, which is still at the maximum - * backoff time - */ - tp->t_rxtshift = 6; - } - tcpstat.tcps_rexmttimeo++; - rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; - TCPT_RANGESET(tp->t_rxtcur, rexmt, - (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - /* - * If losing, let the lower level know and try for - * a better route. Also, if we backed off this far, - * our srtt estimate is probably bogus. Clobber it - * so we'll take the next rtt measurement as our srtt; - * move the current srtt into rttvar to keep the current - * retransmit times until then. - */ - if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { -/* in_losing(tp->t_inpcb); */ - tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); - tp->t_srtt = 0; - } - tp->snd_nxt = tp->snd_una; - /* - * If timing a segment in this window, stop the timer. - */ - tp->t_rtt = 0; - /* - * Close the congestion window down to one segment - * (we'll open it by one segment for each ack we get). - * Since we probably have a window's worth of unacked - * data accumulated, this "slow start" keeps us from - * dumping all that data as back-to-back packets (which - * might overwhelm an intermediate gateway). - * - * There are two phases to the opening: Initially we - * open by one mss on each ack. This makes the window - * size increase exponentially with time. If the - * window is larger than the path can handle, this - * exponential growth results in dropped packet(s) - * almost immediately. To get more time between - * drops but still "push" the network to take advantage - * of improving conditions, we switch from exponential - * to linear window opening at some threshold size. - * For a threshold, we use half the current window - * size, truncated to a multiple of the mss. - * - * (the minimum cwnd that will give us exponential - * growth is 2 mss. We don't allow the threshold - * to go below this.) - */ - { - u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; - if (win < 2) - win = 2; - tp->snd_cwnd = tp->t_maxseg; - tp->snd_ssthresh = win * tp->t_maxseg; - tp->t_dupacks = 0; - } - (void) tcp_output(tp); - break; + switch (timer) { + /* + * 2 MSL timeout in shutdown went off. If we're closed but + * still waiting for peer to close and connection has been idle + * too long, or if 2MSL time is up from TIME_WAIT, delete connection + * control block. Otherwise, check again in a bit. + */ + case TCPT_2MSL: + if (tp->t_state != TCPS_TIME_WAIT && tp->t_idle <= TCP_MAXIDLE) + tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL; + else + tp = tcp_close(tp); + break; - /* - * Persistence timer into zero window. - * Force a byte to be output, if possible. - */ - case TCPT_PERSIST: - tcpstat.tcps_persisttimeo++; - tcp_setpersist(tp); - tp->t_force = 1; - (void) tcp_output(tp); - tp->t_force = 0; - break; + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one segment. + */ + case TCPT_REXMT: - /* - * Keep-alive timer went off; send something - * or drop connection if idle for too long. - */ - case TCPT_KEEP: - tcpstat.tcps_keeptimeo++; - if (tp->t_state < TCPS_ESTABLISHED) - goto dropit; + /* + * XXXXX If a packet has timed out, then remove all the queued + * packets for that session. + */ -/* if (tp->t_socket->so_options & SO_KEEPALIVE && */ - if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { - if (tp->t_idle >= tcp_keepidle + tcp_maxidle) - goto dropit; - /* - * Send a packet designed to force a response - * if the peer is up and reachable: - * either an ACK if the connection is still alive, - * or an RST if the peer has closed the connection - * due to timeout or reboot. - * Using sequence number tp->snd_una-1 - * causes the transmitted zero-length segment - * to lie outside the receive window; - * by the protocol spec, this requires the - * correspondent TCP to respond. - */ - tcpstat.tcps_keepprobe++; -#ifdef TCP_COMPAT_42 - /* - * The keepalive packet must have nonzero length - * to get a 4.2 host to respond. - */ - tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, - tp->rcv_nxt - 1, tp->snd_una - 1, 0); -#else - tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, - tp->rcv_nxt, tp->snd_una - 1, 0); -#endif - tp->t_timer[TCPT_KEEP] = tcp_keepintvl; - } else - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - break; + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { + /* + * This is a hack to suit our terminal server here at the uni of + * canberra since they have trouble with zeroes... It usually lets + * them through unharmed, but under some conditions, it'll eat the + * zeros. If we keep retransmitting it, it'll keep eating the + * zeroes, so we keep retransmitting, and eventually the connection + * dies... (this only happens on incoming data) + * + * So, if we were gonna drop the connection from too many + * retransmits, don't... instead halve the t_maxseg, which might + * break up the NULLs and let them through + * + * *sigh* + */ - dropit: - tcpstat.tcps_keepdrops++; - tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ - break; - } + tp->t_maxseg >>= 1; + if (tp->t_maxseg < 32) { + /* + * We tried our best, now the connection must die! + */ + tp->t_rxtshift = TCP_MAXRXTSHIFT; + tp = tcp_drop(tp, tp->t_softerror); + /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ + return (tp); /* XXX */ + } - return (tp); + /* + * Set rxtshift to 6, which is still at the maximum + * backoff time + */ + tp->t_rxtshift = 6; + } + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + TCPT_RANGESET(tp->t_rxtcur, rexmt, (short)tp->t_rttmin, + TCPTV_REXMTMAX); /* XXX */ + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * If losing, let the lower level know and try for + * a better route. Also, if we backed off this far, + * our srtt estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { + tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); + tp->t_srtt = 0; + } + tp->snd_nxt = tp->snd_una; + /* + * If timing a segment in this window, stop the timer. + */ + tp->t_rtt = 0; + /* + * Close the congestion window down to one segment + * (we'll open it by one segment for each ack we get). + * Since we probably have a window's worth of unacked + * data accumulated, this "slow start" keeps us from + * dumping all that data as back-to-back packets (which + * might overwhelm an intermediate gateway). + * + * There are two phases to the opening: Initially we + * open by one mss on each ack. This makes the window + * size increase exponentially with time. If the + * window is larger than the path can handle, this + * exponential growth results in dropped packet(s) + * almost immediately. To get more time between + * drops but still "push" the network to take advantage + * of improving conditions, we switch from exponential + * to linear window opening at some threshold size. + * For a threshold, we use half the current window + * size, truncated to a multiple of the mss. + * + * (the minimum cwnd that will give us exponential + * growth is 2 mss. We don't allow the threshold + * to go below this.) + */ + { + unsigned win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + if (win < 2) + win = 2; + tp->snd_cwnd = tp->t_maxseg; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_dupacks = 0; + } + (void)tcp_output(tp); + break; + + /* + * Persistence timer into zero window. + * Force a byte to be output, if possible. + */ + case TCPT_PERSIST: + tcp_setpersist(tp); + tp->t_force = 1; + (void)tcp_output(tp); + tp->t_force = 0; + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case TCPT_KEEP: + if (tp->t_state < TCPS_ESTABLISHED) + goto dropit; + + if (slirp_do_keepalive && tp->t_state <= TCPS_CLOSE_WAIT) { + if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE) + goto dropit; + /* + * Send a packet designed to force a response + * if the peer is up and reachable: + * either an ACK if the connection is still alive, + * or an RST if the peer has closed the connection + * due to timeout or reboot. + * Using sequence number tp->snd_una-1 + * causes the transmitted zero-length segment + * to lie outside the receive window; + * by the protocol spec, this requires the + * correspondent TCP to respond. + */ + tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt, + tp->snd_una - 1, 0, tp->t_socket->so_ffamily); + tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL; + } else + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE; + break; + + dropit: + tp = tcp_drop(tp, 0); + break; + } + + return (tp); } diff --git a/src/network/slirp/tcp_timer.h b/src/network/slirp/tcp_timer.h index 0bc438c76..584a5594e 100644 --- a/src/network/slirp/tcp_timer.h +++ b/src/network/slirp/tcp_timer.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -30,19 +31,19 @@ * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp */ -#ifndef _TCP_TIMER_H_ -#define _TCP_TIMER_H_ +#ifndef TCP_TIMER_H +#define TCP_TIMER_H /* * Definitions of the TCP timers. These timers are counted * down PR_SLOWHZ times a second. */ -#define TCPT_NTIMERS 4 +#define TCPT_NTIMERS 4 -#define TCPT_REXMT 0 /* retransmit */ -#define TCPT_PERSIST 1 /* retransmit persistence */ -#define TCPT_KEEP 2 /* keep alive */ -#define TCPT_2MSL 3 /* 2*msl quiet time timer */ +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_PERSIST 1 /* retransmit persistence */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ /* * The TCPT_REXMT timer is used to force retransmissions. @@ -83,56 +84,47 @@ /* * Time constants. */ -#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ +#define TCPTV_MSL (5 * PR_SLOWHZ) /* max seg lifetime (hah!) */ -#define TCPTV_SRTTBASE 0 /* base roundtrip time; - if 0, no idea yet */ -#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ +#define TCPTV_SRTTBASE \ + 0 /* base roundtrip time; \ + if 0, no idea yet */ +#define TCPTV_SRTTDFLT (3 * PR_SLOWHZ) /* assumed RTT if no info */ -#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ -#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ +#define TCPTV_PERSMIN (5 * PR_SLOWHZ) /* retransmit persistence */ +#define TCPTV_PERSMAX (60 * PR_SLOWHZ) /* maximum persist interval */ -#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ -#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ -#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ -#define TCPTV_KEEPCNT 8 /* max probes before drop */ +#define TCPTV_KEEP_INIT (75 * PR_SLOWHZ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120 * 60 * PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL (75 * PR_SLOWHZ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ -#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ -/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ -#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ +#define TCPTV_MIN (1 * PR_SLOWHZ) /* minimum allowable value */ +#define TCPTV_REXMTMAX (12 * PR_SLOWHZ) /* max allowable REXMT value */ -#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ +#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ -#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ -#ifdef TCPTIMERS -char *tcptimers[] = - { "REXMT", "PERSIST", "KEEP", "2MSL" }; -#endif - /* * Force a time value to be in a certain range. */ -#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ - (tv) = (value); \ - if ((tv) < (tvmin)) \ - (tv) = (tvmin); \ - else if ((tv) > (tvmax)) \ - (tv) = (tvmax); \ -} +#define TCPT_RANGESET(tv, value, tvmin, tvmax) \ + { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ + } -extern int tcp_keepidle; /* time before keepalive probes begin */ -extern int tcp_keepintvl; /* time between keepalive probes */ -extern int tcp_maxidle; /* time to drop after starting probes */ -extern int tcp_ttl; /* time to live for TCP segs */ -extern int tcp_backoff[]; +extern const int tcp_backoff[]; struct tcpcb; -void tcp_fasttimo _P((void)); -void tcp_slowtimo _P((void)); -void tcp_canceltimers _P((struct tcpcb *)); -struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); +void tcp_fasttimo(Slirp *); +void tcp_slowtimo(Slirp *); +void tcp_canceltimers(struct tcpcb *); #endif diff --git a/src/network/slirp/tcp_var.h b/src/network/slirp/tcp_var.h index a9606c276..c8da8cbd1 100644 --- a/src/network/slirp/tcp_var.h +++ b/src/network/slirp/tcp_var.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -30,115 +31,103 @@ * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp */ -#ifndef _TCP_VAR_H_ -#define _TCP_VAR_H_ +#ifndef TCP_VAR_H +#define TCP_VAR_H #include "tcpip.h" #include "tcp_timer.h" -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t tcpiphdrp_32; -#else -#if SIZEOF_CHAR_P == 4 - typedef struct tcpiphdr *tcpiphdrp_32; -#else - typedef u_int32_t tcpiphdrp_32; -#endif -#endif - /* * Tcp control block, one per tcp; fields: */ struct tcpcb { - tcpiphdrp_32 seg_next; /* sequencing queue */ - tcpiphdrp_32 seg_prev; - short t_state; /* state of this connection */ - short t_timer[TCPT_NTIMERS]; /* tcp timers */ - short t_rxtshift; /* log(2) of rexmt exp. backoff */ - short t_rxtcur; /* current retransmit value */ - short t_dupacks; /* consecutive dup acks recd */ - u_short t_maxseg; /* maximum segment size */ - char t_force; /* 1 if forcing out a byte */ - u_short t_flags; -#define TF_ACKNOW 0x0001 /* ack peer immediately */ -#define TF_DELACK 0x0002 /* ack, but try to delay it */ -#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ -#define TF_NOOPT 0x0008 /* don't use tcp options */ -#define TF_SENTFIN 0x0010 /* have sent FIN */ -#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ -#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ -#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ -#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ -#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ + struct tcpiphdr *seg_next; /* sequencing queue */ + struct tcpiphdr *seg_prev; + short t_state; /* state of this connection */ + short t_timer[TCPT_NTIMERS]; /* tcp timers */ + short t_rxtshift; /* log(2) of rexmt exp. backoff */ + short t_rxtcur; /* current retransmit value */ + short t_dupacks; /* consecutive dup acks recd */ + uint16_t t_maxseg; /* maximum segment size */ + uint8_t t_force; /* 1 if forcing out a byte */ + uint16_t t_flags; +#define TF_ACKNOW 0x0001 /* ack peer immediately */ +#define TF_DELACK 0x0002 /* ack, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ - /* Make it static for now */ -/* struct tcpiphdr *t_template; / * skeletal packet for transmit */ - struct tcpiphdr t_template; + struct tcpiphdr t_template; /* static skeletal packet for xmit */ - struct SLIRPsocket *t_socket; /* back pointer to socket */ -/* - * The following fields are used as in the protocol specification. - * See RFC783, Dec. 1981, page 21. - */ -/* send sequence variables */ - tcp_seq snd_una; /* send unacknowledged */ - tcp_seq snd_nxt; /* send next */ - tcp_seq snd_up; /* send urgent pointer */ - tcp_seq snd_wl1; /* window update seg seq number */ - tcp_seq snd_wl2; /* window update seg ack number */ - tcp_seq iss; /* initial send sequence number */ - u_int32_t snd_wnd; /* send window */ -/* receive sequence variables */ - u_int32_t rcv_wnd; /* receive window */ - tcp_seq rcv_nxt; /* receive next */ - tcp_seq rcv_up; /* receive urgent pointer */ - tcp_seq irs; /* initial receive sequence number */ -/* - * Additional variables for this implementation. - */ -/* receive variables */ - tcp_seq rcv_adv; /* advertised window */ -/* retransmit variables */ - tcp_seq snd_max; /* highest sequence number sent; - * used to recognize retransmits - */ -/* congestion control (for slow start, source quench, retransmit after loss) */ - u_int32_t snd_cwnd; /* congestion-controlled window */ - u_int32_t snd_ssthresh; /* snd_cwnd size threshold for - * for slow start exponential to - * linear switch - */ -/* - * transmit timing stuff. See below for scale of srtt and rttvar. - * "Variance" is actually smoothed difference. - */ - short t_idle; /* inactivity time */ - short t_rtt; /* round trip time */ - tcp_seq t_rtseq; /* sequence number being timed */ - short t_srtt; /* smoothed round-trip time */ - short t_rttvar; /* variance in round-trip time */ - u_short t_rttmin; /* minimum rtt allowed */ - u_int32_t max_sndwnd; /* largest window peer has offered */ + struct socket *t_socket; /* back pointer to socket */ + /* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ + /* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + uint32_t snd_wnd; /* send window */ + /* receive sequence variables */ + uint32_t rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ + /* + * Additional variables for this implementation. + */ + /* receive variables */ + tcp_seq rcv_adv; /* advertised window */ + /* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ + /* congestion control (for slow start, source quench, retransmit after loss) + */ + uint32_t snd_cwnd; /* congestion-controlled window */ + uint32_t snd_ssthresh; /* snd_cwnd size threshold for + * for slow start exponential to + * linear switch + */ + /* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + short t_idle; /* inactivity time */ + short t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + short t_srtt; /* smoothed round-trip time */ + short t_rttvar; /* variance in round-trip time */ + uint16_t t_rttmin; /* minimum rtt allowed */ + uint32_t max_sndwnd; /* largest window peer has offered */ -/* out-of-band data */ - char t_oobflags; /* have some */ - char t_iobc; /* input character */ -#define TCPOOB_HAVEDATA 0x01 -#define TCPOOB_HADDATA 0x02 - short t_softerror; /* possible error not yet reported */ - -/* RFC 1323 variables */ - u_char snd_scale; /* window scaling for send window */ - u_char rcv_scale; /* window scaling for recv window */ - u_char request_r_scale; /* pending window scaling */ - u_char requested_s_scale; - u_int32_t ts_recent; /* timestamp echo data */ - u_int32_t ts_recent_age; /* when last updated */ - tcp_seq last_ack_sent; + /* out-of-band data */ + uint8_t t_oobflags; /* have some */ + uint8_t t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 + short t_softerror; /* possible error not yet reported */ + /* RFC 1323 variables */ + uint8_t snd_scale; /* window scaling for send window */ + uint8_t rcv_scale; /* window scaling for recv window */ + uint8_t request_r_scale; /* pending window scaling */ + uint8_t requested_s_scale; + uint32_t ts_recent; /* timestamp echo data */ + uint32_t ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; }; -#define sototcpcb(so) ((so)->so_tcpcb) +#define sototcpcb(so) ((so)->so_tcpcb) /* * The smoothed round-trip time and estimated variance @@ -149,10 +138,10 @@ struct tcpcb { * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the * binary point, and is smoothed with an ALPHA of 0.75. */ -#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ -#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ -#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ -#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ +#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ /* * The initial retransmission should happen at rtt + 4 * rttvar. @@ -167,90 +156,6 @@ struct tcpcb { * This macro assumes that the value of TCP_RTTVAR_SCALE * is the same as the multiplier for rttvar. */ -#define TCP_REXMTVAL(tp) \ - (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) - -/* XXX - * We want to avoid doing m_pullup on incoming packets but that - * means avoiding dtom on the tcp reassembly code. That in turn means - * keeping an mbuf pointer in the reassembly queue (since we might - * have a cluster). As a quick hack, the source & destination - * port numbers (which are no longer needed once we've located the - * tcpcb) are overlayed with an mbuf pointer. - */ -#if defined(__amd64__) || defined(__aarch64__) -typedef uintptr_t mbufp_32; -#else -#if SIZEOF_CHAR_P == 4 -typedef struct SLIRPmbuf *mbufp_32; -#else -typedef u_int32_t mbufp_32; -#endif -#endif -#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) - -/* - * TCP statistics. - * Many of these should be kept per connection, - * but that's inconvenient at the moment. - */ -struct tcpstat { - u_long tcps_connattempt; /* connections initiated */ - u_long tcps_accepts; /* connections accepted */ - u_long tcps_connects; /* connections established */ - u_long tcps_drops; /* connections dropped */ - u_long tcps_conndrops; /* embryonic connections dropped */ - u_long tcps_closed; /* conn. closed (includes drops) */ - u_long tcps_segstimed; /* segs where we tried to get rtt */ - u_long tcps_rttupdated; /* times we succeeded */ - u_long tcps_delack; /* delayed acks sent */ - u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ - u_long tcps_rexmttimeo; /* retransmit timeouts */ - u_long tcps_persisttimeo; /* persist timeouts */ - u_long tcps_keeptimeo; /* keepalive timeouts */ - u_long tcps_keepprobe; /* keepalive probes sent */ - u_long tcps_keepdrops; /* connections dropped in keepalive */ - - u_long tcps_sndtotal; /* total packets sent */ - u_long tcps_sndpack; /* data packets sent */ - u_long tcps_sndbyte; /* data bytes sent */ - u_long tcps_sndrexmitpack; /* data packets retransmitted */ - u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ - u_long tcps_sndacks; /* ack-only packets sent */ - u_long tcps_sndprobe; /* window probes sent */ - u_long tcps_sndurg; /* packets sent with URG only */ - u_long tcps_sndwinup; /* window update-only packets sent */ - u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ - - u_long tcps_rcvtotal; /* total packets received */ - u_long tcps_rcvpack; /* packets received in sequence */ - u_long tcps_rcvbyte; /* bytes received in sequence */ - u_long tcps_rcvbadsum; /* packets received with ccksum errs */ - u_long tcps_rcvbadoff; /* packets received with bad offset */ -/* u_long tcps_rcvshort; */ /* packets received too short */ - u_long tcps_rcvduppack; /* duplicate-only packets received */ - u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ - u_long tcps_rcvpartduppack; /* packets with some duplicate data */ - u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ - u_long tcps_rcvoopack; /* out-of-order packets received */ - u_long tcps_rcvoobyte; /* out-of-order bytes received */ - u_long tcps_rcvpackafterwin; /* packets with data after window */ - u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ - u_long tcps_rcvafterclose; /* packets rcvd after "close" */ - u_long tcps_rcvwinprobe; /* rcvd window probe packets */ - u_long tcps_rcvdupack; /* rcvd duplicate acks */ - u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ - u_long tcps_rcvackpack; /* rcvd ack packets */ - u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ - u_long tcps_rcvwinupd; /* rcvd window update packets */ -/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ - u_long tcps_predack; /* times hdr predict ok for acks */ - u_long tcps_preddat; /* times hdr predict ok for data pkts */ - u_long tcps_socachemiss; /* tcp_last_so misses */ - u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ -}; - -extern struct tcpstat tcpstat; /* tcp statistics */ -extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ +#define TCP_REXMTVAL(tp) (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) #endif diff --git a/src/network/slirp/tcpip.h b/src/network/slirp/tcpip.h index dff5a3c96..d3df02149 100644 --- a/src/network/slirp/tcpip.h +++ b/src/network/slirp/tcpip.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -30,41 +31,74 @@ * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp */ -#ifndef _TCPIP_H_ -#define _TCPIP_H_ +#ifndef TCPIP_H +#define TCPIP_H /* * Tcp+ip header, after ip options removed. */ struct tcpiphdr { - struct ipovly ti_i; /* overlaid ip structure */ - struct tcphdr ti_t; /* tcp header */ + struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ + union { + struct { + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ + uint8_t ih_x1; /* (unused) */ + uint8_t ih_pr; /* protocol */ + } ti_i4; + struct { + struct in6_addr ih_src; + struct in6_addr ih_dst; + uint8_t ih_x1; + uint8_t ih_nh; + } ti_i6; + } ti; + uint16_t ti_x0; + uint16_t ti_len; /* protocol length */ + struct tcphdr ti_t; /* tcp header */ }; -#define ti_next ti_i.ih_next -#define ti_prev ti_i.ih_prev -#define ti_x1 ti_i.ih_x1 -#define ti_pr ti_i.ih_pr -#define ti_len ti_i.ih_len -#define ti_src ti_i.ih_src -#define ti_dst ti_i.ih_dst -#define ti_sport ti_t.th_sport -#define ti_dport ti_t.th_dport -#define ti_seq ti_t.th_seq -#define ti_ack ti_t.th_ack -#define ti_x2 ti_t.th_x2 -#define ti_off ti_t.th_off -#define ti_flags ti_t.th_flags -#define ti_win ti_t.th_win -#define ti_sum ti_t.th_sum -#define ti_urp ti_t.th_urp +#define ti_mbuf ih_mbuf.mptr +#define ti_pr ti.ti_i4.ih_pr +#define ti_src ti.ti_i4.ih_src +#define ti_dst ti.ti_i4.ih_dst +#define ti_src6 ti.ti_i6.ih_src +#define ti_dst6 ti.ti_i6.ih_dst +#define ti_nh6 ti.ti_i6.ih_nh +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +#define tcpiphdr2qlink(T) \ + ((struct qlink *)(((char *)(T)) - sizeof(struct qlink))) +#define qlink2tcpiphdr(Q) \ + ((struct tcpiphdr *)(((char *)(Q)) + sizeof(struct qlink))) +#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next) +#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev) +#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next) +#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink *)(T)) +#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr *)(T)) + +/* This is the difference between the size of a tcpiphdr structure, and the + * size of actual ip+tcp headers, rounded up since we need to align data. */ +#define TCPIPHDR_DELTA \ + (MAX(0, (sizeof(struct tcpiphdr) - sizeof(struct ip) - \ + sizeof(struct tcphdr) + 3) & \ + ~3)) /* * Just a clean way to get to the first byte * of the packet */ struct tcpiphdr_2 { - struct tcpiphdr dummy; - char first_char; + struct tcpiphdr dummy; + char first_char; }; #endif diff --git a/src/network/slirp/tftp.c b/src/network/slirp/tftp.c index b7b1ffb0a..c6950ee10 100644 --- a/src/network/slirp/tftp.c +++ b/src/network/slirp/tftp.c @@ -1,8 +1,9 @@ +/* SPDX-License-Identifier: MIT */ /* * tftp.c - a simple, read-only tftp server for qemu - * + * * Copyright (c) 2004 Magnus Damm - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -23,310 +24,441 @@ */ #include "slirp.h" -#include "../ibm.h" -struct tftp_session { - int in_use; - char filename[TFTP_FILENAME_MAX]; - - struct in_addr client_ip; - u_int16_t client_port; - - int timestamp; -}; +#include +#include +#include -struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; +static inline int tftp_session_in_use(struct tftp_session *spt) +{ + return (spt->slirp != NULL); +} -const char *tftp_prefix; - -static void tftp_session_update(struct tftp_session *spt) +static inline void tftp_session_update(struct tftp_session *spt) { spt->timestamp = curtime; - spt->in_use = 1; } static void tftp_session_terminate(struct tftp_session *spt) { - spt->in_use = 0; -} - -static int tftp_session_allocate(struct tftp_t *tp) -{ - struct tftp_session *spt; - int k; - - for (k = 0; k < TFTP_SESSIONS_MAX; k++) { - spt = &tftp_sessions[k]; - - if (!spt->in_use) - goto found; - - /* sessions time out after 5 inactive seconds */ - if ((int)(curtime - spt->timestamp) > 5000) - goto found; - } - - return -1; - - found: - memset(spt, 0, sizeof(*spt)); - memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); - spt->client_port = tp->udp.uh_sport; - - tftp_session_update(spt); - - return k; -} - -static int tftp_session_find(struct tftp_t *tp) -{ - struct tftp_session *spt; - int k; - - for (k = 0; k < TFTP_SESSIONS_MAX; k++) { - spt = &tftp_sessions[k]; - - if (spt->in_use) { - if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { - if (spt->client_port == tp->udp.uh_sport) { - return k; - } - } + if (spt->fd >= 0) { + close(spt->fd); + spt->fd = -1; } - } - - return -1; + g_free(spt->filename); + spt->slirp = NULL; } -static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, - u_int8_t *buf, int len) +static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas, + struct tftp_t *tp) { - int fd; - int bytes_read = 0; + struct tftp_session *spt; + int k; - char file_path[sizeof(pcempath) + 5 + sizeof(spt->filename)]; - strcpy(file_path, pcempath); - strcat(file_path, "tftp/"); - strcat(file_path, spt->filename); + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &slirp->tftp_sessions[k]; - fd = open(file_path, O_RDONLY | O_BINARY); + if (!tftp_session_in_use(spt)) + goto found; - if (fd < 0) { - return -1; - } - - if (len) { - lseek(fd, block_nr * 512, SEEK_SET); - - bytes_read = read(fd, buf, len); - } - - close(fd); - - return bytes_read; -} - -static int tftp_send_error(struct tftp_session *spt, - u_int16_t errorcode, const char *msg, - struct tftp_t *recv_tp) -{ - struct sockaddr_in saddr, daddr; - struct SLIRPmbuf *m; - struct tftp_t *tp; - int nobytes; - - m = m_get(); - - if (!m) { - return -1; - } - - memset(m->m_data, 0, m->m_size); - - m->m_data += if_maxlinkhdr; - tp = (void *)m->m_data; - m->m_data += sizeof(struct udpiphdr); - - tp->tp_op = htons(TFTP_ERROR); - tp->x.tp_error.tp_error_code = htons(errorcode); - strncpy((char *)tp->x.tp_error.tp_msg, msg, sizeof(tp->x.tp_error.tp_msg)); - tp->x.tp_error.tp_msg[sizeof(tp->x.tp_error.tp_msg)-1] = 0; - - saddr.sin_addr = recv_tp->ip.ip_dst; - saddr.sin_port = recv_tp->udp.uh_dport; - - daddr.sin_addr = spt->client_ip; - daddr.sin_port = spt->client_port; - - nobytes = 2; - - m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - - sizeof(struct ip) - sizeof(struct udphdr); - - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); - - tftp_session_terminate(spt); - - return 0; -} - -static int tftp_send_data(struct tftp_session *spt, - u_int16_t block_nr, - struct tftp_t *recv_tp) -{ - struct sockaddr_in saddr, daddr; - struct SLIRPmbuf *m; - struct tftp_t *tp; - int nobytes; - - if (block_nr < 1) { - return -1; - } - - m = m_get(); - - if (!m) { - return -1; - } - - memset(m->m_data, 0, m->m_size); - - m->m_data += if_maxlinkhdr; - tp = (void *)m->m_data; - m->m_data += sizeof(struct udpiphdr); - - tp->tp_op = htons(TFTP_DATA); - tp->x.tp_data.tp_block_nr = htons(block_nr); - - saddr.sin_addr = recv_tp->ip.ip_dst; - saddr.sin_port = recv_tp->udp.uh_dport; - - daddr.sin_addr = spt->client_ip; - daddr.sin_port = spt->client_port; - - nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); - - if (nobytes < 0) { - m_free(m); - - /* send "file not found" error back */ - - tftp_send_error(spt, 1, "File not found", tp); + /* sessions time out after 5 inactive seconds */ + if ((int)(curtime - spt->timestamp) > 5000) { + tftp_session_terminate(spt); + goto found; + } + } return -1; - } - m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - - sizeof(struct ip) - sizeof(struct udphdr); +found: + memset(spt, 0, sizeof(*spt)); + memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas)); + spt->fd = -1; + spt->block_size = 512; + spt->client_port = tp->udp.uh_sport; + spt->slirp = slirp; - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); - - if (nobytes == 512) { tftp_session_update(spt); - } - else { + + return k; +} + +static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas, + struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &slirp->tftp_sessions[k]; + + if (tftp_session_in_use(spt)) { + if (sockaddr_equal(&spt->client_addr, srcsas)) { + if (spt->client_port == tp->udp.uh_sport) { + return k; + } + } + } + } + + return -1; +} + +static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr, + uint8_t *buf, int len) +{ + int bytes_read = 0; + + if (spt->fd < 0) { + spt->fd = open(spt->filename, O_RDONLY | O_BINARY); + } + + if (spt->fd < 0) { + return -1; + } + + if (len) { + if (lseek(spt->fd, block_nr * spt->block_size, SEEK_SET) == (off_t)-1) { + return -1; + } + + bytes_read = read(spt->fd, buf, len); + } + + return bytes_read; +} + +static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt, + struct mbuf *m) +{ + struct tftp_t *tp; + + memset(m->m_data, 0, m->m_size); + + m->m_data += IF_MAXLINKHDR; + if (spt->client_addr.ss_family == AF_INET6) { + m->m_data += sizeof(struct ip6); + } else { + m->m_data += sizeof(struct ip); + } + tp = (void *)m->m_data; + m->m_data += sizeof(struct udphdr); + + return tp; +} + +static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m, + struct tftp_t *recv_tp) +{ + if (spt->client_addr.ss_family == AF_INET6) { + struct sockaddr_in6 sa6, da6; + + sa6.sin6_addr = spt->slirp->vhost_addr6; + sa6.sin6_port = recv_tp->udp.uh_dport; + da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr; + da6.sin6_port = spt->client_port; + + udp6_output(NULL, m, &sa6, &da6); + } else { + struct sockaddr_in sa4, da4; + + sa4.sin_addr = spt->slirp->vhost_addr; + sa4.sin_port = recv_tp->udp.uh_dport; + da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr; + da4.sin_port = spt->client_port; + + udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY); + } +} + +static int tftp_send_oack(struct tftp_session *spt, const char *keys[], + uint32_t values[], int nb, struct tftp_t *recv_tp) +{ + struct mbuf *m; + struct tftp_t *tp; + int i, n = 0; + + m = m_get(spt->slirp); + + if (!m) + return -1; + + tp = tftp_prep_mbuf_data(spt, m); + + tp->tp_op = htons(TFTP_OACK); + for (i = 0; i < nb; i++) { + n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", keys[i]); + n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", values[i]); + } + + m->m_len = G_SIZEOF_MEMBER(struct tftp_t, tp_op) + n; + tftp_udp_output(spt, m, recv_tp); + + return 0; +} + +static void tftp_send_error(struct tftp_session *spt, uint16_t errorcode, + const char *msg, struct tftp_t *recv_tp) +{ + struct mbuf *m; + struct tftp_t *tp; + + DEBUG_TFTP("tftp error msg: %s", msg); + + m = m_get(spt->slirp); + + if (!m) { + goto out; + } + + tp = tftp_prep_mbuf_data(spt, m); + + tp->tp_op = htons(TFTP_ERROR); + tp->x.tp_error.tp_error_code = htons(errorcode); + slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), + msg); + + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + + strlen(msg) - sizeof(struct udphdr); + tftp_udp_output(spt, m, recv_tp); + +out: tftp_session_terminate(spt); - } - - return 0; } -static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) +static void tftp_send_next_block(struct tftp_session *spt, + struct tftp_t *recv_tp) { - struct tftp_session *spt; - int s, k, n; - u_int8_t *src, *dst; + struct mbuf *m; + struct tftp_t *tp; + int nobytes; - s = tftp_session_allocate(tp); + m = m_get(spt->slirp); - if (s < 0) { - return; - } - - spt = &tftp_sessions[s]; - - src = tp->x.tp_buf; - dst = (u_int8_t *)spt->filename; - n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); - - /* get name */ - - for (k = 0; k < n; k++) { - if (k < TFTP_FILENAME_MAX) { - dst[k] = src[k]; + if (!m) { + return; } - else { - return; + + tp = tftp_prep_mbuf_data(spt, m); + + tp->tp_op = htons(TFTP_DATA); + tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff); + + nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, + spt->block_size); + + if (nobytes < 0) { + m_free(m); + + /* send "file not found" error back */ + + tftp_send_error(spt, 1, "File not found", tp); + + return; } - - if (src[k] == '\0') { - break; + + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) - + sizeof(struct udphdr); + tftp_udp_output(spt, m, recv_tp); + + if (nobytes == spt->block_size) { + tftp_session_update(spt); + } else { + tftp_session_terminate(spt); } - } - - if (k >= n) { - return; - } - - k++; - - /* check mode */ - if ((n - k) < 6) { - return; - } - - if (memcmp(&src[k], "octet\0", 6) != 0) { - tftp_send_error(spt, 4, "Unsupported transfer mode", tp); - return; - } - pclog("tftp request: %s\n", spt->filename); - - /* do sanity checks on the filename */ - - if (strstr(spt->filename, "../") || strstr(spt->filename, "..\\")) { - tftp_send_error(spt, 2, "Access violation", tp); - return; - } - - /* check if the file exists */ - - if (tftp_read_data(spt, 0, (u_int8_t *)spt->filename, 0) < 0) { - tftp_send_error(spt, 1, "File not found", tp); - return; - } - - tftp_send_data(spt, 1, tp); + spt->block_nr++; } -static void tftp_handle_ack(struct tftp_t *tp, int pktlen) +static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas, + struct tftp_t *tp, int pktlen) { - int s; + struct tftp_session *spt; + int s, k; + size_t prefix_len; + char *req_fname; + const char *option_name[2]; + uint32_t option_value[2]; + int nb_options = 0; - s = tftp_session_find(tp); + /* check if a session already exists and if so terminate it */ + s = tftp_session_find(slirp, srcsas, tp); + if (s >= 0) { + tftp_session_terminate(&slirp->tftp_sessions[s]); + } - if (s < 0) { - return; - } + s = tftp_session_allocate(slirp, srcsas, tp); - if (tftp_send_data(&tftp_sessions[s], - ntohs(tp->x.tp_data.tp_block_nr) + 1, - tp) < 0) { - return; - } + if (s < 0) { + return; + } + + spt = &slirp->tftp_sessions[s]; + + /* unspecified prefix means service disabled */ + if (!slirp->tftp_prefix) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* skip header fields */ + k = 0; + pktlen -= offsetof(struct tftp_t, x.tp_buf); + + /* prepend tftp_prefix */ + prefix_len = strlen(slirp->tftp_prefix); + spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2); + memcpy(spt->filename, slirp->tftp_prefix, prefix_len); + spt->filename[prefix_len] = '/'; + + /* get name */ + req_fname = spt->filename + prefix_len + 1; + + while (1) { + if (k >= TFTP_FILENAME_MAX || k >= pktlen) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + req_fname[k] = tp->x.tp_buf[k]; + if (req_fname[k++] == '\0') { + break; + } + } + + DEBUG_TFTP("tftp rrq file: %s", req_fname); + + /* check mode */ + if ((pktlen - k) < 6) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) { + tftp_send_error(spt, 4, "Unsupported transfer mode", tp); + return; + } + + k += 6; /* skipping octet */ + + /* do sanity checks on the filename */ + if ( +#ifdef G_OS_WIN32 + strstr(req_fname, "..\\") || + req_fname[strlen(req_fname) - 1] == '\\' || +#endif + strstr(req_fname, "../") || + req_fname[strlen(req_fname) - 1] == '/') { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* check if the file exists */ + if (tftp_read_data(spt, 0, NULL, 0) < 0) { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + + if (tp->x.tp_buf[pktlen - 1] != 0) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) { + const char *key, *value; + + key = &tp->x.tp_buf[k]; + k += strlen(key) + 1; + + if (k >= pktlen) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + value = &tp->x.tp_buf[k]; + k += strlen(value) + 1; + + if (strcasecmp(key, "tsize") == 0) { + int tsize = atoi(value); + struct stat stat_p; + + if (tsize == 0) { + if (stat(spt->filename, &stat_p) == 0) + tsize = stat_p.st_size; + else { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + } + + option_name[nb_options] = "tsize"; + option_value[nb_options] = tsize; + nb_options++; + } else if (strcasecmp(key, "blksize") == 0) { + int blksize = atoi(value); + + /* Accept blksize up to our maximum size */ + if (blksize > 0) { + spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX); + option_name[nb_options] = "blksize"; + option_value[nb_options] = spt->block_size; + nb_options++; + } + } + } + + if (nb_options > 0) { + assert(nb_options <= G_N_ELEMENTS(option_name)); + tftp_send_oack(spt, option_name, option_value, nb_options, tp); + return; + } + + spt->block_nr = 0; + tftp_send_next_block(spt, tp); } -void tftp_input(struct SLIRPmbuf *m) +static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas, + struct tftp_t *tp, int pktlen) { - struct tftp_t *tp = (struct tftp_t *)m->m_data; + int s; - switch(ntohs(tp->tp_op)) { - case TFTP_RRQ: - tftp_handle_rrq(tp, m->m_len); - break; + s = tftp_session_find(slirp, srcsas, tp); - case TFTP_ACK: - tftp_handle_ack(tp, m->m_len); - break; - } + if (s < 0) { + return; + } + + tftp_send_next_block(&slirp->tftp_sessions[s], tp); +} + +static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas, + struct tftp_t *tp, int pktlen) +{ + int s; + + s = tftp_session_find(slirp, srcsas, tp); + + if (s < 0) { + return; + } + + tftp_session_terminate(&slirp->tftp_sessions[s]); +} + +void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m) +{ + struct tftp_t *tp = (struct tftp_t *)m->m_data; + + switch (ntohs(tp->tp_op)) { + case TFTP_RRQ: + tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len); + break; + + case TFTP_ACK: + tftp_handle_ack(m->slirp, srcsas, tp, m->m_len); + break; + + case TFTP_ERROR: + tftp_handle_error(m->slirp, srcsas, tp, m->m_len); + break; + } } diff --git a/src/network/slirp/tftp.h b/src/network/slirp/tftp.h index ba4174115..663485328 100644 --- a/src/network/slirp/tftp.h +++ b/src/network/slirp/tftp.h @@ -1,40 +1,60 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* tftp defines */ -#define TFTP_SESSIONS_MAX 3 +#ifndef SLIRP_TFTP_H +#define SLIRP_TFTP_H -#define TFTP_SERVER 69 +#include "util.h" -#define TFTP_RRQ 1 -#define TFTP_WRQ 2 -#define TFTP_DATA 3 -#define TFTP_ACK 4 -#define TFTP_ERROR 5 +#define TFTP_SESSIONS_MAX 20 + +#define TFTP_SERVER 69 + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 +#define TFTP_OACK 6 #define TFTP_FILENAME_MAX 512 +#define TFTP_BLOCKSIZE_MAX 1428 -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(push, 1) #endif - struct tftp_t { - struct ip ip; - struct udphdr udp; - u_int16_t tp_op; - union { - struct { - u_int16_t tp_block_nr; - u_int8_t tp_buf[512]; - } tp_data; - struct { - u_int16_t tp_error_code; - u_int8_t tp_msg[512]; - } tp_error; - u_int8_t tp_buf[512 + 2]; - } x; -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) + struct udphdr udp; + uint16_t tp_op; + union { + struct { + uint16_t tp_block_nr; + uint8_t tp_buf[TFTP_BLOCKSIZE_MAX]; + } tp_data; + struct { + uint16_t tp_error_code; + uint8_t tp_msg[TFTP_BLOCKSIZE_MAX]; + } tp_error; + char tp_buf[TFTP_BLOCKSIZE_MAX + 2]; + } x; +} SLIRP_PACKED; +#if defined(_MSC_VER) && !defined (__clang__) +#pragma pack(pop) #endif -void tftp_input(struct SLIRPmbuf *m); +struct tftp_session { + Slirp *slirp; + char *filename; + int fd; + uint16_t block_size; + + struct sockaddr_storage client_addr; + uint16_t client_port; + uint32_t block_nr; + + int timestamp; +}; + +void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m); + +#endif diff --git a/src/network/slirp/tinyglib.c b/src/network/slirp/tinyglib.c new file mode 100644 index 000000000..9504ff3af --- /dev/null +++ b/src/network/slirp/tinyglib.c @@ -0,0 +1,133 @@ +/* + * 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. + * + * Minimal reimplementation of GLib for libslirp. + * + * + * + * Author: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include + +/* Must be a function, as libslirp redefines it as a macro. */ +gboolean +g_spawn_async_with_fds(const gchar *working_directory, gchar **argv, + gchar **envp, GSpawnFlags flags, + GSpawnChildSetupFunc child_setup, + gpointer user_data, GPid *child_pid, gint stdin_fd, + gint stdout_fd, gint stderr_fd, GError **error) +{ + return 0; +} + + +/* Needs bounds checking, but not really used by libslirp. */ +GString * +g_string_new(gchar *base) +{ + char *ret = malloc(4096); + if (base) + strcpy(ret, base); + return ret; +} + + +/* Unimplemented, as with anything related to GString. */ +gchar * +g_string_free(GString *string, gboolean free_segment) +{ + return (free_segment ? NULL : string); +} + + +/* Implementation borrowed from GLib itself. */ +gchar * +g_strstr_len(const gchar *haystack, gssize haystack_len, const gchar *needle) +{ + if (haystack_len < 0) + return strstr(haystack, needle); + else { + const gchar *p = haystack; + gsize needle_len = strlen(needle); + gsize haystack_len_unsigned = haystack_len; + const gchar *end; + gsize i; + + if (needle_len == 0) + return (gchar *) haystack; + + if (haystack_len_unsigned < needle_len) + return NULL; + + end = haystack + haystack_len - needle_len; + + while (p <= end && *p) { + for (i = 0; i < needle_len; i++) + if (p[i] != needle[i]) + goto next; + + return (gchar *)p; + +next: + p++; + } + + return NULL; + } +} + + +/* Implementation borrowed from GLib itself. */ +guint +g_strv_length(gchar **str_array) +{ + guint i = 0; + while (str_array[i] != NULL) + ++i; + return i; +} + +/* Implementation borrowed from GLib itself. */ +gsize +g_strlcpy (gchar *dest, + const gchar *src, + gsize dest_size) +{ + gchar *d = dest; + const gchar *s = src; + gsize n = dest_size; + + if (dest == NULL) return 0; + if (src == NULL) return 0; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) + do + { + gchar c = *s++; + + *d++ = c; + if (c == 0) + break; + } + while (--n != 0); + + /* If not enough room in dest, add NUL and traverse rest of src */ + if (n == 0) + { + if (dest_size != 0) + *d = 0; + while (*s++) + ; + } + + return s - src - 1; /* count does not include NUL */ +} diff --git a/src/network/slirp/udp.c b/src/network/slirp/udp.c index f847c51a4..0ad44d7c0 100644 --- a/src/network/slirp/udp.c +++ b/src/network/slirp/udp.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -33,649 +34,332 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ -#include -#ifndef _WIN32 -# include -#endif #include "slirp.h" #include "ip_icmp.h" -struct udpstat udpstat; +static uint8_t udp_tos(struct socket *so); -struct SLIRPsocket udb; - -/* - * UDP protocol implementation. - * Per RFC 768, August, 1980. - */ -#ifndef COMPAT_42 -int udpcksum = 1; -#else -int udpcksum = 0; /* XXX */ -#endif - -struct SLIRPsocket *udp_last_so = &udb; - -void -udp_init() +void udp_init(Slirp *slirp) { - udb.so_next = udb.so_prev = &udb; + slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb; + slirp->udp_last_so = &slirp->udb; } -/* m->m_data points at ip packet header - * m->m_len length ip packet + +void udp_cleanup(Slirp *slirp) +{ + struct socket *so, *so_next; + + for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { + so_next = so->so_next; + udp_detach(slirp->udb.so_next); + } +} + +/* m->m_data points at ip packet header + * m->m_len length ip packet * ip->ip_len length data (IPDU) */ -void -udp_input(m, iphlen) - struct SLIRPmbuf *m; - int iphlen; +void udp_input(register struct mbuf *m, int iphlen) { - struct ip *ip; - struct udphdr *uh; -/* struct SLIRPmbuf *opts = 0;*/ - int len; - struct ip save_ip; - struct SLIRPsocket *so; - - DEBUG_CALL("udp_input"); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("iphlen = %d", iphlen); - - udpstat.udps_ipackets++; + Slirp *slirp = m->slirp; + register struct ip *ip; + register struct udphdr *uh; + int len; + struct ip save_ip; + struct socket *so; + struct sockaddr_storage lhost; + struct sockaddr_in *lhost4; - /* - * Strip IP options, if any; should skip this, - * make available to user, and use on returned packets, - * but we don't yet have a way to check the checksum - * with options still present. - */ - if(iphlen > sizeof(struct ip)) { - ip_stripoptions(m, (struct SLIRPmbuf *)0); - iphlen = sizeof(struct ip); - } + DEBUG_CALL("udp_input"); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("iphlen = %d", iphlen); - /* - * Get IP and UDP header together in first SLIRPmbuf. - */ - ip = mtod(m, struct ip *); - uh = (struct udphdr *)((SLIRPcaddr_t)ip + iphlen); - - /* - * Make SLIRPmbuf data length reflect UDP length. - * If not enough data to reflect UDP length, drop. - */ - len = ntohs((u_int16_t)uh->uh_ulen); - - if (ip->ip_len != len) { - if (len > ip->ip_len) { - udpstat.udps_badlen++; - goto bad; - } - m_adj(m, len - ip->ip_len); - ip->ip_len = len; - } - - /* - * Save a copy of the IP header in case we want restore it - * for sending an ICMP error message in response. - */ - save_ip = *ip; - save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ - - /* - * Checksum extended UDP header and data. - */ - if (udpcksum && uh->uh_sum) { - ((struct ipovly *)ip)->ih_next = 0; - ((struct ipovly *)ip)->ih_prev = 0; - ((struct ipovly *)ip)->ih_x1 = 0; - ((struct ipovly *)ip)->ih_len = uh->uh_ulen; - /* keep uh_sum for ICMP reply - * uh->uh_sum = cksum(m, len + sizeof (struct ip)); - * if (uh->uh_sum) { - */ - if(cksum(m, len + sizeof(struct ip))) { - udpstat.udps_badsum++; - goto bad; - } - } - - /* - * handle DHCP/BOOTP - */ - if (ntohs(uh->uh_dport) == BOOTP_SERVER) { - bootp_input(m); - goto bad; - } - -#ifdef NEED_TFTP - /* - * handle TFTP - */ - if (ntohs(uh->uh_dport) == TFTP_SERVER) { - tftp_input(m); - goto bad; - } -#endif - - /* - * Locate pcb for datagram. - */ - so = udp_last_so; - if (so->so_lport != uh->uh_sport || - so->so_laddr.s_addr != ip->ip_src.s_addr) { - struct SLIRPsocket *tmp; - - for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { - if (tmp->so_lport == uh->uh_sport && - tmp->so_laddr.s_addr == ip->ip_src.s_addr) { - tmp->so_faddr.s_addr = ip->ip_dst.s_addr; - tmp->so_fport = uh->uh_dport; - so = tmp; - break; - } - } - if (tmp == &udb) { - so = NULL; - } else { - udpstat.udpps_pcbcachemiss++; - udp_last_so = so; - } - } - - if (so == NULL) { - /* - * If there's no socket for this packet, - * create one - */ - if ((so = socreate()) == NULL) goto bad; - if(udp_attach(so) == -1) { - DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", - errno,strerror(errno))); - sofree(so); - goto bad; - } - - /* - * Setup fields - */ - /* udp_last_so = so; */ - so->so_laddr = ip->ip_src; - so->so_lport = uh->uh_sport; - - if ((so->so_iptos = udp_tos(so)) == 0) - so->so_iptos = ip->ip_tos; - - /* - * XXXXX Here, check if it's in udpexec_list, - * and if it is, do the fork_exec() etc. - */ - } - - so->so_faddr = ip->ip_dst; /* XXX */ - so->so_fport = uh->uh_dport; /* XXX */ - - iphlen += sizeof(struct udphdr); - m->m_len -= iphlen; - m->m_data += iphlen; - - /* - * Now we sendto() the packet. - */ - if (so->so_emu) - udp_emu(so, m); - - if(sosendto(so,m) == -1) { - m->m_len += iphlen; - m->m_data -= iphlen; - *ip=save_ip; - DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); - } - - m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ - - /* restore the orig SLIRPmbuf packet */ - m->m_len += iphlen; - m->m_data -= iphlen; - *ip=save_ip; - so->so_m=m; /* ICMP backup */ - - return; -bad: - m_freem(m); - /* if (opts) m_freem(opts); */ - return; -} - -int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, - struct sockaddr_in *saddr, struct sockaddr_in *daddr, - int iptos) -{ - struct udpiphdr *ui; - int error = 0; - - DEBUG_CALL("udp_output"); - DEBUG_ARG("so = %lx", (long)so); - DEBUG_ARG("m = %lx", (long)m); - DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); - DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); - - /* - * Adjust for header - */ - m->m_data -= sizeof(struct udpiphdr); - m->m_len += sizeof(struct udpiphdr); - - /* - * Fill in SLIRPmbuf with extended UDP header - * and addresses and length put into network format. - */ - ui = mtod(m, struct udpiphdr *); - ui->ui_next = ui->ui_prev = 0; - ui->ui_x1 = 0; - ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ - /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ - ui->ui_src = saddr->sin_addr; - ui->ui_dst = daddr->sin_addr; - ui->ui_sport = saddr->sin_port; - ui->ui_dport = daddr->sin_port; - ui->ui_ulen = ui->ui_len; - - /* - * Stuff checksum and output datagram. - */ - ui->ui_sum = 0; - if (udpcksum) { - if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) - ui->ui_sum = 0xffff; - } - ((struct ip *)ui)->ip_len = m->m_len; - - ((struct ip *)ui)->ip_ttl = ip_defttl; - ((struct ip *)ui)->ip_tos = iptos; - - udpstat.udps_opackets++; - - error = ip_output(so, m); - - return (error); -} - -int udp_output(struct SLIRPsocket *so, struct SLIRPmbuf *m, - struct sockaddr_in *addr) - -{ - struct sockaddr_in saddr, daddr; - - saddr = *addr; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { - saddr.sin_addr.s_addr = so->so_faddr.s_addr; - if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) - saddr.sin_addr.s_addr = alias_addr.s_addr; - } - daddr.sin_addr = so->so_laddr; - daddr.sin_port = so->so_lport; - - return udp_output2(so, m, &saddr, &daddr, so->so_iptos); -} - -int -udp_attach(so) - struct SLIRPsocket *so; -{ - struct sockaddr_in addr; - - if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { /* - * Here, we bind() the socket. Although not really needed - * (sendto() on an unbound socket will bind it), it's done - * here so that emulation of ytalk etc. don't have to do it + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. */ - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = INADDR_ANY; - if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { - int lasterrno=errno; - closesocket(so->s); - so->s=-1; -#ifdef _WIN32 - WSASetLastError(lasterrno); -#else - errno=lasterrno; -#endif - } else { - /* success, insert in queue */ - so->so_expire = curtime + SO_EXPIRE; - insque(so,&udb); + if (iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); } - } - return(so->s); + + /* + * Get IP and UDP header together in first mbuf. + */ + ip = mtod(m, struct ip *); + uh = (struct udphdr *)((char *)ip + iphlen); + + /* + * Make mbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((uint16_t)uh->uh_ulen); + + if (ip->ip_len != len) { + if (len > ip->ip_len) { + goto bad; + } + m_adj(m, len - ip->ip_len); + ip->ip_len = len; + } + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + save_ip.ip_len += iphlen; /* tcp_input subtracts this */ + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum) { + memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr)); + ((struct ipovly *)ip)->ih_x1 = 0; + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + if (cksum(m, len + sizeof(struct ip))) { + goto bad; + } + } + + lhost.ss_family = AF_INET; + lhost4 = (struct sockaddr_in *)&lhost; + lhost4->sin_addr = ip->ip_src; + lhost4->sin_port = uh->uh_sport; + + /* + * handle DHCP/BOOTP + */ + if (ntohs(uh->uh_dport) == BOOTP_SERVER && + (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr || + ip->ip_dst.s_addr == 0xffffffff)) { + bootp_input(m); + goto bad; + } + + /* + * handle TFTP + */ + if (ntohs(uh->uh_dport) == TFTP_SERVER && + ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) { + m->m_data += iphlen; + m->m_len -= iphlen; + tftp_input(&lhost, m); + m->m_data -= iphlen; + m->m_len += iphlen; + goto bad; + } + + if (slirp->restricted) { + goto bad; + } + + /* + * Locate pcb for datagram. + */ + so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL); + + if (so == NULL) { + /* + * If there's no socket for this packet, + * create one + */ + so = socreate(slirp); + if (udp_attach(so, AF_INET) == -1) { + DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno)); + sofree(so); + goto bad; + } + + /* + * Setup fields + */ + so->so_lfamily = AF_INET; + so->so_laddr = ip->ip_src; + so->so_lport = uh->uh_sport; + + if ((so->so_iptos = udp_tos(so)) == 0) + so->so_iptos = ip->ip_tos; + + /* + * XXXXX Here, check if it's in udpexec_list, + * and if it is, do the fork_exec() etc. + */ + } + + so->so_ffamily = AF_INET; + so->so_faddr = ip->ip_dst; /* XXX */ + so->so_fport = uh->uh_dport; /* XXX */ + + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_data += iphlen; + + /* + * Now we sendto() the packet. + */ + if (sosendto(so, m) == -1) { + m->m_len += iphlen; + m->m_data -= iphlen; + *ip = save_ip; + DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); + goto bad; + } + + m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ + + /* restore the orig mbuf packet */ + m->m_len += iphlen; + m->m_data -= iphlen; + *ip = save_ip; + so->so_m = m; /* ICMP backup */ + + return; +bad: + m_free(m); } -void -udp_detach(so) - struct SLIRPsocket *so; +int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, + struct sockaddr_in *daddr, int iptos) { - closesocket(so->s); - /* if (so->so_m) m_free(so->so_m); done by sofree */ + register struct udpiphdr *ui; + int error = 0; - sofree(so); + DEBUG_CALL("udp_output"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m = %p", m); + DEBUG_ARG("saddr = %s", inet_ntoa(saddr->sin_addr)); + DEBUG_ARG("daddr = %s", inet_ntoa(daddr->sin_addr)); + + /* + * Adjust for header + */ + m->m_data -= sizeof(struct udpiphdr); + m->m_len += sizeof(struct udpiphdr); + + /* + * Fill in mbuf with extended UDP header + * and addresses and length put into network format. + */ + ui = mtod(m, struct udpiphdr *); + memset(&ui->ui_i.ih_mbuf, 0, sizeof(struct mbuf_ptr)); + ui->ui_x1 = 0; + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons(m->m_len - sizeof(struct ip)); + /* XXXXX Check for from-one-location sockets, or from-any-location sockets + */ + ui->ui_src = saddr->sin_addr; + ui->ui_dst = daddr->sin_addr; + ui->ui_sport = saddr->sin_port; + ui->ui_dport = daddr->sin_port; + ui->ui_ulen = ui->ui_len; + + /* + * Stuff checksum and output datagram. + */ + ui->ui_sum = 0; + if ((ui->ui_sum = cksum(m, m->m_len)) == 0) + ui->ui_sum = 0xffff; + ((struct ip *)ui)->ip_len = m->m_len; + + ((struct ip *)ui)->ip_ttl = IPDEFTTL; + ((struct ip *)ui)->ip_tos = iptos; + + error = ip_output(so, m); + + return (error); } -struct tos_t udptos[] = { - {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ - {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ - {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ - {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ - {0, 0, 0, 0} -}; - -u_int8_t -udp_tos(so) - struct SLIRPsocket *so; +int udp_attach(struct socket *so, unsigned short af) { - int i = 0; - - while(udptos[i].tos) { - if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || - (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { - so->so_emu = udptos[i].emu; - return udptos[i].tos; - } - i++; - } - - return 0; + so->s = slirp_socket(af, SOCK_DGRAM, 0); + if (so->s != -1) { + if (slirp_bind_outbound(so, af) != 0) { + // bind failed - close socket + closesocket(so->s); + so->s = -1; + return -1; + } + so->so_expire = curtime + SO_EXPIRE; + insque(so, &so->slirp->udb); + } + return (so->s); } -#ifdef EMULATE_TALK -#include "talkd.h" -#endif - -/* - * Here, talk/ytalk/ntalk requests must be emulated - */ -void -udp_emu(so, m) - struct SLIRPsocket *so; - struct SLIRPmbuf *m; +void udp_detach(struct socket *so) { - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); -#ifdef EMULATE_TALK - CTL_MSG_OLD *omsg; - CTL_MSG *nmsg; - char buff[sizeof(CTL_MSG)]; - u_char type; - -struct talk_request { - struct talk_request *next; - struct SLIRPsocket *udp_so; - struct SLIRPsocket *tcp_so; -} *req; - - static struct talk_request *req_tbl = 0; - -#endif - -struct cu_header { - uint16_t d_family; // destination family - uint16_t d_port; // destination port - uint32_t d_addr; // destination address - uint16_t s_family; // source family - uint16_t s_port; // source port - uint32_t so_addr; // source address - uint32_t seqn; // sequence number - uint16_t message; // message - uint16_t data_type; // data type - uint16_t pkt_len; // packet length -} *cu_head; - - switch(so->so_emu) { - -#ifdef EMULATE_TALK - case EMU_TALK: - case EMU_NTALK: - /* - * Talk emulation. We always change the ctl_addr to get - * some answers from the daemon. When an ANNOUNCE comes, - * we send LEAVE_INVITE to the local daemons. Also when a - * DELETE comes, we send copies to the local daemons. - */ - if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) - return; - -#define IS_OLD (so->so_emu == EMU_TALK) - -#define COPY_MSG(dest, src) { dest->type = src->type; \ - dest->id_num = src->id_num; \ - dest->pid = src->pid; \ - dest->addr = src->addr; \ - dest->ctl_addr = src->ctl_addr; \ - memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ - memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ - memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } - -#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) -/* old_sockaddr to sockaddr_in */ - - - if (IS_OLD) { /* old talk */ - omsg = mtod(m, CTL_MSG_OLD*); - nmsg = (CTL_MSG *) buff; - type = omsg->type; - OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; - OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; - strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); - } else { /* new talk */ - omsg = (CTL_MSG_OLD *) buff; - nmsg = mtod(m, CTL_MSG *); - type = nmsg->type; - OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; - OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; - strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); - } - - if (type == LOOK_UP) - return; /* for LOOK_UP this is enough */ - - if (IS_OLD) { /* make a copy of the message */ - COPY_MSG(nmsg, omsg); - nmsg->vers = 1; - nmsg->answer = 0; - } else - COPY_MSG(omsg, nmsg); - - /* - * If if is an ANNOUNCE message, we go through the - * request table to see if a tcp port has already - * been redirected for this socket. If not, we solisten() - * a new socket and add this entry to the table. - * The port number of the tcp socket and our IP - * are put to the addr field of the message structures. - * Then a LEAVE_INVITE is sent to both local daemon - * ports, 517 and 518. This is why we have two copies - * of the message, one in old talk and one in new talk - * format. - */ - - if (type == ANNOUNCE) { - int s; - u_short temp_port; - - for(req = req_tbl; req; req = req->next) - if (so == req->udp_so) - break; /* found it */ - - if (!req) { /* no entry for so, create new */ - req = (struct talk_request *) - malloc(sizeof(struct talk_request)); - req->udp_so = so; - req->tcp_so = solisten(0, - OTOSIN(omsg, addr)->sin_addr.s_addr, - OTOSIN(omsg, addr)->sin_port, - SS_FACCEPTONCE); - req->next = req_tbl; - req_tbl = req; - } - - /* replace port number in addr field */ - addrlen = sizeof(addr); - getsockname(req->tcp_so->s, - (struct sockaddr *) &addr, - &addrlen); - OTOSIN(omsg, addr)->sin_port = addr.sin_port; - OTOSIN(omsg, addr)->sin_addr = our_addr; - OTOSIN(nmsg, addr)->sin_port = addr.sin_port; - OTOSIN(nmsg, addr)->sin_addr = our_addr; - - /* send LEAVE_INVITEs */ - temp_port = OTOSIN(omsg, ctl_addr)->sin_port; - OTOSIN(omsg, ctl_addr)->sin_port = 0; - OTOSIN(nmsg, ctl_addr)->sin_port = 0; - omsg->type = nmsg->type = LEAVE_INVITE; - - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - addr.sin_addr = our_addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(517); - sendto(s, (char *)omsg, sizeof(*omsg), 0, - (struct sockaddr *)&addr, sizeof(addr)); - addr.sin_port = htons(518); - sendto(s, (char *)nmsg, sizeof(*nmsg), 0, - (struct sockaddr *) &addr, sizeof(addr)); - closesocket(s) ; - - omsg->type = nmsg->type = ANNOUNCE; - OTOSIN(omsg, ctl_addr)->sin_port = temp_port; - OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; - } - - /* - * If it is a DELETE message, we send a copy to the - * local daemons. Then we delete the entry corresponding - * to our socket from the request table. - */ - - if (type == DELETE) { - struct talk_request *temp_req, *req_next; - int s; - u_short temp_port; - - temp_port = OTOSIN(omsg, ctl_addr)->sin_port; - OTOSIN(omsg, ctl_addr)->sin_port = 0; - OTOSIN(nmsg, ctl_addr)->sin_port = 0; - - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - addr.sin_addr = our_addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(517); - sendto(s, (char *)omsg, sizeof(*omsg), 0, - (struct sockaddr *)&addr, sizeof(addr)); - addr.sin_port = htons(518); - sendto(s, (char *)nmsg, sizeof(*nmsg), 0, - (struct sockaddr *)&addr, sizeof(addr)); - closesocket(s); - - OTOSIN(omsg, ctl_addr)->sin_port = temp_port; - OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; - - /* delete table entry */ - if (so == req_tbl->udp_so) { - temp_req = req_tbl; - req_tbl = req_tbl->next; - free(temp_req); - } else { - temp_req = req_tbl; - for(req = req_tbl->next; req; req = req_next) { - req_next = req->next; - if (so == req->udp_so) { - temp_req->next = req_next; - free(req); - break; - } else { - temp_req = req; - } - } - } - } - - return; -#endif - - case EMU_CUSEEME: - - /* - * Cu-SeeMe emulation. - * Hopefully the packet is more that 16 bytes long. We don't - * do any other tests, just replace the address and port - * fields. - */ - if (m->m_len >= sizeof (*cu_head)) { - if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) - return; - cu_head = mtod(m, struct cu_header *); - cu_head->s_port = addr.sin_port; - cu_head->so_addr = our_addr.s_addr; - } - - return; - } + so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); + closesocket(so->s); + sofree(so); } -struct SLIRPsocket * -udp_listen(port, laddr, lport, flags) - u_int port; - u_int32_t laddr; - u_int lport; - int flags; +static const struct tos_t udptos[] = { { 0, 53, IPTOS_LOWDELAY, 0 }, /* DNS */ + { 0, 0, 0, 0 } }; + +static uint8_t udp_tos(struct socket *so) { - struct sockaddr_in addr; - struct SLIRPsocket *so; - socklen_t addrlen = sizeof(struct sockaddr_in); - int opt = 1; - - if ((so = socreate()) == NULL) { - free(so); - return NULL; - } - so->s = socket(AF_INET,SOCK_DGRAM,0); - so->so_expire = curtime + SO_EXPIRE; - insque(so,&udb); + int i = 0; - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = port; + while (udptos[i].tos) { + if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || + (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { + if (so->slirp->enable_emu) + so->so_emu = udptos[i].emu; + return udptos[i].tos; + } + i++; + } - if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { - udp_detach(so); - return NULL; - } - setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); -/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ - - getsockname(so->s,(struct sockaddr *)&addr,&addrlen); - so->so_fport = addr.sin_port; - if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) - so->so_faddr = alias_addr; - else - so->so_faddr = addr.sin_addr; - - so->so_lport = lport; - so->so_laddr.s_addr = laddr; - if (flags != SS_FACCEPTONCE) - so->so_expire = 0; - - so->so_state = SS_ISFCONNECTED; - - return so; + return 0; +} + +struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, + uint32_t laddr, unsigned lport, int flags) +{ + /* TODO: IPv6 */ + struct sockaddr_in addr; + struct socket *so; + socklen_t addrlen = sizeof(struct sockaddr_in); + + memset(&addr, 0, sizeof(addr)); + so = socreate(slirp); + so->s = slirp_socket(AF_INET, SOCK_DGRAM, 0); + if (so->s < 0) { + sofree(so); + return NULL; + } + so->so_expire = curtime + SO_EXPIRE; + insque(so, &slirp->udb); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = haddr; + addr.sin_port = hport; + + if (bind(so->s, (struct sockaddr *)&addr, addrlen) < 0) { + udp_detach(so); + return NULL; + } + slirp_socket_set_fast_reuse(so->s); + + getsockname(so->s, (struct sockaddr *)&addr, &addrlen); + so->fhost.sin = addr; + sotranslate_accept(so); + so->so_lfamily = AF_INET; + so->so_lport = lport; + so->so_laddr.s_addr = laddr; + if (flags != SS_FACCEPTONCE) + so->so_expire = 0; + + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_ISFCONNECTED | flags; + + return so; } diff --git a/src/network/slirp/udp.h b/src/network/slirp/udp.h index 2f6b1e483..c3b83fdc5 100644 --- a/src/network/slirp/udp.h +++ b/src/network/slirp/udp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -30,85 +31,60 @@ * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp */ -#ifndef _UDP_H_ -#define _UDP_H_ +#ifndef UDP_H +#define UDP_H #define UDP_TTL 0x60 #define UDP_UDPDATALEN 16192 -extern struct SLIRPsocket *udp_last_so; - /* * Udp protocol header. * Per RFC 768, September, 1981. */ -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(1) -#endif - struct udphdr { - u_int16_t uh_sport; /* source port */ - u_int16_t uh_dport; /* destination port */ - int16_t uh_ulen; /* udp length */ - u_int16_t uh_sum; /* udp checksum */ -} PACKED__; - -#ifdef PRAGMA_PACK_SUPPORTED -#pragma pack(PACK_END) -#endif + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +}; /* * UDP kernel structures and variables. */ struct udpiphdr { - struct ipovly ui_i; /* overlaid ip structure */ - struct udphdr ui_u; /* udp header */ -}; -#define ui_next ui_i.ih_next -#define ui_prev ui_i.ih_prev -#define ui_x1 ui_i.ih_x1 -#define ui_pr ui_i.ih_pr -#define ui_len ui_i.ih_len -#define ui_src ui_i.ih_src -#define ui_dst ui_i.ih_dst -#define ui_sport ui_u.uh_sport -#define ui_dport ui_u.uh_dport -#define ui_ulen ui_u.uh_ulen -#define ui_sum ui_u.uh_sum - -struct udpstat { - /* input statistics: */ - u_long udps_ipackets; /* total input packets */ - u_long udps_hdrops; /* packet shorter than header */ - u_long udps_badsum; /* checksum error */ - u_long udps_badlen; /* data length larger than packet */ - u_long udps_noport; /* no socket on port */ - u_long udps_noportbcast; /* of above, arrived as broadcast */ - u_long udps_fullsock; /* not delivered, input socket full */ - u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ - /* output statistics: */ - u_long udps_opackets; /* total output packets */ + struct ipovly ui_i; /* overlaid ip structure */ + struct udphdr ui_u; /* udp header */ }; +#define ui_mbuf ui_i.ih_mbuf.mptr +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum /* * Names for UDP sysctl objects */ -#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ -#define UDPCTL_MAXID 2 +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_MAXID 2 -extern struct udpstat udpstat; -extern struct SLIRPsocket udb; -struct SLIRPmbuf; +struct mbuf; + +void udp_init(Slirp *); +void udp_cleanup(Slirp *); +void udp_input(register struct mbuf *, int); +int udp_attach(struct socket *, unsigned short af); +void udp_detach(struct socket *); +struct socket *udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int); +int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, + struct sockaddr_in *daddr, int iptos); + +void udp6_input(register struct mbuf *); +int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr, + struct sockaddr_in6 *daddr); -void udp_init _P((void)); -void udp_input _P((register struct SLIRPmbuf *, int)); -int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *)); -int udp_attach _P((struct SLIRPsocket *)); -void udp_detach _P((struct SLIRPsocket *)); -u_int8_t udp_tos _P((struct SLIRPsocket *)); -void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); -struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int)); -int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, - struct sockaddr_in *saddr, struct sockaddr_in *daddr, - int iptos); #endif diff --git a/src/network/slirp/udp6.c b/src/network/slirp/udp6.c new file mode 100644 index 000000000..6f9486bbc --- /dev/null +++ b/src/network/slirp/udp6.c @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2013 + * Guillaume Subiron + */ + +#include "slirp.h" +#include "udp.h" +#include "dhcpv6.h" + +void udp6_input(struct mbuf *m) +{ + Slirp *slirp = m->slirp; + struct ip6 *ip, save_ip; + struct udphdr *uh; + int iphlen = sizeof(struct ip6); + int len; + struct socket *so; + struct sockaddr_in6 lhost; + + DEBUG_CALL("udp6_input"); + DEBUG_ARG("m = %p", m); + + if (slirp->restricted) { + goto bad; + } + + ip = mtod(m, struct ip6 *); + m->m_len -= iphlen; + m->m_data += iphlen; + uh = mtod(m, struct udphdr *); + m->m_len += iphlen; + m->m_data -= iphlen; + + if (ip6_cksum(m)) { + goto bad; + } + + len = ntohs((uint16_t)uh->uh_ulen); + + /* + * Make mbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + if (ntohs(ip->ip_pl) != len) { + if (len > ntohs(ip->ip_pl)) { + goto bad; + } + m_adj(m, len - ntohs(ip->ip_pl)); + ip->ip_pl = htons(len); + } + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + + /* Locate pcb for datagram. */ + lhost.sin6_family = AF_INET6; + lhost.sin6_addr = ip->ip_src; + lhost.sin6_port = uh->uh_sport; + + /* handle DHCPv6 */ + if (ntohs(uh->uh_dport) == DHCPV6_SERVER_PORT && + (in6_equal(&ip->ip_dst, &slirp->vhost_addr6) || + in6_dhcp_multicast(&ip->ip_dst))) { + m->m_data += iphlen; + m->m_len -= iphlen; + dhcpv6_input(&lhost, m); + m->m_data -= iphlen; + m->m_len += iphlen; + goto bad; + } + + /* handle TFTP */ + if (ntohs(uh->uh_dport) == TFTP_SERVER && + !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) { + m->m_data += iphlen; + m->m_len -= iphlen; + tftp_input((struct sockaddr_storage *)&lhost, m); + m->m_data -= iphlen; + m->m_len += iphlen; + goto bad; + } + + so = solookup(&slirp->udp_last_so, &slirp->udb, + (struct sockaddr_storage *)&lhost, NULL); + + if (so == NULL) { + /* If there's no socket for this packet, create one. */ + so = socreate(slirp); + if (udp_attach(so, AF_INET6) == -1) { + DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno)); + sofree(so); + goto bad; + } + + /* Setup fields */ + so->so_lfamily = AF_INET6; + so->so_laddr6 = ip->ip_src; + so->so_lport6 = uh->uh_sport; + } + + so->so_ffamily = AF_INET6; + so->so_faddr6 = ip->ip_dst; /* XXX */ + so->so_fport6 = uh->uh_dport; /* XXX */ + + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_data += iphlen; + + /* + * Now we sendto() the packet. + */ + if (sosendto(so, m) == -1) { + m->m_len += iphlen; + m->m_data -= iphlen; + *ip = save_ip; + DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno)); + icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE); + goto bad; + } + + m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ + + /* restore the orig mbuf packet */ + m->m_len += iphlen; + m->m_data -= iphlen; + *ip = save_ip; + so->so_m = m; + + return; +bad: + m_free(m); +} + +int udp6_output(struct socket *so, struct mbuf *m, struct sockaddr_in6 *saddr, + struct sockaddr_in6 *daddr) +{ + struct ip6 *ip; + struct udphdr *uh; + + DEBUG_CALL("udp6_output"); + DEBUG_ARG("so = %p", so); + DEBUG_ARG("m = %p", m); + + /* adjust for header */ + m->m_data -= sizeof(struct udphdr); + m->m_len += sizeof(struct udphdr); + uh = mtod(m, struct udphdr *); + m->m_data -= sizeof(struct ip6); + m->m_len += sizeof(struct ip6); + ip = mtod(m, struct ip6 *); + + /* Build IP header */ + ip->ip_pl = htons(m->m_len - sizeof(struct ip6)); + ip->ip_nh = IPPROTO_UDP; + ip->ip_src = saddr->sin6_addr; + ip->ip_dst = daddr->sin6_addr; + + /* Build UDP header */ + uh->uh_sport = saddr->sin6_port; + uh->uh_dport = daddr->sin6_port; + uh->uh_ulen = ip->ip_pl; + uh->uh_sum = 0; + uh->uh_sum = ip6_cksum(m); + if (uh->uh_sum == 0) { + uh->uh_sum = 0xffff; + } + + return ip6_output(so, m, 0); +} diff --git a/src/network/slirp/util.c b/src/network/slirp/util.c new file mode 100644 index 000000000..8478c48d6 --- /dev/null +++ b/src/network/slirp/util.c @@ -0,0 +1,429 @@ +/* SPDX-License-Identifier: MIT */ +/* + * util.c (mostly based on QEMU os-win32.c) + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2010-2016 Red Hat, Inc. + * + * QEMU library functions for win32 which are shared between QEMU and + * the QEMU tools. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "util.h" + +#include +#include +#include +#include + +#if defined(_WIN32) +int slirp_inet_aton(const char *cp, struct in_addr *ia) +{ + uint32_t addr = inet_addr(cp); + if (addr == 0xffffffff) { + return 0; + } + ia->s_addr = addr; + return 1; +} +#endif + +void slirp_set_nonblock(int fd) +{ +#ifndef _WIN32 + int f; + f = fcntl(fd, F_GETFL); + assert(f != -1); + f = fcntl(fd, F_SETFL, f | O_NONBLOCK); + assert(f != -1); +#else + unsigned long opt = 1; + ioctlsocket(fd, FIONBIO, &opt); +#endif +} + +static void slirp_set_cloexec(int fd) +{ +#ifndef _WIN32 + int f; + f = fcntl(fd, F_GETFD); + assert(f != -1); + f = fcntl(fd, F_SETFD, f | FD_CLOEXEC); + assert(f != -1); +#endif +} + +/* + * Opens a socket with FD_CLOEXEC set + */ +int slirp_socket(int domain, int type, int protocol) +{ + int ret; + +#ifdef SOCK_CLOEXEC + ret = socket(domain, type | SOCK_CLOEXEC, protocol); + if (ret != -1 || errno != EINVAL) { + return ret; + } +#endif + ret = socket(domain, type, protocol); + if (ret >= 0) { + slirp_set_cloexec(ret); + } + + return ret; +} + +#ifdef _WIN32 +static int socket_error(void) +{ + switch (WSAGetLastError()) { + case 0: + return 0; + case WSAEINTR: + return EINTR; + case WSAEINVAL: + return EINVAL; + case WSA_INVALID_HANDLE: + return EBADF; + case WSA_NOT_ENOUGH_MEMORY: + return ENOMEM; + case WSA_INVALID_PARAMETER: + return EINVAL; + case WSAENAMETOOLONG: + return ENAMETOOLONG; + case WSAENOTEMPTY: + return ENOTEMPTY; + case WSAEWOULDBLOCK: + /* not using EWOULDBLOCK as we don't want code to have + * to check both EWOULDBLOCK and EAGAIN */ + return EAGAIN; + case WSAEINPROGRESS: + return EINPROGRESS; + case WSAEALREADY: + return EALREADY; + case WSAENOTSOCK: + return ENOTSOCK; + case WSAEDESTADDRREQ: + return EDESTADDRREQ; + case WSAEMSGSIZE: + return EMSGSIZE; + case WSAEPROTOTYPE: + return EPROTOTYPE; + case WSAENOPROTOOPT: + return ENOPROTOOPT; + case WSAEPROTONOSUPPORT: + return EPROTONOSUPPORT; + case WSAEOPNOTSUPP: + return EOPNOTSUPP; + case WSAEAFNOSUPPORT: + return EAFNOSUPPORT; + case WSAEADDRINUSE: + return EADDRINUSE; + case WSAEADDRNOTAVAIL: + return EADDRNOTAVAIL; + case WSAENETDOWN: + return ENETDOWN; + case WSAENETUNREACH: + return ENETUNREACH; + case WSAENETRESET: + return ENETRESET; + case WSAECONNABORTED: + return ECONNABORTED; + case WSAECONNRESET: + return ECONNRESET; + case WSAENOBUFS: + return ENOBUFS; + case WSAEISCONN: + return EISCONN; + case WSAENOTCONN: + return ENOTCONN; + case WSAETIMEDOUT: + return ETIMEDOUT; + case WSAECONNREFUSED: + return ECONNREFUSED; + case WSAELOOP: + return ELOOP; + case WSAEHOSTUNREACH: + return EHOSTUNREACH; + default: + return EIO; + } +} + +#undef ioctlsocket +int slirp_ioctlsocket_wrap(int fd, int req, void *val) +{ + int ret; + ret = ioctlsocket(fd, req, val); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef closesocket +int slirp_closesocket_wrap(int fd) +{ + int ret; + ret = closesocket(fd); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef connect +int slirp_connect_wrap(int sockfd, const struct sockaddr *addr, int addrlen) +{ + int ret; + ret = connect(sockfd, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef listen +int slirp_listen_wrap(int sockfd, int backlog) +{ + int ret; + ret = listen(sockfd, backlog); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef bind +int slirp_bind_wrap(int sockfd, const struct sockaddr *addr, int addrlen) +{ + int ret; + ret = bind(sockfd, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef socket +int slirp_socket_wrap(int domain, int type, int protocol) +{ + int ret; + ret = socket(domain, type, protocol); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef accept +int slirp_accept_wrap(int sockfd, struct sockaddr *addr, int *addrlen) +{ + int ret; + ret = accept(sockfd, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef shutdown +int slirp_shutdown_wrap(int sockfd, int how) +{ + int ret; + ret = shutdown(sockfd, how); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef getsockopt +int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval, + int *optlen) +{ + int ret; + ret = getsockopt(sockfd, level, optname, optval, optlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef setsockopt +int slirp_setsockopt_wrap(int sockfd, int level, int optname, + const void *optval, int optlen) +{ + int ret; + ret = setsockopt(sockfd, level, optname, optval, optlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef getpeername +int slirp_getpeername_wrap(int sockfd, struct sockaddr *addr, int *addrlen) +{ + int ret; + ret = getpeername(sockfd, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef getsockname +int slirp_getsockname_wrap(int sockfd, struct sockaddr *addr, int *addrlen) +{ + int ret; + ret = getsockname(sockfd, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef send +ssize_t slirp_send_wrap(int sockfd, const void *buf, size_t len, int flags) +{ + int ret; + ret = send(sockfd, buf, len, flags); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef sendto +ssize_t slirp_sendto_wrap(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *addr, int addrlen) +{ + int ret; + ret = sendto(sockfd, buf, len, flags, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef recv +ssize_t slirp_recv_wrap(int sockfd, void *buf, size_t len, int flags) +{ + int ret; + ret = recv(sockfd, buf, len, flags); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} + +#undef recvfrom +ssize_t slirp_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *addr, int *addrlen) +{ + int ret; + ret = recvfrom(sockfd, buf, len, flags, addr, addrlen); + if (ret < 0) { + errno = socket_error(); + } + return ret; +} +#endif /* WIN32 */ + +void slirp_pstrcpy(char *buf, int buf_size, const char *str) +{ + int c; + char *q = buf; + + if (buf_size <= 0) + return; + + for (;;) { + c = *str++; + if (c == 0 || q >= buf + buf_size - 1) + break; + *q++ = c; + } + *q = '\0'; +} + +static int slirp_vsnprintf(char *str, size_t size, + const char *format, va_list args) +{ + int rv = g_vsnprintf(str, size, format, args); + + if (rv < 0) { + g_error("g_vsnprintf() failed: %s", g_strerror(errno)); + } + + return rv; +} + +/* + * A snprintf()-like function that: + * - returns the number of bytes written (excluding optional \0-ending) + * - dies on error + * - warn on truncation + */ +int slirp_fmt(char *str, size_t size, const char *format, ...) +{ + va_list args; + int rv; + + va_start(args, format); + rv = slirp_vsnprintf(str, size, format, args); + va_end(args); + + if (rv >= size) { + g_critical("slirp_fmt() truncation"); + } + + return MIN(rv, size); +} + +/* + * A snprintf()-like function that: + * - always \0-end (unless size == 0) + * - returns the number of bytes actually written, including \0 ending + * - dies on error + * - warn on truncation + */ +int slirp_fmt0(char *str, size_t size, const char *format, ...) +{ + va_list args; + int rv; + + va_start(args, format); + rv = slirp_vsnprintf(str, size, format, args); + va_end(args); + + if (rv >= size) { + g_critical("slirp_fmt0() truncation"); + if (size > 0) + str[size - 1] = '\0'; + rv = size; + } else { + rv += 1; /* include \0 */ + } + + return rv; +} diff --git a/src/network/slirp/util.h b/src/network/slirp/util.h new file mode 100644 index 000000000..951bfc57d --- /dev/null +++ b/src/network/slirp/util.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2010-2019 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef UTIL_H_ +#define UTIL_H_ + +#include + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define SLIRP_PACKED +#elif defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) && !defined(__clang__) +#define SLIRP_PACKED __attribute__((gcc_struct, packed)) +#else +#define SLIRP_PACKED __attribute__((packed)) +#endif + +#ifndef DIV_ROUND_UP +#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d)) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member))); +#endif + +#ifndef G_SIZEOF_MEMBER +#define G_SIZEOF_MEMBER(type, member) sizeof(((type *)0)->member) +#endif + +#if defined(_WIN32) /* CONFIG_IOVEC */ +#if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */ +struct iovec { + void *iov_base; + size_t iov_len; +}; +#endif +#else +#include +#endif + +#define stringify(s) tostring(s) +#define tostring(s) #s + +#define SCALE_MS 1000000 + +#define ETH_ALEN 6 +#define ETH_HLEN 14 +#define ETH_P_IP (0x0800) /* Internet Protocol packet */ +#define ETH_P_ARP (0x0806) /* Address Resolution packet */ +#define ETH_P_IPV6 (0x86dd) +#define ETH_P_VLAN (0x8100) +#define ETH_P_DVLAN (0x88a8) +#define ETH_P_NCSI (0x88f8) +#define ETH_P_UNKNOWN (0xffff) + +/* FIXME: remove me when made standalone */ +#ifdef _WIN32 +#undef accept +#undef bind +#undef closesocket +#undef connect +#undef getpeername +#undef getsockname +#undef getsockopt +#undef ioctlsocket +#undef listen +#undef recv +#undef recvfrom +#undef send +#undef sendto +#undef setsockopt +#undef shutdown +#undef socket +#endif + +#ifdef _WIN32 +#define connect slirp_connect_wrap +int slirp_connect_wrap(int fd, const struct sockaddr *addr, int addrlen); +#define listen slirp_listen_wrap +int slirp_listen_wrap(int fd, int backlog); +#define bind slirp_bind_wrap +int slirp_bind_wrap(int fd, const struct sockaddr *addr, int addrlen); +#define socket slirp_socket_wrap +int slirp_socket_wrap(int domain, int type, int protocol); +#define accept slirp_accept_wrap +int slirp_accept_wrap(int fd, struct sockaddr *addr, int *addrlen); +#define shutdown slirp_shutdown_wrap +int slirp_shutdown_wrap(int fd, int how); +#define getpeername slirp_getpeername_wrap +int slirp_getpeername_wrap(int fd, struct sockaddr *addr, int *addrlen); +#define getsockname slirp_getsockname_wrap +int slirp_getsockname_wrap(int fd, struct sockaddr *addr, int *addrlen); +#define send slirp_send_wrap +ssize_t slirp_send_wrap(int fd, const void *buf, size_t len, int flags); +#define sendto slirp_sendto_wrap +ssize_t slirp_sendto_wrap(int fd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, int addrlen); +#define recv slirp_recv_wrap +ssize_t slirp_recv_wrap(int fd, void *buf, size_t len, int flags); +#define recvfrom slirp_recvfrom_wrap +ssize_t slirp_recvfrom_wrap(int fd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, int *addrlen); +#define closesocket slirp_closesocket_wrap +int slirp_closesocket_wrap(int fd); +#define ioctlsocket slirp_ioctlsocket_wrap +int slirp_ioctlsocket_wrap(int fd, int req, void *val); +#define getsockopt slirp_getsockopt_wrap +int slirp_getsockopt_wrap(int sockfd, int level, int optname, void *optval, + int *optlen); +#define setsockopt slirp_setsockopt_wrap +int slirp_setsockopt_wrap(int sockfd, int level, int optname, + const void *optval, int optlen); +#define inet_aton slirp_inet_aton +int slirp_inet_aton(const char *cp, struct in_addr *ia); +#else +#define closesocket(s) close(s) +#define ioctlsocket(s, r, v) ioctl(s, r, v) +#endif + +int slirp_socket(int domain, int type, int protocol); +void slirp_set_nonblock(int fd); + +static inline int slirp_socket_set_nodelay(int fd) +{ + int v = 1; + return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); +} + +static inline int slirp_socket_set_fast_reuse(int fd) +{ +#ifndef _WIN32 + int v = 1; + return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); +#else + /* Enabling the reuse of an endpoint that was used by a socket still in + * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows + * fast reuse is the default and SO_REUSEADDR does strange things. So we + * don't have to do anything here. More info can be found at: + * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */ + return 0; +#endif +} + +void slirp_pstrcpy(char *buf, int buf_size, const char *str); + +int slirp_fmt(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4); +int slirp_fmt0(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4); + +#endif diff --git a/src/network/slirp/version.c b/src/network/slirp/version.c new file mode 100644 index 000000000..93e0be9c2 --- /dev/null +++ b/src/network/slirp/version.c @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include "libslirp.h" + +const char * +slirp_version_string(void) +{ + return SLIRP_VERSION_STRING; +} diff --git a/src/network/slirp/vmstate.c b/src/network/slirp/vmstate.c new file mode 100644 index 000000000..b9926ea41 --- /dev/null +++ b/src/network/slirp/vmstate.c @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * VMState interpreter + * + * Copyright (c) 2009-2018 Red Hat Inc + * + * Authors: + * Juan Quintela + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#include "stream.h" +#include "vmstate.h" + +static int get_nullptr(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) { + return 0; + } + g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER"); + return -EINVAL; +} + +static int put_nullptr(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) + +{ + if (pv == NULL) { + slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER); + return 0; + } + g_warning("vmstate: put_nullptr must be called with pv == NULL"); + return -EINVAL; +} + +const VMStateInfo slirp_vmstate_info_nullptr = { + .name = "uint64", + .get = get_nullptr, + .put = put_nullptr, +}; + +/* 8 bit unsigned int */ + +static int get_uint8(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint8_t *v = pv; + *v = slirp_istream_read_u8(f); + return 0; +} + +static int put_uint8(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint8_t *v = pv; + slirp_ostream_write_u8(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_uint8 = { + .name = "uint8", + .get = get_uint8, + .put = put_uint8, +}; + +/* 16 bit unsigned int */ + +static int get_uint16(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint16_t *v = pv; + *v = slirp_istream_read_u16(f); + return 0; +} + +static int put_uint16(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint16_t *v = pv; + slirp_ostream_write_u16(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_uint16 = { + .name = "uint16", + .get = get_uint16, + .put = put_uint16, +}; + +/* 32 bit unsigned int */ + +static int get_uint32(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint32_t *v = pv; + *v = slirp_istream_read_u32(f); + return 0; +} + +static int put_uint32(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint32_t *v = pv; + slirp_ostream_write_u32(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_uint32 = { + .name = "uint32", + .get = get_uint32, + .put = put_uint32, +}; + +/* 16 bit int */ + +static int get_int16(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + int16_t *v = pv; + *v = slirp_istream_read_i16(f); + return 0; +} + +static int put_int16(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + int16_t *v = pv; + slirp_ostream_write_i16(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_int16 = { + .name = "int16", + .get = get_int16, + .put = put_int16, +}; + +/* 32 bit int */ + +static int get_int32(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + int32_t *v = pv; + *v = slirp_istream_read_i32(f); + return 0; +} + +static int put_int32(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + int32_t *v = pv; + slirp_ostream_write_i32(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_int32 = { + .name = "int32", + .get = get_int32, + .put = put_int32, +}; + +/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate + * a temporary buffer and the pre_load/pre_save methods in the child vmsd + * copy stuff from the parent into the child and do calculations to fill + * in fields that don't really exist in the parent but need to be in the + * stream. + */ +static int get_tmp(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + int ret; + const VMStateDescription *vmsd = field->vmsd; + int version_id = field->version_id; + void *tmp = g_malloc(size); + + /* Writes the parent field which is at the start of the tmp */ + *(void **)tmp = pv; + ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id); + g_free(tmp); + return ret; +} + +static int put_tmp(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + const VMStateDescription *vmsd = field->vmsd; + void *tmp = g_malloc(size); + int ret; + + /* Writes the parent field which is at the start of the tmp */ + *(void **)tmp = pv; + ret = slirp_vmstate_save_state(f, vmsd, tmp); + g_free(tmp); + + return ret; +} + +const VMStateInfo slirp_vmstate_info_tmp = { + .name = "tmp", + .get = get_tmp, + .put = put_tmp, +}; + +/* uint8_t buffers */ + +static int get_buffer(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + slirp_istream_read(f, pv, size); + return 0; +} + +static int put_buffer(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + slirp_ostream_write(f, pv, size); + return 0; +} + +const VMStateInfo slirp_vmstate_info_buffer = { + .name = "buffer", + .get = get_buffer, + .put = put_buffer, +}; + +static int vmstate_n_elems(void *opaque, const VMStateField *field) +{ + int n_elems = 1; + + if (field->flags & VMS_ARRAY) { + n_elems = field->num; + } else if (field->flags & VMS_VARRAY_INT32) { + n_elems = *(int32_t *)(opaque + field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT32) { + n_elems = *(uint32_t *)(opaque + field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT16) { + n_elems = *(uint16_t *)(opaque + field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT8) { + n_elems = *(uint8_t *)(opaque + field->num_offset); + } + + if (field->flags & VMS_MULTIPLY_ELEMENTS) { + n_elems *= field->num; + } + + return n_elems; +} + +static int vmstate_size(void *opaque, const VMStateField *field) +{ + int size = field->size; + + if (field->flags & VMS_VBUFFER) { + size = *(int32_t *)(opaque + field->size_offset); + if (field->flags & VMS_MULTIPLY) { + size *= field->size; + } + } + + return size; +} + +static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd, + void *opaque, int version_id) +{ + int ret = 0; + const VMStateField *field = vmsd->fields; + + if (vmsd->pre_save) { + ret = vmsd->pre_save(opaque); + if (ret) { + g_warning("pre-save failed: %s", vmsd->name); + return ret; + } + } + + while (field->name) { + if ((field->field_exists && field->field_exists(opaque, version_id)) || + (!field->field_exists && field->version_id <= version_id)) { + void *first_elem = opaque + field->offset; + int i, n_elems = vmstate_n_elems(opaque, field); + int size = vmstate_size(opaque, field); + + if (field->flags & VMS_POINTER) { + first_elem = *(void **)first_elem; + assert(first_elem || !n_elems || !size); + } + for (i = 0; i < n_elems; i++) { + void *curr_elem = first_elem + size * i; + + if (field->flags & VMS_ARRAY_OF_POINTER) { + assert(curr_elem); + curr_elem = *(void **)curr_elem; + } + if (!curr_elem && size) { + /* if null pointer write placeholder and do not follow */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size, + NULL); + } else if (field->flags & VMS_STRUCT) { + ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem); + } else if (field->flags & VMS_VSTRUCT) { + ret = vmstate_save_state_v(f, field->vmsd, curr_elem, + field->struct_version_id); + } else { + ret = field->info->put(f, curr_elem, size, field); + } + if (ret) { + g_warning("Save of field %s/%s failed", vmsd->name, + field->name); + return ret; + } + } + } else { + if (field->flags & VMS_MUST_EXIST) { + g_warning("Output state validation failed: %s/%s", vmsd->name, + field->name); + assert(!(field->flags & VMS_MUST_EXIST)); + } + } + field++; + } + + return 0; +} + +int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd, + void *opaque) +{ + return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id); +} + +static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque) +{ + if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) { + size_t size = vmstate_size(opaque, field); + size *= vmstate_n_elems(opaque, field); + if (size) { + *(void **)ptr = g_malloc(size); + } + } +} + +int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd, + void *opaque, int version_id) +{ + VMStateField *field = vmsd->fields; + int ret = 0; + + if (version_id > vmsd->version_id) { + g_warning("%s: incoming version_id %d is too new " + "for local version_id %d", + vmsd->name, version_id, vmsd->version_id); + return -EINVAL; + } + if (vmsd->pre_load) { + int ret = vmsd->pre_load(opaque); + if (ret) { + return ret; + } + } + while (field->name) { + if ((field->field_exists && field->field_exists(opaque, version_id)) || + (!field->field_exists && field->version_id <= version_id)) { + void *first_elem = opaque + field->offset; + int i, n_elems = vmstate_n_elems(opaque, field); + int size = vmstate_size(opaque, field); + + vmstate_handle_alloc(first_elem, field, opaque); + if (field->flags & VMS_POINTER) { + first_elem = *(void **)first_elem; + assert(first_elem || !n_elems || !size); + } + for (i = 0; i < n_elems; i++) { + void *curr_elem = first_elem + size * i; + + if (field->flags & VMS_ARRAY_OF_POINTER) { + curr_elem = *(void **)curr_elem; + } + if (!curr_elem && size) { + /* if null pointer check placeholder and do not follow */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size, + NULL); + } else if (field->flags & VMS_STRUCT) { + ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem, + field->vmsd->version_id); + } else if (field->flags & VMS_VSTRUCT) { + ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem, + field->struct_version_id); + } else { + ret = field->info->get(f, curr_elem, size, field); + } + if (ret < 0) { + g_warning("Failed to load %s:%s", vmsd->name, field->name); + return ret; + } + } + } else if (field->flags & VMS_MUST_EXIST) { + g_warning("Input validation failed: %s/%s", vmsd->name, + field->name); + return -1; + } + field++; + } + if (vmsd->post_load) { + ret = vmsd->post_load(opaque, version_id); + } + return ret; +} diff --git a/src/network/slirp/vmstate.h b/src/network/slirp/vmstate.h new file mode 100644 index 000000000..e6bed53a6 --- /dev/null +++ b/src/network/slirp/vmstate.h @@ -0,0 +1,393 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * QEMU migration/snapshot declarations + * + * Copyright (c) 2009-2011 Red Hat, Inc. + * + * Original author: Juan Quintela + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef VMSTATE_H_ +#define VMSTATE_H_ + +#ifndef _WIN32 +#include +#endif +#include +#include +#include "slirp.h" +#include "stream.h" + +#define stringify(s) tostring(s) +#define tostring(s) #s + +typedef struct VMStateInfo VMStateInfo; +typedef struct VMStateDescription VMStateDescription; +typedef struct VMStateField VMStateField; + +int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd, + void *opaque); +int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd, + void *opaque, int version_id); + +/* VMStateInfo allows customized migration of objects that don't fit in + * any category in VMStateFlags. Additional information is always passed + * into get and put in terms of field and vmdesc parameters. However + * these two parameters should only be used in cases when customized + * handling is needed, such as QTAILQ. For primitive data types such as + * integer, field and vmdesc parameters should be ignored inside get/put. + */ +struct VMStateInfo { + const char *name; + int (*get)(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field); + int (*put)(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field); +}; + +enum VMStateFlags { + /* Ignored */ + VMS_SINGLE = 0x001, + + /* The struct member at opaque + VMStateField.offset is a pointer + * to the actual field (e.g. struct a { uint8_t *b; + * }). Dereference the pointer before using it as basis for + * further pointer arithmetic (see e.g. VMS_ARRAY). Does not + * affect the meaning of VMStateField.num_offset or + * VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for + * those. */ + VMS_POINTER = 0x002, + + /* The field is an array of fixed size. VMStateField.num contains + * the number of entries in the array. The size of each entry is + * given by VMStateField.size and / or opaque + + * VMStateField.size_offset; see VMS_VBUFFER and + * VMS_MULTIPLY. Each array entry will be processed individually + * (VMStateField.info.get()/put() if VMS_STRUCT is not set, + * recursion into VMStateField.vmsd if VMS_STRUCT is set). May not + * be combined with VMS_VARRAY*. */ + VMS_ARRAY = 0x004, + + /* The field is itself a struct, containing one or more + * fields. Recurse into VMStateField.vmsd. Most useful in + * combination with VMS_ARRAY / VMS_VARRAY*, recursing into each + * array entry. */ + VMS_STRUCT = 0x008, + + /* The field is an array of variable size. The int32_t at opaque + + * VMStateField.num_offset contains the number of entries in the + * array. See the VMS_ARRAY description regarding array handling + * in general. May not be combined with VMS_ARRAY or any other + * VMS_VARRAY*. */ + VMS_VARRAY_INT32 = 0x010, + + /* Ignored */ + VMS_BUFFER = 0x020, + + /* The field is a (fixed-size or variable-size) array of pointers + * (e.g. struct a { uint8_t *b[]; }). Dereference each array entry + * before using it. Note: Does not imply any one of VMS_ARRAY / + * VMS_VARRAY*; these need to be set explicitly. */ + VMS_ARRAY_OF_POINTER = 0x040, + + /* The field is an array of variable size. The uint16_t at opaque + * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * contains the number of entries in the array. See the VMS_ARRAY + * description regarding array handling in general. May not be + * combined with VMS_ARRAY or any other VMS_VARRAY*. */ + VMS_VARRAY_UINT16 = 0x080, + + /* The size of the individual entries (a single array entry if + * VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if + * neither is set) is variable (i.e. not known at compile-time), + * but the same for all entries. Use the int32_t at opaque + + * VMStateField.size_offset (subject to VMS_MULTIPLY) to determine + * the size of each (and every) entry. */ + VMS_VBUFFER = 0x100, + + /* Multiply the entry size given by the int32_t at opaque + + * VMStateField.size_offset (see VMS_VBUFFER description) with + * VMStateField.size to determine the number of bytes to be + * allocated. Only valid in combination with VMS_VBUFFER. */ + VMS_MULTIPLY = 0x200, + + /* The field is an array of variable size. The uint8_t at opaque + + * VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * contains the number of entries in the array. See the VMS_ARRAY + * description regarding array handling in general. May not be + * combined with VMS_ARRAY or any other VMS_VARRAY*. */ + VMS_VARRAY_UINT8 = 0x400, + + /* The field is an array of variable size. The uint32_t at opaque + * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * contains the number of entries in the array. See the VMS_ARRAY + * description regarding array handling in general. May not be + * combined with VMS_ARRAY or any other VMS_VARRAY*. */ + VMS_VARRAY_UINT32 = 0x800, + + /* Fail loading the serialised VM state if this field is missing + * from the input. */ + VMS_MUST_EXIST = 0x1000, + + /* When loading serialised VM state, allocate memory for the + * (entire) field. Only valid in combination with + * VMS_POINTER. Note: Not all combinations with other flags are + * currently supported, e.g. VMS_ALLOC|VMS_ARRAY_OF_POINTER won't + * cause the individual entries to be allocated. */ + VMS_ALLOC = 0x2000, + + /* Multiply the number of entries given by the integer at opaque + + * VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num + * to determine the number of entries in the array. Only valid in + * combination with one of VMS_VARRAY*. */ + VMS_MULTIPLY_ELEMENTS = 0x4000, + + /* A structure field that is like VMS_STRUCT, but uses + * VMStateField.struct_version_id to tell which version of the + * structure we are referencing to use. */ + VMS_VSTRUCT = 0x8000, +}; + +struct VMStateField { + const char *name; + size_t offset; + size_t size; + size_t start; + int num; + size_t num_offset; + size_t size_offset; + const VMStateInfo *info; + enum VMStateFlags flags; + const VMStateDescription *vmsd; + int version_id; + int struct_version_id; + bool (*field_exists)(void *opaque, int version_id); +}; + +struct VMStateDescription { + const char *name; + int version_id; + int (*pre_load)(void *opaque); + int (*post_load)(void *opaque, int version_id); + int (*pre_save)(void *opaque); + VMStateField *fields; +}; + + +extern const VMStateInfo slirp_vmstate_info_int16; +extern const VMStateInfo slirp_vmstate_info_int32; +extern const VMStateInfo slirp_vmstate_info_uint8; +extern const VMStateInfo slirp_vmstate_info_uint16; +extern const VMStateInfo slirp_vmstate_info_uint32; + +/** Put this in the stream when migrating a null pointer.*/ +#define VMS_NULLPTR_MARKER (0x30U) /* '0' */ +extern const VMStateInfo slirp_vmstate_info_nullptr; + +extern const VMStateInfo slirp_vmstate_info_buffer; +extern const VMStateInfo slirp_vmstate_info_tmp; + +#define type_check_array(t1, t2, n) ((t1(*)[n])0 - (t2 *)0) +#define type_check_pointer(t1, t2) ((t1 **)0 - (t2 *)0) +#define typeof_field(type, field) typeof(((type *)0)->field) +#define type_check(t1, t2) ((t1 *)0 - (t2 *)0) + +#define vmstate_offset_value(_state, _field, _type) \ + (offsetof(_state, _field) + type_check(_type, typeof_field(_state, _field))) + +#define vmstate_offset_pointer(_state, _field, _type) \ + (offsetof(_state, _field) + \ + type_check_pointer(_type, typeof_field(_state, _field))) + +#define vmstate_offset_array(_state, _field, _type, _num) \ + (offsetof(_state, _field) + \ + type_check_array(_type, typeof_field(_state, _field), _num)) + +#define vmstate_offset_buffer(_state, _field) \ + vmstate_offset_array(_state, _field, uint8_t, \ + sizeof(typeof_field(_state, _field))) + +/* In the macros below, if there is a _version, that means the macro's + * field will be processed only if the version being received is >= + * the _version specified. In general, if you add a new field, you + * would increment the structure's version and put that version + * number into the new field so it would only be processed with the + * new version. + * + * In particular, for VMSTATE_STRUCT() and friends the _version does + * *NOT* pick the version of the sub-structure. It works just as + * specified above. The version of the top-level structure received + * is passed down to all sub-structures. This means that the + * sub-structures must have version that are compatible with all the + * structures that use them. + * + * If you want to specify the version of the sub-structure, use + * VMSTATE_VSTRUCT(), which allows the specific sub-structure version + * to be directly specified. + */ + +#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) \ + { \ + .name = (stringify(_field)), .version_id = (_version), \ + .field_exists = (_test), .size = sizeof(_type), .info = &(_info), \ + .flags = VMS_SINGLE, \ + .offset = vmstate_offset_value(_state, _field, _type), \ + } + +#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) \ + { \ + .name = (stringify(_field)), .version_id = (_version), .num = (_num), \ + .info = &(_info), .size = sizeof(_type), .flags = VMS_ARRAY, \ + .offset = vmstate_offset_array(_state, _field, _type, _num), \ + } + +#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) \ + { \ + .name = (stringify(_field)), .version_id = (_version), \ + .field_exists = (_test), .vmsd = &(_vmsd), .size = sizeof(_type), \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, _type), \ + } + +#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) \ + { \ + .name = (stringify(_field)), .version_id = (_version), \ + .vmsd = &(_vmsd), .size = sizeof(_type *), \ + .flags = VMS_STRUCT | VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, _type), \ + } + +#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, \ + _vmsd, _type) \ + { \ + .name = (stringify(_field)), .num = (_num), .field_exists = (_test), \ + .version_id = (_version), .vmsd = &(_vmsd), .size = sizeof(_type), \ + .flags = VMS_STRUCT | VMS_ARRAY, \ + .offset = vmstate_offset_array(_state, _field, _type, _num), \ + } + +#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) \ + { \ + .name = (stringify(_field)), .version_id = (_version), \ + .field_exists = (_test), .size = (_size - _start), \ + .info = &slirp_vmstate_info_buffer, .flags = VMS_BUFFER, \ + .offset = vmstate_offset_buffer(_state, _field) + _start, \ + } + +#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) \ + { \ + .name = (stringify(_field)), .version_id = (_version), \ + .field_exists = (_test), \ + .size_offset = vmstate_offset_value(_state, _field_size, uint32_t), \ + .info = &slirp_vmstate_info_buffer, \ + .flags = VMS_VBUFFER | VMS_POINTER, \ + .offset = offsetof(_state, _field), \ + } + +#define QEMU_BUILD_BUG_ON_STRUCT(x) \ + struct { \ + int : (x) ? -1 : 1; \ + } + +#define QEMU_BUILD_BUG_ON_ZERO(x) \ + (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - sizeof(QEMU_BUILD_BUG_ON_STRUCT(x))) + +/* Allocate a temporary of type 'tmp_type', set tmp->parent to _state + * and execute the vmsd on the temporary. Note that we're working with + * the whole of _state here, not a field within it. + * We compile time check that: + * That _tmp_type contains a 'parent' member that's a pointer to the + * '_state' type + * That the pointer is right at the start of _tmp_type. + */ +#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) \ + { \ + .name = "tmp", \ + .size = sizeof(_tmp_type) + \ + QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \ + type_check_pointer(_state, typeof_field(_tmp_type, parent)), \ + .vmsd = &(_vmsd), .info = &slirp_vmstate_info_tmp, \ + } + +#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \ + VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type) + +#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \ + VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type) + +#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \ + VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type) + +#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \ + VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, _vmsd, \ + _type) + +#define VMSTATE_INT16_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int16, int16_t) +#define VMSTATE_INT32_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int32, int32_t) + +#define VMSTATE_UINT8_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint8, uint8_t) +#define VMSTATE_UINT16_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint16, uint16_t) +#define VMSTATE_UINT32_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint32, uint32_t) + +#define VMSTATE_INT16(_f, _s) VMSTATE_INT16_V(_f, _s, 0) +#define VMSTATE_INT32(_f, _s) VMSTATE_INT32_V(_f, _s, 0) + +#define VMSTATE_UINT8(_f, _s) VMSTATE_UINT8_V(_f, _s, 0) +#define VMSTATE_UINT16(_f, _s) VMSTATE_UINT16_V(_f, _s, 0) +#define VMSTATE_UINT32(_f, _s) VMSTATE_UINT32_V(_f, _s, 0) + +#define VMSTATE_UINT16_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint16, uint16_t) + +#define VMSTATE_UINT32_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint32, uint32_t) + +#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, slirp_vmstate_info_int16, int16_t) + +#define VMSTATE_INT16_ARRAY(_f, _s, _n) VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0) + +#define VMSTATE_BUFFER_V(_f, _s, _v) \ + VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f))) + +#define VMSTATE_BUFFER(_f, _s) VMSTATE_BUFFER_V(_f, _s, 0) + +#define VMSTATE_END_OF_LIST() \ + { \ + } + +#endif diff --git a/src/nmi.c b/src/nmi.c index 07742cefe..1e820a82a 100644 --- a/src/nmi.c +++ b/src/nmi.c @@ -20,6 +20,6 @@ void nmi_write(uint16_t port, uint8_t val, void *p) void nmi_init(void) { - io_sethandler(0x00a0, 0x0001, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); + io_sethandler(0x00a0, 0x000f, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); nmi_mask = 0; } diff --git a/src/nvr.c b/src/nvr.c index c5752aacb..b73aa6fa7 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -1,4 +1,4 @@ -/* +/* * VARCem Virtual ARchaeological Computer EMulator. * An emulator of (mostly) x86-based PC systems and devices, * using the ISA,EISA,VLB,MCA and PCI system buses, roughly @@ -58,6 +58,7 @@ #include <86box/machine.h> #include <86box/mem.h> #include <86box/timer.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/nvr.h> @@ -143,10 +144,12 @@ static void onesec_timer(void *priv) { nvr_t *nvr = (nvr_t *)priv; + int is_at; if (++nvr->onesec_cnt >= 100) { /* Update the internal clock. */ - if (!(machines[machine].flags & MACHINE_AT)) + is_at = IS_AT(machine); + if (!is_at) rtc_tick(); /* Update the RTC device if needed. */ @@ -164,29 +167,17 @@ onesec_timer(void *priv) void nvr_init(nvr_t *nvr) { - char temp[64]; - struct tm *tm; - time_t now; int c; /* Set up the NVR file's name. */ - sprintf(temp, "%s.nvr", machine_get_internal_name()); - c = strlen(temp); - nvr->fn = (wchar_t *)malloc((c + 1) * sizeof(wchar_t)); - mbstowcs(nvr->fn, temp, c + 1); + c = strlen(machine_get_internal_name()) + 5; + nvr->fn = (char *)malloc(c + 1); + sprintf(nvr->fn, "%s.nvr", machine_get_internal_name()); /* Initialize the internal clock as needed. */ memset(&intclk, 0x00, sizeof(intclk)); if (time_sync & TIME_SYNC_ENABLED) { - /* Get the current time of day, and convert to local time. */ - (void)time(&now); - if(time_sync & TIME_SYNC_UTC) - tm = gmtime(&now); - else - tm = localtime(&now); - - /* Set the internal clock. */ - nvr_time_set(tm); + nvr_time_sync(); } else { /* Reset the internal clock to 1980/01/01 00:00. */ intclk.tm_mon = 1; @@ -208,23 +199,23 @@ nvr_init(nvr_t *nvr) /* Get path to the NVR folder. */ -wchar_t * -nvr_path(wchar_t *str) +char * +nvr_path(char *str) { - static wchar_t temp[1024]; + static char temp[1024]; /* Get the full prefix in place. */ memset(temp, 0x00, sizeof(temp)); - wcscpy(temp, usr_path); - wcscat(temp, NVR_PATH); + strcpy(temp, usr_path); + strcat(temp, NVR_PATH); /* Create the directory if needed. */ if (! plat_dir_check(temp)) plat_dir_create(temp); /* Now append the actual filename. */ - plat_path_slash(temp); - wcscat(temp, str); + path_slash(temp); + strcat(temp, str); return(temp); } @@ -244,7 +235,7 @@ nvr_path(wchar_t *str) int nvr_load(void) { - wchar_t *path; + char *path; FILE *fp; /* Make sure we have been initialized. */ @@ -260,15 +251,17 @@ nvr_load(void) /* Load the (relevant) part of the NVR contents. */ if (saved_nvr->size != 0) { path = nvr_path(saved_nvr->fn); - nvr_log("NVR: loading from '%ls'\n", path); - fp = plat_fopen(path, L"rb"); + nvr_log("NVR: loading from '%s'\n", path); + fp = plat_fopen(path, "rb"); + saved_nvr->is_new = (fp == NULL); if (fp != NULL) { /* Read NVR contents from file. */ if (fread(saved_nvr->regs, 1, saved_nvr->size, fp) != saved_nvr->size) fatal("nvr_load(): Error reading data\n"); (void)fclose(fp); } - } + } else + saved_nvr->is_new = 1; /* Get the local RTC running! */ if (saved_nvr->start != NULL) @@ -289,7 +282,7 @@ nvr_set_ven_save(void (*ven_save)(void)) int nvr_save(void) { - wchar_t *path; + char *path; FILE *fp; /* Make sure we have been initialized. */ @@ -297,8 +290,8 @@ nvr_save(void) if (saved_nvr->size != 0) { path = nvr_path(saved_nvr->fn); - nvr_log("NVR: saving to '%ls'\n", path); - fp = plat_fopen(path, L"wb"); + nvr_log("NVR: saving to '%s'\n", path); + fp = plat_fopen(path, "wb"); if (fp != NULL) { /* Save NVR contents to file. */ (void)fwrite(saved_nvr->regs, saved_nvr->size, 1, fp); @@ -323,6 +316,24 @@ nvr_close(void) } +void +nvr_time_sync(void) +{ + struct tm *tm; + time_t now; + + /* Get the current time of day, and convert to local time. */ + (void)time(&now); + if(time_sync & TIME_SYNC_UTC) + tm = gmtime(&now); + else + tm = localtime(&now); + + /* Set the internal clock. */ + nvr_time_set(tm); +} + + /* Get current time from internal clock. */ void nvr_time_get(struct tm *tm) @@ -362,7 +373,7 @@ nvr_time_set(struct tm *tm) /* Open or create a file in the NVR area. */ FILE * -nvr_fopen(wchar_t *str, wchar_t *mode) +nvr_fopen(char *str, char *mode) { return(plat_fopen(nvr_path(str), mode)); } diff --git a/src/nvr_at.c b/src/nvr_at.c index c07bf4372..b40bd2949 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -149,7 +149,7 @@ * This bit is set after each update cycle. When the UIE * bit is set to 1, the 1 in UF causes the IRQF bit to be * a 1, which asserts the !IRQ pin. This bit can be - * cleared by reading Register C or with a !RESET. + * cleared by reading Register C or with a !RESET. * * * Alarm Interrupt Flag (AF) * A 1 in the AF bit indicates that the current time has @@ -287,17 +287,27 @@ #define RTC_ALDAY 0x7D /* VIA VT82C586B - alarm day */ #define RTC_ALMONTH 0x7E /* VIA VT82C586B - alarm month */ #define RTC_CENTURY_VIA 0x7F /* century register for VIA VT82C586B */ + +#define RTC_ALDAY_SIS 0x7E /* Day of Month Alarm for SiS */ +#define RTC_ALMONT_SIS 0x7F /* Month Alarm for SiS */ + #define RTC_REGS 14 /* number of registers */ -#define FLAG_LS_HACK 0x01 -#define FLAG_PIIX4 0x02 +#define FLAG_NO_NMI 0x01 +#define FLAG_AMI_1992_HACK 0x02 +#define FLAG_AMI_1994_HACK 0x04 +#define FLAG_AMI_1995_HACK 0x08 +#define FLAG_P6RP4_HACK 0x10 +#define FLAG_PIIX4 0x20 typedef struct { int8_t stat; uint8_t cent, def, - flags, read_addr; + flags, read_addr, + wp_0d, wp_32, + pad, pad0; uint8_t addr[8], wp[2], bank[8], *lock; @@ -425,7 +435,7 @@ check_alarm_via(nvr_t *nvr, int8_t addr, int8_t addr_2) return((nvr->regs[addr_2] == nvr->regs[addr]) || ((nvr->regs[addr_2] & AL_DONTCARE) == AL_DONTCARE)); } else - return 0; + return 1; } @@ -454,14 +464,16 @@ timer_update(void *priv) check_alarm(nvr, RTC_MINUTES) && check_alarm(nvr, RTC_HOURS) && check_alarm_via(nvr, RTC_DOM, RTC_ALDAY) && - check_alarm_via(nvr, RTC_MONTH, RTC_ALMONTH)) { + check_alarm_via(nvr, RTC_MONTH, RTC_ALMONTH)/* && + check_alarm_via(nvr, RTC_DOM, RTC_ALDAY_SIS) && + check_alarm_via(nvr, RTC_MONTH, RTC_ALMONT_SIS)*/) { nvr->regs[RTC_REGC] |= REGC_AF; if (nvr->regs[RTC_REGB] & REGB_AIE) { - nvr->regs[RTC_REGC] |= REGC_IRQF; - /* Generate an interrupt. */ - if (nvr->irq != -1) + if ((nvr->irq != -1) && (!(nvr->regs[RTC_REGC] & REGC_IRQF))) picint(1 << nvr->irq); + + nvr->regs[RTC_REGC] |= REGC_IRQF; } } @@ -471,11 +483,11 @@ timer_update(void *priv) */ nvr->regs[RTC_REGC] |= REGC_UF; if (nvr->regs[RTC_REGB] & REGB_UIE) { - nvr->regs[RTC_REGC] |= REGC_IRQF; - /* Generate an interrupt. */ - if (nvr->irq != -1) + if ((nvr->irq != -1) && (!(nvr->regs[RTC_REGC] & REGC_IRQF))) picint(1 << nvr->irq); + + nvr->regs[RTC_REGC] |= REGC_IRQF; } } } @@ -487,6 +499,8 @@ timer_load_count(nvr_t *nvr) int c = nvr->regs[RTC_REGA] & REGA_RS; local_t *local = (local_t *) nvr->data; + timer_disable(&local->rtc_timer); + if ((nvr->regs[RTC_REGA] & 0x70) != 0x20) { local->state = 0; return; @@ -500,9 +514,11 @@ timer_load_count(nvr_t *nvr) break; case 1: case 2: local->count = 1 << (c + 6); + timer_set_delay_u64(&local->rtc_timer, (local->count) * RTCCONST); break; default: local->count = 1 << (c - 1); + timer_set_delay_u64(&local->rtc_timer, (local->count) * RTCCONST); break; } } @@ -514,24 +530,17 @@ timer_intr(void *priv) nvr_t *nvr = (nvr_t *)priv; local_t *local = (local_t *)nvr->data; - timer_advance_u64(&local->rtc_timer, RTCCONST); - if (local->state == 1) { - local->count--; - if (local->count == 0) - timer_load_count(nvr); - else - return; - } else - return; + timer_load_count(nvr); - nvr->regs[RTC_REGC] |= REGC_PF; - if (nvr->regs[RTC_REGB] & REGB_PIE) { - nvr->regs[RTC_REGC] |= REGC_IRQF; + nvr->regs[RTC_REGC] |= REGC_PF; + if (nvr->regs[RTC_REGB] & REGB_PIE) { + /* Generate an interrupt. */ + if ((nvr->irq != -1) && (!(nvr->regs[RTC_REGC] & REGC_IRQF))) + picint(1 << nvr->irq); - /* Generate an interrupt. */ - if (nvr->irq != -1) - picint(1 << nvr->irq); + nvr->regs[RTC_REGC] |= REGC_IRQF; + } } } @@ -556,6 +565,28 @@ timer_tick(nvr_t *nvr) } +static void +nvr_reg_common_write(uint16_t reg, uint8_t val, nvr_t *nvr, local_t *local) +{ + if ((reg == 0x2c) && (local->flags & FLAG_AMI_1994_HACK)) + nvr->is_new = 0; + if ((reg == 0x2d) && (local->flags & FLAG_AMI_1992_HACK)) + nvr->is_new = 0; + if ((reg == 0x52) && (local->flags & FLAG_AMI_1995_HACK)) + nvr->is_new = 0; + if ((reg >= 0x38) && (reg <= 0x3f) && local->wp[0]) + return; + if ((reg >= 0xb8) && (reg <= 0xbf) && local->wp[1]) + return; + if (local->lock[reg]) + return; + if (nvr->regs[reg] != val) { + nvr->regs[reg] = val; + nvr_dosave = 1; + } +} + + /* This must be exposed because ACPI uses it. */ void nvr_reg_write(uint16_t reg, uint8_t val, void *priv) @@ -563,8 +594,7 @@ nvr_reg_write(uint16_t reg, uint8_t val, void *priv) nvr_t *nvr = (nvr_t *)priv; local_t *local = (local_t *)nvr->data; struct tm tm; - uint8_t old, i; - uint16_t checksum = 0x0000; + uint8_t old; old = nvr->regs[reg]; switch(reg) { @@ -575,7 +605,7 @@ nvr_reg_write(uint16_t reg, uint8_t val, void *priv) case RTC_REGB: nvr->regs[RTC_REGB] = val; - if (((old^val) & REGB_SET) && (val®B_SET)) { + if (((old^val) & REGB_SET) && (val & REGB_SET)) { /* According to the datasheet... */ nvr->regs[RTC_REGA] &= ~REGA_UIP; nvr->regs[RTC_REGB] &= ~REGB_UIE; @@ -583,32 +613,22 @@ nvr_reg_write(uint16_t reg, uint8_t val, void *priv) break; case RTC_REGC: /* R/O */ - case RTC_REGD: /* R/O */ break; - case 0x2e: - case 0x2f: - if (local->flags & FLAG_LS_HACK) { - /* 2E and 2F are a simple sum of the values of 0E to 2D. */ - for (i = 0x0e; i < 0x2e; i++) - checksum += (uint16_t) nvr->regs[i]; - nvr->regs[0x2e] = checksum >> 8; - nvr->regs[0x2f] = checksum & 0xff; + case RTC_REGD: /* R/O */ + /* This is needed for VIA, where writing to this register changes a write-only + bit whose value is read from power management register 42. */ + nvr->regs[RTC_REGD] = val & 0x80; + break; + + case 0x32: + if ((reg == 0x32) && (local->cent == RTC_CENTURY_VIA) && local->wp_32) break; - } - /*FALLTHROUGH*/ + nvr_reg_common_write(reg, val, nvr, local); + break; default: /* non-RTC registers are just NVRAM */ - if ((reg >= 0x38) && (reg <= 0x3f) && local->wp[0]) - break; - if ((reg >= 0xb8) && (reg <= 0xbf) && local->wp[1]) - break; - if (local->lock[reg]) - break; - if (nvr->regs[reg] != val) { - nvr->regs[reg] = val; - nvr_dosave = 1; - } + nvr_reg_common_write(reg, val, nvr, local); break; } @@ -633,11 +653,14 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) local_t *local = (local_t *)nvr->data; uint8_t addr_id = (addr & 0x0e) >> 1; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); + + if (local->bank[addr_id] == 0xff) + return; if (addr & 1) { - if (local->bank[addr_id] == 0xff) - return; + // if (local->bank[addr_id] == 0xff) + // return; nvr_reg_write(local->addr[addr_id], val, priv); } else { local->addr[addr_id] = (val & (nvr->size - 1)); @@ -648,8 +671,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) local->addr[addr_id] = (local->addr[addr_id] & 0x7f) | 0x80; if (local->bank[addr_id] > 0) local->addr[addr_id] = (local->addr[addr_id] & 0x7f) | (0x80 * local->bank[addr_id]); - if (!(machines[machine].flags & MACHINE_MCA) && - !(machines[machine].flags & MACHINE_NONMI)) + if (!(local->flags & FLAG_NO_NMI)) nmi_mask = (~val & 0x80); } } @@ -663,14 +685,13 @@ nvr_read(uint16_t addr, void *priv) local_t *local = (local_t *)nvr->data; uint8_t ret; uint8_t addr_id = (addr & 0x0e) >> 1; - uint16_t checksum; + uint16_t i, checksum = 0x0000; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); - if ((addr & 1) && (local->bank[addr_id] == 0xff)) - return 0xff; - - if (addr & 1) switch(local->addr[addr_id]) { + if (local->bank[addr_id] == 0xff) + ret = 0xff; + else if (addr & 1) switch(local->addr[addr_id]) { case RTC_REGA: ret = (nvr->regs[RTC_REGA] & 0x7f) | local->stat; break; @@ -682,23 +703,45 @@ nvr_read(uint16_t addr, void *priv) break; case RTC_REGD: - nvr->regs[RTC_REGD] |= REGD_VRT; - ret = nvr->regs[RTC_REGD]; + /* Bits 6-0 of this register always read 0. Bit 7 is battery state, + we should always return it set, as that means the battery is OK. */ + ret = REGD_VRT; break; case 0x2c: - if (local->flags & FLAG_LS_HACK) + if (!nvr->is_new && (local->flags & FLAG_AMI_1994_HACK)) ret = nvr->regs[local->addr[addr_id]] & 0x7f; else ret = nvr->regs[local->addr[addr_id]]; break; + case 0x2d: + if (!nvr->is_new && (local->flags & FLAG_AMI_1992_HACK)) + ret = nvr->regs[local->addr[addr_id]] & 0xf7; + else + ret = nvr->regs[local->addr[addr_id]]; + break; + case 0x2e: case 0x2f: - if (local->flags & FLAG_LS_HACK) { - checksum = (nvr->regs[0x2e] << 8) | nvr->regs[0x2f]; - if (nvr->regs[0x2c] & 0x80) - checksum -= 0x80; + if (!nvr->is_new && (local->flags & FLAG_AMI_1992_HACK)) { + for (i = 0x10; i <= 0x2d; i++) { + if (i == 0x2d) + checksum += (nvr->regs[i] & 0xf7); + else + checksum += nvr->regs[i]; + } + if (local->addr[addr_id] == 0x2e) + ret = checksum >> 8; + else + ret = checksum & 0xff; + } else if (!nvr->is_new && (local->flags & FLAG_AMI_1994_HACK)) { + for (i = 0x10; i <= 0x2d; i++) { + if (i == 0x2c) + checksum += (nvr->regs[i] & 0x7f); + else + checksum += nvr->regs[i]; + } if (local->addr[addr_id] == 0x2e) ret = checksum >> 8; else @@ -707,6 +750,54 @@ nvr_read(uint16_t addr, void *priv) ret = nvr->regs[local->addr[addr_id]]; break; + case 0x3e: + case 0x3f: + if (!nvr->is_new && (local->flags & FLAG_AMI_1995_HACK)) { + /* The checksum at 3E-3F is for 37-3D and 40-7F. */ + for (i = 0x37; i <= 0x3d; i++) + checksum += nvr->regs[i]; + for (i = 0x40; i <= 0x7f; i++) { + if (i == 0x52) + checksum += (nvr->regs[i] & 0xf3); + else + checksum += nvr->regs[i]; + } + if (local->addr[addr_id] == 0x3e) + ret = checksum >> 8; + else + ret = checksum & 0xff; + } else if (!nvr->is_new && (local->flags & FLAG_P6RP4_HACK)) { + /* The checksum at 3E-3F is for 37-3D and 40-51. */ + for (i = 0x37; i <= 0x3d; i++) + checksum += nvr->regs[i]; + for (i = 0x40; i <= 0x51; i++) { + if (i == 0x43) + checksum += (nvr->regs[i] | 0x02); + else + checksum += nvr->regs[i]; + } + if (local->addr[addr_id] == 0x3e) + ret = checksum >> 8; + else + ret = checksum & 0xff; + } else + ret = nvr->regs[local->addr[addr_id]]; + break; + + case 0x43: + if (!nvr->is_new && (local->flags & FLAG_P6RP4_HACK)) + ret = nvr->regs[local->addr[addr_id]] | 0x02; + else + ret = nvr->regs[local->addr[addr_id]]; + break; + + case 0x52: + if (!nvr->is_new && (local->flags & FLAG_AMI_1995_HACK)) + ret = nvr->regs[local->addr[addr_id]] & 0xf3; + else + ret = nvr->regs[local->addr[addr_id]]; + break; + default: ret = nvr->regs[local->addr[addr_id]]; break; @@ -714,6 +805,8 @@ nvr_read(uint16_t addr, void *priv) ret = local->addr[addr_id]; if (!local->read_addr) ret &= 0x80; + if (alt_access) + ret = (ret & 0x7f) | (nmi_mask ? 0x00 : 0x80); } return(ret); @@ -749,8 +842,9 @@ nvr_reset(nvr_t *nvr) nvr->regs[RTC_YEAR] = RTC_BCD(80); if (local->cent != 0xFF) nvr->regs[local->cent] = RTC_BCD(19); -} + nvr->regs[RTC_REGD] = REGD_VRT; +} /* Process after loading from file. */ static void @@ -837,8 +931,7 @@ nvr_at_speed_changed(void *priv) nvr_t *nvr = (nvr_t *) priv; local_t *local = (local_t *) nvr->data; - timer_disable(&local->rtc_timer); - timer_set_delay_u64(&local->rtc_timer, RTCCONST); + timer_load_count(nvr); timer_disable(&local->update_timer); if (local->ecount > 0ULL) @@ -853,7 +946,7 @@ void nvr_at_handler(int set, uint16_t base, nvr_t *nvr) { io_handler(set, base, 2, - nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); } @@ -861,10 +954,9 @@ void nvr_at_sec_handler(int set, uint16_t base, nvr_t *nvr) { io_handler(set, base, 2, - nvr_sec_read,NULL,NULL, nvr_sec_write,NULL,NULL, nvr); + nvr_sec_read,NULL,NULL, nvr_sec_write,NULL,NULL, nvr); } - void nvr_read_addr_set(int set, nvr_t *nvr) { @@ -883,6 +975,18 @@ nvr_wp_set(int set, int h, nvr_t *nvr) } +void +nvr_via_wp_set(int set, int reg, nvr_t *nvr) +{ + local_t *local = (local_t *) nvr->data; + + if (reg == 0x0d) + local->wp_0d = set; + else + local->wp_32 = set; +} + + void nvr_bank_set(int base, uint8_t bank, nvr_t *nvr) { @@ -903,6 +1007,24 @@ nvr_lock_set(int base, int size, int lock, nvr_t *nvr) } +void +nvr_irq_set(int irq, nvr_t *nvr) +{ + nvr->irq = irq; +} + + +static void +nvr_at_reset(void *priv) +{ + nvr_t *nvr = (nvr_t *) priv; + + /* These bits are reset on reset. */ + nvr->regs[RTC_REGB] &= ~(REGB_PIE | REGB_AIE | REGB_UIE | REGB_SQWE); + nvr->regs[RTC_REGC] &= ~(REGC_PF | REGC_AF | REGC_UF | REGC_IRQF); +} + + static void * nvr_at_init(const device_t *info) { @@ -922,21 +1044,34 @@ nvr_at_init(const device_t *info) nvr->size = machines[machine].nvrmask + 1; local->lock = (uint8_t *) malloc(nvr->size); memset(local->lock, 0x00, nvr->size); - local->def = 0x00; + local->def = 0xff /*0x00*/; local->flags = 0x00; switch(info->local & 7) { case 0: /* standard AT, no century register */ - nvr->irq = 8; - local->cent = 0xff; + if (info->local == 16) { + local->flags |= FLAG_P6RP4_HACK; + nvr->irq = 8; + local->cent = RTC_CENTURY_AT; + } else { + nvr->irq = 8; + local->cent = 0xff; + } break; - case 5: /* Lucky Star LS-486E */ - local->flags |= FLAG_LS_HACK; - /*FALLTHROUGH*/ - case 1: /* standard AT */ + case 5: /* AMI WinBIOS 1994 */ + case 6: /* AMI BIOS 1995 */ if (info->local == 9) local->flags |= FLAG_PIIX4; + else { + local->def = 0x00; + if ((info->local & 7) == 5) + local->flags |= FLAG_AMI_1994_HACK; + else if ((info->local & 7) == 6) + local->flags |= FLAG_AMI_1995_HACK; + else + local->def = 0xff; + } nvr->irq = 8; local->cent = RTC_CENTURY_AT; break; @@ -944,21 +1079,30 @@ nvr_at_init(const device_t *info) case 2: /* PS/1 or PS/2 */ nvr->irq = 8; local->cent = RTC_CENTURY_PS; + local->def = 0x00; + if (info->local & 8) + local->flags |= FLAG_NO_NMI; break; case 3: /* Amstrad PC's */ nvr->irq = 1; local->cent = RTC_CENTURY_AT; local->def = 0xff; + if (info->local & 8) + local->flags |= FLAG_NO_NMI; break; case 4: /* IBM AT */ + if (info->local == 12) { + local->def = 0x00; + local->flags |= FLAG_AMI_1992_HACK; + } else + local->def = 0xff; nvr->irq = 8; local->cent = RTC_CENTURY_AT; - local->def = 0xff; break; - case 6: /* VIA VT82C586B */ + case 7: /* VIA VT82C586B */ nvr->irq = 8; local->cent = RTC_CENTURY_VIA; break; @@ -979,8 +1123,11 @@ nvr_at_init(const device_t *info) timer_add(&local->update_timer, timer_update, nvr, 0); timer_add(&local->rtc_timer, timer_intr, nvr, 0); + /* On power on, if the oscillator is disabled, it's reenabled. */ + if ((nvr->regs[RTC_REGA] & 0x70) == 0x00) + nvr->regs[RTC_REGA] = (nvr->regs[RTC_REGA] & 0x8f) | 0x20; + nvr_at_reset(nvr); timer_load_count(nvr); - timer_set_delay_u64(&local->rtc_timer, RTCCONST); /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, @@ -1009,87 +1156,190 @@ nvr_at_close(void *priv) timer_disable(&local->update_timer); timer_disable(&nvr->onesec_time); - if (nvr->fn != NULL) - free(nvr->fn); + if (nvr != NULL) { + if (nvr->fn != NULL) + free(nvr->fn); - if (nvr->data != NULL) - free(nvr->data); + if (nvr->data != NULL) + free(nvr->data); - free(nvr); + free(nvr); + } if (nvr_at_inited == 1) nvr_at_inited = 0; } - const device_t at_nvr_old_device = { - "PC/AT NVRAM (No century)", - DEVICE_ISA | DEVICE_AT, - 0, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, - NULL + .name = "PC/AT NVRAM (No century)", + .internal_name = "at_nvr_old", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t at_nvr_device = { - "PC/AT NVRAM", - DEVICE_ISA | DEVICE_AT, - 1, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, - NULL + .name = "PC/AT NVRAM", + .internal_name = "at_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 1, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t ps_nvr_device = { - "PS/1 or PS/2 NVRAM", - DEVICE_PS2, - 2, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, - NULL + .name = "PS/1 or PS/2 NVRAM", + .internal_name = "ps_nvr", + .flags = DEVICE_PS2, + .local = 2, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t amstrad_nvr_device = { - "Amstrad NVRAM", - MACHINE_ISA | MACHINE_AT, - 3, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, - NULL + .name = "Amstrad NVRAM", + .internal_name = "amstrad_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 3, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t ibmat_nvr_device = { - "IBM AT NVRAM", - DEVICE_ISA | DEVICE_AT, - 4, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, - NULL + .name = "IBM AT NVRAM", + .internal_name = "ibmat_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 4, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL }; const device_t piix4_nvr_device = { - "Intel PIIX4 PC/AT NVRAM", - DEVICE_ISA | DEVICE_AT, - 9, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, + .name = "Intel PIIX4 PC/AT NVRAM", + .internal_name = "piix4_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 9, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ps_no_nmi_nvr_device = { + "PS/1 or PS/2 NVRAM (No NMI)", + "ps1_nvr", + DEVICE_PS2, + 10, + nvr_at_init, nvr_at_close, nvr_at_reset, + { NULL }, nvr_at_speed_changed, NULL }; -const device_t ls486e_nvr_device = { - "Lucky Star LS-486E PC/AT NVRAM", +const device_t amstrad_no_nmi_nvr_device = { + "Amstrad NVRAM (No NMI)", + "amstrad_nvr", DEVICE_ISA | DEVICE_AT, - 13, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, + 11, + nvr_at_init, nvr_at_close, nvr_at_reset, + { NULL }, nvr_at_speed_changed, NULL }; +const device_t ami_1992_nvr_device = { + .name = "AMI Color 1992 PC/AT NVRAM", + .internal_name = "ami_1992_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 12, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ami_1994_nvr_device = { + .name = "AMI WinBIOS 1994 PC/AT NVRAM", + .internal_name = "ami_1994_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 13, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ami_1995_nvr_device = { + .name = "AMI WinBIOS 1995 PC/AT NVRAM", + .internal_name = "ami_1995_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 14, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t via_nvr_device = { - "VIA PC/AT NVRAM", - DEVICE_ISA | DEVICE_AT, - 14, - nvr_at_init, nvr_at_close, NULL, - NULL, nvr_at_speed_changed, - NULL + .name = "VIA PC/AT NVRAM", + .internal_name = "via_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 15, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t p6rp4_nvr_device = { + .name = "ASUS P/I-P6RP4 PC/AT NVRAM", + .internal_name = "p6rp4_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 16, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index f0203c90a..e82eff150 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -53,9 +53,10 @@ typedef struct { int addr; - uint8_t ram[8192]; + uint8_t *ram; + int size; - wchar_t *fn; + char *fn; } ps2_nvr_t; @@ -107,7 +108,6 @@ ps2_nvr_write(uint16_t port, uint8_t val, void *priv) static void * ps2_nvr_init(const device_t *info) { - char temp[64]; ps2_nvr_t *nvr; FILE *f = NULL; int c; @@ -115,20 +115,25 @@ ps2_nvr_init(const device_t *info) nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t)); memset(nvr, 0x00, sizeof(ps2_nvr_t)); + if (info->local) + nvr->size = 2048; + else + nvr->size = 8192; + /* Set up the NVR file's name. */ - sprintf(temp, "%s_sec.nvr", machine_get_internal_name()); - c = strlen(temp); - nvr->fn = (wchar_t *)malloc((c + 1) * sizeof(wchar_t)); - mbstowcs(nvr->fn, temp, c + 1); + c = strlen(machine_get_internal_name()) + 9; + nvr->fn = (char *)malloc(c + 1); + sprintf(nvr->fn, "%s_sec.nvr", machine_get_internal_name()); io_sethandler(0x0074, 3, ps2_nvr_read,NULL,NULL, ps2_nvr_write,NULL,NULL, nvr); - f = nvr_fopen(nvr->fn, L"rb"); + f = nvr_fopen(nvr->fn, "rb"); - memset(nvr->ram, 0xff, 8192); + nvr->ram = (uint8_t *)malloc(nvr->size); + memset(nvr->ram, 0xff, nvr->size); if (f != NULL) { - if (fread(nvr->ram, 1, 8192, f) != 8192) + if (fread(nvr->ram, 1, nvr->size, f) != nvr->size) fatal("ps2_nvr_init(): Error reading EEPROM data\n"); fclose(f); } @@ -143,21 +148,43 @@ ps2_nvr_close(void *priv) ps2_nvr_t *nvr = (ps2_nvr_t *)priv; FILE *f = NULL; - f = nvr_fopen(nvr->fn, L"wb"); + f = nvr_fopen(nvr->fn, "wb"); if (f != NULL) { - (void)fwrite(nvr->ram, 8192, 1, f); + (void)fwrite(nvr->ram, nvr->size, 1, f); fclose(f); } + if (nvr->ram != NULL) + free(nvr->ram); + free(nvr); } - const device_t ps2_nvr_device = { - "PS/2 Secondary NVRAM", - 0, 0, - ps2_nvr_init, ps2_nvr_close, NULL, - NULL, NULL, - NULL + .name = "PS/2 Secondary NVRAM for PS/2 Models 70-80", + .internal_name = "ps2_nvr", + .flags = 0, + .local = 0, + .init = ps2_nvr_init, + .close = ps2_nvr_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ps2_nvr_55ls_device = { + .name = "PS/2 Secondary NVRAM for PS/2 Models 55LS-65SX", + .internal_name = "ps2_nvr_55ls", + .flags = 0, + .local = 1, + .init = ps2_nvr_init, + .close = ps2_nvr_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/pc.c b/src/pc.c deleted file mode 100644 index 574b81d58..000000000 --- a/src/pc.c +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * 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. - * - * Main emulator module where most things are controlled. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/config.h> -#include <86box/mem.h> -#include "cpu.h" -#ifdef USE_DYNAREC -# include "codegen_public.h" -#endif -#include "x86_ops.h" -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/dma.h> -#include <86box/pci.h> -#include <86box/pic.h> -#include <86box/timer.h> -#include <86box/device.h> -#include <86box/pit.h> -#include <86box/random.h> -#include <86box/timer.h> -#include <86box/nvr.h> -#include <86box/machine.h> -#include <86box/bugger.h> -#include <86box/postcard.h> -#include <86box/isamem.h> -#include <86box/isartc.h> -#include <86box/lpt.h> -#include <86box/serial.h> -#include <86box/keyboard.h> -#include <86box/mouse.h> -#include <86box/gameport.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/fdc_ext.h> -#include <86box/hdd.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/scsi.h> -#include <86box/scsi_device.h> -#include <86box/cdrom.h> -#include <86box/zip.h> -#include <86box/scsi_disk.h> -#include <86box/cdrom_image.h> -#include <86box/network.h> -#include <86box/sound.h> -#include <86box/midi.h> -#include <86box/snd_speaker.h> -#include <86box/video.h> -#include <86box/ui.h> -#include <86box/plat.h> -#include <86box/plat_midi.h> - - -/* Stuff that used to be globally declared in plat.h but is now extern there - and declared here instead. */ -int dopause, /* system is paused */ - doresize, /* screen resize requested */ - quited; /* system exit requested */ -uint64_t timer_freq; -char emu_version[200]; /* version ID string */ - - -/* Commandline options. */ -int dump_on_exit = 0; /* (O) dump regs on exit */ -int do_dump_config = 0; /* (O) dump config on load */ -int start_in_fullscreen = 0; /* (O) start in fullscreen */ -#ifdef _WIN32 -int force_debug = 0; /* (O) force debug output */ -#endif -#ifdef USE_WX -int video_fps = RENDER_FPS; /* (O) render speed in fps */ -#endif -int settings_only = 0; /* (O) show only the settings dialog */ -int no_quit_confirm = 0; /* (O) do not ask for confirmation on quit */ -#ifdef _WIN32 -uint64_t unique_id = 0; -uint64_t source_hwnd = 0; -#endif -wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */ - -/* Configuration values. */ -int window_w, window_h, /* (C) window size and */ - window_x, window_y, /* position info */ - window_remember, - vid_resize, /* (C) allow resizing */ - invert_display = 0, /* (C) invert the display */ - suppress_overscan = 0; /* (C) suppress overscans */ -int scale = 0; /* (C) screen scale factor */ -int vid_api = 0; /* (C) video renderer */ -int vid_cga_contrast = 0, /* (C) video */ - video_fullscreen = 0, /* (C) video */ - video_fullscreen_scale = 0, /* (C) video */ - video_fullscreen_first = 0, /* (C) video */ - enable_overscan = 0, /* (C) video */ - force_43 = 0; /* (C) video */ -int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */ - bugger_enabled = 0, /* (C) enable ISAbugger */ - postcard_enabled = 0, /* (C) enable POST card */ - isamem_type[ISAMEM_MAX] = { 0,0,0,0 }, /* (C) enable ISA mem cards */ - isartc_type = 0; /* (C) enable ISA RTC card */ -int gfxcard = 0; /* (C) graphics/video card */ -int sound_is_float = 1, /* (C) sound uses FP values */ - GAMEBLASTER = 0, /* (C) sound option */ - GUS = 0, /* (C) sound option */ - SSI2001 = 0, /* (C) sound option */ - voodoo_enabled = 0; /* (C) video option */ -uint32_t mem_size = 0; /* (C) memory size */ -int cpu_manufacturer = 0, /* (C) cpu manufacturer */ - cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */ - cpu = 3, /* (C) cpu type */ - fpu_type = 0; /* (C) fpu type */ -int time_sync = 0; /* (C) enable time sync */ -#ifdef USE_DISCORD -int enable_discord = 0; /* (C) enable Discord integration */ -#endif -int enable_crashdump = 0; /* (C) enable crash dump */ - -/* Statistics. */ -extern int - mmuflush, - readlnum, - writelnum; - -int fps, framecount; /* emulator % */ - -extern int CPUID; -extern int output; -int atfullspeed; -int clockrate; - -wchar_t exe_path[2048]; /* path (dir) of executable */ -wchar_t usr_path[1024]; /* path (dir) of user data */ -wchar_t cfg_path[1024]; /* full path of config file */ -FILE *stdlog = NULL; /* file to log output to */ -int scrnsz_x = SCREEN_RES_X, /* current screen size, X */ - scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ -int config_changed; /* config has changed */ -int title_update; -int64_t main_time; - - -int unscaled_size_x = SCREEN_RES_X, /* current unscaled size X */ - unscaled_size_y = SCREEN_RES_Y, /* current unscaled size Y */ - efscrnsz_y = SCREEN_RES_Y; - - -#ifndef RELEASE_BUILD -static char buff[1024]; -static int seen = 0; - -static int suppr_seen = 1; -#endif - -/* - * Log something to the logfile or stdout. - * - * To avoid excessively-large logfiles because some - * module repeatedly logs, we keep track of what is - * being logged, and catch repeating entries. - */ -void -pclog_ex(const char *fmt, va_list ap) -{ -#ifndef RELEASE_BUILD - char temp[1024]; - - if (stdlog == NULL) { - if (log_path[0] != L'\0') { - stdlog = plat_fopen(log_path, L"w"); - if (stdlog == NULL) - stdlog = stdout; - } else { - stdlog = stdout; - } - } - - vsprintf(temp, fmt, ap); - if (suppr_seen && ! strcmp(buff, temp)) { - seen++; - } else { - if (suppr_seen && seen) { - fprintf(stdlog, "*** %d repeats ***\n", seen); - } - seen = 0; - strcpy(buff, temp); - fprintf(stdlog, temp, ap); - } - - fflush(stdlog); -#endif -} - - -void -pclog_toggle_suppr(void) -{ -#ifndef RELEASE_BUILD - suppr_seen ^= 1; -#endif -} - - -/* Log something. We only do this in non-release builds. */ -void -pclog(const char *fmt, ...) -{ -#ifndef RELEASE_BUILD - va_list ap; - - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); -#endif -} - - -/* Log a fatal error, and display a UI message before exiting. */ -void -fatal(const char *fmt, ...) -{ - char temp[1024]; - va_list ap; - char *sp; - - va_start(ap, fmt); - - if (stdlog == NULL) { - if (log_path[0] != L'\0') { - stdlog = plat_fopen(log_path, L"w"); - if (stdlog == NULL) - stdlog = stdout; - } else { - stdlog = stdout; - } - } - - vsprintf(temp, fmt, ap); - fprintf(stdlog, "%s", temp); - fflush(stdlog); - va_end(ap); - - nvr_save(); - - config_save(); - - dumppic(); -#ifdef ENABLE_808X_LOG - dumpregs(1); -#endif - - /* Make sure the message does not have a trailing newline. */ - if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; - - /* Cleanly terminate all of the emulator's components so as - to avoid things like threads getting stuck. */ - do_stop(); - - ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp); - - fflush(stdlog); - - exit(-1); -} - - -#ifdef ENABLE_PC_LOG -int pc_do_log = ENABLE_PC_LOG; - - -static void -pc_log(const char *fmt, ...) -{ - va_list ap; - - if (pc_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define pc_log(fmt, ...) -#endif - - -/* - * Perform initial startup of the PC. - * - * This is the platform-indepenent part of the startup, - * where we check commandline arguments and load a - * configuration file. - */ -int -pc_init(int argc, wchar_t *argv[]) -{ - wchar_t path[2048]; - wchar_t *cfg = NULL, *p; - char temp[128]; - struct tm *info; - time_t now; - int c; - uint32_t *uid, *shwnd; - - /* Grab the executable's full path. */ - plat_get_exe_name(exe_path, sizeof_w(exe_path)-1); - p = plat_get_filename(exe_path); - *p = L'\0'; - - /* - * Get the current working directory. - * - * This is normally the directory from where the - * program was run. If we have been started via - * a shortcut (desktop icon), however, the CWD - * could have been set to something else. - */ - plat_getcwd(usr_path, sizeof_w(usr_path)-1); - memset(path, 0x00, sizeof(path)); - - for (c=1; c= CPU_286) - pit_set_clock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - else - pit_set_clock(14318184.0); -} - - -void -pc_full_speed(void) -{ - if (! atfullspeed) { - pc_log("Set fullspeed - %i %i\n", is386, AT); - pc_speed_changed(); - } - atfullspeed = 1; -} - - -/* Initialize modules, ran once, after pc_init. */ -int -pc_init_modules(void) -{ - int c, m; - wchar_t temp[512]; - - pc_log("Scanning for ROM images:\n"); - c = m = 0; - while (machine_get_internal_name_ex(m) != NULL) { - c += machine_available(m); - m++; - } - if (c == 0) { - /* No usable ROMs found, aborting. */ - return(0); - } - pc_log("A total of %d ROM sets have been loaded.\n", c); - - /* Load the ROMs for the selected machine. */ - if (! machine_available(machine)) { - swprintf(temp, sizeof(temp), plat_get_string(IDS_2063), machine_getname()); - c = 0; - machine = -1; - while (machine_get_internal_name_ex(c) != NULL) { - if (machine_available(c)) { - ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2128, temp); - machine = c; - config_save(); - break; - } - c++; - } - if (machine == -1) { - fatal("No available machines\n"); - exit(-1); - return(0); - } - } - - /* Make sure we have a usable video card. */ - if (! video_card_available(gfxcard)) { - swprintf(temp, sizeof(temp), plat_get_string(IDS_2064), video_card_getname(gfxcard)); - c = 0; - while (video_get_internal_name(c) != NULL) { - gfxcard = -1; - if (video_card_available(c)) { - ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2128, temp); - gfxcard = c; - config_save(); - break; - } - c++; - } - if (gfxcard == -1) { - fatal("No available video cards\n"); - exit(-1); - return(0); - } - } - - atfullspeed = 0; - - random_init(); - - mem_init(); - -#ifdef USE_DYNAREC - codegen_init(); -#endif - - keyboard_init(); - joystick_init(); - - video_init(); - - fdd_init(); - - sound_init(); - - hdc_init(); - - video_reset_close(); - - return(1); -} - - -/* Insert keystrokes into the machine's keyboard buffer. */ -static void -pc_keyboard_send(uint8_t val) -{ - if (AT) - keyboard_at_adddata_keyboard_raw(val); - else - keyboard_send(val); -} - - -void -pc_send_ca(uint8_t sc) -{ - pc_keyboard_send(29); /* Ctrl key pressed */ - pc_keyboard_send(56); /* Alt key pressed */ - pc_keyboard_send(sc); - pc_keyboard_send(sc | 0x80); - pc_keyboard_send(184); /* Alt key released */ - pc_keyboard_send(157); /* Ctrl key released */ -} - - -/* Send the machine a Control-Alt-DEL sequence. */ -void -pc_send_cad(void) -{ - pc_send_ca(83); -} - - -/* Send the machine a Control-Alt-ESC sequence. */ -void -pc_send_cae(void) -{ - pc_send_ca(1); -} - - -void -pc_reset_hard_close(void) -{ - ui_sb_set_ready(0); - - /* Turn off timer processing to avoid potential segmentation faults. */ - timer_close(); - - suppress_overscan = 0; - - nvr_save(); - nvr_close(); - - mouse_close(); - - lpt_devices_close(); - - device_close_all(); - - scsi_device_close_all(); - - midi_close(); - - cdrom_close(); - - zip_close(); - - scsi_disk_close(); - - closeal(); - - video_reset_close(); -} - - -/* - * This is basically the spot where we start up the actual machine, - * by issuing a 'hard reset' to the entire configuration. Order is - * somewhat important here. Functions here should be named _reset - * really, as that is what they do. - */ -void -pc_reset_hard_init(void) -{ - /* - * First, we reset the modules that are not part of - * the actual machine, but which support some of the - * modules that are. - */ - - /* Reset the general machine support modules. */ - io_init(); - - /* Turn on and (re)initialize timer processing. */ - timer_init(); - - device_init(); - - sound_reset(); - - scsi_device_init(); - - /* Initialize the actual machine and its basic modules. */ - machine_init(); - - /* Reset and reconfigure the serial ports. */ - serial_standalone_init(); - - /* Reset and reconfigure the Sound Card layer. */ - sound_card_reset(); - - /* Reset any ISA memory cards. */ - isamem_reset(); - - /* Reset any ISA RTC cards. */ - isartc_reset(); - - fdc_card_init(); - - fdd_reset(); - - /* - * Once the machine has been initialized, all that remains - * should be resetting all devices set up for it, to their - * current configurations ! - * - * For now, we will call their reset functions here, but - * that will be a call to device_reset_all() later ! - */ - - /* Reset some basic devices. */ - speaker_init(); - lpt_devices_init(); - shadowbios = 0; - - /* - * Reset the mouse, this will attach it to any port needed. - */ - mouse_reset(); - - /* Reset the Hard Disk Controller module. */ - hdc_reset(); - /* Reset and reconfigure the SCSI layer. */ - scsi_card_init(); - - cdrom_hard_reset(); - - zip_hard_reset(); - - scsi_disk_hard_reset(); - - /* Reset and reconfigure the Network Card layer. */ - network_reset(); - - if (joystick_type != JOYSTICK_TYPE_NONE) - gameport_update_joystick_type(); - - ui_sb_update_panes(); - - if (config_changed) { - config_save(); - - config_changed = 0; - } else - ui_sb_set_ready(1); - - /* Needs the status bar... */ - if (bugger_enabled) - device_add(&bugger_device); - if (postcard_enabled) - device_add(&postcard_device); - - /* Reset the CPU module. */ - resetx86(); - dma_reset(); - pic_reset(); - cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; - - atfullspeed = 0; - pc_full_speed(); -} - - -void -pc_reset_hard(void) -{ - pc_reset_hard_close(); - - pc_reset_hard_init(); -} - - -void -pc_close(thread_t *ptr) -{ - int i; - - /* Wait a while so things can shut down. */ - plat_delay_ms(200); - - /* Claim the video blitter. */ - startblit(); - - /* Terminate the main thread. */ - if (ptr != NULL) { - thread_kill(ptr); - - /* Wait some more. */ - plat_delay_ms(200); - } - -#if (defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) - codegen_close(); -#endif - - nvr_save(); - - config_save(); - - plat_mouse_capture(0); - - timer_close(); - - lpt_devices_close(); - - for (i=0; i 0 && !dopause) { - /* Yes, so do one frame now. */ - start_time = plat_timer_read(); - drawits -= 10; - if (drawits > 50) - drawits = 0; - - /* Run a block of code. */ - startblit(); - clockrate = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; - - if (is386) { -#ifdef USE_DYNAREC - if (cpu_use_dynarec) - exec386_dynarec(clockrate/100); - else -#endif - exec386(clockrate/100); - } else if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) { - exec386(clockrate/100); - } else { - execx86(clockrate/100); - } - - mouse_process(); - - joystick_process(); - - endblit(); - - /* Done with this frame, update statistics. */ - framecount++; - if (++framecountx >= 100) { - framecountx = 0; - - readlnum = writelnum = 0; - egareads = egawrites = 0; - mmuflush = 0; - frames = 0; - } - - if (title_update) { - mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1); - mbstowcs(wcpu, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, - strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name)+1); - swprintf(temp, sizeof_w(temp), - L"%ls v%ls - %i%% - %ls - %ls - %ls", - EMU_NAME_W,EMU_VERSION_W,fps,wmachine,wcpu, - (!mouse_capture) ? plat_get_string(IDS_2077) - : (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); - - ui_window_title(temp); - - title_update = 0; - } - - /* One more frame done! */ - done++; - - /* Every 200 frames we save the machine status. */ - if (++frames >= 200 && nvr_dosave) { - nvr_save(); - nvr_dosave = 0; - frames = 0; - } - - end_time = plat_timer_read(); - main_time += (end_time - start_time); - } else { - /* Just so we dont overload the host OS. */ - plat_delay_ms(1); - } - - /* If needed, handle a screen resize. */ - if (doresize && !video_fullscreen) { - plat_resize(scrnsz_x, scrnsz_y); - - doresize = 0; - } - } - - pc_log("PC: main thread done.\n"); -} - - -/* Handler for the 1-second timer to refresh the window title. */ -void -pc_onesec(void) -{ - fps = framecount; - framecount = 0; - - title_update = 1; -} - - -void -set_screen_size(int x, int y) -{ - int owsx = scrnsz_x; - int owsy = scrnsz_y; - int temp_overscan_x = overscan_x; - int temp_overscan_y = overscan_y; - double dx, dy, dtx, dty; - - /* Make sure we keep usable values. */ -#if 0 - pc_log("SetScreenSize(%d, %d) resize=%d\n", x, y, vid_resize); -#endif - if (x < 320) x = 320; - if (y < 200) y = 200; - if (x > 2048) x = 2048; - if (y > 2048) y = 2048; - - /* Save the new values as "real" (unscaled) resolution. */ - unscaled_size_x = x; - efscrnsz_y = y; - - if (suppress_overscan) - temp_overscan_x = temp_overscan_y = 0; - - if (force_43) { - dx = (double)x; - dtx = (double)temp_overscan_x; - - dy = (double)y; - dty = (double)temp_overscan_y; - - /* Account for possible overscan. */ - if (!(video_is_ega_vga()) && (temp_overscan_y == 16)) { - /* CGA */ - dy = (((dx - dtx) / 4.0) * 3.0) + dty; - } else if (!(video_is_ega_vga()) && (temp_overscan_y < 16)) { - /* MDA/Hercules */ - dy = (x / 4.0) * 3.0; - } else { - if (enable_overscan) { - /* EGA/(S)VGA with overscan */ - dy = (((dx - dtx) / 4.0) * 3.0) + dty; - } else { - /* EGA/(S)VGA without overscan */ - dy = (x / 4.0) * 3.0; - } - } - unscaled_size_y = (int)dy; - } else { - unscaled_size_y = efscrnsz_y; - } - - switch(scale) { - case 0: /* 50% */ - scrnsz_x = (unscaled_size_x>>1); - scrnsz_y = (unscaled_size_y>>1); - break; - - case 1: /* 100% */ - scrnsz_x = unscaled_size_x; - scrnsz_y = unscaled_size_y; - break; - - case 2: /* 150% */ - scrnsz_x = ((unscaled_size_x*3)>>1); - scrnsz_y = ((unscaled_size_y*3)>>1); - break; - - case 3: /* 200% */ - scrnsz_x = (unscaled_size_x<<1); - scrnsz_y = (unscaled_size_y<<1); - break; - } - - /* If the resolution has changed, let the main thread handle it. */ - if ((owsx != scrnsz_x) || (owsy != scrnsz_y)) - doresize = 1; - else - doresize = 0; -} - - -void -set_screen_size_natural(void) -{ - set_screen_size(unscaled_size_x, unscaled_size_y); -} - - -int -get_actual_size_x(void) -{ - return(unscaled_size_x); -} - - -int -get_actual_size_y(void) -{ - return(efscrnsz_y); -} diff --git a/src/pci.c b/src/pci.c index 4f5b40f66..36dd09002 100644 --- a/src/pci.c +++ b/src/pci.c @@ -37,7 +37,7 @@ typedef struct { - uint8_t id, type; + uint8_t bus, id, type; uint8_t irq_routing[4]; void *priv; @@ -51,24 +51,27 @@ typedef struct { } pci_mirq_t; -int pci_burst_time, - pci_nonburst_time; +int pci_burst_time, agp_burst_time, + pci_nonburst_time, agp_nonburst_time; static pci_card_t pci_cards[32]; -static uint8_t last_pci_card = 0; -static uint8_t pci_card_to_slot_mapping[32]; -static uint8_t elcr[2] = { 0, 0 }; -static uint8_t pci_irqs[4], pci_irq_level[4]; +static uint8_t pci_pmc = 0, last_pci_card = 0, last_normal_pci_card = 0, last_pci_bus = 1; +static uint8_t pci_card_to_slot_mapping[256][32], pci_bus_number_to_index_mapping[256]; +static uint8_t pci_irqs[16], pci_irq_level[16]; static uint64_t pci_irq_hold[16]; -static pci_mirq_t pci_mirqs[3]; +static pci_mirq_t pci_mirqs[8]; static int pci_type, + pci_switch, pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; -static int trc_reg = 0, elcr_enabled = 1; +static int trc_reg = 0; + + +static void pci_reset_regs(void); #ifdef ENABLE_PCI_LOG @@ -91,6 +94,53 @@ pci_log(const char *fmt, ...) #endif +static void +pci_clear_slot(int card) +{ + int i; + + pci_card_to_slot_mapping[pci_cards[card].bus][pci_cards[card].id] = 0xff; + + pci_cards[card].id = 0xff; + pci_cards[card].type = 0xff; + + for (i = 0; i < 4; i++) + pci_cards[card].irq_routing[i] = 0; + + pci_cards[card].read = NULL; + pci_cards[card].write = NULL; + pci_cards[card].priv = NULL; +} + + +void +pci_relocate_slot(int type, int new_slot) +{ + int i, card = -1; + int old_slot; + uint8_t mapping; + + if ((new_slot < 0) || (new_slot > 31)) + return; + + for (i = 0; i < 32; i++) { + if ((pci_cards[i].bus == 0) && (pci_cards[i].type == type)) { + card = i; + break; + } + } + + if (card == -1) + return; + + old_slot = pci_cards[card].id; + pci_cards[card].id = new_slot; + mapping = pci_card_to_slot_mapping[0][old_slot]; + pci_card_to_slot_mapping[0][old_slot] = 0xff; + pci_card_to_slot_mapping[0][new_slot] = mapping; +} + + static void pci_cf8_write(uint16_t port, uint32_t val, void *priv) { @@ -117,32 +167,104 @@ pci_write(uint16_t port, uint8_t val, void *priv) uint8_t slot = 0; if (in_smm) - pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); + pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); switch (port) { case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: - if (! pci_enable) + if (! pci_enable) return; - - pci_log("Writing %02X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index); - if (! pci_bus) { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xff) { - if (pci_cards[slot].write) { - pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); - pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); - } -#ifdef ENABLE_PCI_LOG - else - pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); -#endif + + pci_log("Writing %02X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); + pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); } #ifdef ENABLE_PCI_LOG else - pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); #endif } - +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + + break; + } +} + + +static void +pci_writew(uint16_t port, uint16_t val, void *priv) +{ + uint8_t slot = 0; + + if (in_smm) + pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); + + switch (port) { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (! pci_enable) + return; + + pci_log("Writing %04X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); + pci_cards[slot].write(pci_func, pci_index | (port & 3), val & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | ((port & 3) + 1), val >> 8, pci_cards[slot].priv); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + + break; + } +} + + +static void +pci_writel(uint16_t port, uint32_t val, void *priv) +{ + uint8_t slot = 0; + + if (in_smm) + pci_log("(%i) %03x write: %02X\n", pci_enable, port, val); + + switch (port) { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (! pci_enable) + return; + + pci_log("Writing %08X to PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", val, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); + pci_cards[slot].write(pci_func, pci_index | (port & 3), val & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | ((port & 3) + 1), (val >> 8) & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | ((port & 3) + 2), (val >> 16) & 0xff, pci_cards[slot].priv); + pci_cards[slot].write(pci_func, pci_index | ((port & 3) + 3), (val >> 24) & 0xff, pci_cards[slot].priv); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + break; } } @@ -159,73 +281,103 @@ pci_read(uint16_t port, void *priv) switch (port) { case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: - if (! pci_enable) + if (! pci_enable) return 0xff; - if (! pci_bus) { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xff) { - if (pci_cards[slot].read) - ret = pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); -#ifdef ENABLE_PCI_LOG - else - pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); -#endif - } + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) + ret = pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); #ifdef ENABLE_PCI_LOG else - pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); #endif } - - pci_log("Reading %02X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index); +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif } + pci_log("Reading %02X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + return ret; } -static void -elcr_write(uint16_t port, uint8_t val, void *priv) +static uint16_t +pci_readw(uint16_t port, void *priv) { - pci_log("ELCR%i: WRITE %02X\n", port & 1, val); + uint8_t slot = 0; + uint16_t ret = 0xffff; - if (port & 1) - val &= 0xde; - else - val &= 0xf8; + if (in_smm) + pci_log("(%i) %03x read\n", pci_enable, port); - elcr[port & 1] = val; + switch (port) { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (! pci_enable) + return 0xff; - pci_log("ELCR %i: %c %c %c %c %c %c %c %c\n", - port & 1, - (val & 1) ? 'L' : 'E', - (val & 2) ? 'L' : 'E', - (val & 4) ? 'L' : 'E', - (val & 8) ? 'L' : 'E', - (val & 0x10) ? 'L' : 'E', - (val & 0x20) ? 'L' : 'E', - (val & 0x40) ? 'L' : 'E', - (val & 0x80) ? 'L' : 'E'); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) { + ret = pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); + ret |= (pci_cards[slot].read(pci_func, (pci_index | (port & 3)) + 1, pci_cards[slot].priv) << 8); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } + + pci_log("Reading %04X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + + return ret; } -static uint8_t -elcr_read(uint16_t port, void *priv) +static uint32_t +pci_readl(uint16_t port, void *priv) { - pci_log("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]); + uint8_t slot = 0; + uint32_t ret = 0xffffffff; - return elcr[port & 1]; -} + if (in_smm) + pci_log("(%i) %03x read\n", pci_enable, port); + switch (port) { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (! pci_enable) + return 0xff; -static void -elcr_reset(void) -{ - pic_reset(); + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) { + ret = pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); + ret |= (pci_cards[slot].read(pci_func, (pci_index | (port & 3)) + 1, pci_cards[slot].priv) << 8); + ret |= (pci_cards[slot].read(pci_func, (pci_index | (port & 3)) + 2, pci_cards[slot].priv) << 16); + ret |= (pci_cards[slot].read(pci_func, (pci_index | (port & 3)) + 3, pci_cards[slot].priv) << 24); + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index | (port & 3)); +#endif + } - elcr[0] = 0x00; - elcr[1] = 0x00; + pci_log("Reading %08X, from PCI card on bus %i, slot %02X (pci_cards[%i]) (%02X:%02X)...\n", ret, pci_bus, pci_card, slot, pci_func, pci_index | (port & 3)); + + return ret; } @@ -233,6 +385,35 @@ static void pci_type2_write(uint16_t port, uint8_t val, void *priv); static uint8_t pci_type2_read(uint16_t port, void *priv); +void +pci_set_pmc(uint8_t pmc) +{ + pci_reset_regs(); + + if (!pci_pmc && (pmc & 0x01)) { + io_removehandler(0x0cf8, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + io_removehandler(0x0cfa, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + io_sethandler(0x0cf8, 1, + NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); + io_sethandler(0x0cfc, 4, + pci_read,NULL,NULL, pci_write,NULL,NULL, NULL); + } else if (pci_pmc && !(pmc & 0x01)) { + io_removehandler(0x0cf8, 1, + NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); + io_removehandler(0x0cfc, 4, + pci_read,NULL,NULL, pci_write,NULL,NULL, NULL); + io_sethandler(0x0cf8, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + io_sethandler(0x0cfa, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + } + + pci_pmc = (pmc & 0x01); +} + + static void pci_type2_write(uint16_t port, uint8_t val, void *priv) { @@ -244,34 +425,49 @@ pci_type2_write(uint16_t port, uint8_t val, void *priv) if (!pci_key && (val & 0xf0)) io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, - pci_type2_write, NULL, NULL, priv); - else + pci_type2_write, NULL, NULL, NULL); + else if (pci_key && !(val & 0xf0)) io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, - pci_type2_write, NULL, NULL, priv); + pci_type2_write, NULL, NULL, NULL); pci_key = val & 0xf0; - } else if (port == 0xcfa) { + } else if (port == 0xcfa) pci_bus = val; + else if (port == 0xcfb) { + pci_log("Write %02X to port 0CFB\n", val); + pci_set_pmc(val); } else { pci_card = (port >> 8) & 0xf; pci_index = port & 0xff; - if (! pci_bus) { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xff) { - if (pci_cards[slot].write) - pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); -#ifdef ENABLE_PCI_LOG - else - pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); -#endif - } + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) + pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); #ifdef ENABLE_PCI_LOG else - pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); + pci_log("Writing to empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); #endif } +#ifdef ENABLE_PCI_LOG + else + pci_log("Writing to unassigned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); +#endif + } +} + + +static void +pci_type2_writel(uint16_t port, uint32_t val, void *priv) +{ + int i; + + for (i = 0; i < 4; i++) { + /* Make sure to have the DWORD write not pass through to PMC if mechanism 1 is in use, + as otherwise, the PCI enable bits clobber it. */ + if (!pci_pmc || ((port + i) != 0x0cfb)) + pci_type2_write(port + i, val >> 8, priv); } } @@ -283,28 +479,27 @@ pci_type2_read(uint16_t port, void *priv) if (port == 0xcf8) return pci_key | (pci_func << 1); - - if (port == 0xcfa) + else if (port == 0xcfa) return pci_bus; + else if (port == 0xcfb) + return pci_pmc; pci_card = (port >> 8) & 0xf; pci_index = port & 0xff; - if (! pci_bus) { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xff) { - if (pci_cards[slot].read) - return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); -#ifdef ENABLE_PCI_LOG - else - pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); -#endif - } + slot = pci_card_to_slot_mapping[pci_bus_number_to_index_mapping[pci_bus]][pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) + return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); #ifdef ENABLE_PCI_LOG else - pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); + pci_log("Reading from empty PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); #endif } +#ifdef ENABLE_PCI_LOG + else + pci_log("Reading from unasisgned PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); +#endif return 0xff; } @@ -338,62 +533,35 @@ pci_set_mirq_routing(int mirq, int irq) } -int -pci_irq_is_level(int irq) -{ - int real_irq = irq & 7; - - if (elcr_enabled) { - if ((irq <= 2) || (irq == 8) || (irq == 13)) - return 0; - - if (irq > 7) - return !!(elcr[1] & (1 << real_irq)); - - return !!(elcr[0] & (1 << real_irq)); - } else { - if (irq < 8) - return (pic.icw1 & 8) ? 1 : 0; - else - return (pic2.icw1 & 8) ? 1 : 0; - } -} - - -uint8_t -pci_use_mirq(uint8_t mirq) -{ - if (!PCI || !pci_mirqs[mirq].enabled) - return 0; - - if (pci_mirqs[mirq].irq_line & 0x80) - return 0; - - return 1; -} - - void pci_set_mirq(uint8_t mirq, int level) { uint8_t irq_line = 0; + uint8_t irq_bit; - if (! pci_mirqs[mirq].enabled) { - pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq); - return; + if (mirq >= 0xf0) { + irq_line = mirq & 0x0f; + irq_bit = 0x1D; + } else { + if (! pci_mirqs[mirq].enabled) { + pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq); + return; + } + + if (pci_mirqs[mirq].irq_line > 0x0f) { + pci_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq); + return; + } + + irq_line = pci_mirqs[mirq].irq_line; + irq_bit = (0x1E + mirq); } - - if (pci_mirqs[mirq].irq_line > 0x0f) { - pci_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq); - return; - } - - irq_line = pci_mirqs[mirq].irq_line; pci_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - if (level && (pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { + if (level && (pci_irq_hold[irq_line] & (1ULL << irq_bit))) { /* IRQ already held, do nothing. */ pci_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq); + picintlevel(1 << irq_line); return; } pci_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq); @@ -408,12 +576,13 @@ pci_set_mirq(uint8_t mirq, int level) picint(1 << irq_line); } else if (level && pci_irq_hold[irq_line]) { pci_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq); + picintlevel(1 << irq_line); } /* If the IRQ is level-triggered, mark that this MIRQ is holding it. */ if (level) { pci_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq); - pci_irq_hold[irq_line] |= (1ULL << (0x1E + mirq)); + pci_irq_hold[irq_line] |= (1ULL << irq_bit); } pci_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq); @@ -435,7 +604,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } pci_log("pci_set_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - slot = pci_card_to_slot_mapping[card]; + slot = card; if (slot == 0xff) { pci_log("pci_set_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); return; @@ -463,9 +632,10 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } else pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << card))) { + if (level && (pci_irq_hold[irq_line] & (1ULL << slot))) { /* IRQ already held, do nothing. */ pci_log("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); + picintlevel(1 << irq_line); return; } pci_log("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); @@ -480,12 +650,13 @@ pci_set_irq(uint8_t card, uint8_t pci_int) picint(1 << irq_line); } else if (level && pci_irq_hold[irq_line]) { pci_log("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int); + picintlevel(1 << irq_line); } /* If the IRQ is level-triggered, mark that this card is holding it. */ if (level) { pci_log("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int); - pci_irq_hold[irq_line] |= (1ULL << card); + pci_irq_hold[irq_line] |= (1ULL << slot); } else { pci_log("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int); } @@ -496,26 +667,33 @@ void pci_clear_mirq(uint8_t mirq, int level) { uint8_t irq_line = 0; + uint8_t irq_bit; - if (mirq > 1) { - pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq); - return; + if (mirq >= 0xf0) { + irq_line = mirq & 0x0f; + irq_bit = 0x1D; + } else { + if (mirq > 1) { + pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq); + return; + } + + if (! pci_mirqs[mirq].enabled) { + pci_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq); + return; + } + + if (pci_mirqs[mirq].irq_line > 0x0f) { + pci_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq); + return; + } + + irq_line = pci_mirqs[mirq].irq_line; + irq_bit = (0x1E + mirq); } - - if (! pci_mirqs[mirq].enabled) { - pci_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq); - return; - } - - if (pci_mirqs[mirq].irq_line > 0x0f) { - pci_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq); - return; - } - - irq_line = pci_mirqs[mirq].irq_line; pci_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - if (level && !(pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { + if (level && !(pci_irq_hold[irq_line] & (1ULL << irq_bit))) { /* IRQ not held, do nothing. */ pci_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq); return; @@ -523,11 +701,11 @@ pci_clear_mirq(uint8_t mirq, int level) if (level) { pci_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq); - pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq)); + pci_irq_hold[irq_line] &= ~(1 << irq_bit); if (! pci_irq_hold[irq_line]) { pci_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq); - picintc(1 << irq_line); + picintc(1 << irq_line); } else { pci_log("pci_clear_mirq(%02X): IRQ is still being held\n", mirq); } @@ -548,20 +726,20 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) uint8_t level = 0; if (! last_pci_card) { - pci_log("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); + // pci_log("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); return; } - pci_log("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); + // pci_log("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - slot = pci_card_to_slot_mapping[card]; + slot = card; if (slot == 0xff) { - pci_log("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); + // pci_log("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); return; } - pci_log("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); + // pci_log("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); if (! pci_cards[slot].irq_routing[pci_int_index]) { - pci_log("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); + // pci_log("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); return; } @@ -569,54 +747,75 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) irq_line = pci_cards[slot].read(0, 0x3c, pci_cards[slot].priv); else { irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; - pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); + // pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); irq_line = pci_irqs[irq_routing]; level = pci_irq_level[irq_routing]; } if (irq_line > 0x0f) { - pci_log("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); + // pci_log("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); return; } - pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); + // pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (level && !(pci_irq_hold[irq_line] & (1ULL << card))) { + if (level && !(pci_irq_hold[irq_line] & (1ULL << slot))) { /* IRQ not held, do nothing. */ - pci_log("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); + // pci_log("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); return; } if (level) { - pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); - pci_irq_hold[irq_line] &= ~(1 << card); + // pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); + pci_irq_hold[irq_line] &= ~(1 << slot); if (! pci_irq_hold[irq_line]) { - pci_log("pci_clear_irq(%02X, %02X): IRQ no longer held by any card, clearing it\n", card, pci_int); - picintc(1 << irq_line); - } else { - pci_log("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); - } + // pci_log("pci_clear_irq(%02X, %02X): IRQ no longer held by any card, clearing it\n", card, pci_int); + picintc(1 << irq_line); + } // else { + // pci_log("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); + // } } else { - pci_log("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int); + // pci_log("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int); picintc(1 << irq_line); } } -void -pci_elcr_set_enabled(int enabled) +uint8_t +pci_get_int(uint8_t slot, uint8_t pci_int) { - elcr_enabled = enabled; + return pci_cards[slot].irq_routing[pci_int - PCI_INTA]; +} + + +static void +pci_reset_regs(void) +{ + pci_index = pci_card = pci_func = pci_bus = pci_key = 0; + + io_removehandler(0xc000, 0x1000, + pci_type2_read, NULL, NULL, + pci_type2_write, NULL, NULL, NULL); } void -pci_reset(void) +pci_pic_reset(void) +{ + pic_reset(); + pic_set_pci_flag(last_pci_card > 0); +} + + +static void +pci_reset_hard(void) { int i; + pci_reset_regs(); + for (i = 0; i < 16; i++) { if (pci_irq_hold[i]) { pci_irq_hold[i] = 0; @@ -625,7 +824,27 @@ pci_reset(void) } } - elcr_reset(); + pci_pic_reset(); +} + + +void +pci_reset(void) +{ + if (pci_switch) { + pci_pmc = 0x00; + + io_removehandler(0x0cf8, 1, + NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); + io_removehandler(0x0cfc, 4, + pci_read,NULL,NULL, pci_write,NULL,NULL, NULL); + io_sethandler(0x0cf8, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + io_sethandler(0x0cfa, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + } + + pci_reset_hard(); } @@ -634,21 +853,20 @@ pci_slots_clear(void) { uint8_t i, j; - last_pci_card = 0; + last_pci_card = last_normal_pci_card = 0; + last_pci_bus = 1; - for (i = 0; i < 32; i++) { - pci_cards[i].id = 0xFF; - pci_cards[i].type = 0xFF; + for (i = 0; i < 32; i++) + pci_clear_slot(i); - for (j = 0; j < 4; j++) - pci_cards[i].irq_routing[j] = 0; + i = 0; + do { + for (j = 0; j < 32; j++) + pci_card_to_slot_mapping[i][j] = 0xff; + pci_bus_number_to_index_mapping[i] = 0xff; + } while (i++ < 0xff); - pci_cards[i].read = NULL; - pci_cards[i].write = NULL; - pci_cards[i].priv = NULL; - - pci_card_to_slot_mapping[i] = 0xFF; - } + pci_bus_number_to_index_mapping[0] = 0; /* always map bus 0 to index 0 */ } @@ -678,7 +896,9 @@ trc_reset(uint8_t val) { if (val & 2) { dma_reset(); - device_reset_all_pci(); + dma_set_at(1); + + device_reset_all(); cpu_alt_reset = 0; @@ -737,31 +957,42 @@ pci_init(int type) { int c; - PCI = 1; - pci_slots_clear(); - pci_reset(); + pci_reset_hard(); trc_init(); pci_type = type; + pci_switch = !!(type & PCI_CAN_SWITCH_TYPE); - if (!(type & PCI_NO_IRQ_STEERING)) { - io_sethandler(0x04d0, 0x0002, - elcr_read,NULL,NULL, elcr_write,NULL,NULL, NULL); + if (pci_switch) { + pci_pmc = 0x00; + + io_sethandler(0x0cfb, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,pci_type2_writel, NULL); + } + + if (type & PCI_NO_IRQ_STEERING) { + pic_elcr_io_handler(0); + pic_elcr_set_enabled(0); + } else { + pic_elcr_io_handler(1); + pic_elcr_set_enabled(1); } if ((type & PCI_CONFIG_TYPE_MASK) == PCI_CONFIG_TYPE_1) { io_sethandler(0x0cf8, 1, NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); io_sethandler(0x0cfc, 4, - pci_read,NULL,NULL, pci_write,NULL,NULL, NULL); + pci_read,pci_readw,pci_readl, pci_write,pci_writew,pci_writel, NULL); + pci_pmc = 1; } else { io_sethandler(0x0cf8, 1, pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); io_sethandler(0x0cfa, 1, pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + pci_pmc = 0; } for (c = 0; c < 4; c++) { @@ -774,15 +1005,44 @@ pci_init(int type) pci_mirqs[c].irq_line = PCI_IRQ_DISABLED; } - elcr_enabled = 1; + pic_set_pci_flag(1); +} + + +uint8_t +pci_register_bus() +{ + return last_pci_bus++; +} + + +void +pci_remap_bus(uint8_t bus_index, uint8_t bus_number) +{ + uint8_t i = 1; + do { + if (pci_bus_number_to_index_mapping[i] == bus_index) + pci_bus_number_to_index_mapping[i] = 0xff; + } while (i++ < 0xff); + + if ((bus_number > 0) && (bus_number < 0xff)) + pci_bus_number_to_index_mapping[bus_number] = bus_index; } void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) +{ + pci_register_bus_slot(0, card, type, inta, intb, intc, intd); +} + + +void +pci_register_bus_slot(int bus, int card, int type, int inta, int intb, int intc, int intd) { pci_card_t *dev = &pci_cards[last_pci_card]; + dev->bus = bus; dev->id = card; dev->type = type; dev->irq_routing[0] = inta; @@ -792,54 +1052,79 @@ pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) dev->read = NULL; dev->write = NULL; dev->priv = NULL; - pci_card_to_slot_mapping[card] = last_pci_card; + pci_card_to_slot_mapping[bus][card] = last_pci_card; - pci_log("pci_register_slot(): pci_cards[%i].id = %02X\n", last_pci_card, card); + pci_log("pci_register_slot(): pci_cards[%i].bus = %02X; .id = %02X\n", last_pci_card, bus, card); + if (type == PCI_CARD_NORMAL) + last_normal_pci_card = last_pci_card; last_pci_card++; } +uint8_t +pci_find_slot(uint8_t add_type, uint8_t ignore_slot) +{ + pci_card_t *dev; + uint8_t i, ret = 0xff; + + for (i = 0; i < last_pci_card; i++) { + dev = &pci_cards[i]; + + if (!dev->read && !dev->write && ((ignore_slot == 0xff) || (i != ignore_slot))) { + if (add_type & PCI_ADD_STRICT) { + if (dev->type == (add_type & 0x7f)) { + ret = i; + break; + } + } else { + if (((dev->type == PCI_CARD_NORMAL) && ((add_type & 0x7f) >= PCI_ADD_NORMAL)) || + (dev->type == (add_type & 0x7f))) { + ret = i; + break; + } + } + } + } + + return ret; +} + + uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) { pci_card_t *dev; - uint8_t i; + uint8_t i, j; - if (add_type < PCI_ADD_NORMAL) + if (add_type < PCI_ADD_AGP) pci_log("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type); - if (! PCI) { - pci_log("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); - return 0xff; - } - if (! last_pci_card) { - pci_log("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); + pci_log("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_AGP) ? "AGP" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC"))))); return 0xff; } - for (i = 0; i < last_pci_card; i++) { + /* First, find the next available slot. */ + i = pci_find_slot(add_type, 0xff); + + if (i != 0xff) { dev = &pci_cards[i]; + j = pci_find_slot(add_type, i); - if (!dev->read && !dev->write) { - if (((dev->type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || - ((dev->type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) || - ((dev->type == PCI_CARD_SCSI) && (add_type == PCI_ADD_SCSI)) || - ((dev->type == PCI_CARD_SOUND) && (add_type == PCI_ADD_SOUND)) || - ((dev->type == PCI_CARD_NORTHBRIDGE) && (add_type == PCI_ADD_NORTHBRIDGE)) || - ((dev->type == PCI_CARD_SOUTHBRIDGE) && (add_type == PCI_ADD_SOUTHBRIDGE)) || - ((dev->id == add_type) && (add_type < PCI_ADD_NORTHBRIDGE))) { - dev->read = read; - dev->write = write; - dev->priv = priv; - pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); - return dev->id; - } + if (!(pci_type & PCI_NO_BRIDGES) && (dev->type == PCI_CARD_NORMAL) && (add_type != PCI_ADD_BRIDGE) && (j == 0xff)) { + pci_log("pci_add_card(): Reached last NORMAL slot, adding bridge to pci_cards[%i]\n", i); + device_add_inst(&dec21150_device, last_pci_bus); + i = pci_find_slot(add_type, 0xff); + dev = &pci_cards[i]; } - } - pci_log("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC")))); + dev->read = read; + dev->write = write; + dev->priv = priv; + pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (bus %02X slot %02X) [%s]\n", i, dev->bus, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_AGP) ? "AGP" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : ((add_type == PCI_ADD_SOUND) ? "SOUND" : "SPECIFIC"))))); + return i; + } return 0xff; } diff --git a/src/pci_dummy.c b/src/pci_dummy.c index 066f18dcc..d843b9ee9 100644 --- a/src/pci_dummy.c +++ b/src/pci_dummy.c @@ -100,12 +100,12 @@ static void pci_dummy_writel(uint16_t Port, uint32_t Val, void *p) static void pci_dummy_io_remove(void) { - io_removehandler(pci_bar[0].addr, 0x0020, pci_dummy_read, pci_dummy_readw, pci_dummy_readl, pci_dummy_write, pci_dummy_writew, pci_dummy_writel, NULL); + io_removehandler(pci_bar[0].addr, 0x0020, pci_dummy_read, pci_dummy_readw, pci_dummy_readl, pci_dummy_write, pci_dummy_writew, pci_dummy_writel, NULL); } static void pci_dummy_io_set(void) { - io_sethandler(pci_bar[0].addr, 0x0020, pci_dummy_read, pci_dummy_readw, pci_dummy_readl, pci_dummy_write, pci_dummy_writew, pci_dummy_writel, NULL); + io_sethandler(pci_bar[0].addr, 0x0020, pci_dummy_read, pci_dummy_readw, pci_dummy_readl, pci_dummy_write, pci_dummy_writew, pci_dummy_writel, NULL); } diff --git a/src/pic.c b/src/pic.c index 4e723a12a..fe6b29fc8 100644 --- a/src/pic.c +++ b/src/pic.c @@ -6,19 +6,22 @@ * * This file is part of the 86Box distribution. * - * Implementation of the Intel PIC chip emulation. + * Implementation of the Intel PIC chip emulation, partially + * ported from reenigne's XTCE. * + * Authors: Andrew Jenner, + * Miran Grca, * - * - * Author: Miran Grca, - * + * Copyright 2015-2020 Andrew Jenner. * Copyright 2016-2020 Miran Grca. */ #include -#include #include +#include +#include #include #include + #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -28,17 +31,34 @@ #include <86box/pic.h> #include <86box/timer.h> #include <86box/pit.h> +#include <86box/device.h> +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> -int output; -int intclear; -int keywaiting = 0; -int pic_intpending; -PIC pic, pic2; -uint16_t pic_current; +enum +{ + STATE_NONE = 0, + STATE_ICW2, + STATE_ICW3, + STATE_ICW4 +}; -static int shadow = 0; +pic_t pic, pic2; + + +static pc_timer_t pic_timer; + +static int shadow = 0, elcr_enabled = 0, + tmr_inited = 0, latched = 0, + pic_pci = 0; + +static uint16_t smi_irq_mask = 0x0000, + smi_irq_status = 0x0000; + +static void (*update_pending)(void); #ifdef ENABLE_PIC_LOG @@ -61,46 +81,221 @@ pic_log(const char *fmt, ...) #endif -int picinterrupt_poll(int is_pic2); +void +pic_reset_smi_irq_mask(void) +{ + smi_irq_mask = 0x0000; +} void -pic_updatepending() +pic_set_smi_irq_mask(int irq, int set) { - uint16_t temp_pending = 0; - if (AT) { - if ((pic2.pend & ~pic2.mask) & ~pic2.mask2) - pic.pend |= pic.icw3; + if ((irq >= 0) && (irq <= 15)) { + if (set) + smi_irq_mask |= (1 << irq); else - pic.pend &= ~pic.icw3; + smi_irq_mask &= ~(1 << irq); } - pic_intpending = (pic.pend & ~pic.mask) & ~pic.mask2; - if (AT) { - if (!((pic.mask | pic.mask2) & pic.icw3)) { - temp_pending = ((pic2.pend&~pic2.mask)&~pic2.mask2); - temp_pending <<= 8; - pic_intpending |= temp_pending; +} + +uint16_t +pic_get_smi_irq_status(void) +{ + return smi_irq_status; +} + + +void +pic_clear_smi_irq_status(int irq) +{ + if ((irq >= 0) && (irq <= 15)) + smi_irq_status &= ~(1 << irq); +} + + +void +pic_elcr_write(uint16_t port, uint8_t val, void *priv) +{ + pic_t *dev = (pic_t *) priv; + + pic_log("ELCR%i: WRITE %02X\n", port & 1, val); + + if (port & 1) + val &= 0xde; + else + val &= 0xf8; + + dev->elcr = val; + + pic_log("ELCR %i: %c %c %c %c %c %c %c %c\n", + port & 1, + (val & 1) ? 'L' : 'E', + (val & 2) ? 'L' : 'E', + (val & 4) ? 'L' : 'E', + (val & 8) ? 'L' : 'E', + (val & 0x10) ? 'L' : 'E', + (val & 0x20) ? 'L' : 'E', + (val & 0x40) ? 'L' : 'E', + (val & 0x80) ? 'L' : 'E'); +} + + +uint8_t +pic_elcr_read(uint16_t port, void *priv) +{ + pic_t *dev = (pic_t *) priv; + + pic_log("ELCR%i: READ %02X\n", port & 1, dev->elcr); + + return dev->elcr; +} + + +int +pic_elcr_get_enabled(void) +{ + return elcr_enabled; +} + + +void +pic_elcr_set_enabled(int enabled) +{ + elcr_enabled = enabled; +} + + +void +pic_elcr_io_handler(int set) +{ + io_handler(set, 0x04d0, 0x0001, + pic_elcr_read, NULL, NULL, + pic_elcr_write, NULL, NULL, &pic); + io_handler(set, 0x04d1, 0x0001, + pic_elcr_read, NULL, NULL, + pic_elcr_write, NULL, NULL, &pic2); +} + + +static uint8_t +pic_cascade_mode(pic_t *dev) +{ + return !(dev->icw1 & 2); +} + + +static __inline uint8_t +pic_slave_on(pic_t *dev, int channel) +{ + pic_log("pic_slave_on(%i): %i, %02X, %02X\n", channel, pic_cascade_mode(dev), dev->icw4 & 0x0c, dev->icw3 & (1 << channel)); + + return pic_cascade_mode(dev) && (dev->is_master || ((dev->icw4 & 0x0c) == 0x0c)) && + (dev->icw3 & (1 << channel)); +} + + +static __inline int +find_best_interrupt(pic_t *dev) +{ + uint8_t b; + uint8_t intr; + int i, j; + int ret = -1; + + for (i = 0; i < 8; i++) { + j = (i + dev->priority) & 7; + b = 1 << j; + + if (dev->isr & b) + break; + else if ((dev->state == 0) && ((dev->irr & ~dev->imr) & b)) { + ret = j; + break; } } - pic_log("pic_intpending = %i %02X %02X %02X %02X\n", pic_intpending, pic.ins, pic.pend, pic.mask, pic.mask2); - pic_log(" %02X %02X %02X %02X %i %i\n", pic2.ins, pic2.pend, pic2.mask, pic2.mask2, ((pic.mask | pic.mask2) & (1 << 2)), ((pic2.pend&~pic2.mask)&~pic2.mask2)); + + intr = dev->interrupt = (ret == -1) ? 0x17 : ret; + + if (dev->at && (ret != 1)) { + if (dev == &pic2) + intr += 8; + + if (cpu_fast_off_flags & (1u << intr)) + cpu_fast_off_advance(); + } + + return ret; +} + + +static __inline void +pic_update_pending_xt(void) +{ + if (find_best_interrupt(&pic) != -1) { + latched++; + if (latched == 1) + timer_on_auto(&pic_timer, 0.35); + } else if (latched == 0) + pic.int_pending = 0; +} + + +static __inline void +pic_update_pending_at(void) +{ + pic2.int_pending = (find_best_interrupt(&pic2) != -1); + + if (pic2.int_pending) + pic.irr |= (1 << pic2.icw3); + else + pic.irr &= ~(1 << pic2.icw3); + + pic.int_pending = (find_best_interrupt(&pic) != -1); +} + + +static void +pic_callback(void *priv) +{ + pic_t *dev = (pic_t *) priv; + + dev->int_pending = 1; + + latched--; + if (latched > 0) + timer_on_auto(&pic_timer, 0.35); } void pic_reset() { - pic.icw=0; - pic.mask=0xFF; - pic.mask2=0; - pic.pend=pic.ins=0; - pic.vector=8; - pic.read=1; - pic2.icw=0; - pic2.mask=0xFF; - pic.mask2=0; - pic2.pend=pic2.ins=0; - pic_intpending = 0; + int is_at = IS_AT(machine); + is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088"); + + memset(&pic, 0, sizeof(pic_t)); + memset(&pic2, 0, sizeof(pic_t)); + + pic.is_master = 1; + pic.interrupt = pic2.interrupt = 0x17; + + if (is_at) + pic.slaves[2] = &pic2; + + if (tmr_inited) + timer_on_auto(&pic_timer, 0.0); + memset(&pic_timer, 0x00, sizeof(pc_timer_t)); + timer_add(&pic_timer, pic_callback, &pic, 0); + tmr_inited = 1; + + update_pending = is_at ? pic_update_pending_at : pic_update_pending_xt; + pic.at = pic2.at = is_at; + + smi_irq_mask = smi_irq_status = 0x0000; + + shadow = 0; + pic_pci = 0; } @@ -112,511 +307,426 @@ pic_set_shadow(int sh) void -pic_update_mask(uint8_t *mask, uint8_t ins) +pic_set_pci_flag(int pci) { - int c; - *mask = 0; - for (c = 0; c < 8; c++) { - if (ins & (1 << c)) { - *mask = 0xff << c; - return; - } - } + pic_pci = pci; } -static int -picint_is_level(uint16_t irq) +static uint8_t +pic_level_triggered(pic_t *dev, int irq) { - if (PCI) - return pci_irq_is_level(irq); - else { - if (irq < 8) - return (pic.icw1 & 8) ? 1 : 0; - else - return (pic2.icw1 & 8) ? 1 : 0; - } + if (elcr_enabled) + return !!(dev->elcr & (1 << irq)); + else + return !!(dev->icw1 & 8); +} + + +int +picint_is_level(int irq) +{ + return pic_level_triggered(((irq > 7) ? &pic2 : &pic), irq & 7); } -/* Should this really EOI *ALL* IRQ's at once? */ static void -pic_autoeoi() +pic_acknowledge(pic_t *dev) { - int c; + int pic_int = dev->interrupt & 7; + int pic_int_num = 1 << pic_int; - for (c = 0; c < 8; c++) { - if (pic.ins & ( 1 << c)) { - pic.ins &= ~(1 << c); - pic_update_mask(&pic.mask2, pic.ins); + dev->isr |= pic_int_num; + if (!pic_level_triggered(dev, pic_int) || !(dev->lines & pic_int_num)) + dev->irr &= ~pic_int_num; +} - if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) - pic.pend |= pic.icw3; - } - pic_updatepending(); - return; +/* Find IRQ for non-specific EOI (either by command or automatic) by finding the highest IRQ + priority with ISR bit set, that is also not masked if the PIC is in special mask mode. */ +static uint8_t +pic_non_specific_find(pic_t *dev) +{ + int i, j; + uint8_t b, irq = 0xff; + + for (i = 0; i < 8; i++) { + j = (i + dev->priority) & 7; + b = (1 << j); + + if ((dev->isr & b) && (!dev->special_mask_mode || !(dev->imr & b))) { + irq = j; + break; } } + + return irq; +} + + +/* Do the EOI and rotation, if either is requested, on the given IRQ. */ +static void +pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate) +{ + uint8_t b = (1 << irq); + + if (irq != 0xff) { + if (eoi) + dev->isr &= ~b; + if (rotate) + dev->priority = (irq + 1) & 7; + + update_pending(); + } } -void -pic_write(uint16_t addr, uint8_t val, void *priv) +/* Automatic non-specific EOI. */ +static __inline void +pic_auto_non_specific_eoi(pic_t *dev) { - int c; + uint8_t irq; - addr &= ~0x06; + if (dev->icw4 & 2) { + irq = pic_non_specific_find(dev); - if (addr&1) { - pic_log("%04X:%04X: write: %02X\n", CS, cpu_state.pc, val); - switch (pic.icw) { - case 0: /*OCW1*/ - pic.mask=val; - pic_updatepending(); - break; - case 1: /*ICW2*/ - pic.vector=val&0xF8; - pic_log("ICW%i ->", pic.icw + 1); - if (pic.icw1 & 2) pic.icw=3; - else pic.icw=2; - pic_log("ICW%i\n", pic.icw + 1); - break; - case 2: /*ICW3*/ - pic.icw3 = val; - pic_log("PIC1 ICW3 now %02X\n", val); - pic_log("ICW%i ->", pic.icw + 1); - if (pic.icw1 & 1) pic.icw=3; - else pic.icw=0; - pic_log("ICW%i\n", pic.icw + 1); - break; - case 3: /*ICW4*/ - pic_log("ICW%i ->", pic.icw + 1); - pic.icw4 = val; - pic.icw=0; - pic_log("ICW%i\n", pic.icw + 1); - break; - } - } else { - if (val & 16) { /*ICW1*/ - pic.mask = 0; - pic.mask2 = 0; - pic_log("ICW%i ->", pic.icw + 1); - pic.icw = 1; - pic.icw1 = val; - pic_log("ICW%i\n", pic.icw + 1); - pic.ins = 0; - pic.pend = 0; /* Pending IRQ's are cleared. */ - pic_updatepending(); - } - else if (!(val & 8)) { /*OCW2*/ - pic.ocw2 = val; - if ((val & 0xE0) == 0x60) { - pic.ins &= ~(1 << (val & 7)); - pic_update_mask(&pic.mask2, pic.ins); - if (AT) { - if (((val&7) == pic2.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) - pic.pend |= pic.icw3; - } - - pic_updatepending(); - } else { - for (c = 0; c < 8; c++) { - if (pic.ins & (1 << c)) { - pic.ins &= ~(1 << c); - pic_update_mask(&pic.mask2, pic.ins); - - if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) - pic.pend |= pic.icw3; - } - - if ((c == 1) && keywaiting) - intclear &= ~1; - pic_updatepending(); - return; - } - } - } - } else { /*OCW3*/ - pic.ocw3 = val; - if (val & 4) - pic.read=4; - if (val & 2) - pic.read=(val & 1); - } + pic_action(dev, irq, 1, dev->auto_eoi_rotate); } } +/* Do the PIC command specified by bits 7-5 of the value written to the OCW2 register. */ +static void +pic_command(pic_t *dev) +{ + uint8_t irq = 0xff; + + if (dev->ocw2 & 0x60) { /* SL and/or EOI set */ + if (dev->ocw2 & 0x40) /* SL set, specific priority level */ + irq = (dev->ocw2 & 0x07); + else /* SL clear, non-specific priority level (find highest with ISR set) */ + irq = pic_non_specific_find(dev); + + pic_action(dev, irq, dev->ocw2 & 0x20, dev->ocw2 & 0x80); + } else /* SL and EOI clear */ + dev->auto_eoi_rotate = !!(dev->ocw2 & 0x80); +} + + uint8_t pic_read(uint16_t addr, void *priv) { - uint8_t ret = 0xff; - int temp; + pic_t *dev = (pic_t *) priv; - if ((addr == 0x20) && shadow) { - ret = ((pic.ocw3 & 0x20) >> 5) << 4; - ret |= ((pic.ocw2 & 0x80) >> 7) << 3; - ret |= ((pic.icw4 & 0x10) >> 4) << 2; - ret |= ((pic.icw4 & 0x02) >> 1) << 1; - ret |= ((pic.icw4 & 0x08) >> 3) << 0; - } else if ((addr == 0x21) && shadow) - ret = ((pic.vector & 0xf8) >> 3) << 0; - else if (addr & 1) - ret = pic.mask; - else if (pic.read & 4) { - temp = picinterrupt_poll(0); - if (temp >= 0) - ret = temp | 0x80; - else - ret = 0x00; - } else if (pic.read) { - if (AT) - ret = pic.ins | (pic2.ins ? 4 : 0); - else - ret = pic.ins; - } else - ret = pic.pend; + if (shadow) { + /* VIA PIC shadow read */ + if (addr & 0x0001) + dev->data_bus = ((dev->icw2 & 0xf8) >> 3) << 0; + else { + dev->data_bus = ((dev->ocw3 & 0x20) >> 5) << 4; + dev->data_bus |= ((dev->ocw2 & 0x80) >> 7) << 3; + dev->data_bus |= ((dev->icw4 & 0x10) >> 4) << 2; + dev->data_bus |= ((dev->icw4 & 0x02) >> 1) << 1; + dev->data_bus |= ((dev->icw4 & 0x08) >> 3) << 0; + } + } else { + /* Standard 8259 PIC read */ +#ifndef UNDEFINED_READ + /* Put the IRR on to the data bus by default until the real PIC is probed. */ + dev->data_bus = dev->irr; +#endif + if (dev->ocw3 & 0x04) { + if (dev->int_pending) { + dev->data_bus = 0x80 | (dev->interrupt & 7); + pic_acknowledge(dev); + dev->int_pending = 0; + update_pending(); + } else + dev->data_bus = 0x00; + dev->ocw3 &= ~0x04; + } else if (addr & 0x0001) + dev->data_bus = dev->imr; + else if (dev->ocw3 & 0x02) { + if (dev->ocw3 & 0x01) + dev->data_bus = dev->isr; +#ifdef UNDEFINED_READ + else + dev->data_bus = 0x00; +#endif + } + /* If A0 = 0, VIA shadow is disabled, and poll mode is disabled, + simply read whatever is currently on the data bus. */ + } - pic_log("%04X:%04X: Read PIC 1 port %04X, value %02X\n", CS, cpu_state.pc, addr, val); + pic_log("pic_read(%04X, %08X) = %02X\n", addr, priv, dev->data_bus); - return ret; -} - - -void -pic_init() -{ - shadow = 0; - io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); -} - - -void -pic_init_pcjr() -{ - shadow = 0; - io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); + return dev->data_bus; } static void -pic2_autoeoi() +pic_write(uint16_t addr, uint8_t val, void *priv) { - int c; + pic_t *dev = (pic_t *) priv; - for (c = 0; c < 8; c++) { - if (pic2.ins & (1 << c)) { - pic2.ins &= ~(1 << c); - pic_update_mask(&pic2.mask2, pic2.ins); + pic_log("pic_write(%04X, %02X, %08X)\n", addr, val, priv); - pic_updatepending(); - return; - } - } -} + dev->data_bus = val; - -void -pic2_write(uint16_t addr, uint8_t val, void *priv) -{ - int c; - if (addr & 1) { - switch (pic2.icw) { - case 0: /*OCW1*/ - pic2.mask=val; - pic_updatepending(); + if (addr & 0x0001) { + switch (dev->state) { + case STATE_ICW2: + dev->icw2 = val; + if (pic_cascade_mode(dev)) + dev->state = STATE_ICW3; + else + dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE; break; - case 1: /*ICW2*/ - pic2.vector=val & 0xF8; - pic_log("PIC2 vector now: %02X\n", pic2.vector); - if (pic2.icw1 & 2) pic2.icw=3; - else pic2.icw=2; + case STATE_ICW3: + dev->icw3 = val; + dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE; break; - case 2: /*ICW3*/ - pic2.icw3 = val; - pic_log("PIC2 ICW3 now %02X\n", val); - if (pic2.icw1 & 1) pic2.icw=3; - else pic2.icw=0; + case STATE_ICW4: + dev->icw4 = val; + dev->state = STATE_NONE; break; - case 3: /*ICW4*/ - pic2.icw4 = val; - pic2.icw=0; + case STATE_NONE: + dev->imr = val; + update_pending(); break; } } else { - if (val & 16) { /*ICW1*/ - pic2.mask = 0; - pic2.mask2 = 0; - pic2.icw = 1; - pic2.icw1 = val; - pic2.ins = 0; - pic2.pend = 0; /* Pending IRQ's are cleared. */ - pic.pend &= ~4; - pic_updatepending(); - } else if (!(val & 8)) { /*OCW2*/ -#ifdef ENABLE_PIC_LOG - switch ((val >> 5) & 0x07) { - case 0x00: - pic_log("Rotate in automatic EOI mode (clear)\n"); - break; - case 0x01: - pic_log("Non-specific EOI command\n"); - break; - case 0x02: - pic_log("No operation\n"); - break; - case 0x03: - pic_log("Specific EOI command\n"); - break; - case 0x04: - pic_log("Rotate in automatic EOI mode (set)\n"); - break; - case 0x05: - pic_log("Rotate on on-specific EOI command\n"); - break; - case 0x06: - pic_log("Set priority command\n"); - break; - case 0x07: - pic_log("Rotate on specific EOI command\n"); - break; - } -#endif + if (val & 0x10) { + /* Treat any write with any of the bits 7 to 5 set as invalid if PCI. */ + if (pic_pci && (val & 0xe0)) + return; - pic2.ocw2 = val; - if ((val & 0xE0) == 0x60) { - pic2.ins &= ~(1 << (val & 7)); - pic_update_mask(&pic2.mask2, pic2.ins); - - pic_updatepending(); - } else { - for (c = 0; c < 8; c++) { - if (pic2.ins&(1<icw1 = val; + dev->icw2 = dev->icw3 = 0x00; + if (!(dev->icw1 & 1)) + dev->icw4 = 0x00; + dev->ocw2 = dev->ocw3 = 0x00; + dev->irr = dev->lines; + dev->imr = dev->isr = 0x00; + dev->ack_bytes = dev->priority = 0x00; + dev->auto_eoi_rotate = dev->special_mask_mode = 0x00; + dev->interrupt = 0x17; + dev->int_pending = 0x00; + dev->state = STATE_ICW2; + update_pending(); + } else if (val & 0x08) { + dev->ocw3 = val; + if (dev->ocw3 & 0x40) + dev->special_mask_mode = !!(dev->ocw3 & 0x20); + } else { + dev->ocw2 = val; + pic_command(dev); } } } -uint8_t -pic2_read(uint16_t addr, void *priv) +void +pic_set_pci(void) { - uint8_t ret = 0xff; - int temp; + int i; - if ((addr == 0xa0) && shadow) { - ret = ((pic2.ocw3 & 0x20) >> 5) << 4; - ret |= ((pic2.ocw2 & 0x80) >> 7) << 3; - ret |= ((pic2.icw4 & 0x10) >> 4) << 2; - ret |= ((pic2.icw4 & 0x02) >> 1) << 1; - ret |= ((pic2.icw4 & 0x08) >> 3) << 0; - } else if ((addr == 0xa1) && shadow) - ret = ((pic2.vector & 0xf8) >> 3) << 0; - else if (addr & 1) - ret = pic2.mask; - else if (pic2.read & 4) { - temp = picinterrupt_poll(1); - if (temp >= 0) - ret = (temp | 0x80); - else - ret = 0x00; - } else if (pic2.read) - ret = pic2.ins; - else - ret = pic2.pend; + for (i = 0x0024; i < 0x0040; i += 4) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } - pic_log("%04X:%04X: Read PIC 2 port %04X, value %02X\n", CS, cpu_state.pc, addr, val); - - return ret; + for (i = 0x1120; i < 0x1140; i += 4) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } } void -pic2_init() +pic_init(void) { - io_sethandler(0x00a0, 0x0002, pic2_read, NULL, NULL, pic2_write, NULL, NULL, NULL); + pic_reset(); + + shadow = 0; + io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); } void -clearpic() +pic_init_pcjr(void) { - pic.pend=pic.ins=pic_current=0; - pic_updatepending(); + pic_reset(); + + shadow = 0; + io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); } void -picint_common(uint16_t num, int level) +pic2_init(void) { - int c = 0; + io_sethandler(0x00a0, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + pic.slaves[2] = &pic2; +} + + +void +picint_common(uint16_t num, int level, int set) +{ + int i, raise; + uint8_t b, slaves = 0; + + /* Make sure to ignore all slave IRQ's, and in case of AT+, + translate IRQ 2 to IRQ 9. */ + for (i = 0; i < 8; i++) { + b = (1 << i); + raise = num & b; + + if (pic.icw3 & b) { + slaves++; + + if (raise) { + num &= ~b; + if (pic.at && (i == 2)) + num |= (1 << 9); + } + } + } + + if (!slaves) + num &= 0x00ff; if (!num) { - pic_log("Attempting to raise null IRQ\n"); + pic_log("Attempting to %s null IRQ\n", set ? "raise" : "lower"); return; } - if (AT && (num == pic.icw3) && (pic.icw3 == 4)) - num = 1 << 9; + if (num & 0x0100) + acpi_rtc_status = !!set; - while (!(num & (1 << c))) - c++; + if (set) { + if (smi_irq_mask & num) { + smi_raise(); + smi_irq_status |= num; + } - if (AT && (num == pic.icw3) && (pic.icw3 != 4)) { - pic_log("Attempting to raise cascaded IRQ %i\n"); - return; + if (num & 0xff00) { + if (level) + pic2.lines |= (num >> 8); + + pic2.irr |= (num >> 8); + } + + if (num & 0x00ff) { + if (level) + pic.lines |= (num >> 8); + + pic.irr |= num; + } + } else { + smi_irq_status &= ~num; + + if (num & 0xff00) { + pic2.lines &= ~(num >> 8); + pic2.irr &= ~(num >> 8); + } + + if (num & 0x00ff) { + pic.lines &= ~num; + pic.irr &= ~num; + } } - if (!(pic_current & num) || !level) { - pic_log("Raising IRQ %i\n", c); - - if (level) - pic_current |= num; - - if (AT && (cpu_fast_off_flags & num)) - cpu_fast_off_count = cpu_fast_off_val + 1; - - if (num>0xFF) { - if (!AT) - return; - - pic2.pend|=(num>>8); - if ((pic2.pend&~pic2.mask)&~pic2.mask2) - pic.pend |= (1 << pic2.icw3); - } else - pic.pend|=num; - - pic_updatepending(); - } + if (!(pic.interrupt & 0x20) && !(pic2.interrupt & 0x20)) + update_pending(); } void picint(uint16_t num) { - picint_common(num, 0); + picint_common(num, 0, 1); } void picintlevel(uint16_t num) { - picint_common(num, 1); + picint_common(num, 1, 1); } void picintc(uint16_t num) { - int c = 0; - - if (!num) { - pic_log("Attempting to lower null IRQ\n"); - return; - } - - if (AT && (num == pic.icw3) && (pic.icw3 == 4)) - num = 1 << 9; - - while (!(num & (1 << c))) - c++; - - if (AT && (num == pic.icw3) && (pic.icw3 != 4)) { - pic_log("Attempting to lower cascaded IRQ %i\n"); - return; - } - - if (pic_current & num) - pic_current &= ~num; - - pic_log("Lowering IRQ %i\n", c); - - if (num > 0xff) { - if (!AT) - return; - - pic2.pend &= ~(num >> 8); - if (!((pic2.pend&~pic2.mask)&~pic2.mask2)) - pic.pend &= ~(1 << pic2.icw3); - } else - pic.pend&=~num; - - pic_updatepending(); + picint_common(num, 0, 0); } -static int -pic_process_interrupt(PIC* target_pic, int c) +static uint8_t +pic_i86_mode(pic_t *dev) { - uint8_t pending = target_pic->pend & ~target_pic->mask; - int ret = -1; - /* TODO: On init, a PIC need to get a pointer to one of these, and rotate as needed - if in rotate mode. */ - /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ - int priority_xt[16] = { 7, 6, 5, 4, 3, 2, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1 }; - int priority_at[16] = { 14, 13, -1, 4, 3, 2, 1, 0, 12, 11, 10, 9, 8, 7, 6, 5 }; - int i; + return !!(dev->icw4 & 1); +} - int pic_int = c & 7; - int pic_int_num = 1 << pic_int; - int in_service = 0; +static uint8_t +pic_irq_ack_read(pic_t *dev, int phase) +{ + uint8_t intr = dev->interrupt & 0x47; + uint8_t slave = intr & 0x40; + intr &= 0x07; + pic_log(" pic_irq_ack_read(%08X, %i)\n", dev, phase); - if (AT) { - for (i = 0; i < 16; i++) { - if ((priority_at[i] != -1) && (priority_at[i] >= priority_at[c])) { - if (i < 8) - in_service |= (pic.ins & (1 << i)); - else - in_service |= (pic2.ins & (1 << i)); - } - } - } else { - for (i = 0; i < 16; i++) { - if ((priority_xt[i] != -1) && (priority_xt[i] >= priority_xt[c])) - in_service |= (pic.ins & (1 << i)); + if (dev != NULL) { + if (phase == 0) { + dev->interrupt |= 0x20; /* Freeze it so it still takes interrupts but they do not + override the one currently being processed. */ + pic_acknowledge(dev); + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else + dev->data_bus = pic_i86_mode(dev) ? 0xff : 0xcd; + } else if (pic_i86_mode(dev)) { + dev->int_pending = 0; + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else + dev->data_bus = intr + (dev->icw2 & 0xf8); + pic_auto_non_specific_eoi(dev); + } else if (phase == 1) { + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else if (dev->icw1 & 0x04) + dev->data_bus = (intr << 2) + (dev->icw1 & 0xe0); + else + dev->data_bus = (intr << 3) + (dev->icw1 & 0xc0); + } else if (phase == 2) { + dev->int_pending = 0; + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else + dev->data_bus = dev->icw2; + pic_auto_non_specific_eoi(dev); } } - if ((pending & pic_int_num) && !in_service) { - if (!((pic_current & (1 << c)) && picint_is_level(c))) - target_pic->pend &= ~pic_int_num; - else if (!picint_is_level(c)) - target_pic->pend &= ~pic_int_num; - target_pic->ins |= pic_int_num; - pic_update_mask(&target_pic->mask2, target_pic->ins); + return dev->data_bus; +} - if (AT && (c >= 8)) { - if (!((target_pic->pend & ~target_pic->mask) & ~target_pic->mask2)) - pic.pend &= ~(1 << pic2.icw3); - pic.ins |= (1 << pic2.icw3); /*Cascade IRQ*/ - pic_update_mask(&pic.mask2, pic.ins); - } - pic_updatepending(); +uint8_t +pic_irq_ack(void) +{ + int ret; - if (target_pic->icw4 & 0x02) - (AT && (c >= 8)) ? pic2_autoeoi() : pic_autoeoi(); + ret = pic_irq_ack_read(&pic, pic.ack_bytes); + pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); - if (!c && (pit2 != NULL)) - pit_ctr_set_gate(&pit2->counters[0], 0); - - ret = pic_int + target_pic->vector; + if (pic.ack_bytes == 0) { + pic.interrupt = 0x17; + update_pending(); } return ret; @@ -626,54 +736,36 @@ pic_process_interrupt(PIC* target_pic, int c) int picinterrupt() { - int c, d; - int ret; + int i, ret = -1; - for (c = 0; c <= 7; c++) { - if (AT && ((1 << c) == pic.icw3)) { - for (d = 8; d <= 15; d++) { - ret = pic_process_interrupt(&pic2, d); - if (ret != -1) return ret; + if (pic.int_pending) { + if (pic_slave_on(&pic, pic.interrupt)) { + if (!pic.slaves[pic.interrupt]->int_pending) { + /* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */ + fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt); + exit(-1); + return -1; + } + + pic.interrupt |= 0x40; /* Mark slave pending. */ + } + + if ((pic.interrupt == 0) && (pit_devs[1].data != NULL)) + pit_devs[1].set_gate(pit_devs[1].data, 0, 0); + + /* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */ + for (i = 0; i < 2; i++) { + ret = pic_irq_ack_read(&pic, pic.ack_bytes); + pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); + + if (pic.ack_bytes == 0) { + if (pic.interrupt & 0x40) + pic2.interrupt = 0x17; + pic.interrupt = 0x17; + update_pending(); } - } else { - ret = pic_process_interrupt(&pic, c); - if (ret != -1) return ret; } } - return -1; -} - - -int -picinterrupt_poll(int is_pic2) -{ - int c, d; - int ret; - - if (is_pic2) - pic2.read &= ~4; - else - pic.read &= ~4; - - for (c = 0; c <= 7; c++) { - if (AT && ((1 << c) == pic.icw3)) { - for (d = 8; d <= 15; d++) { - ret = pic_process_interrupt(&pic2, d); - if ((ret != -1) && is_pic2) return c & 7; - } - } else { - ret = pic_process_interrupt(&pic, c); - if ((ret != -1) && !is_pic2) return c; - } - } - return -1; -} - - -void -dumppic() -{ - pic_log("PIC1 : MASK %02X PEND %02X INS %02X LEVEL %02X VECTOR %02X CASCADE %02X\n", pic.mask, pic.pend, pic.ins, (pic.icw1 & 8) ? 1 : 0, pic.vector, pic.icw3); - if (AT) - pic_log("PIC2 : MASK %02X PEND %02X INS %02X LEVEL %02X VECTOR %02X CASCADE %02X\n", pic2.mask, pic2.pend, pic2.ins, (pic2.icw1 & 8) ? 1 : 0, pic2.vector, pic2.icw3); + + return ret; } diff --git a/src/pit.c b/src/pit.c index 7c6c1923d..ba71928ca 100644 --- a/src/pit.c +++ b/src/pit.c @@ -27,25 +27,27 @@ #include "cpu.h" #include <86box/device.h> #include <86box/timer.h> +#include <86box/cassette.h> #include <86box/dma.h> #include <86box/io.h> #include <86box/nmi.h> #include <86box/pic.h> #include <86box/timer.h> #include <86box/pit.h> +#include <86box/pit_fast.h> #include <86box/ppi.h> #include <86box/machine.h> #include <86box/sound.h> #include <86box/snd_speaker.h> #include <86box/video.h> +pit_intf_t pit_devs[2]; -pit_t *pit, *pit2; double cpuclock, PITCONSTD, SYSCLK, isa_timing, - bus_timing, pci_timing, - PCICLK; + bus_timing, pci_timing, agp_timing, + PCICLK, AGPCLK; uint64_t PITCONST, ISACONST, CGACONST, @@ -53,7 +55,8 @@ uint64_t PITCONST, ISACONST, VGACONST1, VGACONST2, RTCCONST, ACPICONST; -int io_delay = 5; +int refresh_at_enable = 1, + io_delay = 5; int64_t firsttime = 1; @@ -62,12 +65,7 @@ int64_t firsttime = 1; #define PIT_PS2 16 /* The PIT is the PS/2's second PIT. */ #define PIT_EXT_IO 32 /* The PIT has externally specified port I/O. */ #define PIT_CUSTOM_CLOCK 64 /* The PIT uses custom clock inputs provided by another provider. */ - - -enum { - PIT_8253 = 0, - PIT_8254 -}; +#define PIT_SECONDARY 128 /* The PIT is secondary (ports 0048-004B). */ #ifdef ENABLE_PIT_LOG @@ -105,47 +103,26 @@ ctr_set_out(ctr_t *ctr, int out) static void ctr_decrease_count(ctr_t *ctr) { - uint8_t units, tens, hundreds, thousands, myriads; - int dec_cnt = 1; - - if (ctr->ctrl & 0x01) { - units = ctr->count & 0x0f; - tens = (ctr->count >> 4) & 0x0f; - hundreds = (ctr->count >> 8) & 0x0f; - thousands = (ctr->count >> 12) & 0x0f; - myriads = (ctr->count >> 16) & 0x0f; - - dec_cnt -= units; - units = (10 - dec_cnt % 10) % 10; - - dec_cnt = (dec_cnt + 9) / 10; /* The +9 is so we get a carry if dec_cnt % 10 was not a 0. */ - if (dec_cnt <= tens) - tens -= dec_cnt; - else { - dec_cnt -= tens; - tens = (10 - dec_cnt % 10) % 10; - - dec_cnt = (dec_cnt + 9) / 10; - if (dec_cnt <= hundreds) - hundreds -= dec_cnt; - else { - dec_cnt -= hundreds; - hundreds = (10 - dec_cnt % 10) % 10; - - dec_cnt = (dec_cnt + 9) / 10; - if (dec_cnt <= thousands) - thousands -= dec_cnt; - else { - dec_cnt -= thousands; - thousands = (10 - dec_cnt % 10) % 10; - - dec_cnt = (dec_cnt + 9) / 10; - myriads = (10 + myriads - dec_cnt % 10) % 10; + if (ctr->bcd) { + ctr->units--; + if (ctr->units == -1) { + ctr->units = -7; + ctr->tens--; + if (ctr->tens == -1) { + ctr->tens = -7; + ctr->hundreds--; + if (ctr->hundreds == -1) { + ctr->hundreds = -7; + ctr->thousands--; + if (ctr->thousands == -1) { + ctr->thousands = -7; + ctr->myriads--; + if (ctr->myriads == -1) + ctr->myriads = -7; /* 0 - 1 should wrap around to 9999. */ + } } } } - - ctr->count = (myriads << 16) | (thousands << 12) | (hundreds << 8) | (tens << 4) | units; } else ctr->count = (ctr->count - 1) & 0xffff; } @@ -166,14 +143,21 @@ ctr_load_count(ctr_t *ctr) static void ctr_tick(ctr_t *ctr) { + uint8_t state = ctr->state; + + if (state == 1) { + /* This is true for all modes */ + ctr_load_count(ctr); + ctr->state = 2; + if ((ctr->m & 0x07) == 0x01) + ctr_set_out(ctr, 0); + return; + } + switch(ctr->m & 0x07) { case 0: - /*Interrupt on terminal count*/ - switch (ctr->state) { - case 1: - ctr_load_count(ctr); - ctr->state = 2; - break; + /* Interrupt on terminal count */ + switch (state) { case 2: if (ctr->gate && (ctr->count >= 1)) { ctr_decrease_count(ctr); @@ -189,8 +173,8 @@ ctr_tick(ctr_t *ctr) } break; case 1: - /*Hardware retriggerable one-shot*/ - switch (ctr->state) { + /* Hardware retriggerable one-shot */ + switch (state) { case 1: ctr_load_count(ctr); ctr->state = 2; @@ -211,13 +195,12 @@ ctr_tick(ctr_t *ctr) } break; case 2: case 6: - /*Rate generator*/ - switch (ctr->state) { - case 1: case 3: + /* Rate generator */ + switch (state) { + case 3: ctr_load_count(ctr); - if (ctr->state == 3) - ctr_set_out(ctr, 1); ctr->state = 2; + ctr_set_out(ctr, 1); break; case 2: if (ctr->gate == 0) @@ -233,17 +216,18 @@ ctr_tick(ctr_t *ctr) } break; case 3: case 7: - /*Square wave mode*/ - switch (ctr->state) { - case 1: - ctr_load_count(ctr); - ctr->state = 2; - break; + /* Square wave mode */ + switch (state) { case 2: if (ctr->gate == 0) break; else if (ctr->count >= 0) { - ctr->count -= (ctr->newcount ? 1 : 2); + if (ctr->bcd) { + ctr_decrease_count(ctr); + if (!ctr->newcount) + ctr_decrease_count(ctr); + } else + ctr->count -= (ctr->newcount ? 1 : 2); if (ctr->count < 0) { ctr_load_count(ctr); ctr->state = 3; @@ -256,7 +240,13 @@ ctr_tick(ctr_t *ctr) if (ctr->gate == 0) break; else if (ctr->count >= 0) { - ctr->count -= (ctr->newcount ? 3 : 2); + if (ctr->bcd) { + ctr_decrease_count(ctr); + ctr_decrease_count(ctr); + if (ctr->newcount) + ctr_decrease_count(ctr); + } else + ctr->count -= (ctr->newcount ? 3 : 2); if (ctr->count < 0) { ctr_load_count(ctr); ctr->state = 2; @@ -268,17 +258,13 @@ ctr_tick(ctr_t *ctr) } break; case 4: case 5: - /*Software triggered strobe*/ - /*Hardware triggered strobe*/ + /* Software triggered strobe */ + /* Hardware triggered strobe */ if ((ctr->gate != 0) || (ctr->m != 4)) { - switch(ctr->state) { + switch(state) { case 0: ctr_decrease_count(ctr); break; - case 1: - ctr_load_count(ctr); - ctr->state = 2; - break; case 2: if (ctr->count >= 1) { ctr_decrease_count(ctr); @@ -302,8 +288,11 @@ ctr_tick(ctr_t *ctr) static void -ctr_clock(ctr_t *ctr) +ctr_clock(void *data, int counter_id) { + pit_t *pit = (pit_t *)data; + ctr_t *ctr = &pit->counters[counter_id]; + /* FIXME: Is this even needed? */ if ((ctr->state == 3) && (ctr->m != 2) && (ctr->m != 3)) return; @@ -318,18 +307,10 @@ ctr_clock(ctr_t *ctr) static void ctr_set_state_1(ctr_t *ctr) { - switch (ctr->m) { - case 0: case 4: - /*Interrupt on terminal count*/ - ctr->state = 1; - break; - case 2: case 3: - /*Rate generator*/ - /*Square wave mode*/ - if (ctr->state == 0) - ctr->state = 1; - break; - } + uint8_t mode = (ctr->m & 0x03); + + if ((mode == 0) || ((mode > 1) && (ctr->state == 0))) + ctr->state = 1; } @@ -357,7 +338,7 @@ ctr_load(ctr_t *ctr) } -static void +static __inline void ctr_latch_status(ctr_t *ctr) { ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0) | (ctr->null_count ? 0x40 : 0); @@ -365,10 +346,10 @@ ctr_latch_status(ctr_t *ctr) } -static void +static __inline void ctr_latch_count(ctr_t *ctr) { - int count = (ctr->latch || ctr->null_count || (ctr->state == 1)) ? ctr->l : ctr->count; + int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count; switch (ctr->rm & 0x03) { case 0x00: @@ -396,70 +377,74 @@ ctr_latch_count(ctr_t *ctr) uint16_t -pit_ctr_get_count(ctr_t *ctr) +pit_ctr_get_count(void *data, int counter_id) { + pit_t *pit = (pit_t *)data; + ctr_t *ctr = &pit->counters[counter_id]; + return (uint16_t) ctr->l; } void -pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count)) +pit_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count)) { - if (ctr == NULL) + if (data == NULL) return; + pit_t *pit = (pit_t *)data; + ctr_t *ctr = &pit->counters[counter_id]; + ctr->load_func = func; } void -pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out)) +pit_ctr_set_out_func(void *data, int counter_id, void (*func)(int new_out, int old_out)) { - if (ctr == NULL) + if (data == NULL) return; + pit_t *pit = (pit_t *)data; + ctr_t *ctr = &pit->counters[counter_id]; + ctr->out_func = func; } void -pit_ctr_set_gate(ctr_t *ctr, int gate) +pit_ctr_set_gate(void *data, int counter_id, int gate) { + pit_t *pit = (pit_t *)data; + ctr_t *ctr = &pit->counters[counter_id]; + int old = ctr->gate; + uint8_t mode = ctr->m & 3; ctr->gate = gate; - switch (ctr->m & 0x07) { + switch (mode) { case 1: case 2: case 3: case 5: case 6: case 7: if (!old && gate) { /* Here we handle the rising edges. */ - switch (ctr->m) { - case 1: - ctr->state = 1; - break; - case 2: case 6: - ctr->state = 3; - break; - case 3: case 5: case 7: + if (mode & 1) { + if (mode != 1) ctr_set_out(ctr, 1); - ctr->state = 1; - break; - } + ctr->state = 1; + } else if (mode == 2) + ctr->state = 3; } else if (old && !gate) { /* Here we handle the lowering edges. */ - switch (ctr->m) { - case 2: case 3: case 6: case 7: - ctr_set_out(ctr, 1); - break; - } + if (mode & 2) + ctr_set_out(ctr, 1); } break; } } -void -pit_ctr_set_clock(ctr_t *ctr, int clock) +static __inline void +pit_ctr_set_clock_common(ctr_t *ctr, int clock) { int old = ctr->clock; @@ -476,13 +461,10 @@ pit_ctr_set_clock(ctr_t *ctr, int clock) ctr->s1_det = 1; /* Rising edge. */ else if (old && !ctr->clock) { ctr->s1_det++; /* Falling edge. */ - if (ctr->s1_det != 2) + if (ctr->s1_det >= 2) { ctr->s1_det = 0; - } - - if (ctr->s1_det == 2) { - ctr->s1_det = 0; - ctr_tick(ctr); + ctr_tick(ctr); + } } } else if (old && !ctr->clock) ctr_tick(ctr); @@ -491,10 +473,19 @@ pit_ctr_set_clock(ctr_t *ctr, int clock) void -pit_ctr_set_using_timer(ctr_t *ctr, int using_timer) +pit_ctr_set_clock(ctr_t *ctr, int clock) { - timer_process(); + pit_ctr_set_clock_common(ctr, clock); +} + +void +pit_ctr_set_using_timer(void *data, int counter_id, int using_timer) +{ + if (tsc > 0) + timer_process(); + pit_t *pit = (pit_t *)data; + ctr_t *ctr = &pit->counters[counter_id]; ctr->using_timer = using_timer; } @@ -508,7 +499,7 @@ pit_timer_over(void *p) dev->clock ^= 1; for (i = 0; i < 3; i++) - pit_ctr_set_clock(&dev->counters[i], dev->clock); + pit_ctr_set_clock_common(&dev->counters[i], dev->clock); timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL); } @@ -528,26 +519,25 @@ pit_write(uint16_t addr, uint8_t val, void *priv) t = val >> 6; if (t == 3) { - if (!(dev->flags & PIT_8254)) - break; - - /* This is 8254-only. */ - if (!(val & 0x20)) { - if (val & 2) - ctr_latch_count(&dev->counters[0]); - if (val & 4) - ctr_latch_count(&dev->counters[1]); - if (val & 8) - ctr_latch_count(&dev->counters[2]); - pit_log("PIT %i: Initiated readback command\n", t); - } - if (!(val & 0x10)) { - if (val & 2) - ctr_latch_status(&dev->counters[0]); - if (val & 4) - ctr_latch_status(&dev->counters[1]); - if (val & 8) - ctr_latch_status(&dev->counters[2]); + if (dev->flags & PIT_8254) { + /* This is 8254-only. */ + if (!(val & 0x20)) { + if (val & 2) + ctr_latch_count(&dev->counters[0]); + if (val & 4) + ctr_latch_count(&dev->counters[1]); + if (val & 8) + ctr_latch_count(&dev->counters[2]); + pit_log("PIT %i: Initiated readback command\n", t); + } + if (!(val & 0x10)) { + if (val & 2) + ctr_latch_status(&dev->counters[0]); + if (val & 4) + ctr_latch_status(&dev->counters[1]); + if (val & 8) + ctr_latch_status(&dev->counters[2]); + } } } else { dev->ctrl = val; @@ -564,8 +554,14 @@ pit_write(uint16_t addr, uint8_t val, void *priv) if (ctr->m > 5) ctr->m &= 3; ctr->null_count = 1; + ctr->bcd = (ctr->ctrl & 0x01); ctr_set_out(ctr, !!ctr->m); ctr->state = 0; + if (ctr->latched) { + pit_log("PIT %i: Reload while counter is latched\n", t); + ctr->rl--; + } + pit_log("PIT %i: M = %i, RM/WM = %i, State = %i, Out = %i\n", t, ctr->m, ctr->rm, ctr->state, ctr->out); } } @@ -575,8 +571,6 @@ pit_write(uint16_t addr, uint8_t val, void *priv) case 1: case 2: /* the actual timers */ ctr = &dev->counters[t]; - /* Reloading timer count, so set null_count to 1. */ - ctr->null_count = 1; switch (ctr->wm) { case 0: @@ -644,7 +638,7 @@ pit_read(uint16_t addr, void *priv) break; } - count = (ctr->null_count || (ctr->state == 1)) ? ctr->l : ctr->count; + count = (ctr->state == 1) ? ctr->l : ctr->count; if (ctr->latched) { ret = (ctr->rl) >> ((ctr->rm & 0x80) ? 8 : 0); @@ -669,6 +663,8 @@ pit_read(uint16_t addr, void *priv) break; case 3: case 0x83: + /* Yes, wm is correct here - this is to ensure correct readout while the + count is being written. */ if (ctr->wm & 0x80) ret = ~(ctr->l & 0xff); else @@ -689,46 +685,19 @@ pit_read(uint16_t addr, void *priv) } -/* FIXME: Should be moved to machine.c (default for most machine). */ -void -pit_irq0_timer(int new_out, int old_out) -{ - if (new_out && !old_out) - picint(1); - - if (!new_out) - picintc(1); -} - - -void -pit_irq0_timer_pcjr(int new_out, int old_out) -{ - if (new_out && !old_out) { - picint(1); - ctr_clock(&pit->counters[1]); - } - - if (!new_out) - picintc(1); -} - - void pit_irq0_timer_ps2(int new_out, int old_out) { - ctr_t *ctr = &pit2->counters[0]; - if (new_out && !old_out) { picint(1); - pit_ctr_set_gate(ctr, 1); + pit_devs[1].set_gate(pit_devs[1].data, 0, 1); } if (!new_out) picintc(1); if (!new_out && old_out) - ctr_clock(ctr); + pit_devs[1].ctr_clock(pit_devs[1].data, 0); } @@ -743,7 +712,7 @@ pit_refresh_timer_xt(int new_out, int old_out) void pit_refresh_timer_at(int new_out, int old_out) { - if (new_out && !old_out) + if (refresh_at_enable && new_out && !old_out) ppi.pb ^= 0x10; } @@ -753,9 +722,13 @@ pit_speaker_timer(int new_out, int old_out) { int l; + if (cassette != NULL) + pc_cas_set_out(cassette, new_out); + speaker_update(); - l = pit->counters[2].l ? pit->counters[2].l : 0x10000; + uint16_t count = pit_devs[0].get_count(pit_devs[0].data, 2); + l = count ? count : 0x10000; if (l < 25) speakon = 0; else @@ -822,11 +795,11 @@ pit_close(void *priv) { pit_t *dev = (pit_t *) priv; - if (dev == pit) - pit = NULL; + if (dev == pit_devs[0].data) + pit_devs[0].data = NULL; - if (dev == pit2) - pit2 = NULL; + if (dev == pit_devs[1].data) + pit_devs[1].data = NULL; if (dev != NULL) free(dev); @@ -846,102 +819,165 @@ pit_init(const device_t *info) dev->flags = info->local; - if (!(dev->flags & PIT_EXT_IO)) - io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, dev); + if (!(dev->flags & PIT_EXT_IO)) { + io_sethandler((dev->flags & PIT_SECONDARY) ? 0x0048 : 0x0040, 0x0004, + pit_read, NULL, NULL, pit_write, NULL, NULL, dev); + } return dev; } - -const device_t i8253_device = -{ - "Intel 8253/8253-5 Programmable Interval Timer", - DEVICE_ISA, - PIT_8253, - pit_init, pit_close, NULL, - NULL, NULL, NULL, - NULL +const device_t i8253_device = { + .name = "Intel 8253/8253-5 Programmable Interval Timer", + .internal_name = "i8253", + .flags = DEVICE_ISA, + .local = PIT_8253, + .init = pit_init, + .close = pit_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i8254_device = -{ - "Intel 8254 Programmable Interval Timer", - DEVICE_ISA, - PIT_8254, - pit_init, pit_close, NULL, - NULL, NULL, NULL, - NULL +const device_t i8254_device = { + .name = "Intel 8254 Programmable Interval Timer", + .internal_name = "i8254", + .flags = DEVICE_ISA, + .local = PIT_8254, + .init = pit_init, + .close = pit_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i8254_ext_io_device = -{ - "Intel 8254 Programmable Interval Timer (External I/O)", - DEVICE_ISA, - PIT_8254 | PIT_EXT_IO, - pit_init, pit_close, NULL, - NULL, NULL, NULL, - NULL +const device_t i8254_sec_device = { + .name = "Intel 8254 Programmable Interval Timer (Secondary)", + .internal_name = "i8254_sec", + .flags = DEVICE_ISA, + .local = PIT_8254 | PIT_SECONDARY, + .init = pit_init, + .close = pit_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t i8254_ps2_device = -{ - "Intel 8254 Programmable Interval Timer (PS/2)", - DEVICE_ISA, - PIT_8254 | PIT_PS2 | PIT_EXT_IO, - pit_init, pit_close, NULL, - NULL, NULL, NULL, - NULL +const device_t i8254_ext_io_device = { + .name = "Intel 8254 Programmable Interval Timer (External I/O)", + .internal_name = "i8254_ext_io", + .flags = DEVICE_ISA, + .local = PIT_8254 | PIT_EXT_IO, + .init = pit_init, + .close = pit_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +const device_t i8254_ps2_device = { + .name = "Intel 8254 Programmable Interval Timer (PS/2)", + .internal_name = "i8254_ps2", + .flags = DEVICE_ISA, + .local = PIT_8254 | PIT_PS2 | PIT_EXT_IO, + .init = pit_init, + .close = pit_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; pit_t * pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out)) { int i; + void *pit; + + pit_intf_t *pit_intf = &pit_devs[0]; switch (type) { case PIT_8253: default: pit = device_add(&i8253_device); + *pit_intf = pit_classic_intf; break; case PIT_8254: pit = device_add(&i8254_device); + *pit_intf = pit_classic_intf; break; + case PIT_8253_FAST: + pit = device_add(&i8253_fast_device); + *pit_intf = pit_fast_intf; + break; + case PIT_8254_FAST: + pit = device_add(&i8254_fast_device); + *pit_intf = pit_fast_intf; + break; + } + pit_intf->data = pit; + for (i = 0; i < 3; i++) { - pit->counters[i].gate = 1; - pit->counters[i].using_timer = 1; + pit_intf->set_gate(pit_intf->data, i, 1); + pit_intf->set_using_timer(pit_intf->data, i, 1); } - pit_ctr_set_out_func(&pit->counters[0], out0); - pit_ctr_set_out_func(&pit->counters[1], out1); - pit_ctr_set_out_func(&pit->counters[2], pit_speaker_timer); - pit_ctr_set_load_func(&pit->counters[2], speaker_set_count); - pit->counters[2].gate = 0; + pit_intf->set_out_func(pit_intf->data, 0, out0); + pit_intf->set_out_func(pit_intf->data, 1, out1); + pit_intf->set_out_func(pit_intf->data, 2, pit_speaker_timer); + pit_intf->set_load_func(pit_intf->data, 2, speaker_set_count); + + pit_intf->set_gate(pit_intf->data, 2, 0); return pit; } pit_t * -pit_ps2_init(void) +pit_ps2_init(int type) { - pit2 = device_add(&i8254_ps2_device); + void *pit; - pit_handler(1, 0x0044, 0x0001, pit2); - pit_handler(1, 0x0047, 0x0001, pit2); + pit_intf_t *ps2_pit = &pit_devs[1]; - pit2->counters[0].gate = 0; - pit2->counters[0].using_timer = pit2->counters[1].using_timer = pit2->counters[2].using_timer = 0; + switch (type) { + case PIT_8254: + default: + pit = device_add(&i8254_ps2_device); + *ps2_pit = pit_classic_intf; + break; - pit_ctr_set_out_func(&pit->counters[0], pit_irq0_timer_ps2); - pit_ctr_set_out_func(&pit2->counters[0], pit_nmi_timer_ps2); + case PIT_8254_FAST: + pit = device_add(&i8254_ps2_fast_device); + *ps2_pit = pit_fast_intf; + break; + } - return pit2; + ps2_pit->data = pit; + + ps2_pit->set_gate(ps2_pit->data, 0, 0); + for (int i = 0; i < 3; i++) { + ps2_pit->set_using_timer(ps2_pit->data, i, 0); + } + + io_sethandler(0x0044, 0x0001, ps2_pit->read, NULL, NULL, ps2_pit->write, NULL, NULL, pit); + io_sethandler(0x0047, 0x0001, ps2_pit->read, NULL, NULL, ps2_pit->write, NULL, NULL, pit); + + pit_devs[0].set_out_func(pit_devs[0].data, 0, pit_irq0_timer_ps2); + ps2_pit->set_out_func(ps2_pit->data, 0, pit_nmi_timer_ps2); + + return pit; } @@ -949,18 +985,19 @@ void pit_set_clock(int clock) { /* Set default CPU/crystal clock and xt_cpu_multi. */ - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) { - if (clock == 66666666) - cpuclock = 200000000.0 / 3.0; - else if (clock == 33333333) - cpuclock = 100000000.0 / 3.0; + if (cpu_s->cpu_type >= CPU_286) { + int remainder = (clock % 100000000); + if (remainder == 66666666) + cpuclock = (double) (clock - remainder) + (200000000.0 / 3.0); + else if (remainder == 33333333) + cpuclock = (double) (clock - remainder) + (100000000.0 / 3.0); else cpuclock = (double) clock; PITCONSTD = (cpuclock / 1193182.0); PITCONST = (uint64_t) (PITCONSTD * (double)(1ull << 32)); CGACONST = (uint64_t) ((cpuclock / (19687503.0/11.0)) * (double)(1ull << 32)); - ISACONST = (uint64_t) ((cpuclock / 8000000.0) * (double)(1ull << 32)); + ISACONST = (uint64_t) ((cpuclock / (double)cpu_isa_speed) * (double)(1ull << 32)); xt_cpu_multi = 1ULL; } else { cpuclock = 14318184.0; @@ -969,9 +1006,9 @@ pit_set_clock(int clock) CGACONST = (8ULL << 32ULL); xt_cpu_multi = 3ULL; - switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) { + switch (cpu_s->rspeed) { case 7159092: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { + if (cpu_s->cpu_flags & CPU_ALTERNATE_XTAL) { cpuclock = 28636368.0; xt_cpu_multi = 4ULL; } else @@ -995,7 +1032,7 @@ pit_set_clock(int clock) break; default: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { + if (cpu_s->cpu_flags & CPU_ALTERNATE_XTAL) { cpuclock = 28636368.0; xt_cpu_multi = 6ULL; } @@ -1017,26 +1054,27 @@ pit_set_clock(int clock) xt_cpu_multi <<= 32ULL; /* Delay for empty I/O ports. */ - io_delay = (int) round(((double) machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) / 3000000.0); + io_delay = (int) round(((double) cpu_s->rspeed) / 3000000.0); MDACONST = (uint64_t) (cpuclock / 2032125.0 * (double)(1ull << 32)); HERCCONST = MDACONST; VGACONST1 = (uint64_t) (cpuclock / 25175000.0 * (double)(1ull << 32)); VGACONST2 = (uint64_t) (cpuclock / 28322000.0 * (double)(1ull << 32)); RTCCONST = (uint64_t) (cpuclock / 32768.0 * (double)(1ull << 32)); - ACPICONST = (uint64_t) (cpuclock / 3579545.0 * (double)(1ull << 32)); TIMER_USEC = (uint64_t)((cpuclock / 1000000.0) * (double)(1ull << 32)); - isa_timing = (cpuclock / (double)8000000.0); + isa_timing = (cpuclock / (double)cpu_isa_speed); if (cpu_64bitbus) - bus_timing = (cpuclock / ((double)cpu_busspeed) / 2); + bus_timing = (cpuclock / ((double)cpu_busspeed / 2)); else - bus_timing = (cpuclock / (double)cpu_busspeed); + bus_timing = (cpuclock / (double)cpu_busspeed); pci_timing = (cpuclock / (double)cpu_pci_speed); + agp_timing = (cpuclock / (double)cpu_agp_speed); /* PCICLK in us for use with timer_on_auto(). */ PCICLK = pci_timing / (cpuclock / 1000000.0); + AGPCLK = agp_timing / (cpuclock / 1000000.0); if (cpu_busspeed >= 30000000) SYSCLK = bus_timing * 4.0; @@ -1047,3 +1085,15 @@ pit_set_clock(int clock) device_speed_changed(); } + +const pit_intf_t pit_classic_intf = { + &pit_read, + &pit_write, + &pit_ctr_get_count, + &pit_ctr_set_gate, + &pit_ctr_set_using_timer, + &pit_ctr_set_out_func, + &pit_ctr_set_load_func, + &ctr_clock, + NULL, +}; \ No newline at end of file diff --git a/src/pit_fast.c b/src/pit_fast.c new file mode 100644 index 000000000..704cfd68c --- /dev/null +++ b/src/pit_fast.c @@ -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 the Intel 8253/8254 Programmable Interval + * Timer. + * + * + * + * Author: Miran Grca, + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/cassette.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/nmi.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/pit_fast.h> +#include <86box/ppi.h> +#include <86box/machine.h> +#include <86box/sound.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> + +#define PIT_PS2 16 /* The PIT is the PS/2's second PIT. */ +#define PIT_EXT_IO 32 /* The PIT has externally specified port I/O. */ +#define PIT_CUSTOM_CLOCK 64 /* The PIT uses custom clock inputs provided by another provider. */ +#define PIT_SECONDARY 128 /* The PIT is secondary (ports 0048-004B). */ + +#ifdef ENABLE_PIT_LOG +int pit_do_log = ENABLE_PIT_LOG; + +static void +pit_log(const char *fmt, ...) +{ + va_list ap; + + if (pit_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pit_log(fmt, ...) +#endif + +static void +pitf_ctr_set_out(ctrf_t *ctr, int out) +{ + if (ctr == NULL) + return; + + if (ctr->out_func != NULL) + ctr->out_func(out, ctr->out); + ctr->out = out; +} + +static void +pitf_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count)) +{ + if (data == NULL) + return; + + pitf_t *pit = (pitf_t *)data; + ctrf_t *ctr = &pit->counters[counter_id]; + + ctr->load_func = func; +} + +static uint16_t +pitf_ctr_get_count(void *data, int counter_id) +{ + pitf_t *pit = (pitf_t *)data; + ctrf_t *ctr = &pit->counters[counter_id]; + return (uint16_t) ctr->l; +} + +static void +pitf_ctr_set_out_func(void *data, int counter_id, void (*func)(int new_out, int old_out)) +{ + if (data == NULL) + return; + + pitf_t *pit = (pitf_t *)data; + ctrf_t *ctr = &pit->counters[counter_id]; + + ctr->out_func = func; +} + +static void +pitf_ctr_set_using_timer(void *data, int counter_id, int using_timer) +{ + if (tsc > 0) + timer_process(); + + pitf_t *pit = (pitf_t *)data; + ctrf_t *ctr = &pit->counters[counter_id]; + ctr->using_timer = using_timer; +} + +static int +pitf_read_timer(ctrf_t *ctr) +{ + if (ctr->using_timer && !(ctr->m == 3 && !ctr->gate) && timer_is_enabled(&ctr->timer)) { + int read = (int) ((timer_get_remaining_u64(&ctr->timer)) / PITCONST); + if (ctr->m == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (ctr->m == 3) + read <<= 1; + return read; + } + if (ctr->m == 2) + return ctr->count + 1; + return ctr->count; +} + +/*Dump timer count back to pit->count[], and disable timer. This should be used + when stopping a PIT timer, to ensure the correct value can be read back.*/ +static void +pitf_dump_and_disable_timer(ctrf_t *ctr) +{ + if (ctr->using_timer && timer_is_enabled(&ctr->timer)) { + ctr->count = pitf_read_timer(ctr); + timer_disable(&ctr->timer); + } +} + +static void +pitf_ctr_load(ctrf_t *ctr) +{ + int l = ctr->l ? ctr->l : 0x10000; + + ctr->newcount = 0; + ctr->disabled = 0; + + switch (ctr->m) { + case 0: /*Interrupt on terminal count*/ + ctr->count = l; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + pitf_ctr_set_out(ctr, 0); + ctr->thit = 0; + ctr->enabled = ctr->gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + ctr->enabled = 1; + break; + case 2: /*Rate generator*/ + if (ctr->initial) { + ctr->count = l - 1; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) ((l - 1) * PITCONST)); + pitf_ctr_set_out(ctr, 1); + ctr->thit = 0; + } + ctr->enabled = ctr->gate; + break; + case 3: /*Square wave mode*/ + if (ctr->initial) { + ctr->count = l; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) (((l + 1) >> 1) * PITCONST)); + pitf_ctr_set_out(ctr, 1); + ctr->thit = 0; + } + ctr->enabled = ctr->gate; + break; + case 4: /*Software triggered stobe*/ + if (!ctr->thit && !ctr->initial) + ctr->newcount = 1; + else { + ctr->count = l; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + pitf_ctr_set_out(ctr, 0); + ctr->thit = 0; + } + ctr->enabled = ctr->gate; + break; + case 5: /*Hardware triggered stobe*/ + ctr->enabled = 1; + break; + } + + if (ctr->load_func != NULL) + ctr->load_func(ctr->m, l); + + ctr->initial = 0; + ctr->running = ctr->enabled && ctr->using_timer && !ctr->disabled; + if (ctr->using_timer && !ctr->running) + pitf_dump_and_disable_timer(ctr); +} + +static void +pitf_set_gate_no_timer(ctrf_t *ctr, int gate) +{ + int l = ctr->l ? ctr->l : 0x10000; + + if (ctr->disabled) { + ctr->gate = gate; + return; + } + + switch (ctr->m) { + case 0: /*Interrupt on terminal count*/ + case 4: /*Software triggered stobe*/ + if (ctr->using_timer && !ctr->running) + timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + ctr->enabled = gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + case 5: /*Hardware triggered stobe*/ + if (gate && !ctr->gate) { + ctr->count = l; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + pitf_ctr_set_out(ctr, 0); + ctr->thit = 0; + ctr->enabled = 1; + } + break; + case 2: /*Rate generator*/ + if (gate && !ctr->gate) { + ctr->count = l - 1; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + pitf_ctr_set_out(ctr, 1); + ctr->thit = 0; + } + ctr->enabled = gate; + break; + case 3: /*Square wave mode*/ + if (gate && !ctr->gate) { + ctr->count = l; + if (ctr->using_timer) + timer_set_delay_u64(&ctr->timer, (uint64_t) (((l + 1) >> 1) * PITCONST)); + pitf_ctr_set_out(ctr, 1); + ctr->thit = 0; + } + ctr->enabled = gate; + break; + } + ctr->gate = gate; + ctr->running = ctr->enabled && ctr->using_timer && !ctr->disabled; + if (ctr->using_timer && !ctr->running) + pitf_dump_and_disable_timer(ctr); +} + +static void +pitf_ctr_set_gate(void *data, int counter_id, int gate) +{ + pitf_t *pit = (pitf_t *)data; + ctrf_t *ctr = &pit->counters[counter_id]; + + if (ctr->disabled) { + ctr->gate = gate; + return; + } + + pitf_set_gate_no_timer(ctr, gate); +} + +static void +pitf_over(ctrf_t *ctr) +{ + int l = ctr->l ? ctr->l : 0x10000; + if (ctr->disabled) { + ctr->count += 0xffff; + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST)); + return; + } + + switch (ctr->m) { + case 0: /*Interrupt on terminal count*/ + case 1: /*Hardware retriggerable one-shot*/ + if (!ctr->thit) + pitf_ctr_set_out(ctr, 1); + ctr->thit = 1; + ctr->count += 0xffff; + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST)); + break; + case 2: /*Rate generator*/ + ctr->count += l; + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + pitf_ctr_set_out(ctr, 0); + pitf_ctr_set_out(ctr, 1); + break; + case 3: /*Square wave mode*/ + if (ctr->out) { + pitf_ctr_set_out(ctr, 0); + ctr->count += (l >> 1); + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) ((l >> 1) * PITCONST)); + } else { + pitf_ctr_set_out(ctr, 1); + ctr->count += ((l + 1) >> 1); + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (((l + 1) >> 1) * PITCONST)); + } + // if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST); + break; + case 4: /*Software triggered strove*/ + if (!ctr->thit) { + pitf_ctr_set_out(ctr, 0); + pitf_ctr_set_out(ctr, 1); + } + if (ctr->newcount) { + ctr->newcount = 0; + ctr->count += l; + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (l * PITCONST)); + } else { + ctr->thit = 1; + ctr->count += 0xffff; + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST)); + } + break; + case 5: /*Hardware triggered strove*/ + if (!ctr->thit) { + pitf_ctr_set_out(ctr, 0); + pitf_ctr_set_out(ctr, 1); + } + ctr->thit = 1; + ctr->count += 0xffff; + if (ctr->using_timer) + timer_advance_u64(&ctr->timer, (uint64_t) (0xffff * PITCONST)); + break; + } + ctr->running = ctr->enabled && ctr->using_timer && !ctr->disabled; + if (ctr->using_timer && !ctr->running) + pitf_dump_and_disable_timer(ctr); +} + +static __inline void +pitf_ctr_latch_count(ctrf_t *ctr) +{ + ctr->rl = pitf_read_timer(ctr); + // pclog("Timer latch %f %04X %04X\n",pit->c[0],pit->rl[0],pit->l[0]); + // pit->ctrl |= 0x30; + ctr->rereadlatch = 0; + ctr->rm = 3; + ctr->latched = 1; +} + +static __inline void +pitf_ctr_latch_status(ctrf_t *ctr) +{ + ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0); + ctr->do_read_status = 1; +} + +static void +pitf_write(uint16_t addr, uint8_t val, void *priv) +{ + pitf_t *dev = (pitf_t *) priv; + int t = (addr & 3); + ctrf_t *ctr; + + pit_log("[%04X:%08X] pit_write(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv); + + switch (addr & 3) { + case 3: /* control */ + t = val >> 6; + + if (t == 3) { + if (dev->flags & PIT_8254) { + /* This is 8254-only. */ + if (!(val & 0x20)) { + if (val & 2) + pitf_ctr_latch_count(&dev->counters[0]); + if (val & 4) + pitf_ctr_latch_count(&dev->counters[1]); + if (val & 8) + pitf_ctr_latch_count(&dev->counters[2]); + pit_log("PIT %i: Initiated readback command\n", t); + } + if (!(val & 0x10)) { + if (val & 2) + pitf_ctr_latch_status(&dev->counters[0]); + if (val & 4) + pitf_ctr_latch_status(&dev->counters[1]); + if (val & 8) + pitf_ctr_latch_status(&dev->counters[2]); + } + } + } else { + dev->ctrl = val; + ctr = &dev->counters[t]; + + if (!(dev->ctrl & 0x30)) { + pitf_ctr_latch_count(ctr); + dev->ctrl |= 0x30; + pit_log("PIT %i: Initiated latched read, %i bytes latched\n", + t, ctr->latched); + } else { + ctr->ctrl = val; + ctr->rm = ctr->wm = (ctr->ctrl >> 4) & 3; + ctr->m = (val >> 1) & 7; + if (ctr->m > 5) + ctr->m &= 3; + if (!(ctr->rm)) { + ctr->rm = 3; + ctr->rl = pitf_read_timer(ctr); + } + ctr->rereadlatch = 1; + ctr->initial = 1; + if (!ctr->m) + pitf_ctr_set_out(ctr, 0); + else + pitf_ctr_set_out(ctr, 1); + ctr->disabled = 1; + + pit_log("PIT %i: M = %i, RM/WM = %i, State = %i, Out = %i\n", t, ctr->m, ctr->rm, ctr->state, ctr->out); + } + ctr->thit = 0; + } + break; + + case 0: + case 1: + case 2: /* the actual timers */ + ctr = &dev->counters[t]; + + switch (ctr->wm) { + case 1: + ctr->l = val; + pitf_ctr_load(ctr); + break; + case 2: + ctr->l = (val << 8); + pitf_ctr_load(ctr); + break; + case 0: + ctr->l &= 0xFF; + ctr->l |= (val << 8); + pitf_ctr_load(ctr); + ctr->wm = 3; + break; + case 3: + ctr->l &= 0xFF00; + ctr->l |= val; + ctr->wm = 0; + break; + } + break; + } +} + +static uint8_t +pitf_read(uint16_t addr, void *priv) +{ + pitf_t *dev = (pitf_t *) priv; + uint8_t ret = 0xff; + int t = (addr & 3); + ctrf_t *ctr; + + switch (addr & 3) { + case 3: /* Control. */ + /* This is 8254-only, 8253 returns 0x00. */ + ret = (dev->flags & PIT_8254) ? dev->ctrl : 0x00; + break; + + case 0: + case 1: + case 2: /* The actual timers. */ + ctr = &dev->counters[t]; + + if (ctr->do_read_status) { + ctr->do_read_status = 0; + ret = ctr->read_status; + break; + } + + if (ctr->rereadlatch && !ctr->latched) { + ctr->rereadlatch = 0; + ctr->rl = pitf_read_timer(ctr); + } + switch (ctr->rm) { + case 0: + ret = ctr->rl >> 8; + ctr->rm = 3; + ctr->latched = 0; + ctr->rereadlatch = 1; + break; + case 1: + ret = (ctr->rl) & 0xFF; + ctr->latched = 0; + ctr->rereadlatch = 1; + break; + case 2: + ret = (ctr->rl) >> 8; + ctr->latched = 0; + ctr->rereadlatch = 1; + break; + case 3: + ret = (ctr->rl) & 0xFF; + if (ctr->m & 0x80) + ctr->m &= 7; + else + ctr->rm = 0; + break; + } + break; + } + + pit_log("[%04X:%08X] pit_read(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); + + return ret; +} + +static void +pitf_timer_over(void *p) +{ + ctrf_t *ctr = (ctrf_t *) p; + pitf_over(ctr); +} + +static void +pitf_ctr_clock(void *data, int counter_id) +{ + pitf_t *pit = (pitf_t *)data; + ctrf_t *ctr = &pit->counters[counter_id]; + + if (ctr->thit || !ctr->enabled) + return; + + if (ctr->using_timer) + return; + + ctr->count -= (ctr->m == 3) ? 2 : 1; + if (!ctr->count) + pitf_over(ctr); +} + +static void +ctr_reset(ctrf_t *ctr) +{ + ctr->ctrl = 0; + ctr->m = 0; + ctr->gate = 0; + ctr->l = 0xffff; + ctr->thit = 1; + ctr->using_timer = 1; +} + +static void +pitf_reset(pitf_t *dev) +{ + int i; + + memset(dev, 0, sizeof(pitf_t)); + + for (i = 0; i < 3; i++) + ctr_reset(&dev->counters[i]); + + /* Disable speaker gate. */ + dev->counters[2].gate = 0; +} + +static void +pitf_close(void *priv) +{ + pitf_t *dev = (pitf_t *) priv; + + if (dev == pit_devs[0].data) + pit_devs[0].data = NULL; + + if (dev == pit_devs[1].data) + pit_devs[1].data = NULL; + + if (dev != NULL) + free(dev); +} + +static void * +pitf_init(const device_t *info) +{ + pitf_t *dev = (pitf_t *) malloc(sizeof(pitf_t)); + pitf_reset(dev); + + dev->flags = info->local; + + if (!(dev->flags & PIT_PS2) && !(dev->flags & PIT_CUSTOM_CLOCK)) { + for (int i = 0; i < 3; i++) { + ctrf_t *ctr = &dev->counters[i]; + timer_add(&ctr->timer, pitf_timer_over, (void *)ctr, 0); + } + } + + if (!(dev->flags & PIT_EXT_IO)) { + io_sethandler((dev->flags & PIT_SECONDARY) ? 0x0048 : 0x0040, 0x0004, + pitf_read, NULL, NULL, pitf_write, NULL, NULL, dev); + } + + return dev; +} + +const device_t i8253_fast_device = { + .name = "Intel 8253/8253-5 Programmable Interval Timer", + .internal_name = "i8253_fast", + .flags = DEVICE_ISA, + .local = PIT_8253, + .init = pitf_init, + .close = pitf_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i8254_fast_device = { + .name = "Intel 8254 Programmable Interval Timer", + .internal_name = "i8254_fast", + .flags = DEVICE_ISA, + .local = PIT_8254, + .init = pitf_init, + .close = pitf_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i8254_sec_fast_device = { + .name = "Intel 8254 Programmable Interval Timer (Secondary)", + .internal_name = "i8254_sec_fast", + .flags = DEVICE_ISA, + .local = PIT_8254 | PIT_SECONDARY, + .init = pitf_init, + .close = pitf_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i8254_ext_io_fast_device = { + .name = "Intel 8254 Programmable Interval Timer (External I/O)", + .internal_name = "i8254_ext_io_fast", + .flags = DEVICE_ISA, + .local = PIT_8254 | PIT_EXT_IO, + .init = pitf_init, + .close = pitf_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i8254_ps2_fast_device = { + .name = "Intel 8254 Programmable Interval Timer (PS/2)", + .internal_name = "i8254_ps2_fast", + .flags = DEVICE_ISA, + .local = PIT_8254 | PIT_PS2 | PIT_EXT_IO, + .init = pitf_init, + .close = pitf_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const pit_intf_t pit_fast_intf = { + &pitf_read, + &pitf_write, + &pitf_ctr_get_count, + &pitf_ctr_set_gate, + &pitf_ctr_set_using_timer, + &pitf_ctr_set_out_func, + &pitf_ctr_set_load_func, + &pitf_ctr_clock, + NULL, +}; \ No newline at end of file diff --git a/src/port_6x.c b/src/port_6x.c new file mode 100644 index 000000000..0fe168a3c --- /dev/null +++ b/src/port_6x.c @@ -0,0 +1,248 @@ +/* + * 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 Ports 61, 62, and 63 used by various + * machines. + * + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/m_xt_xi8088.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sound.h> +#include <86box/snd_speaker.h> +#include <86box/pit.h> +#include <86box/ppi.h> +#include <86box/video.h> +#include <86box/port_6x.h> + + +#define PS2_REFRESH_TIME (16 * TIMER_USEC) + +#define PORT_6X_TURBO 1 +#define PORT_6X_EXT_REF 2 +#define PORT_6X_MIRROR 4 +#define PORT_6X_SWA 8 + + +static void +port_6x_write(uint16_t port, uint8_t val, void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + + port &= 3; + + if ((port == 3) && (dev->flags & PORT_6X_MIRROR)) + port = 1; + + switch (port) { + case 1: + ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); + + 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 (dev->flags & PORT_6X_TURBO) + xi8088_turbo_set(!!(val & 0x04)); + break; + } +} + +static uint8_t +port_61_read_simple(uint16_t port, void *priv) +{ + uint8_t ret = ppi.pb & 0x1f; + + if (ppispeakon) + ret |= 0x20; + + return(ret); +} + +static uint8_t +port_61_read(uint16_t port, void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + uint8_t ret = 0xff; + + if (dev->flags & PORT_6X_EXT_REF) { + ret = ppi.pb & 0x0f; + + if (dev->refresh) + ret |= 0x10; + } else + ret = ppi.pb & 0x1f; + + if (ppispeakon) + ret |= 0x20; + + if (dev->flags & PORT_6X_TURBO) + ret = (ret & 0xfb) | (xi8088_turbo_get() ? 0x04 : 0x00); + + return(ret); +} + +static uint8_t +port_62_read(uint16_t port, void *priv) +{ + uint8_t ret = 0xff; + + /* SWA on Olivetti M240 mainboard (off=1) */ + ret = 0x00; + if (ppi.pb & 0x8) { + /* Switches 4, 5 - floppy drives (number) */ + int i, fdd_count = 0; + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + if (!fdd_count) + ret |= 0x00; + else + ret |= ((fdd_count - 1) << 2); + /* Switches 6, 7 - monitor type */ + if (video_is_mda()) + ret |= 0x3; + else if (video_is_cga()) + ret |= 0x2; /* 0x10 would be 40x25 */ + else + ret |= 0x0; + } else { + /* bit 2 always on */ + ret |= 0x4; + /* Switch 8 - 8087 FPU. */ + if (hasfpu) + ret |= 0x02; + } + + return(ret); +} + +static void +port_6x_refresh(void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_timer, PS2_REFRESH_TIME); +} + + +static void +port_6x_close(void *priv) +{ + port_6x_t *dev = (port_6x_t *) priv; + + timer_disable(&dev->refresh_timer); + + free(dev); +} + + +void * +port_6x_init(const device_t *info) +{ + port_6x_t *dev = (port_6x_t *) malloc(sizeof(port_6x_t)); + memset(dev, 0, sizeof(port_6x_t)); + + dev->flags = info->local & 0xff; + + if (dev->flags & (PORT_6X_TURBO | PORT_6X_EXT_REF)) { + io_sethandler(0x0061, 1, port_61_read, NULL, NULL, port_6x_write, NULL, NULL, dev); + + if (dev->flags & PORT_6X_EXT_REF) + timer_add(&dev->refresh_timer, port_6x_refresh, dev, 1); + + if (dev->flags & PORT_6X_MIRROR) + io_sethandler(0x0063, 1, port_61_read, NULL, NULL, port_6x_write, NULL, NULL, dev); + } else { + io_sethandler(0x0061, 1, port_61_read_simple, NULL, NULL, port_6x_write, NULL, NULL, dev); + + if (dev->flags & PORT_6X_MIRROR) + io_sethandler(0x0063, 1, port_61_read_simple, NULL, NULL, port_6x_write, NULL, NULL, dev); + } + + if (dev->flags & PORT_6X_SWA) + io_sethandler(0x0062, 1, port_62_read, NULL, NULL, NULL, NULL, NULL, dev); + + return dev; +} + +const device_t port_6x_device = { + .name = "Port 6x Registers", + .internal_name = "port_6x", + .flags = 0, + .local = 0, + .init = port_6x_init, + .close = port_6x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t port_6x_xi8088_device = { + .name = "Port 6x Registers (Xi8088)", + .internal_name = "port_6x_xi8088", + .flags = 0, + .local = PORT_6X_TURBO | PORT_6X_EXT_REF | PORT_6X_MIRROR, + .init = port_6x_init, + .close = port_6x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t port_6x_ps2_device = { + .name = "Port 6x Registers (IBM PS/2)", + .internal_name = "port_6x_ps2", + .flags = 0, + .local = PORT_6X_EXT_REF, + .init = port_6x_init, + .close = port_6x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t port_6x_olivetti_device = { + .name = "Port 6x Registers (Olivetti)", + .internal_name = "port_6x_olivetti", + .flags = 0, + .local = PORT_6X_SWA, + .init = port_6x_init, + .close = port_6x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/port_92.c b/src/port_92.c index a575ddf26..c4c421f53 100644 --- a/src/port_92.c +++ b/src/port_92.c @@ -64,14 +64,20 @@ port_92_readb(uint16_t port, void *priv) static uint16_t port_92_readw(uint16_t port, void *priv) { - return port_92_readb(port, priv); + uint16_t ret = 0xffff; + port_92_t *dev = (port_92_t *) priv; + + if (!(dev->flags & PORT_92_PCI)) + ret = port_92_readb(port, priv); + + return ret; } static void port_92_pulse(void *priv) { - softresetx86(); + resetx86(); cpu_set_edx(); } @@ -106,7 +112,10 @@ port_92_writeb(uint16_t port, uint8_t val, void *priv) static void port_92_writew(uint16_t port, uint16_t val, void *priv) { - port_92_writeb(port, val & 0xff, priv); + port_92_t *dev = (port_92_t *) priv; + + if (!(dev->flags & PORT_92_PCI)) + port_92_writeb(port, val & 0xff, priv); } @@ -146,7 +155,7 @@ port_92_add(void *priv) { port_92_t *dev = (port_92_t *) priv; - if (dev->flags & PORT_92_WORD) + if (dev->flags & (PORT_92_WORD | PORT_92_PCI)) io_sethandler(0x0092, 2, port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); else @@ -160,7 +169,7 @@ port_92_remove(void *priv) { port_92_t *dev = (port_92_t *) priv; - if (dev->flags & PORT_92_WORD) + if (dev->flags & (PORT_92_WORD | PORT_92_PCI)) io_removehandler(0x0092, 2, port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); else @@ -207,42 +216,58 @@ port_92_init(const device_t *info) return dev; } - const device_t port_92_device = { - "Port 92 Register", - 0, - 0, - port_92_init, port_92_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Port 92 Register", + .internal_name = "port_92", + .flags = 0, + .local = 0, + .init = port_92_init, + .close = port_92_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t port_92_inv_device = { - "Port 92 Register (inverted bits 2-7)", - 0, - PORT_92_INV, - port_92_init, port_92_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Port 92 Register (inverted bits 2-7)", + .internal_name = "port_92_inv", + .flags = 0, + .local = PORT_92_INV, + .init = port_92_init, + .close = port_92_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t port_92_word_device = { - "Port 92 Register (16-bit)", - 0, - PORT_92_WORD, - port_92_init, port_92_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Port 92 Register (16-bit)", + .internal_name = "port_92_word", + .flags = 0, + .local = PORT_92_WORD, + .init = port_92_init, + .close = port_92_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t port_92_pci_device = { - "Port 92 Register (PCI)", - 0, - PORT_92_PCI, - port_92_init, port_92_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Port 92 Register (PCI)", + .internal_name = "port_92_pci", + .flags = 0, + .local = PORT_92_PCI, + .init = port_92_init, + .close = port_92_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/printer/CMakeLists.txt b/src/printer/CMakeLists.txt new file mode 100644 index 000000000..5990789bb --- /dev/null +++ b/src/printer/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(print OBJECT png.c prt_cpmap.c prt_escp.c prt_text.c prt_ps.c) diff --git a/src/printer/png.c b/src/printer/png.c index dbef31a91..f23ce0949 100644 --- a/src/printer/png.c +++ b/src/printer/png.c @@ -61,10 +61,15 @@ #ifdef _WIN32 # define PATH_PNG_DLL "libpng16-16.dll" +#elif defined __APPLE__ +# define PATH_PNG_DLL "libpng16.dylib" #else # define PATH_PNG_DLL "libpng16.so" #endif +#ifndef PNG_Z_DEFAULT_STRATEGY +#define PNG_Z_DEFAULT_STRATEGY 1 +#endif # define PNGFUNC(x) png_ ## x @@ -105,7 +110,7 @@ warning_handler(png_structp arg, const char *str) /* Write the given image as an 8-bit GrayScale PNG image file. */ int -png_write_gray(wchar_t *fn, int inv, uint8_t *pix, int16_t w, int16_t h) +png_write_gray(char *fn, int inv, uint8_t *pix, int16_t w, int16_t h) { png_structp png = NULL; png_infop info = NULL; @@ -114,11 +119,11 @@ png_write_gray(wchar_t *fn, int inv, uint8_t *pix, int16_t w, int16_t h) FILE *fp; /* Create the image file. */ - fp = plat_fopen(fn, L"wb"); + fp = plat_fopen(fn, "wb"); if (fp == NULL) { /* Yes, this looks weird. */ if (fp == NULL) - png_log("PNG: file %ls could not be opened for writing!\n", fn); + png_log("PNG: file %s could not be opened for writing!\n", fn); else error: png_log("PNG: fatal error, bailing out, error = %i\n", errno); @@ -185,7 +190,7 @@ error: /* Write the given BITMAP-format image as an 8-bit RGBA PNG image file. */ void -png_write_rgb(wchar_t *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol) +png_write_rgb(char *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol) { png_structp png = NULL; png_infop info = NULL; @@ -195,9 +200,9 @@ png_write_rgb(wchar_t *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, P int i; /* Create the image file. */ - fp = plat_fopen(fn, L"wb"); + fp = plat_fopen(fn, "wb"); if (fp == NULL) { - png_log("PNG: File %ls could not be opened for writing!\n", fn); + png_log("PNG: File %s could not be opened for writing!\n", fn); error: if (png != NULL) PNGFUNC(destroy_write_struct)(&png, &info); @@ -229,8 +234,8 @@ error: PNGFUNC(set_compression_strategy)(png, PNG_Z_DEFAULT_STRATEGY); PNGFUNC(set_compression_window_bits)(png, 15); PNGFUNC(set_compression_method)(png, 8); - PNGFUNC(set_compression_buffer_size)(png, 8192); - + PNGFUNC(set_compression_buffer_size)(png, 8192); + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); @@ -242,7 +247,7 @@ error: } PNGFUNC(set_PLTE)(png, info, palette, 256); - + /* Create a buffer for scanlines of pixels. */ rows = (png_bytep *)malloc(sizeof(png_bytep) * h); for (i = 0; i < h; i++) { @@ -251,14 +256,14 @@ error: } PNGFUNC(set_rows)(png, info, rows); - + PNGFUNC(write_png)(png, info, 0, NULL); /* Clean up. */ - (void)fclose(fp); + (void)fclose(fp); PNGFUNC(destroy_write_struct)(&png, &info); - + /* No longer need the row buffers. */ free(rows); } diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c index 62c00d544..2c1465878 100644 --- a/src/printer/prt_cpmap.c +++ b/src/printer/prt_cpmap.c @@ -10,12 +10,12 @@ * * * - * Authors: Michael Dr�ing, + * Authors: Michael Drüing, * Fred N. van Kempen, * * Based on code by Frederic Weymann (originally for DosBox.) * - * Copyright 2018 Michael Dr�ing. + * Copyright 2018 Michael Drüing. * Copyright 2018 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with @@ -54,7 +54,7 @@ #include #include #include <86box/86box.h> -#include <86box/plat.h> +#include <86box/plat.h> #include <86box/printer.h> @@ -553,21 +553,23 @@ static const struct { uint16_t code; const uint16_t *map; } maps[] = { - { 437, cp437Map }, - { 737, cp737Map }, - { 775, cp775Map }, - { 850, cp850Map }, - { 852, cp852Map }, - { 855, cp855Map }, - { 857, cp857Map }, - { 860, cp860Map }, - { 861, cp861Map }, - { 862, cp862Map }, - { 863, cp863Map }, - { 864, cp864Map }, - { 865, cp865Map }, - { 866, cp866Map }, - { -1, NULL } +// clang-format off + { 437, cp437Map }, + { 737, cp737Map }, + { 775, cp775Map }, + { 850, cp850Map }, + { 852, cp852Map }, + { 855, cp855Map }, + { 857, cp857Map }, + { 860, cp860Map }, + { 861, cp861Map }, + { 862, cp862Map }, + { 863, cp863Map }, + { 864, cp864Map }, + { 865, cp865Map }, + { 866, cp866Map }, + { -1, NULL } +// clang-format on }; @@ -587,7 +589,7 @@ select_codepage(uint16_t code, uint16_t *curmap) } i++; } - + for (i = 0; i < 256; i++) curmap[i] = map_to_use[i]; } diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index b30d955ef..ec07dc95f 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -10,12 +10,12 @@ * * * - * Authors: Michael Dr�ing, + * Authors: Michael Drüing, * Fred N. van Kempen, * * Based on code by Frederic Weymann (originally for DosBox.) * - * Copyright 2018,2019 Michael Dr�ing. + * Copyright 2018,2019 Michael Drüing. * Copyright 2019,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with @@ -61,8 +61,9 @@ #include <86box/machine.h> #include <86box/timer.h> #include <86box/mem.h> -#include <86box/rom.h> +#include <86box/rom.h> #include <86box/pit.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/plat_dynld.h> #include <86box/ui.h> @@ -88,6 +89,8 @@ #ifdef _WIN32 # define PATH_FREETYPE_DLL "freetype.dll" +#elif defined __APPLE__ +# define PATH_FREETYPE_DLL "libfreetype.dylib" #else # define PATH_FREETYPE_DLL "libfreetype.so.6" #endif @@ -99,7 +102,7 @@ void *ft_handle = NULL; static int (*ft_Init_FreeType)(FT_Library *alibrary); static int (*ft_Done_Face)(FT_Face face); -static int (*ft_New_Face)(FT_Library library, const char *filepathname, +static int (*ft_New_Face)(FT_Library library, const char *filepathname, FT_Long face_index, FT_Face *aface); static int (*ft_Set_Char_Size)(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, @@ -205,14 +208,14 @@ typedef struct { pc_timer_t pulse_timer; pc_timer_t timeout_timer; - wchar_t page_fn[260]; + char page_fn[260]; uint8_t color; - + /* page data (TODO: make configurable) */ double page_width, /* all in inches */ page_height, left_margin, - top_margin, + top_margin, right_margin, bottom_margin; uint16_t dpi; @@ -257,8 +260,8 @@ typedef struct { uint8_t esc_parms[20]; /* 20 should be enough for everybody */ /* internal page data */ - wchar_t fontpath[1024]; - wchar_t pagepath[1024]; + char fontpath[1024]; + char pagepath[1024]; psurface_t *page; double curr_x, curr_y; /* print head position (inch) */ uint16_t current_font; @@ -291,7 +294,7 @@ typedef struct { uint8_t msb; /* MSB mode, -1 = off */ uint8_t ctrl; - + PALETTE palcol; } escp_t; @@ -321,9 +324,9 @@ static const uint16_t codepages[15] = { }; -/* "patches" to the codepage for the international charsets +/* "patches" to the codepage for the international charsets * these bytes patch the following 12 positions of the char table, in order: - * 0x23 0x24 0x40 0x5b 0x5c 0x5d 0x5e 0x60 0x7b 0x7c 0x7d 0x7e + * 0x23 0x24 0x40 0x5b 0x5c 0x5d 0x5e 0x60 0x7b 0x7c 0x7d 0x7e * TODO: Implement the missing international charsets */ static const uint16_t intCharSets[15][12] = { @@ -395,13 +398,13 @@ escp_log(const char *fmt, ...) /* Dump the current page into a formatted file. */ -static void +static void dump_page(escp_t *dev) { - wchar_t path[1024]; + char path[1024]; - wcscpy(path, dev->pagepath); - wcscat(path, dev->page_fn); + strcpy(path, dev->pagepath); + strcat(path, dev->page_fn); png_write_rgb(path, dev->page->pixels, dev->page->w, dev->page->h, dev->page->pitch, dev->palcol); } @@ -423,7 +426,7 @@ new_page(escp_t *dev, int8_t save, int8_t resetx) } /* Make the page's file name. */ - plat_tempfile(dev->page_fn, NULL, L".png"); + plat_tempfile(dev->page_fn, NULL, ".png"); } @@ -453,7 +456,7 @@ timeout_timer(void *priv) } -static void +static void fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, escp_t *dev) { uint8_t colormask; @@ -499,7 +502,7 @@ reset_printer(escp_t *dev) dev->density_k = 0; dev->density_l = 1; dev->density_y = 2; - dev->density_z = 3; + dev->density_z = 3; dev->char_tables[0] = 0; /* italics */ dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ dev->defined_unit = -1.0; @@ -510,7 +513,7 @@ reset_printer(escp_t *dev) dev->msb = 255; dev->print_everything_count = 0; dev->lq_typeface = TYPEFACE_COURIER; - + init_codepage(dev, dev->char_tables[dev->curr_char_table]); update_font(dev); @@ -520,11 +523,11 @@ reset_printer(escp_t *dev) for (i = 0; i < 32; i++) dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); dev->num_horizontal_tabs = 32; - dev->num_vertical_tabs = 255; - + dev->num_vertical_tabs = -1; + if (dev->page != NULL) - dev->page->dirty = 0; - + dev->page->dirty = 0; + escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", dev->page_width, dev->page_height, (int)dev->dpi, (int)dev->cpi, (int)dev->lpi); @@ -553,9 +556,8 @@ init_codepage(escp_t *dev, uint16_t num) static void update_font(escp_t *dev) { - wchar_t path[1024]; - wchar_t *fn; - char temp[1024]; + char path[1024]; + char *fn; FT_Matrix matrix; double hpoints = 10.5; double vpoints = 10.5; @@ -594,18 +596,15 @@ update_font(escp_t *dev) } /* Create a full pathname for the ROM file. */ - wcscpy(path, dev->fontpath); - plat_path_slash(path); - wcscat(path, fn); + strcpy(path, dev->fontpath); + path_slash(path); + strcat(path, fn); - /* Convert (back) to ANSI for the FreeType API. */ - wcstombs(temp, path, sizeof(temp)); - - escp_log("Temp file=%s\n", temp); + escp_log("Temp file=%s\n", path); /* Load the new font. */ - if (ft_New_Face(ft_lib, temp, 0, &dev->fontface)) { - escp_log("ESC/P: unable to load font '%s'\n", temp); + if (ft_New_Face(ft_lib, path, 0, &dev->fontface)) { + escp_log("ESC/P: unable to load font '%s'\n", path); dev->fontface = NULL; } @@ -689,12 +688,12 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_seen = dev->fss_seen = 0; dev->esc_parms_curr = 0; - escp_log("Command pending=%02x, font path=%ls\n", dev->esc_pending, dev->fontpath); + escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { case 0x02: // Undocumented case 0x0a: // Reverse line feed case 0x0c: // Return to top of current page - case 0x0e: // Select double-width printing (one line) (ESC SO) + case 0x0e: // Select double-width printing (one line) (ESC SO) case 0x0f: // Select condensed printing (ESC SI) case 0x23: // Cancel MSB control (ESC #) case 0x30: // Select 1/8-inch line spacing (ESC 0) @@ -715,7 +714,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x47: // Select double-strike printing (ESC G) case 0x48: // Cancel double-strike printing (ESC H) case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin + case 0x4f: // Cancel bottom margin case 0x50: // Select 10.5-point, 10-cpi (ESC P) case 0x54: // Cancel superscript/subscript printing (ESC T) case 0x5e: // Enable printing of all character codes on next character @@ -727,7 +726,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x852: // Select reverse feed mode (FS R) dev->esc_parms_req = 0; break; - + case 0x19: // Control paper loading/ejecting (ESC EM) case 0x20: // Set intercharacter space (ESC SP) case 0x21: // Master select (ESC !) @@ -791,7 +790,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x5b: // Select character height, width, line spacing dev->esc_parms_req = 7; break; - + case 0x62: // Set vertical tabs in VFU channels (ESC b) case 0x42: // Set vertical tabs (ESC B) dev->num_vertical_tabs = 0; @@ -817,7 +816,7 @@ process_char(escp_t *dev, uint8_t ch) return 1; default: - escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", + escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", dev->esc_pending >= 0x20 ? dev->esc_pending : '?', dev->esc_pending); dev->esc_parms_req = 0; dev->esc_pending = 0; @@ -834,7 +833,7 @@ process_char(escp_t *dev, uint8_t ch) if (dev->esc_pending == '(') { dev->esc_pending = 0x0200 + ch; - escp_log("Two-byte command pending=%03x, font path=%ls\n", dev->esc_pending, dev->fontpath); + escp_log("Two-byte command pending=%03x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { case 0x0242: // Bar code setup and print (ESC (B) case 0x025e: // Print data as characters (ESC (^) @@ -881,11 +880,11 @@ process_char(escp_t *dev, uint8_t ch) /* Collect vertical tabs. */ if (dev->esc_pending == 0x42) { /* check if we're done */ - if ((ch == 0) || + if ((ch == 0) || (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double)ch * dev->linespacing)) { dev->esc_pending = 0; } else { - if (dev->num_vertical_tabs < 16) + if (dev->num_vertical_tabs >= 0 && dev->num_vertical_tabs < 16) dev->vertical_tabs[dev->num_vertical_tabs++] = (double)ch * dev->linespacing; } } @@ -893,7 +892,7 @@ process_char(escp_t *dev, uint8_t ch) /* Collect horizontal tabs. */ if (dev->esc_pending == 0x44) { /* check if we're done... */ - if ((ch == 0) || + if ((ch == 0) || (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double)ch * (1.0 / dev->cpi))) { dev->esc_pending = 0; } else { @@ -992,8 +991,8 @@ process_char(escp_t *dev, uint8_t ch) case 0x85a: /* Print 24-bit hex-density graphics (FS Z) */ setup_bit_image(dev, 40, PARAM16(0)); - break; - + break; + case 0x2a: /* select bit image (ESC *) */ setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); break; @@ -1262,9 +1261,9 @@ process_char(escp_t *dev, uint8_t ch) break; case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet - if (dev->linespacing < 0) + if (dev->linespacing < 0) dev->linespacing *= -1; - break; + break; case 0x6a: // Reverse paper feed (ESC j) reverse = (double)PARAM16(0) / (double)216.0; @@ -1459,7 +1458,7 @@ process_char(escp_t *dev, uint8_t ch) switch (ch) { case 0x00: return 1; - + case 0x07: /* Beeper (BEL) */ /* TODO: beep? */ return 1; @@ -1584,7 +1583,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x1b: /* ESC */ dev->esc_seen = 1; return 1; - + case 0x1c: /* FS (IBM commands) */ dev->fss_seen = 1; return 1; @@ -1655,7 +1654,7 @@ handle_char(escp_t *dev, uint8_t ch) /* mark the page as dirty if anything is drawn */ if ((ch != 0x20) || (dev->font_score != SCORE_NONE)) dev->page->dirty = 1; - + /* draw the glyph */ blit_glyph(dev, pen_x, pen_y, 0); blit_glyph(dev, pen_x + 1, pen_y, 1); @@ -1691,20 +1690,20 @@ handle_char(escp_t *dev, uint8_t ch) if (dev->font_score != SCORE_NONE && (dev->font_style & (STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE))) { /* Find out where to put the line. */ line_y = PIXY; - + if (dev->font_style & STYLE_UNDERLINE) line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.9)); if (dev->font_style & STYLE_STRIKETHROUGH) line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.45)); if (dev->font_style & STYLE_OVERSCORE) line_y = PIXY - ((dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) ? 5 : 0); - + draw_hline(dev, pen_x, PIXX, line_y, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); - + if (dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) draw_hline(dev, line_start, PIXX, line_y + 5, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); } - + if ((dev->curr_x + x_advance) > dev->right_margin) { dev->curr_x = dev->left_margin; dev->curr_y += dev->linespacing; @@ -1739,7 +1738,7 @@ blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) *dst |= (dev->color | 0x1f); else { *dst += src; - *dst |= dev->color; + *dst |= dev->color; } } else *dst = src|dev->color; @@ -1903,7 +1902,7 @@ print_bit_graph(escp_t *dev, uint8_t ch) pixel_w = 1; pixel_h = 1; - + if (dev->bg_adjacent) { /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; @@ -1983,11 +1982,11 @@ write_ctrl(uint8_t val, void *priv) dev->ack = 1; timer_set_delay_u64(&dev->pulse_timer, ISACONST); - timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); + timer_set_delay_u64(&dev->timeout_timer, 5000000 * TIMER_USEC); } dev->ctrl = val; - + dev->autofeed = ((val & 0x02) > 0); } @@ -2058,24 +2057,24 @@ escp_init(void *lpt) dev->lpt = lpt; /* Create a full pathname for the font files. */ - if(wcslen(exe_path) >= sizeof_w(dev->fontpath)) { + if(strlen(exe_path) >= sizeof(dev->fontpath)) { free(dev); return(NULL); } - wcscpy(dev->fontpath, exe_path); - plat_path_slash(dev->fontpath); - wcscat(dev->fontpath, L"roms/printer/fonts/"); + strcpy(dev->fontpath, exe_path); + path_slash(dev->fontpath); + strcat(dev->fontpath, "roms/printer/fonts/"); /* Create the full path for the page images. */ - plat_append_filename(dev->pagepath, usr_path, L"printer"); + path_append_filename(dev->pagepath, usr_path, "printer"); if (! plat_dir_check(dev->pagepath)) plat_dir_create(dev->pagepath); - plat_path_slash(dev->pagepath); + path_slash(dev->pagepath); dev->page_width = PAGE_WIDTH; dev->page_height = PAGE_HEIGHT; - dev->dpi = PAGE_DPI; + dev->dpi = PAGE_DPI; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *)malloc(sizeof(psurface_t)); @@ -2085,7 +2084,7 @@ escp_init(void *lpt) dev->page->pixels = (uint8_t *)malloc(dev->page->pitch * dev->page->h); memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); - /* Initialize parameters. */ + /* Initialize parameters. */ for (i = 0; i < 32; i++) { dev->palcol[i].r = 255; dev->palcol[i].g = 255; @@ -2147,12 +2146,13 @@ escp_close(void *priv) const lpt_device_t lpt_prt_escp_device = { - "EPSON ESC/P compatible printer", - escp_init, - escp_close, - write_data, - write_ctrl, - read_data, - read_status, - read_ctrl + .name = "Generic ESC/P Dot-Matrix", + .internal_name = "dot_matrix", + .init = escp_init, + .close = escp_close, + .write_data = write_data, + .write_ctrl = write_ctrl, + .read_data = read_data, + .read_status = read_status, + .read_ctrl = read_ctrl }; diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index b3d7500d4..231707897 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -27,50 +27,37 @@ #include <86box/lpt.h> #include <86box/timer.h> #include <86box/pit.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/plat_dynld.h> #include <86box/ui.h> #include <86box/prt_devs.h> + #ifdef _WIN32 # define GSDLLAPI __stdcall #else # define GSDLLAPI #endif -#define GS_ARG_ENCODING_UTF16LE 2 -#define gs_error_Quit -101 -#define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" -#define PATH_GHOSTSCRIPT_SO "libgs.so" +#define GS_ARG_ENCODING_UTF8 1 +#define gs_error_Quit -101 + +#ifdef _WIN32 +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) +# define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" +#else +# define PATH_GHOSTSCRIPT_DLL "gsdll64.dll" +#endif +#elif defined __APPLE__ +#define PATH_GHOSTSCRIPT_DLL "libgs.dylib" +#else +#define PATH_GHOSTSCRIPT_DLL "libgs.so.9" +#endif #define POSTSCRIPT_BUFFER_LENGTH 65536 -typedef struct gsapi_revision_s { - const char *product; - const char *copyright; - long revision; - long revisiondate; -} gsapi_revision_t; - -static int (GSDLLAPI *gsapi_revision)(gsapi_revision_t *pr, int len); -static int (GSDLLAPI *gsapi_new_instance)(void **pinstance, void *caller_handle); -static void (GSDLLAPI *gsapi_delete_instance)(void *instance); -static int (GSDLLAPI *gsapi_set_arg_encoding)(void *instance, int encoding); -static int (GSDLLAPI *gsapi_init_with_args)(void *instance, int argc, char **argv); -static int (GSDLLAPI *gsapi_exit)(void *instance); - -static dllimp_t ghostscript_imports[] = { - { "gsapi_revision", &gsapi_revision }, - { "gsapi_new_instance", &gsapi_new_instance }, - { "gsapi_delete_instance", &gsapi_delete_instance }, - { "gsapi_set_arg_encoding", &gsapi_set_arg_encoding }, - { "gsapi_init_with_args", &gsapi_init_with_args }, - { "gsapi_exit", &gsapi_exit }, - { NULL, NULL } -}; - -static void *ghostscript_handle = NULL; typedef struct { @@ -90,20 +77,49 @@ typedef struct bool autofeed; uint8_t ctrl; - wchar_t printer_path[260]; + char printer_path[260]; - wchar_t filename[260]; + char filename[260]; char buffer[POSTSCRIPT_BUFFER_LENGTH]; size_t buffer_pos; } ps_t; +typedef struct gsapi_revision_s { + const char *product; + const char *copyright; + long revision; + long revisiondate; +} gsapi_revision_t; + + +static int (GSDLLAPI *gsapi_revision)(gsapi_revision_t *pr, int len); +static int (GSDLLAPI *gsapi_new_instance)(void **pinstance, void *caller_handle); +static void (GSDLLAPI *gsapi_delete_instance)(void *instance); +static int (GSDLLAPI *gsapi_set_arg_encoding)(void *instance, int encoding); +static int (GSDLLAPI *gsapi_init_with_args)(void *instance, int argc, char **argv); +static int (GSDLLAPI *gsapi_exit)(void *instance); + +static dllimp_t ghostscript_imports[] = { +// clang-format off + { "gsapi_revision", &gsapi_revision }, + { "gsapi_new_instance", &gsapi_new_instance }, + { "gsapi_delete_instance", &gsapi_delete_instance }, + { "gsapi_set_arg_encoding", &gsapi_set_arg_encoding }, + { "gsapi_init_with_args", &gsapi_init_with_args }, + { "gsapi_exit", &gsapi_exit }, + { NULL, NULL } +// clang-format on +}; + +static void *ghostscript_handle = NULL; + + static void reset_ps(ps_t *dev) { - if (dev == NULL) { + if (dev == NULL) return; - } dev->ack = false; @@ -114,6 +130,7 @@ reset_ps(ps_t *dev) timer_disable(&dev->timeout_timer); } + static void pulse_timer(void *priv) { @@ -127,130 +144,122 @@ pulse_timer(void *priv) timer_disable(&dev->pulse_timer); } + static int convert_to_pdf(ps_t *dev) { volatile int code; void *instance = NULL; - wchar_t input_fn[1024], output_fn[1024], *gsargv[9]; + char input_fn[1024], output_fn[1024], *gsargv[9]; - input_fn[0] = 0; - wcscat(input_fn, dev->printer_path); - wcscat(input_fn, dev->filename); + strcpy(input_fn, dev->printer_path); + path_slash(input_fn); + strcat(input_fn, dev->filename); - output_fn[0] = 0; - wcscat(output_fn, input_fn); - wcscpy(output_fn + wcslen(output_fn) - 4, L".pdf"); + strcpy(output_fn, input_fn); + strcpy(output_fn + strlen(output_fn) - 3, ".pdf"); - gsargv[0] = L""; - gsargv[1] = L"-dNOPAUSE"; - gsargv[2] = L"-dBATCH"; - gsargv[3] = L"-dSAFER"; - gsargv[4] = L"-sDEVICE=pdfwrite"; - gsargv[5] = L"-q"; - gsargv[6] = L"-o"; + gsargv[0] = ""; + gsargv[1] = "-dNOPAUSE"; + gsargv[2] = "-dBATCH"; + gsargv[3] = "-dSAFER"; + gsargv[4] = "-sDEVICE=pdfwrite"; + gsargv[5] = "-q"; + gsargv[6] = "-o"; gsargv[7] = output_fn; gsargv[8] = input_fn; code = gsapi_new_instance(&instance, dev); - if (code < 0) { + if (code < 0) return code; - } - code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF16LE); + code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF8); - if (code == 0) { - code = gsapi_init_with_args(instance, 9, (char **) gsargv); - } + if (code == 0) + code = gsapi_init_with_args(instance, 9, gsargv); - if (code == 0 || code == gs_error_Quit) { + if (code == 0 || code == gs_error_Quit) code = gsapi_exit(instance); - } else { + else gsapi_exit(instance); - } gsapi_delete_instance(instance); - if (code == 0) { + if (code == 0) plat_remove(input_fn); - } else { + else plat_remove(output_fn); - } return code; } -static void -finish_document(ps_t *dev) -{ - if (ghostscript_handle != NULL) { - convert_to_pdf(dev); - } - - dev->filename[0] = 0; -} static void -write_buffer(ps_t *dev, bool newline) +write_buffer(ps_t *dev, bool finish) { - wchar_t path[1024]; + char path[1024]; FILE *fp; - if (dev->buffer[0] == 0) { + if (dev->buffer[0] == 0) return; - } - if (dev->filename[0] == 0) { - plat_tempfile(dev->filename, NULL, L".tmp"); - } + if (dev->filename[0] == 0) + plat_tempfile(dev->filename, NULL, ".ps"); - path[0] = 0; - wcscat(path, dev->printer_path); - wcscat(path, dev->filename); + strcpy(path, dev->printer_path); + path_slash(path); + strcat(path, dev->filename); - fp = plat_fopen(path, L"a"); - if (fp == NULL) { + fp = plat_fopen(path, "a"); + if (fp == NULL) return; - } fseek(fp, 0, SEEK_END); - fprintf(fp, "%.*s%s", POSTSCRIPT_BUFFER_LENGTH, dev->buffer, newline ? "\n" : ""); + fprintf(fp, "%.*s", POSTSCRIPT_BUFFER_LENGTH, dev->buffer); fclose(fp); dev->buffer[0] = 0; dev->buffer_pos = 0; + + if (finish) { + if (ghostscript_handle != NULL) + convert_to_pdf(dev); + + dev->filename[0] = 0; + } } + static void timeout_timer(void *priv) { ps_t *dev = (ps_t *) priv; - write_buffer(dev, false); - finish_document(dev); + write_buffer(dev, true); timer_disable(&dev->timeout_timer); } + static void ps_write_data(uint8_t val, void *p) { ps_t *dev = (ps_t *) p; - if (dev == NULL) { + if (dev == NULL) return; - } dev->data = (char) val; } + static void process_data(ps_t *dev) { /* Check for non-printable characters */ - if (dev->data < 0x20 || dev->data == 0x7F) { + if ((dev->data < 0x20) || (dev->data == 0x7f)) { switch (dev->data) { /* The following characters are considered white-space by the PostScript specification */ @@ -267,8 +276,7 @@ process_data(ps_t *dev) /* Ctrl+D (0x04) marks the end of the document */ case '\4': - write_buffer(dev, false); - finish_document(dev); + write_buffer(dev, true); return; /* Don't bother with the others */ @@ -278,32 +286,29 @@ process_data(ps_t *dev) } /* Flush the buffer if we have run to its end */ - if (dev->buffer_pos == POSTSCRIPT_BUFFER_LENGTH - 1) { + if (dev->buffer_pos == POSTSCRIPT_BUFFER_LENGTH - 1) write_buffer(dev, false); - dev->buffer_pos = 0; - } dev->buffer[dev->buffer_pos++] = dev->data; dev->buffer[dev->buffer_pos] = 0; } + static void ps_write_ctrl(uint8_t val, void *p) { ps_t *dev = (ps_t *) p; - if (dev == NULL) { + if (dev == NULL) return; - } dev->autofeed = val & 0x02 ? true : false; - if (val & 0x08) { + if (val & 0x08) dev->select = true; - } if ((val & 0x04) && !(dev->ctrl & 0x04)) { - // reset printer + /* Reset printer */ dev->select = false; reset_ps(dev); @@ -315,27 +320,26 @@ ps_write_ctrl(uint8_t val, void *p) dev->ack = true; timer_set_delay_u64(&dev->pulse_timer, ISACONST); - timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); + timer_set_delay_u64(&dev->timeout_timer, 5000000 * TIMER_USEC); } dev->ctrl = val; } + static uint8_t ps_read_status(void *p) { ps_t *dev = (ps_t *) p; - uint8_t ret = 0x1f; + uint8_t ret = 0x9f; - ret |= 0x80; - - if (!dev->ack) { + if (!dev->ack) ret |= 0x40; - } return(ret); } + static void * ps_init(void *lpt) { @@ -347,48 +351,45 @@ ps_init(void *lpt) dev->ctrl = 0x04; dev->lpt = lpt; - reset_ps(dev); - /* Try loading the DLL. */ ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); - if (ghostscript_handle == NULL) { + if (ghostscript_handle == NULL) ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2114, (wchar_t *) IDS_2132); - } else { - if (gsapi_revision(&rev, sizeof(rev)) == 0) { + else { + if (gsapi_revision(&rev, sizeof(rev)) == 0) pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); - } else { + else { dynld_close(ghostscript_handle); ghostscript_handle = NULL; } } - // Cache print folder path + /* Cache print folder path. */ memset(dev->printer_path, 0x00, sizeof(dev->printer_path)); - plat_append_filename(dev->printer_path, usr_path, L"printer"); - if (!plat_dir_check(dev->printer_path)) { + path_append_filename(dev->printer_path, usr_path, "printer"); + if (!plat_dir_check(dev->printer_path)) plat_dir_create(dev->printer_path); - } - plat_path_slash(dev->printer_path); + path_slash(dev->printer_path); timer_add(&dev->pulse_timer, pulse_timer, dev, 0); timer_add(&dev->timeout_timer, timeout_timer, dev, 0); + reset_ps(dev); + return(dev); } + static void ps_close(void *p) { ps_t *dev = (ps_t *) p; - if (dev == NULL) { + if (dev == NULL) return; - } - if (dev->buffer[0] != 0) { - write_buffer(dev, false); - finish_document(dev); - } + if (dev->buffer[0] != 0) + write_buffer(dev, true); if (ghostscript_handle != NULL) { dynld_close(ghostscript_handle); @@ -398,8 +399,10 @@ ps_close(void *p) free(dev); } + const lpt_device_t lpt_prt_ps_device = { - .name = "Generic PostScript printer", + .name = "Generic PostScript Printer", + .internal_name = "postscript", .init = ps_init, .close = ps_close, .write_data = ps_write_data, @@ -407,4 +410,4 @@ const lpt_device_t lpt_prt_ps_device = { .read_data = NULL, .read_status = ps_read_status, .read_ctrl = NULL -}; \ No newline at end of file +}; diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index 4024deb64..c57a4fef3 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -60,7 +60,8 @@ #include <86box/device.h> #include <86box/timer.h> #include <86box/pit.h> -#include <86box/plat.h> +#include <86box/path.h> +#include <86box/plat.h> #include <86box/lpt.h> #include <86box/printer.h> #include <86box/prt_devs.h> @@ -102,7 +103,7 @@ typedef struct { void * lpt; /* Output file name. */ - wchar_t filename[1024]; + char filename[1024]; /* Printer timeout. */ pc_timer_t pulse_timer; @@ -112,7 +113,7 @@ typedef struct { double page_width, /* all in inches */ page_height, left_margin, - top_margin, + top_margin, right_margin, bot_margin; @@ -140,26 +141,26 @@ typedef struct { /* Dump the current page into a formatted file. */ -static void +static void dump_page(prnt_t *dev) { - wchar_t path[1024]; + char path[1024]; uint16_t x, y; uint8_t ch; FILE *fp; /* Create the full path for this file. */ memset(path, 0x00, sizeof(path)); - plat_append_filename(path, usr_path, L"printer"); + path_append_filename(path, usr_path, "printer"); if (! plat_dir_check(path)) plat_dir_create(path); - plat_path_slash(path); - wcscat(path, dev->filename); + path_slash(path); + strcat(path, dev->filename); /* Create the file. */ - fp = plat_fopen(path, L"a"); + fp = plat_fopen(path, "a"); if (fp == NULL) { - //ERRLOG("PRNT: unable to create print page '%ls'\n", path); + //ERRLOG("PRNT: unable to create print page '%s'\n", path); return; } fseek(fp, 0, SEEK_END); @@ -250,7 +251,7 @@ reset_printer(prnt_t *dev) dev->page->dirty = 0; /* Create a file for this page. */ - plat_tempfile(dev->filename, NULL, L".txt"); + plat_tempfile(dev->filename, NULL, ".txt"); timer_disable(&dev->pulse_timer); timer_disable(&dev->timeout_timer); @@ -410,7 +411,7 @@ write_ctrl(uint8_t val, void *priv) dev->ack = 1; timer_set_delay_u64(&dev->pulse_timer, ISACONST); - timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); + timer_set_delay_u64(&dev->timeout_timer, 5000000 * TIMER_USEC); } dev->ctrl = val; @@ -483,12 +484,13 @@ prnt_close(void *priv) const lpt_device_t lpt_prt_text_device = { - "Generic TEXT printer", - prnt_init, - prnt_close, - write_data, - write_ctrl, - NULL, - read_status, - NULL + .name = "Generic Text Printer", + .internal_name = "text_prt", + .init = prnt_init, + .close = prnt_close, + .write_data = write_data, + .write_ctrl = write_ctrl, + .read_data = NULL, + .read_status = read_status, + .read_ctrl = NULL }; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt new file mode 100644 index 000000000..0cb4560c4 --- /dev/null +++ b/src/qt/CMakeLists.txt @@ -0,0 +1,357 @@ +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +if (USE_QT6) + set(QT_MAJOR 6) +else() + set(QT_MAJOR 5) +endif() + +set(QT_STATIC ${STATIC_BUILD}) + +if(QT_STATIC AND MINGW) + set(CMAKE_PREFIX_PATH "$ENV{MSYSTEM_PREFIX}/qt${QT_MAJOR}-static") +endif() + +if(VCPKG_TOOLCHAIN AND VCPKG_USE_HOST_TOOLS) + set(QT_HOST_PATH "${VCPKG_INSTALLED_DIR}/${VCPKG_HOST_TRIPLET}/tools/Qt${QT_MAJOR}") + set(QT_HOST_PATH_CMAKE_DIR ${VCPKG_INSTALLED_DIR}/${VCPKG_HOST_TRIPLET}) + set(Qt${QT_MAJOR}LinguistTools_ROOT ${QT_HOST_PATH_CMAKE_DIR}) +endif() + +# CMake is a bitch and calls the Harfbuzz config twice on MinGW + Qt6 +# if config mode is preferred :) +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF) + +find_package(Threads REQUIRED) +find_package(Qt${QT_MAJOR} COMPONENTS Core Widgets Network OpenGL REQUIRED) +find_package(Qt${QT_MAJOR}LinguistTools REQUIRED NO_CMAKE_FIND_ROOT_PATH) + +# TODO: Is this the correct way to do this, and is it required on any +# other platforms or with Qt 5? +if(APPLE AND USE_QT6) + find_package(Qt6Gui/Qt6QCocoaIntegrationPlugin REQUIRED) + find_package(Qt6Widgets/Qt6QMacStylePlugin REQUIRED) + find_package(Qt6Gui/Qt6QICOPlugin REQUIRED) + find_package(Qt6Gui/Qt6QICNSPlugin REQUIRED) +endif() + +add_library(plat STATIC + qt.c + qt_main.cpp + qt_platform.cpp +) + +add_library(ui STATIC + qt_ui.cpp + qt_cdrom.c + + qt_mainwindow.cpp + qt_mainwindow.hpp + qt_mainwindow.ui + qt_machinestatus.cpp + qt_machinestatus.hpp + qt_mediamenu.cpp + qt_mediamenu.hpp + qt_rendererstack.cpp + qt_rendererstack.hpp + qt_rendererstack.ui + qt_renderercommon.cpp + qt_renderercommon.hpp + qt_softwarerenderer.cpp + qt_softwarerenderer.hpp + qt_hardwarerenderer.cpp + qt_hardwarerenderer.hpp + qt_openglrenderer.cpp + qt_openglrenderer.hpp + qt_opengloptions.cpp + qt_opengloptions.hpp + qt_opengloptionsdialog.cpp + qt_opengloptionsdialog.hpp + qt_opengloptionsdialog.ui + + qt_settings.cpp + qt_settings.hpp + qt_settings.ui + + qt_settingsmachine.cpp + qt_settingsmachine.hpp + qt_settingsmachine.ui + qt_settingsdisplay.cpp + qt_settingsdisplay.hpp + qt_settingsdisplay.ui + qt_settingsinput.cpp + qt_settingsinput.hpp + qt_settingsinput.ui + qt_settingssound.cpp + qt_settingssound.hpp + qt_settingssound.ui + qt_settingsnetwork.cpp + qt_settingsnetwork.hpp + qt_settingsnetwork.ui + qt_settingsports.cpp + qt_settingsports.hpp + qt_settingsports.ui + qt_settingsstoragecontrollers.cpp + qt_settingsstoragecontrollers.hpp + qt_settingsstoragecontrollers.ui + qt_settingsharddisks.cpp + qt_settingsharddisks.hpp + qt_settingsharddisks.ui + qt_settingsfloppycdrom.cpp + qt_settingsfloppycdrom.hpp + qt_settingsfloppycdrom.ui + qt_settingsotherremovable.cpp + qt_settingsotherremovable.hpp + qt_settingsotherremovable.ui + qt_settingsotherperipherals.cpp + qt_settingsotherperipherals.hpp + qt_settingsotherperipherals.ui + qt_settings_bus_tracking.cpp + qt_settings_bus_tracking.hpp + + qt_deviceconfig.cpp + qt_deviceconfig.hpp + qt_deviceconfig.ui + qt_joystickconfiguration.cpp + qt_joystickconfiguration.hpp + qt_joystickconfiguration.ui + + qt_filefield.cpp + qt_filefield.hpp + qt_filefield.ui + qt_newfloppydialog.cpp + qt_newfloppydialog.hpp + qt_newfloppydialog.ui + qt_harddiskdialog.cpp + qt_harddiskdialog.hpp + qt_harddiskdialog.ui + + qt_harddrive_common.cpp + qt_harddrive_common.hpp + qt_models_common.cpp + qt_models_common.hpp + + qt_specifydimensions.h + qt_specifydimensions.cpp + qt_specifydimensions.ui + qt_soundgain.hpp + qt_soundgain.cpp + qt_soundgain.ui + + qt_styleoverride.cpp + qt_styleoverride.hpp + qt_progsettings.hpp + qt_progsettings.cpp + qt_progsettings.ui + qt_util.hpp + qt_util.cpp + + qt_unixmanagerfilter.cpp + qt_unixmanagerfilter.hpp + + qt_vulkanwindowrenderer.hpp + qt_vulkanwindowrenderer.cpp + + qt_vulkanrenderer.hpp + qt_vulkanrenderer.cpp + + qt_mcadevicelist.hpp + qt_mcadevicelist.cpp + qt_mcadevicelist.ui + + ../qt_resources.qrc +) + + +if(RTMIDI) + target_compile_definitions(ui PRIVATE USE_RTMIDI) +endif() + + +if(WIN32) + enable_language(RC) + target_sources(86Box PUBLIC ../win/86Box-qt.rc) + target_sources(plat PRIVATE win_dynld.c) + target_sources(plat PRIVATE win_joystick_rawinput.c) + target_sources(ui PRIVATE qt_d3d9renderer.hpp qt_d3d9renderer.cpp) + target_link_libraries(86Box hid d3d9) + + # CMake 3.22 messed this up for clang/clang++ + # See https://gitlab.kitware.com/cmake/cmake/-/issues/22611 + if(MSVC OR (NOT MINGW AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)) + # MSVC linker adds its own manifest to the executable, which fails if + # we include ours in 86Box.rc. We therefore need to pass the manifest + # directly as as a source file, so the linker can use that instead. + set_property(SOURCE ../win/86Box-qt.rc DIRECTORY .. PROPERTY COMPILE_DEFINITIONS NO_INCLUDE_MANIFEST) + target_sources(86Box PRIVATE ../win/86Box.manifest) + endif() + + if (MINGW) + add_compile_definitions(NTDDI_VERSION=0x06010000) + endif() +else() + target_sources(plat PRIVATE sdl_joystick.cpp) +endif() + +if(WIN32 AND NOT MINGW) + target_sources(plat PRIVATE ../win/win_opendir.c) +endif() + +if (APPLE) + target_sources(ui PRIVATE macos_event_filter.mm) +endif() + +if (WIN32) + target_sources(ui PRIVATE + qt_winrawinputfilter.hpp + qt_winrawinputfilter.cpp + qt_winmanagerfilter.hpp + qt_winmanagerfilter.cpp + ) +endif() + +target_link_libraries( + plat + PRIVATE + Qt${QT_MAJOR}::Widgets + Qt${QT_MAJOR}::Gui + Qt${QT_MAJOR}::Network + Threads::Threads +) + +target_link_libraries( + ui + PRIVATE + Qt${QT_MAJOR}::Widgets + Qt${QT_MAJOR}::Gui + Qt${QT_MAJOR}::OpenGL + Qt${QT_MAJOR}::Network + Threads::Threads +) + +if(WIN32) + if(STATIC_BUILD) + # needed for static builds + qt_import_plugins(plat INCLUDE Qt${QT_MAJOR}::QWindowsIntegrationPlugin Qt${QT_MAJOR}::QICOPlugin Qt${QT_MAJOR}::QWindowsVistaStylePlugin) + else() + if(USE_QT6) + install(CODE " + get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE) + execute_process( + COMMAND $ + \"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/$\") + ") + else() + find_program(WINDEPLOYQT_EXECUTABLE windeployqt) + if(WINDEPLOYQT_EXECUTABLE) + install(CODE " + get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE) + execute_process( + COMMAND ${WINDEPLOYQT_EXECUTABLE} + \"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/$\") + ") + endif() + endif() + endif() +endif() + +# loads a macro to install Qt5 plugins on macOS +# based on https://stackoverflow.com/questions/35612687/cmake-macos-x-bundle-with-bundleutiliies-for-qt-application +macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var _prefix) + get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + if(EXISTS "${_qt_plugin_path}") + get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) + get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) + get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME) + set(_qt_plugin_dest "${_prefix}/PlugIns/${_qt_plugin_type}") + install(FILES "${_qt_plugin_path}" DESTINATION "${_qt_plugin_dest}") + list(APPEND ${_qt_plugins_var} "\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${_qt_plugin_dest}/${_qt_plugin_file}") + else() + message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found") + endif() +endmacro() + +if (APPLE AND CMAKE_MACOSX_BUNDLE) + set(prefix "86Box.app/Contents") + set(INSTALL_RUNTIME_DIR "${prefix}/MacOS") + set(INSTALL_CMAKE_DIR "${prefix}/Resources") + + # using the install_qt5_plugin to add Qt plugins into the macOS app bundle + install_qt5_plugin("Qt${QT_MAJOR}::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix}) + install_qt5_plugin("Qt${QT_MAJOR}::QMacStylePlugin" QT_PLUGINS ${prefix}) + install_qt5_plugin("Qt${QT_MAJOR}::QICOPlugin" QT_PLUGINS ${prefix}) + install_qt5_plugin("Qt${QT_MAJOR}::QICNSPlugin" QT_PLUGINS ${prefix}) + + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + "[Paths]\nPlugins = PlugIns\n") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + DESTINATION "${INSTALL_CMAKE_DIR}") + + # Path used for searching by FIND_XXX(), with appropriate suffixes added + if(CMAKE_PREFIX_PATH) + foreach(dir ${CMAKE_PREFIX_PATH}) + list(APPEND DIRS "${dir}/bin" "${dir}/lib") + endforeach() + endif() + + # Append Qt's lib folder which is two levels above Qt*Widgets_DIR + list(APPEND DIRS "${Qt${QT_MAJOR}Widgets_DIR}/../..") + + include(InstallRequiredSystemLibraries) + + install(CODE " + include(BundleUtilities) + get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX} ABSOLUTE) + fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${QT_PLUGINS}\" \"${DIRS}\")") +endif() + +if (UNIX AND NOT APPLE AND NOT HAIKU) + find_package(X11 REQUIRED) + target_link_libraries(ui PRIVATE X11::X11 X11::Xi) + target_sources(ui PRIVATE xinput2_mouse.cpp) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBEVDEV IMPORTED_TARGET libevdev) + if (LIBEVDEV_FOUND) + target_compile_definitions(ui PRIVATE EVDEV_INPUT) + target_link_libraries(ui PUBLIC PkgConfig::LIBEVDEV) + target_sources(ui PRIVATE evdev_mouse.cpp) + endif() + + find_package(ECM NO_MODULE) + if (ECM_FOUND) + list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + find_package(Wayland COMPONENTS Client) + if (Wayland_FOUND) + target_link_libraries(ui PRIVATE Wayland::Client) + find_package(WaylandScanner REQUIRED) + if (WaylandScanner_FOUND) + set(WL_SOURCE_VAR) + ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/relative-pointer-unstable-v1.xml BASENAME relative-pointer-unstable-v1) + ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1) + target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS}) + target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp) + target_compile_definitions(ui PRIVATE WAYLAND) + endif() + endif() + endif() +endif() +set(QM_FILES) +file(GLOB po_files "${CMAKE_CURRENT_SOURCE_DIR}/languages/*.po") +foreach(po_file ${po_files}) + get_filename_component(PO_FILE_NAME ${po_file} NAME_WE) + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/86box_${PO_FILE_NAME}.qm" + COMMAND "$" -i ${po_file} -o ${CMAKE_CURRENT_BINARY_DIR}/86box_${PO_FILE_NAME}.qm + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DEPENDS "${po_file}") + list(APPEND QM_FILES "${CMAKE_CURRENT_BINARY_DIR}/86box_${PO_FILE_NAME}.qm") + list(APPEND QM_FILES "${po_file}") +endforeach() +configure_file(qt_translations.qrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) +target_sources(ui PRIVATE ${QM_FILES} ${CMAKE_CURRENT_BINARY_DIR}/qt_translations.qrc) diff --git a/src/qt/cocoa_mouse.hpp b/src/qt/cocoa_mouse.hpp new file mode 100644 index 000000000..8db79d9e8 --- /dev/null +++ b/src/qt/cocoa_mouse.hpp @@ -0,0 +1,16 @@ +#include +#include + +#if QT_VERSION_MAJOR >= 6 +#define result_t qintptr +#else +#define result_t long +#endif + +class CocoaEventFilter : public QAbstractNativeEventFilter +{ +public: + CocoaEventFilter() {}; + ~CocoaEventFilter(); + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) override; +}; diff --git a/src/qt/evdev_mouse.cpp b/src/qt/evdev_mouse.cpp new file mode 100644 index 000000000..120f4572c --- /dev/null +++ b/src/qt/evdev_mouse.cpp @@ -0,0 +1,123 @@ +/* + * 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. + * + * Linux/FreeBSD libevdev mouse input module. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + */ +#include "evdev_mouse.hpp" +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/mouse.h> +} + +static std::vector> evdev_mice; +static std::atomic stopped = false; +static QThread* evdev_thread; + +static std::atomic evdev_mouse_rel_x = 0, evdev_mouse_rel_y = 0; + +void evdev_mouse_poll() +{ + if (!evdev_mice.size() || !mouse_capture) + { + evdev_mouse_rel_x = 0; + evdev_mouse_rel_y = 0; + return; + } + mouse_x = evdev_mouse_rel_x; + mouse_y = evdev_mouse_rel_y; + evdev_mouse_rel_x = evdev_mouse_rel_y = 0; +} + +void evdev_thread_func() +{ + while (!stopped) + { + for (unsigned int i = 0; i < evdev_mice.size(); i++) + { + struct input_event ev; + int rc = libevdev_next_event(evdev_mice[i].second, LIBEVDEV_READ_FLAG_NORMAL, &ev); + if (rc == 0 && ev.type == EV_REL && mouse_capture) + { + if (ev.code == REL_X) evdev_mouse_rel_x += ev.value; + if (ev.code == REL_Y) evdev_mouse_rel_y += ev.value; + } + } + } + for (unsigned int i = 0; i < evdev_mice.size(); i++) + { + libevdev_free(evdev_mice[i].second); + evdev_mice[i].second = nullptr; + close(evdev_mice[i].first); + } + evdev_mice.clear(); +} + +void evdev_stop() +{ + if (evdev_thread) { + stopped = true; + evdev_thread->wait(); + evdev_thread = nullptr; + } +} + +void evdev_init() +{ + if (evdev_thread) return; + for (int i = 0; i < 256; i++) + { + std::string evdev_device_path = "/dev/input/event" + std::to_string(i); + int fd = open(evdev_device_path.c_str(), O_NONBLOCK | O_RDONLY); + if (fd != -1) + { + libevdev* input_struct = nullptr; + int rc = libevdev_new_from_fd(fd, &input_struct); + if (rc <= -1) + { + close(fd); + continue; + } + else + { + if (!libevdev_has_event_type(input_struct, EV_REL) || !libevdev_has_event_code(input_struct, EV_KEY, BTN_LEFT)) + { + libevdev_free(input_struct); + close(fd); + continue; + } + evdev_mice.push_back(std::make_pair(fd, input_struct)); + } + } + else if (errno == ENOENT) break; + } + if (evdev_mice.size() != 0) + { + evdev_thread = QThread::create(evdev_thread_func); + evdev_thread->start(); + atexit(evdev_stop); + } +} diff --git a/src/qt/evdev_mouse.hpp b/src/qt/evdev_mouse.hpp new file mode 100644 index 000000000..7681771c6 --- /dev/null +++ b/src/qt/evdev_mouse.hpp @@ -0,0 +1,4 @@ +#ifdef EVDEV_INPUT +void evdev_init(); +void evdev_mouse_poll(); +#endif diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po new file mode 100644 index 000000000..6f7ecc69e --- /dev/null +++ b/src/qt/languages/cs-CZ.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Akce" + +msgid "&Keyboard requires capture" +msgstr "&Klávesnice vyžaduje záběr" + +msgid "&Right CTRL is left ALT" +msgstr "&Pravý Ctrl je levý Alt" + +msgid "&Hard Reset..." +msgstr "&Resetovat" + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "P&ozastavit" + +msgid "E&xit..." +msgstr "&Ukončit" + +msgid "&View" +msgstr "&Zobrazení" + +msgid "&Hide status bar" +msgstr "&Schovat stavový řádek" + +msgid "Hide &toolbar" +msgstr "Schovat panel &nástrojů" + +msgid "&Resizeable window" +msgstr "&Měnitelná velikost okna" + +msgid "R&emember size && position" +msgstr "&Pamatovat velikost a pozici" + +msgid "Re&nderer" +msgstr "&Renderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "&Zadat velikost..." + +msgid "F&orce 4:3 display ratio" +msgstr "&Dodržovat poměr stran 4:3" + +msgid "&Window scale factor" +msgstr "&Násobek zvětšení okna" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Metoda &filtrování" + +msgid "&Nearest" +msgstr "&Nejbližší" + +msgid "&Linear" +msgstr "&Lineární" + +msgid "Hi&DPI scaling" +msgstr "Š&kálování HiDPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Celá obrazovka\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Režím roztá&hnutí při celé obrazovce" + +msgid "&Full screen stretch" +msgstr "&Roztáhnout" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Zachovat poměr stran" + +msgid "&Integer scale" +msgstr "&Celočíselné škálování" + +msgid "E&GA/(S)VGA settings" +msgstr "Nastavení pro E&GA a (S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Převrátit barvy" + +msgid "VGA screen &type" +msgstr "&Typ VGA monitoru" + +msgid "RGB &Color" +msgstr "RGB &barevný" + +msgid "&RGB Grayscale" +msgstr "&Odstíny šedi" + +msgid "&Amber monitor" +msgstr "&Jantarová obrazovka" + +msgid "&Green monitor" +msgstr "&Zelená obrazovka" + +msgid "&White monitor" +msgstr "&Bílá obrazovka" + +msgid "Grayscale &conversion type" +msgstr "Převod na &odstíny šedi" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Průměr" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Přesah obrazu CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "&Upravit kontrast černobílé obrazovky" + +msgid "&Media" +msgstr "&Média" + +msgid "&Tools" +msgstr "&Nástroje" + +msgid "&Settings..." +msgstr "&Nastavení..." + +msgid "&Update status bar icons" +msgstr "&Aktualizovat ikony stavového řádku" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Pořídit &screenshot\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Předvolby..." + +msgid "Enable &Discord integration" +msgstr "Povolit integraci s &Discordem" + +msgid "Sound &gain..." +msgstr "&Zesílení zvuku" + +msgid "Begin trace\tCtrl+T" +msgstr "Začít trace\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Zastavit trace\tCtrl+T" + +msgid "&Help" +msgstr "Ná&pověda" + +msgid "&Documentation..." +msgstr "&Dokumentace" + +msgid "&About 86Box..." +msgstr "&O programu 86Box" + +msgid "&New image..." +msgstr "&Nový obraz..." + +msgid "&Existing image..." +msgstr "&Existující obraz..." + +msgid "Existing image (&Write-protected)..." +msgstr "Existující obraz (&ochrana proti zápisu)..." + +msgid "&Record" +msgstr "&Nahrávat" + +msgid "&Play" +msgstr "&Přehrát" + +msgid "&Rewind to the beginning" +msgstr "Přetočit na &začátek" + +msgid "&Fast forward to the end" +msgstr "Přetočit na &konec" + +msgid "E&ject" +msgstr "&Vyjmout" + +msgid "&Image..." +msgstr "&Obraz..." + +msgid "E&xport to 86F..." +msgstr "E&xportovat do 86F..." + +msgid "&Mute" +msgstr "&Ztišit" + +msgid "E&mpty" +msgstr "&Vyjmout" + +msgid "&Reload previous image" +msgstr "&Načíst znova předchozí obraz" + +msgid "&Image" +msgstr "&Obraz..." + +msgid "Target &framerate" +msgstr "&Cílová snímková frekvence" + +msgid "&Sync with video" +msgstr "&Synchronizovat s obrazem" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Zvolit shader..." + +msgid "&Remove shader" +msgstr "&Odebrat shader" + +msgid "Preferences" +msgstr "Předvolby" + +msgid "Sound Gain" +msgstr "Zesílení zvuku" + +msgid "New Image" +msgstr "Nový obraz" + +msgid "Settings" +msgstr "Nastavení" + +msgid "Specify Main Window Dimensions" +msgstr "Zadat rozměry hlavního okna" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Storno" + +msgid "Save these settings as &global defaults" +msgstr "Uložit toto nastavení jako &globální výchozí stav" + +msgid "&Default" +msgstr "&Výchozí" + +msgid "Language:" +msgstr "Jazyk:" + +msgid "Icon set:" +msgstr "Sada ikon:" + +msgid "Gain" +msgstr "Zesílení" + +msgid "File name:" +msgstr "Název souboru:" + +msgid "Disk size:" +msgstr "Velikost disku:" + +msgid "RPM mode:" +msgstr "Režím ot./m:" + +msgid "Progress:" +msgstr "Průběh:" + +msgid "Width:" +msgstr "Šířka:" + +msgid "Height:" +msgstr "Výška:" + +msgid "Lock to this size" +msgstr "Uzamknout na tyto rozměry" + +msgid "Machine type:" +msgstr "Typ počítače:" + +msgid "Machine:" +msgstr "Počítač:" + +msgid "Configure" +msgstr "Nastavit" + +msgid "CPU type:" +msgstr "Procesor:" + +msgid "Speed:" +msgstr "Rychlost:" + +msgid "FPU:" +msgstr "Koprocesor:" + +msgid "Wait states:" +msgstr "Čekací stavy:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Pamět:" + +msgid "Time synchronization" +msgstr "Synchronizace času" + +msgid "Disabled" +msgstr "Vypnuta" + +msgid "Enabled (local time)" +msgstr "Zapnuta (místní čas)" + +msgid "Enabled (UTC)" +msgstr "Zapnuta (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamický překladač" + +msgid "Video:" +msgstr "Grafika:" + +msgid "Voodoo Graphics" +msgstr "Použít grafický akcelerátor Voodoo" + +msgid "Mouse:" +msgstr "Myš:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Zvuková karta:" + +msgid "MIDI Out Device:" +msgstr "MIDI výstup:" + +msgid "MIDI In Device:" +msgstr "MIDI vstup:" + +msgid "Standalone MPU-401" +msgstr "Samostatný MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Použít zvuk FLOAT32" + +msgid "Network type:" +msgstr "Druh sítě:" + +msgid "PCap device:" +msgstr "PCap zařízení:" + +msgid "Network adapter:" +msgstr "Síťový adaptér:" + +msgid "COM1 Device:" +msgstr "Zařízení na COM1:" + +msgid "COM2 Device:" +msgstr "Zařízení na COM2:" + +msgid "COM3 Device:" +msgstr "Zařízení na COM3:" + +msgid "COM4 Device:" +msgstr "Zařízení na COM4:" + +msgid "LPT1 Device:" +msgstr "Zařízení na LPT1:" + +msgid "LPT2 Device:" +msgstr "Zařízení na LPT2:" + +msgid "LPT3 Device:" +msgstr "Zařízení na LPT3:" + +msgid "LPT4 Device:" +msgstr "Zařízení na LPT4:" + +msgid "Serial port 1" +msgstr "Povolit port COM1" + +msgid "Serial port 2" +msgstr "Povolit port COM2" + +msgid "Serial port 3" +msgstr "Povolit port COM3" + +msgid "Serial port 4" +msgstr "Povolit port COM4" + +msgid "Parallel port 1" +msgstr "Povolit port LPT1" + +msgid "Parallel port 2" +msgstr "Povolit port LPT2" + +msgid "Parallel port 3" +msgstr "Povolit port LPT3" + +msgid "Parallel port 4" +msgstr "Povolit port LPT4" + +msgid "HD Controller:" +msgstr "Řadič disku:" + +msgid "FD Controller:" +msgstr "Disketový řadič:" + +msgid "Tertiary IDE Controller" +msgstr "Třetí řadič IDE" + +msgid "Quaternary IDE Controller" +msgstr "Čtvrtý řadič IDE" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Řadič 1:" + +msgid "Controller 2:" +msgstr "Řadič 2:" + +msgid "Controller 3:" +msgstr "Řadič 3:" + +msgid "Controller 4:" +msgstr "Řadič 4:" + +msgid "Cassette" +msgstr "Kazeta" + +msgid "Hard disks:" +msgstr "Pevné disky:" + +msgid "&New..." +msgstr "&Nový..." + +msgid "&Existing..." +msgstr "&Existující..." + +msgid "&Remove" +msgstr "&Odebrat" + +msgid "Bus:" +msgstr "Sběrnice:" + +msgid "Channel:" +msgstr "Kanál:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Zadat..." + +msgid "Sectors:" +msgstr "Sektory:" + +msgid "Heads:" +msgstr "Hlavy:" + +msgid "Cylinders:" +msgstr "Cylindry:" + +msgid "Size (MB):" +msgstr "Velikost (MB):" + +msgid "Type:" +msgstr "Typ:" + +msgid "Image Format:" +msgstr "Formát obrazu:" + +msgid "Block Size:" +msgstr "Velikost bloků:" + +msgid "Floppy drives:" +msgstr "Disketové mechaniky:" + +msgid "Turbo timings" +msgstr "Turbo časování" + +msgid "Check BPB" +msgstr "Kontrola BPB" + +msgid "CD-ROM drives:" +msgstr "Mechaniky CD-ROM:" + +msgid "MO drives:" +msgstr "Magnetooptické mechaniky:" + +msgid "ZIP drives:" +msgstr "Mechaniky ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA hodiny:" + +msgid "ISA Memory Expansion" +msgstr "ISA rozšíření paměti" + +msgid "Card 1:" +msgstr "Karta 1:" + +msgid "Card 2:" +msgstr "Karta 2:" + +msgid "Card 3:" +msgstr "Karta 3:" + +msgid "Card 4:" +msgstr "Karta 4:" + +msgid "ISABugger device" +msgstr "Zařízení ISABugger" + +msgid "POST card" +msgstr "Karta pro kódy POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Chyba" + +msgid "Fatal error" +msgstr "Kritická chyba" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Stiskněte Ctrl+Alt+PgDn pro návrat z režimu celé obrazovky." + +msgid "Speed" +msgstr "Rychlost" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Obrazy ZIP disků" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box nenalezl žádné použitelné image pamětí ROM.\n\nStáhněte sadu obrazů ROM a extrahujte ji do složky \"roms\"." + +msgid "(empty)" +msgstr "(prázdné)" + +msgid "All files" +msgstr "All files" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Zap." + +msgid "Off" +msgstr "Vyp." + +msgid "All images" +msgstr "Všechny obrazy disků" + +msgid "Basic sector images" +msgstr "Základní sektorové obrazy" + +msgid "Surface images" +msgstr "Obrazy povrchu" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Počítač \"%hs\" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce \"roms/machines\". Konfigurace se přepne na jiný dostupný počítač." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Video adaptér \"%hs\" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce \"roms/video\". Konfigurace se přepne na jiný dostupný adaptér." + +msgid "Machine" +msgstr "Počítač" + +msgid "Display" +msgstr "Obraz" + +msgid "Input devices" +msgstr "Vstupní zařízení" + +msgid "Sound" +msgstr "Zvuk" + +msgid "Network" +msgstr "Síť" + +msgid "Ports (COM & LPT)" +msgstr "COM a LPT porty" + +msgid "Storage controllers" +msgstr "Řadiče úložiště" + +msgid "Hard disks" +msgstr "Pevné disky" + +msgid "Floppy & CD-ROM drives" +msgstr "Disketové a CD-ROM mechaniky" + +msgid "Other removable devices" +msgstr "Další vyměnitelná zařízení" + +msgid "Other peripherals" +msgstr "Jiné příslušenství" + +msgid "Click to capture mouse" +msgstr "Klikněte pro zabraní myši" + +msgid "Press F8+F12 to release mouse" +msgstr "Stiskněte F8+F12 pro uvolnění myši" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Stiskněte F8+F12 nebo prostřední tlačítko pro uvolnění myši" + +msgid "Unable to initialize FluidSynth" +msgstr "Nastala chyba při inicializaci knihovny FluidSynth." + +msgid "Bus" +msgstr "Sběrnice" + +msgid "File" +msgstr "Soubor" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Nastala chyba při inicializaci video rendereru." + +msgid "Default" +msgstr "Výchozí" + +msgid "%i Wait state(s)" +msgstr "%i čekací stav(y)" + +msgid "Type" +msgstr "Typ" + +msgid "Failed to set up PCap" +msgstr "Nastala chyba při inicializaci knihovny PCap" + +msgid "No PCap devices found" +msgstr "Nebyla nalezena žádná PCap zařízení" + +msgid "Invalid PCap device" +msgstr "Neplatné PCap zařízení" + +msgid "Standard 2-button joystick(s)" +msgstr "Standardní 2tlačítkový joystick" + +msgid "Standard 4-button joystick" +msgstr "Standardní 4tlačítkový joystick" + +msgid "Standard 6-button joystick" +msgstr "Standardní 6tlačítkový joystick" + +msgid "Standard 8-button joystick" +msgstr "Standardní 8tlačítkový joystick" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Žadné" + +msgid "Unable to load keyboard accelerators." +msgstr "Nebylo možné nahrát klávesnicové zkratky." + +msgid "Unable to register raw input." +msgstr "Nebylo možné zaregistrovat raw input." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disketová mechanika %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Rozšířené sektorové obrazy" + +msgid "Flux images" +msgstr "Obrazy magnetického toku" + +msgid "Unable to initialize FreeType" +msgstr "Nastala chyba při inicializaci knihovny FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Nastala chyba při inicializaci knihovny SDL, je potřeba SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Opravdu chcete resetovat emulovaný počítač?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Opravdu chcete ukončit 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Nastala chyba při inicializaci knihovny Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "Obrazy MO" + +msgid "Welcome to 86Box!" +msgstr "Vítejte v programu 86Box!" + +msgid "Internal controller" +msgstr "Vestavěný řadič" + +msgid "Exit" +msgstr "Ukončit" + +msgid "No ROMs found" +msgstr "Nebyly nalezeny žádné obrazy ROM" + +msgid "Do you want to save the settings?" +msgstr "Chcete uložit nastavení?" + +msgid "This will hard reset the emulated machine." +msgstr "Pokračováním se resetuje emulovaný počítač." + +msgid "Save" +msgstr "Uložit" + +msgid "About 86Box" +msgstr "O programu 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Emulátor starých počítačů\n\nAutoři: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nZveřejněno pod licencí GNU General Public License verze 2 nebo novější. Viz soubor LICENSE pro více informací." + +msgid "Hardware not available" +msgstr "Hardware není dostupný" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Ujistěte se, že je nainstalován libpcap a používáte síťové připojení s ním kompatibilní." + +msgid "Invalid configuration" +msgstr "Neplatná konfigurace" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " je potřeba pro emulaci ESC/P tiskáren." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " je potřeba pro automatický převod PostScript dokumentů do PDF.\n\nJakékoliv dokumenty vytisknuté přes obecnou PostScriptovou tiskárnu budou uloženy jako PostScript (.ps) soubory." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " je potřeba pro MIDI výstup přes knihovnu FluidSynth." + +msgid "Entering fullscreen mode" +msgstr "Vstup do režimu celé obrazovky" + +msgid "Don't show this message again" +msgstr "Nezobrazovat dále tuto zprávu" + +msgid "Don't exit" +msgstr "Neukončovat" + +msgid "Reset" +msgstr "Resetovat" + +msgid "Don't reset" +msgstr "Neresetovat" + +msgid "CD-ROM images" +msgstr "Obraz CD-ROM disku" + +msgid "%hs Device Configuration" +msgstr "Konfigurace zařízení %hs" + +msgid "Monitor in sleep mode" +msgstr "Monitor je v režimu spánku" + +msgid "OpenGL Shaders" +msgstr "Shadery OpenGL" + +msgid "OpenGL options" +msgstr "Možnosti OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Pokoušíte se spustit nepodporovanou konfiguraci" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Pro tuto konfiguraci bylo vypnuto filtrování procesorů podle zvoleného počítače.\n\nToto umožňuje zvolit procesor, který by jinak se zvoleným počítačem nebyl kompatibilní. Můžou však nastat potíže s BIOSem nebo jiným softwarem.\n\nPovolení tohoto nastavení není oficiálně podporováno a jakákoliv hlášení o chybách mohou být uzavřeny jako neplatné." + +msgid "Continue" +msgstr "Pokračovat" + +msgid "Cassette: %s" +msgstr "Kazeta: %s" + +msgid "Cassette images" +msgstr "Kazetové nahrávky" + +msgid "Cartridge %i: %ls" +msgstr "Cartridge %i: %ls" + +msgid "Cartridge images" +msgstr "Obrazy cartridge" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Obnovit" + +msgid "Pause execution" +msgstr "Pozastavit" + +msgid "Press Ctrl+Alt+Del" +msgstr "Stisknout Ctrl+Alt+Delete" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Stisknout Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Resetovat" + +msgid "ACPI shutdown" +msgstr "Vypnout skrze rozhraní ACPI" + +msgid "Hard disk (%s)" +msgstr "Pevný disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "CD-ROM mechaniky pro rozhraní MFM/RLL nebo ESDI nikdy neexistovaly" + +msgid "Custom..." +msgstr "Vlastní..." + +msgid "Custom (large)..." +msgstr "Vlastní (velký)..." + +msgid "Add New Hard Disk" +msgstr "Přidat nový pevný disk" + +msgid "Add Existing Hard Disk" +msgstr "Přidat existující pevný disk" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Obraz disku formátu HDI nemůžou být větší než 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Obraz disku nemůžou být větší než 127 GB." + +msgid "Hard disk images" +msgstr "Obrazy pevného disku" + +msgid "Unable to read file" +msgstr "Nebylo možné přečíst soubor" + +msgid "Unable to write file" +msgstr "Nebylo možné zapisovat do souboru" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Obraz disku ve formátu HDI nebo HDX s velikostí sektoru jinou než 512 bajtů nejsou podporovány." + +msgid "USB is not yet supported" +msgstr "USB zatím není podporováno." + +msgid "Disk image file already exists" +msgstr "Soubor obrazu disku již existuje" + +msgid "Please specify a valid file name." +msgstr "Zadejte platný název souboru." + +msgid "Disk image created" +msgstr "Obraz disku byl vytvořen" + +msgid "Make sure the file exists and is readable." +msgstr "Ujistěte se, že soubor existuje a lze jej přečíst." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Ujistěte se, že se do složky, kde se má soubor uložit, dá zapisovat." + +msgid "Disk image too large" +msgstr "Obraz disku je příliš velký" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Nezapomeňte nově vytvořený disk rozdělit a naformátovat." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Zvolený soubor bude přepsán. Opravdu jej chcete použít?" + +msgid "Unsupported disk image" +msgstr "Nepodporovaný obraz disku" + +msgid "Overwrite" +msgstr "Přepsat" + +msgid "Don't overwrite" +msgstr "Nepřepisovat" + +msgid "Raw image (.img)" +msgstr "Surový obraz (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI obraz (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX obraz (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD s pevnou velikostí (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD s dynamickou velikostí (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Rozdílový VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Velké bloky (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Malé bloky (512 KB)" + +msgid "VHD files" +msgstr "Soubory VHD" + +msgid "Select the parent VHD" +msgstr "Vyberte nadřazený virtuální disk" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "To může znamenat, že se obsahy nadřazeného disku změnily po vytvoření rozdílového disku.\n\nTato chyba také může nastat, pokud byl obraz disku kopírován nebo přesunut, nebo kvůli chybě v programu, který jej vytvořil.\n\nChcete časová razítka opravit?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Časová razítka nadřazeného a podřazeného disku nesouhlasí" + +msgid "Could not fix VHD timestamp." +msgstr "Nebylo možné opravit časové razítko VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Dokonalé otáčky za minutu" + +msgid "1% below perfect RPM" +msgstr "1% pod dokonalými ot./m" + +msgid "1.5% below perfect RPM" +msgstr "1.5% pod dokonalými ot./m" + +msgid "2% below perfect RPM" +msgstr "2% pod dokonalými ot./m" + +msgid "(System Default)" +msgstr "(Výchozí nastavení systému)" + diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po new file mode 100644 index 000000000..2951c7b85 --- /dev/null +++ b/src/qt/languages/de-DE.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Aktionen" + +msgid "&Keyboard requires capture" +msgstr "&Tastatur benötigt das Einfangen des Mauszeigers" + +msgid "&Right CTRL is left ALT" +msgstr "&Die rechte Strg-Taste ist die Linke Alt-Taste" + +msgid "&Hard Reset..." +msgstr "&Hard-Reset..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Strg+Alt+Entf\tStrg+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Strg+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pause" + +msgid "E&xit..." +msgstr "Be&enden..." + +msgid "&View" +msgstr "&Ansicht" + +msgid "&Hide status bar" +msgstr "&Statusleiste ausblenden" + +msgid "Hide &toolbar" +msgstr "Werkzeugleiste &ausblenden" + +msgid "&Resizeable window" +msgstr "&Größenverstellbares Fenster" + +msgid "R&emember size && position" +msgstr "&Größe && Position merken" + +msgid "Re&nderer" +msgstr "Re&nderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0-Kern)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Fenstergröße einstellen..." + +msgid "F&orce 4:3 display ratio" +msgstr "&4:3-Seitenverhältnis erzwingen" + +msgid "&Window scale factor" +msgstr "&Fensterskalierungsfaktor" + +msgid "&0.5x" +msgstr "&0,5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1,&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Filteringmethode" + +msgid "&Nearest" +msgstr "&Nearest" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Hi&DPI-Skalierung" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Vollbild\tStrg+Alt+Bild auf" + +msgid "Fullscreen &stretch mode" +msgstr "&Stretching-Modus im Vollbildmodus" + +msgid "&Full screen stretch" +msgstr "&Vollbild-Stretching" + +msgid "&4:3" +msgstr "&4:3-Seitenverhältnis erzwingen" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Quadratische Pixel (Seitenverhältnis beibehalten)" + +msgid "&Integer scale" +msgstr "&Integer-Skalierung" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA-Einstellungen" + +msgid "&Inverted VGA monitor" +msgstr "&Invertierte VGA-Anzeige" + +msgid "VGA screen &type" +msgstr "&VGA-Bildschirmtyp" + +msgid "RGB &Color" +msgstr "&RGB-Farbe" + +msgid "&RGB Grayscale" +msgstr "&RGB-Graustufen" + +msgid "&Amber monitor" +msgstr "&Bernstein-Monitor" + +msgid "&Green monitor" +msgstr "&Grüner Monitor" + +msgid "&White monitor" +msgstr "&Weißer Monitor" + +msgid "Grayscale &conversion type" +msgstr "Methode zur &Graustufenkonversion" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Durchschnittsmethode" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Overscan für CGA/PCjr/Tandy/E&GA/(S)VGA-Displays" + +msgid "Change contrast for &monochrome display" +msgstr "Kontrast für &monochrome Displays ändern" + +msgid "&Media" +msgstr "&Medien" + +msgid "&Tools" +msgstr "&Werkzeuge" + +msgid "&Settings..." +msgstr "&Optionen..." + +msgid "&Update status bar icons" +msgstr "&Statusleistenicons aktualisieren" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "S&creenshot aufnehmen\tStrg+F11" + +msgid "&Preferences..." +msgstr "&Einstellungen..." + +msgid "Enable &Discord integration" +msgstr "&Discord-Integration aktivieren" + +msgid "Sound &gain..." +msgstr "&Klangverstärkung..." + +msgid "Begin trace\tCtrl+T" +msgstr "Tracing starten\tStrg+T" + +msgid "End trace\tCtrl+T" +msgstr "Tracing beenden\tStrg+T" + +msgid "&Help" +msgstr "&Hilfe" + +msgid "&Documentation..." +msgstr "&Dokumentation..." + +msgid "&About 86Box..." +msgstr "&Über 86Box..." + +msgid "&New image..." +msgstr "&Neues Image..." + +msgid "&Existing image..." +msgstr "&Bestehendes Image..." + +msgid "Existing image (&Write-protected)..." +msgstr "Bestehendes Image (&schreibgeschützt)..." + +msgid "&Record" +msgstr "&Aufnehmen" + +msgid "&Play" +msgstr "&Abspielen" + +msgid "&Rewind to the beginning" +msgstr "&An den Anfang zurückspulen" + +msgid "&Fast forward to the end" +msgstr "&An das Ende vorspulen" + +msgid "E&ject" +msgstr "A&uswerfen" + +msgid "&Image..." +msgstr "&Cartridgeimage..." + +msgid "E&xport to 86F..." +msgstr "&In das 86F-Format e&xportieren..." + +msgid "&Mute" +msgstr "&Stummschalten" + +msgid "E&mpty" +msgstr "L&eer" + +msgid "&Reload previous image" +msgstr "&Voriges Image neu laden" + +msgid "&Image" +msgstr "&Image" + +msgid "Target &framerate" +msgstr "Ziel&framerate" + +msgid "&Sync with video" +msgstr "&Mit Videoausgabe synchronisieren" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Shader auswählen..." + +msgid "&Remove shader" +msgstr "&Shader entfernen" + +msgid "Preferences" +msgstr "Einstellungen" + +msgid "Sound Gain" +msgstr "Klangverstärkung" + +msgid "New Image" +msgstr "Neues Image" + +msgid "Settings" +msgstr "Optionen" + +msgid "Specify Main Window Dimensions" +msgstr "Fenstergröße einstellen" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Abbrechen" + +msgid "Save these settings as &global defaults" +msgstr "Einstellungen als &globalen Standard speichern" + +msgid "&Default" +msgstr "&Standard" + +msgid "Language:" +msgstr "Sprache:" + +msgid "Icon set:" +msgstr "Icon-Satz:" + +msgid "Gain" +msgstr "Verstärkung" + +msgid "File name:" +msgstr "Dateiname:" + +msgid "Disk size:" +msgstr "Plattengröße:" + +msgid "RPM mode:" +msgstr "Drehzahlmodus:" + +msgid "Progress:" +msgstr "Fortschritt:" + +msgid "Width:" +msgstr "Breite:" + +msgid "Height:" +msgstr "Höhe:" + +msgid "Lock to this size" +msgstr "Feste Größe" + +msgid "Machine type:" +msgstr "Systemtyp:" + +msgid "Machine:" +msgstr "System:" + +msgid "Configure" +msgstr "Einstellen" + +msgid "CPU type:" +msgstr "CPU-Typ:" + +msgid "Speed:" +msgstr "Geschwindigkeit:" + +msgid "FPU:" +msgstr "FPU-Einheit:" + +msgid "Wait states:" +msgstr "Wartezustände:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Hauptspeicher:" + +msgid "Time synchronization" +msgstr "Zeitsynchronisierung" + +msgid "Disabled" +msgstr "Deaktiviert" + +msgid "Enabled (local time)" +msgstr "Aktiviert (Lokale Uhrzeit)" + +msgid "Enabled (UTC)" +msgstr "Aktiviert (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamischer Recompiler" + +msgid "Video:" +msgstr "Videokarte:" + +msgid "Voodoo Graphics" +msgstr "Voodoo-Grafik" + +msgid "Mouse:" +msgstr "Maus:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Soundkarte:" + +msgid "MIDI Out Device:" +msgstr "MIDI Out-Gerät:" + +msgid "MIDI In Device:" +msgstr "MIDI In-Gerät:" + +msgid "Standalone MPU-401" +msgstr "Standalone-MPU-401-Gerät" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32-Wiedergabe benutzen" + +msgid "Network type:" +msgstr "Netzwerktyp:" + +msgid "PCap device:" +msgstr "PCap-Gerät:" + +msgid "Network adapter:" +msgstr "Netzwerkadapter:" + +msgid "COM1 Device:" +msgstr "COM1-Gerät:" + +msgid "COM2 Device:" +msgstr "COM2-Gerät:" + +msgid "COM3 Device:" +msgstr "COM3-Gerät:" + +msgid "COM4 Device:" +msgstr "COM4-Gerät:" + +msgid "LPT1 Device:" +msgstr "LPT1-Gerät:" + +msgid "LPT2 Device:" +msgstr "LPT2-Gerät:" + +msgid "LPT3 Device:" +msgstr "LPT3-Gerät:" + +msgid "LPT4 Device:" +msgstr "LPT4-Gerät:" + +msgid "Serial port 1" +msgstr "Serielle Schnittstelle 1" + +msgid "Serial port 2" +msgstr "Serielle Schnittstelle 2" + +msgid "Serial port 3" +msgstr "Serielle Schnittstelle 3" + +msgid "Serial port 4" +msgstr "Serielle Schnittstelle 4" + +msgid "Parallel port 1" +msgstr "Parallelport 1" + +msgid "Parallel port 2" +msgstr "Parallelport 2" + +msgid "Parallel port 3" +msgstr "Parallelport 3" + +msgid "Parallel port 4" +msgstr "Parallelport 4" + +msgid "HD Controller:" +msgstr "HDD-Controller:" + +msgid "FD Controller:" +msgstr "FD-Controller:" + +msgid "Tertiary IDE Controller" +msgstr "Tertiärer IDE-Controller" + +msgid "Quaternary IDE Controller" +msgstr "Quartärer IDE-Controller" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controller 1:" + +msgid "Controller 2:" +msgstr "Controller 2:" + +msgid "Controller 3:" +msgstr "Controller 3:" + +msgid "Controller 4:" +msgstr "Controller 4:" + +msgid "Cassette" +msgstr "Kassette" + +msgid "Hard disks:" +msgstr "Festplatten:" + +msgid "&New..." +msgstr "&Neu..." + +msgid "&Existing..." +msgstr "&Vorhanden..." + +msgid "&Remove" +msgstr "&Entfernen" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Kanal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Festlegen..." + +msgid "Sectors:" +msgstr "Sektoren:" + +msgid "Heads:" +msgstr "Köpfe:" + +msgid "Cylinders:" +msgstr "Zylinder:" + +msgid "Size (MB):" +msgstr "Größe (MB):" + +msgid "Type:" +msgstr "Typ:" + +msgid "Image Format:" +msgstr "Imageformat:" + +msgid "Block Size:" +msgstr "Blockgröße:" + +msgid "Floppy drives:" +msgstr "Diskettenlaufwerke:" + +msgid "Turbo timings" +msgstr "Turbo-Timings" + +msgid "Check BPB" +msgstr "BPB überprüfen" + +msgid "CD-ROM drives:" +msgstr "CD-ROM-Laufwerke:" + +msgid "MO drives:" +msgstr "MO-Laufwerke:" + +msgid "ZIP drives:" +msgstr "ZIP-Laufwerke:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA-Echtzeituhr:" + +msgid "ISA Memory Expansion" +msgstr "ISA-Speichererweiterung:" + +msgid "Card 1:" +msgstr "Steckkarte 1:" + +msgid "Card 2:" +msgstr "Steckkarte 2:" + +msgid "Card 3:" +msgstr "Steckkarte 3:" + +msgid "Card 4:" +msgstr "Steckkarte 4:" + +msgid "ISABugger device" +msgstr "ISABugger-Gerät" + +msgid "POST card" +msgstr "POST-Code-Karte" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Fehler" + +msgid "Fatal error" +msgstr "Fataler Fehler" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Bitte Strg+Alt+Bild ab zur Rückkehr in den Fenstermodus drücken." + +msgid "Speed" +msgstr "Geschwindigkeit" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP-Images" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box konnte keine nutzbaren ROM-Dateien finden.\n\nBitte besuchen Sie download, laden ein ROM-Set herunter und extrahieren dies in das \"roms\"-Verzeichnis." + +msgid "(empty)" +msgstr "(leer)" + +msgid "All files" +msgstr "Alle Dateien" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "An" + +msgid "Off" +msgstr "Aus" + +msgid "All images" +msgstr "Alle Images" + +msgid "Basic sector images" +msgstr "Basissektorimages" + +msgid "Surface images" +msgstr "Oberflächenimages" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Das System \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/machines nicht verfügbar. Es wird auf ein verfügbares System gewechselt." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Die Videokarte \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." + +msgid "Machine" +msgstr "System" + +msgid "Display" +msgstr "Anzeige" + +msgid "Input devices" +msgstr "Eingabegeräte" + +msgid "Sound" +msgstr "Multimedia" + +msgid "Network" +msgstr "Netzwerk" + +msgid "Ports (COM & LPT)" +msgstr "Anschlüsse (COM & LPT)" + +msgid "Storage controllers" +msgstr "Speichercontroller" + +msgid "Hard disks" +msgstr "Festplatten" + +msgid "Floppy & CD-ROM drives" +msgstr "Disketten- & CD-ROM-Laufwerke" + +msgid "Other removable devices" +msgstr "Andere Wechsellaufwerke" + +msgid "Other peripherals" +msgstr "Andere Peripheriegeräte" + +msgid "Click to capture mouse" +msgstr "Zum Einfangen des Mauszeigers bitte klicken" + +msgid "Press F8+F12 to release mouse" +msgstr "Bitte F8+F12 zur Mausfreigabe drücken" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Bitte F8+F12 oder die mittlere Maustaste zur Mausfreigabe drücken" + +msgid "Unable to initialize FluidSynth" +msgstr "FluidSynth konnte nicht initialisiert werden" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "Datei" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Der Videorenderer konnte nicht initialisiert werden." + +msgid "Default" +msgstr "Standard" + +msgid "%i Wait state(s)" +msgstr "%i Wartezustände" + +msgid "Type" +msgstr "Typ" + +msgid "Failed to set up PCap" +msgstr "PCap konnte nicht eingerichtet werden" + +msgid "No PCap devices found" +msgstr "Keine PCap-Geräte gefunden" + +msgid "Invalid PCap device" +msgstr "Ungültiges PCap-Gerät" + +msgid "Standard 2-button joystick(s)" +msgstr "Standard 2-Tasten-Joystick(s)" + +msgid "Standard 4-button joystick" +msgstr "Standard 4-Tasten-Joystick" + +msgid "Standard 6-button joystick" +msgstr "Standard 6-Tasten-Joystick" + +msgid "Standard 8-button joystick" +msgstr "Standard 8-Tasten-Joystick" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Ohne" + +msgid "Unable to load keyboard accelerators." +msgstr "Tastaturbeschleuniger konnten nicht geladen werden." + +msgid "Unable to register raw input." +msgstr "Roheingaben konnten nicht registriert werden." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Diskette %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Fortgeschrittene Sektorimages" + +msgid "Flux images" +msgstr "Fluximages" + +msgid "Unable to initialize FreeType" +msgstr "FreeType konnte nicht initialisiert werden" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "SDL konnte nicht initialisiert werden, die Datei SDL2.dll wird benötigt" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Sind Sie sich sicher, dass Sie einen Hard-Reset für das emulierte System durchführen wollen?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Sind Sie sich sicher, dass Sie 86Box beenden wollen?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ghostscript konnte nicht initialisiert werden" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO-Images" + +msgid "Welcome to 86Box!" +msgstr "Willkommen bei 86Box!" + +msgid "Internal controller" +msgstr "Interner Controller" + +msgid "Exit" +msgstr "Beenden" + +msgid "No ROMs found" +msgstr "Keine ROMs gefunden" + +msgid "Do you want to save the settings?" +msgstr "Möchten Sie die Einstellungen speichern?" + +msgid "This will hard reset the emulated machine." +msgstr "Dies wird zu einem Hard-Reset des emulierten Systems führen." + +msgid "Save" +msgstr "Speichern" + +msgid "About 86Box" +msgstr "Über 86Box" + +msgid "86Box v" +msgstr "86Box Version " + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Ein Emulator für alte Computer\n\nAutoren: Sarah Walker, Miran Grča, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho sowie andere.\n\nÜbersetzt von: dob205\n\nVeröffentlicht unter der GNU General Public License in der Version 2 oder neuer. Siehe LICENSE für mehr Informationen." + +msgid "Hardware not available" +msgstr "Hardware nicht verfügbar" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Bitte stellen Sie sicher, dass libpcap installiert ist und sie eine libpcap-kompatible Netzwerkverbindung nutzen." + +msgid "Invalid configuration" +msgstr "Ungültige Konfiguration" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " wird für die ESC/P-Druckeremulation benötigt." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " wird zur automatischen Konversion von PostScript-Dateien in das PDF-Format benötigt.\n\nSämtliche an den generischen PostScript-Drucker gesendete Dateien werden als PostScript (.ps)-Dateien gesichert." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " wird für die FluidSynth-MIDI-Ausgabe benötigt." + +msgid "Entering fullscreen mode" +msgstr "Vollbildmodus wird aktiviert" + +msgid "Don't show this message again" +msgstr "Diese Nachricht nicht mehr anzeigen" + +msgid "Don't exit" +msgstr "Nicht beenden" + +msgid "Reset" +msgstr "Zurücksetzen" + +msgid "Don't reset" +msgstr "Nicht zurücksetzen" + +msgid "CD-ROM images" +msgstr "CD-ROM-Images" + +msgid "%hs Device Configuration" +msgstr "%hs-Gerätekonfiguration" + +msgid "Monitor in sleep mode" +msgstr "Monitor im Standbymodus" + +msgid "OpenGL Shaders" +msgstr "OpenGL-Shader" + +msgid "OpenGL options" +msgstr "OpenGL-Optionen" + +msgid "You are loading an unsupported configuration" +msgstr "Sie laden gerade eine nicht unterstützte Konfiguration" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Das Filtern der CPU-Typen basierend auf dem ausgewählten System ist für dieses System deaktiviert.\n\nDies ermöglicht es, dass man eine sonst nicht mit dem ausgewählten System inkompatible CPU auswählen kann. Allerdings kann dies zu Inkompatiblilitäten mit dem BIOS des Systems oder anderen Programmen kommen.\n\nDas Aktivieren dieser Einstellung wird nicht unterstützt und sämtliche Bugreports können als \"invalid\" geschlossen werden." + +msgid "Continue" +msgstr "Fortfahren" + +msgid "Cassette: %s" +msgstr "Kassette: %s" + +msgid "Cassette images" +msgstr "Kassettenimages" + +msgid "Cartridge %i: %ls" +msgstr "Cartridge %i: %ls" + +msgid "Cartridge images" +msgstr "Cartridgeimages" + +msgid "Error initializing renderer" +msgstr "Fehler bei der Rendererinitialisierung" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "Der OpenGL (3.0-Kern)-Renderer konnte nicht initialisiert werden. Bitte benutzen Sie einen anderen Renderer." + +msgid "Resume execution" +msgstr "Fortsetzen" + +msgid "Pause execution" +msgstr "Pausieren" + +msgid "Press Ctrl+Alt+Del" +msgstr "Strg+Alt+Entf drücken" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Strg+Alt+Esc drücken" + +msgid "Hard reset" +msgstr "Hard-Reset" + +msgid "ACPI shutdown" +msgstr "ACPI-basiertes Herunterfahren" + +msgid "Hard disk (%s)" +msgstr "Festplatte (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL- oder ESDI CD-ROM-Laufwerke hat es niemals gegeben" + +msgid "Custom..." +msgstr "Angepasst..." + +msgid "Custom (large)..." +msgstr "Angepasst (Groß)..." + +msgid "Add New Hard Disk" +msgstr "Neue Festplatte hinzufügen" + +msgid "Add Existing Hard Disk" +msgstr "Bestehende Festplatte hinzufügen" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI-Diskimages können nicht größer als 4 GB groß sein." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Festplattenimages können nicht größer als 127 GB groß sein." + +msgid "Hard disk images" +msgstr "Festplattenimages" + +msgid "Unable to read file" +msgstr "Die Datei konnte nicht gelesen werden" + +msgid "Unable to write file" +msgstr "Die Datei konnte nicht beschrieben werden" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "HDI- oder HDX-Images mit einer Sektorgröße größer als 512 kB werden nicht unterstützt." + +msgid "USB is not yet supported" +msgstr "USB wird noch nicht unterstützt" + +msgid "Disk image file already exists" +msgstr "Die Festplattenimagedatei existiert bereits" + +msgid "Please specify a valid file name." +msgstr "Bitte geben Sie einen gültigen Dateinamen ein." + +msgid "Disk image created" +msgstr "Disk-Image wurde erstellt" + +msgid "Make sure the file exists and is readable." +msgstr "Bitte stellen Sie sicher, dass die Datei existiert und lesbar ist." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Bitte stellen Sie sicher, dass die Datei in ein Verzeichnis mit Schreibberechtigungen gespeichert wird." + +msgid "Disk image too large" +msgstr "Festplattenimage ist zu groß" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Bitte denken Sie an das Partitionieren und Formatieren des neu erstellten Laufwerks." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Die ausgewählte Datei wird überschrieben. Möchten Sie diese Datei nutzen?" + +msgid "Unsupported disk image" +msgstr "Nicht unterstütztes Festplattenimage" + +msgid "Overwrite" +msgstr "Überschreiben" + +msgid "Don't overwrite" +msgstr "Nicht überschreiben" + +msgid "Raw image (.img)" +msgstr "Rohdatenimages (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI-Images (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX-Images (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD mit fester Größe (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD mit dynamischer Größe (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differenzierende VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Große Blöcke (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Kleine Blöcke (512 KB)" + +msgid "VHD files" +msgstr "VHD-Dateien" + +msgid "Select the parent VHD" +msgstr "Eltern-VHD-Datei bitte auswählen" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Dies bedeutet, dass das Elternimage nach der Erstellung des differenzierenden Images erzeugt wurde.\n\nDies kann auch passieren, falls die Image-Dateien verschoben oder kopiert wurden. Ebenso kann auch dies durch einen Bug im Programm, welches das Image erstellt hat, passieren.\n\nMöchten Sie die Zeitstempel korrigieren?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Die Zeitstempel der Eltern- und der Kindesplatte stimmen nicht überein" + +msgid "Could not fix VHD timestamp." +msgstr "Der Zeitstempel der VHD konnte nicht korrigiert werden." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1,2 MB" + +msgid "1.25 MB" +msgstr "1,25 MB" + +msgid "1.44 MB" +msgstr "1,44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (1024 Cluster)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (2048 Cluster)" + +msgid "2.88 MB" +msgstr "2,88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3,5-Zoll 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3,5-Zoll 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3,5-Zoll 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3,5-Zoll 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3,5-Zoll 1,3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3,5-Zoll 2,3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5,25-Zoll 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5,25-Zoll 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5,25-Zoll 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5,25-Zoll 1,3 GB" + +msgid "Perfect RPM" +msgstr "Perfekte Drehzahl" + +msgid "1% below perfect RPM" +msgstr "1% unterhalb der perfekten Drehzahl" + +msgid "1.5% below perfect RPM" +msgstr "1,5% unterhalb der perfekten Drehzahl" + +msgid "2% below perfect RPM" +msgstr "2% unterhalb der perfekten Drehzahl" + +msgid "(System Default)" +msgstr "(Systemstandard)" + diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po new file mode 100644 index 000000000..90820a569 --- /dev/null +++ b/src/qt/languages/en-GB.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Action" + +msgid "&Keyboard requires capture" +msgstr "&Keyboard requires capture" + +msgid "&Right CTRL is left ALT" +msgstr "&Right CTRL is left ALT" + +msgid "&Hard Reset..." +msgstr "&Hard Reset..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pause" + +msgid "E&xit..." +msgstr "E&xit..." + +msgid "&View" +msgstr "&View" + +msgid "&Hide status bar" +msgstr "&Hide status bar" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Resizeable window" + +msgid "R&emember size && position" +msgstr "R&emember size && position" + +msgid "Re&nderer" +msgstr "Re&nderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Specify dimensions..." + +msgid "F&orce 4:3 display ratio" +msgstr "F&orce 4:3 display ratio" + +msgid "&Window scale factor" +msgstr "&Window scale factor" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Filter method" + +msgid "&Nearest" +msgstr "&Nearest" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Hi&DPI scaling" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Fullscreen\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Fullscreen &stretch mode" + +msgid "&Full screen stretch" +msgstr "&Full screen stretch" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Square pixels (Keep ratio)" + +msgid "&Integer scale" +msgstr "&Integer scale" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA settings" + +msgid "&Inverted VGA monitor" +msgstr "&Inverted VGA monitor" + +msgid "VGA screen &type" +msgstr "VGA screen &type" + +msgid "RGB &Color" +msgstr "RGB &Colour" + +msgid "&RGB Grayscale" +msgstr "&RGB Greyscale" + +msgid "&Amber monitor" +msgstr "&Amber monitor" + +msgid "&Green monitor" +msgstr "&Green monitor" + +msgid "&White monitor" +msgstr "&White monitor" + +msgid "Grayscale &conversion type" +msgstr "Grayscale &conversion type" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Average" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" + +msgid "Change contrast for &monochrome display" +msgstr "Change contrast for &monochrome display" + +msgid "&Media" +msgstr "&Media" + +msgid "&Tools" +msgstr "&Tools" + +msgid "&Settings..." +msgstr "&Settings..." + +msgid "&Update status bar icons" +msgstr "&Update status bar icons" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Take s&creenshot\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferences..." + +msgid "Enable &Discord integration" +msgstr "Enable &Discord integration" + +msgid "Sound &gain..." +msgstr "Sound &gain..." + +msgid "Begin trace\tCtrl+T" +msgstr "Begin trace\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "End trace\tCtrl+T" + +msgid "&Help" +msgstr "&Help" + +msgid "&Documentation..." +msgstr "&Documentation..." + +msgid "&About 86Box..." +msgstr "&About 86Box..." + +msgid "&New image..." +msgstr "&New image..." + +msgid "&Existing image..." +msgstr "&Existing image..." + +msgid "Existing image (&Write-protected)..." +msgstr "Existing image (&Write-protected)..." + +msgid "&Record" +msgstr "&Record" + +msgid "&Play" +msgstr "&Play" + +msgid "&Rewind to the beginning" +msgstr "&Rewind to the beginning" + +msgid "&Fast forward to the end" +msgstr "&Fast forward to the end" + +msgid "E&ject" +msgstr "E&ject" + +msgid "&Image..." +msgstr "&Image..." + +msgid "E&xport to 86F..." +msgstr "E&xport to 86F..." + +msgid "&Mute" +msgstr "&Mute" + +msgid "E&mpty" +msgstr "E&mpty" + +msgid "&Reload previous image" +msgstr "&Reload previous image" + +msgid "&Image" +msgstr "&Image" + +msgid "Target &framerate" +msgstr "Target &framerate" + +msgid "&Sync with video" +msgstr "&Sync with video" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Select shader..." + +msgid "&Remove shader" +msgstr "&Remove shader" + +msgid "Preferences" +msgstr "Preferences" + +msgid "Sound Gain" +msgstr "Sound Gain" + +msgid "New Image" +msgstr "New Image" + +msgid "Settings" +msgstr "Settings" + +msgid "Specify Main Window Dimensions" +msgstr "Specify Main Window Dimensions" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Cancel" + +msgid "Save these settings as &global defaults" +msgstr "Save these settings as &global defaults" + +msgid "&Default" +msgstr "&Default" + +msgid "Language:" +msgstr "Language:" + +msgid "Icon set:" +msgstr "Icon set:" + +msgid "Gain" +msgstr "Gain" + +msgid "File name:" +msgstr "File name:" + +msgid "Disk size:" +msgstr "Disk size:" + +msgid "RPM mode:" +msgstr "RPM mode:" + +msgid "Progress:" +msgstr "Progress:" + +msgid "Width:" +msgstr "Width:" + +msgid "Height:" +msgstr "Height:" + +msgid "Lock to this size" +msgstr "Lock to this size" + +msgid "Machine type:" +msgstr "Machine type:" + +msgid "Machine:" +msgstr "Machine:" + +msgid "Configure" +msgstr "Configure" + +msgid "CPU type:" +msgstr "CPU type:" + +msgid "Speed:" +msgstr "Speed:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Wait states:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memory:" + +msgid "Time synchronization" +msgstr "Time synchronization" + +msgid "Disabled" +msgstr "Disabled" + +msgid "Enabled (local time)" +msgstr "Enabled (local time)" + +msgid "Enabled (UTC)" +msgstr "Enabled (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamic Recompiler" + +msgid "Video:" +msgstr "Video:" + +msgid "Voodoo Graphics" +msgstr "Voodoo Graphics" + +msgid "Mouse:" +msgstr "Mouse:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Sound card:" + +msgid "MIDI Out Device:" +msgstr "MIDI Out Device:" + +msgid "MIDI In Device:" +msgstr "MIDI In Device:" + +msgid "Standalone MPU-401" +msgstr "Standalone MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Use FLOAT32 sound" + +msgid "Network type:" +msgstr "Network type:" + +msgid "PCap device:" +msgstr "PCap device:" + +msgid "Network adapter:" +msgstr "Network adapter:" + +msgid "COM1 Device:" +msgstr "COM1 Device:" + +msgid "COM2 Device:" +msgstr "COM2 Device:" + +msgid "COM3 Device:" +msgstr "COM3 Device:" + +msgid "COM4 Device:" +msgstr "COM4 Device:" + +msgid "LPT1 Device:" +msgstr "LPT1 Device:" + +msgid "LPT2 Device:" +msgstr "LPT2 Device:" + +msgid "LPT3 Device:" +msgstr "LPT3 Device:" + +msgid "LPT4 Device:" +msgstr "LPT4 Device:" + +msgid "Serial port 1" +msgstr "Serial port 1" + +msgid "Serial port 2" +msgstr "Serial port 2" + +msgid "Serial port 3" +msgstr "Serial port 3" + +msgid "Serial port 4" +msgstr "Serial port 4" + +msgid "Parallel port 1" +msgstr "Parallel port 1" + +msgid "Parallel port 2" +msgstr "Parallel port 2" + +msgid "Parallel port 3" +msgstr "Parallel port 3" + +msgid "Parallel port 4" +msgstr "Parallel port 4" + +msgid "HD Controller:" +msgstr "HD Controller:" + +msgid "FD Controller:" +msgstr "FD Controller:" + +msgid "Tertiary IDE Controller" +msgstr "Tertiary IDE Controller" + +msgid "Quaternary IDE Controller" +msgstr "Quaternary IDE Controller" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controller 1:" + +msgid "Controller 2:" +msgstr "Controller 2:" + +msgid "Controller 3:" +msgstr "Controller 3:" + +msgid "Controller 4:" +msgstr "Controller 4:" + +msgid "Cassette" +msgstr "Cassette" + +msgid "Hard disks:" +msgstr "Hard disks:" + +msgid "&New..." +msgstr "&New..." + +msgid "&Existing..." +msgstr "&Existing..." + +msgid "&Remove" +msgstr "&Remove" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Channel:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Specify..." + +msgid "Sectors:" +msgstr "Sectors:" + +msgid "Heads:" +msgstr "Heads:" + +msgid "Cylinders:" +msgstr "Cylinders:" + +msgid "Size (MB):" +msgstr "Size (MB):" + +msgid "Type:" +msgstr "Type:" + +msgid "Image Format:" +msgstr "Image Format:" + +msgid "Block Size:" +msgstr "Block Size:" + +msgid "Floppy drives:" +msgstr "Floppy drives:" + +msgid "Turbo timings" +msgstr "Turbo timings" + +msgid "Check BPB" +msgstr "Check BPB" + +msgid "CD-ROM drives:" +msgstr "CD-ROM drives:" + +msgid "MO drives:" +msgstr "MO drives:" + +msgid "ZIP drives:" +msgstr "ZIP drives:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "ISA Memory Expansion" + +msgid "Card 1:" +msgstr "Card 1:" + +msgid "Card 2:" +msgstr "Card 2:" + +msgid "Card 3:" +msgstr "Card 3:" + +msgid "Card 4:" +msgstr "Card 4:" + +msgid "ISABugger device" +msgstr "ISABugger device" + +msgid "POST card" +msgstr "POST card" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Error" + +msgid "Fatal error" +msgstr "Fatal error" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Press Ctrl+Alt+PgDn to return to windowed mode." + +msgid "Speed" +msgstr "Speed" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP images" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." + +msgid "(empty)" +msgstr "(empty)" + +msgid "All files" +msgstr "All files" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "On" + +msgid "Off" +msgstr "Off" + +msgid "All images" +msgstr "All images" + +msgid "Basic sector images" +msgstr "Basic sector images" + +msgid "Surface images" +msgstr "Surface images" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." + +msgid "Machine" +msgstr "Machine" + +msgid "Display" +msgstr "Display" + +msgid "Input devices" +msgstr "Input devices" + +msgid "Sound" +msgstr "Sound" + +msgid "Network" +msgstr "Network" + +msgid "Ports (COM & LPT)" +msgstr "Ports (COM & LPT)" + +msgid "Storage controllers" +msgstr "Storage controllers" + +msgid "Hard disks" +msgstr "Hard disks" + +msgid "Floppy & CD-ROM drives" +msgstr "Floppy & CD-ROM drives" + +msgid "Other removable devices" +msgstr "Other removable devices" + +msgid "Other peripherals" +msgstr "Other peripherals" + +msgid "Click to capture mouse" +msgstr "Click to capture mouse" + +msgid "Press F8+F12 to release mouse" +msgstr "Press F8+F12 to release mouse" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Press F8+F12 or middle button to release mouse" + +msgid "Unable to initialize FluidSynth" +msgstr "Unable to initialize FluidSynth" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "File" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Could not initialize the video renderer." + +msgid "Default" +msgstr "Default" + +msgid "%i Wait state(s)" +msgstr "%i Wait state(s)" + +msgid "Type" +msgstr "Type" + +msgid "Failed to set up PCap" +msgstr "Failed to set up PCap" + +msgid "No PCap devices found" +msgstr "No PCap devices found" + +msgid "Invalid PCap device" +msgstr "Invalid PCap device" + +msgid "Standard 2-button joystick(s)" +msgstr "Standard 2-button joystick(s)" + +msgid "Standard 4-button joystick" +msgstr "Standard 4-button joystick" + +msgid "Standard 6-button joystick" +msgstr "Standard 6-button joystick" + +msgid "Standard 8-button joystick" +msgstr "Standard 8-button joystick" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "None" + +msgid "Unable to load keyboard accelerators." +msgstr "Unable to load keyboard accelerators." + +msgid "Unable to register raw input." +msgstr "Unable to register raw input." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Floppy %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Advanced sector images" + +msgid "Flux images" +msgstr "Flux images" + +msgid "Unable to initialize FreeType" +msgstr "Unable to initialize FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Unable to initialize SDL, SDL2.dll is required" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Are you sure you want to hard reset the emulated machine?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Are you sure you want to exit 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Unable to initialize Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO images" + +msgid "Welcome to 86Box!" +msgstr "Welcome to 86Box!" + +msgid "Internal controller" +msgstr "Internal controller" + +msgid "Exit" +msgstr "Exit" + +msgid "No ROMs found" +msgstr "No ROMs found" + +msgid "Do you want to save the settings?" +msgstr "Do you want to save the settings?" + +msgid "This will hard reset the emulated machine." +msgstr "This will hard reset the emulated machine." + +msgid "Save" +msgstr "Save" + +msgid "About 86Box" +msgstr "About 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." + +msgid "Hardware not available" +msgstr "Hardware not available" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." + +msgid "Invalid configuration" +msgstr "Invalid configuration" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " is required for ESC/P printer emulation." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " is required for FluidSynth MIDI output." + +msgid "Entering fullscreen mode" +msgstr "Entering fullscreen mode" + +msgid "Don't show this message again" +msgstr "Don't show this message again" + +msgid "Don't exit" +msgstr "Don't exit" + +msgid "Reset" +msgstr "Reset" + +msgid "Don't reset" +msgstr "Don't reset" + +msgid "CD-ROM images" +msgstr "CD-ROM images" + +msgid "%hs Device Configuration" +msgstr "%hs Device Configuration" + +msgid "Monitor in sleep mode" +msgstr "Monitor in sleep mode" + +msgid "OpenGL Shaders" +msgstr "OpenGL Shaders" + +msgid "OpenGL options" +msgstr "OpenGL options" + +msgid "You are loading an unsupported configuration" +msgstr "You are loading an unsupported configuration" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." + +msgid "Continue" +msgstr "Continue" + +msgid "Cassette: %s" +msgstr "Cassette: %s" + +msgid "Cassette images" +msgstr "Cassette images" + +msgid "Cartridge %i: %ls" +msgstr "Cartridge %i: %ls" + +msgid "Cartridge images" +msgstr "Cartridge images" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Hard disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL or ESDI CD-ROM drives never existed" + +msgid "Custom..." +msgstr "Custom..." + +msgid "Custom (large)..." +msgstr "Custom (large)..." + +msgid "Add New Hard Disk" +msgstr "Add New Hard Disk" + +msgid "Add Existing Hard Disk" +msgstr "Add Existing Hard Disk" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI disk images cannot be larger than 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Disk images cannot be larger than 127 GB." + +msgid "Hard disk images" +msgstr "Hard disk images" + +msgid "Unable to read file" +msgstr "Unable to read file" + +msgid "Unable to write file" +msgstr "Unable to write file" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "HDI or HDX images with a sector size other than 512 are not supported." + +msgid "USB is not yet supported" +msgstr "USB is not yet supported" + +msgid "Disk image file already exists" +msgstr "Disk image file already exists" + +msgid "Please specify a valid file name." +msgstr "Please specify a valid file name." + +msgid "Disk image created" +msgstr "Disk image created" + +msgid "Make sure the file exists and is readable." +msgstr "Make sure the file exists and is readable." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Make sure the file is being saved to a writable directory." + +msgid "Disk image too large" +msgstr "Disk image too large" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Remember to partition and format the newly-created drive." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "The selected file will be overwritten. Are you sure you want to use it?" + +msgid "Unsupported disk image" +msgstr "Unsupported disk image" + +msgid "Overwrite" +msgstr "Overwrite" + +msgid "Don't overwrite" +msgstr "Don't overwrite" + +msgid "Raw image (.img)" +msgstr "Raw image (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI image (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX image (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "Fixed-size VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dynamic-size VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differencing VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Large blocks (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Small blocks (512 KB)" + +msgid "VHD files" +msgstr "VHD files" + +msgid "Select the parent VHD" +msgstr "Select the parent VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Parent and child disk timestamps do not match" + +msgid "Could not fix VHD timestamp." +msgstr "Could not fix VHD timestamp." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Perfect RPM" + +msgid "1% below perfect RPM" +msgstr "1% below perfect RPM" + +msgid "1.5% below perfect RPM" +msgstr "1.5% below perfect RPM" + +msgid "2% below perfect RPM" +msgstr "2% below perfect RPM" + +msgid "(System Default)" +msgstr "(System Default)" + diff --git a/src/qt/languages/en-US.po b/src/qt/languages/en-US.po new file mode 100644 index 000000000..b11e1cdea --- /dev/null +++ b/src/qt/languages/en-US.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Action" + +msgid "&Keyboard requires capture" +msgstr "&Keyboard requires capture" + +msgid "&Right CTRL is left ALT" +msgstr "&Right CTRL is left ALT" + +msgid "&Hard Reset..." +msgstr "&Hard Reset..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pause" + +msgid "E&xit..." +msgstr "E&xit..." + +msgid "&View" +msgstr "&View" + +msgid "&Hide status bar" +msgstr "&Hide status bar" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Resizeable window" + +msgid "R&emember size && position" +msgstr "R&emember size && position" + +msgid "Re&nderer" +msgstr "Re&nderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Specify dimensions..." + +msgid "F&orce 4:3 display ratio" +msgstr "F&orce 4:3 display ratio" + +msgid "&Window scale factor" +msgstr "&Window scale factor" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Filter method" + +msgid "&Nearest" +msgstr "&Nearest" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Hi&DPI scaling" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Fullscreen\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Fullscreen &stretch mode" + +msgid "&Full screen stretch" +msgstr "&Full screen stretch" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Square pixels (Keep ratio)" + +msgid "&Integer scale" +msgstr "&Integer scale" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA settings" + +msgid "&Inverted VGA monitor" +msgstr "&Inverted VGA monitor" + +msgid "VGA screen &type" +msgstr "VGA screen &type" + +msgid "RGB &Color" +msgstr "RGB &Color" + +msgid "&RGB Grayscale" +msgstr "&RGB Grayscale" + +msgid "&Amber monitor" +msgstr "&Amber monitor" + +msgid "&Green monitor" +msgstr "&Green monitor" + +msgid "&White monitor" +msgstr "&White monitor" + +msgid "Grayscale &conversion type" +msgstr "Grayscale &conversion type" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Average" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" + +msgid "Change contrast for &monochrome display" +msgstr "Change contrast for &monochrome display" + +msgid "&Media" +msgstr "&Media" + +msgid "&Tools" +msgstr "&Tools" + +msgid "&Settings..." +msgstr "&Settings..." + +msgid "&Update status bar icons" +msgstr "&Update status bar icons" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Take s&creenshot\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferences..." + +msgid "Enable &Discord integration" +msgstr "Enable &Discord integration" + +msgid "Sound &gain..." +msgstr "Sound &gain..." + +msgid "Begin trace\tCtrl+T" +msgstr "Begin trace\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "End trace\tCtrl+T" + +msgid "&Help" +msgstr "&Help" + +msgid "&Documentation..." +msgstr "&Documentation..." + +msgid "&About 86Box..." +msgstr "&About 86Box..." + +msgid "&New image..." +msgstr "&New image..." + +msgid "&Existing image..." +msgstr "&Existing image..." + +msgid "Existing image (&Write-protected)..." +msgstr "Existing image (&Write-protected)..." + +msgid "&Record" +msgstr "&Record" + +msgid "&Play" +msgstr "&Play" + +msgid "&Rewind to the beginning" +msgstr "&Rewind to the beginning" + +msgid "&Fast forward to the end" +msgstr "&Fast forward to the end" + +msgid "E&ject" +msgstr "E&ject" + +msgid "&Image..." +msgstr "&Image..." + +msgid "E&xport to 86F..." +msgstr "E&xport to 86F..." + +msgid "&Mute" +msgstr "&Mute" + +msgid "E&mpty" +msgstr "E&mpty" + +msgid "&Reload previous image" +msgstr "&Reload previous image" + +msgid "&Image" +msgstr "&Image" + +msgid "Target &framerate" +msgstr "Target &framerate" + +msgid "&Sync with video" +msgstr "&Sync with video" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Select shader..." + +msgid "&Remove shader" +msgstr "&Remove shader" + +msgid "Preferences" +msgstr "Preferences" + +msgid "Sound Gain" +msgstr "Sound Gain" + +msgid "New Image" +msgstr "New Image" + +msgid "Settings" +msgstr "Settings" + +msgid "Specify Main Window Dimensions" +msgstr "Specify Main Window Dimensions" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Cancel" + +msgid "Save these settings as &global defaults" +msgstr "Save these settings as &global defaults" + +msgid "&Default" +msgstr "&Default" + +msgid "Language:" +msgstr "Language:" + +msgid "Icon set:" +msgstr "Icon set:" + +msgid "Gain" +msgstr "Gain" + +msgid "File name:" +msgstr "File name:" + +msgid "Disk size:" +msgstr "Disk size:" + +msgid "RPM mode:" +msgstr "RPM mode:" + +msgid "Progress:" +msgstr "Progress:" + +msgid "Width:" +msgstr "Width:" + +msgid "Height:" +msgstr "Height:" + +msgid "Lock to this size" +msgstr "Lock to this size" + +msgid "Machine type:" +msgstr "Machine type:" + +msgid "Machine:" +msgstr "Machine:" + +msgid "Configure" +msgstr "Configure" + +msgid "CPU type:" +msgstr "CPU type:" + +msgid "Speed:" +msgstr "Speed:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Wait states:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memory:" + +msgid "Time synchronization" +msgstr "Time synchronization" + +msgid "Disabled" +msgstr "Disabled" + +msgid "Enabled (local time)" +msgstr "Enabled (local time)" + +msgid "Enabled (UTC)" +msgstr "Enabled (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamic Recompiler" + +msgid "Video:" +msgstr "Video:" + +msgid "Voodoo Graphics" +msgstr "Voodoo Graphics" + +msgid "Mouse:" +msgstr "Mouse:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Sound card:" + +msgid "MIDI Out Device:" +msgstr "MIDI Out Device:" + +msgid "MIDI In Device:" +msgstr "MIDI In Device:" + +msgid "Standalone MPU-401" +msgstr "Standalone MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Use FLOAT32 sound" + +msgid "Network type:" +msgstr "Network type:" + +msgid "PCap device:" +msgstr "PCap device:" + +msgid "Network adapter:" +msgstr "Network adapter:" + +msgid "COM1 Device:" +msgstr "COM1 Device:" + +msgid "COM2 Device:" +msgstr "COM2 Device:" + +msgid "COM3 Device:" +msgstr "COM3 Device:" + +msgid "COM4 Device:" +msgstr "COM4 Device:" + +msgid "LPT1 Device:" +msgstr "LPT1 Device:" + +msgid "LPT2 Device:" +msgstr "LPT2 Device:" + +msgid "LPT3 Device:" +msgstr "LPT3 Device:" + +msgid "LPT4 Device:" +msgstr "LPT4 Device:" + +msgid "Serial port 1" +msgstr "Serial port 1" + +msgid "Serial port 2" +msgstr "Serial port 2" + +msgid "Serial port 3" +msgstr "Serial port 3" + +msgid "Serial port 4" +msgstr "Serial port 4" + +msgid "Parallel port 1" +msgstr "Parallel port 1" + +msgid "Parallel port 2" +msgstr "Parallel port 2" + +msgid "Parallel port 3" +msgstr "Parallel port 3" + +msgid "Parallel port 4" +msgstr "Parallel port 4" + +msgid "HD Controller:" +msgstr "HD Controller:" + +msgid "FD Controller:" +msgstr "FD Controller:" + +msgid "Tertiary IDE Controller" +msgstr "Tertiary IDE Controller" + +msgid "Quaternary IDE Controller" +msgstr "Quaternary IDE Controller" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controller 1:" + +msgid "Controller 2:" +msgstr "Controller 2:" + +msgid "Controller 3:" +msgstr "Controller 3:" + +msgid "Controller 4:" +msgstr "Controller 4:" + +msgid "Cassette" +msgstr "Cassette" + +msgid "Hard disks:" +msgstr "Hard disks:" + +msgid "&New..." +msgstr "&New..." + +msgid "&Existing..." +msgstr "&Existing..." + +msgid "&Remove" +msgstr "&Remove" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Channel:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Specify..." + +msgid "Sectors:" +msgstr "Sectors:" + +msgid "Heads:" +msgstr "Heads:" + +msgid "Cylinders:" +msgstr "Cylinders:" + +msgid "Size (MB):" +msgstr "Size (MB):" + +msgid "Type:" +msgstr "Type:" + +msgid "Image Format:" +msgstr "Image Format:" + +msgid "Block Size:" +msgstr "Block Size:" + +msgid "Floppy drives:" +msgstr "Floppy drives:" + +msgid "Turbo timings" +msgstr "Turbo timings" + +msgid "Check BPB" +msgstr "Check BPB" + +msgid "CD-ROM drives:" +msgstr "CD-ROM drives:" + +msgid "MO drives:" +msgstr "MO drives:" + +msgid "ZIP drives:" +msgstr "ZIP drives:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "ISA Memory Expansion" + +msgid "Card 1:" +msgstr "Card 1:" + +msgid "Card 2:" +msgstr "Card 2:" + +msgid "Card 3:" +msgstr "Card 3:" + +msgid "Card 4:" +msgstr "Card 4:" + +msgid "ISABugger device" +msgstr "ISABugger device" + +msgid "POST card" +msgstr "POST card" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Error" + +msgid "Fatal error" +msgstr "Fatal error" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Press Ctrl+Alt+PgDn to return to windowed mode." + +msgid "Speed" +msgstr "Speed" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP images" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." + +msgid "(empty)" +msgstr "(empty)" + +msgid "All files" +msgstr "All files" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "On" + +msgid "Off" +msgstr "Off" + +msgid "All images" +msgstr "All images" + +msgid "Basic sector images" +msgstr "Basic sector images" + +msgid "Surface images" +msgstr "Surface images" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." + +msgid "Machine" +msgstr "Machine" + +msgid "Display" +msgstr "Display" + +msgid "Input devices" +msgstr "Input devices" + +msgid "Sound" +msgstr "Sound" + +msgid "Network" +msgstr "Network" + +msgid "Ports (COM & LPT)" +msgstr "Ports (COM & LPT)" + +msgid "Storage controllers" +msgstr "Storage controllers" + +msgid "Hard disks" +msgstr "Hard disks" + +msgid "Floppy & CD-ROM drives" +msgstr "Floppy & CD-ROM drives" + +msgid "Other removable devices" +msgstr "Other removable devices" + +msgid "Other peripherals" +msgstr "Other peripherals" + +msgid "Click to capture mouse" +msgstr "Click to capture mouse" + +msgid "Press F8+F12 to release mouse" +msgstr "Press F8+F12 to release mouse" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Press F8+F12 or middle button to release mouse" + +msgid "Unable to initialize FluidSynth" +msgstr "Unable to initialize FluidSynth" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "File" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Could not initialize the video renderer." + +msgid "Default" +msgstr "Default" + +msgid "%i Wait state(s)" +msgstr "%i Wait state(s)" + +msgid "Type" +msgstr "Type" + +msgid "Failed to set up PCap" +msgstr "Failed to set up PCap" + +msgid "No PCap devices found" +msgstr "No PCap devices found" + +msgid "Invalid PCap device" +msgstr "Invalid PCap device" + +msgid "Standard 2-button joystick(s)" +msgstr "Standard 2-button joystick(s)" + +msgid "Standard 4-button joystick" +msgstr "Standard 4-button joystick" + +msgid "Standard 6-button joystick" +msgstr "Standard 6-button joystick" + +msgid "Standard 8-button joystick" +msgstr "Standard 8-button joystick" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "None" + +msgid "Unable to load keyboard accelerators." +msgstr "Unable to load keyboard accelerators." + +msgid "Unable to register raw input." +msgstr "Unable to register raw input." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Floppy %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Advanced sector images" + +msgid "Flux images" +msgstr "Flux images" + +msgid "Unable to initialize FreeType" +msgstr "Unable to initialize FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Unable to initialize SDL, SDL2.dll is required" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Are you sure you want to hard reset the emulated machine?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Are you sure you want to exit 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Unable to initialize Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO images" + +msgid "Welcome to 86Box!" +msgstr "Welcome to 86Box!" + +msgid "Internal controller" +msgstr "Internal controller" + +msgid "Exit" +msgstr "Exit" + +msgid "No ROMs found" +msgstr "No ROMs found" + +msgid "Do you want to save the settings?" +msgstr "Do you want to save the settings?" + +msgid "This will hard reset the emulated machine." +msgstr "This will hard reset the emulated machine." + +msgid "Save" +msgstr "Save" + +msgid "About 86Box" +msgstr "About 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." + +msgid "Hardware not available" +msgstr "Hardware not available" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." + +msgid "Invalid configuration" +msgstr "Invalid configuration" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " is required for ESC/P printer emulation." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " is required for FluidSynth MIDI output." + +msgid "Entering fullscreen mode" +msgstr "Entering fullscreen mode" + +msgid "Don't show this message again" +msgstr "Don't show this message again" + +msgid "Don't exit" +msgstr "Don't exit" + +msgid "Reset" +msgstr "Reset" + +msgid "Don't reset" +msgstr "Don't reset" + +msgid "CD-ROM images" +msgstr "CD-ROM images" + +msgid "%hs Device Configuration" +msgstr "%hs Device Configuration" + +msgid "Monitor in sleep mode" +msgstr "Monitor in sleep mode" + +msgid "OpenGL Shaders" +msgstr "OpenGL Shaders" + +msgid "OpenGL options" +msgstr "OpenGL options" + +msgid "You are loading an unsupported configuration" +msgstr "You are loading an unsupported configuration" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." + +msgid "Continue" +msgstr "Continue" + +msgid "Cassette: %s" +msgstr "Cassette: %s" + +msgid "Cassette images" +msgstr "Cassette images" + +msgid "Cartridge %i: %ls" +msgstr "Cartridge %i: %ls" + +msgid "Cartridge images" +msgstr "Cartridge images" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Hard disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL or ESDI CD-ROM drives never existed" + +msgid "Custom..." +msgstr "Custom..." + +msgid "Custom (large)..." +msgstr "Custom (large)..." + +msgid "Add New Hard Disk" +msgstr "Add New Hard Disk" + +msgid "Add Existing Hard Disk" +msgstr "Add Existing Hard Disk" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI disk images cannot be larger than 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Disk images cannot be larger than 127 GB." + +msgid "Hard disk images" +msgstr "Hard disk images" + +msgid "Unable to read file" +msgstr "Unable to read file" + +msgid "Unable to write file" +msgstr "Unable to write file" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "HDI or HDX images with a sector size other than 512 are not supported." + +msgid "USB is not yet supported" +msgstr "USB is not yet supported" + +msgid "Disk image file already exists" +msgstr "Disk image file already exists" + +msgid "Please specify a valid file name." +msgstr "Please specify a valid file name." + +msgid "Disk image created" +msgstr "Disk image created" + +msgid "Make sure the file exists and is readable." +msgstr "Make sure the file exists and is readable." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Make sure the file is being saved to a writable directory." + +msgid "Disk image too large" +msgstr "Disk image too large" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Remember to partition and format the newly-created drive." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "The selected file will be overwritten. Are you sure you want to use it?" + +msgid "Unsupported disk image" +msgstr "Unsupported disk image" + +msgid "Overwrite" +msgstr "Overwrite" + +msgid "Don't overwrite" +msgstr "Don't overwrite" + +msgid "Raw image (.img)" +msgstr "Raw image (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI image (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX image (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "Fixed-size VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dynamic-size VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differencing VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Large blocks (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Small blocks (512 KB)" + +msgid "VHD files" +msgstr "VHD files" + +msgid "Select the parent VHD" +msgstr "Select the parent VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Parent and child disk timestamps do not match" + +msgid "Could not fix VHD timestamp." +msgstr "Could not fix VHD timestamp." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Perfect RPM" + +msgid "1% below perfect RPM" +msgstr "1% below perfect RPM" + +msgid "1.5% below perfect RPM" +msgstr "1.5% below perfect RPM" + +msgid "2% below perfect RPM" +msgstr "2% below perfect RPM" + +msgid "(System Default)" +msgstr "(System Default)" + diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po new file mode 100644 index 000000000..c7b306e1c --- /dev/null +++ b/src/qt/languages/es-ES.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Acción" + +msgid "&Keyboard requires capture" +msgstr "&Teclado requiere captura" + +msgid "&Right CTRL is left ALT" +msgstr "CTRL &derecho es ALT izquierdo" + +msgid "&Hard Reset..." +msgstr "&Hard Reset..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pausa" + +msgid "E&xit..." +msgstr "&Salir..." + +msgid "&View" +msgstr "&Vista" + +msgid "&Hide status bar" +msgstr "&Ocultar barra de estado" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Ventana redimensionable" + +msgid "R&emember size && position" +msgstr "&Recordar tamaño y posición" + +msgid "Re&nderer" +msgstr "Re&nderizador" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "E&specificar dimensiones..." + +msgid "F&orce 4:3 display ratio" +msgstr "F&orzar ratio 4:3" + +msgid "&Window scale factor" +msgstr "&Factor de escalado de ventana" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "&Método de filtrado" + +msgid "&Nearest" +msgstr "&Más cercano" + +msgid "&Linear" +msgstr "&Lineal" + +msgid "Hi&DPI scaling" +msgstr "&Escalado alta densidad" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Pantalla completa\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Escalado pantalla completa" + +msgid "&Full screen stretch" +msgstr "&Estirar" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Píxeles cuadrados (Mant. aspecto)" + +msgid "&Integer scale" +msgstr "&Escalado valor entero" + +msgid "E&GA/(S)VGA settings" +msgstr "&Ajustes EGA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Monitor VGA invertido" + +msgid "VGA screen &type" +msgstr "&Tipo de pantalla VGA" + +msgid "RGB &Color" +msgstr "RGB &Color" + +msgid "&RGB Grayscale" +msgstr "RGB &Grises" + +msgid "&Amber monitor" +msgstr "Monitor &Ámbar" + +msgid "&Green monitor" +msgstr "Monitor &Verde" + +msgid "&White monitor" +msgstr "Monitor &Blanco" + +msgid "Grayscale &conversion type" +msgstr "&Conversión a grises" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Media" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "&Overscan CGA/PCjr/Tandy/EGA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Cambiar contraste para pantalla &monocroma" + +msgid "&Media" +msgstr "&Medios" + +msgid "&Tools" +msgstr "&Herramientas" + +msgid "&Settings..." +msgstr "&Ajustes..." + +msgid "&Update status bar icons" +msgstr "&Actualizar iconos en barra de estado" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Tomar c&aptura\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferencias..." + +msgid "Enable &Discord integration" +msgstr "Habilitar integración con &Discord" + +msgid "Sound &gain..." +msgstr "&Ganancia de sonido..." + +msgid "Begin trace\tCtrl+T" +msgstr "Comenzar traza\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Terminar traza\tCtrl+T" + +msgid "&Help" +msgstr "&Ayuda" + +msgid "&Documentation..." +msgstr "&Documentación..." + +msgid "&About 86Box..." +msgstr "&Acerca de 86Box..." + +msgid "&New image..." +msgstr "&Nueva imagen..." + +msgid "&Existing image..." +msgstr "Imagen &Existente..." + +msgid "Existing image (&Write-protected)..." +msgstr "Imagen Existente (&Sólo-lectura)..." + +msgid "&Record" +msgstr "&Grabar" + +msgid "&Play" +msgstr "&Reproducir" + +msgid "&Rewind to the beginning" +msgstr "&Rebobinar al inicio" + +msgid "&Fast forward to the end" +msgstr "&Avance rápido al final" + +msgid "E&ject" +msgstr "E&xtraer" + +msgid "&Image..." +msgstr "&Imagen..." + +msgid "E&xport to 86F..." +msgstr "E&xportar a 86F..." + +msgid "&Mute" +msgstr "&Silenciar" + +msgid "E&mpty" +msgstr "E&xtraer disco" + +msgid "&Reload previous image" +msgstr "&Recargar imagen previa" + +msgid "&Image" +msgstr "&Imagen..." + +msgid "Target &framerate" +msgstr "&Tasa de refresco objetivo" + +msgid "&Sync with video" +msgstr "&Sincronizar con vídeo" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Seleccionar shader..." + +msgid "&Remove shader" +msgstr "&Eliminar shader" + +msgid "Preferences" +msgstr "Preferencias" + +msgid "Sound Gain" +msgstr "Ganancia de Sonido" + +msgid "New Image" +msgstr "Nueva Imagen" + +msgid "Settings" +msgstr "Ajustes" + +msgid "Specify Main Window Dimensions" +msgstr "Especificar Dimensiones de la Ventana Principal" + +msgid "OK" +msgstr "Aceptar" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Save these settings as &global defaults" +msgstr "Salvar estos ajustes como por &defecto globalmente" + +msgid "&Default" +msgstr "&Por defecto" + +msgid "Language:" +msgstr "Idioma:" + +msgid "Icon set:" +msgstr "Juego de iconos:" + +msgid "Gain" +msgstr "Ganancia" + +msgid "File name:" +msgstr "Nombre de archivo:" + +msgid "Disk size:" +msgstr "Tamaño de disco:" + +msgid "RPM mode:" +msgstr "Modo RPM:" + +msgid "Progress:" +msgstr "Progreso:" + +msgid "Width:" +msgstr "Ancho:" + +msgid "Height:" +msgstr "Alto:" + +msgid "Lock to this size" +msgstr "Bloquear a este tamaño" + +msgid "Machine type:" +msgstr "Tipo de máquina:" + +msgid "Machine:" +msgstr "Máquina:" + +msgid "Configure" +msgstr "Configurar" + +msgid "CPU type:" +msgstr "Tipo de CPU:" + +msgid "Speed:" +msgstr "Velocidad:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Estados en espera:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memoria:" + +msgid "Time synchronization" +msgstr "Sincronización horaria" + +msgid "Disabled" +msgstr "Deshabilitado" + +msgid "Enabled (local time)" +msgstr "Habilitado (hora local)" + +msgid "Enabled (UTC)" +msgstr "Habilitado (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Recompilador Dinámico" + +msgid "Video:" +msgstr "Vídeo:" + +msgid "Voodoo Graphics" +msgstr "Voodoo Graphics" + +msgid "Mouse:" +msgstr "Ratón:" + +msgid "Joystick:" +msgstr "Mando:" + +msgid "Joystick 1..." +msgstr "Mando 1..." + +msgid "Joystick 2..." +msgstr "Mando 2..." + +msgid "Joystick 3..." +msgstr "Mando 3..." + +msgid "Joystick 4..." +msgstr "Mando 4..." + +msgid "Sound card:" +msgstr "Tarjeta de sonido:" + +msgid "MIDI Out Device:" +msgstr "Dispositivo MIDI de salida:" + +msgid "MIDI In Device:" +msgstr "Dispositivo MIDI de entrada:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 independiente" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Usar sonido FLOAT32" + +msgid "Network type:" +msgstr "Tipo de red:" + +msgid "PCap device:" +msgstr "Dispositivo PCap:" + +msgid "Network adapter:" +msgstr "Adaptador de red:" + +msgid "COM1 Device:" +msgstr "Dispositivo COM1:" + +msgid "COM2 Device:" +msgstr "Dispositivo COM2:" + +msgid "COM3 Device:" +msgstr "Dispositivo COM3:" + +msgid "COM4 Device:" +msgstr "Dispositivo COM4:" + +msgid "LPT1 Device:" +msgstr "Dispositivo LPT1:" + +msgid "LPT2 Device:" +msgstr "Dispositivo LPT2:" + +msgid "LPT3 Device:" +msgstr "Dispositivo LPT3:" + +msgid "LPT4 Device:" +msgstr "Dispositivo LPT4:" + +msgid "Serial port 1" +msgstr "Puerto serie 1" + +msgid "Serial port 2" +msgstr "Puerto serie 2" + +msgid "Serial port 3" +msgstr "Puerto serie 3" + +msgid "Serial port 4" +msgstr "Puerto serie 4" + +msgid "Parallel port 1" +msgstr "Puerto paralelo 1" + +msgid "Parallel port 2" +msgstr "Puerto paralelo 2" + +msgid "Parallel port 3" +msgstr "Puerto paralelo 3" + +msgid "Parallel port 4" +msgstr "Puerto paralelo 4" + +msgid "HD Controller:" +msgstr "Controladora HD:" + +msgid "FD Controller:" +msgstr "Controladora FD:" + +msgid "Tertiary IDE Controller" +msgstr "Tercera controladora IDE" + +msgid "Quaternary IDE Controller" +msgstr "Cuarta controladora IDE" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controladora 1:" + +msgid "Controller 2:" +msgstr "Controladora 2:" + +msgid "Controller 3:" +msgstr "Controladora 3:" + +msgid "Controller 4:" +msgstr "Controladora 4:" + +msgid "Cassette" +msgstr "Cassette" + +msgid "Hard disks:" +msgstr "Discos duros:" + +msgid "&New..." +msgstr "&Nuevo..." + +msgid "&Existing..." +msgstr "&Existente..." + +msgid "&Remove" +msgstr "E&liminar" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Canal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "E&specificar..." + +msgid "Sectors:" +msgstr "Sectores:" + +msgid "Heads:" +msgstr "Cabezas:" + +msgid "Cylinders:" +msgstr "Cilindros:" + +msgid "Size (MB):" +msgstr "Tamaño (MB):" + +msgid "Type:" +msgstr "Tipo:" + +msgid "Image Format:" +msgstr "Formato de imagen:" + +msgid "Block Size:" +msgstr "Tamaño de bloque:" + +msgid "Floppy drives:" +msgstr "Unidades de disquete:" + +msgid "Turbo timings" +msgstr "Temporizaciones Turbo" + +msgid "Check BPB" +msgstr "Chequear BPB" + +msgid "CD-ROM drives:" +msgstr "Unidades de CD-ROM:" + +msgid "MO drives:" +msgstr "Unidades MO:" + +msgid "ZIP drives:" +msgstr "Unidades ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Expansión de Memoria ISA" + +msgid "Card 1:" +msgstr "Tarjeta 1:" + +msgid "Card 2:" +msgstr "Tarjeta 2:" + +msgid "Card 3:" +msgstr "Tarjeta 3:" + +msgid "Card 4:" +msgstr "Tarjeta 4:" + +msgid "ISABugger device" +msgstr "Dispositivo ISABugger" + +msgid "POST card" +msgstr "Tarjeta POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Error" + +msgid "Fatal error" +msgstr "Error fatal" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Pulsa Ctrl+Alt+PgDn para volver a modo ventana." + +msgid "Speed" +msgstr "Velocidad" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Imagenes ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box no pudo encontrar ninguna imagen ROM usable.\n\nPor favor descarga un grupo de imágenes y extráelas en el directorio \"roms\"." + +msgid "(empty)" +msgstr "(vacío)" + +msgid "All files" +msgstr "All files" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "On" + +msgid "Off" +msgstr "Off" + +msgid "All images" +msgstr "Todas las imagenes" + +msgid "Basic sector images" +msgstr "Basic sector images" + +msgid "Surface images" +msgstr "Surface images" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "La máquina \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una máquina disponible." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "La tarjeta de vídeo \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una tarjeta de vídeo disponible." + +msgid "Machine" +msgstr "Máquina" + +msgid "Display" +msgstr "Vídeo" + +msgid "Input devices" +msgstr "Dispositivos de Entrada" + +msgid "Sound" +msgstr "Sonido" + +msgid "Network" +msgstr "Red" + +msgid "Ports (COM & LPT)" +msgstr "Puertos (COM y LPT)" + +msgid "Storage controllers" +msgstr "Controladoras de Almacenamiento" + +msgid "Hard disks" +msgstr "Discos Duros" + +msgid "Floppy & CD-ROM drives" +msgstr "Disquetes y unidades de CD-ROM" + +msgid "Other removable devices" +msgstr "Otros dispositivos extraíbles" + +msgid "Other peripherals" +msgstr "Otros periféricos" + +msgid "Click to capture mouse" +msgstr "Haz click para capturar el ratón" + +msgid "Press F8+F12 to release mouse" +msgstr "Pulsa F8+F12 para liberar el ratón" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Pulsa F8+F12 o el botón central para liberar el ratón" + +msgid "Unable to initialize FluidSynth" +msgstr "Incapaz de inicializar FluidSynth" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "Archivo" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Incapaz de inicializar el renderizador de vídeo." + +msgid "Default" +msgstr "Por defecto" + +msgid "%i Wait state(s)" +msgstr "%i estado(s) de Espera" + +msgid "Type" +msgstr "Tipo" + +msgid "Failed to set up PCap" +msgstr "Incapaz de configurar PCap" + +msgid "No PCap devices found" +msgstr "No se encontraron dispositivos PCap" + +msgid "Invalid PCap device" +msgstr "Dispositivo PCap inválido" + +msgid "Standard 2-button joystick(s)" +msgstr "Mando(s) de 2 botones estándar" + +msgid "Standard 4-button joystick" +msgstr "Mando de 4 botones estándar" + +msgid "Standard 6-button joystick" +msgstr "Mando de 6 botones estándar" + +msgid "Standard 8-button joystick" +msgstr "Mando de 8 botones estándar" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Ninguno" + +msgid "Unable to load keyboard accelerators." +msgstr "Incapaz de cargar aceleradores de teclado." + +msgid "Unable to register raw input." +msgstr "Incapaz de registrar entrada directa." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disquete %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Advanced sector images" + +msgid "Flux images" +msgstr "Flux images" + +msgid "Unable to initialize FreeType" +msgstr "Incapaz de inicializar FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Incapaz de inicializar SDL, se requiere SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "¿Seguro que quieres resetear la máquina emulada?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "¿Seguro que quieres cerrar 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Incapaz de inicializar Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "Imágenes de MO" + +msgid "Welcome to 86Box!" +msgstr "¡Bienvenido a 86Box!" + +msgid "Internal controller" +msgstr "Controladora interna" + +msgid "Exit" +msgstr "Salir" + +msgid "No ROMs found" +msgstr "No se encontraron ROMs" + +msgid "Do you want to save the settings?" +msgstr "¿Quieres guardar los ajustes?" + +msgid "This will hard reset the emulated machine." +msgstr "Se hará hard reset de la máquina emulada." + +msgid "Save" +msgstr "Guardar" + +msgid "About 86Box" +msgstr "Acerca de 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Un emulador de ordenadores antigüos\n\nAutores: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, y otros.\n\nLiberado bajo la GNU General Public License versión 2 o posterior. Ver LICENSE para más información." + +msgid "Hardware not available" +msgstr "Hardware no disponible" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Asegúrate de que libpcap está instalado y de que estás en una conexión de red compatible con libpcap." + +msgid "Invalid configuration" +msgstr "Configuración inválida" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " es necesaria para emulación de impresión ESC/P." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " es necesaria para la conversión automática de archivos PostScript a PDF.\n\nCualquier documento enviado a la impresora genérica postScript se guardará como archivo PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " es necesario para salida MIDI FluidSynth." + +msgid "Entering fullscreen mode" +msgstr "Entrando en modo pantalla completa" + +msgid "Don't show this message again" +msgstr "No mostrar más este mensaje" + +msgid "Don't exit" +msgstr "No salir" + +msgid "Reset" +msgstr "Resetear" + +msgid "Don't reset" +msgstr "No resetear" + +msgid "CD-ROM images" +msgstr "Imágenes de CD-ROM" + +msgid "%hs Device Configuration" +msgstr "%hs Configuración de Dispositivo" + +msgid "Monitor in sleep mode" +msgstr "Monitor en modo ahorro" + +msgid "OpenGL Shaders" +msgstr "Shaders OpenGL" + +msgid "OpenGL options" +msgstr "Opciones OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Estás cargando una configuración no soportada" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "El Filtrado de tipo de CPU basado en máquina seleccionada está deshabilitado para la esta máquina.\n\nEsto hace posible seleccionar una CPU que sea incompatible con esta máquina. Por ello, pueden aparecer incompatibilidader con la BIOS de la máquina u otro software.\n\nActivar este ajuste no está oficialmente soportado y cualquier reporte de fallo puede ser cerrado como inválido." + +msgid "Continue" +msgstr "Continuar" + +msgid "Cassette: %s" +msgstr "Cassette: %s" + +msgid "Cassette images" +msgstr "Imágenes de Cassette" + +msgid "Cartridge %i: %ls" +msgstr "Cartucho %i: %ls" + +msgid "Cartridge images" +msgstr "Imágenes de Cartucho" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Disco duro (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Nunca hubo unidades de CD-ROM MFM/RLL o ESDI" + +msgid "Custom..." +msgstr "A medida..." + +msgid "Custom (large)..." +msgstr "A medida (grande)..." + +msgid "Add New Hard Disk" +msgstr "Añadir Nuevo Disco Duro" + +msgid "Add Existing Hard Disk" +msgstr "Añadir Disco Duro Existente" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Las imágenes de disco HDI no pueden superar los 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Las imágenes de disco no pueden superar los 127 GB." + +msgid "Hard disk images" +msgstr "Imágenes de Disco Duro" + +msgid "Unable to read file" +msgstr "No se pudo leer el archivo" + +msgid "Unable to write file" +msgstr "No se pudo escribir el archivo" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "No se soportan las imágenes HDI o HDX con un tamaño de sector diferente a 512." + +msgid "USB is not yet supported" +msgstr "No se soporta aún el USB" + +msgid "Disk image file already exists" +msgstr "La imagen de disco ya existe" + +msgid "Please specify a valid file name." +msgstr "Por favor especifique un nombre de archivo válido." + +msgid "Disk image created" +msgstr "Imagen de disco creada" + +msgid "Make sure the file exists and is readable." +msgstr "Asegúrese de que el archivo existe y es leíble." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Asegúrese de que el archivo en un directorio con permiso de escritura." + +msgid "Disk image too large" +msgstr "Imagen de disco demasiado grande" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Recuerde particionar y formatear la nueva unidad." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "El archivo selecionado será sobreescrito. ¿Está seguro de querer usarlo?" + +msgid "Unsupported disk image" +msgstr "Imagen de disco no soportada" + +msgid "Overwrite" +msgstr "Sobreescribir" + +msgid "Don't overwrite" +msgstr "No sobreescribir" + +msgid "Raw image (.img)" +msgstr "Imagen plana (.img)" + +msgid "HDI image (.hdi)" +msgstr "Imagen HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Imagen HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD de tamaño fijo (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD de tamaño dinámico (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD diferencial (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Bloques grandes (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Bloques pequeños (512 KB)" + +msgid "VHD files" +msgstr "Archivos VHD" + +msgid "Select the parent VHD" +msgstr "Seleccione el VHD padre" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Esto puede deberse a que la imagen padre se modificó después de que la imagen diferencial se crease.\n\nTambién puede ocurrir si las imágenes fueron movidas o copiadas, o por un fallo en el programa que creó este disco.\n\n¿Quiere corregir los registros de tiempo?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Las marcas de tiempo del padre e hijo no coinciden" + +msgid "Could not fix VHD timestamp." +msgstr "No se pudo corregir la marca de tiempo del VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "RPM perfectas" + +msgid "1% below perfect RPM" +msgstr "1% por debajo de RPM perfectas" + +msgid "1.5% below perfect RPM" +msgstr "1.5% por debajo de RPM perfectas" + +msgid "2% below perfect RPM" +msgstr "2% por debajo de RPM perfectas" + +msgid "(System Default)" +msgstr "(Por defecto del sistema)" + diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po new file mode 100644 index 000000000..991b13205 --- /dev/null +++ b/src/qt/languages/fi-FI.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Toiminto" + +msgid "&Keyboard requires capture" +msgstr "&Vaadi näppäimistön kaappaus" + +msgid "&Right CTRL is left ALT" +msgstr "&Oikea CTRL on vasen ALT" + +msgid "&Hard Reset..." +msgstr "&Uudelleenkäynnistys (kylmä)..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Tauko" + +msgid "E&xit..." +msgstr "&Poistu..." + +msgid "&View" +msgstr "&Näytä" + +msgid "&Hide status bar" +msgstr "&Piilota tilapalkki" + +msgid "Hide &toolbar" +msgstr "Piilota &työkalupalkki" + +msgid "&Resizeable window" +msgstr "&Salli koon muuttaminen" + +msgid "R&emember size && position" +msgstr "&Muista koko ja sijainti" + +msgid "Re&nderer" +msgstr "&Renderöijä" + +msgid "&SDL (Software)" +msgstr "&SDL (ohjelmistopohjainen)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&laitteistokiihdytetty)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "&Määritä koko..." + +msgid "F&orce 4:3 display ratio" +msgstr "Pakota 4:3-näyttösuhde" + +msgid "&Window scale factor" +msgstr "&Ikkunan kokokerroin" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "&Suodatusmetodi" + +msgid "&Nearest" +msgstr "&Lähin naapuri" + +msgid "&Linear" +msgstr "Li&neaarinen interpolaatio" + +msgid "Hi&DPI scaling" +msgstr "&Suuri DPI-skaalaus" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Koko näytön tila\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Koko näytön &skaalaustila" + +msgid "&Full screen stretch" +msgstr "&Venytä koko näyttöön" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Tasasivuiset kuvapisteet (säilytä kuvasuhde)" + +msgid "&Integer scale" +msgstr "&Kokonaislukuskaalaus" + +msgid "E&GA/(S)VGA settings" +msgstr "&EGA/(S)VGA-asetukset" + +msgid "&Inverted VGA monitor" +msgstr "&VGA näyttö käänteisillä väreillä" + +msgid "VGA screen &type" +msgstr "VGA-näytön &tyyppi" + +msgid "RGB &Color" +msgstr "RGB, &värit" + +msgid "&RGB Grayscale" +msgstr "&RGB, harmaasävy" + +msgid "&Amber monitor" +msgstr "&Meripihkanvärinen" + +msgid "&Green monitor" +msgstr "V&ihreä" + +msgid "&White monitor" +msgstr "V&alkoinen" + +msgid "Grayscale &conversion type" +msgstr "&Harmaasävymuunnoksen tyyppi" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Keskiarvo" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA-&yliskannaus" + +msgid "Change contrast for &monochrome display" +msgstr "&Muuta harmaavärinäytön kontrastia" + +msgid "&Media" +msgstr "&Media" + +msgid "&Tools" +msgstr "Työ&kalut" + +msgid "&Settings..." +msgstr "&Kokoonpano..." + +msgid "&Update status bar icons" +msgstr "&Päivitä tilapalkin kuvakkeita" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Ota &kuvakaappaus\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Sovellusasetukset..." + +msgid "Enable &Discord integration" +msgstr "Käytä &Discord-integraatiota" + +msgid "Sound &gain..." +msgstr "&Äänitasot..." + +msgid "Begin trace\tCtrl+T" +msgstr "Aloita jäljitys\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Lopeta jäljitys\tCtrl+T" + +msgid "&Help" +msgstr "&Ohje" + +msgid "&Documentation..." +msgstr "&Ohjekirja..." + +msgid "&About 86Box..." +msgstr "&Tietoja 86Boxista..." + +msgid "&New image..." +msgstr "&Uusi levykuva..." + +msgid "&Existing image..." +msgstr "&Olemassaoleva levykuva..." + +msgid "Existing image (&Write-protected)..." +msgstr "Olemassaoleva levykuva (&kirjoitussuojattu)..." + +msgid "&Record" +msgstr "&Nauhoita" + +msgid "&Play" +msgstr "&Toista" + +msgid "&Rewind to the beginning" +msgstr "Kelaa &alkuun" + +msgid "&Fast forward to the end" +msgstr "Kelaa &loppuun" + +msgid "E&ject" +msgstr "&Poista asemasta" + +msgid "&Image..." +msgstr "&ROM-moduulikuva..." + +msgid "E&xport to 86F..." +msgstr "&Vie 86F-tiedostoon..." + +msgid "&Mute" +msgstr "&Mykistä" + +msgid "E&mpty" +msgstr "&Tyhjä" + +msgid "&Reload previous image" +msgstr "&Lataa edellinen levykuva uudelleen" + +msgid "&Image" +msgstr "L&evykuva" + +msgid "Target &framerate" +msgstr "&Kuvataajuustavoite" + +msgid "&Sync with video" +msgstr "&Synkronisoi videoon" + +msgid "&25 fps" +msgstr "&25 ruutua/s" + +msgid "&30 fps" +msgstr "&30 ruutua/s" + +msgid "&50 fps" +msgstr "&50 ruutua/s" + +msgid "&60 fps" +msgstr "&60 ruutua/s" + +msgid "&75 fps" +msgstr "&75 ruutua/s" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "Valitse varjostin&ohjelma..." + +msgid "&Remove shader" +msgstr "&Poista varjostinohjelma" + +msgid "Preferences" +msgstr "Sovellusasetukset" + +msgid "Sound Gain" +msgstr "Äänen taso" + +msgid "New Image" +msgstr "Uusi levykuva" + +msgid "Settings" +msgstr "Kokoonpano" + +msgid "Specify Main Window Dimensions" +msgstr "Määritä pääikkunan koko" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Peruuta" + +msgid "Save these settings as &global defaults" +msgstr "Tallenna nämä asetukset &globaaleiksi oletuksiksi" + +msgid "&Default" +msgstr "&Oletus" + +msgid "Language:" +msgstr "Kieli:" + +msgid "Icon set:" +msgstr "Kuvakkeet:" + +msgid "Gain" +msgstr "Taso" + +msgid "File name:" +msgstr "Tiedostonimi:" + +msgid "Disk size:" +msgstr "Levyn koko:" + +msgid "RPM mode:" +msgstr "Kierroslukutila:" + +msgid "Progress:" +msgstr "Edistyminen:" + +msgid "Width:" +msgstr "Leveys:" + +msgid "Height:" +msgstr "Korkeus:" + +msgid "Lock to this size" +msgstr "Lukitse tähän kokoon" + +msgid "Machine type:" +msgstr "Tietokoneen tyyppi:" + +msgid "Machine:" +msgstr "Tietokone:" + +msgid "Configure" +msgstr "Määritys" + +msgid "CPU type:" +msgstr "Suorittimen tyyppi:" + +msgid "Speed:" +msgstr "Nopeus:" + +msgid "FPU:" +msgstr "Apusuoritin:" + +msgid "Wait states:" +msgstr "Odotustilat:" + +msgid "MB" +msgstr "Mt" + +msgid "Memory:" +msgstr "Muisti:" + +msgid "Time synchronization" +msgstr "Kellon synkronointi" + +msgid "Disabled" +msgstr "Ei käytössä" + +msgid "Enabled (local time)" +msgstr "Käytössä (paikallinen)" + +msgid "Enabled (UTC)" +msgstr "Käytössä (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynaaminen uudelleenkääntäjä" + +msgid "Video:" +msgstr "Näytönohjain:" + +msgid "Voodoo Graphics" +msgstr "Voodoo-grafiikkasuoritin" + +msgid "Mouse:" +msgstr "Hiiri:" + +msgid "Joystick:" +msgstr "Peliohjain:" + +msgid "Joystick 1..." +msgstr "Peliohjain 1..." + +msgid "Joystick 2..." +msgstr "Peliohjain 2..." + +msgid "Joystick 3..." +msgstr "Peliohjain 3..." + +msgid "Joystick 4..." +msgstr "Peliohjain 4..." + +msgid "Sound card:" +msgstr "Äänikortti:" + +msgid "MIDI Out Device:" +msgstr "MIDI-ulostulo:" + +msgid "MIDI In Device:" +msgstr "MIDI-sisääntulo:" + +msgid "Standalone MPU-401" +msgstr "Erillinen MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Käytä FLOAT32-ääntä" + +msgid "Network type:" +msgstr "Verkon tyyppi:" + +msgid "PCap device:" +msgstr "PCap-laite:" + +msgid "Network adapter:" +msgstr "Verkkokortti:" + +msgid "COM1 Device:" +msgstr "COM1-laite:" + +msgid "COM2 Device:" +msgstr "COM2-laite:" + +msgid "COM3 Device:" +msgstr "COM3-laite:" + +msgid "COM4 Device:" +msgstr "COM4-laite:" + +msgid "LPT1 Device:" +msgstr "LPT1-laite:" + +msgid "LPT2 Device:" +msgstr "LPT2-laite:" + +msgid "LPT3 Device:" +msgstr "LPT3-laite:" + +msgid "LPT4 Device:" +msgstr "LPT4-laite:" + +msgid "Serial port 1" +msgstr "Sarjaportti 1" + +msgid "Serial port 2" +msgstr "Sarjaportti 2" + +msgid "Serial port 3" +msgstr "Sarjaportti 3" + +msgid "Serial port 4" +msgstr "Sarjaportti 4" + +msgid "Parallel port 1" +msgstr "Rinnakkaisportti 1" + +msgid "Parallel port 2" +msgstr "Rinnakkaisportti 2" + +msgid "Parallel port 3" +msgstr "Rinnakkaisportti 3" + +msgid "Parallel port 4" +msgstr "Rinnakkaisportti 4" + +msgid "HD Controller:" +msgstr "Kiintolevyohjain:" + +msgid "FD Controller:" +msgstr "Levykeohjain:" + +msgid "Tertiary IDE Controller" +msgstr "Kolmas IDE-ohjain" + +msgid "Quaternary IDE Controller" +msgstr "Neljäs IDE-ohjain" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Ohjain 1:" + +msgid "Controller 2:" +msgstr "Ohjain 2:" + +msgid "Controller 3:" +msgstr "Ohjain 3:" + +msgid "Controller 4:" +msgstr "Ohjain 4:" + +msgid "Cassette" +msgstr "Kasettiasema" + +msgid "Hard disks:" +msgstr "Kiintolevyt:" + +msgid "&New..." +msgstr "&Uusi..." + +msgid "&Existing..." +msgstr "&Olemassaoleva..." + +msgid "&Remove" +msgstr "&Poista" + +msgid "Bus:" +msgstr "Väylä:" + +msgid "Channel:" +msgstr "Kanava:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Määritä..." + +msgid "Sectors:" +msgstr "Sektorit:" + +msgid "Heads:" +msgstr "Lukupäät:" + +msgid "Cylinders:" +msgstr "Sylinterit:" + +msgid "Size (MB):" +msgstr "Koko (Mt):" + +msgid "Type:" +msgstr "Tyyppi:" + +msgid "Image Format:" +msgstr "Tiedostomuoto:" + +msgid "Block Size:" +msgstr "Lohkon koko:" + +msgid "Floppy drives:" +msgstr "Levykeasemat:" + +msgid "Turbo timings" +msgstr "Turbo-ajoitukset" + +msgid "Check BPB" +msgstr "Tarkista BPB" + +msgid "CD-ROM drives:" +msgstr "CD-ROM-asemat:" + +msgid "MO drives:" +msgstr "Magneettisoptiset asemat (MO):" + +msgid "ZIP drives:" +msgstr "ZIP-asemat:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA-RTC (kello):" + +msgid "ISA Memory Expansion" +msgstr "ISA-muistilaajennus" + +msgid "Card 1:" +msgstr "Kortti 1:" + +msgid "Card 2:" +msgstr "Kortti 2:" + +msgid "Card 3:" +msgstr "Kortti 3:" + +msgid "Card 4:" +msgstr "Kortti 4:" + +msgid "ISABugger device" +msgstr "ISABugger-laite" + +msgid "POST card" +msgstr "POST-kortti" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Virhe" + +msgid "Fatal error" +msgstr "Vakava virhe" + +msgid " - PAUSED" +msgstr " - TAUKO" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Paina Ctrl+Alt+PgDn palataksesi ikkunoituun tilaan." + +msgid "Speed" +msgstr "Nopeus" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP-levykuvat" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box ei löytänyt käyttökelpoisia ROM-tiedostoja.\n\nVoit ladata ROM-paketin ja purkaa sen \"roms\"-hakemistoon." + +msgid "(empty)" +msgstr "(tyhjä)" + +msgid "All files" +msgstr "Kaikki tiedostot" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Päällä" + +msgid "Off" +msgstr "Pois" + +msgid "All images" +msgstr "Kaikki levykuvat" + +msgid "Basic sector images" +msgstr "Perussektorilevykuvat" + +msgid "Surface images" +msgstr "Pintalevykuvat" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Konetta \"%hs\" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen koneeseen." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Näytönohjainta \"%hs\" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen näytönohjaimeen." + +msgid "Machine" +msgstr "Tietokone" + +msgid "Display" +msgstr "Näyttö" + +msgid "Input devices" +msgstr "Syöttölaitteet" + +msgid "Sound" +msgstr "Ääni" + +msgid "Network" +msgstr "Verkko" + +msgid "Ports (COM & LPT)" +msgstr "Portit (COM & LPT)" + +msgid "Storage controllers" +msgstr "Tallennusohjaimet" + +msgid "Hard disks" +msgstr "Kiintolevyt" + +msgid "Floppy & CD-ROM drives" +msgstr "Levyke ja CD-ROM" + +msgid "Other removable devices" +msgstr "Muut tallennuslaitteet" + +msgid "Other peripherals" +msgstr "Muut oheislaitteet" + +msgid "Click to capture mouse" +msgstr "Kaappaa hiiri klikkaamalla" + +msgid "Press F8+F12 to release mouse" +msgstr "Paina F8+F12 vapauttaaksesi hiiren" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Paina F8+F12 tai keskipainiketta vapauttaaksesi hiiren" + +msgid "Unable to initialize FluidSynth" +msgstr "FluidSynthin alustus epäonnistui" + +msgid "Bus" +msgstr "Väylä" + +msgid "File" +msgstr "Tiedosto" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "kt" + +msgid "Could not initialize the video renderer." +msgstr "Videorenderöijän alustus epäonnistui" + +msgid "Default" +msgstr "Oletus" + +msgid "%i Wait state(s)" +msgstr "%i odotustilaa" + +msgid "Type" +msgstr "Tyyppi" + +msgid "Failed to set up PCap" +msgstr "PCap-asennus epäonnistui" + +msgid "No PCap devices found" +msgstr "PCap-laitteita ei löytynyt" + +msgid "Invalid PCap device" +msgstr "Virheellinen PCap-laite" + +msgid "Standard 2-button joystick(s)" +msgstr "Standardi 2-painikkeinen peliohjain/-ohjaimet" + +msgid "Standard 4-button joystick" +msgstr "Standardi 4-painikkeinen peliohjain" + +msgid "Standard 6-button joystick" +msgstr "Standardi 6-painikkeinen peliohjain" + +msgid "Standard 8-button joystick" +msgstr "Standardi 8-painikkeinen peliohjain" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Ei mikään" + +msgid "Unable to load keyboard accelerators." +msgstr "Näppäinkiihdyttimien lataus epäonnistui" + +msgid "Unable to register raw input." +msgstr "Raakasyötteen rekisteröinti epäonnistui" + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u Mt (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Levyke %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Kehittyneet sektorilevykuvat" + +msgid "Flux images" +msgstr "Flux-levykuvat" + +msgid "Unable to initialize FreeType" +msgstr "FreeType:n alustus epäonnistui" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "SDL:n alustus epäonnistui. Tarvitaan SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Haluatko varmasti käynnistää emuloidun tietokoneen uudelleen?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Haluatko varmasti sulkea 86Boxin?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ghostscriptin alustus epäonnistui" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO-levykuvat" + +msgid "Welcome to 86Box!" +msgstr "Tervetuloa 86Boxiin!" + +msgid "Internal controller" +msgstr "Sisäinen ohjain" + +msgid "Exit" +msgstr "Poistu" + +msgid "No ROMs found" +msgstr "ROM-tiedostoja ei löytynyt" + +msgid "Do you want to save the settings?" +msgstr "Tallennetaanko asetukset?" + +msgid "This will hard reset the emulated machine." +msgstr "Tämä käynnistää emuloidun tietokoneen uudelleen." + +msgid "Save" +msgstr "Tallenna" + +msgid "About 86Box" +msgstr "Tietoja 86Box:sta" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Vanhojen tietokoneiden emulaattori\n\nTekijät: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho ja muut.\n\nJulkaistu GNU General Public License 2. version tai myöhemmän alaisena. Tarkempia tietoja LICENSE-tiedostossa." + +msgid "Hardware not available" +msgstr "Laitteisto ei ole saatavilla" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Varmista, että libpcap on asennettu ja että verkkoyhteytesi on libpcap-yhteensopiva." + +msgid "Invalid configuration" +msgstr "Virheelliset määritykset" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " vaaditaan ESC/P-tulostimen emuloimiseksi." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " vaaditaan PostScript-tiedostojen automaattiseen muuntamiseen PDF-tiedostoiksi.\n\nKaikki geneeriselle PostScript-tulostimelle lähetetyt asiakirjat tallennetaan PostScript (.ps) -tiedostoina." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " vaaditaan FluidSynth MIDI-ulostuloa varten." + +msgid "Entering fullscreen mode" +msgstr "Siirrytään koko näytön tilaan" + +msgid "Don't show this message again" +msgstr "Älä näytä tätä viestiä uudelleen" + +msgid "Don't exit" +msgstr "Älä poistu" + +msgid "Reset" +msgstr "Käynnistä uudelleen" + +msgid "Don't reset" +msgstr "Älä käynnistä uudelleen" + +msgid "CD-ROM images" +msgstr "CD-ROM-levykuvat" + +msgid "%hs Device Configuration" +msgstr "%hs - Laitteen määritykset" + +msgid "Monitor in sleep mode" +msgstr "Näyttö lepotilassa" + +msgid "OpenGL Shaders" +msgstr "OpenGL-varjostinohjelmat" + +msgid "OpenGL options" +msgstr "OpenGL-asetukset" + +msgid "You are loading an unsupported configuration" +msgstr "Olet lataamassa ei-tuettuja määrittelyjä" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Valittuun tietokoneeseen perustuva suoritintyypin suodatus ei ole käytössä tällä emuloidulla koneella.\n\nTämä mahdollistaa muutoin yhteensopimattoman suorittimen valinnan kyseisen tietokoneen kanssa. Voit kuitenkin kohdata ongelmia tietokoneen BIOS:in tai muun ohjelmiston kanssa.\n\nTämän asetuksen käyttö ei ole virallisesti tuettua ja kaikki tehdyt virheraportit voidaan sulkea epäpätevinä." + +msgid "Continue" +msgstr "Jatka" + +msgid "Cassette: %s" +msgstr "Kasetti: %s" + +msgid "Cassette images" +msgstr "Kasettitiedostot" + +msgid "Cartridge %i: %ls" +msgstr "ROM-moduuli %i: %ls" + +msgid "Cartridge images" +msgstr "ROM-moduulikuvat" + +msgid "Error initializing renderer" +msgstr "Virhe renderöijän alustuksessa" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) -renderöijän alustus epäonnistui. Käytä toista renderöijää." + +msgid "Resume execution" +msgstr "Jatka suoritusta" + +msgid "Pause execution" +msgstr "Pysäytä suoritus" + +msgid "Press Ctrl+Alt+Del" +msgstr "Paina Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Paina Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Kylmä uudelleenkäynnistys" + +msgid "ACPI shutdown" +msgstr "ACPI-sammutus" + +msgid "Hard disk (%s)" +msgstr "Kiintolevy (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL- tai ESDI-CD-ROM-asemia ei ole koskaan ollut olemassa" + +msgid "Custom..." +msgstr "Mukautettu..." + +msgid "Custom (large)..." +msgstr "Mukautettu (suuri)..." + +msgid "Add New Hard Disk" +msgstr "Lisää uusi kiintolevy" + +msgid "Add Existing Hard Disk" +msgstr "Lisää olemassaoleva kiintolevy" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI-levykuvan suurin mahdollinen koko on 4 Gt." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Levykuvien suurin mahdollinen koko on 127 Gt." + +msgid "Hard disk images" +msgstr "Kiintolevykuvat" + +msgid "Unable to read file" +msgstr "Tiedostoa ei voi lukea" + +msgid "Unable to write file" +msgstr "Tiedostoon ei voi kirjoittaa" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "HDI- ja HDX-levykuvien ainoa tuettu sektorikoko on 512" + +msgid "USB is not yet supported" +msgstr "USB-tukea ei vielä ole" + +msgid "Disk image file already exists" +msgstr "Levykuva on jo olemassa" + +msgid "Please specify a valid file name." +msgstr "Anna kelvollinen tiedostonimi." + +msgid "Disk image created" +msgstr "Levykuva luotu" + +msgid "Make sure the file exists and is readable." +msgstr "Varmista, että tiedosto on olemassa ja lukukelpoinen" + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Varmista, että tiedoston tallennuskansioon on kirjoitusoikeus" + +msgid "Disk image too large" +msgstr "Liian suuri levykuva" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Muista osioida ja alustaa juuri luomasi asema." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Valittu tiedosto korvataan. Oletko varma, että haluat käyttää sitä?" + +msgid "Unsupported disk image" +msgstr "Levykuvaa ei tueta" + +msgid "Overwrite" +msgstr "Korvaa" + +msgid "Don't overwrite" +msgstr "Älä korvaa" + +msgid "Raw image (.img)" +msgstr "Raaka levykuva (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI-levykuva (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX-levykuva (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "Kiinteä VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dynaaminen VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differentiaalinen VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Suuret lohkot (2 Mt)" + +msgid "Small blocks (512 KB)" +msgstr "Pienet lohkot (512 kt)" + +msgid "VHD files" +msgstr "VHD-tiedostot" + +msgid "Select the parent VHD" +msgstr "Valitse ylätason VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Tämä saattaa tarkoittaa, että ylätason levykuvaa on muokattu differentiaalisen levykuvan luonnin jälkeen.\n\nNäin voi käydä myös, jos levykuvatiedostoja on siirretty tai kopioitu. Lisäksi syynä voi olla levyn luoneessa sovelluksessa oleva ohjelmistovirhe.\n\nKorjataanko aikaleimat?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Ylä- ja alatason levyjen aikaleimat eivät täsmää" + +msgid "Could not fix VHD timestamp." +msgstr "VHD aikaleimaa ei pystytty korjaamaan." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kt" + +msgid "180 kB" +msgstr "180 kt" + +msgid "320 kB" +msgstr "320 kt" + +msgid "360 kB" +msgstr "360 kt" + +msgid "640 kB" +msgstr "640 kt" + +msgid "720 kB" +msgstr "720 kt" + +msgid "1.2 MB" +msgstr "1.2 Mt" + +msgid "1.25 MB" +msgstr "1.25 Mt" + +msgid "1.44 MB" +msgstr "1.44 Mt" + +msgid "DMF (cluster 1024)" +msgstr "DMF (lohko 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (lohko 2048)" + +msgid "2.88 MB" +msgstr "2.88 Mt" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 Mt (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 Mt (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 Mt (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 Mt (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 Gt (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 Gt (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 Mt" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 Mt" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 Gt" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 Gt" + +msgid "Perfect RPM" +msgstr "Täydellinen kierrosluku" + +msgid "1% below perfect RPM" +msgstr "1% alle täydellisen kierrosluvun" + +msgid "1.5% below perfect RPM" +msgstr "1.5% alle täydellisen kierrosluvun" + +msgid "2% below perfect RPM" +msgstr "2% alle täydellisen kierrosluvun" + +msgid "(System Default)" +msgstr "(Järjestelmän oletus)" + diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po new file mode 100644 index 000000000..7fa029045 --- /dev/null +++ b/src/qt/languages/fr-FR.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Action" + +msgid "&Keyboard requires capture" +msgstr "&Capturer le clavier" + +msgid "&Right CTRL is left ALT" +msgstr "CTRL &Droite devient ALT Gauche" + +msgid "&Hard Reset..." +msgstr "&Hard Reset..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pause" + +msgid "E&xit..." +msgstr "&Quitter..." + +msgid "&View" +msgstr "&Vue" + +msgid "&Hide status bar" +msgstr "&Masquer la barre de status" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "Fenètre &Retaillable" + +msgid "R&emember size && position" +msgstr "S&auvegarder taille && position" + +msgid "Re&nderer" +msgstr "Moteur de &rendu vidéo" + +msgid "&SDL (Software)" +msgstr "&SDL (Logiciel)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Materiel)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Specifier dimensions..." + +msgid "F&orce 4:3 display ratio" +msgstr "F&orcer 4:3" + +msgid "&Window scale factor" +msgstr "&Echelle facteur" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Methode Filtre" + +msgid "&Nearest" +msgstr "&Plus proche" + +msgid "&Linear" +msgstr "&Lineaire" + +msgid "Hi&DPI scaling" +msgstr "Mise à l'échelle Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Plein Ecran\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Mode &Elargi plein écran" + +msgid "&Full screen stretch" +msgstr "&Plein écran étiré" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "pixels &Carrés(Keep ratio)" + +msgid "&Integer scale" +msgstr "Echelle &Entière" + +msgid "E&GA/(S)VGA settings" +msgstr "Réglages E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "Moniteur VGA &Inversé" + +msgid "VGA screen &type" +msgstr "&Type Ecran VGA" + +msgid "RGB &Color" +msgstr "RGB &Couleur" + +msgid "&RGB Grayscale" +msgstr "&RGB Ton de Gris" + +msgid "&Amber monitor" +msgstr "Moniteur &Ambre" + +msgid "&Green monitor" +msgstr "Moniteur &Vert" + +msgid "&White monitor" +msgstr "Moniteur &Blanc" + +msgid "Grayscale &conversion type" +msgstr "Grayscale &conversion type" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Moyenne" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" + +msgid "Change contrast for &monochrome display" +msgstr "Modifier contraste affichage &monochrome" + +msgid "&Media" +msgstr "&Media" + +msgid "&Tools" +msgstr "Ou&tils" + +msgid "&Settings..." +msgstr "&Réglages..." + +msgid "&Update status bar icons" +msgstr "Mettre à jour la barre de stat&us" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Copie &Ecran\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Préférences..." + +msgid "Enable &Discord integration" +msgstr "Activer intégration &Discord" + +msgid "Sound &gain..." +msgstr "&Gain Son..." + +msgid "Begin trace\tCtrl+T" +msgstr "Démarrer traces\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Finir traces\tCtrl+T" + +msgid "&Help" +msgstr "&Aide" + +msgid "&Documentation..." +msgstr "&Documentation..." + +msgid "&About 86Box..." +msgstr "&A Propos de 86Box..." + +msgid "&New image..." +msgstr "&Nouvelle image..." + +msgid "&Existing image..." +msgstr "Image &Existante..." + +msgid "Existing image (&Write-protected)..." +msgstr "Image Existante(&Lecture seule)..." + +msgid "&Record" +msgstr "En®istrer" + +msgid "&Play" +msgstr "&Jouer" + +msgid "&Rewind to the beginning" +msgstr "&Revenir au debut" + +msgid "&Fast forward to the end" +msgstr "Aller à la &Fin" + +msgid "E&ject" +msgstr "E&jecter" + +msgid "&Image..." +msgstr "&Image..." + +msgid "E&xport to 86F..." +msgstr "E&xport vers 86F..." + +msgid "&Mute" +msgstr "&Couper" + +msgid "E&mpty" +msgstr "E&jecter" + +msgid "&Reload previous image" +msgstr "&Recharger image précedente" + +msgid "&Image" +msgstr "&Image" + +msgid "Target &framerate" +msgstr "&Taux de rafraîchissement cible" + +msgid "&Sync with video" +msgstr "&Synchronisation avec la vidéo" + +msgid "&25 fps" +msgstr "&25 images par seconde" + +msgid "&30 fps" +msgstr "&30 images par seconde" + +msgid "&50 fps" +msgstr "&50 images par seconde" + +msgid "&60 fps" +msgstr "&60 images par seconde" + +msgid "&75 fps" +msgstr "&75 images par seconde" + +msgid "&VSync" +msgstr "Synchronisation &verticale" + +msgid "&Select shader..." +msgstr "Sé&lectionnez le shader..." + +msgid "&Remove shader" +msgstr "S&upprimer le shader" + +msgid "Preferences" +msgstr "Préférences" + +msgid "Sound Gain" +msgstr "Gain son" + +msgid "New Image" +msgstr "Nouvelle image" + +msgid "Settings" +msgstr "Réglages" + +msgid "Specify Main Window Dimensions" +msgstr "Spécifier le détournement de la fenêtre principale" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Annuler" + +msgid "Save these settings as &global defaults" +msgstr "Sauvegarder ces paramètres comme valeurs par défaut &globales" + +msgid "&Default" +msgstr "&Défaut" + +msgid "Language:" +msgstr "Langue:" + +msgid "Icon set:" +msgstr "Ensemble d'icônes:" + +msgid "Gain" +msgstr "Gain" + +msgid "File name:" +msgstr "Nom fichier:" + +msgid "Disk size:" +msgstr "Taille disque:" + +msgid "RPM mode:" +msgstr "Mode RPM:" + +msgid "Progress:" +msgstr "Progrès:" + +msgid "Width:" +msgstr "Largeur:" + +msgid "Height:" +msgstr "Hauteur:" + +msgid "Lock to this size" +msgstr "Verrouiller à cette taille" + +msgid "Machine type:" +msgstr "Type de machine:" + +msgid "Machine:" +msgstr "Machine:" + +msgid "Configure" +msgstr "Configurer" + +msgid "CPU type:" +msgstr "Type du processeur:" + +msgid "Speed:" +msgstr "Vitesse:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "États d'attente:" + +msgid "MB" +msgstr "Mo" + +msgid "Memory:" +msgstr "Mémoire:" + +msgid "Time synchronization" +msgstr "Synchronisation du temps" + +msgid "Disabled" +msgstr "Désactivé" + +msgid "Enabled (local time)" +msgstr "Activé (heure locale)" + +msgid "Enabled (UTC)" +msgstr "Activé (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Recompilateur dynamique" + +msgid "Video:" +msgstr "Vidéo:" + +msgid "Voodoo Graphics" +msgstr "Graphique Voodoo" + +msgid "Mouse:" +msgstr "Souris:" + +msgid "Joystick:" +msgstr "Manette de commande:" + +msgid "Joystick 1..." +msgstr "Manette 1..." + +msgid "Joystick 2..." +msgstr "Manette 2..." + +msgid "Joystick 3..." +msgstr "Manette 3..." + +msgid "Joystick 4..." +msgstr "Manette 4..." + +msgid "Sound card:" +msgstr "Carte son:" + +msgid "MIDI Out Device:" +msgstr "Sortie MIDI:" + +msgid "MIDI In Device:" +msgstr "Entrée MIDI:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 autonome" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Utiliser le son FLOAT32" + +msgid "Network type:" +msgstr "Type de réseau:" + +msgid "PCap device:" +msgstr "Dispositif PCap:" + +msgid "Network adapter:" +msgstr "Adaptateur de réseau:" + +msgid "COM1 Device:" +msgstr "Dispositif COM1:" + +msgid "COM2 Device:" +msgstr "Dispositif COM2:" + +msgid "COM3 Device:" +msgstr "Dispositif COM3:" + +msgid "COM4 Device:" +msgstr "Dispositif COM4:" + +msgid "LPT1 Device:" +msgstr "Dispositif LPT1:" + +msgid "LPT2 Device:" +msgstr "Dispositif LPT2:" + +msgid "LPT3 Device:" +msgstr "Dispositif LPT3:" + +msgid "LPT4 Device:" +msgstr "Dispositif LPT4:" + +msgid "Serial port 1" +msgstr "Port série 1" + +msgid "Serial port 2" +msgstr "Port série 2" + +msgid "Serial port 3" +msgstr "Port série 3" + +msgid "Serial port 4" +msgstr "Port série 4" + +msgid "Parallel port 1" +msgstr "Port parallèle 1" + +msgid "Parallel port 2" +msgstr "Port parallèle 2" + +msgid "Parallel port 3" +msgstr "Port parallèle 3" + +msgid "Parallel port 4" +msgstr "Port parallèle 4" + +msgid "HD Controller:" +msgstr "Contrôleur HD:" + +msgid "FD Controller:" +msgstr "Contrôleur FD:" + +msgid "Tertiary IDE Controller" +msgstr "Contrôleur IDE tertiaire" + +msgid "Quaternary IDE Controller" +msgstr "Contrôleur IDE quaternair" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Contrôleur 1:" + +msgid "Controller 2:" +msgstr "Contrôleur 2:" + +msgid "Controller 3:" +msgstr "Contrôleur 3:" + +msgid "Controller 4:" +msgstr "Contrôleur 4:" + +msgid "Cassette" +msgstr "Cassette" + +msgid "Hard disks:" +msgstr "Disques durs:" + +msgid "&New..." +msgstr "&Nouveau..." + +msgid "&Existing..." +msgstr "&Existant..." + +msgid "&Remove" +msgstr "&Supprimer" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Canal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Spécifier..." + +msgid "Sectors:" +msgstr "Secteurs:" + +msgid "Heads:" +msgstr "Têtes:" + +msgid "Cylinders:" +msgstr "Cylindres:" + +msgid "Size (MB):" +msgstr "Taille (Mo):" + +msgid "Type:" +msgstr "Type:" + +msgid "Image Format:" +msgstr "Format Image:" + +msgid "Block Size:" +msgstr "Taille du bloc:" + +msgid "Floppy drives:" +msgstr "Lecteurs de disquettes:" + +msgid "Turbo timings" +msgstr "Turbo" + +msgid "Check BPB" +msgstr "Vérifier BPB" + +msgid "CD-ROM drives:" +msgstr "Lecterus CD-ROM:" + +msgid "MO drives:" +msgstr "Lecteurs magnéto-optiques:" + +msgid "ZIP drives:" +msgstr "Lecteurs ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "Horloge temps réel ISA:" + +msgid "ISA Memory Expansion" +msgstr "Expansion de la mémoire ISA" + +msgid "Card 1:" +msgstr "Carte 1:" + +msgid "Card 2:" +msgstr "Carte 2:" + +msgid "Card 3:" +msgstr "Carte 3:" + +msgid "Card 4:" +msgstr "Carte 4:" + +msgid "ISABugger device" +msgstr "Dispositif ISABugger" + +msgid "POST card" +msgstr "Carte POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Erreur" + +msgid "Fatal error" +msgstr "Erreur fatale" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Appuyez sur Ctrl+Alt+PgDn pour revenir au mode fenêtré." + +msgid "Speed" +msgstr "Vitesse" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Images ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box n'a pas pu trouver d'images ROM utilisables.\n\nS'il vous plait, téléchargez un ensemble ROM et extrayez-le dans le répertoire \"roms\"." + +msgid "(empty)" +msgstr "(vide)" + +msgid "All files" +msgstr "Tous les fichiers" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Activé" + +msgid "Off" +msgstr "Désactivé" + +msgid "All images" +msgstr "Tous les images" + +msgid "Basic sector images" +msgstr "Images basiques du secteur" + +msgid "Surface images" +msgstr "Images de la surface" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "La machine \"%hs\" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/machines. Basculer vers une machine disponible." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "La carte vidéo \"%hs\" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/video. Basculer vers une carte vidéo disponible." + +msgid "Machine" +msgstr "Machine" + +msgid "Display" +msgstr "Affichage" + +msgid "Input devices" +msgstr "Dispositifs d'entrée" + +msgid "Sound" +msgstr "Son" + +msgid "Network" +msgstr "Réseau" + +msgid "Ports (COM & LPT)" +msgstr "Ports (COM et LPT)" + +msgid "Storage controllers" +msgstr "Contrôleurs de stockage" + +msgid "Hard disks" +msgstr "Disques durs" + +msgid "Floppy & CD-ROM drives" +msgstr "Lecteurs de disquette et CD-ROM" + +msgid "Other removable devices" +msgstr "Autres dispositifs amovibles" + +msgid "Other peripherals" +msgstr "Autres périfériques" + +msgid "Click to capture mouse" +msgstr "Cliquer pour capturer la souris" + +msgid "Press F8+F12 to release mouse" +msgstr "Appuyer sur F8+F12 pour libérer la souris" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Appuyer sur F8+F12 ou le bouton central pour libérer la souris" + +msgid "Unable to initialize FluidSynth" +msgstr "Impossible d'initialiser FluidSynth" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "File" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "T" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "Ko" + +msgid "Could not initialize the video renderer." +msgstr "Impossible d'initialiser le moteur de rendu vidéo." + +msgid "Default" +msgstr "Défaut" + +msgid "%i Wait state(s)" +msgstr "%i état(s) d'attente" + +msgid "Type" +msgstr "Type" + +msgid "Failed to set up PCap" +msgstr "Impossible d'initialiser PCap" + +msgid "No PCap devices found" +msgstr "Aucun dispositif PCap trouvé" + +msgid "Invalid PCap device" +msgstr "Dispositif PCap non valide" + +msgid "Standard 2-button joystick(s)" +msgstr "Manette(s) standard avec 2 boutons" + +msgid "Standard 4-button joystick" +msgstr "Manette standard avec 4 boutons" + +msgid "Standard 6-button joystick" +msgstr "Manette standard avec 6 boutons" + +msgid "Standard 8-button joystick" +msgstr "Manette standard avec 6 boutons" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Système de contrôle de vol Thrustmaster" + +msgid "None" +msgstr "Aucun" + +msgid "Unable to load keyboard accelerators." +msgstr "Impossible de charger les accélérateurs de clavier." + +msgid "Unable to register raw input." +msgstr "Impossible de charger l'entrée raw." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u Mo (CTS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disquette %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Images du secteur avancés" + +msgid "Flux images" +msgstr "Images du flux" + +msgid "Unable to initialize FreeType" +msgstr "Impossible d'initialiser FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Impossible d'initialiser SDL, SDL2.dll est nécessaire" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Etes-vous sûr de vouloir réinitialiser la machine émulée ?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Etes-vous sûr de vouloir quitter 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Impossible d'initialiser Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "Magnéto-optique %i (%ls): %ls" + +msgid "MO images" +msgstr "Images magnéto-optiques" + +msgid "Welcome to 86Box!" +msgstr "Bienvenue dans 86Box !" + +msgid "Internal controller" +msgstr "Côntrolleur interne" + +msgid "Exit" +msgstr "Sortir" + +msgid "No ROMs found" +msgstr "Pas de ROMs trouvées" + +msgid "Do you want to save the settings?" +msgstr "Voulez-vous sauvegarder les paramètres ?" + +msgid "This will hard reset the emulated machine." +msgstr "Cela entraînera la réinitialisation complète de la machine émulée." + +msgid "Save" +msgstr "Sauvegarder" + +msgid "About 86Box" +msgstr "À propos de 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Un émulateur de vieux ordinateurs\n\nAuteurs: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nLibéré sous la licence GNU General Public License version 2 ou ultérieure. Pour plus d'informations, voir le fichier LICENSE." + +msgid "Hardware not available" +msgstr "Matériel non disponible" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Assurez-vous que libpcap est installé et que vou utilisez une connexion réseau compatible avec libpcap." + +msgid "Invalid configuration" +msgstr "Configuration non valide" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " est nécessaire pour l'émulation de l'imprimante ESC/P." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " est nécessair pour la conversion automatique des fichiers PostScript dans PDF.\n\nTous les documents envoyés à l'imprimante générique PostScript seront sauvés comme des fichiers PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " est nécessaire pour la sortie MIDI FluidSynth." + +msgid "Entering fullscreen mode" +msgstr "Entrer en mode plein écran" + +msgid "Don't show this message again" +msgstr "Ne pas montrer ce message à nouveau" + +msgid "Don't exit" +msgstr "Ne pas sortir" + +msgid "Reset" +msgstr "Réinitialiser" + +msgid "Don't reset" +msgstr "Ne pas réinitialiser" + +msgid "CD-ROM images" +msgstr "Images CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Configuration du dispositif %hs" + +msgid "Monitor in sleep mode" +msgstr "Moniteur en mode veille" + +msgid "OpenGL Shaders" +msgstr "Shaders OpenGL" + +msgid "OpenGL options" +msgstr "Options OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Vous chargez une configuration non prise en charge" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "La filtrage du type du processeur sur la base de la machine sélectionné est désactivé pur cette machine émulée.\n\nCela permet de sélectionner une processeur que est sinon incompatible avec la machine sélectionné. Cependant, il pourrait y avoir des incompatibilités avec le BIOS de la machine ou autres logiciels.\n\nL'activatione de cette configuration non est officiellement prise en charge et tout rapport de bogue peut être fermé comme étant invalide." + +msgid "Continue" +msgstr "Continuer" + +msgid "Cassette: %s" +msgstr "Cassette: %s" + +msgid "Cassette images" +msgstr "Images cassette" + +msgid "Cartridge %i: %ls" +msgstr "Cartouche %i: %ls" + +msgid "Cartridge images" +msgstr "Images cartouche" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Disque dur (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Les lecteurs de CD-ROM MFM/RLL ou ESDI n'ont jamais existé" + +msgid "Custom..." +msgstr "Personnalisé..." + +msgid "Custom (large)..." +msgstr "Personnalisé (grand)..." + +msgid "Add New Hard Disk" +msgstr "Ajouter un nouveau disque dur" + +msgid "Add Existing Hard Disk" +msgstr "Ajouter un disque dur existant" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Les images de disque HDI ne peuvent pas avoir une taille supériure à Go." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Les images de disque ne peuvent pas avoir un taille supérieure à 127 Go." + +msgid "Hard disk images" +msgstr "Images de dique dur" + +msgid "Unable to read file" +msgstr "Impossible de lire le fichier" + +msgid "Unable to write file" +msgstr "Impossible d'écrire le fichier" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Les images HDI ou HDX avec une taille de secteur différente de 512 non sont pas prises en charge." + +msgid "USB is not yet supported" +msgstr "USB n'est pas encore pris en charge." + +msgid "Disk image file already exists" +msgstr "Le fichier de l'image disque existe déjà." + +msgid "Please specify a valid file name." +msgstr "Veuillez spécifier un nom de fichier valide." + +msgid "Disk image created" +msgstr "Image de disque créée" + +msgid "Make sure the file exists and is readable." +msgstr "Assurez-vous que le fichier existe et est lisible." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Assurez-vous que le fichier en cours d'enregistrement se trouve dans un répertoire accessible en écriture." + +msgid "Disk image too large" +msgstr "Image disque trop grande" + +msgid "Remember to partition and format the newly-created drive." +msgstr "N'oubliez pas de partitionner et de formater le nouveau disque créé." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Le fichier sélectionné sera écrasé. Etes-vous sûr de vouloir l'utiliser?" + +msgid "Unsupported disk image" +msgstr "Image disque non prise en charge" + +msgid "Overwrite" +msgstr "Écraser" + +msgid "Don't overwrite" +msgstr "Ne pas écraser" + +msgid "Raw image (.img)" +msgstr "Image brute (.img)" + +msgid "HDI image (.hdi)" +msgstr "Image HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Image HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD à taille fixe (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD à taille dynamique (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD à différenciation (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Blocs grands (2 Mo)" + +msgid "Small blocks (512 KB)" +msgstr "Blocs petits (512 Ko)" + +msgid "VHD files" +msgstr "Fichiers VHD" + +msgid "Select the parent VHD" +msgstr "Sélectionnez le VHD parent" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Il est possible que l'image parente a été modifié après la création de l'image à différenciation.\n\nIl est même possible que les fichiers de l'mage ont été déplacés ou copiés ou il existe un bogue dans le programme que a créé ce disque.\n\nVoulez-vous réparer l'horodatage?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Les horodatages des disques parent et enfant ne correspondent pas" + +msgid "Could not fix VHD timestamp." +msgstr "Impossible de réparer l'horodatage du VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 Ko" + +msgid "180 kB" +msgstr "180 Ko" + +msgid "320 kB" +msgstr "320 Ko" + +msgid "360 kB" +msgstr "360 Ko" + +msgid "640 kB" +msgstr "640 Ko" + +msgid "720 kB" +msgstr "720 Ko" + +msgid "1.2 MB" +msgstr "1.2 Mo" + +msgid "1.25 MB" +msgstr "1.25 Mo" + +msgid "1.44 MB" +msgstr "1.44 Mo" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 Mo" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 Mo (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 Mo (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 Mo (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 Mo (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 Go (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 Go (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 Mo" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 Mo" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 Go" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 Go" + +msgid "Perfect RPM" +msgstr "RPM précis" + +msgid "1% below perfect RPM" +msgstr "Précision RPM de moins 1%" + +msgid "1.5% below perfect RPM" +msgstr "Précision RPM de moins 1.5%" + +msgid "2% below perfect RPM" +msgstr "Précision RPM de moins 2%" + +msgid "(System Default)" +msgstr "(Défaut du système)" + diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po new file mode 100644 index 000000000..1d3ab11a2 --- /dev/null +++ b/src/qt/languages/hr-HR.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Radnje" + +msgid "&Keyboard requires capture" +msgstr "&Tipkovnica zahtijeva hvatanje miša" + +msgid "&Right CTRL is left ALT" +msgstr "&Desni CTRL je lijevi ALT" + +msgid "&Hard Reset..." +msgstr "&Ponovno pokretanje..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pauza" + +msgid "E&xit..." +msgstr "Iz&laz..." + +msgid "&View" +msgstr "&Pogled" + +msgid "&Hide status bar" +msgstr "&Sakrij statusni redak" + +msgid "Hide &toolbar" +msgstr "&Sakrij alatni redak" + +msgid "&Resizeable window" +msgstr "&Prozor s promjenjivim veličinama" + +msgid "R&emember size && position" +msgstr "&Zapamtite veličinu i položaj" + +msgid "Re&nderer" +msgstr "&Renderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Softver)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardver)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 jezgra)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Odrediti veličinu..." + +msgid "F&orce 4:3 display ratio" +msgstr "&4:3 omjer prikaza" + +msgid "&Window scale factor" +msgstr "&Faktor skaliranja prozora" + +msgid "&0.5x" +msgstr "&0,5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1,&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Metoda filtriranja" + +msgid "&Nearest" +msgstr "&Najbliža" + +msgid "&Linear" +msgstr "&Linearna" + +msgid "Hi&DPI scaling" +msgstr "&HiDPI skaliranje" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Cijelozaslonski način\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "&Način cijelozaslonskog rastezanja" + +msgid "&Full screen stretch" +msgstr "&Razvuci na cijeli zaslona" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Kvadratni pikseli (zadrži omjer)" + +msgid "&Integer scale" +msgstr "&Cijelobrojno skaliranje" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA postavke" + +msgid "&Inverted VGA monitor" +msgstr "&Obrni boje zaslona VGA" + +msgid "VGA screen &type" +msgstr "&Tip zaslona VGA" + +msgid "RGB &Color" +msgstr "RGB u &boji" + +msgid "&RGB Grayscale" +msgstr "&RGB u nijansama sive boje" + +msgid "&Amber monitor" +msgstr "&Jantarni zaslon" + +msgid "&Green monitor" +msgstr "&Zeleni zaslon" + +msgid "&White monitor" +msgstr "&Bijeli zaslon" + +msgid "Grayscale &conversion type" +msgstr "&Vrsta konverzije nijansa sive boje" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Prosjek" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "&Višak slike CGA/PCjr/Tandy/EGA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "&Promjeni kontrast za crno-bijeli zaslon" + +msgid "&Media" +msgstr "&Mediji" + +msgid "&Tools" +msgstr "&Alati" + +msgid "&Settings..." +msgstr "&Opcije..." + +msgid "&Update status bar icons" +msgstr "&Ažuriraj ikone statusnog redka" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Napravi &snimku zaslona\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Postavke..." + +msgid "Enable &Discord integration" +msgstr "Omogući integraciju sa programom &Discord" + +msgid "Sound &gain..." +msgstr "&Pojačanje zvuka..." + +msgid "Begin trace\tCtrl+T" +msgstr "Z&apočni praćenje\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "&Svrši praćenje\tCtrl+T" + +msgid "&Help" +msgstr "&Pomoć" + +msgid "&Documentation..." +msgstr "&Dokumentacija..." + +msgid "&About 86Box..." +msgstr "&O programu 86Box..." + +msgid "&New image..." +msgstr "&Nova slika..." + +msgid "&Existing image..." +msgstr "&Postojeća slika..." + +msgid "Existing image (&Write-protected)..." +msgstr "Postojeća slika (&zaštićena od pisanja)..." + +msgid "&Record" +msgstr "&Snimi" + +msgid "&Play" +msgstr "&Pokreni" + +msgid "&Rewind to the beginning" +msgstr "P&remotaj na početak" + +msgid "&Fast forward to the end" +msgstr "&Preskoči do kraja" + +msgid "E&ject" +msgstr "&Izbaci" + +msgid "&Image..." +msgstr "&Slika..." + +msgid "E&xport to 86F..." +msgstr "&Izvozi u 86F..." + +msgid "&Mute" +msgstr "&Isključi zvuk" + +msgid "E&mpty" +msgstr "&Prazno" + +msgid "&Reload previous image" +msgstr "&Ponovo učitaj prethodnu sliku" + +msgid "&Image" +msgstr "&Slika" + +msgid "Target &framerate" +msgstr "&Ciljni broj okvira u sekundi" + +msgid "&Sync with video" +msgstr "&Sinkroniziraj s videom" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Odaberi shader..." + +msgid "&Remove shader" +msgstr "&Ukloni shader" + +msgid "Preferences" +msgstr "Postavke" + +msgid "Sound Gain" +msgstr "Pojačavanje zvuka" + +msgid "New Image" +msgstr "Nova slika" + +msgid "Settings" +msgstr "Opcije" + +msgid "Specify Main Window Dimensions" +msgstr "Odredite glavne dimenzije prozora" + +msgid "OK" +msgstr "U redu" + +msgid "Cancel" +msgstr "Otkaži" + +msgid "Save these settings as &global defaults" +msgstr "Spremite ove postavke kao &globalne zadane postavke" + +msgid "&Default" +msgstr "Zadano" + +msgid "Language:" +msgstr "Jezik:" + +msgid "Icon set:" +msgstr "Paket ikona:" + +msgid "Gain" +msgstr "Pojačavanje" + +msgid "File name:" +msgstr "Ime datoteke:" + +msgid "Disk size:" +msgstr "Veličina diska:" + +msgid "RPM mode:" +msgstr "Način broja okretaja:" + +msgid "Progress:" +msgstr "Napredak:" + +msgid "Width:" +msgstr "Širina:" + +msgid "Height:" +msgstr "Visina:" + +msgid "Lock to this size" +msgstr "Zaključajte na ovu veličinu" + +msgid "Machine type:" +msgstr "Tip sistema:" + +msgid "Machine:" +msgstr "Sistem:" + +msgid "Configure" +msgstr "Namjesti" + +msgid "CPU type:" +msgstr "Tip procesora:" + +msgid "Speed:" +msgstr "Brzina:" + +msgid "FPU:" +msgstr "FPU uređaj:" + +msgid "Wait states:" +msgstr "Stanja čekanja:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memorija:" + +msgid "Time synchronization" +msgstr "Sinkronizacija vremena" + +msgid "Disabled" +msgstr "Isključeno" + +msgid "Enabled (local time)" +msgstr "Uključeno (lokalno vrijeme)" + +msgid "Enabled (UTC)" +msgstr "Uključeno (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dinamički rekompilator" + +msgid "Video:" +msgstr "Video:" + +msgid "Voodoo Graphics" +msgstr "Voodoo grafika" + +msgid "Mouse:" +msgstr "Miš:" + +msgid "Joystick:" +msgstr "Palica za igru:" + +msgid "Joystick 1..." +msgstr "Palica za igru 1..." + +msgid "Joystick 2..." +msgstr "Palica za igru 2..." + +msgid "Joystick 3..." +msgstr "Palica za igru 3..." + +msgid "Joystick 4..." +msgstr "Palica za igru 4..." + +msgid "Sound card:" +msgstr "Zvučna kartica:" + +msgid "MIDI Out Device:" +msgstr "Izlazni uređaj MIDI:" + +msgid "MIDI In Device:" +msgstr "Ulazni uređaj MIDI:" + +msgid "Standalone MPU-401" +msgstr "Samostalni MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Koristi FLOAT32 za zvuk" + +msgid "Network type:" +msgstr "Tip mreže:" + +msgid "PCap device:" +msgstr "Uređaj PCap:" + +msgid "Network adapter:" +msgstr "Mrežna kartica:" + +msgid "COM1 Device:" +msgstr "Uređaj COM1:" + +msgid "COM2 Device:" +msgstr "Uređaj COM2:" + +msgid "COM3 Device:" +msgstr "Uređaj COM3:" + +msgid "COM4 Device:" +msgstr "Uređaj COM4:" + +msgid "LPT1 Device:" +msgstr "Uređaj LPT1:" + +msgid "LPT2 Device:" +msgstr "Uređaj LPT2:" + +msgid "LPT3 Device:" +msgstr "Uređaj LPT3:" + +msgid "LPT4 Device:" +msgstr "Uređaj LPT4:" + +msgid "Serial port 1" +msgstr "Serijska vrata 1" + +msgid "Serial port 2" +msgstr "Serijska vrata 2" + +msgid "Serial port 3" +msgstr "Serijska vrata 3" + +msgid "Serial port 4" +msgstr "Serijska vrata 4" + +msgid "Parallel port 1" +msgstr "Paralelna vrata 1" + +msgid "Parallel port 2" +msgstr "Paralelna vrata 2" + +msgid "Parallel port 3" +msgstr "Paralelna vrata 3" + +msgid "Parallel port 4" +msgstr "Paralelna vrata 4" + +msgid "HD Controller:" +msgstr "Kontroler tvrdog diska:" + +msgid "FD Controller:" +msgstr "Kontroler diskete:" + +msgid "Tertiary IDE Controller" +msgstr "Tercijarni IDE kontroler" + +msgid "Quaternary IDE Controller" +msgstr "Kvaternarni IDE kontroler" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Kontroler 1:" + +msgid "Controller 2:" +msgstr "Kontroler 2:" + +msgid "Controller 3:" +msgstr "Kontroler 3:" + +msgid "Controller 4:" +msgstr "Kontroler 4:" + +msgid "Cassette" +msgstr "Audio kaseta" + +msgid "Hard disks:" +msgstr "Tvrdi diskovi:" + +msgid "&New..." +msgstr "&Novi..." + +msgid "&Existing..." +msgstr "&Postojeći..." + +msgid "&Remove" +msgstr "&Ukloni" + +msgid "Bus:" +msgstr "Sabirnica:" + +msgid "Channel:" +msgstr "Kanal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Odredi..." + +msgid "Sectors:" +msgstr "Sektori:" + +msgid "Heads:" +msgstr "Glave:" + +msgid "Cylinders:" +msgstr "Cilindri:" + +msgid "Size (MB):" +msgstr "Veličina (MB):" + +msgid "Type:" +msgstr "Tip:" + +msgid "Image Format:" +msgstr "Format slike:" + +msgid "Block Size:" +msgstr "Veličina slike:" + +msgid "Floppy drives:" +msgstr "Disketni pogoni:" + +msgid "Turbo timings" +msgstr "Turbo vrijemena" + +msgid "Check BPB" +msgstr "Provjeraj BPB" + +msgid "CD-ROM drives:" +msgstr "CD-ROM pogoni:" + +msgid "MO drives:" +msgstr "MO pogoni:" + +msgid "ZIP drives:" +msgstr "ZIP pogoni:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "Sat stvarnog vremena (RTC):" + +msgid "ISA Memory Expansion" +msgstr "Proširenje memorije ISA" + +msgid "Card 1:" +msgstr "Kartica 1:" + +msgid "Card 2:" +msgstr "Kartica 2:" + +msgid "Card 3:" +msgstr "Kartica 3:" + +msgid "Card 4:" +msgstr "Kartica 4:" + +msgid "ISABugger device" +msgstr "Uređaj ISABugger" + +msgid "POST card" +msgstr "Kartica POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Greška" + +msgid "Fatal error" +msgstr "Fatalna greška" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Pritisnite Ctrl+Alt+PgDn za povratak u prozorski način rada." + +msgid "Speed" +msgstr "Brzina" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP slike" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box nije mogao pronaći upotrebljive ROM datoteke.\n\nMolimte posjetite sknite paket s ROM datotekama i ekstrahirajte paket u \"roms\" mapu." + +msgid "(empty)" +msgstr "(prazno)" + +msgid "All files" +msgstr "Sve datoteke" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Uključeno" + +msgid "Off" +msgstr "Isključeno" + +msgid "All images" +msgstr "Sve slike" + +msgid "Basic sector images" +msgstr "BOsnovne sektorske slike" + +msgid "Surface images" +msgstr "Površinske slike" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Sistem \"%hs\" nije dostupan jer ne postoje potrebni ROM-ovi u mapu roms/machines. Prebacivanje na dostupno računalo." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Video kartica \"%hs\" nije dostupna jer ne postoje potrebni ROM-ovi u mapu roms/video. Prebacivanje na dostupnu video karticu." + +msgid "Machine" +msgstr "Sistem" + +msgid "Display" +msgstr "Video" + +msgid "Input devices" +msgstr "Ulazni uređaji" + +msgid "Sound" +msgstr "Zvuk" + +msgid "Network" +msgstr "Mreža" + +msgid "Ports (COM & LPT)" +msgstr "Vrata (COM & LPT)" + +msgid "Storage controllers" +msgstr "Kontroleri za diskove" + +msgid "Hard disks" +msgstr "Tvrdi diskovi" + +msgid "Floppy & CD-ROM drives" +msgstr "Floppy & CD-ROM pogoni" + +msgid "Other removable devices" +msgstr "Ostali uklonjivi uređaji" + +msgid "Other peripherals" +msgstr "Ostali periferni uređaji" + +msgid "Click to capture mouse" +msgstr "Kliknite da uhvatite miš" + +msgid "Press F8+F12 to release mouse" +msgstr "Pritisnite F8+F12 za otpustanje miša" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Pritisnite F8+F12 ili srednji gumb miša za otpuštanje miša" + +msgid "Unable to initialize FluidSynth" +msgstr "Nije moguće inicijalizirati FluidSynth" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "Datoteka" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Nije moguće inicijalizirati renderer." + +msgid "Default" +msgstr "Standard" + +msgid "%i Wait state(s)" +msgstr "%i stanje čekanja" + +msgid "Type" +msgstr "Tip" + +msgid "Failed to set up PCap" +msgstr "Postavljanje PCap-a nije uspjelo" + +msgid "No PCap devices found" +msgstr "Nema PCap uređaja" + +msgid "Invalid PCap device" +msgstr "Nevažeći PCap uređaj" + +msgid "Standard 2-button joystick(s)" +msgstr "Standardna palica za igru s 2 tipke" + +msgid "Standard 4-button joystick" +msgstr "Standardna palica za igru s 4 tipke" + +msgid "Standard 6-button joystick" +msgstr "Standardna palica za igru s 6 tipke" + +msgid "Standard 8-button joystick" +msgstr "Standardna palica za igru s 8 tipke" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Bez" + +msgid "Unable to load keyboard accelerators." +msgstr "Nije moguće učitati ubrzivače tipkovnice." + +msgid "Unable to register raw input." +msgstr "Nije moguće registrirati neobrađeni unos." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disketa %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Napredne sektorske slike" + +msgid "Flux images" +msgstr "Flux slike" + +msgid "Unable to initialize FreeType" +msgstr "Nije moguće inicijalizirati FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Nije moguće inicijalizirati SDL, SDL2.dll je potrebno" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Jeste li sigurni da želite hard resetirati emulirani sistem?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Jeste li sigurni da želite zatvoriti 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Nije moguće inicijalizirati GhostScript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO slike" + +msgid "Welcome to 86Box!" +msgstr "Dobrodošli u 86Box!" + +msgid "Internal controller" +msgstr "Uunutarnji kontroler" + +msgid "Exit" +msgstr "Izlazi" + +msgid "No ROMs found" +msgstr "Nisu pronađene ROM datoteke" + +msgid "Do you want to save the settings?" +msgstr "Želite li spremiti postavke?" + +msgid "This will hard reset the emulated machine." +msgstr "Ovo će napraviti hard resetiranje emuliranog sistema." + +msgid "Save" +msgstr "Spremaj" + +msgid "About 86Box" +msgstr "O programu 86Box" + +msgid "86Box v" +msgstr "86Box verzija " + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Emulator starih računala\n\nAutori: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, i drugi.\n\nPreveo: dob205\n\nObjavljeno pod licencom GNU General Public License, verzija 2 ili novije. Za više informacija pogledajte datoteku LICENCE." + +msgid "Hardware not available" +msgstr "Hardver nije dostupan" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Provjerite je li libpcap instaliran i jeste li na mreži, kompadibilnoj s libpcap." + +msgid "Invalid configuration" +msgstr "Nevažeća konfiguracija" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " je potrebno za emuliranje ESC/P pisača." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " je potrebno za automatsku konverziju PostScript datoteke u PDF datoteke.\n\nSvi dokumenti poslani na generički PostScript pisač bit će spremljeni kao PostScript (.ps) datoteke." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " je potrebno za FluidSynth MIDI izlaz." + +msgid "Entering fullscreen mode" +msgstr "Ulazim u cijelozaslonski način" + +msgid "Don't show this message again" +msgstr "Ne pokazi više ovu poruku" + +msgid "Don't exit" +msgstr "Ne izlazi" + +msgid "Reset" +msgstr "Resetiraj" + +msgid "Don't reset" +msgstr "Ne resetiraj" + +msgid "CD-ROM images" +msgstr "CD-ROM slike" + +msgid "%hs Device Configuration" +msgstr "Konfiguracija uređaja %hs " + +msgid "Monitor in sleep mode" +msgstr "Ekran u stanju mirovanja" + +msgid "OpenGL Shaders" +msgstr "OpenGL shaderi" + +msgid "OpenGL options" +msgstr "OpenGL opcije" + +msgid "You are loading an unsupported configuration" +msgstr "Učitavate nepodržanu konfiguraciju" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Filtriranje tipa CPU-a na temelju odabranog sistema onemogućeno je za ovaj emulirani sistem.\n\nOvo omogućuje odabir procesora koji inače nisu kompatibilne s odabranog sistem. Međutim, možete naići na na nekompatibilnosti s BIOS-om sustava ili drugim softverom.\n\nOmogućavanje ove postavke nije službeno podržano i sva prijava o greškama mogu biti zatvorena kao \"invalid\"." + +msgid "Continue" +msgstr "Nastavi" + +msgid "Cassette: %s" +msgstr "Audio kaseta: %s" + +msgid "Cassette images" +msgstr "Slike audio kasete" + +msgid "Cartridge %i: %ls" +msgstr "Kaseta %i: %ls" + +msgid "Cartridge images" +msgstr "Slike kasete" + +msgid "Error initializing renderer" +msgstr "Nije moguće inicijalizirati renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "Nije moguće inicijalizirati OpenGL (3.0 jezgra) renderer. Molimte koristite drugi renderer." + +msgid "Resume execution" +msgstr "Nastavi" + +msgid "Pause execution" +msgstr "Pauziraj" + +msgid "Press Ctrl+Alt+Del" +msgstr "Stisni Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Stisni Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Ponovno pokretanje" + +msgid "ACPI shutdown" +msgstr "ACPI bazirano gašenje" + +msgid "Hard disk (%s)" +msgstr "Tvrdi disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL ili ESDI CD-ROM pogoni nisu nikada postojali" + +msgid "Custom..." +msgstr "Prilagođeno..." + +msgid "Custom (large)..." +msgstr "Prilagođeno (veliko)..." + +msgid "Add New Hard Disk" +msgstr "Dodajte novi tvrdi disk" + +msgid "Add Existing Hard Disk" +msgstr "Dodajte postojeći tvrdi disk" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI disk image datoteke ne mogu biti veće od 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Slike tvrdog diska ne mogu biti veće od 127 GB." + +msgid "Hard disk images" +msgstr "Slike za tvrde diskove" + +msgid "Unable to read file" +msgstr "Nije moguće pročitati datoteku" + +msgid "Unable to write file" +msgstr "Nije moguće napisati datoteku" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "HDI ili HDX slike s veličinom sektora koja nije 512 kB nisu podržane." + +msgid "USB is not yet supported" +msgstr "USB nije još podržano" + +msgid "Disk image file already exists" +msgstr "Slika diska već postoji" + +msgid "Please specify a valid file name." +msgstr "Molimte unesite važeći naziv datoteke." + +msgid "Disk image created" +msgstr "Slika je stvorena" + +msgid "Make sure the file exists and is readable." +msgstr "Provjerite je li postoji datoteka i je li čitljiva." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Provjerite je li se datoteka sprema u mapu s dopuštenjima za pisanje." + +msgid "Disk image too large" +msgstr "Slika diska je prevelika" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Ne zaboravite stvoriti particije i formatirati ih na novom disku." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Odabrana datoteka bit će prebrisana. Jeste li sigurni da želite koristiti ovu daoteku?" + +msgid "Unsupported disk image" +msgstr "Nepodržana slika diska" + +msgid "Overwrite" +msgstr "Prepiši" + +msgid "Don't overwrite" +msgstr "Ne prepiši" + +msgid "Raw image (.img)" +msgstr "Slika neobrađenih podataka (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI slika (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX slika (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD fiksne veličine (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD dinamičke veličine (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Različiti VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Veliki blokovi (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Mali blokovi (512 KB)" + +msgid "VHD files" +msgstr "VHD slike" + +msgid "Select the parent VHD" +msgstr "Izaberi matičnu sliku VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "To bi moglo značiti da je matična slika promijenjena nakon što je stvorena različita slika.\n\nTo se također može dogoditi ako su slike premještene ili kopirane, ili greška u programu koji je stvorio ovaj disk.\n\nŽelite li popraviti vremenske oznake?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Vremenske ozanke matične i poređenog diska ne odgovaraju." + +msgid "Could not fix VHD timestamp." +msgstr "Ne mogu popraviti vremensku oznaku slike VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1,2 MB" + +msgid "1.25 MB" +msgstr "1,25 MB" + +msgid "1.44 MB" +msgstr "1,44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (1024 clusteri)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (2048 clusteri)" + +msgid "2.88 MB" +msgstr "2,88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3,5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3,5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3,5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3,5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3,5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3,5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5,25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5,25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5,25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5,25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Savršeni broj okretaja u minuti" + +msgid "1% below perfect RPM" +msgstr "1% ispod savršenog broja okretaja" + +msgid "1.5% below perfect RPM" +msgstr "1,5% ispod savršenog broja okretaja" + +msgid "2% below perfect RPM" +msgstr "2% ispod savršenog broja okretaja" + +msgid "(System Default)" +msgstr "(Zadana postavka operativnog sustava)" + diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po new file mode 100644 index 000000000..716ad22fc --- /dev/null +++ b/src/qt/languages/hu-HU.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Művelet" + +msgid "&Keyboard requires capture" +msgstr "A &billentyűzet elfogást igényel" + +msgid "&Right CTRL is left ALT" +msgstr "A &jobb oldali CTRL a bal ALT" + +msgid "&Hard Reset..." +msgstr "Hardveres &újraindítás..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Szüneteltetés" + +msgid "E&xit..." +msgstr "&Kilépés..." + +msgid "&View" +msgstr "&Nézet" + +msgid "&Hide status bar" +msgstr "Állapotsor &elrejtése" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Átméretezhető ablak" + +msgid "R&emember size && position" +msgstr "Méret és pozíció &megjegyzése" + +msgid "Re&nderer" +msgstr "&Megjelenítő" + +msgid "&SDL (Software)" +msgstr "&SDL (Szoftveres)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardveres)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Méretek kézi megadása..." + +msgid "F&orce 4:3 display ratio" +msgstr "&Rögzített 4:3 képarány" + +msgid "&Window scale factor" +msgstr "&Ablak méretezési tényező" + +msgid "&0.5x" +msgstr "&0,5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1,&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Szűrési mód" + +msgid "&Nearest" +msgstr "&Szomszédos" + +msgid "&Linear" +msgstr "&Lineáris" + +msgid "Hi&DPI scaling" +msgstr "Hi&DPI méretezés" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Teljes képernyő\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Teljes képernyős &méretezés" + +msgid "&Full screen stretch" +msgstr "&Nyújtás a teljes képernyőre" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Négyzetes képpontok (aránytartás)" + +msgid "&Integer scale" +msgstr "&Egész tényezős nagyítás" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA beállítások" + +msgid "&Inverted VGA monitor" +msgstr "&Invertált VGA kijelző" + +msgid "VGA screen &type" +msgstr "VGA képernyő &típusa" + +msgid "RGB &Color" +msgstr "RGB &színes" + +msgid "&RGB Grayscale" +msgstr "&RGB szürkeárnyalatos" + +msgid "&Amber monitor" +msgstr "&Gyömbér kijelző" + +msgid "&Green monitor" +msgstr "&Zöld kijelző" + +msgid "&White monitor" +msgstr "&Fehér kijelző" + +msgid "Grayscale &conversion type" +msgstr "Szürkéskála &konzerziós eljárás" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Átlag szerint" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA túlpásztázás" + +msgid "Change contrast for &monochrome display" +msgstr "Kontraszt illesztése &monokróm kijelzőhöz" + +msgid "&Media" +msgstr "&Média" + +msgid "&Tools" +msgstr "&Eszközök" + +msgid "&Settings..." +msgstr "&Konfigurálás..." + +msgid "&Update status bar icons" +msgstr "Állapotsori ikonok &frissítése" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "&Képernyőkép készítése\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Beállítások..." + +msgid "Enable &Discord integration" +msgstr "&Discord integráció engedélyezése" + +msgid "Sound &gain..." +msgstr "&Hangerőszabályzó..." + +msgid "Begin trace\tCtrl+T" +msgstr "Nyomkövetés megkezdése\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Nyomkövetés befejezése\tCtrl+T" + +msgid "&Help" +msgstr "&Súgó" + +msgid "&Documentation..." +msgstr "&Dokumentáció..." + +msgid "&About 86Box..." +msgstr "A 86Box &névjegye..." + +msgid "&New image..." +msgstr "&Új képfájl létrehozása..." + +msgid "&Existing image..." +msgstr "Meglévő képfájl &megnyitása..." + +msgid "Existing image (&Write-protected)..." +msgstr "Meglévő képfájl megnyitása (&írásvédett)..." + +msgid "&Record" +msgstr "&Felvétel" + +msgid "&Play" +msgstr "&Lejátszás" + +msgid "&Rewind to the beginning" +msgstr "&Visszatekerés az elejére" + +msgid "&Fast forward to the end" +msgstr "&Előretekerés a végére" + +msgid "E&ject" +msgstr "&Kiadás" + +msgid "&Image..." +msgstr "Kép&fájl..." + +msgid "E&xport to 86F..." +msgstr "E&xportálás 86F formátumba..." + +msgid "&Mute" +msgstr "&Némítás" + +msgid "E&mpty" +msgstr "&Kiadás" + +msgid "&Reload previous image" +msgstr "Előző képfájl &újratöltése" + +msgid "&Image" +msgstr "&Meglévő képfájl &megnyitása..." + +msgid "Target &framerate" +msgstr "Cél &képkockasebesség" + +msgid "&Sync with video" +msgstr "&Szinkronizálás a videóval " + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "Shader &kiválasztása..." + +msgid "&Remove shader" +msgstr "Shader &eltávolítása" + +msgid "Preferences" +msgstr "Beállítások" + +msgid "Sound Gain" +msgstr "Hangerőszabályzó" + +msgid "New Image" +msgstr "Új képfájl létrehozása" + +msgid "Settings" +msgstr "Konfigurálás" + +msgid "Specify Main Window Dimensions" +msgstr "Főablak méreteinek megadása" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Mégse" + +msgid "Save these settings as &global defaults" +msgstr "Beállítások mentése &globális alapértékként" + +msgid "&Default" +msgstr "&Alapértelmezett" + +msgid "Language:" +msgstr "Nyelv:" + +msgid "Icon set:" +msgstr "Ikonkészlet:" + +msgid "Gain" +msgstr "Hangerő" + +msgid "File name:" +msgstr "Fájlnév:" + +msgid "Disk size:" +msgstr "Méret:" + +msgid "RPM mode:" +msgstr "RPM-mód:" + +msgid "Progress:" +msgstr "Folyamat:" + +msgid "Width:" +msgstr "Szélesség:" + +msgid "Height:" +msgstr "Magasság:" + +msgid "Lock to this size" +msgstr "Rögzítés a megadott méretre" + +msgid "Machine type:" +msgstr "Géptípus:" + +msgid "Machine:" +msgstr "Számítógép:" + +msgid "Configure" +msgstr "Beállítások..." + +msgid "CPU type:" +msgstr "Processzor:" + +msgid "Speed:" +msgstr "Seb.:" + +msgid "FPU:" +msgstr "FPU-egység:" + +msgid "Wait states:" +msgstr "Várak. ciklusok:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memória:" + +msgid "Time synchronization" +msgstr "Idő szinkronizáció" + +msgid "Disabled" +msgstr "Letiltva" + +msgid "Enabled (local time)" +msgstr "Engedélyezve (helyi idő)" + +msgid "Enabled (UTC)" +msgstr "Engedélyezve (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dinamikus újrafordítás" + +msgid "Video:" +msgstr "Videokártya:" + +msgid "Voodoo Graphics" +msgstr "Voodoo-gyorsítókártya" + +msgid "Mouse:" +msgstr "Egér:" + +msgid "Joystick:" +msgstr "Játékvezérlő:" + +msgid "Joystick 1..." +msgstr "Játékvez. 1..." + +msgid "Joystick 2..." +msgstr "Játékvez. 2..." + +msgid "Joystick 3..." +msgstr "Játékvez. 3..." + +msgid "Joystick 4..." +msgstr "Játékvez. 4..." + +msgid "Sound card:" +msgstr "Hangkártya:" + +msgid "MIDI Out Device:" +msgstr "MIDI-kimenet:" + +msgid "MIDI In Device:" +msgstr "MIDI-bemenet:" + +msgid "Standalone MPU-401" +msgstr "Különálló MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32 használata" + +msgid "Network type:" +msgstr "Hálózati típusa:" + +msgid "PCap device:" +msgstr "PCap eszköz:" + +msgid "Network adapter:" +msgstr "Hálózati kártya:" + +msgid "COM1 Device:" +msgstr "COM1 eszköz:" + +msgid "COM2 Device:" +msgstr "COM2 eszköz:" + +msgid "COM3 Device:" +msgstr "COM3 eszköz:" + +msgid "COM4 Device:" +msgstr "COM4 eszköz:" + +msgid "LPT1 Device:" +msgstr "LPT1 eszköz:" + +msgid "LPT2 Device:" +msgstr "LPT2 eszköz:" + +msgid "LPT3 Device:" +msgstr "LPT3 eszköz:" + +msgid "LPT4 Device:" +msgstr "LPT4 eszköz:" + +msgid "Serial port 1" +msgstr "Soros port 1" + +msgid "Serial port 2" +msgstr "Soros port 2" + +msgid "Serial port 3" +msgstr "Soros port 3" + +msgid "Serial port 4" +msgstr "Soros port 4" + +msgid "Parallel port 1" +msgstr "Párhuzamos port 1" + +msgid "Parallel port 2" +msgstr "Párhuzamos port 2" + +msgid "Parallel port 3" +msgstr "Párhuzamos port 3" + +msgid "Parallel port 4" +msgstr "Párhuzamos port 4" + +msgid "HD Controller:" +msgstr "Merevl.-vezérlő:" + +msgid "FD Controller:" +msgstr "Floppy-vezérlő:" + +msgid "Tertiary IDE Controller" +msgstr "Harmadlagos IDE-vezérlő" + +msgid "Quaternary IDE Controller" +msgstr "Negyedleges IDE-vezérlő" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Gazdaadapt. 1:" + +msgid "Controller 2:" +msgstr "Gazdaadapt. 2:" + +msgid "Controller 3:" +msgstr "Gazdaadapt. 3:" + +msgid "Controller 4:" +msgstr "Gazdaadapt. 4:" + +msgid "Cassette" +msgstr "Magnókazetta" + +msgid "Hard disks:" +msgstr "Merevlemezek:" + +msgid "&New..." +msgstr "&Új..." + +msgid "&Existing..." +msgstr "&Megnyitás..." + +msgid "&Remove" +msgstr "&Eltávolítás" + +msgid "Bus:" +msgstr "Busz:" + +msgid "Channel:" +msgstr "Csatorna:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Kiválasztás..." + +msgid "Sectors:" +msgstr "Szektor:" + +msgid "Heads:" +msgstr "Fej:" + +msgid "Cylinders:" +msgstr "Cilinder:" + +msgid "Size (MB):" +msgstr "Méret (MB):" + +msgid "Type:" +msgstr "Típus:" + +msgid "Image Format:" +msgstr "Formátum:" + +msgid "Block Size:" +msgstr "Blokkméret:" + +msgid "Floppy drives:" +msgstr "Floppy-meghajtók:" + +msgid "Turbo timings" +msgstr "Turbó időzítés" + +msgid "Check BPB" +msgstr "BPB ellenőrzés" + +msgid "CD-ROM drives:" +msgstr "CD-ROM meghajtók:" + +msgid "MO drives:" +msgstr "MO-meghajtók:" + +msgid "ZIP drives:" +msgstr "ZIP-meghajtók:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC (óra):" + +msgid "ISA Memory Expansion" +msgstr "ISA memóriabővítők" + +msgid "Card 1:" +msgstr "Kártya 1:" + +msgid "Card 2:" +msgstr "Kártya 2:" + +msgid "Card 3:" +msgstr "Kártya 3:" + +msgid "Card 4:" +msgstr "Kártya 4:" + +msgid "ISABugger device" +msgstr "ISABugger eszköz" + +msgid "POST card" +msgstr "POST kártya" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Hiba" + +msgid "Fatal error" +msgstr "Végzetes hiba" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Használja a Ctrl+Alt+PgDn gombokat az ablakhoz való visszatéréshez." + +msgid "Speed" +msgstr "Sebesség" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP-lemezképek" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "A 86Box nem talált használható ROM-képeket\n\nKérem töltse le a ROM készletet és bontsa ki a \"roms\" könyvtárba." + +msgid "(empty)" +msgstr "(üres)" + +msgid "All files" +msgstr "Minden fájl" + +msgid "Turbo" +msgstr "Turbó" + +msgid "On" +msgstr "Bekapcsolva" + +msgid "Off" +msgstr "Kikapcsolva" + +msgid "All images" +msgstr "Minden képfájl" + +msgid "Basic sector images" +msgstr "Alapvető szektor képfájlok" + +msgid "Surface images" +msgstr "Felületi képfájlok" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "A számítógép \"%hs\" nem elérhető a \"roms/machines\" mappából hiányzó ROM-képek miatt. Ehelyett egy másik gép kerül futtatásra." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "A videokártya \"%hs\" nem elérhető a \"roms/video\" mappából hiányzó ROM-képek miatt. Ehelyett egy másik kártya kerül futtatásra." + +msgid "Machine" +msgstr "Számítógép" + +msgid "Display" +msgstr "Megjelenítő" + +msgid "Input devices" +msgstr "Beviteli eszközök" + +msgid "Sound" +msgstr "Hang" + +msgid "Network" +msgstr "Hálózat" + +msgid "Ports (COM & LPT)" +msgstr "Portok (COM és LPT)" + +msgid "Storage controllers" +msgstr "Tárolóvezérlők" + +msgid "Hard disks" +msgstr "Merevlemezek" + +msgid "Floppy & CD-ROM drives" +msgstr "Floppy és CD-ROM meghajtók" + +msgid "Other removable devices" +msgstr "Egyéb cserélhető tárolók" + +msgid "Other peripherals" +msgstr "Egyéb perifériák" + +msgid "Click to capture mouse" +msgstr "Kattintson az egér elfogásához" + +msgid "Press F8+F12 to release mouse" +msgstr "Nyomja meg az F8+F12-t az egér elengédéséhez" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Nyomja meg az F8+F12-t vagy a középső gombot az egér elengédéséhez" + +msgid "Unable to initialize FluidSynth" +msgstr "Nem sikerült a FluidSynth inicializálása" + +msgid "Bus" +msgstr "Busz" + +msgid "File" +msgstr "Fájl" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Nem sikerült inicializálni a videó megjelenítőt." + +msgid "Default" +msgstr "Alapértelmezett" + +msgid "%i Wait state(s)" +msgstr "%i várakozási ciklus(ok)" + +msgid "Type" +msgstr "Típus" + +msgid "Failed to set up PCap" +msgstr "Nem sikerült a PCap beállítása" + +msgid "No PCap devices found" +msgstr "Nem találhatóak PCap eszközök" + +msgid "Invalid PCap device" +msgstr "Érvénytelen PCap eszköz" + +msgid "Standard 2-button joystick(s)" +msgstr "Szabványos 2-gombos játékvezérlő(k)" + +msgid "Standard 4-button joystick" +msgstr "Szabványos 4-gombos játékvezérlő" + +msgid "Standard 6-button joystick" +msgstr "Szabványos 6-gombos játékvezérlő" + +msgid "Standard 8-button joystick" +msgstr "Szabványos 8-gombos játékvezérlő" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Nincs" + +msgid "Unable to load keyboard accelerators." +msgstr "Nem lehet betölteni a billentyűzetgyorsítókat." + +msgid "Unable to register raw input." +msgstr "A közvetlen nyers bevitel regisztrálása nem sikerült." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Floppy %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Továbbfejlesztett szektor képek" + +msgid "Flux images" +msgstr "Flux képekfájlok" + +msgid "Unable to initialize FreeType" +msgstr "A FreeType inicializálása nem lehetséges" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Az SDL inicializálása nem lehetséges, az SDL2.dll fájl szükséges" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Biztosan szeretné újraindítani az emulált gépet?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Biztos benne, hogy ki szeretne lépni a 86Box-ból?" + +msgid "Unable to initialize Ghostscript" +msgstr "Nem sikerült inicializálni a Ghostscript-et" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO-képfájlok" + +msgid "Welcome to 86Box!" +msgstr "Üdvözli önt az 86Box!" + +msgid "Internal controller" +msgstr "Integrált vezérlő" + +msgid "Exit" +msgstr "Kilépés" + +msgid "No ROMs found" +msgstr "Nem találhatóak meg a ROM-képek" + +msgid "Do you want to save the settings?" +msgstr "Szeretné menteni a beállításokat?" + +msgid "This will hard reset the emulated machine." +msgstr "Ezzel hardveresen újraindítja az emulált gépet." + +msgid "Save" +msgstr "Mentés" + +msgid "About 86Box" +msgstr "A 86Box névjegye" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Régi számítógépek emulátora\n\nFejlesztők: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nFordította: Laci bá'\n\nMegjelent a GNU General Public License v2 vagy újabb alatt. További információért lásd a LICENSE fájlt." + +msgid "Hardware not available" +msgstr "Hardver nem elérhető" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Győződjön meg hogy a(z) libpcap telepítve van és jelenleg a libpcap-kompatibilis kapcsolatot használja." + +msgid "Invalid configuration" +msgstr "Érvénytelen konfiguráció" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " szükséges az ESC/P nyomtató emulációhoz." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " szükséges a PostScript fájlok PDF formátumba való automatikus konvertálásához.\n\nAz általános PostScript nyomtatóra küldött dokumentumok PostScript (.ps) fájlként kerülnek mentésre." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " szükséges a FluidSynth MIDI kimenethez." + +msgid "Entering fullscreen mode" +msgstr "Teljes képernyős módra váltás" + +msgid "Don't show this message again" +msgstr "Ne jelenítse meg újra ezt az üzenetet " + +msgid "Don't exit" +msgstr "Ne lépjen ki" + +msgid "Reset" +msgstr "Újraindítás" + +msgid "Don't reset" +msgstr "Ne indítsa újra" + +msgid "CD-ROM images" +msgstr "CD-ROM-képek" + +msgid "%hs Device Configuration" +msgstr "%hs eszközkonfiguráció" + +msgid "Monitor in sleep mode" +msgstr "Képernyő alvó módban" + +msgid "OpenGL Shaders" +msgstr "OpenGL Shaderek" + +msgid "OpenGL options" +msgstr "OpenGL beállítások" + +msgid "You are loading an unsupported configuration" +msgstr "Egy nem támogatott konfigurációt tölt be" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "A kiválasztott gépen alapuló CPU-típusszűrés le van tiltva ezen az emulált gépen.\n\nEz lehetővé teszi olyan CPU kiválasztását, amely egyébként nem kompatibilis a kiválasztott géppel. Előfordulhat azonban, hogy nem kompatibilis a gép BIOS-ával vagy más szoftverekkel.\n\nA beállítás engedélyezése hivatalosan nem támogatott, és a benyújtott hibajelentéseket érvénytelenként lezárhatjuk." + +msgid "Continue" +msgstr "Folytatás" + +msgid "Cassette: %s" +msgstr "Magnókazetta: %s" + +msgid "Cassette images" +msgstr "Magnókazetta-képek" + +msgid "Cartridge %i: %ls" +msgstr "ROM-kazetta %i: %ls" + +msgid "Cartridge images" +msgstr "ROM-kazetta képek" + +msgid "Error initializing renderer" +msgstr "Hiba történt a renderelő inicializálásakor" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "Az OpenGL (3.0 Core) megjelenítő-motort nem sikerült inicializálni. Kérem használjon másik renderelőt." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Merevlemez (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL vagy ESDI CD-ROM meghajtók soha nem léteztek" + +msgid "Custom..." +msgstr "Egyéni..." + +msgid "Custom (large)..." +msgstr "Egyéni (nagy)..." + +msgid "Add New Hard Disk" +msgstr "Új merevlemez hozzáadása" + +msgid "Add Existing Hard Disk" +msgstr "Meglévő merevlemez hozzáadása" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "A HDI lemezképek nem lehetnek nagyobbak 4 GB-nál." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "A lemezképek mérete nem haladhatja meg a 127 GB-ot." + +msgid "Hard disk images" +msgstr "Merevlemez-képfájlok" + +msgid "Unable to read file" +msgstr "A fájl nem olvasható" + +msgid "Unable to write file" +msgstr "A fájl nem írható" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Az 512-től eltérő szektorméretű HDI vagy HDX képek nem támogatottak." + +msgid "USB is not yet supported" +msgstr "Az USB még nem támogatott" + +msgid "Disk image file already exists" +msgstr "A lemezképfájl már létezik" + +msgid "Please specify a valid file name." +msgstr "Adjon meg egy érvényes fájlnevet." + +msgid "Disk image created" +msgstr "A lemezképfájl létrehozásra került" + +msgid "Make sure the file exists and is readable." +msgstr "Győződjön meg arról, hogy a fájl létezik és olvasható." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Győződjön meg arról, hogy a fájlt egy írható könyvtárba menti." + +msgid "Disk image too large" +msgstr "A lemezképfájl túl nagy" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Ne felejtse el particionálni és formázni az újonnan létrehozott meghajtót." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "A kiválasztott fájl felülírásra kerül. Biztos, hogy ezt kívánja használni?" + +msgid "Unsupported disk image" +msgstr "Nem támogatott lemezkép" + +msgid "Overwrite" +msgstr "Felülírás" + +msgid "Don't overwrite" +msgstr "Ne írja felül" + +msgid "Raw image (.img)" +msgstr "Nyers lemezkép (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI-lemezkép (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX-lemezkép (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "Rögzített méretű VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dinamikusan bővülő VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Különbség-VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Nagy blokkméret (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Kis blokkméret (512 KB)" + +msgid "VHD files" +msgstr "VHD fájlok" + +msgid "Select the parent VHD" +msgstr "Válassza ki a szülő VHD-t" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Ez azt jelentheti, hogy a szülőkép módosult az eltérő kép létrehozása után.\n\nEz akkor is előfordulhat, ha a képfájlokat áthelyezték vagy másolták, vagy a lemezt létrehozó program hibája miatt.\n\nSzeretné kijavítani az időbélyegeket?" + +msgid "Parent and child disk timestamps do not match" +msgstr "A szülő- és a gyermeklemez időbélyegei nem egyeznek" + +msgid "Could not fix VHD timestamp." +msgstr "Nem sikerült kijavítani a VHD időbélyegét." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (1024 klaszter)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (2048 klaszter)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Tökéletes RPM" + +msgid "1% below perfect RPM" +msgstr "1%-kal a tökéletes RPM alatt" + +msgid "1.5% below perfect RPM" +msgstr "1.5%-kal a tökéletes RPM alatt" + +msgid "2% below perfect RPM" +msgstr "2%-kal a tökéletes RPM alatt" + +msgid "(System Default)" +msgstr "(A rendszer nyelve)" + diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po new file mode 100644 index 000000000..ee5e2a01a --- /dev/null +++ b/src/qt/languages/it-IT.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Azione" + +msgid "&Keyboard requires capture" +msgstr "&Tastiera richiede la cattura" + +msgid "&Right CTRL is left ALT" +msgstr "&CTRL destro è ALT sinistro" + +msgid "&Hard Reset..." +msgstr "&Riavvia..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pausa" + +msgid "E&xit..." +msgstr "E&sci..." + +msgid "&View" +msgstr "&Visualizza" + +msgid "&Hide status bar" +msgstr "&Nascondi barra di stato" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Finestra ridimensionabile" + +msgid "R&emember size && position" +msgstr "R&icorda dimensioni e posizione" + +msgid "Re&nderer" +msgstr "Re&nderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Specifica dimensioni..." + +msgid "F&orce 4:3 display ratio" +msgstr "F&orza display 4:3" + +msgid "&Window scale factor" +msgstr "&Fattore scalare della finestra" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Metodo filtro" + +msgid "&Nearest" +msgstr "&Dal più vicino" + +msgid "&Linear" +msgstr "&Lineare" + +msgid "Hi&DPI scaling" +msgstr "Scala Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Schermo intero\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Modalità adattamento &schermo intero" + +msgid "&Full screen stretch" +msgstr "&Adatta a schermo intero" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Pixel quadrati (mantiene l'aspetto)" + +msgid "&Integer scale" +msgstr "&Scala intera" + +msgid "E&GA/(S)VGA settings" +msgstr "Impostazioni E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Invertire monitor VGA" + +msgid "VGA screen &type" +msgstr "Schermi VGA &" + +msgid "RGB &Color" +msgstr "RGB &Color" + +msgid "&RGB Grayscale" +msgstr "&RGB Monocroma" + +msgid "&Amber monitor" +msgstr "&Monitor ambra" + +msgid "&Green monitor" +msgstr "&Monitor verde" + +msgid "&White monitor" +msgstr "&Monitor bianco" + +msgid "Grayscale &conversion type" +msgstr "Conversione &scala grigia" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&AMedia" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Sovrascansione CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Cambia il contrasto per &display monocromatici" + +msgid "&Media" +msgstr "&Dispositivi" + +msgid "&Tools" +msgstr "&Strumenti" + +msgid "&Settings..." +msgstr "&Impostazioni..." + +msgid "&Update status bar icons" +msgstr "&Aggiorna icone della barra di stato" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Cattura schermata\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferenze..." + +msgid "Enable &Discord integration" +msgstr "Abilita &integrazione Discord" + +msgid "Sound &gain..." +msgstr "Guadagno &suono..." + +msgid "Begin trace\tCtrl+T" +msgstr "Inizia traccia\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Ferma traccia\tCtrl+T" + +msgid "&Help" +msgstr "&?" + +msgid "&Documentation..." +msgstr "&Documentazione..." + +msgid "&About 86Box..." +msgstr "&Informazioni su 86Box..." + +msgid "&New image..." +msgstr "&Nuova immagine..." + +msgid "&Existing image..." +msgstr "&Immagine esistente..." + +msgid "Existing image (&Write-protected)..." +msgstr "Immagine esistente (&protezione contro scrittura)..." + +msgid "&Record" +msgstr "&Registra" + +msgid "&Play" +msgstr "R&iproduci" + +msgid "&Rewind to the beginning" +msgstr "Ri&avvolgi all'inizio" + +msgid "&Fast forward to the end" +msgstr "A&vanti veloce alla fine" + +msgid "E&ject" +msgstr "&Espelli" + +msgid "&Image..." +msgstr "&Immagine..." + +msgid "E&xport to 86F..." +msgstr "E&sporta in 86F..." + +msgid "&Mute" +msgstr "&Muto" + +msgid "E&mpty" +msgstr "&Espelli" + +msgid "&Reload previous image" +msgstr "&Ricarica l'immagine precedente" + +msgid "&Image" +msgstr "&Immagine" + +msgid "Target &framerate" +msgstr "Imposta obiettivo &fotogrammi" + +msgid "&Sync with video" +msgstr "&Sincronizza col video" + +msgid "&25 fps" +msgstr "&25 FPS" + +msgid "&30 fps" +msgstr "&30 FPS" + +msgid "&50 fps" +msgstr "&50 FPS" + +msgid "&60 fps" +msgstr "&60 FPS" + +msgid "&75 fps" +msgstr "&75 FPS" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Seleziona shader..." + +msgid "&Remove shader" +msgstr "&Rimuovi shader" + +msgid "Preferences" +msgstr "Preferenze" + +msgid "Sound Gain" +msgstr "Guadagno del suono" + +msgid "New Image" +msgstr "Nuova immagine" + +msgid "Settings" +msgstr "Impostazioni" + +msgid "Specify Main Window Dimensions" +msgstr "Specifica dimensioni della finestra principale" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Annulla" + +msgid "Save these settings as &global defaults" +msgstr "Salva queste impostazioni come &predefinite globali" + +msgid "&Default" +msgstr "&Predefinito" + +msgid "Language:" +msgstr "Lingua:" + +msgid "Icon set:" +msgstr "Pacchetto di icone:" + +msgid "Gain" +msgstr "Guadagno" + +msgid "File name:" +msgstr "Nome file:" + +msgid "Disk size:" +msgstr "Dimensioni disco:" + +msgid "RPM mode:" +msgstr "Modalità RPM:" + +msgid "Progress:" +msgstr "Progresso:" + +msgid "Width:" +msgstr "Larghezza:" + +msgid "Height:" +msgstr "Altezza:" + +msgid "Lock to this size" +msgstr "Blocca in queste dimensioni" + +msgid "Machine type:" +msgstr "Tipo di piastra madre:" + +msgid "Machine:" +msgstr "Piastra madre:" + +msgid "Configure" +msgstr "Configura" + +msgid "CPU type:" +msgstr "Tipo del CPU:" + +msgid "Speed:" +msgstr "Veloc.:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Stati di attesa:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memoria:" + +msgid "Time synchronization" +msgstr "Sincronizzazione dell'ora" + +msgid "Disabled" +msgstr "Disabilitata" + +msgid "Enabled (local time)" +msgstr "Abilitata (ora locale)" + +msgid "Enabled (UTC)" +msgstr "Abilitata (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Ricompilatore dinamico" + +msgid "Video:" +msgstr "Video:" + +msgid "Voodoo Graphics" +msgstr "Grafica Voodoo" + +msgid "Mouse:" +msgstr "Mouse:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Scheda audio:" + +msgid "MIDI Out Device:" +msgstr "Uscita MIDI:" + +msgid "MIDI In Device:" +msgstr "Entrata MIDI:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 autonomo" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Usa suono FLOAT32" + +msgid "Network type:" +msgstr "Tipo di rete:" + +msgid "PCap device:" +msgstr "Dispositivo PCap:" + +msgid "Network adapter:" +msgstr "Scheda di rete:" + +msgid "COM1 Device:" +msgstr "Dispositivo COM1:" + +msgid "COM2 Device:" +msgstr "Dispositivo COM2:" + +msgid "COM3 Device:" +msgstr "Dispositivo COM3:" + +msgid "COM4 Device:" +msgstr "Dispositivo COM4:" + +msgid "LPT1 Device:" +msgstr "Dispositivo LPT1:" + +msgid "LPT2 Device:" +msgstr "Dispositivo LPT2:" + +msgid "LPT3 Device:" +msgstr "Dispositivo LPT3:" + +msgid "LPT4 Device:" +msgstr "Dispositivo LPT4:" + +msgid "Serial port 1" +msgstr "Porta seriale 1" + +msgid "Serial port 2" +msgstr "Porta seriale 2" + +msgid "Serial port 3" +msgstr "Porta seriale 3" + +msgid "Serial port 4" +msgstr "Porta seriale 4" + +msgid "Parallel port 1" +msgstr "Porta parallela 1" + +msgid "Parallel port 2" +msgstr "Porta parallela 2" + +msgid "Parallel port 3" +msgstr "Porta parallela 3" + +msgid "Parallel port 4" +msgstr "Porta parallela 4" + +msgid "HD Controller:" +msgstr "Controller HD:" + +msgid "FD Controller:" +msgstr "Controller FD:" + +msgid "Tertiary IDE Controller" +msgstr "Controller IDE terziario" + +msgid "Quaternary IDE Controller" +msgstr "Controller IDE quaternario" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controller 1:" + +msgid "Controller 2:" +msgstr "Controller 2:" + +msgid "Controller 3:" +msgstr "Controller 3:" + +msgid "Controller 4:" +msgstr "Controller 4:" + +msgid "Cassette" +msgstr "Cassetta" + +msgid "Hard disks:" +msgstr "Hard disk:" + +msgid "&New..." +msgstr "&Nuovo..." + +msgid "&Existing..." +msgstr "&Esistente..." + +msgid "&Remove" +msgstr "&Rimouvi" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Canale:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Specifica..." + +msgid "Sectors:" +msgstr "Settori:" + +msgid "Heads:" +msgstr "Testine:" + +msgid "Cylinders:" +msgstr "Cilindri:" + +msgid "Size (MB):" +msgstr "Dimensioni (MB):" + +msgid "Type:" +msgstr "Tipo:" + +msgid "Image Format:" +msgstr "Formato immagine:" + +msgid "Block Size:" +msgstr "Dimensioni blocco:" + +msgid "Floppy drives:" +msgstr "Unità floppy:" + +msgid "Turbo timings" +msgstr "Turbo" + +msgid "Check BPB" +msgstr "Verifica BPB" + +msgid "CD-ROM drives:" +msgstr "Unità CD-ROM:" + +msgid "MO drives:" +msgstr "Unità magneto-ottiche:" + +msgid "ZIP drives:" +msgstr "Unità ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "RTC ISA:" + +msgid "ISA Memory Expansion" +msgstr "Espansione memoria ISA" + +msgid "Card 1:" +msgstr "Scheda 1:" + +msgid "Card 2:" +msgstr "Scheda 2:" + +msgid "Card 3:" +msgstr "Scheda 3:" + +msgid "Card 4:" +msgstr "Scheda 4:" + +msgid "ISABugger device" +msgstr "Dispositivo ISABugger" + +msgid "POST card" +msgstr "Scheda POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Errore" + +msgid "Fatal error" +msgstr "Errore fatale" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Usa Ctrl+Alt+PgDn per tornare alla modalità finestra." + +msgid "Speed" +msgstr "Velocità" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Immagini ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box non può trovare immagini ROM utilizzabili.\n\nPlease download a ROM set and extract it into the \"roms\" directory." + +msgid "(empty)" +msgstr "(empty)" + +msgid "All files" +msgstr "Tutti i file" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Acceso" + +msgid "Off" +msgstr "Spento" + +msgid "All images" +msgstr "Tutte le immagini" + +msgid "Basic sector images" +msgstr "Immagini di settori base" + +msgid "Surface images" +msgstr "Immagini di superficie" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "La macchina \"%hs\" non è disponibile a causa di immagini ROM mancanti nella directory roms/machines. Cambiando ad una macchina disponibile." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "La scheda video \"%hs\" non è disponibile a causa di immagini ROM mancanti nella directory roms/video. Cambiando ad una scheda video disponibile." + +msgid "Machine" +msgstr "Piastra madre" + +msgid "Display" +msgstr "Schermo" + +msgid "Input devices" +msgstr "Dispositivi di entrata" + +msgid "Sound" +msgstr "Audio" + +msgid "Network" +msgstr "Rete" + +msgid "Ports (COM & LPT)" +msgstr "Porte (COM & LPT)" + +msgid "Storage controllers" +msgstr "Controller memoria" + +msgid "Hard disks" +msgstr "Hard disk" + +msgid "Floppy & CD-ROM drives" +msgstr "Unità CD-ROM e Floppy" + +msgid "Other removable devices" +msgstr "Altri dispositivi rimuovibili" + +msgid "Other peripherals" +msgstr "Altre periferiche" + +msgid "Click to capture mouse" +msgstr "Fare clic per catturare mouse" + +msgid "Press F8+F12 to release mouse" +msgstr "Premi F8+F12 per rilasciare il mouse" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Premi F8+F12 o pulsante centrale per rilasciare il mouse" + +msgid "Unable to initialize FluidSynth" +msgstr "Impossibile inizializzare FluidSynth" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "File" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Impossibile inizializzare il renderer video." + +msgid "Default" +msgstr "Predefinito" + +msgid "%i Wait state(s)" +msgstr "%i stati d'attesa" + +msgid "Type" +msgstr "Tipo" + +msgid "Failed to set up PCap" +msgstr "Impossibile impostare PCap" + +msgid "No PCap devices found" +msgstr "Nessun dispositivo PCap trovato" + +msgid "Invalid PCap device" +msgstr "Dispositivo PCap invalido" + +msgid "Standard 2-button joystick(s)" +msgstr "Joystick comune da 2 pulsanti" + +msgid "Standard 4-button joystick" +msgstr "Joystick comune da 4 pulsanti" + +msgid "Standard 6-button joystick" +msgstr "Joystick comune da 6 pulsanti" + +msgid "Standard 8-button joystick" +msgstr "Joystick comune da 8 pulsanti" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Nessuno" + +msgid "Unable to load keyboard accelerators." +msgstr "Impossibile caricare gli acceleratori da tastiera." + +msgid "Unable to register raw input." +msgstr "Impossibile registrare input raw." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Floppy %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Immagini da settori avanzati" + +msgid "Flux images" +msgstr "Immagini flusso" + +msgid "Unable to initialize FreeType" +msgstr "Impossibile inizializzare FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Impossibile inizializzare SDL, SDL2.dll è necessario" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Sei sicuro di voler riavviare la macchina emulata?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Sei sicuro di voler uscire da 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Impossibile inizializzare Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "Immagini MO" + +msgid "Welcome to 86Box!" +msgstr "Benvenuti in 86Box!" + +msgid "Internal controller" +msgstr "Controller interno" + +msgid "Exit" +msgstr "Esci" + +msgid "No ROMs found" +msgstr "Nessune immagini ROM trovate" + +msgid "Do you want to save the settings?" +msgstr "Vuole salvare queste impostazioni?" + +msgid "This will hard reset the emulated machine." +msgstr "Questo riavvierà la macchina emulata." + +msgid "Save" +msgstr "Salva" + +msgid "About 86Box" +msgstr "Informazioni su 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Un emulatore di computer vecchi\n\nAutori: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nTradotto da: explorerdotexe\n\nRilasciato sotto la Licenza Pubblica GNU versione 2 o dopo. Vedi LICENSE per maggior informazioni." + +msgid "Hardware not available" +msgstr "Hardware non disponibile" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Controlla se libpcap è installato e che tu sia connesso ad una connessione libpcap compatibile." + +msgid "Invalid configuration" +msgstr "Configurazione invalida" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " è richesto per l'emuazione di stampanti ESC/P." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " è richiesto per la conversione automatica di file PostScript a file PDF.\n\nQualsiasi documento mandato alla stampante generica PostScript sarà salvato come file PostScript. (.ps)" + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " è richiesto per l'output FluidSynth MIDI." + +msgid "Entering fullscreen mode" +msgstr "Entrando nella modalità schermo intero" + +msgid "Don't show this message again" +msgstr "Non mostrare più questo messaggio" + +msgid "Don't exit" +msgstr "Non uscire" + +msgid "Reset" +msgstr "Riavvia" + +msgid "Don't reset" +msgstr "Non riavviare" + +msgid "CD-ROM images" +msgstr "Immagini CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Configurazione del dispositivo %hs" + +msgid "Monitor in sleep mode" +msgstr "Monitor in modalità riposo" + +msgid "OpenGL Shaders" +msgstr "Shader OpenGL" + +msgid "OpenGL options" +msgstr "Impostazioni OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Stai caricando una configurazione non supportata" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Il filtraggio della tipologia di CPU è disabilitato per la macchina selezionata.\n\nQuesto lo rende possibile scegliere un CPU che è altrimenti incompatibile con la macchina selezionata. Tuttavia, portresti incorrere in incompatibilità con il BIOS della macchina o altri programmi. \n\nL'abilitare di questa impostazione non è ufficialmente supportato e tutte le segnalazioni di errori saranno considerate invalide." + +msgid "Continue" +msgstr "Continua" + +msgid "Cassette: %s" +msgstr "Cassetta: %s" + +msgid "Cassette images" +msgstr "Immagini cassetta" + +msgid "Cartridge %i: %ls" +msgstr "Cartuccia %i: %ls" + +msgid "Cartridge images" +msgstr "Immagini cartuccia" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Hard disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Le unità CD-ROM MFM/RLL o ESDI non sono mai esistite." + +msgid "Custom..." +msgstr "Personalizzata..." + +msgid "Custom (large)..." +msgstr "Personalizzata (grande)..." + +msgid "Add New Hard Disk" +msgstr "Aggiungi un nuovo disco rigido" + +msgid "Add Existing Hard Disk" +msgstr "Aggiungi un disco rigido esistente" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Le immagini HDI non possono essere più grandi di 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Le immmagini disco non possono essere più grandi di 127 GB." + +msgid "Hard disk images" +msgstr "Immagini disco rigido" + +msgid "Unable to read file" +msgstr "Impossibile leggere il file" + +msgid "Unable to write file" +msgstr "Impossibile scrivere al file" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Le immagini HDI o HDX con settori di dimensioni diverse da 512 non sono supportati." + +msgid "USB is not yet supported" +msgstr "USB non è ancora supportato" + +msgid "Disk image file already exists" +msgstr "Immagine disco già esiste" + +msgid "Please specify a valid file name." +msgstr "Specifica un nome file valido." + +msgid "Disk image created" +msgstr "Immagine disco creata" + +msgid "Make sure the file exists and is readable." +msgstr "Controlla che il file esiste e che sia leggibile." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Controlla che il file viene salvato ad un percorso con diritti di scrittura" + +msgid "Disk image too large" +msgstr "Immagine disco troppo grande" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Ricordati di partizionare e formattare il disco appena creato." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Il file selezionato sarà sovrascritto, sei sicuro di volerlo usare?" + +msgid "Unsupported disk image" +msgstr "Immagine disco non supportata" + +msgid "Overwrite" +msgstr "Sovrascrivi" + +msgid "Don't overwrite" +msgstr "Non sovrascrivere" + +msgid "Raw image (.img)" +msgstr "Immagine raw (.img)" + +msgid "HDI image (.hdi)" +msgstr "Immagine HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Immagine HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD di dimensioni fisse (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD di dimensioni dinamiche (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD differenziato (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Blocchi larghi (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Blocchi piccoli (512 KB)" + +msgid "VHD files" +msgstr "File VHD" + +msgid "Select the parent VHD" +msgstr "Seleziona il VHD padre." + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Questo potrebbe significare che l'immagine padre sia stata modificata dopo la creazione dell'immagine di differenziazione.\n\nPuò anche succedere se i file immagini sono stati spostati o copiati, o da un errore nel programma che ha creato questo disco.\n\nVuoi aggiustare le marcature di tempo?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Le marcature di tempo padre e figlio non corrispondono" + +msgid "Could not fix VHD timestamp." +msgstr "Impossibile aggiustare marcature di tempo VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "RPM perfette" + +msgid "1% below perfect RPM" +msgstr "RPM 1% sotto perfezione" + +msgid "1.5% below perfect RPM" +msgstr "RPM 1.5% sotto perfezione" + +msgid "2% below perfect RPM" +msgstr "RPM 2% sotto perfezione" + +msgid "(System Default)" +msgstr "(Predefinito del sistema)" + diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po new file mode 100644 index 000000000..d1da289c4 --- /dev/null +++ b/src/qt/languages/ja-JP.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "動作(&A)" + +msgid "&Keyboard requires capture" +msgstr "キーボードはキャプチャが必要(&K)" + +msgid "&Right CTRL is left ALT" +msgstr "右CTRLを左ALTへ(&R)" + +msgid "&Hard Reset..." +msgstr "ハードリセット(&H)..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+Esc(&E)" + +msgid "&Pause" +msgstr "一時停止(&P)" + +msgid "E&xit..." +msgstr "終了(&X)..." + +msgid "&View" +msgstr "表示(&V)" + +msgid "&Hide status bar" +msgstr "ステータスバーを隠す(&H)" + +msgid "Hide &toolbar" +msgstr "ツールバーを隠す(&T)" + +msgid "&Resizeable window" +msgstr "ウィンドウのサイズをリサイズ可能(&R)" + +msgid "R&emember size && position" +msgstr "ウィンドウのサイズと位置を記憶(&E)" + +msgid "Re&nderer" +msgstr "レンダラー(&N)" + +msgid "&SDL (Software)" +msgstr "SDL (ソフトウェア)(&S)" + +msgid "SDL (&Hardware)" +msgstr "SDL (ハードウェア)(&H)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (OpenGL)(&O)" + +msgid "Open&GL (3.0 Core)" +msgstr "OpenGL (3.0コア)(&G)" + +msgid "&VNC" +msgstr "VNC(&V)" + +msgid "Specify dimensions..." +msgstr "ウィンドウのサイズを指定..." + +msgid "F&orce 4:3 display ratio" +msgstr "4:3アスペクト比を固定(&O)" + +msgid "&Window scale factor" +msgstr "ウィンドウの表示倍率(&W)" + +msgid "&0.5x" +msgstr "0.5x(&0)" + +msgid "&1x" +msgstr "1x(&1)" + +msgid "1.&5x" +msgstr "1.5x(&5)" + +msgid "&2x" +msgstr "2x(&2)" + +msgid "Filter method" +msgstr "フィルター方式" + +msgid "&Nearest" +msgstr "最近傍補間(&N)" + +msgid "&Linear" +msgstr "線形補間(&L)" + +msgid "Hi&DPI scaling" +msgstr "HiDPIスケーリング(&D)" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "フルスクリーン(&F)\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "フルスクリーンのスケール(&S)" + +msgid "&Full screen stretch" +msgstr "フルスクリーンに拡大(&F)" + +msgid "&4:3" +msgstr "4:3(&4)" + +msgid "&Square pixels (Keep ratio)" +msgstr "正方形ピクセル(アスペクト比を維持)(&S)" + +msgid "&Integer scale" +msgstr "整数倍(&I)" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGAの設定" + +msgid "&Inverted VGA monitor" +msgstr "色を反転(&I)" + +msgid "VGA screen &type" +msgstr "画面タイプ(&T)" + +msgid "RGB &Color" +msgstr "RGB(カラー)(&C)" + +msgid "&RGB Grayscale" +msgstr "RGB(グレースケール)(&R)" + +msgid "&Amber monitor" +msgstr "モニター(琥珀色)(&A)" + +msgid "&Green monitor" +msgstr "モニター(緑色)(&G)" + +msgid "&White monitor" +msgstr "モニター(白色)(&W)" + +msgid "Grayscale &conversion type" +msgstr "グレースケール変換タイプ(&C)" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT601 (NTSC/PAL)(&6)" + +msgid "BT&709 (HDTV)" +msgstr "BT709 (HDTV)(&7)" + +msgid "&Average" +msgstr "平均(&A)" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/EGA/(S)VGAオーバースキャン(&G)" + +msgid "Change contrast for &monochrome display" +msgstr "単色モニター用コントラストを変更(&M)" + +msgid "&Media" +msgstr "メディア(&M)" + +msgid "&Tools" +msgstr "ツール(&T)" + +msgid "&Settings..." +msgstr "設定(&S)..." + +msgid "&Update status bar icons" +msgstr "ステータスバーのアイコンを更新(&U)" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "スクリーンショットを撮る(&C)\tCtrl+F11" + +msgid "&Preferences..." +msgstr "環境設定(&P)..." + +msgid "Enable &Discord integration" +msgstr "Discordとの連携機能(&D)" + +msgid "Sound &gain..." +msgstr "音量を調節(&G)..." + +msgid "Begin trace\tCtrl+T" +msgstr "トレース開始\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "トレース終了\tCtrl+T" + +msgid "&Help" +msgstr "ヘルプ(&H)" + +msgid "&Documentation..." +msgstr "ドキュメント(&D)..." + +msgid "&About 86Box..." +msgstr "86Boxのバージョン情報(&A)..." + +msgid "&New image..." +msgstr "新規イメージ(&N)..." + +msgid "&Existing image..." +msgstr "既存のイメージを開く(&E)..." + +msgid "Existing image (&Write-protected)..." +msgstr "既存のイメージを開く(書き込み保護)(&W)..." + +msgid "&Record" +msgstr "録音(&R)" + +msgid "&Play" +msgstr "再生(&P)" + +msgid "&Rewind to the beginning" +msgstr "冒頭に巻き戻す(&R)" + +msgid "&Fast forward to the end" +msgstr "最後まで早送り(&F)" + +msgid "E&ject" +msgstr "取り出す(&J)" + +msgid "&Image..." +msgstr "イメージ(&I)..." + +msgid "E&xport to 86F..." +msgstr "86Fイメージにエクスポート(&X)..." + +msgid "&Mute" +msgstr "ミュート(&M)" + +msgid "E&mpty" +msgstr "空(&M)" + +msgid "&Reload previous image" +msgstr "前のイメージを再読み込み(&R)" + +msgid "&Image" +msgstr "イメージ(&I)" + +msgid "Target &framerate" +msgstr "目標フレームレート(&F)" + +msgid "&Sync with video" +msgstr "ビデオと同期(&S)" + +msgid "&25 fps" +msgstr "25 fps(&2)" + +msgid "&30 fps" +msgstr "30 fps(&3)" + +msgid "&50 fps" +msgstr "50 fps(&5)" + +msgid "&60 fps" +msgstr "60 fps(&6)" + +msgid "&75 fps" +msgstr "75 fps(&7)" + +msgid "&VSync" +msgstr "垂直同期(VSync)(&V)" + +msgid "&Select shader..." +msgstr "シェーダーを選択(&S)..." + +msgid "&Remove shader" +msgstr "シェーダーを削除(&R)" + +msgid "Preferences" +msgstr "環境設定" + +msgid "Sound Gain" +msgstr "音量ゲイン" + +msgid "New Image" +msgstr "新規のイメージ" + +msgid "Settings" +msgstr "設定" + +msgid "Specify Main Window Dimensions" +msgstr "メインウィンドウのサイズ指定" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "キャンセル" + +msgid "Save these settings as &global defaults" +msgstr "これらの設定をグローバル既定値として保存する(&G)" + +msgid "&Default" +msgstr "既定値(&D)" + +msgid "Language:" +msgstr "言語:" + +msgid "Icon set:" +msgstr "アイコンセット:" + +msgid "Gain" +msgstr "ゲイン値" + +msgid "File name:" +msgstr "ファイル名:" + +msgid "Disk size:" +msgstr "ディスクサイズ:" + +msgid "RPM mode:" +msgstr "回転数モード:" + +msgid "Progress:" +msgstr "進行状況:" + +msgid "Width:" +msgstr "幅:" + +msgid "Height:" +msgstr "高さ:" + +msgid "Lock to this size" +msgstr "このサイズをロックする" + +msgid "Machine type:" +msgstr "マシンタイプ:" + +msgid "Machine:" +msgstr "マシン:" + +msgid "Configure" +msgstr "設定" + +msgid "CPU type:" +msgstr "CPUタイプ:" + +msgid "Speed:" +msgstr "速度:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "待機状態:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "メモリ:" + +msgid "Time synchronization" +msgstr "時刻同期機能" + +msgid "Disabled" +msgstr "無効にする" + +msgid "Enabled (local time)" +msgstr "有効にする (現地時間)" + +msgid "Enabled (UTC)" +msgstr "有効にする (UTC)" + +msgid "Dynamic Recompiler" +msgstr "動的リコンパイラ" + +msgid "Video:" +msgstr "ビデオカード:" + +msgid "Voodoo Graphics" +msgstr "Voodooグラフィック" + +msgid "Mouse:" +msgstr "マウス:" + +msgid "Joystick:" +msgstr "ジョイスティック:" + +msgid "Joystick 1..." +msgstr "ジョイスティック1..." + +msgid "Joystick 2..." +msgstr "ジョイスティック2..." + +msgid "Joystick 3..." +msgstr "ジョイスティック3..." + +msgid "Joystick 4..." +msgstr "ジョイスティック4..." + +msgid "Sound card:" +msgstr "サウンドカード:" + +msgid "MIDI Out Device:" +msgstr "MIDI出力デバイス:" + +msgid "MIDI In Device:" +msgstr "MIDI入力デバイス:" + +msgid "Standalone MPU-401" +msgstr "独立型MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32サウンドを使用する" + +msgid "Network type:" +msgstr "ネットワークタイプ:" + +msgid "PCap device:" +msgstr "PCapデバイス:" + +msgid "Network adapter:" +msgstr "ネットワークアダプター:" + +msgid "COM1 Device:" +msgstr "COM1デバイス:" + +msgid "COM2 Device:" +msgstr "COM2デバイス:" + +msgid "COM3 Device:" +msgstr "COM3デバイス:" + +msgid "COM4 Device:" +msgstr "COM4デバイス:" + +msgid "LPT1 Device:" +msgstr "LPT1デバイス:" + +msgid "LPT2 Device:" +msgstr "LPT2デバイス:" + +msgid "LPT3 Device:" +msgstr "LPT3デバイス:" + +msgid "LPT4 Device:" +msgstr "LPT4デバイス:" + +msgid "Serial port 1" +msgstr "シリアルポート1" + +msgid "Serial port 2" +msgstr "シリアルポート2" + +msgid "Serial port 3" +msgstr "シリアルポート3" + +msgid "Serial port 4" +msgstr "シリアルポート4" + +msgid "Parallel port 1" +msgstr "パラレルポート1" + +msgid "Parallel port 2" +msgstr "パラレルポート2" + +msgid "Parallel port 3" +msgstr "パラレルポート3" + +msgid "Parallel port 4" +msgstr "パラレルポート4" + +msgid "HD Controller:" +msgstr "HDコントローラー:" + +msgid "FD Controller:" +msgstr "FDコントローラー:" + +msgid "Tertiary IDE Controller" +msgstr "第三のIDEコントローラー" + +msgid "Quaternary IDE Controller" +msgstr "第四のIDEコントローラー" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "コントローラー1:" + +msgid "Controller 2:" +msgstr "コントローラー2:" + +msgid "Controller 3:" +msgstr "コントローラー3:" + +msgid "Controller 4:" +msgstr "コントローラー4:" + +msgid "Cassette" +msgstr "カセット" + +msgid "Hard disks:" +msgstr "ハードディスク:" + +msgid "&New..." +msgstr "新規(&N)..." + +msgid "&Existing..." +msgstr "既定(&E)..." + +msgid "&Remove" +msgstr "除去(&R)" + +msgid "Bus:" +msgstr "バス:" + +msgid "Channel:" +msgstr "チャンネル:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "参照(&S)..." + +msgid "Sectors:" +msgstr "セクター:" + +msgid "Heads:" +msgstr "ヘッド:" + +msgid "Cylinders:" +msgstr "シリンダー:" + +msgid "Size (MB):" +msgstr "サイズ(MB):" + +msgid "Type:" +msgstr "タイプ:" + +msgid "Image Format:" +msgstr "イメージ形式:" + +msgid "Block Size:" +msgstr "ブロックサイズ:" + +msgid "Floppy drives:" +msgstr "フロッピードライブ:" + +msgid "Turbo timings" +msgstr "高速タイミング" + +msgid "Check BPB" +msgstr "BPBをチェック" + +msgid "CD-ROM drives:" +msgstr "CD-ROMドライブ:" + +msgid "MO drives:" +msgstr "光磁気ドライブ:" + +msgid "ZIP drives:" +msgstr "ZIPドライブ:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTCカード:" + +msgid "ISA Memory Expansion" +msgstr "ISAメモリー拡張カード" + +msgid "Card 1:" +msgstr "カード1:" + +msgid "Card 2:" +msgstr "カード2:" + +msgid "Card 3:" +msgstr "カード3:" + +msgid "Card 4:" +msgstr "カード4:" + +msgid "ISABugger device" +msgstr "ISABuggerデバイス" + +msgid "POST card" +msgstr "POSTカード" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Meiryo UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "エラー" + +msgid "Fatal error" +msgstr "致命的なエラー" + +msgid " - PAUSED" +msgstr " - 一時停止" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Ctrl+Alt+PgDnでウィンドウモードに戻ります。" + +msgid "Speed" +msgstr "速度" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIPイメージ" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Boxで使用可能なROMイメージが見つかりませんでした。\n\nROMセットをダウンロードして、「roms」ディレクトリに解凍してください。" + +msgid "(empty)" +msgstr "(空)" + +msgid "All files" +msgstr "すべてのファイル" + +msgid "Turbo" +msgstr "高速" + +msgid "On" +msgstr "オン" + +msgid "Off" +msgstr "オフ" + +msgid "All images" +msgstr "すべてのイメージ" + +msgid "Basic sector images" +msgstr "基本的なセクターイメージ" + +msgid "Surface images" +msgstr "表面イメージ" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "roms/machinesディレクトリにROMがないため、マシン「%hs」は使用できません。使用可能なマシンに切り替えます。" + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "roms/videoディレクトリにROMがないため、ビデオカード「%hs」は使用できません。使用可能なビデオカードに切り替えます。" + +msgid "Machine" +msgstr "マシン" + +msgid "Display" +msgstr "画面表示" + +msgid "Input devices" +msgstr "入力デバイス" + +msgid "Sound" +msgstr "サウンド" + +msgid "Network" +msgstr "ネットワーク" + +msgid "Ports (COM & LPT)" +msgstr "ポート (COM & LPT)" + +msgid "Storage controllers" +msgstr "ストレージコントローラ" + +msgid "Hard disks" +msgstr "ハードディスク" + +msgid "Floppy & CD-ROM drives" +msgstr "フロッピー/CD-ROMドライブ" + +msgid "Other removable devices" +msgstr "その他のリムーバブルデバイス" + +msgid "Other peripherals" +msgstr "その他の周辺装置" + +msgid "Click to capture mouse" +msgstr "クリックするとマウスをキャプチャします" + +msgid "Press F8+F12 to release mouse" +msgstr "F8+F12キーでマウスを解放します" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "F8+F12キーまたは中ボタンでマウスを解放します" + +msgid "Unable to initialize FluidSynth" +msgstr "FluidSynthが初期化できません" + +msgid "Bus" +msgstr "バス" + +msgid "File" +msgstr "ファイル" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "ビデオレンダラーが初期化できません。" + +msgid "Default" +msgstr "既定値" + +msgid "%i Wait state(s)" +msgstr "%iつの待機状態" + +msgid "Type" +msgstr "タイプ" + +msgid "Failed to set up PCap" +msgstr "PCapのセットアップに失敗しました" + +msgid "No PCap devices found" +msgstr "PCapデバイスがありません" + +msgid "Invalid PCap device" +msgstr "不正なPCapデバイスです" + +msgid "Standard 2-button joystick(s)" +msgstr "標準ジョイスティック(2ボタン)" + +msgid "Standard 4-button joystick" +msgstr "標準ジョイスティック(4ボタン)" + +msgid "Standard 6-button joystick" +msgstr "標準ジョイスティック(6ボタン)" + +msgid "Standard 8-button joystick" +msgstr "標準ジョイスティック(8ボタン)" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "なし" + +msgid "Unable to load keyboard accelerators." +msgstr "キーボードアクセラレータを読み込めません。" + +msgid "Unable to register raw input." +msgstr "生の入力が登録できません。" + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "フロッピー %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "アドバンスドセクターイメージ" + +msgid "Flux images" +msgstr "フラックスイメージ" + +msgid "Unable to initialize FreeType" +msgstr "FreeTypeが初期化できません" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "SDLが初期化できません。SDL2.dllが必要です" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "使用中のマシンをハードリセットしますか?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "86Boxを終了しますか?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ghostscriptが初期化できません" + +msgid "MO %i (%ls): %ls" +msgstr "光磁気 %i (%ls): %ls" + +msgid "MO images" +msgstr "光磁気イメージ" + +msgid "Welcome to 86Box!" +msgstr "86Boxへようこそ!" + +msgid "Internal controller" +msgstr "内蔵コントローラー" + +msgid "Exit" +msgstr "終了" + +msgid "No ROMs found" +msgstr "ROMが見つかりません" + +msgid "Do you want to save the settings?" +msgstr "設定を保存しますか?" + +msgid "This will hard reset the emulated machine." +msgstr "保存すると使用中のマシンがハードリセットされます。" + +msgid "Save" +msgstr "保存" + +msgid "About 86Box" +msgstr "86Boxのバージョン情報" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "古いパソコンのエミュレーター\n\n著者: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nGNU General Public License version 2以降でリリースされています。詳しくは LICENSE をご覧ください。" + +msgid "Hardware not available" +msgstr "ハードウェアが利用できません" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "がインストールされてるか、libpcapに対応したネットワークに接続されてるか確認してください。" + +msgid "Invalid configuration" +msgstr "不正な設定です" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr "ESC/Pプリンタのエミュレーションにはlibfreetypeが必要です。" + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr "PostScriptファイルをPDFに自動変換するにはlibgsが必要です。\n\n汎用PostScriptプリンターに送信されたドキュメントは、PostScript(.ps)ファイルとして保存されます。" + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr "FluidSynthのMIDI出力にはlibfluidsynthが必要です。" + +msgid "Entering fullscreen mode" +msgstr "フルスクリーンに切り替えています" + +msgid "Don't show this message again" +msgstr "今後、このメッセージを表示しない" + +msgid "Don't exit" +msgstr "終了しない" + +msgid "Reset" +msgstr "リセット" + +msgid "Don't reset" +msgstr "リセットしない" + +msgid "CD-ROM images" +msgstr "CD-ROMイメージ" + +msgid "%hs Device Configuration" +msgstr "%hs デバイスの設定" + +msgid "Monitor in sleep mode" +msgstr "モニターのスリープモード" + +msgid "OpenGL Shaders" +msgstr "OpenGLシェーダー" + +msgid "OpenGL options" +msgstr "OpenGL設定" + +msgid "You are loading an unsupported configuration" +msgstr "サポートされていない設定を読み込んでいます" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "選択したマシンに基づくCPUタイプのフィルタリングは、このエミュレートされたマシンでは無効になっています。\n\nこれにより、選択したマシンと互換性のないCPUが選択できます。ただし、マシンのBIOSまたは他のソフトウェアとの互換性が失われる可能性があります。\n\nこの設定の有効化は公式サポートができません。また、バグレポートが無効として閉じられる場合があります。" + +msgid "Continue" +msgstr "続行" + +msgid "Cassette: %s" +msgstr "カセット: %s" + +msgid "Cassette images" +msgstr "カセットイメージ" + +msgid "Cartridge %i: %ls" +msgstr "カートリッジ %i: %ls" + +msgid "Cartridge images" +msgstr "カートリッジイメージ" + +msgid "Error initializing renderer" +msgstr "レンダラーの初期化エラー" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0コア) レンダラーが初期化できませんでした。別のレンダラーを使用してください。" + +msgid "Resume execution" +msgstr "実行を再開" + +msgid "Pause execution" +msgstr "実行を一時停止" + +msgid "Press Ctrl+Alt+Del" +msgstr "Ctrl+Alt+DELを押し" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Ctrl+Alt+Escを押し" + +msgid "Hard reset" +msgstr "ハードリセット" + +msgid "ACPI shutdown" +msgstr "ACPIシャットダウン" + +msgid "Hard disk (%s)" +msgstr "ハードディスク (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLLまたはESDIのCD-ROMドライブが存在しません" + +msgid "Custom..." +msgstr "カスタム..." + +msgid "Custom (large)..." +msgstr "カスタム (大型)..." + +msgid "Add New Hard Disk" +msgstr "新規のディスクを追加" + +msgid "Add Existing Hard Disk" +msgstr "既定のディスクを追加" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDIディスクイメージは4GBを超えることはできません。" + +msgid "Disk images cannot be larger than 127 GB." +msgstr "ディスクイメージは127GBを超えることはできません。" + +msgid "Hard disk images" +msgstr "ハードディスクイメージ" + +msgid "Unable to read file" +msgstr "ファイルの読み込みができません" + +msgid "Unable to write file" +msgstr "ファイルの書き込みができません" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "512以外のセクタサイズを持つHDIまたはHDXイメージはサポートされていません。" + +msgid "USB is not yet supported" +msgstr "USBはまだサポートされていません" + +msgid "Disk image file already exists" +msgstr "ディスクイメージファイルが既に存在します" + +msgid "Please specify a valid file name." +msgstr "有効なファイル名を指定してください。" + +msgid "Disk image created" +msgstr "ディスクイメージが作成されました" + +msgid "Make sure the file exists and is readable." +msgstr "ファイルが存在し、読み取り可能であることを確認してください。" + +msgid "Make sure the file is being saved to a writable directory." +msgstr "ファイルが書き込み可能なディレクトリに保存されていることを確認してください。" + +msgid "Disk image too large" +msgstr "ディスクイメージのサイズが大きすぎます" + +msgid "Remember to partition and format the newly-created drive." +msgstr "新規ドライブをパーティション分割し、フォーマットを必ずしといてください。" + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "選択したファイルが上書きされます。使っていいですか?" + +msgid "Unsupported disk image" +msgstr "サポートされていないディスクイメージ" + +msgid "Overwrite" +msgstr "上書き" + +msgid "Don't overwrite" +msgstr "上書きしない" + +msgid "Raw image (.img)" +msgstr "Rawイメージ (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDIイメージ (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDXイメージ (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD(容量固定)(.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD(容量可変)(.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD(差分)(.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "大型ブロック (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "小型ブロック (512 KB)" + +msgid "VHD files" +msgstr "VHDファイル" + +msgid "Select the parent VHD" +msgstr "親VHDの選択" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "親イメージがディファレンシングイメージの作成の後に修正した可能性があります。\n\nイメージファイルの移動、コピーまたはこのディスクを作成したプログラムにバグが発生した可能性があります。\n\nタイムスタンプを修正しますか?" + +msgid "Parent and child disk timestamps do not match" +msgstr "親ディスクと子ディスクのタイムスタンプが一致しません" + +msgid "Could not fix VHD timestamp." +msgstr "VHD のタイムスタンプを修正できませんでした。" + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (クラスター1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (クラスター2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "規定の回転数" + +msgid "1% below perfect RPM" +msgstr "1%低い回転数" + +msgid "1.5% below perfect RPM" +msgstr "1.5%低い回転数" + +msgid "2% below perfect RPM" +msgstr "2%低い回転数" + +msgid "(System Default)" +msgstr "(システム既定値)" + diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po new file mode 100644 index 000000000..bd5cd3e37 --- /dev/null +++ b/src/qt/languages/ko-KR.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "동작(&A)" + +msgid "&Keyboard requires capture" +msgstr "키보드는 캡쳐가 필요함(&K)" + +msgid "&Right CTRL is left ALT" +msgstr "우측CTRL로 좌측ALT 입력(&R)" + +msgid "&Hard Reset..." +msgstr "재시작(&H)..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+Esc(&E)" + +msgid "&Pause" +msgstr "일시정지(&P)" + +msgid "E&xit..." +msgstr "끝내기(&X)..." + +msgid "&View" +msgstr "표시(&V)" + +msgid "&Hide status bar" +msgstr "상태 바 숨기기(&H)" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "창 크기 조절 가능하게 하기(&R)" + +msgid "R&emember size && position" +msgstr "창 크기와 위치를 기억하기(&E)" + +msgid "Re&nderer" +msgstr "렌더러(&N)" + +msgid "&SDL (Software)" +msgstr "SDL (소프트웨어)(&S)" + +msgid "SDL (&Hardware)" +msgstr "SDL (하드웨어)(&H)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (OpenGL)(&O)" + +msgid "Open&GL (3.0 Core)" +msgstr "OpenGL (3.0 코어)(&G)" + +msgid "&VNC" +msgstr "VNC(&V)" + +msgid "Specify dimensions..." +msgstr "창 크기 지정하기..." + +msgid "F&orce 4:3 display ratio" +msgstr "화면 비율을 4:3으로 맞추기(&O)" + +msgid "&Window scale factor" +msgstr "창 표시 배율(&W)" + +msgid "&0.5x" +msgstr "0.5배(&0)" + +msgid "&1x" +msgstr "1배(&1)" + +msgid "1.&5x" +msgstr "1.5배(&5)" + +msgid "&2x" +msgstr "2배(&2)" + +msgid "Filter method" +msgstr "필터 형식" + +msgid "&Nearest" +msgstr "최근방 이웃 보간법(&N)" + +msgid "&Linear" +msgstr "선형 보간법(&L)" + +msgid "Hi&DPI scaling" +msgstr "HiDPI 스케일링(&D)" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "전체 화면(&F)\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "전체 화면 비율(&S)" + +msgid "&Full screen stretch" +msgstr "전체 화면으로 확대(&F)" + +msgid "&4:3" +msgstr "4:3(&4)" + +msgid "&Square pixels (Keep ratio)" +msgstr "정사각형 픽셀 (비율 유지)(&S)" + +msgid "&Integer scale" +msgstr "정수배 확대(&I)" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA 설정" + +msgid "&Inverted VGA monitor" +msgstr "색상 반전된 VGA 모니터(&I)" + +msgid "VGA screen &type" +msgstr "VGA 화면 종류(&T)" + +msgid "RGB &Color" +msgstr "RGB 천연색(&C)" + +msgid "&RGB Grayscale" +msgstr "RGB 회색조(&R)" + +msgid "&Amber monitor" +msgstr "주황색 모니터(&A)" + +msgid "&Green monitor" +msgstr "녹색 모니터(&G)" + +msgid "&White monitor" +msgstr "흰색 모니터(&W)" + +msgid "Grayscale &conversion type" +msgstr "회색조 표현방식(&C)" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT601 (NTSC/PAL)(&6)" + +msgid "BT&709 (HDTV)" +msgstr "BT709 (HDTV)(&7)" + +msgid "&Average" +msgstr "평균값(&A)" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/EGA/(S)VGA 오버스캔(&G)" + +msgid "Change contrast for &monochrome display" +msgstr "흑백 표시를 위한 밝기 조정(&M)" + +msgid "&Media" +msgstr "미디어(&M)" + +msgid "&Tools" +msgstr "도구(&T)" + +msgid "&Settings..." +msgstr "설정(&S)..." + +msgid "&Update status bar icons" +msgstr "상태 바 아이콘 갱신하기(&U)" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "스크린샷 찍기(&C)\tCtrl+F11" + +msgid "&Preferences..." +msgstr "환경설정(&P)..." + +msgid "Enable &Discord integration" +msgstr "디스코드 연동 활성화하기(&D)" + +msgid "Sound &gain..." +msgstr "음량 증폭(&G)..." + +msgid "Begin trace\tCtrl+T" +msgstr "추적 시작하기\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "추적 끝내기\tCtrl+T" + +msgid "&Help" +msgstr "도움말(&H)" + +msgid "&Documentation..." +msgstr "문서(&D)..." + +msgid "&About 86Box..." +msgstr "86Box에 대해(&A)..." + +msgid "&New image..." +msgstr "새 이미지(&N)..." + +msgid "&Existing image..." +msgstr "이미지 불러오기(&E)..." + +msgid "Existing image (&Write-protected)..." +msgstr "이미지 불러오기 (쓰기방지)(&W)..." + +msgid "&Record" +msgstr "녹음하기(&R)" + +msgid "&Play" +msgstr "재생하기(&P)" + +msgid "&Rewind to the beginning" +msgstr "맨앞으로 되감기(&R)" + +msgid "&Fast forward to the end" +msgstr "맨끝으로 빨리감기(&F)" + +msgid "E&ject" +msgstr "꺼내기(&J)" + +msgid "&Image..." +msgstr "이미지(&I)..." + +msgid "E&xport to 86F..." +msgstr "86F로 보내기(&X)..." + +msgid "&Mute" +msgstr "음소거(&M)" + +msgid "E&mpty" +msgstr "비었음(&M)" + +msgid "&Reload previous image" +msgstr "이전 이미지 다시 불러오기(&R)" + +msgid "&Image" +msgstr "이미지(&I)" + +msgid "Target &framerate" +msgstr "목표 프레임 레이트(&F)" + +msgid "&Sync with video" +msgstr "비디오와 동기(&S)" + +msgid "&25 fps" +msgstr "25 fps(&2)" + +msgid "&30 fps" +msgstr "30 fps(&3)" + +msgid "&50 fps" +msgstr "50 fps(&5)" + +msgid "&60 fps" +msgstr "60 fps(&6)" + +msgid "&75 fps" +msgstr "75 fps(&7)" + +msgid "&VSync" +msgstr "수직 동기화(&V)" + +msgid "&Select shader..." +msgstr "쉐이더 불러오기(&S)..." + +msgid "&Remove shader" +msgstr "쉐이더 끄기(&R)" + +msgid "Preferences" +msgstr "환경설정" + +msgid "Sound Gain" +msgstr "음량 증폭" + +msgid "New Image" +msgstr "새 이미지" + +msgid "Settings" +msgstr "설정" + +msgid "Specify Main Window Dimensions" +msgstr "창 크기 지정" + +msgid "OK" +msgstr "확인" + +msgid "Cancel" +msgstr "취소" + +msgid "Save these settings as &global defaults" +msgstr "이 설정들을 전역 기본값으로 저장하기(&G)" + +msgid "&Default" +msgstr "기본값(&D)" + +msgid "Language:" +msgstr "언어:" + +msgid "Icon set:" +msgstr "아이콘셋:" + +msgid "Gain" +msgstr "증가값" + +msgid "File name:" +msgstr "파일명:" + +msgid "Disk size:" +msgstr "디스크 용량:" + +msgid "RPM mode:" +msgstr "RPM 모드:" + +msgid "Progress:" +msgstr "진행:" + +msgid "Width:" +msgstr "가로:" + +msgid "Height:" +msgstr "세로:" + +msgid "Lock to this size" +msgstr "크기 고정" + +msgid "Machine type:" +msgstr "머신 종류:" + +msgid "Machine:" +msgstr "기종:" + +msgid "Configure" +msgstr "설정" + +msgid "CPU type:" +msgstr "CPU 종류:" + +msgid "Speed:" +msgstr "속도:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "대기 상태:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "메모리:" + +msgid "Time synchronization" +msgstr "시간 동기화" + +msgid "Disabled" +msgstr "사용하지 않음" + +msgid "Enabled (local time)" +msgstr "사용 (현지 시간)" + +msgid "Enabled (UTC)" +msgstr "사용 (UTC)" + +msgid "Dynamic Recompiler" +msgstr "동적 재컴파일" + +msgid "Video:" +msgstr "비디오 카드:" + +msgid "Voodoo Graphics" +msgstr "Voodoo 그래픽" + +msgid "Mouse:" +msgstr "마우스:" + +msgid "Joystick:" +msgstr "조이스틱:" + +msgid "Joystick 1..." +msgstr "조이스틱 1..." + +msgid "Joystick 2..." +msgstr "조이스틱 2..." + +msgid "Joystick 3..." +msgstr "조이스틱 3..." + +msgid "Joystick 4..." +msgstr "조이스틱 4..." + +msgid "Sound card:" +msgstr "사운드 카드:" + +msgid "MIDI Out Device:" +msgstr "MIDI 출력 장치:" + +msgid "MIDI In Device:" +msgstr "MIDI 입력 장치:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 단독 사용" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32 사운드 사용" + +msgid "Network type:" +msgstr "네트워크 종류:" + +msgid "PCap device:" +msgstr "PCap 장치:" + +msgid "Network adapter:" +msgstr "네트워크 어댑터:" + +msgid "COM1 Device:" +msgstr "COM1 장치:" + +msgid "COM2 Device:" +msgstr "COM2 장치:" + +msgid "COM3 Device:" +msgstr "COM3 장치:" + +msgid "COM4 Device:" +msgstr "COM4 장치:" + +msgid "LPT1 Device:" +msgstr "LPT1 장치:" + +msgid "LPT2 Device:" +msgstr "LPT2 장치:" + +msgid "LPT3 Device:" +msgstr "LPT3 장치:" + +msgid "LPT4 Device:" +msgstr "LPT4 장치:" + +msgid "Serial port 1" +msgstr "직렬 포트 1" + +msgid "Serial port 2" +msgstr "직렬 포트 2" + +msgid "Serial port 3" +msgstr "직렬 포트 3" + +msgid "Serial port 4" +msgstr "직렬 포트 4" + +msgid "Parallel port 1" +msgstr "병렬 포트 1" + +msgid "Parallel port 2" +msgstr "병렬 포트 2" + +msgid "Parallel port 3" +msgstr "병렬 포트 3" + +msgid "Parallel port 4" +msgstr "병렬 포트 4" + +msgid "HD Controller:" +msgstr "HD 컨트롤러:" + +msgid "FD Controller:" +msgstr "FD 컨트롤러:" + +msgid "Tertiary IDE Controller" +msgstr "제3의 IDE 컨트롤러" + +msgid "Quaternary IDE Controller" +msgstr "제4의 IDE 컨트롤러" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "컨트롤러 1:" + +msgid "Controller 2:" +msgstr "컨트롤러 2:" + +msgid "Controller 3:" +msgstr "컨트롤러 3:" + +msgid "Controller 4:" +msgstr "컨트롤러 4:" + +msgid "Cassette" +msgstr "카세트 테이프" + +msgid "Hard disks:" +msgstr "하드 디스크:" + +msgid "&New..." +msgstr "새로 만들기(&N)..." + +msgid "&Existing..." +msgstr "불러오기(&E)..." + +msgid "&Remove" +msgstr "목록에서 제거(&R)" + +msgid "Bus:" +msgstr "버스:" + +msgid "Channel:" +msgstr "채널:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "열기(&S)..." + +msgid "Sectors:" +msgstr "섹터:" + +msgid "Heads:" +msgstr "헤드:" + +msgid "Cylinders:" +msgstr "실린더:" + +msgid "Size (MB):" +msgstr "용량(MB):" + +msgid "Type:" +msgstr "형식:" + +msgid "Image Format:" +msgstr "이미지 포맷:" + +msgid "Block Size:" +msgstr "블록 크기:" + +msgid "Floppy drives:" +msgstr "플로피 드라이브:" + +msgid "Turbo timings" +msgstr "고속 동작" + +msgid "Check BPB" +msgstr "BPB 확인" + +msgid "CD-ROM drives:" +msgstr "CD-ROM 드라이브:" + +msgid "MO drives:" +msgstr "광자기 드라이브:" + +msgid "ZIP drives:" +msgstr "ZIP 드라이브:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC 카드:" + +msgid "ISA Memory Expansion" +msgstr "ISA 메모리 확장 카드" + +msgid "Card 1:" +msgstr "카드 1:" + +msgid "Card 2:" +msgstr "카드 2:" + +msgid "Card 3:" +msgstr "카드 3:" + +msgid "Card 4:" +msgstr "카드 4:" + +msgid "ISABugger device" +msgstr "ISABugger 장치" + +msgid "POST card" +msgstr "POST 카드" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Malgun Gothic" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "오류" + +msgid "Fatal error" +msgstr "치명적인 오류" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Ctrl+Alt+PgDn 키를 누르면 창 모드로 전환합니다." + +msgid "Speed" +msgstr "속도" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP 이미지" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box에서 사용 가능한 ROM 이미지를 찾을 수 없습니다.\n\nROM 세트를다운로드 후 \"roms\" 디렉토리에 압축을 풀어 주세요." + +msgid "(empty)" +msgstr "(비었음)" + +msgid "All files" +msgstr "모든 파일" + +msgid "Turbo" +msgstr "터보" + +msgid "On" +msgstr "켜짐" + +msgid "Off" +msgstr "꺼짐" + +msgid "All images" +msgstr "모든 이미지" + +msgid "Basic sector images" +msgstr "기본 섹터 이미지" + +msgid "Surface images" +msgstr "표면 이미지" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "roms/machines 디렉토리에 필요한 롬파일이 없어 기종 \"%hs\"을(를) 사용할 수 없습니다. 사용 가능한 기종으로 변경합니다." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "roms/video 디렉토리에 필요한 롬파일이 없어 비디오 카드 \"%hs\"을(를) 사용할 수 없습니다. 사용 가능한 기종으로 변경합니다." + +msgid "Machine" +msgstr "기종" + +msgid "Display" +msgstr "디스플레이" + +msgid "Input devices" +msgstr "입력 장치" + +msgid "Sound" +msgstr "사운드" + +msgid "Network" +msgstr "네트워크" + +msgid "Ports (COM & LPT)" +msgstr "포트 (COM & LPT)" + +msgid "Storage controllers" +msgstr "장치 컨트롤러" + +msgid "Hard disks" +msgstr "하드 디스크" + +msgid "Floppy & CD-ROM drives" +msgstr "플로피 / CD-ROM" + +msgid "Other removable devices" +msgstr "기타 이동식 저장장치" + +msgid "Other peripherals" +msgstr "기타 주변기기" + +msgid "Click to capture mouse" +msgstr "이 창을 클릭하면 마우스를 사용합니다" + +msgid "Press F8+F12 to release mouse" +msgstr "F12+F8키를 누르면 마우스를 해제합니다" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "F12+F8키 또는 가운데 버튼을 클릭하면 마우스를 해제합니다" + +msgid "Unable to initialize FluidSynth" +msgstr "FluidSynth를 초기화할 수 없습니다" + +msgid "Bus" +msgstr "버스" + +msgid "File" +msgstr "파일" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "비디오 렌더러를 초기화할 수 없습니다." + +msgid "Default" +msgstr "기본값" + +msgid "%i Wait state(s)" +msgstr "%i 대기 상태" + +msgid "Type" +msgstr "형식" + +msgid "Failed to set up PCap" +msgstr "PCap 설정에 실패했습니다" + +msgid "No PCap devices found" +msgstr "PCap 장치가 없습니다" + +msgid "Invalid PCap device" +msgstr "PCap 장치가 올바르지 않습니다" + +msgid "Standard 2-button joystick(s)" +msgstr "표준 2버튼 조이스틱" + +msgid "Standard 4-button joystick" +msgstr "표준 4버튼 조이스틱" + +msgid "Standard 6-button joystick" +msgstr "표준 6버튼 조이스틱" + +msgid "Standard 8-button joystick" +msgstr "표준 8버튼 조이스틱" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "없음" + +msgid "Unable to load keyboard accelerators." +msgstr "키보드 가속기를 불러올 수 없습니다." + +msgid "Unable to register raw input." +msgstr "Raw 입력을 등록할 수 없습니다." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "플로피 %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "어드밴스드 섹터 이미지" + +msgid "Flux images" +msgstr "플럭스 이미지" + +msgid "Unable to initialize FreeType" +msgstr "FreeType을 초기화할 수 없습니다" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "SDL을 초기화할 수 없습니다. SDL2.dll이 필요합니다" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "실행중인 머신을 재시작하시겠습니까?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "86Box를 끝내시겠습니까?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ghostscript를 초기화할 수 없습니다" + +msgid "MO %i (%ls): %ls" +msgstr "광자기 %i (%ls): %ls" + +msgid "MO images" +msgstr "광자기 이미지" + +msgid "Welcome to 86Box!" +msgstr "86Box에 어서오세요!" + +msgid "Internal controller" +msgstr "내부 컨트롤러" + +msgid "Exit" +msgstr "끝내기" + +msgid "No ROMs found" +msgstr "ROM을 불러올 수 없습니다" + +msgid "Do you want to save the settings?" +msgstr "설정을 저장하시겠습니까?" + +msgid "This will hard reset the emulated machine." +msgstr "사용중인 머신이 재부팅됩니다." + +msgid "Save" +msgstr "저장" + +msgid "About 86Box" +msgstr "86Box에 대해" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "고전 컴퓨터 에뮬레이터\n\n저자: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nGNU General Public 라이선스 (버전 2 이상)에 의해 배포되었습니다. 자세한 내용은 LICENSE 파일을 읽어 주세요." + +msgid "Hardware not available" +msgstr "하드웨어를 이용할 수 없습니다" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "이 설치되었는지 libpcap에 대응하는 네트워크에 접속되어 있는지 확인해 주세요." + +msgid "Invalid configuration" +msgstr "올바르지 않은 설정입니다" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr "ESC/P 프린터 에뮬레이션에 libfreetype이(가) 필요합니다." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr "은(는) PostScript 파일을 PDF로 자동변환하는 데에 필요합니다.\n\n표준 PostScript 프린터로 보내신 임의의 문서는 PostScript (.ps) 파일로 저장됩니다." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr "FluidSynth의 MIDI 출력에 libfluidsynth이(가) 필요합니다." + +msgid "Entering fullscreen mode" +msgstr "전체 화면으로 전환" + +msgid "Don't show this message again" +msgstr "이 메시지 그만 보기" + +msgid "Don't exit" +msgstr "끝내지 않기" + +msgid "Reset" +msgstr "재시작" + +msgid "Don't reset" +msgstr "재시작 안함" + +msgid "CD-ROM images" +msgstr "CD-ROM 이미지" + +msgid "%hs Device Configuration" +msgstr "%hs 장치 설정" + +msgid "Monitor in sleep mode" +msgstr "모니터 절전 모드" + +msgid "OpenGL Shaders" +msgstr "OpenGL 쉐이더" + +msgid "OpenGL options" +msgstr "OpenGL 설정" + +msgid "You are loading an unsupported configuration" +msgstr "지원하지 않는 설정입니다" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "이 에뮬레이트된 기종에 대해 선택한 기종을 기반으로 하는 CPU 종류 필터링이 사용되지 않도록 설정되었습니다.\n\n따라서 선택된 머신과 호환되지 않는 CPU를 선택하실 수 있습니다. 하지만 BIOS 또는 다른 소프트웨어와 호환되지 않을 수 있습니다.\n\n이 설정을 활성화하는 것은 공식적으로 지원되지 않으며, 제출된 버그 보고서는 유효하지 않음으로 닫힐 수 있습니다." + +msgid "Continue" +msgstr "계속" + +msgid "Cassette: %s" +msgstr "카세트: %s" + +msgid "Cassette images" +msgstr "카세트 이미지" + +msgid "Cartridge %i: %ls" +msgstr "카트리지 %i: %ls" + +msgid "Cartridge images" +msgstr "카트리지 이미지" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "하드 디스크 (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL 또는 ESDI CD-ROM 드라이브가 존재하지 않습니다" + +msgid "Custom..." +msgstr "사용자 설정..." + +msgid "Custom (large)..." +msgstr "사용자 설정 (대용량)..." + +msgid "Add New Hard Disk" +msgstr "새로 생성" + +msgid "Add Existing Hard Disk" +msgstr "기존 이미지 사용" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI 디스크 이미지는 4GB 이상으로 지정할 수 없습니다" + +msgid "Disk images cannot be larger than 127 GB." +msgstr "디스크 이미지는 127GB 이상으로 지정할 수 없습니다" + +msgid "Hard disk images" +msgstr "하드 디스크 이미지" + +msgid "Unable to read file" +msgstr "파일을 읽을 수 없습니다" + +msgid "Unable to write file" +msgstr "파일을 저장할 수 없습니다" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "512 바이트 이외의 섹터 크기를 가진 HDI 또는 HDX 형식의 이미지를 생성할 수 없습니다" + +msgid "USB is not yet supported" +msgstr "USB는 아직 지원하지 않습니다" + +msgid "Disk image file already exists" +msgstr "디스크 이미지 파일이 이미 존재합니다" + +msgid "Please specify a valid file name." +msgstr "올바른 파일명을 지정해 주세요." + +msgid "Disk image created" +msgstr "디스크 이미지가 생성되었습니다" + +msgid "Make sure the file exists and is readable." +msgstr "파일이 존재하며 읽을 수 있는지 확인합니다." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "파일이 쓰기 가능한 디렉토리에 저장되고 있는지 확인합니다." + +msgid "Disk image too large" +msgstr "디스크 이미지가 너무 큽니다" + +msgid "Remember to partition and format the newly-created drive." +msgstr "새로 생성한 드라이브의 파티션 설정과 포맷을 꼭 해주세요." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "선택하신 파일을 덮어씌웁니다. 사용하시겠습니까?" + +msgid "Unsupported disk image" +msgstr "지원하지 않는 디스크 이미지입니다" + +msgid "Overwrite" +msgstr "덮어쓰기" + +msgid "Don't overwrite" +msgstr "덮어쓰지 않음" + +msgid "Raw image (.img)" +msgstr "Raw 이미지 (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI 이미지 (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX 이미지 (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "고정 사이즈 VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "동적 사이즈 VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "디퍼런싱 VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "대형 블록 (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "소형 블록 (512 KB)" + +msgid "VHD files" +msgstr "VHD 파일" + +msgid "Select the parent VHD" +msgstr "부모 VHD 선택" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "이는 디퍼런싱 이미지가 생성된 후 부모 이미지가 수정되었음을 의미할 수 있습니다.\n\n이미지 파일이 이동 또는 복사된 경우 또는 이 디스크를 만든 프로그램의 버그로 인해 발생할 수도 있습니다.\n\n타임스탬프를 수정하시겠습니까?" + +msgid "Parent and child disk timestamps do not match" +msgstr "부모 디스크와 자식 디스크의 타임스탬프가 일치하지 않습니다" + +msgid "Could not fix VHD timestamp." +msgstr "VHD 타임스탬프를 고칠 수 없습니다" + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (클러스터 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (클러스터 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "완벽한 회전수" + +msgid "1% below perfect RPM" +msgstr "1% 낮은 회전수" + +msgid "1.5% below perfect RPM" +msgstr "1.5% 낮은 회전수" + +msgid "2% below perfect RPM" +msgstr "2% 낮은 회전수" + +msgid "(System Default)" +msgstr "(시스템 기본값)" + diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po new file mode 100644 index 000000000..5c60b1eda --- /dev/null +++ b/src/qt/languages/pl-PL.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Akcje" + +msgid "&Keyboard requires capture" +msgstr "&Klawaitura wymaga przechwytu myszy" + +msgid "&Right CTRL is left ALT" +msgstr "&Prawy CTRL to lewy Alt" + +msgid "&Hard Reset..." +msgstr "&Twardy reset..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pauza" + +msgid "E&xit..." +msgstr "W&yjdź..." + +msgid "&View" +msgstr "&Widok" + +msgid "&Hide status bar" +msgstr "&Ukryj pasek statusu" + +msgid "Hide &toolbar" +msgstr "Ukryj &pasek narzędzi" + +msgid "&Resizeable window" +msgstr "&Okno o zmiennym rozmiarze" + +msgid "R&emember size && position" +msgstr "P&amiętaj rozmiar &i pozycję" + +msgid "Re&nderer" +msgstr "Re&nderer" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Określ rozmiary..." + +msgid "F&orce 4:3 display ratio" +msgstr "&Wymuś proporcje wyświetlania 4:3" + +msgid "&Window scale factor" +msgstr "&Czynnik skalowania okna" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Metoda filtrowania" + +msgid "&Nearest" +msgstr "&Nearest" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Skalowanie Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Pełny ekran\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Fullscreen &stretch mode" + +msgid "&Full screen stretch" +msgstr "&Tryb rozciągania na pełnym ekranie" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Kwadratowe piksele (Zachowaj proporcje)" + +msgid "&Integer scale" +msgstr "&Skalowanie całkowite" + +msgid "E&GA/(S)VGA settings" +msgstr "Ustawienia E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Odwrócony monitor VGA" + +msgid "VGA screen &type" +msgstr "Rodzaj ekranu &VGA" + +msgid "RGB &Color" +msgstr "RGB - &Kolorowy" + +msgid "&RGB Grayscale" +msgstr "&RGB - Skala szarości" + +msgid "&Amber monitor" +msgstr "&Bursztynowy monitor" + +msgid "&Green monitor" +msgstr "&Zielony monitor" + +msgid "&White monitor" +msgstr "&Biały monitor" + +msgid "Grayscale &conversion type" +msgstr "Typ konwersji &w skali szarości" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Średni" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Overscan dla CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Zmień kontrast dla &monochromatycznego ekranu" + +msgid "&Media" +msgstr "&Nośnik" + +msgid "&Tools" +msgstr "&Narzędzia" + +msgid "&Settings..." +msgstr "&Ustawienia..." + +msgid "&Update status bar icons" +msgstr "&Aktualizuj ikony na pasku statusu" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Zrób &zrzut ekranu\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferencje..." + +msgid "Enable &Discord integration" +msgstr "Włącz integrację z &Discord" + +msgid "Sound &gain..." +msgstr "Wzmocnienie &dźwięku..." + +msgid "Begin trace\tCtrl+T" +msgstr "Rozpocznij śledzenie\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Zakończ śledzenie\tCtrl+T" + +msgid "&Help" +msgstr "&Pomoc" + +msgid "&Documentation..." +msgstr "&Dokumentacja..." + +msgid "&About 86Box..." +msgstr "&O 86Box..." + +msgid "&New image..." +msgstr "&Nowy obraz..." + +msgid "&Existing image..." +msgstr "&Istniejący obraz..." + +msgid "Existing image (&Write-protected)..." +msgstr "Istniejący obraz (&Chroniony przed zapisem)..." + +msgid "&Record" +msgstr "&Nagraj" + +msgid "&Play" +msgstr "&Odtwórz" + +msgid "&Rewind to the beginning" +msgstr "&Przewiń do początku" + +msgid "&Fast forward to the end" +msgstr "&Przewiń do końca" + +msgid "E&ject" +msgstr "W&yjmij" + +msgid "&Image..." +msgstr "&Obraz..." + +msgid "E&xport to 86F..." +msgstr "E&ksportuj do 86F..." + +msgid "&Mute" +msgstr "&Ścisz" + +msgid "E&mpty" +msgstr "P&usty" + +msgid "&Reload previous image" +msgstr "&Przeładuj poprzedni obraz" + +msgid "&Image" +msgstr "&Obraz" + +msgid "Target &framerate" +msgstr "Docelowa &liczba klatek na sekundę" + +msgid "&Sync with video" +msgstr "&Zsynchronizuj z wideo" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Wybierz shader..." + +msgid "&Remove shader" +msgstr "&Usuń shader" + +msgid "Preferences" +msgstr "Preferencje" + +msgid "Sound Gain" +msgstr "Wzmocnienie dźwięku" + +msgid "New Image" +msgstr "Nowy obraz" + +msgid "Settings" +msgstr "Ustawienia" + +msgid "Specify Main Window Dimensions" +msgstr "Określ rozmiary okna" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Anuluj" + +msgid "Save these settings as &global defaults" +msgstr "Zapisz ustawienia jako &globalne ustawienia domyślne" + +msgid "&Default" +msgstr "&Domyślny" + +msgid "Language:" +msgstr "Język:" + +msgid "Icon set:" +msgstr "Zestaw ikon:" + +msgid "Gain" +msgstr "Wzmacniacz" + +msgid "File name:" +msgstr "Nazwa pliku:" + +msgid "Disk size:" +msgstr "Rozmiar dysku:" + +msgid "RPM mode:" +msgstr "Tryb RPM:" + +msgid "Progress:" +msgstr "Postęp:" + +msgid "Width:" +msgstr "Szerokość:" + +msgid "Height:" +msgstr "Wysokość:" + +msgid "Lock to this size" +msgstr "Stały rozmiar" + +msgid "Machine type:" +msgstr "Rodzaj maszyny:" + +msgid "Machine:" +msgstr "Maszyna:" + +msgid "Configure" +msgstr "Konfiguruj" + +msgid "CPU type:" +msgstr "Rodzaj procesora:" + +msgid "Speed:" +msgstr "Szybkość:" + +msgid "FPU:" +msgstr "Jednostka FPU:" + +msgid "Wait states:" +msgstr "Stany oczekiwania:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Pamięć:" + +msgid "Time synchronization" +msgstr "Synchronizacja czasu" + +msgid "Disabled" +msgstr "Wyłączona" + +msgid "Enabled (local time)" +msgstr "Włączona (czas lokalny)" + +msgid "Enabled (UTC)" +msgstr "Włączona (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamiczny rekompilator" + +msgid "Video:" +msgstr "Wideo:" + +msgid "Voodoo Graphics" +msgstr "Grafika Voodoo" + +msgid "Mouse:" +msgstr "Mysz:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Karta dźwiękowa:" + +msgid "MIDI Out Device:" +msgstr "Urządzenie wyjściowe MIDI:" + +msgid "MIDI In Device:" +msgstr "Urządzenie wejściowe MIDI:" + +msgid "Standalone MPU-401" +msgstr "Samodzielne urządzenie MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Użyj dźwięku FLOAT32" + +msgid "Network type:" +msgstr "Rodzaj sieci:" + +msgid "PCap device:" +msgstr "Urządzenie PCap:" + +msgid "Network adapter:" +msgstr "Karta sieciowa:" + +msgid "COM1 Device:" +msgstr "Urządzenie COM1:" + +msgid "COM2 Device:" +msgstr "Urządzenie COM2:" + +msgid "COM3 Device:" +msgstr "Urządzenie COM3:" + +msgid "COM4 Device:" +msgstr "Urządzenie COM4:" + +msgid "LPT1 Device:" +msgstr "Urządzenie LPT1:" + +msgid "LPT2 Device:" +msgstr "Urządzenie LPT2:" + +msgid "LPT3 Device:" +msgstr "Urządzenie LPT3:" + +msgid "LPT4 Device:" +msgstr "Urządzenie LPT4:" + +msgid "Serial port 1" +msgstr "Port szeregowy 1" + +msgid "Serial port 2" +msgstr "Port szeregowy 2" + +msgid "Serial port 3" +msgstr "Port szeregowy 3" + +msgid "Serial port 4" +msgstr "Port Szeregowy 4" + +msgid "Parallel port 1" +msgstr "Port równoległy 1" + +msgid "Parallel port 2" +msgstr "Port równoległy 2" + +msgid "Parallel port 3" +msgstr "Port równoległy 3" + +msgid "Parallel port 4" +msgstr "Port równoległy 4" + +msgid "HD Controller:" +msgstr "Kontroler dysku twardego:" + +msgid "FD Controller:" +msgstr "Kontroler dyskietek:" + +msgid "Tertiary IDE Controller" +msgstr "Trzeciorzędowy kontroler IDE" + +msgid "Quaternary IDE Controller" +msgstr "Czwartorzędowy kontroler IDE" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Kontroler 1:" + +msgid "Controller 2:" +msgstr "Kontroler 2:" + +msgid "Controller 3:" +msgstr "Kontroler 3:" + +msgid "Controller 4:" +msgstr "Kontroler 4:" + +msgid "Cassette" +msgstr "Kaseta" + +msgid "Hard disks:" +msgstr "Dyski twarde:" + +msgid "&New..." +msgstr "&Nowy..." + +msgid "&Existing..." +msgstr "&Istniejący..." + +msgid "&Remove" +msgstr "&Usuń" + +msgid "Bus:" +msgstr "Magistrala:" + +msgid "Channel:" +msgstr "Kanał:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Określ..." + +msgid "Sectors:" +msgstr "Sektory:" + +msgid "Heads:" +msgstr "Głowice:" + +msgid "Cylinders:" +msgstr "Cylindry:" + +msgid "Size (MB):" +msgstr "Rozmiar (MB):" + +msgid "Type:" +msgstr "Rodzaj:" + +msgid "Image Format:" +msgstr "Format obrazu:" + +msgid "Block Size:" +msgstr "Rozmiar bloku:" + +msgid "Floppy drives:" +msgstr "Napędy dyskietek:" + +msgid "Turbo timings" +msgstr "Rozrządy Turbo" + +msgid "Check BPB" +msgstr "Sprawdzaj BPB" + +msgid "CD-ROM drives:" +msgstr "Napędy CD-ROM:" + +msgid "MO drives:" +msgstr "Napędy MO:" + +msgid "ZIP drives:" +msgstr "Napędy ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Rozszerzenie pamięci ISA" + +msgid "Card 1:" +msgstr "Karta 1:" + +msgid "Card 2:" +msgstr "Karta 2:" + +msgid "Card 3:" +msgstr "Karta 3:" + +msgid "Card 4:" +msgstr "Karta 4:" + +msgid "ISABugger device" +msgstr "Urządzenie ISABugger" + +msgid "POST card" +msgstr "Karta POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Błąd" + +msgid "Fatal error" +msgstr "Fatalny błąd" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Naciśnij klawisze Ctrl+Alt+PgDn aby wrócić to trybu okna." + +msgid "Speed" +msgstr "Szybkość" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Obrazy ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box nie może znaleźć obrazów ROM nadających się do użytku.\n\nProszę pobrać zestaw obrazów ROM ze strony download, i rozpakować je do katalogu \"roms\"." + +msgid "(empty)" +msgstr "(pusty)" + +msgid "All files" +msgstr "Wszystkie pliki" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Włącz" + +msgid "Off" +msgstr "Wyłącz" + +msgid "All images" +msgstr "Wszystkie obrazy" + +msgid "Basic sector images" +msgstr "Podstawowe obrazy sektorów" + +msgid "Surface images" +msgstr "Obrazy powierzchniowe" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Maszyna \"%hs\" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/machines. Przełączanie na dostępną maszynę." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Karta wideo \"%hs\" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/video. Przełączanie na dostępną kartę wideo." + +msgid "Machine" +msgstr "Maszyna" + +msgid "Display" +msgstr "Ekran" + +msgid "Input devices" +msgstr "Urządzenia wejściowe" + +msgid "Sound" +msgstr "Dźwięk" + +msgid "Network" +msgstr "Sieć" + +msgid "Ports (COM & LPT)" +msgstr "Porty (COM & LPT)" + +msgid "Storage controllers" +msgstr "Kontrolery pamięci" + +msgid "Hard disks" +msgstr "Dyski twarde" + +msgid "Floppy & CD-ROM drives" +msgstr "Napędy dyskietek i CD-ROM" + +msgid "Other removable devices" +msgstr "Inne urządzenia wymienne" + +msgid "Other peripherals" +msgstr "Inne urządzenia peryferyjne" + +msgid "Click to capture mouse" +msgstr "Kliknij w celu przechwycenia myszy" + +msgid "Press F8+F12 to release mouse" +msgstr "Naciśnij klawisze F8+F12 w celu uwolnienia myszy" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Naciśnij klawisze F8+F12 lub środkowy przycisk w celu uwolnienia myszy" + +msgid "Unable to initialize FluidSynth" +msgstr "Nie można zainicjować FluidSynth" + +msgid "Bus" +msgstr "Magistrala" + +msgid "File" +msgstr "Plik" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Nie można zainicjować renderera wideo." + +msgid "Default" +msgstr "Domyślny" + +msgid "%i Wait state(s)" +msgstr "%i Stany oczekiwania" + +msgid "Type" +msgstr "Rodzaj" + +msgid "Failed to set up PCap" +msgstr "Nie udało się ustawić PCap" + +msgid "No PCap devices found" +msgstr "Nie znaleziono urządzeń PCap" + +msgid "Invalid PCap device" +msgstr "Nieprawidłowe urządzenie PCap" + +msgid "Standard 2-button joystick(s)" +msgstr "Standardowe joysticki 2-przyciskowe" + +msgid "Standard 4-button joystick" +msgstr "Standardowy joystick 4-przyciskowy" + +msgid "Standard 6-button joystick" +msgstr "Standardowy joystick 6-przyciskowy" + +msgid "Standard 8-button joystick" +msgstr "Standardowy joystick 8-przyciskowy" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Żaden" + +msgid "Unable to load keyboard accelerators." +msgstr "Nie można załadować akceleratorów klawiaturowych." + +msgid "Unable to register raw input." +msgstr "Nie można zarejestrować surowych danych wejściowych." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Dyskietka %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Zaawansowane obrazy sektorów" + +msgid "Flux images" +msgstr "Flux images" + +msgid "Unable to initialize FreeType" +msgstr "Nie można zainicjować FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Nie można zainicjować SDL, wymagany SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Jesteś pewien że chcesz wykonać twardy reset emulowanej maszyny?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Jesteś pewien że chcesz zakończyć 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Nie można zainicjować Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "Obrazy MO" + +msgid "Welcome to 86Box!" +msgstr "Witamy w 86Box!" + +msgid "Internal controller" +msgstr "Kontroler wewnętrzny" + +msgid "Exit" +msgstr "Zakończ" + +msgid "No ROMs found" +msgstr "Nie znaleziono obrazów ROM" + +msgid "Do you want to save the settings?" +msgstr "Czy chcesz zapisać ustawienia?" + +msgid "This will hard reset the emulated machine." +msgstr "To spowoduje twardy reset wirtualnej maszyny." + +msgid "Save" +msgstr "Zapisz" + +msgid "About 86Box" +msgstr "O 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Emulator starych komputerów\n\nAutorzy: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, i inni.\n\nPrzetłumaczony przez: Fanta-Shokata\n\nWydany na licencji GNU General Public License w wersji 2 lub nowszej. Zobacz LICENSE aby uzyskać więcej informacji." + +msgid "Hardware not available" +msgstr "Sprzęt niedostępny" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Sprawdź, czy libpcap jest zainstalowany i czy posiadasz połączenie sieciowe kompatybilne z libpcap." + +msgid "Invalid configuration" +msgstr "Nieprawidłowa konfiguracja" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " jest wymagany do emulacji drukarki ESC-P." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " jest wymagany do automatycznej konwersji plików PostScript do PDF.\n\nDokumenty wysłane do ogólnej drukarki PostScript zostaną zapisane jako pliki PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " jest wymagany dla wyjścia FluidSynth MIDI." + +msgid "Entering fullscreen mode" +msgstr "Przechodzenie do trybu pełnoekranowego" + +msgid "Don't show this message again" +msgstr "Nie pokazuj więcej tego komunikatu" + +msgid "Don't exit" +msgstr "Nie kończ" + +msgid "Reset" +msgstr "Przywróć" + +msgid "Don't reset" +msgstr "Nie przywracaj" + +msgid "CD-ROM images" +msgstr "Obrazy CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Konfiguracja urządzenia %hs" + +msgid "Monitor in sleep mode" +msgstr "Monitor w trybie czuwania" + +msgid "OpenGL Shaders" +msgstr "Shadery OpenGL" + +msgid "OpenGL options" +msgstr "Opcje OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Ładujesz nieobsługiwaną konfigurację" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Wybór rodzaju procesora oparty na wybranej maszynie jest wyłączony dla tej emulowanej maszyny.\n\nPozwala to na wybór procesora który jest niekompatybilny z wybraną maszyną. Jednak możesz napotkać niezgodności z BIOS-em maszyny lub innym oprogramowaniem.\n\nAktywacja tego ustawienia nie jest wspierana i każde zgłoszenie błędu może zostać zamknięte jako nieważne." + +msgid "Continue" +msgstr "Kontynuuj" + +msgid "Cassette: %s" +msgstr "Kaseta: %s" + +msgid "Cassette images" +msgstr "Obrazy kaset" + +msgid "Cartridge %i: %ls" +msgstr "Kartrydż %i: %ls" + +msgid "Cartridge images" +msgstr "Obrazy kartrydżu" + +msgid "Error initializing renderer" +msgstr "Błąd inicjalizacji renderera" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "Nie można zainicjować renderera OpenGL (3.0 Core). Użyj innego." + +msgid "Resume execution" +msgstr "Wznów wykonywanie" + +msgid "Pause execution" +msgstr "Zatrzymaj wykonywanie" + +msgid "Press Ctrl+Alt+Del" +msgstr "Naciśnij Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Naciśnij Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Twardy reset" + +msgid "ACPI shutdown" +msgstr "Wyłączenie ACPI" + +msgid "Hard disk (%s)" +msgstr "Dysk twardy (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Napędy CD-ROM MFM/RLL lub ESDI nigdy nie istniały" + +msgid "Custom..." +msgstr "Niestandardowy..." + +msgid "Custom (large)..." +msgstr "Niestandardowy (duży)..." + +msgid "Add New Hard Disk" +msgstr "Dodaj nowy dysk twardy" + +msgid "Add Existing Hard Disk" +msgstr "Dodaj istniejący dysk twardy" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Obrazy dysków HDI nie mogą być większe niż 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Obrazy dysków nie mogą być większe niż 127 GB." + +msgid "Hard disk images" +msgstr "Obrazy dysku twardego" + +msgid "Unable to read file" +msgstr "Nie można odczytać pliku" + +msgid "Unable to write file" +msgstr "Nie można zapisać pliku" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Obrazy HDI lub HDX z rozmiarem sektora innym niż 512 nie są wspierane." + +msgid "USB is not yet supported" +msgstr "USB nie jest jeszcze wspierane" + +msgid "Disk image file already exists" +msgstr "Plik obrazu dysku już istnieje" + +msgid "Please specify a valid file name." +msgstr "Określ prawidłową nazwę pliku." + +msgid "Disk image created" +msgstr "Utworzono obraz dysku" + +msgid "Make sure the file exists and is readable." +msgstr "Sprawdź, czy plik istnieje i nadaje się do odczytu." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Sprawdź, czy plik jest zapiyswany w katalogu z możliwością zapisu." + +msgid "Disk image too large" +msgstr "Obraz dysku jest za duży" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Nie zapomnij o partycjonowaniu i sformatowaniu nowo utworzego dysku" + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Wybrany plik zostanie nadpisany. Czy na pewno chcesz użyć tego pliku?" + +msgid "Unsupported disk image" +msgstr "Niewspierany obraz dysku" + +msgid "Overwrite" +msgstr "Nadpisz" + +msgid "Don't overwrite" +msgstr "Nie nadpisuj" + +msgid "Raw image (.img)" +msgstr "Obraz surowy (.img)" + +msgid "HDI image (.hdi)" +msgstr "Obraz HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Obraz HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD o stałym rozmiarze (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD o dynamicznym rozmiarze (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD różnicujący (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Duże bloki (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Małe bloki (512 KB)" + +msgid "VHD files" +msgstr "Pliki VHD" + +msgid "Select the parent VHD" +msgstr "Wybierz nadrzędny plik VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Może to oznaczać, że obraz nadrzędny został zmodyfikowany po utworzeniu obrazu różnicującego.\n\nMoże się to również zdarzyć, jeśli pliki obrazów zostały przeniesione lub skopiowane, lub wystąpił błąd w programie, który utworzył ten dysk\n\nCzy chcesz naprawić sygnatury czasowe?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Sygnatury czasowe dysku nadrzędnego i podrzędnego nie zgadzają się" + +msgid "Could not fix VHD timestamp." +msgstr "Nie można naprawić sygnatury czasowej VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1,2 MB" + +msgid "1.25 MB" +msgstr "1,25 MB" + +msgid "1.44 MB" +msgstr "1,44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (klaster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (klaster 2048)" + +msgid "2.88 MB" +msgstr "2,88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1,3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2,3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1,3 GB" + +msgid "Perfect RPM" +msgstr "Idealne obroty" + +msgid "1% below perfect RPM" +msgstr "1% poniżej idealnych obrotów" + +msgid "1.5% below perfect RPM" +msgstr "1.5% poniżej idealnych obrotów" + +msgid "2% below perfect RPM" +msgstr "2% poniżej idealnych obrotów" + +msgid "(System Default)" +msgstr "(Domyślne ustawienie systemowe)" + diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po new file mode 100644 index 000000000..b7f325a9a --- /dev/null +++ b/src/qt/languages/pt-BR.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Ação" + +msgid "&Keyboard requires capture" +msgstr "&Teclado requer captura" + +msgid "&Right CTRL is left ALT" +msgstr "CTRL &direito é o ALT esquerdo" + +msgid "&Hard Reset..." +msgstr "&Reinicialização completa..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pausar" + +msgid "E&xit..." +msgstr "&Sair..." + +msgid "&View" +msgstr "&Exibir" + +msgid "&Hide status bar" +msgstr "&Ocultar barra de status" + +msgid "Hide &toolbar" +msgstr "Ocultar &barra de ferramenta" + +msgid "&Resizeable window" +msgstr "&Janela redimensionável" + +msgid "R&emember size && position" +msgstr "&Lembrar tamanho e posição" + +msgid "Re&nderer" +msgstr "&Renderizador" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (Núcleo 3.0)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Especificar as dimensões..." + +msgid "F&orce 4:3 display ratio" +msgstr "F&orçar proporção de tela em 4:3" + +msgid "&Window scale factor" +msgstr "&Fator de redimensionamento da janela" + +msgid "&0.5x" +msgstr "&0,5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1,&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Método de filtragem" + +msgid "&Nearest" +msgstr "&Mais próximo" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Escala Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Tela cheia\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Modo de &redimensionamento da tela cheia" + +msgid "&Full screen stretch" +msgstr "&Tela cheia esticada" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "Pixel&s quadrados (manter proporção)" + +msgid "&Integer scale" +msgstr "&Redimensionamento com valores inteiros" + +msgid "E&GA/(S)VGA settings" +msgstr "Configurações E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "Monitor VGA &invertido" + +msgid "VGA screen &type" +msgstr "&Tipo de tela VGA" + +msgid "RGB &Color" +msgstr "&Cores RGB" + +msgid "&RGB Grayscale" +msgstr "Tons de cinza &RGB" + +msgid "&Amber monitor" +msgstr "Monitor &âmbar" + +msgid "&Green monitor" +msgstr "Monitor &verde" + +msgid "&White monitor" +msgstr "Monitor &branco" + +msgid "Grayscale &conversion type" +msgstr "Tipo de &conversão de tons de cinza" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Média" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Overscan do CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Alterar contraste para exibição &monocromática" + +msgid "&Media" +msgstr "&Mídia" + +msgid "&Tools" +msgstr "&Ferramentas" + +msgid "&Settings..." +msgstr "&Configurações..." + +msgid "&Update status bar icons" +msgstr "&Atualizar ícones da barra de status" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Capturar &tela\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferências..." + +msgid "Enable &Discord integration" +msgstr "Ativar integração com o &Discord" + +msgid "Sound &gain..." +msgstr "&Ganho de som..." + +msgid "Begin trace\tCtrl+T" +msgstr "Inicio do rastreamento\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Fim do rastreamento\tCtrl+T" + +msgid "&Help" +msgstr "&Ajuda" + +msgid "&Documentation..." +msgstr "&Documentação..." + +msgid "&About 86Box..." +msgstr "&Sobre o 86Box..." + +msgid "&New image..." +msgstr "&Nova imagem..." + +msgid "&Existing image..." +msgstr "&Imagem existente..." + +msgid "Existing image (&Write-protected)..." +msgstr "Imagem existente (&protegida contra escrita)..." + +msgid "&Record" +msgstr "&Gravar" + +msgid "&Play" +msgstr "&Reproduzir" + +msgid "&Rewind to the beginning" +msgstr "&Rebobinar até o começo" + +msgid "&Fast forward to the end" +msgstr "&Avançar até o fim" + +msgid "E&ject" +msgstr "E&jetar" + +msgid "&Image..." +msgstr "&Imagem..." + +msgid "E&xport to 86F..." +msgstr "E&xportar para 86F..." + +msgid "&Mute" +msgstr "&Sem som" + +msgid "E&mpty" +msgstr "&Vazio" + +msgid "&Reload previous image" +msgstr "&Recarregar imagem anterior" + +msgid "&Image" +msgstr "&Imagem" + +msgid "Target &framerate" +msgstr "&Taxa de quadro pretendida" + +msgid "&Sync with video" +msgstr "&Sincronizar com vídeo" + +msgid "&25 fps" +msgstr "&25 qps" + +msgid "&30 fps" +msgstr "&30 qps" + +msgid "&50 fps" +msgstr "&50 qps" + +msgid "&60 fps" +msgstr "&60 qps" + +msgid "&75 fps" +msgstr "&75 qps" + +msgid "&VSync" +msgstr "Sincronização &vertical" + +msgid "&Select shader..." +msgstr "&Selecionar shader..." + +msgid "&Remove shader" +msgstr "&Remover shader" + +msgid "Preferences" +msgstr "Preferências" + +msgid "Sound Gain" +msgstr "Ganho de som" + +msgid "New Image" +msgstr "Nova imagem de disquete" + +msgid "Settings" +msgstr "Configurações" + +msgid "Specify Main Window Dimensions" +msgstr "Especifique as dimensões da janela principal" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Save these settings as &global defaults" +msgstr "Usar estas configurações como &padrões globais" + +msgid "&Default" +msgstr "&Padrão" + +msgid "Language:" +msgstr "Idioma:" + +msgid "Icon set:" +msgstr "Pacote de ícones:" + +msgid "Gain" +msgstr "Ganho" + +msgid "File name:" +msgstr "Nome:" + +msgid "Disk size:" +msgstr "Tamanho:" + +msgid "RPM mode:" +msgstr "Modo RPM:" + +msgid "Progress:" +msgstr "Progresso:" + +msgid "Width:" +msgstr "Largura:" + +msgid "Height:" +msgstr "Altura:" + +msgid "Lock to this size" +msgstr "Travar nesse tamanho" + +msgid "Machine type:" +msgstr "Tipo de máquina:" + +msgid "Machine:" +msgstr "Máquina:" + +msgid "Configure" +msgstr "Configurar" + +msgid "CPU type:" +msgstr "Tipo de CPU:" + +msgid "Speed:" +msgstr "Veloc.:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Estados de espera:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memória:" + +msgid "Time synchronization" +msgstr "Sincronização da hora" + +msgid "Disabled" +msgstr "Desativar" + +msgid "Enabled (local time)" +msgstr "Ativar (hora local)" + +msgid "Enabled (UTC)" +msgstr "Ativar (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Recompilador dinâmico" + +msgid "Video:" +msgstr "Vídeo:" + +msgid "Voodoo Graphics" +msgstr "3DFX Voodoo" + +msgid "Mouse:" +msgstr "Mouse:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Placa de som:" + +msgid "MIDI Out Device:" +msgstr "Disp. de saída MIDI:" + +msgid "MIDI In Device:" +msgstr "Disp. de entrada MIDI:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 autônomo" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Usar som FLOAT32" + +msgid "Network type:" +msgstr "Tipo de rede:" + +msgid "PCap device:" +msgstr "Dispositivo PCap:" + +msgid "Network adapter:" +msgstr "Adaptador de rede:" + +msgid "COM1 Device:" +msgstr "Dispositivo COM1:" + +msgid "COM2 Device:" +msgstr "Dispositivo COM2:" + +msgid "COM3 Device:" +msgstr "Dispositivo COM3:" + +msgid "COM4 Device:" +msgstr "Dispositivo COM4:" + +msgid "LPT1 Device:" +msgstr "Dispositivo LPT1:" + +msgid "LPT2 Device:" +msgstr "Dispositivo LPT2:" + +msgid "LPT3 Device:" +msgstr "Dispositivo LPT3:" + +msgid "LPT4 Device:" +msgstr "Dispositivo LPT4:" + +msgid "Serial port 1" +msgstr "Porta serial 1" + +msgid "Serial port 2" +msgstr "Porta serial 2" + +msgid "Serial port 3" +msgstr "Porta serial 3" + +msgid "Serial port 4" +msgstr "Porta serial 4" + +msgid "Parallel port 1" +msgstr "Porta paralela 1" + +msgid "Parallel port 2" +msgstr "Porta paralela 2" + +msgid "Parallel port 3" +msgstr "Porta paralela 3" + +msgid "Parallel port 4" +msgstr "Porta paralela 4" + +msgid "HD Controller:" +msgstr "Controlador HD:" + +msgid "FD Controller:" +msgstr "Controlador FD:" + +msgid "Tertiary IDE Controller" +msgstr "Controlador IDE terciário" + +msgid "Quaternary IDE Controller" +msgstr "Controlador IDE quaternário" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controlador 1:" + +msgid "Controller 2:" +msgstr "Controlador 2:" + +msgid "Controller 3:" +msgstr "Controlador 3:" + +msgid "Controller 4:" +msgstr "Controlador 4:" + +msgid "Cassette" +msgstr "Cassete" + +msgid "Hard disks:" +msgstr "Discos rígidos:" + +msgid "&New..." +msgstr "&Novo..." + +msgid "&Existing..." +msgstr "&Existente..." + +msgid "&Remove" +msgstr "&Remover" + +msgid "Bus:" +msgstr "Barramento:" + +msgid "Channel:" +msgstr "Canal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Especificar..." + +msgid "Sectors:" +msgstr "Setores:" + +msgid "Heads:" +msgstr "Cabeças:" + +msgid "Cylinders:" +msgstr "Cilindros:" + +msgid "Size (MB):" +msgstr "Tamanho (MB):" + +msgid "Type:" +msgstr "Tipo:" + +msgid "Image Format:" +msgstr "Formato:" + +msgid "Block Size:" +msgstr "Blocos:" + +msgid "Floppy drives:" +msgstr "Unidades de disquete:" + +msgid "Turbo timings" +msgstr "Turbo" + +msgid "Check BPB" +msgstr "Verificar BPB" + +msgid "CD-ROM drives:" +msgstr "Unidades de CD-ROM:" + +msgid "MO drives:" +msgstr "Unidades magneto-ópticas:" + +msgid "ZIP drives:" +msgstr "Unidades ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "RTC ISA:" + +msgid "ISA Memory Expansion" +msgstr "Expansão de memória ISA" + +msgid "Card 1:" +msgstr "Placa 1:" + +msgid "Card 2:" +msgstr "Placa 2:" + +msgid "Card 3:" +msgstr "Placa 3:" + +msgid "Card 4:" +msgstr "Placa 4:" + +msgid "ISABugger device" +msgstr "Dispositivo ISABugger" + +msgid "POST card" +msgstr "Placa de diagnóstico" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Erro" + +msgid "Fatal error" +msgstr "Erro fatal" + +msgid " - PAUSED" +msgstr " - PAUSADO" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Use Ctrl+Alt+PgDn para retornar ao modo janela" + +msgid "Speed" +msgstr "Velocidade" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Imagens ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "O 86Box não conseguiu encontrar nenhuma imagem de ROM utilizável.\n\nPor favor, baixe um conjunto de ROM e extraia no diretório \"roms\"." + +msgid "(empty)" +msgstr "(vazio)" + +msgid "All files" +msgstr "Todos os arquivos" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Lig." + +msgid "Off" +msgstr "Desl." + +msgid "All images" +msgstr "Todas as imagens" + +msgid "Basic sector images" +msgstr "Imagens de setor básico" + +msgid "Surface images" +msgstr "Imagens de superfície" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "A máquina \"%hs\" não está disponível devido à falta de ROMs no diretório roms/machines. Mudando para uma máquina disponível." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "A placa de vídeo \"%hs\" não está disponível devido à falta de ROMs no diretório roms/video. Mudando para uma placa de vídeo disponível." + +msgid "Machine" +msgstr "Máquina" + +msgid "Display" +msgstr "Vídeo" + +msgid "Input devices" +msgstr "Dispositivos de entrada" + +msgid "Sound" +msgstr "Som" + +msgid "Network" +msgstr "Rede" + +msgid "Ports (COM & LPT)" +msgstr "Portas (COM & LPT)" + +msgid "Storage controllers" +msgstr "Controladores de armaz." + +msgid "Hard disks" +msgstr "Discos rígidos" + +msgid "Floppy & CD-ROM drives" +msgstr "Disquete & CD-ROM" + +msgid "Other removable devices" +msgstr "Dispos. removíveis" + +msgid "Other peripherals" +msgstr "Outros periféricos" + +msgid "Click to capture mouse" +msgstr "Clique para capturar o mouse" + +msgid "Press F8+F12 to release mouse" +msgstr "Aperte F8+F12 para liberar o mouse" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Aperte F8+F12 ou botão do meio para liberar o mouse" + +msgid "Unable to initialize FluidSynth" +msgstr "Não foi possível inicializar o FluidSynth" + +msgid "Bus" +msgstr "Barramento" + +msgid "File" +msgstr "Arquivo" + +msgid "C" +msgstr "CI" + +msgid "H" +msgstr "CA" + +msgid "S" +msgstr "SE" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Não foi possível inicializar o renderizador de vídeo." + +msgid "Default" +msgstr "Padrão" + +msgid "%i Wait state(s)" +msgstr "%i estado(s) de espera" + +msgid "Type" +msgstr "Tipo" + +msgid "Failed to set up PCap" +msgstr "Não foi possível configurar o PCap" + +msgid "No PCap devices found" +msgstr "Nenhum dispositivo PCap encontrado" + +msgid "Invalid PCap device" +msgstr "Dispositivo PCap inválido" + +msgid "Standard 2-button joystick(s)" +msgstr "Joystick padrão de 2 botões" + +msgid "Standard 4-button joystick" +msgstr "Joystick padrão de 4 botões" + +msgid "Standard 6-button joystick" +msgstr "Joystick padrão de 6 botões" + +msgid "Standard 8-button joystick" +msgstr "Joystick padrão de 8 botões" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Sistema de Controle de Voo Thrustmaster" + +msgid "None" +msgstr "Nada" + +msgid "Unable to load keyboard accelerators." +msgstr "Não foi possível carregar os aceleradores do teclado." + +msgid "Unable to register raw input." +msgstr "Não foi possível registrar a entrada bruta." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disquete %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Imagens de setor avançado" + +msgid "Flux images" +msgstr "Imagens de fluxo" + +msgid "Unable to initialize FreeType" +msgstr "Não foi possível inicializar o FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Não é possível inicializar o SDL, é necessário o SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Tem certeza de que deseja reiniciar completamente a máquina emulada?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Tem certeza de que deseja sair do 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Não é possível inicializar o Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "Magneto-óptico %i (%ls): %ls" + +msgid "MO images" +msgstr "Imagens magneto-ópticas" + +msgid "Welcome to 86Box!" +msgstr "Bem-vindo ao 86Box!" + +msgid "Internal controller" +msgstr "Controlador interno" + +msgid "Exit" +msgstr "Sair" + +msgid "No ROMs found" +msgstr "Nenhum ROM encontrada" + +msgid "Do you want to save the settings?" +msgstr "Você deseja salvar as configurações?" + +msgid "This will hard reset the emulated machine." +msgstr "Isto fará com que a máquina emulada seja reinicializada." + +msgid "Save" +msgstr "Salvar" + +msgid "About 86Box" +msgstr "Sobre o 86Box" + +msgid "86Box v" +msgstr "86Box versão " + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Um emulador de computadores antigos\n\nAutores: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, e outros.\n\nTraduzido por: Altieres Lima da Silva\n\nLançado sob a Licença Pública Geral GNU versão 2 ou posterior. Veja o arquivo LICENSE para mais informações." + +msgid "Hardware not available" +msgstr "Hardware não disponível" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Certifique-se de que libpcap esteja instalado e que você tenha uma conexão de rede compatível com libpcap." + +msgid "Invalid configuration" +msgstr "Configuração inválida" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " é necessário para emulação de impressora ESC/P." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " é necessário para a conversão automática de arquivos PostScript para PDF.\n\nQualquer documento enviado para a impressora genérica PostScript será salvo como arquivos PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " é necessário para a saída MIDI FluidSynth." + +msgid "Entering fullscreen mode" +msgstr "Entrando no modo de tela cheia" + +msgid "Don't show this message again" +msgstr "Não exibir esta mensagem novamente" + +msgid "Don't exit" +msgstr "Não sair" + +msgid "Reset" +msgstr "Reiniciar" + +msgid "Don't reset" +msgstr "Não reiniciar" + +msgid "CD-ROM images" +msgstr "Imagens de CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Configuração do dispositivo %hs" + +msgid "Monitor in sleep mode" +msgstr "Monitor em modo de suspensão" + +msgid "OpenGL Shaders" +msgstr "Shaders OpenGL" + +msgid "OpenGL options" +msgstr "Opções do OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Você está carregando uma configuração não suportada" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "A filtragem do tipo CPU baseada na máquina selecionada é desativada para esta máquina emulada.\n\nIsto torna possível escolher uma CPU que de outra forma seria incompatível com a máquina selecionada. Entretanto, você pode encontrar incompatibilidades com a BIOS da máquina ou outro software.\n\nA ativação desta configuração não é oficialmente suportada e qualquer relatório de erro arquivado pode ser fechado como inválido." + +msgid "Continue" +msgstr "Continuar" + +msgid "Cassette: %s" +msgstr "Cassete: %s" + +msgid "Cassette images" +msgstr "Imagens de cassete" + +msgid "Cartridge %i: %ls" +msgstr "Cartucho %i: %ls" + +msgid "Cartridge images" +msgstr "Imagens de cartucho" + +msgid "Error initializing renderer" +msgstr "Erro ao inicializar o renderizador" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "O renderizador OpenGL (Núcleo 3.0) não pôde ser inicializado. Use outro renderizador." + +msgid "Resume execution" +msgstr "Continuar a execução" + +msgid "Pause execution" +msgstr "Pausar a execução" + +msgid "Press Ctrl+Alt+Del" +msgstr "Pressionar Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Pressionar Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Reinicialização completa" + +msgid "ACPI shutdown" +msgstr "Desligamento por ACPI" + +msgid "Hard disk (%s)" +msgstr "Disco rígido (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "As unidades de CD-ROM MFM/RLL ou ESDI nunca existiram" + +msgid "Custom..." +msgstr "Personalizado..." + +msgid "Custom (large)..." +msgstr "Personalizado (grande)..." + +msgid "Add New Hard Disk" +msgstr "Adicionar novo disco rígido" + +msgid "Add Existing Hard Disk" +msgstr "Adicionar disco rígido existente" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "As imagens de disco HDI não podem ser maiores do que 4GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "As imagens de disco não podem ser maiores do que 127GB." + +msgid "Hard disk images" +msgstr "Imagens de disco rígido" + +msgid "Unable to read file" +msgstr "Não foi possível ler o arquivo" + +msgid "Unable to write file" +msgstr "Não foi possível escrever o arquivo" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Imagens HDI ou HDX com um tamanho de setor que não seja 512 não são suportadas." + +msgid "USB is not yet supported" +msgstr "O USB ainda não é suportado" + +msgid "Disk image file already exists" +msgstr "Esta imagem existe" + +msgid "Please specify a valid file name." +msgstr "Digite um nome de arquivo válido." + +msgid "Disk image created" +msgstr "A imagem foi criada com sucesso" + +msgid "Make sure the file exists and is readable." +msgstr "Certifique-se de que o arquivo existe e é legível." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Certifique-se de que o arquivo está sendo salvo em um diretório gravável." + +msgid "Disk image too large" +msgstr "A imagem do disco é muito grande" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Lembre-se de particionar e formatar a unidade recém-criada." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "O arquivo selecionado será sobrescrito. Você tem certeza de que deseja usá-lo?" + +msgid "Unsupported disk image" +msgstr "Imagem de disco sem suporte" + +msgid "Overwrite" +msgstr "Sobrescrever" + +msgid "Don't overwrite" +msgstr "Não sobrescrever" + +msgid "Raw image (.img)" +msgstr "Imagem bruta (.img)" + +msgid "HDI image (.hdi)" +msgstr "Imagem HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Imagem HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD de tamanho fixo (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD de tamanho dinâmico (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD diferencial (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Blocos grandes (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Blocos pequenos (512 KB)" + +msgid "VHD files" +msgstr "Arquivos VHD" + +msgid "Select the parent VHD" +msgstr "Selecione o VHD pai" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Isto pode significar que a imagem de origem foi modificada após a criação da imagem diferencial.\n\nTambém pode acontecer caso os arquivos de imagem tenham sido movidos ou copiados, ou por um erro no programa que criou este disco.\n\nVocê quer consertar os marcadores de tempo?" + +msgid "Parent and child disk timestamps do not match" +msgstr "A data/hora dos arquivos de pais e filhos não correspondem" + +msgid "Could not fix VHD timestamp." +msgstr "Não foi possível consertar o carimbo de data/hora da VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "RPM perfeita" + +msgid "1% below perfect RPM" +msgstr "1% abaixo das RPM perfeita" + +msgid "1.5% below perfect RPM" +msgstr "1.5% abaixo das RPM perfeita" + +msgid "2% below perfect RPM" +msgstr "2% abaixo das RPM perfeita" + +msgid "(System Default)" +msgstr "(Padrão do sistema)" + diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po new file mode 100644 index 000000000..8497b935d --- /dev/null +++ b/src/qt/languages/pt-PT.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Ação" + +msgid "&Keyboard requires capture" +msgstr "&Teclado requere captura" + +msgid "&Right CTRL is left ALT" +msgstr "&CTRL direito é ALT esquerdo" + +msgid "&Hard Reset..." +msgstr "&Reinicialização completa..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pausa" + +msgid "E&xit..." +msgstr "&Sair..." + +msgid "&View" +msgstr "&Ver" + +msgid "&Hide status bar" +msgstr "&Ocultar barra de estado" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Janela redimensionável" + +msgid "R&emember size && position" +msgstr "&Lembrar tamanho e posição" + +msgid "Re&nderer" +msgstr "&Renderizador" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (Núcleo 3.0)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "&Especificar dimensões..." + +msgid "F&orce 4:3 display ratio" +msgstr "&Forçar rácio de visualização 4:3" + +msgid "&Window scale factor" +msgstr "F&actor de escala de janela" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Método de filtragem" + +msgid "&Nearest" +msgstr "&Mais próximo" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Escala Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "E&crã cheio\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Modo &de estiramento em ecrã cheio" + +msgid "&Full screen stretch" +msgstr "&Estiramento em ecrã cheio" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "Pixels &quadrados (Manter rácio)" + +msgid "&Integer scale" +msgstr "Escala &inteira" + +msgid "E&GA/(S)VGA settings" +msgstr "Definições E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "Monitor VGA &invertido" + +msgid "VGA screen &type" +msgstr "&Tipo de ecrã VGA" + +msgid "RGB &Color" +msgstr "&Cores RGB" + +msgid "&RGB Grayscale" +msgstr "&RGB em escala de cinzentos" + +msgid "&Amber monitor" +msgstr "Monitor âmb&ar" + +msgid "&Green monitor" +msgstr "Monitor &verde" + +msgid "&White monitor" +msgstr "Monitor &branco" + +msgid "Grayscale &conversion type" +msgstr "Tipo de &conversão para escala de cinzentos" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Media" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Overscan de CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Mudar &contraste para ecrã monocromático" + +msgid "&Media" +msgstr "&Media" + +msgid "&Tools" +msgstr "&Ferramentas" + +msgid "&Settings..." +msgstr "&Definições..." + +msgid "&Update status bar icons" +msgstr "&Atualizar ícones da barra de estado" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Gravar imagem de ecrã\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Preferências..." + +msgid "Enable &Discord integration" +msgstr "Ativar integração com &Discord" + +msgid "Sound &gain..." +msgstr "&Ganho de som..." + +msgid "Begin trace\tCtrl+T" +msgstr "Iniciar o rastreio\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Terminar o rastreio\tCtrl+T" + +msgid "&Help" +msgstr "&Ajuda" + +msgid "&Documentation..." +msgstr "&Documentação..." + +msgid "&About 86Box..." +msgstr "&Acerca do 86Box..." + +msgid "&New image..." +msgstr "&Nova imagem..." + +msgid "&Existing image..." +msgstr "Imagem &existente..." + +msgid "Existing image (&Write-protected)..." +msgstr "Imagem existente (&Proteção contra escrita)..." + +msgid "&Record" +msgstr "&Gravar" + +msgid "&Play" +msgstr "&Reproduzir" + +msgid "&Rewind to the beginning" +msgstr "Re&bobinar para o início" + +msgid "&Fast forward to the end" +msgstr "&Avanço rápido para o fim" + +msgid "E&ject" +msgstr "E&jetar" + +msgid "&Image..." +msgstr "&Imagem..." + +msgid "E&xport to 86F..." +msgstr "E&xportar para 86F..." + +msgid "&Mute" +msgstr "&Mute" + +msgid "E&mpty" +msgstr "&CDROM vazio" + +msgid "&Reload previous image" +msgstr "&Recarregar imagem anterior" + +msgid "&Image" +msgstr "&Imagem" + +msgid "Target &framerate" +msgstr "&Taxa de quadros de destino" + +msgid "&Sync with video" +msgstr "&Sincronizar com vídeo" + +msgid "&25 fps" +msgstr "&25 q/s" + +msgid "&30 fps" +msgstr "&30 q/s" + +msgid "&50 fps" +msgstr "&50 q/s" + +msgid "&60 fps" +msgstr "&60 q/s" + +msgid "&75 fps" +msgstr "&75 q/s" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Selecionar shader..." + +msgid "&Remove shader" +msgstr "&Remover shader" + +msgid "Preferences" +msgstr "Preferências" + +msgid "Sound Gain" +msgstr "Ganho de som" + +msgid "New Image" +msgstr "Nova imagem" + +msgid "Settings" +msgstr "Definições" + +msgid "Specify Main Window Dimensions" +msgstr "Especificar dimensões da janela principal" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Save these settings as &global defaults" +msgstr "Guardar estas definições como padrões &globais" + +msgid "&Default" +msgstr "&Padrão" + +msgid "Language:" +msgstr "Idioma:" + +msgid "Icon set:" +msgstr "Pacote de ícones:" + +msgid "Gain" +msgstr "Ganho" + +msgid "File name:" +msgstr "Nome:" + +msgid "Disk size:" +msgstr "Tamanho:" + +msgid "RPM mode:" +msgstr "Modo RPM:" + +msgid "Progress:" +msgstr "Progresso:" + +msgid "Width:" +msgstr "Largura:" + +msgid "Height:" +msgstr "Altura:" + +msgid "Lock to this size" +msgstr "Fixar neste tamanho" + +msgid "Machine type:" +msgstr "Tipo de máquina:" + +msgid "Machine:" +msgstr "Máquina:" + +msgid "Configure" +msgstr "Configurar" + +msgid "CPU type:" +msgstr "Tipo do CPU:" + +msgid "Speed:" +msgstr "Velocidade:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Estados de espera:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memória:" + +msgid "Time synchronization" +msgstr "Sincronização da hora" + +msgid "Disabled" +msgstr "Desativada" + +msgid "Enabled (local time)" +msgstr "Ativada (hora local)" + +msgid "Enabled (UTC)" +msgstr "Ativada (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Recompilador dinâmico" + +msgid "Video:" +msgstr "Vídeo:" + +msgid "Voodoo Graphics" +msgstr "Gráficos Voodoo" + +msgid "Mouse:" +msgstr "Rato:" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick 1..." +msgstr "Joystick 1..." + +msgid "Joystick 2..." +msgstr "Joystick 2..." + +msgid "Joystick 3..." +msgstr "Joystick 3..." + +msgid "Joystick 4..." +msgstr "Joystick 4..." + +msgid "Sound card:" +msgstr "Placa de som:" + +msgid "MIDI Out Device:" +msgstr "Disp. saída MIDI:" + +msgid "MIDI In Device:" +msgstr "Disp. entrada MIDI:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 autónomo" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Utilizar som FLOAT32" + +msgid "Network type:" +msgstr "Tipo de rede:" + +msgid "PCap device:" +msgstr "Dispositivo PCap:" + +msgid "Network adapter:" +msgstr "Placa de rede:" + +msgid "COM1 Device:" +msgstr "Dispositivo COM1:" + +msgid "COM2 Device:" +msgstr "Dispositivo COM2:" + +msgid "COM3 Device:" +msgstr "Dispositivo COM3:" + +msgid "COM4 Device:" +msgstr "Dispositivo COM4:" + +msgid "LPT1 Device:" +msgstr "Dispositivo LPT1:" + +msgid "LPT2 Device:" +msgstr "Dispositivo LPT2:" + +msgid "LPT3 Device:" +msgstr "Dispositivo LPT3:" + +msgid "LPT4 Device:" +msgstr "Dispositivo LPT4:" + +msgid "Serial port 1" +msgstr "Porta de série 1" + +msgid "Serial port 2" +msgstr "Porta de série 2" + +msgid "Serial port 3" +msgstr "Porta de série 3" + +msgid "Serial port 4" +msgstr "Porta de série 4" + +msgid "Parallel port 1" +msgstr "Porta paralela 1" + +msgid "Parallel port 2" +msgstr "Porta paralela 2" + +msgid "Parallel port 3" +msgstr "Porta paralela 3" + +msgid "Parallel port 4" +msgstr "Porta paralela 4" + +msgid "HD Controller:" +msgstr "Controlador HD:" + +msgid "FD Controller:" +msgstr "Controlador FD:" + +msgid "Tertiary IDE Controller" +msgstr "Controlador IDE terciário" + +msgid "Quaternary IDE Controller" +msgstr "Controlador IDE quaternário" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Controlador 1:" + +msgid "Controller 2:" +msgstr "Controlador 2:" + +msgid "Controller 3:" +msgstr "Controlador 3:" + +msgid "Controller 4:" +msgstr "Controlador 4:" + +msgid "Cassette" +msgstr "Cassete" + +msgid "Hard disks:" +msgstr "Discos rígidos:" + +msgid "&New..." +msgstr "&Novo..." + +msgid "&Existing..." +msgstr "&Existente..." + +msgid "&Remove" +msgstr "&Remover" + +msgid "Bus:" +msgstr "Barram.:" + +msgid "Channel:" +msgstr "Canal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Especificar..." + +msgid "Sectors:" +msgstr "Sectores:" + +msgid "Heads:" +msgstr "Cabeças:" + +msgid "Cylinders:" +msgstr "Cilindros:" + +msgid "Size (MB):" +msgstr "Tamanho (MB):" + +msgid "Type:" +msgstr "Tipo:" + +msgid "Image Format:" +msgstr "Formato de imagem:" + +msgid "Block Size:" +msgstr "Tamanho de bloco:" + +msgid "Floppy drives:" +msgstr "Unidades de disquete:" + +msgid "Turbo timings" +msgstr "Velocidade turbo" + +msgid "Check BPB" +msgstr "Verificar BPB" + +msgid "CD-ROM drives:" +msgstr "Unidades CD-ROM:" + +msgid "MO drives:" +msgstr "Unidades magneto-ópticas:" + +msgid "ZIP drives:" +msgstr "Unidades ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Expansão de memória ISA" + +msgid "Card 1:" +msgstr "Placa 1:" + +msgid "Card 2:" +msgstr "Placa 2:" + +msgid "Card 3:" +msgstr "Placa 3:" + +msgid "Card 4:" +msgstr "Placa 4:" + +msgid "ISABugger device" +msgstr "Dispositivo ISABugger" + +msgid "POST card" +msgstr "Placa POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Erro" + +msgid "Fatal error" +msgstr "Erro fatal" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Pressione Ctrl+Alt+PgDn para voltar ao modo de janela." + +msgid "Speed" +msgstr "Velocidade" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Imagens ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "O 86Box não conseguiu encontrar nenhuma imagem ROM utilizável.\n\nPor favor, vá descarregue um pacote ROM e instale-o na pasta \"roms\"." + +msgid "(empty)" +msgstr "(empty)" + +msgid "All files" +msgstr "Todos os ficheiros" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Ativado" + +msgid "Off" +msgstr "Desativado" + +msgid "All images" +msgstr "Todas as imagens" + +msgid "Basic sector images" +msgstr "Imagens básicas de sector" + +msgid "Surface images" +msgstr "Imagens de superfície" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "A máquina \"%hs\" não está disponível devido à falta de ROMs na pasta roms/machines. A mudar para uma máquina disponível." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "A placa vídeo \"%hs\" não está disponível devido à falta de ROMs na pasta roms/video. A mudar para uma placa vídeo disponível." + +msgid "Machine" +msgstr "Máquina" + +msgid "Display" +msgstr "Apresentação" + +msgid "Input devices" +msgstr "Dispositivos de entrada" + +msgid "Sound" +msgstr "Som" + +msgid "Network" +msgstr "Rede" + +msgid "Ports (COM & LPT)" +msgstr "Portas (COM e LPT)" + +msgid "Storage controllers" +msgstr "Dispositivos de armazenamento" + +msgid "Hard disks" +msgstr "Discos rígidos" + +msgid "Floppy & CD-ROM drives" +msgstr "Unidades de disquete e CD-ROM" + +msgid "Other removable devices" +msgstr "Outros dispostivos removíveis" + +msgid "Other peripherals" +msgstr "Outros dispositivos" + +msgid "Click to capture mouse" +msgstr "Clique para capturar o rato" + +msgid "Press F8+F12 to release mouse" +msgstr "Pressione F8+F12 para soltar o rato" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Pressione F8+F12 ou tecla média para soltar o rato" + +msgid "Unable to initialize FluidSynth" +msgstr "Não foi possível inicializar o FluidSynth" + +msgid "Bus" +msgstr "Barramento" + +msgid "File" +msgstr "Ficheiro" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "C" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Não foi possível inicializar o renderizador vídeo." + +msgid "Default" +msgstr "Padrão" + +msgid "%i Wait state(s)" +msgstr "%i estado(s) de espera" + +msgid "Type" +msgstr "Tipo" + +msgid "Failed to set up PCap" +msgstr "Falha na configuração de PCap" + +msgid "No PCap devices found" +msgstr "Não foi encontrado um dispositivo PCap" + +msgid "Invalid PCap device" +msgstr "Dispositivo PCap inválido" + +msgid "Standard 2-button joystick(s)" +msgstr "Joystick(s) standard de 2 botões" + +msgid "Standard 4-button joystick" +msgstr "Joystick(s) standard de 4 botões" + +msgid "Standard 6-button joystick" +msgstr "Joystick(s) standard de 6 botões" + +msgid "Standard 8-button joystick" +msgstr "Joystick(s) standard de 8 botões" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Nenhum" + +msgid "Unable to load keyboard accelerators." +msgstr "Não foi possível inicializar os aceleradores de teclado." + +msgid "Unable to register raw input." +msgstr "Não foi possível registar a entrada bruta." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CCS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disquete %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Imagens avançadas de sector" + +msgid "Flux images" +msgstr "Imagens de fluxo" + +msgid "Unable to initialize FreeType" +msgstr "Não foi possível inicializar o FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Não foi possível inicializar o SDL. O ficheiro SDL2.dll é necessário!" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Tem a certeza de que quer um reinício completo da máquina emulada?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Tem a certeza de que quer sair do 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Não foi possível inicializar o Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "Magneto-óptico %i (%ls): %ls" + +msgid "MO images" +msgstr "Imagens magneto-ópticas" + +msgid "Welcome to 86Box!" +msgstr "Bem-vindos ao 86Box!" + +msgid "Internal controller" +msgstr "Controlador interno" + +msgid "Exit" +msgstr "Sair" + +msgid "No ROMs found" +msgstr "Não foi encontrada nenhuma ROM" + +msgid "Do you want to save the settings?" +msgstr "Deseja guardar as definições?" + +msgid "This will hard reset the emulated machine." +msgstr "Isto irá causar um reinício completo da máquina emulada." + +msgid "Save" +msgstr "Guardar" + +msgid "About 86Box" +msgstr "Acerca do 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Um emulador de computadores antigos\n\nAutores: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nUsado sob a licença GNU General Public License versão 2 ou posterior. Veja o ficheiro LICENSE para mais informações." + +msgid "Hardware not available" +msgstr "Hardware não disponível" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Certifique-se de que a biblioteca libpcap está instalada e de que está a utilizar uma ligação de rede compatível com a biblioteca libpcap." + +msgid "Invalid configuration" +msgstr "Configuração inválida" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " é requerida para a emulação de impressora ESC/P." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " é requerido para a conversão automática de ficheiros PostScript para ficheiros PDF.\n\nQualquer documento enviado para a impressora PostScript genérica será gravado como um ficheiro PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " é necessário para a saída MIDI FluidSynth MIDI." + +msgid "Entering fullscreen mode" +msgstr "A entrar no modo de ecrã cheio" + +msgid "Don't show this message again" +msgstr "Não mostrar mais esta mensagem" + +msgid "Don't exit" +msgstr "Não sair" + +msgid "Reset" +msgstr "Reiniciar" + +msgid "Don't reset" +msgstr "Não reiniciar" + +msgid "CD-ROM images" +msgstr "Imagens CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Configuração de dispositivo %hs" + +msgid "Monitor in sleep mode" +msgstr "Ecrã em modo de sono" + +msgid "OpenGL Shaders" +msgstr "Shaders OpenGL" + +msgid "OpenGL options" +msgstr "Opções de OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Está a carregar uma configuração sem suporte!" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "A filtragem do tipo de CPU baseada na máquina escolhida está desativada para esta máquina emulada.\n\nIsto torna possível escolher um CPU que, de outra forma, não seria compatível com a máquina escolhida. No entanto, pode não ser compatível com a BIOS da máquina ou outros programas.\n\nA activação desta definição não tem suporte oficial e qualquer relatório de erros pode ser fechado como inválido." + +msgid "Continue" +msgstr "Continuar" + +msgid "Cassette: %s" +msgstr "Cassete: %s" + +msgid "Cassette images" +msgstr "Imagens de cassete" + +msgid "Cartridge %i: %ls" +msgstr "Cartucho %i: %ls" + +msgid "Cartridge images" +msgstr "Imagens de cartucho" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Disco rígido (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Unidades CD-ROM com barramento MFM/RLL ou ESDI nunca existiram!" + +msgid "Custom..." +msgstr "Personalizado..." + +msgid "Custom (large)..." +msgstr "Personalizado (grande)..." + +msgid "Add New Hard Disk" +msgstr "Adicionar novo disco rígido" + +msgid "Add Existing Hard Disk" +msgstr "Adicionar disco rígido existente" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "As imagens de disco HDI não podem ter mais de 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "As imagens de disco não podem ter mais de 127 GB." + +msgid "Hard disk images" +msgstr "Imagens de disco rígido" + +msgid "Unable to read file" +msgstr "Não foi possível ler o ficheiro" + +msgid "Unable to write file" +msgstr "Não foi possível escrever o ficheiro" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Imagens HDI ou HDX com um tamanho de sector diferente de 512 não são suportadas." + +msgid "USB is not yet supported" +msgstr "O barramento USB ainda não tem suporte" + +msgid "Disk image file already exists" +msgstr "A imagem de disco já existe" + +msgid "Please specify a valid file name." +msgstr "Por favor, especifique um nome de ficheiro válido." + +msgid "Disk image created" +msgstr "Imagem de disco criada" + +msgid "Make sure the file exists and is readable." +msgstr "Certifique-se de que o ficheiro existe e é legível." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Certifique-se de que o ficheiro está a ser guardado numa pasta editável." + +msgid "Disk image too large" +msgstr "Imagem de disco muito grande" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Lembre-se de particionar e formatar o novo disco criado." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "O ficheiro selecionado será sobrescrito. Tem a certeza de que quer utilizá-lo?" + +msgid "Unsupported disk image" +msgstr "Imagem de disco sem suporte" + +msgid "Overwrite" +msgstr "Sobrescrever" + +msgid "Don't overwrite" +msgstr "Não sobrescrever" + +msgid "Raw image (.img)" +msgstr "Imagem bruta (.img)" + +msgid "HDI image (.hdi)" +msgstr "Imagem HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Imagem HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD com tamanho fixo (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD com tamanho dinâmico (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD diferenciador (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Blocos grandes (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Blocos pequenos (512 KB)" + +msgid "VHD files" +msgstr "Ficheiros VHD" + +msgid "Select the parent VHD" +msgstr "Seleccione o VHD pai" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Isto pode significar que a imagem pai foi modificada depois da criação da imagem diferenciadora.\n\nTambém pode acontecer se os ficheiros da imagem foram movidos ou copiados ou por causa de um erro no programa que criou este disco.\n\nQuer corrigir os carimbos de data/hora?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Os carimbos de data/hora dos discos pai e filho não correspondem!" + +msgid "Could not fix VHD timestamp." +msgstr "Não foi possível corrigir o carimbo de data/hora do VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "RPM perfeito" + +msgid "1% below perfect RPM" +msgstr "RPM 1% abaixo do RPM perfeito" + +msgid "1.5% below perfect RPM" +msgstr "RPM 1.5% abaixo do RPM perfeito" + +msgid "2% below perfect RPM" +msgstr "RPM 2% abaixo do RPM perfeito" + +msgid "(System Default)" +msgstr "(Padrão do sistema)" + diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po new file mode 100644 index 000000000..a33cc81dd --- /dev/null +++ b/src/qt/languages/ru-RU.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Действие" + +msgid "&Keyboard requires capture" +msgstr "&Клавиатура требует захвата" + +msgid "&Right CTRL is left ALT" +msgstr "&Правый CTRL - это левый ALT" + +msgid "&Hard Reset..." +msgstr "&Холодная перезагрузка..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Пауза" + +msgid "E&xit..." +msgstr "&Выход..." + +msgid "&View" +msgstr "&Вид" + +msgid "&Hide status bar" +msgstr "&Скрыть строку состояния" + +msgid "Hide &toolbar" +msgstr "С&крыть панель инструментов" + +msgid "&Resizeable window" +msgstr "&Изменяемый размер окна" + +msgid "R&emember size && position" +msgstr "&Запомнить размер и положение" + +msgid "Re&nderer" +msgstr "&Рендеринг" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "&Указать размеры..." + +msgid "F&orce 4:3 display ratio" +msgstr "У&становить соотношение сторон 4:3" + +msgid "&Window scale factor" +msgstr "&Масштаб окна" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Метод фильтрации" + +msgid "&Nearest" +msgstr "&Ближайший" + +msgid "&Linear" +msgstr "&Линейный" + +msgid "Hi&DPI scaling" +msgstr "Масштабирование Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Полноэкранный режим\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "&Растягивание в полноэкранном режиме" + +msgid "&Full screen stretch" +msgstr "&На весь экран" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Квадратные пиксели (сохранить соотношение)" + +msgid "&Integer scale" +msgstr "&Целочисленное масштабирование" + +msgid "E&GA/(S)VGA settings" +msgstr "Настройки E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Инвертировать цвета VGA" + +msgid "VGA screen &type" +msgstr "&Тип экрана VGA" + +msgid "RGB &Color" +msgstr "RGB &цветной" + +msgid "&RGB Grayscale" +msgstr "&RGB монохромный" + +msgid "&Amber monitor" +msgstr "&Янтарный оттенок" + +msgid "&Green monitor" +msgstr "&Зелёный оттенок" + +msgid "&White monitor" +msgstr "&Белый оттенок" + +msgid "Grayscale &conversion type" +msgstr "Тип монохромного &конвертирования" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Усреднённый" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Вылеты развёртки CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Изменить контрастность &монохромного дисплея" + +msgid "&Media" +msgstr "&Носители" + +msgid "&Tools" +msgstr "&Инструменты" + +msgid "&Settings..." +msgstr "&Настройки машины..." + +msgid "&Update status bar icons" +msgstr "&Обновление значков строки состояния" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Сделать с&криншот\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Параметры..." + +msgid "Enable &Discord integration" +msgstr "Включить интеграцию &Discord" + +msgid "Sound &gain..." +msgstr "&Усиление звука..." + +msgid "Begin trace\tCtrl+T" +msgstr "Начать трассировку\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Завершить трассировку\tCtrl+T" + +msgid "&Help" +msgstr "&Помощь" + +msgid "&Documentation..." +msgstr "&Документация..." + +msgid "&About 86Box..." +msgstr "&О программе 86Box..." + +msgid "&New image..." +msgstr "&Новый образ..." + +msgid "&Existing image..." +msgstr "&Выбрать образ..." + +msgid "Existing image (&Write-protected)..." +msgstr "Выбрать образ (&Защита от записи)..." + +msgid "&Record" +msgstr "&Запись" + +msgid "&Play" +msgstr "&Воспроизведение" + +msgid "&Rewind to the beginning" +msgstr "&Перемотка на начало" + +msgid "&Fast forward to the end" +msgstr "&Перемотка в конец" + +msgid "E&ject" +msgstr "И&звлечь" + +msgid "&Image..." +msgstr "&Образ..." + +msgid "E&xport to 86F..." +msgstr "Э&кспорт в 86F..." + +msgid "&Mute" +msgstr "О&тключить звук" + +msgid "E&mpty" +msgstr "П&устой" + +msgid "&Reload previous image" +msgstr "&Снова загрузить предыдущий образ" + +msgid "&Image" +msgstr "&Образ..." + +msgid "Target &framerate" +msgstr "Целевая &частота кадров" + +msgid "&Sync with video" +msgstr "&Синхронизация с видео" + +msgid "&25 fps" +msgstr "&25 кадров в секунду" + +msgid "&30 fps" +msgstr "&30 кадров в секунду" + +msgid "&50 fps" +msgstr "&50 кадров в секунду" + +msgid "&60 fps" +msgstr "&60 кадров в секунду" + +msgid "&75 fps" +msgstr "&75 кадров в секунду" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Выбрать шейдер..." + +msgid "&Remove shader" +msgstr "&Удалить шейдер" + +msgid "Preferences" +msgstr "Параметры" + +msgid "Sound Gain" +msgstr "Усиление звука" + +msgid "New Image" +msgstr "Новый образ" + +msgid "Settings" +msgstr "Настройки" + +msgid "Specify Main Window Dimensions" +msgstr "Указать размеры главного окна" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Отмена" + +msgid "Save these settings as &global defaults" +msgstr "Сохранить эти параметры как &глобальные по умолчанию" + +msgid "&Default" +msgstr "&По умолчанию" + +msgid "Language:" +msgstr "Язык:" + +msgid "Icon set:" +msgstr "Набор иконок:" + +msgid "Gain" +msgstr "Усиление" + +msgid "File name:" +msgstr "Имя файла:" + +msgid "Disk size:" +msgstr "Размер диска:" + +msgid "RPM mode:" +msgstr "RPM режим:" + +msgid "Progress:" +msgstr "Прогресс:" + +msgid "Width:" +msgstr "Ширина:" + +msgid "Height:" +msgstr "Высота:" + +msgid "Lock to this size" +msgstr "Зафиксировать размер" + +msgid "Machine type:" +msgstr "Тип машины:" + +msgid "Machine:" +msgstr "Системная плата:" + +msgid "Configure" +msgstr "Настройка" + +msgid "CPU type:" +msgstr "Тип ЦП:" + +msgid "Speed:" +msgstr "Скорость:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Циклы ожидания:" + +msgid "MB" +msgstr "МБ" + +msgid "Memory:" +msgstr "Память:" + +msgid "Time synchronization" +msgstr "Синхронизация времени" + +msgid "Disabled" +msgstr "Отключить" + +msgid "Enabled (local time)" +msgstr "Включить (местное)" + +msgid "Enabled (UTC)" +msgstr "Включить (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Динамический рекомпилятор" + +msgid "Video:" +msgstr "Видеокарта:" + +msgid "Voodoo Graphics" +msgstr "Ускоритель Voodoo" + +msgid "Mouse:" +msgstr "Мышь:" + +msgid "Joystick:" +msgstr "Джойстик:" + +msgid "Joystick 1..." +msgstr "Джойстик 1..." + +msgid "Joystick 2..." +msgstr "Джойстик 2..." + +msgid "Joystick 3..." +msgstr "Джойстик 3..." + +msgid "Joystick 4..." +msgstr "Джойстик 4..." + +msgid "Sound card:" +msgstr "Звуковая карта:" + +msgid "MIDI Out Device:" +msgstr "MIDI Out устр-во:" + +msgid "MIDI In Device:" +msgstr "MIDI In устр-во:" + +msgid "Standalone MPU-401" +msgstr "Отдельный MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32 звук" + +msgid "Network type:" +msgstr "Тип сети:" + +msgid "PCap device:" +msgstr "Устройство PCap:" + +msgid "Network adapter:" +msgstr "Сетевая карта:" + +msgid "COM1 Device:" +msgstr "Устройство COM1:" + +msgid "COM2 Device:" +msgstr "Устройство COM2:" + +msgid "COM3 Device:" +msgstr "Устройство COM3:" + +msgid "COM4 Device:" +msgstr "Устройство COM4:" + +msgid "LPT1 Device:" +msgstr "Устройство LPT1:" + +msgid "LPT2 Device:" +msgstr "Устройство LPT2:" + +msgid "LPT3 Device:" +msgstr "Устройство LPT3:" + +msgid "LPT4 Device:" +msgstr "Устройство LPT4:" + +msgid "Serial port 1" +msgstr "Последов. порт COM1" + +msgid "Serial port 2" +msgstr "Последов. порт COM2" + +msgid "Serial port 3" +msgstr "Последов. порт COM3" + +msgid "Serial port 4" +msgstr "Последов. порт COM4" + +msgid "Parallel port 1" +msgstr "Параллельный порт LPT1" + +msgid "Parallel port 2" +msgstr "Параллельный порт LPT2" + +msgid "Parallel port 3" +msgstr "Параллельный порт LPT3" + +msgid "Parallel port 4" +msgstr "Параллельный порт LPT4" + +msgid "HD Controller:" +msgstr "Контроллер HD:" + +msgid "FD Controller:" +msgstr "Контроллер FD:" + +msgid "Tertiary IDE Controller" +msgstr "Третичный IDE контроллер" + +msgid "Quaternary IDE Controller" +msgstr "Четвертичный IDE контроллер" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Контроллер 1:" + +msgid "Controller 2:" +msgstr "Контроллер 2:" + +msgid "Controller 3:" +msgstr "Контроллер 3:" + +msgid "Controller 4:" +msgstr "Контроллер 4:" + +msgid "Cassette" +msgstr "Кассета" + +msgid "Hard disks:" +msgstr "Жёсткие диски:" + +msgid "&New..." +msgstr "&Создать..." + +msgid "&Existing..." +msgstr "&Выбрать..." + +msgid "&Remove" +msgstr "&Убрать" + +msgid "Bus:" +msgstr "Шина:" + +msgid "Channel:" +msgstr "Канал:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Указать..." + +msgid "Sectors:" +msgstr "Сектора:" + +msgid "Heads:" +msgstr "Головки:" + +msgid "Cylinders:" +msgstr "Цилиндры:" + +msgid "Size (MB):" +msgstr "Размер (МБ):" + +msgid "Type:" +msgstr "Тип:" + +msgid "Image Format:" +msgstr "Тип образа:" + +msgid "Block Size:" +msgstr "Размер блока:" + +msgid "Floppy drives:" +msgstr "Гибкие диски:" + +msgid "Turbo timings" +msgstr "Турбо тайминги" + +msgid "Check BPB" +msgstr "Проверять BPB" + +msgid "CD-ROM drives:" +msgstr "Дисководы CD-ROM:" + +msgid "MO drives:" +msgstr "Магнитооптические дисководы:" + +msgid "ZIP drives:" +msgstr "ZIP дисководы:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Карта расширения памяти (ISA)" + +msgid "Card 1:" +msgstr "Карта 1:" + +msgid "Card 2:" +msgstr "Карта 2:" + +msgid "Card 3:" +msgstr "Карта 3:" + +msgid "Card 4:" +msgstr "Карта 4:" + +msgid "ISABugger device" +msgstr "Устройство ISABugger" + +msgid "POST card" +msgstr "Карта POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Ошибка" + +msgid "Fatal error" +msgstr "Неустранимая ошибка" + +msgid " - PAUSED" +msgstr " - ПАУЗА" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Нажмите Ctrl+Alt+PgDn для возврата в оконный режим." + +msgid "Speed" +msgstr "Скорость" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Образы ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box не смог найти ни одного подходящего для использования файла с ПЗУ.\n\nПожалуйста скачайте набор ПЗУ и извлеките его в каталог \"roms\"." + +msgid "(empty)" +msgstr "(пусто)" + +msgid "All files" +msgstr "Все файлы" + +msgid "Turbo" +msgstr "Турбо" + +msgid "On" +msgstr "Вкл" + +msgid "Off" +msgstr "Выкл" + +msgid "All images" +msgstr "Все образы" + +msgid "Basic sector images" +msgstr "Простые посекторные образы" + +msgid "Surface images" +msgstr "Surface образы" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Системная плата \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/machines. Переключение на доступную системную плату." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Видеокарта \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Переключение на доступную видеокарту." + +msgid "Machine" +msgstr "Компьютер" + +msgid "Display" +msgstr "Дисплей" + +msgid "Input devices" +msgstr "Устройства ввода" + +msgid "Sound" +msgstr "Звук" + +msgid "Network" +msgstr "Сеть" + +msgid "Ports (COM & LPT)" +msgstr "Порты (COM и LPT)" + +msgid "Storage controllers" +msgstr "Контроллеры дисков" + +msgid "Hard disks" +msgstr "Жёсткие диски" + +msgid "Floppy & CD-ROM drives" +msgstr "Гибкие диски и CD-ROM" + +msgid "Other removable devices" +msgstr "Другие съёмные устр-ва" + +msgid "Other peripherals" +msgstr "Другая периферия" + +msgid "Click to capture mouse" +msgstr "Щёлкните мышью для захвата курсора" + +msgid "Press F8+F12 to release mouse" +msgstr "Нажмите F8+F12 чтобы освободить курсор" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Нажмите F8+F12 или среднюю кнопку мыши чтобы освободить курсор" + +msgid "Unable to initialize FluidSynth" +msgstr "Невозможно инициализировать FluidSynth" + +msgid "Bus" +msgstr "Шина" + +msgid "File" +msgstr "Файл" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "КБ" + +msgid "Could not initialize the video renderer." +msgstr "Не удалось инициализировать рендерер видео." + +msgid "Default" +msgstr "По умолчанию" + +msgid "%i Wait state(s)" +msgstr "%i WS" + +msgid "Type" +msgstr "Тип" + +msgid "Failed to set up PCap" +msgstr "Не удалось настроить PCap" + +msgid "No PCap devices found" +msgstr "Устройства PCap не найдены" + +msgid "Invalid PCap device" +msgstr "Неверное устройство PCap" + +msgid "Standard 2-button joystick(s)" +msgstr "Стандартный 2-кнопочный джойстик" + +msgid "Standard 4-button joystick" +msgstr "Стандартный 4-кнопочный джойстик" + +msgid "Standard 6-button joystick" +msgstr "Стандартный 6-кнопочный джойстик" + +msgid "Standard 8-button joystick" +msgstr "Стандартный 8-кнопочный джойстик" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Система управления полетом Thrustmaster" + +msgid "None" +msgstr "Нет" + +msgid "Unable to load keyboard accelerators." +msgstr "Невозможно загрузить ускорители клавиатуры." + +msgid "Unable to register raw input." +msgstr "Невозможно зарегистрировать необработанный (RAW) ввод." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u МБ (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Дисковод %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Расширенные образы секторов" + +msgid "Flux images" +msgstr "Образы Flux" + +msgid "Unable to initialize FreeType" +msgstr "Невозможно инициализировать FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Невозможно инициализировать SDL, требуется SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Вы уверены, что хотите выполнить холодную перезагрузку эмулируемой машины?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Вы уверены, что хотите выйти из 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Невозможно инициализировать Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "Магнитооптический %i (%ls): %ls" + +msgid "MO images" +msgstr "Образы магнитооптических дисков" + +msgid "Welcome to 86Box!" +msgstr "Добро пожаловать в 86Box!" + +msgid "Internal controller" +msgstr "Встроенный контроллер" + +msgid "Exit" +msgstr "Выход" + +msgid "No ROMs found" +msgstr "ПЗУ не найдены" + +msgid "Do you want to save the settings?" +msgstr "Хотите ли вы сохранить настройки?" + +msgid "This will hard reset the emulated machine." +msgstr "Это приведет к холодной перезагрузке эмулируемой машины." + +msgid "Save" +msgstr "Сохранить" + +msgid "About 86Box" +msgstr "О 86Box" + +msgid "86Box v" +msgstr "86Box v." + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Эмулятор старых компьютеров\n\nАвторы: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nВыпускается под лицензией GNU General Public License версии 2 или более поздней. Дополнительную информацию см. в файле LICENSE." + +msgid "Hardware not available" +msgstr "Оборудование недоступно" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Убедитесь, что libpcap установлен и ваше сетевое соединение, совместимо с libpcap." + +msgid "Invalid configuration" +msgstr "Недопустимая конфигурация" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr "Для эмуляции принтера ESC/P требуется libfreetype." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " требуется для автоматического преобразования файлов PostScript в PDF.\n\nВсе документы, отправленные на общий принтер PostScript, будут сохранены в виде файлов PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr "Для FluidSynth MIDI-вывода требуется libfluidsynth." + +msgid "Entering fullscreen mode" +msgstr "Вход в полноэкранный режим" + +msgid "Don't show this message again" +msgstr "Больше не показывать это сообщение" + +msgid "Don't exit" +msgstr "Не выходить" + +msgid "Reset" +msgstr "Перезагрузить" + +msgid "Don't reset" +msgstr "Не перезагружать" + +msgid "CD-ROM images" +msgstr "Образы CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Конфигурация устройства %hs" + +msgid "Monitor in sleep mode" +msgstr "Монитор в спящем режиме" + +msgid "OpenGL Shaders" +msgstr "Шейдеры OpenGL" + +msgid "OpenGL options" +msgstr "Параметры OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Вы загружаете неподдерживаемую конфигурацию" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Выбор типов ЦП для этой системной платы на данной эмулируемой машине отключен.\n\nЭто позволяет выбрать процессор, который в противном случае несовместим с выбранной материнской платой. Однако, вы можете столкнуться с несовместимостью с BIOS материнской платы или другим ПО.\n\nВключение этого параметра официально не поддерживается, и все поданные отчеты об ошибках могут быть закрыты как недействительные." + +msgid "Continue" +msgstr "Продолжить" + +msgid "Cassette: %s" +msgstr "Кассета: %s" + +msgid "Cassette images" +msgstr "Образы кассет" + +msgid "Cartridge %i: %ls" +msgstr "Картридж %i: %ls" + +msgid "Cartridge images" +msgstr "Образы картриджей" + +msgid "Error initializing renderer" +msgstr "Ошибка инициализации рендерера" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "Невозможно инициализировать рендерер OpenGL (3.0). Пожалуйста, используйте другой рендерер." + +msgid "Resume execution" +msgstr "Возобновить выполнение" + +msgid "Pause execution" +msgstr "Приостановить выполнение" + +msgid "Press Ctrl+Alt+Del" +msgstr "Нажать Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Нажать Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Холодная перезагрузка" + +msgid "ACPI shutdown" +msgstr "Сигнал завершения ACPI" + +msgid "Hard disk (%s)" +msgstr "Жёсткий диск (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL или ESDI дисководов CD-ROM никогда не существовало" + +msgid "Custom..." +msgstr "Задать вручную..." + +msgid "Custom (large)..." +msgstr "Задать вручную (large)..." + +msgid "Add New Hard Disk" +msgstr "Создать новый жёсткий диск" + +msgid "Add Existing Hard Disk" +msgstr "Выбрать существующий жёсткий диск" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Размер образов дисков HDI не может превышать 4 ГБ." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Размер образов дисков не может превышать 127 ГБ." + +msgid "Hard disk images" +msgstr "Образы жёстких дисков" + +msgid "Unable to read file" +msgstr "Невозможно прочитать файл" + +msgid "Unable to write file" +msgstr "Невозможно записать файл" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Образы HDI или HDX с размером сектора, отличным от 512, не поддерживаются." + +msgid "USB is not yet supported" +msgstr "USB пока не поддерживается" + +msgid "Disk image file already exists" +msgstr "Файл образа диска уже существует" + +msgid "Please specify a valid file name." +msgstr "Пожалуйста, укажите правильное имя файла." + +msgid "Disk image created" +msgstr "Образ диска создан" + +msgid "Make sure the file exists and is readable." +msgstr "Убедитесь, что файл существует и доступен для чтения." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Убедитесь, что файл сохраняется в директории доступной для записи." + +msgid "Disk image too large" +msgstr "Слишком большой образ диска" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Не забудьте разметить и отформатировать вновь созданный диск." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Выбранный файл будет перезаписан. Вы уверены, что хотите использовать его?" + +msgid "Unsupported disk image" +msgstr "Неподдерживаемый образ диска" + +msgid "Overwrite" +msgstr "Перезаписать" + +msgid "Don't overwrite" +msgstr "Не перезаписывать" + +msgid "Raw image (.img)" +msgstr "RAW образ (.img)" + +msgid "HDI image (.hdi)" +msgstr "Образ HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Образ HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD фиксированного размера (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD динамического размера (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Дифференцированный образ VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Большие блоки (2 МБ)" + +msgid "Small blocks (512 KB)" +msgstr "Маленькие блоки (512 КБ)" + +msgid "VHD files" +msgstr "Файлы VHD" + +msgid "Select the parent VHD" +msgstr "Выберите родительский VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Это может означать, что родительский образ был изменён после того, как был создан дифференцированный образ.\n\nЭто также может произойти, если файлы образа были перемещены или скопированы, или из-за ошибки в программе, создавшей этот диск.\n\nВы хотите исправить временные метки?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Временные метки родительского и дочернего дисков не совпадают" + +msgid "Could not fix VHD timestamp." +msgstr "Не удалось исправить временную метку VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 кБ" + +msgid "180 kB" +msgstr "180 кБ" + +msgid "320 kB" +msgstr "320 кБ" + +msgid "360 kB" +msgstr "360 кБ" + +msgid "640 kB" +msgstr "640 кБ" + +msgid "720 kB" +msgstr "720 кБ" + +msgid "1.2 MB" +msgstr "1.2 МБ" + +msgid "1.25 MB" +msgstr "1.25 МБ" + +msgid "1.44 MB" +msgstr "1.44 МБ" + +msgid "DMF (cluster 1024)" +msgstr "DMF (кластер 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (кластер 2048)" + +msgid "2.88 MB" +msgstr "2.88 МБ" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 МБ (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 МБ (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 МБ (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 МБ (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 ГБ (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 ГБ (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 МБ" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 МБ" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 ГБ" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 ГБ" + +msgid "Perfect RPM" +msgstr "Точный RPM" + +msgid "1% below perfect RPM" +msgstr "На 1% медленнее точного RPM" + +msgid "1.5% below perfect RPM" +msgstr "На 1.5% медленнее точного RPM" + +msgid "2% below perfect RPM" +msgstr "На 2% медленнее точного RPM" + +msgid "(System Default)" +msgstr "(Системный)" + diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po new file mode 100644 index 000000000..5a396c855 --- /dev/null +++ b/src/qt/languages/sl-SI.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Dejanja" + +msgid "&Keyboard requires capture" +msgstr "&Tipkovnica potrebuje zajem" + +msgid "&Right CTRL is left ALT" +msgstr "&Desni CTRL je levi ALT" + +msgid "&Hard Reset..." +msgstr "&Ponovni zagon..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Premor" + +msgid "E&xit..." +msgstr "Iz&hod..." + +msgid "&View" +msgstr "&Pogled" + +msgid "&Hide status bar" +msgstr "&Skrij statusno vrstico" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "S&premenljiva velikost okna" + +msgid "R&emember size && position" +msgstr "&Zapomni si velikost in položaj" + +msgid "Re&nderer" +msgstr "&Upodabljanje" + +msgid "&SDL (Software)" +msgstr "&SDL (programsko)" + +msgid "SDL (&Hardware)" +msgstr "SDL (s&trojno)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (Jedro 3.0)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "&Določi velikost..." + +msgid "F&orce 4:3 display ratio" +msgstr "&Vsili 4:3 razmerje zaslona" + +msgid "&Window scale factor" +msgstr "&Faktor velikosti okna" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "&Metoda filtriranja" + +msgid "&Nearest" +msgstr "&Najbližja" + +msgid "&Linear" +msgstr "&Linearna" + +msgid "Hi&DPI scaling" +msgstr "&Raztezanje za visok DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Celozaslonski način\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "&Način celozaslonskega raztezanja" + +msgid "&Full screen stretch" +msgstr "&Raztegni na celoten zaslon" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Kvadratni piksli (ohrani razmerje)" + +msgid "&Integer scale" +msgstr "&Celoštevilsko raztezanje" + +msgid "E&GA/(S)VGA settings" +msgstr "Nastavitve E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Obrni barve zaslona VGA" + +msgid "VGA screen &type" +msgstr "&Vrsta zaslona VGA" + +msgid "RGB &Color" +msgstr "&Barvni RGB" + +msgid "&RGB Grayscale" +msgstr "&Sivinski RGB" + +msgid "&Amber monitor" +msgstr "&Rumeni zaslon" + +msgid "&Green monitor" +msgstr "&Zeleni zaslon" + +msgid "&White monitor" +msgstr "B&eli zaslon" + +msgid "Grayscale &conversion type" +msgstr "V&rsta pretvorbe sivin" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Povprečje" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "&Presežek slike CGA/PCjr/Tandy/EGA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "&Spremeni contrast za črno-beli zaslon" + +msgid "&Media" +msgstr "&Mediji" + +msgid "&Tools" +msgstr "&Orodja" + +msgid "&Settings..." +msgstr "&Nastavitve..." + +msgid "&Update status bar icons" +msgstr "&Posodabljaj ikone statusne vrstice" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "&Zajemi posnetek zaslona\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Možnosti..." + +msgid "Enable &Discord integration" +msgstr "Omogoči integracijo s programom &Discord" + +msgid "Sound &gain..." +msgstr "&Ojačanje zvoka..." + +msgid "Begin trace\tCtrl+T" +msgstr "Z&ačni sledenje\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "&Končaj sledenje\tCtrl+T" + +msgid "&Help" +msgstr "&Pomoč" + +msgid "&Documentation..." +msgstr "&Dokumentacija..." + +msgid "&About 86Box..." +msgstr "&O programu 86Box..." + +msgid "&New image..." +msgstr "&Nova slika..." + +msgid "&Existing image..." +msgstr "&Obstoječa slika..." + +msgid "Existing image (&Write-protected)..." +msgstr "Obstoječa slika (&samo za branje)..." + +msgid "&Record" +msgstr "Snemaj" + +msgid "&Play" +msgstr "Predvajaj" + +msgid "&Rewind to the beginning" +msgstr "Previj na začetek" + +msgid "&Fast forward to the end" +msgstr "Preskoči na konec" + +msgid "E&ject" +msgstr "Izvrzi" + +msgid "&Image..." +msgstr "Slika..." + +msgid "E&xport to 86F..." +msgstr "&Izvozi v 86F..." + +msgid "&Mute" +msgstr "&Utišaj" + +msgid "E&mpty" +msgstr "&Prazen" + +msgid "&Reload previous image" +msgstr "&Naloži zadnjo sliko" + +msgid "&Image" +msgstr "&Slika" + +msgid "Target &framerate" +msgstr "&Ciljno št. sličic na sekundo" + +msgid "&Sync with video" +msgstr "&Sinhroniziraj z videom" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Izberi senčilnik..." + +msgid "&Remove shader" +msgstr "&Odstrani senčilnik" + +msgid "Preferences" +msgstr "Možnosti" + +msgid "Sound Gain" +msgstr "Ojačanje zvoka" + +msgid "New Image" +msgstr "Nova slika" + +msgid "Settings" +msgstr "Nastavitve" + +msgid "Specify Main Window Dimensions" +msgstr "Določi velikost glavnega okna" + +msgid "OK" +msgstr "V redu" + +msgid "Cancel" +msgstr "Prekliči" + +msgid "Save these settings as &global defaults" +msgstr "Shrani te nastavitve kot globalne privzete" + +msgid "&Default" +msgstr "Privzeto" + +msgid "Language:" +msgstr "Jezik:" + +msgid "Icon set:" +msgstr "Komplet ikon:" + +msgid "Gain" +msgstr "Ojačanje" + +msgid "File name:" +msgstr "Ime datoteke:" + +msgid "Disk size:" +msgstr "Velikost diska:" + +msgid "RPM mode:" +msgstr "Način števila obratov:" + +msgid "Progress:" +msgstr "Napredek:" + +msgid "Width:" +msgstr "Širina:" + +msgid "Height:" +msgstr "Višina:" + +msgid "Lock to this size" +msgstr "Zakleni na to velikost" + +msgid "Machine type:" +msgstr "Vrsta sistema:" + +msgid "Machine:" +msgstr "Sistem:" + +msgid "Configure" +msgstr "Nastavi" + +msgid "CPU type:" +msgstr "Vrsta procesorja:" + +msgid "Speed:" +msgstr "Hitrost:" + +msgid "FPU:" +msgstr "Procesor plavajoče vejice:" + +msgid "Wait states:" +msgstr "Čakalna stanja:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Spomin:" + +msgid "Time synchronization" +msgstr "Sinhronizacija časa" + +msgid "Disabled" +msgstr "Onemogočeno" + +msgid "Enabled (local time)" +msgstr "Omogočeno (lokalni čas)" + +msgid "Enabled (UTC)" +msgstr "Omogočeno (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dinamični prevajalnik" + +msgid "Video:" +msgstr "Video:" + +msgid "Voodoo Graphics" +msgstr "Voodoo grafika" + +msgid "Mouse:" +msgstr "Miška:" + +msgid "Joystick:" +msgstr "Igralna palica:" + +msgid "Joystick 1..." +msgstr "Igralna palica 1..." + +msgid "Joystick 2..." +msgstr "Igralna palica 2..." + +msgid "Joystick 3..." +msgstr "Igralna palica 3..." + +msgid "Joystick 4..." +msgstr "Igralna palica 4..." + +msgid "Sound card:" +msgstr "Zvočna kartica:" + +msgid "MIDI Out Device:" +msgstr "Izhodna naprava MIDI:" + +msgid "MIDI In Device:" +msgstr "Vhodna naprava MIDI:" + +msgid "Standalone MPU-401" +msgstr "Samostojen MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "Uporabi FLOAT32 za zvok" + +msgid "Network type:" +msgstr "Vrsta omrežja:" + +msgid "PCap device:" +msgstr "Naprava PCap:" + +msgid "Network adapter:" +msgstr "Omrežna kartica:" + +msgid "COM1 Device:" +msgstr "Naprava COM1:" + +msgid "COM2 Device:" +msgstr "Naprava COM2:" + +msgid "COM3 Device:" +msgstr "Naprava COM3:" + +msgid "COM4 Device:" +msgstr "Naprava COM4:" + +msgid "LPT1 Device:" +msgstr "Naprava LPT1:" + +msgid "LPT2 Device:" +msgstr "Naprava LPT2:" + +msgid "LPT3 Device:" +msgstr "Naprava LPT3:" + +msgid "LPT4 Device:" +msgstr "Naprava LPT4:" + +msgid "Serial port 1" +msgstr "Serijska vrata 1" + +msgid "Serial port 2" +msgstr "Serijska vrata 2" + +msgid "Serial port 3" +msgstr "Serijska vrata 3" + +msgid "Serial port 4" +msgstr "Serijska vrata 4" + +msgid "Parallel port 1" +msgstr "Paralelna vrata 1" + +msgid "Parallel port 2" +msgstr "Paralelna vrata 2" + +msgid "Parallel port 3" +msgstr "Paralelna vrata 3" + +msgid "Parallel port 4" +msgstr "Paralelna vrata 4" + +msgid "HD Controller:" +msgstr "Krmilnik trdega diska:" + +msgid "FD Controller:" +msgstr "Krmilnik disketnika:" + +msgid "Tertiary IDE Controller" +msgstr "Terciarni krmilnik IDE" + +msgid "Quaternary IDE Controller" +msgstr "Kvartarni krmilnik IDE" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Krmilnik 1:" + +msgid "Controller 2:" +msgstr "Krmilnik 2:" + +msgid "Controller 3:" +msgstr "Krmilnik 3:" + +msgid "Controller 4:" +msgstr "Krmilnik 4:" + +msgid "Cassette" +msgstr "Kasetnik" + +msgid "Hard disks:" +msgstr "Trdi diski:" + +msgid "&New..." +msgstr "Nov..." + +msgid "&Existing..." +msgstr "Obstoječ..." + +msgid "&Remove" +msgstr "Odstrani" + +msgid "Bus:" +msgstr "Vodilo:" + +msgid "Channel:" +msgstr "Kanal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "Določi..." + +msgid "Sectors:" +msgstr "Sektorji:" + +msgid "Heads:" +msgstr "Glave:" + +msgid "Cylinders:" +msgstr "Cilindri:" + +msgid "Size (MB):" +msgstr "Velikost (MB):" + +msgid "Type:" +msgstr "Vrsta:" + +msgid "Image Format:" +msgstr "Format slike:" + +msgid "Block Size:" +msgstr "Velikost bloka:" + +msgid "Floppy drives:" +msgstr "Disketni pogoni:" + +msgid "Turbo timings" +msgstr "Turbo časovniki" + +msgid "Check BPB" +msgstr "Preverjaj BPB" + +msgid "CD-ROM drives:" +msgstr "Pogoni CD-ROM:" + +msgid "MO drives:" +msgstr "Magnetno-optični pogoni:" + +msgid "ZIP drives:" +msgstr "Pogoni ZIP:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "Ura v realnem času ISA:" + +msgid "ISA Memory Expansion" +msgstr "Razširitev spomina ISA" + +msgid "Card 1:" +msgstr "Kartica 1:" + +msgid "Card 2:" +msgstr "Kartica 2:" + +msgid "Card 3:" +msgstr "Kartica 3:" + +msgid "Card 4:" +msgstr "Kartica 4:" + +msgid "ISABugger device" +msgstr "Naprava ISABugger" + +msgid "POST card" +msgstr "Kartica POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Napaka" + +msgid "Fatal error" +msgstr "Kritična napaka" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Pritisnite Ctrl+Alt+PgDn za povratek iz celozaslonskega načina." + +msgid "Speed" +msgstr "Hitrost" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP slike" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box ni našel nobenih uporabnih ROM slik.\n\nProsim prenesite set ROM-ov in ga razširite v mapo \"roms\"." + +msgid "(empty)" +msgstr "(prazno)" + +msgid "All files" +msgstr "Vse datoteke" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Vključeno" + +msgid "Off" +msgstr "Izključeno" + +msgid "All images" +msgstr "Vse slike" + +msgid "Basic sector images" +msgstr "Osnovne sektorske slike" + +msgid "Surface images" +msgstr "Površinske slike" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Sistem \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/machines. Preklapljam na drug sistem, ki je na voljo." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Grafična kartica \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/video. Preklapljam na drugo grafično kartico, ki je na voljo.." + +msgid "Machine" +msgstr "Sistem" + +msgid "Display" +msgstr "Zaslon" + +msgid "Input devices" +msgstr "Vhodne naprave" + +msgid "Sound" +msgstr "Zvok" + +msgid "Network" +msgstr "Omrežje" + +msgid "Ports (COM & LPT)" +msgstr "Vrata (COM & LPT)" + +msgid "Storage controllers" +msgstr "Krmilniki shrambe" + +msgid "Hard disks" +msgstr "Trdi diski" + +msgid "Floppy & CD-ROM drives" +msgstr "Disketni in CD-ROM pogoni" + +msgid "Other removable devices" +msgstr "Druge odstranljive naprave" + +msgid "Other peripherals" +msgstr "Druga periferija" + +msgid "Click to capture mouse" +msgstr "Kliknite za zajem miške" + +msgid "Press F8+F12 to release mouse" +msgstr "Pritisnite F8+F12 za izpust miške" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Pritisnite F8+F12 ali srednji gumb za izpust miške" + +msgid "Unable to initialize FluidSynth" +msgstr "Ne morem inicializirati FluidSynth" + +msgid "Bus" +msgstr "Vodilo" + +msgid "File" +msgstr "Datoteka" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Ne morem inicializirati pogona upodabljanja." + +msgid "Default" +msgstr "Privzeto" + +msgid "%i Wait state(s)" +msgstr "%i stanj čakanja" + +msgid "Type" +msgstr "Vrsta" + +msgid "Failed to set up PCap" +msgstr "Nastavitev PCap ni uspela" + +msgid "No PCap devices found" +msgstr "Nobena naprava PCap ni bila najdena" + +msgid "Invalid PCap device" +msgstr "Neveljavna naprava PCap" + +msgid "Standard 2-button joystick(s)" +msgstr "Standardna krmilna palica z 2 gumboma" + +msgid "Standard 4-button joystick" +msgstr "Standardna krmilna palica s 4 gumbi" + +msgid "Standard 6-button joystick" +msgstr "Standardna krmilna palica s 6 gumbi" + +msgid "Standard 8-button joystick" +msgstr "Standardna krmilna palica z 8 gumbi" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Brez" + +msgid "Unable to load keyboard accelerators." +msgstr "Ne morem naložiti pospeševalnikov tipkovnice." + +msgid "Unable to register raw input." +msgstr "Ne morem registrirati neobdelanega vnosa." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disketa %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Napredne sektorske slike" + +msgid "Flux images" +msgstr "Tokovne slike" + +msgid "Unable to initialize FreeType" +msgstr "Ne morem inicializirati FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Ne morem inicializirati SDL, potrebna je knjižica SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Ste prepričani, da želite ponovno zagnati emulirani sistem?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Ste prepričani, da želite zapreti 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ne morem inicializirati Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "Slike MO" + +msgid "Welcome to 86Box!" +msgstr "Dobrodošli v 86Box!" + +msgid "Internal controller" +msgstr "Notranji krmilnik" + +msgid "Exit" +msgstr "Izhod" + +msgid "No ROMs found" +msgstr "Nobeni ROM-i niso bili najdeni" + +msgid "Do you want to save the settings?" +msgstr "Želite shraniti nastavitve?" + +msgid "This will hard reset the emulated machine." +msgstr "To bo ponovno zagnalo emuliran sistem." + +msgid "Save" +msgstr "Shrani" + +msgid "About 86Box" +msgstr "O programu 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Emulator starih računalnikov\n\nAvtorji: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho in drugi.\n\nIzdano pod licenco GNU General Public License različica 2 ali novejša. Glej datoteko LICENSE za več informacij." + +msgid "Hardware not available" +msgstr "Strojna oprema ni na voljo" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Prepičajte se, da je nameščen libpcap in da ste na omrežni povezavi, združljivi z " + +msgid "Invalid configuration" +msgstr "Neveljavna konfiguracija" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " je potreben za emuliranje ESC/P tiskalnika." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " je potreben za samodejno pretvorbo PostScript datotek v PDF.\n\nVsi dokumenti, poslani generičnemu PostScript tiskalniku bodo shranjeni kot PostScript (.ps) datoteke." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " je potreben za FluidSynth MIDI izhod." + +msgid "Entering fullscreen mode" +msgstr "Preklapljam v celozaslonski način" + +msgid "Don't show this message again" +msgstr "Ne pokaži več tega sporočila" + +msgid "Don't exit" +msgstr "Prekliči izhod" + +msgid "Reset" +msgstr "Resetiraj" + +msgid "Don't reset" +msgstr "Ne resetiraj" + +msgid "CD-ROM images" +msgstr "Slike CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Konfiguracija naprave %hs" + +msgid "Monitor in sleep mode" +msgstr "Zaslon v načinu spanja" + +msgid "OpenGL Shaders" +msgstr "Senčilniki OpenGL" + +msgid "OpenGL options" +msgstr "Možnosti OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Nalagate nepodprto konfiguracijo" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Filtriranje vrste procesorja glede na izbran sistem je onemogočeno za ta emuliran sistem.\n\nTako lahko izberete procesor, ki je sicer nezdružljiv z izbranim sistemom. Vendar lahko naletite na nezdružljivosti z BIOS-om sistema ali drugo programsko opremo\n\nOmogočanje te nastavitve ni uradno podprto, vsa poročila o hroščih iz tega naslova pa bodo zaprta kot neveljavna." + +msgid "Continue" +msgstr "Nadaljuj" + +msgid "Cassette: %s" +msgstr "Kaseta: %s" + +msgid "Cassette images" +msgstr "Slike kaset" + +msgid "Cartridge %i: %ls" +msgstr "Spominski vložek %i: %ls" + +msgid "Cartridge images" +msgstr "Slike spominskega vložka" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Trdi disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL ali ESDI pogoni CD-ROM niso nikoli obstajali" + +msgid "Custom..." +msgstr "Po meri..." + +msgid "Custom (large)..." +msgstr "Po meri (velik)..." + +msgid "Add New Hard Disk" +msgstr "Dodaj nov trdi disk" + +msgid "Add Existing Hard Disk" +msgstr "Dodaj obstoječ trdi disk" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Slike diska HDI ne morejo biti večje od 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Slike diska ne morejo biti večje od 127 GB." + +msgid "Hard disk images" +msgstr "Slike trdega diska" + +msgid "Unable to read file" +msgstr "Ne morem prebrati datoteke" + +msgid "Unable to write file" +msgstr "Ne morem pisati v datoteko" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Slike HDI ali HDX, ki nimajo sektorjev velikosti 512 bajtov, niso podprte." + +msgid "USB is not yet supported" +msgstr "USB še ni podprt" + +msgid "Disk image file already exists" +msgstr "Datoteka s sliko diska že obstaja" + +msgid "Please specify a valid file name." +msgstr "Prosim, navedite veljavno ime datoteke." + +msgid "Disk image created" +msgstr "Slika diska ustvarjena" + +msgid "Make sure the file exists and is readable." +msgstr "Prepričajte se, da datoteka obstaja in je berljiva." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Prepričajte se, da datoteko shranjujete v zapisljivo mapo." + +msgid "Disk image too large" +msgstr "Slika diska je prevelika" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Ne pozabite na novem disku ustvariti particij in jih formatirati." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Izbrana datoteka bo prepisana. Ali jo res želite uporabiti?" + +msgid "Unsupported disk image" +msgstr "Nepodprta slika diska" + +msgid "Overwrite" +msgstr "Prepiši" + +msgid "Don't overwrite" +msgstr "Ne prepiši" + +msgid "Raw image (.img)" +msgstr "Surova slika (.img)" + +msgid "HDI image (.hdi)" +msgstr "Slika HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Slika HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD fiksne velikosti (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dinamičen VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Diferencialni VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Veliki bloki (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Mali bloki (512 KB)" + +msgid "VHD files" +msgstr "Datoteke VHD" + +msgid "Select the parent VHD" +msgstr "Izberite starševsko sliko VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "To lahko pomeni, da je bila starševska slika spremenjena potem, ko je že bila ustvarjena diferencialna slika.\n\nDo tega lahko pride tudi kadar so datoteke slik diska premaknjene ali kopirane, ali pa gre za hrošča v programu, ki je ustvaril ta disk.\n\nŽelite popraviti časovni žig?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Časovna žiga starševske slike diska in slike diska otroka se ne ujemata" + +msgid "Could not fix VHD timestamp." +msgstr "Ne morem popraviti časovnega žiga slike VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (grozd 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (grozd 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Popolni obrati na minuto" + +msgid "1% below perfect RPM" +msgstr "1% pod popolnimi obrati" + +msgid "1.5% below perfect RPM" +msgstr "1.5% pod popolnimi obrati" + +msgid "2% below perfect RPM" +msgstr "2% pod popolnimi obrati" + +msgid "(System Default)" +msgstr "(Sistemsko privzeto)" + diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po new file mode 100644 index 000000000..2a12b3d85 --- /dev/null +++ b/src/qt/languages/tr-TR.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Komutlar" + +msgid "&Keyboard requires capture" +msgstr "&Klavye sadece fare yakalandığında çalışsın" + +msgid "&Right CTRL is left ALT" +msgstr "&Sağ CTRL tuşunu sol ALT tuşu olarak ayarla" + +msgid "&Hard Reset..." +msgstr "&Makineyi yeniden başlat..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Duraklat" + +msgid "E&xit..." +msgstr "Emülatörden &çık..." + +msgid "&View" +msgstr "&Görüntüleme" + +msgid "&Hide status bar" +msgstr "&Durum çubuğunu gizle" + +msgid "Hide &toolbar" +msgstr "Hide &toolbar" + +msgid "&Resizeable window" +msgstr "&Yeniden boyutlandırılabilir pencere" + +msgid "R&emember size && position" +msgstr "&Pencere boyut ve pozisyonunu hatırla" + +msgid "Re&nderer" +msgstr "&İşleyici" + +msgid "&SDL (Software)" +msgstr "&SDL (Yazılım)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Donanım)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Pencere &boyutunu belirle..." + +msgid "F&orce 4:3 display ratio" +msgstr "&4:3 görüntüleme oranına zorla" + +msgid "&Window scale factor" +msgstr "Pencere &ölçek çarpanı" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "&Filtre metodu" + +msgid "&Nearest" +msgstr "&Nearest (En yakın)" + +msgid "&Linear" +msgstr "&Linear (Doğrusal)" + +msgid "Hi&DPI scaling" +msgstr "Hi&DPI ölçeklemesi" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Tam ekran\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "Tam ekran &germe modu" + +msgid "&Full screen stretch" +msgstr "&Tam ekrana ger" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Kare piksel (ölçeği koru)" + +msgid "&Integer scale" +msgstr "Tam &sayı ölçeklemesi" + +msgid "E&GA/(S)VGA settings" +msgstr "EGA/&(S)VGA ayarları" + +msgid "&Inverted VGA monitor" +msgstr "Ters &renk VGA monitör" + +msgid "VGA screen &type" +msgstr "VGA ekran &tipi" + +msgid "RGB &Color" +msgstr "RGB (&renkli)" + +msgid "&RGB Grayscale" +msgstr "RGB (&gri tonlama)" + +msgid "&Amber monitor" +msgstr "&Kehribar rengi monitör" + +msgid "&Green monitor" +msgstr "&Yeşil renk monitör" + +msgid "&White monitor" +msgstr "&Beyaz renk monitör" + +msgid "Grayscale &conversion type" +msgstr "&Gri tonlama dönüştürme tipi" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Ortalama" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA aşırı taraması" + +msgid "Change contrast for &monochrome display" +msgstr "Gri to&nlamalı görüntü için kontrastı değiştir" + +msgid "&Media" +msgstr "&Medya" + +msgid "&Tools" +msgstr "&Araçlar" + +msgid "&Settings..." +msgstr "&Ayarlar..." + +msgid "&Update status bar icons" +msgstr "Durum &çubuğu ikonlarını güncelle" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "&Ekran görüntüsü al\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Tercihler..." + +msgid "Enable &Discord integration" +msgstr "&Discord entegrasyonunu etkinleştir" + +msgid "Sound &gain..." +msgstr "&Ses yükseltici..." + +msgid "Begin trace\tCtrl+T" +msgstr "Begin trace\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "End trace\tCtrl+T" + +msgid "&Help" +msgstr "&Yardım" + +msgid "&Documentation..." +msgstr "&Dökümanlar..." + +msgid "&About 86Box..." +msgstr "&86Box Hakkında..." + +msgid "&New image..." +msgstr "&Yeni imaj oluştur..." + +msgid "&Existing image..." +msgstr "&İmaj seç..." + +msgid "Existing image (&Write-protected)..." +msgstr "İmaj &seç (Yazma-korumalı)..." + +msgid "&Record" +msgstr "&Kaydet" + +msgid "&Play" +msgstr "&Oynat" + +msgid "&Rewind to the beginning" +msgstr "&Başlangıca geri sar" + +msgid "&Fast forward to the end" +msgstr "Sona doğru &ileri sar" + +msgid "E&ject" +msgstr "&Çıkar" + +msgid "&Image..." +msgstr "&İmaj..." + +msgid "E&xport to 86F..." +msgstr "&86F dosyası olarak aktar..." + +msgid "&Mute" +msgstr "&Sesi kapat" + +msgid "E&mpty" +msgstr "İmajı &çıkar" + +msgid "&Reload previous image" +msgstr "&Önceki imajı seç" + +msgid "&Image" +msgstr "&İmaj seç" + +msgid "Target &framerate" +msgstr "Hedef &kare oranı" + +msgid "&Sync with video" +msgstr "Video ile &senkronize et" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "Gölgelendirici &seç..." + +msgid "&Remove shader" +msgstr "&Gölgelendiriciyi kaldır" + +msgid "Preferences" +msgstr "Tercihler" + +msgid "Sound Gain" +msgstr "Ses Artırma" + +msgid "New Image" +msgstr "Yeni İmaj" + +msgid "Settings" +msgstr "Ayarlar" + +msgid "Specify Main Window Dimensions" +msgstr "Ana Pencere Boyutunu Belirle" + +msgid "OK" +msgstr "Tamam" + +msgid "Cancel" +msgstr "İptal et" + +msgid "Save these settings as &global defaults" +msgstr "Bu ayarları &varsayılan olarak kaydet" + +msgid "&Default" +msgstr "&Varsayılan" + +msgid "Language:" +msgstr "Dil:" + +msgid "Icon set:" +msgstr "Simge seti:" + +msgid "Gain" +msgstr "Artırma" + +msgid "File name:" +msgstr "Dosya adı:" + +msgid "Disk size:" +msgstr "Disk boyutu:" + +msgid "RPM mode:" +msgstr "RPM modu:" + +msgid "Progress:" +msgstr "İşlem:" + +msgid "Width:" +msgstr "Genişlik:" + +msgid "Height:" +msgstr "Yükseklik:" + +msgid "Lock to this size" +msgstr "Bu boyuta kilitle" + +msgid "Machine type:" +msgstr "Makine türü:" + +msgid "Machine:" +msgstr "Makine:" + +msgid "Configure" +msgstr "Ayarla" + +msgid "CPU type:" +msgstr "CPU türü:" + +msgid "Speed:" +msgstr "Hız:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Bekleme süreleri:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Bellek:" + +msgid "Time synchronization" +msgstr "Zaman senkronizasyonu" + +msgid "Disabled" +msgstr "Devre dışı" + +msgid "Enabled (local time)" +msgstr "Etkin (yerel zaman)" + +msgid "Enabled (UTC)" +msgstr "Etkin (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dinamik Derleyici" + +msgid "Video:" +msgstr "Ekran kartı:" + +msgid "Voodoo Graphics" +msgstr "Voodoo Grafikleri" + +msgid "Mouse:" +msgstr "Fare:" + +msgid "Joystick:" +msgstr "Oyun kolu:" + +msgid "Joystick 1..." +msgstr "Oyun kolu 1..." + +msgid "Joystick 2..." +msgstr "Oyun kolu 2..." + +msgid "Joystick 3..." +msgstr "Oyun kolu 3..." + +msgid "Joystick 4..." +msgstr "Oyun kolu 4..." + +msgid "Sound card:" +msgstr "Ses kartı:" + +msgid "MIDI Out Device:" +msgstr "MIDI Çıkış Cihazı:" + +msgid "MIDI In Device:" +msgstr "MIDI Giriş Cihazı:" + +msgid "Standalone MPU-401" +msgstr "Bağımsız MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32 ses kullan" + +msgid "Network type:" +msgstr "Ağ tipi:" + +msgid "PCap device:" +msgstr "PCap cihazı:" + +msgid "Network adapter:" +msgstr "Ağ cihazı:" + +msgid "COM1 Device:" +msgstr "COM1 Cihazı:" + +msgid "COM2 Device:" +msgstr "COM2 Cihazı:" + +msgid "COM3 Device:" +msgstr "COM3 Cihazı:" + +msgid "COM4 Device:" +msgstr "COM4 Cihazı:" + +msgid "LPT1 Device:" +msgstr "LPT1 Cihazı:" + +msgid "LPT2 Device:" +msgstr "LPT2 Cihazı:" + +msgid "LPT3 Device:" +msgstr "LPT3 Cihazı:" + +msgid "LPT4 Device:" +msgstr "LPT4 Cihazı:" + +msgid "Serial port 1" +msgstr "Seri port 1" + +msgid "Serial port 2" +msgstr "Seri port 2" + +msgid "Serial port 3" +msgstr "Seri port 3" + +msgid "Serial port 4" +msgstr "Seri port 4" + +msgid "Parallel port 1" +msgstr "Paralel port 1" + +msgid "Parallel port 2" +msgstr "Paralel port 2" + +msgid "Parallel port 3" +msgstr "Paralel port 3" + +msgid "Parallel port 4" +msgstr "Paralel port 4" + +msgid "HD Controller:" +msgstr "HD Kontrolcüsü:" + +msgid "FD Controller:" +msgstr "FD Kontrolcüsü:" + +msgid "Tertiary IDE Controller" +msgstr "Üçlü IDE Kontrolcüsü" + +msgid "Quaternary IDE Controller" +msgstr "Dörtlü IDE Kontrolcüsü" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Kontrolcü 1:" + +msgid "Controller 2:" +msgstr "Kontrolcü 2:" + +msgid "Controller 3:" +msgstr "Kontrolcü 3:" + +msgid "Controller 4:" +msgstr "Kontrolcü 4:" + +msgid "Cassette" +msgstr "Kaset" + +msgid "Hard disks:" +msgstr "Hard diskler:" + +msgid "&New..." +msgstr "&Yeni..." + +msgid "&Existing..." +msgstr "&Var olan..." + +msgid "&Remove" +msgstr "&Kaldır" + +msgid "Bus:" +msgstr "Veri yolu:" + +msgid "Channel:" +msgstr "Kanal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Belirle..." + +msgid "Sectors:" +msgstr "Sektörler:" + +msgid "Heads:" +msgstr "Veri Kafaları:" + +msgid "Cylinders:" +msgstr "Silindirler:" + +msgid "Size (MB):" +msgstr "Boyut (MB):" + +msgid "Type:" +msgstr "Tip:" + +msgid "Image Format:" +msgstr "İmaj Düzeni:" + +msgid "Block Size:" +msgstr "Blok Boyutu:" + +msgid "Floppy drives:" +msgstr "Disket sürücüleri:" + +msgid "Turbo timings" +msgstr "Turbo zamanlamaları" + +msgid "Check BPB" +msgstr "BPB'yi denetle" + +msgid "CD-ROM drives:" +msgstr "CD-ROM sürücüleri:" + +msgid "MO drives:" +msgstr "MO sürücüleri:" + +msgid "ZIP drives:" +msgstr "ZIP sürücüleri:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "ISA Bellek Artırma" + +msgid "Card 1:" +msgstr "Kart 1:" + +msgid "Card 2:" +msgstr "Kart 2:" + +msgid "Card 3:" +msgstr "Kart 3:" + +msgid "Card 4:" +msgstr "Kart 4:" + +msgid "ISABugger device" +msgstr "ISABugger cihazı" + +msgid "POST card" +msgstr "POST kartı" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Hata" + +msgid "Fatal error" +msgstr "Kritik hata" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Pencere moduna geri dönmek için Ctrl+Alt+PgDn tuşlarına basın." + +msgid "Speed" +msgstr "Hız" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP imajları" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box hiç bir kullanılabilir ROM imajı bulamadı.\n\nLütfen ROM setini indirin ve onu \"Roms\" klasörüne çıkarın." + +msgid "(empty)" +msgstr "(empty)" + +msgid "All files" +msgstr "All files" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Açık" + +msgid "Off" +msgstr "Kapalı" + +msgid "All images" +msgstr "Tüm imajlar" + +msgid "Basic sector images" +msgstr "Basit sektör imajları" + +msgid "Surface images" +msgstr "Yüzey imajları" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "\"%hs\" makinesi roms/machines klasöründe mevcut olmayan ROM imajı yüzünden mevcut değil. Mevcut olan bir makineye geçiş yapılıyor." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "\"%hs\" ekran kartı roms/video klasöründe mevcut olmayan ROM imajı yüzünden mevcut değil. Mevcut olan bir ekran kartına geçiş yapılıyor." + +msgid "Machine" +msgstr "Makine" + +msgid "Display" +msgstr "Görüntü" + +msgid "Input devices" +msgstr "Giriş aygıtları" + +msgid "Sound" +msgstr "Ses" + +msgid "Network" +msgstr "Ağ" + +msgid "Ports (COM & LPT)" +msgstr "Portlar (COM & LPT)" + +msgid "Storage controllers" +msgstr "Depolama kontrolcüleri" + +msgid "Hard disks" +msgstr "Hard diskler" + +msgid "Floppy & CD-ROM drives" +msgstr "Disket & CD-ROM sürücüleri" + +msgid "Other removable devices" +msgstr "Diğer kaldırılabilir cihazlar" + +msgid "Other peripherals" +msgstr "Diğer cihazlar" + +msgid "Click to capture mouse" +msgstr "Farenin yakalanması için tıklayın" + +msgid "Press F8+F12 to release mouse" +msgstr "Farenin bırakılması için F8+F12 tuşlarına basın" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Farenin bırakılması için F8+F12 veya farenin orta tuşuna basın" + +msgid "Unable to initialize FluidSynth" +msgstr "FluidSynth başlatılamadı" + +msgid "Bus" +msgstr "Veri yolu" + +msgid "File" +msgstr "Dosya" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "Video işleyici başlatılamadı." + +msgid "Default" +msgstr "Varsayılan" + +msgid "%i Wait state(s)" +msgstr "%i Bekleme durumları" + +msgid "Type" +msgstr "Tür" + +msgid "Failed to set up PCap" +msgstr "PCap ayarlanamadı" + +msgid "No PCap devices found" +msgstr "Herhangi bir PCap cihazı bulunamadı" + +msgid "Invalid PCap device" +msgstr "Geçersiz PCap cihazı" + +msgid "Standard 2-button joystick(s)" +msgstr "Standart 2-button oyun kolları" + +msgid "Standard 4-button joystick" +msgstr "Standart 4-button oyun kolu" + +msgid "Standard 6-button joystick" +msgstr "Standart 6-button oyun kolu" + +msgid "Standard 8-button joystick" +msgstr "Standart 8-button oyun kolu" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Kontrol Sistemi" + +msgid "None" +msgstr "Hiçbiri" + +msgid "Unable to load keyboard accelerators." +msgstr "Klavye ivdirgeçleri yüklenemedi." + +msgid "Unable to register raw input." +msgstr "Ham girdi kaydedilemedi." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Disket %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Gelişmiş sektör imajları" + +msgid "Flux images" +msgstr "Flux images" + +msgid "Unable to initialize FreeType" +msgstr "FreeType başlatılamadı" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "SDL başlatılamadı, SDL2.dll gerekmektedir" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Emüle edilen makineyi yeniden başlatmak istediğinizden emin misiniz?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "86Box'tan çıkmak istediğinize emin misiniz?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ghostscript başlatılamadı" + +msgid "MO %i (%ls): %ls" +msgstr "MO %i (%ls): %ls" + +msgid "MO images" +msgstr "MO imajları" + +msgid "Welcome to 86Box!" +msgstr "86Box'a hoşgeldiniz!" + +msgid "Internal controller" +msgstr "Dahili kontrolcü" + +msgid "Exit" +msgstr "Çıkış" + +msgid "No ROMs found" +msgstr "Hiçbir ROM imajı bulunamadı" + +msgid "Do you want to save the settings?" +msgstr "Ayarları kaydetmek istediğinizden emin misiniz?" + +msgid "This will hard reset the emulated machine." +msgstr "Bu makineyi yeniden başlatacak." + +msgid "Save" +msgstr "Kaydet" + +msgid "About 86Box" +msgstr "86Box Hakkında" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Bir eski bilgisayar emülatörü\n\nYapanlar: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, ve diğerleri.\n\nGNU Genel Kamu Lisansı versiyon 2 veya sonrası altında yayınlanmıştır. Daha fazla bilgi için LICENSE'ı gözden geçirin." + +msgid "Hardware not available" +msgstr "Donanım mevcut değil" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "libpcap kurulu olduğundan ve libpcap-uyumlu bir internet ağında bulunduğunuzdan emin olun." + +msgid "Invalid configuration" +msgstr "Geçersiz konfigürasyon" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr " ESC/P yazıcı emülasyonu için gereklidir." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " PostScript dosyalarının otomatik olarak PDF dosyalarına çevirilmesi için gereklidir.\n\nGenel PostScript yazıcısına gönderilen tüm dökümanlar PostScript (.ps) dosyaları olarak kaydedilecektir." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr " FluidSynth MIDI çıkışı için gereklidir." + +msgid "Entering fullscreen mode" +msgstr "Tam ekran moduna geçiliyor" + +msgid "Don't show this message again" +msgstr "Bu mesajı bir daha gösterme" + +msgid "Don't exit" +msgstr "Çıkış yapma" + +msgid "Reset" +msgstr "Yeniden başlat" + +msgid "Don't reset" +msgstr "Yeniden başlatma" + +msgid "CD-ROM images" +msgstr "CD-ROM imajları" + +msgid "%hs Device Configuration" +msgstr "%hs Cihaz Konfigürasyonu" + +msgid "Monitor in sleep mode" +msgstr "Monitör uyku modunda" + +msgid "OpenGL Shaders" +msgstr "OpenGL Gölgelendiricileri" + +msgid "OpenGL options" +msgstr "OpenGL ayarları" + +msgid "You are loading an unsupported configuration" +msgstr "Desteklenmeyen bir konfigürasyon yüklüyorsunuz" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Seçtiğiniz makineye uygun CPU (işlemci) türü filtrelemesi bu emülasyon için devre dışı bırakıldı.\n\nBu, normalde seçilen makine ile uyumlu olmayan bir CPU seçmenizi mümkün kılmaktadır. Ancak, bundan dolayı seçilen makinenin BIOS'u veya diğer yazılımlar ile uyumsuzluk sorunu yaşayabilirsiniz.\n\nBu filtrelemeyi devre dışı bırakmak emülatör tarafından resmi olarak desteklenmemektedir ve açtığınız bug (hata) raporları geçersiz olarak kapatılabilir." + +msgid "Continue" +msgstr "Devam et" + +msgid "Cassette: %s" +msgstr "Kaset: %s" + +msgid "Cassette images" +msgstr "Kaset imajları" + +msgid "Cartridge %i: %ls" +msgstr "Kartuş %i: %ls" + +msgid "Cartridge images" +msgstr "Kartuş imajları" + +msgid "Error initializing renderer" +msgstr "Error initializing renderer" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + +msgid "Resume execution" +msgstr "Resume execution" + +msgid "Pause execution" +msgstr "Pause execution" + +msgid "Press Ctrl+Alt+Del" +msgstr "Press Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Press Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hard reset" + +msgid "ACPI shutdown" +msgstr "ACPI shutdown" + +msgid "Hard disk (%s)" +msgstr "Hard disk (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL veya ESDI CD-ROM sürücüleri hiçbir zaman var olmamıştır" + +msgid "Custom..." +msgstr "Diğer..." + +msgid "Custom (large)..." +msgstr "Diğer (büyük)..." + +msgid "Add New Hard Disk" +msgstr "Yeni Hard Disk Dosyası Oluştur" + +msgid "Add Existing Hard Disk" +msgstr "Var Olan Hard Disk Dosyası Ekle" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI disk imajları 4 GB'tan daha büyük olamaz." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Disk imajları 127 GB'tan daha büyük olamaz." + +msgid "Hard disk images" +msgstr "Hard disk imajları" + +msgid "Unable to read file" +msgstr "Dosya okunamıyor" + +msgid "Unable to write file" +msgstr "Dosyanın üzerine yazılamıyor" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "512 dışında sektör boyutu olan HDI veya HDX imajları desteklenmemektedir." + +msgid "USB is not yet supported" +msgstr "USB şu anda desteklenmemektedir" + +msgid "Disk image file already exists" +msgstr "Disk imaj dosyası zaten var olmakta" + +msgid "Please specify a valid file name." +msgstr "Lütfen geçerli bir dosya ismi belirleyin." + +msgid "Disk image created" +msgstr "Disk imajı oluşturuldu" + +msgid "Make sure the file exists and is readable." +msgstr "Dosyanın var olduğuna ve okunabildiğine emin olun." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Dosyanın yazılabilir bir klasöre kaydedildiğinden emin olun." + +msgid "Disk image too large" +msgstr "Disk imajı çok büyük" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Yeni oluşturulan diski bölmeyi ve formatlamayı unutmayın." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Seçili dosyanın üzerine yazılacaktır. Bunu yapmak istediğinizden emin misiniz?" + +msgid "Unsupported disk image" +msgstr "Desteklenmeyen disk imajı" + +msgid "Overwrite" +msgstr "Üzerine yaz" + +msgid "Don't overwrite" +msgstr "Üzerine yazma" + +msgid "Raw image (.img)" +msgstr "Ham imaj (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI imajı (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX imajı (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "Sabit-boyutlu VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dinamik-boyutlu VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differencing VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Büyük bloklar (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Küçük bloklar (512 KB)" + +msgid "VHD files" +msgstr "VHD dosyaları" + +msgid "Select the parent VHD" +msgstr "Ana VHD dosyasını seçin" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Bu, farkı alınan imaj oluşturulduktan sonra ana imaj dosyasının düzenlendiği anlamına geliyor olabilir.\n\nBu durum ayrıca imaj dosyaları kopyalandığında veya yerleri değiştirildiğinde veya imaj dosyalarını oluşturan programdaki bir hatadan dolayı olmuş olabilir.\n\nZaman damgalarını düzeltmek ister misiniz?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Ana ve ek disk zaman damgaları uyuşmuyor" + +msgid "Could not fix VHD timestamp." +msgstr "VHD zaman damgası düzeltilemedi." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Mükemmel RPM" + +msgid "1% below perfect RPM" +msgstr "mükemmel RPM değerinin 1% altı" + +msgid "1.5% below perfect RPM" +msgstr "mükemmel RPM değerinin 1.5% altı" + +msgid "2% below perfect RPM" +msgstr "mükemmel RPM değerinin 2% altı" + +msgid "(System Default)" +msgstr "(Sistem Varsayılanı)" + diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po new file mode 100644 index 000000000..76382a9c7 --- /dev/null +++ b/src/qt/languages/uk-UA.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "&Дія" + +msgid "&Keyboard requires capture" +msgstr "&Клавіатура потребує захвату" + +msgid "&Right CTRL is left ALT" +msgstr "&Правий CTRL - це лівий ALT" + +msgid "&Hard Reset..." +msgstr "&Холодне перезавантаження..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "&Ctrl+Alt+Del\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Пауза" + +msgid "E&xit..." +msgstr "&Вихід..." + +msgid "&View" +msgstr "&Вигляд" + +msgid "&Hide status bar" +msgstr "&Приховати рядок стану" + +msgid "Hide &toolbar" +msgstr "&Приховати панель інструментів" + +msgid "&Resizeable window" +msgstr "&Змінний розмір вікна" + +msgid "R&emember size && position" +msgstr "&Запам'ятати розмір і становище" + +msgid "Re&nderer" +msgstr "&Рендеринг" + +msgid "&SDL (Software)" +msgstr "&SDL (Software)" + +msgid "SDL (&Hardware)" +msgstr "SDL (&Hardware)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "&Вказати розміри..." + +msgid "F&orce 4:3 display ratio" +msgstr "&Встановити відношення сторін 4:3" + +msgid "&Window scale factor" +msgstr "&Масштаб вікна" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "Filter method" +msgstr "Метод фільтрації" + +msgid "&Nearest" +msgstr "&Найближчий" + +msgid "&Linear" +msgstr "&Лінійний" + +msgid "Hi&DPI scaling" +msgstr "Масштабування Hi&DPI" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "&Повноекранний режим\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "&Розстягування у повноекранному режимі" + +msgid "&Full screen stretch" +msgstr "&На весь екран" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Квадратні пікселі (зберегти відношення)" + +msgid "&Integer scale" +msgstr "&Цілісночисленне масштабування" + +msgid "E&GA/(S)VGA settings" +msgstr "Налаштування E&GA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Інвертувати кольори VGA" + +msgid "VGA screen &type" +msgstr "&Тип екрана VGA" + +msgid "RGB &Color" +msgstr "RGB &кольоровий" + +msgid "&RGB Grayscale" +msgstr "&RGB монохромний" + +msgid "&Amber monitor" +msgstr "&Бурштиновий відтінок" + +msgid "&Green monitor" +msgstr "&Зелений відтінок" + +msgid "&White monitor" +msgstr "&Білий відтінок" + +msgid "Grayscale &conversion type" +msgstr "Тип монохромного &конвертування" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Усереднений" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Вильоти розгортки CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Змінити контрастність &монохромного дисплея" + +msgid "&Media" +msgstr "&Носії" + +msgid "&Tools" +msgstr "&Інструменти" + +msgid "&Settings..." +msgstr "&Налаштування машини..." + +msgid "&Update status bar icons" +msgstr "&Обновлення значків рядка стану" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "Зробити &знімок\tCtrl+F11" + +msgid "&Preferences..." +msgstr "&Параметри..." + +msgid "Enable &Discord integration" +msgstr "Увімкнути інтеграцію &Discord" + +msgid "Sound &gain..." +msgstr "&Посилення звуку..." + +msgid "Begin trace\tCtrl+T" +msgstr "Почати трасування\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "Завершити трасування\tCtrl+T" + +msgid "&Help" +msgstr "&Допомога" + +msgid "&Documentation..." +msgstr "&Документація..." + +msgid "&About 86Box..." +msgstr "&Про програму 86Box..." + +msgid "&New image..." +msgstr "&Новий образ..." + +msgid "&Existing image..." +msgstr "&Вибрати образ..." + +msgid "Existing image (&Write-protected)..." +msgstr "Вибрати образ (&Захист від запису)..." + +msgid "&Record" +msgstr "&Запис" + +msgid "&Play" +msgstr "&Відтворення" + +msgid "&Rewind to the beginning" +msgstr "&Перемотування на початок" + +msgid "&Fast forward to the end" +msgstr "&Перемотування у кінець" + +msgid "E&ject" +msgstr "&Вилучити" + +msgid "&Image..." +msgstr "&Образ..." + +msgid "E&xport to 86F..." +msgstr "&Експорт в 86F..." + +msgid "&Mute" +msgstr "&Відключити звук" + +msgid "E&mpty" +msgstr "&Пустий" + +msgid "&Reload previous image" +msgstr "&Знову завантажити попередній образ" + +msgid "&Image" +msgstr "&Образ..." + +msgid "Target &framerate" +msgstr "Цільова &частота кадрів" + +msgid "&Sync with video" +msgstr "&Синхронізація з відео" + +msgid "&25 fps" +msgstr "&25 кадрів в секунду" + +msgid "&30 fps" +msgstr "&30 кадрів в секунду" + +msgid "&50 fps" +msgstr "&50 кадрів в секунду" + +msgid "&60 fps" +msgstr "&60 кадрів в секунду" + +msgid "&75 fps" +msgstr "&75 кадрів в секунду" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Вибрати шейдер..." + +msgid "&Remove shader" +msgstr "&Видалити шейдер" + +msgid "Preferences" +msgstr "Параметри" + +msgid "Sound Gain" +msgstr "Посилення звуку" + +msgid "New Image" +msgstr "Новий образ" + +msgid "Settings" +msgstr "Налаштування" + +msgid "Specify Main Window Dimensions" +msgstr "Вказати розміри головного вікна" + +msgid "OK" +msgstr "OK" + +msgid "Cancel" +msgstr "Відміна" + +msgid "Save these settings as &global defaults" +msgstr "Зберегти ці параметри як &глобальні за замовчуванням" + +msgid "&Default" +msgstr "&За замовчуванням" + +msgid "Language:" +msgstr "Язык:" + +msgid "Icon set:" +msgstr "Набір іконок:" + +msgid "Gain" +msgstr "Посилення" + +msgid "File name:" +msgstr "Ім'я файлу:" + +msgid "Disk size:" +msgstr "Розмір диска:" + +msgid "RPM mode:" +msgstr "RPM режим:" + +msgid "Progress:" +msgstr "Прогрес:" + +msgid "Width:" +msgstr "Ширина:" + +msgid "Height:" +msgstr "Висота:" + +msgid "Lock to this size" +msgstr "Зафіксувати розмір" + +msgid "Machine type:" +msgstr "Тип машини:" + +msgid "Machine:" +msgstr "Системна плата:" + +msgid "Configure" +msgstr "Налаштування" + +msgid "CPU type:" +msgstr "Тип ЦП:" + +msgid "Speed:" +msgstr "Швидкість:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Цикли очікування:" + +msgid "MB" +msgstr "МБ" + +msgid "Memory:" +msgstr "Пам'ять:" + +msgid "Time synchronization" +msgstr "Синхронізація часу" + +msgid "Disabled" +msgstr "Відключити" + +msgid "Enabled (local time)" +msgstr "Увімкнути (місцеве)" + +msgid "Enabled (UTC)" +msgstr "Увімкнути (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Динамічний рекомпілятор" + +msgid "Video:" +msgstr "Відеокарта:" + +msgid "Voodoo Graphics" +msgstr "Прискорювач Voodoo" + +msgid "Mouse:" +msgstr "Миша:" + +msgid "Joystick:" +msgstr "Джойстик:" + +msgid "Joystick 1..." +msgstr "Джойстик 1..." + +msgid "Joystick 2..." +msgstr "Джойстик 2..." + +msgid "Joystick 3..." +msgstr "Джойстик 3..." + +msgid "Joystick 4..." +msgstr "Джойстик 4..." + +msgid "Sound card:" +msgstr "Звукова карта:" + +msgid "MIDI Out Device:" +msgstr "MIDI Out при-ій:" + +msgid "MIDI In Device:" +msgstr "MIDI In при-ій:" + +msgid "Standalone MPU-401" +msgstr "Окремий MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "FLOAT32 звук" + +msgid "Network type:" +msgstr "Тип мережі:" + +msgid "PCap device:" +msgstr "Пристрій PCap:" + +msgid "Network adapter:" +msgstr "Мережева карта:" + +msgid "COM1 Device:" +msgstr "Пристрій COM1:" + +msgid "COM2 Device:" +msgstr "Пристрій COM2:" + +msgid "COM3 Device:" +msgstr "Пристрій COM3:" + +msgid "COM4 Device:" +msgstr "Пристрій COM4:" + +msgid "LPT1 Device:" +msgstr "Пристрій LPT1:" + +msgid "LPT2 Device:" +msgstr "Пристрій LPT2:" + +msgid "LPT3 Device:" +msgstr "Пристрій LPT3:" + +msgid "LPT4 Device:" +msgstr "Пристрій LPT4:" + +msgid "Serial port 1" +msgstr "Послідов. порт COM1" + +msgid "Serial port 2" +msgstr "Послідов. порт COM2" + +msgid "Serial port 3" +msgstr "Послідов. порт COM3" + +msgid "Serial port 4" +msgstr "Послідов. порт COM4" + +msgid "Parallel port 1" +msgstr "Паралельний порт LPT1" + +msgid "Parallel port 2" +msgstr "Паралельний порт LPT2" + +msgid "Parallel port 3" +msgstr "Паралельний порт LPT3" + +msgid "Parallel port 4" +msgstr "Паралельний порт LPT4" + +msgid "HD Controller:" +msgstr "Контролер HD:" + +msgid "FD Controller:" +msgstr "Контролер FD:" + +msgid "Tertiary IDE Controller" +msgstr "Третинний IDE контролер" + +msgid "Quaternary IDE Controller" +msgstr "Четвертинний IDE контролер" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Контролер 1:" + +msgid "Controller 2:" +msgstr "Контролер 2:" + +msgid "Controller 3:" +msgstr "Контролер 3:" + +msgid "Controller 4:" +msgstr "Контролер 4:" + +msgid "Cassette" +msgstr "Касета" + +msgid "Hard disks:" +msgstr "Жорсткі диски:" + +msgid "&New..." +msgstr "&Створити..." + +msgid "&Existing..." +msgstr "&Вибрати..." + +msgid "&Remove" +msgstr "&Прибрати" + +msgid "Bus:" +msgstr "Шина:" + +msgid "Channel:" +msgstr "Канал:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Вказати..." + +msgid "Sectors:" +msgstr "Сектора:" + +msgid "Heads:" +msgstr "Головки:" + +msgid "Cylinders:" +msgstr "Циліндри:" + +msgid "Size (MB):" +msgstr "Розмір (МБ):" + +msgid "Type:" +msgstr "Тип:" + +msgid "Image Format:" +msgstr "Тип образу:" + +msgid "Block Size:" +msgstr "Розмір блоку:" + +msgid "Floppy drives:" +msgstr "Гнучкі диски:" + +msgid "Turbo timings" +msgstr "Турбо таймінги" + +msgid "Check BPB" +msgstr "Перевіряти BPB" + +msgid "CD-ROM drives:" +msgstr "Дисководи CD-ROM:" + +msgid "MO drives:" +msgstr "Магнітооптичні дисководи:" + +msgid "ZIP drives:" +msgstr "ZIP дисководи:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Карта розширення пам'яті (ISA)" + +msgid "Card 1:" +msgstr "Карта 1:" + +msgid "Card 2:" +msgstr "Карта 2:" + +msgid "Card 3:" +msgstr "Карта 3:" + +msgid "Card 4:" +msgstr "Карта 4:" + +msgid "ISABugger device" +msgstr "Пристрій ISABugger" + +msgid "POST card" +msgstr "Карта POST" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Segoe UI" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Помилка" + +msgid "Fatal error" +msgstr "Непереробна помилка" + +msgid " - PAUSED" +msgstr " - PAUSED" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Натисніть Ctrl+Alt+PgDn для повернення у віконний режим." + +msgid "Speed" +msgstr "Швидкість" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "Образи ZIP" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box не зміг знайти жодного відповідного для використання файлу з ПЗУ.\n\nБудь ласка завантажте набір ПЗУ і витягніть його в каталог \"roms\"." + +msgid "(empty)" +msgstr "(порожньо)" + +msgid "All files" +msgstr "Всі файли" + +msgid "Turbo" +msgstr "Турбо" + +msgid "On" +msgstr "Увімк" + +msgid "Off" +msgstr "Вимк" + +msgid "All images" +msgstr "Всі образи" + +msgid "Basic sector images" +msgstr "Прості посекторні образи" + +msgid "Surface images" +msgstr "Образ поверхні" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Системна плата \"%hs\" недоступна через відсутність файлу її ПЗУ в каталозі roms/machines. Переключення на доступну системну плату." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Відеокарта \"%hs\" недоступна через відсутність файлу її ПЗУ в каталозі roms/video. Переключення на доступну відеокарту." + +msgid "Machine" +msgstr "Комп'ютер" + +msgid "Display" +msgstr "Дисплей" + +msgid "Input devices" +msgstr "Пристрій введення" + +msgid "Sound" +msgstr "Звук" + +msgid "Network" +msgstr "Мережа" + +msgid "Ports (COM & LPT)" +msgstr "Порти (COM и LPT)" + +msgid "Storage controllers" +msgstr "Контролери дисків" + +msgid "Hard disks" +msgstr "Жорсткі диски" + +msgid "Floppy & CD-ROM drives" +msgstr "Гнучкі диски і CD-ROM" + +msgid "Other removable devices" +msgstr "Інші знімні при-ої" + +msgid "Other peripherals" +msgstr "Інша периферія" + +msgid "Click to capture mouse" +msgstr "Клацніть мишею для захвату курсора" + +msgid "Press F8+F12 to release mouse" +msgstr "Натисніть F8+F12, щоб звільнити курсор" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "Натисніть F8+F12 або середню кнопку миші, щоб звільнити курсор" + +msgid "Unable to initialize FluidSynth" +msgstr "Неможливо ініціалізувати FluidSynth" + +msgid "Bus" +msgstr "Шина" + +msgid "File" +msgstr "Файл" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "КБ" + +msgid "Could not initialize the video renderer." +msgstr "Не вдалося ініціалізувати рендер відео." + +msgid "Default" +msgstr "За замовчуванням" + +msgid "%i Wait state(s)" +msgstr "%i WS" + +msgid "Type" +msgstr "Тип" + +msgid "Failed to set up PCap" +msgstr "Не вдалося налаштувати PCap" + +msgid "No PCap devices found" +msgstr "Пристрої PCap не знайдені" + +msgid "Invalid PCap device" +msgstr "Невірний пристрій PCap" + +msgid "Standard 2-button joystick(s)" +msgstr "Стандартний 2-кнопковий джойстик" + +msgid "Standard 4-button joystick" +msgstr "Стандартний 4-кнопковий джойстик" + +msgid "Standard 6-button joystick" +msgstr "Стандартний 6-кнопковий джойстик" + +msgid "Standard 8-button joystick" +msgstr "Стандартний 8-кнопковий джойстик" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Система управління польотом Thrustmaster" + +msgid "None" +msgstr "Ні" + +msgid "Unable to load keyboard accelerators." +msgstr "Неможливо завантажити прискорювачі клавіатури." + +msgid "Unable to register raw input." +msgstr "Неможливо зарреєструвати необроблене (RAW) введення." + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u МБ (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "Дисковод %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "Розширені образи секторів" + +msgid "Flux images" +msgstr "Образи Flux" + +msgid "Unable to initialize FreeType" +msgstr "Неможливо ініціалізувати FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "Неможливо ініціалізувати SDL, потрібно SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Ви впевнені, що хочете виконати холодне перезавантаження емульованої машини?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Ви впевнені, що хочете вийти з 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Неможливо ініціалізувати Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "Магнітооптичний %i (%ls): %ls" + +msgid "MO images" +msgstr "Образи магнітооптичних дисків" + +msgid "Welcome to 86Box!" +msgstr "Ласкаво просимо в 86Box!" + +msgid "Internal controller" +msgstr "Вбудований контролер" + +msgid "Exit" +msgstr "Вихід" + +msgid "No ROMs found" +msgstr "ПЗУ не знайдені" + +msgid "Do you want to save the settings?" +msgstr "Чи бажаєте ви зберегти налаштування?" + +msgid "This will hard reset the emulated machine." +msgstr "Це призведе до холодної перезагрузки емульованої машини." + +msgid "Save" +msgstr "Зберегти" + +msgid "About 86Box" +msgstr "Про 86Box" + +msgid "86Box v" +msgstr "86Box v." + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Емулятор старих комп'ютерів\n\nАвтори: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nВипускаєтся під ліцензією GNU General Public License версії 2 або більше пізніше. Додадкову інформацію см. у файлі LICENSE." + +msgid "Hardware not available" +msgstr "Обладнання недоступне" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "Переконайтесь, що libpcap встановлений і ваше мережеве з'єднання, сумісне з libpcap." + +msgid "Invalid configuration" +msgstr "Неприпустима конфігурація" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr "Для емуляції принтера ESC/P потрібно libfreetype." + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " потрібно для автоматичного перетворення файлів PostScript в PDF.\n\nВсі документи, відправлені на загальний принтер PostScript, будуть збережені у вигляді файлів PostScript (.ps)." + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr "Для FluidSynth MIDI-висновку потрібно libfluidsynth." + +msgid "Entering fullscreen mode" +msgstr "Вхід у повноекранний режим" + +msgid "Don't show this message again" +msgstr "Більше не показувати це повідомлення" + +msgid "Don't exit" +msgstr "Не виходити" + +msgid "Reset" +msgstr "Перезавантажити" + +msgid "Don't reset" +msgstr "Не перезавантажувати" + +msgid "CD-ROM images" +msgstr "Образи CD-ROM" + +msgid "%hs Device Configuration" +msgstr "Конфігурація пристрою %hs" + +msgid "Monitor in sleep mode" +msgstr "Монітор у сплячому режимі" + +msgid "OpenGL Shaders" +msgstr "Шейдери OpenGL" + +msgid "OpenGL options" +msgstr "Параметри OpenGL" + +msgid "You are loading an unsupported configuration" +msgstr "Ви завантажуєте непідтримувану конфігурацію" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Вибір типів ЦП для цієї системної плати на даній емульованій машині відключено.\n\nЦе дозволяє вибрати процесор, який в іншому випадку не сумісний з вибраною материнською платою. Однак, ви можете зіткнутися з несумісністю з BIOS материнської плати або іншим ПО.\n\nВключення цього параметра офіційно не підтримується, і всі подані звіти про помилки можуть бути закриті як недійсні." + +msgid "Continue" +msgstr "Продовжити" + +msgid "Cassette: %s" +msgstr "Касета: %s" + +msgid "Cassette images" +msgstr "Образи касет" + +msgid "Cartridge %i: %ls" +msgstr "Картридж %i: %ls" + +msgid "Cartridge images" +msgstr "Образи картриджів" + +msgid "Error initializing renderer" +msgstr "Помилка ініціалізації рендерера" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "Неможливо ініціалізувати рендерер OpenGL (3.0). Будь ласка, використовуйте інший рендерер." + +msgid "Resume execution" +msgstr "Відновити виконання" + +msgid "Pause execution" +msgstr "Призупинити виконання" + +msgid "Press Ctrl+Alt+Del" +msgstr "Натиснути Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Натиснути Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Холодне перезавантаження" + +msgid "ACPI shutdown" +msgstr "Сигнал завершення ACPI" + +msgid "Hard disk (%s)" +msgstr "Жорсткий диск (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL або ESDI дисководів CD-ROM ніколи не існувало" + +msgid "Custom..." +msgstr "Задати вручну..." + +msgid "Custom (large)..." +msgstr "Задати вручну (large)..." + +msgid "Add New Hard Disk" +msgstr "Створити новий жорсткий диск" + +msgid "Add Existing Hard Disk" +msgstr "Вибрати існуючий жорсткий диск" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Розмір образів дисків HDI не може перевищувати 4 ГБ." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Розмір образів дисків не може перевищувати 127 ГБ." + +msgid "Hard disk images" +msgstr "Образи жорстких дисків" + +msgid "Unable to read file" +msgstr "Неможливо прочитати файл" + +msgid "Unable to write file" +msgstr "Неможливо записати файл" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Образи HDI або HDX з розміром сектора, відмінним від 512, не підтримуються." + +msgid "USB is not yet supported" +msgstr "USB поки не підтримується" + +msgid "Disk image file already exists" +msgstr "Файл образу диска вже існує" + +msgid "Please specify a valid file name." +msgstr "Вкажіть правильне ім'я файлу." + +msgid "Disk image created" +msgstr "Образ диску створено" + +msgid "Make sure the file exists and is readable." +msgstr "Переконайтеся, що файл є доступним для читання." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Переконайтеся, що файл зберігається в каталог, який є доступним для запису." + +msgid "Disk image too large" +msgstr "Занадто великий образ диска" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Не забудьте розмітити та відформатувати новостворений диск." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Вибраний файл буде перезаписано. Ви впевнені, що хочете використовувати його?" + +msgid "Unsupported disk image" +msgstr "Образ диска, що не підтримується" + +msgid "Overwrite" +msgstr "Перезаписати" + +msgid "Don't overwrite" +msgstr "Не перезаписувати" + +msgid "Raw image (.img)" +msgstr "RAW образ (.img)" + +msgid "HDI image (.hdi)" +msgstr "Образ HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Образ HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD фіксованого розміру (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD динамічного розміру (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Диференційований образ VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Великі блоки (2 МБ)" + +msgid "Small blocks (512 KB)" +msgstr "Маленькі блоки (512 КБ)" + +msgid "VHD files" +msgstr "Файли VHD" + +msgid "Select the parent VHD" +msgstr "Виберіть батьківський VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Це може означати, що батьківський образ був змінений після того, як було створено диференційований образ.\n\nЦе також може статися, якщо файли зображення були переміщені або скопійовані, або через помилку в програмі, що створила цей диск.\n \nВи хочете виправити тимчасові позначки?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Тимчасові мітки батьківського та дочірнього дисків не співпадають" + +msgid "Could not fix VHD timestamp." +msgstr "Не вдалося виправити тимчасову позначку VHD." + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "CD-ROM %i (%s): %s" + +msgid "160 kB" +msgstr "160 кБ" + +msgid "180 kB" +msgstr "180 кБ" + +msgid "320 kB" +msgstr "320 кБ" + +msgid "360 kB" +msgstr "360 кБ" + +msgid "640 kB" +msgstr "640 кБ" + +msgid "720 kB" +msgstr "720 кБ" + +msgid "1.2 MB" +msgstr "1.2 МБ" + +msgid "1.25 MB" +msgstr "1.25 МБ" + +msgid "1.44 MB" +msgstr "1.44 МБ" + +msgid "DMF (cluster 1024)" +msgstr "DMF (кластер 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (кластер 2048)" + +msgid "2.88 MB" +msgstr "2.88 МБ" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 МБ (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 МБ (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 МБ (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 МБ (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 ГБ (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 ГБ (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 МБ" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 МБ" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 ГБ" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 ГБ" + +msgid "Perfect RPM" +msgstr "Точний RPM" + +msgid "1% below perfect RPM" +msgstr "На 1% повільніше точного RPM" + +msgid "1.5% below perfect RPM" +msgstr "На 1.5% повільніше точного RPM" + +msgid "2% below perfect RPM" +msgstr "На 2% повільніше точного RPM" + +msgid "(System Default)" +msgstr "(Системний)" + diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po new file mode 100644 index 000000000..b9c6f6c98 --- /dev/null +++ b/src/qt/languages/zh-CN.po @@ -0,0 +1,1185 @@ +msgid "&Action" +msgstr "操作(&A)" + +msgid "&Keyboard requires capture" +msgstr "键盘需要捕捉(&K)" + +msgid "&Right CTRL is left ALT" +msgstr "将右 CTRL 键映射为左 ALT 键(&R)" + +msgid "&Hard Reset..." +msgstr "硬重置(&H)..." + +msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+Esc(&E)" + +msgid "&Pause" +msgstr "暂停(&P)" + +msgid "E&xit..." +msgstr "退出(&X)..." + +msgid "&View" +msgstr "查看(&V)" + +msgid "&Hide status bar" +msgstr "隐藏状态栏(&H)" + +msgid "Hide &toolbar" +msgstr "隐藏工具栏(&T)" + +msgid "&Resizeable window" +msgstr "窗口大小可调(&R)" + +msgid "R&emember size && position" +msgstr "记住窗口大小和位置(&E)" + +msgid "Re&nderer" +msgstr "渲染器(&N)" + +msgid "&SDL (Software)" +msgstr "SDL (软件)(&S)" + +msgid "SDL (&Hardware)" +msgstr "SDL (硬件)(&H)" + +msgid "SDL (&OpenGL)" +msgstr "SDL (OpenGL)(&O)" + +msgid "Open&GL (3.0 Core)" +msgstr "OpenGL (3.0 核心)(&G)" + +msgid "&VNC" +msgstr "VNC(&V)" + +msgid "Specify dimensions..." +msgstr "指定窗口大小..." + +msgid "F&orce 4:3 display ratio" +msgstr "强制 4:3 显示比例(&O)" + +msgid "&Window scale factor" +msgstr "窗口缩放系数(&W)" + +msgid "&0.5x" +msgstr "0.5x(&0)" + +msgid "&1x" +msgstr "1x(&1)" + +msgid "1.&5x" +msgstr "1.5x(&5)" + +msgid "&2x" +msgstr "2x(&2)" + +msgid "Filter method" +msgstr "过滤方式" + +msgid "&Nearest" +msgstr "邻近(&N)" + +msgid "&Linear" +msgstr "线性(&L)" + +msgid "Hi&DPI scaling" +msgstr "HiDPI 缩放(&D)" + +msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgstr "全屏(&F)\tCtrl+Alt+PgUp" + +msgid "Fullscreen &stretch mode" +msgstr "全屏拉伸模式(&S)" + +msgid "&Full screen stretch" +msgstr "全屏拉伸(&F)" + +msgid "&4:3" +msgstr "4:3(&4)" + +msgid "&Square pixels (Keep ratio)" +msgstr "保持比例(&S)" + +msgid "&Integer scale" +msgstr "整数比例(&I)" + +msgid "E&GA/(S)VGA settings" +msgstr "EGA/(S)VGA 设置(&G)" + +msgid "&Inverted VGA monitor" +msgstr "VGA 显示器反色显示(&I)" + +msgid "VGA screen &type" +msgstr "VGA 屏幕类型(&T)" + +msgid "RGB &Color" +msgstr "RGB 彩色(&C)" + +msgid "&RGB Grayscale" +msgstr "RGB 灰度(&R)" + +msgid "&Amber monitor" +msgstr "琥珀色单色显示器(&A)" + +msgid "&Green monitor" +msgstr "绿色单色显示器(&G)" + +msgid "&White monitor" +msgstr "白色单色显示器(&W)" + +msgid "Grayscale &conversion type" +msgstr "灰度转换类型(&C)" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT601 (NTSC/PAL)(&6)" + +msgid "BT&709 (HDTV)" +msgstr "BT709 (HDTV)(&7)" + +msgid "&Average" +msgstr "平均(&A)" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/EGA/(S)VGA 过扫描(&G)" + +msgid "Change contrast for &monochrome display" +msgstr "更改单色显示对比度(&M)" + +msgid "&Media" +msgstr "介质(&M)" + +msgid "&Tools" +msgstr "工具(&T)" + +msgid "&Settings..." +msgstr "设置(&S)..." + +msgid "&Update status bar icons" +msgstr "更新状态栏图标(&U)" + +msgid "Take s&creenshot\tCtrl+F11" +msgstr "截图(&C)\tCtrl+F11" + +msgid "&Preferences..." +msgstr "首选项(&P)..." + +msgid "Enable &Discord integration" +msgstr "启用 Discord 集成(&D)" + +msgid "Sound &gain..." +msgstr "音量增益(&G)..." + +msgid "Begin trace\tCtrl+T" +msgstr "开始追踪\tCtrl+T" + +msgid "End trace\tCtrl+T" +msgstr "结束追踪\tCtrl+T" + +msgid "&Help" +msgstr "帮助(&H)" + +msgid "&Documentation..." +msgstr "文档(&D)..." + +msgid "&About 86Box..." +msgstr "关于 86Box(&A)..." + +msgid "&New image..." +msgstr "新建镜像(&N)..." + +msgid "&Existing image..." +msgstr "打开已存在的镜像(&E)..." + +msgid "Existing image (&Write-protected)..." +msgstr "打开已存在的镜像并写保护(&W)..." + +msgid "&Record" +msgstr "录制(&R)" + +msgid "&Play" +msgstr "播放(&P)" + +msgid "&Rewind to the beginning" +msgstr "倒带至起点(&R)" + +msgid "&Fast forward to the end" +msgstr "快进至终点(&F)" + +msgid "E&ject" +msgstr "弹出(&J)" + +msgid "&Image..." +msgstr "镜像(&I)..." + +msgid "E&xport to 86F..." +msgstr "导出为 86F 格式(&x)..." + +msgid "&Mute" +msgstr "静音(&M)" + +msgid "E&mpty" +msgstr "空置驱动器(&M)" + +msgid "&Reload previous image" +msgstr "载入上一个镜像(&R)" + +msgid "&Image" +msgstr "镜像(&I)" + +msgid "Target &framerate" +msgstr "目标帧率(&F)" + +msgid "&Sync with video" +msgstr "与视频同步(&S)" + +msgid "&25 fps" +msgstr "25 fps(&2)" + +msgid "&30 fps" +msgstr "30 fps(&3)" + +msgid "&50 fps" +msgstr "50 fps(&5)" + +msgid "&60 fps" +msgstr "60 fps(&6)" + +msgid "&75 fps" +msgstr "75 fps(&7)" + +msgid "&VSync" +msgstr "垂直同步(&V)" + +msgid "&Select shader..." +msgstr "选择着色器(&S)..." + +msgid "&Remove shader" +msgstr "移除着色器(&R)" + +msgid "Preferences" +msgstr "首选项" + +msgid "Sound Gain" +msgstr "音量增益" + +msgid "New Image" +msgstr "新建镜像" + +msgid "Settings" +msgstr "设置" + +msgid "Specify Main Window Dimensions" +msgstr "指定主窗口大小" + +msgid "OK" +msgstr "确定" + +msgid "Cancel" +msgstr "取消" + +msgid "Save these settings as &global defaults" +msgstr "将以上设置存储为全局默认值(&G)" + +msgid "&Default" +msgstr "默认(&D)" + +msgid "Language:" +msgstr "语言:" + +msgid "Icon set:" +msgstr "图标集:" + +msgid "Gain" +msgstr "增益" + +msgid "File name:" +msgstr "文件名:" + +msgid "Disk size:" +msgstr "磁盘大小:" + +msgid "RPM mode:" +msgstr "转速 (RPM) 模式:" + +msgid "Progress:" +msgstr "进度:" + +msgid "Width:" +msgstr "宽度:" + +msgid "Height:" +msgstr "高度:" + +msgid "Lock to this size" +msgstr "锁定此大小" + +msgid "Machine type:" +msgstr "机器类型:" + +msgid "Machine:" +msgstr "机型:" + +msgid "Configure" +msgstr "配置" + +msgid "CPU type:" +msgstr "CPU 类型:" + +msgid "Speed:" +msgstr "速度:" + +msgid "FPU:" +msgstr "浮点处理器 (FPU):" + +msgid "Wait states:" +msgstr "等待状态 (WS):" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "内存:" + +msgid "Time synchronization" +msgstr "时间同步" + +msgid "Disabled" +msgstr "禁用" + +msgid "Enabled (local time)" +msgstr "启用 (本地时间)" + +msgid "Enabled (UTC)" +msgstr "启用 (UTC)" + +msgid "Dynamic Recompiler" +msgstr "动态重编译器" + +msgid "Video:" +msgstr "显卡:" + +msgid "Voodoo Graphics" +msgstr "Voodoo Graphics" + +msgid "Mouse:" +msgstr "鼠标:" + +msgid "Joystick:" +msgstr "操纵杆:" + +msgid "Joystick 1..." +msgstr "操纵杆 1..." + +msgid "Joystick 2..." +msgstr "操纵杆 2..." + +msgid "Joystick 3..." +msgstr "操纵杆 3..." + +msgid "Joystick 4..." +msgstr "操纵杆 4..." + +msgid "Sound card:" +msgstr "声卡:" + +msgid "MIDI Out Device:" +msgstr "MIDI 输出设备:" + +msgid "MIDI In Device:" +msgstr "MIDI 输入设备:" + +msgid "Standalone MPU-401" +msgstr "独立 MPU-401" + +msgid "Innovation SSI-2001" +msgstr "Innovation SSI-2001" + +msgid "CMS / Game Blaster" +msgstr "CMS / Game Blaster" + +msgid "Gravis Ultrasound" +msgstr "Gravis Ultrasound" + +msgid "Use FLOAT32 sound" +msgstr "使用单精度浮点 (FLOAT32)" + +msgid "Network type:" +msgstr "网络类型:" + +msgid "PCap device:" +msgstr "PCap 设备:" + +msgid "Network adapter:" +msgstr "网络适配器:" + +msgid "COM1 Device:" +msgstr "COM1 设备:" + +msgid "COM2 Device:" +msgstr "COM2 设备:" + +msgid "COM3 Device:" +msgstr "COM3 设备:" + +msgid "COM4 Device:" +msgstr "COM4 设备:" + +msgid "LPT1 Device:" +msgstr "LPT1 设备:" + +msgid "LPT2 Device:" +msgstr "LPT2 设备:" + +msgid "LPT3 Device:" +msgstr "LPT3 设备:" + +msgid "LPT4 Device:" +msgstr "LPT4 设备:" + +msgid "Serial port 1" +msgstr "串口 1" + +msgid "Serial port 2" +msgstr "串口 2" + +msgid "Serial port 3" +msgstr "串口 3" + +msgid "Serial port 4" +msgstr "串口 4" + +msgid "Parallel port 1" +msgstr "并口 1" + +msgid "Parallel port 2" +msgstr "并口 2" + +msgid "Parallel port 3" +msgstr "并口 3" + +msgid "Parallel port 4" +msgstr "并口 4" + +msgid "HD Controller:" +msgstr "硬盘控制器:" + +msgid "FD Controller:" +msgstr "软盘控制器:" + +msgid "Tertiary IDE Controller" +msgstr "第三 IDE 控制器" + +msgid "Quaternary IDE Controller" +msgstr "第四 IDE 控制器" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "控制器 1:" + +msgid "Controller 2:" +msgstr "控制器 2:" + +msgid "Controller 3:" +msgstr "控制器 3:" + +msgid "Controller 4:" +msgstr "控制器 4:" + +msgid "Cassette" +msgstr "磁带" + +msgid "Hard disks:" +msgstr "硬盘:" + +msgid "&New..." +msgstr "新建(&N)..." + +msgid "&Existing..." +msgstr "已有镜像(&E)..." + +msgid "&Remove" +msgstr "移除(&R)" + +msgid "Bus:" +msgstr "总线:" + +msgid "Channel:" +msgstr "通道:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "指定(&S)..." + +msgid "Sectors:" +msgstr "扇区(S):" + +msgid "Heads:" +msgstr "磁头(H):" + +msgid "Cylinders:" +msgstr "柱面(C):" + +msgid "Size (MB):" +msgstr "大小 (MB):" + +msgid "Type:" +msgstr "类型:" + +msgid "Image Format:" +msgstr "镜像格式:" + +msgid "Block Size:" +msgstr "块大小:" + +msgid "Floppy drives:" +msgstr "软盘驱动器:" + +msgid "Turbo timings" +msgstr "加速时序" + +msgid "Check BPB" +msgstr "检查 BPB" + +msgid "CD-ROM drives:" +msgstr "光盘驱动器:" + +msgid "MO drives:" +msgstr "磁光盘驱动器:" + +msgid "ZIP drives:" +msgstr "ZIP 驱动器:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA 实时时钟:" + +msgid "ISA Memory Expansion" +msgstr "ISA 内存扩充" + +msgid "Card 1:" +msgstr "扩展卡 1:" + +msgid "Card 2:" +msgstr "扩展卡 2:" + +msgid "Card 3:" +msgstr "扩展卡 3:" + +msgid "Card 4:" +msgstr "扩展卡 4:" + +msgid "ISABugger device" +msgstr "ISABugger 设备" + +msgid "POST card" +msgstr "自检 (POST) 卡" + +msgid "FONT_SIZE" +msgstr "9" + +msgid "FONT_NAME" +msgstr "Microsoft YaHei" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "错误" + +msgid "Fatal error" +msgstr "致命错误" + +msgid " - PAUSED" +msgstr " - 已暂停" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "按下 Ctrl+Alt+PgDn 返回到窗口模式。" + +msgid "Speed" +msgstr "速度" + +msgid "ZIP %03i %i (%s): %ls" +msgstr "ZIP %03i %i (%s): %ls" + +msgid "ZIP images" +msgstr "ZIP 镜像" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box 找不到任何可用的 ROM 镜像。\n\n请下载ROM 包并将其解压到 \"roms\" 文件夹。" + +msgid "(empty)" +msgstr "(空)" + +msgid "All files" +msgstr "所有文件" + +msgid "Turbo" +msgstr "加速" + +msgid "On" +msgstr "开" + +msgid "Off" +msgstr "关" + +msgid "All images" +msgstr "所有镜像" + +msgid "Basic sector images" +msgstr "基本扇区镜像" + +msgid "Surface images" +msgstr "表面镜像" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "由于 roms/machines 文件夹中缺少合适的 ROM,机型 \"%hs\" 不可用。将切换到其他可用机型。" + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "由于 roms/video 文件夹中缺少合适的 ROM,显卡 \"%hs\" 不可用。将切换到其他可用显卡。" + +msgid "Machine" +msgstr "机型" + +msgid "Display" +msgstr "显示" + +msgid "Input devices" +msgstr "输入设备" + +msgid "Sound" +msgstr "声音" + +msgid "Network" +msgstr "网络" + +msgid "Ports (COM & LPT)" +msgstr "端口 (COM 和 LPT)" + +msgid "Storage controllers" +msgstr "存储控制器" + +msgid "Hard disks" +msgstr "硬盘" + +msgid "Floppy & CD-ROM drives" +msgstr "软盘/光盘驱动器" + +msgid "Other removable devices" +msgstr "其他可移动设备" + +msgid "Other peripherals" +msgstr "其他外围设备" + +msgid "Click to capture mouse" +msgstr "单击窗口捕捉鼠标" + +msgid "Press F8+F12 to release mouse" +msgstr "按下 F8+F12 释放鼠标" + +msgid "Press F8+F12 or middle button to release mouse" +msgstr "按下 F8+F12 或鼠标中键释放鼠标" + +msgid "Unable to initialize FluidSynth" +msgstr "无法初始化 FluidSynth" + +msgid "Bus" +msgstr "总线" + +msgid "File" +msgstr "文件" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Could not initialize the video renderer." +msgstr "无法初始化视频渲染器。" + +msgid "Default" +msgstr "默认" + +msgid "%i Wait state(s)" +msgstr "%i 等待状态 (WS)" + +msgid "Type" +msgstr "类型" + +msgid "Failed to set up PCap" +msgstr "设置 PCap 失败" + +msgid "No PCap devices found" +msgstr "未找到 PCap 设备" + +msgid "Invalid PCap device" +msgstr "无效 PCap 设备" + +msgid "Standard 2-button joystick(s)" +msgstr "标准 2 键操纵杆" + +msgid "Standard 4-button joystick" +msgstr "标准 4 键操纵杆" + +msgid "Standard 6-button joystick" +msgstr "标准 6 键操纵杆" + +msgid "Standard 8-button joystick" +msgstr "标准 8 键操纵杆" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "无" + +msgid "Unable to load keyboard accelerators." +msgstr "无法加载键盘加速器。" + +msgid "Unable to register raw input." +msgstr "无法注册原始输入。" + +msgid "%u" +msgstr "%u" + +msgid "%u MB (CHS: %i, %i, %i)" +msgstr "%u MB (CHS: %i, %i, %i)" + +msgid "Floppy %i (%s): %ls" +msgstr "软盘 %i (%s): %ls" + +msgid "Advanced sector images" +msgstr "高级扇区镜像" + +msgid "Flux images" +msgstr "Flux 镜像" + +msgid "Unable to initialize FreeType" +msgstr "无法初始化 FreeType" + +msgid "Unable to initialize SDL, SDL2.dll is required" +msgstr "无法初始化 SDL,需要 SDL2.dll" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "确定要硬重置模拟器吗?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "确定要退出 86Box 吗?" + +msgid "Unable to initialize Ghostscript" +msgstr "无法初始化 Ghostscript" + +msgid "MO %i (%ls): %ls" +msgstr "磁光盘 %i (%ls): %ls" + +msgid "MO images" +msgstr "磁光盘镜像" + +msgid "Welcome to 86Box!" +msgstr "欢迎使用 86Box!" + +msgid "Internal controller" +msgstr "内部控制器" + +msgid "Exit" +msgstr "退出" + +msgid "No ROMs found" +msgstr "找不到 ROM" + +msgid "Do you want to save the settings?" +msgstr "要保存设置吗?" + +msgid "This will hard reset the emulated machine." +msgstr "此操作将硬重置模拟器。" + +msgid "Save" +msgstr "保存" + +msgid "About 86Box" +msgstr "关于 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "一个旧式计算机模拟器\n\n作者: Sarah Walker、Miran Grca、Fred N. van Kempen (waltje)、SA1988、Tiseno100、reenigne、leilei、JohnElliott、greatpsycho 等人。\n\n本软件依据 GNU 通用公共许可证第二版或更新版本发布。详情见 LICENSE 文件。" + +msgid "Hardware not available" +msgstr "硬件不可用" + +msgid "WinPcap" +msgstr "WinPcap" + +msgid "libpcap" +msgstr "libpcap" + +msgid "Make sure libpcap is installed and that you are on a libpcap-compatible network connection." +msgstr "请确认 libpcap 已安装且使用兼容 libpcap 的网络连接。" + +msgid "Invalid configuration" +msgstr "无效配置" + +msgid "freetype.dll" +msgstr "freetype.dll" + +msgid "libfreetype" +msgstr "libfreetype" + +msgid " is required for ESC/P printer emulation." +msgstr "ESC/P 打印机模拟需要" + +msgid "gsdll32.dll" +msgstr "gsdll32.dll" + +msgid "libgs" +msgstr "libgs" + +msgid " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr " 是将 PostScript 文件转换为 PDF 所需要的库。\n\n使用通用 PostScript 打印机打印的文档将被保存为 PostScript (.ps) 文件。" + +msgid "libfluidsynth.dll" +msgstr "libfluidsynth.dll" + +msgid "libfluidsynth" +msgstr "libfluidsynth" + +msgid " is required for FluidSynth MIDI output." +msgstr "FluidSynth MIDI 输出需要" + +msgid "Entering fullscreen mode" +msgstr "正在进入全屏模式" + +msgid "Don't show this message again" +msgstr "不要再显示此消息" + +msgid "Don't exit" +msgstr "不退出" + +msgid "Reset" +msgstr "重置" + +msgid "Don't reset" +msgstr "不重置" + +msgid "CD-ROM images" +msgstr "光盘镜像" + +msgid "%hs Device Configuration" +msgstr "%hs 设备配置" + +msgid "Monitor in sleep mode" +msgstr "显示器处在睡眠状态" + +msgid "OpenGL Shaders" +msgstr "OpenGL 着色器" + +msgid "OpenGL options" +msgstr "OpenGL 选项" + +msgid "You are loading an unsupported configuration" +msgstr "正在载入一个不受支持的配置" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "此模拟计算机禁用了基于选定计算机的 CPU 类型过滤。\n\n能够选中与所选机器本不兼容的 CPU,但是可能会遇到与机器 BIOS 或其他软件不兼容的问题。\n\n启用此设置不受官方支持,并且提交的任何错误报告可能会视为无效而关闭。" + +msgid "Continue" +msgstr "继续" + +msgid "Cassette: %s" +msgstr "磁带: %s" + +msgid "Cassette images" +msgstr "磁带镜像" + +msgid "Cartridge %i: %ls" +msgstr "卡带 %i: %ls" + +msgid "Cartridge images" +msgstr "卡带镜像" + +msgid "Error initializing renderer" +msgstr "初始化渲染器时出错" + +msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." +msgstr "无法初始化 OpenGL (3.0 核心) 渲染器。请使用其他渲染器。" + +msgid "Resume execution" +msgstr "恢复执行" + +msgid "Pause execution" +msgstr "暂停执行" + +msgid "Press Ctrl+Alt+Del" +msgstr "按下 Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "按下 Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "硬重置" + +msgid "ACPI shutdown" +msgstr "ACPI 关机" + +msgid "Hard disk (%s)" +msgstr "硬盘 (%s)" + +msgid "%01i:%01i" +msgstr "%01i:%01i" + +msgid "%01i" +msgstr "%01i" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "不存在 MFM/RLL 或 ESDI CD-ROM 驱动器" + +msgid "Custom..." +msgstr "自定义..." + +msgid "Custom (large)..." +msgstr "自定义 (大容量)..." + +msgid "Add New Hard Disk" +msgstr "添加新硬盘" + +msgid "Add Existing Hard Disk" +msgstr "添加已存在的硬盘" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "HDI 磁盘镜像不能超过 4 GB。" + +msgid "Disk images cannot be larger than 127 GB." +msgstr "磁盘镜像不能超过 127 GB。" + +msgid "Hard disk images" +msgstr "硬盘镜像" + +msgid "Unable to read file" +msgstr "无法读取文件" + +msgid "Unable to write file" +msgstr "无法写入文件" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "不支持非 512 字节扇区大小的 HDI 或 HDX 镜像。" + +msgid "USB is not yet supported" +msgstr "尚未支持 USB" + +msgid "Disk image file already exists" +msgstr "磁盘镜像文件已存在" + +msgid "Please specify a valid file name." +msgstr "请指定有效的文件名。" + +msgid "Disk image created" +msgstr "已创建磁盘镜像" + +msgid "Make sure the file exists and is readable." +msgstr "请确定此文件已存在并可读取。" + +msgid "Make sure the file is being saved to a writable directory." +msgstr "请确定此文件保存在可写目录中。" + +msgid "Disk image too large" +msgstr "磁盘镜像太大" + +msgid "Remember to partition and format the newly-created drive." +msgstr "请记得为新创建的镜像分区并格式化。" + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "选定的文件将被覆盖。确定继续使用此文件吗?" + +msgid "Unsupported disk image" +msgstr "不支持的磁盘镜像" + +msgid "Overwrite" +msgstr "覆盖" + +msgid "Don't overwrite" +msgstr "不覆盖" + +msgid "Raw image (.img)" +msgstr "原始镜像 (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI 镜像 (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX 镜像 (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "固定大小 VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "动态大小 VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "差分 VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "大块 (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "小块 (512 KB)" + +msgid "VHD files" +msgstr "VHD 文件" + +msgid "Select the parent VHD" +msgstr "选择父 VHD 文件" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "父映像可能在创建差异镜像后被修改。\n\n如果镜像文件被移动或复制,或创建此磁盘的程序中存在错误,也可能发生这种情况。\n\n是否需要修复时间戳?" + +msgid "Parent and child disk timestamps do not match" +msgstr "父盘与子盘的时间戳不匹配" + +msgid "Could not fix VHD timestamp." +msgstr "无法修复 VHD 时间戳。" + +msgid "%01i:%02i" +msgstr "%01i:%02i" + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "MFM/RLL (%01i:%01i)" +msgstr "MFM/RLL (%01i:%01i)" + +msgid "XTA (%01i:%01i)" +msgstr "XTA (%01i:%01i)" + +msgid "ESDI (%01i:%01i)" +msgstr "ESDI (%01i:%01i)" + +msgid "IDE (%01i:%01i)" +msgstr "IDE (%01i:%01i)" + +msgid "ATAPI (%01i:%01i)" +msgstr "ATAPI (%01i:%01i)" + +msgid "SCSI (%01i:%02i)" +msgstr "SCSI (%01i:%02i)" + +msgid "CD-ROM %i (%s): %s" +msgstr "光盘 %i (%s): %s" + +msgid "160 kB" +msgstr "160 kB" + +msgid "180 kB" +msgstr "180 kB" + +msgid "320 kB" +msgstr "320 kB" + +msgid "360 kB" +msgstr "360 kB" + +msgid "640 kB" +msgstr "640 kB" + +msgid "720 kB" +msgstr "720 kB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (1024 簇)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (2048 簇)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5 英寸 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5 英寸 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5 英寸 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5 英寸 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5 英寸 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5 英寸 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25 英寸 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25 英寸 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25 英寸 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25 英寸 1.3 GB" + +msgid "Perfect RPM" +msgstr "标准转速 (RPM)" + +msgid "1% below perfect RPM" +msgstr "低于标准转速的 1%" + +msgid "1.5% below perfect RPM" +msgstr "低于标准转速的 1.5%" + +msgid "2% below perfect RPM" +msgstr "低于标准转速的 2%" + +msgid "(System Default)" +msgstr "(系统默认)" + diff --git a/src/qt/macos_event_filter.mm b/src/qt/macos_event_filter.mm new file mode 100644 index 000000000..0ea799f99 --- /dev/null +++ b/src/qt/macos_event_filter.mm @@ -0,0 +1,103 @@ +#include +//#include "86box/plat.h" +#include "cocoa_mouse.hpp" +#import +extern "C" +{ +#include <86box/86box.h> +#include <86box/keyboard.h> +#include <86box/mouse.h> +#include <86box/config.h> +//#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/ui.h> +#include <86box/video.h> +extern int mouse_capture; +extern void plat_mouse_capture(int); +} + +typedef struct mouseinputdata +{ + int deltax, deltay, deltaz; + int mousebuttons; +} mouseinputdata; + +static mouseinputdata mousedata; + +CocoaEventFilter::~CocoaEventFilter() +{ + +} + +bool CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) +{ + if (mouse_capture) + { + if (eventType == "mac_generic_NSEvent") + { + NSEvent* event = (NSEvent*)message; + if ([event type] == NSEventTypeMouseMoved + || [event type] == NSEventTypeLeftMouseDragged + || [event type] == NSEventTypeRightMouseDragged + || [event type] == NSEventTypeOtherMouseDragged) + { + mousedata.deltax += [event deltaX]; + mousedata.deltay += [event deltaY]; + return true; + } + if ([event type] == NSEventTypeScrollWheel) + { + mousedata.deltaz += [event deltaY]; + return true; + } + switch ([event type]) + { + default: return false; + case NSEventTypeLeftMouseDown: + { + mousedata.mousebuttons |= 1; + break; + } + case NSEventTypeLeftMouseUp: + { + mousedata.mousebuttons &= ~1; + break; + } + case NSEventTypeRightMouseDown: + { + mousedata.mousebuttons |= 2; + break; + } + case NSEventTypeRightMouseUp: + { + mousedata.mousebuttons &= ~2; + break; + } + case NSEventTypeOtherMouseDown: + { + mousedata.mousebuttons |= 4; + break; + } + case NSEventTypeOtherMouseUp: + { + if (mouse_get_buttons() < 3) { plat_mouse_capture(0); return true; } + mousedata.mousebuttons &= ~4; + break; + } + } + return true; + } + } + return false; +} + +extern "C" void macos_poll_mouse() +{ + mouse_x = mousedata.deltax; + mouse_y = mousedata.deltay; + mouse_z = mousedata.deltaz; + mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; + mouse_buttons = mousedata.mousebuttons; +} diff --git a/src/qt/qt.c b/src/qt/qt.c new file mode 100644 index 000000000..68b204dbc --- /dev/null +++ b/src/qt/qt.c @@ -0,0 +1,87 @@ +/* + * 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. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +/* + * C functionality for Qt platform, where the C equivalent is not easily + * implemented in Qt + */ +#if !defined(_WIN32) || !defined(__clang__) +#include +#endif +#include +#include +#include + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/timer.h> +#include <86box/nvr.h> + +int qt_nvr_save(void) { + return nvr_save(); +} + +char icon_set[256] = ""; /* name of the iconset to be used */ + +int +plat_vidapi(char* api) { + if (!strcasecmp(api, "default") || !strcasecmp(api, "system")) { + return 0; + } else if (!strcasecmp(api, "qt_software")) { + return 0; + } else if (!strcasecmp(api, "qt_opengl")) { + return 1; + } else if (!strcasecmp(api, "qt_opengles")) { + return 2; + } else if (!strcasecmp(api, "qt_opengl3")) { + return 3; + } else if (!strcasecmp(api, "qt_vulkan")) { + return 4; + } else if (!strcasecmp(api, "qt_d3d9")) { + return 5; + } + + return 0; +} + +char* plat_vidapi_name(int api) { + char* name = "default"; + + switch (api) { + case 0: + name = "qt_software"; + break; + case 1: + name = "qt_opengl"; + break; + case 2: + name = "qt_opengles"; + break; + case 3: + name = "qt_opengl3"; + break; + case 4: + name = "qt_vulkan"; + break; + case 5: + name = "qt_d3d9"; + break; + default: + fatal("Unknown renderer: %i\n", api); + break; + } + + return name; +} diff --git a/src/qt/qt_cdrom.c b/src/qt/qt_cdrom.c new file mode 100644 index 000000000..a15e9c600 --- /dev/null +++ b/src/qt/qt_cdrom.c @@ -0,0 +1,55 @@ +/* + * 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. + * + * Handle the platform-side of CDROM/ZIP/MO drives. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> +#include <86box/fdd.h> +#include <86box/hdd.h> +#include <86box/scsi_device.h> +#include <86box/cdrom.h> +#include <86box/mo.h> +#include <86box/zip.h> +#include <86box/scsi_disk.h> +#include <86box/plat.h> +#include <86box/ui.h> + +void +plat_cdrom_ui_update(uint8_t id, uint8_t reload) +{ + cdrom_t *drv = &cdrom[id]; + + if (drv->host_drive == 0) { + ui_sb_update_icon_state(SB_CDROM|id, 1); + } else { + ui_sb_update_icon_state(SB_CDROM|id, 0); + } + + //media_menu_update_cdrom(id); + ui_sb_update_tip(SB_CDROM|id); +} diff --git a/src/qt/qt_d3d9renderer.cpp b/src/qt/qt_d3d9renderer.cpp new file mode 100644 index 000000000..cb2d0a25a --- /dev/null +++ b/src/qt/qt_d3d9renderer.cpp @@ -0,0 +1,168 @@ +#include "qt_d3d9renderer.hpp" +#include +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/video.h> +} + +D3D9Renderer::D3D9Renderer(QWidget *parent, int monitor_index) + : QWidget{parent}, RendererCommon() +{ + QPalette pal = palette(); + pal.setColor(QPalette::Window, Qt::black); + setAutoFillBackground(true); + setPalette(pal); + + setAttribute(Qt::WA_NativeWindow); + setAttribute(Qt::WA_PaintOnScreen); + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_OpaquePaintEvent); + + windowHandle = (HWND)winId(); + surfaceInUse = true; + + RendererCommon::parentWidget = parent; + + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + this->m_monitor_index = monitor_index; +} + +D3D9Renderer::~D3D9Renderer() +{ + finalize(); +} + +void D3D9Renderer::finalize() +{ + if (!finalized) { + while (surfaceInUse) {} + finalized = true; + } + surfaceInUse = true; + if (d3d9surface) { d3d9surface->Release(); d3d9surface = nullptr;} + if (d3d9dev) { d3d9dev->Release(); d3d9dev = nullptr; } + if (d3d9) { d3d9->Release(); d3d9 = nullptr; }; +} + +void D3D9Renderer::hideEvent(QHideEvent *event) +{ + finalize(); +} + +void D3D9Renderer::showEvent(QShowEvent *event) +{ + params = {}; + + if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9))) { + return error("Failed to create Direct3D 9 context"); + } + + params.Windowed = true; + params.SwapEffect = D3DSWAPEFFECT_FLIPEX; + params.BackBufferWidth = width() * devicePixelRatioF(); + params.BackBufferHeight = height() * devicePixelRatioF(); + params.BackBufferCount = 1; + params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + params.hDeviceWindow = windowHandle; + + HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING, ¶ms, nullptr, &d3d9dev); + if (FAILED(result)) result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶ms, nullptr, &d3d9dev); + if (FAILED(result)) { + return error("Failed to create Direct3D 9 device"); + } + + result = d3d9dev->CreateOffscreenPlainSurface(2048, 2048, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9surface, nullptr); + if (FAILED(result)) result = d3d9dev->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9surface, nullptr); + if (FAILED(result)) { + return error("Failed to create Direct3D 9 surface"); + } + if (!alreadyInitialized) { + emit initialized(); + alreadyInitialized = true; + } + surfaceInUse = false; + finalized = false; +} + +void D3D9Renderer::paintEvent(QPaintEvent *event) +{ + IDirect3DSurface9* backbuffer = nullptr; + RECT srcRect, dstRect; + HRESULT result = d3d9dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); + + if (FAILED(result)) { + return; + } + + srcRect.top = source.top(); + srcRect.bottom = source.bottom(); + srcRect.left = source.left(); + srcRect.right = source.right(); + dstRect.top = destination.top(); + dstRect.bottom = destination.bottom(); + dstRect.left = destination.left(); + dstRect.right = destination.right(); + d3d9dev->BeginScene(); + while (surfaceInUse) {} + surfaceInUse = true; + d3d9dev->StretchRect(d3d9surface, &srcRect, backbuffer, &dstRect, video_filter_method == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR); + result = d3d9dev->EndScene(); + surfaceInUse = false; + if (SUCCEEDED(result)) { + if (FAILED(d3d9dev->PresentEx(nullptr, nullptr, 0, nullptr, 0))) { + finalize(); + showEvent(nullptr); + } + } +} + +bool D3D9Renderer::event(QEvent *event) +{ + bool res = false; + if (!eventDelegate(event, res)) return QWidget::event(event); + return res; +} + +void D3D9Renderer::resizeEvent(QResizeEvent *event) +{ + onResize(event->size().width() * devicePixelRatioF(), event->size().height() * devicePixelRatioF()); + + params.BackBufferWidth = event->size().width() * devicePixelRatioF(); + params.BackBufferHeight = event->size().height() * devicePixelRatioF(); + if (d3d9dev) d3d9dev->Reset(¶ms); + QWidget::resizeEvent(event); +} + +void D3D9Renderer::blit(int x, int y, int w, int h) +{ + if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || surfaceInUse) { + video_blit_complete_monitor(m_monitor_index); + return; + } + surfaceInUse = true; + source.setRect(x, y, w, h); + RECT srcRect; + D3DLOCKED_RECT lockRect; + srcRect.top = source.top(); + srcRect.bottom = source.bottom(); + srcRect.left = source.left(); + srcRect.right = source.right(); + + if (monitors[m_monitor_index].mon_screenshots) { + video_screenshot_monitor((uint32_t *) &(monitors[m_monitor_index].target_buffer->line[y][x]), 0, 0, 2048, m_monitor_index); + } + if (SUCCEEDED(d3d9surface->LockRect(&lockRect, &srcRect, 0))) { + for (int y1 = 0; y1 < h; y1++) { + video_copy(((uint8_t*)lockRect.pBits) + (y1 * lockRect.Pitch), &(monitors[m_monitor_index].target_buffer->line[y + y1][x]), w * 4); + } + video_blit_complete_monitor(m_monitor_index); + d3d9surface->UnlockRect(); + } + else video_blit_complete_monitor(m_monitor_index); + surfaceInUse = false; + QTimer::singleShot(0, this, [this] { this->update(); }); +} diff --git a/src/qt/qt_d3d9renderer.hpp b/src/qt/qt_d3d9renderer.hpp new file mode 100644 index 000000000..d93781236 --- /dev/null +++ b/src/qt/qt_d3d9renderer.hpp @@ -0,0 +1,45 @@ +#ifndef D3D9RENDERER_HPP +#define D3D9RENDERER_HPP + +#include +#include "qt_renderercommon.hpp" + +#include +#include +#include + +class D3D9Renderer : public QWidget, public RendererCommon +{ + Q_OBJECT +public: + explicit D3D9Renderer(QWidget *parent = nullptr, int monitor_index = 0); + ~D3D9Renderer(); + bool hasBlitFunc() override { return true; } + void blit(int x, int y, int w, int h) override; + void finalize() override; + +protected: + void showEvent(QShowEvent* event) override; + void hideEvent(QHideEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void paintEvent(QPaintEvent *event) override; + bool event(QEvent* event) override; + QPaintEngine* paintEngine() const override { return nullptr; } + +signals: + void initialized(); + void error(QString); + +private: + HWND windowHandle = 0; + D3DPRESENT_PARAMETERS params{}; + IDirect3D9Ex* d3d9 = nullptr; + IDirect3DDevice9Ex* d3d9dev = nullptr; + IDirect3DSurface9* d3d9surface = nullptr; + + std::atomic surfaceInUse{false}, finalized{false}; + bool alreadyInitialized = false; + int m_monitor_index = 0; +}; + +#endif // D3D9RENDERER_HPP diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp new file mode 100644 index 000000000..6ebc59b5d --- /dev/null +++ b/src/qt/qt_deviceconfig.cpp @@ -0,0 +1,272 @@ +/* + * 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. + * + * Device configuration UI code. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2022 Cacodemon345 + */ +#include "qt_deviceconfig.hpp" +#include "ui_qt_deviceconfig.h" +#include "qt_settings.hpp" + +#include +#include +#include +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/device.h> +#include <86box/midi_rtmidi.h> +#include <86box/mem.h> +#include <86box/rom.h> +} + +#include "qt_filefield.hpp" +#include "qt_models_common.hpp" + +DeviceConfig::DeviceConfig(QWidget *parent) : + QDialog(parent), + ui(new Ui::DeviceConfig) +{ + ui->setupUi(this); +} + +DeviceConfig::~DeviceConfig() +{ + delete ui; +} + +void DeviceConfig::ConfigureDevice(const _device_* device, int instance, Settings* settings) { + DeviceConfig dc(settings); + dc.setWindowTitle(QString("%1 Device Configuration").arg(device->name)); + int combo_to_struct[256]; + int c, d, p, q; + + device_context_t device_context; + device_set_context(&device_context, device, instance); + + const auto* config = device->config; + while (config->type != -1) { + switch (config->type) { + case CONFIG_BINARY: + { + auto value = config_get_int(device_context.name, const_cast(config->name), config->default_int); + auto* cbox = new QCheckBox(); + cbox->setObjectName(config->name); + cbox->setChecked(value > 0); + dc.ui->formLayout->addRow(config->description, cbox); + break; + } +#ifdef USE_RTMIDI + case CONFIG_MIDI_OUT: + { + auto* cbox = new QComboBox(); + cbox->setObjectName(config->name); + auto* model = cbox->model(); + int currentIndex = -1; + int selected = config_get_int(device_context.name, const_cast(config->name), config->default_int); + for (int i = 0; i < rtmidi_out_get_num_devs(); i++) { + char midiName[512] = { 0 }; + rtmidi_out_get_dev_name(i, midiName); + + Models::AddEntry(model, midiName, i); + if (selected == i) { + currentIndex = i; + } + } + dc.ui->formLayout->addRow(config->description, cbox); + cbox->setCurrentIndex(currentIndex); + break; + } + case CONFIG_MIDI_IN: + { + auto* cbox = new QComboBox(); + cbox->setObjectName(config->name); + auto* model = cbox->model(); + int currentIndex = -1; + int selected = config_get_int(device_context.name, const_cast(config->name), config->default_int); + for (int i = 0; i < rtmidi_in_get_num_devs(); i++) { + char midiName[512] = { 0 }; + rtmidi_in_get_dev_name(i, midiName); + + Models::AddEntry(model, midiName, i); + if (selected == i) { + currentIndex = i; + } + } + dc.ui->formLayout->addRow(config->description, cbox); + cbox->setCurrentIndex(currentIndex); + break; + } +#endif + case CONFIG_SELECTION: + case CONFIG_HEX16: + case CONFIG_HEX20: + { + auto* cbox = new QComboBox(); + cbox->setObjectName(config->name); + auto* model = cbox->model(); + int currentIndex = -1; + int selected = 0; + switch (config->type) { + case CONFIG_SELECTION: + selected = config_get_int(device_context.name, const_cast(config->name), config->default_int); + break; + case CONFIG_HEX16: + selected = config_get_hex16(device_context.name, const_cast(config->name), config->default_int); + break; + case CONFIG_HEX20: + selected = config_get_hex20(device_context.name, const_cast(config->name), config->default_int); + break; + } + + for (auto* sel = config->selection; (sel != nullptr) && (sel->description != nullptr) && (strlen(sel->description) > 0); ++sel) { + int row = Models::AddEntry(model, sel->description, sel->value); + if (selected == sel->value) { + currentIndex = row; + } + } + dc.ui->formLayout->addRow(config->description, cbox); + cbox->setCurrentIndex(currentIndex); + break; + } + case CONFIG_BIOS: + { + auto* cbox = new QComboBox(); + cbox->setObjectName(config->name); + auto* model = cbox->model(); + int currentIndex = -1; + char *selected; + selected = config_get_string(device_context.name, const_cast(config->name), const_cast(config->default_string)); + + c = q = 0; + for (auto* bios = config->bios; (bios != nullptr) && (bios->name != nullptr) && (strlen(bios->name) > 0); ++bios) { + p = 0; + for (d = 0; d < bios->files_no; d++) + p += !!rom_present(const_cast(bios->files[d])); + if (p == bios->files_no) { + int row = Models::AddEntry(model, bios->name, q); + if (!strcmp(selected, bios->internal_name)) { + currentIndex = row; + } + c++; + } + q++; + } + dc.ui->formLayout->addRow(config->description, cbox); + cbox->setCurrentIndex(currentIndex); + break; + } + case CONFIG_SPINNER: + { + int value = config_get_int(device_context.name, const_cast(config->name), config->default_int); + auto* spinBox = new QSpinBox(); + spinBox->setObjectName(config->name); + spinBox->setMaximum(config->spinner.max); + spinBox->setMinimum(config->spinner.min); + if (config->spinner.step > 0) { + spinBox->setSingleStep(config->spinner.step); + } + spinBox->setValue(value); + dc.ui->formLayout->addRow(config->description, spinBox); + break; + } + case CONFIG_FNAME: + { + auto* fileName = config_get_string(device_context.name, const_cast(config->name), const_cast(config->default_string)); + auto* fileField = new FileField(); + fileField->setObjectName(config->name); + fileField->setFileName(fileName); + fileField->setFilter(QString(config->file_filter).left(strcspn(config->file_filter, "|"))); + dc.ui->formLayout->addRow(config->description, fileField); + break; + } + } + ++config; + } + + dc.setFixedSize(dc.minimumSizeHint()); + int res = dc.exec(); + if (res == QDialog::Accepted) { + config = device->config; + while (config->type != -1) { + switch (config->type) { + case CONFIG_BINARY: + { + auto* cbox = dc.findChild(config->name); + config_set_int(device_context.name, const_cast(config->name), cbox->isChecked() ? 1 : 0); + break; + } + case CONFIG_MIDI_OUT: + case CONFIG_MIDI_IN: + case CONFIG_SELECTION: + { + auto* cbox = dc.findChild(config->name); + config_set_int(device_context.name, const_cast(config->name), cbox->currentData().toInt()); + break; + } + case CONFIG_BIOS: + { + auto* cbox = dc.findChild(config->name); + int idx = cbox->currentData().toInt(); + config_set_string(device_context.name, const_cast(config->name), const_cast(config->bios[idx].internal_name)); + break; + } + case CONFIG_HEX16: + { + auto* cbox = dc.findChild(config->name); + config_set_hex16(device_context.name, const_cast(config->name), cbox->currentData().toInt()); + break; + } + case CONFIG_HEX20: + { + auto* cbox = dc.findChild(config->name); + config_set_hex20(device_context.name, const_cast(config->name), cbox->currentData().toInt()); + break; + } + case CONFIG_FNAME: + { + auto* fbox = dc.findChild(config->name); + auto fileName = fbox->fileName().toUtf8(); + config_set_string(device_context.name, const_cast(config->name), fileName.data()); + break; + } + case CONFIG_SPINNER: + { + auto* spinBox = dc.findChild(config->name); + config_set_int(device_context.name, const_cast(config->name), spinBox->value()); + break; + } + } + config++; + } + } +} + +QString DeviceConfig::DeviceName(const _device_* device, const char *internalName, int bus) { + if (QStringLiteral("none") == internalName) { + return tr("None"); + } else if (QStringLiteral("internal") == internalName) { + return tr("Internal controller"); + } else if (device == nullptr) { + return QString(); + } else { + char temp[512]; + device_get_name(device, bus, temp); + return tr(temp, nullptr, 512); + } +} diff --git a/src/qt/qt_deviceconfig.hpp b/src/qt/qt_deviceconfig.hpp new file mode 100644 index 000000000..2662df11c --- /dev/null +++ b/src/qt/qt_deviceconfig.hpp @@ -0,0 +1,32 @@ +#ifndef QT_DEVICECONFIG_HPP +#define QT_DEVICECONFIG_HPP + +#include + +#include "qt_settings.hpp" + +extern "C" { +struct _device_; +} + +namespace Ui { +class DeviceConfig; +} + +class Settings; + +class DeviceConfig : public QDialog +{ + Q_OBJECT + +public: + explicit DeviceConfig(QWidget *parent = nullptr); + ~DeviceConfig(); + + static void ConfigureDevice(const _device_* device, int instance = 0, Settings* settings = nullptr); + static QString DeviceName(const _device_* device, const char* internalName, int bus); +private: + Ui::DeviceConfig *ui; +}; + +#endif // QT_DEVICECONFIG_HPP diff --git a/src/qt/qt_deviceconfig.ui b/src/qt/qt_deviceconfig.ui new file mode 100644 index 000000000..0a7e7d974 --- /dev/null +++ b/src/qt/qt_deviceconfig.ui @@ -0,0 +1,74 @@ + + + DeviceConfig + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + DeviceConfig + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DeviceConfig + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_filefield.cpp b/src/qt/qt_filefield.cpp new file mode 100644 index 000000000..0639ad0fc --- /dev/null +++ b/src/qt/qt_filefield.cpp @@ -0,0 +1,60 @@ +/* + * 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. + * + * File field widget. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2022 Cacodemon345 + */ +#include "qt_filefield.hpp" +#include "ui_qt_filefield.h" + +#include + +FileField::FileField(QWidget *parent) : + QWidget(parent), + ui(new Ui::FileField) +{ + ui->setupUi(this); + + connect(ui->label, &QLineEdit::editingFinished, this, [this] () { + fileName_ = ui->label->text(); + emit fileSelected(ui->label->text()); + }); + this->setFixedWidth(this->sizeHint().width() + ui->pushButton->sizeHint().width()); +} + +FileField::~FileField() +{ + delete ui; +} + +void FileField::setFileName(const QString &fileName) { + fileName_ = fileName; + ui->label->setText(fileName); +} + +void FileField::on_pushButton_clicked() { + QString fileName; + if (createFile_) { + fileName = QFileDialog::getSaveFileName(this, QString(), QString(), filter_, &selectedFilter_); + } else { + fileName = QFileDialog::getOpenFileName(this, QString(), QString(), filter_, &selectedFilter_); + } + + if (!fileName.isNull()) { + fileName_ = fileName; + ui->label->setText(fileName); + emit fileSelected(fileName); + } +} diff --git a/src/qt/qt_filefield.hpp b/src/qt/qt_filefield.hpp new file mode 100644 index 000000000..00c4a5e12 --- /dev/null +++ b/src/qt/qt_filefield.hpp @@ -0,0 +1,41 @@ +#ifndef QT_FILEFIELD_HPP +#define QT_FILEFIELD_HPP + +#include + +namespace Ui { +class FileField; +} + +class FileField : public QWidget +{ + Q_OBJECT + +public: + explicit FileField(QWidget *parent = nullptr); + ~FileField(); + + QString fileName() const { return fileName_; } + void setFileName(const QString& fileName); + + void setFilter(const QString& filter) { filter_ = filter; } + QString selectedFilter() const { return selectedFilter_; } + + void setCreateFile(bool createFile) { createFile_ = createFile; } + bool createFile() { return createFile_; } + +signals: + void fileSelected(const QString& fileName); + +private slots: + void on_pushButton_clicked(); + +private: + Ui::FileField *ui; + QString fileName_; + QString selectedFilter_; + QString filter_; + bool createFile_ = false; +}; + +#endif // QT_FILEFIELD_HPP diff --git a/src/qt/qt_filefield.ui b/src/qt/qt_filefield.ui new file mode 100644 index 000000000..3a1e3e753 --- /dev/null +++ b/src/qt/qt_filefield.ui @@ -0,0 +1,62 @@ + + + FileField + + + + 0 + 0 + 354 + 25 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + &Specify... + + + + + + + + diff --git a/src/qt/qt_harddiskdialog.cpp b/src/qt/qt_harddiskdialog.cpp new file mode 100644 index 000000000..91179cdbc --- /dev/null +++ b/src/qt/qt_harddiskdialog.cpp @@ -0,0 +1,802 @@ +/* + * 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. + * + * Hard disk dialog code. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2022 Cacodemon345 + */ +#include "qt_harddiskdialog.hpp" +#include "ui_qt_harddiskdialog.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/hdd.h> +#include "../disk/minivhd/minivhd.h" +#include "../disk/minivhd/minivhd_util.h" +} + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qt_harddrive_common.hpp" +#include "qt_settings_bus_tracking.hpp" +#include "qt_models_common.hpp" +#include "qt_util.hpp" + +HarddiskDialog::HarddiskDialog(bool existing, QWidget *parent) : + QDialog(parent), + ui(new Ui::HarddiskDialog) +{ + ui->setupUi(this); + + if (existing) { + ui->fileField->setFilter(tr("Hard disk images") % util::DlgFilter({ "hd?", "im?", "vhd" }) % tr("All files") % util::DlgFilter({ "*" }, true)); + + setWindowTitle(tr("Add Existing Hard Disk")); + ui->lineEditCylinders->setEnabled(false); + ui->lineEditHeads->setEnabled(false); + ui->lineEditSectors->setEnabled(false); + ui->lineEditSize->setEnabled(false); + ui->comboBoxType->setEnabled(false); + + ui->comboBoxFormat->hide(); + ui->labelFormat->hide(); + + connect(ui->fileField, &FileField::fileSelected, this, &HarddiskDialog::onExistingFileSelected); + } else { + QStringList filters({ tr("Raw image") % util::DlgFilter({ "img" }, true), + tr("HDI image") % util::DlgFilter({ "hdi" }, true), + tr("HDX image") % util::DlgFilter({ "hdx" }, true), + tr("Fixed-size VHD") % util::DlgFilter({ "vhd" }, true), + tr("Dynamic-size VHD") % util::DlgFilter({ "vhd" }, true), + tr("Differencing VHD") % util::DlgFilter({ "vhd" }, true) }); + + ui->fileField->setFilter(filters.join(";;")); + + setWindowTitle(tr("Add New Hard Disk")); + ui->fileField->setCreateFile(true); + + connect(ui->fileField, &FileField::fileSelected, this, [this, filters] { + int filter = filters.indexOf(ui->fileField->selectedFilter()); + if (filter > -1) + ui->comboBoxFormat->setCurrentIndex(filter); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + }); + } + + auto* model = ui->comboBoxFormat->model(); + model->insertRows(0, 6); + model->setData(model->index(0, 0), tr("Raw image (.img)")); + model->setData(model->index(1, 0), tr("HDI image (.hdi)")); + model->setData(model->index(2, 0), tr("HDX image (.hdx)")); + model->setData(model->index(3, 0), tr("Fixed-size VHD (.vhd)")); + model->setData(model->index(4, 0), tr("Dynamic-size VHD (.vhd)")); + model->setData(model->index(5, 0), tr("Differencing VHD (.vhd)")); + + model = ui->comboBoxBlockSize->model(); + model->insertRows(0, 2); + model->setData(model->index(0, 0), tr("Large blocks (2 MB)")); + model->setData(model->index(1, 0), tr("Small blocks (512 KB)")); + + ui->comboBoxBlockSize->hide(); + ui->labelBlockSize->hide(); + + Harddrives::populateBuses(ui->comboBoxBus->model()); + ui->comboBoxBus->setCurrentIndex(3); + + model = ui->comboBoxType->model(); + for (int i = 0; i < 127; i++) { + uint64_t size = ((uint64_t) hdd_table[i][0]) * hdd_table[i][1] * hdd_table[i][2]; + uint32_t size_mb = size >> 11LL; + //QString text = QString("%1 MiB (CHS: %2, %3, %4)").arg(size_mb).arg(hdd_table[i][0]).arg(hdd_table[i][1]).arg(hdd_table[i][2]); + QString text = QString::asprintf(tr("%u MB (CHS: %i, %i, %i)").toUtf8().constData(), (size_mb), (hdd_table[i][0]), (hdd_table[i][1]), (hdd_table[i][2])); + Models::AddEntry(model, text, i); + } + Models::AddEntry(model, tr("Custom..."), 127); + Models::AddEntry(model, tr("Custom (large)..."), 128); + + ui->lineEditSize->setValidator(new QIntValidator()); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); +} + +HarddiskDialog::~HarddiskDialog() +{ + delete ui; +} + +uint8_t HarddiskDialog::bus() const { + return static_cast(ui->comboBoxBus->currentData().toUInt()); +} + +uint8_t HarddiskDialog::channel() const { + return static_cast(ui->comboBoxChannel->currentData().toUInt()); +} + +QString HarddiskDialog::fileName() const { + return ui->fileField->fileName(); +} + +uint32_t HarddiskDialog::speed() const { + return static_cast(ui->comboBoxSpeed->currentData().toUInt()); +} + +void HarddiskDialog::on_comboBoxFormat_currentIndexChanged(int index) { + bool enabled; + if (index == 5) { /* They switched to a diff VHD; disable the geometry fields. */ + enabled = false; + ui->lineEditCylinders->setText(tr("(N/A)")); + ui->lineEditHeads->setText(tr("(N/A)")); + ui->lineEditSectors->setText(tr("(N/A)")); + ui->lineEditSize->setText(tr("(N/A)")); + } else { + enabled = true; + ui->lineEditCylinders->setText(QString::number(cylinders_)); + ui->lineEditHeads->setText(QString::number(heads_)); + ui->lineEditSectors->setText(QString::number(sectors_)); + recalcSize(); + } + ui->lineEditCylinders->setEnabled(enabled); + ui->lineEditHeads->setEnabled(enabled); + ui->lineEditSectors->setEnabled(enabled); + ui->lineEditSize->setEnabled(enabled); + ui->comboBoxType->setEnabled(enabled); + + if (index < 4) { + ui->comboBoxBlockSize->hide(); + ui->labelBlockSize->hide(); + } else { + ui->comboBoxBlockSize->show(); + ui->labelBlockSize->show(); + } +} + +/* If the disk geometry requested in the 86Box GUI is not compatible with the internal VHD geometry, + * we adjust it to the next-largest size that is compatible. On average, this will be a difference + * of about 21 MB, and should only be necessary for VHDs larger than 31.5 GB, so should never be more + * than a tenth of a percent change in size. + */ +static void adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry) +{ + if (_86box_geometry->cyl <= 65535) { + vhd_geometry->cyl = _86box_geometry->cyl; + vhd_geometry->heads = _86box_geometry->heads; + vhd_geometry->spt = _86box_geometry->spt; + return; + } + + int desired_sectors = _86box_geometry->cyl * _86box_geometry->heads * _86box_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors += (85680 - remainder); + + _86box_geometry->cyl = desired_sectors / (16 * 63); + _86box_geometry->heads = 16; + _86box_geometry->spt = 63; + + vhd_geometry->cyl = desired_sectors / (16 * 255); + vhd_geometry->heads = 16; + vhd_geometry->spt = 255; +} + +static HarddiskDialog* callbackPtr = nullptr; +static MVHDGeom create_drive_vhd_fixed(const QString& fileName, HarddiskDialog* p, uint16_t cyl, uint8_t heads, uint8_t spt) { + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + + int vhd_error = 0; + QByteArray filenameBytes = fileName.toUtf8(); + callbackPtr = p; + MVHDMeta *vhd = mvhd_create_fixed(filenameBytes.data(), vhd_geometry, &vhd_error, [](uint32_t current_sector, uint32_t total_sectors) { + callbackPtr->fileProgress((current_sector * 100) / total_sectors); + }); + callbackPtr = nullptr; + + if (vhd == NULL) { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } else { + mvhd_close(vhd); + } + + return _86box_geometry; +} + +static MVHDGeom create_drive_vhd_dynamic(const QString& fileName, uint16_t cyl, uint8_t heads, uint8_t spt, int blocksize) { + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + int vhd_error = 0; + QByteArray filenameBytes = fileName.toUtf8(); + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filenameBytes.data(); + options.size_in_bytes = 0; + options.geometry = vhd_geometry; + options.type = MVHD_TYPE_DYNAMIC; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + if (vhd == NULL) { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } else { + mvhd_close(vhd); + } + + return _86box_geometry; +} + +static MVHDGeom create_drive_vhd_diff(const QString& fileName, const QString& parentFileName, int blocksize) { + int vhd_error = 0; + QByteArray filenameBytes = fileName.toUtf8(); + QByteArray parentFilenameBytes = parentFileName.toUtf8(); + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filenameBytes.data(); + options.parent_path = parentFilenameBytes.data(); + options.type = MVHD_TYPE_DIFF; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + MVHDGeom vhd_geometry; + if (vhd == NULL) { + vhd_geometry.cyl = 0; + vhd_geometry.heads = 0; + vhd_geometry.spt = 0; + } else { + vhd_geometry = mvhd_get_geometry(vhd); + + if (vhd_geometry.spt > 63) { + vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); + vhd_geometry.heads = 16; + vhd_geometry.spt = 63; + } + + mvhd_close(vhd); + } + + return vhd_geometry; +} + +void HarddiskDialog::onCreateNewFile() { + + for (auto& curObject : children()) + { + if (qobject_cast(curObject)) qobject_cast(curObject)->setDisabled(true); + } + + ui->progressBar->setEnabled(true); + setResult(QDialog::Rejected); + qint64 size = ui->lineEditSize->text().toUInt() << 20U; + if (size > 0x1FFFFFFE00ll) { + QMessageBox::critical(this, tr("Disk image too large"), tr("Disk images cannot be larger than 127 GB.")); + return; + } + + int img_format = ui->comboBoxFormat->currentIndex(); + uint32_t zero = 0; + uint32_t base = 0x1000; + uint32_t sector_size = 512; + + auto fileName = ui->fileField->fileName(); + QString expectedSuffix; + switch (img_format) { + case 1: + expectedSuffix = "hdi"; + break; + case 2: + expectedSuffix = "hdx"; + break; + case 3: + case 4: + case 5: + expectedSuffix = "vhd"; + break; + } + if (! expectedSuffix.isEmpty()) { + QFileInfo fileInfo(fileName); + if (fileInfo.suffix().compare(expectedSuffix, Qt::CaseInsensitive) != 0) { + fileName = QString("%1.%2").arg(fileName, expectedSuffix); + ui->fileField->setFileName(fileName); + } + } + + QFile file(fileName); + if (! file.open(QIODevice::WriteOnly)) { + QMessageBox::critical(this, tr("Unable to write file"), tr("Make sure the file is being saved to a writable directory.")); + return; + } + + if (img_format == 1) { /* HDI file */ + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + if (size >= 0x100000000ll) { + QMessageBox::critical(this, tr("Disk image too large"), tr("HDI disk images cannot be larger than 4 GB.")); + return; + } + uint32_t s = static_cast(size); + stream << zero; /* 00000000: Zero/unknown */ + stream << zero; /* 00000004: Zero/unknown */ + stream << base; /* 00000008: Offset at which data starts */ + stream << s; /* 0000000C: Full size of the data (32-bit) */ + stream << sector_size; /* 00000010: Sector size in bytes */ + stream << sectors_; /* 00000014: Sectors per cylinder */ + stream << heads_; /* 00000018: Heads per cylinder */ + stream << cylinders_; /* 0000001C: Cylinders */ + + for (int i = 0; i < 0x3f8; i++) { + stream << zero; + } + } else if (img_format == 2) { /* HDX file */ + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + quint64 signature = 0xD778A82044445459; + stream << signature; /* 00000000: Signature */ + stream << size; /* 00000008: Full size of the data (64-bit) */ + stream << sector_size; /* 00000010: Sector size in bytes */ + stream << sectors_; /* 00000014: Sectors per cylinder */ + stream << heads_; /* 00000018: Heads per cylinder */ + stream << cylinders_; /* 0000001C: Cylinders */ + stream << zero; /* 00000020: [Translation] Sectors per cylinder */ + stream << zero; /* 00000004: [Translation] Heads per cylinder */ + } else if (img_format >= 3) { /* VHD file */ + file.close(); + + MVHDGeom _86box_geometry{}; + int block_size = ui->comboBoxBlockSize->currentIndex() == 0 ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL; + switch (img_format) { + case 3: + { + connect(this, &HarddiskDialog::fileProgress, this, [this] (int value) { ui->progressBar->setValue(value); QApplication::processEvents(); } ); + ui->progressBar->setVisible(true); + [&_86box_geometry, fileName, this] { + _86box_geometry = create_drive_vhd_fixed(fileName, this, cylinders_, heads_, sectors_); + }(); + } + break; + case 4: + _86box_geometry = create_drive_vhd_dynamic(fileName, cylinders_, heads_, sectors_, block_size); + break; + case 5: + QString vhdParent = QFileDialog::getOpenFileName( + this, + tr("Select the parent VHD"), + QString(), + tr("VHD files") % + util::DlgFilter({ "vhd" }) % + tr("All files") % + util::DlgFilter({ "*" }, true)); + + if (vhdParent.isEmpty()) { + return; + } + _86box_geometry = create_drive_vhd_diff(fileName, vhdParent, block_size); + break; + } + + if (_86box_geometry.cyl == 0 && + _86box_geometry.heads == 0 && + _86box_geometry.spt == 0) + { + QMessageBox::critical(this, tr("Unable to write file"), tr("Make sure the file is being saved to a writable directory.")); + return; + } + else if (img_format != 5) { + QMessageBox::information(this, tr("Disk image created"), tr("Remember to partition and format the newly-created drive.")); + } + + ui->lineEditCylinders->setText(QString::number(_86box_geometry.cyl)); + ui->lineEditHeads->setText(QString::number(_86box_geometry.heads)); + ui->lineEditSectors->setText(QString::number(_86box_geometry.spt)); + cylinders_ = _86box_geometry.cyl; + heads_ = _86box_geometry.heads; + sectors_ = _86box_geometry.spt; + setResult(QDialog::Accepted); + + return; + } + + // formats 0, 1 and 2 + connect(this, &HarddiskDialog::fileProgress, this, [this] (int value) { ui->progressBar->setValue(value); QApplication::processEvents(); } ); + ui->progressBar->setVisible(true); + [size, &file, this] { + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + + QByteArray buf(1048576, 0); + uint64_t mibBlocks = size >> 20; + uint64_t restBlock = size & 0xfffff; + + if (restBlock) { + stream.writeRawData(buf.data(), restBlock); + } + + if (mibBlocks) { + for (uint64_t i = 0; i < mibBlocks; ++i) { + stream.writeRawData(buf.data(), buf.size()); + emit fileProgress(static_cast((i * 100) / mibBlocks)); + } + } + emit fileProgress(100); + }(); + + QMessageBox::information(this, tr("Disk image created"), tr("Remember to partition and format the newly-created drive.")); + setResult(QDialog::Accepted); +} + +static void adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) { + if (vhd_geometry->spt <= 63) + return; + + int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors -= remainder; + + vhd_geometry->cyl = desired_sectors / (16 * 63); + vhd_geometry->heads = 16; + vhd_geometry->spt = 63; +} + +void HarddiskDialog::recalcSelection() { + int selection = 127; + for (int i = 0; i < 127; i++) { + if ((cylinders_ == hdd_table[i][0]) && + (heads_ == hdd_table[i][1]) && + (sectors_ == hdd_table[i][2])) + selection = i; + } + if ((selection == 127) && (heads_ == 16) && (sectors_ == 63)) { + selection = 128; + } + ui->comboBoxType->setCurrentIndex(selection); +} + +void HarddiskDialog::onExistingFileSelected(const QString &fileName) { + // TODO : Over to non-existing file selected + /* + if (!(existing & 1)) { + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) { + fclose(f); + if (settings_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_4111, (wchar_t *) IDS_4118, (wchar_t *) IDS_4120, (wchar_t *) IDS_4121, NULL) != 0) / * yes * / + return FALSE; + } + } + + f = _wfopen(wopenfilestring, (existing & 1) ? L"rb" : L"wb"); + if (f == NULL) { + hdd_add_file_open_error: + fclose(f); + settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); + return TRUE; + } + */ + + uint64_t size = 0; + uint32_t sector_size = 0; + uint32_t sectors = 0; + uint32_t heads = 0; + uint32_t cylinders = 0; + int vhd_error = 0; + + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + QFile file(fileName); + if (! file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, tr("Unable to read file"), tr("Make sure the file exists and is readable.")); + return; + } + QByteArray fileNameUtf8 = fileName.toUtf8(); + + QFileInfo fi(file); + if (image_is_hdi(fileNameUtf8.data()) || image_is_hdx(fileNameUtf8.data(), 1)) { + file.seek(0x10); + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> sector_size; + if (sector_size != 512) { + QMessageBox::critical(this, tr("Unsupported disk image"), tr("HDI or HDX images with a sector size other than 512 are not supported.")); + return; + } + + sectors = heads = cylinders = 0; + stream >> sectors; + stream >> heads; + stream >> cylinders; + } else if (image_is_vhd(fileNameUtf8.data(), 1)) { + MVHDMeta* vhd = mvhd_open(fileNameUtf8.data(), 0, &vhd_error); + if (vhd == nullptr) { + QMessageBox::critical(this, tr("Unable to read file"), tr("Make sure the file exists and is readable")); + return; + } else if (vhd_error == MVHD_ERR_TIMESTAMP) { + QMessageBox::StandardButton btn = QMessageBox::warning(this, tr("Parent and child disk timestamps do not match"), tr("This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?"), QMessageBox::Yes | QMessageBox::No); + if (btn == QMessageBox::Yes) { + int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); + if (ts_res != 0) { + QMessageBox::critical(this, tr("Error"), tr("Could not fix VHD timestamp")); + mvhd_close(vhd); + return; + } + } else { + mvhd_close(vhd); + return; + } + } + + MVHDGeom vhd_geom = mvhd_get_geometry(vhd); + adjust_vhd_geometry_for_86box(&vhd_geom); + cylinders = vhd_geom.cyl; + heads = vhd_geom.heads; + sectors = vhd_geom.spt; + size = static_cast(cylinders * heads * sectors * 512); + mvhd_close(vhd); + } else { + size = file.size(); + if (((size % 17) == 0) && (size <= 142606336)) { + sectors = 17; + if (size <= 26738688) + heads = 4; + else if (((size % 3072) == 0) && (size <= 53477376)) + heads = 6; + else { + uint32_t i; + for (i = 5; i < 16; i++) { + if (((size % (i << 9)) == 0) && (size <= ((i * 17) << 19))) + break; + if (i == 5) + i++; + } + heads = i; + } + } else { + sectors = 63; + heads = 16; + } + + cylinders = ((size >> 9) / heads) / sectors; + } + + if ((sectors > max_sectors) || (heads > max_heads) || (cylinders > max_cylinders)) { + QMessageBox::critical(this, tr("Unable to read file"), tr("Make sure the file exists and is readable")); + return; + } + + heads_ = heads; + sectors_ = sectors; + cylinders_ = cylinders; + ui->lineEditCylinders->setText(QString::number(cylinders)); + ui->lineEditHeads->setText(QString::number(heads)); + ui->lineEditSectors->setText(QString::number(sectors)); + recalcSize(); + recalcSelection(); + + ui->lineEditCylinders->setEnabled(true); + ui->lineEditHeads->setEnabled(true); + ui->lineEditSectors->setEnabled(true); + ui->lineEditSize->setEnabled(true); + ui->comboBoxType->setEnabled(true); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); +} + +void HarddiskDialog::recalcSize() { + uint64_t size = (static_cast(cylinders_) * static_cast(heads_) * static_cast(sectors_)) << 9; + ui->lineEditSize->setText(QString::number(size >> 20)); +} + +bool HarddiskDialog::checkAndAdjustSectors() { + if (sectors_ > max_sectors) { + sectors_ = max_sectors; + ui->lineEditSectors->setText(QString::number(max_sectors)); + recalcSize(); + recalcSelection(); + return false; + } + return true; +} + +bool HarddiskDialog::checkAndAdjustHeads() { + if (heads_ > max_heads) { + heads_ = max_heads; + ui->lineEditHeads->setText(QString::number(max_heads)); + recalcSize(); + recalcSelection(); + return false; + } + return true; +} + +bool HarddiskDialog::checkAndAdjustCylinders() { + if (cylinders_ > max_cylinders) { + cylinders_ = max_cylinders; + ui->lineEditCylinders->setText(QString::number(max_cylinders)); + recalcSize(); + recalcSelection(); + return false; + } + return true; +} + + +void HarddiskDialog::on_comboBoxBus_currentIndexChanged(int index) { + int chanIdx = 0; + if (index < 0) { + return; + } + + switch (ui->comboBoxBus->currentData().toInt()) { + case HDD_BUS_DISABLED: + default: + max_sectors = max_heads = max_cylinders = 0; + break; + case HDD_BUS_MFM: + max_sectors = 26; /* 17 for MFM, 26 for RLL. */ + max_heads = 15; + max_cylinders = 2047; + break; + case HDD_BUS_XTA: + max_sectors = 63; + max_heads = 16; + max_cylinders = 1023; + break; + case HDD_BUS_ESDI: + max_sectors = 99; /* ESDI drives usually had 32 to 43 sectors per track. */ + max_heads = 16; + max_cylinders = 266305; + break; + case HDD_BUS_IDE: + max_sectors = 63; + max_heads = 255; + max_cylinders = 266305; + break; + case HDD_BUS_ATAPI: + case HDD_BUS_SCSI: + max_sectors = 99; + max_heads = 255; + max_cylinders = 266305; + break; + } + + checkAndAdjustCylinders(); + checkAndAdjustHeads(); + checkAndAdjustSectors(); + + if (ui->lineEditCylinders->validator() != nullptr) { + delete ui->lineEditCylinders->validator(); + } + if (ui->lineEditHeads->validator() != nullptr) { + delete ui->lineEditHeads->validator(); + } + if (ui->lineEditSectors->validator() != nullptr) { + delete ui->lineEditSectors->validator(); + } + + ui->lineEditCylinders->setValidator(new QIntValidator(1, max_cylinders, this)); + ui->lineEditHeads->setValidator(new QIntValidator(1, max_heads, this)); + ui->lineEditSectors->setValidator(new QIntValidator(1, max_sectors, this)); + + Harddrives::populateBusChannels(ui->comboBoxChannel->model(), ui->comboBoxBus->currentData().toInt()); + Harddrives::populateSpeeds(ui->comboBoxSpeed->model(), ui->comboBoxBus->currentData().toInt()); + + switch (ui->comboBoxBus->currentData().toInt()) + { + case HDD_BUS_MFM: + chanIdx = (Harddrives::busTrackClass->next_free_mfm_channel()); + break; + case HDD_BUS_XTA: + chanIdx = (Harddrives::busTrackClass->next_free_xta_channel()); + break; + case HDD_BUS_ESDI: + chanIdx = (Harddrives::busTrackClass->next_free_esdi_channel()); + break; + case HDD_BUS_ATAPI: + case HDD_BUS_IDE: + chanIdx = (Harddrives::busTrackClass->next_free_ide_channel()); + break; + case HDD_BUS_SCSI: + chanIdx = (Harddrives::busTrackClass->next_free_scsi_id()); + break; + } + + if (chanIdx == 0xFF) chanIdx = 0; + ui->comboBoxChannel->setCurrentIndex(chanIdx); +} + +void HarddiskDialog::on_lineEditSize_textEdited(const QString &text) { + uint32_t size = text.toUInt(); + /* This is needed to ensure VHD standard compliance. */ + hdd_image_calc_chs(&cylinders_, &heads_, §ors_, size); + ui->lineEditCylinders->setText(QString::number(cylinders_)); + ui->lineEditHeads->setText(QString::number(heads_)); + ui->lineEditSectors->setText(QString::number(sectors_)); + recalcSelection(); + + checkAndAdjustCylinders(); + checkAndAdjustHeads(); + checkAndAdjustSectors(); +} + +void HarddiskDialog::on_lineEditCylinders_textEdited(const QString &text) { + cylinders_ = text.toUInt(); + if (checkAndAdjustCylinders()) { + recalcSize(); + recalcSelection(); + } +} + +void HarddiskDialog::on_lineEditHeads_textEdited(const QString &text) { + heads_ = text.toUInt(); + if (checkAndAdjustHeads()) { + recalcSize(); + recalcSelection(); + } +} + +void HarddiskDialog::on_lineEditSectors_textEdited(const QString &text) { + sectors_ = text.toUInt(); + if (checkAndAdjustSectors()) { + recalcSize(); + recalcSelection(); + } +} + +void HarddiskDialog::on_comboBoxType_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + if ((index != 127) && (index != 128)) { + cylinders_ = hdd_table[index][0]; + heads_ = hdd_table[index][1]; + sectors_ = hdd_table[index][2]; + ui->lineEditCylinders->setText(QString::number(cylinders_)); + ui->lineEditHeads->setText(QString::number(heads_)); + ui->lineEditSectors->setText(QString::number(sectors_)); + recalcSize(); + } else if (index == 128) { + heads_ = 16; + sectors_ = 63; + ui->lineEditHeads->setText(QString::number(heads_)); + ui->lineEditSectors->setText(QString::number(sectors_)); + recalcSize(); + } + + checkAndAdjustCylinders(); + checkAndAdjustHeads(); + checkAndAdjustSectors(); +} + +void HarddiskDialog::accept() +{ + if (ui->fileField->createFile()) onCreateNewFile(); + else setResult(QDialog::Accepted); + QDialog::done(result()); +} diff --git a/src/qt/qt_harddiskdialog.hpp b/src/qt/qt_harddiskdialog.hpp new file mode 100644 index 000000000..408726f63 --- /dev/null +++ b/src/qt/qt_harddiskdialog.hpp @@ -0,0 +1,60 @@ +#ifndef QT_HARDDISKDIALOG_HPP +#define QT_HARDDISKDIALOG_HPP + +#include + +namespace Ui { +class HarddiskDialog; +} + +class HarddiskDialog : public QDialog +{ + Q_OBJECT + +public: + explicit HarddiskDialog(bool existing, QWidget *parent = nullptr); + ~HarddiskDialog(); + + uint8_t bus() const; + uint8_t channel() const; + QString fileName() const; + uint32_t cylinders() const { return cylinders_; } + uint32_t heads() const { return heads_; } + uint32_t sectors() const { return sectors_; } + uint32_t speed() const; + +signals: + void fileProgress(int i); + +public slots: + void accept() override; + +private slots: + void on_comboBoxType_currentIndexChanged(int index); + void on_lineEditSectors_textEdited(const QString &arg1); + void on_lineEditHeads_textEdited(const QString &arg1); + void on_lineEditCylinders_textEdited(const QString &arg1); + void on_lineEditSize_textEdited(const QString &arg1); + void on_comboBoxBus_currentIndexChanged(int index); + void on_comboBoxFormat_currentIndexChanged(int index); + void onCreateNewFile(); + void onExistingFileSelected(const QString& fileName); +private: + Ui::HarddiskDialog *ui; + + uint32_t cylinders_; + uint32_t heads_; + uint32_t sectors_; + + uint32_t max_sectors = 0; + uint32_t max_heads = 0; + uint32_t max_cylinders = 0; + + bool checkAndAdjustCylinders(); + bool checkAndAdjustHeads(); + bool checkAndAdjustSectors(); + void recalcSize(); + void recalcSelection(); +}; + +#endif // QT_HARDDISKDIALOG_HPP diff --git a/src/qt/qt_harddiskdialog.ui b/src/qt/qt_harddiskdialog.ui new file mode 100644 index 000000000..84c557660 --- /dev/null +++ b/src/qt/qt_harddiskdialog.ui @@ -0,0 +1,295 @@ + + + HarddiskDialog + + + + 0 + 0 + 421 + 269 + + + + + 0 + 0 + + + + + 421 + 269 + + + + + 421 + 269 + + + + Dialog + + + + + + + + + Channel: + + + + + + + Speed: + + + + + + + + + + Sectors: + + + + + + + Type: + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + + + + + Size (MB): + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + Cylinders: + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + 32767 + + + + + + + Image Format: + + + + + + + Heads: + + + + + + + + + + Bus: + + + + + + + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + 32767 + + + + + + + + + + Block Size: + + + + + + + File name: + + + + + + + false + + + 0 + + + true + + + + + + + + FileField + QWidget +
qt_filefield.hpp
+ 1 +
+
+ + lineEditCylinders + lineEditHeads + lineEditSectors + lineEditSize + comboBoxType + comboBoxBus + comboBoxChannel + comboBoxFormat + comboBoxBlockSize + + + + + buttonBox + accepted() + HarddiskDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + HarddiskDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/qt/qt_harddrive_common.cpp b/src/qt/qt_harddrive_common.cpp new file mode 100644 index 000000000..5ac46dd42 --- /dev/null +++ b/src/qt/qt_harddrive_common.cpp @@ -0,0 +1,138 @@ +/* + * 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. + * + * Common storage devices module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_harddrive_common.hpp" + +#include + +extern "C" { +#include <86box/hdd.h> +} + +#include + +void Harddrives::populateBuses(QAbstractItemModel *model) { + model->removeRows(0, model->rowCount()); + model->insertRows(0, 6); + model->setData(model->index(0, 0), "MFM/RLL"); + model->setData(model->index(1, 0), "XTA"); + model->setData(model->index(2, 0), "ESDI"); + model->setData(model->index(3, 0), "IDE"); + model->setData(model->index(4, 0), "ATAPI"); + model->setData(model->index(5, 0), "SCSI"); + + model->setData(model->index(0, 0), HDD_BUS_MFM, Qt::UserRole); + model->setData(model->index(1, 0), HDD_BUS_XTA, Qt::UserRole); + model->setData(model->index(2, 0), HDD_BUS_ESDI, Qt::UserRole); + model->setData(model->index(3, 0), HDD_BUS_IDE, Qt::UserRole); + model->setData(model->index(4, 0), HDD_BUS_ATAPI, Qt::UserRole); + model->setData(model->index(5, 0), HDD_BUS_SCSI, Qt::UserRole); +} + +void Harddrives::populateRemovableBuses(QAbstractItemModel *model) { + model->removeRows(0, model->rowCount()); + model->insertRows(0, 3); + model->setData(model->index(0, 0), QObject::tr("Disabled")); + model->setData(model->index(1, 0), QObject::tr("ATAPI")); + model->setData(model->index(2, 0), QObject::tr("SCSI")); + + model->setData(model->index(0, 0), HDD_BUS_DISABLED, Qt::UserRole); + model->setData(model->index(1, 0), HDD_BUS_ATAPI, Qt::UserRole); + model->setData(model->index(2, 0), HDD_BUS_SCSI, Qt::UserRole); +} + +void Harddrives::populateSpeeds(QAbstractItemModel *model, int bus) { + int num_preset; + + switch (bus) { + case HDD_BUS_IDE: + num_preset = hdd_preset_get_num(); + break; + + default: + num_preset = 1; + } + + model->removeRows(0, model->rowCount()); + model->insertRows(0, num_preset); + + for (int i = 0; i < num_preset; i++) { + model->setData(model->index(i, 0), QObject::tr(hdd_preset_getname(i))); + model->setData(model->index(i, 0), i, Qt::UserRole); + } +} + +void Harddrives::populateBusChannels(QAbstractItemModel *model, int bus) { + model->removeRows(0, model->rowCount()); + + int busRows = 0; + int shifter = 1; + int orer = 1; + int subChannelWidth = 1; + switch (bus) { + case HDD_BUS_MFM: + case HDD_BUS_XTA: + case HDD_BUS_ESDI: + busRows = 2; + break; + case HDD_BUS_IDE: + case HDD_BUS_ATAPI: + busRows = 8; + break; + case HDD_BUS_SCSI: + shifter = 4; + orer = 15; + busRows = 64; + subChannelWidth = 2; + break; + } + + model->insertRows(0, busRows); + for (int i = 0; i < busRows; ++i) { + auto idx = model->index(i, 0); + model->setData(idx, QString("%1:%2").arg(i >> shifter).arg(i & orer, subChannelWidth, 10, QChar('0'))); + model->setData(idx, ((i >> shifter) << shifter) | (i & orer), Qt::UserRole); + } +} + +QString Harddrives::BusChannelName(uint8_t bus, uint8_t channel) { + QString busName; + switch(bus) { + case HDD_BUS_DISABLED: + busName = QString(QObject::tr("Disabled")); + break; + case HDD_BUS_MFM: + busName = QString("MFM/RLL (%1:%2)").arg(channel >> 1).arg(channel & 1); + break; + case HDD_BUS_XTA: + busName = QString("XTA (%1:%2)").arg(channel >> 1).arg(channel & 1); + break; + case HDD_BUS_ESDI: + busName = QString("ESDI (%1:%2)").arg(channel >> 1).arg(channel & 1); + break; + case HDD_BUS_IDE: + busName = QString("IDE (%1:%2)").arg(channel >> 1).arg(channel & 1); + break; + case HDD_BUS_ATAPI: + busName = QString("ATAPI (%1:%2)").arg(channel >> 1).arg(channel & 1); + break; + case HDD_BUS_SCSI: + busName = QString("SCSI (%1:%2)").arg(channel >> 4).arg(channel & 15, 2, 10, QChar('0')); + break; + } + + return busName; +} diff --git a/src/qt/qt_harddrive_common.hpp b/src/qt/qt_harddrive_common.hpp new file mode 100644 index 000000000..6e133506f --- /dev/null +++ b/src/qt/qt_harddrive_common.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +class QString; +class QAbstractItemModel; +class SettingsBusTracking; + +namespace Harddrives { + void populateBuses(QAbstractItemModel* model); + void populateRemovableBuses(QAbstractItemModel* model); + void populateBusChannels(QAbstractItemModel* model, int bus); + void populateSpeeds(QAbstractItemModel* model, int bus); + QString BusChannelName(uint8_t bus, uint8_t channel); + inline SettingsBusTracking* busTrackClass = nullptr; +}; diff --git a/src/qt/qt_hardwarerenderer.cpp b/src/qt/qt_hardwarerenderer.cpp new file mode 100644 index 000000000..30ca74ecd --- /dev/null +++ b/src/qt/qt_hardwarerenderer.cpp @@ -0,0 +1,224 @@ +/* + * 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. + * + * Hardware renderer module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021-2022 Teemu Korhonen + */ +#include "qt_hardwarerenderer.hpp" +#include +#include +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/video.h> +} + +void HardwareRenderer::resizeGL(int w, int h) +{ + m_context->makeCurrent(this); + glViewport(0, 0, qRound(w * devicePixelRatio()), qRound(h * devicePixelRatio())); +} + +#define PROGRAM_VERTEX_ATTRIBUTE 0 +#define PROGRAM_TEXCOORD_ATTRIBUTE 1 + +void HardwareRenderer::initializeGL() +{ + m_context->makeCurrent(this); + initializeOpenGLFunctions(); + m_texture = new QOpenGLTexture(QImage(2048,2048, QImage::Format::Format_RGB32)); + m_blt = new QOpenGLTextureBlitter; + m_blt->setRedBlueSwizzle(true); + m_blt->create(); + QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); + const char *vsrc = + "attribute highp vec4 VertexCoord;\n" + "attribute mediump vec4 TexCoord;\n" + "varying mediump vec4 texc;\n" + "uniform mediump mat4 MVPMatrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = MVPMatrix * VertexCoord;\n" + " texc = TexCoord;\n" + "}\n"; + QString vsrccore = + "in highp vec4 VertexCoord;\n" + "in mediump vec4 TexCoord;\n" + "out mediump vec4 texc;\n" + "uniform mediump mat4 MVPMatrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = MVPMatrix * VertexCoord;\n" + " texc = TexCoord;\n" + "}\n"; + if (m_context->isOpenGLES() && m_context->format().version() >= qMakePair(3, 0)) + { + vsrccore.prepend("#version 300 es\n"); + vshader->compileSourceCode(vsrccore); + } + else if (m_context->format().version() >= qMakePair(3, 0) && m_context->format().profile() == QSurfaceFormat::CoreProfile) + { + vsrccore.prepend("#version 130\n"); + vshader->compileSourceCode(vsrccore); + } + else vshader->compileSourceCode(vsrc); + + QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); + const char *fsrc = + "uniform sampler2D texture;\n" + "varying mediump vec4 texc;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = texture2D(texture, texc.st).bgra;\n" + "}\n"; + QString fsrccore = + "uniform sampler2D texture;\n" + "in mediump vec4 texc;\n" + "out highp vec4 FragColor;\n" + "void main(void)\n" + "{\n" + " FragColor = texture2D(texture, texc.st).bgra;\n" + "}\n"; + if (m_context->isOpenGLES() && m_context->format().version() >= qMakePair(3, 0)) + { + fsrccore.prepend("#version 300 es\n"); + fshader->compileSourceCode(fsrccore); + } + else if (m_context->format().version() >= qMakePair(3, 0) && m_context->format().profile() == QSurfaceFormat::CoreProfile) + { + fsrccore.prepend("#version 130\n"); + fshader->compileSourceCode(fsrccore); + } + else fshader->compileSourceCode(fsrc); + + m_prog = new QOpenGLShaderProgram; + m_prog->addShader(vshader); + m_prog->addShader(fshader); + m_prog->bindAttributeLocation("VertexCoord", PROGRAM_VERTEX_ATTRIBUTE); + m_prog->bindAttributeLocation("TexCoord", PROGRAM_TEXCOORD_ATTRIBUTE); + m_prog->link(); + + m_prog->bind(); + m_prog->setUniformValue("texture", 0); + + if (m_context->format().version() >= qMakePair(3, 0) && m_vao.create()) { + m_vao.bind(); + } + + m_vbo[PROGRAM_VERTEX_ATTRIBUTE].create(); + m_vbo[PROGRAM_VERTEX_ATTRIBUTE].bind(); + m_vbo[PROGRAM_VERTEX_ATTRIBUTE].allocate(sizeof(QVector2D) * 4); + m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].create(); + m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].bind(); + m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].allocate(sizeof(QVector2D) * 4); + + pclog("OpenGL vendor: %s\n", glGetString(GL_VENDOR)); + pclog("OpenGL renderer: %s\n", glGetString(GL_RENDERER)); + pclog("OpenGL version: %s\n", glGetString(GL_VERSION)); + pclog("OpenGL shader language version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + glClearColor(0, 0, 0, 1); +} + +void HardwareRenderer::paintGL() { + m_context->makeCurrent(this); + glClear(GL_COLOR_BUFFER_BIT); + QVector verts, texcoords; + QMatrix4x4 mat; + mat.setToIdentity(); + mat.ortho(QRectF(0, 0, (qreal)width(), (qreal)height())); + verts.push_back(QVector2D((float)destination.x(), (float)destination.y())); + verts.push_back(QVector2D((float)destination.x(), (float)destination.y() + (float)destination.height())); + verts.push_back(QVector2D((float)destination.x() + (float)destination.width(), (float)destination.y() + (float)destination.height())); + verts.push_back(QVector2D((float)destination.x() + (float)destination.width(), (float)destination.y())); + texcoords.push_back(QVector2D((float)source.x() / 2048.f, (float)(source.y()) / 2048.f)); + texcoords.push_back(QVector2D((float)source.x() / 2048.f, (float)(source.y() + source.height()) / 2048.f)); + texcoords.push_back(QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y() + source.height()) / 2048.f)); + texcoords.push_back(QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y()) / 2048.f)); + + m_vbo[PROGRAM_VERTEX_ATTRIBUTE].bind(); m_vbo[PROGRAM_VERTEX_ATTRIBUTE].write(0, verts.data(), sizeof(QVector2D) * 4); m_vbo[PROGRAM_VERTEX_ATTRIBUTE].release(); + m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].bind(); m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].write(0, texcoords.data(), sizeof(QVector2D) * 4); m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].release(); + + m_prog->setUniformValue("MVPMatrix", mat); + m_prog->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE); + m_prog->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE); + + m_vbo[PROGRAM_VERTEX_ATTRIBUTE].bind(); m_prog->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 2, 0); m_vbo[PROGRAM_VERTEX_ATTRIBUTE].release(); + m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].bind(); m_prog->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 0, 2, 0); m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].release(); + m_texture->bind(); + m_texture->setMinMagFilters(video_filter_method ? QOpenGLTexture::Linear : QOpenGLTexture::Nearest, video_filter_method ? QOpenGLTexture::Linear : QOpenGLTexture::Nearest); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +void HardwareRenderer::setRenderType(RenderType type) { + QSurfaceFormat format; + switch (type) { + case RenderType::OpenGL3: + format.setVersion(3, 0); + format.setProfile(QSurfaceFormat::CoreProfile); + case RenderType::OpenGL: + format.setRenderableType(QSurfaceFormat::OpenGL); + break; + case RenderType::OpenGLES: + format.setRenderableType(QSurfaceFormat::OpenGLES); + break; + } + format.setSwapInterval(0); + setFormat(format); +} + +void HardwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { + auto tval = this; + void* nuldata = 0; + if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return; + if (!m_texture || !m_texture->isCreated()) + { + buf_usage[buf_idx].clear(); + source.setRect(x, y, w, h); + return; + } + m_context->makeCurrent(this); + m_texture->setData(QOpenGLTexture::PixelFormat::RGBA, QOpenGLTexture::PixelType::UInt8, (const void*)imagebufs[buf_idx].get()); + buf_usage[buf_idx].clear(); + source.setRect(x, y, w, h); + update(); +} + +void HardwareRenderer::resizeEvent(QResizeEvent *event) { + onResize(width(), height()); + + QOpenGLWindow::resizeEvent(event); +} + +bool HardwareRenderer::event(QEvent *event) +{ + bool res = false; + if (!eventDelegate(event, res)) return QOpenGLWindow::event(event); + return res; +} + +std::vector> HardwareRenderer::getBuffers() +{ + std::vector> buffers; + + buffers.push_back(std::make_tuple(imagebufs[0].get(), &buf_usage[0])); + buffers.push_back(std::make_tuple(imagebufs[1].get(), &buf_usage[1])); + + return buffers; +} diff --git a/src/qt/qt_hardwarerenderer.hpp b/src/qt/qt_hardwarerenderer.hpp new file mode 100644 index 000000000..af4f05464 --- /dev/null +++ b/src/qt/qt_hardwarerenderer.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "qt_renderercommon.hpp" + +#ifdef WAYLAND +#include "wl_mouse.hpp" +#endif + +class HardwareRenderer : public QOpenGLWindow, protected QOpenGLFunctions, public RendererCommon +{ + Q_OBJECT + +private: + bool wayland = false; + QOpenGLContext* m_context; + QOpenGLTexture* m_texture{nullptr}; + QOpenGLShaderProgram* m_prog{nullptr}; + QOpenGLTextureBlitter* m_blt{nullptr}; + QOpenGLBuffer m_vbo[2]; + QOpenGLVertexArrayObject m_vao; +public: + enum class RenderType { + OpenGL, + OpenGLES, + OpenGL3, + }; + void resizeGL(int w, int h) override; + void initializeGL() override; + void paintGL() override; + std::vector> getBuffers() override; + HardwareRenderer(QWidget* parent = nullptr, RenderType rtype = RenderType::OpenGL) + : QOpenGLWindow(QOpenGLWindow::NoPartialUpdate, parent->windowHandle()), QOpenGLFunctions() + { + imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + imagebufs[1] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); + + setMinimumSize(QSize(16, 16)); + setFlags(Qt::FramelessWindowHint); + parentWidget = parent; + setRenderType(rtype); + + m_context = new QOpenGLContext(); + m_context->setFormat(format()); + m_context->create(); + } + ~HardwareRenderer() + { + m_context->makeCurrent(this); + if (m_blt) m_blt->destroy(); + m_prog->release(); + delete m_prog; + m_prog = nullptr; + m_context->doneCurrent(); + delete m_context; + } + + + void setRenderType(RenderType type); + +public slots: + void onBlit(int buf_idx, int x, int y, int w, int h); + +protected: + std::array, 2> imagebufs; + + void resizeEvent(QResizeEvent *event) override; + bool event(QEvent* event) override; +}; diff --git a/src/qt/qt_joystickconfiguration.cpp b/src/qt/qt_joystickconfiguration.cpp new file mode 100644 index 000000000..54aec5c6d --- /dev/null +++ b/src/qt/qt_joystickconfiguration.cpp @@ -0,0 +1,202 @@ +/* + * 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. + * + * Joystick configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_joystickconfiguration.hpp" +#include "ui_qt_joystickconfiguration.h" + +extern "C" { +#include <86box/device.h> +#include <86box/gameport.h> +} + + +#include +#include +#include +#include "qt_models_common.hpp" + +JoystickConfiguration::JoystickConfiguration(int type, int joystick_nr, QWidget *parent) : + QDialog(parent), + ui(new Ui::JoystickConfiguration), + type(type), + joystick_nr(joystick_nr) +{ + ui->setupUi(this); + + auto model = ui->comboBoxDevice->model(); + Models::AddEntry(model, "None", 0); + for (int c = 0; c < joysticks_present; c++) { + Models::AddEntry(model, plat_joystick_state[c].name, c+1); + } + + ui->comboBoxDevice->setCurrentIndex(joystick_state[joystick_nr].plat_joystick_nr); + layout()->setSizeConstraint(QLayout::SetFixedSize); +} + +JoystickConfiguration::~JoystickConfiguration() +{ + delete ui; +} + +int JoystickConfiguration::selectedDevice() { + return ui->comboBoxDevice->currentIndex(); +} + +int JoystickConfiguration::selectedAxis(int axis) { + auto* cbox = findChild(QString("cboxAxis%1").arg(QString::number(axis))); + if (cbox == nullptr) { + return 0; + } + return cbox->currentIndex(); +} + +int JoystickConfiguration::selectedButton(int button) { + auto* cbox = findChild(QString("cboxButton%1").arg(QString::number(button))); + if (cbox == nullptr) { + return 0; + } + return cbox->currentIndex(); +} + +int JoystickConfiguration::selectedPov(int pov) { + auto* cbox = findChild(QString("cboxPov%1").arg(QString::number(pov))); + if (cbox == nullptr) { + return 0; + } + return cbox->currentIndex(); +} + +void JoystickConfiguration::on_comboBoxDevice_currentIndexChanged(int index) { + for (auto w : widgets) { + ui->ct->removeWidget(w); + w->deleteLater(); + } + widgets.clear(); + + if (index == 0) { + return; + } + + int joystick = index - 1; + int row = 0; + for (int c = 0; c < joystick_get_axis_count(type); c++) { + /*Combo box*/ + auto label = new QLabel(joystick_get_axis_name(type, c), this); + auto cbox = new QComboBox(this); + cbox->setObjectName(QString("cboxAxis%1").arg(QString::number(c))); + auto model = cbox->model(); + + for (int d = 0; d < plat_joystick_state[joystick].nr_axes; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].axis[d].name, 0); + } + + for (int d = 0; d < plat_joystick_state[joystick].nr_povs; d++) { + Models::AddEntry(model, QString("%1 (X axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + Models::AddEntry(model, QString("%1 (Y axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + } + + for (int d = 0; d < plat_joystick_state[joystick].nr_sliders; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].slider[d].name, 0); + } + + int nr_axes = plat_joystick_state[joystick].nr_axes; + int nr_povs = plat_joystick_state[joystick].nr_povs; + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + if (mapping & POV_X) + cbox->setCurrentIndex(nr_axes + (mapping & 3) * 2); + else if (mapping & POV_Y) + cbox->setCurrentIndex(nr_axes + (mapping & 3) * 2 + 1); + else if (mapping & SLIDER) + cbox->setCurrentIndex(nr_axes + nr_povs * 2 + (mapping & 3)); + else + cbox->setCurrentIndex(mapping); + + ui->ct->addWidget(label, row, 0); + ui->ct->addWidget(cbox, row, 1); + + widgets.append(label); + widgets.append(cbox); + + ++row; + } + + for (int c = 0; c < joystick_get_button_count(type); c++) { + auto label = new QLabel(joystick_get_button_name(type, c), this); + auto cbox = new QComboBox(this); + cbox->setObjectName(QString("cboxButton%1").arg(QString::number(c))); + auto model = cbox->model(); + + for (int d = 0; d < plat_joystick_state[joystick].nr_buttons; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].button[d].name, 0); + } + + cbox->setCurrentIndex(joystick_state[joystick_nr].button_mapping[c]); + + ui->ct->addWidget(label, row, 0); + ui->ct->addWidget(cbox, row, 1); + + widgets.append(label); + widgets.append(cbox); + + ++row; + } + + for (int c = 0; c < joystick_get_pov_count(type) * 2; c++) { + QLabel* label; + if (c & 1) { + label = new QLabel(QString("%1 (Y axis)").arg(joystick_get_pov_name(type, c/2)), this); + } else { + label = new QLabel(QString("%1 (X axis)").arg(joystick_get_pov_name(type, c/2)), this); + } + auto cbox = new QComboBox(this); + cbox->setObjectName(QString("cboxPov%1").arg(QString::number(c))); + auto model = cbox->model(); + + for (int d = 0; d < plat_joystick_state[joystick].nr_povs; d++) { + Models::AddEntry(model, QString("%1 (X axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + Models::AddEntry(model, QString("%1 (Y axis)").arg(plat_joystick_state[joystick].pov[d].name), 0); + } + + for (int d = 0; d < plat_joystick_state[joystick].nr_axes; d++) { + Models::AddEntry(model, plat_joystick_state[joystick].axis[d].name, 0); + } + + int mapping = joystick_state[joystick_nr].pov_mapping[c][0]; + int nr_povs = plat_joystick_state[joystick].nr_povs; + if (mapping & POV_X) + cbox->setCurrentIndex((mapping & 3) * 2); + else if (mapping & POV_Y) + cbox->setCurrentIndex((mapping & 3)*2 + 1); + else + cbox->setCurrentIndex(mapping + nr_povs * 2); + + mapping = joystick_state[joystick_nr].pov_mapping[c][1]; + if (mapping & POV_X) + cbox->setCurrentIndex((mapping & 3)*2); + else if (mapping & POV_Y) + cbox->setCurrentIndex((mapping & 3)*2 + 1); + else + cbox->setCurrentIndex(mapping + nr_povs*2); + + ui->ct->addWidget(label, row, 0); + ui->ct->addWidget(cbox, row, 1); + + widgets.append(label); + widgets.append(cbox); + + ++row; + } +} diff --git a/src/qt/qt_joystickconfiguration.hpp b/src/qt/qt_joystickconfiguration.hpp new file mode 100644 index 000000000..b6882c52b --- /dev/null +++ b/src/qt/qt_joystickconfiguration.hpp @@ -0,0 +1,32 @@ +#ifndef QT_JOYSTICKCONFIGURATION_HPP +#define QT_JOYSTICKCONFIGURATION_HPP + +#include + +namespace Ui { +class JoystickConfiguration; +} + +class JoystickConfiguration : public QDialog +{ + Q_OBJECT + +public: + explicit JoystickConfiguration(int type, int joystick_nr, QWidget *parent = nullptr); + ~JoystickConfiguration(); + + int selectedDevice(); + int selectedAxis(int axis); + int selectedButton(int button); + int selectedPov(int pov); +private slots: + void on_comboBoxDevice_currentIndexChanged(int index); + +private: + Ui::JoystickConfiguration *ui; + QList widgets; + int type; + int joystick_nr; +}; + +#endif // QT_JOYSTICKCONFIGURATION_HPP diff --git a/src/qt/qt_joystickconfiguration.ui b/src/qt/qt_joystickconfiguration.ui new file mode 100644 index 000000000..7789b48c4 --- /dev/null +++ b/src/qt/qt_joystickconfiguration.ui @@ -0,0 +1,87 @@ + + + JoystickConfiguration + + + + 0 + 0 + 400 + 300 + + + + Joystick configuration + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + Device + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + buttonBox + accepted() + JoystickConfiguration + accept() + + + 223 + 278 + + + 199 + 149 + + + + + buttonBox + rejected() + JoystickConfiguration + reject() + + + 223 + 278 + + + 199 + 149 + + + + + diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp new file mode 100644 index 000000000..773566319 --- /dev/null +++ b/src/qt/qt_machinestatus.cpp @@ -0,0 +1,604 @@ +/* + * 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. + * + * Joystick configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + */ +#include "qt_machinestatus.hpp" + +extern "C" { +#define EMU_CPU_H // superhack - don't want timer.h to include cpu.h here, and some combo is preventing a compile +extern uint64_t tsc; + +#include <86box/hdd.h> +#include <86box/timer.h> +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/cartridge.h> +#include <86box/cassette.h> +#include <86box/cdrom.h> +#include <86box/fdd.h> +#include <86box/hdc.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/plat.h> +#include <86box/machine.h> +#include <86box/network.h> +#include <86box/ui.h> +#include <86box/machine_status.h> +}; + +#include +#include +#include +#include +#include +#include +#include + +#include "qt_mediamenu.hpp" +#include "qt_mainwindow.hpp" +#include "qt_soundgain.hpp" +#include "qt_progsettings.hpp" + +#include + +extern MainWindow* main_window; + +namespace { + struct PixmapSetActive { + QPixmap normal; + QPixmap active; + void load(const QString& basePath); + }; + struct PixmapSetEmpty { + QPixmap normal; + QPixmap empty; + void load(const QString& basePath); + }; + struct PixmapSetEmptyActive { + QPixmap normal; + QPixmap active; + QPixmap empty; + QPixmap empty_active; + void load(QString basePath); + }; + struct Pixmaps { + PixmapSetEmpty cartridge; + PixmapSetEmptyActive cassette; + PixmapSetEmptyActive floppy_disabled; + PixmapSetEmptyActive floppy_525; + PixmapSetEmptyActive floppy_35; + PixmapSetEmptyActive cdrom; + PixmapSetEmptyActive zip; + PixmapSetEmptyActive mo; + PixmapSetActive hd; + PixmapSetActive net; + QPixmap sound; + }; + + struct StateActive { + std::unique_ptr label; + PixmapSetActive* pixmaps = nullptr; + bool active = false; + + void setActive(bool b) { + if (!label || b == active) + return; + active = b; + + refresh(); + } + + void refresh() { + if (!label) + return; + label->setPixmap(active ? pixmaps->active : pixmaps->normal); + } + }; + struct StateEmpty { + std::unique_ptr label; + PixmapSetEmpty* pixmaps = nullptr; + bool empty = false; + + void setEmpty(bool e) { + if (!label || e == empty) + return; + empty = e; + + refresh(); + } + + void refresh() { + if (!label) + return; + label->setPixmap(empty ? pixmaps->empty : pixmaps->normal); + } + }; + struct StateEmptyActive { + std::unique_ptr label; + PixmapSetEmptyActive* pixmaps = nullptr; + bool empty = false; + bool active = false; + + void setActive(bool b) { + if (!label || b == active) + return; + + active = b; + refresh(); + } + void setEmpty(bool b) { + if (!label || b == empty) + return; + + empty = b; + refresh(); + } + void refresh() { + if (!label) + return; + if (empty) { + label->setPixmap(active ? pixmaps->empty_active : pixmaps->empty); + } else { + label->setPixmap(active ? pixmaps->active : pixmaps->normal); + } + } + }; + + static QSize pixmap_size(16, 16); + static const QString pixmap_empty = QStringLiteral("_empty"); + static const QString pixmap_active = QStringLiteral("_active"); + static const QString pixmap_empty_active = QStringLiteral("_empty_active"); + void PixmapSetEmpty::load(const QString &basePath) { + normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); + empty = ProgSettings::loadIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); + } + + void PixmapSetActive::load(const QString &basePath) { + normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); + active = ProgSettings::loadIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); + } + + void PixmapSetEmptyActive::load(QString basePath) { + normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); + active = ProgSettings::loadIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); + empty = ProgSettings::loadIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); + empty_active = ProgSettings::loadIcon(basePath.arg(pixmap_empty_active)).pixmap(pixmap_size); + } +} + +struct MachineStatus::States { + Pixmaps pixmaps; + + States(QObject* parent) { + pixmaps.cartridge.load("/cartridge%1.ico"); + pixmaps.cassette.load("/cassette%1.ico"); + pixmaps.floppy_disabled.normal = ProgSettings::loadIcon(QStringLiteral("/floppy_disabled.ico")).pixmap(pixmap_size); + pixmaps.floppy_disabled.active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.empty = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.empty_active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_525.load("/floppy_525%1.ico"); + pixmaps.floppy_35.load("/floppy_35%1.ico"); + pixmaps.cdrom.load("/cdrom%1.ico"); + pixmaps.zip.load("/zip%1.ico"); + pixmaps.mo.load("/mo%1.ico"); + pixmaps.hd.load("/hard_disk%1.ico"); + pixmaps.net.load("/network%1.ico"); + pixmaps.sound = ProgSettings::loadIcon("/sound.ico").pixmap(pixmap_size); + + cartridge[0].pixmaps = &pixmaps.cartridge; + cartridge[1].pixmaps = &pixmaps.cartridge; + cassette.pixmaps = &pixmaps.cassette; + for (auto& f : fdd) { + f.pixmaps = &pixmaps.floppy_disabled; + } + for (auto& c : cdrom) { + c.pixmaps = &pixmaps.cdrom; + } + for (auto& z : zip) { + z.pixmaps = &pixmaps.zip; + } + for (auto& m : mo) { + m.pixmaps = &pixmaps.mo; + } + for (auto& h : hdds) { + h.pixmaps = &pixmaps.hd; + } + net.pixmaps = &pixmaps.net; + } + + std::array cartridge; + StateEmptyActive cassette; + std::array fdd; + std::array cdrom; + std::array zip; + std::array mo; + std::array hdds; + StateActive net; + std::unique_ptr sound; + std::unique_ptr text; +}; + +MachineStatus::MachineStatus(QObject *parent) : + QObject(parent), + refreshTimer(new QTimer(this)) +{ + d = std::make_unique(this); + connect(refreshTimer, &QTimer::timeout, this, &MachineStatus::refreshIcons); + refreshTimer->start(75); +} + +MachineStatus::~MachineStatus() = default; + +bool MachineStatus::hasCassette() { + return cassette_enable > 0 ? true : false; +} + +bool MachineStatus::hasIDE() { + return machine_has_flags(machine, MACHINE_IDE_QUAD) > 0; +} + +bool MachineStatus::hasSCSI() { + return machine_has_flags(machine, MACHINE_SCSI_DUAL) > 0; +} + +void MachineStatus::iterateFDD(const std::function &cb) { + for (int i = 0; i < FDD_NUM; ++i) { + if (fdd_get_type(i) != 0) { + cb(i); + } + } +} + +void MachineStatus::iterateCDROM(const std::function &cb) { + auto hdc_name = QString(hdc_get_internal_name(hdc_current)); + for (size_t i = 0; i < CDROM_NUM; i++) { + /* Could be Internal or External IDE.. */ + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && + !hasIDE() && hdc_name.left(3) != QStringLiteral("ide") && + hdc_name.left(5) != QStringLiteral("xtide")) + continue; + if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && !hasSCSI() && + (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && + (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) + continue; + if (cdrom[i].bus_type != 0) { + cb(i); + } + } +} + +void MachineStatus::iterateZIP(const std::function &cb) { + auto hdc_name = QString(hdc_get_internal_name(hdc_current)); + for (size_t i = 0; i < ZIP_NUM; i++) { + /* Could be Internal or External IDE.. */ + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && + !hasIDE() && hdc_name.left(3) != QStringLiteral("ide") && + hdc_name.left(5) != QStringLiteral("xtide")) + continue; + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && !hasSCSI() && + (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && + (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) + continue; + if (zip_drives[i].bus_type != 0) { + cb(i); + } + } +} + +void MachineStatus::iterateMO(const std::function &cb) { + auto hdc_name = QString(hdc_get_internal_name(hdc_current)); + for (size_t i = 0; i < MO_NUM; i++) { + /* Could be Internal or External IDE.. */ + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && + !hasIDE() && hdc_name.left(3) != QStringLiteral("ide") && + hdc_name.left(5) != QStringLiteral("xtide")) + continue; + if ((mo_drives[i].bus_type == MO_BUS_SCSI) && !hasSCSI() && + (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && + (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) + continue; + if (mo_drives[i].bus_type != 0) { + cb(i); + } + } +} + +static int hdd_count(int bus) { + int c = 0; + int i; + + for (i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus == bus) { + c++; + } + } + + return(c); +} + +void MachineStatus::refreshIcons() { + for (size_t i = 0; i < FDD_NUM; ++i) { + d->fdd[i].setActive(machine_status.fdd[i].active); + d->fdd[i].setEmpty(machine_status.fdd[i].empty); + } + for (size_t i = 0; i < CDROM_NUM; ++i) { + d->cdrom[i].setActive(machine_status.cdrom[i].active); + d->cdrom[i].setEmpty(machine_status.cdrom[i].empty); + } + for (size_t i = 0; i < ZIP_NUM; i++) { + d->zip[i].setActive(machine_status.zip[i].active); + d->zip[i].setEmpty(machine_status.zip[i].empty); + } + for (size_t i = 0; i < MO_NUM; i++) { + d->mo[i].setActive(machine_status.mo[i].active); + d->mo[i].setEmpty(machine_status.mo[i].empty); + } + + d->cassette.setEmpty(machine_status.cassette.empty); + + for (size_t i = 0; i < HDD_BUS_USB; i++) { + d->hdds[i].setActive(machine_status.hdd[i].active); + } + + d->net.setActive(machine_status.net.active); + + for (int i = 0; i < 2; ++i) { + d->cartridge[i].setEmpty(machine_status.cartridge[i].empty); + } + +} + +void MachineStatus::refresh(QStatusBar* sbar) { + bool has_mfm = machine_has_flags(machine, MACHINE_MFM) > 0; + bool has_xta = machine_has_flags(machine, MACHINE_XTA) > 0; + bool has_esdi = machine_has_flags(machine, MACHINE_ESDI) > 0; + + int c_mfm = hdd_count(HDD_BUS_MFM); + int c_esdi = hdd_count(HDD_BUS_ESDI); + int c_xta = hdd_count(HDD_BUS_XTA); + int c_ide = hdd_count(HDD_BUS_IDE); + int c_scsi = hdd_count(HDD_BUS_SCSI); + int do_net = network_available(); + + sbar->removeWidget(d->cassette.label.get()); + for (int i = 0; i < 2; ++i) { + sbar->removeWidget(d->cartridge[i].label.get()); + } + for (size_t i = 0; i < FDD_NUM; ++i) { + sbar->removeWidget(d->fdd[i].label.get()); + } + for (size_t i = 0; i < CDROM_NUM; i++) { + sbar->removeWidget(d->cdrom[i].label.get()); + } + for (size_t i = 0; i < ZIP_NUM; i++) { + sbar->removeWidget(d->zip[i].label.get()); + } + for (size_t i = 0; i < MO_NUM; i++) { + sbar->removeWidget(d->mo[i].label.get()); + } + for (size_t i = 0; i < HDD_BUS_USB; i++) { + sbar->removeWidget(d->hdds[i].label.get()); + } + sbar->removeWidget(d->net.label.get()); + sbar->removeWidget(d->sound.get()); + + if (cassette_enable) { + d->cassette.label = std::make_unique(); + d->cassette.setEmpty(QString(cassette_fname).isEmpty()); + d->cassette.refresh(); + connect((ClickableLabel*)d->cassette.label.get(), &ClickableLabel::clicked, [](QPoint pos) { + MediaMenu::ptr->cassetteMenu->popup(pos - QPoint(0, MediaMenu::ptr->cassetteMenu->sizeHint().height())); + }); + connect((ClickableLabel*)d->cassette.label.get(), &ClickableLabel::dropped, [](QString str) { + MediaMenu::ptr->cassetteMount(str, false); + }); + d->cassette.label->setToolTip(MediaMenu::ptr->cassetteMenu->title()); + d->cassette.label->setAcceptDrops(true); + sbar->addWidget(d->cassette.label.get()); + } + + if (machine_has_cartridge(machine)) { + for (int i = 0; i < 2; ++i) { + d->cartridge[i].label = std::make_unique(); + d->cartridge[i].setEmpty(QString(cart_fns[i]).isEmpty()); + d->cartridge[i].refresh(); + connect((ClickableLabel*)d->cartridge[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { + MediaMenu::ptr->cartridgeMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->cartridgeMenus[i]->sizeHint().height())); + }); + connect((ClickableLabel*)d->cartridge[i].label.get(), &ClickableLabel::dropped, [i](QString str) { + MediaMenu::ptr->cartridgeMount(i, str); + }); + d->cartridge[i].label->setToolTip(MediaMenu::ptr->cartridgeMenus[i]->title()); + d->cartridge[i].label->setAcceptDrops(true); + sbar->addWidget(d->cartridge[i].label.get()); + } + } + + iterateFDD([this, sbar](int i) { + int t = fdd_get_type(i); + if (t == 0) { + d->fdd[i].pixmaps = &d->pixmaps.floppy_disabled; + } else if (t >= 1 && t <= 6) { + d->fdd[i].pixmaps = &d->pixmaps.floppy_525; + } else { + d->fdd[i].pixmaps = &d->pixmaps.floppy_35; + } + d->fdd[i].label = std::make_unique(); + d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty()); + d->fdd[i].setActive(false); + d->fdd[i].refresh(); + connect((ClickableLabel*)d->fdd[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { + MediaMenu::ptr->floppyMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->floppyMenus[i]->sizeHint().height())); + }); + connect((ClickableLabel*)d->fdd[i].label.get(), &ClickableLabel::dropped, [i](QString str) { + MediaMenu::ptr->floppyMount(i, str, false); + }); + d->fdd[i].label->setToolTip(MediaMenu::ptr->floppyMenus[i]->title()); + d->fdd[i].label->setAcceptDrops(true); + sbar->addWidget(d->fdd[i].label.get()); + }); + + iterateCDROM([this, sbar](int i) { + d->cdrom[i].label = std::make_unique(); + d->cdrom[i].setEmpty(cdrom[i].host_drive != 200 || QString(cdrom[i].image_path).isEmpty()); + d->cdrom[i].setActive(false); + d->cdrom[i].refresh(); + connect((ClickableLabel*)d->cdrom[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { + MediaMenu::ptr->cdromMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->cdromMenus[i]->sizeHint().height())); + }); + connect((ClickableLabel*)d->cdrom[i].label.get(), &ClickableLabel::dropped, [i](QString str) { + MediaMenu::ptr->cdromMount(i, str); + }); + d->cdrom[i].label->setToolTip(MediaMenu::ptr->cdromMenus[i]->title()); + d->cdrom[i].label->setAcceptDrops(true); + sbar->addWidget(d->cdrom[i].label.get()); + }); + + iterateZIP([this, sbar](int i) { + d->zip[i].label = std::make_unique(); + d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty()); + d->zip[i].setActive(false); + d->zip[i].refresh(); + connect((ClickableLabel*)d->zip[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { + MediaMenu::ptr->zipMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->zipMenus[i]->sizeHint().height())); + }); + connect((ClickableLabel*)d->zip[i].label.get(), &ClickableLabel::dropped, [i](QString str) { + MediaMenu::ptr->zipMount(i, str, false); + }); + d->zip[i].label->setToolTip(MediaMenu::ptr->zipMenus[i]->title()); + d->zip[i].label->setAcceptDrops(true); + sbar->addWidget(d->zip[i].label.get()); + }); + + iterateMO([this, sbar](int i) { + d->mo[i].label = std::make_unique(); + d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty()); + d->mo[i].setActive(false); + d->mo[i].refresh(); + connect((ClickableLabel*)d->mo[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { + MediaMenu::ptr->moMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->moMenus[i]->sizeHint().height())); + }); + connect((ClickableLabel*)d->mo[i].label.get(), &ClickableLabel::dropped, [i](QString str) { + MediaMenu::ptr->moMount(i, str, false); + }); + d->mo[i].label->setToolTip(MediaMenu::ptr->moMenus[i]->title()); + d->mo[i].label->setAcceptDrops(true); + sbar->addWidget(d->mo[i].label.get()); + }); + + auto hdc_name = QString(hdc_get_internal_name(hdc_current)); + if ((has_mfm || hdc_name.left(5) == QStringLiteral("st506")) && c_mfm > 0) { + d->hdds[HDD_BUS_MFM].label = std::make_unique(); + d->hdds[HDD_BUS_MFM].setActive(false); + d->hdds[HDD_BUS_MFM].refresh(); + d->hdds[HDD_BUS_MFM].label->setToolTip(tr("Hard disk (%s)").replace("%s", "MFM/RLL")); + sbar->addWidget(d->hdds[HDD_BUS_MFM].label.get()); + } + if ((has_esdi || hdc_name.left(4) == QStringLiteral("esdi")) && c_esdi > 0) { + d->hdds[HDD_BUS_ESDI].label = std::make_unique(); + d->hdds[HDD_BUS_ESDI].setActive(false); + d->hdds[HDD_BUS_ESDI].refresh(); + d->hdds[HDD_BUS_ESDI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "ESDI")); + sbar->addWidget(d->hdds[HDD_BUS_ESDI].label.get()); + } + if ((has_xta || hdc_name.left(3) == QStringLiteral("xta")) && c_xta > 0) { + d->hdds[HDD_BUS_XTA].label = std::make_unique(); + d->hdds[HDD_BUS_XTA].setActive(false); + d->hdds[HDD_BUS_XTA].refresh(); + d->hdds[HDD_BUS_XTA].label->setToolTip(tr("Hard disk (%s)").replace("%s", "XTA")); + sbar->addWidget(d->hdds[HDD_BUS_XTA].label.get()); + } + if ((hasIDE() || hdc_name.left(5) == QStringLiteral("xtide") || hdc_name.left(3) == QStringLiteral("ide")) && c_ide > 0) { + d->hdds[HDD_BUS_IDE].label = std::make_unique(); + d->hdds[HDD_BUS_IDE].setActive(false); + d->hdds[HDD_BUS_IDE].refresh(); + d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%s)").replace("%s", "IDE")); + sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get()); + } + if ((hasSCSI() || (scsi_card_current[0] != 0) || (scsi_card_current[1] != 0) || + (scsi_card_current[2] != 0) || (scsi_card_current[3] != 0)) && c_scsi > 0) { + d->hdds[HDD_BUS_SCSI].label = std::make_unique(); + d->hdds[HDD_BUS_SCSI].setActive(false); + d->hdds[HDD_BUS_SCSI].refresh(); + d->hdds[HDD_BUS_SCSI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "SCSI")); + sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get()); + } + + if (do_net) { + d->net.label = std::make_unique(); + d->net.setActive(false); + d->net.refresh(); + d->net.label->setToolTip(tr("Network")); + sbar->addWidget(d->net.label.get()); + } + d->sound = std::make_unique(); + d->sound->setPixmap(d->pixmaps.sound); + + connect(d->sound.get(), &ClickableLabel::doubleClicked, d->sound.get(), [](QPoint pos) { + SoundGain gain(main_window); + gain.exec(); + }); + d->sound->setToolTip(tr("Sound")); + sbar->addWidget(d->sound.get()); + d->text = std::make_unique(); + sbar->addWidget(d->text.get()); +} + +void MachineStatus::message(const QString &msg) { + d->text->setText(msg); +} + +QString MachineStatus::getMessage() { + return d->text->text(); +} + +void MachineStatus::updateTip(int tag) +{ + int category = tag & 0xfffffff0; + int item = tag & 0xf; + if (!MediaMenu::ptr) return; + switch (category) { + case SB_CASSETTE: + if (d->cassette.label && MediaMenu::ptr->cassetteMenu) d->cassette.label->setToolTip(MediaMenu::ptr->cassetteMenu->title()); + break; + case SB_CARTRIDGE: + if (d->cartridge[item].label && MediaMenu::ptr->cartridgeMenus[item]) d->cartridge[item].label->setToolTip(MediaMenu::ptr->cartridgeMenus[item]->title()); + break; + case SB_FLOPPY: + if (d->fdd[item].label && MediaMenu::ptr->floppyMenus[item]) d->fdd[item].label->setToolTip(MediaMenu::ptr->floppyMenus[item]->title()); + break; + case SB_CDROM: + if (d->cdrom[item].label && MediaMenu::ptr->cdromMenus[item]) d->cdrom[item].label->setToolTip(MediaMenu::ptr->cdromMenus[item]->title()); + break; + case SB_ZIP: + if (d->zip[item].label && MediaMenu::ptr->zipMenus[item]) d->zip[item].label->setToolTip(MediaMenu::ptr->zipMenus[item]->title()); + break; + case SB_MO: + if (d->mo[item].label && MediaMenu::ptr->moMenus[item]) d->mo[item].label->setToolTip(MediaMenu::ptr->moMenus[item]->title()); + break; + case SB_HDD: + break; + case SB_NETWORK: + break; + case SB_SOUND: + break; + case SB_TEXT: + break; + } +} diff --git a/src/qt/qt_machinestatus.hpp b/src/qt/qt_machinestatus.hpp new file mode 100644 index 000000000..8c31dd238 --- /dev/null +++ b/src/qt/qt_machinestatus.hpp @@ -0,0 +1,83 @@ +#ifndef QT_MACHINESTATUS_HPP +#define QT_MACHINESTATUS_HPP + +#include +#include +#include +#include + +#include + +class QStatusBar; + +class ClickableLabel : public QLabel { + Q_OBJECT; + public: + explicit ClickableLabel(QWidget* parent = nullptr) + : QLabel(parent) {} + ~ClickableLabel() {}; + + signals: + void clicked(QPoint); + void doubleClicked(QPoint); + void dropped(QString); + + protected: + void mousePressEvent(QMouseEvent* event) override { emit clicked(event->globalPos()); } + void mouseDoubleClickEvent(QMouseEvent* event) override { emit doubleClicked(event->globalPos()); } + void dragEnterEvent(QDragEnterEvent* event) override + { + if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) { + event->setDropAction(Qt::CopyAction); + event->acceptProposedAction(); + } + else event->ignore(); + } + void dragMoveEvent(QDragMoveEvent* event) override + { + if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) { + event->setDropAction(Qt::CopyAction); + event->acceptProposedAction(); + } + else event->ignore(); + } + void dropEvent(QDropEvent* event) override + { + if (event->dropAction() == Qt::CopyAction) + { + emit dropped(event->mimeData()->urls()[0].toLocalFile()); + } + else event->ignore(); + } +}; + +class MachineStatus : public QObject +{ + Q_OBJECT + +public: + explicit MachineStatus(QObject *parent = nullptr); + ~MachineStatus(); + + static bool hasCassette(); + static bool hasIDE(); + static bool hasSCSI(); + static void iterateFDD(const std::function& cb); + static void iterateCDROM(const std::function& cb); + static void iterateZIP(const std::function& cb); + static void iterateMO(const std::function& cb); + + QString getMessage(); +public slots: + void refresh(QStatusBar* sbar); + void message(const QString& msg); + void updateTip(int tag); + void refreshIcons(); + +private: + struct States; + std::unique_ptr d; + QTimer *refreshTimer; +}; + +#endif // QT_MACHINESTATUS_HPP diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp new file mode 100644 index 000000000..c30304eb8 --- /dev/null +++ b/src/qt/qt_main.cpp @@ -0,0 +1,295 @@ +/* + * 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. + * + * Main entry point module + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021-2022 Teemu Korhonen + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef QT_STATIC +/* Static builds need plugin imports */ +#include +Q_IMPORT_PLUGIN(QICOPlugin) +#ifdef Q_OS_WINDOWS +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) +Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin) +#endif +#endif + +#ifdef Q_OS_WINDOWS +#include "qt_winrawinputfilter.hpp" +#include "qt_winmanagerfilter.hpp" +#include <86box/win.h> +#include +#endif + +extern "C" +{ +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/video.h> +#include <86box/discord.h> +#include <86box/gdbstub.h> +} + +#include +#include +#include + +#include "qt_mainwindow.hpp" +#include "qt_progsettings.hpp" +#include "qt_settings.hpp" +#include "cocoa_mouse.hpp" +#include "qt_styleoverride.hpp" +#include "qt_unixmanagerfilter.hpp" + +// Void Cast +#define VC(x) const_cast(x) + +extern QElapsedTimer elapsed_timer; +extern MainWindow* main_window; + +extern "C" { +#include <86box/timer.h> +#include <86box/nvr.h> + extern int qt_nvr_save(void); +} + +void qt_set_sequence_auto_mnemonic(bool b); + +void +main_thread_fn() +{ + uint64_t old_time, new_time; + int drawits, frames; + + QThread::currentThread()->setPriority(QThread::HighestPriority); + framecountx = 0; + //title_update = 1; + old_time = elapsed_timer.elapsed(); + drawits = frames = 0; + while (!is_quit && cpu_thread_run) { + /* See if it is time to run a frame of code. */ + new_time = elapsed_timer.elapsed(); +#ifdef USE_GDBSTUB + if (gdbstub_next_asap && (drawits <= 0)) + drawits = 10; + else +#endif + drawits += (new_time - old_time); + old_time = new_time; + if (drawits > 0 && !dopause) { + /* Yes, so do one frame now. */ + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + pc_run(); + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + qt_nvr_save(); + nvr_dosave = 0; + frames = 0; + } + } else { + /* Just so we dont overload the host OS. */ + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + is_quit = 1; + QTimer::singleShot(0, QApplication::instance(), [] () { QApplication::instance()->quit(); }); +} + +static std::thread* main_thread; + +int main(int argc, char* argv[]) { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, false); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif + QApplication app(argc, argv); + QLocale::setDefault(QLocale::C); + + qt_set_sequence_auto_mnemonic(false); + Q_INIT_RESOURCE(qt_resources); + Q_INIT_RESOURCE(qt_translations); + QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); + fmt.setSwapInterval(0); + QSurfaceFormat::setDefaultFormat(fmt); + app.setStyle(new StyleOverride()); + +#ifdef __APPLE__ + CocoaEventFilter cocoafilter; + app.installNativeEventFilter(&cocoafilter); +#endif + elapsed_timer.start(); + + if (!pc_init(argc, argv)) + { + return 0; + } + + fprintf(stderr, "Qt: version %s, platform \"%s\"\n", qVersion(), QApplication::platformName().toUtf8().data()); + ProgSettings::loadTranslators(&app); +#ifdef Q_OS_WINDOWS + auto font_name = QObject::tr("FONT_NAME"); + auto font_size = QObject::tr("FONT_SIZE"); + QApplication::setFont(QFont(font_name, font_size.toInt())); + SetCurrentProcessExplicitAppUserModelID(L"86Box.86Box"); +#endif + if (! pc_init_modules()) { + ui_msgbox_header(MBX_FATAL, (void*)IDS_2120, (void*)IDS_2056); + return 6; + } + + if (settings_only) + { + Settings settings; + if (settings.exec() == QDialog::Accepted) + { + settings.save(); + config_save(); + } + return 0; + } + + discord_load(); + + main_window = new MainWindow(); + main_window->show(); + app.installEventFilter(main_window); + +#ifdef Q_OS_WINDOWS + /* Setup VM-manager messages */ + std::unique_ptr wmfilter; + if (source_hwnd) + { + HWND main_hwnd = (HWND)main_window->winId(); + + wmfilter.reset(new WindowsManagerFilter()); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::showsettings, main_window, &MainWindow::showSettings); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::pause, main_window, &MainWindow::togglePause); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::reset, main_window, &MainWindow::hardReset); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::request_shutdown, main_window, &MainWindow::close); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::force_shutdown, [](){ + do_stop(); + emit main_window->close(); + }); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::ctrlaltdel, [](){ pc_send_cad(); }); + QObject::connect(wmfilter.get(), &WindowsManagerFilter::dialogstatus, [main_hwnd](bool open){ + PostMessage((HWND)(uintptr_t)source_hwnd, WM_SENDDLGSTATUS, (WPARAM)(open ? 1 : 0), (LPARAM)main_hwnd); + }); + + /* Native filter to catch VM-managers commands */ + app.installNativeEventFilter(wmfilter.get()); + + /* Filter to catch main window being blocked (by modal dialog) */ + main_window->installEventFilter(wmfilter.get()); + + /* Send main window HWND to manager */ + PostMessage((HWND)(uintptr_t)source_hwnd, WM_SENDHWND, (WPARAM)unique_id, (LPARAM)main_hwnd); + + /* Send shutdown message to manager */ + QObject::connect(&app, &QApplication::destroyed, [main_hwnd](QObject*) { + PostMessage((HWND)(uintptr_t)source_hwnd, WM_HAS_SHUTDOWN, (WPARAM)0, (LPARAM)main_hwnd); + }); + } + + /* Setup raw input */ + auto rawInputFilter = WindowsRawInputFilter::Register(main_window); + if (rawInputFilter) + { + app.installNativeEventFilter(rawInputFilter.get()); + QObject::disconnect(main_window, &MainWindow::pollMouse, 0, 0); + QObject::connect(main_window, &MainWindow::pollMouse, (WindowsRawInputFilter*)rawInputFilter.get(), &WindowsRawInputFilter::mousePoll, Qt::DirectConnection); + main_window->setSendKeyboardInput(false); + } +#endif + + UnixManagerSocket socket; + if (qgetenv("86BOX_MANAGER_SOCKET").size()) + { + QObject::connect(&socket, &UnixManagerSocket::showsettings, main_window, &MainWindow::showSettings); + QObject::connect(&socket, &UnixManagerSocket::pause, main_window, &MainWindow::togglePause); + QObject::connect(&socket, &UnixManagerSocket::resetVM, main_window, &MainWindow::hardReset); + QObject::connect(&socket, &UnixManagerSocket::request_shutdown, main_window, &MainWindow::close); + QObject::connect(&socket, &UnixManagerSocket::force_shutdown, [](){ + do_stop(); + emit main_window->close(); + }); + QObject::connect(&socket, &UnixManagerSocket::ctrlaltdel, [](){ pc_send_cad(); }); + main_window->installEventFilter(&socket); + socket.connectToServer(qgetenv("86BOX_MANAGER_SOCKET")); + } + //pc_reset_hard_init(); + + /* Set the PAUSE mode depending on the renderer. */ + // plat_pause(0); + QTimer onesec; + QTimer discordupdate; + QObject::connect(&onesec, &QTimer::timeout, &app, [] { + pc_onesec(); + }); + onesec.setTimerType(Qt::PreciseTimer); + onesec.start(1000); + if (discord_loaded) { + QTimer::singleShot(1000, &app, [] { + if (enable_discord) { + discord_init(); + discord_update_activity(dopause); + } else + discord_close(); + }); + QObject::connect(&discordupdate, &QTimer::timeout, &app, [] { + discord_run_callbacks(); + }); + discordupdate.start(0); + } + + /* Initialize the rendering window, or fullscreen. */ + QTimer::singleShot(0, &app, [] + { + pc_reset_hard_init(); + main_thread = new std::thread(main_thread_fn); + }); + + auto ret = app.exec(); + cpu_thread_run = 0; + main_thread->join(); + pc_close(nullptr); + + socket.close(); + return ret; +} diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp new file mode 100644 index 000000000..0725d21a4 --- /dev/null +++ b/src/qt/qt_mainwindow.cpp @@ -0,0 +1,2059 @@ +/* + * 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. + * + * Main window module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * dob205 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021-2022 Teemu Korhonen + * Copyright 2022 dob205 + */ +#include + +#include "qt_mainwindow.hpp" +#include "ui_qt_mainwindow.h" + +#include "qt_specifydimensions.h" +#include "qt_soundgain.hpp" +#include "qt_progsettings.hpp" +#include "qt_mcadevicelist.hpp" + +#include "qt_rendererstack.hpp" +#include "qt_renderercommon.hpp" + +extern "C" { +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/keyboard.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/discord.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/machine.h> +#include <86box/vid_ega.h> +#include <86box/version.h> + + extern int qt_nvr_save(void); + +#ifdef MTR_ENABLED +#include +#endif +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "qt_settings.hpp" +#include "qt_machinestatus.hpp" +#include "qt_mediamenu.hpp" +#include "qt_util.hpp" + +#if defined __unix__ && !defined __HAIKU__ +#ifdef WAYLAND +#include "wl_mouse.hpp" +#endif +#include +#include +#undef KeyPress +#undef KeyRelease +#endif + +#ifdef Q_OS_MACOS +// The namespace is required to avoid clashing typedefs; we only use this +// header for its #defines anyway. +namespace IOKit { + #include +} +#endif + +#ifdef __HAIKU__ +#include +#include + +extern MainWindow* main_window; + +filter_result keyb_filter(BMessage *message, BHandler **target, BMessageFilter *filter) +{ + if (message->what == B_KEY_DOWN || message->what == B_KEY_UP + || message->what == B_UNMAPPED_KEY_DOWN || message->what == B_UNMAPPED_KEY_UP) + { + int key_state = 0, key_scancode = 0; + key_state = message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN; + message->FindInt32("key", &key_scancode); + QGuiApplication::postEvent(main_window, new QKeyEvent(key_state ? QEvent::KeyPress : QEvent::KeyRelease, 0, QGuiApplication::keyboardModifiers(), key_scancode, 0, 0)); + if (key_scancode == 0x68 && key_state) + { + QGuiApplication::postEvent(main_window, new QKeyEvent(QEvent::KeyRelease, 0, QGuiApplication::keyboardModifiers(), key_scancode, 0, 0)); + } + } + return B_DISPATCH_MESSAGE; +} + +static BMessageFilter* filter; +#endif + +extern void qt_mouse_capture(int); +extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index); + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + mm = std::make_shared(this); + MediaMenu::ptr = mm; + status = std::make_unique(this); + +#ifdef __HAIKU__ + filter = new BMessageFilter(B_PROGRAMMED_DELIVERY, B_ANY_SOURCE, keyb_filter); + ((BWindow*)this->winId())->AddFilter(filter); +#endif + setUnifiedTitleAndToolBarOnMac(true); + ui->setupUi(this); + ui->stackedWidget->setMouseTracking(true); + statusBar()->setVisible(!hide_status_bar); + statusBar()->setStyleSheet("QStatusBar::item {border: None; } QStatusBar QLabel { margin-right: 2px; margin-bottom: 1px; }"); + ui->toolBar->setVisible(!hide_tool_bar); + renderers[0].reset(nullptr); + auto toolbar_spacer = new QWidget(); + toolbar_spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + ui->toolBar->addWidget(toolbar_spacer); + + auto toolbar_label = new QLabel(); + ui->toolBar->addWidget(toolbar_label); + +#ifdef RELEASE_BUILD + this->setWindowIcon(QIcon(":/settings/win/icons/86Box-green.ico")); +#elif defined ALPHA_BUILD + this->setWindowIcon(QIcon(":/settings/win/icons/86Box-red.ico")); +#elif defined BETA_BUILD + this->setWindowIcon(QIcon(":/settings/win/icons/86Box-yellow.ico")); +#else + this->setWindowIcon(QIcon(":/settings/win/icons/86Box-gray.ico")); +#endif + this->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, vid_resize != 1); + this->setWindowFlag(Qt::WindowMaximizeButtonHint, vid_resize == 1); + + QString vmname(vm_name); + if (vmname.at(vmname.size() - 1) == '"' || vmname.at(vmname.size() - 1) == '\'') vmname.truncate(vmname.size() - 1); + this->setWindowTitle(QString("%1 - %2 %3").arg(vmname, EMU_NAME, EMU_VERSION_FULL)); + + connect(this, &MainWindow::showMessageForNonQtThread, this, &MainWindow::showMessage_, Qt::BlockingQueuedConnection); + + connect(this, &MainWindow::setTitle, this, [this,toolbar_label](const QString& title) { + if (dopause && !hide_tool_bar) + { + toolbar_label->setText(toolbar_label->text() + tr(" - PAUSED")); + return; + } + if (!hide_tool_bar) +#ifdef _WIN32 + toolbar_label->setText(title); +#else + { + /* get the percentage and mouse message, TODO: refactor ui_window_title() */ + auto parts = title.split(" - "); + if (parts.size() >= 2) { + if (parts.size() < 5) + toolbar_label->setText(parts[1]); + else + toolbar_label->setText(QString("%1 - %2").arg(parts[1], parts.last())); + } + } +#endif + ui->actionPause->setChecked(dopause); + }); + connect(this, &MainWindow::getTitleForNonQtThread, this, &MainWindow::getTitle_, Qt::BlockingQueuedConnection); + + connect(this, &MainWindow::updateMenuResizeOptions, [this]() { + ui->actionResizable_window->setEnabled(vid_resize != 2); + ui->actionResizable_window->setChecked(vid_resize == 1); + ui->menuWindow_scale_factor->setEnabled(vid_resize == 0); + }); + + connect(this, &MainWindow::updateWindowRememberOption, [this]() { + ui->actionRemember_size_and_position->setChecked(window_remember); + }); + + emit updateMenuResizeOptions(); + + connect(this, &MainWindow::pollMouse, ui->stackedWidget, &RendererStack::mousePoll, Qt::DirectConnection); + + connect(this, &MainWindow::setMouseCapture, this, [this](bool state) { + mouse_capture = state ? 1 : 0; + qt_mouse_capture(mouse_capture); + if (mouse_capture) { + this->grabKeyboard(); + if (ui->stackedWidget->mouse_capture_func) + ui->stackedWidget->mouse_capture_func(this->windowHandle()); + } else { + this->releaseKeyboard(); + if (ui->stackedWidget->mouse_uncapture_func) + ui->stackedWidget->mouse_uncapture_func(); + } + }); + + connect(qApp, &QGuiApplication::applicationStateChanged, [this](Qt::ApplicationState state) { + if (mouse_capture && state != Qt::ApplicationState::ApplicationActive) + emit setMouseCapture(false); + }); + + connect(this, &MainWindow::resizeContents, this, [this](int w, int h) { + if (shownonce) { + if (resizableonce == false) ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + resizableonce = true; + } + if (!QApplication::platformName().contains("eglfs") && vid_resize != 1) { + w = (w / (!dpi_scale ? util::screenOfWidget(this)->devicePixelRatio() : 1.)); + + int modifiedHeight = (h / (!dpi_scale ? util::screenOfWidget(this)->devicePixelRatio() : 1.)) + + menuBar()->height() + + (statusBar()->height() * !hide_status_bar) + + (ui->toolBar->height() * !hide_tool_bar); + + ui->stackedWidget->resize(w, h); + setFixedSize(w, modifiedHeight); + } + }); + + connect(this, &MainWindow::resizeContentsMonitor, this, [this](int w, int h, int monitor_index) + { + if (!QApplication::platformName().contains("eglfs") && vid_resize != 1) { + qDebug() << "Resize"; + w = (w / (!dpi_scale ? util::screenOfWidget(renderers[monitor_index].get())->devicePixelRatio() : 1.)); + + int modifiedHeight = (h / (!dpi_scale ? util::screenOfWidget(renderers[monitor_index].get())->devicePixelRatio() : 1.)); + + renderers[monitor_index]->setFixedSize(w, modifiedHeight); + } + }); + + connect(ui->menubar, &QMenuBar::triggered, this, [this] { + config_save(); + if (QApplication::activeWindow() == this) + { + ui->stackedWidget->setFocusRenderer(); + } + }); + + connect(this, &MainWindow::updateStatusBarPanes, this, [this] { + refreshMediaMenu(); + }); + connect(this, &MainWindow::updateStatusBarPanes, this, &MainWindow::refreshMediaMenu); + connect(this, &MainWindow::updateStatusBarTip, status.get(), &MachineStatus::updateTip); + connect(this, &MainWindow::statusBarMessage, status.get(), &MachineStatus::message, Qt::QueuedConnection); + + ui->actionKeyboard_requires_capture->setChecked(kbd_req_capture); + ui->actionRight_CTRL_is_left_ALT->setChecked(rctrl_is_lalt); + ui->actionResizable_window->setChecked(vid_resize == 1); + ui->actionRemember_size_and_position->setChecked(window_remember); + ui->menuWindow_scale_factor->setEnabled(vid_resize == 0); + ui->actionHiDPI_scaling->setChecked(dpi_scale); + ui->actionHide_status_bar->setChecked(hide_status_bar); + ui->actionHide_tool_bar->setChecked(hide_tool_bar); + ui->actionShow_non_primary_monitors->setChecked(show_second_monitors); + ui->actionUpdate_status_bar_icons->setChecked(update_icons); + ui->actionEnable_Discord_integration->setChecked(enable_discord); + +#if defined Q_OS_WINDOWS || defined Q_OS_MACOS + /* Make the option visible only if ANGLE is loaded. */ + ui->actionHardware_Renderer_OpenGL_ES->setVisible(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES); + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGLES && vid_api == 2) vid_api = 1; +#endif + ui->actionHardware_Renderer_OpenGL->setVisible(QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGLES); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES && vid_api == 1) vid_api = 0; + + if ((QApplication::platformName().contains("eglfs") || QApplication::platformName() == "haiku")) { + if (vid_api >= 1) fprintf(stderr, "OpenGL renderers are unsupported on %s.\n", QApplication::platformName().toUtf8().data()); + vid_api = 0; + ui->actionHardware_Renderer_OpenGL->setVisible(false); + ui->actionHardware_Renderer_OpenGL_ES->setVisible(false); + ui->actionVulkan->setVisible(false); + ui->actionOpenGL_3_0_Core->setVisible(false); + } +#if !defined Q_OS_WINDOWS + ui->actionDirect3D_9->setVisible(false); + if (vid_api == 5) vid_api = 0; +#endif + +#if !QT_CONFIG(vulkan) + if (vid_api == 4) vid_api = 0; + ui->actionVulkan->setVisible(false); +#endif + + QActionGroup* actGroup = nullptr; + + actGroup = new QActionGroup(this); + actGroup->addAction(ui->actionSoftware_Renderer); + actGroup->addAction(ui->actionHardware_Renderer_OpenGL); + actGroup->addAction(ui->actionHardware_Renderer_OpenGL_ES); + actGroup->addAction(ui->actionOpenGL_3_0_Core); + actGroup->addAction(ui->actionVulkan); + actGroup->addAction(ui->actionDirect3D_9); + actGroup->setExclusive(true); + + connect(actGroup, &QActionGroup::triggered, [this](QAction* action) { + vid_api = action->property("vid_api").toInt(); + RendererStack::Renderer newVidApi = RendererStack::Renderer::Software; + switch (vid_api) + { + case 0: + newVidApi = RendererStack::Renderer::Software; + break; + case 1: + newVidApi = (RendererStack::Renderer::OpenGL); + break; + case 2: + newVidApi = (RendererStack::Renderer::OpenGLES); + break; + case 3: + newVidApi = (RendererStack::Renderer::OpenGL3); + break; + case 4: + newVidApi = (RendererStack::Renderer::Vulkan); + break; + case 5: + newVidApi = (RendererStack::Renderer::Direct3D9); + break; + } + ui->stackedWidget->switchRenderer(newVidApi); + if (!show_second_monitors) return; + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i]) renderers[i]->switchRenderer(newVidApi); + } + }); + + connect(ui->stackedWidget, &RendererStack::rendererChanged, [this]() { + ui->actionRenderer_options->setVisible(ui->stackedWidget->hasOptions()); + }); + + /* Trigger initial renderer switch */ + for (auto action : actGroup->actions()) + if (action->property("vid_api").toInt() == vid_api) { + action->setChecked(true); + emit actGroup->triggered(action); + break; + } + + switch (scale) { + case 0: + ui->action0_5x->setChecked(true); + break; + case 1: + ui->action1x->setChecked(true); + break; + case 2: + ui->action1_5x->setChecked(true); + break; + case 3: + ui->action2x->setChecked(true); + break; + } + actGroup = new QActionGroup(this); + actGroup->addAction(ui->action0_5x); + actGroup->addAction(ui->action1x); + actGroup->addAction(ui->action1_5x); + actGroup->addAction(ui->action2x); + switch (video_filter_method) { + case 0: + ui->actionNearest->setChecked(true); + break; + case 1: + ui->actionLinear->setChecked(true); + break; + } + actGroup = new QActionGroup(this); + actGroup->addAction(ui->actionNearest); + actGroup->addAction(ui->actionLinear); + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_FULL: + ui->actionFullScreen_stretch->setChecked(true); + break; + case FULLSCR_SCALE_43: + ui->actionFullScreen_43->setChecked(true); + break; + case FULLSCR_SCALE_KEEPRATIO: + ui->actionFullScreen_keepRatio->setChecked(true); + break; + case FULLSCR_SCALE_INT: + ui->actionFullScreen_int->setChecked(true); + break; + } + actGroup = new QActionGroup(this); + actGroup->addAction(ui->actionFullScreen_stretch); + actGroup->addAction(ui->actionFullScreen_43); + actGroup->addAction(ui->actionFullScreen_keepRatio); + actGroup->addAction(ui->actionFullScreen_int); + switch (video_grayscale) { + case 0: + ui->actionRGB_Color->setChecked(true); + break; + case 1: + ui->actionRGB_Grayscale->setChecked(true); + break; + case 2: + ui->actionAmber_monitor->setChecked(true); + break; + case 3: + ui->actionGreen_monitor->setChecked(true); + break; + case 4: + ui->actionWhite_monitor->setChecked(true); + break; + } + actGroup = new QActionGroup(this); + actGroup->addAction(ui->actionRGB_Grayscale); + actGroup->addAction(ui->actionAmber_monitor); + actGroup->addAction(ui->actionGreen_monitor); + actGroup->addAction(ui->actionWhite_monitor); + actGroup->addAction(ui->actionRGB_Color); + switch (video_graytype) { + case 0: + ui->actionBT601_NTSC_PAL->setChecked(true); + break; + case 1: + ui->actionBT709_HDTV->setChecked(true); + break; + case 2: + ui->actionAverage->setChecked(true); + break; + } + actGroup = new QActionGroup(this); + actGroup->addAction(ui->actionBT601_NTSC_PAL); + actGroup->addAction(ui->actionBT709_HDTV); + actGroup->addAction(ui->actionAverage); + if (force_43 > 0) { + ui->actionForce_4_3_display_ratio->setChecked(true); + } + if (enable_overscan > 0) { + ui->actionCGA_PCjr_Tandy_EGA_S_VGA_overscan->setChecked(true); + } + if (vid_cga_contrast > 0) { + ui->actionChange_contrast_for_monochrome_display->setChecked(true); + } + +#ifdef Q_OS_MACOS + ui->actionFullscreen->setShortcutVisibleInContextMenu(true); + ui->actionCtrl_Alt_Del->setShortcutVisibleInContextMenu(true); + ui->actionTake_screenshot->setShortcutVisibleInContextMenu(true); +#endif + video_setblit(qt_blit); + + if (start_in_fullscreen) { + connect(ui->stackedWidget, &RendererStack::blitToRenderer, this, [this] () { + if (start_in_fullscreen) { + QTimer::singleShot(100, ui->actionFullscreen, &QAction::trigger); + start_in_fullscreen = 0; + } + }); + } + +#ifdef MTR_ENABLED + { + ui->actionBegin_trace->setVisible(true); + ui->actionEnd_trace->setVisible(true); + ui->actionBegin_trace->setShortcut(QKeySequence(Qt::Key_Control + Qt::Key_T)); + ui->actionEnd_trace->setShortcut(QKeySequence(Qt::Key_Control + Qt::Key_T)); + ui->actionEnd_trace->setDisabled(true); + static auto init_trace = [&] + { + mtr_init("trace.json"); + mtr_start(); + }; + static auto shutdown_trace = [&] + { + mtr_stop(); + mtr_shutdown(); + }; +#ifdef Q_OS_MACOS + ui->actionBegin_trace->setShortcutVisibleInContextMenu(true); + ui->actionEnd_trace->setShortcutVisibleInContextMenu(true); +#endif + static bool trace = false; + connect(ui->actionBegin_trace, &QAction::triggered, this, [this] + { + if (trace) return; + ui->actionBegin_trace->setDisabled(true); + ui->actionEnd_trace->setDisabled(false); + init_trace(); + trace = true; + }); + connect(ui->actionEnd_trace, &QAction::triggered, this, [this] + { + if (!trace) return; + ui->actionBegin_trace->setDisabled(false); + ui->actionEnd_trace->setDisabled(true); + shutdown_trace(); + trace = false; + }); + } +#endif + + setContextMenuPolicy(Qt::PreventContextMenu); + + connect(this, &MainWindow::initRendererMonitor, this, &MainWindow::initRendererMonitorSlot); + connect(this, &MainWindow::initRendererMonitorForNonQtThread, this, &MainWindow::initRendererMonitorSlot, Qt::BlockingQueuedConnection); + connect(this, &MainWindow::destroyRendererMonitor, this, &MainWindow::destroyRendererMonitorSlot); + connect(this, &MainWindow::destroyRendererMonitorForNonQtThread, this, &MainWindow::destroyRendererMonitorSlot, Qt::BlockingQueuedConnection); +} + +void MainWindow::closeEvent(QCloseEvent *event) { + if (mouse_capture) { + event->ignore(); + return; + } + + if (confirm_exit && confirm_exit_cmdl && cpu_thread_run) + { + QMessageBox questionbox(QMessageBox::Icon::Question, "86Box", tr("Are you sure you want to exit 86Box?"), QMessageBox::Yes | QMessageBox::No, this); + QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); + questionbox.setCheckBox(chkbox); + chkbox->setChecked(!confirm_exit); + + QObject::connect(chkbox, &QCheckBox::stateChanged, [](int state) { + confirm_exit = (state == Qt::CheckState::Unchecked); + }); + questionbox.exec(); + if (questionbox.result() == QMessageBox::No) { + confirm_exit = true; + event->ignore(); + return; + } + } + if (window_remember) { + window_w = ui->stackedWidget->width(); + window_h = ui->stackedWidget->height(); + if (!QApplication::platformName().contains("wayland")) { + window_x = this->geometry().x(); + window_y = this->geometry().y(); + } + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i]) { + monitor_settings[i].mon_window_w = renderers[i]->geometry().width(); + monitor_settings[i].mon_window_h = renderers[i]->geometry().height(); + if (QApplication::platformName().contains("wayland")) continue; + monitor_settings[i].mon_window_x = renderers[i]->geometry().x(); + monitor_settings[i].mon_window_y = renderers[i]->geometry().y(); + } + } + } + + if (ui->stackedWidget->mouse_exit_func) + ui->stackedWidget->mouse_exit_func(); + + ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software); + + qt_nvr_save(); + config_save(); + QApplication::processEvents(); + cpu_thread_run = 0; + event->accept(); +} + +void MainWindow::initRendererMonitorSlot(int monitor_index) +{ + auto& secondaryRenderer = this->renderers[monitor_index]; + secondaryRenderer.reset(new RendererStack(nullptr, monitor_index)); + if (secondaryRenderer) { + connect(secondaryRenderer.get(), &RendererStack::rendererChanged, this, [this, monitor_index] + { + this->renderers[monitor_index]->show(); + }); + secondaryRenderer->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + secondaryRenderer->setWindowTitle(QObject::tr("86Box Monitor #") + QString::number(monitor_index + 1)); + + if (vid_resize == 2) { + secondaryRenderer->setFixedSize(fixed_size_x, fixed_size_y); + } + secondaryRenderer->setWindowIcon(this->windowIcon()); + if (show_second_monitors) { + secondaryRenderer->show(); + if (window_remember) { + secondaryRenderer->setGeometry(monitor_settings[monitor_index].mon_window_x < 120 ? 120 : monitor_settings[monitor_index].mon_window_x, + monitor_settings[monitor_index].mon_window_y < 120 ? 120 : monitor_settings[monitor_index].mon_window_y, + monitor_settings[monitor_index].mon_window_w > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_w, + monitor_settings[monitor_index].mon_window_h > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_h); + } + secondaryRenderer->switchRenderer((RendererStack::Renderer)vid_api); + } + + } +} + +void MainWindow::destroyRendererMonitorSlot(int monitor_index) +{ + if (this->renderers[monitor_index]) { + if (window_remember) { + monitor_settings[monitor_index].mon_window_w = renderers[monitor_index]->geometry().width(); + monitor_settings[monitor_index].mon_window_h = renderers[monitor_index]->geometry().height(); + monitor_settings[monitor_index].mon_window_x = renderers[monitor_index]->geometry().x(); + monitor_settings[monitor_index].mon_window_y = renderers[monitor_index]->geometry().y(); + } + config_save(); + this->renderers[monitor_index].release()->deleteLater(); + } +} + +MainWindow::~MainWindow() { + delete ui; +} + +void MainWindow::showEvent(QShowEvent *event) { + if (shownonce) return; + shownonce = true; + if (window_remember && !QApplication::platformName().contains("wayland")) { + setGeometry(window_x, window_y, window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height())); + } + if (vid_resize == 2) { + setFixedSize(fixed_size_x, fixed_size_y + + menuBar()->height() + + (hide_status_bar ? 0 : statusBar()->height()) + + (hide_tool_bar ? 0 : ui->toolBar->height())); + + monitors[0].mon_scrnsz_x = fixed_size_x; + monitors[0].mon_scrnsz_y = fixed_size_y; + } + if (window_remember && vid_resize == 1) { + ui->stackedWidget->setFixedSize(window_w, window_h); + QApplication::processEvents(); + this->adjustSize(); + } +} + +void MainWindow::on_actionKeyboard_requires_capture_triggered() { + kbd_req_capture ^= 1; +} + +void MainWindow::on_actionRight_CTRL_is_left_ALT_triggered() { + rctrl_is_lalt ^= 1; +} + +void MainWindow::on_actionHard_Reset_triggered() { + if (confirm_reset) + { + QMessageBox questionbox(QMessageBox::Icon::Question, "86Box", tr("Are you sure you want to hard reset the emulated machine?"), QMessageBox::NoButton, this); + questionbox.addButton(tr("Reset"), QMessageBox::AcceptRole); + questionbox.addButton(tr("Don't reset"), QMessageBox::RejectRole); + QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); + questionbox.setCheckBox(chkbox); + chkbox->setChecked(!confirm_reset); + + QObject::connect(chkbox, &QCheckBox::stateChanged, [](int state) { + confirm_reset = (state == Qt::CheckState::Unchecked); + }); + questionbox.exec(); + if (questionbox.result() == QDialog::Accepted) + { + confirm_reset = true; + return; + } + } + config_changed = 2; + pc_reset_hard(); +} + +void MainWindow::on_actionCtrl_Alt_Del_triggered() { + pc_send_cad(); +} + +void MainWindow::on_actionCtrl_Alt_Esc_triggered() { + pc_send_cae(); +} + +void MainWindow::on_actionPause_triggered() { + plat_pause(dopause ^ 1); +} + +void MainWindow::on_actionExit_triggered() { + close(); +} + +void MainWindow::on_actionSettings_triggered() { + int currentPause = dopause; + plat_pause(1); + Settings settings(this); + settings.setModal(true); + settings.setWindowModality(Qt::WindowModal); + settings.exec(); + + switch (settings.result()) { + case QDialog::Accepted: + /* + pc_reset_hard_close(); + settings.save(); + config_changed = 2; + pc_reset_hard_init(); + */ + settings.save(); + config_changed = 2; + pc_reset_hard(); + + break; + case QDialog::Rejected: + break; + } + plat_pause(currentPause); +} + +#if defined(__unix__) && !defined(__HAIKU__) +std::array x11_to_xt_base +{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x147, + 0x148, + 0x149, + 0, + 0x14B, + 0, + 0x14D, + 0x14F, + 0x150, + 0x151, + 0x152, + 0x153, + 0x11C, + 0x11D, + 0, // Pause/Break key. + 0x137, + 0x135, + 0x138, + 0, // Ditto as above comment. + 0x15B, + 0x15C, + 0x15D, +}; + +std::array x11_to_xt_2 +{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x0E, + 0x0F, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x11C, + 0x11D, + 0x135, + 0x137, + 0x138, + 0, + 0x147, + 0x148, + 0x149, + 0x14B, + 0x14D, + 0x14F, + 0x150, + 0x151, + 0x152, + 0x153 +}; + +std::array x11_to_xt_vnc +{ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x1D, + 0x11D, + 0x2A, + 0x36, + 0, + 0, + 0x38, + 0x138, + 0x39, + 0x0B, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0C, + 0x0D, + 0x1A, + 0x1B, + 0x27, + 0x28, + 0x29, + 0x33, + 0x34, + 0x35, + 0x2B, + 0x1E, + 0x30, + 0x2E, + 0x20, + 0x12, + 0x21, + 0x22, + 0x23, + 0x17, + 0x24, + 0x25, + 0x26, + 0x32, + 0x31, + 0x18, + 0x19, + 0x10, + 0x13, + 0x1F, + 0x14, + 0x16, + 0x2F, + 0x11, + 0x2D, + 0x15, + 0x2C, + 0x0E, + 0x1C, + 0x0F, + 0x01, + 0x153, + 0x147, + 0x14F, + 0x149, + 0x151, + 0x148, + 0x150, + 0x14B, + 0x14D, +}; +#endif + +#ifdef Q_OS_MACOS +std::array darwin_to_xt +{ + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x23, + 0x22, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x2B, + 0x30, + 0x10, + 0x11, + 0x12, + 0x13, + 0x15, + 0x14, + 0x02, + 0x03, + 0x04, + 0x05, + 0x07, + 0x06, + 0x0D, + 0x0A, + 0x08, + 0x0C, + 0x09, + 0x0B, + 0x1B, + 0x18, + 0x16, + 0x1A, + 0x17, + 0x19, + 0x1C, + 0x26, + 0x24, + 0x28, + 0x25, + 0x27, + 0x2B, + 0x33, + 0x35, + 0x31, + 0x32, + 0x34, + 0x0F, + 0x39, + 0x29, + 0x0E, + 0x11C, + 0x01, + 0x15C, + 0x15B, + 0x2A, + 0x3A, + 0x38, + 0x1D, + 0x36, + 0x138, + 0x11D, + 0x15C, + 0, + 0x53, + 0, + 0x37, + 0, + 0x4E, + 0, + 0x45, + 0x130, + 0x12E, + 0x120, + 0x135, + 0x11C, + 0, + 0x4A, + 0, + 0, + 0, + 0x52, + 0x4F, + 0x50, + 0x51, + 0x4B, + 0x4C, + 0x4D, + 0x47, + 0, + 0x48, + 0x49, + 0, + 0, + 0, + 0x3F, + 0x40, + 0x41, + 0x3D, + 0x42, + 0x43, + 0, + 0x57, + 0, + 0x137, + 0, + 0x46, + 0, + 0x44, + 0x15D, + 0x58, + 0, + 0, // Pause/Break key. + 0x152, + 0x147, + 0x149, + 0x153, + 0x3E, + 0x14F, + 0x3C, + 0x151, + 0x3B, + 0x14B, + 0x14D, + 0x150, + 0x148, + 0, +}; +#endif + +#if defined(__unix__) && !defined(__HAIKU__) +static std::unordered_map evdev_to_xt = + { + {96, 0x11C}, + {97, 0x11D}, + {98, 0x135}, + {99, 0x71}, + {100, 0x138}, + {101, 0x1C}, + {102, 0x147}, + {103, 0x148}, + {104, 0x149}, + {105, 0x14B}, + {106, 0x14D}, + {107, 0x14F}, + {108, 0x150}, + {109, 0x151}, + {110, 0x152}, + {111, 0x153} +}; +#endif + +#ifdef __HAIKU__ +static std::unordered_map be_to_xt = +{ + {0x01, 0x01}, + {B_F1_KEY, 0x3B}, + {B_F2_KEY, 0x3C}, + {B_F3_KEY, 0x3D}, + {B_F4_KEY, 0x3E}, + {B_F5_KEY, 0x3F}, + {B_F6_KEY, 0x40}, + {B_F7_KEY, 0x41}, + {B_F8_KEY, 0x42}, + {B_F9_KEY, 0x43}, + {B_F10_KEY, 0x44}, + {B_F11_KEY, 0x57}, + {B_F12_KEY, 0x58}, + {0x11, 0x29}, + {0x12, 0x02}, + {0x13, 0x03}, + {0x14, 0x04}, + {0x15, 0x05}, + {0x16, 0x06}, + {0x17, 0x07}, + {0x18, 0x08}, + {0x19, 0x09}, + {0x1A, 0x0A}, + {0x1B, 0x0B}, + {0x1C, 0x0C}, + {0x1D, 0x0D}, + {0x1E, 0x0E}, + {0x1F, 0x152}, + {0x20, 0x147}, + {0x21, 0x149}, + {0x22, 0x45}, + {0x23, 0x135}, + {0x24, 0x37}, + {0x25, 0x4A}, + {0x26, 0x0F}, + {0x27, 0x10}, + {0x28, 0x11}, + {0x29, 0x12}, + {0x2A, 0x13}, + {0x2B, 0x14}, + {0x2C, 0x15}, + {0x2D, 0x16}, + {0x2E, 0x17}, + {0x2F, 0x18}, + {0x30, 0x19}, + {0x31, 0x1A}, + {0x32, 0x1B}, + {0x33, 0x2B}, + {0x34, 0x153}, + {0x35, 0x14F}, + {0x36, 0x151}, + {0x37, 0x47}, + {0x38, 0x48}, + {0x39, 0x49}, + {0x3A, 0x4E}, + {0x3B, 0x3A}, + {0x3C, 0x1E}, + {0x3D, 0x1F}, + {0x3E, 0x20}, + {0x3F, 0x21}, + {0x40, 0x22}, + {0x41, 0x23}, + {0x42, 0x24}, + {0x43, 0x25}, + {0x44, 0x26}, + {0x45, 0x27}, + {0x46, 0x28}, + {0x47, 0x1C}, + {0x48, 0x4B}, + {0x49, 0x4C}, + {0x4A, 0x4D}, + {0x4B, 0x2A}, + {0x4C, 0x2C}, + {0x4D, 0x2D}, + {0x4E, 0x2E}, + {0x4F, 0x2F}, + {0x50, 0x30}, + {0x51, 0x31}, + {0x52, 0x32}, + {0x53, 0x33}, + {0x54, 0x34}, + {0x55, 0x35}, + {0x56, 0x36}, + {0x57, 0x148}, + {0x58, 0x51}, + {0x59, 0x50}, + {0x5A, 0x4F}, + {0x5B, 0x11C}, + {0x5C, 0x1D}, + {0x5D, 0x38}, + {0x5E, 0x39}, + {0x5F, 0x138}, + {0x60, 0x11D}, + {0x61, 0x14B}, + {0x62, 0x150}, + {0x63, 0x14D}, + {0x64, 0x52}, + {0x65, 0x53}, + + {0x0e, 0x137}, + {0x0f, 0x46}, + {0x66, 0x15B}, + {0x67, 0x15C}, + {0x68, 0x15D}, + {0x69, 0x56} +}; +#endif + +#if defined(__unix__) && !defined(__HAIKU__) +static std::array& selected_keycode = x11_to_xt_base; +#endif + +uint16_t x11_keycode_to_keysym(uint32_t keycode) +{ + uint16_t finalkeycode = 0; +#if defined(Q_OS_WINDOWS) + finalkeycode = (keycode & 0xFFFF); +#elif defined(Q_OS_MACOS) + finalkeycode = darwin_to_xt[keycode]; +#elif defined(__HAIKU__) + finalkeycode = be_to_xt[keycode]; +#else + static Display* x11display = nullptr; + if (QApplication::platformName().contains("wayland")) + { + selected_keycode = x11_to_xt_2; + } + else if (QApplication::platformName().contains("eglfs")) + { + keycode -= 8; + if (keycode <= 88) finalkeycode = keycode; + else finalkeycode = evdev_to_xt[keycode]; + } + else if (!x11display) + { + x11display = XOpenDisplay(nullptr); + if (XKeysymToKeycode(x11display, XK_Home) == 110) + { + selected_keycode = x11_to_xt_2; + } + else if (XKeysymToKeycode(x11display, XK_Home) == 69) + { + selected_keycode = x11_to_xt_vnc; + } + } + if (!QApplication::platformName().contains("eglfs")) finalkeycode = selected_keycode[keycode]; +#endif + if (rctrl_is_lalt && finalkeycode == 0x11D) + { + finalkeycode = 0x38; + } + return finalkeycode; +} + +#ifdef Q_OS_MACOS +// These modifiers are listed as "device-dependent" in IOLLEvent.h, but +// that's followed up with "(really?)". It's the only way to distinguish +// left and right modifiers with Qt 6 on macOS, so let's just roll with it. +static std::unordered_map mac_modifiers_to_xt = { + {NX_DEVICELCTLKEYMASK, 0x1D}, + {NX_DEVICELSHIFTKEYMASK, 0x2A}, + {NX_DEVICERSHIFTKEYMASK, 0x36}, + {NX_DEVICELCMDKEYMASK, 0x15B}, + {NX_DEVICERCMDKEYMASK, 0x15C}, + {NX_DEVICELALTKEYMASK, 0x38}, + {NX_DEVICERALTKEYMASK, 0x138}, + {NX_DEVICE_ALPHASHIFT_STATELESS_MASK, 0x3A}, + {NX_DEVICERCTLKEYMASK, 0x11D}, +}; + +void MainWindow::processMacKeyboardInput(bool down, const QKeyEvent* event) { + // Per QTBUG-69608 (https://bugreports.qt.io/browse/QTBUG-69608), + // QKeyEvents QKeyEvents for presses/releases of modifiers on macOS give + // nativeVirtualKey() == 0 (at least in Qt 6). Handle this by manually + // processing the nativeModifiers(). We need to check whether the key() is + // a known modifier because because kVK_ANSI_A is also 0, so the + // nativeVirtualKey() == 0 condition is ambiguous... + if (event->nativeVirtualKey() == 0 + && (event->key() == Qt::Key_Shift + || event->key() == Qt::Key_Control + || event->key() == Qt::Key_Meta + || event->key() == Qt::Key_Alt + || event->key() == Qt::Key_AltGr + || event->key() == Qt::Key_CapsLock)) { + // We only process one modifier at a time since events from Qt seem to + // always be non-coalesced (NX_NONCOALESCEDMASK is always set). + uint32_t changed_modifiers = last_modifiers ^ event->nativeModifiers(); + for (auto const& pair : mac_modifiers_to_xt) { + if (changed_modifiers & pair.first) { + last_modifiers ^= pair.first; + keyboard_input(down, pair.second); + return; + } + } + + // Caps Lock seems to be delivered as a single key press event when + // enabled and a single key release event when disabled, so we can't + // detect Caps Lock being held down; just send an infinitesimally-long + // press and release as a compromise. + // + // The event also doesn't get delivered if you turn Caps Lock off after + // turning it on when the window isn't focused. Doing better than this + // probably requires bypassing Qt input processing. + // + // It's possible that other lock keys get delivered in this way, but + // standard Apple keyboards don't have them, so this is untested. + if (event->key() == Qt::Key_CapsLock) { + keyboard_input(1, 0x3A); + keyboard_input(0, 0x3A); + } + } else { + keyboard_input(down, x11_keycode_to_keysym(event->nativeVirtualKey())); + } +} +#endif + +void MainWindow::on_actionFullscreen_triggered() { + if (video_fullscreen > 0) { + showNormal(); + if (vid_api == 5) ui->stackedWidget->switchRenderer(RendererStack::Renderer::Direct3D9); + ui->menubar->show(); + if (!hide_status_bar) ui->statusbar->show(); + if (!hide_tool_bar) ui->toolBar->show(); + video_fullscreen = 0; + if (vid_resize != 1) { + emit resizeContents(vid_resize == 2 ? fixed_size_x : monitors[0].mon_scrnsz_x, vid_resize == 2 ? fixed_size_y : monitors[0].mon_scrnsz_y); + } + } else { + if (video_fullscreen_first) + { + bool wasCaptured = mouse_capture == 1; + + QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), tr("Press Ctrl+Alt+PgDn to return to windowed mode."), QMessageBox::Ok, this); + QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); + questionbox.setCheckBox(chkbox); + chkbox->setChecked(!video_fullscreen_first); + + QObject::connect(chkbox, &QCheckBox::stateChanged, [](int state) { + video_fullscreen_first = (state == Qt::CheckState::Unchecked); + }); + questionbox.exec(); + config_save(); + + /* (re-capture mouse after dialog. */ + if (wasCaptured) + emit setMouseCapture(true); + } + video_fullscreen = 1; + setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + ui->menubar->hide(); + ui->statusbar->hide(); + ui->toolBar->hide(); + showFullScreen(); + } + ui->stackedWidget->onResize(width(), height()); +} + +void MainWindow::getTitle_(wchar_t *title) +{ + this->windowTitle().toWCharArray(title); +} + +void MainWindow::getTitle(wchar_t *title) +{ + if (QThread::currentThread() == this->thread()) { + getTitle_(title); + } else { + emit getTitleForNonQtThread(title); + } +} + +bool MainWindow::eventFilter(QObject* receiver, QEvent* event) +{ + if (!dopause && (mouse_capture || !kbd_req_capture)) { + if (event->type() == QEvent::Shortcut) { + auto shortcutEvent = (QShortcutEvent*)event; + if (shortcutEvent->key() == ui->actionExit->shortcut()) { + event->accept(); + return true; + } + } + if (event->type() == QEvent::KeyPress) { + event->accept(); + this->keyPressEvent((QKeyEvent *) event); + return true; + } + if (event->type() == QEvent::KeyRelease) { + event->accept(); + this->keyReleaseEvent((QKeyEvent *) event); + return true; + } + } + + if (receiver == this) { + static auto curdopause = dopause; + if (event->type() == QEvent::WindowBlocked) { + curdopause = dopause; + plat_pause(1); + emit setMouseCapture(false); + } else if (event->type() == QEvent::WindowUnblocked) { + plat_pause(curdopause); + } + } + + return QMainWindow::eventFilter(receiver, event); +} + +void MainWindow::refreshMediaMenu() { + mm->refresh(ui->menuMedia); + status->refresh(ui->statusbar); + ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); +} + +void MainWindow::showMessage(int flags, const QString& header, const QString& message) { + if (QThread::currentThread() == this->thread()) { + showMessage_(flags, header, message); + } else { + emit showMessageForNonQtThread(flags, header, message); + } +} + +void MainWindow::showMessage_(int flags, const QString &header, const QString &message) { + QMessageBox box(QMessageBox::Warning, header, message, QMessageBox::NoButton, this); + if (flags & (MBX_FATAL)) { + box.setIcon(QMessageBox::Critical); + } + else if (!(flags & (MBX_ERROR | MBX_WARNING))) { + box.setIcon(QMessageBox::Warning); + } + box.setTextFormat(Qt::TextFormat::RichText); + box.exec(); + if (cpu_thread_run == 0) QApplication::exit(-1); +} + +void MainWindow::keyPressEvent(QKeyEvent* event) +{ + if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen)) + { + // Windows keys in Qt have one-to-one mapping. + if (event->key() == Qt::Key_Super_L || event->key() == Qt::Key_Super_R) { + keyboard_input(1, event->key() == Qt::Key_Super_L ? 0x15B : 0x15C); + } else +#ifdef Q_OS_MACOS + processMacKeyboardInput(true, event); +#else + keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode())); +#endif + } + + if ((video_fullscreen > 0) && keyboard_isfsexit()) { + ui->actionFullscreen->trigger(); + } + + if (keyboard_ismsexit()) { + plat_mouse_capture(0); + } + event->accept(); +} + +void MainWindow::blitToWidget(int x, int y, int w, int h, int monitor_index) +{ + if (monitor_index >= 1) { + if (renderers[monitor_index]) renderers[monitor_index]->blit(x, y, w, h); + else video_blit_complete_monitor(monitor_index); + } + else ui->stackedWidget->blit(x, y, w, h); +} + +void MainWindow::keyReleaseEvent(QKeyEvent* event) +{ + if (!send_keyboard_input) + return; + + if (event->key() == Qt::Key_Super_L || event->key() == Qt::Key_Super_R) { + keyboard_input(0, event->key() == Qt::Key_Super_L ? 0x15B : 0x15C); + } else +#ifdef Q_OS_MACOS + processMacKeyboardInput(false, event); +#else + keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode())); +#endif +} + +QSize MainWindow::getRenderWidgetSize() +{ + return ui->stackedWidget->size(); +} + +void MainWindow::focusInEvent(QFocusEvent* event) +{ + this->grabKeyboard(); +} + +void MainWindow::focusOutEvent(QFocusEvent* event) +{ + this->releaseKeyboard(); +} + +void MainWindow::on_actionResizable_window_triggered(bool checked) { + if (checked) { + vid_resize = 1; + setWindowFlag(Qt::WindowMaximizeButtonHint); + setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, false); + setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + for (int i = 1; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) { + renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint); + renderers[i]->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + } + } + } else { + vid_resize = 0; + setWindowFlag(Qt::WindowMaximizeButtonHint, false); + setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); + for (int i = 1; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) { + renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint, false); + emit resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); + } + } + } + show(); + ui->menuWindow_scale_factor->setEnabled(! checked); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api); + for (int i = 1; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer && show_second_monitors) { + renderers[i]->show(); + renderers[i]->switchRenderer((RendererStack::Renderer)vid_api); + QApplication::processEvents(); + } + } +} + +static void +video_toggle_option(QAction* action, int *val) +{ + startblit(); + *val ^= 1; + video_copy = (video_grayscale || invert_display) ? video_transform_copy : memcpy; + action->setChecked(*val > 0 ? true : false); + endblit(); + config_save(); + device_force_redraw(); + for (int i = 0; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) video_force_resize_set_monitor(1, i); + } +} + +void MainWindow::on_actionInverted_VGA_monitor_triggered() { + video_toggle_option(ui->actionInverted_VGA_monitor, &invert_display); +} + +static void update_scaled_checkboxes(Ui::MainWindow* ui, QAction* selected) { + ui->action0_5x->setChecked(ui->action0_5x == selected); + ui->action1x->setChecked(ui->action1x == selected); + ui->action1_5x->setChecked(ui->action1_5x == selected); + ui->action2x->setChecked(ui->action2x == selected); + + reset_screen_size(); + device_force_redraw(); + for (int i = 0; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) video_force_resize_set_monitor(1, i); + } + config_save(); +} + +void MainWindow::on_action0_5x_triggered() { + scale = 0; + update_scaled_checkboxes(ui, ui->action0_5x); +} + +void MainWindow::on_action1x_triggered() { + scale = 1; + update_scaled_checkboxes(ui, ui->action1x); +} + +void MainWindow::on_action1_5x_triggered() { + scale = 2; + update_scaled_checkboxes(ui, ui->action1_5x); +} + +void MainWindow::on_action2x_triggered() { + scale = 3; + update_scaled_checkboxes(ui, ui->action2x); +} + +void MainWindow::on_actionNearest_triggered() { + video_filter_method = 0; + ui->actionLinear->setChecked(false); +} + +void MainWindow::on_actionLinear_triggered() { + video_filter_method = 1; + ui->actionNearest->setChecked(false); +} + +static void update_fullscreen_scale_checkboxes(Ui::MainWindow* ui, QAction* selected) { + ui->actionFullScreen_stretch->setChecked(ui->actionFullScreen_stretch == selected); + ui->actionFullScreen_43->setChecked(ui->actionFullScreen_43 == selected); + ui->actionFullScreen_keepRatio->setChecked(ui->actionFullScreen_keepRatio == selected); + ui->actionFullScreen_int->setChecked(ui->actionFullScreen_int == selected); + + if (video_fullscreen > 0) { + auto widget = ui->stackedWidget->currentWidget(); + ui->stackedWidget->onResize(widget->width(), widget->height()); + } + + device_force_redraw(); + config_save(); +} + +void MainWindow::on_actionFullScreen_stretch_triggered() { + video_fullscreen_scale = FULLSCR_SCALE_FULL; + update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_stretch); +} + +void MainWindow::on_actionFullScreen_43_triggered() { + video_fullscreen_scale = FULLSCR_SCALE_43; + update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_43); +} + +void MainWindow::on_actionFullScreen_keepRatio_triggered() { + video_fullscreen_scale = FULLSCR_SCALE_KEEPRATIO; + update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_keepRatio); +} + +void MainWindow::on_actionFullScreen_int_triggered() { + video_fullscreen_scale = FULLSCR_SCALE_INT; + update_fullscreen_scale_checkboxes(ui, ui->actionFullScreen_int); +} + +static void update_greyscale_checkboxes(Ui::MainWindow* ui, QAction* selected, int value) { + ui->actionRGB_Color->setChecked(ui->actionRGB_Color == selected); + ui->actionRGB_Grayscale->setChecked(ui->actionRGB_Grayscale == selected); + ui->actionAmber_monitor->setChecked(ui->actionAmber_monitor == selected); + ui->actionGreen_monitor->setChecked(ui->actionGreen_monitor == selected); + ui->actionWhite_monitor->setChecked(ui->actionWhite_monitor == selected); + + startblit(); + video_grayscale = value; + video_copy = (video_grayscale || invert_display) ? video_transform_copy : memcpy; + endblit(); + device_force_redraw(); + config_save(); +} + +void MainWindow::on_actionRGB_Color_triggered() { + update_greyscale_checkboxes(ui, ui->actionRGB_Color, 0); +} + +void MainWindow::on_actionRGB_Grayscale_triggered() { + update_greyscale_checkboxes(ui, ui->actionRGB_Grayscale, 1); +} + +void MainWindow::on_actionAmber_monitor_triggered() { + update_greyscale_checkboxes(ui, ui->actionAmber_monitor, 2); +} + +void MainWindow::on_actionGreen_monitor_triggered() { + update_greyscale_checkboxes(ui, ui->actionGreen_monitor, 3); +} + +void MainWindow::on_actionWhite_monitor_triggered() { + update_greyscale_checkboxes(ui, ui->actionWhite_monitor, 4); +} + +static void update_greyscale_type_checkboxes(Ui::MainWindow* ui, QAction* selected, int value) { + ui->actionBT601_NTSC_PAL->setChecked(ui->actionBT601_NTSC_PAL == selected); + ui->actionBT709_HDTV->setChecked(ui->actionBT709_HDTV == selected); + ui->actionAverage->setChecked(ui->actionAverage == selected); + + video_graytype = value; + device_force_redraw(); + config_save(); +} + +void MainWindow::on_actionBT601_NTSC_PAL_triggered() { + update_greyscale_type_checkboxes(ui, ui->actionBT601_NTSC_PAL, 0); +} + +void MainWindow::on_actionBT709_HDTV_triggered() { + update_greyscale_type_checkboxes(ui, ui->actionBT709_HDTV, 1); +} + +void MainWindow::on_actionAverage_triggered() { + update_greyscale_type_checkboxes(ui, ui->actionAverage, 2); +} + +void MainWindow::on_actionAbout_Qt_triggered() +{ + QApplication::aboutQt(); +} + +void MainWindow::on_actionAbout_86Box_triggered() +{ + QMessageBox msgBox; + msgBox.setTextFormat(Qt::RichText); + QString githash; +#ifdef EMU_GIT_HASH + githash = QString(" [%1]").arg(EMU_GIT_HASH); +#endif + msgBox.setText(QString("%3%1%2").arg(EMU_VERSION_FULL, githash, tr("86Box v"))); + msgBox.setInformativeText(tr("An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information.")); + msgBox.setWindowTitle("About 86Box"); + msgBox.addButton("OK", QMessageBox::ButtonRole::AcceptRole); + auto webSiteButton = msgBox.addButton(EMU_SITE, QMessageBox::ButtonRole::HelpRole); + webSiteButton->connect(webSiteButton, &QPushButton::released, []() + { + QDesktopServices::openUrl(QUrl("https://" EMU_SITE)); + }); +#ifdef RELEASE_BUILD + msgBox.setIconPixmap(QIcon(":/settings/win/icons/86Box-green.ico").pixmap(32, 32)); +#elif defined ALPHA_BUILD + msgBox.setIconPixmap(QIcon(":/settings/win/icons/86Box-red.ico").pixmap(32, 32)); +#elif defined BETA_BUILD + msgBox.setIconPixmap(QIcon(":/settings/win/icons/86Box-yellow.ico").pixmap(32, 32)); +#else + msgBox.setIconPixmap(QIcon(":/settings/win/icons/86Box-gray.ico").pixmap(32, 32)); +#endif + msgBox.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + msgBox.exec(); +} + +void MainWindow::on_actionDocumentation_triggered() +{ + QDesktopServices::openUrl(QUrl(EMU_DOCS_URL)); +} + +void MainWindow::on_actionCGA_PCjr_Tandy_EGA_S_VGA_overscan_triggered() { + update_overscan = 1; + video_toggle_option(ui->actionCGA_PCjr_Tandy_EGA_S_VGA_overscan, &enable_overscan); +} + +void MainWindow::on_actionChange_contrast_for_monochrome_display_triggered() { + vid_cga_contrast ^= 1; + cgapal_rebuild(); + config_save(); +} + +void MainWindow::on_actionForce_4_3_display_ratio_triggered() { + video_toggle_option(ui->actionForce_4_3_display_ratio, &force_43); +} + +void MainWindow::on_actionRemember_size_and_position_triggered() +{ + window_remember ^= 1; + window_w = ui->stackedWidget->width(); + window_h = ui->stackedWidget->height(); + if (!QApplication::platformName().contains("wayland")) { + window_x = geometry().x(); + window_y = geometry().y(); + } + for (int i = 1; i < MONITORS_NUM; i++) { + if (window_remember && renderers[i]) { + monitor_settings[i].mon_window_w = renderers[i]->geometry().width(); + monitor_settings[i].mon_window_h = renderers[i]->geometry().height(); + monitor_settings[i].mon_window_x = renderers[i]->geometry().x(); + monitor_settings[i].mon_window_y = renderers[i]->geometry().y(); + } + } + ui->actionRemember_size_and_position->setChecked(window_remember); +} + +void MainWindow::on_actionSpecify_dimensions_triggered() +{ + SpecifyDimensions dialog(this); + dialog.setWindowModality(Qt::WindowModal); + dialog.exec(); +} + +void MainWindow::on_actionHiDPI_scaling_triggered() +{ + dpi_scale ^= 1; + ui->actionHiDPI_scaling->setChecked(dpi_scale); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i]) emit resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); + } +} + +void MainWindow::on_actionHide_status_bar_triggered() +{ + hide_status_bar ^= 1; + ui->actionHide_status_bar->setChecked(hide_status_bar); + statusBar()->setVisible(!hide_status_bar); + if (vid_resize >= 2) { + setFixedSize(fixed_size_x, fixed_size_y + + menuBar()->height() + + (hide_status_bar ? 0 : statusBar()->height()) + + (hide_tool_bar ? 0 : ui->toolBar->height())); + } else { + int vid_resize_orig = vid_resize; + vid_resize = 0; + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + vid_resize = vid_resize_orig; + } +} + +void MainWindow::on_actionHide_tool_bar_triggered() +{ + hide_tool_bar ^= 1; + ui->actionHide_tool_bar->setChecked(hide_tool_bar); + ui->toolBar->setVisible(!hide_tool_bar); + if (vid_resize >= 2) { + setFixedSize(fixed_size_x, fixed_size_y + + menuBar()->height() + + (hide_status_bar ? 0 : statusBar()->height()) + + (hide_tool_bar ? 0 : ui->toolBar->height())); + } else { + int vid_resize_orig = vid_resize; + vid_resize = 0; + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + vid_resize = vid_resize_orig; + } +} + +void MainWindow::on_actionUpdate_status_bar_icons_triggered() +{ + update_icons ^= 1; + ui->actionUpdate_status_bar_icons->setChecked(update_icons); +} + +void MainWindow::on_actionTake_screenshot_triggered() +{ + startblit(); + for (int i = 0; i < MONITORS_NUM; i++) + monitors[i].mon_screenshots++; + endblit(); + device_force_redraw(); +} + +void MainWindow::on_actionSound_gain_triggered() +{ + SoundGain gain(this); + gain.exec(); +} + +void MainWindow::setSendKeyboardInput(bool enabled) +{ + send_keyboard_input = enabled; +} + +void MainWindow::on_actionPreferences_triggered() +{ + ProgSettings progsettings(this); + progsettings.exec(); +} + + +void MainWindow::on_actionEnable_Discord_integration_triggered(bool checked) +{ + enable_discord = checked; + if(enable_discord) { + discord_init(); + discord_update_activity(dopause); + } else + discord_close(); +} + +void MainWindow::showSettings() +{ + if (findChild() == nullptr) + ui->actionSettings->trigger(); +} + +void MainWindow::hardReset() +{ + ui->actionHard_Reset->trigger(); +} + +void MainWindow::togglePause() +{ + ui->actionPause->trigger(); +} + +void MainWindow::changeEvent(QEvent* event) +{ +#ifdef Q_OS_WINDOWS + if (event->type() == QEvent::LanguageChange) + { + auto font_name = tr("FONT_NAME"); + auto font_size = tr("FONT_SIZE"); + QApplication::setFont(QFont(font_name, font_size.toInt())); + } +#endif + QWidget::changeEvent(event); +} + +void MainWindow::on_actionRenderer_options_triggered() +{ + auto dlg = ui->stackedWidget->getOptions(this); + + if (dlg) { + if (dlg->exec() == QDialog::Accepted) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); + } + } + } +} + +void MainWindow::on_actionMCA_devices_triggered() +{ + auto dlg = new MCADeviceList(this); + + if (dlg) + dlg->exec(); +} + + +void MainWindow::on_actionShow_non_primary_monitors_triggered() +{ + show_second_monitors ^= 1; + + if (show_second_monitors) { + for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) { + auto& secondaryRenderer = renderers[monitor_index]; + if (!renderers[monitor_index]) continue; + secondaryRenderer->show(); + if (window_remember) { + secondaryRenderer->setGeometry(monitor_settings[monitor_index].mon_window_x < 120 ? 120 : monitor_settings[monitor_index].mon_window_x, + monitor_settings[monitor_index].mon_window_y < 120 ? 120 : monitor_settings[monitor_index].mon_window_y, + monitor_settings[monitor_index].mon_window_w > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_w, + monitor_settings[monitor_index].mon_window_h > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_h); + } + secondaryRenderer->switchRenderer((RendererStack::Renderer)vid_api); + } + } else { + for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) { + auto& secondaryRenderer = renderers[monitor_index]; + if (!renderers[monitor_index]) continue; + secondaryRenderer->hide(); + if (window_remember && renderers[monitor_index]) { + monitor_settings[monitor_index].mon_window_w = renderers[monitor_index]->geometry().width(); + monitor_settings[monitor_index].mon_window_h = renderers[monitor_index]->geometry().height(); + monitor_settings[monitor_index].mon_window_x = renderers[monitor_index]->geometry().x(); + monitor_settings[monitor_index].mon_window_y = renderers[monitor_index]->geometry().y(); + } + } + } +} + diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp new file mode 100644 index 000000000..49300e72b --- /dev/null +++ b/src/qt/qt_mainwindow.hpp @@ -0,0 +1,151 @@ +#ifndef QT_MAINWINDOW_HPP +#define QT_MAINWINDOW_HPP + +#include +#include +#include +#include + +#include +#include + +class MediaMenu; +class RendererStack; + +namespace Ui { +class MainWindow; +} + +class MachineStatus; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + void showMessage(int flags, const QString& header, const QString& message); + void getTitle(wchar_t* title); + void blitToWidget(int x, int y, int w, int h, int monitor_index); + QSize getRenderWidgetSize(); + void setSendKeyboardInput(bool enabled); +signals: + void paint(const QImage& image); + void resizeContents(int w, int h); + void resizeContentsMonitor(int w, int h, int monitor_index); + void pollMouse(); + void statusBarMessage(const QString& msg); + void updateStatusBarPanes(); + void updateStatusBarActivity(int tag, bool active); + void updateStatusBarEmpty(int tag, bool empty); + void updateStatusBarTip(int tag); + void updateMenuResizeOptions(); + void updateWindowRememberOption(); + void initRendererMonitor(int monitor_index); + void destroyRendererMonitor(int monitor_index); + void initRendererMonitorForNonQtThread(int monitor_index); + void destroyRendererMonitorForNonQtThread(int monitor_index); + + void setTitle(const QString& title); + void setFullscreen(bool state); + void setMouseCapture(bool state); + + void showMessageForNonQtThread(int flags, const QString& header, const QString& message); + void getTitleForNonQtThread(wchar_t* title); +public slots: + void showSettings(); + void hardReset(); + void togglePause(); + void initRendererMonitorSlot(int monitor_index); + void destroyRendererMonitorSlot(int monitor_index); +private slots: + void on_actionFullscreen_triggered(); + void on_actionSettings_triggered(); + void on_actionExit_triggered(); + void on_actionPause_triggered(); + void on_actionCtrl_Alt_Del_triggered(); + void on_actionCtrl_Alt_Esc_triggered(); + void on_actionHard_Reset_triggered(); + void on_actionRight_CTRL_is_left_ALT_triggered(); + void on_actionKeyboard_requires_capture_triggered(); + void on_actionResizable_window_triggered(bool checked); + void on_actionInverted_VGA_monitor_triggered(); + void on_action0_5x_triggered(); + void on_action1x_triggered(); + void on_action1_5x_triggered(); + void on_action2x_triggered(); + void on_actionLinear_triggered(); + void on_actionNearest_triggered(); + void on_actionFullScreen_int_triggered(); + void on_actionFullScreen_keepRatio_triggered(); + void on_actionFullScreen_43_triggered(); + void on_actionFullScreen_stretch_triggered(); + void on_actionWhite_monitor_triggered(); + void on_actionGreen_monitor_triggered(); + void on_actionAmber_monitor_triggered(); + void on_actionRGB_Grayscale_triggered(); + void on_actionRGB_Color_triggered(); + void on_actionAverage_triggered(); + void on_actionBT709_HDTV_triggered(); + void on_actionBT601_NTSC_PAL_triggered(); + void on_actionDocumentation_triggered(); + void on_actionAbout_86Box_triggered(); + void on_actionAbout_Qt_triggered(); + void on_actionForce_4_3_display_ratio_triggered(); + void on_actionChange_contrast_for_monochrome_display_triggered(); + void on_actionCGA_PCjr_Tandy_EGA_S_VGA_overscan_triggered(); + void on_actionRemember_size_and_position_triggered(); + void on_actionSpecify_dimensions_triggered(); + void on_actionHiDPI_scaling_triggered(); + void on_actionHide_status_bar_triggered(); + void on_actionHide_tool_bar_triggered(); + void on_actionUpdate_status_bar_icons_triggered(); + void on_actionTake_screenshot_triggered(); + void on_actionSound_gain_triggered(); + void on_actionPreferences_triggered(); + void on_actionEnable_Discord_integration_triggered(bool checked); + void on_actionRenderer_options_triggered(); + + void refreshMediaMenu(); + void showMessage_(int flags, const QString& header, const QString& message); + void getTitle_(wchar_t* title); + + void on_actionMCA_devices_triggered(); + +protected: + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; + void focusInEvent(QFocusEvent* event) override; + void focusOutEvent(QFocusEvent* event) override; + bool eventFilter(QObject* receiver, QEvent* event) override; + void showEvent(QShowEvent* event) override; + void closeEvent(QCloseEvent* event) override; + void changeEvent(QEvent* event) override; + +private slots: + void on_actionShow_non_primary_monitors_triggered(); + +private: + Ui::MainWindow *ui; + std::unique_ptr status; + std::array, 8> renderers; + std::shared_ptr mm; + +#ifdef Q_OS_MACOS + uint32_t last_modifiers = 0; + void processMacKeyboardInput(bool down, const QKeyEvent* event); +#endif + + /* If main window should send keyboard input */ + bool send_keyboard_input = true; + bool shownonce = false; + bool resizableonce = false; + + friend class SpecifyDimensions; + friend class ProgSettings; + friend class RendererCommon; +}; + +#endif // QT_MAINWINDOW_HPP diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui new file mode 100644 index 000000000..f077f7e97 --- /dev/null +++ b/src/qt/qt_mainwindow.ui @@ -0,0 +1,782 @@ + + + MainWindow + + + + 0 + 0 + 724 + 427 + + + + 86Box + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + + 0 + 0 + 724 + 23 + + + + + &Action + + + + + + + + + + + + + + + + &Tools + + + + + + + + + + + + + + + + + + + &View + + + + Re&nderer + + + + + + + + + + + &Window scale factor + + + + + + + + + Filter method + + + + + + + Fullscreen &stretch mode + + + + + + + + + E&GA/(S)VGA settings + + + + VGA screen &type + + + + + + + + + + Grayscale &conversion type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &Media + + + + + &Help + + + + + + + + + + + + + + + Qt::PreventContextMenu + + + toolBar + + + false + + + Qt::TopToolBarArea + + + + 16 + 16 + + + + Qt::ToolButtonIconOnly + + + false + + + TopToolBarArea + + + false + + + + + + + + + + + + + true + + + &Keyboard requires capture + + + + + true + + + &Right CTRL is left ALT + + + + + + :/menuicons/win/icons/hard_reset.ico:/menuicons/win/icons/hard_reset.ico + + + &Hard Reset... + + + false + + + + + + :/menuicons/win/icons/send_cad.ico:/menuicons/win/icons/send_cad.ico + + + &Ctrl+Alt+Del + + + Ctrl+Alt+Del + + + Ctrl+F12 + + + false + + + false + + + + + + :/menuicons/win/icons/send_cae.ico:/menuicons/win/icons/send_cae.ico + + + Ctrl+Alt+&Esc + + + false + + + + + true + + + + :/menuicons/win/icons/pause.ico:/menuicons/win/icons/pause.ico + + + &Pause + + + false + + + + + Exit + + + + + + :/menuicons/win/icons/settings.ico:/menuicons/win/icons/settings.ico + + + &Settings... + + + QAction::NoRole + + + false + + + + + &Fullscreen + + + Ctrl+Alt+PgUp + + + false + + + + + true + + + &Qt (Software) + + + 0 + + + + + true + + + Qt (&OpenGL) + + + 1 + + + + + true + + + Qt (OpenGL &ES) + + + 2 + + + + + true + + + &Hide status bar + + + + + true + + + &Resizeable window + + + + + true + + + R&emember size && position + + + + + Specify dimensions... + + + + + true + + + F&orce 4:3 display ratio + + + + + true + + + Hi&DPI scaling + + + + + true + + + CGA/PCjr/Tandy/E&GA/(S)VGA overscan + + + + + true + + + Change contrast for &monochrome display + + + + + true + + + &0.5x + + + + + true + + + &1x + + + + + true + + + 1.&5x + + + + + true + + + &2x + + + + + true + + + &Nearest + + + + + true + + + &Linear + + + + + true + + + &Full screen stretch + + + + + true + + + &4:3 + + + + + true + + + &Square pixels (Keep ratio) + + + + + true + + + &Integer scale + + + + + true + + + &Inverted VGA monitor + + + + + true + + + RGB &Color + + + + + true + + + &RGB Grayscale + + + + + true + + + &Amber monitor + + + + + true + + + &Green monitor + + + + + true + + + &White monitor + + + + + true + + + BT&601 (NTSC/PAL) + + + + + true + + + BT&709 (HDTV) + + + + + true + + + &Average + + + + + About Qt + + + false + + + QAction::AboutQtRole + + + + + &About 86Box... + + + QAction::AboutRole + + + + + &Documentation... + + + + + true + + + &Update status bar icons + + + + + Take s&creenshot + + + Ctrl+F11 + + + false + + + + + Sound &gain... + + + + + true + + + Open&GL (3.0 Core) + + + 3 + + + + + &Preferences... + + + QAction::PreferencesRole + + + + + true + + + Enable &Discord integration + + + + + true + + + Hide &toolbar + + + Hide tool bar + + + + + false + + + + :/menuicons/win/icons/acpi_shutdown.ico:/menuicons/win/icons/acpi_shutdown.ico + + + ACPI Shutdown + + + ACPI Shutdown + + + false + + + + + Begin trace + + + Ctrl+T + + + false + + + false + + + + + End trace + + + Ctrl+T + + + false + + + false + + + + + Renderer options... + + + + + true + + + &Vulkan + + + 4 + + + + + MCA devices... + + + + + true + + + Direct3D 9 + + + 5 + + + + + true + + + Show non-primary monitors + + + + + + RendererStack + QStackedWidget +
qt_rendererstack.hpp
+ 1 +
+
+ + + + +
diff --git a/src/qt/qt_mcadevicelist.cpp b/src/qt/qt_mcadevicelist.cpp new file mode 100644 index 000000000..f1a39e358 --- /dev/null +++ b/src/qt/qt_mcadevicelist.cpp @@ -0,0 +1,42 @@ +#include "qt_mcadevicelist.hpp" +#include "ui_qt_mcadevicelist.h" + +extern "C" +{ +#include <86box/86box.h> +#include <86box/video.h> +#include <86box/mca.h> +#include <86box/plat.h> +} + +MCADeviceList::MCADeviceList(QWidget *parent) : + QDialog(parent), + ui(new Ui::MCADeviceList) +{ + ui->setupUi(this); + + startblit(); + if (mca_get_nr_cards() == 0) + { + ui->listWidget->addItem(QObject::tr("No MCA devices.")); + ui->listWidget->setDisabled(true); + } + else + { + for (int i = 0; i < mca_get_nr_cards(); i++) + { + uint32_t deviceId = (mca_read_index(0x00, i) | (mca_read_index(0x01, i) << 8)); + if (deviceId != 0xFFFF) + { + QString hexRepresentation = QString::number(deviceId, 16).toUpper(); + ui->listWidget->addItem(QString("Slot %1: 0x%2 (@%3.ADF)").arg(i + 1).arg(hexRepresentation, hexRepresentation)); + } + } + } + endblit(); +} + +MCADeviceList::~MCADeviceList() +{ + delete ui; +} diff --git a/src/qt/qt_mcadevicelist.hpp b/src/qt/qt_mcadevicelist.hpp new file mode 100644 index 000000000..e45992519 --- /dev/null +++ b/src/qt/qt_mcadevicelist.hpp @@ -0,0 +1,22 @@ +#ifndef QT_MCADEVICELIST_HPP +#define QT_MCADEVICELIST_HPP + +#include + +namespace Ui { +class MCADeviceList; +} + +class MCADeviceList : public QDialog +{ + Q_OBJECT + +public: + explicit MCADeviceList(QWidget *parent = nullptr); + ~MCADeviceList(); + +private: + Ui::MCADeviceList *ui; +}; + +#endif // QT_MCADEVICELIST_HPP diff --git a/src/qt/qt_mcadevicelist.ui b/src/qt/qt_mcadevicelist.ui new file mode 100644 index 000000000..2efac1886 --- /dev/null +++ b/src/qt/qt_mcadevicelist.ui @@ -0,0 +1,74 @@ + + + MCADeviceList + + + + 0 + 0 + 400 + 300 + + + + MCA devices + + + + + + List of MCA devices: + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + MCADeviceList + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MCADeviceList + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp new file mode 100644 index 000000000..ebfe68bef --- /dev/null +++ b/src/qt/qt_mediamenu.cpp @@ -0,0 +1,679 @@ +/* + * 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. + * + * Media menu UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021-2022 Teemu Korhonen + */ +#include "qt_mediamenu.hpp" + +#include "qt_machinestatus.hpp" + +#include +#include +#include +#include + +extern "C" { +#include <86box/config.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/plat.h> +#include <86box/cassette.h> +#include <86box/machine.h> +#include <86box/cartridge.h> +#include <86box/fdd.h> +#include <86box/fdd_86f.h> +#include <86box/cdrom.h> +#include <86box/scsi_device.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/sound.h> +#include <86box/ui.h> +}; + +#include "qt_newfloppydialog.hpp" +#include "qt_util.hpp" + +std::shared_ptr MediaMenu::ptr; + +MediaMenu::MediaMenu(QWidget* parent) : QObject(parent) { + parentWidget = parent; +} + +void MediaMenu::refresh(QMenu *parentMenu) { + parentMenu->clear(); + + if(MachineStatus::hasCassette()) { + cassetteMenu = parentMenu->addMenu(""); + cassetteMenu->addAction(tr("&New image..."), [this]() { cassetteNewImage(); }); + cassetteMenu->addSeparator(); + cassetteMenu->addAction(tr("&Existing image..."), [this]() { cassetteSelectImage(false); }); + cassetteMenu->addAction(tr("Existing image (&Write-protected)..."), [this]() { cassetteSelectImage(true); }); + cassetteMenu->addSeparator(); + cassetteRecordPos = cassetteMenu->children().count(); + cassetteMenu->addAction(tr("&Record"), [this] { pc_cas_set_mode(cassette, 1); cassetteUpdateMenu(); })->setCheckable(true); + cassettePlayPos = cassetteMenu->children().count(); + cassetteMenu->addAction(tr("&Play"), [this] { pc_cas_set_mode(cassette, 0); cassetteUpdateMenu(); })->setCheckable(true); + cassetteRewindPos = cassetteMenu->children().count(); + cassetteMenu->addAction(tr("&Rewind to the beginning"), [] { pc_cas_rewind(cassette); }); + cassetteFastFwdPos = cassetteMenu->children().count(); + cassetteMenu->addAction(tr("&Fast forward to the end"), [] { pc_cas_append(cassette); }); + cassetteMenu->addSeparator(); + cassetteEjectPos = cassetteMenu->children().count(); + cassetteMenu->addAction(tr("E&ject"), [this]() { cassetteEject(); }); + cassetteUpdateMenu(); + } + + cartridgeMenus.clear(); + if (machine_has_cartridge(machine)) { + for(int i = 0; i < 2; i++) { + auto* menu = parentMenu->addMenu(""); + menu->addAction(tr("&Image..."), [this, i]() { cartridgeSelectImage(i); }); + menu->addSeparator(); + cartridgeEjectPos = menu->children().count(); + menu->addAction(tr("E&ject"), [this, i]() { cartridgeEject(i); }); + cartridgeMenus[i] = menu; + cartridgeUpdateMenu(i); + } + } + + floppyMenus.clear(); + MachineStatus::iterateFDD([this, parentMenu](int i) { + auto* menu = parentMenu->addMenu(""); + menu->addAction(tr("&New image..."), [this, i]() { floppyNewImage(i); }); + menu->addSeparator(); + menu->addAction(tr("&Existing image..."), [this, i]() { floppySelectImage(i, false); }); + menu->addAction(tr("Existing image (&Write-protected)..."), [this, i]() { floppySelectImage(i, true); }); + menu->addSeparator(); + floppyExportPos = menu->children().count(); + menu->addAction(tr("E&xport to 86F..."), [this, i]() { floppyExportTo86f(i); }); + menu->addSeparator(); + floppyEjectPos = menu->children().count(); + menu->addAction(tr("E&ject"), [this, i]() { floppyEject(i); }); + floppyMenus[i] = menu; + floppyUpdateMenu(i); + }); + + cdromMenus.clear(); + MachineStatus::iterateCDROM([this, parentMenu](int i) { + auto* menu = parentMenu->addMenu(""); + cdromMutePos = menu->children().count(); + menu->addAction(tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true); + menu->addSeparator(); + cdromEmptyPos = menu->children().count(); + menu->addAction(tr("E&mpty"), [this, i]() { cdromEject(i); })->setCheckable(true); + cdromReloadPos = menu->children().count(); + menu->addAction(tr("&Reload previous image"), [this, i]() { cdromReload(i); }); + menu->addSeparator(); + cdromImagePos = menu->children().count(); + menu->addAction(tr("&Image"), [this, i]() { cdromMount(i); })->setCheckable(true); + cdromMenus[i] = menu; + cdromUpdateMenu(i); + }); + + zipMenus.clear(); + MachineStatus::iterateZIP([this, parentMenu](int i) { + auto* menu = parentMenu->addMenu(""); + menu->addAction(tr("&New image..."), [this, i]() { zipNewImage(i); }); + menu->addSeparator(); + menu->addAction(tr("&Existing image..."), [this, i]() { zipSelectImage(i, false); }); + menu->addAction(tr("Existing image (&Write-protected)..."), [this, i]() { zipSelectImage(i, true); }); + menu->addSeparator(); + zipEjectPos = menu->children().count(); + menu->addAction(tr("E&ject"), [this, i]() { zipEject(i); }); + zipReloadPos = menu->children().count(); + menu->addAction(tr("&Reload previous image"), [this, i]() { zipReload(i); }); + zipMenus[i] = menu; + zipUpdateMenu(i); + }); + + moMenus.clear(); + MachineStatus::iterateMO([this, parentMenu](int i) { + auto* menu = parentMenu->addMenu(""); + menu->addAction(tr("&New image..."), [this, i]() { moNewImage(i); }); + menu->addSeparator(); + menu->addAction(tr("&Existing image..."), [this, i]() { moSelectImage(i, false); }); + menu->addAction(tr("Existing image (&Write-protected)..."), [this, i]() { moSelectImage(i, true); }); + menu->addSeparator(); + moEjectPos = menu->children().count(); + menu->addAction(tr("E&ject"), [this, i]() { moEject(i); }); + moReloadPos = menu->children().count(); + menu->addAction(tr("&Reload previous image"), [this, i]() { moReload(i); }); + moMenus[i] = menu; + moUpdateMenu(i); + }); +} + +void MediaMenu::cassetteNewImage() { + auto filename = QFileDialog::getSaveFileName(parentWidget, tr("Create...")); + QFileInfo fileinfo(filename); + if (fileinfo.suffix().isEmpty()) { + filename.append(".cas"); + } + if (!filename.isNull()) { + if (filename.isEmpty()) cassetteEject(); + else cassetteMount(filename, false); + } +} + +void MediaMenu::cassetteSelectImage(bool wp) { + auto filename = QFileDialog::getOpenFileName(parentWidget, + QString(), + QString(), + tr("Cassette images") % + util::DlgFilter({ "pcm","raw","wav","cas" }) % + tr("All files") % + util::DlgFilter({ "*" }, true)); + + if (!filename.isEmpty()) cassetteMount(filename, wp); +} + +void MediaMenu::cassetteMount(const QString& filename, bool wp) { + pc_cas_set_fname(cassette, nullptr); + memset(cassette_fname, 0, sizeof(cassette_fname)); + cassette_ui_writeprot = wp ? 1 : 0; + + if (! filename.isEmpty()) { + QByteArray filenameBytes = filename.toUtf8(); + strncpy(cassette_fname, filenameBytes.data(), sizeof(cassette_fname) - 1); + pc_cas_set_fname(cassette, cassette_fname); + } + + ui_sb_update_icon_state(SB_CASSETTE, filename.isEmpty() ? 1 : 0); + cassetteUpdateMenu(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + +void MediaMenu::cassetteEject() { + pc_cas_set_fname(cassette, nullptr); + memset(cassette_fname, 0, sizeof(cassette_fname)); + ui_sb_update_icon_state(SB_CASSETTE, 1); + cassetteUpdateMenu(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + +void MediaMenu::cassetteUpdateMenu() { + QString name = cassette_fname; + QString mode = cassette_mode; + auto childs = cassetteMenu->children(); + auto* recordMenu = dynamic_cast(childs[cassetteRecordPos]); + auto* playMenu = dynamic_cast(childs[cassettePlayPos]); + auto* rewindMenu = dynamic_cast(childs[cassetteRewindPos]); + auto* fastFwdMenu = dynamic_cast(childs[cassetteFastFwdPos]); + auto* ejectMenu = dynamic_cast(childs[cassetteEjectPos]); + + recordMenu->setEnabled(!name.isEmpty()); + playMenu->setEnabled(!name.isEmpty()); + rewindMenu->setEnabled(!name.isEmpty()); + fastFwdMenu->setEnabled(!name.isEmpty()); + ejectMenu->setEnabled(!name.isEmpty()); + + bool isSaving = mode == QStringLiteral("save"); + recordMenu->setChecked(isSaving); + playMenu->setChecked(! isSaving); + + cassetteMenu->setTitle(QString::asprintf(tr("Cassette: %s").toUtf8().constData(), (name.isEmpty() ? tr("(empty)") : name).toUtf8().constData())); +} + +void MediaMenu::cartridgeMount(int i, const QString &filename) +{ + cart_close(i); + QByteArray filenameBytes = filename.toUtf8(); + cart_load(i, filenameBytes.data()); + + ui_sb_update_icon_state(SB_CARTRIDGE | i, filename.isEmpty() ? 1 : 0); + cartridgeUpdateMenu(i); + ui_sb_update_tip(SB_CARTRIDGE | i); + config_save(); +} + +void MediaMenu::cartridgeSelectImage(int i) { + auto filename = QFileDialog::getOpenFileName( + parentWidget, + QString(), + QString(), + tr("Cartridge images") % + util::DlgFilter({ "a","b","jrc" }) % + tr("All files") % + util::DlgFilter({ "*" }, true)); + + if (filename.isEmpty()) { + return; + } + cartridgeMount(i, filename); +} + +void MediaMenu::cartridgeEject(int i) { + cart_close(i); + ui_sb_update_icon_state(SB_CARTRIDGE | i, 1); + cartridgeUpdateMenu(i); + ui_sb_update_tip(SB_CARTRIDGE | i); + config_save(); +} + +void MediaMenu::cartridgeUpdateMenu(int i) { + QString name = cart_fns[i]; + auto* menu = cartridgeMenus[i]; + auto childs = menu->children(); + auto* ejectMenu = dynamic_cast(childs[cartridgeEjectPos]); + ejectMenu->setEnabled(!name.isEmpty()); + //menu->setTitle(tr("Cartridge %1: %2").arg(QString::number(i+1), name.isEmpty() ? tr("(empty)") : name)); + menu->setTitle(QString::asprintf(tr("Cartridge %i: %ls").toUtf8().constData(), i + 1, name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); +} + +void MediaMenu::floppyNewImage(int i) { + NewFloppyDialog dialog(NewFloppyDialog::MediaType::Floppy, parentWidget); + switch (dialog.exec()) { + case QDialog::Accepted: + QByteArray filename = dialog.fileName().toUtf8(); + floppyMount(i, filename, false); + break; + } +} + +void MediaMenu::floppySelectImage(int i, bool wp) { + auto filename = QFileDialog::getOpenFileName( + parentWidget, + QString(), + QString(), + tr("All images") % + util::DlgFilter({ "0??","1??","??0","86f","bin","cq?","d??","flp","hdm","im?","json","td0","*fd?","mfm","xdf" }) % + tr("Advanced sector images") % + util::DlgFilter({ "imd","json","td0" }) % + tr("Basic sector images") % + util::DlgFilter({ "0??","1??","??0","bin","cq?","d??","flp","hdm","im?","xdf","*fd?" }) % + tr("Flux images") % + util::DlgFilter({ "fdi" }) % + tr("Surface images") % + util::DlgFilter({ "86f","mfm" }) % + tr("All files") % + util::DlgFilter({ "*" }, true)); + + if (!filename.isEmpty()) floppyMount(i, filename, wp); +} + +void MediaMenu::floppyMount(int i, const QString &filename, bool wp) { + fdd_close(i); + ui_writeprot[i] = wp ? 1 : 0; + if (! filename.isEmpty()) { + QByteArray filenameBytes = filename.toUtf8(); + fdd_load(i, filenameBytes.data()); + } + ui_sb_update_icon_state(SB_FLOPPY | i, filename.isEmpty() ? 1 : 0); + floppyUpdateMenu(i); + ui_sb_update_tip(SB_FLOPPY | i); + config_save(); +} + +void MediaMenu::floppyEject(int i) { + fdd_close(i); + ui_sb_update_icon_state(SB_FLOPPY | i, 1); + floppyUpdateMenu(i); + ui_sb_update_tip(SB_FLOPPY | i); + config_save(); +} + +void MediaMenu::floppyExportTo86f(int i) { + auto filename = QFileDialog::getSaveFileName(parentWidget, QString(), QString(), tr("Surface images") % util::DlgFilter({ "86f" }, true)); + if (! filename.isEmpty()) { + QByteArray filenameBytes = filename.toUtf8(); + plat_pause(1); + if (d86f_export(i, filenameBytes.data()) == 0) { + QMessageBox::critical(parentWidget, tr("Unable to write file"), tr("Make sure the file is being saved to a writable directory")); + } + plat_pause(0); + } +} + +void MediaMenu::floppyUpdateMenu(int i) { + QString name = floppyfns[i]; + + if (!floppyMenus.contains(i)) + return; + + auto* menu = floppyMenus[i]; + auto childs = menu->children(); + + auto* ejectMenu = dynamic_cast(childs[floppyEjectPos]); + auto* exportMenu = dynamic_cast(childs[floppyExportPos]); + ejectMenu->setEnabled(!name.isEmpty()); + exportMenu->setEnabled(!name.isEmpty()); + + int type = fdd_get_type(i); + //floppyMenus[i]->setTitle(tr("Floppy %1 (%2): %3").arg(QString::number(i+1), fdd_getname(type), name.isEmpty() ? tr("(empty)") : name)); + floppyMenus[i]->setTitle(QString::asprintf(tr("Floppy %i (%s): %ls").toUtf8().constData(), i + 1, fdd_getname(type), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); +} + +void MediaMenu::cdromMute(int i) { + cdrom[i].sound_on ^= 1; + config_save(); + cdromUpdateMenu(i); + sound_cd_thread_reset(); +} + +void MediaMenu::cdromMount(int i, const QString &filename) +{ + QByteArray fn = filename.toUtf8().data(); + + cdrom[i].prev_host_drive = cdrom[i].host_drive; + strcpy(cdrom[i].prev_image_path, cdrom[i].image_path); + if (cdrom[i].ops && cdrom[i].ops->exit) + cdrom[i].ops->exit(&(cdrom[i])); + + cdrom[i].ops = nullptr; + memset(cdrom[i].image_path, 0, sizeof(cdrom[i].image_path)); + cdrom_image_open(&(cdrom[i]), fn.data()); + /* Signal media change to the emulated machine. */ + if (cdrom[i].insert) + cdrom[i].insert(cdrom[i].priv); + cdrom[i].host_drive = (strlen(cdrom[i].image_path) == 0) ? 0 : 200; + if (cdrom[i].host_drive == 200) { + ui_sb_update_icon_state(SB_CDROM | i, 0); + } else { + ui_sb_update_icon_state(SB_CDROM | i, 1); + } + cdromUpdateMenu(i); + ui_sb_update_tip(SB_CDROM | i); + config_save(); +} + +void MediaMenu::cdromMount(int i) { + QString dir; + QFileInfo fi(cdrom[i].image_path); + + auto filename = QFileDialog::getOpenFileName( + parentWidget, + QString(), + QString(), + tr("CD-ROM images") % + util::DlgFilter({ "iso","cue" }) % + tr("All files") % + util::DlgFilter({ "*" }, true)); + + if (filename.isEmpty()) { + return; + } + + cdromMount(i, filename); +} + +void MediaMenu::cdromEject(int i) { + cdrom_eject(i); + cdromUpdateMenu(i); + ui_sb_update_tip(SB_CDROM | i); +} + +void MediaMenu::cdromReload(int i) { + cdrom_reload(i); + cdromUpdateMenu(i); + ui_sb_update_tip(SB_CDROM | i); +} + +void MediaMenu::cdromUpdateMenu(int i) { + QString name = cdrom[i].image_path; + if (!cdromMenus.contains(i)) + return; + auto* menu = cdromMenus[i]; + auto childs = menu->children(); + + auto* muteMenu = dynamic_cast(childs[cdromMutePos]); + muteMenu->setChecked(cdrom[i].sound_on == 0); + + auto* imageMenu = dynamic_cast(childs[cdromImagePos]); + auto* emptyMenu = dynamic_cast(childs[cdromEmptyPos]); + imageMenu->setChecked(cdrom[i].host_drive == 200); + emptyMenu->setChecked(cdrom[i].host_drive != 200); + + auto* prevMenu = dynamic_cast(childs[cdromReloadPos]); + prevMenu->setEnabled(cdrom[i].prev_host_drive != 0); + + QString busName = tr("Unknown Bus"); + switch (cdrom[i].bus_type) { + case CDROM_BUS_ATAPI: + busName = "ATAPI"; + break; + case CDROM_BUS_SCSI: + busName = "SCSI"; + break; + } + + //menu->setTitle(tr("CD-ROM %1 (%2): %3").arg(QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name)); + menu->setTitle(QString::asprintf(tr("CD-ROM %i (%s): %s").toUtf8().constData(), i + 1, busName.toUtf8().data(), name.isEmpty() ? tr("(empty)").toUtf8().data() : name.toUtf8().data())); +} + +void MediaMenu::zipNewImage(int i) { + NewFloppyDialog dialog(NewFloppyDialog::MediaType::Zip, parentWidget); + switch (dialog.exec()) { + case QDialog::Accepted: + QByteArray filename = dialog.fileName().toUtf8(); + zipMount(i, filename, false); + break; + } +} + +void MediaMenu::zipSelectImage(int i, bool wp) { + auto filename = QFileDialog::getOpenFileName( + parentWidget, + QString(), + QString(), + tr("ZIP images") % + util::DlgFilter({ "im?","zdi" }) % + tr("All files") % + util::DlgFilter({ "*" }, true)); + + if (!filename.isEmpty()) zipMount(i, filename, wp); +} + +void MediaMenu::zipMount(int i, const QString &filename, bool wp) { + zip_t *dev = (zip_t *) zip_drives[i].priv; + + zip_disk_close(dev); + zip_drives[i].read_only = wp; + if (! filename.isEmpty()) { + QByteArray filenameBytes = filename.toUtf8(); + zip_load(dev, filenameBytes.data()); + zip_insert(dev); + } + + ui_sb_update_icon_state(SB_ZIP | i, filename.isEmpty() ? 1 : 0); + zipUpdateMenu(i); + ui_sb_update_tip(SB_ZIP | i); + + config_save(); +} + +void MediaMenu::zipEject(int i) { + zip_t *dev = (zip_t *) zip_drives[i].priv; + + zip_disk_close(dev); + zip_drives[i].image_path[0] = 0; + if (zip_drives[i].bus_type) { + /* Signal disk change to the emulated machine. */ + zip_insert(dev); + } + + ui_sb_update_icon_state(SB_ZIP | i, 1); + zipUpdateMenu(i); + ui_sb_update_tip(SB_ZIP | i); + config_save(); +} + +void MediaMenu::zipReload(int i) { + zip_t *dev = (zip_t *) zip_drives[i].priv; + + zip_disk_reload(dev); + if (strlen(zip_drives[i].image_path) == 0) { + ui_sb_update_icon_state(SB_ZIP|i, 1); + } else { + ui_sb_update_icon_state(SB_ZIP|i, 0); + } + + zipUpdateMenu(i); + ui_sb_update_tip(SB_ZIP|i); + + config_save(); +} + +void MediaMenu::zipUpdateMenu(int i) { + QString name = zip_drives[i].image_path; + QString prev_name = zip_drives[i].prev_image_path; + if (!zipMenus.contains(i)) + return; + auto* menu = zipMenus[i]; + auto childs = menu->children(); + + auto* ejectMenu = dynamic_cast(childs[zipEjectPos]); + auto* reloadMenu = dynamic_cast(childs[zipReloadPos]); + ejectMenu->setEnabled(!name.isEmpty()); + reloadMenu->setEnabled(!prev_name.isEmpty()); + + QString busName = tr("Unknown Bus"); + switch (zip_drives[i].bus_type) { + case ZIP_BUS_ATAPI: + busName = "ATAPI"; + break; + case ZIP_BUS_SCSI: + busName = "SCSI"; + break; + } + + //menu->setTitle(tr("ZIP %1 %2 (%3): %4").arg((zip_drives[i].is_250 > 0) ? "250" : "100", QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name)); + menu->setTitle(QString::asprintf(tr("ZIP %03i %i (%s): %ls").toUtf8().constData(), (zip_drives[i].is_250 > 0) ? 250 : 100, i + 1, busName.toUtf8().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); +} + +void MediaMenu::moNewImage(int i) { + NewFloppyDialog dialog(NewFloppyDialog::MediaType::Mo, parentWidget); + switch (dialog.exec()) { + case QDialog::Accepted: + QByteArray filename = dialog.fileName().toUtf8(); + moMount(i, filename, false); + break; + } +} + +void MediaMenu::moSelectImage(int i, bool wp) { + auto filename = QFileDialog::getOpenFileName( + parentWidget, + QString(), + QString(), + tr("MO images") % + util::DlgFilter({ "im?", "mdi" }) % + tr("All files") % + util::DlgFilter({ "*", }, true)); + + if (!filename.isEmpty()) moMount(i, filename, wp); +} + +void MediaMenu::moMount(int i, const QString &filename, bool wp) { + mo_t *dev = (mo_t *) mo_drives[i].priv; + + mo_disk_close(dev); + mo_drives[i].read_only = wp; + if (! filename.isEmpty()) { + QByteArray filenameBytes = filename.toUtf8(); + mo_load(dev, filenameBytes.data()); + mo_insert(dev); + } + + ui_sb_update_icon_state(SB_MO | i, filename.isEmpty() ? 1 : 0); + moUpdateMenu(i); + ui_sb_update_tip(SB_MO | i); + + config_save(); +} + +void MediaMenu::moEject(int i) { + mo_t *dev = (mo_t *) mo_drives[i].priv; + + mo_disk_close(dev); + mo_drives[i].image_path[0] = 0; + if (mo_drives[i].bus_type) { + /* Signal disk change to the emulated machine. */ + mo_insert(dev); + } + + ui_sb_update_icon_state(SB_MO | i, 1); + moUpdateMenu(i); + ui_sb_update_tip(SB_MO | i); + config_save(); +} + +void MediaMenu::moReload(int i) { + mo_t *dev = (mo_t *) mo_drives[i].priv; + + mo_disk_reload(dev); + if (strlen(mo_drives[i].image_path) == 0) { + ui_sb_update_icon_state(SB_MO|i, 1); + } else { + ui_sb_update_icon_state(SB_MO|i, 0); + } + + moUpdateMenu(i); + ui_sb_update_tip(SB_MO|i); + + config_save(); +} + +void MediaMenu::moUpdateMenu(int i) { + QString name = mo_drives[i].image_path; + QString prev_name = mo_drives[i].prev_image_path; + if (!moMenus.contains(i)) + return; + auto* menu = moMenus[i]; + auto childs = menu->children(); + + auto* ejectMenu = dynamic_cast(childs[moEjectPos]); + auto* reloadMenu = dynamic_cast(childs[moReloadPos]); + ejectMenu->setEnabled(!name.isEmpty()); + reloadMenu->setEnabled(!prev_name.isEmpty()); + + QString busName = tr("Unknown Bus"); + switch (mo_drives[i].bus_type) { + case MO_BUS_ATAPI: + busName = "ATAPI"; + break; + case MO_BUS_SCSI: + busName = "SCSI"; + break; + } + + menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); +} + + +// callbacks from 86box C code +extern "C" { + +void zip_eject(uint8_t id) { + MediaMenu::ptr->zipEject(id); +} + +void zip_reload(uint8_t id) { + MediaMenu::ptr->zipReload(id); +} + +void mo_eject(uint8_t id) { + MediaMenu::ptr->moEject(id); +} + +void mo_reload(uint8_t id) { + MediaMenu::ptr->moReload(id); +} + +} diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp new file mode 100644 index 000000000..3c45b2414 --- /dev/null +++ b/src/qt/qt_mediamenu.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include + +class QMenu; + +class MediaMenu : QObject +{ + Q_OBJECT +public: + MediaMenu(QWidget* parent); + + void refresh(QMenu* parentMenu); + + // because some 86box C-only code needs to call zip and + // mo eject directly + static std::shared_ptr ptr; + + void cassetteNewImage(); + void cassetteSelectImage(bool wp); + void cassetteMount(const QString& filename, bool wp); + void cassetteEject(); + void cassetteUpdateMenu(); + + void cartridgeSelectImage(int i); + void cartridgeMount(int i, const QString& filename); + void cartridgeEject(int i); + void cartridgeUpdateMenu(int i); + + void floppyNewImage(int i); + void floppySelectImage(int i, bool wp); + void floppyMount(int i, const QString& filename, bool wp); + void floppyEject(int i); + void floppyExportTo86f(int i); + void floppyUpdateMenu(int i); + + void cdromMute(int i); + void cdromMount(int i); + void cdromMount(int i, const QString& filename); + void cdromEject(int i); + void cdromReload(int i); + void cdromUpdateMenu(int i); + + void zipNewImage(int i); + void zipSelectImage(int i, bool wp); + void zipMount(int i, const QString& filename, bool wp); + void zipEject(int i); + void zipReload(int i); + void zipUpdateMenu(int i); + + void moNewImage(int i); + void moSelectImage(int i, bool wp); + void moMount(int i, const QString& filename, bool wp); + void moEject(int i); + void moReload(int i); + void moUpdateMenu(int i); +private: + QWidget* parentWidget = nullptr; + + QMenu* cassetteMenu = nullptr; + QMap cartridgeMenus; + QMap floppyMenus; + QMap cdromMenus; + QMap zipMenus; + QMap moMenus; + + int cassetteRecordPos; + int cassettePlayPos; + int cassetteRewindPos; + int cassetteFastFwdPos; + int cassetteEjectPos; + + int cartridgeEjectPos; + + int floppyExportPos; + int floppyEjectPos; + + int cdromMutePos; + int cdromEmptyPos; + int cdromReloadPos; + int cdromImagePos; + + int zipEjectPos; + int zipReloadPos; + + int moEjectPos; + int moReloadPos; + + friend class MachineStatus; +}; diff --git a/src/qt/qt_midi.cpp b/src/qt/qt_midi.cpp new file mode 100644 index 000000000..a9b741c9e --- /dev/null +++ b/src/qt/qt_midi.cpp @@ -0,0 +1,44 @@ +#include + +extern "C" { + +void plat_midi_play_msg(uint8_t *msg) +{} + +void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{} + +void plat_midi_input_init(void) +{} + +void plat_midi_input_close(void) +{} + +int plat_midi_write(uint8_t val) +{ return 0; } + +void plat_midi_init() +{} + +void plat_midi_close() +{} + +int plat_midi_get_num_devs() +{ return 0; } + +int plat_midi_in_get_num_devs(void) +{ return 0; } + +void plat_midi_get_dev_name(int num, char *s) +{ + s[0] = ' '; + s[1] = 0; +} + +void plat_midi_in_get_dev_name(int num, char *s) +{ + s[0] = ' '; + s[1] = 0; +} + +} diff --git a/src/qt/qt_models_common.cpp b/src/qt/qt_models_common.cpp new file mode 100644 index 000000000..eaa14bc0d --- /dev/null +++ b/src/qt/qt_models_common.cpp @@ -0,0 +1,31 @@ +/* + * 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. + * + * Common storage devices module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_models_common.hpp" + +#include + +int Models::AddEntry(QAbstractItemModel *model, const QString& displayRole, int userRole) +{ + int row = model->rowCount(); + model->insertRow(row); + auto idx = model->index(row, 0); + + model->setData(idx, displayRole, Qt::DisplayRole); + model->setData(idx, userRole, Qt::UserRole); + + return row; +} diff --git a/src/qt/qt_models_common.hpp b/src/qt/qt_models_common.hpp new file mode 100644 index 000000000..91cda3836 --- /dev/null +++ b/src/qt/qt_models_common.hpp @@ -0,0 +1,8 @@ +#pragma once + +class QString; +class QAbstractItemModel; +namespace Models +{ + int AddEntry(QAbstractItemModel* model, const QString& displayRole, int userRole); +}; diff --git a/src/qt/qt_newfloppydialog.cpp b/src/qt/qt_newfloppydialog.cpp new file mode 100644 index 000000000..576798e54 --- /dev/null +++ b/src/qt/qt_newfloppydialog.cpp @@ -0,0 +1,688 @@ +/* + * 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. + * + * Common storage devices module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2022 Cacodemon345 + * Copyright 2022 Teemu Korhonen + */ +#include "qt_newfloppydialog.hpp" +#include "ui_qt_newfloppydialog.h" + +#include "qt_models_common.hpp" +#include "qt_util.hpp" + +extern "C" { +#include <86box/plat.h> +#include <86box/random.h> +#include <86box/scsi_device.h> +#include <86box/zip.h> +#include <86box/mo.h> +} + +#include +#include + +#include +#include +#include +#include +#include +#include + +struct disk_size_t { + int hole; + int sides; + int data_rate; + int encoding; + int rpm; + int tracks; + int sectors; /* For IMG and Japanese FDI only. */ + int sector_len; /* For IMG and Japanese FDI only. */ + int media_desc; + int spc; + int num_fats; + int spfat; + int root_dir_entries; +}; + +static const disk_size_t disk_sizes[14] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xfe, 2, 2, 1, 64 }, /* 160k */ + { 0, 1, 2, 1, 0, 40, 9, 2, 0xfc, 2, 2, 1, 64 }, /* 180k */ + { 0, 2, 2, 1, 0, 40, 8, 2, 0xff, 2, 2, 1, 112 }, /* 320k */ + { 0, 2, 2, 1, 0, 40, 9, 2, 0xfd, 2, 2, 2, 112 }, /* 360k */ + { 0, 2, 2, 1, 0, 80, 8, 2, 0xfb, 2, 2, 2, 112 }, /* 640k */ + { 0, 2, 2, 1, 0, 80, 9, 2, 0xf9, 2, 2, 3, 112 }, /* 720k */ + { 1, 2, 0, 1, 1, 80, 15, 2, 0xf9, 1, 2, 7, 224 }, /* 1.2M */ + { 1, 2, 0, 1, 1, 77, 8, 3, 0xfe, 1, 2, 2, 192 }, /* 1.25M */ + { 1, 2, 0, 1, 0, 80, 18, 2, 0xf0, 1, 2, 9, 224 }, /* 1.44M */ + { 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 2, 2, 5, 16 }, /* DMF cluster 1024 */ + { 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 4, 2, 3, 16 }, /* DMF cluster 2048 */ + { 2, 2, 3, 1, 0, 80, 36, 2, 0xf0, 2, 2, 9, 240 }, /* 2.88M */ + { 0, 64, 0, 0, 0, 96, 32, 2, 0, 0, 0, 0, 0 }, /* ZIP 100 */ + { 0, 64, 0, 0, 0, 239, 32, 2, 0, 0, 0, 0, 0 } }; /* ZIP 250 */ + +static const QStringList rpmModes = { + "Perfect RPM", + "1% below perfect RPM", + "1.5% below perfect RPM", + "2% below perfect RPM", +}; + +static const QStringList floppyTypes = { + "160 kB", + "180 kB", + "320 kB", + "360 kB", + "640 kB", + "720 kB", + "1.2 MB", + "1.25 MB", + "1.44 MB", + "DMF (cluster 1024)", + "DMF (cluster 2048)", + "2.88 MB", +}; + +static const QStringList zipTypes = { + "ZIP 100", + "ZIP 250", +}; + +static const QStringList moTypes = { + "3.5\" 128 MB (ISO 10090)", + "3.5\" 230 MB (ISO 13963)", + "3.5\" 540 MB (ISO 15498)", + "3.5\" 640 MB (ISO 15498)", + "3.5\" 1.3 GB (GigaMO)", + "3.5\" 2.3 GB (GigaMO 2)", + "5.25\" 600 MB", + "5.25\" 650 MB", + "5.25\" 1 GB", + "5.25\" 1.3 GB", +}; + +NewFloppyDialog::NewFloppyDialog(MediaType type, QWidget *parent) : + QDialog(parent), + ui(new Ui::NewFloppyDialog), + mediaType_(type) +{ + ui->setupUi(this); + ui->fileField->setCreateFile(true); + + auto* model = ui->comboBoxSize->model(); + switch (type) { + case MediaType::Floppy: + for (int i = 0; i < floppyTypes.size(); ++i) { + Models::AddEntry(model, tr(floppyTypes[i].toUtf8().data()), i); + } + ui->fileField->setFilter( + tr("All images") % + util::DlgFilter({ "86f","dsk","flp","im?","*fd?" }) % + tr("Basic sector images") % + util::DlgFilter({ "dsk","flp","im?","img","*fd?" }) % + tr("Surface images") % + util::DlgFilter({ "86f" }, true)); + + break; + case MediaType::Zip: + for (int i = 0; i < zipTypes.size(); ++i) { + Models::AddEntry(model, tr(zipTypes[i].toUtf8().data()), i); + } + ui->fileField->setFilter(tr("ZIP images") % util::DlgFilter({ "im?","zdi" }, true)); + break; + case MediaType::Mo: + for (int i = 0; i < moTypes.size(); ++i) { + Models::AddEntry(model, tr(moTypes[i].toUtf8().data()), i); + } + ui->fileField->setFilter(tr("MO images") % util::DlgFilter({ "im?","mdi" }) % tr("All files") % util::DlgFilter({ "*" }, true)); + break; + } + + model = ui->comboBoxRpm->model(); + for (int i = 0; i < rpmModes.size(); ++i) { + Models::AddEntry(model, tr(rpmModes[i].toUtf8().data()), i); + } + + connect(ui->fileField, &FileField::fileSelected, this, [this](const QString& filename) { + bool hide = true; + if (mediaType_ == MediaType::Floppy) { + if (QFileInfo(filename).suffix().toLower() == QStringLiteral("86f")) { + hide = false; + } + } + + ui->labelRpm->setHidden(hide); + ui->comboBoxRpm->setHidden(hide); + }); + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &NewFloppyDialog::onCreate); + + ui->labelRpm->setHidden(true); + ui->comboBoxRpm->setHidden(true); +} + +NewFloppyDialog::~NewFloppyDialog() { + delete ui; +} + +QString NewFloppyDialog::fileName() const{ + return ui->fileField->fileName(); +} + +void NewFloppyDialog::onCreate() { + auto filename = ui->fileField->fileName(); + QFileInfo fi(filename); + FileType fileType; + + QProgressDialog progress("Creating floppy image", QString(), 0, 100, this); + connect(this, &NewFloppyDialog::fileProgress, &progress, &QProgressDialog::setValue); + switch (mediaType_) { + case MediaType::Floppy: + if (fi.suffix().toLower() == QStringLiteral("86f")) { + if (create86f(filename, disk_sizes[ui->comboBoxSize->currentIndex()], ui->comboBoxRpm->currentIndex())) { + return; + } + } else { + fileType = fi.suffix().toLower() == QStringLiteral("zdi") ? FileType::Fdi : FileType::Img; + if (createSectorImage(filename, disk_sizes[ui->comboBoxSize->currentIndex()], fileType)) { + return; + } + } + break; + case MediaType::Zip: + { + fileType = fi.suffix().toLower() == QStringLiteral("zdi") ? FileType::Zdi: FileType::Img; + + std::atomic_bool res; + std::thread t([this, &res, filename, fileType, &progress] { + res = createZipSectorImage(filename, disk_sizes[ui->comboBoxSize->currentIndex() + 12], fileType, progress); + }); + progress.exec(); + t.join(); + + if (res) { + return; + } + } + break; + case MediaType::Mo: + { + fileType = fi.suffix().toLower() == QStringLiteral("mdi") ? FileType::Mdi: FileType::Img; + + std::atomic_bool res; + std::thread t([this, &res, filename, fileType, &progress] { + res = createMoSectorImage(filename, ui->comboBoxSize->currentIndex(), fileType, progress); + }); + progress.exec(); + t.join(); + + if (res) { + return; + } + } + break; + } + + QMessageBox::critical(this, tr("Unable to write file"), tr("Make sure the file is being saved to a writable directory")); + reject(); +} + +bool NewFloppyDialog::create86f(const QString& filename, const disk_size_t& disk_size, uint8_t rpm_mode) +{ + FILE *f; + + uint32_t magic = 0x46423638; + uint16_t version = 0x020C; + uint16_t dflags = 0; + uint16_t tflags = 0; + uint32_t index_hole_pos = 0; + uint32_t tarray[512]; + uint32_t array_size; + uint32_t track_base, track_size; + int i; + uint32_t shift = 0; + + dflags = 0; /* Has surface data? - Assume no for now. */ + dflags |= (disk_size.hole << 1); /* Hole */ + dflags |= ((disk_size.sides - 1) << 3); /* Sides. */ + dflags |= (0 << 4); /* Write protect? - Assume no for now. */ + dflags |= (rpm_mode << 5); /* RPM mode. */ + dflags |= (0 << 7); /* Has extra bit cells? - Assume no for now. */ + + tflags = disk_size.data_rate; /* Data rate. */ + tflags |= (disk_size.encoding << 3); /* Encoding. */ + tflags |= (disk_size.rpm << 5); /* RPM. */ + + switch (disk_size.hole) { + case 0: + case 1: + default: + switch(rpm_mode) { + case 1: + array_size = 25250; + break; + case 2: + array_size = 25374; + break; + case 3: + array_size = 25750; + break; + default: + array_size = 25000; + break; + } + break; + case 2: + switch(rpm_mode) { + case 1: + array_size = 50500; + break; + case 2: + array_size = 50750; + break; + case 3: + array_size = 51000; + break; + default: + array_size = 50000; + break; + } + break; + } + + auto empty = (unsigned char *) malloc(array_size); + + memset(tarray, 0, 2048); + memset(empty, 0, array_size); + + f = plat_fopen(filename.toUtf8().data(), "wb"); + if (!f) + return false; + + fwrite(&magic, 4, 1, f); + fwrite(&version, 2, 1, f); + fwrite(&dflags, 2, 1, f); + + track_size = array_size + 6; + + track_base = 8 + ((disk_size.sides == 2) ? 2048 : 1024); + + if (disk_size.tracks <= 43) + shift = 1; + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) + tarray[i] = track_base + (i * track_size); + + fwrite(tarray, 1, (disk_size.sides == 2) ? 2048 : 1024, f); + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) { + fwrite(&tflags, 2, 1, f); + fwrite(&index_hole_pos, 4, 1, f); + fwrite(empty, 1, array_size, f); + } + + free(empty); + + fclose(f); + + return true; +} + +/* Ignore false positive warning caused by a bug on gcc */ +#if __GNUC__ >= 11 +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + +bool NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t& disk_size, FileType type) +{ + uint32_t total_size = 0; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint32_t root_dir_bytes = 0; + uint32_t fat_size = 0; + uint32_t fat1_offs = 0; + uint32_t fat2_offs = 0; + uint32_t zero_bytes = 0; + uint16_t base = 0x1000; + + QFile file(filename); + if (! file.open(QIODevice::WriteOnly)) { + return false; + } + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + + sector_bytes = (128 << disk_size.sector_len); + total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; + if (total_sectors > ZIP_SECTORS) + total_sectors = ZIP_250_SECTORS; + total_size = total_sectors * sector_bytes; + root_dir_bytes = (disk_size.root_dir_entries << 5); + fat_size = (disk_size.spfat * sector_bytes); + fat1_offs = sector_bytes; + fat2_offs = fat1_offs + fat_size; + zero_bytes = fat2_offs + fat_size + root_dir_bytes; + + if (type == FileType::Fdi) { + QByteArray bytes(base, 0); + auto empty = bytes.data(); + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; + stream.writeRawData(empty, base); + } + + QByteArray bytes(total_size, 0); + auto empty = bytes.data(); + + memset(empty + zero_bytes, 0xF6, total_size - zero_bytes); + + empty[0x00] = 0xEB; /* Jump to make MS-DOS happy. */ + empty[0x01] = 0x58; + empty[0x02] = 0x90; + + empty[0x03] = 0x38; /* '86BOX5.0' OEM ID. */ + empty[0x04] = 0x36; + empty[0x05] = 0x42; + empty[0x06] = 0x4F; + empty[0x07] = 0x58; + empty[0x08] = 0x35; + empty[0x09] = 0x2E; + empty[0x0A] = 0x30; + + *(uint16_t *) &(empty[0x0B]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x0D]) = (uint8_t) disk_size.spc; + *(uint16_t *) &(empty[0x0E]) = (uint16_t) 1; + *(uint8_t *) &(empty[0x10]) = (uint8_t) disk_size.num_fats; + *(uint16_t *) &(empty[0x11]) = (uint16_t) disk_size.root_dir_entries; + *(uint16_t *) &(empty[0x13]) = (uint16_t) total_sectors; + *(uint8_t *) &(empty[0x15]) = (uint8_t) disk_size.media_desc; + *(uint16_t *) &(empty[0x16]) = (uint16_t) disk_size.spfat; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x1A]) = (uint8_t) disk_size.sides; + + empty[0x26] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x27] = random_generate(); + empty[0x28] = random_generate(); + empty[0x29] = random_generate(); + empty[0x2A] = random_generate(); + + memset(&(empty[0x2B]), 0x20, 11); + + empty[0x36] = 'F'; + empty[0x37] = 'A'; + empty[0x38] = 'T'; + empty[0x39] = '1'; + empty[0x3A] = '2'; + memset(&(empty[0x3B]), 0x20, 0x0003); + + empty[0x1FE] = 0x55; + empty[0x1FF] = 0xAA; + + empty[fat1_offs + 0x00] = empty[fat2_offs + 0x00] = empty[0x15]; + empty[fat1_offs + 0x01] = empty[fat2_offs + 0x01] = 0xFF; + empty[fat1_offs + 0x02] = empty[fat2_offs + 0x02] = 0xFF; + + stream.writeRawData(empty, total_size); + return true; +} + +bool NewFloppyDialog::createZipSectorImage(const QString &filename, const disk_size_t& disk_size, FileType type, QProgressDialog& pbar) +{ + uint32_t total_size = 0; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint16_t base = 0x1000; + uint32_t pbar_max = 0; + + QFile file(filename); + if (! file.open(QIODevice::WriteOnly)) { + return false; + } + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + + sector_bytes = (128 << disk_size.sector_len); + total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; + if (total_sectors > ZIP_SECTORS) + total_sectors = ZIP_250_SECTORS; + total_size = total_sectors * sector_bytes; + + pbar_max = total_size; + if (type == FileType::Zdi) { + pbar_max += base; + } + pbar_max >>= 11; + + if (type == FileType::Zdi) { + QByteArray data(base, 0); + auto empty = data.data(); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; + + stream.writeRawData(empty, base); + pbar_max -= 2; + } + + QByteArray bytes(total_size, 0); + auto empty = bytes.data(); + + if (total_sectors == ZIP_SECTORS) { + /* ZIP 100 */ + /* MBR */ + *(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL; + *(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL; + *(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL; + *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; + *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; + + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E90644LL; + *(uint64_t *) &(empty[0x01B6]) = 0xED08BBE5014E0135LL; + *(uint64_t *) &(empty[0x01BE]) = 0xFFFFFE06FFFFFE80LL; + *(uint64_t *) &(empty[0x01C6]) = 0x0002FFE000000020LL; + + *(uint16_t *) &(empty[0x01FE]) = 0xAA55; + + /* 31 sectors filled with 0x48 */ + memset(&(empty[0x0200]), 0x48, 0x3E00); + + /* Boot sector */ + *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; + *(uint64_t *) &(empty[0x4008]) = 0x0008040200302E35LL; + *(uint64_t *) &(empty[0x4010]) = 0x00C0F80000020002LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000FF003FLL; + *(uint32_t *) &(empty[0x4020]) = 0x0002FFE0; + *(uint16_t *) &(empty[0x4024]) = 0x0080; + + empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x4027] = random_generate(); + empty[0x4028] = random_generate(); + empty[0x4029] = random_generate(); + empty[0x402A] = random_generate(); + + memset(&(empty[0x402B]), 0x00, 0x000B); + memset(&(empty[0x4036]), 0x20, 0x0008); + + empty[0x4036] = 'F'; + empty[0x4037] = 'A'; + empty[0x4038] = 'T'; + empty[0x4039] = '1'; + empty[0x403A] = '6'; + memset(&(empty[0x403B]), 0x20, 0x0003); + + empty[0x41FE] = 0x55; + empty[0x41FF] = 0xAA; + + empty[0x5000] = empty[0x1D000] = empty[0x4015]; + empty[0x5001] = empty[0x1D001] = 0xFF; + empty[0x5002] = empty[0x1D002] = 0xFF; + empty[0x5003] = empty[0x1D003] = 0xFF; + + /* Root directory = 0x35000 + Data = 0x39000 */ + } else { + /* ZIP 250 */ + /* MBR */ + *(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL; + *(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL; + *(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL; + *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; + *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; + + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E900E9LL; + *(uint64_t *) &(empty[0x01B6]) = 0x2E32A7AC014E0135LL; + + *(uint64_t *) &(empty[0x01EE]) = 0xEE203F0600010180LL; + *(uint64_t *) &(empty[0x01F6]) = 0x000777E000000020LL; + *(uint16_t *) &(empty[0x01FE]) = 0xAA55; + + /* 31 sectors filled with 0x48 */ + memset(&(empty[0x0200]), 0x48, 0x3E00); + + /* The second sector begins with some strange data + in my reference image. */ + *(uint64_t *) &(empty[0x0200]) = 0x3831393230334409LL; + *(uint64_t *) &(empty[0x0208]) = 0x6A57766964483130LL; + *(uint64_t *) &(empty[0x0210]) = 0x3C3A34676063653FLL; + *(uint64_t *) &(empty[0x0218]) = 0x586A56A8502C4161LL; + *(uint64_t *) &(empty[0x0220]) = 0x6F2D702535673D6CLL; + *(uint64_t *) &(empty[0x0228]) = 0x255421B8602D3456LL; + *(uint64_t *) &(empty[0x0230]) = 0x577B22447B52603ELL; + *(uint64_t *) &(empty[0x0238]) = 0x46412CC871396170LL; + *(uint64_t *) &(empty[0x0240]) = 0x704F55237C5E2626LL; + *(uint64_t *) &(empty[0x0248]) = 0x6C7932C87D5C3C20LL; + *(uint64_t *) &(empty[0x0250]) = 0x2C50503E47543D6ELL; + *(uint64_t *) &(empty[0x0258]) = 0x46394E807721536ALL; + *(uint64_t *) &(empty[0x0260]) = 0x505823223F245325LL; + *(uint64_t *) &(empty[0x0268]) = 0x365C79B0393B5B6ELL; + + /* Boot sector */ + *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; + *(uint64_t *) &(empty[0x4008]) = 0x0001080200302E35LL; + *(uint64_t *) &(empty[0x4010]) = 0x00EFF80000020002LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL; + *(uint32_t *) &(empty[0x4020]) = 0x000777E0; + *(uint16_t *) &(empty[0x4024]) = 0x0080; + + empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x4027] = random_generate(); + empty[0x4028] = random_generate(); + empty[0x4029] = random_generate(); + empty[0x402A] = random_generate(); + + memset(&(empty[0x402B]), 0x00, 0x000B); + memset(&(empty[0x4036]), 0x20, 0x0008); + + empty[0x4036] = 'F'; + empty[0x4037] = 'A'; + empty[0x4038] = 'T'; + empty[0x4039] = '1'; + empty[0x403A] = '6'; + memset(&(empty[0x403B]), 0x20, 0x0003); + + empty[0x41FE] = 0x55; + empty[0x41FF] = 0xAA; + + empty[0x4200] = empty[0x22000] = empty[0x4015]; + empty[0x4201] = empty[0x22001] = 0xFF; + empty[0x4202] = empty[0x22002] = 0xFF; + empty[0x4203] = empty[0x22003] = 0xFF; + + /* Root directory = 0x3FE00 + Data = 0x38200 */ + } + + pbar.setMaximum(pbar_max); + for (uint32_t i = 0; i < pbar_max; i++) { + stream.writeRawData(&empty[i << 11], 2048); + fileProgress(i); + } + fileProgress(pbar_max); + + return true; +} + + +bool NewFloppyDialog::createMoSectorImage(const QString& filename, int8_t disk_size, FileType type, QProgressDialog& pbar) +{ + const mo_type_t *dp = &mo_types[disk_size]; + uint32_t total_size = 0, total_size2; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint16_t base = 0x1000; + uint32_t pbar_max = 0, blocks_num; + + QFile file(filename); + if (! file.open(QIODevice::WriteOnly)) { + return false; + } + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + + sector_bytes = dp->bytes_per_sector; + total_sectors = dp->sectors; + total_size = total_sectors * sector_bytes; + + total_size2 = (total_size >> 20) << 20; + total_size2 = total_size - total_size2; + + pbar_max = total_size; + pbar_max >>= 20; + blocks_num = pbar_max; + if (type == FileType::Mdi) + pbar_max++; + if (total_size2 == 0) + pbar_max++; + + if (type == FileType::Mdi) { + QByteArray bytes(base, 0); + auto empty = bytes.data(); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) 25; + *(uint8_t *) &(empty[0x18]) = (uint8_t) 64; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) (dp->sectors / 64) / 25; + + stream.writeRawData(empty, base); + } + + QByteArray bytes(1048576, 0); + auto empty = bytes.data(); + + pbar.setMaximum(blocks_num); + for (uint32_t i = 0; i < blocks_num; i++) { + stream.writeRawData(empty, bytes.size()); + fileProgress(i); + } + + if (total_size2 > 0) { + QByteArray extra_bytes(total_size2, 0); + stream.writeRawData(extra_bytes.data(), total_size2); + } + fileProgress(blocks_num); + + return true; +} diff --git a/src/qt/qt_newfloppydialog.hpp b/src/qt/qt_newfloppydialog.hpp new file mode 100644 index 000000000..12e761cdf --- /dev/null +++ b/src/qt/qt_newfloppydialog.hpp @@ -0,0 +1,50 @@ +#ifndef QT_NEWFLOPPYDIALOG_HPP +#define QT_NEWFLOPPYDIALOG_HPP + +#include + +namespace Ui { +class NewFloppyDialog; +} + +struct disk_size_t; +class QProgressDialog; + +class NewFloppyDialog : public QDialog +{ + Q_OBJECT + +public: + enum class MediaType { + Floppy, + Zip, + Mo, + }; + enum class FileType { + Img, + Fdi, + Zdi, + Mdi, + }; + explicit NewFloppyDialog(MediaType type, QWidget *parent = nullptr); + ~NewFloppyDialog(); + + QString fileName() const; + +signals: + void fileProgress(int i); + +private slots: + void onCreate(); + +private: + Ui::NewFloppyDialog *ui; + MediaType mediaType_; + + bool create86f(const QString& filename, const disk_size_t& disk_size, uint8_t rpm_mode); + bool createSectorImage(const QString& filename, const disk_size_t& disk_size, FileType type); + bool createZipSectorImage(const QString& filename, const disk_size_t& disk_size, FileType type, QProgressDialog& pbar); + bool createMoSectorImage(const QString& filename, int8_t disk_size, FileType type, QProgressDialog& pbar); +}; + +#endif // QT_NEWFLOPPYDIALOG_HPP diff --git a/src/qt/qt_newfloppydialog.ui b/src/qt/qt_newfloppydialog.ui new file mode 100644 index 000000000..7fb044fcc --- /dev/null +++ b/src/qt/qt_newfloppydialog.ui @@ -0,0 +1,148 @@ + + + NewFloppyDialog + + + + 0 + 0 + 327 + 200 + + + + + 327 + 200 + + + + + 327 + 200 + + + + New Image + + + + + + File name: + + + + + + + + 0 + 0 + + + + + + + + Disk size: + + + + + + + + 0 + 0 + + + + + + + + RPM mode: + + + + + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + FileField + QWidget +
qt_filefield.hpp
+ 1 +
+
+ + + + buttonBox + accepted() + NewFloppyDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NewFloppyDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/qt/qt_opengloptions.cpp b/src/qt/qt_opengloptions.cpp new file mode 100644 index 000000000..f90ba37c0 --- /dev/null +++ b/src/qt/qt_opengloptions.cpp @@ -0,0 +1,195 @@ +/* + * 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. + * + * OpenGL renderer options for Qt + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#include +#include +#include +#include + +#include + +#include "qt_opengloptions.hpp" + +extern "C" { +#include <86box/86box.h> +} + +/* Default vertex shader. */ +static const GLchar *vertex_shader = "\ +in vec2 VertexCoord;\n\ +in vec2 TexCoord;\n\ +out vec2 tex;\n\ +void main(){\n\ + gl_Position = vec4(VertexCoord, 0.0, 1.0);\n\ + tex = TexCoord;\n\ +}\n"; + +/* Default fragment shader. */ +static const GLchar *fragment_shader = "\ +in vec2 tex;\n\ +uniform sampler2D texsampler;\n\ +out vec4 color;\n\ +void main() {\n\ + color = texture(texsampler, tex);\n\ +}\n"; + +OpenGLOptions::OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion) + : QObject(parent) + , m_glslVersion(glslVersion) +{ + m_filter = video_filter_method == 0 + ? FilterType::Nearest + : FilterType::Linear; + + if (!loadConfig) + return; + + /* Initialize with config. */ + m_vsync = video_vsync != 0; + m_framerate = video_framerate; + + m_renderBehavior = video_framerate == -1 + ? RenderBehaviorType::SyncWithVideo + : RenderBehaviorType::TargetFramerate; + + QString shaderPath(video_shader); + + if (shaderPath.isEmpty()) { + addDefaultShader(); + } else { + try { + addShader(shaderPath); + } catch (const std::runtime_error &) { + /* Fallback to default shader */ + addDefaultShader(); + } + } +} + +void +OpenGLOptions::save() const +{ + video_vsync = m_vsync ? 1 : 0; + video_framerate = m_renderBehavior == RenderBehaviorType::SyncWithVideo ? -1 : m_framerate; + video_filter_method = m_filter == FilterType::Nearest ? 0 : 1; + + /* TODO: multiple shaders */ + auto path = m_shaders.first().path().toLocal8Bit(); + + if (!path.isEmpty()) + qstrncpy(video_shader, path.constData(), sizeof(video_shader)); + else + video_shader[0] = '\0'; +} + +OpenGLOptions::FilterType +OpenGLOptions::filter() const +{ + /* Filter method is controlled externally */ + return video_filter_method == 0 + ? FilterType::Nearest + : FilterType::Linear; +} + +void +OpenGLOptions::setRenderBehavior(RenderBehaviorType value) +{ + m_renderBehavior = value; +} + +void +OpenGLOptions::setFrameRate(int value) +{ + m_framerate = value; +} + +void +OpenGLOptions::setVSync(bool value) +{ + m_vsync = value; +} + +void +OpenGLOptions::setFilter(FilterType value) +{ + m_filter = value; +} + +void +OpenGLOptions::addShader(const QString &path) +{ + QFile shader_file(path); + + if (!shader_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + throw std::runtime_error( + QString(tr("Error opening \"%1\": %2")) + .arg(path) + .arg(shader_file.errorString()) + .toStdString()); + } + + auto shader_text = QString(shader_file.readAll()); + + shader_file.close(); + + /* Remove parameter lines */ + shader_text.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption)); + + QRegularExpression version("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption); + + auto match = version.match(shader_text); + + QString version_line(m_glslVersion); + + if (match.hasMatch()) { + /* Extract existing version and remove it. */ + version_line = match.captured(1); + shader_text.remove(version); + } + + auto shader = new QOpenGLShaderProgram(this); + + auto throw_shader_error = [path, shader](const QString &what) { + throw std::runtime_error( + QString(what % ":\n\n %2") + .arg(path) + .arg(shader->log()) + .toStdString()); + }; + + static const char *extension = "\n#extension GL_ARB_shading_language_420pack : enable\n"; + + if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % extension % "\n#define VERTEX\n#line 1\n" % shader_text)) + throw_shader_error(tr("Error compiling vertex shader in file \"%1\"")); + + if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % extension % "\n#define FRAGMENT\n#line 1\n" % shader_text)) + throw_shader_error(tr("Error compiling fragment shader in file \"%1\"")); + + if (!shader->link()) + throw_shader_error(tr("Error linking shader program in file \"%1\"")); + + m_shaders << OpenGLShaderPass(shader, path); +} + +void +OpenGLOptions::addDefaultShader() +{ + auto shader = new QOpenGLShaderProgram(this); + shader->addShaderFromSourceCode(QOpenGLShader::Vertex, m_glslVersion % "\n" % vertex_shader); + shader->addShaderFromSourceCode(QOpenGLShader::Fragment, m_glslVersion % "\n" % fragment_shader); + shader->link(); + m_shaders << OpenGLShaderPass(shader, QString()); +} diff --git a/src/qt/qt_opengloptions.hpp b/src/qt/qt_opengloptions.hpp new file mode 100644 index 000000000..b88cf4b07 --- /dev/null +++ b/src/qt/qt_opengloptions.hpp @@ -0,0 +1,101 @@ +/* + * 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. + * + * Header for OpenGL renderer options + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#ifndef QT_OPENGLOPTIONS_HPP +#define QT_OPENGLOPTIONS_HPP + +#include +#include +#include +#include + +class OpenGLShaderPass { +public: + OpenGLShaderPass(QOpenGLShaderProgram *shader, const QString &path) + : m_shader(shader) + , m_path(path) + , m_vertex_coord(shader->attributeLocation("VertexCoord")) + , m_tex_coord(shader->attributeLocation("TexCoord")) + , m_color(shader->attributeLocation("Color")) + , m_mvp_matrix(shader->uniformLocation("MVPMatrix")) + , m_input_size(shader->uniformLocation("InputSize")) + , m_output_size(shader->uniformLocation("OutputSize")) + , m_texture_size(shader->uniformLocation("TextureSize")) + , m_frame_count(shader->uniformLocation("FrameCount")) + { + } + + bool bind() const { return m_shader->bind(); } + const QString &path() const { return m_path; } + const GLint &vertex_coord() const { return m_vertex_coord; } + const GLint &tex_coord() const { return m_tex_coord; } + const GLint &color() const { return m_color; } + const GLint &mvp_matrix() const { return m_mvp_matrix; } + const GLint &input_size() const { return m_input_size; } + const GLint &output_size() const { return m_output_size; } + const GLint &texture_size() const { return m_texture_size; } + const GLint &frame_count() const { return m_frame_count; } + +private: + QOpenGLShaderProgram *m_shader; + QString m_path; + GLint m_vertex_coord; + GLint m_tex_coord; + GLint m_color; + GLint m_mvp_matrix; + GLint m_input_size; + GLint m_output_size; + GLint m_texture_size; + GLint m_frame_count; +}; + +class OpenGLOptions : public QObject { + Q_OBJECT + +public: + enum RenderBehaviorType { SyncWithVideo, + TargetFramerate }; + + enum FilterType { Nearest, + Linear }; + + OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion); + + RenderBehaviorType renderBehavior() const { return m_renderBehavior; } + int framerate() const { return m_framerate; } + bool vSync() const { return m_vsync; } + FilterType filter() const; + + const QList &shaders() const { return m_shaders; } + + void setRenderBehavior(RenderBehaviorType value); + void setFrameRate(int value); + void setVSync(bool value); + void setFilter(FilterType value); + void addShader(const QString &path); + void addDefaultShader(); + void save() const; + +private: + RenderBehaviorType m_renderBehavior = SyncWithVideo; + int m_framerate = -1; + bool m_vsync = false; + FilterType m_filter = Nearest; + QList m_shaders; + QString m_glslVersion; +}; + +#endif diff --git a/src/qt/qt_opengloptionsdialog.cpp b/src/qt/qt_opengloptionsdialog.cpp new file mode 100644 index 000000000..c87989161 --- /dev/null +++ b/src/qt/qt_opengloptionsdialog.cpp @@ -0,0 +1,115 @@ +/* + * 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. + * + * OpenGL renderer options dialog for Qt + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#include +#include +#include + +#include + +#include "qt_opengloptionsdialog.hpp" +#include "qt_util.hpp" +#include "ui_qt_opengloptionsdialog.h" + +OpenGLOptionsDialog::OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory) + : QDialog(parent) + , ui(new Ui::OpenGLOptionsDialog) + , createOptions(optionsFactory) +{ + ui->setupUi(this); + + if (options.renderBehavior() == OpenGLOptions::SyncWithVideo) + ui->syncWithVideo->setChecked(true); + else { + ui->syncToFramerate->setChecked(true); + ui->targetFps->setValue(options.framerate()); + } + + ui->vsync->setChecked(options.vSync()); + + if (!options.shaders().isEmpty()) { + auto path = options.shaders().first().path(); + if (!path.isEmpty()) + ui->shader->setPlainText(path); + } +} + +OpenGLOptionsDialog::~OpenGLOptionsDialog() +{ + delete ui; +} + +void +OpenGLOptionsDialog::accept() +{ + auto options = createOptions(); + + options->setRenderBehavior( + ui->syncWithVideo->isChecked() + ? OpenGLOptions::SyncWithVideo + : OpenGLOptions::TargetFramerate); + + options->setFrameRate(ui->targetFps->value()); + + options->setVSync(ui->vsync->isChecked()); + + auto shader = ui->shader->toPlainText(); + + try { + + if (!shader.isEmpty()) + options->addShader(shader); + else + options->addDefaultShader(); + + } catch (const std::runtime_error &e) { + delete options; + + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Shader error")); + msgBox.setText(tr("Could not load shaders.")); + msgBox.setInformativeText(tr("More information in details.")); + msgBox.setDetailedText(e.what()); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Close); + msgBox.setDefaultButton(QMessageBox::Close); + msgBox.setStyleSheet("QTextEdit { min-width: 45em; }"); + msgBox.exec(); + + return; + } + + options->save(); + + emit optionsChanged(options); + + QDialog::accept(); +} + +void +OpenGLOptionsDialog::on_addShader_clicked() +{ + auto shader = QFileDialog::getOpenFileName( + this, + QString(), + QString(), + tr("OpenGL Shaders") % util::DlgFilter({ "glsl" }, true)); + + if (shader.isNull()) + return; + + ui->shader->setPlainText(shader); +} diff --git a/src/qt/qt_opengloptionsdialog.hpp b/src/qt/qt_opengloptionsdialog.hpp new file mode 100644 index 000000000..6b1c673bd --- /dev/null +++ b/src/qt/qt_opengloptionsdialog.hpp @@ -0,0 +1,52 @@ +/* + * 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. + * + * Header for OpenGL renderer options dialog + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#ifndef QT_OPENGLOPTIONSDIALOG_H +#define QT_OPENGLOPTIONSDIALOG_H + +#include + +#include + +#include "qt_opengloptions.hpp" + +namespace Ui { +class OpenGLOptionsDialog; +} + +class OpenGLOptionsDialog : public QDialog { + Q_OBJECT + +public: + explicit OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory); + ~OpenGLOptionsDialog(); + +signals: + void optionsChanged(OpenGLOptions *options); + +public slots: + void accept() override; + +private: + Ui::OpenGLOptionsDialog *ui; + + std::function createOptions; + +private slots: + void on_addShader_clicked(); +}; + +#endif // QT_OPENGLOPTIONSDIALOG_H diff --git a/src/qt/qt_opengloptionsdialog.ui b/src/qt/qt_opengloptionsdialog.ui new file mode 100644 index 000000000..a6f86b6c2 --- /dev/null +++ b/src/qt/qt_opengloptionsdialog.ui @@ -0,0 +1,280 @@ + + + OpenGLOptionsDialog + + + + 0 + 0 + 400 + 320 + + + + OpenGL 3.0 renderer options + + + + + + Render behavior + + + + + + Use target framerate: + + + + + + + false + + + fps + + + 15 + + + 240 + + + 60 + + + + + + + VSync + + + + + + + <html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html> + + + Synchronize with video + + + true + + + + + + + false + + + 15 + + + 240 + + + 60 + + + Qt::Horizontal + + + false + + + QSlider::NoTicks + + + + + + + + + + Shaders + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + true + + + No shader selected + + + + + + + Browse... + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + syncWithVideo + syncToFramerate + fpsSlider + targetFps + vsync + shader + addShader + removeShader + + + + + buttonBox + accepted() + OpenGLOptionsDialog + accept() + + + 257 + 310 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenGLOptionsDialog + reject() + + + 325 + 310 + + + 286 + 274 + + + + + syncToFramerate + toggled(bool) + targetFps + setEnabled(bool) + + + 140 + 71 + + + 380 + 98 + + + + + syncToFramerate + toggled(bool) + fpsSlider + setEnabled(bool) + + + 158 + 66 + + + 168 + 87 + + + + + fpsSlider + valueChanged(int) + targetFps + setValue(int) + + + 252 + 90 + + + 308 + 89 + + + + + targetFps + valueChanged(int) + fpsSlider + setValue(int) + + + 364 + 93 + + + 134 + 93 + + + + + removeShader + clicked() + shader + clear() + + + 333 + 201 + + + 235 + 208 + + + + + diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp new file mode 100644 index 000000000..7c7cd55fa --- /dev/null +++ b/src/qt/qt_openglrenderer.cpp @@ -0,0 +1,441 @@ +/* + * 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. + * + * OpenGL renderer for Qt + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "qt_opengloptionsdialog.hpp" +#include "qt_openglrenderer.hpp" + +OpenGLRenderer::OpenGLRenderer(QWidget *parent) + : QWindow(parent->windowHandle()) + , renderTimer(new QTimer(this)) + , options(nullptr) +{ + renderTimer->setTimerType(Qt::PreciseTimer); + /* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */ + connect(renderTimer, &QTimer::timeout, this, &OpenGLRenderer::render); + + buf_usage = std::vector(BUFFERCOUNT); + for (auto &flag : buf_usage) + flag.clear(); + + setSurfaceType(QWindow::OpenGLSurface); + + QSurfaceFormat format; + +#ifdef Q_OS_MACOS + format.setVersion(4, 1); +#else + format.setVersion(3, 2); +#endif + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + format.setRenderableType(QSurfaceFormat::OpenGLES); + + setFormat(format); + + parentWidget = parent; + + source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT); +} + +OpenGLRenderer::~OpenGLRenderer() +{ + finalize(); +} + +void +OpenGLRenderer::exposeEvent(QExposeEvent *event) +{ + Q_UNUSED(event); + + if (!isInitialized) + initialize(); +} + +void +OpenGLRenderer::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + + onResize(event->size().width(), event->size().height()); + + if (notReady()) + return; + + context->makeCurrent(this); + + glViewport( + destination.x(), + destination.y(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +} + +bool +OpenGLRenderer::event(QEvent *event) +{ + Q_UNUSED(event); + + bool res = false; + if (!eventDelegate(event, res)) + return QWindow::event(event); + return res; +} + +void +OpenGLRenderer::initialize() +{ + try { + context = new QOpenGLContext(this); + + context->setFormat(format()); + + if (!context->create()) + throw opengl_init_error(tr("Couldn't create OpenGL context.")); + + if (!context->makeCurrent(this)) + throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); + + auto version = context->format().version(); + + if (version.first < 3) + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); + + initializeOpenGLFunctions(); + + /* Prepare the shader version string */ + glslVersion = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); + glslVersion.truncate(4); + glslVersion.remove('.'); + glslVersion.prepend("#version "); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + glslVersion.append(" es"); + else if (context->format().profile() == QSurfaceFormat::CoreProfile) + glslVersion.append(" core"); + + initializeExtensions(); + + initializeBuffers(); + + /* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */ + const GLfloat surface[] = { + -1.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, + 1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, + -1.f, -1.f, 0.f, 1.f, 1.f, 1.f, 1.f, 1.f, + 1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f + }; + + glGenVertexArrays(1, &vertexArrayID); + + glBindVertexArray(vertexArrayID); + + glGenBuffers(1, &vertexBufferID); + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); + glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW); + + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D, textureID); + + const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; + + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + + reloadOptions(); + + glClearColor(0.f, 0.f, 0.f, 1.f); + + glViewport( + destination.x(), + destination.y(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); + + GLenum error = glGetError(); + if (error != GL_NO_ERROR) + throw opengl_init_error(tr("OpenGL initialization failed. Error %1.").arg(error)); + + isInitialized = true; + + emit initialized(); + + } catch (const opengl_init_error &e) { + /* Mark all buffers as in use */ + for (auto &flag : buf_usage) + flag.test_and_set(); + + QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() % tr("\nFalling back to software rendering.")); + + context->doneCurrent(); + isFinalized = true; + isInitialized = true; + + emit errorInitializing(); + } +} + +void +OpenGLRenderer::finalize() +{ + if (isFinalized) + return; + + renderTimer->stop(); + + context->makeCurrent(this); + + if (hasBufferStorage) + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + + glDeleteBuffers(1, &unpackBufferID); + glDeleteTextures(1, &textureID); + glDeleteBuffers(1, &vertexBufferID); + glDeleteVertexArrays(1, &vertexArrayID); + + if (!hasBufferStorage && unpackBuffer) + free(unpackBuffer); + + context->doneCurrent(); + + isFinalized = true; +} + +QDialog * +OpenGLRenderer::getOptions(QWidget *parent) +{ + auto dialog = new OpenGLOptionsDialog(parent, *options, [this]() { return new OpenGLOptions(this, false, glslVersion); }); + + connect(dialog, &OpenGLOptionsDialog::optionsChanged, this, &OpenGLRenderer::updateOptions); + + return dialog; +} + +void +OpenGLRenderer::initializeExtensions() +{ +#ifndef NO_BUFFER_STORAGE + if (context->hasExtension("GL_ARB_buffer_storage")) { + hasBufferStorage = true; + + glBufferStorage = (PFNGLBUFFERSTORAGEPROC) context->getProcAddress("glBufferStorage"); + } +#endif +} + +void +OpenGLRenderer::initializeBuffers() +{ + glGenBuffers(1, &unpackBufferID); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); + + if (hasBufferStorage) { +#ifndef NO_BUFFER_STORAGE + /* Create persistent buffer for pixel transfer. */ + glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + + unpackBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); +#endif + } else { + /* Fallback; create our own buffer. */ + unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT); + + if (unpackBuffer == nullptr) + throw opengl_init_error(tr("Allocating memory for unpack buffer failed.")); + + glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW); + } +} + +void +OpenGLRenderer::applyOptions() +{ + /* TODO: change detection in options */ + + if (options->framerate() > 0) { + int interval = (int) ceilf(1000.f / (float) options->framerate()); + renderTimer->setInterval(std::chrono::milliseconds(interval)); + } + + if (options->renderBehavior() == OpenGLOptions::TargetFramerate) + renderTimer->start(); + else + renderTimer->stop(); + + auto format = this->format(); + int interval = options->vSync() ? 1 : 0; + + if (format.swapInterval() != interval) { + format.setSwapInterval(interval); + setFormat(format); + context->setFormat(format); + } + + GLint filter = options->filter() == OpenGLOptions::Linear ? GL_LINEAR : GL_NEAREST; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + currentFilter = options->filter(); +} + +void +OpenGLRenderer::reloadOptions() +{ + if (options) { delete options; options = nullptr; } + options = new OpenGLOptions(this, true, glslVersion); + + applyOptions(); +} + +void +OpenGLRenderer::applyShader(const OpenGLShaderPass &shader) +{ + if (!shader.bind()) + return; + + if (shader.vertex_coord() != -1) { + glEnableVertexAttribArray(shader.vertex_coord()); + glVertexAttribPointer(shader.vertex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); + } + + if (shader.tex_coord() != -1) { + glEnableVertexAttribArray(shader.tex_coord()); + glVertexAttribPointer(shader.tex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat))); + } + + if (shader.color() != -1) { + glEnableVertexAttribArray(shader.color()); + glVertexAttribPointer(shader.color(), 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (4 * sizeof(GLfloat))); + } + + if (shader.mvp_matrix() != -1) { + static const GLfloat mvp[] = { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + glUniformMatrix4fv(shader.mvp_matrix(), 1, GL_FALSE, mvp); + } + + if (shader.output_size() != -1) + glUniform2f(shader.output_size(), destination.width(), destination.height()); + + if (shader.input_size() != -1) + glUniform2f(shader.input_size(), source.width(), source.height()); + + if (shader.texture_size() != -1) + glUniform2f(shader.texture_size(), source.width(), source.height()); + + if (shader.frame_count() != -1) + glUniform1i(shader.frame_count(), frameCounter); +} + +void +OpenGLRenderer::render() +{ + context->makeCurrent(this); + + if (options->filter() != currentFilter) + applyOptions(); + + /* TODO: multiple shader passes */ + applyShader(options->shaders().first()); + + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + context->swapBuffers(this); + + frameCounter = (frameCounter + 1) & 1023; +} + +void +OpenGLRenderer::updateOptions(OpenGLOptions *newOptions) +{ + context->makeCurrent(this); + + glUseProgram(0); + + delete options; + + options = newOptions; + + options->setParent(this); + + applyOptions(); +} + +std::vector> +OpenGLRenderer::getBuffers() +{ + std::vector> buffers; + + if (notReady() || !unpackBuffer) + return buffers; + + /* Split the buffer area */ + for (int i = 0; i < BUFFERCOUNT; i++) { + buffers.push_back(std::make_tuple((uint8_t *) unpackBuffer + BUFFERBYTES * i, &buf_usage[i])); + } + + return buffers; +} + +void +OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) +{ + if (notReady()) + return; + + context->makeCurrent(this); + + if (source.width() != w || source.height() != h) { + source.setRect(0, 0, w, h); + + /* Resize the texture */ + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); + } + + if (!hasBufferStorage) + glBufferSubData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * buf_idx, h * ROW_LENGTH * sizeof(uint32_t) + (y * ROW_LENGTH * sizeof(uint32_t)), (uint8_t *) unpackBuffer + BUFFERBYTES * buf_idx); + + glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x); + glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + + /* TODO: check if fence sync is implementable here and still has any benefit. */ + glFinish(); + + buf_usage[buf_idx].clear(); + + if (options->renderBehavior() == OpenGLOptions::SyncWithVideo) + render(); +} diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp new file mode 100644 index 000000000..a27e0fe21 --- /dev/null +++ b/src/qt/qt_openglrenderer.hpp @@ -0,0 +1,122 @@ +/* + * 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. + * + * Header file for OpenGL renderer + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#ifndef QT_OPENGLRENDERER_HPP +#define QT_OPENGLRENDERER_HPP + +#if defined Q_OS_MACOS || __arm__ +# define NO_BUFFER_STORAGE +#endif + +#include +#include +#include +#include +#include +#include +#if !defined NO_BUFFER_STORAGE && !(QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +# include +#endif + +#include +#include +#include +#include + +#include "qt_opengloptions.hpp" +#include "qt_renderercommon.hpp" + +class OpenGLRenderer : public QWindow, protected QOpenGLExtraFunctions, public RendererCommon { + Q_OBJECT + +public: + QOpenGLContext *context; + + OpenGLRenderer(QWidget *parent = nullptr); + ~OpenGLRenderer(); + + std::vector> getBuffers() override; + + void finalize() override final; + bool hasOptions() const override { return true; } + QDialog *getOptions(QWidget *parent) override; + void reloadOptions() override; + +signals: + void initialized(); + void errorInitializing(); + +public slots: + void onBlit(int buf_idx, int x, int y, int w, int h); + +protected: + void exposeEvent(QExposeEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + bool event(QEvent *event) override; + +private: + static constexpr int INIT_WIDTH = 640; + static constexpr int INIT_HEIGHT = 400; + static constexpr int ROW_LENGTH = 2048; + static constexpr int BUFFERPIXELS = 4194304; + static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ + static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ + + OpenGLOptions *options; + QTimer *renderTimer; + + QString glslVersion; + + bool isInitialized = false; + bool isFinalized = false; + + GLuint unpackBufferID = 0; + GLuint vertexArrayID = 0; + GLuint vertexBufferID = 0; + GLuint textureID = 0; + int frameCounter = 0; + + OpenGLOptions::FilterType currentFilter; + + void *unpackBuffer = nullptr; + + void initialize(); + void initializeExtensions(); + void initializeBuffers(); + void applyOptions(); + void applyShader(const OpenGLShaderPass &shader); + bool notReady() const { return !isInitialized || isFinalized; } + + /* GL_ARB_buffer_storage */ + bool hasBufferStorage = false; +#ifndef NO_BUFFER_STORAGE + PFNGLBUFFERSTORAGEPROC glBufferStorage = nullptr; +#endif + +private slots: + void render(); + void updateOptions(OpenGLOptions *newOptions); +}; + +class opengl_init_error : public std::runtime_error { +public: + opengl_init_error(const QString &what) + : std::runtime_error(what.toStdString()) + { + } +}; + +#endif diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp new file mode 100644 index 000000000..d1f5318ba --- /dev/null +++ b/src/qt/qt_platform.cpp @@ -0,0 +1,617 @@ +/* + * 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. + * + * Common platform functions. + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021-2022 Teemu Korhonen + */ +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "qt_rendererstack.hpp" +#include "qt_mainwindow.hpp" +#include "qt_progsettings.hpp" + +#ifdef Q_OS_UNIX +#include +#endif + +// static QByteArray buf; +extern QElapsedTimer elapsed_timer; +extern MainWindow* main_window; +QElapsedTimer elapsed_timer; + +static std::atomic_int blitmx_contention = 0; +static std::recursive_mutex blitmx; +static thread_local std::unique_lock blit_lock { blitmx, std::defer_lock }; + +class CharPointer { +public: + CharPointer(char* buf, int size) : b(buf), s(size) {} + CharPointer& operator=(const QByteArray &ba) { + if (s > 0) { + strncpy(b, ba.data(), s-1); + b[s] = 0; + } else { + // if we haven't been told the length of b, just assume enough + // because we didn't get it from emulator code + strcpy(b, ba.data()); + b[ba.size()] = 0; + } + return *this; + } +private: + char* b; + int s; +}; + +extern "C" { +#ifdef Q_OS_WINDOWS +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include +# include <86box/win.h> +#else +# include +#endif +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/gameport.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/path.h> +#include <86box/plat_dynld.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/config.h> +#include <86box/ui.h> +#include <86box/discord.h> + +#include "../cpu/cpu.h" +#include <86box/plat.h> + +volatile int cpu_thread_run = 1; +int mouse_capture = 0; +int fixed_size_x = 640; +int fixed_size_y = 480; +int rctrl_is_lalt = 0; +int update_icons = 1; +int kbd_req_capture = 0; +int hide_status_bar = 0; +int hide_tool_bar = 0; +uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US + +int stricmp(const char* s1, const char* s2) +{ +#ifdef Q_OS_WINDOWS + return _stricmp(s1, s2); +#else + return strcasecmp(s1, s2); +#endif +} + +int strnicmp(const char *s1, const char *s2, size_t n) +{ +#ifdef Q_OS_WINDOWS + return _strnicmp(s1, s2, n); +#else + return strncasecmp(s1, s2, n); +#endif +} + +void +do_stop(void) +{ + cpu_thread_run = 0; + //main_window->close(); +} + +void plat_get_exe_name(char *s, int size) +{ + QByteArray exepath_temp = QCoreApplication::applicationDirPath().toLocal8Bit(); + + memcpy(s, exepath_temp.data(), std::min((qsizetype)exepath_temp.size(),(qsizetype)size)); + + path_slash(s); +} + +uint32_t +plat_get_ticks(void) +{ + return elapsed_timer.elapsed(); +} + +uint64_t +plat_timer_read(void) +{ + return elapsed_timer.elapsed(); +} + +FILE * +plat_fopen(const char *path, const char *mode) +{ + return fopen(QString::fromUtf8(path).toLocal8Bit(), mode); +} + +FILE * +plat_fopen64(const char *path, const char *mode) +{ + return fopen(path, mode); +} + +int +plat_dir_create(char *path) +{ + return QDir().mkdir(path) ? 0 : -1; +} + +int +plat_dir_check(char *path) +{ + QFileInfo fi(path); + return fi.isDir() ? 1 : 0; +} + +int +plat_getcwd(char *bufp, int max) +{ +#ifdef __APPLE__ + /* Working directory for .app bundles is undefined. */ + strncpy(bufp, exe_path, max); +#else + CharPointer(bufp, max) = QDir::currentPath().toUtf8(); +#endif + return 0; +} + +void +path_get_dirname(char *dest, const char *path) +{ + QFileInfo fi(path); + CharPointer(dest, -1) = fi.dir().path().toUtf8(); +} + +char * +path_get_extension(char *s) +{ + auto len = strlen(s); + auto idx = QByteArray::fromRawData(s, len).lastIndexOf('.'); + if (idx >= 0) { + return s+idx+1; + } + return s+len; +} + +char * +path_get_filename(char *s) +{ +#ifdef Q_OS_WINDOWS + int c = strlen(s) - 1; + + while (c > 0) { + if (s[c] == '/' || s[c] == '\\') + return(&s[c+1]); + c--; + } + + return(s); +#else + auto idx = QByteArray::fromRawData(s, strlen(s)).lastIndexOf(QDir::separator().toLatin1()); + if (idx >= 0) { + return s+idx+1; + } + return s; +#endif +} + +int +path_abs(char *path) +{ +#ifdef Q_OS_WINDOWS + if ((path[1] == ':') || (path[0] == '\\') || (path[0] == '/')) + return 1; + + return 0; +#else + return path[0] == '/'; +#endif +} + +void +path_normalize(char* path) +{ +#ifdef Q_OS_WINDOWS + while (*path++ != 0) + { + if (*path == '\\') *path = '/'; + } +#endif +} + +void +path_slash(char *path) +{ + auto len = strlen(path); + auto separator = '/'; + if (path[len-1] != separator) { + path[len] = separator; + path[len+1] = 0; + } + path_normalize(path); +} + +void +path_append_filename(char *dest, const char *s1, const char *s2) +{ + strcpy(dest, s1); + path_slash(dest); + strcat(dest, s2); +} + +void +plat_tempfile(char *bufp, char *prefix, char *suffix) +{ + QString name; + + if (prefix != nullptr) { + name.append(QString("%1-").arg(prefix)); + } + + name.append(QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss-zzzz")); + if (suffix) name.append(suffix); + strcpy(bufp, name.toUtf8().data()); +} + +void plat_remove(char* path) +{ + QFile(path).remove(); +} + +void * +plat_mmap(size_t size, uint8_t executable) +{ +#if defined Q_OS_WINDOWS + return VirtualAlloc(NULL, size, MEM_COMMIT, executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); +#elif defined Q_OS_UNIX +#if defined Q_OS_DARWIN && defined MAP_JIT + void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE | (executable ? MAP_JIT : 0), -1, 0); +#else + void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + return (ret == MAP_FAILED) ? nullptr : ret; +#endif +} + +void +plat_munmap(void *ptr, size_t size) +{ +#if defined Q_OS_WINDOWS + VirtualFree(ptr, 0, MEM_RELEASE); +#else + munmap(ptr, size); +#endif +} + +void +plat_pause(int p) +{ + static wchar_t oldtitle[512]; + wchar_t title[1024], paused_msg[512]; + + if (p == dopause) { +#ifdef Q_OS_WINDOWS + if (source_hwnd) + PostMessage((HWND)(uintptr_t)source_hwnd, WM_SENDSTATUS, (WPARAM)!!p, (LPARAM)(HWND)main_window->winId()); +#endif + return; + } + if ((p == 0) && (time_sync & TIME_SYNC_ENABLED)) + nvr_time_sync(); + + dopause = p; + if (p) { + wcsncpy(oldtitle, ui_window_title(NULL), sizeof_w(oldtitle) - 1); + wcscpy(title, oldtitle); + paused_msg[QObject::tr(" - PAUSED").toWCharArray(paused_msg)] = 0; + wcscat(title, paused_msg); + ui_window_title(title); + } else { + ui_window_title(oldtitle); + } + discord_update_activity(dopause); + +#ifdef Q_OS_WINDOWS + if (source_hwnd) + PostMessage((HWND)(uintptr_t)source_hwnd, WM_SENDSTATUS, (WPARAM)!!p, (LPARAM)(HWND)main_window->winId()); +#endif +} + +// because we can't include nvr.h because it's got fields named new +extern int nvr_save(void); + +void +plat_power_off(void) +{ + plat_mouse_capture(0); + confirm_exit = 0; + nvr_save(); + config_save(); + + /* Deduct a sufficiently large number of cycles that no instructions will + run before the main thread is terminated */ + cycles -= 99999999; + + cpu_thread_run = 0; + QTimer::singleShot(0, (const QWidget *) main_window, &QMainWindow::close); +} + +void set_language(uint32_t id) { + lang_id = id; +} + +extern "C++" +{ + QMap> ProgSettings::lcid_langcode = + { + {0x0405, {"cs-CZ", "Czech (Czech Republic)"} }, + {0x0407, {"de-DE", "German (Germany)"} }, + {0x0409, {"en-US", "English (United States)"} }, + {0x0809, {"en-GB", "English (United Kingdom)"} }, + {0x0C0A, {"es-ES", "Spanish (Spain)"} }, + {0x040B, {"fi-FI", "Finnish (Finland)"} }, + {0x040C, {"fr-FR", "French (France)"} }, + {0x041A, {"hr-HR", "Croatian (Croatia)"} }, + {0x040E, {"hu-HU", "Hungarian (Hungary)"} }, + {0x0410, {"it-IT", "Italian (Italy)"} }, + {0x0411, {"ja-JP", "Japanese (Japan)"} }, + {0x0412, {"ko-KR", "Korean (Korea)"} }, + {0x0415, {"pl-PL", "Polish (Poland)"} }, + {0x0416, {"pt-BR", "Portuguese (Brazil)"} }, + {0x0816, {"pt-PT", "Portuguese (Portugal)"} }, + {0x0419, {"ru-RU", "Russian (Russia)"} }, + {0x0424, {"sl-SI", "Slovenian (Slovenia)"} }, + {0x041F, {"tr-TR", "Turkish (Turkey)"} }, + {0x0422, {"uk-UA", "Ukrainian (Ukraine)"} }, + {0x0804, {"zh-CN", "Chinese (China)"} }, + {0xFFFF, {"system", "(System Default)"} }, + }; +} + +/* Sets up the program language before initialization. */ +uint32_t plat_language_code(char* langcode) { + for (auto& curKey : ProgSettings::lcid_langcode.keys()) + { + if (ProgSettings::lcid_langcode[curKey].first == langcode) + { + return curKey; + } + } + return 0xFFFF; +} + +/* Converts back the language code to LCID */ +void plat_language_code_r(uint32_t lcid, char* outbuf, int len) { + if (!ProgSettings::lcid_langcode.contains(lcid)) + { + qstrncpy(outbuf, "system", len); + return; + } + qstrncpy(outbuf, ProgSettings::lcid_langcode[lcid].first.toUtf8().constData(), len); + return; +} + +#ifndef Q_OS_WINDOWS +void* dynld_module(const char *name, dllimp_t *table) +{ + QString libraryName = name; + QFileInfo fi(libraryName); + QStringList removeSuffixes = {"dll", "dylib", "so"}; + if (removeSuffixes.contains(fi.suffix())) { + libraryName = fi.completeBaseName(); + } + + auto lib = std::unique_ptr(new QLibrary(libraryName)); + if (lib->load()) { + for (auto imp = table; imp->name != nullptr; imp++) + { + auto ptr = lib->resolve(imp->name); + if (ptr == nullptr) { + return nullptr; + } + auto imp_ptr = reinterpret_cast(imp->func); + *imp_ptr = reinterpret_cast(ptr); + } + } else { + return nullptr; + } + + return lib.release(); +} + +void dynld_close(void *handle) +{ + delete reinterpret_cast(handle); +} +#endif + +void startblit() +{ + blitmx_contention++; + if (blit_lock.try_lock()) { + return; + } + + blit_lock.lock(); +} + +void endblit() +{ + blitmx_contention--; + blit_lock.unlock(); + if (blitmx_contention > 0) { + // a deadlock has been observed on linux when toggling via video_toggle_option + // because the mutex is typically unfair on linux + // => sleep if there's contention + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +} + +} + +#ifdef Q_OS_WINDOWS +size_t mbstoc16s(uint16_t dst[], const char src[], int len) +{ + if (src == NULL) return 0; + if (len < 0) return 0; + + size_t ret = MultiByteToWideChar(CP_UTF8, 0, src, -1, reinterpret_cast(dst), dst == NULL ? 0 : len); + + if (!ret) { + return -1; + } + + return ret; +} + +size_t c16stombs(char dst[], const uint16_t src[], int len) +{ + if (src == NULL) return 0; + if (len < 0) return 0; + + size_t ret = WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast(src), -1, dst, dst == NULL ? 0 : len, NULL, NULL); + + if (!ret) { + return -1; + } + + return ret; +} +#endif + +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#define LIB_NAME_GS "gsdll32.dll" +#define LIB_NAME_FREETYPE "freetype.dll" +#define MOUSE_CAPTURE_KEYSEQ "F8+F12" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#define LIB_NAME_GS "libgs" +#define LIB_NAME_FREETYPE "libfreetype" +#define MOUSE_CAPTURE_KEYSEQ "CTRL-END" +#endif + + +QMap ProgSettings::translatedstrings; + +void ProgSettings::reloadStrings() +{ + translatedstrings.clear(); + translatedstrings[IDS_2077] = QCoreApplication::translate("", "Click to capture mouse").toStdWString(); + translatedstrings[IDS_2078] = QCoreApplication::translate("", "Press F8+F12 to release mouse").replace("F8+F12", MOUSE_CAPTURE_KEYSEQ).replace("CTRL-END", QLocale::system().name() == "de_DE" ? "Strg+Ende" : "CTRL-END").toStdWString(); + translatedstrings[IDS_2079] = QCoreApplication::translate("", "Press F8+F12 or middle button to release mouse").replace("F8+F12", MOUSE_CAPTURE_KEYSEQ).replace("CTRL-END", QLocale::system().name() == "de_DE" ? "Strg+Ende" : "CTRL-END").toStdWString(); + translatedstrings[IDS_2080] = QCoreApplication::translate("", "Failed to initialize FluidSynth").toStdWString(); + translatedstrings[IDS_2130] = QCoreApplication::translate("", "Invalid configuration").toStdWString(); + translatedstrings[IDS_4099] = QCoreApplication::translate("", "MFM/RLL or ESDI CD-ROM drives never existed").toStdWString(); + translatedstrings[IDS_2093] = QCoreApplication::translate("", "Failed to set up PCap").toStdWString(); + translatedstrings[IDS_2094] = QCoreApplication::translate("", "No PCap devices found").toStdWString(); + translatedstrings[IDS_2095] = QCoreApplication::translate("", "Invalid PCap device").toStdWString(); + translatedstrings[IDS_2110] = QCoreApplication::translate("", "Unable to initialize FreeType").toStdWString(); + translatedstrings[IDS_2111] = QCoreApplication::translate("", "Unable to initialize SDL, libsdl2 is required").toStdWString(); + translatedstrings[IDS_2129] = QCoreApplication::translate("", "Make sure libpcap is installed and that you are on a libpcap-compatible network connection.").toStdWString(); + translatedstrings[IDS_2114] = QCoreApplication::translate("", "Unable to initialize Ghostscript").toStdWString(); + translatedstrings[IDS_2063] = QCoreApplication::translate("", "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine.").toStdWString(); + translatedstrings[IDS_2064] = QCoreApplication::translate("", "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card.").toStdWString(); + translatedstrings[IDS_2128] = QCoreApplication::translate("", "Hardware not available").toStdWString(); + translatedstrings[IDS_2142] = QCoreApplication::translate("", "Monitor in sleep mode").toStdWString(); + translatedstrings[IDS_2120] = QCoreApplication::translate("", "No ROMs found").toStdWString(); + translatedstrings[IDS_2056] = QCoreApplication::translate("", "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory.").toStdWString(); + + auto flsynthstr = QCoreApplication::translate("", " is required for FluidSynth MIDI output."); + if (flsynthstr.contains("libfluidsynth")) + { + flsynthstr.replace("libfluidsynth", LIB_NAME_FLUIDSYNTH); + } + else flsynthstr.prepend(LIB_NAME_FLUIDSYNTH); + translatedstrings[IDS_2133] = flsynthstr.toStdWString(); + auto gssynthstr = QCoreApplication::translate("", " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files."); + if (gssynthstr.contains("libgs")) + { + gssynthstr.replace("libgs", LIB_NAME_GS); + } + else gssynthstr.prepend(LIB_NAME_GS); + translatedstrings[IDS_2132] = gssynthstr.toStdWString(); + auto ftsynthstr = QCoreApplication::translate("", " is required for ESC/P printer emulation."); + if (ftsynthstr.contains("libfreetype")) + { + ftsynthstr.replace("libfreetype", LIB_NAME_FREETYPE); + } + else ftsynthstr.prepend(LIB_NAME_FREETYPE); + translatedstrings[IDS_2131] = ftsynthstr.toStdWString(); +} + +wchar_t* plat_get_string(int i) +{ + if (ProgSettings::translatedstrings.empty()) ProgSettings::reloadStrings(); + return ProgSettings::translatedstrings[i].data(); +} + +int +plat_chdir(char *path) +{ + return QDir::setCurrent(QString(path)) ? 0 : -1; +} + +void +plat_init_rom_paths() +{ + auto paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); + +#ifdef _WIN32 + // HACK: The standard locations returned for GenericDataLocation include + // the EXE path and a `data` directory within it as the last two entries. + + // Remove the entries as we don't need them. + paths.removeLast(); + paths.removeLast(); +#endif + + for (auto& path : paths) { +#ifdef __APPLE__ + rom_add_path(QDir(path).filePath("net.86Box.86Box/roms").toUtf8().constData()); +#else + rom_add_path(QDir(path).filePath("86Box/roms").toUtf8().constData()); +#endif + } +} diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp new file mode 100644 index 000000000..b11466c08 --- /dev/null +++ b/src/qt/qt_progsettings.cpp @@ -0,0 +1,210 @@ +/* + * 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. + * + * Program settings UI module. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + */ +#include + +#include "qt_progsettings.hpp" +#include "ui_qt_progsettings.h" +#include "qt_mainwindow.hpp" +#include "ui_qt_mainwindow.h" +#include "qt_machinestatus.hpp" + +#include +#include +#include +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/version.h> +#include <86box/config.h> +#include <86box/plat.h> +} + + +static QMap iconset_to_qt; +extern MainWindow* main_window; + +ProgSettings::CustomTranslator* ProgSettings::translator = nullptr; +QTranslator* ProgSettings::qtTranslator = nullptr; +QString ProgSettings::getIconSetPath() +{ + QString roms_root; + if (rom_path[0]) + roms_root = rom_path; + else { + roms_root = QString("%1/roms").arg(exe_path); + } + + if (iconset_to_qt.isEmpty()) + { + iconset_to_qt.insert("", ":/settings/win/icons"); + QDir dir(roms_root + "/icons/"); + if (dir.isReadable()) + { + auto dirList = dir.entryList(QDir::AllDirs | QDir::Executable | QDir::Readable); + for (auto &curIconSet : dirList) + { + if (curIconSet == "." || curIconSet == "..") continue; + iconset_to_qt.insert(curIconSet, (dir.canonicalPath() + '/') + curIconSet); + } + } + } + return iconset_to_qt[icon_set]; +} + +QIcon ProgSettings::loadIcon(QString file) +{ + (void)getIconSetPath(); + if (!QFile::exists(iconset_to_qt[icon_set] + file)) return QIcon(iconset_to_qt[""] + file); + return QIcon(iconset_to_qt[icon_set] + file); +} + +ProgSettings::ProgSettings(QWidget *parent) : + QDialog(parent), + ui(new Ui::ProgSettings) +{ + ui->setupUi(this); + (void)getIconSetPath(); + ui->comboBox->setItemData(0, ""); + ui->comboBox->setCurrentIndex(0); + for (auto i = iconset_to_qt.begin(); i != iconset_to_qt.end(); i++) + { + if (i.key() == "") continue; + QFile iconfile(i.value() + "/iconinfo.txt"); + iconfile.open(QFile::ReadOnly); + QString friendlyName; + QString iconsetinfo(iconfile.readAll()); + iconfile.close(); + if (iconsetinfo.isEmpty()) friendlyName = i.key(); + else friendlyName = iconsetinfo.split('\n')[0]; + ui->comboBox->addItem(friendlyName, i.key()); + if (strcmp(icon_set, i.key().toUtf8().data()) == 0) + { + ui->comboBox->setCurrentIndex(ui->comboBox->findData(i.key())); + } + } + ui->comboBox->setItemData(0, '(' + tr("Default") + ')', Qt::DisplayRole); + + ui->comboBoxLanguage->setItemData(0, 0xFFFF); + for (auto i = lcid_langcode.begin(); i != lcid_langcode.end(); i++) + { + if (i.key() == 0xFFFF) continue; + ui->comboBoxLanguage->addItem(lcid_langcode[i.key()].second, i.key()); + if (i.key() == lang_id) + { + ui->comboBoxLanguage->setCurrentIndex(ui->comboBoxLanguage->findData(i.key())); + } + } + + mouseSensitivity = mouse_sensitivity; + ui->horizontalSlider->setValue(mouseSensitivity * 100.); +} + +void ProgSettings::accept() +{ + strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data()); + lang_id = ui->comboBoxLanguage->currentData().toUInt(); + + loadTranslators(QCoreApplication::instance()); + reloadStrings(); + update_mouse_msg(); + main_window->ui->retranslateUi(main_window); + QString vmname(vm_name); + if (vmname.at(vmname.size() - 1) == '"' || vmname.at(vmname.size() - 1) == '\'') vmname.truncate(vmname.size() - 1); + main_window->setWindowTitle(QString("%1 - %2 %3").arg(vmname, EMU_NAME, EMU_VERSION_FULL)); + QString msg = main_window->status->getMessage(); + main_window->status.reset(new MachineStatus(main_window)); + main_window->refreshMediaMenu(); + main_window->status->message(msg); + connect(main_window, &MainWindow::updateStatusBarTip, main_window->status.get(), &MachineStatus::updateTip); + connect(main_window, &MainWindow::statusBarMessage, main_window->status.get(), &MachineStatus::message, Qt::QueuedConnection); + mouse_sensitivity = mouseSensitivity; + QDialog::accept(); +} + +ProgSettings::~ProgSettings() +{ + delete ui; +} + +void ProgSettings::on_pushButton_released() +{ + ui->comboBox->setCurrentIndex(0); +} + +void ProgSettings::loadTranslators(QObject *parent) +{ + if (qtTranslator) + { + QApplication::removeTranslator(qtTranslator); + qtTranslator = nullptr; + } + if (translator) + { + QApplication::removeTranslator(translator); + translator = nullptr; + } + qtTranslator = new QTranslator(parent); + translator = new CustomTranslator(parent); + QString localetofilename = ""; + if (lang_id == 0xFFFF || lcid_langcode.contains(lang_id) == false) + { + for (int i = 0; i < QLocale::system().uiLanguages().size(); i++) + { + localetofilename = QLocale::system().uiLanguages()[i]; + if (translator->load(QLatin1String("86box_") + localetofilename, QLatin1String(":/"))) + { + qDebug() << "Translations loaded.\n"; + QCoreApplication::installTranslator(translator); + if (!qtTranslator->load(QLatin1String("qtbase_") + localetofilename.replace('-', '_'), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + qtTranslator->load(QLatin1String("qt_") + localetofilename.replace('-', '_'), QApplication::applicationDirPath() + "/./translations/"); + if (QApplication::installTranslator(qtTranslator)) + { + qDebug() << "Qt translations loaded." << "\n"; + } + break; + } + } + } + else + { + translator->load(QLatin1String("86box_") + lcid_langcode[lang_id].first, QLatin1String(":/")); + QCoreApplication::installTranslator(translator); + if (!qtTranslator->load(QLatin1String("qtbase_") + QString(lcid_langcode[lang_id].first).replace('-', '_'), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + qtTranslator->load(QLatin1String("qt_") + QString(lcid_langcode[lang_id].first).replace('-', '_'), QApplication::applicationDirPath() + "/./translations/"); + QCoreApplication::installTranslator(qtTranslator); + } +} + +void ProgSettings::on_pushButtonLanguage_released() +{ + ui->comboBoxLanguage->setCurrentIndex(0); +} + +void ProgSettings::on_horizontalSlider_valueChanged(int value) +{ + mouseSensitivity = (double)value / 100.; +} + + +void ProgSettings::on_pushButton_2_clicked() +{ + mouseSensitivity = 1.0; + ui->horizontalSlider->setValue(100); +} + diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp new file mode 100644 index 000000000..07cf62051 --- /dev/null +++ b/src/qt/qt_progsettings.hpp @@ -0,0 +1,71 @@ +#ifndef QT_PROGSETTINGS_HPP +#define QT_PROGSETTINGS_HPP + +#include +#include + +namespace Ui { +class ProgSettings; +} + +class ProgSettings : public QDialog +{ + Q_OBJECT + +public: + explicit ProgSettings(QWidget *parent = nullptr); + ~ProgSettings(); + static QString getIconSetPath(); + static QIcon loadIcon(QString file); + static void loadTranslators(QObject* parent = nullptr); + static void reloadStrings(); + class CustomTranslator : public QTranslator + { + public: + CustomTranslator(QObject* parent = nullptr) : QTranslator(parent) {}; + protected: + QString translate(const char *context, const char *sourceText, + const char *disambiguation = nullptr, int n = -1) const override + { + if (strcmp(sourceText, "&Fullscreen") == 0) sourceText = "&Fullscreen\tCtrl+Alt+PgUp"; + if (strcmp(sourceText, "&Ctrl+Alt+Del") == 0) sourceText = "&Ctrl+Alt+Del\tCtrl+F12"; + if (strcmp(sourceText, "Take s&creenshot") == 0) sourceText = "Take s&creenshot\tCtrl+F11"; + if (strcmp(sourceText, "Begin trace") == 0) sourceText = "Begin trace\tCtrl+T"; + if (strcmp(sourceText, "End trace") == 0) sourceText = "End trace\tCtrl+T"; + if (strcmp(sourceText, "&Qt (Software)") == 0) + { + QString finalstr = QTranslator::translate("", "&SDL (Software)", disambiguation, n); + finalstr.replace("SDL", "Qt"); + finalstr.replace("(&S)", "(&Q)"); + return finalstr; + } + QString finalstr = QTranslator::translate("", sourceText, disambiguation, n); +#ifdef Q_OS_MACOS + if (finalstr.contains('\t')) finalstr.truncate(finalstr.indexOf('\t')); +#endif + return finalstr; + } + }; + static CustomTranslator* translator; + static QTranslator* qtTranslator; + static QMap> lcid_langcode; + static QMap translatedstrings; + +protected slots: + void accept() override; +private slots: + void on_pushButton_released(); + void on_pushButtonLanguage_released(); + + void on_horizontalSlider_valueChanged(int value); + + void on_pushButton_2_clicked(); + +private: + Ui::ProgSettings *ui; + + friend class MainWindow; + double mouseSensitivity; +}; + +#endif // QT_PROGSETTINGS_HPP diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui new file mode 100644 index 000000000..11bb39b74 --- /dev/null +++ b/src/qt/qt_progsettings.ui @@ -0,0 +1,203 @@ + + + ProgSettings + + + + 0 + 0 + 458 + 303 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Preferences + + + + QLayout::SetFixedSize + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + (System Default) + + + + + + + + Mouse sensitivity: + + + + + + + Default + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Default + + + + + + + Icon set: + + + + + + + Default + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Language: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 50 + + + 200 + + + 10 + + + 20 + + + 100 + + + Qt::Horizontal + + + + + + + false + + + + (Default) + + + + + + + + + + buttonBox + accepted() + ProgSettings + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ProgSettings + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_renderercommon.cpp b/src/qt/qt_renderercommon.cpp new file mode 100644 index 000000000..0974c1f78 --- /dev/null +++ b/src/qt/qt_renderercommon.cpp @@ -0,0 +1,124 @@ +/* + * 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. + * + * Program settings UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ + +#include "qt_renderercommon.hpp" +#include "qt_mainwindow.hpp" + +#include +#include +#include +#include + +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/video.h> +} + +RendererCommon::RendererCommon() = default; + +extern MainWindow* main_window; + +static void integer_scale(double *d, double *g) { + double ratio; + + if (*d > *g) { + ratio = std::floor(*d / *g); + *d = *g * ratio; + } else { + ratio = std::ceil(*d / *g); + *d = *g / ratio; + } +} + +void RendererCommon::onResize(int width, int height) { + if (video_fullscreen == 0) { + destination.setRect(0, 0, width, height); + return; + } + double dx, dy, dw, dh, gsr; + + double hw = width; + double hh = height; + double gw = source.width(); + double gh = source.height(); + double hsr = hw / hh; + + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_INT: + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + integer_scale(&dw, &gw); + integer_scale(&dh, &gh); + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + destination.setRect(dx, dy, dw, dh); + break; + case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: + if (video_fullscreen_scale == FULLSCR_SCALE_43) { + gsr = 4.0 / 3.0; + } else { + gsr = gw / gh; + } + + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + destination.setRect(dx, dy, dw, dh); + break; + case FULLSCR_SCALE_FULL: + default: + destination.setRect(0, 0, hw, hh); + break; + } +} + +bool RendererCommon::eventDelegate(QEvent *event, bool& result) +{ + switch (event->type()) + { + default: + return false; + case QEvent::KeyPress: + case QEvent::KeyRelease: + result = QApplication::sendEvent(main_window, event); + return true; + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + case QEvent::Wheel: + case QEvent::Enter: + case QEvent::Leave: + result = QApplication::sendEvent(parentWidget, event); + return true; + } + return false; +} diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp new file mode 100644 index 000000000..1a0bf73e1 --- /dev/null +++ b/src/qt/qt_renderercommon.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class QWidget; + +class RendererCommon { +public: + RendererCommon(); + + void onResize(int width, int height); + virtual void finalize() { } + + virtual uint32_t getBytesPerRow() { return 2048 * 4; } + + virtual std::vector> getBuffers() { std::vector> buffers; return buffers; } + + /* Does renderer implement options dialog */ + virtual bool hasOptions() const { return false; } + /* Returns options dialog for renderer */ + virtual QDialog *getOptions(QWidget *parent) { return nullptr; } + /* Reloads options of renderer */ + virtual void reloadOptions() {} + + virtual bool hasBlitFunc() { return false; } + virtual void blit(int x, int y, int w, int h) {} + +protected: + bool eventDelegate(QEvent *event, bool &result); + + QRect source, destination; + QWidget *parentWidget { nullptr }; + + std::vector buf_usage; +}; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp new file mode 100644 index 000000000..fab20b5b7 --- /dev/null +++ b/src/qt/qt_rendererstack.cpp @@ -0,0 +1,457 @@ +/* + * 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. + * + * Program settings UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2021 Teemu Korhonen + * Copyright 2021-2022 Cacodemon345 + */ +#include "qt_rendererstack.hpp" +#include "ui_qt_rendererstack.h" + +#include "qt_hardwarerenderer.hpp" +#include "qt_openglrenderer.hpp" +#include "qt_softwarerenderer.hpp" +#include "qt_vulkanwindowrenderer.hpp" +#ifdef Q_OS_WIN +#include "qt_d3d9renderer.hpp" +#endif + +#include "qt_mainwindow.hpp" +#include "qt_util.hpp" + +#include "evdev_mouse.hpp" + +#include +#include + +#include +#include + +#ifdef __APPLE__ +# include +#endif + +extern "C" { +#include <86box/86box.h> +#include <86box/mouse.h> +#include <86box/plat.h> +#include <86box/video.h> + +double mouse_sensitivity = 1.0; +} + +struct mouseinputdata { + atomic_int deltax, deltay, deltaz; + atomic_int mousebuttons; +}; +static mouseinputdata mousedata; + +extern "C" void macos_poll_mouse(); +extern MainWindow *main_window; +RendererStack::RendererStack(QWidget *parent, int monitor_index) + : QStackedWidget(parent) + , ui(new Ui::RendererStack) +{ + ui->setupUi(this); + + m_monitor_index = monitor_index; +#if defined __unix__ && !defined __HAIKU__ + char *mouse_type = getenv("EMU86BOX_MOUSE"), auto_mouse_type[16]; + if (!mouse_type || (mouse_type[0] == '\0') || !stricmp(mouse_type, "auto")) { + if (QApplication::platformName().contains("wayland")) + strcpy(auto_mouse_type, "wayland"); + else if (QApplication::platformName() == "eglfs" || QApplication::platformName() == "xcb") + strcpy(auto_mouse_type, "evdev"); + else + auto_mouse_type[0] = '\0'; + mouse_type = auto_mouse_type; + } + +# ifdef WAYLAND + if (!stricmp(mouse_type, "wayland")) { + wl_init(); + this->mouse_poll_func = wl_mouse_poll; + this->mouse_capture_func = wl_mouse_capture; + this->mouse_uncapture_func = wl_mouse_uncapture; + } +# endif +# ifdef EVDEV_INPUT + if (!stricmp(mouse_type, "evdev")) { + evdev_init(); + this->mouse_poll_func = evdev_mouse_poll; + } +# endif +#endif +#ifdef __APPLE__ + this->mouse_poll_func = macos_poll_mouse; +#endif +} + +RendererStack::~RendererStack() +{ + delete ui; +} + +void +qt_mouse_capture(int on) +{ + if (!on) { + mouse_capture = 0; + QApplication::setOverrideCursor(Qt::ArrowCursor); +#ifdef __APPLE__ + CGAssociateMouseAndMouseCursorPosition(true); +#endif + return; + } + mouse_capture = 1; + QApplication::setOverrideCursor(Qt::BlankCursor); +#ifdef __APPLE__ + CGAssociateMouseAndMouseCursorPosition(false); +#endif + return; +} + +void +RendererStack::mousePoll() +{ +#ifndef __APPLE__ + mouse_x = mousedata.deltax; + mouse_y = mousedata.deltay; + mouse_z = mousedata.deltaz; + mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; + mouse_buttons = mousedata.mousebuttons; + + if (this->mouse_poll_func) +#endif + this->mouse_poll_func(); + + mouse_x *= mouse_sensitivity; + mouse_y *= mouse_sensitivity; +} + +int ignoreNextMouseEvent = 1; +void +RendererStack::mouseReleaseEvent(QMouseEvent *event) +{ + if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1) && mouse_get_buttons() != 0) { + plat_mouse_capture(1); + this->setCursor(Qt::BlankCursor); + if (!ignoreNextMouseEvent) + ignoreNextMouseEvent++; // Avoid jumping cursor when moved. + isMouseDown &= ~1; + return; + } + if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3) { + plat_mouse_capture(0); + this->setCursor(Qt::ArrowCursor); + isMouseDown &= ~1; + return; + } + if (mouse_capture) { + mousedata.mousebuttons &= ~event->button(); + } + isMouseDown &= ~1; +} + +void +RendererStack::mousePressEvent(QMouseEvent *event) +{ + isMouseDown |= 1; + if (mouse_capture) { + mousedata.mousebuttons |= event->button(); + } + event->accept(); +} + +void +RendererStack::wheelEvent(QWheelEvent *event) +{ + if (mouse_capture) { + mousedata.deltaz += event->pixelDelta().y(); + } +} + +void +RendererStack::mouseMoveEvent(QMouseEvent *event) +{ + if (QApplication::platformName().contains("wayland")) { + event->accept(); + return; + } + if (!mouse_capture) { + event->ignore(); + return; + } +#if defined __APPLE__ || defined _WIN32 + event->accept(); + return; +#else + static QPoint oldPos = QCursor::pos(); + if (ignoreNextMouseEvent) { + oldPos = event->pos(); + ignoreNextMouseEvent--; + event->accept(); + return; + } + mousedata.deltax += event->pos().x() - oldPos.x(); + mousedata.deltay += event->pos().y() - oldPos.y(); + if (QApplication::platformName() == "eglfs") { + leaveEvent((QEvent *) event); + ignoreNextMouseEvent--; + } + QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2))); + ignoreNextMouseEvent = 2; + oldPos = event->pos(); +#endif +} + +void +RendererStack::leaveEvent(QEvent *event) +{ + if (QApplication::platformName().contains("wayland")) { + event->accept(); + return; + } + if (!mouse_capture) + return; + QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2))); + ignoreNextMouseEvent = 2; + event->accept(); +} + +void +RendererStack::switchRenderer(Renderer renderer) +{ + startblit(); + if (current) { + rendererWindow->finalize(); + if (rendererWindow->hasBlitFunc()) { + while (directBlitting) {} + connect(this, &RendererStack::blit, this, &RendererStack::blitDummy, Qt::DirectConnection); + disconnect(this, &RendererStack::blit, this, &RendererStack::blitRenderer); + } else { + connect(this, &RendererStack::blit, this, &RendererStack::blitDummy, Qt::DirectConnection); + disconnect(this, &RendererStack::blit, this, &RendererStack::blitCommon); + } + + removeWidget(current.get()); + disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr); + + /* Create new renderer only after previous is destroyed! */ + connect(current.get(), &QObject::destroyed, [this, renderer](QObject *) { + createRenderer(renderer); + disconnect(this, &RendererStack::blit, this, &RendererStack::blitDummy); + blitDummied = false; + QTimer::singleShot(1000, this, [this]() { this->blitDummied = false; } ); + }); + + rendererWindow->hasBlitFunc() ? current.reset() : current.release()->deleteLater(); + } else { + createRenderer(renderer); + } +} + +void +RendererStack::createRenderer(Renderer renderer) +{ + switch (renderer) { + default: + case Renderer::Software: + { + auto sw = new SoftwareRenderer(this); + rendererWindow = sw; + connect(this, &RendererStack::blitToRenderer, sw, &SoftwareRenderer::onBlit, Qt::QueuedConnection); +#ifdef __HAIKU__ + current.reset(sw); +#else + current.reset(this->createWindowContainer(sw, this)); +#endif + } + break; + case Renderer::OpenGL: + { + this->createWinId(); + auto hw = new HardwareRenderer(this); + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection); + current.reset(this->createWindowContainer(hw, this)); + break; + } + case Renderer::OpenGLES: + { + this->createWinId(); + auto hw = new HardwareRenderer(this, HardwareRenderer::RenderType::OpenGLES); + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection); + current.reset(this->createWindowContainer(hw, this)); + break; + } + case Renderer::OpenGL3: + { + this->createWinId(); + auto hw = new OpenGLRenderer(this); + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRenderer::initialized, [=]() { + /* Buffers are available only after initialization. */ + imagebufs = rendererWindow->getBuffers(); + endblit(); + emit rendererChanged(); + }); + connect(hw, &OpenGLRenderer::errorInitializing, [=]() { + /* Renderer not could initialize, fallback to software. */ + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + }); + current.reset(this->createWindowContainer(hw, this)); + break; + } +#ifdef Q_OS_WIN + case Renderer::Direct3D9: + { + this->createWinId(); + auto hw = new D3D9Renderer(this, m_monitor_index); + rendererWindow = hw; + connect(hw, &D3D9Renderer::error, this, [this](QString str) + { + auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", QString("Failed to initialize D3D9 renderer. Falling back to software rendering.\n\n") + str, QMessageBox::Ok); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->show(); + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + }); + connect(hw, &D3D9Renderer::initialized, this, [this]() + { + endblit(); + emit rendererChanged(); + }); + current.reset(hw); + break; + } +#endif +#if QT_CONFIG(vulkan) + case Renderer::Vulkan: + { + this->createWinId(); + VulkanWindowRenderer *hw = nullptr; + try { + hw = new VulkanWindowRenderer(this); + } catch(std::runtime_error& e) { + auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", e.what() + QString("\nFalling back to software rendering."), QMessageBox::Ok); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->show(); + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + current.reset(nullptr); + break; + }; + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &VulkanWindowRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &VulkanWindowRenderer::rendererInitialized, [=]() { + /* Buffers are available only after initialization. */ + imagebufs = rendererWindow->getBuffers(); + endblit(); + emit rendererChanged(); + }); + connect(hw, &VulkanWindowRenderer::errorInitializing, [=]() { + /* Renderer could not initialize, fallback to software. */ + auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", QString("Failed to initialize Vulkan renderer.\nFalling back to software rendering."), QMessageBox::Ok); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->show(); + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + }); + current.reset(this->createWindowContainer(hw, this)); + break; + } +#endif + } + if (current.get() == nullptr) return; + current->setFocusPolicy(Qt::NoFocus); + current->setFocusProxy(this); + addWidget(current.get()); + + this->setStyleSheet("background-color: black"); + + currentBuf = 0; + + if (rendererWindow->hasBlitFunc()) { + connect(this, &RendererStack::blit, this, &RendererStack::blitRenderer, Qt::DirectConnection); + } + else { + connect(this, &RendererStack::blit, this, &RendererStack::blitCommon, Qt::DirectConnection); + } + + if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::Direct3D9) { + imagebufs = rendererWindow->getBuffers(); + endblit(); + emit rendererChanged(); + } +} + +void +RendererStack::blitDummy(int x, int y, int w, int h) +{ + video_blit_complete_monitor(m_monitor_index); + blitDummied = true; +} + +void +RendererStack::blitRenderer(int x, int y, int w, int h) +{ + if (blitDummied) { blitDummied = false; video_blit_complete_monitor(m_monitor_index); return; } + directBlitting = true; + rendererWindow->blit(x, y, w, h); + directBlitting = false; +} + +// called from blitter thread +void +RendererStack::blitCommon(int x, int y, int w, int h) +{ + if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || imagebufs.empty() || std::get(imagebufs[currentBuf])->test_and_set() || blitDummied) { + video_blit_complete_monitor(m_monitor_index); + return; + } + sx = x; + sy = y; + sw = this->w = w; + sh = this->h = h; + uint8_t *imagebits = std::get(imagebufs[currentBuf]); + for (int y1 = y; y1 < (y + h); y1++) { + auto scanline = imagebits + (y1 * rendererWindow->getBytesPerRow()) + (x * 4); + video_copy(scanline, &(monitors[m_monitor_index].target_buffer->line[y1][x]), w * 4); + } + + if (monitors[m_monitor_index].mon_screenshots) { + video_screenshot_monitor((uint32_t *) imagebits, x, y, 2048, m_monitor_index); + } + video_blit_complete_monitor(m_monitor_index); + emit blitToRenderer(currentBuf, sx, sy, sw, sh); + currentBuf = (currentBuf + 1) % imagebufs.size(); +} + +void RendererStack::closeEvent(QCloseEvent* event) +{ + if (cpu_thread_run == 0 || is_quit == 0) { + event->accept(); + show_second_monitors = 0; // TODO: This isn't actually the right fix, so fix this properly. + return; + } + event->ignore(); + main_window->close(); +} + diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp new file mode 100644 index 000000000..72495ec33 --- /dev/null +++ b/src/qt/qt_rendererstack.hpp @@ -0,0 +1,106 @@ +#ifndef QT_RENDERERCONTAINER_HPP +#define QT_RENDERERCONTAINER_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "qt_renderercommon.hpp" + +namespace Ui { +class RendererStack; +} + +class RendererCommon; +class RendererStack : public QStackedWidget { + Q_OBJECT + +public: + explicit RendererStack(QWidget *parent = nullptr, int monitor_index = 0); + ~RendererStack(); + + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + void leaveEvent(QEvent *event) override; + void closeEvent(QCloseEvent *event) override; + void keyPressEvent(QKeyEvent *event) override + { + event->ignore(); + } + void keyReleaseEvent(QKeyEvent *event) override + { + event->ignore(); + } + + enum class Renderer { + Software, + OpenGL, + OpenGLES, + OpenGL3, + Vulkan, + Direct3D9 + }; + void switchRenderer(Renderer renderer); + + /* Does current renderer implement options dialog */ + bool hasOptions() const { return rendererWindow ? rendererWindow->hasOptions() : false; } + /* Reloads options of current renderer */ + void reloadOptions() const { return rendererWindow->reloadOptions(); } + /* Returns options dialog for current renderer */ + QDialog *getOptions(QWidget *parent) { return rendererWindow ? rendererWindow->getOptions(parent) : nullptr; } + + void setFocusRenderer() + { + if (current) + current->setFocus(); + } + void onResize(int width, int height) + { + if (rendererWindow) + rendererWindow->onResize(width, height); + } + + void (*mouse_poll_func)() = nullptr; + void (*mouse_capture_func)(QWindow *window) = nullptr; + void (*mouse_uncapture_func)() = nullptr; + void (*mouse_exit_func)() = nullptr; + +signals: + void blitToRenderer(int buf_idx, int x, int y, int w, int h); + void blit(int x, int y, int w, int h); + void rendererChanged(); + +public slots: + void blitCommon(int x, int y, int w, int h); + void blitRenderer(int x, int y, int w, int h); + void blitDummy(int x, int y, int w, int h); + void mousePoll(); + +private: + void createRenderer(Renderer renderer); + + Ui::RendererStack *ui; + + int x, y, w, h, sx, sy, sw, sh; + + int currentBuf = 0; + int isMouseDown = 0; + int m_monitor_index = 0; + + std::vector> imagebufs; + + RendererCommon *rendererWindow { nullptr }; + std::unique_ptr current; + std::atomic directBlitting{false}, blitDummied{false}; +}; + +#endif // QT_RENDERERCONTAINER_HPP diff --git a/src/qt/qt_rendererstack.ui b/src/qt/qt_rendererstack.ui new file mode 100644 index 000000000..634784714 --- /dev/null +++ b/src/qt/qt_rendererstack.ui @@ -0,0 +1,19 @@ + + + RendererStack + + + + 0 + 0 + 400 + 300 + + + + StackedWidget + + + + + diff --git a/src/qt/qt_sdl.c b/src/qt/qt_sdl.c new file mode 100644 index 000000000..57b9538e9 --- /dev/null +++ b/src/qt/qt_sdl.c @@ -0,0 +1,732 @@ +/* + * 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. + * + * Rendering module for libSDL2 + * + * NOTE: Given all the problems reported with FULLSCREEN use of SDL, + * we will not use that, but, instead, use a new window which + * coverrs the entire desktop. + * + * + * + * Authors: Fred N. van Kempen, + * Michael Drüing, + * + * Copyright 2018-2020 Fred N. van Kempen. + * Copyright 2018-2020 Michael Drüing. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include +#include +#include +#include +/* This #undef is needed because a SDL include header redefines HAVE_STDARG_H. */ +#undef HAVE_STDARG_H +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/mouse.h> +#include <86box/keyboard.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/video.h> +#include <86box/ui.h> +#include <86box/version.h> + +#include "qt_sdl.h" + +#define RENDERER_FULL_SCREEN 1 +#define RENDERER_HARDWARE 2 +#define RENDERER_OPENGL 4 + + +static SDL_Window *sdl_win = NULL; +static SDL_Renderer *sdl_render = NULL; +static SDL_Texture *sdl_tex = NULL; +static int sdl_w, sdl_h; +static int sdl_fs, sdl_flags = -1; +static int cur_w, cur_h; +static int cur_ww = 0, cur_wh = 0; +static volatile int sdl_enabled = 0; +static SDL_mutex* sdl_mutex = NULL; + +static const uint16_t sdl_to_xt[0x200] = + { + [SDL_SCANCODE_ESCAPE] = 0x01, + [SDL_SCANCODE_1] = 0x02, + [SDL_SCANCODE_2] = 0x03, + [SDL_SCANCODE_3] = 0x04, + [SDL_SCANCODE_4] = 0x05, + [SDL_SCANCODE_5] = 0x06, + [SDL_SCANCODE_6] = 0x07, + [SDL_SCANCODE_7] = 0x08, + [SDL_SCANCODE_8] = 0x09, + [SDL_SCANCODE_9] = 0x0A, + [SDL_SCANCODE_0] = 0x0B, + [SDL_SCANCODE_MINUS] = 0x0C, + [SDL_SCANCODE_EQUALS] = 0x0D, + [SDL_SCANCODE_BACKSPACE] = 0x0E, + [SDL_SCANCODE_TAB] = 0x0F, + [SDL_SCANCODE_Q] = 0x10, + [SDL_SCANCODE_W] = 0x11, + [SDL_SCANCODE_E] = 0x12, + [SDL_SCANCODE_R] = 0x13, + [SDL_SCANCODE_T] = 0x14, + [SDL_SCANCODE_Y] = 0x15, + [SDL_SCANCODE_U] = 0x16, + [SDL_SCANCODE_I] = 0x17, + [SDL_SCANCODE_O] = 0x18, + [SDL_SCANCODE_P] = 0x19, + [SDL_SCANCODE_LEFTBRACKET] = 0x1A, + [SDL_SCANCODE_RIGHTBRACKET] = 0x1B, + [SDL_SCANCODE_RETURN] = 0x1C, + [SDL_SCANCODE_LCTRL] = 0x1D, + [SDL_SCANCODE_A] = 0x1E, + [SDL_SCANCODE_S] = 0x1F, + [SDL_SCANCODE_D] = 0x20, + [SDL_SCANCODE_F] = 0x21, + [SDL_SCANCODE_G] = 0x22, + [SDL_SCANCODE_H] = 0x23, + [SDL_SCANCODE_J] = 0x24, + [SDL_SCANCODE_K] = 0x25, + [SDL_SCANCODE_L] = 0x26, + [SDL_SCANCODE_SEMICOLON] = 0x27, + [SDL_SCANCODE_APOSTROPHE] = 0x28, + [SDL_SCANCODE_GRAVE] = 0x29, + [SDL_SCANCODE_LSHIFT] = 0x2A, + [SDL_SCANCODE_BACKSLASH] = 0x2B, + [SDL_SCANCODE_Z] = 0x2C, + [SDL_SCANCODE_X] = 0x2D, + [SDL_SCANCODE_C] = 0x2E, + [SDL_SCANCODE_V] = 0x2F, + [SDL_SCANCODE_B] = 0x30, + [SDL_SCANCODE_N] = 0x31, + [SDL_SCANCODE_M] = 0x32, + [SDL_SCANCODE_COMMA] = 0x33, + [SDL_SCANCODE_PERIOD] = 0x34, + [SDL_SCANCODE_SLASH] = 0x35, + [SDL_SCANCODE_RSHIFT] = 0x36, + [SDL_SCANCODE_KP_MULTIPLY] = 0x37, + [SDL_SCANCODE_LALT] = 0x38, + [SDL_SCANCODE_SPACE] = 0x39, + [SDL_SCANCODE_CAPSLOCK] = 0x3A, + [SDL_SCANCODE_F1] = 0x3B, + [SDL_SCANCODE_F2] = 0x3C, + [SDL_SCANCODE_F3] = 0x3D, + [SDL_SCANCODE_F4] = 0x3E, + [SDL_SCANCODE_F5] = 0x3F, + [SDL_SCANCODE_F6] = 0x40, + [SDL_SCANCODE_F7] = 0x41, + [SDL_SCANCODE_F8] = 0x42, + [SDL_SCANCODE_F9] = 0x43, + [SDL_SCANCODE_F10] = 0x44, + [SDL_SCANCODE_NUMLOCKCLEAR] = 0x45, + [SDL_SCANCODE_SCROLLLOCK] = 0x46, + [SDL_SCANCODE_HOME] = 0x147, + [SDL_SCANCODE_UP] = 0x148, + [SDL_SCANCODE_PAGEUP] = 0x149, + [SDL_SCANCODE_KP_MINUS] = 0x4A, + [SDL_SCANCODE_LEFT] = 0x14B, + [SDL_SCANCODE_KP_5] = 0x4C, + [SDL_SCANCODE_RIGHT] = 0x14D, + [SDL_SCANCODE_KP_PLUS] = 0x4E, + [SDL_SCANCODE_END] = 0x14F, + [SDL_SCANCODE_DOWN] = 0x150, + [SDL_SCANCODE_PAGEDOWN] = 0x151, + [SDL_SCANCODE_INSERT] = 0x152, + [SDL_SCANCODE_DELETE] = 0x153, + [SDL_SCANCODE_F11] = 0x57, + [SDL_SCANCODE_F12] = 0x58, + + [SDL_SCANCODE_KP_ENTER] = 0x11c, + [SDL_SCANCODE_RCTRL] = 0x11d, + [SDL_SCANCODE_KP_DIVIDE] = 0x135, + [SDL_SCANCODE_RALT] = 0x138, + [SDL_SCANCODE_KP_9] = 0x49, + [SDL_SCANCODE_KP_8] = 0x48, + [SDL_SCANCODE_KP_7] = 0x47, + [SDL_SCANCODE_KP_6] = 0x4D, + [SDL_SCANCODE_KP_4] = 0x4B, + [SDL_SCANCODE_KP_3] = 0x51, + [SDL_SCANCODE_KP_2] = 0x50, + [SDL_SCANCODE_KP_1] = 0x4F, + [SDL_SCANCODE_KP_0] = 0x52, + [SDL_SCANCODE_KP_PERIOD] = 0x53, + + [SDL_SCANCODE_LGUI] = 0x15B, + [SDL_SCANCODE_RGUI] = 0x15C, + [SDL_SCANCODE_APPLICATION] = 0x15D, + [SDL_SCANCODE_PRINTSCREEN] = 0x137, + [SDL_SCANCODE_NONUSBACKSLASH] = 0x56, +}; + +typedef struct mouseinputdata +{ + int deltax, deltay, deltaz; + int mousebuttons; +} mouseinputdata; +static mouseinputdata mousedata; + +// #define ENABLE_SDL_LOG 3 +#ifdef ENABLE_SDL_LOG +int sdl_do_log = ENABLE_SDL_LOG; + +static void +sdl_log(const char *fmt, ...) +{ + va_list ap; + + if (sdl_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sdl_log(fmt, ...) +#endif + + +static void +sdl_integer_scale(double *d, double *g) +{ + double ratio; + + if (*d > *g) { + ratio = floor(*d / *g); + *d = *g * ratio; + } else { + ratio = ceil(*d / *g); + *d = *g / ratio; + } +} + + +static void +sdl_stretch(int *w, int *h, int *x, int *y) +{ + double hw, gw, hh, gh, dx, dy, dw, dh, gsr, hsr; + + hw = (double) sdl_w; + hh = (double) sdl_h; + gw = (double) *w; + gh = (double) *h; + hsr = hw / hh; + + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_FULL: + default: + *w = sdl_w; + *h = sdl_h; + *x = 0; + *y = 0; + break; + case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = (int) dy; + break; + case FULLSCR_SCALE_INT: + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + sdl_integer_scale(&dw, &gw); + sdl_integer_scale(&dh, &gh); + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = (int) dy; + break; + } +} + +static void +sdl_blit(int x, int y, int w, int h) +{ + SDL_Rect r_src; + void *pixeldata; + int ret, pitch; + + if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) { + video_blit_complete(); + return; + } + + SDL_LockMutex(sdl_mutex); + SDL_LockTexture(sdl_tex, 0, &pixeldata, &pitch); + + video_copy(pixeldata, &(buffer32->line[y][x]), h * (2048) * sizeof(uint32_t)); + + if (monitors[m_monitor_index].mon_screenshots) + video_screenshot((uint32_t *) pixeldata, 0, 0, (2048)); + + SDL_UnlockTexture(sdl_tex); + + video_blit_complete(); + + SDL_RenderClear(sdl_render); + + r_src.x = 0; + r_src.y = 0; + r_src.w = w; + r_src.h = h; + + ret = SDL_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + if (ret) + sdl_log("SDL: unable to copy texture to renderer (%s)\n", sdl_GetError()); + + SDL_RenderPresent(sdl_render); + + SDL_UnlockMutex(sdl_mutex); +} + + +static void +sdl_destroy_window(void) +{ + if (sdl_win != NULL) { + SDL_DestroyWindow(sdl_win); + sdl_win = NULL; + } +} + + +static void +sdl_destroy_texture(void) +{ + if (sdl_tex != NULL) { + SDL_DestroyTexture(sdl_tex); + sdl_tex = NULL; + } + + /* SDL_DestroyRenderer also automatically destroys all associated textures. */ + if (sdl_render != NULL) { + SDL_DestroyRenderer(sdl_render); + sdl_render = NULL; + } +} + + +void +sdl_close(void) +{ + if (sdl_mutex != NULL) + SDL_LockMutex(sdl_mutex); + + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_enabled) + sdl_enabled = 0; + + if (sdl_mutex != NULL) { + SDL_DestroyMutex(sdl_mutex); + sdl_mutex = NULL; + } + + sdl_destroy_texture(); + sdl_destroy_window(); + + /* Quit. */ + SDL_Quit(); + sdl_flags = -1; +} + +static void sdl_select_best_hw_driver(void) { + int i; + SDL_RendererInfo renderInfo; + + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { + SDL_GetRenderDriverInfo(i, &renderInfo); + if (renderInfo.flags & SDL_RENDERER_ACCELERATED) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, renderInfo.name); + return; + } + } +} + +static void +sdl_init_texture(void) +{ + if (sdl_flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + } else { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + } + + sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, (2048), (2048)); + + if (sdl_render == NULL) { + sdl_log("SDL: unable to SDL_CreateRenderer (%s)\n", SDL_GetError()); + } + if (sdl_tex == NULL) { + sdl_log("SDL: unable to SDL_CreateTexture (%s)\n", SDL_GetError()); + } +} + + +static void +sdl_reinit_texture(void) +{ + if (sdl_flags == -1) + return; + + sdl_destroy_texture(); + sdl_init_texture(); +} + + +void sdl_set_fs(int fs) { + SDL_SetWindowFullscreen(sdl_win, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_SetRelativeMouseMode((SDL_bool)mouse_capture); + + sdl_fs = fs; + + if (fs) { + sdl_flags |= RENDERER_FULL_SCREEN; + } else { + sdl_flags &= ~RENDERER_FULL_SCREEN; + } + + sdl_reinit_texture(); +} + + +static int +sdl_init_common(void* win, int flags) +{ + wchar_t temp[128]; + SDL_version ver; + + sdl_log("SDL: init (fs=%d)\n", 0); + + /* Get and log the version of the DLL we are using. */ + SDL_GetVersion(&ver); + sdl_log("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + sdl_log("SDL: initialization failed (%s)\n", SDL_GetError()); + return(0); + } + + if (flags & RENDERER_HARDWARE) { + if (flags & RENDERER_OPENGL) + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "OpenGL"); + else + sdl_select_best_hw_driver(); + } + + /* Get the size of the (current) desktop. */ + SDL_DisplayMode dm; + if (SDL_GetDesktopDisplayMode(0, &dm) != 0) { + sdl_log("SDL: SDL_GetDesktopDisplayMode failed (%s)\n", SDL_GetError()); + return(0); + } + sdl_w = dm.w; + sdl_h = dm.h; + sdl_flags = flags; + + sdl_win = SDL_CreateWindow("86Box renderer", 640, 480, 100, 100, sdl_flags); + if (sdl_win == NULL) { + sdl_log("SDL: unable to CreateWindowFrom (%s)\n", SDL_GetError()); + } + sdl_init_texture(); + sdl_set_fs(video_fullscreen & 1); + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit); + + sdl_enabled = 1; + sdl_mutex = SDL_CreateMutex(); + + return(1); +} + + +int +sdl_inits(void* win) +{ + return sdl_init_common(win, 0); +} + + +int +sdl_inith(void* win) +{ + return sdl_init_common(win, RENDERER_HARDWARE); +} + + +int +sdl_initho(void* win) +{ + return sdl_init_common(win, RENDERER_HARDWARE | RENDERER_OPENGL); +} + + +int +sdl_pause(void) +{ + return(0); +} + + +void +sdl_resize(int w, int h) +{ + int ww = 0, wh = 0; + + if (video_fullscreen & 2) + return; + + if ((w == cur_w) && (h == cur_h)) + return; + + SDL_LockMutex(sdl_mutex); + + ww = w; + wh = h; + + if (sdl_fs) { +// sdl_stretch(&ww, &wh, &wx, &wy); +// MoveWindow(hwndRender, wx, wy, ww, wh, TRUE); + } + + cur_w = w; + cur_h = h; + + cur_ww = ww; + cur_wh = wh; + + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); +} + + +void +sdl_enable(int enable) +{ + if (sdl_flags == -1) + return; + + SDL_LockMutex(sdl_mutex); + sdl_enabled = !!enable; + + if (enable == 1) { + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + sdl_reinit_texture(); + } + + SDL_UnlockMutex(sdl_mutex); +} + + +void +sdl_reload(void) +{ + if (sdl_flags & RENDERER_HARDWARE) { + SDL_LockMutex(sdl_mutex); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); + } +} + +static int mouse_inside = 0; +enum sdl_main_status sdl_main() { + int ret = SdlMainOk; + SDL_Rect r_src; + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + switch(event.type) + { + case SDL_QUIT: + ret = SdlMainQuit; + break; + case SDL_MOUSEWHEEL: + { + if (mouse_capture || video_fullscreen) + { + if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) + { + event.wheel.x *= -1; + event.wheel.y *= -1; + } + mousedata.deltaz = event.wheel.y; + } + break; + } + case SDL_MOUSEMOTION: + { + if (mouse_capture || video_fullscreen) + { + mousedata.deltax += event.motion.xrel; + mousedata.deltay += event.motion.yrel; + } + break; + } + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + if ((event.button.button == SDL_BUTTON_LEFT) + && !(mouse_capture || video_fullscreen) + && event.button.state == SDL_RELEASED + && mouse_inside) + { + plat_mouse_capture(1); + break; + } + if (mouse_get_buttons() < 3 && event.button.button == SDL_BUTTON_MIDDLE && !video_fullscreen) + { + plat_mouse_capture(0); + break; + } + if (mouse_capture || video_fullscreen) + { + int buttonmask = 0; + + switch(event.button.button) + { + case SDL_BUTTON_LEFT: + buttonmask = 1; + break; + case SDL_BUTTON_RIGHT: + buttonmask = 2; + break; + case SDL_BUTTON_MIDDLE: + buttonmask = 4; + break; + } + if (event.button.state == SDL_PRESSED) + { + mousedata.mousebuttons |= buttonmask; + } + else mousedata.mousebuttons &= ~buttonmask; + } + break; + } + case SDL_RENDER_DEVICE_RESET: + case SDL_RENDER_TARGETS_RESET: + { + sdl_reinit_texture(); + break; + } + case SDL_KEYDOWN: + case SDL_KEYUP: + { + uint16_t xtkey = 0; + switch(event.key.keysym.scancode) + { + default: + xtkey = sdl_to_xt[event.key.keysym.scancode]; + break; + } + keyboard_input(event.key.state == SDL_PRESSED, xtkey); + } + break; + case SDL_WINDOWEVENT: + { + switch (event.window.event) + { + case SDL_WINDOWEVENT_ENTER: + mouse_inside = 1; + break; + case SDL_WINDOWEVENT_LEAVE: + mouse_inside = 0; + break; + } + } + } + } + + if (mouse_capture && keyboard_ismsexit()) { + plat_mouse_capture(0); + } + if (video_fullscreen && keyboard_isfsexit()) { + plat_setfullscreen(0); + } + + return ret; +} + +void sdl_mouse_capture(int on) { + SDL_SetRelativeMouseMode((SDL_bool)on); +} + +void sdl_mouse_poll() { + mouse_x = mousedata.deltax; + mouse_y = mousedata.deltay; + mouse_z = mousedata.deltaz; + mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; + mouse_buttons = mousedata.mousebuttons; +} diff --git a/src/qt/qt_sdl.h b/src/qt/qt_sdl.h new file mode 100644 index 000000000..02fd47ddf --- /dev/null +++ b/src/qt/qt_sdl.h @@ -0,0 +1,73 @@ +/* + * 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. + * + * Definitions for the libSDL2 rendering module. + * + * + * + * Authors: Fred N. van Kempen, + * Michael Drüing, + * + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Michael Drüing. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef WIN_SDL_H +# define WIN_SDL_H + +extern void* sdl_win_handle; +extern void sdl_close(void); +extern int sdl_inits(); +extern int sdl_inith(); +extern int sdl_initho(); +extern int sdl_pause(void); +extern void sdl_resize(int w, int h); +extern void sdl_enable(int enable); +extern void sdl_set_fs(int fs); +extern void sdl_reload(void); + +enum sdl_main_status { + SdlMainOk, + SdlMainQuit, +}; + +extern enum sdl_main_status sdl_main(); + +extern void sdl_mouse_capture(int on); +extern void sdl_mouse_poll(); + +#endif /*WIN_SDL_H*/ diff --git a/src/qt/qt_settings.cpp b/src/qt/qt_settings.cpp new file mode 100644 index 000000000..290b95982 --- /dev/null +++ b/src/qt/qt_settings.cpp @@ -0,0 +1,191 @@ +/* + * 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. + * + * Program settings UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + */ +#include "qt_settings.hpp" +#include "ui_qt_settings.h" + +#include "qt_settingsmachine.hpp" +#include "qt_settingsdisplay.hpp" +#include "qt_settingsinput.hpp" +#include "qt_settingssound.hpp" +#include "qt_settingsnetwork.hpp" +#include "qt_settingsports.hpp" +#include "qt_settingsstoragecontrollers.hpp" +#include "qt_settingsharddisks.hpp" +#include "qt_settingsfloppycdrom.hpp" +#include "qt_settingsotherremovable.hpp" +#include "qt_settingsotherperipherals.hpp" + +#include "qt_progsettings.hpp" +#include "qt_harddrive_common.hpp" +#include "qt_settings_bus_tracking.hpp" + +extern "C" +{ +#include <86box/86box.h> +} + +#include +#include +#include +#include +#include + +class SettingsModel : public QAbstractListModel { +public: + SettingsModel(QObject* parent) : QAbstractListModel(parent) {} + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; +private: + QStringList pages = { + "Machine", + "Display", + "Input devices", + "Sound", + "Network", + "Ports (COM & LPT)", + "Storage controllers", + "Hard disks", + "Floppy & CD-ROM drives", + "Other removable devices", + "Other peripherals", + }; + QStringList page_icons = { + "machine", + "display", + "input_devices", + "sound", + "network", + "ports", + "storage_controllers", + "hard_disk", + "floppy_and_cdrom_drives", + "other_removable_devices", + "other_peripherals", + }; +}; + +QVariant SettingsModel::data(const QModelIndex &index, int role) const { + Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); + + switch (role) { + case Qt::DisplayRole: + return tr(pages.at(index.row()).toUtf8().data()); + case Qt::DecorationRole: + return QIcon(QString("%1/%2.ico").arg(ProgSettings::getIconSetPath(), page_icons[index.row()])); + default: + return {}; + } +} + +int SettingsModel::rowCount(const QModelIndex &parent) const { + (void) parent; + return pages.size(); +} + +Settings* Settings::settings = nullptr;; +Settings::Settings(QWidget *parent) : + QDialog(parent), + ui(new Ui::Settings) +{ + ui->setupUi(this); + ui->listView->setModel(new SettingsModel(this)); + + Harddrives::busTrackClass = new SettingsBusTracking; + machine = new SettingsMachine(this); + display = new SettingsDisplay(this); + input = new SettingsInput(this); + sound = new SettingsSound(this); + network = new SettingsNetwork(this); + ports = new SettingsPorts(this); + storageControllers = new SettingsStorageControllers(this); + harddisks = new SettingsHarddisks(this); + floppyCdrom = new SettingsFloppyCDROM(this); + otherRemovable = new SettingsOtherRemovable(this); + otherPeripherals = new SettingsOtherPeripherals(this); + + ui->stackedWidget->addWidget(machine); + ui->stackedWidget->addWidget(display); + ui->stackedWidget->addWidget(input); + ui->stackedWidget->addWidget(sound); + ui->stackedWidget->addWidget(network); + ui->stackedWidget->addWidget(ports); + ui->stackedWidget->addWidget(storageControllers); + ui->stackedWidget->addWidget(harddisks); + ui->stackedWidget->addWidget(floppyCdrom); + ui->stackedWidget->addWidget(otherRemovable); + ui->stackedWidget->addWidget(otherPeripherals); + + connect(machine, &SettingsMachine::currentMachineChanged, display, &SettingsDisplay::onCurrentMachineChanged); + connect(machine, &SettingsMachine::currentMachineChanged, input, &SettingsInput::onCurrentMachineChanged); + connect(machine, &SettingsMachine::currentMachineChanged, sound, &SettingsSound::onCurrentMachineChanged); + connect(machine, &SettingsMachine::currentMachineChanged, network, &SettingsNetwork::onCurrentMachineChanged); + connect(machine, &SettingsMachine::currentMachineChanged, storageControllers, &SettingsStorageControllers::onCurrentMachineChanged); + connect(machine, &SettingsMachine::currentMachineChanged, otherPeripherals, &SettingsOtherPeripherals::onCurrentMachineChanged); + + connect(ui->listView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex ¤t, const QModelIndex &previous) { + ui->stackedWidget->setCurrentIndex(current.row()); + }); + + ui->listView->setMinimumWidth(ui->listView->sizeHintForColumn(0) + qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent)); + + Settings::settings = this; +} + +Settings::~Settings() +{ + delete ui; + delete Harddrives::busTrackClass; + Harddrives::busTrackClass = nullptr; + Settings::settings = nullptr; +} + +void Settings::save() { + machine->save(); + display->save(); + input->save(); + sound->save(); + network->save(); + ports->save(); + storageControllers->save(); + harddisks->save(); + floppyCdrom->save(); + otherRemovable->save(); + otherPeripherals->save(); +} + +void Settings::accept() +{ + if (confirm_save && !settings_only) + { + QMessageBox questionbox(QMessageBox::Icon::Question, "86Box", QStringLiteral("%1\n\n%2").arg(tr("Do you want to save the settings?"), tr("This will hard reset the emulated machine.")), QMessageBox::Save | QMessageBox::Cancel, this); + QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); + questionbox.setCheckBox(chkbox); + chkbox->setChecked(!confirm_save); + QObject::connect(chkbox, &QCheckBox::stateChanged, [](int state) { + confirm_save = (state == Qt::CheckState::Unchecked); + }); + questionbox.exec(); + if (questionbox.result() == QMessageBox::Cancel) { + confirm_save = true; + return; + } + } + QDialog::accept(); +} diff --git a/src/qt/qt_settings.hpp b/src/qt/qt_settings.hpp new file mode 100644 index 000000000..7e0a78cfa --- /dev/null +++ b/src/qt/qt_settings.hpp @@ -0,0 +1,50 @@ +#ifndef QT_SETTINGS_HPP +#define QT_SETTINGS_HPP + +#include + +namespace Ui { +class Settings; +} + +class SettingsMachine; +class SettingsDisplay; +class SettingsInput; +class SettingsSound; +class SettingsNetwork; +class SettingsPorts; +class SettingsStorageControllers; +class SettingsHarddisks; +class SettingsFloppyCDROM; +class SettingsOtherRemovable; +class SettingsOtherPeripherals; + +class Settings : public QDialog +{ + Q_OBJECT + +public: + explicit Settings(QWidget *parent = nullptr); + ~Settings(); + void save(); + + static Settings* settings; +protected slots: + void accept() override; + +private: + Ui::Settings *ui; + SettingsMachine* machine; + SettingsDisplay* display; + SettingsInput* input; + SettingsSound* sound; + SettingsNetwork* network; + SettingsPorts* ports; + SettingsStorageControllers* storageControllers; + SettingsHarddisks* harddisks; + SettingsFloppyCDROM* floppyCdrom; + SettingsOtherRemovable* otherRemovable; + SettingsOtherPeripherals* otherPeripherals; +}; + +#endif // QT_SETTINGS_HPP diff --git a/src/qt/qt_settings.ui b/src/qt/qt_settings.ui new file mode 100644 index 000000000..ec3198ebe --- /dev/null +++ b/src/qt/qt_settings.ui @@ -0,0 +1,103 @@ + + + Settings + + + + 0 + 0 + 831 + 595 + + + + + 831 + 595 + + + + + 831 + 595 + + + + Settings + + + + + + + + + QListView::ListMode + + + + + + + -1 + + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Settings + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Settings + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_settings_bus_tracking.cpp b/src/qt/qt_settings_bus_tracking.cpp new file mode 100644 index 000000000..a1d8e3369 --- /dev/null +++ b/src/qt/qt_settings_bus_tracking.cpp @@ -0,0 +1,273 @@ +/* + * 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. + * + * Program settings UI module. + * + * + * + * Authors: Miran Grca + * Cacodemon345 + * + * Copyright 2022 Miran Grca + * Copyright 2022 Cacodemon345 + */ +#include +#include +#include +#include + +#include "86box/hdd.h" +#include "qt_settings_bus_tracking.hpp" + + +SettingsBusTracking::SettingsBusTracking() +{ + int i; + + mfm_tracking = 0x0000000000000000ULL; + esdi_tracking = 0x0000000000000000ULL; + xta_tracking = 0x0000000000000000ULL; + + for (i = 0; i < 8; i++) { + if (i < 4) + ide_tracking[i] = 0x0000000000000000ULL; + + scsi_tracking[i] = 0x0000000000000000ULL; + } +} + + +uint8_t +SettingsBusTracking::next_free_mfm_channel() +{ + if ((mfm_tracking & 0xff00ULL) && !(mfm_tracking & 0x00ffULL)) + return 1; + + if (!(mfm_tracking & 0xff00ULL) && (mfm_tracking & 0x00ffULL)) + return 0; + + return CHANNEL_NONE; +} + + +uint8_t +SettingsBusTracking::next_free_esdi_channel() +{ + if ((esdi_tracking & 0xff00ULL) && !(esdi_tracking & 0x00ffULL)) + return 1; + + if (!(esdi_tracking & 0xff00ULL) && (esdi_tracking & 0x00ffULL)) + return 0; + + return CHANNEL_NONE; +} + + +uint8_t +SettingsBusTracking::next_free_xta_channel() +{ + if ((xta_tracking & 0xff00ULL) && !(xta_tracking & 0x00ffULL)) + return 1; + + if (!(xta_tracking & 0xff00ULL) && (xta_tracking & 0x00ffULL)) + return 0; + + return CHANNEL_NONE; +} + + +uint8_t +SettingsBusTracking::next_free_ide_channel() +{ + int i, element; + uint64_t mask; + uint8_t ret = CHANNEL_NONE; + + for (i = 0; i < 32; i++) { + element = ((i << 3) >> 6); + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (!(ide_tracking[element] & mask)) { + ret = (uint8_t) i; + break; + } + } + + return ret; +} + + +uint8_t +SettingsBusTracking::next_free_scsi_id() +{ + int i, element; + uint64_t mask; + uint8_t ret = CHANNEL_NONE; + + for (i = 0; i < 64; i++) { + element = ((i << 3) >> 6); + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (!(scsi_tracking[element] & mask)) { + ret = (uint8_t) i; + break; + } + } + + return ret; +} + + +int +SettingsBusTracking::mfm_bus_full() +{ + int i; + uint64_t mask; + uint8_t count = 0; + + for (i = 0; i < 2; i++) { + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (mfm_tracking & mask) + count++; + } + + return (count == 2); +} + + +int +SettingsBusTracking::esdi_bus_full() +{ + int i; + uint64_t mask; + uint8_t count = 0; + + for (i = 0; i < 2; i++) { + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (esdi_tracking & mask) + count++; + } + + return (count == 2); +} + + +int +SettingsBusTracking::xta_bus_full() +{ + int i; + uint64_t mask; + uint8_t count = 0; + + for (i = 0; i < 2; i++) { + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (xta_tracking & mask) + count++; + } + + return (count == 2); +} + + +int +SettingsBusTracking::ide_bus_full() +{ + int i, element; + uint64_t mask; + uint8_t count = 0; + + for (i = 0; i < 32; i++) { + element = ((i << 3) >> 6); + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (ide_tracking[element] & mask) + count++; + } + + return (count == 32); +} + + +int +SettingsBusTracking::scsi_bus_full() +{ + int i, element; + uint64_t mask; + uint8_t count = 0; + + for (i = 0; i < 64; i++) { + element = ((i << 3) >> 6); + mask = 0xffULL << ((uint64_t) ((i << 3) & 0x3f)); + + if (scsi_tracking[element] & mask) + count++; + } + + return (count == 64); +} + + +void +SettingsBusTracking::device_track(int set, uint8_t dev_type, int bus, int channel) +{ + int element; + uint64_t mask; + + switch (bus) { + case HDD_BUS_MFM: + mask = ((uint64_t) dev_type) << ((uint64_t) ((channel << 3) & 0x3f)); + + if (set) + mfm_tracking |= mask; + else + mfm_tracking &= ~mask; + break; + + case HDD_BUS_ESDI: + mask = ((uint64_t) dev_type) << ((uint64_t) ((channel << 3) & 0x3f)); + + if (set) + esdi_tracking |= mask; + else + esdi_tracking &= ~mask; + break; + + case HDD_BUS_XTA: + mask = ((uint64_t) dev_type) << ((uint64_t) ((channel << 3) & 0x3f)); + + if (set) + xta_tracking |= mask; + else + xta_tracking &= ~mask; + break; + + case HDD_BUS_IDE: + case HDD_BUS_ATAPI: + element = ((channel << 3) >> 6); + mask = ((uint64_t) dev_type) << ((uint64_t) ((channel << 3) & 0x3f)); + + if (set) + ide_tracking[element] |= mask; + else + ide_tracking[element] &= ~mask; + break; + + case HDD_BUS_SCSI: + element = ((channel << 3) >> 6); + mask = ((uint64_t) dev_type) << ((uint64_t) ((channel << 3) & 0x3f)); + + if (set) + scsi_tracking[element] |= mask; + else + scsi_tracking[element] &= ~mask; + break; + } +} diff --git a/src/qt/qt_settings_bus_tracking.hpp b/src/qt/qt_settings_bus_tracking.hpp new file mode 100644 index 000000000..0272b4359 --- /dev/null +++ b/src/qt/qt_settings_bus_tracking.hpp @@ -0,0 +1,63 @@ +#ifndef QT_SETTINGS_BUS_TRACKING_HPP +#define QT_SETTINGS_BUS_TRACKING_HPP + +#include + +#define TRACK_CLEAR 0 +#define TRACK_SET 1 + +#define DEV_HDD 0x01 +#define DEV_CDROM 0x02 +#define DEV_ZIP 0x04 +#define DEV_MO 0x08 + +#define BUS_MFM 0 +#define BUS_ESDI 1 +#define BUS_XTA 2 +#define BUS_IDE 3 +#define BUS_SCSI 4 + +#define CHANNEL_NONE 0xff + +namespace Ui { +class SettingsBusTracking; +} + +class SettingsBusTracking +{ +public: + explicit SettingsBusTracking(); + ~SettingsBusTracking() = default; + + /* These return 0xff is none is free. */ + uint8_t next_free_mfm_channel(); + uint8_t next_free_esdi_channel(); + uint8_t next_free_xta_channel(); + uint8_t next_free_ide_channel(); + uint8_t next_free_scsi_id(); + + int mfm_bus_full(); + int esdi_bus_full(); + int xta_bus_full(); + int ide_bus_full(); + int scsi_bus_full(); + + /* Set: 0 = Clear the device from the tracking, 1 = Set the device on the tracking. + Device type: 1 = Hard Disk, 2 = CD-ROM, 4 = ZIP, 8 = Magneto-Optical. + Bus: 0 = MFM, 1 = ESDI, 2 = XTA, 3 = IDE, 4 = SCSI. */ + void device_track(int set, uint8_t dev_type, int bus, int channel); + +private: + /* 1 channel, 2 devices per channel, 8 bits per device = 16 bits. */ + uint64_t mfm_tracking{0}; + /* 1 channel, 2 devices per channel, 8 bits per device = 16 bits. */ + uint64_t esdi_tracking{0}; + /* 1 channel, 2 devices per channel, 8 bits per device = 16 bits. */ + uint64_t xta_tracking{0}; + /* 16 channels (prepatation for that weird IDE card), 2 devices per channel, 8 bits per device = 256 bits. */ + uint64_t ide_tracking[4]{0, 0, 0, 0}; + /* 4 buses, 16 devices per bus, 8 bits per device (future-proofing) = 512 bits. */ + uint64_t scsi_tracking[8]{0, 0, 0, 0, 0, 0, 0, 0}; +}; + +#endif // QT_SETTINGS_BUS_TRACKING_HPP diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp new file mode 100644 index 000000000..84054806d --- /dev/null +++ b/src/qt/qt_settingsdisplay.cpp @@ -0,0 +1,207 @@ +/* + * 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. + * + * Display settings UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsdisplay.hpp" +#include "ui_qt_settingsdisplay.h" + +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/video.h> +#include <86box/vid_xga_device.h> +} + +#include "qt_deviceconfig.hpp" +#include "qt_models_common.hpp" + +SettingsDisplay::SettingsDisplay(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsDisplay) +{ + ui->setupUi(this); + + onCurrentMachineChanged(machine); +} + +SettingsDisplay::~SettingsDisplay() +{ + delete ui; +} + +void SettingsDisplay::save() { + gfxcard = ui->comboBoxVideo->currentData().toInt(); + gfxcard_2 = ui->comboBoxVideoSecondary->currentData().toInt(); + voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0; + ibm8514_enabled = ui->checkBox8514->isChecked() ? 1 : 0; + xga_enabled = ui->checkBoxXga->isChecked() ? 1 : 0; +} + +void SettingsDisplay::onCurrentMachineChanged(int machineId) { + // win_settings_video_proc, WM_INITDIALOG + this->machineId = machineId; + + auto* model = ui->comboBoxVideo->model(); + auto removeRows = model->rowCount(); + + int c = 0; + int selectedRow = 0; + while (true) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && (machine_has_flags(machineId, MACHINE_VIDEO) == 0)) { + c++; + continue; + } + + const device_t* video_dev = video_card_getdevice(c); + QString name = DeviceConfig::DeviceName(video_dev, video_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (video_card_available(c) && + device_is_valid(video_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == gfxcard) { + selectedRow = row - removeRows; + } + } + + c++; + } + model->removeRows(0, removeRows); + + if (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0) { + ui->comboBoxVideo->setEnabled(false); + ui->comboBoxVideoSecondary->setEnabled(false); + ui->pushButtonConfigureSecondary->setEnabled(false); + selectedRow = 1; + } else { + ui->comboBoxVideo->setEnabled(true); + ui->comboBoxVideoSecondary->setEnabled(true); + ui->pushButtonConfigureSecondary->setEnabled(true); + } + ui->comboBoxVideo->setCurrentIndex(selectedRow); + if (gfxcard_2 == 0) ui->pushButtonConfigureSecondary->setEnabled(false); +} + +void SettingsDisplay::on_pushButtonConfigure_clicked() { + auto* device = video_card_getdevice(ui->comboBoxVideo->currentData().toInt()); + DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); +} + +void SettingsDisplay::on_pushButtonConfigureVoodoo_clicked() { + DeviceConfig::ConfigureDevice(&voodoo_device, 0, qobject_cast(Settings::settings)); +} + +void SettingsDisplay::on_pushButtonConfigureXga_clicked() { + if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) { + DeviceConfig::ConfigureDevice(&xga_device, 0, qobject_cast(Settings::settings)); + } else { + DeviceConfig::ConfigureDevice(&xga_isa_device, 0, qobject_cast(Settings::settings)); + } +} + +void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) { + if (index < 0) { + return; + } + int videoCard = ui->comboBoxVideo->currentData().toInt(); + ui->pushButtonConfigure->setEnabled(video_card_has_config(videoCard) > 0); + + bool machineHasPci = machine_has_bus(machineId, MACHINE_BUS_PCI) > 0; + ui->checkBoxVoodoo->setEnabled(machineHasPci); + if (machineHasPci) { + ui->checkBoxVoodoo->setChecked(voodoo_enabled); + } + ui->pushButtonConfigureVoodoo->setEnabled(machineHasPci && ui->checkBoxVoodoo->isChecked()); + + bool hasIsa16 = machine_has_bus(machineId, MACHINE_BUS_ISA16) > 0; + bool has_MCA = machine_has_bus(machineId, MACHINE_BUS_MCA) > 0; + ui->checkBox8514->setEnabled(hasIsa16 || has_MCA); + if (hasIsa16 || has_MCA) { + ui->checkBox8514->setChecked(ibm8514_enabled); + } + + ui->checkBoxXga->setEnabled(hasIsa16 || has_MCA); + if (hasIsa16 || has_MCA) + ui->checkBoxXga->setChecked(xga_enabled); + + ui->pushButtonConfigureXga->setEnabled((hasIsa16 || has_MCA) && ui->checkBoxXga->isChecked()); + + int c = 2; + + ui->comboBoxVideoSecondary->clear(); + ui->comboBoxVideoSecondary->addItem(QObject::tr("None"), 0); + + ui->comboBoxVideoSecondary->setCurrentIndex(0); + // TODO: Implement support for selecting non-MDA secondary cards properly when MDA cards are the primary ones. + if (video_card_get_flags(videoCard) == VIDEO_FLAG_TYPE_MDA) { + ui->comboBoxVideoSecondary->setCurrentIndex(0); + return; + } + while (true) { + const device_t* video_dev = video_card_getdevice(c); + QString name = DeviceConfig::DeviceName(video_dev, video_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (video_card_available(c) && + device_is_valid(video_dev, machineId) && + !(video_card_get_flags(c) == video_card_get_flags(videoCard))) { + ui->comboBoxVideoSecondary->addItem(name, c); + if (c == gfxcard_2) + ui->comboBoxVideoSecondary->setCurrentIndex(ui->comboBoxVideoSecondary->count() - 1); + } + + c++; + } + + if (gfxcard_2 == 0 || (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0)) + { + ui->comboBoxVideoSecondary->setCurrentIndex(0); + ui->pushButtonConfigureSecondary->setEnabled(false); + } +} + +void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) { + ui->pushButtonConfigureVoodoo->setEnabled(state == Qt::Checked); +} + +void SettingsDisplay::on_checkBoxXga_stateChanged(int state) { + ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked); +} + +void SettingsDisplay::on_comboBoxVideoSecondary_currentIndexChanged(int index) +{ + if (index < 0) { + ui->pushButtonConfigureSecondary->setEnabled(false); + return; + } + int videoCard = ui->comboBoxVideoSecondary->currentData().toInt(); + ui->pushButtonConfigureSecondary->setEnabled(index != 0 && video_card_has_config(videoCard) > 0); +} + + +void SettingsDisplay::on_pushButtonConfigureSecondary_clicked() +{ + auto* device = video_card_getdevice(ui->comboBoxVideoSecondary->currentData().toInt()); + DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); +} + diff --git a/src/qt/qt_settingsdisplay.hpp b/src/qt/qt_settingsdisplay.hpp new file mode 100644 index 000000000..06badd656 --- /dev/null +++ b/src/qt/qt_settingsdisplay.hpp @@ -0,0 +1,42 @@ +#ifndef QT_SETTINGSDISPLAY_HPP +#define QT_SETTINGSDISPLAY_HPP + +#include + +namespace Ui { +class SettingsDisplay; +} + +class SettingsDisplay : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsDisplay(QWidget *parent = nullptr); + ~SettingsDisplay(); + + void save(); + +public slots: + void onCurrentMachineChanged(int machineId); + +private slots: + void on_pushButtonConfigureSecondary_clicked(); + +private slots: + void on_comboBoxVideoSecondary_currentIndexChanged(int index); + +private slots: + void on_checkBoxVoodoo_stateChanged(int state); + void on_checkBoxXga_stateChanged(int state); + void on_comboBoxVideo_currentIndexChanged(int index); + void on_pushButtonConfigureVoodoo_clicked(); + void on_pushButtonConfigureXga_clicked(); + void on_pushButtonConfigure_clicked(); + +private: + Ui::SettingsDisplay *ui; + int machineId = 0; +}; + +#endif // QT_SETTINGSDISPLAY_HPP diff --git a/src/qt/qt_settingsdisplay.ui b/src/qt/qt_settingsdisplay.ui new file mode 100644 index 000000000..c9bbaf1c7 --- /dev/null +++ b/src/qt/qt_settingsdisplay.ui @@ -0,0 +1,121 @@ + + + SettingsDisplay + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 8514/A + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + Voodoo Graphics + + + + + + + Configure + + + + + + + Video: + + + + + + + XGA + + + + + + + Configure + + + + + + + Video #2: + + + + + + + + + + Configure + + + + + + + + diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp new file mode 100644 index 000000000..bf26c5162 --- /dev/null +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -0,0 +1,253 @@ +/* + * 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. + * + * Floppy/CD-ROM devices configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsfloppycdrom.hpp" +#include "ui_qt_settingsfloppycdrom.h" + +extern "C" { +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/cdrom.h> +} + +#include + +#include "qt_models_common.hpp" +#include "qt_harddrive_common.hpp" +#include "qt_settings_bus_tracking.hpp" +#include "qt_progsettings.hpp" + +static void setFloppyType(QAbstractItemModel* model, const QModelIndex& idx, int type) { + QIcon icon; + if (type == 0) { + icon = ProgSettings::loadIcon("/floppy_disabled.ico"); + } else if (type >= 1 && type <= 6) { + icon = ProgSettings::loadIcon("/floppy_525.ico"); + } else { + icon = ProgSettings::loadIcon("/floppy_35.ico"); + } + + model->setData(idx, QObject::tr(fdd_getname(type))); + model->setData(idx, type, Qt::UserRole); + model->setData(idx, icon, Qt::DecorationRole); +} + +static void setCDROMBus(QAbstractItemModel* model, const QModelIndex& idx, uint8_t bus, uint8_t channel) { + QIcon icon; + switch (bus) { + case CDROM_BUS_DISABLED: + icon = ProgSettings::loadIcon("/cdrom_disabled.ico"); + break; + case CDROM_BUS_ATAPI: + case CDROM_BUS_SCSI: + icon = ProgSettings::loadIcon("/cdrom.ico"); + break; + } + + auto i = idx.siblingAtColumn(0); + model->setData(i, Harddrives::BusChannelName(bus, channel)); + model->setData(i, bus, Qt::UserRole); + model->setData(i, channel, Qt::UserRole + 1); + model->setData(i, icon, Qt::DecorationRole); +} + +static void setCDROMSpeed(QAbstractItemModel* model, const QModelIndex& idx, uint8_t speed) { + if (!speed) speed = 8; + auto i = idx.siblingAtColumn(1); + model->setData(i, QString("%1x").arg(speed)); + model->setData(i, speed, Qt::UserRole); +} + +SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsFloppyCDROM) +{ + ui->setupUi(this); + + auto* model = ui->comboBoxFloppyType->model(); + int i = 0; + while (true) { + QString name = tr(fdd_getname(i)); + if (name.isEmpty()) { + break; + } + + Models::AddEntry(model, name, i); + ++i; + } + + model = new QStandardItemModel(0, 3, this); + ui->tableViewFloppy->setModel(model); + model->setHeaderData(0, Qt::Horizontal, tr("Type")); + model->setHeaderData(1, Qt::Horizontal, tr("Turbo")); + model->setHeaderData(2, Qt::Horizontal, tr("Check BPB")); + + model->insertRows(0, FDD_NUM); + /* Floppy drives category */ + for (int i = 0; i < FDD_NUM; i++) { + auto idx = model->index(i, 0); + int type = fdd_get_type(i); + setFloppyType(model, idx, type); + model->setData(idx.siblingAtColumn(1), fdd_get_turbo(i) > 0 ? tr("On") : tr("Off")); + model->setData(idx.siblingAtColumn(2), fdd_get_check_bpb(i) > 0 ? tr("On") : tr("Off")); + } + + ui->tableViewFloppy->resizeColumnsToContents(); + ui->tableViewFloppy->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + connect(ui->tableViewFloppy->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsFloppyCDROM::onFloppyRowChanged); + ui->tableViewFloppy->setCurrentIndex(model->index(0, 0)); + + + Harddrives::populateRemovableBuses(ui->comboBoxBus->model()); + model = ui->comboBoxSpeed->model(); + for (int i = 0; i < 72; i++) { + Models::AddEntry(model, QString("%1x").arg(i + 1), i + 1); + } + + model = new QStandardItemModel(0, 2, this); + ui->tableViewCDROM->setModel(model); + model->setHeaderData(0, Qt::Horizontal, tr("Bus")); + model->setHeaderData(1, Qt::Horizontal, tr("Speed")); + model->insertRows(0, CDROM_NUM); + for (int i = 0; i < CDROM_NUM; i++) { + auto idx = model->index(i, 0); + setCDROMBus(model, idx, cdrom[i].bus_type, cdrom[i].res); + setCDROMSpeed(model, idx.siblingAtColumn(1), cdrom[i].speed); + Harddrives::busTrackClass->device_track(1, DEV_CDROM, cdrom[i].bus_type, cdrom[i].bus_type == CDROM_BUS_ATAPI ? cdrom[i].ide_channel : cdrom[i].scsi_device_id); + } + ui->tableViewCDROM->resizeColumnsToContents(); + ui->tableViewCDROM->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + connect(ui->tableViewCDROM->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsFloppyCDROM::onCDROMRowChanged); + ui->tableViewCDROM->setCurrentIndex(model->index(0, 0)); +} + +SettingsFloppyCDROM::~SettingsFloppyCDROM() +{ + delete ui; +} + +void SettingsFloppyCDROM::save() { + auto* model = ui->tableViewFloppy->model(); + for (int i = 0; i < FDD_NUM; i++) { + fdd_set_type(i, model->index(i, 0).data(Qt::UserRole).toInt()); + fdd_set_turbo(i, model->index(i, 1).data() == tr("On") ? 1 : 0); + fdd_set_check_bpb(i, model->index(i, 2).data() == tr("On") ? 1 : 0); + } + + /* Removable devices category */ + model = ui->tableViewCDROM->model(); + for (int i = 0; i < CDROM_NUM; i++) { + cdrom[i].img_fp = NULL; + cdrom[i].priv = NULL; + cdrom[i].ops = NULL; + cdrom[i].image = NULL; + cdrom[i].insert = NULL; + cdrom[i].close = NULL; + cdrom[i].get_volume = NULL; + cdrom[i].get_channel = NULL; + cdrom[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt(); + cdrom[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt(); + cdrom[i].speed = model->index(i, 1).data(Qt::UserRole).toUInt(); + } +} + +void SettingsFloppyCDROM::onFloppyRowChanged(const QModelIndex ¤t) { + int type = current.siblingAtColumn(0).data(Qt::UserRole).toInt(); + ui->comboBoxFloppyType->setCurrentIndex(type); + ui->checkBoxTurboTimings->setChecked(current.siblingAtColumn(1).data() == tr("On")); + ui->checkBoxCheckBPB->setChecked(current.siblingAtColumn(2).data() == tr("On")); +} + +void SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) { + uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); + uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); + uint8_t speed = current.siblingAtColumn(1).data(Qt::UserRole).toUInt(); + + ui->comboBoxBus->setCurrentIndex(-1); + auto* model = ui->comboBoxBus->model(); + auto match = model->match(model->index(0, 0), Qt::UserRole, bus); + if (! match.isEmpty()) { + ui->comboBoxBus->setCurrentIndex(match.first().row()); + } + + model = ui->comboBoxChannel->model(); + match = model->match(model->index(0, 0), Qt::UserRole, channel); + if (! match.isEmpty()) { + ui->comboBoxChannel->setCurrentIndex(match.first().row()); + } + + ui->comboBoxSpeed->setCurrentIndex(speed == 0 ? 7 : speed - 1); +} + +void SettingsFloppyCDROM::on_checkBoxTurboTimings_stateChanged(int arg1) { + auto idx = ui->tableViewFloppy->selectionModel()->currentIndex(); + ui->tableViewFloppy->model()->setData(idx.siblingAtColumn(1), arg1 == Qt::Checked ? tr("On") : tr("Off")); +} + +void SettingsFloppyCDROM::on_checkBoxCheckBPB_stateChanged(int arg1) { + auto idx = ui->tableViewFloppy->selectionModel()->currentIndex(); + ui->tableViewFloppy->model()->setData(idx.siblingAtColumn(2), arg1 == Qt::Checked ? tr("On") : tr("Off")); +} + +void SettingsFloppyCDROM::on_comboBoxFloppyType_activated(int index) { + setFloppyType(ui->tableViewFloppy->model(), ui->tableViewFloppy->selectionModel()->currentIndex(), index); +} + +void SettingsFloppyCDROM::on_comboBoxBus_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + int bus = ui->comboBoxBus->currentData().toInt(); + bool enabled = (bus != CDROM_BUS_DISABLED); + ui->comboBoxChannel->setEnabled(enabled); + ui->comboBoxSpeed->setEnabled(enabled); + Harddrives::populateBusChannels(ui->comboBoxChannel->model(), bus); +} + +void SettingsFloppyCDROM::on_comboBoxSpeed_activated(int index) { + auto idx = ui->tableViewCDROM->selectionModel()->currentIndex(); + setCDROMSpeed(ui->tableViewCDROM->model(), idx.siblingAtColumn(1), index + 1); +} + + +void SettingsFloppyCDROM::on_comboBoxBus_activated(int) { + auto i = ui->tableViewCDROM->selectionModel()->currentIndex().siblingAtColumn(0); + Harddrives::busTrackClass->device_track(0, DEV_CDROM, ui->tableViewCDROM->model()->data(i, Qt::UserRole).toInt(), ui->tableViewCDROM->model()->data(i, Qt::UserRole + 1).toInt()); + ui->comboBoxChannel->setCurrentIndex(ui->comboBoxBus->currentData().toUInt() == CDROM_BUS_ATAPI ? Harddrives::busTrackClass->next_free_ide_channel() : Harddrives::busTrackClass->next_free_scsi_id()); + setCDROMBus( + ui->tableViewCDROM->model(), + ui->tableViewCDROM->selectionModel()->currentIndex(), + ui->comboBoxBus->currentData().toUInt(), + ui->comboBoxChannel->currentData().toUInt()); + Harddrives::busTrackClass->device_track(1, DEV_CDROM, ui->tableViewCDROM->model()->data(i, Qt::UserRole).toInt(), ui->tableViewCDROM->model()->data(i, Qt::UserRole + 1).toInt()); +} + + +void SettingsFloppyCDROM::on_comboBoxChannel_activated(int) { + auto i = ui->tableViewCDROM->selectionModel()->currentIndex().siblingAtColumn(0); + Harddrives::busTrackClass->device_track(0, DEV_CDROM, ui->tableViewCDROM->model()->data(i, Qt::UserRole).toInt(), ui->tableViewCDROM->model()->data(i, Qt::UserRole + 1).toInt()); + setCDROMBus( + ui->tableViewCDROM->model(), + ui->tableViewCDROM->selectionModel()->currentIndex(), + ui->comboBoxBus->currentData().toUInt(), + ui->comboBoxChannel->currentData().toUInt()); + Harddrives::busTrackClass->device_track(1, DEV_CDROM, ui->tableViewCDROM->model()->data(i, Qt::UserRole).toInt(), ui->tableViewCDROM->model()->data(i, Qt::UserRole + 1).toInt()); +} diff --git a/src/qt/qt_settingsfloppycdrom.hpp b/src/qt/qt_settingsfloppycdrom.hpp new file mode 100644 index 000000000..f68646ab0 --- /dev/null +++ b/src/qt/qt_settingsfloppycdrom.hpp @@ -0,0 +1,35 @@ +#ifndef QT_SETTINGSFLOPPYCDROM_HPP +#define QT_SETTINGSFLOPPYCDROM_HPP + +#include + +namespace Ui { +class SettingsFloppyCDROM; +} + +class SettingsFloppyCDROM : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsFloppyCDROM(QWidget *parent = nullptr); + ~SettingsFloppyCDROM(); + + void save(); + +private slots: + void on_comboBoxChannel_activated(int index); + void on_comboBoxBus_activated(int index); + void on_comboBoxSpeed_activated(int index); + void on_comboBoxBus_currentIndexChanged(int index); + void on_comboBoxFloppyType_activated(int index); + void on_checkBoxCheckBPB_stateChanged(int arg1); + void on_checkBoxTurboTimings_stateChanged(int arg1); + void onFloppyRowChanged(const QModelIndex ¤t); + void onCDROMRowChanged(const QModelIndex ¤t); + +private: + Ui::SettingsFloppyCDROM *ui; +}; + +#endif // QT_SETTINGSFLOPPYCDROM_HPP diff --git a/src/qt/qt_settingsfloppycdrom.ui b/src/qt/qt_settingsfloppycdrom.ui new file mode 100644 index 000000000..8f7ffa995 --- /dev/null +++ b/src/qt/qt_settingsfloppycdrom.ui @@ -0,0 +1,154 @@ + + + SettingsFloppyCDROM + + + + 0 + 0 + 544 + 617 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Floppy drives: + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + + + Type: + + + + + + + + + + Turbo timings + + + + + + + Check BPB + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + CD-ROM drives: + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + + + Channel: + + + + + + + + + + Speed: + + + + + + + Bus: + + + + + + + + + + + + + + + + diff --git a/src/qt/qt_settingsharddisks.cpp b/src/qt/qt_settingsharddisks.cpp new file mode 100644 index 000000000..0c3938c91 --- /dev/null +++ b/src/qt/qt_settingsharddisks.cpp @@ -0,0 +1,328 @@ +/* + * 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. + * + * Hard disk configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsharddisks.hpp" +#include "ui_qt_settingsharddisks.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/hdd.h> +} + +#include + +#include "qt_harddiskdialog.hpp" +#include "qt_harddrive_common.hpp" +#include "qt_settings_bus_tracking.hpp" +#include "qt_progsettings.hpp" + +const int ColumnBus = 0; +const int ColumnFilename = 1; +const int ColumnCylinders = 2; +const int ColumnHeads = 3; +const int ColumnSectors = 4; +const int ColumnSize = 5; +const int ColumnSpeed = 6; + +const int DataBus = Qt::UserRole; +const int DataBusChannel = Qt::UserRole + 1; +const int DataBusPrevious = Qt::UserRole + 2; +const int DataBusChannelPrevious = Qt::UserRole + 3; + +/* +static void +normalize_hd_list() +{ + hard_disk_t ihdd[HDD_NUM]; + int i, j; + + j = 0; + memset(ihdd, 0x00, HDD_NUM * sizeof(hard_disk_t)); + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus != HDD_BUS_DISABLED) { + memcpy(&(ihdd[j]), &(temp_hdd[i]), sizeof(hard_disk_t)); + j++; + } + } + + memcpy(temp_hdd, ihdd, HDD_NUM * sizeof(hard_disk_t)); +} +*/ + +static QString busChannelName(const QModelIndex& idx) { + return Harddrives::BusChannelName(idx.data(DataBus).toUInt(), idx.data(DataBusChannel).toUInt()); +} + +static void addRow(QAbstractItemModel* model, hard_disk_t* hd) { + const QString userPath = usr_path; + + int row = model->rowCount(); + model->insertRow(row); + + QString busName = Harddrives::BusChannelName(hd->bus, hd->channel); + model->setData(model->index(row, ColumnBus), busName); + model->setData(model->index(row, ColumnBus), ProgSettings::loadIcon( "/hard_disk.ico"), Qt::DecorationRole); + model->setData(model->index(row, ColumnBus), hd->bus, DataBus); + model->setData(model->index(row, ColumnBus), hd->bus, DataBusPrevious); + model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannel); + model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannelPrevious); + Harddrives::busTrackClass->device_track(1, DEV_HDD, hd->bus, hd->channel); + QString fileName = hd->fn; + if (fileName.startsWith(userPath, Qt::CaseInsensitive)) { + model->setData(model->index(row, ColumnFilename), fileName.mid(userPath.size())); + } else { + model->setData(model->index(row, ColumnFilename), fileName); + } + model->setData(model->index(row, ColumnFilename), fileName, Qt::UserRole); + + model->setData(model->index(row, ColumnCylinders), hd->tracks); + model->setData(model->index(row, ColumnHeads), hd->hpc); + model->setData(model->index(row, ColumnSectors), hd->spt); + model->setData(model->index(row, ColumnSize), (hd->tracks * hd->hpc * hd->spt) >> 11); + model->setData(model->index(row, ColumnSpeed), hdd_preset_getname(hd->speed_preset)); + model->setData(model->index(row, ColumnSpeed), hd->speed_preset, Qt::UserRole); +} + +SettingsHarddisks::SettingsHarddisks(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsHarddisks) +{ + ui->setupUi(this); + + QAbstractItemModel* model = new QStandardItemModel(0, 7, this); + model->setHeaderData(ColumnBus, Qt::Horizontal, tr("Bus")); + model->setHeaderData(ColumnFilename, Qt::Horizontal, tr("File")); + model->setHeaderData(ColumnCylinders, Qt::Horizontal, tr("C")); + model->setHeaderData(ColumnHeads, Qt::Horizontal, tr("H")); + model->setHeaderData(ColumnSectors, Qt::Horizontal, tr("S")); + model->setHeaderData(ColumnSize, Qt::Horizontal, tr("MiB")); + model->setHeaderData(ColumnSpeed, Qt::Horizontal, tr("Speed")); + ui->tableView->setModel(model); + + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus > 0) { + addRow(model, &hdd[i]); + } + } + if (model->rowCount() == HDD_NUM) + { + ui->pushButtonNew->setEnabled(false); + ui->pushButtonExisting->setEnabled(false); + } + ui->tableView->resizeColumnsToContents(); + ui->tableView->horizontalHeader()->setSectionResizeMode(ColumnFilename, QHeaderView::Stretch); + + auto* tableSelectionModel = ui->tableView->selectionModel(); + connect(tableSelectionModel, &QItemSelectionModel::currentRowChanged, this, &SettingsHarddisks::onTableRowChanged); + onTableRowChanged(QModelIndex()); + + Harddrives::populateBuses(ui->comboBoxBus->model()); + on_comboBoxBus_currentIndexChanged(0); +} + +SettingsHarddisks::~SettingsHarddisks() +{ + delete ui; +} + +void SettingsHarddisks::save() { + memset(hdd, 0, sizeof(hdd)); + + auto* model = ui->tableView->model(); + int rows = model->rowCount(); + for (int i = 0; i < rows; ++i) { + auto idx = model->index(i, ColumnBus); + hdd[i].bus = idx.data(DataBus).toUInt(); + hdd[i].channel = idx.data(DataBusChannel).toUInt(); + hdd[i].tracks = idx.siblingAtColumn(ColumnCylinders).data().toUInt(); + hdd[i].hpc = idx.siblingAtColumn(ColumnHeads).data().toUInt(); + hdd[i].spt = idx.siblingAtColumn(ColumnSectors).data().toUInt(); + hdd[i].speed_preset = idx.siblingAtColumn(ColumnSpeed).data(Qt::UserRole).toUInt(); + + QByteArray fileName = idx.siblingAtColumn(ColumnFilename).data(Qt::UserRole).toString().toUtf8(); + strncpy(hdd[i].fn, fileName.data(), sizeof(hdd[i].fn) - 1); + hdd[i].priv = nullptr; + } +} + +void SettingsHarddisks::on_comboBoxBus_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + buschangeinprogress = true; + auto idx = ui->tableView->selectionModel()->currentIndex(); + if (idx.isValid()) { + auto* model = ui->tableView->model(); + auto col = idx.siblingAtColumn(ColumnBus); + model->setData(col, ui->comboBoxBus->currentData(Qt::UserRole), DataBus); + model->setData(col, busChannelName(col), Qt::DisplayRole); + Harddrives::busTrackClass->device_track(0, DEV_HDD, model->data(col, DataBusPrevious).toInt(), model->data(col, DataBusChannelPrevious).toInt()); + model->setData(col, ui->comboBoxBus->currentData(Qt::UserRole), DataBusPrevious); + } + + Harddrives::populateBusChannels(ui->comboBoxChannel->model(), ui->comboBoxBus->currentData().toInt()); + Harddrives::populateSpeeds(ui->comboBoxSpeed->model(), ui->comboBoxBus->currentData().toInt()); + int chanIdx = 0; + + switch (ui->comboBoxBus->currentData().toInt()) + { + case HDD_BUS_MFM: + chanIdx = (Harddrives::busTrackClass->next_free_mfm_channel()); + break; + case HDD_BUS_XTA: + chanIdx = (Harddrives::busTrackClass->next_free_xta_channel()); + break; + case HDD_BUS_ESDI: + chanIdx = (Harddrives::busTrackClass->next_free_esdi_channel()); + break; + case HDD_BUS_ATAPI: + case HDD_BUS_IDE: + chanIdx = (Harddrives::busTrackClass->next_free_ide_channel()); + break; + case HDD_BUS_SCSI: + chanIdx = (Harddrives::busTrackClass->next_free_scsi_id()); + break; + } + + if (idx.isValid()) { + auto* model = ui->tableView->model(); + auto col = idx.siblingAtColumn(ColumnBus); + model->setData(col, chanIdx, DataBusChannelPrevious); + } + ui->comboBoxChannel->setCurrentIndex(chanIdx); + buschangeinprogress = false; +} + +void SettingsHarddisks::on_comboBoxChannel_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + auto idx = ui->tableView->selectionModel()->currentIndex(); + if (idx.isValid()) { + auto* model = ui->tableView->model(); + auto col = idx.siblingAtColumn(ColumnBus); + model->setData(col, ui->comboBoxChannel->currentData(Qt::UserRole), DataBusChannel); + model->setData(col, busChannelName(col), Qt::DisplayRole); + if (!buschangeinprogress) Harddrives::busTrackClass->device_track(0, DEV_HDD, model->data(col, DataBus).toInt(), model->data(col, DataBusChannelPrevious).toUInt()); + Harddrives::busTrackClass->device_track(1, DEV_HDD, model->data(col, DataBus).toInt(), model->data(col, DataBusChannel).toUInt()); + model->setData(col, ui->comboBoxChannel->currentData(Qt::UserRole), DataBusChannelPrevious); + } +} + +void SettingsHarddisks::on_comboBoxSpeed_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + auto idx = ui->tableView->selectionModel()->currentIndex(); + if (idx.isValid()) { + auto* model = ui->tableView->model(); + auto col = idx.siblingAtColumn(ColumnSpeed); + model->setData(col, ui->comboBoxSpeed->currentData(Qt::UserRole), Qt::UserRole); + model->setData(col, hdd_preset_getname(ui->comboBoxSpeed->currentData(Qt::UserRole).toUInt())); + } +} + +void SettingsHarddisks::onTableRowChanged(const QModelIndex ¤t) { + bool hidden = !current.isValid(); + ui->labelBus->setHidden(hidden); + ui->labelChannel->setHidden(hidden); + ui->labelSpeed->setHidden(hidden); + ui->comboBoxBus->setHidden(hidden); + ui->comboBoxChannel->setHidden(hidden); + ui->comboBoxSpeed->setHidden(hidden); + + uint32_t bus = current.siblingAtColumn(ColumnBus).data(DataBus).toUInt(); + uint32_t busChannel = current.siblingAtColumn(ColumnBus).data(DataBusChannel).toUInt(); + uint32_t speed = current.siblingAtColumn(ColumnSpeed).data(Qt::UserRole).toUInt(); + + auto* model = ui->comboBoxBus->model(); + auto match = model->match(model->index(0, 0), Qt::UserRole, bus); + if (! match.isEmpty()) { + ui->comboBoxBus->setCurrentIndex(match.first().row()); + } + model = ui->comboBoxChannel->model(); + match = model->match(model->index(0, 0), Qt::UserRole, busChannel); + if (! match.isEmpty()) { + ui->comboBoxChannel->setCurrentIndex(match.first().row()); + } + + model = ui->comboBoxSpeed->model(); + match = model->match(model->index(0, 0), Qt::UserRole, speed); + if (! match.isEmpty()) { + ui->comboBoxSpeed->setCurrentIndex(match.first().row()); + } +} + +static void addDriveFromDialog(Ui::SettingsHarddisks* ui, const HarddiskDialog& dlg) { + QByteArray fn = dlg.fileName().toUtf8(); + + hard_disk_t hd; + memset(&hd, 0, sizeof(hd)); + + hd.bus = dlg.bus(); + hd.channel = dlg.channel(); + hd.tracks = dlg.cylinders(); + hd.hpc = dlg.heads(); + hd.spt = dlg.sectors(); + strncpy(hd.fn, fn.data(), sizeof(hd.fn) - 1); + hd.speed_preset = dlg.speed(); + + addRow(ui->tableView->model(), &hd); + ui->tableView->resizeColumnsToContents(); + ui->tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + if (ui->tableView->model()->rowCount() == HDD_NUM) + { + ui->pushButtonNew->setEnabled(false); + ui->pushButtonExisting->setEnabled(false); + } +} + +void SettingsHarddisks::on_pushButtonNew_clicked() { + HarddiskDialog dialog(false, this); + switch (dialog.exec()) { + case QDialog::Accepted: + addDriveFromDialog(ui, dialog); + break; + } +} + + +void SettingsHarddisks::on_pushButtonExisting_clicked() { + HarddiskDialog dialog(true, this); + switch (dialog.exec()) { + case QDialog::Accepted: + addDriveFromDialog(ui, dialog); + break; + } +} + +void SettingsHarddisks::on_pushButtonRemove_clicked() { + auto idx = ui->tableView->selectionModel()->currentIndex(); + if (! idx.isValid()) { + return; + } + + auto* model = ui->tableView->model(); + model->removeRow(idx.row()); + ui->pushButtonNew->setEnabled(true); + ui->pushButtonExisting->setEnabled(true); +} diff --git a/src/qt/qt_settingsharddisks.hpp b/src/qt/qt_settingsharddisks.hpp new file mode 100644 index 000000000..a8aebb0bd --- /dev/null +++ b/src/qt/qt_settingsharddisks.hpp @@ -0,0 +1,37 @@ +#ifndef QT_SETTINGSHARDDISKS_HPP +#define QT_SETTINGSHARDDISKS_HPP + +#include + +namespace Ui { +class SettingsHarddisks; +} + +class SettingsHarddisks : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsHarddisks(QWidget *parent = nullptr); + ~SettingsHarddisks(); + + void save(); + +private slots: + void on_comboBoxChannel_currentIndexChanged(int index); + void on_comboBoxSpeed_currentIndexChanged(int index); + +private slots: + void on_pushButtonRemove_clicked(); + void on_pushButtonExisting_clicked(); + void on_pushButtonNew_clicked(); + void on_comboBoxBus_currentIndexChanged(int index); + + void onTableRowChanged(const QModelIndex& current); + +private: + Ui::SettingsHarddisks *ui; + bool buschangeinprogress = false; +}; + +#endif // QT_SETTINGSHARDDISKS_HPP diff --git a/src/qt/qt_settingsharddisks.ui b/src/qt/qt_settingsharddisks.ui new file mode 100644 index 000000000..b5ab110c9 --- /dev/null +++ b/src/qt/qt_settingsharddisks.ui @@ -0,0 +1,108 @@ + + + SettingsHarddisks + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + + + Bus: + + + + + + + + + + ID: + + + + + + + + + + Speed: + + + + + + + + + + + + + + &New... + + + + + + + &Existing... + + + + + + + &Remove + + + + + + + + + + diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp new file mode 100644 index 000000000..d5a62534f --- /dev/null +++ b/src/qt/qt_settingsinput.cpp @@ -0,0 +1,201 @@ +/* + * 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. + * + * Mouse/Joystick configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsinput.hpp" +#include "ui_qt_settingsinput.h" + +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/mouse.h> +#include <86box/gameport.h> +} + +#include "qt_models_common.hpp" +#include "qt_deviceconfig.hpp" +#include "qt_joystickconfiguration.hpp" + +SettingsInput::SettingsInput(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsInput) +{ + ui->setupUi(this); + + onCurrentMachineChanged(machine); +} + +SettingsInput::~SettingsInput() +{ + delete ui; +} + +void SettingsInput::save() { + mouse_type = ui->comboBoxMouse->currentData().toInt(); + joystick_type = ui->comboBoxJoystick->currentData().toInt(); +} + +void SettingsInput::onCurrentMachineChanged(int machineId) { + // win_settings_video_proc, WM_INITDIALOG + this->machineId = machineId; + + auto* mouseModel = ui->comboBoxMouse->model(); + auto removeRows = mouseModel->rowCount(); + + int selectedRow = 0; + for (int i = 0; i < mouse_get_ndev(); ++i) { + const auto* dev = mouse_get_device(i); + if ((i == MOUSE_TYPE_INTERNAL) && (machine_has_flags(machineId, MACHINE_MOUSE) == 0)) { + continue; + } + + if (device_is_valid(dev, machineId) == 0) { + continue; + } + + QString name = DeviceConfig::DeviceName(dev, mouse_get_internal_name(i), 0); + int row = mouseModel->rowCount(); + mouseModel->insertRow(row); + auto idx = mouseModel->index(row, 0); + + mouseModel->setData(idx, name, Qt::DisplayRole); + mouseModel->setData(idx, i, Qt::UserRole); + + if (i == mouse_type) { + selectedRow = row - removeRows; + } + } + mouseModel->removeRows(0, removeRows); + ui->comboBoxMouse->setCurrentIndex(selectedRow); + + + int i = 0; + char* joyName = joystick_get_name(i); + auto* joystickModel = ui->comboBoxJoystick->model(); + removeRows = joystickModel->rowCount(); + selectedRow = 0; + while (joyName) { + int row = Models::AddEntry(joystickModel, tr(joyName).toUtf8().data(), i); + if (i == joystick_type) { + selectedRow = row - removeRows; + } + + ++i; + joyName = joystick_get_name(i); + } + joystickModel->removeRows(0, removeRows); + ui->comboBoxJoystick->setCurrentIndex(selectedRow); +} + +void SettingsInput::on_comboBoxMouse_currentIndexChanged(int index) { + int mouseId = ui->comboBoxMouse->currentData().toInt(); + ui->pushButtonConfigureMouse->setEnabled(mouse_has_config(mouseId) > 0); +} + + +void SettingsInput::on_comboBoxJoystick_currentIndexChanged(int index) { + int joystickId = ui->comboBoxJoystick->currentData().toInt(); + for (int i = 0; i < 4; ++i) { + auto* btn = findChild(QString("pushButtonJoystick%1").arg(i+1)); + if (btn == nullptr) { + continue; + } + btn->setEnabled(joystick_get_max_joysticks(joystickId) > i); + } +} + +void SettingsInput::on_pushButtonConfigureMouse_clicked() { + int mouseId = ui->comboBoxMouse->currentData().toInt(); + DeviceConfig::ConfigureDevice(mouse_get_device(mouseId), 0, qobject_cast(Settings::settings)); +} + +static int get_axis(JoystickConfiguration& jc, int axis, int joystick_nr) { + int axis_sel = jc.selectedAxis(axis); + int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_axes; + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_povs; + + if (axis_sel < nr_axes) { + return axis_sel; + } + + axis_sel -= nr_axes; + if (axis_sel < nr_povs * 2) { + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); + } + axis_sel -= nr_povs; + + return SLIDER | (axis_sel >> 1); +} + +static int get_pov(JoystickConfiguration& jc, int pov, int joystick_nr) { + int pov_sel = jc.selectedPov(pov); + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2; + + if (pov_sel < nr_povs) + { + if (pov_sel & 1) + return POV_Y | (pov_sel >> 1); + else + return POV_X | (pov_sel >> 1); + } + + return pov_sel - nr_povs; +} + +static void updateJoystickConfig(int type, int joystick_nr, QWidget* parent) { + JoystickConfiguration jc(type, joystick_nr, parent); + switch (jc.exec()) { + case QDialog::Rejected: + return; + case QDialog::Accepted: + break; + } + + joystick_state[joystick_nr].plat_joystick_nr = jc.selectedDevice(); + if (joystick_state[joystick_nr].plat_joystick_nr) { + for (int c = 0; c < joystick_get_axis_count(type); c++) { + joystick_state[joystick_nr].axis_mapping[c] = get_axis(jc, c, joystick_nr); + } + for (int c = 0; c < joystick_get_button_count(type); c++) { + joystick_state[joystick_nr].button_mapping[c] = jc.selectedButton(c); + } + for (int c = 0; c < joystick_get_button_count(type); c++) { + joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(jc, c, joystick_nr); + joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(jc, c, joystick_nr); + } + } +} + +void SettingsInput::on_pushButtonJoystick1_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 0, this); +} + +void SettingsInput::on_pushButtonJoystick2_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 1, this); +} + +void SettingsInput::on_pushButtonJoystick3_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 2, this); +} + +void SettingsInput::on_pushButtonJoystick4_clicked() { + updateJoystickConfig(ui->comboBoxJoystick->currentData().toInt(), 3, this); +} diff --git a/src/qt/qt_settingsinput.hpp b/src/qt/qt_settingsinput.hpp new file mode 100644 index 000000000..f9e44740d --- /dev/null +++ b/src/qt/qt_settingsinput.hpp @@ -0,0 +1,37 @@ +#ifndef QT_SETTINGSINPUT_HPP +#define QT_SETTINGSINPUT_HPP + +#include + +namespace Ui { +class SettingsInput; +} + +class SettingsInput : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsInput(QWidget *parent = nullptr); + ~SettingsInput(); + + void save(); + +public slots: + void onCurrentMachineChanged(int machineId); + +private slots: + void on_pushButtonConfigureMouse_clicked(); + void on_comboBoxJoystick_currentIndexChanged(int index); + void on_comboBoxMouse_currentIndexChanged(int index); + void on_pushButtonJoystick1_clicked(); + void on_pushButtonJoystick2_clicked(); + void on_pushButtonJoystick3_clicked(); + void on_pushButtonJoystick4_clicked(); + +private: + Ui::SettingsInput *ui; + int machineId = 0; +}; + +#endif // QT_SETTINGSINPUT_HPP diff --git a/src/qt/qt_settingsinput.ui b/src/qt/qt_settingsinput.ui new file mode 100644 index 000000000..8f4f46167 --- /dev/null +++ b/src/qt/qt_settingsinput.ui @@ -0,0 +1,114 @@ + + + SettingsInput + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + + + Joystick 2... + + + + + + + Joystick: + + + + + + + Joystick 4... + + + + + + + Mouse: + + + + + + + Joystick 3... + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Joystick 1... + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + 0 + 0 + + + + + + + + + + + + diff --git a/src/qt/qt_settingsmachine.cpp b/src/qt/qt_settingsmachine.cpp new file mode 100644 index 000000000..56456000b --- /dev/null +++ b/src/qt/qt_settingsmachine.cpp @@ -0,0 +1,299 @@ +/* + * 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. + * + * Machine selection and configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsmachine.hpp" +#include "ui_qt_settingsmachine.h" + +#include +#include +#include +#include +#include + +#include + +extern "C" { +#include "../cpu/cpu.h" + +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/device.h> +#include <86box/machine.h> +} + +// from nvr.h, which we can't import into CPP code +#define TIME_SYNC_DISABLED 0 +#define TIME_SYNC_ENABLED 1 +#define TIME_SYNC_UTC 2 + +#include "qt_deviceconfig.hpp" +#include "qt_models_common.hpp" + +SettingsMachine::SettingsMachine(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsMachine) +{ + ui->setupUi(this); + + switch (time_sync) { + case TIME_SYNC_ENABLED: + ui->radioButtonLocalTime->setChecked(true); + break; + case TIME_SYNC_ENABLED | TIME_SYNC_UTC: + ui->radioButtonUTC->setChecked(true); + break; + case TIME_SYNC_DISABLED: + default: + ui->radioButtonDisabled->setChecked(true); + break; + } + + auto* waitStatesModel = ui->comboBoxWaitStates->model(); + waitStatesModel->insertRows(0, 9); + auto idx = waitStatesModel->index(0, 0); + waitStatesModel->setData(idx, tr("Default"), Qt::DisplayRole); + waitStatesModel->setData(idx, 0, Qt::UserRole); + for (int i = 0; i < 8; ++i) { + idx = waitStatesModel->index(i+1, 0); + waitStatesModel->setData(idx, QString::asprintf(tr("%i Wait state(s)").toUtf8().constData(), i), Qt::DisplayRole); + waitStatesModel->setData(idx, i+1, Qt::UserRole); + } + + int selectedMachineType = 0; + auto* machineTypesModel = ui->comboBoxMachineType->model(); + for (int i = 1; i < MACHINE_TYPE_MAX; ++i) { + int j = 0; + while (machine_get_internal_name_ex(j) != nullptr) { + if (machine_available(j) && (machine_get_type(j) == i)) { + int row = Models::AddEntry(machineTypesModel, machine_types[i].name, machine_types[i].id); + if (machine_types[i].id == machine_get_type(machine)) { + selectedMachineType = row; + } + break; + } + j++; + } + } + + ui->comboBoxMachineType->setCurrentIndex(-1); + ui->comboBoxMachineType->setCurrentIndex(selectedMachineType); +} + +SettingsMachine::~SettingsMachine() { + delete ui; +} + +void SettingsMachine::save() { + machine = ui->comboBoxMachine->currentData().toInt(); + cpu_f = const_cast(&cpu_families[ui->comboBoxCPU->currentData().toInt()]); + cpu = ui->comboBoxSpeed->currentData().toInt(); + fpu_type = ui->comboBoxFPU->currentData().toInt(); + cpu_use_dynarec = ui->checkBoxDynamicRecompiler->isChecked() ? 1 : 0; + int64_t temp_mem_size; + if (machine_get_ram_granularity(machine) < 1024) { + temp_mem_size = ui->spinBoxRAM->value(); + } else { + temp_mem_size = ui->spinBoxRAM->value() * 1024; + } + + temp_mem_size &= ~(machine_get_ram_granularity(machine) - 1); + if (temp_mem_size < machine_get_min_ram(machine)) { + temp_mem_size = machine_get_min_ram(machine); + } else if (temp_mem_size > machine_get_max_ram(machine)) { + temp_mem_size = machine_get_max_ram(machine); + } + mem_size = static_cast(temp_mem_size); + + if (ui->comboBoxWaitStates->isEnabled()) { + cpu_waitstates = ui->comboBoxWaitStates->currentData().toInt(); + } else { + cpu_waitstates = 0; + } + + time_sync = 0; + if (ui->radioButtonLocalTime->isChecked()) { + time_sync = TIME_SYNC_ENABLED; + } + if (ui->radioButtonUTC->isChecked()) { + time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; + } +} + +void SettingsMachine::on_comboBoxMachineType_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + auto* model = ui->comboBoxMachine->model(); + int removeRows = model->rowCount(); + + int selectedMachineRow = 0; + for (int i = 0; i < machine_count(); ++i) { + if ((machine_get_type(i) == ui->comboBoxMachineType->currentData().toInt()) && machine_available(i)) { + int row = Models::AddEntry(model, machines[i].name, i); + if (i == machine) { + selectedMachineRow = row - removeRows; + } + } + } + model->removeRows(0, removeRows); + + ui->comboBoxMachine->setCurrentIndex(-1); + ui->comboBoxMachine->setCurrentIndex(selectedMachineRow); +} + + +void SettingsMachine::on_comboBoxMachine_currentIndexChanged(int index) { + // win_settings_machine_recalc_machine + if (index < 0) { + return; + } + + int machineId = ui->comboBoxMachine->currentData().toInt(); + const auto* device = machine_getdevice(machineId); + ui->pushButtonConfigure->setEnabled((device != nullptr) && (device->config != nullptr)); + + auto* modelCpu = ui->comboBoxCPU->model(); + int removeRows = modelCpu->rowCount(); + + int i = 0; + int eligibleRows = 0; + int selectedCpuFamilyRow = 0; + while (cpu_families[i].package != 0) { + if (cpu_family_is_eligible(&cpu_families[i], machineId)) { + Models::AddEntry(modelCpu, QString("%1 %2").arg(cpu_families[i].manufacturer, cpu_families[i].name), i); + if (&cpu_families[i] == cpu_f) { + selectedCpuFamilyRow = eligibleRows; + } + ++eligibleRows; + } + ++i; + } + modelCpu->removeRows(0, removeRows); + ui->comboBoxCPU->setEnabled(eligibleRows > 1); + ui->comboBoxCPU->setCurrentIndex(-1); + ui->comboBoxCPU->setCurrentIndex(selectedCpuFamilyRow); + + int divisor; + if ((machine_get_ram_granularity(machineId) < 1024)) { + divisor = 1; + ui->spinBoxRAM->setSuffix(QCoreApplication::translate("", "KB").prepend(' ')); + } else { + divisor = 1024; + ui->spinBoxRAM->setSuffix(QCoreApplication::translate("", "MB").prepend(' ')); + } + ui->spinBoxRAM->setMinimum(machine_get_min_ram(machineId) / divisor); + ui->spinBoxRAM->setMaximum(machine_get_max_ram(machineId) / divisor); + ui->spinBoxRAM->setSingleStep(machine_get_ram_granularity(machineId) / divisor); + ui->spinBoxRAM->setValue(mem_size / divisor); + ui->spinBoxRAM->setEnabled(machine_get_min_ram(machineId) != machine_get_max_ram(machineId)); + + emit currentMachineChanged(machineId); +} + + +void SettingsMachine::on_comboBoxCPU_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + int machineId = ui->comboBoxMachine->currentData().toInt(); + int cpuFamilyId = ui->comboBoxCPU->currentData().toInt(); + const auto* cpuFamily = &cpu_families[cpuFamilyId]; + + auto* modelSpeed = ui->comboBoxSpeed->model(); + int removeRows = modelSpeed->rowCount(); + + // win_settings_machine_recalc_cpu_m + int i = 0; + int eligibleRows = 0; + int selectedSpeedRow = 0; + while (cpuFamily->cpus[i].cpu_type != 0) { + if (cpu_is_eligible(cpuFamily, i, machineId)) { + Models::AddEntry(modelSpeed, QString("%1").arg(cpuFamily->cpus[i].name), i); + if (cpu == i) { + selectedSpeedRow = eligibleRows; + } + ++eligibleRows; + } + ++i; + } + modelSpeed->removeRows(0, removeRows); + ui->comboBoxSpeed->setEnabled(eligibleRows > 1); + ui->comboBoxSpeed->setCurrentIndex(-1); + ui->comboBoxSpeed->setCurrentIndex(selectedSpeedRow); +} + + +void SettingsMachine::on_comboBoxSpeed_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + // win_settings_machine_recalc_cpu + int cpuFamilyId = ui->comboBoxCPU->currentData().toInt(); + const auto* cpuFamily = &cpu_families[cpuFamilyId]; + int cpuId = ui->comboBoxSpeed->currentData().toInt(); + uint cpuType = cpuFamily->cpus[cpuId].cpu_type; + + if ((cpuType >= CPU_286) && (cpuType <= CPU_386DX)) { + ui->comboBoxWaitStates->setEnabled(true); + ui->comboBoxWaitStates->setCurrentIndex(cpu_waitstates); + } else { + ui->comboBoxWaitStates->setCurrentIndex(0); + ui->comboBoxWaitStates->setEnabled(false); + } + +#ifdef USE_DYNAREC + uint8_t flags = cpuFamily->cpus[cpuId].cpu_flags; + if (! (flags & CPU_SUPPORTS_DYNAREC)) { + ui->checkBoxDynamicRecompiler->setChecked(false); + ui->checkBoxDynamicRecompiler->setEnabled(false); + } else if (flags & CPU_REQUIRES_DYNAREC) { + ui->checkBoxDynamicRecompiler->setChecked(true); + ui->checkBoxDynamicRecompiler->setEnabled(false); + } else { + ui->checkBoxDynamicRecompiler->setChecked(cpu_use_dynarec); + ui->checkBoxDynamicRecompiler->setEnabled(true); + } +#endif + + // win_settings_machine_recalc_fpu + auto* modelFpu = ui->comboBoxFPU->model(); + int removeRows = modelFpu->rowCount(); + + int i = 0; + int selectedFpuRow = 0; + for (const char* fpuName = fpu_get_name_from_index(cpuFamily, cpuId, i); fpuName != nullptr; fpuName = fpu_get_name_from_index(cpuFamily, cpuId, ++i)) { + auto fpuType = fpu_get_type_from_index(cpuFamily, cpuId, i); + Models::AddEntry(modelFpu, QString("%1").arg(fpuName), fpuType); + if (fpu_type == fpuType) { + selectedFpuRow = i; + } + } + + modelFpu->removeRows(0, removeRows); + ui->comboBoxFPU->setEnabled(modelFpu->rowCount() > 1); + ui->comboBoxFPU->setCurrentIndex(-1); + ui->comboBoxFPU->setCurrentIndex(selectedFpuRow); +} + +void SettingsMachine::on_pushButtonConfigure_clicked() { + // deviceconfig_inst_open + int machineId = ui->comboBoxMachine->currentData().toInt(); + const auto* device = machine_getdevice(machineId); + DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); +} diff --git a/src/qt/qt_settingsmachine.hpp b/src/qt/qt_settingsmachine.hpp new file mode 100644 index 000000000..d0d4aabd2 --- /dev/null +++ b/src/qt/qt_settingsmachine.hpp @@ -0,0 +1,41 @@ +#ifndef QT_SETTINGSMACHINE_HPP +#define QT_SETTINGSMACHINE_HPP + +#include + +namespace Ui { +class SettingsMachine; +} + +class SettingsMachine : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsMachine(QWidget *parent = nullptr); + ~SettingsMachine(); + + void save(); + +signals: + void currentMachineChanged(int machineId); +private slots: + void on_pushButtonConfigure_clicked(); + +private slots: + void on_comboBoxSpeed_currentIndexChanged(int index); + +private slots: + void on_comboBoxCPU_currentIndexChanged(int index); + +private slots: + void on_comboBoxMachine_currentIndexChanged(int index); + +private slots: + void on_comboBoxMachineType_currentIndexChanged(int index); + +private: + Ui::SettingsMachine *ui; +}; + +#endif // QT_SETTINGSMACHINE_HPP diff --git a/src/qt/qt_settingsmachine.ui b/src/qt/qt_settingsmachine.ui new file mode 100644 index 000000000..30f375f7e --- /dev/null +++ b/src/qt/qt_settingsmachine.ui @@ -0,0 +1,256 @@ + + + SettingsMachine + + + + 0 + 0 + 458 + 390 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Machine type: + + + + + + + + + + Machine: + + + + + + + CPU type: + + + + + + + FPU: + + + + + + + Wait states: + + + + + + + Memory: + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + Speed: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + + + + + + + 2 + 2 + + + + Dynamic Recompiler + + + + + + + + 0 + 0 + + + + Time synchronization + + + + + + Disabled + + + + + + + Enabled (local time) + + + + + + + Enabled (UTC) + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp new file mode 100644 index 000000000..ec5ebbe53 --- /dev/null +++ b/src/qt/qt_settingsnetwork.cpp @@ -0,0 +1,137 @@ +/* + * 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. + * + * Network devices configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsnetwork.hpp" +#include "ui_qt_settingsnetwork.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/network.h> +} + +#include "qt_models_common.hpp" +#include "qt_deviceconfig.hpp" + +static void enableElements(Ui::SettingsNetwork *ui) { + int netType = ui->comboBoxNetwork->currentData().toInt(); + ui->comboBoxPcap->setEnabled(netType == NET_TYPE_PCAP); + + bool adaptersEnabled = netType == NET_TYPE_SLIRP || + (netType == NET_TYPE_PCAP && ui->comboBoxPcap->currentData().toInt() > 0); + ui->comboBoxAdapter->setEnabled(adaptersEnabled); + ui->pushButtonConfigure->setEnabled(adaptersEnabled && ui->comboBoxAdapter->currentIndex() > 0 && network_card_has_config(ui->comboBoxAdapter->currentData().toInt())); +} + +SettingsNetwork::SettingsNetwork(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsNetwork) +{ + ui->setupUi(this); + + auto* model = ui->comboBoxNetwork->model(); + Models::AddEntry(model, tr("None"), NET_TYPE_NONE); + Models::AddEntry(model, "PCap", NET_TYPE_PCAP); + Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP); + ui->comboBoxNetwork->setCurrentIndex(network_type); + + int selectedRow = 0; + model = ui->comboBoxPcap->model(); + QString currentPcapDevice = network_host; + for (int c = 0; c < network_ndev; c++) { + + Models::AddEntry(model, tr(network_devs[c].description), c); + if (QString(network_devs[c].device) == currentPcapDevice) { + selectedRow = c; + } + } + ui->comboBoxPcap->setCurrentIndex(-1); + ui->comboBoxPcap->setCurrentIndex(selectedRow); + + onCurrentMachineChanged(machine); + enableElements(ui); +} + +SettingsNetwork::~SettingsNetwork() +{ + delete ui; +} + +void SettingsNetwork::save() { + network_type = ui->comboBoxNetwork->currentData().toInt(); + memset(network_host, '\0', sizeof(network_host)); + strcpy(network_host, network_devs[ui->comboBoxPcap->currentData().toInt()].device); + network_card = ui->comboBoxAdapter->currentData().toInt(); +} + +void SettingsNetwork::onCurrentMachineChanged(int machineId) { + this->machineId = machineId; + + auto* model = ui->comboBoxAdapter->model(); + auto removeRows = model->rowCount(); + int c = 0; + int selectedRow = 0; + while (true) { + auto name = DeviceConfig::DeviceName(network_card_getdevice(c), network_card_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == network_card) { + selectedRow = row - removeRows; + } + } + + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxAdapter->setEnabled(model->rowCount() > 0); + ui->comboBoxAdapter->setCurrentIndex(-1); + ui->comboBoxAdapter->setCurrentIndex(selectedRow); +} + +void SettingsNetwork::on_comboBoxNetwork_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + enableElements(ui); +} + +void SettingsNetwork::on_comboBoxAdapter_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + enableElements(ui); +} + +void SettingsNetwork::on_pushButtonConfigure_clicked() { + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxAdapter->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + + +void SettingsNetwork::on_comboBoxPcap_currentIndexChanged(int index) +{ + if (index < 0) { + return; + } + + enableElements(ui); +} diff --git a/src/qt/qt_settingsnetwork.hpp b/src/qt/qt_settingsnetwork.hpp new file mode 100644 index 000000000..b473ee3df --- /dev/null +++ b/src/qt/qt_settingsnetwork.hpp @@ -0,0 +1,35 @@ +#ifndef QT_SETTINGSNETWORK_HPP +#define QT_SETTINGSNETWORK_HPP + +#include + +namespace Ui { +class SettingsNetwork; +} + +class SettingsNetwork : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsNetwork(QWidget *parent = nullptr); + ~SettingsNetwork(); + + void save(); + +public slots: + void onCurrentMachineChanged(int machineId); + +private slots: + void on_pushButtonConfigure_clicked(); + void on_comboBoxAdapter_currentIndexChanged(int index); + void on_comboBoxNetwork_currentIndexChanged(int index); + + void on_comboBoxPcap_currentIndexChanged(int index); + +private: + Ui::SettingsNetwork *ui; + int machineId = 0; +}; + +#endif // QT_SETTINGSNETWORK_HPP diff --git a/src/qt/qt_settingsnetwork.ui b/src/qt/qt_settingsnetwork.ui new file mode 100644 index 000000000..751e3854d --- /dev/null +++ b/src/qt/qt_settingsnetwork.ui @@ -0,0 +1,97 @@ + + + SettingsNetwork + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + PCap device: + + + + + + + Network type: + + + + + + + + 0 + 0 + + + + + + + + Network adapter: + + + + + + + Configure + + + + + + + + 0 + 0 + + + + + + + + + + + + diff --git a/src/qt/qt_settingsotherperipherals.cpp b/src/qt/qt_settingsotherperipherals.cpp new file mode 100644 index 000000000..ebf849d28 --- /dev/null +++ b/src/qt/qt_settingsotherperipherals.cpp @@ -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. + * + * Other peripherals configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsotherperipherals.hpp" +#include "ui_qt_settingsotherperipherals.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/isamem.h> +#include <86box/isartc.h> +} + +#include "qt_deviceconfig.hpp" +#include "qt_models_common.hpp" + +SettingsOtherPeripherals::SettingsOtherPeripherals(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsOtherPeripherals) +{ + ui->setupUi(this); + onCurrentMachineChanged(machine); +} + +void SettingsOtherPeripherals::onCurrentMachineChanged(int machineId) +{ + this->machineId = machineId; + + ui->checkBoxISABugger->setChecked(bugger_enabled > 0 ? true : false); + ui->checkBoxPOSTCard->setChecked(postcard_enabled > 0 ? true : false); + ui->checkBoxISABugger->setEnabled(machine_has_bus(machineId, MACHINE_BUS_ISA)); + ui->comboBoxRTC->setEnabled(machine_has_bus(machineId, MACHINE_BUS_ISA)); + ui->pushButtonConfigureRTC->setEnabled(machine_has_bus(machineId, MACHINE_BUS_ISA)); + + ui->comboBoxCard1->clear(); + ui->comboBoxCard2->clear(); + ui->comboBoxCard3->clear(); + ui->comboBoxCard4->clear(); + ui->comboBoxRTC->clear(); + + auto* model = ui->comboBoxRTC->model(); + int d = 0; + int selectedRow = 0; + while (true) { + QString name = DeviceConfig::DeviceName(isartc_get_device(d), isartc_get_internal_name(d), 0); + if (name.isEmpty()) { + break; + } + + if (!device_is_valid(isartc_get_device(d), machineId)) { + break; + } + + int row = Models::AddEntry(model, name, d); + if (d == isartc_type) { + selectedRow = row; + } + ++d; + } + ui->comboBoxRTC->setCurrentIndex(selectedRow); + + for (int c = 0; c < ISAMEM_MAX; c++) { + auto* cbox = findChild(QString("comboBoxCard%1").arg(c + 1)); + model = cbox->model(); + d = 0; + selectedRow = 0; + while (true) { + QString name = DeviceConfig::DeviceName(isamem_get_device(d), isamem_get_internal_name(d), 0); + if (name.isEmpty()) { + break; + } + + if (!device_is_valid(isamem_get_device(d), machineId)) { + break; + } + + int row = Models::AddEntry(model, name, d); + if (d == isamem_type[c]) { + selectedRow = row; + } + ++d; + } + cbox->setCurrentIndex(-1); + cbox->setCurrentIndex(selectedRow); + cbox->setEnabled(machine_has_bus(machineId, MACHINE_BUS_ISA)); + findChild(QString("pushButtonConfigureCard%1").arg(c + 1))->setEnabled(isamem_type[c] != 0 && machine_has_bus(machineId, MACHINE_BUS_ISA)); + } +} + +SettingsOtherPeripherals::~SettingsOtherPeripherals() +{ + delete ui; +} + +void SettingsOtherPeripherals::save() { + /* Other peripherals category */ + bugger_enabled = ui->checkBoxISABugger->isChecked() ? 1 : 0; + postcard_enabled = ui->checkBoxPOSTCard->isChecked() ? 1 : 0; + isartc_type = ui->comboBoxRTC->currentData().toInt(); + + /* ISA memory boards. */ + for (int i = 0; i < ISAMEM_MAX; i++) { + auto* cbox = findChild(QString("comboBoxCard%1").arg(i + 1)); + isamem_type[i] = cbox->currentData().toInt(); + } +} + +void SettingsOtherPeripherals::on_comboBoxRTC_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureRTC->setEnabled(index != 0 && machine_has_bus(machineId, MACHINE_BUS_ISA)); +} + +void SettingsOtherPeripherals::on_pushButtonConfigureRTC_clicked() { + DeviceConfig::ConfigureDevice(isartc_get_device(ui->comboBoxRTC->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsOtherPeripherals::on_comboBoxCard1_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureCard1->setEnabled(index != 0 && machine_has_bus(machineId, MACHINE_BUS_ISA)); +} + +void SettingsOtherPeripherals::on_pushButtonConfigureCard1_clicked() { + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard1->currentData().toInt()), 1, qobject_cast(Settings::settings)); +} + +void SettingsOtherPeripherals::on_comboBoxCard2_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureCard2->setEnabled(index != 0 && machine_has_bus(machineId, MACHINE_BUS_ISA)); +} + +void SettingsOtherPeripherals::on_pushButtonConfigureCard2_clicked() { + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard2->currentData().toInt()), 2, qobject_cast(Settings::settings)); +} + +void SettingsOtherPeripherals::on_comboBoxCard3_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureCard3->setEnabled(index != 0 && machine_has_bus(machineId, MACHINE_BUS_ISA)); +} + +void SettingsOtherPeripherals::on_pushButtonConfigureCard3_clicked() { + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard3->currentData().toInt()), 3, qobject_cast(Settings::settings)); +} + +void SettingsOtherPeripherals::on_comboBoxCard4_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureCard4->setEnabled(index != 0 && machine_has_bus(machineId, MACHINE_BUS_ISA)); +} + +void SettingsOtherPeripherals::on_pushButtonConfigureCard4_clicked() { + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard4->currentData().toInt()), 4, qobject_cast(Settings::settings)); +} diff --git a/src/qt/qt_settingsotherperipherals.hpp b/src/qt/qt_settingsotherperipherals.hpp new file mode 100644 index 000000000..f8eed2c9e --- /dev/null +++ b/src/qt/qt_settingsotherperipherals.hpp @@ -0,0 +1,40 @@ +#ifndef QT_SETTINGSOTHERPERIPHERALS_HPP +#define QT_SETTINGSOTHERPERIPHERALS_HPP + +#include + +namespace Ui { +class SettingsOtherPeripherals; +} + +class SettingsOtherPeripherals : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsOtherPeripherals(QWidget *parent = nullptr); + ~SettingsOtherPeripherals(); + + void save(); + +public slots: + void onCurrentMachineChanged(int machineId); + +private slots: + void on_pushButtonConfigureCard4_clicked(); + void on_comboBoxCard4_currentIndexChanged(int index); + void on_pushButtonConfigureCard3_clicked(); + void on_comboBoxCard3_currentIndexChanged(int index); + void on_pushButtonConfigureCard2_clicked(); + void on_comboBoxCard2_currentIndexChanged(int index); + void on_pushButtonConfigureCard1_clicked(); + void on_comboBoxCard1_currentIndexChanged(int index); + void on_pushButtonConfigureRTC_clicked(); + void on_comboBoxRTC_currentIndexChanged(int index); + +private: + Ui::SettingsOtherPeripherals *ui; + int machineId{0}; +}; + +#endif // QT_SETTINGSOTHERPERIPHERALS_HPP diff --git a/src/qt/qt_settingsotherperipherals.ui b/src/qt/qt_settingsotherperipherals.ui new file mode 100644 index 000000000..62a4b9308 --- /dev/null +++ b/src/qt/qt_settingsotherperipherals.ui @@ -0,0 +1,176 @@ + + + SettingsOtherPeripherals + + + + 0 + 0 + 421 + 458 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + ISA RTC: + + + + + + + + 0 + 0 + + + + + + + + Configure + + + + + + + + + ISA Memory Expansion + + + + + + Configure + + + + + + + + + + Configure + + + + + + + Card 2: + + + + + + + Card 3: + + + + + + + Configure + + + + + + + + 0 + 0 + + + + + + + + Card 1: + + + + + + + + + + + + + Configure + + + + + + + Card 4: + + + + + + + + + + + + ISABugger device + + + + + + + POST card + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/qt/qt_settingsotherremovable.cpp b/src/qt/qt_settingsotherremovable.cpp new file mode 100644 index 000000000..574fdccb5 --- /dev/null +++ b/src/qt/qt_settingsotherremovable.cpp @@ -0,0 +1,302 @@ +/* + * 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. + * + * Other removable devices configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsotherremovable.hpp" +#include "ui_qt_settingsotherremovable.h" + +extern "C" { +#include <86box/timer.h> +#include <86box/scsi_device.h> +#include <86box/mo.h> +#include <86box/zip.h> +} + +#include + +#include "qt_models_common.hpp" +#include "qt_harddrive_common.hpp" +#include "qt_settings_bus_tracking.hpp" +#include "qt_progsettings.hpp" + +static QString moDriveTypeName(int i) { + return QString("%1 %2 %3").arg(mo_drive_types[i].vendor, mo_drive_types[i].model, mo_drive_types[i].revision); +} + +static void setMOBus(QAbstractItemModel* model, const QModelIndex& idx, uint8_t bus, uint8_t channel) { + QIcon icon; + switch (bus) { + case MO_BUS_DISABLED: + icon = ProgSettings::loadIcon("/mo_disabled.ico"); + break; + case MO_BUS_ATAPI: + case MO_BUS_SCSI: + icon = ProgSettings::loadIcon("/mo.ico"); + break; + } + + auto i = idx.siblingAtColumn(0); + model->setData(i, Harddrives::BusChannelName(bus, channel)); + model->setData(i, bus, Qt::UserRole); + model->setData(i, channel, Qt::UserRole + 1); + model->setData(i, icon, Qt::DecorationRole); +} + +static void setMOType(QAbstractItemModel* model, const QModelIndex& idx, uint32_t type) { + auto i = idx.siblingAtColumn(1); + if (idx.siblingAtColumn(0).data(Qt::UserRole).toUInt() == MO_BUS_DISABLED) { + model->setData(i, QCoreApplication::translate("", "None")); + } else { + model->setData(i, moDriveTypeName(type)); + } + model->setData(i, type, Qt::UserRole); +} + +static void setZIPBus(QAbstractItemModel* model, const QModelIndex& idx, uint8_t bus, uint8_t channel) { + QIcon icon; + switch (bus) { + case ZIP_BUS_DISABLED: + icon = ProgSettings::loadIcon("/zip_disabled.ico"); + break; + case ZIP_BUS_ATAPI: + case ZIP_BUS_SCSI: + icon = ProgSettings::loadIcon("/zip.ico"); + break; + } + + auto i = idx.siblingAtColumn(0); + model->setData(i, Harddrives::BusChannelName(bus, channel)); + model->setData(i, bus, Qt::UserRole); + model->setData(i, channel, Qt::UserRole + 1); + model->setData(i, icon, Qt::DecorationRole); +} + +static void setZIPType(QAbstractItemModel* model, const QModelIndex& idx, bool is250) { + auto i = idx.siblingAtColumn(1); + model->setData(i, is250 ? "ZIP 250" : "ZIP 100"); + model->setData(i, is250, Qt::UserRole); +} + +SettingsOtherRemovable::SettingsOtherRemovable(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsOtherRemovable) +{ + ui->setupUi(this); + + Harddrives::populateRemovableBuses(ui->comboBoxMOBus->model()); + auto* model = ui->comboBoxMOType->model(); + for (uint32_t i = 0; i < KNOWN_MO_DRIVE_TYPES; i++) { + Models::AddEntry(model, moDriveTypeName(i), i); + } + + model = new QStandardItemModel(0, 2, this); + ui->tableViewMO->setModel(model); + model->setHeaderData(0, Qt::Horizontal, tr("Bus")); + model->setHeaderData(1, Qt::Horizontal, tr("Type")); + model->insertRows(0, MO_NUM); + for (int i = 0; i < MO_NUM; i++) { + auto idx = model->index(i, 0); + setMOBus(model, idx, mo_drives[i].bus_type, mo_drives[i].res); + setMOType(model, idx.siblingAtColumn(1), mo_drives[i].type); + Harddrives::busTrackClass->device_track(1, DEV_MO, mo_drives[i].bus_type, mo_drives[i].bus_type == MO_BUS_ATAPI ? mo_drives[i].ide_channel : mo_drives[i].scsi_device_id); + } + ui->tableViewMO->resizeColumnsToContents(); + ui->tableViewMO->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + connect(ui->tableViewMO->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsOtherRemovable::onMORowChanged); + ui->tableViewMO->setCurrentIndex(model->index(0, 0)); + + + + + Harddrives::populateRemovableBuses(ui->comboBoxZIPBus->model()); + + model = new QStandardItemModel(0, 2, this); + ui->tableViewZIP->setModel(model); + model->setHeaderData(0, Qt::Horizontal, "Bus"); + model->setHeaderData(1, Qt::Horizontal, "Type"); + model->insertRows(0, ZIP_NUM); + for (int i = 0; i < ZIP_NUM; i++) { + auto idx = model->index(i, 0); + setZIPBus(model, idx, zip_drives[i].bus_type, zip_drives[i].res); + setZIPType(model, idx, zip_drives[i].is_250 > 0); + Harddrives::busTrackClass->device_track(1, DEV_ZIP, zip_drives[i].bus_type, zip_drives[i].bus_type == ZIP_BUS_ATAPI ? zip_drives[i].ide_channel : zip_drives[i].scsi_device_id); + } + ui->tableViewZIP->resizeColumnsToContents(); + ui->tableViewZIP->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + connect(ui->tableViewZIP->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SettingsOtherRemovable::onZIPRowChanged); + ui->tableViewZIP->setCurrentIndex(model->index(0, 0)); +} + +SettingsOtherRemovable::~SettingsOtherRemovable() +{ + delete ui; +} + +void SettingsOtherRemovable::save() { + auto* model = ui->tableViewMO->model(); + for (int i = 0; i < MO_NUM; i++) { + mo_drives[i].f = NULL; + mo_drives[i].priv = NULL; + mo_drives[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt(); + mo_drives[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt(); + mo_drives[i].type = model->index(i, 1).data(Qt::UserRole).toUInt(); + } + + model = ui->tableViewZIP->model(); + for (int i = 0; i < ZIP_NUM; i++) { + zip_drives[i].f = NULL; + zip_drives[i].priv = NULL; + zip_drives[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt(); + zip_drives[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt(); + zip_drives[i].is_250 = model->index(i, 1).data(Qt::UserRole).toBool() ? 1 : 0; + } +} + +void SettingsOtherRemovable::onMORowChanged(const QModelIndex ¤t) { + uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); + uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); + uint8_t type = current.siblingAtColumn(1).data(Qt::UserRole).toUInt(); + + ui->comboBoxMOBus->setCurrentIndex(-1); + auto* model = ui->comboBoxMOBus->model(); + auto match = model->match(model->index(0, 0), Qt::UserRole, bus); + if (! match.isEmpty()) { + ui->comboBoxMOBus->setCurrentIndex(match.first().row()); + } + + model = ui->comboBoxMOChannel->model(); + match = model->match(model->index(0, 0), Qt::UserRole, channel); + if (! match.isEmpty()) { + ui->comboBoxMOChannel->setCurrentIndex(match.first().row()); + } + ui->comboBoxMOType->setCurrentIndex(type); +} + +void SettingsOtherRemovable::onZIPRowChanged(const QModelIndex ¤t) { + uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); + uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); + bool is250 = current.siblingAtColumn(1).data(Qt::UserRole).toBool(); + + ui->comboBoxZIPBus->setCurrentIndex(-1); + auto* model = ui->comboBoxZIPBus->model(); + auto match = model->match(model->index(0, 0), Qt::UserRole, bus); + if (! match.isEmpty()) { + ui->comboBoxZIPBus->setCurrentIndex(match.first().row()); + } + + model = ui->comboBoxZIPChannel->model(); + match = model->match(model->index(0, 0), Qt::UserRole, channel); + if (! match.isEmpty()) { + ui->comboBoxZIPChannel->setCurrentIndex(match.first().row()); + } + ui->checkBoxZIP250->setChecked(is250); +} + +void SettingsOtherRemovable::on_comboBoxMOBus_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + int bus = ui->comboBoxMOBus->currentData().toInt(); + bool enabled = (bus != MO_BUS_DISABLED); + ui->comboBoxMOChannel->setEnabled(enabled); + ui->comboBoxMOType->setEnabled(enabled); + Harddrives::populateBusChannels(ui->comboBoxMOChannel->model(), bus); +} + +void SettingsOtherRemovable::on_comboBoxMOBus_activated(int) { + auto i = ui->tableViewMO->selectionModel()->currentIndex().siblingAtColumn(0); + Harddrives::busTrackClass->device_track(0, DEV_MO, ui->tableViewMO->model()->data(i, Qt::UserRole).toInt(), ui->tableViewMO->model()->data(i, Qt::UserRole + 1).toInt()); + ui->comboBoxMOChannel->setCurrentIndex(ui->comboBoxMOBus->currentData().toUInt() == MO_BUS_ATAPI ? Harddrives::busTrackClass->next_free_ide_channel() : Harddrives::busTrackClass->next_free_scsi_id()); + ui->tableViewMO->model()->data(i, Qt::UserRole + 1); + setMOBus( + ui->tableViewMO->model(), + ui->tableViewMO->selectionModel()->currentIndex(), + ui->comboBoxMOBus->currentData().toUInt(), + ui->comboBoxMOChannel->currentData().toUInt()); + setMOType( + ui->tableViewMO->model(), + ui->tableViewMO->selectionModel()->currentIndex(), + ui->comboBoxMOType->currentData().toUInt()); + ui->tableViewMO->resizeColumnsToContents(); + ui->tableViewMO->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + Harddrives::busTrackClass->device_track(1, DEV_MO, ui->tableViewMO->model()->data(i, Qt::UserRole).toInt(), ui->tableViewMO->model()->data(i, Qt::UserRole + 1).toInt()); +} + +void SettingsOtherRemovable::on_comboBoxMOChannel_activated(int) { + auto i = ui->tableViewMO->selectionModel()->currentIndex().siblingAtColumn(0); + Harddrives::busTrackClass->device_track(0, DEV_MO, ui->tableViewMO->model()->data(i, Qt::UserRole).toInt(), ui->tableViewMO->model()->data(i, Qt::UserRole + 1).toInt()); + setMOBus( + ui->tableViewMO->model(), + ui->tableViewMO->selectionModel()->currentIndex(), + ui->comboBoxMOBus->currentData().toUInt(), + ui->comboBoxMOChannel->currentData().toUInt()); + Harddrives::busTrackClass->device_track(1, DEV_MO, ui->tableViewMO->model()->data(i, Qt::UserRole).toInt(), ui->tableViewMO->model()->data(i, Qt::UserRole + 1).toInt()); +} + +void SettingsOtherRemovable::on_comboBoxMOType_activated(int) { + setMOType( + ui->tableViewMO->model(), + ui->tableViewMO->selectionModel()->currentIndex(), + ui->comboBoxMOType->currentData().toUInt()); + ui->tableViewMO->resizeColumnsToContents(); + ui->tableViewMO->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); +} + +void SettingsOtherRemovable::on_comboBoxZIPBus_currentIndexChanged(int index) { + if (index < 0) { + return; + } + + int bus = ui->comboBoxZIPBus->currentData().toInt(); + bool enabled = (bus != ZIP_BUS_DISABLED); + ui->comboBoxZIPChannel->setEnabled(enabled); + ui->checkBoxZIP250->setEnabled(enabled); + Harddrives::populateBusChannels(ui->comboBoxZIPChannel->model(), bus); +} + +void SettingsOtherRemovable::on_comboBoxZIPBus_activated(int) { + auto i = ui->tableViewZIP->selectionModel()->currentIndex().siblingAtColumn(0); + Harddrives::busTrackClass->device_track(0, DEV_ZIP, ui->tableViewZIP->model()->data(i, Qt::UserRole).toInt(), ui->tableViewZIP->model()->data(i, Qt::UserRole + 1).toInt()); + ui->comboBoxZIPChannel->setCurrentIndex(ui->comboBoxZIPBus->currentData().toUInt() == ZIP_BUS_ATAPI ? Harddrives::busTrackClass->next_free_ide_channel() : Harddrives::busTrackClass->next_free_scsi_id()); + setZIPBus( + ui->tableViewZIP->model(), + ui->tableViewZIP->selectionModel()->currentIndex(), + ui->comboBoxZIPBus->currentData().toUInt(), + ui->comboBoxZIPChannel->currentData().toUInt()); + Harddrives::busTrackClass->device_track(1, DEV_ZIP, ui->tableViewZIP->model()->data(i, Qt::UserRole).toInt(), ui->tableViewZIP->model()->data(i, Qt::UserRole + 1).toInt()); +} + +void SettingsOtherRemovable::on_comboBoxZIPChannel_activated(int) { + auto i = ui->tableViewZIP->selectionModel()->currentIndex().siblingAtColumn(0); + Harddrives::busTrackClass->device_track(0, DEV_ZIP, ui->tableViewZIP->model()->data(i, Qt::UserRole).toInt(), ui->tableViewZIP->model()->data(i, Qt::UserRole + 1).toInt()); + setZIPBus( + ui->tableViewZIP->model(), + ui->tableViewZIP->selectionModel()->currentIndex(), + ui->comboBoxZIPBus->currentData().toUInt(), + ui->comboBoxZIPChannel->currentData().toUInt()); + Harddrives::busTrackClass->device_track(1, DEV_ZIP, ui->tableViewZIP->model()->data(i, Qt::UserRole).toInt(), ui->tableViewZIP->model()->data(i, Qt::UserRole + 1).toInt()); +} + +void SettingsOtherRemovable::on_checkBoxZIP250_stateChanged(int state) { + setZIPType( + ui->tableViewZIP->model(), + ui->tableViewZIP->selectionModel()->currentIndex(), + state == Qt::Checked); +} diff --git a/src/qt/qt_settingsotherremovable.hpp b/src/qt/qt_settingsotherremovable.hpp new file mode 100644 index 000000000..c48f6f819 --- /dev/null +++ b/src/qt/qt_settingsotherremovable.hpp @@ -0,0 +1,52 @@ +#ifndef QT_SETTINGSOTHERREMOVABLE_HPP +#define QT_SETTINGSOTHERREMOVABLE_HPP + +#include + +namespace Ui { +class SettingsOtherRemovable; +} + +class SettingsOtherRemovable : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsOtherRemovable(QWidget *parent = nullptr); + ~SettingsOtherRemovable(); + + void save(); + +private slots: + void on_checkBoxZIP250_stateChanged(int arg1); + +private slots: + void on_comboBoxZIPChannel_activated(int index); + +private slots: + void on_comboBoxZIPBus_activated(int index); + +private slots: + void on_comboBoxZIPBus_currentIndexChanged(int index); + +private slots: + void on_comboBoxMOType_activated(int index); + +private slots: + void on_comboBoxMOChannel_activated(int index); + +private slots: + void on_comboBoxMOBus_activated(int index); + +private slots: + void on_comboBoxMOBus_currentIndexChanged(int index); + +private slots: + void onMORowChanged(const QModelIndex ¤t); + void onZIPRowChanged(const QModelIndex ¤t); + +private: + Ui::SettingsOtherRemovable *ui; +}; + +#endif // QT_SETTINGSOTHERREMOVABLE_HPP diff --git a/src/qt/qt_settingsotherremovable.ui b/src/qt/qt_settingsotherremovable.ui new file mode 100644 index 000000000..a82c296ae --- /dev/null +++ b/src/qt/qt_settingsotherremovable.ui @@ -0,0 +1,157 @@ + + + SettingsOtherRemovable + + + + 0 + 0 + 418 + 433 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + MO drives: + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + + + Bus: + + + + + + + Channel: + + + + + + + + + + + + + Type: + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + ZIP drives: + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + + + Bus: + + + + + + + + + + Channel: + + + + + + + + + + ZIP 250 + + + + + + + + + + diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp new file mode 100644 index 000000000..6e0388ede --- /dev/null +++ b/src/qt/qt_settingsports.cpp @@ -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. + * + * Serial/Parallel ports configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2022 Cacodemon345 + * Copyright 2022 Jasmine Iwanek + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsports.hpp" +#include "ui_qt_settingsports.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/lpt.h> +} + +#include "qt_deviceconfig.hpp" +#include "qt_models_common.hpp" + +SettingsPorts::SettingsPorts(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsPorts) +{ + ui->setupUi(this); + + for (int i = 0; i < PARALLEL_MAX; i++) { + auto* cbox = findChild(QString("comboBoxLpt%1").arg(i+1)); + auto* model = cbox->model(); + int c = 0; + int selectedRow = 0; + while (true) { + const char* lptName = lpt_device_get_name(c); + if (lptName == nullptr) { + break; + } + + Models::AddEntry(model, tr(lptName), c); + if (c == lpt_ports[i].device) { + selectedRow = c; + } + c++; + } + cbox->setCurrentIndex(selectedRow); + + auto* checkBox = findChild(QString("checkBoxParallel%1").arg(i+1)); + checkBox->setChecked(lpt_ports[i].enabled > 0); + cbox->setEnabled(lpt_ports[i].enabled > 0); + } + + for (int i = 0; i < SERIAL_MAX; i++) { + auto* checkBox = findChild(QString("checkBoxSerial%1").arg(i+1)); + checkBox->setChecked(serial_enabled[i] > 0); + } +} + +SettingsPorts::~SettingsPorts() +{ + delete ui; +} + +void SettingsPorts::save() { + for (int i = 0; i < PARALLEL_MAX; i++) { + auto* cbox = findChild(QString("comboBoxLpt%1").arg(i+1)); + auto* checkBox = findChild(QString("checkBoxParallel%1").arg(i+1)); + lpt_ports[i].device = cbox->currentData().toInt(); + lpt_ports[i].enabled = checkBox->isChecked() ? 1 : 0; + } + + for (int i = 0; i < SERIAL_MAX; i++) { + auto* checkBox = findChild(QString("checkBoxSerial%1").arg(i+1)); + serial_enabled[i] = checkBox->isChecked() ? 1 : 0; + } +} + +void SettingsPorts::on_checkBoxParallel1_stateChanged(int state) { + ui->comboBoxLpt1->setEnabled(state == Qt::Checked); +} + +void SettingsPorts::on_checkBoxParallel2_stateChanged(int state) { + ui->comboBoxLpt2->setEnabled(state == Qt::Checked); +} + +void SettingsPorts::on_checkBoxParallel3_stateChanged(int state) { + ui->comboBoxLpt3->setEnabled(state == Qt::Checked); +} + +void SettingsPorts::on_checkBoxParallel4_stateChanged(int state) { + ui->comboBoxLpt4->setEnabled(state == Qt::Checked); +} diff --git a/src/qt/qt_settingsports.hpp b/src/qt/qt_settingsports.hpp new file mode 100644 index 000000000..c5deef80a --- /dev/null +++ b/src/qt/qt_settingsports.hpp @@ -0,0 +1,30 @@ +#ifndef QT_SETTINGSPORTS_HPP +#define QT_SETTINGSPORTS_HPP + +#include + +namespace Ui { +class SettingsPorts; +} + +class SettingsPorts : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsPorts(QWidget *parent = nullptr); + ~SettingsPorts(); + + void save(); +private slots: + void on_checkBoxParallel3_stateChanged(int arg1); + void on_checkBoxParallel2_stateChanged(int arg1); + void on_checkBoxParallel1_stateChanged(int arg1); + + void on_checkBoxParallel4_stateChanged(int arg1); + +private: + Ui::SettingsPorts *ui; +}; + +#endif // QT_SETTINGSPORTS_HPP diff --git a/src/qt/qt_settingsports.ui b/src/qt/qt_settingsports.ui new file mode 100644 index 000000000..a1fbb47e7 --- /dev/null +++ b/src/qt/qt_settingsports.ui @@ -0,0 +1,150 @@ + + + SettingsPorts + + + + 0 + 0 + 398 + 341 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + LPT1 Device: + + + + + + + + + + LPT2 Device: + + + + + + + + + + LPT3 Device: + + + + + + + + + + LPT4 Device: + + + + + + + + + + + + + + Serial port 1 + + + + + + + Parallel port 1 + + + + + + + Serial port 2 + + + + + + + Parallel port 2 + + + + + + + Serial port 3 + + + + + + + Parallel port 3 + + + + + + + Serial port 4 + + + + + + + Parallel port 4 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp new file mode 100644 index 000000000..1c441b8ef --- /dev/null +++ b/src/qt/qt_settingssound.cpp @@ -0,0 +1,257 @@ +/* + * 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. + * + * Sound/MIDI devices configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingssound.hpp" +#include "ui_qt_settingssound.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/sound.h> +#include <86box/midi.h> +#include <86box/snd_mpu401.h> +#include <86box/snd_opl.h> +} + +#include "qt_deviceconfig.hpp" +#include "qt_models_common.hpp" + +SettingsSound::SettingsSound(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsSound) +{ + ui->setupUi(this); + onCurrentMachineChanged(machine); +} + +SettingsSound::~SettingsSound() +{ + delete ui; +} + +void SettingsSound::save() { + sound_card_current = ui->comboBoxSoundCard->currentData().toInt(); + midi_output_device_current = ui->comboBoxMidiOut->currentData().toInt(); + midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); + mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; + SSI2001 = ui->checkBoxSSI2001->isChecked() ? 1 : 0;; + GAMEBLASTER = ui->checkBoxCMS->isChecked() ? 1 : 0; + GUS = ui->checkBoxGUS->isChecked() ? 1 : 0;; + sound_is_float = ui->checkBoxFloat32->isChecked() ? 1 : 0;; + if (ui->radioButtonYMFM->isChecked()) + fm_driver = FM_DRV_YMFM; + else + fm_driver = FM_DRV_NUKED; +} + +void SettingsSound::onCurrentMachineChanged(int machineId) { + this->machineId = machineId; + + auto* model = ui->comboBoxSoundCard->model(); + auto removeRows = model->rowCount(); + int c = 0; + int selectedRow = 0; + while (true) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && (machine_has_flags(machineId, MACHINE_SOUND) == 0)) { + c++; + continue; + } + + auto* sound_dev = sound_card_getdevice(c); + QString name = DeviceConfig::DeviceName(sound_dev, sound_card_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (sound_card_available(c)) { + if (device_is_valid(sound_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == sound_card_current) { + selectedRow = row - removeRows; + } + } + } + + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxSoundCard->setEnabled(model->rowCount() > 0); + ui->comboBoxSoundCard->setCurrentIndex(-1); + ui->comboBoxSoundCard->setCurrentIndex(selectedRow); + + model = ui->comboBoxMidiOut->model(); + removeRows = model->rowCount(); + c = 0; + selectedRow = 0; + while (true) { + QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); + if (name.isEmpty()) { + break; + } + + if (midi_out_device_available(c)) { + int row = Models::AddEntry(model, name, c); + if (c == midi_output_device_current) { + selectedRow = row - removeRows; + } + } + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxMidiOut->setEnabled(model->rowCount() > 0); + ui->comboBoxMidiOut->setCurrentIndex(-1); + ui->comboBoxMidiOut->setCurrentIndex(selectedRow); + + model = ui->comboBoxMidiIn->model(); + removeRows = model->rowCount(); + c = 0; + selectedRow = 0; + while (true) { + QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); + if (name.isEmpty()) { + break; + } + + if (midi_in_device_available(c)) { + int row = Models::AddEntry(model, name, c); + if (c == midi_input_device_current) { + selectedRow = row - removeRows; + } + } + + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxMidiIn->setEnabled(model->rowCount() > 0); + ui->comboBoxMidiIn->setCurrentIndex(-1); + ui->comboBoxMidiIn->setCurrentIndex(selectedRow); + + ui->checkBoxMPU401->setChecked(mpu401_standalone_enable > 0); + ui->checkBoxSSI2001->setChecked(SSI2001 > 0); + ui->checkBoxCMS->setChecked(GAMEBLASTER > 0); + ui->checkBoxGUS->setChecked(GUS > 0); + ui->checkBoxFloat32->setChecked(sound_is_float > 0); + + bool hasIsa = machine_has_bus(machineId, MACHINE_BUS_ISA) > 0; + bool hasIsa16 = machine_has_bus(machineId, MACHINE_BUS_ISA16) > 0; + ui->checkBoxCMS->setEnabled(hasIsa); + ui->pushButtonConfigureCMS->setEnabled((GAMEBLASTER > 0) && hasIsa); + ui->checkBoxGUS->setEnabled(hasIsa16); + ui->pushButtonConfigureGUS->setEnabled((GUS > 0) && hasIsa16); + ui->checkBoxSSI2001->setEnabled(hasIsa); + ui->pushButtonConfigureSSI2001->setEnabled((SSI2001 > 0) && hasIsa); + switch (fm_driver) { + case FM_DRV_YMFM: + ui->radioButtonYMFM->setChecked(true); + break; + case FM_DRV_NUKED: + default: + ui->radioButtonNuked->setChecked(true); + break; + } +} + +static bool allowMpu401(Ui::SettingsSound *ui) { + QString midiOut = midi_out_device_get_internal_name(ui->comboBoxMidiOut->currentData().toInt()); + QString midiIn = midi_in_device_get_internal_name(ui->comboBoxMidiIn->currentData().toInt()); + + if (midiOut.isEmpty()) { + return false; + } + + if (midiOut == QStringLiteral("none") && midiIn == QStringLiteral("none")) { + return false; + } + + return true; +} + +void SettingsSound::on_comboBoxSoundCard_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureSoundCard->setEnabled(sound_card_has_config(ui->comboBoxSoundCard->currentData().toInt())); +} + + +void SettingsSound::on_pushButtonConfigureSoundCard_clicked() { + DeviceConfig::ConfigureDevice(sound_card_getdevice(ui->comboBoxSoundCard->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsSound::on_comboBoxMidiOut_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureMidiOut->setEnabled(midi_out_device_has_config(ui->comboBoxMidiOut->currentData().toInt())); + ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); + ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); +} + +void SettingsSound::on_pushButtonConfigureMidiOut_clicked() { + DeviceConfig::ConfigureDevice(midi_out_device_getdevice(ui->comboBoxMidiOut->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsSound::on_comboBoxMidiIn_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonConfigureMidiIn->setEnabled(midi_in_device_has_config(ui->comboBoxMidiIn->currentData().toInt())); + ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); + ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); +} + +void SettingsSound::on_pushButtonConfigureMidiIn_clicked() { + DeviceConfig::ConfigureDevice(midi_in_device_getdevice(ui->comboBoxMidiIn->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsSound::on_checkBoxMPU401_stateChanged(int state) { + ui->pushButtonConfigureMPU401->setEnabled(state == Qt::Checked); +} + +void SettingsSound::on_checkBoxSSI2001_stateChanged(int state) { + ui->pushButtonConfigureSSI2001->setEnabled(state == Qt::Checked); +} + +void SettingsSound::on_checkBoxCMS_stateChanged(int state) { + ui->pushButtonConfigureCMS->setEnabled(state == Qt::Checked); +} + +void SettingsSound::on_checkBoxGUS_stateChanged(int state) { + ui->pushButtonConfigureGUS->setEnabled(state == Qt::Checked); +} + +void SettingsSound::on_pushButtonConfigureMPU401_clicked() { + if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) { + DeviceConfig::ConfigureDevice(&mpu401_mca_device, 0, qobject_cast(Settings::settings)); + } else { + DeviceConfig::ConfigureDevice(&mpu401_device, 0, qobject_cast(Settings::settings)); + } +} + +void SettingsSound::on_pushButtonConfigureSSI2001_clicked() { + DeviceConfig::ConfigureDevice(&ssi2001_device, 0, qobject_cast(Settings::settings)); +} + +void SettingsSound::on_pushButtonConfigureCMS_clicked() { + DeviceConfig::ConfigureDevice(&cms_device, 0, qobject_cast(Settings::settings)); +} + +void SettingsSound::on_pushButtonConfigureGUS_clicked() { + DeviceConfig::ConfigureDevice(&gus_device, 0, qobject_cast(Settings::settings)); +} diff --git a/src/qt/qt_settingssound.hpp b/src/qt/qt_settingssound.hpp new file mode 100644 index 000000000..c649eb2a2 --- /dev/null +++ b/src/qt/qt_settingssound.hpp @@ -0,0 +1,44 @@ +#ifndef QT_SETTINGSSOUND_HPP +#define QT_SETTINGSSOUND_HPP + +#include + +namespace Ui { +class SettingsSound; +} + +class SettingsSound : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsSound(QWidget *parent = nullptr); + ~SettingsSound(); + + void save(); + +public slots: + void onCurrentMachineChanged(int machineId); + +private slots: + void on_pushButtonConfigureGUS_clicked(); + void on_pushButtonConfigureCMS_clicked(); + void on_pushButtonConfigureSSI2001_clicked(); + void on_pushButtonConfigureMPU401_clicked(); + void on_checkBoxGUS_stateChanged(int arg1); + void on_checkBoxCMS_stateChanged(int arg1); + void on_checkBoxSSI2001_stateChanged(int arg1); + void on_checkBoxMPU401_stateChanged(int arg1); + void on_pushButtonConfigureMidiIn_clicked(); + void on_pushButtonConfigureMidiOut_clicked(); + void on_comboBoxMidiIn_currentIndexChanged(int index); + void on_comboBoxMidiOut_currentIndexChanged(int index); + void on_pushButtonConfigureSoundCard_clicked(); + void on_comboBoxSoundCard_currentIndexChanged(int index); + +private: + Ui::SettingsSound *ui; + int machineId = 0; +}; + +#endif // QT_SETTINGSSOUND_HPP diff --git a/src/qt/qt_settingssound.ui b/src/qt/qt_settingssound.ui new file mode 100644 index 000000000..9ae91dcd2 --- /dev/null +++ b/src/qt/qt_settingssound.ui @@ -0,0 +1,210 @@ + + + SettingsSound + + + + 0 + 0 + 387 + 332 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + MIDI In Device: + + + + + + + Innovation SSI-2001 + + + + + + + Gravis Ultrasound + + + + + + + Sound card: + + + + + + + Configure + + + + + + + + 0 + 0 + + + + + + + + MIDI Out Device: + + + + + + + Standalone MPU-401 + + + + + + + Configure + + + + + + + Configure + + + + + + + Configure + + + + + + + CMS / Game Blaster + + + + + + + + 0 + 0 + + + + + + + + Configure + + + + + + + Use FLOAT32 sound + + + + + + + Configure + + + + + + + Configure + + + + + + + + 0 + 0 + + + + FM synth driver + + + + + + Nuked (more accurate) + + + + + + + YMFM (faster) + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + + + + + diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp new file mode 100644 index 000000000..114654340 --- /dev/null +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -0,0 +1,248 @@ +/* + * 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. + * + * Storage devices configuration UI module. + * + * + * + * Authors: Joakim L. Gilje + * + * Copyright 2021 Joakim L. Gilje + */ +#include "qt_settingsstoragecontrollers.hpp" +#include "ui_qt_settingsstoragecontrollers.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdc_ext.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/cassette.h> +} + +#include "qt_deviceconfig.hpp" +#include "qt_models_common.hpp" + +SettingsStorageControllers::SettingsStorageControllers(QWidget *parent) : + QWidget(parent), + ui(new Ui::SettingsStorageControllers) +{ + ui->setupUi(this); + + ui->checkBoxCassette->setChecked(cassette_enable > 0); + + onCurrentMachineChanged(machine); +} + +SettingsStorageControllers::~SettingsStorageControllers() +{ + delete ui; +} + +void SettingsStorageControllers::save() { + /* Storage devices category */ + for (int i = 0; i < SCSI_BUS_MAX; ++i) { + auto* cbox = findChild(QString("comboBoxSCSI%1").arg(i+1)); + scsi_card_current[i] = cbox->currentData().toInt(); + } + hdc_current = ui->comboBoxHD->currentData().toInt(); + fdc_type = ui->comboBoxFD->currentData().toInt(); + ide_ter_enabled = ui->checkBoxTertiaryIDE->isChecked() ? 1 : 0; + ide_qua_enabled = ui->checkBoxQuaternaryIDE->isChecked() ? 1 : 0; + cassette_enable = ui->checkBoxCassette->isChecked() ? 1 : 0; +} + +void SettingsStorageControllers::onCurrentMachineChanged(int machineId) { + this->machineId = machineId; + + /*HD controller config*/ + auto* model = ui->comboBoxHD->model(); + auto removeRows = model->rowCount(); + int c = 0; + int selectedRow = 0; + while (true) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && (machine_has_flags(machineId, MACHINE_HDC) == 0)) { + c++; + continue; + } + + QString name = DeviceConfig::DeviceName(hdc_get_device(c), hdc_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (hdc_available(c)) { + auto* hdc_dev = hdc_get_device(c); + + if (device_is_valid(hdc_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == hdc_current) { + selectedRow = row - removeRows; + } + } + } + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxHD->setEnabled(model->rowCount() > 0); + ui->comboBoxHD->setCurrentIndex(-1); + ui->comboBoxHD->setCurrentIndex(selectedRow); + + /*FD controller config*/ + model = ui->comboBoxFD->model(); + removeRows = model->rowCount(); + c = 0; + selectedRow = 0; + while (true) { + QString name = DeviceConfig::DeviceName(fdc_card_getdevice(c), fdc_card_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (fdc_card_available(c)) { + auto* fdc_dev = fdc_card_getdevice(c); + + if (device_is_valid(fdc_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == fdc_type) { + selectedRow = row - removeRows; + } + } + } + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxFD->setEnabled(model->rowCount() > 0); + ui->comboBoxFD->setCurrentIndex(-1); + ui->comboBoxFD->setCurrentIndex(selectedRow); + + for (int i = 0; i < SCSI_BUS_MAX; ++i) { + auto* cbox = findChild(QString("comboBoxSCSI%1").arg(i+1)); + model = cbox->model(); + removeRows = model->rowCount(); + c = 0; + selectedRow = 0; + + while (true) { + auto name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (scsi_card_available(c)) { + auto* scsi_dev = scsi_card_getdevice(c); + if (device_is_valid(scsi_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == scsi_card_current[i]) { + selectedRow = row - removeRows; + } + } + } + c++; + } + + model->removeRows(0, removeRows); + cbox->setEnabled(model->rowCount() > 0); + cbox->setCurrentIndex(-1); + cbox->setCurrentIndex(selectedRow); + } + + int is_at = IS_AT(machineId); + ui->checkBoxTertiaryIDE->setEnabled(is_at > 0); + ui->checkBoxQuaternaryIDE->setEnabled(is_at > 0); +} + +void SettingsStorageControllers::on_comboBoxHD_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonHD->setEnabled(hdc_has_config(ui->comboBoxHD->currentData().toInt()) > 0); +} + +void SettingsStorageControllers::on_comboBoxFD_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonFD->setEnabled(hdc_has_config(ui->comboBoxFD->currentData().toInt()) > 0); +} + +void SettingsStorageControllers::on_checkBoxTertiaryIDE_stateChanged(int arg1) { + ui->pushButtonTertiaryIDE->setEnabled(arg1 == Qt::Checked); +} + + +void SettingsStorageControllers::on_checkBoxQuaternaryIDE_stateChanged(int arg1) { + ui->pushButtonQuaternaryIDE->setEnabled(arg1 == Qt::Checked); +} + +void SettingsStorageControllers::on_pushButtonHD_clicked() { + DeviceConfig::ConfigureDevice(hdc_get_device(ui->comboBoxHD->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_pushButtonFD_clicked() { + DeviceConfig::ConfigureDevice(fdc_card_getdevice(ui->comboBoxFD->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_pushButtonTertiaryIDE_clicked() { + DeviceConfig::ConfigureDevice(&ide_ter_device, 0, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_pushButtonQuaternaryIDE_clicked() { + DeviceConfig::ConfigureDevice(&ide_qua_device, 0, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_comboBoxSCSI1_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonSCSI1->setEnabled(scsi_card_has_config(ui->comboBoxSCSI1->currentData().toInt()) > 0); +} + +void SettingsStorageControllers::on_comboBoxSCSI2_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonSCSI2->setEnabled(scsi_card_has_config(ui->comboBoxSCSI2->currentData().toInt()) > 0); +} + +void SettingsStorageControllers::on_comboBoxSCSI3_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonSCSI3->setEnabled(scsi_card_has_config(ui->comboBoxSCSI3->currentData().toInt()) > 0); +} + +void SettingsStorageControllers::on_comboBoxSCSI4_currentIndexChanged(int index) { + if (index < 0) { + return; + } + ui->pushButtonSCSI4->setEnabled(scsi_card_has_config(ui->comboBoxSCSI4->currentData().toInt()) > 0); +} + + +void SettingsStorageControllers::on_pushButtonSCSI1_clicked() { + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI1->currentData().toInt()), 1, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_pushButtonSCSI2_clicked() { + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI2->currentData().toInt()), 2, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_pushButtonSCSI3_clicked() { + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI3->currentData().toInt()), 3, qobject_cast(Settings::settings)); +} + +void SettingsStorageControllers::on_pushButtonSCSI4_clicked() { + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()), 4, qobject_cast(Settings::settings)); +} diff --git a/src/qt/qt_settingsstoragecontrollers.hpp b/src/qt/qt_settingsstoragecontrollers.hpp new file mode 100644 index 000000000..e4596b567 --- /dev/null +++ b/src/qt/qt_settingsstoragecontrollers.hpp @@ -0,0 +1,46 @@ +#ifndef QT_SETTINGSSTORAGECONTROLLERS_HPP +#define QT_SETTINGSSTORAGECONTROLLERS_HPP + +#include + +namespace Ui { +class SettingsStorageControllers; +} + +class SettingsStorageControllers : public QWidget +{ + Q_OBJECT + +public: + explicit SettingsStorageControllers(QWidget *parent = nullptr); + ~SettingsStorageControllers(); + + void save(); + +public slots: + void onCurrentMachineChanged(int machineId); + +private slots: + void on_pushButtonSCSI4_clicked(); + void on_pushButtonSCSI3_clicked(); + void on_pushButtonSCSI2_clicked(); + void on_pushButtonSCSI1_clicked(); + void on_comboBoxSCSI4_currentIndexChanged(int index); + void on_comboBoxSCSI3_currentIndexChanged(int index); + void on_comboBoxSCSI2_currentIndexChanged(int index); + void on_comboBoxSCSI1_currentIndexChanged(int index); + void on_pushButtonQuaternaryIDE_clicked(); + void on_pushButtonTertiaryIDE_clicked(); + void on_pushButtonFD_clicked(); + void on_pushButtonHD_clicked(); + void on_checkBoxQuaternaryIDE_stateChanged(int arg1); + void on_checkBoxTertiaryIDE_stateChanged(int arg1); + void on_comboBoxFD_currentIndexChanged(int index); + void on_comboBoxHD_currentIndexChanged(int index); + +private: + Ui::SettingsStorageControllers *ui; + int machineId = 0; +}; + +#endif // QT_SETTINGSSTORAGECONTROLLERS_HPP diff --git a/src/qt/qt_settingsstoragecontrollers.ui b/src/qt/qt_settingsstoragecontrollers.ui new file mode 100644 index 000000000..c4c44b019 --- /dev/null +++ b/src/qt/qt_settingsstoragecontrollers.ui @@ -0,0 +1,216 @@ + + + SettingsStorageControllers + + + + 0 + 0 + 496 + 449 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + HD Controller: + + + + + + + Configure + + + + + + + FD Controller: + + + + + + + + 0 + 0 + + + + + + + + Configure + + + + + + + + + + Tertiary IDE Controller + + + + + + + Quaternary IDE Controller + + + + + + + false + + + Configure + + + + + + + false + + + Configure + + + + + + + + + SCSI + + + + + + Configure + + + + + + + Configure + + + + + + + Controller 3: + + + + + + + + 0 + 0 + + + + + + + + Configure + + + + + + + + + + + + + + + + Controller 1: + + + + + + + Controller 2: + + + + + + + Controller 4: + + + + + + + Configure + + + + + + + + + + Cassette + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/qt/qt_softwarerenderer.cpp b/src/qt/qt_softwarerenderer.cpp new file mode 100644 index 000000000..850e8369a --- /dev/null +++ b/src/qt/qt_softwarerenderer.cpp @@ -0,0 +1,112 @@ +/* + * 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. + * + * Software renderer module. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * Teemu Korhonen + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + * Copyright 2021-2022 Teemu Korhonen + */ +#include "qt_softwarerenderer.hpp" +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/video.h> +} + +SoftwareRenderer::SoftwareRenderer(QWidget *parent) +#ifdef __HAIKU__ + : QWidget(parent) +#else + : QRasterWindow(parent->windowHandle()) +#endif +{ + RendererCommon::parentWidget = parent; + + images[0] = std::make_unique(QSize(2048, 2048), QImage::Format_RGB32); + images[1] = std::make_unique(QSize(2048, 2048), QImage::Format_RGB32); + + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); +#ifdef __HAIKU__ + this->setMouseTracking(true); +#endif +} + +void SoftwareRenderer::paintEvent(QPaintEvent* event) { + (void)event; + onPaint(this); +} + +void SoftwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { + /* TODO: should look into deleteLater() */ + auto tval = this; + void* nuldata = 0; + if (memcmp(&tval, &nuldata, sizeof(void*)) == 0) return; + + cur_image = buf_idx; + buf_usage[(buf_idx + 1) % 2].clear(); + + source.setRect(x, y, w, h); + update(); +} + +void SoftwareRenderer::resizeEvent(QResizeEvent *event) { + onResize(width(), height()); +#ifdef __HAIKU__ + QWidget::resizeEvent(event); +#else + QRasterWindow::resizeEvent(event); +#endif +} + +bool SoftwareRenderer::event(QEvent *event) +{ + bool res = false; + if (!eventDelegate(event, res)) +#ifdef __HAIKU__ + return QWidget::event(event); +#else + return QRasterWindow::event(event); +#endif + return res; +} + +void SoftwareRenderer::onPaint(QPaintDevice* device) { + if (cur_image == -1) + return; + + QPainter painter(device); + painter.setRenderHint(QPainter::SmoothPixmapTransform, video_filter_method > 0 ? true : false); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + painter.fillRect(0, 0, device->width(), device->height(), QColorConstants::Black); +#else + painter.fillRect(0, 0, device->width(), device->height(), Qt::black); +#endif + painter.setCompositionMode(QPainter::CompositionMode_Plus); + painter.drawImage(destination, *images[cur_image], source); +} + +std::vector> SoftwareRenderer::getBuffers() +{ + std::vector> buffers; + + buffers.push_back(std::make_tuple(images[0]->bits(), &buf_usage[0])); + buffers.push_back(std::make_tuple(images[1]->bits(), &buf_usage[1])); + + return buffers; +} diff --git a/src/qt/qt_softwarerenderer.hpp b/src/qt/qt_softwarerenderer.hpp new file mode 100644 index 000000000..5b0f7b0f5 --- /dev/null +++ b/src/qt/qt_softwarerenderer.hpp @@ -0,0 +1,39 @@ +#ifndef SOFTWARERENDERER_HPP +#define SOFTWARERENDERER_HPP + +#include +#include +#include +#include +#include +#include "qt_renderercommon.hpp" + +class SoftwareRenderer : + #ifdef __HAIKU__ + public QWidget, + #else + public QRasterWindow, + #endif + public RendererCommon +{ + Q_OBJECT +public: + explicit SoftwareRenderer(QWidget *parent = nullptr); + + void paintEvent(QPaintEvent* event) override; + + std::vector> getBuffers() override; + +public slots: + void onBlit(int buf_idx, int x, int y, int w, int h); + +protected: + std::array, 2> images; + int cur_image = -1; + + void onPaint(QPaintDevice* device); + void resizeEvent(QResizeEvent *event) override; + bool event(QEvent *event) override; +}; + +#endif // SOFTWARERENDERER_HPP diff --git a/src/qt/qt_soundgain.cpp b/src/qt/qt_soundgain.cpp new file mode 100644 index 000000000..26ac3dd73 --- /dev/null +++ b/src/qt/qt_soundgain.cpp @@ -0,0 +1,50 @@ +/* + * 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. + * + * Sound gain dialog UI module. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + */ +#include "qt_soundgain.hpp" +#include "ui_qt_soundgain.h" + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/sound.h> +} + +SoundGain::SoundGain(QWidget *parent) : + QDialog(parent), + ui(new Ui::SoundGain) +{ + ui->setupUi(this); + ui->verticalSlider->setValue(sound_gain); + sound_gain_orig = sound_gain; +} + +SoundGain::~SoundGain() +{ + delete ui; +} + +void SoundGain::on_verticalSlider_valueChanged(int value) +{ + sound_gain = value; +} + + +void SoundGain::on_SoundGain_rejected() +{ + sound_gain = sound_gain_orig; +} diff --git a/src/qt/qt_soundgain.hpp b/src/qt/qt_soundgain.hpp new file mode 100644 index 000000000..0e19bab53 --- /dev/null +++ b/src/qt/qt_soundgain.hpp @@ -0,0 +1,28 @@ +#ifndef QT_SOUNDGAIN_HPP +#define QT_SOUNDGAIN_HPP + +#include + +namespace Ui { +class SoundGain; +} + +class SoundGain : public QDialog +{ + Q_OBJECT + +public: + explicit SoundGain(QWidget *parent = nullptr); + ~SoundGain(); + +private slots: + void on_verticalSlider_valueChanged(int value); + + void on_SoundGain_rejected(); + +private: + Ui::SoundGain *ui; + int sound_gain_orig; +}; + +#endif // QT_SOUNDGAIN_HPP diff --git a/src/qt/qt_soundgain.ui b/src/qt/qt_soundgain.ui new file mode 100644 index 000000000..8d3f2c3f6 --- /dev/null +++ b/src/qt/qt_soundgain.ui @@ -0,0 +1,126 @@ + + + SoundGain + + + + 0 + 0 + 200 + 250 + + + + + 0 + 0 + + + + + 200 + 250 + + + + + 200 + 250 + + + + Sound Gain + + + + + + + 0 + 0 + + + + Gain + + + Qt::AlignCenter + + + + + + + 18 + + + 2 + + + 4 + + + Qt::Vertical + + + false + + + QSlider::TicksBothSides + + + + + + + + 0 + 0 + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SoundGain + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SoundGain + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_specifydimensions.cpp b/src/qt/qt_specifydimensions.cpp new file mode 100644 index 000000000..1fc294d79 --- /dev/null +++ b/src/qt/qt_specifydimensions.cpp @@ -0,0 +1,116 @@ +/* + * 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. + * + * Specify dimensions UI module. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + */ +#include "qt_specifydimensions.h" +#include "ui_qt_specifydimensions.h" + +#include "qt_mainwindow.hpp" +#include "ui_qt_mainwindow.h" + +#include "qt_util.hpp" + +#include +#include +#include +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/video.h> +} + +extern MainWindow* main_window; + +SpecifyDimensions::SpecifyDimensions(QWidget *parent) : + QDialog(parent), + ui(new Ui::SpecifyDimensions) +{ + ui->setupUi(this); + ui->checkBox->setChecked(vid_resize == 2); + ui->spinBoxWidth->setRange(16, 2048); + ui->spinBoxWidth->setValue(main_window->getRenderWidgetSize().width()); + ui->spinBoxHeight->setRange(16, 2048); + ui->spinBoxHeight->setValue(main_window->getRenderWidgetSize().height()); + + if (dpi_scale == 0) { + ui->spinBoxWidth->setValue(main_window->getRenderWidgetSize().width() * util::screenOfWidget(main_window)->devicePixelRatio()); + ui->spinBoxHeight->setValue(main_window->getRenderWidgetSize().height() * util::screenOfWidget(main_window)->devicePixelRatio()); + } +} + +SpecifyDimensions::~SpecifyDimensions() +{ + delete ui; +} + +void SpecifyDimensions::on_SpecifyDimensions_accepted() +{ + if (ui->checkBox->isChecked()) + { + vid_resize = 2; + main_window->setWindowFlag(Qt::WindowMaximizeButtonHint, false); + main_window->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); + window_remember = 0; + fixed_size_x = ui->spinBoxWidth->value(); + fixed_size_y = ui->spinBoxHeight->value(); + + main_window->resizeContents(fixed_size_x, fixed_size_y); + + emit main_window->updateMenuResizeOptions(); + main_window->show(); + for (int i = 1; i < MONITORS_NUM; i++) { + if (main_window->renderers[i]) { + main_window->renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint, false); + main_window->renderers[i]->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); + emit main_window->resizeContentsMonitor(fixed_size_x, fixed_size_y, i); + if (show_second_monitors) { + main_window->renderers[i]->show(); + main_window->renderers[i]->switchRenderer((RendererStack::Renderer)vid_api); + } + } + } + main_window->ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api); + } + else + { + main_window->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + main_window->ui->actionResizable_window->setChecked(false); + vid_resize = 0; + main_window->ui->actionResizable_window->trigger(); + window_remember = 1; + window_w = ui->spinBoxWidth->value(); + window_h = ui->spinBoxHeight->value(); + main_window->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + emit main_window->resizeContents(ui->spinBoxWidth->value(), ui->spinBoxHeight->value()); + for (int i = 1; i < MONITORS_NUM; i++) { + if (main_window->renderers[i]) { + main_window->renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint); + main_window->renderers[i]->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, false); + emit main_window->resizeContentsMonitor(ui->spinBoxWidth->value(), ui->spinBoxHeight->value(), i); + main_window->renderers[i]->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + if (show_second_monitors) { main_window->renderers[i]->show(); + main_window->renderers[i]->switchRenderer((RendererStack::Renderer)vid_api); } + } + } + vid_resize = 1; + emit main_window->updateMenuResizeOptions(); + } + main_window->show(); + emit main_window->updateWindowRememberOption(); +} diff --git a/src/qt/qt_specifydimensions.h b/src/qt/qt_specifydimensions.h new file mode 100644 index 000000000..2aa820455 --- /dev/null +++ b/src/qt/qt_specifydimensions.h @@ -0,0 +1,25 @@ +#ifndef QT_SPECIFYDIMENSIONS_H +#define QT_SPECIFYDIMENSIONS_H + +#include + +namespace Ui { +class SpecifyDimensions; +} + +class SpecifyDimensions : public QDialog +{ + Q_OBJECT + +public: + explicit SpecifyDimensions(QWidget *parent = nullptr); + ~SpecifyDimensions(); + +private slots: + void on_SpecifyDimensions_accepted(); + +private: + Ui::SpecifyDimensions *ui; +}; + +#endif // QT_SPECIFYDIMENSIONS_H diff --git a/src/qt/qt_specifydimensions.ui b/src/qt/qt_specifydimensions.ui new file mode 100644 index 000000000..8012ced71 --- /dev/null +++ b/src/qt/qt_specifydimensions.ui @@ -0,0 +1,91 @@ + + + SpecifyDimensions + + + + 0 + 0 + 388 + 158 + + + + Specify Main Window Dimensions + + + + + + Width: + + + + + + + + + + Height: + + + + + + + + + + Lock to this size + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SpecifyDimensions + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SpecifyDimensions + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_styleoverride.cpp b/src/qt/qt_styleoverride.cpp new file mode 100644 index 000000000..a2af1296b --- /dev/null +++ b/src/qt/qt_styleoverride.cpp @@ -0,0 +1,54 @@ +/* + * 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. + * + * Style override class. + * + * + * + * Authors: Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ +#include "qt_styleoverride.hpp" + +#include +#include + +int StyleOverride::styleHint( + StyleHint hint, + const QStyleOption *option, + const QWidget *widget, + QStyleHintReturn *returnData) const +{ + /* Disable using menu with alt key */ + if (hint == QStyle::SH_MenuBar_AltKeyNavigation) + return 0; + + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +void StyleOverride::polish(QWidget* widget) +{ + QProxyStyle::polish(widget); + /* Disable title bar context help buttons globally as they are unused. */ + if (widget->isWindow()) { + if (widget->layout() && widget->minimumSize() == widget->maximumSize()) { + if (widget->minimumSize().width() < widget->minimumSizeHint().width() + || widget->minimumSize().height() < widget->minimumSizeHint().height()) { + widget->setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); + widget->layout()->setSizeConstraint(QLayout::SetFixedSize); + } + widget->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, true); + } + widget->setWindowFlag(Qt::WindowContextHelpButtonHint, false); + } + + if (qobject_cast(widget)) { + qobject_cast(widget)->view()->setMinimumWidth(widget->minimumSizeHint().width()); + } +} diff --git a/src/qt/qt_styleoverride.hpp b/src/qt/qt_styleoverride.hpp new file mode 100644 index 000000000..9a2223322 --- /dev/null +++ b/src/qt/qt_styleoverride.hpp @@ -0,0 +1,20 @@ +#ifndef QT_STYLEOVERRIDE_HPP +#define QT_STYLEOVERRIDE_HPP + +#include +#include +#include + +class StyleOverride : public QProxyStyle +{ +public: + int styleHint( + StyleHint hint, + const QStyleOption *option = nullptr, + const QWidget *widget = nullptr, + QStyleHintReturn *returnData = nullptr) const override; + + void polish(QWidget* widget) override; +}; + +#endif diff --git a/src/qt/qt_translations.qrc b/src/qt/qt_translations.qrc new file mode 100644 index 000000000..1de212273 --- /dev/null +++ b/src/qt/qt_translations.qrc @@ -0,0 +1,24 @@ + + + 86box_cs-CZ.qm + 86box_de-DE.qm + 86box_en-US.qm + 86box_en-GB.qm + 86box_es-ES.qm + 86box_fi-FI.qm + 86box_fr-FR.qm + 86box_hr-HR.qm + 86box_hu-HU.qm + 86box_it-IT.qm + 86box_ja-JP.qm + 86box_ko-KR.qm + 86box_pl-PL.qm + 86box_pt-BR.qm + 86box_pt-PT.qm + 86box_ru-RU.qm + 86box_sl-SI.qm + 86box_tr-TR.qm + 86box_uk-UA.qm + 86box_zh-CN.qm + + diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp new file mode 100644 index 000000000..7400a4f7a --- /dev/null +++ b/src/qt/qt_ui.cpp @@ -0,0 +1,258 @@ +/* + * 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. + * + * Common UI functions. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2021-2022 Cacodemon345 + */ +#include + +#include +#include +#include + +#include + +#include "qt_mainwindow.hpp" +#include "qt_machinestatus.hpp" + +MainWindow* main_window = nullptr; + +static QString sb_text, sb_buguitext, sb_mt32lcdtext; + +extern "C" { + +#include "86box/86box.h" +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/mouse.h> +#include <86box/timer.h> +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/fdd.h> +#include <86box/hdc.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/cartridge.h> +#include <86box/cassette.h> +#include <86box/cdrom.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/hdd.h> +#include <86box/machine_status.h> + +void +plat_delay_ms(uint32_t count) +{ + QThread::msleep(count); +} + +wchar_t* ui_window_title(wchar_t* str) +{ + if (str == nullptr) { + static wchar_t title[512]; + memset(title, 0, sizeof(title)); + main_window->getTitle(title); + str = title; + } else { + emit main_window->setTitle(QString::fromWCharArray(str)); + } + return str; +} + +extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index) +{ + main_window->blitToWidget(x, y, w, h, monitor_index); +} + +void mouse_poll() { + main_window->pollMouse(); +} + +extern "C" int vid_resize; +void plat_resize_request(int w, int h, int monitor_index) +{ + if (video_fullscreen || is_quit) return; + if (vid_resize & 2) { + plat_resize_monitor(fixed_size_x, fixed_size_y, monitor_index); + } + else { + plat_resize_monitor(w, h, monitor_index); + } +} + +void plat_resize_monitor(int w, int h, int monitor_index) { + if (monitor_index >= 1) main_window->resizeContentsMonitor(w, h, monitor_index); + else main_window->resizeContents(w, h); +} + +void plat_setfullscreen(int on) { + main_window->setFullscreen(on > 0 ? true : false); +} + +void plat_mouse_capture(int on) { + if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE)) + return; + + main_window->setMouseCapture(on > 0 ? true : false); +} + +int ui_msgbox_header(int flags, void *header, void* message) { + if (header <= (void*)7168) header = plat_get_string((uintptr_t)header); + if (message <= (void*)7168) message = plat_get_string((uintptr_t)message); + + auto hdr = (flags & MBX_ANSI) ? QString((char*)header) : QString::fromWCharArray(reinterpret_cast(header)); + auto msg = (flags & MBX_ANSI) ? QString((char*)message) : QString::fromWCharArray(reinterpret_cast(message)); + + // any error in early init + if (main_window == nullptr) { + QMessageBox msgBox(QMessageBox::Icon::Critical, hdr, msg); + msgBox.setTextFormat(Qt::TextFormat::RichText); + msgBox.exec(); + } else { + // else scope it to main_window + main_window->showMessage(flags, hdr, msg); + } + return 0; +} + +void ui_init_monitor(int monitor_index) { + if (QThread::currentThread() == main_window->thread()) { + emit main_window->initRendererMonitor(monitor_index); + } + else emit main_window->initRendererMonitorForNonQtThread(monitor_index); +} + +void ui_deinit_monitor(int monitor_index) { + if (QThread::currentThread() == main_window->thread()) { + emit main_window->destroyRendererMonitor(monitor_index); + } + else emit main_window->destroyRendererMonitorForNonQtThread(monitor_index); +} + +int ui_msgbox(int flags, void *message) { + return ui_msgbox_header(flags, nullptr, message); +} + +void ui_sb_update_text() { + emit main_window->statusBarMessage( !sb_mt32lcdtext.isEmpty() ? sb_mt32lcdtext : sb_text.isEmpty() ? sb_buguitext : sb_text); +} + +void ui_sb_mt32lcd(char* str) +{ + sb_mt32lcdtext = QString(str); + ui_sb_update_text(); +} + +void ui_sb_set_text_w(wchar_t *wstr) { + sb_text = QString::fromWCharArray(wstr); + ui_sb_update_text(); +} + +void ui_sb_set_text(char *str) { + sb_text = str; + ui_sb_update_text(); +} + +void +ui_sb_update_tip(int arg) { + main_window->updateStatusBarTip(arg); +} + +void +ui_sb_update_panes() { + main_window->updateStatusBarPanes(); +} + +void ui_sb_bugui(char *str) { + sb_buguitext = str; + ui_sb_update_text();; +} + +void ui_sb_set_ready(int ready) { + if (ready == 0) { + ui_sb_bugui(nullptr); + ui_sb_set_text(nullptr); + } +} + +void +ui_sb_update_icon_state(int tag, int state) { + int category = tag & 0xfffffff0; + int item = tag & 0xf; + switch (category) { + case SB_CASSETTE: + machine_status.cassette.empty = state > 0 ? true : false; + break; + case SB_CARTRIDGE: + machine_status.cartridge[item].empty = state > 0 ? true : false; + break; + case SB_FLOPPY: + machine_status.fdd[item].empty = state > 0 ? true : false; + break; + case SB_CDROM: + machine_status.cdrom[item].empty = state > 0 ? true : false; + break; + case SB_ZIP: + machine_status.zip[item].empty = state > 0 ? true : false; + break; + case SB_MO: + machine_status.mo[item].empty = state > 0 ? true : false; + break; + case SB_HDD: + break; + case SB_NETWORK: + break; + case SB_SOUND: + break; + case SB_TEXT: + break; + } +} + +void +ui_sb_update_icon(int tag, int active) { + int category = tag & 0xfffffff0; + int item = tag & 0xf; + switch (category) { + case SB_CASSETTE: + break; + case SB_CARTRIDGE: + break; + case SB_FLOPPY: + machine_status.fdd[item].active = active > 0 ? true : false; + break; + case SB_CDROM: + machine_status.cdrom[item].active = active > 0 ? true : false; + break; + case SB_ZIP: + machine_status.zip[item].active = active > 0 ? true : false; + break; + case SB_MO: + machine_status.mo[item].active = active > 0 ? true : false; + break; + case SB_HDD: + machine_status.hdd[item].active = active > 0 ? true : false; + break; + case SB_NETWORK: + machine_status.net.active = active > 0 ? true : false; + break; + case SB_SOUND: + break; + case SB_TEXT: + break; + } +} + +} diff --git a/src/qt/qt_unixmanagerfilter.cpp b/src/qt/qt_unixmanagerfilter.cpp new file mode 100644 index 000000000..9df6da5cb --- /dev/null +++ b/src/qt/qt_unixmanagerfilter.cpp @@ -0,0 +1,78 @@ +/* + * 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. + * + * Source file for Unix VM-managers (client-side) + * + * Authors: + * Teemu Korhonen + Cacodemon345 + * + * Copyright 2022 Teemu Korhonen + * Copyright 2022 Cacodemon345 + */ + +#include "qt_unixmanagerfilter.hpp" + +UnixManagerSocket::UnixManagerSocket(QObject* obj) + : QLocalSocket(obj) +{ + connect(this, &QLocalSocket::readyRead, this, &UnixManagerSocket::readyToRead); +} + +void UnixManagerSocket::readyToRead() +{ + if (canReadLine()) + { + QByteArray line = readLine(); + if (line.size()) + { + line.resize(line.size() - 1); + if (line == "showsettings") + { + emit showsettings(); + } + else if (line == "pause") + { + emit pause(); + } + else if (line == "cad") + { + emit ctrlaltdel(); + } + else if (line == "reset") + { + emit resetVM(); + } + else if (line == "shutdownnoprompt") + { + emit force_shutdown(); + } + else if (line == "shutdown") + { + emit request_shutdown(); + } + } + } +} + +bool UnixManagerSocket::eventFilter(QObject *obj, QEvent *event) +{ + if (state() == QLocalSocket::ConnectedState) + { + if (event->type() == QEvent::WindowBlocked) + { + write(QByteArray{"1"}); + } + else if (event->type() == QEvent::WindowUnblocked) + { + write(QByteArray{"0"}); + } + } + + return QObject::eventFilter(obj, event); +} diff --git a/src/qt/qt_unixmanagerfilter.hpp b/src/qt/qt_unixmanagerfilter.hpp new file mode 100644 index 000000000..33b0f76a8 --- /dev/null +++ b/src/qt/qt_unixmanagerfilter.hpp @@ -0,0 +1,50 @@ +/* + * 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. + * + * Header file for Unix VM-managers (client-side) + * + * Authors: + * Teemu Korhonen + Cacodemon345 + * + * Copyright 2022 Teemu Korhonen + * Copyright 2022 Cacodemon345 + */ + +#ifndef QT_UNIXMANAGERFILTER_HPP +#define QT_UNIXMANAGERFILTER_HPP + +#include +#include +#include + +/* + * Filters messages from VM-manager and + * window blocked events to notify about open modal dialogs. + */ +class UnixManagerSocket : public QLocalSocket +{ + Q_OBJECT +public: + UnixManagerSocket(QObject* object = nullptr); +signals: + void pause(); + void ctrlaltdel(); + void showsettings(); + void resetVM(); + void request_shutdown(); + void force_shutdown(); + void dialogstatus(bool open); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; +protected slots: + void readyToRead(); +}; + +#endif diff --git a/src/qt/qt_util.cpp b/src/qt/qt_util.cpp new file mode 100644 index 000000000..771c6d94a --- /dev/null +++ b/src/qt/qt_util.cpp @@ -0,0 +1,60 @@ +/* + * 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. + * + * Utility functions. + * + * + * + * Authors: Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ +#include +#include +#include +#include +#if QT_VERSION <= QT_VERSION_CHECK(5, 14, 0) +#include +#endif +#include "qt_util.hpp" + +namespace util +{ + QScreen* screenOfWidget(QWidget* widget) + { +#if QT_VERSION <= QT_VERSION_CHECK(5, 14, 0) + return QApplication::screens()[QApplication::desktop()->screenNumber(widget) == -1 ? 0 : QApplication::desktop()->screenNumber(widget)]; +#else + return widget->screen(); +#endif + } + + QString DlgFilter(std::initializer_list extensions, bool last) + { + QStringList temp; + + for (auto ext : extensions) + { +#ifdef Q_OS_UNIX + if (ext == "*") + { + temp.append("*"); + continue; + } + temp.append("*." % ext.toUpper()); +#endif + temp.append("*." % ext); + } + +#ifdef Q_OS_UNIX + temp.removeDuplicates(); +#endif + return " (" % temp.join(' ') % ")" % (!last ? ";;" : ""); + } + +} diff --git a/src/qt/qt_util.hpp b/src/qt/qt_util.hpp new file mode 100644 index 000000000..4e62c8e12 --- /dev/null +++ b/src/qt/qt_util.hpp @@ -0,0 +1,18 @@ +#ifndef QT_UTIL_HPP +#define QT_UTIL_HPP + +#include +#include + +#include + +class QScreen; +namespace util +{ + /* Creates extension list for qt filedialog */ + QString DlgFilter(std::initializer_list extensions, bool last = false); + /* Returns screen the widget is on */ + QScreen* screenOfWidget(QWidget* widget); +}; + +#endif diff --git a/src/qt/qt_vulkanrenderer.cpp b/src/qt/qt_vulkanrenderer.cpp new file mode 100644 index 000000000..c62154669 --- /dev/null +++ b/src/qt/qt_vulkanrenderer.cpp @@ -0,0 +1,1007 @@ +/**************************************************************************** +** +** Copyright (C) 2022 Cacodemon345 +** Copyright (C) 2017 The Qt Company Ltd. +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + +#include +#include +#include "qt_vulkanrenderer.hpp" +#if QT_CONFIG(vulkan) +#include + +extern "C" +{ +#include <86box/86box.h> +} + +// Use a triangle strip to get a quad. +// +// Note that the vertex data and the projection matrix assume OpenGL. With +// Vulkan Y is negated in clip space and the near/far plane is at 0/1 instead +// of -1/1. These will be corrected for by an extra transformation when +// calculating the modelview-projection matrix. +static float vertexData[] = { // Y up, front = CW + // x, y, z, u, v + -1, -1, 0, 0, 1, + -1, 1, 0, 0, 0, + 1, -1, 0, 1, 1, + 1, 1, 0, 1, 0 +}; + +static const int UNIFORM_DATA_SIZE = 16 * sizeof(float); + +static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign) +{ + return (v + byteAlign - 1) & ~(byteAlign - 1); +} + +VulkanRenderer2::VulkanRenderer2(QVulkanWindow *w) + : m_window(w) +{ +} + +VkShaderModule VulkanRenderer2::createShader(const QString &name) +{ + QFile file(name); + if (!file.open(QIODevice::ReadOnly)) { + qWarning("Failed to read shader %s", qPrintable(name)); + return VK_NULL_HANDLE; + } + QByteArray blob = file.readAll(); + file.close(); + + VkShaderModuleCreateInfo shaderInfo; + memset(&shaderInfo, 0, sizeof(shaderInfo)); + shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shaderInfo.codeSize = blob.size(); + shaderInfo.pCode = reinterpret_cast(blob.constData()); + VkShaderModule shaderModule; + VkResult err = m_devFuncs->vkCreateShaderModule(m_window->device(), &shaderInfo, nullptr, &shaderModule); + if (err != VK_SUCCESS) { + qWarning("Failed to create shader module: %d", err); + return VK_NULL_HANDLE; + } + + return shaderModule; +} + +bool VulkanRenderer2::createTexture() +{ + QImage img(2048, 2048, QImage::Format_RGBA8888_Premultiplied); + img.fill(QColor(0, 0, 0)); + + QVulkanFunctions *f = m_window->vulkanInstance()->functions(); + VkDevice dev = m_window->device(); + + m_texFormat = VK_FORMAT_B8G8R8A8_UNORM; + + // Now we can either map and copy the image data directly, or have to go + // through a staging buffer to copy and convert into the internal optimal + // tiling format. + VkFormatProperties props; + f->vkGetPhysicalDeviceFormatProperties(m_window->physicalDevice(), m_texFormat, &props); + const bool canSampleLinear = (props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); + const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); + if (!canSampleLinear && !canSampleOptimal) { + qWarning("Neither linear nor optimal image sampling is supported for RGBA8"); + return false; + } + + static bool alwaysStage = qEnvironmentVariableIntValue("QT_VK_FORCE_STAGE_TEX"); + + if (canSampleLinear && !alwaysStage) { + if (!createTextureImage(img.size(), &m_texImage, &m_texMem, + VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, + m_window->hostVisibleMemoryIndex())) + return false; + + if (!writeLinearImage(img, m_texImage, m_texMem)) + return false; + + m_texLayoutPending = true; + } else { + if (!createTextureImage(img.size(), &m_texStaging, &m_texStagingMem, + VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + m_window->hostVisibleMemoryIndex())) + return false; + + if (!createTextureImage(img.size(), &m_texImage, &m_texMem, + VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + m_window->deviceLocalMemoryIndex())) + return false; + + if (!writeLinearImage(img, m_texStaging, m_texStagingMem)) + return false; + + m_texStagingPending = true; + } + + VkImageViewCreateInfo viewInfo; + memset(&viewInfo, 0, sizeof(viewInfo)); + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = m_texImage; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = m_texFormat; + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.levelCount = viewInfo.subresourceRange.layerCount = 1; + + VkResult err = m_devFuncs->vkCreateImageView(dev, &viewInfo, nullptr, &m_texView); + if (err != VK_SUCCESS) { + qWarning("Failed to create image view for texture: %d", err); + return false; + } + + m_texSize = img.size(); + + return true; +} + +bool VulkanRenderer2::createTextureImage(const QSize &size, VkImage *image, VkDeviceMemory *mem, + VkImageTiling tiling, VkImageUsageFlags usage, uint32_t memIndex) +{ + VkDevice dev = m_window->device(); + + VkImageCreateInfo imageInfo; + memset(&imageInfo, 0, sizeof(imageInfo)); + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.format = m_texFormat; + imageInfo.extent.width = size.width(); + imageInfo.extent.height = size.height(); + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.tiling = tiling; + imageInfo.usage = usage; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + + VkResult err = m_devFuncs->vkCreateImage(dev, &imageInfo, nullptr, image); + if (err != VK_SUCCESS) { + qWarning("Failed to create linear image for texture: %d", err); + return false; + } + + VkMemoryRequirements memReq; + m_devFuncs->vkGetImageMemoryRequirements(dev, *image, &memReq); + + if (!(memReq.memoryTypeBits & (1 << memIndex))) { + VkPhysicalDeviceMemoryProperties physDevMemProps; + m_window->vulkanInstance()->functions()->vkGetPhysicalDeviceMemoryProperties(m_window->physicalDevice(), &physDevMemProps); + for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) { + if (!(memReq.memoryTypeBits & (1 << i))) + continue; + memIndex = i; + } + } + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + nullptr, + memReq.size, + memIndex + }; + qDebug("allocating %u bytes for texture image", uint32_t(memReq.size)); + + err = m_devFuncs->vkAllocateMemory(dev, &allocInfo, nullptr, mem); + if (err != VK_SUCCESS) { + qWarning("Failed to allocate memory for linear image: %d", err); + return false; + } + + err = m_devFuncs->vkBindImageMemory(dev, *image, *mem, 0); + if (err != VK_SUCCESS) { + qWarning("Failed to bind linear image memory: %d", err); + return false; + } + + return true; +} + +bool VulkanRenderer2::writeLinearImage(const QImage &img, VkImage image, VkDeviceMemory memory) +{ + VkDevice dev = m_window->device(); + + VkImageSubresource subres = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, // mip level + 0 + }; + VkSubresourceLayout layout; + m_devFuncs->vkGetImageSubresourceLayout(dev, image, &subres, &layout); + + uchar *p; + VkResult err = m_devFuncs->vkMapMemory(dev, memory, layout.offset, layout.size, 0, reinterpret_cast(&p)); + if (err != VK_SUCCESS) { + qWarning("Failed to map memory for linear image: %d", err); + return false; + } + + for (int y = 0; y < img.height(); ++y) { + const uchar *line = img.constScanLine(y); + memcpy(p, line, img.width() * 4); + p += layout.rowPitch; + } + + m_devFuncs->vkUnmapMemory(dev, memory); + return true; +} + +void VulkanRenderer2::ensureTexture() +{ + if (!m_texLayoutPending && !m_texStagingPending) + return; + + Q_ASSERT(m_texLayoutPending != m_texStagingPending); + VkCommandBuffer cb = m_window->currentCommandBuffer(); + + VkImageMemoryBarrier barrier; + memset(&barrier, 0, sizeof(barrier)); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1; + + if (m_texLayoutPending) { + m_texLayoutPending = false; + + barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.image = m_texImage; + + m_devFuncs->vkCmdPipelineBarrier(cb, + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, 0, nullptr, 0, nullptr, + 1, &barrier); + + VkDevice dev = m_window->device(); + + VkImageSubresource subres = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, // mip level + 0 + }; + VkSubresourceLayout layout; + m_devFuncs->vkGetImageSubresourceLayout(dev, m_texImage, &subres, &layout); + + VkResult err = m_devFuncs->vkMapMemory(dev, m_texMem, layout.offset, layout.size, 0, reinterpret_cast(&mappedPtr)); + if (err != VK_SUCCESS) { + qWarning("Failed to map memory for linear image: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + imagePitch = layout.rowPitch; + + if (qobject_cast(m_window)) { + emit qobject_cast(m_window)->rendererInitialized(); + } + } else { + m_texStagingPending = false; + + if (!m_texStagingTransferLayout) { + barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.image = m_texStaging; + m_devFuncs->vkCmdPipelineBarrier(cb, + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, nullptr, 0, nullptr, + 1, &barrier); + + barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.image = m_texImage; + m_devFuncs->vkCmdPipelineBarrier(cb, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, nullptr, 0, nullptr, + 1, &barrier); + + VkDevice dev = m_window->device(); + + VkImageSubresource subres = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, // mip level + 0 + }; + VkSubresourceLayout layout; + m_devFuncs->vkGetImageSubresourceLayout(dev, m_texStaging, &subres, &layout); + + VkResult err = m_devFuncs->vkMapMemory(dev, m_texStagingMem, layout.offset, layout.size, 0, reinterpret_cast(&mappedPtr)); + if (err != VK_SUCCESS) { + qWarning("Failed to map memory for linear image: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + imagePitch = layout.rowPitch; + + if (qobject_cast(m_window)) { + emit qobject_cast(m_window)->rendererInitialized(); + } + + m_texStagingTransferLayout = true; + } + + VkImageCopy copyInfo; + memset(©Info, 0, sizeof(copyInfo)); + copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyInfo.srcSubresource.layerCount = 1; + copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyInfo.dstSubresource.layerCount = 1; + copyInfo.extent.width = m_texSize.width(); + copyInfo.extent.height = m_texSize.height(); + copyInfo.extent.depth = 1; + m_devFuncs->vkCmdCopyImage(cb, m_texStaging, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + m_texImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.image = m_texImage; + m_devFuncs->vkCmdPipelineBarrier(cb, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, 0, nullptr, 0, nullptr, + 1, &barrier); + } +} + +void VulkanRenderer2::updateSamplers() +{ + static int cur_video_filter_method = -1; + + if (cur_video_filter_method != video_filter_method) { + cur_video_filter_method = video_filter_method; + m_devFuncs->vkDeviceWaitIdle(m_window->device()); + + VkDescriptorImageInfo descImageInfo = { + cur_video_filter_method == 1 ? m_linearSampler : m_sampler, + m_texView, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }; + + for (int i = 0; i < m_window->concurrentFrameCount(); i++) { + VkWriteDescriptorSet descWrite[2]; + memset(descWrite, 0, sizeof(descWrite)); + descWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite[0].dstSet = m_descSet[i]; + descWrite[0].dstBinding = 0; + descWrite[0].descriptorCount = 1; + descWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descWrite[0].pBufferInfo = &m_uniformBufInfo[i]; + + descWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite[1].dstSet = m_descSet[i]; + descWrite[1].dstBinding = 1; + descWrite[1].descriptorCount = 1; + descWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descWrite[1].pImageInfo = &descImageInfo; + m_devFuncs->vkUpdateDescriptorSets(m_window->device(), 2, descWrite, 0, nullptr); + } + } +} + +void VulkanRenderer2::initResources() +{ + qDebug("initResources"); + + VkDevice dev = m_window->device(); + m_devFuncs = m_window->vulkanInstance()->deviceFunctions(dev); + + // The setup is similar to hellovulkantriangle. The difference is the + // presence of a second vertex attribute (texcoord), a sampler, and that we + // need blending. + + const int concurrentFrameCount = m_window->concurrentFrameCount(); + const VkPhysicalDeviceLimits *pdevLimits = &m_window->physicalDeviceProperties()->limits; + const VkDeviceSize uniAlign = pdevLimits->minUniformBufferOffsetAlignment; + qDebug("uniform buffer offset alignment is %u", (uint) uniAlign); + VkBufferCreateInfo bufInfo; + memset(&bufInfo, 0, sizeof(bufInfo)); + bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + // Our internal layout is vertex, uniform, uniform, ... with each uniform buffer start offset aligned to uniAlign. + const VkDeviceSize vertexAllocSize = aligned(sizeof(vertexData), uniAlign); + const VkDeviceSize uniformAllocSize = aligned(UNIFORM_DATA_SIZE, uniAlign); + bufInfo.size = vertexAllocSize + concurrentFrameCount * uniformAllocSize; + bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + + VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_buf); + if (err != VK_SUCCESS) { + qWarning("Failed to create buffer: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + VkMemoryRequirements memReq; + m_devFuncs->vkGetBufferMemoryRequirements(dev, m_buf, &memReq); + + VkMemoryAllocateInfo memAllocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + nullptr, + memReq.size, + m_window->hostVisibleMemoryIndex() + }; + + err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_bufMem); + if (err != VK_SUCCESS) { + qWarning("Failed to allocate memory: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + err = m_devFuncs->vkBindBufferMemory(dev, m_buf, m_bufMem, 0); + if (err != VK_SUCCESS) { + qWarning("Failed to bind buffer memory: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + quint8 *p; + err = m_devFuncs->vkMapMemory(dev, m_bufMem, 0, memReq.size, 0, reinterpret_cast(&p)); + if (err != VK_SUCCESS) { + qWarning("Failed to map memory: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + memcpy(p, vertexData, sizeof(vertexData)); + QMatrix4x4 ident; + memset(m_uniformBufInfo, 0, sizeof(m_uniformBufInfo)); + for (int i = 0; i < concurrentFrameCount; ++i) { + const VkDeviceSize offset = vertexAllocSize + i * uniformAllocSize; + memcpy(p + offset, ident.constData(), 16 * sizeof(float)); + m_uniformBufInfo[i].buffer = m_buf; + m_uniformBufInfo[i].offset = offset; + m_uniformBufInfo[i].range = uniformAllocSize; + } + m_devFuncs->vkUnmapMemory(dev, m_bufMem); + + VkVertexInputBindingDescription vertexBindingDesc = { + 0, // binding + 5 * sizeof(float), + VK_VERTEX_INPUT_RATE_VERTEX + }; + VkVertexInputAttributeDescription vertexAttrDesc[] = { + { // position + 0, // location + 0, // binding + VK_FORMAT_R32G32B32_SFLOAT, + 0 + }, + { // texcoord + 1, + 0, + VK_FORMAT_R32G32_SFLOAT, + 3 * sizeof(float) + } + }; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.pNext = nullptr; + vertexInputInfo.flags = 0; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDesc; + vertexInputInfo.vertexAttributeDescriptionCount = 2; + vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc; + + // Sampler. + VkSamplerCreateInfo samplerInfo; + memset(&samplerInfo, 0, sizeof(samplerInfo)); + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_NEAREST; + samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.maxLod = 0.25; + err = m_devFuncs->vkCreateSampler(dev, &samplerInfo, nullptr, &m_sampler); + if (err != VK_SUCCESS) { + qWarning("Failed to create sampler: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + err = m_devFuncs->vkCreateSampler(dev, &samplerInfo, nullptr, &m_linearSampler); + if (err != VK_SUCCESS) { + qWarning("Failed to create sampler: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + // Texture. + if (!createTexture()) { + qWarning("Failed to create texture"); + return emit qobject_cast(m_window)->errorInitializing(); + } + + // Set up descriptor set and its layout. + VkDescriptorPoolSize descPoolSizes[2] = { + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uint32_t(concurrentFrameCount) }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32_t(concurrentFrameCount) } + }; + VkDescriptorPoolCreateInfo descPoolInfo; + memset(&descPoolInfo, 0, sizeof(descPoolInfo)); + descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descPoolInfo.maxSets = concurrentFrameCount; + descPoolInfo.poolSizeCount = 2; + descPoolInfo.pPoolSizes = descPoolSizes; + err = m_devFuncs->vkCreateDescriptorPool(dev, &descPoolInfo, nullptr, &m_descPool); + if (err != VK_SUCCESS) { + qWarning("Failed to create descriptor pool: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + VkDescriptorSetLayoutBinding layoutBinding[2] = + { + { + 0, // binding + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 1, // descriptorCount + VK_SHADER_STAGE_VERTEX_BIT, + nullptr + }, + { + 1, // binding + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 1, // descriptorCount + VK_SHADER_STAGE_FRAGMENT_BIT, + nullptr + } + }; + VkDescriptorSetLayoutCreateInfo descLayoutInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + nullptr, + 0, + 2, // bindingCount + layoutBinding + }; + err = m_devFuncs->vkCreateDescriptorSetLayout(dev, &descLayoutInfo, nullptr, &m_descSetLayout); + if (err != VK_SUCCESS) { + qWarning("Failed to create descriptor set layout: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + for (int i = 0; i < concurrentFrameCount; ++i) { + VkDescriptorSetAllocateInfo descSetAllocInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + nullptr, + m_descPool, + 1, + &m_descSetLayout + }; + err = m_devFuncs->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_descSet[i]); + if (err != VK_SUCCESS) { + qWarning("Failed to allocate descriptor set: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + VkWriteDescriptorSet descWrite[2]; + memset(descWrite, 0, sizeof(descWrite)); + descWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite[0].dstSet = m_descSet[i]; + descWrite[0].dstBinding = 0; + descWrite[0].descriptorCount = 1; + descWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descWrite[0].pBufferInfo = &m_uniformBufInfo[i]; + + VkDescriptorImageInfo descImageInfo = { + video_filter_method == 1 ? m_linearSampler : m_sampler, + m_texView, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + }; + + descWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite[1].dstSet = m_descSet[i]; + descWrite[1].dstBinding = 1; + descWrite[1].descriptorCount = 1; + descWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descWrite[1].pImageInfo = &descImageInfo; + + m_devFuncs->vkUpdateDescriptorSets(dev, 2, descWrite, 0, nullptr); + } + + // Pipeline cache + VkPipelineCacheCreateInfo pipelineCacheInfo; + memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo)); + pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + err = m_devFuncs->vkCreatePipelineCache(dev, &pipelineCacheInfo, nullptr, &m_pipelineCache); + if (err != VK_SUCCESS) { + qWarning("Failed to create pipeline cache: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + // Pipeline layout + VkPipelineLayoutCreateInfo pipelineLayoutInfo; + memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo)); + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &m_descSetLayout; + err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_pipelineLayout); + if (err != VK_SUCCESS) { + qWarning("Failed to create pipeline layout: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + // Shaders +/* +#version 440 + +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoord; + +layout(location = 0) out vec2 v_texcoord; + +layout(std140, binding = 0) uniform buf { + mat4 mvp; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_texcoord = texcoord; + gl_Position = ubuf.mvp * position; +} +*/ + VkShaderModule vertShaderModule = createShader(QStringLiteral(":/texture_vert.spv")); +/* +#version 440 + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D tex; + +void main() +{ + fragColor = texture(tex, v_texcoord); +} +*/ + VkShaderModule fragShaderModule = createShader(QStringLiteral(":/texture_frag.spv")); + + // Graphics pipeline + VkGraphicsPipelineCreateInfo pipelineInfo; + memset(&pipelineInfo, 0, sizeof(pipelineInfo)); + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + + VkPipelineShaderStageCreateInfo shaderStages[2] = { + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_VERTEX_BIT, + vertShaderModule, + "main", + nullptr + }, + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + 0, + VK_SHADER_STAGE_FRAGMENT_BIT, + fragShaderModule, + "main", + nullptr + } + }; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + + pipelineInfo.pVertexInputState = &vertexInputInfo; + + VkPipelineInputAssemblyStateCreateInfo ia; + memset(&ia, 0, sizeof(ia)); + ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + pipelineInfo.pInputAssemblyState = &ia; + + // The viewport and scissor will be set dynamically via vkCmdSetViewport/Scissor. + // This way the pipeline does not need to be touched when resizing the window. + VkPipelineViewportStateCreateInfo vp; + memset(&vp, 0, sizeof(vp)); + vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp.viewportCount = 1; + vp.scissorCount = 1; + pipelineInfo.pViewportState = &vp; + + VkPipelineRasterizationStateCreateInfo rs; + memset(&rs, 0, sizeof(rs)); + rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs.polygonMode = VK_POLYGON_MODE_FILL; + rs.cullMode = VK_CULL_MODE_BACK_BIT; + rs.frontFace = VK_FRONT_FACE_CLOCKWISE; + rs.lineWidth = 1.0f; + pipelineInfo.pRasterizationState = &rs; + + VkPipelineMultisampleStateCreateInfo ms; + memset(&ms, 0, sizeof(ms)); + ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + pipelineInfo.pMultisampleState = &ms; + + VkPipelineDepthStencilStateCreateInfo ds; + memset(&ds, 0, sizeof(ds)); + ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds.depthTestEnable = VK_TRUE; + ds.depthWriteEnable = VK_TRUE; + ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + pipelineInfo.pDepthStencilState = &ds; + + VkPipelineColorBlendStateCreateInfo cb; + memset(&cb, 0, sizeof(cb)); + cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + // assume pre-multiplied alpha, blend, write out all of rgba + VkPipelineColorBlendAttachmentState att; + memset(&att, 0, sizeof(att)); + att.colorWriteMask = 0xF; + att.blendEnable = VK_TRUE; + att.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + att.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + att.colorBlendOp = VK_BLEND_OP_ADD; + att.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + att.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + att.alphaBlendOp = VK_BLEND_OP_ADD; + cb.attachmentCount = 1; + cb.pAttachments = &att; + pipelineInfo.pColorBlendState = &cb; + + VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dyn; + memset(&dyn, 0, sizeof(dyn)); + dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState); + dyn.pDynamicStates = dynEnable; + pipelineInfo.pDynamicState = &dyn; + + pipelineInfo.layout = m_pipelineLayout; + pipelineInfo.renderPass = m_window->defaultRenderPass(); + + err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline); + if (err != VK_SUCCESS) { + qWarning("Failed to create graphics pipeline: %d", err); + return emit qobject_cast(m_window)->errorInitializing(); + } + + if (vertShaderModule) + m_devFuncs->vkDestroyShaderModule(dev, vertShaderModule, nullptr); + if (fragShaderModule) + m_devFuncs->vkDestroyShaderModule(dev, fragShaderModule, nullptr); + + pclog("Vulkan device: %s\n", m_window->physicalDeviceProperties()->deviceName); + pclog("Vulkan API version: %d.%d.%d\n", VK_VERSION_MAJOR(m_window->physicalDeviceProperties()->apiVersion), VK_VERSION_MINOR(m_window->physicalDeviceProperties()->apiVersion), VK_VERSION_PATCH(m_window->physicalDeviceProperties()->apiVersion)); + pclog("Vulkan driver version: %d.%d.%d\n", VK_VERSION_MAJOR(m_window->physicalDeviceProperties()->driverVersion), VK_VERSION_MINOR(m_window->physicalDeviceProperties()->driverVersion), VK_VERSION_PATCH(m_window->physicalDeviceProperties()->driverVersion)); +} + +void VulkanRenderer2::initSwapChainResources() +{ + qDebug("initSwapChainResources"); + + // Projection matrix + m_proj = m_window->clipCorrectionMatrix(); // adjust for Vulkan-OpenGL clip space differences +} + +void VulkanRenderer2::releaseSwapChainResources() +{ + qDebug("releaseSwapChainResources"); +} + +void VulkanRenderer2::releaseResources() +{ + qDebug("releaseResources"); + + VkDevice dev = m_window->device(); + + if (m_sampler) { + m_devFuncs->vkDestroySampler(dev, m_sampler, nullptr); + m_sampler = VK_NULL_HANDLE; + } + + if (m_linearSampler) { + m_devFuncs->vkDestroySampler(dev, m_linearSampler, nullptr); + m_linearSampler = VK_NULL_HANDLE; + } + + if (m_texStaging) { + m_devFuncs->vkDestroyImage(dev, m_texStaging, nullptr); + m_texStaging = VK_NULL_HANDLE; + } + + if (m_texStagingMem) { + m_devFuncs->vkFreeMemory(dev, m_texStagingMem, nullptr); + m_texStagingMem = VK_NULL_HANDLE; + } + + if (m_texView) { + m_devFuncs->vkDestroyImageView(dev, m_texView, nullptr); + m_texView = VK_NULL_HANDLE; + } + + if (m_texImage) { + m_devFuncs->vkDestroyImage(dev, m_texImage, nullptr); + m_texImage = VK_NULL_HANDLE; + } + + if (m_texMem) { + m_devFuncs->vkFreeMemory(dev, m_texMem, nullptr); + m_texMem = VK_NULL_HANDLE; + } + + if (m_pipeline) { + m_devFuncs->vkDestroyPipeline(dev, m_pipeline, nullptr); + m_pipeline = VK_NULL_HANDLE; + } + + if (m_pipelineLayout) { + m_devFuncs->vkDestroyPipelineLayout(dev, m_pipelineLayout, nullptr); + m_pipelineLayout = VK_NULL_HANDLE; + } + + if (m_pipelineCache) { + m_devFuncs->vkDestroyPipelineCache(dev, m_pipelineCache, nullptr); + m_pipelineCache = VK_NULL_HANDLE; + } + + if (m_descSetLayout) { + m_devFuncs->vkDestroyDescriptorSetLayout(dev, m_descSetLayout, nullptr); + m_descSetLayout = VK_NULL_HANDLE; + } + + if (m_descPool) { + m_devFuncs->vkDestroyDescriptorPool(dev, m_descPool, nullptr); + m_descPool = VK_NULL_HANDLE; + } + + if (m_buf) { + m_devFuncs->vkDestroyBuffer(dev, m_buf, nullptr); + m_buf = VK_NULL_HANDLE; + } + + if (m_bufMem) { + m_devFuncs->vkFreeMemory(dev, m_bufMem, nullptr); + m_bufMem = VK_NULL_HANDLE; + } +} + +void VulkanRenderer2::startNextFrame() +{ + VkDevice dev = m_window->device(); + VkCommandBuffer cb = m_window->currentCommandBuffer(); + const QSize sz = m_window->swapChainImageSize(); + + updateSamplers(); + // Add the necessary barriers and do the host-linear -> device-optimal copy, if not yet done. + ensureTexture(); + + VkClearColorValue clearColor = {{ 0, 0, 0, 1 }}; + VkClearDepthStencilValue clearDS = { 1, 0 }; + VkClearValue clearValues[2]; + memset(clearValues, 0, sizeof(clearValues)); + clearValues[0].color = clearColor; + clearValues[1].depthStencil = clearDS; + + VkRenderPassBeginInfo rpBeginInfo; + memset(&rpBeginInfo, 0, sizeof(rpBeginInfo)); + rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpBeginInfo.renderPass = m_window->defaultRenderPass(); + rpBeginInfo.framebuffer = m_window->currentFramebuffer(); + rpBeginInfo.renderArea.extent.width = sz.width(); + rpBeginInfo.renderArea.extent.height = sz.height(); + rpBeginInfo.clearValueCount = 2; + rpBeginInfo.pClearValues = clearValues; + VkCommandBuffer cmdBuf = m_window->currentCommandBuffer(); + m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + quint8 *p; + VkResult err = m_devFuncs->vkMapMemory(dev, m_bufMem, m_uniformBufInfo[m_window->currentFrame()].offset, + UNIFORM_DATA_SIZE, 0, reinterpret_cast(&p)); + if (err != VK_SUCCESS) + qFatal("Failed to map memory: %d", err); + QMatrix4x4 m = m_proj; + //m.rotate(m_rotation, 0, 0, 1); + memcpy(p, m.constData(), 16 * sizeof(float)); + m_devFuncs->vkUnmapMemory(dev, m_bufMem); + p = nullptr; + + // Second pass for texture coordinates. + err = m_devFuncs->vkMapMemory(dev, m_bufMem, 0, + sizeof(vertexData), 0, reinterpret_cast(&p)); + if (err != VK_SUCCESS) + qFatal("Failed to map memory: %d", err); + + float* floatData = (float*)p; + auto source = qobject_cast(m_window)->source; + auto destination = qobject_cast(m_window)->destination; + floatData[3] = (float)source.x() / 2048.f; + floatData[9] = (float)(source.y()) / 2048.f; + floatData[8] = (float)source.x() / 2048.f; + floatData[4] = (float)(source.y() + source.height()) / 2048.f; + floatData[13] = (float)(source.x() + source.width()) / 2048.f; + floatData[19] = (float)(source.y()) / 2048.f; + floatData[18] = (float)(source.x() + source.width()) / 2048.f; + floatData[14] = (float)(source.y() + source.height()) / 2048.f; + + m_devFuncs->vkUnmapMemory(dev, m_bufMem); + + m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); + m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, + &m_descSet[m_window->currentFrame()], 0, nullptr); + VkDeviceSize vbOffset = 0; + m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_buf, &vbOffset); + + VkViewport viewport; + viewport.x = destination.x() * m_window->devicePixelRatio(); + viewport.y = destination.y() * m_window->devicePixelRatio(); + viewport.width = destination.width() * m_window->devicePixelRatio(); + viewport.height = destination.height() * m_window->devicePixelRatio(); + viewport.minDepth = 0; + viewport.maxDepth = 1; + m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = viewport.x; + scissor.offset.y = viewport.y; + scissor.extent.width = viewport.width; + scissor.extent.height = viewport.height; + m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor); + + m_devFuncs->vkCmdDraw(cb, 4, 1, 0, 0); + + m_devFuncs->vkCmdEndRenderPass(cmdBuf); + + if (m_texStagingTransferLayout) { + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.image = m_texImage; + m_devFuncs->vkCmdPipelineBarrier(cb, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, nullptr, 0, nullptr, + 1, &barrier); + m_texStagingPending = true; + } + + m_window->frameReady(); + m_window->requestUpdate(); // render continuously, throttled by the presentation rate +} +#endif diff --git a/src/qt/qt_vulkanrenderer.hpp b/src/qt/qt_vulkanrenderer.hpp new file mode 100644 index 000000000..abd4d7a13 --- /dev/null +++ b/src/qt/qt_vulkanrenderer.hpp @@ -0,0 +1,95 @@ +#pragma once +/**************************************************************************** +** +** Copyright (C) 2022 Cacodemon345 +** Copyright (C) 2017 The Qt Company Ltd. +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + +#include +#include + +#if QT_CONFIG(vulkan) +#include "qt_vulkanwindowrenderer.hpp" + +class VulkanRenderer2 : public QVulkanWindowRenderer +{ +public: + void* mappedPtr = nullptr; + size_t imagePitch = 2048 * 4; + VulkanRenderer2(QVulkanWindow *w); + + void initResources() override; + void initSwapChainResources() override; + void releaseSwapChainResources() override; + void releaseResources() override; + + void startNextFrame() override; + +private: + VkShaderModule createShader(const QString &name); + bool createTexture(); + bool createTextureImage(const QSize &size, VkImage *image, VkDeviceMemory *mem, + VkImageTiling tiling, VkImageUsageFlags usage, uint32_t memIndex); + bool writeLinearImage(const QImage &img, VkImage image, VkDeviceMemory memory); + void ensureTexture(); + void updateSamplers(); + + QVulkanWindow *m_window; + QVulkanDeviceFunctions *m_devFuncs; + + VkDeviceMemory m_bufMem = VK_NULL_HANDLE; + VkBuffer m_buf = VK_NULL_HANDLE; + VkDescriptorBufferInfo m_uniformBufInfo[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT]; + + VkDescriptorPool m_descPool = VK_NULL_HANDLE; + VkDescriptorSetLayout m_descSetLayout = VK_NULL_HANDLE; + VkDescriptorSet m_descSet[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT]; + + VkPipelineCache m_pipelineCache = VK_NULL_HANDLE; + VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + VkPipeline m_pipeline = VK_NULL_HANDLE; + + VkSampler m_sampler = VK_NULL_HANDLE; + VkSampler m_linearSampler = VK_NULL_HANDLE; + VkImage m_texImage = VK_NULL_HANDLE; + VkDeviceMemory m_texMem = VK_NULL_HANDLE; + bool m_texLayoutPending = false; + VkImageView m_texView = VK_NULL_HANDLE; + VkImage m_texStaging = VK_NULL_HANDLE; + VkDeviceMemory m_texStagingMem = VK_NULL_HANDLE; + bool m_texStagingPending = false; + bool m_texStagingTransferLayout = false; + QSize m_texSize; + VkFormat m_texFormat; + + QMatrix4x4 m_proj; + float m_rotation = 0.0f; +}; +#endif diff --git a/src/qt/qt_vulkanwindowrenderer.cpp b/src/qt/qt_vulkanwindowrenderer.cpp new file mode 100644 index 000000000..cb3b96e14 --- /dev/null +++ b/src/qt/qt_vulkanwindowrenderer.cpp @@ -0,0 +1,853 @@ +#include "qt_vulkanwindowrenderer.hpp" + +#include +#include + +#if QT_CONFIG(vulkan) +#include +#include +#include +#include + +#include "qt_mainwindow.hpp" +#include "qt_vulkanrenderer.hpp" + +extern "C" +{ +#include <86box/86box.h> +#include <86box/video.h> +} +#if 0 +extern MainWindow* main_window; +/* +#version 450 + +layout(location = 0) out vec2 v_texcoord; + +mat4 mvp = mat4( +vec4(1.0, 0, 0, 0), +vec4(0, 1.0, 0, 0), +vec4(0, 0, 1.0, 0), +vec4(0, 0, 0, 1.0) +); + +// Y coordinate in Vulkan viewport space is flipped as compared to OpenGL. +vec4 vertCoords[4] = vec4[]( +vec4(-1.0, -1.0, 0, 1), +vec4(1.0, -1.0, 0, 1), +vec4(-1.0, 1.0, 0, 1), +vec4(1.0, 1.0, 0, 1) +); + +layout(push_constant) uniform texCoordBuf { + vec2 texCoords[4]; +} texCoordUniform; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + v_texcoord = texCoordUniform.texCoords[gl_VertexIndex]; + gl_Position = mvp * vertCoords[gl_VertexIndex]; +} +*/ +// Compiled with glslangValidator -V +static const uint8_t vertShaderCode[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x6d, 0x76, 0x70, 0x00, 0x05, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x76, 0x65, 0x72, 0x74, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x73, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x74, 0x65, + 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, + 0x42, 0x75, 0x66, 0x00, 0x06, 0x00, 0x06, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, + 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x55, 0x6e, 0x69, 0x66, + 0x6f, 0x72, 0x6d, 0x00, 0x05, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x00, 0x05, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, + 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x03, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, + 0x38, 0x00, 0x01, 0x00 +}; + +/* +#version 440 + +layout(location = 0) in vec2 v_texcoord; + +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D tex; + +void main() +{ + fragColor = texture(tex, v_texcoord); +} +*/ + +static const uint8_t fragShaderCode[] +{ + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, + 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, + 0x72, 0x64, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x15, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, + 0x38, 0x00, 0x01, 0x00 +}; + +class VulkanRendererEmu : public QVulkanWindowRenderer +{ + VulkanWindowRenderer* m_window{nullptr}; + QVulkanDeviceFunctions* m_devFuncs{nullptr}; + VmaAllocator allocator{nullptr}; + VmaAllocation allocation{nullptr}; + VkImage image{nullptr}; + VkImageView imageView{nullptr}; + VkPipeline pipeline{nullptr}; + VkPipelineLayout pipelineLayout{nullptr}; + VkDescriptorSetLayout descLayout{nullptr}; + VkDescriptorPool descPool{nullptr}; + VkDescriptorSet descSet{nullptr}; + VkSampler sampler{nullptr}, nearestSampler{nullptr}; + bool imageLayoutTransitioned{false}; + int cur_video_filter_method = -1; +private: + void updateOptions() { + VkResult res; + if (cur_video_filter_method == video_filter_method) return; + if (!descPool) { + VkDescriptorPoolSize descSize{}; + descSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descSize.descriptorCount = 2; + + VkDescriptorPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 1; + poolInfo.pPoolSizes = &descSize; + poolInfo.maxSets = 2; + + if ((res = m_devFuncs->vkCreateDescriptorPool(m_window->device(), &poolInfo, nullptr, &descPool)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create descriptor pool. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + VkDescriptorSetAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descPool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &descLayout; + + if ((res = m_devFuncs->vkAllocateDescriptorSets(m_window->device(), &allocInfo, &descSet)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create descriptor set. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + }} + VkDescriptorImageInfo imageDescInfo{}; + imageDescInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageDescInfo.imageView = imageView; + imageDescInfo.sampler = video_filter_method == 0 ? nearestSampler : sampler; + + VkWriteDescriptorSet descWrite{}; + descWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descWrite.dstSet = descSet; + descWrite.dstBinding = 1; + descWrite.dstArrayElement = 0; + descWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descWrite.descriptorCount = 1; + descWrite.pImageInfo = &imageDescInfo; + + m_devFuncs->vkUpdateDescriptorSets(m_window->device(), 1, &descWrite, 0, nullptr); + cur_video_filter_method = video_filter_method; + } +public: + void* mappedPtr = nullptr; + uint32_t imagePitch{2048 * 4}; + VulkanRendererEmu(VulkanWindowRenderer *w) : m_window(w), m_devFuncs(nullptr) { } + + void initResources() override + { + VmaAllocatorCreateInfo info{}; + info.instance = m_window->vulkanInstance()->vkInstance(); + info.device = m_window->device(); + info.physicalDevice = m_window->physicalDevice(); + VmaVulkanFunctions funcs{}; + funcs.vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)m_window->vulkanInstance()->getInstanceProcAddr("vkGetInstanceProcAddr"); + funcs.vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)m_window->vulkanInstance()->getInstanceProcAddr("vkGetDeviceProcAddr"); + info.pVulkanFunctions = &funcs; + if (vmaCreateAllocator(&info, &allocator) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create Vulkan allocator. Switch to another renderer"); + return; + } + + m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device()); + + VkResult res; + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.format = VK_FORMAT_B8G8R8A8_UNORM; + imageInfo.extent.width = imageInfo.extent.height = 2048; + imageInfo.extent.depth = imageInfo.arrayLayers = imageInfo.mipLevels = 1; + imageInfo.tiling = VK_IMAGE_TILING_LINEAR; + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + + VmaAllocationInfo allocatedInfo{}; + VmaAllocationCreateInfo allocInfo{}; + allocInfo.pUserData = allocInfo.pool = nullptr; + allocInfo.requiredFlags = allocInfo.preferredFlags = 0; + allocInfo.usage = VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO; + allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + + if ((res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &image, &allocation, &allocatedInfo)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create Vulkan image. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + }; + + VkImageViewCreateInfo imageViewInfo{}; + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.format = VK_FORMAT_B8G8R8A8_UNORM; + imageViewInfo.image = image; + imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageViewInfo.subresourceRange.baseMipLevel = 0; + imageViewInfo.subresourceRange.levelCount = 1; + imageViewInfo.subresourceRange.baseArrayLayer = 0; + imageViewInfo.subresourceRange.layerCount = 1; + imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + + if ((res = m_devFuncs->vkCreateImageView(m_window->device(), &imageViewInfo, nullptr, &imageView)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create Vulkan image view. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + // Begin Pipeline creation. + { + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.pVertexBindingDescriptions = nullptr; + vertexInputInfo.vertexAttributeDescriptionCount = 0; + vertexInputInfo.pVertexAttributeDescriptions = nullptr; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = {2048, 2048}; + + VkViewport viewport{}; + viewport.x = m_window->destination.x(); + viewport.y = m_window->destination.y(); + viewport.width = (float)m_window->destination.width(); + viewport.height = (float)m_window->destination.height(); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkPipelineViewportStateCreateInfo viewportState{}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer{}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + + VkPipelineMultisampleStateCreateInfo multisampling{}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState colorBlendAttachment{}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = VK_TRUE; + colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + + VkPipelineColorBlendStateCreateInfo colorBlending{}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + VkDynamicState dynState = VK_DYNAMIC_STATE_VIEWPORT; + VkPipelineDynamicStateCreateInfo dynamicState{}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = 1; + dynamicState.pDynamicStates = &dynState; + + VkPushConstantRange range{}; + range.offset = 0; + range.size = sizeof(float) * 8; + range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + // Sampler binding start. + VkDescriptorSetLayoutBinding samplerLayoutBinding{}; + samplerLayoutBinding.binding = 1; + samplerLayoutBinding.descriptorCount = 1; + samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + samplerLayoutBinding.pImmutableSamplers = nullptr; + samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutCreateInfo layoutInfo{}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = 1; + layoutInfo.pBindings = &samplerLayoutBinding; + + if ((res = m_devFuncs->vkCreateDescriptorSetLayout(m_window->device(), &layoutInfo, nullptr, &descLayout))) { + QMessageBox::critical(main_window, "86Box", "Could not create descriptor set layout. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + // Sampler binding end. + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &descLayout; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = ⦥ + + if ((res = m_devFuncs->vkCreatePipelineLayout(m_window->device(), &pipelineLayoutInfo, nullptr, &pipelineLayout)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create pipeline layout. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + // Shader loading start. + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = sizeof(vertShaderCode); + createInfo.pCode = (uint32_t*)vertShaderCode; + VkShaderModule vertModule{nullptr}, fragModule{nullptr}; + if ((res = m_devFuncs->vkCreateShaderModule(m_window->device(), &createInfo, nullptr, &vertModule)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create vertex shader. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + createInfo.codeSize = sizeof(fragShaderCode); + createInfo.pCode = (uint32_t*)fragShaderCode; + if ((res = m_devFuncs->vkCreateShaderModule(m_window->device(), &createInfo, nullptr, &fragModule)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create fragment shader. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertModule; + vertShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragShaderStageInfo{vertShaderStageInfo}; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragModule; + + VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; + // Shader loading end. + + VkPipelineDepthStencilStateCreateInfo depthInfo{}; + depthInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthInfo.pNext = nullptr; + depthInfo.depthTestEnable = VK_TRUE; + depthInfo.depthWriteEnable = VK_TRUE; + depthInfo.depthBoundsTestEnable = VK_FALSE; + depthInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthInfo.stencilTestEnable = VK_FALSE; + depthInfo.maxDepthBounds = 1.0f; + + VkGraphicsPipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pDepthStencilState = &depthInfo; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = pipelineLayout; + pipelineInfo.renderPass = m_window->defaultRenderPass(); + pipelineInfo.subpass = 0; + + if ((res = m_devFuncs->vkCreateGraphicsPipelines(m_window->device(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline)) != VK_SUCCESS) { + m_devFuncs->vkDestroyShaderModule(m_window->device(), vertModule, nullptr); + m_devFuncs->vkDestroyShaderModule(m_window->device(), fragModule, nullptr); + QMessageBox::critical(main_window, "86Box", "Could not create graphics pipeline. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + m_devFuncs->vkDestroyShaderModule(m_window->device(), vertModule, nullptr); + m_devFuncs->vkDestroyShaderModule(m_window->device(), fragModule, nullptr); + } + + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0; + + if ((res = m_devFuncs->vkCreateSampler(m_window->device(), &samplerInfo, nullptr, &sampler)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create linear image sampler. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + samplerInfo.magFilter = samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + + if ((res = m_devFuncs->vkCreateSampler(m_window->device(), &samplerInfo, nullptr, &nearestSampler)) != VK_SUCCESS) { + QMessageBox::critical(main_window, "86Box", "Could not create nearest image sampler. Switch to another renderer. " + Vulkan_GetResultString(res)); + return; + } + + updateOptions(); + + VkImageSubresource resource{}; + resource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resource.arrayLayer = 0; + resource.mipLevel = 0; + VkSubresourceLayout layout{}; + m_devFuncs->vkGetImageSubresourceLayout(m_window->device(), image, &resource, &layout); + + imagePitch = layout.rowPitch; + mappedPtr = (uint8_t*)allocatedInfo.pMappedData + layout.offset; + emit m_window->rendererInitialized(); + } + + void releaseResources() override + { + if (pipeline) m_devFuncs->vkDestroyPipeline(m_window->device(), pipeline, nullptr); + if (pipelineLayout) m_devFuncs->vkDestroyPipelineLayout(m_window->device(), pipelineLayout, nullptr); + if (descSet) m_devFuncs->vkDestroyDescriptorPool(m_window->device(), descPool, nullptr); + if (descLayout) m_devFuncs->vkDestroyDescriptorSetLayout(m_window->device(), descLayout, nullptr); + if (imageView) m_devFuncs->vkDestroyImageView(m_window->device(), imageView, nullptr); + if (image) vmaDestroyImage(allocator, image, allocation); + if (sampler) m_devFuncs->vkDestroySampler(m_window->device(), sampler, nullptr); + if (nearestSampler) m_devFuncs->vkDestroySampler(m_window->device(), nearestSampler, nullptr); + image = nullptr; + pipeline = nullptr; + pipelineLayout = nullptr; + imageView = nullptr; + descLayout = nullptr; + descPool = nullptr; + descSet = nullptr; + sampler = nullptr; + vmaDestroyAllocator(allocator); + allocator = nullptr; + } + + QString Vulkan_GetResultString(VkResult result) + { + switch ((int)result) { + case VK_SUCCESS: + return "VK_SUCCESS"; + case VK_NOT_READY: + return "VK_NOT_READY"; + case VK_TIMEOUT: + return "VK_TIMEOUT"; + case VK_EVENT_SET: + return "VK_EVENT_SET"; + case VK_EVENT_RESET: + return "VK_EVENT_RESET"; + case VK_INCOMPLETE: + return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: + return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: + return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_FRAGMENTED_POOL: + return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_UNKNOWN: + return "VK_ERROR_UNKNOWN"; + case VK_ERROR_OUT_OF_POOL_MEMORY: + return "VK_ERROR_OUT_OF_POOL_MEMORY"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: + return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; + case VK_ERROR_FRAGMENTATION: + return "VK_ERROR_FRAGMENTATION"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: + return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_SUBOPTIMAL_KHR: + return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_INVALID_SHADER_NV: + return "VK_ERROR_INVALID_SHADER_NV"; +#if VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162 + case VK_ERROR_INCOMPATIBLE_VERSION_KHR: + return "VK_ERROR_INCOMPATIBLE_VERSION_KHR"; +#endif + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: + return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VK_ERROR_NOT_PERMITTED_EXT: + return "VK_ERROR_NOT_PERMITTED_EXT"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: + return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VK_THREAD_IDLE_KHR: + return "VK_THREAD_IDLE_KHR"; + case VK_THREAD_DONE_KHR: + return "VK_THREAD_DONE_KHR"; + case VK_OPERATION_DEFERRED_KHR: + return "VK_OPERATION_DEFERRED_KHR"; + case VK_OPERATION_NOT_DEFERRED_KHR: + return "VK_OPERATION_NOT_DEFERRED_KHR"; + case VK_PIPELINE_COMPILE_REQUIRED_EXT: + return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; + default: + break; + } + if (result < 0) { + return "VK_ERROR_"; + } + return "VK_"; + } + + void startNextFrame() override + { + m_devFuncs->vkDeviceWaitIdle(m_window->device()); + VkClearValue values[2]; + auto cmdBufs = m_window->currentCommandBuffer(); + memset(values, 0, sizeof(values)); + values[0].depthStencil = { 1, 0 }; + values[1].depthStencil = { 1, 0 }; + VkRenderPassBeginInfo info{}; + VkSubpassDependency deps{}; + info.pClearValues = values; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.framebuffer = m_window->currentFramebuffer(); + info.renderArea = VkRect2D{{0, 0}, {(uint32_t)m_window->swapChainImageSize().width(), (uint32_t)m_window->swapChainImageSize().height()}}; + info.clearValueCount = 2; + info.renderPass = m_window->defaultRenderPass(); + + updateOptions(); + if (!imageLayoutTransitioned) { + VkPipelineStageFlags srcflags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_HOST_BIT, dstflags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = image; + barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + m_devFuncs->vkCmdPipelineBarrier(cmdBufs, srcflags, dstflags, 0, 0, nullptr, 0, nullptr, 1, &barrier); + imageLayoutTransitioned = true; + } + vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); + VkViewport viewport{}; + viewport.x = m_window->destination.x(); + viewport.y = m_window->destination.y(); + viewport.width = (float)m_window->destination.width(); + viewport.height = (float)m_window->destination.height(); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + m_devFuncs->vkCmdSetViewport(cmdBufs, 0, 1, &viewport); + m_devFuncs->vkCmdBeginRenderPass(m_window->currentCommandBuffer(), &info, VK_SUBPASS_CONTENTS_INLINE); + m_devFuncs->vkCmdBindPipeline(cmdBufs, VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + m_devFuncs->vkCmdBindDescriptorSets(cmdBufs, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descSet, 0, nullptr); + std::array texcoords; + auto source = m_window->source; + texcoords[0] = (QVector2D((float)source.x() / 2048.f, (float)(source.y()) / 2048.f)); + texcoords[2] = (QVector2D((float)source.x() / 2048.f, (float)(source.y() + source.height()) / 2048.f)); + texcoords[1] = (QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y()) / 2048.f)); + texcoords[3] = (QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y() + source.height()) / 2048.f)); + m_devFuncs->vkCmdPushConstants(cmdBufs, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(QVector2D) * 4, texcoords.data()); + m_devFuncs->vkCmdDraw(cmdBufs, 4, 1, 0, 0); + m_devFuncs->vkCmdEndRenderPass(cmdBufs); + + m_window->frameReady(); + m_devFuncs->vkDeviceWaitIdle(m_window->device()); + } +}; +#endif + +VulkanWindowRenderer::VulkanWindowRenderer(QWidget* parent) + : QVulkanWindow(parent->windowHandle()) +{ + parentWidget = parent; + instance.setLayers(QByteArrayList() << "VK_LAYER_KHRONOS_validation"); + instance.setExtensions(QByteArrayList() << "VK_EXT_debug_report"); + instance.setApiVersion(QVersionNumber(1, 0)); + if (!instance.create()) { + throw std::runtime_error("Could not create Vulkan instance"); + } + uint32_t physicalDevices = 0; + instance.functions()->vkEnumeratePhysicalDevices(instance.vkInstance(), &physicalDevices, nullptr); + if (physicalDevices == 0) { + throw std::runtime_error("No physical devices available."); + } + qDebug() << instance.layers(); + setVulkanInstance(&instance); + setPhysicalDeviceIndex(0); + setPreferredColorFormats({VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_A8B8G8R8_UNORM_PACK32}); + setFlags(Flag::PersistentResources); + buf_usage = std::vector(1); + buf_usage[0].clear(); +} + +QVulkanWindowRenderer* VulkanWindowRenderer::createRenderer() +{ + renderer = new VulkanRenderer2(this); + return renderer; +} + +void VulkanWindowRenderer::resizeEvent(QResizeEvent *event) { + onResize(width(), height()); + + QVulkanWindow::resizeEvent(event); +} + +bool VulkanWindowRenderer::event(QEvent *event) +{ + bool res = false; + if (!eventDelegate(event, res)) return QVulkanWindow::event(event); + return res; +} + +void VulkanWindowRenderer::onBlit(int buf_idx, int x, int y, int w, int h) +{ + source.setRect(x, y, w, h); + if (isExposed()) requestUpdate(); + buf_usage[0].clear(); +} + +uint32_t VulkanWindowRenderer::getBytesPerRow() +{ + return renderer->imagePitch; +} + +std::vector> VulkanWindowRenderer::getBuffers() +{ + return std::vector{std::make_tuple((uint8_t*)renderer->mappedPtr, &this->buf_usage[0])}; +} +#endif diff --git a/src/qt/qt_vulkanwindowrenderer.hpp b/src/qt/qt_vulkanwindowrenderer.hpp new file mode 100644 index 000000000..df252d393 --- /dev/null +++ b/src/qt/qt_vulkanwindowrenderer.hpp @@ -0,0 +1,39 @@ +#ifndef VULKANWINDOWRENDERER_HPP +#define VULKANWINDOWRENDERER_HPP + +#include + +#if QT_CONFIG(vulkan) +#include "qt_renderercommon.hpp" +#include "qt_vulkanrenderer.hpp" + +class VulkanRenderer2; + +class VulkanWindowRenderer : public QVulkanWindow, public RendererCommon +{ + Q_OBJECT +public: + VulkanWindowRenderer(QWidget* parent); +public slots: + void onBlit(int buf_idx, int x, int y, int w, int h); +signals: + void rendererInitialized(); + void errorInitializing(); +protected: + virtual std::vector> getBuffers() override; + void resizeEvent(QResizeEvent*) override; + bool event(QEvent*) override; + uint32_t getBytesPerRow() override; +private: + QVulkanInstance instance; + + QVulkanWindowRenderer* createRenderer() override; + + friend class VulkanRendererEmu; + friend class VulkanRenderer2; + + VulkanRenderer2* renderer; +}; +#endif + +#endif // VULKANWINDOWRENDERER_HPP diff --git a/src/qt/qt_winmanagerfilter.cpp b/src/qt/qt_winmanagerfilter.cpp new file mode 100644 index 000000000..2c6053839 --- /dev/null +++ b/src/qt/qt_winmanagerfilter.cpp @@ -0,0 +1,66 @@ +/* + * 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. + * + * Windows VM-managers native messages filter + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#include "qt_winmanagerfilter.hpp" + +#include +#include <86box/win.h> + +bool WindowsManagerFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) +{ + if (eventType == "windows_generic_MSG") + { + MSG *msg = static_cast(message); + + switch (msg->message) + { + case WM_SHOWSETTINGS: + emit showsettings(); + return true; + case WM_PAUSE: + emit pause(); + return true; + case WM_HARDRESET: + emit reset(); + return true; + case WM_SHUTDOWN: + if (msg->wParam == 1) + emit force_shutdown(); + else + emit request_shutdown(); + return true; + case WM_CTRLALTDEL: + emit ctrlaltdel(); + return true; + } + } + + return false; +} + +bool WindowsManagerFilter::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::WindowBlocked) + { + emit dialogstatus(1); + } + else if (event->type() == QEvent::WindowUnblocked) + { + emit dialogstatus(0); + } + + return QObject::eventFilter(obj, event); +} diff --git a/src/qt/qt_winmanagerfilter.hpp b/src/qt/qt_winmanagerfilter.hpp new file mode 100644 index 000000000..d715d9322 --- /dev/null +++ b/src/qt/qt_winmanagerfilter.hpp @@ -0,0 +1,55 @@ +/* + * 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. + * + * Header file for Windows VM-managers native messages filter + * + * Authors: + * Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#ifndef QT_WINDOWSMANAGERFILTER_HPP +#define QT_WINDOWSMANAGERFILTER_HPP + +#include +#include +#include +#include + +#if QT_VERSION_MAJOR >= 6 +#define result_t qintptr +#else +#define result_t long +#endif + +/* + * Filters native events for messages from VM-manager and + * window blocked events to notify about open modal dialogs. + */ +class WindowsManagerFilter : public QObject, public QAbstractNativeEventFilter +{ + Q_OBJECT + +public: + bool nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) override; + +signals: + void pause(); + void ctrlaltdel(); + void showsettings(); + void reset(); + void request_shutdown(); + void force_shutdown(); + void dialogstatus(bool open); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; +}; + +#endif diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp new file mode 100644 index 000000000..1e5ec5a71 --- /dev/null +++ b/src/qt/qt_winrawinputfilter.cpp @@ -0,0 +1,429 @@ +/* + * 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. + * + * Windows raw input native filter for QT + * + * Authors: + * Teemu Korhonen + * Miran Grca, + * + * Copyright 2021 Teemu Korhonen + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "qt_winrawinputfilter.hpp" + +#include + +#include + +#include <86box/keyboard.h> +#include <86box/mouse.h> +#include <86box/plat.h> +#include <86box/86box.h> + +#include +#include + +extern "C" void win_joystick_handle(PRAWINPUT); +std::unique_ptr WindowsRawInputFilter::Register(QMainWindow *window) +{ + HWND wnd = (HWND)window->winId(); + + RAWINPUTDEVICE rid[2] = + { + { + .usUsagePage = 0x01, + .usUsage = 0x06, + .dwFlags = RIDEV_NOHOTKEYS, + .hwndTarget = wnd + }, + { + .usUsagePage = 0x01, + .usUsage = 0x02, + .dwFlags = 0, + .hwndTarget = wnd + } + }; + + if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) + return std::unique_ptr(nullptr); + + std::unique_ptr inputfilter(new WindowsRawInputFilter(window)); + + return inputfilter; +} + +WindowsRawInputFilter::WindowsRawInputFilter(QMainWindow *window) +{ + this->window = window; + + for (auto menu : window->findChildren()) + { + connect(menu, &QMenu::aboutToShow, this, [=]() { menus_open++; }); + connect(menu, &QMenu::aboutToHide, this, [=]() { menus_open--; }); + } + + for (size_t i = 0; i < sizeof(scancode_map) / sizeof(scancode_map[0]); i++) + scancode_map[i] = i; + + keyboard_getkeymap(); +} + +WindowsRawInputFilter::~WindowsRawInputFilter() +{ + RAWINPUTDEVICE rid[2] = + { + { + .usUsagePage = 0x01, + .usUsage = 0x06, + .dwFlags = RIDEV_REMOVE, + .hwndTarget = NULL + }, + { + .usUsagePage = 0x01, + .usUsage = 0x02, + .dwFlags = RIDEV_REMOVE, + .hwndTarget = NULL + } + }; + + RegisterRawInputDevices(rid, 2, sizeof(rid[0])); +} + +bool WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) +{ + if (eventType == "windows_generic_MSG") + { + MSG *msg = static_cast(message); + + if (msg->message == WM_INPUT) { + if (window->isActiveWindow() && menus_open == 0) + handle_input((HRAWINPUT) msg->lParam); + + return true; + } + + /* Stop processing of Alt-F4 */ + if (msg->message == WM_SYSKEYDOWN) { + if (msg->wParam == 0x73) { + return true; + } + } + } + + return false; +} + +void WindowsRawInputFilter::handle_input(HRAWINPUT input) +{ + UINT size = 0; + + GetRawInputData(input, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + + std::vector buf(size); + + if (GetRawInputData(input, RID_INPUT, buf.data(), &size, sizeof(RAWINPUTHEADER)) == size) + { + PRAWINPUT raw = (PRAWINPUT)buf.data(); + + switch(raw->header.dwType) + { + case RIM_TYPEKEYBOARD: + keyboard_handle(raw); + break; + case RIM_TYPEMOUSE: + if (mouse_capture) + mouse_handle(raw); + break; + case RIM_TYPEHID: + { + win_joystick_handle(raw); + break; + } + } + } +} + +/* The following is more or less a direct copy of the old WIN32 implementation */ + +void WindowsRawInputFilter::keyboard_handle(PRAWINPUT raw) +{ + USHORT scancode; + static int recv_lalt = 0, recv_ralt = 0, recv_tab = 0; + + RAWKEYBOARD rawKB = raw->data.keyboard; + scancode = rawKB.MakeCode; + + if (kbd_req_capture && !mouse_capture && !video_fullscreen) + return; + + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) + { + if (rawKB.Flags & RI_KEY_E0) + scancode |= 0x100; + + /* Translate the scan code to 9-bit */ + scancode = convert_scan_code(scancode); + + /* Remap it according to the list from the Registry */ + if (scancode != scancode_map[scancode]) + pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); + scancode = scancode_map[scancode]; + + /* If it's not 0xFFFF, send it to the emulated + keyboard. + We use scan code 0xFFFF to mean a mapping that + has a prefix other than E0 and that is not E1 1D, + which is, for our purposes, invalid. */ + if ((scancode == 0x00F) && + !(rawKB.Flags & RI_KEY_BREAK) && + (recv_lalt || recv_ralt) && + !mouse_capture) + { + /* We received a TAB while ALT was pressed, while the mouse + is not captured, suppress the TAB and send an ALT key up. */ + if (recv_lalt) + { + keyboard_input(0, 0x038); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x038); + keyboard_input(0, 0x038); + recv_lalt = 0; + } + if (recv_ralt) + { + keyboard_input(0, 0x138); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x138); + keyboard_input(0, 0x138); + recv_ralt = 0; + } + } + else if (((scancode == 0x038) || (scancode == 0x138)) && + !(rawKB.Flags & RI_KEY_BREAK) && + recv_tab && + !mouse_capture) + { + /* We received an ALT while TAB was pressed, while the mouse + is not captured, suppress the ALT and send a TAB key up. */ + keyboard_input(0, 0x00F); + recv_tab = 0; + } + else + { + switch (scancode) + { + case 0x00F: + recv_tab = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x038: + recv_lalt = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x138: + recv_ralt = !(rawKB.Flags & RI_KEY_BREAK); + break; + } + + /* Translate right CTRL to left ALT if the user has so + chosen. */ + if ((scancode == 0x11D) && rctrl_is_lalt) + scancode = 0x038; + + /* Normal scan code pass through, pass it through as is if + it's not an invalid scan code. */ + if (scancode != 0xFFFF) + keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + } + } + else + { + if (rawKB.MakeCode == 0x1D) + { + scancode = scancode_map[0x100]; /* Translate E1 1D to 0x100 (which would + otherwise be E0 00 but that is invalid + anyway). + Also, take a potential mapping into + account. */ + } + else + scancode = 0xFFFF; + if (scancode != 0xFFFF) + keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + } +} + +/* This is so we can disambiguate scan codes that would otherwise conflict and get + passed on incorrectly. */ +UINT16 WindowsRawInputFilter::convert_scan_code(UINT16 scan_code) +{ + if ((scan_code & 0xff00) == 0xe000) + scan_code = (scan_code & 0xff) | 0x0100; + + if (scan_code == 0xE11D) + scan_code = 0x0100; + /* E0 00 is sent by some USB keyboards for their special keys, as it is an + invalid scan code (it has no untranslated set 2 equivalent), we mark it + appropriately so it does not get passed through. */ + else if ((scan_code > 0x01FF) || (scan_code == 0x0100)) + scan_code = 0xFFFF; + + return scan_code; +} + +void WindowsRawInputFilter::keyboard_getkeymap() +{ + const LPCSTR keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; + const LPCSTR valueName = "Scancode Map"; + unsigned char buf[32768]; + DWORD bufSize; + HKEY hKey; + int j; + UINT32 *bufEx2; + int scMapCount; + UINT16 *bufEx; + int scancode_unmapped; + int scancode_mapped; + + /* First, prepare the default scan code map list which is 1:1. + * Remappings will be inserted directly into it. + * 512 bytes so this takes less memory, bit 9 set means E0 + * prefix. + */ + for (j = 0; j < 512; j++) + scancode_map[j] = j; + + /* Get the scan code remappings from: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ + bufSize = 32768; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueExA(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) + { + bufEx2 = (UINT32 *)buf; + scMapCount = bufEx2[2]; + if ((bufSize != 0) && (scMapCount != 0)) + { + bufEx = (UINT16 *)(buf + 12); + for (j = 0; j < scMapCount * 2; j += 2) + { + /* Each scan code is 32-bit: 16 bits of remapped scan code, + and 16 bits of original scan code. */ + scancode_unmapped = bufEx[j + 1]; + scancode_mapped = bufEx[j]; + + scancode_unmapped = convert_scan_code(scancode_unmapped); + scancode_mapped = convert_scan_code(scancode_mapped); + + /* Ignore source scan codes with prefixes other than E1 + that are not E1 1D. */ + if (scancode_unmapped != 0xFFFF) + scancode_map[scancode_unmapped] = scancode_mapped; + } + } + } + RegCloseKey(hKey); + } +} + +void WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) +{ + RAWMOUSE state = raw->data.mouse; + static int x, y; + + /* read mouse buttons and wheel */ + if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) + buttons |= 1; + else if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) + buttons &= ~1; + + if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) + buttons |= 4; + else if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) + buttons &= ~4; + + if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) + buttons |= 2; + else if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) + buttons &= ~2; + + if (state.usButtonFlags & RI_MOUSE_WHEEL) + { + dwheel += (SHORT)state.usButtonData / 120; + } + + if (state.usFlags & MOUSE_MOVE_ABSOLUTE) + { + /* absolute mouse, i.e. RDP or VNC + * seems to work fine for RDP on Windows 10 + * Not sure about other environments. + */ + dx += (state.lLastX - x) / 25; + dy += (state.lLastY - y) / 25; + x = state.lLastX; + y = state.lLastY; + } + else + { + /* relative mouse, i.e. regular mouse */ + dx += state.lLastX; + dy += state.lLastY; + } + HWND wnd = (HWND)window->winId(); + + RECT rect; + + GetWindowRect(wnd, &rect); + + int left = rect.left + (rect.right - rect.left) / 2; + int top = rect.top + (rect.bottom - rect.top) / 2; + + SetCursorPos(left, top); +} + +void WindowsRawInputFilter::mousePoll() +{ + if (mouse_capture || video_fullscreen) + { + static int b = 0; + + if (dx != 0 || dy != 0 || dwheel != 0) + { + mouse_x += dx; + mouse_y += dy; + mouse_z = dwheel; + + dx = 0; + dy = 0; + dwheel = 0; + } + + if (b != buttons) + { + mouse_buttons = buttons; + b = buttons; + } + } +} diff --git a/src/qt/qt_winrawinputfilter.hpp b/src/qt/qt_winrawinputfilter.hpp new file mode 100644 index 000000000..dabd3f4dd --- /dev/null +++ b/src/qt/qt_winrawinputfilter.hpp @@ -0,0 +1,81 @@ +/* + * 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. + * + * Header file for windows raw input native filter for QT + * + * Authors: + * Teemu Korhonen + * + * Copyright 2021 Teemu Korhonen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef QT_WINDOWSRAWINPUTFILTER_HPP +#define QT_WINDOWSRAWINPUTFILTER_HPP + +#include +#include +#include +#include + +#include + +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#define result_t qintptr +#else +#define result_t long +#endif + +class WindowsRawInputFilter : public QObject, public QAbstractNativeEventFilter +{ + Q_OBJECT + +public: + static std::unique_ptr Register(QMainWindow *window); + + bool nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) override; + + ~WindowsRawInputFilter(); + +public slots: + void mousePoll(); + +private: + QMainWindow *window; + uint16_t scancode_map[768]; + int buttons = 0; + int dx = 0; + int dy = 0; + int dwheel = 0; + int menus_open = 0; + + WindowsRawInputFilter(QMainWindow *window); + + void handle_input(HRAWINPUT input); + void keyboard_handle(PRAWINPUT raw); + void mouse_handle(PRAWINPUT raw); + static UINT16 convert_scan_code(UINT16 scan_code); + void keyboard_getkeymap(); +}; + +#endif diff --git a/src/qt/sdl_joystick.cpp b/src/qt/sdl_joystick.cpp new file mode 100644 index 000000000..ab72145c3 --- /dev/null +++ b/src/qt/sdl_joystick.cpp @@ -0,0 +1,169 @@ +// Lifted from wx-sdl2-joystick.c in PCem + +#include + +#include + +extern "C" { +#include <86box/device.h> +#include <86box/gameport.h> + +int joysticks_present; +joystick_t joystick_state[MAX_JOYSTICKS]; +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +static SDL_Joystick *sdl_joy[MAX_PLAT_JOYSTICKS]; +} + +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +void joystick_init() { + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) { + return; + } + joysticks_present = SDL_NumJoysticks(); + + memset(sdl_joy, 0, sizeof(sdl_joy)); + for (int c = 0; c < joysticks_present; c++) + { + sdl_joy[c] = SDL_JoystickOpen(c); + + if (sdl_joy[c]) + { + int d; + + strncpy(plat_joystick_state[c].name, SDL_JoystickNameForIndex(c), 64); + plat_joystick_state[c].nr_axes = SDL_JoystickNumAxes(sdl_joy[c]); + plat_joystick_state[c].nr_buttons = SDL_JoystickNumButtons(sdl_joy[c]); + plat_joystick_state[c].nr_povs = SDL_JoystickNumHats(sdl_joy[c]); + + for (d = 0; d < std::min(plat_joystick_state[c].nr_axes, 8); d++) + { + sprintf(plat_joystick_state[c].axis[d].name, "Axis %i", d); + plat_joystick_state[c].axis[d].id = d; + } + for (d = 0; d < std::min(plat_joystick_state[c].nr_buttons, 8); d++) + { + sprintf(plat_joystick_state[c].button[d].name, "Button %i", d); + plat_joystick_state[c].button[d].id = d; + } + for (d = 0; d < std::min(plat_joystick_state[c].nr_povs, 4); d++) + { + sprintf(plat_joystick_state[c].pov[d].name, "POV %i", d); + plat_joystick_state[c].pov[d].id = d; + } + } + } +} + +void joystick_close() +{ + int c; + + for (c = 0; c < joysticks_present; c++) + { + if (sdl_joy[c]) + SDL_JoystickClose(sdl_joy[c]); + } +} + +static int joystick_get_axis(int joystick_nr, int mapping) +{ + if (mapping & POV_X) + { + switch (plat_joystick_state[joystick_nr].p[mapping & 3]) + { + case SDL_HAT_LEFTUP: case SDL_HAT_LEFT: case SDL_HAT_LEFTDOWN: + return -32767; + + case SDL_HAT_RIGHTUP: case SDL_HAT_RIGHT: case SDL_HAT_RIGHTDOWN: + return 32767; + + default: + return 0; + } + } + else if (mapping & POV_Y) + { + switch (plat_joystick_state[joystick_nr].p[mapping & 3]) + { + case SDL_HAT_LEFTUP: case SDL_HAT_UP: case SDL_HAT_RIGHTUP: + return -32767; + + case SDL_HAT_LEFTDOWN: case SDL_HAT_DOWN: case SDL_HAT_RIGHTDOWN: + return 32767; + + default: + return 0; + } + } + else + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; +} +void joystick_process() +{ + int c, d; + + if (!joystick_type) return; + + SDL_JoystickUpdate(); + for (c = 0; c < joysticks_present; c++) + { + int b; + + plat_joystick_state[c].a[0] = SDL_JoystickGetAxis(sdl_joy[c], 0); + plat_joystick_state[c].a[1] = SDL_JoystickGetAxis(sdl_joy[c], 1); + plat_joystick_state[c].a[2] = SDL_JoystickGetAxis(sdl_joy[c], 2); + plat_joystick_state[c].a[3] = SDL_JoystickGetAxis(sdl_joy[c], 3); + plat_joystick_state[c].a[4] = SDL_JoystickGetAxis(sdl_joy[c], 4); + plat_joystick_state[c].a[5] = SDL_JoystickGetAxis(sdl_joy[c], 5); + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = SDL_JoystickGetButton(sdl_joy[c], b); + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = SDL_JoystickGetHat(sdl_joy[c], b); + // pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + int x, y; + double angle, magnitude; + + x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); + y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); + magnitude = sqrt((double)x*(double)x + (double)y*(double)y); + + if (magnitude < 16384) + joystick_state[c].pov[d] = -1; + else + joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; + } + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + joystick_state[c].pov[d] = -1; + } + } +} diff --git a/src/qt/texture_frag.spv b/src/qt/texture_frag.spv new file mode 100644 index 000000000..7521ef6ee Binary files /dev/null and b/src/qt/texture_frag.spv differ diff --git a/src/qt/texture_vert.spv b/src/qt/texture_vert.spv new file mode 100644 index 000000000..6292c0de3 Binary files /dev/null and b/src/qt/texture_vert.spv differ diff --git a/src/qt/win_dynld.c b/src/qt/win_dynld.c new file mode 100644 index 000000000..98eb4739f --- /dev/null +++ b/src/qt/win_dynld.c @@ -0,0 +1,87 @@ +/* + * 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. + * + * Try to load a support DLL. + * + * + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/plat_dynld.h> + + +#ifdef ENABLE_DYNLD_LOG +int dynld_do_log = ENABLE_DYNLD_LOG; + + +static void +dynld_log(const char *fmt, ...) +{ + va_list ap; + + if (dynld_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define dynld_log(fmt, ...) +#endif + + +void * +dynld_module(const char *name, dllimp_t *table) +{ + HMODULE h; + dllimp_t *imp; + void *func; + + /* See if we can load the desired module. */ + if ((h = LoadLibrary(name)) == NULL) { + dynld_log("DynLd(\"%s\"): library not found! (%08X)\n", name, GetLastError()); + return(NULL); + } + + /* Now load the desired function pointers. */ + for (imp=table; imp->name!=NULL; imp++) { + func = GetProcAddress(h, imp->name); + if (func == NULL) { + dynld_log("DynLd(\"%s\"): function '%s' not found! (%08X)\n", + name, imp->name, GetLastError()); + FreeLibrary(h); + return(NULL); + } + + /* To overcome typing issues.. */ + *(char **)imp->func = (char *)func; + } + + /* All good. */ + dynld_log("loaded %s\n", name); + return((void *)h); +} + + +void +dynld_close(void *handle) +{ + if (handle != NULL) + FreeLibrary((HMODULE)handle); +} diff --git a/src/qt/win_joystick_rawinput.c b/src/qt/win_joystick_rawinput.c new file mode 100644 index 000000000..d1fca0491 --- /dev/null +++ b/src/qt/win_joystick_rawinput.c @@ -0,0 +1,470 @@ +/* + * 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. + * + * RawInput joystick interface. + * + * Authors: Sarah Walker, + * Miran Grca, + * GH Cao, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2020 GH Cao. + */ +#include +#include +#include +#include +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/gameport.h> +#include <86box/win.h> + +#ifdef ENABLE_JOYSTICK_LOG +int joystick_do_log = ENABLE_JOYSTICK_LOG; + + +static void +joystick_log(const char *fmt, ...) +{ + va_list ap; + + if (joystick_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define joystick_log(fmt, ...) +#endif + +typedef struct { + HANDLE hdevice; + PHIDP_PREPARSED_DATA data; + + USAGE usage_button[256]; + + struct raw_axis_t { + USAGE usage; + USHORT link; + USHORT bitsize; + LONG max; + LONG min; + } axis[8]; + + struct raw_pov_t { + USAGE usage; + USHORT link; + LONG max; + LONG min; + } pov[4]; +} raw_joystick_t; + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; +int joysticks_present = 0; + +raw_joystick_t raw_joystick_state[MAX_PLAT_JOYSTICKS]; + +/* We only use the first 32 buttons reported, from Usage ID 1-128 */ +void joystick_add_button(raw_joystick_t* rawjoy, plat_joystick_t* joy, USAGE usage) { + if (joy->nr_buttons >= 32) return; + if (usage < 1 || usage > 128) return; + + rawjoy->usage_button[usage] = joy->nr_buttons; + sprintf(joy->button[joy->nr_buttons].name, "Button %d", usage); + joy->nr_buttons++; +} + +void joystick_add_axis(raw_joystick_t* rawjoy, plat_joystick_t* joy, PHIDP_VALUE_CAPS prop) { + if (joy->nr_axes >= 8) return; + + switch (prop->Range.UsageMin) { + case HID_USAGE_GENERIC_X: + sprintf(joy->axis[joy->nr_axes].name, "X"); + break; + case HID_USAGE_GENERIC_Y: + sprintf(joy->axis[joy->nr_axes].name, "Y"); + break; + case HID_USAGE_GENERIC_Z: + sprintf(joy->axis[joy->nr_axes].name, "Z"); + break; + case HID_USAGE_GENERIC_RX: + sprintf(joy->axis[joy->nr_axes].name, "RX"); + break; + case HID_USAGE_GENERIC_RY: + sprintf(joy->axis[joy->nr_axes].name, "RY"); + break; + case HID_USAGE_GENERIC_RZ: + sprintf(joy->axis[joy->nr_axes].name, "RZ"); + break; + default: + return; + } + + joy->axis[joy->nr_axes].id = joy->nr_axes; + rawjoy->axis[joy->nr_axes].usage = prop->Range.UsageMin; + rawjoy->axis[joy->nr_axes].link = prop->LinkCollection; + rawjoy->axis[joy->nr_axes].bitsize = prop->BitSize; + + /* Assume unsigned when min >= 0 */ + if (prop->LogicalMin < 0) { + rawjoy->axis[joy->nr_axes].max = prop->LogicalMax; + } else { + /* + * Some joysticks will send -1 in LogicalMax, like Xbox Controllers + * so we need to mask that to appropriate value (instead of 0xFFFFFFFF) + */ + rawjoy->axis[joy->nr_axes].max = prop->LogicalMax & ((1 << prop->BitSize) - 1); + } + rawjoy->axis[joy->nr_axes].min = prop->LogicalMin; + + joy->nr_axes++; +} + +void joystick_add_pov(raw_joystick_t* rawjoy, plat_joystick_t* joy, PHIDP_VALUE_CAPS prop) { + if (joy->nr_povs >= 4) return; + + sprintf(joy->pov[joy->nr_povs].name, "POV %d", joy->nr_povs+1); + rawjoy->pov[joy->nr_povs].usage = prop->Range.UsageMin; + rawjoy->pov[joy->nr_povs].link = prop->LinkCollection; + rawjoy->pov[joy->nr_povs].min = prop->LogicalMin; + rawjoy->pov[joy->nr_povs].max = prop->LogicalMax; + + joy->nr_povs++; +} + +void joystick_get_capabilities(raw_joystick_t* rawjoy, plat_joystick_t* joy) { + UINT size = 0; + PHIDP_BUTTON_CAPS btn_caps = NULL; + PHIDP_VALUE_CAPS val_caps = NULL; + + /* Get preparsed data (HID data format) */ + GetRawInputDeviceInfoW(rawjoy->hdevice, RIDI_PREPARSEDDATA, NULL, &size); + rawjoy->data = malloc(size); + if (GetRawInputDeviceInfoW(rawjoy->hdevice, RIDI_PREPARSEDDATA, rawjoy->data, &size) <= 0) + fatal("joystick_get_capabilities: Failed to get preparsed data.\n"); + + HIDP_CAPS caps; + HidP_GetCaps(rawjoy->data, &caps); + + /* Buttons */ + if (caps.NumberInputButtonCaps > 0) { + btn_caps = calloc(caps.NumberInputButtonCaps, sizeof(HIDP_BUTTON_CAPS)); + if (HidP_GetButtonCaps(HidP_Input, btn_caps, &caps.NumberInputButtonCaps, rawjoy->data) != HIDP_STATUS_SUCCESS) { + joystick_log("joystick_get_capabilities: Failed to query input buttons.\n"); + goto end; + } + /* We only detect generic stuff */ + for (int c=0; c 0) { + val_caps = calloc(caps.NumberInputValueCaps, sizeof(HIDP_VALUE_CAPS)); + if (HidP_GetValueCaps(HidP_Input, val_caps, &caps.NumberInputValueCaps, rawjoy->data) != HIDP_STATUS_SUCCESS) { + joystick_log("joystick_get_capabilities: Failed to query axes and povs.\n"); + goto end; + } + /* We only detect generic stuff */ + for (int c=0; chdevice, RIDI_DEVICENAME, device_name, &size); + device_name = calloc(size, sizeof(char)); + if (GetRawInputDeviceInfoA(rawjoy->hdevice, RIDI_DEVICENAME, device_name, &size) <= 0) + fatal("joystick_get_capabilities: Failed to get device name.\n"); + + HANDLE hDevObj = CreateFile(device_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (hDevObj) { + HidD_GetProductString(hDevObj, device_desc_wide, sizeof(WCHAR) * 200); + CloseHandle(hDevObj); + } + free(device_name); + + int result = WideCharToMultiByte(CP_ACP, 0, device_desc_wide, 200, joy->name, 260, NULL, NULL); + if (result == 0 || strlen(joy->name) == 0) + sprintf(joy->name, + "RawInput %s, VID:%04lX PID:%04lX", + info->hid.usUsage == HID_USAGE_GENERIC_JOYSTICK ? "Joystick" : "Gamepad", + info->hid.dwVendorId, + info->hid.dwProductId); +} + +void joystick_init() +{ + UINT size = 0; + atexit(joystick_close); + + joysticks_present = 0; + memset(raw_joystick_state, 0, sizeof(raw_joystick_t) * MAX_PLAT_JOYSTICKS); + + /* Get a list of raw input devices from Windows */ + UINT raw_devices = 0; + GetRawInputDeviceList(NULL, &raw_devices, sizeof(RAWINPUTDEVICELIST)); + PRAWINPUTDEVICELIST deviceList = calloc(raw_devices, sizeof(RAWINPUTDEVICELIST)); + GetRawInputDeviceList(deviceList, &raw_devices, sizeof(RAWINPUTDEVICELIST)); + + for (int i=0; i= MAX_PLAT_JOYSTICKS) break; + if (deviceList[i].dwType != RIM_TYPEHID) continue; + + /* Get device info: hardware IDs and usage IDs */ + GetRawInputDeviceInfoA(deviceList[i].hDevice, RIDI_DEVICEINFO, NULL, &size); + info = malloc(size); + info->cbSize = sizeof(RID_DEVICE_INFO); + if (GetRawInputDeviceInfoA(deviceList[i].hDevice, RIDI_DEVICEINFO, info, &size) <= 0) + goto end_loop; + + /* If this is not a joystick/gamepad, skip */ + if (info->hid.usUsagePage != HID_USAGE_PAGE_GENERIC) goto end_loop; + if (info->hid.usUsage != HID_USAGE_GENERIC_JOYSTICK && + info->hid.usUsage != HID_USAGE_GENERIC_GAMEPAD) goto end_loop; + + plat_joystick_t *joy = &plat_joystick_state[joysticks_present]; + raw_joystick_t *rawjoy = &raw_joystick_state[joysticks_present]; + rawjoy->hdevice = deviceList[i].hDevice; + + joystick_get_capabilities(rawjoy, joy); + joystick_get_device_name(rawjoy, joy, info); + + joystick_log("joystick_init: %s - %d buttons, %d axes, %d POVs\n", + joy->name, joy->nr_buttons, joy->nr_axes, joy->nr_povs); + + joysticks_present++; + + end_loop: + free(info); + } + + joystick_log("joystick_init: joysticks_present=%i\n", joysticks_present); + + /* Initialize the RawInput (joystick and gamepad) module. */ + RAWINPUTDEVICE ridev[2]; + ridev[0].dwFlags = 0; + ridev[0].hwndTarget = NULL; + ridev[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + ridev[0].usUsage = HID_USAGE_GENERIC_JOYSTICK; + + ridev[1].dwFlags = 0; + ridev[1].hwndTarget = NULL; + ridev[1].usUsagePage = HID_USAGE_PAGE_GENERIC; + ridev[1].usUsage = HID_USAGE_GENERIC_GAMEPAD; + + if (!RegisterRawInputDevices(ridev, 2, sizeof(RAWINPUTDEVICE))) + fatal("plat_joystick_init: RegisterRawInputDevices failed\n"); +} + +void joystick_close() +{ + RAWINPUTDEVICE ridev[2]; + ridev[0].dwFlags = RIDEV_REMOVE; + ridev[0].hwndTarget = NULL; + ridev[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + ridev[0].usUsage = HID_USAGE_GENERIC_JOYSTICK; + + ridev[1].dwFlags = RIDEV_REMOVE; + ridev[1].hwndTarget = NULL; + ridev[1].usUsagePage = HID_USAGE_PAGE_GENERIC; + ridev[1].usUsage = HID_USAGE_GENERIC_GAMEPAD; + + RegisterRawInputDevices(ridev, 2, sizeof(RAWINPUTDEVICE)); +} + + +void win_joystick_handle(PRAWINPUT raw) +{ + HRESULT r; + int j = -1; /* current joystick index, -1 when not found */ + + /* If the input is not from a known device, we ignore it */ + for (int i=0; iheader.hDevice) { + j = i; + break; + } + } + if (j == -1) return; + + /* Read buttons */ + USAGE usage_list[128] = {0}; + ULONG usage_length = plat_joystick_state[j].nr_buttons; + memset(plat_joystick_state[j].b, 0, 32 * sizeof(int)); + + r = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usage_list, &usage_length, + raw_joystick_state[j].data, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid); + + if (r == HIDP_STATUS_SUCCESS) { + for (int i=0; imax - axis->min + 1) / 2; + + r = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, axis->link, axis->usage, &uvalue, + raw_joystick_state[j].data, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid); + + if (r == HIDP_STATUS_SUCCESS) { + if (axis->min < 0) { + /* extend signed uvalue to LONG */ + if (uvalue & (1 << (axis->bitsize-1))) { + ULONG mask = (1 << axis->bitsize) - 1; + value = -1U ^ mask; + value |= uvalue; + } else { + value = uvalue; + } + } else { + /* Assume unsigned when min >= 0, convert to a signed value */ + value = (LONG)uvalue - center; + } + if (abs(value) == 1) value = 0; + value = value * 32768 / center; + } + + plat_joystick_state[j].a[a] = value; + //joystick_log("%s %-06d ", plat_joystick_state[j].axis[a].name, plat_joystick_state[j].a[a]); + } + + /* read povs */ + for (int p=0; plink, pov->usage, &uvalue, + raw_joystick_state[j].data, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid); + + if (r == HIDP_STATUS_SUCCESS && (uvalue >= pov->min && uvalue <= pov->max)) { + value = (uvalue - pov->min) * 36000; + value /= (pov->max - pov->min + 1); + value %= 36000; + } + + plat_joystick_state[j].p[p] = value; + + //joystick_log("%s %-3d ", plat_joystick_state[j].pov[p].name, plat_joystick_state[j].p[p]); + + } + //joystick_log("\n"); +} + + +static int joystick_get_axis(int joystick_nr, int mapping) +{ + if (mapping & POV_X) + { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + if (LOWORD(pov) == 0xFFFF) + return 0; + else + return sin((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else if (mapping & POV_Y) + { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + + if (LOWORD(pov) == 0xFFFF) + return 0; + else + return -cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; + +} + + +void joystick_process(void) +{ + int c, d; + + if (joystick_type == 7) return; + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + int x, y; + double angle, magnitude; + + x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); + y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); + magnitude = sqrt((double)x*(double)x + (double)y*(double)y); + + if (magnitude < 16384) + joystick_state[c].pov[d] = -1; + else + joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; + } + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + joystick_state[c].pov[d] = -1; + } + } +} diff --git a/src/qt/wl_mouse.cpp b/src/qt/wl_mouse.cpp new file mode 100644 index 000000000..9e487cde3 --- /dev/null +++ b/src/qt/wl_mouse.cpp @@ -0,0 +1,126 @@ +/* + * 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. + * + * Wayland mouse input module. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2021-2022 Cacodemon345 + */ +#include "wl_mouse.hpp" +#include +#include +#include +#include +#include + +#include +#include +#include + +extern "C" +{ +#include <86box/plat.h> +} + +static zwp_relative_pointer_manager_v1* rel_manager = nullptr; +static zwp_relative_pointer_v1* rel_pointer = nullptr; +static zwp_pointer_constraints_v1* conf_pointer_interface = nullptr; +static zwp_locked_pointer_v1* conf_pointer = nullptr; + +static int rel_mouse_x = 0, rel_mouse_y = 0; +static bool wl_init_ok = false; + +void rel_mouse_event(void* data, zwp_relative_pointer_v1* zwp_relative_pointer_v1, uint32_t tstmp, uint32_t tstmpl, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_real, wl_fixed_t dy_real) +{ + rel_mouse_x += wl_fixed_to_int(dx_real); + rel_mouse_y += wl_fixed_to_int(dy_real); +} + +extern "C" +{ + extern int mouse_x, mouse_y; +} + +void wl_mouse_poll() +{ + mouse_x = rel_mouse_x; + mouse_y = rel_mouse_y; + rel_mouse_x = 0; + rel_mouse_y = 0; +} + +static struct zwp_relative_pointer_v1_listener rel_listener = +{ + rel_mouse_event +}; + +static void +display_handle_global(void *data, struct wl_registry *registry, uint32_t id, + const char *interface, uint32_t version) +{ + if (!strcmp(interface, "zwp_relative_pointer_manager_v1")) + { + rel_manager = (zwp_relative_pointer_manager_v1*)wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, version); + } + if (!strcmp(interface, "zwp_pointer_constraints_v1")) + { + conf_pointer_interface = (zwp_pointer_constraints_v1*)wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, version); + } +} + +static void +display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) +{ + plat_mouse_capture(0); + zwp_relative_pointer_manager_v1_destroy(rel_manager); + zwp_pointer_constraints_v1_destroy(conf_pointer_interface); + rel_manager = nullptr; + conf_pointer_interface = nullptr; +} + +static const struct wl_registry_listener registry_listener = { + display_handle_global, + display_global_remove +}; + +void wl_init() +{ + if (!wl_init_ok) { + wl_display* display = (wl_display*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display"); + if (display) + { + auto registry = wl_display_get_registry(display); + if (registry) + { + wl_registry_add_listener(registry, ®istry_listener, nullptr); + wl_display_roundtrip(display); + } + } + wl_init_ok = true; + } +} + +void wl_mouse_capture(QWindow *window) +{ + if (rel_manager) { + rel_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(rel_manager, (wl_pointer*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer")); + zwp_relative_pointer_v1_add_listener(rel_pointer, &rel_listener, nullptr); + } + if (conf_pointer_interface) conf_pointer = zwp_pointer_constraints_v1_lock_pointer(conf_pointer_interface, (wl_surface*)QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window), (wl_pointer*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer"), nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); +} + +void wl_mouse_uncapture() +{ + if (conf_pointer) zwp_locked_pointer_v1_destroy(conf_pointer); + if (rel_pointer) zwp_relative_pointer_v1_destroy(rel_pointer); + rel_pointer = nullptr; + conf_pointer = nullptr; +} diff --git a/src/qt/wl_mouse.hpp b/src/qt/wl_mouse.hpp new file mode 100644 index 000000000..a62d70fee --- /dev/null +++ b/src/qt/wl_mouse.hpp @@ -0,0 +1,5 @@ +class QWindow; +void wl_mouse_capture(QWindow* window); +void wl_mouse_uncapture(); +void wl_mouse_poll(); +void wl_init(); diff --git a/src/qt/xinput2_mouse.cpp b/src/qt/xinput2_mouse.cpp new file mode 100644 index 000000000..07791b5ba --- /dev/null +++ b/src/qt/xinput2_mouse.cpp @@ -0,0 +1,190 @@ +/* + * 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. + * + * X11 Xinput2 mouse input module. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2022 Cacodemon345 + */ + +/* Valuator parsing and duplicate event checking code from SDL2. */ +#include +#include +#include +#include +#include + +#include "qt_mainwindow.hpp" +extern MainWindow* main_window; + +#include +#include +#include + +#include + +extern "C" +{ +#include +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/mouse.h> +#include <86box/plat.h> +} + +int xi2flides[2] = { 0, 0 }; + +static Display* disp = nullptr; +static QThread* procThread = nullptr; +static XIEventMask ximask; +static std::atomic exitfromthread = false; +static std::atomic xi2_mouse_x = 0, xi2_mouse_y = 0, xi2_mouse_abs_x = 0, xi2_mouse_abs_y = 0; +static int xi2opcode = 0; +static double prev_rel_coords[2] = { 0., 0. }; +static Time prev_time = 0; + +// From SDL2. +static void parse_valuators(const double *input_values, const unsigned char *mask,int mask_len, + double *output_values,int output_values_len) { + int i = 0,z = 0; + int top = mask_len * 8; + if (top > 16) + top = 16; + + memset(output_values,0,output_values_len * sizeof(double)); + for (; i < top && z < output_values_len; i++) { + if (XIMaskIsSet(mask, i)) { + const int value = (int) *input_values; + output_values[z] = value; + input_values++; + } + z++; + } +} + +static bool exitthread = false; + +void xinput2_proc() +{ + Window win; + win = DefaultRootWindow(disp); + + // XIAllMasterDevices doesn't work for click-and-drag operations. + ximask.deviceid = XIAllDevices; + ximask.mask_len = XIMaskLen(XI_LASTEVENT); + ximask.mask = (unsigned char*)calloc(ximask.mask_len, sizeof(unsigned char)); + + XISetMask(ximask.mask, XI_RawKeyPress); + XISetMask(ximask.mask, XI_RawKeyRelease); + XISetMask(ximask.mask, XI_RawButtonPress); + XISetMask(ximask.mask, XI_RawButtonRelease); + XISetMask(ximask.mask, XI_RawMotion); + if (XKeysymToKeycode(disp, XK_Home) == 69) XISetMask(ximask.mask, XI_Motion); + + XISelectEvents(disp, win, &ximask, 1); + + XSync(disp, False); + while(true) + { + XEvent ev; + XGenericEventCookie *cookie = (XGenericEventCookie*)&ev.xcookie; + XNextEvent(disp, (XEvent*)&ev); + + if (XGetEventData(disp, cookie) && cookie->type == GenericEvent && cookie->extension == xi2opcode) { + switch (cookie->evtype) { + case XI_RawMotion: { + const XIRawEvent *rawev = (const XIRawEvent*)cookie->data; + double relative_coords[2] = { 0., 0. }; + parse_valuators(rawev->raw_values,rawev->valuators.mask, + rawev->valuators.mask_len,relative_coords,2); + + if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) { + break; // Ignore duplicated events. + } + xi2_mouse_x = xi2_mouse_x + relative_coords[0]; + xi2_mouse_y = xi2_mouse_y + relative_coords[1]; + prev_rel_coords[0] = relative_coords[0]; + prev_rel_coords[1] = relative_coords[1]; + prev_time = rawev->time; + if (!mouse_capture) break; + XWindowAttributes winattrib{}; + if (XGetWindowAttributes(disp, main_window->winId(), &winattrib)) { + auto globalPoint = main_window->mapToGlobal(QPoint(main_window->width() / 2, main_window->height() / 2)); + XWarpPointer(disp, XRootWindow(disp, XScreenNumberOfScreen(winattrib.screen)), XRootWindow(disp, XScreenNumberOfScreen(winattrib.screen)), 0, 0, 0, 0, globalPoint.x(), globalPoint.y()); + XFlush(disp); + } + + } + case XI_Motion: { + if (XKeysymToKeycode(disp, XK_Home) == 69) { + // No chance we will get raw motion events on VNC. + const XIDeviceEvent *motionev = (const XIDeviceEvent*)cookie->data; + if (xi2_mouse_abs_x != 0 || xi2_mouse_abs_y != 0) { + xi2_mouse_x = xi2_mouse_x + (motionev->event_x - xi2_mouse_abs_x); + xi2_mouse_y = xi2_mouse_y + (motionev->event_y - xi2_mouse_abs_y); + } + xi2_mouse_abs_x = motionev->event_x; + xi2_mouse_abs_y = motionev->event_y; + } + } + } + } + + XFreeEventData(disp, cookie); + if (exitthread) break; + } + XCloseDisplay(disp); +} + +void xinput2_exit() +{ + if (!exitthread) + { + exitthread = true; + procThread->wait(5000); + procThread->terminate(); + } +} + +void xinput2_init() +{ + disp = XOpenDisplay(nullptr); + if (!disp) + { + qWarning() << "Cannot open current X11 display"; + return; + } + auto event = 0, err = 0, minor = 0, major = 2; + if (XQueryExtension(disp, "XInputExtension", &xi2opcode, &event, &err)) + { + if (XIQueryVersion(disp, &major, &minor) == Success) + { + procThread = QThread::create(xinput2_proc); + procThread->start(); + atexit(xinput2_exit); + } + } +} + +void xinput2_poll() +{ + if (procThread && mouse_capture) + { + mouse_x = xi2_mouse_x; + mouse_y = xi2_mouse_y; + } + xi2_mouse_x = 0; + xi2_mouse_y = 0; +} diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc new file mode 100644 index 000000000..fec56ad71 --- /dev/null +++ b/src/qt_resources.qrc @@ -0,0 +1,64 @@ + + + win/icons/cartridge.ico + win/icons/cartridge_empty.ico + win/icons/cassette.ico + win/icons/cassette_active.ico + win/icons/cassette_empty.ico + win/icons/cassette_empty_active.ico + win/icons/cdrom.ico + win/icons/cdrom_active.ico + win/icons/cdrom_disabled.ico + win/icons/cdrom_empty.ico + win/icons/cdrom_empty_active.ico + win/icons/display.ico + win/icons/floppy_35.ico + win/icons/floppy_35_active.ico + win/icons/floppy_35_empty.ico + win/icons/floppy_35_empty_active.ico + win/icons/floppy_525.ico + win/icons/floppy_525_active.ico + win/icons/floppy_525_empty.ico + win/icons/floppy_525_empty_active.ico + win/icons/floppy_and_cdrom_drives.ico + win/icons/floppy_disabled.ico + win/icons/hard_disk.ico + win/icons/hard_disk_active.ico + win/icons/input_devices.ico + win/icons/machine.ico + win/icons/mo.ico + win/icons/mo_active.ico + win/icons/mo_disabled.ico + win/icons/mo_empty.ico + win/icons/mo_empty_active.ico + win/icons/network.ico + win/icons/network_active.ico + win/icons/other_peripherals.ico + win/icons/other_removable_devices.ico + win/icons/ports.ico + win/icons/sound.ico + win/icons/storage_controllers.ico + win/icons/zip.ico + win/icons/zip_active.ico + win/icons/zip_disabled.ico + win/icons/zip_empty.ico + win/icons/zip_empty_active.ico + win/icons/86Box-gray.ico + win/icons/86Box-green.ico + win/icons/86Box-red.ico + win/icons/86Box-yellow.ico + + + win/icons/acpi_shutdown.ico + win/icons/hard_reset.ico + win/icons/pause.ico + win/icons/run.ico + win/icons/send_cad.ico + win/icons/send_cae.ico + win/icons/settings.ico + + + qt/texture_vert.spv + qt/texture_frag.spv + + diff --git a/src/random.c b/src/random.c index 4f7168c4b..fb1fead52 100644 --- a/src/random.c +++ b/src/random.c @@ -82,7 +82,7 @@ static void random_twist(uint32_t *val) uint8_t random_generate(void) { uint16_t r = 0; - r = (rand() ^ ROTATE_LEFT(preconst, rand() % 32)) % 256; + r = (RDTSC() ^ ROTATE_LEFT(preconst, rand() % 32)) % 256; random_twist(&preconst); return (r & 0xff); } diff --git a/src/scsi/CMakeLists.txt b/src/scsi/CMakeLists.txt new file mode 100644 index 000000000..4518e0aa8 --- /dev/null +++ b/src/scsi/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(scsi OBJECT scsi.c scsi_device.c scsi_cdrom.c scsi_disk.c + scsi_x54x.c scsi_aha154x.c scsi_buslogic.c scsi_ncr5380.c + scsi_ncr53c8xx.c scsi_pcscsi.c scsi_spock.c) diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index 829e273c1..b6db9e051 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> +#include <86box/machine.h> #include <86box/hdc.h> #include <86box/hdd.h> #include <86box/plat.h> @@ -38,52 +39,99 @@ #include <86box/scsi_buslogic.h> #include <86box/scsi_ncr5380.h> #include <86box/scsi_ncr53c8xx.h> +#include <86box/scsi_pcscsi.h> #include <86box/scsi_spock.h> #ifdef WALTJE # include "scsi_wd33c93.h" #endif -int scsi_card_current = 0; -int scsi_card_last = 0; +int scsi_card_current[SCSI_BUS_MAX] = { 0, 0 }; + +static uint8_t next_scsi_bus = 0; + + +static const device_t scsi_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; typedef const struct { - const char *name; - const char *internal_name; const device_t *device; } SCSI_CARD; static SCSI_CARD scsi_cards[] = { - { "None", "none", NULL, }, - { "[ISA] Adaptec AHA-154xA", "aha154xa", &aha154xa_device, }, - { "[ISA] Adaptec AHA-154xB", "aha154xb", &aha154xb_device, }, - { "[ISA] Adaptec AHA-154xC", "aha154xc", &aha154xc_device, }, - { "[ISA] Adaptec AHA-154xCF", "aha154xcf", &aha154xcf_device, }, - { "[ISA] BusLogic BT-542B", "bt542b", &buslogic_542b_1991_device, }, - { "[ISA] BusLogic BT-542BH", "bt542bh", &buslogic_device, }, - { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device, }, - { "[ISA] Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device, }, - { "[ISA] Rancho RT1000B", "rt1000b", &scsi_rt1000b_device, }, - { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, +// clang-format off + { &scsi_none_device, }, + { &aha154xa_device, }, + { &aha154xb_device, }, + { &aha154xc_device, }, + { &aha154xcf_device, }, + { &aha154xcp_device, }, + { &buslogic_542b_device, }, + { &buslogic_542bh_device, }, + { &buslogic_545s_device, }, + { &buslogic_545c_device, }, + { &scsi_ls2000_device, }, + { &scsi_lcs6821n_device, }, + { &scsi_rt1000b_device, }, + { &scsi_rt1000mc_device, }, + { &scsi_t128_device, }, + { &scsi_t130b_device, }, #ifdef WALTJE - { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, - { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, + { &scsi_wd33c93_device, }, #endif - { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, - { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device, }, - { "[MCA] IBM PS/2 SCSI", "spock", &spock_device, }, - { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, - { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device, }, - { "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, - { "[PCI] NCR 53C860", "ncr53c860", &ncr53c860_pci_device, }, - { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, - { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, - { "", "", NULL, }, + { &aha1640_device, }, + { &buslogic_640a_device, }, + { &ncr53c90_mca_device, }, + { &spock_device, }, + { &buslogic_958d_pci_device, }, + { &ncr53c810_pci_device, }, + { &ncr53c815_pci_device, }, + { &ncr53c820_pci_device, }, + { &ncr53c825a_pci_device, }, + { &ncr53c860_pci_device, }, + { &ncr53c875_pci_device, }, + { &dc390_pci_device, }, + { &buslogic_445s_device, }, + { &buslogic_445c_device, }, + { NULL, }, +// clang-format on }; +void +scsi_reset(void) +{ + next_scsi_bus = 0; +} + + +uint8_t +scsi_get_bus(void) +{ + uint8_t ret = next_scsi_bus; + + if (next_scsi_bus >= SCSI_BUS_MAX) + return 0xff; + + next_scsi_bus++; + + return ret; +} + + int scsi_card_available(int card) { @@ -94,13 +142,6 @@ scsi_card_available(int card) } -char * -scsi_card_getname(int card) -{ - return((char *) scsi_cards[card].name); -} - - const device_t * scsi_card_getdevice(int card) { @@ -113,14 +154,14 @@ scsi_card_has_config(int card) { if (! scsi_cards[card].device) return(0); - return(scsi_cards[card].device->config ? 1 : 0); + return(device_has_config(scsi_cards[card].device) ? 1 : 0); } char * scsi_card_get_internal_name(int card) { - return((char *) scsi_cards[card].internal_name); + return device_get_internal_name(scsi_cards[card].device); } @@ -129,12 +170,12 @@ scsi_card_get_from_internal_name(char *s) { int c = 0; - while (strlen((char *) scsi_cards[c].internal_name)) { - if (!strcmp((char *) scsi_cards[c].internal_name, s)) + while (scsi_cards[c].device != NULL) { + if (!strcmp((char *) scsi_cards[c].device->internal_name, s)) return(c); c++; } - + return(0); } @@ -142,10 +183,21 @@ scsi_card_get_from_internal_name(char *s) void scsi_card_init(void) { - if (!scsi_cards[scsi_card_current].device) - return; + int i = 0, max = SCSI_BUS_MAX; - device_add(scsi_cards[scsi_card_current].device); + /* On-board SCSI controllers get the first bus, so if one is present, + increase our instance number here. */ + if (machine_has_flags(machine, MACHINE_SCSI)) + max--; - scsi_card_last = scsi_card_current; + /* Do not initialize any controllers if we have do not have any SCSI + bus left. */ + if (max > 0) { + for (i = 0; i < max; i++) { + if (!scsi_cards[scsi_card_current[i]].device) + continue; + + device_add_inst(scsi_cards[scsi_card_current[i]].device, i + 1); + } + } } diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 8e50864e1..cdf1f1a56 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -38,7 +38,9 @@ #include <86box/plat.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/isapnp.h> #include <86box/scsi.h> +#include <86box/scsi_device.h> #include <86box/scsi_aha154x.h> #include <86box/scsi_x54x.h> @@ -70,6 +72,8 @@ uint16_t aha_ports[] = { 0x0130, 0x0134, 0x0000, 0x0000 }; +static uint8_t *aha1542cp_pnp_rom = NULL; + #pragma pack(push,1) typedef struct { @@ -160,7 +164,7 @@ aha_eeprom_save(x54x_t *dev) { FILE *f; - f = nvr_fopen(dev->nvr_path, L"wb"); + f = nvr_fopen(dev->nvr_path, "wb"); if (f) { fwrite(dev->nvr, 1, NVR_SIZE, f); @@ -189,11 +193,11 @@ aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint r = 0; aha_eeprom_save(dev); - + if (dev->type == AHA_154xCF) { if (dev->fdc_address > 0) { fdc_remove(dev->fdc); - fdc_set_base(dev->fdc, dev->fdc_address); + fdc_set_base(dev->fdc, (dev->nvr[0] & EE0_ALTFLOP) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); } } } @@ -297,7 +301,7 @@ aha_param_len(void *p) case CMD_SHADOW_RAM: return 1; - break; + break; case CMD_WRITE_EEPROM: return 35; @@ -309,6 +313,12 @@ aha_param_len(void *p) case CMD_MBENABLE: return 2; + case 0x39: + return 3; + + case 0x40: + return 2; + default: return 0; } @@ -397,7 +407,7 @@ aha_cmds(void *p) dev->DataBuf[1] = dev->Lock; dev->DataReplyLeft = 2; break; - + case CMD_MBENABLE: /* Mailbox interface enable Command */ dev->DataReplyLeft = 0; if (dev->CmdBuf[1] == dev->Lock) { @@ -409,17 +419,47 @@ aha_cmds(void *p) } break; - case 0x2C: /* AHA-1542CP sends this */ - dev->DataBuf[0] = 0x00; + case 0x2C: /* Detect termination status */ + /* Bits 7,6 are termination status and must be 1,0 for the BIOS to work. */ + dev->DataBuf[0] = 0x40; dev->DataReplyLeft = 1; break; - case 0x33: /* AHA-1542CP sends this */ + case 0x2D: /* ???? - Returns two bytes according to the microcode */ dev->DataBuf[0] = 0x00; - dev->DataBuf[1] = 0x00; - dev->DataBuf[2] = 0x00; - dev->DataBuf[3] = 0x00; - dev->DataReplyLeft = 256; + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 2; + break; + + case 0x33: /* Send the SCSISelect code decompressor program */ + if (dev->cmd_33_len == 0x0000) { + /* If we are on a controller without this command, return invalid command. */ + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + /* We have to send (decompressor program length + 2 bytes of little endian size). */ + dev->DataReplyLeft = dev->cmd_33_len + 2; + memset(dev->DataBuf, 0x00, dev->DataReplyLeft); + dev->DataBuf[0] = dev->cmd_33_len & 0xff; + dev->DataBuf[1] = (dev->cmd_33_len >> 8) & 0xff; + memcpy(&(dev->DataBuf[2]), dev->cmd_33_buf, dev->cmd_33_len); + break; + + case 0x39: /* Receive 3 bytes: address high, address low, byte to write to that address. */ + /* Since we are not running the actual microcode, just log the received values + (if logging is enabled) and break. */ + aha_log("aha_cmds(): Command 0x39: %02X -> %02X%02X\n", + dev->CmdBuf[2], dev->CmdBuf[0], dev->CmdBuf[1]); + break; + + case 0x40: /* Receive 2 bytes: address high, address low, then return one byte from that + address. */ + aha_log("aha_cmds(): Command 0x40: %02X%02X\n", + dev->CmdBuf[0], dev->CmdBuf[1]); + dev->DataReplyLeft = 1; + dev->DataBuf[0] = 0xff; break; default: @@ -509,7 +549,7 @@ aha_mca_write(int port, uint8_t val, void *priv) /* Save the new IRQ and DMA channel values. */ dev->Irq = (dev->pos_regs[4] & 0x07) + 8; - dev->DmaChannel = dev->pos_regs[5] & 0x0f; + dev->DmaChannel = dev->pos_regs[5] & 0x0f; /* Extract the BIOS ROM address info. */ if (! (dev->pos_regs[2] & 0x80)) switch(dev->pos_regs[3] & 0x38) { @@ -597,6 +637,94 @@ aha_mca_feedb(void *priv) } +static void +aha_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + x54x_t *dev = (x54x_t *) priv; + int i; + + switch (ld) { + case 0: + if (dev->Base) { + x54x_io_remove(dev, dev->Base, 4); + dev->Base = 0; + } + + dev->Irq = 0; + dev->DmaChannel = ISAPNP_DMA_DISABLED; + dev->rom_addr = 0; + + mem_mapping_disable(&dev->bios.mapping); + + if (config->activate) { + dev->Base = config->io[0].base; + if (dev->Base != ISAPNP_IO_DISABLED) + x54x_io_set(dev, dev->Base, 4); + + /* + * Patch the ROM BIOS image for stuff Adaptec deliberately + * made hard to understand. Well, maybe not, maybe it was + * their way of handling issues like these at the time.. + * + * Patch 1: emulate the I/O ADDR SW setting by patching a + * byte in the BIOS that indicates the I/O ADDR + * switch setting on the board. + */ + if (dev->rom_ioaddr != 0x0000) { + /* Look up the I/O address in the table. */ + for (i=0; i<8; i++) + if (aha_ports[i] == dev->Base) break; + if (i == 8) { + aha_log("%s: invalid I/O address %04x selected!\n", + dev->name, dev->Base); + return; + } + dev->bios.rom[dev->rom_ioaddr] = (uint8_t)i; + /* Negation of the DIP switches to satify the checksum. */ + dev->bios.rom[dev->rom_ioaddr + 1] = (uint8_t)((i ^ 0xff) + 1); + } + + dev->Irq = config->irq[0].irq; + dev->DmaChannel = config->dma[0].dma; + + dev->nvr[1] = (dev->Irq - 9) | (dev->DmaChannel << 4); + aha_eeprom_save(dev); + + dev->rom_addr = config->mem[0].base; + if (dev->rom_addr) { + mem_mapping_enable(&dev->bios.mapping); + aha_log("SCSI BIOS set to: %08X-%08X\n", dev->rom_addr, dev->rom_addr + config->mem[0].size - 1); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, config->mem[0].size); + } + } + + break; + +#ifdef AHA1542CP_FDC + case 1: + if (dev->fdc_address) { + fdc_remove(dev->fdc); + dev->fdc_address = 0; + } + + fdc_set_irq(dev->fdc, 0); + fdc_set_dma_ch(dev->fdc, ISAPNP_DMA_DISABLED); + + if (config->activate) { + dev->fdc_address = config->io[0].base; + if (dev->fdc_address != ISAPNP_IO_DISABLED) + fdc_set_base(dev->fdc, dev->fdc_address); + + fdc_set_irq(dev->fdc, config->irq[0].irq); + fdc_set_dma_ch(dev->fdc, config->dma[0].dma); + } + + break; +#endif + } +} + + /* Initialize the board's ROM BIOS. */ static void aha_setbios(x54x_t *dev) @@ -611,8 +739,8 @@ aha_setbios(x54x_t *dev) if (dev->bios_path == NULL) return; /* Open the BIOS image file and make sure it exists. */ - aha_log("%s: loading BIOS from '%ls'\n", dev->name, dev->bios_path); - if ((f = rom_fopen(dev->bios_path, L"rb")) == NULL) { + aha_log("%s: loading BIOS from '%s'\n", dev->name, dev->bios_path); + if ((f = rom_fopen(dev->bios_path, "rb")) == NULL) { aha_log("%s: BIOS ROM not found!\n", dev->name); return; } @@ -705,13 +833,75 @@ aha_setbios(x54x_t *dev) } +/* Get the SCSISelect code decompressor program from the microcode rom for the + AHA-1542CP. */ +static void +aha_setmcode(x54x_t *dev) +{ + uint32_t temp; + FILE *f; + + /* Only if this device has a BIOS ROM. */ + if (dev->mcode_path == NULL) return; + + /* Open the microcode image file and make sure it exists. */ + aha_log("%s: loading microcode from '%ls'\n", dev->name, dev->bios_path); + if ((f = rom_fopen(dev->mcode_path, "rb")) == NULL) { + aha_log("%s: microcode ROM not found!\n", dev->name); + return; + } + + /* + * Manually load and process the ROM image. + * + * We *could* use the system "rom_init" function here, but for + * this special case, we can't: we may need WRITE access to the + * memory later on. + */ + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + if (temp < (dev->cmd_33_offset + dev->cmd_33_len - 1)) { + aha_log("%s: microcode ROM size invalid!\n", dev->name); + (void)fclose(f); + return; + } + + /* Allocate the buffer and then read the real PnP ROM into it. */ + if (aha1542cp_pnp_rom != NULL) { + free(aha1542cp_pnp_rom); + aha1542cp_pnp_rom = NULL; + } + aha1542cp_pnp_rom = (uint8_t *) malloc(dev->pnp_len + 7); + fseek(f, dev->pnp_offset, SEEK_SET); + (void)fread(aha1542cp_pnp_rom, dev->pnp_len, 1, f); + memset(&(aha1542cp_pnp_rom[4]), 0x00, 5); + fseek(f, dev->pnp_offset + 4, SEEK_SET); + (void)fread(&(aha1542cp_pnp_rom[9]), dev->pnp_len - 4, 1, f); + /* Even the real AHA-1542CP microcode seem to be flipping bit + 4 to not erroneously indicate there is a range length. */ + aha1542cp_pnp_rom[0x87] |= 0x04; + /* Insert the terminator and the checksum byte that will later + be filled in by the isapnp code. */ + aha1542cp_pnp_rom[dev->pnp_len + 5] = 0x79; + aha1542cp_pnp_rom[dev->pnp_len + 6] = 0x00; + + /* Load the SCSISelect decompression code. */ + fseek(f, dev->cmd_33_offset, SEEK_SET); + (void)fread(dev->cmd_33_buf, dev->cmd_33_len, 1, f); + + (void)fclose(f); +} + + static void aha_initnvr(x54x_t *dev) { /* Initialize the on-board EEPROM. */ dev->nvr[0] = dev->HostID; /* SCSI ID 7 */ dev->nvr[0] |= (0x10 | 0x20 | 0x40); - if (dev->fdc_address == 0x370) + if (dev->fdc_address == FDC_SECONDARY_ADDR) dev->nvr[0] |= EE0_ALTFLOP; dev->nvr[1] = dev->Irq-9; /* IRQ15 */ dev->nvr[1] |= (dev->DmaChannel<<4); /* DMA6 */ @@ -737,7 +927,7 @@ aha_setnvr(x54x_t *dev) dev->nvr = (uint8_t *)malloc(NVR_SIZE); memset(dev->nvr, 0x00, NVR_SIZE); - f = nvr_fopen(dev->nvr_path, L"rb"); + f = nvr_fopen(dev->nvr_path, "rb"); if (f) { if (fread(dev->nvr, 1, NVR_SIZE, f) != NVR_SIZE) fatal("aha_setnvr(): Error reading data\n"); @@ -745,6 +935,25 @@ aha_setnvr(x54x_t *dev) f = NULL; } else aha_initnvr(dev); + + if (dev->type == AHA_154xCF) { + if (dev->fdc_address > 0) { + fdc_remove(dev->fdc); + fdc_set_base(dev->fdc, (dev->nvr[0] & EE0_ALTFLOP) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); + } + } +} + + +void +aha1542cp_close(void *priv) +{ + if (aha1542cp_pnp_rom != NULL) { + free(aha1542cp_pnp_rom); + aha1542cp_pnp_rom = NULL; + } + + x54x_close(priv); } @@ -756,6 +965,7 @@ aha_init(const device_t *info) /* Call common initializer. */ dev = x54x_init(info); + dev->bus = scsi_get_bus(); /* * Set up the (initial) I/O address, IRQ and DMA info. @@ -768,7 +978,7 @@ aha_init(const device_t *info) dev->Irq = device_get_config_int("irq"); dev->DmaChannel = device_get_config_int("dma"); dev->rom_addr = device_get_config_hex20("bios_addr"); - if (!(dev->bus & DEVICE_MCA)) + if (!(dev->card_bus & DEVICE_MCA)) dev->fdc_address = device_get_config_hex16("fdc_addr"); else dev->fdc_address = 0; @@ -784,6 +994,11 @@ aha_init(const device_t *info) dev->ven_cmds = aha_cmds; dev->get_ven_data = aha_setup_data; + dev->mcode_path = NULL; + dev->cmd_33_len = 0x0000; + dev->cmd_33_offset = 0x0000; + memset(dev->cmd_33_buf, 0x00, 4096); + strcpy(dev->vendor, "Adaptec"); /* Perform per-board initialization. */ @@ -791,25 +1006,25 @@ aha_init(const device_t *info) case AHA_154xA: strcpy(dev->name, "AHA-154xA"); dev->fw_rev = "A003"; /* The 3.07 microcode says A006. */ - dev->bios_path = L"roms/scsi/adaptec/aha1540a307.bin"; /*Only for port 0x330*/ + dev->bios_path = "roms/scsi/adaptec/aha1540a307.bin"; /*Only for port 0x330*/ /* This is configurable from the configuration for the 154xB, the rest of the controllers read it from the EEPROM. */ dev->HostID = device_get_config_int("hostid"); dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->ha_bps = 5000000.0; /* normal SCSI */ break; - + case AHA_154xB: strcpy(dev->name, "AHA-154xB"); switch(dev->Base) { case 0x0330: dev->bios_path = - L"roms/scsi/adaptec/aha1540b320_330.bin"; + "roms/scsi/adaptec/aha1540b320_330.bin"; break; case 0x0334: dev->bios_path = - L"roms/scsi/adaptec/aha1540b320_334.bin"; + "roms/scsi/adaptec/aha1540b320_334.bin"; break; } dev->fw_rev = "A005"; /* The 3.2 microcode says A012. */ @@ -822,8 +1037,8 @@ aha_init(const device_t *info) case AHA_154xC: strcpy(dev->name, "AHA-154xC"); - dev->bios_path = L"roms/scsi/adaptec/aha1542c102.bin"; - dev->nvr_path = L"aha1542c.nvr"; + dev->bios_path = "roms/scsi/adaptec/aha1542c102.bin"; + dev->nvr_path = "aha1542c.nvr"; dev->fw_rev = "D001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ @@ -837,14 +1052,14 @@ aha_init(const device_t *info) case AHA_154xCF: strcpy(dev->name, "AHA-154xCF"); - dev->bios_path = L"roms/scsi/adaptec/aha1542cf211.bin"; - dev->nvr_path = L"aha1542cf.nvr"; + dev->bios_path = "roms/scsi/adaptec/aha1542cf211.bin"; + dev->nvr_path = "aha1542cf.nvr"; dev->fw_rev = "E001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ - dev->flags |= X54X_CDROM_BOOT; + dev->flags |= X54X_CDROM_BOOT; dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ @@ -855,33 +1070,48 @@ aha_init(const device_t *info) case AHA_154xCP: strcpy(dev->name, "AHA-154xCP"); - dev->bios_path = L"roms/scsi/adaptec/aha1542cp102.bin"; - dev->nvr_path = L"aha1540cp.nvr"; + dev->bios_path = "roms/scsi/adaptec/aha1542cp102.bin"; + dev->mcode_path = "roms/scsi/adaptec/908301-00_f_mcode_17c9.u12"; + dev->nvr_path = "aha1542cp.nvr"; dev->fw_rev = "F001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0055; /* firmware version (hi/lo) */ + dev->flags |= X54X_CDROM_BOOT; + dev->flags |= X54X_ISAPNP; dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ - dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->pnp_len = 0x00be; /* length of the PnP ROM */ + dev->pnp_offset = 0x533d; /* offset of the PnP ROM in the microcode ROM */ + dev->cmd_33_len = 0x06dc; /* length of the SCSISelect code expansion routine returned by + SCSI controller command 0x33 */ + dev->cmd_33_offset = 0x7000; /* offset of the SCSISelect code expansion routine in the + microcode ROM */ + aha_setmcode(dev); + if (aha1542cp_pnp_rom) + isapnp_add_card(aha1542cp_pnp_rom, dev->pnp_len + 7, aha_pnp_config_changed, NULL, NULL, NULL, dev); +#ifdef AHA1542CP_FDC + dev->fdc = device_add(&fdc_at_device); +#endif break; case AHA_1640: strcpy(dev->name, "AHA-1640"); - dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; + dev->bios_path = "roms/scsi/adaptec/aha1640.bin"; dev->fw_rev = "BB01"; dev->flags |= X54X_LBA_BIOS; /* Enable MCA. */ dev->pos_regs[0] = 0x1F; /* MCA board ID */ - dev->pos_regs[1] = 0x0F; + dev->pos_regs[1] = 0x0F; mca_add(aha_mca_read, aha_mca_write, aha_mca_feedb, NULL, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ break; - } + } /* Initialize ROM BIOS if needed. */ aha_setbios(dev); @@ -893,7 +1123,7 @@ aha_init(const device_t *info) /* Initialize the device. */ x54x_device_reset(dev); - if (!(dev->bus & DEVICE_MCA)) { + if (!(dev->card_bus & DEVICE_MCA) && !(dev->flags & X54X_ISAPNP)) { /* Register our address space. */ x54x_io_set(dev, dev->Base, 4); @@ -908,393 +1138,344 @@ aha_init(const device_t *info) return(dev); } - +// clang-format off static const device_config_t aha_154xb_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x334, - { - { - "None", 0 - }, - { - "0x330", 0x330 - }, - { - "0x334", 0x334 - }, - { - "0x230", 0x230 - }, - { - "0x234", 0x234 - }, - { - "0x130", 0x130 - }, - { - "0x134", 0x134 - }, - { - "" - } - }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x334, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "0x330", .value = 0x330 }, + { .description = "0x334", .value = 0x334 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x234", .value = 0x234 }, + { .description = "0x130", .value = 0x130 }, + { .description = "0x134", .value = 0x134 }, + { .description = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "IRQ 14", 14 - }, - { - "IRQ 15", 15 - }, - { - "" - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 11, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, + { .description = "" } }, - { - "dma", "DMA channel", CONFIG_SELECTION, "", 6, - { - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "" - } - }, + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } }, - { - "hostid", "Host ID", CONFIG_SELECTION, "", 7, - { - { - "0", 0 - }, - { - "1", 1 - }, - { - "2", 2 - }, - { - "3", 3 - }, - { - "4", 4 - }, - { - "5", 5 - }, - { - "6", 6 - }, - { - "7", 7 - }, - { - "" - } - }, + }, + { + .name = "hostid", + .description = "Host ID", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0", .value = 0 }, + { .description = "1", .value = 1 }, + { .description = "2", .value = 2 }, + { .description = "3", .value = 3 }, + { .description = "4", .value = 4 }, + { .description = "5", .value = 5 }, + { .description = "6", .value = 6 }, + { .description = "7", .value = 7 }, + { .description = "" } }, - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, - { - { - "Disabled", 0 - }, - { - "C800H", 0xc8000 - }, - { - "D000H", 0xd0000 - }, - { - "D800H", 0xd8000 - }, - { - "" - } - }, + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "" } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t aha_154x_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x334, - { - { - "None", 0 - }, - { - "0x330", 0x330 - }, - { - "0x334", 0x334 - }, - { - "0x230", 0x230 - }, - { - "0x234", 0x234 - }, - { - "0x130", 0x130 - }, - { - "0x134", 0x134 - }, - { - "" - } - }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x334, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "0x330", .value = 0x330 }, + { .description = "0x334", .value = 0x334 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x234", .value = 0x234 }, + { .description = "0x130", .value = 0x130 }, + { .description = "0x134", .value = 0x134 }, + { .description = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "IRQ 14", 14 - }, - { - "IRQ 15", 15 - }, - { - "" - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 11, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, + { .description = "" } }, - { - "dma", "DMA channel", CONFIG_SELECTION, "", 6, - { - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "" - } - }, + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } }, - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, - { - { - "Disabled", 0 - }, - { - "C800H", 0xc8000 - }, - { - "D000H", 0xd0000 - }, - { - "D800H", 0xd8000 - }, - { - "" - } - }, + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "" } + }, }, - { - "", "", -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; - static const device_config_t aha_154xcf_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x334, - { - { - "None", 0 - }, - { - "0x330", 0x330 - }, - { - "0x334", 0x334 - }, - { - "0x230", 0x230 - }, - { - "0x234", 0x234 - }, - { - "0x130", 0x130 - }, - { - "0x134", 0x134 - }, - { - "" - } - }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x334, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "0x330", .value = 0x330 }, + { .description = "0x334", .value = 0x334 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x234", .value = 0x234 }, + { .description = "0x130", .value = 0x130 }, + { .description = "0x134", .value = 0x134 }, + { .description = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "IRQ 14", 14 - }, - { - "IRQ 15", 15 - }, - { - "" - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 11, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, + { .description = "" } }, - { - "dma", "DMA channel", CONFIG_SELECTION, "", 6, - { - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "" - } - }, + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } }, - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, - { - { - "Disabled", 0 - }, - { - "C800H", 0xc8000 - }, - { - "D000H", 0xd0000 - }, - { - "D800H", 0xd8000 - }, - { - "" - } - }, + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .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 = "" } }, - { - "fdc_addr", "FDC address", CONFIG_HEX16, "", 0, - { - { - "None", 0 - }, - { - "0x3f0", 0x3f0 - }, - { - "0x370", 0x370 - }, - { - "" - } - }, + }, + { + .name = "fdc_addr", + .description = "FDC address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "0x3f0", .value = FDC_PRIMARY_ADDR }, + { .description = "0x370", .value = FDC_SECONDARY_ADDR }, + { .description = "" } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } }; - +// clang-format on const device_t aha154xa_device = { - "Adaptec AHA-154xA", - DEVICE_ISA | DEVICE_AT, - AHA_154xA, - aha_init, x54x_close, NULL, - NULL, NULL, NULL, - aha_154xb_config + .name = "Adaptec AHA-154xA", + .internal_name = "aha154xa", + .flags = DEVICE_ISA | DEVICE_AT, + .local = AHA_154xA, + .init = aha_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = aha_154xb_config }; const device_t aha154xb_device = { - "Adaptec AHA-154xB", - DEVICE_ISA | DEVICE_AT, - AHA_154xB, - aha_init, x54x_close, NULL, - NULL, NULL, NULL, - aha_154xb_config + .name = "Adaptec AHA-154xB", + .internal_name = "aha154xb", + .flags = DEVICE_ISA | DEVICE_AT, + .local = AHA_154xB, + .init = aha_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = aha_154xb_config }; const device_t aha154xc_device = { - "Adaptec AHA-154xC", - DEVICE_ISA | DEVICE_AT, - AHA_154xC, - aha_init, x54x_close, NULL, - NULL, NULL, NULL, - aha_154x_config + .name = "Adaptec AHA-154xC", + .internal_name = "aha154xc", + .flags = DEVICE_ISA | DEVICE_AT, + .local = AHA_154xC, + .init = aha_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = aha_154x_config }; const device_t aha154xcf_device = { - "Adaptec AHA-154xCF", - DEVICE_ISA | DEVICE_AT, - AHA_154xCF, - aha_init, x54x_close, NULL, - NULL, NULL, NULL, - aha_154xcf_config + .name = "Adaptec AHA-154xCF", + .internal_name = "aha154xcf", + .flags = DEVICE_ISA | DEVICE_AT, + .local = AHA_154xCF, + .init = aha_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = aha_154xcf_config +}; + +const device_t aha154xcp_device = { + .name = "Adaptec AHA-154xCP", + .internal_name = "aha154xcp", + .flags = DEVICE_ISA | DEVICE_AT, + .local = AHA_154xCP, + .init = aha_init, + .close = aha1542cp_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t aha1640_device = { - "Adaptec AHA-1640", - DEVICE_MCA, - AHA_1640, - aha_init, x54x_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Adaptec AHA-1640", + .internal_name = "aha1640", + .flags = DEVICE_MCA, + .local = AHA_1640, + .init = aha_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index a3e7b6161..e8c4dde57 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -231,13 +231,14 @@ typedef struct { enum { - CHIP_BUSLOGIC_ISA_542_1991, - CHIP_BUSLOGIC_ISA_542, - CHIP_BUSLOGIC_ISA, - CHIP_BUSLOGIC_MCA, - CHIP_BUSLOGIC_EISA, - CHIP_BUSLOGIC_VLB, - CHIP_BUSLOGIC_PCI + CHIP_BUSLOGIC_ISA_542B_1991_12_14, + CHIP_BUSLOGIC_ISA_545S_1992_10_05, + CHIP_BUSLOGIC_ISA_542BH_1993_05_23, + CHIP_BUSLOGIC_ISA_545C_1994_12_01, + CHIP_BUSLOGIC_VLB_445S_1993_11_16, + CHIP_BUSLOGIC_VLB_445C_1994_12_01, + CHIP_BUSLOGIC_MCA_640A_1993_05_23, + CHIP_BUSLOGIC_PCI_958D_1995_12_30 }; @@ -261,23 +262,27 @@ buslogic_log(const char *fmt, ...) #endif -static wchar_t * +static char * BuslogicGetNVRFileName(buslogic_data_t *bl) { switch(bl->chip) { - case CHIP_BUSLOGIC_ISA_542_1991: - return L"bt542b.nvr"; - case CHIP_BUSLOGIC_ISA_542: - return L"bt542bh.nvr"; - case CHIP_BUSLOGIC_ISA: - return L"bt545s.nvr"; - case CHIP_BUSLOGIC_MCA: - return L"bt640a.nvr"; - case CHIP_BUSLOGIC_VLB: - return L"bt445s.nvr"; - case CHIP_BUSLOGIC_PCI: - return L"bt958d.nvr"; + case CHIP_BUSLOGIC_ISA_542B_1991_12_14: + return "bt542b.nvr"; + case CHIP_BUSLOGIC_ISA_545S_1992_10_05: + return "bt545s.nvr"; + case CHIP_BUSLOGIC_ISA_542BH_1993_05_23: + return "bt542bh.nvr"; + case CHIP_BUSLOGIC_ISA_545C_1994_12_01: + return "bt545c.nvr"; + case CHIP_BUSLOGIC_VLB_445S_1993_11_16: + return "bt445s.nvr"; + case CHIP_BUSLOGIC_VLB_445C_1994_12_01: + return "bt445c.nvr"; + case CHIP_BUSLOGIC_MCA_640A_1993_05_23: + return "bt640a.nvr"; + case CHIP_BUSLOGIC_PCI_958D_1995_12_30: + return "bt958d.nvr"; default: fatal("Unrecognized BusLogic chip: %i\n", bl->chip); return NULL; @@ -303,30 +308,36 @@ BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; switch (bl->chip) { - case CHIP_BUSLOGIC_ISA_542_1991: + case CHIP_BUSLOGIC_ISA_542B_1991_12_14: memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542B", 4); break; - case CHIP_BUSLOGIC_ISA_542: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); - break; - case CHIP_BUSLOGIC_ISA: + case CHIP_BUSLOGIC_ISA_545S_1992_10_05: memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "545S", 4); break; - case CHIP_BUSLOGIC_MCA: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); + case CHIP_BUSLOGIC_ISA_542BH_1993_05_23: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); break; - case CHIP_BUSLOGIC_VLB: + case CHIP_BUSLOGIC_ISA_545C_1994_12_01: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "545C", 4); + break; + case CHIP_BUSLOGIC_VLB_445S_1993_11_16: memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "445S", 4); break; - case CHIP_BUSLOGIC_PCI: + case CHIP_BUSLOGIC_VLB_445C_1994_12_01: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "445C", 4); + break; + case CHIP_BUSLOGIC_MCA_640A_1993_05_23: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); + break; + case CHIP_BUSLOGIC_PCI_958D_1995_12_30: memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "958D", 4); break; } - HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 1 : 0; HALR->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; - if (bl->chip != CHIP_BUSLOGIC_PCI) { + if (bl->chip != CHIP_BUSLOGIC_PCI_958D_1995_12_30) { switch(dev->DmaChannel) { case 5: HALR->structured.autoSCSIData.uDMAChannel = 1; @@ -342,9 +353,9 @@ BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) break; } } - HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 0 : 1; - if (bl->chip != CHIP_BUSLOGIC_PCI) { + if (bl->chip != CHIP_BUSLOGIC_PCI_958D_1995_12_30) { switch(dev->Irq) { case 9: HALR->structured.autoSCSIData.uIrqChannel = 1; @@ -369,14 +380,14 @@ BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) break; } } - HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 0 : 1; - HALR->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + HALR->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 0 : 1; HALR->structured.autoSCSIData.uSCSIId = 7; HALR->structured.autoSCSIData.uSCSIConfiguration = 0x3F; - HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; - HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; + HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 0 : 7; + HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 0 : 4; HALR->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; if (!safe) HALR->structured.autoSCSIData.uBIOSConfiguration |= 0x04; @@ -409,14 +420,14 @@ BuslogicInitializeAutoSCSIRam(x54x_t *dev) FILE *f; - f = nvr_fopen(BuslogicGetNVRFileName(bl), L"rb"); + f = nvr_fopen(BuslogicGetNVRFileName(bl), "rb"); if (f) { if (fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f) != 64) fatal("BuslogicInitializeAutoSCSIRam(): Error reading data\n"); fclose(f); f = NULL; - if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) { x54x_io_remove(dev, dev->Base, 4); switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { case 0: @@ -472,7 +483,10 @@ buslogic_get_host_id(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542B_1991_12_14) || + (bl->chip == CHIP_BUSLOGIC_ISA_545S_1992_10_05) || + (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23) || + (bl->chip == CHIP_BUSLOGIC_VLB_445S_1993_11_16)) return dev->HostID; else return HALR->structured.autoSCSIData.uSCSIId; @@ -489,7 +503,11 @@ buslogic_get_irq(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_PCI)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542B_1991_12_14) || + (bl->chip == CHIP_BUSLOGIC_ISA_545S_1992_10_05) || + (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23) || + (bl->chip == CHIP_BUSLOGIC_VLB_445S_1993_11_16) || + (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30)) return dev->Irq; else return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; @@ -506,9 +524,12 @@ buslogic_get_dma(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if (bl->chip == CHIP_BUSLOGIC_PCI) + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) return (dev->Base ? 7 : 0); - else if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991)) + else if ((bl->chip == CHIP_BUSLOGIC_ISA_542B_1991_12_14) || + (bl->chip == CHIP_BUSLOGIC_ISA_545S_1992_10_05) || + (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23) || + (bl->chip == CHIP_BUSLOGIC_VLB_445S_1993_11_16)) return dev->DmaChannel; else return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; @@ -536,22 +557,22 @@ buslogic_param_len(void *p) return sizeof(MailboxInitExtended_t); case 0x83: return 12; - case 0x90: + case 0x90: case 0x91: return 2; case 0x94: case 0xFB: return 3; case 0x93: /* Valid only for VLB */ - return (bl->chip == CHIP_BUSLOGIC_VLB) ? 1 : 0; + return (bl->chip == CHIP_BUSLOGIC_VLB_445C_1994_12_01 || bl->chip == CHIP_BUSLOGIC_VLB_445S_1993_11_16) ? 1 : 0; case 0x95: /* Valid only for PCI */ - return (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + return (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 1 : 0; case 0x97: /* Valid only for PCI */ case 0xA7: /* Valid only for PCI */ - return (bl->chip == CHIP_BUSLOGIC_PCI) ? 10 : 0; + return (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 10 : 0; case 0xA8: /* Valid only for PCI */ case 0xA9: /* Valid only for PCI */ - return (bl->chip == CHIP_BUSLOGIC_PCI) ? 4 : 0; + return (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 4 : 0; default: return 0; } @@ -559,13 +580,13 @@ buslogic_param_len(void *p) static void -BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir, int transfer_size) +BuslogicSCSIBIOSDMATransfer(x54x_t *dev, ESCMD *ESCSICmd, uint8_t TargetID, int dir, int transfer_size) { uint32_t DataPointer = ESCSICmd->DataPointer; int DataLength = ESCSICmd->DataLength; uint32_t Address; uint32_t TransferLength; - scsi_device_t *dev = &scsi_devices[TargetID]; + scsi_device_t *sd = &scsi_devices[dev->bus][TargetID]; if (ESCSICmd->DataDirection == 0x03) { /* Non-data command. */ @@ -577,16 +598,16 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir, int tran /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && (dev->buffer_length > 0)) { + if ((DataLength > 0) && (sd->buffer_length > 0)) { Address = DataPointer; - TransferLength = MIN(DataLength, dev->buffer_length); + TransferLength = MIN(DataLength, sd->buffer_length); if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); - dma_bm_read(Address, (uint8_t *)dev->sc->temp_buffer, TransferLength, transfer_size); + dma_bm_read(Address, (uint8_t *)sd->sc->temp_buffer, TransferLength, transfer_size); } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); - dma_bm_write(Address, (uint8_t *)dev->sc->temp_buffer, TransferLength, transfer_size); + dma_bm_write(Address, (uint8_t *)sd->sc->temp_buffer, TransferLength, transfer_size); } } } @@ -594,7 +615,7 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir, int tran static void BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) -{ +{ ESCMD *ESCSICmd = (ESCMD *)CmdBuf; uint32_t i; uint8_t temp_cdb[12]; @@ -603,7 +624,7 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u uint8_t target_id = 0; #endif int phase; - scsi_device_t *sd = &scsi_devices[ESCSICmd->TargetId]; + scsi_device_t *sd = &scsi_devices[dev->bus][ESCSICmd->TargetId]; DataInBuf[0] = DataInBuf[1] = 0; @@ -612,21 +633,22 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u DataInBuf[3] = SCSI_STATUS_OK; return; } - - buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); + + buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); sd->status = SCSI_STATUS_OK; - if (!scsi_device_present(sd)) { + if (!scsi_device_present(sd) || (ESCSICmd->LogicalUnit > 0)) { buslogic_log("SCSI Target ID %i has no device attached\n", ESCSICmd->TargetId); DataInBuf[2] = CCB_SELECTION_TIMEOUT; DataInBuf[3] = SCSI_STATUS_OK; return; } else { buslogic_log("SCSI Target ID %i detected and working\n", ESCSICmd->TargetId); + scsi_device_identify(sd, ESCSICmd->LogicalUnit); buslogic_log("Transfer Control %02X\n", ESCSICmd->DataDirection); - buslogic_log("CDB Length %i\n", ESCSICmd->CDBLength); + buslogic_log("CDB Length %i\n", ESCSICmd->CDBLength); } target_cdb_len = 12; @@ -653,21 +675,22 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u phase = sd->phase; if (phase != SCSI_PHASE_STATUS) { - BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT), dev->transfer_size); + BuslogicSCSIBIOSDMATransfer(dev, ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT), dev->transfer_size); scsi_device_command_phase1(sd); } buslogic_log("BIOS Request complete\n"); + scsi_device_identify(sd, SCSI_LUN_USE_CDB); if (sd->status == SCSI_STATUS_OK) { DataInBuf[2] = CCB_COMPLETE; DataInBuf[3] = SCSI_STATUS_OK; - } else if (scsi_devices[ESCSICmd->TargetId].status == SCSI_STATUS_CHECK_CONDITION) { + } else if (scsi_devices[dev->bus][ESCSICmd->TargetId].status == SCSI_STATUS_CHECK_CONDITION) { DataInBuf[2] = CCB_COMPLETE; - DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; + DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; } - dev->DataReplyLeft = DataReply; + dev->DataReplyLeft = DataReply; } @@ -688,6 +711,8 @@ buslogic_cmds(void *p) BuslogicPCIInformation_t *ReplyPI; int cCharsToTransfer; + buslogic_log("Buslogic cmds = 0x%02x\n", dev->Command); + switch (dev->Command) { case 0x20: dev->DataReplyLeft = 0; @@ -702,14 +727,14 @@ buslogic_cmds(void *p) memset(dev->DataBuf, 0, 8); for (i = 8; i < 15; i++) { dev->DataBuf[i - 8] = 0; - if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev))) + if (scsi_device_present(&scsi_devices[dev->bus][i]) && (i != buslogic_get_host_id(dev))) dev->DataBuf[i - 8] |= 1; } dev->DataReplyLeft = 8; break; - case 0x24: + case 0x24: for (i = 0; i < 15; i++) { - if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev))) + if (scsi_device_present(&scsi_devices[dev->bus][i]) && (i != buslogic_get_host_id(dev))) TargetsPresentMask |= (1 << i); } dev->DataBuf[0] = TargetsPresentMask & 0xFF; @@ -746,13 +771,13 @@ buslogic_cmds(void *p) buslogic_log("Execute SCSI BIOS Command: %u more bytes follow\n", dev->CmdParamLeft); } else { buslogic_log("Execute SCSI BIOS Command: received %u bytes\n", dev->CmdBuf[0]); - BuslogicSCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); + BuslogicSCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); } break; case 0x84: dev->DataBuf[0] = dev->fw_rev[4]; dev->DataReplyLeft = 1; - break; + break; case 0x85: if (strlen(dev->fw_rev) == 6) dev->DataBuf[0] = dev->fw_rev[5]; @@ -761,7 +786,7 @@ buslogic_cmds(void *p) dev->DataReplyLeft = 1; break; case 0x86: - if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) { ReplyPI = (BuslogicPCIInformation_t *) dev->DataBuf; memset(ReplyPI, 0, sizeof(BuslogicPCIInformation_t)); ReplyPI->InformationIsValid = 0; @@ -792,14 +817,14 @@ buslogic_cmds(void *p) dev->DataReplyLeft = sizeof(BuslogicPCIInformation_t); } else { dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; + dev->Status |= STAT_INVCMD; } break; case 0x8B: /* The reply length is set by the guest and is found in the first byte of the command buffer. */ dev->DataReplyLeft = dev->CmdBuf[0]; memset(dev->DataBuf, 0, dev->DataReplyLeft); - if (bl->chip == CHIP_BUSLOGIC_ISA_542) + if (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23) i = 5; else i = 4; @@ -817,16 +842,18 @@ buslogic_cmds(void *p) memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); switch (bl->chip) { - case CHIP_BUSLOGIC_ISA_542_1991: - case CHIP_BUSLOGIC_ISA_542: - case CHIP_BUSLOGIC_ISA: - case CHIP_BUSLOGIC_VLB: + case CHIP_BUSLOGIC_ISA_542B_1991_12_14: + case CHIP_BUSLOGIC_ISA_545S_1992_10_05: + case CHIP_BUSLOGIC_ISA_542BH_1993_05_23: + case CHIP_BUSLOGIC_ISA_545C_1994_12_01: + case CHIP_BUSLOGIC_VLB_445S_1993_11_16: + case CHIP_BUSLOGIC_VLB_445C_1994_12_01: ReplyIESI->uBusType = 'A'; /* ISA style */ break; - case CHIP_BUSLOGIC_MCA: + case CHIP_BUSLOGIC_MCA_640A_1993_05_23: ReplyIESI->uBusType = 'M'; /* MCA style */ break; - case CHIP_BUSLOGIC_PCI: + case CHIP_BUSLOGIC_PCI_958D_1995_12_30: ReplyIESI->uBusType = 'E'; /* PCI style */ break; } @@ -834,25 +861,27 @@ buslogic_cmds(void *p) ReplyIESI->u16ScatterGatherLimit = 8192; ReplyIESI->cMailbox = dev->MailboxCount; ReplyIESI->uMailboxAddressBase = dev->MailboxOutAddr; - ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ - if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_ISA_542_1991) && (bl->chip != CHIP_BUSLOGIC_MCA)) + ReplyIESI->fHostWideSCSI = (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ? 1 : 0; + if ((bl->chip != CHIP_BUSLOGIC_ISA_542B_1991_12_14) && (bl->chip != CHIP_BUSLOGIC_ISA_545S_1992_10_05) && + (bl->chip != CHIP_BUSLOGIC_ISA_542BH_1993_05_23) && (bl->chip != CHIP_BUSLOGIC_MCA_640A_1993_05_23) && + (bl->chip != CHIP_BUSLOGIC_VLB_445S_1993_11_16)) ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; - if (bl->chip == CHIP_BUSLOGIC_PCI) + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) ReplyIESI->fHostUltraSCSI = 1; memcpy(ReplyIESI->aFirmwareRevision, &(dev->fw_rev[strlen(dev->fw_rev) - 3]), sizeof(ReplyIESI->aFirmwareRevision)); buslogic_log("Return Extended Setup Information: %d\n", dev->CmdBuf[0]); break; case 0x8F: bl->fAggressiveRoundRobinMode = dev->CmdBuf[0] & 1; - + buslogic_log("Aggressive Round Robin Mode = %d\n", bl->fAggressiveRoundRobinMode); dev->DataReplyLeft = 0; break; - case 0x90: + case 0x90: buslogic_log("Store Local RAM\n"); Offset = dev->CmdBuf[0]; dev->DataReplyLeft = 0; memcpy(&(bl->LocalRAM.u8View[Offset]), &(dev->CmdBuf[2]), dev->CmdBuf[1]); - + dev->DataReply = 0; break; case 0x91: @@ -864,13 +893,16 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; case 0x93: - if (bl->chip != CHIP_BUSLOGIC_VLB) { + if ((bl->chip != CHIP_BUSLOGIC_VLB_445C_1994_12_01) && (bl->chip != CHIP_BUSLOGIC_VLB_445S_1993_11_16)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; } case 0x92: - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + if ((bl->chip == CHIP_BUSLOGIC_ISA_542B_1991_12_14) || + (bl->chip == CHIP_BUSLOGIC_ISA_545S_1992_10_05) || + (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23) || + (bl->chip == CHIP_BUSLOGIC_MCA_640A_1993_05_23)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -887,7 +919,7 @@ buslogic_cmds(void *p) BuslogicAutoSCSIRamSetDefaults(dev, 3); break; case 1: - f = nvr_fopen(BuslogicGetNVRFileName(bl), L"wb"); + f = nvr_fopen(BuslogicGetNVRFileName(bl), "wb"); if (f) { fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); fclose(f); @@ -899,7 +931,7 @@ buslogic_cmds(void *p) break; } - if ((bl->chip == CHIP_BUSLOGIC_PCI) && !(dev->Status & STAT_INVCMD)) { + if ((bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) && !(dev->Status & STAT_INVCMD)) { x54x_io_remove(dev, dev->Base, 4); switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { case 0: @@ -916,7 +948,8 @@ buslogic_cmds(void *p) } break; case 0x94: - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + if ((bl->chip == CHIP_BUSLOGIC_ISA_542B_1991_12_14) || (bl->chip == CHIP_BUSLOGIC_ISA_545S_1992_10_05) || (bl->chip == CHIP_BUSLOGIC_MCA_640A_1993_05_23) || + (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -935,7 +968,7 @@ buslogic_cmds(void *p) } break; case 0x95: - if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) { if (dev->Base != 0) x54x_io_remove(dev, dev->Base, 4); if (dev->CmdBuf[0] < 6) { @@ -947,7 +980,7 @@ buslogic_cmds(void *p) return 1; } else { dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; + dev->Status |= STAT_INVCMD; } break; case 0x96: @@ -955,7 +988,7 @@ buslogic_cmds(void *p) bl->ExtendedLUNCCBFormat = 0; else if (dev->CmdBuf[0] == 1) bl->ExtendedLUNCCBFormat = 1; - + dev->DataReplyLeft = 0; break; case 0x97: @@ -964,7 +997,7 @@ buslogic_cmds(void *p) dev->DataReplyLeft = 0; break; case 0xA8: - if (bl->chip != CHIP_BUSLOGIC_PCI) { + if (bl->chip != CHIP_BUSLOGIC_PCI_958D_1995_12_30) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -983,7 +1016,7 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; case 0xA9: - if (bl->chip != CHIP_BUSLOGIC_PCI) { + if (bl->chip != CHIP_BUSLOGIC_PCI_958D_1995_12_30) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -1036,18 +1069,20 @@ buslogic_setup_data(void *p) bl_setup->uCharacterD = 'D'; /* BusLogic model. */ switch(bl->chip) { - case CHIP_BUSLOGIC_ISA_542_1991: - case CHIP_BUSLOGIC_ISA_542: - case CHIP_BUSLOGIC_ISA: + case CHIP_BUSLOGIC_ISA_542B_1991_12_14: + case CHIP_BUSLOGIC_ISA_545S_1992_10_05: + case CHIP_BUSLOGIC_ISA_542BH_1993_05_23: + case CHIP_BUSLOGIC_ISA_545C_1994_12_01: bl_setup->uHostBusType = 'A'; break; - case CHIP_BUSLOGIC_MCA: + case CHIP_BUSLOGIC_MCA_640A_1993_05_23: bl_setup->uHostBusType = 'B'; break; - case CHIP_BUSLOGIC_VLB: + case CHIP_BUSLOGIC_VLB_445S_1993_11_16: + case CHIP_BUSLOGIC_VLB_445C_1994_12_01: bl_setup->uHostBusType = 'E'; break; - case CHIP_BUSLOGIC_PCI: + case CHIP_BUSLOGIC_PCI_958D_1995_12_30: bl_setup->uHostBusType = 'F'; break; } @@ -1060,6 +1095,8 @@ buslogic_is_aggressive_mode(void *p) x54x_t *dev = (x54x_t *)p; buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + buslogic_log("Buslogic: Aggressive mode = %d\n", bl->fAggressiveRoundRobinMode); + return bl->fAggressiveRoundRobinMode; } @@ -1070,7 +1107,8 @@ buslogic_interrupt_type(void *p) x54x_t *dev = (x54x_t *)p; buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542B_1991_12_14) || (bl->chip == CHIP_BUSLOGIC_ISA_545S_1992_10_05) || (bl->chip == CHIP_BUSLOGIC_ISA_542BH_1993_05_23) || + (bl->chip == CHIP_BUSLOGIC_VLB_445S_1993_11_16) || (bl->chip == CHIP_BUSLOGIC_MCA_640A_1993_05_23)) return 0; else return !!bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; @@ -1271,7 +1309,7 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) x54x_mem_set_addr(dev, bl->MMIOBase); } } - return; + return; case 0x30: /* PCI_ROMBAR */ case 0x31: /* PCI_ROMBAR */ @@ -1300,7 +1338,7 @@ static void BuslogicInitializeLocalRAM(buslogic_data_t *bl) { memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); - if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) { bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; } else { bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 0; @@ -1352,7 +1390,7 @@ buslogic_mca_write(int port, uint8_t val, void *priv) /* Save the new IRQ and DMA channel values. */ dev->Irq = ((dev->pos_regs[2] >> 1) & 0x07) + 8; - dev->DmaChannel = dev->pos_regs[5] & 0x0f; + dev->DmaChannel = dev->pos_regs[5] & 0x0f; /* Extract the BIOS ROM address info. */ if (dev->pos_regs[2] & 0xe0) switch(dev->pos_regs[2] & 0xe0) { @@ -1363,7 +1401,7 @@ buslogic_mca_write(int port, uint8_t val, void *priv) case 0x00: /* [0]=000x xxxx */ bl->bios_addr = 0; break; - + case 0xc0: /* [0]=110x xxxx */ bl->bios_addr = 0xD8000; break; @@ -1515,14 +1553,14 @@ static void * buslogic_init(const device_t *info) { x54x_t *dev; - wchar_t *bios_rom_name; + char *bios_rom_name; uint16_t bios_rom_size; uint16_t bios_rom_mask; uint8_t has_autoscsi_rom; - wchar_t *autoscsi_rom_name; + char *autoscsi_rom_name; uint16_t autoscsi_rom_size; uint8_t has_scam_rom; - wchar_t *scam_rom_name; + char *scam_rom_name; uint16_t scam_rom_size; FILE *f; buslogic_data_t *bl; @@ -1530,13 +1568,14 @@ buslogic_init(const device_t *info) /* Call common initializer. */ dev = x54x_init(info); + dev->bus = scsi_get_bus(); dev->ven_data = malloc(sizeof(buslogic_data_t)); memset(dev->ven_data, 0x00, sizeof(buslogic_data_t)); bl = (buslogic_data_t *) dev->ven_data; - dev->bus = info->flags; + dev->card_bus = info->flags; if (!(info->flags & DEVICE_MCA) && !(info->flags & DEVICE_PCI)) { dev->Base = device_get_config_hex16("base"); dev->Irq = device_get_config_int("irq"); @@ -1579,94 +1618,117 @@ buslogic_init(const device_t *info) bl->fAggressiveRoundRobinMode = 1; - switch(bl->chip) - { - case CHIP_BUSLOGIC_ISA_542_1991: - strcpy(dev->name, "BT-542B"); - bios_rom_name = L"roms/scsi/buslogic/BT-542B_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 0; - has_scam_rom = 0; - dev->fw_rev = "AA221"; - dev->ha_bps = 5000000.0; /* normal SCSI */ - dev->max_id = 7; /* narrow SCSI */ - break; - case CHIP_BUSLOGIC_ISA_542: - strcpy(dev->name, "BT-542BH"); - bios_rom_name = L"roms/scsi/buslogic/BT-542BH_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 0; - has_scam_rom = 0; - dev->fw_rev = "AA335"; - dev->ha_bps = 5000000.0; /* normal SCSI */ - dev->max_id = 7; /* narrow SCSI */ - break; - case CHIP_BUSLOGIC_ISA: - default: - strcpy(dev->name, "BT-545S"); - bios_rom_name = L"roms/scsi/buslogic/BT-545S_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/BT-545S_AutoSCSI.rom"; - autoscsi_rom_size = 0x4000; - has_scam_rom = 0; - dev->fw_rev = "AA421E"; - dev->ha_bps = 10000000.0; /* fast SCSI */ - dev->max_id = 7; /* narrow SCSI */ - break; - case CHIP_BUSLOGIC_MCA: - strcpy(dev->name, "BT-640A"); - bios_rom_name = L"roms/scsi/buslogic/BT-640A_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 0; - has_scam_rom = 0; - dev->fw_rev = "BA150"; - dev->flags |= X54X_32BIT; - dev->pos_regs[0] = 0x08; /* MCA board ID */ - dev->pos_regs[1] = 0x07; - mca_add(buslogic_mca_read, buslogic_mca_write, buslogic_mca_feedb, NULL, dev); - dev->ha_bps = 5000000.0; /* normal SCSI */ - dev->max_id = 7; /* narrow SCSI */ - break; - case CHIP_BUSLOGIC_VLB: - strcpy(dev->name, "BT-445S"); - bios_rom_name = L"roms/scsi/buslogic/BT-445S_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/BT-445S_AutoSCSI.rom"; - autoscsi_rom_size = 0x8000; - has_scam_rom = 1; - scam_rom_name = L"roms/scsi/buslogic/BT-445S_SCAM.rom"; - scam_rom_size = 0x0200; - dev->fw_rev = "AA507B"; - dev->flags |= X54X_32BIT; - dev->ha_bps = 10000000.0; /* fast SCSI */ - dev->max_id = 7; /* narrow SCSI */ - break; - case CHIP_BUSLOGIC_PCI: - strcpy(dev->name, "BT-958D"); - bios_rom_name = L"roms/scsi/buslogic/BT-958D_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/BT-958D_AutoSCSI.rom"; - autoscsi_rom_size = 0x8000; - has_scam_rom = 1; - scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; - scam_rom_size = 0x0200; - dev->fw_rev = "AA507B"; - dev->flags |= (X54X_CDROM_BOOT | X54X_32BIT); - dev->ha_bps = 20000000.0; /* ultra SCSI */ - dev->max_id = 15; /* wide SCSI */ - break; - } + bios_rom_name = NULL; + has_autoscsi_rom = 0; + has_scam_rom = 0; - if ((dev->Base != 0) && !(dev->bus & DEVICE_MCA) && !(dev->bus & DEVICE_PCI)) { + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542B_1991_12_14: /*Dated December 14th, 1991*/ + strcpy(dev->name, "BT-542B"); + bios_rom_name = "roms/scsi/buslogic/BT-542B_BIOS.ROM"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA221"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_ISA_545S_1992_10_05: /*Dated October 5th, 1992*/ + strcpy(dev->name, "BT-545S"); + bios_rom_name = "roms/scsi/buslogic/BT-545S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA331"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_ISA_542BH_1993_05_23: /*Dated May 23rd, 1993*/ + strcpy(dev->name, "BT-542BH"); + bios_rom_name = "roms/scsi/buslogic/BT-542BH_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA335"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_ISA_545C_1994_12_01: /*Dated December 1st, 1994*/ + strcpy(dev->name, "BT-545C"); + bios_rom_name = "roms/scsi/buslogic/BT-545C_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = "roms/scsi/buslogic/BT-545C_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA425J"; + dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_MCA_640A_1993_05_23: /*Dated May 23rd, 1993*/ + strcpy(dev->name, "BT-640A"); + bios_rom_name = "roms/scsi/buslogic/BT-640A_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "BA335"; + dev->flags |= X54X_32BIT; + dev->pos_regs[0] = 0x08; /* MCA board ID */ + dev->pos_regs[1] = 0x07; + mca_add(buslogic_mca_read, buslogic_mca_write, buslogic_mca_feedb, NULL, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_VLB_445S_1993_11_16: /*Dated November 16th, 1993*/ + strcpy(dev->name, "BT-445S"); + bios_rom_name = "roms/scsi/buslogic/BT-445S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA335"; + dev->flags |= X54X_32BIT; + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_VLB_445C_1994_12_01: /*Dated December 1st, 1994*/ + strcpy(dev->name, "BT-445C"); + bios_rom_name = "roms/scsi/buslogic/BT-445C_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = "roms/scsi/buslogic/BT-445C_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA425J"; + dev->flags |= X54X_32BIT; + dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; + case CHIP_BUSLOGIC_PCI_958D_1995_12_30: /*Dated December 30th, 1995*/ + strcpy(dev->name, "BT-958D"); + bios_rom_name = "roms/scsi/buslogic/BT-958D_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = "roms/scsi/buslogic/BT-958D_AutoSCSI.rom"; + autoscsi_rom_size = 0x8000; + has_scam_rom = 1; + scam_rom_name = "roms/scsi/buslogic/BT-958D_SCAM.rom"; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; + dev->flags |= (X54X_CDROM_BOOT | X54X_32BIT); + dev->ha_bps = 20000000.0; /* ultra SCSI */ + dev->max_id = 15; /* wide SCSI */ + break; + } + + if ((dev->Base != 0) && !(dev->card_bus & DEVICE_MCA) && !(dev->card_bus & DEVICE_PCI)) { x54x_io_set(dev, dev->Base, 4); } @@ -1683,7 +1745,7 @@ buslogic_init(const device_t *info) rom_init(&bl->bios, bios_rom_name, bios_rom_addr, bios_rom_size, bios_rom_mask, 0, MEM_MAPPING_EXTERNAL); if (has_autoscsi_rom) { - f = rom_fopen(autoscsi_rom_name, L"rb"); + f = rom_fopen(autoscsi_rom_name, "rb"); if (f) { fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); fclose(f); @@ -1692,7 +1754,7 @@ buslogic_init(const device_t *info) } if (has_scam_rom) { - f = rom_fopen(scam_rom_name, L"rb"); + f = rom_fopen(scam_rom_name, "rb"); if (f) { fread(bl->SCAMData, 1, scam_rom_size, f); fclose(f); @@ -1706,7 +1768,7 @@ buslogic_init(const device_t *info) bl->bios_mask = 0; } - if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) { dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, BuslogicPCIRead, BuslogicPCIWrite, dev); buslogic_pci_bar[0].addr_regs[0] = 1; @@ -1724,14 +1786,15 @@ buslogic_init(const device_t *info) x54x_mem_disable(dev); } - if ((bl->chip == CHIP_BUSLOGIC_MCA) || (bl->chip == CHIP_BUSLOGIC_PCI)) + if ((bl->chip == CHIP_BUSLOGIC_MCA_640A_1993_05_23) || (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30)) mem_mapping_disable(&bl->bios.mapping); - + buslogic_log("Buslogic on port 0x%04X\n", dev->Base); - + x54x_device_reset(dev); - if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_ISA_542_1991) && (bl->chip != CHIP_BUSLOGIC_MCA)) { + if ((bl->chip != CHIP_BUSLOGIC_ISA_542B_1991_12_14) && (bl->chip != CHIP_BUSLOGIC_ISA_545S_1992_10_05) && (bl->chip != CHIP_BUSLOGIC_ISA_542BH_1993_05_23) && + (bl->chip != CHIP_BUSLOGIC_VLB_445S_1993_11_16) && (bl->chip != CHIP_BUSLOGIC_MCA_640A_1993_05_23)) { BuslogicInitializeLocalRAM(bl); BuslogicInitializeAutoSCSIRam(dev); } @@ -1739,162 +1802,198 @@ buslogic_init(const device_t *info) return(dev); } - +// clang-format off static const device_config_t BT_ISA_Config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x334, - { - { - "0x330", 0x330 - }, - { - "0x334", 0x334 - }, - { - "0x230", 0x230 - }, - { - "0x234", 0x234 - }, - { - "0x130", 0x130 - }, - { - "0x134", 0x134 - }, - { - "", 0 - } - }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x334, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x330", .value = 0x330 }, + { .description = "0x334", .value = 0x334 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x234", .value = 0x234 }, + { .description = "0x130", .value = 0x130 }, + { .description = "0x134", .value = 0x134 }, + { .description = "", .value = 0 } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "IRQ 14", 14 - }, - { - "IRQ 15", 15 - }, - { - "", 0 - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 11, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, + { .description = "", 0 } }, - { - "dma", "DMA channel", CONFIG_SELECTION, "", 6, - { - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "", 0 - } - }, + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "", .value = 0 } }, - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, - { - { - "Disabled", 0 - }, - { - "C800H", 0xc8000 - }, - { - "D000H", 0xd0000 - }, - { - "D800H", 0xd8000 - }, - { - "", 0 - } - }, + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "", .value = 0 } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } }; - static const device_config_t BT958D_Config[] = { - { - "bios", "Enable BIOS", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 - } + { + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; +// clang-format on -const device_t buslogic_542b_1991_device = { - "Buslogic BT-542B ISA", - DEVICE_ISA | DEVICE_AT, - CHIP_BUSLOGIC_ISA_542_1991, - buslogic_init, x54x_close, NULL, - NULL, NULL, NULL, - BT_ISA_Config -}; - -const device_t buslogic_device = { - "Buslogic BT-542BH ISA", - DEVICE_ISA | DEVICE_AT, - CHIP_BUSLOGIC_ISA_542, - buslogic_init, x54x_close, NULL, - NULL, NULL, NULL, - BT_ISA_Config +const device_t buslogic_542b_device = { + .name = "BusLogic BT-542B ISA", + .internal_name = "bt542b", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CHIP_BUSLOGIC_ISA_542B_1991_12_14, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT_ISA_Config }; const device_t buslogic_545s_device = { - "Buslogic BT-545S ISA", - DEVICE_ISA | DEVICE_AT, - CHIP_BUSLOGIC_ISA, - buslogic_init, x54x_close, NULL, - NULL, NULL, NULL, - BT_ISA_Config + .name = "BusLogic BT-545S ISA", + .internal_name = "bt545s", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CHIP_BUSLOGIC_ISA_545S_1992_10_05, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT_ISA_Config +}; + +const device_t buslogic_542bh_device = { + .name = "BusLogic BT-542BH ISA", + .internal_name = "bt542bh", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CHIP_BUSLOGIC_ISA_542BH_1993_05_23, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT_ISA_Config +}; + +const device_t buslogic_545c_device = { + .name = "BusLogic BT-545C ISA", + .internal_name = "bt545c", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CHIP_BUSLOGIC_ISA_545C_1994_12_01, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT_ISA_Config }; const device_t buslogic_640a_device = { - "Buslogic BT-640A MCA", - DEVICE_MCA, - CHIP_BUSLOGIC_MCA, - buslogic_init, x54x_close, NULL, - NULL, NULL, NULL, - NULL + .name = "BusLogic BT-640A MCA", + .internal_name = "bt640a", + .flags = DEVICE_MCA, + .local = CHIP_BUSLOGIC_MCA_640A_1993_05_23, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t buslogic_445s_device = { - "Buslogic BT-445S VLB", - DEVICE_VLB, - CHIP_BUSLOGIC_VLB, - buslogic_init, x54x_close, NULL, - NULL, NULL, NULL, - BT_ISA_Config + .name = "BusLogic BT-445S VLB", + .internal_name = "bt445s", + .flags = DEVICE_VLB, + .local = CHIP_BUSLOGIC_VLB_445S_1993_11_16, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT_ISA_Config }; -const device_t buslogic_pci_device = { - "Buslogic BT-958D PCI", - DEVICE_PCI, - CHIP_BUSLOGIC_PCI, - buslogic_init, x54x_close, NULL, - NULL, NULL, NULL, - BT958D_Config +const device_t buslogic_445c_device = { + .name = "BusLogic BT-445C VLB", + .internal_name = "bt445c", + .flags = DEVICE_VLB, + .local = CHIP_BUSLOGIC_VLB_445C_1994_12_01, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT_ISA_Config +}; + +const device_t buslogic_958d_pci_device = { + .name = "BusLogic BT-958D PCI", + .internal_name = "bt958d", + .flags = DEVICE_PCI, + .local = CHIP_BUSLOGIC_PCI_958D_1995_12_30, + .init = buslogic_init, + .close = x54x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = BT958D_Config }; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 8e1b5a55d..c7e9060e9 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -36,6 +36,7 @@ #include <86box/ui.h> #include <86box/cdrom.h> #include <86box/scsi_cdrom.h> +#include <86box/version.h> #pragma pack(push,1) @@ -139,7 +140,7 @@ const uint8_t scsi_cdrom_command_flags[0x100] = IMPLEMENTED | CHECK_READY, /* 0xBE */ IMPLEMENTED | CHECK_READY, /* 0xBF */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC0 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC1 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC1 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ 0, /* 0xC3 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC4 */ @@ -159,6 +160,7 @@ static uint64_t scsi_cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_CDROM_PAGE | GPMODEP_CDROM_AUDIO_PAGE | + (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); @@ -179,7 +181,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -226,7 +228,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_scsi = { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -260,7 +262,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { { { 0, 0 }, { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, + { GPMODE_DISCONNECT_PAGE, 0x0E, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -273,7 +275,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0x8E, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -441,7 +443,7 @@ static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); if (dev->drv->bus_type == CDROM_BUS_SCSI) @@ -449,12 +451,12 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) else memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, sizeof(mode_sense_pages_t)); - memset(file_name, 0, 512 * sizeof(wchar_t)); + memset(file_name, 0, 512); if (dev->drv->bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"rb"); + sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "rb"); if (f) { if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f) != 0x10) fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); @@ -467,14 +469,14 @@ static void scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); + memset(file_name, 0, 512); if (dev->drv->bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"wb"); + sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "wb"); if (f) { fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); fclose(f); @@ -797,12 +799,13 @@ scsi_cdrom_sense_clear(scsi_cdrom_t *dev, int command) static void scsi_cdrom_set_phase(scsi_cdrom_t *dev, uint8_t phase) { - uint8_t scsi_id = dev->drv->scsi_device_id; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type != CDROM_BUS_SCSI) return; - scsi_devices[scsi_id].phase = phase; + scsi_devices[scsi_bus][scsi_id].phase = phase; } @@ -1124,7 +1127,7 @@ scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *pack /* Size of buffer, not including 2 byte size field */ buf[0] = ((4 + 2) >> 8) & 0xff; - buf[1] = (4 + 2) & 0xff; + buf[1] = (4 + 2) & 0xff; /* 4 byte header + 4 byte data */ return (4 + 4); @@ -1202,7 +1205,7 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) int ready = 0; if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { scsi_cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); scsi_cdrom_invalid_lun(dev); @@ -1313,6 +1316,7 @@ scsi_cdrom_reset(scsi_common_t *sc) dev->request_length = 0xEB14; dev->packet_status = PHASE_NONE; dev->unit_attention = 0xff; + dev->cur_lun = SCSI_LUN_USE_CDB; } @@ -1415,9 +1419,11 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) int32_t blen = 0, *BufLen; uint8_t *b; uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type == CDROM_BUS_SCSI) { - BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; dev->status &= ~ERR_STAT; } else { BufLen = &blen; @@ -1430,9 +1436,9 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) device_identify[7] = dev->id + 0x30; device_identify_ex[7] = dev->id + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; + device_identify_ex[10] = EMU_VERSION_EX[0]; + device_identify_ex[12] = EMU_VERSION_EX[2]; + device_identify_ex[13] = EMU_VERSION_EX[3]; memcpy(dev->current_cdb, cdb, 12); @@ -1533,9 +1539,15 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) return; } - if (toc_format < 3) + if (toc_format < 3) { len = cdrom_read_toc(dev->drv, dev->buffer, toc_format, cdb[6], msf, max_len); - else { + if (len == -1) { + /* If the returned length is -1, this means cdrom_read_toc() has encountered an error. */ + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + } else { scsi_cdrom_invalid_field(dev); scsi_cdrom_buf_free(dev); return; @@ -1552,16 +1564,16 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); scsi_cdrom_buf_alloc(dev, 65536); - + if ((!dev->drv->ops) && ((cdb[1] & 3) == 2)) { scsi_cdrom_not_ready(dev); return; - } - + } + memset(dev->buffer, 0, 4); - + cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); - + len = 4; scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -1611,7 +1623,22 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len -= dev->sector_pos; dev->sector_len++; + msf = 1; + + if ((cdb[9] & 0xf8) == 0x08) { + /* 0x08 is an illegal mode */ + scsi_cdrom_invalid_field(dev); + return; + } + + /* If all the flag bits are cleared, then treat it as a non-data command. */ + if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) == 0x00)) + dev->sector_len = 0; + else if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) != 0x00)) { + scsi_cdrom_invalid_field(dev); + return; + } break; case GPCMD_READ_CD_OLD: case GPCMD_READ_CD: @@ -1620,6 +1647,20 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; msf = 0; + + if ((cdb[9] & 0xf8) == 0x08) { + /* 0x08 is an illegal mode */ + scsi_cdrom_invalid_field(dev); + return; + } + + /* If all the flag bits are cleared, then treat it as a non-data command. */ + if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) == 0x00)) + dev->sector_len = 0; + else if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) != 0x00)) { + scsi_cdrom_invalid_field(dev); + return; + } break; } @@ -1938,7 +1979,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_READ_DISC_INFORMATION: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - + max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; @@ -2023,7 +2064,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_illegal_mode(dev); break; - case GPCMD_TOSHIBA_PLAY_AUDIO: + case GPCMD_TOSHIBA_PLAY_AUDIO: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); if ((dev->drv->host_drive < 1) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { scsi_cdrom_illegal_mode(dev); @@ -2031,7 +2072,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; ret = cdrom_toshiba_audio_play(dev->drv, pos, cdb[9]); - + if (ret) scsi_cdrom_command_complete(dev); else @@ -2166,7 +2207,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[1] = 0x13; break; } - + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[1]); } @@ -2205,7 +2246,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); scsi_cdrom_data_command_finish(dev, len, len, len, 0); - break; + break; case GPCMD_READ_DVD_STRUCTURE: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); @@ -2265,7 +2306,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_command_complete(dev); break; - + case GPCMD_CADDY_EJECT: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); @@ -2343,22 +2384,22 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->buffer, 0, 8); dev->buffer[0] = 5; /*CD-ROM*/ dev->buffer[1] = 0x80; /*Removable*/ - + if (dev->drv->bus_type == CDROM_BUS_SCSI) { dev->buffer[2] = 0x02; dev->buffer[3] = 0x02; } else { dev->buffer[2] = 0x00; - dev->buffer[3] = 0x21; + dev->buffer[3] = 0x21; } - + dev->buffer[4] = 31; if (dev->drv->bus_type == CDROM_BUS_SCSI) { dev->buffer[6] = 1; /* 16-bit transfers supported */ dev->buffer[7] = 0x20; /* Wide bus supported */ } - + if (dev->drv->bus_type == CDROM_BUS_SCSI) { ide_padstr8(dev->buffer + 8, 8, "TOSHIBA"); /* Vendor */ ide_padstr8(dev->buffer + 16, 16, "XM6201TASUN32XCD"); /* Product */ @@ -2366,7 +2407,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } else { ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->buffer + 32, 4, EMU_VERSION); /* Revision */ + ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ } idx = 36; @@ -2446,7 +2487,7 @@ atapi_out: case GPCMD_STOP_PLAY_SCAN: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if (dev->drv->cd_status <= CD_STATUS_DATA_ONLY) { + if (dev->drv->cd_status <= CD_STATUS_DATA_ONLY) { scsi_cdrom_illegal_mode(dev); break; } @@ -2483,6 +2524,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; uint16_t block_desc_len, pos; + uint16_t param_list_len; uint16_t i = 0; uint8_t error = 0; @@ -2491,10 +2533,15 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) switch(dev->current_cdb[0]) { case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) { hdr_len = 8; - else + param_list_len = dev->current_cdb[7]; + param_list_len <<= 8; + param_list_len |= dev->current_cdb[8]; + } else { hdr_len = 4; + param_list_len = dev->current_cdb[4]; + } if (dev->drv->bus_type == CDROM_BUS_SCSI) { if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { @@ -2512,7 +2559,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos = hdr_len + block_desc_len; while(1) { - if (pos >= dev->current_cdb[4]) { + if (pos >= param_list_len) { scsi_cdrom_log("CD-ROM %i: Buffer has only block descriptor\n", dev->id); break; } @@ -2594,7 +2641,7 @@ scsi_cdrom_get_max(int ide_has_dma, int type) ret = ide_has_dma ? 2 : -1; break; case TYPE_UDMA: - ret = ide_has_dma ? 4 /*2*/ : -1; + ret = ide_has_dma ? 5 : -1; break; default: ret = -1; @@ -2648,7 +2695,7 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ #if 0 - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ #else ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ @@ -2660,6 +2707,8 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) if (ide_has_dma) { ide->buffer[71] = 30; ide->buffer[72] = 30; + ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/ + ide->buffer[81] = 0x19; /*ATA-6 revision 3a supported*/ } } @@ -2671,10 +2720,18 @@ scsi_cdrom_drive_reset(int c) scsi_cdrom_t *dev; scsi_device_t *sd; ide_t *id; + uint8_t scsi_bus = (drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = drv->scsi_device_id & 0x0f; - /* Make sure to ignore any SCSI CD-ROM drive that has an out of range ID. */ - if ((drv->bus_type == CDROM_BUS_SCSI) && (drv->scsi_device_id >= SCSI_ID_MAX)) - return; + if (drv->bus_type == CDROM_BUS_SCSI) { + /* Make sure to ignore any SCSI CD-ROM drive that has an out of range SCSI bus. */ + if (scsi_bus >= SCSI_BUS_MAX) + return; + + /* Make sure to ignore any SCSI CD-ROM drive that has an out of range ID. */ + if (scsi_id >= SCSI_ID_MAX) + return; + } /* Make sure to ignore any ATAPI CD-ROM drive that has an out of range IDE channel. */ if ((drv->bus_type == CDROM_BUS_ATAPI) && (drv->ide_channel > 7)) @@ -2689,6 +2746,9 @@ scsi_cdrom_drive_reset(int c) dev->id = c; dev->drv = drv; + + dev->cur_lun = SCSI_LUN_USE_CDB; + drv->insert = scsi_cdrom_insert; drv->get_volume = scsi_cdrom_get_volume; drv->get_channel = scsi_cdrom_get_channel; @@ -2698,7 +2758,7 @@ scsi_cdrom_drive_reset(int c) if (drv->bus_type == CDROM_BUS_SCSI) { /* SCSI CD-ROM, attach to the SCSI bus. */ - sd = &scsi_devices[drv->scsi_device_id]; + sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = scsi_cdrom_command; diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index f4dc555c0..09e44a914 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -27,7 +27,7 @@ #include <86box/scsi_device.h> -scsi_device_t scsi_devices[SCSI_ID_MAX]; +scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX]; uint8_t scsi_null_device_sense[18] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0,0,0,0,0 }; @@ -158,16 +158,33 @@ scsi_device_command_phase1(scsi_device_t *dev) } +/* When LUN is FF, there has been no IDENTIFY message, otherwise + there has been one. */ +void +scsi_device_identify(scsi_device_t *dev, uint8_t lun) +{ + if ((dev == NULL) || (dev->type == SCSI_NONE) || !dev->sc) + return; + + dev->sc->cur_lun = lun; + + /* TODO: This should return a value, should IDENTIFY fail due to a + a LUN not supported by the target. */ +} + + void scsi_device_close_all(void) { - int i; + int i, j; scsi_device_t *dev; - for (i = 0; i < SCSI_ID_MAX; i++) { - dev = &(scsi_devices[i]); - if (dev->command_stop && dev->sc) - dev->command_stop(dev->sc); + for (i = 0; i < SCSI_BUS_MAX; i++) { + for (j = 0; j < SCSI_ID_MAX; j++) { + dev = &(scsi_devices[i][j]); + if (dev->command_stop && dev->sc) + dev->command_stop(dev->sc); + } } } @@ -175,13 +192,15 @@ scsi_device_close_all(void) void scsi_device_init(void) { - int i; + int i, j; scsi_device_t *dev; - for (i = 0; i < SCSI_ID_MAX; i++) { - dev = &(scsi_devices[i]); + for (i = 0; i < SCSI_BUS_MAX; i++) { + for (j = 0; j < SCSI_ID_MAX; j++) { + dev = &(scsi_devices[i][j]); - memset(dev, 0, sizeof(scsi_device_t)); - dev->type = SCSI_NONE; + memset(dev, 0, sizeof(scsi_device_t)); + dev->type = SCSI_NONE; + } } } diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 19d87bfa6..d3e7b6f11 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -30,6 +30,7 @@ #include <86box/plat.h> #include <86box/ui.h> #include <86box/scsi_disk.h> +#include <86box/version.h> #define scsi_disk_sense_error dev->sense[0] @@ -145,14 +146,14 @@ void scsi_disk_mode_sense_load(scsi_disk_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); memcpy(&dev->ms_pages_saved, &scsi_disk_mode_sense_pages_default, sizeof(mode_sense_pages_t)); - memset(file_name, 0, 512 * sizeof(wchar_t)); - swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"rb"); + memset(file_name, 0, 512); + sprintf(file_name, "scsi_disk_%02i_mode_sense.bin", dev->id); + f = plat_fopen(nvr_path(file_name), "rb"); if (f) { if (fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f) != 0x18) fatal("scsi_disk_mode_sense_load(): Error reading data\n"); @@ -165,11 +166,11 @@ void scsi_disk_mode_sense_save(scsi_disk_t *dev) { FILE *f; - wchar_t file_name[512]; + char file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"wb"); + memset(file_name, 0, 512); + sprintf(file_name, "scsi_disk_%02i_mode_sense.bin", dev->id); + f = plat_fopen(nvr_path(file_name), "wb"); if (f) { fwrite(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); fclose(f); @@ -346,12 +347,13 @@ scsi_disk_sense_clear(scsi_disk_t *dev, int command) static void scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase) { - uint8_t scsi_id = dev->drv->scsi_id; + uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_id & 0x0f; if (dev->drv->bus != HDD_BUS_SCSI) return; - scsi_devices[scsi_id].phase = phase; + scsi_devices[scsi_bus][scsi_id].phase = phase; } @@ -435,7 +437,7 @@ scsi_disk_data_phase_error(scsi_disk_t *dev) static int scsi_disk_pre_execution_check(scsi_disk_t *dev, uint8_t *cdb) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { scsi_disk_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); scsi_disk_invalid_lun(dev); @@ -487,12 +489,13 @@ scsi_disk_reset(scsi_common_t *sc) dev->status = 0; dev->callback = 0.0; dev->packet_status = PHASE_NONE; + dev->cur_lun = SCSI_LUN_USE_CDB; } void scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) -{ +{ /*Will return 18 bytes of 0*/ if (alloc_length != 0) { memset(buffer, 0, alloc_length); @@ -570,8 +573,10 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int block_desc = 0; + uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_id & 0x0f; - BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; + BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; last_sector = hdd_image_get_last_sector(dev->id); @@ -583,9 +588,9 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) device_identify_ex[6] = (dev->id / 10) + 0x30; device_identify_ex[7] = (dev->id % 10) + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; + device_identify_ex[10] = EMU_VERSION_EX[0]; + device_identify_ex[12] = EMU_VERSION_EX[2]; + device_identify_ex[13] = EMU_VERSION_EX[3]; memcpy(dev->current_cdb, cdb, 12); @@ -917,7 +922,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * SCSI_TIME; break; - } + } scsi_disk_buf_alloc(dev, 65536); @@ -984,7 +989,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) ide_padstr8(dev->temp_buffer + 8, 8, EMU_NAME); /* Vendor */ ide_padstr8(dev->temp_buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION_EX); /* Revision */ idx = 36; if (max_len == 96) { @@ -1071,11 +1076,14 @@ static uint8_t scsi_disk_phase_data_out(scsi_common_t *sc) { scsi_disk_t *dev = (scsi_disk_t *) sc; + uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_id & 0x0f; int i; - int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; + int32_t *BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; uint32_t last_sector = hdd_image_get_last_sector(dev->id); uint32_t c, h, s, last_to_write = 0; uint16_t block_desc_len, pos; + uint16_t param_list_len; uint8_t hdr_len, val, old_val, ch, error = 0; uint8_t page, page_len; @@ -1132,10 +1140,15 @@ scsi_disk_phase_data_out(scsi_common_t *sc) break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) { hdr_len = 8; - else + param_list_len = dev->current_cdb[7]; + param_list_len <<= 8; + param_list_len |= dev->current_cdb[8]; + } else { hdr_len = 4; + param_list_len = dev->current_cdb[4]; + } if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { block_desc_len = dev->temp_buffer[2]; @@ -1150,7 +1163,7 @@ scsi_disk_phase_data_out(scsi_common_t *sc) pos = hdr_len + block_desc_len; while(1) { - if (pos >= dev->current_cdb[4]) { + if (pos >= param_list_len) { scsi_disk_log("SCSI HD %i: Buffer has only block descriptor\n", dev->id); break; } @@ -1207,17 +1220,25 @@ scsi_disk_hard_reset(void) int c; scsi_disk_t *dev; scsi_device_t *sd; + uint8_t scsi_bus, scsi_id; for (c = 0; c < HDD_NUM; c++) { if (hdd[c].bus == HDD_BUS_SCSI) { scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); + scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; + scsi_id = hdd[c].scsi_id & 0x0f; + + /* Make sure to ignore any SCSI disk that has an out of range SCSI bus. */ + if (scsi_bus >= SCSI_BUS_MAX) + continue; + /* Make sure to ignore any SCSI disk that has an out of range ID. */ - if (hdd[c].scsi_id >= SCSI_ID_MAX) + if (scsi_id >= SCSI_ID_MAX) continue; /* Make sure to ignore any SCSI disk whose image file name is empty. */ - if (wcslen(hdd[c].fn) == 0) + if (strlen(hdd[c].fn) == 0) continue; /* Make sure to ignore any SCSI disk whose image fails to load. */ @@ -1232,7 +1253,7 @@ scsi_disk_hard_reset(void) dev = (scsi_disk_t *) hdd[c].priv; /* SCSI disk, attach to the SCSI bus. */ - sd = &scsi_devices[hdd[c].scsi_id]; + sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = scsi_disk_command; @@ -1245,6 +1266,8 @@ scsi_disk_hard_reset(void) dev->id = c; dev->drv = &hdd[c]; + dev->cur_lun = SCSI_LUN_USE_CDB; + scsi_disk_mode_sense_load(dev); scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); @@ -1258,10 +1281,14 @@ scsi_disk_close(void) { scsi_disk_t *dev; int c; + uint8_t scsi_bus, scsi_id; for (c = 0; c < HDD_NUM; c++) { if (hdd[c].bus == HDD_BUS_SCSI) { - memset(&scsi_devices[hdd[c].scsi_id], 0x00, sizeof(scsi_device_t)); + scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; + scsi_id = hdd[c].scsi_id & 0x0f; + + memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); hdd_image_close(c); diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 659f6cf5e..387d650f1 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -43,10 +43,12 @@ #include <86box/scsi_ncr5380.h> -#define LCS6821N_ROM L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" -#define RT1000B_810R_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" -#define RT1000B_820R_ROM L"roms/scsi/ncr5380/RTBIOS82.rom" -#define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" +#define LCS6821N_ROM "roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" +#define RT1000B_810R_ROM "roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define RT1000B_820R_ROM "roms/scsi/ncr5380/RTBIOS82.ROM" +#define T130B_ROM "roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" +#define T128_ROM "roms/scsi/ncr5380/trantor_t128_bios_v1.12.bin" +#define COREL_LS2000_ROM "roms/scsi/ncr5380/Corel LS2000 - BIOS ROM - Ver 1.65.bin" #define NCR_CURDATA 0 /* current SCSI data (read only) */ @@ -93,7 +95,7 @@ #define STATUS_BUFFER_NOT_READY 0x04 #define STATUS_53C80_ACCESSIBLE 0x80 -typedef struct { +typedef struct { uint8_t icr, mode, tcr, data_wait; uint8_t isr, output_data, target_id, tx_data; uint8_t msglun; @@ -108,8 +110,22 @@ typedef struct { int command_pos, data_pos; } ncr_t; +typedef struct { + uint8_t ctrl; + uint8_t status; + uint8_t buffer[512]; + uint8_t ext_ram[0x80]; + uint8_t block_count; + + int block_loaded; + int pos, host_pos; + + int bios_enabled; +} t128_t; + typedef struct { ncr_t ncr; + t128_t t128; const char *name; @@ -124,7 +140,7 @@ typedef struct { int8_t bios_ver; uint8_t block_count; uint8_t status_ctrl; - uint8_t pad[2]; + uint8_t bus, pad; rom_t bios_rom; mem_mapping_t mapping; @@ -139,7 +155,8 @@ typedef struct { pc_timer_t timer; double period; - int ncr_busy; + int ncr_busy; + uint8_t pos_regs[8]; } ncr5380_t; #define STATE_IDLE 0 @@ -181,9 +198,26 @@ ncr_log(const char *fmt, ...) #define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) +static void +ncr_dma_send(ncr5380_t *ncr_dev, ncr_t *ncr, scsi_device_t *dev); + +static void +ncr_dma_initiator_receive(ncr5380_t *ncr_dev, ncr_t *ncr, scsi_device_t *dev); + static void ncr_callback(void *priv); +static void +ncr_irq(ncr5380_t *ncr_dev, ncr_t *ncr, int set_irq) +{ + if (set_irq) { + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } else { + ncr->isr &= ~STATUS_INT; + picintc(1 << ncr_dev->irq); + } +} static int get_dev_id(uint8_t data) @@ -197,7 +231,7 @@ get_dev_id(uint8_t data) return(-1); } -static int +static int getmsglen(uint8_t *msgp, int len) { uint8_t msg = msgp[0]; @@ -211,58 +245,38 @@ getmsglen(uint8_t *msgp, int len) } static void -ncr_reset(ncr_t *ncr) +ncr_reset(ncr5380_t *ncr_dev, ncr_t *ncr) { memset(ncr, 0x00, sizeof(ncr_t)); ncr_log("NCR reset\n"); + + timer_stop(&ncr_dev->timer); + + for (int i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[ncr_dev->bus][i]); + + ncr_irq(ncr_dev, ncr, 0); } - static void -dma_timer_on(ncr5380_t *ncr_dev) +ncr_timer_on(ncr5380_t *ncr_dev, ncr_t *ncr, int callback) { - ncr_t *ncr = &ncr_dev->ncr; - double period = ncr_dev->period; + double p = ncr_dev->period; - /* DMA Timer on: 1 wait period + 64 byte periods + 64 byte periods if first time. */ - if (ncr->data_wait & 2) { - ncr->data_wait &= ~2; - period *= 128.0; - } else - period *= 64.0; + if (ncr->data_wait & 2) + ncr->data_wait &= ~2; - /* This is the 1 us wait period. */ - period += 1.0; + if (callback) { + if (ncr_dev->type == 3) + p *= 512.0; + else + p *= 128.0; + } - timer_on_auto(&ncr_dev->timer, period); -} + p += 1.0; - -static void -wait_timer_on(ncr5380_t *ncr_dev) -{ - /* PIO Wait Timer On: 1 period. */ - timer_on_auto(&ncr_dev->timer, ncr_dev->period); -} - - -static void -set_dma_enable(ncr5380_t *dev, int enable) -{ - if (enable) { - if (!timer_is_enabled(&dev->timer)) - dma_timer_on(dev); - } else - timer_stop(&dev->timer); -} - - -static void -dma_changed(ncr5380_t *dev, int mode, int enable) -{ - dev->dma_enabled = (mode && enable); - - set_dma_enable(dev, dev->dma_enabled && dev->block_count_loaded); + ncr_log("P = %lf, command = %02x, callback = %i, period = %lf, t128 pos = %i\n", p, ncr->command[0], callback, ncr_dev->period, ncr_dev->t128.host_pos); + timer_on_auto(&ncr_dev->timer, p); } @@ -325,8 +339,8 @@ ncr_bus_read(ncr5380_t *ncr_dev) if (ncr->wait_data) { ncr->wait_data--; if (!ncr->wait_data) { - dev = &scsi_devices[ncr->target_id]; - SET_BUS_STATE(ncr, ncr->new_phase); + dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; + SET_BUS_STATE(ncr, ncr->new_phase); phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); if (phase == SCSI_PHASE_DATA_IN) { @@ -367,7 +381,7 @@ ncr_bus_update(void *priv, int bus) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; ncr_t *ncr = &ncr_dev->ncr; - scsi_device_t *dev = &scsi_devices[ncr->target_id]; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; double p; uint8_t sel_data; int msglen; @@ -376,193 +390,209 @@ ncr_bus_update(void *priv, int bus) if (bus & BUS_ARB) ncr->state = STATE_IDLE; - if (ncr->state == STATE_IDLE) { - ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; - if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { - ncr_log("Selection phase\n"); - sel_data = BUS_GETDATA(bus); + ncr_log("State = %i\n", ncr->state); - ncr->target_id = get_dev_id(sel_data); + switch (ncr->state) { + case STATE_IDLE: + ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; + if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { + ncr_log("Selection phase\n"); + sel_data = BUS_GETDATA(bus); - ncr_log("Select - target ID = %i\n", ncr->target_id); + ncr->target_id = get_dev_id(sel_data); - /*Once the device has been found and selected, mark it as busy*/ - if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { - ncr->cur_bus |= BUS_BSY; - ncr->state = STATE_SELECT; - } else { - ncr_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->cur_bus = 0; - } - } - } else if (ncr->state == STATE_SELECT) { - if (!(bus & BUS_SEL)) { - if (!(bus & BUS_ATN)) { - if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { - ncr_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - picint(1 << ncr_dev->irq); + ncr_log("Select - target ID = %i\n", ncr->target_id); + + /*Once the device has been found and selected, mark it as busy*/ + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr_dev->bus][ncr->target_id])) { + ncr->cur_bus |= BUS_BSY; + ncr->state = STATE_SELECT; } else { - ncr->state = STATE_IDLE; + ncr_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); ncr->cur_bus = 0; } - } else { - ncr_log("Set to SCSI Message Out\n"); - ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; - ncr->wait_data = 4; - ncr->msgout_pos = 0; - ncr->is_msgout = 1; } - } - } else if (ncr->state == STATE_COMMAND) { - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*Write command byte to the output data register*/ - ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); - ncr->clear_req = 3; - ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; - ncr->cur_bus &= ~BUS_REQ; - - ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); - - if (ncr->command_pos == cmd_len[(ncr->command[0] >> 5) & 7]) { - if (ncr->is_msgout) { - ncr->is_msgout = 0; - ncr->command[1] &= ~(0x80 | 0x40 | 0x20); - ncr->command[1] |= ncr->msglun << 5; - } - - /*Reset data position to default*/ - ncr->data_pos = 0; - - dev = &scsi_devices[ncr->target_id]; - - ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); - dev->buffer_length = -1; - scsi_device_command_phase0(dev, ncr->command); - ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); - - ncr_dev->period = 1.0; /* 1 us default */ - ncr->wait_data = 4; - ncr->data_wait = 0; - - if (dev->status == SCSI_STATUS_OK) { - /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ - if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { - p = scsi_device_get_callback(dev); - if (p <= 0.0) - ncr_dev->period = 0.2/* * ((double) dev->buffer_length) */; - else - ncr_dev->period = p / ((double) dev->buffer_length); - ncr->data_wait |= 2; + break; + case STATE_SELECT: + if (!(bus & BUS_SEL)) { + if (!(bus & BUS_ATN)) { + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr_dev->bus][ncr->target_id])) { + ncr_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + } else { + ncr->state = STATE_IDLE; + ncr->cur_bus = 0; } + } else { + ncr_log("Set to SCSI Message Out\n"); + ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; + ncr->wait_data = 4; + ncr->msgout_pos = 0; + ncr->is_msgout = 1; } - - ncr->new_phase = dev->phase; } - } - } else if (ncr->state == STATE_DATAIN) { - dev = &scsi_devices[ncr->target_id]; - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - if (ncr->data_pos >= dev->buffer_length) { + break; + case STATE_COMMAND: + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + /*Write command byte to the output data register*/ + ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); + ncr->clear_req = 3; + ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; ncr->cur_bus &= ~BUS_REQ; - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; + + ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); + + if (ncr->command_pos == cmd_len[(ncr->command[0] >> 5) & 7]) { + if (ncr->is_msgout) { + ncr->is_msgout = 0; + // ncr->command[1] = (ncr->command[1] & 0x1f) | (ncr->msglun << 5); + } + + /*Reset data position to default*/ + ncr->data_pos = 0; + + dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; + + ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); + dev->buffer_length = -1; + scsi_device_command_phase0(dev, ncr->command); + ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); + + ncr_dev->period = 1.0; + ncr->wait_data = 4; + ncr->data_wait = 0; + + if (dev->status == SCSI_STATUS_OK) { + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { + p = scsi_device_get_callback(dev); + if (p <= 0.0) { + ncr_dev->period = 0.2; + } else { + ncr_dev->period = p / ((double) dev->buffer_length); + } + ncr->data_wait |= 2; + ncr_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i\n", ncr->target_id, ncr->command[0], p, ncr_dev->period, dev->buffer_length); + } + } + ncr->new_phase = dev->phase; + } + } + break; + case STATE_DATAIN: + dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + if (ncr->data_pos >= dev->buffer_length) { + ncr->cur_bus &= ~BUS_REQ; + scsi_device_command_phase1(dev); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + if (ncr->data_wait & 2) + ncr->data_wait &= ~2; + if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/ + ncr->data_wait |= 1; + ncr_log("DMA mode idle in\n"); + timer_on_auto(&ncr_dev->timer, ncr_dev->period); + } else + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + } + break; + case STATE_DATAOUT: + dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); + + if (ncr->data_pos >= dev->buffer_length) { + ncr->cur_bus &= ~BUS_REQ; + scsi_device_command_phase1(dev); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + /*More data is to be transferred, place a request*/ + if (ncr->dma_mode == DMA_IDLE) { /*If a data out command that is not write 6/10 has been issued*/ + ncr->data_wait |= 1; + ncr_log("DMA mode idle out\n"); + timer_on_auto(&ncr_dev->timer, ncr_dev->period); + } else { + ncr->clear_req = 3; + } + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + } + break; + case STATE_STATUS: + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + /*All transfers done, wait until next transfer*/ + scsi_device_identify(&scsi_devices[ncr_dev->bus][ncr->target_id], SCSI_LUN_USE_CDB); + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_MESSAGE_IN; ncr->wait_data = 4; ncr->wait_complete = 8; - } else { - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - if (ncr->data_wait & 2) - ncr->data_wait &= ~2; - if (ncr->dma_mode == DMA_IDLE) { - ncr->data_wait |= 1; - wait_timer_on(ncr_dev); - } else - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; } - } - } else if (ncr->state == STATE_DATAOUT) { - dev = &scsi_devices[ncr->target_id]; - - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); - - if (ncr->data_pos >= dev->buffer_length) { + break; + case STATE_MESSAGEIN: + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { ncr->cur_bus &= ~BUS_REQ; - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; + ncr->new_phase = BUS_IDLE; ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - /*More data is to be transferred, place a request*/ - if (ncr->dma_mode == DMA_IDLE) { - ncr->data_wait |= 1; - wait_timer_on(ncr_dev); - } else - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); } - } - } else if (ncr->state == STATE_STATUS) { - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*All transfers done, wait until next transfer*/ - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_MESSAGE_IN; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - } else if (ncr->state == STATE_MESSAGEIN) { - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = BUS_IDLE; - ncr->wait_data = 4; - } - } else if (ncr->state == STATE_MESSAGEOUT) { - ncr_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); - msglen = getmsglen(ncr->msgout, ncr->msgout_pos); - if (ncr->msgout_pos >= msglen) { - if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) - ncr->msglun = ncr->msgout[0] & 7; - ncr->cur_bus &= ~BUS_REQ; - ncr->state = STATE_MESSAGE_ID; + break; + case STATE_MESSAGEOUT: + ncr_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); + msglen = getmsglen(ncr->msgout, ncr->msgout_pos); + if (ncr->msgout_pos >= msglen) { + if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) + ncr->msglun = ncr->msgout[0] & 7; + ncr->cur_bus &= ~BUS_REQ; + ncr->state = STATE_MESSAGE_ID; + } } - } - } else if (ncr->state == STATE_MESSAGE_ID) { - if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { + break; + case STATE_MESSAGE_ID: + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr_dev->bus][ncr->target_id])) { ncr_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + scsi_device_identify(&scsi_devices[ncr_dev->bus][ncr->target_id], ncr->msglun); ncr->state = STATE_COMMAND; ncr->cur_bus = BUS_BSY | BUS_REQ; ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); ncr->command_pos = 0; SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); } - } + break; + } ncr->bus_in = bus; } -static void +static void ncr_write(uint16_t port, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; int bus_host = 0; - ncr_log("NCR5380 write(%04x,%02x)\n",port & 7,val); + ncr_log("NCR5380 write(%04x,%02x)\n",port & 7,val); switch (port & 7) { case 0: /* Output data register */ - ncr_log("Write: Output data register\n"); + ncr_log("Write: Output data register, val = %02x\n", val); ncr->output_data = val; break; @@ -570,7 +600,7 @@ ncr_write(uint16_t port, uint8_t val, void *priv) ncr_log("Write: Initiator command register\n"); if ((val & 0x80) && !(ncr->icr & 0x80)) { ncr_log("Resetting the 5380\n"); - ncr_reset(&ncr_dev->ncr); + ncr_reset(ncr_dev, &ncr_dev->ncr); } ncr->icr = val; break; @@ -583,17 +613,35 @@ ncr_write(uint16_t port, uint8_t val, void *priv) } ncr->mode = val; - - /*Don't stop the timer until it finishes the transfer*/ - if (ncr_dev->block_count_loaded && (ncr->mode & MODE_DMA)) - dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); - /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - if (!ncr_dev->block_count_loaded && !(ncr->mode & MODE_DMA)) { - ncr_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; + if (ncr_dev->type == 3) { + /*Don't stop the timer until it finishes the transfer*/ + if (ncr_dev->t128.block_loaded && (ncr->mode & MODE_DMA)) { + ncr_log("Continuing DMA mode\n"); + ncr_timer_on(ncr_dev, ncr, 0); + } + + /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ + if (!ncr_dev->t128.block_loaded && !(ncr->mode & MODE_DMA)) { + ncr_log("No DMA mode\n"); + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } + } else { + /*Don't stop the timer until it finishes the transfer*/ + if (ncr_dev->block_count_loaded && (ncr->mode & MODE_DMA) && !timer_is_enabled(&ncr_dev->timer)) { + ncr_log("Continuing DMA mode\n"); + ncr_timer_on(ncr_dev, ncr, 0); + } + + /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ + if (!ncr_dev->block_count_loaded && !(ncr->mode & MODE_DMA)) { + ncr_log("No DMA mode\n"); + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } } break; @@ -605,21 +653,60 @@ ncr_write(uint16_t port, uint8_t val, void *priv) case 4: /* Select Enable Register */ ncr_log("Write: Select Enable register\n"); break; - + case 5: /* start DMA Send */ ncr_log("Write: start DMA send register\n"); - ncr_log("Write 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_SEND; - dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); + if (ncr_dev->type == 3) { + if (dev->buffer_length > 0) { + memset(ncr_dev->t128.buffer, 0, MIN(512, dev->buffer_length)); + + ncr_log("DMA send timer start, enabled? = %i\n", timer_is_enabled(&ncr_dev->timer)); + ncr_dev->t128.block_count = dev->buffer_length >> 9; + ncr_dev->t128.block_loaded = 1; + + ncr_dev->t128.host_pos = 0; + ncr_dev->t128.status |= 0x04; + } + } else { + if ((ncr->mode & MODE_DMA) && !timer_is_enabled(&ncr_dev->timer)) { + memset(ncr_dev->buffer, 0, MIN(128, dev->buffer_length)); + + ncr_log("DMA send timer on\n"); + ncr_timer_on(ncr_dev, ncr, 0); + } + } break; case 7: /* start DMA Initiator Receive */ - ncr_log("Write: start DMA initiator receive register\n"); - ncr_log("Read 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); + ncr_log("Write: start DMA initiator receive register, dma? = %02x\n", ncr->mode & MODE_DMA); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; - dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); + if (ncr_dev->type == 3) { + ncr_log("DMA receive timer start, enabled? = %i, cdb[0] = %02x, buflen = %i\n", timer_is_enabled(&ncr_dev->timer), ncr->command[0], dev->buffer_length); + if (dev->buffer_length > 0) { + memset(ncr_dev->t128.buffer, 0, MIN(512, dev->buffer_length)); + + ncr_dev->t128.block_count = dev->buffer_length >> 9; + + if (dev->buffer_length < 512) + ncr_dev->t128.block_count = 1; + + ncr_dev->t128.block_loaded = 1; + + ncr_dev->t128.host_pos = MIN(512, dev->buffer_length); + ncr_dev->t128.status |= 0x04; + timer_on_auto(&ncr_dev->timer, 0.02); + } + } else { + if ((ncr->mode & MODE_DMA) && !timer_is_enabled(&ncr_dev->timer)) { + memset(ncr_dev->buffer, 0, MIN(128, dev->buffer_length)); + + ncr_log("DMA receive timer start\n"); + ncr_timer_on(ncr_dev, ncr, 0); + } + } break; default: @@ -627,12 +714,14 @@ ncr_write(uint16_t port, uint8_t val, void *priv) break; } - bus_host = get_bus_host(ncr); - ncr_bus_update(priv, bus_host); + if (ncr->dma_mode == DMA_IDLE || ncr_dev->type == 0 || ncr_dev->type >= 3) { + bus_host = get_bus_host(ncr); + ncr_bus_update(priv, bus_host); + } } -static uint8_t +static uint8_t ncr_read(uint16_t port, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; @@ -645,7 +734,7 @@ ncr_read(uint16_t port, void *priv) ncr_log("Read: Current SCSI data register\n"); if (ncr->icr & ICR_DBP) { /*Return the data from the output register if on data bus phase from ICR*/ - ncr_log("Data Bus Phase\n"); + ncr_log("Data Bus Phase, ret = %02x\n", ncr->output_data); ret = ncr->output_data; } else { /*Return the data from the SCSI bus*/ @@ -657,11 +746,15 @@ ncr_read(uint16_t port, void *priv) case 1: /* Initiator Command Register */ ncr_log("Read: Initiator Command register, NCR ICR Read=%02x\n", ncr->icr); - ret = ncr->icr; break; case 2: /* Mode register */ + if (((ncr->mode & 0x30) == 0x30) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1))) + ncr->mode = 0; + if (((ncr->mode & 0x20) == 0x20) && (ncr_dev->type == 0)) + ncr->mode = 0; + ncr_log("Read: Mode register\n"); ret = ncr->mode; break; @@ -677,42 +770,49 @@ ncr_read(uint16_t port, void *priv) ncr_bus_read(ncr_dev); ncr_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff); ret |= (ncr->cur_bus & 0xff); + if ((ncr->icr & ICR_SEL) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1))) + ret |= 0x02; + if ((ncr->icr & ICR_BSY) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1))) + ret |= 0x40; break; case 5: /* Bus and Status register */ ncr_log("Read: Bus and Status register\n"); - ret = 0; + ret = 0; bus = get_bus_host(ncr); ncr_log("Get host from Interrupt\n"); - + /*Check if the phase in process matches with TCR's*/ if ((bus & SCSI_PHASE_MESSAGE_IN) == (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) { ncr_log("Phase match\n"); ret |= STATUS_PHASE_MATCH; - } else - picint(1 << ncr_dev->irq); + } ncr_bus_read(ncr_dev); bus = ncr->cur_bus; - if (bus & BUS_ACK) + if ((bus & BUS_ACK) || ((ncr->icr & ICR_ACK) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1)))) ret |= STATUS_ACK; - + if ((bus & BUS_ATN) || ((ncr->icr & ICR_ATN) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1)))) + ret |= 0x02; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) { ncr_log("Entering DMA mode\n"); ret |= STATUS_DRQ; - + bus_state = 0; - + if (bus & BUS_IO) bus_state |= TCR_IO; if (bus & BUS_CD) bus_state |= TCR_CD; if (bus & BUS_MSG) bus_state |= TCR_MSG; - if ((ncr->tcr & 7) != bus_state) - ncr->isr |= STATUS_INT; + if ((ncr->tcr & 7) != bus_state) { + ncr_irq(ncr_dev, ncr, 1); + ncr_log("IRQ issued\n"); + } } if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { ncr_log("Busy error\n"); @@ -721,10 +821,14 @@ ncr_read(uint16_t port, void *priv) ret |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); break; + case 6: + ret = ncr->tx_data; + break; + case 7: /* reset Parity/Interrupt */ - ncr->isr &= ~STATUS_INT; - picintc(1 << ncr_dev->irq); - ncr_log("Reset IRQ\n"); + ncr->isr &= ~(STATUS_BUSY_ERROR | 0x20); + ncr_irq(ncr_dev, ncr, 0); + ncr_log("Reset Interrupt\n"); break; default: @@ -739,12 +843,14 @@ ncr_read(uint16_t port, void *priv) /* Memory-mapped I/O READ handler. */ -static uint8_t +static uint8_t memio_read(uint32_t addr, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; uint8_t ret = 0xff; - + addr &= 0x3fff; if (addr < 0x2000) @@ -767,16 +873,16 @@ memio_read(uint32_t addr, void *priv) #endif ret = ncr_read(addr, ncr_dev); break; - + case 0x3900: - if (ncr_dev->buffer_host_pos >= 128 || !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) + if (ncr_dev->buffer_host_pos >= MIN(128, dev->buffer_length) || !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { ret = 0xff; - else { + } else { ret = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; - - if (ncr_dev->buffer_host_pos == 128) { - ncr_log("Not ready\n"); + + if (ncr_dev->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + ncr_log("Transfer busy read, status = %02x\n", ncr_dev->status_ctrl); } } break; @@ -802,7 +908,7 @@ memio_read(uint32_t addr, void *priv) ret = 0xff; break; } - break; + break; } #if ENABLE_NCR5380_LOG @@ -815,14 +921,14 @@ memio_read(uint32_t addr, void *priv) /* Memory-mapped I/O WRITE handler. */ -static void +static void memio_write(uint32_t addr, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; - - addr &= 0x3fff; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; - ncr_log("memio_write(%08x,%02x) %i %02x\n", addr, val, ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); + addr &= 0x3fff; if (addr >= 0x3a00) ncr_dev->ext_ram[addr - 0x3a00] = val; @@ -834,12 +940,14 @@ memio_write(uint32_t addr, uint8_t val, void *priv) case 0x3880: ncr_write(addr, val, ncr_dev); break; - + case 0x3900: - if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR) && ncr_dev->buffer_host_pos < 128) { + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR) && ncr_dev->buffer_host_pos < MIN(128, dev->buffer_length)) { ncr_dev->buffer[ncr_dev->buffer_host_pos++] = val; - if (ncr_dev->buffer_host_pos == 128) { + ncr_log("Write host pos = %i, val = %02x\n", ncr_dev->buffer_host_pos, val); + + if (ncr_dev->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr_dev->ncr_busy = 1; } @@ -850,7 +958,7 @@ memio_write(uint32_t addr, uint8_t val, void *priv) switch (addr) { case 0x3980: /* Control */ if ((val & CTRL_DATA_DIR) && !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { - ncr_dev->buffer_host_pos = 128; + ncr_dev->buffer_host_pos = MIN(128, dev->buffer_length); ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } else if (!(val & CTRL_DATA_DIR) && (ncr_dev->status_ctrl & CTRL_DATA_DIR)) { @@ -861,13 +969,15 @@ memio_write(uint32_t addr, uint8_t val, void *priv) break; case 0x3981: /* block counter register */ - ncr_log("Write block counter register: val=%d\n", val); + ncr_log("Write block counter register: val=%d, dma mode = %i, period = %lf\n", val, ncr->dma_mode, ncr_dev->period); ncr_dev->block_count = val; ncr_dev->block_count_loaded = 1; - set_dma_enable(ncr_dev, ncr_dev->dma_enabled && ncr_dev->block_count_loaded); + + if (ncr->mode & MODE_DMA) + ncr_timer_on(ncr_dev, ncr, 0); if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { - ncr_dev->buffer_host_pos = 128; + ncr_dev->buffer_host_pos = MIN(128, dev->buffer_length); ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } else { ncr_dev->buffer_host_pos = 0; @@ -875,13 +985,13 @@ memio_write(uint32_t addr, uint8_t val, void *priv) } break; } - break; + break; } } /* Memory-mapped I/O READ handler for the Trantor T130B. */ -static uint8_t +static uint8_t t130b_read(uint32_t addr, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; @@ -899,7 +1009,7 @@ t130b_read(uint32_t addr, void *priv) /* Memory-mapped I/O WRITE handler for the Trantor T130B. */ -static void +static void t130b_write(uint32_t addr, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; @@ -911,7 +1021,7 @@ t130b_write(uint32_t addr, uint8_t val, void *priv) } -static uint8_t +static uint8_t t130b_in(uint16_t port, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; @@ -924,8 +1034,8 @@ t130b_in(uint16_t port, void *priv) case 0x04: case 0x05: ret = memio_read(0x3900, ncr_dev); - break; - + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: ret = ncr_read(port, ncr_dev); @@ -937,7 +1047,7 @@ t130b_in(uint16_t port, void *priv) } -static void +static void t130b_out(uint16_t port, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; @@ -951,8 +1061,8 @@ t130b_out(uint16_t port, uint8_t val, void *priv) case 0x04: case 0x05: memio_write(0x3900, val, ncr_dev); - break; - + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: ncr_write(port, val, ncr_dev); @@ -960,152 +1070,252 @@ t130b_out(uint16_t port, uint8_t val, void *priv) } } +static void +ncr_dma_send(ncr5380_t *ncr_dev, ncr_t *ncr, scsi_device_t *dev) +{ + int bus, c = 0; + uint8_t data; + + if (scsi_device_get_callback(dev) > 0.0) + ncr_timer_on(ncr_dev, ncr, 1); + else + ncr_timer_on(ncr_dev, ncr, 0); + + for (c = 0; c < 10; c++) { + ncr_bus_read(ncr_dev); + if (ncr->cur_bus & BUS_REQ) + break; + } + + /* Data ready. */ + if (ncr_dev->type == 3) + data = ncr_dev->t128.buffer[ncr_dev->t128.pos]; + else + data = ncr_dev->buffer[ncr_dev->buffer_pos]; + bus = get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(data); + + ncr_bus_update(ncr_dev, bus | BUS_ACK); + ncr_bus_update(ncr_dev, bus & ~BUS_ACK); + + if (ncr_dev->type == 3) { + ncr_dev->t128.pos++; + ncr_log("Buffer pos for writing = %d, data = %02x\n", ncr_dev->t128.pos, data); + + if (ncr_dev->t128.pos == MIN(512, dev->buffer_length)) { + ncr_dev->t128.pos = 0; + ncr_dev->t128.host_pos = 0; + ncr_dev->t128.status &= ~0x02; + ncr_dev->t128.block_count = (ncr_dev->t128.block_count - 1) & 0xff; + ncr_log("Remaining blocks to be written=%d\n", ncr_dev->t128.block_count); + if (!ncr_dev->t128.block_count) { + ncr_dev->t128.block_loaded = 0; + ncr_log("IO End of write transfer\n"); + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + timer_stop(&ncr_dev->timer); + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr_log("NCR write irq\n"); + ncr_irq(ncr_dev, ncr, 1); + } + } + return; + } + } else { + ncr_dev->buffer_pos++; + ncr_log("Buffer pos for writing = %d\n", ncr_dev->buffer_pos); + + if (ncr_dev->buffer_pos == MIN(128, dev->buffer_length)) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->ncr_busy = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 0xff; + ncr_log("Remaining blocks to be written=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of write transfer\n"); + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + timer_stop(&ncr_dev->timer); + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr_log("NCR write irq\n"); + ncr_irq(ncr_dev, ncr, 1); + } + } + return; + } + } + ncr_dma_send(ncr_dev, ncr, dev); +} + +static void +ncr_dma_initiator_receive(ncr5380_t *ncr_dev, ncr_t *ncr, scsi_device_t *dev) +{ + int bus, c = 0; + uint8_t temp; + + if (scsi_device_get_callback(dev) > 0.0) { + ncr_timer_on(ncr_dev, ncr, 1); + } else { + ncr_timer_on(ncr_dev, ncr, 0); + } + + for (c = 0; c < 10; c++) { + ncr_bus_read(ncr_dev); + if (ncr->cur_bus & BUS_REQ) + break; + } + + /* Data ready. */ + ncr_bus_read(ncr_dev); + temp = BUS_GETDATA(ncr->cur_bus); + + bus = get_bus_host(ncr); + + ncr_bus_update(ncr_dev, bus | BUS_ACK); + ncr_bus_update(ncr_dev, bus & ~BUS_ACK); + + if (ncr_dev->type == 3) { + ncr_dev->t128.buffer[ncr_dev->t128.pos++] = temp; + ncr_log("Buffer pos for reading = %d, temp = %02x\n", ncr_dev->t128.pos, temp); + + if (ncr_dev->t128.pos == MIN(512, dev->buffer_length)) { + ncr_dev->t128.pos = 0; + ncr_dev->t128.host_pos = 0; + ncr_dev->t128.status &= ~0x02; + ncr_dev->t128.block_count = (ncr_dev->t128.block_count - 1) & 0xff; + ncr_log("Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", ncr_dev->t128.block_count, ncr_dev->t128.status, dev->buffer_length, ncr->command[0]); + if (!ncr_dev->t128.block_count) { + ncr_dev->t128.block_loaded = 0; + ncr_log("IO End of read transfer\n"); + ncr->isr |= STATUS_END_OF_DMA; + timer_stop(&ncr_dev->timer); + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr_log("NCR read irq\n"); + ncr_irq(ncr_dev, ncr, 1); + } + } + return; + } + } else { + ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; + ncr_log("Buffer pos for reading = %d\n", ncr_dev->buffer_pos); + + if (ncr_dev->buffer_pos == MIN(128, dev->buffer_length)) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 0xff; + ncr_log("Remaining blocks to be read=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of read transfer\n"); + ncr->isr |= STATUS_END_OF_DMA; + timer_stop(&ncr_dev->timer); + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr_log("NCR read irq\n"); + ncr_irq(ncr_dev, ncr, 1); + } + } + return; + } + } + ncr_dma_initiator_receive(ncr_dev, ncr, dev); +} static void ncr_callback(void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; ncr_t *ncr = &ncr_dev->ncr; - int bus, bt = 0, c = 0; - uint8_t temp, data; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; - ncr_log("DMA mode=%d\n", ncr->dma_mode); - - if (ncr->data_wait & 1) - ncr->clear_req = 3; - - if (ncr->dma_mode != DMA_IDLE) - dma_timer_on(ncr_dev); + if (ncr_dev->type == 3) { + ncr_log("DMA Callback, load = %i\n", ncr_dev->t128.block_loaded); + if (ncr->dma_mode != DMA_IDLE && (ncr->mode & MODE_DMA) && ncr_dev->t128.block_loaded) { + ncr_log("Timer on! Host POS = %i, status = %02x, DMA mode = %i, Period = %lf\n", ncr_dev->t128.host_pos, ncr_dev->t128.status, ncr->dma_mode, scsi_device_get_callback(dev)); + if (ncr_dev->t128.host_pos == MIN(512, dev->buffer_length) && ncr_dev->t128.block_count) { + ncr_dev->t128.status |= 0x04; + } + ncr_timer_on(ncr_dev, ncr, 0); + } + } else { + ncr_log("DMA mode=%d, status ctrl = %02x\n", ncr->dma_mode, ncr_dev->status_ctrl); + if (ncr->dma_mode != DMA_IDLE && (ncr->mode & MODE_DMA) && ncr_dev->block_count_loaded) { + ncr_timer_on(ncr_dev, ncr, 0); + } + } if (ncr->data_wait & 1) { + ncr->clear_req = 3; ncr->data_wait &= ~1; - if (ncr->dma_mode == DMA_IDLE) + if (ncr->dma_mode == DMA_IDLE) { return; + } } switch(ncr->dma_mode) { case DMA_SEND: - if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { - ncr_log("DMA_SEND with DMA direction set wrong\n"); - break; - } - - ncr_log("Status for writing=%02x\n", ncr_dev->status_ctrl); - - if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) { - ncr_log("Buffer ready\n"); - break; - } - - if (!ncr_dev->block_count_loaded) - break; - - while (bt < 64) { - for (c = 0; c < 10; c++) { - ncr_bus_read(ncr_dev); - if (ncr->cur_bus & BUS_REQ) - break; - } - - if (c == 10) - break; - - /* Data ready. */ - data = ncr_dev->buffer[ncr_dev->buffer_pos]; - bus = get_bus_host(ncr) & ~BUS_DATAMASK; - bus |= BUS_SETDATA(data); - - ncr_bus_update(priv, bus | BUS_ACK); - ncr_bus_update(priv, bus & ~BUS_ACK); - - bt++; - ncr_dev->buffer_pos++; - ncr_log("Buffer pos for writing = %d\n", ncr_dev->buffer_pos); - - if (ncr_dev->buffer_pos == 128) { - ncr_dev->buffer_pos = 0; - ncr_dev->buffer_host_pos = 0; - ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; - ncr_dev->ncr_busy = 0; - ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; - ncr_log("Remaining blocks to be written=%d\n", ncr_dev->block_count); - if (!ncr_dev->block_count) { - ncr_dev->block_count_loaded = 0; - set_dma_enable(ncr_dev, 0); - ncr_log("IO End of write transfer\n"); - - ncr->tcr |= TCR_LAST_BYTE_SENT; - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) { - ncr_log("NCR write irq\n"); - ncr->isr |= STATUS_INT; - picint(1 << ncr_dev->irq); - } - } + if (ncr_dev->type != 3) { + if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { + ncr_log("DMA_SEND with DMA direction set wrong\n"); break; } + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) { + ncr_log("Write buffer status ready\n"); + break; + } + + if (!ncr_dev->block_count_loaded) + break; + } else { + if (!(ncr_dev->t128.status & 0x04)) { + ncr_log("Write status busy\n"); + break; + } + + if (!ncr_dev->t128.block_loaded) { + ncr_log("Write block not loaded\n"); + break; + } + + if (ncr_dev->t128.host_pos < MIN(512, dev->buffer_length)) + break; } + ncr_dma_send(ncr_dev, ncr, dev); break; case DMA_INITIATOR_RECEIVE: - if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { - ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); - break; + if (ncr_dev->type != 3) { + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + break; + } + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) { + ncr_log("Read buffer status ready\n"); + break; + } + + if (!ncr_dev->block_count_loaded) + break; + } else { + if (!(ncr_dev->t128.status & 0x04)) { + ncr_log("Read status busy, block count = %i, host pos = %i\n", ncr_dev->t128.block_count, ncr_dev->t128.host_pos); + break; + } + + if (!ncr_dev->t128.block_loaded) { + ncr_log("Read block not loaded\n"); + break; + } + + if (ncr_dev->t128.host_pos < MIN(512, dev->buffer_length)) + break; } - - ncr_log("Status for reading=%02x\n", ncr_dev->status_ctrl); - - if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) - break; - - if (!ncr_dev->block_count_loaded) - break; - - while (bt < 64) { - for (c = 0; c < 10; c++) { - ncr_bus_read(ncr_dev); - if (ncr->cur_bus & BUS_REQ) - break; - } - - if (c == 10) - break; - - /* Data ready. */ - ncr_bus_read(ncr_dev); - temp = BUS_GETDATA(ncr->cur_bus); - - bus = get_bus_host(ncr); - - ncr_bus_update(priv, bus | BUS_ACK); - ncr_bus_update(priv, bus & ~BUS_ACK); - - ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; - bt++; - - if (ncr_dev->buffer_pos == 128) { - ncr_dev->buffer_pos = 0; - ncr_dev->buffer_host_pos = 0; - ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; - ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; - - ncr_log("Remaining blocks to be read=%d\n", ncr_dev->block_count); - - if (!ncr_dev->block_count) { - ncr_dev->block_count_loaded = 0; - set_dma_enable(ncr_dev, 0); - ncr_log("IO End of read transfer\n"); - - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) { - ncr_log("NCR read irq\n"); - ncr->isr |= STATUS_INT; - picint(1 << ncr_dev->irq); - } - } - break; - } - } + ncr_dma_initiator_receive(ncr_dev, ncr, dev); break; } @@ -1115,15 +1325,179 @@ ncr_callback(void *priv) ncr_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; ncr->dma_mode = DMA_IDLE; - dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); + timer_on_auto(&ncr_dev->timer, 10.0); } } +static uint8_t +t128_read(uint32_t addr, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; + uint8_t ret = 0xff; + + addr &= 0x3fff; + if (addr >= 0 && addr < 0x1800) + ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; + else if (addr >= 0x1800 && addr < 0x1880) + ret = ncr_dev->t128.ext_ram[addr & 0x7f]; + else if (addr >= 0x1c00 && addr < 0x1c20) { + ret = ncr_dev->t128.ctrl; + } else if (addr >= 0x1c20 && addr < 0x1c40) { + ret = ncr_dev->t128.status; + ncr_log("T128 status read = %02x, cur bus = %02x, req = %02x, dma = %02x\n", ret, ncr->cur_bus, ncr->cur_bus & BUS_REQ, ncr->mode & MODE_DMA); + } else if (addr >= 0x1d00 && addr < 0x1e00) { + if (addr >= 0x1d00 && addr < 0x1d20) + ret = ncr_read(0, ncr_dev); + else if (addr >= 0x1d20 && addr < 0x1d40) + ret = ncr_read(1, ncr_dev); + else if (addr >= 0x1d40 && addr < 0x1d60) + ret = ncr_read(2, ncr_dev); + else if (addr >= 0x1d60 && addr < 0x1d80) + ret = ncr_read(3, ncr_dev); + else if (addr >= 0x1d80 && addr < 0x1da0) + ret = ncr_read(4, ncr_dev); + else if (addr >= 0x1da0 && addr < 0x1dc0) + ret = ncr_read(5, ncr_dev); + else if (addr >= 0x1dc0 && addr < 0x1de0) + ret = ncr_read(6, ncr_dev); + else if (addr >= 0x1de0 && addr < 0x1e00) + ret = ncr_read(7, ncr_dev); + } else if (addr >= 0x1e00 && addr < 0x2000) { + if (ncr_dev->t128.host_pos >= MIN(512, dev->buffer_length) || ncr->dma_mode != DMA_INITIATOR_RECEIVE) { + ret = 0xff; + } else { + ret = ncr_dev->t128.buffer[ncr_dev->t128.host_pos++]; + + ncr_log("Read transfer, addr = %i, pos = %i\n", addr & 0x1ff, ncr_dev->t128.host_pos); + + if (ncr_dev->t128.host_pos == MIN(512, dev->buffer_length)) { + ncr_dev->t128.status &= ~0x04; + ncr_log("Transfer busy read, status = %02x, period = %lf\n", ncr_dev->t128.status, ncr_dev->period); + if (ncr_dev->period == 0.2 || ncr_dev->period == 0.02) + timer_on_auto(&ncr_dev->timer, 40.2); + } else if (ncr_dev->t128.host_pos < MIN(512, dev->buffer_length) && scsi_device_get_callback(dev) > 100.0) + cycles += 100; /*Needed to avoid timer de-syncing with transfers.*/ + } + } + + return(ret); +} + +static void +t128_write(uint32_t addr, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &scsi_devices[ncr_dev->bus][ncr->target_id]; + + addr &= 0x3fff; + if (addr >= 0x1800 && addr < 0x1880) + ncr_dev->t128.ext_ram[addr & 0x7f] = val; + else if (addr >= 0x1c00 && addr < 0x1c20) { + if ((val & 0x02) && !(ncr_dev->t128.ctrl & 0x02)) { + ncr_dev->t128.status |= 0x02; + ncr_log("Timer fired\n"); + } + ncr_dev->t128.ctrl = val; + ncr_log("T128 ctrl write = %02x\n", val); + } else if (addr >= 0x1d00 && addr < 0x1e00) { + if (addr >= 0x1d00 && addr < 0x1d20) + ncr_write(0, val, ncr_dev); + else if (addr >= 0x1d20 && addr < 0x1d40) + ncr_write(1, val, ncr_dev); + else if (addr >= 0x1d40 && addr < 0x1d60) + ncr_write(2, val, ncr_dev); + else if (addr >= 0x1d60 && addr < 0x1d80) + ncr_write(3, val, ncr_dev); + else if (addr >= 0x1d80 && addr < 0x1da0) + ncr_write(4, val, ncr_dev); + else if (addr >= 0x1da0 && addr < 0x1dc0) + ncr_write(5, val, ncr_dev); + else if (addr >= 0x1dc0 && addr < 0x1de0) + ncr_write(6, val, ncr_dev); + else if (addr >= 0x1de0 && addr < 0x1e00) + ncr_write(7, val, ncr_dev); + } else if (addr >= 0x1e00 && addr < 0x2000) { + if (ncr_dev->t128.host_pos < MIN(512, dev->buffer_length) && ncr->dma_mode == DMA_SEND) { + ncr_dev->t128.buffer[ncr_dev->t128.host_pos] = val; + ncr_dev->t128.host_pos++; + + ncr_log("Write transfer, addr = %i, pos = %i, val = %02x\n", addr & 0x1ff, ncr_dev->t128.host_pos, val); + + if (ncr_dev->t128.host_pos == MIN(512, dev->buffer_length)) { + ncr_dev->t128.status &= ~0x04; + ncr_log("Transfer busy write, status = %02x\n", ncr_dev->t128.status); + timer_on_auto(&ncr_dev->timer, 0.02); + } + } else + ncr_log("Write PDMA addr = %i, val = %02x\n", addr & 0x1ff, val); + } +} + +static uint8_t +rt1000b_mc_read(int port, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + return(ncr_dev->pos_regs[port & 7]); +} + + +static void +rt1000b_mc_write(int port, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + mem_mapping_disable(&ncr_dev->bios_rom.mapping); + mem_mapping_disable(&ncr_dev->mapping); + + /* Save the MCA register value. */ + ncr_dev->pos_regs[port & 7] = val; + + if (ncr_dev->pos_regs[2] & 1) { + switch (ncr_dev->pos_regs[2] & 0xe0) { + case 0: + ncr_dev->rom_addr = 0xd4000; + break; + case 0x20: + ncr_dev->rom_addr = 0xd0000; + break; + case 0x40: + ncr_dev->rom_addr = 0xcc000; + break; + case 0x60: + ncr_dev->rom_addr = 0xc8000; + break; + case 0xc0: + ncr_dev->rom_addr = 0xdc000; + break; + case 0xe0: + ncr_dev->rom_addr = 0xd8000; + break; + } + + mem_mapping_set_addr(&ncr_dev->bios_rom.mapping, ncr_dev->rom_addr, 0x4000); + mem_mapping_set_addr(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000); + } +} + +static uint8_t +rt1000b_mc_feedb(void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + return ncr_dev->pos_regs[2] & 1; +} static void * ncr_init(const device_t *info) { - wchar_t *fn = NULL; + char *fn = NULL; char temp[128]; ncr5380_t *ncr_dev; @@ -1132,6 +1506,8 @@ ncr_init(const device_t *info) ncr_dev->name = info->name; ncr_dev->type = info->local; + ncr_dev->bus = scsi_get_bus(); + switch(ncr_dev->type) { case 0: /* Longshine LCS6821N */ ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); @@ -1139,29 +1515,43 @@ ncr_init(const device_t *info) rom_init(&ncr_dev->bios_rom, LCS6821N_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); break; - case 1: /* Rancho RT1000B */ + case 1: /* Rancho RT1000B/MC */ ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); ncr_dev->irq = device_get_config_int("irq"); ncr_dev->bios_ver = device_get_config_int("bios_ver"); - + if (info->flags & DEVICE_MCA) { + ncr_dev->rom_addr = 0xd8000; + ncr_dev->bios_ver = 1; + } + if (ncr_dev->bios_ver == 1) fn = RT1000B_820R_ROM; else fn = RT1000B_810R_ROM; - + rom_init(&ncr_dev->bios_rom, fn, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, - memio_read, NULL, NULL, - memio_write, NULL, NULL, - ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); + if (info->flags & DEVICE_MCA) { + mem_mapping_add(&ncr_dev->mapping, 0, 0, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); + ncr_dev->pos_regs[0] = 0x8d; + ncr_dev->pos_regs[1] = 0x70; + mca_add(rt1000b_mc_read, rt1000b_mc_write, rt1000b_mc_feedb, NULL, ncr_dev); + } else { + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); + } break; case 2: /* Trantor T130B */ @@ -1173,7 +1563,7 @@ ncr_init(const device_t *info) rom_init(&ncr_dev->bios_rom, T130B_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, t130b_read, NULL, NULL, t130b_write, NULL, NULL, ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); @@ -1182,6 +1572,33 @@ ncr_init(const device_t *info) io_sethandler(ncr_dev->base, 16, t130b_in,NULL,NULL, t130b_out,NULL,NULL, ncr_dev); break; + + case 3: /* Trantor T128 */ + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->irq = device_get_config_int("irq"); + ncr_dev->t128.bios_enabled = device_get_config_int("boot"); + + if (ncr_dev->t128.bios_enabled) + rom_init(&ncr_dev->bios_rom, T128_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + t128_read, NULL, NULL, + t128_write, NULL, NULL, + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); + break; + + case 4: /* Corel LS2000 */ + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->irq = device_get_config_int("irq"); + rom_init(&ncr_dev->bios_rom, COREL_LS2000_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); + break; } sprintf(temp, "%s: BIOS=%05X", ncr_dev->name, ncr_dev->rom_addr); @@ -1191,17 +1608,24 @@ ncr_init(const device_t *info) sprintf(&temp[strlen(temp)], " IRQ=%d", ncr_dev->irq); ncr_log("%s\n", temp); - ncr_reset(&ncr_dev->ncr); - ncr_dev->status_ctrl = STATUS_BUFFER_NOT_READY; - ncr_dev->buffer_host_pos = 128; + ncr_reset(ncr_dev, &ncr_dev->ncr); + if (ncr_dev->type < 3 || ncr_dev->type == 4) { + ncr_dev->status_ctrl = STATUS_BUFFER_NOT_READY; + ncr_dev->buffer_host_pos = 128; + } else { + ncr_dev->t128.status = 0x04; + ncr_dev->t128.host_pos = 512; - timer_add(&ncr_dev->timer, ncr_callback, ncr_dev, 0); + if (!ncr_dev->t128.bios_enabled) + ncr_dev->t128.status |= 0x80; + } + timer_add(&ncr_dev->timer, ncr_callback, ncr_dev, 0); return(ncr_dev); } -static void +static void ncr_close(void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; @@ -1229,205 +1653,315 @@ rt1000b_available(void) return(rom_present(RT1000B_820R_ROM) && rom_present(RT1000B_810R_ROM)); } +static int +rt1000b_820_available(void) +{ + return(rom_present(RT1000B_820R_ROM)); +} + static int t130b_available(void) { return(rom_present(T130B_ROM)); } +static int +t128_available(void) +{ + return(rom_present(T128_ROM)); +} +static int +corel_ls2000_available(void) +{ + return(rom_present(COREL_LS2000_ROM)); +} + +// clang-format off static const device_config_t ncr5380_mmio_config[] = { - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, - { - { - "C800H", 0xc8000 - }, - { - "CC00H", 0xcc000 - }, - { - "D800H", 0xd8000 - }, - { - "DC00H", 0xdc000 - }, - { - "" - } - }, - + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD8000, + .file_filter = "", + .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 = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "" - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t rancho_config[] = { - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, - { - { - "C800H", 0xc8000 - }, - { - "CC00H", 0xcc000 - }, - { - "D800H", 0xd8000 - }, - { - "DC00H", 0xdc000 - }, - { - "" - } - }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD8000, + .file_filter = "", + .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 = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + }, + { + .name = "bios_ver", + .description = "BIOS Version", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "8.20R", .value = 1 }, + { .description = "8.10R", .value = 0 }, + { .description = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +static const device_config_t rancho_mc_config[] = { + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "" - } - }, - }, - { - "bios_ver", "BIOS Version", CONFIG_SELECTION, "", 1, - { - { - "8.20R", 1 - }, - { - "8.10R", 0 - }, - { - "" - } - }, - }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t t130b_config[] = { - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, - { - { - "Disabled", 0 - }, - { - "C800H", 0xc8000 - }, - { - "CC00H", 0xcc000 - }, - { - "D800H", 0xd8000 - }, - { - "DC00H", 0xdc000 - }, - { - "" - } - }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD8000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "" } }, - { - "base", "Address", CONFIG_HEX16, "", 0x0350, - { - { - "240H", 0x0240 - }, - { - "250H", 0x0250 - }, - { - "340H", 0x0340 - }, - { - "350H", 0x0350 - }, - { - "" - } - }, + }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0350, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "240H", .value = 0x0240 }, + { .description = "250H", .value = 0x0250 }, + { .description = "340H", .value = 0x0340 }, + { .description = "350H", .value = 0x0350 }, + { .description = "" } }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "" - } - }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } }; +static const device_config_t t128_config[] = { + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xD8000, + .file_filter = "", + .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 = "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner ={ 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + }, + { + .name = "boot", + .description = "Enable Boot ROM", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on -const device_t scsi_lcs6821n_device = -{ - "Longshine LCS-6821N", - DEVICE_ISA, - 0, - ncr_init, ncr_close, NULL, - lcs6821n_available, - NULL, NULL, - ncr5380_mmio_config +const device_t scsi_lcs6821n_device = { + .name = "Longshine LCS-6821N", + .internal_name = "lcs6821n", + .flags = DEVICE_ISA, + .local = 0, + .init = ncr_init, + .close = ncr_close, + .reset = NULL, + { .available = lcs6821n_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ncr5380_mmio_config }; -const device_t scsi_rt1000b_device = -{ - "Rancho RT1000B", - DEVICE_ISA, - 1, - ncr_init, ncr_close, NULL, - rt1000b_available, - NULL, NULL, - rancho_config +const device_t scsi_rt1000b_device = { + .name = "Rancho RT1000B", + .internal_name = "rt1000b", + .flags = DEVICE_ISA, + .local = 1, + .init = ncr_init, + .close = ncr_close, + .reset = NULL, + { .available = rt1000b_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = rancho_config }; -const device_t scsi_t130b_device = -{ - "Trantor T130B", - DEVICE_ISA, - 2, - ncr_init, ncr_close, NULL, - t130b_available, - NULL, NULL, - t130b_config +const device_t scsi_rt1000mc_device = { + .name = "Rancho RT1000B-MC", + .internal_name = "rt1000mc", + .flags = DEVICE_MCA, + .local = 1, + .init = ncr_init, + .close = ncr_close, + .reset = NULL, + { .available = rt1000b_820_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = rancho_mc_config +}; + +const device_t scsi_t130b_device = { + .name = "Trantor T130B", + .internal_name = "t130b", + .flags = DEVICE_ISA, + .local = 2, + .init = ncr_init, + .close = ncr_close, + .reset = NULL, + { .available = t130b_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = t130b_config +}; + +const device_t scsi_t128_device = { + .name = "Trantor T128", + .internal_name = "t128", + .flags = DEVICE_ISA, + .local = 3, + .init = ncr_init, + .close = ncr_close, + .reset = NULL, + { .available = t128_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = t128_config +}; + +const device_t scsi_ls2000_device = { + .name = "Corel LS2000", + .internal_name = "ls2000", + .flags = DEVICE_ISA, + .local = 4, + .init = ncr_init, + .close = ncr_close, + .reset = NULL, + { .available = corel_ls2000_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ncr5380_mmio_config }; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index d9c06a33f..999948648 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -10,9 +10,6 @@ * Adapters made by NCR and later Symbios and LSI. These * controllers were designed for the PCI bus. * - * To do: Identify the type of serial EEPROM used and its - * interface. - * * * * Authors: Paul Brook (QEMU) @@ -43,18 +40,28 @@ #include <86box/device.h> #include <86box/nvr.h> #include <86box/plat.h> +#include <86box/i2c.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/scsi_ncr53c8xx.h> -#define NCR53C8XX_ROM L"roms/scsi/ncr53c8xx/NCR307.BIN" + +#define NCR53C8XX_SDMS3_ROM "roms/scsi/ncr53c8xx/NCR307.BIN" +#define SYM53C8XX_SDMS4_ROM "roms/scsi/ncr53c8xx/8xx_64.rom" #define HA_ID 7 #define CHIP_810 0x01 +#define CHIP_820 0x02 #define CHIP_825 0x03 +#define CHIP_815 0x04 +#define CHIP_810AP 0x05 #define CHIP_860 0x06 +#define CHIP_895 0x0c #define CHIP_875 0x0f +#define CHIP_895A 0x12 +#define CHIP_875A 0x13 +#define CHIP_875J 0x8f #define NCR_SCNTL0_TRG 0x01 #define NCR_SCNTL0_AAP 0x02 @@ -178,6 +185,7 @@ /* Flag set if this is a tagged command. */ #define NCR_TAG_VALID (1 << 16) +#define NCR_NVRAM_SIZE 2048 #define NCR_BUF_SIZE 4096 typedef struct ncr53c8xx_request { @@ -199,9 +207,9 @@ typedef enum } scsi_state_t; typedef struct { - wchar_t *nvr_path; + char *nvr_path; uint8_t pci_slot; - uint8_t chip; + uint8_t chip, wide; int has_bios; int BIOSBase; rom_t bios; @@ -218,15 +226,9 @@ typedef struct { int msg_action; int msg_len; uint8_t msg[NCR_MAX_MSGIN_LEN]; -#ifdef USE_NVRAM - uint16_t nvram; - uint8_t nvram_t; - uint8_t nvram_op; - uint8_t nvram_param; - uint8_t nvram_start; - uint8_t nvram_index; -#endif - uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ + uint8_t nvram[NCR_NVRAM_SIZE]; /* 24C16 EEPROM (16 Kbit) */ + void *i2c, *eeprom; + uint8_t ram[NCR_BUF_SIZE]; /* NCR 53C875 RAM (4 KB) */ /* 0 if SCRIPTS are running or stopped. * 1 if a Wait Reselect instruction has been issued. * 2 if processing DMA from ncr53c8xx_execute_script. @@ -284,7 +286,7 @@ typedef struct { ncr53c8xx_request *current; int irq; - + uint32_t dsa; uint32_t temp; uint32_t dnad; @@ -304,6 +306,10 @@ typedef struct { uint8_t regop; uint32_t adder; + uint32_t bios_mask; + + uint8_t bus; + pc_timer_t timer; #ifdef USE_WDTR @@ -402,7 +408,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev) dev->scntl0 = 0xc0; dev->scntl1 = 0; dev->scntl2 = 0; - if (dev->chip >= CHIP_825) + if (dev->wide) dev->scntl3 = 8; else dev->scntl3 = 0; @@ -427,19 +433,16 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev) dev->gpreg = 0; dev->slpar = 0; dev->sstop = 1; - dev->gpcntl = 0x0f; -#ifdef USE_NVRAM - dev->nvram_t = dev->nvram_index = 0; -#endif + dev->gpcntl = 0x03; - if (dev->chip >= CHIP_825) { + if (dev->wide) { /* This *IS* a wide SCSI controller, so reset all SCSI devices. */ for (i = 0; i < 16; i++) { #ifdef USE_WDTR dev->tr_set[i] = 0; #endif - scsi_device_reset(&scsi_devices[i]); + scsi_device_reset(&scsi_devices[dev->bus][i]); } } else { /* This is *NOT* a wide SCSI controller, so do not touch @@ -448,7 +451,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev) #ifdef USE_WDTR dev->tr_set[i] = 0; #endif - scsi_device_reset(&scsi_devices[i]); + scsi_device_reset(&scsi_devices[dev->bus][i]); } } } @@ -467,7 +470,7 @@ ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) buf[i] = inb((uint16_t) (addr + i)); } else { ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr); - dma_bm_read(addr, buf, len, 4); + dma_bm_read(addr, buf, len, 4); } } @@ -485,7 +488,7 @@ ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) outb((uint16_t) (addr + i), buf[i]); } else { ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr); - dma_bm_write(addr, buf, len, 4); + dma_bm_write(addr, buf, len, 4); } } @@ -504,10 +507,10 @@ static void do_irq(ncr53c8xx_t *dev, int level) { if (level) { - pci_set_irq(dev->pci_slot, PCI_INTA); + pci_set_irq(dev->pci_slot, PCI_INTA); ncr53c8xx_log("Raising IRQ...\n"); } else { - pci_clear_irq(dev->pci_slot, PCI_INTA); + pci_clear_irq(dev->pci_slot, PCI_INTA); ncr53c8xx_log("Lowering IRQ...\n"); } } @@ -610,10 +613,15 @@ ncr53c8xx_bad_phase(ncr53c8xx_t *dev, int out, int new_phase) static void ncr53c8xx_disconnect(ncr53c8xx_t *dev) { + scsi_device_t *sd; + + sd = &scsi_devices[dev->bus][dev->sdid]; + dev->scntl1 &= ~NCR_SCNTL1_CON; dev->sstat1 &= ~PHASE_MASK; if (dev->dcmd & 0x01) /* Select with ATN */ dev->sstat1 |= 0x07; + scsi_device_identify(sd, SCSI_LUN_USE_CDB); } @@ -632,11 +640,11 @@ ncr53c8xx_command_complete(void *priv, uint32_t status) { ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; int out; - + out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); dev->status = status; - dev->command_complete = 2; + dev->command_complete = 2; if (dev->waiting && dev->dbc != 0) { /* Raise phase mismatch for short transfers. */ ncr53c8xx_bad_phase(dev, out, PHASE_ST); @@ -653,13 +661,13 @@ ncr53c8xx_do_dma(ncr53c8xx_t *dev, int out, uint8_t id) uint32_t addr, tdbc; int count; - scsi_device_t *sd = &scsi_devices[id]; + scsi_device_t *sd = &scsi_devices[dev->bus][id]; if ((!scsi_device_present(sd))) { ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); return; } - + if (!dev->current->dma_len) { /* Wait until data is available. */ ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); @@ -691,7 +699,7 @@ ncr53c8xx_do_dma(ncr53c8xx_t *dev, int out, uint8_t id) dev->buffer_pos += count; if (dev->temp_buf_len <= 0) { - scsi_device_command_phase1(&scsi_devices[id]); + scsi_device_command_phase1(&scsi_devices[dev->bus][id]); #ifdef ENABLE_NCR53C8XX_LOG if (out) ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); @@ -744,13 +752,13 @@ ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) dev->sfbr = buf[0]; dev->command_complete = 0; - sd = &scsi_devices[id]; - if (!scsi_device_present(sd)) { + sd = &scsi_devices[dev->bus][id]; + if (!scsi_device_present(sd) || (dev->current_lun > 0)) { ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); ncr53c8xx_bad_selection(dev, id); return 0; } - + dev->current = (ncr53c8xx_request*)malloc(sizeof(ncr53c8xx_request)); dev->current->tag = id; @@ -763,7 +771,7 @@ ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) if ((buf[1] & 0xe0) != (dev->current_lun << 5)) buf[1] = (buf[1] & 0x1f) | (dev->current_lun << 5); - scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf); + scsi_device_command_phase0(&scsi_devices[dev->bus][dev->current->tag], buf); dev->hba_private = (void *)dev->current; dev->waiting = 0; @@ -779,12 +787,12 @@ ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); ncr53c8xx_set_phase(dev, PHASE_DI); - ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->bus][dev->current->tag])); return 1; } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); ncr53c8xx_set_phase(dev, PHASE_DO); - ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->bus][dev->current->tag])); return 1; } else { ncr53c8xx_command_complete(dev, sd->status); @@ -845,8 +853,8 @@ ncr53c8xx_do_msgin(ncr53c8xx_t *dev) switch to PHASE_MO. */ switch (dev->msg_action) { case 0: - ncr53c8xx_set_phase(dev, PHASE_CMD); - break; + ncr53c8xx_set_phase(dev, PHASE_CMD); + break; case 1: ncr53c8xx_disconnect(dev); break; @@ -907,7 +915,7 @@ ncr53c8xx_do_msgout(ncr53c8xx_t *dev, uint8_t id) #endif scsi_device_t *sd; - sd = &scsi_devices[id]; + sd = &scsi_devices[dev->bus][id]; #ifdef ENABLE_NCR53C8XX_LOG current_tag = id; @@ -996,6 +1004,7 @@ ncr53c8xx_do_msgout(ncr53c8xx_t *dev, uint8_t id) /* 0x80 to 0xff are IDENTIFY messages. */ ncr53c8xx_log("MSG: Identify\n"); dev->current_lun = msg & 7; + scsi_device_identify(sd, msg & 7); ncr53c8xx_log("Select LUN %d\n", dev->current_lun); #ifdef USE_WDTR if ((dev->chip == CHIP_875) && !dev->tr_set[dev->sdid]) @@ -1059,7 +1068,7 @@ again: dev->dsps = addr; dev->dcmd = insn >> 24; dev->dsp += 8; - + switch (insn >> 30) { case 0: /* Block move. */ ncr53c8xx_log("00: Block move\n"); @@ -1162,7 +1171,7 @@ again: } dev->sstat0 |= NCR_SSTAT0_WOA; dev->scntl1 &= ~NCR_SCNTL1_IARB; - if (!scsi_device_present(&scsi_devices[id])) { + if (!scsi_device_present(&scsi_devices[dev->bus][id])) { ncr53c8xx_bad_selection(dev, id); break; } @@ -1437,7 +1446,7 @@ ncr53c8xx_callback(void *p) if (dev->waiting) timer_on_auto(&dev->timer, 40.0); else - ncr53c8xx_process_script(dev); + ncr53c8xx_process_script(dev); } if (dev->sstop) @@ -1445,146 +1454,22 @@ ncr53c8xx_callback(void *p) } -#ifdef USE_NVRAM static void -ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) +ncr53c8xx_eeprom(ncr53c8xx_t *dev, uint8_t save) { FILE *f; - if (save) - f = nvr_fopen(dev->nvr_path, L"wb"); - else - f = nvr_fopen(dev->nvr_path, L"rb"); - if (f) - { - if (save) { - fwrite((uint8_t *) &dev->nvram, 1, 1, f); - fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f); - } else { - fread((uint8_t *) &dev->nvram, 1, 1, f); - fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f); - } + f = nvr_fopen(dev->nvr_path, save ? "wb": "rb"); + if (f) { + if (save) + fwrite(&dev->nvram, sizeof(dev->nvram), 1, f); + else + fread(&dev->nvram, sizeof(dev->nvram), 1, f); fclose(f); - f = NULL; } } -#define ADDRESS_LENGTH 9 -#define ADDRESS_END (ADDRESS_LENGTH + 2) -#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2) -#define ADDRESS_MASK 0x3f -#define DATA_LENGTH 8 -#define DATA_START (ADDRESS_END + 1) -#define DATA_END (ADDRESS_END + DATA_LENGTH) - - -static void -ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val) -{ - uint8_t temp, old = dev->nvram_t; - dev->nvram_t = val & 0x03; - - if (val & 0x02) { - if (!dev->nvram_index) { - /* First signal clocked in after clock is high, start bit. */ - dev->nvram_start = 1; - ncr53c8xx_log("[W] Serial EEPROM: Start bit\n"); - dev->nvram_op = 0; - } else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) { - if (!dev->nvram_start) - return; - - dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1); - if (dev->nvram_index == 2) { - // ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op); - dev->nvram_param = 0; - } - } else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) { - if (!dev->nvram_start) - return; - - dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3); - if (dev->nvram_index < ADDRESS_END) { - dev->nvram_index++; - return; - } - - switch (dev->nvram_op) { - case 0x00: - temp = dev->nvram_param >> ADDRESS_SHIFT; - switch(temp) { - case 0x00: - ncr53c8xx_log("[W] Serial EEPROM: EWDS\n"); - break; - case 0x01: - ncr53c8xx_log("[W] Serial EEPROM: WRAL\n"); - break; - case 0x02: - ncr53c8xx_log("[W] Serial EEPROM: ERAL\n"); - break; - case 0x03: - ncr53c8xx_log("[W] Serial EEPROM: EWEN\n"); - break; - default: - ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n"); - break; - } - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return; - case 0x01: - ncr53c8xx_log("[W] Serial EEPROM: WRITE\n"); - break; - case 0x02: - ncr53c8xx_log("[W] Serial EEPROM: READ\n"); - break; - case 0x03: - ncr53c8xx_log("[W] Serial EEPROM: ERASE\n"); - break; - default: - ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n"); - break; - } - } else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { - if (!dev->nvram_start) - return; - - if (dev->nvram_index == DATA_END) { - ncr53c8xx_log("[W] Serial EEPROM: Data end\n"); - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return; - } - } - dev->nvram_index++; - } -} - - -static uint8_t -ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev) -{ - uint8_t temp = 0; - - if (dev->gpreg & 0x02) { - if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { - if (!dev->nvram_start) - return temp; - - dev->nvram_index++; - - if (dev->nvram_index == DATA_END) { - ncr53c8xx_log("[R] Serial EEPROM: Data end\n"); - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return temp; - } - } - } - - return temp; -} -#endif - - static void ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) { @@ -1652,12 +1537,8 @@ ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) break; case 0x07: /* GPREG */ ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); - tmp = dev->gpreg; - dev->gpreg = val & 0xfe; -#ifdef USE_NVRAM - if ((dev->gpcntl & 0xc3) == 0x00) - ncr53c8xx_serial_eeprom_write(dev, val & 0x03); -#endif + dev->gpreg = val; + i2c_gpio_set(dev->i2c, (dev->gpreg & 0x02) || ((dev->gpcntl & 0x82) == 0x02), (dev->gpreg & 0x01) || ((dev->gpcntl & 0x41) == 0x01)); break; case 0x08: /* SFBR */ /* The CPU is not allowed to write to this register. However the @@ -1792,7 +1673,7 @@ ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) dev->respid0 = val; break; case 0x4b: /* RESPID1 */ - if (dev->chip >= CHIP_825) + if (dev->wide) dev->respid1 = val; break; case 0x4d: /* STEST1 */ @@ -1844,19 +1725,19 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) case addr + 3: return (dev->name >> 24) & 0xff; #define CASE_GET_REG32_COND(name, addr) \ - case addr: if (dev->chip >= CHIP_825) \ + case addr: if (dev->wide) \ return dev->name & 0xff; \ else \ return 0x00; \ - case addr + 1: if (dev->chip >= CHIP_825) \ + case addr + 1: if (dev->wide) \ return (dev->name >> 8) & 0xff; \ else \ return 0x00; \ - case addr + 2: if (dev->chip >= CHIP_825) \ + case addr + 2: if (dev->wide) \ return (dev->name >> 16) & 0xff; \ else \ return 0x00; \ - case addr + 3: if (dev->chip >= CHIP_825) \ + case addr + 3: if (dev->wide) \ return (dev->name >> 24) & 0xff; \ else \ return 0x00; @@ -1886,13 +1767,18 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); return dev->sdid; case 0x07: /* GPREG */ -#ifdef USE_NVRAM - tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; - if ((dev->gpcntl & 0xc3) == 0x01) - tmp |= ncr53c8xx_serial_eeprom_read(dev); -#else - tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; -#endif + tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1f; + if ((dev->gpcntl & 0x41) == 0x01) { + tmp &= 0xfe; + if (i2c_gpio_get_sda(dev->i2c)) + tmp |= 0x01; + } + if ((dev->gpcntl & 0x82) == 0x02) { + tmp &= 0xfd; + if (i2c_gpio_get_scl(dev->i2c)) + tmp |= 0x02; + } + ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); return tmp; case 0x08: /* Revision ID */ @@ -1935,12 +1821,12 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) tmp = dev->istat; return tmp; case 0x16: /* MBOX0 */ - if (dev->chip >= CHIP_825) + if (dev->wide) return 0x00; ncr53c8xx_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); return dev->mbox0; case 0x17: /* MBOX1 */ - if (dev->chip >= CHIP_825) + if (dev->wide) return 0x00; ncr53c8xx_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); return dev->mbox1; @@ -2015,12 +1901,12 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) ncr53c8xx_log("NCR 810: Read SIST1 %02X\n", tmp); return tmp; case 0x44: /* SLPAR */ - if (dev->chip < CHIP_825) + if (!dev->wide) return 0x00; ncr53c8xx_log("NCR 810: Read SLPAR %02X\n", dev->stime0); return dev->slpar; case 0x45: /* SWIDE */ - if (dev->chip < CHIP_825) + if (!dev->wide) return 0x00; ncr53c8xx_log("NCR 810: Read SWIDE %02X\n", dev->stime0); return dev->swide; @@ -2034,13 +1920,14 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) ncr53c8xx_log("NCR 810: Read STIME0 %02X\n", dev->stime0); return dev->stime0; case 0x4a: /* RESPID0 */ - if (dev->chip >= CHIP_825) + if (dev->wide) { ncr53c8xx_log("NCR 810: Read RESPID0 %02X\n", dev->respid0); - else + } else { ncr53c8xx_log("NCR 810: Read RESPID %02X\n", dev->respid0); + } return dev->respid0; case 0x4b: /* RESPID1 */ - if (dev->chip < CHIP_825) + if (!dev->wide) return 0x00; ncr53c8xx_log("NCR 810: Read RESPID1 %02X\n", dev->respid1); return dev->respid1; @@ -2059,13 +1946,14 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) case 0x50: /* SIDL0 */ /* This is needed by the linux drivers. We currently only update it during the MSG IN phase. */ - if (dev->chip >= CHIP_825) + if (dev->wide) { ncr53c8xx_log("NCR 810: Read SIDL0 %02X\n", dev->sidl0); - else + } else { ncr53c8xx_log("NCR 810: Read SIDL %02X\n", dev->sidl0); + } return dev->sidl0; case 0x51: /* SIDL1 */ - if (dev->chip < CHIP_825) + if (!dev->wide) return 0x00; ncr53c8xx_log("NCR 810: Read SIDL1 %02X\n", dev->sidl1); return dev->sidl1; @@ -2114,7 +2002,7 @@ ncr53c8xx_io_readw(uint16_t addr, void *p) { ncr53c8xx_t *dev = (ncr53c8xx_t *)p; uint16_t val; - + addr &= 0xff; val = ncr53c8xx_reg_readb(dev, addr); val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; @@ -2127,7 +2015,7 @@ ncr53c8xx_io_readl(uint16_t addr, void *p) { ncr53c8xx_t *dev = (ncr53c8xx_t *)p; uint32_t val; - + addr &= 0xff; val = ncr53c8xx_reg_readb(dev, addr); val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; @@ -2148,7 +2036,7 @@ ncr53c8xx_io_writeb(uint16_t addr, uint8_t val, void *p) static void ncr53c8xx_io_writew(uint16_t addr, uint16_t val, void *p) { - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; addr &= 0xff; ncr53c8xx_reg_writeb(dev, addr, val & 0xff); ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); @@ -2232,7 +2120,7 @@ ncr53c8xx_mmio_readl(uint32_t addr, void *p) val = ncr53c8xx_reg_readb(dev, addr); val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; - val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; return val; } @@ -2294,7 +2182,7 @@ ncr53c8xx_ram_readl(uint32_t addr, void *p) val = ncr53c8xx_ram_readb(addr, p); val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; val |= ncr53c8xx_ram_readb(addr + 2, p) << 16; - val |= ncr53c8xx_ram_readb(addr + 3, p) << 24; + val |= ncr53c8xx_ram_readb(addr + 3, p) << 24; return val; } @@ -2354,13 +2242,14 @@ ncr53c8xx_ram_set_addr(ncr53c8xx_t *dev, uint32_t base) } -#ifdef USE_BIOS_BAR static void ncr53c8xx_bios_set_addr(ncr53c8xx_t *dev, uint32_t base) { - mem_mapping_set_addr(&dev->bios.mapping, base, 0x10000); + if (dev->has_bios == 2) + mem_mapping_set_addr(&dev->bios.mapping, base, 0x10000); + else if (dev->has_bios == 1) + mem_mapping_set_addr(&dev->bios.mapping, base, 0x04000); } -#endif static void @@ -2377,13 +2266,11 @@ ncr53c8xx_ram_disable(ncr53c8xx_t *dev) } -#ifdef USE_BIOS_BAR static void ncr53c8xx_bios_disable(ncr53c8xx_t *dev) { mem_mapping_disable(&dev->bios.mapping); } -#endif uint8_t ncr53c8xx_pci_regs[256]; @@ -2447,47 +2334,37 @@ ncr53c8xx_pci_read(int func, int addr, void *p) case 0x18: return 0; /*Memory space*/ case 0x19: - if (dev->chip < CHIP_825) + if (!dev->wide) return 0; return ncr53c8xx_pci_bar[2].addr_regs[1]; case 0x1A: - if (dev->chip < CHIP_825) + if (!dev->wide) return 0; return ncr53c8xx_pci_bar[2].addr_regs[2]; case 0x1B: - if (dev->chip < CHIP_825) + if (!dev->wide) return 0; return ncr53c8xx_pci_bar[2].addr_regs[3]; case 0x2C: return 0x00; case 0x2D: - if (dev->chip >= CHIP_825) + if (dev->wide) return 0; return 0x10; case 0x2E: - if (dev->chip >= CHIP_825) + if (dev->wide) return 0; return 0x01; case 0x2F: return 0x00; -#ifdef USE_BIOS_BAR case 0x30: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; - return ncr53c8xx_pci_bar[3].addr_regs[0]; + return ncr53c8xx_pci_bar[3].addr_regs[0] & 0x01; case 0x31: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; return ncr53c8xx_pci_bar[3].addr_regs[1]; case 0x32: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; return ncr53c8xx_pci_bar[3].addr_regs[2]; case 0x33: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; return ncr53c8xx_pci_bar[3].addr_regs[3]; -#endif case 0x3C: return dev->irq; case 0x3D: @@ -2515,7 +2392,7 @@ ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) return; } - switch (addr) + switch (addr) { case 0x04: valxor = (val & 0x57) ^ ncr53c8xx_pci_regs[addr]; @@ -2528,7 +2405,7 @@ ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) ncr53c8xx_mem_disable(dev); if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); - if (dev->chip >= CHIP_825) { + if (dev->wide) { ncr53c8xx_ram_disable(dev); if ((dev->RAMBase != 0) && (val & PCI_COMMAND_MEM)) ncr53c8xx_ram_set_addr(dev, dev->RAMBase); @@ -2581,10 +2458,10 @@ ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) if (dev->MMIOBase != 0) ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); } - return; + return; case 0x19: case 0x1A: case 0x1B: - if (dev->chip < CHIP_825) + if (!dev->wide) return; /* RAM Base set. */ /* First, remove the old I/O. */ @@ -2592,8 +2469,8 @@ ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) /* Then let's set the PCI regs. */ ncr53c8xx_pci_bar[2].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ - ncr53c8xx_pci_bar[2].addr &= 0xffffc000; - dev->RAMBase = ncr53c8xx_pci_bar[2].addr & 0xffffc000; + ncr53c8xx_pci_bar[2].addr &= 0xfffff000; + dev->RAMBase = ncr53c8xx_pci_bar[2].addr & 0xfffff000; /* Log the new base. */ ncr53c8xx_log("NCR53c8xx: New RAM base is %08X\n" , dev->RAMBase); /* We're done, so get out of the here. */ @@ -2601,12 +2478,10 @@ ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) if (dev->RAMBase != 0) ncr53c8xx_ram_set_addr(dev, dev->RAMBase); } - return; - -#ifdef USE_BIOS_BAR - case 0x30: case 0x31: case 0x32: case 0x33: return; - if ((dev->chip < CHIP_825) || !dev->has_bios) + + case 0x30: case 0x31: case 0x32: case 0x33: + if (dev->has_bios == 0) return; /* BIOS Base set. */ /* First, remove the old I/O. */ @@ -2614,15 +2489,15 @@ ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) /* Then let's set the PCI regs. */ ncr53c8xx_pci_bar[3].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ - ncr53c8xx_pci_bar[3].addr &= 0xffff0001; - dev->BIOSBase = ncr53c8xx_pci_bar[3].addr & 0xffff0000; + ncr53c8xx_pci_bar[3].addr &= (dev->bios_mask | 0x00000001); + dev->BIOSBase = ncr53c8xx_pci_bar[3].addr & dev->bios_mask; + ncr53c8xx_log("BIOS BAR: %08X\n", dev->BIOSBase | ncr53c8xx_pci_bar[3].addr_regs[0]); /* Log the new base. */ ncr53c8xx_log("NCR53c8xx: New BIOS base is %08X\n" , dev->BIOSBase); /* We're done, so get out of the here. */ - if (ncr53c8xx_pci_bar[3].addr & 0x00000001) + if (ncr53c8xx_pci_bar[3].addr_regs[0] & 0x01) ncr53c8xx_bios_set_addr(dev, dev->BIOSBase); - return; -#endif + return; case 0x3C: ncr53c8xx_pci_regs[addr] = val; @@ -2640,58 +2515,95 @@ ncr53c8xx_init(const device_t *info) dev = malloc(sizeof(ncr53c8xx_t)); memset(dev, 0x00, sizeof(ncr53c8xx_t)); + dev->bus = scsi_get_bus(); + dev->chip_rev = 0; - // dev->pci_slot = pci_add_card(PCI_ADD_SCSI, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); - dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); + dev->chip = info->local & 0xff; + + if ((dev->chip != CHIP_810) && (dev->chip != CHIP_820) && !(info->local & 0x8000)) { + dev->has_bios = device_get_config_int("bios"); + + /* We have to auto-patch the BIOS to have the correct PCI Device ID, because for some reason, they all ship with + the PCI Device ID set to that of the NCR 53c825, but for a machine BIOS to load the SCSI BIOS correctly, the + PCI Device ID in the BIOS' PCIR block must match the one returned in the PCI registers. */ + if (dev->has_bios == 2) { + rom_init(&dev->bios, SYM53C8XX_SDMS4_ROM, 0xd0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + ncr53c8xx_log("BIOS v4.19: Old BIOS CHIP ID: %02X, old BIOS checksum: %02X\n", dev->bios.rom[0x0022], dev->bios.rom[0xffff]); + dev->bios.rom[0xffff] += (dev->bios.rom[0x0022] - dev->chip); + dev->bios.rom[0x0022] = dev->chip; + ncr53c8xx_log("BIOS v4.19: New BIOS CHIP ID: %02X, old BIOS checksum: %02X\n", dev->bios.rom[0x0022], dev->bios.rom[0xffff]); + } else if (dev->has_bios == 1) { + rom_init(&dev->bios, NCR53C8XX_SDMS3_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + ncr53c8xx_log("BIOS v3.07: Old BIOS CHIP ID: %02X, old BIOS checksum: %02X\n", dev->bios.rom[0x3fcb], dev->bios.rom[0x3fff]); + dev->bios.rom[0x3fff] += (dev->bios.rom[0x3fcb] - dev->chip); + dev->bios.rom[0x3fcb] = dev->chip; + ncr53c8xx_log("BIOS v3.07: New BIOS CHIP ID: %02X, old BIOS checksum: %02X\n", dev->bios.rom[0x3fcb], dev->bios.rom[0x3fff]); + } + } else + dev->has_bios = 0; + + if (info->local & 0x8000) + dev->pci_slot = pci_add_card(PCI_ADD_SCSI, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); + else + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); + + if (dev->chip == CHIP_875) { + dev->chip_rev = 0x04; + dev->nvr_path = "ncr53c875.nvr"; + dev->wide = 1; + } else if (dev->chip == CHIP_860) { + dev->chip_rev = 0x04; + dev->nvr_path = "ncr53c860.nvr"; + dev->wide = 1; + } else if (dev->chip == CHIP_820) { + dev->nvr_path = "ncr53c820.nvr"; + dev->wide = 1; + } else if (dev->chip == CHIP_825) { + dev->chip_rev = 0x26; + dev->nvr_path = "ncr53c825a.nvr"; + dev->wide = 1; + } else if (dev->chip == CHIP_810) { + dev->nvr_path = "ncr53c810.nvr"; + dev->wide = 0; + } else if (dev->chip == CHIP_815) { + dev->chip_rev = 0x04; + dev->nvr_path = "ncr53c815.nvr"; + dev->wide = 0; + } ncr53c8xx_pci_bar[0].addr_regs[0] = 1; ncr53c8xx_pci_bar[1].addr_regs[0] = 0; - dev->chip = info->local & 0xff; + ncr53c8xx_pci_regs[0x04] = 3; - ncr53c8xx_pci_regs[0x04] = 3; + if (dev->has_bios == 2) { + ncr53c8xx_pci_bar[3].addr = 0xffff0000; + dev->bios_mask = 0xffff0000; + } else if (dev->has_bios == 1) { + ncr53c8xx_pci_bar[3].addr = 0xffffc000; + dev->bios_mask = 0xffffc000; + } else { + ncr53c8xx_pci_bar[3].addr = 0x00000000; + dev->bios_mask = 0x00000000; + } ncr53c8xx_mem_init(dev, 0x0fffff00); ncr53c8xx_mem_disable(dev); - if (info->local & 0x8000) - dev->has_bios = 0; - else - dev->has_bios = device_get_config_int("bios"); - if (dev->has_bios) - rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (dev->chip >= CHIP_825) { - if (dev->chip == CHIP_875) { - dev->chip_rev = 0x04; - dev->nvr_path = L"ncr53c875.nvr"; - } else if (dev->chip == CHIP_860) { - dev->chip_rev = 0x04; - dev->nvr_path = L"ncr53c860.nvr"; - } else { - dev->chip_rev = 0x26; - dev->nvr_path = L"ncr53c825a.nvr"; - } - ncr53c8xx_pci_bar[2].addr_regs[0] = 0; - ncr53c8xx_pci_bar[3].addr = 0xffff0000; - /* Need to make it align on a 16k boundary as that's this emulator's - memory mapping granularity. */ - ncr53c8xx_ram_init(dev, 0x0fffc000); + ncr53c8xx_pci_bar[2].addr_regs[0] = 0; + + if (dev->wide) { + ncr53c8xx_ram_init(dev, 0x0ffff000); ncr53c8xx_ram_disable(dev); - -#ifdef USE_BIOS_BAR - if (dev->has_bios) - ncr53c8xx_bios_disable(dev); -#endif - } else { - /* if (dev->has_bios) - rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); */ - - dev->nvr_path = L"ncr53c810.nvr"; } -#ifdef USE_NVRAM + if (dev->has_bios) + ncr53c8xx_bios_disable(dev); + + dev->i2c = i2c_gpio_init("nvr_ncr53c8xx"); + dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->nvram, sizeof(dev->nvram), 1); + /* Load the serial EEPROM. */ ncr53c8xx_eeprom(dev, 0); -#endif ncr53c8xx_soft_reset(dev); @@ -2701,74 +2613,141 @@ ncr53c8xx_init(const device_t *info) } -static void +static void ncr53c8xx_close(void *priv) { ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; if (dev) { + if (dev->eeprom) + i2c_eeprom_close(dev->eeprom); + + if (dev->i2c) + i2c_gpio_close(dev->i2c); + + /* Save the serial EEPROM. */ + ncr53c8xx_eeprom(dev, 1); + free(dev); dev = NULL; } } - static const device_config_t ncr53c8xx_pci_config[] = { - { - "bios", "Enable BIOS", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 - } +// clang-format off + { + .name = "bios", + .description = "BIOS", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "SDMS 4.x BIOS", .value = 2 }, + { .description = "SDMS 3.x BIOS", .value = 1 }, + { .description = "Disable BIOS", .value = 0 }, + { .description = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; +const device_t ncr53c810_pci_device = { + .name = "NCR 53c810", + .internal_name = "ncr53c810", + .flags = DEVICE_PCI, + .local = CHIP_810, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; -const device_t ncr53c810_pci_device = -{ - "NCR 53c810 (SCSI)", - DEVICE_PCI, - 0x01, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, +const device_t ncr53c810_onboard_pci_device = { + .name = "NCR 53c810 On-Board", + .internal_name = "ncr53c810_onboard", + .flags = DEVICE_PCI, + .local = 0x8001, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ncr53c815_pci_device = { + .name = "NCR 53c815", + .internal_name = "ncr53c815", + .flags = DEVICE_PCI, + .local = CHIP_815, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, ncr53c8xx_pci_config }; -const device_t ncr53c810_onboard_pci_device = -{ - "NCR 53c810 (SCSI) On-Board", - DEVICE_PCI, - 0x8001, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - NULL +const device_t ncr53c820_pci_device = { + .name = "NCR 53c820", + .internal_name = "ncr53c820", + .flags = DEVICE_PCI, + .local = CHIP_820, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t ncr53c825a_pci_device = -{ - "NCR 53c825A (SCSI)", - DEVICE_PCI, - CHIP_825, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - ncr53c8xx_pci_config +const device_t ncr53c825a_pci_device = { + .name = "NCR 53c825A", + .internal_name = "ncr53c825a", + .flags = DEVICE_PCI, + .local = CHIP_825, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ncr53c8xx_pci_config }; -const device_t ncr53c860_pci_device = -{ - "NCR 53c860 (SCSI)", - DEVICE_PCI, - CHIP_860, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - ncr53c8xx_pci_config +const device_t ncr53c860_pci_device = { + .name = "NCR 53c860", + .internal_name = "ncr53c860", + .flags = DEVICE_PCI, + .local = CHIP_860, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ncr53c8xx_pci_config }; -const device_t ncr53c875_pci_device = -{ - "NCR 53c875 (SCSI)", - DEVICE_PCI, - CHIP_875, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - ncr53c8xx_pci_config +const device_t ncr53c875_pci_device = { + .name = "NCR 53c875", + .internal_name = "ncr53c875", + .flags = DEVICE_PCI, + .local = CHIP_875, + .init = ncr53c8xx_init, + .close = ncr53c8xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ncr53c8xx_pci_config }; diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c new file mode 100644 index 000000000..3266dc802 --- /dev/null +++ b/src/scsi/scsi_pcscsi.c @@ -0,0 +1,2051 @@ +/* + * 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 Tekram DC-390 SCSI and related MCA + * controllers using the NCR 53c9x series of chips. + * + * + * + * + * Authors: Fabrice Bellard (QEMU) + * Herve Poussineau (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2005-2018 Fabrice Bellard. + * Copyright 2012-2018 Herve Poussineau. + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/dma.h> +#include <86box/pic.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/mca.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/nvr.h> +#include <86box/plat.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/scsi_pcscsi.h> +#include <86box/vid_ati_eeprom.h> +#include <86box/fifo8.h> + +#define DC390_ROM "roms/scsi/esp_pci/INT13.BIN" + +#define ESP_REGS 16 +#define ESP_FIFO_SZ 16 +#define ESP_CMDFIFO_SZ 32 + +#define ESP_TCLO 0x0 +#define ESP_TCMID 0x1 +#define ESP_FIFO 0x2 +#define ESP_CMD 0x3 +#define ESP_RSTAT 0x4 +#define ESP_WBUSID 0x4 +#define ESP_RINTR 0x5 +#define ESP_WSEL 0x5 +#define ESP_RSEQ 0x6 +#define ESP_WSYNTP 0x6 +#define ESP_RFLAGS 0x7 +#define ESP_WSYNO 0x7 +#define ESP_CFG1 0x8 +#define ESP_RRES1 0x9 +#define ESP_WCCF 0x9 +#define ESP_RRES2 0xa +#define ESP_WTEST 0xa +#define ESP_CFG2 0xb +#define ESP_CFG3 0xc +#define ESP_RES3 0xd +#define ESP_TCHI 0xe +#define ESP_RES4 0xf + +#define CMD_DMA 0x80 +#define CMD_CMD 0x7f + +#define CMD_NOP 0x00 +#define CMD_FLUSH 0x01 +#define CMD_RESET 0x02 +#define CMD_BUSRESET 0x03 +#define CMD_TI 0x10 +#define CMD_ICCS 0x11 +#define CMD_MSGACC 0x12 +#define CMD_PAD 0x18 +#define CMD_SATN 0x1a +#define CMD_RSTATN 0x1b +#define CMD_SEL 0x41 +#define CMD_SELATN 0x42 +#define CMD_SELATNS 0x43 +#define CMD_ENSEL 0x44 +#define CMD_DISSEL 0x45 + +#define STAT_DO 0x00 +#define STAT_DI 0x01 +#define STAT_CD 0x02 +#define STAT_ST 0x03 +#define STAT_MO 0x06 +#define STAT_MI 0x07 +#define STAT_PIO_MASK 0x06 + +#define STAT_TC 0x10 +#define STAT_PE 0x20 +#define STAT_GE 0x40 +#define STAT_INT 0x80 + +#define BUSID_DID 0x07 + +#define INTR_FC 0x08 +#define INTR_BS 0x10 +#define INTR_DC 0x20 +#define INTR_RST 0x80 + +#define SEQ_0 0x0 +#define SEQ_MO 0x1 +#define SEQ_CD 0x4 + +#define CFG1_RESREPT 0x40 + +#define TCHI_FAS100A 0x04 +#define TCHI_AM53C974 0x12 + +#define DMA_CMD 0x0 +#define DMA_STC 0x1 +#define DMA_SPA 0x2 +#define DMA_WBC 0x3 +#define DMA_WAC 0x4 +#define DMA_STAT 0x5 +#define DMA_SMDLA 0x6 +#define DMA_WMAC 0x7 + +#define DMA_CMD_MASK 0x03 +#define DMA_CMD_DIAG 0x04 +#define DMA_CMD_MDL 0x10 +#define DMA_CMD_INTE_P 0x20 +#define DMA_CMD_INTE_D 0x40 +#define DMA_CMD_DIR 0x80 + +#define DMA_STAT_PWDN 0x01 +#define DMA_STAT_ERROR 0x02 +#define DMA_STAT_ABORT 0x04 +#define DMA_STAT_DONE 0x08 +#define DMA_STAT_SCSIINT 0x10 +#define DMA_STAT_BCMBLT 0x20 + +#define SBAC_STATUS (1 << 24) +#define SBAC_PABTEN (1 << 25) + +typedef struct { + mem_mapping_t mmio_mapping; + mem_mapping_t ram_mapping; + char *nvr_path; + uint8_t pci_slot; + int has_bios; + int BIOSBase; + int MMIOBase; + rom_t bios; + ati_eeprom_t eeprom; + int PCIBase; + + uint8_t rregs[ESP_REGS]; + uint8_t wregs[ESP_REGS]; + int irq; + int tchi_written; + uint32_t ti_size; + uint32_t status; + uint32_t dma; + Fifo8 fifo; + uint8_t bus; + uint8_t id, lun; + Fifo8 cmdfifo; + uint32_t do_cmd; + uint8_t cmdfifo_cdb_offset; + + int32_t xfer_counter; + int dma_enabled; + + uint32_t buffer_pos; + uint32_t dma_regs[8]; + uint32_t sbac; + + double period; + + pc_timer_t timer; + + int mca; + uint16_t Base; + uint8_t HostID, DmaChannel; + + struct + { + uint8_t mode; + uint8_t status; + int pos; + } dma_86c01; + + uint8_t pos_regs[8]; +} esp_t; + +#define READ_FROM_DEVICE 1 +#define WRITE_TO_DEVICE 0 + + +#ifdef ENABLE_ESP_LOG +int esp_do_log = ENABLE_ESP_LOG; + + +static void +esp_log(const char *fmt, ...) +{ + va_list ap; + + if (esp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define esp_log(fmt, ...) +#endif + +static void esp_dma_enable(esp_t *dev, int level); +static void esp_do_dma(esp_t *dev, scsi_device_t *sd); +static void esp_do_nodma(esp_t *dev, scsi_device_t *sd); +static void esp_pci_dma_memory_rw(esp_t *dev, uint8_t *buf, uint32_t len, int dir); +static void esp_timer_on(esp_t *dev, scsi_device_t *sd, double p); +static void esp_command_complete(void *priv, uint32_t status); +static void esp_pci_command_complete(void *priv, uint32_t status); +static void esp_pci_soft_reset(esp_t *dev); +static void esp_pci_hard_reset(esp_t *dev); +static void handle_ti(void *priv); + +static void +esp_irq(esp_t *dev, int level) +{ + if (dev->mca) { + if (level) { + picint(1 << dev->irq); + dev->dma_86c01.status |= 0x01; + esp_log("Raising IRQ...\n"); + } else { + picintc(1 << dev->irq); + dev->dma_86c01.status &= ~0x01; + esp_log("Lowering IRQ...\n"); + } + } else { + if (level) { + pci_set_irq(dev->pci_slot, PCI_INTA); + esp_log("Raising IRQ...\n"); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + esp_log("Lowering IRQ...\n"); + } + } +} + +static void +esp_raise_irq(esp_t *dev) +{ + if (!(dev->rregs[ESP_RSTAT] & STAT_INT)) { + dev->rregs[ESP_RSTAT] |= STAT_INT; + esp_irq(dev, 1); + } +} + +static void +esp_lower_irq(esp_t *dev) +{ + if (dev->rregs[ESP_RSTAT] & STAT_INT) { + dev->rregs[ESP_RSTAT] &= ~STAT_INT; + esp_irq(dev, 0); + } +} + +static void +esp_fifo_push(Fifo8 *fifo, uint8_t val) +{ + if (fifo8_num_used(fifo) == fifo->capacity) { + return; + } + + fifo8_push(fifo, val); +} + +static uint8_t +esp_fifo_pop(Fifo8 *fifo) +{ + if (fifo8_is_empty(fifo)) { + return 0; + } + + return fifo8_pop(fifo); +} + +static uint32_t +esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen) +{ + const uint8_t *buf; + uint32_t n; + + if (maxlen == 0) { + return 0; + } + + buf = fifo8_pop_buf(fifo, maxlen, &n); + if (dest) { + memcpy(dest, buf, n); + } + + return n; +} + +static uint32_t +esp_get_tc(esp_t *dev) +{ + uint32_t dmalen; + + dmalen = dev->rregs[ESP_TCLO]; + dmalen |= dev->rregs[ESP_TCMID] << 8; + dmalen |= dev->rregs[ESP_TCHI] << 16; + + return dmalen; +} + +static void +esp_set_tc(esp_t *dev, uint32_t dmalen) +{ + dev->rregs[ESP_TCLO] = dmalen; + dev->rregs[ESP_TCMID] = dmalen >> 8; + dev->rregs[ESP_TCHI] = dmalen >> 16; +} + +static uint32_t +esp_get_stc(esp_t *dev) +{ + uint32_t dmalen; + + dmalen = dev->wregs[ESP_TCLO]; + dmalen |= dev->wregs[ESP_TCMID] << 8; + dmalen |= dev->wregs[ESP_TCHI] << 16; + + return dmalen; +} + +static void +esp_dma_done(esp_t *dev) +{ + dev->rregs[ESP_RSTAT] |= STAT_TC; + dev->rregs[ESP_RINTR] = INTR_BS; + dev->rregs[ESP_RSEQ] = 0; + dev->rregs[ESP_RFLAGS] = 0; + esp_set_tc(dev, 0); + esp_log("ESP DMA Finished\n"); + esp_raise_irq(dev); +} + +static uint32_t +esp_get_cmd(esp_t *dev, uint32_t maxlen) +{ + uint8_t buf[ESP_CMDFIFO_SZ]; + uint32_t dmalen, n; + + dev->id = dev->wregs[ESP_WBUSID] & BUSID_DID; + if (dev->dma) { + dmalen = MIN(esp_get_tc(dev), maxlen); + esp_log("ESP Get data, dmalen = %d\n", dmalen); + if (dmalen == 0) + return 0; + if (dev->mca) { + dma_set_drq(dev->DmaChannel, 1); + while (dev->dma_86c01.pos < dmalen) { + int val = dma_channel_read(dev->DmaChannel); + buf[dev->dma_86c01.pos++] = val & 0xff; + } + dev->dma_86c01.pos = 0; + dma_set_drq(dev->DmaChannel, 0); + } else { + esp_pci_dma_memory_rw(dev, buf, dmalen, WRITE_TO_DEVICE); + dmalen = MIN(fifo8_num_free(&dev->cmdfifo), dmalen); + fifo8_push_all(&dev->cmdfifo, buf, dmalen); + } + } else { + dmalen = MIN(fifo8_num_used(&dev->fifo), maxlen); + esp_log("ESP Get command, dmalen = %i\n", dmalen); + if (dmalen == 0) { + return 0; + } + n = esp_fifo_pop_buf(&dev->fifo, buf, dmalen); + n = MIN(fifo8_num_free(&dev->cmdfifo), n); + fifo8_push_all(&dev->cmdfifo, buf, n); + } + + dev->ti_size = 0; + fifo8_reset(&dev->fifo); + + dev->rregs[ESP_RINTR] |= INTR_FC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + + return dmalen; +} + +static void +esp_do_command_phase(esp_t *dev) +{ + uint32_t cmdlen; + uint8_t buf[ESP_CMDFIFO_SZ]; + scsi_device_t *sd; + + sd = &scsi_devices[dev->bus][dev->id]; + + sd->buffer_length = -1; + + cmdlen = fifo8_num_used(&dev->cmdfifo); + if (!cmdlen) + return; + + esp_fifo_pop_buf(&dev->cmdfifo, buf, cmdlen); + + for (int i = 0; i < cmdlen; i++) + esp_log("CDB[%i] = %02x\n", i, buf[i]); + + scsi_device_command_phase0(sd, buf); + + dev->buffer_pos = 0; + dev->ti_size = sd->buffer_length; + dev->xfer_counter = sd->buffer_length; + + esp_log("ESP SCSI Command = 0x%02x, ID = %d, LUN = %d, len = %d\n", buf[0], dev->id, dev->lun, sd->buffer_length); + + fifo8_reset(&dev->cmdfifo); + + if (sd->buffer_length > 0) { + /* This should be set to the underlying device's buffer by command phase 0. */ + dev->rregs[ESP_RSTAT] = STAT_TC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + + if (sd->phase == SCSI_PHASE_DATA_IN) { + dev->rregs[ESP_RSTAT] |= STAT_DI; + esp_log("ESP Data In\n"); + esp_timer_on(dev, sd, scsi_device_get_callback(sd)); + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + dev->rregs[ESP_RSTAT] |= STAT_DO; + esp_log("ESP Data Out\n"); + dev->ti_size = -sd->buffer_length; + esp_timer_on(dev, sd, scsi_device_get_callback(sd)); + } + esp_log("ESP SCSI Start reading/writing\n"); + esp_do_dma(dev, sd); + } else { + esp_log("ESP SCSI Command with no length\n"); + if (dev->mca) { + if (buf[0] == 0x43) { + dev->rregs[ESP_RSTAT] = STAT_DI | STAT_TC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + esp_do_dma(dev, sd); + } else + esp_command_complete(dev, sd->status); + } else + esp_pci_command_complete(dev, sd->status); + } + + scsi_device_identify(sd, SCSI_LUN_USE_CDB); + + dev->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; + esp_raise_irq(dev); +} + +static void +esp_do_message_phase(esp_t *dev) +{ + int len; + uint8_t message; + + if (dev->cmdfifo_cdb_offset) { + message = esp_fifo_pop(&dev->cmdfifo); + + dev->lun = message & 7; + dev->cmdfifo_cdb_offset--; + + if (scsi_device_present(&scsi_devices[dev->bus][dev->id]) && (dev->lun > 0)) { + /* We only support LUN 0 */ + esp_log("LUN = %i\n", dev->lun); + dev->rregs[ESP_RSTAT] = 0; + dev->rregs[ESP_RINTR] = INTR_DC; + dev->rregs[ESP_RSEQ] = SEQ_0; + esp_raise_irq(dev); + fifo8_reset(&dev->cmdfifo); + return; + } + + scsi_device_identify(&scsi_devices[dev->bus][dev->id], dev->lun); + } + + esp_log("CDB offset = %i\n", dev->cmdfifo_cdb_offset); + + if (dev->cmdfifo_cdb_offset) { + len = MIN(dev->cmdfifo_cdb_offset, fifo8_num_used(&dev->cmdfifo)); + esp_fifo_pop_buf(&dev->cmdfifo, NULL, len); + dev->cmdfifo_cdb_offset = 0; + } +} + +static void +esp_do_cmd(esp_t *dev) +{ + esp_do_message_phase(dev); + if (dev->cmdfifo_cdb_offset == 0) + esp_do_command_phase(dev); +} + +static void +esp_dma_enable(esp_t *dev, int level) +{ + if (level) { + esp_log("ESP DMA Enabled\n"); + dev->dma_enabled = 1; + dev->dma_86c01.status |= 0x02; + if ((dev->rregs[ESP_CMD] & CMD_CMD) != CMD_TI) { + timer_on_auto(&dev->timer, 40.0); + } else { + esp_log("Period = %lf\n", dev->period); + timer_on_auto(&dev->timer, dev->period); + } + } else { + esp_log("ESP DMA Disabled\n"); + dev->dma_enabled = 0; + dev->dma_86c01.status &= ~0x02; + } +} + +static void +esp_hard_reset(esp_t *dev) +{ + memset(dev->rregs, 0, ESP_REGS); + memset(dev->wregs, 0, ESP_REGS); + dev->tchi_written = 0; + dev->ti_size = 0; + fifo8_reset(&dev->fifo); + fifo8_reset(&dev->cmdfifo); + dev->dma = 0; + dev->do_cmd = 0; + dev->rregs[ESP_CFG1] = dev->mca ? dev->HostID : 7; + esp_log("ESP Reset\n"); + timer_stop(&dev->timer); +} + +static void +esp_do_nodma(esp_t *dev, scsi_device_t *sd) +{ + int count; + + esp_log("ESP SCSI Actual FIFO len = %d\n", dev->xfer_counter); + + if (dev->do_cmd) { + esp_log("ESP Command on FIFO\n"); + dev->ti_size = 0; + + if ((dev->rregs[ESP_RSTAT] & 7) == STAT_CD) { + if (dev->cmdfifo_cdb_offset == fifo8_num_used(&dev->cmdfifo)) { + esp_log("CDB offset = %i used return\n", dev->cmdfifo_cdb_offset); + return; + } + + dev->do_cmd = 0; + esp_do_cmd(dev); + } else { + dev->cmdfifo_cdb_offset = fifo8_num_used(&dev->cmdfifo);; + esp_log("CDB offset = %i used\n", dev->cmdfifo_cdb_offset); + + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; + dev->rregs[ESP_RSEQ] = SEQ_CD; + dev->rregs[ESP_RINTR] |= INTR_BS; + esp_raise_irq(dev); + } + return; + } + + if (dev->xfer_counter == 0) { + /* Wait until data is available. */ + esp_log("(ID=%02i LUN=%02i): FIFO no data available\n", dev->id, dev->lun); + return; + } + + esp_log("ESP FIFO = %d, buffer length = %d\n", dev->xfer_counter, sd->buffer_length); + + if (sd->phase == SCSI_PHASE_DATA_IN) { + if (fifo8_is_empty(&dev->fifo)) { + fifo8_push(&dev->fifo, sd->sc->temp_buffer[dev->buffer_pos]); + dev->buffer_pos++; + dev->ti_size--; + dev->xfer_counter--; + } + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + count = MIN(fifo8_num_used(&dev->fifo), ESP_FIFO_SZ); + esp_fifo_pop_buf(&dev->fifo, sd->sc->temp_buffer + dev->buffer_pos, count); + dev->buffer_pos += count; + dev->ti_size += count; + dev->xfer_counter -= count; + } + + esp_log("ESP FIFO Transfer bytes = %d\n", dev->xfer_counter); + if (dev->xfer_counter <= 0) { + if (sd->phase == SCSI_PHASE_DATA_OUT) { + if (dev->ti_size < 0) { + esp_log("ESP FIFO Keep writing\n"); + esp_do_nodma(dev, sd); + } else { + esp_log("ESP FIFO Write finished\n"); + scsi_device_command_phase1(sd); + if (dev->mca) { + esp_command_complete(dev, sd->status); + } else + esp_pci_command_complete(dev, sd->status); + } + } else if (sd->phase == SCSI_PHASE_DATA_IN) { + /* If there is still data to be read from the device then + complete the DMA operation immediately. Otherwise defer + until the scsi layer has completed. */ + if (dev->ti_size <= 0) { + esp_log("ESP FIFO Read finished\n"); + scsi_device_command_phase1(sd); + if (dev->mca) { + esp_command_complete(dev, sd->status); + } else + esp_pci_command_complete(dev, sd->status); + } else { + esp_log("ESP FIFO Keep reading\n"); + esp_do_nodma(dev, sd); + } + } + } else { + /* Partially filled a scsi buffer. Complete immediately. */ + esp_log("ESP SCSI Partially filled the FIFO buffer\n"); + dev->rregs[ESP_RINTR] |= INTR_BS; + esp_raise_irq(dev); + } +} + + +static void +esp_do_dma(esp_t *dev, scsi_device_t *sd) +{ + uint8_t buf[ESP_CMDFIFO_SZ]; + uint32_t tdbc; + int count; + + esp_log("ESP SCSI Actual DMA len = %d\n", esp_get_tc(dev)); + + if (!scsi_device_present(sd)) { + esp_log("ESP SCSI no devices on ID %d, LUN %d\n", dev->id, dev->lun); + /* No such drive */ + dev->rregs[ESP_RSTAT] = 0; + dev->rregs[ESP_RINTR] = INTR_DC; + dev->rregs[ESP_RSEQ] = SEQ_0; + esp_raise_irq(dev); + fifo8_reset(&dev->cmdfifo); + return; + } else { + esp_log("ESP SCSI device found on ID %d, LUN %d\n", dev->id, dev->lun); + } + + count = tdbc = esp_get_tc(dev); + + if (dev->mca) { /*See the comment in the esp_do_busid_cmd() function.*/ + if (sd->buffer_length < 0) { + if (dev->dma_enabled) + goto done; + else + goto partial; + } + } + + if (dev->do_cmd) { + esp_log("ESP Command on DMA\n"); + count = MIN(count, fifo8_num_free(&dev->cmdfifo)); + if (dev->mca) { + dma_set_drq(dev->DmaChannel, 1); + while (dev->dma_86c01.pos < count) { + dma_channel_write(dev->DmaChannel, buf[dev->dma_86c01.pos]); + dev->dma_86c01.pos++; + } + dev->dma_86c01.pos = 0; + dma_set_drq(dev->DmaChannel, 0); + } else + esp_pci_dma_memory_rw(dev, buf, count, READ_FROM_DEVICE); + fifo8_push_all(&dev->cmdfifo, buf, count); + dev->ti_size = 0; + + if ((dev->rregs[ESP_RSTAT] & 7) == STAT_CD) { + if (dev->cmdfifo_cdb_offset == fifo8_num_used(&dev->cmdfifo)) + return; + + dev->do_cmd = 0; + esp_do_cmd(dev); + } else { + dev->cmdfifo_cdb_offset = fifo8_num_used(&dev->cmdfifo); + + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; + dev->rregs[ESP_RSEQ] = SEQ_CD; + dev->rregs[ESP_RINTR] |= INTR_BS; + esp_raise_irq(dev); + } + return; + } + + if (dev->xfer_counter == 0) { + /* Wait until data is available. */ + esp_log("(ID=%02i LUN=%02i): DMA no data available\n", dev->id, dev->lun); + return; + } + + esp_log("ESP SCSI dmaleft = %d, async_len = %i, buffer length = %d\n", esp_get_tc(dev), sd->buffer_length); + + /* Make sure count is never bigger than buffer_length. */ + if (count > dev->xfer_counter) + count = dev->xfer_counter; + + if (sd->phase == SCSI_PHASE_DATA_IN) { + esp_log("ESP SCSI Read, dma cnt = %i, ti size = %i, positive len = %i\n", esp_get_tc(dev), dev->ti_size, count); + if (dev->mca) { + dma_set_drq(dev->DmaChannel, 1); + while (dev->dma_86c01.pos < count) { + dma_channel_write(dev->DmaChannel, sd->sc->temp_buffer[dev->buffer_pos + dev->dma_86c01.pos]); + esp_log("ESP SCSI DMA read for 53C90: pos = %i, val = %02x\n", dev->dma_86c01.pos, sd->sc->temp_buffer[dev->buffer_pos + dev->dma_86c01.pos]); + dev->dma_86c01.pos++; + } + dev->dma_86c01.pos = 0; + dma_set_drq(dev->DmaChannel, 0); + } else { + esp_pci_dma_memory_rw(dev, sd->sc->temp_buffer + dev->buffer_pos, count, READ_FROM_DEVICE); + } + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + esp_log("ESP SCSI Write, negative len = %i, ti size = %i, dma cnt = %i\n", count, -dev->ti_size, esp_get_tc(dev)); + if (dev->mca) { + dma_set_drq(dev->DmaChannel, 1); + while (dev->dma_86c01.pos < count) { + int val = dma_channel_read(dev->DmaChannel); + esp_log("ESP SCSI DMA write for 53C90: pos = %i, val = %02x\n", dev->dma_86c01.pos, val & 0xff); + sd->sc->temp_buffer[dev->buffer_pos + dev->dma_86c01.pos] = val & 0xff; + dev->dma_86c01.pos++; + } + dma_set_drq(dev->DmaChannel, 0); + dev->dma_86c01.pos = 0; + } else + esp_pci_dma_memory_rw(dev, sd->sc->temp_buffer + dev->buffer_pos, count, WRITE_TO_DEVICE); + } + esp_set_tc(dev, esp_get_tc(dev) - count); + dev->buffer_pos += count; + dev->xfer_counter -= count; + if (sd->phase == SCSI_PHASE_DATA_IN) { + dev->ti_size -= count; + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + dev->ti_size += count; + } + + esp_log("ESP SCSI Transfer bytes = %d\n", dev->xfer_counter); + if (dev->xfer_counter <= 0) { + if (sd->phase == SCSI_PHASE_DATA_OUT) { + if (dev->ti_size < 0) { + esp_log("ESP SCSI Keep writing\n"); + esp_do_dma(dev, sd); + } else { + esp_log("ESP SCSI Write finished\n"); + scsi_device_command_phase1(sd); + if (dev->mca) { + esp_command_complete(dev, sd->status); + } else + esp_pci_command_complete(dev, sd->status); + } + } else if (sd->phase == SCSI_PHASE_DATA_IN) { + /* If there is still data to be read from the device then + complete the DMA operation immediately. Otherwise defer + until the scsi layer has completed. */ + if (dev->ti_size <= 0) { +done: + esp_log("ESP SCSI Read finished\n"); + scsi_device_command_phase1(sd); + if (dev->mca) { + esp_command_complete(dev, sd->status); + } else + esp_pci_command_complete(dev, sd->status); + } else { + esp_log("ESP SCSI Keep reading\n"); + esp_do_dma(dev, sd); + } + } + } else { + /* Partially filled a scsi buffer. Complete immediately. */ +partial: + esp_log("ESP SCSI Partially filled the SCSI buffer\n"); + esp_dma_done(dev); + } +} + + +static void +esp_report_command_complete(esp_t *dev, uint32_t status) +{ + esp_log("ESP Command complete\n"); + + dev->ti_size = 0; + dev->status = status; + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; + esp_dma_done(dev); +} + +/* Callback to indicate that the SCSI layer has completed a command. */ +static void +esp_command_complete(void *priv, uint32_t status) +{ + esp_t *dev = (esp_t *)priv; + + esp_report_command_complete(dev, status); +} + +static void +esp_pci_command_complete(void *priv, uint32_t status) +{ + esp_t *dev = (esp_t *)priv; + + esp_command_complete(dev, status); + dev->dma_regs[DMA_WBC] = 0; + dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE; +} + +static void +esp_timer_on(esp_t *dev, scsi_device_t *sd, double p) +{ + if (dev->mca) { + /* Normal SCSI: 5000000 bytes per second */ + dev->period = (p > 0.0) ? p : (((double) sd->buffer_length) * 0.2); + } else { + /* Fast SCSI: 10000000 bytes per second */ + dev->period = (p > 0.0) ? p : (((double) sd->buffer_length) * 0.1); + } + + timer_on_auto(&dev->timer, dev->period + 40.0); +} + +static void +handle_ti(void *priv) +{ + esp_t *dev = (esp_t *)priv; + scsi_device_t *sd = &scsi_devices[dev->bus][dev->id]; + + if (dev->dma) { + esp_log("ESP Handle TI, do data, minlen = %i\n", esp_get_tc(dev)); + esp_do_dma(dev, sd); + } else { + esp_log("ESP Handle TI, do nodma, minlen = %i\n", dev->xfer_counter); + esp_do_nodma(dev, sd); + } +} + +static void +handle_s_without_atn(void *priv) +{ + esp_t *dev = (esp_t *)priv; + int len; + + len = esp_get_cmd(dev, ESP_CMDFIFO_SZ); + esp_log("ESP SEL w/o ATN len = %d, id = %d\n", len, dev->id); + if (len > 0) { + dev->cmdfifo_cdb_offset = 0; + dev->do_cmd = 0; + esp_do_cmd(dev); + } else if (len == 0) { + dev->do_cmd = 1; + /* Target present, but no cmd yet - switch to command phase */ + dev->rregs[ESP_RSEQ] = SEQ_CD; + dev->rregs[ESP_RSTAT] = STAT_CD; + } +} + +static void +handle_satn(void *priv) +{ + esp_t *dev = (esp_t *)priv; + int len; + + len = esp_get_cmd(dev, ESP_CMDFIFO_SZ); + esp_log("ESP SEL with ATN len = %d, id = %d\n", len, dev->id); + if (len > 0) { + dev->cmdfifo_cdb_offset = 1; + dev->do_cmd = 0; + esp_do_cmd(dev); + } else if (len == 0) { + dev->do_cmd = 1; + /* Target present, but no cmd yet - switch to command phase */ + dev->rregs[ESP_RSEQ] = SEQ_CD; + dev->rregs[ESP_RSTAT] = STAT_CD; + } +} + +static void +handle_satn_stop(void *priv) +{ + esp_t *dev = (esp_t *)priv; + int cmdlen; + + cmdlen = esp_get_cmd(dev, 1); + if (cmdlen > 0) { + dev->do_cmd = 1; + dev->cmdfifo_cdb_offset = 1; + dev->rregs[ESP_RSTAT] = STAT_MO; + dev->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + dev->rregs[ESP_RSEQ] = SEQ_MO; + esp_log("ESP SCSI Command len = %d, raising IRQ\n", cmdlen); + esp_raise_irq(dev); + } else if (cmdlen == 0) { + dev->do_cmd = 1; + /* Target present, switch to message out phase */ + dev->rregs[ESP_RSEQ] = SEQ_MO; + dev->rregs[ESP_RSTAT] = STAT_MO; + } +} + +static void +esp_write_response(esp_t *dev) +{ + uint8_t buf[2]; + + buf[0] = dev->status; + buf[1] = 0; + + if (dev->dma) { + if (dev->mca) { + dma_set_drq(dev->DmaChannel, 1); + while (dev->dma_86c01.pos < 2) { + int val = dma_channel_read(dev->DmaChannel); + buf[dev->dma_86c01.pos++] = val & 0xff; + } + dev->dma_86c01.pos = 0; + dma_set_drq(dev->DmaChannel, 0); + } else + esp_pci_dma_memory_rw(dev, buf, 2, WRITE_TO_DEVICE); + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; + dev->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + } else { + fifo8_reset(&dev->fifo); + fifo8_push_all(&dev->fifo, buf, 2); + dev->rregs[ESP_RFLAGS] = 2; + } + esp_log("ESP SCSI ICCS IRQ\n"); + esp_raise_irq(dev); +} + +static void +esp_callback(void *p) +{ + esp_t *dev = (esp_t *) p; + + if (dev->dma_enabled || dev->do_cmd) { + if ((dev->rregs[ESP_CMD] & CMD_CMD) == CMD_TI) { + esp_log("ESP SCSI Handle TI Callback\n"); + handle_ti(dev); + } + } + + esp_log("ESP DMA activated = %d, CMD activated = %d\n", dev->dma_enabled, dev->do_cmd); +} + +static uint32_t +esp_reg_read(esp_t *dev, uint32_t saddr) +{ + uint32_t ret; + + switch (saddr) { + case ESP_FIFO: + if ((dev->rregs[ESP_RSTAT] & 7) == STAT_DI) { + if (dev->ti_size) { + esp_log("TI size FIFO = %i\n", dev->ti_size); + esp_do_nodma(dev, &scsi_devices[dev->bus][dev->id]); + } else { + /* + * The last byte of a non-DMA transfer has been read out + * of the FIFO so switch to status phase + */ + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; + } + } + + dev->rregs[ESP_FIFO] = esp_fifo_pop(&dev->fifo); + ret = dev->rregs[ESP_FIFO]; + break; + case ESP_RINTR: + /* Clear sequence step, interrupt register and all status bits + except TC */ + ret = dev->rregs[ESP_RINTR]; + dev->rregs[ESP_RINTR] = 0; + dev->rregs[ESP_RSTAT] &= ~STAT_TC; + esp_log("ESP SCSI Clear sequence step\n"); + esp_lower_irq(dev); + esp_log("ESP RINTR read old val = %02x\n", ret); + break; + case ESP_TCHI: + /* Return the unique id if the value has never been written */ + if (!dev->tchi_written && !dev->mca) { + esp_log("ESP TCHI read id 0x12\n"); + ret = TCHI_AM53C974; + } else + ret = dev->rregs[saddr]; + break; + case ESP_RFLAGS: + ret = fifo8_num_used(&dev->fifo); + break; + default: + ret = dev->rregs[saddr]; + break; + + } + esp_log("Read reg %02x = %02x\n", saddr, ret); + return ret; +} + + +static void +esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val) +{ + esp_log("Write reg %02x = %02x\n", saddr, val); + + switch (saddr) { + case ESP_TCHI: + dev->tchi_written = 1; + /* fall through */ + case ESP_TCLO: + case ESP_TCMID: + esp_log("Transfer count regs %02x = %i\n", saddr, val); + dev->rregs[ESP_RSTAT] &= ~STAT_TC; + break; + case ESP_FIFO: + if (dev->do_cmd) { + esp_fifo_push(&dev->cmdfifo, val); + esp_log("ESP CmdVal = %02x\n", val); + /* + * If any unexpected message out/command phase data is + * transferred using non-DMA, raise the interrupt + */ + if (dev->rregs[ESP_CMD] == CMD_TI) { + dev->rregs[ESP_RINTR] |= INTR_BS; + esp_raise_irq(dev); + } + } else { + esp_fifo_push(&dev->fifo, val); + esp_log("ESP fifoval = %02x\n", val); + } + break; + case ESP_CMD: + dev->rregs[saddr] = val; + + if (val & CMD_DMA) { + dev->dma = 1; + /* Reload DMA counter. */ + esp_set_tc(dev, esp_get_stc(dev)); + if (dev->mca) + esp_dma_enable(dev, 1); + } else { + dev->dma = 0; + esp_log("ESP Command not for DMA\n"); + if (dev->mca) + esp_dma_enable(dev, 0); + } + esp_log("[%04X:%08X]: ESP Command = %02x, DMA ena1 = %d, DMA ena2 = %d\n", CS, cpu_state.pc, val & (CMD_CMD|CMD_DMA), dev->dma, dev->dma_enabled); + switch (val & CMD_CMD) { + case CMD_NOP: + break; + case CMD_FLUSH: + fifo8_reset(&dev->fifo); + timer_on_auto(&dev->timer, 10.0); + break; + case CMD_RESET: + if (dev->mca) { + esp_lower_irq(dev); + esp_hard_reset(dev); + } else + esp_pci_soft_reset(dev); + break; + case CMD_BUSRESET: + if (!(dev->wregs[ESP_CFG1] & CFG1_RESREPT)) { + dev->rregs[ESP_RINTR] |= INTR_RST; + esp_log("ESP Bus Reset with IRQ\n"); + esp_raise_irq(dev); + } + break; + case CMD_TI: + break; + case CMD_SEL: + handle_s_without_atn(dev); + break; + case CMD_SELATN: + handle_satn(dev); + break; + case CMD_SELATNS: + handle_satn_stop(dev); + break; + case CMD_ICCS: + esp_write_response(dev); + dev->rregs[ESP_RINTR] |= INTR_FC; + dev->rregs[ESP_RSTAT] |= STAT_MI; + break; + case CMD_MSGACC: + dev->rregs[ESP_RINTR] |= INTR_DC; + dev->rregs[ESP_RSEQ] = 0; + dev->rregs[ESP_RFLAGS] = 0; + esp_log("ESP SCSI MSGACC IRQ\n"); + esp_raise_irq(dev); + break; + case CMD_PAD: + dev->rregs[ESP_RSTAT] = STAT_TC; + dev->rregs[ESP_RINTR] |= INTR_FC; + dev->rregs[ESP_RSEQ] = 0; + esp_log("ESP Transfer Pad\n"); + break; + case CMD_SATN: + case CMD_RSTATN: + break; + case CMD_ENSEL: + dev->rregs[ESP_RINTR] = 0; + esp_log("ESP Enable Selection, do cmd = %d\n", dev->do_cmd); + break; + case CMD_DISSEL: + dev->rregs[ESP_RINTR] = 0; + esp_log("ESP Disable Selection\n"); + esp_raise_irq(dev); + break; + } + break; + case ESP_WBUSID: + case ESP_WSEL: + case ESP_WSYNTP: + case ESP_WSYNO: + break; + case ESP_CFG1: + case ESP_CFG2: + case ESP_CFG3: + case ESP_RES3: + case ESP_RES4: + dev->rregs[saddr] = val; + break; + case ESP_WCCF: + case ESP_WTEST: + break; + default: + esp_log("Unhandled writeb 0x%x = 0x%x\n", saddr, val); + break; + } + dev->wregs[saddr] = val; +} + + +static void +esp_pci_dma_memory_rw(esp_t *dev, uint8_t *buf, uint32_t len, int dir) +{ + int expected_dir; + + if (dev->dma_regs[DMA_CMD] & DMA_CMD_DIR) + expected_dir = READ_FROM_DEVICE; + else + expected_dir = WRITE_TO_DEVICE; + + esp_log("ESP DMA WBC = %d, addr = %06x, expected direction = %d, dir = %i\n", dev->dma_regs[DMA_WBC], dev->dma_regs[DMA_SPA], expected_dir, dir); + + if (dir != expected_dir) { + esp_log("ESP unexpected direction\n"); + return; + } + + if (dev->dma_regs[DMA_WBC] < len) + len = dev->dma_regs[DMA_WBC]; + + if (expected_dir) { + dma_bm_write(dev->dma_regs[DMA_SPA], buf, len, 4); + } else { + dma_bm_read(dev->dma_regs[DMA_SPA], buf, len, 4); + } + + /* update status registers */ + dev->dma_regs[DMA_WBC] -= len; + dev->dma_regs[DMA_WAC] += len; + if (dev->dma_regs[DMA_WBC] == 0) + dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE; +} + +static uint32_t +esp_pci_dma_read(esp_t *dev, uint16_t saddr) +{ + uint32_t ret; + + ret = dev->dma_regs[saddr]; + + if (saddr == DMA_STAT) { + if (dev->rregs[ESP_RSTAT] & STAT_INT) { + ret |= DMA_STAT_SCSIINT; + esp_log("ESP PCI DMA Read SCSI interrupt issued\n"); + } + if (!(dev->sbac & SBAC_STATUS)) { + dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT | + DMA_STAT_DONE); + esp_log("ESP PCI DMA Read done cleared\n"); + } + } + + esp_log("ESP PCI DMA Read regs addr = %04x, temp = %06x\n", saddr, ret); + return ret; +} + +static void +esp_pci_dma_write(esp_t *dev, uint16_t saddr, uint32_t val) +{ + uint32_t mask; + + switch (saddr) { + case DMA_CMD: + dev->dma_regs[saddr] = val; + esp_log("ESP PCI DMA Write CMD = %02x\n", val & DMA_CMD_MASK); + switch (val & DMA_CMD_MASK) { + case 0: /*IDLE*/ + esp_dma_enable(dev, 0); + break; + case 1: /*BLAST*/ + break; + case 2: /*ABORT*/ + scsi_device_command_stop(&scsi_devices[dev->bus][dev->id]); + break; + case 3: /*START*/ + dev->dma_regs[DMA_WBC] = dev->dma_regs[DMA_STC]; + dev->dma_regs[DMA_WAC] = dev->dma_regs[DMA_SPA]; + dev->dma_regs[DMA_WMAC] = dev->dma_regs[DMA_SMDLA]; + dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT | + DMA_STAT_DONE | DMA_STAT_ABORT | + DMA_STAT_ERROR | DMA_STAT_PWDN); + esp_dma_enable(dev, 1); + break; + default: /* can't happen */ + abort(); + } + break; + case DMA_STC: + case DMA_SPA: + case DMA_SMDLA: + dev->dma_regs[saddr] = val; + break; + case DMA_STAT: + if (dev->sbac & SBAC_STATUS) { + /* clear some bits on write */ + mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE; + dev->dma_regs[DMA_STAT] &= ~(val & mask); + } + break; + } +} + +static void +esp_pci_soft_reset(esp_t *dev) +{ + esp_irq(dev, 0); + esp_pci_hard_reset(dev); +} + +static void +esp_pci_hard_reset(esp_t *dev) +{ + esp_hard_reset(dev); + dev->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P + | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK); + dev->dma_regs[DMA_WBC] &= ~0xffff; + dev->dma_regs[DMA_WAC] = 0xffffffff; + dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT + | DMA_STAT_DONE | DMA_STAT_ABORT + | DMA_STAT_ERROR); + dev->dma_regs[DMA_WMAC] = 0xfffffffd; +} + +static uint32_t +esp_io_pci_read(esp_t *dev, uint32_t addr, unsigned int size) +{ + uint32_t ret; + + addr &= 0x7f; + + if (addr < 0x40) { + /* SCSI core reg */ + ret = esp_reg_read(dev, addr >> 2); + } else if (addr < 0x60) { + /* PCI DMA CCB */ + ret = esp_pci_dma_read(dev, (addr - 0x40) >> 2); + esp_log("ESP PCI DMA CCB read addr = %02x, ret = %02x\n", (addr - 0x40) >> 2, ret); + } else if (addr == 0x70) { + /* DMA SCSI Bus and control */ + ret = dev->sbac; + esp_log("ESP PCI SBAC read = %02x\n", ret); + } else { + /* Invalid region */ + ret = 0; + } + + /* give only requested data */ + ret >>= (addr & 3) * 8; + ret &= ~(~(uint64_t)0 << (8 * size)); + + esp_log("ESP PCI I/O read: addr = %02x, val = %02x\n", addr, ret); + return ret; +} + +static void +esp_io_pci_write(esp_t *dev, uint32_t addr, uint32_t val, unsigned int size) +{ + uint32_t current, mask; + int shift; + + addr &= 0x7f; + + if (size < 4 || addr & 3) { + /* need to upgrade request: we only support 4-bytes accesses */ + current = 0; + + if (addr < 0x40) { + current = dev->wregs[addr >> 2]; + } else if (addr < 0x60) { + current = dev->dma_regs[(addr - 0x40) >> 2]; + } else if (addr < 0x74) { + current = dev->sbac; + } + + shift = (4 - size) * 8; + mask = (~(uint32_t)0 << shift) >> shift; + + shift = ((4 - (addr & 3)) & 3) * 8; + val <<= shift; + val |= current & ~(mask << shift); + addr &= ~3; + size = 4; + } + + esp_log("ESP PCI I/O write: addr = %02x, val = %02x\n", addr, val); + + if (addr < 0x40) { + /* SCSI core reg */ + esp_reg_write(dev, addr >> 2, val); + } else if (addr < 0x60) { + /* PCI DMA CCB */ + esp_pci_dma_write(dev, (addr - 0x40) >> 2, val); + } else if (addr == 0x70) { + /* DMA SCSI Bus and control */ + dev->sbac = val; + } +} + + +static void +esp_pci_io_writeb(uint16_t addr, uint8_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + esp_io_pci_write(dev, addr, val, 1); +} + +static void +esp_pci_io_writew(uint16_t addr, uint16_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + esp_io_pci_write(dev, addr, val, 2); +} + +static void +esp_pci_io_writel(uint16_t addr, uint32_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + esp_io_pci_write(dev, addr, val, 4); +} + +static uint8_t +esp_pci_io_readb(uint16_t addr, void *p) +{ + esp_t *dev = (esp_t *)p; + return esp_io_pci_read(dev, addr, 1); +} + +static uint16_t +esp_pci_io_readw(uint16_t addr, void *p) +{ + esp_t *dev = (esp_t *)p; + return esp_io_pci_read(dev, addr, 2); +} + +static uint32_t +esp_pci_io_readl(uint16_t addr, void *p) +{ + esp_t *dev = (esp_t *)p; + return esp_io_pci_read(dev, addr, 4); +} + +static void +esp_io_set(esp_t *dev, uint32_t base, uint16_t len) +{ + esp_log("ESP: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + esp_pci_io_readb, esp_pci_io_readw, esp_pci_io_readl, + esp_pci_io_writeb, esp_pci_io_writew, esp_pci_io_writel, dev); +} + + +static void +esp_io_remove(esp_t *dev, uint32_t base, uint16_t len) +{ + esp_log("ESP: [PCI] Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + esp_pci_io_readb, esp_pci_io_readw, esp_pci_io_readl, + esp_pci_io_writeb, esp_pci_io_writew, esp_pci_io_writel, dev); +} + +static void +esp_bios_set_addr(esp_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->bios.mapping, base, 0x8000); +} + +static void +esp_bios_disable(esp_t *dev) +{ + mem_mapping_disable(&dev->bios.mapping); +} + +#define EE_ADAPT_SCSI_ID 64 +#define EE_MODE2 65 +#define EE_DELAY 66 +#define EE_TAG_CMD_NUM 67 +#define EE_ADAPT_OPTIONS 68 +#define EE_BOOT_SCSI_ID 69 +#define EE_BOOT_SCSI_LUN 70 +#define EE_CHKSUM1 126 +#define EE_CHKSUM2 127 + +#define EE_ADAPT_OPTION_F6_F8_AT_BOOT 0x01 +#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02 +#define EE_ADAPT_OPTION_INT13 0x04 +#define EE_ADAPT_OPTION_SCAM_SUPPORT 0x08 + +/*To do: make this separate from the SCSI card*/ +static void +dc390_save_eeprom(esp_t *dev) +{ + FILE *f = nvr_fopen(dev->nvr_path, "wb"); + if (!f) return; + fwrite(dev->eeprom.data, 1, 128, f); + fclose(f); +} + +static void +dc390_write_eeprom(esp_t *dev, int ena, int clk, int dat) +{ + /*Actual EEPROM is the same as the one used by the ATI cards, the 93cxx series.*/ + ati_eeprom_t *eeprom = &dev->eeprom; + uint8_t tick = eeprom->count; + uint8_t eedo = eeprom->out; + uint16_t address = eeprom->address; + uint8_t command = eeprom->opcode; + + esp_log("EEPROM CS=%02x,SK=%02x,DI=%02x,DO=%02x,tick=%d\n", + ena, clk, dat, eedo, tick); + + if (!eeprom->oldena && ena) { + esp_log("EEPROM Start chip select cycle\n"); + tick = 0; + command = 0; + address = 0; + } else if (eeprom->oldena && !ena) { + if (!eeprom->wp) { + uint8_t subcommand = address >> 4; + if (command == 0 && subcommand == 2) { + esp_log("EEPROM Erase All\n"); + for (address = 0; address < 64; address++) + eeprom->data[address] = 0xffff; + dc390_save_eeprom(dev); + } else if (command == 3) { + esp_log("EEPROM Erase Word\n"); + eeprom->data[address] = 0xffff; + dc390_save_eeprom(dev); + } else if (tick >= 26) { + if (command == 1) { + esp_log("EEPROM Write Word\n"); + eeprom->data[address] &= eeprom->dat; + dc390_save_eeprom(dev); + } else if (command == 0 && subcommand == 1) { + esp_log("EEPROM Write All\n"); + for (address = 0; address < 64; address++) + eeprom->data[address] &= eeprom->dat; + dc390_save_eeprom(dev); + } + } + } + eedo = 1; + esp_log("EEPROM DO read\n"); + } else if (ena && !eeprom->oldclk && clk) { + if (tick == 0) { + if (dat == 0) { + esp_log("EEPROM Got correct 1st start bit, waiting for 2nd start bit (1)\n"); + tick++; + } else { + esp_log("EEPROM Wrong 1st start bit (is 1, should be 0)\n"); + tick = 2; + } + } else if (tick == 1) { + if (dat != 0) { + esp_log("EEPROM Got correct 2nd start bit, getting command + address\n"); + tick++; + } else { + esp_log("EEPROM 1st start bit is longer than needed\n"); + } + } else if (tick < 4) { + tick++; + command <<= 1; + if (dat) + command += 1; + } else if (tick < 10) { + tick++; + address = (address << 1) | dat; + if (tick == 10) { + esp_log("EEPROM command = %02x, address = %02x (val = %04x)\n", command, + address, eeprom->data[address]); + if (command == 2) + eedo = 0; + address = address % 64; + if (command == 0) { + switch (address >> 4) { + case 0: + esp_log("EEPROM Write disable command\n"); + eeprom->wp = 1; + break; + case 1: + esp_log("EEPROM Write all command\n"); + break; + case 2: + esp_log("EEPROM Erase all command\n"); + break; + case 3: + esp_log("EEPROM Write enable command\n"); + eeprom->wp = 0; + break; + } + } else { + esp_log("EEPROM Read, write or erase word\n"); + eeprom->dat = eeprom->data[address]; + } + } + } else if (tick < 26) { + tick++; + if (command == 2) { + esp_log("EEPROM Read Word\n"); + eedo = ((eeprom->dat & 0x8000) != 0); + } + eeprom->dat <<= 1; + eeprom->dat += dat; + } else { + esp_log("EEPROM Additional unneeded tick, not processed\n"); + } + } + + eeprom->count = tick; + eeprom->oldena = ena; + eeprom->oldclk = clk; + eeprom->out = eedo; + eeprom->address = address; + eeprom->opcode = command; + esp_log("EEPROM EEDO = %d\n", eeprom->out); +} + +static void +dc390_load_eeprom(esp_t *dev) +{ + ati_eeprom_t *eeprom = &dev->eeprom; + uint8_t *nvr = (uint8_t *)eeprom->data; + int i; + uint16_t checksum = 0; + FILE *f; + + eeprom->out = 1; + + f = nvr_fopen(dev->nvr_path, "rb"); + if (f) { + esp_log("EEPROM Load\n"); + if (fread(nvr, 1, 128, f) != 128) + fatal("dc390_eeprom_load(): Error reading data\n"); + fclose(f); + } else { + for (i = 0; i < 16; i++) { + nvr[i * 2] = 0x57; + nvr[i * 2 + 1] = 0x00; + } + + esp_log("EEPROM Defaults\n"); + + nvr[EE_ADAPT_SCSI_ID] = 7; + nvr[EE_MODE2] = 0x0f; + nvr[EE_TAG_CMD_NUM] = 0x04; + nvr[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT | + EE_ADAPT_OPTION_BOOT_FROM_CDROM | + EE_ADAPT_OPTION_INT13; + for (i = 0; i < EE_CHKSUM1; i += 2) { + checksum += ((nvr[i] & 0xff) | (nvr[i + 1] << 8)); + esp_log("Checksum calc = %04x, nvr = %02x\n", checksum, nvr[i]); + } + + checksum = 0x1234 - checksum; + nvr[EE_CHKSUM1] = checksum & 0xff; + nvr[EE_CHKSUM2] = checksum >> 8; + esp_log("EEPROM Checksum = %04x\n", checksum); + } +} + +uint8_t esp_pci_regs[256]; +bar_t esp_pci_bar[2]; + + +static uint8_t +esp_pci_read(int func, int addr, void *p) +{ + esp_t *dev = (esp_t *)p; + + //esp_log("ESP PCI: Reading register %02X\n", addr & 0xff); + + switch (addr) { + case 0x00: + //esp_log("ESP PCI: Read DO line = %02x\n", dev->eeprom.out); + if (!dev->has_bios) + return 0x22; + else { + if (dev->eeprom.out) + return 0x22; + else { + dev->eeprom.out = 1; + return 2; + } + } + break; + case 0x01: + return 0x10; + case 0x02: + return 0x20; + case 0x03: + return 0x20; + case 0x04: + return esp_pci_regs[0x04] & 3; /*Respond to IO*/ + case 0x07: + return 2; + case 0x08: + return 0; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return esp_pci_bar[0].addr_regs[1]; + case 0x12: + return esp_pci_bar[0].addr_regs[2]; + case 0x13: + return esp_pci_bar[0].addr_regs[3]; + case 0x30: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[0]; + case 0x31: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[1]; + case 0x32: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[2]; + case 0x33: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[3]; + case 0x3C: + return dev->irq; + case 0x3D: + return PCI_INTA; + + case 0x40 ... 0x4f: + return esp_pci_regs[addr]; + } + + return(0); +} + + +static void +esp_pci_write(int func, int addr, uint8_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + uint8_t valxor; + int eesk; + int eedi; + + //esp_log("ESP PCI: Write value %02X to register %02X\n", val, addr); + + if ((addr >= 0x80) && (addr <= 0xFF)) { + if (addr == 0x80) { + eesk = val & 0x80 ? 1 : 0; + eedi = val & 0x40 ? 1 : 0; + dc390_write_eeprom(dev, 1, eesk, eedi); + } else if (addr == 0xc0) + dc390_write_eeprom(dev, 0, 0, 0); + //esp_log("ESP PCI: Write value %02X to register %02X\n", val, addr); + return; + } + + switch (addr) { + case 0x04: + valxor = (val & 3) ^ esp_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + esp_io_remove(dev, dev->PCIBase, 0x80); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) + esp_io_set(dev, dev->PCIBase, 0x80); + } + esp_pci_regs[addr] = val & 3; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + esp_io_remove(dev, dev->PCIBase, 0x80); + /* Then let's set the PCI regs. */ + esp_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + esp_pci_bar[0].addr &= 0xff00; + dev->PCIBase = esp_pci_bar[0].addr; + /* Log the new base. */ + //esp_log("ESP PCI: New I/O base is %04X\n" , dev->PCIBase); + /* We're done, so get out of the here. */ + if (esp_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) { + esp_io_set(dev, dev->PCIBase, 0x80); + } + } + return; + + case 0x30: case 0x31: case 0x32: case 0x33: + if (!dev->has_bios) + return; + /* BIOS Base set. */ + /* First, remove the old I/O. */ + esp_bios_disable(dev); + /* Then let's set the PCI regs. */ + esp_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + esp_pci_bar[1].addr &= 0xfff80001; + dev->BIOSBase = esp_pci_bar[1].addr & 0xfff80000; + /* Log the new base. */ + //esp_log("ESP PCI: New BIOS base is %08X\n" , dev->BIOSBase); + /* We're done, so get out of the here. */ + if (esp_pci_bar[1].addr & 0x00000001) + esp_bios_set_addr(dev, dev->BIOSBase); + return; + + case 0x3C: + esp_pci_regs[addr] = val; + dev->irq = val; + esp_log("ESP IRQ now: %i\n", val); + return; + + case 0x40 ... 0x4f: + esp_pci_regs[addr] = val; + return; + } +} + +static void * +dc390_init(const device_t *info) +{ + esp_t *dev; + + dev = malloc(sizeof(esp_t)); + memset(dev, 0x00, sizeof(esp_t)); + + dev->bus = scsi_get_bus(); + + dev->mca = 0; + + fifo8_create(&dev->fifo, ESP_FIFO_SZ); + fifo8_create(&dev->cmdfifo, ESP_CMDFIFO_SZ); + + dev->PCIBase = 0; + dev->MMIOBase = 0; + + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, esp_pci_read, esp_pci_write, dev); + + esp_pci_bar[0].addr_regs[0] = 1; + esp_pci_regs[0x04] = 3; + + dev->has_bios = device_get_config_int("bios"); + if (dev->has_bios) + rom_init(&dev->bios, DC390_ROM, 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + /* Enable our BIOS space in PCI, if needed. */ + if (dev->has_bios) { + esp_pci_bar[1].addr = 0xfff80000; + } else { + esp_pci_bar[1].addr = 0; + } + + if (dev->has_bios) + esp_bios_disable(dev); + + dev->nvr_path = "dc390.nvr"; + + /* Load the serial EEPROM. */ + dc390_load_eeprom(dev); + + esp_pci_hard_reset(dev); + + timer_add(&dev->timer, esp_callback, dev, 0); + + return(dev); +} + +static uint16_t +ncr53c90_in(uint16_t port, void *priv) +{ + esp_t *dev = (esp_t *)priv; + uint16_t ret = 0; + + port &= 0x1f; + + if (port >= 0x10) + ret = esp_reg_read(dev, port - 0x10); + else { + switch (port) { + case 0x02: + ret = dev->dma_86c01.mode; + break; + + case 0x0c: + ret = dev->dma_86c01.status; + break; + } + } + + esp_log("[%04X:%08X]: NCR53c90 DMA read port = %02x, ret = %02x\n", CS, cpu_state.pc, port, ret); + + return ret; +} + +static uint8_t +ncr53c90_inb(uint16_t port, void *priv) +{ + return ncr53c90_in(port, priv); +} + +static uint16_t +ncr53c90_inw(uint16_t port, void *priv) +{ + return (ncr53c90_in(port, priv) & 0xff) | (ncr53c90_in(port + 1, priv) << 8); +} + +static void +ncr53c90_out(uint16_t port, uint16_t val, void *priv) +{ + esp_t *dev = (esp_t *)priv; + + port &= 0x1f; + + esp_log("[%04X:%08X]: NCR53c90 DMA write port = %02x, val = %02x\n", CS, cpu_state.pc, port, val); + + if (port >= 0x10) + esp_reg_write(dev, port - 0x10, val); + else { + if (port == 0x02) { + dev->dma_86c01.mode = (val & 0x40); + } + } +} + +static void +ncr53c90_outb(uint16_t port, uint8_t val, void *priv) +{ + ncr53c90_out(port, val, priv); +} + +static void +ncr53c90_outw(uint16_t port, uint16_t val, void *priv) +{ + ncr53c90_out(port, val & 0xff, priv); + ncr53c90_out(port + 1, val >> 8, priv); +} + +static uint8_t +ncr53c90_mca_read(int port, void *priv) +{ + esp_t *dev = (esp_t *)priv; + + return(dev->pos_regs[port & 7]); +} + + +static void +ncr53c90_mca_write(int port, uint8_t val, void *priv) +{ + esp_t *dev = (esp_t *)priv; + static const uint16_t ncrmca_iobase[] = { + 0, 0x240, 0x340, 0x400, 0x420, 0x3240, 0x8240, 0xa240 + }; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + /* This is always necessary so that the old handler doesn't remain. */ + if (dev->Base != 0) { + io_removehandler(dev->Base, 0x20, + ncr53c90_inb, ncr53c90_inw, NULL, + ncr53c90_outb, ncr53c90_outw, NULL, dev); + } + + /* Get the new assigned I/O base address. */ + dev->Base = ncrmca_iobase[(dev->pos_regs[2] & 0x0e) >> 1]; + + /* Save the new IRQ and DMA channel values. */ + dev->irq = 3 + (2 * ((dev->pos_regs[2] & 0x30) >> 4)); + if (dev->irq == 9) + dev->irq = 2; + + dev->DmaChannel = dev->pos_regs[3] & 0x0f; + + /* + * Get misc SCSI config stuff. For now, we are only + * interested in the configured HA target ID. + */ + dev->HostID = 6 + ((dev->pos_regs[5] & 0x20) ? 1 : 0); + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + if (dev->Base != 0) { + /* Card enabled; register (new) I/O handler. */ + io_sethandler(dev->Base, 0x20, + ncr53c90_inb, ncr53c90_inw, NULL, + ncr53c90_outb, ncr53c90_outw, NULL, dev); + + esp_hard_reset(dev); + } + + /* Say hello. */ + esp_log("NCR 53c90: I/O=%04x, IRQ=%d, DMA=%d, HOST ID %i\n", + dev->Base, dev->irq, dev->DmaChannel, dev->HostID); + } +} + + +static uint8_t +ncr53c90_mca_feedb(void *priv) +{ + esp_t *dev = (esp_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + +static void * +ncr53c90_mca_init(const device_t *info) +{ + esp_t *dev; + + dev = malloc(sizeof(esp_t)); + memset(dev, 0x00, sizeof(esp_t)); + + dev->bus = scsi_get_bus(); + + dev->mca = 1; + + fifo8_create(&dev->fifo, ESP_FIFO_SZ); + fifo8_create(&dev->cmdfifo, ESP_CMDFIFO_SZ); + + dev->pos_regs[0] = 0x4d; /* MCA board ID */ + dev->pos_regs[1] = 0x7f; + mca_add(ncr53c90_mca_read, ncr53c90_mca_write, ncr53c90_mca_feedb, NULL, dev); + + esp_hard_reset(dev); + + timer_add(&dev->timer, esp_callback, dev, 0); + + return(dev); +} + +static void +esp_close(void *priv) +{ + esp_t *dev = (esp_t *)priv; + + if (dev) { + fifo8_destroy(&dev->fifo); + fifo8_destroy(&dev->cmdfifo); + + free(dev); + dev = NULL; + } +} + + +static const device_config_t bios_enable_config[] = { +// clang-format off + { + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +const device_t dc390_pci_device = { + .name = "Tekram DC-390 PCI", + .internal_name = "dc390", + .flags = DEVICE_PCI, + .local = 0, + .init = dc390_init, + .close = esp_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = bios_enable_config +}; + +const device_t ncr53c90_mca_device = { + .name = "NCR 53c90 MCA", + .internal_name = "ncr53c90", + .flags = DEVICE_MCA, + .local = 0, + .init = ncr53c90_mca_init, + .close = esp_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 9eab04354..cfcf8e816 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -40,11 +40,11 @@ #include <86box/scsi_device.h> #include <86box/scsi_spock.h> -#define SPOCK_U68_1990_ROM L"roms/scsi/ibm/64f4376.bin" -#define SPOCK_U69_1990_ROM L"roms/scsi/ibm/64f4377.bin" +#define SPOCK_U68_1990_ROM "roms/scsi/ibm/64f4376.bin" +#define SPOCK_U69_1990_ROM "roms/scsi/ibm/64f4377.bin" -#define SPOCK_U68_1991_ROM L"roms/scsi/ibm/92F2244.U68" -#define SPOCK_U69_1991_ROM L"roms/scsi/ibm/92F2245.U69" +#define SPOCK_U68_1991_ROM "roms/scsi/ibm/92F2244.U68" +#define SPOCK_U69_1991_ROM "roms/scsi/ibm/92F2245.U69" #define SPOCK_TIME (20) @@ -52,7 +52,6 @@ typedef enum { SCSI_STATE_IDLE, SCSI_STATE_SELECT, - SCSI_STATE_SELECT_FAILED, SCSI_STATE_SEND_COMMAND, SCSI_STATE_END_PHASE } scsi_state_t; @@ -102,33 +101,35 @@ typedef struct { typedef struct { rom_t bios_rom; - + int bios_ver; int irq, irq_inactive; - + uint8_t pos_regs[8]; uint8_t basic_ctrl; uint32_t command; - + uint8_t attention, attention_pending; int attention_wait; - + uint8_t cir[4], cir_pending[4]; uint8_t irq_status; - + uint32_t scb_addr; - + uint8_t status; get_complete_stat_t get_complete_stat; get_pos_info_t get_pos_info; scb_t scb; + int adapter_reset; int scb_id; + int adapter_id; int cmd_status; int cir_status; @@ -142,7 +143,7 @@ typedef struct { int lun_id; } dev_id[SCSI_ID_MAX]; - uint8_t last_status; + uint8_t last_status, bus; uint8_t cdb[12]; int cdb_len; int cdb_id; @@ -152,16 +153,16 @@ typedef struct { int irq_requests[SCSI_ID_MAX]; pc_timer_t callback_timer; - + int cmd_timer; - + int scb_state; int in_reset; int in_invalid; uint64_t temp_period; double media_period; - + scsi_state_t scsi_state; } spock_t; @@ -264,7 +265,7 @@ spock_rethink_irqs(spock_t *scsi) } } -static __inline void +static __inline void spock_set_irq(spock_t *scsi, int id, int type) { spock_log("spock_set_irq id=%i type=%x %02x\n", id, type, scsi->irq_status); @@ -273,7 +274,7 @@ spock_set_irq(spock_t *scsi, int id, int type) spock_rethink_irqs(scsi); } -static __inline void +static __inline void spock_clear_irq(spock_t *scsi, int id) { spock_log("spock_clear_irq id=%i\n", id); @@ -293,7 +294,7 @@ spock_write(uint16_t port, uint8_t val, void *p) spock_t *scsi = (spock_t *)p; spock_log("spock_write: port=%04x val=%02x %04x:%04x\n", port, val, CS, cpu_state.pc); - + switch (port & 7) { case 0: case 1: case 2: case 3: /*Command Interface Register*/ scsi->cir_pending[port & 3] = val; @@ -308,7 +309,7 @@ spock_write(uint16_t port, uint8_t val, void *p) scsi->attention_wait = 2; scsi->status |= STATUS_BUSY; break; - + case 5: /*Basic Control Register*/ if ((scsi->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { spock_log("Spock: SCSI reset and busy\n"); @@ -349,7 +350,7 @@ spock_read(uint16_t port, void *p) { spock_t *scsi = (spock_t *)p; uint8_t temp = 0xff; - + switch (port & 7) { case 0: case 1: case 2: case 3: /*Command Interface Register*/ temp = scsi->cir_pending[port & 3]; @@ -366,19 +367,20 @@ spock_read(uint16_t port, void *p) break; case 7: /*Basic Status Register*/ temp = scsi->status; + spock_log("Cir Status=%d\n", scsi->cir_status); if (scsi->cir_status == 0) { spock_log("Status Cmd Empty\n"); temp |= STATUS_CMD_EMPTY; } - if (scsi->cir_status == 3) { + else if (scsi->cir_status == 3) { spock_log("Status Cmd Full\n"); temp |= STATUS_CMD_FULL; } break; } - + spock_log("spock_read: port=%04x val=%02x %04x(%05x):%04x %02x\n", port, temp, CS, cs, cpu_state.pc, BH); - return temp; + return temp; } static uint16_t @@ -395,9 +397,9 @@ spock_readw(uint16_t port, void *p) temp = scsi->cir_pending[2] | (scsi->cir_pending[3] << 8); break; } - + spock_log("spock_readw: port=%04x val=%04x\n", port, temp); - return temp; + return temp; } static void @@ -421,7 +423,7 @@ spock_get_len(spock_t *scsi, scb_t *scb) if (scb->enable & ENABLE_PT) { for (i = 0; i < scsi->data_len; i += 8) { spock_rd_sge(scsi, scsi->data_ptr + i, &scb->sge); - + DataToTransfer += scb->sge.sys_buf_byte_count; } return(DataToTransfer); @@ -435,66 +437,68 @@ spock_process_imm_cmd(spock_t *scsi) { int i; int adapter_id, phys_id, lun_id; - - switch (scsi->command & CMD_MASK) { - case CMD_ASSIGN: - adapter_id = (scsi->command >> 16) & 15; - phys_id = (scsi->command >> 20) & 7; - lun_id = (scsi->command >> 24) & 7; + switch (scsi->command & CMD_MASK) { + case CMD_ASSIGN: + adapter_id = (scsi->command >> 16) & 15; + phys_id = (scsi->command >> 20) & 7; + lun_id = (scsi->command >> 24) & 7; if (adapter_id == 15) { - if (phys_id == 7) /*Device 15 always adapter*/ - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - else /*Can not re-assign device 15 (always adapter)*/ - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); - } else { - if (scsi->command & (1 << 23)) { - spock_log("Physical Device Number -1\n"); - scsi->dev_id[adapter_id].phys_id = -1; - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - } else if (phys_id == 7) { /*Can not assign adapter*/ - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); - } else { - scsi->dev_id[adapter_id].phys_id = phys_id; - scsi->dev_id[adapter_id].lun_id = lun_id; - spock_log("Assign: adapter dev=%x scsi ID=%i LUN=%i\n", adapter_id, scsi->dev_id[adapter_id].phys_id, scsi->dev_id[adapter_id].lun_id); - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - } - } + if (phys_id == 7) /*Device 15 always adapter*/ + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + else /*Can not re-assign device 15 (always adapter)*/ + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); + } else { + if (scsi->command & (1 << 23)) { + spock_log("Assign: adapter id=%d\n", adapter_id); + scsi->dev_id[adapter_id].phys_id = -1; + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + } else { + if (phys_id != scsi->adapter_id) { + scsi->dev_id[adapter_id].phys_id = phys_id; + scsi->dev_id[adapter_id].lun_id = lun_id; + spock_log("Assign: adapter dev=%x scsi ID=%i LUN=%i\n", adapter_id, scsi->dev_id[adapter_id].phys_id, scsi->dev_id[adapter_id].lun_id); + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + } else { /*Can not assign adapter*/ + spock_log("Assign: PUN=%d, cannot assign adapter\n", phys_id); + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); + } + } + } break; - case CMD_DMA_PACING_CONTROL: - scsi->pacing = scsi->cir[2]; - spock_log("Pacing control: %i\n", scsi->pacing); - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - break; + scsi->pacing = scsi->cir[2]; + spock_log("Pacing control: %i\n", scsi->pacing); + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + case CMD_FEATURE_CONTROL: + spock_log("Feature control: timeout=%is d-rate=%i\n", (scsi->command >> 16) & 0x1fff, scsi->command >> 29); + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + case CMD_INVALID_412: + spock_log("Invalid 412\n"); + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + case CMD_RESET: + spock_log("Reset Command\n"); + if ((scsi->attention & 0x0f) == 0x0f) { /*Adapter reset*/ + for (i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[scsi->bus][i]); + spock_log("Adapter Reset\n"); - case CMD_FEATURE_CONTROL: - spock_log("Feature control: timeout=%is d-rate=%i\n", (scsi->command >> 16) & 0x1fff, scsi->command >> 29); - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - break; + if (!scsi->adapter_reset) /*The early 1990 bios must have its boot drive + set to ID 6 according https://www.ardent-tool.com/IBM_SCSI/SCSI-A.html */ + scsi->adapter_reset = 1; - case CMD_INVALID_412: - spock_log("Invalid 412\n"); - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - break; - - case CMD_RESET: - spock_log("Reset Command\n"); - if ((scsi->attention & 15) == 15) { /*Adapter reset*/ - for (i = 0; i < 7; i++) - scsi_device_reset(&scsi_devices[i]); - spock_log("Adapter Reset\n"); - - scsi->scb_state = 0; + scsi->scb_state = 0; } - spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); - break; + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; - default: - fatal("scsi_callback: Bad command %02x\n", scsi->command); - break; - } + default: + fatal("scsi_callback: Bad command %02x\n", scsi->command); + break; + } } static void @@ -512,11 +516,11 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) for (c = 0; c < SCSI_ID_MAX; c++) spock_clear_irq(scsi, c); - if (scsi->in_reset == 1) { - scsi->basic_ctrl |= CTRL_IRQ_ENA; - spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); - } else - spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); + if (scsi->in_reset == 1) { + scsi->basic_ctrl |= CTRL_IRQ_ENA; + spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); + } else + spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); /*Reset device mappings*/ for (c = 0; c < 7; c++) { @@ -529,35 +533,37 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->in_reset = 0; return; } - + if (scsi->in_invalid) { spock_log("Invalid command\n"); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_ERROR); scsi->in_invalid = 0; return; } - + + spock_log("SCB State = %d\n", scsi->scb_state); + do { old_scb_state = scsi->scb_state; - + switch (scsi->scb_state) { case 0: /* Idle */ break; - - case 1: /* Select */ - if (scsi->dev_id[scsi->scb_id].phys_id == -1) { - uint16_t term_stat_block_addr7 = (0xe << 8) | 0; - uint16_t term_stat_block_addr8 = (0xa << 8) | 0; - spock_log("Start failed, SCB ID = %d\n", scsi->scb_id); - spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); - scsi->scb_state = 0; - dma_bm_write(scb->term_status_block_addr + 0x7*2, (uint8_t *)&term_stat_block_addr7, 2, 2); - dma_bm_write(scb->term_status_block_addr + 0x8*2, (uint8_t *)&term_stat_block_addr8, 2, 2); - break; - } - + case 1: /* Select */ + if (scsi->dev_id[scsi->scb_id].phys_id == -1) { + uint16_t term_stat_block_addr7 = (0xe << 8) | 0; + uint16_t term_stat_block_addr8 = (0xa << 8) | 0; + + spock_log("Start failed, SCB ID = %d\n", scsi->scb_id); + spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); + scsi->scb_state = 0; + dma_bm_write(scb->term_status_block_addr + 0x7*2, (uint8_t *)&term_stat_block_addr7, 2, 2); + dma_bm_write(scb->term_status_block_addr + 0x8*2, (uint8_t *)&term_stat_block_addr8, 2, 2); + break; + } + dma_bm_read(scsi->scb_addr, (uint8_t *)&scb->command, 2, 2); dma_bm_read(scsi->scb_addr + 2, (uint8_t *)&scb->enable, 2, 2); dma_bm_read(scsi->scb_addr + 4, (uint8_t *)&scb->lba_addr, 4, 2); @@ -577,23 +583,19 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) " Terminate status block addr = %08x\n" " SCB chain address = %08x\n" " Block count = %04x\n" - " Block length = %04x\n", + " Block length = %04x\n" + " SCB id = %d, Phys id = %d\n", scb->command, scb->enable, scb->lba_addr, scb->sge.sys_buf_addr, scb->sge.sys_buf_byte_count, scb->term_status_block_addr, scb->scb_chain_addr, - scb->block_count, scb->block_length); - - if (scb->command == 0x245f) { /*Issued by NT October 1991 and December 1991 (Undocumented version of Send Other SCSI?)*/ - spock_log("Send Other SCSI (BIOS?)\n"); - scb->command = CMD_SEND_OTHER_SCSI; - } - + scb->block_count, scb->block_length, scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); + switch (scb->command & CMD_MASK) { case CMD_GET_COMPLETE_STATUS: { spock_log("Get Complete Status\n"); get_complete_stat_t *get_complete_stat = &scsi->get_complete_stat; - + get_complete_stat->scb_status = 0x201; get_complete_stat->retry_count = 0; get_complete_stat->residual_byte_count = 0; @@ -635,7 +637,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) { spock_log("Get POS Info\n"); get_pos_info_t *get_pos_info = &scsi->get_pos_info; - + get_pos_info->pos = 0x8eff; get_pos_info->pos1 = scsi->pos_regs[3] | (scsi->pos_regs[2] << 8); get_pos_info->pos2 = 0x0e | (scsi->pos_regs[4] << 8); @@ -645,7 +647,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) get_pos_info->pos6 = (30 << 8) | 1; get_pos_info->pos7 = 0; get_pos_info->pos8 = 0; - + dma_bm_write(scb->sge.sys_buf_addr, (uint8_t *)&get_pos_info->pos, 2, 2); dma_bm_write(scb->sge.sys_buf_addr + 2, (uint8_t *)&get_pos_info->pos1, 2, 2); dma_bm_write(scb->sge.sys_buf_addr + 4, (uint8_t *)&get_pos_info->pos2, 2, 2); @@ -660,7 +662,11 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) break; case CMD_DEVICE_INQUIRY: - spock_log("Device Inquiry\n"); + if (scb->command != CMD_DEVICE_INQUIRY) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + spock_log("Device Inquiry, ID=%d\n", scsi->cdb_id); scsi->cdb[0] = GPCMD_INQUIRY; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = 0; /*Page code*/ @@ -668,7 +674,6 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->cdb[4] = scb->sge.sys_buf_byte_count; /*Allocation length*/ scsi->cdb[5] = 0; /*Control*/ scsi->cdb_len = 6; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->data_ptr = scb->sge.sys_buf_addr; scsi->data_len = scb->sge.sys_buf_byte_count; scsi->scsi_state = SCSI_STATE_SELECT; @@ -676,17 +681,24 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_SEND_OTHER_SCSI: - spock_log("Send Other SCSI\n"); + if (scb->command != CMD_SEND_OTHER_SCSI) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + spock_log("Send Other SCSI, SCB ID=%d, PHYS ID=%d, reset=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->adapter_reset); dma_bm_read(scsi->scb_addr + 0x18, scsi->cdb, 12, 2); scsi->cdb[1] = (scsi->cdb[1] & 0x1f) | (scsi->dev_id[scsi->scb_id].lun_id << 5); /*Patch correct LUN into command*/ scsi->cdb_len = (scb->lba_addr & 0xff) ? (scb->lba_addr & 0xff) : 6; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->scsi_state = SCSI_STATE_SELECT; scsi->scb_state = 2; return; case CMD_READ_DEVICE_CAPACITY: - spock_log("Device Capacity\n"); + if (scb->command != CMD_READ_DEVICE_CAPACITY) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + spock_log("Device Capacity, SCB ID=%d, PHYS ID=%d, reset=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->adapter_reset); scsi->cdb[0] = GPCMD_READ_CDROM_CAPACITY; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = 0; /*LBA*/ @@ -698,13 +710,16 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->cdb[8] = 0; scsi->cdb[9] = 0; /*Control*/ scsi->cdb_len = 10; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->scsi_state = SCSI_STATE_SELECT; scsi->scb_state = 2; return; case CMD_READ_DATA: - spock_log("Device Read Data\n"); + if (scb->command != CMD_READ_DATA) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + spock_log("Device Read Data, SCB ID=%d, PHYS ID=%d, reset=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->adapter_reset); scsi->cdb[0] = GPCMD_READ_10; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = (scb->lba_addr >> 24) & 0xff; /*LBA*/ @@ -716,12 +731,15 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->cdb[8] = scb->block_count & 0xff; scsi->cdb[9] = 0; /*Control*/ scsi->cdb_len = 10; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->scsi_state = SCSI_STATE_SELECT; scsi->scb_state = 2; return; case CMD_WRITE_DATA: + if (scb->command != CMD_WRITE_DATA) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; spock_log("Device Write Data\n"); scsi->cdb[0] = GPCMD_WRITE_10; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ @@ -734,12 +752,15 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->cdb[8] = scb->block_count & 0xff; scsi->cdb[9] = 0; /*Control*/ scsi->cdb_len = 10; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->scsi_state = SCSI_STATE_SELECT; scsi->scb_state = 2; return; - + case CMD_VERIFY: + if (scb->command != CMD_VERIFY) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; spock_log("Device Verify\n"); scsi->cdb[0] = GPCMD_VERIFY_10; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ @@ -752,14 +773,17 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->cdb[8] = scb->block_count & 0xff; scsi->cdb[9] = 0; /*Control*/ scsi->cdb_len = 10; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->data_len = 0; scsi->scsi_state = SCSI_STATE_SELECT; scsi->scb_state = 2; return; - + case CMD_REQUEST_SENSE: - spock_log("Device Request Sense\n"); + if (scb->command != CMD_REQUEST_SENSE) + scsi->cdb_id = scsi->scb_id; + else + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + spock_log("Device Request Sense, ID=%d\n", scsi->cdb_id); scsi->cdb[0] = GPCMD_REQUEST_SENSE; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = 0; @@ -767,42 +791,44 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->cdb[4] = scb->sge.sys_buf_byte_count; /*Allocation length*/ scsi->cdb[5] = 0; scsi->cdb_len = 6; - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; scsi->scsi_state = SCSI_STATE_SELECT; scsi->scb_state = 2; return; } break; - + case 2: /* Wait */ - if (scsi->scsi_state == SCSI_STATE_IDLE) { - if (scsi->last_status == SCSI_STATUS_OK) { - scsi->scb_state = 3; - spock_log("Status is Good on device ID %d\n", scsi->cdb_id); - } else if (scsi->last_status == SCSI_STATUS_CHECK_CONDITION) { - uint16_t term_stat_block_addr7 = (0xc << 8) | 2; - uint16_t term_stat_block_addr8 = 0x20; - uint16_t term_stat_block_addrb = scsi->scb_addr & 0xffff; - uint16_t term_stat_block_addrc = scsi->scb_addr >> 16; - - spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); - scsi->scb_state = 0; - spock_log("Status Check Condition on device ID %d\n", scsi->cdb_id); - dma_bm_write(scb->term_status_block_addr + 0x7*2, (uint8_t *)&term_stat_block_addr7, 2, 2); - dma_bm_write(scb->term_status_block_addr + 0x8*2, (uint8_t *)&term_stat_block_addr8, 2, 2); - dma_bm_write(scb->term_status_block_addr + 0xb*2, (uint8_t *)&term_stat_block_addrb, 2, 2); - dma_bm_write(scb->term_status_block_addr + 0xc*2, (uint8_t *)&term_stat_block_addrc, 2, 2); - } - } else if (scsi->scsi_state == SCSI_STATE_SELECT_FAILED) { - uint16_t term_stat_block_addr7 = (0xc << 8) | 2; - uint16_t term_stat_block_addr8 = 0x10; - spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); - scsi->scb_state = 0; - dma_bm_write(scb->term_status_block_addr + 0x7*2, (uint8_t *)&term_stat_block_addr7, 2, 2); - dma_bm_write(scb->term_status_block_addr + 0x8*2, (uint8_t *)&term_stat_block_addr8, 2, 2); - } + if (scsi->scsi_state == SCSI_STATE_IDLE) { + if (scsi_device_present(&scsi_devices[scsi->bus][scsi->cdb_id])) { + if (scsi->last_status == SCSI_STATUS_OK) { + scsi->scb_state = 3; + spock_log("Status is Good on device ID %d, reset = %d\n", scsi->scb_id, scsi->adapter_reset); + } else if (scsi->last_status == SCSI_STATUS_CHECK_CONDITION) { + uint16_t term_stat_block_addr7 = (0xc << 8) | 2; + uint16_t term_stat_block_addr8 = 0x20; + uint16_t term_stat_block_addrb = scsi->scb_addr & 0xffff; + uint16_t term_stat_block_addrc = scsi->scb_addr >> 16; + + spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); + scsi->scb_state = 0; + spock_log("Status Check Condition on device ID %d, reset = %d\n", scsi->scb_id, scsi->adapter_reset); + dma_bm_write(scb->term_status_block_addr + 0x7*2, (uint8_t *)&term_stat_block_addr7, 2, 2); + dma_bm_write(scb->term_status_block_addr + 0x8*2, (uint8_t *)&term_stat_block_addr8, 2, 2); + dma_bm_write(scb->term_status_block_addr + 0xb*2, (uint8_t *)&term_stat_block_addrb, 2, 2); + dma_bm_write(scb->term_status_block_addr + 0xc*2, (uint8_t *)&term_stat_block_addrc, 2, 2); + } + } else { + uint16_t term_stat_block_addr7 = (0xc << 8) | 2; + uint16_t term_stat_block_addr8 = 0x10; + spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); + scsi->scb_state = 0; + spock_log("Status Check Condition on device ID %d on no device, reset = %d\n", scsi->scb_id, scsi->adapter_reset); + dma_bm_write(scb->term_status_block_addr + 0x7*2, (uint8_t *)&term_stat_block_addr7, 2, 2); + dma_bm_write(scb->term_status_block_addr + 0x8*2, (uint8_t *)&term_stat_block_addr8, 2, 2); + } + } break; - + case 3: /* Complete */ if (scb->enable & 1) { scsi->scb_state = 1; @@ -828,15 +854,15 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) switch (scsi->scsi_state) { case SCSI_STATE_IDLE: break; - + case SCSI_STATE_SELECT: - if ((scsi->cdb_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[scsi->cdb_id])) { + spock_log("Selecting ID %d\n", scsi->cdb_id); + if ((scsi->cdb_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[scsi->bus][scsi->cdb_id])) { scsi->scsi_state = SCSI_STATE_SEND_COMMAND; spock_log("Device selected at ID %i\n", scsi->cdb_id); - break; } else { spock_log("Device selection failed at ID %i\n", scsi->cdb_id); - scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + scsi->scsi_state = SCSI_STATE_IDLE; if (!scsi->cmd_timer) { spock_log("Callback to reset\n"); scsi->cmd_timer = 1; @@ -844,12 +870,9 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) spock_add_to_period(scsi, 1); } break; - - case SCSI_STATE_SELECT_FAILED: - break; case SCSI_STATE_SEND_COMMAND: - sd = &scsi_devices[scsi->cdb_id]; + sd = &scsi_devices[scsi->bus][scsi->cdb_id]; memset(scsi->temp_cdb, 0x00, 12); if (scsi->cdb_len < 12) { @@ -861,14 +884,17 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) 12); spock_add_to_period(scsi, 12); } - + scsi->data_ptr = scb->sge.sys_buf_addr; scsi->data_len = scb->sge.sys_buf_byte_count; - - sd->buffer_length = spock_get_len(scsi, scb); - + + if (scb->enable & 0x400) + sd->buffer_length = -1; + else + sd->buffer_length = spock_get_len(scsi, scb); + scsi_device_command_phase0(sd, scsi->temp_cdb); - spock_log("SCSI ID %i: Command %02X: CDB1 = %02x, LUN = %i, Buffer Length %i, SCSI Phase %02X\n", scsi->cdb_id, scsi->temp_cdb[0], scsi->temp_cdb[1], scsi->dev_id[scsi->scb_id].lun_id, sd->buffer_length, sd->phase); + spock_log("SCSI ID %i: Current CDB[0] = %02x, LUN = %i, data len = %i, max len = %i, phase val = %02x\n", scsi->cdb_id, scsi->temp_cdb[0], scsi->temp_cdb[1] >> 5, sd->buffer_length, spock_get_len(scsi, scb), sd->phase); if (sd->phase != SCSI_PHASE_STATUS && sd->buffer_length > 0) { p = scsi_device_get_callback(sd); @@ -876,20 +902,20 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) spock_add_to_period(scsi, sd->buffer_length); else scsi->media_period += p; - + if (scb->enable & ENABLE_PT) { int32_t buflen = sd->buffer_length; int sg_pos = 0; uint32_t DataTx = 0; uint32_t Address; - + if (scb->sge.sys_buf_byte_count > 0) { for (c = 0; c < scsi->data_len; c += 8) { spock_rd_sge(scsi, scsi->data_ptr + c, &scb->sge); - + Address = scb->sge.sys_buf_addr; DataTx = MIN((int) scb->sge.sys_buf_byte_count, buflen); - + if ((sd->phase == SCSI_PHASE_DATA_IN) && DataTx) { spock_log("Writing S/G segment %i: length %i, pointer %08X\n", c, DataTx, Address); dma_bm_write(Address, &sd->sc->temp_buffer[sg_pos], DataTx, 2); @@ -897,15 +923,16 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) spock_log("Reading S/G segment %i: length %i, pointer %08X\n", c, DataTx, Address); dma_bm_read(Address, &sd->sc->temp_buffer[sg_pos], DataTx, 2); } - + sg_pos += scb->sge.sys_buf_byte_count; buflen -= scb->sge.sys_buf_byte_count; - + if (buflen < 0) buflen = 0; } } } else { + spock_log("Normal Transfer\n"); if (sd->phase == SCSI_PHASE_DATA_IN) { dma_bm_write(scsi->data_ptr, sd->sc->temp_buffer, MIN(sd->buffer_length, (int)scsi->data_len), 2); } else if (sd->phase == SCSI_PHASE_DATA_OUT) @@ -921,7 +948,7 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) case SCSI_STATE_END_PHASE: scsi->scsi_state = SCSI_STATE_IDLE; - spock_log("State to idle\n"); + spock_log("State to idle, cmd timer %d\n", scsi->cmd_timer); if (!scsi->cmd_timer) { scsi->cmd_timer = 1; } @@ -943,7 +970,7 @@ spock_callback(void *priv) if (scsi->cmd_timer) { scsi->cmd_timer--; if (!scsi->cmd_timer) { - spock_execute_cmd(scsi, scb); + spock_execute_cmd(scsi, scb); } } @@ -958,7 +985,7 @@ spock_callback(void *priv) scsi->cir[2] = scsi->cir_pending[2]; scsi->cir[3] = scsi->cir_pending[3]; scsi->cir_status = 0; - + switch (scsi->attention >> 4) { case 1: /*Immediate command*/ scsi->cmd_status = 0x0a; @@ -973,16 +1000,16 @@ spock_callback(void *priv) break; } break; - + case 3: case 4: case 0x0f: /*Start SCB*/ scsi->cmd_status = 1; scsi->scb_addr = scsi->cir[0] | (scsi->cir[1] << 8) | (scsi->cir[2] << 16) | (scsi->cir[3] << 24); scsi->scb_id = scsi->attention & 0x0f; scsi->cmd_timer = SPOCK_TIME * 2; - spock_log("Start SCB at %08x\n", scsi->scb_addr); + spock_log("Start SCB at ID = %d\n", scsi->scb_id); scsi->scb_state = 1; break; - + case 5: /*Invalid*/ case 0x0a: /*Invalid*/ scsi->in_invalid = 1; @@ -998,13 +1025,13 @@ spock_callback(void *priv) } spock_process_scsi(scsi, scb); - + period = 0.2 * ((double) scsi->temp_period); timer_on(&scsi->callback_timer, (scsi->media_period + period + 10.0), 0); spock_log("Temporary period: %lf us (%" PRIi64 " periods)\n", scsi->callback_timer.period, scsi->temp_period); } -static void +static void spock_mca_write(int port, uint8_t val, void *priv) { spock_t *scsi = (spock_t *)priv; @@ -1012,34 +1039,28 @@ spock_mca_write(int port, uint8_t val, void *priv) if (port < 0x102) return; - spock_log("spock_mca_write: port=%04x val=%02x %04x:%04x\n", port, val, CS, cpu_state.pc); - io_removehandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); mem_mapping_disable(&scsi->bios_rom.mapping); - + scsi->pos_regs[port & 7] = val; - spock_log("SCSI pos reg write POS2 = %02x, POS3 = %02x, POS4 = %02x\n", scsi->pos_regs[2], scsi->pos_regs[3], scsi->pos_regs[4]); + scsi->adapter_id = (scsi->pos_regs[3] & 0xe0) >> 5; if (scsi->pos_regs[2] & 1) { - spock_log("spock scsi io = %04x\n", (((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540); io_sethandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); if ((scsi->pos_regs[2] >> 4) == 0x0f) mem_mapping_disable(&scsi->bios_rom.mapping); else { - spock_log("Spock BIOS segment select (hex val) = %02x, enabled bios area is %s\n", scsi->pos_regs[2] >> 4, (scsi->pos_regs[4] & 0x80) ? "32KB" : "16KB"); mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); } } } -static uint8_t +static uint8_t spock_mca_read(int port, void *priv) { spock_t *scsi = (spock_t *)priv; - - spock_log("spock_mca_read: port=%04x %02x %04x:%04x\n", port, scsi->pos_regs[port & 7], CS,cpu_state.pc); - + return scsi->pos_regs[port & 7]; } @@ -1056,7 +1077,7 @@ spock_mca_reset(void *priv) { spock_t *scsi = (spock_t *)priv; int i; - + scsi->in_reset = 2; scsi->cmd_timer = SPOCK_TIME * 50; scsi->status = STATUS_BUSY; @@ -1067,8 +1088,10 @@ spock_mca_reset(void *priv) scsi->basic_ctrl = 0; /* Reset all devices on controller reset. */ - for (i = 0; i < 7; i++) - scsi_device_reset(&scsi_devices[i]); + for (i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[scsi->bus][i]); + + scsi->adapter_reset = 0; } static void * @@ -1077,85 +1100,94 @@ spock_init(const device_t *info) int c; spock_t *scsi = malloc(sizeof(spock_t)); memset(scsi, 0x00, sizeof(spock_t)); - + + scsi->bus = scsi_get_bus(); + scsi->irq = 14; - + scsi->bios_ver = device_get_config_int("bios_ver"); - - if (scsi->bios_ver) - rom_init_interleaved(&scsi->bios_rom, SPOCK_U68_1991_ROM, SPOCK_U69_1991_ROM, - 0xc8000, 0x8000, 0x7fff, 0x4000, MEM_MAPPING_EXTERNAL); - else - rom_init_interleaved(&scsi->bios_rom, SPOCK_U68_1990_ROM, SPOCK_U69_1990_ROM, - 0xc8000, 0x8000, 0x7fff, 0x4000, MEM_MAPPING_EXTERNAL); - mem_mapping_disable(&scsi->bios_rom.mapping); + switch (scsi->bios_ver) { + case 1: + rom_init_interleaved(&scsi->bios_rom, SPOCK_U68_1991_ROM, SPOCK_U69_1991_ROM, + 0xc8000, 0x8000, 0x7fff, 0x4000, MEM_MAPPING_EXTERNAL); + break; + case 0: + rom_init_interleaved(&scsi->bios_rom, SPOCK_U68_1990_ROM, SPOCK_U69_1990_ROM, + 0xc8000, 0x8000, 0x7fff, 0x4000, MEM_MAPPING_EXTERNAL); + break; + } + mem_mapping_disable(&scsi->bios_rom.mapping); - scsi->pos_regs[0] = 0xff; - scsi->pos_regs[1] = 0x8e; + scsi->pos_regs[0] = 0xff; + scsi->pos_regs[1] = 0x8e; mca_add(spock_mca_read, spock_mca_write, spock_mca_feedb, spock_mca_reset, scsi); scsi->in_reset = 2; scsi->cmd_timer = SPOCK_TIME * 50; scsi->status = STATUS_BUSY; - for (c = 0; c < (SCSI_ID_MAX-1); c++) - scsi->dev_id[c].phys_id = -1; + for (c = 0; c < (SCSI_ID_MAX-1); c++) { + scsi->dev_id[c].phys_id = -1; + } - scsi->dev_id[SCSI_ID_MAX-1].phys_id = 7; + scsi->dev_id[SCSI_ID_MAX-1].phys_id = scsi->adapter_id; timer_add(&scsi->callback_timer, spock_callback, scsi, 1); scsi->callback_timer.period = 10.0; timer_set_delay_u64(&scsi->callback_timer, (uint64_t) (scsi->callback_timer.period * ((double) TIMER_USEC))); - + return scsi; } -static void +static void spock_close(void *p) { - spock_t *scsi = (spock_t *)p; - + spock_t *scsi = (spock_t *)p; + if (scsi) { free(scsi); scsi = NULL; } } -static int +static int spock_available(void) { return rom_present(SPOCK_U68_1991_ROM) && rom_present(SPOCK_U69_1991_ROM) && - rom_present(SPOCK_U68_1990_ROM) && rom_present(SPOCK_U69_1990_ROM); + rom_present(SPOCK_U68_1990_ROM) && rom_present(SPOCK_U69_1990_ROM); } static const device_config_t spock_rom_config[] = { - { - "bios_ver", "BIOS Version", CONFIG_SELECTION, "", 1, - { - { - "1991 BIOS (>1GB)", 1 - }, - { - "1990 BIOS", 0 - }, - { - "" - } - }, +// clang-format off + { + .name = "bios_ver", + .description = "BIOS Version", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "1991 BIOS (>1GB)", .value = 1 }, + { .description = "1990 BIOS", .value = 0 }, + { .description = "" } }, - { - "", "", -1 - } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -const device_t spock_device = -{ - "IBM PS/2 SCSI Adapter (Spock)", - DEVICE_MCA, - 0, - spock_init, spock_close, NULL, - spock_available, - NULL, NULL, - spock_rom_config +const device_t spock_device = { + .name = "IBM PS/2 SCSI Adapter (Spock)", + .internal_name = "spock", + .flags = DEVICE_MCA, + .local = 0, + .init = spock_init, + .close = spock_close, + .reset = NULL, + { .available = spock_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = spock_rom_config }; diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index a3e8d2f0d..5cd1f6d8f 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -85,13 +85,15 @@ x54x_irq(x54x_t *dev, int set) else irq = dev->Irq; - if (dev->bus & DEVICE_PCI) { + if (dev->card_bus & DEVICE_PCI) { x54x_log("PCI IRQ: %02X, PCI_INTA\n", dev->pci_slot); if (set) pci_set_irq(dev->pci_slot, PCI_INTA); else pci_clear_irq(dev->pci_slot, PCI_INTA); } else { + x54x_log("%sing IRQ %i\n", set ? "Rais" : "Lower", irq); + if (set) { if (dev->interrupt_type) int_type = dev->interrupt_type(dev); @@ -153,9 +155,9 @@ clear_irq(x54x_t *dev) static void -target_check(uint8_t id) +target_check(x54x_t *dev, uint8_t id) { - if (! scsi_device_valid(&scsi_devices[id])) + if (! scsi_device_valid(&scsi_devices[dev->bus][id])) fatal("BIOS INT13 device on ID %02i has disappeared\n", id); } @@ -430,13 +432,15 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) if (!ret) { /* Get pointer to selected device. */ - dev = &scsi_devices[cmd->id]; + dev = &scsi_devices[x54x->bus][cmd->id]; dev->buffer_length = 0; if (! scsi_device_present(dev)) { x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); ret = 0x80; } else { + scsi_device_identify(dev, 0xff); + if ((dev->type == SCSI_REMOVABLE_CDROM) && !(x54x->flags & X54X_CDROM_BOOT)) { x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id); return(0x80); @@ -455,7 +459,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) break; case 0x01: /* Read Status of Last Operation */ - target_check(cmd->id); + target_check(x54x, cmd->id); /* * Assuming 14 bytes because that is the default @@ -475,7 +479,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x03: /* Write Desired Sectors from Memory */ case 0x04: /* Verify Desired Sectors */ case 0x0c: /* Seek */ - target_check(cmd->id); + target_check(x54x, cmd->id); cdb[0] = bios_cmd_to_scsi[cmd->command]; cdb[1] = (cmd->lun & 7) << 5; @@ -515,7 +519,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x07: /* Format Unit */ case 0x10: /* Test Drive Ready */ case 0x11: /* Recalibrate */ - target_check(cmd->id); + target_check(x54x, cmd->id); cdb[0] = bios_cmd_to_scsi[cmd->command]; cdb[1] = (cmd->lun & 7) << 5; @@ -525,7 +529,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x08: /* Read Drive Parameters */ case 0x15: /* Read DASD Type */ - target_check(cmd->id); + target_check(x54x, cmd->id); dev->buffer_length = 6; @@ -541,7 +545,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) break; } - + x54x_log("BIOS Request %02X complete: %02X\n", cmd->command, ret); return(ret); } @@ -618,7 +622,7 @@ x54x_ccb(x54x_t *dev) static void x54x_mbi(x54x_t *dev) -{ +{ Req_t *req = &dev->Req; // uint32_t CCBPointer = req->CCBPointer; addr24 CCBPointer; @@ -754,7 +758,7 @@ x54x_set_residue(x54x_t *dev, Req_t *req, int32_t TransferLength) { uint32_t Residue = 0; addr24 Residue24; - int32_t BufLen = scsi_devices[req->TargetID].buffer_length; + int32_t BufLen = scsi_devices[dev->bus][req->TargetID].buffer_length; uint8_t bytes[4] = { 0, 0, 0, 0 }; if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || @@ -788,7 +792,7 @@ x54x_buf_dma_transfer(x54x_t *dev, Req_t *req, int Is24bit, int TransferLength, uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); uint32_t Address, i; - int32_t BufLen = scsi_devices[req->TargetID].buffer_length; + int32_t BufLen = scsi_devices[dev->bus][req->TargetID].buffer_length; uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))); uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))); int sg_pos = 0; @@ -820,11 +824,11 @@ x54x_buf_dma_transfer(x54x_t *dev, Req_t *req, int Is24bit, int TransferLength, if (read_from_host && DataToTransfer) { x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - dma_bm_read(Address, &(scsi_devices[req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer, dev->transfer_size); + dma_bm_read(Address, &(scsi_devices[dev->bus][req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer, dev->transfer_size); } else if (write_to_host && DataToTransfer) { x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - dma_bm_write(Address, &(scsi_devices[req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer, dev->transfer_size); + dma_bm_write(Address, &(scsi_devices[dev->bus][req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer, dev->transfer_size); } else x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); @@ -844,9 +848,9 @@ x54x_buf_dma_transfer(x54x_t *dev, Req_t *req, int Is24bit, int TransferLength, if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { if (read_from_host) - dma_bm_read(Address, scsi_devices[req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength), dev->transfer_size); + dma_bm_read(Address, scsi_devices[dev->bus][req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength), dev->transfer_size); else if (write_to_host) - dma_bm_write(Address, scsi_devices[req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength), dev->transfer_size); + dma_bm_write(Address, scsi_devices[dev->bus][req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength), dev->transfer_size); } } } @@ -892,7 +896,7 @@ SenseBufferFree(x54x_t *dev, Req_t *req, int Copy) uint8_t temp_sense[256]; if (SenseLength && Copy) { - scsi_device_request_sense(&scsi_devices[req->TargetID], temp_sense, SenseLength); + scsi_device_request_sense(&scsi_devices[dev->bus][req->TargetID], temp_sense, SenseLength); /* * The sense address, in 32-bit mode, is located in the @@ -921,7 +925,7 @@ x54x_scsi_cmd(x54x_t *dev) uint32_t i, target_cdb_len = 12; scsi_device_t *sd; - sd = &scsi_devices[req->TargetID]; + sd = &scsi_devices[dev->bus][req->TargetID]; target_cdb_len = 12; dev->target_data_len = x54x_get_length(dev, req, bit24); @@ -961,7 +965,7 @@ x54x_scsi_cmd(x54x_t *dev) else dev->callback_sub_phase = 2; - x54x_log("scsi_devices[%02i].Status = %02X\n", id, sd->status); + x54x_log("scsi_devices[%02i][%02i].Status = %02X\n", dev->bus, req->TargetID, sd->status); } @@ -973,7 +977,7 @@ x54x_scsi_cmd_phase1(x54x_t *dev) uint8_t bit24 = !!req->Is24bit; scsi_device_t *sd; - sd = &scsi_devices[req->TargetID]; + sd = &scsi_devices[dev->bus][req->TargetID]; if (dev->scsi_cmd_phase != SCSI_PHASE_STATUS) { if ((dev->temp_cdb[0] != 0x03) || (req->CmdBlock.common.ControlByte != 0x03)) { @@ -988,7 +992,7 @@ x54x_scsi_cmd_phase1(x54x_t *dev) } dev->callback_sub_phase = 3; - x54x_log("scsi_devices[%02i].Status = %02X\n", req->TargetID, sd->status); + x54x_log("scsi_devices[%02xi][%02i].Status = %02X\n", x54x->bus, req->TargetID, sd->status); } @@ -999,7 +1003,7 @@ x54x_request_sense(x54x_t *dev) uint32_t SenseBufferAddress; scsi_device_t *sd; - sd = &scsi_devices[req->TargetID]; + sd = &scsi_devices[dev->bus][req->TargetID]; if (dev->scsi_cmd_phase != SCSI_PHASE_STATUS) { if ((dev->temp_cdb[0] == 0x03) && (req->CmdBlock.common.ControlByte == 0x03)) { @@ -1007,7 +1011,7 @@ x54x_request_sense(x54x_t *dev) sd->buffer_length = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); if ((sd->status != SCSI_STATUS_OK) && (sd->buffer_length > 0)) { SenseBufferAddress = SenseBufferPointer(req); - dma_bm_write(SenseBufferAddress, scsi_devices[req->TargetID].sc->temp_buffer, sd->buffer_length, dev->transfer_size); + dma_bm_write(SenseBufferAddress, scsi_devices[dev->bus][req->TargetID].sc->temp_buffer, sd->buffer_length, dev->transfer_size); x54x_add_to_period(dev, sd->buffer_length); } scsi_device_command_phase1(sd); @@ -1029,7 +1033,7 @@ x54x_request_sense(x54x_t *dev) } dev->callback_sub_phase = 4; - x54x_log("scsi_devices[%02i].Status = %02X\n", req->TargetID, sd->status); + x54x_log("scsi_devices[%02i][%02i].Status = %02X\n", dev->bus, req->TargetID, sd->status); } @@ -1049,18 +1053,27 @@ x54x_mbo_free(x54x_t *dev) static void x54x_notify(x54x_t *dev) { + Req_t *req = &dev->Req; + scsi_device_t *sd; + + sd = &scsi_devices[dev->bus][req->TargetID]; + x54x_mbo_free(dev); if (dev->MailboxIsBIOS) x54x_ccb(dev); else x54x_mbi(dev); + + /* Make sure to restore device to non-IDENTIFY'd state as we disconnect. */ + if (sd->type != SCSI_NONE) + scsi_device_identify(sd, SCSI_LUN_USE_CDB); } static void x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) -{ +{ Req_t *req = &dev->Req; uint8_t id, lun; scsi_device_t *sd; @@ -1075,7 +1088,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) req->LUN = req->Is24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; id = req->TargetID; - sd = &scsi_devices[id]; + sd = &scsi_devices[dev->bus][id]; lun = req->LUN; if ((id > dev->max_id) || (lun > 7)) { x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun); @@ -1089,18 +1102,18 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) sd->status = SCSI_STATUS_OK; - /* If there is no device at ID:0, timeout the selection - the LUN is then checked later. */ - if (! scsi_device_present(sd)) { + if (!scsi_device_present(sd) || (lun > 0)) { x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); dev->callback_sub_phase = 4; } else { x54x_log("SCSI Target ID %i detected and working\n", id); + scsi_device_identify(sd, lun); x54x_log("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); - x54x_log("CDB Length %i\n", req->CmdBlock.common.CdbLength); - x54x_log("CCB Opcode %x\n", req->CmdBlock.common.Opcode); + x54x_log("CDB Length %i\n", req->CmdBlock.common.CdbLength); + x54x_log("CCB Opcode %x\n", req->CmdBlock.common.Opcode); if ((req->CmdBlock.common.Opcode > 0x04) && (req->CmdBlock.common.Opcode != 0x81)) { x54x_log("Invalid opcode: %02X\n", req->CmdBlock.common.ControlByte); @@ -1139,7 +1152,7 @@ x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) static uint32_t x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) -{ +{ Mailbox_t MailboxOut; uint32_t Outgoing; uint32_t ccbp; @@ -1310,7 +1323,7 @@ x54x_cmd_callback(void *priv) period = (1000000.0 / dev->ha_bps) * ((double) dev->temp_period); timer_on(&dev->timer, dev->media_period + period + 10.0, 0); - x54x_log("Temporary period: %lf us (%" PRIi64 " periods)\n", dev->timer.period, dev->temp_period); + // x54x_log("Temporary period: %lf us (%" PRIi64 " periods)\n", dev->timer.period, dev->temp_period); } @@ -1371,6 +1384,13 @@ x54x_in(uint16_t port, void *priv) break; } +#ifdef ENABLE_X54X_LOG + if (port == 0x0332) + x54x_log("x54x_in(): %04X, %02X, %08X\n", port, ret, dev->DataReplyLeft); + else + x54x_log("x54x_in(): %04X, %02X\n", port, ret); +#endif + return(ret); } @@ -1446,7 +1466,7 @@ x54x_reset(x54x_t *dev) /* Reset all devices on controller reset. */ for (i = 0; i < 16; i++) - scsi_device_reset(&scsi_devices[i]); + scsi_device_reset(&scsi_devices[dev->bus][i]); if (dev->ven_reset) dev->ven_reset(dev); @@ -1502,7 +1522,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (val & CTRL_SCRST) { /* Reset all devices on SCSI bus reset. */ for (i = 0; i < 16; i++) - scsi_device_reset(&scsi_devices[i]); + scsi_device_reset(&scsi_devices[dev->bus][i]); } if (val & CTRL_IRST) { @@ -1549,7 +1569,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) case CMD_ECHO: case CMD_OPTIONS: dev->CmdParamLeft = 1; - break; + break; case CMD_SELTIMEOUT: dev->CmdParamLeft = 4; @@ -1573,7 +1593,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (dev->ven_cmd_phase1) dev->ven_cmd_phase1(dev); } - + if (! dev->CmdParamLeft) { x54x_log("Running Operation Code 0x%02X\n", dev->Command); switch (dev->Command) { @@ -1679,7 +1699,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (i == host_id) continue; /* TODO: Query device for LUN's. */ - if (scsi_device_present(&scsi_devices[i])) + if (scsi_device_present(&scsi_devices[dev->bus][i])) dev->DataBuf[i] |= 1; } dev->DataReplyLeft = i; @@ -1826,9 +1846,9 @@ x54x_is_32bit(x54x_t *dev) { int bit32 = 0; - if (dev->bus & DEVICE_PCI) + if (dev->card_bus & DEVICE_PCI) bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && (dev->flags & X54X_32BIT)) + else if ((dev->card_bus & DEVICE_MCA) && (dev->flags & X54X_32BIT)) bit32 = 1; return bit32; @@ -1919,9 +1939,9 @@ x54x_init(const device_t *info) memset(dev, 0x00, sizeof(x54x_t)); dev->type = info->local; - dev->bus = info->flags; + dev->card_bus = info->flags; dev->callback_phase = 0; - + timer_add(&dev->ResetCB, x54x_reset_poll, dev, 0); timer_add(&dev->timer, x54x_cmd_callback, dev, 1); dev->timer.period = 10.0; diff --git a/src/sio/CMakeLists.txt b/src/sio/CMakeLists.txt new file mode 100644 index 000000000..5017295b1 --- /dev/null +++ b/src/sio/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(sio OBJECT sio_acc3221.c sio_ali5123.c sio_f82c710.c sio_82091aa.c + sio_fdc37c6xx.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c + sio_it8661f.c + sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c + sio_prime3b.c sio_prime3c.c + sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c + sio_vt82c686.c) + +if(SIO_DETECT) + target_sources(sio PRIVATE sio_detect.c) +endif() diff --git a/src/sio/sio_82091aa.c b/src/sio/sio_82091aa.c new file mode 100644 index 000000000..7a60aa7c4 --- /dev/null +++ b/src/sio/sio_82091aa.c @@ -0,0 +1,334 @@ +/* + * 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 the Intel 82091AA Super I/O chip. + * + * + * + * Author: Miran Grca, + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + + +typedef struct { + uint8_t cur_reg, has_ide, + regs[81]; + uint16_t base_address; + fdc_t * fdc; + serial_t * uart[2]; +} i82091aa_t; + + +static void +fdc_handler(i82091aa_t *dev) +{ + fdc_remove(dev->fdc); + if (dev->regs[0x10] & 0x01) + fdc_set_base(dev->fdc, (dev->regs[0x10] & 0x02) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); +} + + +static void +lpt1_handler(i82091aa_t *dev) +{ + uint16_t lpt_port = LPT1_ADDR; + + lpt1_remove(); + + switch ((dev->regs[0x20] >> 1) & 0x03) { + case 0x00: + lpt_port = LPT1_ADDR; + break; + case 1: + lpt_port = LPT2_ADDR; + break; + case 2: + lpt_port = LPT_MDA_ADDR; + break; + case 3: + lpt_port = 0x000; + break; + } + + if ((dev->regs[0x20] & 0x01) && lpt_port) + lpt1_init(lpt_port); + + lpt1_irq((dev->regs[0x20] & 0x08) ? LPT1_IRQ : LPT2_IRQ); +} + + +static void +serial_handler(i82091aa_t *dev, int uart) +{ + int reg = (0x30 + (uart << 4)); + uint16_t uart_port = COM1_ADDR; + + serial_remove(dev->uart[uart]); + + switch ((dev->regs[reg] >> 1) & 0x07) { + case 0x00: + uart_port = COM1_ADDR; + break; + case 0x01: + uart_port = COM2_ADDR; + break; + case 0x02: + uart_port = 0x220; + break; + case 0x03: + uart_port = 0x228; + break; + case 0x04: + uart_port = 0x238; + break; + case 0x05: + uart_port = COM4_ADDR; + break; + case 0x06: + uart_port = 0x338; + break; + case 0x07: + uart_port = COM3_ADDR; + break; + } + + if (dev->regs[reg] & 0x01) + serial_setup(dev->uart[uart], uart_port, (dev->regs[reg] & 0x10) ? COM1_IRQ : COM2_IRQ); +} + + +static void +ide_handler(i82091aa_t *dev) +{ + int board = dev->has_ide - 1; + + ide_remove_handlers(board); + ide_set_base(board, (dev->regs[0x50] & 0x02) ? 0x170 : 0x1f0); + ide_set_side(board, (dev->regs[0x50] & 0x02) ? 0x376 : 0x3f6); + if (dev->regs[0x50] & 0x01) + ide_set_handlers(board); +} + + +static void +i82091aa_write(uint16_t port, uint8_t val, void *priv) +{ + i82091aa_t *dev = (i82091aa_t *) priv; + uint8_t index, valxor; + uint8_t uart = (dev->cur_reg >> 4) - 0x03; + uint8_t *reg = &(dev->regs[dev->cur_reg]); + + index = (port & 1) ? 0 : 1; + + if (index) { + dev->cur_reg = val; + return; + } else if (dev->cur_reg < 0x51) + valxor = val ^ *reg; + else if (dev->cur_reg >= 0x51) + return; + + switch(dev->cur_reg) { + case 0x02: + *reg = (*reg & 0x78) | (val & 0x01); + break; + case 0x03: + *reg = (val & 0xf8); + break; + case 0x10: + *reg = (val & 0x83); + if (valxor & 0x03) + fdc_handler(dev); + break; + case 0x11: + *reg = (val & 0x0f); + if ((valxor & 0x04) && (val & 0x04)) + fdc_reset(dev->fdc); + break; + case 0x20: + *reg = (val & 0xef); + if (valxor & 0x07) + lpt1_handler(dev); + break; + case 0x21: + *reg = (val & 0x2f); + break; + case 0x30: case 0x40: + *reg = (val & 0x9f); + if (valxor & 0x1f) + serial_handler(dev, uart); + if (valxor & 0x80) + serial_set_clock_src(dev->uart[uart], (val & 0x80) ? 2000000.0 : (24000000.0 / 13.0)); + break; + case 0x31: case 0x41: + *reg = (val & 0x1f); + if ((valxor & 0x04) && (val & 0x04)) + serial_reset_port(dev->uart[uart]); + break; + case 0x50: + *reg = (val & 0x07); + if (dev->has_ide && (valxor & 0x03)) + ide_handler(dev); + break; + } +} + + +uint8_t +i82091aa_read(uint16_t port, void *priv) +{ + i82091aa_t *dev = (i82091aa_t *) priv; + uint8_t ret = 0xff, index; + + index = (port & 1) ? 0 : 1; + + if (index) + ret = dev->cur_reg; + else if (dev->cur_reg < 0x51) + ret = dev->regs[dev->cur_reg]; + + return ret; +} + + +void +i82091aa_reset(i82091aa_t *dev) +{ + memset(dev->regs, 0x00, 81); + + dev->regs[0x00] = 0xa0; + dev->regs[0x10] = 0x01; + dev->regs[0x31] = dev->regs[0x41] = 0x02; + dev->regs[0x50] = 0x01; + + fdc_reset(dev->fdc); + + fdc_handler(dev); + lpt1_handler(dev); + serial_handler(dev, 0); + serial_handler(dev, 1); + serial_set_clock_src(dev->uart[0], (24000000.0 / 13.0)); + serial_set_clock_src(dev->uart[1], (24000000.0 / 13.0)); + + if (dev->has_ide) + ide_handler(dev); +} + + +static void +i82091aa_close(void *priv) +{ + i82091aa_t *dev = (i82091aa_t *) priv; + + free(dev); +} + + +static void * +i82091aa_init(const device_t *info) +{ + i82091aa_t *dev = (i82091aa_t *) malloc(sizeof(i82091aa_t)); + memset(dev, 0, sizeof(i82091aa_t)); + + dev->fdc = device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->has_ide = (info->local >> 9) & 0x03; + + i82091aa_reset(dev); + + dev->regs[0x02] = info->local & 0xff; + + if (info->local & 0x08) + dev->base_address = (info->local & 0x100) ? 0x0398 : 0x0024; + else + dev->base_address = (info->local & 0x100) ? 0x026e : 0x0022; + + io_sethandler(dev->base_address, 0x0002, + i82091aa_read, NULL, NULL, i82091aa_write, NULL, NULL, dev); + + return dev; +} + +const device_t i82091aa_device = { + .name = "Intel 82091AA Super I/O", + .internal_name = "i82091aa", + .flags = 0, + .local = 0x40, + .init = i82091aa_init, + .close = i82091aa_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i82091aa_398_device = { + .name = "Intel 82091AA Super I/O (Port 398h)", + .internal_name = "i82091aa_398", + .flags = 0, + .local = 0x148, + .init = i82091aa_init, + .close = i82091aa_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i82091aa_ide_pri_device = { + .name = "Intel 82091AA Super I/O (With Primary IDE)", + .internal_name = "i82091aa_ide", + .flags = 0, + .local = 0x240, + .init = i82091aa_init, + .close = i82091aa_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t i82091aa_ide_device = { + .name = "Intel 82091AA Super I/O (With IDE)", + .internal_name = "i82091aa_ide", + .flags = 0, + .local = 0x440, + .init = i82091aa_init, + .close = i82091aa_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_acc3221.c b/src/sio/sio_acc3221.c index 81af15036..313bbbd1a 100644 --- a/src/sio/sio_acc3221.c +++ b/src/sio/sio_acc3221.c @@ -349,10 +349,10 @@ acc3221_serial2_handler(acc3221_t *dev) } -static void +static void acc3221_write(uint16_t addr, uint8_t val, void *p) { - acc3221_t *dev = (acc3221_t *)p; + acc3221_t *dev = (acc3221_t *)p; uint8_t old; if (!(addr & 1)) @@ -400,7 +400,7 @@ acc3221_write(uint16_t addr, uint8_t val, void *p) if ((old ^ val) & REG_FB_FDC_DISABLE) { fdc_remove(dev->fdc); if (!(dev->regs[0xfb] & REG_FB_FDC_DISABLE)) - fdc_set_base(dev->fdc, 0x03f0); + fdc_set_base(dev->fdc, FDC_PRIMARY_ADDR); } break; @@ -416,10 +416,10 @@ acc3221_write(uint16_t addr, uint8_t val, void *p) } -static uint8_t +static uint8_t acc3221_read(uint16_t addr, void *p) { - acc3221_t *dev = (acc3221_t *)p; + acc3221_t *dev = (acc3221_t *)p; if (!(addr & 1)) return dev->reg_idx; @@ -435,14 +435,14 @@ static void acc3221_reset(acc3221_t *dev) { serial_remove(dev->uart[0]); - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ); serial_remove(dev->uart[1]); - serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - + serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); + lpt1_remove(); - lpt1_init(0x378); - lpt1_irq(7); + lpt1_init(LPT1_ADDR); + lpt1_irq(LPT1_IRQ); fdc_reset(dev->fdc); } @@ -465,7 +465,7 @@ acc3221_init(const device_t *info) dev->fdc = device_add(&fdc_at_device); dev->uart[0] = device_add_inst(&ns16450_device, 1); - dev->uart[1] = device_add_inst(&ns16450_device, 2); + dev->uart[1] = device_add_inst(&ns16450_device, 2); io_sethandler(0x00f2, 0x0002, acc3221_read, NULL, NULL, acc3221_write, NULL, NULL, dev); @@ -476,10 +476,15 @@ acc3221_init(const device_t *info) const device_t acc3221_device = { - "ACC 3221-SP Super I/O", - 0, - 0, - acc3221_init, acc3221_close, NULL, - NULL, NULL, NULL, - NULL + .name = "ACC 3221-SP Super I/O", + .internal_name = "acc3221", + .flags = 0, + .local = 0, + .init = acc3221_init, + .close = acc3221_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_ali5123.c b/src/sio/sio_ali5123.c new file mode 100644 index 000000000..79d9219ba --- /dev/null +++ b/src/sio/sio_ali5123.c @@ -0,0 +1,478 @@ +/* + * 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 ALi M5123/1543C Super I/O Chip. + * + * + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/pic.h> +#include <86box/pci.h> +#include <86box/keyboard.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include "cpu.h" +#include <86box/sio.h> + + +#define AB_RST 0x80 + + +typedef struct { + uint8_t chip_id, is_apm, + tries, + regs[48], + ld_regs[13][256]; + int locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[3]; +} ali5123_t; + + +static void ali5123_write(uint16_t port, uint8_t val, void *priv); +static uint8_t ali5123_read(uint16_t port, void *priv); + + +static uint16_t +make_port(ali5123_t *dev, uint8_t ld) +{ + uint16_t r0 = dev->ld_regs[ld][0x60]; + uint16_t r1 = dev->ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + + +static void +ali5123_fdc_handler(ali5123_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + uint8_t local_enable = !!dev->ld_regs[0][0x30]; + + fdc_remove(dev->fdc); + if (global_enable && local_enable) { + ld_port = make_port(dev, 0) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + fdc_set_base(dev->fdc, ld_port); + } +} + + +static void +ali5123_lpt_handler(ali5123_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + + if (lpt_irq > 15) + lpt_irq = 0xff; + + lpt1_remove(); + if (global_enable && local_enable) { + ld_port = make_port(dev, 3) & 0xFFFC; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } + lpt1_irq(lpt_irq); +} + + +static void +ali5123_serial_handler(ali5123_t *dev, int uart) +{ + uint16_t ld_port = 0; + uint8_t uart_no = (uart == 2) ? 0x0b : (4 + uart); + uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + uint8_t mask = (uart == 1) ? 0x04 : 0x05; + + serial_remove(dev->uart[uart]); + if (global_enable && local_enable) { + ld_port = make_port(dev, uart_no) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + } + + switch (dev->ld_regs[uart_no][0xf0] & mask) { + case 0x00: + serial_set_clock_src(dev->uart[uart], 1843200.0); + break; + case 0x04: + serial_set_clock_src(dev->uart[uart], 8000000.0); + break; + case 0x01: case 0x05: + serial_set_clock_src(dev->uart[uart], 2000000.0); + break; + } +} + + +static void +ali5123_reset(ali5123_t *dev) +{ + int i = 0; + + memset(dev->regs, 0, 48); + + dev->regs[0x20] = 0x43; + dev->regs[0x21] = 0x15; + dev->regs[0x2d] = 0x20; + + for (i = 0; i < 13; i++) + memset(dev->ld_regs[i], 0, 256); + + /* Logical device 0: FDD */ + dev->ld_regs[0][0x60] = 3; + dev->ld_regs[0][0x61] = 0xf0; + dev->ld_regs[0][0x70] = 6; + dev->ld_regs[0][0x74] = 2; + dev->ld_regs[0][0xf0] = 0x08; + dev->ld_regs[0][0xf2] = 0xff; + + /* Logical device 3: Parallel Port */ + dev->ld_regs[3][0x60] = 3; + dev->ld_regs[3][0x61] = 0x78; + dev->ld_regs[3][0x70] = 5; + dev->ld_regs[3][0x74] = 4; + dev->ld_regs[3][0xf0] = 0x8c; + dev->ld_regs[3][0xf1] = 0x85; + + /* Logical device 4: Serial Port 1 */ + dev->ld_regs[4][0x60] = 3; + dev->ld_regs[4][0x61] = 0xf8; + dev->ld_regs[4][0x70] = 4; + dev->ld_regs[4][0xf2] = 0x0c; + serial_setup(dev->uart[0], COM1_ADDR, dev->ld_regs[4][0x70]); + + /* Logical device 5: Serial Port 2 - HP like module */ + dev->ld_regs[5][0x60] = 3; + dev->ld_regs[5][0x61] = 0xe8; + dev->ld_regs[5][0x70] = 9; + dev->ld_regs[5][0xf0] = 0x80; + dev->ld_regs[4][0xf2] = 0x0c; + serial_setup(dev->uart[1], 0x03e8, dev->ld_regs[5][0x70]); + + /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x70] = 1; + /* TODO: Register F0 bit 6: 0 = PS/2, 1 = AT */ + + /* Logical device B: Serial Port 2 - HP like module */ + dev->ld_regs[0x0b][0x60] = 2; + dev->ld_regs[0x0b][0x61] = 0xf8; + dev->ld_regs[0x0b][0x70] = 3; + dev->ld_regs[0x0b][0xf0] = 0x00; + dev->ld_regs[0x0b][0xf2] = 0x0c; + serial_setup(dev->uart[2], COM2_ADDR, dev->ld_regs[0x0b][0x70]); + + /* Logical device C: Hotkey */ + dev->ld_regs[0x0c][0xf0] = 0x35; + dev->ld_regs[0x0c][0xf1] = 0x14; + dev->ld_regs[0x0c][0xf2] = 0x11; + dev->ld_regs[0x0c][0xf3] = 0x71; + dev->ld_regs[0x0c][0xf4] = 0x42; + + ali5123_lpt_handler(dev); + ali5123_serial_handler(dev, 0); + ali5123_serial_handler(dev, 1); + ali5123_serial_handler(dev, 2); + + fdc_reset(dev->fdc); + ali5123_fdc_handler(dev); + + dev->locked = 0; +} + + +static void +ali5123_write(uint16_t port, uint8_t val, void *priv) +{ + ali5123_t *dev = (ali5123_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0x00, keep = 0x00; + uint8_t cur_ld; + + if (index) { + if (((val == 0x51) && (!dev->tries) && (!dev->locked)) || + ((val == 0x23) && (dev->tries) && (!dev->locked))) { + if (dev->tries) { + dev->locked = 1; + fdc_3f1_enable(dev->fdc, 0); + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val == 0xbb) { + dev->locked = 0; + fdc_3f1_enable(dev->fdc, 1); + return; + } + dev->cur_reg = val; + } else { + if (dev->tries) + dev->tries = 0; + } + } + return; + } else { + if (dev->locked) { + if (dev->cur_reg < 48) { + valxor = val ^ dev->regs[dev->cur_reg]; + if ((val == 0x1f) || (val == 0x20) || (val == 0x21)) + return; + dev->regs[dev->cur_reg] = val; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (((dev->cur_reg & 0xf0) == 0x70) && (dev->regs[7] < 4)) + return; + /* Block writes to some logical devices. */ + if (dev->regs[7] > 0x0c) + return; + else switch (dev->regs[7]) { + case 0x01: case 0x02: case 0x06: case 0x08: + case 0x09: case 0x0a: + return; + } + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val | keep; + } + } else + return; + } + + if (dev->cur_reg < 48) { + switch(dev->cur_reg) { + case 0x02: + if (val & 0x01) + ali5123_reset(dev); + dev->regs[0x02] = 0x00; + break; + case 0x22: + if (valxor & 0x01) + ali5123_fdc_handler(dev); + if (valxor & 0x08) + ali5123_lpt_handler(dev); + if (valxor & 0x10) + ali5123_serial_handler(dev, 0); + if (valxor & 0x20) + ali5123_serial_handler(dev, 1); + if (valxor & 0x40) + ali5123_serial_handler(dev, 2); + break; + } + + return; + } + + cur_ld = dev->regs[7]; + if ((dev->regs[7] == 5) && (dev->regs[0x2d] & 0x20)) + cur_ld = 0x0b; + else if ((dev->regs[7] == 0x0b) && (dev->regs[0x2d] & 0x20)) + cur_ld = 5; + switch(cur_ld) { + case 0: + /* FDD */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x01; + if (valxor) + ali5123_fdc_handler(dev); + break; + case 0xf0: + if (valxor & 0x08) + fdc_update_enh_mode(dev->fdc, !(val & 0x08)); + if (valxor & 0x10) + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xf1: + if (valxor & 0xc) + fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); + break; + case 0xf4: + if (valxor & 0x08) + fdc_update_drvrate(dev->fdc, 0, (val & 0x08) >> 3); + break; + case 0xf5: + if (valxor & 0x08) + fdc_update_drvrate(dev->fdc, 1, (val & 0x08) >> 3); + break; + case 0xf6: + if (valxor & 0x08) + fdc_update_drvrate(dev->fdc, 2, (val & 0x08) >> 3); + break; + case 0xf7: + if (valxor & 0x08) + fdc_update_drvrate(dev->fdc, 3, (val & 0x08) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x08; + if (valxor) + ali5123_lpt_handler(dev); + break; + } + break; + case 4: + /* Serial port 1 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + case 0xf0: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x10; + if (valxor) + ali5123_serial_handler(dev, 0); + break; + } + break; + case 5: + /* Serial port 2 - HP like module */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + case 0xf0: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x20; + if (valxor) + ali5123_serial_handler(dev, 1); + break; + } + break; + case 0x0b: + /* Serial port 3 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + case 0xf0: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x40; + if (valxor) + ali5123_serial_handler(dev, 2); + break; + } + break; + } +} + + +static uint8_t +ali5123_read(uint16_t port, void *priv) +{ + ali5123_t *dev = (ali5123_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff, cur_ld; + + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; + else + ret = dev->regs[dev->cur_reg]; + } else { + cur_ld = dev->regs[7]; + if ((dev->regs[7] == 5) && (dev->regs[0x2d] & 0x20)) + cur_ld = 0x0b; + else if ((dev->regs[7] == 0x0b) && (dev->regs[0x2d] & 0x20)) + cur_ld = 5; + + ret = dev->ld_regs[cur_ld][dev->cur_reg]; + } + } + } + + return ret; +} + + +static void +ali5123_close(void *priv) +{ + ali5123_t *dev = (ali5123_t *) priv; + + free(dev); +} + + +static void * +ali5123_init(const device_t *info) +{ + ali5123_t *dev = (ali5123_t *) malloc(sizeof(ali5123_t)); + memset(dev, 0, sizeof(ali5123_t)); + + dev->fdc = device_add(&fdc_at_ali_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->uart[2] = device_add_inst(&ns16550_device, 3); + + dev->chip_id = info->local & 0xff; + + ali5123_reset(dev); + + io_sethandler(FDC_PRIMARY_ADDR, 0x0002, + ali5123_read, NULL, NULL, ali5123_write, NULL, NULL, dev); + + device_add(&keyboard_ps2_ali_pci_device); + + return dev; +} + + +const device_t ali5123_device = { + .name = "ALi M5123/M1543C Super I/O", + .internal_name = "ali5123", + .flags = 0, + .local = 0x40, + .init = ali5123_init, + .close = ali5123_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_detect.c b/src/sio/sio_detect.c index e322ae544..2e3302179 100644 --- a/src/sio/sio_detect.c +++ b/src/sio/sio_detect.c @@ -53,7 +53,7 @@ sio_detect_read(uint16_t port, void *priv) pclog("sio_detect_read : port=%04x = %02X\n", port, dev->regs[port & 1]); - return dev->regs[port & 1]; + return 0xff /*dev->regs[port & 1]*/; } @@ -74,7 +74,7 @@ sio_detect_init(const device_t *info) device_add(&fdc_at_smc_device); - io_sethandler(0x0024, 0x0004, + io_sethandler(0x0022, 0x0006, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); io_sethandler(0x002e, 0x0002, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); @@ -84,15 +84,21 @@ sio_detect_init(const device_t *info) sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); io_sethandler(0x0108, 0x0002, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x015c, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); io_sethandler(0x0250, 0x0003, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x026e, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); io_sethandler(0x0279, 0x0001, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); - io_sethandler(0x0370, 0x0002, + io_sethandler(FDC_SECONDARY_ADDR, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0398, 0x0002, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); io_sethandler(0x03e3, 0x0001, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); - io_sethandler(0x03f0, 0x0002, + io_sethandler(FDC_PRIMARY_ADDR, 0x0002, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); io_sethandler(0x0a79, 0x0001, sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); @@ -102,10 +108,15 @@ sio_detect_init(const device_t *info) const device_t sio_detect_device = { - "Super I/O Detection Helper", - 0, - 0, - sio_detect_init, sio_detect_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Super I/O Detection Helper", + .internal_name = "sio_detect", + .flags = 0, + .local = 0, + .init = sio_detect_init, + .close = sio_detect_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_f82c710.c b/src/sio/sio_f82c710.c index 46cca26b8..fadbc76e2 100644 --- a/src/sio/sio_f82c710.c +++ b/src/sio/sio_f82c710.c @@ -6,13 +6,23 @@ * * This file is part of the 86Box distribution. * - * Implementation of the Chips & Technologies F82C710 Universal Peripheral Controller (UPC). + * Implementation of the Chips & Technologies F82C710 Universal Peripheral + * Controller (UPC) and 82C606 CHIPSpak Multifunction Controller. + * + * Relevant literature: + * + * [1] Chips and Technologies, Inc., + * 82C605/82C606 CHIPSpak/CHIPSport MULTIFUNCTION CONTROLLERS, + * PRELIMINARY Data Sheet, Revision 1, May 1987. + * * * Authors: Sarah Walker, * Eluan Costa Miranda + * Lubomir Rintel * * Copyright 2020 Sarah Walker. * Copyright 2020 Eluan Costa Miranda. + * Copyright 2021 Lubomir Rintel. */ #include #include @@ -25,213 +35,335 @@ #include <86box/device.h> #include <86box/lpt.h> #include <86box/serial.h> +#include <86box/gameport.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/nvr.h> #include <86box/sio.h> + typedef struct upc_t { - int configuration_state; /* state of algorithm to enter configuration mode */ - int configuration_mode; - uint16_t cri_addr; /* cri = configuration index register, addr is even */ - uint16_t cap_addr; /* cap = configuration access port, addr is odd and is cri_addr + 1 */ - uint8_t cri; /* currently indexed register */ + uint32_t local; + int configuration_state; /* state of algorithm to enter configuration mode */ + int configuration_mode; + uint16_t cri_addr; /* cri = configuration index register, addr is even */ + uint16_t cap_addr; /* cap = configuration access port, addr is odd and is cri_addr + 1 */ + uint8_t cri; /* currently indexed register */ + uint8_t last_write; - /* these regs are not affected by reset */ - uint8_t regs[15]; /* there are 16 indexes, but there is no need to store the last one which is: R = cri_addr / 4, W = exit config mode */ - fdc_t *fdc; - serial_t *uart[2]; + /* these regs are not affected by reset */ + uint8_t regs[15]; /* there are 16 indexes, but there is no need to store the last one which is: R = cri_addr / 4, W = exit config mode */ + fdc_t * fdc; + nvr_t * nvr; + void * gameport; + serial_t * uart[2]; } upc_t; -static void -f82c710_update_ports(upc_t *upc) + +static void +f82c710_update_ports(upc_t *dev, int set) { - uint16_t com_addr = 0; - uint16_t lpt_addr = 0; - - serial_remove(upc->uart[0]); - serial_remove(upc->uart[1]); - lpt1_remove(); - lpt2_remove(); - fdc_remove(upc->fdc); - ide_pri_disable(); + uint16_t com_addr = 0; + uint16_t lpt_addr = 0; - if (upc->regs[0] & 4) { - com_addr = upc->regs[4] * 4; - if (com_addr == SERIAL1_ADDR) { - serial_setup(upc->uart[0], com_addr, 4); - } else if (com_addr == SERIAL2_ADDR) { - serial_setup(upc->uart[1], com_addr, 3); - } - } - + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + lpt1_remove(); + lpt2_remove(); + fdc_remove(dev->fdc); + ide_pri_disable(); - if (upc->regs[0] & 8) { - lpt_addr = upc->regs[6] * 4; - lpt1_init(lpt_addr); - if ((lpt_addr == 0x378) || (lpt_addr == 0x3bc)) { - lpt1_irq(7); - } else if (lpt_addr == 0x278) { - lpt1_irq(5); - } - } + if (!set) + return; - if (upc->regs[12] & 0x80) { - ide_pri_enable(); - } + if (dev->regs[0] & 4) { + com_addr = dev->regs[4] * 4; + if (com_addr == COM1_ADDR) + serial_setup(dev->uart[0], com_addr, COM1_IRQ); + else if (com_addr == COM2_ADDR) + serial_setup(dev->uart[1], com_addr, COM2_IRQ); + } - if (upc->regs[12] & 0x20) { - fdc_set_base(upc->fdc, 0x03f0); - } -} + if (dev->regs[0] & 8) { + lpt_addr = dev->regs[6] * 4; + lpt1_init(lpt_addr); + if ((lpt_addr == LPT1_ADDR) || (lpt_addr == LPT_MDA_ADDR)) + lpt1_irq(LPT1_IRQ); + else if (lpt_addr == LPT2_ADDR) + lpt1_irq(LPT2_IRQ); + } -static uint8_t -f82c710_config_read(uint16_t port, void *priv) -{ - upc_t *upc = (upc_t *)priv; - uint8_t temp = 0xff; + if (dev->regs[12] & 0x80) + ide_pri_enable(); - if (upc->configuration_mode) { - if (port == upc->cri_addr) { - temp = upc->cri; - } else if (port == upc->cap_addr) { - if (upc->cri == 0xf) - temp = upc->cri_addr / 4; - else - temp = upc->regs[upc->cri]; - } - } - - return temp; -} - -static void -f82c710_config_write(uint16_t port, uint8_t val, void *priv) -{ - upc_t *upc = (upc_t *)priv; - int configuration_state_event = 0; - - switch(port) { - case 0x2fa: - if (upc->configuration_state == 0 && val == 0x55) - configuration_state_event = 1; - else if (upc->configuration_state == 4) { - uint8_t addr_verify = upc->cri_addr / 4; - addr_verify += val; - if (addr_verify == 0xff) { - upc->configuration_mode = 1; - /* TODO: is the value of cri reset here or when exiting configuration mode? */ - io_sethandler(upc->cri_addr, 0x0002, f82c710_config_read, NULL, NULL, f82c710_config_write, NULL, NULL, upc); - } else { - upc->configuration_mode = 0; - } - } - break; - case 0x3fa: - if (upc->configuration_state == 1 && val == 0xaa) - configuration_state_event = 1; - else if (upc->configuration_state == 2 && val == 0x36) - configuration_state_event = 1; - else if (upc->configuration_state == 3) { - upc->cri_addr = val * 4; - upc->cap_addr = upc->cri_addr + 1; - configuration_state_event = 1; - } - break; - default: - break; - } - - if (upc->configuration_mode) { - if (port == upc->cri_addr) { - upc->cri = val & 0xf; - } else if (port == upc->cap_addr) { - if (upc->cri == 0xf) { - upc->configuration_mode = 0; - io_removehandler(upc->cri_addr, 0x0002, f82c710_config_read, NULL, NULL, f82c710_config_write, NULL, NULL, upc); - f82c710_update_ports(upc); /* TODO: any benefit in updating at each register write instead of when exiting config mode? */ - } else { - upc->regs[upc->cri] = val; - } - } - } - - /* TODO: is the state only reset when accessing 0x2fa and 0x3fa wrongly? */ - if ((port == 0x2fa || port == 0x3fa) && configuration_state_event) - upc->configuration_state++; - else - upc->configuration_state = 0; + if (dev->regs[12] & 0x20) + fdc_set_base(dev->fdc, FDC_PRIMARY_ADDR); } static void -f82c710_reset(upc_t *upc) +f82c606_update_ports(upc_t *dev, int set) { - serial_remove(upc->uart[0]); - serial_setup(upc->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + uint8_t uart1_int = 0xff; + uint8_t uart2_int = 0xff; + uint8_t lpt1_int = 0xff; + int nvr_int = -1; - serial_remove(upc->uart[1]); - serial_setup(upc->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - - lpt1_remove(); - lpt1_init(0x378); - lpt1_irq(7); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + lpt1_remove(); + lpt2_remove(); - fdc_reset(upc->fdc); + nvr_at_handler(0, ((uint16_t) dev->regs[3]) << 2, dev->nvr); + nvr_at_handler(0, 0x70, dev->nvr); + + gameport_remap(dev->gameport, 0); + + if (!set) + return; + + switch (dev->regs[8] & 0xc0) { + case 0x40: nvr_int = 3; break; + case 0x80: uart1_int = COM2_IRQ; break; + case 0xc0: uart2_int = COM2_IRQ; break; + } + + switch (dev->regs[8] & 0x30) { + case 0x10: nvr_int = 4; break; + case 0x20: uart1_int = COM1_IRQ; break; + case 0x30: uart2_int = COM1_IRQ; break; + } + + switch (dev->regs[8] & 0x0c) { + case 0x04: nvr_int = 5; break; + case 0x08: uart1_int = 5; break; + case 0x0c: lpt1_int = LPT2_IRQ; break; + } + + switch (dev->regs[8] & 0x03) { + case 0x01: nvr_int = 7; break; + case 0x02: uart2_int = 7; break; + case 0x03: lpt1_int = LPT1_IRQ; break; + } + + if (dev->regs[0] & 1) { + gameport_remap(dev->gameport, ((uint16_t) dev->regs[7]) << 2); + pclog("Game port at %04X\n", ((uint16_t) dev->regs[7]) << 2); + } + + if (dev->regs[0] & 2) { + serial_setup(dev->uart[0], ((uint16_t) dev->regs[4]) << 2, uart1_int); + pclog("UART 1 at %04X, IRQ %i\n", ((uint16_t) dev->regs[4]) << 2, uart1_int); + } + + if (dev->regs[0] & 4) { + serial_setup(dev->uart[1], ((uint16_t) dev->regs[5]) << 2, uart2_int); + pclog("UART 2 at %04X, IRQ %i\n", ((uint16_t) dev->regs[5]) << 2, uart2_int); + } + + if (dev->regs[0] & 8) { + lpt1_init(((uint16_t) dev->regs[6]) << 2); + lpt1_irq(lpt1_int); + pclog("LPT1 at %04X, IRQ %i\n", ((uint16_t) dev->regs[6]) << 2, lpt1_int); + } + + nvr_at_handler(1, ((uint16_t) dev->regs[3]) << 2, dev->nvr); + nvr_irq_set(nvr_int, dev->nvr); + pclog("RTC at %04X, IRQ %i\n", ((uint16_t) dev->regs[3]) << 2, nvr_int); } -static void * -f82c710_init(const device_t *info) + +static uint8_t +f82c710_config_read(uint16_t port, void *priv) { - upc_t *upc = (upc_t *) malloc(sizeof(upc_t)); - memset(upc, 0, sizeof(upc_t)); + upc_t *dev = (upc_t *) priv; + uint8_t temp = 0xff; - upc->fdc = device_add(&fdc_at_device); + if (dev->configuration_mode) { + if (port == dev->cri_addr) { + temp = dev->cri; + } else if (port == dev->cap_addr) { + if (dev->cri == 0xf) + temp = dev->cri_addr / 4; + else + temp = dev->regs[dev->cri]; + } + } - upc->uart[0] = device_add_inst(&ns16450_device, 1); - upc->uart[1] = device_add_inst(&ns16450_device, 2); - - io_sethandler(0x02fa, 0x0001, NULL, NULL, NULL, f82c710_config_write, NULL, NULL, upc); - io_sethandler(0x03fa, 0x0001, NULL, NULL, NULL, f82c710_config_write, NULL, NULL, upc); - - upc->regs[0] = 0x0c; - upc->regs[1] = 0x00; - upc->regs[2] = 0x00; - upc->regs[3] = 0x00; - upc->regs[4] = 0xfe; - upc->regs[5] = 0x00; - upc->regs[6] = 0x9e; - upc->regs[7] = 0x00; - upc->regs[8] = 0x00; - upc->regs[9] = 0xb0; - upc->regs[10] = 0x00; - upc->regs[11] = 0x00; - upc->regs[12] = 0xa0; - upc->regs[13] = 0x00; - upc->regs[14] = 0x00; - - f82c710_reset(upc); - - f82c710_update_ports(upc); - - return upc; + return temp; } + +static void +f82c710_config_write(uint16_t port, uint8_t val, void *priv) +{ + upc_t *dev = (upc_t *) priv; + int configuration_state_event = 0; + + switch (port) { + case 0x2fa: + if ((dev->configuration_state == 0) && (val != 0x00) && (val != 0xff) && (dev->local == 606)) { + configuration_state_event = 1; + dev->last_write = val; + } else if ((dev->configuration_state == 0) && (val == 0x55) && (dev->local == 710)) + configuration_state_event = 1; + else if (dev->configuration_state == 4) { + if ((val | dev->last_write) == 0xff) { + dev->cri_addr = ((uint16_t) dev->last_write) << 2; + dev->cap_addr = dev->cri_addr + 1; + dev->configuration_mode = 1; + if (dev->local == 606) + f82c606_update_ports(dev, 0); + else if (dev->local == 710) + f82c710_update_ports(dev, 0); + /* TODO: is the value of cri reset here or when exiting configuration mode? */ + io_sethandler(dev->cri_addr, 0x0002, f82c710_config_read, NULL, NULL, f82c710_config_write, NULL, NULL, dev); + } else + dev->configuration_mode = 0; + } + break; + case 0x3fa: + if ((dev->configuration_state == 1) && ((val | dev->last_write) == 0xff) && (dev->local == 606)) + configuration_state_event = 1; + else if ((dev->configuration_state == 1) && (val == 0xaa) && (dev->local == 710)) + configuration_state_event = 1; + else if ((dev->configuration_state == 2) && (val == 0x36)) + configuration_state_event = 1; + else if (dev->configuration_state == 3) { + dev->last_write = val; + configuration_state_event = 1; + } + break; + default: + break; + } + + if (dev->configuration_mode) { + if (port == dev->cri_addr) { + dev->cri = val & 0xf; + } else if (port == dev->cap_addr) { + if (dev->cri == 0xf) { + dev->configuration_mode = 0; + io_removehandler(dev->cri_addr, 0x0002, f82c710_config_read, NULL, NULL, f82c710_config_write, NULL, NULL, dev); + /* TODO: any benefit in updating at each register write instead of when exiting config mode? */ + if (dev->local == 606) + f82c606_update_ports(dev, 1); + else if (dev->local == 710) + f82c710_update_ports(dev, 1); + } else + dev->regs[dev->cri] = val; + } + } + + /* TODO: is the state only reset when accessing 0x2fa and 0x3fa wrongly? */ + if ((port == 0x2fa || port == 0x3fa) && configuration_state_event) + dev->configuration_state++; + else + dev->configuration_state = 0; +} + + +static void +f82c710_reset(void *priv) +{ + upc_t *dev = (upc_t *) priv; + + /* Set power-on defaults. */ + if (dev->local == 606) { + dev->regs[0] = 0x00; /* Enable */ + dev->regs[1] = 0x00; /* Configuration Register */ + dev->regs[2] = 0x00; /* Ext Baud Rate Select */ + dev->regs[3] = 0xb0; /* RTC Base */ + dev->regs[4] = 0xfe; /* UART1 Base */ + dev->regs[5] = 0xbe; /* UART2 Base */ + dev->regs[6] = 0x9e; /* Parallel Base */ + dev->regs[7] = 0x80; /* Game Base */ + dev->regs[8] = 0xec; /* Interrupt Select */ + } else if (dev->local == 710) { + dev->regs[0] = 0x0c; + dev->regs[1] = 0x00; + dev->regs[2] = 0x00; + dev->regs[3] = 0x00; + dev->regs[4] = 0xfe; + dev->regs[5] = 0x00; + dev->regs[6] = 0x9e; + dev->regs[7] = 0x00; + dev->regs[8] = 0x00; + dev->regs[9] = 0xb0; + dev->regs[10] = 0x00; + dev->regs[11] = 0x00; + dev->regs[12] = 0xa0; + dev->regs[13] = 0x00; + dev->regs[14] = 0x00; + } + + if (dev->local == 606) + f82c606_update_ports(dev, 1); + else if (dev->local == 710) + f82c710_update_ports(dev, 1); +} + + static void f82c710_close(void *priv) { - upc_t *upc = (upc_t *)priv; + upc_t *dev = (upc_t *) priv; - free(upc); + free(dev); } -const device_t f82c710_device = { - "F82C710 UPC Super I/O", - 0, - 0, - f82c710_init, f82c710_close, NULL, - NULL, NULL, NULL, - NULL + +static void * +f82c710_init(const device_t *info) +{ + upc_t *dev = (upc_t *) malloc(sizeof(upc_t)); + memset(dev, 0, sizeof(upc_t)); + dev->local = info->local; + + if (dev->local == 606) { + dev->nvr = device_add(&at_nvr_old_device); + dev->gameport = gameport_add(&gameport_sio_device); + } else if (dev->local == 710) + dev->fdc = device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + + io_sethandler(0x02fa, 0x0001, NULL, NULL, NULL, f82c710_config_write, NULL, NULL, dev); + io_sethandler(0x03fa, 0x0001, NULL, NULL, NULL, f82c710_config_write, NULL, NULL, dev); + + f82c710_reset(dev); + + return dev; +} + +const device_t f82c606_device = { + .name = "82C606 CHIPSpak Multifunction Controller", + .internal_name = "f82c606", + .flags = 0, + .local = 606, + .init = f82c710_init, + .close = f82c710_close, + .reset = f82c710_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t f82c710_device = { + .name = "F82C710 UPC Super I/O", + .internal_name = "f82c710", + .flags = 0, + .local = 710, + .init = f82c710_init, + .close = f82c710_close, + .reset = f82c710_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index 4f6823f8f..caa92fad5 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -33,7 +33,7 @@ typedef struct { - uint8_t tries, + uint8_t id, tries, regs[42]; int locked, rw_locked, cur_reg; @@ -42,6 +42,9 @@ typedef struct { } fdc37c669_t; +static int next_id = 0; + + static uint16_t make_port(fdc37c669_t *dev, uint8_t reg) { @@ -114,7 +117,7 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) switch(dev->cur_reg) { case 0: - if (valxor & 8) { + if (!dev->id && (valxor & 8)) { fdc_remove(dev->fdc); if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) fdc_set_base(dev->fdc, make_port(dev, 0x20)); @@ -122,9 +125,15 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) break; case 1: if (valxor & 4) { - lpt1_remove(); - if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) - lpt1_init(make_port(dev, 0x23)); + if (dev->id) { + lpt2_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt2_init(make_port(dev, 0x23)); + } else { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } } if (valxor & 7) dev->rw_locked = (val & 8) ? 0 : 1; @@ -142,23 +151,23 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) } break; case 3: - if (valxor & 2) + if (!dev->id && (valxor & 2)) fdc_update_enh_mode(dev->fdc, (val & 2) ? 1 : 0); break; case 5: - if (valxor & 0x18) + if (!dev->id && (valxor & 0x18)) fdc_update_densel_force(dev->fdc, (val & 0x18) >> 3); - if (valxor & 0x20) + if (!dev->id && (valxor & 0x20)) fdc_set_swap(dev->fdc, (val & 0x20) >> 5); break; case 0xB: - if (valxor & 3) + if (!dev->id && (valxor & 3)) fdc_update_rwc(dev->fdc, 0, val & 3); - if (valxor & 0xC) + if (!dev->id && (valxor & 0xC)) fdc_update_rwc(dev->fdc, 1, (val & 0xC) >> 2); break; case 0x20: - if (valxor & 0xfc) { + if (!dev->id && (valxor & 0xfc)) { fdc_remove(dev->fdc); if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) fdc_set_base(dev->fdc, make_port(dev, 0x20)); @@ -166,9 +175,15 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) break; case 0x23: if (valxor) { - lpt1_remove(); - if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) - lpt1_init(make_port(dev, 0x23)); + if (dev->id) { + lpt2_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt2_init(make_port(dev, 0x23)); + } else { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } } break; case 0x24: @@ -186,8 +201,12 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) } break; case 0x27: - if (valxor & 0xf) - lpt1_irq(val & 0xf); + if (valxor & 0xf) { + if (dev->id) + lpt2_irq(val & 0xf); + else + lpt1_irq(val & 0xf); + } break; case 0x28: if (valxor & 0xf) { @@ -226,16 +245,11 @@ fdc37c669_read(uint16_t port, void *priv) static void fdc37c669_reset(fdc37c669_t *dev) { - fdc_reset(dev->fdc); - serial_remove(dev->uart[0]); - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ); serial_remove(dev->uart[1]); - serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - - lpt1_remove(); - lpt1_init(0x378); + serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); memset(dev->regs, 0, 42); dev->regs[0x00] = 0x28; @@ -246,14 +260,30 @@ fdc37c669_reset(fdc37c669_t *dev) dev->regs[0x0d] = 0x03; dev->regs[0x0e] = 0x02; dev->regs[0x1e] = 0x80; /* Gameport controller. */ - dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; + dev->regs[0x20] = (FDC_PRIMARY_ADDR >> 2) & 0xfc; dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - dev->regs[0x23] = (0x378 >> 2); - dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; - dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + if (dev->id == 1) { + dev->regs[0x23] = (LPT2_ADDR >> 2); + + lpt2_remove(); + lpt2_init(LPT2_ADDR); + + dev->regs[0x24] = (COM3_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (COM4_ADDR >> 2) & 0xfe; + } else { + fdc_reset(dev->fdc); + + lpt1_remove(); + lpt1_init(LPT1_ADDR); + + dev->regs[0x23] = (LPT1_ADDR >> 2); + + dev->regs[0x24] = (COM1_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (COM2_ADDR >> 2) & 0xfe; + } dev->regs[0x26] = (2 << 4) | 3; - dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x27] = (6 << 4) | (dev->id ? 5 : 7); dev->regs[0x28] = (4 << 4) | 3; dev->locked = 0; @@ -266,6 +296,8 @@ fdc37c669_close(void *priv) { fdc37c669_t *dev = (fdc37c669_t *) priv; + next_id = 0; + free(dev); } @@ -276,25 +308,49 @@ fdc37c669_init(const device_t *info) fdc37c669_t *dev = (fdc37c669_t *) malloc(sizeof(fdc37c669_t)); memset(dev, 0, sizeof(fdc37c669_t)); - dev->fdc = device_add(&fdc_at_smc_device); + dev->id = next_id; - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + if (next_id != 1) + dev->fdc = device_add(&fdc_at_smc_device); - io_sethandler(0x3f0, 0x0002, + dev->uart[0] = device_add_inst(&ns16550_device, (next_id << 1) + 1); + dev->uart[1] = device_add_inst(&ns16550_device, (next_id << 1) + 2); + + io_sethandler(info->local ? FDC_SECONDARY_ADDR : (next_id ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR), 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev); fdc37c669_reset(dev); + next_id++; + return dev; } - const device_t fdc37c669_device = { - "SMC FDC37C669 Super I/O", - 0, - 0, - fdc37c669_init, fdc37c669_close, NULL, - NULL, NULL, NULL, - NULL + .name = "SMC FDC37C669 Super I/O", + .internal_name = "fdc37c669", + .flags = 0, + .local = 0, + .init = fdc37c669_init, + .close = fdc37c669_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + + +const device_t fdc37c669_370_device = { + .name = "SMC FDC37C669 Super I/O (Port 370h)", + .internal_name = "fdc37c669_370", + .flags = 0, + .local = 1, + fdc37c669_init, + fdc37c669_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_fdc37c66x.c b/src/sio/sio_fdc37c66x.c deleted file mode 100644 index eefafe083..000000000 --- a/src/sio/sio_fdc37c66x.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 SMC FDC37C663 and FDC37C665 Super - * I/O Chips. - * - * - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/io.h> -#include <86box/timer.h> -#include <86box/device.h> -#include <86box/pci.h> -#include <86box/lpt.h> -#include <86box/serial.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/sio.h> - - -typedef struct { - uint8_t chip_id, - lock[2], - regs[16]; - int cur_reg, - com3_addr, com4_addr; - fdc_t *fdc; - serial_t *uart[2]; -} fdc37c66x_t; - - -static void -write_lock(fdc37c66x_t *dev, uint8_t val) -{ - if (val == 0x55 && dev->lock[1] == 0x55) - fdc_3f1_enable(dev->fdc, 0); - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55) && (val != 0x55)) - fdc_3f1_enable(dev->fdc, 1); - - dev->lock[0] = dev->lock[1]; - dev->lock[1] = val; -} - - -static void -set_com34_addr(fdc37c66x_t *dev) -{ - switch (dev->regs[1] & 0x60) { - case 0x00: - dev->com3_addr = 0x338; - dev->com4_addr = 0x238; - break; - case 0x20: - dev->com3_addr = 0x3e8; - dev->com4_addr = 0x2e8; - break; - case 0x40: - dev->com3_addr = 0x3e8; - dev->com4_addr = 0x2e0; - break; - case 0x60: - dev->com3_addr = 0x220; - dev->com4_addr = 0x228; - break; - } -} - - -static void -set_serial_addr(fdc37c66x_t *dev, int port) -{ - uint8_t shift = (port << 4); - - if (dev->regs[2] & (4 << shift)) { - switch (dev->regs[2] & (3 << shift)) { - case 0: - serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); - break; - case 1: - serial_setup(dev->uart[port], SERIAL2_ADDR, SERIAL2_IRQ); - break; - case 2: - serial_setup(dev->uart[port], dev->com3_addr, 4); - break; - case 3: - serial_setup(dev->uart[port], dev->com4_addr, 3); - break; - } - } -} - - -static void -lpt1_handler(fdc37c66x_t *dev) -{ - lpt1_remove(); - switch (dev->regs[1] & 3) { - case 1: - lpt1_init(0x3bc); - lpt1_irq(7); - break; - case 2: - lpt1_init(0x378); - lpt1_irq(5); - break; - case 3: - lpt1_init(0x278); - lpt1_irq(5); - break; - } -} - - -static void -fdc_handler(fdc37c66x_t *dev) -{ - fdc_remove(dev->fdc); - if (dev->regs[0] & 0x10) - fdc_set_base(dev->fdc, (dev->regs[5] & 0x01) ? 0x0370 : 0x03f0); -} - - -static void -fdc37c66x_write(uint16_t port, uint8_t val, void *priv) -{ - fdc37c66x_t *dev = (fdc37c66x_t *) priv; - uint8_t valxor = 0; - - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { - if (port == 0x3f0) { - if (val == 0xaa) - write_lock(dev, val); - else - dev->cur_reg = val; - } else { - if (dev->cur_reg > 15) - return; - - valxor = val ^ dev->regs[dev->cur_reg]; - dev->regs[dev->cur_reg] = val; - - switch(dev->cur_reg) { - case 0: - if (valxor & 0x10) - fdc_handler(dev); - break; - case 1: - if (valxor & 3) - lpt1_handler(dev); - if (valxor & 0x60) { - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); - set_com34_addr(dev); - set_serial_addr(dev, 0); - set_serial_addr(dev, 1); - } - break; - case 2: - if (valxor & 7) { - serial_remove(dev->uart[0]); - set_serial_addr(dev, 0); - } - if (valxor & 0x70) { - serial_remove(dev->uart[1]); - set_serial_addr(dev, 1); - } - break; - case 3: - if (valxor & 2) - fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 2) ? 1 : 0); - break; - case 5: - if (valxor & 0x01) - fdc_handler(dev); - if (valxor & 0x18) - fdc_update_densel_force(dev->fdc, (dev->regs[5] & 0x18) >> 3); - if (valxor & 0x20) - fdc_set_swap(dev->fdc, (dev->regs[5] & 0x20) >> 5); - break; - } - } - } else { - if (port == 0x3f0) - write_lock(dev, val); - } -} - - -static uint8_t -fdc37c66x_read(uint16_t port, void *priv) -{ - fdc37c66x_t *dev = (fdc37c66x_t *) priv; - uint8_t ret = 0xff; - - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { - if (port == 0x3f1) - ret = dev->regs[dev->cur_reg]; - } - - return ret; -} - - -static void -fdc37c66x_reset(fdc37c66x_t *dev) -{ - dev->com3_addr = 0x338; - dev->com4_addr = 0x238; - - serial_remove(dev->uart[0]); - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - - serial_remove(dev->uart[1]); - serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - - lpt1_remove(); - lpt1_init(0x378); - - fdc_reset(dev->fdc); - - memset(dev->lock, 0, 2); - memset(dev->regs, 0, 16); - - dev->regs[0x0] = 0x3a; - dev->regs[0x1] = 0x9f; - dev->regs[0x2] = 0xdc; - dev->regs[0x3] = 0x78; - dev->regs[0x6] = 0xff; - dev->regs[0xd] = dev->chip_id; - dev->regs[0xe] = 0x01; -} - - -static void -fdc37c66x_close(void *priv) -{ - fdc37c66x_t *dev = (fdc37c66x_t *) priv; - - free(dev); -} - - -static void * -fdc37c66x_init(const device_t *info) -{ - fdc37c66x_t *dev = (fdc37c66x_t *) malloc(sizeof(fdc37c66x_t)); - memset(dev, 0, sizeof(fdc37c66x_t)); - - dev->fdc = device_add(&fdc_at_smc_device); - - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); - - dev->chip_id = info->local; - - io_sethandler(0x03f0, 0x0002, - fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, dev); - - fdc37c66x_reset(dev); - - return dev; -} - - -/* The three appear to differ only in the chip ID, if I - understood their datasheets correctly. */ -const device_t fdc37c663_device = { - "SMC FDC37C663 Super I/O", - 0, - 0x63, - fdc37c66x_init, fdc37c66x_close, NULL, - NULL, NULL, NULL, - NULL -}; - -const device_t fdc37c665_device = { - "SMC FDC37C665 Super I/O", - 0, - 0x65, - fdc37c66x_init, fdc37c66x_close, NULL, - NULL, NULL, NULL, - NULL -}; - -const device_t fdc37c666_device = { - "SMC FDC37C666 Super I/O", - 0, - 0x66, - fdc37c66x_init, fdc37c66x_close, NULL, - NULL, NULL, NULL, - NULL -}; diff --git a/src/sio/sio_fdc37c67x.c b/src/sio/sio_fdc37c67x.c new file mode 100644 index 000000000..098ffbb44 --- /dev/null +++ b/src/sio/sio_fdc37c67x.c @@ -0,0 +1,618 @@ +/* + * 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 SMC FDC37C67X Super I/O Chip. + * + * + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/pic.h> +#include <86box/pci.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include "cpu.h" +#include <86box/sio.h> + + +#define AB_RST 0x80 + + +typedef struct { + uint8_t chip_id, is_apm, + tries, + gpio_regs[2], auxio_reg, + regs[48], + ld_regs[11][256]; + uint16_t gpio_base, /* Set to EA */ + auxio_base, sio_base; + int locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c67x_t; + + +static void fdc37c67x_write(uint16_t port, uint8_t val, void *priv); +static uint8_t fdc37c67x_read(uint16_t port, void *priv); + + +static uint16_t +make_port(fdc37c67x_t *dev, uint8_t ld) +{ + uint16_t r0 = dev->ld_regs[ld][0x60]; + uint16_t r1 = dev->ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + + +static uint8_t +fdc37c67x_auxio_read(uint16_t port, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + return dev->auxio_reg; +} + + +static void +fdc37c67x_auxio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + dev->auxio_reg = val; +} + + +static uint8_t +fdc37c67x_gpio_read(uint16_t port, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + uint8_t ret = 0xff; + + ret = dev->gpio_regs[port & 1]; + + return ret; +} + + +static void +fdc37c67x_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + if (!(port & 1)) + dev->gpio_regs[0] = (dev->gpio_regs[0] & 0xfc) | (val & 0x03); +} + + +static void +fdc37c67x_fdc_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + uint8_t local_enable = !!dev->ld_regs[0][0x30]; + + fdc_remove(dev->fdc); + if (global_enable && local_enable) { + ld_port = make_port(dev, 0) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + fdc_set_base(dev->fdc, ld_port); + } +} + + +static void +fdc37c67x_lpt_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + + if (lpt_irq > 15) + lpt_irq = 0xff; + + lpt1_remove(); + if (global_enable && local_enable) { + ld_port = make_port(dev, 3) & 0xFFFC; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } + lpt1_irq(lpt_irq); +} + + +static void +fdc37c67x_serial_handler(fdc37c67x_t *dev, int uart) +{ + uint16_t ld_port = 0; + uint8_t uart_no = 4 + uart; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + + serial_remove(dev->uart[uart]); + if (global_enable && local_enable) { + ld_port = make_port(dev, uart_no) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + } +} + + +static void +fdc37c67x_auxio_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable = !!dev->ld_regs[8][0x30]; + + io_removehandler(dev->auxio_base, 0x0001, + fdc37c67x_auxio_read, NULL, NULL, fdc37c67x_auxio_write, NULL, NULL, dev); + if (local_enable) { + dev->auxio_base = ld_port = make_port(dev, 8); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + io_sethandler(dev->auxio_base, 0x0001, + fdc37c67x_auxio_read, NULL, NULL, fdc37c67x_auxio_write, NULL, NULL, dev); + } +} + + +static void +fdc37c67x_sio_handler(fdc37c67x_t *dev) +{ +#if 0 + if (dev->sio_base) { + io_removehandler(dev->sio_base, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + } + dev->sio_base = (((uint16_t) dev->regs[0x27]) << 8) | dev->regs[0x26]; + if (dev->sio_base) { + io_sethandler(dev->sio_base, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + } +#endif +} + + +static void +fdc37c67x_gpio_handler(fdc37c67x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable; + + local_enable = !!(dev->regs[0x03] & 0x80); + + io_removehandler(dev->gpio_base, 0x0002, + fdc37c67x_gpio_read, NULL, NULL, fdc37c67x_gpio_write, NULL, NULL, dev); + if (local_enable) { + switch (dev->regs[0x03] & 0x03) { + case 0: + ld_port = 0xe0; + break; + case 1: + ld_port = 0xe2; + break; + case 2: + ld_port = 0xe4; + break; + case 3: + ld_port = 0xea; /* Default */ + break; + } + dev->gpio_base = ld_port; + if (ld_port > 0x0000) + io_sethandler(dev->gpio_base, 0x0002, + fdc37c67x_gpio_read, NULL, NULL, fdc37c67x_gpio_write, NULL, NULL, dev); + } +} + + +static void +fdc37c67x_smi_handler(fdc37c67x_t *dev) +{ + /* TODO: 8042 P1.2 SMI#. */ + pic_reset_smi_irq_mask(); + pic_set_smi_irq_mask(dev->ld_regs[3][0x70], dev->ld_regs[8][0xb4] & 0x02); + pic_set_smi_irq_mask(dev->ld_regs[5][0x70], dev->ld_regs[8][0xb4] & 0x04); + pic_set_smi_irq_mask(dev->ld_regs[4][0x70], dev->ld_regs[8][0xb4] & 0x08); + pic_set_smi_irq_mask(dev->ld_regs[0][0x70], dev->ld_regs[8][0xb4] & 0x10); + pic_set_smi_irq_mask(12, dev->ld_regs[8][0xb5] & 0x01); + pic_set_smi_irq_mask(1, dev->ld_regs[8][0xb5] & 0x02); + pic_set_smi_irq_mask(10, dev->ld_regs[8][0xb5] & 0x80); +} + + +static void +fdc37c67x_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0x00, keep = 0x00; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + fdc_3f1_enable(dev->fdc, 0); + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val == 0xaa) { + dev->locked = 0; + fdc_3f1_enable(dev->fdc, 1); + return; + } + dev->cur_reg = val; + } else { + if (dev->tries) + dev->tries = 0; + } + } + return; + } else { + if (dev->locked) { + if (dev->cur_reg < 48) { + valxor = val ^ dev->regs[dev->cur_reg]; + if ((val == 0x20) || (val == 0x21)) + return; + dev->regs[dev->cur_reg] = val; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) + return; + /* Block writes to some logical devices. */ + if (dev->regs[7] > 0x0a) + return; + else switch (dev->regs[7]) { + case 0x01: + case 0x02: + case 0x07: + return; + } + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val | keep; + } + } else + return; + } + + if (dev->cur_reg < 48) { + switch(dev->cur_reg) { + case 0x03: + if (valxor & 0x83) + fdc37c67x_gpio_handler(dev); + dev->regs[0x03] &= 0x83; + break; + case 0x22: + if (valxor & 0x01) + fdc37c67x_fdc_handler(dev); + if (valxor & 0x08) + fdc37c67x_lpt_handler(dev); + if (valxor & 0x10) + fdc37c67x_serial_handler(dev, 0); + if (valxor & 0x20) + fdc37c67x_serial_handler(dev, 1); + break; + case 0x26: case 0x27: + fdc37c67x_sio_handler(dev); + } + + return; + } + + switch(dev->regs[7]) { + case 0: + /* FDD */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x01; + if (valxor) + fdc37c67x_fdc_handler(dev); + break; + case 0xF0: + if (valxor & 0x01) + fdc_update_enh_mode(dev->fdc, val & 0x01); + if (valxor & 0x10) + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) + fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); + break; + case 0xF2: + if (valxor & 0xC0) + fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); + if (valxor & 0x0C) + fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, (val & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 1, (val & 0x18) >> 3); + break; + case 0xF6: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 2, (val & 0x18) >> 3); + break; + case 0xF7: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 3, (val & 0x18) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x08; + if (valxor) + fdc37c67x_lpt_handler(dev); + if (dev->cur_reg == 0x70) + fdc37c67x_smi_handler(dev); + break; + } + break; + case 4: + /* Serial port 1 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x10; + if (valxor) + fdc37c67x_serial_handler(dev, 0); + if (dev->cur_reg == 0x70) + fdc37c67x_smi_handler(dev); + break; + } + break; + case 5: + /* Serial port 2 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x20; + if (valxor) + fdc37c67x_serial_handler(dev, 1); + if (dev->cur_reg == 0x70) + fdc37c67x_smi_handler(dev); + break; + } + break; + case 8: + /* Auxiliary I/O */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c67x_auxio_handler(dev); + break; + case 0xb4: + case 0xb5: + fdc37c67x_smi_handler(dev); + break; + } + break; + } +} + + +static uint8_t +fdc37c67x_read(uint16_t port, void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; + uint16_t smi_stat = pic_get_smi_irq_status(); + int f_irq = dev->ld_regs[0][0x70]; + int p_irq = dev->ld_regs[3][0x70]; + int s1_irq = dev->ld_regs[4][0x70]; + int s2_irq = dev->ld_regs[5][0x70]; + + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; + else + ret = dev->regs[dev->cur_reg]; + } else { + if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + } else + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; + + /* TODO: 8042 P1.2 SMI#. */ + if ((dev->regs[7] == 8) && (dev->cur_reg == 0xb6)) { + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg] & 0xe1; + ret |= ((!!(smi_stat & (1 << p_irq))) << 1); + ret |= ((!!(smi_stat & (1 << s2_irq))) << 2); + ret |= ((!!(smi_stat & (1 << s1_irq))) << 3); + ret |= ((!!(smi_stat & (1 << f_irq))) << 4); + } else if ((dev->regs[7] == 8) && (dev->cur_reg == 0xb7)) { + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg] & 0xec; + ret |= ((!!(smi_stat & (1 << 12))) << 0); + ret |= ((!!(smi_stat & (1 << 1))) << 1); + ret |= ((!!(smi_stat & (1 << 10))) << 4); + } + } + } + } + + return ret; +} + + +static void +fdc37c67x_reset(fdc37c67x_t *dev) +{ + int i = 0; + + memset(dev->regs, 0, 48); + + dev->regs[0x03] = 0x03; + dev->regs[0x20] = dev->chip_id; + dev->regs[0x22] = 0x39; + dev->regs[0x24] = 0x04; + dev->regs[0x26] = 0xf0; + dev->regs[0x27] = 0x03; + + for (i = 0; i < 11; i++) + memset(dev->ld_regs[i], 0, 256); + + /* Logical device 0: FDD */ + dev->ld_regs[0][0x30] = 1; + dev->ld_regs[0][0x60] = 3; + dev->ld_regs[0][0x61] = 0xf0; + dev->ld_regs[0][0x70] = 6; + dev->ld_regs[0][0x74] = 2; + dev->ld_regs[0][0xf0] = 0x0e; + dev->ld_regs[0][0xf2] = 0xff; + + /* Logical device 3: Parallel Port */ + dev->ld_regs[3][0x30] = 1; + dev->ld_regs[3][0x60] = 3; + dev->ld_regs[3][0x61] = 0x78; + dev->ld_regs[3][0x70] = 7; + dev->ld_regs[3][0x74] = 4; + dev->ld_regs[3][0xf0] = 0x3c; + + /* Logical device 4: Serial Port 1 */ + dev->ld_regs[4][0x30] = 1; + dev->ld_regs[4][0x60] = 3; + dev->ld_regs[4][0x61] = 0xf8; + dev->ld_regs[4][0x70] = 4; + dev->ld_regs[4][0xf0] = 3; + serial_setup(dev->uart[0], COM1_ADDR, dev->ld_regs[4][0x70]); + + /* Logical device 5: Serial Port 2 */ + dev->ld_regs[5][0x30] = 1; + dev->ld_regs[5][0x60] = 2; + dev->ld_regs[5][0x61] = 0xf8; + dev->ld_regs[5][0x70] = 3; + dev->ld_regs[5][0x74] = 4; + dev->ld_regs[5][0xf1] = 2; + dev->ld_regs[5][0xf2] = 3; + serial_setup(dev->uart[1], COM2_ADDR, dev->ld_regs[5][0x70]); + + /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x30] = 1; + dev->ld_regs[7][0x61] = 0x60; + dev->ld_regs[7][0x70] = 1; + dev->ld_regs[7][0x72] = 12; + + /* Logical device 8: Auxiliary I/O */ + dev->ld_regs[8][0xc0] = 6; + dev->ld_regs[8][0xc1] = 3; + + fdc37c67x_gpio_handler(dev); + fdc37c67x_lpt_handler(dev); + fdc37c67x_serial_handler(dev, 0); + fdc37c67x_serial_handler(dev, 1); + fdc37c67x_auxio_handler(dev); + fdc37c67x_sio_handler(dev); + + fdc_reset(dev->fdc); + fdc37c67x_fdc_handler(dev); + + dev->locked = 0; +} + + +static void +fdc37c67x_close(void *priv) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) priv; + + free(dev); +} + + +static void * +fdc37c67x_init(const device_t *info) +{ + fdc37c67x_t *dev = (fdc37c67x_t *) malloc(sizeof(fdc37c67x_t)); + memset(dev, 0, sizeof(fdc37c67x_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->chip_id = info->local & 0xff; + + dev->gpio_regs[0] = 0xff; + // dev->gpio_regs[1] = (info->local == 0x0030) ? 0xff : 0xfd; + dev->gpio_regs[1] = (dev->chip_id == 0x30) ? 0xff : 0xfd; + + fdc37c67x_reset(dev); + + io_sethandler(FDC_SECONDARY_ADDR, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + io_sethandler(FDC_PRIMARY_ADDR, 0x0002, + fdc37c67x_read, NULL, NULL, fdc37c67x_write, NULL, NULL, dev); + + return dev; +} + + +const device_t fdc37c67x_device = { + .name = "SMC FDC37C67X Super I/O", + .internal_name = "fdc37c67x", + .flags = 0, + .local = 0x40, + .init = fdc37c67x_init, + .close = fdc37c67x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c new file mode 100644 index 000000000..15949c81c --- /dev/null +++ b/src/sio/sio_fdc37c6xx.c @@ -0,0 +1,462 @@ +/* + * 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 SMC FDC37C663 and FDC37C665 Super + * I/O Chips. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/pci.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + + +typedef struct { + uint8_t max_reg, chip_id, + tries, has_ide, + regs[16]; + int cur_reg, + com3_addr, com4_addr; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c6xx_t; + + +static void +set_com34_addr(fdc37c6xx_t *dev) +{ + switch (dev->regs[1] & 0x60) { + case 0x00: + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + break; + case 0x20: + dev->com3_addr = COM3_ADDR; + dev->com4_addr = COM4_ADDR; + break; + case 0x40: + dev->com3_addr = COM3_ADDR; + dev->com4_addr = 0x2e0; + break; + case 0x60: + dev->com3_addr = 0x220; + dev->com4_addr = 0x228; + break; + } +} + + +static void +set_serial_addr(fdc37c6xx_t *dev, int port) +{ + uint8_t shift = (port << 2); + double clock_src = 24000000.0 / 13.0; + + if (dev->regs[4] & (1 << (4 + port))) + clock_src = 24000000.0 / 12.0; + + serial_remove(dev->uart[port]); + if (dev->regs[2] & (4 << shift)) { + switch ((dev->regs[2] >> shift) & 3) { + case 0: + serial_setup(dev->uart[port], COM1_ADDR, COM1_IRQ); + break; + case 1: + serial_setup(dev->uart[port], COM2_ADDR, COM2_IRQ); + break; + case 2: + serial_setup(dev->uart[port], dev->com3_addr, COM3_IRQ); + break; + case 3: + serial_setup(dev->uart[port], dev->com4_addr, COM4_IRQ); + break; + } + } + + serial_set_clock_src(dev->uart[port], clock_src); +} + + +static void +lpt1_handler(fdc37c6xx_t *dev) +{ + lpt1_remove(); + switch (dev->regs[1] & 3) { + case 1: + lpt1_init(LPT_MDA_ADDR); + lpt1_irq(7); + break; + case 2: + lpt1_init(LPT1_ADDR); + lpt1_irq(7 /*5*/); + break; + case 3: + lpt1_init(LPT2_ADDR); + lpt1_irq(7 /*5*/); + break; + } +} + + +static void +fdc_handler(fdc37c6xx_t *dev) +{ + fdc_remove(dev->fdc); + if (dev->regs[0] & 0x10) + fdc_set_base(dev->fdc, (dev->regs[5] & 0x01) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); +} + + + +static void +ide_handler(fdc37c6xx_t *dev) +{ + /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ + if (dev->has_ide == 2) { + ide_sec_disable(); + ide_set_base(1, (dev->regs[0x05] & 0x02) ? 0x170 : 0x1f0); + ide_set_side(1, (dev->regs[0x05] & 0x02) ? 0x376 : 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_sec_enable(); + } else if (dev->has_ide == 1) { + ide_pri_disable(); + ide_set_base(0, (dev->regs[0x05] & 0x02) ? 0x170 : 0x1f0); + ide_set_side(0, (dev->regs[0x05] & 0x02) ? 0x376 : 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_pri_enable(); + } +} + + +static void +fdc37c6xx_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c6xx_t *dev = (fdc37c6xx_t *) priv; + uint8_t valxor = 0; + + if (dev->tries == 2) { + if (port == FDC_PRIMARY_ADDR) { + if (val == 0xaa) + dev->tries = 0; + else + dev->cur_reg = val; + } else { + if (dev->cur_reg > dev->max_reg) + return; + + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + + switch(dev->cur_reg) { + case 0: + if (dev->has_ide && (valxor & 0x01)) + ide_handler(dev); + if (valxor & 0x10) + fdc_handler(dev); + break; + case 1: + if (valxor & 3) + lpt1_handler(dev); + if (valxor & 0x60) { + set_com34_addr(dev); + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + } + break; + case 2: + if (valxor & 7) + set_serial_addr(dev, 0); + if (valxor & 0x70) + set_serial_addr(dev, 1); + break; + case 3: + if (valxor & 2) + fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 2) ? 1 : 0); + break; + case 4: + if (valxor & 0x10) + set_serial_addr(dev, 0); + if (valxor & 0x20) + set_serial_addr(dev, 1); + break; + case 5: + if (valxor & 0x01) + fdc_handler(dev); + if (dev->has_ide && (valxor & 0x02)) + ide_handler(dev); + if (valxor & 0x18) + fdc_update_densel_force(dev->fdc, (dev->regs[5] & 0x18) >> 3); + if (valxor & 0x20) + fdc_set_swap(dev->fdc, (dev->regs[5] & 0x20) >> 5); + break; + } + } + } else if ((port == FDC_PRIMARY_ADDR) && (val == 0x55)) + dev->tries++; +} + + +static uint8_t +fdc37c6xx_read(uint16_t port, void *priv) +{ + fdc37c6xx_t *dev = (fdc37c6xx_t *) priv; + uint8_t ret = 0x00; + + if (dev->tries == 2) { + if (port == 0x3f1) + ret = dev->regs[dev->cur_reg]; + } + + return ret; +} + + +static void +fdc37c6xx_reset(fdc37c6xx_t *dev) +{ + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); + + lpt1_remove(); + lpt1_init(LPT1_ADDR); + + fdc_reset(dev->fdc); + fdc_remove(dev->fdc); + + dev->tries = 0; + memset(dev->regs, 0, 16); + + switch (dev->chip_id) { + case 0x63: case 0x65: + dev->max_reg = 0x0f; + dev->regs[0x0] = 0x3b; + break; + case 0x64: case 0x66: + dev->max_reg = 0x0f; + dev->regs[0x0] = 0x2b; + break; + default: + dev->max_reg = (dev->chip_id >= 0x61) ? 0x03 : 0x02; + dev->regs[0x0] = 0x3f; + break; + } + + dev->regs[0x1] = 0x9f; + dev->regs[0x2] = 0xdc; + dev->regs[0x3] = 0x78; + + if (dev->chip_id >= 0x63) { + dev->regs[0x6] = 0xff; + dev->regs[0xd] = dev->chip_id; + if (dev->chip_id >= 0x65) + dev->regs[0xe] = 0x02; + else + dev->regs[0xe] = 0x01; + } + + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + + lpt1_handler(dev); + + fdc_handler(dev); + + if (dev->has_ide) + ide_handler(dev); +} + + +static void +fdc37c6xx_close(void *priv) +{ + fdc37c6xx_t *dev = (fdc37c6xx_t *) priv; + + free(dev); +} + + +static void * +fdc37c6xx_init(const device_t *info) +{ + fdc37c6xx_t *dev = (fdc37c6xx_t *) malloc(sizeof(fdc37c6xx_t)); + memset(dev, 0, sizeof(fdc37c6xx_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->chip_id = info->local & 0xff; + dev->has_ide = (info->local >> 8) & 0xff; + + if (dev->chip_id >= 0x63) { + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + } else { + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + } + + io_sethandler(FDC_PRIMARY_ADDR, 0x0002, + fdc37c6xx_read, NULL, NULL, fdc37c6xx_write, NULL, NULL, dev); + + fdc37c6xx_reset(dev); + + return dev; +} + +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ +const device_t fdc37c651_device = { + .name = "SMC FDC37C651 Super I/O", + .internal_name = "fdc37c651", + .flags = 0, + .local = 0x51, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c651_ide_device = { + .name = "SMC FDC37C651 Super I/O (With IDE)", + .internal_name = "fdc37c651_ide", + .flags = 0, + .local = 0x151, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c661_device = { + .name = "SMC FDC37C661 Super I/O", + .internal_name = "fdc37c661", + .flags = 0, + .local = 0x61, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c661_ide_device = { + .name = "SMC FDC37C661 Super I/O (With IDE)", + .internal_name = "fdc37c661_ide", + .flags = 0, + .local = 0x161, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c663_device = { + .name = "SMC FDC37C663 Super I/O", + .internal_name = "fdc37c663", + .flags = 0, + .local = 0x63, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c663_ide_device = { + .name = "SMC FDC37C663 Super I/O (With IDE)", + .internal_name = "fdc37c663_ide", + .flags = 0, + .local = 0x163, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c665_device = { + .name = "SMC FDC37C665 Super I/O", + .internal_name = "fdc37c665", + .flags = 0, + .local = 0x65, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c665_ide_device = { + .name = "SMC FDC37C665 Super I/O (With IDE)", + .internal_name = "fdc37c665_ide", + .flags = 0, + .local = 0x265, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c666_device = { + .name = "SMC FDC37C666 Super I/O", + .internal_name = "fdc37c666", + .flags = 0, + .local = 0x66, + .init = fdc37c6xx_init, + .close = fdc37c6xx_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index 7e08ab373..b9e9ef767 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -31,6 +31,8 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/nvr.h> +#include <86box/apm.h> +#include <86box/acpi.h> #include <86box/sio.h> @@ -47,10 +49,11 @@ typedef struct { } access_bus_t; typedef struct { - uint8_t chip_id, tries, + uint8_t chip_id, is_apm, + tries, gpio_regs[2], auxio_reg, regs[48], - ld_regs[10][256]; + ld_regs[11][256]; uint16_t gpio_base, /* Set to EA */ auxio_base, nvr_sec_base; int locked, @@ -59,6 +62,7 @@ typedef struct { serial_t *uart[2]; access_bus_t *access_bus; nvr_t *nvr; + acpi_t *acpi; } fdc37c93x_t; @@ -108,8 +112,11 @@ static uint8_t fdc37c93x_gpio_read(uint16_t port, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t ret = 0xff; - return dev->gpio_regs[port & 1]; + ret = dev->gpio_regs[port & 1]; + + return ret; } @@ -118,7 +125,8 @@ fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; - dev->gpio_regs[port & 1] = val; + if (!(port & 1)) + dev->gpio_regs[0] = (dev->gpio_regs[0] & 0xfc) | (val & 0x03); } @@ -131,7 +139,7 @@ fdc37c93x_fdc_handler(fdc37c93x_t *dev) fdc_remove(dev->fdc); if (global_enable && local_enable) { - ld_port = make_port(dev, 0); + ld_port = make_port(dev, 0) & 0xFFF8; if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) fdc_set_base(dev->fdc, ld_port); } @@ -151,7 +159,7 @@ fdc37c93x_lpt_handler(fdc37c93x_t *dev) lpt1_remove(); if (global_enable && local_enable) { - ld_port = make_port(dev, 3); + ld_port = make_port(dev, 3) & 0xFFFC; if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) lpt1_init(ld_port); } @@ -169,7 +177,7 @@ fdc37c93x_serial_handler(fdc37c93x_t *dev, int uart) serial_remove(dev->uart[uart]); if (global_enable && local_enable) { - ld_port = make_port(dev, uart_no); + ld_port = make_port(dev, uart_no) & 0xFFF8; if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); } @@ -195,9 +203,11 @@ fdc37c93x_nvr_sec_handler(fdc37c93x_t *dev) nvr_at_sec_handler(0, dev->nvr_sec_base, dev->nvr); if (local_enable) { - dev->nvr_sec_base = ld_port = make_port_sec(dev, 6); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFE)) - nvr_at_sec_handler(1, ld_port, dev->nvr); + dev->nvr_sec_base = ld_port = make_port_sec(dev, 6) & 0xFFFE; + /* Datasheet erratum: First it says minimum address is 0x0100, but later implies that it's 0x0000 + and that default is 0x0070, same as (unrelocatable) primary NVR. */ + if (ld_port <= 0x0FFE) + nvr_at_sec_handler(1, dev->nvr_sec_base, dev->nvr); } } @@ -219,7 +229,8 @@ fdc37c93x_auxio_handler(fdc37c93x_t *dev) } -static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) +static void +fdc37c93x_gpio_handler(fdc37c93x_t *dev) { uint16_t ld_port = 0; uint8_t local_enable; @@ -252,7 +263,7 @@ static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) static uint8_t -fdc37c932fr_access_bus_read(uint16_t port, void *priv) +fdc37c93x_access_bus_read(uint16_t port, void *priv) { access_bus_t *dev = (access_bus_t *) priv; uint8_t ret = 0xff; @@ -277,7 +288,7 @@ fdc37c932fr_access_bus_read(uint16_t port, void *priv) static void -fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) +fdc37c93x_access_bus_write(uint16_t port, uint8_t val, void *priv) { access_bus_t *dev = (access_bus_t *) priv; @@ -299,29 +310,61 @@ fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) } -static void fdc37c932fr_access_bus_handler(fdc37c93x_t *dev) +static void +fdc37c93x_access_bus_handler(fdc37c93x_t *dev) { uint16_t ld_port = 0; uint8_t global_enable = !!(dev->regs[0x22] & (1 << 6)); uint8_t local_enable = !!dev->ld_regs[9][0x30]; io_removehandler(dev->access_bus->base, 0x0004, - fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + fdc37c93x_access_bus_read, NULL, NULL, fdc37c93x_access_bus_write, NULL, NULL, dev->access_bus); if (global_enable && local_enable) { dev->access_bus->base = ld_port = make_port(dev, 9); if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) io_sethandler(dev->access_bus->base, 0x0004, - fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + fdc37c93x_access_bus_read, NULL, NULL, fdc37c93x_access_bus_write, NULL, NULL, dev->access_bus); } } +static void +fdc37c93x_acpi_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable = !!dev->ld_regs[0x0a][0x30]; + uint8_t sci_irq = dev->ld_regs[0x0a][0x70]; + + acpi_update_io_mapping(dev->acpi, 0x0000, local_enable); + if (local_enable) { + ld_port = make_port(dev, 0x0a) & 0xFFF0; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF0)) + acpi_update_io_mapping(dev->acpi, ld_port, local_enable); + } + + acpi_update_aux_io_mapping(dev->acpi, 0x0000, local_enable); + if (local_enable) { + ld_port = make_port_sec(dev, 0x0a) & 0xFFF8; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + acpi_update_aux_io_mapping(dev->acpi, ld_port, local_enable); + } + + acpi_set_irq_line(dev->acpi, sci_irq); +} + + static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; + uint8_t valxor = 0x00, keep = 0x00; + + /* Compaq Presario 4500: Unlock at FB, Register at EA, Data at EB, Lock at F9. */ + if ((port == 0xea) || (port == 0xf9) || (port == 0xfb)) + index = 1; + else if (port == 0xeb) + index = 0; if (index) { if ((val == 0x55) && !dev->locked) { @@ -357,21 +400,35 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) return; /* Block writes to some logical devices. */ - if (dev->regs[7] > 9) + if (dev->regs[7] > 0x0a) return; else switch (dev->regs[7]) { - case 1: - case 2: - case 7: + case 0x01: + case 0x02: + case 0x07: return; - case 9: + case 0x06: + if (dev->chip_id != 0x30) + return; + /* Bits 0 to 3 of logical device 6 (RTC) register F0h must stay set + once they are set. */ + else if (dev->cur_reg == 0xf0) + keep = dev->ld_regs[dev->regs[7]][dev->cur_reg] & 0x0f; + break; + case 0x09: /* If we're on the FDC37C935, return as this is not a valid logical device there. */ - if (dev->chip_id == 0x02) + if (!dev->is_apm && (dev->chip_id == 0x02)) + return; + break; + case 0x0a: + /* If we're not on the FDC37C931APM, return as this is not a + valid logical device there. */ + if (!dev->is_apm) return; break; } - dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val | keep; } } else return; @@ -394,7 +451,7 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) if (valxor & 0x20) fdc37c93x_serial_handler(dev, 1); if ((valxor & 0x40) && (dev->chip_id != 0x02)) - fdc37c932fr_access_bus_handler(dev); + fdc37c93x_access_bus_handler(dev); break; } @@ -421,17 +478,17 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) break; case 0xF1: if (valxor & 0xC) - fdc_update_densel_force(dev->fdc, (val & 0xC) >> 2); + fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); break; case 0xF2: if (valxor & 0xC0) - fdc_update_rwc(dev->fdc, 3, (valxor & 0xC0) >> 6); + fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); if (valxor & 0x30) - fdc_update_rwc(dev->fdc, 2, (valxor & 0x30) >> 4); + fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); if (valxor & 0x0C) - fdc_update_rwc(dev->fdc, 1, (valxor & 0x0C) >> 2); + fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); if (valxor & 0x03) - fdc_update_rwc(dev->fdc, 0, (valxor & 0x03)); + fdc_update_rwc(dev->fdc, 0, (val & 0x03)); break; case 0xF4: if (valxor & 0x18) @@ -501,9 +558,8 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) case 0x30: if (valxor) fdc37c93x_nvr_pri_handler(dev); - /* FALLTHROUGH */ - case 0x60: - case 0x61: + case 0x62: + case 0x63: if (valxor) fdc37c93x_nvr_sec_handler(dev); break; @@ -560,7 +616,7 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) } break; case 9: - /* Access bus (FDC37C932FR only) */ + /* Access bus (FDC37C932FR and FDC37C931APM only) */ switch(dev->cur_reg) { case 0x30: case 0x60: @@ -569,7 +625,21 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) if ((dev->cur_reg == 0x30) && (val & 0x01)) dev->regs[0x22] |= 0x40; if (valxor) - fdc37c932fr_access_bus_handler(dev); + fdc37c93x_access_bus_handler(dev); + break; + } + break; + case 10: + /* Access bus (FDC37C931APM only) */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x70: + if (valxor) + fdc37c93x_acpi_handler(dev); break; } break; @@ -577,12 +647,19 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) } -static uint8_t fdc37c93x_read(uint16_t port, void *priv) +static uint8_t +fdc37c93x_read(uint16_t port, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; uint8_t index = (port & 1) ? 0 : 1; uint8_t ret = 0xff; + /* Compaq Presario 4500: Unlock at FB, Register at EA, Data at EB, Lock at F9. */ + if ((port == 0xea) || (port == 0xf9) || (port == 0xfb)) + index = 1; + else if (port == 0xeb) + index = 0; + if (dev->locked) { if (index) ret = dev->cur_reg; @@ -621,7 +698,7 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->regs[0x26] = 0xF0; dev->regs[0x27] = 0x03; - for (i = 0; i < 10; i++) + for (i = 0; i < 11; i++) memset(dev->ld_regs[i], 0, 256); /* Logical device 0: FDD */ @@ -664,7 +741,7 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->ld_regs[4][0x61] = 0xf8; dev->ld_regs[4][0x70] = 4; dev->ld_regs[4][0xF0] = 3; - serial_setup(dev->uart[0], 0x3f8, dev->ld_regs[4][0x70]); + serial_setup(dev->uart[0], COM1_ADDR, dev->ld_regs[4][0x70]); /* Logical device 5: Serial Port 2 */ dev->ld_regs[5][0x30] = 1; @@ -674,11 +751,11 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->ld_regs[5][0x74] = 4; dev->ld_regs[5][0xF1] = 2; dev->ld_regs[5][0xF2] = 3; - serial_setup(dev->uart[1], 0x2f8, dev->ld_regs[5][0x70]); + serial_setup(dev->uart[1], COM2_ADDR, dev->ld_regs[5][0x70]); /* Logical device 6: RTC */ - dev->ld_regs[5][0x30] = 1; - dev->ld_regs[6][0x63] = 0x00; + dev->ld_regs[6][0x30] = 1; + dev->ld_regs[6][0x63] = (dev->chip_id == 0x30) ? 0x70 : 0x00; dev->ld_regs[6][0xF4] = 3; /* Logical device 7: Keyboard */ @@ -690,17 +767,28 @@ fdc37c93x_reset(fdc37c93x_t *dev) /* Logical device 9: ACCESS.bus */ + /* Logical device A: ACPI */ + fdc37c93x_gpio_handler(dev); fdc37c93x_lpt_handler(dev); fdc37c93x_serial_handler(dev, 0); fdc37c93x_serial_handler(dev, 1); fdc37c93x_auxio_handler(dev); - if (dev->chip_id == 0x03) - fdc37c932fr_access_bus_handler(dev); + if (dev->is_apm || (dev->chip_id == 0x03)) + fdc37c93x_access_bus_handler(dev); + if (dev->is_apm) + fdc37c93x_acpi_handler(dev); fdc_reset(dev->fdc); fdc37c93x_fdc_handler(dev); + if (dev->chip_id == 0x30) { + fdc37c93x_nvr_pri_handler(dev); + fdc37c93x_nvr_sec_handler(dev); + nvr_bank_set(0, 0, dev->nvr); + nvr_bank_set(1, 0xff, dev->nvr); + } + dev->locked = 0; } @@ -726,10 +814,11 @@ access_bus_init(const device_t *info) static const device_t access_bus_device = { "SMC FDC37C932FR ACCESS.bus", + "access_bus", 0, 0x03, access_bus_init, access_bus_close, NULL, - NULL, NULL, NULL, + { NULL }, NULL, NULL, NULL }; @@ -746,6 +835,7 @@ fdc37c93x_close(void *priv) static void * fdc37c93x_init(const device_t *info) { + int is_compaq; fdc37c93x_t *dev = (fdc37c93x_t *) malloc(sizeof(fdc37c93x_t)); memset(dev, 0, sizeof(fdc37c93x_t)); @@ -754,10 +844,13 @@ fdc37c93x_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->chip_id = info->local; + dev->chip_id = info->local & 0xff; + dev->is_apm = (info->local >> 8) & 0x01; + is_compaq = (info->local >> 8) & 0x02; - dev->gpio_regs[0] = 0xFD; - dev->gpio_regs[1] = 0xFF; + dev->gpio_regs[0] = 0xff; + // dev->gpio_regs[1] = (info->local == 0x0030) ? 0xff : 0xfd; + dev->gpio_regs[1] = (dev->chip_id == 0x30) ? 0xff : 0xfd; if (dev->chip_id == 0x30) { dev->nvr = device_add(&at_nvr_device); @@ -766,43 +859,97 @@ fdc37c93x_init(const device_t *info) nvr_bank_set(1, 0xff, dev->nvr); } - if (dev->chip_id == 0x03) + if (dev->is_apm || (dev->chip_id == 0x03)) dev->access_bus = device_add(&access_bus_device); - io_sethandler(0x370, 0x0002, - fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); - io_sethandler(0x3f0, 0x0002, - fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + if (dev->is_apm) + dev->acpi = device_add(&acpi_smc_device); + + if (is_compaq) { + io_sethandler(0x0ea, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + io_sethandler(0x0f9, 0x0001, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + io_sethandler(0x0fb, 0x0001, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + } else { + io_sethandler(FDC_SECONDARY_ADDR, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + io_sethandler(FDC_PRIMARY_ADDR, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + } fdc37c93x_reset(dev); return dev; } +const device_t fdc37c931apm_device = { + .name = "SMC FDC37C932QF Super I/O", + .internal_name = "fdc37c931apm", + .flags = 0, + .local = 0x130, /* Share the same ID with the 932QF. */ + .init = fdc37c93x_init, + .close = fdc37c93x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37c931apm_compaq_device = { + .name = "SMC FDC37C932QF Super I/O (Compaq Presario 4500)", + .internal_name = "fdc37c931apm_compaq", + .flags = 0, + .local = 0x330, /* Share the same ID with the 932QF. */ + .init = fdc37c93x_init, + .close = fdc37c93x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; const device_t fdc37c932fr_device = { - "SMC FDC37C932FR Super I/O", - 0, - 0x03, - fdc37c93x_init, fdc37c93x_close, NULL, - NULL, NULL, NULL, - NULL + .name = "SMC FDC37C932FR Super I/O", + .internal_name = "fdc37c932fr", + .flags = 0, + .local = 0x03, + .init = fdc37c93x_init, + .close = fdc37c93x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc37c932qf_device = { - "SMC FDC37C932QF Super I/O", - 0, - 0x30, /* Share the same ID with the 935. */ - fdc37c93x_init, fdc37c93x_close, NULL, - NULL, NULL, NULL, - NULL + .name = "SMC FDC37C932QF Super I/O", + .internal_name = "fdc37c932qf", + .flags = 0, + .local = 0x30, + .init = fdc37c93x_init, + .close = fdc37c93x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t fdc37c935_device = { - "SMC FDC37C935 Super I/O", - 0, - 0x02, - fdc37c93x_init, fdc37c93x_close, NULL, - NULL, NULL, NULL, - NULL + .name = "SMC FDC37C935 Super I/O", + .internal_name = "fdc37c935", + .flags = 0, + .local = 0x02, + .init = fdc37c93x_init, + .close = fdc37c93x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_fdc37m60x.c b/src/sio/sio_fdc37m60x.c new file mode 100644 index 000000000..a4433e582 --- /dev/null +++ b/src/sio/sio_fdc37m60x.c @@ -0,0 +1,343 @@ +/* + * 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 the SMSC FDC37M60x Super I/O + * + * Authors: Tiseno100 + * Copyright 2020 Tiseno100 + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/keyboard.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + +#define SIO_INDEX_PORT dev->sio_index_port +#define INDEX dev->index + +/* Current Logical Device Number */ +#define CURRENT_LOGICAL_DEVICE dev->regs[0x07] + +/* Global Device Configuration */ +#define ENABLED(ld) dev->device_regs[ld][0x30] +#define BASE_ADDRESS(ld) ((dev->device_regs[ld][0x60] << 8) | \ + (dev->device_regs[ld][0x61])) +#define IRQ(ld) dev->device_regs[ld][0x70] +#define DMA(ld) dev->device_regs[ld][0x74] + +/* Miscellaneous Chip Functionality */ +#define SOFT_RESET (val & 0x01) +#define POWER_CONTROL dev->regs[0x22] + + +#ifdef ENABLE_FDC37M60X_LOG +int fdc37m60x_do_log = ENABLE_FDC37M60X_LOG; + +static void +fdc37m60x_log(const char *fmt, ...) +{ + va_list ap; + + if (fdc37m60x_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define fdc37m60x_log(fmt, ...) +#endif + + +typedef struct +{ + uint8_t index, regs[256], device_regs[10][256], cfg_lock, ide_function; + uint16_t sio_index_port; + + fdc_t * fdc; + serial_t * uart[2]; + +} fdc37m60x_t; + + +static void fdc37m60x_fdc_handler(fdc37m60x_t *dev); +static void fdc37m60x_uart_handler(uint8_t num, fdc37m60x_t *dev); +static void fdc37m60x_lpt_handler(fdc37m60x_t *dev); +static void fdc37m60x_logical_device_handler(fdc37m60x_t *dev); +static void fdc37m60x_reset(void *priv); + + +static void +fdc37m60x_write(uint16_t addr, uint8_t val, void *priv) +{ + fdc37m60x_t *dev = (fdc37m60x_t *)priv; + + if (addr & 1) { + if (!dev->cfg_lock) { + switch (INDEX) { + /* Global Configuration */ + case 0x02: + dev->regs[INDEX] = val; + if (SOFT_RESET) + fdc37m60x_reset(dev); + break; + + case 0x07: + CURRENT_LOGICAL_DEVICE = val; + break; + + case 0x22: + POWER_CONTROL = val & 0x3f; + break; + + case 0x23: + dev->regs[INDEX] = val & 0x3f; + break; + + case 0x24: + dev->regs[INDEX] = val & 0x4e; + break; + + case 0x2b: case 0x2c: case 0x2d: case 0x2e: + case 0x2f: + dev->regs[INDEX] = val; + break; + + /* Device Configuration */ + case 0x30: + case 0x60: case 0x61: + case 0x70: + case 0x74: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + if (CURRENT_LOGICAL_DEVICE <= 0x81) /* Avoid Overflow */ + dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] = (INDEX == 0x30) ? (val & 1) : val; + fdc37m60x_logical_device_handler(dev); + break; + } + } + } else { + /* Enter/Escape Configuration Mode */ + if (val == 0x55) + dev->cfg_lock = 0; + else if (!dev->cfg_lock && (val == 0xaa)) + dev->cfg_lock = 1; + else if (!dev->cfg_lock) + INDEX = val; + } +} + + +static uint8_t +fdc37m60x_read(uint16_t addr, void *priv) +{ + fdc37m60x_t *dev = (fdc37m60x_t *)priv; + uint8_t ret = 0xff; + + if (addr & 1) + ret = (INDEX >= 0x30) ? dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] : dev->regs[INDEX]; + + return ret; +} + + +static void +fdc37m60x_fdc_handler(fdc37m60x_t *dev) +{ + fdc_remove(dev->fdc); + + if (ENABLED(0) || (POWER_CONTROL & 0x01)) + { + fdc_set_base(dev->fdc, BASE_ADDRESS(0)); + fdc_set_irq(dev->fdc, IRQ(0) & 0xf); + fdc_set_dma_ch(dev->fdc, DMA(0) & 0x07); + fdc37m60x_log("SMC60x-FDC: BASE %04x IRQ %d DMA %d\n", BASE_ADDRESS(0), IRQ(0) & 0xf, DMA(0) & 0x07); + } + + fdc_update_enh_mode(dev->fdc, dev->device_regs[0][0xf0] & 0x01); + + fdc_update_densel_force(dev->fdc, (dev->device_regs[0][0xf1] & 0xc) >> 2); + + fdc_update_rwc(dev->fdc, 3, (dev->device_regs[0][0xf2] & 0xc0) >> 6); + fdc_update_rwc(dev->fdc, 2, (dev->device_regs[0][0xf2] & 0x30) >> 4); + fdc_update_rwc(dev->fdc, 1, (dev->device_regs[0][0xf2] & 0x0c) >> 2); + fdc_update_rwc(dev->fdc, 0, (dev->device_regs[0][0xf2] & 0x03)); + + fdc_update_drvrate(dev->fdc, 0, (dev->device_regs[0][0xf4] & 0x18) >> 3); + fdc_update_drvrate(dev->fdc, 1, (dev->device_regs[0][0xf5] & 0x18) >> 3); + fdc_update_drvrate(dev->fdc, 2, (dev->device_regs[0][0xf6] & 0x18) >> 3); + fdc_update_drvrate(dev->fdc, 3, (dev->device_regs[0][0xf7] & 0x18) >> 3); +} + + +static void +fdc37m60x_uart_handler(uint8_t num, fdc37m60x_t *dev) +{ + serial_remove(dev->uart[num & 1]); + + if (ENABLED(4 + (num & 1)) || (POWER_CONTROL & (1 << (4 + (num & 1))))) + { + serial_setup(dev->uart[num & 1], BASE_ADDRESS(4 + (num & 1)), IRQ(4 + (num & 1)) & 0xf); + fdc37m60x_log("SMC60x-UART%d: BASE %04x IRQ %d\n", num & 1, BASE_ADDRESS(4 + (num & 1)), IRQ(4 + (num & 1)) & 0xf); + } +} + + +void fdc37m60x_lpt_handler(fdc37m60x_t *dev) +{ + lpt1_remove(); + + if (ENABLED(3) || (POWER_CONTROL & 0x08)) { + lpt1_init(BASE_ADDRESS(3)); + lpt1_irq(IRQ(3) & 0xf); + fdc37m60x_log("SMC60x-LPT: BASE %04x IRQ %d\n", BASE_ADDRESS(3), IRQ(3) & 0xf); + } +} + + +void fdc37m60x_logical_device_handler(fdc37m60x_t *dev) +{ + /* Register 07h: + Device 0: FDC + Device 3: LPT + Device 4: UART1 + Device 5: UART2 + */ + + switch (CURRENT_LOGICAL_DEVICE) { + case 0x00: + fdc37m60x_fdc_handler(dev); + break; + + case 0x03: + fdc37m60x_lpt_handler(dev); + break; + + case 0x04: + fdc37m60x_uart_handler(0, dev); + break; + + case 0x05: + fdc37m60x_uart_handler(1, dev); + break; + } +} + + +static void +fdc37m60x_reset(void *priv) +{ + fdc37m60x_t *dev = (fdc37m60x_t *) priv; + uint8_t i; + + memset(dev->regs, 0, sizeof(dev->regs)); + for (i = 0; i < 10; i++) + memset(dev->device_regs[i], 0, sizeof(dev->device_regs[i])); + + dev->regs[0x20] = 0x47; + dev->regs[0x24] = 0x04; + dev->regs[0x26] = SIO_INDEX_PORT & 0xf; + dev->regs[0x27] = (SIO_INDEX_PORT >> 4) & 0xf; + + /* FDC Registers */ + dev->device_regs[0][0x60] = 0x03; /* Base Address */ + dev->device_regs[0][0x61] = 0xf0; + dev->device_regs[0][0x70] = 0x06; + dev->device_regs[0][0x74] = 0x02; + dev->device_regs[0][0xf0] = 0x0e; + dev->device_regs[0][0xf2] = 0xff; + + /* LPT Port */ + dev->device_regs[3][0x74] = 0x04; + dev->device_regs[3][0xf0] = 0x3c; + + /* UART1 */ + dev->device_regs[4][0x74] = 0x04; + dev->device_regs[4][0xf1] = 0x02; + dev->device_regs[4][0xf2] = 0x03; + + /* AUX */ + dev->device_regs[8][0xc0] = 0x06; + dev->device_regs[8][0xc1] = 0x03; + + fdc37m60x_fdc_handler(dev); + fdc37m60x_uart_handler(0, dev); + fdc37m60x_uart_handler(1, dev); + fdc37m60x_lpt_handler(dev); +} + + +static void +fdc37m60x_close(void *priv) +{ + fdc37m60x_t *dev = (fdc37m60x_t *)priv; + + free(dev); +} + + +static void * +fdc37m60x_init(const device_t *info) +{ + fdc37m60x_t *dev = (fdc37m60x_t *)malloc(sizeof(fdc37m60x_t)); + memset(dev, 0, sizeof(fdc37m60x_t)); + SIO_INDEX_PORT = info->local; + + dev->fdc = device_add(&fdc_at_smc_device); + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(SIO_INDEX_PORT, 0x0002, fdc37m60x_read, NULL, NULL, fdc37m60x_write, NULL, NULL, dev); + + fdc37m60x_reset(dev); + + return dev; +} + +const device_t fdc37m60x_device = { + .name = "SMSC FDC37M60X", + .internal_name = "fdc37m60x", + .flags = 0, + .local = FDC_PRIMARY_ADDR, + .init = fdc37m60x_init, + .close = fdc37m60x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t fdc37m60x_370_device = { + .name = "SMSC FDC37M60X with 10K Pull Up Resistor", + .internal_name = "fdc37m60x_370", + .flags = 0, + .local = FDC_SECONDARY_ADDR, + .init = fdc37m60x_init, + .close = fdc37m60x_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_it8661f.c b/src/sio/sio_it8661f.c new file mode 100644 index 000000000..31109df91 --- /dev/null +++ b/src/sio/sio_it8661f.c @@ -0,0 +1,350 @@ +/* + * 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 ITE IT8661F chipset. + * + * Note: This Super I/O is partially incomplete and intended only for having the intended machine to function + * + * Authors: Tiseno100 + * + * Copyright 2021 Tiseno100 + * + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdd_common.h> +#include <86box/sio.h> + + +#define LDN dev->regs[7] + + +typedef struct +{ + fdc_t *fdc_controller; + serial_t *uart[2]; + + uint8_t index, regs[256], device_regs[6][256]; + int unlocked, enumerator; +} it8661f_t; + + +static uint8_t mb_pnp_key[32] = {0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39}; + + +static void it8661f_reset(void *priv); + + +#ifdef ENABLE_IT8661_LOG +int it8661_do_log = ENABLE_IT8661_LOG; + + +void +it8661_log(const char *fmt, ...) +{ + va_list ap; + + if (it8661_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define it8661_log(fmt, ...) +#endif + + +static void +it8661_fdc(uint16_t addr, uint8_t val, it8661f_t *dev) +{ + fdc_remove(dev->fdc_controller); + + if (((addr == 0x30) && (val & 1)) || (dev->device_regs[0][0x30] & 1)) { + switch (addr) { + case 0x30: + dev->device_regs[0][addr] = val & 1; + break; + + case 0x31: + dev->device_regs[0][addr] = val & 3; + if (val & 1) + dev->device_regs[0][addr] |= 0x55; + break; + + case 0x60: + case 0x61: + dev->device_regs[0][addr] = val & ((addr == 0x61) ? 0xff : 0xf8); + break; + + case 0x70: + dev->device_regs[0][addr] = val & 0x0f; + break; + + case 0x74: + dev->device_regs[0][addr] = val & 7; + break; + + case 0xf0: + dev->device_regs[0][addr] = val & 0x0f; + break; + } + + fdc_set_base(dev->fdc_controller, (dev->device_regs[0][0x60] << 8) | (dev->device_regs[0][0x61])); + fdc_set_irq(dev->fdc_controller, dev->device_regs[0][0x70] & 0x0f); + fdc_set_dma_ch(dev->fdc_controller, dev->device_regs[0][0x74] & 7); + + if (dev->device_regs[0][0xf0] & 1) + fdc_writeprotect(dev->fdc_controller); + + it8661_log("ITE 8661-FDC: BASE %04x IRQ %02x\n", (dev->device_regs[0][0x60] << 8) | (dev->device_regs[0][0x61]), + dev->device_regs[0][0x70] & 0x0f); + } +} + + +static void +it8661_serial(int uart, uint16_t addr, uint8_t val, it8661f_t *dev) +{ + serial_remove(dev->uart[uart]); + + if (((addr == 0x30) && (val & 1)) || (dev->device_regs[1 + uart][0x30] & 1)) { + switch (addr) { + case 0x30: + dev->device_regs[1 + uart][addr] = val & 1; + break; + + case 0x60: + case 0x61: + dev->device_regs[1 + uart][addr] = val & ((addr == 0x61) ? 0xff : 0xf8); + break; + + case 0x70: + dev->device_regs[1 + uart][addr] = val & 0x0f; + break; + + case 0x74: + dev->device_regs[1 + uart][addr] = val & 7; + break; + + case 0xf0: + dev->device_regs[1 + uart][addr] = val & 3; + break; + } + + serial_setup(dev->uart[uart], (dev->device_regs[1 + uart][0x60] << 8) | (dev->device_regs[1 + uart][0x61]), dev->device_regs[1 + uart][0x70] & 0x0f); + + it8661_log("ITE 8661-UART%01x: BASE %04x IRQ %02x\n", 1 + (LDN % 1), + (dev->device_regs[1 + uart][0x60] << 8) | (dev->device_regs[1 + uart][0x61]), + dev->device_regs[1 + uart][0x70] & 0x0f); + } +} + + +void +it8661_lpt(uint16_t addr, uint8_t val, it8661f_t *dev) +{ + lpt1_remove(); + + if (((addr == 0x30) && (val & 1)) || (dev->device_regs[3][0x30] & 1)) { + switch (addr) { + case 0x30: + dev->device_regs[3][addr] = val & 1; + break; + + case 0x60: + case 0x61: + dev->device_regs[3][addr] = val & ((addr == 0x61) ? 0xff : 0xf8); + break; + + case 0x70: + dev->device_regs[3][addr] = val & 0x0f; + break; + + case 0x74: + dev->device_regs[3][addr] = val & 7; + break; + + case 0xf0: + dev->device_regs[3][addr] = val & 3; + break; + } + + lpt1_init((dev->device_regs[3][0x60] << 8) | (dev->device_regs[3][0x61])); + lpt1_irq(dev->device_regs[3][0x70] & 0x0f); + + it8661_log("ITE 8661-LPT: BASE %04x IRQ %02x\n", (dev->device_regs[3][0x60] << 8) | (dev->device_regs[3][0x61]), + dev->device_regs[3][0x70] & 0x0f); + } +} + + +void +it8661_ldn(uint16_t addr, uint8_t val, it8661f_t *dev) +{ + switch (LDN) { + case 0: + it8661_fdc(addr, val, dev); + break; + case 1: + case 2: + it8661_serial(LDN & 2, addr, val, dev); + break; + case 3: + it8661_lpt(addr, val, dev); + break; + } +} + + +static void +it8661f_write(uint16_t addr, uint8_t val, void *priv) +{ + it8661f_t *dev = (it8661f_t *)priv; + + switch (addr) { + case FDC_SECONDARY_ADDR: + if (!dev->unlocked) { + (val == mb_pnp_key[dev->enumerator]) ? dev->enumerator++ : (dev->enumerator = 0); + if (dev->enumerator == 31) { + dev->unlocked = 1; + it8661_log("ITE8661F: Unlocked!\n"); + } + } else + dev->index = val; + break; + + case 0x371: + if (dev->unlocked) { + switch (dev->index) { + case 0x02: + dev->regs[dev->index] = val; + if (val & 1) + it8661f_reset(dev); + if (val & 2) + dev->unlocked = 0; + break; + case 0x07: + dev->regs[dev->index] = val; + break; + case 0x22: + dev->regs[dev->index] = val & 0x30; + break; + case 0x23: + dev->regs[dev->index] = val & 0x1f; + break; + default: + it8661_ldn(dev->index, val, dev); + break; + } + } + break; + } + + return; +} + + +static uint8_t +it8661f_read(uint16_t addr, void *priv) +{ + it8661f_t *dev = (it8661f_t *)priv; + + it8661_log("IT8661F:\n", addr, dev->regs[dev->index]); + return (addr == 0xa79) ? dev->regs[dev->index] : 0xff; +} + + +static void +it8661f_reset(void *priv) +{ + it8661f_t *dev = (it8661f_t *)priv; + dev->regs[0x20] = 0x86; + dev->regs[0x21] = 0x61; + + dev->device_regs[0][0x60] = 3; + dev->device_regs[0][0x61] = 0xf0; + dev->device_regs[0][0x70] = 6; + dev->device_regs[0][0x71] = 2; + dev->device_regs[0][0x74] = 2; + + dev->device_regs[1][0x60] = 3; + dev->device_regs[1][0x61] = 0xf8; + dev->device_regs[1][0x70] = 4; + dev->device_regs[1][0x71] = 2; + + dev->device_regs[2][0x60] = 2; + dev->device_regs[2][0x61] = 0xf8; + dev->device_regs[2][0x70] = 3; + dev->device_regs[2][0x71] = 2; + + dev->device_regs[3][0x60] = 3; + dev->device_regs[3][0x61] = 0x78; + dev->device_regs[3][0x70] = 7; + dev->device_regs[3][0x71] = 2; + dev->device_regs[3][0x74] = 3; + dev->device_regs[3][0xf0] = 3; +} + + +static void +it8661f_close(void *priv) +{ + it8661f_t *dev = (it8661f_t *)priv; + + free(dev); +} + + +static void * +it8661f_init(const device_t *info) +{ + it8661f_t *dev = (it8661f_t *)malloc(sizeof(it8661f_t)); + memset(dev, 0, sizeof(it8661f_t)); + + dev->fdc_controller = device_add(&fdc_at_smc_device); + fdc_reset(dev->fdc_controller); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(FDC_SECONDARY_ADDR, 0x0002, it8661f_read, NULL, NULL, it8661f_write, NULL, NULL, dev); + + dev->enumerator = 0; + dev->unlocked = 0; + + it8661f_reset(dev); + return dev; +} + +const device_t it8661f_device = { + .name = "ITE IT8661F", + .internal_name = "it8661f", + .flags = 0, + .local = 0, + .init = it8661f_init, + .close = it8661f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index 604567395..5037768fd 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -90,27 +90,27 @@ static void lpt1_handler(pc87306_t *dev) { int temp; - uint16_t lptba, lpt_port = 0x378; - uint8_t lpt_irq = 5; + uint16_t lptba, lpt_port = LPT1_ADDR; + uint8_t lpt_irq = LPT2_IRQ; temp = dev->regs[0x01] & 3; lptba = ((uint16_t) dev->regs[0x19]) << 2; switch (temp) { case 0: - lpt_port = 0x378; - lpt_irq = (dev->regs[0x02] & 0x08) ? 7 : 5; + lpt_port = LPT1_ADDR; + lpt_irq = (dev->regs[0x02] & 0x08) ? LPT1_IRQ : LPT2_IRQ; break; case 1: if (dev->regs[0x1b] & 0x40) lpt_port = lptba; else - lpt_port = 0x3bc; - lpt_irq = 7; + lpt_port = LPT_MDA_ADDR; + lpt_irq = LPT_MDA_IRQ; break; case 2: - lpt_port = 0x278; - lpt_irq = 5; + lpt_port = LPT2_ADDR; + lpt_irq = LPT2_IRQ; break; case 3: lpt_port = 0x000; @@ -149,21 +149,21 @@ serial_handler(pc87306_t *dev, int uart) switch (temp) { case 0: - serial_setup(dev->uart[uart], SERIAL1_ADDR, irq); + serial_setup(dev->uart[uart], COM1_ADDR, irq); break; case 1: - serial_setup(dev->uart[uart], SERIAL2_ADDR, irq); + serial_setup(dev->uart[uart], COM2_ADDR, irq); break; case 2: switch ((dev->regs[1] >> 6) & 3) { case 0: - serial_setup(dev->uart[uart], 0x3e8, irq); + serial_setup(dev->uart[uart], COM3_ADDR, irq); break; case 1: serial_setup(dev->uart[uart], 0x338, irq); break; case 2: - serial_setup(dev->uart[uart], 0x2e8, irq); + serial_setup(dev->uart[uart], COM4_ADDR, irq); break; case 3: serial_setup(dev->uart[uart], 0x220, irq); @@ -173,7 +173,7 @@ serial_handler(pc87306_t *dev, int uart) case 3: switch ((dev->regs[1] >> 6) & 3) { case 0: - serial_setup(dev->uart[uart], 0x2e8, irq); + serial_setup(dev->uart[uart], COM4_ADDR, irq); break; case 1: serial_setup(dev->uart[uart], 0x238, irq); @@ -242,7 +242,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) if (valxor & 0x28) { fdc_remove(dev->fdc); if ((val & 8) && !(dev->regs[2] & 1)) - fdc_set_base(dev->fdc, (val & 0x20) ? 0x370 : 0x3f0); + fdc_set_base(dev->fdc, (val & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); } break; case 1: @@ -277,7 +277,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) if (dev->regs[0] & 4) serial_handler(dev, 1); if (dev->regs[0] & 8) - fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? 0x370 : 0x3f0); + fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); } } if (valxor & 8) { @@ -418,12 +418,16 @@ pc87306_init(const device_t *info) return dev; } - const device_t pc87306_device = { - "National Semiconductor PC87306 Super I/O", - 0, - 0, - pc87306_init, pc87306_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor PC87306 Super I/O", + .internal_name = "pc87306", + .flags = 0, + .local = 0, + .init = pc87306_init, + .close = pc87306_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index 0921c4677..91dd1f59d 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -38,9 +38,10 @@ typedef struct { uint8_t id, pm_idx, regs[48], ld_regs[256][208], - pcregs[16], gpio[8], + pcregs[16], gpio[2][4], pm[8]; - uint16_t gpio_base, pm_base; + uint16_t gpio_base, gpio_base2, + pm_base; int cur_reg; fdc_t *fdc; serial_t *uart[2]; @@ -56,8 +57,9 @@ static void pc87307_gpio_write(uint16_t port, uint8_t val, void *priv) { pc87307_t *dev = (pc87307_t *) priv; + uint8_t bank = ((port & 0xfffc) == dev->gpio_base2); - dev->gpio[port & 7] = val; + dev->gpio[bank][port & 3] = val; } @@ -65,8 +67,17 @@ uint8_t pc87307_gpio_read(uint16_t port, void *priv) { pc87307_t *dev = (pc87307_t *) priv; + uint8_t pins = 0xff, bank = ((port & 0xfffc) == dev->gpio_base2); + uint8_t mask, ret = dev->gpio[bank][port & 0x0003]; - return dev->gpio[port & 7]; + switch (port & 0x0003) { + case 0x0000: + mask = dev->gpio[bank][0x0001]; + ret = (ret & mask) | (pins & ~mask); + break; + } + + return ret; } @@ -74,19 +85,27 @@ static void pc87307_gpio_remove(pc87307_t *dev) { if (dev->gpio_base != 0xffff) { - io_removehandler(dev->gpio_base, 0x0008, + io_removehandler(dev->gpio_base, 0x0002, pc87307_gpio_read, NULL, NULL, pc87307_gpio_write, NULL, NULL, dev); dev->gpio_base = 0xffff; } + + if (dev->gpio_base2 != 0xffff) { + io_removehandler(dev->gpio_base2, 0x0002, + pc87307_gpio_read, NULL, NULL, pc87307_gpio_write, NULL, NULL, dev); + dev->gpio_base2 = 0xffff; + } } static void -pc87307_gpio_init(pc87307_t *dev, uint16_t addr) +pc87307_gpio_init(pc87307_t *dev, int bank, uint16_t addr) { - dev->gpio_base = addr; + uint16_t *bank_base = bank ? &(dev->gpio_base2) : &(dev->gpio_base); - io_sethandler(dev->gpio_base, 0x0008, + *bank_base = addr; + + io_sethandler(*bank_base, 0x0002, pc87307_gpio_read, NULL, NULL, pc87307_gpio_write, NULL, NULL, dev); } @@ -157,7 +176,7 @@ fdc_handler(pc87307_t *dev) addr = ((dev->ld_regs[0x03][0x30] << 8) | dev->ld_regs[0x03][0x31]) - 0x0002; irq = (dev->ld_regs[0x03][0x40] & 0x0f); - if (active && (addr <= 0xfff2)) { + if (active && (addr <= 0xfff8)) { fdc_set_base(dev->fdc, addr); fdc_set_irq(dev->fdc, irq); } @@ -212,7 +231,12 @@ gpio_handler(pc87307_t *dev) addr = (dev->ld_regs[0x07][0x30] << 8) | dev->ld_regs[0x07][0x31]; if (active) - pc87307_gpio_init(dev, addr); + pc87307_gpio_init(dev, 0, addr); + + addr = (dev->ld_regs[0x07][0x32] << 8) | dev->ld_regs[0x07][0x33]; + + if (active) + pc87307_gpio_init(dev, 1, addr); } @@ -293,7 +317,7 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) break; case 0x60: case 0x62: dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x07; - if (dev->cur_reg == 0x62) + if ((dev->cur_reg == 0x62) && (dev->regs[0x07] != 0x07)) break; switch (dev->regs[0x07]) { case 0x03: @@ -322,7 +346,7 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfb; break; case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; fdc_handler(dev); break; case 0x04: @@ -350,6 +374,10 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) case 0x63: if (dev->regs[0x07] == 0x00) dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfb) | 0x04; + else if (dev->regs[0x07] == 0x07) { + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; + gpio_handler(dev); + } break; case 0x70: case 0x74: case 0x75: @@ -413,11 +441,11 @@ pc87307_read(uint16_t port, void *priv) ret = dev->cur_reg; else { if (dev->cur_reg >= 0x30) - ret = dev->regs[dev->cur_reg]; + ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; else if (dev->cur_reg == 0x24) ret = dev->pcregs[dev->regs[0x23]]; else - ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; + ret = dev->regs[dev->cur_reg]; } return ret; @@ -497,8 +525,16 @@ pc87307_reset(pc87307_t *dev) dev->ld_regs[0x08][0x44] = 0x04; dev->ld_regs[0x08][0x45] = 0x04; - dev->gpio[0] = 0xff; - dev->gpio[1] = 0xfb; + // dev->gpio[0] = 0xff; + // dev->gpio[1] = 0xfb; + dev->gpio[0][0] = 0xff; + dev->gpio[0][1] = 0x00; + dev->gpio[0][2] = 0x00; + dev->gpio[0][3] = 0xff; + dev->gpio[1][0] = 0xff; + dev->gpio[1][1] = 0x00; + dev->gpio[1][2] = 0x00; + dev->gpio[1][3] = 0xff; dev->pm[0] = 0xff; dev->pm[1] = 0xff; @@ -542,28 +578,70 @@ pc87307_init(const device_t *info) pc87307_reset(dev); - io_sethandler(0x02e, 0x0002, - pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + if (info->local & 0x100) { + io_sethandler(0x02e, 0x0002, + pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + } + if (info->local & 0x200) { + io_sethandler(0x15c, 0x0002, + pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + } return dev; } - const device_t pc87307_device = { - "National Semiconductor PC87307 Super I/O", - 0, - 0xc0, - pc87307_init, pc87307_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor PC87307 Super I/O", + .internal_name = "pc87307", + .flags = 0, + .local = 0x1c0, + .init = pc87307_init, + .close = pc87307_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +const device_t pc87307_15c_device = { + .name = "National Semiconductor PC87307 Super I/O (Port 15Ch)", + .internal_name = "pc87307_15c", + .flags = 0, + .local = 0x2c0, + .init = pc87307_init, + .close = pc87307_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87307_both_device = { + .name = "National Semiconductor PC87307 Super I/O (Ports 2Eh and 15Ch)", + .internal_name = "pc87307_both", + .flags = 0, + .local = 0x3c0, + .init = pc87307_init, + .close = pc87307_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; const device_t pc97307_device = { - "National Semiconductor PC97307 Super I/O", - 0, - 0xcf, - pc87307_init, pc87307_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor PC97307 Super I/O", + .internal_name = "pc97307", + .flags = 0, + .local = 0x1cf, + .init = pc87307_init, + .close = pc87307_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index f60d02374..bf261a26f 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -56,10 +56,9 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv) { pc87309_t *dev = (pc87309_t *) priv; - if (port & 1) + if (port & 1) { dev->pm[dev->pm_idx] = val; - else { - dev->pm_idx = val & 0x07; + switch (dev->pm_idx) { case 0x00: fdc_handler(dev); @@ -68,7 +67,8 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv) serial_handler(dev, 0); break; } - } + } else + dev->pm_idx = val & 0x07; } @@ -255,7 +255,7 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) case 0x61: switch (dev->regs[0x07]) { case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; fdc_handler(dev); break; case 0x01: @@ -337,9 +337,9 @@ pc87309_read(uint16_t port, void *priv) if (index) ret = dev->cur_reg & 0x1f; else { - if (dev->cur_reg == 8) - ret = 0x70; - else if (dev->cur_reg < 28) + if (dev->cur_reg >= 0x30) + ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; + else ret = dev->regs[dev->cur_reg]; } @@ -420,7 +420,7 @@ pc87309_reset(pc87309_t *dev) dev->regs[0x12] = 0x30; dev->regs[0x19] = 0xEF; - dev->pm[0] = 0xe9; + dev->pm[0] = 0x79; dev->pm[4] = 0x0e; dev->pm_base = 0xffff; @@ -460,18 +460,41 @@ pc87309_init(const device_t *info) pc87309_reset(dev); - io_sethandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + if (info->local & 0x100) { + io_sethandler(0x15c, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + } else { + io_sethandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + } return dev; } - const device_t pc87309_device = { - "National Semiconductor PC87309 Super I/O", - 0, - 0xe0, - pc87309_init, pc87309_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor PC87309 Super I/O", + .internal_name = "pc87309", + .flags = 0, + .local = 0xe0, + .init = pc87309_init, + .close = pc87309_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87309_15c_device = { + .name = "National Semiconductor PC87309 Super I/O (Port 15Ch)", + .internal_name = "pc87309_15c", + .flags = 0, + .local = 0x1e0, + .init = pc87309_init, + .close = pc87309_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_pc87310.c b/src/sio/sio_pc87310.c new file mode 100644 index 000000000..7817fee9d --- /dev/null +++ b/src/sio/sio_pc87310.c @@ -0,0 +1,292 @@ +/* + * 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 the NatSemi PC87310 Super I/O chip. + * + * + * + * Author: Miran Grca, + * Tiseno100 + * EngiNerd + * + * Copyright 2020 Miran Grca. + * Copyright 2020 Tiseno100 + * Copyright 2021 EngiNerd. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + +#define HAS_IDE_FUNCTIONALITY dev->ide_function + +#ifdef ENABLE_PC87310_LOG +int pc87310_do_log = ENABLE_PC87310_LOG; +static void +pc87310_log(const char *fmt, ...) +{ + va_list ap; + + if (pc87310_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pc87310_log(fmt, ...) +#endif + +typedef struct { + uint8_t tries, ide_function, + reg; + fdc_t *fdc; + serial_t *uart[2]; +} pc87310_t; + + +static void +lpt1_handler(pc87310_t *dev) +{ + int temp; + uint16_t lpt_port = LPT1_ADDR; + uint8_t lpt_irq = LPT1_IRQ; + + /* bits 0-1: + * 00 378h + * 01 3bch + * 10 278h + * 11 disabled + */ + temp = dev->reg & 3; + + switch (temp) { + case 0: + lpt_port = LPT1_ADDR; + break; + case 1: + lpt_port = LPT_MDA_ADDR; + break; + case 2: + lpt_port = LPT2_ADDR; + break; + case 3: + lpt_port = 0x000; + lpt_irq = 0xff; + break; + } + + if (lpt_port) + lpt1_init(lpt_port); + + lpt1_irq(lpt_irq); +} + + +static void +serial_handler(pc87310_t *dev, int uart) +{ + int temp; + /* bit 2: disable serial port 1 + * bit 3: disable serial port 2 + * bit 4: swap serial ports + */ + temp = (dev->reg >> (2 + uart)) & 1; + + //current serial port is enabled + if (!temp){ + //configure serial port as COM2 + if (((dev->reg >> 4) & 1) ^ uart) + serial_setup(dev->uart[uart], COM2_ADDR, COM2_IRQ); + // configure serial port as COM1 + else + serial_setup(dev->uart[uart], COM1_ADDR, COM1_IRQ); + } +} + + +static void +pc87310_write(uint16_t port, uint8_t val, void *priv) +{ + pc87310_t *dev = (pc87310_t *) priv; + uint8_t valxor; + + // second write to config register + if (dev->tries) { + valxor = val ^ dev->reg; + dev->tries = 0; + dev->reg = val; + // first write to config register + } else { + dev->tries++; + return; + } + + pc87310_log("SIO: written %01X\n", val); + + /* reconfigure parallel port */ + if (valxor & 0x03) { + lpt1_remove(); + /* bits 0-1: 11 disable parallel port */ + if (!((val & 1) && (val & 2))) + lpt1_handler(dev); + } + /* reconfigure serial ports */ + if (valxor & 0x1c) { + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + /* bit 2: 1 disable first serial port */ + if (!(val & 4)) + serial_handler(dev, 0); + /* bit 3: 1 disable second serial port */ + if (!(val & 8)) + serial_handler(dev, 1); + } + /* reconfigure IDE controller */ + if (valxor & 0x20) { + pc87310_log("SIO: HDC disabled\n"); + ide_pri_disable(); + /* bit 5: 1 disable ide controller */ + if (!(val & 0x20) && HAS_IDE_FUNCTIONALITY) { + pc87310_log("SIO: HDC enabled\n"); + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + ide_pri_enable(); + } + } + /* reconfigure floppy disk controller */ + if (valxor & 0x40) { + pc87310_log("SIO: FDC disabled\n"); + fdc_remove(dev->fdc); + /* bit 6: 1 disable fdc */ + if (!(val & 0x40)) { + pc87310_log("SIO: FDC enabled\n"); + fdc_set_base(dev->fdc, FDC_PRIMARY_ADDR); + } + } + return; +} + + +uint8_t +pc87310_read(uint16_t port, void *priv) +{ + pc87310_t *dev = (pc87310_t *) priv; + uint8_t ret = 0xff; + + dev->tries = 0; + + ret = dev->reg; + + pc87310_log("SIO: read %01X\n", ret); + + return ret; +} + + +void +pc87310_reset(pc87310_t *dev) +{ + dev->reg = 0x0; + dev->tries = 0; + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + lpt1_handler(dev); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + serial_handler(dev, 0); + serial_handler(dev, 1); + fdc_reset(dev->fdc); + //ide_pri_enable(); +} + + +static void +pc87310_close(void *priv) +{ + pc87310_t *dev = (pc87310_t *) priv; + + free(dev); +} + + +static void * +pc87310_init(const device_t *info) +{ + pc87310_t *dev = (pc87310_t *) malloc(sizeof(pc87310_t)); + memset(dev, 0, sizeof(pc87310_t)); + + /* Avoid conflicting with machines that make no use of the PC87310 Internal IDE */ + HAS_IDE_FUNCTIONALITY = info->local; + + dev->fdc = device_add(&fdc_at_nsc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + if (HAS_IDE_FUNCTIONALITY) + device_add(&ide_isa_device); + + pc87310_reset(dev); + + io_sethandler(0x3f3, 0x0001, + pc87310_read, NULL, NULL, pc87310_write, NULL, NULL, dev); + + + return dev; +} + +const device_t pc87310_device = { + .name = "National Semiconductor PC87310 Super I/O", + .internal_name = "pc87310", + .flags = 0, + .local = 0, + .init = pc87310_init, + .close = pc87310_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87310_ide_device = { + .name = "National Semiconductor PC87310 Super I/O with IDE functionality", + .internal_name = "pc87310_ide", + .flags = 0, + .local = 1, + .init = pc87310_init, + .close = pc87310_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_pc87311.c b/src/sio/sio_pc87311.c new file mode 100644 index 000000000..f52b065df --- /dev/null +++ b/src/sio/sio_pc87311.c @@ -0,0 +1,301 @@ +/* + * 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 the National Semiconductor PC87311 Super I/O + * + * Authors: Tiseno100 + * Copyright 2020 Tiseno100 + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + +#define HAS_IDE_FUNCTIONALITY dev->ide_function + +/* Basic Functionalities */ +#define FUNCTION_ENABLE dev->regs[0x00] +#define FUNCTION_ADDRESS dev->regs[0x01] +#define POWER_TEST dev->regs[0x02] + +/* Base Addresses */ +#define LPT_BA (FUNCTION_ADDRESS & 0x03) +#define UART1_BA ((FUNCTION_ADDRESS >> 2) & 0x03) +#define UART2_BA ((FUNCTION_ADDRESS >> 4) & 0x03) +#define COM_BA ((FUNCTION_ADDRESS >> 6) & 0x03) + +#ifdef ENABLE_PC87311_LOG +int pc87311_do_log = ENABLE_PC87311_LOG; +static void +pc87311_log(const char *fmt, ...) +{ + va_list ap; + + if (pc87311_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pc87311_log(fmt, ...) +#endif + +typedef struct +{ + uint8_t index, regs[256], cfg_lock, ide_function; + uint16_t base, irq; + fdc_t *fdc_controller; + serial_t *uart[2]; + +} pc87311_t; + +void pc87311_fdc_handler(pc87311_t *dev); +void pc87311_uart_handler(uint8_t num, pc87311_t *dev); +void pc87311_lpt_handler(pc87311_t *dev); +void pc87311_ide_handler(pc87311_t *dev); +void pc87311_enable(pc87311_t *dev); + +static void +pc87311_write(uint16_t addr, uint8_t val, void *priv) +{ + pc87311_t *dev = (pc87311_t *)priv; + + switch (addr) + { + case 0x398: + case 0x26e: + dev->index = val; + break; + + case 0x399: + case 0x26f: + switch (dev->index) + { + case 0x00: + FUNCTION_ENABLE = val; + break; + case 0x01: + FUNCTION_ADDRESS = val; + break; + case 0x02: + POWER_TEST = val; + break; + } + break; + } + + pc87311_enable(dev); +} + +static uint8_t +pc87311_read(uint16_t addr, void *priv) +{ + pc87311_t *dev = (pc87311_t *)priv; + + return dev->regs[dev->index]; +} + +void pc87311_fdc_handler(pc87311_t *dev) +{ + fdc_remove(dev->fdc_controller); + fdc_set_base(dev->fdc_controller, (FUNCTION_ENABLE & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); + pc87311_log("PC87311-FDC: BASE %04x\n", (FUNCTION_ENABLE & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); +} + +uint16_t com3(pc87311_t *dev) +{ + switch (COM_BA) + { + case 0: + return COM3_ADDR; + case 1: + return 0x0338; + case 2: + return COM4_ADDR; + case 3: + return 0x0220; + default: + return COM3_ADDR; + } +} + +uint16_t com4(pc87311_t *dev) +{ + switch (COM_BA) + { + case 0: + return COM4_ADDR; + case 1: + return 0x0238; + case 2: + return 0x02e0; + case 3: + return 0x0228; + default: + return COM4_ADDR; + } +} + +void pc87311_uart_handler(uint8_t num, pc87311_t *dev) +{ + serial_remove(dev->uart[num & 1]); + + switch (!(num & 1) ? UART1_BA : UART2_BA) + { + case 0: + dev->base = COM1_ADDR; + dev->irq = COM1_IRQ; + break; + case 1: + dev->base = COM2_ADDR; + dev->irq = COM2_IRQ; + break; + case 2: + dev->base = com3(dev); + dev->irq = COM3_IRQ; + break; + case 3: + dev->base = com4(dev); + dev->irq = COM4_IRQ; + break; + } + serial_setup(dev->uart[num & 1], dev->base, dev->irq); + pc87311_log("PC87311-UART%01x: BASE %04x IRQ %01x\n", num & 1, dev->base, dev->irq); +} + +void pc87311_lpt_handler(pc87311_t *dev) +{ + lpt1_remove(); + switch (LPT_BA) + { + case 0: + dev->base = LPT1_ADDR; + dev->irq = (POWER_TEST & 0x08) ? LPT1_IRQ : LPT2_IRQ; + break; + case 1: + dev->base = LPT_MDA_ADDR; + dev->irq = LPT_MDA_IRQ; + break; + case 2: + dev->base = LPT2_ADDR; + dev->irq = LPT2_IRQ; + break; + } + lpt1_init(dev->base); + lpt1_irq(dev->irq); + pc87311_log("PC87311-LPT: BASE %04x IRQ %01x\n", dev->base, dev->irq); +} + +void pc87311_ide_handler(pc87311_t *dev) +{ + ide_pri_disable(); + ide_sec_disable(); + + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + ide_pri_enable(); + + if (FUNCTION_ENABLE & 0x80) + { + ide_set_base(1, 0x170); + ide_set_side(1, 0x376); + ide_sec_enable(); + } + pc87311_log("PC87311-IDE: PRI %01x SEC %01x\n", (FUNCTION_ENABLE >> 6) & 1, (FUNCTION_ENABLE >> 7) & 1); +} + +void pc87311_enable(pc87311_t *dev) +{ + (FUNCTION_ENABLE & 0x01) ? pc87311_lpt_handler(dev) : lpt1_remove(); + (FUNCTION_ENABLE & 0x02) ? pc87311_uart_handler(0, dev) : serial_remove(dev->uart[0]); + (FUNCTION_ENABLE & 0x04) ? pc87311_uart_handler(1, dev) : serial_remove(dev->uart[1]); + (FUNCTION_ENABLE & 0x08) ? pc87311_fdc_handler(dev) : fdc_remove(dev->fdc_controller); + if (FUNCTION_ENABLE & 0x20) + pc87311_fdc_handler(dev); + if (HAS_IDE_FUNCTIONALITY) + { + (FUNCTION_ENABLE & 0x40) ? pc87311_ide_handler(dev) : ide_pri_disable(); + (FUNCTION_ADDRESS & 0x80) ? pc87311_ide_handler(dev) : ide_sec_disable(); + } +} + +static void +pc87311_close(void *priv) +{ + pc87311_t *dev = (pc87311_t *)priv; + + free(dev); +} + +static void * +pc87311_init(const device_t *info) +{ + pc87311_t *dev = (pc87311_t *)malloc(sizeof(pc87311_t)); + memset(dev, 0, sizeof(pc87311_t)); + + /* Avoid conflicting with machines that make no use of the PC87311 Internal IDE */ + HAS_IDE_FUNCTIONALITY = info->local; + + dev->fdc_controller = device_add(&fdc_at_nsc_device); + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + + if (HAS_IDE_FUNCTIONALITY) + device_add(&ide_isa_2ch_device); + + io_sethandler(0x0398, 0x0002, pc87311_read, NULL, NULL, pc87311_write, NULL, NULL, dev); + io_sethandler(0x026e, 0x0002, pc87311_read, NULL, NULL, pc87311_write, NULL, NULL, dev); + + pc87311_enable(dev); + + return dev; +} + +const device_t pc87311_device = { + .name = "National Semiconductor PC87311", + .internal_name = "pc87311", + .flags = 0, + .local = 0, + .init = pc87311_init, + .close = pc87311_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87311_ide_device = { + .name = "National Semiconductor PC87311 with IDE functionality", + .internal_name = "pc87311_ide", + .flags = 0, + .local = 1, + .init = pc87311_init, + .close = pc87311_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_pc87332.c b/src/sio/sio_pc87332.c index 3a9b04785..a2fd7f0d3 100644 --- a/src/sio/sio_pc87332.c +++ b/src/sio/sio_pc87332.c @@ -36,12 +36,11 @@ typedef struct { - uint8_t tries, - regs[15]; + uint8_t tries, has_ide, + fdc_on, regs[15]; int cur_reg; fdc_t *fdc; serial_t *uart[2]; - nvr_t *nvr; } pc87332_t; @@ -49,23 +48,23 @@ static void lpt1_handler(pc87332_t *dev) { int temp; - uint16_t lpt_port = 0x378; - uint8_t lpt_irq = 5; + uint16_t lpt_port = LPT1_ADDR; + uint8_t lpt_irq = LPT2_IRQ; temp = dev->regs[0x01] & 3; switch (temp) { case 0: - lpt_port = 0x378; - lpt_irq = (dev->regs[0x02] & 0x08) ? 7 : 5; + lpt_port = LPT1_ADDR; + lpt_irq = (dev->regs[0x02] & 0x08) ? LPT1_IRQ : LPT2_IRQ; break; case 1: - lpt_port = 0x3bc; - lpt_irq = 7; + lpt_port = LPT_MDA_ADDR; + lpt_irq = LPT_MDA_IRQ; break; case 2: - lpt_port = 0x278; - lpt_irq = 5; + lpt_port = LPT2_ADDR; + lpt_irq = LPT2_IRQ; break; case 3: lpt_port = 0x000; @@ -89,40 +88,40 @@ serial_handler(pc87332_t *dev, int uart) switch (temp) { case 0: - serial_setup(dev->uart[uart], SERIAL1_ADDR, 4); + serial_setup(dev->uart[uart], COM1_ADDR, 4); break; case 1: - serial_setup(dev->uart[uart], SERIAL2_ADDR, 3); + serial_setup(dev->uart[uart], COM2_ADDR, 3); break; case 2: switch ((dev->regs[1] >> 6) & 3) { case 0: - serial_setup(dev->uart[uart], 0x3e8, 4); + serial_setup(dev->uart[uart], COM3_ADDR, COM3_IRQ); break; case 1: - serial_setup(dev->uart[uart], 0x338, 4); + serial_setup(dev->uart[uart], 0x338, COM3_IRQ); break; case 2: - serial_setup(dev->uart[uart], 0x2e8, 4); + serial_setup(dev->uart[uart], COM4_ADDR, COM3_IRQ); break; case 3: - serial_setup(dev->uart[uart], 0x220, 4); + serial_setup(dev->uart[uart], 0x220, COM3_IRQ); break; } break; case 3: switch ((dev->regs[1] >> 6) & 3) { case 0: - serial_setup(dev->uart[uart], 0x2e8, 3); + serial_setup(dev->uart[uart], COM4_ADDR, COM4_IRQ); break; case 1: - serial_setup(dev->uart[uart], 0x238, 3); + serial_setup(dev->uart[uart], 0x238, COM4_IRQ); break; case 2: - serial_setup(dev->uart[uart], 0x2e0, 3); + serial_setup(dev->uart[uart], 0x2e0, COM4_IRQ); break; case 3: - serial_setup(dev->uart[uart], 0x228, 3); + serial_setup(dev->uart[uart], 0x228, COM4_IRQ); break; } break; @@ -130,6 +129,26 @@ serial_handler(pc87332_t *dev, int uart) } +static void +ide_handler(pc87332_t *dev) +{ + /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ + if (dev->has_ide == 2) { + ide_sec_disable(); + ide_set_base(1, (dev->regs[0x00] & 0x80) ? 0x170 : 0x1f0); + ide_set_side(1, (dev->regs[0x00] & 0x80) ? 0x376 : 0x3f6); + if (dev->regs[0x00] & 0x40) + ide_sec_enable(); + } else if (dev->has_ide == 1) { + ide_pri_disable(); + ide_set_base(0, (dev->regs[0x00] & 0x80) ? 0x170 : 0x1f0); + ide_set_side(0, (dev->regs[0x00] & 0x80) ? 0x376 : 0x3f6); + if (dev->regs[0x00] & 0x40) + ide_pri_enable(); + } +} + + static void pc87332_write(uint16_t port, uint8_t val, void *priv) { @@ -176,8 +195,10 @@ pc87332_write(uint16_t port, uint8_t val, void *priv) if (valxor & 0x28) { fdc_remove(dev->fdc); if ((val & 8) && !(dev->regs[2] & 1)) - fdc_set_base(dev->fdc, (val & 0x20) ? 0x370 : 0x3f0); + fdc_set_base(dev->fdc, (val & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); } + if (dev->has_ide && (valxor & 0xc0)) + ide_handler(dev); break; case 1: if (valxor & 3) { @@ -211,7 +232,7 @@ pc87332_write(uint16_t port, uint8_t val, void *priv) if (dev->regs[0] & 4) serial_handler(dev, 1); if (dev->regs[0] & 8) - fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? 0x370 : 0x3f0); + fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); } } if (valxor & 8) { @@ -252,7 +273,9 @@ pc87332_reset(pc87332_t *dev) { memset(dev->regs, 0, 15); - dev->regs[0x00] = 0x0F; + dev->regs[0x00] = dev->fdc_on ? 0x4f : 0x07; + if (dev->has_ide == 2) + dev->regs[0x00] |= 0x80; dev->regs[0x01] = 0x10; dev->regs[0x03] = 0x01; dev->regs[0x05] = 0x0D; @@ -269,6 +292,11 @@ pc87332_reset(pc87332_t *dev) serial_handler(dev, 0); serial_handler(dev, 1); fdc_reset(dev->fdc); + if (!dev->fdc_on) + fdc_remove(dev->fdc); + + if (dev->has_ide) + ide_handler(dev); } @@ -292,22 +320,87 @@ pc87332_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - // dev->nvr = device_add(&piix4_nvr_device); - + dev->has_ide = (info->local >> 8) & 0xff; + dev->fdc_on = (info->local >> 16) & 0xff; pc87332_reset(dev); - io_sethandler(0x02e, 0x0002, - pc87332_read, NULL, NULL, pc87332_write, NULL, NULL, dev); + if ((info->local & 0xff) == (0x01)) { + io_sethandler(0x398, 0x0002, + pc87332_read, NULL, NULL, pc87332_write, NULL, NULL, dev); + } else { + io_sethandler(0x02e, 0x0002, + pc87332_read, NULL, NULL, pc87332_write, NULL, NULL, dev); + } return dev; } - const device_t pc87332_device = { - "National Semiconductor PC87332 Super I/O", - 0, - 0, - pc87332_init, pc87332_close, NULL, - NULL, NULL, NULL, - NULL + .name = "National Semiconductor PC87332 Super I/O", + .internal_name = "pc87332", + .flags = 0, + .local = 0x00, + .init = pc87332_init, + .close = pc87332_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87332_398_device = { + .name = "National Semiconductor PC87332 Super I/O (Port 398h)", + .internal_name = "pc87332_398", + .flags = 0, + .local = 0x01, + .init = pc87332_init, + .close = pc87332_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87332_398_ide_device = { + .name = "National Semiconductor PC87332 Super I/O (Port 398h) (With IDE)", + .internal_name = "pc87332_398_ide", + .flags = 0, + .local = 0x101, + .init = pc87332_init, + .close = pc87332_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87332_398_ide_sec_device = { + .name = "National Semiconductor PC87332 Super I/O (Port 398h) (With Secondary IDE)", + .internal_name = "pc87332_398_ide_sec", + .flags = 0, + .local = 0x201, + .init = pc87332_init, + .close = pc87332_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pc87332_398_ide_fdcon_device = { + .name = "National Semiconductor PC87332 Super I/O (Port 398h) (With IDE and FDC on)", + .internal_name = "pc87332_398_ide_fdcon", + .flags = 0, + .local = 0x10101, + .init = pc87332_init, + .close = pc87332_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_prime3b.c b/src/sio/sio_prime3b.c new file mode 100644 index 000000000..ac00106d3 --- /dev/null +++ b/src/sio/sio_prime3b.c @@ -0,0 +1,297 @@ +/* + * 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 the Goldstar Prime3B Super I/O + * + * Authors: Tiseno100 + * Copyright 2021 Tiseno100 + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + +#define FSR dev->regs[0xa0] +#define ASR dev->regs[0xa1] +#define PDR dev->regs[0xa2] +#define HAS_IDE_FUNCTIONALITY dev->ide_function + +#ifdef ENABLE_PRIME3B_LOG +int prime3b_do_log = ENABLE_PRIME3B_LOG; +static void +prime3b_log(const char *fmt, ...) +{ + va_list ap; + + if (prime3b_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define prime3b_log(fmt, ...) +#endif + +typedef struct +{ + uint8_t index, regs[256], cfg_lock, ide_function; + uint16_t com3_addr, com4_addr; + + fdc_t *fdc_controller; + serial_t *uart[2]; + +} prime3b_t; + +void prime3b_fdc_handler(prime3b_t *dev); +void prime3b_uart_handler(uint8_t num, prime3b_t *dev); +void prime3b_lpt_handler(prime3b_t *dev); +void prime3b_ide_handler(prime3b_t *dev); +void prime3b_enable(prime3b_t *dev); +void prime3b_powerdown(prime3b_t *dev); + +static void +prime3b_write(uint16_t addr, uint8_t val, void *priv) +{ + prime3b_t *dev = (prime3b_t *)priv; + + if (addr == 0x398) + { + dev->index = val; + + /* Enter/Escape Configuration Mode */ + if (val == 0x33) + dev->cfg_lock = 0; + else if (val == 0xcc) + dev->cfg_lock = 1; + } + else if ((addr == 0x399) && !dev->cfg_lock) + { + switch (dev->index) + { + case 0xa0: /* Function Selection Register (FSR) */ + FSR = val; + prime3b_enable(dev); + break; + case 0xa1: /* Address Selection Register (ASR) */ + ASR = val; + prime3b_enable(dev); + break; + case 0xa2: /* Power Down Register (PDR) */ + dev->regs[0xa2] = val; + break; + case 0xa3: /* Test Mode Register (TMR) */ + dev->regs[0xa3] = val; + break; + case 0xa4: /* Miscellaneous Function Register */ + dev->regs[0xa4] = val; + switch ((dev->regs[0xa4] >> 6) & 3) + { + case 0: + dev->com3_addr = COM3_ADDR; + dev->com4_addr = COM4_ADDR; + break; + case 1: + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + break; + case 2: + dev->com3_addr = COM4_ADDR; + dev->com4_addr = 0x2e0; + break; + case 3: + dev->com3_addr = 0x220; + dev->com4_addr = 0x228; + break; + } + break; + case 0xa5: /* ECP Register */ + dev->regs[0xa5] = val; + break; + } + } +} + +static uint8_t +prime3b_read(uint16_t addr, void *priv) +{ + prime3b_t *dev = (prime3b_t *)priv; + + return dev->regs[dev->index]; +} + +void prime3b_fdc_handler(prime3b_t *dev) +{ + uint16_t fdc_base = !(ASR & 0x40) ? FDC_PRIMARY_ADDR : FDC_SECONDARY_ADDR; + fdc_remove(dev->fdc_controller); + fdc_set_base(dev->fdc_controller, fdc_base); + prime3b_log("Prime3B-FDC: Enabled with base %03x\n", fdc_base); +} + +void prime3b_uart_handler(uint8_t num, prime3b_t *dev) +{ + uint16_t uart_base; + if ((ASR >> (3 + 2 * num)) & 1) + uart_base = !((ASR >> (2 + 2 * num)) & 1) ? dev->com3_addr : dev->com4_addr; + else + uart_base = !((ASR >> (2 + 2 * num)) & 1) ? COM1_ADDR : COM2_ADDR; + + serial_remove(dev->uart[num]); + serial_setup(dev->uart[num], uart_base, 4 - num); + prime3b_log("Prime3B-UART%d: Enabled with base %03x\n", num, uart_base); +} + +void prime3b_lpt_handler(prime3b_t *dev) +{ + uint16_t lpt_base = (ASR & 2) ? LPT_MDA_ADDR : (!(ASR & 1) ? LPT1_ADDR : LPT2_ADDR); + lpt1_remove(); + lpt1_init(lpt_base); + lpt1_irq(LPT1_IRQ); + prime3b_log("Prime3B-LPT: Enabled with base %03x\n", lpt_base); +} + +void prime3b_ide_handler(prime3b_t *dev) +{ + ide_pri_disable(); + uint16_t ide_base = !(ASR & 0x80) ? 0x1f0 : 0x170; + uint16_t ide_side = ide_base + 0x206; + ide_set_base(0, ide_base); + ide_set_side(0, ide_side); + prime3b_log("Prime3B-IDE: Enabled with base %03x and side %03x\n", ide_base, ide_side); +} + +void prime3b_enable(prime3b_t *dev) +{ + /* + Simulate a device enable/disable scenario + + Register A0: Function Selection Register (FSR) + Bit 7: Gameport + Bit 6: 4 FDD Enable + Bit 5: IDE + Bit 4: FDC + Bit 3: UART 2 + Bit 2: UART 1 + Bit 1/0: PIO (0/0 Bidirectional , 0/1 ECP, 1/0 EPP, 1/1 Disabled) + + Note: 86Box LPT is simplistic and can't do ECP or EPP. + */ + + !(FSR & 3) ? prime3b_lpt_handler(dev) : lpt1_remove(); + (FSR & 4) ? prime3b_uart_handler(0, dev) : serial_remove(dev->uart[0]); + (FSR & 8) ? prime3b_uart_handler(1, dev) : serial_remove(dev->uart[1]); + (FSR & 0x10) ? prime3b_fdc_handler(dev) : fdc_remove(dev->fdc_controller); + if (HAS_IDE_FUNCTIONALITY) + (FSR & 0x20) ? prime3b_ide_handler(dev) : ide_pri_disable(); +} + +void prime3b_powerdown(prime3b_t *dev) +{ + /* Note: It can be done more efficiently for sure */ + uint8_t old_base = PDR; + + if (PDR & 1) + PDR |= 0x1e; + + if (PDR & 0x40) + io_removehandler(0x0398, 0x0002, prime3b_read, NULL, NULL, prime3b_write, NULL, NULL, dev); + + if (PDR & 2) + fdc_remove(dev->fdc_controller); + + if (PDR & 4) + serial_remove(dev->uart[0]); + + if (PDR & 8) + serial_remove(dev->uart[1]); + + if (PDR & 0x10) + lpt1_remove(); + + if (PDR & 1) + PDR = old_base; +} + +static void +prime3b_close(void *priv) +{ + prime3b_t *dev = (prime3b_t *)priv; + + free(dev); +} + +static void * +prime3b_init(const device_t *info) +{ + prime3b_t *dev = (prime3b_t *)malloc(sizeof(prime3b_t)); + memset(dev, 0, sizeof(prime3b_t)); + + /* Avoid conflicting with machines that make no use of the Prime3B Internal IDE */ + HAS_IDE_FUNCTIONALITY = info->local; + + dev->regs[0xa0] = 3; + + dev->fdc_controller = device_add(&fdc_at_device); + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + if (HAS_IDE_FUNCTIONALITY) + device_add(&ide_isa_device); + + dev->com3_addr = COM3_ADDR; + dev->com4_addr = COM4_ADDR; + fdc_reset(dev->fdc_controller); + + prime3b_enable(dev); + + io_sethandler(0x0398, 0x0002, prime3b_read, NULL, NULL, prime3b_write, NULL, NULL, dev); + + return dev; +} + +const device_t prime3b_device = { + .name = "Goldstar Prime3B", + .internal_name = "prime3b", + .flags = 0, + .local = 0, + .init = prime3b_init, + .close = prime3b_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t prime3b_ide_device = { + .name = "Goldstar Prime3B with IDE functionality", + .internal_name = "prime3b_ide", + .flags = 0, + .local = 1, + .init = prime3b_init, + .close = prime3b_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_prime3c.c b/src/sio/sio_prime3c.c new file mode 100644 index 000000000..ec350ece2 --- /dev/null +++ b/src/sio/sio_prime3c.c @@ -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. + * + * Emulation of the LG Prime3C Super I/O + * + * Authors: Tiseno100 + * Copyright 2020 Tiseno100 + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + +#ifdef ENABLE_PRIME3C_LOG +int prime3c_do_log = ENABLE_PRIME3C_LOG; +static void +prime3c_log(const char *fmt, ...) +{ + va_list ap; + + if (prime3c_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define prime3c_log(fmt, ...) +#endif + +/* Function Select(Note on prime3c_enable) */ +#define FUNCTION_SELECT dev->regs[0xc2] + +/* Base Address Registers */ +#define FDC_BASE_ADDRESS dev->regs[0xc3] +#define IDE_BASE_ADDRESS dev->regs[0xc4] +#define IDE_SIDE_ADDRESS dev->regs[0xc5] +#define LPT_BASE_ADDRESS dev->regs[0xc6] +#define UART1_BASE_ADDRESS dev->regs[0xc7] +#define UART2_BASE_ADDRESS dev->regs[0xc8] + +/* FDC/LPT Configuration */ +#define FDC_LPT_DMA dev->regs[0xc9] +#define FDC_LPT_IRQ dev->regs[0xca] + +/* UART 1/2 Configuration */ +#define UART_IRQ dev->regs[0xcb] + +/* Miscellaneous Configuration*/ +#define FDC_SWAP (dev->regs[0xd6] & 0x01) + +/* IDE functionality(Note on Init) */ +#define HAS_IDE_FUNCTIONALITY dev->ide_function + +typedef struct +{ + uint8_t index, regs[256], cfg_lock, ide_function; + + fdc_t *fdc_controller; + serial_t *uart[2]; + +} prime3c_t; + +void prime3c_fdc_handler(prime3c_t *dev); +void prime3c_uart_handler(uint8_t num, prime3c_t *dev); +void prime3c_lpt_handler(prime3c_t *dev); +void prime3c_ide_handler(prime3c_t *dev); +void prime3c_enable(prime3c_t *dev); + +static void +prime3c_write(uint16_t addr, uint8_t val, void *priv) +{ + prime3c_t *dev = (prime3c_t *)priv; + + switch (addr) + { + case 0x398: + dev->index = val; + + /* Enter/Escape Configuration Mode */ + if (val == 0x33) + dev->cfg_lock = 0; + else if (val == 0x55) + dev->cfg_lock = 1; + break; + + case 0x399: + if (!dev->cfg_lock) + { + switch (dev->index) + { + case 0xc2: + FUNCTION_SELECT = val & 0xbf; + prime3c_enable(dev); + break; + + case 0xc3: + FDC_BASE_ADDRESS = val & 0xfc; + prime3c_fdc_handler(dev); + break; + + case 0xc4: + IDE_BASE_ADDRESS = val & 0xfc; + if (HAS_IDE_FUNCTIONALITY) + prime3c_ide_handler(dev); + break; + + case 0xc5: + IDE_SIDE_ADDRESS = (val & 0xfc) | 0x02; + if (HAS_IDE_FUNCTIONALITY) + prime3c_ide_handler(dev); + break; + + case 0xc6: + LPT_BASE_ADDRESS = val; + break; + + case 0xc7: + UART1_BASE_ADDRESS = val & 0xfe; + prime3c_uart_handler(0, dev); + break; + + case 0xc8: + UART2_BASE_ADDRESS = val & 0xfe; + prime3c_uart_handler(1, dev); + break; + + case 0xc9: + FDC_LPT_DMA = val; + prime3c_fdc_handler(dev); + break; + + case 0xca: + FDC_LPT_IRQ = val; + prime3c_fdc_handler(dev); + prime3c_lpt_handler(dev); + break; + + case 0xcb: + UART_IRQ = val; + prime3c_uart_handler(0, dev); + prime3c_uart_handler(1, dev); + break; + + case 0xcd: + case 0xce: + dev->regs[dev->index] = val; + break; + + case 0xcf: + dev->regs[dev->index] = val & 0x3f; + break; + + case 0xd0: + dev->regs[dev->index] = val & 0xfc; + break; + + case 0xd1: + dev->regs[dev->index] = val & 0x3f; + break; + + case 0xd3: + dev->regs[dev->index] = val & 0x7c; + break; + + case 0xd5: + case 0xd6: + case 0xd7: + case 0xd8: + dev->regs[dev->index] = val; + break; + } + } + break; + } +} + +static uint8_t +prime3c_read(uint16_t addr, void *priv) +{ + prime3c_t *dev = (prime3c_t *)priv; + + return dev->regs[dev->index]; +} + +void prime3c_fdc_handler(prime3c_t *dev) +{ + fdc_remove(dev->fdc_controller); + if (FUNCTION_SELECT & 0x10) + { + fdc_set_base(dev->fdc_controller, FDC_BASE_ADDRESS << 2); + fdc_set_irq(dev->fdc_controller, (FDC_LPT_IRQ >> 4) & 0xf); + fdc_set_dma_ch(dev->fdc_controller, (FDC_LPT_DMA >> 4) & 0xf); + fdc_set_swap(dev->fdc_controller, FDC_SWAP); + prime3c_log("Prime3C-FDC: BASE %04x IRQ %01x DMA %01x\n", FDC_BASE_ADDRESS << 2, (FDC_LPT_IRQ >> 4) & 0xf, (FDC_LPT_DMA >> 4) & 0xf); + } +} + +void prime3c_uart_handler(uint8_t num, prime3c_t *dev) +{ + serial_remove(dev->uart[num & 1]); + if (FUNCTION_SELECT & (!(num & 1) ? 0x04 : 0x08)) + { + serial_setup(dev->uart[num & 1], (!(num & 1) ? UART1_BASE_ADDRESS : UART2_BASE_ADDRESS) << 2, (UART_IRQ >> (!(num & 1) ? 4 : 0)) & 0xf); + prime3c_log("Prime3C-UART%01x: BASE %04x IRQ %01x\n", num & 1, (!(num & 1) ? UART1_BASE_ADDRESS : UART2_BASE_ADDRESS) << 2, (UART_IRQ >> (!(num & 1) ? 4 : 0)) & 0xf); + } +} + +void prime3c_lpt_handler(prime3c_t *dev) +{ + lpt1_remove(); + if (!(FUNCTION_SELECT & 0x03)) + { + + lpt1_init(LPT_BASE_ADDRESS << 2); + lpt1_irq(FDC_LPT_IRQ & 0xf); + prime3c_log("Prime3C-LPT: BASE %04x IRQ %02x\n", LPT_BASE_ADDRESS << 2, FDC_LPT_IRQ & 0xf); + } +} + +void prime3c_ide_handler(prime3c_t *dev) +{ + ide_pri_disable(); + if (FUNCTION_SELECT & 0x20) + { + ide_set_base(0, IDE_BASE_ADDRESS << 2); + ide_set_side(0, IDE_SIDE_ADDRESS << 2); + ide_pri_enable(); + prime3c_log("Prime3C-IDE: BASE %04x SIDE %04x\n", IDE_BASE_ADDRESS << 2, IDE_SIDE_ADDRESS << 2); + } +} + +void prime3c_enable(prime3c_t *dev) +{ +/* +Simulate a device enable/disable scenario + +Register C2: Function Select +Bit 7: Gameport +Bit 6: Reserved +Bit 5: IDE +Bit 4: FDC +Bit 3: UART 2 +Bit 2: UART 1 +Bit 1/0: PIO (0/0 Unidirectional , 0/1 ECP, 1/0 EPP, 1/1 Disabled) + +Note: 86Box LPT is simplistic and can't do ECP or EPP. +*/ + +!(FUNCTION_SELECT & 0x03) ? prime3c_lpt_handler(dev) : lpt1_remove(); +(FUNCTION_SELECT & 0x04) ? prime3c_uart_handler(0, dev) : serial_remove(dev->uart[0]); +(FUNCTION_SELECT & 0x08) ? prime3c_uart_handler(1, dev) : serial_remove(dev->uart[1]); +(FUNCTION_SELECT & 0x10) ? prime3c_fdc_handler(dev) : fdc_remove(dev->fdc_controller); +if (HAS_IDE_FUNCTIONALITY) + (FUNCTION_SELECT & 0x20) ? prime3c_ide_handler(dev) : ide_pri_disable(); +} + +static void +prime3c_close(void *priv) +{ + prime3c_t *dev = (prime3c_t *)priv; + + free(dev); +} + +static void * +prime3c_init(const device_t *info) +{ + prime3c_t *dev = (prime3c_t *)malloc(sizeof(prime3c_t)); + memset(dev, 0, sizeof(prime3c_t)); + + /* Avoid conflicting with machines that make no use of the Prime3C Internal IDE */ + HAS_IDE_FUNCTIONALITY = info->local; + + dev->regs[0xc0] = 0x3c; + dev->regs[0xc2] = 0x03; + dev->regs[0xc3] = 0x3c; + dev->regs[0xc4] = 0x3c; + dev->regs[0xc5] = 0x3d; + dev->regs[0xd5] = 0x3c; + + dev->fdc_controller = device_add(&fdc_at_device); + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + if (HAS_IDE_FUNCTIONALITY) + device_add(&ide_isa_device); + + prime3c_fdc_handler(dev); + prime3c_uart_handler(0, dev); + prime3c_uart_handler(1, dev); + prime3c_lpt_handler(dev); + if (HAS_IDE_FUNCTIONALITY) + prime3c_ide_handler(dev); + + io_sethandler(0x0398, 0x0002, prime3c_read, NULL, NULL, prime3c_write, NULL, NULL, dev); + + return dev; +} + +const device_t prime3c_device = { + .name = "Goldstar Prime3C", + .internal_name = "prime3c", + .flags = 0, + .local = 0, + .init = prime3c_init, + .close = prime3c_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t prime3c_ide_device = { + .name = "Goldstar Prime3C with IDE functionality", + .internal_name = "prime3c_ide", + .flags = 0, + .local = 1, + .init = prime3c_init, + .close = prime3c_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index cdaf8cf72..aece09fe6 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -1,31 +1,30 @@ -/*um8669f : - - aa to 108 unlocks - next 108 write is register select (Cx?) - data read/write to 109 - 55 to 108 locks - -C1 -bit 7 - enable PnP registers - -PnP registers : - -07 - device : - 0 = FDC - 1 = COM1 - 2 = COM2 - 3 = LPT1 - 5 = Game port -30 - enable -60/61 - addr -70 - IRQ -74 - DMA*/ - +/* + * 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 the UMC UM8669F Super I/O chip. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * RichardG, + * + * Copyright 2008-2021 Sarah Walker. + * Copyright 2016-2021 Miran Grca. + * Copyright 2021 RichardG. + */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> @@ -35,149 +34,163 @@ PnP registers : #include <86box/serial.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/gameport.h> #include <86box/sio.h> +#include <86box/isapnp.h> -#define DEV_FDC 0 -#define DEV_COM1 1 -#define DEV_COM2 2 -#define DEV_LPT1 3 -#define DEV_GAME 5 +/* This ROM was reconstructed out of many assumptions, some of which based on the IT8671F. */ +static uint8_t um8669f_pnp_rom[] = { + 0x55, 0xa3, 0x86, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, /* UMC8669, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ -#define REG_DEVICE 0x07 -#define REG_ENABLE 0x30 -#define REG_ADDRHI 0x60 -#define REG_ADDRLO 0x61 -#define REG_IRQ 0x70 -#define REG_DMA 0x74 + 0x15, 0x41, 0xd0, 0x07, 0x00, 0x01, /* logical device PNP0700, can participate in boot */ + 0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */ + 0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */ + 0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */ + 0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */ + 0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x04, 0x00, 0x01, /* logical device PNP0400, can participate in boot */ + 0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */ + 0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0xff, 0xff, 0x00, /* logical device PNPFFFF (just a dummy to create a gap in LDNs) */ + + 0x15, 0x41, 0xd0, 0xb0, 0x2f, 0x01, /* logical device PNPB02F, can participate in boot */ + 0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; +static const isapnp_device_config_t um8669f_pnp_defaults[] = { + { + .activate = 1, + .io = { { .base = FDC_PRIMARY_ADDR }, }, + .irq = { { .irq = FDC_PRIMARY_IRQ }, }, + .dma = { { .dma = FDC_PRIMARY_DMA }, } + }, { + .activate = 1, + .io = { { .base = COM1_ADDR }, }, + .irq = { { .irq = COM1_IRQ }, } + }, { + .activate = 1, + .io = { { .base = COM2_ADDR }, }, + .irq = { { .irq = COM2_IRQ }, } + }, { + .activate = 1, + .io = { { .base = LPT1_ADDR }, }, + .irq = { { .irq = LPT1_IRQ }, } + }, { + .activate = 0 + }, { + .activate = 0, + .io = { { .base = 0x200 }, } + } +}; + + +#ifdef ENABLE_UM8669F_LOG +int um8669f_do_log = ENABLE_UM8669F_LOG; + + +static void +um8669f_log(const char *fmt, ...) +{ + va_list ap; + + if (um8669f_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define um8669f_log(fmt, ...) +#endif typedef struct um8669f_t { - int locked, cur_reg_108, - cur_reg, cur_device, - pnp_active; + int locked, cur_reg_108; + void *pnp_card; + isapnp_device_config_t *pnp_config[5]; - uint8_t regs_108[256]; - - struct { - int enable; - uint16_t addr; - int irq; - int dma; - } dev[8]; + uint8_t regs_108[256]; - fdc_t *fdc; - serial_t *uart[2]; + fdc_t *fdc; + serial_t *uart[2]; + void *gameport; } um8669f_t; static void -um8669f_pnp_write(uint16_t port, uint8_t val, void *priv) +um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { - um8669f_t *dev = (um8669f_t *) priv; - - uint8_t valxor = 0; - uint8_t lpt_irq = 0xff; - - if (port == 0x279) - dev->cur_reg = val; - else { - if (dev->cur_reg == REG_DEVICE) - dev->cur_device = val & 7; - else { - switch (dev->cur_reg) { - case REG_ENABLE: - valxor = dev->dev[dev->cur_device].enable ^ val; - dev->dev[dev->cur_device].enable = val; - break; - case REG_ADDRLO: - valxor = (dev->dev[dev->cur_device].addr & 0xff) ^ val; - dev->dev[dev->cur_device].addr = (dev->dev[dev->cur_device].addr & 0xff00) | val; - break; - case REG_ADDRHI: - valxor = ((dev->dev[dev->cur_device].addr >> 8) & 0xff) ^ val; - dev->dev[dev->cur_device].addr = (dev->dev[dev->cur_device].addr & 0x00ff) | (val << 8); - break; - case REG_IRQ: - valxor = dev->dev[dev->cur_device].irq ^ val; - dev->dev[dev->cur_device].irq = val; - break; - case REG_DMA: - valxor = dev->dev[dev->cur_device].dma ^ val; - dev->dev[dev->cur_device].dma = val; - break; - default: - valxor = 0; - break; - } - - switch (dev->cur_device) { - case DEV_FDC: - if ((dev->cur_reg == REG_ENABLE) && valxor) { - fdc_remove(dev->fdc); - if (dev->dev[DEV_FDC].enable & 1) - fdc_set_base(dev->fdc, 0x03f0); - } - break; - case DEV_COM1: - if ((dev->cur_reg == REG_ENABLE) && valxor) { - serial_remove(dev->uart[0]); - if (dev->dev[DEV_COM1].enable & 1) - serial_setup(dev->uart[0], dev->dev[DEV_COM1].addr, dev->dev[DEV_COM1].irq); - } - break; - case DEV_COM2: - if ((dev->cur_reg == REG_ENABLE) && valxor) { - serial_remove(dev->uart[1]); - if (dev->dev[DEV_COM2].enable & 1) - serial_setup(dev->uart[1], dev->dev[DEV_COM2].addr, dev->dev[DEV_COM2].irq); - } - break; - case DEV_LPT1: - if ((dev->cur_reg == REG_ENABLE) && valxor) { - lpt1_remove(); - if (dev->dev[DEV_LPT1].enable & 1) - lpt1_init(dev->dev[DEV_LPT1].addr); - } - if (dev->dev[DEV_LPT1].irq <= 15) - lpt_irq = dev->dev[DEV_LPT1].irq; - lpt1_irq(lpt_irq); - break; - } - } - } -} - - -static uint8_t -um8669f_pnp_read(uint16_t port, void *priv) -{ - um8669f_t *dev = (um8669f_t *) priv; - uint8_t ret = 0xff; - - switch (dev->cur_reg) { - case REG_DEVICE: - ret = dev->cur_device; - break; - case REG_ENABLE: - ret = dev->dev[dev->cur_device].enable; - break; - case REG_ADDRLO: - ret = dev->dev[dev->cur_device].addr & 0xff; - break; - case REG_ADDRHI: - ret = dev->dev[dev->cur_device].addr >> 8; - break; - case REG_IRQ: - ret = dev->dev[dev->cur_device].irq; - break; - case REG_DMA: - ret = dev->dev[dev->cur_device].dma; - break; + if (ld > 5) { + um8669f_log("UM8669F: Unknown logical device %d\n", ld); + return; } - return ret; + um8669f_t *dev = (um8669f_t *) priv; + + switch (ld) { + case 0: + fdc_remove(dev->fdc); + + if (config->activate) { + um8669f_log("UM8669F: FDC enabled at port %04X IRQ %d DMA %d\n", config->io[0].base, config->irq[0].irq, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma); + + if (config->io[0].base != ISAPNP_IO_DISABLED) + fdc_set_base(dev->fdc, config->io[0].base); + + fdc_set_irq(dev->fdc, config->irq[0].irq); + fdc_set_dma_ch(dev->fdc, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma); + } else { + um8669f_log("UM8669F: FDC disabled\n"); + } + + break; + + case 1: + case 2: + serial_remove(dev->uart[ld - 1]); + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + um8669f_log("UM8669F: UART %d enabled at port %04X IRQ %d\n", ld - 1, config->io[0].base, config->irq[0].irq); + serial_setup(dev->uart[ld - 1], config->io[0].base, config->irq[0].irq); + } else { + um8669f_log("UM8669F: UART %d disabled\n", ld - 1); + } + + break; + + case 3: + lpt1_remove(); + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + um8669f_log("UM8669F: LPT enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq); + lpt1_init(config->io[0].base); + } else { + um8669f_log("UM8669F: LPT disabled\n"); + } + + break; + + case 5: + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base); + gameport_remap(dev->gameport, config->io[0].base); + } else { + um8669f_log("UM8669F: Game port disabled\n"); + gameport_remap(dev->gameport, 0); + } + } } @@ -185,7 +198,8 @@ void um8669f_write(uint16_t port, uint8_t val, void *priv) { um8669f_t *dev = (um8669f_t *) priv; - int new_pnp_active; + + um8669f_log("UM8669F: write(%04X, %02X)\n", port, val); if (dev->locked) { if ((port == 0x108) && (val == 0xaa)) @@ -200,25 +214,8 @@ um8669f_write(uint16_t port, uint8_t val, void *priv) dev->regs_108[dev->cur_reg_108] = val; if (dev->cur_reg_108 == 0xc1) { - new_pnp_active = !!(dev->regs_108[0xc1] & 0x80); - if (new_pnp_active != dev->pnp_active) { - if (new_pnp_active) { - io_sethandler(0x0279, 0x0001, - NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); - io_sethandler(0x0a79, 0x0001, - NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); - io_sethandler(0x03e3, 0x0001, - um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); - } else { - io_removehandler(0x0279, 0x0001, - NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); - io_removehandler(0x0a79, 0x0001, - NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); - io_removehandler(0x03e3, 0x0001, - um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); - } - dev->pnp_active = new_pnp_active; - } + um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis"); + isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE); } } } @@ -238,6 +235,8 @@ um8669f_read(uint16_t port, void *priv) ret = dev->regs_108[dev->cur_reg_108]; } + um8669f_log("UM8669F: read(%04X) = %02X\n", port, ret); + return ret; } @@ -245,42 +244,21 @@ um8669f_read(uint16_t port, void *priv) void um8669f_reset(um8669f_t *dev) { + um8669f_log("UM8669F: reset()\n"); + fdc_reset(dev->fdc); serial_remove(dev->uart[0]); - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); serial_remove(dev->uart[1]); - serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); lpt1_remove(); - lpt1_init(0x378); - if (dev->pnp_active) { - io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); - io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); - io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); - dev->pnp_active = 0; - } + isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE); dev->locked = 1; - dev->dev[DEV_FDC].enable = 1; - dev->dev[DEV_FDC].addr = 0x03f0; - dev->dev[DEV_FDC].irq = 6; - dev->dev[DEV_FDC].dma = 2; - - dev->dev[DEV_COM1].enable = 1; - dev->dev[DEV_COM1].addr = 0x03f8; - dev->dev[DEV_COM1].irq = 4; - - dev->dev[DEV_COM2].enable = 1; - dev->dev[DEV_COM2].addr = 0x02f8; - dev->dev[DEV_COM2].irq = 3; - - dev->dev[DEV_LPT1].enable = 1; - dev->dev[DEV_LPT1].addr = 0x0378; - dev->dev[DEV_LPT1].irq = 7; + isapnp_reset_card(dev->pnp_card); } @@ -289,6 +267,8 @@ um8669f_close(void *priv) { um8669f_t *dev = (um8669f_t *) priv; + um8669f_log("UM8669F: close()\n"); + free(dev); } @@ -296,14 +276,22 @@ um8669f_close(void *priv) static void * um8669f_init(const device_t *info) { + um8669f_log("UM8669F: init()\n"); + um8669f_t *dev = (um8669f_t *) malloc(sizeof(um8669f_t)); memset(dev, 0, sizeof(um8669f_t)); + dev->pnp_card = isapnp_add_card(um8669f_pnp_rom, sizeof(um8669f_pnp_rom), um8669f_pnp_config_changed, NULL, NULL, NULL, dev); + for (uint8_t i = 0; i < (sizeof(um8669f_pnp_defaults) / sizeof(isapnp_device_config_t)); i++) + isapnp_set_device_defaults(dev->pnp_card, i, &um8669f_pnp_defaults[i]); + dev->fdc = device_add(&fdc_at_smc_device); dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->gameport = gameport_add(&gameport_sio_device); + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); @@ -314,10 +302,15 @@ um8669f_init(const device_t *info) const device_t um8669f_device = { - "UMC UM8669F Super I/O", - 0, - 0, - um8669f_init, um8669f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "UMC UM8669F Super I/O", + .internal_name = "um8669f", + .flags = 0, + .local = 0, + .init = um8669f_init, + .close = um8669f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_vt82c686.c b/src/sio/sio_vt82c686.c new file mode 100644 index 000000000..8d242165e --- /dev/null +++ b/src/sio/sio_vt82c686.c @@ -0,0 +1,317 @@ +/* + * 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 the VIA VT82C686A/B integrated Super I/O. + * + * + * + * Author: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pci.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sio.h> + + +typedef struct { + uint8_t cur_reg, last_val, regs[25], + fdc_dma, fdc_irq, uart_irq[2], lpt_dma, lpt_irq; + fdc_t *fdc; + serial_t *uart[2]; +} vt82c686_t; + + +static uint8_t +get_lpt_length(vt82c686_t *dev) +{ + uint8_t length = 4; /* non-EPP */ + + if ((dev->regs[0x02] & 0x03) == 0x02) + length = 8; /* EPP */ + + return length; +} + + +static void +vt82c686_fdc_handler(vt82c686_t *dev) +{ + uint16_t io_base = (dev->regs[0x03] & 0xfc) << 2; + + fdc_remove(dev->fdc); + + if (dev->regs[0x02] & 0x10) + fdc_set_base(dev->fdc, io_base); + + fdc_set_dma_ch(dev->fdc, dev->fdc_dma); + fdc_set_irq(dev->fdc, dev->fdc_irq); + fdc_set_swap(dev->fdc, dev->regs[0x16] & 0x01); +} + + +static void +vt82c686_lpt_handler(vt82c686_t *dev) +{ + uint16_t io_mask, io_base = dev->regs[0x06] << 2; + int io_len = get_lpt_length(dev); + io_base &= (0xff8 | io_len); + io_mask = 0x3fc; /* non-EPP */ + if (io_len == 8) + io_mask = 0x3f8; /* EPP */ + + lpt1_remove(); + + if (((dev->regs[0x02] & 0x03) != 0x03) && (io_base >= 0x100) && (io_base <= io_mask)) + lpt1_init(io_base); + + if (dev->lpt_irq) { + lpt1_irq(dev->lpt_irq); + } else { + lpt1_irq(0xff); + } +} + + +static void +vt82c686_serial_handler(vt82c686_t *dev, int uart) +{ + serial_remove(dev->uart[uart]); + + if (dev->regs[0x02] & (0x04 << uart)) + serial_setup(dev->uart[uart], dev->regs[0x07 + uart] << 2, dev->uart_irq[uart]); +} + + +static void +vt82c686_write(uint16_t port, uint8_t val, void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + + /* Store last written value for echo (see comment on read). */ + dev->last_val = val; + + /* Write current register index on port 0. */ + if (!(port & 1)) { + dev->cur_reg = val; + return; + } + + /* NOTE: Registers are [0xE0:0xF8] but we store them as [0x00:0x18]. */ + if ((dev->cur_reg < 0xe0) || (dev->cur_reg > 0xf8)) + return; + uint8_t reg = dev->cur_reg & 0x1f; + + /* Read-only registers. */ + if ((reg < 0x02) || (reg == 0x0c)) + return; + + /* Write current register value on port 1. */ + dev->regs[reg] = val; + + /* Update device state. */ + switch (reg) { + case 0x02: + dev->regs[reg] &= 0xbf; + vt82c686_lpt_handler(dev); + vt82c686_serial_handler(dev, 0); + vt82c686_serial_handler(dev, 1); + vt82c686_fdc_handler(dev); + break; + + case 0x03: + dev->regs[reg] &= 0xfc; + vt82c686_fdc_handler(dev); + break; + + case 0x04: + dev->regs[reg] &= 0xfc; + break; + + case 0x05: + dev->regs[reg] |= 0x03; + break; + + case 0x06: + vt82c686_lpt_handler(dev); + break; + + case 0x07: case 0x08: + dev->regs[reg] &= 0xfe; + vt82c686_serial_handler(dev, reg == 0x08); + break; + + case 0x0d: + dev->regs[reg] &= 0x0f; + break; + + case 0x0f: + dev->regs[reg] &= 0x7f; + break; + + case 0x10: + dev->regs[reg] &= 0xf4; + break; + + case 0x11: + dev->regs[reg] &= 0x3f; + break; + + case 0x13: + dev->regs[reg] &= 0xfb; + break; + + case 0x14: case 0x17: + dev->regs[reg] &= 0xfe; + break; + + case 0x16: + dev->regs[reg] &= 0xf7; + vt82c686_fdc_handler(dev); + break; + } +} + + +static uint8_t +vt82c686_read(uint16_t port, void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + + /* NOTE: Registers are [0xE0:0xF8] but we store them as [0x00:0x18]. + Real 686B echoes the last read/written value when reading from + registers outside that range. */ + if (!(port & 1)) + dev->last_val = dev->cur_reg; + else if ((dev->cur_reg >= 0xe0) && (dev->cur_reg <= 0xf8)) + dev->last_val = dev->regs[dev->cur_reg & 0x1f]; + + return dev->last_val; +} + + +/* Writes to Super I/O-related configuration space registers + of the VT82C686 PCI-ISA bridge are sent here by via_pipc.c */ +void +vt82c686_sio_write(uint8_t addr, uint8_t val, void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + + switch (addr) { + case 0x50: + dev->fdc_dma = val & 0x03; + vt82c686_fdc_handler(dev); + dev->lpt_dma = (val >> 2) & 0x03; + vt82c686_lpt_handler(dev); + break; + + case 0x51: + dev->fdc_irq = val & 0x0f; + vt82c686_fdc_handler(dev); + dev->lpt_irq = val >> 4; + vt82c686_lpt_handler(dev); + break; + + case 0x52: + dev->uart_irq[0] = val & 0x0f; + vt82c686_serial_handler(dev, 0); + dev->uart_irq[1] = val >> 4; + vt82c686_serial_handler(dev, 1); + break; + + case 0x85: + io_removehandler(FDC_PRIMARY_ADDR, 2, vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev); + if (val & 0x02) + io_sethandler(FDC_PRIMARY_ADDR, 2, vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev); + break; + } +} + + +static void +vt82c686_reset(vt82c686_t *dev) +{ + memset(dev->regs, 0, 20); + + dev->regs[0x00] = 0x3c; + dev->regs[0x02] = 0x03; + dev->regs[0x03] = 0xfc; + dev->regs[0x06] = 0xde; + dev->regs[0x07] = 0xfe; + dev->regs[0x08] = 0xbe; + + fdc_reset(dev->fdc); + + serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ); + serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); + + vt82c686_lpt_handler(dev); + vt82c686_serial_handler(dev, 0); + vt82c686_serial_handler(dev, 1); + vt82c686_fdc_handler(dev); + + vt82c686_sio_write(0x85, 0x00, dev); +} + + +static void +vt82c686_close(void *priv) +{ + vt82c686_t *dev = (vt82c686_t *) priv; + + free(dev); +} + + +static void * +vt82c686_init(const device_t *info) +{ + vt82c686_t *dev = (vt82c686_t *) malloc(sizeof(vt82c686_t)); + memset(dev, 0, sizeof(vt82c686_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + dev->fdc_dma = 2; + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->lpt_dma = 3; + + vt82c686_reset(dev); + + return dev; +} + + +const device_t via_vt82c686_sio_device = { + .name = "VIA VT82C686 Integrated Super I/O", + .internal_name = "via_vt82c686_sio", + .flags = 0, + .local = 0, + .init = vt82c686_init, + .close = vt82c686_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sio/sio_w83787f.c b/src/sio/sio_w83787f.c index bc1a4792c..393ab5fd9 100644 --- a/src/sio/sio_w83787f.c +++ b/src/sio/sio_w83787f.c @@ -16,24 +16,44 @@ * Author: Miran Grca, * Copyright 2020 Miran Grca. */ -#include +#include #include +#include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> #include <86box/timer.h> -#include <86box/pci.h> #include <86box/mem.h> -#include <86box/rom.h> #include <86box/lpt.h> #include <86box/serial.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/gameport.h> #include <86box/sio.h> +#ifdef ENABLE_W83787_LOG +int w83787_do_log = ENABLE_W83787_LOG; +static void +w83787_log(const char *fmt, ...) +{ + va_list ap; + + if (w83787_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define w83787_log(fmt, ...) +#endif #define FDDA_TYPE (dev->regs[7] & 3) #define FDDB_TYPE ((dev->regs[7] >> 2) & 3) @@ -52,15 +72,18 @@ #define HEFERE ((dev->regs[0xC] >> 5) & 1) +#define HAS_IDE_FUNCTIONALITY dev->ide_function typedef struct { uint8_t tries, regs[42]; uint16_t reg_init; int locked, rw_locked, cur_reg, - key; + key, ide_function, + ide_start; fdc_t *fdc; serial_t *uart[2]; + void *gameport; } w83787f_t; @@ -71,9 +94,9 @@ static uint8_t w83787f_read(uint16_t port, void *priv); static void w83787f_remap(w83787f_t *dev) { - io_removehandler(0x250, 0x0003, + io_removehandler(0x250, 0x0004, w83787f_read, NULL, NULL, w83787f_write, NULL, NULL, dev); - io_sethandler(0x250, 0x0003, + io_sethandler(0x250, 0x0004, w83787f_read, NULL, NULL, w83787f_write, NULL, NULL, dev); dev->key = 0x88 | HEFERE; } @@ -104,27 +127,27 @@ w83787f_serial_handler(w83787f_t *dev, int uart) int urs0 = !!(dev->regs[1] & (1 << uart)); int urs1 = !!(dev->regs[1] & (4 << uart)); int urs2 = !!(dev->regs[3] & (8 >> uart)); - int urs, irq = 4; - uint16_t addr = 0x3f8, enable = 1; + int urs, irq = COM1_IRQ; + uint16_t addr = COM1_ADDR, enable = 1; urs = (urs1 << 1) | urs0; if (urs2) { - addr = uart ? 0x3f8 : 0x2f8; - irq = uart ? 4 : 3; + addr = uart ? COM1_ADDR : COM2_ADDR; + irq = uart ? COM1_IRQ : COM2_IRQ; } else { switch (urs) { case 0: - addr = uart ? 0x3e8 : 0x2e8; - irq = uart ? 4 : 3; + addr = uart ? COM3_ADDR : COM4_ADDR; + irq = uart ? COM3_IRQ : COM4_IRQ; break; case 1: - addr = uart ? 0x2e8 : 0x3e8; - irq = uart ? 3 : 4; + addr = uart ? COM4_ADDR : COM3_ADDR; + irq = uart ? COM4_IRQ : COM3_IRQ; break; case 2: - addr = uart ? 0x2f8 : 0x3f8; - irq = uart ? 3 : 4; + addr = uart ? COM2_ADDR : COM1_ADDR; + irq = uart ? COM2_IRQ : COM1_IRQ; break; case 3: default: @@ -145,27 +168,24 @@ w83787f_serial_handler(w83787f_t *dev, int uart) static void w83787f_lpt_handler(w83787f_t *dev) { - int ptrs0 = !!(dev->regs[1] & 4); - int ptrs1 = !!(dev->regs[1] & 5); - int ptrs, irq = 7; - uint16_t addr = 0x378, enable = 1; + int ptras = (dev->regs[1] >> 4) & 0x03; + int irq = LPT1_IRQ; + uint16_t addr = LPT1_ADDR, enable = 1; - ptrs = (ptrs1 << 1) | ptrs0; - - switch (ptrs) { - case 0: - addr = 0x3bc; - irq = 7; + switch (ptras) { + case 0x00: + addr = LPT_MDA_ADDR; + irq = LPT_MDA_IRQ; break; - case 1: - addr = 0x278; - irq = 5; + case 0x01: + addr = LPT2_ADDR; + irq = LPT2_IRQ; break; - case 2: - addr = 0x378; - irq = 7; + case 0x02: + addr = LPT1_ADDR; + irq = LPT1_IRQ; break; - case 3: + case 0x03: default: enable = 0; break; @@ -182,12 +202,43 @@ w83787f_lpt_handler(w83787f_t *dev) } +static void +w83787f_gameport_handler(w83787f_t *dev) +{ + if (!(dev->regs[3] & 0x40) && !(dev->regs[4] & 0x40)) + gameport_remap(dev->gameport, 0x201); + else + gameport_remap(dev->gameport, 0); +} + + static void w83787f_fdc_handler(w83787f_t *dev) { fdc_remove(dev->fdc); - if (!(dev->regs[0] & 0x20)) - fdc_set_base(dev->fdc, (dev->regs[0] & 0x10) ? 0x03f0 : 0x0370); + if (!(dev->regs[0] & 0x20) && !(dev->regs[6] & 0x08)) + fdc_set_base(dev->fdc, (dev->regs[0] & 0x10) ? FDC_PRIMARY_ADDR : FDC_SECONDARY_ADDR); +} + + +static void +w83787f_ide_handler(w83787f_t *dev) +{ + if (dev->ide_function & 0x20) { + ide_sec_disable(); + if (!(dev->regs[0] & 0x80)) { + ide_set_base(1, (dev->regs[0] & 0x40) ? 0x1f0 : 0x170); + ide_set_side(1, (dev->regs[0] & 0x40) ? 0x3f6 : 0x376); + ide_sec_enable(); + } + } else { + ide_pri_disable(); + if (!(dev->regs[0] & 0x80)) { + ide_set_base(0, (dev->regs[0] & 0x40) ? 0x1f0 : 0x170); + ide_set_side(0, (dev->regs[0] & 0x40) ? 0x3f6 : 0x376); + ide_pri_enable(); + } + } } @@ -222,6 +273,9 @@ w83787f_write(uint16_t port, uint8_t val, void *priv) switch (dev->cur_reg) { case 0: + w83787_log("REG 00: %02X\n", val); + if ((valxor & 0xc0) && (HAS_IDE_FUNCTIONALITY)) + w83787f_ide_handler(dev); if (valxor & 0x30) w83787f_fdc_handler(dev); if (valxor & 0x0c) @@ -240,6 +294,8 @@ w83787f_write(uint16_t port, uint8_t val, void *priv) case 3: if (valxor & 0x80) w83787f_lpt_handler(dev); + if (valxor & 0x40) + w83787f_gameport_handler(dev); if (valxor & 0x08) w83787f_serial_handler(dev, 0); if (valxor & 0x04) @@ -252,13 +308,12 @@ w83787f_write(uint16_t port, uint8_t val, void *priv) w83787f_serial_handler(dev, 0); if (valxor & 0x80) w83787f_lpt_handler(dev); + if (valxor & 0x40) + w83787f_gameport_handler(dev); break; case 6: - if (valxor & 0x08) { - fdc_remove(dev->fdc); - if (!(dev->regs[6] & 0x08)) - fdc_set_base(dev->fdc, 0x03f0); - } + if (valxor & 0x08) + w83787f_fdc_handler(dev); break; case 7: if (valxor & 0x03) @@ -286,6 +341,9 @@ w83787f_write(uint16_t port, uint8_t val, void *priv) if (valxor & 0x80) w83787f_lpt_handler(dev); break; + case 0xB: + w83787_log("Writing %02X to CRB\n", val); + break; case 0xC: if (valxor & 0x20) w83787f_remap(dev); @@ -319,23 +377,50 @@ static void w83787f_reset(w83787f_t *dev) { lpt1_remove(); - lpt1_init(0x378); - lpt1_irq(7); + lpt1_init(LPT1_ADDR); + lpt1_irq(LPT1_IRQ); + + memset(dev->regs, 0, 0x2A); + + if (HAS_IDE_FUNCTIONALITY) { + if (dev->ide_function & 0x20) { + dev->regs[0x00] = 0x90; + ide_sec_disable(); + ide_set_base(1, 0x170); + ide_set_side(1, 0x376); + } else { + dev->regs[0x00] = 0xd0; + ide_pri_disable(); + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + } + + if (dev->ide_start) { + dev->regs[0x00] &= 0x7f; + if (dev->ide_function & 0x20) + ide_sec_enable(); + else + ide_pri_enable(); + } + } else + dev->regs[0x00] = 0xd0; fdc_reset(dev->fdc); - memset(dev->regs, 0, 0x2A); - dev->regs[0x00] = 0x50; dev->regs[0x01] = 0x2C; - dev->regs[0x03] = 0x30; + dev->regs[0x03] = 0x70; dev->regs[0x07] = 0xF5; dev->regs[0x09] = dev->reg_init & 0xff; dev->regs[0x0a] = 0x1F; dev->regs[0x0c] = 0x2C; dev->regs[0x0d] = 0xA3; - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + gameport_remap(dev->gameport, 0); + + serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ); + serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); + + w83787f_lpt_handler(dev); dev->key = 0x89; @@ -361,24 +446,78 @@ w83787f_init(const device_t *info) w83787f_t *dev = (w83787f_t *) malloc(sizeof(w83787f_t)); memset(dev, 0, sizeof(w83787f_t)); + HAS_IDE_FUNCTIONALITY = (info->local & 0x30); + dev->fdc = device_add(&fdc_at_winbond_device); dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->reg_init = info->local; + dev->gameport = gameport_add(&gameport_sio_1io_device); + if ((dev->ide_function & 0x30) == 0x10) + device_add(&ide_isa_device); + + dev->ide_start = !!(info->local & 0x40); + + dev->reg_init = info->local & 0x0f; w83787f_reset(dev); return dev; } - const device_t w83787f_device = { - "Winbond W83787F/IF Super I/O", - 0, - 0x09, - w83787f_init, w83787f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83787F/IF Super I/O", + .internal_name = "w83787f", + .flags = 0, + .local = 0x09, + .init = w83787f_init, + .close = w83787f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t w83787f_ide_device = { + .name = "Winbond W83787F/IF Super I/O (With IDE)", + .internal_name = "w83787f_ide", + .flags = 0, + .local = 0x19, + .init = w83787f_init, + .close = w83787f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t w83787f_ide_en_device = { + .name = "Winbond W83787F/IF Super I/O (With IDE Enabled)", + .internal_name = "w83787f_ide_en", + .flags = 0, + .local = 0x59, + .init = w83787f_init, + .close = w83787f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t w83787f_ide_sec_device = { + .name = "Winbond W83787F/IF Super I/O (With Secondary IDE)", + .internal_name = "w83787f_ide_sec", + .flags = 0, + .local = 0x39, + .init = w83787f_init, + .close = w83787f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_w83877f.c b/src/sio/sio_w83877f.c index 7f562b6be..424414e01 100644 --- a/src/sio/sio_w83877f.c +++ b/src/sio/sio_w83877f.c @@ -81,9 +81,9 @@ w83877f_remap(w83877f_t *dev) io_removehandler(0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); - io_removehandler(0x3f0, 0x0002, + io_removehandler(FDC_PRIMARY_ADDR, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); - dev->base_address = (hefras ? 0x3f0 : 0x250); + dev->base_address = (hefras ? FDC_PRIMARY_ADDR : 0x250); io_sethandler(dev->base_address, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); dev->key_times = hefras + 1; @@ -127,7 +127,7 @@ make_port(w83877f_t *dev, uint8_t reg) p &= 0x3F8; else p &= 0x3FC; - if ((p < 0x100) || (p > 0x3FF)) p = 0x378; + if ((p < 0x100) || (p > 0x3FF)) p = LPT1_ADDR; /* In ECP mode, A10 is active. */ if (l & 0x80) p |= 0x400; @@ -135,12 +135,12 @@ make_port(w83877f_t *dev, uint8_t reg) case 0x24: p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2; p &= 0xFF8; - if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + if ((p < 0x100) || (p > 0x3F8)) p = COM1_ADDR; break; case 0x25: p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2; p &= 0xFF8; - if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + if ((p < 0x100) || (p > 0x3F8)) p = COM2_ADDR; break; } @@ -153,7 +153,7 @@ w83877f_fdc_handler(w83877f_t *dev) { fdc_remove(dev->fdc); if (!(dev->regs[6] & 0x08) && (dev->regs[0x20] & 0xc0)) - fdc_set_base(dev->fdc, 0x03f0); + fdc_set_base(dev->fdc, FDC_PRIMARY_ADDR); } @@ -190,20 +190,12 @@ w83877f_serial_handler(w83877f_t *dev, int uart) if (!(dev->regs[4] & reg_mask) && (dev->regs[reg_id] & 0xc0)) serial_setup(dev->uart[uart], make_port(dev, reg_id), (dev->regs[0x28] & irq_mask) >> irq_shift); - switch (!!(dev->regs[0x19] & (0x02 >> uart))) { - case 0: - switch (!!(dev->regs[0x03] & (0x02 >> uart))) { - case 0: - clock_src = 24000000.0 / 13.0; - break; - case 1: - clock_src = 24000000.0 / 12.0; - break; - } - break; - case 1: - clock_src = 14769000.0; - break; + if (dev->regs[0x19] & (0x02 >> uart)) { + clock_src = 14769000.0; + } else if (dev->regs[0x03] & (0x02 >> uart)) { + clock_src = 24000000.0 / 12.0; + } else { + clock_src = 24000000.0 / 13.0; } serial_set_clock_src(dev->uart[uart], clock_src); @@ -227,7 +219,7 @@ w83877f_write(uint16_t port, uint8_t val, void *priv) if (val <= max) dev->cur_reg = val; return; - } else if (port == 0x03f0) { + } else if (port == FDC_PRIMARY_ADDR) { if ((val == dev->key) && !dev->locked) { if (dev->key_times == 2) { if (dev->tries) { @@ -383,7 +375,7 @@ w83877f_read(uint16_t port, void *priv) uint8_t ret = 0xff; if (dev->locked) { - if ((port == 0x3f0) || (port == 0x251)) + if ((port == FDC_PRIMARY_ADDR) || (port == 0x251)) ret = dev->cur_reg; else if ((port == 0x3f1) || (port == 0x252)) { if (dev->cur_reg == 7) @@ -411,12 +403,12 @@ w83877f_reset(w83877f_t *dev) dev->regs[0x0d] = 0xA3; dev->regs[0x16] = dev->reg_init & 0xff; dev->regs[0x1e] = 0x81; - dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; + dev->regs[0x20] = (FDC_PRIMARY_ADDR >> 2) & 0xfc; dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - dev->regs[0x23] = (0x378 >> 2); - dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; - dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + dev->regs[0x23] = (LPT1_ADDR >> 2); + dev->regs[0x24] = (COM1_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (COM2_ADDR >> 2) & 0xfe; dev->regs[0x26] = (2 << 4) | 4; dev->regs[0x27] = (2 << 4) | 5; dev->regs[0x28] = (4 << 4) | 3; @@ -429,7 +421,7 @@ w83877f_reset(w83877f_t *dev) w83877f_serial_handler(dev, 0); w83877f_serial_handler(dev, 1); - dev->base_address = 0x3f0; + dev->base_address = FDC_PRIMARY_ADDR; dev->key = 0x89; dev->key_times = 1; @@ -467,42 +459,58 @@ w83877f_init(const device_t *info) return dev; } - const device_t w83877f_device = { - "Winbond W83877F Super I/O", - 0, - 0x0a05, - w83877f_init, w83877f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83877F Super I/O", + .internal_name = "w83877f", + .flags = 0, + .local = 0x0a05, + .init = w83877f_init, + .close = w83877f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t w83877f_president_device = { - "Winbond W83877F Super I/O (President)", - 0, - 0x0a04, - w83877f_init, w83877f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83877F Super I/O (President)", + .internal_name = "w83877f_president", + .flags = 0, + .local = 0x0a04, + .init = w83877f_init, + .close = w83877f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t w83877tf_device = { - "Winbond W83877TF Super I/O", - 0, - 0x0c04, - w83877f_init, w83877f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83877TF Super I/O", + .internal_name = "w83877tf", + .flags = 0, + .local = 0x0c04, + .init = w83877f_init, + .close = w83877f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t w83877tf_acorp_device = { - "Winbond W83877TF Super I/O", - 0, - 0x0c05, - w83877f_init, w83877f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83877TF Super I/O", + .internal_name = "w83877tf_acorp", + .flags = 0, + .local = 0x0c05, + .init = w83877f_init, + .close = w83877f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sio/sio_w83977f.c b/src/sio/sio_w83977f.c index 469428fe6..370bb8c68 100644 --- a/src/sio/sio_w83977f.c +++ b/src/sio/sio_w83977f.c @@ -39,16 +39,20 @@ typedef struct { - uint8_t tries, regs[48], + uint8_t id, tries, + regs[48], dev_regs[256][208]; int locked, rw_locked, cur_reg, base_address, - type; + type, hefras; fdc_t *fdc; serial_t *uart[2]; } w83977f_t; +static int next_id = 0; + + static void w83977f_write(uint16_t port, uint8_t val, void *priv); static uint8_t w83977f_read(uint16_t port, void *priv); @@ -56,12 +60,12 @@ static uint8_t w83977f_read(uint16_t port, void *priv); static void w83977f_remap(w83977f_t *dev) { - io_removehandler(0x3f0, 0x0002, + io_removehandler(FDC_PRIMARY_ADDR, 0x0002, w83977f_read, NULL, NULL, w83977f_write, NULL, NULL, dev); - io_removehandler(0x370, 0x0002, + io_removehandler(FDC_SECONDARY_ADDR, 0x0002, w83977f_read, NULL, NULL, w83977f_write, NULL, NULL, dev); - dev->base_address = (HEFRAS ? 0x370 : 0x3f0); + dev->base_address = (HEFRAS ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); io_sethandler(dev->base_address, 0x0002, w83977f_read, NULL, NULL, w83977f_write, NULL, NULL, dev); @@ -86,6 +90,9 @@ w83977f_fdc_handler(w83977f_t *dev) { uint16_t io_base = (dev->dev_regs[0][0x30] << 8) | dev->dev_regs[0][0x31]; + if (dev->id == 1) + return; + fdc_remove(dev->fdc); if ((dev->dev_regs[0][0x00] & 0x01) && (dev->regs[0x22] & 0x01) && (io_base >= 0x100) && (io_base <= 0xff8)) @@ -105,12 +112,21 @@ w83977f_lpt_handler(w83977f_t *dev) if (io_len == 8) io_mask = 0xff8; - lpt1_remove(); + if (dev->id == 1) { + lpt2_remove(); - if ((dev->dev_regs[1][0x00] & 0x01) && (dev->regs[0x22] & 0x08) && (io_base >= 0x100) && (io_base <= io_mask)) - lpt1_init(io_base); + if ((dev->dev_regs[1][0x00] & 0x01) && (dev->regs[0x22] & 0x08) && (io_base >= 0x100) && (io_base <= io_mask)) + lpt2_init(io_base); - lpt1_irq(dev->dev_regs[1][0x40] & 0x0f); + lpt2_irq(dev->dev_regs[1][0x40] & 0x0f); + } else { + lpt1_remove(); + + if ((dev->dev_regs[1][0x00] & 0x01) && (dev->regs[0x22] & 0x08) && (io_base >= 0x100) && (io_base <= io_mask)) + lpt1_init(io_base); + + lpt1_irq(dev->dev_regs[1][0x40] & 0x0f); + } } @@ -249,11 +265,14 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) case 0xf0: switch (ld) { case 0x00: - if (valxor & 0x20) + if (dev->id == 1) + break; + + if (!dev->id && (valxor & 0x20)) fdc_update_drv2en(dev->fdc, (val & 0x20) ? 0 : 1); - if (valxor & 0x10) + if (!dev->id && (valxor & 0x10)) fdc_set_swap(dev->fdc, (val & 0x10) ? 1 : 0); - if (valxor & 0x01) + if (!dev->id && (valxor & 0x01)) fdc_update_enh_mode(dev->fdc, (val & 0x01) ? 1 : 0); break; case 0x01: @@ -269,13 +288,16 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) case 0xf1: switch (ld) { case 0x00: - if (valxor & 0xc0) + if (dev->id == 1) + break; + + if (!dev->id && (valxor & 0xc0)) fdc_update_boot_drive(dev->fdc, (val & 0xc0) >> 6); - if (valxor & 0x0c) + if (!dev->id && (valxor & 0x0c)) fdc_update_densel_force(dev->fdc, (val & 0x0c) >> 2); - if (valxor & 0x02) + if (!dev->id && (valxor & 0x02)) fdc_set_diswr(dev->fdc, (val & 0x02) ? 1 : 0); - if (valxor & 0x01) + if (!dev->id && (valxor & 0x01)) fdc_set_swwp(dev->fdc, (val & 0x01) ? 1 : 0); break; } @@ -283,13 +305,16 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) case 0xf2: switch (ld) { case 0x00: - if (valxor & 0xc0) + if (dev->id == 1) + break; + + if (!dev->id && (valxor & 0xc0)) fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); - if (valxor & 0x30) + if (!dev->id && (valxor & 0x30)) fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); - if (valxor & 0x0c) + if (!dev->id && (valxor & 0x0c)) fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); - if (valxor & 0x03) + if (!dev->id && (valxor & 0x03)) fdc_update_rwc(dev->fdc, 0, val & 0x03); break; } @@ -297,7 +322,10 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) case 0xf4: case 0xf5: case 0xf6: case 0xf7: switch (ld) { case 0x00: - if (valxor & 0x18) + if (dev->id == 1) + break; + + if (!dev->id && (valxor & 0x18)) fdc_update_drvrate(dev->fdc, dev->cur_reg & 0x03, (val & 0x18) >> 3); break; } @@ -319,7 +347,7 @@ w83977f_read(uint16_t port, void *priv) ret = dev->cur_reg; else { if (!dev->rw_locked) { - if ((dev->cur_reg == 0xf2) && (ld == 0x00)) + if (!dev->id && ((dev->cur_reg == 0xf2) && (ld == 0x00))) ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); else if (dev->cur_reg >= 0x30) ret = dev->dev_regs[ld][dev->cur_reg - 0x30]; @@ -351,13 +379,18 @@ w83977f_reset(w83977f_t *dev) } dev->regs[0x22] = 0xff; dev->regs[0x24] = dev->type ? 0x84 : 0xa4; + dev->regs[0x26] = dev->hefras; /* WARNING: Array elements are register - 0x30. */ /* Logical Device 0 (FDC) */ dev->dev_regs[0][0x00] = 0x01; if (!dev->type) dev->dev_regs[0][0x01] = 0x02; - dev->dev_regs[0][0x30] = 0x03; dev->dev_regs[0][0x31] = 0xf0; + if (next_id == 1) { + dev->dev_regs[0][0x30] = 0x03; dev->dev_regs[0][0x31] = 0x70; + } else { + dev->dev_regs[0][0x30] = 0x03; dev->dev_regs[0][0x31] = 0xf0; + } dev->dev_regs[0][0x40] = 0x06; if (!dev->type) dev->dev_regs[0][0x41] = 0x02; /* Read-only */ @@ -368,8 +401,13 @@ w83977f_reset(w83977f_t *dev) dev->dev_regs[1][0x00] = 0x01; if (!dev->type) dev->dev_regs[1][0x01] = 0x02; - dev->dev_regs[1][0x30] = 0x03; dev->dev_regs[1][0x31] = 0x78; - dev->dev_regs[1][0x40] = 0x07; + if (next_id == 1) { + dev->dev_regs[1][0x30] = 0x02; dev->dev_regs[1][0x31] = 0x78; + dev->dev_regs[1][0x40] = 0x05; + } else { + dev->dev_regs[1][0x30] = 0x03; dev->dev_regs[1][0x31] = 0x78; + dev->dev_regs[1][0x40] = 0x07; + } if (!dev->type) dev->dev_regs[1][0x41] = 0x01 /*0x02*/; /* Read-only */ dev->dev_regs[1][0x44] = 0x04; @@ -379,7 +417,11 @@ w83977f_reset(w83977f_t *dev) dev->dev_regs[2][0x00] = 0x01; if (!dev->type) dev->dev_regs[2][0x01] = 0x02; - dev->dev_regs[2][0x30] = 0x03; dev->dev_regs[2][0x31] = 0xf8; + if (next_id == 1) { + dev->dev_regs[2][0x30] = 0x03; dev->dev_regs[2][0x31] = 0xe8; + } else { + dev->dev_regs[2][0x30] = 0x03; dev->dev_regs[2][0x31] = 0xf8; + } dev->dev_regs[2][0x40] = 0x04; if (!dev->type) dev->dev_regs[2][0x41] = 0x02; /* Read-only */ @@ -388,7 +430,11 @@ w83977f_reset(w83977f_t *dev) dev->dev_regs[3][0x00] = 0x01; if (!dev->type) dev->dev_regs[3][0x01] = 0x02; - dev->dev_regs[3][0x30] = 0x02; dev->dev_regs[3][0x31] = 0xf8; + if (next_id == 1) { + dev->dev_regs[3][0x30] = 0x02; dev->dev_regs[3][0x31] = 0xe8; + } else { + dev->dev_regs[3][0x30] = 0x02; dev->dev_regs[3][0x31] = 0xf8; + } dev->dev_regs[3][0x40] = 0x03; if (!dev->type) dev->dev_regs[3][0x41] = 0x02; /* Read-only */ @@ -460,12 +506,18 @@ w83977f_reset(w83977f_t *dev) dev->dev_regs[10][0xc0] = 0x8f; } - fdc_reset(dev->fdc); + if (dev->id == 1) { + serial_setup(dev->uart[0], COM3_ADDR, COM3_IRQ); + serial_setup(dev->uart[1], COM4_ADDR, COM4_IRQ); + } else { + fdc_reset(dev->fdc); - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ); + serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); + + w83977f_fdc_handler(dev); + } - w83977f_fdc_handler(dev); w83977f_lpt_handler(dev); w83977f_serial_handler(dev, 0); w83977f_serial_handler(dev, 1); @@ -482,6 +534,8 @@ w83977f_close(void *priv) { w83977f_t *dev = (w83977f_t *) priv; + next_id = 0; + free(dev); } @@ -492,44 +546,92 @@ w83977f_init(const device_t *info) w83977f_t *dev = (w83977f_t *) malloc(sizeof(w83977f_t)); memset(dev, 0, sizeof(w83977f_t)); - dev->type = info->local; + dev->type = info->local & 0x0f; + dev->hefras = info->local & 0x40; - dev->fdc = device_add(&fdc_at_smc_device); + dev->id = next_id; - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + if (next_id == 1) + dev->hefras ^= 0x40; + else + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, (next_id << 1) + 1); + dev->uart[1] = device_add_inst(&ns16550_device, (next_id << 1) + 2); w83977f_reset(dev); + next_id++; + return dev; } - const device_t w83977f_device = { - "Winbond W83977F Super I/O", - 0, - 0, - w83977f_init, w83977f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83977F Super I/O", + .internal_name = "w83977f", + .flags = 0, + .local = 0, + .init = w83977f_init, + .close = w83977f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; +const device_t w83977f_370_device = { + .name = "Winbond W83977F Super I/O (Port 370h)", + .internal_name = "w83977f_370", + .flags = 0, + .local = 0x40, + .init = w83977f_init, + .close = w83977f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; const device_t w83977tf_device = { - "Winbond W83977TF Super I/O", - 0, - 1, - w83977f_init, w83977f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83977TF Super I/O", + .internal_name = "w83977tf", + .flags = 0, + .local = 1, + .init = w83977f_init, + .close = w83977f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - const device_t w83977ef_device = { - "Winbond W83977TF Super I/O", - 0, - 2, - w83977f_init, w83977f_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Winbond W83977TF Super I/O", + .internal_name = "w83977ef", + .flags = 0, + .local = 2, + .init = w83977f_init, + .close = w83977f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t w83977ef_370_device = { + .name = "Winbond W83977TF Super I/O (Port 370h)", + .internal_name = "w83977ef_370", + .flags = 0, + .local = 0x42, + .init = w83977f_init, + .close = w83977f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt new file mode 100644 index 000000000..581f8d517 --- /dev/null +++ b/src/sound/CMakeLists.txt @@ -0,0 +1,125 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_resid.cc + midi.c snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_ac97_codec.c snd_ac97_via.c + snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c + snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c + snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c) + +if(OPENAL) + if(VCPKG_TOOLCHAIN) + find_package(OpenAL CONFIG REQUIRED) + elseif(MINGW) + find_package(OpenAL MODULE REQUIRED) + else() + find_package(OpenAL REQUIRED) + endif() + + if(TARGET OpenAL::OpenAL) + target_link_libraries(86Box OpenAL::OpenAL) + else() + target_link_libraries(86Box ${OPENAL_LIBRARY}) + endif() + + include_directories(${OPENAL_INCLUDE_DIR}) + + target_sources(snd PRIVATE openal.c) +else() + if(WIN32) + option(FAUDIO "Use FAudio instead of XAudio2" OFF) + endif() + + target_sources(snd PRIVATE xaudio2.c) + + if(NOT WIN32 OR FAUDIO) + find_package(PkgConfig REQUIRED) + + # Use FAudio, a reimplementation of XAudio2 + pkg_check_modules(FAUDIO IMPORTED_TARGET FAudio) + if(FAUDIO_FOUND) + target_link_libraries(86Box PkgConfig::FAUDIO) + else() + find_path(FAUDIO_INCLUDE_DIR NAMES "FAudio.h") + find_library(FAUDIO_LIBRARY FAudio) + + target_link_libraries(86Box ${FAUDIO_LIBRARY}) + endif() + + include_directories(${FAUDIO_INCLUDE_DIRS}) + + set_property(SOURCE xaudio2.c PROPERTY COMPILE_DEFINITIONS USE_FAUDIO) + endif() +endif() + +if(RTMIDI) + if(VCPKG_TOOLCHAIN) + # vcpkg includes a config file for rtmidi + find_package(RtMidi REQUIRED) + target_link_libraries(86Box RtMidi::rtmidi) + else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(RTMIDI REQUIRED IMPORTED_TARGET rtmidi) + target_link_libraries(86Box PkgConfig::RTMIDI) + + if(WIN32) + target_link_libraries(PkgConfig::RTMIDI INTERFACE winmm) + endif() + endif() + + target_compile_definitions(snd PRIVATE USE_RTMIDI) + target_sources(snd PRIVATE midi_rtmidi.cpp) +endif() + +if(FLUIDSYNTH) + target_compile_definitions(snd PRIVATE USE_FLUIDSYNTH) + target_sources(snd PRIVATE midi_fluidsynth.c) +endif() + +if(MUNT) + target_compile_definitions(snd PRIVATE USE_MUNT) + target_sources(snd PRIVATE midi_mt32.c) + + option(MUNT_EXTERNAL "Link against the system-provided MUNT library" OFF) + mark_as_advanced(MUNT_EXTERNAL) + + if(MUNT_EXTERNAL) + find_package(PkgConfig REQUIRED) + pkg_check_modules(MT32EMU REQUIRED IMPORTED_TARGET mt32emu) + target_link_libraries(86Box PkgConfig::MT32EMU) + else() + add_subdirectory(munt) + target_link_libraries(86Box mt32emu) + endif() +endif() + +add_subdirectory(ymfm) +target_link_libraries(86Box ymfm) + +if(PAS16) + target_compile_definitions(snd PRIVATE USE_PAS16) + target_sources(snd PRIVATE snd_pas16.c) +endif() + +if(GUSMAX) + target_compile_definitions(snd PRIVATE USE_GUSMAX) +endif() + +if(TANDY_ISA) + target_compile_definitions(snd PRIVATE USE_TANDY_ISA) +endif() + +add_subdirectory(resid-fp) +target_link_libraries(86Box resid-fp) diff --git a/src/sound/midi.c b/src/sound/midi.c index 22efb56f2..ae5cdc456 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -1,194 +1,211 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * MIDI device core module. + * MIDI device core module. * * * - * Authors: Sarah Walker, - * Miran Grca, - * Bit, - * DOSBox Team, + * Authors: Sarah Walker, + * Miran Grca, + * Bit, + * DOSBox Team, * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. - * Copyright 2016-2020 Bit. - * Copyright 2008-2020 DOSBox Team. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2020 Bit. + * Copyright 2008-2020 DOSBox Team. */ -#include #include -#include +#include #include +#include #include + #include <86box/86box.h> #include <86box/device.h> -#include <86box/plat.h> -#include <86box/plat_midi.h> #include <86box/midi.h> -#include <86box/midi_input.h> +#include <86box/plat.h> +int midi_output_device_current = 0; +static int midi_output_device_last = 0; +int midi_input_device_current = 0; +static int midi_input_device_last = 0; -int midi_device_current = 0; -static int midi_device_last = 0; -int midi_input_device_current = 0; -static int midi_input_device_last = 0; - -midi_t *midi = NULL, *midi_in = NULL; +midi_t *midi_out = NULL, *midi_in = NULL; midi_in_handler_t *mih_first = NULL, *mih_last = NULL, - *mih_cur = NULL; + *mih_cur = NULL; uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; uint8_t MIDI_evt_len[256] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x00 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x10 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x20 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x30 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x40 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x50 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x60 */ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x70 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0x80 */ - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0x90 */ - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xa0 */ - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xb0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x80 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x90 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xa0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xb0 */ - 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* 0xc0 */ - 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* 0xd0 */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 */ - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xe0 */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 */ - 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 /* 0xf0 */ + 0, 2, 3, 2, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0 /* 0xf0 */ }; typedef struct { - const char *name, *internal_name; const device_t *device; -} MIDI_DEVICE, MIDI_IN_DEVICE; +} MIDI_OUT_DEVICE, MIDI_IN_DEVICE; -static const MIDI_DEVICE devices[] = -{ - {"None", "none", NULL}, -#ifdef USE_FLUIDSYNTH - {"FluidSynth", "fluidsynth", &fluidsynth_device}, -#endif -#ifdef USE_MUNT - {"Roland MT-32 Emulation", "mt32", &mt32_device}, - {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, -#endif - {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, - {"", "", NULL} +static const device_t midi_out_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -static const MIDI_IN_DEVICE midi_in_devices[] = -{ - {"None", "none", NULL}, - {MIDI_INPUT_NAME, MIDI_INPUT_INTERNAL_NAME, &midi_input_device}, - {"", "", NULL} +static const MIDI_OUT_DEVICE devices[] = { + // clang-format off + { &midi_out_none_device }, +#ifdef USE_FLUIDSYNTH + { &fluidsynth_device }, +#endif +#ifdef USE_MUNT + { &mt32_device }, + { &cm32l_device }, +#endif +#ifdef USE_RTMIDI + { &rtmidi_output_device }, +#endif + { NULL } + // clang-format on +}; + +static const device_t midi_in_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +static const MIDI_IN_DEVICE midi_in_devices[] = { + // clang-format off + { &midi_in_none_device }, +#ifdef USE_RTMIDI + { &rtmidi_input_device }, +#endif + { NULL } + // clang-format on }; int -midi_device_available(int card) +midi_out_device_available(int card) { if (devices[card].device) - return device_available(devices[card].device); + return device_available(devices[card].device); return 1; } - -char * -midi_device_getname(int card) -{ - return (char *) devices[card].name; -} - - const device_t * -midi_device_getdevice(int card) +midi_out_device_getdevice(int card) { return devices[card].device; } - int -midi_device_has_config(int card) +midi_out_device_has_config(int card) { if (!devices[card].device) - return 0; + return 0; return devices[card].device->config ? 1 : 0; } - char * -midi_device_get_internal_name(int card) +midi_out_device_get_internal_name(int card) { - return (char *) devices[card].internal_name; + return device_get_internal_name(devices[card].device); } - int -midi_device_get_from_internal_name(char *s) +midi_out_device_get_from_internal_name(char *s) { int c = 0; - while (strlen(devices[c].internal_name)) { - if (!strcmp(devices[c].internal_name, s)) - return c; - c++; + while (devices[c].device != NULL) { + if (!strcmp(devices[c].device->internal_name, s)) + return c; + c++; } return 0; } - void -midi_device_init() +midi_out_device_init() { - if (devices[midi_device_current].device) - device_add(devices[midi_device_current].device); - midi_device_last = midi_device_current; -} - - -void -midi_init(midi_device_t* device) -{ - midi = (midi_t *) malloc(sizeof(midi_t)); - memset(midi, 0, sizeof(midi_t)); - - midi->m_out_device = device; + if (devices[midi_output_device_current].device) + device_add(devices[midi_output_device_current].device); + midi_output_device_last = midi_output_device_current; } void -midi_in_init(midi_device_t* device, midi_t **mididev) +midi_out_init(midi_device_t *device) { - *mididev = (midi_t *)malloc(sizeof(midi_t)); + midi_out = (midi_t *) malloc(sizeof(midi_t)); + memset(midi_out, 0, sizeof(midi_t)); + + midi_out->m_out_device = device; +} + +void +midi_in_init(midi_device_t *device, midi_t **mididev) +{ + *mididev = (midi_t *) malloc(sizeof(midi_t)); memset(*mididev, 0, sizeof(midi_t)); (*mididev)->m_in_device = device; } - void -midi_close(void) +midi_out_close(void) { - if (midi && midi->m_out_device) { - free(midi->m_out_device); - midi->m_out_device = NULL; + if (midi_out && midi_out->m_out_device) { + free(midi_out->m_out_device); + midi_out->m_out_device = NULL; } - if (midi) { - free(midi); - midi = NULL; + if (midi_out) { + free(midi_out); + midi_out = NULL; } } @@ -196,56 +213,46 @@ void midi_in_close(void) { if (midi_in && midi_in->m_in_device) { - free(midi_in->m_in_device); - midi_in->m_in_device = NULL; + free(midi_in->m_in_device); + midi_in->m_in_device = NULL; } if (midi_in) { - free(midi_in); - midi_in = NULL; + free(midi_in); + midi_in = NULL; } } - void midi_poll(void) { - if (midi && midi->m_out_device && midi->m_out_device->poll) - midi->m_out_device->poll(); + if (midi_out && midi_out->m_out_device && midi_out->m_out_device->poll) + midi_out->m_out_device->poll(); } - void play_msg(uint8_t *msg) { - if (midi->m_out_device->play_msg) - midi->m_out_device->play_msg(msg); + if (midi_out->m_out_device->play_msg) + midi_out->m_out_device->play_msg(msg); } - void play_sysex(uint8_t *sysex, unsigned int len) { - if (midi->m_out_device->play_sysex) - midi->m_out_device->play_sysex(sysex, len); + if (midi_out->m_out_device->play_sysex) + midi_out->m_out_device->play_sysex(sysex, len); } - int midi_in_device_available(int card) { if (midi_in_devices[card].device) - return device_available(midi_in_devices[card].device); + return device_available(midi_in_devices[card].device); return 1; } -char * -midi_in_device_getname(int card) -{ - return (char *) midi_in_devices[card].name; -} - const device_t * midi_in_device_getdevice(int card) { @@ -256,357 +263,344 @@ int midi_in_device_has_config(int card) { if (!midi_in_devices[card].device) - return 0; + return 0; return midi_in_devices[card].device->config ? 1 : 0; } - char * midi_in_device_get_internal_name(int card) { - return (char *) midi_in_devices[card].internal_name; + return device_get_internal_name(midi_in_devices[card].device); } - int midi_in_device_get_from_internal_name(char *s) { int c = 0; - while (strlen(midi_in_devices[c].internal_name)) { - if (!strcmp(midi_in_devices[c].internal_name, s)) - return c; - c++; + while (midi_in_devices[c].device != NULL) { + if (!strcmp(midi_in_devices[c].device->internal_name, s)) + return c; + c++; } return 0; } - void midi_in_device_init() { if (midi_in_devices[midi_input_device_current].device) - device_add(midi_in_devices[midi_input_device_current].device); + device_add(midi_in_devices[midi_input_device_current].device); midi_input_device_last = midi_input_device_current; } - void midi_raw_out_rt_byte(uint8_t val) { + if (!midi_in) + return; + if (!midi_in->midi_realtime) - return; + return; if ((!midi_in->midi_clockout && (val == 0xf8))) - return; + return; midi_in->midi_cmd_r = val << 24; /* pclog("Play RT Byte msg\n"); */ - play_msg((uint8_t *)&midi_in->midi_cmd_r); + play_msg((uint8_t *) &midi_in->midi_cmd_r); } - void midi_raw_out_thru_rt_byte(uint8_t val) { - if (midi_in->thruchan) - midi_raw_out_rt_byte(val); + if (midi_in && midi_in->thruchan) + midi_raw_out_rt_byte(val); } - void midi_raw_out_byte(uint8_t val) { uint32_t passed_ticks; - if (!midi || !midi->m_out_device) - return; + if (!midi_out || !midi_out->m_out_device) + return; - if ((midi->m_out_device->write && midi->m_out_device->write(val))) - return; + if ((midi_out->m_out_device->write && midi_out->m_out_device->write(val))) + return; - if (midi->midi_sysex_start) { - passed_ticks = plat_get_ticks() - midi->midi_sysex_start; - if (passed_ticks < midi->midi_sysex_delay) - plat_delay_ms(midi->midi_sysex_delay - passed_ticks); + if (midi_out->midi_sysex_start) { + passed_ticks = plat_get_ticks() - midi_out->midi_sysex_start; + if (passed_ticks < midi_out->midi_sysex_delay) + plat_delay_ms(midi_out->midi_sysex_delay - passed_ticks); } /* Test for a realtime MIDI message */ if (val >= 0xf8) { - midi->midi_rt_buf[0] = val; - play_msg(midi->midi_rt_buf); - return; + midi_out->midi_rt_buf[0] = val; + play_msg(midi_out->midi_rt_buf); + return; } /* Test for a active sysex transfer */ - if (midi->midi_status == 0xf0) { - if (!(val & 0x80)) { - if (midi->midi_pos < (SYSEX_SIZE-1)) - midi->midi_sysex_data[midi->midi_pos++] = val; - return; - } else { - midi->midi_sysex_data[midi->midi_pos++] = 0xf7; + if (midi_out->midi_status == 0xf0) { + if (!(val & 0x80)) { + if (midi_out->midi_pos < (SYSEX_SIZE - 1)) + midi_out->midi_sysex_data[midi_out->midi_pos++] = val; + return; + } else { + midi_out->midi_sysex_data[midi_out->midi_pos++] = 0xf7; - if ((midi->midi_sysex_start) && (midi->midi_pos >= 4) && (midi->midi_pos <= 9) && - (midi->midi_sysex_data[1] == 0x41) && (midi->midi_sysex_data[3] == 0x16)) { - /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ - } else { - play_sysex(midi->midi_sysex_data, midi->midi_pos); - if (midi->midi_sysex_start) { - if (midi-> midi_sysex_data[5] == 0x7f) - midi->midi_sysex_delay = 290; /* All parameters reset */ - else if ((midi->midi_sysex_data[5] == 0x10) && (midi->midi_sysex_data[6] == 0x00) && - (midi->midi_sysex_data[7] == 0x04)) - midi->midi_sysex_delay = 145; /* Viking Child */ - else if ((midi->midi_sysex_data[5] == 0x10) && (midi->midi_sysex_data[6] == 0x00) && - (midi->midi_sysex_data[7] == 0x01)) - midi->midi_sysex_delay = 30; /* Dark Sun 1 */ - else - midi->midi_sysex_delay = (unsigned int) (((float) (midi->midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + if ((midi_out->midi_sysex_start) && (midi_out->midi_pos >= 4) && (midi_out->midi_pos <= 9) && (midi_out->midi_sysex_data[1] == 0x41) && (midi_out->midi_sysex_data[3] == 0x16)) { + /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ + } else { + play_sysex(midi_out->midi_sysex_data, midi_out->midi_pos); + if (midi_out->midi_sysex_start) { + if (midi_out->midi_sysex_data[5] == 0x7f) + midi_out->midi_sysex_delay = 290; /* All parameters reset */ + else if ((midi_out->midi_sysex_data[5] == 0x10) && (midi_out->midi_sysex_data[6] == 0x00) && (midi_out->midi_sysex_data[7] == 0x04)) + midi_out->midi_sysex_delay = 145; /* Viking Child */ + else if ((midi_out->midi_sysex_data[5] == 0x10) && (midi_out->midi_sysex_data[6] == 0x00) && (midi_out->midi_sysex_data[7] == 0x01)) + midi_out->midi_sysex_delay = 30; /* Dark Sun 1 */ + else + midi_out->midi_sysex_delay = (unsigned int) (((float) (midi_out->midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; - midi->midi_sysex_start = plat_get_ticks(); - } - } - } + midi_out->midi_sysex_start = plat_get_ticks(); + } + } + } } if (val & 0x80) { - midi->midi_status = val; - midi->midi_cmd_pos = 0; - midi->midi_cmd_len = MIDI_evt_len[val]; - if (midi->midi_status == 0xf0) { - midi->midi_sysex_data[0] = 0xf0; - midi->midi_pos = 1; - } + midi_out->midi_status = val; + midi_out->midi_cmd_pos = 0; + midi_out->midi_cmd_len = MIDI_evt_len[val]; + if (midi_out->midi_status == 0xf0) { + midi_out->midi_sysex_data[0] = 0xf0; + midi_out->midi_pos = 1; + } } - if (midi->midi_cmd_len) { - midi->midi_cmd_buf[midi->midi_cmd_pos++] = val; - if (midi->midi_cmd_pos >= midi->midi_cmd_len) { - play_msg(midi->midi_cmd_buf); - midi->midi_cmd_pos = 1; - } + if (midi_out->midi_cmd_len) { + midi_out->midi_cmd_buf[midi_out->midi_cmd_pos++] = val; + if (midi_out->midi_cmd_pos >= midi_out->midi_cmd_len) { + play_msg(midi_out->midi_cmd_buf); + midi_out->midi_cmd_pos = 1; + } } } - -void -midi_clear_buffer(void) -{ - if (!midi) - return; - - midi->midi_pos = 0; - midi->midi_status = 0x00; - midi->midi_cmd_pos = 0; - midi->midi_cmd_len = 0; -} - - void -midi_in_handler(int set, void (*msg)(void *p, uint8_t *msg), int (*sysex)(void *p, uint8_t *buffer, uint32_t len, int abort), void *p) +midi_clear_buffer(void) +{ + if (!midi_out) + return; + + midi_out->midi_pos = 0; + midi_out->midi_status = 0x00; + midi_out->midi_cmd_pos = 0; + midi_out->midi_cmd_len = 0; +} + +void +midi_in_handler(int set, void (*msg)(void *p, uint8_t *msg, uint32_t len), int (*sysex)(void *p, uint8_t *buffer, uint32_t len, int abort), void *p) { midi_in_handler_t *temp = NULL, *next; if (set) { - /* Add MIDI IN handler. */ - if ((mih_first == NULL) && (mih_last != NULL)) - fatal("Last MIDI IN handler present with no first MIDI IN handler\n"); + /* Add MIDI IN handler. */ + if ((mih_first == NULL) && (mih_last != NULL)) + fatal("Last MIDI IN handler present with no first MIDI IN handler\n"); - if ((mih_first != NULL) && (mih_last == NULL)) - fatal("First MIDI IN handler present with no last MIDI IN handler\n"); + if ((mih_first != NULL) && (mih_last == NULL)) + fatal("First MIDI IN handler present with no last MIDI IN handler\n"); - temp = (midi_in_handler_t *) malloc(sizeof(midi_in_handler_t)); - memset(temp, 0, sizeof(midi_in_handler_t)); - temp->msg = msg; - temp->sysex = sysex; - temp->p = p; + temp = (midi_in_handler_t *) malloc(sizeof(midi_in_handler_t)); + memset(temp, 0, sizeof(midi_in_handler_t)); + temp->msg = msg; + temp->sysex = sysex; + temp->p = p; - if (mih_last == NULL) - mih_first = mih_last = temp; - else { - temp->prev = mih_last; - mih_last = temp; - } + if (mih_last == NULL) + mih_first = mih_last = temp; + else { + temp->prev = mih_last; + mih_last = temp; + } } else if ((mih_first != NULL) && (mih_last != NULL)) { - temp = mih_first; + temp = mih_first; - while(1) { - if (temp == NULL) - break; + while (1) { + if (temp == NULL) + break; - if ((temp->msg == msg) && (temp->sysex == sysex) && (temp->p == p)) { - if (temp->prev != NULL) - temp->prev->next = temp->next; + if ((temp->msg == msg) && (temp->sysex == sysex) && (temp->p == p)) { + if (temp->prev != NULL) + temp->prev->next = temp->next; - if (temp->next != NULL) - temp->next->prev = temp->prev; + if (temp->next != NULL) + temp->next->prev = temp->prev; - next = temp->next; + next = temp->next; - if (temp == mih_first) { - mih_first = NULL; - if (next == NULL) - mih_last = NULL; - } + if (temp == mih_first) { + mih_first = NULL; + if (next == NULL) + mih_last = NULL; + } - if (temp == mih_last) - mih_last = NULL; + if (temp == mih_last) + mih_last = NULL; - free(temp); - temp = next; + free(temp); + temp = next; - if (next == NULL) - break; - } - } + if (next == NULL) + break; + } + } } } - void midi_in_handlers_clear(void) { midi_in_handler_t *temp = mih_first, *next; - while(1) { - if (temp == NULL) - break; + while (1) { + if (temp == NULL) + break; - next = temp->next; - free(temp); + next = temp->next; + free(temp); - temp = next; + temp = next; - if (next == NULL) - break; + if (next == NULL) + break; } mih_first = mih_last = NULL; } - void -midi_in_msg(uint8_t *msg) +midi_in_msg(uint8_t *msg, uint32_t len) { midi_in_handler_t *temp = mih_first; - while(1) { - if (temp == NULL) - break; + while (1) { + if (temp == NULL) + break; - if (temp->msg) - temp->msg(temp->p, msg); + if (temp->msg) + temp->msg(temp->p, msg, len); - temp = temp->next; + temp = temp->next; - if (temp == NULL) - break; + if (temp == NULL) + break; } } - static void midi_start_sysex(uint8_t *buffer, uint32_t len) { midi_in_handler_t *temp = mih_first; - while(1) { - if (temp == NULL) - break; + while (1) { + if (temp == NULL) + break; - temp->cnt = 5; - temp->buf = buffer; - temp->len = len; + temp->cnt = 5; + temp->buf = buffer; + temp->len = len; - temp = temp->next; + temp = temp->next; - if (temp == NULL) - break; + if (temp == NULL) + break; } } - /* Returns: - 0 = All handlers have returnd 0; - 1 = There are still handlers to go. */ + 0 = All handlers have returnd 0; + 1 = There are still handlers to go. */ static int midi_do_sysex(void) { midi_in_handler_t *temp = mih_first; - int ret, cnt_acc = 0; + int ret, cnt_acc = 0; - while(1) { - if (temp == NULL) - break; + while (1) { + if (temp == NULL) + break; - /* Do nothing if the handler has a zero count. */ - if ((temp->cnt > 0) || (temp->len > 0)) { - ret = 0; - if (temp->sysex) { - if (temp->cnt == 0) - ret = temp->sysex(temp->p, temp->buf, 0, 0); - else - ret = temp->sysex(temp->p, temp->buf, temp->len, 0); - } + /* Do nothing if the handler has a zero count. */ + if ((temp->cnt > 0) || (temp->len > 0)) { + ret = 0; + if (temp->sysex) { + if (temp->cnt == 0) + ret = temp->sysex(temp->p, temp->buf, 0, 0); + else + ret = temp->sysex(temp->p, temp->buf, temp->len, 0); + } - /* If count is 0 and length is 0, then this is just a finishing - call to temp->sysex(), so skip this entire block. */ - if (temp->cnt > 0) { - if (ret) { - /* Decrease or reset the counter. */ - if (temp->len == ret) - temp->cnt--; - else - temp->cnt = 5; + /* If count is 0 and length is 0, then this is just a finishing + call to temp->sysex(), so skip this entire block. */ + if (temp->cnt > 0) { + if (ret) { + /* Decrease or reset the counter. */ + if (temp->len == ret) + temp->cnt--; + else + temp->cnt = 5; - /* Advance the buffer pointer and remember the - remaining length. */ - temp->buf += (temp->len - ret); - temp->len = ret; - } else { - /* Set count to 0 so that this handler will be - ignored on the next interation. */ - temp->cnt = 0; + /* Advance the buffer pointer and remember the + remaining length. */ + temp->buf += (temp->len - ret); + temp->len = ret; + } else { + /* Set count to 0 so that this handler will be + ignored on the next interation. */ + temp->cnt = 0; - /* Reset the buffer pointer and length. */ - temp->buf = NULL; - temp->len = 0; - } + /* Reset the buffer pointer and length. */ + temp->buf = NULL; + temp->len = 0; + } - /* If the remaining count is above zero, add it to the - accumulator. */ - if (temp->cnt > 0) - cnt_acc |= temp->cnt; - } - } + /* If the remaining count is above zero, add it to the + accumulator. */ + if (temp->cnt > 0) + cnt_acc |= temp->cnt; + } + } - temp = temp->next; + temp = temp->next; - if (temp == NULL) - break; + if (temp == NULL) + break; } /* Return 0 if all handlers have returned 0 or all the counts are otherwise 0. */ if (cnt_acc == 0) - return 0; + return 0; else - return 1; + return 1; } - void midi_in_sysex(uint8_t *buffer, uint32_t len) { midi_start_sysex(buffer, len); while (1) { - /* This will return 0 if all theh handlers have either - timed out or otherwise indicated it is time to stop. */ - if (midi_do_sysex()) - plat_delay_ms(5); /* msec */ - else - break; + /* This will return 0 if all theh handlers have either + timed out or otherwise indicated it is time to stop. */ + if (midi_do_sysex()) + plat_delay_ms(5); /* msec */ + else + break; } } diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 20f64b55a..749c74b9f 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -1,566 +1,563 @@ /* some code borrowed from scummvm */ #ifdef USE_FLUIDSYNTH -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/config.h> -#include <86box/device.h> -#include <86box/plat.h> -#include <86box/plat_dynld.h> -#include <86box/ui.h> -#include <86box/midi.h> -#include <86box/sound.h> +# include +# include +# include +# include +# include +# ifdef __unix__ +# include +# endif +# include <86box/86box.h> +# include <86box/config.h> +# include <86box/device.h> +# include <86box/midi.h> +# include <86box/plat.h> +# include <86box/plat_dynld.h> +# include <86box/thread.h> +# include <86box/sound.h> +# include <86box/ui.h> -#define FLUID_CHORUS_DEFAULT_N 3 -#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f -#define FLUID_CHORUS_DEFAULT_SPEED 0.3f -#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f -#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE - -#define RENDER_RATE 100 -#define BUFFER_SEGMENTS 10 +# define FLUID_CHORUS_DEFAULT_N 3 +# define FLUID_CHORUS_DEFAULT_LEVEL 2.0f +# define FLUID_CHORUS_DEFAULT_SPEED 0.3f +# define FLUID_CHORUS_DEFAULT_DEPTH 8.0f +# define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE +# define RENDER_RATE 100 +# define BUFFER_SEGMENTS 10 enum fluid_chorus_mod { - FLUID_CHORUS_MOD_SINE = 0, - FLUID_CHORUS_MOD_TRIANGLE = 1 + FLUID_CHORUS_MOD_SINE = 0, + FLUID_CHORUS_MOD_TRIANGLE = 1 }; enum fluid_interp { - FLUID_INTERP_NONE = 0, - FLUID_INTERP_LINEAR = 1, - FLUID_INTERP_DEFAULT = 4, - FLUID_INTERP_4THORDER = 4, - FLUID_INTERP_7THORDER = 7, - FLUID_INTERP_HIGHEST = 7 + FLUID_INTERP_NONE = 0, + FLUID_INTERP_LINEAR = 1, + FLUID_INTERP_DEFAULT = 4, + FLUID_INTERP_4THORDER = 4, + FLUID_INTERP_7THORDER = 7, + FLUID_INTERP_HIGHEST = 7 }; - extern void givealbuffer_midi(void *buf, uint32_t size); extern void al_set_midi(int freq, int buf_size); -static void *fluidsynth_handle; /* handle to FluidSynth DLL */ +static void *fluidsynth_handle; /* handle to FluidSynth DLL */ /* Pointers to the real functions. */ -static void * (*f_new_fluid_settings)(void); -static void (*f_delete_fluid_settings)(void *settings); -static int (*f_fluid_settings_setnum)(void *settings, const char *name, double val); -static int (*f_fluid_settings_getnum)(void *settings, const char *name, double *val); -static void * (*f_new_fluid_synth)(void *settings); -static int (*f_delete_fluid_synth)(void *synth); -static int (*f_fluid_synth_noteon)(void *synth, int chan, int key, int vel); -static int (*f_fluid_synth_noteoff)(void *synth, int chan, int key); -static int (*f_fluid_synth_cc)(void *synth, int chan, int ctrl, int val); -static int (*f_fluid_synth_sysex)(void *synth, const char *data, int len, char *response, int *response_len, int *handled, int dryrun); -static int (*f_fluid_synth_pitch_bend)(void *synth, int chan, int val); -static int (*f_fluid_synth_program_change)(void *synth, int chan, int program); -static int (*f_fluid_synth_sfload)(void *synth, const char *filename, int reset_presets); -static int (*f_fluid_synth_set_interp_method)(void *synth, int chan, int interp_method); -static void (*f_fluid_synth_set_reverb)(void *synth, double roomsize, double damping, double width, double level); -static void (*f_fluid_synth_set_reverb_on)(void *synth, int on); -static void (*f_fluid_synth_set_chorus)(void *synth, int nr, double level, double speed, double depth_ms, int type); -static void (*f_fluid_synth_set_chorus_on)(void *synth, int on); -static int (*f_fluid_synth_write_s16)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr); -static int (*f_fluid_synth_write_float)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr); -static char* (*f_fluid_version_str)(void); +// clang-format off +static void *(*f_new_fluid_settings)(void); +static void (*f_delete_fluid_settings)(void *settings); +static int (*f_fluid_settings_setnum)(void *settings, const char *name, double val); +static int (*f_fluid_settings_getnum)(void *settings, const char *name, double *val); +static void *(*f_new_fluid_synth)(void *settings); +static int (*f_delete_fluid_synth)(void *synth); +static int (*f_fluid_synth_noteon)(void *synth, int chan, int key, int vel); +static int (*f_fluid_synth_noteoff)(void *synth, int chan, int key); +static int (*f_fluid_synth_cc)(void *synth, int chan, int ctrl, int val); +static int (*f_fluid_synth_sysex)(void *synth, const char *data, int len, char *response, int *response_len, int *handled, int dryrun); +static int (*f_fluid_synth_pitch_bend)(void *synth, int chan, int val); +static int (*f_fluid_synth_program_change)(void *synth, int chan, int program); +static int (*f_fluid_synth_sfload)(void *synth, const char *filename, int reset_presets); +static int (*f_fluid_synth_set_interp_method)(void *synth, int chan, int interp_method); +static void (*f_fluid_synth_set_reverb)(void *synth, double roomsize, double damping, double width, double level); +static void (*f_fluid_synth_set_reverb_on)(void *synth, int on); +static void (*f_fluid_synth_set_chorus)(void *synth, int nr, double level, double speed, double depth_ms, int type); +static void (*f_fluid_synth_set_chorus_on)(void *synth, int on); +static int (*f_fluid_synth_write_s16)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr); +static int (*f_fluid_synth_write_float)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr); +static char *(*f_fluid_version_str)(void); +// clang-format on + static dllimp_t fluidsynth_imports[] = { - { "new_fluid_settings", &f_new_fluid_settings }, - { "delete_fluid_settings", &f_delete_fluid_settings }, - { "fluid_settings_setnum", &f_fluid_settings_setnum }, - { "fluid_settings_getnum", &f_fluid_settings_getnum }, - { "new_fluid_synth", &f_new_fluid_synth }, - { "delete_fluid_synth", &f_delete_fluid_synth }, - { "fluid_synth_noteon", &f_fluid_synth_noteon }, - { "fluid_synth_noteoff", &f_fluid_synth_noteoff }, - { "fluid_synth_cc", &f_fluid_synth_cc }, - { "fluid_synth_sysex", &f_fluid_synth_sysex }, - { "fluid_synth_pitch_bend", &f_fluid_synth_pitch_bend }, - { "fluid_synth_program_change", &f_fluid_synth_program_change }, - { "fluid_synth_sfload", &f_fluid_synth_sfload }, - { "fluid_synth_set_interp_method", &f_fluid_synth_set_interp_method }, - { "fluid_synth_set_reverb", &f_fluid_synth_set_reverb }, - { "fluid_synth_set_reverb_on", &f_fluid_synth_set_reverb_on }, - { "fluid_synth_set_chorus", &f_fluid_synth_set_chorus }, - { "fluid_synth_set_chorus_on", &f_fluid_synth_set_chorus_on }, - { "fluid_synth_write_s16", &f_fluid_synth_write_s16 }, - { "fluid_synth_write_float", &f_fluid_synth_write_float }, - { "fluid_version_str", &f_fluid_version_str }, - { NULL, NULL }, + // clang-format off + { "new_fluid_settings", &f_new_fluid_settings }, + { "delete_fluid_settings", &f_delete_fluid_settings }, + { "fluid_settings_setnum", &f_fluid_settings_setnum }, + { "fluid_settings_getnum", &f_fluid_settings_getnum }, + { "new_fluid_synth", &f_new_fluid_synth }, + { "delete_fluid_synth", &f_delete_fluid_synth }, + { "fluid_synth_noteon", &f_fluid_synth_noteon }, + { "fluid_synth_noteoff", &f_fluid_synth_noteoff }, + { "fluid_synth_cc", &f_fluid_synth_cc }, + { "fluid_synth_sysex", &f_fluid_synth_sysex }, + { "fluid_synth_pitch_bend", &f_fluid_synth_pitch_bend }, + { "fluid_synth_program_change", &f_fluid_synth_program_change }, + { "fluid_synth_sfload", &f_fluid_synth_sfload }, + { "fluid_synth_set_interp_method", &f_fluid_synth_set_interp_method }, + { "fluid_synth_set_reverb", &f_fluid_synth_set_reverb }, + { "fluid_synth_set_reverb_on", &f_fluid_synth_set_reverb_on }, + { "fluid_synth_set_chorus", &f_fluid_synth_set_chorus }, + { "fluid_synth_set_chorus_on", &f_fluid_synth_set_chorus_on }, + { "fluid_synth_write_s16", &f_fluid_synth_write_s16 }, + { "fluid_synth_write_float", &f_fluid_synth_write_float }, + { "fluid_version_str", &f_fluid_version_str }, + { NULL, NULL }, + // clang-format on }; +typedef struct fluidsynth { + void *settings; + void *synth; + int samplerate; + int sound_font; -typedef struct fluidsynth -{ - void* settings; - void* synth; - int samplerate; - int sound_font; + thread_t *thread_h; + event_t *event, *start_event; + int buf_size; + float *buffer; + int16_t *buffer_int16; + int midi_pos; - thread_t *thread_h; - event_t *event, *start_event; - int buf_size; - float* buffer; - int16_t* buffer_int16; - int midi_pos; - - int on; + int on; } fluidsynth_t; fluidsynth_t fsdev; -int fluidsynth_available(void) +int +fluidsynth_available(void) { - return 1; + return 1; } -void fluidsynth_poll(void) +void +fluidsynth_poll(void) { - fluidsynth_t* data = &fsdev; - data->midi_pos++; - if (data->midi_pos == 48000/RENDER_RATE) - { - data->midi_pos = 0; - thread_set_event(data->event); + fluidsynth_t *data = &fsdev; + data->midi_pos++; + if (data->midi_pos == 48000 / RENDER_RATE) { + data->midi_pos = 0; + thread_set_event(data->event); + } +} + +static void +fluidsynth_thread(void *param) +{ + fluidsynth_t *data = (fluidsynth_t *) param; + int buf_pos = 0; + int buf_size = data->buf_size / BUFFER_SEGMENTS; + + thread_set_event(data->start_event); + + while (data->on) { + thread_wait_event(data->event, -1); + thread_reset_event(data->event); + + if (sound_is_float) { + float *buf = (float *) ((uint8_t *) data->buffer + buf_pos); + memset(buf, 0, buf_size); + if (data->synth) + f_fluid_synth_write_float(data->synth, buf_size / (2 * sizeof(float)), buf, 0, 2, buf, 1, 2); + buf_pos += buf_size; + if (buf_pos >= data->buf_size) { + givealbuffer_midi(data->buffer, data->buf_size / sizeof(float)); + buf_pos = 0; + } + } else { + int16_t *buf = (int16_t *) ((uint8_t *) data->buffer_int16 + buf_pos); + memset(buf, 0, buf_size); + if (data->synth) + f_fluid_synth_write_s16(data->synth, buf_size / (2 * sizeof(int16_t)), buf, 0, 2, buf, 1, 2); + buf_pos += buf_size; + if (buf_pos >= data->buf_size) { + givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t)); + buf_pos = 0; + } } + } } -static void fluidsynth_thread(void *param) +void +fluidsynth_msg(uint8_t *msg) { - fluidsynth_t* data = (fluidsynth_t*)param; - int buf_pos = 0; - int buf_size = data->buf_size / BUFFER_SEGMENTS; + fluidsynth_t *data = &fsdev; - thread_set_event(data->start_event); + uint32_t val = *((uint32_t *) msg); - while (data->on) - { - thread_wait_event(data->event, -1); - thread_reset_event(data->event); + uint32_t param2 = (uint8_t) ((val >> 16) & 0xFF); + uint32_t param1 = (uint8_t) ((val >> 8) & 0xFF); + uint8_t cmd = (uint8_t) (val & 0xF0); + uint8_t chan = (uint8_t) (val & 0x0F); - if (sound_is_float) - { - float *buf = (float*)((uint8_t*)data->buffer + buf_pos); - memset(buf, 0, buf_size); - if (data->synth) - f_fluid_synth_write_float(data->synth, buf_size/(2 * sizeof(float)), buf, 0, 2, buf, 1, 2); - buf_pos += buf_size; - if (buf_pos >= data->buf_size) - { - givealbuffer_midi(data->buffer, data->buf_size / sizeof(float)); - buf_pos = 0; - } - } - else - { - int16_t *buf = (int16_t*)((uint8_t*)data->buffer_int16 + buf_pos); - memset(buf, 0, buf_size); - if (data->synth) - f_fluid_synth_write_s16(data->synth, buf_size/(2 * sizeof(int16_t)), buf, 0, 2, buf, 1, 2); - buf_pos += buf_size; - if (buf_pos >= data->buf_size) - { - givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t)); - buf_pos = 0; - } - } - } -} - -void fluidsynth_msg(uint8_t *msg) -{ - fluidsynth_t* data = &fsdev; - - uint32_t val = *((uint32_t*)msg); - - uint32_t param2 = (uint8_t) ((val >> 16) & 0xFF); - uint32_t param1 = (uint8_t) ((val >> 8) & 0xFF); - uint8_t cmd = (uint8_t) (val & 0xF0); - uint8_t chan = (uint8_t) (val & 0x0F); - - switch (cmd) { - case 0x80: /* Note Off */ - f_fluid_synth_noteoff(data->synth, chan, param1); - break; - case 0x90: /* Note On */ - f_fluid_synth_noteon(data->synth, chan, param1, param2); - break; - case 0xA0: /* Aftertouch */ - break; - case 0xB0: /* Control Change */ - f_fluid_synth_cc(data->synth, chan, param1, param2); - break; - case 0xC0: /* Program Change */ - f_fluid_synth_program_change(data->synth, chan, param1); - break; - case 0xD0: /* Channel Pressure */ - break; - case 0xE0: /* Pitch Bend */ - f_fluid_synth_pitch_bend(data->synth, chan, (param2 << 7) | param1); - break; - case 0xF0: /* SysEx */ - break; + switch (cmd) { + case 0x80: /* Note Off */ + f_fluid_synth_noteoff(data->synth, chan, param1); + break; + case 0x90: /* Note On */ + f_fluid_synth_noteon(data->synth, chan, param1, param2); + break; + case 0xA0: /* Aftertouch */ + break; + case 0xB0: /* Control Change */ + f_fluid_synth_cc(data->synth, chan, param1, param2); + break; + case 0xC0: /* Program Change */ + f_fluid_synth_program_change(data->synth, chan, param1); + break; + case 0xD0: /* Channel Pressure */ + break; + case 0xE0: /* Pitch Bend */ + f_fluid_synth_pitch_bend(data->synth, chan, (param2 << 7) | param1); + break; + case 0xF0: /* SysEx */ + break; default: - break; - } + break; + } } -void fluidsynth_sysex(uint8_t* data, unsigned int len) +void +fluidsynth_sysex(uint8_t *data, unsigned int len) { - fluidsynth_t* d = &fsdev; + fluidsynth_t *d = &fsdev; - f_fluid_synth_sysex(d->synth, (const char *) data, len, 0, 0, 0, 0); + f_fluid_synth_sysex(d->synth, (const char *) data, len, 0, 0, 0, 0); } -void* fluidsynth_init(const device_t *info) +void * +fluidsynth_init(const device_t *info) { - fluidsynth_t* data = &fsdev; - midi_device_t* dev; + fluidsynth_t *data = &fsdev; + midi_device_t *dev; - memset(data, 0, sizeof(fluidsynth_t)); + memset(data, 0, sizeof(fluidsynth_t)); - /* Try loading the DLL. */ -#ifdef _WIN32 - fluidsynth_handle = dynld_module("libfluidsynth.dll", fluidsynth_imports); -#else - fluidsynth_handle = dynld_module("libfluidsynth.so", fluidsynth_imports); -#endif - if (fluidsynth_handle == NULL) - { - ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2080, (wchar_t *) IDS_2133); - return NULL; - } + /* Try loading the DLL. */ +# ifdef _WIN32 +# if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + fluidsynth_handle = dynld_module("libfluidsynth.dll", fluidsynth_imports); +# else + fluidsynth_handle = dynld_module("libfluidsynth64.dll", fluidsynth_imports); +# endif +# elif defined __APPLE__ + fluidsynth_handle = dynld_module("libfluidsynth.dylib", fluidsynth_imports); +# else + fluidsynth_handle = dynld_module("libfluidsynth.so.3", fluidsynth_imports); + if (fluidsynth_handle == NULL) + fluidsynth_handle = dynld_module("libfluidsynth.so.2", fluidsynth_imports); +# endif + if (fluidsynth_handle == NULL) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2080, (wchar_t *) IDS_2133); + return NULL; + } - data->settings = f_new_fluid_settings(); + data->settings = f_new_fluid_settings(); - f_fluid_settings_setnum(data->settings, "synth.sample-rate", 44100); - f_fluid_settings_setnum(data->settings, "synth.gain", device_get_config_int("output_gain")/100.0f); + f_fluid_settings_setnum(data->settings, "synth.sample-rate", 44100); + f_fluid_settings_setnum(data->settings, "synth.gain", device_get_config_int("output_gain") / 100.0f); - data->synth = f_new_fluid_synth(data->settings); + data->synth = f_new_fluid_synth(data->settings); - char* sound_font = (char *) device_get_config_string("sound_font"); - data->sound_font = f_fluid_synth_sfload(data->synth, sound_font, 1); + const char *sound_font = (char *) device_get_config_string("sound_font"); +# ifdef __unix__ + if (!sound_font || sound_font[0] == 0) + sound_font = (access("/usr/share/sounds/sf2/FluidR3_GM.sf2", F_OK) == 0 ? "/usr/share/sounds/sf2/FluidR3_GM.sf2" : + (access("/usr/share/soundfonts/default.sf2", F_OK) == 0 ? "/usr/share/soundfonts/default.sf2" : "")); +# endif + data->sound_font = f_fluid_synth_sfload(data->synth, sound_font, 1); - if (device_get_config_int("chorus")) - { - f_fluid_synth_set_chorus_on(data->synth, 1); + if (device_get_config_int("chorus")) { + f_fluid_synth_set_chorus_on(data->synth, 1); - int chorus_voices = device_get_config_int("chorus_voices"); - double chorus_level = device_get_config_int("chorus_level") / 100.0; - double chorus_speed = device_get_config_int("chorus_speed") / 100.0; - double chorus_depth = device_get_config_int("chorus_depth") / 10.0; + int chorus_voices = device_get_config_int("chorus_voices"); + double chorus_level = device_get_config_int("chorus_level") / 100.0; + double chorus_speed = device_get_config_int("chorus_speed") / 100.0; + double chorus_depth = device_get_config_int("chorus_depth") / 10.0; - int chorus_waveform = FLUID_CHORUS_MOD_SINE; - if (device_get_config_int("chorus_waveform") == 0) - chorus_waveform = FLUID_CHORUS_MOD_SINE; - else - chorus_waveform = FLUID_CHORUS_MOD_TRIANGLE; - - f_fluid_synth_set_chorus(data->synth, chorus_voices, chorus_level, chorus_speed, chorus_depth, chorus_waveform); - } + int chorus_waveform = FLUID_CHORUS_MOD_SINE; + if (device_get_config_int("chorus_waveform") == 0) + chorus_waveform = FLUID_CHORUS_MOD_SINE; else - f_fluid_synth_set_chorus_on(data->synth, 0); + chorus_waveform = FLUID_CHORUS_MOD_TRIANGLE; - if (device_get_config_int("reverb")) - { - f_fluid_synth_set_reverb_on(data->synth, 1); + f_fluid_synth_set_chorus(data->synth, chorus_voices, chorus_level, chorus_speed, chorus_depth, chorus_waveform); + } else + f_fluid_synth_set_chorus_on(data->synth, 0); - double reverb_room_size = device_get_config_int("reverb_room_size") / 100.0; - double reverb_damping = device_get_config_int("reverb_damping") / 100.0; - int reverb_width = device_get_config_int("reverb_width"); - double reverb_level = device_get_config_int("reverb_level") / 100.0; + if (device_get_config_int("reverb")) { + f_fluid_synth_set_reverb_on(data->synth, 1); - f_fluid_synth_set_reverb(data->synth, reverb_room_size, reverb_damping, reverb_width, reverb_level); - } - else - f_fluid_synth_set_reverb_on(data->synth, 0); + double reverb_room_size = device_get_config_int("reverb_room_size") / 100.0; + double reverb_damping = device_get_config_int("reverb_damping") / 100.0; + int reverb_width = device_get_config_int("reverb_width"); + double reverb_level = device_get_config_int("reverb_level") / 100.0; - int interpolation = device_get_config_int("interpolation"); - int fs_interpolation = FLUID_INTERP_4THORDER; + f_fluid_synth_set_reverb(data->synth, reverb_room_size, reverb_damping, reverb_width, reverb_level); + } else + f_fluid_synth_set_reverb_on(data->synth, 0); - if (interpolation == 0) - fs_interpolation = FLUID_INTERP_NONE; - else if (interpolation == 1) - fs_interpolation = FLUID_INTERP_LINEAR; - else if (interpolation == 2) - fs_interpolation = FLUID_INTERP_4THORDER; - else if (interpolation == 3) - fs_interpolation = FLUID_INTERP_7THORDER; + int interpolation = device_get_config_int("interpolation"); + int fs_interpolation = FLUID_INTERP_4THORDER; - f_fluid_synth_set_interp_method(data->synth, -1, fs_interpolation); + if (interpolation == 0) + fs_interpolation = FLUID_INTERP_NONE; + else if (interpolation == 1) + fs_interpolation = FLUID_INTERP_LINEAR; + else if (interpolation == 2) + fs_interpolation = FLUID_INTERP_4THORDER; + else if (interpolation == 3) + fs_interpolation = FLUID_INTERP_7THORDER; - double samplerate; - f_fluid_settings_getnum(data->settings, "synth.sample-rate", &samplerate); - data->samplerate = (int)samplerate; - if (sound_is_float) - { - data->buf_size = (data->samplerate/RENDER_RATE)*2*sizeof(float)*BUFFER_SEGMENTS; - data->buffer = malloc(data->buf_size); - data->buffer_int16 = NULL; - } - else - { - data->buf_size = (data->samplerate/RENDER_RATE)*2*sizeof(int16_t)*BUFFER_SEGMENTS; - data->buffer = NULL; - data->buffer_int16 = malloc(data->buf_size); - } + f_fluid_synth_set_interp_method(data->synth, -1, fs_interpolation); - al_set_midi(data->samplerate, data->buf_size); + double samplerate; + f_fluid_settings_getnum(data->settings, "synth.sample-rate", &samplerate); + data->samplerate = (int) samplerate; + if (sound_is_float) { + data->buf_size = (data->samplerate / RENDER_RATE) * 2 * sizeof(float) * BUFFER_SEGMENTS; + data->buffer = malloc(data->buf_size); + data->buffer_int16 = NULL; + } else { + data->buf_size = (data->samplerate / RENDER_RATE) * 2 * sizeof(int16_t) * BUFFER_SEGMENTS; + data->buffer = NULL; + data->buffer_int16 = malloc(data->buf_size); + } - dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); + al_set_midi(data->samplerate, data->buf_size); - dev->play_msg = fluidsynth_msg; - dev->play_sysex = fluidsynth_sysex; - dev->poll = fluidsynth_poll; + dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); - midi_init(dev); + dev->play_msg = fluidsynth_msg; + dev->play_sysex = fluidsynth_sysex; + dev->poll = fluidsynth_poll; - data->on = 1; + midi_out_init(dev); - data->start_event = thread_create_event(); + data->on = 1; - data->event = thread_create_event(); - data->thread_h = thread_create(fluidsynth_thread, data); + data->start_event = thread_create_event(); - thread_wait_event(data->start_event, -1); - thread_reset_event(data->start_event); + data->event = thread_create_event(); + data->thread_h = thread_create(fluidsynth_thread, data); - return dev; + thread_wait_event(data->start_event, -1); + thread_reset_event(data->start_event); + + return dev; } -void fluidsynth_close(void* p) +void +fluidsynth_close(void *p) { - if (!p) return; + if (!p) + return; - fluidsynth_t* data = &fsdev; + fluidsynth_t *data = &fsdev; - data->on = 0; - thread_set_event(data->event); - thread_wait(data->thread_h, -1); + data->on = 0; + thread_set_event(data->event); + thread_wait(data->thread_h); - if (data->synth) { - f_delete_fluid_synth(data->synth); - data->synth = NULL; - } + if (data->synth) { + f_delete_fluid_synth(data->synth); + data->synth = NULL; + } - if (data->settings) { - f_delete_fluid_settings(data->settings); - data->settings = NULL; - } + if (data->settings) { + f_delete_fluid_settings(data->settings); + data->settings = NULL; + } - if (data->buffer) - { - free(data->buffer); - data->buffer = NULL; - } + if (data->buffer) { + free(data->buffer); + data->buffer = NULL; + } - if (data->buffer_int16) - { - free(data->buffer_int16); - data->buffer_int16 = NULL; - } + if (data->buffer_int16) { + free(data->buffer_int16); + data->buffer_int16 = NULL; + } - /* Unload the DLL if possible. */ - if (fluidsynth_handle != NULL) - { - dynld_close(fluidsynth_handle); - fluidsynth_handle = NULL; - } + /* Unload the DLL if possible. */ + if (fluidsynth_handle != NULL) { + dynld_close(fluidsynth_handle); + fluidsynth_handle = NULL; + } } -static const device_config_t fluidsynth_config[] = -{ +static const device_config_t fluidsynth_config[] = { + // clang-format off + { + .name = "sound_font", + .description = "Sound Font", + .type = CONFIG_FNAME, + .default_string = "", + .file_filter = "SF2 Sound Fonts (*.sf2)|*.sf2" + }, + { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .spinner = { - .name = "sound_font", - .description = "Sound Font", - .type = CONFIG_FNAME, - .default_string = "", - .file_filter = - { - { - .description = "SF2 Sound Fonts", - .extensions = - { - "sf2" - } - } - } + .min = 0, + .max = 100 }, + .default_int = 100 + }, + { + .name = "chorus", + .description = "Chorus", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "chorus_voices", + .description = "Chorus Voices", + .type = CONFIG_SPINNER, + .spinner = { - .name = "output_gain", - .description = "Output Gain", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 100 + .min = 0, + .max = 99 }, + .default_int = 3 + }, + { + .name = "chorus_level", + .description = "Chorus Level", + .type = CONFIG_SPINNER, + .spinner = { - .name = "chorus", - .description = "Chorus", - .type = CONFIG_BINARY, - .default_int = 0 + .min = 0, + .max = 100 }, + .default_int = 100 + }, + { + .name = "chorus_speed", + .description = "Chorus Speed", + .type = CONFIG_SPINNER, + .spinner = { - .name = "chorus_voices", - .description = "Chorus Voices", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 99 - }, - .default_int = 3 + .min = 30, + .max = 500 }, + .default_int = 30 + }, + { + .name = "chorus_depth", + .description = "Chorus Depth", + .type = CONFIG_SPINNER, + .spinner = { - .name = "chorus_level", - .description = "Chorus Level", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 100 + .min = 0, + .max = 210 }, + .default_int = 80 + }, + { + .name = "chorus_waveform", + .description = "Chorus Waveform", + .type = CONFIG_SELECTION, + .selection = { - .name = "chorus_speed", - .description = "Chorus Speed", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 30, - .max = 500 - }, - .default_int = 30 + { + .description = "Sine", + .value = 0 + }, + { + .description = "Triangle", + .value = 1 + } }, + .default_int = 0 + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "reverb_room_size", + .description = "Reverb Room Size", + .type = CONFIG_SPINNER, + .spinner = { - .name = "chorus_depth", - .description = "Chorus Depth", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 210 - }, - .default_int = 80 + .min = 0, + .max = 120 }, + .default_int = 20 + }, + { + .name = "reverb_damping", + .description = "Reverb Damping", + .type = CONFIG_SPINNER, + .spinner = { - .name = "chorus_waveform", - .description = "Chorus Waveform", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Sine", - .value = 0 - }, - { - .description = "Triangle", - .value = 1 - } - }, - .default_int = 0 + .min = 0, + .max = 100 }, + .default_int = 0 + }, + { + .name = "reverb_width", + .description = "Reverb Width", + .type = CONFIG_SPINNER, + .spinner = { - .name = "reverb", - .description = "Reverb", - .type = CONFIG_BINARY, - .default_int = 0 + .min = 0, + .max = 100 }, + .default_int = 1 + }, + { + .name = "reverb_level", + .description = "Reverb Level", + .type = CONFIG_SPINNER, + .spinner = { - .name = "reverb_room_size", - .description = "Reverb Room Size", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 120 - }, - .default_int = 20 + .min = 0, + .max = 100 }, + .default_int = 90 + }, + { + .name = "interpolation", + .description = "Interpolation Method", + .type = CONFIG_SELECTION, + .selection = { - .name = "reverb_damping", - .description = "Reverb Damping", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 0 + { + .description = "None", + .value = 0 + }, + { + .description = "Linear", + .value = 1 + }, + { + .description = "4th Order", + .value = 2 + }, + { + .description = "7th Order", + .value = 3 + } }, - { - .name = "reverb_width", - .description = "Reverb Width", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 1 - }, - { - .name = "reverb_level", - .description = "Reverb Level", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 90 - }, - { - .name = "interpolation", - .description = "Interpolation Method", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "None", - .value = 0 - }, - { - .description = "Linear", - .value = 1 - }, - { - .description = "4th Order", - .value = 2 - }, - { - .description = "7th Order", - .value = 3 - } - }, - .default_int = 2 - }, - { - .type = -1 - } + .default_int = 2 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on }; -const device_t fluidsynth_device = -{ - "FluidSynth", - 0, - 0, - fluidsynth_init, - fluidsynth_close, - NULL, - fluidsynth_available, - NULL, - NULL, - fluidsynth_config +const device_t fluidsynth_device = { + .name = "FluidSynth", + .internal_name = "fluidsynth", + .flags = 0, + .local = 0, + .init = fluidsynth_init, + .close = fluidsynth_close, + .reset = NULL, + { .available = fluidsynth_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = fluidsynth_config }; - -#endif /*USE_FLUIDSYNTH*/ +#endif /*USE_FLUIDSYNTH*/ diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index 987d615a1..bb86210f3 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -1,340 +1,402 @@ -#include #include -#include +#include #include +#include #include -#include + #include <86box/86box.h> #include <86box/device.h> #include <86box/mem.h> -#include <86box/rom.h> -#include <86box/plat.h> -#include <86box/sound.h> #include <86box/midi.h> - +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/rom.h> +#include <86box/sound.h> +#include <86box/ui.h> +#include extern void givealbuffer_midi(void *buf, uint32_t size); extern void al_set_midi(int freq, int buf_size); -static const mt32emu_report_handler_i_v0 handler_v0 = { - /** Returns the actual interface version ID */ - NULL, //mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); +static void display_mt32_message(void *instance_data, const char *message); - /** Callback for debug messages, in vprintf() format */ - NULL, //void (*printDebug)(void *instance_data, const char *fmt, va_list list); - /** Callbacks for reporting errors */ - NULL, //void (*onErrorControlROM)(void *instance_data); - NULL, //void (*onErrorPCMROM)(void *instance_data); - /** Callback for reporting about displaying a new custom message on LCD */ - NULL, //void (*showLCDMessage)(void *instance_data, const char *message); - /** Callback for reporting actual processing of a MIDI message */ - NULL, //void (*onMIDIMessagePlayed)(void *instance_data); - /** - * Callback for reporting an overflow of the input MIDI queue. - * Returns MT32EMU_BOOL_TRUE if a recovery action was taken - * and yet another attempt to enqueue the MIDI event is desired. - */ - NULL, //mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); - /** - * Callback invoked when a System Realtime MIDI message is detected in functions - * mt32emu_parse_stream and mt32emu_play_short_message and the likes. - */ - NULL, //void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); - /** Callbacks for reporting system events */ - NULL, //void (*onDeviceReset)(void *instance_data); - NULL, //void (*onDeviceReconfig)(void *instance_data); - /** Callbacks for reporting changes of reverb settings */ - NULL, //void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); - NULL, //void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); - NULL, //void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); - /** Callbacks for reporting various information */ - NULL, //void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); - NULL, //void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); +static const mt32emu_report_handler_i_v0 handler_mt32_v0 = { + /** Returns the actual interface version ID */ + NULL, // mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); + + /** Callback for debug messages, in vprintf() format */ + NULL, // void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + NULL, // void (*onErrorControlROM)(void *instance_data); + NULL, // void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + display_mt32_message, // void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + NULL, // void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + NULL, // mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + NULL, // void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + NULL, // void (*onDeviceReset)(void *instance_data); + NULL, // void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + NULL, // void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + NULL, // void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + NULL, // void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + NULL, // void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + NULL, // void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); }; -static const mt32emu_report_handler_i handler = { &handler_v0 }; +/** Alternate report handler for Roland CM-32L */ +static const mt32emu_report_handler_i_v0 handler_cm32l_v0 = { + /** Returns the actual interface version ID */ + NULL, // mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); -static mt32emu_context context = NULL; -static int roms_present[2] = {-1, -1}; + /** Callback for debug messages, in vprintf() format */ + NULL, // void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + NULL, // void (*onErrorControlROM)(void *instance_data); + NULL, // void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + NULL, // void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + NULL, // void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + NULL, // mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + NULL, // void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + NULL, // void (*onDeviceReset)(void *instance_data); + NULL, // void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + NULL, // void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + NULL, // void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + NULL, // void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + NULL, // void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + NULL, // void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); +}; -mt32emu_return_code mt32_check(const char* func, mt32emu_return_code ret, mt32emu_return_code expected) +static const mt32emu_report_handler_i handler_mt32 = { &handler_mt32_v0 }; +static const mt32emu_report_handler_i handler_cm32l = { &handler_cm32l_v0 }; + +static mt32emu_context context = NULL; +static int roms_present[2] = { -1, -1 }; + +mt32emu_return_code +mt32_check(const char *func, mt32emu_return_code ret, mt32emu_return_code expected) { - if (ret != expected) - { - return 0; - } - return 1; + if (ret != expected) { + return 0; + } + return 1; } -int mt32_available() +int +mt32_available() { - if (roms_present[0] < 0) - roms_present[0] = (rom_present(L"roms/sound/mt32/mt32_control.rom") && rom_present(L"roms/sound/mt32/mt32_pcm.rom")); - return roms_present[0]; + if (roms_present[0] < 0) + roms_present[0] = (rom_present("roms/sound/mt32/MT32_CONTROL.ROM") && rom_present("roms/sound/mt32/MT32_PCM.ROM")); + return roms_present[0]; } -int cm32l_available() +int +cm32l_available() { - if (roms_present[1] < 0) - roms_present[1] = (rom_present(L"roms/sound/cm32l/cm32l_control.rom") && rom_present(L"roms/sound/cm32l/cm32l_pcm.rom")); - return roms_present[1]; + if (roms_present[1] < 0) + roms_present[1] = (rom_present("roms/sound/cm32l/CM32L_CONTROL.ROM") && rom_present("roms/sound/cm32l/CM32L_PCM.ROM")); + return roms_present[1]; } -static thread_t *thread_h = NULL; -static event_t *event = NULL; -static event_t *start_event = NULL; -static int mt32_on = 0; +static thread_t *thread_h = NULL; +static event_t *event = NULL; +static event_t *start_event = NULL; +static int mt32_on = 0; -#define RENDER_RATE 100 +#define RENDER_RATE 100 #define BUFFER_SEGMENTS 10 -static uint32_t samplerate = 44100; -static int buf_size = 0; -static float* buffer = NULL; -static int16_t* buffer_int16 = NULL; -static int midi_pos = 0; +static uint32_t samplerate = 44100; +static int buf_size = 0; +static float *buffer = NULL; +static int16_t *buffer_int16 = NULL; +static int midi_pos = 0; -void mt32_stream(float* stream, int len) +static void +display_mt32_message(void *instance_data, const char *message) { - if (context) mt32emu_render_float(context, stream, len); + int sz = 0; + char *ui_msg = NULL; + + sz = snprintf(NULL, 0, "MT-32: %s", message); + ui_msg = calloc(sz + 1, 1); + if (ui_msg) { + snprintf(ui_msg, sz, "MT-32: %s", message); + ui_sb_mt32lcd(ui_msg); + } } -void mt32_stream_int16(int16_t* stream, int len) +void +mt32_stream(float *stream, int len) { - if (context) mt32emu_render_bit16s(context, stream, len); + if (context) + mt32emu_render_float(context, stream, len); } -void mt32_poll() +void +mt32_stream_int16(int16_t *stream, int len) { - midi_pos++; - if (midi_pos == 48000/RENDER_RATE) - { - midi_pos = 0; - thread_set_event(event); + if (context) + mt32emu_render_bit16s(context, stream, len); +} + +void +mt32_poll() +{ + midi_pos++; + if (midi_pos == 48000 / RENDER_RATE) { + midi_pos = 0; + thread_set_event(event); + } +} + +static void +mt32_thread(void *param) +{ + int buf_pos = 0; + int bsize = buf_size / BUFFER_SEGMENTS; + float *buf; + int16_t *buf16; + + thread_set_event(start_event); + + while (mt32_on) { + thread_wait_event(event, -1); + thread_reset_event(event); + + if (sound_is_float) { + buf = (float *) ((uint8_t *) buffer + buf_pos); + memset(buf, 0, bsize); + mt32_stream(buf, bsize / (2 * sizeof(float))); + buf_pos += bsize; + if (buf_pos >= buf_size) { + givealbuffer_midi(buffer, buf_size / sizeof(float)); + buf_pos = 0; + } + } else { + buf16 = (int16_t *) ((uint8_t *) buffer_int16 + buf_pos); + memset(buf16, 0, bsize); + mt32_stream_int16(buf16, bsize / (2 * sizeof(int16_t))); + buf_pos += bsize; + if (buf_pos >= buf_size) { + givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); + buf_pos = 0; + } } + } } -static void mt32_thread(void *param) +void +mt32_msg(uint8_t *val) { - int buf_pos = 0; - int bsize = buf_size / BUFFER_SEGMENTS; - float *buf; - int16_t *buf16; - - thread_set_event(start_event); - - while (mt32_on) - { - thread_wait_event(event, -1); - thread_reset_event(event); - - if (sound_is_float) - { - buf = (float *) ((uint8_t*)buffer + buf_pos); - memset(buf, 0, bsize); - mt32_stream(buf, bsize / (2 * sizeof(float))); - buf_pos += bsize; - if (buf_pos >= buf_size) - { - givealbuffer_midi(buffer, buf_size / sizeof(float)); - buf_pos = 0; - } - } - else - { - buf16 = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); - memset(buf16, 0, bsize); - mt32_stream_int16(buf16, bsize / (2 * sizeof(int16_t))); - buf_pos += bsize; - if (buf_pos >= buf_size) - { - givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); - buf_pos = 0; - } - } - } + if (context) + mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t *) val), MT32EMU_RC_OK); } -void mt32_msg(uint8_t* val) +void +mt32_sysex(uint8_t *data, unsigned int len) { - if (context) mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t*)val), MT32EMU_RC_OK); + if (context) + mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); } -void mt32_sysex(uint8_t* data, unsigned int len) +void * +mt32emu_init(char *control_rom, char *pcm_rom) { - if (context) mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); -} + midi_device_t *dev; + char fn[512]; -void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) -{ - midi_device_t* dev; - wchar_t s[512]; - char fn[512]; + context = mt32emu_create_context(strstr(control_rom, "CM32L_CONTROL.ROM") ? handler_cm32l : handler_mt32, NULL); - context = mt32emu_create_context(handler, NULL); + if (!rom_getfile(control_rom, fn, 512)) + return 0; + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) + return 0; + if (!rom_getfile(pcm_rom, fn, 512)) + return 0; + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) + return 0; - if (!rom_getfile(control_rom, s, 512)) return 0; - wcstombs(fn, s, (wcslen(s) << 1) + 2); - if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; - if (!rom_getfile(pcm_rom, s, 512)) return 0; - wcstombs(fn, s, (wcslen(s) << 1) + 2); - if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) return 0; + if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) + return 0; - if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; - - samplerate = mt32emu_get_actual_stereo_output_samplerate(context); - /* buf_size = samplerate/RENDER_RATE*2; */ - if (sound_is_float) - { - buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(float); - buffer = malloc(buf_size); - buffer_int16 = NULL; - } - else - { - buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(int16_t); - buffer = NULL; - buffer_int16 = malloc(buf_size); - } - - mt32emu_set_output_gain(context, device_get_config_int("output_gain")/100.0f); - mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); - mt32emu_set_reverb_output_gain(context, device_get_config_int("reverb_output_gain")/100.0f); - mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); - mt32emu_set_nice_amp_ramp_enabled(context, device_get_config_int("nice_ramp")); - - al_set_midi(samplerate, buf_size); - - dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); - - dev->play_msg = mt32_msg; - dev->play_sysex = mt32_sysex; - dev->poll = mt32_poll; - - midi_init(dev); - - mt32_on = 1; - - start_event = thread_create_event(); - - event = thread_create_event(); - thread_h = thread_create(mt32_thread, 0); - - thread_wait_event(start_event, -1); - thread_reset_event(start_event); - - return dev; -} - -void *mt32_init(const device_t *info) -{ - return mt32emu_init(L"roms/sound/mt32/mt32_control.rom", L"roms/sound/mt32/mt32_pcm.rom"); -} - -void *cm32l_init(const device_t *info) -{ - return mt32emu_init(L"roms/sound/cm32l/cm32l_control.rom", L"roms/sound/cm32l/cm32l_pcm.rom"); -} - -void mt32_close(void* p) -{ - if (!p) return; - - mt32_on = 0; - thread_set_event(event); - thread_wait(thread_h, -1); - - event = NULL; - start_event = NULL; - thread_h = NULL; - - if (context) { - mt32emu_close_synth(context); - mt32emu_free_context(context); - } - context = NULL; - - if (buffer) - free(buffer); - buffer = NULL; - - if (buffer_int16) - free(buffer_int16); + samplerate = mt32emu_get_actual_stereo_output_samplerate(context); + /* buf_size = samplerate/RENDER_RATE*2; */ + if (sound_is_float) { + buf_size = (samplerate / RENDER_RATE) * 2 * BUFFER_SEGMENTS * sizeof(float); + buffer = malloc(buf_size); buffer_int16 = NULL; + } else { + buf_size = (samplerate / RENDER_RATE) * 2 * BUFFER_SEGMENTS * sizeof(int16_t); + buffer = NULL; + buffer_int16 = malloc(buf_size); + } + + mt32emu_set_output_gain(context, device_get_config_int("output_gain") / 100.0f); + mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); + mt32emu_set_reverb_output_gain(context, device_get_config_int("reverb_output_gain") / 100.0f); + mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); + mt32emu_set_nice_amp_ramp_enabled(context, device_get_config_int("nice_ramp")); + + al_set_midi(samplerate, buf_size); + + dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = mt32_msg; + dev->play_sysex = mt32_sysex; + dev->poll = mt32_poll; + + midi_out_init(dev); + + mt32_on = 1; + + start_event = thread_create_event(); + + event = thread_create_event(); + thread_h = thread_create(mt32_thread, 0); + + thread_wait_event(start_event, -1); + thread_reset_event(start_event); + + return dev; } -static const device_config_t mt32_config[] = +void * +mt32_init(const device_t *info) { - { - .name = "output_gain", - .description = "Output Gain", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 100 + return mt32emu_init("roms/sound/mt32/MT32_CONTROL.ROM", "roms/sound/mt32/MT32_PCM.ROM"); +} + +void * +cm32l_init(const device_t *info) +{ + return mt32emu_init("roms/sound/cm32l/CM32L_CONTROL.ROM", "roms/sound/cm32l/CM32L_PCM.ROM"); +} + +void +mt32_close(void *p) +{ + if (!p) + return; + + mt32_on = 0; + thread_set_event(event); + thread_wait(thread_h); + + event = NULL; + start_event = NULL; + thread_h = NULL; + + if (context) { + mt32emu_close_synth(context); + mt32emu_free_context(context); + } + context = NULL; + + if (buffer) + free(buffer); + buffer = NULL; + + if (buffer_int16) + free(buffer_int16); + buffer_int16 = NULL; +} + +static const device_config_t mt32_config[] = { +// clang-format off + { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .spinner = { + .min = 0, + .max = 100 }, - { - .name = "reverb", - .description = "Reverb", - .type = CONFIG_BINARY, - .default_int = 1 + .default_int = 100 + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "reverb_output_gain", + .description = "Reverb Output Gain", + .type = CONFIG_SPINNER, + .spinner = { + .min = 0, + .max = 100 }, - { - .name = "reverb_output_gain", - .description = "Reverb Output Gain", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 100 - }, - { - .name = "reversed_stereo", - .description = "Reversed stereo", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "nice_ramp", - .description = "Nice ramp", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .type = -1 - } + .default_int = 100 + }, + { + .name = "reversed_stereo", + .description = "Reversed stereo", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "nice_ramp", + .description = "Nice ramp", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -const device_t mt32_device = -{ - "Roland MT-32 Emulation", - 0, - 0, - mt32_init, - mt32_close, - NULL, - mt32_available, - NULL, - NULL, - mt32_config +const device_t mt32_device = { + .name = "Roland MT-32 Emulation", + .internal_name = "mt32", + .flags = 0, + .local = 0, + .init = mt32_init, + .close = mt32_close, + .reset = NULL, + { .available = mt32_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mt32_config }; -const device_t cm32l_device = -{ - "Roland CM-32L Emulation", - 0, - 0, - cm32l_init, - mt32_close, - NULL, - cm32l_available, - NULL, - NULL, - mt32_config +const device_t cm32l_device = { + .name = "Roland CM-32L Emulation", + .internal_name = "cm32l", + .flags = 0, + .local = 0, + .init = cm32l_init, + .close = mt32_close, + .reset = NULL, + { .available = cm32l_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mt32_config }; diff --git a/src/sound/midi_rtmidi.cpp b/src/sound/midi_rtmidi.cpp new file mode 100644 index 000000000..c60f224ab --- /dev/null +++ b/src/sound/midi_rtmidi.cpp @@ -0,0 +1,305 @@ +/* + * 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. + * + * MIDI backend implemented using the RtMidi library. + * + * Author: Cacodemon345, + * Miran Grca, + * Copyright 2021 Cacodemon345. + * Copyright 2021 Miran Grca. + */ + +#if defined __has_include +# if __has_include() +# include +# endif +# if __has_include() +# include +# endif +#endif + +#include +#include +#include +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/midi.h> +#include <86box/midi_rtmidi.h> +#include <86box/config.h> + +// Disable c99-designator to avoid the warnings in rtmidi_*_device +#ifdef __clang__ +# if __has_warning("-Wc99-designator") +# pragma clang diagnostic ignored "-Wc99-designator" +# endif +#endif + +static RtMidiOut *midiout = nullptr; +static RtMidiIn *midiin = nullptr; +static int midi_out_id = 0, midi_in_id = 0; +static const int midi_lengths[8] = { 3, 3, 3, 3, 2, 2, 3, 1 }; + +int +rtmidi_write(uint8_t val) +{ + return 0; +} + +void +rtmidi_play_msg(uint8_t *msg) +{ + if (midiout) + midiout->sendMessage(msg, midi_lengths[(msg[0] >> 4) & 7]); +} + +void +rtmidi_play_sysex(uint8_t *sysex, unsigned int len) +{ + if (midiout) + midiout->sendMessage(sysex, len); +} + +void* +rtmidi_output_init(const device_t *info) +{ + midi_device_t *dev = (midi_device_t *) malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = rtmidi_play_msg; + dev->play_sysex = rtmidi_play_sysex; + dev->write = rtmidi_write; + + try { + if (!midiout) + midiout = new RtMidiOut; + } catch (RtMidiError &error) { + pclog("Failed to initialize MIDI output: %s\n", error.getMessage().c_str()); + return nullptr; + } + + midi_out_id = config_get_int((char *) SYSTEM_MIDI_NAME, (char *) "midi", 0); + + try { + midiout->openPort(midi_out_id); + } catch (RtMidiError &error) { + pclog("Fallback to default MIDI output port: %s\n", error.getMessage().c_str()); + + try { + midiout->openPort(0); + } catch (RtMidiError &error) { + pclog("Failed to initialize MIDI output: %s\n", error.getMessage().c_str()); + delete midiout; + midiout = nullptr; + return nullptr; + } + } + + midi_out_init(dev); + + return dev; +} + +void +rtmidi_output_close(void *p) +{ + if (!midiout) + return; + + midiout->closePort(); + + delete midiout; + midiout = nullptr; + + midi_out_close(); +} + +int +rtmidi_out_get_num_devs(void) +{ + if (!midiout) { + try { + midiout = new RtMidiOut; + } catch (RtMidiError &error) { + pclog("Failed to initialize MIDI output: %s\n", error.getMessage().c_str()); + } + } + + return midiout ? midiout->getPortCount() : 0; +} + +void +rtmidi_out_get_dev_name(int num, char *s) +{ + strcpy(s, midiout->getPortName(num).c_str()); +} + +void +rtmidi_input_callback(double timeStamp, std::vector *message, void *userData) +{ + if (message->front() == 0xF0) + midi_in_sysex(message->data(), message->size()); + else + midi_in_msg(message->data(), message->size()); +} + +void* +rtmidi_input_init(const device_t *info) +{ + midi_device_t *dev = (midi_device_t *) malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + try { + if (!midiin) + midiin = new RtMidiIn; + } catch (RtMidiError &error) { + pclog("Failed to initialize MIDI input: %s\n", error.getMessage().c_str()); + return nullptr; + } + + midi_in_id = config_get_int((char *) MIDI_INPUT_NAME, (char *) "midi_input", 0); + + try { + midiin->openPort(midi_in_id); + } catch (RtMidiError &error) { + pclog("Fallback to default MIDI input port: %s\n", error.getMessage().c_str()); + + try { + midiin->openPort(0); + } catch (RtMidiError &error) { + pclog("Failed to initialize MIDI input: %s\n", error.getMessage().c_str()); + delete midiin; + midiin = nullptr; + return nullptr; + } + } + + midiin->setCallback(&rtmidi_input_callback); + + // Don't ignore sysex, timing, or active sensing messages. + midiin->ignoreTypes(false, false, false); + + midi_in_init(dev, &midi_in); + + midi_in->midi_realtime = device_get_config_int("realtime"); + midi_in->thruchan = device_get_config_int("thruchan"); + midi_in->midi_clockout = device_get_config_int("clockout"); + + return dev; +} + +void +rtmidi_input_close(void *p) +{ + midiin->cancelCallback(); + midiin->closePort(); + + delete midiin; + midiin = nullptr; + + midi_out_close(); +} + +int +rtmidi_in_get_num_devs(void) +{ + if (!midiin) { + try { + midiin = new RtMidiIn; + } catch (RtMidiError &error) { + pclog("Failed to initialize MIDI input: %s\n", error.getMessage().c_str()); + } + } + + return midiin ? midiin->getPortCount() : 0; +} + +void +rtmidi_in_get_dev_name(int num, char *s) +{ + strcpy(s, midiin->getPortName(num).c_str()); +} + +static const device_config_t system_midi_config[] = { + // clang-format off + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI_OUT, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +static const device_config_t midi_input_config[] = { + // clang-format off + { + .name = "midi_input", + .description = "MIDI in device", + .type = CONFIG_MIDI_IN, + .default_string = "", + .default_int = 0 + }, + { + .name = "realtime", + .description = "MIDI Real time", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { + .name = "thruchan", + .description = "MIDI Thru", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "clockout", + .description = "MIDI Clockout", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t rtmidi_output_device = { + .name = SYSTEM_MIDI_NAME, + .internal_name = SYSTEM_MIDI_INTERNAL_NAME, + .flags = 0, + .local = 0, + .init = rtmidi_output_init, + .close = rtmidi_output_close, + .reset = NULL, + { .available = rtmidi_out_get_num_devs }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = system_midi_config +}; + +const device_t rtmidi_input_device = { + .name = MIDI_INPUT_NAME, + .internal_name = MIDI_INPUT_INTERNAL_NAME, + .flags = 0, + .local = 0, + .init = rtmidi_input_init, + .close = rtmidi_input_close, + .reset = NULL, + { .available = rtmidi_in_get_num_devs }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = midi_input_config +}; +} diff --git a/src/sound/midi_system.c b/src/sound/midi_system.c deleted file mode 100644 index 071e30883..000000000 --- a/src/sound/midi_system.c +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/device.h> -#include <86box/plat.h> -#include <86box/plat_midi.h> -#include <86box/midi.h> -#include <86box/midi_input.h> - - -void* system_midi_init(const device_t *info) -{ - midi_device_t* dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); - - dev->play_msg = plat_midi_play_msg; - dev->play_sysex = plat_midi_play_sysex; - dev->write = plat_midi_write; - - plat_midi_init(); - - midi_init(dev); - - return dev; -} - -void* midi_input_init(const device_t *info) -{ - midi_device_t* dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); - - plat_midi_input_init(); - - midi_in_init(dev, &midi_in); - - midi_in->midi_realtime = device_get_config_int("realtime"); - midi_in->thruchan = device_get_config_int("thruchan"); - midi_in->midi_clockout = device_get_config_int("clockout"); - - return dev; -} - -void system_midi_close(void* p) -{ - plat_midi_close(); - - midi_close(); -} - -void midi_input_close(void* p) -{ - plat_midi_input_close(); - - midi_close(); -} - -int system_midi_available(void) -{ - return plat_midi_get_num_devs(); -} - -int midi_input_available(void) -{ - return plat_midi_in_get_num_devs(); -} - -static const device_config_t system_midi_config[] = -{ - { - .name = "midi", - .description = "MIDI out device", - .type = CONFIG_MIDI, - .default_int = 0 - }, - { - .type = -1 - } -}; - -static const device_config_t midi_input_config[] = -{ - { - .name = "midi_input", - .description = "MIDI in device", - .type = CONFIG_MIDI_IN, - .default_int = 0 - }, - { - .name = "realtime", - .description = "MIDI Real time", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "thruchan", - .description = "MIDI Thru", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "clockout", - .description = "MIDI Clockout", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .type = -1 - } -}; - -const device_t system_midi_device = -{ - SYSTEM_MIDI_NAME, - 0, 0, - system_midi_init, - system_midi_close, - NULL, - system_midi_available, - NULL, - NULL, - system_midi_config -}; - - -const device_t midi_input_device = -{ - MIDI_INPUT_NAME, - 0, 0, - midi_input_init, - midi_input_close, - NULL, - midi_input_available, - NULL, - NULL, - midi_input_config -}; \ No newline at end of file diff --git a/src/sound/munt/CMakeLists.txt b/src/sound/munt/CMakeLists.txt new file mode 100644 index 000000000..79ac7b2d9 --- /dev/null +++ b/src/sound/munt/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(mt32emu STATIC Analog.cpp BReverbModel.cpp File.cpp FileStream.cpp + LA32Ramp.cpp LA32FloatWaveGenerator.cpp LA32WaveGenerator.cpp + MidiStreamParser.cpp Part.cpp Partial.cpp PartialManager.cpp + Poly.cpp ROMInfo.cpp SampleRateConverter.cpp + srchelper/srctools/src/FIRResampler.cpp + srchelper/srctools/src/IIR2xResampler.cpp + srchelper/srctools/src/LinearResampler.cpp + srchelper/srctools/src/ResamplerModel.cpp + srchelper/srctools/src/SincResampler.cpp + srchelper/InternalResampler.cpp Synth.cpp Tables.cpp TVA.cpp TVF.cpp + TVP.cpp sha1/sha1.cpp c_interface/c_interface.cpp) \ No newline at end of file diff --git a/src/sound/munt/Structures.h b/src/sound/munt/Structures.h index de7281b16..8202c44b9 100644 --- a/src/sound/munt/Structures.h +++ b/src/sound/munt/Structures.h @@ -28,7 +28,7 @@ namespace MT32Emu { #define MT32EMU_MEMADDR(x) ((((x) & 0x7f0000) >> 2) | (((x) & 0x7f00) >> 1) | ((x) & 0x7f)) #define MT32EMU_SYSEXMEMADDR(x) ((((x) & 0x1FC000) << 2) | (((x) & 0x3F80) << 1) | ((x) & 0x7f)) -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) #define MT32EMU_ALIGN_PACKED __declspec(align(1)) #else #define MT32EMU_ALIGN_PACKED __attribute__((packed)) diff --git a/src/sound/nukedopl.c b/src/sound/nukedopl.c deleted file mode 100644 index a2bc192c5..000000000 --- a/src/sound/nukedopl.c +++ /dev/null @@ -1,1387 +0,0 @@ -// -// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// Nuked OPL3 emulator. -// Thanks: -// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): -// Feedback and Rhythm part calculation information. -// forums.submarine.org.uk(carbon14, opl3): -// Tremolo and phase generator calculation information. -// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): -// OPL2 ROMs. -// siliconpr0n.org(John McMaster, digshadow): -// YMF262 and VRC VII decaps and die shots. -// -// version: 1.8 -// - -#include -#include -#include -#include "nukedopl.h" - -#define RSM_FRAC 10 - -// Channel types - -enum { - ch_2op = 0, - ch_4op = 1, - ch_4op2 = 2, - ch_drum = 3 -}; - -// Envelope key types - -enum { - egk_norm = 0x01, - egk_drum = 0x02 -}; - - -// -// logsin table -// - -static const Bit16u logsinrom[256] = { - 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, - 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, - 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, - 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, - 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, - 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, - 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, - 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, - 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, - 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, - 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, - 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, - 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, - 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, - 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, - 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, - 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, - 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, - 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, - 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, - 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, - 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, - 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, - 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, - 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, - 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, - 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, - 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, - 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, - 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, - 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 -}; - -// -// exp table -// - -static const Bit16u exprom[256] = { - 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, - 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, - 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, - 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, - 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, - 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, - 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, - 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, - 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, - 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, - 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, - 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, - 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, - 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, - 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, - 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, - 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, - 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, - 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, - 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, - 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, - 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, - 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, - 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, - 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, - 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, - 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, - 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, - 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, - 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, - 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, - 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 -}; - -// -// freq mult table multiplied by 2 -// -// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 -// - -static const Bit8u mt[16] = { - 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 -}; - -// -// ksl table -// - -static const Bit8u kslrom[16] = { - 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 -}; - -static const Bit8u kslshift[4] = { - 8, 1, 2, 0 -}; - -// -// envelope generator constants -// - -static const Bit8u eg_incstep[4][4] = { - { 0, 0, 0, 0 }, - { 1, 0, 0, 0 }, - { 1, 0, 1, 0 }, - { 1, 1, 1, 0 } -}; - -// -// address decoding -// - -static const Bit8s ad_slot[0x20] = { - 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, - 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static const Bit8u ch_slot[18] = { - 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 -}; - -// -// Envelope generator -// - -typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(struct opl3_slot *slott); - -static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) -{ - if (level > 0x1fff) - { - level = 0x1fff; - } - return (exprom[level & 0xff] << 1) >> (level >> 8); -} - -static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - } - if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x100) - { - out = 0x1000; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if ((phase & 0x300) == 0x100) - { - neg = 0xffff; - } - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x80) - { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else - { - out = logsinrom[(phase << 1) & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x80) - { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else - { - out = logsinrom[(phase << 1) & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) -{ - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - } - return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - phase = (phase & 0x1ff) ^ 0x1ff; - } - out = phase << 3; - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static const envelope_sinfunc envelope_sin[8] = { - OPL3_EnvelopeCalcSin0, - OPL3_EnvelopeCalcSin1, - OPL3_EnvelopeCalcSin2, - OPL3_EnvelopeCalcSin3, - OPL3_EnvelopeCalcSin4, - OPL3_EnvelopeCalcSin5, - OPL3_EnvelopeCalcSin6, - OPL3_EnvelopeCalcSin7 -}; - -enum envelope_gen_num -{ - envelope_gen_num_attack = 0, - envelope_gen_num_decay = 1, - envelope_gen_num_sustain = 2, - envelope_gen_num_release = 3 -}; - -static void OPL3_EnvelopeUpdateKSL(struct opl3_slot *slot) -{ - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - - ((0x08 - slot->channel->block) << 5); - if (ksl < 0) - { - ksl = 0; - } - slot->eg_ksl = (Bit8u)ksl; -} - -static void OPL3_EnvelopeCalc(struct opl3_slot *slot) -{ - Bit8u nonzero; - Bit8u rate; - Bit8u rate_hi; - Bit8u rate_lo; - Bit8u reg_rate = 0; - Bit8u ks; - Bit8u eg_shift, shift; - Bit16u eg_rout; - Bit16s eg_inc; - Bit8u eg_off; - Bit8u reset = 0; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) - + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - if (slot->key && slot->eg_gen == envelope_gen_num_release) - { - reset = 1; - reg_rate = slot->reg_ar; - } - else - { - switch (slot->eg_gen) - { - case envelope_gen_num_attack: - reg_rate = slot->reg_ar; - break; - case envelope_gen_num_decay: - reg_rate = slot->reg_dr; - break; - case envelope_gen_num_sustain: - if (!slot->reg_type) - { - reg_rate = slot->reg_rr; - } - break; - case envelope_gen_num_release: - reg_rate = slot->reg_rr; - break; - } - } - slot->pg_reset = reset; - ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); - nonzero = (reg_rate != 0); - rate = ks + (reg_rate << 2); - rate_hi = rate >> 2; - rate_lo = rate & 0x03; - if (rate_hi & 0x10) - { - rate_hi = 0x0f; - } - eg_shift = rate_hi + slot->chip->eg_add; - shift = 0; - if (nonzero) - { - if (rate_hi < 12) - { - if (slot->chip->eg_state) - { - switch (eg_shift) - { - case 12: - shift = 1; - break; - case 13: - shift = (rate_lo >> 1) & 0x01; - break; - case 14: - shift = rate_lo & 0x01; - break; - default: - break; - } - } - } - else - { - shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; - if (shift & 0x04) - { - shift = 0x03; - } - if (!shift) - { - shift = slot->chip->eg_state; - } - } - } - eg_rout = slot->eg_rout; - eg_inc = 0; - eg_off = 0; - // Instant attack - if (reset && rate_hi == 0x0f) - { - eg_rout = 0x00; - } - // Envelope off - if ((slot->eg_rout & 0x1f8) == 0x1f8) - { - eg_off = 1; - } - if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) - { - eg_rout = 0x1ff; - } - switch (slot->eg_gen) - { - case envelope_gen_num_attack: - if (!slot->eg_rout) - { - slot->eg_gen = envelope_gen_num_decay; - } - else if (slot->key && shift > 0 && rate_hi != 0x0f) - { - eg_inc = ((~slot->eg_rout) << shift) >> 4; - } - break; - case envelope_gen_num_decay: - if ((slot->eg_rout >> 4) == slot->reg_sl) - { - slot->eg_gen = envelope_gen_num_sustain; - } - else if (!eg_off && !reset && shift > 0) - { - eg_inc = 1 << (shift - 1); - } - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - if (!eg_off && !reset && shift > 0) - { - eg_inc = 1 << (shift - 1); - } - break; - } - slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; - // Key off - if (reset) - { - slot->eg_gen = envelope_gen_num_attack; - } - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_release; - } -} - -static void OPL3_EnvelopeKeyOn(struct opl3_slot *slot, Bit8u type) -{ - slot->key |= type; -} - -static void OPL3_EnvelopeKeyOff(struct opl3_slot *slot, Bit8u type) -{ - slot->key &= ~type; -} - -// -// Phase Generator -// - -static void OPL3_PhaseGenerate(struct opl3_slot *slot) -{ - struct opl3_chip *chip; - Bit16u f_num; - Bit32u basefreq; - Bit8u rm_xor, n_bit; - Bit32u noise; - Bit16u phase; - - chip = slot->chip; - f_num = slot->channel->f_num; - if (slot->reg_vib) - { - Bit8s range; - Bit8u vibpos; - - range = (f_num >> 7) & 7; - vibpos = slot->chip->vibpos; - - if (!(vibpos & 3)) - { - range = 0; - } - else if (vibpos & 1) - { - range >>= 1; - } - range >>= slot->chip->vibshift; - - if (vibpos & 4) - { - range = -range; - } - f_num += range; - } - basefreq = (f_num << slot->channel->block) >> 1; - phase = (Bit16u)(slot->pg_phase >> 9); - if (slot->pg_reset) - { - slot->pg_phase = 0; - } - slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; - // Rhythm mode - noise = chip->noise; - slot->pg_phase_out = phase; - if (slot->slot_num == 13) // hh - { - chip->rm_hh_bit2 = (phase >> 2) & 1; - chip->rm_hh_bit3 = (phase >> 3) & 1; - chip->rm_hh_bit7 = (phase >> 7) & 1; - chip->rm_hh_bit8 = (phase >> 8) & 1; - } - if (slot->slot_num == 17 && (chip->rhy & 0x20)) // tc - { - chip->rm_tc_bit3 = (phase >> 3) & 1; - chip->rm_tc_bit5 = (phase >> 5) & 1; - } - if (chip->rhy & 0x20) - { - rm_xor = (chip->rm_hh_bit2 ^ chip->rm_hh_bit7) - | (chip->rm_hh_bit3 ^ chip->rm_tc_bit5) - | (chip->rm_tc_bit3 ^ chip->rm_tc_bit5); - switch (slot->slot_num) - { - case 13: // hh - slot->pg_phase_out = rm_xor << 9; - if (rm_xor ^ (noise & 1)) - { - slot->pg_phase_out |= 0xd0; - } - else - { - slot->pg_phase_out |= 0x34; - } - break; - case 16: // sd - slot->pg_phase_out = (chip->rm_hh_bit8 << 9) - | ((chip->rm_hh_bit8 ^ (noise & 1)) << 8); - break; - case 17: // tc - slot->pg_phase_out = (rm_xor << 9) | 0x80; - break; - default: - break; - } - } - n_bit = ((noise >> 14) ^ noise) & 0x01; - chip->noise = (noise >> 1) | (n_bit << 22); -} - -// -// Slot -// - -static void OPL3_SlotWrite20(struct opl3_slot *slot, Bit8u data) -{ - if ((data >> 7) & 0x01) - { - slot->trem = &slot->chip->tremolo; - } - else - { - slot->trem = (Bit8u*)&slot->chip->zeromod; - } - slot->reg_vib = (data >> 6) & 0x01; - slot->reg_type = (data >> 5) & 0x01; - slot->reg_ksr = (data >> 4) & 0x01; - slot->reg_mult = data & 0x0f; -} - -static void OPL3_SlotWrite40(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_ksl = (data >> 6) & 0x03; - slot->reg_tl = data & 0x3f; - OPL3_EnvelopeUpdateKSL(slot); -} - -static void OPL3_SlotWrite60(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_ar = (data >> 4) & 0x0f; - slot->reg_dr = data & 0x0f; -} - -static void OPL3_SlotWrite80(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_sl = (data >> 4) & 0x0f; - if (slot->reg_sl == 0x0f) - { - slot->reg_sl = 0x1f; - } - slot->reg_rr = data & 0x0f; -} - -static void OPL3_SlotWriteE0(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_wf = data & 0x07; - if (slot->chip->newm == 0x00) - { - slot->reg_wf &= 0x03; - } -} - -static void OPL3_SlotGenerate(struct opl3_slot *slot) -{ - slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); -} - -static void OPL3_SlotCalcFB(struct opl3_slot *slot) -{ - if (slot->channel->fb != 0x00) - { - slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); - } - else - { - slot->fbmod = 0; - } - slot->prout = slot->out; -} - -// -// Channel -// - -static void OPL3_ChannelSetupAlg(struct opl3_channel *channel); - -static void OPL3_ChannelUpdateRhythm(struct opl3_chip *chip, Bit8u data) -{ - struct opl3_channel *channel6; - struct opl3_channel *channel7; - struct opl3_channel *channel8; - Bit8u chnum; - - chip->rhy = data & 0x3f; - if (chip->rhy & 0x20) - { - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - channel6->out[0] = &channel6->slots[1]->out; - channel6->out[1] = &channel6->slots[1]->out; - channel6->out[2] = &chip->zeromod; - channel6->out[3] = &chip->zeromod; - channel7->out[0] = &channel7->slots[0]->out; - channel7->out[1] = &channel7->slots[0]->out; - channel7->out[2] = &channel7->slots[1]->out; - channel7->out[3] = &channel7->slots[1]->out; - channel8->out[0] = &channel8->slots[0]->out; - channel8->out[1] = &channel8->slots[0]->out; - channel8->out[2] = &channel8->slots[1]->out; - channel8->out[3] = &channel8->slots[1]->out; - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_drum; - } - OPL3_ChannelSetupAlg(channel6); - OPL3_ChannelSetupAlg(channel7); - OPL3_ChannelSetupAlg(channel8); - //hh - if (chip->rhy & 0x01) - { - OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); - } - //tc - if (chip->rhy & 0x02) - { - OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); - } - //tom - if (chip->rhy & 0x04) - { - OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); - } - //sd - if (chip->rhy & 0x08) - { - OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); - } - //bd - if (chip->rhy & 0x10) - { - OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); - OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); - OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); - } - } - else - { - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_2op; - OPL3_ChannelSetupAlg(&chip->channel[chnum]); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum); - } - } -} - -static void OPL3_ChannelWriteA0(struct opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0x300) | data; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); - } -} - -static void OPL3_ChannelWriteB0(struct opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); - channel->block = (data >> 2) & 0x07; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->block = channel->block; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); - } -} - -static void OPL3_ChannelSetupAlg(struct opl3_channel *channel) -{ - if (channel->chtype == ch_drum) - { - if (channel->ch_num == 7 || channel->ch_num == 8) - { - channel->slots[0]->mod = &channel->chip->zeromod; - channel->slots[1]->mod = &channel->chip->zeromod; - return; - } - switch (channel->alg & 0x01) - { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - break; - } - return; - } - if (channel->alg & 0x08) - { - return; - } - if (channel->alg & 0x04) - { - channel->pair->out[0] = &channel->chip->zeromod; - channel->pair->out[1] = &channel->chip->zeromod; - channel->pair->out[2] = &channel->chip->zeromod; - channel->pair->out[3] = &channel->chip->zeromod; - switch (channel->alg & 0x03) - { - case 0x00: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->chip->zeromod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[1]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x02: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x03: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[0]->out; - channel->out[2] = &channel->slots[1]->out; - channel->out[3] = &channel->chip->zeromod; - break; - } - } - else - { - switch (channel->alg & 0x01) - { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - } - } -} - -static void OPL3_ChannelWriteC0(struct opl3_channel *channel, Bit8u data) -{ - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; - channel->alg = channel->con; - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); - channel->alg = 0x08; - OPL3_ChannelSetupAlg(channel->pair); - } - else if (channel->chtype == ch_4op2) - { - channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); - channel->pair->alg = 0x08; - OPL3_ChannelSetupAlg(channel); - } - else - { - OPL3_ChannelSetupAlg(channel); - } - } - else - { - OPL3_ChannelSetupAlg(channel); - } - if (channel->chip->newm) - { - channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; - channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; - } - else - { - channel->cha = channel->chb = (Bit16u)~0; - } -} - -static void OPL3_ChannelKeyOn(struct opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); - } -} - -static void OPL3_ChannelKeyOff(struct opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); - } -} - -static void OPL3_ChannelSet4Op(struct opl3_chip *chip, Bit8u data) -{ - Bit8u bit; - Bit8u chnum; - for (bit = 0; bit < 6; bit++) - { - chnum = bit; - if (bit >= 3) - { - chnum += 9 - 3; - } - if ((data >> bit) & 0x01) - { - chip->channel[chnum].chtype = ch_4op; - chip->channel[chnum + 3].chtype = ch_4op2; - } - else - { - chip->channel[chnum].chtype = ch_2op; - chip->channel[chnum + 3].chtype = ch_2op; - } - } -} - -static Bit16s OPL3_ClipSample(Bit32s sample) -{ - if (sample > 32767) - { - sample = 32767; - } - else if (sample < -32768) - { - sample = -32768; - } - return (Bit16s)sample; -} - -void OPL3_Generate(struct opl3_chip *chip, Bit16s *buf) -{ - Bit8u ii; - Bit8u jj; - Bit16s accm; - Bit8u shift = 0; - - buf[1] = OPL3_ClipSample(chip->mixbuff[1]); - - for (ii = 0; ii < 15; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - chip->mixbuff[0] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); - } - - for (ii = 15; ii < 18; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - buf[0] = OPL3_ClipSample(chip->mixbuff[0]); - - for (ii = 18; ii < 33; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - chip->mixbuff[1] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); - } - - for (ii = 33; ii < 36; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - if ((chip->timer & 0x3f) == 0x3f) - { - chip->tremolopos = (chip->tremolopos + 1) % 210; - } - if (chip->tremolopos < 105) - { - chip->tremolo = chip->tremolopos >> chip->tremoloshift; - } - else - { - chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; - } - - if ((chip->timer & 0x3ff) == 0x3ff) - { - chip->vibpos = (chip->vibpos + 1) & 7; - } - - chip->timer++; - - chip->eg_add = 0; - if (chip->eg_timer) - { - while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) - { - shift++; - } - if (shift > 12) - { - chip->eg_add = 0; - } - else - { - chip->eg_add = shift + 1; - } - } - - if (chip->eg_timerrem || chip->eg_state) - { - if (chip->eg_timer == 0xfffffffff) - { - chip->eg_timer = 0; - chip->eg_timerrem = 1; - } - else - { - chip->eg_timer++; - chip->eg_timerrem = 0; - } - } - - chip->eg_state ^= 1; - - while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) - { - if (!(chip->writebuf[chip->writebuf_cur].reg & 0x200)) - { - break; - } - chip->writebuf[chip->writebuf_cur].reg &= 0x1ff; - OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, - chip->writebuf[chip->writebuf_cur].data); - chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; - } - chip->writebuf_samplecnt++; -} - -void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf) -{ - while (chip->samplecnt >= chip->rateratio) - { - chip->oldsamples[0] = chip->samples[0]; - chip->oldsamples[1] = chip->samples[1]; - OPL3_Generate(chip, chip->samples); - chip->samplecnt -= chip->rateratio; - } - buf[0] = (Bit32s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) - + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (Bit32s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) - + chip->samples[1] * chip->samplecnt) / chip->rateratio); - chip->samplecnt += 1 << RSM_FRAC; -} - -void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate) -{ - Bit8u slotnum; - Bit8u channum; - - memset(chip, 0, sizeof(struct opl3_chip)); - for (slotnum = 0; slotnum < 36; slotnum++) - { - chip->slot[slotnum].chip = chip; - chip->slot[slotnum].mod = &chip->zeromod; - chip->slot[slotnum].eg_rout = 0x1ff; - chip->slot[slotnum].eg_out = 0x1ff; - chip->slot[slotnum].eg_gen = envelope_gen_num_release; - chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; - chip->slot[slotnum].slot_num = slotnum; - } - for (channum = 0; channum < 18; channum++) - { - chip->channel[channum].slots[0] = &chip->slot[ch_slot[channum]]; - chip->channel[channum].slots[1] = &chip->slot[ch_slot[channum] + 3]; - chip->slot[ch_slot[channum]].channel = &chip->channel[channum]; - chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum]; - if ((channum % 9) < 3) - { - chip->channel[channum].pair = &chip->channel[channum + 3]; - } - else if ((channum % 9) < 6) - { - chip->channel[channum].pair = &chip->channel[channum - 3]; - } - chip->channel[channum].chip = chip; - chip->channel[channum].out[0] = &chip->zeromod; - chip->channel[channum].out[1] = &chip->zeromod; - chip->channel[channum].out[2] = &chip->zeromod; - chip->channel[channum].out[3] = &chip->zeromod; - chip->channel[channum].chtype = ch_2op; - chip->channel[channum].cha = 0xffff; - chip->channel[channum].chb = 0xffff; - chip->channel[channum].ch_num = channum; - OPL3_ChannelSetupAlg(&chip->channel[channum]); - } - chip->noise = 1; - chip->rateratio = (samplerate << RSM_FRAC) / 49716; - chip->tremoloshift = 4; - chip->vibshift = 1; -} - -Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val) -{ - Bit16u addr; - addr = val; - if ((port & 2) && (addr == 0x05 || chip->newm)) { - addr |= 0x100; - } - return addr; -} - -void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - switch (regm & 0xf0) - { - case 0x00: - if (high) - { - switch (regm & 0x0f) - { - case 0x04: - OPL3_ChannelSet4Op(chip, v); - break; - case 0x05: - chip->newm = v & 0x01; - break; - } - } - else - { - switch (regm & 0x0f) - { - case 0x08: - chip->nts = (v >> 6) & 0x01; - break; - } - } - break; - case 0x20: - case 0x30: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x40: - case 0x50: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x60: - case 0x70: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x80: - case 0x90: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xe0: - case 0xf0: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xa0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - case 0xb0: - if (regm == 0xbd && !high) - { - chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; - chip->vibshift = ((v >> 6) & 0x01) ^ 1; - OPL3_ChannelUpdateRhythm(chip, v); - } - else if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); - if (v & 0x20) - { - OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); - } - else - { - OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); - } - } - break; - case 0xc0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - } -} - -void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit64u time1, time2; - - if (chip->writebuf[chip->writebuf_last].reg & 0x200) - { - OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_last].reg & 0x1ff, - chip->writebuf[chip->writebuf_last].data); - - chip->writebuf_cur = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; - chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; - } - - chip->writebuf[chip->writebuf_last].reg = reg | 0x200; - chip->writebuf[chip->writebuf_last].data = v; - time1 = chip->writebuf_lasttime + OPL_WRITEBUF_DELAY; - time2 = chip->writebuf_samplecnt; - - if (time1 < time2) - { - time1 = time2; - } - - chip->writebuf[chip->writebuf_last].time = time1; - chip->writebuf_lasttime = time1; - chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; -} - -void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples) -{ - Bit32u i; - - for(i = 0; i < numsamples; i++) - { - OPL3_GenerateResampled(chip, sndptr); - sndptr += 2; - } -} diff --git a/src/sound/openal.c b/src/sound/openal.c index 39819f591..2153d4c2b 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -1,109 +1,105 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Interface to the OpenAL sound processing library. + * Interface to the OpenAL sound processing library. * * * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Sarah Walker, + * Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include -#include #include -#include +#include #include +#include #include -# undef AL_API -# undef ALC_API -# define AL_LIBTYPE_STATIC -# define ALC_LIBTYPE_STATIC -# include -# include -# include +#undef AL_API +#undef ALC_API +#define AL_LIBTYPE_STATIC +#define ALC_LIBTYPE_STATIC + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" #include <86box/86box.h> -#include <86box/sound.h> #include <86box/midi.h> +#include <86box/sound.h> +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN -#define FREQ 48000 -#define BUFLEN SOUNDBUFLEN +ALuint buffers[4]; /* front and back buffers */ +ALuint buffers_cd[4]; /* front and back buffers */ +ALuint buffers_midi[4]; /* front and back buffers */ +static ALuint source[3]; /* audio source */ - -ALuint buffers[4]; /* front and back buffers */ -ALuint buffers_cd[4]; /* front and back buffers */ -ALuint buffers_midi[4]; /* front and back buffers */ -static ALuint source[3]; /* audio source */ - - -static int midi_freq = 44100; -static int midi_buf_size = 4410; -static int initialized = 0; -static int sources = 2; +static int midi_freq = 44100; +static int midi_buf_size = 4410; +static int initialized = 0; +static int sources = 2; static ALCcontext *Context; -static ALCdevice *Device; +static ALCdevice *Device; void al_set_midi(int freq, int buf_size) { - midi_freq = freq; + midi_freq = freq; midi_buf_size = buf_size; } - void closeal(void); -ALvoid alutInit(ALint *argc,ALbyte **argv) +ALvoid +alutInit(ALint *argc, ALbyte **argv) { /* Open device */ - Device = alcOpenDevice((ALCchar *)""); + Device = alcOpenDevice((ALCchar *) ""); if (Device != NULL) { - /* Create context(s) */ - Context = alcCreateContext(Device, NULL); - if (Context != NULL) { - /* Set active context */ - alcMakeContextCurrent(Context); - } + /* Create context(s) */ + Context = alcCreateContext(Device, NULL); + if (Context != NULL) { + /* Set active context */ + alcMakeContextCurrent(Context); + } } } - ALvoid -alutExit(ALvoid) +alutExit(ALvoid) { if (Context != NULL) { - /* Disable context */ - alcMakeContextCurrent(NULL); + /* Disable context */ + alcMakeContextCurrent(NULL); - /* Release context(s) */ - alcDestroyContext(Context); + /* Release context(s) */ + alcDestroyContext(Context); - if (Device != NULL) { - /* Close device */ - alcCloseDevice(Device); - } + if (Device != NULL) { + /* Close device */ + alcCloseDevice(Device); + } } } - void closeal(void) { if (!initialized) - return; + return; alSourceStopv(sources, source); alDeleteSources(sources, source); if (sources == 3) - alDeleteBuffers(4, buffers_midi); + alDeleteBuffers(4, buffers_midi); alDeleteBuffers(4, buffers_cd); alDeleteBuffers(4, buffers); @@ -112,168 +108,163 @@ closeal(void) initialized = 0; } - void inital(void) { - float *buf = NULL, *cd_buf = NULL, *midi_buf = NULL; + float *buf = NULL, *cd_buf = NULL, *midi_buf = NULL; int16_t *buf_int16 = NULL, *cd_buf_int16 = NULL, *midi_buf_int16 = NULL; - int c; + int c; char *mdn; - int init_midi = 0; + int init_midi = 0; if (initialized) - return; + return; alutInit(0, 0); atexit(closeal); - mdn = midi_device_get_internal_name(midi_device_current); + mdn = midi_out_device_get_internal_name(midi_output_device_current); if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) - init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the - MIDI buffer and source, otherwise, do not. */ + init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the + MIDI buffer and source, otherwise, do not. */ sources = 2 + !!init_midi; if (sound_is_float) { - buf = (float *) malloc((BUFLEN << 1) * sizeof(float)); - cd_buf = (float *) malloc((CD_BUFLEN << 1) * sizeof(float)); - if (init_midi) - midi_buf = (float *) malloc(midi_buf_size * sizeof(float)); + buf = (float *) calloc((BUFLEN << 1), sizeof(float)); + cd_buf = (float *) calloc((CD_BUFLEN << 1), sizeof(float)); + if (init_midi) + midi_buf = (float *) calloc(midi_buf_size, sizeof(float)); } else { - buf_int16 = (int16_t *) malloc((BUFLEN << 1) * sizeof(int16_t)); - cd_buf_int16 = (int16_t *) malloc((CD_BUFLEN << 1) * sizeof(int16_t)); - if (init_midi) - midi_buf_int16 = (int16_t *) malloc(midi_buf_size * sizeof(int16_t)); + buf_int16 = (int16_t *) calloc((BUFLEN << 1), sizeof(int16_t)); + cd_buf_int16 = (int16_t *) calloc((CD_BUFLEN << 1), sizeof(int16_t)); + if (init_midi) + midi_buf_int16 = (int16_t *) calloc(midi_buf_size, sizeof(int16_t)); } alGenBuffers(4, buffers); alGenBuffers(4, buffers_cd); if (init_midi) - alGenBuffers(4, buffers_midi); + alGenBuffers(4, buffers_midi); if (init_midi) - alGenSources(3, source); + alGenSources(3, source); else - alGenSources(2, source); + alGenSources(2, source); - alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); - alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); - alSourcef (source[0], AL_ROLLOFF_FACTOR, 0.0 ); - alSourcei (source[0], AL_SOURCE_RELATIVE, AL_TRUE ); - alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); - alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); - alSourcef (source[1], AL_ROLLOFF_FACTOR, 0.0 ); - alSourcei (source[1], AL_SOURCE_RELATIVE, AL_TRUE ); + alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef(source[0], AL_ROLLOFF_FACTOR, 0.0); + alSourcei(source[0], AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef(source[1], AL_ROLLOFF_FACTOR, 0.0); + alSourcei(source[1], AL_SOURCE_RELATIVE, AL_TRUE); if (init_midi) { - alSource3f(source[2], AL_POSITION, 0.0, 0.0, 0.0); - alSource3f(source[2], AL_VELOCITY, 0.0, 0.0, 0.0); - alSource3f(source[2], AL_DIRECTION, 0.0, 0.0, 0.0); - alSourcef (source[2], AL_ROLLOFF_FACTOR, 0.0 ); - alSourcei (source[2], AL_SOURCE_RELATIVE, AL_TRUE ); + alSource3f(source[2], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[2], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[2], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef(source[2], AL_ROLLOFF_FACTOR, 0.0); + alSourcei(source[2], AL_SOURCE_RELATIVE, AL_TRUE); } if (sound_is_float) { - memset(buf,0,BUFLEN*2*sizeof(float)); - memset(cd_buf,0,BUFLEN*2*sizeof(float)); - if (init_midi) - memset(midi_buf,0,midi_buf_size*sizeof(float)); + memset(buf, 0, BUFLEN * 2 * sizeof(float)); + memset(cd_buf, 0, BUFLEN * 2 * sizeof(float)); + if (init_midi) + memset(midi_buf, 0, midi_buf_size * sizeof(float)); } else { - memset(buf_int16,0,BUFLEN*2*sizeof(int16_t)); - memset(cd_buf_int16,0,BUFLEN*2*sizeof(int16_t)); - if (init_midi) - memset(midi_buf_int16,0,midi_buf_size*sizeof(int16_t)); + memset(buf_int16, 0, BUFLEN * 2 * sizeof(int16_t)); + memset(cd_buf_int16, 0, BUFLEN * 2 * sizeof(int16_t)); + if (init_midi) + memset(midi_buf_int16, 0, midi_buf_size * sizeof(int16_t)); } - for (c=0; c<4; c++) { - if (sound_is_float) { - alBufferData(buffers[c], AL_FORMAT_STEREO_FLOAT32, buf, BUFLEN*2*sizeof(float), FREQ); - alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN*2*sizeof(float), CD_FREQ); - if (init_midi) - alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size*sizeof(float), midi_freq); - } else { - alBufferData(buffers[c], AL_FORMAT_STEREO16, buf_int16, BUFLEN*2*sizeof(int16_t), FREQ); - alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN*2*sizeof(int16_t), CD_FREQ); - if (init_midi) - alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size*sizeof(int16_t), midi_freq); - } + for (c = 0; c < 4; c++) { + if (sound_is_float) { + alBufferData(buffers[c], AL_FORMAT_STEREO_FLOAT32, buf, BUFLEN * 2 * sizeof(float), FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN * 2 * sizeof(float), CD_FREQ); + if (init_midi) + alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size * sizeof(float), midi_freq); + } else { + alBufferData(buffers[c], AL_FORMAT_STEREO16, buf_int16, BUFLEN * 2 * sizeof(int16_t), FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN * 2 * sizeof(int16_t), CD_FREQ); + if (init_midi) + alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size * sizeof(int16_t), midi_freq); + } } alSourceQueueBuffers(source[0], 4, buffers); alSourceQueueBuffers(source[1], 4, buffers_cd); if (init_midi) - alSourceQueueBuffers(source[2], 4, buffers_midi); + alSourceQueueBuffers(source[2], 4, buffers_midi); alSourcePlay(source[0]); alSourcePlay(source[1]); if (init_midi) - alSourcePlay(source[2]); + alSourcePlay(source[2]); if (sound_is_float) { - if (init_midi) - free(midi_buf); - free(cd_buf); - free(buf); + if (init_midi) + free(midi_buf); + free(cd_buf); + free(buf); } else { - if (init_midi) - free(midi_buf_int16); - free(cd_buf_int16); - free(buf_int16); + if (init_midi) + free(midi_buf_int16); + free(cd_buf_int16); + free(buf_int16); } initialized = 1; } - void givealbuffer_common(void *buf, uint8_t src, int size, int freq) { - int processed; - int state; + int processed; + int state; ALuint buffer; double gain; if (!initialized) - return; + return; alGetSourcei(source[src], AL_SOURCE_STATE, &state); if (state == 0x1014) { - alSourcePlay(source[src]); + alSourcePlay(source[src]); } alGetSourcei(source[src], AL_BUFFERS_PROCESSED, &processed); if (processed >= 1) { - gain = pow(10.0, (double)sound_gain / 20.0); - alListenerf(AL_GAIN, gain); + gain = pow(10.0, (double) sound_gain / 20.0); + alListenerf(AL_GAIN, gain); - alSourceUnqueueBuffers(source[src], 1, &buffer); + alSourceUnqueueBuffers(source[src], 1, &buffer); - if (sound_is_float) - alBufferData(buffer, AL_FORMAT_STEREO_FLOAT32, buf, size * sizeof(float), freq); - else - alBufferData(buffer, AL_FORMAT_STEREO16, buf, size * sizeof(int16_t), freq); + if (sound_is_float) + alBufferData(buffer, AL_FORMAT_STEREO_FLOAT32, buf, size * sizeof(float), freq); + else + alBufferData(buffer, AL_FORMAT_STEREO16, buf, size * sizeof(int16_t), freq); - alSourceQueueBuffers(source[src], 1, &buffer); + alSourceQueueBuffers(source[src], 1, &buffer); } } - void givealbuffer(void *buf) { givealbuffer_common(buf, 0, BUFLEN << 1, FREQ); } - void givealbuffer_cd(void *buf) { givealbuffer_common(buf, 1, CD_BUFLEN << 1, CD_FREQ); } - void givealbuffer_midi(void *buf, uint32_t size) { diff --git a/src/sound/resid-fp/CMakeLists.txt b/src/sound/resid-fp/CMakeLists.txt new file mode 100644 index 000000000..fb9b5396e --- /dev/null +++ b/src/sound/resid-fp/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(resid-fp STATIC convolve-sse.cc convolve.cc envelope.cc extfilt.cc + filter.cc pot.cc sid.cc voice.cc wave.cc wave6581_PST.cc + wave6581_PS_.cc wave6581_P_T.cc wave6581__ST.cc wave8580_PST.cc + wave8580_PS_.cc wave8580_P_T.cc wave8580__ST.cc) \ No newline at end of file diff --git a/src/sound/resid-fp/envelope.h b/src/sound/resid-fp/envelope.h index 556e71a47..af0764ccd 100644 --- a/src/sound/resid-fp/envelope.h +++ b/src/sound/resid-fp/envelope.h @@ -130,7 +130,7 @@ void EnvelopeGeneratorFP::clock() --envelope_counter &= 0xff; break; } - + // Check for change of exponential counter period. switch (envelope_counter) { case 0xff: diff --git a/src/sound/resid-fp/filter.h b/src/sound/resid-fp/filter.h index 13e6aa67e..9ca254564 100644 --- a/src/sound/resid-fp/filter.h +++ b/src/sound/resid-fp/filter.h @@ -57,7 +57,7 @@ // // SID filter // ---------- -// +// // ----------------------------------------------- // | | // | ---Rq-- | @@ -66,15 +66,15 @@ // | | | | // | | ---C---| ---C---| // | | | | | | -// | --R1-- ---R1-- |---Rs--| |---Rs--| +// | --R1-- ---R1-- |---Rs--| |---Rs--| // | | | | | | | | // ----R1--|-----[A>--|--R-----[A>--|--R-----[A>--| // | | | | // vi -----R1-- | | | -// +// // vhp vbp vlp -// -// +// +// // vi - input voltage // vhp - highpass output // vbp - bandpass output @@ -85,14 +85,14 @@ // R - NMOS FET voltage controlled resistor controlling cutoff frequency // Rs - shunt resitor // C - capacitor -// -// -// +// +// +// // SID integrator // -------------- -// +// // V+ -// +// // | // | // -----| @@ -114,7 +114,7 @@ // R1 V- // | // | -// +// // Vw // // ---------------------------------------------------------------------------- @@ -312,7 +312,7 @@ float FilterFP::clock(float voice1, else if (! voice3off) Vnf += voice3; ((filt & 8) ? Vi : Vnf) += ext_in; - + if (! enabled) return (Vnf - Vi) * volf; @@ -322,7 +322,7 @@ float FilterFP::clock(float voice1, Vf += Vbp; if (hp_bp_lp & 4) Vf += Vhp; - + if (model == MOS6581FP) { float diff1, diff2; @@ -345,7 +345,7 @@ float FilterFP::clock(float voice1, Vbp += (Vf + Vnf - Vbp) * distortion_cf_threshold; if (hp_bp_lp & 4) Vhp += (Vf + Vnf - Vhp) * distortion_cf_threshold; - + /* Simulating the exponential VCR that the FET block is... */ Vlp -= Vbp * type3_w0(Vbp, type3_fc_distortion_offset_bp); Vbp -= Vhp * type3_w0(Vhp, type3_fc_distortion_offset_hp) * outputleveldifference_bp_hp; @@ -354,7 +354,7 @@ float FilterFP::clock(float voice1, * discontinuity but a saturation effect... */ if (Vnf > 3.2e6f) Vnf = 3.2e6f; - + Vf += Vnf + Vlp * (outputleveldifference_lp_bp - 1.f); } else { /* On the 8580, BP appears mixed in phase with the rest. */ @@ -364,7 +364,7 @@ float FilterFP::clock(float voice1, Vf += Vnf; } - + return Vf * volf; } diff --git a/src/sound/resid-fp/sid.cc b/src/sound/resid-fp/sid.cc index 431d5712d..6f7544423 100644 --- a/src/sound/resid-fp/sid.cc +++ b/src/sound/resid-fp/sid.cc @@ -29,7 +29,7 @@ enum host_cpu_feature { }; /* This code is appropriate for 32-bit and 64-bit x86 CPUs. */ -#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) +#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || (defined(_M_X64) && !(defined(_MSC_VER) && !defined(__clang__))) struct cpu_x86_regs_s { unsigned int eax; @@ -43,7 +43,7 @@ static cpu_x86_regs_t get_cpuid_regs(unsigned int index) { cpu_x86_regs_t retval; -#if defined(_MSC_VER) /* MSVC assembly */ +#if defined(_MSC_VER) && !defined(__clang__) /* MSVC assembly */ __asm { mov eax, [index] cpuid diff --git a/src/sound/resid-fp/sid.h b/src/sound/resid-fp/sid.h index 6dad2e0c4..5180898fb 100644 --- a/src/sound/resid-fp/sid.h +++ b/src/sound/resid-fp/sid.h @@ -47,7 +47,7 @@ public: void clock(); int clock(cycle_count& delta_t, short* buf, int n, int interleave = 1); void reset(); - + // Read/write registers. reg8 read(reg8 offset); void write(reg8 offset, reg8 value); @@ -73,7 +73,7 @@ public: EnvelopeGeneratorFP::State envelope_state[3]; bool hold_zero[3]; }; - + State read_state(); void write_state(const State& state); @@ -114,7 +114,7 @@ protected: int sample_index; int fir_N; int fir_RES; - + // Linear interpolation helper float sample_prev; diff --git a/src/sound/resid-fp/siddefs-fp.h b/src/sound/resid-fp/siddefs-fp.h index 1f3f72715..fb10d5dff 100644 --- a/src/sound/resid-fp/siddefs-fp.h +++ b/src/sound/resid-fp/siddefs-fp.h @@ -74,7 +74,7 @@ const char* resid_version_string = VERSION; // Inlining on/off. #define RESID_INLINE inline -#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) +#if defined(__SSE__) || (defined(_M_IX86_FP ) && _M_IX86_FP >= 1) || defined(_M_X64) #define RESID_USE_SSE 1 #else #define RESID_USE_SSE 0 diff --git a/src/sound/resid-fp/wave.h b/src/sound/resid-fp/wave.h index 07d229ba0..64684228b 100644 --- a/src/sound/resid-fp/wave.h +++ b/src/sound/resid-fp/wave.h @@ -269,7 +269,7 @@ reg12 WaveformGeneratorFP::outputN___() // in the output. The reason for this has not been determined. // // Example: -// +// // 1 1 // Bit # 1 0 9 8 7 6 5 4 3 2 1 0 // ----------------------- @@ -303,14 +303,14 @@ reg12 WaveformGeneratorFP::outputN___() // // Sawtooth+Triangle: // The sawtooth output is used to look up an OSC3 sample. -// +// // Pulse+Triangle: // The triangle output is right-shifted and used to look up an OSC3 sample. // The sample is output if the pulse output is on. // The reason for using the triangle output as the index is to handle ring // modulation. Only the first half of the sample is used, which should be OK // since the triangle waveform has half the resolution of the accumulator. -// +// // Pulse+Sawtooth: // The sawtooth output is used to look up an OSC3 sample. // The sample is output if the pulse output is on. @@ -318,7 +318,7 @@ reg12 WaveformGeneratorFP::outputN___() // Pulse+Sawtooth+Triangle: // The sawtooth output is used to look up an OSC3 sample. // The sample is output if the pulse output is on. -// +// RESID_INLINE reg12 WaveformGeneratorFP::output__ST() { diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c new file mode 100644 index 000000000..348989180 --- /dev/null +++ b/src/sound/snd_ac97_codec.c @@ -0,0 +1,753 @@ +/* + * 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. + * + * AC'97 audio codec emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/snd_ac97.h> + +static const struct { + const uint32_t vendor_id, min_rate, max_rate, misc_flags; /* definitions for misc_flags in snd_ac97.h */ + const uint16_t reset_flags, extid_flags, /* definitions in snd_ac97.h */ + powerdown_mask; /* bits [7:0] => register 26 bits [15:8]; bits [11:8] => register 2A bits [14:11] */ + const ac97_vendor_reg_t *vendor_regs; /* bits [11:8] of index are the page number if applicable (registers [60:6F]) */ + const device_t *device; +} ac97_codecs[] = { + // clang-format off + [AC97_CODEC_AD1881] = { + .vendor_id = AC97_VENDOR_ID('A', 'D', 'S', 0x40), + .min_rate = 7000, + .max_rate = 48000, + .misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_POP | AC97_MS | AC97_LPBK, + .reset_flags = (1 << AC97_3D_SHIFT), /* datasheet contradicts itself on AC97_HPOUT */ + .extid_flags = AC97_VRA, + .powerdown_mask = 0x0bf, + .vendor_regs = (const ac97_vendor_reg_t[]) {{0x74, 0x0000, 0xff07}, {0x76, 0x0404, 0xdde5}, {0x78, 48000, 0x0000}, {0x7a, 48000, 0x0000}, {0}}, + .device = &ad1881_device + }, + [AC97_CODEC_AK4540] = { + .vendor_id = AC97_VENDOR_ID('A', 'K', 'M', 0x00), + .misc_flags = AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .powerdown_mask = 0x01f, + .device = &ak4540_device + }, + [AC97_CODEC_ALC100] = { + .vendor_id = AC97_VENDOR_ID('A', 'L', 'C', 0x20), + .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_POP | AC97_MS | AC97_LPBK, + .reset_flags = (22 << AC97_3D_SHIFT), + .extid_flags = AC97_AMAP, + .powerdown_mask = 0x0bf, + .device = &alc100_device + }, + [AC97_CODEC_CS4297] = { + .vendor_id = AC97_VENDOR_ID('C', 'R', 'Y', 0x03), + .misc_flags = AC97_MASTER_6B | AC97_AUXOUT | AC97_AUXOUT_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = AC97_HPOUT | AC97_DAC_18B | AC97_ADC_18B, + .extid_flags = 0, + .powerdown_mask = 0x07f, + .vendor_regs = (const ac97_vendor_reg_t[]) {{0x5a, 0x0301, 0x0000}, {0}}, + .device = &cs4297_device + }, + [AC97_CODEC_CS4297A] = { + .vendor_id = AC97_VENDOR_ID('C', 'R', 'Y', 0x11), + .misc_flags = AC97_MASTER_6B | AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = AC97_HPOUT | AC97_DAC_20B | AC97_ADC_18B | (6 << AC97_3D_SHIFT), + .extid_flags = AC97_AMAP, + .powerdown_mask = 0x0ff, + .vendor_regs = (const ac97_vendor_reg_t[]) {{0x5e, 0x0000, 0x01b0}, {0x60, 0x0023, 0x0001}, {0x68, 0x0000, 0xdfff}, {0}}, + .device = &cs4297a_device + }, + [AC97_CODEC_STAC9708] = { + .vendor_id = AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x08), + .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = (26 << AC97_3D_SHIFT) | AC97_DAC_18B | AC97_ADC_18B, + .extid_flags = AC97_SDAC, + .powerdown_mask = 0x2ff, + .vendor_regs = (const ac97_vendor_reg_t []) {{0x6c, 0x0000, 0x0003}, {0x74, 0x0000, 0x0003}, {0}}, + .device = &stac9708_device + }, + [AC97_CODEC_STAC9721] = { + .vendor_id = AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x09), + .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = (26 << AC97_3D_SHIFT) | AC97_DAC_18B | AC97_ADC_18B, + .extid_flags = AC97_AMAP, + .powerdown_mask = 0x0ff, + .vendor_regs = (const ac97_vendor_reg_t []) {{0x6c, 0x0000, 0x0000}, {0x6e, 0x0000, 0x0003}, {0x70, 0x0000, 0xffff}, {0x72, 0x0000, 0x0006}, {0x74, 0x0000, 0x0003}, {0x76, 0x0000, 0xffff}, {0x78, 0x0000, 0x3802}, {0}}, + .device = &stac9721_device + }, + [AC97_CODEC_WM9701A] = { + .vendor_id = AC97_VENDOR_ID('W', 'M', 'L', 0x00), + .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = AC97_DAC_18B | AC97_ADC_18B, + .extid_flags = 0, + .powerdown_mask = 0x03f, + .device = &wm9701a_device + } + // clang-format on +}; + +#ifdef ENABLE_AC97_CODEC_LOG +int ac97_codec_do_log = ENABLE_AC97_CODEC_LOG; + +static void +ac97_codec_log(const char *fmt, ...) +{ + va_list ap; + + if (ac97_codec_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define ac97_codec_log(fmt, ...) +#endif + +static const int32_t codec_attn[] = { + // clang-format off + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, + 25, 32, 41, 51, 65, 82, 103, 130, 164, 206, 260, 327, 412, 519, 653, 822, + 1036, 1304, 1641, 2067, 2602, 3276, 4125, 5192, 6537, 8230, 10362, 13044, 16422, 20674, 26027, 32767, + 41305, 52068, 65636, 82739, 104299, 131477, 165737, 208925 + // clang-format on +}; + +ac97_codec_t **ac97_codec = NULL, **ac97_modem_codec = NULL; +int ac97_codec_count = 0, ac97_modem_codec_count = 0, + ac97_codec_id = 0, ac97_modem_codec_id = 0; + +uint16_t +ac97_codec_readw(ac97_codec_t *dev, uint8_t reg) +{ + /* Redirect a read from extended pages 1+ to the right array. */ + reg &= 0x7e; + uint16_t ret = dev->regs[0x24 >> 1] & 0x000f; + if ((ret > 0) && (reg >= 0x60) && (reg < 0x6f)) + ret = (ret <= dev->vendor_reg_page_max) ? dev->vendor_reg_pages[(ret << 3) | ((reg & 0x0e) >> 1)] : 0; + else + ret = dev->regs[reg >> 1]; + + ac97_codec_log("AC97 Codec %d: readw(%02X) = %04X\n", dev->codec_id, reg, ret); + + return ret; +} + +void +ac97_codec_writew(ac97_codec_t *dev, uint8_t reg, uint16_t val) +{ + ac97_codec_log("AC97 Codec %d: writew(%02X, %04X)\n", dev->codec_id, reg, val); + + reg &= 0x7e; + uint16_t i = 0, prev = dev->regs[reg >> 1]; + int j; + + switch (reg) { + case 0x00: /* Reset / ID code */ + ac97_codec_reset(dev); + return; + + case 0x02: /* Master Volume */ + val &= 0xbf3f; + + /* Convert 1xxxxx to 011111 where unsupported, per specification. */ + if (!(dev->misc_flags & AC97_MASTER_6B)) { +clamp_5b: + if (val & 0x2000) + val = (val & ~0x2000) | 0x1f00; +clamp_5b_r: + if (val & 0x0020) + val = (val & ~0x0020) | 0x001f; + } + break; + + case 0x04: /* Aux Out Volume */ + if (!(dev->misc_flags & AC97_AUXOUT)) + return; + val &= 0xbf3f; + + /* Convert 1xxxxx to 011111 where unsupported, per specification. */ + if (!(dev->misc_flags & AC97_AUXOUT_6B)) + goto clamp_5b; + break; + + case 0x06: /* Mono Out Volume */ + if (!(dev->misc_flags & AC97_MONOOUT)) + return; + val &= 0x803f; + + /* Convert 1xxxxx to 011111 where unsupported, per specification. */ + if (!(dev->misc_flags & AC97_MONOOUT_6B)) + goto clamp_5b_r; + break; + + case 0x08: /* Master Tone Control */ + if (!(dev->reset_flags & AC97_TONECTL)) + return; + val &= 0x0f0f; + break; + + case 0x0a: /* PC Beep Volume */ + if (dev->misc_flags & AC97_PCBEEP) + i |= 0x801e; + if (dev->misc_flags & AC97_PCBEEP_GEN) + i |= 0x1fe0; + val &= i; + break; + + case 0x0c: /* Phone Volume */ + if (!(dev->misc_flags & AC97_PHONE)) + return; + val &= 0x801f; + break; + + case 0x0e: /* Mic Volume */ + val &= 0x805f; + break; + + case 0x10: /* Line In Volume */ + case 0x12: /* CD Volume */ + case 0x18: /* PCM Out Volume */ +line_gain: + val &= 0x9f1f; + break; + + case 0x14: /* Video Volume */ + if (!(dev->misc_flags & AC97_VIDEO)) + return; + goto line_gain; + + case 0x16: /* Aux In Volume */ + if (!(dev->misc_flags & AC97_AUXIN)) + return; + goto line_gain; + + case 0x1a: /* Record Select Control */ + val &= 0x0707; + break; + + case 0x1c: /* Record Gain */ + val &= 0x8f0f; + break; + + case 0x1e: /* Record Gain Mic */ + if (!(dev->reset_flags & AC97_MICPCM)) + return; + val &= 0x800f; + break; + + case 0x20: /* General Purpose */ + i = AC97_MIX | (dev->misc_flags & (AC97_POP | AC97_MS | AC97_LPBK)); + if (dev->reset_flags >> AC97_3D_SHIFT) + i |= AC97_3D; + if (dev->reset_flags & AC97_SIMSTEREO) + i |= AC97_ST; + if (dev->reset_flags & AC97_LOUDNESS) + i |= AC97_LD; + if (dev->extid_flags & AC97_DRA) + i |= AC97_DRSS_MASK; + val &= i; + break; + + case 0x22: /* 3D Control */ + switch (dev->reset_flags >> AC97_3D_SHIFT) { + case 1: /* Analog Devices */ + case 6: /* Crystal */ + val &= 0x000f; + break; + + case 22: /* Avance Logic / Realtek */ + val &= 0x0003; + break; + + case 26: /* SigmaTel */ + i = 0x0003; + if (dev->extid_flags & AC97_SDAC) + i |= 0x000c; + val &= i; + break; + + default: + return; + } + break; + + case 0x24: /* Audio Interrupt and Paging Mechanism */ + if ((dev->extid_flags & AC97_REV_MASK) < AC97_REV_2_3) + return; + val &= 0x000f; + break; + + case 0x26: /* Powerdown Control/Status */ + i = dev->powerdown_mask << 8; + val = (val & i) | (prev & ~i); + + /* Update status bits to reflect powerdowns. */ + val = (val & ~0x000f) | (~(val >> 8) & 0x000f); + if (val & 0x0800) /* PR3 clears both ANL and REF */ + val &= ~0x0004; + break; + + case 0x28: /* Extended Audio ID */ + if (dev->misc_flags & AC97_DSA) + i |= 0x0030; + val = (val & i) | (prev & ~i); + break; + + case 0x2a: /* Extended Audio Status/Control */ + i = dev->extid_flags & (AC97_VRA | AC97_DRA | AC97_SPDIF | AC97_VRM); + if (dev->extid_flags & AC97_SPDIF) + i |= AC97_SPSA_MASK << AC97_SPSA_SHIFT; + i |= (dev->powerdown_mask << 3) & 0x7800; /* multichannel powerdowns */ + val = (val & i) | (prev & ~i); + + /* Reset DAC sample rates to 48 KHz (96 KHz with DRA) if VRA is being cleared. */ + if (!(val & AC97_VRA)) { + for (i = 0x2c; i <= 0x30; i += 2) + dev->regs[i >> 1] = 48000; + } + + /* Reset ADC sample rates to 48 KHz if VRM is being cleared. */ + if (!(val & AC97_VRM)) { + for (i = 0x32; i <= 0x34; i += 2) + dev->regs[i >> 1] = 48000; + } + break; + + case 0x2c: /* PCM Front DAC Rate */ + case 0x32: /* PCM L/R ADC Rate */ +rate: /* Writable only if VRA/VRM is set. */ + i = (reg >= 0x32) ? AC97_VRM : AC97_VRA; + if (!(dev->extid_flags & i)) + return; + + /* Limit to supported sample rate range. */ + if (val < dev->min_rate) + val = dev->min_rate; + else if (val > dev->max_rate) + val = dev->max_rate; + break; + + case 0x2e: /* PCM Surround DAC Rate */ + if (!(dev->extid_flags & AC97_SDAC)) + return; + goto rate; + + case 0x30: /* PCM LFE DAC Rate */ + if (!(dev->extid_flags & AC97_LDAC)) + return; + goto rate; + + case 0x34: /* Mic ADC Rate */ + if (!(dev->reset_flags & AC97_MICPCM)) + return; + goto rate; + + case 0x36: /* Center/LFE Volume */ + if (dev->extid_flags & AC97_LDAC) + i |= 0xbf00; + if (dev->extid_flags & AC97_CDAC) + i |= 0x00bf; + val &= i; + + /* Convert 1xxxxx to 011111 where unsupported, per specification. */ + if (!(dev->misc_flags & AC97_LFE_6B) && (val & 0x2000)) + val = (val & ~0x2000) | 0x1f00; + if (!(dev->misc_flags & AC97_CENTER_6B)) + goto clamp_5b_r; + break; + + case 0x38: /* Surround Volume */ + if (!(dev->extid_flags & AC97_SDAC)) + return; + val &= 0xbfbf; + + /* Convert 1xxxxx to 011111 where unsupported, per specification. */ + if (!(dev->misc_flags & AC97_SURR_6B)) + goto clamp_5b; + break; + + case 0x3a: /* S/PDIF Control */ + if (!(dev->extid_flags & AC97_SPDIF)) + return; + break; + + case 0x60 ... 0x6e: /* Extended */ + /* Get extended register page. */ + i = dev->regs[0x24 >> 1] & 0x000f; + + /* Redirect a write to page 1+ to the right array, part 1. */ + if (i > 0) { + /* Don't overflow the pages. */ + if (i > dev->vendor_reg_page_max) + return; + + /* Get actual previous value. */ + prev = dev->vendor_reg_pages[(i << 3) | ((reg & 0x0e) >> 1)]; + } + + i <<= 8; + /* fall-through */ + + case 0x5a ... 0x5e: /* Vendor Reserved */ + case 0x70 ... 0x7a: + /* Stop if no vendor-specific registers are defined. */ + if (!dev->vendor_regs) + return; + + /* Look for a matching vendor-specific register. */ + i |= reg; + for (j = 0; dev->vendor_regs[j].index; j++) { + /* If a match was found, inject written bits. */ + if (dev->vendor_regs[j].index == i) { + val = (val & dev->vendor_regs[j].write_mask) | (prev & ~dev->vendor_regs[j].write_mask); + break; + } + } + + /* No match found. */ + if (!dev->vendor_regs[j].index) + return; + + /* Redirect a write to page 1+ to the right array, part 2. */ + i >>= 8; + if (i > 0) { + dev->vendor_reg_pages[(i << 3) | ((reg & 0x0e) >> 1)] = val; + return; + } + break; + + case 0x7c: /* Vendor ID1 */ + case 0x7e: /* Vendor ID2 */ + return; + } + + dev->regs[reg >> 1] = val; +} + +void +ac97_codec_reset(void *priv) +{ + ac97_codec_t *dev = (ac97_codec_t *) priv; + uint16_t i, j; + + ac97_codec_log("AC97 Codec %d: reset()\n", dev->codec_id); + + memset(dev->regs, 0, sizeof(dev->regs)); + + /* Set default level and gain values. */ + dev->regs[0x02 >> 1] = AC97_MUTE; + if (dev->misc_flags & AC97_AUXOUT) + dev->regs[0x04 >> 1] = AC97_MUTE; + if (dev->misc_flags & AC97_MONOOUT) + dev->regs[0x06 >> 1] = AC97_MUTE; + if (dev->misc_flags & AC97_PHONE) + dev->regs[0x0c >> 1] = AC97_MUTE | 0x0008; + dev->regs[0x0e >> 1] = AC97_MUTE | 0x0008; /* mic */ + dev->regs[0x10 >> 1] = dev->regs[0x12 >> 1] = dev->regs[0x18 >> 1] = AC97_MUTE | 0x0808; /* line in, CD, PCM out */ + if (dev->misc_flags & AC97_VIDEO) + dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808; + if (dev->misc_flags & AC97_AUXIN) + dev->regs[0x14 >> 1] = AC97_MUTE | 0x0808; + dev->regs[0x1c >> 1] = AC97_MUTE; /* record gain */ + if (dev->reset_flags & AC97_MICPCM) + dev->regs[0x1e >> 1] = AC97_MUTE; /* mic record gain */ + if (dev->misc_flags & AC97_LDAC) + dev->regs[0x36 >> 1] = AC97_MUTE_L; + if (dev->misc_flags & AC97_CDAC) + dev->regs[0x36 >> 1] |= AC97_MUTE_R; + if (dev->misc_flags & AC97_SDAC) + dev->regs[0x38 >> 1] = AC97_MUTE_L | AC97_MUTE_R; + + /* Set flags. */ + dev->regs[0x00 >> 1] = dev->reset_flags; + dev->regs[0x26 >> 1] = 0x000f; /* codec ready */ + dev->regs[0x28 >> 1] = (dev->codec_id << 14) | dev->extid_flags; + ac97_codec_writew(dev, 0x2a, 0x0000); /* reset variable DAC/ADC sample rates */ + i = dev->extid_flags & (AC97_CDAC | AC97_SDAC | AC97_LDAC); + dev->regs[0x2a >> 1] |= i | (i << 5); /* any additional DACs are ready but powered down */ + if (dev->extid_flags & AC97_SPDIF) + dev->regs[0x2a >> 1] |= AC97_SPCV; + if (dev->reset_flags & AC97_MICPCM) + dev->regs[0x2a >> 1] |= AC97_MADC | AC97_PRL; + + /* Set vendor ID. */ + dev->regs[0x7c >> 1] = dev->vendor_id >> 16; + dev->regs[0x7e >> 1] = dev->vendor_id; + + /* Set vendor-specific registers. */ + if (dev->vendor_regs) { + for (j = 0; dev->vendor_regs[j].index; j++) { + i = (dev->vendor_regs[j].index >> 8) & 0x000f; + if (i > 0) + dev->vendor_reg_pages[(i << 3) | (dev->vendor_regs[j].index >> 1)] = dev->vendor_regs[j].value; + else + dev->regs[dev->vendor_regs[j].index >> 1] = dev->vendor_regs[j].value; + } + } +} + +void +ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r) +{ + ac97_codec_t *dev = (ac97_codec_t *) priv; + uint16_t val = dev->regs[reg >> 1]; + + /* Apply full mute and powerdowns. */ + int full_mute = (reg < 0x36); + if ((full_mute && (val & AC97_MUTE)) || /* full mute */ + (dev->regs[0x26 >> 1] & 0x3e00) || /* DAC powerdown */ + ((reg == 0x38) && (dev->regs[0x2a >> 1] & AC97_PRJ))) { /* surround DAC powerdown */ + *l = 0; + *r = 0; + } else { /* per-channel mute */ + /* Determine attenuation value. */ + uint8_t l_val = val >> 8, r_val = val; + if (reg <= 0x06) { /* 6-bit level */ + *l = codec_attn[0x3f - (l_val & 0x3f)]; + *r = codec_attn[0x3f - (r_val & 0x3f)]; + } else { /* 5-bit gain */ + *l = codec_attn[0x47 - (l_val & 0x1f)]; + *r = codec_attn[0x47 - (r_val & 0x1f)]; + } + + /* Apply per-channel mute and center/LFE powerdowns where applicable. */ + if (!full_mute) { + if ((val & AC97_MUTE_L) || /* left mute */ + ((reg == 0x36) && (dev->regs[0x2a >> 1] & AC97_PRK))) /* LFE DAC powerdown */ + *l = 0; + if ((val & AC97_MUTE_R) || /* right mute */ + ((reg == 0x36) && (dev->regs[0x2a >> 1] & AC97_PRI))) /* center DAC powerdown */ + *r = 0; + } + } + + ac97_codec_log("AC97 Codec %d: getattn(%02X) = %d %d\n", dev->codec_id, reg, *l, *r); +} + +uint32_t +ac97_codec_getrate(void *priv, uint8_t reg) +{ + ac97_codec_t *dev = (ac97_codec_t *) priv; + + /* Get configured sample rate, which is always 48000 if VRA/VRM is not set. */ + uint32_t ret = dev->regs[reg >> 1]; + + /* If this is the PCM DAC, double sample rate if DRA is set. */ + if ((reg == 0x2c) && (dev->regs[0x2a >> 1] & AC97_DRA)) + ret <<= 1; + + ac97_codec_log("AC97 Codec %d: getrate(%02X) = %d\n", dev->codec_id, reg, ret); + + return ret; +} + +static void * +ac97_codec_init(const device_t *info) +{ + ac97_codec_t *dev = malloc(sizeof(ac97_codec_t)); + memset(dev, 0, sizeof(ac97_codec_t)); + + dev->vendor_id = ac97_codecs[info->local].vendor_id; + dev->min_rate = ac97_codecs[info->local].min_rate; + dev->max_rate = ac97_codecs[info->local].max_rate; + dev->reset_flags = ac97_codecs[info->local].reset_flags; + dev->extid_flags = ac97_codecs[info->local].extid_flags; + dev->misc_flags = ac97_codecs[info->local].misc_flags; + dev->powerdown_mask = ac97_codecs[info->local].powerdown_mask; + dev->vendor_regs = ac97_codecs[info->local].vendor_regs; + ac97_codec_log("AC97 Codec %d: init(%c%c%c%02X)\n", ac97_codec_id, (dev->vendor_id >> 24) & 0xff, (dev->vendor_id >> 16) & 0xff, (dev->vendor_id >> 8) & 0xff, dev->vendor_id & 0xff); + + /* Associate this codec to the current controller. */ + if (!ac97_codec || (ac97_codec_count <= 0)) { + pclog("AC97 Codec %d: No controller to associate codec\n", ac97_codec_id); + return NULL; + } + *ac97_codec = dev; + if (--ac97_codec_count == 0) + ac97_codec = NULL; + else + ac97_codec += sizeof(ac97_codec_t *); + dev->codec_id = ac97_codec_id++; + + /* Allocate vendor-specific register pages if required. */ + if (dev->vendor_regs) { + /* Get the highest vendor-specific register page number. */ + int i, j; + dev->vendor_reg_page_max = 0; + for (j = 0; dev->vendor_regs[j].index; j++) { + i = (dev->vendor_regs[j].index >> 8) & 0x000f; + if (i > dev->vendor_reg_page_max) + dev->vendor_reg_page_max = i; + } + + /* Allocate pages 1+. */ + if (dev->vendor_reg_page_max > 0) { + ac97_codec_log("AC97 Codec %d: Allocating %d vendor-specific register pages\n", dev->codec_id, dev->vendor_reg_page_max); + i = 16 * dev->vendor_reg_page_max; + dev->vendor_reg_pages = (uint16_t *) malloc(i); + memset(dev->vendor_reg_pages, 0, i); + } + } + + /* Initialize codec registers. */ + ac97_codec_reset(dev); + + return dev; +} + +static void +ac97_codec_close(void *priv) +{ + ac97_codec_t *dev = (ac97_codec_t *) priv; + if (!dev) + return; + + ac97_codec_log("AC97 Codec %d: close()\n", dev->codec_id); + + if (dev->vendor_reg_pages) + free(dev->vendor_reg_pages); + free(dev); +} + +const device_t * +ac97_codec_get(int model) +{ + if ((model >= 0) && (model < (sizeof(ac97_codecs) / sizeof(ac97_codecs[0])))) + return ac97_codecs[model].device; + else + return &cs4297a_device; /* fallback */ +} + +const device_t ad1881_device = { + .name = "Analog Devices AD1881", + .internal_name = "ad1881", + .flags = DEVICE_AC97, + .local = AC97_CODEC_AD1881, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ak4540_device = { + .name = "Asahi Kasei AK4540", + .internal_name = "ak4540", + .flags = DEVICE_AC97, + .local = AC97_CODEC_AK4540, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t alc100_device = { + .name = "Avance Logic ALC100", + .internal_name = "alc100", + .flags = DEVICE_AC97, + .local = AC97_CODEC_ALC100, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t cs4297_device = { + .name = "Crystal CS4297", + .internal_name = "cs4297", + .flags = DEVICE_AC97, + .local = AC97_CODEC_CS4297, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t cs4297a_device = { + .name = "Crystal CS4297A", + .internal_name = "cs4297a", + .flags = DEVICE_AC97, + .local = AC97_CODEC_CS4297A, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t stac9708_device = { + .name = "SigmaTel STAC9708", + .internal_name = "stac9708", + .flags = DEVICE_AC97, + .local = AC97_CODEC_STAC9708, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t stac9721_device = { + .name = "SigmaTel STAC9721", + .internal_name = "stac9721", + .flags = DEVICE_AC97, + .local = AC97_CODEC_STAC9721, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t wm9701a_device = { + .name = "Wolfson WM9701A", + .internal_name = "wm9701a", + .flags = DEVICE_AC97, + .local = AC97_CODEC_WM9701A, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c new file mode 100644 index 000000000..b3dbd30d8 --- /dev/null +++ b/src/sound/snd_ac97_via.c @@ -0,0 +1,818 @@ +/* + * 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. + * + * VIA AC'97 audio controller emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/snd_ac97.h> +#include <86box/sound.h> +#include <86box/timer.h> + +typedef struct { + uint8_t id, always_run; + struct _ac97_via_ *dev; + + uint32_t entry_ptr, sample_ptr, fifo_pos, fifo_end; + int32_t sample_count; + uint8_t entry_flags, fifo[32], restart; + + int16_t out_l, out_r; + int vol_l, vol_r, pos; + int32_t buffer[SOUNDBUFLEN * 2]; + uint64_t timer_latch; + + pc_timer_t dma_timer, poll_timer; +} ac97_via_sgd_t; + +typedef struct _ac97_via_ { + uint16_t audio_sgd_base, audio_codec_base, modem_sgd_base, modem_codec_base; + uint8_t sgd_regs[256], pcm_enabled : 1, fm_enabled : 1, vsr_enabled : 1; + struct { + union { + uint8_t regs_codec[2][128]; + uint8_t regs_linear[256]; + }; + } codec_shadow[2]; + int slot, irq_pin; + + ac97_codec_t *codec[2][2]; + ac97_via_sgd_t sgd[6]; + + int master_vol_l, master_vol_r, cd_vol_l, cd_vol_r; +} ac97_via_t; + +#ifdef ENABLE_AC97_VIA_LOG +int ac97_via_do_log = ENABLE_AC97_VIA_LOG; + +static void +ac97_via_log(const char *fmt, ...) +{ + va_list ap; + + if (ac97_via_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define ac97_via_log(fmt, ...) +#endif + +static void ac97_via_sgd_process(void *priv); +static void ac97_via_update_codec(ac97_via_t *dev); +static void ac97_via_speed_changed(void *priv); +static void ac97_via_filter_cd_audio(int channel, double *buffer, void *priv); + +void +ac97_via_set_slot(void *priv, int slot, int irq_pin) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + ac97_via_log("AC97 VIA: set_slot(%d, %d)\n", slot, irq_pin); + + dev->slot = slot; + dev->irq_pin = irq_pin; +} + +uint8_t +ac97_via_read_status(void *priv, uint8_t modem) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + uint8_t ret = 0x00; + + /* Flag each codec as ready if present. */ + for (uint8_t i = 0; i <= 1; i++) { + if (dev->codec[modem][i]) + ret |= 0x01 << (i << 1); + } + + ac97_via_log("AC97 VIA %d: read_status() = %02X\n", modem, ret); + + return ret; +} + +void +ac97_via_write_control(void *priv, uint8_t modem, uint8_t val) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + uint8_t i; + + ac97_via_log("AC97 VIA %d: write_control(%02X)\n", modem, val); + + /* Reset codecs if requested. */ + if (!(val & 0x40)) { + for (i = 0; i <= 1; i++) { + if (dev->codec[modem][i]) + ac97_codec_reset(dev->codec[modem][i]); + } + } + + if (!modem) { + /* Set the variable sample rate flag. */ + dev->vsr_enabled = (val & 0xf8) == 0xc8; + + /* Start or stop PCM playback. */ + i = (val & 0xf4) == 0xc4; + if (i && !dev->pcm_enabled) + timer_advance_u64(&dev->sgd[0].poll_timer, dev->sgd[0].timer_latch); + dev->pcm_enabled = i; + + /* Start or stop FM playback. */ + i = (val & 0xf2) == 0xc2; + if (i && !dev->fm_enabled) + timer_advance_u64(&dev->sgd[2].poll_timer, dev->sgd[2].timer_latch); + dev->fm_enabled = i; + + /* Update primary audio codec state. */ + if (dev->codec[0][0]) + ac97_via_update_codec(dev); + } +} + +static void +ac97_via_update_irqs(ac97_via_t *dev) +{ + /* Check interrupt flags in all SGDs. */ + for (uint8_t i = 0x00; i < ((sizeof(dev->sgd) / sizeof(dev->sgd[0])) << 4); i += 0x10) { + /* Stop immediately if any flag is set. Doing it this way optimizes + rising edges for the playback SGD (0 - first to be checked). */ + if (dev->sgd_regs[i] & (dev->sgd_regs[i | 0x2] & 0x03)) { + pci_set_irq(dev->slot, dev->irq_pin); + return; + } + } + + pci_clear_irq(dev->slot, dev->irq_pin); +} + +static void +ac97_via_update_codec(ac97_via_t *dev) +{ + /* Get primary audio codec. */ + ac97_codec_t *codec = dev->codec[0][0]; + + /* Update volumes according to codec registers. */ + ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); + ac97_codec_getattn(codec, 0x18, &dev->sgd[0].vol_l, &dev->sgd[0].vol_r); + ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); + + /* Update sample rate according to codec registers and the variable sample rate flag. */ + ac97_via_speed_changed(dev); +} + +uint8_t +ac97_via_sgd_read(uint16_t addr, void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; +#ifdef ENABLE_AC97_VIA_LOG + uint8_t modem = (addr & 0xff00) == dev->modem_sgd_base; +#endif + addr &= 0xff; + uint8_t ret; + + if (!(addr & 0x80)) { + /* Process SGD channel registers. */ + switch (addr & 0xf) { + case 0x4: + ret = dev->sgd[addr >> 4].entry_ptr; + break; + + case 0x5: + ret = dev->sgd[addr >> 4].entry_ptr >> 8; + break; + + case 0x6: + ret = dev->sgd[addr >> 4].entry_ptr >> 16; + break; + + case 0x7: + ret = dev->sgd[addr >> 4].entry_ptr >> 24; + break; + + case 0xc: + ret = dev->sgd[addr >> 4].sample_count; + break; + + case 0xd: + ret = dev->sgd[addr >> 4].sample_count >> 8; + break; + + case 0xe: + ret = dev->sgd[addr >> 4].sample_count >> 16; + break; + + default: + ret = dev->sgd_regs[addr]; + break; + } + } else { + /* Process regular registers. */ + switch (addr) { + case 0x84: + ret = (dev->sgd_regs[0x00] & 0x01); + ret |= (dev->sgd_regs[0x10] & 0x01) << 1; + ret |= (dev->sgd_regs[0x20] & 0x01) << 2; + + ret |= (dev->sgd_regs[0x00] & 0x02) << 3; + ret |= (dev->sgd_regs[0x10] & 0x02) << 4; + ret |= (dev->sgd_regs[0x20] & 0x02) << 5; + break; + + case 0x85: + ret = (dev->sgd_regs[0x00] & 0x04) >> 2; + ret |= (dev->sgd_regs[0x10] & 0x04) >> 1; + ret |= (dev->sgd_regs[0x20] & 0x04); + + ret |= (dev->sgd_regs[0x00] & 0x80) >> 3; + ret |= (dev->sgd_regs[0x10] & 0x80) >> 2; + ret |= (dev->sgd_regs[0x20] & 0x80) >> 1; + break; + + case 0x86: + ret = (dev->sgd_regs[0x40] & 0x01); + ret |= (dev->sgd_regs[0x50] & 0x01) << 1; + + ret |= (dev->sgd_regs[0x40] & 0x02) << 3; + ret |= (dev->sgd_regs[0x50] & 0x02) << 4; + break; + + case 0x87: + ret = (dev->sgd_regs[0x40] & 0x04) >> 2; + ret |= (dev->sgd_regs[0x50] & 0x04) >> 1; + + ret |= (dev->sgd_regs[0x40] & 0x80) >> 3; + ret |= (dev->sgd_regs[0x50] & 0x80) >> 2; + break; + + default: + ret = dev->sgd_regs[addr]; + break; + } + } + + ac97_via_log("AC97 VIA %d: sgd_read(%02X) = %02X\n", modem, addr, ret); + + return ret; +} + +void +ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + uint8_t modem = (addr & 0xff00) == dev->modem_sgd_base, i; + ac97_codec_t *codec; + addr &= 0xff; + + ac97_via_log("AC97 VIA %d: sgd_write(%02X, %02X)\n", modem, addr, val); + + /* Check function-specific read only registers. */ + if ((addr >= (modem ? 0x00 : 0x40)) && (addr < (modem ? 0x40 : 0x60))) + return; + if (addr >= (modem ? 0x90 : 0x88)) + return; + + if (!(addr & 0x80)) { + /* Process SGD channel registers. */ + switch (addr & 0xf) { + case 0x0: + /* Clear RWC status bits. */ + dev->sgd_regs[addr] &= ~(val & 0x07); + + /* Update status interrupts. */ + ac97_via_update_irqs(dev); + + return; + + case 0x1: + /* Start SGD if requested. */ + if (val & 0x80) { + if (dev->sgd_regs[addr & 0xf0] & 0x80) { + /* Queue SGD trigger if already running. */ + dev->sgd_regs[addr & 0xf0] |= 0x08; + } else { + /* Start SGD immediately. */ + dev->sgd_regs[addr & 0xf0] |= 0x80; + dev->sgd_regs[addr & 0xf0] &= ~0x44; + + /* Start at the specified entry pointer. */ + dev->sgd[addr >> 4].sample_ptr = 0; + dev->sgd[addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[(addr & 0xf0) | 0x4]) & 0xfffffffe; + dev->sgd[addr >> 4].restart = 1; + + /* Start the actual SGD process. */ + ac97_via_sgd_process(&dev->sgd[addr >> 4]); + } + } + /* Stop SGD if requested. */ + if (val & 0x40) + dev->sgd_regs[addr & 0xf0] &= ~0x88; + + val &= 0x08; + + /* (Un)pause SGD if requested. */ + if (val & 0x08) + dev->sgd_regs[addr & 0xf0] |= 0x40; + else + dev->sgd_regs[addr & 0xf0] &= ~0x40; + + break; + + case 0x2: + if (addr & 0x10) + val &= 0xf3; + break; + + case 0x3: + case 0x8 ... 0xf: + /* Read-only registers. */ + return; + } + } else { + /* Process regular registers. */ + switch (addr) { + case 0x30 ... 0x3f: + case 0x60 ... 0x7f: + case 0x84 ... 0x87: + /* Read-only registers. */ + return; + + case 0x82: + /* Determine the selected codec. */ + i = !!(dev->sgd_regs[0x83] & 0x40); + codec = dev->codec[modem][i]; + + /* Keep value in register if this codec is not present. */ + if (codec) { + /* Read from or write to codec. */ + if (val & 0x80) { + if (val & 1) { /* return 0x0000 on unaligned reads (real 686B behavior) */ + dev->sgd_regs[0x80] = dev->sgd_regs[0x81] = 0x00; + } else { + *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[0x80]) = ac97_codec_readw(codec, val); + } + + /* Flag data/status/index for this codec as valid. */ + dev->sgd_regs[0x83] |= 0x02 << (i << 1); + } else if (!(val & 1)) { /* do nothing on unaligned writes */ + ac97_codec_writew(codec, val, + *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[0x80])); + + /* Update primary audio codec state if that codec was written to. */ + if (!modem && !i) { + ac97_via_update_codec(dev); + + /* Set up CD audio filter if CD volume was written to. Setting it + up at init prevents CD audio from working on other cards, but + this works as the CD channel is muted by default per AC97 spec. */ + if (val == 0x12) + sound_set_cd_audio_filter(ac97_via_filter_cd_audio, dev); + } + } + } + + break; + + case 0x83: + /* Clear RWC status bits. */ +#if 0 /* race condition with Linux accessing a register and clearing status bits on the same dword write */ + val = (dev->sgd_regs[addr] & ~(val & 0x0a)) | (val & 0xc0); +#else + val = dev->sgd_regs[addr] | (val & 0xc0); +#endif + break; + } + } + + dev->sgd_regs[addr] = val; +} + +void +ac97_via_remap_audio_sgd(void *priv, uint16_t new_io_base, uint8_t enable) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + if (dev->audio_sgd_base) + io_removehandler(dev->audio_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev); + + dev->audio_sgd_base = new_io_base; + + if (dev->audio_sgd_base && enable) + io_sethandler(dev->audio_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev); +} + +void +ac97_via_remap_modem_sgd(void *priv, uint16_t new_io_base, uint8_t enable) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + if (dev->modem_sgd_base) + io_removehandler(dev->modem_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev); + + dev->modem_sgd_base = new_io_base; + + if (dev->modem_sgd_base && enable) + io_sethandler(dev->modem_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev); +} + +uint8_t +ac97_via_codec_read(uint16_t addr, void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + uint8_t modem = (addr & 0xff00) == dev->modem_codec_base; + addr &= 0xff; + uint8_t ret = 0xff; + + ret = dev->codec_shadow[modem].regs_linear[addr]; + + ac97_via_log("AC97 VIA %d: codec_read(%02X) = %02X\n", modem, addr, ret); + + return ret; +} + +void +ac97_via_codec_write(uint16_t addr, uint8_t val, void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + uint8_t modem = (addr & 0xff00) == dev->modem_codec_base; + addr &= 0xff; + + ac97_via_log("AC97 VIA %d: codec_write(%02X, %02X)\n", modem, addr, val); + + /* Unknown behavior, maybe it does write to the shadow registers? */ + dev->codec_shadow[modem].regs_linear[addr] = val; +} + +void +ac97_via_remap_audio_codec(void *priv, uint16_t new_io_base, uint8_t enable) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + if (dev->audio_codec_base) + io_removehandler(dev->audio_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); + + dev->audio_codec_base = new_io_base; + + if (dev->audio_codec_base && enable) + io_sethandler(dev->audio_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); +} + +void +ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + if (dev->modem_codec_base) + io_removehandler(dev->modem_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); + + dev->modem_codec_base = new_io_base; + + if (dev->modem_codec_base && enable) + io_sethandler(dev->modem_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); +} + +static void +ac97_via_update_stereo(ac97_via_t *dev, ac97_via_sgd_t *sgd) +{ + int32_t l = (((sgd->out_l * sgd->vol_l) >> 15) * dev->master_vol_l) >> 15, + r = (((sgd->out_r * sgd->vol_r) >> 15) * dev->master_vol_r) >> 15; + + if (l < -32768) + l = -32768; + else if (l > 32767) + l = 32767; + if (r < -32768) + r = -32768; + else if (r > 32767) + r = 32767; + + for (; sgd->pos < sound_pos_global; sgd->pos++) { + sgd->buffer[sgd->pos * 2] = l; + sgd->buffer[sgd->pos * 2 + 1] = r; + } +} + +static void +ac97_via_sgd_process(void *priv) +{ + ac97_via_sgd_t *sgd = (ac97_via_sgd_t *) priv; + ac97_via_t *dev = sgd->dev; + + /* Stop if this SGD is not active. */ + uint8_t sgd_status = dev->sgd_regs[sgd->id] & 0xc4; + if (!(sgd_status & 0x80)) + return; + + /* Schedule next run. */ + timer_on_auto(&sgd->dma_timer, 10.0); + + /* Process SGD if it's active, and the FIFO has room or is disabled. */ + if ((sgd_status == 0x80) && (sgd->always_run || ((sgd->fifo_end - sgd->fifo_pos) <= (sizeof(sgd->fifo) - 4)))) { + /* Move on to the next block if no entry is present. */ + if (sgd->restart) { + sgd->restart = 0; + + /* Start at first entry if no pointer is present. */ + if (!sgd->entry_ptr) + sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->id | 0x4]) & 0xfffffffe; + + /* Read entry. */ + sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr); + sgd->entry_ptr += 4; + sgd->sample_count = mem_readl_phys(sgd->entry_ptr); + sgd->entry_ptr += 4; +#ifdef ENABLE_AC97_VIA_LOG + if (((sgd->sample_ptr == 0xffffffff) && (sgd->sample_count == 0xffffffff)) || ((sgd->sample_ptr == 0x00000000) && (sgd->sample_count == 0x00000000))) + fatal("AC97 VIA: Invalid SGD %d entry %08X%08X at %08X\n", sgd->id >> 4, + sgd->sample_ptr, sgd->sample_count, sgd->entry_ptr - 8); +#endif + + /* Extract flags from the most significant byte. */ + sgd->entry_flags = sgd->sample_count >> 24; + sgd->sample_count &= 0xffffff; + + ac97_via_log("AC97 VIA: Starting SGD %d block at %08X start %08X len %06X flags %02X\n", sgd->id >> 4, + sgd->entry_ptr - 8, sgd->sample_ptr, sgd->sample_count, sgd->entry_flags); + } + + if (sgd->id & 0x10) { + /* Write channel: read data from FIFO. */ + mem_writel_phys(sgd->sample_ptr, *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)])); + } else { + /* Read channel: write data to FIFO. */ + *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]) = mem_readl_phys(sgd->sample_ptr); + } + sgd->fifo_end += 4; + sgd->sample_ptr += 4; + sgd->sample_count -= 4; + + /* Check if we've hit the end of this block. */ + if (sgd->sample_count <= 0) { + ac97_via_log("AC97 VIA: Ending SGD %d block", sgd->id >> 4); + + if (sgd->entry_flags & 0x20) { + ac97_via_log(" with STOP"); + + /* Raise STOP to pause SGD. */ + dev->sgd_regs[sgd->id] |= 0x04; + } + + if (sgd->entry_flags & 0x40) { + ac97_via_log(" with FLAG"); + + /* Raise FLAG and STOP. */ + dev->sgd_regs[sgd->id] |= 0x05; + +#ifdef ENABLE_AC97_VIA_LOG + if (dev->sgd_regs[sgd->id | 0x2] & 0x01) + ac97_via_log(" interrupt"); +#endif + } + + if (sgd->entry_flags & 0x80) { + ac97_via_log(" with EOL"); + + /* Raise EOL. */ + dev->sgd_regs[sgd->id] |= 0x02; + +#ifdef ENABLE_AC97_VIA_LOG + if (dev->sgd_regs[sgd->id | 0x2] & 0x02) + ac97_via_log(" interrupt"); +#endif + + /* Restart SGD if a trigger is queued or auto-start is enabled. */ + if ((dev->sgd_regs[sgd->id] & 0x08) || (dev->sgd_regs[sgd->id | 0x2] & 0x80)) { + ac97_via_log(" restart"); + + /* Un-queue trigger. */ + dev->sgd_regs[sgd->id] &= ~0x08; + + /* Go back to the starting block. */ + sgd->entry_ptr = 0; /* ugly, but Windows XP plays too fast if the pointer is reloaded now */ + } else { + ac97_via_log(" finish"); + + /* Terminate SGD. */ + dev->sgd_regs[sgd->id] &= ~0x80; + } + } + ac97_via_log("\n"); + + /* Fire any requested status interrupts. */ + ac97_via_update_irqs(dev); + + /* Move on to a new block on the next run. */ + sgd->restart = 1; + } + } +} + +static void +ac97_via_poll_stereo(void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + ac97_via_sgd_t *sgd = &dev->sgd[0]; /* Audio Read */ + + /* Schedule next run if PCM playback is enabled. */ + if (dev->pcm_enabled) + timer_advance_u64(&sgd->poll_timer, sgd->timer_latch); + + /* Update stereo audio buffer. */ + ac97_via_update_stereo(dev, sgd); + + /* Feed next sample from the FIFO. */ + switch (dev->sgd_regs[sgd->id | 0x2] & 0x30) { + case 0x00: /* Mono, 8-bit PCM */ + if ((sgd->fifo_end - sgd->fifo_pos) >= 1) { + sgd->out_l = sgd->out_r = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8; + return; + } + break; + + case 0x10: /* Stereo, 8-bit PCM */ + if ((sgd->fifo_end - sgd->fifo_pos) >= 2) { + sgd->out_l = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8; + sgd->out_r = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8; + return; + } + break; + + case 0x20: /* Mono, 16-bit PCM */ + if ((sgd->fifo_end - sgd->fifo_pos) >= 2) { + sgd->out_l = sgd->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->fifo_pos += 2; + return; + } + break; + + case 0x30: /* Stereo, 16-bit PCM */ + if ((sgd->fifo_end - sgd->fifo_pos) >= 4) { + sgd->out_l = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->fifo_pos += 2; + sgd->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->fifo_pos += 2; + return; + } + break; + } + + /* Feed silence if the FIFO is empty. */ + sgd->out_l = sgd->out_r = 0; +} + +static void +ac97_via_poll_fm(void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + ac97_via_sgd_t *sgd = &dev->sgd[2]; /* FM Read */ + + /* Schedule next run if FM playback is enabled. */ + if (dev->fm_enabled) + timer_advance_u64(&sgd->poll_timer, sgd->timer_latch); + + /* Update FM audio buffer. */ + ac97_via_update_stereo(dev, sgd); + + /* Feed next sample from the FIFO. + The data format is not documented, but it probes as 16-bit stereo at 24 KHz. */ + if ((sgd->fifo_end - sgd->fifo_pos) >= 4) { + sgd->out_l = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->fifo_pos += 2; + sgd->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]); + sgd->fifo_pos += 2; + return; + } + + /* Feed silence if the FIFO is empty. */ + sgd->out_l = sgd->out_r = 0; +} + +static void +ac97_via_get_buffer(int32_t *buffer, int len, void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + ac97_via_update_stereo(dev, &dev->sgd[0]); + ac97_via_update_stereo(dev, &dev->sgd[2]); + + for (int c = 0; c < len * 2; c++) { + buffer[c] += dev->sgd[0].buffer[c] / 2; + buffer[c] += dev->sgd[2].buffer[c] / 2; + } + + dev->sgd[0].pos = dev->sgd[2].pos = 0; +} + +static void +ac97_via_filter_cd_audio(int channel, double *buffer, void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + double c, volume = channel ? dev->cd_vol_r : dev->cd_vol_l; + + c = ((*buffer) * volume) / 65536.0; + *buffer = c; +} + +static void +ac97_via_speed_changed(void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + double freq; + + /* Get variable sample rate if enabled. */ + if (dev->vsr_enabled && dev->codec[0][0]) + freq = ac97_codec_getrate(dev->codec[0][0], 0x2c); + else + freq = 48000.0; + + dev->sgd[0].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq)); + dev->sgd[2].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 24000.0)); +} + +static void * +ac97_via_init(const device_t *info) +{ + ac97_via_t *dev = malloc(sizeof(ac97_via_t)); + memset(dev, 0, sizeof(ac97_via_t)); + + ac97_via_log("AC97 VIA: init()\n"); + + /* Set up codecs. */ + ac97_codec = &dev->codec[0][0]; + ac97_modem_codec = &dev->codec[1][0]; + ac97_codec_count = ac97_modem_codec_count = sizeof(dev->codec[0]) / sizeof(dev->codec[0][0]); + ac97_codec_id = ac97_modem_codec_id = 0; + + /* Set up SGD channels. */ + for (uint8_t i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) { + dev->sgd[i].id = i << 4; + dev->sgd[i].dev = dev; + + /* Disable the FIFO on SGDs we don't care about. */ + if ((i != 0) && (i != 2)) + dev->sgd[i].always_run = 1; + + /* No volume control on FM SGD that I know of. */ + if (i == 2) + dev->sgd[i].vol_l = dev->sgd[i].vol_r = 32767; + + timer_add(&dev->sgd[i].dma_timer, ac97_via_sgd_process, &dev->sgd[i], 0); + } + + /* Set up playback pollers. */ + timer_add(&dev->sgd[0].poll_timer, ac97_via_poll_stereo, dev, 0); + timer_add(&dev->sgd[2].poll_timer, ac97_via_poll_fm, dev, 0); + ac97_via_speed_changed(dev); + + /* Set up playback handler. */ + sound_add_handler(ac97_via_get_buffer, dev); + + return dev; +} + +static void +ac97_via_close(void *priv) +{ + ac97_via_t *dev = (ac97_via_t *) priv; + + ac97_via_log("AC97 VIA: close()\n"); + + free(dev); +} + +const device_t ac97_via_device = { + .name = "VIA VT82C686 Integrated AC97 Controller", + .internal_name = "ac97_via", + .flags = DEVICE_PCI, + .local = 0, + .init = ac97_via_init, + .close = ac97_via_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ac97_via_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 4953da1a0..bf3858aa3 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -1,11 +1,29 @@ /* - AD1848 / CS4248 / CS4231 CODEC emulation (Windows Sound System compatible)*/ - -#include + * 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. + * + * AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * RichardG, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + * Copyright 2021-2022 RichardG. + */ +#include #include +#include #include #include -#include + #include <86box/86box.h> #include <86box/dma.h> #include <86box/pic.h> @@ -13,285 +31,687 @@ #include <86box/sound.h> #include <86box/snd_ad1848.h> -#define CS4231 0x80 +#define CS4231 0x80 +#define CS4236 0x03 -static int ad1848_vols_6bits[64]; -static uint32_t ad1848_vols_5bits_aux_gain[32]; +static int ad1848_vols_7bits[128]; +static double ad1848_vols_5bits_aux_gain[32]; +/* Borrowed from snd_sb_dsp */ +extern int8_t scaleMap4[64]; +extern uint8_t adjustMap4[64]; -void ad1848_setirq(ad1848_t *ad1848, int irq) +void +ad1848_setirq(ad1848_t *ad1848, int irq) { - ad1848->irq = irq; + ad1848->irq = irq; } -void ad1848_setdma(ad1848_t *ad1848, int dma) +void +ad1848_setdma(ad1848_t *ad1848, int dma) { - ad1848->dma = dma; + ad1848->dma = dma; } -uint8_t ad1848_read(uint16_t addr, void *p) +void +ad1848_updatevolmask(ad1848_t *ad1848) { - ad1848_t *ad1848 = (ad1848_t *)p; - uint8_t temp = 0xff; - switch (addr & 3) - { - case 0: /*Index*/ - temp = ad1848->index | ad1848->trd | ad1848->mce; - break; + if ((ad1848->type >= AD1848_TYPE_CS4235) && ((ad1848->xregs[4] & 0x10) || ad1848->wten)) + ad1848->wave_vol_mask = 0x3f; + else + ad1848->wave_vol_mask = 0x7f; +} + +static void +ad1848_updatefreq(ad1848_t *ad1848) +{ + double freq; + uint8_t set = 0; + + if (ad1848->type >= AD1848_TYPE_CS4235) { + if (ad1848->xregs[11] & 0x20) { + freq = 16934400LL; + switch (ad1848->xregs[13]) { case 1: - temp = ad1848->regs[ad1848->index]; - if (ad1848->index == 0x0b) { - temp ^= 0x20; - ad1848->regs[ad1848->index] = temp; - } - break; + freq /= 353; + break; case 2: - temp = ad1848->status; + freq /= 529; + break; + case 3: + freq /= 617; + break; + case 4: + freq /= 1058; + break; + case 5: + freq /= 1764; + break; + case 6: + freq /= 2117; + break; + case 7: + freq /= 2558; + break; + default: + freq /= 16 * MAX(ad1848->xregs[13], 21); + break; + } + set = 1; + } else if (ad1848->regs[22] & 0x80) { + freq = (ad1848->regs[22] & 1) ? 33868800LL : 49152000LL; + set = (ad1848->regs[22] >> 1) & 0x3f; + switch (ad1848->regs[10] & 0x30) { + case 0x00: + freq /= 128 * set; + break; + case 0x10: + freq /= 64 * set; + break; + case 0x20: + freq /= 256 * set; + break; + } + set = 1; + } + } + + if (!set) { + freq = (ad1848->regs[8] & 1) ? 16934400LL : 24576000LL; + switch ((ad1848->regs[8] >> 1) & 7) { + case 0: + freq /= 3072; + break; + case 1: + freq /= 1536; + break; + case 2: + freq /= 896; + break; + case 3: + freq /= 768; + break; + case 4: + freq /= 448; + break; + case 5: + freq /= 384; + break; + case 6: + freq /= 512; + break; + case 7: + freq /= 2560; break; } - return temp; + } + + ad1848->freq = freq; + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); } -void ad1848_write(uint16_t addr, uint8_t val, void *p) +uint8_t +ad1848_read(uint16_t addr, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - double freq; - uint32_t new_cd_vol_l, new_cd_vol_r; - switch (addr & 3) - { - case 0: /*Index*/ - if ((ad1848->regs[12] & 0x40) && (ad1848->type == AD1848_TYPE_CS4231)) - ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ - else - ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ - ad1848->trd = val & 0x20; - ad1848->mce = val & 0x40; - break; - case 1: - switch (ad1848->index) - { - case 8: - freq = (val & 1) ? 16934400LL : 24576000LL; - switch ((val >> 1) & 7) - { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; + ad1848_t *ad1848 = (ad1848_t *) priv; + uint8_t ret = 0xff; + + switch (addr & 3) { + case 0: /* Index */ + ret = ad1848->index | ad1848->trd | ad1848->mce; + break; + + case 1: + ret = ad1848->regs[ad1848->index]; + switch (ad1848->index) { + case 11: + ret ^= 0x20; + ad1848->regs[ad1848->index] = ret; + break; + + case 18: + case 19: + if (ad1848->type >= AD1848_TYPE_CS4235) { + if ((ad1848->xregs[4] & 0x14) == 0x14) /* FM remapping */ + ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ + else if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */ + ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ + } + break; + + case 20: + case 21: + /* Backdoor to the Control/RAM registers on CS4235. */ + if ((ad1848->type == AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) + ret = ad1848->cram_read(ad1848->index - 15, ad1848->cram_priv); + break; + + case 23: + if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->regs[23] & 0x08)) { + if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */ + ret = ad1848->regs[18 + ad1848->xindex]; + else + ret = ad1848->xregs[ad1848->xindex]; + } + break; + } + break; + + case 2: + ret = ad1848->status; + break; + } + + return ret; +} + +void +ad1848_write(uint16_t addr, uint8_t val, void *priv) +{ + ad1848_t *ad1848 = (ad1848_t *) priv; + uint8_t temp = 0, updatefreq = 0; + + switch (addr & 3) { + case 0: /* Index */ + if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) + ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ + else + ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ + if (ad1848->type >= AD1848_TYPE_CS4235) + ad1848->regs[23] &= ~0x08; /* clear XRAE */ + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; + + case 1: + switch (ad1848->index) { + case 10: + if (ad1848->type < AD1848_TYPE_CS4235) + break; + /* fall-through */ + + case 8: + updatefreq = 1; + break; + + case 9: + if (!ad1848->enable && (val & 0x41) == 0x01) { + ad1848->adpcm_pos = 0; + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); + } + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) { + timer_disable(&ad1848->timer_count); + ad1848->out_l = ad1848->out_r = 0; + } + break; + + case 11: + return; + + case 12: + if (ad1848->type != AD1848_TYPE_DEFAULT) + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + + case 17: + /* Enable additional data formats on modes 2 and 3 where supported. */ + if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236)) + ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70; + break; + + case 18: + case 19: + if (ad1848->type >= AD1848_TYPE_CS4235) { + if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ + ad1848->xregs[ad1848->index - 12] = val; /* real FM volume on extended registers 6 and 7 */ + temp = 1; + + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + } } - ad1848->freq = freq; - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); - break; - - case 9: - if (!ad1848->enable && (val & 0x41) == 0x01) { - if (ad1848->timer_latch) - timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); - } - ad1848->enable = ((val & 0x41) == 0x01); - if (!ad1848->enable) { - timer_disable(&ad1848->timer_count); - ad1848->out_l = ad1848->out_r = 0; - } - break; - - - case 11: - break; - - case 12: - if (ad1848->type != AD1848_TYPE_DEFAULT) - ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) { /* wavetable remapping */ + ad1848->xregs[ad1848->index - 2] = val; /* real wavetable volume on extended registers 16 and 17 */ + temp = 1; + } + + /* Stop here if any remapping is enabled. */ + if (temp) + return; + + /* HACK: the Windows 9x driver's "Synth" control writes to this + register with no remapping, even if internal FM is enabled. */ + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; + } + } + break; + + case 20: + case 21: + /* Backdoor to the Control/RAM registers on CS4235. */ + if ((ad1848->type == AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) { + ad1848->cram_write(ad1848->index - 15, val, ad1848->cram_priv); + val = ad1848->regs[ad1848->index]; + } + break; + + case 22: + updatefreq = 1; + break; + + case 23: + if ((ad1848->type >= AD1848_TYPE_CS4235) && ((ad1848->regs[12] & 0x60) == 0x60)) { + if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */ + ad1848->xindex = ((val & 0x04) << 2) | (val >> 4); + break; + } + + switch (ad1848->xindex) { + case 0: + case 1: /* remapped line volume */ + ad1848->regs[18 + ad1848->xindex] = val; + return; + + case 6: + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + break; + + case 7: + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + break; + + case 11: + case 13: + updatefreq = 1; + break; + + case 25: + return; + } + ad1848->xregs[ad1848->xindex] = val; + + if (updatefreq) + ad1848_updatefreq(ad1848); + return; - - case 14: - ad1848->count = ad1848->regs[15] | (val << 8); - break; + } + break; - case 24: - if (! (val & 0x70)) - ad1848->status &= 0xfe; - break; + case 24: + val = ad1848->regs[24] & ((val & 0x70) | 0x0f); + if (!(val & 0x70)) { + ad1848->status &= 0xfe; + picintc(1 << ad1848->irq); + } + break; - case 25: - break; - } - ad1848->regs[ad1848->index] = val; + case 25: + return; + } + ad1848->regs[ad1848->index] = val; - if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ - if (ad1848->regs[0x12] & 0x80) - new_cd_vol_l = 0; - else - new_cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; - if (ad1848->regs[0x13] & 0x80) - new_cd_vol_r = 0; - else - new_cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + if (updatefreq) + ad1848_updatefreq(ad1848); - /* Apparently there is no master volume to modulate here - (The windows mixer just adjusts all registers at the same - time when the master slider is adjusted) */ - sound_set_cd_volume(new_cd_vol_l, new_cd_vol_r); - } + if (ad1848->type >= AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ + temp = (ad1848->type == AD1848_TYPE_CS4231) ? 18 : 4; + if (ad1848->regs[temp] & 0x80) + ad1848->cd_vol_l = 0; + else + ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; + temp++; + if (ad1848->regs[temp] & 0x80) + ad1848->cd_vol_r = 0; + else + ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; + } + break; + + case 2: + ad1848->status &= 0xfe; + ad1848->regs[24] &= 0x0f; + break; + } +} + +void +ad1848_speed_changed(ad1848_t *ad1848) +{ + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); +} + +void +ad1848_update(ad1848_t *ad1848) +{ + for (; ad1848->pos < sound_pos_global; ad1848->pos++) { + ad1848->buffer[ad1848->pos * 2] = ad1848->out_l; + ad1848->buffer[ad1848->pos * 2 + 1] = ad1848->out_r; + } +} + +static int16_t +ad1848_process_mulaw(uint8_t byte) +{ + byte = ~byte; + int16_t dec = ((byte & 0x0f) << 3) + 0x84; + dec <<= (byte & 0x70) >> 4; + return (byte & 0x80) ? (0x84 - dec) : (dec - 0x84); +} + +static int16_t +ad1848_process_alaw(uint8_t byte) +{ + byte ^= 0x55; + int16_t dec = (byte & 0x0f) << 4; + int seg = (byte & 0x70) >> 4; + switch (seg) { + case 0: + dec |= 0x8; + break; + + case 1: + dec |= 0x108; + break; + + default: + dec |= 0x108; + dec <<= seg - 1; + break; + } + return (byte & 0x80) ? dec : -dec; +} + +static int16_t +ad1848_process_adpcm(ad1848_t *ad1848) +{ + int temp; + if (ad1848->adpcm_pos++ & 1) { + temp = (ad1848->adpcm_data & 0x0f) + ad1848->adpcm_step; + } else { + ad1848->adpcm_data = dma_channel_read(ad1848->dma); + temp = (ad1848->adpcm_data >> 4) + ad1848->adpcm_step; + } + if (temp < 0) + temp = 0; + else if (temp > 63) + temp = 63; + + ad1848->adpcm_ref += scaleMap4[temp]; + if (ad1848->adpcm_ref > 0xff) + ad1848->adpcm_ref = 0xff; + else if (ad1848->adpcm_ref < 0x00) + ad1848->adpcm_ref = 0x00; + + ad1848->adpcm_step = (ad1848->adpcm_step + adjustMap4[temp]) & 0xff; + + return (ad1848->adpcm_ref ^ 0x80) << 8; +} + +static void +ad1848_poll(void *priv) +{ + ad1848_t *ad1848 = (ad1848_t *) priv; + + if (ad1848->timer_latch) + timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + + ad1848_update(ad1848); + + if (ad1848->enable) { + int32_t temp; + + switch (ad1848->regs[8] & ad1848->fmt_mask) { + case 0x00: /* Mono, 8-bit PCM */ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) << 8; break; - case 2: - ad1848->status &= 0xfe; - break; + + case 0x10: /* Stereo, 8-bit PCM */ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) << 8; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) << 8; + break; + + case 0x20: /* Mono, 8-bit Mu-Law */ + ad1848->out_l = ad1848->out_r = ad1848_process_mulaw(dma_channel_read(ad1848->dma)); + break; + + case 0x30: /* Stereo, 8-bit Mu-Law */ + ad1848->out_l = ad1848_process_mulaw(dma_channel_read(ad1848->dma)); + ad1848->out_r = ad1848_process_mulaw(dma_channel_read(ad1848->dma)); + break; + + case 0x40: /* Mono, 16-bit PCM little endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + + case 0x50: /* Stereo, 16-bit PCM little endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + + case 0x60: /* Mono, 8-bit A-Law */ + ad1848->out_l = ad1848->out_r = ad1848_process_alaw(dma_channel_read(ad1848->dma)); + break; + + case 0x70: /* Stereo, 8-bit A-Law */ + ad1848->out_l = ad1848_process_alaw(dma_channel_read(ad1848->dma)); + ad1848->out_r = ad1848_process_alaw(dma_channel_read(ad1848->dma)); + break; + + /* 0x80 and 0x90 reserved */ + + case 0xa0: /* Mono, 4-bit ADPCM */ + ad1848->out_l = ad1848->out_r = ad1848_process_adpcm(ad1848); + break; + + case 0xb0: /* Stereo, 4-bit ADPCM */ + ad1848->out_l = ad1848_process_adpcm(ad1848); + ad1848->out_r = ad1848_process_adpcm(ad1848); + break; + + case 0xc0: /* Mono, 16-bit PCM big endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; + + case 0xd0: /* Stereo, 16-bit PCM big endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = dma_channel_read(ad1848->dma) | (temp << 8); + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; + + /* 0xe0 and 0xf0 reserved */ } -} -void ad1848_speed_changed(ad1848_t *ad1848) -{ - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); -} - -void ad1848_update(ad1848_t *ad1848) -{ - for (; ad1848->pos < sound_pos_global; ad1848->pos++) - { - ad1848->buffer[ad1848->pos*2] = ad1848->out_l; - ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; - } -} - -static void ad1848_poll(void *p) -{ - ad1848_t *ad1848 = (ad1848_t *)p; - - if (ad1848->timer_latch) - timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; else - timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + ad1848->out_l = (ad1848->out_l * ad1848_vols_7bits[ad1848->regs[6] & ad1848->wave_vol_mask]) >> 16; - ad1848_update(ad1848); - - if (ad1848->enable) - { - int32_t temp; - - switch (ad1848->regs[8] & 0x70) - { - case 0x00: /*Mono, 8-bit PCM*/ - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; - temp = dma_channel_read(ad1848->dma); - ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - } - - if (ad1848->regs[6] & 0x80) - ad1848->out_l = 0; - else - ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; - - if (ad1848->regs[7] & 0x80) - ad1848->out_r = 0; - else - ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; - - if (ad1848->count < 0) - { - ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); - if (!(ad1848->status & 0x01)) - { - ad1848->status |= 0x01; - if (ad1848->regs[10] & 2) - picint(1 << ad1848->irq); - } - } - - ad1848->count--; - } + if (ad1848->regs[7] & 0x80) + ad1848->out_r = 0; else - { - ad1848->out_l = ad1848->out_r = 0; - sound_set_cd_volume(0, 0); + ad1848->out_r = (ad1848->out_r * ad1848_vols_7bits[ad1848->regs[7] & ad1848->wave_vol_mask]) >> 16; + + if (ad1848->count < 0) { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + ad1848->adpcm_pos = 0; + if (!(ad1848->status & 0x01)) { + ad1848->status |= 0x01; + ad1848->regs[24] |= 0x10; + if (ad1848->regs[10] & 2) + picint(1 << ad1848->irq); + } } + + if (!(ad1848->adpcm_pos & 7)) /* ADPCM counts down every 4 bytes */ + ad1848->count--; + } else { + ad1848->out_l = ad1848->out_r = 0; + ad1848->cd_vol_l = ad1848->cd_vol_r = 0; + } } -void ad1848_init(ad1848_t *ad1848, int type) +void +ad1848_filter_cd_audio(int channel, double *buffer, void *priv) { - int c; - double attenuation; - - ad1848->status = 0xcc; - ad1848->index = ad1848->trd = 0; - ad1848->mce = 0x40; - - ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ - ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ - ad1848->regs[8] = 0; - ad1848->regs[9] = 0x08; - ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231)) - ad1848->regs[12] = 0x8a; - else - ad1848->regs[12] = 0xa; - ad1848->regs[13] = 0; - ad1848->regs[14] = ad1848->regs[15] = 0; - - if (type == AD1848_TYPE_CS4231) - { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0x88; - ad1848->regs[22] = 0x80; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4231; - ad1848->regs[26] = 0x80; - ad1848->regs[29] = 0x80; - } - - ad1848->out_l = 0; - ad1848->out_r = 0; - - for (c = 0; c < 64; c++) { - attenuation = 0.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_6bits[c] = (int)(attenuation * 65536); - } - - for (c = 0; c < 32; c++) { - attenuation = 12.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; + ad1848_t *ad1848 = (ad1848_t *) priv; + double c; + double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; - attenuation = pow(10, attenuation / 10); - - ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536); - } - - ad1848->type = type; - - timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + c = ((*buffer) * volume) / 65536.0; + *buffer = c; +} + +void +ad1848_init(ad1848_t *ad1848, uint8_t type) +{ + uint8_t c; + double attenuation; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + ad1848->wten = 0; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type >= AD1848_TYPE_CS4235)) + ad1848->regs[12] = 0x8a; + else + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + if (type == AD1848_TYPE_CS4231) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0x88; + ad1848->regs[22] = 0x80; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4231; + ad1848->regs[26] = 0x80; + ad1848->regs[29] = 0x80; + } else if (type >= AD1848_TYPE_CS4235) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0; + ad1848->regs[20] = ad1848->regs[21] = 0; + ad1848->regs[22] = ad1848->regs[23] = 0; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4236; + ad1848->regs[26] = 0xa0; + ad1848->regs[27] = ad1848->regs[29] = 0; + ad1848->regs[30] = ad1848->regs[31] = 0; + + ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; + ad1848->xregs[2] = ad1848->xregs[3] = 0xcf; + ad1848->xregs[4] = 0x84; + ad1848->xregs[5] = 0; + ad1848->xregs[6] = ad1848->xregs[7] = 0x80; + ad1848->xregs[8] = ad1848->xregs[9] = 0; + ad1848->xregs[10] = 0x3f; + ad1848->xregs[11] = 0xc0; + ad1848->xregs[14] = ad1848->xregs[15] = 0; + ad1848->xregs[16] = ad1848->xregs[17] = 0; + } + + ad1848_updatefreq(ad1848); + + ad1848->out_l = ad1848->out_r = 0; + ad1848->fm_vol_l = ad1848->fm_vol_r = 65536; + ad1848_updatevolmask(ad1848); + if (type == AD1848_TYPE_CS4235) + ad1848->fmt_mask = 0x50; + else + ad1848->fmt_mask = 0x70; + + for (c = 0; c < 128; c++) { + attenuation = 0.0; + if (c & 0x40) { + if (c < 72) + attenuation = (c - 72) * -1.5; + } else { + if (c & 0x01) + attenuation -= 1.5; + if (c & 0x02) + attenuation -= 3.0; + if (c & 0x04) + attenuation -= 6.0; + if (c & 0x08) + attenuation -= 12.0; + if (c & 0x10) + attenuation -= 24.0; + if (c & 0x20) + attenuation -= 48.0; + } + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_7bits[c] = (int) (attenuation * 65536); + } + + for (c = 0; c < 32; c++) { + attenuation = 12.0; + if (c & 0x01) + attenuation -= 1.5; + if (c & 0x02) + attenuation -= 3.0; + if (c & 0x04) + attenuation -= 6.0; + if (c & 0x08) + attenuation -= 12.0; + if (c & 0x10) + attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); + } + + ad1848->type = type; + + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + + if ((ad1848->type != AD1848_TYPE_DEFAULT) && (ad1848->type != AD1848_TYPE_CS4248)) + sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 2b9dfb443..d4bc1e3ca 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -1,145 +1,169 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/io.h> -#include <86box/timer.h> -#include <86box/mca.h> -#include <86box/device.h> -#include <86box/sound.h> -#include <86box/snd_opl.h> +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mca.h> +#include <86box/sound.h> +#include <86box/timer.h> +#include <86box/snd_opl.h> #ifdef ENABLE_ADLIB_LOG int adlib_do_log = ENABLE_ADLIB_LOG; - static void adlib_log(const char *fmt, ...) { va_list ap; if (adlib_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define adlib_log(fmt, ...) +# define adlib_log(fmt, ...) #endif +typedef struct adlib_t { + fm_drv_t opl; -typedef struct adlib_t -{ - opl_t opl; - - uint8_t pos_regs[8]; + uint8_t pos_regs[8]; } adlib_t; - -static void adlib_get_buffer(int32_t *buffer, int len, void *p) +static void +adlib_get_buffer(int32_t *buffer, int len, void *p) { - adlib_t *adlib = (adlib_t *)p; - int c; + adlib_t *adlib = (adlib_t *) p; + int c; - opl2_update2(&adlib->opl); - - for (c = 0; c < len * 2; c++) - buffer[c] += (int32_t)adlib->opl.buffer[c]; + int32_t *opl_buf = adlib->opl.update(adlib->opl.priv); - adlib->opl.pos = 0; + for (c = 0; c < len * 2; c++) + buffer[c] += (int32_t) opl_buf[c]; + + adlib->opl.reset_buffer(adlib->opl.priv); } -uint8_t adlib_mca_read(int port, void *p) +uint8_t +adlib_mca_read(int port, void *p) { - adlib_t *adlib = (adlib_t *)p; - - adlib_log("adlib_mca_read: port=%04x\n", port); - - return adlib->pos_regs[port & 7]; + adlib_t *adlib = (adlib_t *) p; + + adlib_log("adlib_mca_read: port=%04x\n", port); + + return adlib->pos_regs[port & 7]; } -void adlib_mca_write(int port, uint8_t val, void *p) +void +adlib_mca_write(int port, uint8_t val, void *p) { - adlib_t *adlib = (adlib_t *)p; + adlib_t *adlib = (adlib_t *) p; - if (port < 0x102) - return; - - adlib_log("adlib_mca_write: port=%04x val=%02x\n", port, val); - - switch (port) - { - case 0x102: - if ((adlib->pos_regs[2] & 1) && !(val & 1)) - io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - if (!(adlib->pos_regs[2] & 1) && (val & 1)) - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - break; - } - adlib->pos_regs[port & 7] = val; + if (port < 0x102) + return; + + adlib_log("adlib_mca_write: port=%04x val=%02x\n", port, val); + + switch (port) { + case 0x102: + if ((adlib->pos_regs[2] & 1) && !(val & 1)) + io_removehandler(0x0388, 0x0002, + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); + if (!(adlib->pos_regs[2] & 1) && (val & 1)) + io_sethandler(0x0388, 0x0002, + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); + break; + } + adlib->pos_regs[port & 7] = val; } -uint8_t adlib_mca_feedb(void *p) +uint8_t +adlib_mca_feedb(void *p) { - adlib_t *adlib = (adlib_t *)p; + adlib_t *adlib = (adlib_t *) p; - return (adlib->pos_regs[2] & 1); + return (adlib->pos_regs[2] & 1); } - -void *adlib_init(const device_t *info) +void * +adlib_init(const device_t *info) { - adlib_t *adlib = malloc(sizeof(adlib_t)); - memset(adlib, 0, sizeof(adlib_t)); - - adlib_log("adlib_init\n"); - opl2_init(&adlib->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - sound_add_handler(adlib_get_buffer, adlib); - return adlib; + adlib_t *adlib = malloc(sizeof(adlib_t)); + memset(adlib, 0, sizeof(adlib_t)); + + adlib_log("adlib_init\n"); + fm_driver_get(FM_YM3812, &adlib->opl); + io_sethandler(0x0388, 0x0002, + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); + sound_add_handler(adlib_get_buffer, adlib); + return adlib; } -void *adlib_mca_init(const device_t *info) +void * +adlib_mca_init(const device_t *info) { - adlib_t *adlib = adlib_init(info); - - io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - mca_add(adlib_mca_read, adlib_mca_write, adlib_mca_feedb, NULL, adlib); - adlib->pos_regs[0] = 0xd7; - adlib->pos_regs[1] = 0x70; + adlib_t *adlib = adlib_init(info); - return adlib; + io_removehandler(0x0388, 0x0002, + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); + mca_add(adlib_mca_read, + adlib_mca_write, + adlib_mca_feedb, + NULL, + adlib); + adlib->pos_regs[0] = 0xd7; + adlib->pos_regs[1] = 0x70; + + return adlib; } -void adlib_close(void *p) +void +adlib_close(void *p) { - adlib_t *adlib = (adlib_t *)p; - - free(adlib); + adlib_t *adlib = (adlib_t *) p; + free(adlib); } -const device_t adlib_device = -{ - "AdLib", - DEVICE_ISA, - 0, - adlib_init, adlib_close, NULL, - NULL, NULL, NULL, - NULL +const device_t adlib_device = { + .name = "AdLib", + .internal_name = "adlib", + .flags = DEVICE_ISA, + .local = 0, + .init = adlib_init, + .close = adlib_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t adlib_mca_device = -{ - "AdLib (MCA)", - DEVICE_MCA, - 0, - adlib_init, adlib_close, NULL, - NULL, NULL, NULL, - NULL +const device_t adlib_mca_device = { + .name = "AdLib (MCA)", + .internal_name = "adlib_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = adlib_init, + .close = adlib_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 09a51994b..a15174b45 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -1,851 +1,1094 @@ -#include #include -#include +#include #include +#include #include + #include <86box/86box.h> -#include <86box/io.h> -#include <86box/timer.h> -#include <86box/dma.h> -#include <86box/pic.h> #include <86box/device.h> -#include <86box/nvr.h> -#include <86box/sound.h> +#include <86box/dma.h> #include <86box/filters.h> +#include <86box/gameport.h> +#include <86box/io.h> +#include <86box/midi.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/pic.h> +#include <86box/sound.h> #include <86box/snd_opl.h> #include <86box/snd_ym7128.h> +typedef struct adgold_t { + int adgold_irq_status; + int irq, dma, hdma; -typedef struct adgold_t -{ - int adgold_irq_status; + uint8_t adgold_eeprom[0x1a]; - uint8_t adgold_eeprom[0x1a]; + uint8_t adgold_status; + int adgold_38x_state, adgold_38x_addr; + uint8_t adgold_38x_regs[0x1a]; - uint8_t adgold_status; - int adgold_38x_state, adgold_38x_addr; - uint8_t adgold_38x_regs[0x1a]; + int adgold_mma_addr; + uint8_t adgold_mma_regs[2][0xe]; - int adgold_mma_addr; - uint8_t adgold_mma_regs[2][0xe]; + int adgold_mma_enable[2]; + uint8_t adgold_mma_fifo[2][256]; + int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2]; + uint8_t adgold_mma_status; - int adgold_mma_enable[2]; - uint8_t adgold_mma_fifo[2][256]; - int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2]; - uint8_t adgold_mma_status; + int16_t adgold_mma_out[2]; + int adgold_mma_intpos[2]; - int16_t adgold_mma_out[2]; - int adgold_mma_intpos[2]; + pc_timer_t adgold_mma_timer_count; - pc_timer_t adgold_mma_timer_count; + uint8_t adgold_midi_ctrl, midi_queue[16]; + int midi_r, midi_w; + int uart_in, uart_out, sysex; - struct - { - int timer0_latch, timer0_count; - int timerbase_latch, timerbase_count; - int timer1_latch, timer1_count; - int timer2_latch, timer2_count, timer2_read; - - int voice_count[2], voice_latch[2]; - } adgold_mma; + struct + { + int timer0_latch, timer0_count; + int timerbase_latch, timerbase_count; + int timer1_latch, timer1_count; + int timer2_latch, timer2_count, timer2_read; - opl_t opl; - ym7128_t ym7128; - - int fm_vol_l, fm_vol_r; - int samp_vol_l, samp_vol_r; - int vol_l, vol_r; - int treble, bass; + int voice_count[2], voice_latch[2]; + } adgold_mma; - int16_t opl_buffer[SOUNDBUFLEN * 2]; - int16_t mma_buffer[2][SOUNDBUFLEN]; + fm_drv_t opl; + ym7128_t ym7128; - int pos; - - int surround_enabled; + int fm_vol_l, fm_vol_r; + int samp_vol_l, samp_vol_r; + int aux_vol_l, aux_vol_r; + int vol_l, vol_r; + int treble, bass; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t mma_buffer[2][SOUNDBUFLEN]; + + int pos; + + int gameport_enabled; + + int surround_enabled; } adgold_t; static int attenuation[0x40]; -static int bass_attenuation[0x10] = -{ - (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ - (int)(1.995 * 16384), - (int)(1.995 * 16384), - (int)(1.413 * 16384), /*9 dB*/ - (int)(1 * 16384), /*6 dB*/ - (int)(0.708 * 16384), /*3 dB*/ - (int)(0 * 16384), /*0 dB*/ - (int)(0.708 * 16384), /*3 dB*/ - (int)(1 * 16384), /*6 dB*/ - (int)(1.413 * 16384), /*9 dB*/ - (int)(1.995 * 16384), /*12 dB*/ - (int)(2.819 * 16384), /*15 dB*/ - (int)(2.819 * 16384), - (int)(2.819 * 16384), - (int)(2.819 * 16384), - (int)(2.819 * 16384) +static int bass_attenuation[0x10] = { + (int) (1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int) (1.995 * 16384), + (int) (1.995 * 16384), + (int) (1.413 * 16384), /*9 dB*/ + (int) (1 * 16384), /*6 dB*/ + (int) (0.708 * 16384), /*3 dB*/ + (int) (0 * 16384), /*0 dB*/ + (int) (0.708 * 16384), /*3 dB*/ + (int) (1 * 16384), /*6 dB*/ + (int) (1.413 * 16384), /*9 dB*/ + (int) (1.995 * 16384), /*12 dB*/ + (int) (2.819 * 16384), /*15 dB*/ + (int) (2.819 * 16384), + (int) (2.819 * 16384), + (int) (2.819 * 16384), + (int) (2.819 * 16384) }; -static int bass_cut[6] = -{ - (int)(0.126 * 16384), /*-12 dB*/ - (int)(0.126 * 16384), /*-12 dB*/ - (int)(0.126 * 16384), /*-12 dB*/ - (int)(0.178 * 16384), /*-9 dB*/ - (int)(0.251 * 16384), /*-6 dB*/ - (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +static int bass_cut[6] = { + (int) (0.126 * 16384), /*-12 dB*/ + (int) (0.126 * 16384), /*-12 dB*/ + (int) (0.126 * 16384), /*-12 dB*/ + (int) (0.178 * 16384), /*-9 dB*/ + (int) (0.251 * 16384), /*-6 dB*/ + (int) (0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ }; -static int treble_attenuation[0x10] = -{ - (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ - (int)(1.995 * 16384), - (int)(1.995 * 16384), - (int)(1.413 * 16384), /*9 dB*/ - (int)(1 * 16384), /*6 dB*/ - (int)(0.708 * 16384), /*3 dB*/ - (int)(0 * 16384), /*0 dB*/ - (int)(0.708 * 16384), /*3 dB*/ - (int)(1 * 16384), /*6 dB*/ - (int)(1.413 * 16384), /*9 dB*/ - (int)(1.995 * 16384), /*12 dB*/ - (int)(1.995 * 16384), - (int)(1.995 * 16384), - (int)(1.995 * 16384), - (int)(1.995 * 16384), - (int)(1.995 * 16384) +static int treble_attenuation[0x10] = { + (int) (1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int) (1.995 * 16384), + (int) (1.995 * 16384), + (int) (1.413 * 16384), /*9 dB*/ + (int) (1 * 16384), /*6 dB*/ + (int) (0.708 * 16384), /*3 dB*/ + (int) (0 * 16384), /*0 dB*/ + (int) (0.708 * 16384), /*3 dB*/ + (int) (1 * 16384), /*6 dB*/ + (int) (1.413 * 16384), /*9 dB*/ + (int) (1.995 * 16384), /*12 dB*/ + (int) (1.995 * 16384), + (int) (1.995 * 16384), + (int) (1.995 * 16384), + (int) (1.995 * 16384), + (int) (1.995 * 16384) }; -static int treble_cut[6] = -{ - (int)(0.126 * 16384), /*-12 dB*/ - (int)(0.126 * 16384), /*-12 dB*/ - (int)(0.126 * 16384), /*-12 dB*/ - (int)(0.178 * 16384), /*-9 dB*/ - (int)(0.251 * 16384), /*-6 dB*/ - (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +static int treble_cut[6] = { + (int) (0.126 * 16384), /*-12 dB*/ + (int) (0.126 * 16384), /*-12 dB*/ + (int) (0.126 * 16384), /*-12 dB*/ + (int) (0.178 * 16384), /*-9 dB*/ + (int) (0.251 * 16384), /*-6 dB*/ + (int) (0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ }; void adgold_timer_poll(); void adgold_update(adgold_t *adgold); -void adgold_update_irq_status(adgold_t *adgold) +void +adgold_update_irq_status(adgold_t *adgold) { - uint8_t temp = 0xf; + uint8_t temp = 0xf; - if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/ - temp &= ~2; - if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/ - temp &= ~2; - if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/ - temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][0xd] & 0x01) && (adgold->adgold_mma_status & 0x04)) + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][0xd] & 0x04) && (adgold->adgold_mma_status & 0x08)) + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][0xd] & 0x10) && (adgold->adgold_mma_status & 0x80)) + temp &= ~2; + if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2)) + temp &= ~2; + if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) + temp &= ~2; + adgold->adgold_status = temp; - if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2)) - temp &= ~2; - if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) - temp &= ~2; - adgold->adgold_status = temp; - - if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) - { - picint(0x80); - } - - adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; + if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) { + picint(1 << adgold->irq); + } + + adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; } -void adgold_getsamp_dma(adgold_t *adgold, int channel) +void +adgold_getsamp_dma(adgold_t *adgold, int channel) { - int temp; - - if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) - return; - - temp = dma_channel_read(1); - if (temp == DMA_NODATA) return; + int temp; + dma_set_drq(adgold->dma, 1); + + if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) + return; + + temp = dma_channel_read(adgold->dma); + if (temp == DMA_NODATA) { + return; + } + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + if (adgold->adgold_mma_regs[channel][0xc] & 0x60) { + temp = dma_channel_read(adgold->dma); adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; - if (adgold->adgold_mma_regs[channel][0xc] & 0x60) - { - temp = dma_channel_read(1); - adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; - adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; - } - if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) - { - adgold->adgold_mma_status &= ~(0x01 << channel); - adgold_update_irq_status(adgold); - } + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) { + adgold->adgold_mma_status &= ~(0x01 << channel); + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } } -void adgold_write(uint16_t addr, uint8_t val, void *p) +void +adgold_write(uint16_t addr, uint8_t val, void *p) { - adgold_t *adgold = (adgold_t *)p; - switch (addr & 7) - { - case 0: case 1: - opl3_write(addr, val, &adgold->opl); - break; + adgold_t *adgold = (adgold_t *) p; + switch (addr & 7) { + case 0: + case 1: + adgold->opl.write(addr, val, adgold->opl.priv); + break; - case 2: - if (val == 0xff) - { - adgold->adgold_38x_state = 1; - return; - } - if (val == 0xfe) - { - adgold->adgold_38x_state = 0; - return; - } - if (adgold->adgold_38x_state) /*Write to control chip*/ - adgold->adgold_38x_addr = val; - else - opl3_write(addr, val, &adgold->opl); - break; - case 3: - if (adgold->adgold_38x_state) - { - if (adgold->adgold_38x_addr >= 0x19) break; - switch (adgold->adgold_38x_addr) - { - case 0x00: /*Control/ID*/ - if (val & 1) - memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x1a); - if (val & 2) - memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x1a); - break; - - case 0x04: /*Final output volume left*/ - adgold->adgold_38x_regs[0x04] = val; - adgold->vol_l = attenuation[val & 0x3f]; - break; - case 0x05: /*Final output volume right*/ - adgold->adgold_38x_regs[0x05] = val; - adgold->vol_r = attenuation[val & 0x3f]; - break; - case 0x06: /*Bass*/ - adgold->adgold_38x_regs[0x06] = val; - adgold->bass = val & 0xf; - break; - case 0x07: /*Treble*/ - adgold->adgold_38x_regs[0x07] = val; - adgold->treble = val & 0xf; - break; - - case 0x09: /*FM volume left*/ - adgold->adgold_38x_regs[0x09] = val; - adgold->fm_vol_l = (int)(int8_t)(val - 128); - break; - case 0x0a: /*FM volume right*/ - adgold->adgold_38x_regs[0x0a] = val; - adgold->fm_vol_r = (int)(int8_t)(val - 128); - break; - case 0x0b: /*Sample volume left*/ - adgold->adgold_38x_regs[0x0b] = val; - adgold->samp_vol_l = (int)(int8_t)(val - 128); - break; - case 0x0c: /*Sample volume right*/ - adgold->adgold_38x_regs[0x0c] = val; - adgold->samp_vol_r = (int)(int8_t)(val - 128); - break; - - case 0x18: /*Surround*/ - adgold->adgold_38x_regs[0x18] = val; - ym7128_write(&adgold->ym7128, val); - break; - - default: - adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; - break; - } - } - else - opl3_write(addr, val, &adgold->opl); - break; - case 4: case 6: - adgold->adgold_mma_addr = val; - break; - case 5: - if (adgold->adgold_mma_addr >= 0xf) break; - switch (adgold->adgold_mma_addr) - { - case 0x2: - adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val; + case 2: + if (val == 0xff) { + adgold->adgold_38x_state = 1; + return; + } + if (val == 0xfe) { + adgold->adgold_38x_state = 0; + return; + } + if (adgold->adgold_38x_state) /*Write to control chip*/ + adgold->adgold_38x_addr = val; + else + adgold->opl.write(addr, val, adgold->opl.priv); + break; + case 3: + if (adgold->adgold_38x_state) { + if (adgold->adgold_38x_addr >= 0x19) + break; + switch (adgold->adgold_38x_addr) { + case 0x00: /*Control/ID*/ + if (val & 1) + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x1a); + if (val & 2) + memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x1a); break; - case 0x3: - adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8); - break; - case 0x4: - adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val; - break; - case 0x5: - adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8); - adgold->adgold_mma.timer1_latch = val >> 4; - break; - case 0x6: - adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val; - break; - case 0x7: - adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8); - break; - - case 0x8: - if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/ - adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; - - if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/ - adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; - if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/ - adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + case 0x04: /*Final output volume left*/ + adgold->adgold_38x_regs[0x04] = val; + adgold->vol_l = attenuation[val & 0x3f]; + break; + case 0x05: /*Final output volume right*/ + adgold->adgold_38x_regs[0x05] = val; + adgold->vol_r = attenuation[val & 0x3f]; + break; + case 0x06: /*Bass*/ + adgold->adgold_38x_regs[0x06] = val; + adgold->bass = val & 0xf; + break; + case 0x07: /*Treble*/ + adgold->adgold_38x_regs[0x07] = val; + adgold->treble = val & 0xf; + break; - if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/ - adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + case 0x09: /*FM volume left*/ + adgold->adgold_38x_regs[0x09] = val; + adgold->fm_vol_l = (int) (int8_t) (val - 128); + break; + case 0x0a: /*FM volume right*/ + adgold->adgold_38x_regs[0x0a] = val; + adgold->fm_vol_r = (int) (int8_t) (val - 128); + break; + case 0x0b: /*Sample volume left*/ + adgold->adgold_38x_regs[0x0b] = val; + adgold->samp_vol_l = (int) (int8_t) (val - 128); + break; + case 0x0c: /*Sample volume right*/ + adgold->adgold_38x_regs[0x0c] = val; + adgold->samp_vol_r = (int) (int8_t) (val - 128); + break; + case 0x0d: /*Aux volume left*/ + adgold->adgold_38x_regs[0x0d] = val; + adgold->aux_vol_l = (int) (int8_t) (val - 128); + break; + case 0x0e: /*Aux volume right*/ + adgold->adgold_38x_regs[0x0e] = val; + adgold->aux_vol_r = (int) (int8_t) (val - 128); break; - - case 0x9: - switch (val & 0x18) - { - case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/ - case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/ - case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/ - case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/ - } - if (val & 0x80) - { - adgold->adgold_mma_enable[0] = 0; - adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0; - adgold->adgold_mma_status &= ~0x01; - adgold_update_irq_status(adgold); - } - if ((val & 0x01)) /*Start playback*/ - { - if (!(adgold->adgold_mma_regs[0][0x9] & 1)) - adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; - - if (adgold->adgold_mma_regs[0][0xc] & 1) - { - if (adgold->adgold_mma_regs[0][0xc] & 0x80) - { - adgold->adgold_mma_enable[1] = 1; - adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; - while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) - { - adgold_getsamp_dma(adgold, 0); - adgold_getsamp_dma(adgold, 1); - } - if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) - { - adgold->adgold_mma_status &= ~0x01; - adgold_update_irq_status(adgold); - } - if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) - { - adgold->adgold_mma_status &= ~0x02; - adgold_update_irq_status(adgold); - } - } - else - { - while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) - { - adgold_getsamp_dma(adgold, 0); - } - if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) - { - adgold->adgold_mma_status &= ~0x01; - adgold_update_irq_status(adgold); - } - } - } - } - adgold->adgold_mma_enable[0] = val & 0x01; + case 0x18: /*Surround*/ + adgold->adgold_38x_regs[0x18] = val; + ym7128_write(&adgold->ym7128, val); break; - - case 0xb: - if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) - { - adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val; - adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255; - if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) - { - adgold->adgold_mma_status &= ~0x01; - adgold_update_irq_status(adgold); - } - } - break; - - case 0xc: - adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8; + + default: + adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; break; } - adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; + } else + adgold->opl.write(addr, val, adgold->opl.priv); + break; + case 4: + case 6: + adgold->adgold_mma_addr = val; + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) break; - case 7: - if (adgold->adgold_mma_addr >= 0xe) break; - switch (adgold->adgold_mma_addr) - { - case 0x9: - adgold_update(adgold); - switch (val & 0x18) - { - case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/ - case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/ - case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/ - case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/ - } - if (val & 0x80) - { - adgold->adgold_mma_enable[1] = 0; - adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0; - adgold->adgold_mma_status &= ~0x02; - adgold_update_irq_status(adgold); - } - if ((val & 0x01)) /*Start playback*/ - { - if (!(adgold->adgold_mma_regs[1][0x9] & 1)) - adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; - - if (adgold->adgold_mma_regs[1][0xc] & 1) - { - while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) - { - adgold_getsamp_dma(adgold, 1); - } - } - } - adgold->adgold_mma_enable[1] = val & 0x01; - break; - - case 0xb: - if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) - { - adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val; - adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255; - if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) - { - adgold->adgold_mma_status &= ~0x02; - adgold_update_irq_status(adgold); - } - } - break; + switch (adgold->adgold_mma_addr) { + case 0x2: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val; + break; + case 0x3: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8); + break; + case 0x4: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val; + break; + case 0x5: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8); + adgold->adgold_mma.timer1_latch = val >> 4; + break; + case 0x6: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val; + break; + case 0x7: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8); + break; - case 0xc: - adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8; - break; - } - adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val; - break; - } -} + case 0x8: + if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/ + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; -uint8_t adgold_read(uint16_t addr, void *p) -{ - adgold_t *adgold = (adgold_t *)p; - uint8_t temp = 0; - - switch (addr & 7) - { - case 0: case 1: - temp = opl3_read(addr, &adgold->opl); - break; - - case 2: - if (adgold->adgold_38x_state) /*Read from control chip*/ - temp = adgold->adgold_status; - else - temp = opl3_read(addr, &adgold->opl); - break; - - case 3: - if (adgold->adgold_38x_state) - { - if (adgold->adgold_38x_addr >= 0x19) temp = 0xff; - switch (adgold->adgold_38x_addr) - { - case 0x00: /*Control/ID*/ - if (adgold->surround_enabled) - temp = 0x50; /*16-bit ISA, surround module, no telephone/CDROM*/ - else - temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ - break; - - default: - temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; - } - } - else - temp = opl3_read(addr, &adgold->opl); - break; + if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/ + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; - case 4: case 6: - temp = adgold->adgold_mma_status; - adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/ - adgold_update_irq_status(adgold); - break; - case 5: - if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; - switch (adgold->adgold_mma_addr) - { - case 6: /*Timer 2 low*/ - adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count; - temp = adgold->adgold_mma.timer2_read & 0xff; - break; - case 7: /*Timer 2 high*/ - temp = adgold->adgold_mma.timer2_read >> 8; - break; - - default: - temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr]; - break; - } - break; - case 7: - if (adgold->adgold_mma_addr >= 0xf) - temp = 0xff; - else - temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; - break; - } - return temp; -} + if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/ + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; -void adgold_update(adgold_t *adgold) -{ - for (; adgold->pos < sound_pos_global; adgold->pos++) - { - adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0; - - if (adgold->adgold_mma_regs[0][9] & 0x20) - adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2; - if (adgold->adgold_mma_regs[0][9] & 0x40) - adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2; + if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/ + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + break; - if (adgold->adgold_mma_regs[1][9] & 0x20) - adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2; - if (adgold->adgold_mma_regs[1][9] & 0x40) - adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2; - } -} - -void adgold_mma_poll(adgold_t *adgold, int channel) -{ - int16_t dat; - - adgold_update(adgold); - - if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel]) - { - switch (adgold->adgold_mma_regs[channel][0xc] & 0x60) - { - case 0x00: /*8-bit*/ - dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256; - adgold->adgold_mma_out[channel] = dat; - adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; - break; - - case 0x40: /*12-bit sensible format*/ - if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2) - return; - - dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0; - adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; - dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8); - adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; - adgold->adgold_mma_out[channel] = dat; - break; - } - - if (adgold->adgold_mma_regs[channel][0xc] & 1) - { - adgold_getsamp_dma(adgold, channel); - } - if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) - { - adgold->adgold_mma_status |= 1 << channel; + case 0x9: + switch (val & 0x18) { + case 0x00: + adgold->adgold_mma.voice_latch[0] = 12; + break; /*44100 Hz*/ + case 0x08: + adgold->adgold_mma.voice_latch[0] = 24; + break; /*22050 Hz*/ + case 0x10: + adgold->adgold_mma.voice_latch[0] = 48; + break; /*11025 Hz*/ + case 0x18: + adgold->adgold_mma.voice_latch[0] = 72; + break; /* 7350 Hz*/ + } + if (val & 0x80) { + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0; + adgold->adgold_mma_status &= ~0x01; adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[0][0x9] & 1)) + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + + if (adgold->adgold_mma_regs[0][0xc] & 1) { + if (adgold->adgold_mma_regs[0][0xc] & 0x80) { + adgold->adgold_mma_enable[1] = 1; + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) { + adgold_getsamp_dma(adgold, 0); + adgold_getsamp_dma(adgold, 1); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + } else { + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) { + adgold_getsamp_dma(adgold, 0); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + } + } + } + adgold->adgold_mma_enable[0] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) { + adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val; + adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8; + break; + + case 0xd: + adgold->adgold_midi_ctrl = val & 0x3f; + + if ((adgold->adgold_midi_ctrl & 0x0f) != 0x0f) { + if ((adgold->adgold_midi_ctrl & 0x0f) == 0x00) { + adgold->uart_out = 0; + adgold->uart_in = 0; + adgold->midi_w = 0; + adgold->midi_r = 0; + adgold->adgold_mma_status &= ~0x8c; + } else { + if (adgold->adgold_midi_ctrl & 0x01) + adgold->uart_in = 1; + if (adgold->adgold_midi_ctrl & 0x04) + adgold->uart_out = 1; + if (adgold->adgold_midi_ctrl & 0x02) { + adgold->uart_in = 0; + adgold->midi_w = 0; + adgold->midi_r = 0; + } + if (adgold->adgold_midi_ctrl & 0x08) + adgold->uart_out = 0; + adgold->adgold_mma_status &= ~0x80; + } + } else + adgold->adgold_mma_status &= ~0x8c; + + adgold_update_irq_status(adgold); + break; + + case 0xe: + if (adgold->uart_out) { + midi_raw_out_byte(val); + + adgold->adgold_mma_status &= ~0x08; + adgold_update_irq_status(adgold); + } + break; + } + adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; + break; + case 7: + if (adgold->adgold_mma_addr >= 0xe) + break; + switch (adgold->adgold_mma_addr) { + case 0x9: + adgold_update(adgold); + switch (val & 0x18) { + case 0x00: + adgold->adgold_mma.voice_latch[1] = 12; + break; /*44100 Hz*/ + case 0x08: + adgold->adgold_mma.voice_latch[1] = 24; + break; /*22050 Hz*/ + case 0x10: + adgold->adgold_mma.voice_latch[1] = 48; + break; /*11025 Hz*/ + case 0x18: + adgold->adgold_mma.voice_latch[1] = 72; + break; /* 7350 Hz*/ + } + if (val & 0x80) { + adgold->adgold_mma_enable[1] = 0; + adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0; + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[1][0x9] & 1)) + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + if (adgold->adgold_mma_regs[1][0xc] & 1) { + while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) { + adgold_getsamp_dma(adgold, 1); + } + } + } + adgold->adgold_mma_enable[1] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) { + adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val; + adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + dma_set_drq(adgold->dma, 0); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val; + break; + } +} + +uint8_t +adgold_read(uint16_t addr, void *p) +{ + adgold_t *adgold = (adgold_t *) p; + uint8_t temp = 0; + + switch (addr & 7) { + case 0: + case 1: + temp = adgold->opl.read(addr, adgold->opl.priv); + break; + + case 2: + if (adgold->adgold_38x_state) /*Read from control chip*/ + temp = adgold->adgold_status; + else + temp = adgold->opl.read(addr, adgold->opl.priv); + break; + + case 3: + if (adgold->adgold_38x_state) { + if (adgold->adgold_38x_addr >= 0x19) + temp = 0xff; + switch (adgold->adgold_38x_addr) { + case 0x00: /*Control/ID*/ + if (adgold->surround_enabled) + temp = 0x51; /*8-bit ISA, surround module, no telephone/CD-ROM*/ + else + temp = 0x71; /*8-bit ISA, no telephone/surround/CD-ROM*/ + break; + + default: + temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; + break; } - } - if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel]) - { - adgold->adgold_mma_enable[channel] = 0; - } + } else + temp = adgold->opl.read(addr, adgold->opl.priv); + break; + + case 4: + case 6: + temp = adgold->adgold_mma_status; + adgold->adgold_mma_status &= ~0xf3; /*JUKEGOLD expects timer status flags to auto-clear*/ + adgold_update_irq_status(adgold); + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) + temp = 0xff; + switch (adgold->adgold_mma_addr) { + case 6: /*Timer 2 low*/ + adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count; + adgold->adgold_mma_status |= 0x40; + temp = adgold->adgold_mma.timer2_read & 0xff; + break; + case 7: /*Timer 2 high*/ + temp = adgold->adgold_mma.timer2_read >> 8; + break; + + case 0xe: + temp = 0; + if (adgold->uart_in) { + temp = adgold->midi_queue[adgold->midi_r]; + if (adgold->midi_r != adgold->midi_w) { + adgold->midi_r++; + adgold->midi_r &= 0x0f; + } + adgold->adgold_mma_status &= ~0x04; + adgold_update_irq_status(adgold); + } + break; + + default: + temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr]; + break; + } + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) + temp = 0xff; + else + temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; + break; + } + return temp; } -void adgold_timer_poll(void *p) +void +adgold_update(adgold_t *adgold) { - adgold_t *adgold = (adgold_t *)p; - - timer_advance_u64(&adgold->adgold_mma_timer_count, (uint64_t)((double)TIMER_USEC * 1.88964)); - if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ - { - adgold->adgold_mma.timer0_count--; - if (!adgold->adgold_mma.timer0_count) - { - adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; - adgold->adgold_mma_status |= 0x10; - adgold_update_irq_status(adgold); - } - } - if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ - { - adgold->adgold_mma.timerbase_count--; - if (!adgold->adgold_mma.timerbase_count) - { - adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; - if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ - { - adgold->adgold_mma.timer1_count--; - if (!adgold->adgold_mma.timer1_count) - { - adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; - adgold->adgold_mma_status |= 0x20; - adgold_update_irq_status(adgold); - } - } - if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ - { - adgold->adgold_mma.timer2_count--; - if (!adgold->adgold_mma.timer2_count) - { - adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; - adgold->adgold_mma_status |= 0x40; - adgold_update_irq_status(adgold); - } - } - } - } + for (; adgold->pos < sound_pos_global; adgold->pos++) { + adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0; - if (adgold->adgold_mma_enable[0]) - { - adgold->adgold_mma.voice_count[0]--; - if (!adgold->adgold_mma.voice_count[0]) - { - adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; - adgold_mma_poll(adgold, 0); - } - } - if (adgold->adgold_mma_enable[1]) - { - adgold->adgold_mma.voice_count[1]--; - if (!adgold->adgold_mma.voice_count[1]) - { - adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; - adgold_mma_poll(adgold, 1); - } - } + if (adgold->adgold_mma_regs[0][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2; + if (adgold->adgold_mma_regs[0][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2; + + if (adgold->adgold_mma_regs[1][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2; + if (adgold->adgold_mma_regs[1][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2; + } } -static void adgold_get_buffer(int32_t *buffer, int len, void *p) +void +adgold_mma_poll(adgold_t *adgold, int channel) { - adgold_t *adgold = (adgold_t *)p; - int16_t* adgold_buffer = malloc(sizeof(int16_t) * len * 2); - if (adgold_buffer == NULL) fatal("adgold_buffer = NULL"); - - int c; + int16_t dat; - opl3_update2(&adgold->opl); - adgold_update(adgold); - - for (c = 0; c < len * 2; c += 2) - { - adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2; - adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; - adgold_buffer[c+1] = ((adgold->opl.buffer[c+1] * adgold->fm_vol_r) >> 7) / 2; - adgold_buffer[c+1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + adgold_update(adgold); + + if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel]) { + switch (adgold->adgold_mma_regs[channel][0xc] & 0x60) { + case 0x00: /*8-bit*/ + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256; + adgold->adgold_mma_out[channel] = dat; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + break; + + case 0x40: /*12-bit sensible format*/ + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2) + return; + + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8); + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + adgold->adgold_mma_out[channel] = dat; + break; } - if (adgold->surround_enabled) - ym7128_apply(&adgold->ym7128, adgold_buffer, len); - - switch (adgold->adgold_38x_regs[0x8] & 6) - { - case 0: - for (c = 0; c < len * 2; c++) - adgold_buffer[c] = 0; - break; - case 2: /*Left channel only*/ - for (c = 0; c < len * 2; c += 2) - adgold_buffer[c+1] = adgold_buffer[c]; - break; - case 4: /*Right channel only*/ - for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] = adgold_buffer[c+1]; - break; - case 6: /*Left and right channels*/ - break; + if (adgold->adgold_mma_regs[channel][0xc] & 1) { + adgold_getsamp_dma(adgold, channel); } - - switch (adgold->adgold_38x_regs[0x8] & 0x18) - { - case 0x00: /*Forced mono*/ - for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] = adgold_buffer[c+1] = ((int32_t)adgold_buffer[c] + (int32_t)adgold_buffer[c+1]) / 2; - break; - case 0x08: /*Linear stereo*/ - break; - case 0x10: /*Pseudo stereo*/ - /*Filter left channel, leave right channel unchanged*/ - /*Filter cutoff is largely a guess*/ - for (c = 0; c < len * 2; c += 2) - adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); - break; - case 0x18: /*Spatial stereo*/ - /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet - and a very vague understanding of how op-amps work to go on*/ - for (c = 0; c < len * 2; c += 2) - { - int16_t l = adgold_buffer[c]; - int16_t r = adgold_buffer[c+1]; - - adgold_buffer[c] += (r / 3) + ((l * 2) / 3); - adgold_buffer[c+1] += (l / 3) + ((r * 2) / 3); + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) { + adgold->adgold_mma_status |= 1 << channel; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel]) { + adgold->adgold_mma_enable[channel] = 0; + } +} + +void +adgold_timer_poll(void *p) +{ + adgold_t *adgold = (adgold_t *) p; + + timer_advance_u64(&adgold->adgold_mma_timer_count, (uint64_t) ((double) TIMER_USEC * 1.88964)); + + if (adgold->adgold_midi_ctrl & 0x3f) { + if ((adgold->adgold_midi_ctrl & 0x3f) != 0x3f) { + if (adgold->uart_out) + adgold->adgold_mma_status |= 0x08; + if (adgold->adgold_midi_ctrl & 0x10) + adgold->adgold_mma_status |= 0x80; + } + adgold_update_irq_status(adgold); + } + + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); } - break; + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } } + } - for (c = 0; c < len * 2; c += 2) - { - int32_t temp, lowpass, highpass; - - /*Output is deliberately halved to avoid clipping*/ - temp = ((int32_t)adgold_buffer[c] * adgold->vol_l) >> 17; - lowpass = adgold_lowpass_iir(0, temp); - highpass = adgold_highpass_iir(0, temp); - if (adgold->bass > 6) - temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; - else if (adgold->bass < 6) - temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); - if (adgold->treble > 6) - temp += (highpass * treble_attenuation[adgold->treble]) >> 14; - else if (adgold->treble < 6) - temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); - if (temp < -32768) - temp = -32768; - if (temp > 32767) - temp = 32767; - buffer[c] += temp; - - temp = ((int32_t)adgold_buffer[c+1] * adgold->vol_r) >> 17; - lowpass = adgold_lowpass_iir(1, temp); - highpass = adgold_highpass_iir(1, temp); - if (adgold->bass > 6) - temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; - else if (adgold->bass < 6) - temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); - if (adgold->treble > 6) - temp += (highpass * treble_attenuation[adgold->treble]) >> 14; - else if (adgold->treble < 6) - temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); - if (temp < -32768) - temp = -32768; - if (temp > 32767) - temp = 32767; - buffer[c+1] += temp; + if (adgold->adgold_mma_enable[0]) { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); } - - adgold->opl.pos = 0; - adgold->pos = 0; - - free(adgold_buffer); + } + if (adgold->adgold_mma_enable[1]) { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } } - -void *adgold_init(const device_t *info) +static void +adgold_get_buffer(int32_t *buffer, int len, void *p) { - FILE *f; - int c; - double out; - adgold_t *adgold = malloc(sizeof(adgold_t)); - memset(adgold, 0, sizeof(adgold_t)); + adgold_t *adgold = (adgold_t *) p; + int16_t *adgold_buffer = malloc(sizeof(int16_t) * len * 2); + if (adgold_buffer == NULL) + fatal("adgold_buffer = NULL"); - adgold->surround_enabled = device_get_config_int("surround"); - - opl3_init(&adgold->opl); - if (adgold->surround_enabled) - ym7128_init(&adgold->ym7128); + int c; - out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/ - for (c = 0x3f; c >= 0x1c; c--) - { - attenuation[c] = (int)out; - out /= 1.25963; /*2 dB steps*/ - } - for (; c >= 0; c--) - attenuation[c] = 0; + int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); + adgold_update(adgold); - f = nvr_fopen(L"adgold.bin", L"rb"); - if (f) - { - if (fread(adgold->adgold_eeprom, 1, 0x1a, f) != 0x1a) - fatal("adgold_init(): Error reading data\n"); - fclose(f); - } + for (c = 0; c < len * 2; c += 2) { + adgold_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; + adgold_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; + adgold_buffer[c + 1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + } - adgold->adgold_status = 0xf; - adgold->adgold_38x_addr = 0; - adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/ - adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/ - adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/ - memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); - adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f]; - adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f]; - adgold->bass = adgold->adgold_eeprom[0x06] & 0xf; - adgold->treble = adgold->adgold_eeprom[0x07] & 0xf; - adgold->fm_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x09] - 128); - adgold->fm_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0a] - 128); - adgold->samp_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x0b] - 128); - adgold->samp_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0c] - 128); + if (adgold->surround_enabled) + ym7128_apply(&adgold->ym7128, adgold_buffer, len); - adgold->adgold_mma_enable[0] = 0; - adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0; - - /*388/389 are handled by adlib_init*/ - io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); - - timer_add(&adgold->adgold_mma_timer_count, adgold_timer_poll, adgold, 1); + switch (adgold->adgold_38x_regs[0x8] & 6) { + case 0: + for (c = 0; c < len * 2; c++) + adgold_buffer[c] = 0; + break; + case 2: /*Left channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c + 1] = adgold_buffer[c]; + break; + case 4: /*Right channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c + 1]; + break; + case 6: /*Left and right channels*/ + break; + } - sound_add_handler(adgold_get_buffer, adgold); - - return adgold; + switch (adgold->adgold_38x_regs[0x8] & 0x18) { + case 0x00: /*Forced mono*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c + 1] = ((int32_t) adgold_buffer[c] + (int32_t) adgold_buffer[c + 1]) / 2; + break; + case 0x08: /*Linear stereo*/ + break; + case 0x10: /*Pseudo stereo*/ + /*Filter left channel, leave right channel unchanged*/ + /*Filter cutoff is largely a guess*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); + break; + case 0x18: /*Spatial stereo*/ + /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet + and a very vague understanding of how op-amps work to go on*/ + for (c = 0; c < len * 2; c += 2) { + int16_t l = adgold_buffer[c]; + int16_t r = adgold_buffer[c + 1]; + + adgold_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold_buffer[c + 1] += (l / 3) + ((r * 2) / 3); + } + break; + } + + for (c = 0; c < len * 2; c += 2) { + int32_t temp, lowpass, highpass; + + /*Output is deliberately halved to avoid clipping*/ + temp = ((int32_t) adgold_buffer[c] * adgold->vol_l) >> 17; + lowpass = adgold_lowpass_iir(0, temp); + highpass = adgold_highpass_iir(0, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c] += temp; + + temp = ((int32_t) adgold_buffer[c + 1] * adgold->vol_r) >> 17; + lowpass = adgold_lowpass_iir(1, temp); + highpass = adgold_highpass_iir(1, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c + 1] += temp; + } + + adgold->opl.reset_buffer(adgold->opl.priv); + adgold->pos = 0; + + free(adgold_buffer); } -void adgold_close(void *p) +static void +adgold_filter_cd_audio(int channel, double *buffer, void *p) { - FILE *f; - adgold_t *adgold = (adgold_t *)p; - - f = nvr_fopen(L"adgold.bin", L"wb"); - if (f) - { - fwrite(adgold->adgold_eeprom, 0x18, 1, f); - fclose(f); - } + adgold_t *adgold = (adgold_t *) p; + double c; + int aux = channel ? adgold->aux_vol_r : adgold->aux_vol_l; + int vol = channel ? adgold->vol_r : adgold->vol_l; - free(adgold); + c = ((((*buffer) * aux) / 4096.0) * vol) / 4096.0; + *buffer = c; } -static const device_config_t adgold_config[] = +static void +adgold_input_msg(void *p, uint8_t *msg, uint32_t len) { - { - "surround", "Surround module", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 + adgold_t *adgold = (adgold_t *) p; + uint8_t i; + + if (adgold->sysex) + return; + + if (adgold->uart_in) { + adgold->adgold_mma_status |= 0x04; + + for (i = 0; i < len; i++) { + adgold->midi_queue[adgold->midi_w++] = msg[i]; + adgold->midi_w &= 0x0f; } + + adgold_update_irq_status(adgold); + } +} + +static int +adgold_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + adgold_t *adgold = (adgold_t *) p; + uint32_t i; + + if (abort) { + adgold->sysex = 0; + return 0; + } + adgold->sysex = 1; + for (i = 0; i < len; i++) { + if (adgold->midi_r == adgold->midi_w) + return (len - i); + adgold->midi_queue[adgold->midi_w++] = buffer[i]; + adgold->midi_w &= 0x0f; + } + adgold->sysex = 0; + return 0; +} + +void * +adgold_init(const device_t *info) +{ + FILE *f; + int c; + double out; + adgold_t *adgold = malloc(sizeof(adgold_t)); + memset(adgold, 0, sizeof(adgold_t)); + + adgold->dma = device_get_config_int("dma"); + adgold->irq = device_get_config_int("irq"); + adgold->surround_enabled = device_get_config_int("surround"); + adgold->gameport_enabled = device_get_config_int("gameport"); + + fm_driver_get(FM_YMF262, &adgold->opl); + if (adgold->surround_enabled) + ym7128_init(&adgold->ym7128); + + out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/ + for (c = 0x3f; c >= 0x1c; c--) { + attenuation[c] = (int) out; + out /= 1.25963; /*2 dB steps*/ + } + for (; c >= 0; c--) + attenuation[c] = 0; + + adgold->adgold_eeprom[0x00] = 0x00; + adgold->adgold_eeprom[0x01] = 0x00; + adgold->adgold_eeprom[0x02] = 0x7f; + adgold->adgold_eeprom[0x03] = 0x7f; + adgold->adgold_eeprom[0x04] = 0xf8; /* vol_l */ + adgold->adgold_eeprom[0x05] = 0xf8; /* vol_r */ + adgold->adgold_eeprom[0x06] = 0xf6; /* bass */ + adgold->adgold_eeprom[0x07] = 0xf6; /* treble */ + adgold->adgold_eeprom[0x08] = 0xce; + adgold->adgold_eeprom[0x09] = 0xff; /* fm_vol_l */ + adgold->adgold_eeprom[0x0a] = 0xff; /* fm_vol_r */ + adgold->adgold_eeprom[0x0b] = 0xff; /* samp_vol_l */ + adgold->adgold_eeprom[0x0c] = 0xff; /* samp_vol_r */ + adgold->adgold_eeprom[0x0d] = 0xff; /* aux_vol_l */ + adgold->adgold_eeprom[0x0e] = 0xff; /* aux_vol_r */ + adgold->adgold_eeprom[0x0f] = 0xff; + adgold->adgold_eeprom[0x10] = 0xff; + adgold->adgold_eeprom[0x11] = 0x20; + adgold->adgold_eeprom[0x12] = 0x00; + adgold->adgold_eeprom[0x13] = 0xa0; + adgold->adgold_eeprom[0x14] = 0x00; + adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/ + adgold->adgold_eeprom[0x16] = 0x00; + adgold->adgold_eeprom[0x17] = 0x68; + adgold->adgold_eeprom[0x18] = 0x00; /* Surround */ + adgold->adgold_eeprom[0x19] = 0x00; + + f = nvr_fopen("adgold.bin", "rb"); + if (f) { + if (fread(adgold->adgold_eeprom, 1, 0x1a, f) != 0x1a) + fatal("adgold_init(): Error reading data\n"); + fclose(f); + } + + adgold->adgold_status = 0xf; + adgold->adgold_38x_addr = 0; + switch (adgold->irq) { + case 3: + adgold->adgold_eeprom[0x13] |= 0x00; + break; + case 4: + adgold->adgold_eeprom[0x13] |= 0x01; + break; + case 5: + adgold->adgold_eeprom[0x13] |= 0x02; + break; + case 7: + adgold->adgold_eeprom[0x13] |= 0x03; + break; + } + adgold->adgold_eeprom[0x13] |= (adgold->dma << 3); + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f]; + adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f]; + adgold->bass = adgold->adgold_eeprom[0x06] & 0xf; + adgold->treble = adgold->adgold_eeprom[0x07] & 0xf; + adgold->fm_vol_l = (int) (int8_t) (adgold->adgold_eeprom[0x09] - 128); + adgold->fm_vol_r = (int) (int8_t) (adgold->adgold_eeprom[0x0a] - 128); + adgold->samp_vol_l = (int) (int8_t) (adgold->adgold_eeprom[0x0b] - 128); + adgold->samp_vol_r = (int) (int8_t) (adgold->adgold_eeprom[0x0c] - 128); + adgold->aux_vol_l = (int) (int8_t) (adgold->adgold_eeprom[0x0d] - 128); + adgold->aux_vol_r = (int) (int8_t) (adgold->adgold_eeprom[0x0e] - 128); + + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0; + + /*388/389 are handled by adlib_init*/ + io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); + + if (adgold->gameport_enabled) + gameport_remap(gameport_add(&gameport_201_device), 0x201); + + timer_add(&adgold->adgold_mma_timer_count, adgold_timer_poll, adgold, 1); + + sound_add_handler(adgold_get_buffer, adgold); + sound_set_cd_audio_filter(adgold_filter_cd_audio, adgold); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, adgold_input_msg, adgold_input_sysex, adgold); + + return adgold; +} + +void +adgold_close(void *p) +{ + FILE *f; + adgold_t *adgold = (adgold_t *) p; + + f = nvr_fopen("adgold.bin", "wb"); + if (f) { + fwrite(adgold->adgold_eeprom, 0x1a, 1, f); + fclose(f); + } + + free(adgold); +} + +static const device_config_t adgold_config[] = { +// clang-format off + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 4", + .value = 4 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "Low DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "gameport", + .description = "Enable Game port", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "surround", + .description = "Surround module", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -const device_t adgold_device = -{ - "AdLib Gold", - DEVICE_ISA, 0, - adgold_init, - adgold_close, - NULL, - NULL, - NULL, - NULL, - adgold_config +const device_t adgold_device = { + .name = "AdLib Gold", + .internal_name = "adlibgold", + .flags = DEVICE_ISA, + .local = 0, + .init = adgold_init, + .close = adgold_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = adgold_config }; diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 250de39d1..4791be6a0 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -1,32 +1,51 @@ -#include +/* + * 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. + * + * Ensoniq AudioPCI (ES1371) emulation. + * + * + * + * Authors: Sarah Walker, + * RichardG, + * Miran Grca, + * + * Copyright 2008-2021 Sarah Walker. + * Copyright 2021 RichardG. + * Copyright 2021 Miran Grca. + */ +#include #include +#include #include #include -#include #define _USE_MATH_DEFINES #include #define HAVE_STDARG_H + #include <86box/86box.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/io.h> -#include <86box/nmi.h> #include <86box/mem.h> -#include <86box/pci.h> -#include <86box/timer.h> -#include <86box/sound.h> #include <86box/midi.h> -#include <86box/snd_mpu401.h> +#include <86box/nmi.h> +#include <86box/pci.h> +#include <86box/snd_ac97.h> +#include <86box/sound.h> +#include <86box/timer.h> - -#define N 16 +#define N 16 #define ES1371_NCoef 91 static float low_fir_es1371_coef[ES1371_NCoef]; typedef struct { - mpu_t mpu; - uint8_t pci_command, pci_serr; uint32_t base_addr; @@ -35,10 +54,9 @@ typedef struct { uint16_t pmcsr; - uint32_t int_ctrl; - uint32_t int_status; - - uint32_t legacy_ctrl; + uint32_t int_ctrl, int_status, + legacy_ctrl; + void *gameport; int mem_page; @@ -47,1363 +65,2071 @@ typedef struct { uint32_t sr_cir; uint16_t sr_ram[128]; - uint8_t uart_ctrl; - uint8_t uart_status; + uint8_t uart_data, uart_ctrl, + uart_status, uart_res; + uint32_t uart_fifo[8]; + uint8_t read_fifo_pos, write_fifo_pos; - uint16_t codec_regs[128]; - uint32_t codec_ctrl; + ac97_codec_t *codec; + uint32_t codec_ctrl; struct { - uint32_t addr, addr_latch; - uint16_t count, size; + uint32_t addr, addr_latch; + uint16_t count, size; - uint16_t samp_ct; - int curr_samp_ct; + uint16_t samp_ct; + int curr_samp_ct; - pc_timer_t timer; - uint64_t latch; + pc_timer_t timer; + uint64_t latch; - uint32_t vf, ac; + uint32_t vf, ac; - int16_t buffer_l[64], buffer_r[64]; - int buffer_pos, buffer_pos_end; + int16_t buffer_l[64], buffer_r[64]; + int buffer_pos, buffer_pos_end; - int filtered_l[32], filtered_r[32]; - int f_pos; + int filtered_l[32], filtered_r[32]; + int f_pos; - int16_t out_l, out_r; + int16_t out_l, out_r; - int32_t vol_l, vol_r; + int32_t vol_l, vol_r; } dac[2], adc; int64_t dac_latch, dac_time; - int master_vol_l, master_vol_r; + int master_vol_l, master_vol_r, + pcm_vol_l, pcm_vol_r, + cd_vol_l, cd_vol_r; int card; - int pos; + int pos; int16_t buffer[SOUNDBUFLEN * 2]; int type; } es1371_t; +#define LEGACY_SB_ADDR (1 << 29) +#define LEGACY_SSCAPE_ADDR_SHIFT 27 +#define LEGACY_CODEC_ADDR_SHIFT 25 +#define LEGACY_FORCE_IRQ (1 << 24) +#define LEGACY_CAPTURE_SLAVE_DMA (1 << 23) +#define LEGACY_CAPTURE_SLAVE_PIC (1 << 22) +#define LEGACY_CAPTURE_MASTER_DMA (1 << 21) +#define LEGACY_CAPTURE_MASTER_PIC (1 << 20) +#define LEGACY_CAPTURE_ADLIB (1 << 19) +#define LEGACY_CAPTURE_SB (1 << 18) +#define LEGACY_CAPTURE_CODEC (1 << 17) +#define LEGACY_CAPTURE_SSCAPE (1 << 16) +#define LEGACY_EVENT_SSCAPE (0 << 8) +#define LEGACY_EVENT_CODEC (1 << 8) +#define LEGACY_EVENT_SB (2 << 8) +#define LEGACY_EVENT_ADLIB (3 << 8) +#define LEGACY_EVENT_MASTER_PIC (4 << 8) +#define LEGACY_EVENT_MASTER_DMA (5 << 8) +#define LEGACY_EVENT_SLAVE_PIC (6 << 8) +#define LEGACY_EVENT_SLAVE_DMA (7 << 8) +#define LEGACY_EVENT_MASK (7 << 8) +#define LEGACY_EVENT_ADDR_SHIFT 3 +#define LEGACY_EVENT_ADDR_MASK (0x1f << 3) +#define LEGACY_EVENT_TYPE_RW (1 << 2) +#define LEGACY_INT (1 << 0) -#define LEGACY_SB_ADDR (1<<29) -#define LEGACY_SSCAPE_ADDR_SHIFT 27 -#define LEGACY_CODEC_ADDR_SHIFT 25 -#define LEGACY_FORCE_IRQ (1<<24) -#define LEGACY_CAPTURE_SLAVE_DMA (1<<23) -#define LEGACY_CAPTURE_SLAVE_PIC (1<<22) -#define LEGACY_CAPTURE_MASTER_DMA (1<<21) -#define LEGACY_CAPTURE_MASTER_PIC (1<<20) -#define LEGACY_CAPTURE_ADLIB (1<<19) -#define LEGACY_CAPTURE_SB (1<<18) -#define LEGACY_CAPTURE_CODEC (1<<17) -#define LEGACY_CAPTURE_SSCAPE (1<<16) -#define LEGACY_EVENT_SSCAPE (0<<8) -#define LEGACY_EVENT_CODEC (1<<8) -#define LEGACY_EVENT_SB (2<<8) -#define LEGACY_EVENT_ADLIB (3<<8) -#define LEGACY_EVENT_MASTER_PIC (4<<8) -#define LEGACY_EVENT_MASTER_DMA (5<<8) -#define LEGACY_EVENT_SLAVE_PIC (6<<8) -#define LEGACY_EVENT_SLAVE_DMA (7<<8) -#define LEGACY_EVENT_MASK (7<<8) -#define LEGACY_EVENT_ADDR_SHIFT 3 -#define LEGACY_EVENT_ADDR_MASK (0x1f<<3) -#define LEGACY_EVENT_TYPE_RW (1<<2) -#define LEGACY_INT (1<<0) +#define SRC_RAM_WE (1 << 24) -#define SRC_RAM_WE (1<<24) +#define CODEC_READ (1 << 23) +#define CODEC_READY (1 << 31) -#define CODEC_READ (1<<23) -#define CODEC_READY (1<<31) +#define INT_DAC1_EN (1 << 6) +#define INT_DAC2_EN (1 << 5) +#define INT_UART_EN (1 << 3) -#define INT_DAC1_EN (1<<6) -#define INT_DAC2_EN (1<<5) -#define INT_UART_EN (1<<3) +#define SI_P2_PAUSE (1 << 12) +#define SI_P1_PAUSE (1 << 11) +#define SI_P2_INTR_EN (1 << 9) +#define SI_P1_INTR_EN (1 << 8) -#define SI_P2_INTR_EN (1<<9) -#define SI_P1_INTR_EN (1<<8) +#define INT_STATUS_INTR (1 << 31) +#define INT_STATUS_UART (1 << 3) +#define INT_STATUS_DAC1 (1 << 2) +#define INT_STATUS_DAC2 (1 << 1) -#define INT_STATUS_INTR (1<<31) -#define INT_STATUS_UART (1<<3) -#define INT_STATUS_DAC1 (1<<2) -#define INT_STATUS_DAC2 (1<<1) +#define UART_CTRL_RXINTEN (1 << 7) +#define UART_CTRL_TXINTEN (3 << 5) -#define UART_CTRL_RXINTEN (1<<7) -#define UART_CTRL_TXINTEN (1<<5) +#define UART_STATUS_RXINT (1 << 7) +#define UART_STATUS_TXINT (1 << 2) +#define UART_STATUS_TXRDY (1 << 1) +#define UART_STATUS_RXRDY (1 << 0) -#define UART_STATUS_RXINT (1<<7) -#define UART_STATUS_TXINT (1<<2) -#define UART_STATUS_TXRDY (1<<1) -#define UART_STATUS_RXRDY (1<<0) +#define UART_FIFO_BYTE_VALID 0x00000100 -#define FORMAT_MONO_8 0 -#define FORMAT_STEREO_8 1 -#define FORMAT_MONO_16 2 -#define FORMAT_STEREO_16 3 +#define FORMAT_MONO_8 0 +#define FORMAT_STEREO_8 1 +#define FORMAT_MONO_16 2 +#define FORMAT_STEREO_16 3 -const int32_t codec_attn[]= { - 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, - 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, - 16422,20674,26027,32767 -}; - -static void es1371_fetch(es1371_t *es1371, int dac_nr); -static void update_legacy(es1371_t *es1371); +static void es1371_fetch(es1371_t *dev, int dac_nr); +static void update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl); #ifdef ENABLE_AUDIOPCI_LOG int audiopci_do_log = ENABLE_AUDIOPCI_LOG; - static void audiopci_log(const char *fmt, ...) { va_list ap; if (audiopci_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define audiopci_log(fmt, ...) +# define audiopci_log(fmt, ...) #endif - -static void es1371_update_irqs(es1371_t *es1371) +static void +es1371_update_irqs(es1371_t *dev) { - int irq = 0; - - if ((es1371->int_status & INT_STATUS_DAC1) && (es1371->si_cr & SI_P1_INTR_EN)) - irq = 1; - if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) { - irq = 1; - } - /*MIDI input is unsupported for now*/ - if ((es1371->int_status & INT_STATUS_UART) && (es1371->uart_status & UART_STATUS_TXINT)) { - irq = 1; - } + int irq = 0; - if (irq) - es1371->int_status |= INT_STATUS_INTR; - else - es1371->int_status &= ~INT_STATUS_INTR; + if ((dev->int_status & INT_STATUS_DAC1) && (dev->si_cr & SI_P1_INTR_EN)) + irq = 1; + if ((dev->int_status & INT_STATUS_DAC2) && (dev->si_cr & SI_P2_INTR_EN)) + irq = 1; - if (es1371->legacy_ctrl & LEGACY_FORCE_IRQ) - irq = 1; - - if (irq) - { - pci_set_irq(es1371->card, PCI_INTA); -// audiopci_log("Raise IRQ\n"); - } - else - { - pci_clear_irq(es1371->card, PCI_INTA); -// audiopci_log("Drop IRQ\n"); - } + dev->int_status &= ~INT_STATUS_UART; + + if ((dev->uart_status & UART_STATUS_TXINT) || (dev->uart_status & UART_STATUS_RXINT)) { + dev->int_status |= INT_STATUS_UART; + irq = 1; + } + + if (irq) + dev->int_status |= INT_STATUS_INTR; + else + dev->int_status &= ~INT_STATUS_INTR; + + if (dev->legacy_ctrl & LEGACY_FORCE_IRQ) + irq = 1; + + if (irq) + pci_set_irq(dev->card, PCI_INTA); + else + pci_clear_irq(dev->card, PCI_INTA); } -static uint8_t es1371_inb(uint16_t port, void *p) +static void +es1371_update_tx_irq(es1371_t *dev) { - es1371_t *es1371 = (es1371_t *)p; - uint8_t ret = 0; - - switch (port & 0x3f) - { - case 0x00: - ret = es1371->int_ctrl & 0xff; - break; - case 0x01: - ret = (es1371->int_ctrl >> 8) & 0xff; - break; - case 0x02: - ret = (es1371->int_ctrl >> 16) & 0xff; - break; - case 0x03: - ret = (es1371->int_ctrl >> 24) & 0xff; - break; + dev->uart_status &= ~UART_STATUS_TXINT; - case 0x04: - ret = es1371->int_status & 0xff; - break; - case 0x05: - ret = (es1371->int_status >> 8) & 0xff; - break; - case 0x06: - ret = (es1371->int_status >> 16) & 0xff; - break; - case 0x07: - ret = (es1371->int_status >> 24) & 0xff; - break; - - case 0x09: - ret = es1371->uart_status & 0xc7; - audiopci_log("ES1371 UART Status = %02x\n", es1371->uart_status); - break; - - case 0x0c: - ret = es1371->mem_page; - break; - - case 0x1a: - ret = es1371->legacy_ctrl >> 16; - break; - case 0x1b: - ret = es1371->legacy_ctrl >> 24; - break; - - case 0x20: - ret = es1371->si_cr & 0xff; - break; - case 0x21: - ret = es1371->si_cr >> 8; - break; - case 0x22: - ret = (es1371->si_cr >> 16) | 0x80; - break; - case 0x23: - ret = 0xff; - break; - - default: - audiopci_log("Bad es1371_inb: port=%04x\n", port); - } + if (((dev->uart_ctrl & UART_CTRL_TXINTEN) == 0x20) && (dev->uart_status & UART_STATUS_TXRDY)) + dev->uart_status |= UART_STATUS_TXINT; - audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); -// output = 3; - return ret; -} -static uint16_t es1371_inw(uint16_t port, void *p) -{ - es1371_t *es1371 = (es1371_t *)p; - uint16_t ret = 0; - - switch (port & 0x3e) - { - case 0x00: - ret = es1371->int_ctrl & 0xffff; - break; - case 0x02: - ret = (es1371->int_ctrl >> 16) & 0xffff; - break; - - case 0x18: - ret = es1371->legacy_ctrl & 0xffff; -// audiopci_log("Read legacy ctrl %04x\n", ret); - break; - - case 0x26: - ret = es1371->dac[0].curr_samp_ct; - break; - - case 0x2a: - ret = es1371->dac[1].curr_samp_ct; - break; - - case 0x36: - switch (es1371->mem_page) - { - case 0xc: - ret = es1371->dac[0].count; - break; - - default: - audiopci_log("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); - } - break; - - case 0x3e: - switch (es1371->mem_page) - { - case 0xc: - ret = es1371->dac[1].count; - break; - - default: - audiopci_log("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); - } - break; - - default: - audiopci_log("Bad es1371_inw: port=%04x\n", port); - } - -// audiopci_log("es1371_inw: port=%04x ret=%04x %04x:%08x\n", port, ret, CS,cpu_state.pc); - return ret; -} -static uint32_t es1371_inl(uint16_t port, void *p) -{ - es1371_t *es1371 = (es1371_t *)p; - uint32_t ret = 0; - - switch (port & 0x3c) - { - case 0x00: - ret = es1371->int_ctrl; - break; - case 0x04: - ret = es1371->int_status; - break; - - case 0x10: - ret = es1371->sr_cir & ~0xffff; - ret |= es1371->sr_ram[es1371->sr_cir >> 25]; - break; - - case 0x14: - ret = es1371->codec_ctrl & 0x00ff0000; - ret |= es1371->codec_regs[(es1371->codec_ctrl >> 16) & 0x7f]; - if (((es1371->codec_ctrl >> 16) & 0x7f) == 0x26) - ret |= 0x0f; - ret |= CODEC_READY; - break; - - case 0x30: - switch (es1371->mem_page) { - case 0xe: case 0xf: - audiopci_log("ES1371 0x30 read UART FIFO: val = %02x\n", ret & 0xff); - break; - } - break; - - case 0x34: - switch (es1371->mem_page) { - case 0xc: - ret = es1371->dac[0].size | (es1371->dac[0].count << 16); - break; - - case 0xd: - ret = es1371->adc.size | (es1371->adc.count << 16); - break; - - case 0xe: case 0xf: - audiopci_log("ES1371 0x34 read UART FIFO: val = %02x\n", ret & 0xff); - break; - - default: - audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); - } - break; - - case 0x38: - switch (es1371->mem_page) { - case 0xe: case 0xf: - audiopci_log("ES1371 0x38 read UART FIFO: val = %02x\n", ret & 0xff); - break; - } - break; - - case 0x3c: - switch (es1371->mem_page) { - case 0xc: - ret = es1371->dac[1].size | (es1371->dac[1].count << 16); - break; - - case 0xe: case 0xf: - audiopci_log("ES1371 0x3c read UART FIFO: val = %02x\n", ret & 0xff); - break; - - default: - audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); - } - break; - - default: - audiopci_log("Bad es1371_inl: port=%04x\n", port); - } - - audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret); - return ret; + es1371_update_irqs(dev); } -static void es1371_outb(uint16_t port, uint8_t val, void *p) +static void +es1371_set_tx_irq(es1371_t *dev, int set) { - es1371_t *es1371 = (es1371_t *)p; + dev->uart_status &= ~UART_STATUS_TXRDY; - audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val); - switch (port & 0x3f) - { - case 0x00: - if (!(es1371->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) - { - es1371->dac[0].addr = es1371->dac[0].addr_latch; - es1371->dac[0].buffer_pos = 0; - es1371->dac[0].buffer_pos_end = 0; - es1371_fetch(es1371, 0); - } - if (!(es1371->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) - { - es1371->dac[1].addr = es1371->dac[1].addr_latch; - es1371->dac[1].buffer_pos = 0; - es1371->dac[1].buffer_pos_end = 0; - es1371_fetch(es1371, 1); - } - es1371->int_ctrl = (es1371->int_ctrl & 0xffffff00) | val; - break; - case 0x01: - es1371->int_ctrl = (es1371->int_ctrl & 0xffff00ff) | (val << 8); - break; - case 0x02: - es1371->int_ctrl = (es1371->int_ctrl & 0xff00ffff) | (val << 16); - break; - case 0x03: - es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24); - break; - - case 0x08: - midi_raw_out_byte(val); - break; - - case 0x09: - es1371->uart_ctrl = val & 0xe3; - audiopci_log("ES1371 UART Cntrl = %02x\n", es1371->uart_ctrl); - break; - - case 0x0c: - es1371->mem_page = val & 0xf; - break; + if (set) + dev->uart_status |= UART_STATUS_TXRDY; - case 0x18: - es1371->legacy_ctrl |= LEGACY_INT; - nmi = 0; - break; - case 0x1a: - es1371->legacy_ctrl = (es1371->legacy_ctrl & 0xff00ffff) | (val << 16); - update_legacy(es1371); - break; - case 0x1b: - es1371->legacy_ctrl = (es1371->legacy_ctrl & 0x00ffffff) | (val << 24); - es1371_update_irqs(es1371); -// output = 3; - update_legacy(es1371); - break; - - case 0x20: - es1371->si_cr = (es1371->si_cr & 0xffff00) | val; - break; - case 0x21: - es1371->si_cr = (es1371->si_cr & 0xff00ff) | (val << 8); - if (!(es1371->si_cr & SI_P1_INTR_EN)) - es1371->int_status &= ~INT_STATUS_DAC1; - if (!(es1371->si_cr & SI_P2_INTR_EN)) - es1371->int_status &= ~INT_STATUS_DAC2; - es1371_update_irqs(es1371); - break; - case 0x22: - es1371->si_cr = (es1371->si_cr & 0x00ffff) | (val << 16); - break; - - default: - audiopci_log("Bad es1371_outb: port=%04x val=%02x\n", port, val); - } -} -static void es1371_outw(uint16_t port, uint16_t val, void *p) -{ - es1371_t *es1371 = (es1371_t *)p; - -// audiopci_log("es1371_outw: port=%04x val=%04x\n", port, val); - switch (port & 0x3f) - { - case 0x0c: - es1371->mem_page = val & 0xf; - break; - - case 0x24: - es1371->dac[0].samp_ct = val; - break; - - case 0x28: - es1371->dac[1].samp_ct = val; - break; - - default: - audiopci_log("Bad es1371_outw: port=%04x val=%04x\n", port, val); - } -} -static void es1371_outl(uint16_t port, uint32_t val, void *p) -{ - es1371_t *es1371 = (es1371_t *)p; - - audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val); - switch (port & 0x3f) - { - case 0x04: - break; - - case 0x0c: - es1371->mem_page = val & 0xf; - break; - - case 0x10: - es1371->sr_cir = val; - if (es1371->sr_cir & SRC_RAM_WE) - { -// audiopci_log("Write SR RAM %02x %04x\n", es1371->sr_cir >> 25, val & 0xffff); - es1371->sr_ram[es1371->sr_cir >> 25] = val & 0xffff; - switch (es1371->sr_cir >> 25) - { - case 0x71: - es1371->dac[0].vf = (es1371->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5); - es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15); - es1371->dac[0].f_pos = 0; - break; - case 0x72: - es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7fff) | (val & 0x7fff); - break; - case 0x73: - es1371->dac[0].vf = (es1371->dac[0].vf & ~0x7fff) | (val & 0x7fff); - break; - - case 0x75: - es1371->dac[1].vf = (es1371->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5); - es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15); - es1371->dac[1].f_pos = 0; - break; - case 0x76: - es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7fff) | (val & 0x7fff); - break; - case 0x77: - es1371->dac[1].vf = (es1371->dac[1].vf & ~0x7fff) | (val & 0x7fff); - break; - - case 0x7c: - es1371->dac[0].vol_l = (int32_t)(int16_t)(val & 0xffff); - break; - case 0x7d: - es1371->dac[0].vol_r = (int32_t)(int16_t)(val & 0xffff); - break; - case 0x7e: - es1371->dac[1].vol_l = (int32_t)(int16_t)(val & 0xffff); - break; - case 0x7f: - es1371->dac[1].vol_r = (int32_t)(int16_t)(val & 0xffff); - break; - } - } - break; - - case 0x14: - es1371->codec_ctrl = val; - if (!(val & CODEC_READ)) - { -// audiopci_log("Write codec %02x %04x\n", (val >> 16) & 0x7f, val & 0xffff); - if ((((val >> 16) & 0x7f) != 0x7c) || (((val >> 16) & 0x7f) != 0x7e)) - es1371->codec_regs[(val >> 16) & 0x7f] = val & 0xffff; - switch ((val >> 16) & 0x7f) - { - case 0x02: /*Master volume*/ - if (val & 0x8000) - es1371->master_vol_l = es1371->master_vol_r = 0; - else - { - if (val & 0x2000) - es1371->master_vol_l = codec_attn[0]; - else - es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)]; - if (val & 0x20) - es1371->master_vol_r = codec_attn[0]; - else - es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)]; - } - break; - case 0x12: /*CD volume*/ - if (val & 0x8000) - sound_set_cd_volume(0, 0); - else - sound_set_cd_volume(codec_attn[0x1f - ((val >> 8) & 0x1f)] * 2, codec_attn[0x1f - (val & 0x1f)] * 2); - break; - } - } - break; - - case 0x24: - es1371->dac[0].samp_ct = val & 0xffff; - break; - - case 0x28: - es1371->dac[1].samp_ct = val & 0xffff; - break; - - case 0x30: - switch (es1371->mem_page) - { - case 0x0: case 0x1: case 0x2: case 0x3: - case 0x4: case 0x5: case 0x6: case 0x7: - case 0x8: case 0x9: case 0xa: case 0xb: - break; - - case 0xc: - es1371->dac[0].addr_latch = val; -// audiopci_log("DAC1 addr %08x\n", val); - break; - - case 0xe: case 0xf: - audiopci_log("ES1371 0x30 write UART FIFO: val = %02x\n", val & 0xff); - break; - - default: - audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); - } - break; - case 0x34: - switch (es1371->mem_page) - { - case 0x0: case 0x1: case 0x2: case 0x3: - case 0x4: case 0x5: case 0x6: case 0x7: - case 0x8: case 0x9: case 0xa: case 0xb: - break; - - case 0xc: - es1371->dac[0].size = val & 0xffff; - es1371->dac[0].count = val >> 16; - break; - - case 0xd: - es1371->adc.size = val & 0xffff; - es1371->adc.count = val >> 16; - break; - - case 0xe: case 0xf: - audiopci_log("ES1371 0x34 write UART FIFO: val = %02x\n", val & 0xff); - break; - - default: - audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); - } - break; - case 0x38: - switch (es1371->mem_page) - { - case 0x0: case 0x1: case 0x2: case 0x3: - case 0x4: case 0x5: case 0x6: case 0x7: - case 0x8: case 0x9: case 0xa: case 0xb: - break; - - case 0xc: - es1371->dac[1].addr_latch = val; - break; - - case 0xd: - break; - - case 0xe: case 0xf: - audiopci_log("ES1371 0x38 write UART FIFO: val = %02x\n", val & 0xff); - break; - - default: - audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); - } - break; - case 0x3c: - switch (es1371->mem_page) - { - case 0x0: case 0x1: case 0x2: case 0x3: - case 0x4: case 0x5: case 0x6: case 0x7: - case 0x8: case 0x9: case 0xa: case 0xb: - break; - - case 0xc: - es1371->dac[1].size = val & 0xffff; - es1371->dac[1].count = val >> 16; - break; - - case 0xe: case 0xf: - audiopci_log("ES1371 0x3c write UART FIFO: val = %02x\n", val & 0xff); - break; - - default: - audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); - } - break; - - default: - audiopci_log("Bad es1371_outl: port=%04x val=%08x\n", port, val); - } + es1371_update_tx_irq(dev); } -static void capture_event(es1371_t *es1371, int type, int rw, uint16_t port) +static void +es1371_update_rx_irq(es1371_t *dev) { - es1371->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK); - es1371->legacy_ctrl |= type; - if (rw) - es1371->legacy_ctrl |= LEGACY_EVENT_TYPE_RW; - else - es1371->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW; - es1371->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK); - es1371->legacy_ctrl &= ~LEGACY_INT; - nmi = 1; -// audiopci_log("Event! %s %04x\n", rw ? "write" : "read", port); + dev->uart_status &= ~UART_STATUS_RXINT; + + if ((dev->uart_ctrl & UART_CTRL_RXINTEN) && (dev->uart_status & UART_STATUS_RXRDY)) + dev->uart_status |= UART_STATUS_RXINT; + + es1371_update_irqs(dev); } -static void capture_write_sscape(uint16_t port, uint8_t val, void *p) +static void +es1371_set_rx_irq(es1371_t *dev, int set) { - capture_event(p, LEGACY_EVENT_SSCAPE, 1, port); -} -static void capture_write_codec(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_CODEC, 1, port); -} -static void capture_write_sb(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_SB, 1, port); -} -static void capture_write_adlib(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_ADLIB, 1, port); -} -static void capture_write_master_pic(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port); -} -static void capture_write_master_dma(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port); -} -static void capture_write_slave_pic(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port); -} -static void capture_write_slave_dma(uint16_t port, uint8_t val, void *p) -{ - capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port); + dev->uart_status &= ~UART_STATUS_RXRDY; + + if (set) + dev->uart_status |= UART_STATUS_RXRDY; + + es1371_update_rx_irq(dev); } -static uint8_t capture_read_sscape(uint16_t port, void *p) +static void +es1371_scan_fifo(es1371_t *dev) { - capture_event(p, LEGACY_EVENT_SSCAPE, 0, port); - return 0xff; -} -static uint8_t capture_read_codec(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_CODEC, 0, port); - return 0xff; -} -static uint8_t capture_read_sb(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_SB, 0, port); - return 0xff; -} -static uint8_t capture_read_adlib(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_ADLIB, 0, port); - return 0xff; -} -static uint8_t capture_read_master_pic(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port); - return 0xff; -} -static uint8_t capture_read_master_dma(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port); - return 0xff; -} -static uint8_t capture_read_slave_pic(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port); - return 0xff; -} -static uint8_t capture_read_slave_dma(uint16_t port, void *p) -{ - capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port); - return 0xff; + if (dev->read_fifo_pos != dev->write_fifo_pos) { + dev->uart_data = dev->uart_fifo[dev->read_fifo_pos]; + dev->read_fifo_pos = (dev->read_fifo_pos + 1) & 7; + + es1371_set_rx_irq(dev, 1); + } else + es1371_set_rx_irq(dev, 0); } -static void update_legacy(es1371_t *es1371) +static void +es1371_write_fifo(es1371_t *dev, uint8_t val) { - io_removehandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); - io_removehandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); - io_removehandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); - io_removehandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); - - io_removehandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); - io_removehandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); - io_removehandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); - - io_removehandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); - io_removehandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); - - io_removehandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); - - io_removehandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); - io_removehandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); - io_removehandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); - io_removehandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); - - if (es1371->legacy_ctrl & LEGACY_CAPTURE_SSCAPE) - { - switch ((es1371->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) - { - case 0: io_sethandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; - case 1: io_sethandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; - case 2: io_sethandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; - case 3: io_sethandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; - } - } - if (es1371->legacy_ctrl & LEGACY_CAPTURE_CODEC) - { - switch ((es1371->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) - { - case 0: io_sethandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; - case 2: io_sethandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; - case 3: io_sethandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; - } - } - if (es1371->legacy_ctrl & LEGACY_CAPTURE_SB) - { - if (!(es1371->legacy_ctrl & LEGACY_SB_ADDR)) - io_sethandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); - else - io_sethandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); - } - if (es1371->legacy_ctrl & LEGACY_CAPTURE_ADLIB) - io_sethandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); - if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) - io_sethandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); - if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) - io_sethandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); - if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) - io_sethandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); - if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) - io_sethandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); + if (dev->write_fifo_pos < 8) { + dev->uart_fifo[dev->write_fifo_pos] = val | UART_FIFO_BYTE_VALID; + dev->write_fifo_pos = (dev->write_fifo_pos + 1) & 7; + } } - -static uint8_t es1371_pci_read(int func, int addr, void *p) +static void +es1371_reset_fifo(es1371_t *dev) { - es1371_t *es1371 = (es1371_t *)p; + int i; - if (func) - return 0; + for (i = 0; i < 8; i++) + dev->uart_fifo[i] = 0x00000000; - //audiopci_log("ES1371 PCI read %08X PC=%08x\n", addr, cpu_state.pc); + dev->read_fifo_pos = dev->write_fifo_pos = 0; - if (addr > 0x3f) - return 0x00; - - switch (addr) - { - case 0x00: return 0x74; /*Ensoniq*/ - case 0x01: return 0x12; - - case 0x02: return 0x71; /* ES1371 */ - case 0x03: return 0x13; - - case 0x04: return es1371->pci_command; - case 0x05: return es1371->pci_serr; - - case 0x06: return 0x10; /* Supports support ACPI */ - case 0x07: return 0x00; - - case 0x08: return 0x02; /* Revision ID */ - case 0x09: return 0x00; /* Multimedia audio device */ - case 0x0a: return 0x01; - case 0x0b: return 0x04; - - case 0x10: return 0x01 | (es1371->base_addr & 0xc0); /* memBaseAddr */ - case 0x11: return es1371->base_addr >> 8; - case 0x12: return es1371->base_addr >> 16; - case 0x13: return es1371->base_addr >> 24; - - case 0x2c: return 0x74; /* Subsystem vendor ID */ - case 0x2d: return 0x12; - case 0x2e: return 0x71; - case 0x2f: return 0x13; - - case 0x34: return 0xdc; /*Capabilites pointer*/ - - case 0x3c: return es1371->int_line; - case 0x3d: return 0x01; /*INTA*/ - - case 0x3e: return 0xc; /*Minimum grant*/ - case 0x3f: return 0x80; /*Maximum latency*/ - - case 0xdc: return 0x01; /*Capabilities identifier*/ - case 0xdd: return 0x00; /*Next item pointer*/ - case 0xde: return 0x31; /*Power management capabilities*/ - case 0xdf: return 0x6c; - - case 0xe0: return es1371->pmcsr & 0xff; - case 0xe1: return es1371->pmcsr >> 8; - } - return 0; + es1371_set_rx_irq(dev, 0); } -static void es1371_pci_write(int func, int addr, uint8_t val, void *p) +static void +es1371_reset(void *p) { - es1371_t *es1371 = (es1371_t *)p; - - if (func) - return; + es1371_t *dev = (es1371_t *) p; + int i; -// audiopci_log("ES1371 PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + nmi = 0; - switch (addr) - { - case 0x04: - if (es1371->pci_command & PCI_COMMAND_IO) - io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); - es1371->pci_command = val & 0x05; - if (es1371->pci_command & PCI_COMMAND_IO) - io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); - break; - case 0x05: - es1371->pci_serr = val & 1; - break; - - case 0x10: - if (es1371->pci_command & PCI_COMMAND_IO) - io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); - es1371->base_addr = (es1371->base_addr & 0xffffff00) | (val & 0xc0); - if (es1371->pci_command & PCI_COMMAND_IO) - io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); - break; - case 0x11: - if (es1371->pci_command & PCI_COMMAND_IO) - io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); - es1371->base_addr = (es1371->base_addr & 0xffff00c0) | (val << 8); - if (es1371->pci_command & PCI_COMMAND_IO) - io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); - break; - case 0x12: - es1371->base_addr = (es1371->base_addr & 0xff00ffc0) | (val << 16); - break; - case 0x13: - es1371->base_addr = (es1371->base_addr & 0x00ffffc0) | (val << 24); - break; + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + dev->int_ctrl = 0xfc0f0000; - case 0x3c: - es1371->int_line = val; - break; + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as longword only */ + dev->int_status = 0x7ffffec0; - case 0xe0: - es1371->pmcsr = (es1371->pmcsr & 0xff00) | (val & 0x03); - break; - case 0xe1: - es1371->pmcsr = (es1371->pmcsr & 0x00ff) | ((val & 0x01) << 8); - break; - } -// audiopci_log("es1371->base_addr %08x\n", es1371->base_addr); + /* UART Status Register, Address 09H + Addressable as byte only */ + dev->uart_status = 0x00; + + /* UART Control Register, Address 09H + Addressable as byte only */ + dev->uart_ctrl = 0x00; + + /* UART Reserved Register, Address 0AH + Addressable as byte only */ + dev->uart_res = 0x00; + + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + dev->mem_page = 0x00; + + /* Sample Rate Converter Interface Register, Address 10H + Addressable as longword only */ + dev->sr_cir = 0x00000000; + + /* CODEC Write Register, Address 14H + Addressable as longword only */ + dev->codec_ctrl = 0x00000000; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + dev->legacy_ctrl = 0x0000f800; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + dev->si_cr = 0xff800000; + + /* DAC1 Channel Sample Count Register, Address 24H + Addressable as word, longword */ + dev->dac[0].samp_ct = 0x00000000; + dev->dac[0].curr_samp_ct = 0x00000000; + + /* DAC2 Channel Sample Count Register, Address 28H + Addressable as word, longword */ + dev->dac[1].samp_ct = 0x00000000; + dev->dac[1].curr_samp_ct = 0x00000000; + + /* ADC Channel Sample Count Register, Address 2CH + Addressable as word, longword */ + dev->adc.samp_ct = 0x00000000; + dev->adc.curr_samp_ct = 0x00000000; + + /* DAC1 Frame Register 1, Address 30H, Memory Page 1100b + Addressable as longword only */ + dev->dac[0].addr_latch = 0x00000000; + + /* DAC1 Frame Register 2, Address 34H, Memory Page 1100b + Addressable as longword only */ + dev->dac[0].size = 0x00000000; + dev->dac[0].count = 0x00000000; + + /* DAC2 Frame Register 1, Address 38H, Memory Page 1100b + Addressable as longword only */ + dev->dac[1].addr_latch = 0x00000000; + + /* DAC2 Frame Register 2, Address 3CH, Memory Page 1100b + Addressable as longword only */ + dev->dac[1].size = 0x00000000; + dev->dac[1].count = 0x00000000; + + /* ADC Frame Register 1, Address 30H, Memory Page 1101b + Addressable as longword only */ + dev->adc.addr_latch = 0x00000000; + + /* ADC Frame Register 2, Address 34H, Memory Page 1101b + Addressable as longword only */ + dev->adc.size = 0x00000000; + dev->adc.count = 0x00000000; + + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + for (i = 0; i < 8; i++) + dev->uart_fifo[i] = 0xffff0000; + + /* Reset the UART TX. */ + es1371_set_tx_irq(dev, 0); + + /* Reset the UART (RX) FIFO. */ + es1371_reset_fifo(dev); + + /* Update interrupts to ensure they're all correctly cleared. */ + es1371_update_irqs(dev); } -static void es1371_fetch(es1371_t *es1371, int dac_nr) +static uint32_t +es1371_read_frame_reg(es1371_t *dev, int frame, int page) { - int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); - int pos = es1371->dac[dac_nr].buffer_pos & 63; - int c; + uint32_t ret = 0xffffffff; -//audiopci_log("Fetch format=%i %08x %08x %08x %08x %08x\n", format, es1371->dac[dac_nr].count, es1371->dac[dac_nr].size, es1371->dac[dac_nr].curr_samp_ct,es1371->dac[dac_nr].samp_ct, es1371->dac[dac_nr].addr); - switch (format) - { - case FORMAT_MONO_8: - for (c = 0; c < 32; c += 4) - { - es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; - es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+1) ^ 0x80) << 8; - es1371->dac[dac_nr].buffer_l[(pos+c+2) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+2) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+2) ^ 0x80) << 8; - es1371->dac[dac_nr].buffer_l[(pos+c+3) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+3) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+3) ^ 0x80) << 8; - es1371->dac[dac_nr].addr += 4; - - es1371->dac[dac_nr].buffer_pos_end += 4; - es1371->dac[dac_nr].count++; - if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) - { - es1371->dac[dac_nr].count = 0; - es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; - break; - } - } - break; - case FORMAT_STEREO_8: - for (c = 0; c < 16; c += 2) - { - es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; - es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 1) ^ 0x80) << 8; - es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 2) ^ 0x80) << 8; - es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 3) ^ 0x80) << 8; - es1371->dac[dac_nr].addr += 4; - - es1371->dac[dac_nr].buffer_pos_end += 2; - es1371->dac[dac_nr].count++; - if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) - { - es1371->dac[dac_nr].count = 0; - es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; - break; - } - } - break; - case FORMAT_MONO_16: - for (c = 0; c < 16; c += 2) - { - es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); - es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); - es1371->dac[dac_nr].addr += 4; + switch (frame) { + case 0x30: + switch (page) { + /* DAC1 Frame Register 1, Address 30H, Memory Page 1100b + Addressable as longword only */ + case 0xc: + ret = dev->dac[0].addr_latch; + break; + /* ADC Frame Register 1, Address 30H, Memory Page 1101b + Addressable as longword only */ + case 0xd: + ret = dev->adc.addr_latch; + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[30:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]); + ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]; + break; + } + break; + case 0x34: + switch (page) { + /* DAC1 Frame Register 2, Address 34H, Memory Page 1100b + Addressable as longword only */ + case 0xc: + ret = dev->dac[0].size | (dev->dac[0].count << 16); + break; + /* ADC Frame Register 2, Address 34H, Memory Page 1101b + Addressable as longword only */ + case 0xd: + ret = dev->adc.size | (dev->adc.count << 16); + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[34:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]); + ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]; + break; + } + break; + case 0x38: + switch (page) { + /* DAC2 Frame Register 1, Address 38H, Memory Page 1100b + Addressable as longword only */ + case 0xc: + ret = dev->dac[1].addr_latch; + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[38:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]); + ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]; + break; + } + break; + case 0x3c: + switch (page) { + /* DAC2 Frame Register 2, Address 3CH, Memory Page 1100b + Addressable as longword only */ + case 0xc: + ret = dev->dac[1].size | (dev->dac[1].count << 16); + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[3C:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]); + ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]; + break; + } + break; + } - es1371->dac[dac_nr].buffer_pos_end += 2; - es1371->dac[dac_nr].count++; - if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) - { - es1371->dac[dac_nr].count = 0; - es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; - break; - } - } - break; - case FORMAT_STEREO_16: - for (c = 0; c < 4; c++) - { - es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); - es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); -// audiopci_log("Fetch %02x %08x %04x %04x\n", (pos+c) & 63, es1371->dac[dac_nr].addr, es1371->dac[dac_nr].buffer_l[(pos+c) & 63], es1371->dac[dac_nr].buffer_r[(pos+c) & 63]); - es1371->dac[dac_nr].addr += 4; - - es1371->dac[dac_nr].buffer_pos_end++; - es1371->dac[dac_nr].count++; - if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) - { - es1371->dac[dac_nr].count = 0; - es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; - break; - } - } - break; - } + if (page == 0x0e || page == 0x0f) { + audiopci_log("Read frame = %02x, page = %02x, uart fifo valid = %02x, temp = %03x\n", frame, page, dev->valid, ret); + } + + return ret; } -static inline float low_fir_es1371(int dac_nr, int i, float NewSample) +static void +es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) { - static float x[2][2][128]; //input samples - static int x_pos[2] = {0, 0}; - float out = 0.0; - int read_pos; - int n_coef; - int pos = x_pos[dac_nr]; + switch (frame) { + case 0x30: + switch (page) { + /* DAC1 Frame Register 1, Address 30H, Memory Page 1100b + Addressable as longword only */ + case 0xc: + dev->dac[0].addr_latch = val; + break; + /* ADC Frame Register 1, Address 30H, Memory Page 1101b + Addressable as longword only */ + case 0xd: + dev->adc.addr_latch = val; + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[30:%02X] dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), val); + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val; + break; + } + break; + case 0x34: + switch (page) { + /* DAC1 Frame Register 2, Address 34H, Memory Page 1100b + Addressable as longword only */ + case 0xc: + dev->dac[0].size = val & 0xffff; + dev->dac[0].count = val >> 16; + break; + /* ADC Frame Register 2, Address 34H, Memory Page 1101b + Addressable as longword only */ + case 0xd: + dev->adc.size = val & 0xffff; + dev->adc.count = val >> 16; + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[34:%02X] dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), val); + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val; + break; + } + break; + case 0x38: + switch (page) { + /* DAC2 Frame Register 1, Address 38H, Memory Page 1100b + Addressable as longword only */ + case 0xc: + dev->dac[1].addr_latch = val; + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[38:%02X] dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), val); + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val; + break; + } + break; + case 0x3c: + switch (page) { + /* DAC2 Frame Register 2, Address 3CH, Memory Page 1100b + Addressable as longword only */ + case 0xc: + dev->dac[1].size = val & 0xffff; + dev->dac[1].count = val >> 16; + break; + /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b + Addressable as longword only */ + case 0xe: + case 0xf: + audiopci_log("[3C:%02X] dev->uart_fifo[%02X] = %08X\n", page, + ((page & 0x01) << 2) + ((frame >> 2) & 0x03), val); + dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val; + break; + } + break; + } - x[dac_nr][i][pos] = NewSample; - - /*Since only 1/16th of input samples are non-zero, only filter those that - are valid.*/ - read_pos = (pos + 15) & (127 & ~15); - n_coef = (16 - pos) & 15; - - while (n_coef < ES1371_NCoef) - { - out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos]; - read_pos = (read_pos + 16) & (127 & ~15); - n_coef += 16; - } - - if (i == 1) - { - x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127; - if (x_pos[dac_nr] > 127) - x_pos[dac_nr] = 0; - } - - return out; + if (page == 0x0e || page == 0x0f) { + audiopci_log("Write frame = %02x, page = %02x, uart fifo = %08x, val = %02x\n", frame, page, dev->uart_fifo, val); + } } -static void es1371_next_sample_filtered(es1371_t *es1371, int dac_nr, int out_idx) +static uint8_t +es1371_inb(uint16_t port, void *p) { - int out_l, out_r; - int c; - - if ((es1371->dac[dac_nr].buffer_pos - es1371->dac[dac_nr].buffer_pos_end) >= 0) - { - es1371_fetch(es1371, dac_nr); - } + es1371_t *dev = (es1371_t *) p; + uint8_t ret = 0xff; - out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; - out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; - - es1371->dac[dac_nr].filtered_l[out_idx] = (int)low_fir_es1371(dac_nr, 0, (float)out_l); - es1371->dac[dac_nr].filtered_r[out_idx] = (int)low_fir_es1371(dac_nr, 1, (float)out_r); - for (c = 1; c < 16; c++) - { - es1371->dac[dac_nr].filtered_l[out_idx+c] = (int)low_fir_es1371(dac_nr, 0, 0); - es1371->dac[dac_nr].filtered_r[out_idx+c] = (int)low_fir_es1371(dac_nr, 1, 0); - } - -// audiopci_log("Use %02x %04x %04x\n", es1371->dac[dac_nr].buffer_pos & 63, es1371->dac[dac_nr].out_l, es1371->dac[dac_nr].out_r); - - es1371->dac[dac_nr].buffer_pos++; -// audiopci_log("Next sample %08x %08x %08x\n", es1371->dac[dac_nr].buffer_pos, es1371->dac[dac_nr].buffer_pos_end, es1371->dac[dac_nr].curr_samp_ct); + switch (port & 0x3f) { + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + case 0x00: + ret = dev->int_ctrl & 0xff; + break; + case 0x01: + ret = (dev->int_ctrl >> 8) & 0xff; + break; + case 0x02: + ret = (dev->int_ctrl >> 16) & 0x0f; + break; + case 0x03: + ret = ((dev->int_ctrl >> 24) & 0x03) | 0xfc; + break; + + /* Interrupt/Chip Select Status Register, Address 04H + Addressable as longword only, but PCem implements byte access, which + must be for a reason */ + case 0x04: + ret = dev->int_status & 0xff; + audiopci_log("[R] STATUS 0- 7 = %02X\n", ret); + break; + case 0x05: + ret = (dev->int_status >> 8) & 0xff; + audiopci_log("[R] STATUS 8-15 = %02X\n", ret); + break; + case 0x06: + ret = (dev->int_status >> 16) & 0x0f; + audiopci_log("[R] STATUS 16-23 = %02X\n", ret); + break; + case 0x07: + ret = ((dev->int_status >> 24) & 0x03) | 0xfc; + audiopci_log("[R] STATUS 24-31 = %02X\n", ret); + break; + + /* UART Data Register, Address 08H + Addressable as byte only */ + case 0x08: + ret = dev->uart_data; + es1371_set_rx_irq(dev, 0); + audiopci_log("[R] UART DATA = %02X\n", ret); + break; + + /* UART Status Register, Address 09H + Addressable as byte only */ + case 0x09: + ret = dev->uart_status & 0x87; + audiopci_log("ES1371 UART Status = %02x\n", dev->uart_status); + break; + + /* UART Reserved Register, Address 0AH + Addressable as byte only */ + case 0x0a: + ret = dev->uart_res & 0x01; + audiopci_log("[R] UART RES = %02X\n", ret); + break; + + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + case 0x0c: + ret = dev->mem_page; + break; + case 0x0d ... 0x0e: + ret = 0x00; + break; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + case 0x18: + ret = dev->legacy_ctrl & 0xfd; + break; + case 0x19: + ret = ((dev->legacy_ctrl >> 8) & 0x07) | 0xf8; + break; + case 0x1a: + ret = dev->legacy_ctrl >> 16; + break; + case 0x1b: + ret = dev->legacy_ctrl >> 24; + break; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + case 0x20: + ret = dev->si_cr & 0xff; + break; + case 0x21: + ret = dev->si_cr >> 8; + break; + case 0x22: + ret = (dev->si_cr >> 16) | 0x80; + break; + case 0x23: + ret = 0xff; + break; + + default: + audiopci_log("Bad es1371_inb: port=%04x\n", port); + } + + audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); + return ret; } -//static FILE *es1371_f;//,*es1371_f2; - -static void es1371_update(es1371_t *es1371) +static uint16_t +es1371_inw(uint16_t port, void *p) { - int32_t l, r; - - l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; - l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); - r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; - r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); - - l >>= 1; - r >>= 1; - - l = (l * es1371->master_vol_l) >> 15; - r = (r * es1371->master_vol_r) >> 15; - - if (l < -32768) - l = -32768; - else if (l > 32767) - l = 32767; - if (r < -32768) - r = -32768; - else if (r > 32767) - r = 32767; + es1371_t *dev = (es1371_t *) p; + uint16_t ret = 0xffff; - for (; es1371->pos < sound_pos_global; es1371->pos++) - { - es1371->buffer[es1371->pos*2] = l; - es1371->buffer[es1371->pos*2 + 1] = r; - } + switch (port & 0x3e) { + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + case 0x00: + ret = dev->int_ctrl & 0xffff; + break; + case 0x02: + ret = ((dev->int_ctrl >> 16) & 0x030f) | 0xfc00; + break; + + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + case 0x0c: + ret = dev->mem_page; + break; + case 0x0e: + ret = 0x0000; + break; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + case 0x18: + ret = (dev->legacy_ctrl & 0x07fd) | 0xf800; + break; + case 0x1a: + ret = dev->legacy_ctrl >> 16; + break; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + case 0x20: + ret = dev->si_cr & 0xffff; + break; + case 0x22: + ret = (dev->si_cr >> 16) | 0xff80; + break; + + /* DAC1 Channel Sample Count Register, Address 24H + Addressable as word, longword */ + case 0x24: + ret = dev->dac[0].samp_ct; + break; + case 0x26: + ret = dev->dac[0].curr_samp_ct; + break; + + /* DAC2 Channel Sample Count Register, Address 28H + Addressable as word, longword */ + case 0x28: + ret = dev->dac[1].samp_ct; + break; + case 0x2a: + ret = dev->dac[1].curr_samp_ct; + break; + + /* ADC Channel Sample Count Register, Address 2CH + Addressable as word, longword */ + case 0x2c: + ret = dev->adc.samp_ct; + break; + case 0x2e: + ret = dev->adc.curr_samp_ct; + break; + + case 0x30: + case 0x34: + case 0x38: + case 0x3c: + ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page) & 0xffff; + break; + case 0x32: + case 0x36: + case 0x3a: + case 0x3e: + ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page) >> 16; + break; + } + + audiopci_log("es1371_inw: port=%04x ret=%04x\n", port, ret); + + return ret; } -static void es1371_poll(void *p) +static uint32_t +es1371_inl(uint16_t port, void *p) { - es1371_t *es1371 = (es1371_t *)p; - - timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch); + es1371_t *dev = (es1371_t *) p; + uint32_t ret = 0xffffffff; - es1371_update(es1371); + switch (port & 0x3c) { + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + case 0x00: + ret = (dev->int_ctrl & 0x030fffff) | 0xfc000000; + break; - if (es1371->int_ctrl & INT_UART_EN) { - audiopci_log("UART INT Enabled\n"); - if (es1371->uart_ctrl & UART_CTRL_RXINTEN) { /*We currently don't implement MIDI Input.*/ - /*But if anything sets MIDI Input and Output together we'd have to take account - of the MIDI Output case, and disable IRQ's and RX bits when MIDI Input is enabled as well but not in the MIDI Output portion*/ - if (es1371->uart_ctrl & UART_CTRL_TXINTEN) - es1371->int_status |= INT_STATUS_UART; - else - es1371->int_status &= ~INT_STATUS_UART; - } else if (!(es1371->uart_ctrl & UART_CTRL_RXINTEN) && ((es1371->uart_ctrl & UART_CTRL_TXINTEN))) { /*Or enable the UART IRQ and the respective TX bits only when the MIDI Output is enabled*/ - es1371->int_status |= INT_STATUS_UART; - } - - if (es1371->uart_ctrl & UART_CTRL_RXINTEN) { - if (es1371->uart_ctrl & UART_CTRL_TXINTEN) - es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); - else - es1371->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY); - } else - es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); - - es1371_update_irqs(es1371); - } - - if (es1371->int_ctrl & INT_DAC1_EN) { - int frac = es1371->dac[0].ac & 0x7fff; - int idx = es1371->dac[0].ac >> 15; - int samp1_l = es1371->dac[0].filtered_l[idx]; - int samp1_r = es1371->dac[0].filtered_r[idx]; - int samp2_l = es1371->dac[0].filtered_l[(idx + 1) & 31]; - int samp2_r = es1371->dac[0].filtered_r[(idx + 1) & 31]; - - es1371->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; - es1371->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; - es1371->dac[0].ac += es1371->dac[0].vf; - es1371->dac[0].ac &= ((32 << 15) - 1); - if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos) - { - es1371_next_sample_filtered(es1371, 0, es1371->dac[0].f_pos ? 16 : 0); - es1371->dac[0].f_pos = (es1371->dac[0].f_pos + 1) & 1; + /* Interrupt/Chip Select Status Register, Address 04H + Addressable as longword only */ + case 0x04: + ret = dev->int_status; + audiopci_log("[R] STATUS = %08X\n", ret); + break; - es1371->dac[0].curr_samp_ct--; - if (es1371->dac[0].curr_samp_ct < 0) - { - es1371->int_status |= INT_STATUS_DAC1; - es1371_update_irqs(es1371); - es1371->dac[0].curr_samp_ct = es1371->dac[0].samp_ct; - } - } - } + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + case 0x0c: + ret = dev->mem_page; + break; - if (es1371->int_ctrl & INT_DAC2_EN) - { - int frac = es1371->dac[1].ac & 0x7fff; - int idx = es1371->dac[1].ac >> 15; - int samp1_l = es1371->dac[1].filtered_l[idx]; - int samp1_r = es1371->dac[1].filtered_r[idx]; - int samp2_l = es1371->dac[1].filtered_l[(idx + 1) & 31]; - int samp2_r = es1371->dac[1].filtered_r[(idx + 1) & 31]; - - es1371->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; - es1371->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; - es1371->dac[1].ac += es1371->dac[1].vf; - es1371->dac[1].ac &= ((32 << 15) - 1); - if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos) - { - es1371_next_sample_filtered(es1371, 1, es1371->dac[1].f_pos ? 16 : 0); - es1371->dac[1].f_pos = (es1371->dac[1].f_pos + 1) & 1; + /* Sample Rate Converter Interface Register, Address 10H + Addressable as longword only */ + case 0x10: + ret = dev->sr_cir & ~0xffff; + ret |= dev->sr_ram[dev->sr_cir >> 25]; + break; - es1371->dac[1].curr_samp_ct--; - if (es1371->dac[1].curr_samp_ct < 0) - { - es1371->int_status |= INT_STATUS_DAC2; - es1371_update_irqs(es1371); - es1371->dac[1].curr_samp_ct = es1371->dac[1].samp_ct; - } - } - } + /* CODEC Read Register, Address 14H + Addressable as longword only */ + case 0x14: + ret = dev->codec_ctrl | CODEC_READY; + break; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + case 0x18: + ret = (dev->legacy_ctrl & 0xffff07fd) | 0x0000f800; + break; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + case 0x20: + ret = dev->si_cr | 0xff800000; + break; + + /* DAC1 Channel Sample Count Register, Address 24H + Addressable as word, longword */ + case 0x24: + ret = dev->dac[0].samp_ct | (((uint32_t) dev->dac[0].curr_samp_ct) << 16); + break; + + /* DAC2 Channel Sample Count Register, Address 28H + Addressable as word, longword */ + case 0x28: + ret = dev->dac[1].samp_ct | (((uint32_t) dev->dac[1].curr_samp_ct) << 16); + break; + + /* ADC Channel Sample Count Register, Address 2CH + Addressable as word, longword */ + case 0x2c: + ret = dev->adc.samp_ct | (((uint32_t) dev->adc.curr_samp_ct) << 16); + break; + + case 0x30: + case 0x34: + case 0x38: + case 0x3c: + ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page); + break; + } + + audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret); + return ret; } -static void es1371_get_buffer(int32_t *buffer, int len, void *p) +static void +es1371_outb(uint16_t port, uint8_t val, void *p) { - es1371_t *es1371 = (es1371_t *)p; - int c; + es1371_t *dev = (es1371_t *) p; + uint32_t old_legacy_ctrl; - es1371_update(es1371); + audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val); - for (c = 0; c < len * 2; c++) - buffer[c] += (es1371->buffer[c] / 2); - - es1371->pos = 0; + switch (port & 0x3f) { + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + case 0x00: + if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) { + dev->dac[0].addr = dev->dac[0].addr_latch; + dev->dac[0].buffer_pos = 0; + dev->dac[0].buffer_pos_end = 0; + es1371_fetch(dev, 0); + } + if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) { + dev->dac[1].addr = dev->dac[1].addr_latch; + dev->dac[1].buffer_pos = 0; + dev->dac[1].buffer_pos_end = 0; + es1371_fetch(dev, 1); + } + dev->int_ctrl = (dev->int_ctrl & 0xffffff00) | val; + break; + case 0x01: + dev->int_ctrl = (dev->int_ctrl & 0xffff00ff) | (val << 8); + break; + case 0x02: + dev->int_ctrl = (dev->int_ctrl & 0xff00ffff) | (val << 16); + break; + case 0x03: + dev->int_ctrl = (dev->int_ctrl & 0x00ffffff) | (val << 24); + gameport_remap(dev->gameport, 0x200 | ((val & 0x03) << 3)); + break; + + /* UART Data Register, Address 08H + Addressable as byte only */ + case 0x08: + audiopci_log("MIDI data = %02x\n", val); + /* TX does not use FIFO. */ + midi_raw_out_byte(val); + es1371_set_tx_irq(dev, 1); + break; + + /* UART Control Register, Address 09H + Addressable as byte only */ + case 0x09: + audiopci_log("[W] UART CTRL = %02X\n", val); + dev->uart_ctrl = val & 0xe3; + + if ((val & 0x03) == 0x03) { + /* Reset TX */ + es1371_set_tx_irq(dev, 1); + + /* Software reset */ + es1371_reset_fifo(dev); + } else { + es1371_set_tx_irq(dev, 1); + + es1371_update_tx_irq(dev); + es1371_update_rx_irq(dev); + } + break; + + /* UART Reserved Register, Address 0AH + Addressable as byte only */ + case 0x0a: + audiopci_log("[W] UART RES = %02X\n", val); + dev->uart_res = val & 0x01; + break; + + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + case 0x0c: + dev->mem_page = val & 0xf; + break; + case 0x0d ... 0x0f: + break; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + case 0x18: + dev->legacy_ctrl |= LEGACY_INT; + break; + case 0x1a: + old_legacy_ctrl = dev->legacy_ctrl; + dev->legacy_ctrl = (dev->legacy_ctrl & 0xff00ffff) | (val << 16); + update_legacy(dev, old_legacy_ctrl); + break; + case 0x1b: + old_legacy_ctrl = dev->legacy_ctrl; + dev->legacy_ctrl = (dev->legacy_ctrl & 0x00ffffff) | (val << 24); + es1371_update_irqs(dev); + update_legacy(dev, old_legacy_ctrl); + break; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + case 0x20: + dev->si_cr = (dev->si_cr & 0xffffff00) | val; + break; + case 0x21: + dev->si_cr = (dev->si_cr & 0xffff00ff) | (val << 8); + if (!(dev->si_cr & SI_P1_INTR_EN)) + dev->int_status &= ~INT_STATUS_DAC1; + if (!(dev->si_cr & SI_P2_INTR_EN)) + dev->int_status &= ~INT_STATUS_DAC2; + es1371_update_irqs(dev); + break; + case 0x22: + dev->si_cr = (dev->si_cr & 0xff80ffff) | ((val & 0x7f) << 16); + break; + + default: + audiopci_log("Bad es1371_outb: port=%04x val=%02x\n", port, val); + } } -static inline double sinc(double x) +static void +es1371_outw(uint16_t port, uint16_t val, void *p) { - return sin(M_PI * x) / (M_PI * x); + es1371_t *dev = (es1371_t *) p; + uint32_t old_legacy_ctrl; + + switch (port & 0x3f) { + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + case 0x00: + if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) { + dev->dac[0].addr = dev->dac[0].addr_latch; + dev->dac[0].buffer_pos = 0; + dev->dac[0].buffer_pos_end = 0; + es1371_fetch(dev, 0); + } + if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) { + dev->dac[1].addr = dev->dac[1].addr_latch; + dev->dac[1].buffer_pos = 0; + dev->dac[1].buffer_pos_end = 0; + es1371_fetch(dev, 1); + } + dev->int_ctrl = (dev->int_ctrl & 0xffff0000) | val; + break; + case 0x02: + dev->int_ctrl = (dev->int_ctrl & 0x0000ffff) | (val << 16); + gameport_remap(dev->gameport, 0x200 | ((val & 0x0300) >> 5)); + break; + + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + case 0x0c: + dev->mem_page = val & 0xf; + break; + case 0x0e: + break; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + case 0x18: + dev->legacy_ctrl |= LEGACY_INT; + break; + case 0x1a: + old_legacy_ctrl = dev->legacy_ctrl; + dev->legacy_ctrl = (dev->legacy_ctrl & 0x0000ffff) | (val << 16); + es1371_update_irqs(dev); + update_legacy(dev, old_legacy_ctrl); + break; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + case 0x20: + dev->si_cr = (dev->si_cr & 0xffff0000) | val; + if (!(dev->si_cr & SI_P1_INTR_EN)) + dev->int_status &= ~INT_STATUS_DAC1; + if (!(dev->si_cr & SI_P2_INTR_EN)) + dev->int_status &= ~INT_STATUS_DAC2; + es1371_update_irqs(dev); + break; + case 0x22: + dev->si_cr = (dev->si_cr & 0xff80ffff) | ((val & 0x007f) << 16); + break; + + /* DAC1 Channel Sample Count Register, Address 24H + Addressable as word, longword */ + case 0x24: + dev->dac[0].samp_ct = val; + break; + + /* DAC2 Channel Sample Count Register, Address 28H + Addressable as word, longword */ + case 0x28: + dev->dac[1].samp_ct = val; + break; + + /* ADC Channel Sample Count Register, Address 2CH + Addressable as word, longword */ + case 0x2c: + dev->adc.samp_ct = val; + break; + } } -static void generate_es1371_filter() +static void +es1371_outl(uint16_t port, uint32_t val, void *p) { - /*Cutoff frequency = 1 / 32*/ - float fC = 1.0 / 32.0; - float gain; - int n; - - for (n = 0; n < ES1371_NCoef; n++) - { - /*Blackman window*/ - double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(ES1371_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(ES1371_NCoef-1))); - /*Sinc filter*/ - double h = sinc(2.0 * fC * ((double)n - ((double)(ES1371_NCoef-1) / 2.0))); - - /*Create windowed-sinc filter*/ - low_fir_es1371_coef[n] = w * h; - } - - low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0; + es1371_t *dev = (es1371_t *) p; + uint32_t old_legacy_ctrl; - gain = 0.0; - for (n = 0; n < ES1371_NCoef; n++) - gain += low_fir_es1371_coef[n] / (float)N; + audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val); - gain /= 0.95; + switch (port & 0x3f) { + /* Interrupt/Chip Select Control Register, Address 00H + Addressable as byte, word, longword */ + case 0x00: + if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) { + dev->dac[0].addr = dev->dac[0].addr_latch; + dev->dac[0].buffer_pos = 0; + dev->dac[0].buffer_pos_end = 0; + es1371_fetch(dev, 0); + } + if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) { + dev->dac[1].addr = dev->dac[1].addr_latch; + dev->dac[1].buffer_pos = 0; + dev->dac[1].buffer_pos_end = 0; + es1371_fetch(dev, 1); + } + dev->int_ctrl = val; + gameport_remap(dev->gameport, 0x200 | ((val & 0x03000000) >> 21)); + break; - /*Normalise filter, to produce unity gain*/ - for (n = 0; n < ES1371_NCoef; n++) - low_fir_es1371_coef[n] /= gain; -} + /* Interrupt/Chip Select Status Register, Address 04H + Addressable as longword only */ + case 0x04: + audiopci_log("[W] STATUS = %08X\n", val); + break; -static void *es1371_init(const device_t *info) -{ - es1371_t *es1371 = malloc(sizeof(es1371_t)); - memset(es1371, 0, sizeof(es1371_t)); - - sound_add_handler(es1371_get_buffer, es1371); + /* Memory Page Register, Address 0CH + Addressable as byte, word, longword */ + case 0x0c: + dev->mem_page = val & 0xf; + break; - es1371->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); - - timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); - - generate_es1371_filter(); - - /* Return a CS4297A like VMWare does. */ - es1371->codec_regs[0x7c] = 0x4352; - es1371->codec_regs[0x7e] = 0x5910; - - return es1371; -} - -static void es1371_close(void *p) -{ - es1371_t *es1371 = (es1371_t *)p; - - free(es1371); -} - -static void es1371_speed_changed(void *p) -{ - es1371_t *es1371 = (es1371_t *)p; - - es1371->dac[1].latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); -} - -void es1371_add_status_info_dac(es1371_t *es1371, char *s, int max_len, int dac_nr) -{ - int ena = dac_nr ? INT_DAC2_EN : INT_DAC1_EN; - char *dac_name = dac_nr ? "DAC2 (Wave)" : "DAC1 (MIDI)"; - char temps[128]; - - if (es1371->int_ctrl & ena) - { - int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); - double freq = 48000.0 * ((double)es1371->dac[dac_nr].vf / (32768.0 * 16.0)); - - switch (format) - { - case FORMAT_MONO_8: - snprintf(temps, 128, "%s format : 8-bit mono\n", dac_name); + /* Sample Rate Converter Interface Register, Address 10H + Addressable as longword only */ + case 0x10: + dev->sr_cir = val & 0xfff8ffff; /*Bits 16 to 18 are undefined*/ + if (dev->sr_cir & SRC_RAM_WE) { + dev->sr_ram[dev->sr_cir >> 25] = val & 0xffff; + switch (dev->sr_cir >> 25) { + case 0x71: + dev->dac[0].vf = (dev->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5); + dev->dac[0].ac = (dev->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + dev->dac[0].f_pos = 0; break; - case FORMAT_STEREO_8: - snprintf(temps, 128, "%s format : 8-bit stereo\n", dac_name); + case 0x72: + dev->dac[0].ac = (dev->dac[0].ac & ~0x7fff) | (val & 0x7fff); break; - case FORMAT_MONO_16: - snprintf(temps, 128, "%s format : 16-bit mono\n", dac_name); + case 0x73: + dev->dac[0].vf = (dev->dac[0].vf & ~0x7fff) | (val & 0x7fff); break; - case FORMAT_STEREO_16: - snprintf(temps, 128, "%s format : 16-bit stereo\n", dac_name); + + case 0x75: + dev->dac[1].vf = (dev->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5); + dev->dac[1].ac = (dev->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + dev->dac[1].f_pos = 0; + break; + case 0x76: + dev->dac[1].ac = (dev->dac[1].ac & ~0x7fff) | (val & 0x7fff); + break; + case 0x77: + dev->dac[1].vf = (dev->dac[1].vf & ~0x7fff) | (val & 0x7fff); + break; + + case 0x7c: + dev->dac[0].vol_l = (int32_t) (int16_t) (val & 0xffff); + break; + case 0x7d: + dev->dac[0].vol_r = (int32_t) (int16_t) (val & 0xffff); + break; + case 0x7e: + dev->dac[1].vol_l = (int32_t) (int16_t) (val & 0xffff); + break; + case 0x7f: + dev->dac[1].vol_r = (int32_t) (int16_t) (val & 0xffff); break; } - - strncat(s, temps, max_len); - max_len -= strlen(temps); + } + break; - snprintf(temps, 128, "Playback frequency : %i Hz\n", (int)freq); - strncat(s, temps, max_len); - } - else - { - snprintf(temps, max_len, "%s stopped\n", dac_name); - strncat(s, temps, max_len); - } + /* CODEC Write Register, Address 14H + Addressable as longword only */ + case 0x14: + if (val & CODEC_READ) { + dev->codec_ctrl &= 0x00ff0000; + dev->codec_ctrl |= ac97_codec_readw(dev->codec, val >> 16); + } else { + dev->codec_ctrl = val & 0x00ffffff; + ac97_codec_writew(dev->codec, val >> 16, val); + + ac97_codec_getattn(dev->codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); + ac97_codec_getattn(dev->codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r); + ac97_codec_getattn(dev->codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); + } + break; + + /* Legacy Control/Status Register, Address 18H + Addressable as byte, word, longword */ + case 0x18: + old_legacy_ctrl = dev->legacy_ctrl; + dev->legacy_ctrl = (dev->legacy_ctrl & 0x0000ffff) | (val & 0xffff0000); + dev->legacy_ctrl |= LEGACY_INT; + es1371_update_irqs(dev); + update_legacy(dev, old_legacy_ctrl); + break; + + /* Serial Interface Control Register, Address 20H + Addressable as byte, word, longword */ + case 0x20: + dev->si_cr = (val & 0x007fffff) | 0xff800000; + if (!(dev->si_cr & SI_P1_INTR_EN)) + dev->int_status &= ~INT_STATUS_DAC1; + if (!(dev->si_cr & SI_P2_INTR_EN)) + dev->int_status &= ~INT_STATUS_DAC2; + es1371_update_irqs(dev); + break; + + /* DAC1 Channel Sample Count Register, Address 24H + Addressable as word, longword */ + case 0x24: + dev->dac[0].samp_ct = val & 0xffff; + break; + + /* DAC2 Channel Sample Count Register, Address 28H + Addressable as word, longword */ + case 0x28: + dev->dac[1].samp_ct = val & 0xffff; + break; + + /* ADC Channel Sample Count Register, Address 2CH + Addressable as word, longword */ + case 0x2c: + dev->adc.samp_ct = val & 0xffff; + break; + + case 0x30: + case 0x34: + case 0x38: + case 0x3c: + es1371_write_frame_reg(dev, port & 0x3c, dev->mem_page, val); + break; + } } -const device_t es1371_device = +static void +capture_event(es1371_t *dev, int type, int rw, uint16_t port) { - "Ensoniq AudioPCI (ES1371)", - DEVICE_PCI, - 0, - es1371_init, - es1371_close, - NULL, - NULL, - es1371_speed_changed, - NULL, - NULL + dev->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK); + dev->legacy_ctrl |= type; + if (rw) + dev->legacy_ctrl |= LEGACY_EVENT_TYPE_RW; + else + dev->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW; + dev->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK); + dev->legacy_ctrl &= ~LEGACY_INT; + nmi_raise(); +} + +static void +capture_write_sscape(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 1, port); +} + +static void +capture_write_codec(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 1, port); +} + +static void +capture_write_sb(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 1, port); +} + +static void +capture_write_adlib(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 1, port); +} + +static void +capture_write_master_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port); +} + +static void +capture_write_master_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port); +} + +static void +capture_write_slave_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port); +} + +static void +capture_write_slave_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port); +} + +static uint8_t +capture_read_sscape(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 0, port); + return 0xff; +} + +static uint8_t +capture_read_codec(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 0, port); + return 0xff; +} + +static uint8_t +capture_read_sb(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 0, port); + return 0xff; +} + +static uint8_t +capture_read_adlib(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 0, port); + return 0xff; +} + +static uint8_t +capture_read_master_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port); + return 0xff; +} + +static uint8_t +capture_read_master_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port); + return 0xff; +} + +static uint8_t +capture_read_slave_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port); + return 0xff; +} + +static uint8_t +capture_read_slave_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port); + return 0xff; +} + +static void +update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl) +{ + if (old_legacy_ctrl & LEGACY_CAPTURE_SSCAPE) { + switch ((old_legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) { + case 0: + io_removehandler(0x0320, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + case 1: + io_removehandler(0x0330, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + case 2: + io_removehandler(0x0340, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + case 3: + io_removehandler(0x0350, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + } + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_CODEC) { + switch ((old_legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) { + case 0: + io_removehandler(0x0530, 0x0008, + capture_read_codec, NULL, NULL, + capture_write_codec, NULL, NULL, dev); + break; + case 2: + io_removehandler(0x0e80, 0x0008, + capture_read_codec, NULL, NULL, + capture_write_codec, NULL, NULL, dev); + break; + case 3: + io_removehandler(0x0f40, 0x0008, + capture_read_codec, NULL, NULL, + capture_write_codec, NULL, NULL, dev); + break; + } + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_SB) { + if (!(old_legacy_ctrl & LEGACY_SB_ADDR)) { + io_removehandler(0x0220, 0x0010, + capture_read_sb, NULL, NULL, + capture_write_sb, NULL, NULL, dev); + } else { + io_removehandler(0x0240, 0x0010, + capture_read_sb, NULL, NULL, + capture_write_sb, NULL, NULL, dev); + } + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_ADLIB) { + io_removehandler(0x0388, 0x0004, + capture_read_adlib, NULL, NULL, + capture_write_adlib, NULL, NULL, dev); + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) { + io_removehandler(0x0020, 0x0002, + capture_read_master_pic, NULL, NULL, + capture_write_master_pic, NULL, NULL, dev); + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) { + io_removehandler(0x0000, 0x0010, + capture_read_master_dma, NULL, NULL, + capture_write_master_dma, NULL, NULL, dev); + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) { + io_removehandler(0x00a0, 0x0002, + capture_read_slave_pic, NULL, NULL, + capture_write_slave_pic, NULL, NULL, dev); + } + + if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) { + io_removehandler(0x00c0, 0x0020, + capture_read_slave_dma, NULL, NULL, + capture_write_slave_dma, NULL, NULL, dev); + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_SSCAPE) { + switch ((dev->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) { + case 0: + io_sethandler(0x0320, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + case 1: + io_sethandler(0x0330, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + case 2: + io_sethandler(0x0340, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + case 3: + io_sethandler(0x0350, 0x0008, + capture_read_sscape, NULL, NULL, + capture_write_sscape, NULL, NULL, dev); + break; + } + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_CODEC) { + switch ((dev->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) { + case 0: + io_sethandler(0x0530, 0x0008, + capture_read_codec, NULL, NULL, + capture_write_codec, NULL, NULL, dev); + break; + case 2: + io_sethandler(0x0e80, 0x0008, + capture_read_codec, NULL, NULL, + capture_write_codec, NULL, NULL, dev); + break; + case 3: + io_sethandler(0x0f40, 0x0008, + capture_read_codec, NULL, NULL, + capture_write_codec, NULL, NULL, dev); + break; + } + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_SB) { + if (!(dev->legacy_ctrl & LEGACY_SB_ADDR)) { + io_sethandler(0x0220, 0x0010, + capture_read_sb, NULL, NULL, + capture_write_sb, NULL, NULL, dev); + } else { + io_sethandler(0x0240, 0x0010, + capture_read_sb, NULL, NULL, + capture_write_sb, NULL, NULL, dev); + } + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_ADLIB) { + io_sethandler(0x0388, 0x0004, + capture_read_adlib, NULL, NULL, + capture_write_adlib, NULL, NULL, dev); + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) { + io_sethandler(0x0020, 0x0002, + capture_read_master_pic, NULL, NULL, + capture_write_master_pic, NULL, NULL, dev); + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) { + io_sethandler(0x0000, 0x0010, + capture_read_master_dma, NULL, NULL, + capture_write_master_dma, NULL, NULL, dev); + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) { + io_sethandler(0x00a0, 0x0002, + capture_read_slave_pic, NULL, NULL, + capture_write_slave_pic, NULL, NULL, dev); + } + + if (dev->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) { + io_sethandler(0x00c0, 0x0020, + capture_read_slave_dma, NULL, NULL, + capture_write_slave_dma, NULL, NULL, dev); + } +} + +static uint8_t +es1371_pci_read(int func, int addr, void *p) +{ + es1371_t *dev = (es1371_t *) p; + + if (func > 0) + return 0xff; + + if ((addr > 0x3f) && ((addr < 0xdc) || (addr > 0xe1))) + return 0x00; + + switch (addr) { + case 0x00: + return 0x74; /* Ensoniq */ + case 0x01: + return 0x12; + + case 0x02: + return 0x71; /* ES1371 */ + case 0x03: + return 0x13; + + case 0x04: + return dev->pci_command; + case 0x05: + return dev->pci_serr; + + case 0x06: + return 0x10; /* Supports ACPI */ + case 0x07: + return 0x00; + + case 0x08: + return 0x08; /* Revision ID - 0x02 (datasheet, VMware) has issues with the 2001 Creative WDM driver */ + case 0x09: + return 0x00; /* Multimedia audio device */ + case 0x0a: + return 0x01; + case 0x0b: + return 0x04; + + case 0x10: + return 0x01 | (dev->base_addr & 0xc0); /* memBaseAddr */ + case 0x11: + return dev->base_addr >> 8; + case 0x12: + return dev->base_addr >> 16; + case 0x13: + return dev->base_addr >> 24; + + case 0x2c: + return 0x74; /* Subsystem vendor ID */ + case 0x2d: + return 0x12; + case 0x2e: + return 0x71; + case 0x2f: + return 0x13; + + case 0x34: + return 0xdc; /* Capabilites pointer */ + + case 0x3c: + return dev->int_line; + case 0x3d: + return 0x01; /* INTA */ + + case 0x3e: + return 0xc; /* Minimum grant */ + case 0x3f: + return 0x80; /* Maximum latency */ + + case 0xdc: + return 0x01; /* Capabilities identifier */ + case 0xdd: + return 0x00; /* Next item pointer */ + case 0xde: + return 0x31; /* Power management capabilities */ + case 0xdf: + return 0x6c; + + case 0xe0: + return dev->pmcsr & 0xff; + case 0xe1: + return dev->pmcsr >> 8; + } + + return 0x00; +} + +static void +es1371_io_set(es1371_t *dev, int set) +{ + if (dev->pci_command & PCI_COMMAND_IO) { + io_handler(set, dev->base_addr, 0x0040, + es1371_inb, es1371_inw, es1371_inl, + es1371_outb, es1371_outw, es1371_outl, dev); + } +} + +static void +es1371_pci_write(int func, int addr, uint8_t val, void *p) +{ + es1371_t *dev = (es1371_t *) p; + + if (func) + return; + + switch (addr) { + case 0x04: + es1371_io_set(dev, 0); + dev->pci_command = val & 0x05; + es1371_io_set(dev, 1); + break; + case 0x05: + dev->pci_serr = val & 1; + break; + + case 0x10: + es1371_io_set(dev, 0); + dev->base_addr = (dev->base_addr & 0xffffff00) | (val & 0xc0); + es1371_io_set(dev, 1); + break; + case 0x11: + es1371_io_set(dev, 0); + dev->base_addr = (dev->base_addr & 0xffff00c0) | (val << 8); + es1371_io_set(dev, 1); + break; + case 0x12: + dev->base_addr = (dev->base_addr & 0xff00ffc0) | (val << 16); + break; + case 0x13: + dev->base_addr = (dev->base_addr & 0x00ffffc0) | (val << 24); + break; + + case 0x3c: + dev->int_line = val; + break; + + case 0xe0: + dev->pmcsr = (dev->pmcsr & 0xff00) | (val & 0x03); + break; + case 0xe1: + dev->pmcsr = (dev->pmcsr & 0x00ff) | ((val & 0x01) << 8); + break; + } +} + +static void +es1371_fetch(es1371_t *dev, int dac_nr) +{ + if (dev->si_cr & (dac_nr ? SI_P2_PAUSE : SI_P1_PAUSE)) + return; + + int format = dac_nr ? ((dev->si_cr >> 2) & 3) : (dev->si_cr & 3); + int pos = dev->dac[dac_nr].buffer_pos & 63; + int c; + + switch (format) { + case FORMAT_MONO_8: + for (c = 0; c < 32; c += 4) { + dev->dac[dac_nr].buffer_l[(pos + c) & 63] = dev->dac[dac_nr].buffer_r[(pos + c) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr) ^ 0x80) << 8; + dev->dac[dac_nr].buffer_l[(pos + c + 1) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 1) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 1) ^ 0x80) << 8; + dev->dac[dac_nr].buffer_l[(pos + c + 2) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 2) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 2) ^ 0x80) << 8; + dev->dac[dac_nr].buffer_l[(pos + c + 3) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 3) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 3) ^ 0x80) << 8; + dev->dac[dac_nr].addr += 4; + + dev->dac[dac_nr].buffer_pos_end += 4; + dev->dac[dac_nr].count++; + + if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) { + dev->dac[dac_nr].count = 0; + dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch; + break; + } + } + break; + + case FORMAT_STEREO_8: + for (c = 0; c < 16; c += 2) { + dev->dac[dac_nr].buffer_l[(pos + c) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr) ^ 0x80) << 8; + dev->dac[dac_nr].buffer_r[(pos + c) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 1) ^ 0x80) << 8; + dev->dac[dac_nr].buffer_l[(pos + c + 1) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 2) ^ 0x80) << 8; + dev->dac[dac_nr].buffer_r[(pos + c + 1) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 3) ^ 0x80) << 8; + dev->dac[dac_nr].addr += 4; + + dev->dac[dac_nr].buffer_pos_end += 2; + dev->dac[dac_nr].count++; + + if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) { + dev->dac[dac_nr].count = 0; + dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch; + break; + } + } + break; + + case FORMAT_MONO_16: + for (c = 0; c < 16; c += 2) { + dev->dac[dac_nr].buffer_l[(pos + c) & 63] = dev->dac[dac_nr].buffer_r[(pos + c) & 63] = mem_readw_phys(dev->dac[dac_nr].addr); + dev->dac[dac_nr].buffer_l[(pos + c + 1) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 1) & 63] = mem_readw_phys(dev->dac[dac_nr].addr + 2); + dev->dac[dac_nr].addr += 4; + + dev->dac[dac_nr].buffer_pos_end += 2; + dev->dac[dac_nr].count++; + + if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) { + dev->dac[dac_nr].count = 0; + dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch; + break; + } + } + break; + + case FORMAT_STEREO_16: + for (c = 0; c < 4; c++) { + dev->dac[dac_nr].buffer_l[(pos + c) & 63] = mem_readw_phys(dev->dac[dac_nr].addr); + dev->dac[dac_nr].buffer_r[(pos + c) & 63] = mem_readw_phys(dev->dac[dac_nr].addr + 2); + dev->dac[dac_nr].addr += 4; + + dev->dac[dac_nr].buffer_pos_end++; + dev->dac[dac_nr].count++; + + if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) { + dev->dac[dac_nr].count = 0; + dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch; + break; + } + } + break; + } +} + +static inline float +low_fir_es1371(int dac_nr, int i, float NewSample) +{ + static float x[2][2][128]; // input samples + static int x_pos[2] = { 0, 0 }; + float out = 0.0; + int read_pos, n_coef; + int pos = x_pos[dac_nr]; + + x[dac_nr][i][pos] = NewSample; + + /* Since only 1/16th of input samples are non-zero, only filter those that + are valid.*/ + read_pos = (pos + 15) & (127 & ~15); + n_coef = (16 - pos) & 15; + + while (n_coef < ES1371_NCoef) { + out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos]; + read_pos = (read_pos + 16) & (127 & ~15); + n_coef += 16; + } + + if (i == 1) { + x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127; + if (x_pos[dac_nr] > 127) + x_pos[dac_nr] = 0; + } + + return out; +} + +static void +es1371_next_sample_filtered(es1371_t *dev, int dac_nr, int out_idx) +{ + int out_l, out_r; + int c; + + if ((dev->dac[dac_nr].buffer_pos - dev->dac[dac_nr].buffer_pos_end) >= 0) + es1371_fetch(dev, dac_nr); + + out_l = dev->dac[dac_nr].buffer_l[dev->dac[dac_nr].buffer_pos & 63]; + out_r = dev->dac[dac_nr].buffer_r[dev->dac[dac_nr].buffer_pos & 63]; + + dev->dac[dac_nr].filtered_l[out_idx] = (int) low_fir_es1371(dac_nr, 0, (float) out_l); + dev->dac[dac_nr].filtered_r[out_idx] = (int) low_fir_es1371(dac_nr, 1, (float) out_r); + + for (c = 1; c < 16; c++) { + dev->dac[dac_nr].filtered_l[out_idx + c] = (int) low_fir_es1371(dac_nr, 0, 0); + dev->dac[dac_nr].filtered_r[out_idx + c] = (int) low_fir_es1371(dac_nr, 1, 0); + } + + dev->dac[dac_nr].buffer_pos++; +} + +static void +es1371_update(es1371_t *dev) +{ + int32_t l, r; + + l = (dev->dac[0].out_l * dev->dac[0].vol_l) >> 12; + l += ((dev->dac[1].out_l * dev->dac[1].vol_l) >> 12); + r = (dev->dac[0].out_r * dev->dac[0].vol_r) >> 12; + r += ((dev->dac[1].out_r * dev->dac[1].vol_r) >> 12); + + l >>= 1; + r >>= 1; + + l = (((l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15; + r = (((r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15; + + if (l < -32768) + l = -32768; + else if (l > 32767) + l = 32767; + if (r < -32768) + r = -32768; + else if (r > 32767) + r = 32767; + + for (; dev->pos < sound_pos_global; dev->pos++) { + dev->buffer[dev->pos * 2] = l; + dev->buffer[dev->pos * 2 + 1] = r; + } +} + +static void +es1371_poll(void *p) +{ + es1371_t *dev = (es1371_t *) p; + int frac, idx, samp1_l, samp1_r, samp2_l, samp2_r; + + timer_advance_u64(&dev->dac[1].timer, dev->dac[1].latch); + + es1371_scan_fifo(dev); + + es1371_update(dev); + + if (dev->int_ctrl & INT_DAC1_EN) { + frac = dev->dac[0].ac & 0x7fff; + idx = dev->dac[0].ac >> 15; + samp1_l = dev->dac[0].filtered_l[idx]; + samp1_r = dev->dac[0].filtered_r[idx]; + samp2_l = dev->dac[0].filtered_l[(idx + 1) & 31]; + samp2_r = dev->dac[0].filtered_r[(idx + 1) & 31]; + + dev->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + dev->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; + dev->dac[0].ac += dev->dac[0].vf; + dev->dac[0].ac &= ((32 << 15) - 1); + if ((dev->dac[0].ac >> (15 + 4)) != dev->dac[0].f_pos) { + es1371_next_sample_filtered(dev, 0, dev->dac[0].f_pos ? 16 : 0); + dev->dac[0].f_pos = (dev->dac[0].f_pos + 1) & 1; + + dev->dac[0].curr_samp_ct--; + if (dev->dac[0].curr_samp_ct < 0) { + dev->int_status |= INT_STATUS_DAC1; + es1371_update_irqs(dev); + dev->dac[0].curr_samp_ct = dev->dac[0].samp_ct; + } + } + } + + if (dev->int_ctrl & INT_DAC2_EN) { + frac = dev->dac[1].ac & 0x7fff; + idx = dev->dac[1].ac >> 15; + samp1_l = dev->dac[1].filtered_l[idx]; + samp1_r = dev->dac[1].filtered_r[idx]; + samp2_l = dev->dac[1].filtered_l[(idx + 1) & 31]; + samp2_r = dev->dac[1].filtered_r[(idx + 1) & 31]; + + dev->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + dev->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; + dev->dac[1].ac += dev->dac[1].vf; + dev->dac[1].ac &= ((32 << 15) - 1); + if ((dev->dac[1].ac >> (15 + 4)) != dev->dac[1].f_pos) { + es1371_next_sample_filtered(dev, 1, dev->dac[1].f_pos ? 16 : 0); + dev->dac[1].f_pos = (dev->dac[1].f_pos + 1) & 1; + + dev->dac[1].curr_samp_ct--; + if (dev->dac[1].curr_samp_ct < 0) { + dev->int_status |= INT_STATUS_DAC2; + es1371_update_irqs(dev); + dev->dac[1].curr_samp_ct = dev->dac[1].samp_ct; + } + } + } +} + +static void +es1371_get_buffer(int32_t *buffer, int len, void *p) +{ + es1371_t *dev = (es1371_t *) p; + int c; + + es1371_update(dev); + + for (c = 0; c < len * 2; c++) + buffer[c] += (dev->buffer[c] / 2); + + dev->pos = 0; +} + +static void +es1371_filter_cd_audio(int channel, double *buffer, void *p) +{ + es1371_t *dev = (es1371_t *) p; + double c; + int cd = channel ? dev->cd_vol_r : dev->cd_vol_l; + int master = channel ? dev->master_vol_r : dev->master_vol_l; + + c = ((((*buffer) * cd) / 65536.0) * master) / 65536.0; + *buffer = c; +} + +static inline double +sinc(double x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +static void +generate_es1371_filter(void) +{ + /* Cutoff frequency = 1 / 32 */ + float fC = 1.0 / 32.0; + float gain; + int n; + + for (n = 0; n < ES1371_NCoef; n++) { + /* Blackman window */ + double w = 0.42 - (0.5 * cos((2.0 * n * M_PI) / (double) (ES1371_NCoef - 1))) + (0.08 * cos((4.0 * n * M_PI) / (double) (ES1371_NCoef - 1))); + /* Sinc filter */ + double h = sinc(2.0 * fC * ((double) n - ((double) (ES1371_NCoef - 1) / 2.0))); + + /* Create windowed-sinc filter */ + low_fir_es1371_coef[n] = w * h; + } + + low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < ES1371_NCoef; n++) + gain += low_fir_es1371_coef[n] / (float) N; + + gain /= 0.95; + + /* Normalise filter, to produce unity gain */ + for (n = 0; n < ES1371_NCoef; n++) + low_fir_es1371_coef[n] /= gain; +} + +static void +es1371_input_msg(void *p, uint8_t *msg, uint32_t len) +{ + es1371_t *dev = (es1371_t *) p; + uint8_t i; + + for (i = 0; i < len; i++) + es1371_write_fifo(dev, msg[i]); +} + +static int +es1371_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + es1371_t *dev = (es1371_t *) p; + uint32_t i = -1; + + audiopci_log("Abort = %i\n", abort); + + if (dev->uart_status & UART_STATUS_RXRDY) + abort = 1; + + if (!abort) { + for (i = 0; i < len; i++) { + es1371_write_fifo(dev, buffer[i]); + if (dev->uart_status & UART_STATUS_RXRDY) + break; + } + } + + /* The last sent position is in i. Return 7 - i. */ + + return 7 - i; +} + +static void * +es1371_init(const device_t *info) +{ + es1371_t *dev = malloc(sizeof(es1371_t)); + memset(dev, 0x00, sizeof(es1371_t)); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, es1371_input_msg, es1371_input_sysex, dev); + + sound_add_handler(es1371_get_buffer, dev); + sound_set_cd_audio_filter(es1371_filter_cd_audio, dev); + + dev->gameport = gameport_add(&gameport_pnp_device); + gameport_remap(dev->gameport, 0x200); + + dev->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, dev); + + timer_add(&dev->dac[1].timer, es1371_poll, dev, 1); + + generate_es1371_filter(); + + ac97_codec = &dev->codec; + ac97_codec_count = 1; + ac97_codec_id = 0; + /* Let the machine decide the codec on onboard implementations. */ + if (!info->local) + device_add(ac97_codec_get(device_get_config_int("codec"))); + + es1371_reset(dev); + + return dev; +} + +static void +es1371_close(void *p) +{ + es1371_t *dev = (es1371_t *) p; + + free(dev); +} + +static void +es1371_speed_changed(void *p) +{ + es1371_t *dev = (es1371_t *) p; + + dev->dac[1].latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 48000.0)); +} + +static const device_config_t es1371_config[] = { +// clang-format off + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "Asahi Kasei AK4540", + .value = AC97_CODEC_AK4540 + }, + { + .description = "Crystal CS4297", + .value = AC97_CODEC_CS4297 + }, + { + .description = "Crystal CS4297A", + .value = AC97_CODEC_CS4297A + }, + { + .description = "SigmaTel STAC9708", + .value = AC97_CODEC_STAC9708 + }, + { + .description = "SigmaTel STAC9721", + .value = AC97_CODEC_STAC9721 + } + }, + .default_int = AC97_CODEC_CS4297A + }, + { + .name = "receive_input", + .description = "Receive input (MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -const device_t es1371_onboard_device = -{ - "Ensoniq AudioPCI (ES1371) (On-Board)", - DEVICE_PCI, - 1, - es1371_init, - es1371_close, - NULL, - NULL, - es1371_speed_changed, - NULL, - NULL +static const device_config_t es1371_onboard_config[] = { +// clang-format off + { + .name = "receive_input", + .description = "Receive input (MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +const device_t es1371_device = { + .name = "Ensoniq AudioPCI (ES1371)", + .internal_name = "es1371", + .flags = DEVICE_PCI, + .local = 0, + .init = es1371_init, + .close = es1371_close, + .reset = es1371_reset, + { .available = NULL }, + .speed_changed = es1371_speed_changed, + .force_redraw = NULL, + .config = es1371_config +}; + +const device_t es1371_onboard_device = { + .name = "Ensoniq AudioPCI (ES1371) (On-Board)", + .internal_name = "es1371_onboard", + .flags = DEVICE_PCI, + .local = 1, + .init = es1371_init, + .close = es1371_close, + .reset = es1371_reset, + { .available = NULL }, + .speed_changed = es1371_speed_changed, + .force_redraw = NULL, + .config = es1371_onboard_config }; diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index b88ee9abb..890734450 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -130,22 +130,23 @@ * are probably due to this. */ +#include #include -#include #include -#include +#include #include +#include #include -#include #define HAVE_STDARG_H + #include <86box/86box.h> -#include <86box/io.h> -#include <86box/timer.h> -#include <86box/pic.h> -#include <86box/nvr.h> #include <86box/device.h> -#include <86box/sound.h> +#include <86box/io.h> #include <86box/midi.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/pic.h> +#include <86box/sound.h> #include <86box/snd_ad1848.h> #include <86box/snd_azt2316a.h> #include <86box/snd_sb.h> @@ -161,1325 +162,1359 @@ /*e80, 11, 1 - 530=22*/ /*f40, 11, 1 - 530=22*/ +static int azt2316a_wss_dma[4] = { 0, 0, 1, 3 }; +static int azt2316a_wss_irq[8] = { 5, 7, 9, 10, 11, 12, 14, 15 }; /* W95 only uses 7-10, others may be wrong */ +// static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; -static int azt2316a_wss_dma[4] = {0, 0, 1, 3}; -static int azt2316a_wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-10, others may be wrong */ -//static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; +typedef struct azt2316a_t { + int type; + int wss_interrupt_after_config; -typedef struct azt2316a_t -{ - int type; - int wss_interrupt_after_config; + uint8_t wss_config; - uint8_t wss_config; + uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr; - uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr; + int cur_irq, cur_dma; + int cur_wss_enabled, cur_wss_irq, cur_wss_dma; + int cur_mpu401_irq; + int cur_mpu401_enabled; - int cur_irq, cur_dma; - int cur_wss_enabled, cur_wss_irq, cur_wss_dma; - int cur_mpu401_irq; - int cur_mpu401_enabled; + uint32_t config_word; + uint32_t config_word_unlocked; - uint32_t config_word; - uint32_t config_word_unlocked; + uint8_t cur_mode; - uint8_t cur_mode; + ad1848_t ad1848; + mpu_t *mpu; - ad1848_t ad1848; - mpu_t *mpu; - - sb_t *sb; + sb_t *sb; } azt2316a_t; -static uint8_t +static uint8_t azt2316a_wss_read(uint16_t addr, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - uint8_t temp; + azt2316a_t *azt2316a = (azt2316a_t *) p; + uint8_t temp; - /* TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to - 0x530 makes reading from 0x533 return 0x44, but writing 0x50 - makes this return 0x04. Why? */ - if (addr & 1) - temp = 4 | (azt2316a->wss_config & 0x40); - else - temp = 4 | (azt2316a->wss_config & 0xC0); + /* TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to + 0x530 makes reading from 0x533 return 0x44, but writing 0x50 + makes this return 0x04. Why? */ + if (addr & 1) + temp = 4 | (azt2316a->wss_config & 0x40); + else + temp = 4 | (azt2316a->wss_config & 0xC0); - return temp; -} - -static void + return temp; +} + +static void azt2316a_wss_write(uint16_t addr, uint8_t val, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - int interrupt = 0; + azt2316a_t *azt2316a = (azt2316a_t *) p; + int interrupt = 0; - if (azt2316a->wss_interrupt_after_config) { - if ((azt2316a->wss_config & 0x40) && !(val & 0x40)) { // TODO: is this the right edge? - interrupt = 1; - } - } + if (azt2316a->wss_interrupt_after_config) { + if ((azt2316a->wss_config & 0x40) && !(val & 0x40)) { // TODO: is this the right edge? + interrupt = 1; + } + } - azt2316a->wss_config = val; - azt2316a->cur_wss_dma = azt2316a_wss_dma[val & 3]; - azt2316a->cur_wss_irq = azt2316a_wss_irq[(val >> 3) & 7]; - ad1848_setdma(&azt2316a->ad1848, azt2316a_wss_dma[val & 3]); - ad1848_setirq(&azt2316a->ad1848, azt2316a_wss_irq[(val >> 3) & 7]); - - if (interrupt) - picint(1 << azt2316a->cur_wss_irq); + azt2316a->wss_config = val; + azt2316a->cur_wss_dma = azt2316a_wss_dma[val & 3]; + azt2316a->cur_wss_irq = azt2316a_wss_irq[(val >> 3) & 7]; + ad1848_setdma(&azt2316a->ad1848, azt2316a_wss_dma[val & 3]); + ad1848_setirq(&azt2316a->ad1848, azt2316a_wss_irq[(val >> 3) & 7]); + + if (interrupt) + picint(1 << azt2316a->cur_wss_irq); } /* generate a config word based on current settings */ -static void +static void azt1605_create_config_word(void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - uint32_t temp = 0; + azt2316a_t *azt2316a = (azt2316a_t *) p; + uint32_t temp = 0; - /* not implemented / hardcoded */ - uint8_t game_enable = 1; - uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ - uint8_t cd_dma8 = -1; - uint8_t cd_irq = 0; + /* not implemented / hardcoded */ + uint8_t game_enable = 1; + uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ + uint8_t cd_dma8 = -1; + uint8_t cd_irq = 0; - switch (azt2316a->cur_addr) { - case 0x220: - /* do nothing - temp += 0 << 0; */ - break; - case 0x240: - temp += 1 << 0; - break; -/* - case 0x260: // TODO: INVALID? - temp += 2 << 0; - break; - case 0x280: // TODO: INVALID? - temp += 3 << 0; - break; -*/ - } + switch (azt2316a->cur_addr) { + case 0x220: + /* do nothing + temp += 0 << 0; */ + break; + case 0x240: + temp += 1 << 0; + break; + /* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; + */ + } - switch (azt2316a->cur_irq) { - case 9: - temp += 1 << 8; - break; - case 3: - temp += 1 << 9; - break; - case 5: - temp += 1 << 10; - break; - case 7: - temp += 1 << 11; - break; - } + switch (azt2316a->cur_irq) { + case 9: + temp += 1 << 8; + break; + case 3: + temp += 1 << 9; + break; + case 5: + temp += 1 << 10; + break; + case 7: + temp += 1 << 11; + break; + } - switch (azt2316a->cur_wss_addr) { - case 0x530: - /* do nothing - temp += 0 << 16; */ - break; - case 0x604: - temp += 1 << 16; - break; - case 0xE80: - temp += 2 << 16; - break; - case 0xF40: - temp += 3 << 16; - break; - } + switch (azt2316a->cur_wss_addr) { + case 0x530: + /* do nothing + temp += 0 << 16; */ + break; + case 0x604: + temp += 1 << 16; + break; + case 0xE80: + temp += 2 << 16; + break; + case 0xF40: + temp += 3 << 16; + break; + } - if (azt2316a->cur_wss_enabled) - temp += 1 << 18; + if (azt2316a->cur_wss_enabled) + temp += 1 << 18; - if (game_enable) - temp += 1 << 4; + if (game_enable) + temp += 1 << 4; - switch (azt2316a->cur_mpu401_addr) { - case 0x300: - /* do nothing - temp += 0 << 2; */ - break; - case 0x330: - temp += 1 << 2; - break; - } + switch (azt2316a->cur_mpu401_addr) { + case 0x300: + /* do nothing + temp += 0 << 2; */ + break; + case 0x330: + temp += 1 << 2; + break; + } - if (azt2316a->cur_mpu401_enabled) - temp += 1 << 3; - - switch (cd_type) { - case 0: /* disabled - do nothing - temp += 0 << 5; */ - break; - case 1: // panasonic - temp += 1 << 5; - break; - case 2: // mitsumi/sony/aztech - temp += 2 << 5; - break; - case 3: // all enabled - temp += 3 << 5; - break; - case 4: // unused - temp += 4 << 5; - break; - case 5: // unused - temp += 5 << 5; - break; - case 6: // unused - temp += 6 << 5; - break; - case 7: // unused - temp += 7 << 5; - break; - } + if (azt2316a->cur_mpu401_enabled) + temp += 1 << 3; - switch (cd_dma8) { - case 0xFF: /* -1 - do nothing - temp += 0 << 22;*/ - break; - case 0: - temp += 1 << 22; - break; - case 1: - temp += 2 << 22; - break; - case 3: - temp += 3 << 22; - break; - } - - switch (azt2316a->cur_mpu401_irq) { - case 9: - temp += 1 << 12; - break; - case 3: - temp += 1 << 13; - break; - case 5: - temp += 1 << 14; - break; - case 7: - temp += 1 << 15; - break; - } - - switch (cd_irq) { - case 0: // disabled - // do nothing - break; - case 11: - temp += 1 << 19; - break; - case 12: - temp += 1 << 20; - break; - case 15: - temp += 1 << 21; - break; - } + switch (cd_type) { + case 0: /* disabled + do nothing + temp += 0 << 5; */ + break; + case 1: // panasonic + temp += 1 << 5; + break; + case 2: // mitsumi/sony/aztech + temp += 2 << 5; + break; + case 3: // all enabled + temp += 3 << 5; + break; + case 4: // unused + temp += 4 << 5; + break; + case 5: // unused + temp += 5 << 5; + break; + case 6: // unused + temp += 6 << 5; + break; + case 7: // unused + temp += 7 << 5; + break; + } - azt2316a->config_word = temp; -} + switch (cd_dma8) { + case 0xFF: /* -1 + do nothing + temp += 0 << 22;*/ + break; + case 0: + temp += 1 << 22; + break; + case 1: + temp += 2 << 22; + break; + case 3: + temp += 3 << 22; + break; + } -static void + switch (azt2316a->cur_mpu401_irq) { + case 9: + temp += 1 << 12; + break; + case 3: + temp += 1 << 13; + break; + case 5: + temp += 1 << 14; + break; + case 7: + temp += 1 << 15; + break; + } + + switch (cd_irq) { + case 0: // disabled + // do nothing + break; + case 11: + temp += 1 << 19; + break; + case 12: + temp += 1 << 20; + break; + case 15: + temp += 1 << 21; + break; + } + + azt2316a->config_word = temp; +} + +static void azt2316a_create_config_word(void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - uint32_t temp = 0; + azt2316a_t *azt2316a = (azt2316a_t *) p; + uint32_t temp = 0; - /* not implemented / hardcoded */ - uint8_t game_enable = 1; - uint16_t cd_addr = 0x310; - uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ - uint8_t cd_dma8 = -1; - uint8_t cd_dma16 = -1; - uint8_t cd_irq = 15; + /* not implemented / hardcoded */ + uint8_t game_enable = 1; + uint16_t cd_addr = 0x310; + uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ + uint8_t cd_dma8 = -1; + uint8_t cd_dma16 = -1; + uint8_t cd_irq = 15; - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - azt1605_create_config_word(p); - return; - } + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + azt1605_create_config_word(p); + return; + } - switch (azt2316a->cur_addr) { - case 0x220: - /* do nothing - temp += 0 << 0; */ - break; - case 0x240: - temp += 1 << 0; - break; -/* - case 0x260: // TODO: INVALID? - temp += 2 << 0; - break; - case 0x280: // TODO: INVALID? - temp += 3 << 0; - break; -*/ - } - - switch (azt2316a->cur_irq) { - case 9: - temp += 1 << 2; - break; - case 5: - temp += 1 << 3; - break; - case 7: - temp += 1 << 4; - break; - case 10: - temp += 1 << 5; - break; - } - - switch (azt2316a->cur_dma) { -/* - // TODO: INVALID? - case 0xFF: // -1 - // do nothing - //temp += 0 << 6; - break; -*/ - case 0: - temp += 1 << 6; - break; - case 1: - temp += 2 << 6; - break; - case 3: - temp += 3 << 6; - break; - } - - switch (azt2316a->cur_wss_addr) - { - case 0x530: - // do nothing - //temp += 0 << 8; - break; - case 0x604: - temp += 1 << 8; - break; - case 0xE80: - temp += 2 << 8; - break; - case 0xF40: - temp += 3 << 8; - break; - } - if (azt2316a->cur_wss_enabled) - temp += 1 << 10; - if (game_enable) - temp += 1 << 11; - switch (azt2316a->cur_mpu401_addr) - { - case 0x300: - // do nothing - //temp += 0 << 12; - break; - case 0x330: - temp += 1 << 12; - break; - } - - if (azt2316a->cur_mpu401_enabled) - temp += 1 << 13; - - switch (cd_addr) { - case 0x310: - // do nothing - //temp += 0 << 14; - break; - case 0x320: - temp += 1 << 14; - break; - case 0x340: - temp += 2 << 14; - break; - case 0x350: - temp += 3 << 14; - break; - } - switch (cd_type) { - case 0: /* disabled - do nothing - temp += 0 << 16; */ - break; - case 1: /* panasonic */ - temp += 1 << 16; - break; - case 2: /* sony */ - temp += 2 << 16; - break; - case 3: /* mitsumi */ - temp += 3 << 16; - break; - case 4: /* aztech */ - temp += 4 << 16; - break; - case 5: /* unused */ - temp += 5 << 16; - break; - case 6: /* unused */ - temp += 6 << 16; - break; - case 7: /* unused */ - temp += 7 << 16; - break; - } - - switch (cd_dma8) { - case 0xFF: /* -1 - do nothing - temp += 0 << 20; */ - break; - case 0: - temp += 1 << 20; - break; -/* - case 1: // TODO: INVALID? - temp += 2 << 20; - break; -*/ - case 3: - temp += 3 << 20; - break; - } - - switch (cd_dma16) { - case 0xFF: /* -1 - do nothing - temp += 0 << 22; */ - break; - case 5: - temp += 1 << 22; - break; - case 6: - temp += 2 << 22; - break; - case 7: - temp += 3 << 22; - break; - } - - switch (azt2316a->cur_mpu401_irq) { - case 9: - temp += 1 << 24; - break; - case 5: - temp += 1 << 25; - break; - case 7: - temp += 1 << 26; - break; - case 10: - temp += 1 << 27; - break; - } - - switch (cd_irq) { - case 5: - temp += 1 << 28; - break; - case 11: - temp += 1 << 29; - break; - case 12: - temp += 1 << 30; - break; - case 15: - temp += 1 << 31; - break; - } + switch (azt2316a->cur_addr) { + case 0x220: + /* do nothing + temp += 0 << 0; */ + break; + case 0x240: + temp += 1 << 0; + break; + /* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; + */ + } - azt2316a->config_word = temp; + switch (azt2316a->cur_irq) { + case 9: + temp += 1 << 2; + break; + case 5: + temp += 1 << 3; + break; + case 7: + temp += 1 << 4; + break; + case 10: + temp += 1 << 5; + break; + } + + switch (azt2316a->cur_dma) { + /* + // TODO: INVALID? + case 0xFF: // -1 + // do nothing + //temp += 0 << 6; + break; + */ + case 0: + temp += 1 << 6; + break; + case 1: + temp += 2 << 6; + break; + case 3: + temp += 3 << 6; + break; + } + + switch (azt2316a->cur_wss_addr) { + case 0x530: + // do nothing + // temp += 0 << 8; + break; + case 0x604: + temp += 1 << 8; + break; + case 0xE80: + temp += 2 << 8; + break; + case 0xF40: + temp += 3 << 8; + break; + } + if (azt2316a->cur_wss_enabled) + temp += 1 << 10; + if (game_enable) + temp += 1 << 11; + switch (azt2316a->cur_mpu401_addr) { + case 0x300: + // do nothing + // temp += 0 << 12; + break; + case 0x330: + temp += 1 << 12; + break; + } + + if (azt2316a->cur_mpu401_enabled) + temp += 1 << 13; + + switch (cd_addr) { + case 0x310: + // do nothing + // temp += 0 << 14; + break; + case 0x320: + temp += 1 << 14; + break; + case 0x340: + temp += 2 << 14; + break; + case 0x350: + temp += 3 << 14; + break; + } + switch (cd_type) { + case 0: /* disabled + do nothing + temp += 0 << 16; */ + break; + case 1: /* panasonic */ + temp += 1 << 16; + break; + case 2: /* sony */ + temp += 2 << 16; + break; + case 3: /* mitsumi */ + temp += 3 << 16; + break; + case 4: /* aztech */ + temp += 4 << 16; + break; + case 5: /* unused */ + temp += 5 << 16; + break; + case 6: /* unused */ + temp += 6 << 16; + break; + case 7: /* unused */ + temp += 7 << 16; + break; + } + + switch (cd_dma8) { + case 0xFF: /* -1 + do nothing + temp += 0 << 20; */ + break; + case 0: + temp += 1 << 20; + break; + /* + case 1: // TODO: INVALID? + temp += 2 << 20; + break; + */ + case 3: + temp += 3 << 20; + break; + } + + switch (cd_dma16) { + case 0xFF: /* -1 + do nothing + temp += 0 << 22; */ + break; + case 5: + temp += 1 << 22; + break; + case 6: + temp += 2 << 22; + break; + case 7: + temp += 3 << 22; + break; + } + + switch (azt2316a->cur_mpu401_irq) { + case 9: + temp += 1 << 24; + break; + case 5: + temp += 1 << 25; + break; + case 7: + temp += 1 << 26; + break; + case 10: + temp += 1 << 27; + break; + } + + switch (cd_irq) { + case 5: + temp += 1 << 28; + break; + case 11: + temp += 1 << 29; + break; + case 12: + temp += 1 << 30; + break; + case 15: + temp += 1 << 31; + break; + } + + azt2316a->config_word = temp; } -static uint8_t +static uint8_t azt2316a_config_read(uint16_t addr, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - uint8_t temp = 0; + azt2316a_t *azt2316a = (azt2316a_t *) p; + uint8_t temp = 0; - /* Some WSS config here + config change enable bit - (setting bit 7 and writing back) */ + /* Some WSS config here + config change enable bit + (setting bit 7 and writing back) */ - if (addr == (azt2316a->cur_addr + 0x404)) { - /* TODO: what is the real meaning of the read value? - I got a mention of bit 0x10 for WSS from disassembling the source - code of the driver, and when playing with the I/O ports on real - hardware after doing some configuration, but didn't dig into it. - Bit 0x08 seems to be a busy flag and generates a timeout - (continuous re-reading when initializing windows 98) */ - temp = azt2316a->cur_mode ? 0x07 : 0x0F; - if (azt2316a->config_word_unlocked) { - temp |= 0x80; - } - } else { - // Rest of config. These are documented in the Linux driver. - switch (addr & 0x3) - { - case 0: - temp = azt2316a->config_word & 0xFF; - break; - case 1: - temp = (azt2316a->config_word >> 8); - break; - case 2: - temp = (azt2316a->config_word >> 16); - break; - case 3: - temp = (azt2316a->config_word >> 24); - break; - } + if (addr == (azt2316a->cur_addr + 0x404)) { + /* TODO: what is the real meaning of the read value? + I got a mention of bit 0x10 for WSS from disassembling the source + code of the driver, and when playing with the I/O ports on real + hardware after doing some configuration, but didn't dig into it. + Bit 0x08 seems to be a busy flag and generates a timeout + (continuous re-reading when initializing windows 98) */ + temp = azt2316a->cur_mode ? 0x07 : 0x0F; + if (azt2316a->config_word_unlocked) { + temp |= 0x80; } + } else { + // Rest of config. These are documented in the Linux driver. + switch (addr & 0x3) { + case 0: + temp = azt2316a->config_word & 0xFF; + break; + case 1: + temp = (azt2316a->config_word >> 8); + break; + case 2: + temp = (azt2316a->config_word >> 16); + break; + case 3: + temp = (azt2316a->config_word >> 24); + break; + } + } - return temp; + return temp; } - -static void +static void azt1605_config_write(uint16_t addr, uint8_t val, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - uint8_t temp; + azt2316a_t *azt2316a = (azt2316a_t *) p; + uint8_t temp; - if (addr == (azt2316a->cur_addr + 0x404)) { - if (val & 0x80) - azt2316a->config_word_unlocked = 1; - else - azt2316a->config_word_unlocked = 0; - } else if (azt2316a->config_word_unlocked) { - if (val == 0xFF) { /* TODO: check if this still happens on eeprom.sys after having more complete emulation! */ - return; - } - switch (addr & 3) { - case 0: - azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; - - temp = val & 3; - if (temp == 0) - azt2316a->cur_addr = 0x220; - else if (temp == 1) - azt2316a->cur_addr = 0x240; -/* - else if (temp == 2) - azt2316a->cur_addr = 0x260; // TODO: INVALID - else if (temp == 3) - azt2316a->cur_addr = 0x280; // TODO: INVALID -*/ - if (val & 0x4) - azt2316a->cur_mpu401_addr = 0x330; - else - azt2316a->cur_mpu401_addr = 0x300; - - if (val & 0x8) - azt2316a->cur_mpu401_enabled = 1; - else - azt2316a->cur_mpu401_enabled = 0; - break; - case 1: - azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); - - if (val & 0x1) - azt2316a->cur_irq = 9; - else if (val & 0x2) - azt2316a->cur_irq = 3; - else if (val & 0x4) - azt2316a->cur_irq = 5; - else if (val & 0x8) - azt2316a->cur_irq = 7; - /* else undefined? */ - - if (val & 0x10) - azt2316a->cur_mpu401_irq = 9; - else if (val & 0x20) - azt2316a->cur_mpu401_irq = 3; - else if (val & 0x40) - azt2316a->cur_mpu401_irq = 5; - else if (val & 0x80) - azt2316a->cur_mpu401_irq = 7; - /* else undefined? */ - break; - case 2: - azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); - - io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); - - temp = val & 0x3; - if (temp == 0) - azt2316a->cur_wss_addr = 0x530; - else if (temp == 1) - azt2316a->cur_wss_addr = 0x604; - else if (temp == 2) - azt2316a->cur_wss_addr = 0xE80; - else if (temp == 3) - azt2316a->cur_wss_addr = 0xF40; - - io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); - - /* no actual effect */ - if (val & 0x4) - azt2316a->cur_wss_enabled = 1; - else - azt2316a->cur_wss_enabled = 0; - break; - case 3: - break; - } - /* update sbprov2 configs */ - sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); - sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); - sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); - - mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); - mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + if (addr == (azt2316a->cur_addr + 0x404)) { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } else if (azt2316a->config_word_unlocked) { + if (val == 0xFF) { /* TODO: check if this still happens on eeprom.sys after having more complete emulation! */ + return; } + switch (addr & 3) { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; + + temp = val & 3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; + /* + else if (temp == 2) + azt2316a->cur_addr = 0x260; // TODO: INVALID + else if (temp == 3) + azt2316a->cur_addr = 0x280; // TODO: INVALID + */ + if (val & 0x4) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (val & 0x8) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); + + if (val & 0x1) + azt2316a->cur_irq = 9; + else if (val & 0x2) + azt2316a->cur_irq = 3; + else if (val & 0x4) + azt2316a->cur_irq = 5; + else if (val & 0x8) + azt2316a->cur_irq = 7; + /* else undefined? */ + + if (val & 0x10) + azt2316a->cur_mpu401_irq = 9; + else if (val & 0x20) + azt2316a->cur_mpu401_irq = 3; + else if (val & 0x40) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x80) + azt2316a->cur_mpu401_irq = 7; + /* else undefined? */ + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); + + io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + /* no actual effect */ + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + break; + case 3: + break; + } + /* update sbprov2 configs */ + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + + mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); + mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + } } -static void +static void azt2316a_config_write(uint16_t addr, uint8_t val, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - uint8_t temp; + azt2316a_t *azt2316a = (azt2316a_t *) p; + uint8_t temp; - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - azt1605_config_write(addr, val, azt2316a); - return; - } + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + azt1605_config_write(addr, val, azt2316a); + return; + } - if (addr == (azt2316a->cur_addr + 0x404)) { - if (val & 0x80) - azt2316a->config_word_unlocked = 1; + if (addr == (azt2316a->cur_addr + 0x404)) { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } else if (azt2316a->config_word_unlocked) { + if (val == 0xFF) // TODO: check if this still happens on eeprom.sys after having more complete emulation! + return; + switch (addr & 3) { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; + temp = val & 3; + + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; + + if (val & 0x4) + azt2316a->cur_irq = 9; + else if (val & 0x8) + azt2316a->cur_irq = 5; + else if (val & 0x10) + azt2316a->cur_irq = 7; + else if (val & 0x20) + azt2316a->cur_irq = 10; + + temp = (val >> 6) & 3; + if (temp == 1) + azt2316a->cur_dma = 0; + else if (temp == 2) + azt2316a->cur_dma = 1; + else if (temp == 3) + azt2316a->cur_dma = 3; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); + + io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + /* no actual effect */ + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; else - azt2316a->config_word_unlocked = 0; - } else if (azt2316a->config_word_unlocked) { - if (val == 0xFF) // TODO: check if this still happens on eeprom.sys after having more complete emulation! - return; - switch (addr & 3) { - case 0: - azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; - temp = val & 3; - - if (temp == 0) - azt2316a->cur_addr = 0x220; - else if (temp == 1) - azt2316a->cur_addr = 0x240; + azt2316a->cur_wss_enabled = 0; - if (val & 0x4) - azt2316a->cur_irq = 9; - else if (val & 0x8) - azt2316a->cur_irq = 5; - else if (val & 0x10) - azt2316a->cur_irq = 7; - else if (val & 0x20) - azt2316a->cur_irq = 10; + if (val & 0x10) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; - temp = (val >> 6) & 3; - if (temp == 1) - azt2316a->cur_dma = 0; - else if (temp == 2) - azt2316a->cur_dma = 1; - else if (temp == 3) - azt2316a->cur_dma = 3; - break; - case 1: - azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); - - io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + if (val & 0x20) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); + break; + case 3: + azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) | (val << 24); - temp = val & 0x3; - if (temp == 0) - azt2316a->cur_wss_addr = 0x530; - else if (temp == 1) - azt2316a->cur_wss_addr = 0x604; - else if (temp == 2) - azt2316a->cur_wss_addr = 0xE80; - else if (temp == 3) - azt2316a->cur_wss_addr = 0xF40; - - io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); - - /* no actual effect */ - if (val & 0x4) - azt2316a->cur_wss_enabled = 1; - else - azt2316a->cur_wss_enabled = 0; - - if (val & 0x10) - azt2316a->cur_mpu401_addr = 0x330; - else - azt2316a->cur_mpu401_addr = 0x300; - - if (val & 0x20) - azt2316a->cur_mpu401_enabled = 1; - else - azt2316a->cur_mpu401_enabled = 0; - break; - case 2: - azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); - break; - case 3: - azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) | (val << 24); - - if (val & 0x1) - azt2316a->cur_mpu401_irq = 9; - else if (val & 0x2) - azt2316a->cur_mpu401_irq = 5; - else if (val & 0x4) - azt2316a->cur_mpu401_irq = 7; - else if (val & 0x8) - azt2316a->cur_mpu401_irq = 10; - /* else undefined? */ - break; - } - /* update sbprov2 configs */ - sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); - sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); - sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); - - mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); - mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + if (val & 0x1) + azt2316a->cur_mpu401_irq = 9; + else if (val & 0x2) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x4) + azt2316a->cur_mpu401_irq = 7; + else if (val & 0x8) + azt2316a->cur_mpu401_irq = 10; + /* else undefined? */ + break; } + /* update sbprov2 configs */ + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + + mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); + mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + } } /* How it behaves when one or another is activated may affect games auto-detecting (and will also use more of the limited system resources!) */ -void +void azt2316a_enable_wss(uint8_t enable, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; + azt2316a_t *azt2316a = (azt2316a_t *) p; - if (enable) - azt2316a->cur_mode = 1; - else - azt2316a->cur_mode = 0; + if (enable) + azt2316a->cur_mode = 1; + else + azt2316a->cur_mode = 0; } -static void +static void azt2316a_get_buffer(int32_t *buffer, int len, void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - int c; + azt2316a_t *azt2316a = (azt2316a_t *) p; + int c; - /* wss part */ - ad1848_update(&azt2316a->ad1848); - for (c = 0; c < len * 2; c++) - buffer[c] += (azt2316a->ad1848.buffer[c] / 2); + /* wss part */ + ad1848_update(&azt2316a->ad1848); + for (c = 0; c < len * 2; c++) + buffer[c] += (azt2316a->ad1848.buffer[c] / 2); - azt2316a->ad1848.pos = 0; + azt2316a->ad1848.pos = 0; - /* sbprov2 part */ - sb_get_buffer_sbpro(buffer, len, azt2316a->sb); + /* sbprov2 part */ + sb_get_buffer_sbpro(buffer, len, azt2316a->sb); } static void * azt_init(const device_t *info) { - FILE *f; - wchar_t *fn = NULL; - int i; - int loaded_from_eeprom = 0; - uint16_t addr_setting; - uint8_t read_eeprom[AZTECH_EEPROM_SIZE]; - azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); - memset(azt2316a, 0, sizeof(azt2316a_t)); - - azt2316a->type = info->local; - - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - fn = L"azt1605.nvr"; - } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - fn = L"azt2316a.nvr"; - } + FILE *f; + char *fn = NULL; + int i; + int loaded_from_eeprom = 0; + uint16_t addr_setting; + uint8_t read_eeprom[AZTECH_EEPROM_SIZE]; + azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); + memset(azt2316a, 0, sizeof(azt2316a_t)); - /* config */ - f = nvr_fopen(fn, L"rb"); - if (f) { - uint8_t checksum = 0x7f; - uint8_t saved_checksum; - size_t res; - - res = fread(read_eeprom, AZTECH_EEPROM_SIZE, 1, f); - for (i = 0; i < AZTECH_EEPROM_SIZE; i++) - checksum += read_eeprom[i]; - - res = fread(&saved_checksum, sizeof(saved_checksum), 1, f); - (void)res; + azt2316a->type = info->local; - fclose(f); - - if (checksum == saved_checksum) - loaded_from_eeprom = 1; + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + fn = "azt1605.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + fn = "azt2316a.nvr"; + } + + /* config */ + f = nvr_fopen(fn, "rb"); + if (f) { + uint8_t checksum = 0x7f; + uint8_t saved_checksum; + size_t res; + + res = fread(read_eeprom, AZTECH_EEPROM_SIZE, 1, f); + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += read_eeprom[i]; + + res = fread(&saved_checksum, sizeof(saved_checksum), 1, f); + (void) res; + + fclose(f); + + if (checksum == saved_checksum) + loaded_from_eeprom = 1; + } + + if (!loaded_from_eeprom) { + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + read_eeprom[0] = 0x00; + read_eeprom[1] = 0x00; + read_eeprom[2] = 0x00; + read_eeprom[3] = 0x00; + read_eeprom[4] = 0x00; + read_eeprom[5] = 0x00; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x00; + read_eeprom[9] = 0x00; + read_eeprom[10] = 0x00; + read_eeprom[11] = 0x88; + read_eeprom[12] = 0xbc; + read_eeprom[13] = 0x00; + read_eeprom[14] = 0x01; + read_eeprom[15] = 0x00; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + read_eeprom[0] = 0x80; + read_eeprom[1] = 0x80; + read_eeprom[2] = 0x9F; + read_eeprom[3] = 0x13; + read_eeprom[4] = 0x16; + read_eeprom[5] = 0x13; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x16; + read_eeprom[9] = 0x0B; + read_eeprom[10] = 0x06; + read_eeprom[11] = 0x01; + read_eeprom[12] = 0x1C; + read_eeprom[13] = 0x14; + read_eeprom[14] = 0x04; + read_eeprom[15] = 0x1C; } - - if (!loaded_from_eeprom) { - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - read_eeprom[0] = 0x00; - read_eeprom[1] = 0x00; - read_eeprom[2] = 0x00; - read_eeprom[3] = 0x00; - read_eeprom[4] = 0x00; - read_eeprom[5] = 0x00; - read_eeprom[6] = 0x00; - read_eeprom[7] = 0x00; - read_eeprom[8] = 0x00; - read_eeprom[9] = 0x00; - read_eeprom[10] = 0x00; - read_eeprom[11] = 0x88; - read_eeprom[12] = 0xbc; - read_eeprom[13] = 0x00; - read_eeprom[14] = 0x01; - read_eeprom[15] = 0x00; - } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - read_eeprom[0] = 0x80; - read_eeprom[1] = 0x80; - read_eeprom[2] = 0x9F; - read_eeprom[3] = 0x13; - read_eeprom[4] = 0x16; - read_eeprom[5] = 0x13; - read_eeprom[6] = 0x00; - read_eeprom[7] = 0x00; - read_eeprom[8] = 0x16; - read_eeprom[9] = 0x0B; - read_eeprom[10] = 0x06; - read_eeprom[11] = 0x01; - read_eeprom[12] = 0x1C; - read_eeprom[13] = 0x14; - read_eeprom[14] = 0x04; - read_eeprom[15] = 0x1C; - } - } + } - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - azt2316a->config_word = read_eeprom[11] | (read_eeprom[12] << 8) | (read_eeprom[13] << 16) | (read_eeprom[14] << 24); + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + azt2316a->config_word = read_eeprom[11] | (read_eeprom[12] << 8) | (read_eeprom[13] << 16) | (read_eeprom[14] << 24); - switch (azt2316a->config_word & (3 << 0)) { - case 0: - azt2316a->cur_addr = 0x220; - break; - case 1: - azt2316a->cur_addr = 0x240; - break; - default: - fatal("AZT2316A: invalid sb addr in config word %08X\n", azt2316a->config_word); - } - - if (azt2316a->config_word & (1 << 2)) - azt2316a->cur_irq = 9; - else if (azt2316a->config_word & (1 << 3)) - azt2316a->cur_irq = 5; - else if (azt2316a->config_word & (1 << 4)) - azt2316a->cur_irq = 7; - else if (azt2316a->config_word & (1 << 5)) - azt2316a->cur_irq = 10; - else - fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); - - switch (azt2316a->config_word & (3 << 6)) { - case 1 << 6: - azt2316a->cur_dma = 0; - break; - case 2 << 6: - azt2316a->cur_dma = 1; - break; - case 3 << 6: - azt2316a->cur_dma = 3; - break; - default: - fatal("AZT2316A: invalid sb dma in config word %08X\n", azt2316a->config_word); - } - - switch (azt2316a->config_word & (3 << 8)) { - case 0: - azt2316a->cur_wss_addr = 0x530; - break; - case 1 << 8: - azt2316a->cur_wss_addr = 0x604; - break; - case 2 << 8: - azt2316a->cur_wss_addr = 0xE80; - break; - case 3 << 8: - azt2316a->cur_wss_addr = 0xF40; - break; - default: - fatal("AZT2316A: invalid wss addr in config word %08X\n", azt2316a->config_word); - } - - if (azt2316a->config_word & (1 << 10)) - azt2316a->cur_wss_enabled = 1; - else - azt2316a->cur_wss_enabled = 0; - - if (azt2316a->config_word & (1 << 12)) - azt2316a->cur_mpu401_addr = 0x330; - else - azt2316a->cur_mpu401_addr = 0x300; - - if (azt2316a->config_word & (1 << 13)) - azt2316a->cur_mpu401_enabled = 1; - else - azt2316a->cur_mpu401_enabled = 0; - - if (azt2316a->config_word & (1 << 24)) - azt2316a->cur_mpu401_irq = 9; - else if (azt2316a->config_word & (1 << 25)) - azt2316a->cur_mpu401_irq = 5; - else if (azt2316a->config_word & (1 << 26)) - azt2316a->cur_mpu401_irq = 7; - else if (azt2316a->config_word & (1 << 27)) - azt2316a->cur_mpu401_irq = 10; - else - fatal("AZT2316A: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); - - /* these are not present on the EEPROM */ - azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); - azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); - azt2316a->cur_mode = 0; - } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - azt2316a->config_word = read_eeprom[12] + (read_eeprom[13] << 8) + (read_eeprom[14] << 16); - - switch (azt2316a->config_word & (3 << 0)) { - case 0: - azt2316a->cur_addr = 0x220; - break; - case 1: - azt2316a->cur_addr = 0x240; - break; - default: - fatal("AZT1605: invalid sb addr in config word %08X\n", azt2316a->config_word); - } - - if (azt2316a->config_word & (1 << 2)) - azt2316a->cur_mpu401_addr = 0x330; - else - azt2316a->cur_mpu401_addr = 0x300; - - if (azt2316a->config_word & (1 << 3)) - azt2316a->cur_mpu401_enabled = 1; - else - azt2316a->cur_mpu401_enabled = 0; - - if (azt2316a->config_word & (1 << 8)) - azt2316a->cur_irq = 9; - else if (azt2316a->config_word & (1 << 9)) - azt2316a->cur_irq = 3; - else if (azt2316a->config_word & (1 << 10)) - azt2316a->cur_irq = 5; - else if (azt2316a->config_word & (1 << 11)) - azt2316a->cur_irq = 7; - else - fatal("AZT1605: invalid sb irq in config word %08X\n", azt2316a->config_word); - - if (azt2316a->config_word & (1 << 12)) - azt2316a->cur_mpu401_irq = 9; - else if (azt2316a->config_word & (1 << 13)) - azt2316a->cur_mpu401_irq = 3; - else if (azt2316a->config_word & (1 << 14)) - azt2316a->cur_mpu401_irq = 5; - else if (azt2316a->config_word & (1 << 15)) - azt2316a->cur_mpu401_irq = 7; - else - fatal("AZT1605: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); - - switch (azt2316a->config_word & (3 << 16)) { - case 0: - azt2316a->cur_wss_addr = 0x530; - break; - case 1 << 16: - azt2316a->cur_wss_addr = 0x604; - break; - case 2 << 16: - azt2316a->cur_wss_addr = 0xE80; - break; - case 3 << 16: - azt2316a->cur_wss_addr = 0xF40; - break; - default: - fatal("AZT1605: invalid wss addr in config word %08X\n", azt2316a->config_word); - } - - if (azt2316a->config_word & (1 << 18)) - azt2316a->cur_wss_enabled = 1; - else - azt2316a->cur_wss_enabled = 0; - - // these are not present on the EEPROM - azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? - azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); - azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); - azt2316a->cur_mode = 0; - } - - addr_setting = device_get_config_hex16("addr"); - if (addr_setting) - azt2316a->cur_addr = addr_setting; - - azt2316a->wss_interrupt_after_config = device_get_config_int("wss_interrupt_after_config"); - - /* wss part */ - ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); - - ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq); - ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); - - io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); - io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); - - /* sbprov2 part */ - /*sbpro port mappings. 220h or 240h. - 2x0 to 2x3 -> FM chip (18 voices) - 2x4 to 2x5 -> Mixer interface - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip (9 voices).*/ - azt2316a->sb = malloc(sizeof(sb_t)); - memset(azt2316a->sb, 0, sizeof(sb_t)); - - azt2316a->sb->opl_enabled = device_get_config_int("opl"); - - for (i = 0; i < AZTECH_EEPROM_SIZE; i++) - azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[i]; - - if (azt2316a->sb->opl_enabled) - opl3_init(&azt2316a->sb->opl); - - sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); - sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); - sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); - sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); - sb_ct1345_mixer_reset(azt2316a->sb); - /* DSP I/O handler is activated in sb_dsp_setaddr */ - if (azt2316a->sb->opl_enabled) { - io_sethandler(azt2316a->cur_addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); - io_sethandler(azt2316a->cur_addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + switch (azt2316a->config_word & (3 << 0)) { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT2316A: invalid sb addr in config word %08X\n", azt2316a->config_word); } - - io_sethandler(azt2316a->cur_addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, azt2316a->sb); - azt2316a_create_config_word(azt2316a); - sound_add_handler(azt2316a_get_buffer, azt2316a); + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_irq = 9; + else if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 4)) + azt2316a->cur_irq = 7; + else if (azt2316a->config_word & (1 << 5)) + azt2316a->cur_irq = 10; + else + fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); - if (azt2316a->cur_mpu401_enabled) { - azt2316a->mpu = (mpu_t *) malloc(sizeof(mpu_t)); - memset(azt2316a->mpu, 0, sizeof(mpu_t)); - mpu401_init(azt2316a->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); - } else - azt2316a->mpu = NULL; + switch (azt2316a->config_word & (3 << 6)) { + case 1 << 6: + azt2316a->cur_dma = 0; + break; + case 2 << 6: + azt2316a->cur_dma = 1; + break; + case 3 << 6: + azt2316a->cur_dma = 3; + break; + default: + fatal("AZT2316A: invalid sb dma in config word %08X\n", azt2316a->config_word); + } - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &azt2316a->sb->dsp); + switch (azt2316a->config_word & (3 << 8)) { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 8: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 8: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 8: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT2316A: invalid wss addr in config word %08X\n", azt2316a->config_word); + } - return azt2316a; + if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (azt2316a->config_word & (1 << 24)) + azt2316a->cur_mpu401_irq = 9; + else if (azt2316a->config_word & (1 << 25)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 26)) + azt2316a->cur_mpu401_irq = 7; + else if (azt2316a->config_word & (1 << 27)) + azt2316a->cur_mpu401_irq = 10; + else + fatal("AZT2316A: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + /* these are not present on the EEPROM */ + azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); + azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); + azt2316a->cur_mode = 0; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + azt2316a->config_word = read_eeprom[12] + (read_eeprom[13] << 8) + (read_eeprom[14] << 16); + + switch (azt2316a->config_word & (3 << 0)) { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT1605: invalid sb addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (azt2316a->config_word & (1 << 8)) + azt2316a->cur_irq = 9; + else if (azt2316a->config_word & (1 << 9)) + azt2316a->cur_irq = 3; + else if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 11)) + azt2316a->cur_irq = 7; + else + fatal("AZT1605: invalid sb irq in config word %08X\n", azt2316a->config_word); + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_irq = 9; + else if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_irq = 3; + else if (azt2316a->config_word & (1 << 14)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 15)) + azt2316a->cur_mpu401_irq = 7; + else + fatal("AZT1605: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 16)) { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 16: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 16: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 16: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT1605: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 18)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // these are not present on the EEPROM + azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); + azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); + azt2316a->cur_mode = 0; + } + + addr_setting = device_get_config_hex16("addr"); + if (addr_setting) + azt2316a->cur_addr = addr_setting; + + azt2316a->wss_interrupt_after_config = device_get_config_int("wss_interrupt_after_config"); + + /* wss part */ + ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); + + ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq); + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + + io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + /* sbprov2 part */ + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices).*/ + azt2316a->sb = malloc(sizeof(sb_t)); + memset(azt2316a->sb, 0, sizeof(sb_t)); + + azt2316a->sb->opl_enabled = device_get_config_int("opl"); + + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[i]; + + if (azt2316a->sb->opl_enabled) + fm_driver_get(FM_YMF262, &azt2316a->sb->opl); + + sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + sb_ct1345_mixer_reset(azt2316a->sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (azt2316a->sb->opl_enabled) { + io_sethandler(azt2316a->cur_addr + 0, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); + io_sethandler(azt2316a->cur_addr + 8, 0x0002, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); + io_sethandler(0x0388, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); + } + + io_sethandler(azt2316a->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, azt2316a->sb); + + azt2316a_create_config_word(azt2316a); + sound_add_handler(azt2316a_get_buffer, azt2316a); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, azt2316a->sb); + + if (azt2316a->cur_mpu401_enabled) { + azt2316a->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(azt2316a->mpu, 0, sizeof(mpu_t)); + mpu401_init(azt2316a->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); + } else + azt2316a->mpu = NULL; + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &azt2316a->sb->dsp); + + return azt2316a; } -static void +static void azt_close(void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; - wchar_t *fn = NULL; - FILE *f; - uint8_t checksum = 0x7f; - int i; + azt2316a_t *azt2316a = (azt2316a_t *) p; + char *fn = NULL; + FILE *f; + uint8_t checksum = 0x7f; + int i; - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - fn = L"azt1605.nvr"; - } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - fn = L"azt2316a.nvr"; - } + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + fn = "azt1605.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + fn = "azt2316a.nvr"; + } - /* always save to eeprom (recover from bad values) */ - f = nvr_fopen(fn, L"wb"); - if (f) { - for (i = 0; i < AZTECH_EEPROM_SIZE; i++) - checksum += azt2316a->sb->dsp.azt_eeprom[i]; - fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, f); + /* always save to eeprom (recover from bad values) */ + f = nvr_fopen(fn, "wb"); + if (f) { + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += azt2316a->sb->dsp.azt_eeprom[i]; + fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, f); - // TODO: confirm any models saving mixer settings to EEPROM and implement reading back - // TODO: should remember to save wss duplex setting if 86Box has voice recording implemented in the future? Also, default azt2316a->wss_config - // TODO: azt2316a->cur_mode is not saved to EEPROM? - fwrite(&checksum, sizeof(checksum), 1, f); + // TODO: confirm any models saving mixer settings to EEPROM and implement reading back + // TODO: should remember to save wss duplex setting if 86Box has voice recording implemented in the future? Also, default azt2316a->wss_config + // TODO: azt2316a->cur_mode is not saved to EEPROM? + fwrite(&checksum, sizeof(checksum), 1, f); - fclose(f); - } + fclose(f); + } - sb_close(azt2316a->sb); + sb_close(azt2316a->sb); - free(azt2316a); + free(azt2316a); } -static void +static void azt_speed_changed(void *p) { - azt2316a_t *azt2316a = (azt2316a_t *)p; + azt2316a_t *azt2316a = (azt2316a_t *) p; - ad1848_speed_changed(&azt2316a->ad1848); - sb_speed_changed(azt2316a->sb); + ad1848_speed_changed(&azt2316a->ad1848); + sb_speed_changed(azt2316a->sb); } -static const device_config_t azt1605_config[] = -{ - { - .name = "codec", - .description = "CODEC", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "CS4248", - .value = AD1848_TYPE_CS4248 - }, - { - .description = "CS4231", - .value = AD1848_TYPE_CS4231 - }, - }, - .default_int = AD1848_TYPE_CS4248 +static const device_config_t azt1605_config[] = { + // clang-format off + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "CS4248", + .value = AD1848_TYPE_CS4248 + }, + { + .description = "CS4231", + .value = AD1848_TYPE_CS4231 + }, }, - { - .name = "wss_interrupt_after_config", - .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - "addr", "SB Address", CONFIG_HEX16, "", 0, - { - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "Use EEPROM setting", 0 - }, - { - "" - } - } - }, - { - .name = "sb_dma8", - .description = "SB low DMA", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { - .description = "" - } - }, - .default_int = 1 - }, - { - .name = "wss_irq", - .description = "WSS IRQ", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "IRQ 11", - .value = 11 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "" - } - }, - .default_int = 10 - }, - { - .name = "wss_dma", - .description = "WSS DMA", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { - .description = "" - } - }, - .default_int = 0 - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 + .default_int = AD1848_TYPE_CS4248 + }, + { + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "addr", + .description = "SB Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "Use EEPROM setting", + .value = 0 + }, + { + .description = "" + } } -}; - -static const device_config_t azt2316a_config[] = -{ + }, + { + .name = "sb_dma8", + .description = "SB low DMA", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 1 + }, + { + .name = "wss_irq", + .description = "WSS IRQ", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 10 + }, { - .name = "codec", - .description = "CODEC", - .type = CONFIG_SELECTION, - .selection = + .name = "wss_dma", + .description = "WSS DMA", + .type = CONFIG_SELECTION, + .selection = { { - { - .description = "CS4248", - .value = AD1848_TYPE_CS4248 - }, - { - .description = "CS4231", - .value = AD1848_TYPE_CS4231 - }, + .description = "DMA 0", + .value = 0 }, - .default_int = AD1848_TYPE_CS4248 - }, - { - .name = "wss_interrupt_after_config", - .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - "addr", "SB Address", CONFIG_HEX16, "", 0, { - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "Use EEPROM setting", 0 - }, - { - "" - } + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" } + }, + .default_int = 0 }, - { - .name = "wss_irq", - .description = "WSS IRQ", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "IRQ 11", - .value = 11 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "" - } - }, - .default_int = 10 + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +static const device_config_t azt2316a_config[] = { + // clang-format off + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "CS4248", + .value = AD1848_TYPE_CS4248 + }, + { + .description = "CS4231", + .value = AD1848_TYPE_CS4231 + }, }, - { - .name = "wss_dma", - .description = "WSS DMA", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { - .description = "" - } - }, - .default_int = 0 - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 + .default_int = AD1848_TYPE_CS4248 + }, + { + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "addr", + .description = "SB Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "Use EEPROM setting", + .value = 0 + }, + { + .description = "" + } } + }, + { + .name = "wss_irq", + .description = "WSS IRQ", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 10 + }, + { + .name = "wss_dma", + .description = "WSS DMA", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on }; -const device_t azt2316a_device = -{ - "Aztech Sound Galaxy Pro 16 AB (Washington)", - DEVICE_ISA | DEVICE_AT, - SB_SUBTYPE_CLONE_AZT2316A_0X11, - azt_init, azt_close, NULL, NULL, - azt_speed_changed, - NULL, - azt2316a_config +const device_t azt2316a_device = { + .name = "Aztech Sound Galaxy Pro 16 AB (Washington)", + .internal_name = "azt2316a", + .flags = DEVICE_ISA | DEVICE_AT, + .local = SB_SUBTYPE_CLONE_AZT2316A_0X11, + .init = azt_init, + .close = azt_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = azt_speed_changed, + .force_redraw = NULL, + .config = azt2316a_config }; -const device_t azt1605_device = -{ - "Aztech Sound Galaxy Nova 16 Extra (Clinton)", - DEVICE_ISA | DEVICE_AT, - SB_SUBTYPE_CLONE_AZT1605_0X0C, - azt_init, azt_close, NULL, NULL, - azt_speed_changed, - NULL, - azt1605_config +const device_t azt1605_device = { + .name = "Aztech Sound Galaxy Nova 16 Extra (Clinton)", + .internal_name = "azt1605", + .flags = DEVICE_ISA | DEVICE_AT, + .local = SB_SUBTYPE_CLONE_AZT1605_0X0C, + .init = azt_init, + .close = azt_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = azt_speed_changed, + .force_redraw = NULL, + .config = azt1605_config }; diff --git a/src/sound/snd_cmi8x38.c b/src/sound/snd_cmi8x38.c new file mode 100644 index 000000000..d4a54880b --- /dev/null +++ b/src/sound/snd_cmi8x38.c @@ -0,0 +1,1548 @@ +/* + * 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. + * + * C-Media CMI8x38 PCI audio controller emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2022 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/dma.h> +#include <86box/pci.h> +#include <86box/sound.h> +#include <86box/snd_sb.h> +#include <86box/snd_sb_dsp.h> +#include <86box/gameport.h> +#include <86box/nmi.h> +#include <86box/ui.h> + +enum { + /* [23:16] = reg 0F [7:0] (reg 0C [31:24]) + [13] = onboard flag + [12:8] = reg 0B [4:0] (reg 08 [28:24]) + [7:0] = PCI device ID [7:0] */ + CMEDIA_CMI8338 = 0x000000, + CMEDIA_CMI8738_4CH = 0x040011, /* chip version 039 with 4-channel output */ + CMEDIA_CMI8738_6CH = 0x080011 /* chip version 055 with 6-channel output */ +}; + +enum { + TRAP_DMA = 0, + TRAP_PIC, + TRAP_OPL, + TRAP_MPU, + TRAP_MAX +}; + +typedef struct { + uint8_t id, reg, always_run, playback_enabled, channels; + struct _cmi8x38_ *dev; + + uint32_t sample_ptr, fifo_pos, fifo_end; + int32_t frame_count_dma, frame_count_fragment, sample_count_out; + uint8_t fifo[256], restart; + + int16_t out_fl, out_fr, out_rl, out_rr, out_c, out_lfe; + int vol_l, vol_r, pos; + int32_t buffer[SOUNDBUFLEN * 2]; + uint64_t timer_latch; + double dma_latch; + + pc_timer_t dma_timer, poll_timer; +} cmi8x38_dma_t; + +typedef struct _cmi8x38_ { + uint32_t type; + uint16_t io_base, sb_base, opl_base, mpu_base; + uint8_t pci_regs[256], io_regs[256]; + int slot; + + sb_t *sb; + void *gameport, *io_traps[TRAP_MAX]; + + cmi8x38_dma_t dma[2]; + uint16_t tdma_base_addr, tdma_base_count; + int tdma_8, tdma_16, tdma_mask, prev_mask, tdma_irq_mask; + + int master_vol_l, master_vol_r, cd_vol_l, cd_vol_r; +} cmi8x38_t; + +#ifdef ENABLE_CMI8X38_LOG +int cmi8x38_do_log = ENABLE_CMI8X38_LOG; + +static void +cmi8x38_log(const char *fmt, ...) +{ + va_list ap; + + if (cmi8x38_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define cmi8x38_log(fmt, ...) +#endif + +static const double freqs[] = { 5512.0, 11025.0, 22050.0, 44100.0, 8000.0, 16000.0, 32000.0, 48000.0 }; +static const uint16_t opl_ports_cmi8738[] = { 0x388, 0x3c8, 0x3e0, 0x3e8 }; + +static void cmi8x38_dma_process(void *priv); +static void cmi8x38_speed_changed(void *priv); + +static void +cmi8x38_update_irqs(cmi8x38_t *dev) +{ + /* Calculate and use the INTR flag. */ + if (*((uint32_t *) &dev->io_regs[0x10]) & 0x0401c003) { + dev->io_regs[0x13] |= 0x80; + pci_set_irq(dev->slot, PCI_INTA); + cmi8x38_log("CMI8x38: Raising IRQ\n"); + } else { + dev->io_regs[0x13] &= ~0x80; + pci_clear_irq(dev->slot, PCI_INTA); + } +} + +static void +cmi8x38_mpu_irq_update(void *priv, int set) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + if (set) + dev->io_regs[0x12] |= 0x01; + else + dev->io_regs[0x12] &= ~0x01; + cmi8x38_update_irqs(dev); +} + +static int +cmi8x38_mpu_irq_pending(void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + return dev->io_regs[0x12] & 0x01; +} + +static void +cmi8x38_sb_irq_update(void *priv, int set) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + /* Interrupt flag shared with the first DMA channel. Combining SB and + PCI DMA is undefined; the VxD driver disables SB if PCI is in use. */ + if (set) + dev->io_regs[0x10] |= 0x01; + else + dev->io_regs[0x10] &= ~0x01; + cmi8x38_update_irqs(dev); +} + +static int +cmi8x38_sb_dma_post(cmi8x38_t *dev, uint16_t *addr, uint16_t *count, int channel) +{ + /* Increment address and decrement count. */ + *addr += 1; + *count -= 1; + + /* Copy TDMA registers to DMA on CMI8738+. Everything so far suggests that + those chips use PCI bus mastering to directly write to the DMA registers. */ +#if 0 /* TSRs don't set ENWR8237, except for the patched C3DPCI - does that bit have no effect? */ + if ((dev->type != CMEDIA_CMI8338) && (dev->io_regs[0x17] & 0x10)) +#else + if (dev->type != CMEDIA_CMI8338) +#endif + { + if (channel & 4) + dma[channel].ab = (dma[channel].ab & 0xfffe0000) | ((*addr) << 1); + else + dma[channel].ab = (dma[channel].ab & 0xffff0000) | *addr; + dma[channel].ac = dma[channel].ab; + dma[channel].cc = dma[channel].cb = *count; + } + + /* Check TDMA position update interrupt if enabled. */ + if (dev->io_regs[0x0e] & 0x04) { + /* Nothing uses this; I assume it goes by the SB DSP sample counter (forwards instead of backwards). */ + int origlength = (channel & 4) ? dev->sb->dsp.sb_16_origlength : dev->sb->dsp.sb_8_origlength, + length = (channel & 4) ? dev->sb->dsp.sb_16_length : dev->sb->dsp.sb_8_length; + if ((origlength != length) && (((origlength - length) & dev->tdma_irq_mask) == 0)) { /* skip initial sample */ + /* Fire the interrupt. */ + dev->io_regs[0x11] |= (channel & 4) ? 0x40 : 0x80; + cmi8x38_update_irqs(dev); + } + } + + /* Handle end of DMA. */ + if (*count == 0xffff) { + if (dma[channel].mode & 0x10) { /* auto-init */ + /* Restart TDMA. */ + *addr = dev->tdma_base_addr; + *count = dev->tdma_base_count; + cmi8x38_log("CMI8x38: Restarting TDMA on DMA %d with addr %08X count %04X\n", + channel, + (channel & 4) ? ((dma[channel].ab & 0xfffe0000) | ((*addr) << 1)) : ((dma[channel].ab & 0xffff0000) | *addr), + *count); + } else { + /* Mask TDMA. */ + dev->tdma_mask |= 1 << channel; + } + + /* Set the mysterious LHBTOG bit, assuming it corresponds + to the 8237 channel status bit. Nothing reads it. */ + dev->io_regs[0x10] |= 0x40; + + return DMA_OVER; + } + return 0; +} + +static int +cmi8x38_sb_dma_readb(void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Stop if the DMA channel is invalid or if TDMA is masked. */ + int channel = dev->tdma_8; + if ((channel < 0) || (dev->tdma_mask & (1 << channel))) + return DMA_NODATA; + + /* Get 16-bit address and count registers. */ + uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c], + *count = (uint16_t *) &dev->io_regs[0x1e]; + + /* Read data. */ + int ret = mem_readb_phys((dma[channel].ab & 0xffff0000) | *addr); + + /* Handle address, count and end. */ + ret |= cmi8x38_sb_dma_post(dev, addr, count, channel); + + return ret; +} + +static int +cmi8x38_sb_dma_readw(void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Stop if the DMA channel is invalid or if TDMA is masked. */ + int channel = dev->tdma_16; + if ((channel < 0) || (dev->tdma_mask & (1 << channel))) + return DMA_NODATA; + + /* Get 16-bit address and count registers. */ + uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c], + *count = (uint16_t *) &dev->io_regs[0x1e]; + + /* Read data. */ + int ret = mem_readw_phys((dma[channel].ab & 0xfffe0000) | ((*addr) << 1)); + + /* Handle address, count and end. */ + ret |= cmi8x38_sb_dma_post(dev, addr, count, channel); + + return ret; +} + +static int +cmi8x38_sb_dma_writeb(void *priv, uint8_t val) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Stop if the DMA channel is invalid or if TDMA is masked. */ + int channel = dev->tdma_8; + if ((channel < 0) || (dev->tdma_mask & (1 << channel))) + return 1; + + /* Get 16-bit address and count registers. */ + uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c], + *count = (uint16_t *) &dev->io_regs[0x1e]; + + /* Write data. */ + mem_writeb_phys((dma[channel].ab & 0xffff0000) | *addr, val); + + /* Handle address, count and end. */ + cmi8x38_sb_dma_post(dev, addr, count, channel); + + return 0; +} + +static int +cmi8x38_sb_dma_writew(void *priv, uint16_t val) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Stop if the DMA channel is invalid or if TDMA is masked. */ + int channel = dev->tdma_16; + if ((channel < 0) || (dev->tdma_mask & (1 << channel))) + return 1; + + /* Get 16-bit address and count registers. */ + uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c], + *count = (uint16_t *) &dev->io_regs[0x1e]; + + /* Write data. */ + mem_writew_phys((dma[channel].ab & 0xfffe0000) | ((*addr) << 1), val); + + /* Handle address, count and end. */ + cmi8x38_sb_dma_post(dev, addr, count, channel); + + return 0; +} + +static void +cmi8x38_dma_write(uint16_t addr, uint8_t val, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Stop if DMA channel auto-detection is disabled. This is required for the CMI8338 TSR, + which disables auto-detection while copying the TDMA address/count to the SB DMA channel, + so that those writes don't loop back to the DMA register snoop mechanism implemented here. */ + if (!(dev->io_regs[0x27] & 0x01)) + return; + + /* Stop if this is not a TDMA channel. Also set or + clear the high channel flag while we're here. */ + int channel; + if (addr < 0x08) { + channel = addr >> 1; + if (channel != dev->tdma_8) + return; + dev->io_regs[0x10] &= ~0x20; + } else { + channel = 4 | ((addr >> 2) & 3); + if (channel != dev->tdma_16) + return; + dev->io_regs[0x10] |= 0x20; + } + + /* Write base address and count. */ + uint16_t *daddr = (uint16_t *) &dev->io_regs[0x1c], + *count = (uint16_t *) &dev->io_regs[0x1e]; + *daddr = dev->tdma_base_addr = dma[channel].ab >> !!(channel & 4); + *count = dev->tdma_base_count = dma[channel].cb; + cmi8x38_log("CMI8x38: Starting TDMA on DMA %d with addr %08X count %04X\n", + channel, + (channel & 4) ? ((dma[channel].ab & 0xfffe0000) | ((*daddr) << 1)) : ((dma[channel].ab & 0xffff0000) | *daddr), + *count); + + /* Clear the mysterious LHBTOG bit, assuming it corresponds + to the 8237 channel status bit. Nothing reads it. */ + dev->io_regs[0x10] &= ~0x40; +} + +static void +cmi8x38_dma_mask_write(uint16_t addr, uint8_t val, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* See comment on dma_write above. */ + if (!(dev->io_regs[0x27] & 0x01)) + return; + + /* Unmask TDMA on DMA unmasking edge. */ + if ((dev->tdma_8 >= 0) && (dev->prev_mask & (1 << dev->tdma_8)) && !(dma_m & (1 << dev->tdma_8))) + dev->tdma_mask &= ~(1 << dev->tdma_8); + else if ((dev->tdma_16 >= 0) && (dev->prev_mask & (1 << dev->tdma_16)) && !(dma_m & (1 << dev->tdma_16))) + dev->tdma_mask &= ~(1 << dev->tdma_16); + dev->prev_mask = dma_m; +} + +static void +cmi8338_io_trap(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + +#ifdef ENABLE_CMI8X38_LOG + if (write) + cmi8x38_log("CMI8x38: cmi8338_io_trap(%04X, %02X)\n", addr, val); + else + cmi8x38_log("CMI8x38: cmi8338_io_trap(%04X)\n", addr); +#endif + + /* Weird offsets, it's best to just treat the register as a big dword. */ + uint32_t *lcs = (uint32_t *) &dev->io_regs[0x14]; + *lcs &= ~0x0003dff0; + *lcs |= (addr & 0x0f) << 14; + if (write) + *lcs |= 0x1000 | (val << 4); + + /* Raise NMI. */ + nmi = 1; +} + +static uint8_t +cmi8x38_sb_mixer_read(uint16_t addr, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16; + uint8_t ret = sb_ct1745_mixer_read(addr, dev->sb); + + if (addr & 1) { + if ((mixer->index == 0x0e) || (mixer->index >= 0xf0)) + ret = mixer->regs[mixer->index]; + cmi8x38_log("CMI8x38: sb_mixer_read(1, %02X) = %02X\n", mixer->index, ret); + } else { + cmi8x38_log("CMI8x38: sb_mixer_read(0) = %02X\n", ret); + } + + return ret; +} + +static void +cmi8x38_sb_mixer_write(uint16_t addr, uint8_t val, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16; + + /* Our clone mixer has a few differences. */ + if (addr & 1) { + cmi8x38_log("CMI8x38: sb_mixer_write(1, %02X, %02X)\n", mixer->index, val); + + switch (mixer->index) { + /* Reset interleaved stereo flag for SBPro mode. */ + case 0x00: + mixer->regs[0x0e] = 0x00; + break; + + /* No dynamic MPU port assignment. */ + case 0x84: + return; + + /* Some extended registers beyond those accepted by the CT1745. */ + case 0xf0: + if (dev->type == CMEDIA_CMI8338) + val &= 0xfe; + mixer->regs[mixer->index] = val; + return; + + case 0xf8 ... 0xff: + if (dev->type == CMEDIA_CMI8338) + mixer->regs[mixer->index] = val; + /* fall-through */ + + case 0xf1 ... 0xf7: + return; + } + + sb_ct1745_mixer_write(addr, val, dev->sb); + + /* No [3F:47] controls. */ + mixer->input_gain_L = 0; + mixer->input_gain_R = 0; + mixer->output_gain_L = (double) 1.0; + mixer->output_gain_R = (double) 1.0; + mixer->bass_l = 8; + mixer->bass_r = 8; + mixer->treble_l = 8; + mixer->treble_r = 8; + + /* Check interleaved stereo flag for SBPro mode. */ + if ((mixer->index == 0x00) || (mixer->index == 0x0e)) + sb_dsp_set_stereo(&dev->sb->dsp, mixer->regs[0x0e] & 2); + + /* Set TDMA channels if auto-detection is enabled. */ + if ((dev->io_regs[0x27] & 0x01) && (mixer->index == 0x81)) { + dev->tdma_8 = dev->sb->dsp.sb_8_dmanum; + if (dev->sb->dsp.sb_type >= SB16) + dev->tdma_16 = dev->sb->dsp.sb_16_dmanum; + } + } else { + cmi8x38_log("CMI8x38: sb_mixer_write(0, %02X)\n", val); + sb_ct1745_mixer_write(addr, val, dev->sb); + } +} + +static void +cmi8x38_remap_sb(cmi8x38_t *dev) +{ + if (dev->sb_base) { + io_removehandler(dev->sb_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 8, 0x0002, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 4, 0x0002, cmi8x38_sb_mixer_read, NULL, NULL, + cmi8x38_sb_mixer_write, NULL, NULL, dev); + + sb_dsp_setaddr(&dev->sb->dsp, 0); + } + + dev->sb_base = 0x220; + if (dev->type == CMEDIA_CMI8338) + dev->sb_base += (dev->io_regs[0x17] & 0x80) >> 2; + else + dev->sb_base += (dev->io_regs[0x17] & 0x0c) << 3; + if (!(dev->io_regs[0x04] & 0x08)) + dev->sb_base = 0; + cmi8x38_log("CMI8x38: remap_sb(%04X)\n", dev->sb_base); + + if (dev->sb_base) { + io_sethandler(dev->sb_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 8, 0x0002, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 4, 0x0002, cmi8x38_sb_mixer_read, NULL, NULL, + cmi8x38_sb_mixer_write, NULL, NULL, dev); + + sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); + } +} + +static void +cmi8x38_remap_opl(cmi8x38_t *dev) +{ + if (dev->opl_base) { + io_removehandler(dev->opl_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + } + + dev->opl_base = (dev->type == CMEDIA_CMI8338) ? 0x388 : opl_ports_cmi8738[dev->io_regs[0x17] & 0x03]; + io_trap_remap(dev->io_traps[TRAP_OPL], (dev->io_regs[0x04] & 0x01) && (dev->io_regs[0x16] & 0x80), dev->opl_base, 4); + if (!(dev->io_regs[0x1a] & 0x08)) + dev->opl_base = 0; + + cmi8x38_log("CMI8x38: remap_opl(%04X)\n", dev->opl_base); + + if (dev->opl_base) { + io_sethandler(dev->opl_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + } +} + +static void +cmi8x38_remap_mpu(cmi8x38_t *dev) +{ + if (dev->mpu_base) + mpu401_change_addr(dev->sb->mpu, 0); + + /* The CMI8338 datasheet's port range of [300:330] is + inaccurate. Drivers expect [330:300] like CMI8738. */ + dev->mpu_base = 0x330 - ((dev->io_regs[0x17] & 0x60) >> 1); + io_trap_remap(dev->io_traps[TRAP_MPU], (dev->io_regs[0x04] & 0x01) && (dev->io_regs[0x16] & 0x20), dev->mpu_base, 2); + if (!(dev->io_regs[0x04] & 0x04)) + dev->mpu_base = 0; + + cmi8x38_log("CMI8x38: remap_mpu(%04X)\n", dev->mpu_base); + + if (dev->mpu_base) + mpu401_change_addr(dev->sb->mpu, dev->mpu_base); +} + +static void +cmi8x38_remap_traps(cmi8x38_t *dev) +{ + cmi8x38_remap_opl(dev); + cmi8x38_remap_mpu(dev); + io_trap_remap(dev->io_traps[TRAP_DMA], (dev->io_regs[0x04] & 0x01) && (dev->io_regs[0x17] & 0x02), 0x0000, 16); + io_trap_remap(dev->io_traps[TRAP_PIC], (dev->io_regs[0x04] & 0x01) && (dev->io_regs[0x17] & 0x01), 0x0020, 2); +} + +static void +cmi8x38_start_playback(cmi8x38_t *dev) +{ + uint8_t i, val = dev->io_regs[0x00]; + + i = !(val & 0x01); + if (!dev->dma[0].playback_enabled && i) + timer_set_delay_u64(&dev->dma[0].poll_timer, dev->dma[0].timer_latch); + dev->dma[0].playback_enabled = i; + + i = !(val & 0x02); + if (!dev->dma[1].playback_enabled && i) + timer_set_delay_u64(&dev->dma[1].poll_timer, dev->dma[1].timer_latch); + dev->dma[1].playback_enabled = i; +} + +static uint8_t +cmi8x38_read(uint16_t addr, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + addr &= 0xff; + uint8_t ret; + + switch (addr) { + case 0x22: + case 0x23: + ret = cmi8x38_sb_mixer_read(addr ^ 1, dev); + break; + + case 0x40 ... 0x4f: + if (dev->type == CMEDIA_CMI8338) + goto io_reg; + else + ret = mpu401_read(addr, dev->sb->mpu); + break; + + case 0x50 ... 0x5f: + if (dev->type == CMEDIA_CMI8338) + goto io_reg; + else + ret = dev->sb->opl.read(addr, dev->sb->opl.priv); + break; + + case 0x80: + case 0x88: + ret = dev->dma[(addr & 0x78) >> 3].sample_ptr; + break; + + case 0x81: + case 0x89: + ret = dev->dma[(addr & 0x78) >> 3].sample_ptr >> 8; + break; + + case 0x82: + case 0x8a: + ret = dev->dma[(addr & 0x78) >> 3].sample_ptr >> 16; + break; + + case 0x83: + case 0x8b: + ret = dev->dma[(addr & 0x78) >> 3].sample_ptr >> 24; + break; + + case 0x84: + case 0x8c: + ret = dev->dma[(addr & 0x78) >> 3].frame_count_dma; + break; + + case 0x85: + case 0x8d: + ret = dev->dma[(addr & 0x78) >> 3].frame_count_dma >> 8; + break; + + case 0x86: + case 0x8e: + ret = dev->dma[(addr & 0x78) >> 3].sample_count_out >> 2; + break; + + case 0x87: + case 0x8f: + ret = dev->dma[(addr & 0x78) >> 3].sample_count_out >> 10; + break; + + default: +io_reg: + ret = dev->io_regs[addr]; + break; + } + + cmi8x38_log("CMI8x38: read(%02X) = %02X\n", addr, ret); + return ret; +} + +static void +cmi8x38_write(uint16_t addr, uint8_t val, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + addr &= 0xff; + cmi8x38_log("CMI8x38: write(%02X, %02X)\n", addr, val); + + switch (addr) { + case 0x00: + val &= 0x0f; + + /* Don't care about recording DMA. */ + dev->dma[0].always_run = val & 0x01; + dev->dma[1].always_run = val & 0x02; + + /* Start playback if requested. */ + dev->io_regs[addr] = val; + cmi8x38_start_playback(dev); + break; + + case 0x02: + /* Reset or start DMA channels if requested. */ + dev->io_regs[addr] = val & 0x03; + for (int i = 0; i < (sizeof(dev->dma) / sizeof(dev->dma[0])); i++) { + if (val & (0x04 << i)) { + /* Reset DMA channel. */ + val &= ~(0x01 << i); + dev->io_regs[0x10] &= ~(0x01 << i); /* clear interrupt */ + + /* Reset Sound Blaster as well when resetting channel 0. */ + if ((i == 0) && (dev->sb->dsp.sb_8_enable || dev->sb->dsp.sb_16_enable || dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16)) + dev->sb->dsp.sb_8_enable = dev->sb->dsp.sb_16_enable = dev->sb->dsp.sb_irq8 = dev->sb->dsp.sb_irq16 = 0; + } else if (val & (0x01 << i)) { + /* Start DMA channel. */ + cmi8x38_log("CMI8x38: DMA %d trigger\n", i); + dev->dma[i].restart = 1; + cmi8x38_dma_process(&dev->dma[i]); + } + } + + /* Clear reset bits. */ + val &= 0x03; + + /* Start playback along with DMA channels. */ + if (val & 0x03) + cmi8x38_start_playback(dev); + + /* Update interrupts. */ + dev->io_regs[addr] = val; + cmi8x38_update_irqs(dev); + break; + + case 0x04: + /* Enable or disable the game port. */ + gameport_remap(dev->gameport, (val & 0x02) ? 0x200 : 0); + + /* Enable or disable the legacy devices. */ + dev->io_regs[addr] = val; + cmi8x38_remap_sb(dev); + /* remap_mpu called by remap_traps */ + + /* Enable or disable I/O traps. */ + cmi8x38_remap_traps(dev); + break; + + case 0x05: + dev->io_regs[addr] = val; + cmi8x38_speed_changed(dev); + break; + + case 0x08: + if (dev->type == CMEDIA_CMI8338) + val &= 0x0f; + break; + + case 0x09: + if (dev->type == CMEDIA_CMI8338) + return; + + /* Update sample rate. */ + dev->io_regs[addr] = val; + cmi8x38_speed_changed(dev); + break; + + case 0x0a: + case 0x0b: + if (dev->type == CMEDIA_CMI8338) + return; + else + val &= 0xe0; + + if (addr == 0x0a) { + /* Set PCI latency timer if requested. */ + dev->pci_regs[0x0d] = (val & 0x80) ? 0x48 : 0x20; /* clearing SETLAT48 is undefined */ + } else { + /* Update channel count. */ + dev->io_regs[addr] = val; + cmi8x38_speed_changed(dev); + } + break; + + case 0x0e: + val &= 0x07; + + /* Clear interrupts. */ + dev->io_regs[0x10] &= val | 0xfc; + if (!(val & 0x04)) + dev->io_regs[0x11] &= ~0xc0; + cmi8x38_update_irqs(dev); + break; + + case 0x15: + if (dev->type == CMEDIA_CMI8338) + return; + else + val &= 0xf0; + + /* Update channel count. */ + dev->io_regs[addr] = val; + cmi8x38_speed_changed(dev); + break; + + case 0x16: + if (dev->type == CMEDIA_CMI8338) { + val &= 0xa0; + + /* Enable or disable I/O traps. */ + dev->io_regs[addr] = val; + cmi8x38_remap_traps(dev); + } + break; + + case 0x17: + if (dev->type == CMEDIA_CMI8338) { + val &= 0xf3; + + /* Force IRQ if requested. Clearing this bit is undefined. */ + if (val & 0x10) + pci_set_irq(dev->slot, PCI_INTA); + else if ((dev->io_regs[0x17] & 0x10) && !(val & 0x10)) + pci_clear_irq(dev->slot, PCI_INTA); + + /* Enable or disable I/O traps. */ + dev->io_regs[addr] = val; + cmi8x38_remap_traps(dev); + } + + /* Remap the legacy devices. */ + dev->io_regs[addr] = val; + cmi8x38_remap_sb(dev); + cmi8x38_remap_mpu(dev); + break; + + case 0x18: + if (dev->type == CMEDIA_CMI8338) + val &= 0x0f; + else + val &= 0xdf; + + /* Update the TDMA position update interrupt's sample interval. */ + dev->tdma_irq_mask = 2047 >> ((val >> 2) & 3); + break; + + case 0x19: + if (dev->type == CMEDIA_CMI8338) + return; + else + val &= 0xe0; + break; + + case 0x1a: + val &= 0xfd; + + /* Enable or disable the OPL. */ + dev->io_regs[addr] = val; + cmi8x38_remap_opl(dev); + break; + + case 0x1b: + if (dev->type == CMEDIA_CMI8338) + val &= 0xf0; + else + val &= 0xd7; + break; + + case 0x20: + /* ??? */ + break; + + case 0x21: + if (dev->type == CMEDIA_CMI8338) + val &= 0xf7; + else + val &= 0x07; + + /* Enable or disable SBPro channel swapping. */ + dev->sb->dsp.sbleftright_default = !!(val & 0x02); + + /* Enable or disable SB16 mode. */ + dev->sb->dsp.sb_type = (val & 0x01) ? SBPRO2 : SB16; + break; + + case 0x22: + case 0x23: + cmi8x38_sb_mixer_write(addr ^ 1, val, dev); + return; + + case 0x24: + if (dev->type == CMEDIA_CMI8338) + val &= 0xcf; + break; + + case 0x27: + if (dev->type == CMEDIA_CMI8338) + val &= 0x03; + else + val &= 0x27; + break; + + case 0x40 ... 0x4f: + if (dev->type != CMEDIA_CMI8338) + mpu401_write(addr, val, dev->sb->mpu); + return; + + case 0x50 ... 0x5f: + if (dev->type != CMEDIA_CMI8338) + dev->sb->opl.write(addr, val, dev->sb->opl.priv); + return; + + case 0x92: + if (dev->type == CMEDIA_CMI8338) + return; + else + val &= 0x1f; + break; + + case 0x93: + if (dev->type == CMEDIA_CMI8338) + return; + else + val &= 0x10; + break; + + case 0x25: + case 0x26: + case 0x70: + case 0x71: + case 0x80 ... 0x8f: + break; + + default: + return; + } + + dev->io_regs[addr] = val; +} + +static void +cmi8x38_remap(cmi8x38_t *dev) +{ + if (dev->io_base) + io_removehandler(dev->io_base, 256, cmi8x38_read, NULL, NULL, cmi8x38_write, NULL, NULL, dev); + + dev->io_base = (dev->pci_regs[0x04] & 0x01) ? (dev->pci_regs[0x11] << 8) : 0; + cmi8x38_log("CMI8x38: remap(%04X)\n", dev->io_base); + + if (dev->io_base) + io_sethandler(dev->io_base, 256, cmi8x38_read, NULL, NULL, cmi8x38_write, NULL, NULL, dev); +} + +static uint8_t +cmi8x38_pci_read(int func, int addr, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + uint8_t ret = 0xff; + + if (!func) { + ret = dev->pci_regs[addr]; + cmi8x38_log("CMI8x38: pci_read(%02X) = %02X\n", addr, ret); + } + + return ret; +} + +static void +cmi8x38_pci_write(int func, int addr, uint8_t val, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + if (func) + return; + + cmi8x38_log("CMI8x38: pci_write(%02X, %02X)\n", addr, val); + + switch (addr) { + case 0x04: + val &= 0x05; + + /* Enable or disable the I/O BAR. */ + dev->pci_regs[addr] = val; + cmi8x38_remap(dev); + break; + + case 0x05: + val &= 0x01; + break; + + case 0x11: + /* Remap the I/O BAR. */ + dev->pci_regs[addr] = val; + cmi8x38_remap(dev); + break; + + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + if (!(dev->io_regs[0x1a] & 0x01)) + return; + break; + + case 0x40: + if (dev->type == CMEDIA_CMI8338) + val &= 0x0f; + else + return; + break; + + case 0x0c: + case 0x0d: + case 0x3c: + break; + + default: + return; + } + + dev->pci_regs[addr] = val; +} + +static void +cmi8x38_update(cmi8x38_t *dev, cmi8x38_dma_t *dma) +{ + sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16; + int32_t l = (dma->out_fl * mixer->voice_l) * mixer->master_l, + r = (dma->out_fr * mixer->voice_r) * mixer->master_r; + + for (; dma->pos < sound_pos_global; dma->pos++) { + dma->buffer[dma->pos * 2] = l; + dma->buffer[dma->pos * 2 + 1] = r; + } +} + +static void +cmi8x38_dma_process(void *priv) +{ + cmi8x38_dma_t *dma = (cmi8x38_dma_t *) priv; + cmi8x38_t *dev = dma->dev; + + /* Stop if this DMA channel is not active. */ + uint8_t dma_bit = 0x01 << dma->id; + if (!(dev->io_regs[0x02] & dma_bit)) { + cmi8x38_log("CMI8x38: Stopping DMA %d due to inactive channel (%02X)\n", dma->id, dev->io_regs[0x02]); + return; + } + + /* Schedule next run. */ + timer_on_auto(&dma->dma_timer, dma->dma_latch); + + /* Process DMA if it's active, and the FIFO has room or is disabled. */ + uint8_t dma_status = dev->io_regs[0x00] >> dma->id; + if (!(dma_status & 0x04) && (dma->always_run || ((dma->fifo_end - dma->fifo_pos) <= (sizeof(dma->fifo) - 4)))) { + /* Start DMA if requested. */ + if (dma->restart) { + /* Set up base address and counters. + Nothing reads sample_count_out; it's implemented as an assumption. */ + dma->restart = 0; + dma->sample_ptr = *((uint32_t *) &dev->io_regs[dma->reg]); + dma->frame_count_dma = dma->sample_count_out = *((uint16_t *) &dev->io_regs[dma->reg | 0x4]) + 1; + dma->frame_count_fragment = *((uint16_t *) &dev->io_regs[dma->reg | 0x6]) + 1; + + cmi8x38_log("CMI8x38: Starting DMA %d at %08X (count %04X fragment %04X)\n", dma->id, dma->sample_ptr, dma->frame_count_dma, dma->frame_count_fragment); + } + + if (dma_status & 0x01) { + /* Write channel: read data from FIFO. */ + mem_writel_phys(dma->sample_ptr, *((uint32_t *) &dma->fifo[dma->fifo_end & (sizeof(dma->fifo) - 1)])); + } else { + /* Read channel: write data to FIFO. */ + *((uint32_t *) &dma->fifo[dma->fifo_end & (sizeof(dma->fifo) - 1)]) = mem_readl_phys(dma->sample_ptr); + } + dma->fifo_end += 4; + dma->sample_ptr += 4; + + /* Check if the fragment size was reached. */ + if (--dma->frame_count_fragment <= 0) { + /* Reset fragment counter. */ + dma->frame_count_fragment = *((uint16_t *) &dev->io_regs[dma->reg | 0x6]) + 1; +#ifdef ENABLE_CMI8X38_LOG + if (dma->frame_count_fragment > 1) /* avoid log spam if fragment counting is unused, like on the newer WDM drivers (cmudax3) */ + cmi8x38_log("CMI8x38: DMA %d fragment size reached at %04X frames left", dma->id, dma->frame_count_dma - 1); +#endif + /* Fire interrupt if requested. */ + if (dev->io_regs[0x0e] & dma_bit) { +#ifdef ENABLE_CMI8X38_LOG + if (dma->frame_count_fragment > 1) + cmi8x38_log(", firing interrupt\n"); +#endif + /* Set channel interrupt flag. */ + dev->io_regs[0x10] |= dma_bit; + + /* Fire interrupt. */ + cmi8x38_update_irqs(dev); + } else { +#ifdef ENABLE_CMI8X38_LOG + if (dma->frame_count_fragment > 1) + cmi8x38_log("\n"); +#endif + } + } + + /* Check if the buffer's end was reached. */ + if (--dma->frame_count_dma <= 0) { + dma->frame_count_dma = 0; + cmi8x38_log("CMI8x38: DMA %d end reached, restarting\n", dma->id); + + /* Restart DMA on the next run. */ + dma->restart = 1; + } + } +} + +static void +cmi8x38_poll(void *priv) +{ + cmi8x38_dma_t *dma = (cmi8x38_dma_t *) priv; + cmi8x38_t *dev = dma->dev; + int16_t *out_l, *out_r, *out_ol, *out_or; /* o = opposite */ + + /* Schedule next run if playback is enabled. */ + if (dma->playback_enabled) + timer_advance_u64(&dma->poll_timer, dma->timer_latch); + + /* Update audio buffer. */ + cmi8x38_update(dev, dma); + + /* Swap stereo pair if this is the rear DMA channel according to ENDBDAC and XCHGDAC. */ + if ((dev->io_regs[0x1a] & 0x80) && (!!(dev->io_regs[0x1a] & 0x40) ^ dma->id)) { + out_l = &dma->out_rl; + out_r = &dma->out_rr; + out_ol = &dma->out_fl; + out_or = &dma->out_fr; + } else { + out_l = &dma->out_fl; + out_r = &dma->out_fr; + out_ol = &dma->out_rl; + out_or = &dma->out_rr; + } + *out_ol = *out_or = dma->out_c = dma->out_lfe = 0; + + /* Feed next sample from the FIFO. */ + switch ((dev->io_regs[0x08] >> (dma->id << 1)) & 0x03) { + case 0x00: /* Mono, 8-bit PCM */ + if ((dma->fifo_end - dma->fifo_pos) >= 1) { + *out_l = *out_r = (dma->fifo[dma->fifo_pos++ & (sizeof(dma->fifo) - 1)] ^ 0x80) << 8; + dma->sample_count_out--; + goto n4spk3d; + } + break; + + case 0x01: /* Stereo, 8-bit PCM */ + if ((dma->fifo_end - dma->fifo_pos) >= 2) { + *out_l = (dma->fifo[dma->fifo_pos++ & (sizeof(dma->fifo) - 1)] ^ 0x80) << 8; + *out_r = (dma->fifo[dma->fifo_pos++ & (sizeof(dma->fifo) - 1)] ^ 0x80) << 8; + dma->sample_count_out -= 2; + goto n4spk3d; + } + break; + + case 0x02: /* Mono, 16-bit PCM */ + if ((dma->fifo_end - dma->fifo_pos) >= 2) { + *out_l = *out_r = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->sample_count_out -= 2; + goto n4spk3d; + } + break; + + case 0x03: /* Stereo, 16-bit PCM, with multi-channel capability */ + switch (dma->channels) { + case 2: + if ((dma->fifo_end - dma->fifo_pos) >= 4) { + *out_l = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + *out_r = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->sample_count_out -= 4; + goto n4spk3d; + } + break; + + case 4: + if ((dma->fifo_end - dma->fifo_pos) >= 8) { + dma->out_fl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_fr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_rl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_rr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->sample_count_out -= 8; + return; + } + break; + + case 5: /* not supported by WDM and Linux drivers; channel layout assumed */ + if ((dma->fifo_end - dma->fifo_pos) >= 10) { + dma->out_fl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_fr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_rl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_rr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_c = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->sample_count_out -= 10; + return; + } + break; + + case 6: + if ((dma->fifo_end - dma->fifo_pos) >= 12) { + dma->out_fl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_fr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_rl = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_rr = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_c = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->out_lfe = *((uint16_t *) &dma->fifo[dma->fifo_pos & (sizeof(dma->fifo) - 1)]); + dma->fifo_pos += 2; + dma->sample_count_out -= 12; + return; + } + break; + } + break; + } + + /* Feed silence if the FIFO is empty. */ + *out_l = *out_r = 0; + + /* Stop playback if DMA is disabled. */ + if ((*((uint32_t *) &dev->io_regs[0x00]) & (0x00010001 << dma->id)) != (0x00010000 << dma->id)) { + cmi8x38_log("CMI8x38: Stopping playback of DMA channel %d\n", dma->id); + dma->playback_enabled = 0; + } + + return; +n4spk3d: + /* Mirror front and rear channels if requested. */ + if (dev->io_regs[0x1b] & 0x04) { + *out_ol = *out_l; + *out_or = *out_r; + } +} + +static void +cmi8x38_get_buffer(int32_t *buffer, int len, void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Update wave playback channels. */ + cmi8x38_update(dev, &dev->dma[0]); + cmi8x38_update(dev, &dev->dma[1]); + + /* Apply wave mute. */ + if (!(dev->io_regs[0x24] & 0x40)) { + /* Fill buffer. */ + for (int c = 0; c < len * 2; c++) { + buffer[c] += dev->dma[0].buffer[c]; + buffer[c] += dev->dma[1].buffer[c]; + } + } + + dev->dma[0].pos = dev->dma[1].pos = 0; +} + +static void +cmi8x38_speed_changed(void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + double freq; + uint8_t dsr = dev->io_regs[0x09], freqreg = dev->io_regs[0x05] >> 2, + chfmt45 = dev->io_regs[0x0b], chfmt6 = dev->io_regs[0x15]; + +#ifdef ENABLE_CMI8X38_LOG + char buf[256]; + sprintf(buf, "%02X-%02X-%02X-%02X", dsr, freqreg, chfmt45, chfmt6); +#endif + + /* CMI8338 claims the frequency controls are for DAC (playback) and ADC (recording) + respectively, while CMI8738 claims they're for channel 0 and channel 1. The Linux + driver just assumes the latter definition, so that's what we're going to use here. */ + for (int i = 0; i < (sizeof(dev->dma) / sizeof(dev->dma[0])); i++) { + /* More confusion. The Linux driver implies the sample rate doubling + bits take precedence over any configured sample rate. 128K with both + doubling bits set is also supported there, but that's for newer chips. */ + switch (dsr & 0x03) { + case 0x01: + freq = 88200.0; + break; + case 0x02: + freq = 96000.0; + break; +#if 0 + case 0x03: + freq = 128000.0; + break; +#endif + default: + freq = freqs[freqreg & 0x07]; + break; + } + + /* Set polling timer period. */ + freq = 1000000.0 / freq; + dev->dma[i].timer_latch = (uint64_t) ((double) TIMER_USEC * freq); + + /* Calculate channel count and set DMA timer period. */ + if ((dev->type == CMEDIA_CMI8338) || (i == 0)) { /* multi-channel requires channel 1 */ +stereo: + dev->dma[i].channels = 2; + } else { + if (chfmt45 & 0x80) + dev->dma[i].channels = (chfmt6 & 0x80) ? 6 : 5; + else if (chfmt45 & 0x20) + dev->dma[i].channels = 4; + else + goto stereo; + } + dev->dma[i].dma_latch = freq / dev->dma[i].channels; /* frequency / approximately(dwords * 2) */ + + /* Shift sample rate configuration registers. */ +#ifdef ENABLE_CMI8X38_LOG + sprintf(&buf[strlen(buf)], " %d:%X-%X-%.0f-%dC", i, dsr & 0x03, freqreg & 0x07, 1000000.0 / freq, dev->dma[i].channels); +#endif + dsr >>= 2; + freqreg >>= 3; + } + +#ifdef ENABLE_CMI8X38_LOG + if (cmi8x38_do_log) + ui_sb_bugui(buf); +#endif +} + +static void +cmi8x38_reset(void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + /* Reset PCI configuration registers. */ + memset(dev->pci_regs, 0, sizeof(dev->pci_regs)); + dev->pci_regs[0x00] = 0xf6; + dev->pci_regs[0x01] = 0x13; + dev->pci_regs[0x02] = dev->type; + dev->pci_regs[0x03] = 0x01; + dev->pci_regs[0x06] = (dev->type == CMEDIA_CMI8338) ? 0x80 : 0x10; + dev->pci_regs[0x07] = 0x02; + dev->pci_regs[0x08] = 0x10; + dev->pci_regs[0x0a] = 0x01; + dev->pci_regs[0x0b] = 0x04; + dev->pci_regs[0x0d] = 0x20; + dev->pci_regs[0x10] = 0x01; + dev->pci_regs[0x2c] = 0xf6; + dev->pci_regs[0x2d] = 0x13; + if (dev->type == CMEDIA_CMI8338) { + dev->pci_regs[0x2e] = 0xff; + dev->pci_regs[0x2f] = 0xff; + } else { + dev->pci_regs[0x2e] = dev->type; + dev->pci_regs[0x2f] = 0x01; + dev->pci_regs[0x34] = 0x40; + } + dev->pci_regs[0x3d] = 0x01; + dev->pci_regs[0x3e] = 0x02; + dev->pci_regs[0x3f] = 0x18; + + /* Reset I/O space registers. */ + memset(dev->io_regs, 0, sizeof(dev->io_regs)); + dev->io_regs[0x0b] = (dev->type >> 8) & 0x1f; + dev->io_regs[0x0f] = dev->type >> 16; + dev->tdma_irq_mask = 2047; + + /* Reset I/O mappings. */ + cmi8x38_remap(dev); + cmi8x38_remap_sb(dev); + /* remap_mpu and remap_opl called by remap_traps */ + cmi8x38_remap_traps(dev); + + /* Reset DMA channels. */ + for (int i = 0; i < (sizeof(dev->dma) / sizeof(dev->dma[0])); i++) { + dev->dma[i].playback_enabled = 0; + dev->dma[i].fifo_pos = dev->dma[i].fifo_end = 0; + memset(dev->dma[i].fifo, 0, sizeof(dev->dma[i].fifo)); + } + + /* Reset TDMA channel. */ + dev->tdma_8 = 1; + dev->tdma_16 = 5; + dev->tdma_mask = 0; + + /* Reset Sound Blaster 16 mixer. */ + sb_ct1745_mixer_reset(dev->sb); +} + +static void * +cmi8x38_init(const device_t *info) +{ + cmi8x38_t *dev = malloc(sizeof(cmi8x38_t)); + memset(dev, 0, sizeof(cmi8x38_t)); + + /* Set the chip type. */ + if ((info->local == CMEDIA_CMI8738_6CH) && !device_get_config_int("six_channel")) + dev->type = CMEDIA_CMI8738_4CH; + else + dev->type = info->local; + cmi8x38_log("CMI8x38: init(%06X)\n", dev->type); + + /* Initialize Sound Blaster 16. */ + dev->sb = device_add_inst(device_get_config_int("receive_input") ? &sb_16_compat_device : &sb_16_compat_nompu_device, 1); + dev->sb->opl_enabled = 1; /* let snd_sb.c handle the OPL3 */ + dev->sb->mixer_sb16.output_filter = 0; /* no output filtering */ + + /* Initialize legacy interrupt and DMA handlers. */ + mpu401_irq_attach(dev->sb->mpu, cmi8x38_mpu_irq_update, cmi8x38_mpu_irq_pending, dev); + sb_dsp_irq_attach(&dev->sb->dsp, cmi8x38_sb_irq_update, dev); + sb_dsp_dma_attach(&dev->sb->dsp, cmi8x38_sb_dma_readb, cmi8x38_sb_dma_readw, cmi8x38_sb_dma_writeb, cmi8x38_sb_dma_writew, dev); + io_sethandler(0x00, 8, NULL, NULL, NULL, cmi8x38_dma_write, NULL, NULL, dev); + io_sethandler(0x08, 8, NULL, NULL, NULL, cmi8x38_dma_mask_write, NULL, NULL, dev); + io_sethandler(0xc0, 16, NULL, NULL, NULL, cmi8x38_dma_write, NULL, NULL, dev); + io_sethandler(0xd0, 16, NULL, NULL, NULL, cmi8x38_dma_mask_write, NULL, NULL, dev); + + /* Initialize DMA channels. */ + for (int i = 0; i < (sizeof(dev->dma) / sizeof(dev->dma[0])); i++) { + dev->dma[i].id = i; + dev->dma[i].reg = 0x80 + (8 * i); + dev->dma[i].dev = dev; + + timer_add(&dev->dma[i].dma_timer, cmi8x38_dma_process, &dev->dma[i], 0); + timer_add(&dev->dma[i].poll_timer, cmi8x38_poll, &dev->dma[i], 0); + } + cmi8x38_speed_changed(dev); + + /* Initialize playback handler and CD audio filter. */ + sound_add_handler(cmi8x38_get_buffer, dev); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, dev->sb); + + /* Initialize game port. */ + dev->gameport = gameport_add(&gameport_pnp_device); + + /* Initialize I/O traps. */ + if (dev->type == CMEDIA_CMI8338) { + dev->io_traps[TRAP_DMA] = io_trap_add(cmi8338_io_trap, dev); + dev->io_traps[TRAP_PIC] = io_trap_add(cmi8338_io_trap, dev); + dev->io_traps[TRAP_OPL] = io_trap_add(cmi8338_io_trap, dev); + dev->io_traps[TRAP_MPU] = io_trap_add(cmi8338_io_trap, dev); + } + + /* Add PCI card. */ + dev->slot = pci_add_card((info->local & (1 << 13)) ? PCI_ADD_SOUND : PCI_ADD_NORMAL, cmi8x38_pci_read, cmi8x38_pci_write, dev); + + /* Perform initial reset. */ + cmi8x38_reset(dev); + + return dev; +} + +static void +cmi8x38_close(void *priv) +{ + cmi8x38_t *dev = (cmi8x38_t *) priv; + + cmi8x38_log("CMI8x38: close()\n"); + + for (int i = 0; i < TRAP_MAX; i++) + io_trap_remove(dev->io_traps[i]); + + free(dev); +} + +static const device_config_t cmi8x38_config[] = { + // clang-format off + { + .name = "receive_input", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +static const device_config_t cmi8738_config[] = { + // clang-format off + { + .name = "six_channel", + .description = "6CH variant (6-channel)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t cmi8338_device = { + .name = "C-Media CMI8338", + .internal_name = "cmi8338", + .flags = DEVICE_PCI, + .local = CMEDIA_CMI8338, + .init = cmi8x38_init, + .close = cmi8x38_close, + .reset = cmi8x38_reset, + { .available = NULL }, + .speed_changed = cmi8x38_speed_changed, + .force_redraw = NULL, + .config = cmi8x38_config +}; + +const device_t cmi8338_onboard_device = { + .name = "C-Media CMI8338 (On-Board)", + .internal_name = "cmi8338_onboard", + .flags = DEVICE_PCI, + .local = CMEDIA_CMI8338 | (1 << 13), + .init = cmi8x38_init, + .close = cmi8x38_close, + .reset = cmi8x38_reset, + { .available = NULL }, + .speed_changed = cmi8x38_speed_changed, + .force_redraw = NULL, + .config = cmi8x38_config +}; + +const device_t cmi8738_device = { + .name = "C-Media CMI8738", + .internal_name = "cmi8738", + .flags = DEVICE_PCI, + .local = CMEDIA_CMI8738_6CH, + .init = cmi8x38_init, + .close = cmi8x38_close, + .reset = cmi8x38_reset, + { .available = NULL }, + .speed_changed = cmi8x38_speed_changed, + .force_redraw = NULL, + .config = cmi8738_config +}; + +const device_t cmi8738_onboard_device = { + .name = "C-Media CMI8738 (On-Board)", + .internal_name = "cmi8738_onboard", + .flags = DEVICE_PCI, + .local = CMEDIA_CMI8738_4CH | (1 << 13), + .init = cmi8x38_init, + .close = cmi8x38_close, + .reset = cmi8x38_reset, + { .available = NULL }, + .speed_changed = cmi8x38_speed_changed, + .force_redraw = NULL, + .config = cmi8x38_config +}; + +const device_t cmi8738_6ch_onboard_device = { + .name = "C-Media CMI8738-6CH (On-Board)", + .internal_name = "cmi8738_6ch_onboard", + .flags = DEVICE_PCI, + .local = CMEDIA_CMI8738_6CH | (1 << 13), + .init = cmi8x38_init, + .close = cmi8x38_close, + .reset = cmi8x38_reset, + { .available = NULL }, + .speed_changed = cmi8x38_speed_changed, + .force_redraw = NULL, + .config = cmi8x38_config +}; diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 9a635b50e..50b05dd48 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -1,203 +1,245 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/io.h> #include <86box/device.h> +#include <86box/io.h> +#include <86box/snd_cms.h> #include <86box/sound.h> - -#define MASTER_CLOCK 7159090 - - -typedef struct cms_t +void +cms_update(cms_t *cms) { - int addrs[2]; - uint8_t regs[2][32]; - uint16_t latch[2][6]; - int freq[2][6]; - float count[2][6]; - int vol[2][6][2]; - int stat[2][6]; - uint16_t noise[2][2]; - uint16_t noisefreq[2][2]; - int noisecount[2][2]; - int noisetype[2][2]; - - uint8_t latched_data; + for (; cms->pos < sound_pos_global; cms->pos++) { + int c, d; + int16_t out_l = 0, out_r = 0; - int16_t buffer[SOUNDBUFLEN * 2]; - - int pos; -} cms_t; - -void cms_update(cms_t *cms) -{ - for (; cms->pos < sound_pos_global; cms->pos++) - { - int c, d; - int16_t out_l = 0, out_r = 0; - - for (c = 0; c < 4; c++) - { - switch (cms->noisetype[c >> 1][c & 1]) - { - case 0: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/256; break; - case 1: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/512; break; - case 2: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/1024; break; - case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; - } - } - for (c = 0; c < 2; c ++) - { - if (cms->regs[c][0x1C] & 1) - { - for (d = 0; d < 6; d++) - { - if (cms->regs[c][0x14] & (1 << d)) - { - if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90); - if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90); - cms->count[c][d] += cms->freq[c][d]; - if (cms->count[c][d] >= 24000) - { - cms->count[c][d] -= 24000; - cms->stat[c][d] ^= 1; - } - } - else if (cms->regs[c][0x15] & (1 << d)) - { - if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90); - if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90); - } - } - for (d = 0; d < 2; d++) - { - cms->noisecount[c][d] += cms->noisefreq[c][d]; - while (cms->noisecount[c][d] >= 24000) - { - cms->noisecount[c][d] -= 24000; - cms->noise[c][d] <<= 1; - if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) - cms->noise[c][d] |= 1; - } - } - } - } - cms->buffer[(cms->pos << 1)] = out_l; - cms->buffer[(cms->pos << 1) + 1] = out_r; - } -} - -void cms_get_buffer(int32_t *buffer, int len, void *p) -{ - cms_t *cms = (cms_t *)p; - - int c; - - cms_update(cms); - - for (c = 0; c < len * 2; c++) - buffer[c] += cms->buffer[c]; - - cms->pos = 0; -} - -void cms_write(uint16_t addr, uint8_t val, void *p) -{ - cms_t *cms = (cms_t *)p; - int voice; - int chip = (addr & 2) >> 1; - - switch (addr & 0xf) - { + for (c = 0; c < 4; c++) { + switch (cms->noisetype[c >> 1][c & 1]) { + case 0: + cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 256; + break; case 1: - cms->addrs[0] = val & 31; - break; + cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 512; + break; + case 2: + cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 1024; + break; case 3: - cms->addrs[1] = val & 31; - break; - - case 0: case 2: - cms_update(cms); - cms->regs[chip][cms->addrs[chip] & 31] = val; - switch (cms->addrs[chip] & 31) - { - case 0x00: case 0x01: case 0x02: /*Volume*/ - case 0x03: case 0x04: case 0x05: - voice = cms->addrs[chip] & 7; - cms->vol[chip][voice][0] = val & 0xf; - cms->vol[chip][voice][1] = val >> 4; - break; - case 0x08: case 0x09: case 0x0A: /*Frequency*/ - case 0x0B: case 0x0C: case 0x0D: - voice = cms->addrs[chip] & 7; - cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; - cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - break; - case 0x10: case 0x11: case 0x12: /*Octave*/ - voice = (cms->addrs[chip] & 3) << 1; - cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); - cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); - cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - cms->freq[chip][voice + 1] = (MASTER_CLOCK/512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); - break; - case 0x16: /*Noise*/ - cms->noisetype[chip][0] = val & 3; - cms->noisetype[chip][1] = (val >> 4) & 3; - break; + cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; + break; + } + } + for (c = 0; c < 2; c++) { + if (cms->regs[c][0x1C] & 1) { + for (d = 0; d < 6; d++) { + if (cms->regs[c][0x14] & (1 << d)) { + if (cms->stat[c][d]) + out_l += (cms->vol[c][d][0] * 90); + if (cms->stat[c][d]) + out_r += (cms->vol[c][d][1] * 90); + cms->count[c][d] += cms->freq[c][d]; + if (cms->count[c][d] >= 24000) { + cms->count[c][d] -= 24000; + cms->stat[c][d] ^= 1; + } + } else if (cms->regs[c][0x15] & (1 << d)) { + if (cms->noise[c][d / 3] & 1) + out_l += (cms->vol[c][d][0] * 90); + if (cms->noise[c][d / 3] & 1) + out_r += (cms->vol[c][d][0] * 90); + } } - break; - case 0x6: case 0x7: - cms->latched_data = val; - break; + for (d = 0; d < 2; d++) { + cms->noisecount[c][d] += cms->noisefreq[c][d]; + while (cms->noisecount[c][d] >= 24000) { + cms->noisecount[c][d] -= 24000; + cms->noise[c][d] <<= 1; + if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) + cms->noise[c][d] |= 1; + } + } + } } + cms->buffer[(cms->pos << 1)] = out_l; + cms->buffer[(cms->pos << 1) + 1] = out_r; + } } -uint8_t cms_read(uint16_t addr, void *p) +void +cms_get_buffer(int32_t *buffer, int len, void *p) { - cms_t *cms = (cms_t *)p; + cms_t *cms = (cms_t *) p; - switch (addr & 0xf) - { - case 0x1: - return cms->addrs[0]; - case 0x3: - return cms->addrs[1]; - case 0x4: - return 0x7f; - case 0xa: case 0xb: - return cms->latched_data; + int c; + + cms_update(cms); + + for (c = 0; c < len * 2; c++) + buffer[c] += cms->buffer[c]; + + cms->pos = 0; +} + +void +cms_write(uint16_t addr, uint8_t val, void *p) +{ + cms_t *cms = (cms_t *) p; + int voice; + int chip = (addr & 2) >> 1; + + switch (addr & 0xf) { + case 1: + cms->addrs[0] = val & 31; + break; + case 3: + cms->addrs[1] = val & 31; + break; + + case 0: + case 2: + cms_update(cms); + cms->regs[chip][cms->addrs[chip] & 31] = val; + switch (cms->addrs[chip] & 31) { + case 0x00: + case 0x01: + case 0x02: /*Volume*/ + case 0x03: + case 0x04: + case 0x05: + voice = cms->addrs[chip] & 7; + cms->vol[chip][voice][0] = val & 0xf; + cms->vol[chip][voice][1] = val >> 4; + break; + case 0x08: + case 0x09: + case 0x0A: /*Frequency*/ + case 0x0B: + case 0x0C: + case 0x0D: + voice = cms->addrs[chip] & 7; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; + cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + break; + case 0x10: + case 0x11: + case 0x12: /*Octave*/ + voice = (cms->addrs[chip] & 3) << 1; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + break; + case 0x16: /*Noise*/ + cms->noisetype[chip][0] = val & 3; + cms->noisetype[chip][1] = (val >> 4) & 3; + break; + } + break; + case 0x6: + case 0x7: + cms->latched_data = val; + break; + } +} + +uint8_t +cms_read(uint16_t addr, void *p) +{ + cms_t *cms = (cms_t *) p; + + switch (addr & 0xf) { + case 0x1: + return cms->addrs[0]; + case 0x3: + return cms->addrs[1]; + case 0x4: + return 0x7f; + case 0xa: + case 0xb: + return cms->latched_data; + } + return 0xff; +} + +void * +cms_init(const device_t *info) +{ + cms_t *cms = malloc(sizeof(cms_t)); + memset(cms, 0, sizeof(cms_t)); + + uint16_t addr = device_get_config_hex16("base"); + io_sethandler(addr, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); + sound_add_handler(cms_get_buffer, cms); + return cms; +} + +void +cms_close(void *p) +{ + cms_t *cms = (cms_t *) p; + + free(cms); +} + +static const device_config_t cms_config[] = { + // clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x210", + .value = 0x210 + }, + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x230", + .value = 0x230 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "" + } } - return 0xff; -} - -void *cms_init(const device_t *info) -{ - cms_t *cms = malloc(sizeof(cms_t)); - memset(cms, 0, sizeof(cms_t)); - - io_sethandler(0x0220, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); - sound_add_handler(cms_get_buffer, cms); - return cms; -} - -void cms_close(void *p) -{ - cms_t *cms = (cms_t *)p; - - free(cms); -} - -const device_t cms_device = -{ - "Creative Music System / Game Blaster", - 0, 0, - cms_init, cms_close, NULL, - NULL, NULL, NULL, - NULL + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t cms_device = { + .name = "Creative Music System / Game Blaster", + .internal_name = "cms", + .flags = DEVICE_ISA, + .local = 0, + .init = cms_init, + .close = cms_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = cms_config }; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c new file mode 100644 index 000000000..31f4e8e6c --- /dev/null +++ b/src/sound/snd_cs423x.c @@ -0,0 +1,898 @@ +/* + * 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. + * + * Crystal CS423x (SBPro/WSS compatible sound chips) emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021-2022 RichardG. + */ +#include +#include +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.h> +#include <86box/gameport.h> +#include <86box/i2c.h> +#include <86box/io.h> +#include <86box/isapnp.h> +#include <86box/midi.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/pic.h> +#include <86box/sound.h> +#include <86box/snd_ad1848.h> +#include <86box/snd_opl.h> +#include <86box/snd_sb.h> + +#define CRYSTAL_NOEEPROM 0x100 + +enum { + CRYSTAL_CS4235 = 0xdd, + CRYSTAL_CS4236B = 0xcb, + CRYSTAL_CS4237B = 0xc8, + CRYSTAL_CS4238B = 0xc9 +}; +enum { + CRYSTAL_SLAM_NONE = 0, + CRYSTAL_SLAM_INDEX = 1, + CRYSTAL_SLAM_BYTE1 = 2, + CRYSTAL_SLAM_BYTE2 = 3 +}; + +static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0x79, 0xBC, + 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, + 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, + 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; +static const uint8_t cs4236b_eeprom[] = { + // clang-format off + /* Chip configuration */ + 0x55, 0xbb, /* magic */ + 0x00, 0x00, /* length */ + 0x00, 0x03, /* CD-ROM and modem decode */ + 0x80, /* misc. config */ + 0x80, /* global config */ + 0x0b, /* chip ID */ + 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, /* reserved */ + 0x00, /* external decode length */ + 0x48, /* reserved */ + 0x75, 0xb9, 0xfc, /* IRQ routing */ + 0x10, 0x03, /* DMA routing */ + + /* PnP resources */ + 0x0e, 0x63, 0x42, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4236, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ + 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ + + 0x15, 0x0e, 0x63, 0x00, 0x00, 0x00, /* logical device CSC0000 */ + 0x82, 0x07, 0x00, 'W', 'S', 'S', '/', 'S', 'B', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x2a, 0x02, 0x28, /* DMA 1, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x09, 0x28, /* DMA 0/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0x20, 0x00, /* IRQ 5 */ + 0x47, 0x01, 0x34, 0x05, 0x34, 0x05, 0x04, 0x04, /* I/O 0x534, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x10, /* I/O 0x220, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x2a, 0x0a, 0x28, /* DMA 1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */ + 0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x60, 0x02, 0x20, 0x10, /* I/O 0x220-0x260, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */ + 0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x08, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x00, 0x03, 0x20, 0x10, /* I/O 0x220-0x300, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x38, /* end dependent functions */ + + 0x15, 0x0e, 0x63, 0x00, 0x01, 0x00, /* logical device CSC0001 */ + 0x82, 0x05, 0x00, 'G', 'A', 'M', 'E', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x38, /* end dependent functions */ + + 0x15, 0x0e, 0x63, 0x00, 0x10, 0x00, /* logical device CSC0010 */ + 0x82, 0x05, 0x00, 'C', 'T', 'R', 'L', 0x00, /* ANSI identifier */ + 0x47, 0x01, 0x20, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x120-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x0e, 0x63, 0x00, 0x03, 0x00, /* logical device CSC0003 */ + 0x82, 0x04, 0x00, 'M', 'P', 'U', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x00, 0x02, /* IRQ 9 */ + 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x08, 0x02, /* I/O 0x330, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0x00, 0x9a, /* IRQ 9/11/12/15 */ + 0x47, 0x01, 0x30, 0x03, 0x60, 0x03, 0x08, 0x02, /* I/O 0x330-0x360, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x47, 0x01, 0x30, 0x03, 0xe0, 0x03, 0x08, 0x02, /* I/O 0x330-0x3E0, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ + // clang-format on +}; + +typedef struct cs423x_t { + void *pnp_card; + ad1848_t ad1848; + sb_t *sb; + void *gameport; + void *i2c, *eeprom; + + uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size : 11, pnp_offset; + uint8_t type, ad1848_type, regs[8], indirect_regs[16], + eeprom_data[2048], ram_data[65536], ram_dl : 2, opl_wss : 1; + char *nvr_path; + + uint8_t pnp_enable : 1, key_pos : 5, slam_enable : 1, slam_state : 2, slam_ld, slam_reg; + isapnp_device_config_t *slam_config; +} cs423x_t; + +static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); +static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig); +static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); + +static void +cs423x_nvram(cs423x_t *dev, uint8_t save) +{ + FILE *f = nvr_fopen(dev->nvr_path, save ? "wb" : "rb"); + if (f) { + if (save) + fwrite(dev->eeprom_data, sizeof(dev->eeprom_data), 1, f); + else + fread(dev->eeprom_data, sizeof(dev->eeprom_data), 1, f); + fclose(f); + } +} + +static uint8_t +cs423x_read(uint16_t addr, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t reg = addr & 7; + uint8_t ret = dev->regs[reg]; + + switch (reg) { + case 1: /* EEPROM Interface */ + ret &= ~0x04; + if ((dev->regs[1] & 0x04) && i2c_gpio_get_sda(dev->i2c)) + ret |= 0x04; + break; + + case 4: /* Control Indirect Data Register */ + ret = dev->indirect_regs[dev->regs[3]]; + break; + + case 5: /* Control/RAM Access */ + /* Reading RAM is undocumented; the Windows drivers do so. */ + if (dev->ram_dl == 3) + ret = dev->ram_data[dev->ram_addr++]; + break; + + case 7: /* Global Status */ + /* Context switching: take active context and interrupt flag, then clear interrupt flag. */ + ret &= 0xc0; + dev->regs[7] &= 0x80; + + if (dev->sb->mpu->state.irq_pending) /* MPU interrupt */ + ret |= 0x08; + if (dev->ad1848.status & 0x01) /* WSS interrupt */ + ret |= 0x10; + if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) /* SBPro interrupt */ + ret |= 0x20; + + break; + } + + return ret; +} + +static void +cs423x_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t reg = addr & 0x07; + + switch (reg) { + case 1: /* EEPROM Interface */ + if (val & 0x04) + i2c_gpio_set(dev->i2c, val & 0x01, val & 0x02); + break; + + case 3: /* Control Indirect Access Register */ + val &= 0x0f; + break; + + case 4: /* Control Indirect Data Register */ + switch (dev->regs[3] & 0x0f) { + case 0: /* WSS Master Control */ + if (val & 0x80) + ad1848_init(&dev->ad1848, dev->ad1848_type); + val = 0x00; + break; + + case 1: /* Version / Chip ID */ + case 7: /* Reserved */ + case 9 ... 15: /* unspecified */ + return; + + case 2: /* 3D Space and {Center|Volume} */ + case 6: /* Upper Channel Status */ + if (dev->type < CRYSTAL_CS4237B) + return; + break; + + case 3: /* 3D Enable */ + if (dev->type < CRYSTAL_CS4237B) + return; + val &= 0xe0; + break; + + case 4: /* Consumer Serial Port Enable */ + if (dev->type < CRYSTAL_CS4237B) + return; + val &= 0xf0; + break; + + case 5: /* Lower Channel Status */ + if (dev->type < CRYSTAL_CS4237B) + return; + val &= 0xfe; + break; + + case 8: /* CS9236 Wavetable Control */ + val &= 0x0f; + cs423x_pnp_enable(dev, 0, 0); + + /* Update WTEN state on the WSS codec. */ + dev->ad1848.wten = !!(val & 0x08); + ad1848_updatevolmask(&dev->ad1848); + break; + } + dev->indirect_regs[dev->regs[3]] = val; + break; + + case 5: /* Control/RAM Access */ + switch (dev->ram_dl) { + case 0: /* commands */ + switch (val) { + case 0x55: /* Disable PnP Key */ + dev->pnp_enable = 0; + /* fall-through */ + + case 0x5a: /* Update Hardware Configuration Data */ + cs423x_pnp_enable(dev, 0, 1); + break; + + case 0x56: /* Disable Crystal Key */ + cs423x_slam_enable(dev, 0); + break; + + case 0x57: /* Jump to ROM */ + break; + + case 0xaa: /* Download RAM */ + dev->ram_dl = 1; + break; + } + break; + + case 1: /* low address byte */ + dev->ram_addr = val; + dev->ram_dl++; + break; + + case 2: /* high address byte */ + dev->ram_addr |= (val << 8); + dev->ram_dl++; + break; + + case 3: /* data */ + dev->ram_data[dev->ram_addr++] = val; + break; + } + break; + + case 6: /* RAM Access End */ + /* TriGem Delhi-III BIOS writes undocumented value 0x40 instead of 0x00. */ + if ((val == 0x00) || (val == 0x40)) { + dev->ram_dl = 0; + + /* Update PnP state and resource data. */ + cs423x_pnp_enable(dev, 1, 0); + } + break; + + case 7: /* Global Status */ + return; + } + + dev->regs[reg] = val; +} + +static void +cs423x_slam_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t idx; + + switch (dev->slam_state) { + case CRYSTAL_SLAM_NONE: + /* Not in SLAM: read and compare Crystal key. */ + if (val == slam_init_key[dev->key_pos]) { + dev->key_pos++; + /* Was the key successfully written? */ + if (!dev->key_pos) { + /* Discard any pending logical device configuration, just to be safe. */ + if (dev->slam_config) { + free(dev->slam_config); + dev->slam_config = NULL; + } + + /* Enter SLAM. */ + dev->slam_state = CRYSTAL_SLAM_INDEX; + } + } else { + dev->key_pos = 0; + } + break; + + case CRYSTAL_SLAM_INDEX: + /* Intercept the Activate Audio Device command. */ + if (val == 0x79) { + /* Apply the last logical device's configuration. */ + if (dev->slam_config) { + cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); + free(dev->slam_config); + dev->slam_config = NULL; + } + + /* Exit out of SLAM. */ + dev->slam_state = CRYSTAL_SLAM_NONE; + break; + } + + /* Write register index. */ + dev->slam_reg = val; + dev->slam_state = CRYSTAL_SLAM_BYTE1; + break; + + case CRYSTAL_SLAM_BYTE1: + case CRYSTAL_SLAM_BYTE2: + /* Write register value: two bytes for I/O ports, single byte otherwise. */ + switch (dev->slam_reg) { + case 0x06: /* Card Select Number */ + isapnp_set_csn(dev->pnp_card, val); + break; + + case 0x15: /* Logical Device ID */ + /* Apply the previous logical device's configuration, and reuse its config structure. */ + if (dev->slam_config) + cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); + else + dev->slam_config = (isapnp_device_config_t *) malloc(sizeof(isapnp_device_config_t)); + + /* Start new logical device. */ + memset(dev->slam_config, 0, sizeof(isapnp_device_config_t)); + dev->slam_ld = val; + break; + + case 0x47: /* I/O Port Base Address 0 */ + case 0x48: /* I/O Port Base Address 1 */ + case 0x42: /* I/O Port Base Address 2 */ + idx = (dev->slam_reg == 0x42) ? 2 : (dev->slam_reg - 0x47); + if (dev->slam_state == CRYSTAL_SLAM_BYTE1) { + /* Set high byte, or ignore it if no logical device is selected. */ + if (dev->slam_config) + dev->slam_config->io[idx].base = val << 8; + + /* Prepare for the second (low byte) write. */ + dev->slam_state = CRYSTAL_SLAM_BYTE2; + return; + } else if (dev->slam_config) { + /* Set low byte, or ignore it if no logical device is selected. */ + dev->slam_config->io[idx].base |= val; + } + break; + + case 0x22: /* Interrupt Select 0 */ + case 0x27: /* Interrupt Select 1 */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Set IRQ value. */ + idx = (dev->slam_reg == 0x22) ? 0 : 1; + dev->slam_config->irq[idx].irq = val & 15; + break; + + case 0x2a: /* DMA Select 0 */ + case 0x25: /* DMA Select 1 */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Set DMA value. */ + idx = (dev->slam_reg == 0x2a) ? 0 : 1; + dev->slam_config->dma[idx].dma = val & 7; + break; + + case 0x33: /* Activate Device */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Activate or deactivate the device. */ + dev->slam_config->activate = val & 0x01; + break; + } + + /* Prepare for the next register, unless a two-byte read returns above. */ + dev->slam_state = CRYSTAL_SLAM_INDEX; + break; + } +} + +static void +cs423x_slam_enable(cs423x_t *dev, uint8_t enable) +{ + /* Disable SLAM. */ + if (dev->slam_enable) { + dev->slam_state = CRYSTAL_SLAM_NONE; + dev->slam_enable = 0; + io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } + + /* Enable SLAM if the CKD bit is not set. */ + if (enable && !(dev->ram_data[0x4002] & 0x10)) { + dev->slam_enable = 1; + io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } +} + +static void +cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t ctx = (dev->regs[7] & 0x80), + enable_opl = (dev->ad1848.xregs[4] & 0x10) && !(dev->indirect_regs[2] & 0x85); + + /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being written. */ + if ((dev->regs[7] & 0x80) ? ((addr & 0xfff0) == dev->sb_base) : ((addr & 0xfffc) == dev->wss_base)) { + /* Flip context bit. */ + dev->regs[7] ^= 0x80; + ctx ^= 0x80; + + /* Update CD audio filter. + FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ + sound_set_cd_audio_filter(NULL, NULL); + if (ctx) /* WSS */ + sound_set_cd_audio_filter(ad1848_filter_cd_audio, &dev->ad1848); + else /* SBPro */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); + + /* Fire a context switch interrupt if enabled. */ + if ((dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { + dev->regs[7] |= 0x40; /* set interrupt flag */ + picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ + } + } + + /* Update OPL ownership and state regardless of context switch, + to trap writes to other registers which may disable the OPL. */ + dev->sb->opl_enabled = !ctx && enable_opl; + dev->opl_wss = ctx && enable_opl; +} + +static void +cs423x_get_buffer(int32_t *buffer, int len, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + int c, opl_wss = dev->opl_wss; + int32_t *opl_buf = NULL; + + /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ + ad1848_update(&dev->ad1848); + if (opl_wss) + opl_buf = dev->sb->opl.update(dev->sb->opl.priv); + + /* Don't output anything if the analog section is powered down. */ + if (!(dev->indirect_regs[2] & 0xa4)) { + for (c = 0; c < len * 2; c += 2) { + if (opl_wss) { + buffer[c] += (opl_buf[c] * dev->ad1848.fm_vol_l) >> 16; + buffer[c + 1] += (opl_buf[c + 1] * dev->ad1848.fm_vol_r) >> 16; + } + + buffer[c] += dev->ad1848.buffer[c] / 2; + buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; + } + } + + dev->ad1848.pos = 0; + if (opl_wss) + dev->sb->opl.reset_buffer(dev->sb->opl.priv); +} + +static void +cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) +{ + if (dev->pnp_card) { + /* Update PnP resource data if requested. */ + if (update_rom) + isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], 384); + + /* Disable PnP key if the PKD bit is set, or if it was disabled by command 0x55. */ + /* But wait! The TriGem Delhi-III BIOS sends command 0x55, and its behavior doesn't + line up with real hardware (still listed in the POST summary and seen by software). + Disable the PnP key disabling mechanism until someone figures something out. */ + // isapnp_enable_card(dev->pnp_card, ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable) ? ISAPNP_CARD_NO_KEY : ISAPNP_CARD_ENABLE); + if ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable) + pclog("CS423x: Attempted to disable PnP key\n"); + } + + /* Update some register bits based on the config data in RAM if requested. */ + if (update_hwconfig) { + /* Update WTEN. */ + if (dev->ram_data[0x4003] & 0x08) { + dev->indirect_regs[8] |= 0x08; + dev->ad1848.wten = 1; + } else { + dev->indirect_regs[8] &= ~0x08; + dev->ad1848.wten = 0; + } + + /* Update SPS. */ + if (dev->type != CRYSTAL_CS4235) { + if (dev->ram_data[0x4003] & 0x04) + dev->indirect_regs[8] |= 0x04; + else + dev->indirect_regs[8] &= ~0x04; + } + + /* Update IFM. */ + if (dev->ram_data[0x4003] & 0x80) + dev->ad1848.xregs[4] |= 0x10; + else + dev->ad1848.xregs[4] &= ~0x10; + + /* Inform WSS codec of the changes. */ + ad1848_updatevolmask(&dev->ad1848); + } +} + +static void +cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + switch (ld) { + case 0: /* WSS, OPL3 and SBPro */ + if (dev->wss_base) { + io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_removehandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->wss_base = 0; + } + + if (dev->opl_base) { + io_removehandler(dev->opl_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + dev->opl_base = 0; + } + + if (dev->sb_base) { + sb_dsp_setaddr(&dev->sb->dsp, 0); + io_removehandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + io_removehandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->sb_base = 0; + } + + ad1848_setirq(&dev->ad1848, 0); + sb_dsp_setirq(&dev->sb->dsp, 0); + + ad1848_setdma(&dev->ad1848, 0); + sb_dsp_setdma8(&dev->sb->dsp, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) { + dev->wss_base = config->io[0].base; + io_sethandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_sethandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + } + + if (config->io[1].base != ISAPNP_IO_DISABLED) { + dev->opl_base = config->io[1].base; + io_sethandler(dev->opl_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + } + + if (config->io[2].base != ISAPNP_IO_DISABLED) { + dev->sb_base = config->io[2].base; + sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); + io_sethandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + io_sethandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + } + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { + ad1848_setirq(&dev->ad1848, config->irq[0].irq); + sb_dsp_setirq(&dev->sb->dsp, config->irq[0].irq); + } + + if (config->dma[0].dma != ISAPNP_DMA_DISABLED) { + ad1848_setdma(&dev->ad1848, config->dma[0].dma); + sb_dsp_setdma8(&dev->sb->dsp, config->dma[0].dma); + } + } + break; + + case 1: /* Game Port */ + if (dev->gameport) + gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; + + case 2: /* Control Registers */ + if (dev->ctrl_base) { + io_removehandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); + dev->ctrl_base = 0; + } + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + dev->ctrl_base = config->io[0].base; + io_sethandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); + } + + break; + + case 3: /* MPU-401 */ + mpu401_change_addr(dev->sb->mpu, 0); + mpu401_setirq(dev->sb->mpu, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) + mpu401_change_addr(dev->sb->mpu, config->io[0].base); + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) + mpu401_setirq(dev->sb->mpu, config->irq[0].irq); + } + + break; + } +} + +static void +cs423x_reset(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + /* Clear RAM. */ + memset(dev->ram_data, 0, sizeof(dev->ram_data)); + + if (dev->eeprom) { + /* Load EEPROM data to RAM. */ + memcpy(&dev->ram_data[0x4000], &dev->eeprom_data[4], MIN(384, ((dev->eeprom_data[2] << 8) | dev->eeprom_data[3]) - 4)); + + /* Save EEPROM contents to file. */ + cs423x_nvram(dev, 1); + } + + /* Reset registers. */ + memset(dev->regs, 0, sizeof(dev->regs)); + dev->regs[1] = 0x80; + memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); + dev->indirect_regs[1] = dev->type; + if (dev->type == CRYSTAL_CS4238B) + dev->indirect_regs[2] = 0x20; + + /* Reset WSS codec. */ + ad1848_init(&dev->ad1848, dev->ad1848_type); + + /* Reset PnP resource data, state and logical devices. */ + dev->pnp_enable = 1; + cs423x_pnp_enable(dev, 1, 1); + if (dev->pnp_card && dev->sb) + isapnp_reset_card(dev->pnp_card); + + /* Reset SLAM. */ + cs423x_slam_enable(dev, 1); +} + +static void * +cs423x_init(const device_t *info) +{ + cs423x_t *dev = malloc(sizeof(cs423x_t)); + memset(dev, 0, sizeof(cs423x_t)); + + /* Initialize model-specific data. */ + dev->type = info->local & 0xff; + switch (dev->type) { + case CRYSTAL_CS4235: + case CRYSTAL_CS4236B: + case CRYSTAL_CS4237B: + case CRYSTAL_CS4238B: + /* Same WSS codec and EEPROM structure. */ + dev->ad1848_type = (dev->type == CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236; + dev->pnp_offset = 0x4013; + + /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */ + dev->ad1848.xregs[25] = dev->type; + + if (!(info->local & CRYSTAL_NOEEPROM)) { + /* Load EEPROM contents from template. */ + memcpy(dev->eeprom_data, cs4236b_eeprom, sizeof(cs4236b_eeprom)); + + /* Set content size. */ + dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8; + dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff; + + /* Set PnP card ID and EEPROM file name. */ + switch (dev->type) { + case CRYSTAL_CS4235: + dev->eeprom_data[8] = 0x05; + dev->eeprom_data[16] = 0x08; + dev->eeprom_data[26] = 0x25; + dev->nvr_path = "cs4235.nvr"; + break; + + case CRYSTAL_CS4236B: + dev->nvr_path = "cs4236b.nvr"; + break; + + case CRYSTAL_CS4237B: + dev->eeprom_data[26] = 0x37; + dev->nvr_path = "cs4237b.nvr"; + break; + + case CRYSTAL_CS4238B: + dev->eeprom_data[26] = 0x38; + dev->nvr_path = "cs4238b.nvr"; + break; + } + + /* Load EEPROM contents from file if present. */ + cs423x_nvram(dev, 0); + } + + /* Initialize game port. The '7B and '8B game port only responds to 6 I/O ports; the remaining + 2 ports are reserved on those chips, and probably connected to the Digital Assist feature. */ + dev->gameport = gameport_add(((dev->type == CRYSTAL_CS4235) || (dev->type == CRYSTAL_CS4236B)) ? &gameport_pnp_device : &gameport_pnp_6io_device); + + break; + } + + /* Initialize I2C bus for the EEPROM. */ + dev->i2c = i2c_gpio_init("nvr_cs423x"); + + /* Initialize I2C EEPROM if the contents are valid. */ + if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb)) + dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); + + /* Initialize ISAPnP. */ + dev->pnp_card = isapnp_add_card(NULL, 0, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + + /* Initialize SBPro codec. The WSS codec is initialized later by cs423x_reset */ + dev->sb = device_add_inst(&sb_pro_compat_device, 1); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); /* CD audio filter for the default context */ + + /* Initialize RAM, registers and WSS codec. */ + cs423x_reset(dev); + sound_add_handler(cs423x_get_buffer, dev); + + /* Add Control/RAM backdoor handlers for CS4235. */ + dev->ad1848.cram_priv = dev; + dev->ad1848.cram_read = cs423x_read; + dev->ad1848.cram_write = cs423x_write; + + return dev; +} + +static void +cs423x_close(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + /* Save EEPROM contents to file. */ + if (dev->eeprom) { + cs423x_nvram(dev, 1); + i2c_eeprom_close(dev->eeprom); + } + + i2c_gpio_close(dev->i2c); + + free(dev); +} + +static void +cs423x_speed_changed(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + ad1848_speed_changed(&dev->ad1848); +} + +const device_t cs4235_device = { + .name = "Crystal CS4235", + .internal_name = "cs4235", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4235, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + { .available = NULL }, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t cs4235_onboard_device = { + .name = "Crystal CS4235 (On-Board)", + .internal_name = "cs4235_onboard", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4235 | CRYSTAL_NOEEPROM, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + { .available = NULL }, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t cs4236b_device = { + .name = "Crystal CS4236B", + .internal_name = "cs4236b", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4236B, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + { .available = NULL }, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t cs4237b_device = { + .name = "Crystal CS4237B", + .internal_name = "cs4237b", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4237B, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + { .available = NULL }, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t cs4238b_device = { + .name = "Crystal CS4238B", + .internal_name = "cs4238b", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4238B, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + { .available = NULL }, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index 70465f121..33e80fb31 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -1,120 +1,120 @@ #include #include -#include #include -#include +#include #include +#include #include #define _USE_MATH_DEFINES #include #define HAVE_STDARG_H + #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> #include <86box/rom.h> -#include <86box/timer.h> #include <86box/sound.h> #include <86box/snd_emu8k.h> - +#include <86box/timer.h> #if !defined FILTER_INITIAL && !defined FILTER_MOOG && !defined FILTER_CONSTANT //#define FILTER_INITIAL -#define FILTER_MOOG +# define FILTER_MOOG //#define FILTER_CONSTANT #endif #if !defined RESAMPLER_LINEAR && !defined RESAMPLER_CUBIC //#define RESAMPLER_LINEAR -#define RESAMPLER_CUBIC +# define RESAMPLER_CUBIC #endif //#define EMU8K_DEBUG_REGISTERS -char *PORT_NAMES[][8] = -{ - /* Data 0 ( 0x620/0x622) */ - { "AWE_CPF", - "AWE_PTRX", - "AWE_CVCF", - "AWE_VTFT", - "Unk-620-4", - "Unk-620-5", - "AWE_PSST", - "AWE_CSL", - }, - /* Data 1 0xA20 */ - { "AWE_CCCA", - 0, - /* - "AWE_HWCF4" - "AWE_HWCF5" - "AWE_HWCF6" - "AWE_HWCF7" - "AWE_SMALR" - "AWE_SMARR" - "AWE_SMALW" - "AWE_SMARW" - "AWE_SMLD" - "AWE_SMRD" - "AWE_WC" - "AWE_HWCF1" - "AWE_HWCF2" - "AWE_HWCF3" - */ - 0,//"AWE_INIT1", - 0,//"AWE_INIT3", - "AWE_ENVVOL", - "AWE_DCYSUSV", - "AWE_ENVVAL", - "AWE_DCYSUS", - }, - /* Data 2 0xA22 */ - { "AWE_CCCA", - 0, - 0,//"AWE_INIT2", - 0,//"AWE_INIT4", - "AWE_ATKHLDV", - "AWE_LFO1VAL", - "AWE_ATKHLD", - "AWE_LFO2VAL", - }, - /* Data 3 0xE20 */ - { "AWE_IP", - "AWE_IFATN", - "AWE_PEFE", - "AWE_FMMOD", - "AWE_TREMFRQ", - "AWE_FM2FRQ2", - 0, - 0, - }, +char *PORT_NAMES[][8] = { + /* Data 0 ( 0x620/0x622) */ + { + "AWE_CPF", + "AWE_PTRX", + "AWE_CVCF", + "AWE_VTFT", + "Unk-620-4", + "Unk-620-5", + "AWE_PSST", + "AWE_CSL", + }, + /* Data 1 0xA20 */ + { + "AWE_CCCA", + 0, + /* + "AWE_HWCF4" + "AWE_HWCF5" + "AWE_HWCF6" + "AWE_HWCF7" + "AWE_SMALR" + "AWE_SMARR" + "AWE_SMALW" + "AWE_SMARW" + "AWE_SMLD" + "AWE_SMRD" + "AWE_WC" + "AWE_HWCF1" + "AWE_HWCF2" + "AWE_HWCF3" + */ + 0, //"AWE_INIT1", + 0, //"AWE_INIT3", + "AWE_ENVVOL", + "AWE_DCYSUSV", + "AWE_ENVVAL", + "AWE_DCYSUS", + }, + /* Data 2 0xA22 */ + { + "AWE_CCCA", + 0, + 0, //"AWE_INIT2", + 0, //"AWE_INIT4", + "AWE_ATKHLDV", + "AWE_LFO1VAL", + "AWE_ATKHLD", + "AWE_LFO2VAL", + }, + /* Data 3 0xE20 */ + { + "AWE_IP", + "AWE_IFATN", + "AWE_PEFE", + "AWE_FMMOD", + "AWE_TREMFRQ", + "AWE_FM2FRQ2", + 0, + 0, + }, }; -enum -{ - ENV_STOPPED = 0, - ENV_DELAY = 1, - ENV_ATTACK = 2, - ENV_HOLD = 3, - //ENV_DECAY = 4, - ENV_SUSTAIN = 5, - //ENV_RELEASE = 6, - ENV_RAMP_DOWN = 7, - ENV_RAMP_UP = 8 +enum { + ENV_STOPPED = 0, + ENV_DELAY = 1, + ENV_ATTACK = 2, + ENV_HOLD = 3, + // ENV_DECAY = 4, + ENV_SUSTAIN = 5, + // ENV_RELEASE = 6, + ENV_RAMP_DOWN = 7, + ENV_RAMP_UP = 8 }; - static int random_helper = 0; -int dmareadbit = 0; -int dmawritebit = 0; - +int dmareadbit = 0; +int dmawritebit = 0; /* cubic and linear tables resolution. Note: higher than 10 does not improve the result. */ #define CUBIC_RESOLUTION_LOG 10 -#define CUBIC_RESOLUTION (1<> 15 to move back to +/-1 range). */ static double chortable[65536]; -static const int REV_BUFSIZE_STEP=242; - +static const int REV_BUFSIZE_STEP = 242; /* These lines come from the awe32faq, describing the NRPN control for the initial filter * where it describes a linear increment filter instead of an octave-incremented one. @@ -188,9 +188,9 @@ static const int REV_BUFSIZE_STEP=242; * Filter cutoff from 100Hz to 8000Hz * This table comes from the awe32faq, describing the NRPN control for the filter Q. - * I don't know if is meant to be interpreted as the actual measured output of the + * I don't know if is meant to be interpreted as the actual measured output of the * filter or what. Especially, I don't understand the "low" and "high" ranges. - * What is otherwise documented is that the Q ranges from 0dB to 24dB and the attenuation + * What is otherwise documented is that the Q ranges from 0dB to 24dB and the attenuation * is half of the Q ( i.e. for 12dB Q, attenuate the input signal with -6dB) Coeff Low Fc(Hz)Low Q(dB)High Fc(kHz)High Q(dB)DC Attenuation(dB) * 0 92 5 Flat Flat -0.0 @@ -211,2178 +211,2078 @@ Coeff Low Fc(Hz)Low Q(dB)High Fc(kHz)High Q(dB)DC Attenuation(dB) * 15 100 28 7.0 18 -11.0 * * Attenuation as above, codified in amplitude.*/ -static int32_t filter_atten[16] = -{ +static int32_t filter_atten[16] = { 65536, 61869, 57079, 53269, 49145, 44820, 40877, 34792, 32845, 30653, 28607, - 26392, 24630, 22463, 20487, 18470 + 26392, 24630, 22463, 20487, 18470 }; /*Coefficients for the filters for a defined Q and cutoff.*/ static int32_t filt_coeffs[16][256][3]; -#define READ16_SWITCH(addr, var) switch ((addr) & 2) \ - { \ - case 0: ret = (var) & 0xffff; break; \ - case 2: ret = ((var) >> 16) & 0xffff; break; \ - } - -#define WRITE16_SWITCH(addr, var, val) switch ((addr) & 2) \ - { \ - case 0: var = (var & 0xffff0000) | (val); break; \ - case 2: var = (var & 0x0000ffff) | ((val) << 16); break; \ - } +#define READ16_SWITCH(addr, var) \ + switch ((addr) &2) { \ + case 0: \ + ret = (var) &0xffff; \ + break; \ + case 2: \ + ret = ((var) >> 16) & 0xffff; \ + break; \ + } + +#define WRITE16_SWITCH(addr, var, val) \ + switch ((addr) &2) { \ + case 0: \ + var = (var & 0xffff0000) | (val); \ + break; \ + case 2: \ + var = (var & 0x0000ffff) | ((val) << 16); \ + break; \ + } #ifdef EMU8K_DEBUG_REGISTERS -uint32_t dw_value = 0; -uint32_t last_read = 0; -uint32_t last_write = 0; +uint32_t dw_value = 0; +uint32_t last_read = 0; +uint32_t last_write = 0; uint32_t rep_count_r = 0; uint32_t rep_count_w = 0; -# define READ16(addr, var) READ16_SWITCH(addr, var) \ - { \ - const char *name=0; \ - switch(addr&0xF02) \ - { \ - case 0x600: case 0x602: \ - name = PORT_NAMES[0][emu8k->cur_reg]; \ - break; \ - case 0xA00: \ - name = PORT_NAMES[1][emu8k->cur_reg]; \ - break; \ - case 0xA02: \ - name = PORT_NAMES[2][emu8k->cur_reg]; \ - break; \ - } \ - if (name == 0) \ - { \ - /*emu8k_log("EMU8K READ %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_voice,ret);*/ \ - } \ - else \ - { \ - emu8k_log("EMU8K READ %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice, ret); \ - }\ - } -# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) \ - { \ - const char *name=0; \ - switch(addr&0xF02) \ - { \ - case 0x600: case 0x602: \ - name = PORT_NAMES[0][emu8k->cur_reg]; \ - break; \ - case 0xA00: \ - name = PORT_NAMES[1][emu8k->cur_reg]; \ - break; \ - case 0xA02: \ - name = PORT_NAMES[2][emu8k->cur_reg]; \ - break; \ - } \ - if (name == 0) \ - { \ - /*emu8k_log("EMU8K WRITE %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_voice, val);*/ \ - } \ - else \ - { \ - emu8k_log("EMU8K WRITE %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice,val); \ - }\ - } +# define READ16(addr, var) \ + READ16_SWITCH(addr, var) \ + { \ + const char *name = 0; \ + switch (addr & 0xF02) { \ + case 0x600: \ + case 0x602: \ + name = PORT_NAMES[0][emu8k->cur_reg]; \ + break; \ + case 0xA00: \ + name = PORT_NAMES[1][emu8k->cur_reg]; \ + break; \ + case 0xA02: \ + name = PORT_NAMES[2][emu8k->cur_reg]; \ + break; \ + } \ + if (name == 0) { \ + /*emu8k_log("EMU8K READ %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_voice,ret);*/ \ + } else { \ + emu8k_log("EMU8K READ %s(%d) (%d): %04X\n", name, (addr & 0x2), emu8k->cur_voice, ret); \ + } \ + } +# define WRITE16(addr, var, val) \ + WRITE16_SWITCH(addr, var, val) \ + { \ + const char *name = 0; \ + switch (addr & 0xF02) { \ + case 0x600: \ + case 0x602: \ + name = PORT_NAMES[0][emu8k->cur_reg]; \ + break; \ + case 0xA00: \ + name = PORT_NAMES[1][emu8k->cur_reg]; \ + break; \ + case 0xA02: \ + name = PORT_NAMES[2][emu8k->cur_reg]; \ + break; \ + } \ + if (name == 0) { \ + /*emu8k_log("EMU8K WRITE %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_voice, val);*/ \ + } else { \ + emu8k_log("EMU8K WRITE %s(%d) (%d): %04X\n", name, (addr & 0x2), emu8k->cur_voice, val); \ + } \ + } #else -# define READ16(addr, var) READ16_SWITCH(addr, var) -# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) -#endif //EMU8K_DEBUG_REGISTERS - +# define READ16(addr, var) READ16_SWITCH(addr, var) +# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) +#endif // EMU8K_DEBUG_REGISTERS #ifdef ENABLE_EMU8K_LOG int emu8k_do_log = ENABLE_EMU8K_LOG; - static void emu8k_log(const char *fmt, ...) { va_list ap; if (emu8k_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define emu8k_log(fmt, ...) +# define emu8k_log(fmt, ...) #endif - -static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) +static inline int16_t +EMU8K_READ(emu8k_t *emu8k, uint32_t addr) { - const register emu8k_mem_pointers_t addrmem = {{addr}}; - return emu8k->ram_pointers[addrmem.hb_address][addrmem.lw_address]; + const register emu8k_mem_pointers_t addrmem = { { addr } }; + return emu8k->ram_pointers[addrmem.hb_address][addrmem.lw_address]; } #if NOTUSED -static inline int16_t EMU8K_READ_INTERP_LINEAR(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) +static inline int16_t +EMU8K_READ_INTERP_LINEAR(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) { - /* The interpolation in AWE32 used a so-called patented 3-point interpolation - * ( I guess some sort of spline having one point before and one point after). - * Also, it has the consequence that the playback is delayed by one sample. - * I simulate the "one sample later" than the address with addr+1 and addr+2 - * instead of +0 and +1 */ - int16_t dat1 = EMU8K_READ(emu8k, int_addr+1); - int32_t dat2 = EMU8K_READ(emu8k, int_addr+2); - dat1 += ((dat2-(int32_t)dat1)* fract) >> 16; - return dat1; + /* The interpolation in AWE32 used a so-called patented 3-point interpolation + * ( I guess some sort of spline having one point before and one point after). + * Also, it has the consequence that the playback is delayed by one sample. + * I simulate the "one sample later" than the address with addr+1 and addr+2 + * instead of +0 and +1 */ + int16_t dat1 = EMU8K_READ(emu8k, int_addr + 1); + int32_t dat2 = EMU8K_READ(emu8k, int_addr + 2); + dat1 += ((dat2 - (int32_t) dat1) * fract) >> 16; + return dat1; } #endif -static inline int32_t EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) +static inline int32_t +EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) { - /*Since there are four floats in the table for each fraction, the position is 16byte aligned. */ - fract >>= 16-CUBIC_RESOLUTION_LOG; - fract <<=2; + /*Since there are four floats in the table for each fraction, the position is 16byte aligned. */ + fract >>= 16 - CUBIC_RESOLUTION_LOG; + fract <<= 2; - /* TODO: I still have to verify how this works, but I think that - * the card could use two oscillators (usually 31 and 32) where it would - * be writing the OPL3 output, and to which, chorus and reverb could be applied to get - * those effects for OPL3 sounds.*/ -// if ((addr & EMU8K_FM_MEM_ADDRESS) == EMU8K_FM_MEM_ADDRESS) {} + /* TODO: I still have to verify how this works, but I think that + * the card could use two oscillators (usually 31 and 32) where it would + * be writing the OPL3 output, and to which, chorus and reverb could be applied to get + * those effects for OPL3 sounds.*/ + // if ((addr & EMU8K_FM_MEM_ADDRESS) == EMU8K_FM_MEM_ADDRESS) {} - /* This is cubic interpolation. - * Not the same than 3-point interpolation, but a better approximation than linear - * interpolation. - * Also, it takes into account the "Note that the actual audio location is the point - * 1 word higher than this value due to interpolation offset". - * That's why the pointers are 0, 1, 2, 3 and not -1, 0, 1, 2 */ - int32_t dat2 = EMU8K_READ(emu8k, int_addr+1); - const float *table = &cubic_table[fract]; - const int32_t dat1 = EMU8K_READ(emu8k, int_addr); - const int32_t dat3 = EMU8K_READ(emu8k, int_addr+2); - const int32_t dat4 = EMU8K_READ(emu8k, int_addr+3); - /* Note: I've ended using float for the table values to avoid some cases of integer overflow. */ - dat2 = dat1*table[0] + dat2*table[1] + dat3*table[2] + dat4*table[3]; - return dat2; + /* This is cubic interpolation. + * Not the same than 3-point interpolation, but a better approximation than linear + * interpolation. + * Also, it takes into account the "Note that the actual audio location is the point + * 1 word higher than this value due to interpolation offset". + * That's why the pointers are 0, 1, 2, 3 and not -1, 0, 1, 2 */ + int32_t dat2 = EMU8K_READ(emu8k, int_addr + 1); + const float *table = &cubic_table[fract]; + const int32_t dat1 = EMU8K_READ(emu8k, int_addr); + const int32_t dat3 = EMU8K_READ(emu8k, int_addr + 2); + const int32_t dat4 = EMU8K_READ(emu8k, int_addr + 3); + /* Note: I've ended using float for the table values to avoid some cases of integer overflow. */ + dat2 = dat1 * table[0] + dat2 * table[1] + dat3 * table[2] + dat4 * table[3]; + return dat2; } -static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val) +static inline void +EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val) { - addr &= EMU8K_MEM_ADDRESS_MASK; - if ( !emu8k->ram || addr < EMU8K_RAM_MEM_START || addr >= EMU8K_FM_MEM_ADDRESS ) - return; + addr &= EMU8K_MEM_ADDRESS_MASK; + if (!emu8k->ram || addr < EMU8K_RAM_MEM_START || addr >= EMU8K_FM_MEM_ADDRESS) + return; - /* It looks like if an application writes to a memory part outside of the available - * amount on the card, it wraps, and opencubicplayer uses that to detect the amount - * of memory, as opposed to simply check at the address that it has just tried to write. */ - while (addr >= emu8k->ram_end_addr) - addr -= emu8k->ram_end_addr - EMU8K_RAM_MEM_START; + /* It looks like if an application writes to a memory part outside of the available + * amount on the card, it wraps, and opencubicplayer uses that to detect the amount + * of memory, as opposed to simply check at the address that it has just tried to write. */ + while (addr >= emu8k->ram_end_addr) + addr -= emu8k->ram_end_addr - EMU8K_RAM_MEM_START; - emu8k->ram[addr - EMU8K_RAM_MEM_START] = val; + emu8k->ram[addr - EMU8K_RAM_MEM_START] = val; } -uint16_t emu8k_inw(uint16_t addr, void *p) +uint16_t +emu8k_inw(uint16_t addr, void *p) { - emu8k_t *emu8k = (emu8k_t *)p; - uint16_t ret = 0xffff; - + emu8k_t *emu8k = (emu8k_t *) p; + uint16_t ret = 0xffff; + #ifdef EMU8K_DEBUG_REGISTERS - if (addr == 0xE22) - { - emu8k_log("EMU8K READ POINTER: %d\n", - ((0x80 | ((random_helper + 1) & 0x1F)) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice); + if (addr == 0xE22) { + emu8k_log("EMU8K READ POINTER: %d\n", + ((0x80 | ((random_helper + 1) & 0x1F)) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice); + } else if ((addr & 0xF00) == 0x600) { + /* These are automatically reported by READ16 */ + if (rep_count_r > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r = 0; } - else if ((addr&0xF00) == 0x600) - { - /* These are automatically reported by READ16 */ - if (rep_count_r>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_r); - rep_count_r=0; + last_read = 0; + } else if ((addr & 0xF00) == 0xA00 && emu8k->cur_reg == 0) { + /* These are automatically reported by READ16 */ + if (rep_count_r > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r = 0; + } + last_read = 0; + } else if ((addr & 0xF00) == 0xA00 && emu8k->cur_reg == 1) { + uint32_t tmpz = ((addr & 0xF00) << 16) | (emu8k->cur_reg << 5); + if (tmpz != last_read) { + if (rep_count_r > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r = 0; + } + last_read = tmpz; + emu8k_log("EMU8K READ RAM I/O or configuration or clock \n"); + } + // emu8k_log("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + } else if ((addr & 0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) { + uint32_t tmpz = ((addr & 0xF00) << 16); + if (tmpz != last_read) { + if (rep_count_r > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r = 0; + } + last_read = tmpz; + emu8k_log("EMU8K READ INIT \n"); + } + // emu8k_log("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + } else { + uint32_t tmpz = (addr << 16) | (emu8k->cur_reg << 5) | emu8k->cur_voice; + if (tmpz != last_read) { + char *name = 0; + uint16_t val = 0xBAAD; + if (addr == 0xA20) { + name = PORT_NAMES[1][emu8k->cur_reg]; + switch (emu8k->cur_reg) { + case 2: + val = emu8k->init1[emu8k->cur_voice]; + break; + case 3: + val = emu8k->init3[emu8k->cur_voice]; + break; + case 4: + val = emu8k->voice[emu8k->cur_voice].envvol; + break; + case 5: + val = emu8k->voice[emu8k->cur_voice].dcysusv; + break; + case 6: + val = emu8k->voice[emu8k->cur_voice].envval; + break; + case 7: + val = emu8k->voice[emu8k->cur_voice].dcysus; + break; } - last_read=0; - } - else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 0) - { - /* These are automatically reported by READ16 */ - if (rep_count_r>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_r); - rep_count_r=0; + } else if (addr == 0xA22) { + name = PORT_NAMES[2][emu8k->cur_reg]; + switch (emu8k->cur_reg) { + case 2: + val = emu8k->init2[emu8k->cur_voice]; + break; + case 3: + val = emu8k->init4[emu8k->cur_voice]; + break; + case 4: + val = emu8k->voice[emu8k->cur_voice].atkhldv; + break; + case 5: + val = emu8k->voice[emu8k->cur_voice].lfo1val; + break; + case 6: + val = emu8k->voice[emu8k->cur_voice].atkhld; + break; + case 7: + val = emu8k->voice[emu8k->cur_voice].lfo2val; + break; } - last_read=0; - } - else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 1) - { - uint32_t tmpz = ((addr&0xF00) << 16)|(emu8k->cur_reg<<5); - if (tmpz != last_read) - { - if (rep_count_r>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_r); - rep_count_r=0; - } - last_read=tmpz; - emu8k_log("EMU8K READ RAM I/O or configuration or clock \n"); + } else if (addr == 0xE20) { + name = PORT_NAMES[3][emu8k->cur_reg]; + switch (emu8k->cur_reg) { + case 0: + val = emu8k->voice[emu8k->cur_voice].ip; + break; + case 1: + val = emu8k->voice[emu8k->cur_voice].ifatn; + break; + case 2: + val = emu8k->voice[emu8k->cur_voice].pefe; + break; + case 3: + val = emu8k->voice[emu8k->cur_voice].fmmod; + break; + case 4: + val = emu8k->voice[emu8k->cur_voice].tremfrq; + break; + case 5: + val = emu8k->voice[emu8k->cur_voice].fm2frq2; + break; + case 6: + val = 0xffff; + break; + case 7: + val = 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); + break; } - //emu8k_log("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); - } - else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) - { - uint32_t tmpz = ((addr&0xF00) << 16); - if (tmpz != last_read) - { - if (rep_count_r>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_r); - rep_count_r=0; - } - last_read=tmpz; - emu8k_log("EMU8K READ INIT \n"); - } - //emu8k_log("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); - } - else - { - uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; - if (tmpz != last_read) - { - char* name = 0; - uint16_t val = 0xBAAD; - if (addr == 0xA20) - { - name = PORT_NAMES[1][emu8k->cur_reg]; - switch (emu8k->cur_reg) - { - case 2: val = emu8k->init1[emu8k->cur_voice]; break; - case 3: val = emu8k->init3[emu8k->cur_voice]; break; - case 4: val = emu8k->voice[emu8k->cur_voice].envvol; break; - case 5: val = emu8k->voice[emu8k->cur_voice].dcysusv; break; - case 6: val = emu8k->voice[emu8k->cur_voice].envval; break; - case 7: val = emu8k->voice[emu8k->cur_voice].dcysus; break; - } - } - else if (addr == 0xA22) - { - name = PORT_NAMES[2][emu8k->cur_reg]; - switch (emu8k->cur_reg) - { - case 2: val = emu8k->init2[emu8k->cur_voice]; break; - case 3: val = emu8k->init4[emu8k->cur_voice]; break; - case 4: val = emu8k->voice[emu8k->cur_voice].atkhldv; break; - case 5: val = emu8k->voice[emu8k->cur_voice].lfo1val; break; - case 6: val = emu8k->voice[emu8k->cur_voice].atkhld; break; - case 7: val = emu8k->voice[emu8k->cur_voice].lfo2val; break; - } - } - else if (addr == 0xE20) - { - name = PORT_NAMES[3][emu8k->cur_reg]; - switch (emu8k->cur_reg) - { - case 0: val = emu8k->voice[emu8k->cur_voice].ip; break; - case 1: val = emu8k->voice[emu8k->cur_voice].ifatn; break; - case 2: val = emu8k->voice[emu8k->cur_voice].pefe; break; - case 3: val = emu8k->voice[emu8k->cur_voice].fmmod; break; - case 4: val = emu8k->voice[emu8k->cur_voice].tremfrq; break; - case 5: val = emu8k->voice[emu8k->cur_voice].fm2frq2;break; - case 6: val = 0xffff; break; - case 7: val = 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); break; - } - } - if (rep_count_r>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_r); - } - if (name == 0) - { - emu8k_log("EMU8K READ %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice,val); - } - else - { - emu8k_log("EMU8K READ %s (%d): %04X\n",name,emu8k->cur_voice, val); - } + } + if (rep_count_r > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + } + if (name == 0) { + emu8k_log("EMU8K READ %04X-%02X(%d/%d): %04X\n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice, val); + } else { + emu8k_log("EMU8K READ %s (%d): %04X\n", name, emu8k->cur_voice, val); + } - rep_count_r=0; - last_read=tmpz; - } - rep_count_r++; + rep_count_r = 0; + last_read = tmpz; } + rep_count_r++; + } #endif // EMU8K_DEBUG_REGISTERS + switch (addr & 0xF02) { + case 0x600: + case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ + switch (emu8k->cur_reg) { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + return ret; - switch (addr & 0xF02) - { - case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ - switch (emu8k->cur_reg) - { - case 0: - READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); - return ret; - - case 1: - READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx); - return ret; - - case 2: - READ16(addr, emu8k->voice[emu8k->cur_voice].cvcf); - return ret; - - case 3: - READ16(addr, emu8k->voice[emu8k->cur_voice].vtft); - return ret; - - case 4: - READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4); - return ret; + case 1: + READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx); + return ret; - case 5: - READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5); - return ret; - - case 6: - READ16(addr, emu8k->voice[emu8k->cur_voice].psst); - return ret; - - case 7: - READ16(addr, emu8k->voice[emu8k->cur_voice].csl); - return ret; - } - break; + case 2: + READ16(addr, emu8k->voice[emu8k->cur_voice].cvcf); + return ret; - case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ - switch (emu8k->cur_reg) - { - case 0: - READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); - return ret; + case 3: + READ16(addr, emu8k->voice[emu8k->cur_voice].vtft); + return ret; - case 1: - switch (emu8k->cur_voice) - { - case 9: - READ16(addr, emu8k->hwcf4); - return ret; - case 10: - READ16(addr, emu8k->hwcf5); - return ret; - /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ - case 13: - READ16(addr, emu8k->hwcf6); - return ret; - case 14: - READ16(addr, emu8k->hwcf7); - return ret; - - case 20: - READ16(addr, emu8k->smalr); - return ret; - case 21: - READ16(addr, emu8k->smarr); - return ret; - case 22: - READ16(addr, emu8k->smalw); - return ret; - case 23: - READ16(addr, emu8k->smarw); - return ret; - - case 26: - { - uint16_t val = emu8k->smld_buffer; - emu8k->smld_buffer = EMU8K_READ(emu8k, emu8k->smalr); - emu8k->smalr = (emu8k->smalr+1) & EMU8K_MEM_ADDRESS_MASK; - return val; - } + case 4: + READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4); + return ret; - /*The EMU8000 PGM describes the return values of these registers as 'a VLSI error'*/ - case 29: /*Configuration Word 1*/ - return (emu8k->hwcf1 & 0xfe) | (emu8k->hwcf3 & 0x01); - case 30: /*Configuration Word 2*/ - return ((emu8k->hwcf2 >> 4) & 0x0e) | (emu8k->hwcf1 & 0x01) | ((emu8k->hwcf3 & 0x02) ? 0x10 : 0) | ((emu8k->hwcf3 & 0x04) ? 0x40 : 0) - | ((emu8k->hwcf3 & 0x08) ? 0x20 : 0) | ((emu8k->hwcf3 & 0x10) ? 0x80 : 0); - case 31: /*Configuration Word 3*/ - return emu8k->hwcf2 & 0x1f; - } - break; + case 5: + READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5); + return ret; - case 2: - return emu8k->init1[emu8k->cur_voice]; - - case 3: - return emu8k->init3[emu8k->cur_voice]; - - case 4: - return emu8k->voice[emu8k->cur_voice].envvol; + case 6: + READ16(addr, emu8k->voice[emu8k->cur_voice].psst); + return ret; - case 5: - return emu8k->voice[emu8k->cur_voice].dcysusv; - - case 6: - return emu8k->voice[emu8k->cur_voice].envval; + case 7: + READ16(addr, emu8k->voice[emu8k->cur_voice].csl); + return ret; + } + break; - case 7: - return emu8k->voice[emu8k->cur_voice].dcysus; - } - break; + case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ + switch (emu8k->cur_reg) { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; - case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ - switch (emu8k->cur_reg) - { - case 0: - READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); - return ret; + case 1: + switch (emu8k->cur_voice) { + case 9: + READ16(addr, emu8k->hwcf4); + return ret; + case 10: + READ16(addr, emu8k->hwcf5); + return ret; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ + case 13: + READ16(addr, emu8k->hwcf6); + return ret; + case 14: + READ16(addr, emu8k->hwcf7); + return ret; - case 1: - switch (emu8k->cur_voice) - { - case 9: - READ16(addr, emu8k->hwcf4); - return ret; - case 10: - READ16(addr, emu8k->hwcf5); - return ret; - /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ - case 13: - READ16(addr, emu8k->hwcf6); - return ret; - case 14: - READ16(addr, emu8k->hwcf7); - return ret; + case 20: + READ16(addr, emu8k->smalr); + return ret; + case 21: + READ16(addr, emu8k->smarr); + return ret; + case 22: + READ16(addr, emu8k->smalw); + return ret; + case 23: + READ16(addr, emu8k->smarw); + return ret; - /* Simulating empty/full bits by unsetting it once read. */ - case 20: - READ16(addr, emu8k->smalr|dmareadbit); - /* xor with itself to set to zero faster. */ - dmareadbit^=dmareadbit; - return ret; - case 21: - READ16(addr, emu8k->smarr|dmareadbit); - /* xor with itself to set to zero faster.*/ - dmareadbit^=dmareadbit; - return ret; - case 22: - READ16(addr, emu8k->smalw|dmawritebit); - /*xor with itself to set to zero faster.*/ - dmawritebit^=dmawritebit; - return ret; - case 23: - READ16(addr, emu8k->smarw|dmawritebit); - /*xor with itself to set to zero faster.*/ - dmawritebit^=dmawritebit; - return ret; - - case 26: - { - uint16_t val = emu8k->smrd_buffer; - emu8k->smrd_buffer = EMU8K_READ(emu8k, emu8k->smarr); - emu8k->smarr = (emu8k->smarr+1) & EMU8K_MEM_ADDRESS_MASK; - return val; - } - /*TODO: We need to improve the precision of this clock, since - it is used by programs to wait. Not critical, but should help reduce - the amount of calls and wait time */ - case 27: /*Sample Counter ( 44Khz clock) */ - return emu8k->wc; - } - break; + case 26: + { + uint16_t val = emu8k->smld_buffer; + emu8k->smld_buffer = EMU8K_READ(emu8k, emu8k->smalr); + emu8k->smalr = (emu8k->smalr + 1) & EMU8K_MEM_ADDRESS_MASK; + return val; + } - case 2: - return emu8k->init2[emu8k->cur_voice]; + /*The EMU8000 PGM describes the return values of these registers as 'a VLSI error'*/ + case 29: /*Configuration Word 1*/ + return (emu8k->hwcf1 & 0xfe) | (emu8k->hwcf3 & 0x01); + case 30: /*Configuration Word 2*/ + return ((emu8k->hwcf2 >> 4) & 0x0e) | (emu8k->hwcf1 & 0x01) | ((emu8k->hwcf3 & 0x02) ? 0x10 : 0) | ((emu8k->hwcf3 & 0x04) ? 0x40 : 0) + | ((emu8k->hwcf3 & 0x08) ? 0x20 : 0) | ((emu8k->hwcf3 & 0x10) ? 0x80 : 0); + case 31: /*Configuration Word 3*/ + return emu8k->hwcf2 & 0x1f; + } + break; - case 3: - return emu8k->init4[emu8k->cur_voice]; - - case 4: - return emu8k->voice[emu8k->cur_voice].atkhldv; + case 2: + return emu8k->init1[emu8k->cur_voice]; - case 5: - return emu8k->voice[emu8k->cur_voice].lfo1val; + case 3: + return emu8k->init3[emu8k->cur_voice]; - case 6: - return emu8k->voice[emu8k->cur_voice].atkhld; + case 4: + return emu8k->voice[emu8k->cur_voice].envvol; - case 7: - return emu8k->voice[emu8k->cur_voice].lfo2val; - } - break; - - case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ - switch (emu8k->cur_reg) - { - case 0: - return emu8k->voice[emu8k->cur_voice].ip; + case 5: + return emu8k->voice[emu8k->cur_voice].dcysusv; - case 1: - return emu8k->voice[emu8k->cur_voice].ifatn; + case 6: + return emu8k->voice[emu8k->cur_voice].envval; - case 2: - return emu8k->voice[emu8k->cur_voice].pefe; + case 7: + return emu8k->voice[emu8k->cur_voice].dcysus; + } + break; - case 3: - return emu8k->voice[emu8k->cur_voice].fmmod; + case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ + switch (emu8k->cur_reg) { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; - case 4: - return emu8k->voice[emu8k->cur_voice].tremfrq; + case 1: + switch (emu8k->cur_voice) { + case 9: + READ16(addr, emu8k->hwcf4); + return ret; + case 10: + READ16(addr, emu8k->hwcf5); + return ret; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ + case 13: + READ16(addr, emu8k->hwcf6); + return ret; + case 14: + READ16(addr, emu8k->hwcf7); + return ret; - case 5: - return emu8k->voice[emu8k->cur_voice].fm2frq2; + /* Simulating empty/full bits by unsetting it once read. */ + case 20: + READ16(addr, emu8k->smalr | dmareadbit); + /* xor with itself to set to zero faster. */ + dmareadbit ^= dmareadbit; + return ret; + case 21: + READ16(addr, emu8k->smarr | dmareadbit); + /* xor with itself to set to zero faster.*/ + dmareadbit ^= dmareadbit; + return ret; + case 22: + READ16(addr, emu8k->smalw | dmawritebit); + /*xor with itself to set to zero faster.*/ + dmawritebit ^= dmawritebit; + return ret; + case 23: + READ16(addr, emu8k->smarw | dmawritebit); + /*xor with itself to set to zero faster.*/ + dmawritebit ^= dmawritebit; + return ret; - case 6: - return 0xffff; - - case 7: /*ID?*/ - return 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); - } - break; + case 26: + { + uint16_t val = emu8k->smrd_buffer; + emu8k->smrd_buffer = EMU8K_READ(emu8k, emu8k->smarr); + emu8k->smarr = (emu8k->smarr + 1) & EMU8K_MEM_ADDRESS_MASK; + return val; + } + /*TODO: We need to improve the precision of this clock, since + it is used by programs to wait. Not critical, but should help reduce + the amount of calls and wait time */ + case 27: /*Sample Counter ( 44Khz clock) */ + return emu8k->wc; + } + break; - case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ - /* LS five bits = channel number, next 3 bits = register number - * and MS 8 bits = VLSI test register. - * Impulse tracker tests the non variability of the LS byte that it has set, and the variability - * of the MS byte to determine that it really is an AWE32. - * cubic player has a similar code, where it waits until value & 0x1000 is nonzero, and then waits again until it changes to zero.*/ - random_helper = (random_helper + 1) & 0x1F; - return ((0x80 | random_helper) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice; - } - emu8k_log("EMU8K READ : Unknown register read: %04X-%02X(%d/%d) \n", addr, (emu8k->cur_reg << 5) | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); - return 0xffff; + case 2: + return emu8k->init2[emu8k->cur_voice]; + + case 3: + return emu8k->init4[emu8k->cur_voice]; + + case 4: + return emu8k->voice[emu8k->cur_voice].atkhldv; + + case 5: + return emu8k->voice[emu8k->cur_voice].lfo1val; + + case 6: + return emu8k->voice[emu8k->cur_voice].atkhld; + + case 7: + return emu8k->voice[emu8k->cur_voice].lfo2val; + } + break; + + case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ + switch (emu8k->cur_reg) { + case 0: + return emu8k->voice[emu8k->cur_voice].ip; + + case 1: + return emu8k->voice[emu8k->cur_voice].ifatn; + + case 2: + return emu8k->voice[emu8k->cur_voice].pefe; + + case 3: + return emu8k->voice[emu8k->cur_voice].fmmod; + + case 4: + return emu8k->voice[emu8k->cur_voice].tremfrq; + + case 5: + return emu8k->voice[emu8k->cur_voice].fm2frq2; + + case 6: + return 0xffff; + + case 7: /*ID?*/ + return 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); + } + break; + + case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ + /* LS five bits = channel number, next 3 bits = register number + * and MS 8 bits = VLSI test register. + * Impulse tracker tests the non variability of the LS byte that it has set, and the variability + * of the MS byte to determine that it really is an AWE32. + * cubic player has a similar code, where it waits until value & 0x1000 is nonzero, and then waits again until it changes to zero.*/ + random_helper = (random_helper + 1) & 0x1F; + return ((0x80 | random_helper) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice; + } + emu8k_log("EMU8K READ : Unknown register read: %04X-%02X(%d/%d) \n", addr, (emu8k->cur_reg << 5) | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + return 0xffff; } -void emu8k_outw(uint16_t addr, uint16_t val, void *p) +void +emu8k_outw(uint16_t addr, uint16_t val, void *p) { - emu8k_t *emu8k = (emu8k_t *)p; + emu8k_t *emu8k = (emu8k_t *) p; - /*TODO: I would like to not call this here, but i found it was needed or else cubic player would not finish opening (take a looot more of time than usual). - * Basically, being here means that the audio is generated in the emulation thread, instead of the audio thread.*/ - emu8k_update(emu8k); + /*TODO: I would like to not call this here, but i found it was needed or else cubic player would not finish opening (take a looot more of time than usual). + * Basically, being here means that the audio is generated in the emulation thread, instead of the audio thread.*/ + emu8k_update(emu8k); #ifdef EMU8K_DEBUG_REGISTERS - if (addr == 0xE22) - { - //emu8k_log("EMU8K WRITE POINTER: %d\n", val); + if (addr == 0xE22) { + // emu8k_log("EMU8K WRITE POINTER: %d\n", val); + } else if ((addr & 0xF00) == 0x600) { + /* These are automatically reported by WRITE16 */ + if (rep_count_w > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w = 0; } - else if ((addr&0xF00) == 0x600) - { - /* These are automatically reported by WRITE16 */ - if (rep_count_w>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_w); - rep_count_w=0; - } - last_write=0; + last_write = 0; + } else if ((addr & 0xF00) == 0xA00 && emu8k->cur_reg == 0) { + /* These are automatically reported by WRITE16 */ + if (rep_count_w > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w = 0; } - else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 0) - { - /* These are automatically reported by WRITE16 */ - if (rep_count_w>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_w); - rep_count_w=0; - } - last_write=0; + last_write = 0; + } else if ((addr & 0xF00) == 0xA00 && emu8k->cur_reg == 1) { + uint32_t tmpz = ((addr & 0xF00) << 16) | (emu8k->cur_reg << 5); + if (tmpz != last_write) { + if (rep_count_w > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w = 0; + } + last_write = tmpz; + emu8k_log("EMU8K WRITE RAM I/O or configuration \n"); } - else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 1) - { - uint32_t tmpz = ((addr&0xF00) << 16)|(emu8k->cur_reg<<5); - if (tmpz != last_write) - { - if (rep_count_w>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_w); - rep_count_w=0; - } - last_write=tmpz; - emu8k_log("EMU8K WRITE RAM I/O or configuration \n"); - } - //emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + // emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } else if ((addr & 0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) { + uint32_t tmpz = ((addr & 0xF00) << 16); + if (tmpz != last_write) { + if (rep_count_w > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w = 0; + } + last_write = tmpz; + emu8k_log("EMU8K WRITE INIT \n"); } - else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) - { - uint32_t tmpz = ((addr&0xF00) << 16); - if (tmpz != last_write) - { - if (rep_count_w>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_w); - rep_count_w=0; - } - last_write=tmpz; - emu8k_log("EMU8K WRITE INIT \n"); - } - //emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); - } - else if (addr != 0xE22) - { - uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; - //if (tmpz != last_write) - if(1) - { - char* name = 0; - if (addr == 0xA20) - { - name = PORT_NAMES[1][emu8k->cur_reg]; - } - else if (addr == 0xA22) - { - name = PORT_NAMES[2][emu8k->cur_reg]; - } - else if (addr == 0xE20) - { - name = PORT_NAMES[3][emu8k->cur_reg]; - } + // emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } else if (addr != 0xE22) { + uint32_t tmpz = (addr << 16) | (emu8k->cur_reg << 5) | emu8k->cur_voice; + // if (tmpz != last_write) + if (1) { + char *name = 0; + if (addr == 0xA20) { + name = PORT_NAMES[1][emu8k->cur_reg]; + } else if (addr == 0xA22) { + name = PORT_NAMES[2][emu8k->cur_reg]; + } else if (addr == 0xE20) { + name = PORT_NAMES[3][emu8k->cur_reg]; + } - if (rep_count_w>1) - { - emu8k_log("EMU8K ...... for %d times\n", rep_count_w); - } - if (name == 0) - { - emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); - } - else - { - emu8k_log("EMU8K WRITE %s (%d): %04X\n",name,emu8k->cur_voice, val); - } - - rep_count_w=0; - last_write=tmpz; - } - rep_count_w++; + if (rep_count_w > 1) { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + } + if (name == 0) { + emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice, val); + } else { + emu8k_log("EMU8K WRITE %s (%d): %04X\n", name, emu8k->cur_voice, val); + } + + rep_count_w = 0; + last_write = tmpz; } -#endif //EMU8K_DEBUG_REGISTERS + rep_count_w++; + } +#endif // EMU8K_DEBUG_REGISTERS + switch (addr & 0xF02) { + case 0x600: + case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ + switch (emu8k->cur_reg) { + case 0: + /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over ptrx */ + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + return; - switch (addr & 0xF02) - { - case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ - switch (emu8k->cur_reg) - { - case 0: - /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over ptrx */ - WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); - return; - - case 1: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].ptrx, val); - return; - - case 2: - /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over vtft */ - WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val); - return; - - case 3: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val); - return; - - case 4: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4, val); - return; + case 1: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ptrx, val); + return; - case 5: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5, val); - return; - - case 6: - { - emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; - WRITE16(addr, emu_voice->psst, val); - /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ - emu_voice->loop_start.int_address = emu_voice->psst & EMU8K_MEM_ADDRESS_MASK; - if (addr & 2) - { - emu_voice->vol_l = emu_voice->psst_pan; - emu_voice->vol_r = 255 - (emu_voice->psst_pan); - } - } - return; - - case 7: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].csl, val); + case 2: + /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over vtft */ + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val); + return; + + case 3: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val); + return; + + case 4: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4, val); + return; + + case 5: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5, val); + return; + + case 6: + { + emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; + WRITE16(addr, emu_voice->psst, val); /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ - emu8k->voice[emu8k->cur_voice].loop_end.int_address = emu8k->voice[emu8k->cur_voice].csl & EMU8K_MEM_ADDRESS_MASK; - return; - } - break; - - case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ - switch (emu8k->cur_reg) - { - case 0: - WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); - /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ - emu8k->voice[emu8k->cur_voice].addr.int_address = emu8k->voice[emu8k->cur_voice].ccca & EMU8K_MEM_ADDRESS_MASK; - return; - - case 1: - switch (emu8k->cur_voice) - { - case 9: - WRITE16(addr, emu8k->hwcf4, val); - return; - case 10: - WRITE16(addr, emu8k->hwcf5, val); - return; - /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ - case 13: - WRITE16(addr, emu8k->hwcf6, val); - return; - case 14: - WRITE16(addr, emu8k->hwcf7, val); - return; - - case 20: - WRITE16(addr, emu8k->smalr, val); - return; - case 21: - WRITE16(addr, emu8k->smarr, val); - return; - case 22: - WRITE16(addr, emu8k->smalw, val); - return; - case 23: - WRITE16(addr, emu8k->smarw, val); - return; - - case 26: - EMU8K_WRITE(emu8k, emu8k->smalw, val); - emu8k->smalw = (emu8k->smalw+1) & EMU8K_MEM_ADDRESS_MASK; - return; - - case 29: - emu8k->hwcf1 = val; - return; - case 30: - emu8k->hwcf2 = val; - return; - case 31: - emu8k->hwcf3 = val; - return; + emu_voice->loop_start.int_address = emu_voice->psst & EMU8K_MEM_ADDRESS_MASK; + if (addr & 2) { + emu_voice->vol_l = emu_voice->psst_pan; + emu_voice->vol_r = 255 - (emu_voice->psst_pan); } - break; + } + return; - case 2: - emu8k->init1[emu8k->cur_voice] = val; - /* Skip if in first/second initialization step */ - if (emu8k->init1[0] != 0x03FF) - { - switch(emu8k->cur_voice) + case 7: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].csl, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].loop_end.int_address = emu8k->voice[emu8k->cur_voice].csl & EMU8K_MEM_ADDRESS_MASK; + return; + } + break; + + case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ + switch (emu8k->cur_reg) { + case 0: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].addr.int_address = emu8k->voice[emu8k->cur_voice].ccca & EMU8K_MEM_ADDRESS_MASK; + return; + + case 1: + switch (emu8k->cur_voice) { + case 9: + WRITE16(addr, emu8k->hwcf4, val); + return; + case 10: + WRITE16(addr, emu8k->hwcf5, val); + return; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ + case 13: + WRITE16(addr, emu8k->hwcf6, val); + return; + case 14: + WRITE16(addr, emu8k->hwcf7, val); + return; + + case 20: + WRITE16(addr, emu8k->smalr, val); + return; + case 21: + WRITE16(addr, emu8k->smarr, val); + return; + case 22: + WRITE16(addr, emu8k->smalw, val); + return; + case 23: + WRITE16(addr, emu8k->smarw, val); + return; + + case 26: + EMU8K_WRITE(emu8k, emu8k->smalw, val); + emu8k->smalw = (emu8k->smalw + 1) & EMU8K_MEM_ADDRESS_MASK; + return; + + case 29: + emu8k->hwcf1 = val; + return; + case 30: + emu8k->hwcf2 = val; + return; + case 31: + emu8k->hwcf3 = val; + return; + } + break; + + case 2: + emu8k->init1[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { + switch (emu8k->cur_voice) { + case 0x3: + emu8k->reverb_engine.out_mix = val & 0xFF; + break; + case 0x5: { - case 0x3: emu8k->reverb_engine.out_mix = val&0xFF; - break; - case 0x5: - { - int c; - for (c=0;c<8;c++) - { - emu8k->reverb_engine.allpass[c].feedback=(val&0xFF)/((float)0xFF); - } - } - break; - case 0x7: emu8k->reverb_engine.link_return_type = (val==0x8474)? 1:0; - break; - case 0xF: emu8k->reverb_engine.reflections[0].output_gain = ((val&0xF0)>>4)/15.0; - break; - case 0x17: emu8k->reverb_engine.reflections[1].output_gain = ((val&0xF0)>>4)/15.0; - break; - case 0x1F: emu8k->reverb_engine.reflections[2].output_gain = ((val&0xF0)>>4)/15.0; - break; - case 0x9: emu8k->reverb_engine.reflections[0].feedback = (val&0xF)/15.0; - break; - case 0xB: //emu8k->reverb_engine.reflections[0].feedback_r = (val&0xF)/15.0; - break; - case 0x11:emu8k->reverb_engine.reflections[1].feedback = (val&0xF)/15.0; - break; - case 0x13: //emu8k->reverb_engine.reflections[1].feedback_r = (val&0xF)/15.0; - break; - case 0x19: emu8k->reverb_engine.reflections[2].feedback = (val&0xF)/15.0; - break; - case 0x1B: //emu8k->reverb_engine.reflections[2].feedback_r = (val&0xF)/15.0; - break; + int c; + for (c = 0; c < 8; c++) { + emu8k->reverb_engine.allpass[c].feedback = (val & 0xFF) / ((float) 0xFF); + } } + break; + case 0x7: + emu8k->reverb_engine.link_return_type = (val == 0x8474) ? 1 : 0; + break; + case 0xF: + emu8k->reverb_engine.reflections[0].output_gain = ((val & 0xF0) >> 4) / 15.0; + break; + case 0x17: + emu8k->reverb_engine.reflections[1].output_gain = ((val & 0xF0) >> 4) / 15.0; + break; + case 0x1F: + emu8k->reverb_engine.reflections[2].output_gain = ((val & 0xF0) >> 4) / 15.0; + break; + case 0x9: + emu8k->reverb_engine.reflections[0].feedback = (val & 0xF) / 15.0; + break; + case 0xB: // emu8k->reverb_engine.reflections[0].feedback_r = (val&0xF)/15.0; + break; + case 0x11: + emu8k->reverb_engine.reflections[1].feedback = (val & 0xF) / 15.0; + break; + case 0x13: // emu8k->reverb_engine.reflections[1].feedback_r = (val&0xF)/15.0; + break; + case 0x19: + emu8k->reverb_engine.reflections[2].feedback = (val & 0xF) / 15.0; + break; + case 0x1B: // emu8k->reverb_engine.reflections[2].feedback_r = (val&0xF)/15.0; + break; } - return; + } + return; - case 3: - emu8k->init3[emu8k->cur_voice] = val; - /* Skip if in first/second initialization step */ - if (emu8k->init1[0] != 0x03FF) - { - switch(emu8k->cur_voice) - { - case 9: - emu8k->chorus_engine.feedback = (val&0xFF); - break; - case 12: - /* Limiting this to a sane value given our buffer. */ - emu8k->chorus_engine.delay_samples_central = (val&0x1FFF); - break; - - case 1: emu8k->reverb_engine.refl_in_amp = val&0xFF; - break; - case 3: //emu8k->reverb_engine.refl_in_amp_r = val&0xFF; - break; - } + case 3: + emu8k->init3[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { + switch (emu8k->cur_voice) { + case 9: + emu8k->chorus_engine.feedback = (val & 0xFF); + break; + case 12: + /* Limiting this to a sane value given our buffer. */ + emu8k->chorus_engine.delay_samples_central = (val & 0x1FFF); + break; + + case 1: + emu8k->reverb_engine.refl_in_amp = val & 0xFF; + break; + case 3: // emu8k->reverb_engine.refl_in_amp_r = val&0xFF; + break; } - return; - - case 4: - emu8k->voice[emu8k->cur_voice].envvol = val; - emu8k->voice[emu8k->cur_voice].vol_envelope.delay_samples = ENVVOL_TO_EMU_SAMPLES(val); - return; - - case 5: - { - emu8k->voice[emu8k->cur_voice].dcysusv = val; - emu8k_envelope_t * const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; - int old_on=emu8k->voice[emu8k->cur_voice].env_engine_on; - emu8k->voice[emu8k->cur_voice].env_engine_on = DCYSUSV_GENERATOR_ENGINE_ON(val); - - if (emu8k->voice[emu8k->cur_voice].env_engine_on && - old_on != emu8k->voice[emu8k->cur_voice].env_engine_on) - { - if (emu8k->hwcf3 != 0x04) - { - /* This is a hack for some programs like Doom or cubic player 1.7 that don't initialize - the hwcfg and init registers (doom does not init the card at all. only tests the cfg registers) */ - emu8k->hwcf3 = 0x04; - } - - //reset lfos. - emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; - emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; - // Trigger envelopes - if (ATKHLDV_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhldv)) - { - vol_env->value_amp_hz = 0; - if (vol_env->delay_samples) - { - vol_env->state = ENV_DELAY; - } - else if (vol_env->attack_amount_amp_hz == 0) - { - vol_env->state = ENV_STOPPED; - } - else - { - vol_env->state = ENV_ATTACK; - /* TODO: Verify if "never attack" means eternal mute, - * or it means skip attack, go to hold". - if (vol_env->attack_amount == 0) - { - vol_env->value = (1 << 21); - vol_env->state = ENV_HOLD; - }*/ - } - } - - if (ATKHLD_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhld)) - { - emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; - mod_env->value_amp_hz = 0; - mod_env->value_db_oct = 0; - if (mod_env->delay_samples) - { - mod_env->state = ENV_DELAY; - } - else if (mod_env->attack_amount_amp_hz == 0) - { - mod_env->state = ENV_STOPPED; - } - else - { - mod_env->state = ENV_ATTACK; - /* TODO: Verify if "never attack" means eternal start, - * or it means skip attack, go to hold". - if (mod_env->attack_amount == 0) - { - mod_env->value = (1 << 21); - mod_env->state = ENV_HOLD; - }*/ - } - } + } + return; + + case 4: + emu8k->voice[emu8k->cur_voice].envvol = val; + emu8k->voice[emu8k->cur_voice].vol_envelope.delay_samples = ENVVOL_TO_EMU_SAMPLES(val); + return; + + case 5: + { + emu8k->voice[emu8k->cur_voice].dcysusv = val; + emu8k_envelope_t *const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; + int old_on = emu8k->voice[emu8k->cur_voice].env_engine_on; + emu8k->voice[emu8k->cur_voice].env_engine_on = DCYSUSV_GENERATOR_ENGINE_ON(val); + + if (emu8k->voice[emu8k->cur_voice].env_engine_on && old_on != emu8k->voice[emu8k->cur_voice].env_engine_on) { + if (emu8k->hwcf3 != 0x04) { + /* This is a hack for some programs like Doom or cubic player 1.7 that don't initialize + the hwcfg and init registers (doom does not init the card at all. only tests the cfg registers) */ + emu8k->hwcf3 = 0x04; + } + + // reset lfos. + emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; + emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; + // Trigger envelopes + if (ATKHLDV_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhldv)) { + vol_env->value_amp_hz = 0; + if (vol_env->delay_samples) { + vol_env->state = ENV_DELAY; + } else if (vol_env->attack_amount_amp_hz == 0) { + vol_env->state = ENV_STOPPED; + } else { + vol_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal mute, + * or it means skip attack, go to hold". + if (vol_env->attack_amount == 0) + { + vol_env->value = (1 << 21); + vol_env->state = ENV_HOLD; + }*/ } - + } - /* Converting the input in dBs to envelope value range. */ - vol_env->sustain_value_db_oct = DCYSUSV_SUS_TO_ENV_RANGE(DCYSUSV_SUSVALUE_GET(val)); - vol_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUSV_DECAYRELEASE_GET(val)]; - if (DCYSUSV_IS_RELEASE(val)) - { - if (vol_env->state == ENV_DELAY || vol_env->state == ENV_ATTACK || vol_env->state == ENV_HOLD) - { - vol_env->value_db_oct = env_vol_amplitude_to_db[vol_env->value_amp_hz >> 5] << 5; - if (vol_env->value_db_oct > (1 << 21)) - vol_env->value_db_oct = 1 << 21; - } - - vol_env->state = (vol_env->value_db_oct >= vol_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; + if (ATKHLD_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhld)) { + emu8k_envelope_t *const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + mod_env->value_amp_hz = 0; + mod_env->value_db_oct = 0; + if (mod_env->delay_samples) { + mod_env->state = ENV_DELAY; + } else if (mod_env->attack_amount_amp_hz == 0) { + mod_env->state = ENV_STOPPED; + } else { + mod_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal start, + * or it means skip attack, go to hold". + if (mod_env->attack_amount == 0) + { + mod_env->value = (1 << 21); + mod_env->state = ENV_HOLD; + }*/ } + } } - return; - case 6: - emu8k->voice[emu8k->cur_voice].envval = val; - emu8k->voice[emu8k->cur_voice].mod_envelope.delay_samples = ENVVAL_TO_EMU_SAMPLES(val); - return; + /* Converting the input in dBs to envelope value range. */ + vol_env->sustain_value_db_oct = DCYSUSV_SUS_TO_ENV_RANGE(DCYSUSV_SUSVALUE_GET(val)); + vol_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUSV_DECAYRELEASE_GET(val)]; + if (DCYSUSV_IS_RELEASE(val)) { + if (vol_env->state == ENV_DELAY || vol_env->state == ENV_ATTACK || vol_env->state == ENV_HOLD) { + vol_env->value_db_oct = env_vol_amplitude_to_db[vol_env->value_amp_hz >> 5] << 5; + if (vol_env->value_db_oct > (1 << 21)) + vol_env->value_db_oct = 1 << 21; + } - case 7: - { - //TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) - emu8k->voice[emu8k->cur_voice].dcysus = val; - emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; - /* Converting the input in octaves to envelope value range. */ - mod_env->sustain_value_db_oct = DCYSUS_SUS_TO_ENV_RANGE(DCYSUS_SUSVALUE_GET(val)); - mod_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUS_DECAYRELEASE_GET(val)]; - if (DCYSUS_IS_RELEASE(val)) - { - if (mod_env->state == ENV_DELAY || mod_env->state == ENV_ATTACK || mod_env->state == ENV_HOLD) - { - mod_env->value_db_oct = env_mod_hertz_to_octave[mod_env->value_amp_hz >> 9] << 9; - if (mod_env->value_db_oct >= (1 << 21)) - mod_env->value_db_oct = (1 << 21)-1; - } - - mod_env->state = (mod_env->value_db_oct >= mod_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; - } + vol_env->state = (vol_env->value_db_oct >= vol_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; } - return; - } - break; - - case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ - switch (emu8k->cur_reg) - { - case 0: - { - emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; - WRITE16(addr, emu_voice->ccca, val); - emu_voice->addr.int_address = emu_voice->ccca & EMU8K_MEM_ADDRESS_MASK; - uint32_t paramq = CCCA_FILTQ_GET(emu_voice->ccca); - emu_voice->filt_att = filter_atten[paramq]; - emu_voice->filterq_idx = paramq; - } - return; + } + return; - case 1: - switch (emu8k->cur_voice) - { - case 9: - WRITE16(addr, emu8k->hwcf4, val); - /* Skip if in first/second initialization step */ - if (emu8k->init1[0] != 0x03FF) - { - /*(1/256th of a 44Khz sample) */ - /* clip the value to a reasonable value given our buffer */ - int32_t tmp = emu8k->hwcf4&0x1FFFFF; - emu8k->chorus_engine.delay_offset_samples_right = ((double)tmp)/256.0; - } - return; - case 10: - WRITE16(addr, emu8k->hwcf5, val); - /* Skip if in first/second initialization step */ - if (emu8k->init1[0] != 0x03FF) - { - /* The scale of this value is unknown. I've taken it as milliHz. - * Another interpretation could be periods. (and so, Hz = 1/period)*/ - double osc_speed = emu8k->hwcf5;//*1.316; -#if 1 // milliHz - /*milliHz to lfotable samples.*/ - osc_speed *= 65.536/44100.0; -#elif 0 //periods - /* 44.1Khz ticks to lfotable samples.*/ - osc_speed = 65.536/osc_speed; + case 6: + emu8k->voice[emu8k->cur_voice].envval = val; + emu8k->voice[emu8k->cur_voice].mod_envelope.delay_samples = ENVVAL_TO_EMU_SAMPLES(val); + return; + + case 7: + { + // TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) + emu8k->voice[emu8k->cur_voice].dcysus = val; + emu8k_envelope_t *const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + /* Converting the input in octaves to envelope value range. */ + mod_env->sustain_value_db_oct = DCYSUS_SUS_TO_ENV_RANGE(DCYSUS_SUSVALUE_GET(val)); + mod_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUS_DECAYRELEASE_GET(val)]; + if (DCYSUS_IS_RELEASE(val)) { + if (mod_env->state == ENV_DELAY || mod_env->state == ENV_ATTACK || mod_env->state == ENV_HOLD) { + mod_env->value_db_oct = env_mod_hertz_to_octave[mod_env->value_amp_hz >> 9] << 9; + if (mod_env->value_db_oct >= (1 << 21)) + mod_env->value_db_oct = (1 << 21) - 1; + } + + mod_env->state = (mod_env->value_db_oct >= mod_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; + } + } + return; + } + break; + + case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ + switch (emu8k->cur_reg) { + case 0: + { + emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; + WRITE16(addr, emu_voice->ccca, val); + emu_voice->addr.int_address = emu_voice->ccca & EMU8K_MEM_ADDRESS_MASK; + uint32_t paramq = CCCA_FILTQ_GET(emu_voice->ccca); + emu_voice->filt_att = filter_atten[paramq]; + emu_voice->filterq_idx = paramq; + } + return; + + case 1: + switch (emu8k->cur_voice) { + case 9: + WRITE16(addr, emu8k->hwcf4, val); + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { + /*(1/256th of a 44Khz sample) */ + /* clip the value to a reasonable value given our buffer */ + int32_t tmp = emu8k->hwcf4 & 0x1FFFFF; + emu8k->chorus_engine.delay_offset_samples_right = ((double) tmp) / 256.0; + } + return; + case 10: + WRITE16(addr, emu8k->hwcf5, val); + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { + /* The scale of this value is unknown. I've taken it as milliHz. + * Another interpretation could be periods. (and so, Hz = 1/period)*/ + double osc_speed = emu8k->hwcf5; //*1.316; +#if 1 // milliHz + /*milliHz to lfotable samples.*/ + osc_speed *= 65.536 / 44100.0; +#elif 0 // periods + /* 44.1Khz ticks to lfotable samples.*/ + osc_speed = 65.536 / osc_speed; #endif - /*left shift 32bits for 32.32 fixed.point*/ - osc_speed *= 65536.0*65536.0; - emu8k->chorus_engine.lfo_inc.addr = (uint64_t)osc_speed; + /*left shift 32bits for 32.32 fixed.point*/ + osc_speed *= 65536.0 * 65536.0; + emu8k->chorus_engine.lfo_inc.addr = (uint64_t) osc_speed; + } + return; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ + case 13: + WRITE16(addr, emu8k->hwcf6, val); + return; + case 14: + WRITE16(addr, emu8k->hwcf7, val); + return; + + case 20: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ + WRITE16(addr, emu8k->smalr, val & 0xFF); + dmareadbit = 0x8000; + return; + case 21: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ + WRITE16(addr, emu8k->smarr, val & 0xFF); + dmareadbit = 0x8000; + return; + case 22: /*Top 8 bits are for full bit or non-addressable.*/ + WRITE16(addr, emu8k->smalw, val & 0xFF); + return; + case 23: /*Top 8 bits are for full bit or non-addressable.*/ + WRITE16(addr, emu8k->smarw, val & 0xFF); + return; + + case 26: + dmawritebit = 0x8000; + EMU8K_WRITE(emu8k, emu8k->smarw, val); + emu8k->smarw++; + return; + } + break; + + case 2: + emu8k->init2[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { + switch (emu8k->cur_voice) { + case 0x14: + { + int multip = ((val & 0xF00) >> 8) + 18; + emu8k->reverb_engine.reflections[5].bufsize = multip * REV_BUFSIZE_STEP; + emu8k->reverb_engine.tailL.bufsize = (multip + 1) * REV_BUFSIZE_STEP; + if (emu8k->reverb_engine.link_return_type == 0) { + emu8k->reverb_engine.tailR.bufsize = (multip + 1) * REV_BUFSIZE_STEP; + } } - return; - /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ - case 13: - WRITE16(addr, emu8k->hwcf6, val); - return; - case 14: - WRITE16(addr, emu8k->hwcf7, val); - return; - - case 20: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ - WRITE16(addr, emu8k->smalr, val&0xFF); - dmareadbit=0x8000; - return; - case 21: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ - WRITE16(addr, emu8k->smarr, val&0xFF); - dmareadbit=0x8000; - return; - case 22: /*Top 8 bits are for full bit or non-addressable.*/ - WRITE16(addr, emu8k->smalw, val&0xFF); - return; - case 23: /*Top 8 bits are for full bit or non-addressable.*/ - WRITE16(addr, emu8k->smarw, val&0xFF); - return; - - case 26: - dmawritebit=0x8000; - EMU8K_WRITE(emu8k, emu8k->smarw, val); - emu8k->smarw++; - return; + break; + case 0x16: + if (emu8k->reverb_engine.link_return_type == 1) { + int multip = ((val & 0xF00) >> 8) + 18; + emu8k->reverb_engine.tailR.bufsize = (multip + 1) * REV_BUFSIZE_STEP; + } + break; + case 0x7: + emu8k->reverb_engine.reflections[3].output_gain = ((val & 0xF0) >> 4) / 15.0; + break; + case 0xf: + emu8k->reverb_engine.reflections[4].output_gain = ((val & 0xF0) >> 4) / 15.0; + break; + case 0x17: + emu8k->reverb_engine.reflections[5].output_gain = ((val & 0xF0) >> 4) / 15.0; + break; + case 0x1d: + { + int c; + for (c = 0; c < 6; c++) { + emu8k->reverb_engine.reflections[c].damp1 = (val & 0xFF) / 255.0; + emu8k->reverb_engine.reflections[c].damp2 = (0xFF - (val & 0xFF)) / 255.0; + emu8k->reverb_engine.reflections[c].filterstore = 0; + } + emu8k->reverb_engine.damper.damp1 = (val & 0xFF) / 255.0; + emu8k->reverb_engine.damper.damp2 = (0xFF - (val & 0xFF)) / 255.0; + emu8k->reverb_engine.damper.filterstore = 0; + } + break; + case 0x1f: /* filter r */ + break; + case 0x1: + emu8k->reverb_engine.reflections[3].feedback = (val & 0xF) / 15.0; + break; + case 0x3: // emu8k->reverb_engine.reflections[3].feedback_r = (val&0xF)/15.0; + break; + case 0x9: + emu8k->reverb_engine.reflections[4].feedback = (val & 0xF) / 15.0; + break; + case 0xb: // emu8k->reverb_engine.reflections[4].feedback_r = (val&0xF)/15.0; + break; + case 0x11: + emu8k->reverb_engine.reflections[5].feedback = (val & 0xF) / 15.0; + break; + case 0x13: // emu8k->reverb_engine.reflections[5].feedback_r = (val&0xF)/15.0; + break; } - break; + } + return; - case 2: - emu8k->init2[emu8k->cur_voice] = val; - /* Skip if in first/second initialization step */ - if (emu8k->init1[0] != 0x03FF) - { - switch(emu8k->cur_voice) + case 3: + emu8k->init4[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { + switch (emu8k->cur_voice) { + case 0x3: { - case 0x14: - { - int multip = ((val&0xF00)>>8)+18; - emu8k->reverb_engine.reflections[5].bufsize = multip*REV_BUFSIZE_STEP; - emu8k->reverb_engine.tailL.bufsize = (multip+1)*REV_BUFSIZE_STEP; - if ( emu8k->reverb_engine.link_return_type == 0) - { - emu8k->reverb_engine.tailR.bufsize = (multip+1)*REV_BUFSIZE_STEP; - } - } - break; - case 0x16: - if ( emu8k->reverb_engine.link_return_type == 1) - { - int multip = ((val&0xF00)>>8)+18; - emu8k->reverb_engine.tailR.bufsize = (multip+1)*REV_BUFSIZE_STEP; - } - break; - case 0x7: emu8k->reverb_engine.reflections[3].output_gain = ((val&0xF0)>>4)/15.0; - break; - case 0xf: emu8k->reverb_engine.reflections[4].output_gain = ((val&0xF0)>>4)/15.0; - break; - case 0x17: emu8k->reverb_engine.reflections[5].output_gain = ((val&0xF0)>>4)/15.0; - break; - case 0x1d: - { - int c; - for (c=0;c<6;c++) - { - emu8k->reverb_engine.reflections[c].damp1=(val&0xFF)/255.0; - emu8k->reverb_engine.reflections[c].damp2=(0xFF-(val&0xFF))/255.0; - emu8k->reverb_engine.reflections[c].filterstore=0; - } - emu8k->reverb_engine.damper.damp1=(val&0xFF)/255.0; - emu8k->reverb_engine.damper.damp2=(0xFF-(val&0xFF))/255.0; - emu8k->reverb_engine.damper.filterstore=0; - } - break; - case 0x1f: /* filter r */ - break; - case 0x1: emu8k->reverb_engine.reflections[3].feedback = (val&0xF)/15.0; - break; - case 0x3: //emu8k->reverb_engine.reflections[3].feedback_r = (val&0xF)/15.0; - break; - case 0x9: emu8k->reverb_engine.reflections[4].feedback = (val&0xF)/15.0; - break; - case 0xb: //emu8k->reverb_engine.reflections[4].feedback_r = (val&0xF)/15.0; - break; - case 0x11: emu8k->reverb_engine.reflections[5].feedback = (val&0xF)/15.0; - break; - case 0x13: //emu8k->reverb_engine.reflections[5].feedback_r = (val&0xF)/15.0; - break; + int32_t samples = ((val & 0xFF) * emu8k->chorus_engine.delay_samples_central) >> 8; + emu8k->chorus_engine.lfodepth_multip = samples; } + break; + + case 0x1F: + emu8k->reverb_engine.link_return_amp = val & 0xFF; + break; } - return; + } + return; - case 3: - emu8k->init4[emu8k->cur_voice] = val; - /* Skip if in first/second initialization step */ - if (emu8k->init1[0] != 0x03FF) - { - switch(emu8k->cur_voice) - { - case 0x3: - { - int32_t samples = ((val&0xFF)*emu8k->chorus_engine.delay_samples_central) >> 8; - emu8k->chorus_engine.lfodepth_multip = samples; - - } - break; - - case 0x1F: - emu8k->reverb_engine.link_return_amp = val&0xFF; - break; - } + case 4: + { + emu8k->voice[emu8k->cur_voice].atkhldv = val; + emu8k_envelope_t *const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; + vol_env->attack_samples = env_attack_to_samples[ATKHLDV_ATTACK(val)]; + if (vol_env->attack_samples == 0) { + vol_env->attack_amount_amp_hz = 0; + } else { + /* Linear amplitude increase each sample. */ + vol_env->attack_amount_amp_hz = (1 << 21) / vol_env->attack_samples; } - return ; + vol_env->hold_samples = ATKHLDV_HOLD_TO_EMU_SAMPLES(val); + if (ATKHLDV_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) { + /*TODO: I assume that "envelope trigger" is the same as new note + * (since changing the IP can be done when modulating pitch too) */ + emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; + emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; - case 4: - { - emu8k->voice[emu8k->cur_voice].atkhldv = val; - emu8k_envelope_t* const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; - vol_env->attack_samples = env_attack_to_samples[ATKHLDV_ATTACK(val)]; - if (vol_env->attack_samples == 0) + vol_env->value_amp_hz = 0; + if (vol_env->delay_samples) { + vol_env->state = ENV_DELAY; + } else if (vol_env->attack_amount_amp_hz == 0) { + vol_env->state = ENV_STOPPED; + } else { + vol_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal mute, + * or it means skip attack, go to hold". + if (vol_env->attack_amount == 0) { - vol_env->attack_amount_amp_hz = 0; - } - else - { - /* Linear amplitude increase each sample. */ - vol_env->attack_amount_amp_hz = (1<<21) / vol_env->attack_samples; - } - vol_env->hold_samples = ATKHLDV_HOLD_TO_EMU_SAMPLES(val); - if (ATKHLDV_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) - { - /*TODO: I assume that "envelope trigger" is the same as new note - * (since changing the IP can be done when modulating pitch too) */ - emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; - emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; - - vol_env->value_amp_hz = 0; - if (vol_env->delay_samples) - { - vol_env->state = ENV_DELAY; - } - else if (vol_env->attack_amount_amp_hz == 0) - { - vol_env->state = ENV_STOPPED; - } - else - { - vol_env->state = ENV_ATTACK; - /* TODO: Verify if "never attack" means eternal mute, - * or it means skip attack, go to hold". - if (vol_env->attack_amount == 0) - { - vol_env->value = (1 << 21); - vol_env->state = ENV_HOLD; - }*/ - } - } + vol_env->value = (1 << 21); + vol_env->state = ENV_HOLD; + }*/ + } } - return; - - case 5: - emu8k->voice[emu8k->cur_voice].lfo1val = val; - /* TODO: verify if this is set once, or set every time. */ - emu8k->voice[emu8k->cur_voice].lfo1_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); - return; + } + return; - case 6: - { - emu8k->voice[emu8k->cur_voice].atkhld = val; - emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; - mod_env->attack_samples = env_attack_to_samples[ATKHLD_ATTACK(val)]; - if (mod_env->attack_samples == 0) - { - mod_env->attack_amount_amp_hz = 0; - } - else - { - /* Linear amplitude increase each sample. */ - mod_env->attack_amount_amp_hz = (1<<21) / mod_env->attack_samples; - } - mod_env->hold_samples = ATKHLD_HOLD_TO_EMU_SAMPLES(val); - if (ATKHLD_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) - { - mod_env->value_amp_hz = 0; - mod_env->value_db_oct = 0; - if (mod_env->delay_samples) - { - mod_env->state = ENV_DELAY; - } - else if (mod_env->attack_amount_amp_hz == 0) - { - mod_env->state = ENV_STOPPED; - } - else - { - mod_env->state = ENV_ATTACK; - /* TODO: Verify if "never attack" means eternal start, - * or it means skip attack, go to hold". - if (mod_env->attack_amount == 0) - { - mod_env->value = (1 << 21); - mod_env->state = ENV_HOLD; - }*/ - } - } + case 5: + emu8k->voice[emu8k->cur_voice].lfo1val = val; + /* TODO: verify if this is set once, or set every time. */ + emu8k->voice[emu8k->cur_voice].lfo1_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); + return; + + case 6: + { + emu8k->voice[emu8k->cur_voice].atkhld = val; + emu8k_envelope_t *const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + mod_env->attack_samples = env_attack_to_samples[ATKHLD_ATTACK(val)]; + if (mod_env->attack_samples == 0) { + mod_env->attack_amount_amp_hz = 0; + } else { + /* Linear amplitude increase each sample. */ + mod_env->attack_amount_amp_hz = (1 << 21) / mod_env->attack_samples; } - return; - - case 7: - emu8k->voice[emu8k->cur_voice].lfo2val = val; - emu8k->voice[emu8k->cur_voice].lfo2_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); - - return; - } - break; - - case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ - switch (emu8k->cur_reg) - { - case 0: - emu8k->voice[emu8k->cur_voice].ip = val; - emu8k->voice[emu8k->cur_voice].ptrx_pit_target = freqtable[val] >> 18; - return; - - case 1: - { - emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; - if ((val&0xFF) == 0 && the_voice->cvcf_curr_volume == 0 && the_voice->vtft_vol_target == 0 - && the_voice->dcysusv == 0x80 && the_voice->ip == 0) + mod_env->hold_samples = ATKHLD_HOLD_TO_EMU_SAMPLES(val); + if (ATKHLD_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) { + mod_env->value_amp_hz = 0; + mod_env->value_db_oct = 0; + if (mod_env->delay_samples) { + mod_env->state = ENV_DELAY; + } else if (mod_env->attack_amount_amp_hz == 0) { + mod_env->state = ENV_STOPPED; + } else { + mod_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal start, + * or it means skip attack, go to hold". + if (mod_env->attack_amount == 0) { - // Patch to avoid some clicking noises with Impulse tracker or other software that sets - // different values to 0 to set noteoff, but here, 0 means no attenuation = full volume. - return; - } - the_voice->ifatn = val; - the_voice->initial_att = (((int32_t)the_voice->ifatn_attenuation <<21)/0xFF); - the_voice->vtft_vol_target = attentable[the_voice->ifatn_attenuation]; - - the_voice->initial_filter = (((int32_t)the_voice->ifatn_init_filter <<21)/0xFF); - if (the_voice->ifatn_init_filter==0xFF) - { - the_voice->vtft_filter_target = 0xFFFF; - } - else - { - the_voice->vtft_filter_target = the_voice->initial_filter >> 5; - } + mod_env->value = (1 << 21); + mod_env->state = ENV_HOLD; + }*/ + } } - return; + } + return; - case 2: - { - emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; - the_voice->pefe = val; + case 7: + emu8k->voice[emu8k->cur_voice].lfo2val = val; + emu8k->voice[emu8k->cur_voice].lfo2_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); - int divider = (the_voice->pefe_modenv_filter_height < 0) ? 0x80 : 0x7F; - the_voice->fixed_modenv_filter_height = ((int32_t)the_voice->pefe_modenv_filter_height)*0x4000/divider; + return; + } + break; - divider = (the_voice->pefe_modenv_pitch_height < 0) ? 0x80 : 0x7F; - the_voice->fixed_modenv_pitch_height = ((int32_t)the_voice->pefe_modenv_pitch_height)*0x4000/divider; + case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ + switch (emu8k->cur_reg) { + case 0: + emu8k->voice[emu8k->cur_voice].ip = val; + emu8k->voice[emu8k->cur_voice].ptrx_pit_target = freqtable[val] >> 18; + return; + + case 1: + { + emu8k_voice_t *const the_voice = &emu8k->voice[emu8k->cur_voice]; + if ((val & 0xFF) == 0 && the_voice->cvcf_curr_volume == 0 && the_voice->vtft_vol_target == 0 + && the_voice->dcysusv == 0x80 && the_voice->ip == 0) { + // Patch to avoid some clicking noises with Impulse tracker or other software that sets + // different values to 0 to set noteoff, but here, 0 means no attenuation = full volume. + return; } - return; + the_voice->ifatn = val; + the_voice->initial_att = (((int32_t) the_voice->ifatn_attenuation << 21) / 0xFF); + the_voice->vtft_vol_target = attentable[the_voice->ifatn_attenuation]; - case 3: - { - emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; - the_voice->fmmod = val; - - int divider = (the_voice->fmmod_lfo1_filt_mod < 0) ? 0x80 : 0x7F; - the_voice->fixed_lfo1_filt_mod = ((int32_t)the_voice->fmmod_lfo1_filt_mod)*0x4000/divider; - - divider = (the_voice->fmmod_lfo1_vibrato < 0) ? 0x80 : 0x7F; - the_voice->fixed_lfo1_vibrato = ((int32_t)the_voice->fmmod_lfo1_vibrato)*0x4000/divider; + the_voice->initial_filter = (((int32_t) the_voice->ifatn_init_filter << 21) / 0xFF); + if (the_voice->ifatn_init_filter == 0xFF) { + the_voice->vtft_filter_target = 0xFFFF; + } else { + the_voice->vtft_filter_target = the_voice->initial_filter >> 5; } - return; + } + return; - case 4: - { - emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; - the_voice->tremfrq = val; - the_voice->lfo1_speed = lfofreqtospeed[the_voice->tremfrq_lfo1_freq]; + case 2: + { + emu8k_voice_t *const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->pefe = val; - int divider = (the_voice->tremfrq_lfo1_tremolo < 0) ? 0x80 : 0x7F; - the_voice->fixed_lfo1_tremolo = ((int32_t)the_voice->tremfrq_lfo1_tremolo)*0x4000/divider; - } - return; + int divider = (the_voice->pefe_modenv_filter_height < 0) ? 0x80 : 0x7F; + the_voice->fixed_modenv_filter_height = ((int32_t) the_voice->pefe_modenv_filter_height) * 0x4000 / divider; - case 5: - { - emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; - the_voice->fm2frq2 = val; - the_voice->lfo2_speed = lfofreqtospeed[the_voice->fm2frq2_lfo2_freq]; - - int divider = (the_voice->fm2frq2_lfo2_vibrato < 0) ? 0x80 : 0x7F; - the_voice->fixed_lfo2_vibrato = ((int32_t)the_voice->fm2frq2_lfo2_vibrato)*0x4000/divider; - } - return; + divider = (the_voice->pefe_modenv_pitch_height < 0) ? 0x80 : 0x7F; + the_voice->fixed_modenv_pitch_height = ((int32_t) the_voice->pefe_modenv_pitch_height) * 0x4000 / divider; + } + return; - case 7: /*ID? I believe that this allows applications to know if the emu is in use by another application */ - emu8k->id = val; - return; - } - break; - - case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ - emu8k->cur_voice = (val & 31); - emu8k->cur_reg = ((val >> 5) & 7); - return; - } - emu8k_log("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg)<<5|emu8k->cur_voice, - emu8k->cur_reg,emu8k->cur_voice, val); + case 3: + { + emu8k_voice_t *const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->fmmod = val; + int divider = (the_voice->fmmod_lfo1_filt_mod < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_filt_mod = ((int32_t) the_voice->fmmod_lfo1_filt_mod) * 0x4000 / divider; + + divider = (the_voice->fmmod_lfo1_vibrato < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_vibrato = ((int32_t) the_voice->fmmod_lfo1_vibrato) * 0x4000 / divider; + } + return; + + case 4: + { + emu8k_voice_t *const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->tremfrq = val; + the_voice->lfo1_speed = lfofreqtospeed[the_voice->tremfrq_lfo1_freq]; + + int divider = (the_voice->tremfrq_lfo1_tremolo < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_tremolo = ((int32_t) the_voice->tremfrq_lfo1_tremolo) * 0x4000 / divider; + } + return; + + case 5: + { + emu8k_voice_t *const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->fm2frq2 = val; + the_voice->lfo2_speed = lfofreqtospeed[the_voice->fm2frq2_lfo2_freq]; + + int divider = (the_voice->fm2frq2_lfo2_vibrato < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo2_vibrato = ((int32_t) the_voice->fm2frq2_lfo2_vibrato) * 0x4000 / divider; + } + return; + + case 7: /*ID? I believe that this allows applications to know if the emu is in use by another application */ + emu8k->id = val; + return; + } + break; + + case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ + emu8k->cur_voice = (val & 31); + emu8k->cur_reg = ((val >> 5) & 7); + return; + } + emu8k_log("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg) << 5 | emu8k->cur_voice, + emu8k->cur_reg, emu8k->cur_voice, val); } -uint8_t emu8k_inb(uint16_t addr, void *p) +uint8_t +emu8k_inb(uint16_t addr, void *p) { - /* Reading a single byte is a feature that at least Impulse tracker uses, - * but only on detection code and not for odd addresses.*/ - if (addr & 1) - return emu8k_inw(addr & ~1, p) >> 1; - return emu8k_inw(addr, p) & 0xff; + /* Reading a single byte is a feature that at least Impulse tracker uses, + * but only on detection code and not for odd addresses.*/ + if (addr & 1) + return emu8k_inw(addr & ~1, p) >> 1; + return emu8k_inw(addr, p) & 0xff; } -void emu8k_outb(uint16_t addr, uint8_t val, void *p) +void +emu8k_outb(uint16_t addr, uint8_t val, void *p) { - /* TODO: AWE32 docs says that you cannot write in bytes, but if - * an app were to use this implementation, the content of the LS Byte would be lost.*/ - if (addr & 1) - emu8k_outw(addr & ~1, val << 8, p); - else - emu8k_outw(addr, val, p); + /* TODO: AWE32 docs says that you cannot write in bytes, but if + * an app were to use this implementation, the content of the LS Byte would be lost.*/ + if (addr & 1) + emu8k_outw(addr & ~1, val << 8, p); + else + emu8k_outw(addr, val, p); } /* TODO: This is not a correct emulation, just a workalike implementation. */ -void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engine, int count) +void +emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engine, int count) { - int pos; - for (pos = 0; pos < count; pos++) - { - double lfo_inter1 = chortable[engine->lfo_pos.int_address]; - // double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; + int pos; + for (pos = 0; pos < count; pos++) { + double lfo_inter1 = chortable[engine->lfo_pos.int_address]; + // double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; - double offset_lfo =lfo_inter1; //= lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0); - offset_lfo *= engine->lfodepth_multip; + double offset_lfo = lfo_inter1; //= lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0); + offset_lfo *= engine->lfodepth_multip; - /* Work left */ - double readdouble = (double)engine->write - (double)engine->delay_samples_central - offset_lfo; - int read = (int32_t)floor(readdouble); - int fraction_part = (readdouble - (double)read)*65536.0; - int next_value = read + 1; - if(read < 0) - { - read += EMU8K_LFOCHORUS_SIZE; - if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; - } - else if(next_value >= EMU8K_LFOCHORUS_SIZE) - { - next_value -= EMU8K_LFOCHORUS_SIZE; - if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; - } - int32_t dat1 = engine->chorus_left_buffer[read]; - int32_t dat2 = engine->chorus_left_buffer[next_value]; - dat1 += ((dat2-dat1)* fraction_part) >> 16; - - engine->chorus_left_buffer[engine->write] = *inbuf + ((dat1 * engine->feedback)>>8); - - - /* Work right */ - readdouble = (double)engine->write - (double)engine->delay_samples_central - engine->delay_offset_samples_right - offset_lfo; - read = (int32_t)floor(readdouble); - next_value = read + 1; - if(read < 0) - { - read += EMU8K_LFOCHORUS_SIZE; - if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; - } - else if(next_value >= EMU8K_LFOCHORUS_SIZE) - { - next_value -= EMU8K_LFOCHORUS_SIZE; - if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; - } - int32_t dat3 = engine->chorus_right_buffer[read]; - int32_t dat4 = engine->chorus_right_buffer[next_value]; - dat3 += ((dat4-dat3)* fraction_part) >> 16; - - engine->chorus_right_buffer[engine->write] = *inbuf + ((dat3 * engine->feedback)>>8); - - ++engine->write; - engine->write %= EMU8K_LFOCHORUS_SIZE; - engine->lfo_pos.addr +=engine->lfo_inc.addr; - engine->lfo_pos.int_address &= 0xFFFF; - - (*outbuf++) += dat1; - (*outbuf++) += dat3; - inbuf++; + /* Work left */ + double readdouble = (double) engine->write - (double) engine->delay_samples_central - offset_lfo; + int read = (int32_t) floor(readdouble); + int fraction_part = (readdouble - (double) read) * 65536.0; + int next_value = read + 1; + if (read < 0) { + read += EMU8K_LFOCHORUS_SIZE; + if (next_value < 0) + next_value += EMU8K_LFOCHORUS_SIZE; + } else if (next_value >= EMU8K_LFOCHORUS_SIZE) { + next_value -= EMU8K_LFOCHORUS_SIZE; + if (read >= EMU8K_LFOCHORUS_SIZE) + read -= EMU8K_LFOCHORUS_SIZE; } - + int32_t dat1 = engine->chorus_left_buffer[read]; + int32_t dat2 = engine->chorus_left_buffer[next_value]; + dat1 += ((dat2 - dat1) * fraction_part) >> 16; + + engine->chorus_left_buffer[engine->write] = *inbuf + ((dat1 * engine->feedback) >> 8); + + /* Work right */ + readdouble = (double) engine->write - (double) engine->delay_samples_central - engine->delay_offset_samples_right - offset_lfo; + read = (int32_t) floor(readdouble); + next_value = read + 1; + if (read < 0) { + read += EMU8K_LFOCHORUS_SIZE; + if (next_value < 0) + next_value += EMU8K_LFOCHORUS_SIZE; + } else if (next_value >= EMU8K_LFOCHORUS_SIZE) { + next_value -= EMU8K_LFOCHORUS_SIZE; + if (read >= EMU8K_LFOCHORUS_SIZE) + read -= EMU8K_LFOCHORUS_SIZE; + } + int32_t dat3 = engine->chorus_right_buffer[read]; + int32_t dat4 = engine->chorus_right_buffer[next_value]; + dat3 += ((dat4 - dat3) * fraction_part) >> 16; + + engine->chorus_right_buffer[engine->write] = *inbuf + ((dat3 * engine->feedback) >> 8); + + ++engine->write; + engine->write %= EMU8K_LFOCHORUS_SIZE; + engine->lfo_pos.addr += engine->lfo_inc.addr; + engine->lfo_pos.int_address &= 0xFFFF; + + (*outbuf++) += dat1; + (*outbuf++) += dat3; + inbuf++; + } } -int32_t emu8k_reverb_comb_work(emu8k_reverb_combfilter_t* comb, int32_t in) +int32_t +emu8k_reverb_comb_work(emu8k_reverb_combfilter_t *comb, int32_t in) { - - int32_t bufin; - /* get echo */ - int32_t output = comb->reflection[comb->read_pos]; - /* apply lowpass */ - comb->filterstore = (output*comb->damp2) + (comb->filterstore*comb->damp1); - /* appply feedback */ - bufin = in - (comb->filterstore*comb->feedback); - /* store new value in delayed buffer */ - comb->reflection[comb->read_pos] = bufin; - if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + int32_t bufin; + /* get echo */ + int32_t output = comb->reflection[comb->read_pos]; + /* apply lowpass */ + comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); + /* appply feedback */ + bufin = in - (comb->filterstore * comb->feedback); + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = bufin; - return output*comb->output_gain; + if (++comb->read_pos >= comb->bufsize) + comb->read_pos = 0; + + return output * comb->output_gain; } -int32_t emu8k_reverb_diffuser_work(emu8k_reverb_combfilter_t* comb, int32_t in) +int32_t +emu8k_reverb_diffuser_work(emu8k_reverb_combfilter_t *comb, int32_t in) { - - int32_t bufout = comb->reflection[comb->read_pos]; - /*diffuse*/ - int32_t bufin = -in + (bufout*comb->feedback); - int32_t output = bufout - (bufin*comb->feedback); - /* store new value in delayed buffer */ - comb->reflection[comb->read_pos] = bufin; - if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + int32_t bufout = comb->reflection[comb->read_pos]; + /*diffuse*/ + int32_t bufin = -in + (bufout * comb->feedback); + int32_t output = bufout - (bufin * comb->feedback); + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = bufin; - return output; + if (++comb->read_pos >= comb->bufsize) + comb->read_pos = 0; + + return output; } -int32_t emu8k_reverb_tail_work(emu8k_reverb_combfilter_t* comb, emu8k_reverb_combfilter_t* allpasses, int32_t in) +int32_t +emu8k_reverb_tail_work(emu8k_reverb_combfilter_t *comb, emu8k_reverb_combfilter_t *allpasses, int32_t in) { - int32_t output = comb->reflection[comb->read_pos]; - /* store new value in delayed buffer */ - comb->reflection[comb->read_pos] = in; - - //output = emu8k_reverb_allpass_work(&allpasses[0],output); - output = emu8k_reverb_diffuser_work(&allpasses[1],output); - output = emu8k_reverb_diffuser_work(&allpasses[2],output); - //output = emu8k_reverb_allpass_work(&allpasses[3],output); - - if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; - - return output; + int32_t output = comb->reflection[comb->read_pos]; + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = in; + + // output = emu8k_reverb_allpass_work(&allpasses[0],output); + output = emu8k_reverb_diffuser_work(&allpasses[1], output); + output = emu8k_reverb_diffuser_work(&allpasses[2], output); + // output = emu8k_reverb_allpass_work(&allpasses[3],output); + + if (++comb->read_pos >= comb->bufsize) + comb->read_pos = 0; + + return output; } -int32_t emu8k_reverb_damper_work(emu8k_reverb_combfilter_t* comb, int32_t in) +int32_t +emu8k_reverb_damper_work(emu8k_reverb_combfilter_t *comb, int32_t in) { - /* apply lowpass */ - comb->filterstore = (in*comb->damp2) + (comb->filterstore*comb->damp1); - return comb->filterstore; + /* apply lowpass */ + comb->filterstore = (in * comb->damp2) + (comb->filterstore * comb->damp1); + return comb->filterstore; } /* TODO: This is not a correct emulation, just a workalike implementation. */ -void emu8k_work_reverb(int32_t *inbuf, int32_t *outbuf, emu8k_reverb_eng_t *engine, int count) +void +emu8k_work_reverb(int32_t *inbuf, int32_t *outbuf, emu8k_reverb_eng_t *engine, int count) { - int pos; - if (engine->link_return_type) - { - for (pos = 0; pos < count; pos++) - { - int32_t dat1, dat2, in, in2; - in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); - in2 = (in * engine->refl_in_amp) >> 8; - dat2 = emu8k_reverb_comb_work(&engine->reflections[0], in2); - dat2 += emu8k_reverb_comb_work(&engine->reflections[1], in2); - dat1 = emu8k_reverb_comb_work(&engine->reflections[2], in2); - dat2 += emu8k_reverb_comb_work(&engine->reflections[3], in2); - dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); - dat2 += emu8k_reverb_comb_work(&engine->reflections[5], in2); - - dat1 += (emu8k_reverb_tail_work(&engine->tailL,&engine->allpass[0], in+dat1)*engine->link_return_amp) >> 8; - dat2 += (emu8k_reverb_tail_work(&engine->tailR,&engine->allpass[4], in+dat2)*engine->link_return_amp) >> 8; - - (*outbuf++) += (dat1 * engine->out_mix) >> 8; - (*outbuf++) += (dat2 * engine->out_mix) >> 8; - } + int pos; + if (engine->link_return_type) { + for (pos = 0; pos < count; pos++) { + int32_t dat1, dat2, in, in2; + in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); + in2 = (in * engine->refl_in_amp) >> 8; + dat2 = emu8k_reverb_comb_work(&engine->reflections[0], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[1], in2); + dat1 = emu8k_reverb_comb_work(&engine->reflections[2], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[3], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[5], in2); + + dat1 += (emu8k_reverb_tail_work(&engine->tailL, &engine->allpass[0], in + dat1) * engine->link_return_amp) >> 8; + dat2 += (emu8k_reverb_tail_work(&engine->tailR, &engine->allpass[4], in + dat2) * engine->link_return_amp) >> 8; + + (*outbuf++) += (dat1 * engine->out_mix) >> 8; + (*outbuf++) += (dat2 * engine->out_mix) >> 8; } - else - { - for (pos = 0; pos < count; pos++) - { - int32_t dat1, dat2, in, in2; - in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); - in2 = (in * engine->refl_in_amp) >> 8; - dat1 = emu8k_reverb_comb_work(&engine->reflections[0], in2); - dat1 += emu8k_reverb_comb_work(&engine->reflections[1], in2); - dat1 += emu8k_reverb_comb_work(&engine->reflections[2], in2); - dat1 += emu8k_reverb_comb_work(&engine->reflections[3], in2); - dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); - dat1 += emu8k_reverb_comb_work(&engine->reflections[5], in2); - dat2 = dat1; - - dat1 += (emu8k_reverb_tail_work(&engine->tailL,&engine->allpass[0], in+dat1)*engine->link_return_amp) >> 8; - dat2 += (emu8k_reverb_tail_work(&engine->tailR,&engine->allpass[4], in+dat2)*engine->link_return_amp) >> 8; - - (*outbuf++) += (dat1 * engine->out_mix) >> 8; - (*outbuf++) += (dat2 * engine->out_mix) >> 8; - } + } else { + for (pos = 0; pos < count; pos++) { + int32_t dat1, dat2, in, in2; + in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); + in2 = (in * engine->refl_in_amp) >> 8; + dat1 = emu8k_reverb_comb_work(&engine->reflections[0], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[1], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[2], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[3], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[5], in2); + dat2 = dat1; + + dat1 += (emu8k_reverb_tail_work(&engine->tailL, &engine->allpass[0], in + dat1) * engine->link_return_amp) >> 8; + dat2 += (emu8k_reverb_tail_work(&engine->tailR, &engine->allpass[4], in + dat2) * engine->link_return_amp) >> 8; + + (*outbuf++) += (dat1 * engine->out_mix) >> 8; + (*outbuf++) += (dat2 * engine->out_mix) >> 8; } + } } -void emu8k_work_eq(int32_t *inoutbuf, int count) +void +emu8k_work_eq(int32_t *inoutbuf, int count) { - // TODO: Work EQ over buf + // TODO: Work EQ over buf } - -int32_t emu8k_vol_slide(emu8k_slide_t* slide, int32_t target) +int32_t +emu8k_vol_slide(emu8k_slide_t *slide, int32_t target) { + if (slide->last < target) { + slide->last += 0x400; + if (slide->last > target) + slide->last = target; + } else if (slide->last > target) { + slide->last -= 0x400; if (slide->last < target) - { - slide->last+=0x400; - if (slide->last > target) slide->last = target; - } - else if (slide->last > target) - { - slide->last-=0x400; - if (slide->last < target) slide->last = target; - } - return slide->last; + slide->last = target; + } + return slide->last; } -//int32_t old_pitch[32]={0}; -//int32_t old_cut[32]={0}; -//int32_t old_vol[32]={0}; -void emu8k_update(emu8k_t *emu8k) +// int32_t old_pitch[32]={0}; +// int32_t old_cut[32]={0}; +// int32_t old_vol[32]={0}; +void +emu8k_update(emu8k_t *emu8k) { - int new_pos = (sound_pos_global * 44100) / 48000; - if (emu8k->pos >= new_pos) - return; + int new_pos = (sound_pos_global * 44100) / 48000; + if (emu8k->pos >= new_pos) + return; - int32_t *buf; - emu8k_voice_t* emu_voice; - int pos; - int c; + int32_t *buf; + emu8k_voice_t *emu_voice; + int pos; + int c; - /* Clean the buffers since we will accumulate into them. */ - buf = &emu8k->buffer[emu8k->pos*2]; - memset(buf, 0, 2*(new_pos-emu8k->pos)*sizeof(emu8k->buffer[0])); - memset(&emu8k->chorus_in_buffer[emu8k->pos], 0, (new_pos-emu8k->pos)*sizeof(emu8k->chorus_in_buffer[0])); - memset(&emu8k->reverb_in_buffer[emu8k->pos], 0, (new_pos-emu8k->pos)*sizeof(emu8k->reverb_in_buffer[0])); + /* Clean the buffers since we will accumulate into them. */ + buf = &emu8k->buffer[emu8k->pos * 2]; + memset(buf, 0, 2 * (new_pos - emu8k->pos) * sizeof(emu8k->buffer[0])); + memset(&emu8k->chorus_in_buffer[emu8k->pos], 0, (new_pos - emu8k->pos) * sizeof(emu8k->chorus_in_buffer[0])); + memset(&emu8k->reverb_in_buffer[emu8k->pos], 0, (new_pos - emu8k->pos) * sizeof(emu8k->reverb_in_buffer[0])); - /* Voices section */ - for (c = 0; c < 32; c++) - { - emu_voice = &emu8k->voice[c]; - buf = &emu8k->buffer[emu8k->pos*2]; - - for (pos = emu8k->pos; pos < new_pos; pos++) - { - int32_t dat; + /* Voices section */ + for (c = 0; c < 32; c++) { + emu_voice = &emu8k->voice[c]; + buf = &emu8k->buffer[emu8k->pos * 2]; - /* Waveform oscillator */ + for (pos = emu8k->pos; pos < new_pos; pos++) { + int32_t dat; + + if (emu_voice->cvcf_curr_volume) { + /* Waveform oscillator */ #ifdef RESAMPLER_LINEAR - dat = EMU8K_READ_INTERP_LINEAR(emu8k, emu_voice->addr.int_address, - emu_voice->addr.fract_address); + dat = EMU8K_READ_INTERP_LINEAR(emu8k, emu_voice->addr.int_address, + emu_voice->addr.fract_address); #elif defined RESAMPLER_CUBIC - dat = EMU8K_READ_INTERP_CUBIC(emu8k, emu_voice->addr.int_address, - emu_voice->addr.fract_address); + dat = EMU8K_READ_INTERP_CUBIC(emu8k, emu_voice->addr.int_address, + emu_voice->addr.fract_address); #endif - /* Filter section */ - if (emu_voice->filterq_idx || emu_voice->cvcf_curr_filt_ctoff != 0xFFFF ) - { - int cutoff = emu_voice->cvcf_curr_filt_ctoff >> 8; - const int64_t coef0 = filt_coeffs[emu_voice->filterq_idx][cutoff][0]; - const int64_t coef1 = filt_coeffs[emu_voice->filterq_idx][cutoff][1]; - const int64_t coef2 = filt_coeffs[emu_voice->filterq_idx][cutoff][2]; - /* clip at twice the range */ - #define ClipBuffer(buf) (buf < -16777216) ? -16777216 : (buf > 16777216) ? 16777216 : buf + /* Filter section */ + if (emu_voice->filterq_idx || emu_voice->cvcf_curr_filt_ctoff != 0xFFFF) { + int cutoff = emu_voice->cvcf_curr_filt_ctoff >> 8; + const int64_t coef0 = filt_coeffs[emu_voice->filterq_idx][cutoff][0]; + const int64_t coef1 = filt_coeffs[emu_voice->filterq_idx][cutoff][1]; + const int64_t coef2 = filt_coeffs[emu_voice->filterq_idx][cutoff][2]; +/* clip at twice the range */ +#define ClipBuffer(buf) (buf < -16777216) ? -16777216 : (buf > 16777216) ? 16777216 \ + : buf - #ifdef FILTER_INITIAL - #define NOOP(x) (void)x; - NOOP(coef1) - /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one doesn't). - * Work in 24bits. */ - dat = (dat * emu_voice->filt_att) >> 8; - - int64_t vhp = ((-emu_voice->filt_buffer[0] * coef2) >> 24) - emu_voice->filt_buffer[1] - dat; - emu_voice->filt_buffer[1] += (emu_voice->filt_buffer[0] * coef0) >> 24; - emu_voice->filt_buffer[0] += (vhp * coef0) >> 24; - dat = (int32_t)(emu_voice->filt_buffer[1] >> 8); - if (dat > 32767) { dat = 32767; } - else if (dat < -32768) { dat = -32768; } - - #elif defined FILTER_MOOG - - /*move to 24bits*/ - dat <<= 8; - - dat -= (coef2 * emu_voice->filt_buffer[4]) >> 24; /*feedback*/ - int64_t t1 = emu_voice->filt_buffer[1]; - emu_voice->filt_buffer[1] = ((dat + emu_voice->filt_buffer[0]) * coef0 - emu_voice->filt_buffer[1] * coef1) >> 24; - emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); - - int64_t t2 = emu_voice->filt_buffer[2]; - emu_voice->filt_buffer[2] = ((emu_voice->filt_buffer[1] + t1) * coef0 - emu_voice->filt_buffer[2] * coef1) >> 24; - emu_voice->filt_buffer[2] = ClipBuffer(emu_voice->filt_buffer[2]); - - int64_t t3 = emu_voice->filt_buffer[3]; - emu_voice->filt_buffer[3] = ((emu_voice->filt_buffer[2] + t2) * coef0 - emu_voice->filt_buffer[3] * coef1) >> 24; - emu_voice->filt_buffer[3] = ClipBuffer(emu_voice->filt_buffer[3]); - - emu_voice->filt_buffer[4] = ((emu_voice->filt_buffer[3] + t3) * coef0 - emu_voice->filt_buffer[4] * coef1) >> 24; - emu_voice->filt_buffer[4] = ClipBuffer(emu_voice->filt_buffer[4]); - - emu_voice->filt_buffer[0] = ClipBuffer(dat); - - dat = (int32_t)(emu_voice->filt_buffer[4] >> 8); - if (dat > 32767) { dat = 32767; } - else if (dat < -32768) { dat = -32768; } - - #elif defined FILTER_CONSTANT - - /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one is constant gain). - * Also stay at 24bits.*/ - dat = (dat * emu_voice->filt_att) >> 8; - - emu_voice->filt_buffer[0] = (coef1 * emu_voice->filt_buffer[0] - + coef0 * (dat + - ((coef2 * (emu_voice->filt_buffer[0] - emu_voice->filt_buffer[1]))>>24)) - ) >> 24; - emu_voice->filt_buffer[1] = (coef1 * emu_voice->filt_buffer[1] - + coef0 * emu_voice->filt_buffer[0]) >> 24; - - emu_voice->filt_buffer[0] = ClipBuffer(emu_voice->filt_buffer[0]); - emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); - - dat = (int32_t)(emu_voice->filt_buffer[1] >> 8); - if (dat > 32767) { dat = 32767; } - else if (dat < -32768) { dat = -32768; } - - #endif - - } - if (( emu8k->hwcf3 & 0x04) && !CCCA_DMA_ACTIVE(emu_voice->ccca)) - { - /*volume and pan*/ - dat = (dat * emu_voice->cvcf_curr_volume) >> 16; - - (*buf++) += (dat * emu_voice->vol_l) >> 8; - (*buf++) += (dat * emu_voice->vol_r) >> 8; - - /* Effects section */ - if (emu_voice->ptrx_revb_send > 0) - { - emu8k->reverb_in_buffer[pos]+=(dat*emu_voice->ptrx_revb_send) >> 8; - } - if (emu_voice->csl_chor_send > 0) - { - emu8k->chorus_in_buffer[pos]+=(dat*emu_voice->csl_chor_send) >> 8; - } - } - - if ( emu_voice->env_engine_on) - { - int32_t attenuation = emu_voice->initial_att; - int32_t filtercut = emu_voice->initial_filter; - int32_t currentpitch = emu_voice->ip; - /* run envelopes */ - emu8k_envelope_t *volenv = &emu_voice->vol_envelope; - switch (volenv->state) - { - case ENV_DELAY: - volenv->delay_samples--; - if (volenv->delay_samples <=0) - { - volenv->state=ENV_ATTACK; - volenv->delay_samples=0; - } - attenuation = 0x1FFFFF; - break; - - case ENV_ATTACK: - /* Attack amount is in linear amplitude */ - volenv->value_amp_hz += volenv->attack_amount_amp_hz; - if (volenv->value_amp_hz >= (1 << 21)) - { - volenv->value_amp_hz = 1 << 21; - volenv->value_db_oct = 0; - if (volenv->hold_samples) - { - volenv->state = ENV_HOLD; - } - else - { - /* RAMP_UP since db value is inverted and it is 0 at this point. */ - volenv->state = ENV_RAMP_UP; - } - } - attenuation += env_vol_amplitude_to_db[volenv->value_amp_hz >> 5] << 5; - break; - - case ENV_HOLD: - volenv->hold_samples--; - if (volenv->hold_samples <=0) - { - volenv->state=ENV_RAMP_UP; - } - attenuation += volenv->value_db_oct; - break; - - case ENV_RAMP_DOWN: - /* Decay/release amount is in fraction of dBs and is always positive */ - volenv->value_db_oct -= volenv->ramp_amount_db_oct; - if (volenv->value_db_oct <= volenv->sustain_value_db_oct) - { - volenv->value_db_oct = volenv->sustain_value_db_oct; - volenv->state = ENV_SUSTAIN; - } - attenuation += volenv->value_db_oct; - break; - - case ENV_RAMP_UP: - /* Decay/release amount is in fraction of dBs and is always positive */ - volenv->value_db_oct += volenv->ramp_amount_db_oct; - if (volenv->value_db_oct >= volenv->sustain_value_db_oct) - { - volenv->value_db_oct = volenv->sustain_value_db_oct; - volenv->state = ENV_SUSTAIN; - } - attenuation += volenv->value_db_oct; - break; - - case ENV_SUSTAIN: - attenuation += volenv->value_db_oct; - break; - - case ENV_STOPPED: - attenuation = 0x1FFFFF; - break; - } - - emu8k_envelope_t *modenv = &emu_voice->mod_envelope; - switch (modenv->state) - { - case ENV_DELAY: - modenv->delay_samples--; - if (modenv->delay_samples <=0) - { - modenv->state=ENV_ATTACK; - modenv->delay_samples=0; - } - break; - - case ENV_ATTACK: - /* Attack amount is in linear amplitude */ - modenv->value_amp_hz += modenv->attack_amount_amp_hz; - modenv->value_db_oct = env_mod_hertz_to_octave[modenv->value_amp_hz >> 5] << 5; - if (modenv->value_amp_hz >= (1 << 21)) - { - modenv->value_amp_hz = 1 << 21; - modenv->value_db_oct = 1 << 21; - if (modenv->hold_samples) - { - modenv->state = ENV_HOLD; - } - else - { - modenv->state = ENV_RAMP_DOWN; - } - } - break; - - case ENV_HOLD: - modenv->hold_samples--; - if (modenv->hold_samples <=0) - { - modenv->state=ENV_RAMP_UP; - } - break; - - case ENV_RAMP_DOWN: - /* Decay/release amount is in fraction of octave and is always positive */ - modenv->value_db_oct -= modenv->ramp_amount_db_oct; - if (modenv->value_db_oct <= modenv->sustain_value_db_oct) - { - modenv->value_db_oct = modenv->sustain_value_db_oct; - modenv->state = ENV_SUSTAIN; - } - break; - - case ENV_RAMP_UP: - /* Decay/release amount is in fraction of octave and is always positive */ - modenv->value_db_oct += modenv->ramp_amount_db_oct; - if (modenv->value_db_oct >= modenv->sustain_value_db_oct) - { - modenv->value_db_oct = modenv->sustain_value_db_oct; - modenv->state = ENV_SUSTAIN; - } - break; - } - - /* run lfos */ - if (emu_voice->lfo1_delay_samples) - { - emu_voice->lfo1_delay_samples--; - } - else - { - emu_voice->lfo1_count.addr += emu_voice->lfo1_speed; - emu_voice->lfo1_count.int_address &= 0xFFFF; - } - if (emu_voice->lfo2_delay_samples) - { - emu_voice->lfo2_delay_samples--; - } - else - { - emu_voice->lfo2_count.addr += emu_voice->lfo2_speed; - emu_voice->lfo2_count.int_address &= 0xFFFF; - } - - - if (emu_voice->fixed_modenv_pitch_height) - { - /* modenv range 1<<21, pitch height range 1<<14 desired range 0x1000 (+/-one octave) */ - currentpitch += ((modenv->value_db_oct>>9)*emu_voice->fixed_modenv_pitch_height) >> 14; - } - - if (emu_voice->fixed_lfo1_vibrato) - { - /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ - int32_t lfo1_vibrato = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_vibrato) >> 17; - currentpitch += lfo1_vibrato; - } - if (emu_voice->fixed_lfo2_vibrato) - { - /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ - int32_t lfo2_vibrato = (lfotable[emu_voice->lfo2_count.int_address]*emu_voice->fixed_lfo2_vibrato) >> 17; - currentpitch += lfo2_vibrato; - } - - if (emu_voice->fixed_modenv_filter_height) - { - /* modenv range 1<<21, pitch height range 1<<14 desired range 0x200000 (+/-full filter range) */ - filtercut += ((modenv->value_db_oct>>9)*emu_voice->fixed_modenv_filter_height) >> 5; - } - - if (emu_voice->fixed_lfo1_filt_mod) - { - /* table range 1<<15, pitch mod range 1<<14 desired range 0x100000 (+/-three octaves) */ - int32_t lfo1_filtmod = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_filt_mod) >> 9; - filtercut += lfo1_filtmod; - } - - if (emu_voice->fixed_lfo1_tremolo) - { - /* table range 1<<15, pitch mod range 1<<14 desired range 0x40000 (+/-12dBs). */ - int32_t lfo1_tremolo = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_tremolo) >> 11; - attenuation += lfo1_tremolo; - } - - if (currentpitch > 0xFFFF) currentpitch = 0xFFFF; - if (currentpitch < 0) currentpitch = 0; - if (attenuation > 0x1FFFFF) attenuation = 0x1FFFFF; - if (attenuation < 0) attenuation = 0; - if (filtercut > 0x1FFFFF) filtercut = 0x1FFFFF; - if (filtercut < 0) filtercut = 0; - - emu_voice->vtft_vol_target = env_vol_db_to_vol_target[attenuation >> 5]; - emu_voice->vtft_filter_target = filtercut >> 5; - emu_voice->ptrx_pit_target = freqtable[currentpitch]>>18; - - } -/* -I've recopilated these sentences to get an idea of how to loop - -- Set its PSST register and its CLS register to zero to cause no loops to occur. --Setting the Loop Start Offset and the Loop End Offset to the same value, will cause the oscillator to loop the entire memory. - --Setting the PlayPosition greater than the Loop End Offset, will cause the oscillator to play in reverse, back to the Loop End Offset. - It's pretty neat, but appears to be uncontrollable (the rate at which the samples are played in reverse). - --Note that due to interpolator offset, the actual loop point is one greater than the start address --Note that due to interpolator offset, the actual loop point will end at an address one greater than the loop address --Note that the actual audio location is the point 1 word higher than this value due to interpolation offset --In programs that use the awe, they generally set the loop address as "loopaddress -1" to compensate for the above. -(Note: I am already using address+1 in the interpolators so these things are already as they should.) -*/ - emu_voice->addr.addr += ((uint64_t)emu_voice->cpf_curr_pitch) << 18; - if (emu_voice->addr.addr >= emu_voice->loop_end.addr) - { - emu_voice->addr.int_address -= (emu_voice->loop_end.int_address - emu_voice->loop_start.int_address); - emu_voice->addr.int_address &= EMU8K_MEM_ADDRESS_MASK; - } - - /* TODO: How and when are the target and current values updated */ - emu_voice->cpf_curr_pitch = emu_voice->ptrx_pit_target; - emu_voice->cvcf_curr_volume = emu8k_vol_slide(&emu_voice->volumeslide,emu_voice->vtft_vol_target); - emu_voice->cvcf_curr_filt_ctoff = emu_voice->vtft_filter_target; - } - - /* Update EMU voice registers. */ - emu_voice->ccca = (((uint32_t)emu_voice->ccca_qcontrol) << 24) | emu_voice->addr.int_address; - emu_voice->cpf_curr_frac_addr = emu_voice->addr.fract_address; - - //if ( emu_voice->cvcf_curr_volume != old_vol[c]) { - // emu8k_log("EMUVOL (%d):%d\n", c, emu_voice->cvcf_curr_volume); - // old_vol[c]=emu_voice->cvcf_curr_volume; - //} - //emu8k_log("EMUFILT :%d\n", emu_voice->cvcf_curr_filt_ctoff); - } - - - buf = &emu8k->buffer[emu8k->pos*2]; - emu8k_work_reverb(&emu8k->reverb_in_buffer[emu8k->pos], buf, &emu8k->reverb_engine, new_pos-emu8k->pos); - emu8k_work_chorus(&emu8k->chorus_in_buffer[emu8k->pos], buf, &emu8k->chorus_engine, new_pos-emu8k->pos); - emu8k_work_eq(buf, new_pos-emu8k->pos); - - // Clip signal - for (pos = emu8k->pos; pos < new_pos; pos++) - { - if (buf[0] < -32768) - buf[0] = -32768; - else if (buf[0] > 32767) - buf[0] = 32767; - - if (buf[1] < -32768) - buf[1] = -32768; - else if (buf[1] > 32767) - buf[1] = 32767; - - buf += 2; - } - - /* Update EMU clock. */ - emu8k->wc += (new_pos - emu8k->pos); - - emu8k->pos = new_pos; -} -/* onboard_ram in kilobytes */ -void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) -{ - uint32_t const BLOCK_SIZE_WORDS = 0x10000; - FILE *f; - int c; - double out; - - f = rom_fopen(L"roms/sound/awe32.raw", L"rb"); - if (!f) - fatal("AWE32.RAW not found\n"); - - emu8k->rom = malloc(1024 * 1024); - if (fread(emu8k->rom, 1, 1048576, f) != 1048576) - fatal("emu8k_init(): Error reading data\n"); - fclose(f); - /*AWE-DUMP creates ROM images offset by 2 bytes, so if we detect this - then correct it*/ - if (emu8k->rom[3] == 0x314d && emu8k->rom[4] == 0x474d) - { - memmove(&emu8k->rom[0], &emu8k->rom[1], (1024 * 1024) - 2); - emu8k->rom[0x7ffff] = 0; - } - - emu8k->empty = malloc(2*BLOCK_SIZE_WORDS); - memset(emu8k->empty, 0, 2*BLOCK_SIZE_WORDS); - - int j=0; - for (;j<0x8;j++) - { - emu8k->ram_pointers[j]=emu8k->rom+(j*BLOCK_SIZE_WORDS); - } - for (;j<0x20;j++) - { - emu8k->ram_pointers[j]=emu8k->empty; - } - - if (onboard_ram) - { - /*Clip to 28MB, since that's the max that we can address. */ - if (onboard_ram > 0x7000) onboard_ram = 0x7000; - emu8k->ram = malloc(onboard_ram * 1024); - memset(emu8k->ram, 0, onboard_ram * 1024); - const int i_end=onboard_ram>>7; - int i=0; - for(;iram_pointers[j]=emu8k->ram+(i*BLOCK_SIZE_WORDS); - } - emu8k->ram_end_addr = EMU8K_RAM_MEM_START + (onboard_ram<<9); - } - else - { - emu8k->ram = 0; - emu8k->ram_end_addr = EMU8K_RAM_MEM_START; - } - for (;j < 0x100;j++) - { - emu8k->ram_pointers[j]=emu8k->empty; - - } - - io_sethandler(emu_addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - io_sethandler(emu_addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - io_sethandler(emu_addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - - /*Create frequency table. (Convert initial pitch register value to a linear speed change) - * The input is encoded such as 0xe000 is center note (no pitch shift) - * and from then on , changing up or down 0x1000 (4096) increments/decrements an octave. - * Note that this is in reference to the 44.1Khz clock that the channels play at. - * The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. - */ - for (c = 0; c < 0x10000; c++) - { - freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0); - } - /* Shortcut: minimum pitch equals stopped. I don't really know if this is true, but it's better - * since some programs set the pitch to 0 for unused channels. */ - freqtable[0] = 0; - - /* starting at 65535 because it is used for "volume target" register conversion. */ - out = 65535.0; - for (c = 0; c < 256; c++) - { - attentable[c] = (int32_t)out; - out /= sqrt(1.09018); /*0.375 dB steps*/ - } - /* Shortcut: max attenuation is silent, not -96dB. */ - attentable[255]=0; - - /* Note: these two tables have "db" inverted: 0 dB is max volume, 65535 "db" (-96.32dBFS) is silence. - * Important: Using 65535 as max output value because this is intended to be used with the volume target register! */ - out = 65535.0; - for (c = 0; c < 0x10000; c++) - { - //double db = -(c*6.0205999/65535.0)*16.0; - //out = powf(10.f,db/20.f) * 65536.0; - env_vol_db_to_vol_target[c] = (int32_t)out; - /* calculated from the 65536th root of 65536 */ - out /= 1.00016923970; - } - /* Shortcut: max attenuation is silent, not -96dB. */ - env_vol_db_to_vol_target[0x10000-1]=0; - /* One more position to accept max value being 65536. */ - env_vol_db_to_vol_target[0x10000]=0; - - for (c = 1; c < 0x10000; c++) - { - out = -680.32142884264* 20.0 * log10(((double)c)/65535.0); - env_vol_amplitude_to_db[c] = (int32_t)out; - } - /*Shortcut: max attenuation is silent, not -96dB.*/ - env_vol_amplitude_to_db[0]=65535; - /* One more position to accept max value being 65536. */ - env_vol_amplitude_to_db[0x10000]=0; - - - for (c = 1; c < 0x10000; c++) - { - out = log2((((double)c)/0x10000)+1.0) *65536.0; - env_mod_hertz_to_octave[c] = (int32_t)out; - } - /*No hertz change, no octave change. */ - env_mod_hertz_to_octave[0]=0; - /* One more position to accept max value being 65536. */ - env_mod_hertz_to_octave[0x10000]=65536; - - - /* This formula comes from vince vu/judge dredd's awe32p10 and corresponds to what the freebsd/linux AWE32 driver has. */ - float millis; - for (c=0;c<128;c++) - { - if (c==0) - millis = 0; /* This means never attack. */ - else if (c < 32) - millis = 11878.0/c; - else - millis = 360*exp((c - 32) / (16.0/log(1.0/2.0))); - - env_attack_to_samples[c] = 44.1*millis; - /* This is an alternate formula with linear increments, but probably incorrect: - * millis = (256+4096*(0x7F-c)) */ - } - - /* The LFOs use a triangular waveform starting at zero and going 1/-1/1/-1. - * This table is stored in signed 16bits precision, with a period of 65536 samples */ - for (c = 0; c < 65536; c++) - { - int d = (c + 16384) & 65535; - if (d >= 32768) - lfotable[c] = 32768 + ((32768 - d)*2); - else - lfotable[c] = (d*2) - 32768; - } - /* The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. */ - out = 0.01; - for (c = 0; c < 256; c++) - { - lfofreqtospeed[c] = (uint64_t)(out *65536.0/44100.0 * 65536.0 * 65536.0); - out += 0.042; - } - - for (c = 0; c < 65536; c++) - { - chortable[c] = sin(c*M_PI/32768.0); - } - - - /* Filter coefficients tables. Note: Values are multiplied by *16777216 to left shift 24 bits. (i.e. 8.24 fixed point) */ - int qidx; - for (qidx = 0; qidx < 16; qidx++) - { - out = 125.0; /* Start at 125Hz */ - for (c = 0; c < 256; c++) - { #ifdef FILTER_INITIAL - float w0 = sin(2.0*M_PI*out / 44100.0); - /* The value 102.5f has been selected a bit randomly. Pretends to reach 0.2929 at w0 = 1.0 */ - float q = (qidx / 102.5f) * (1.0 + 1.0 / w0); - /* Limit max value. Else it would be 470. */ - if (q > 200) q=200; - filt_coeffs[qidx][c][0] = (int32_t)(w0 * 16777216.0); - filt_coeffs[qidx][c][1] = 16777216.0; - filt_coeffs[qidx][c][2] = (int32_t)((1.0f / (0.7071f + q)) * 16777216.0); -#elif defined FILTER_MOOG - float w0 = sin(2.0*M_PI*out / 44100.0); - float q_factor = 1.0f - w0; - float p = w0 + 0.8f * w0 * q_factor; - float f = p + p - 1.0f; - float resonance = (1.0-pow(2.0,-qidx*24.0/90.0))*0.8; - float q = resonance * (1.0f + 0.5f * q_factor * (w0 + 5.6f * q_factor * q_factor)); - filt_coeffs[qidx][c][0] = (int32_t)(p * 16777216.0); - filt_coeffs[qidx][c][1] = (int32_t)(f * 16777216.0); - filt_coeffs[qidx][c][2] = (int32_t)(q * 16777216.0); +# define NOOP(x) (void) x; + NOOP(coef1) + /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one doesn't). + * Work in 24bits. */ + dat = (dat * emu_voice->filt_att) >> 8; + + int64_t vhp = ((-emu_voice->filt_buffer[0] * coef2) >> 24) - emu_voice->filt_buffer[1] - dat; + emu_voice->filt_buffer[1] += (emu_voice->filt_buffer[0] * coef0) >> 24; + emu_voice->filt_buffer[0] += (vhp * coef0) >> 24; + dat = (int32_t) (emu_voice->filt_buffer[1] >> 8); + if (dat > 32767) { + dat = 32767; + } else if (dat < -32768) { + dat = -32768; + } + +#elif defined FILTER_MOOG + + /*move to 24bits*/ + dat <<= 8; + + dat -= (coef2 * emu_voice->filt_buffer[4]) >> 24; /*feedback*/ + int64_t t1 = emu_voice->filt_buffer[1]; + emu_voice->filt_buffer[1] = ((dat + emu_voice->filt_buffer[0]) * coef0 - emu_voice->filt_buffer[1] * coef1) >> 24; + emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); + + int64_t t2 = emu_voice->filt_buffer[2]; + emu_voice->filt_buffer[2] = ((emu_voice->filt_buffer[1] + t1) * coef0 - emu_voice->filt_buffer[2] * coef1) >> 24; + emu_voice->filt_buffer[2] = ClipBuffer(emu_voice->filt_buffer[2]); + + int64_t t3 = emu_voice->filt_buffer[3]; + emu_voice->filt_buffer[3] = ((emu_voice->filt_buffer[2] + t2) * coef0 - emu_voice->filt_buffer[3] * coef1) >> 24; + emu_voice->filt_buffer[3] = ClipBuffer(emu_voice->filt_buffer[3]); + + emu_voice->filt_buffer[4] = ((emu_voice->filt_buffer[3] + t3) * coef0 - emu_voice->filt_buffer[4] * coef1) >> 24; + emu_voice->filt_buffer[4] = ClipBuffer(emu_voice->filt_buffer[4]); + + emu_voice->filt_buffer[0] = ClipBuffer(dat); + + dat = (int32_t) (emu_voice->filt_buffer[4] >> 8); + if (dat > 32767) { + dat = 32767; + } else if (dat < -32768) { + dat = -32768; + } + #elif defined FILTER_CONSTANT - float q = (1.0-pow(2.0,-qidx*24.0/90.0))*0.8; - float coef0 = sin(2.0*M_PI*out / 44100.0); - float coef1 = 1.0 - coef0; - float coef2 = q * (1.0 + 1.0 / coef1); - filt_coeffs[qidx][c][0] = (int32_t)(coef0 * 16777216.0); - filt_coeffs[qidx][c][1] = (int32_t)(coef1 * 16777216.0); - filt_coeffs[qidx][c][2] = (int32_t)(coef2 * 16777216.0); -#endif //FILTER_TYPE - /* 42.66 divisions per octave (the doc says quarter seminotes which is 48, but then it would be almost an octave less) */ - out *= 1.016378315; - /* 42 divisions. This moves the max frequency to 8.5Khz.*/ - //out *= 1.0166404394; - /* This is a linear increment method, that corresponds to the NRPN table, but contradicts the EMU8KPRM doc: */ - //out = 100.0 + (c+1.0)*31.25; //31.25Hz steps */ + + /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one is constant gain). + * Also stay at 24bits.*/ + dat = (dat * emu_voice->filt_att) >> 8; + + emu_voice->filt_buffer[0] = (coef1 * emu_voice->filt_buffer[0] + + coef0 * (dat + ((coef2 * (emu_voice->filt_buffer[0] - emu_voice->filt_buffer[1])) >> 24))) + >> 24; + emu_voice->filt_buffer[1] = (coef1 * emu_voice->filt_buffer[1] + + coef0 * emu_voice->filt_buffer[0]) + >> 24; + + emu_voice->filt_buffer[0] = ClipBuffer(emu_voice->filt_buffer[0]); + emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); + + dat = (int32_t) (emu_voice->filt_buffer[1] >> 8); + if (dat > 32767) { + dat = 32767; + } else if (dat < -32768) { + dat = -32768; + } + +#endif } - } - /* NOTE! read_pos and buffer content is implicitly initialized to zero by the sb_t structure memset on sb_awe32_init() */ - emu8k->reverb_engine.reflections[0].bufsize=2*REV_BUFSIZE_STEP; - emu8k->reverb_engine.reflections[1].bufsize=4*REV_BUFSIZE_STEP; - emu8k->reverb_engine.reflections[2].bufsize=8*REV_BUFSIZE_STEP; - emu8k->reverb_engine.reflections[3].bufsize=13*REV_BUFSIZE_STEP; - emu8k->reverb_engine.reflections[4].bufsize=19*REV_BUFSIZE_STEP; - emu8k->reverb_engine.reflections[5].bufsize=26*REV_BUFSIZE_STEP; + if ((emu8k->hwcf3 & 0x04) && !CCCA_DMA_ACTIVE(emu_voice->ccca)) { + /*volume and pan*/ + dat = (dat * emu_voice->cvcf_curr_volume) >> 16; - /*This is a bit random.*/ - for (c=0;c<4;c++) - { - emu8k->reverb_engine.allpass[3-c].feedback=0.5; - emu8k->reverb_engine.allpass[3-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55; - emu8k->reverb_engine.allpass[7-c].feedback=0.5; - emu8k->reverb_engine.allpass[7-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55; - } - + (*buf++) += (dat * emu_voice->vol_l) >> 8; + (*buf++) += (dat * emu_voice->vol_r) >> 8; - - /* Cubic Resampling ( 4point cubic spline) */ - double const resdouble = 1.0/(double)CUBIC_RESOLUTION; - for (c = 0; c < CUBIC_RESOLUTION; c++) - { - double x = (double)c * resdouble; - /* Cubic resolution is made of four table, but I've put them all in one table to optimize memory access. */ - cubic_table[c*4] = (-0.5 * x * x * x + x * x - 0.5 * x) ; - cubic_table[c*4+1] = ( 1.5 * x * x * x - 2.5 * x * x + 1.0) ; - cubic_table[c*4+2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x) ; - cubic_table[c*4+3] = ( 0.5 * x * x * x - 0.5 * x * x) ; + /* Effects section */ + if (emu_voice->ptrx_revb_send > 0) { + emu8k->reverb_in_buffer[pos] += (dat * emu_voice->ptrx_revb_send) >> 8; + } + if (emu_voice->csl_chor_send > 0) { + emu8k->chorus_in_buffer[pos] += (dat * emu_voice->csl_chor_send) >> 8; + } + } + } + + if (emu_voice->env_engine_on) { + int32_t attenuation = emu_voice->initial_att; + int32_t filtercut = emu_voice->initial_filter; + int32_t currentpitch = emu_voice->ip; + /* run envelopes */ + emu8k_envelope_t *volenv = &emu_voice->vol_envelope; + switch (volenv->state) { + case ENV_DELAY: + volenv->delay_samples--; + if (volenv->delay_samples <= 0) { + volenv->state = ENV_ATTACK; + volenv->delay_samples = 0; + } + attenuation = 0x1FFFFF; + break; + + case ENV_ATTACK: + /* Attack amount is in linear amplitude */ + volenv->value_amp_hz += volenv->attack_amount_amp_hz; + if (volenv->value_amp_hz >= (1 << 21)) { + volenv->value_amp_hz = 1 << 21; + volenv->value_db_oct = 0; + if (volenv->hold_samples) { + volenv->state = ENV_HOLD; + } else { + /* RAMP_UP since db value is inverted and it is 0 at this point. */ + volenv->state = ENV_RAMP_UP; + } + } + attenuation += env_vol_amplitude_to_db[volenv->value_amp_hz >> 5] << 5; + break; + + case ENV_HOLD: + volenv->hold_samples--; + if (volenv->hold_samples <= 0) { + volenv->state = ENV_RAMP_UP; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_RAMP_DOWN: + /* Decay/release amount is in fraction of dBs and is always positive */ + volenv->value_db_oct -= volenv->ramp_amount_db_oct; + if (volenv->value_db_oct <= volenv->sustain_value_db_oct) { + volenv->value_db_oct = volenv->sustain_value_db_oct; + volenv->state = ENV_SUSTAIN; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_RAMP_UP: + /* Decay/release amount is in fraction of dBs and is always positive */ + volenv->value_db_oct += volenv->ramp_amount_db_oct; + if (volenv->value_db_oct >= volenv->sustain_value_db_oct) { + volenv->value_db_oct = volenv->sustain_value_db_oct; + volenv->state = ENV_SUSTAIN; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_SUSTAIN: + attenuation += volenv->value_db_oct; + break; + + case ENV_STOPPED: + attenuation = 0x1FFFFF; + break; + } + + emu8k_envelope_t *modenv = &emu_voice->mod_envelope; + switch (modenv->state) { + case ENV_DELAY: + modenv->delay_samples--; + if (modenv->delay_samples <= 0) { + modenv->state = ENV_ATTACK; + modenv->delay_samples = 0; + } + break; + + case ENV_ATTACK: + /* Attack amount is in linear amplitude */ + modenv->value_amp_hz += modenv->attack_amount_amp_hz; + modenv->value_db_oct = env_mod_hertz_to_octave[modenv->value_amp_hz >> 5] << 5; + if (modenv->value_amp_hz >= (1 << 21)) { + modenv->value_amp_hz = 1 << 21; + modenv->value_db_oct = 1 << 21; + if (modenv->hold_samples) { + modenv->state = ENV_HOLD; + } else { + modenv->state = ENV_RAMP_DOWN; + } + } + break; + + case ENV_HOLD: + modenv->hold_samples--; + if (modenv->hold_samples <= 0) { + modenv->state = ENV_RAMP_UP; + } + break; + + case ENV_RAMP_DOWN: + /* Decay/release amount is in fraction of octave and is always positive */ + modenv->value_db_oct -= modenv->ramp_amount_db_oct; + if (modenv->value_db_oct <= modenv->sustain_value_db_oct) { + modenv->value_db_oct = modenv->sustain_value_db_oct; + modenv->state = ENV_SUSTAIN; + } + break; + + case ENV_RAMP_UP: + /* Decay/release amount is in fraction of octave and is always positive */ + modenv->value_db_oct += modenv->ramp_amount_db_oct; + if (modenv->value_db_oct >= modenv->sustain_value_db_oct) { + modenv->value_db_oct = modenv->sustain_value_db_oct; + modenv->state = ENV_SUSTAIN; + } + break; + } + + /* run lfos */ + if (emu_voice->lfo1_delay_samples) { + emu_voice->lfo1_delay_samples--; + } else { + emu_voice->lfo1_count.addr += emu_voice->lfo1_speed; + emu_voice->lfo1_count.int_address &= 0xFFFF; + } + if (emu_voice->lfo2_delay_samples) { + emu_voice->lfo2_delay_samples--; + } else { + emu_voice->lfo2_count.addr += emu_voice->lfo2_speed; + emu_voice->lfo2_count.int_address &= 0xFFFF; + } + + if (emu_voice->fixed_modenv_pitch_height) { + /* modenv range 1<<21, pitch height range 1<<14 desired range 0x1000 (+/-one octave) */ + currentpitch += ((modenv->value_db_oct >> 9) * emu_voice->fixed_modenv_pitch_height) >> 14; + } + + if (emu_voice->fixed_lfo1_vibrato) { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ + int32_t lfo1_vibrato = (lfotable[emu_voice->lfo1_count.int_address] * emu_voice->fixed_lfo1_vibrato) >> 17; + currentpitch += lfo1_vibrato; + } + if (emu_voice->fixed_lfo2_vibrato) { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ + int32_t lfo2_vibrato = (lfotable[emu_voice->lfo2_count.int_address] * emu_voice->fixed_lfo2_vibrato) >> 17; + currentpitch += lfo2_vibrato; + } + + if (emu_voice->fixed_modenv_filter_height) { + /* modenv range 1<<21, pitch height range 1<<14 desired range 0x200000 (+/-full filter range) */ + filtercut += ((modenv->value_db_oct >> 9) * emu_voice->fixed_modenv_filter_height) >> 5; + } + + if (emu_voice->fixed_lfo1_filt_mod) { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x100000 (+/-three octaves) */ + int32_t lfo1_filtmod = (lfotable[emu_voice->lfo1_count.int_address] * emu_voice->fixed_lfo1_filt_mod) >> 9; + filtercut += lfo1_filtmod; + } + + if (emu_voice->fixed_lfo1_tremolo) { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x40000 (+/-12dBs). */ + int32_t lfo1_tremolo = (lfotable[emu_voice->lfo1_count.int_address] * emu_voice->fixed_lfo1_tremolo) >> 11; + attenuation += lfo1_tremolo; + } + + if (currentpitch > 0xFFFF) + currentpitch = 0xFFFF; + if (currentpitch < 0) + currentpitch = 0; + if (attenuation > 0x1FFFFF) + attenuation = 0x1FFFFF; + if (attenuation < 0) + attenuation = 0; + if (filtercut > 0x1FFFFF) + filtercut = 0x1FFFFF; + if (filtercut < 0) + filtercut = 0; + + emu_voice->vtft_vol_target = env_vol_db_to_vol_target[attenuation >> 5]; + emu_voice->vtft_filter_target = filtercut >> 5; + emu_voice->ptrx_pit_target = freqtable[currentpitch] >> 18; + } + /* + I've recopilated these sentences to get an idea of how to loop + + - Set its PSST register and its CLS register to zero to cause no loops to occur. + -Setting the Loop Start Offset and the Loop End Offset to the same value, will cause the oscillator to loop the entire memory. + + -Setting the PlayPosition greater than the Loop End Offset, will cause the oscillator to play in reverse, back to the Loop End Offset. + It's pretty neat, but appears to be uncontrollable (the rate at which the samples are played in reverse). + + -Note that due to interpolator offset, the actual loop point is one greater than the start address + -Note that due to interpolator offset, the actual loop point will end at an address one greater than the loop address + -Note that the actual audio location is the point 1 word higher than this value due to interpolation offset + -In programs that use the awe, they generally set the loop address as "loopaddress -1" to compensate for the above. + (Note: I am already using address+1 in the interpolators so these things are already as they should.) + */ + emu_voice->addr.addr += ((uint64_t) emu_voice->cpf_curr_pitch) << 18; + if (emu_voice->addr.addr >= emu_voice->loop_end.addr) { + emu_voice->addr.int_address -= (emu_voice->loop_end.int_address - emu_voice->loop_start.int_address); + emu_voice->addr.int_address &= EMU8K_MEM_ADDRESS_MASK; + } + + /* TODO: How and when are the target and current values updated */ + emu_voice->cpf_curr_pitch = emu_voice->ptrx_pit_target; + emu_voice->cvcf_curr_volume = emu8k_vol_slide(&emu_voice->volumeslide, emu_voice->vtft_vol_target); + emu_voice->cvcf_curr_filt_ctoff = emu_voice->vtft_filter_target; } - /* Even when the documentation says that this has to be written by applications to initialize the card, - * several applications and drivers ( aweman on windows, linux oss driver..) read it to detect an AWE card. */ - emu8k->hwcf1 = 0x59; - emu8k->hwcf2 = 0x20; - /* Initial state is muted. 0x04 is unmuted. */ - emu8k->hwcf3 = 0x00; + + /* Update EMU voice registers. */ + emu_voice->ccca = (((uint32_t) emu_voice->ccca_qcontrol) << 24) | emu_voice->addr.int_address; + emu_voice->cpf_curr_frac_addr = emu_voice->addr.fract_address; + + // if ( emu_voice->cvcf_curr_volume != old_vol[c]) { + // pclog("EMUVOL (%d):%d\n", c, emu_voice->cvcf_curr_volume); + // old_vol[c]=emu_voice->cvcf_curr_volume; + // } + // pclog("EMUFILT :%d\n", emu_voice->cvcf_curr_filt_ctoff); + } + + buf = &emu8k->buffer[emu8k->pos * 2]; + emu8k_work_reverb(&emu8k->reverb_in_buffer[emu8k->pos], buf, &emu8k->reverb_engine, new_pos - emu8k->pos); + emu8k_work_chorus(&emu8k->chorus_in_buffer[emu8k->pos], buf, &emu8k->chorus_engine, new_pos - emu8k->pos); + emu8k_work_eq(buf, new_pos - emu8k->pos); + + // Clip signal + for (pos = emu8k->pos; pos < new_pos; pos++) { + if (buf[0] < -32768) + buf[0] = -32768; + else if (buf[0] > 32767) + buf[0] = 32767; + + if (buf[1] < -32768) + buf[1] = -32768; + else if (buf[1] > 32767) + buf[1] = 32767; + + buf += 2; + } + + /* Update EMU clock. */ + emu8k->wc += (new_pos - emu8k->pos); + + emu8k->pos = new_pos; } -void emu8k_close(emu8k_t *emu8k) +void +emu8k_change_addr(emu8k_t *emu8k, uint16_t emu_addr) { - free(emu8k->rom); - free(emu8k->ram); + if (emu8k->addr) { + io_removehandler(emu8k->addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_removehandler(emu8k->addr + 0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_removehandler(emu8k->addr + 0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + emu8k->addr = 0; + } + if (emu_addr) { + emu8k->addr = emu_addr; + io_sethandler(emu8k->addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu8k->addr + 0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu8k->addr + 0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + } } +/* onboard_ram in kilobytes */ +void +emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) +{ + uint32_t const BLOCK_SIZE_WORDS = 0x10000; + FILE *f; + int c; + double out; + + f = rom_fopen("roms/sound/awe32.raw", "rb"); + if (!f) + fatal("AWE32.RAW not found\n"); + + emu8k->rom = malloc(1024 * 1024); + if (fread(emu8k->rom, 1, 1048576, f) != 1048576) + fatal("emu8k_init(): Error reading data\n"); + fclose(f); + /*AWE-DUMP creates ROM images offset by 2 bytes, so if we detect this + then correct it*/ + if (emu8k->rom[3] == 0x314d && emu8k->rom[4] == 0x474d) { + memmove(&emu8k->rom[0], &emu8k->rom[1], (1024 * 1024) - 2); + emu8k->rom[0x7ffff] = 0; + } + + emu8k->empty = malloc(2 * BLOCK_SIZE_WORDS); + memset(emu8k->empty, 0, 2 * BLOCK_SIZE_WORDS); + + int j = 0; + for (; j < 0x8; j++) { + emu8k->ram_pointers[j] = emu8k->rom + (j * BLOCK_SIZE_WORDS); + } + for (; j < 0x20; j++) { + emu8k->ram_pointers[j] = emu8k->empty; + } + + if (onboard_ram) { + /*Clip to 28MB, since that's the max that we can address. */ + if (onboard_ram > 0x7000) + onboard_ram = 0x7000; + emu8k->ram = malloc(onboard_ram * 1024); + memset(emu8k->ram, 0, onboard_ram * 1024); + const int i_end = onboard_ram >> 7; + int i = 0; + for (; i < i_end; i++, j++) { + emu8k->ram_pointers[j] = emu8k->ram + (i * BLOCK_SIZE_WORDS); + } + emu8k->ram_end_addr = EMU8K_RAM_MEM_START + (onboard_ram << 9); + } else { + emu8k->ram = 0; + emu8k->ram_end_addr = EMU8K_RAM_MEM_START; + } + for (; j < 0x100; j++) { + emu8k->ram_pointers[j] = emu8k->empty; + } + + emu8k_change_addr(emu8k, emu_addr); + + /*Create frequency table. (Convert initial pitch register value to a linear speed change) + * The input is encoded such as 0xe000 is center note (no pitch shift) + * and from then on , changing up or down 0x1000 (4096) increments/decrements an octave. + * Note that this is in reference to the 44.1Khz clock that the channels play at. + * The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. + */ + for (c = 0; c < 0x10000; c++) { + freqtable[c] = (uint64_t) (exp2((double) (c - 0xe000) / 4096.0) * 65536.0 * 65536.0); + } + /* Shortcut: minimum pitch equals stopped. I don't really know if this is true, but it's better + * since some programs set the pitch to 0 for unused channels. */ + freqtable[0] = 0; + + /* starting at 65535 because it is used for "volume target" register conversion. */ + out = 65535.0; + for (c = 0; c < 256; c++) { + attentable[c] = (int32_t) out; + out /= sqrt(1.09018); /*0.375 dB steps*/ + } + /* Shortcut: max attenuation is silent, not -96dB. */ + attentable[255] = 0; + + /* Note: these two tables have "db" inverted: 0 dB is max volume, 65535 "db" (-96.32dBFS) is silence. + * Important: Using 65535 as max output value because this is intended to be used with the volume target register! */ + out = 65535.0; + for (c = 0; c < 0x10000; c++) { + // double db = -(c*6.0205999/65535.0)*16.0; + // out = powf(10.f,db/20.f) * 65536.0; + env_vol_db_to_vol_target[c] = (int32_t) out; + /* calculated from the 65536th root of 65536 */ + out /= 1.00016923970; + } + /* Shortcut: max attenuation is silent, not -96dB. */ + env_vol_db_to_vol_target[0x10000 - 1] = 0; + /* One more position to accept max value being 65536. */ + env_vol_db_to_vol_target[0x10000] = 0; + + for (c = 1; c < 0x10000; c++) { + out = -680.32142884264 * 20.0 * log10(((double) c) / 65535.0); + env_vol_amplitude_to_db[c] = (int32_t) out; + } + /*Shortcut: max attenuation is silent, not -96dB.*/ + env_vol_amplitude_to_db[0] = 65535; + /* One more position to accept max value being 65536. */ + env_vol_amplitude_to_db[0x10000] = 0; + + for (c = 1; c < 0x10000; c++) { + out = log2((((double) c) / 0x10000) + 1.0) * 65536.0; + env_mod_hertz_to_octave[c] = (int32_t) out; + } + /*No hertz change, no octave change. */ + env_mod_hertz_to_octave[0] = 0; + /* One more position to accept max value being 65536. */ + env_mod_hertz_to_octave[0x10000] = 65536; + + /* This formula comes from vince vu/judge dredd's awe32p10 and corresponds to what the freebsd/linux AWE32 driver has. */ + float millis; + for (c = 0; c < 128; c++) { + if (c == 0) + millis = 0; /* This means never attack. */ + else if (c < 32) + millis = 11878.0 / c; + else + millis = 360 * exp((c - 32) / (16.0 / log(1.0 / 2.0))); + + env_attack_to_samples[c] = 44.1 * millis; + /* This is an alternate formula with linear increments, but probably incorrect: + * millis = (256+4096*(0x7F-c)) */ + } + + /* The LFOs use a triangular waveform starting at zero and going 1/-1/1/-1. + * This table is stored in signed 16bits precision, with a period of 65536 samples */ + for (c = 0; c < 65536; c++) { + int d = (c + 16384) & 65535; + if (d >= 32768) + lfotable[c] = 32768 + ((32768 - d) * 2); + else + lfotable[c] = (d * 2) - 32768; + } + /* The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. */ + out = 0.01; + for (c = 0; c < 256; c++) { + lfofreqtospeed[c] = (uint64_t) (out * 65536.0 / 44100.0 * 65536.0 * 65536.0); + out += 0.042; + } + + for (c = 0; c < 65536; c++) { + chortable[c] = sin(c * M_PI / 32768.0); + } + + /* Filter coefficients tables. Note: Values are multiplied by *16777216 to left shift 24 bits. (i.e. 8.24 fixed point) */ + int qidx; + for (qidx = 0; qidx < 16; qidx++) { + out = 125.0; /* Start at 125Hz */ + for (c = 0; c < 256; c++) { +#ifdef FILTER_INITIAL + float w0 = sin(2.0 * M_PI * out / 44100.0); + /* The value 102.5f has been selected a bit randomly. Pretends to reach 0.2929 at w0 = 1.0 */ + float q = (qidx / 102.5f) * (1.0 + 1.0 / w0); + /* Limit max value. Else it would be 470. */ + if (q > 200) + q = 200; + filt_coeffs[qidx][c][0] = (int32_t) (w0 * 16777216.0); + filt_coeffs[qidx][c][1] = 16777216.0; + filt_coeffs[qidx][c][2] = (int32_t) ((1.0f / (0.7071f + q)) * 16777216.0); +#elif defined FILTER_MOOG + float w0 = sin(2.0 * M_PI * out / 44100.0); + float q_factor = 1.0f - w0; + float p = w0 + 0.8f * w0 * q_factor; + float f = p + p - 1.0f; + float resonance = (1.0 - pow(2.0, -qidx * 24.0 / 90.0)) * 0.8; + float q = resonance * (1.0f + 0.5f * q_factor * (w0 + 5.6f * q_factor * q_factor)); + filt_coeffs[qidx][c][0] = (int32_t) (p * 16777216.0); + filt_coeffs[qidx][c][1] = (int32_t) (f * 16777216.0); + filt_coeffs[qidx][c][2] = (int32_t) (q * 16777216.0); +#elif defined FILTER_CONSTANT + float q = (1.0 - pow(2.0, -qidx * 24.0 / 90.0)) * 0.8; + float coef0 = sin(2.0 * M_PI * out / 44100.0); + float coef1 = 1.0 - coef0; + float coef2 = q * (1.0 + 1.0 / coef1); + filt_coeffs[qidx][c][0] = (int32_t) (coef0 * 16777216.0); + filt_coeffs[qidx][c][1] = (int32_t) (coef1 * 16777216.0); + filt_coeffs[qidx][c][2] = (int32_t) (coef2 * 16777216.0); +#endif // FILTER_TYPE + /* 42.66 divisions per octave (the doc says quarter seminotes which is 48, but then it would be almost an octave less) */ + out *= 1.016378315; + /* 42 divisions. This moves the max frequency to 8.5Khz.*/ + // out *= 1.0166404394; + /* This is a linear increment method, that corresponds to the NRPN table, but contradicts the EMU8KPRM doc: */ + // out = 100.0 + (c+1.0)*31.25; //31.25Hz steps */ + } + } + /* NOTE! read_pos and buffer content is implicitly initialized to zero by the sb_t structure memset on sb_awe32_init() */ + emu8k->reverb_engine.reflections[0].bufsize = 2 * REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[1].bufsize = 4 * REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[2].bufsize = 8 * REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[3].bufsize = 13 * REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[4].bufsize = 19 * REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[5].bufsize = 26 * REV_BUFSIZE_STEP; + + /*This is a bit random.*/ + for (c = 0; c < 4; c++) { + emu8k->reverb_engine.allpass[3 - c].feedback = 0.5; + emu8k->reverb_engine.allpass[3 - c].bufsize = (4 * c) * REV_BUFSIZE_STEP + 55; + emu8k->reverb_engine.allpass[7 - c].feedback = 0.5; + emu8k->reverb_engine.allpass[7 - c].bufsize = (4 * c) * REV_BUFSIZE_STEP + 55; + } + + /* Cubic Resampling ( 4point cubic spline) */ + double const resdouble = 1.0 / (double) CUBIC_RESOLUTION; + for (c = 0; c < CUBIC_RESOLUTION; c++) { + double x = (double) c * resdouble; + /* Cubic resolution is made of four table, but I've put them all in one table to optimize memory access. */ + cubic_table[c * 4] = (-0.5 * x * x * x + x * x - 0.5 * x); + cubic_table[c * 4 + 1] = (1.5 * x * x * x - 2.5 * x * x + 1.0); + cubic_table[c * 4 + 2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x); + cubic_table[c * 4 + 3] = (0.5 * x * x * x - 0.5 * x * x); + } + /* Even when the documentation says that this has to be written by applications to initialize the card, + * several applications and drivers ( aweman on windows, linux oss driver..) read it to detect an AWE card. */ + emu8k->hwcf1 = 0x59; + emu8k->hwcf2 = 0x20; + /* Initial state is muted. 0x04 is unmuted. */ + emu8k->hwcf3 = 0x00; +} + +void +emu8k_close(emu8k_t *emu8k) +{ + free(emu8k->rom); + free(emu8k->ram); +} diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 966044b77..2bef7edac 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -1,1299 +1,1316 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/io.h> -#include <86box/nmi.h> -#include <86box/pic.h> -#include <86box/dma.h> -#include <86box/timer.h> -#include <86box/device.h> -#include <86box/sound.h> -#include <86box/midi.h> -#include <86box/snd_ad1848.h> #include -enum -{ - MIDI_INT_RECEIVE = 0x01, - MIDI_INT_TRANSMIT = 0x02, - MIDI_INT_MASTER = 0x80 +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/midi.h> +#include <86box/nmi.h> +#include <86box/pic.h> +#include <86box/sound.h> +#include <86box/timer.h> +#include <86box/snd_ad1848.h> + +enum { + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 }; -enum -{ - MIDI_CTRL_TRANSMIT_MASK = 0x60, - MIDI_CTRL_TRANSMIT = 0x20, - MIDI_CTRL_RECEIVE = 0x80 +enum { + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 }; -enum -{ - GUS_INT_MIDI_TRANSMIT = 0x01, - GUS_INT_MIDI_RECEIVE = 0x02 +enum { + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 }; -enum -{ - GUS_TIMER_CTRL_AUTO = 0x01 +enum { + GUS_TIMER_CTRL_AUTO = 0x01 }; -enum -{ - GUS_CLASSIC = 0, - GUS_MAX = 1, +enum { + GUS_CLASSIC = 0, + GUS_MAX = 1, }; -typedef struct gus_t -{ - int reset; - - int global; - uint32_t addr,dmaaddr; - int voice; - uint32_t start[32],end[32],cur[32]; - uint32_t startx[32],endx[32],curx[32]; - int rstart[32],rend[32]; - int rcur[32]; - uint16_t freq[32]; - uint16_t rfreq[32]; - uint8_t ctrl[32]; - uint8_t rctrl[32]; - int curvol[32]; - int pan_l[32], pan_r[32]; - int t1on,t2on; - uint8_t tctrl; - uint16_t t1,t2,t1l,t2l; - uint8_t irqstatus,irqstatus2; - uint8_t adcommand; - int waveirqs[32],rampirqs[32]; - int voices; - uint8_t dmactrl; +typedef struct gus_t { + int reset; - int32_t out_l, out_r; - - int16_t buffer[2][SOUNDBUFLEN]; - int pos; - - pc_timer_t samp_timer; - uint64_t samp_latch; - - uint8_t *ram; - uint32_t gus_end_ram; - - int irqnext; - - pc_timer_t timer_1, timer_2; - - int irq, dma, irq_midi; - uint16_t base; - int latch_enable; - - uint8_t sb_2xa, sb_2xc, sb_2xe; - uint8_t sb_ctrl; - int sb_nmi; - - uint8_t reg_ctrl; - - uint8_t ad_status, ad_data; - uint8_t ad_timer_ctrl; - - uint8_t midi_ctrl, midi_status, midi_queue[64], midi_data; - int midi_r, midi_w; - int uart_in, uart_out, sysex; - - uint8_t gp1, gp2; - uint16_t gp1_addr, gp2_addr; - - uint8_t usrr; + int global; + uint32_t addr, dmaaddr; + int voice; + uint32_t start[32], end[32], cur[32]; + uint32_t startx[32], endx[32], curx[32]; + int rstart[32], rend[32]; + int rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int pan_l[32], pan_r[32]; + int t1on, t2on; + uint8_t tctrl; + uint16_t t1, t2, t1l, t2l; + uint8_t irqstatus, irqstatus2; + uint8_t adcommand; + int waveirqs[32], rampirqs[32]; + int voices; + uint8_t dmactrl; - uint8_t max_ctrl; + int32_t out_l, out_r; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; + + pc_timer_t samp_timer; + uint64_t samp_latch; + + uint8_t *ram; + uint32_t gus_end_ram; + + int irqnext; + + pc_timer_t timer_1, timer_2; + + int irq, dma, irq_midi; + uint16_t base; + int latch_enable; + + uint8_t sb_2xa, sb_2xc, sb_2xe; + uint8_t sb_ctrl; + int sb_nmi; + + uint8_t reg_ctrl; + + uint8_t ad_status, ad_data; + uint8_t ad_timer_ctrl; + + uint8_t midi_ctrl, midi_status, midi_queue[64], midi_data; + int midi_r, midi_w; + int uart_in, uart_out, sysex; + + uint8_t gp1, gp2; + uint16_t gp1_addr, gp2_addr; + + uint8_t usrr; + + uint8_t max_ctrl; #if defined(DEV_BRANCH) && defined(USE_GUSMAX) - ad1848_t ad1848; + ad1848_t ad1848; #endif } gus_t; -static int gus_gf1_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; -static int gus_midi_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; -static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; +static int gus_gf1_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 }; +static int gus_midi_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 }; +static int gus_dmas[8] = { -1, 1, 3, 5, 6, 7, -1, -1 }; -int gusfreqs[]= -{ - 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, - 23746,22866,22050,21289,20580,19916,19293 +int gusfreqs[] = { + 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843, 25725, 24696, + 23746, 22866, 22050, 21289, 20580, 19916, 19293 }; double vol16bit[4096]; -void pollgusirqs(gus_t *gus) +void +gus_update_int_status(gus_t *gus) { - int c; + int c; + int irq_pending = 0; + int midi_irq_pending = 0; - gus->irqstatus&=~0x60; - for (c=0;c<32;c++) - { - if (gus->waveirqs[c]) - { - gus->irqstatus2=0x60|c; - if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; - gus->irqstatus|=0x20; - if (gus->irq != -1) - picint(1 << gus->irq); - return; - } - if (gus->rampirqs[c]) - { - gus->irqstatus2=0xA0|c; - gus->irqstatus|=0x40; - if (gus->irq != -1) - picint(1 << gus->irq); - return; - } + gus->irqstatus &= ~0x60; + gus->irqstatus2 = 0xE0; + for (c = 0; c < 32; c++) { + if (gus->waveirqs[c]) { + gus->irqstatus2 = 0x60 | c; + if (gus->rampirqs[c]) + gus->irqstatus2 |= 0x80; + gus->irqstatus |= 0x20; + irq_pending = 1; + break; } - gus->irqstatus2=0xE0; - if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); + if (gus->rampirqs[c]) { + gus->irqstatus2 = 0xA0 | c; + gus->irqstatus |= 0x40; + irq_pending = 1; + break; + } + } + if ((gus->tctrl & 4) && (gus->irqstatus & 0x04)) + irq_pending = 1; /*Timer 1 interrupt pending*/ + if ((gus->tctrl & 8) && (gus->irqstatus & 0x08)) + irq_pending = 1; /*Timer 2 interrupt pending*/ + if ((gus->irqstatus & 0x80) && (gus->dmactrl & 0x20)) + irq_pending = 1; /*DMA TC interrupt pending*/ + + midi_irq_pending = gus->midi_status & MIDI_INT_MASTER; + + if (gus->irq == gus->irq_midi && gus->irq != -1) { + if (irq_pending || midi_irq_pending) + picintlevel(1 << gus->irq); + else + picintc(1 << gus->irq); + } else { + if (gus->irq != -1) { + if (irq_pending) + picintlevel(1 << gus->irq); + else + picintc(1 << gus->irq); + } + if (gus->irq_midi != -1) { + if (midi_irq_pending) + picintlevel(1 << gus->irq_midi); + else + picintc(1 << gus->irq_midi); + } + } } -void gus_midi_update_int_status(gus_t *gus) +void +gus_midi_update_int_status(gus_t *gus) { - gus->midi_status &= ~MIDI_INT_MASTER; - if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) - { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; - } - else - gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; - - if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) - { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_RECEIVE; - } - else - gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + gus->midi_status &= ~MIDI_INT_MASTER; + if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } else + gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; - if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) - { - picint(1 << gus->irq_midi); - } + if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + } else + gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + gus_update_int_status(gus); } -void writegus(uint16_t addr, uint8_t val, void *p) +void +writegus(uint16_t addr, uint8_t val, void *p) { - gus_t *gus = (gus_t *)p; - int c, d; - int old; - uint16_t port; + gus_t *gus = (gus_t *) p; + int c, d; + int old; + uint16_t port; #if defined(DEV_BRANCH) && defined(USE_GUSMAX) - uint16_t csioport; + uint16_t csioport; #endif - - if ((addr == 0x388) || (addr == 0x389)) - port = addr; - else - port = addr & 0xf0f; - - switch (port) - { - case 0x300: /*MIDI control*/ - old = gus->midi_ctrl; - gus->midi_ctrl = val; - gus->uart_out = 1; - - if ((val & 3) == 3) { /*Master reset*/ - gus->uart_in = 0; - gus->midi_status = 0; - gus->midi_r = 0; - gus->midi_w = 0; - } else if ((old & 3) == 3) { - gus->midi_status |= MIDI_INT_TRANSMIT; - } else if (gus->midi_ctrl & MIDI_CTRL_RECEIVE) { - gus->uart_in = 1; - } - gus_midi_update_int_status(gus); - break; - case 0x301: /*MIDI data*/ - gus->midi_data = val; - if (gus->uart_out) { - midi_raw_out_byte(val); - } - if (gus->latch_enable & 0x20) { - gus->midi_status |= MIDI_INT_RECEIVE; - } else - gus->midi_status |= MIDI_INT_TRANSMIT; - break; - case 0x302: /*Voice select*/ - gus->voice=val&31; - break; - case 0x303: /*Global select*/ - gus->global=val; - break; - case 0x304: /*Global low*/ - switch (gus->global) - { - case 0: /*Voice control*/ - gus->ctrl[gus->voice]=val; - break; - case 1: /*Frequency control*/ - gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val; - break; - case 2: /*Start addr high*/ - gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); - gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); - break; - case 3: /*Start addr low*/ - gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; - break; - case 4: /*End addr high*/ - gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); - gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); - break; - case 5: /*End addr low*/ - gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; - break; - case 6: /*Ramp frequency*/ - gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); - break; + if ((addr == 0x388) || (addr == 0x389)) + port = addr; + else + port = addr & 0xf0f; - case 9: /*Current volume*/ - gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); - break; + switch (port) { + case 0x300: /*MIDI control*/ + old = gus->midi_ctrl; + gus->midi_ctrl = val; + gus->uart_out = 1; - case 0xA: /*Current addr high*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); -gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); - break; - case 0xB: /*Current addr low*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; - break; + if ((val & 3) == 3) { /*Master reset*/ + gus->uart_in = 0; + gus->midi_status = 0; + gus->midi_r = 0; + gus->midi_w = 0; + } else if ((old & 3) == 3) { + gus->midi_status |= MIDI_INT_TRANSMIT; + } else if (gus->midi_ctrl & MIDI_CTRL_RECEIVE) { + gus->uart_in = 1; + } + gus_midi_update_int_status(gus); + break; + case 0x301: /*MIDI data*/ + gus->midi_data = val; + if (gus->uart_out) { + midi_raw_out_byte(val); + } + if (gus->latch_enable & 0x20) { + gus->midi_status |= MIDI_INT_RECEIVE; + } else + gus->midi_status |= MIDI_INT_TRANSMIT; + break; + case 0x302: /*Voice select*/ + gus->voice = val & 31; + break; + case 0x303: /*Global select*/ + gus->global = val; + break; + case 0x304: /*Global low*/ + switch (gus->global) { + case 0: /*Voice control*/ + gus->ctrl[gus->voice] = val; + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice] = (gus->freq[gus->voice] & 0xFF00) | val; + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice] = (gus->startx[gus->voice] & 0xF807F) | (val << 7); + gus->start[gus->voice] = (gus->start[gus->voice] & 0x1F00FFFF) | (val << 16); + break; + case 3: /*Start addr low*/ + gus->start[gus->voice] = (gus->start[gus->voice] & 0x1FFFFF00) | val; + break; + case 4: /*End addr high*/ + gus->endx[gus->voice] = (gus->endx[gus->voice] & 0xF807F) | (val << 7); + gus->end[gus->voice] = (gus->end[gus->voice] & 0x1F00FFFF) | (val << 16); + break; + case 5: /*End addr low*/ + gus->end[gus->voice] = (gus->end[gus->voice] & 0x1FFFFF00) | val; + break; - case 0x42: /*DMA address low*/ - gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4); - break; + case 6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int) ((double) ((val & 63) * 512) / (double) (1 << (3 * (val >> 6)))); + break; - case 0x43: /*Address low*/ - gus->addr=(gus->addr&0xFFF00)|val; - break; - case 0x45: /*Timer control*/ - gus->tctrl=val; - break; - } - break; - case 0x305: /*Global high*/ - switch (gus->global) - { - case 0: /*Voice control*/ - gus->ctrl[gus->voice] = val & 0x7f; + case 9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); + break; - old = gus->waveirqs[gus->voice]; - gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; - if (gus->waveirqs[gus->voice] != old) - pollgusirqs(gus); - break; - case 1: /*Frequency control*/ - gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); - break; - case 2: /*Start addr high*/ - gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); - gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); - break; - case 3: /*Start addr low*/ - gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); - gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); - break; - case 4: /*End addr high*/ - gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); - gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); - break; - case 5: /*End addr low*/ - gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); - gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); - break; + case 0xA: /*Current addr high*/ + gus->cur[gus->voice] = (gus->cur[gus->voice] & 0x1F00FFFF) | (val << 16); + gus->curx[gus->voice] = (gus->curx[gus->voice] & 0xF807F00) | ((val << 7) << 8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice] = (gus->cur[gus->voice] & 0x1FFFFF00) | val; + break; - case 6: /*Ramp frequency*/ - gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); - break; - case 7: /*Ramp start*/ - gus->rstart[gus->voice] = val << 14; - break; - case 8: /*Ramp end*/ - gus->rend[gus->voice] = val << 14; - break; - case 9: /*Current volume*/ - gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); - break; + case 0x42: /*DMA address low*/ + gus->dmaaddr = (gus->dmaaddr & 0xFF000) | (val << 4); + break; - case 0xA: /*Current addr high*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); - gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); - break; - case 0xB: /*Current addr low*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); -gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); - break; - case 0xC: /*Pan*/ - gus->pan_l[gus->voice] = 15 - (val & 0xf); - gus->pan_r[gus->voice] = (val & 0xf); - break; - case 0xD: /*Ramp control*/ - old = gus->rampirqs[gus->voice]; - gus->rctrl[gus->voice] = val & 0x7F; - gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; - if (gus->rampirqs[gus->voice] != old) - pollgusirqs(gus); - break; + case 0x43: /*Address low*/ + gus->addr = (gus->addr & 0xFFF00) | val; + break; + case 0x45: /*Timer control*/ + gus->tctrl = val; + gus_update_int_status(gus); + break; + } + break; + case 0x305: /*Global high*/ + switch (gus->global) { + case 0: /*Voice control*/ + gus->ctrl[gus->voice] = val & 0x7f; - case 0xE: - gus->voices=(val&63)+1; - if (gus->voices>32) gus->voices=32; - if (gus->voices<14) gus->voices=14; - gus->global=val; - if (gus->voices < 14) - gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); - else - gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); - break; + old = gus->waveirqs[gus->voice]; + gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->waveirqs[gus->voice] != old) + gus_update_int_status(gus); + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice] = (gus->freq[gus->voice] & 0xFF) | (val << 8); + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice] = (gus->startx[gus->voice] & 0x07FFF) | (val << 15); + gus->start[gus->voice] = (gus->start[gus->voice] & 0x00FFFFFF) | ((val & 0x1F) << 24); + break; + case 3: /*Start addr low*/ + gus->startx[gus->voice] = (gus->startx[gus->voice] & 0xFFF80) | (val & 0x7F); + gus->start[gus->voice] = (gus->start[gus->voice] & 0x1FFF00FF) | (val << 8); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice] = (gus->endx[gus->voice] & 0x07FFF) | (val << 15); + gus->end[gus->voice] = (gus->end[gus->voice] & 0x00FFFFFF) | ((val & 0x1F) << 24); + break; + case 5: /*End addr low*/ + gus->endx[gus->voice] = (gus->endx[gus->voice] & 0xFFF80) | (val & 0x7F); + gus->end[gus->voice] = (gus->end[gus->voice] & 0x1FFF00FF) | (val << 8); + break; - case 0x41: /*DMA*/ - if (val&1 && gus->dma != -1) - { - if (val & 2) - { - c=0; - while (c<65536) - { - int dma_result; - if (val & 0x04) - { - uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); - d = gus->ram[gus_addr] | (gus->ram[gus_addr + 1] << 8); - if (val & 0x80) - d ^= 0x8080; - dma_result = dma_channel_write(gus->dma, d); - if (dma_result == DMA_NODATA) - break; - } - else - { - d = gus->ram[gus->dmaaddr]; - if (val & 0x80) - d ^= 0x80; - dma_result = dma_channel_write(gus->dma, d); - if (dma_result == DMA_NODATA) - break; - } - gus->dmaaddr++; - gus->dmaaddr &= 0xFFFFF; - c++; - if (dma_result & DMA_OVER) - break; - } - gus->dmactrl=val&~0x40; - if (val&0x20) gus->irqnext=1; + case 6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int) ((double) ((val & 63) * (1 << 10)) / (double) (1 << (3 * (val >> 6)))); + break; + case 7: /*Ramp start*/ + gus->rstart[gus->voice] = val << 14; + break; + case 8: /*Ramp end*/ + gus->rend[gus->voice] = val << 14; + break; + case 9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice] = (gus->cur[gus->voice] & 0x00FFFFFF) | ((val & 0x1F) << 24); + gus->curx[gus->voice] = (gus->curx[gus->voice] & 0x07FFF00) | ((val << 15) << 8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice] = (gus->cur[gus->voice] & 0x1FFF00FF) | (val << 8); + gus->curx[gus->voice] = (gus->curx[gus->voice] & 0xFFF8000) | ((val & 0x7F) << 8); + break; + case 0xC: /*Pan*/ + gus->pan_l[gus->voice] = 15 - (val & 0xf); + gus->pan_r[gus->voice] = (val & 0xf); + break; + case 0xD: /*Ramp control*/ + old = gus->rampirqs[gus->voice]; + gus->rctrl[gus->voice] = val & 0x7F; + gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->rampirqs[gus->voice] != old) + gus_update_int_status(gus); + break; + + case 0xE: + gus->voices = (val & 63) + 1; + if (gus->voices > 32) + gus->voices = 32; + if (gus->voices < 14) + gus->voices = 14; + gus->global = val; + if (gus->voices < 14) + gus->samp_latch = (uint64_t) (TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (uint64_t) (TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + break; + + case 0x41: /*DMA*/ + if (val & 1 && gus->dma != -1) { + if (val & 2) { + c = 0; + while (c < 65536) { + int dma_result; + if (val & 0x04) { + uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); + d = gus->ram[gus_addr] | (gus->ram[gus_addr + 1] << 8); + if (val & 0x80) + d ^= 0x8080; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; + } else { + d = gus->ram[gus->dmaaddr]; + if (val & 0x80) + d ^= 0x80; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; } - else - { - c=0; - while (c<65536) - { - d = dma_channel_read(gus->dma); - if (d == DMA_NODATA) - break; - if (val & 0x04) - { - uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); - if (val & 0x80) - d ^= 0x8080; - gus->ram[gus_addr] = d & 0xff; - gus->ram[gus_addr +1] = (d >> 8) & 0xff; - } - else - { - if (val & 0x80) - d ^= 0x80; - gus->ram[gus->dmaaddr] = d; - } - gus->dmaaddr++; - gus->dmaaddr &= 0xFFFFF; - c++; - if (d & DMA_OVER) - break; - } - gus->dmactrl=val&~0x40; - if (val&0x20) gus->irqnext=1; + gus->dmaaddr++; + gus->dmaaddr &= 0xFFFFF; + c++; + if (dma_result & DMA_OVER) + break; + } + gus->dmactrl = val & ~0x40; + gus->irqnext = 1; + } else { + c = 0; + while (c < 65536) { + d = dma_channel_read(gus->dma); + if (d == DMA_NODATA) + break; + if (val & 0x04) { + uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); + if (val & 0x80) + d ^= 0x8080; + gus->ram[gus_addr] = d & 0xff; + gus->ram[gus_addr + 1] = (d >> 8) & 0xff; + } else { + if (val & 0x80) + d ^= 0x80; + gus->ram[gus->dmaaddr] = d; } + gus->dmaaddr++; + gus->dmaaddr &= 0xFFFFF; + c++; + if (d & DMA_OVER) + break; + } + gus->dmactrl = val & ~0x40; + gus->irqnext = 1; } - break; + } + break; - case 0x42: /*DMA address low*/ - gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12); - break; + case 0x42: /*DMA address low*/ + gus->dmaaddr = (gus->dmaaddr & 0xFF0) | (val << 12); + break; - case 0x43: /*Address low*/ - gus->addr=(gus->addr&0xF00FF)|(val<<8); - break; - case 0x44: /*Address high*/ - gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000); - break; - case 0x45: /*Timer control*/ - if (!(val&4)) gus->irqstatus&=~4; - if (!(val&8)) gus->irqstatus&=~8; - if (!(val & 0x20)) - { - gus->ad_status &= ~0x18; - nmi = 0; - } - if (!(val & 0x02)) - { - gus->ad_status &= ~0x01; - nmi = 0; - } - gus->tctrl=val; - gus->sb_ctrl = val; - break; - case 0x46: /*Timer 1*/ - gus->t1 = gus->t1l = val; + case 0x43: /*Address low*/ + gus->addr = (gus->addr & 0xF00FF) | (val << 8); + break; + case 0x44: /*Address high*/ + gus->addr = (gus->addr & 0xFFFF) | ((val << 16) & 0xF0000); + break; + case 0x45: /*Timer control*/ + if (!(val & 4)) + gus->irqstatus &= ~4; + if (!(val & 8)) + gus->irqstatus &= ~8; + if (!(val & 0x20)) { + gus->ad_status &= ~0x18; +#ifdef OLD_NMI_BEHAVIOR + nmi = 0; +#endif + } + if (!(val & 0x02)) { + gus->ad_status &= ~0x01; +#ifdef OLD_NMI_BEHAVIOR + nmi = 0; +#endif + } + gus->tctrl = val; + gus->sb_ctrl = val; + gus_update_int_status(gus); + break; + case 0x46: /*Timer 1*/ + gus->t1 = gus->t1l = val; + gus->t1on = 1; + break; + case 0x47: /*Timer 2*/ + gus->t2 = gus->t2l = val; + gus->t2on = 1; + break; + + case 0x4c: /*Reset*/ + gus->reset = val; + break; + } + break; + case 0x307: /*DRAM access*/ + if (gus->addr < gus->gus_end_ram) + gus->ram[gus->addr] = val; + gus->addr &= 0xFFFFF; + break; + case 0x208: + case 0x388: + gus->adcommand = val; + break; + + case 0x389: + if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) { + gus->ad_data = val; + gus->ad_status |= 0x01; + if (gus->sb_ctrl & 0x02) { + if (gus->sb_nmi) + nmi_raise(); + else if (gus->irq != -1) + picint(1 << gus->irq); + } + } else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) { + if (val & 0x80) { + gus->ad_status &= ~0x60; + } else { + gus->ad_timer_ctrl = val; + + if (val & 0x01) gus->t1on = 1; - break; - case 0x47: /*Timer 2*/ - gus->t2 = gus->t2l = val; + else + gus->t1 = gus->t1l; + + if (val & 0x02) gus->t2on = 1; - break; - - case 0x4c: /*Reset*/ - gus->reset = val; - break; + else + gus->t2 = gus->t2l; } - break; - case 0x307: /*DRAM access*/ - if (gus->addr < gus->gus_end_ram) - gus->ram[gus->addr]=val; - gus->addr&=0xFFFFF; - break; - case 0x208: case 0x388: - gus->adcommand = val; - break; - - case 0x389: - if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) - { - gus->ad_data = val; - gus->ad_status |= 0x01; - if (gus->sb_ctrl & 0x02) - { - if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); - } - } - else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) - { - if (val & 0x80) - { - gus->ad_status &= ~0x60; - } - else - { - gus->ad_timer_ctrl = val; - - if (val & 0x01) - gus->t1on = 1; - else - gus->t1 = gus->t1l; + } + break; - if (val & 0x02) - gus->t2on = 1; - else - gus->t2 = gus->t2l; - } - } - break; - - case 0x200: - gus->latch_enable = val; - break; - - case 0x20b: - switch (gus->reg_ctrl & 0x07) - { - case 0: - if (gus->latch_enable & 0x40) { - gus->irq = gus_gf1_irqs[val & 7]; - - if (val & 0x40) - { - if (gus->irq == -1) - gus->irq = gus->irq_midi = gus_gf1_irqs[(val >> 3) & 7]; - else - gus->irq_midi = gus->irq; - } - else - gus->irq_midi = gus_midi_irqs[(val >> 3) & 7]; -#if defined(DEV_BRANCH) && defined(USE_GUSMAX) - ad1848_setirq(&gus->ad1848, gus->irq); -#endif - - gus->sb_nmi = val & 0x80; - } else { - gus->dma = gus_dmas[val & 7]; + case 0x200: + gus->latch_enable = val; + break; + + case 0x20b: + switch (gus->reg_ctrl & 0x07) { + case 0: + if (gus->latch_enable & 0x40) { + gus->irq = gus_gf1_irqs[val & 7]; + + if (val & 0x40) { + if (gus->irq == -1) + gus->irq = gus->irq_midi = gus_gf1_irqs[(val >> 3) & 7]; + else + gus->irq_midi = gus->irq; + } else + gus->irq_midi = gus_midi_irqs[(val >> 3) & 7]; #if defined(DEV_BRANCH) && defined(USE_GUSMAX) - ad1848_setdma(&gus->ad1848, gus->dma); -#endif - } - break; - case 1: - gus->gp1 = val; - break; - case 2: - gus->gp2 = val; - break; - case 3: - gus->gp1_addr = val; - break; - case 4: - gus->gp2_addr = val; - break; - case 5: - gus->usrr = 0; - break; - case 6: - break; - } - break; - - case 0x206: - gus->ad_status |= 0x08; - if (gus->sb_ctrl & 0x20) - { - if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); - } - break; - case 0x20a: - gus->sb_2xa = val; - break; - case 0x20c: - gus->ad_status |= 0x10; - if (gus->sb_ctrl & 0x20) - { - if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); - } - /*FALLTHROUGH*/ - case 0x20d: - gus->sb_2xc = val; - break; - case 0x20e: - gus->sb_2xe = val; - break; - case 0x20f: - gus->reg_ctrl = val; - break; - case 0x306: case 0x706: - if (gus->dma >= 4) - val |= 0x30; - gus->max_ctrl = (val >> 6) & 1; -#if defined(DEV_BRANCH) && defined(USE_GUSMAX) - if (val & 0x40) { - if ((val & 0xF) != ((addr >> 4) & 0xF)) { - csioport = 0x30c | ((addr >> 4) & 0xf); - io_removehandler(csioport, 4, - ad1848_read,NULL,NULL, - ad1848_write,NULL,NULL,&gus->ad1848); - csioport = 0x30c | ((val & 0xf) << 4); - io_sethandler(csioport, 4, - ad1848_read,NULL,NULL, - ad1848_write,NULL,NULL, &gus->ad1848); - } - } -#endif - break; - } -} - - -uint8_t readgus(uint16_t addr, void *p) -{ - gus_t *gus = (gus_t *)p; - uint8_t val = 0xff; - uint16_t port; - - if ((addr == 0x388) || (addr == 0x389)) - port = addr; - else - port = addr & 0xf0f; - - switch (port) - { - case 0x300: /*MIDI status*/ - val = gus->midi_status; - break; - - case 0x301: /*MIDI data*/ - val = 0; - if (gus->uart_in) { - if ((gus->midi_data == 0xaa) && (gus->midi_ctrl & MIDI_CTRL_RECEIVE)) /*Handle master reset*/ - val = gus->midi_data; - else { - val = gus->midi_queue[gus->midi_r]; - if (gus->midi_r != gus->midi_w) { - gus->midi_r++; - gus->midi_r &= 63; - } - } - gus->midi_status &= ~MIDI_INT_RECEIVE; - gus_midi_update_int_status(gus); - } - break; - - case 0x200: - return 0; - - case 0x206: /*IRQ status*/ - val = gus->irqstatus & ~0x10; - if (gus->ad_status & 0x19) - val |= 0x10; - return val; - - case 0x20F: - if (gus->max_ctrl) - val = 0x02; - else - val = 0x00; - break; - - case 0x302: - return gus->voice; - - case 0x303: - return gus->global; - - case 0x304: /*Global low*/ - switch (gus->global) - { - case 0x82: /*Start addr high*/ - return gus->start[gus->voice]>>16; - case 0x83: /*Start addr low*/ - return gus->start[gus->voice]&0xFF; - - case 0x89: /*Current volume*/ - return gus->rcur[gus->voice]>>6; - case 0x8A: /*Current addr high*/ - return gus->cur[gus->voice]>>16; - case 0x8B: /*Current addr low*/ - return gus->cur[gus->voice]&0xFF; - - case 0x8F: /*IRQ status*/ - val=gus->irqstatus2; - gus->rampirqs[gus->irqstatus2&0x1F]=0; - gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); - return val; - - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - val = 0xff; - break; - } - break; - case 0x305: /*Global high*/ - switch (gus->global) - { - case 0x80: /*Voice control*/ - return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); - - case 0x82: /*Start addr high*/ - return gus->start[gus->voice]>>24; - case 0x83: /*Start addr low*/ - return gus->start[gus->voice]>>8; - - case 0x89: /*Current volume*/ - return gus->rcur[gus->voice]>>14; - - case 0x8A: /*Current addr high*/ - return gus->cur[gus->voice]>>24; - case 0x8B: /*Current addr low*/ - return gus->cur[gus->voice]>>8; - - case 0x8C: /*Pan*/ - return gus->pan_r[gus->voice]; - - case 0x8D: - return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); - - case 0x8F: /*IRQ status*/ - val=gus->irqstatus2; - gus->rampirqs[gus->irqstatus2&0x1F]=0; - gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); - return val; - - case 0x41: /*DMA control*/ - val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0); - gus->irqstatus&=~0x80; - return val; - case 0x45: /*Timer control*/ - return gus->tctrl; - case 0x49: /*Sampling control*/ - return 0; - - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - val = 0xff; - break; - } - break; - case 0x306: case 0x706: - if (gus->max_ctrl) - val = 0x0a; /* GUS MAX */ - else - val = 0xff; /*Pre 3.7 - no mixer*/ - break; - - break; - case 0x307: /*DRAM access*/ - val=gus->ram[gus->addr]; - gus->addr&=0xFFFFF; - if (gus->addr < gus->gus_end_ram) - val = gus->ram[gus->addr]; - else - val = 0; - return val; - case 0x309: return 0; - - case 0x20b: - switch (gus->reg_ctrl & 0x07) - { - case 1: - val = gus->gp1; - break; - case 2: - val = gus->gp2; - break; - case 3: - val = gus->gp1_addr; - break; - case 4: - val = gus->gp2_addr; - break; - } - break; - - case 0x20c: - val = gus->sb_2xc; - if (gus->reg_ctrl & 0x20) - gus->sb_2xc &= 0x80; - break; - case 0x20e: - return gus->sb_2xe; - - case 0x208: case 0x388: - if (gus->tctrl & GUS_TIMER_CTRL_AUTO) - val = gus->sb_2xa; - else - { - val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); - if (val & 0x60) - val |= 0x80; - } - break; - - case 0x209: - gus->ad_status &= ~0x01; - nmi = 0; - /*FALLTHROUGH*/ - case 0x389: - val = gus->ad_data; - break; - - case 0x20A: - val = gus->adcommand; - break; - - } - return val; -} - -void gus_poll_timer_1(void *p) -{ - gus_t *gus = (gus_t *)p; - - timer_advance_u64(&gus->timer_1, (uint64_t)(TIMER_USEC * 80)); - if (gus->t1on) - { - gus->t1++; - if (gus->t1 > 0xFF) - { - gus->t1=gus->t1l; - gus->ad_status |= 0x40; - if (gus->tctrl&4) - { - if (gus->irq != -1) - picint(1 << gus->irq); - gus->ad_status |= 0x04; - gus->irqstatus |= 0x04; - } - } - } - if (gus->irqnext) - { - gus->irqnext=0; - gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); - } - - gus_midi_update_int_status(gus); -} - -void gus_poll_timer_2(void *p) -{ - gus_t *gus = (gus_t *)p; - - timer_advance_u64(&gus->timer_2, (uint64_t)(TIMER_USEC * 320)); - if (gus->t2on) - { - gus->t2++; - if (gus->t2 > 0xFF) - { - gus->t2=gus->t2l; - gus->ad_status |= 0x20; - if (gus->tctrl&8) - { - if (gus->irq != -1) - picint(1 << gus->irq); - gus->ad_status |= 0x02; - gus->irqstatus |= 0x08; - } - } - } - if (gus->irqnext) - { - gus->irqnext=0; - gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); - } -} - -static void gus_update(gus_t *gus) -{ - for (; gus->pos < sound_pos_global; gus->pos++) - { - if (gus->out_l < -32768) - gus->buffer[0][gus->pos] = -32768; - else if (gus->out_l > 32767) - gus->buffer[0][gus->pos] = 32767; - else - gus->buffer[0][gus->pos] = gus->out_l; - if (gus->out_r < -32768) - gus->buffer[1][gus->pos] = -32768; - else if (gus->out_r > 32767) - gus->buffer[1][gus->pos] = 32767; - else - gus->buffer[1][gus->pos] = gus->out_r; - } -} - -void gus_poll_wave(void *p) -{ - gus_t *gus = (gus_t *)p; - uint32_t addr; - int d; - int16_t v; - int32_t vl; - int update_irqs = 0; - - gus_update(gus); - - timer_advance_u64(&gus->samp_timer, gus->samp_latch); - - gus->out_l = gus->out_r = 0; - - if ((gus->reset & 3) != 3) - return; - for (d=0;d<32;d++) - { - if (!(gus->ctrl[d] & 3)) - { - if (gus->ctrl[d] & 4) - { - addr = gus->cur[d] >> 9; - addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); - if (!(gus->freq[d] >> 10)) /*Interpolate*/ - { - vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); - vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); - v = vl >> 9; - } - else - v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); - } - else - { - if (!(gus->freq[d] >> 10)) /*Interpolate*/ - { - vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); - vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); - v = vl >> 9; - } - else - v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); - } - - if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095]; - else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]; - - gus->out_l += (v * gus->pan_l[d]) / 7; - gus->out_r += (v * gus->pan_r[d]) / 7; - - if (gus->ctrl[d]&0x40) - { - gus->cur[d] -= (gus->freq[d] >> 1); - if (gus->cur[d] <= gus->start[d]) - { - int diff = gus->start[d] - gus->cur[d]; - - if (gus->ctrl[d]&8) - { - if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); - } - else if (!(gus->rctrl[d]&4)) - { - gus->ctrl[d] |= 1; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; - } - - if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) - { - gus->waveirqs[d] = 1; - update_irqs = 1; - } - } - } - else - { - gus->cur[d] += (gus->freq[d] >> 1); - - if (gus->cur[d] >= gus->end[d]) - { - int diff = gus->cur[d] - gus->end[d]; - - if (gus->ctrl[d]&8) - { - if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); - } - else if (!(gus->rctrl[d]&4)) - { - gus->ctrl[d] |= 1; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; - } - - if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) - { - gus->waveirqs[d] = 1; - update_irqs = 1; - } - } - } - } - if (!(gus->rctrl[d] & 3)) - { - if (gus->rctrl[d] & 0x40) - { - gus->rcur[d] -= gus->rfreq[d]; - if (gus->rcur[d] <= gus->rstart[d]) - { - int diff = gus->rstart[d] - gus->rcur[d]; - if (!(gus->rctrl[d] & 8)) - { - gus->rctrl[d] |= 1; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; - } - else - { - if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); - } - - if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) - { - gus->rampirqs[d] = 1; - update_irqs = 1; - } - } - } - else - { - gus->rcur[d] += gus->rfreq[d]; - if (gus->rcur[d] >= gus->rend[d]) - { - int diff = gus->rcur[d] - gus->rend[d]; - if (!(gus->rctrl[d] & 8)) - { - gus->rctrl[d] |= 1; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; - } - else - { - if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); - } - - if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) - { - gus->rampirqs[d] = 1; - update_irqs = 1; - } - } - } - } - } - - if (update_irqs) - pollgusirqs(gus); -} - -static void gus_get_buffer(int32_t *buffer, int len, void *p) -{ - gus_t *gus = (gus_t *)p; - int c; - -#if defined(DEV_BRANCH) && defined(USE_GUSMAX) - if (gus->max_ctrl) - ad1848_update(&gus->ad1848); -#endif - gus_update(gus); - - for (c = 0; c < len * 2; c++) - { -#if defined(DEV_BRANCH) && defined(USE_GUSMAX) - if (gus->max_ctrl) - buffer[c] += (int32_t)(gus->ad1848.buffer[c] / 2); -#endif - buffer[c] += (int32_t)gus->buffer[c & 1][c >> 1]; - } - -#if defined(DEV_BRANCH) && defined(USE_GUSMAX) - if (gus->max_ctrl) - gus->ad1848.pos = 0; -#endif - gus->pos = 0; -} - -static void gus_input_msg(void *p, uint8_t *msg) -{ - gus_t *gus = (gus_t *)p; - uint8_t i; - - if (gus->sysex) - return; - - if (gus->uart_in) { - gus->midi_status |= MIDI_INT_RECEIVE; - - for (i=0;imidi_queue[gus->midi_w++] = msg[i]; - gus->midi_w &= 63; - } - - gus_midi_update_int_status(gus); - } -} - -static int gus_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) -{ - gus_t *gus = (gus_t *)p; - uint32_t i; - - if (abort) { - gus->sysex = 0; - return 0; - } - gus->sysex = 1; - for (i=0;imidi_r == gus->midi_w) - return (len-i); - gus->midi_queue[gus->midi_w++] = buffer[i]; - gus->midi_w &= 63; - } - gus->sysex = 0; - return 0; -} - -void *gus_init(const device_t *info) -{ - int c; - double out = 1.0; - uint8_t gus_ram = device_get_config_int("gus_ram"); - gus_t *gus = malloc(sizeof(gus_t)); - memset(gus, 0, sizeof(gus_t)); - - gus->gus_end_ram = 1 << (18 + gus_ram); - gus->ram = (uint8_t *)malloc(gus->gus_end_ram); - memset(gus->ram, 0x00, (gus->gus_end_ram)); - - for (c=0;c<32;c++) - { - gus->ctrl[c]=1; - gus->rctrl[c]=1; - gus->rfreq[c]=63*512; - } - - for (c=4095;c>=0;c--) { - vol16bit[c]=out; - out/=1.002709201; /* 0.0235 dB Steps */ - } - - gus->voices=14; - - gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); - - gus->t1l = gus->t2l = 0xff; - - gus->uart_out = 1; - - gus->base = device_get_config_hex16("base"); - - io_sethandler(gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0100+gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0506+gus->base, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); - -#if defined(DEV_BRANCH) && defined(USE_GUSMAX) - ad1848_init(&gus->ad1848, AD1848_TYPE_CS4231); - ad1848_setirq(&gus->ad1848, 5); - ad1848_setdma(&gus->ad1848, 3); - io_sethandler(0x10C+gus->base, 4, - ad1848_read,NULL,NULL, ad1848_write,NULL,NULL, &gus->ad1848); + ad1848_setirq(&gus->ad1848, gus->irq); #endif - timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); - timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); - timer_add(&gus->timer_2, gus_poll_timer_2, gus, 1); + gus->sb_nmi = val & 0x80; + } else { + gus->dma = gus_dmas[val & 7]; +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + ad1848_setdma(&gus->ad1848, gus->dma); +#endif + } + break; + case 1: + gus->gp1 = val; + break; + case 2: + gus->gp2 = val; + break; + case 3: + gus->gp1_addr = val; + break; + case 4: + gus->gp2_addr = val; + break; + case 5: + gus->usrr = 0; + break; + case 6: + break; + } + break; - sound_add_handler(gus_get_buffer, gus); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, gus_input_msg, gus_input_sysex, gus); - - return gus; + case 0x206: + gus->ad_status |= 0x08; + if (gus->sb_ctrl & 0x20) { + if (gus->sb_nmi) + nmi_raise(); + else if (gus->irq != -1) + picint(1 << gus->irq); + } + break; + case 0x20a: + gus->sb_2xa = val; + break; + case 0x20c: + gus->ad_status |= 0x10; + if (gus->sb_ctrl & 0x20) { + if (gus->sb_nmi) + nmi_raise(); + else if (gus->irq != -1) + picint(1 << gus->irq); + } + /*FALLTHROUGH*/ + case 0x20d: + gus->sb_2xc = val; + break; + case 0x20e: + gus->sb_2xe = val; + break; + case 0x20f: + gus->reg_ctrl = val; + break; + case 0x306: + case 0x706: + if (gus->dma >= 4) + val |= 0x30; + gus->max_ctrl = (val >> 6) & 1; +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + if (val & 0x40) { + if ((val & 0xF) != ((addr >> 4) & 0xF)) { + csioport = 0x30c | ((addr >> 4) & 0xf); + io_removehandler(csioport, 4, + ad1848_read, NULL, NULL, + ad1848_write, NULL, NULL, &gus->ad1848); + csioport = 0x30c | ((val & 0xf) << 4); + io_sethandler(csioport, 4, + ad1848_read, NULL, NULL, + ad1848_write, NULL, NULL, &gus->ad1848); + } + } +#endif + break; + } } -void gus_close(void *p) +uint8_t +readgus(uint16_t addr, void *p) { - gus_t *gus = (gus_t *)p; - - free(gus->ram); - free(gus); + gus_t *gus = (gus_t *) p; + uint8_t val = 0xff; + uint16_t port; + + if ((addr == 0x388) || (addr == 0x389)) + port = addr; + else + port = addr & 0xf0f; + + switch (port) { + case 0x300: /*MIDI status*/ + val = gus->midi_status; + break; + + case 0x301: /*MIDI data*/ + val = 0; + if (gus->uart_in) { + if ((gus->midi_data == 0xaa) && (gus->midi_ctrl & MIDI_CTRL_RECEIVE)) /*Handle master reset*/ + val = gus->midi_data; + else { + val = gus->midi_queue[gus->midi_r]; + if (gus->midi_r != gus->midi_w) { + gus->midi_r++; + gus->midi_r &= 63; + } + } + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); + } + break; + + case 0x200: + return 0; + + case 0x206: /*IRQ status*/ + val = gus->irqstatus & ~0x10; + if (gus->ad_status & 0x19) + val |= 0x10; + return val; + + case 0x20F: + if (gus->max_ctrl) + val = 0x02; + else + val = 0x00; + break; + + case 0x302: + return gus->voice; + + case 0x303: + return gus->global; + + case 0x304: /*Global low*/ + switch (gus->global) { + case 0x82: /*Start addr high*/ + return gus->start[gus->voice] >> 16; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice] & 0xFF; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice] >> 6; + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice] >> 16; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice] & 0xFF; + + case 0x8F: /*IRQ status*/ + val = gus->irqstatus2; + gus->rampirqs[gus->irqstatus2 & 0x1F] = 0; + gus->waveirqs[gus->irqstatus2 & 0x1F] = 0; + gus_update_int_status(gus); + return val; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + val = 0xff; + break; + } + break; + case 0x305: /*Global high*/ + switch (gus->global) { + case 0x80: /*Voice control*/ + return gus->ctrl[gus->voice] | (gus->waveirqs[gus->voice] ? 0x80 : 0); + + case 0x82: /*Start addr high*/ + return gus->start[gus->voice] >> 24; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice] >> 8; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice] >> 14; + + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice] >> 24; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice] >> 8; + + case 0x8C: /*Pan*/ + return gus->pan_r[gus->voice]; + + case 0x8D: + return gus->rctrl[gus->voice] | (gus->rampirqs[gus->voice] ? 0x80 : 0); + + case 0x8F: /*IRQ status*/ + val = gus->irqstatus2; + gus->rampirqs[gus->irqstatus2 & 0x1F] = 0; + gus->waveirqs[gus->irqstatus2 & 0x1F] = 0; + gus_update_int_status(gus); + return val; + + case 0x41: /*DMA control*/ + val = gus->dmactrl | ((gus->irqstatus & 0x80) ? 0x40 : 0); + gus->irqstatus &= ~0x80; + return val; + case 0x45: /*Timer control*/ + return gus->tctrl; + case 0x49: /*Sampling control*/ + return 0; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + val = 0xff; + break; + } + break; + case 0x306: + case 0x706: + if (gus->max_ctrl) + val = 0x0a; /* GUS MAX */ + else + val = 0xff; /*Pre 3.7 - no mixer*/ + break; + + break; + case 0x307: /*DRAM access*/ + val = gus->ram[gus->addr]; + gus->addr &= 0xFFFFF; + if (gus->addr < gus->gus_end_ram) + val = gus->ram[gus->addr]; + else + val = 0; + return val; + case 0x309: + return 0; + + case 0x20b: + switch (gus->reg_ctrl & 0x07) { + case 1: + val = gus->gp1; + break; + case 2: + val = gus->gp2; + break; + case 3: + val = gus->gp1_addr; + break; + case 4: + val = gus->gp2_addr; + break; + } + break; + + case 0x20c: + val = gus->sb_2xc; + if (gus->reg_ctrl & 0x20) + gus->sb_2xc &= 0x80; + break; + case 0x20e: + return gus->sb_2xe; + + case 0x208: + case 0x388: + if (gus->tctrl & GUS_TIMER_CTRL_AUTO) + val = gus->sb_2xa; + else { + val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); + if (val & 0x60) + val |= 0x80; + } + break; + + case 0x209: + gus->ad_status &= ~0x01; +#ifdef OLD_NMI_BEHAVIOR + nmi = 0; +#endif + /*FALLTHROUGH*/ + case 0x389: + val = gus->ad_data; + break; + + case 0x20A: + val = gus->adcommand; + break; + } + return val; } -void gus_speed_changed(void *p) +void +gus_poll_timer_1(void *p) { - gus_t *gus = (gus_t *)p; + gus_t *gus = (gus_t *) p; - if (gus->voices < 14) - gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); + timer_advance_u64(&gus->timer_1, (uint64_t) (TIMER_USEC * 80)); + if (gus->t1on) { + gus->t1++; + if (gus->t1 > 0xFF) { + gus->t1 = gus->t1l; + gus->ad_status |= 0x40; + if (gus->tctrl & 4) { + gus->ad_status |= 0x04; + gus->irqstatus |= 0x04; + } + } + } + if (gus->irqnext) { + gus->irqnext = 0; + gus->irqstatus |= 0x80; + } + + gus_midi_update_int_status(gus); + gus_update_int_status(gus); +} + +void +gus_poll_timer_2(void *p) +{ + gus_t *gus = (gus_t *) p; + + timer_advance_u64(&gus->timer_2, (uint64_t) (TIMER_USEC * 320)); + if (gus->t2on) { + gus->t2++; + if (gus->t2 > 0xFF) { + gus->t2 = gus->t2l; + gus->ad_status |= 0x20; + if (gus->tctrl & 8) { + gus->ad_status |= 0x02; + gus->irqstatus |= 0x08; + } + } + } + if (gus->irqnext) { + gus->irqnext = 0; + gus->irqstatus |= 0x80; + } + gus_update_int_status(gus); +} + +static void +gus_update(gus_t *gus) +{ + for (; gus->pos < sound_pos_global; gus->pos++) { + if (gus->out_l < -32768) + gus->buffer[0][gus->pos] = -32768; + else if (gus->out_l > 32767) + gus->buffer[0][gus->pos] = 32767; else - gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + gus->buffer[0][gus->pos] = gus->out_l; + if (gus->out_r < -32768) + gus->buffer[1][gus->pos] = -32768; + else if (gus->out_r > 32767) + gus->buffer[1][gus->pos] = 32767; + else + gus->buffer[1][gus->pos] = gus->out_r; + } +} + +void +gus_poll_wave(void *p) +{ + gus_t *gus = (gus_t *) p; + uint32_t addr; + int d; + int16_t v; + int32_t vl; + int update_irqs = 0; + + gus_update(gus); + + timer_advance_u64(&gus->samp_timer, gus->samp_latch); + + gus->out_l = gus->out_r = 0; + + if ((gus->reset & 3) != 3) + return; + for (d = 0; d < 32; d++) { + if (!(gus->ctrl[d] & 3)) { + if (gus->ctrl[d] & 4) { + addr = gus->cur[d] >> 9; + addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = (int16_t) (int8_t) ((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); + vl += (int16_t) (int8_t) ((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); + v = vl >> 9; + } else + v = (int16_t) (int8_t) ((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); + } else { + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = ((int8_t) ((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); + vl += ((int8_t) ((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); + v = vl >> 9; + } else + v = (int16_t) (int8_t) ((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); + } + + if ((gus->rcur[d] >> 14) > 4095) + v = (int16_t) (float) (v) *24.0 * vol16bit[4095]; + else + v = (int16_t) (float) (v) *24.0 * vol16bit[(gus->rcur[d] >> 10) & 4095]; + + gus->out_l += (v * gus->pan_l[d]) / 7; + gus->out_r += (v * gus->pan_r[d]) / 7; + + if (gus->ctrl[d] & 0x40) { + gus->cur[d] -= (gus->freq[d] >> 1); + if (gus->cur[d] <= gus->start[d]) { + int diff = gus->start[d] - gus->cur[d]; + + if (gus->ctrl[d] & 8) { + if (gus->ctrl[d] & 0x10) + gus->ctrl[d] ^= 0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } else if (!(gus->rctrl[d] & 4)) { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) { + gus->waveirqs[d] = 1; + update_irqs = 1; + } + } + } else { + gus->cur[d] += (gus->freq[d] >> 1); + + if (gus->cur[d] >= gus->end[d]) { + int diff = gus->cur[d] - gus->end[d]; + + if (gus->ctrl[d] & 8) { + if (gus->ctrl[d] & 0x10) + gus->ctrl[d] ^= 0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } else if (!(gus->rctrl[d] & 4)) { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) { + gus->waveirqs[d] = 1; + update_irqs = 1; + } + } + } + } + if (!(gus->rctrl[d] & 3)) { + if (gus->rctrl[d] & 0x40) { + gus->rcur[d] -= gus->rfreq[d]; + if (gus->rcur[d] <= gus->rstart[d]) { + int diff = gus->rstart[d] - gus->rcur[d]; + if (!(gus->rctrl[d] & 8)) { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } else { + if (gus->rctrl[d] & 0x10) + gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) { + gus->rampirqs[d] = 1; + update_irqs = 1; + } + } + } else { + gus->rcur[d] += gus->rfreq[d]; + if (gus->rcur[d] >= gus->rend[d]) { + int diff = gus->rcur[d] - gus->rend[d]; + if (!(gus->rctrl[d] & 8)) { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } else { + if (gus->rctrl[d] & 0x10) + gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) { + gus->rampirqs[d] = 1; + update_irqs = 1; + } + } + } + } + } + + if (update_irqs) + gus_update_int_status(gus); +} + +static void +gus_get_buffer(int32_t *buffer, int len, void *p) +{ + gus_t *gus = (gus_t *) p; + int c; +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + if (gus->max_ctrl) + ad1848_update(&gus->ad1848); +#endif + gus_update(gus); + + for (c = 0; c < len * 2; c++) { #if defined(DEV_BRANCH) && defined(USE_GUSMAX) if (gus->max_ctrl) - ad1848_speed_changed(&gus->ad1848); + buffer[c] += (int32_t) (gus->ad1848.buffer[c] / 2); +#endif + buffer[c] += (int32_t) gus->buffer[c & 1][c >> 1]; + } + +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + if (gus->max_ctrl) + gus->ad1848.pos = 0; +#endif + gus->pos = 0; +} + +static void +gus_input_msg(void *p, uint8_t *msg, uint32_t len) +{ + gus_t *gus = (gus_t *) p; + uint8_t i; + + if (gus->sysex) + return; + + if (gus->uart_in) { + gus->midi_status |= MIDI_INT_RECEIVE; + + for (i = 0; i < len; i++) { + gus->midi_queue[gus->midi_w++] = msg[i]; + gus->midi_w &= 63; + } + + gus_midi_update_int_status(gus); + } +} + +static int +gus_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + gus_t *gus = (gus_t *) p; + uint32_t i; + + if (abort) { + gus->sysex = 0; + return 0; + } + gus->sysex = 1; + for (i = 0; i < len; i++) { + if (gus->midi_r == gus->midi_w) + return (len - i); + gus->midi_queue[gus->midi_w++] = buffer[i]; + gus->midi_w &= 63; + } + gus->sysex = 0; + return 0; +} + +void * +gus_init(const device_t *info) +{ + int c; + double out = 1.0; + uint8_t gus_ram = device_get_config_int("gus_ram"); + gus_t *gus = malloc(sizeof(gus_t)); + memset(gus, 0, sizeof(gus_t)); + + gus->gus_end_ram = 1 << (18 + gus_ram); + gus->ram = (uint8_t *) malloc(gus->gus_end_ram); + memset(gus->ram, 0x00, (gus->gus_end_ram)); + + for (c = 0; c < 32; c++) { + gus->ctrl[c] = 1; + gus->rctrl[c] = 1; + gus->rfreq[c] = 63 * 512; + } + + for (c = 4095; c >= 0; c--) { + vol16bit[c] = out; + out /= 1.002709201; /* 0.0235 dB Steps */ + } + + gus->voices = 14; + + gus->samp_latch = (uint64_t) (TIMER_USEC * (1000000.0 / 44100.0)); + + gus->t1l = gus->t2l = 0xff; + + gus->uart_out = 1; + + gus->base = device_get_config_hex16("base"); + + io_sethandler(gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0100 + gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0506 + gus->base, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); + +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + ad1848_init(&gus->ad1848, AD1848_TYPE_CS4231); + ad1848_setirq(&gus->ad1848, 5); + ad1848_setdma(&gus->ad1848, 3); + io_sethandler(0x10C + gus->base, 4, + ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &gus->ad1848); +#endif + + timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); + timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); + timer_add(&gus->timer_2, gus_poll_timer_2, gus, 1); + + sound_add_handler(gus_get_buffer, gus); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, gus_input_msg, gus_input_sysex, gus); + + return gus; +} + +void +gus_close(void *p) +{ + gus_t *gus = (gus_t *) p; + + free(gus->ram); + free(gus); +} + +void +gus_speed_changed(void *p) +{ + gus_t *gus = (gus_t *) p; + + if (gus->voices < 14) + gus->samp_latch = (uint64_t) (TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (uint64_t) (TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + +#if defined(DEV_BRANCH) && defined(USE_GUSMAX) + if (gus->max_ctrl) + ad1848_speed_changed(&gus->ad1848); #endif } static const device_config_t gus_config[] = { - { - "type", "GUS type", CONFIG_SELECTION, "", 0, - { - { - "Classic", GUS_CLASSIC - }, + // clang-format off + { + .name = "type", + .description = "GUS type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "Classic", + .value = GUS_CLASSIC + }, #if defined(DEV_BRANCH) && defined(USE_GUSMAX) - { - "MAX", GUS_MAX - }, + { + .description = "MAX", + .value = GUS_MAX + }, #endif - { - NULL - } - }, - }, - { - "base", "Address", CONFIG_HEX16, "", 0x220, - { - { - "210H", 0x210 - }, - { - "220H", 0x220 - }, - { - "230H", 0x230 - }, - { - "240H", 0x240 - }, - { - "250H", 0x250 - }, - { - "260H", 0x260 - }, - }, - }, - { - "gus_ram", "Onboard RAM", CONFIG_SELECTION, "", 0, - { - { - "256 KB", 0 - }, - { - "512 KB", 1 - }, - { - "1 MB", 2 - }, - { - NULL - } - } - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 - } + { NULL } + }, + }, + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "210H", + .value = 0x210 + }, + { + .description = "220H", + .value = 0x220 + }, + { + .description = "230H", + .value = 0x230 + }, + { + .description = "240H", + .value = 0x240 + }, + { + .description = "250H", + .value = 0x250 + }, + { + .description = "260H", + .value = 0x260 + }, + }, + }, + { + .name = "gus_ram", + "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "256 KB", + .value = 0 + }, + { + .description = "512 KB", + .value = 1 + }, + { + .description = "1 MB", + .value = 2 + }, + { NULL } + } + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format off }; -const device_t gus_device = -{ - "Gravis UltraSound", - DEVICE_ISA, - 0, - gus_init, gus_close, NULL, - NULL, - gus_speed_changed, - NULL, - gus_config +const device_t gus_device = { + .name = "Gravis UltraSound", + .internal_name = "gus", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = gus_init, + .close = gus_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = gus_speed_changed, + .force_redraw = NULL, + .config = gus_config }; diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index b869e2d9f..70e02d847 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -1,129 +1,133 @@ -#include #include -#include +#include #include +#include #include -#include <86box/86box.h> + #include "cpu.h" -#include <86box/machine.h> -#include <86box/lpt.h> -#include <86box/timer.h> -#include <86box/sound.h> +#include <86box/86box.h> #include <86box/filters.h> +#include <86box/lpt.h> +#include <86box/machine.h> +#include <86box/sound.h> +#include <86box/timer.h> -typedef struct lpt_dac_t -{ - void *lpt; +typedef struct lpt_dac_t { + void *lpt; - uint8_t dac_val_l, dac_val_r; - - int is_stereo; - int channel; - - int16_t buffer[2][SOUNDBUFLEN]; - int pos; + uint8_t dac_val_l, dac_val_r; + + int is_stereo; + int channel; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; } lpt_dac_t; -static void dac_update(lpt_dac_t *lpt_dac) +static void +dac_update(lpt_dac_t *lpt_dac) { - for (; lpt_dac->pos < sound_pos_global; lpt_dac->pos++) - { - lpt_dac->buffer[0][lpt_dac->pos] = (int8_t)(lpt_dac->dac_val_l ^ 0x80) * 0x40; - lpt_dac->buffer[1][lpt_dac->pos] = (int8_t)(lpt_dac->dac_val_r ^ 0x80) * 0x40; - } + for (; lpt_dac->pos < sound_pos_global; lpt_dac->pos++) { + lpt_dac->buffer[0][lpt_dac->pos] = (int8_t) (lpt_dac->dac_val_l ^ 0x80) * 0x40; + lpt_dac->buffer[1][lpt_dac->pos] = (int8_t) (lpt_dac->dac_val_r ^ 0x80) * 0x40; + } } - -static void dac_write_data(uint8_t val, void *p) +static void +dac_write_data(uint8_t val, void *p) { - lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + lpt_dac_t *lpt_dac = (lpt_dac_t *) p; - if (lpt_dac->is_stereo) - { - if (lpt_dac->channel) - lpt_dac->dac_val_r = val; - else - lpt_dac->dac_val_l = val; - } - else - lpt_dac->dac_val_l = lpt_dac->dac_val_r = val; - dac_update(lpt_dac); + if (lpt_dac->is_stereo) { + if (lpt_dac->channel) + lpt_dac->dac_val_r = val; + else + lpt_dac->dac_val_l = val; + } else + lpt_dac->dac_val_l = lpt_dac->dac_val_r = val; + dac_update(lpt_dac); } -static void dac_write_ctrl(uint8_t val, void *p) +static void +dac_write_ctrl(uint8_t val, void *p) { - lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + lpt_dac_t *lpt_dac = (lpt_dac_t *) p; - if (lpt_dac->is_stereo) - lpt_dac->channel = val & 0x01; + if (lpt_dac->is_stereo) + lpt_dac->channel = val & 0x01; } -static uint8_t dac_read_status(void *p) +static uint8_t +dac_read_status(void *p) { - return 0; + return 0x0f; } - -static void dac_get_buffer(int32_t *buffer, int len, void *p) +static void +dac_get_buffer(int32_t *buffer, int len, void *p) { - lpt_dac_t *lpt_dac = (lpt_dac_t *)p; - int c; - - dac_update(lpt_dac); - - for (c = 0; c < len; c++) - { - buffer[c*2] += dac_iir(0, lpt_dac->buffer[0][c]); - buffer[c*2 + 1] += dac_iir(1, lpt_dac->buffer[1][c]); - } - lpt_dac->pos = 0; + lpt_dac_t *lpt_dac = (lpt_dac_t *) p; + int c; + + dac_update(lpt_dac); + + for (c = 0; c < len; c++) { + buffer[c * 2] += dac_iir(0, lpt_dac->buffer[0][c]); + buffer[c * 2 + 1] += dac_iir(1, lpt_dac->buffer[1][c]); + } + lpt_dac->pos = 0; } -static void *dac_init(void *lpt) +static void * +dac_init(void *lpt) { - lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); - memset(lpt_dac, 0, sizeof(lpt_dac_t)); + lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); + memset(lpt_dac, 0, sizeof(lpt_dac_t)); - lpt_dac->lpt = lpt; + lpt_dac->lpt = lpt; - sound_add_handler(dac_get_buffer, lpt_dac); - - return lpt_dac; -} -static void *dac_stereo_init(void *lpt) -{ - lpt_dac_t *lpt_dac = dac_init(lpt); - - lpt_dac->is_stereo = 1; - - return lpt_dac; -} -static void dac_close(void *p) -{ - lpt_dac_t *lpt_dac = (lpt_dac_t *)p; - - free(lpt_dac); + sound_add_handler(dac_get_buffer, lpt_dac); + + return lpt_dac; } -const lpt_device_t lpt_dac_device = +static void * +dac_stereo_init(void *lpt) { - "LPT DAC / Covox Speech Thing", - dac_init, - dac_close, - dac_write_data, - dac_write_ctrl, - NULL, - dac_read_status, - NULL + lpt_dac_t *lpt_dac = dac_init(lpt); + + lpt_dac->is_stereo = 1; + + return lpt_dac; +} +static void +dac_close(void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *) p; + + free(lpt_dac); +} + +const lpt_device_t lpt_dac_device = { + .name = "LPT DAC / Covox Speech Thing", + .internal_name = "lpt_dac", + .init = dac_init, + .close = dac_close, + .write_data = dac_write_data, + .write_ctrl = dac_write_ctrl, + .read_data = NULL, + .read_status = dac_read_status, + .read_ctrl = NULL }; -const lpt_device_t lpt_dac_stereo_device = -{ - "Stereo LPT DAC", - dac_stereo_init, - dac_close, - dac_write_data, - dac_write_ctrl, - NULL, - dac_read_status, - NULL + +const lpt_device_t lpt_dac_stereo_device = { + .name = "Stereo LPT DAC", + .internal_name = "lpt_dac_stereo", + .init = dac_stereo_init, + .close = dac_close, + .write_data = dac_write_data, + .write_ctrl = dac_write_ctrl, + .read_data = NULL, + .read_status = dac_read_status, + .read_ctrl = NULL }; diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index c1945d4ff..a855425b2 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -1,141 +1,144 @@ -#include #include -#include +#include #include +#include #include -#include <86box/86box.h> + #include "cpu.h" -#include <86box/machine.h> -#include <86box/timer.h> -#include <86box/lpt.h> -#include <86box/sound.h> +#include <86box/86box.h> #include <86box/filters.h> +#include <86box/lpt.h> +#include <86box/machine.h> +#include <86box/sound.h> +#include <86box/timer.h> -typedef struct dss_t -{ - void *lpt; +typedef struct dss_t { + void *lpt; - uint8_t fifo[16]; - int read_idx, write_idx; - - uint8_t dac_val, - status; - - pc_timer_t timer; - - int16_t buffer[SOUNDBUFLEN]; - int pos; + uint8_t fifo[16]; + int read_idx, write_idx; + + uint8_t dac_val, + status; + + pc_timer_t timer; + + int16_t buffer[SOUNDBUFLEN]; + int pos; } dss_t; -static void dss_update(dss_t *dss) +static void +dss_update(dss_t *dss) { - for (; dss->pos < sound_pos_global; dss->pos++) - dss->buffer[dss->pos] = (int8_t)(dss->dac_val ^ 0x80) * 0x40; + for (; dss->pos < sound_pos_global; dss->pos++) + dss->buffer[dss->pos] = (int8_t) (dss->dac_val ^ 0x80) * 0x40; } - -static void dss_update_status(dss_t *dss) +static void +dss_update_status(dss_t *dss) { - uint8_t old = dss->status; + uint8_t old = dss->status; - dss->status &= ~0x40; + dss->status &= ~0x40; - if ((dss->write_idx - dss->read_idx) >= 16) - dss->status |= 0x40; + if ((dss->write_idx - dss->read_idx) >= 16) + dss->status |= 0x40; - if ((old & 0x40) && !(dss->status & 0x40)) - lpt_irq(dss->lpt, 1); + if ((old & 0x40) && !(dss->status & 0x40)) + lpt_irq(dss->lpt, 1); } - -static void dss_write_data(uint8_t val, void *p) +static void +dss_write_data(uint8_t val, void *p) { - dss_t *dss = (dss_t *)p; + dss_t *dss = (dss_t *) p; - if ((dss->write_idx - dss->read_idx) < 16) - { - dss->fifo[dss->write_idx & 15] = val; - dss->write_idx++; - dss_update_status(dss); - } + if ((dss->write_idx - dss->read_idx) < 16) { + dss->fifo[dss->write_idx & 15] = val; + dss->write_idx++; + dss_update_status(dss); + } } -static void dss_write_ctrl(uint8_t val, void *p) +static void +dss_write_ctrl(uint8_t val, void *p) { } -static uint8_t dss_read_status(void *p) +static uint8_t +dss_read_status(void *p) { - dss_t *dss = (dss_t *)p; + dss_t *dss = (dss_t *) p; - return dss->status; + return dss->status | 0x0f; } - -static void dss_get_buffer(int32_t *buffer, int len, void *p) +static void +dss_get_buffer(int32_t *buffer, int len, void *p) { - dss_t *dss = (dss_t *)p; - int c; - int16_t val; - float fval; - - dss_update(dss); - - for (c = 0; c < len*2; c += 2) - { - fval = dss_iir((float)dss->buffer[c >> 1]); - val = (float) fval; - - buffer[c] += val; - buffer[c+1] += val; - } + dss_t *dss = (dss_t *) p; + int c; + int16_t val; + float fval; - dss->pos = 0; + dss_update(dss); + + for (c = 0; c < len * 2; c += 2) { + fval = dss_iir((float) dss->buffer[c >> 1]); + val = (float) fval; + + buffer[c] += val; + buffer[c + 1] += val; + } + + dss->pos = 0; } -static void dss_callback(void *p) +static void +dss_callback(void *p) { - dss_t *dss = (dss_t *)p; + dss_t *dss = (dss_t *) p; - dss_update(dss); + dss_update(dss); - if ((dss->write_idx - dss->read_idx) > 0) - { - dss->dac_val = dss->fifo[dss->read_idx & 15]; - dss->read_idx++; - dss_update_status(dss); - } + if ((dss->write_idx - dss->read_idx) > 0) { + dss->dac_val = dss->fifo[dss->read_idx & 15]; + dss->read_idx++; + dss_update_status(dss); + } - timer_advance_u64(&dss->timer, (TIMER_USEC * (1000000.0 / 7000.0))); + timer_advance_u64(&dss->timer, (TIMER_USEC * (1000000.0 / 7000.0))); } -static void *dss_init(void *lpt) +static void * +dss_init(void *lpt) { - dss_t *dss = malloc(sizeof(dss_t)); - memset(dss, 0, sizeof(dss_t)); + dss_t *dss = malloc(sizeof(dss_t)); + memset(dss, 0, sizeof(dss_t)); - dss->lpt = lpt; + dss->lpt = lpt; - sound_add_handler(dss_get_buffer, dss); - timer_add(&dss->timer, dss_callback, dss, 1); + sound_add_handler(dss_get_buffer, dss); + timer_add(&dss->timer, dss_callback, dss, 1); - return dss; + return dss; } -static void dss_close(void *p) +static void +dss_close(void *p) { - dss_t *dss = (dss_t *)p; - - free(dss); + dss_t *dss = (dss_t *) p; + + free(dss); } -const lpt_device_t dss_device = -{ - "Disney Sound Source", - dss_init, - dss_close, - dss_write_data, - dss_write_ctrl, - NULL, - dss_read_status, - NULL +const lpt_device_t dss_device = { + .name = "Disney Sound Source", + .internal_name = "dss", + .init = dss_init, + .close = dss_close, + .write_data = dss_write_data, + .write_ctrl = dss_write_ctrl, + .read_data = NULL, + .read_status = dss_read_status, + .read_ctrl = NULL }; diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index c9523c026..6ee107923 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -1,85 +1,78 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Roland MPU-401 emulation. + * Roland MPU-401 emulation. * * * - * Authors: Sarah Walker, - * DOSBox Team, - * Miran Grca, - * TheCollector1995, + * Authors: Sarah Walker, + * DOSBox Team, + * Miran Grca, + * TheCollector1995, * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2008-2020 DOSBox Team. - * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2008-2020 DOSBox Team. + * Copyright 2016-2020 Miran Grca. */ #include #include #include -#include #include -#include +#include #include #define HAVE_STDARG_H + #include <86box/86box.h> #include <86box/device.h> -#include <86box/plat.h> #include <86box/io.h> #include <86box/machine.h> #include <86box/mca.h> -#include <86box/pic.h> -#include <86box/timer.h> -#include <86box/sound.h> -#include <86box/snd_mpu401.h> #include <86box/midi.h> +#include <86box/pic.h> +#include <86box/plat.h> +#include <86box/timer.h> +#include <86box/snd_mpu401.h> +#include <86box/sound.h> - -static uint32_t MPUClockBase[8] = {48,72,96,120,144,168,192}; -static uint8_t cth_data[16] = {0,0,0,0,1,0,0,0,1,0,1,0,1,1,1,0}; - +static uint32_t MPUClockBase[8] = { 48, 72, 96, 120, 144, 168, 192 }; +static uint8_t cth_data[16] = { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0 }; enum { STATUS_OUTPUT_NOT_READY = 0x40, STATUS_INPUT_NOT_READY = 0x80 }; - int mpu401_standalone_enable = 0; - static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t track); static void MPU401_EOIHandler(void *priv); static void MPU401_EOIHandlerDispatch(void *p); static void MPU401_NotesOff(mpu_t *mpu, int i); - #ifdef ENABLE_MPU401_LOG int mpu401_do_log = ENABLE_MPU401_LOG; - static void mpu401_log(const char *fmt, ...) { va_list ap; if (mpu401_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define mpu401_log(fmt, ...) +# define mpu401_log(fmt, ...) #endif - static void MPU401_ReCalcClock(mpu_t *mpu) { @@ -87,963 +80,984 @@ MPU401_ReCalcClock(mpu_t *mpu) int32_t freq; if (mpu->clock.timebase < 72) { - maxtempo = 240; - mintempo = 32; + maxtempo = 240; + mintempo = 32; } else if (mpu->clock.timebase < 120) { - maxtempo = 240; - mintempo = 16; + maxtempo = 240; + mintempo = 16; } else if (mpu->clock.timebase < 168) { - maxtempo = 208; - mintempo = 8; + maxtempo = 208; + mintempo = 8; } else { - maxtempo = 179; - mintempo = 8; + maxtempo = 179; + mintempo = 8; } - mpu->clock.freq = ((uint32_t)(mpu->clock.tempo * 2 * mpu->clock.tempo_rel)) >> 6; - mpu->clock.freq = mpu->clock.timebase * (mpu->clock.freq < (mintempo * 2) ? mintempo : - ((mpu->clock.freq / 2) < maxtempo ? (mpu->clock.freq / 2) : maxtempo)); + mpu->clock.freq = ((uint32_t) (mpu->clock.tempo * 2 * mpu->clock.tempo_rel)) >> 6; + mpu->clock.freq = mpu->clock.timebase * (mpu->clock.freq < (mintempo * 2) ? mintempo : ((mpu->clock.freq / 2) < maxtempo ? (mpu->clock.freq / 2) : maxtempo)); if (mpu->state.sync_in) { - freq = (int32_t)((float)(mpu->clock.freq) * mpu->clock.freq_mod); - if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo))) - mpu->clock.freq = freq; - } + freq = (int32_t) ((float) (mpu->clock.freq) * mpu->clock.freq_mod); + if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo))) + mpu->clock.freq = freq; + } } - static void MPU401_StartClock(mpu_t *mpu) { if (mpu->clock.active) - return; + return; if (!(mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON))) - return; + return; mpu->clock.active = 1; timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); } - static void MPU401_StopClock(mpu_t *mpu) { if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)) - return; + return; mpu->clock.active = 0; timer_disable(&mpu->mpu401_event_callback); } - static void MPU401_RunClock(mpu_t *mpu) { if (!mpu->clock.active) { - timer_disable(&mpu->mpu401_event_callback); - return; + timer_disable(&mpu->mpu401_event_callback); + return; } timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); - mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); + mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); } - static void MPU401_QueueByteEx(mpu_t *mpu, uint8_t data, int irq) { if (mpu->state.block_ack) { - mpu->state.block_ack = 0; - return; + mpu->state.block_ack = 0; + return; } if (mpu->queue_used == 0) { - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 1); - else { - mpu->state.irq_pending = 1; - picint(1 << mpu->irq); - } + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 1); + else { + mpu->state.irq_pending = 1; + picint(1 << mpu->irq); + } } if (mpu->queue_used < MPU401_QUEUE) { - int pos = mpu->queue_used+mpu->queue_pos; + int pos = mpu->queue_used + mpu->queue_pos; - if (mpu->queue_pos >= MPU401_QUEUE) - mpu->queue_pos -= MPU401_QUEUE; - if (pos>=MPU401_QUEUE) - pos-=MPU401_QUEUE; + if (mpu->queue_pos >= MPU401_QUEUE) + mpu->queue_pos -= MPU401_QUEUE; + if (pos >= MPU401_QUEUE) + pos -= MPU401_QUEUE; - mpu->queue_used++; - mpu->queue[pos] = data; + mpu->queue_used++; + mpu->queue[pos] = data; } } - static void -MPU401_QueueByte(mpu_t *mpu, uint8_t data) +MPU401_QueueByte(mpu_t *mpu, uint8_t data) { MPU401_QueueByteEx(mpu, data, 1); } - static int MPU401_IRQPending(mpu_t *mpu) { int irq_pending; if (mpu->ext_irq_pending) - irq_pending = mpu->ext_irq_pending(mpu->priv); + irq_pending = mpu->ext_irq_pending(mpu->priv); else - irq_pending = mpu->state.irq_pending; + irq_pending = mpu->state.irq_pending; return irq_pending; } - static void MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) { uint32_t cnt = 0; - int pos; + int pos; while (cnt < len) { - if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { - pos = mpu->rec_queue_used + mpu->rec_queue_pos; - if (pos >= MPU401_INPUT_QUEUE) - pos -= MPU401_INPUT_QUEUE; - mpu->rec_queue[pos] = buf[cnt]; - mpu->rec_queue_used++; - if ((!mpu->state.sysex_in_finished) && (buf[cnt] == MSG_EOX)) { - /* finish sysex */ - mpu->state.sysex_in_finished = 1; - break; - } - cnt++; - } + if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { + pos = mpu->rec_queue_used + mpu->rec_queue_pos; + if (pos >= MPU401_INPUT_QUEUE) + pos -= MPU401_INPUT_QUEUE; + mpu->rec_queue[pos] = buf[cnt]; + mpu->rec_queue_used++; + if ((!mpu->state.sysex_in_finished) && (buf[cnt] == MSG_EOX)) { + /* finish sysex */ + mpu->state.sysex_in_finished = 1; + break; + } + cnt++; + } } if (mpu->queue_used == 0) { - if (mpu->state.rec_copy || MPU401_IRQPending(mpu)) { - if (MPU401_IRQPending(mpu)) { - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } - } - return; - } - mpu->state.rec_copy = 1; - if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) - mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; - MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); - mpu->rec_queue_used--; - mpu->rec_queue_pos++; + if (mpu->state.rec_copy || MPU401_IRQPending(mpu)) { + if (MPU401_IRQPending(mpu)) { + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } + } + return; + } + mpu->state.rec_copy = 1; + if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) + mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; + MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); + mpu->rec_queue_used--; + mpu->rec_queue_pos++; } } - static void -MPU401_ClrQueue(mpu_t *mpu) +MPU401_ClrQueue(mpu_t *mpu) { - mpu->queue_used = 0; - mpu->queue_pos = 0; - mpu->rec_queue_used = 0; - mpu->rec_queue_pos = 0; + mpu->queue_used = 0; + mpu->queue_pos = 0; + mpu->rec_queue_used = 0; + mpu->rec_queue_pos = 0; mpu->state.sysex_in_finished = 1; if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); + mpu->ext_irq_update(mpu->priv, 0); else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); } } - static void -MPU401_Reset(mpu_t *mpu) +MPU401_Reset(mpu_t *mpu) { uint8_t i; #ifdef DOSBOX_CODE if (mpu->mode == M_INTELLIGENT) { - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } } #else if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); + mpu->ext_irq_update(mpu->priv, 0); else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); } #endif - mpu->mode = M_INTELLIGENT; - mpu->midi_thru = 0; - mpu->state.rec = M_RECOFF; + mpu->mode = M_INTELLIGENT; + mpu->midi_thru = 0; + mpu->state.rec = M_RECOFF; mpu->state.eoi_scheduled = 0; - mpu->state.wsd = 0; - mpu->state.wsm = 0; - mpu->state.conductor = 0; - mpu->state.cond_req = 0; - mpu->state.cond_set = 0; - mpu->state.playing = 0; - mpu->state.run_irq = 0; - mpu->state.cmask = 0xff; + mpu->state.wsd = 0; + mpu->state.wsm = 0; + mpu->state.conductor = 0; + mpu->state.cond_req = 0; + mpu->state.cond_set = 0; + mpu->state.playing = 0; + mpu->state.run_irq = 0; + mpu->state.cmask = 0xff; mpu->state.amask = mpu->state.tmask = 0; - mpu->state.midi_mask = 0xffff; - mpu->state.command_byte = 0; - mpu->state.block_ack = 0; + mpu->state.midi_mask = 0xffff; + mpu->state.command_byte = 0; + mpu->state.block_ack = 0; mpu->clock.tempo = mpu->clock.old_tempo = 100; mpu->clock.timebase = mpu->clock.old_timebase = 120; mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 0x40; - mpu->clock.freq_mod = 1.0; - mpu->clock.tempo_grad = 0; + mpu->clock.freq_mod = 1.0; + mpu->clock.tempo_grad = 0; MPU401_StopClock(mpu); MPU401_ReCalcClock(mpu); for (i = 0; i < 4; i++) - mpu->clock.cth_rate[i] = 60; + mpu->clock.cth_rate[i] = 60; - mpu->clock.cth_counter = 0; - mpu->clock.midimetro = 12; - mpu->clock.metromeas = 8; + mpu->clock.cth_counter = 0; + mpu->clock.midimetro = 12; + mpu->clock.metromeas = 8; mpu->filter.rec_measure_end = 1; - mpu->filter.rt_out = 1; - mpu->filter.rt_affection = 1; + mpu->filter.rt_out = 1; + mpu->filter.rt_affection = 1; mpu->filter.allnotesoff_out = 1; - mpu->filter.all_thru = 1; - mpu->filter.midi_thru = 1; + mpu->filter.all_thru = 1; + mpu->filter.midi_thru = 1; mpu->filter.commonmsgs_thru = 1; /* Reset channel reference and input tables. */ for (i = 0; i < 4; i++) { - mpu->chanref[i].on = 1; - mpu->chanref[i].chan = i; - mpu->ch_toref[i] = i; + mpu->chanref[i].on = 1; + mpu->chanref[i].chan = i; + mpu->ch_toref[i] = i; } for (i = 0; i < 16; i++) { - mpu->inputref[i].on = 1; - mpu->inputref[i].chan = i; - if (i > 3) - mpu->ch_toref[i] = 4; /* Dummy reftable. */ + mpu->inputref[i].on = 1; + mpu->inputref[i].chan = i; + if (i > 3) + mpu->ch_toref[i] = 4; /* Dummy reftable. */ } MPU401_ClrQueue(mpu); mpu->state.data_onoff = -1; - mpu->state.req_mask = 0; - mpu->condbuf.counter = 0; - mpu->condbuf.type = T_OVERFLOW; + mpu->state.req_mask = 0; + mpu->condbuf.counter = 0; + mpu->condbuf.type = T_OVERFLOW; for (i = 0; i < 8; i++) { - mpu->playbuf[i].type = T_OVERFLOW; - mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + mpu->playbuf[i].counter = 0; } /* Clear MIDI buffers, terminate notes. */ midi_clear_buffer(); for (i = 0xb0; i <= 0xbf; i++) { - midi_raw_out_byte(i); - midi_raw_out_byte(0x7b); - midi_raw_out_byte(0); + midi_raw_out_byte(i); + midi_raw_out_byte(0x7b); + midi_raw_out_byte(0); } } - static void -MPU401_ResetDone(void *priv) +MPU401_ResetDone(void *priv) { - mpu_t *mpu = (mpu_t *)priv; + mpu_t *mpu = (mpu_t *) priv; mpu401_log("MPU-401 reset callback\n"); timer_disable(&mpu->mpu401_reset_callback); mpu->state.reset = 0; - + if (mpu->state.cmd_pending) { - MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1); - mpu->state.cmd_pending = 0; + MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1); + mpu->state.cmd_pending = 0; } } - static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) -{ +{ uint8_t i, j, was_uart, recmsg[3]; if (mpu->state.reset) - mpu->state.cmd_pending = val + 1; + mpu->state.cmd_pending = val + 1; /* The only command recognized in UART mode is 0xFF: Reset and return to Intelligent mode. */ if ((val != 0xff) && (mpu->mode == M_UART)) - return; + return; /* In Intelligent mode, UART-only variants of the MPU-401 only support commands 0x3F and 0xFF. */ if (!mpu->intelligent && (val != 0x3f) && (val != 0xff)) - return; + return; /* Hack: Enable midi through after the first mpu401 command is written. */ mpu->midi_thru = 1; if (val <= 0x2f) { /* Sequencer state */ - int send_prchg = 0; - if ((val & 0xf) < 0xc) { - switch (val & 3) { /* MIDI realtime messages */ - case 1: - mpu->state.last_rtcmd = 0xfc; - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(0xfc); - mpu->clock.meas_old = mpu->clock.measure_counter; - mpu->clock.cth_old = mpu->clock.cth_counter; - break; - case 2: - mpu->state.last_rtcmd = 0xfa; - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(0xfb); - mpu->clock.measure_counter = mpu->clock.meas_old = 0; - mpu->clock.cth_counter = mpu->clock.cth_old = 0; - break; - case 3: - mpu->state.last_rtcmd = 0xfc; - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(0xfa); - mpu->clock.measure_counter = mpu->clock.meas_old; - mpu->clock.cth_counter = mpu->clock.cth_old; - break; - } - switch (val & 0xc) { /* Playing */ - case 0x4: /* Stop */ - mpu->state.playing = 0; - MPU401_StopClock(mpu); - for (i = 0; i < 16; i++) - MPU401_NotesOff(mpu, i); - mpu->filter.prchg_mask = 0; - break; - case 0x8: /* Start */ - mpu->state.playing = 1; - MPU401_StartClock(mpu); - break; - } - switch (val & 0x30) { /* Recording */ - case 0: /* check if it waited for MIDI RT command */ - if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB)) - break; - mpu->state.rec = M_RECON; - MPU401_StartClock(mpu); - if (mpu->filter.prchg_mask) - send_prchg = 1; - break; - case 0x10: /* Stop */ - mpu->state.rec = M_RECOFF; - MPU401_StopClock(mpu); - MPU401_QueueByte(mpu, MSG_MPU_ACK); - MPU401_QueueByte(mpu, mpu->clock.rec_counter); - MPU401_QueueByte(mpu, MSG_MPU_END); - mpu->filter.prchg_mask = 0; - mpu->clock.rec_counter = 0; - return; - case 0x20: /* Start */ - if (!(mpu->state.rec == M_RECON)) { - mpu->clock.rec_counter = 0; - mpu->state.rec = M_RECSTB; - } - if ((mpu->state.last_rtcmd == 0xfa) || (mpu->state.last_rtcmd == 0xfb)) { - mpu->clock.rec_counter = 0; - mpu->state.rec = M_RECON; - if (mpu->filter.prchg_mask) - send_prchg = 1; - MPU401_StartClock(mpu); - } - break; - } - } - MPU401_QueueByte(mpu, MSG_MPU_ACK); - /* record counter hack: needed by Prism, but sent only on cmd 0x20/0x26 (or breaks Ballade) */ - uint8_t rec_cnt = mpu->clock.rec_counter; - if (((val == 0x20) || (val == 0x26)) && (mpu->state.rec == M_RECON)) - MPU401_RecQueueBuffer(mpu, &rec_cnt, 1, 0); - - if (send_prchg) { - for (i = 0; i < 16; i++) { - if (mpu->filter.prchg_mask & (1 << i)) { - recmsg[0] = mpu->clock.rec_counter; - recmsg[1] = 0xc0 | i; - recmsg[2] = mpu->filter.prchg_buf[i]; - MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); - mpu->filter.prchg_mask &= ~(1 << i); - } - } - } - } else if ((val >= 0xa0) && (val <= 0xa7)) /* Request play counter */ - MPU401_QueueByte(mpu, mpu->playbuf[val & 7].counter); - else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */ - mpu->state.old_track = mpu->state.track; - mpu->state.track= val & 7; - mpu->state.wsd = 1; - mpu->state.wsm = 0; - mpu->state.wsd_start = 1; - } else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */ - mpu->chanref[(val >> 4) - 4].on = 1; - mpu->chanref[(val >> 4) - 4].chan = val & 0x0f; - mpu->chanref[(val >> 4) - 4].trmask = 0; - for (i = 0; i < 4; i++) - mpu->chanref[(val >> 4) - 4].key[i] = 0; - for (i = 0; i < 16; i++) { - if (mpu->ch_toref[i] == ((val >> 4) - 4)) - mpu->ch_toref[i] = 4; - } - mpu->ch_toref[val & 0x0f] = (val >> 4) - 4; - } else switch (val) { - case 0x30: /* Configuration 0x30 - 0x39 */ - mpu->filter.allnotesoff_out = 0; - break; - case 0x32: - mpu->filter.rt_out = 0; - break; - case 0x33: - mpu->filter.all_thru = 0; - mpu->filter.commonmsgs_thru = 0; - mpu->filter.midi_thru = 0; - for (i = 0; i < 16; i++) { - mpu->inputref[i].on = 0; - for (j = 0; j < 4; j++) - mpu->inputref[i].key[j] = 0; - } - break; - case 0x34: - mpu->filter.timing_in_stop = 1; - break; - case 0x35: - mpu->filter.modemsgs_in = 1; - break; - case 0x37: - mpu->filter.sysex_thru = 1; - break; - case 0x38: - mpu->filter.commonmsgs_in = 1; - break; - case 0x39: - mpu->filter.rt_in = 1; - break; - case 0x3f: /* UART mode */ - mpu401_log("MPU-401: Set UART mode %X\n",val); - MPU401_QueueByte(mpu, MSG_MPU_ACK); - mpu->mode = M_UART; - return; - case 0x80: /* Internal clock */ - if (mpu->clock.active && mpu->state.sync_in) { - timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); - mpu->clock.freq_mod = 1.0; - } - mpu->state.sync_in = 0; - break; - case 0x81: /* Sync to tape signal */ - case 0x82: /* Sync to MIDI */ - mpu->clock.ticks_in = 0; - mpu->state.sync_in = 1; - break; - case 0x86: case 0x87: /* Bender */ - mpu->filter.bender_in = !!(val & 1); - break; - case 0x88: case 0x89: /* MIDI through */ - mpu->filter.midi_thru = !!(val & 1); - for (i = 0; i < 16; i++) { - mpu->inputref[i].on = mpu->filter.midi_thru; - if (!(val & 1)) { - for (j = 0; j < 4; j++) - mpu->inputref[i].key[j] = 0; - } - } - break; - case 0x8a: case 0x8b: /* Data in stop */ - mpu->filter.data_in_stop = !!(val & 1); - break; - case 0x8c: case 0x8d: /* Send measure end */ - mpu->filter.rec_measure_end = !!(val & 1); - break; - case 0x8e: case 0x8f: /* Conductor */ - mpu->state.cond_set = !!(val & 1); - break; - case 0x90: case 0x91: /* Realtime affection */ - mpu->filter.rt_affection = !!(val & 1); - break; - case 0x94: /* Clock to host */ - mpu->state.clock_to_host = 0; - MPU401_StopClock(mpu); - break; - case 0x95: - mpu->state.clock_to_host = 1; - MPU401_StartClock(mpu); - break; - case 0x96: case 0x97: /* Sysex input allow */ - mpu->filter.sysex_in = !!(val & 1); - if (val & 1) - mpu->filter.sysex_thru = 0; - break; - case 0x98: case 0x99: case 0x9a: case 0x9b: /* Reference tables on/off */ - case 0x9c: case 0x9d: case 0x9e: case 0x9f: - mpu->chanref[(val - 0x98) / 2].on = !!(val & 1); - break; - /* Commands 0xa# returning data */ - case 0xab: /* Request and clear recording counter */ - MPU401_QueueByte(mpu, MSG_MPU_ACK); - MPU401_QueueByte(mpu, 0); - return; - case 0xac: /* Request version */ - MPU401_QueueByte(mpu, MSG_MPU_ACK); - MPU401_QueueByte(mpu, MPU401_VERSION); - return; - case 0xad: /* Request revision */ - MPU401_QueueByte(mpu, MSG_MPU_ACK); - MPU401_QueueByte(mpu, MPU401_REVISION); - return; - case 0xaf: /* Request tempo */ - MPU401_QueueByte(mpu, MSG_MPU_ACK); - MPU401_QueueByte(mpu, mpu->clock.tempo); - return; - case 0xb1: /* Reset relative tempo */ - mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; - mpu->clock.tempo_rel = 0x40; - break; - case 0xb8: /* Clear play counters */ - mpu->state.last_rtcmd = 0; - for (i = 0; i < 8; i++) { - mpu->playbuf[i].counter = 0; - mpu->playbuf[i].type = T_OVERFLOW; - } - mpu->condbuf.counter = 0; - mpu->condbuf.type = T_OVERFLOW; - mpu->state.amask = mpu->state.tmask; - mpu->state.conductor = mpu->state.cond_set; - mpu->clock.cth_counter = mpu->clock.cth_old = 0; - mpu->clock.measure_counter = mpu->clock.meas_old = 0; - break; - case 0xb9: /* Clear play map */ - for (i = 0; i < 16; i++) - MPU401_NotesOff(mpu, i); - for (i = 0; i < 8; i++) { - mpu->playbuf[i].counter = 0; - mpu->playbuf[i].type = T_OVERFLOW; - } - mpu->state.last_rtcmd = 0; - mpu->clock.cth_counter = mpu->clock.cth_old = 0; - mpu->clock.measure_counter = mpu->clock.meas_old = 0; - break; - case 0xba: /* Clear record counter */ - mpu->clock.rec_counter = 0; - break; - case 0xc2: case 0xc3: case 0xc4: /* Internal timebase */ - case 0xc5: case 0xc6: case 0xc7: case 0xc8: - mpu->clock.timebase = MPUClockBase[val-0xc2]; - MPU401_ReCalcClock(mpu); - break; - case 0xdf: /* Send system message */ - mpu->state.wsd = 0; - mpu->state.wsm = 1; - mpu->state.wsd_start = 1; - break; - /* Commands with data byte */ - case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: - case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: - mpu->state.command_byte = val; - break; - case 0xff: /* Reset MPU-401 */ - mpu401_log("MPU-401: Reset %X\n", val); - timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC); - mpu->state.reset = 1; - was_uart = (mpu->mode == M_UART); - MPU401_Reset(mpu); - if (was_uart) - return; - break; + int send_prchg = 0; + if ((val & 0xf) < 0xc) { + switch (val & 3) { /* MIDI realtime messages */ + case 1: + mpu->state.last_rtcmd = 0xfc; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfc); + mpu->clock.meas_old = mpu->clock.measure_counter; + mpu->clock.cth_old = mpu->clock.cth_counter; + break; + case 2: + mpu->state.last_rtcmd = 0xfa; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfb); + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + break; + case 3: + mpu->state.last_rtcmd = 0xfc; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfa); + mpu->clock.measure_counter = mpu->clock.meas_old; + mpu->clock.cth_counter = mpu->clock.cth_old; + break; + } + switch (val & 0xc) { /* Playing */ + case 0x4: /* Stop */ + mpu->state.playing = 0; + MPU401_StopClock(mpu); + for (i = 0; i < 16; i++) + MPU401_NotesOff(mpu, i); + mpu->filter.prchg_mask = 0; + break; + case 0x8: /* Start */ + mpu->state.playing = 1; + MPU401_StartClock(mpu); + break; + } + switch (val & 0x30) { /* Recording */ + case 0: /* check if it waited for MIDI RT command */ + if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB)) + break; + mpu->state.rec = M_RECON; + MPU401_StartClock(mpu); + if (mpu->filter.prchg_mask) + send_prchg = 1; + break; + case 0x10: /* Stop */ + mpu->state.rec = M_RECOFF; + MPU401_StopClock(mpu); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, mpu->clock.rec_counter); + MPU401_QueueByte(mpu, MSG_MPU_END); + mpu->filter.prchg_mask = 0; + mpu->clock.rec_counter = 0; + return; + case 0x20: /* Start */ + if (!(mpu->state.rec == M_RECON)) { + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECSTB; + } + if ((mpu->state.last_rtcmd == 0xfa) || (mpu->state.last_rtcmd == 0xfb)) { + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECON; + if (mpu->filter.prchg_mask) + send_prchg = 1; + MPU401_StartClock(mpu); + } + break; + } + } + MPU401_QueueByte(mpu, MSG_MPU_ACK); + /* record counter hack: needed by Prism, but sent only on cmd 0x20/0x26 (or breaks Ballade) */ + uint8_t rec_cnt = mpu->clock.rec_counter; + if (((val == 0x20) || (val == 0x26)) && (mpu->state.rec == M_RECON)) + MPU401_RecQueueBuffer(mpu, &rec_cnt, 1, 0); - /* default: - mpu401_log("MPU-401:Unhandled command %X",val); */ - } + if (send_prchg) { + for (i = 0; i < 16; i++) { + if (mpu->filter.prchg_mask & (1 << i)) { + recmsg[0] = mpu->clock.rec_counter; + recmsg[1] = 0xc0 | i; + recmsg[2] = mpu->filter.prchg_buf[i]; + MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); + mpu->filter.prchg_mask &= ~(1 << i); + } + } + } + } else if ((val >= 0xa0) && (val <= 0xa7)) /* Request play counter */ + MPU401_QueueByte(mpu, mpu->playbuf[val & 7].counter); + else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */ + mpu->state.old_track = mpu->state.track; + mpu->state.track = val & 7; + mpu->state.wsd = 1; + mpu->state.wsm = 0; + mpu->state.wsd_start = 1; + } else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */ + mpu->chanref[(val >> 4) - 4].on = 1; + mpu->chanref[(val >> 4) - 4].chan = val & 0x0f; + mpu->chanref[(val >> 4) - 4].trmask = 0; + for (i = 0; i < 4; i++) + mpu->chanref[(val >> 4) - 4].key[i] = 0; + for (i = 0; i < 16; i++) { + if (mpu->ch_toref[i] == ((val >> 4) - 4)) + mpu->ch_toref[i] = 4; + } + mpu->ch_toref[val & 0x0f] = (val >> 4) - 4; + } else + switch (val) { + case 0x30: /* Configuration 0x30 - 0x39 */ + mpu->filter.allnotesoff_out = 0; + break; + case 0x32: + mpu->filter.rt_out = 0; + break; + case 0x33: + mpu->filter.all_thru = 0; + mpu->filter.commonmsgs_thru = 0; + mpu->filter.midi_thru = 0; + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = 0; + for (j = 0; j < 4; j++) + mpu->inputref[i].key[j] = 0; + } + break; + case 0x34: + mpu->filter.timing_in_stop = 1; + break; + case 0x35: + mpu->filter.modemsgs_in = 1; + break; + case 0x37: + mpu->filter.sysex_thru = 1; + break; + case 0x38: + mpu->filter.commonmsgs_in = 1; + break; + case 0x39: + mpu->filter.rt_in = 1; + break; + case 0x3f: /* UART mode */ + mpu401_log("MPU-401: Set UART mode %X\n", val); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + mpu->mode = M_UART; + return; + case 0x80: /* Internal clock */ + if (mpu->clock.active && mpu->state.sync_in) { + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu->clock.freq_mod = 1.0; + } + mpu->state.sync_in = 0; + break; + case 0x81: /* Sync to tape signal */ + case 0x82: /* Sync to MIDI */ + mpu->clock.ticks_in = 0; + mpu->state.sync_in = 1; + break; + case 0x86: + case 0x87: /* Bender */ + mpu->filter.bender_in = !!(val & 1); + break; + case 0x88: + case 0x89: /* MIDI through */ + mpu->filter.midi_thru = !!(val & 1); + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = mpu->filter.midi_thru; + if (!(val & 1)) { + for (j = 0; j < 4; j++) + mpu->inputref[i].key[j] = 0; + } + } + break; + case 0x8a: + case 0x8b: /* Data in stop */ + mpu->filter.data_in_stop = !!(val & 1); + break; + case 0x8c: + case 0x8d: /* Send measure end */ + mpu->filter.rec_measure_end = !!(val & 1); + break; + case 0x8e: + case 0x8f: /* Conductor */ + mpu->state.cond_set = !!(val & 1); + break; + case 0x90: + case 0x91: /* Realtime affection */ + mpu->filter.rt_affection = !!(val & 1); + break; + case 0x94: /* Clock to host */ + mpu->state.clock_to_host = 0; + MPU401_StopClock(mpu); + break; + case 0x95: + mpu->state.clock_to_host = 1; + MPU401_StartClock(mpu); + break; + case 0x96: + case 0x97: /* Sysex input allow */ + mpu->filter.sysex_in = !!(val & 1); + if (val & 1) + mpu->filter.sysex_thru = 0; + break; + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: /* Reference tables on/off */ + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + mpu->chanref[(val - 0x98) / 2].on = !!(val & 1); + break; + /* Commands 0xa# returning data */ + case 0xab: /* Request and clear recording counter */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, 0); + return; + case 0xac: /* Request version */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_VERSION); + return; + case 0xad: /* Request revision */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_REVISION); + return; + case 0xaf: /* Request tempo */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, mpu->clock.tempo); + return; + case 0xb1: /* Reset relative tempo */ + mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; + mpu->clock.tempo_rel = 0x40; + break; + case 0xb8: /* Clear play counters */ + mpu->state.last_rtcmd = 0; + for (i = 0; i < 8; i++) { + mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + } + mpu->condbuf.counter = 0; + mpu->condbuf.type = T_OVERFLOW; + mpu->state.amask = mpu->state.tmask; + mpu->state.conductor = mpu->state.cond_set; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + break; + case 0xb9: /* Clear play map */ + for (i = 0; i < 16; i++) + MPU401_NotesOff(mpu, i); + for (i = 0; i < 8; i++) { + mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + } + mpu->state.last_rtcmd = 0; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + break; + case 0xba: /* Clear record counter */ + mpu->clock.rec_counter = 0; + break; + case 0xc2: + case 0xc3: + case 0xc4: /* Internal timebase */ + case 0xc5: + case 0xc6: + case 0xc7: + case 0xc8: + mpu->clock.timebase = MPUClockBase[val - 0xc2]; + MPU401_ReCalcClock(mpu); + break; + case 0xdf: /* Send system message */ + mpu->state.wsd = 0; + mpu->state.wsm = 1; + mpu->state.wsd_start = 1; + break; + /* Commands with data byte */ + case 0xe0: + case 0xe1: + case 0xe2: + case 0xe4: + case 0xe6: + case 0xe7: + case 0xec: + case 0xed: + case 0xee: + case 0xef: + mpu->state.command_byte = val; + break; + case 0xff: /* Reset MPU-401 */ + mpu401_log("MPU-401: Reset %X\n", val); + timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC); + mpu->state.reset = 1; + was_uart = (mpu->mode == M_UART); + MPU401_Reset(mpu); + if (was_uart) + return; + break; + + /* default: + mpu401_log("MPU-401:Unhandled command %X",val); */ + } MPU401_QueueByte(mpu, MSG_MPU_ACK); } - static void -MPU401_WriteData(mpu_t *mpu, uint8_t val) +MPU401_WriteData(mpu_t *mpu, uint8_t val) { static int length, cnt; - uint8_t i; + uint8_t i; #ifdef DOSBOX_CODE if (mpu->mode == M_UART) { - midi_raw_out_byte(val); - return; + midi_raw_out_byte(val); + return; } if (!mpu->intelligent) { - mpu->state.command_byte = 0; - return; + mpu->state.command_byte = 0; + return; } #else if (!mpu->intelligent || (mpu->mode == M_UART)) { - midi_raw_out_byte(val); - return; + midi_raw_out_byte(val); + return; } #endif - - switch (mpu->state.command_byte) { /* 0xe# command data */ - case 0x00: - break; - case 0xe0: /* Set tempo */ - mpu->state.command_byte = 0; - if (mpu->clock.tempo < 8) - mpu->clock.tempo = 8; - else if (mpu->clock.tempo > 250) - mpu->clock.tempo = 250; - else - mpu->clock.tempo = val; - MPU401_ReCalcClock(mpu); - return; - case 0xe1: /* Set relative tempo */ - mpu->state.command_byte = 0; - mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; - mpu->clock.tempo_rel = val; - MPU401_ReCalcClock(mpu); - return; - case 0xe2: /* Set gradation for relative tempo */ - mpu->clock.tempo_grad = val; - MPU401_ReCalcClock(mpu); - return; - case 0xe4: /* Set MIDI clocks for metronome ticks */ - mpu->state.command_byte = 0; - mpu->clock.midimetro = val; - return; - case 0xe6: /* Set metronome ticks per measure */ - mpu->state.command_byte = 0; - mpu->clock.metromeas = val; - return; - case 0xe7: /* Set internal clock to host interval */ - mpu->state.command_byte = 0; - if (!val) - val = 64; - for (i = 0; i < 4; i++) - mpu->clock.cth_rate[i] = (val >> 2) + cth_data[(val & 3) * 4 + i]; - mpu->clock.cth_mode = 0; - return; - case 0xec: /* Set active track mask */ - mpu->state.command_byte = 0; - mpu->state.tmask = val; - return; - case 0xed: /* Set play counter mask */ - mpu->state.command_byte = 0; - mpu->state.cmask = val; - return; - case 0xee: /* Set 1-8 MIDI channel mask */ - mpu->state.command_byte = 0; - mpu->state.midi_mask &= 0xff00; - mpu->state.midi_mask |= val; - return; - case 0xef: /* Set 9-16 MIDI channel mask */ - mpu->state.command_byte = 0; - mpu->state.midi_mask &= 0x00ff; - mpu->state.midi_mask |= ((uint16_t) val) << 8; - return; - default: - mpu->state.command_byte = 0; - return; + switch (mpu->state.command_byte) { /* 0xe# command data */ + case 0x00: + break; + case 0xe0: /* Set tempo */ + mpu->state.command_byte = 0; + if (mpu->clock.tempo < 8) + mpu->clock.tempo = 8; + else if (mpu->clock.tempo > 250) + mpu->clock.tempo = 250; + else + mpu->clock.tempo = val; + MPU401_ReCalcClock(mpu); + return; + case 0xe1: /* Set relative tempo */ + mpu->state.command_byte = 0; + mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; + mpu->clock.tempo_rel = val; + MPU401_ReCalcClock(mpu); + return; + case 0xe2: /* Set gradation for relative tempo */ + mpu->clock.tempo_grad = val; + MPU401_ReCalcClock(mpu); + return; + case 0xe4: /* Set MIDI clocks for metronome ticks */ + mpu->state.command_byte = 0; + mpu->clock.midimetro = val; + return; + case 0xe6: /* Set metronome ticks per measure */ + mpu->state.command_byte = 0; + mpu->clock.metromeas = val; + return; + case 0xe7: /* Set internal clock to host interval */ + mpu->state.command_byte = 0; + if (!val) + val = 64; + for (i = 0; i < 4; i++) + mpu->clock.cth_rate[i] = (val >> 2) + cth_data[(val & 3) * 4 + i]; + mpu->clock.cth_mode = 0; + return; + case 0xec: /* Set active track mask */ + mpu->state.command_byte = 0; + mpu->state.tmask = val; + return; + case 0xed: /* Set play counter mask */ + mpu->state.command_byte = 0; + mpu->state.cmask = val; + return; + case 0xee: /* Set 1-8 MIDI channel mask */ + mpu->state.command_byte = 0; + mpu->state.midi_mask &= 0xff00; + mpu->state.midi_mask |= val; + return; + case 0xef: /* Set 9-16 MIDI channel mask */ + mpu->state.command_byte = 0; + mpu->state.midi_mask &= 0x00ff; + mpu->state.midi_mask |= ((uint16_t) val) << 8; + return; + + default: + mpu->state.command_byte = 0; + return; } if (mpu->state.wsd && !mpu->state.track_req && !mpu->state.cond_req) { - /* Directly send MIDI message */ - if (mpu->state.wsd_start) { - mpu->state.wsd_start = 0; - cnt = 0; - switch (val & 0xf0) { - case 0xc0: case 0xd0: - length = mpu->playbuf[mpu->state.track].length = 2; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - case 0x80: case 0x90: case 0xa0: case 0xb0:case 0xe0: - length = mpu->playbuf[mpu->state.track].length = 3; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; + /* Directly send MIDI message */ + if (mpu->state.wsd_start) { + mpu->state.wsd_start = 0; + cnt = 0; + switch (val & 0xf0) { + case 0xc0: + case 0xd0: + length = mpu->playbuf[mpu->state.track].length = 2; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + length = mpu->playbuf[mpu->state.track].length = 3; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; - case 0xf0: - /* mpu401_log("MPU-401:Illegal WSD byte\n"); */ - mpu->state.wsd = 0; - mpu->state.track = mpu->state.old_track; - return; + case 0xf0: + /* mpu401_log("MPU-401:Illegal WSD byte\n"); */ + mpu->state.wsd = 0; + mpu->state.track = mpu->state.old_track; + return; - default: /* MIDI with running status */ - cnt++; - length = mpu->playbuf[mpu->state.track].length; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - } - } + default: /* MIDI with running status */ + cnt++; + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + } + } - if (cnt < length) { - mpu->playbuf[mpu->state.track].value[cnt] = val; - cnt++; - } + if (cnt < length) { + mpu->playbuf[mpu->state.track].value[cnt] = val; + cnt++; + } - if (cnt == length) { - MPU401_IntelligentOut(mpu, mpu->state.track); - mpu->state.wsd = 0; - mpu->state.track = mpu->state.old_track; - } + if (cnt == length) { + MPU401_IntelligentOut(mpu, mpu->state.track); + mpu->state.wsd = 0; + mpu->state.track = mpu->state.old_track; + } - return; + return; } - if (mpu->state.wsm && !mpu->state.track_req && !mpu->state.cond_req) { /* Send system message */ - if (mpu->state.wsd_start) { - mpu->state.wsd_start = 0; - cnt = 0; - switch (val) { - case 0xf2: - length = 3; - break; + if (mpu->state.wsm && !mpu->state.track_req && !mpu->state.cond_req) { /* Send system message */ + if (mpu->state.wsd_start) { + mpu->state.wsd_start = 0; + cnt = 0; + switch (val) { + case 0xf2: + length = 3; + break; - case 0xf3: - length = 2; - break; + case 0xf3: + length = 2; + break; - case 0xf6: - length = 1; - break; + case 0xf6: + length = 1; + break; - case 0xf0: - length = 0; - break; + case 0xf0: + length = 0; + break; - default: - mpu->state.wsm = 0; - return; - } - } else if (val & 0x80) { - midi_raw_out_byte(MSG_EOX); - mpu->state.wsm = 0; - return; - } + default: + mpu->state.wsm = 0; + return; + } + } else if (val & 0x80) { + midi_raw_out_byte(MSG_EOX); + mpu->state.wsm = 0; + return; + } - if (!length || (cnt < length)) { - midi_raw_out_byte(val); - cnt++; - } + if (!length || (cnt < length)) { + midi_raw_out_byte(val); + cnt++; + } - if (cnt == length) - mpu->state.wsm = 0; + if (cnt == length) + mpu->state.wsm = 0; - return; + return; } if (mpu->state.cond_req) { - /* Command */ - switch (mpu->state.data_onoff) { - case -1: - return; - case 0: /* Timing byte */ - mpu->condbuf.length = 0; - if (val < 0xf0) - mpu->state.data_onoff++; - else { - mpu->state.cond_req = 0; - mpu->state.data_onoff = -1; - MPU401_EOIHandlerDispatch(mpu); - break; - } - mpu->state.send_now = !val ? 1 : 0; - mpu->condbuf.counter = val; - break; - case 1: /* Command byte #1 */ - mpu->condbuf.type = T_COMMAND; - if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc)) - mpu->condbuf.type = T_OVERFLOW; - mpu->condbuf.value[mpu->condbuf.length] = val; - mpu->condbuf.length++; - if ((val & 0xf0) != 0xe0) { /*no cmd data byte*/ - MPU401_EOIHandler(mpu); - mpu->state.data_onoff = -1; - mpu->state.cond_req = 0; - } else - mpu->state.data_onoff++; - break; + /* Command */ + switch (mpu->state.data_onoff) { + case -1: + return; + case 0: /* Timing byte */ + mpu->condbuf.length = 0; + if (val < 0xf0) + mpu->state.data_onoff++; + else { + mpu->state.cond_req = 0; + mpu->state.data_onoff = -1; + MPU401_EOIHandlerDispatch(mpu); + break; + } + mpu->state.send_now = !val ? 1 : 0; + mpu->condbuf.counter = val; + break; + case 1: /* Command byte #1 */ + mpu->condbuf.type = T_COMMAND; + if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc)) + mpu->condbuf.type = T_OVERFLOW; + mpu->condbuf.value[mpu->condbuf.length] = val; + mpu->condbuf.length++; + if ((val & 0xf0) != 0xe0) { /*no cmd data byte*/ + MPU401_EOIHandler(mpu); + mpu->state.data_onoff = -1; + mpu->state.cond_req = 0; + } else + mpu->state.data_onoff++; + break; - case 2:/* Command byte #2 */ - mpu->condbuf.value[mpu->condbuf.length]=val; - mpu->condbuf.length++; - MPU401_EOIHandler(mpu); - mpu->state.data_onoff = -1; - mpu->state.cond_req = 0; - break; - } - return; + case 2: /* Command byte #2 */ + mpu->condbuf.value[mpu->condbuf.length] = val; + mpu->condbuf.length++; + MPU401_EOIHandler(mpu); + mpu->state.data_onoff = -1; + mpu->state.cond_req = 0; + break; + } + return; } switch (mpu->state.data_onoff) { - /* Data */ - case -1: - break; - case 0: /* Timing byte */ - if (val < 0xf0) - mpu->state.data_onoff++; - else { - mpu->state.data_onoff = -1; - MPU401_EOIHandlerDispatch(mpu); - mpu->state.track_req = 0; - return; - } - mpu->state.send_now = !val ? 1 : 0; - mpu->playbuf[mpu->state.track].counter = val; - break; - case 1: /* MIDI */ - cnt = 0; - mpu->state.data_onoff++; - switch (val & 0xf0) { - case 0xc0: case 0xd0: /* MIDI Message */ - length = mpu->playbuf[mpu->state.track].length = 2; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: - length = mpu->playbuf[mpu->state.track].length = 3; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - case 0xf0: /* System message or mark */ - mpu->playbuf[mpu->state.track].sys_val = val; - if (val > 0xf7) { - mpu->playbuf[mpu->state.track].type = T_MARK; - if (val == 0xf9) - mpu->clock.measure_counter = 0; - } else { - /* mpu401_log("MPU-401:Illegal message"); */ - mpu->playbuf[mpu->state.track].type = T_OVERFLOW; - } - mpu->state.data_onoff = -1; - MPU401_EOIHandler(mpu); - mpu->state.track_req = 0; - return; - default: /* MIDI with running status */ - cnt++; - length = mpu->playbuf[mpu->state.track].length; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - } - break; - case 2: - if (cnt < length) { - mpu->playbuf[mpu->state.track].value[cnt] = val; - cnt++; - } - if (cnt == length) { - mpu->state.data_onoff = -1; - mpu->state.track_req = 0; - MPU401_EOIHandler(mpu); - } - break; + /* Data */ + case -1: + break; + case 0: /* Timing byte */ + if (val < 0xf0) + mpu->state.data_onoff++; + else { + mpu->state.data_onoff = -1; + MPU401_EOIHandlerDispatch(mpu); + mpu->state.track_req = 0; + return; + } + mpu->state.send_now = !val ? 1 : 0; + mpu->playbuf[mpu->state.track].counter = val; + break; + case 1: /* MIDI */ + cnt = 0; + mpu->state.data_onoff++; + switch (val & 0xf0) { + case 0xc0: + case 0xd0: /* MIDI Message */ + length = mpu->playbuf[mpu->state.track].length = 2; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + length = mpu->playbuf[mpu->state.track].length = 3; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; + case 0xf0: /* System message or mark */ + mpu->playbuf[mpu->state.track].sys_val = val; + if (val > 0xf7) { + mpu->playbuf[mpu->state.track].type = T_MARK; + if (val == 0xf9) + mpu->clock.measure_counter = 0; + } else { + /* mpu401_log("MPU-401:Illegal message"); */ + mpu->playbuf[mpu->state.track].type = T_OVERFLOW; + } + mpu->state.data_onoff = -1; + MPU401_EOIHandler(mpu); + mpu->state.track_req = 0; + return; + default: /* MIDI with running status */ + cnt++; + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; + } + break; + case 2: + if (cnt < length) { + mpu->playbuf[mpu->state.track].value[cnt] = val; + cnt++; + } + if (cnt == length) { + mpu->state.data_onoff = -1; + mpu->state.track_req = 0; + MPU401_EOIHandler(mpu); + } + break; } - - return; + + return; } - static void -MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) +MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) { uint8_t chan, chrefnum, key, msg; - int send, retrigger; + int send, retrigger; uint8_t i; switch (mpu->playbuf[track].type) { - case T_OVERFLOW: - break; + case T_OVERFLOW: + break; - case T_MARK: - if (mpu->playbuf[track].sys_val == 0xfc) { - midi_raw_out_rt_byte(mpu->playbuf[track].sys_val); - mpu->state.amask&=~(1<playbuf[track].sys_val == 0xfc) { + midi_raw_out_rt_byte(mpu->playbuf[track].sys_val); + mpu->state.amask &= ~(1 << track); + } + break; - case T_MIDI_NORM: - chan = mpu->playbuf[track].value[0] & 0xf; - key = mpu->playbuf[track].value[1] & 0x7f; - chrefnum = mpu->ch_toref[chan]; - send = 1; - retrigger = 0; - switch (msg = mpu->playbuf[track].value[0] & 0xf0) { - case 0x80: /* note off */ - if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) - send = 0; - if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) - send = 0; - mpu->chanref[chrefnum].M_DELKEY; - break; - case 0x90: /* note on */ - if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) - retrigger = 1; - if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) - retrigger = 1; - mpu->chanref[chrefnum].M_SETKEY; - break; - case 0xb0: - if (mpu->playbuf[track].value[1] == 123) { /* All notes off */ - MPU401_NotesOff(mpu, mpu->playbuf[track].value[0] & 0xf); - return; - } - break; - } - if (retrigger) { - midi_raw_out_byte(0x80 | chan); - midi_raw_out_byte(key); - midi_raw_out_byte(0); - } - if (send) { - for (i = 0; i < mpu->playbuf[track].length; i++) - midi_raw_out_byte(mpu->playbuf[track].value[i]); - } - break; - - default: - break; + case T_MIDI_NORM: + chan = mpu->playbuf[track].value[0] & 0xf; + key = mpu->playbuf[track].value[1] & 0x7f; + chrefnum = mpu->ch_toref[chan]; + send = 1; + retrigger = 0; + switch (msg = mpu->playbuf[track].value[0] & 0xf0) { + case 0x80: /* note off */ + if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) + send = 0; + if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) + send = 0; + mpu->chanref[chrefnum].M_DELKEY; + break; + case 0x90: /* note on */ + if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) + retrigger = 1; + if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) + retrigger = 1; + mpu->chanref[chrefnum].M_SETKEY; + break; + case 0xb0: + if (mpu->playbuf[track].value[1] == 123) { /* All notes off */ + MPU401_NotesOff(mpu, mpu->playbuf[track].value[0] & 0xf); + return; + } + break; + } + if (retrigger) { + midi_raw_out_byte(0x80 | chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + if (send) { + for (i = 0; i < mpu->playbuf[track].length; i++) + midi_raw_out_byte(mpu->playbuf[track].value[i]); + } + break; + + default: + break; } } - static void -UpdateTrack(mpu_t *mpu, uint8_t track) +UpdateTrack(mpu_t *mpu, uint8_t track) { MPU401_IntelligentOut(mpu, track); - if (mpu->state.amask&(1<playbuf[track].type = T_OVERFLOW; - mpu->playbuf[track].counter = 0xf0; - mpu->state.req_mask |= (1 << track); + if (mpu->state.amask & (1 << track)) { + mpu->playbuf[track].type = T_OVERFLOW; + mpu->playbuf[track].counter = 0xf0; + mpu->state.req_mask |= (1 << track); } else { - if ((mpu->state.amask == 0) && !mpu->state.conductor) - mpu->state.req_mask |= (1 << 12); + if ((mpu->state.amask == 0) && !mpu->state.conductor) + mpu->state.req_mask |= (1 << 12); } } - #if 0 static void -UpdateConductor(mpu_t *mpu) +UpdateConductor(mpu_t *mpu) { if (mpu->condbuf.value[0] == 0xfc) { - mpu->condbuf.value[0] = 0; - mpu->state.conductor = 0; - mpu->state.req_mask &= ~(1 << 9); - if (mpu->state.amask == 0) - mpu->state.req_mask |= (1 << 12); - return; + mpu->condbuf.value[0] = 0; + mpu->state.conductor = 0; + mpu->state.req_mask &= ~(1 << 9); + if (mpu->state.amask == 0) + mpu->state.req_mask |= (1 << 12); + return; } mpu->condbuf.vlength = 0; @@ -1052,390 +1066,388 @@ UpdateConductor(mpu_t *mpu) } #endif - /* Updates counters and requests new data on "End of Input" */ static void MPU401_EOIHandler(void *priv) { - mpu_t *mpu = (mpu_t *)priv; + mpu_t *mpu = (mpu_t *) priv; uint8_t i; mpu401_log("MPU-401 end of input callback\n"); - + timer_disable(&mpu->mpu401_eoi_callback); mpu->state.eoi_scheduled = 0; if (mpu->state.send_now) { - mpu->state.send_now = 0; - if (mpu->state.cond_req) { - mpu->condbuf.counter = 0xf0; - mpu->state.req_mask |= (1 << 9); - } else UpdateTrack(mpu, mpu->state.track); + mpu->state.send_now = 0; + if (mpu->state.cond_req) { + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } else + UpdateTrack(mpu, mpu->state.track); } - if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) - return; + if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) + return; if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); + mpu->ext_irq_update(mpu->priv, 0); else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); } if (!(mpu->state.req_mask && mpu->clock.active)) - return; + return; i = 0; do { - if (mpu->state.req_mask & (1 << i)) { - MPU401_QueueByte(mpu, 0xf0 + i); - mpu->state.req_mask &= ~(1 << i); - break; - } + if (mpu->state.req_mask & (1 << i)) { + MPU401_QueueByte(mpu, 0xf0 + i); + mpu->state.req_mask &= ~(1 << i); + break; + } } while ((i++) < 16); } - static void -MPU401_EOIHandlerDispatch(void *priv) +MPU401_EOIHandlerDispatch(void *priv) { - mpu_t *mpu = (mpu_t *)priv; + mpu_t *mpu = (mpu_t *) priv; mpu401_log("EOI handler dispatch\n"); if (mpu->state.send_now) { - mpu->state.eoi_scheduled = 1; - timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ - } else if (!mpu->state.eoi_scheduled) - MPU401_EOIHandler(mpu); + mpu->state.eoi_scheduled = 1; + timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ + } else if (!mpu->state.eoi_scheduled) + MPU401_EOIHandler(mpu); } - static void imf_write(uint16_t addr, uint8_t val, void *priv) { mpu401_log("IMF:Wr %4X,%X\n", addr, val); } - void MPU401_ReadRaiseIRQ(mpu_t *mpu) { /* Clear IRQ. */ if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); + mpu->ext_irq_update(mpu->priv, 0); else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); } if (mpu->queue_used) { - /* Bytes remaining in queue, raise IRQ again. */ - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 1); - else { - mpu->state.irq_pending = 1; - picint(1 << mpu->irq); - } + /* Bytes remaining in queue, raise IRQ again. */ + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 1); + else { + mpu->state.irq_pending = 1; + picint(1 << mpu->irq); + } } } - uint8_t MPU401_ReadData(mpu_t *mpu) { uint8_t ret; - + ret = MSG_MPU_ACK; if (mpu->queue_used) { - if (mpu->queue_pos >= MPU401_QUEUE) - mpu->queue_pos -= MPU401_QUEUE; - ret = mpu->queue[mpu->queue_pos]; - mpu->queue_pos++; - mpu->queue_used--; + if (mpu->queue_pos >= MPU401_QUEUE) + mpu->queue_pos -= MPU401_QUEUE; + ret = mpu->queue[mpu->queue_pos]; + mpu->queue_pos++; + mpu->queue_used--; } /* Shouldn't this check mpu->mode? */ #ifdef DOSBOX_CODE if (mpu->mode == M_UART) { - MPU401_ReadRaiseIRQ(mpu); - return ret; + MPU401_ReadRaiseIRQ(mpu); + return ret; } #else if (!mpu->intelligent || (mpu->mode == M_UART)) { - MPU401_ReadRaiseIRQ(mpu); - return ret; + MPU401_ReadRaiseIRQ(mpu); + return ret; } #endif if (mpu->state.rec_copy && !mpu->rec_queue_used) { - mpu->state.rec_copy = 0; - MPU401_EOIHandler(mpu); - return ret; + mpu->state.rec_copy = 0; + MPU401_EOIHandler(mpu); + return ret; } /* Copy from recording buffer. */ if (!mpu->queue_used && mpu->rec_queue_used) { - mpu->state.rec_copy = 1; - if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) - mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; - MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); - mpu->rec_queue_pos++; - mpu->rec_queue_used--; + mpu->state.rec_copy = 1; + if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) + mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; + MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); + mpu->rec_queue_pos++; + mpu->rec_queue_used--; } MPU401_ReadRaiseIRQ(mpu); if ((ret >= 0xf0) && (ret <= 0xf7)) { - /* MIDI data request */ - mpu->state.track = ret & 7; - mpu->state.data_onoff = 0; - mpu->state.cond_req = 0; - mpu->state.track_req = 1; + /* MIDI data request */ + mpu->state.track = ret & 7; + mpu->state.data_onoff = 0; + mpu->state.cond_req = 0; + mpu->state.track_req = 1; } if (ret == MSG_MPU_COMMAND_REQ) { - mpu->state.data_onoff = 0; - mpu->state.cond_req = 1; - if (mpu->condbuf.type != T_OVERFLOW) { - mpu->state.block_ack = 1; - MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); - if (mpu->state.command_byte) - MPU401_WriteData(mpu, mpu->condbuf.value[1]); - mpu->condbuf.type = T_OVERFLOW; - } + mpu->state.data_onoff = 0; + mpu->state.cond_req = 1; + if (mpu->condbuf.type != T_OVERFLOW) { + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); + if (mpu->state.command_byte) + MPU401_WriteData(mpu, mpu->condbuf.value[1]); + mpu->condbuf.type = T_OVERFLOW; + } } if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW)) - MPU401_EOIHandlerDispatch(mpu); + MPU401_EOIHandlerDispatch(mpu); return ret; } - -static void +void mpu401_write(uint16_t addr, uint8_t val, void *priv) { - mpu_t *mpu = (mpu_t *)priv; - + mpu_t *mpu = (mpu_t *) priv; + /* mpu401_log("MPU401 Write Port %04X, val %x\n", addr, val); */ switch (addr & 1) { - case 0: /*Data*/ - MPU401_WriteData(mpu, val); - mpu401_log("Write Data (0x330) %X\n", val); - break; + case 0: /*Data*/ + MPU401_WriteData(mpu, val); + mpu401_log("Write Data (0x330) %X\n", val); + break; - case 1: /*Command*/ - MPU401_WriteCommand(mpu, val); - mpu401_log("Write Command (0x331) %x\n", val); - break; + case 1: /*Command*/ + MPU401_WriteCommand(mpu, val); + mpu401_log("Write Command (0x331) %x\n", val); + break; } } - -static uint8_t +uint8_t mpu401_read(uint16_t addr, void *priv) { - mpu_t *mpu = (mpu_t *)priv; + mpu_t *mpu = (mpu_t *) priv; uint8_t ret = 0; - switch (addr & 1) { - case 0: /* Read Data */ - ret = MPU401_ReadData(mpu); - mpu401_log("Read Data (0x330) %X\n", ret); - break; + switch (addr & 1) { + case 0: /* Read Data */ + ret = MPU401_ReadData(mpu); + mpu401_log("Read Data (0x330) %X\n", ret); + break; - case 1: /* Read Status */ - if (mpu->state.cmd_pending) - ret = STATUS_OUTPUT_NOT_READY; - if (!mpu->queue_used) - ret = STATUS_INPUT_NOT_READY; - ret |= 0x3f; + case 1: /* Read Status */ + if (mpu->state.cmd_pending) + ret = STATUS_OUTPUT_NOT_READY; + if (!mpu->queue_used) + ret = STATUS_INPUT_NOT_READY; + ret |= 0x3f; - mpu401_log("Read Status (0x331) %x\n", ret); - break; + mpu401_log("Read Status (0x331) %x\n", ret); + break; } /* mpu401_log("MPU401 Read Port %04X, ret %x\n", addr, ret); */ - return(ret); + return (ret); } - static void -MPU401_Event(void *priv) +MPU401_Event(void *priv) { - mpu_t *mpu = (mpu_t *)priv; + mpu_t *mpu = (mpu_t *) priv; uint8_t i; - int max_meascnt; + int max_meascnt; mpu401_log("MPU-401 event callback\n"); #ifdef DOSBOX_CODE if (mpu->mode == M_UART) { - timer_disable(&mpu->mpu401_event_callback); - return; + timer_disable(&mpu->mpu401_event_callback); + return; } #else if (!mpu->intelligent || (mpu->mode == M_UART)) { - timer_disable(&mpu->mpu401_event_callback); - return; + timer_disable(&mpu->mpu401_event_callback); + return; } #endif if (MPU401_IRQPending(mpu)) - goto next_event; + goto next_event; if (mpu->state.playing) { - for (i = 0; i < 8; i++) { - /* Decrease counters. */ - if (mpu->state.amask & (1 << i)) { - mpu->playbuf[i].counter--; - if (mpu->playbuf[i].counter <= 0) - UpdateTrack(mpu, i); - } - } + for (i = 0; i < 8; i++) { + /* Decrease counters. */ + if (mpu->state.amask & (1 << i)) { + mpu->playbuf[i].counter--; + if (mpu->playbuf[i].counter <= 0) + UpdateTrack(mpu, i); + } + } - if (mpu->state.conductor) { - mpu->condbuf.counter--; - if (mpu->condbuf.counter <= 0) { - mpu->condbuf.counter = 0xf0; - mpu->state.req_mask |= (1 << 9); - } - } + if (mpu->state.conductor) { + mpu->condbuf.counter--; + if (mpu->condbuf.counter <= 0) { + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } + } } if (mpu->state.clock_to_host) { - mpu->clock.cth_counter++; - if (mpu->clock.cth_counter >= mpu->clock.cth_rate[mpu->clock.cth_mode]) { - mpu->clock.cth_counter = 0; - mpu->clock.cth_mode++; - mpu->clock.cth_mode %= 4; - mpu->state.req_mask |= (1 << 13); - } + mpu->clock.cth_counter++; + if (mpu->clock.cth_counter >= mpu->clock.cth_rate[mpu->clock.cth_mode]) { + mpu->clock.cth_counter = 0; + mpu->clock.cth_mode++; + mpu->clock.cth_mode %= 4; + mpu->state.req_mask |= (1 << 13); + } } if (mpu->state.rec == M_RECON) { - /* Recording. */ - mpu->clock.rec_counter++; - if (mpu->clock.rec_counter>=240) { - mpu->clock.rec_counter=0; - mpu->state.req_mask|=(1<<8); - } + /* Recording. */ + mpu->clock.rec_counter++; + if (mpu->clock.rec_counter >= 240) { + mpu->clock.rec_counter = 0; + mpu->state.req_mask |= (1 << 8); + } } if (mpu->state.playing || (mpu->state.rec == M_RECON)) { - max_meascnt = (mpu->clock.timebase * mpu->clock.midimetro * mpu->clock.metromeas) / 24; - if (max_meascnt != 0) { - /* Measure end. */ - if (++mpu->clock.measure_counter >= max_meascnt) { - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(0xf8); - mpu->clock.measure_counter = 0; - if (mpu->filter.rec_measure_end && (mpu->state.rec == M_RECON)) - mpu->state.req_mask |= (1 << 12); - } - } + max_meascnt = (mpu->clock.timebase * mpu->clock.midimetro * mpu->clock.metromeas) / 24; + if (max_meascnt != 0) { + /* Measure end. */ + if (++mpu->clock.measure_counter >= max_meascnt) { + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xf8); + mpu->clock.measure_counter = 0; + if (mpu->filter.rec_measure_end && (mpu->state.rec == M_RECON)) + mpu->state.req_mask |= (1 << 12); + } + } } if (MPU401_IRQPending(mpu) && mpu->state.req_mask) - MPU401_EOIHandler(mpu); + MPU401_EOIHandler(mpu); next_event: MPU401_RunClock(mpu); if (mpu->state.sync_in) - mpu->clock.ticks_in++; + mpu->clock.ticks_in++; } - -static void -MPU401_NotesOff(mpu_t *mpu, int i) +static void +MPU401_NotesOff(mpu_t *mpu, int i) { - int j; + int j; uint8_t key; - if (mpu->filter.allnotesoff_out && !(mpu->inputref[i].on && - (mpu->inputref[i].key[0] | mpu->inputref[i].key[1] | - mpu->inputref[i].key[2] | mpu->inputref[i].key[3]))) { - for (j=0;j<4;j++) - mpu->chanref[mpu->ch_toref[i]].key[j]=0; - midi_raw_out_byte(0xb0 | i); - midi_raw_out_byte(123); - midi_raw_out_byte(0); + if (mpu->filter.allnotesoff_out && !(mpu->inputref[i].on && (mpu->inputref[i].key[0] | mpu->inputref[i].key[1] | mpu->inputref[i].key[2] | mpu->inputref[i].key[3]))) { + for (j = 0; j < 4; j++) + mpu->chanref[mpu->ch_toref[i]].key[j] = 0; + midi_raw_out_byte(0xb0 | i); + midi_raw_out_byte(123); + midi_raw_out_byte(0); } else if (mpu->chanref[mpu->ch_toref[i]].on) { - for (key = 0; key < 128; key++) { - if ((mpu->chanref[mpu->ch_toref[i]].M_GETKEY) && - !(mpu->inputref[i].on && (mpu->inputref[i].M_GETKEY))) { - midi_raw_out_byte(0x80|i); - midi_raw_out_byte(key); - midi_raw_out_byte(0); - } - mpu->chanref[mpu->ch_toref[i]].M_DELKEY; - } + for (key = 0; key < 128; key++) { + if ((mpu->chanref[mpu->ch_toref[i]].M_GETKEY) && !(mpu->inputref[i].on && (mpu->inputref[i].M_GETKEY))) { + midi_raw_out_byte(0x80 | i); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + mpu->chanref[mpu->ch_toref[i]].M_DELKEY; + } } } - /*Input handler for SysEx */ int MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort) { - mpu_t *mpu = (mpu_t *)p; - int i; + mpu_t *mpu = (mpu_t *) p; + int i; uint8_t val_ff = 0xff; mpu401_log("MPU401 Input Sysex\n"); - if (mpu->filter.sysex_in) { - if (abort) { - mpu->state.sysex_in_finished=1; - mpu->rec_queue_used=0;/*reset also the input queue*/ - return 0; - } - if (mpu->state.sysex_in_finished) { - if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) - return len; - MPU401_RecQueueBuffer(mpu, &val_ff, 1, 1); - mpu->state.sysex_in_finished=0; - mpu->clock.rec_counter=0; - } - if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) - return len; - int available = MPU401_INPUT_QUEUE - mpu->rec_queue_used; +#ifdef DOSBOX_CODE + if (mpu->mode == M_UART) { +#else + if (!mpu->intelligent || mpu->mode == M_UART) { +#endif + /* UART mode input. */ + for (i = 0; i < len; i++) + MPU401_QueueByte(mpu, buffer[i]); + return 0; + } - if (available >= len) { - MPU401_RecQueueBuffer(mpu, buffer, len, 1); - return 0; - } else { - MPU401_RecQueueBuffer(mpu,buffer, available, 1); - if (mpu->state.sysex_in_finished) - return 0; - return (len - available); - } + if (mpu->filter.sysex_in) { + if (abort) { + mpu->state.sysex_in_finished = 1; + mpu->rec_queue_used = 0; /*reset also the input queue*/ + return 0; + } + if (mpu->state.sysex_in_finished) { + if (mpu->rec_queue_used >= MPU401_INPUT_QUEUE) + return len; + MPU401_RecQueueBuffer(mpu, &val_ff, 1, 1); + mpu->state.sysex_in_finished = 0; + mpu->clock.rec_counter = 0; + } + if (mpu->rec_queue_used >= MPU401_INPUT_QUEUE) + return len; + int available = MPU401_INPUT_QUEUE - mpu->rec_queue_used; + + if (available >= len) { + MPU401_RecQueueBuffer(mpu, buffer, len, 1); + return 0; + } else { + MPU401_RecQueueBuffer(mpu, buffer, available, 1); + if (mpu->state.sysex_in_finished) + return 0; + return (len - available); + } } else if (mpu->filter.sysex_thru && mpu->midi_thru) { - midi_raw_out_byte(0xf0); - for (i = 0; i < len; i++) - midi_raw_out_byte(*(buffer+i)); + midi_raw_out_byte(0xf0); + for (i = 0; i < len; i++) + midi_raw_out_byte(*(buffer + i)); } return 0; } - /*Input handler for MIDI*/ void -MPU401_InputMsg(void *p, uint8_t *msg) +MPU401_InputMsg(void *p, uint8_t *msg, uint32_t len) { - mpu_t *mpu = (mpu_t *)p; - int i, tick; + mpu_t *mpu = (mpu_t *) p; + int i, tick; static uint8_t old_msg = 0; - uint8_t len = msg[3], key; - uint8_t recdata[2], recmsg[4]; - int send = 1, send_thru = 0; - int retrigger_thru = 0, chan, chrefnum; + uint8_t key; + uint8_t recdata[2], recmsg[4]; + int send = 1, send_thru = 0; + int retrigger_thru = 0, chan, chrefnum; /* Abort if sysex transfer is in progress. */ if (!mpu->state.sysex_in_finished) { - mpu401_log("SYSEX in progress\n"); - return; + mpu401_log("SYSEX in progress\n"); + return; } mpu401_log("MPU401 Input Msg\n"); @@ -1445,202 +1457,202 @@ MPU401_InputMsg(void *p, uint8_t *msg) #else if (mpu->intelligent && (mpu->mode == M_INTELLIGENT)) { #endif - if (msg[0] < 0x80) { - /* Expand running status */ - msg[2] = msg[1]; - msg[1] = msg[0]; - msg[0] = old_msg; - } - old_msg = msg[0]; - chan = msg[0] & 0xf; - chrefnum = mpu->ch_toref[chan]; - key = msg[1] & 0x7f; - if (msg[0] < 0xf0) { - /* If non-system msg. */ - if (!(mpu->state.midi_mask & (1 << chan)) && mpu->filter.all_thru) - send_thru = 1; - else if (mpu->filter.midi_thru) - send_thru = 1; - switch (msg[0] & 0xf0) { - case 0x80: /* Note off. */ - if (send_thru) { - if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) - send_thru = 0; - if (!mpu->filter.midi_thru) - break; - if (!(mpu->inputref[chan].M_GETKEY)) - send_thru = 0; - mpu->inputref[chan].M_DELKEY; - } - break; - case 0x90: /* Note on. */ - if (send_thru) { - if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) - retrigger_thru = 1; - if (!mpu->filter.midi_thru) - break; - if (mpu->inputref[chan].M_GETKEY) - retrigger_thru = 1; - mpu->inputref[chan].M_SETKEY; - } - break; - case 0xb0: - if (msg[1] >= 120) { - send_thru = 0; - if (msg[1] == 123) { - /* All notes off. */ - for (key = 0; key < 128; key++) { - if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) { - if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { - midi_raw_out_byte(0x80 | chan); - midi_raw_out_byte(key); - midi_raw_out_byte(0); - } - mpu->inputref[chan].M_DELKEY; - } - } - } - break; - } - } - } - if ((msg[0] >= 0xf0) || (mpu->state.midi_mask & (1 << chan))) { - switch (msg[0] & 0xf0) { - case 0xa0: /* Aftertouch. */ - if (!mpu->filter.bender_in) - send = 0; - break; - case 0xb0: /* Control change. */ - if (!mpu->filter.bender_in && (msg[1] < 64)) - send = 0; - if (msg[1] >= 120) { - if (mpu->filter.modemsgs_in) - send = 1; - } - break; - case 0xc0: /* Program change. */ - if ((mpu->state.rec != M_RECON) && !mpu->filter.data_in_stop) { - mpu->filter.prchg_buf[chan] = msg[1]; - mpu->filter.prchg_mask |= 1 << chan; - } - break; - case 0xd0: /* Ch pressure. */ - case 0xe0: /* Pitch wheel. */ - if (!mpu->filter.bender_in) - send = 0; - break; - case 0xf0: /* System message. */ - if (msg[0] == 0xf8) { - send = 0; - if (mpu->clock.active && mpu->state.sync_in) { - send = 0; /* Don't pass to host in this mode? */ - tick = mpu->clock.timebase / 24; - if (mpu->clock.ticks_in != tick) { - if (!mpu->clock.ticks_in || (mpu->clock.ticks_in > (tick * 2))) - mpu->clock.freq_mod *= 2.0; - else { - if (ABS(mpu->clock.ticks_in-tick) == 1) - mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick * 2); - else - mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick); - } - MPU401_ReCalcClock(mpu); - } - mpu->clock.ticks_in = 0; - } - } else if (msg[0] > 0xf8) { /* Realtime. */ - if (!(mpu->filter.rt_in && (msg[0] <= 0xfc) && (msg[0] >= 0xfa))) { - recdata[0] = 0xff; - recdata[1] = msg[0]; - MPU401_RecQueueBuffer(mpu, recdata, 2, 1); - send = 0; - } - } else { /* Common or system. */ - send = 0; - if ((msg[0] == 0xf2) || (msg[0] == 0xf3) || (msg[0] == 0xf6)) { - if (mpu->filter.commonmsgs_in) - send = 1; - if (mpu->filter.commonmsgs_thru) - for (i = 0; i < len; i++) - midi_raw_out_byte(msg[i]); - } - } - if (send) { - recmsg[0] = 0xff; - recmsg[1] = msg[0]; - recmsg[2] = msg[1]; - recmsg[3] = msg[2]; - MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); - } - if (mpu->filter.rt_affection) { - switch(msg[0]) { - case 0xf2: case 0xf3: - mpu->state.block_ack = 1; - MPU401_WriteCommand(mpu, 0xb8); /* Clear play counters. */ - break; - case 0xfa: - mpu->state.block_ack = 1; - MPU401_WriteCommand(mpu, 0xa); /* Start, play. */ - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(msg[0]); - break; - case 0xfb: - mpu->state.block_ack = 1; - MPU401_WriteCommand(mpu, 0xb); /* Continue, play. */ - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(msg[0]); - break; - case 0xfc: - mpu->state.block_ack = 1; - MPU401_WriteCommand(mpu, 0xd) ;/* Stop: Play, rec, midi */ - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(msg[0]); - break; - } - return; - } - } - } - if (send_thru && mpu->midi_thru) { - if (retrigger_thru) { - midi_raw_out_byte(0x80 | (msg[0] & 0xf)); - midi_raw_out_byte(msg[1]); - midi_raw_out_byte(msg[2]); - } - for (i = 0; i < len; i++) - midi_raw_out_byte(msg[i]); - } - if (send) { - if (mpu->state.rec == M_RECON) { - recmsg[0] = mpu->clock.rec_counter; - recmsg[1] = msg[0]; - recmsg[2] = msg[1]; - recmsg[3] = msg[2]; - MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); - mpu->clock.rec_counter = 0; - } - else if (mpu->filter.data_in_stop) { - if (mpu->filter.timing_in_stop) { - recmsg[0] = 0; - recmsg[1] = msg[0]; - recmsg[2] = msg[1]; - recmsg[3] = msg[2]; - MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); - } else { - recmsg[0] = msg[0]; - recmsg[1] = msg[1]; - recmsg[2] = msg[2]; - recmsg[3] = 0; - MPU401_RecQueueBuffer(mpu, recmsg, len, 1); - } - } - } - return; + if (msg[0] < 0x80) { + /* Expand running status */ + msg[2] = msg[1]; + msg[1] = msg[0]; + msg[0] = old_msg; + } + old_msg = msg[0]; + chan = msg[0] & 0xf; + chrefnum = mpu->ch_toref[chan]; + key = msg[1] & 0x7f; + if (msg[0] < 0xf0) { + /* If non-system msg. */ + if (!(mpu->state.midi_mask & (1 << chan)) && mpu->filter.all_thru) + send_thru = 1; + else if (mpu->filter.midi_thru) + send_thru = 1; + switch (msg[0] & 0xf0) { + case 0x80: /* Note off. */ + if (send_thru) { + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) + send_thru = 0; + if (!mpu->filter.midi_thru) + break; + if (!(mpu->inputref[chan].M_GETKEY)) + send_thru = 0; + mpu->inputref[chan].M_DELKEY; + } + break; + case 0x90: /* Note on. */ + if (send_thru) { + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) + retrigger_thru = 1; + if (!mpu->filter.midi_thru) + break; + if (mpu->inputref[chan].M_GETKEY) + retrigger_thru = 1; + mpu->inputref[chan].M_SETKEY; + } + break; + case 0xb0: + if (msg[1] >= 120) { + send_thru = 0; + if (msg[1] == 123) { + /* All notes off. */ + for (key = 0; key < 128; key++) { + if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) { + if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { + midi_raw_out_byte(0x80 | chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + mpu->inputref[chan].M_DELKEY; + } + } + } + break; + } + } + } + if ((msg[0] >= 0xf0) || (mpu->state.midi_mask & (1 << chan))) { + switch (msg[0] & 0xf0) { + case 0xa0: /* Aftertouch. */ + if (!mpu->filter.bender_in) + send = 0; + break; + case 0xb0: /* Control change. */ + if (!mpu->filter.bender_in && (msg[1] < 64)) + send = 0; + if (msg[1] >= 120) { + if (mpu->filter.modemsgs_in) + send = 1; + } + break; + case 0xc0: /* Program change. */ + if ((mpu->state.rec != M_RECON) && !mpu->filter.data_in_stop) { + mpu->filter.prchg_buf[chan] = msg[1]; + mpu->filter.prchg_mask |= 1 << chan; + } + break; + case 0xd0: /* Ch pressure. */ + case 0xe0: /* Pitch wheel. */ + if (!mpu->filter.bender_in) + send = 0; + break; + case 0xf0: /* System message. */ + if (msg[0] == 0xf8) { + send = 0; + if (mpu->clock.active && mpu->state.sync_in) { + send = 0; /* Don't pass to host in this mode? */ + tick = mpu->clock.timebase / 24; + if (mpu->clock.ticks_in != tick) { + if (!mpu->clock.ticks_in || (mpu->clock.ticks_in > (tick * 2))) + mpu->clock.freq_mod *= 2.0; + else { + if (ABS(mpu->clock.ticks_in - tick) == 1) + mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick * 2); + else + mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick); + } + MPU401_ReCalcClock(mpu); + } + mpu->clock.ticks_in = 0; + } + } else if (msg[0] > 0xf8) { /* Realtime. */ + if (!(mpu->filter.rt_in && (msg[0] <= 0xfc) && (msg[0] >= 0xfa))) { + recdata[0] = 0xff; + recdata[1] = msg[0]; + MPU401_RecQueueBuffer(mpu, recdata, 2, 1); + send = 0; + } + } else { /* Common or system. */ + send = 0; + if ((msg[0] == 0xf2) || (msg[0] == 0xf3) || (msg[0] == 0xf6)) { + if (mpu->filter.commonmsgs_in) + send = 1; + if (mpu->filter.commonmsgs_thru) + for (i = 0; i < len; i++) + midi_raw_out_byte(msg[i]); + } + } + if (send) { + recmsg[0] = 0xff; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + } + if (mpu->filter.rt_affection) { + switch (msg[0]) { + case 0xf2: + case 0xf3: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xb8); /* Clear play counters. */ + break; + case 0xfa: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xa); /* Start, play. */ + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + case 0xfb: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xb); /* Continue, play. */ + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + case 0xfc: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xd); /* Stop: Play, rec, midi */ + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + } + return; + } + } + } + if (send_thru && mpu->midi_thru) { + if (retrigger_thru) { + midi_raw_out_byte(0x80 | (msg[0] & 0xf)); + midi_raw_out_byte(msg[1]); + midi_raw_out_byte(msg[2]); + } + for (i = 0; i < len; i++) + midi_raw_out_byte(msg[i]); + } + if (send) { + if (mpu->state.rec == M_RECON) { + recmsg[0] = mpu->clock.rec_counter; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + mpu->clock.rec_counter = 0; + } else if (mpu->filter.data_in_stop) { + if (mpu->filter.timing_in_stop) { + recmsg[0] = 0; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + } else { + recmsg[0] = msg[0]; + recmsg[1] = msg[1]; + recmsg[2] = msg[2]; + recmsg[3] = 0; + MPU401_RecQueueBuffer(mpu, recmsg, len, 1); + } + } + } + return; } /* UART mode input. */ for (i = 0; i < len; i++) - MPU401_QueueByte(mpu, msg[i]); + MPU401_QueueByte(mpu, msg[i]); } void @@ -1653,39 +1665,38 @@ void mpu401_change_addr(mpu_t *mpu, uint16_t addr) { if (mpu == NULL) - return; + return; if (mpu->addr) - io_removehandler(mpu->addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_removehandler(mpu->addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); mpu->addr = addr; if (mpu->addr) - io_sethandler(mpu->addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_sethandler(mpu->addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); } - void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input) { - mpu->status = STATUS_INPUT_NOT_READY; - mpu->irq = irq; + mpu->status = STATUS_INPUT_NOT_READY; + mpu->irq = irq; mpu->queue_used = 0; - mpu->queue_pos = 0; - mpu->mode = M_UART; - mpu->addr = addr; + mpu->queue_pos = 0; + mpu->mode = M_UART; + mpu->addr = addr; /* Expalantion: - MPU-401 starting in intelligent mode = Full MPU-401 intelligent mode capability; - MPU-401 starting in UART mode = Reduced MPU-401 intelligent mode capability seen on the Sound Blaster 16/AWE32, - only supporting commands 3F (set UART mode) and FF (reset). */ + MPU-401 starting in intelligent mode = Full MPU-401 intelligent mode capability; + MPU-401 starting in UART mode = Reduced MPU-401 intelligent mode capability seen on the Sound Blaster 16/AWE32, + only supporting commands 3F (set UART mode) and FF (reset). */ mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; mpu401_log("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); if (mpu->addr) - io_sethandler(mpu->addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_sethandler(mpu->addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); io_sethandler(0x2A20, 16, - NULL, NULL, NULL, imf_write, NULL, NULL, mpu); + NULL, NULL, NULL, imf_write, NULL, NULL, mpu); timer_add(&mpu->mpu401_event_callback, MPU401_Event, mpu, 0); timer_add(&mpu->mpu401_eoi_callback, MPU401_EOIHandler, mpu, 0); timer_add(&mpu->mpu401_reset_callback, MPU401_ResetDone, mpu, 0); @@ -1693,40 +1704,37 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input) MPU401_Reset(mpu); if (receive_input) - midi_in_handler(1, MPU401_InputMsg, MPU401_InputSysex, mpu); + midi_in_handler(1, MPU401_InputMsg, MPU401_InputSysex, mpu); } - void mpu401_device_add(void) { if (!mpu401_standalone_enable) - return; + return; - if (machines[machine].flags & MACHINE_MCA) - device_add(&mpu401_mca_device); + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&mpu401_mca_device); else - device_add(&mpu401_device); + device_add(&mpu401_device); } - static uint8_t mpu401_mca_read(int port, void *p) { - mpu_t *mpu = (mpu_t *)p; + mpu_t *mpu = (mpu_t *) p; return mpu->pos_regs[port & 7]; } - static void mpu401_mca_write(int port, uint8_t val, void *p) { - mpu_t *mpu = (mpu_t *)p; + mpu_t *mpu = (mpu_t *) p; uint16_t addr; if (port < 0x102) - return; + return; addr = (mpu->pos_regs[2] & 2) ? 0x0330 : 0x1330; @@ -1735,38 +1743,35 @@ mpu401_mca_write(int port, uint8_t val, void *p) mpu->pos_regs[port] = val; if (port == 2) { - io_removehandler(addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_removehandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); - addr = (mpu->pos_regs[2] & 2) ? 0x1330 : 0x0330; + addr = (mpu->pos_regs[2] & 2) ? 0x1330 : 0x0330; - io_sethandler(addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_sethandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); } } - static uint8_t mpu401_mca_feedb(void *p) { return 1; } - void mpu401_irq_attach(mpu_t *mpu, void (*ext_irq_update)(void *priv, int set), int (*ext_irq_pending)(void *priv), void *priv) { - mpu->ext_irq_update = ext_irq_update; + mpu->ext_irq_update = ext_irq_update; mpu->ext_irq_pending = ext_irq_pending; - mpu->priv = priv; + mpu->priv = priv; } - static void * mpu401_standalone_init(const device_t *info) { - mpu_t *mpu; - int irq; + mpu_t *mpu; + int irq; uint16_t base; mpu = malloc(sizeof(mpu_t)); @@ -1775,115 +1780,161 @@ mpu401_standalone_init(const device_t *info) mpu401_log("mpu_init\n"); if (info->flags & DEVICE_MCA) { - mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, NULL, mpu); - mpu->pos_regs[0] = 0x0F; - mpu->pos_regs[1] = 0x6C; - base = 0; /* Tell mpu401_init() that this is the MCA variant. */ - irq = 2; /* According to @6c0f.adf, the IRQ is fixed to 2. */ + mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, NULL, mpu); + mpu->pos_regs[0] = 0x0F; + mpu->pos_regs[1] = 0x6C; + base = 0; /* Tell mpu401_init() that this is the MCA variant. */ + irq = 2; /* According to @6c0f.adf, the IRQ is fixed to 2. */ } else { - base = device_get_config_hex16("base"); - irq = device_get_config_int("irq"); + base = device_get_config_hex16("base"); + irq = device_get_config_int("irq"); } mpu401_init(mpu, base, irq, M_INTELLIGENT, device_get_config_int("receive_input")); - - return(mpu); -} + return (mpu); +} static void mpu401_standalone_close(void *priv) { - mpu_t *mpu = (mpu_t *)priv; + mpu_t *mpu = (mpu_t *) priv; free(mpu); } - -static const device_config_t mpu401_standalone_config[] = -{ - { - "base", "MPU-401 Address", CONFIG_HEX16, "", 0x330, - { - { - "0x300", 0x300 - }, - { - "0x330", 0x330 - }, - { - "" - } - } - }, - { - "irq", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, - { - .name = "receive_input", - .description = "Receive input", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - "", "", -1 +static const device_config_t mpu401_standalone_config[] = { + // clang-format off + { + .name = "base", + .description = "MPU-401 Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x330, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x230", + .value = 0x230 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x300", + .value = 0x300 + }, + { + .description = "0x320", + .value = 0x320 + }, + { + .description = "0x330", + .value = 0x330 + }, + { + .description = "0x340", + .value = 0x340 + }, + { + .description = "0x350", + .value = 0x350 + }, + { .description = "" } } + }, + { + .name = "irq", + .description = "MPU-401 IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 4", + .value = 4 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 6", + .value = 6 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { .description = "" } + } + }, + { + .name = "receive_input", + .description = "Receive input", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on }; - -static const device_config_t mpu401_standalone_mca_config[] = -{ - { - .name = "receive_input", - .description = "Receive input", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - "", "", -1 - } +static const device_config_t mpu401_standalone_mca_config[] = { + // clang-format off + { + .name = "receive_input", + .description = "Receive input", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on }; - const device_t mpu401_device = { - "Roland MPU-IPC-T", - DEVICE_ISA, 0, - mpu401_standalone_init, mpu401_standalone_close, NULL, - NULL, - NULL, - NULL, - mpu401_standalone_config + .name = "Roland MPU-IPC-T", + .internal_name = "mpu401", + .flags = DEVICE_ISA, + .local = 0, + .init = mpu401_standalone_init, + .close = mpu401_standalone_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mpu401_standalone_config }; const device_t mpu401_mca_device = { - "Roland MPU-IMC", - DEVICE_MCA, 0, - mpu401_standalone_init, mpu401_standalone_close, NULL, - NULL, - NULL, - NULL, - mpu401_standalone_mca_config + .name = "Roland MPU-IMC", + .internal_name = "mpu401_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = mpu401_standalone_init, + .close = mpu401_standalone_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mpu401_standalone_mca_config }; diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index ce36078f6..cce75bf39 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -1,222 +1,71 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#include +/* + * 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. + * + * Interface to the actual OPL emulator. + * + * TODO: Finish re-working this into a device_t, which requires a + * poll-like function for "update" so the sound card can call + * that and get a buffer-full of sample data. + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + */ +#include #include -#include +#include #include +#include #include -#include <86box/86box.h> +#define HAVE_STDARG_H + #include "cpu.h" +#include <86box/86box.h> +#include <86box/device.h> #include <86box/io.h> -#include <86box/timer.h> #include <86box/sound.h> #include <86box/snd_opl.h> -#include <86box/snd_opl_backend.h> - - -/*Interfaces between 86Box and the actual OPL emulator*/ +static uint32_t fm_dev_inst[FM_DRV_MAX][FM_MAX]; uint8_t -opl2_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; +fm_driver_get(int chip_id, fm_drv_t *drv) { + switch (chip_id) { + case FM_YM3812: + if (fm_driver == FM_DRV_NUKED) { + *drv = nuked_opl_drv; + drv->priv = device_add_inst(&ym3812_nuked_device, fm_dev_inst[fm_driver][chip_id]++); + } else { + *drv = ymfm_drv; + drv->priv = device_add_inst(&ym3812_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + } + break; - sub_cycles((int) (isa_timing * 8)); - opl2_update2(opl); + case FM_YMF262: + if (fm_driver == FM_DRV_NUKED) { + *drv = nuked_opl_drv; + drv->priv = device_add_inst(&ymf262_nuked_device, fm_dev_inst[fm_driver][chip_id]++); + } else { + *drv = ymfm_drv; + drv->priv = device_add_inst(&ymf262_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + } + break; - return opl_read(0, a); -} + case FM_YMF289B: + *drv = ymfm_drv; + drv->priv = device_add_inst(&ymf289b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + break; - -void -opl2_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - opl2_update2(opl); - opl_write(0, a, v); - opl_write(1, a, v); -} - - -uint8_t -opl2_l_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - - return opl_read(0, a); -} - - -void -opl2_l_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - opl2_update2(opl); - opl_write(0, a, v); -} - - -uint8_t -opl2_r_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - - return opl_read(1, a); -} - - -void -opl2_r_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - opl2_update2(opl); - opl_write(1, a, v); -} - - -uint8_t -opl3_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - sub_cycles((int)(isa_timing * 8)); - opl3_update2(opl); - - return opl_read(0, a); -} - - -void -opl3_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - opl3_update2(opl); - opl_write(0, a, v); -} - - -void -opl2_update2(opl_t *opl) -{ - if (opl->pos < sound_pos_global) { - opl2_update(0, &opl->buffer[opl->pos << 1], sound_pos_global - opl->pos); - opl2_update(1, &opl->buffer2[opl->pos << 1], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) { - opl->buffer[(opl->pos << 1) + 1] = opl->buffer2[(opl->pos << 1) + 1]; - opl->filtbuf[0] = opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); - opl->filtbuf[1] = opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); - } + default: + return 0; } -} - -void -opl3_update2(opl_t *opl) -{ - if (opl->pos < sound_pos_global) { - opl3_update(0, &opl->buffer[(opl->pos << 1)], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) { - opl->filtbuf[0] = opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); - opl->filtbuf[1] = opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); - } - } -} - - -void -ym3812_timer_set_0(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - - if (period) - timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[0][timer]); -} - - -void -ym3812_timer_set_1(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - - if (period) - timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[1][timer]); -} - - -void -ymf262_timer_set(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - - if (period) - timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[0][timer]); -} - - -static void -opl_timer_callback00(void *p) -{ - opl_timer_over(0, 0); -} - - -static void -opl_timer_callback01(void *p) -{ - opl_timer_over(0, 1); -} - - -static void -opl_timer_callback10(void *p) -{ - opl_timer_over(1, 0); -} - - -static void -opl_timer_callback11(void *p) -{ - opl_timer_over(1, 1); -} - - -void -opl2_init(opl_t *opl) -{ - opl_init(ym3812_timer_set_0, opl, 0, 0); - opl_init(ym3812_timer_set_1, opl, 1, 0); - - timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); - timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0); - timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0); -} - - -void -opl3_init(opl_t *opl) -{ - opl_init(ymf262_timer_set, opl, 0, 1); - - timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); -} + return 1; +}; diff --git a/src/sound/snd_opl_backend.c b/src/sound/snd_opl_backend.c deleted file mode 100644 index 03bdbd2ea..000000000 --- a/src/sound/snd_opl_backend.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#include -#include -#include -#include - -#include <86box/86box.h> -#include -#include <86box/sound.h> -#include <86box/snd_opl_backend.h> -#include "cpu.h" -#include <86box/mem.h> - - -int opl_type = 0; - - -static struct -{ - struct opl3_chip opl3chip; - int addr; - int timer[2]; - uint8_t timer_ctrl; - uint8_t status_mask; - uint8_t status; - int is_opl3; - - void (*timer_callback)(void *param, int timer, uint64_t period); - void *timer_param; -} opl[2]; - - -enum -{ - STATUS_TIMER_1 = 0x40, - STATUS_TIMER_2 = 0x20, - STATUS_TIMER_ALL = 0x80 -}; - -enum -{ - CTRL_IRQ_RESET = 0x80, - CTRL_TIMER1_MASK = 0x40, - CTRL_TIMER2_MASK = 0x20, - CTRL_TIMER2_CTRL = 0x02, - CTRL_TIMER1_CTRL = 0x01 -}; - - -void -opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3) -{ - opl[nr].timer_callback = timer_callback; - opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = is_opl3; - - opl[nr].opl3chip.newm = 0; - OPL3_Reset(&opl[nr].opl3chip, 48000); -} - - -void -opl_status_update(int nr) -{ - if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) - opl[nr].status |= STATUS_TIMER_ALL; - else - opl[nr].status &= ~STATUS_TIMER_ALL; -} - - -void -opl_timer_over(int nr, int timer) -{ - if (!timer) { - opl[nr].status |= STATUS_TIMER_1; - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - } else { - opl[nr].status |= STATUS_TIMER_2; - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - } - - opl_status_update(nr); -} - - -void -opl_write(int nr, uint16_t addr, uint8_t val) -{ - if (!(addr & 1)) { - opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; - if (!opl[nr].is_opl3) - opl[nr].addr &= 0xff; - } else { - OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); - if (opl[nr].addr == 0x105) - opl[nr].opl3chip.newm = opl[nr].addr & 0x01; - - switch (opl[nr].addr) { - case 0x02: /*Timer 1*/ - opl[nr].timer[0] = 256 - val; - break; - case 0x03: /*Timer 2*/ - opl[nr].timer[1] = 256 - val; - break; - case 0x04: /*Timer control*/ - if (val & CTRL_IRQ_RESET) { /*IRQ reset*/ - opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); - opl_status_update(nr); - return; - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) { - if (val & CTRL_TIMER1_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - else - opl[nr].timer_callback(opl[nr].timer_param, 0, 0); - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) { - if (val & CTRL_TIMER2_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - else - opl[nr].timer_callback(opl[nr].timer_param, 1, 0); - } - opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; - opl[nr].timer_ctrl = val; - break; - } - } -} - - -uint8_t -opl_read(int nr, uint16_t addr) -{ - if (!(addr & 1)) - return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); - - if (opl[nr].is_opl3 && ((addr & 3) == 3)) - return 0x00; - - return opl[nr].is_opl3 ? 0 : 0xff; -} - - -void -opl2_update(int nr, int32_t *buffer, int samples) -{ - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); -} - - -void -opl3_update(int nr, int32_t *buffer, int samples) -{ - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); -} diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c new file mode 100644 index 000000000..8e1a7e774 --- /dev/null +++ b/src/sound/snd_opl_nuked.c @@ -0,0 +1,1618 @@ +/* + * 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. + * + * Nuked OPL3 emulator. + * + * Thanks: + * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): + * Feedback and Rhythm part calculation information. + * forums.submarine.org.uk(carbon14, opl3): + * Tremolo and phase generator calculation information. + * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): + * OPL2 ROMs. + * siliconpr0n.org(John McMaster, digshadow): + * YMF262 and VRC VII decaps and die shots. + * + * Version: 1.8.0 + * + * Translation from C++ into C done by Miran Grca. + * + * **TODO** The OPL3 is a stereo chip, and, thus, always generates + * a two-sample stream of data, for the L and R channels, + * in that order. The OPL2, however, is mono. What should + * we generate for that? + * + * Version: @(#)snd_opl_nuked.c 1.0.5 2020/07/16 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Alexey Khokholov (Nuke.YKT) + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2013-2018 Alexey Khokholov (Nuke.YKT) + */ +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/snd_opl_nuked.h> +#include <86box/sound.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/snd_opl.h> + +#define WRBUF_SIZE 1024 +#define WRBUF_DELAY 1 +#define RSM_FRAC 10 + +// Channel types +enum { + ch_2op = 0, + ch_4op = 1, + ch_4op2 = 2, + ch_drum = 3 +}; + +// Envelope key types +enum { + egk_norm = 0x01, + egk_drum = 0x02 +}; + +enum envelope_gen_num { + envelope_gen_num_attack = 0, + envelope_gen_num_decay = 1, + envelope_gen_num_sustain = 2, + envelope_gen_num_release = 3 +}; + +struct chan; +struct chip; + +typedef struct slot { + struct chan *chan; + struct chip *dev; + int16_t out; + int16_t fbmod; + int16_t *mod; + int16_t prout; + int16_t eg_rout; + int16_t eg_out; + uint8_t eg_inc; + uint8_t eg_gen; + uint8_t eg_rate; + uint8_t eg_ksl; + uint8_t *trem; + uint8_t reg_vib; + uint8_t reg_type; + uint8_t reg_ksr; + uint8_t reg_mult; + uint8_t reg_ksl; + uint8_t reg_tl; + uint8_t reg_ar; + uint8_t reg_dr; + uint8_t reg_sl; + uint8_t reg_rr; + uint8_t reg_wf; + uint8_t key; + uint32_t pg_reset; + uint32_t pg_phase; + uint16_t pg_phase_out; + uint8_t slot_num; +} slot_t; + +typedef struct chan { + slot_t *slots[2]; + struct chan *pair; + struct chip *dev; + int16_t *out[4]; + uint8_t chtype; + uint16_t f_num; + uint8_t block; + uint8_t fb; + uint8_t con; + uint8_t alg; + uint8_t ksv; + uint16_t cha, + chb; + uint8_t ch_num; +} chan_t; + +typedef struct wrbuf { + uint64_t time; + uint16_t reg; + uint8_t data; +} wrbuf_t; + +typedef struct chip { + chan_t chan[18]; + slot_t slot[36]; + uint16_t timer; + uint64_t eg_timer; + uint8_t eg_timerrem; + uint8_t eg_state; + uint8_t eg_add; + uint8_t newm; + uint8_t nts; + uint8_t rhy; + uint8_t vibpos; + uint8_t vibshift; + uint8_t tremolo; + uint8_t tremolopos; + uint8_t tremoloshift; + uint32_t noise; + int16_t zeromod; + int32_t mixbuff[2]; + uint8_t rm_hh_bit2; + uint8_t rm_hh_bit3; + uint8_t rm_hh_bit7; + uint8_t rm_hh_bit8; + uint8_t rm_tc_bit3; + uint8_t rm_tc_bit5; + + // OPL3L + int32_t rateratio; + int32_t samplecnt; + int32_t oldsamples[2]; + int32_t samples[2]; + + uint64_t wrbuf_samplecnt; + uint32_t wrbuf_cur; + uint32_t wrbuf_last; + uint64_t wrbuf_lasttime; + wrbuf_t wrbuf[WRBUF_SIZE]; +} nuked_t; + +typedef struct { + nuked_t opl; + int8_t flags, pad; + + uint16_t port; + uint8_t status, timer_ctrl; + uint16_t timer_count[2], + timer_cur_count[2]; + + pc_timer_t timers[2]; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; +} nuked_drv_t; + +enum { + FLAG_CYCLES = 0x02, + FLAG_OPL3 = 0x01 +}; + +enum { + STAT_TMR_OVER = 0x60, + STAT_TMR1_OVER = 0x40, + STAT_TMR2_OVER = 0x20, + STAT_TMR_ANY = 0x80 +}; + +enum { + CTRL_RESET = 0x80, + CTRL_TMR_MASK = 0x60, + CTRL_TMR1_MASK = 0x40, + CTRL_TMR2_MASK = 0x20, + CTRL_TMR2_START = 0x02, + CTRL_TMR1_START = 0x01 +}; + +#ifdef ENABLE_OPL_LOG +static void +nuked_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +} +#else +# define nuked_log(fmt, ...) +#endif + +// logsin table +static const uint16_t logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, + 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, + 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, + 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, + 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, + 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, + 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, + 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, + 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, + 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, + 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, + 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, + 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, + 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, + 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, + 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +// exp table +static const uint16_t exprom[256] = { + 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, + 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, + 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, + 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, + 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, + 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, + 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, + 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, + 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, + 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, + 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, + 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, + 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, + 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, + 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, + 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, + 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, + 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, + 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, + 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, + 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, + 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, + 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, + 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, + 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, + 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, + 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, + 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, + 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, + 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, + 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, + 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 +}; + +// freq mult table multiplied by 2 +// +// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 +static const uint8_t mt[16] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 +}; + +// ksl table +static const uint8_t kslrom[16] = { + 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 +}; + +static const uint8_t kslshift[4] = { + 8, 1, 2, 0 +}; + +// envelope generator constants +static const uint8_t eg_incstep[4][4] = { + {0, 0, 0, 0}, + { 1, 0, 0, 0}, + { 1, 0, 1, 0}, + { 1, 1, 1, 0} +}; + +// address decoding +static const int8_t ad_slot[0x20] = { + 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, + 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static const uint8_t ch_slot[18] = { + 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 +}; + +// Envelope generator +typedef int16_t (*env_sinfunc)(uint16_t phase, uint16_t envelope); +typedef void (*env_genfunc)(slot_t *slot); + +static int16_t +env_calc_exp(uint32_t level) +{ + if (level > 0x1fff) + level = 0x1fff; + + return ((exprom[level & 0xff] << 1) >> (level >> 8)); +} + +static int16_t +env_calc_sin0(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + uint16_t neg = 0; + + phase &= 0x3ff; + + if (phase & 0x0200) + neg = 0xffff; + + if (phase & 0x0100) + out = logsinrom[(phase & 0xff) ^ 0xff]; + else + out = logsinrom[phase & 0xff]; + + return (env_calc_exp(out + (env << 3)) ^ neg); +} + +static int16_t +env_calc_sin1(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x3ff; + + if (phase & 0x0200) + out = 0x1000; + else if (phase & 0x0100) + out = logsinrom[(phase & 0xff) ^ 0xff]; + else + out = logsinrom[phase & 0xff]; + + return (env_calc_exp(out + (env << 3))); +} + +static int16_t +env_calc_sin2(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x03ff; + + if (phase & 0x0100) + out = logsinrom[(phase & 0xff) ^ 0xff]; + else + out = logsinrom[phase & 0xff]; + + return (env_calc_exp(out + (env << 3))); +} + +static int16_t +env_calc_sin3(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x03ff; + + if (phase & 0x0100) + out = 0x1000; + else + out = logsinrom[phase & 0xff]; + + return (env_calc_exp(out + (env << 3))); +} + +static int16_t +env_calc_sin4(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + uint16_t neg = 0; + + phase &= 0x03ff; + + if ((phase & 0x0300) == 0x0100) + neg = 0xffff; + + if (phase & 0x0200) + out = 0x1000; + else if (phase & 0x80) + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + else + out = logsinrom[(phase << 1) & 0xff]; + + return (env_calc_exp(out + (env << 3)) ^ neg); +} + +static int16_t +env_calc_sin5(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x03ff; + + if (phase & 0x0200) + out = 0x1000; + else if (phase & 0x80) + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + else + out = logsinrom[(phase << 1) & 0xff]; + + return (env_calc_exp(out + (env << 3))); +} + +static int16_t +env_calc_sin6(uint16_t phase, uint16_t env) +{ + uint16_t neg = 0; + + phase &= 0x03ff; + + if (phase & 0x0200) + neg = 0xffff; + + return (env_calc_exp(env << 3) ^ neg); +} + +static int16_t +env_calc_sin7(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + uint16_t neg = 0; + + phase &= 0x03ff; + + if (phase & 0x0200) { + neg = 0xffff; + phase = (phase & 0x01ff) ^ 0x01ff; + } + + out = phase << 3; + + return (env_calc_exp(out + (env << 3)) ^ neg); +} + +static const env_sinfunc env_sin[8] = { + env_calc_sin0, + env_calc_sin1, + env_calc_sin2, + env_calc_sin3, + env_calc_sin4, + env_calc_sin5, + env_calc_sin6, + env_calc_sin7 +}; + +static void +env_update_ksl(slot_t *slot) +{ + int16_t ksl = (kslrom[slot->chan->f_num >> 6] << 2) - ((0x08 - slot->chan->block) << 5); + + if (ksl < 0) + ksl = 0; + + slot->eg_ksl = (uint8_t) ksl; +} + +static void +env_calc(slot_t *slot) +{ + uint8_t nonzero; + uint8_t rate; + uint8_t rate_hi; + uint8_t rate_lo; + uint8_t reg_rate = 0; + uint8_t ks; + uint8_t eg_shift, shift; + uint16_t eg_rout; + int16_t eg_inc; + uint8_t eg_off; + uint8_t reset = 0; + + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + if (slot->key && slot->eg_gen == envelope_gen_num_release) { + reset = 1; + reg_rate = slot->reg_ar; + } else + switch (slot->eg_gen) { + case envelope_gen_num_attack: + reg_rate = slot->reg_ar; + break; + + case envelope_gen_num_decay: + reg_rate = slot->reg_dr; + break; + + case envelope_gen_num_sustain: + if (!slot->reg_type) + reg_rate = slot->reg_rr; + break; + + case envelope_gen_num_release: + reg_rate = slot->reg_rr; + break; + } + + slot->pg_reset = reset; + ks = slot->chan->ksv >> ((slot->reg_ksr ^ 1) << 1); + nonzero = (reg_rate != 0); + rate = ks + (reg_rate << 2); + rate_hi = rate >> 2; + rate_lo = rate & 0x03; + if (rate_hi & 0x10) + rate_hi = 0x0f; + eg_shift = rate_hi + slot->dev->eg_add; + shift = 0; + + if (nonzero) { + if (rate_hi < 12) { + if (slot->dev->eg_state) + switch (eg_shift) { + case 12: + shift = 1; + break; + + case 13: + shift = (rate_lo >> 1) & 0x01; + break; + + case 14: + shift = rate_lo & 0x01; + break; + + default: + break; + } + } else { + shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->dev->timer & 0x03]; + if (shift & 0x04) + shift = 0x03; + if (!shift) + shift = slot->dev->eg_state; + } + } + + eg_rout = slot->eg_rout; + eg_inc = 0; + eg_off = 0; + + // Instant attack + if (reset && rate_hi == 0x0f) + eg_rout = 0x00; + + // Envelope off + if ((slot->eg_rout & 0x1f8) == 0x1f8) + eg_off = 1; + + if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) + eg_rout = 0x1ff; + + switch (slot->eg_gen) { + case envelope_gen_num_attack: + if (!slot->eg_rout) + slot->eg_gen = envelope_gen_num_decay; + else if (slot->key && shift > 0 && rate_hi != 0x0f) + eg_inc = ((~slot->eg_rout) << shift) >> 4; + break; + + case envelope_gen_num_decay: + if ((slot->eg_rout >> 4) == slot->reg_sl) + slot->eg_gen = envelope_gen_num_sustain; + else if (!eg_off && !reset && shift > 0) + eg_inc = 1 << (shift - 1); + break; + + case envelope_gen_num_sustain: + case envelope_gen_num_release: + if (!eg_off && !reset && shift > 0) + eg_inc = 1 << (shift - 1); + break; + } + slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; + + // Key off + if (reset) + slot->eg_gen = envelope_gen_num_attack; + + if (!slot->key) + slot->eg_gen = envelope_gen_num_release; +} + +static void +env_key_on(slot_t *slot, uint8_t type) +{ + slot->key |= type; +} + +static void +env_key_off(slot_t *slot, uint8_t type) +{ + slot->key &= ~type; +} + +static void +phase_generate(slot_t *slot) +{ + uint16_t f_num; + uint32_t basefreq; + uint8_t rm_xor, n_bit; + uint32_t noise; + uint16_t phase; + int8_t range; + uint8_t vibpos; + nuked_t *dev; + + dev = slot->dev; + f_num = slot->chan->f_num; + if (slot->reg_vib) { + range = (f_num >> 7) & 7; + vibpos = dev->vibpos; + + if (!(vibpos & 3)) + range = 0; + else if (vibpos & 1) + range >>= 1; + range >>= dev->vibshift; + + if (vibpos & 4) + range = -range; + f_num += range; + } + + basefreq = (f_num << slot->chan->block) >> 1; + phase = (uint16_t) (slot->pg_phase >> 9); + + if (slot->pg_reset) + slot->pg_phase = 0; + slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; + + // Rhythm mode + noise = dev->noise; + slot->pg_phase_out = phase; + if (slot->slot_num == 13) { // hh + dev->rm_hh_bit2 = (phase >> 2) & 1; + dev->rm_hh_bit3 = (phase >> 3) & 1; + dev->rm_hh_bit7 = (phase >> 7) & 1; + dev->rm_hh_bit8 = (phase >> 8) & 1; + } + if (slot->slot_num == 17 && (dev->rhy & 0x20)) { // tc + dev->rm_tc_bit3 = (phase >> 3) & 1; + dev->rm_tc_bit5 = (phase >> 5) & 1; + } + if (dev->rhy & 0x20) { + rm_xor = (dev->rm_hh_bit2 ^ dev->rm_hh_bit7) | (dev->rm_hh_bit3 ^ dev->rm_tc_bit5) | (dev->rm_tc_bit3 ^ dev->rm_tc_bit5); + + switch (slot->slot_num) { + case 13: // hh + slot->pg_phase_out = rm_xor << 9; + if (rm_xor ^ (noise & 1)) + slot->pg_phase_out |= 0xd0; + else + slot->pg_phase_out |= 0x34; + break; + + case 16: // sd + slot->pg_phase_out = (dev->rm_hh_bit8 << 9) | ((dev->rm_hh_bit8 ^ (noise & 1)) << 8); + break; + + case 17: // tc + slot->pg_phase_out = (rm_xor << 9) | 0x80; + break; + + default: + break; + } + } + + n_bit = ((noise >> 14) ^ noise) & 0x01; + + dev->noise = (noise >> 1) | (n_bit << 22); +} + +static void +slot_write_20(slot_t *slot, uint8_t data) +{ + if ((data >> 7) & 0x01) + slot->trem = &slot->dev->tremolo; + else + slot->trem = (uint8_t *) &slot->dev->zeromod; + + slot->reg_vib = (data >> 6) & 0x01; + slot->reg_type = (data >> 5) & 0x01; + slot->reg_ksr = (data >> 4) & 0x01; + slot->reg_mult = data & 0x0f; +} + +static void +slot_write_40(slot_t *slot, uint8_t data) +{ + slot->reg_ksl = (data >> 6) & 0x03; + slot->reg_tl = data & 0x3f; + + env_update_ksl(slot); +} + +static void +slot_write_60(slot_t *slot, uint8_t data) +{ + slot->reg_ar = (data >> 4) & 0x0f; + slot->reg_dr = data & 0x0f; +} + +static void +slot_write_80(slot_t *slot, uint8_t data) +{ + slot->reg_sl = (data >> 4) & 0x0f; + + if (slot->reg_sl == 0x0f) + slot->reg_sl = 0x1f; + + slot->reg_rr = data & 0x0f; +} + +static void +slot_write_e0(slot_t *slot, uint8_t data) +{ + slot->reg_wf = data & 0x07; + + if (slot->dev->newm == 0x00) + slot->reg_wf &= 0x03; +} + +static void +slot_generate(slot_t *slot) +{ + slot->out = env_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, + slot->eg_out); +} + +static void +slot_calc_fb(slot_t *slot) +{ + if (slot->chan->fb != 0x00) + slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->chan->fb); + else + slot->fbmod = 0; + + slot->prout = slot->out; +} + +static void +channel_setup_alg(chan_t *ch) +{ + if (ch->chtype == ch_drum) { + if (ch->ch_num == 7 || ch->ch_num == 8) { + ch->slots[0]->mod = &ch->dev->zeromod; + ch->slots[1]->mod = &ch->dev->zeromod; + return; + } + + switch (ch->alg & 0x01) { + case 0x00: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->slots[0]->out; + break; + + case 0x01: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->dev->zeromod; + break; + } + return; + } + + if (ch->alg & 0x08) + return; + + if (ch->alg & 0x04) { + ch->pair->out[0] = &ch->dev->zeromod; + ch->pair->out[1] = &ch->dev->zeromod; + ch->pair->out[2] = &ch->dev->zeromod; + ch->pair->out[3] = &ch->dev->zeromod; + + switch (ch->alg & 0x03) { + case 0x00: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->pair->slots[0]->out; + ch->slots[0]->mod = &ch->pair->slots[1]->out; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->slots[1]->out; + ch->out[1] = &ch->dev->zeromod; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x01: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->pair->slots[0]->out; + ch->slots[0]->mod = &ch->dev->zeromod; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->pair->slots[1]->out; + ch->out[1] = &ch->slots[1]->out; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x02: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->dev->zeromod; + ch->slots[0]->mod = &ch->pair->slots[1]->out; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->pair->slots[0]->out; + ch->out[1] = &ch->slots[1]->out; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x03: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->dev->zeromod; + ch->slots[0]->mod = &ch->pair->slots[1]->out; + ch->slots[1]->mod = &ch->dev->zeromod; + ch->out[0] = &ch->pair->slots[0]->out; + ch->out[1] = &ch->slots[0]->out; + ch->out[2] = &ch->slots[1]->out; + ch->out[3] = &ch->dev->zeromod; + break; + } + } else + switch (ch->alg & 0x01) { + case 0x00: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->slots[1]->out; + ch->out[1] = &ch->dev->zeromod; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x01: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->dev->zeromod; + ch->out[0] = &ch->slots[0]->out; + ch->out[1] = &ch->slots[1]->out; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + } +} + +static void +channel_update_rhythm(nuked_t *dev, uint8_t data) +{ + chan_t *ch6, *ch7, *ch8; + uint8_t chnum; + + dev->rhy = data & 0x3f; + if (dev->rhy & 0x20) { + ch6 = &dev->chan[6]; + ch7 = &dev->chan[7]; + ch8 = &dev->chan[8]; + ch6->out[0] = &ch6->slots[1]->out; + ch6->out[1] = &ch6->slots[1]->out; + ch6->out[2] = &dev->zeromod; + ch6->out[3] = &dev->zeromod; + ch7->out[0] = &ch7->slots[0]->out; + ch7->out[1] = &ch7->slots[0]->out; + ch7->out[2] = &ch7->slots[1]->out; + ch7->out[3] = &ch7->slots[1]->out; + ch8->out[0] = &ch8->slots[0]->out; + ch8->out[1] = &ch8->slots[0]->out; + ch8->out[2] = &ch8->slots[1]->out; + ch8->out[3] = &ch8->slots[1]->out; + + for (chnum = 6; chnum < 9; chnum++) + dev->chan[chnum].chtype = ch_drum; + + channel_setup_alg(ch6); + channel_setup_alg(ch7); + channel_setup_alg(ch8); + + // hh + if (dev->rhy & 0x01) + env_key_on(ch7->slots[0], egk_drum); + else + env_key_off(ch7->slots[0], egk_drum); + + // tc + if (dev->rhy & 0x02) + env_key_on(ch8->slots[1], egk_drum); + else + env_key_off(ch8->slots[1], egk_drum); + + // tom + if (dev->rhy & 0x04) + env_key_on(ch8->slots[0], egk_drum); + else + env_key_off(ch8->slots[0], egk_drum); + + // sd + if (dev->rhy & 0x08) + env_key_on(ch7->slots[1], egk_drum); + else + env_key_off(ch7->slots[1], egk_drum); + + // bd + if (dev->rhy & 0x10) { + env_key_on(ch6->slots[0], egk_drum); + env_key_on(ch6->slots[1], egk_drum); + } else { + env_key_off(ch6->slots[0], egk_drum); + env_key_off(ch6->slots[1], egk_drum); + } + } else { + for (chnum = 6; chnum < 9; chnum++) { + dev->chan[chnum].chtype = ch_2op; + + channel_setup_alg(&dev->chan[chnum]); + env_key_off(dev->chan[chnum].slots[0], egk_drum); + env_key_off(dev->chan[chnum].slots[1], egk_drum); + } + } +} + +static void +channel_write_a0(chan_t *ch, uint8_t data) +{ + if (ch->dev->newm && ch->chtype == ch_4op2) + return; + + ch->f_num = (ch->f_num & 0x300) | data; + ch->ksv = (ch->block << 1) | ((ch->f_num >> (0x09 - ch->dev->nts)) & 0x01); + + env_update_ksl(ch->slots[0]); + env_update_ksl(ch->slots[1]); + + if (ch->dev->newm && ch->chtype == ch_4op) { + ch->pair->f_num = ch->f_num; + ch->pair->ksv = ch->ksv; + + env_update_ksl(ch->pair->slots[0]); + env_update_ksl(ch->pair->slots[1]); + } +} + +static void +channel_write_b0(chan_t *ch, uint8_t data) +{ + if (ch->dev->newm && ch->chtype == ch_4op2) + return; + + ch->f_num = (ch->f_num & 0xff) | ((data & 0x03) << 8); + ch->block = (data >> 2) & 0x07; + ch->ksv = (ch->block << 1) | ((ch->f_num >> (0x09 - ch->dev->nts)) & 0x01); + + env_update_ksl(ch->slots[0]); + env_update_ksl(ch->slots[1]); + + if (ch->dev->newm && ch->chtype == ch_4op) { + ch->pair->f_num = ch->f_num; + ch->pair->block = ch->block; + ch->pair->ksv = ch->ksv; + + env_update_ksl(ch->pair->slots[0]); + env_update_ksl(ch->pair->slots[1]); + } +} + +static void +channel_write_c0(chan_t *ch, uint8_t data) +{ + ch->fb = (data & 0x0e) >> 1; + ch->con = data & 0x01; + ch->alg = ch->con; + + if (ch->dev->newm) { + if (ch->chtype == ch_4op) { + ch->pair->alg = 0x04 | (ch->con << 1) | ch->pair->con; + ch->alg = 0x08; + channel_setup_alg(ch->pair); + } else if (ch->chtype == ch_4op2) { + ch->alg = 0x04 | (ch->pair->con << 1) | ch->con; + ch->pair->alg = 0x08; + channel_setup_alg(ch); + } else + channel_setup_alg(ch); + } else + channel_setup_alg(ch); + + if (ch->dev->newm) { + ch->cha = ((data >> 4) & 0x01) ? ~0 : 0; + ch->chb = ((data >> 5) & 0x01) ? ~0 : 0; + } else + ch->cha = ch->chb = (uint16_t) ~0; +} + +static void +channel_key_on(chan_t *ch) +{ + if (ch->dev->newm) { + if (ch->chtype == ch_4op) { + env_key_on(ch->slots[0], egk_norm); + env_key_on(ch->slots[1], egk_norm); + env_key_on(ch->pair->slots[0], egk_norm); + env_key_on(ch->pair->slots[1], egk_norm); + } else if (ch->chtype == ch_2op || ch->chtype == ch_drum) { + env_key_on(ch->slots[0], egk_norm); + env_key_on(ch->slots[1], egk_norm); + } + } else { + env_key_on(ch->slots[0], egk_norm); + env_key_on(ch->slots[1], egk_norm); + } +} + +static void +channel_key_off(chan_t *ch) +{ + if (ch->dev->newm) { + if (ch->chtype == ch_4op) { + env_key_off(ch->slots[0], egk_norm); + env_key_off(ch->slots[1], egk_norm); + env_key_off(ch->pair->slots[0], egk_norm); + env_key_off(ch->pair->slots[1], egk_norm); + } else if (ch->chtype == ch_2op || ch->chtype == ch_drum) { + env_key_off(ch->slots[0], egk_norm); + env_key_off(ch->slots[1], egk_norm); + } + } else { + env_key_off(ch->slots[0], egk_norm); + env_key_off(ch->slots[1], egk_norm); + } +} + +static void +channel_set_4op(nuked_t *dev, uint8_t data) +{ + uint8_t chnum; + uint8_t bit; + + for (bit = 0; bit < 6; bit++) { + chnum = bit; + + if (bit >= 3) + chnum += 9 - 3; + + if ((data >> bit) & 0x01) { + dev->chan[chnum].chtype = ch_4op; + dev->chan[chnum + 3].chtype = ch_4op2; + } else { + dev->chan[chnum].chtype = ch_2op; + dev->chan[chnum + 3].chtype = ch_2op; + } + } +} + +uint16_t +nuked_write_addr(void *priv, uint16_t port, uint8_t val) +{ + nuked_t *dev = (nuked_t *) priv; + uint16_t addr; + + addr = val; + if ((port & 0x0002) && ((addr == 0x0005) || dev->newm)) + addr |= 0x0100; + + return (addr); +} + +void +nuked_write_reg(void *priv, uint16_t reg, uint8_t val) +{ + nuked_t *dev = (nuked_t *) priv; + uint8_t high = (reg >> 8) & 0x01; + uint8_t regm = reg & 0xff; + + switch (regm & 0xf0) { + case 0x00: + if (high) + switch (regm & 0x0f) { + case 0x04: + channel_set_4op(dev, val); + break; + + case 0x05: + dev->newm = val & 0x01; + break; + } + else + switch (regm & 0x0f) { + case 0x08: + dev->nts = (val >> 6) & 0x01; + break; + } + break; + + case 0x20: + case 0x30: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_20(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0x40: + case 0x50: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_40(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0x60: + case 0x70: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_60(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0x80: + case 0x90: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_80(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0xa0: + if ((regm & 0x0f) < 9) + channel_write_a0(&dev->chan[9 * high + (regm & 0x0f)], val); + break; + + case 0xb0: + if (regm == 0xbd && !high) { + dev->tremoloshift = (((val >> 7) ^ 1) << 1) + 2; + dev->vibshift = ((val >> 6) & 0x01) ^ 1; + channel_update_rhythm(dev, val); + } else if ((regm & 0x0f) < 9) { + channel_write_b0(&dev->chan[9 * high + (regm & 0x0f)], val); + + if (val & 0x20) + channel_key_on(&dev->chan[9 * high + (regm & 0x0f)]); + else + channel_key_off(&dev->chan[9 * high + (regm & 0x0f)]); + } + break; + + case 0xc0: + if ((regm & 0x0f) < 9) + channel_write_c0(&dev->chan[9 * high + (regm & 0x0f)], val); + break; + + case 0xe0: + case 0xf0: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_e0(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + } +} + +void +nuked_write_reg_buffered(void *priv, uint16_t reg, uint8_t val) +{ + nuked_t *dev = (nuked_t *) priv; + uint64_t time1, time2; + + if (dev->wrbuf[dev->wrbuf_last].reg & 0x0200) { + nuked_write_reg(dev, dev->wrbuf[dev->wrbuf_last].reg & 0x01ff, + dev->wrbuf[dev->wrbuf_last].data); + + dev->wrbuf_cur = (dev->wrbuf_last + 1) % WRBUF_SIZE; + dev->wrbuf_samplecnt = dev->wrbuf[dev->wrbuf_last].time; + } + + dev->wrbuf[dev->wrbuf_last].reg = reg | 0x0200; + dev->wrbuf[dev->wrbuf_last].data = val; + time1 = dev->wrbuf_lasttime + WRBUF_DELAY; + time2 = dev->wrbuf_samplecnt; + + if (time1 < time2) + time1 = time2; + + dev->wrbuf[dev->wrbuf_last].time = time1; + dev->wrbuf_lasttime = time1; + dev->wrbuf_last = (dev->wrbuf_last + 1) % WRBUF_SIZE; +} + +void +nuked_generate(void *priv, int32_t *bufp) +{ + nuked_t *dev = (nuked_t *) priv; + int16_t accm, shift = 0; + uint8_t i, j; + + bufp[1] = dev->mixbuff[1]; + + for (i = 0; i < 15; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + dev->mixbuff[0] = 0; + + for (i = 0; i < 18; i++) { + accm = 0; + + for (j = 0; j < 4; j++) + accm += *dev->chan[i].out[j]; + + dev->mixbuff[0] += (int16_t) (accm & dev->chan[i].cha); + } + for (i = 15; i < 18; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + bufp[0] = dev->mixbuff[0]; + + for (i = 18; i < 33; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + dev->mixbuff[1] = 0; + + for (i = 0; i < 18; i++) { + accm = 0; + + for (j = 0; j < 4; j++) + accm += *dev->chan[i].out[j]; + + dev->mixbuff[1] += (int16_t) (accm & dev->chan[i].chb); + } + + for (i = 33; i < 36; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + if ((dev->timer & 0x3f) == 0x3f) + dev->tremolopos = (dev->tremolopos + 1) % 210; + + if (dev->tremolopos < 105) + dev->tremolo = dev->tremolopos >> dev->tremoloshift; + else + dev->tremolo = (210 - dev->tremolopos) >> dev->tremoloshift; + + if ((dev->timer & 0x03ff) == 0x03ff) + dev->vibpos = (dev->vibpos + 1) & 7; + + dev->timer++; + dev->eg_add = 0; + + if (dev->eg_timer) { + while (shift < 36 && ((dev->eg_timer >> shift) & 1) == 0) + shift++; + + if (shift > 12) + dev->eg_add = 0; + else + dev->eg_add = shift + 1; + } + + if (dev->eg_timerrem || dev->eg_state) { + if (dev->eg_timer == 0xfffffffff) { + dev->eg_timer = 0; + dev->eg_timerrem = 1; + } else { + dev->eg_timer++; + dev->eg_timerrem = 0; + } + } + + dev->eg_state ^= 1; + + while (dev->wrbuf[dev->wrbuf_cur].time <= dev->wrbuf_samplecnt) { + if (!(dev->wrbuf[dev->wrbuf_cur].reg & 0x200)) + break; + + dev->wrbuf[dev->wrbuf_cur].reg &= 0x01ff; + + nuked_write_reg(dev, dev->wrbuf[dev->wrbuf_cur].reg, + dev->wrbuf[dev->wrbuf_cur].data); + + dev->wrbuf_cur = (dev->wrbuf_cur + 1) % WRBUF_SIZE; + } + + dev->wrbuf_samplecnt++; +} + +void +nuked_generate_resampled(nuked_t *dev, int32_t *bufp) +{ + while (dev->samplecnt >= dev->rateratio) { + dev->oldsamples[0] = dev->samples[0]; + dev->oldsamples[1] = dev->samples[1]; + nuked_generate(dev, dev->samples); + dev->samplecnt -= dev->rateratio; + } + + bufp[0] = (int32_t) ((dev->oldsamples[0] * (dev->rateratio - dev->samplecnt) + + dev->samples[0] * dev->samplecnt) + / dev->rateratio); + bufp[1] = (int32_t) ((dev->oldsamples[1] * (dev->rateratio - dev->samplecnt) + + dev->samples[1] * dev->samplecnt) + / dev->rateratio); + + dev->samplecnt += 1 << RSM_FRAC; +} + +void +nuked_generate_stream(nuked_t *dev, int32_t *sndptr, uint32_t num) +{ + uint32_t i; + + for (i = 0; i < num; i++) { + nuked_generate_resampled(dev, sndptr); + sndptr += 2; + } +} + +void +nuked_init(nuked_t *dev, uint32_t samplerate) +{ + uint8_t i; + + memset(dev, 0x00, sizeof(nuked_t)); + + for (i = 0; i < 36; i++) { + dev->slot[i].dev = dev; + dev->slot[i].mod = &dev->zeromod; + dev->slot[i].eg_rout = 0x01ff; + dev->slot[i].eg_out = 0x01ff; + dev->slot[i].eg_gen = envelope_gen_num_release; + dev->slot[i].trem = (uint8_t *) &dev->zeromod; + dev->slot[i].slot_num = i; + } + + for (i = 0; i < 18; i++) { + dev->chan[i].slots[0] = &dev->slot[ch_slot[i]]; + dev->chan[i].slots[1] = &dev->slot[ch_slot[i] + 3]; + dev->slot[ch_slot[i]].chan = &dev->chan[i]; + dev->slot[ch_slot[i] + 3].chan = &dev->chan[i]; + + if ((i % 9) < 3) + dev->chan[i].pair = &dev->chan[i + 3]; + else if ((i % 9) < 6) + dev->chan[i].pair = &dev->chan[i - 3]; + + dev->chan[i].dev = dev; + dev->chan[i].out[0] = &dev->zeromod; + dev->chan[i].out[1] = &dev->zeromod; + dev->chan[i].out[2] = &dev->zeromod; + dev->chan[i].out[3] = &dev->zeromod; + dev->chan[i].chtype = ch_2op; + dev->chan[i].cha = 0xffff; + dev->chan[i].chb = 0xffff; + dev->chan[i].ch_num = i; + + channel_setup_alg(&dev->chan[i]); + } + + dev->noise = 1; + dev->rateratio = (samplerate << RSM_FRAC) / 49716; + dev->tremoloshift = 4; + dev->vibshift = 1; +} + +static void +nuked_timer_tick(nuked_drv_t *dev, int tmr) +{ + dev->timer_cur_count[tmr] = (dev->timer_cur_count[tmr] + 1) & 0xff; + + nuked_log("Ticking timer %i, count now %02X...\n", tmr, dev->timer_cur_count[tmr]); + + if (dev->timer_cur_count[tmr] == 0x00) { + dev->status |= ((STAT_TMR1_OVER >> tmr) & ~dev->timer_ctrl); + dev->timer_cur_count[tmr] = dev->timer_count[tmr]; + + nuked_log("Count wrapped around to zero, reloading timer %i (%02X), status = %02X...\n", tmr, (STAT_TMR1_OVER >> tmr), dev->status); + } + + timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); +} + +static void +nuked_timer_control(nuked_drv_t *dev, int tmr, int start) +{ + timer_on_auto(&dev->timers[tmr], 0.0); + + if (start) { + nuked_log("Loading timer %i count: %02X = %02X\n", tmr, dev->timer_cur_count[tmr], dev->timer_count[tmr]); + dev->timer_cur_count[tmr] = dev->timer_count[tmr]; + if (dev->flags & FLAG_OPL3) + nuked_timer_tick(dev, tmr); /* Per the YMF 262 datasheet, OPL3 starts counting immediately, unlike OPL2. */ + else + timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); + } else { + nuked_log("Timer %i stopped\n", tmr); + if (tmr == 1) { + dev->status &= ~STAT_TMR2_OVER; + } else + dev->status &= ~STAT_TMR1_OVER; + } +} + +static void +nuked_timer_1(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + nuked_timer_tick(dev, 0); +} + +static void +nuked_timer_2(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + nuked_timer_tick(dev, 1); +} + +static void +nuked_drv_set_do_cycles(void *priv, int8_t do_cycles) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + + if (do_cycles) + dev->flags |= FLAG_CYCLES; + else + dev->flags &= ~FLAG_CYCLES; +} + +static void * +nuked_drv_init(const device_t *info) +{ + nuked_drv_t *dev = (nuked_drv_t *) calloc(1, sizeof(nuked_drv_t)); + dev->flags = FLAG_CYCLES; + if (info->local == FM_YMF262) + dev->flags |= FLAG_OPL3; + else + dev->status = 0x06; + + /* Initialize the NukedOPL object. */ + nuked_init(&dev->opl, 48000); + + timer_add(&dev->timers[0], nuked_timer_1, dev, 0); + timer_add(&dev->timers[1], nuked_timer_2, dev, 0); + + return dev; +} + +static void +nuked_drv_close(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + free(dev); +} + +static int32_t * +nuked_drv_update(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + + if (dev->pos >= sound_pos_global) + return dev->buffer; + + nuked_generate_stream(&dev->opl, + &dev->buffer[dev->pos * 2], + sound_pos_global - dev->pos); + + for (; dev->pos < sound_pos_global; dev->pos++) { + dev->buffer[dev->pos * 2] /= 2; + dev->buffer[(dev->pos * 2) + 1] /= 2; + } + + return dev->buffer; +} + +static uint8_t +nuked_drv_read(uint16_t port, void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + if (dev->flags & FLAG_CYCLES) + cycles -= ((int) (isa_timing * 8)); + + nuked_drv_update(dev); + + uint8_t ret = 0xff; + + if ((port & 0x0003) == 0x0000) { + ret = dev->status; + if (dev->status & STAT_TMR_OVER) + ret |= STAT_TMR_ANY; + } + + nuked_log("OPL statret = %02x, status = %02x\n", ret, dev->status); + + return ret; +} + +static void +nuked_drv_write(uint16_t port, uint8_t val, void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + nuked_drv_update(dev); + + if ((port & 0x0001) == 0x0001) { + nuked_write_reg_buffered(&dev->opl, dev->port, val); + + switch (dev->port) { + case 0x02: /* Timer 1 */ + dev->timer_count[0] = val; + nuked_log("Timer 0 count now: %i\n", dev->timer_count[0]); + break; + + case 0x03: /* Timer 2 */ + dev->timer_count[1] = val; + nuked_log("Timer 1 count now: %i\n", dev->timer_count[1]); + break; + + case 0x04: /* Timer control */ + if (val & CTRL_RESET) { + nuked_log("Resetting timer status...\n"); + dev->status &= ~STAT_TMR_OVER; + } else { + dev->timer_ctrl = val; + nuked_timer_control(dev, 0, val & CTRL_TMR1_START); + nuked_timer_control(dev, 1, val & CTRL_TMR2_START); + nuked_log("Status mask now %02X (val = %02X)\n", (val & ~CTRL_TMR_MASK) & CTRL_TMR_MASK, val); + } + break; + } + } else { + dev->port = nuked_write_addr(&dev->opl, port, val) & 0x01ff; + + if (!(dev->flags & FLAG_OPL3)) + dev->port &= 0x00ff; + } +} + +static void +nuked_drv_reset_buffer(void *priv) { + nuked_drv_t *dev = (nuked_drv_t *)priv; + + dev->pos = 0; +} + +const device_t ym3812_nuked_device = { + .name = "Yamaha YM3812 OPL2 (NUKED)", + .internal_name = "ym3812_nuked", + .flags = 0, + .local = FM_YM3812, + .init = nuked_drv_init, + .close = nuked_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ymf262_nuked_device = { + .name = "Yamaha YMF262 OPL3 (NUKED)", + .internal_name = "ymf262_nuked", + .flags = 0, + .local = FM_YMF262, + .init = nuked_drv_init, + .close = nuked_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const fm_drv_t nuked_opl_drv = { + &nuked_drv_read, + &nuked_drv_write, + &nuked_drv_update, + &nuked_drv_reset_buffer, + &nuked_drv_set_do_cycles, + NULL, +}; \ No newline at end of file diff --git a/src/sound/snd_opl_ymfm.cpp b/src/sound/snd_opl_ymfm.cpp new file mode 100644 index 000000000..28ea7a621 --- /dev/null +++ b/src/sound/snd_opl_ymfm.cpp @@ -0,0 +1,374 @@ +/* + * 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. + * + * Interface to the YMFM emulator. + * + * + * Authors: Adrien Moulin, + * + * Copyright 2022 Adrien Moulin. + */ + +#include +#include +#include +#include +#include "ymfm/ymfm_opl.h" + +extern "C" { +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/sound.h> +#include <86box/snd_opl.h> +} + +#define RSM_FRAC 10 + +enum { + FLAG_CYCLES = (1 << 0) +}; + +class YMFMChipBase +{ +public: + YMFMChipBase(uint32_t clock, fm_type type, uint32_t samplerate) + : m_buf_pos(0), m_flags(0), m_type(type) + { + memset(m_buffer, 0, sizeof(m_buffer)); + } + + virtual ~YMFMChipBase() + { + } + + fm_type type() const { return m_type; } + int8_t flags() const { return m_flags; } + void set_do_cycles(int8_t do_cycles) { do_cycles ? m_flags |= FLAG_CYCLES : m_flags &= ~FLAG_CYCLES; } + int32_t *buffer() const { return (int32_t *)m_buffer; } + void reset_buffer() { m_buf_pos = 0; } + + virtual uint32_t sample_rate() const = 0; + + virtual void write(uint16_t addr, uint8_t data) = 0; + virtual void generate(int32_t *data, uint32_t num_samples) = 0; + virtual void generate_resampled(int32_t *data, uint32_t num_samples) = 0; + virtual int32_t * update() = 0; + virtual uint8_t read(uint16_t addr) = 0; + +protected: + int32_t m_buffer[SOUNDBUFLEN * 2]; + uint32_t m_buf_pos; + int8_t m_flags; + fm_type m_type; +}; + +template +class YMFMChip : public YMFMChipBase, public ymfm::ymfm_interface +{ +public: + YMFMChip(uint32_t clock, fm_type type, uint32_t samplerate) + : YMFMChipBase(clock, type, samplerate) + , m_chip(*this) + , m_clock(clock) + , m_samplecnt(0) + { + memset(m_samples, 0, sizeof(m_samples)); + memset(m_oldsamples, 0, sizeof(m_oldsamples)); + m_rateratio = (samplerate << RSM_FRAC) / m_chip.sample_rate(m_clock); + m_clock_us = 1000000 / (double) m_clock; + m_subtract[0] = 80.0; + m_subtract[1] = 320.0; + m_type = type; + + timer_add(&m_timers[0], YMFMChip::timer1, this, 0); + timer_add(&m_timers[1], YMFMChip::timer2, this, 0); + } + + virtual uint32_t sample_rate() const override + { + return m_chip.sample_rate(m_clock); + } + + virtual void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) override + { + if (tnum > 1) + return; + + pc_timer_t *timer = &m_timers[tnum]; + if (duration_in_clocks < 0) + timer_stop(timer); + else { + double period = m_clock_us * duration_in_clocks; + if (period < m_subtract[tnum]) + m_engine->engine_timer_expired(tnum); + else + timer_on_auto(timer, period); + } + } + + virtual void generate(int32_t *data, uint32_t num_samples) override + { + for (uint32_t i = 0; i < num_samples; i++) { + m_chip.generate(&m_output); + if (ChipType::OUTPUTS == 1) { + *data++ = m_output.data[0]; + *data++ = m_output.data[0]; + } else { + *data++ = m_output.data[0]; + *data++ = m_output.data[1 % ChipType::OUTPUTS]; + } + } + } + +virtual void generate_resampled(int32_t *data, uint32_t num_samples) override + { + for (uint32_t i = 0; i < num_samples; i++) { + while (m_samplecnt >= m_rateratio) { + m_oldsamples[0] = m_samples[0]; + m_oldsamples[1] = m_samples[1]; + m_chip.generate(&m_output); + if (ChipType::OUTPUTS == 1) { + m_samples[0] = m_output.data[0]; + m_samples[1] = m_output.data[0]; + } else { + m_samples[0] = m_output.data[0]; + m_samples[1] = m_output.data[1 % ChipType::OUTPUTS]; + } + m_samplecnt -= m_rateratio; + } + + *data++ = ((int32_t) ((m_oldsamples[0] * (m_rateratio - m_samplecnt) + + m_samples[0] * m_samplecnt) + / m_rateratio)); + *data++ = ((int32_t) ((m_oldsamples[1] * (m_rateratio - m_samplecnt) + + m_samples[1] * m_samplecnt) + / m_rateratio)); + + m_samplecnt += 1 << RSM_FRAC; + } + } + + virtual int32_t *update() override + { + if (m_buf_pos >= sound_pos_global) + return m_buffer; + + generate_resampled(&m_buffer[m_buf_pos * 2], sound_pos_global - m_buf_pos); + + for (; m_buf_pos < sound_pos_global; m_buf_pos++) { + m_buffer[m_buf_pos * 2] /= 2; + m_buffer[(m_buf_pos * 2) + 1] /= 2; + } + + return m_buffer; + } + + virtual void write(uint16_t addr, uint8_t data) override + { + m_chip.write(addr, data); + } + + virtual uint8_t read(uint16_t addr) override + { + return m_chip.read(addr); + } + + virtual uint32_t get_special_flags(void) override + { + return ((m_type == FM_YMF262) || (m_type == FM_YMF289B)) ? 0x8000 : 0x0000; + } + + static void timer1(void *priv) + { + YMFMChip *drv = (YMFMChip *) priv; + drv->m_engine->engine_timer_expired(0); + } + + static void timer2(void *priv) + { + YMFMChip *drv = (YMFMChip *) priv; + drv->m_engine->engine_timer_expired(1); + } + +private: + ChipType m_chip; + uint32_t m_clock; + double m_clock_us, m_subtract[2]; + typename ChipType::output_data m_output; + pc_timer_t m_timers[2]; + + // Resampling + int32_t m_rateratio; + int32_t m_samplecnt; + int32_t m_oldsamples[2]; + int32_t m_samples[2]; +}; + +extern "C" +{ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include "cpu.h" +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/snd_opl.h> + +#ifdef ENABLE_OPL_LOG + +static void +ymfm_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +} +#else +# define ymfm_log(fmt, ...) +#endif + +static void * +ymfm_drv_init(const device_t *info) +{ + YMFMChipBase *fm; + + switch (info->local) { + case FM_YM3812: + default: + fm = (YMFMChipBase *) new YMFMChip(3579545, FM_YM3812, 48000); + break; + + case FM_YMF262: + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF262, 48000); + break; + + case FM_YMF289B: + fm = (YMFMChipBase *) new YMFMChip(33868800, FM_YMF289B, 48000); + break; + } + + fm->set_do_cycles(1); + + return fm; +} + +static void +ymfm_drv_close(void *priv) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + + if (drv != NULL) + delete(drv); +} + +static uint8_t +ymfm_drv_read(uint16_t port, void *priv) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + + if (drv->flags() & FLAG_CYCLES) { + cycles -= ((int) (isa_timing * 8)); + } + + uint8_t ret = drv->read(port); + drv->update(); + + ymfm_log("YMFM read port %04x, status = %02x\n", port, ret); + return ret; +} + +static void +ymfm_drv_write(uint16_t port, uint8_t val, void *priv) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + ymfm_log("YMFM write port %04x value = %02x\n", port, val); + drv->write(port, val); + drv->update(); +} + +static int32_t * +ymfm_drv_update(void *priv) { + YMFMChipBase *drv = (YMFMChipBase *) priv; + + return drv->update(); +} + +static void +ymfm_drv_reset_buffer(void *priv) { + YMFMChipBase *drv = (YMFMChipBase *) priv; + + drv->reset_buffer(); +} + +static void +ymfm_drv_set_do_cycles(void *priv, int8_t do_cycles) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + drv->set_do_cycles(do_cycles); +} + +const device_t ym3812_ymfm_device = { + .name = "Yamaha YM3812 OPL2 (YMFM)", + .internal_name = "ym3812_ymfm", + .flags = 0, + .local = FM_YM3812, + .init = ymfm_drv_init, + .close = ymfm_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ymf262_ymfm_device = { + .name = "Yamaha YMF262 OPL3 (YMFM)", + .internal_name = "ymf262_ymfm", + .flags = 0, + .local = FM_YMF262, + .init = ymfm_drv_init, + .close = ymfm_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ymf289b_ymfm_device = { + .name = "Yamaha YMF289B OPL3-L (YMFM)", + .internal_name = "ymf289b_ymfm", + .flags = 0, + .local = FM_YMF289B, + .init = ymfm_drv_init, + .close = ymfm_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const fm_drv_t ymfm_drv { + &ymfm_drv_read, + &ymfm_drv_write, + &ymfm_drv_update, + &ymfm_drv_reset_buffer, + &ymfm_drv_set_do_cycles, + NULL, +}; + +} diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 8eccf1f6d..1662598c9 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -1,766 +1,757 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H -#include <86box/86box.h> + #include "cpu.h" +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.h> +#include <86box/filters.h> #include <86box/io.h> #include <86box/pic.h> #include <86box/timer.h> #include <86box/pit.h> -#include <86box/dma.h> -#include <86box/device.h> -#include <86box/sound.h> -#include <86box/filters.h> #include <86box/snd_mpu401.h> +#include <86box/sound.h> #include <86box/snd_opl.h> +#include <86box/snd_sb.h> #include <86box/snd_sb_dsp.h> - /* Original PAS uses 2 x OPL2 PIT - sample rate/count LMC835N/LMC1982 - mixer YM3802 - MIDI Control System - + 9A01 - IO base base >> 2 - + All below + IO base B89 - interrupt status / clear bit 2 - sample rate bit 3 - PCM bit 4 - MIDI - + B88 - Audio mixer control register - + B8A - Audio filter control bit 5 - mute? - + B8B - interrupt mask / board ID bits 5-7 - board ID (read only on PAS16) F88 - PCM data (low) - + F89 - PCM data (high) - + F8A - PCM control? bit 4 - input/output select (1 = output) bit 5 - mono/stereo select bit 6 - PCM enable - + 1388-138b - PIT clocked at 1193180 Hz 1388 - sample rate 1389 - sample count - - 178b - + + 178b - 2789 - board revision - + 8389 - bit 2 - 8/16 bit - + BF88 - wait states - + EF8B - bit 3 - 16 bits okay ? - - F388 - + + F388 - bit 6 - joystick enable - + F389 - bits 0-2 - DMA - + F38A - bits 0-3 - IRQ F788 - bit 1 - SB emulation bit 0 - MPU401 emulation - + F789 - SB base addr bits 0-3 - addr bits 4-7 - + FB8A - SB IRQ/DMA bits 3-5 - IRQ bits 6-7 - DMA - + FF88 - board model 3 = PAS16 */ -typedef struct pas16_t -{ - uint16_t base; - - int irq, dma; - - uint8_t audiofilt; - - uint8_t audio_mixer; - - uint8_t compat, compat_base; - - uint8_t enhancedscsi; - - uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4; - - uint8_t irq_stat, irq_ena; - - uint8_t pcm_ctrl; - uint16_t pcm_dat; +typedef struct pas16_t { + uint16_t base; - uint16_t pcm_dat_l, pcm_dat_r; - - uint8_t sb_irqdma; - - int stereo_lr; - - uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4; - - struct - { - uint32_t l[3]; - int64_t c[3]; - pc_timer_t timer[3]; - uint8_t m[3]; - uint8_t ctrl, ctrls[2]; - int wp, rm[3], wm[3]; - uint16_t rl[3]; - int thit[3]; - int delay[3]; - int rereadlatch[3]; - int64_t enable[3]; - } pit; + int irq, dma; - opl_t opl; - sb_dsp_t dsp; + uint8_t audiofilt; - int16_t pcm_buffer[2][SOUNDBUFLEN]; + uint8_t audio_mixer; - int pos; + uint8_t compat, compat_base; + + uint8_t enhancedscsi; + + uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4; + + uint8_t irq_stat, irq_ena; + + uint8_t pcm_ctrl; + uint16_t pcm_dat; + + uint16_t pcm_dat_l, pcm_dat_r; + + uint8_t sb_irqdma; + + int stereo_lr; + + uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4; + + struct + { + uint32_t l[3]; + int64_t c[3]; + pc_timer_t timer[3]; + uint8_t m[3]; + uint8_t ctrl, ctrls[2]; + int wp, rm[3], wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int64_t enable[3]; + } pit; + + fm_drv_t opl; + sb_dsp_t dsp; + + int16_t pcm_buffer[2][SOUNDBUFLEN]; + + int pos; } pas16_t; static uint8_t pas16_pit_in(uint16_t port, void *priv); -static void pas16_pit_out(uint16_t port, uint8_t val, void *priv); -static void pas16_update(pas16_t *pas16); +static void pas16_pit_out(uint16_t port, uint8_t val, void *priv); +static void pas16_update(pas16_t *pas16); -static int pas16_dmas[8] = {4, 1, 2, 3, 0, 5, 6, 7}; -static int pas16_irqs[16] = {0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0}; -static int pas16_sb_irqs[8] = {0, 2, 3, 5, 7, 10, 11, 12}; -static int pas16_sb_dmas[8] = {0, 1, 2, 3}; +static int pas16_dmas[8] = { 4, 1, 2, 3, 0, 5, 6, 7 }; +static int pas16_irqs[16] = { 0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0 }; +static int pas16_sb_irqs[8] = { 0, 2, 3, 5, 7, 10, 11, 12 }; +static int pas16_sb_dmas[8] = { 0, 1, 2, 3 }; -enum -{ - PAS16_INT_SAMP = 0x04, - PAS16_INT_PCM = 0x08 +enum { + PAS16_INT_SAMP = 0x04, + PAS16_INT_PCM = 0x08 }; -enum -{ - PAS16_PCM_MONO = 0x20, - PAS16_PCM_ENA = 0x40 +enum { + PAS16_PCM_MONO = 0x20, + PAS16_PCM_ENA = 0x40 }; -enum -{ - PAS16_SC2_16BIT = 0x04, - PAS16_SC2_MSBINV = 0x10 +enum { + PAS16_SC2_16BIT = 0x04, + PAS16_SC2_MSBINV = 0x10 }; -enum -{ - PAS16_FILT_MUTE = 0x20 +enum { + PAS16_FILT_MUTE = 0x20 }; - #ifdef ENABLE_PAS16_LOG int pas16_do_log = ENABLE_PAS16_LOG; - static void pas16_log(const char *fmt, ...) { va_list ap; if (pas16_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define pas16_log(fmt, ...) +# define pas16_log(fmt, ...) #endif - -static uint8_t pas16_in(uint16_t port, void *p) +static uint8_t +pas16_in(uint16_t port, void *p) { - pas16_t *pas16 = (pas16_t *)p; - uint8_t temp = 0xff; - switch ((port - pas16->base) + 0x388) - { - case 0x388: case 0x389: case 0x38a: case 0x38b: - temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl); - break; - - case 0xb88: - temp = pas16->audio_mixer; - break; - - case 0xb89: - temp = pas16->irq_stat; - break; - - case 0xb8a: - temp = pas16->audiofilt; - break; - - case 0xb8b: - temp = (pas16->irq_ena & ~0xe0) | 0x20; - break; - - case 0xf8a: - temp = pas16->pcm_ctrl; - break; - - case 0x1388: case 0x1389: case 0x138a: case 0x138b: - temp = pas16_pit_in(port, pas16); - break; + pas16_t *pas16 = (pas16_t *) p; + uint8_t temp = 0xff; + switch ((port - pas16->base) + 0x388) { + case 0x388: + case 0x389: + case 0x38a: + case 0x38b: + temp = pas16->opl.read((port - pas16->base) + 0x388, pas16->opl.priv); + break; - case 0x2789: /*Board revision*/ - temp = 0; - break; - - case 0x7f89: - temp = pas16->enhancedscsi & ~1; - break; - - case 0x8388: - temp = pas16->sys_conf_1; - break; - case 0x8389: - temp = pas16->sys_conf_2; - break; - case 0x838b: - temp = pas16->sys_conf_3; - break; - case 0x838c: - temp = pas16->sys_conf_4; - break; - - case 0xef8b: - temp = 0x0c; - break; + case 0xb88: + temp = pas16->audio_mixer; + break; - case 0xf388: - temp = pas16->io_conf_1; - break; - case 0xf389: - temp = pas16->io_conf_2; - break; - case 0xf38b: - temp = pas16->io_conf_3; - break; - case 0xf38c: - temp = pas16->io_conf_4; - break; + case 0xb89: + temp = pas16->irq_stat; + break; - case 0xf788: - temp = pas16->compat; - break; - case 0xf789: - temp = pas16->compat_base; - break; - - case 0xfb8a: - temp = pas16->sb_irqdma; - break; + case 0xb8a: + temp = pas16->audiofilt; + break; - case 0xff88: /*Board model*/ - temp = 4; /*PAS16*/ - break; - case 0xff8b: /*Master mode read*/ - temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ - break; - } - pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); - return temp; + case 0xb8b: + temp = (pas16->irq_ena & ~0xe0) | 0x20; + break; + + case 0xf8a: + temp = pas16->pcm_ctrl; + break; + + case 0x1388: + case 0x1389: + case 0x138a: + case 0x138b: + temp = pas16_pit_in(port, pas16); + break; + + case 0x2789: /*Board revision*/ + temp = 0; + break; + + case 0x7f89: + temp = pas16->enhancedscsi & ~1; + break; + + case 0x8388: + temp = pas16->sys_conf_1; + break; + case 0x8389: + temp = pas16->sys_conf_2; + break; + case 0x838b: + temp = pas16->sys_conf_3; + break; + case 0x838c: + temp = pas16->sys_conf_4; + break; + + case 0xef8b: + temp = 0x0c; + break; + + case 0xf388: + temp = pas16->io_conf_1; + break; + case 0xf389: + temp = pas16->io_conf_2; + break; + case 0xf38b: + temp = pas16->io_conf_3; + break; + case 0xf38c: + temp = pas16->io_conf_4; + break; + + case 0xf788: + temp = pas16->compat; + break; + case 0xf789: + temp = pas16->compat_base; + break; + + case 0xfb8a: + temp = pas16->sb_irqdma; + break; + + case 0xff88: /*Board model*/ + temp = 4; /*PAS16*/ + break; + case 0xff8b: /*Master mode read*/ + temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ + break; + } + pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS, cpu_state.pc); + return temp; } -static void pas16_out(uint16_t port, uint8_t val, void *p) +static void +pas16_out(uint16_t port, uint8_t val, void *p) { - pas16_t *pas16 = (pas16_t *)p; - pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); - switch ((port - pas16->base) + 0x388) - { - case 0x388: case 0x389: case 0x38a: case 0x38b: - opl3_write((port - pas16->base) + 0x388, val, &pas16->opl); - break; - - case 0xb88: - pas16->audio_mixer = val; - break; + pas16_t *pas16 = (pas16_t *) p; + pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS, cpu_state.pc); + switch ((port - pas16->base) + 0x388) { + case 0x388: + case 0x389: + case 0x38a: + case 0x38b: + pas16->opl.write((port - pas16->base) + 0x388, val, pas16->opl.priv); + break; - case 0xb89: - pas16->irq_stat &= ~val; - break; + case 0xb88: + pas16->audio_mixer = val; + break; - case 0xb8a: - pas16_update(pas16); - pas16->audiofilt = val; - break; + case 0xb89: + pas16->irq_stat &= ~val; + break; - case 0xb8b: - pas16->irq_ena = val; - break; + case 0xb8a: + pas16_update(pas16); + pas16->audiofilt = val; + break; - case 0xf88: - pas16_update(pas16); - pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val; - break; - case 0xf89: - pas16_update(pas16); - pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8); - break; - case 0xf8a: - if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/ - pas16->stereo_lr = 0; - pas16->pcm_ctrl = val; - break; - - case 0x1388: case 0x1389: case 0x138a: case 0x138b: - pas16_pit_out(port, val, pas16); - break; + case 0xb8b: + pas16->irq_ena = val; + break; - case 0x7f89: - pas16->enhancedscsi = val; - break; + case 0xf88: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val; + break; + case 0xf89: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8); + break; + case 0xf8a: + if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/ + pas16->stereo_lr = 0; + pas16->pcm_ctrl = val; + break; - case 0x8388: - pas16->sys_conf_1 = val; - break; - case 0x8389: - pas16->sys_conf_2 = val; - break; - case 0x838a: - pas16->sys_conf_3 = val; - break; - case 0x838b: - pas16->sys_conf_4 = val; - break; + case 0x1388: + case 0x1389: + case 0x138a: + case 0x138b: + pas16_pit_out(port, val, pas16); + break; - case 0xf388: - pas16->io_conf_1 = val; - break; - case 0xf389: - pas16->io_conf_2 = val; - pas16->dma = pas16_dmas[val & 0x7]; - pas16_log("pas16_out : set PAS DMA %i\n", pas16->dma); - break; - case 0xf38a: - pas16->io_conf_3 = val; - pas16->irq = pas16_irqs[val & 0xf]; - pas16_log("pas16_out : set PAS IRQ %i\n", pas16->irq); - break; - case 0xf38b: - pas16->io_conf_4 = val; - break; + case 0x7f89: + pas16->enhancedscsi = val; + break; - case 0xf788: - pas16->compat = val; - if (pas16->compat & 0x02) - sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); - else - sb_dsp_setaddr(&pas16->dsp, 0); - break; - case 0xf789: - pas16->compat_base = val; - if (pas16->compat & 0x02) - sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); - break; - - case 0xfb8a: - pas16->sb_irqdma = val; - sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]); - sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]); - pas16_log("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]); - break; - - default: - pas16_log("pas16_out : unknown %04X\n", port); - } - if (cpu_state.pc == 0x80048CF3) - { - if (output) - fatal("here\n"); - output = 3; - } + case 0x8388: + pas16->sys_conf_1 = val; + break; + case 0x8389: + pas16->sys_conf_2 = val; + break; + case 0x838a: + pas16->sys_conf_3 = val; + break; + case 0x838b: + pas16->sys_conf_4 = val; + break; + + case 0xf388: + pas16->io_conf_1 = val; + break; + case 0xf389: + pas16->io_conf_2 = val; + pas16->dma = pas16_dmas[val & 0x7]; + pas16_log("pas16_out : set PAS DMA %i\n", pas16->dma); + break; + case 0xf38a: + pas16->io_conf_3 = val; + pas16->irq = pas16_irqs[val & 0xf]; + pas16_log("pas16_out : set PAS IRQ %i\n", pas16->irq); + break; + case 0xf38b: + pas16->io_conf_4 = val; + break; + + case 0xf788: + pas16->compat = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + else + sb_dsp_setaddr(&pas16->dsp, 0); + break; + case 0xf789: + pas16->compat_base = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + break; + + case 0xfb8a: + pas16->sb_irqdma = val; + sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]); + sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]); + pas16_log("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]); + break; + + default: + pas16_log("pas16_out : unknown %04X\n", port); + } +#if 0 + if (cpu_state.pc == 0x80048CF3) { + if (output) + fatal("here\n"); + output = 3; + } +#endif } -static void pas16_pit_out(uint16_t port, uint8_t val, void *p) +static void +pas16_pit_out(uint16_t port, uint8_t val, void *p) { - pas16_t *pas16 = (pas16_t *)p; - int t; - switch (port & 3) - { - case 3: /*CTRL*/ - if ((val & 0xC0) == 0xC0) - { - if (!(val & 0x20)) - { - if (val & 2) pas16->pit.rl[0] = timer_get_remaining_u64(&pit.timer[0]) / PITCONST;; - if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; - if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; - } - return; + pas16_t *pas16 = (pas16_t *) p; + int t; + switch (port & 3) { + case 3: /*CTRL*/ + if ((val & 0xC0) == 0xC0) { + if (!(val & 0x20)) { + if (val & 2) + pas16->pit.rl[0] = timer_get_remaining_u64(&pas16->pit.timer[0]) / PITCONST; + ; + if (val & 4) + pas16->pit.rl[1] = pas16->pit.c[1]; + if (val & 8) + pas16->pit.rl[2] = pas16->pit.c[2]; } - t = val >> 6; - pas16->pit.ctrls[t] = pas16->pit.ctrl = val; - if (t == 3) - { - printf("Bad PIT reg select\n"); - return; + return; + } + t = val >> 6; + pas16->pit.ctrls[t] = pas16->pit.ctrl = val; + if (t == 3) { + printf("Bad PIT reg select\n"); + return; + } + if (!(pas16->pit.ctrl & 0x30)) { + if (!t) + pas16->pit.rl[t] = timer_get_remaining_u64(&pas16->pit.timer[t]) / PITCONST; + else { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] < 0) + pas16->pit.rl[t] = 0; } - if (!(pas16->pit.ctrl & 0x30)) - { - if (!t) - pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; - else - { - pas16->pit.rl[t] = pas16->pit.c[t]; - if (pas16->pit.c[t] < 0) - pas16->pit.rl[t] = 0; - } - pas16->pit.ctrl |= 0x30; - pas16->pit.rereadlatch[t] = 0; - pas16->pit.rm[t] = 3; + pas16->pit.ctrl |= 0x30; + pas16->pit.rereadlatch[t] = 0; + pas16->pit.rm[t] = 3; + } else { + pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3; + pas16->pit.m[t] = (val >> 1) & 7; + if (pas16->pit.m[t] > 5) + pas16->pit.m[t] &= 3; + if (!pas16->pit.rm[t]) { + pas16->pit.rm[t] = 3; + if (!t) + pas16->pit.rl[t] = timer_get_remaining_u64(&pas16->pit.timer[t]) / PITCONST; + else + pas16->pit.rl[t] = pas16->pit.c[t]; } - else - { - pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3; - pas16->pit.m[t] = (val >> 1) & 7; - if (pas16->pit.m[t] > 5) - pas16->pit.m[t] &= 3; - if (!pas16->pit.rm[t]) - { - pas16->pit.rm[t] = 3; - if (!t) - pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; - else - pas16->pit.rl[t] = pas16->pit.c[t]; - } - pas16->pit.rereadlatch[t] = 1; - } - pas16->pit.wp = 0; - pas16->pit.thit[t] = 0; - break; - case 0: case 1: case 2: /*Timers*/ - t = port & 3; - switch (pas16->pit.wm[t]) - { - case 1: - pas16->pit.l[t] = val; - pas16->pit.thit[t] = 0; - pas16->pit.c[t] = pas16->pit.l[t]; - if (!t) - timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); - pas16->pit.enable[t] = 1; - break; - case 2: - pas16->pit.l[t] = val << 8; - pas16->pit.thit[t] = 0; - pas16->pit.c[t] = pas16->pit.l[t]; - if (!t) - timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); - pas16->pit.enable[t] = 1; - break; - case 0: - pas16->pit.l[t] &= 0xFF; - pas16->pit.l[t] |= (val << 8); - pas16->pit.c[t] = pas16->pit.l[t]; - if (!t) - timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); - pas16->pit.thit[t] = 0; - pas16->pit.wm[t] = 3; - pas16->pit.enable[t] = 1; - break; - case 3: - pas16->pit.l[t] &= 0xFF00; - pas16->pit.l[t] |= val; - pas16->pit.wm[t] = 0; - break; - } - if (!pas16->pit.l[t]) - { - pas16->pit.l[t] |= 0x10000; - pas16->pit.c[t] = pas16->pit.l[t]; - if (!t) - timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); - } - break; - } + pas16->pit.rereadlatch[t] = 1; + } + pas16->pit.wp = 0; + pas16->pit.thit[t] = 0; + break; + case 0: + case 1: + case 2: /*Timers*/ + t = port & 3; + switch (pas16->pit.wm[t]) { + case 1: + pas16->pit.l[t] = val; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); + pas16->pit.enable[t] = 1; + break; + case 2: + pas16->pit.l[t] = val << 8; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); + pas16->pit.enable[t] = 1; + break; + case 0: + pas16->pit.l[t] &= 0xFF; + pas16->pit.l[t] |= (val << 8); + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); + pas16->pit.thit[t] = 0; + pas16->pit.wm[t] = 3; + pas16->pit.enable[t] = 1; + break; + case 3: + pas16->pit.l[t] &= 0xFF00; + pas16->pit.l[t] |= val; + pas16->pit.wm[t] = 0; + break; + } + if (!pas16->pit.l[t]) { + pas16->pit.l[t] |= 0x10000; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); + } + break; + } } -static uint8_t pas16_pit_in(uint16_t port, void *p) +static uint8_t +pas16_pit_in(uint16_t port, void *p) { - pas16_t *pas16 = (pas16_t *)p; - uint8_t temp = 0xff; - int t = port & 3; - switch (port & 3) - { - case 0: case 1: case 2: /*Timers*/ - if (pas16->pit.rereadlatch[t]) - { - pas16->pit.rereadlatch[t] = 0; - if (!t) - { - pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; - if ((timer_get_remaining_u64(&pit.timer[t]) / PITCONST) > 65536) - pas16->pit.rl[t] = 0xFFFF; - } - else - { - pas16->pit.rl[t] = pas16->pit.c[t]; - if (pas16->pit.c[t] > 65536) - pas16->pit.rl[t] = 0xFFFF; - } + pas16_t *pas16 = (pas16_t *) p; + uint8_t temp = 0xff; + int t = port & 3; + switch (port & 3) { + case 0: + case 1: + case 2: /*Timers*/ + if (pas16->pit.rereadlatch[t]) { + pas16->pit.rereadlatch[t] = 0; + if (!t) { + pas16->pit.rl[t] = timer_get_remaining_u64(&pas16->pit.timer[t]) / PITCONST; + if ((timer_get_remaining_u64(&pas16->pit.timer[t]) / PITCONST) > 65536) + pas16->pit.rl[t] = 0xFFFF; + } else { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] > 65536) + pas16->pit.rl[t] = 0xFFFF; } - switch (pas16->pit.rm[t]) - { - case 0: - temp = pas16->pit.rl[t] >> 8; - pas16->pit.rm[t] = 3; - pas16->pit.rereadlatch[t] = 1; - break; - case 1: - temp = (pas16->pit.rl[t]) & 0xFF; - pas16->pit.rereadlatch[t] = 1; - break; - case 2: - temp = (pas16->pit.rl[t]) >> 8; - pas16->pit.rereadlatch[t] = 1; - break; - case 3: - temp = (pas16->pit.rl[t]) & 0xFF; - if (pas16->pit.m[t] & 0x80) pas16->pit.m[t] &= 7; - else pas16->pit.rm[t] = 0; - break; - } - break; - case 3: /*Control*/ - temp = pas16->pit.ctrl; - break; - } - return temp; + } + switch (pas16->pit.rm[t]) { + case 0: + temp = pas16->pit.rl[t] >> 8; + pas16->pit.rm[t] = 3; + pas16->pit.rereadlatch[t] = 1; + break; + case 1: + temp = (pas16->pit.rl[t]) & 0xFF; + pas16->pit.rereadlatch[t] = 1; + break; + case 2: + temp = (pas16->pit.rl[t]) >> 8; + pas16->pit.rereadlatch[t] = 1; + break; + case 3: + temp = (pas16->pit.rl[t]) & 0xFF; + if (pas16->pit.m[t] & 0x80) + pas16->pit.m[t] &= 7; + else + pas16->pit.rm[t] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pas16->pit.ctrl; + break; + } + return temp; } -static uint8_t pas16_readdma(pas16_t *pas16) +static uint8_t +pas16_readdma(pas16_t *pas16) { - return dma_channel_read(pas16->dma); + return dma_channel_read(pas16->dma); } -static void pas16_pcm_poll(void *p) +static void +pas16_pcm_poll(void *p) { - pas16_t *pas16 = (pas16_t *)p; - - pas16_update(pas16); - if (pas16->pit.m[0] & 2) - { - if (pas16->pit.l[0]) - timer_advance_u64(&pas16->pit.timer[0], pas16->pit.l[0] * PITCONST); - else - timer_advance_u64(&pas16->pit.timer[0], 0x10000 * PITCONST); - } + pas16_t *pas16 = (pas16_t *) p; + + pas16_update(pas16); + if (pas16->pit.m[0] & 2) { + if (pas16->pit.l[0]) + timer_advance_u64(&pas16->pit.timer[0], pas16->pit.l[0] * PITCONST); else - { - pas16->pit.enable[0] = 0; - } + timer_advance_u64(&pas16->pit.timer[0], 0x10000 * PITCONST); + } else { + pas16->pit.enable[0] = 0; + } - pas16->irq_stat |= PAS16_INT_SAMP; - if (pas16->irq_ena & PAS16_INT_SAMP) + pas16->irq_stat |= PAS16_INT_SAMP; + if (pas16->irq_ena & PAS16_INT_SAMP) + picint(1 << pas16->irq); + + /*Update sample rate counter*/ + if (pas16->pit.enable[1]) { + if (pas16->pcm_ctrl & PAS16_PCM_ENA) { + uint16_t temp; + + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) { + temp = pas16_readdma(pas16) << 8; + temp |= pas16_readdma(pas16); + } else + temp = (pas16_readdma(pas16) ^ 0x80) << 8; + + if (pas16->sys_conf_2 & PAS16_SC2_MSBINV) + temp ^= 0x8000; + if (pas16->pcm_ctrl & PAS16_PCM_MONO) + pas16->pcm_dat_l = pas16->pcm_dat_r = temp; + else { + if (pas16->stereo_lr) + pas16->pcm_dat_r = temp; + else + pas16->pcm_dat_l = temp; + + pas16->stereo_lr = !pas16->stereo_lr; + } + } + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + pas16->pit.c[1] -= 2; + else + pas16->pit.c[1]--; + if (pas16->pit.c[1] == 0) { + if (pas16->pit.m[1] & 2) { + if (pas16->pit.l[1]) + pas16->pit.c[1] += pas16->pit.l[1]; + else + pas16->pit.c[1] += 0x10000; + } else { + pas16->pit.c[1] = -1; + pas16->pit.enable[1] = 0; + } + + pas16->irq_stat |= PAS16_INT_PCM; + if (pas16->irq_ena & PAS16_INT_PCM) { + pas16_log("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq); picint(1 << pas16->irq); - - /*Update sample rate counter*/ - if (pas16->pit.enable[1]) - { - if (pas16->pcm_ctrl & PAS16_PCM_ENA) - { - uint16_t temp; - - if (pas16->sys_conf_2 & PAS16_SC2_16BIT) - { - temp = pas16_readdma(pas16) << 8; - temp |= pas16_readdma(pas16); - } - else - temp = (pas16_readdma(pas16) ^ 0x80) << 8; - - if (pas16->sys_conf_2 & PAS16_SC2_MSBINV) - temp ^= 0x8000; - if (pas16->pcm_ctrl & PAS16_PCM_MONO) - pas16->pcm_dat_l = pas16->pcm_dat_r = temp; - else - { - if (pas16->stereo_lr) - pas16->pcm_dat_r = temp; - else - pas16->pcm_dat_l = temp; - - pas16->stereo_lr = !pas16->stereo_lr; - } - } - if (pas16->sys_conf_2 & PAS16_SC2_16BIT) - pas16->pit.c[1] -= 2; - else - pas16->pit.c[1]--; - if (pas16->pit.c[1] == 0) - { - if (pas16->pit.m[1] & 2) - { - if (pas16->pit.l[1]) - pas16->pit.c[1] += pas16->pit.l[1]; - else - pas16->pit.c[1] += 0x10000; - } - else - { - pas16->pit.c[1] = -1; - pas16->pit.enable[1] = 0; - } - - pas16->irq_stat |= PAS16_INT_PCM; - if (pas16->irq_ena & PAS16_INT_PCM) - { - pas16_log("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq); - picint(1 << pas16->irq); - } - } + } } + } } -static void pas16_out_base(uint16_t port, uint8_t val, void *p) +static void +pas16_out_base(uint16_t port, uint8_t val, void *p) { - pas16_t *pas16 = (pas16_t *)p; + pas16_t *pas16 = (pas16_t *) p; - io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - - pas16->base = val << 2; - pas16_log("pas16_write_base : PAS16 base now at %04X\n", pas16->base); + io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); - io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + pas16->base = val << 2; + pas16_log("pas16_write_base : PAS16 base now at %04X\n", pas16->base); + + io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); } - -static void pas16_update(pas16_t *pas16) +static void +pas16_update(pas16_t *pas16) { - if (!(pas16->audiofilt & PAS16_FILT_MUTE)) - { - for (; pas16->pos < sound_pos_global; pas16->pos++) - { - pas16->pcm_buffer[0][pas16->pos] = 0; - pas16->pcm_buffer[1][pas16->pos] = 0; - } + if (!(pas16->audiofilt & PAS16_FILT_MUTE)) { + for (; pas16->pos < sound_pos_global; pas16->pos++) { + pas16->pcm_buffer[0][pas16->pos] = 0; + pas16->pcm_buffer[1][pas16->pos] = 0; } - else - { - for (; pas16->pos < sound_pos_global; pas16->pos++) - { - pas16->pcm_buffer[0][pas16->pos] = (int16_t)pas16->pcm_dat_l; - pas16->pcm_buffer[1][pas16->pos] = (int16_t)pas16->pcm_dat_r; - } + } else { + for (; pas16->pos < sound_pos_global; pas16->pos++) { + pas16->pcm_buffer[0][pas16->pos] = (int16_t) pas16->pcm_dat_l; + pas16->pcm_buffer[1][pas16->pos] = (int16_t) pas16->pcm_dat_r; } + } } -void pas16_get_buffer(int32_t *buffer, int len, void *p) +void +pas16_get_buffer(int32_t *buffer, int len, void *p) { - pas16_t *pas16 = (pas16_t *)p; - int c; + pas16_t *pas16 = (pas16_t *) p; + int c; - opl3_update2(&pas16->opl); - sb_dsp_update(&pas16->dsp); - pas16_update(pas16); - for (c = 0; c < len * 2; c++) - { - buffer[c] += pas16->opl.buffer[c]; - buffer[c] += (int16_t)(sb_iir(c & 1, (float)pas16->dsp.buffer[c]) / 1.3) / 2; - buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); - } + int32_t *opl_buf = pas16->opl.update(pas16->opl.priv); + sb_dsp_update(&pas16->dsp); + pas16_update(pas16); + for (c = 0; c < len * 2; c++) { + buffer[c] += opl_buf[c]; + buffer[c] += (int16_t) (sb_iir(0, c & 1, (double) pas16->dsp.buffer[c]) / 1.3) / 2; + buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); + } - pas16->pos = 0; - pas16->opl.pos = 0; - pas16->dsp.pos = 0; + pas16->pos = 0; + pas16->opl.reset_buffer(pas16->opl.priv); + pas16->dsp.pos = 0; } - -static void *pas16_init(const device_t *info) +static void * +pas16_init(const device_t *info) { - pas16_t *pas16 = malloc(sizeof(pas16_t)); - memset(pas16, 0, sizeof(pas16_t)); + pas16_t *pas16 = malloc(sizeof(pas16_t)); + memset(pas16, 0, sizeof(pas16_t)); - opl3_init(&pas16->opl); - sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16); + fm_driver_get(FM_YMF262, &pas16->opl); + sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16); - io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); - - timer_add(&pas16->pit.timer[0], pas16_pcm_poll, pas16, 0); - - sound_add_handler(pas16_get_buffer, pas16); - - return pas16; + io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); + + timer_add(&pas16->pit.timer[0], pas16_pcm_poll, pas16, 0); + + sound_add_handler(pas16_get_buffer, pas16); + + return pas16; } -static void pas16_close(void *p) +static void +pas16_close(void *p) { - pas16_t *pas16 = (pas16_t *)p; - - free(pas16); + pas16_t *pas16 = (pas16_t *) p; + + free(pas16); } -const device_t pas16_device = -{ - "Pro Audio Spectrum 16", - DEVICE_ISA | DEVICE_NOT_WORKING, - 0, - pas16_init, pas16_close, NULL, - NULL, NULL, NULL, - NULL +const device_t pas16_device = { + .name = "Pro Audio Spectrum 16", + .internal_name = "pas16", + .flags = DEVICE_ISA | DEVICE_NOT_WORKING, + .local = 0, + .init = pas16_init, + .close = pas16_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sound/snd_ps1.c b/src/sound/snd_ps1.c new file mode 100644 index 000000000..308d01589 --- /dev/null +++ b/src/sound/snd_ps1.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/sound.h> +#include <86box/snd_sn76489.h> +#include <86box/timer.h> + +typedef struct { + sn76489_t sn76489; + uint8_t status, ctrl; + uint64_t timer_latch; + pc_timer_t timer_count; + int timer_enable; + uint8_t fifo[2048]; + int fifo_read_idx, fifo_write_idx; + int fifo_threshold; + uint8_t dac_val; + int16_t buffer[SOUNDBUFLEN]; + int pos; +} ps1snd_t; + +static void +ps1snd_update_irq_status(ps1snd_t *snd) +{ + if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01)) + picint(1 << 7); + else + picintc(1 << 7); +} + +static uint8_t +ps1snd_read(uint16_t port, void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *) priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* ADC data */ + ps1snd->status &= ~0x10; + ps1snd_update_irq_status(ps1snd); + ret = 0; + break; + + case 2: /* status */ + ret = ps1snd->status; + ret |= (ps1snd->ctrl & 0x01); + if ((ps1snd->fifo_write_idx - ps1snd->fifo_read_idx) >= 2048) + ret |= 0x08; /* FIFO full */ + if (ps1snd->fifo_read_idx == ps1snd->fifo_write_idx) + ret |= 0x04; /* FIFO empty */ + break; + + case 3: /* FIFO timer */ + /* + * The PS/1 Technical Reference says this should return + * thecurrent value, but the PS/1 BIOS and Stunt Island + * expect it not to change. + */ + ret = ps1snd->timer_latch; + break; + + case 4: + case 5: + case 6: + case 7: + ret = 0; + } + + return (ret); +} + +static void +ps1snd_write(uint16_t port, uint8_t val, void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *) priv; + + switch (port & 7) { + case 0: /* DAC output */ + if ((ps1snd->fifo_write_idx - ps1snd->fifo_read_idx) < 2048) { + ps1snd->fifo[ps1snd->fifo_write_idx & 2047] = val; + ps1snd->fifo_write_idx++; + } + break; + + case 2: /* control */ + ps1snd->ctrl = val; + if (!(val & 0x02)) + ps1snd->status &= ~0x02; + ps1snd_update_irq_status(ps1snd); + break; + + case 3: /* timer reload value */ + ps1snd->timer_latch = val; + if (val) + timer_set_delay_u64(&ps1snd->timer_count, ((0xff - val) * TIMER_USEC)); + else + timer_disable(&ps1snd->timer_count); + break; + + case 4: /* almost empty */ + ps1snd->fifo_threshold = val * 4; + break; + } +} + +static void +ps1snd_update(ps1snd_t *ps1snd) +{ + for (; ps1snd->pos < sound_pos_global; ps1snd->pos++) + ps1snd->buffer[ps1snd->pos] = (int8_t) (ps1snd->dac_val ^ 0x80) * 0x20; +} + +static void +ps1snd_callback(void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *) priv; + + ps1snd_update(ps1snd); + + if (ps1snd->fifo_read_idx != ps1snd->fifo_write_idx) { + ps1snd->dac_val = ps1snd->fifo[ps1snd->fifo_read_idx & 2047]; + ps1snd->fifo_read_idx++; + } + + if ((ps1snd->fifo_write_idx - ps1snd->fifo_read_idx) == ps1snd->fifo_threshold) + ps1snd->status |= 0x02; /*FIFO almost empty*/ + + ps1snd->status |= 0x10; /*ADC data ready*/ + ps1snd_update_irq_status(ps1snd); + + timer_advance_u64(&ps1snd->timer_count, ps1snd->timer_latch * TIMER_USEC); +} + +static void +ps1snd_get_buffer(int32_t *buffer, int len, void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *) priv; + int c; + + ps1snd_update(ps1snd); + + for (c = 0; c < len * 2; c++) + buffer[c] += ps1snd->buffer[c >> 1]; + + ps1snd->pos = 0; +} + +static void * +ps1snd_init(const device_t *info) +{ + ps1snd_t *ps1snd = malloc(sizeof(ps1snd_t)); + memset(ps1snd, 0x00, sizeof(ps1snd_t)); + + sn76489_init(&ps1snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); + + io_sethandler(0x0200, 1, + ps1snd_read, NULL, NULL, + ps1snd_write, NULL, NULL, + ps1snd); + io_sethandler(0x0202, 6, + ps1snd_read, NULL, NULL, + ps1snd_write, NULL, NULL, + ps1snd); + + timer_add(&ps1snd->timer_count, ps1snd_callback, ps1snd, 0); + + sound_add_handler(ps1snd_get_buffer, ps1snd); + + return (ps1snd); +} + +static void +ps1snd_close(void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *) priv; + + free(ps1snd); +} + +const device_t ps1snd_device = { + .name = "IBM PS/1 Audio Card", + .internal_name = "ps1snd", + .flags = 0, + .local = 0, + .init = ps1snd_init, + .close = ps1snd_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index 9585ff662..41efc4218 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -1,221 +1,312 @@ -#include #include -#include +#include #include +#include #include + #include <86box/86box.h> -#include <86box/io.h> -#include <86box/dma.h> -#include <86box/pic.h> -#include <86box/timer.h> #include <86box/device.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/pic.h> #include <86box/sound.h> #include <86box/snd_sn76489.h> +#include <86box/timer.h> +typedef struct pssj_t { + sn76489_t sn76489; -typedef struct pssj_t -{ - sn76489_t sn76489; - - uint8_t ctrl; - uint8_t wave; - uint8_t dac_val; - uint16_t freq; - int amplitude; - - int irq; - pc_timer_t timer_count; - int enable; - - int wave_pos; - int pulse_width; + uint8_t ctrl; + uint8_t wave; + uint8_t dac_val; + uint16_t freq; + int amplitude; - int16_t buffer[SOUNDBUFLEN]; - int pos; + int irq; + pc_timer_t timer_count; + int enable; + + int wave_pos; + int pulse_width; + + int16_t buffer[SOUNDBUFLEN]; + int pos; } pssj_t; -static void pssj_update_irq(pssj_t *pssj) +static void +pssj_update_irq(pssj_t *pssj) { - if (pssj->irq && (pssj->ctrl & 0x10) && (pssj->ctrl & 0x08)) - picint(1 << 7); + if (pssj->irq && (pssj->ctrl & 0x10) && (pssj->ctrl & 0x08)) + picint(1 << 7); } -static void pssj_write(uint16_t port, uint8_t val, void *p) +static void +pssj_write(uint16_t port, uint8_t val, void *p) { - pssj_t *pssj = (pssj_t *)p; - - switch (port & 3) - { - case 0: - pssj->ctrl = val; - if (!pssj->enable && ((val & 4) && (pssj->ctrl & 3))) - timer_set_delay_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); - pssj->enable = (val & 4) && (pssj->ctrl & 3); - if (!pssj->enable) - timer_disable(&pssj->timer_count); - sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); - if (!(val & 8)) - pssj->irq = 0; + pssj_t *pssj = (pssj_t *) p; + + switch (port & 3) { + case 0: + pssj->ctrl = val; + if (!pssj->enable && ((val & 4) && (pssj->ctrl & 3))) + timer_set_delay_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double) (pssj->freq ? pssj->freq : 0x400))); + pssj->enable = (val & 4) && (pssj->ctrl & 3); + if (!pssj->enable) + timer_disable(&pssj->timer_count); + sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); + if (!(val & 8)) + pssj->irq = 0; + pssj_update_irq(pssj); + break; + case 1: + switch (pssj->ctrl & 3) { + case 1: /*Sound channel*/ + pssj->wave = val; + pssj->pulse_width = val & 7; + break; + case 3: /*Direct DAC*/ + pssj->dac_val = val; + break; + } + break; + case 2: + pssj->freq = (pssj->freq & 0xf00) | val; + break; + case 3: + pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); + pssj->amplitude = val >> 4; + break; + } +} +static uint8_t +pssj_read(uint16_t port, void *p) +{ + pssj_t *pssj = (pssj_t *) p; + + switch (port & 3) { + case 0: + return (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0); + case 1: + switch (pssj->ctrl & 3) { + case 0: /*Joystick*/ + return 0; + case 1: /*Sound channel*/ + return pssj->wave; + case 2: /*Successive approximation*/ + return 0x80; + case 3: /*Direct DAC*/ + return pssj->dac_val; + } + break; + case 2: + return pssj->freq & 0xff; + case 3: + return (pssj->freq >> 8) | (pssj->amplitude << 4); + default: + return 0xff; + } + + return 0xff; +} + +static void +pssj_update(pssj_t *pssj) +{ + for (; pssj->pos < sound_pos_global; pssj->pos++) + pssj->buffer[pssj->pos] = (((int8_t) (pssj->dac_val ^ 0x80) * 0x20) * pssj->amplitude) / 15; +} + +static void +pssj_callback(void *p) +{ + pssj_t *pssj = (pssj_t *) p; + int data; + + pssj_update(pssj); + if (pssj->ctrl & 2) { + if ((pssj->ctrl & 3) == 3) { + data = dma_channel_read(1); + + if (data != DMA_NODATA) { + pssj->dac_val = data & 0xff; + } + } else { + data = dma_channel_write(1, 0x80); + } + + if ((data & DMA_OVER) && data != DMA_NODATA) { + if (pssj->ctrl & 0x08) { + pssj->irq = 1; pssj_update_irq(pssj); - break; - case 1: - switch (pssj->ctrl & 3) - { - case 1: /*Sound channel*/ - pssj->wave = val; - pssj->pulse_width = val & 7; - break; - case 3: /*Direct DAC*/ - pssj->dac_val = val; - break; - } - break; - case 2: - pssj->freq = (pssj->freq & 0xf00) | val; - break; - case 3: - pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); - pssj->amplitude = val >> 4; - break; - } -} -static uint8_t pssj_read(uint16_t port, void *p) -{ - pssj_t *pssj = (pssj_t *)p; - - switch (port & 3) - { - case 0: - return (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0); - case 1: - switch (pssj->ctrl & 3) - { - case 0: /*Joystick*/ - return 0; - case 1: /*Sound channel*/ - return pssj->wave; - case 2: /*Successive approximation*/ - return 0x80; - case 3: /*Direct DAC*/ - return pssj->dac_val; - } - break; - case 2: - return pssj->freq & 0xff; - case 3: - return (pssj->freq >> 8) | (pssj->amplitude << 4); - default: - return 0xff; + } } - - return 0xff; -} - -static void pssj_update(pssj_t *pssj) -{ - for (; pssj->pos < sound_pos_global; pssj->pos++) - pssj->buffer[pssj->pos] = (((int8_t)(pssj->dac_val ^ 0x80) * 0x20) * pssj->amplitude) / 15; -} - -static void pssj_callback(void *p) -{ - pssj_t *pssj = (pssj_t *)p; - int data; - - pssj_update(pssj); - if (pssj->ctrl & 2) - { - if ((pssj->ctrl & 3) == 3) - { - data = dma_channel_read(1); - - if (data != DMA_NODATA) - { - pssj->dac_val = data & 0xff; - } - } + } else { + switch (pssj->wave & 0xc0) { + case 0x00: /*Pulse*/ + pssj->dac_val = (pssj->wave_pos > (pssj->pulse_width << 1)) ? 0xff : 0; + break; + case 0x40: /*Ramp*/ + pssj->dac_val = pssj->wave_pos << 3; + break; + case 0x80: /*Triangle*/ + if (pssj->wave_pos & 16) + pssj->dac_val = (pssj->wave_pos ^ 31) << 4; else - { - data = dma_channel_write(1, 0x80); - } - - if ((data & DMA_OVER) && data != DMA_NODATA) - { - if (pssj->ctrl & 0x08) - { - pssj->irq = 1; - pssj_update_irq(pssj); - } - } + pssj->dac_val = pssj->wave_pos << 4; + break; + case 0xc0: + pssj->dac_val = 0x80; + break; } - else - { - switch (pssj->wave & 0xc0) - { - case 0x00: /*Pulse*/ - pssj->dac_val = (pssj->wave_pos > (pssj->pulse_width << 1)) ? 0xff : 0; - break; - case 0x40: /*Ramp*/ - pssj->dac_val = pssj->wave_pos << 3; - break; - case 0x80: /*Triangle*/ - if (pssj->wave_pos & 16) - pssj->dac_val = (pssj->wave_pos ^ 31) << 4; - else - pssj->dac_val = pssj->wave_pos << 4; - break; - case 0xc0: - pssj->dac_val = 0x80; - break; - } - pssj->wave_pos = (pssj->wave_pos + 1) & 31; + pssj->wave_pos = (pssj->wave_pos + 1) & 31; + } + + timer_advance_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double) (pssj->freq ? pssj->freq : 0x400))); +} + +static void +pssj_get_buffer(int32_t *buffer, int len, void *p) +{ + pssj_t *pssj = (pssj_t *) p; + int c; + + pssj_update(pssj); + + for (c = 0; c < len * 2; c++) + buffer[c] += pssj->buffer[c >> 1]; + + pssj->pos = 0; +} + +void * +pssj_init(const device_t *info) +{ + pssj_t *pssj = malloc(sizeof(pssj_t)); + memset(pssj, 0, sizeof(pssj_t)); + + sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); + + io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); + timer_add(&pssj->timer_count, pssj_callback, pssj, pssj->enable); + sound_add_handler(pssj_get_buffer, pssj); + + return pssj; +} + +void * +pssj_1e0_init(const device_t *info) +{ + pssj_t *pssj = malloc(sizeof(pssj_t)); + memset(pssj, 0, sizeof(pssj_t)); + + sn76489_init(&pssj->sn76489, 0x01e0, 0x0004, PSSJ, 3579545); + + io_sethandler(0x01E4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); + timer_add(&pssj->timer_count, pssj_callback, pssj, pssj->enable); + sound_add_handler(pssj_get_buffer, pssj); + + return pssj; +} + +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +void * +pssj_isa_init(const device_t *info) +{ + pssj_t *pssj = malloc(sizeof(pssj_t)); + memset(pssj, 0, sizeof(pssj_t)); + + sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); + + uint16_t addr = device_get_config_hex16("base"); + + io_sethandler(addr, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); + timer_add(&pssj->timer_count, pssj_callback, pssj, pssj->enable); + sound_add_handler(pssj_get_buffer, pssj); + + return pssj; +} +#endif + +void +pssj_close(void *p) +{ + pssj_t *pssj = (pssj_t *) p; + + free(pssj); +} + +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +static const device_config_t pssj_isa_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x2C0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x0C0", + .value = 0x0C0 + }, + { + .description = "0x1E0", + .value = 0x1E0 + }, + { + .description = "0x2C0", + .value = 0x2C0 + }, + { .description = "" } } - - timer_advance_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); -} - -static void pssj_get_buffer(int32_t *buffer, int len, void *p) -{ - pssj_t *pssj = (pssj_t *)p; - int c; - - pssj_update(pssj); - - for (c = 0; c < len * 2; c++) - buffer[c] += pssj->buffer[c >> 1]; - - pssj->pos = 0; -} - -void *pssj_init(const device_t *info) -{ - pssj_t *pssj = malloc(sizeof(pssj_t)); - memset(pssj, 0, sizeof(pssj_t)); - - sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); - - io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); - timer_add(&pssj->timer_count, pssj_callback, pssj, pssj->enable); - sound_add_handler(pssj_get_buffer, pssj); - - return pssj; -} - -void pssj_close(void *p) -{ - pssj_t *pssj = (pssj_t *)p; - - free(pssj); -} - -const device_t pssj_device = -{ - "Tandy PSSJ", - 0, 0, - pssj_init, - pssj_close, - NULL, - NULL, - NULL, - NULL + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; +#endif + +const device_t pssj_device = { + .name = "Tandy PSSJ", + .internal_name = "pssj", + .flags = 0, + .local = 0, + .init = pssj_init, + .close = pssj_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t pssj_1e0_device = { + .name = "Tandy PSSJ (port 1e0h)", + .internal_name = "pssj_1e0", + .flags = 0, + .local = 0, + .init = pssj_1e0_init, + .close = pssj_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +const device_t pssj_isa_device = { + .name = "Tandy PSSJ Clone", + .internal_name = "pssj_isa", + .flags = DEVICE_ISA, + .local = 0, + .init = pssj_isa_init, + .close = pssj_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pssj_isa_config +}; +#endif diff --git a/src/sound/snd_resid.cc b/src/sound/snd_resid.cc index 5ca5f6804..173039098 100644 --- a/src/sound/snd_resid.cc +++ b/src/sound/snd_resid.cc @@ -1,112 +1,114 @@ -#include -#include #include +#include #include +#include + #include "resid-fp/sid.h" #include <86box/plat.h> #include <86box/snd_resid.h> - -typedef struct psid_t -{ - /* resid sid implementation */ - SIDFP *sid; - int16_t last_sample; +typedef struct psid_t { + /* resid sid implementation */ + SIDFP *sid; + int16_t last_sample; } psid_t; - psid_t *psid; - -void *sid_init(void) +void * +sid_init(void) { -// psid_t *psid; - int c; - sampling_method method=SAMPLE_INTERPOLATE; - float cycles_per_sec = 14318180.0 / 16.0; - - psid = new psid_t; -// psid = (psid_t *)malloc(sizeof(sound_t)); - psid->sid = new SIDFP; - - psid->sid->set_chip_model(MOS8580FP); - - psid->sid->set_voice_nonlinearity(1.0f); - psid->sid->get_filter().set_distortion_properties(0.f, 0.f, 0.f); - psid->sid->get_filter().set_type4_properties(6.55f, 20.0f); + // psid_t *psid; + int c; + sampling_method method = SAMPLE_INTERPOLATE; + float cycles_per_sec = 14318180.0 / 16.0; - psid->sid->enable_filter(true); - psid->sid->enable_external_filter(true); + psid = new psid_t; + // psid = (psid_t *)malloc(sizeof(sound_t)); + psid->sid = new SIDFP; - psid->sid->reset(); - - for (c=0;c<32;c++) - psid->sid->write(c,0); - - if (!psid->sid->set_sampling_parameters((float)cycles_per_sec, method, - (float)48000, 0.9*48000.0/2.0)) - { - // printf("reSID failed!\n"); - } + psid->sid->set_chip_model(MOS8580FP); - psid->sid->set_chip_model(MOS6581FP); - psid->sid->set_voice_nonlinearity(0.96f); - psid->sid->get_filter().set_distortion_properties(3.7e-3f, 2048.f, 1.2e-4f); + psid->sid->set_voice_nonlinearity(1.0f); + psid->sid->get_filter().set_distortion_properties(0.f, 0.f, 0.f); + psid->sid->get_filter().set_type4_properties(6.55f, 20.0f); - psid->sid->input(0); - psid->sid->get_filter().set_type3_properties(1.33e6f, 2.2e9f, 1.0056f, 7e3f); + psid->sid->enable_filter(true); + psid->sid->enable_external_filter(true); - return (void *)psid; + psid->sid->reset(); + + for (c = 0; c < 32; c++) + psid->sid->write(c, 0); + + if (!psid->sid->set_sampling_parameters((float) cycles_per_sec, method, + (float) 48000, 0.9 * 48000.0 / 2.0)) { + // printf("reSID failed!\n"); + } + + psid->sid->set_chip_model(MOS6581FP); + psid->sid->set_voice_nonlinearity(0.96f); + psid->sid->get_filter().set_distortion_properties(3.7e-3f, 2048.f, 1.2e-4f); + + psid->sid->input(0); + psid->sid->get_filter().set_type3_properties(1.33e6f, 2.2e9f, 1.0056f, 7e3f); + + return (void *) psid; } -void sid_close(UNUSED(void *p)) +void +sid_close(UNUSED(void *p)) { -// psid_t *psid = (psid_t *)p; - delete psid->sid; -// free(psid); + // psid_t *psid = (psid_t *)p; + delete psid->sid; + // free(psid); } -void sid_reset(UNUSED(void *p)) +void +sid_reset(UNUSED(void *p)) { -// psid_t *psid = (psid_t *)p; - int c; - - psid->sid->reset(); + // psid_t *psid = (psid_t *)p; + int c; - for (c = 0; c < 32; c++) - psid->sid->write(c, 0); + psid->sid->reset(); + + for (c = 0; c < 32; c++) + psid->sid->write(c, 0); } - -uint8_t sid_read(uint16_t addr, UNUSED(void *p)) +uint8_t +sid_read(uint16_t addr, UNUSED(void *p)) { -// psid_t *psid = (psid_t *)p; - - return psid->sid->read(addr & 0x1f); -// return 0xFF; + // psid_t *psid = (psid_t *)p; + + return psid->sid->read(addr & 0x1f); + // return 0xFF; } -void sid_write(uint16_t addr, uint8_t val, UNUSED(void *p)) +void +sid_write(uint16_t addr, uint8_t val, UNUSED(void *p)) { -// psid_t *psid = (psid_t *)p; - - psid->sid->write(addr & 0x1f,val); + // psid_t *psid = (psid_t *)p; + + psid->sid->write(addr & 0x1f, val); } -#define CLOCK_DELTA(n) (int)(((14318180.0 * n) / 16.0) / 48000.0) +#define CLOCK_DELTA(n) (int) (((14318180.0 * n) / 16.0) / 48000.0) -static void fillbuf2(int& count, int16_t *buf, int len) +static void +fillbuf2(int &count, int16_t *buf, int len) { - int c; - c = psid->sid->clock(count, buf, len, 1); - if (!c) - *buf = psid->last_sample; - psid->last_sample = *buf; + int c; + c = psid->sid->clock(count, buf, len, 1); + if (!c) + *buf = psid->last_sample; + psid->last_sample = *buf; } -void sid_fillbuf(int16_t *buf, int len, UNUSED(void *p)) +void +sid_fillbuf(int16_t *buf, int len, UNUSED(void *p)) { -// psid_t *psid = (psid_t *)p; - int x = CLOCK_DELTA(len); - - fillbuf2(x, buf, len); + // psid_t *psid = (psid_t *)p; + int x = CLOCK_DELTA(len); + + fillbuf2(x, buf, len); } diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index e96e02c19..609786d0d 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1,1875 +1,3706 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Sound Blaster emulation. + * Sound Blaster emulation. * * * - * Authors: Sarah Walker, - * Miran Grca, - * TheCollector1995, + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H + #include <86box/86box.h> +#include <86box/device.h> +#include <86box/filters.h> +#include <86box/gameport.h> +#include <86box/hdc.h> +#include <86box/isapnp.h> +#include <86box/hdc_ide.h> #include <86box/io.h> -#include <86box/timer.h> #include <86box/mca.h> #include <86box/mem.h> -#include <86box/rom.h> -#include <86box/device.h> -#include <86box/pic.h> -#include <86box/sound.h> #include <86box/midi.h> -#include <86box/filters.h> +#include <86box/pic.h> +#include <86box/rom.h> +#include <86box/sound.h> +#include <86box/timer.h> #include <86box/snd_sb.h> -//#define SB_DSP_RECORD_DEBUG - -#ifdef SB_DSP_RECORD_DEBUG -FILE* soundfsb = 0/*NULL*/; -FILE* soundfsbin = 0/*NULL*/; -#endif - - /* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps. - Note that for positive dB values, this is not amplitude, it is amplitude-1. */ -const float sb_bass_treble_4bits[]= { - 0.199526231, 0.25, 0.316227766, 0.398107170, 0.5, 0.63095734, 0.794328234, 1, + Note that for positive dB values, this is not amplitude, it is amplitude - 1. */ +static const double sb_bass_treble_4bits[] = { + 0.199526231, 0.25, 0.316227766, 0.398107170, 0.5, 0.63095734, 0.794328234, 1, 0, 0.25892541, 0.584893192, 1, 1.511886431, 2.16227766, 3, 4.011872336 }; -/* Attenuation tables for the mixer. Max volume = 32767 in order to give 6dB of +/* Attenuation tables for the mixer. Max volume = 32767 in order to give 6dB of * headroom and avoid integer overflow */ -const int32_t sb_att_2dbstep_5bits[]= -{ - 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, - 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, - 16422,20674,26027,32767 -}; -const int32_t sb_att_4dbstep_3bits[]= -{ - 164,2067,3276,5193,8230,13045,20675,32767 -}; -const int32_t sb_att_7dbstep_2bits[]= -{ - 164,6537,14637,32767 +// clang-format off +static const double sb_att_2dbstep_5bits[] = { + 25.0, 32.0, 41.0, 51.0, 65.0, 82.0, 103.0, 130.0, 164.0, 206.0, + 260.0, 327.0, 412.0, 519.0, 653.0, 822.0, 1036.0, 1304.0, 1641.0, 2067.0, + 2602.0, 3276.0, 4125.0, 5192.0, 6537.0, 8230.0, 10362.0, 13044.0, 16422.0, 20674.0, + 26027.0, 32767.0 }; +static const double sb_att_4dbstep_3bits[] = { + 164.0, 2067.0, 3276.0, 5193.0, 8230.0, 13045.0, 20675.0, 32767.0 +}; + +static const double sb_att_7dbstep_2bits[] = { + 164.0, 6537.0, 14637.0, 32767.0 +}; +// clang-format on + +static const uint16_t sb_mcv_addr[8] = { 0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270 }; +static const int sb_pro_mcv_irqs[4] = { 7, 5, 3, 3 }; + +/* Each card in the SB16 family has a million variants, and it shows in the large variety of device IDs for the PnP models. + This ROM was reconstructed in a best-effort basis around a pnpdump output log found in a forum. */ +static uint8_t sb_16_pnp_rom[] = { + // clang-format off + 0x0e, 0x8c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0024, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '1', '6', ' ', 'P', 'n', 'P', /* ANSI identifier */ + + 0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0x65, /* logical device CTL0031, supports vendor-specific registers 0x39/0x3A/0x3D/0x3F */ + 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x20, 0x00, /* IRQ 5 */ + 0x2a, 0x02, 0x08, /* DMA 1, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x20, 0x12, /* DMA 5, compatibility, count by word, no count by byte, not bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x01, 0x10, /* I/O 0x220, decodes 16-bit, 1-byte alignment, 16 addresses */ + 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x01, 0x02, /* I/O 0x330, decodes 16-bit, 1-byte alignment, 2 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ + 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0xe0, 0x12, /* DMA 5/6/7, compatibility, count by word, no count by byte, not bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ + 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0xe0, 0x12, /* DMA 5/6/7, compatibility, count by word, no count by byte, not bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 0x31, 0x02, /* start dependent functions, functional */ + 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ + 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0xe0, 0x12, /* DMA 5/6/7, compatibility, count by word, no count by byte, not bus master, 16-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x02, /* start dependent functions, functional */ + 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ + 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ + 0x31, 0x02, /* start dependent functions, functional */ + 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ + 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */ + 0x31, 0x02, /* start dependent functions, functional */ + 0x22, 0xa0, 0x04, /* IRQ 5/7/10 */ + 0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */ + 0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x38, /* end dependent functions */ + + 0x16, 0x0e, 0x8c, 0x20, 0x11, 0x00, 0x5a, /* logical device CTL2011, supports vendor-specific registers 0x39/0x3B/0x3C/0x3E */ + 0x1c, 0x41, 0xd0, 0x06, 0x00, /* compatible device PNP0600 */ + 0x82, 0x03, 0x00, 'I', 'D', 'E', /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x00, 0x04, /* IRQ 10 */ + 0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x02, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 2 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0x00, 0x08, /* IRQ 11 */ + 0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x02, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 2 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0x00, 0x8c, /* IRQ 10/11/15 */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x01, 0x08, 0x08, /* I/O 0x100-0x1F8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x03, 0xfe, 0x03, 0x02, 0x02, /* I/O 0x300-0x3FE, decodes 16-bit, 2-byte alignment, 2 addresses */ + 0x31, 0x02, /* start dependent functions, functional */ + 0x22, 0x00, 0x80, /* IRQ 15 */ + 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x01, 0x08, /* I/O 0x170, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0x76, 0x03, 0x76, 0x03, 0x01, 0x02, /* I/O 0x376, decodes 16-bit, 1-byte alignment, 1 addresses */ + 0x38, /* end dependent functions */ + + 0x16, 0x41, 0xd0, 0xff, 0xff, 0x00, 0xda, /* logical device PNPFFFF, supports vendor-specific registers 0x38/0x39/0x3B/0x3C/0x3E */ + 0x82, 0x08, 0x00, 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x01, /* I/O 0x100-0x3F8, decodes 16-bit, 8-byte alignment, 1 address */ + + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ + // clang-format on +}; #ifdef ENABLE_SB_LOG int sb_do_log = ENABLE_SB_LOG; - static void sb_log(const char *fmt, ...) { va_list ap; if (sb_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define sb_log(fmt, ...) +# define sb_log(fmt, ...) #endif - -/* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ -static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) +/* SB 1, 1.5, MCV, and 2 do not have a mixer, so signal is hardwired. */ +static void +sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { - sb_t *sb = (sb_t *)p; - - int c; + sb_t *sb = (sb_t *) p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + int c; + double out_mono = 0.0, out_l = 0.0, out_r = 0.0; + int32_t *opl_buf = NULL; - if (sb->opl_enabled) - opl2_update2(&sb->opl); - sb_dsp_update(&sb->dsp); - for (c = 0; c < len * 2; c += 2) - { - int32_t out = 0; - if (sb->opl_enabled) - out = ((sb->opl.buffer[c] * (sb->opl_emu ? 47000 : 51000)) >> 16); - //TODO: Recording: Mic and line In with AGC - out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; - - buffer[c] += out; - buffer[c + 1] += out; + if (sb->opl_enabled) + opl_buf = sb->opl.update(sb->opl.priv); + + sb_dsp_update(&sb->dsp); + + if (sb->cms_enabled) + cms_update(&sb->cms); + + for (c = 0; c < len * 2; c += 2) { + out_mono = 0.0; + out_l = 0.0; + out_r = 0.0; + + if (sb->opl_enabled) + out_mono = ((double) opl_buf[c]) * 0.7171630859375; + + if (sb->cms_enabled) { + out_l += sb->cms.buffer[c]; + out_r += sb->cms.buffer[c + 1]; + } + out_l += out_mono; + out_r += out_mono; + + if (((sb->opl_enabled) || (sb->cms_enabled)) && sb->mixer_enabled) { + out_l *= mixer->fm; + out_r *= mixer->fm; } - sb->pos = 0; - sb->opl.pos = 0; - sb->dsp.pos = 0; -} + /* TODO: Recording: I assume it has direct mic and line in like SB2. + It is unclear from the docs if it has a filter, but it probably does. */ + /* TODO: Recording: Mic and line In with AGC. */ + if (sb->mixer_enabled) + out_mono = (sb_iir(0, 0, (double) sb->dsp.buffer[c]) * mixer->voice) / 3.9; + else + out_mono = (((sb_iir(0, 0, (double) sb->dsp.buffer[c]) / 1.3) * 65536.0) / 3.0) / 65536.0; + out_l += out_mono; + out_r += out_mono; -static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; - - int c; - - if (sb->opl_enabled) - opl2_update2(&sb->opl); - sb_dsp_update(&sb->dsp); - for (c = 0; c < len * 2; c += 2) - { - int32_t out = 0; - - if (sb->opl_enabled) - out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - /* TODO: Recording : I assume it has direct mic and line in like sb2 */ - /* It is unclear from the docs if it has a filter, but it probably does */ - out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice) / 3) >> 15; - - out = (out * mixer->master) >> 15; - - buffer[c] += out; - buffer[c + 1] += out; + if (sb->mixer_enabled) { + out_l *= mixer->master; + out_r *= mixer->master; } - sb->pos = 0; - sb->opl.pos = 0; - sb->dsp.pos = 0; + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + sb->pos = 0; + + if (sb->opl_enabled) + sb->opl.reset_buffer(sb->opl.priv); + + sb->dsp.pos = 0; + + if (sb->cms_enabled) + sb->cms.pos = 0; } -void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +static void +sb2_filter_cd_audio(int channel, double *buffer, void *p) { - sb_t *sb = (sb_t *)p; - sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; - - int c; + sb_t *sb = (sb_t *) p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + double c; - if (sb->opl_enabled) { - if (sb->dsp.sb_type == SBPRO) - opl2_update2(&sb->opl); - else - opl3_update2(&sb->opl); - } + if (sb->mixer_enabled) { + c = ((sb_iir(1, 0, *buffer) / 1.3) * mixer->cd) / 3.0; + *buffer = c * mixer->master; + } else { + c = (((sb_iir(1, 0, ((double) *buffer)) / 1.3) * 65536) / 3.0) / 65536.0; + *buffer = c; + } +} - sb_dsp_update(&sb->dsp); - for (c = 0; c < len * 2; c += 2) - { - int32_t out_l = 0, out_r = 0; - - if (sb->opl_enabled) { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - } - - /*TODO: Implement the stereo switch on the mixer instead of on the dsp? */ - if (mixer->output_filter) - { - out_l += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 15; - out_r += (int32_t)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 15; - } - else - { - out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 15; - out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 15; - } - //TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. - - out_l = (out_l * mixer->master_l) >> 15; - out_r = (out_r * mixer->master_r) >> 15; +void +sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + int c; + double out_l = 0.0, out_r = 0.0; + int32_t *opl_buf, *opl2_buf; - buffer[c] += out_l; - buffer[c + 1] += out_r; + if (sb->opl_enabled) { + if (sb->dsp.sb_type == SBPRO) { + opl_buf = sb->opl.update(sb->opl.priv); + opl2_buf = sb->opl2.update(sb->opl2.priv); + } else + opl_buf = sb->opl.update(sb->opl.priv); + } + + sb_dsp_update(&sb->dsp); + + for (c = 0; c < len * 2; c += 2) { + out_l = 0.0, out_r = 0.0; + + if (sb->opl_enabled) { + if (sb->dsp.sb_type == SBPRO) { + /* Two chips for LEFT and RIGHT channels. + Each chip stores data into the LEFT channel only (no sample alternating.) */ + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl2_buf[c]) * mixer->fm_r) * 0.7171630859375; + } else { + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl_buf[c + 1]) * mixer->fm_r) * 0.7171630859375; + } } - sb->pos = 0; - sb->opl.pos = 0; - sb->dsp.pos = 0; -} - -static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - - int c; - - if (sb->opl_enabled) - opl3_update2(&sb->opl); - sb_dsp_update(&sb->dsp); - const int dsp_rec_pos = sb->dsp.record_pos_write; - for (c = 0; c < len * 2; c += 2) - { - int32_t out_l = 0, out_r = 0, in_l, in_r; - - if (sb->opl_enabled) { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - } - - /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ - in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; - in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; - - out_l += ((int32_t)(low_fir_sb16(0, (float)sb->dsp.buffer[c]) * mixer->voice_l) / 3) >> 15; - out_r += ((int32_t)(low_fir_sb16(1, (float)sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3) >> 15; - - out_l = (out_l * mixer->master_l) >> 15; - out_r = (out_r * mixer->master_r) >> 15; - - if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) - { - /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ - if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); - if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); - if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); - if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); - if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); - if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); - if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); - if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); - } - if (sb->dsp.sb_enable_i) - { - int c_record = dsp_rec_pos; - c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; - in_l <<= mixer->input_gain_L; - in_r <<= mixer->input_gain_R; - // Clip signal - if (in_l < -32768) - in_l = -32768; - else if (in_l > 32767) - in_l = 32767; - - if (in_r < -32768) - in_r = -32768; - else if (in_r > 32767) - in_r = 32767; - sb->dsp.record_buffer[c_record&0xFFFF] = in_l; - sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; - } - - buffer[c] += (out_l << mixer->output_gain_L); - buffer[c + 1] += (out_r << mixer->output_gain_R); + /* TODO: Implement the stereo switch on the mixer instead of on the dsp? */ + if (mixer->output_filter) { + out_l += (sb_iir(0, 0, (double) sb->dsp.buffer[c]) * mixer->voice_l) / 3.9; + out_r += (sb_iir(0, 1, (double) sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3.9; + } else { + out_l += (sb->dsp.buffer[c] * mixer->voice_l) / 3.0; + out_r += (sb->dsp.buffer[c + 1] * mixer->voice_r) / 3.0; } - sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; - sb->dsp.record_pos_write&=0xFFFF; - sb->pos = 0; - sb->opl.pos = 0; - sb->dsp.pos = 0; + /* TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. */ + out_l *= mixer->master_l; + out_r *= mixer->master_r; + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + sb->pos = 0; + + if (sb->opl_enabled) { + sb->opl.reset_buffer(sb->opl.priv); + if (sb->dsp.sb_type == SBPRO) + sb->opl2.reset_buffer(sb->opl2.priv); + } + + sb->dsp.pos = 0; } -#ifdef SB_DSP_RECORD_DEBUG -int old_dsp_rec_pos=0; -int buf_written=0; -int last_crecord=0; -#endif -static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - - int c; - if (sb->opl_enabled) - opl3_update2(&sb->opl); +void +sbpro_filter_cd_audio(int channel, double *buffer, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + double c; + double cd = channel ? mixer->cd_r : mixer->cd_l; + double master = channel ? mixer->master_r : mixer->master_l; + + if (mixer->output_filter) + c = (sb_iir(1, channel, *buffer) * cd) / 3.9; + else + c = (*buffer * cd) / 3.0; + *buffer = c * master; +} + +static void +sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + int c, dsp_rec_pos = sb->dsp.record_pos_write; + int c_emu8k, c_record; + int32_t in_l, in_r; + double out_l = 0.0, out_r = 0.0; + double bass_treble; + int32_t *opl_buf = NULL; + + if (sb->opl_enabled) + opl_buf = sb->opl.update(sb->opl.priv); + + if (sb->dsp.sb_type > SB16) emu8k_update(&sb->emu8k); - sb_dsp_update(&sb->dsp); - const int dsp_rec_pos = sb->dsp.record_pos_write; - for (c = 0; c < len * 2; c += 2) - { - int32_t out_l = 0, out_r = 0, in_l, in_r; - int c_emu8k = (((c/2) * 44100) / 48000)*2; - - if (sb->opl_enabled) { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); - } - out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 15); - out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_r) >> 15); - - /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ - in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; - in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; - - out_l += ((int32_t)(low_fir_sb16(0, (float)sb->dsp.buffer[c]) * mixer->voice_l) / 3) >> 15; - out_r += ((int32_t)(low_fir_sb16(1, (float)sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3) >> 15; + sb_dsp_update(&sb->dsp); - out_l = (out_l * mixer->master_l) >> 15; - out_r = (out_r * mixer->master_r) >> 15; + for (c = 0; c < len * 2; c += 2) { + out_l = 0.0, out_r = 0.0; - if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) - { - /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ - if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); - if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); - if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); - if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); - if (mixer->bass_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); - if (mixer->bass_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); - if (mixer->treble_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); - if (mixer->treble_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); - } - if (sb->dsp.sb_enable_i) - { -// in_l += (mixer->input_selector_left&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k] : 0 + (mixer->input_selector_left&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; -// in_r += (mixer->input_selector_right&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k]: 0 + (mixer->input_selector_right&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; + if (sb->dsp.sb_type > SB16) + c_emu8k = ((((c / 2) * 44100) / 48000) * 2); - int c_record = dsp_rec_pos; - c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; - #ifdef SB_DSP_RECORD_DEBUG - if (c_record > 0xFFFF && !buf_written) - { - if (!soundfsb) soundfsb=plat_fopen(L"sound_sb.pcm",L"wb"); - fwrite(sb->dsp.record_buffer,2,0x10000,soundfsb); - old_dsp_rec_pos = dsp_rec_pos; - buf_written=1; - } - #endif - in_l <<= mixer->input_gain_L; - in_r <<= mixer->input_gain_R; - // Clip signal - if (in_l < -32768) - in_l = -32768; - else if (in_l > 32767) - in_l = 32767; - - if (in_r < -32768) - in_r = -32768; - else if (in_r > 32767) - in_r = 32767; - sb->dsp.record_buffer[c_record&0xFFFF] = in_l; - sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; - #ifdef SB_DSP_RECORD_DEBUG - if (c_record != last_crecord) - { - if (!soundfsbin) soundfsbin=plat_fopen(L"sound_sb_in.pcm",L"wb"); - fwrite(&sb->dsp.record_buffer[c_record&0xFFFF],2,2,soundfsbin); - last_crecord=c_record; - } - #endif - } - - buffer[c] += (out_l << mixer->output_gain_L); - buffer[c + 1] += (out_r << mixer->output_gain_R); + if (sb->opl_enabled) { + out_l = ((double) opl_buf[c]) * mixer->fm_l * 0.7171630859375; + out_r = ((double) opl_buf[c + 1]) * mixer->fm_r * 0.7171630859375; } - #ifdef SB_DSP_RECORD_DEBUG - if (old_dsp_rec_pos > dsp_rec_pos) - { - buf_written=0; - old_dsp_rec_pos=dsp_rec_pos; + + if (sb->dsp.sb_type > SB16) { + out_l += (((double) sb->emu8k.buffer[c_emu8k]) * mixer->fm_l); + out_r += (((double) sb->emu8k.buffer[c_emu8k + 1]) * mixer->fm_r); } - #endif - - sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; - sb->dsp.record_pos_write&=0xFFFF; - sb->pos = 0; - sb->opl.pos = 0; - sb->dsp.pos = 0; + + /* TODO: Multi-recording mic with agc/+20db, CD, and line in with channel inversion */ + in_l = (mixer->input_selector_left & INPUT_MIDI_L) ? ((int32_t) out_l) : 0 + (mixer->input_selector_left & INPUT_MIDI_R) ? ((int32_t) out_r) + : 0; + in_r = (mixer->input_selector_right & INPUT_MIDI_L) ? ((int32_t) out_l) : 0 + (mixer->input_selector_right & INPUT_MIDI_R) ? ((int32_t) out_r) + : 0; + + if (mixer->output_filter) { + /* We divide by 3 to get the volume down to normal. */ + out_l += (low_fir_sb16(0, 0, (double) sb->dsp.buffer[c]) * mixer->voice_l) / 3.0; + out_r += (low_fir_sb16(0, 1, (double) sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3.0; + } else { + out_l += (((double) sb->dsp.buffer[c]) * mixer->voice_l) / 3.0; + out_r += (((double) sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3.0; + } + + out_l *= mixer->master_l; + out_r *= mixer->master_r; + + /* This is not exactly how one does bass/treble controls, but the end result is like it. + A better implementation would reduce the CPU usage. */ + if (mixer->bass_l != 8) { + bass_treble = sb_bass_treble_4bits[mixer->bass_l]; + + if (mixer->bass_l > 8) + out_l += (low_iir(0, 0, out_l) * bass_treble); + else if (mixer->bass_l < 8) + out_l = ((out_l) *bass_treble + low_cut_iir(0, 0, out_l) * (1.0 - bass_treble)); + } + + if (mixer->bass_r != 8) { + bass_treble = sb_bass_treble_4bits[mixer->bass_r]; + + if (mixer->bass_r > 8) + out_r += (low_iir(0, 1, out_r) * bass_treble); + else if (mixer->bass_r < 8) + out_r = ((out_r) *bass_treble + low_cut_iir(0, 1, out_r) * (1.0 - bass_treble)); + } + + if (mixer->treble_l != 8) { + bass_treble = sb_bass_treble_4bits[mixer->treble_l]; + + if (mixer->treble_l > 8) + out_l += (high_iir(0, 0, out_l) * bass_treble); + else if (mixer->treble_l < 8) + out_l = ((out_l) *bass_treble + high_cut_iir(0, 0, out_l) * (1.0 - bass_treble)); + } + + if (mixer->treble_r != 8) { + bass_treble = sb_bass_treble_4bits[mixer->treble_r]; + + if (mixer->treble_r > 8) + out_r += (high_iir(0, 1, out_r) * bass_treble); + else if (mixer->treble_r < 8) + out_r = ((out_l) *bass_treble + high_cut_iir(0, 1, out_r) * (1.0 - bass_treble)); + } + + if (sb->dsp.sb_enable_i) { + c_record = dsp_rec_pos + ((c * sb->dsp.sb_freq) / 48000); + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + + /* Clip signal */ + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + + sb->dsp.record_buffer[c_record & 0xffff] = in_l; + sb->dsp.record_buffer[(c_record + 1) & 0xffff] = in_r; + } + + buffer[c] += (int32_t) (out_l * mixer->output_gain_L); + buffer[c + 1] += (int32_t) (out_r * mixer->output_gain_R); + } + + sb->dsp.record_pos_write += ((len * sb->dsp.sb_freq) / 24000); + sb->dsp.record_pos_write &= 0xffff; + + sb->pos = 0; + + if (sb->opl_enabled) + sb->opl.reset_buffer(sb->opl.priv); + + sb->dsp.pos = 0; + + if (sb->dsp.sb_type > SB16) sb->emu8k.pos = 0; } - -void sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *p) +void +sb16_awe32_filter_cd_audio(int channel, double *buffer, void *p) { - sb_t *sb = (sb_t *)p; - sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; - - if (!(addr & 1)) - { - mixer->index = val; - mixer->regs[0x01] = val; - } - else - { - if (mixer->index == 0) - { - /* Reset */ - mixer->regs[0x02] = 4 << 1; - mixer->regs[0x06] = 4 << 1; - mixer->regs[0x08] = 0 << 1; - /* changed default from -46dB to 0dB*/ - mixer->regs[0x0A] = 3 << 1; - } - else - { - mixer->regs[mixer->index] = val; - switch (mixer->index) - { - case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: - break; + sb_t *sb = (sb_t *) p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + double c; + double cd = channel ? mixer->cd_r : mixer->cd_l /* / 3.0 */; + double master = channel ? mixer->master_r : mixer->master_l; + int32_t bass = channel ? mixer->bass_r : mixer->bass_l; + int32_t treble = channel ? mixer->treble_r : mixer->treble_l; + double bass_treble; + double output_gain = (channel ? mixer->output_gain_R : mixer->output_gain_L); - default: - sb_log("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - break; - } - } - mixer->master = sb_att_4dbstep_3bits[(mixer->regs[0x02] >> 1)&0x7]; - mixer->fm = sb_att_4dbstep_3bits[(mixer->regs[0x06] >> 1)&0x7]; - mixer->cd = sb_att_4dbstep_3bits[(mixer->regs[0x08] >> 1)&0x7]; - mixer->voice = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + if (mixer->output_filter) + c = (low_fir_sb16(1, channel, *buffer) * cd) / 3.0; + else + c = ((*buffer) * cd) / 3.0; + c *= master; - sound_set_cd_volume(((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535, - ((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535); - } + /* This is not exactly how one does bass/treble controls, but the end result is like it. + A better implementation would reduce the CPU usage. */ + if (bass != 8) { + bass_treble = sb_bass_treble_4bits[bass]; + + if (bass > 8) + c += (low_iir(1, channel, c) * bass_treble); + else if (bass < 8) + c = (c * bass_treble + low_cut_iir(1, channel, c) * (1.0 - bass_treble)); + } + + if (treble != 8) { + bass_treble = sb_bass_treble_4bits[treble]; + + if (treble > 8) + c += (high_iir(1, channel, c) * bass_treble); + else if (treble < 8) + c = (c * bass_treble + high_cut_iir(1, channel, c) * (1.0 - bass_treble)); + } + + *buffer = c * output_gain; } -uint8_t sb_ct1335_mixer_read(uint16_t addr, void *p) +void +sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *p) { - sb_t *sb = (sb_t *)p; - sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + sb_t *sb = (sb_t *) p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; - if (!(addr & 1)) - return mixer->index; + if (!(addr & 1)) { + mixer->index = val; + mixer->regs[0x01] = val; + } else { + if (mixer->index == 0) { + /* Reset */ + mixer->regs[0x02] = mixer->regs[0x06] = 0x08; + mixer->regs[0x08] = 0x00; + /* Changed default from -46dB to 0dB*/ + mixer->regs[0x0a] = 0x06; + } else { + mixer->regs[mixer->index] = val; + switch (mixer->index) { + case 0x00: + case 0x02: + case 0x06: + case 0x08: + case 0x0a: + break; - switch (mixer->index) - { - case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: - return mixer->regs[mixer->index]; default: - sb_log("sb_ct1335: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - break; - } - - return 0xff; -} - -void sb_ct1335_mixer_reset(sb_t* sb) -{ - sb_ct1335_mixer_write(0x254,0,sb); - sb_ct1335_mixer_write(0x255,0,sb); -} - -void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; - - if (!(addr & 1)) - { - mixer->index = val; - mixer->regs[0x01] = val; - } - else - { - if (mixer->index == 0) - { - /* Reset */ - mixer->regs[0x0A] = 0 << 1; - mixer->regs[0x0C] = (0 << 5) | (0 << 3) | (0 << 1); - mixer->regs[0x0E] = (0 << 5) | (0 << 1); - /* changed default from -11dB to 0dB */ - mixer->regs[0x04] = (7 << 5) | (7 << 1); - mixer->regs[0x22] = (7 << 5) | (7 << 1); - mixer->regs[0x26] = (7 << 5) | (7 << 1); - mixer->regs[0x28] = (7 << 5) | (7 << 1); - mixer->regs[0x2E] = (0 << 5) | (0 << 1); - sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0E] & 2); - } - else - { - mixer->regs[mixer->index] = val; - switch (mixer->index) - { - /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ - case 0x02: case 0x06: case 0x08: - mixer->regs[mixer->index+0x20]=((val&0xE) << 4)|(val&0xE); - break; - - case 0x22: case 0x26: case 0x28: - mixer->regs[mixer->index-0x20]=(val&0xE); - break; - - /* More compatibility: SoundBlaster Pro selects register 020h for 030h, 022h for 032h, 026h for 036h,028h for 038h. */ - case 0x30: case 0x32: case 0x36: case 0x38: - mixer->regs[mixer->index-0x10]=(val&0xEE); - break; - - case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: - case 0x2e: - break; - - - default: - sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - break; - } - } - - mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5)&0x7]; - mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1)&0x7]; - mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5)&0x7]; - mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1)&0x7]; - mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5)&0x7]; - mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1)&0x7]; - mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5)&0x7]; - mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1)&0x7]; - mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 5)&0x7]; - mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 1)&0x7]; - - mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; - - mixer->output_filter = !(mixer->regs[0xE] & 0x20); - mixer->input_filter = !(mixer->regs[0xC] & 0x20); - mixer->in_filter_freq = ((mixer->regs[0xC] & 0x8) == 0) ? 3200 : 8800; - mixer->stereo = mixer->regs[0xE] & 2; - if (mixer->index == 0xE) - sb_dsp_set_stereo(&sb->dsp, val & 2); - - switch ((mixer->regs[0xc]&6)) - { - case 2: - mixer->input_selector = INPUT_CD_L|INPUT_CD_R; - break; - case 6: - mixer->input_selector = INPUT_LINE_L|INPUT_LINE_R; - break; - default: - mixer->input_selector = INPUT_MIC; - break; - } - - /* TODO: pcspeaker volume? Or is it not worth? */ - sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, - ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); - } -} - -uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; - - if (!(addr & 1)) - return mixer->index; - - switch (mixer->index) - { - case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: - case 0x22: case 0x26: case 0x28: case 0x2e: case 0x02: case 0x06: - case 0x30: case 0x32: case 0x36: case 0x38: - return mixer->regs[mixer->index]; - - default: - sb_log("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - break; - } - - return 0xff; -} -void sb_ct1345_mixer_reset(sb_t* sb) -{ - sb_ct1345_mixer_write(4,0,sb); - sb_ct1345_mixer_write(5,0,sb); -} - -void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - - if (!(addr & 1)) - mixer->index = val; - else - { - // TODO: and this? 001h: - /*DESCRIPTION - Contains previously selected register value. Mixer Data Register value - NOTES - * SoundBlaster 16 sets bit 7 if previous mixer index invalid. - * Status bytes initially 080h on startup for all but level bytes (SB16) - */ - - if (mixer->index == 0) - { - /* Reset */ - /* Changed defaults from -14dB to 0dB*/ - mixer->regs[0x30]=31 << 3; - mixer->regs[0x31]=31 << 3; - mixer->regs[0x32]=31 << 3; - mixer->regs[0x33]=31 << 3; - mixer->regs[0x34]=31 << 3; - mixer->regs[0x35]=31 << 3; - mixer->regs[0x36]=31 << 3; - mixer->regs[0x37]=31 << 3; - mixer->regs[0x38]=0 << 3; - mixer->regs[0x39]=0 << 3; - - mixer->regs[0x3A]=0 << 3; - - mixer->regs[0x3B]=0 << 6; - mixer->regs[0x3C] = OUTPUT_MIC|OUTPUT_CD_R|OUTPUT_CD_L|OUTPUT_LINE_R|OUTPUT_LINE_L; - mixer->regs[0x3D] = INPUT_MIC|INPUT_CD_L|INPUT_LINE_L|INPUT_MIDI_L; - mixer->regs[0x3E] = INPUT_MIC|INPUT_CD_R|INPUT_LINE_R|INPUT_MIDI_R; - - mixer->regs[0x3F] = mixer->regs[0x40] = 0 << 6; - mixer->regs[0x41] = mixer->regs[0x42] = 0 << 6; - - mixer->regs[0x44] = mixer->regs[0x45] = 8 << 4; - mixer->regs[0x46] = mixer->regs[0x47] = 8 << 4; - - mixer->regs[0x43] = 0; - - mixer->regs[0x83] = 0xff; - sb->dsp.sb_irqm8 = 0; - sb->dsp.sb_irqm16 = 0; - sb->dsp.sb_irqm401 = 0; - } - else - { - mixer->regs[mixer->index] = val; - } - switch (mixer->index) - { - /* SB1/2 compatibility? */ - case 0x02: - mixer->regs[0x30] = ((mixer->regs[0x02] & 0xf) << 4) | 0x8; - mixer->regs[0x31] = ((mixer->regs[0x02] & 0xf) << 4) | 0x8; - break; - case 0x06: - mixer->regs[0x34] = ((mixer->regs[0x06] & 0xf) << 4) | 0x8; - mixer->regs[0x35] = ((mixer->regs[0x06] & 0xf) << 4) | 0x8; - break; - case 0x08: - mixer->regs[0x36] = ((mixer->regs[0x08] & 0xf) << 4) | 0x8; - mixer->regs[0x37] = ((mixer->regs[0x08] & 0xf) << 4) | 0x8; - break; - /* SBPro compatibility. Copy values to sb16 registers. */ - case 0x22: - mixer->regs[0x30] = (mixer->regs[0x22] & 0xF0) | 0x8; - mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) << 4) | 0x8; - break; - case 0x04: - mixer->regs[0x32] = (mixer->regs[0x04] & 0xF0) | 0x8; - mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) << 4) | 0x8; - break; - case 0x26: - mixer->regs[0x34] = (mixer->regs[0x26] & 0xF0) | 0x8; - mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) << 4) | 0x8; - break; - case 0x28: - mixer->regs[0x36] = (mixer->regs[0x28] & 0xF0) | 0x8; - mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) << 4) | 0x8; - break; - case 0x0A: - // mixer->regs[0x3A] = (mixer->regs[0x0A]*3)+10; - mixer->regs[0x3A] = (mixer->regs[0x0A] << 5) | 0x18; - break; - case 0x2E: - mixer->regs[0x38] = (mixer->regs[0x2E] & 0xF0) | 0x8; - mixer->regs[0x39] = ((mixer->regs[0x2E] & 0xf) << 4) | 0x8; - break; - - /* - (DSP 4.xx feature) The Interrupt Setup register, addressed as register 80h on the Mixer register map, is used to configure or determine the Interrupt request line. The DMA setup register, addressed as register 81h on the Mixer register map, is used to configure or determine the DMA channels. - - Note: Registers 80h and 81h are Read-only for PnP boards. - */ - case 0x80: - if (val & 1) sb_dsp_setirq(&sb->dsp,2); - if (val & 2) sb_dsp_setirq(&sb->dsp,5); - if (val & 4) sb_dsp_setirq(&sb->dsp,7); - if (val & 8) sb_dsp_setirq(&sb->dsp,10); - break; - - case 0x81: - /* The documentation is confusing. sounds as if multple dma8 channels could be set. */ - if (val & 1) sb_dsp_setdma8(&sb->dsp,0); - if (val & 2) sb_dsp_setdma8(&sb->dsp,1); - if (val & 8) sb_dsp_setdma8(&sb->dsp,3); - if (val & 0x20) sb_dsp_setdma16(&sb->dsp,5); - if (val & 0x40) sb_dsp_setdma16(&sb->dsp,6); - if (val & 0x80) sb_dsp_setdma16(&sb->dsp,7); - break; - - case 0x83: - /* Interrupt mask. */ - sb->dsp.sb_irqm8 = !(val & 0x01); - sb->dsp.sb_irqm16 = !(val & 0x02); - sb->dsp.sb_irqm401 = !(val & 0x04); - sb_update_irq(&sb->dsp); - break; - - case 0x84: - /* MPU Control register, per the Linux source code. */ - if (sb->mpu != NULL) { - if ((val & 0x06) == 0x00) - mpu401_change_addr(sb->mpu, 0x330); - else if ((val & 0x06) == 0x04) - mpu401_change_addr(sb->mpu, 0x300); - else if ((val & 0x06) == 0x02) - mpu401_change_addr(sb->mpu, 0); - } - break; - } - - mixer->output_selector = mixer->regs[0x3C]; - mixer->input_selector_left = mixer->regs[0x3D]; - mixer->input_selector_right = mixer->regs[0x3E]; - - mixer->master_l = sb_att_2dbstep_5bits[mixer->regs[0x30] >> 3]; - mixer->master_r = sb_att_2dbstep_5bits[mixer->regs[0x31] >> 3]; - mixer->voice_l = sb_att_2dbstep_5bits[mixer->regs[0x32] >> 3]; - mixer->voice_r = sb_att_2dbstep_5bits[mixer->regs[0x33] >> 3]; - mixer->fm_l = sb_att_2dbstep_5bits[mixer->regs[0x34] >> 3]; - mixer->fm_r = sb_att_2dbstep_5bits[mixer->regs[0x35] >> 3]; - mixer->cd_l = (mixer->output_selector&OUTPUT_CD_L) ? sb_att_2dbstep_5bits[mixer->regs[0x36] >> 3] : 0; - mixer->cd_r = (mixer->output_selector&OUTPUT_CD_R) ? sb_att_2dbstep_5bits[mixer->regs[0x37] >> 3] : 0; - mixer->line_l = (mixer->output_selector&OUTPUT_LINE_L) ? sb_att_2dbstep_5bits[mixer->regs[0x38] >> 3] : 0; - mixer->line_r = (mixer->output_selector&OUTPUT_LINE_R) ? sb_att_2dbstep_5bits[mixer->regs[0x39] >> 3] : 0; - - mixer->mic = sb_att_2dbstep_5bits[mixer->regs[0x3A] >> 3]; - mixer->speaker = sb_att_2dbstep_5bits[mixer->regs[0x3B]*3 + 22]; - - - mixer->input_gain_L = (mixer->regs[0x3F] >> 6); - mixer->input_gain_R = (mixer->regs[0x40] >> 6); - mixer->output_gain_L = (mixer->regs[0x41] >> 6); - mixer->output_gain_R = (mixer->regs[0x42] >> 6); - - mixer->bass_l = mixer->regs[0x46] >> 4; - mixer->bass_r = mixer->regs[0x47] >> 4; - mixer->treble_l = mixer->regs[0x44] >> 4; - mixer->treble_r = mixer->regs[0x45] >> 4; - - /*TODO: pcspeaker volume, with "output_selector" check? or better not? */ - sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, - ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); - sb_log("sb_ct1745: Received register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - } -} - -uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - uint8_t temp, ret = 0xff; - - if (!(addr & 1)) - ret = mixer->index; - - sb_log("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - - if (mixer->index>=0x30 && mixer->index<=0x47) - ret = mixer->regs[mixer->index]; - else switch (mixer->index) { - case 0x00: - ret = mixer->regs[mixer->index]; - break; - - /*SB Pro compatibility*/ - case 0x04: - ret = ((mixer->regs[0x33] >> 4) & 0x0f) | (mixer->regs[0x32] & 0xf0); - break; - case 0x0a: - // ret = (mixer->regs[0x3a] - 10) / 3; - ret = (mixer->regs[0x3a] >> 5); - break; - case 0x02: - ret = ((mixer->regs[0x30] >> 4) & 0x0f); - break; - case 0x06: - ret = ((mixer->regs[0x34] >> 4) & 0x0f); - break; - case 0x08: - ret = ((mixer->regs[0x36] >> 4) & 0x0f); - break; - case 0x22: - ret = ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); - break; - case 0x26: - ret = ((mixer->regs[0x35] >> 4) & 0x0f) | (mixer->regs[0x34] & 0xf0); - break; - case 0x28: - ret = ((mixer->regs[0x37] >> 4) & 0x0f) | (mixer->regs[0x36] & 0xf0); - break; - case 0x2e: - ret = ((mixer->regs[0x39] >> 4) & 0x0f) | (mixer->regs[0x38] & 0xf0); - break; - - case 0x48: - // Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector). even when writing. - // Also, the version I have (5.17) does not use the MIDI.L/R input selectors. it uses the volume to mute (Affecting the output, obviously) - ret = mixer->regs[mixer->index]; - break; - - case 0x80: - /*TODO: Unaffected by mixer reset or soft reboot. - * Enabling multiple bits enables multiple IRQs. - */ - - switch (sb->dsp.sb_irqnum) { - case 2: ret = 1; break; - case 5: ret = 2; break; - case 7: ret = 4; break; - case 10: ret = 8; break; - } - break; - - case 0x81: - /* TODO: Unaffected by mixer reset or soft reboot. - * Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. - * Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, - including translated 16-bit DMA requests. - * Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA - requests to 8-bit ones, using the selected 8-bit DMA channel.*/ - - ret = 0; - switch (sb->dsp.sb_8_dmanum) { - case 0: ret |= 1; break; - case 1: ret |= 2; break; - case 3: ret |= 8; break; - } - switch (sb->dsp.sb_16_dmanum) { - case 5: ret |= 0x20; break; - case 6: ret |= 0x40; break; - case 7: ret |= 0x80; break; - } - break; - - /* The Interrupt status register, addressed as register 82h on the Mixer register map, - is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, - in which case it should chain to the previous routine. - */ - case 0x82: - /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ - /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ - temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | - ((sb->dsp.sb_irq401) ? 4 : 0) | 0x4000; - ret = temp; - break; - - case 0x83: - /* Interrupt mask. */ - ret = mixer->regs[mixer->index]; - break; - - case 0x84: - /* MPU Control. */ - if (sb->mpu == NULL) - ret = 0x02; - else { - if (sb->mpu->addr == 0x330) - ret = 0x00; - else if (sb->mpu->addr == 0x300) - ret = 0x04; - else if (sb->mpu->addr == 0) - ret = 0x02; - else - ret = 0x06; /* Should never happen. */ - } - break; - - case 0x90: - /* 3D Enhancement switch. */ - ret = mixer->regs[mixer->index]; - break; - - /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ - case 0xfd: - ret = 16; - break; - - case 0xfe: - ret = 6; - break; - - default: - sb_log("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - break; - } - - sb_log("CT1745: read REG%02X: %02X\n", mixer->index, ret); - return ret; -} - -void sb_ct1745_mixer_reset(sb_t* sb) -{ - sb_ct1745_mixer_write(4,0,sb); - sb_ct1745_mixer_write(5,0,sb); - - sb->mixer_sb16.regs[0xfd] = 16; - sb->mixer_sb16.regs[0xfe] = 6; -} - - -static uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270}; - -uint8_t sb_mcv_read(int port, void *p) -{ - sb_t *sb = (sb_t *)p; - - sb_log("sb_mcv_read: port=%04x\n", port); - - return sb->pos_regs[port & 7]; -} - -void sb_mcv_write(int port, uint8_t val, void *p) -{ - uint16_t addr; - sb_t *sb = (sb_t *)p; - - if (port < 0x102) - return; - - sb_log("sb_mcv_write: port=%04x val=%02x\n", port, val); - - addr = sb_mcv_addr[sb->pos_regs[4] & 7]; - if (sb->opl_enabled) { - io_removehandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - } - /* DSP I/O handler is activated in sb_dsp_setaddr */ - sb_dsp_setaddr(&sb->dsp, 0); - - sb->pos_regs[port & 7] = val; - - if (sb->pos_regs[2] & 1) - { - addr = sb_mcv_addr[sb->pos_regs[4] & 7]; - - if (sb->opl_enabled) { - io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - } - /* DSP I/O handler is activated in sb_dsp_setaddr */ - sb_dsp_setaddr(&sb->dsp, addr); - } -} - -uint8_t sb_mcv_feedb(void *p) -{ - sb_t *sb = (sb_t *)p; - - return (sb->pos_regs[2] & 1); -} - - -static int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; - -uint8_t sb_pro_mcv_read(int port, void *p) -{ - sb_t *sb = (sb_t *)p; - - sb_log("sb_pro_mcv_read: port=%04x\n", port); - - return sb->pos_regs[port & 7]; -} - -void sb_pro_mcv_write(int port, uint8_t val, void *p) -{ - uint16_t addr; - sb_t *sb = (sb_t *)p; - - if (port < 0x102) - return; - - sb_log("sb_pro_mcv_write: port=%04x val=%02x\n", port, val); - - addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; - io_removehandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); - /* DSP I/O handler is activated in sb_dsp_setaddr */ - sb_dsp_setaddr(&sb->dsp, 0); - - sb->pos_regs[port & 7] = val; - - if (sb->pos_regs[2] & 1) - { - addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; - - io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); - /* DSP I/O handler is activated in sb_dsp_setaddr */ - sb_dsp_setaddr(&sb->dsp, addr); - } - sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]); - sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3); -} - -void *sb_1_init(const device_t *info) -{ - /*sb1/2 port mappings, 210h to 260h in 10h steps - 2x0 to 2x3 -> CMS chip - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip*/ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - /* CMS I/O handler is activated on the dedicated sound_cms module - DSP I/O handler is activated in sb_dsp_setaddr */ - if (sb->opl_enabled) { - io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - } - sound_add_handler(sb_get_buffer_sb2, sb); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} -void *sb_15_init(const device_t *info) -{ - /*sb1/2 port mappings, 210h to 260h in 10h steps - 2x0 to 2x3 -> CMS chip - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip*/ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - /* CMS I/O handler is activated on the dedicated sound_cms module - DSP I/O handler is activated in sb_dsp_setaddr */ - if (sb->opl_enabled) { - io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - } - sound_add_handler(sb_get_buffer_sb2, sb); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -void *sb_mcv_init(const device_t *info) -{ - /*sb1/2 port mappings, 210h to 260h in 10h steps - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip*/ - sb_t *sb = malloc(sizeof(sb_t)); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, 0);//addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sound_add_handler(sb_get_buffer_sb2, sb); - /* I/O handlers activated in sb_mcv_write */ - mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, NULL, sb); - sb->pos_regs[0] = 0x84; - sb->pos_regs[1] = 0x50; - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} -void *sb_2_init(const device_t *info) -{ - /*sb2 port mappings. 220h or 240h. - 2x0 to 2x3 -> CMS chip - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip - "CD version" also uses 250h or 260h for - 2x0 to 2x3 -> CDROM interface - 2x4 to 2x5 -> Mixer interface*/ - /*My SB 2.0 mirrors the OPL2 at ports 2x0/2x1. Presumably this mirror is - disabled when the CMS chips are present. - This mirror may also exist on SB 1.5 & MCV, however I am unable to - test this. It shouldn't exist on SB 1.0 as the CMS chips are always - present there. - Syndicate requires this mirror for music to play.*/ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_ct1335_mixer_reset(sb); - /* CMS I/O handler is activated on the dedicated sound_cms module - DSP I/O handler is activated in sb_dsp_setaddr */ - if (sb->opl_enabled) { - if (!GAMEBLASTER) - io_sethandler(addr, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - } - - int mixer_addr = device_get_config_int("mixaddr"); - if (mixer_addr > 0) - { - io_sethandler(mixer_addr+4, 0x0002, sb_ct1335_mixer_read, NULL, NULL, sb_ct1335_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_sb2_mixer, sb); - } - else - sound_add_handler(sb_get_buffer_sb2, sb); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -void *sb_pro_v1_init(const device_t *info) -{ - /*sbpro port mappings. 220h or 240h. - 2x0 to 2x3 -> FM chip, Left and Right (9*2 voices) - 2x4 to 2x5 -> Mixer interface - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip (9 voices) - 2x0+10 to 2x0+13 CDROM interface.*/ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_ct1345_mixer_reset(sb); - /* DSP I/O handler is activated in sb_dsp_setaddr */ - if (sb->opl_enabled) { - io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); - io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - } - io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_sbpro, sb); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -void *sb_pro_v2_init(const device_t *info) -{ - /*sbpro port mappings. 220h or 240h. - 2x0 to 2x3 -> FM chip (18 voices) - 2x4 to 2x5 -> Mixer interface - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip (9 voices) - 2x0+10 to 2x0+13 CDROM interface.*/ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_ct1345_mixer_reset(sb); - /* DSP I/O handler is activated in sb_dsp_setaddr */ - if (sb->opl_enabled) { - io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - } - io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_sbpro, sb); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -void *sb_pro_mcv_init(const device_t *info) -{ - /*sbpro port mappings. 220h or 240h. - 2x0 to 2x3 -> FM chip, Left and Right (18 voices) - 2x4 to 2x5 -> Mixer interface - 2x6, 2xA, 2xC, 2xE -> DSP chip - 2x8, 2x9, 388 and 389 FM chip (9 voices)*/ - sb_t *sb = malloc(sizeof(sb_t)); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = 1; - opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); - sb_ct1345_mixer_reset(sb); - /* I/O handlers activated in sb_mcv_write */ - sound_add_handler(sb_get_buffer_sbpro, sb); - - /* I/O handlers activated in sb_pro_mcv_write */ - mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb_mcv_feedb, NULL, sb); - sb->pos_regs[0] = 0x03; - sb->pos_regs[1] = 0x51; - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -void *sb_16_init(const device_t *info) -{ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - uint16_t mpu_addr = device_get_config_hex16("base401"); - memset(sb, 0, sizeof(sb_t)); - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); - sb_ct1745_mixer_reset(sb); - if (sb->opl_enabled) { - io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - } - io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_sb16, sb); - if (mpu_addr) { - sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); - memset(sb->mpu, 0, sizeof(mpu_t)); - mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART, device_get_config_int("receive_input401")); - } else - sb->mpu = NULL; - sb_dsp_set_mpu(&sb->dsp, sb->mpu); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -int sb_awe32_available() -{ - return rom_present(L"roms/sound/awe32.raw"); -} - -void *sb_awe32_init(const device_t *info) -{ - sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); - uint16_t mpu_addr = device_get_config_hex16("base401"); - uint16_t emu_addr = device_get_config_hex16("emu_base"); - int onboard_ram = device_get_config_int("onboard_ram"); - memset(sb, 0, sizeof(sb_t)); - - - sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) - opl3_init(&sb->opl); - - sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb); - sb_dsp_setaddr(&sb->dsp, addr); - sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); - sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); - sb_ct1745_mixer_reset(sb); - if (sb->opl_enabled) { - io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - } - io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_emu8k, sb); - if (mpu_addr) { - sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); - memset(sb->mpu, 0, sizeof(mpu_t)); - mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART, device_get_config_int("receive_input401")); - sb_dsp_set_mpu(&sb->dsp, sb->mpu); - } else - sb->mpu = NULL; - emu8k_init(&sb->emu8k, emu_addr, onboard_ram); - - if (device_get_config_int("receive_input")) - midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); - - return sb; -} - -void sb_close(void *p) -{ - sb_t *sb = (sb_t *)p; - sb_dsp_close(&sb->dsp); - #ifdef SB_DSP_RECORD_DEBUG - if (soundfsb != 0) - { - fclose(soundfsb); - soundfsb=0; + sb_log("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; } - if (soundfsbin!= 0) + } + + mixer->master = sb_att_4dbstep_3bits[(mixer->regs[0x02] >> 1) & 0x7] / 32768.0; + mixer->fm = sb_att_4dbstep_3bits[(mixer->regs[0x06] >> 1) & 0x7] / 32768.0; + mixer->cd = sb_att_4dbstep_3bits[(mixer->regs[0x08] >> 1) & 0x7] / 32768.0; + mixer->voice = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0; + } +} + +uint8_t +sb_ct1335_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) { + case 0x00: + case 0x02: + case 0x06: + case 0x08: + case 0x0A: + return mixer->regs[mixer->index]; + default: + sb_log("sb_ct1335: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} + +void +sb_ct1335_mixer_reset(sb_t *sb) +{ + sb_ct1335_mixer_write(0x254, 0, sb); + sb_ct1335_mixer_write(0x255, 0, sb); +} + +void +sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) { + mixer->index = val; + mixer->regs[0x01] = val; + } else { + if (mixer->index == 0) { + /* Reset */ + mixer->regs[0x0a] = mixer->regs[0x0c] = 0x00; + mixer->regs[0x0e] = 0x00; + /* Changed default from -11dB to 0dB */ + mixer->regs[0x04] = mixer->regs[0x22] = 0xee; + mixer->regs[0x26] = mixer->regs[0x28] = 0xee; + mixer->regs[0x2e] = 0x00; + sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0e] & 2); + } else { + mixer->regs[mixer->index] = val; + + switch (mixer->index) { + /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ + case 0x02: + case 0x06: + case 0x08: + mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe); + break; + + case 0x22: + case 0x26: + case 0x28: + mixer->regs[mixer->index - 0x20] = (val & 0xe); + break; + + /* More compatibility: + SoundBlaster Pro selects register 020h for 030h, 022h for 032h, + 026h for 036h, and 028h for 038h. */ + case 0x30: + case 0x32: + case 0x36: + case 0x38: + mixer->regs[mixer->index - 0x10] = (val & 0xee); + break; + + case 0x00: + case 0x04: + case 0x0a: + case 0x0c: + case 0x0e: + case 0x2e: + break; + + default: + sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + + mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5) & 0x7] / 32768.0; + mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1) & 0x7] / 32768.0; + mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5) & 0x7] / 32768.0; + mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1) & 0x7] / 32768.0; + mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5) & 0x7] / 32768.0; + mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1) & 0x7] / 32768.0; + mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5) & 0x7] / 32768.0; + mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1) & 0x7] / 32768.0; + mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 5) & 0x7] / 32768.0; + mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 1) & 0x7] / 32768.0; + + mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0; + + mixer->output_filter = !(mixer->regs[0xe] & 0x20); + mixer->input_filter = !(mixer->regs[0xc] & 0x20); + mixer->in_filter_freq = ((mixer->regs[0xc] & 0x8) == 0) ? 3200 : 8800; + mixer->stereo = mixer->regs[0xe] & 2; + if (mixer->index == 0xe) + sb_dsp_set_stereo(&sb->dsp, val & 2); + + switch ((mixer->regs[0xc] & 6)) { + case 2: + mixer->input_selector = INPUT_CD_L | INPUT_CD_R; + break; + case 6: + mixer->input_selector = INPUT_LINE_L | INPUT_LINE_R; + break; + default: + mixer->input_selector = INPUT_MIC; + break; + } + + /* TODO: pcspeaker volume? Or is it not worth? */ + } +} + +uint8_t +sb_ct1345_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) { + case 0x00: + case 0x04: + case 0x0a: + case 0x0c: + case 0x0e: + case 0x22: + case 0x26: + case 0x28: + case 0x2e: + case 0x02: + case 0x06: + case 0x30: + case 0x32: + case 0x36: + case 0x38: + return mixer->regs[mixer->index]; + + default: + sb_log("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} + +void +sb_ct1345_mixer_reset(sb_t *sb) +{ + sb_ct1345_mixer_write(4, 0, sb); + sb_ct1345_mixer_write(5, 0, sb); +} + +void +sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + if (!(addr & 1)) + mixer->index = val; + else { + /* DESCRIPTION: + Contains previously selected register value. Mixer Data Register value. + NOTES: + SoundBlaster 16 sets bit 7 if previous mixer index invalid. + Status bytes initially 080h on startup for all but level bytes (SB16). */ + + if (mixer->index == 0) { + /* Reset: Changed defaults from -14dB to 0dB */ + + mixer->regs[0x30] = mixer->regs[0x31] = 0xf8; + mixer->regs[0x32] = mixer->regs[0x33] = 0xf8; + mixer->regs[0x34] = mixer->regs[0x35] = 0xf8; + mixer->regs[0x36] = mixer->regs[0x37] = 0xf8; + mixer->regs[0x38] = mixer->regs[0x39] = 0x00; + + mixer->regs[0x3a] = mixer->regs[0x3b] = 0x00; + + mixer->regs[0x3c] = (OUTPUT_MIC | OUTPUT_CD_R | OUTPUT_CD_L | OUTPUT_LINE_R | OUTPUT_LINE_L); + mixer->regs[0x3d] = (INPUT_MIC | INPUT_CD_L | INPUT_LINE_L | INPUT_MIDI_L); + mixer->regs[0x3e] = (INPUT_MIC | INPUT_CD_R | INPUT_LINE_R | INPUT_MIDI_R); + + mixer->regs[0x3f] = mixer->regs[0x40] = 0x00; + mixer->regs[0x41] = mixer->regs[0x42] = 0x00; + + mixer->regs[0x44] = mixer->regs[0x45] = 0x80; + mixer->regs[0x46] = mixer->regs[0x47] = 0x80; + + mixer->regs[0x43] = 0x00; + + mixer->regs[0x83] = 0xff; + sb->dsp.sb_irqm8 = 0; + sb->dsp.sb_irqm16 = 0; + sb->dsp.sb_irqm401 = 0; + } else + mixer->regs[mixer->index] = val; + + switch (mixer->index) { + /* SB1/2 compatibility? */ + case 0x02: + mixer->regs[0x30] = ((mixer->regs[0x02] & 0xf) << 4) | 0x8; + mixer->regs[0x31] = ((mixer->regs[0x02] & 0xf) << 4) | 0x8; + break; + case 0x06: + mixer->regs[0x34] = ((mixer->regs[0x06] & 0xf) << 4) | 0x8; + mixer->regs[0x35] = ((mixer->regs[0x06] & 0xf) << 4) | 0x8; + break; + case 0x08: + mixer->regs[0x36] = ((mixer->regs[0x08] & 0xf) << 4) | 0x8; + mixer->regs[0x37] = ((mixer->regs[0x08] & 0xf) << 4) | 0x8; + break; + /* SBPro compatibility. Copy values to sb16 registers. */ + case 0x22: + mixer->regs[0x30] = (mixer->regs[0x22] & 0xf0) | 0x8; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) << 4) | 0x8; + break; + case 0x04: + mixer->regs[0x32] = (mixer->regs[0x04] & 0xf0) | 0x8; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) << 4) | 0x8; + break; + case 0x26: + mixer->regs[0x34] = (mixer->regs[0x26] & 0xf0) | 0x8; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) << 4) | 0x8; + break; + case 0x28: + mixer->regs[0x36] = (mixer->regs[0x28] & 0xf0) | 0x8; + mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) << 4) | 0x8; + break; + case 0x0A: + mixer->regs[0x3a] = (mixer->regs[0x0a] << 5) | 0x18; + break; + case 0x2e: + mixer->regs[0x38] = (mixer->regs[0x2e] & 0xf0) | 0x8; + mixer->regs[0x39] = ((mixer->regs[0x2e] & 0xf) << 4) | 0x8; + break; + + /* (DSP 4.xx feature): + The Interrupt Setup register, addressed as register 80h on the Mixer register map, + is used to configure or determine the Interrupt request line. + The DMA setup register, addressed as register 81h on the Mixer register map, is + used to configure or determine the DMA channels. + + Note: Registers 80h and 81h are Read-only for PnP boards. */ + case 0x80: + if (val & 0x01) + sb_dsp_setirq(&sb->dsp, 2); + if (val & 0x02) + sb_dsp_setirq(&sb->dsp, 5); + if (val & 0x04) + sb_dsp_setirq(&sb->dsp, 7); + if (val & 0x08) + sb_dsp_setirq(&sb->dsp, 10); + break; + + case 0x81: + /* The documentation is confusing. sounds as if multple dma8 channels could + be set. */ + if (val & 0x01) + sb_dsp_setdma8(&sb->dsp, 0); + if (val & 0x02) + sb_dsp_setdma8(&sb->dsp, 1); + if (val & 0x08) + sb_dsp_setdma8(&sb->dsp, 3); + if (val & 0x20) + sb_dsp_setdma16(&sb->dsp, 5); + if (val & 0x40) + sb_dsp_setdma16(&sb->dsp, 6); + if (val & 0x80) + sb_dsp_setdma16(&sb->dsp, 7); + break; + + case 0x83: + /* Interrupt mask. */ + sb_update_mask(&sb->dsp, !(val & 0x01), !(val & 0x02), !(val & 0x04)); + break; + + case 0x84: + /* MPU Control register, per the Linux source code. */ + if (sb->mpu != NULL) { + if ((val & 0x06) == 0x00) + mpu401_change_addr(sb->mpu, 0x330); + else if ((val & 0x06) == 0x04) + mpu401_change_addr(sb->mpu, 0x300); + else if ((val & 0x06) == 0x02) + mpu401_change_addr(sb->mpu, 0); + } + break; + } + + mixer->output_selector = mixer->regs[0x3c]; + mixer->input_selector_left = mixer->regs[0x3d]; + mixer->input_selector_right = mixer->regs[0x3e]; + + mixer->master_l = sb_att_2dbstep_5bits[mixer->regs[0x30] >> 3] / 32768.0; + mixer->master_r = sb_att_2dbstep_5bits[mixer->regs[0x31] >> 3] / 32768.0; + mixer->voice_l = sb_att_2dbstep_5bits[mixer->regs[0x32] >> 3] / 32768.0; + mixer->voice_r = sb_att_2dbstep_5bits[mixer->regs[0x33] >> 3] / 32768.0; + mixer->fm_l = sb_att_2dbstep_5bits[mixer->regs[0x34] >> 3] / 32768.0; + mixer->fm_r = sb_att_2dbstep_5bits[mixer->regs[0x35] >> 3] / 32768.0; + mixer->cd_l = (mixer->output_selector & OUTPUT_CD_L) ? (sb_att_2dbstep_5bits[mixer->regs[0x36] >> 3] / 32768.0) : 0.0; + mixer->cd_r = (mixer->output_selector & OUTPUT_CD_R) ? (sb_att_2dbstep_5bits[mixer->regs[0x37] >> 3] / 32768.0) : 0.0; + mixer->line_l = (mixer->output_selector & OUTPUT_LINE_L) ? (sb_att_2dbstep_5bits[mixer->regs[0x38] >> 3] / 32768.0) : 0.0; + mixer->line_r = (mixer->output_selector & OUTPUT_LINE_R) ? (sb_att_2dbstep_5bits[mixer->regs[0x39] >> 3] / 32768.0) : 0.0; + + mixer->mic = sb_att_2dbstep_5bits[mixer->regs[0x3a] >> 3] / 32768.0; + mixer->speaker = sb_att_2dbstep_5bits[mixer->regs[0x3b] * 3 + 22] / 32768.0; + + mixer->input_gain_L = (mixer->regs[0x3f] >> 6); + mixer->input_gain_R = (mixer->regs[0x40] >> 6); + mixer->output_gain_L = (double) (1 << (mixer->regs[0x41] >> 6)); + mixer->output_gain_R = (double) (1 << (mixer->regs[0x42] >> 6)); + + mixer->bass_l = mixer->regs[0x46] >> 4; + mixer->bass_r = mixer->regs[0x47] >> 4; + mixer->treble_l = mixer->regs[0x44] >> 4; + mixer->treble_r = mixer->regs[0x45] >> 4; + + /* TODO: PC Speaker volume, with "output_selector" check? or better not? */ + sb_log("sb_ct1745: Received register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + } +} + +uint8_t +sb_ct1745_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *) p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + uint8_t temp, ret = 0xff; + + if (!(addr & 1)) + ret = mixer->index; + + sb_log("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + + if ((mixer->index >= 0x30) && (mixer->index <= 0x47)) + ret = mixer->regs[mixer->index]; + else + switch (mixer->index) { + case 0x00: + ret = mixer->regs[mixer->index]; + break; + + /*SB Pro compatibility*/ + case 0x04: + ret = ((mixer->regs[0x33] >> 4) & 0x0f) | (mixer->regs[0x32] & 0xf0); + break; + case 0x0a: + ret = (mixer->regs[0x3a] >> 5); + break; + case 0x02: + ret = ((mixer->regs[0x30] >> 4) & 0x0f); + break; + case 0x06: + ret = ((mixer->regs[0x34] >> 4) & 0x0f); + break; + case 0x08: + ret = ((mixer->regs[0x36] >> 4) & 0x0f); + break; + case 0x0e: + ret = 0x02; + break; + case 0x22: + ret = ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); + break; + case 0x26: + ret = ((mixer->regs[0x35] >> 4) & 0x0f) | (mixer->regs[0x34] & 0xf0); + break; + case 0x28: + ret = ((mixer->regs[0x37] >> 4) & 0x0f) | (mixer->regs[0x36] & 0xf0); + break; + case 0x2e: + ret = ((mixer->regs[0x39] >> 4) & 0x0f) | (mixer->regs[0x38] & 0xf0); + break; + + case 0x48: + /* Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector), + even when writing. + Also, the version I have (5.17), does not use the MIDI.L/R input selectors, it uses + the volume to mute (Affecting the output, obviously). */ + ret = mixer->regs[mixer->index]; + break; + + case 0x80: + /* TODO: Unaffected by mixer reset or soft reboot. + Enabling multiple bits enables multiple IRQs. */ + + switch (sb->dsp.sb_irqnum) { + case 2: + ret = 1; + break; + case 5: + ret = 2; + break; + case 7: + ret = 4; + break; + case 10: + ret = 8; + break; + } + break; + + case 0x81: + /* TODO: Unaffected by mixer reset or soft reboot. + Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. + Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, + including translated 16-bit DMA requests. + Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA + requests to 8-bit ones, using the selected 8-bit DMA channel. */ + + ret = 0; + switch (sb->dsp.sb_8_dmanum) { + case 0: + ret |= 1; + break; + case 1: + ret |= 2; + break; + case 3: + ret |= 8; + break; + } + switch (sb->dsp.sb_16_dmanum) { + case 5: + ret |= 0x20; + break; + case 6: + ret |= 0x40; + break; + case 7: + ret |= 0x80; + break; + } + break; + + case 0x82: + /* The Interrupt status register, addressed as register 82h on the Mixer register map, + is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, + in which case it should chain to the previous routine. */ + /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ + /* 0x02000 DSP v4.04, 0x4000 DSP v4.05, 0x8000 DSP v4.12. + I haven't seen this making any difference, but I'm keeping it for now. */ + /* If QEMU is any indication, then the values are actually 0x20, 0x40, and 0x80. */ + temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | ((sb->dsp.sb_irq401) ? 4 : 0) | 0x40; + ret = temp; + break; + + case 0x83: + /* Interrupt mask. */ + ret = mixer->regs[mixer->index]; + break; + + case 0x84: + /* MPU Control. */ + if (sb->mpu == NULL) + ret = 0x02; + else { + if (sb->mpu->addr == 0x330) + ret = 0x00; + else if (sb->mpu->addr == 0x300) + ret = 0x04; + else if (sb->mpu->addr == 0) + ret = 0x02; + else + ret = 0x06; /* Should never happen. */ + } + break; + + case 0x90: + /* 3D Enhancement switch. */ + ret = mixer->regs[mixer->index]; + break; + + /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ + case 0xfd: + ret = 16; + break; + + case 0xfe: + ret = 6; + break; + + default: + sb_log("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + sb_log("CT1745: read REG%02X: %02X\n", mixer->index, ret); + + return ret; +} + +void +sb_ct1745_mixer_reset(sb_t *sb) +{ + sb_ct1745_mixer_write(4, 0, sb); + sb_ct1745_mixer_write(5, 0, sb); + + sb->mixer_sb16.regs[0xfd] = 16; + sb->mixer_sb16.regs[0xfe] = 6; +} + +uint8_t +sb_mcv_read(int port, void *p) +{ + sb_t *sb = (sb_t *) p; + + sb_log("sb_mcv_read: port=%04x\n", port); + + return sb->pos_regs[port & 7]; +} + +void +sb_mcv_write(int port, uint8_t val, void *p) +{ + uint16_t addr; + sb_t *sb = (sb_t *) p; + + if (port < 0x102) + return; + + sb_log("sb_mcv_write: port=%04x val=%02x\n", port, val); + + addr = sb_mcv_addr[sb->pos_regs[4] & 7]; + if (sb->opl_enabled) { + io_removehandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(0x0388, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) { + addr = sb_mcv_addr[sb->pos_regs[4] & 7]; + + if (sb->opl_enabled) { + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, addr); + } +} + +uint8_t +sb_mcv_feedb(void *p) +{ + sb_t *sb = (sb_t *) p; + + return (sb->pos_regs[2] & 1); +} + +static uint8_t +sb_pro_mcv_read(int port, void *p) +{ + sb_t *sb = (sb_t *) p; + uint8_t ret = sb->pos_regs[port & 7]; + + sb_log("sb_pro_mcv_read: port=%04x ret=%02x\n", port, ret); + + return ret; +} + +static void +sb_pro_mcv_write(int port, uint8_t val, void *p) +{ + uint16_t addr; + sb_t *sb = (sb_t *) p; + + if (port < 0x102) + return; + + sb_log("sb_pro_mcv_write: port=%04x val=%02x\n", port, val); + + addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; + + io_removehandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 4, 0x0002, + sb_ct1345_mixer_read, NULL, NULL, + sb_ct1345_mixer_write, NULL, NULL, + sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) { + addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; + + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, sb->opl.priv); + io_sethandler(addr + 4, 0x0002, + sb_ct1345_mixer_read, NULL, NULL, + sb_ct1345_mixer_write, NULL, NULL, + sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, addr); + } + + sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]); + sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3); +} + +static uint8_t +sb_16_reply_mca_read(int port, void *p) +{ + sb_t *sb = (sb_t *) p; + uint8_t ret = sb->pos_regs[port & 7]; + + sb_log("sb_16_reply_mca_read: port=%04x ret=%02x\n", port, ret); + + return ret; +} + +static void +sb_16_reply_mca_write(int port, uint8_t val, void *p) +{ + uint16_t addr, mpu401_addr; + int low_dma, high_dma; + sb_t *sb = (sb_t *) p; + + if (port < 0x102) + return; + + sb_log("sb_16_reply_mca_write: port=%04x val=%02x\n", port, val); + + switch (sb->pos_regs[2] & 0xc4) { + case 4: + addr = 0x220; + break; + case 0x44: + addr = 0x240; + break; + case 0x84: + addr = 0x260; + break; + case 0xc4: + addr = 0x280; + break; + case 0: + default: + addr = 0; + break; + } + + if (addr) { + io_removehandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 4, 0x0002, + sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, + sb); + } + + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, 0); + mpu401_change_addr(sb->mpu, 0); + gameport_remap(sb->gameport, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) { + switch (sb->pos_regs[2] & 0xc4) { + case 4: + addr = 0x220; + break; + case 0x44: + addr = 0x240; + break; + case 0x84: + addr = 0x260; + break; + case 0xc4: + addr = 0x280; + break; + case 0: + default: + addr = 0; + break; + } + switch (sb->pos_regs[2] & 0x18) { + case 8: + mpu401_addr = 0x330; + break; + case 0x18: + mpu401_addr = 0x300; + break; + case 0: + default: + mpu401_addr = 0; + break; + } + + if (addr) { + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, sb->opl.priv); + io_sethandler(addr + 4, 0x0002, + sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, + sb); + } + + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, addr); + mpu401_change_addr(sb->mpu, mpu401_addr); + gameport_remap(sb->gameport, (sb->pos_regs[2] & 0x20) ? 0x200 : 0); + } + + switch (sb->pos_regs[4] & 0x60) { + case 0x20: + sb_dsp_setirq(&sb->dsp, 5); + break; + case 0x40: + sb_dsp_setirq(&sb->dsp, 7); + break; + case 0x60: + sb_dsp_setirq(&sb->dsp, 10); + break; + } + + low_dma = sb->pos_regs[3] & 3; + high_dma = (sb->pos_regs[3] >> 4) & 7; + if (!high_dma) + high_dma = low_dma; + + sb_dsp_setdma8(&sb->dsp, low_dma); + sb_dsp_setdma16(&sb->dsp, high_dma); +} + +static void +sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + sb_t *sb = (sb_t *) priv; + uint16_t addr = sb->dsp.sb_addr; + uint8_t val; + + switch (ld) { + case 0: /* Audio */ + io_removehandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 4, 0x0002, + sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, + sb); + + addr = sb->opl_pnp_addr; + if (addr) { + sb->opl_pnp_addr = 0; + io_removehandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); + + mpu401_change_addr(sb->mpu, 0); + + if (config->activate) { + addr = config->io[0].base; + if (addr != ISAPNP_IO_DISABLED) { + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 4, 0x0002, + sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, + sb); + + sb_dsp_setaddr(&sb->dsp, addr); + } + + addr = config->io[1].base; + if (addr != ISAPNP_IO_DISABLED) + mpu401_change_addr(sb->mpu, addr); + + addr = config->io[2].base; + if (addr != ISAPNP_IO_DISABLED) { + sb->opl_pnp_addr = addr; + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + val = config->irq[0].irq; + if (val != ISAPNP_IRQ_DISABLED) + sb_dsp_setirq(&sb->dsp, val); + + val = config->dma[0].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma8(&sb->dsp, val); + + val = config->dma[1].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma16(&sb->dsp, val); + } + + break; + + case 1: /* IDE */ + ide_pnp_config_changed(0, config, (void *) 2); + break; + + case 2: /* Reserved (16) / WaveTable (32+) */ + if (sb->dsp.sb_type > SB16) + emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; + + case 3: /* Game */ + gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; + + case 4: /* StereoEnhance (32) */ + break; + } +} + +static void +sb_awe32_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + sb_t *sb = (sb_t *) priv; + + switch (ld) { + case 0: /* Audio */ + case 1: /* IDE */ + sb_16_pnp_config_changed(ld, config, sb); + break; + + case 2: /* Game */ + case 3: /* WaveTable */ + sb_16_pnp_config_changed(ld ^ 1, config, sb); + break; + } +} + +static void +sb_awe64_gold_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + sb_t *sb = (sb_t *) priv; + + switch (ld) { + case 0: /* Audio */ + case 2: /* WaveTable */ + sb_16_pnp_config_changed(ld, config, sb); + break; + + case 1: /* Game */ + sb_16_pnp_config_changed(3, config, sb); + break; + } +} + +void * +sb_1_init(const device_t *info) +{ + /* SB1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip */ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YM3812, &sb->opl); + + sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + sb->cms_enabled = 1; + memset(&sb->cms, 0, sizeof(cms_t)); + io_sethandler(addr, 0x0004, + cms_read, NULL, NULL, + cms_write, NULL, NULL, + &sb->cms); + + sb->mixer_enabled = 0; + sound_add_handler(sb_get_buffer_sb2, sb); + sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +void * +sb_15_init(const device_t *info) +{ + /* SB1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip */ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YM3812, &sb->opl); + + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + sb->cms_enabled = device_get_config_int("cms"); + if (sb->cms_enabled) { + memset(&sb->cms, 0, sizeof(cms_t)); + io_sethandler(addr, 0x0004, + cms_read, NULL, NULL, + cms_write, NULL, NULL, + &sb->cms); + } + + sb->mixer_enabled = 0; + sound_add_handler(sb_get_buffer_sb2, sb); + sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +void * +sb_mcv_init(const device_t *info) +{ + /* SB1/2 port mappings, 210h to 260h in 10h steps + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip */ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YM3812, &sb->opl); + + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + + sb->mixer_enabled = 0; + sound_add_handler(sb_get_buffer_sb2, sb); + sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); + + /* I/O handlers activated in sb_mcv_write */ + mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, NULL, sb); + sb->pos_regs[0] = 0x84; + sb->pos_regs[1] = 0x50; + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +void * +sb_2_init(const device_t *info) +{ + /* SB2 port mappings, 220h or 240h. + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip + "CD version" also uses 250h or 260h for + 2x0 to 2x3 -> CDROM interface + 2x4 to 2x5 -> Mixer interface */ + /* My SB 2.0 mirrors the OPL2 at ports 2x0/2x1. Presumably this mirror is disabled when the + CMS chips are present. + This mirror may also exist on SB 1.5 & MCV, however I am unable to test this. It shouldn't + exist on SB 1.0 as the CMS chips are always present there. Syndicate requires this mirror + for music to play.*/ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + uint16_t mixer_addr = device_get_config_int("mixaddr"); + + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YM3812, &sb->opl); + + sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + if (mixer_addr > 0x000) + sb_ct1335_mixer_reset(sb); + + sb->cms_enabled = device_get_config_int("cms"); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + if (!sb->cms_enabled) { + io_sethandler(addr, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.write); + } + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.write); + io_sethandler(0x0388, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.write); + } + + if (sb->cms_enabled) { + memset(&sb->cms, 0, sizeof(cms_t)); + io_sethandler(addr, 0x0004, + cms_read, NULL, NULL, + cms_write, NULL, NULL, + &sb->cms); + } + + if (mixer_addr > 0x000) { + sb->mixer_enabled = 1; + io_sethandler(mixer_addr + 4, 0x0002, + sb_ct1335_mixer_read, NULL, NULL, + sb_ct1335_mixer_write, NULL, NULL, + sb); + } else + sb->mixer_enabled = 0; + sound_add_handler(sb_get_buffer_sb2, sb); + sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +static uint8_t +sb_pro_v1_opl_read(uint16_t port, void *priv) +{ + sb_t *sb = (sb_t *) priv; + + cycles -= ((int) (isa_timing * 8)); + + (void) sb->opl2.read(port, sb->opl2.priv); // read, but ignore + return (sb->opl.read(port, sb->opl.priv)); +} + +static void +sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv) +{ + sb_t *sb = (sb_t *) priv; + + sb->opl.write(port, val, sb->opl.priv); + sb->opl2.write(port, val, sb->opl2.priv); +} + +static void * +sb_pro_v1_init(const device_t *info) +{ + /* SB Pro port mappings, 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (9*2 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface. */ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) { + fm_driver_get(FM_YM3812, &sb->opl); + sb->opl.set_do_cycles(sb->opl.priv, 0); + fm_driver_get(FM_YM3812, &sb->opl2); + sb->opl2.set_do_cycles(sb->opl2.priv, 0); + } + + sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 2, 0x0002, + sb->opl2.read, NULL, NULL, + sb->opl2.write, NULL, NULL, + sb->opl2.priv); + io_sethandler(addr + 8, 0x0002, + sb_pro_v1_opl_read, NULL, NULL, + sb_pro_v1_opl_write, NULL, NULL, + sb); + io_sethandler(0x0388, 0x0002, + sb_pro_v1_opl_read, NULL, NULL, + sb_pro_v1_opl_write, NULL, NULL, + sb); + } + + sb->mixer_enabled = 1; + io_sethandler(addr + 4, 0x0002, + sb_ct1345_mixer_read, NULL, NULL, + sb_ct1345_mixer_write, NULL, NULL, + sb); + sound_add_handler(sb_get_buffer_sbpro, sb); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +static void * +sb_pro_v2_init(const device_t *info) +{ + /* SB Pro 2 port mappings, 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface. */ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + sb->mixer_enabled = 1; + io_sethandler(addr + 4, 0x0002, + sb_ct1345_mixer_read, NULL, NULL, + sb_ct1345_mixer_write, NULL, NULL, + sb); + sound_add_handler(sb_get_buffer_sbpro, sb); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +static void * +sb_pro_mcv_init(const device_t *info) +{ + /* SB Pro MCV port mappings, 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) */ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = 1; + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); + sb_ct1345_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sbpro, sb); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); + + /* I/O handlers activated in sb_pro_mcv_write */ + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb_mcv_feedb, NULL, sb); + sb->pos_regs[0] = 0x03; + sb->pos_regs[1] = 0x51; + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +static void * +sb_pro_compat_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); + sb_ct1345_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sbpro, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, 1); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + return sb; +} + +static void * +sb_16_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + uint16_t mpu_addr = device_get_config_hex16("base401"); + + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); + sb_ct1745_mixer_reset(sb); + + if (sb->opl_enabled) { + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + sb->mixer_enabled = 1; + sb->mixer_sb16.output_filter = 1; + io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + if (mpu_addr) { + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART, device_get_config_int("receive_input401")); + } else + sb->mpu = NULL; + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +static void * +sb_16_reply_mca_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = 1; + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); + sb_ct1745_mixer_reset(sb); + + sb->mixer_enabled = 1; + sb->mixer_sb16.output_filter = 1; + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, device_get_config_int("receive_input401")); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + sb->gameport = gameport_add(&gameport_device); + + /* I/O handlers activated in sb_pro_mcv_write */ + mca_add(sb_16_reply_mca_read, sb_16_reply_mca_write, sb_mcv_feedb, NULL, sb); + sb->pos_regs[0] = 0x38; + sb->pos_regs[1] = 0x51; + + return sb; +} + +static void * +sb_16_pnp_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = 1; + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); + sb_ct1745_mixer_reset(sb); + + sb->mixer_enabled = 1; + sb->mixer_sb16.output_filter = 1; + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, device_get_config_int("receive_input401")); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + sb->gameport = gameport_add(&gameport_pnp_device); + + device_add(&ide_ter_pnp_device); + + isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb); + + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); + + mpu401_change_addr(sb->mpu, 0); + ide_remove_handlers(2); + + gameport_remap(sb->gameport, 0); + + return sb; +} + +static void * +sb_16_compat_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); + sb_ct1745_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, info->local); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + return sb; +} + +static int +sb_awe32_available() +{ + return rom_present("roms/sound/awe32.raw"); +} + +static int +sb_32_pnp_available() +{ + return sb_awe32_available() && rom_present("roms/sound/CT3600 PnP.BIN"); +} + +static int +sb_awe32_pnp_available() +{ + return sb_awe32_available() && rom_present("roms/sound/CT3980 PnP.BIN"); +} + +static int +sb_awe64_value_available() +{ + return sb_awe32_available() && rom_present("roms/sound/CT4520 PnP.BIN"); +} + +static int +sb_awe64_available() +{ + return sb_awe32_available() && rom_present("roms/sound/CT4520 PnP.BIN"); +} + +static int +sb_awe64_gold_available() +{ + return sb_awe32_available() && rom_present("roms/sound/CT4540 PnP.BIN"); +} + +static void * +sb_awe32_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + uint16_t mpu_addr = device_get_config_hex16("base401"); + uint16_t emu_addr = device_get_config_hex16("emu_base"); + int onboard_ram = device_get_config_int("onboard_ram"); + + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, SBAWE32, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); + sb_ct1745_mixer_reset(sb); + + if (sb->opl_enabled) { + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + sb->mixer_enabled = 1; + sb->mixer_sb16.output_filter = 1; + io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + if (mpu_addr) { + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART, device_get_config_int("receive_input401")); + } else + sb->mpu = NULL; + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + emu8k_init(&sb->emu8k, emu_addr, onboard_ram); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + return sb; +} + +static void * +sb_awe32_pnp_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + int onboard_ram = device_get_config_int("onboard_ram"); + + memset(sb, 0x00, sizeof(sb_t)); + + sb->opl_enabled = 1; + fm_driver_get(FM_YMF262, &sb->opl); + + sb_dsp_init(&sb->dsp, ((info->local == 2) || (info->local == 3) || (info->local == 4)) ? SBAWE64 : SBAWE32, SB_SUBTYPE_DEFAULT, sb); + sb_ct1745_mixer_reset(sb); + + sb->mixer_enabled = 1; + sb->mixer_sb16.output_filter = 1; + sound_add_handler(sb_get_buffer_sb16_awe32, sb); + sound_set_cd_audio_filter(sb16_awe32_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, device_get_config_int("receive_input401")); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + emu8k_init(&sb->emu8k, 0, onboard_ram); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + + sb->gameport = gameport_add(&gameport_pnp_device); + + if ((info->local != 2) && (info->local != 3) && (info->local != 4)) + device_add(&ide_ter_pnp_device); + + char *pnp_rom_file = NULL; + switch (info->local) { + case 0: + pnp_rom_file = "roms/sound/CT3600 PnP.BIN"; + break; + + case 1: + pnp_rom_file = "roms/sound/CT3980 PnP.BIN"; + break; + + case 2: + case 3: + pnp_rom_file = "roms/sound/CT4520 PnP.BIN"; + break; + + case 4: + pnp_rom_file = "roms/sound/CT4540 PnP.BIN"; + break; + } + + uint8_t *pnp_rom = NULL; + if (pnp_rom_file) { + FILE *f = rom_fopen(pnp_rom_file, "rb"); + if (f) { + if (fread(sb->pnp_rom, 1, 512, f) == 512) + pnp_rom = sb->pnp_rom; + fclose(f); + } + } + + switch (info->local) { + case 0: + isapnp_add_card(pnp_rom, sizeof(sb->pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb); + break; + + case 1: + isapnp_add_card(pnp_rom, sizeof(sb->pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb); + break; + + case 2: + case 3: + case 4: + isapnp_add_card(pnp_rom, sizeof(sb->pnp_rom), sb_awe64_gold_pnp_config_changed, NULL, NULL, NULL, sb); + break; + } + + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); + + mpu401_change_addr(sb->mpu, 0); + ide_remove_handlers(2); + + emu8k_change_addr(&sb->emu8k, 0); + + gameport_remap(sb->gameport, 0); + + return sb; +} + +void +sb_close(void *p) +{ + sb_t *sb = (sb_t *) p; + sb_dsp_close(&sb->dsp); + + free(sb); +} + +static void +sb_awe32_close(void *p) +{ + sb_t *sb = (sb_t *) p; + + emu8k_close(&sb->emu8k); + + sb_close(sb); +} + +void +sb_speed_changed(void *p) +{ + sb_t *sb = (sb_t *) p; + + sb_dsp_speed_changed(&sb->dsp); +} + +// clang-format off +static const device_config_t sb_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { { - fclose(soundfsbin); - soundfsbin=0; - } - #endif - - free(sb); -} - -void sb_awe32_close(void *p) -{ - sb_t *sb = (sb_t *)p; - - emu8k_close(&sb->emu8k); - - sb_close(sb); -} - -void sb_speed_changed(void *p) -{ - sb_t *sb = (sb_t *)p; - - sb_dsp_speed_changed(&sb->dsp); -} - -static const device_config_t sb_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x220, - { - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "" - } - } - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 7, - { - { - "IRQ 2", 2 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "" - } - } - }, - { - "dma", "DMA", CONFIG_SELECTION, "", 1, - { - { - "DMA 1", 1 - }, - { - "DMA 3", 3 - }, - { - "" - } - } - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 + .description = "0x210", + .value = 0x210 + }, + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x230", + .value = 0x230 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x260", + .value = 0x260 }, + { .description = "" } } -}; - -static const device_config_t sb_mcv_config[] = -{ - { - "irq", "IRQ", CONFIG_SELECTION, "", 7, - { - { - "IRQ 3", 3 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "" - } - } - }, - { - "dma", "DMA", CONFIG_SELECTION, "", 1, - { - { - "DMA 1", 1 - }, - { - "DMA 3", 3 - }, - { - "" - } - } - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { .description = "" } } -}; - -static const device_config_t sb_pro_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x220, - { - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "" - } - } - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 7, - { - { - "IRQ 2", 2 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, - { - "dma", "DMA", CONFIG_SELECTION, "", 1, - { - { - "DMA 1", 1 - }, - { - "DMA 3", 3 - }, - { - "" - } - } - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { "" } } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t sb_16_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x220, - { - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "0x260", 0x260 - }, - { - "0x280", 0x280 - }, - { - "" - } - } - }, - { - "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, - { - { - "Disabled", 0 - }, - { - "0x300", 0x300 - }, - { - "0x330", 0x330 - }, - { - "" - } - } - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 2", 2 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, - { - "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, - { - { - "DMA 0", 0 - }, - { - "DMA 1", 1 - }, - { - "DMA 3", 3 - }, - { - "" - } - } - }, - { - "dma16", "High DMA channel", CONFIG_SELECTION, "", 5, - { - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "" - } - } - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 +static const device_config_t sb15_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x210", + .value = 0x210 + }, + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x230", + .value = 0x230 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "" } } -}; - -static const device_config_t sb_awe32_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x220, - { - { - "0x220", 0x220 - }, - { - "0x240", 0x240 - }, - { - "0x260", 0x260 - }, - { - "0x280", 0x280 - }, - { - "" - } - } - }, - { - "emu_base", "EMU8000 Address", CONFIG_HEX16, "", 0x620, - { - { - "0x620", 0x620 - }, - { - "0x640", 0x640 - }, - { - "0x660", 0x660 - }, - { - "0x680", 0x680 - }, - { - .description = "" - } - } - }, - { - "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, - { - { - "Disabled", 0 - }, - { - "0x300", 0x300 - }, - { - "0x330", 0x330 - }, - { - "" - } - } - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 2", 2 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, - { - "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, - { - { - "DMA 0", 0 - }, - { - "DMA 1", 1 - }, - { - "DMA 3", 3 - }, - { - "" - } - } - }, - { - "dma16", "High DMA channel", CONFIG_SELECTION, "", 5, - { - { - "DMA 5", 5 - }, - { - "DMA 6", 6 - }, - { - "DMA 7", 7 - }, - { - "" - } - } - }, - { - "onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512, - { - { - "None", 0 - }, - { - "512 KB", 512 - }, - { - "2 MB", 2048 - }, - { - "8 MB", 8192 - }, - { - "28 MB", 28*1024 - }, - { - "" - } - } - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 - }, - { - "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { .description = "" } } + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "cms", + .description = "Enable CMS", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_1_device = -{ - "Sound Blaster v1.0", - DEVICE_ISA, - 0, - sb_1_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_config +static const device_config_t sb2_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x260", + .value = 0x260 + }, + { .description = "" } + } + }, + { + .name = "mixaddr", + .description = "Mixer", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "Disabled", + .value = 0 + }, + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x260", + .value = 0x260 + }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "cms", + .description = "Enable CMS", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_15_device = -{ - "Sound Blaster v1.5", - DEVICE_ISA, - 0, - sb_15_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_config + +static const device_config_t sb_mcv_config[] = { + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_mcv_device = -{ - "Sound Blaster MCV", - DEVICE_MCA, - 0, - sb_mcv_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_mcv_config + +static const device_config_t sb_pro_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_2_device = -{ - "Sound Blaster v2.0", - DEVICE_ISA, - 0, - sb_2_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_config + +static const device_config_t sb_pro_mcv_config[] = { + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_pro_v1_device = -{ - "Sound Blaster Pro v1", - DEVICE_ISA, - 0, - sb_pro_v1_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_pro_config + +static const device_config_t sb_16_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "0x280", + .value = 0x280 + }, + { .description = "" } + } + }, + { + .name = "base401", + .description = "MPU-401 Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x330, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "Disabled", + .value = 0 + }, + { + .description = "0x300", + .value = 0x300 + }, + { + .description = "0x330", + .value = 0x330 + }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "Low DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "dma16", + .description = "High DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 5", + .value = 5 + }, + { + .description = "DMA 6", + .value = 6 + }, + { + .description = "DMA 7", + .value = 7 + }, + { .description = "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_pro_v2_device = -{ - "Sound Blaster Pro v2", - DEVICE_ISA, - 0, - sb_pro_v2_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_pro_config + +static const device_config_t sb_16_pnp_config[] = { + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_pro_mcv_device = -{ - "Sound Blaster Pro MCV", - DEVICE_MCA, - 0, - sb_pro_mcv_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - NULL + +static const device_config_t sb_32_pnp_config[] = { + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "None", + .value = 0 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "28 MB", + .value = 28672 + }, + { .description = "" } + } + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_16_device = -{ - "Sound Blaster 16", - DEVICE_ISA, - 0, - sb_16_init, sb_close, NULL, NULL, - sb_speed_changed, - NULL, - sb_16_config + +static const device_config_t sb_awe32_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "0x280", + .value = 0x280 + }, + { .description = "" } + } + }, + { + .name = "emu_base", + .description = "EMU8000 Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x620, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x620", + .value = 0x620 + }, + { + .description = "0x640", + .value = 0x640 + }, + { + .description = "0x660", + .value = 0x660 + }, + { + .description = "0x680", + .value = 0x680 + }, + { .description = ""} + } + }, + { + .name = "base401", + .description = "MPU-401 Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x330, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "Disabled", + .value = 0 + }, + { + .description = "0x300", + .value = 0x300 + }, + { + .description = "0x330", + .value = 0x330 + }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "Low DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "dma16", + .description = "High DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 5, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 5", + .value = 5 + }, + { + .description = "DMA 6", + .value = 6 + }, + { + .description = "DMA 7", + .value = 7 + }, + { .description = "" } + } + }, + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "None", + .value = 0 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "28 MB", + .value = 28672 + }, + { "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } }; -const device_t sb_awe32_device = -{ - "Sound Blaster AWE32", - DEVICE_ISA, - 0, - sb_awe32_init, sb_close, NULL, - sb_awe32_available, - sb_speed_changed, - NULL, - sb_awe32_config + +static const device_config_t sb_awe32_pnp_config[] = { + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "None", + .value = 0 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "28 MB", + .value = 28672 + }, + { .description = "" } + } + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t sb_awe64_value_config[] = { + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 512, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "4 MB", + .value = 4096 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "12 MB", + .value = 12288 + }, + { + .description = "16 MB", + .value = 16384 + }, + { + .description = "20 MB", + .value = 20480 + }, + { + .description = "24 MB", + .value = 24576 + }, + { + .description = "28 MB", + .value = 28672 + }, + { .description = "" } + } + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t sb_awe64_config[] = { + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1024, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "4 MB", + .value = 4096 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "12 MB", + .value = 12288 + }, + { + .description = "16 MB", + .value = 16384 + }, + { + .description = "20 MB", + .value = 20480 + }, + { + .description = "24 MB", + .value = 24576 + }, + { + .description = "28 MB", + .value = 28672 + }, + { .description = "" } + } + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t sb_awe64_gold_config[] = { + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 4096, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "4 MB", + .value = 4096 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "12 MB", + .value = 12288 + }, + { + .description = "16 MB", + .value = 16384 + }, + { + .description = "20 MB", + .value = 20480 + }, + { + .description = "24 MB", + .value = 24576 + }, + { + .description = "28 MB", + .value = 28672 + }, + { .description = "" } + } + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on + +const device_t sb_1_device = { + .name = "Sound Blaster v1.0", + .internal_name = "sb", + .flags = DEVICE_ISA, + .local = 0, + .init = sb_1_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_config +}; + +const device_t sb_15_device = { + .name = "Sound Blaster v1.5", + .internal_name = "sb1.5", + .flags = DEVICE_ISA, + .local = 0, + .init = sb_15_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb15_config +}; + +const device_t sb_mcv_device = { + .name = "Sound Blaster MCV", + .internal_name = "sbmcv", + .flags = DEVICE_MCA, + .local = 0, + .init = sb_mcv_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_mcv_config +}; + +const device_t sb_2_device = { + .name = "Sound Blaster v2.0", + .internal_name = "sb2.0", + .flags = DEVICE_ISA, + .local = 0, + .init = sb_2_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb2_config +}; + +const device_t sb_pro_v1_device = { + .name = "Sound Blaster Pro v1", + .internal_name = "sbprov1", + .flags = DEVICE_ISA, + .local = 0, + .init = sb_pro_v1_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_pro_config +}; + +const device_t sb_pro_v2_device = { + .name = "Sound Blaster Pro v2", + .internal_name = "sbprov2", + .flags = DEVICE_ISA, + .local = 0, + .init = sb_pro_v2_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_pro_config +}; + +const device_t sb_pro_mcv_device = { + .name = "Sound Blaster Pro MCV", + .internal_name = "sbpromcv", + .flags = DEVICE_MCA, + .local = 0, + .init = sb_pro_mcv_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_pro_mcv_config +}; + +const device_t sb_pro_compat_device = { + .name = "Sound Blaster Pro (Compatibility)", + .internal_name = "sbpro_compat", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = sb_pro_compat_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sb_16_device = { + .name = "Sound Blaster 16", + .internal_name = "sb16", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = sb_16_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_16_config +}; + +const device_t sb_16_reply_mca_device = { + .name = "Sound Blaster 16 Reply MCA", + .internal_name = "sb16_reply_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = sb_16_reply_mca_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_16_pnp_config +}; + +const device_t sb_16_pnp_device = { + .name = "Sound Blaster 16 PnP", + .internal_name = "sb16_pnp", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = sb_16_pnp_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_16_pnp_config +}; + +const device_t sb_16_compat_device = { + .name = "Sound Blaster 16 (Compatibility)", + .internal_name = "sb16_compat", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 1, + .init = sb_16_compat_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sb_16_compat_nompu_device = { + .name = "Sound Blaster 16 (Compatibility - MPU-401 Off)", + .internal_name = "sb16_compat", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = sb_16_compat_init, + .close = sb_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sb_32_pnp_device = { + .name = "Sound Blaster 32 PnP", + .internal_name = "sb32_pnp", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = sb_awe32_pnp_init, + .close = sb_awe32_close, + .reset = NULL, + { .available = sb_32_pnp_available }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_32_pnp_config +}; + +const device_t sb_awe32_device = { + .name = "Sound Blaster AWE32", + .internal_name = "sbawe32", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = sb_awe32_init, + .close = sb_awe32_close, + .reset = NULL, + { .available = sb_awe32_available }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_awe32_config +}; + +const device_t sb_awe32_pnp_device = { + .name = "Sound Blaster AWE32 PnP", + .internal_name = "sbawe32_pnp", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 1, + .init = sb_awe32_pnp_init, + .close = sb_awe32_close, + .reset = NULL, + { .available = sb_awe32_pnp_available }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_awe32_pnp_config +}; + +const device_t sb_awe64_value_device = { + .name = "Sound Blaster AWE64 Value", + .internal_name = "sbawe64_value", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 2, + .init = sb_awe32_pnp_init, + .close = sb_awe32_close, + .reset = NULL, + { .available = sb_awe64_value_available }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_awe64_value_config +}; + +const device_t sb_awe64_device = { + .name = "Sound Blaster AWE64", + .internal_name = "sbawe64", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 3, + .init = sb_awe32_pnp_init, + .close = sb_awe32_close, + .reset = NULL, + { .available = sb_awe64_available }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_awe64_config +}; + +const device_t sb_awe64_gold_device = { + .name = "Sound Blaster AWE64 Gold", + .internal_name = "sbawe64_gold", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 4, + .init = sb_awe32_pnp_init, + .close = sb_awe32_close, + .reset = NULL, + { .available = sb_awe64_gold_available }, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = sb_awe64_gold_config }; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 30b5ae23a..c87f45e2f 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -9,27 +9,26 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H + #include <86box/86box.h> -#include <86box/io.h> -#include <86box/pic.h> -#include <86box/dma.h> -#include <86box/timer.h> #include <86box/device.h> +#include <86box/dma.h> #include <86box/filters.h> -#include <86box/sound.h> +#include <86box/io.h> #include <86box/midi.h> -#include <86box/sound.h> +#include <86box/pic.h> #include <86box/snd_azt2316a.h> +#include <86box/sound.h> +#include <86box/timer.h> #include <86box/snd_sb.h> - -#define ADPCM_4 1 -#define ADPCM_26 2 -#define ADPCM_2 3 +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 /*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/ #define SB_DSP_REC_SAFEFTY_MARGIN 4096 @@ -38,66 +37,63 @@ void pollsb(void *p); void sb_poll_i(void *p); static int sbe2dat[4][9] = { - { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, - { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, - { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, - { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } + {0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106}, + { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, + { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151}, + { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } }; -static int sb_commands[256]= -{ - -1, 2,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, - 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, - 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, - 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, - 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, - 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, - -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 +static int sb_commands[256] = { + -1, 2, -1, 0, 1, 2, -1, 0, 1, -1, -1, -1, -1, -1, 2, 1, + 1, -1, -1, -1, 2, -1, 2, 2, -1, -1, -1, -1, 0, -1, -1, 0, + 0, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 2, 2, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2, 2, 2, 2, -1, -1, -1, -1, -1, 0, -1, 0, + 2, 2, -1, -1, -1, -1, -1, -1, 2, 2, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, -1, -1, -1, -1, -1, + 1, 0, 1, 0, 1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0, 0, -1, -1, -1, -1, -1, 1, 2, -1, -1, -1, -1, 0 }; - -char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; -uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d}; - +char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +uint16_t sb_dsp_versions[] = { 0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d, 0x410 }; /*These tables were 'borrowed' from DOSBox*/ int8_t scaleMap4[64] = { - 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, - 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, - 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 }; uint8_t adjustMap4[64] = { - 0, 0, 0, 0, 0, 16, 16, 16, - 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, 240, 0, 0, 0, 0, 16, 16, 16, 240, 0, 0, 0, 0, 16, 16, 16, 240, 0, 0, 0, 0, 16, 16, 16, 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 0, 0, 0, - 240, 0, 0, 0, 0, 0, 0, 0 + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 }; int8_t scaleMap26[40] = { - 0, 1, 2, 3, 0, -1, -2, -3, - 1, 3, 5, 7, -1, -3, -5, -7, - 2, 6, 10, 14, -2, -6, -10, -14, + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, 4, 12, 20, 28, -4, -12, -20, -28, 5, 15, 25, 35, -5, -15, -25, -35 }; uint8_t adjustMap26[40] = { - 0, 0, 0, 8, 0, 0, 0, 8, + 0, 0, 0, 8, 0, 0, 0, 8, 248, 0, 0, 8, 248, 0, 0, 8, 248, 0, 0, 8, 248, 0, 0, 8, 248, 0, 0, 8, 248, 0, 0, 8, @@ -105,41 +101,38 @@ uint8_t adjustMap26[40] = { }; int8_t scaleMap2[24] = { - 0, 1, 0, -1, 1, 3, -1, -3, - 2, 6, -2, -6, 4, 12, -4, -12, + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, 8, 24, -8, -24, 6, 48, -16, -48 }; uint8_t adjustMap2[24] = { - 0, 4, 0, 4, + 0, 4, 0, 4, 252, 4, 252, 4, 252, 4, 252, 4, 252, 4, 252, 4, 252, 4, 252, 4, 252, 0, 252, 0 }; -float low_fir_sb16_coef[SB16_NCoef]; - +double low_fir_sb16_coef[2][SB16_NCoef]; #ifdef ENABLE_SB_DSP_LOG int sb_dsp_do_log = ENABLE_SB_DSP_LOG; - static void sb_dsp_log(const char *fmt, ...) { va_list ap; if (sb_dsp_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define sb_dsp_log(fmt, ...) +# define sb_dsp_log(fmt, ...) #endif - static __inline double sinc(double x) { @@ -147,86 +140,103 @@ sinc(double x) } static void -recalc_sb16_filter(int playback_freq) +recalc_sb16_filter(int c, int playback_freq) { /* Cutoff frequency = playback / 2 */ - float fC = ((float)playback_freq / 2.0) / 48000.0; - float gain; - int n; + int n; double w, h; + double fC = ((double) playback_freq) / 96000.0; + double gain; for (n = 0; n < SB16_NCoef; n++) { - /* Blackman window */ - w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(SB16_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(SB16_NCoef-1))); - /* Sinc filter */ - h = sinc(2.0 * fC * ((double)n - ((double)(SB16_NCoef-1) / 2.0))); + /* Blackman window */ + w = 0.42 - (0.5 * cos((2.0 * n * M_PI) / (double) (SB16_NCoef - 1))) + (0.08 * cos((4.0 * n * M_PI) / (double) (SB16_NCoef - 1))); + /* Sinc filter */ + h = sinc(2.0 * fC * ((double) n - ((double) (SB16_NCoef - 1) / 2.0))); - /* Create windowed-sinc filter */ - low_fir_sb16_coef[n] = w * h; + /* Create windowed-sinc filter */ + low_fir_sb16_coef[c][n] = w * h; } - low_fir_sb16_coef[(SB16_NCoef - 1) / 2] = 1.0; + low_fir_sb16_coef[c][(SB16_NCoef - 1) / 2] = 1.0; gain = 0.0; for (n = 0; n < SB16_NCoef; n++) - gain += low_fir_sb16_coef[n]; + gain += low_fir_sb16_coef[c][n]; /* Normalise filter, to produce unity gain */ for (n = 0; n < SB16_NCoef; n++) - low_fir_sb16_coef[n] /= gain; + low_fir_sb16_coef[c][n] /= gain; } +static void +sb_irq_update_pic(void *priv, int set) +{ + sb_dsp_t *dsp = (sb_dsp_t *) priv; + if (set) + picint(1 << dsp->sb_irqnum); + else + picintc(1 << dsp->sb_irqnum); +} void -sb_update_irq(sb_dsp_t *dsp) +sb_update_mask(sb_dsp_t *dsp, int irqm8, int irqm16, int irqm401) { - int irq_pending; + int clear = 0; - irq_pending = (dsp->sb_irq8 && !dsp->sb_irqm8) || - (dsp->sb_irq16 && !dsp->sb_irqm16) || - (dsp->sb_irq401 && !dsp->sb_irqm401); + if (!dsp->sb_irqm8 && irqm8) + clear |= 1; + dsp->sb_irqm8 = irqm8; + if (!dsp->sb_irqm16 && irqm16) + clear |= 1; + dsp->sb_irqm16 = irqm16; + if (!dsp->sb_irqm401 && irqm401) + clear |= 1; + dsp->sb_irqm401 = irqm401; - if (irq_pending) - picint(1 << dsp->sb_irqnum); - else - picintc(1 << dsp->sb_irqnum); + if (clear) + dsp->irq_update(dsp->irq_priv, 0); } - void sb_update_status(sb_dsp_t *dsp, int bit, int set) { + int masked = 0; + switch (bit) { - case 0: - default: - dsp->sb_irq8 = set; - break; - case 1: - dsp->sb_irq16 = set; - break; - case 2: - dsp->sb_irq401 = set; - break; + case 0: + default: + dsp->sb_irq8 = set; + masked = dsp->sb_irqm8; + break; + case 1: + dsp->sb_irq16 = set; + masked = dsp->sb_irqm16; + break; + case 2: + dsp->sb_irq401 = set; + masked = dsp->sb_irqm401; + break; } - sb_update_irq(dsp); + if (set && !masked) + dsp->irq_update(dsp->irq_priv, 1); + else if (!set) + dsp->irq_update(dsp->irq_priv, 0); } - void sb_irq(sb_dsp_t *dsp, int irq8) { sb_update_status(dsp, !irq8, 1); } - void sb_irqc(sb_dsp_t *dsp, int irq8) { sb_update_status(dsp, !irq8, 0); } - static void sb_dsp_irq_update(void *priv, int set) { @@ -235,7 +245,6 @@ sb_dsp_irq_update(void *priv, int set) sb_update_status(dsp, 2, set); } - static int sb_dsp_irq_pending(void *priv) { @@ -244,53 +253,49 @@ sb_dsp_irq_pending(void *priv) return dsp->sb_irq401; } - void sb_dsp_set_mpu(sb_dsp_t *dsp, mpu_t *mpu) { dsp->mpu = mpu; if (mpu != NULL) - mpu401_irq_attach(mpu, sb_dsp_irq_update, sb_dsp_irq_pending, dsp); + mpu401_irq_attach(mpu, sb_dsp_irq_update, sb_dsp_irq_pending, dsp); } - void sb_dsp_reset(sb_dsp_t *dsp) { - midi_clear_buffer(); - + midi_clear_buffer(); + timer_disable(&dsp->output_timer); timer_disable(&dsp->input_timer); dsp->sb_command = 0; - dsp->sb_8_length = 0xffff; + dsp->sb_8_length = 0xffff; dsp->sb_8_autolen = 0xffff; - dsp->sb_irq8 = 0; - dsp->sb_irq16 = 0; - dsp->sb_irq401 = 0; - sb_update_irq(dsp); + dsp->sb_irq8 = 0; + dsp->sb_irq16 = 0; + dsp->sb_irq401 = 0; dsp->sb_16_pause = 0; - dsp->sb_read_wp = dsp->sb_read_rp = 0; - dsp->sb_data_stat = -1; - dsp->sb_speaker = 0; - dsp->sb_pausetime = -1LL; - dsp->sbe2 = 0xAA; - dsp->sbe2count = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_data_stat = -1; + dsp->sb_speaker = 0; + dsp->sb_pausetime = -1LL; + dsp->sbe2 = 0xAA; + dsp->sbe2count = 0; dsp->sbreset = 0; - dsp->record_pos_read = 0; + dsp->record_pos_read = 0; dsp->record_pos_write = SB_DSP_REC_SAFEFTY_MARGIN; - picintc(1 << dsp->sb_irqnum); + dsp->irq_update(dsp->irq_priv, 0); dsp->asp_data_len = 0; } - void sb_doreset(sb_dsp_t *dsp) { @@ -298,40 +303,39 @@ sb_doreset(sb_dsp_t *dsp) sb_dsp_reset(dsp); - if (IS_AZTECH(dsp)) { - sb_commands[8] = 1; - sb_commands[9] = 1; + sb_commands[8] = 1; + sb_commands[9] = 1; } else { - if (dsp->sb_type==SB16) - sb_commands[8] = 1; + if (dsp->sb_type >= SB16) + sb_commands[8] = 1; else - sb_commands[8] = -1; + sb_commands[8] = -1; } + dsp->sb_asp_mode = 0; + dsp->sb_asp_ram_index = 0; for (c = 0; c < 256; c++) - dsp->sb_asp_regs[c] = 0; + dsp->sb_asp_regs[c] = 0; dsp->sb_asp_regs[5] = 0x01; dsp->sb_asp_regs[9] = 0xf8; } - void sb_dsp_speed_changed(sb_dsp_t *dsp) { if (dsp->sb_timeo < 256) - dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); + dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); else - dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256))); + dsp->sblatcho = (uint64_t) (TIMER_USEC * (1000000.0f / (float) (dsp->sb_timeo - 256))); if (dsp->sb_timei < 256) - dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); + dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); else - dsp->sblatchi = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); + dsp->sblatchi = (uint64_t) (TIMER_USEC * (1000000.0f / (float) (dsp->sb_timei - 256))); } - void sb_add_data(sb_dsp_t *dsp, uint8_t v) { @@ -339,115 +343,109 @@ sb_add_data(sb_dsp_t *dsp, uint8_t v) dsp->sb_read_wp &= 0xff; } - void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { dsp->sb_pausetime = -1; if (dma8) { - dsp->sb_8_length = len; - dsp->sb_8_format = format; - dsp->sb_8_autoinit = autoinit; - dsp->sb_8_pause = 0; - dsp->sb_8_enable = 1; + dsp->sb_8_length = dsp->sb_8_origlength = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; - if (dsp->sb_16_enable && dsp->sb_16_output) - dsp->sb_16_enable = 0; - dsp->sb_8_output = 1; - if (!timer_is_enabled(&dsp->output_timer)) - timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); - dsp->sbleftright = 0; - dsp->sbdacpos = 0; + if (dsp->sb_16_enable && dsp->sb_16_output) + dsp->sb_16_enable = 0; + dsp->sb_8_output = 1; + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); + dsp->sbleftright = dsp->sbleftright_default; + dsp->sbdacpos = 0; } else { - dsp->sb_16_length = len; - dsp->sb_16_format = format; - dsp->sb_16_autoinit = autoinit; - dsp->sb_16_pause = 0; - dsp->sb_16_enable = 1; - if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; - dsp->sb_16_output = 1; - if (!timer_is_enabled(&dsp->output_timer)) - timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); + dsp->sb_16_length = dsp->sb_16_origlength = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && dsp->sb_8_output) + dsp->sb_8_enable = 0; + dsp->sb_16_output = 1; + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); } } - void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { if (dma8) { - dsp->sb_8_length = len; - dsp->sb_8_format = format; - dsp->sb_8_autoinit = autoinit; - dsp->sb_8_pause = 0; - dsp->sb_8_enable = 1; - if (dsp->sb_16_enable && !dsp->sb_16_output) - dsp->sb_16_enable = 0; - dsp->sb_8_output = 0; - if (!timer_is_enabled(&dsp->input_timer)) - timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); + dsp->sb_8_length = dsp->sb_8_origlength = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && !dsp->sb_16_output) + dsp->sb_16_enable = 0; + dsp->sb_8_output = 0; + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); } else { - dsp->sb_16_length = len; - dsp->sb_16_format = format; - dsp->sb_16_autoinit = autoinit; - dsp->sb_16_pause = 0; - dsp->sb_16_enable = 1; - if (dsp->sb_8_enable && !dsp->sb_8_output) - dsp->sb_8_enable = 0; - dsp->sb_16_output = 0; - if (!timer_is_enabled(&dsp->input_timer)) - timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); + dsp->sb_16_length = dsp->sb_16_origlength = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && !dsp->sb_8_output) + dsp->sb_8_enable = 0; + dsp->sb_16_output = 0; + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); } - memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); + memset(dsp->record_buffer, 0, sizeof(dsp->record_buffer)); } - int -sb_8_read_dma(sb_dsp_t *dsp) +sb_8_read_dma(void *priv) { + sb_dsp_t *dsp = (sb_dsp_t *) priv; return dma_channel_read(dsp->sb_8_dmanum); } - -void -sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) +int +sb_8_write_dma(void *priv, uint8_t val) { - dma_channel_write(dsp->sb_8_dmanum, val); + sb_dsp_t *dsp = (sb_dsp_t *) priv; + return dma_channel_write(dsp->sb_8_dmanum, val) == DMA_NODATA; } - int -sb_16_read_dma(sb_dsp_t *dsp) +sb_16_read_dma(void *priv) { + sb_dsp_t *dsp = (sb_dsp_t *) priv; return dma_channel_read(dsp->sb_16_dmanum); } - int -sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +sb_16_write_dma(void *priv, uint16_t val) { - int ret = dma_channel_write(dsp->sb_16_dmanum, val); - - return (ret == DMA_NODATA); + sb_dsp_t *dsp = (sb_dsp_t *) priv; + return dma_channel_write(dsp->sb_16_dmanum, val) == DMA_NODATA; } - void sb_dsp_setirq(sb_dsp_t *dsp, int irq) { dsp->sb_irqnum = irq; } - void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) { dsp->sb_8_dmanum = dma; } - void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) { @@ -461,383 +459,471 @@ sb_exec_command(sb_dsp_t *dsp) sb_dsp_log("sb_exec_command : SB command %02X\n", dsp->sb_command); + /* Update 8051 ram with the current DSP command. + See https://github.com/joncampbell123/dosbox-x/issues/1044 */ + if (dsp->sb_type >= SB16) + dsp->sb_8051_ram[0x20] = dsp->sb_command; + switch (dsp->sb_command) { - case 0x01: /* ???? */ - if (dsp->sb_type >= SB16) - dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; - break; - case 0x03: /* ASP status */ - sb_add_data(dsp, 0); - break; - case 0x10: /* 8-bit direct mode */ - sb_dsp_update(dsp); - dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; - break; - case 0x14: /* 8-bit single cycle DMA output */ - sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x17: /* 2-bit ADPCM output with reference */ - dsp->sbref = sb_8_read_dma(dsp); - dsp->sbstep = 0; - /* Fall through */ - case 0x16: /* 2-bit ADPCM output */ - sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - if (dsp->sb_command == 0x17) - dsp->sb_8_length--; - break; - case 0x1C: /* 8-bit autoinit DMA output */ - if (dsp->sb_type >= SB15) - sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); - break; - case 0x1F: /* 2-bit ADPCM autoinit output */ - if (dsp->sb_type >= SB15) { - sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } - break; - case 0x20: /* 8-bit direct input */ - sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); - /* Due to the current implementation, I need to emulate a samplerate, even if this - mode does not imply such samplerate. Position is increased in sb_poll_i(). */ - if (!timer_is_enabled(&dsp->input_timer)) { - dsp->sb_timei = 256 - 22; - dsp->sblatchi = TIMER_USEC * 22; - temp = 1000000 / 22; - dsp->sb_freq = temp; - timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); - } - break; - case 0x24: /* 8-bit single cycle DMA input */ - sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x2C: /* 8-bit autoinit DMA input */ - if (dsp->sb_type >= SB15) - sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x30: /* MIDI Polling mode input */ - sb_dsp_log("MIDI polling mode input\n"); - dsp->midi_in_poll = 1; - dsp->uart_irq = 0; - break; - case 0x31: /* MIDI Interrupt mode input */ - sb_dsp_log("MIDI interrupt mode input\n"); - dsp->midi_in_poll = 0; - dsp->uart_irq = 1; - break; - case 0x34: /* MIDI In poll */ - if (dsp->sb_type < SB2) - break; - sb_dsp_log("MIDI poll in\n"); - dsp->midi_in_poll = 1; - dsp->uart_midi = 1; - dsp->uart_irq = 0; - break; - case 0x35: /* MIDI In irq */ - if (dsp->sb_type < SB2) - break; - sb_dsp_log("MIDI irq in\n"); - dsp->midi_in_poll = 0; - dsp->uart_midi = 1; - dsp->uart_irq = 1; - break; - case 0x36: case 0x37: /* MIDI timestamps */ - break; - case 0x38: /* Write to SB MIDI Output (Raw) */ - dsp->onebyte_midi = 1; - break; - case 0x40: /* Set time constant */ - dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; - dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); - temp = 256 - dsp->sb_data[0]; - temp = 1000000 / temp; - sb_dsp_log("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); - if ((dsp->sb_freq != temp) && (dsp->sb_type >= SB16)) - recalc_sb16_filter(temp); - dsp->sb_freq = temp; - break; - case 0x41: /* Set output sampling rate */ - case 0x42: /* Set input sampling rate */ - if (dsp->sb_type >= SB16) { - dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); - sb_dsp_log("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); - temp = dsp->sb_freq; - dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); - dsp->sb_timeo = 256LL + dsp->sb_freq; - dsp->sblatchi = dsp->sblatcho; - dsp->sb_timei = dsp->sb_timeo; - if (dsp->sb_freq != temp && dsp->sb_type >= SB16) - recalc_sb16_filter(dsp->sb_freq); - } + case 0x01: /* ???? */ + if (dsp->sb_type >= SB16) + dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; + break; + case 0x03: /* ASP status */ + if (dsp->sb_type >= SB16) + sb_add_data(dsp, 0); + break; + case 0x10: /* 8-bit direct mode */ + sb_dsp_update(dsp); + dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; + break; + case 0x14: /* 8-bit single cycle DMA output */ + sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x17: /* 2-bit ADPCM output with reference */ + dsp->sbref = dsp->dma_readb(dsp->dma_priv); + dsp->sbstep = 0; + /* Fall through */ + case 0x16: /* 2-bit ADPCM output */ + sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + if (dsp->sb_command == 0x17) + dsp->sb_8_length--; + break; + case 0x1C: /* 8-bit autoinit DMA output */ + if (dsp->sb_type >= SB15) + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x1F: /* 2-bit ADPCM autoinit output */ + if (dsp->sb_type >= SB15) { + sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + } + break; + case 0x20: /* 8-bit direct input */ + sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80); + /* Due to the current implementation, I need to emulate a samplerate, even if this + mode does not imply such samplerate. Position is increased in sb_poll_i(). */ + if (!timer_is_enabled(&dsp->input_timer)) { + dsp->sb_timei = 256 - 22; + dsp->sblatchi = TIMER_USEC * 22; + temp = 1000000 / 22; + dsp->sb_freq = temp; + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); + } + break; + case 0x24: /* 8-bit single cycle DMA input */ + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x28: /* Direct ADC, 8-bit (Burst) */ + break; + case 0x2C: /* 8-bit autoinit DMA input */ + if (dsp->sb_type >= SB15) + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x30: /* MIDI Polling mode input */ + sb_dsp_log("MIDI polling mode input\n"); + dsp->midi_in_poll = 1; + dsp->uart_irq = 0; + break; + case 0x31: /* MIDI Interrupt mode input */ + sb_dsp_log("MIDI interrupt mode input\n"); + dsp->midi_in_poll = 0; + dsp->uart_irq = 1; + break; + case 0x32: /* MIDI Read Timestamp Poll */ + break; + case 0x33: /* MIDI Read Timestamp Interrupt */ + break; + case 0x34: /* MIDI In poll */ + if (dsp->sb_type < SB2) break; - case 0x48: /* Set DSP block transfer size */ - dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); - break; - case 0x75: /* 4-bit ADPCM output with reference */ - dsp->sbref = sb_8_read_dma(dsp); - dsp->sbstep = 0; - /* Fall through */ - case 0x74: /* 4-bit ADPCM output */ - sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - if (dsp->sb_command == 0x75) - dsp->sb_8_length--; - break; - case 0x77: /* 2.6-bit ADPCM output with reference */ - dsp->sbref = sb_8_read_dma(dsp); - dsp->sbstep = 0; - /* Fall through */ - case 0x76: /* 2.6-bit ADPCM output */ - sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - if (dsp->sb_command == 0x77) - dsp->sb_8_length--; - break; - case 0x7D: /* 4-bit ADPCM autoinit output */ - if (dsp->sb_type >= SB15) { - sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } - break; - case 0x7F: /* 2.6-bit ADPCM autoinit output */ - if (dsp->sb_type >= SB15) { - sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } - break; - case 0x80: /* Pause DAC */ - dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); - if (!timer_is_enabled(&dsp->output_timer)) - timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); - break; - case 0x90: /* High speed 8-bit autoinit DMA output */ - if (dsp->sb_type >= SB2) - sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); - break; - case 0x91: /* High speed 8-bit single cycle DMA output */ - if (dsp->sb_type >= SB2) - sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); - break; - case 0x98: /* High speed 8-bit autoinit DMA input */ - if (dsp->sb_type >= SB2) - sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); - break; - case 0x99: /* High speed 8-bit single cycle DMA input */ - if (dsp->sb_type >= SB2) - sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); - break; - case 0xA0: /* Set input mode to mono */ - case 0xA8: /* Set input mode to stereo */ - if ((dsp->sb_type < SB2) || (dsp->sb_type > SBPRO2)) - break; - /* TODO: Implement. 3.xx-only command. */ - break; - case 0xB0: case 0xB1: case 0xB2: case 0xB3: - case 0xB4: case 0xB5: case 0xB6: case 0xB7: /* 16-bit DMA output */ - if (dsp->sb_type >= SB16) { - sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - } + sb_dsp_log("MIDI poll in\n"); + dsp->midi_in_poll = 1; + dsp->uart_midi = 1; + dsp->uart_irq = 0; + break; + case 0x35: /* MIDI In irq */ + if (dsp->sb_type < SB2) break; - case 0xB8: case 0xB9: case 0xBA: case 0xBB: - case 0xBC: case 0xBD: case 0xBE: case 0xBF: /* 16-bit DMA input */ - if (dsp->sb_type >= SB16) { - sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - } - break; - case 0xC0: case 0xC1: case 0xC2: case 0xC3: - case 0xC4: case 0xC5: case 0xC6: case 0xC7: /* 8-bit DMA output */ - if (dsp->sb_type >= SB16) { - sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - } - break; - case 0xC8: case 0xC9: case 0xCA: case 0xCB: - case 0xCC: case 0xCD: case 0xCE: case 0xCF: /* 8-bit DMA input */ - if (dsp->sb_type >= SB16) { - sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - } - break; - case 0xD0: /* Pause 8-bit DMA */ - dsp->sb_8_pause = 1; - break; - case 0xD1: /* Speaker on */ - if (dsp->sb_type < SB15) - dsp->sb_8_pause = 1; - else if (dsp->sb_type < SB16) - dsp->muted = 0; - dsp->sb_speaker = 1; - break; - case 0xD3: /* Speaker off */ - if (dsp->sb_type < SB15 ) - dsp->sb_8_pause = 1; - else if (dsp->sb_type < SB16) - dsp->muted = 1; - dsp->sb_speaker = 0; - break; - case 0xD4: /* Continue 8-bit DMA */ - dsp->sb_8_pause = 0; - break; - case 0xD5: /* Pause 16-bit DMA */ - if (dsp->sb_type >= SB16) - dsp->sb_16_pause = 1; - break; - case 0xD6: /* Continue 16-bit DMA */ - if (dsp->sb_type >= SB16) - dsp->sb_16_pause = 0; - break; - case 0xD8: /* Get speaker status */ - sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); - break; - case 0xD9: /* Exit 16-bit auto-init mode */ - if (dsp->sb_type >= SB16) - dsp->sb_16_autoinit = 0; - break; - case 0xDA: /* Exit 8-bit auto-init mode */ - dsp->sb_8_autoinit = 0; - break; - case 0xE0: /* DSP identification */ - sb_add_data(dsp, ~dsp->sb_data[0]); - break; - case 0xE1: /* Get DSP version */ - if (IS_AZTECH(dsp)) { - if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - sb_add_data(dsp, 0x3); - sb_add_data(dsp, 0x1); - } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - sb_add_data(dsp, 0x2); - sb_add_data(dsp, 0x1); - } - break; - } - sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); - sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); - break; - case 0xE2: /* Stupid ID/protection */ - for (c = 0; c < 8; c++) { - if (dsp->sb_data[0] & (1 << c)) - dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; - } - dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; - dsp->sbe2count++; - sb_8_write_dma(dsp, dsp->sbe2); - break; - case 0xE3: /* DSP copyright */ - if (dsp->sb_type >= SB16) { - c = 0; - while (sb16_copyright[c]) - sb_add_data(dsp, sb16_copyright[c++]); - sb_add_data(dsp, 0); - } - break; - case 0xE4: /* Write test register */ - dsp->sb_test = dsp->sb_data[0]; - break; - case 0xE8: /* Read test register */ - sb_add_data(dsp, dsp->sb_test); - break; - case 0xF2: /* Trigger 8-bit IRQ */ - sb_dsp_log("Trigger IRQ\n"); - sb_irq(dsp, 1); - break; - case 0xF3: /* Trigger 16-bit IRQ */ - sb_dsp_log("Trigger IRQ\n"); - sb_irq(dsp, 0); - break; - case 0xE7: case 0xFA: /* ???? */ - break; - case 0x07: case 0xFF: /* No, that's not how you program auto-init DMA */ - break; - case 0x08: /* ASP get version */ - if (IS_AZTECH(dsp)) { - if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55)&& dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) - sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */ - else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) - sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */ - else if (dsp->sb_data[0] == 0x08) { - /* EEPROM address to write followed by byte */ - if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) - fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]); - sb_dsp_log("EEPROM write = %02x\n", dsp->sb_data[2]); - dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2]; - break; - } else if (dsp->sb_data[0] == 0x07) { - /* EEPROM address to read */ - if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) - fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]); - sb_dsp_log("EEPROM read = %02x\n", dsp->azt_eeprom[dsp->sb_data[1]]); - sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]); - break; - } else - sb_dsp_log("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); /* 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen */ - break; - } - if (dsp->sb_type >= SB16) - sb_add_data(dsp, 0x18); - break; - case 0x0E: /* ASP set register */ - if (dsp->sb_type >= SB16) - dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; - break; - case 0x0F: /* ASP get register */ - if (dsp->sb_type >= SB16) - sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); - break; - case 0xF8: - if (dsp->sb_type < SB16) - sb_add_data(dsp, 0); - break; - case 0xF9: - if (dsp->sb_type >= SB16) { - if (dsp->sb_data[0] == 0x0e) - sb_add_data(dsp, 0xff); - else if (dsp->sb_data[0] == 0x0f) - sb_add_data(dsp, 0x07); - else if (dsp->sb_data[0] == 0x37) - sb_add_data(dsp, 0x38); - else - sb_add_data(dsp, 0x00); - } - case 0x04: case 0x05: - break; + sb_dsp_log("MIDI irq in\n"); + dsp->midi_in_poll = 0; + dsp->uart_midi = 1; + dsp->uart_irq = 1; + break; + case 0x36: + case 0x37: /* MIDI timestamps */ + break; + case 0x38: /* Write to SB MIDI Output (Raw) */ + dsp->onebyte_midi = 1; + break; + case 0x40: /* Set time constant */ + dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); + temp = 256 - dsp->sb_data[0]; + temp = 1000000 / temp; + sb_dsp_log("Sample rate - %ihz (%i)\n", temp, dsp->sblatcho); + if ((dsp->sb_freq != temp) && (dsp->sb_type >= SB16)) + recalc_sb16_filter(0, temp); + dsp->sb_freq = temp; + break; + case 0x41: /* Set output sampling rate */ + case 0x42: /* Set input sampling rate */ + if (dsp->sb_type >= SB16) { + dsp->sblatcho = (uint64_t) (TIMER_USEC * (1000000.0f / (float) (dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); + sb_dsp_log("Sample rate - %ihz (%i)\n", dsp->sb_data[1] + (dsp->sb_data[0] << 8), dsp->sblatcho); + temp = dsp->sb_freq; + dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); + dsp->sb_timeo = 256LL + dsp->sb_freq; + dsp->sblatchi = dsp->sblatcho; + dsp->sb_timei = dsp->sb_timeo; + if (dsp->sb_freq != temp && dsp->sb_type >= SB16) + recalc_sb16_filter(0, dsp->sb_freq); + dsp->sb_8051_ram[0x13] = dsp->sb_freq & 0xff; + dsp->sb_8051_ram[0x14] = (dsp->sb_freq >> 8) & 0xff; + } + break; + case 0x45: /* Continue Auto-Initialize DMA, 8-bit */ + break; + case 0x47: /* Continue Auto-Initialize DMA, 16-bit */ + break; + case 0x48: /* Set DSP block transfer size */ + dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + break; + case 0x75: /* 4-bit ADPCM output with reference */ + dsp->sbref = dsp->dma_readb(dsp->dma_priv); + dsp->sbstep = 0; + /* Fall through */ + case 0x74: /* 4-bit ADPCM output */ + sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + if (dsp->sb_command == 0x75) + dsp->sb_8_length--; + break; + case 0x77: /* 2.6-bit ADPCM output with reference */ + dsp->sbref = dsp->dma_readb(dsp->dma_priv); + dsp->sbstep = 0; + /* Fall through */ + case 0x76: /* 2.6-bit ADPCM output */ + sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + if (dsp->sb_command == 0x77) + dsp->sb_8_length--; + break; + case 0x7D: /* 4-bit ADPCM autoinit output */ + if (dsp->sb_type >= SB15) { + sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + } + break; + case 0x7F: /* 2.6-bit ADPCM autoinit output */ + if (dsp->sb_type >= SB15) { + sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + } + break; + case 0x80: /* Pause DAC */ + dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); + break; + case 0x90: /* High speed 8-bit autoinit DMA output */ + if (dsp->sb_type >= SB2) + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x91: /* High speed 8-bit single cycle DMA output */ + if (dsp->sb_type >= SB2) + sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0x98: /* High speed 8-bit autoinit DMA input */ + if (dsp->sb_type >= SB2) + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x99: /* High speed 8-bit single cycle DMA input */ + if (dsp->sb_type >= SB2) + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0xA0: /* Set input mode to mono */ + case 0xA8: /* Set input mode to stereo */ + if ((dsp->sb_type < SB2) || (dsp->sb_type > SBPRO2)) + break; + /* TODO: Implement. 3.xx-only command. */ + break; + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: /* 16-bit DMA output */ + if (dsp->sb_type >= SB16) { + sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: /* 16-bit DMA input */ + if (dsp->sb_type >= SB16) { + sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xC0: + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: /* 8-bit DMA output */ + if (dsp->sb_type >= SB16) { + sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: /* 8-bit DMA input */ + if (dsp->sb_type >= SB16) { + sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xD0: /* Pause 8-bit DMA */ + dsp->sb_8_pause = 1; + break; + case 0xD1: /* Speaker on */ + if (dsp->sb_type < SB15) + dsp->sb_8_pause = 1; + else if (dsp->sb_type < SB16) + dsp->muted = 0; + dsp->sb_speaker = 1; + break; + case 0xD3: /* Speaker off */ + if (dsp->sb_type < SB15) + dsp->sb_8_pause = 1; + else if (dsp->sb_type < SB16) + dsp->muted = 1; + dsp->sb_speaker = 0; + break; + case 0xD4: /* Continue 8-bit DMA */ + dsp->sb_8_pause = 0; + break; + case 0xD5: /* Pause 16-bit DMA */ + if (dsp->sb_type >= SB16) + dsp->sb_16_pause = 1; + break; + case 0xD6: /* Continue 16-bit DMA */ + if (dsp->sb_type >= SB16) + dsp->sb_16_pause = 0; + break; + case 0xD8: /* Get speaker status */ + sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); + break; + case 0xD9: /* Exit 16-bit auto-init mode */ + if (dsp->sb_type >= SB16) + dsp->sb_16_autoinit = 0; + break; + case 0xDA: /* Exit 8-bit auto-init mode */ + dsp->sb_8_autoinit = 0; + break; + case 0xE0: /* DSP identification */ + sb_add_data(dsp, ~dsp->sb_data[0]); + break; + case 0xE1: /* Get DSP version */ + if (IS_AZTECH(dsp)) { + if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + sb_add_data(dsp, 0x3); + sb_add_data(dsp, 0x1); + } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + sb_add_data(dsp, 0x2); + sb_add_data(dsp, 0x1); + } + break; + } + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); + break; + case 0xE2: /* Stupid ID/protection */ + for (c = 0; c < 8; c++) { + if (dsp->sb_data[0] & (1 << c)) + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; + } + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; + dsp->sbe2count++; + dsp->dma_writeb(dsp->dma_priv, dsp->sbe2); + break; + case 0xE3: /* DSP copyright */ + if (dsp->sb_type >= SB16) { + c = 0; + while (sb16_copyright[c]) + sb_add_data(dsp, sb16_copyright[c++]); + sb_add_data(dsp, 0); + } + break; + case 0xE4: /* Write test register */ + dsp->sb_test = dsp->sb_data[0]; + break; + case 0xE8: /* Read test register */ + sb_add_data(dsp, dsp->sb_test); + break; + case 0xF2: /* Trigger 8-bit IRQ */ + sb_dsp_log("Trigger IRQ\n"); + sb_irq(dsp, 1); + break; + case 0xF3: /* Trigger 16-bit IRQ */ + sb_dsp_log("Trigger IRQ\n"); + sb_irq(dsp, 0); + break; + case 0xE7: /* ???? */ + break; + case 0x07: + case 0xFF: /* No, that's not how you program auto-init DMA */ + break; + case 0x08: /* ASP get version / AZTECH type/EEPROM access */ + if (IS_AZTECH(dsp)) { + if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) + sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */ + else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) + sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */ + else if (dsp->sb_data[0] == 0x08) { + /* EEPROM address to write followed by byte */ + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]); + sb_dsp_log("EEPROM write = %02x\n", dsp->sb_data[2]); + dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2]; + break; + } else if (dsp->sb_data[0] == 0x07) { + /* EEPROM address to read */ + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]); + sb_dsp_log("EEPROM read = %02x\n", dsp->azt_eeprom[dsp->sb_data[1]]); + sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]); + break; + } else + sb_dsp_log("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); /* 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen */ + break; + } + if (dsp->sb_type == SBAWE64) /* AWE64 has no ASP or a socket for it */ + sb_add_data(dsp, 0xFF); + else if (dsp->sb_type >= SB16) + sb_add_data(dsp, 0x18); + break; + case 0x0E: /* ASP set register */ + if (dsp->sb_type >= SB16) { + dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; - case 0x09: /*AZTECH mode set*/ - if (IS_AZTECH(dsp)) { - if (dsp->sb_data[0] == 0x00) { - sb_dsp_log("AZT2316A: WSS MODE!\n"); - azt2316a_enable_wss(1, dsp->parent); - } else if (dsp->sb_data[0] == 0x01) { - sb_dsp_log("AZT2316A: SB8PROV2 MODE!\n"); - azt2316a_enable_wss(0, dsp->parent); - } else - sb_dsp_log("AZT2316A: UNKNOWN MODE! = %02x\n", dsp->sb_data[0]); // sequences 0x02->0xFF, 0x04->0xFF seen - } - break; + if ((dsp->sb_data[0] == 0x83) && (dsp->sb_asp_mode & 128) && (dsp->sb_asp_mode & 8)) { /* ASP memory write */ + if (dsp->sb_asp_mode & 8) + dsp->sb_asp_ram_index = 0; - /* TODO: Some more data about the DSP registeres - * http://the.earth.li/~tfm/oldpage/sb_dsp.html - * http://www.synchrondata.com/pheaven/www/area19.htm - * http://www.dcee.net/Files/Programm/Sound/ - * 0E3h DSP Copyright SBPro2??? - * 0F0h Sine Generator SB - * 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 - * 0F2h IRQ Request, 8-bit SB - * 0F3h IRQ Request, 16-bit SB16 - * 0FBh DSP Status SB16 - * 0FCh DSP Auxiliary Status SB16 - * 0FDh DSP Command Status SB16 - */ + dsp->sb_asp_ram[dsp->sb_asp_ram_index] = dsp->sb_data[1]; + + if (dsp->sb_asp_mode & 2) { + dsp->sb_asp_ram_index++; + if (dsp->sb_asp_ram_index >= 2048) + dsp->sb_asp_ram_index = 0; + } + } + sb_dsp_log("SB16 ASP write reg %02X, val %02X\n", dsp->sb_data[0], dsp->sb_data[1]); + } + break; + case 0x0F: /* ASP get register */ + if (dsp->sb_type >= SB16) { + if ((dsp->sb_data[0] == 0x83) && (dsp->sb_asp_mode & 128) && (dsp->sb_asp_mode & 8)) { /* ASP memory read */ + if (dsp->sb_asp_mode & 8) + dsp->sb_asp_ram_index = 0; + + dsp->sb_asp_regs[0x83] = dsp->sb_asp_ram[dsp->sb_asp_ram_index]; + + if (dsp->sb_asp_mode & 1) { + dsp->sb_asp_ram_index++; + if (dsp->sb_asp_ram_index >= 2048) + dsp->sb_asp_ram_index = 0; + } + } else if (dsp->sb_data[0] == 0x83) { + dsp->sb_asp_regs[0x83] = 0x18; + } + sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); + sb_dsp_log("SB16 ASP read reg %02X, val %02X\n", dsp->sb_data[0], dsp->sb_asp_regs[dsp->sb_data[0]]); + } + break; + case 0xF8: + if (dsp->sb_type < SB16) + sb_add_data(dsp, 0); + break; + case 0xF9: /* SB16 8051 RAM read */ + if (dsp->sb_type >= SB16) + sb_add_data(dsp, dsp->sb_8051_ram[dsp->sb_data[0]]); + break; + case 0xFA: /* SB16 8051 RAM write */ + if (dsp->sb_type >= SB16) + dsp->sb_8051_ram[dsp->sb_data[0]] = dsp->sb_data[1]; + break; + case 0x04: /* ASP set mode register */ + if (dsp->sb_type >= SB16) { + dsp->sb_asp_mode = dsp->sb_data[0]; + if (dsp->sb_asp_mode & 4) + dsp->sb_asp_ram_index = 0; + sb_dsp_log("SB16 ASP set mode %02X\n", dsp->sb_asp_mode); + } /* else DSP Status (Obsolete) */ + break; + case 0x05: /* ASP set codec parameter */ + if (dsp->sb_type >= SB16) + sb_dsp_log("SB16 ASP unknown codec params %02X, %02X\n", dsp->sb_data[0], dsp->sb_data[1]); + break; + + case 0x09: /* AZTECH mode set */ + if (IS_AZTECH(dsp)) { + if (dsp->sb_data[0] == 0x00) { + sb_dsp_log("AZT2316A: WSS MODE!\n"); + azt2316a_enable_wss(1, dsp->parent); + } else if (dsp->sb_data[0] == 0x01) { + sb_dsp_log("AZT2316A: SB8PROV2 MODE!\n"); + azt2316a_enable_wss(0, dsp->parent); + } else + sb_dsp_log("AZT2316A: UNKNOWN MODE! = %02x\n", dsp->sb_data[0]); // sequences 0x02->0xFF, 0x04->0xFF seen + } + break; + + /* TODO: Some more data about the DSP registeres + * http://the.earth.li/~tfm/oldpage/sb_dsp.html + * http://www.synchrondata.com/pheaven/www/area19.htm + * http://www.dcee.net/Files/Programm/Sound/ + * 0E3h DSP Copyright SBPro2??? + * 0F0h Sine Generator SB + * 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 + * 0F2h IRQ Request, 8-bit SB + * 0F3h IRQ Request, 16-bit SB16 + * 0FBh DSP Status SB16 + * 0FCh DSP Auxiliary Status SB16 + * 0FDh DSP Command Status SB16 + */ } -} + /* Update 8051 ram with the last DSP command. + See https://github.com/joncampbell123/dosbox-x/issues/1044 */ + if (dsp->sb_type >= SB16) + dsp->sb_8051_ram[0x30] = dsp->sb_command; +} void sb_write(uint16_t a, uint8_t v, void *priv) @@ -845,178 +931,175 @@ sb_write(uint16_t a, uint8_t v, void *priv) sb_dsp_t *dsp = (sb_dsp_t *) priv; switch (a & 0xF) { - case 6: /* Reset */ - if (!dsp->uart_midi) { - if (!(v & 1) && (dsp->sbreset & 1)) { - sb_dsp_reset(dsp); - sb_add_data(dsp, 0xAA); - } - dsp->sbreset = v; - } - dsp->uart_midi = 0; - dsp->uart_irq = 0; - dsp->onebyte_midi = 0; - return; - case 0xC: /* Command/data write */ - if (dsp->uart_midi || dsp->onebyte_midi ) { - midi_raw_out_byte(v); - dsp->onebyte_midi = 0; - return; - } - timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); - if (dsp->asp_data_len) { - sb_dsp_log("ASP data %i\n", dsp->asp_data_len); - dsp->asp_data_len--; - if (!dsp->asp_data_len) - sb_add_data(dsp, 0); - return; - } - if (dsp->sb_data_stat == -1) { - dsp->sb_command = v; - if (v == 0x01) - sb_add_data(dsp, 0); - dsp->sb_data_stat++; - } else { - dsp->sb_data[dsp->sb_data_stat++] = v; - if (IS_AZTECH(dsp)) { - /* variable length commands */ - if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08) - sb_commands[dsp->sb_command] = 3; - else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07) - sb_commands[dsp->sb_command] = 2; - } - } - if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) { - sb_exec_command(dsp); - dsp->sb_data_stat = -1; - if (IS_AZTECH(dsp)) { - /* variable length commands */ - if (dsp->sb_command == 0x08) - sb_commands[dsp->sb_command] = 1; - } - } - break; + case 6: /* Reset */ + if (!dsp->uart_midi) { + if (!(v & 1) && (dsp->sbreset & 1)) { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; + } + dsp->uart_midi = 0; + dsp->uart_irq = 0; + dsp->onebyte_midi = 0; + return; + case 0xC: /* Command/data write */ + if (dsp->uart_midi || dsp->onebyte_midi) { + midi_raw_out_byte(v); + dsp->onebyte_midi = 0; + return; + } + timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); + if (dsp->asp_data_len) { + sb_dsp_log("ASP data %i\n", dsp->asp_data_len); + dsp->asp_data_len--; + if (!dsp->asp_data_len) + sb_add_data(dsp, 0); + return; + } + if (dsp->sb_data_stat == -1) { + dsp->sb_command = v; + if (v == 0x01) + sb_add_data(dsp, 0); + dsp->sb_data_stat++; + } else { + dsp->sb_data[dsp->sb_data_stat++] = v; + if (IS_AZTECH(dsp)) { + /* variable length commands */ + if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08) + sb_commands[dsp->sb_command] = 3; + else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07) + sb_commands[dsp->sb_command] = 2; + } + } + if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) { + sb_exec_command(dsp); + dsp->sb_data_stat = -1; + if (IS_AZTECH(dsp)) { + /* variable length commands */ + if (dsp->sb_command == 0x08) + sb_commands[dsp->sb_command] = 1; + } + } + break; } } - uint8_t sb_read(uint16_t a, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *) priv; - uint8_t ret = 0x00; + uint8_t ret = 0x00; switch (a & 0xf) { - case 0xA: /* Read data */ - if (dsp->mpu && dsp->uart_midi) { - ret = MPU401_ReadData(dsp->mpu); - } else { - dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; - if (dsp->sb_read_rp != dsp->sb_read_wp) { - dsp->sb_read_rp++; - dsp->sb_read_rp &= 0xff; - } - return dsp->sbreaddat; - } - break; - case 0xC: /* Write data ready */ - if (dsp->sb_8_enable || dsp->sb_type >= SB16) - dsp->busy_count = (dsp->busy_count + 1) & 3; - else - dsp->busy_count = 0; - if (dsp->wb_full || (dsp->busy_count & 2)) { - dsp->wb_full = timer_is_enabled(&dsp->wb_timer); - if (IS_AZTECH(dsp)) { - sb_dsp_log("SB Write Data Aztech read 0x80\n"); - return 0x80; - } else { - sb_dsp_log("SB Write Data Creative read 0xff\n"); - return 0xff; - } - } - if (IS_AZTECH(dsp)) { - sb_dsp_log("SB Write Data Aztech read 0x00\n"); - ret = 0x00; - } else { - sb_dsp_log("SB Write Data Creative read 0x7f\n"); - ret = 0x7f; - } - break; - case 0xE: /* Read data ready */ - picintc(1 << dsp->sb_irqnum); - dsp->sb_irq8 = dsp->sb_irq16 = 0; - /* Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working. */ - if (IS_AZTECH(dsp)) { - sb_dsp_log("SB Read Data Aztech read %02X, Read RP = %d, Read WP = %d\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80, dsp->sb_read_rp, dsp->sb_read_wp); - ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80; - } else { - sb_dsp_log("SB Read Data Creative read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff); - ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; - } - break; - case 0xF: /* 16-bit ack */ - dsp->sb_irq16 = 0; - if (!dsp->sb_irq8) - picintc(1 << dsp->sb_irqnum); - sb_dsp_log("SB 16-bit ACK read 0xFF\n"); - ret = 0xff; - break; - } + case 0xA: /* Read data */ + if (dsp->mpu && dsp->uart_midi) { + ret = MPU401_ReadData(dsp->mpu); + } else { + dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; + if (dsp->sb_read_rp != dsp->sb_read_wp) { + dsp->sb_read_rp++; + dsp->sb_read_rp &= 0xff; + } + return dsp->sbreaddat; + } + break; + case 0xC: /* Write data ready */ + if (dsp->sb_8_enable || dsp->sb_type >= SB16) + dsp->busy_count = (dsp->busy_count + 1) & 3; + else + dsp->busy_count = 0; + if (dsp->wb_full || (dsp->busy_count & 2)) { + dsp->wb_full = timer_is_enabled(&dsp->wb_timer); + if (IS_AZTECH(dsp)) { + sb_dsp_log("SB Write Data Aztech read 0x80\n"); + return 0x80; + } else { + sb_dsp_log("SB Write Data Creative read 0xff\n"); + return 0xff; + } + } + if (IS_AZTECH(dsp)) { + sb_dsp_log("SB Write Data Aztech read 0x00\n"); + ret = 0x00; + } else { + sb_dsp_log("SB Write Data Creative read 0x7f\n"); + ret = 0x7f; + } + break; + case 0xE: /* Read data ready */ + dsp->irq_update(dsp->irq_priv, 0); + dsp->sb_irq8 = dsp->sb_irq16 = 0; + /* Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working. */ + if (IS_AZTECH(dsp)) { + sb_dsp_log("SB Read Data Aztech read %02X, Read RP = %d, Read WP = %d\n", (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80, dsp->sb_read_rp, dsp->sb_read_wp); + ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80; + } else { + sb_dsp_log("SB Read Data Creative read %02X\n", (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff); + ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + } + break; + case 0xF: /* 16-bit ack */ + dsp->sb_irq16 = 0; + if (!dsp->sb_irq8) + dsp->irq_update(dsp->irq_priv, 0); + sb_dsp_log("SB 16-bit ACK read 0xFF\n"); + ret = 0xff; + break; + } - return ret; + return ret; } - -void -sb_dsp_input_msg(void *p, uint8_t *msg) +void +sb_dsp_input_msg(void *p, uint8_t *msg, uint32_t len) { sb_dsp_t *dsp = (sb_dsp_t *) p; - uint8_t len = msg[3], i = 0; + uint8_t i = 0; - sb_dsp_log("MIDI in sysex = %d, uart irq = %d, msg = %d\n", dsp->midi_in_sysex, dsp->uart_irq, msg[3]); + sb_dsp_log("MIDI in sysex = %d, uart irq = %d, msg = %d\n", dsp->midi_in_sysex, dsp->uart_irq, len); if (!dsp->uart_irq && !dsp->midi_in_poll && (dsp->mpu != NULL)) { - MPU401_InputMsg(dsp->mpu, msg); - return; + MPU401_InputMsg(dsp->mpu, msg, len); + return; } if (dsp->midi_in_sysex) - return; + return; if (dsp->uart_irq) { - for (i = 0; i < len; i++) - sb_add_data(dsp, msg[i]); - sb_irq(dsp, 1); - } else if (dsp->midi_in_poll) { - for (i = 0; i < len; i++) - sb_add_data(dsp, msg[i]); + for (i = 0; i < len; i++) + sb_add_data(dsp, msg[i]); + sb_irq(dsp, 1); + } else if (dsp->midi_in_poll) { + for (i = 0; i < len; i++) + sb_add_data(dsp, msg[i]); } } - -int -sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +int +sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) { sb_dsp_t *dsp = (sb_dsp_t *) p; - uint32_t i; + uint32_t i; if (!dsp->uart_irq && !dsp->midi_in_poll && (dsp->mpu != NULL)) - return MPU401_InputSysex(dsp->mpu, buffer, len, abort); + return MPU401_InputSysex(dsp->mpu, buffer, len, abort); if (abort) { - dsp->midi_in_sysex = 0; - return 0; + dsp->midi_in_sysex = 0; + return 0; } dsp->midi_in_sysex = 1; for (i = 0; i < len; i++) { - if (dsp->sb_read_rp == dsp->sb_read_wp) { - sb_dsp_log("Length sysex SB = %d\n", len - i); - return (len - i); - } + if (dsp->sb_read_rp == dsp->sb_read_wp) { + sb_dsp_log("Length sysex SB = %d\n", len - i); + return (len - i); + } - sb_add_data(dsp, buffer[i]); + sb_add_data(dsp, buffer[i]); } dsp->midi_in_sysex = 0; @@ -1024,19 +1107,28 @@ sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) return 0; } - void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) { - dsp->sb_type = type; + dsp->sb_type = type; dsp->sb_subtype = subtype; - dsp->parent = parent; + dsp->parent = parent; /* Default values. Use sb_dsp_setxxx() methods to change. */ - dsp->sb_irqnum = 7; - dsp->sb_8_dmanum = 1; + dsp->sb_irqnum = 7; + dsp->sb_8_dmanum = 1; dsp->sb_16_dmanum = 5; - dsp->mpu = NULL; + dsp->mpu = NULL; + + dsp->sbleftright_default = 0; + + dsp->irq_update = sb_irq_update_pic; + dsp->irq_priv = dsp; + dsp->dma_readb = sb_8_read_dma; + dsp->dma_readw = sb_16_read_dma; + dsp->dma_writeb = sb_8_write_dma; + dsp->dma_writew = sb_16_write_dma; + dsp->dma_priv = dsp; sb_doreset(dsp); @@ -1046,406 +1138,433 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) /* Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when a set frequency command is sent. */ - recalc_sb16_filter(3200*2); -} + recalc_sb16_filter(0, 3200 * 2); + recalc_sb16_filter(1, 44100); + /* Initialize SB16 8051 RAM and ASP internal RAM */ + memset(dsp->sb_8051_ram, 0x00, sizeof(dsp->sb_8051_ram)); + dsp->sb_8051_ram[0x0e] = 0xff; + dsp->sb_8051_ram[0x0f] = 0x07; + dsp->sb_8051_ram[0x37] = 0x38; + + memset(dsp->sb_asp_ram, 0xff, sizeof(dsp->sb_asp_ram)); +} void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) { sb_dsp_log("sb_dsp_setaddr : %04X\n", addr); if (dsp->sb_addr != 0) { - io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); - io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); } dsp->sb_addr = addr; if (dsp->sb_addr != 0) { - io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); - io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); } } - void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) { dsp->stereo = stereo; } +void +sb_dsp_irq_attach(sb_dsp_t *dsp, void (*irq_update)(void *priv, int set), void *priv) +{ + dsp->irq_update = irq_update; + dsp->irq_priv = priv; +} + +void +sb_dsp_dma_attach(sb_dsp_t *dsp, + int (*dma_readb)(void *priv), + int (*dma_readw)(void *priv), + int (*dma_writeb)(void *priv, uint8_t val), + int (*dma_writew)(void *priv, uint16_t val), + void *priv) +{ + dsp->dma_readb = dma_readb; + dsp->dma_readw = dma_readw; + dsp->dma_writeb = dma_writeb; + dsp->dma_writew = dma_writew; + dsp->dma_priv = priv; +} void pollsb(void *p) { sb_dsp_t *dsp = (sb_dsp_t *) p; - int tempi, ref; - int data[2]; + int tempi, ref; + int data[2]; timer_advance_u64(&dsp->output_timer, dsp->sblatcho); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) { - sb_dsp_update(dsp); + sb_dsp_update(dsp); - switch (dsp->sb_8_format) { - case 0x00: /* Mono unsigned */ - data[0] = sb_8_read_dma(dsp); - /* Needed to prevent clicking in Worms, which programs the DSP to - auto-init DMA but programs the DMA controller to single cycle */ - if (data[0] == DMA_NODATA) - break; - dsp->sbdat = (data[0] ^ 0x80) << 8; - if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - sb_dsp_log("pollsb: Mono unsigned, dsp->stereo, %s channel, %04X\n", - dsp->sbleftright ? "left" : "right", dsp->sbdat); - if (dsp->sbleftright) - dsp->sbdatl = dsp->sbdat; - else - dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - dsp->sb_8_length--; - break; - case 0x10: /* Mono signed */ - data[0] = sb_8_read_dma(dsp); - if (data[0] == DMA_NODATA) - break; - dsp->sbdat = data[0] << 8; - if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - sb_dsp_log("pollsb: Mono signed, dsp->stereo, %s channel, %04X\n", - dsp->sbleftright ? "left" : "right", data[0], dsp->sbdat); - if (dsp->sbleftright) - dsp->sbdatl = dsp->sbdat; - else - dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - dsp->sb_8_length--; - break; - case 0x20: /* Stereo unsigned */ - data[0] = sb_8_read_dma(dsp); - data[1] = sb_8_read_dma(dsp); - if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) - break; - dsp->sbdatl = (data[0] ^ 0x80) << 8; - dsp->sbdatr = (data[1] ^ 0x80) << 8; - dsp->sb_8_length -= 2; - break; - case 0x30: /* Stereo signed */ - data[0] = sb_8_read_dma(dsp); - data[1] = sb_8_read_dma(dsp); - if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) - break; - dsp->sbdatl = data[0] << 8; - dsp->sbdatr = data[1] << 8; - dsp->sb_8_length -= 2; - break; + switch (dsp->sb_8_format) { + case 0x00: /* Mono unsigned */ + data[0] = dsp->dma_readb(dsp->dma_priv); + /* Needed to prevent clicking in Worms, which programs the DSP to + auto-init DMA but programs the DMA controller to single cycle */ + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = (data[0] ^ 0x80) << 8; + if (dsp->stereo) { + sb_dsp_log("pollsb: Mono unsigned, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x10: /* Mono signed */ + data[0] = dsp->dma_readb(dsp->dma_priv); + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = data[0] << 8; + if (dsp->stereo) { + sb_dsp_log("pollsb: Mono signed, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", data[0], dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x20: /* Stereo unsigned */ + data[0] = dsp->dma_readb(dsp->dma_priv); + data[1] = dsp->dma_readb(dsp->dma_priv); + if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) + break; + dsp->sbdatl = (data[0] ^ 0x80) << 8; + dsp->sbdatr = (data[1] ^ 0x80) << 8; + dsp->sb_8_length -= 2; + break; + case 0x30: /* Stereo signed */ + data[0] = dsp->dma_readb(dsp->dma_priv); + data[1] = dsp->dma_readb(dsp->dma_priv); + if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) + break; + dsp->sbdatl = data[0] << 8; + dsp->sbdatr = data[1] << 8; + dsp->sb_8_length -= 2; + break; - case ADPCM_4: - if (dsp->sbdacpos) - tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; - else - tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; - if (tempi < 0) - tempi = 0; - if (tempi > 63) - tempi = 63; + case ADPCM_4: + if (dsp->sbdacpos) + tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; + else + tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; + if (tempi < 0) + tempi = 0; + if (tempi > 63) + tempi = 63; - ref = dsp->sbref + scaleMap4[tempi]; - if (ref > 0xff) - dsp->sbref = 0xff; - else if (ref < 0x00) - dsp->sbref = 0x00; - else - dsp->sbref = ref; + ref = dsp->sbref + scaleMap4[tempi]; + if (ref > 0xff) + dsp->sbref = 0xff; + else if (ref < 0x00) + dsp->sbref = 0x00; + else + dsp->sbref = ref; - dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; - dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; - dsp->sbdacpos++; + dsp->sbdacpos++; - if (dsp->sbdacpos >= 2) { - dsp->sbdacpos = 0; - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } + if (dsp->sbdacpos >= 2) { + dsp->sbdacpos = 0; + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + } - if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - sb_dsp_log("pollsb: ADPCM 4, dsp->stereo, %s channel, %04X\n", - dsp->sbleftright ? "left" : "right", dsp->sbdat); - if (dsp->sbleftright) - dsp->sbdatl = dsp->sbdat; - else - dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - break; + if (dsp->stereo) { + sb_dsp_log("pollsb: ADPCM 4, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; - case ADPCM_26: - if (!dsp->sbdacpos) - tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; - else if (dsp->sbdacpos == 1) - tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; - else - tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; + case ADPCM_26: + if (!dsp->sbdacpos) + tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; + else if (dsp->sbdacpos == 1) + tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; + else + tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; - if (tempi < 0) - tempi = 0; - if (tempi > 39) - tempi = 39; + if (tempi < 0) + tempi = 0; + if (tempi > 39) + tempi = 39; - ref = dsp->sbref + scaleMap26[tempi]; - if (ref > 0xff) - dsp->sbref = 0xff; - else if (ref < 0x00) - dsp->sbref = 0x00; - else - dsp->sbref = ref; - dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; + ref = dsp->sbref + scaleMap26[tempi]; + if (ref > 0xff) + dsp->sbref = 0xff; + else if (ref < 0x00) + dsp->sbref = 0x00; + else + dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; - dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; - dsp->sbdacpos++; - if (dsp->sbdacpos >= 3) { - dsp->sbdacpos = 0; - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } + dsp->sbdacpos++; + if (dsp->sbdacpos >= 3) { + dsp->sbdacpos = 0; + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + } - if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - sb_dsp_log("pollsb: ADPCM 26, dsp->stereo, %s channel, %04X\n", - dsp->sbleftright ? "left" : "right", dsp->sbdat); - if (dsp->sbleftright) - dsp->sbdatl = dsp->sbdat; - else - dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - break; + if (dsp->stereo) { + sb_dsp_log("pollsb: ADPCM 26, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; - case ADPCM_2: - tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; - if (tempi < 0) - tempi = 0; - if (tempi > 23) - tempi = 23; + case ADPCM_2: + tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; + if (tempi < 0) + tempi = 0; + if (tempi > 23) + tempi = 23; - ref = dsp->sbref + scaleMap2[tempi]; - if (ref > 0xff) - dsp->sbref = 0xff; - else if (ref < 0x00) - dsp->sbref = 0x00; - else - dsp->sbref = ref; - dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; + ref = dsp->sbref + scaleMap2[tempi]; + if (ref > 0xff) + dsp->sbref = 0xff; + else if (ref < 0x00) + dsp->sbref = 0x00; + else + dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; - dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; - dsp->sbdacpos++; - if (dsp->sbdacpos >= 4) { - dsp->sbdacpos = 0; - dsp->sbdat2 = sb_8_read_dma(dsp); - } + dsp->sbdacpos++; + if (dsp->sbdacpos >= 4) { + dsp->sbdacpos = 0; + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + } - if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - sb_dsp_log("pollsb: ADPCM 2, dsp->stereo, %s channel, %04X\n", - dsp->sbleftright ? "left" : "right", dsp->sbdat); - if (dsp->sbleftright) - dsp->sbdatl = dsp->sbdat; - else - dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - break; - } + if (dsp->stereo) { + sb_dsp_log("pollsb: ADPCM 2, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + } - if (dsp->sb_8_length < 0) { - if (dsp->sb_8_autoinit) - dsp->sb_8_length = dsp->sb_8_autolen; - else { - dsp->sb_8_enable = 0; - timer_disable(&dsp->output_timer); - } - sb_irq(dsp, 1); - } - } if (dsp->sb_16_enable && !dsp->sb_16_pause && (dsp->sb_pausetime < 0LL) && dsp->sb_16_output) { - sb_dsp_update(dsp); + if (dsp->sb_8_length < 0) { + if (dsp->sb_8_autoinit) + dsp->sb_8_length = dsp->sb_8_origlength = dsp->sb_8_autolen; + else { + dsp->sb_8_enable = 0; + timer_disable(&dsp->output_timer); + } + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && (dsp->sb_pausetime < 0LL) && dsp->sb_16_output) { + sb_dsp_update(dsp); - switch (dsp->sb_16_format) { - case 0x00: /* Mono unsigned */ - data[0] = sb_16_read_dma(dsp); - if (data[0] == DMA_NODATA) - break; - dsp->sbdatl = dsp->sbdatr = data[0] ^ 0x8000; - dsp->sb_16_length--; - break; - case 0x10: /* Mono signed */ - data[0] = sb_16_read_dma(dsp); - if (data[0] == DMA_NODATA) - break; - dsp->sbdatl = dsp->sbdatr = data[0]; - dsp->sb_16_length--; - break; - case 0x20: /* Stereo unsigned */ - data[0] = sb_16_read_dma(dsp); - data[1] = sb_16_read_dma(dsp); - if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) - break; - dsp->sbdatl = data[0] ^ 0x8000; - dsp->sbdatr = data[1] ^ 0x8000; - dsp->sb_16_length -= 2; - break; - case 0x30: /* Stereo signed */ - data[0] = sb_16_read_dma(dsp); - data[1] = sb_16_read_dma(dsp); - if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) - break; - dsp->sbdatl = data[0]; - dsp->sbdatr = data[1]; - dsp->sb_16_length -= 2; - break; - } + switch (dsp->sb_16_format) { + case 0x00: /* Mono unsigned */ + data[0] = dsp->dma_readw(dsp->dma_priv); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0] ^ 0x8000; + dsp->sb_16_length--; + break; + case 0x10: /* Mono signed */ + data[0] = dsp->dma_readw(dsp->dma_priv); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0]; + dsp->sb_16_length--; + break; + case 0x20: /* Stereo unsigned */ + data[0] = dsp->dma_readw(dsp->dma_priv); + data[1] = dsp->dma_readw(dsp->dma_priv); + if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) + break; + dsp->sbdatl = data[0] ^ 0x8000; + dsp->sbdatr = data[1] ^ 0x8000; + dsp->sb_16_length -= 2; + break; + case 0x30: /* Stereo signed */ + data[0] = dsp->dma_readw(dsp->dma_priv); + data[1] = dsp->dma_readw(dsp->dma_priv); + if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) + break; + dsp->sbdatl = data[0]; + dsp->sbdatr = data[1]; + dsp->sb_16_length -= 2; + break; + } - if (dsp->sb_16_length < 0) { - sb_dsp_log("16DMA over %i\n", dsp->sb_16_autoinit); - if (dsp->sb_16_autoinit) - dsp->sb_16_length = dsp->sb_16_autolen; - else { - dsp->sb_16_enable = 0; - timer_disable(&dsp->output_timer); - } - sb_irq(dsp, 0); - } + if (dsp->sb_16_length < 0) { + sb_dsp_log("16DMA over %i\n", dsp->sb_16_autoinit); + if (dsp->sb_16_autoinit) + dsp->sb_16_length = dsp->sb_16_origlength = dsp->sb_16_autolen; + else { + dsp->sb_16_enable = 0; + timer_disable(&dsp->output_timer); + } + sb_irq(dsp, 0); + } } if (dsp->sb_pausetime > -1) { - dsp->sb_pausetime--; - if (dsp->sb_pausetime < 0) { - sb_irq(dsp, 1); - if (!dsp->sb_8_enable) - timer_disable(&dsp->output_timer); - sb_dsp_log("SB pause over\n"); - } + dsp->sb_pausetime--; + if (dsp->sb_pausetime < 0) { + sb_irq(dsp, 1); + if (!dsp->sb_8_enable) + timer_disable(&dsp->output_timer); + sb_dsp_log("SB pause over\n"); + } } } - void sb_poll_i(void *p) { - sb_dsp_t *dsp = (sb_dsp_t *) p; - int processed = 0; + sb_dsp_t *dsp = (sb_dsp_t *) p; + int processed = 0; timer_advance_u64(&dsp->input_timer, dsp->sblatchi); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) { - switch (dsp->sb_8_format) { - case 0x00: /* Mono unsigned As the manual says, only the left channel is recorded */ - sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); - dsp->sb_8_length--; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - case 0x10: /* Mono signed As the manual says, only the left channel is recorded */ - sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); - dsp->sb_8_length--; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - case 0x20: /* Stereo unsigned */ - sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)^0x80); - sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)^0x80); - dsp->sb_8_length -= 2; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - case 0x30: /* Stereo signed */ - sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); - sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)); - dsp->sb_8_length -= 2; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - } + switch (dsp->sb_8_format) { + case 0x00: /* Mono unsigned As the manual says, only the left channel is recorded */ + dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80); + dsp->sb_8_length--; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + case 0x10: /* Mono signed As the manual says, only the left channel is recorded */ + dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8)); + dsp->sb_8_length--; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + case 0x20: /* Stereo unsigned */ + dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80); + dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read + 1] >> 8) ^ 0x80); + dsp->sb_8_length -= 2; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + case 0x30: /* Stereo signed */ + dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8)); + dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read + 1] >> 8)); + dsp->sb_8_length -= 2; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + } - if (dsp->sb_8_length < 0) { - if (dsp->sb_8_autoinit) - dsp->sb_8_length = dsp->sb_8_autolen; - else { - dsp->sb_8_enable = 0; - timer_disable(&dsp->input_timer); - } - sb_irq(dsp, 1); - } - processed = 1; + if (dsp->sb_8_length < 0) { + if (dsp->sb_8_autoinit) + dsp->sb_8_length = dsp->sb_8_origlength = dsp->sb_8_autolen; + else { + dsp->sb_8_enable = 0; + timer_disable(&dsp->input_timer); + } + sb_irq(dsp, 1); + } + processed = 1; } if (dsp->sb_16_enable && !dsp->sb_16_pause && (dsp->sb_pausetime < 0LL) && !dsp->sb_16_output) { - switch (dsp->sb_16_format) { - case 0x00: /* Unsigned mono. As the manual says, only the left channel is recorded */ - if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) - return; - dsp->sb_16_length--; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - case 0x10: /* Signed mono. As the manual says, only the left channel is recorded */ - if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) - return; - dsp->sb_16_length--; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - case 0x20: /* Unsigned stereo */ - if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) - return; - sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]^0x8000); - dsp->sb_16_length -= 2; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - case 0x30: /* Signed stereo */ - if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) - return; - sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]); - dsp->sb_16_length -= 2; - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; - break; - } + switch (dsp->sb_16_format) { + case 0x00: /* Unsigned mono. As the manual says, only the left channel is recorded */ + if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read] ^ 0x8000)) + return; + dsp->sb_16_length--; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + case 0x10: /* Signed mono. As the manual says, only the left channel is recorded */ + if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read])) + return; + dsp->sb_16_length--; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + case 0x20: /* Unsigned stereo */ + if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read] ^ 0x8000)) + return; + dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read + 1] ^ 0x8000); + dsp->sb_16_length -= 2; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + case 0x30: /* Signed stereo */ + if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read])) + return; + dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read + 1]); + dsp->sb_16_length -= 2; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + break; + } - if (dsp->sb_16_length < 0) { - if (dsp->sb_16_autoinit) - dsp->sb_16_length = dsp->sb_16_autolen; - else { - dsp->sb_16_enable = 0; - timer_disable(&dsp->input_timer); - } - sb_irq(dsp, 0); - } - processed = 1; + if (dsp->sb_16_length < 0) { + if (dsp->sb_16_autoinit) + dsp->sb_16_length = dsp->sb_16_origlength = dsp->sb_16_autolen; + else { + dsp->sb_16_enable = 0; + timer_disable(&dsp->input_timer); + } + sb_irq(dsp, 0); + } + processed = 1; } /* Assume this is direct mode */ if (!processed) { - dsp->record_pos_read += 2; - dsp->record_pos_read &= 0xFFFF; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; } } - -void sb_dsp_update(sb_dsp_t *dsp) +void +sb_dsp_update(sb_dsp_t *dsp) { if (dsp->muted) { - dsp->sbdatl = 0; - dsp->sbdatr = 0; + dsp->sbdatl = 0; + dsp->sbdatr = 0; } for (; dsp->pos < sound_pos_global; dsp->pos++) { - dsp->buffer[dsp->pos*2] = dsp->sbdatl; - dsp->buffer[dsp->pos*2 + 1] = dsp->sbdatr; + dsp->buffer[dsp->pos * 2] = dsp->sbdatl; + dsp->buffer[dsp->pos * 2 + 1] = dsp->sbdatr; } } - void sb_dsp_close(sb_dsp_t *dsp) { diff --git a/src/sound/snd_sn76489.c b/src/sound/snd_sn76489.c index 215cea02a..125eff4d6 100644 --- a/src/sound/snd_sn76489.c +++ b/src/sound/snd_sn76489.c @@ -1,253 +1,320 @@ -#include #include -#include +#include #include -#include +#include #include +#include + #include <86box/86box.h> -#include <86box/io.h> #include <86box/device.h> +#include <86box/io.h> #include <86box/sound.h> #include <86box/snd_sn76489.h> - int sn76489_mute; - -static float volslog[16]= -{ - 0.00000f,0.59715f,0.75180f,0.94650f, - 1.19145f,1.50000f,1.88835f,2.37735f, - 2.99295f,3.76785f,4.74345f,5.97165f, - 7.51785f,9.46440f,11.9194f,15.0000f +static float volslog[16] = { + 0.00000f, 0.59715f, 0.75180f, 0.94650f, + 1.19145f, 1.50000f, 1.88835f, 2.37735f, + 2.99295f, 3.76785f, 4.74345f, 5.97165f, + 7.51785f, 9.46440f, 11.9194f, 15.0000f }; -void sn76489_update(sn76489_t *sn76489) +void +sn76489_update(sn76489_t *sn76489) { - for (; sn76489->pos < sound_pos_global; sn76489->pos++) - { - int c; - int16_t result = 0; - - for (c = 1; c < 4; c++) - { - if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]); - else result += (int16_t) (volslog[sn76489->vol[c]] * 127); + for (; sn76489->pos < sound_pos_global; sn76489->pos++) { + int c; + int16_t result = 0; - sn76489->count[c] -= (256 * sn76489->psgconst); - while ((int)sn76489->count[c] < 0) - { - sn76489->count[c] += sn76489->latch[c]; - sn76489->stat[c] = -sn76489->stat[c]; - } - } - result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2); + for (c = 1; c < 4; c++) { + if (sn76489->latch[c] > 256) + result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]); + else + result += (int16_t) (volslog[sn76489->vol[c]] * 127); - sn76489->count[0] -= (512 * sn76489->psgconst); - while ((int)sn76489->count[0] < 0 && sn76489->latch[0]) - { - sn76489->count[0] += (sn76489->latch[0] * 4); - if (!(sn76489->noise & 4)) - { - if (sn76489->shift & 1) - sn76489->shift |= 0x8000; - sn76489->shift >>= 1; - } - else - { - if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1)) - sn76489->shift |= 0x8000; - sn76489->shift >>= 1; - } - } - - sn76489->buffer[sn76489->pos] = result; + sn76489->count[c] -= (256 * sn76489->psgconst); + while ((int) sn76489->count[c] < 0) { + sn76489->count[c] += sn76489->latch[c]; + sn76489->stat[c] = -sn76489->stat[c]; + } } -} + result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2); -void sn76489_get_buffer(int32_t *buffer, int len, void *p) -{ - sn76489_t *sn76489 = (sn76489_t *)p; - - int c; - - sn76489_update(sn76489); - - if (!sn76489_mute) - { - for (c = 0; c < len * 2; c++) - buffer[c] += sn76489->buffer[c >> 1]; + sn76489->count[0] -= (512 * sn76489->psgconst); + while ((int) sn76489->count[0] < 0 && sn76489->latch[0]) { + sn76489->count[0] += (sn76489->latch[0] * 4); + if (!(sn76489->noise & 4)) { + if (sn76489->shift & 1) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } else { + if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1)) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } } - sn76489->pos = 0; + sn76489->buffer[sn76489->pos] = result; + } } -void sn76489_write(uint16_t addr, uint8_t data, void *p) +void +sn76489_get_buffer(int32_t *buffer, int len, void *p) { - sn76489_t *sn76489 = (sn76489_t *)p; - int freq; + sn76489_t *sn76489 = (sn76489_t *) p; - sn76489_update(sn76489); - - if (data & 0x80) - { - sn76489->firstdat = data; - switch (data & 0x70) - { - case 0: - sn76489->freqlo[3] = data & 0xf; - sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; - if (sn76489->extra_divide) - sn76489->latch[3] &= 0x3ff; - if (!sn76489->latch[3]) - sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; - sn76489->lasttone = 3; - break; - case 0x10: - data &= 0xf; - sn76489->vol[3] = 0xf - data; - break; - case 0x20: - sn76489->freqlo[2] = data & 0xf; - sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; - if (sn76489->extra_divide) - sn76489->latch[2] &= 0x3ff; - if (!sn76489->latch[2]) - sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; - sn76489->lasttone = 2; - break; - case 0x30: - data &= 0xf; - sn76489->vol[2] = 0xf - data; - break; - case 0x40: - sn76489->freqlo[1] = data & 0xf; - sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; - if (sn76489->extra_divide) - sn76489->latch[1] &= 0x3ff; - if (!sn76489->latch[1]) - sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; - sn76489->lasttone = 1; - break; - case 0x50: - data &= 0xf; - sn76489->vol[1] = 0xf - data; - break; - case 0x60: - if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) - sn76489->shift = 0x4000; - sn76489->noise = data & 0xf; - if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; - else sn76489->latch[0] = 0x400 << (data & 3); - if (sn76489->extra_divide) - sn76489->latch[0] &= 0x3ff; - if (!sn76489->latch[0]) - sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6; - break; - case 0x70: - data &= 0xf; - sn76489->vol[0] = 0xf - data; - break; - } + int c; + + sn76489_update(sn76489); + + if (!sn76489_mute) { + for (c = 0; c < len * 2; c++) + buffer[c] += sn76489->buffer[c >> 1]; + } + + sn76489->pos = 0; +} + +void +sn76489_write(uint16_t addr, uint8_t data, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *) p; + int freq; + + sn76489_update(sn76489); + + if (data & 0x80) { + sn76489->firstdat = data; + switch (data & 0x70) { + case 0: + sn76489->freqlo[3] = data & 0xf; + sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[3] &= 0x3ff; + if (!sn76489->latch[3]) + sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 3; + break; + case 0x10: + data &= 0xf; + sn76489->vol[3] = 0xf - data; + break; + case 0x20: + sn76489->freqlo[2] = data & 0xf; + sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[2] &= 0x3ff; + if (!sn76489->latch[2]) + sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 2; + break; + case 0x30: + data &= 0xf; + sn76489->vol[2] = 0xf - data; + break; + case 0x40: + sn76489->freqlo[1] = data & 0xf; + sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[1] &= 0x3ff; + if (!sn76489->latch[1]) + sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 1; + break; + case 0x50: + data &= 0xf; + sn76489->vol[1] = 0xf - data; + break; + case 0x60: + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) + sn76489->latch[0] = sn76489->latch[1]; + else + sn76489->latch[0] = 0x400 << (data & 3); + if (sn76489->extra_divide) + sn76489->latch[0] &= 0x3ff; + if (!sn76489->latch[0]) + sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6; + break; + case 0x70: + data &= 0xf; + sn76489->vol[0] = 0xf - data; + break; } - else - { - if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496)) - { - if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) - sn76489->shift = 0x4000; - sn76489->noise = data & 0xf; - if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; - else sn76489->latch[0] = 0x400 << (data & 3); - if (!sn76489->latch[0]) - sn76489->latch[0] = 1024 << 6; - } - else if ((sn76489->firstdat & 0x70) != 0x60) - { - sn76489->freqhi[sn76489->lasttone] = data & 0x7F; - freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); - if (sn76489->extra_divide) - freq &= 0x3ff; - if (!freq) - freq = sn76489->extra_divide ? 2048 : 1024; - if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) - sn76489->latch[0] = freq << 6; - sn76489->latch[sn76489->lasttone] = freq << 6; - } + } else { + if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496)) { + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) + sn76489->latch[0] = sn76489->latch[1]; + else + sn76489->latch[0] = 0x400 << (data & 3); + if (!sn76489->latch[0]) + sn76489->latch[0] = 1024 << 6; + } else if ((sn76489->firstdat & 0x70) != 0x60) { + sn76489->freqhi[sn76489->lasttone] = data & 0x7F; + freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); + if (sn76489->extra_divide) + freq &= 0x3ff; + if (!freq) + freq = sn76489->extra_divide ? 2048 : 1024; + if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) + sn76489->latch[0] = freq << 6; + sn76489->latch[sn76489->lasttone] = freq << 6; } + } } -void sn74689_set_extra_divide(sn76489_t *sn76489, int enable) +void +sn74689_set_extra_divide(sn76489_t *sn76489, int enable) { - sn76489->extra_divide = enable; + sn76489->extra_divide = enable; } -void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq) +void +sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq) { - sound_add_handler(sn76489_get_buffer, sn76489); + sound_add_handler(sn76489_get_buffer, sn76489); - sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6; - sn76489->vol[0] = 0; - sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8; - sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127; - srand(time(NULL)); - sn76489->count[0] = 0; - sn76489->count[1] = (rand()&0x3FF)<<6; - sn76489->count[2] = (rand()&0x3FF)<<6; - sn76489->count[3] = (rand()&0x3FF)<<6; - sn76489->noise = 3; - sn76489->shift = 0x4000; - sn76489->type = type; - sn76489->psgconst = (((double)freq / 64.0) / 48000.0); + sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6; + sn76489->vol[0] = 0; + sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8; + sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127; + srand(time(NULL)); + sn76489->count[0] = 0; + sn76489->count[1] = (rand() & 0x3FF) << 6; + sn76489->count[2] = (rand() & 0x3FF) << 6; + sn76489->count[3] = (rand() & 0x3FF) << 6; + sn76489->noise = 3; + sn76489->shift = 0x4000; + sn76489->type = type; + sn76489->psgconst = (((double) freq / 64.0) / 48000.0); - sn76489_mute = 0; + sn76489_mute = 0; - io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); + io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); } -void *sn76489_device_init(const device_t *info) +void * +sn76489_device_init(const device_t *info) { - sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); - memset(sn76489, 0, sizeof(sn76489_t)); + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); - sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545); + sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545); - return sn76489; + return sn76489; } -void *ncr8496_device_init(const device_t *info) +void * +ncr8496_device_init(const device_t *info) { - sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); - memset(sn76489, 0, sizeof(sn76489_t)); + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); - sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545); + sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545); - return sn76489; + return sn76489; } -void sn76489_device_close(void *p) +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +void * +tndy_device_init(const device_t *info) { - sn76489_t *sn76489 = (sn76489_t *)p; + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); - free(sn76489); + uint16_t addr = device_get_config_hex16("base"); + + sn76489_init(sn76489, addr, 0x0008, SN76496, 3579545); + + return sn76489; +} +#endif + +void +sn76489_device_close(void *p) +{ + sn76489_t *sn76489 = (sn76489_t *) p; + + free(sn76489); } -const device_t sn76489_device = -{ - "TI SN74689 PSG", - 0, - 0, - sn76489_device_init, - sn76489_device_close, - NULL, NULL, NULL, - NULL +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +static const device_config_t tndy_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0C0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x0C0", + .value = 0x0C0 + }, + { + .description = "0x1E0", + .value = 0x1E0 + }, + { + .description = "0x2C0", + .value = 0x2C0 + }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -const device_t ncr8496_device = -{ - "NCR8496 PSG", - 0, - 0, - ncr8496_device_init, - sn76489_device_close, - NULL, NULL, NULL, - NULL +#endif + +const device_t sn76489_device = { + .name = "TI SN74689 PSG", + .internal_name = "sn76489", + .flags = 0, + .local = 0, + .init = sn76489_device_init, + .close = sn76489_device_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; + +const device_t ncr8496_device = { + .name = "NCR8496 PSG", + .internal_name = "ncr8496", + .flags = 0, + .local = 0, + .init = ncr8496_device_init, + .close = sn76489_device_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) +const device_t tndy_device = { + .name = "TNDY", + .internal_name = "tndy", + .flags = DEVICE_ISA, + .local = 0, + .init = tndy_device_init, + .close = sn76489_device_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = tndy_config +}; +#endif diff --git a/src/sound/snd_speaker.c b/src/sound/snd_speaker.c index d2ed41b82..34d32c110 100644 --- a/src/sound/snd_speaker.c +++ b/src/sound/snd_speaker.c @@ -1,89 +1,85 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Emulation of the PC speaker. + * Emulation of the PC speaker. * * * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Sarah Walker, + * Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ -#include #include +#include #include #include + #include <86box/86box.h> #include <86box/timer.h> #include <86box/pit.h> -#include <86box/sound.h> #include <86box/snd_speaker.h> - +#include <86box/sound.h> int speaker_mute = 0, speaker_gated = 0; int speaker_enable = 0, was_speaker_enable = 0; int gated, speakval, speakon; - static int32_t speaker_buffer[SOUNDBUFLEN]; -static int speaker_pos = 0; - -static uint8_t speaker_mode = 0; -static double speaker_count = 65535.0; +static int speaker_pos = 0; +static uint8_t speaker_mode = 0; +static double speaker_count = 65535.0; void speaker_set_count(uint8_t new_m, int new_count) { - speaker_mode = new_m; + speaker_mode = new_m; speaker_count = (double) new_count; } - void speaker_update(void) { int32_t val; - double amplitude; + double amplitude; amplitude = ((speaker_count / 64.0) * 10240.0) - 5120.0; if (amplitude > 5120.0) - amplitude = 5120.0; + amplitude = 5120.0; if (speaker_pos < sound_pos_global) { - for (; speaker_pos < sound_pos_global; speaker_pos++) { - if (speaker_gated && was_speaker_enable) { - if ((speaker_mode == 0) || (speaker_mode == 4)) - val = (int32_t) amplitude; - else if (speaker_count < 64.0) - val = 0xa00; - else - val = speakon ? 0x1400 : 0; - } else { - if (speaker_mode == 1) - val = was_speaker_enable ? (int32_t) amplitude : 0; - else - val = was_speaker_enable ? 0x1400 : 0; - } + for (; speaker_pos < sound_pos_global; speaker_pos++) { + if (speaker_gated && was_speaker_enable) { + if ((speaker_mode == 0) || (speaker_mode == 4)) + val = (int32_t) amplitude; + else if (speaker_count < 64.0) + val = 0xa00; + else + val = speakon ? 0x1400 : 0; + } else { + if (speaker_mode == 1) + val = was_speaker_enable ? (int32_t) amplitude : 0; + else + val = was_speaker_enable ? 0x1400 : 0; + } - if (!speaker_enable) - was_speaker_enable = 0; + if (!speaker_enable) + was_speaker_enable = 0; - speaker_buffer[speaker_pos] = val; - } + speaker_buffer[speaker_pos] = val; + } } } - void speaker_get_buffer(int32_t *buffer, int len, void *p) { @@ -92,20 +88,20 @@ speaker_get_buffer(int32_t *buffer, int len, void *p) speaker_update(); if (!speaker_mute) { - for (c = 0; c < len * 2; c += 2) { - val = speaker_buffer[c >> 1]; - buffer[c] += val; - buffer[c + 1] += val; - } + for (c = 0; c < len * 2; c += 2) { + val = speaker_buffer[c >> 1]; + buffer[c] += val; + buffer[c + 1] += val; + } } speaker_pos = 0; } - void speaker_init(void) { + memset(speaker_buffer, 0, sizeof(speaker_buffer)); sound_add_handler(speaker_get_buffer, NULL); speaker_mute = 0; } diff --git a/src/sound/snd_ssi2001.c b/src/sound/snd_ssi2001.c index ee994389e..211091dfa 100644 --- a/src/sound/snd_ssi2001.c +++ b/src/sound/snd_ssi2001.c @@ -1,89 +1,141 @@ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H + #include <86box/86box.h> -#include <86box/io.h> #include <86box/device.h> -#include <86box/sound.h> +#include <86box/gameport.h> +#include <86box/io.h> #include <86box/snd_resid.h> +#include <86box/sound.h> - -typedef struct ssi2001_t -{ - void *psid; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; +typedef struct ssi2001_t { + void *psid; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + int gameport_enabled; } ssi2001_t; -static void ssi2001_update(ssi2001_t *ssi2001) +static void +ssi2001_update(ssi2001_t *ssi2001) { - if (ssi2001->pos >= sound_pos_global) - return; - - sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid); - ssi2001->pos = sound_pos_global; + if (ssi2001->pos >= sound_pos_global) + return; + + sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid); + ssi2001->pos = sound_pos_global; } -static void ssi2001_get_buffer(int32_t *buffer, int len, void *p) +static void +ssi2001_get_buffer(int32_t *buffer, int len, void *p) { - ssi2001_t *ssi2001 = (ssi2001_t *)p; - int c; + ssi2001_t *ssi2001 = (ssi2001_t *) p; + int c; - ssi2001_update(ssi2001); - - for (c = 0; c < len * 2; c++) - buffer[c] += ssi2001->buffer[c >> 1] / 2; + ssi2001_update(ssi2001); - ssi2001->pos = 0; + for (c = 0; c < len * 2; c++) + buffer[c] += ssi2001->buffer[c >> 1] / 2; + + ssi2001->pos = 0; } -static uint8_t ssi2001_read(uint16_t addr, void *p) +static uint8_t +ssi2001_read(uint16_t addr, void *p) { - ssi2001_t *ssi2001 = (ssi2001_t *)p; - - ssi2001_update(ssi2001); - - return sid_read(addr, p); + ssi2001_t *ssi2001 = (ssi2001_t *) p; + + ssi2001_update(ssi2001); + + return sid_read(addr, p); } -static void ssi2001_write(uint16_t addr, uint8_t val, void *p) +static void +ssi2001_write(uint16_t addr, uint8_t val, void *p) { - ssi2001_t *ssi2001 = (ssi2001_t *)p; - - ssi2001_update(ssi2001); - sid_write(addr, val, p); + ssi2001_t *ssi2001 = (ssi2001_t *) p; + + ssi2001_update(ssi2001); + sid_write(addr, val, p); } -void *ssi2001_init(const device_t *info) +void * +ssi2001_init(const device_t *info) { - ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); - memset(ssi2001, 0, sizeof(ssi2001_t)); + ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); + memset(ssi2001, 0, sizeof(ssi2001_t)); - ssi2001->psid = sid_init(); - sid_reset(ssi2001->psid); - io_sethandler(0x0280, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); - sound_add_handler(ssi2001_get_buffer, ssi2001); - return ssi2001; + ssi2001->psid = sid_init(); + sid_reset(ssi2001->psid); + uint16_t addr = device_get_config_hex16("base"); + ssi2001->gameport_enabled = device_get_config_int("gameport"); + io_sethandler(addr, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); + if (ssi2001->gameport_enabled) + gameport_remap(gameport_add(&gameport_201_device), 0x201); + sound_add_handler(ssi2001_get_buffer, ssi2001); + return ssi2001; } -void ssi2001_close(void *p) +void +ssi2001_close(void *p) { - ssi2001_t *ssi2001 = (ssi2001_t *)p; - - sid_close(ssi2001->psid); + ssi2001_t *ssi2001 = (ssi2001_t *) p; - free(ssi2001); + sid_close(ssi2001->psid); + + free(ssi2001); } +static const device_config_t ssi2001_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x280, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x280", + .value = 0x280 + }, + { + .description = "0x2A0", + .value = 0x2A0 + }, + { + .description = "0x2C0", + .value = 0x2C0 + }, + { + .description = "0x2E0", + .value = 0x2E0 + }, + { .description = "" } + } + }, + { "gameport", "Enable Game port", CONFIG_BINARY, "", 1 }, + { "", "", -1 } +// clang-format off +}; + const device_t ssi2001_device = { - "Innovation SSI-2001", - 0, 0, - ssi2001_init, ssi2001_close, NULL, - NULL, NULL, NULL, - NULL + .name = "Innovation SSI-2001", + .internal_name = "ssi2001", + .flags = DEVICE_ISA, + .local = 0, + .init = ssi2001_init, + .close = ssi2001_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ssi2001_config }; diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 0dc3d2f6b..b4859e128 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -1,250 +1,296 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Windows Sound System emulation. + * Windows Sound System emulation. * * * - * Authors: Sarah Walker, - * TheCollector1995, + * Authors: Sarah Walker, + * TheCollector1995, * - * Copyright 2012-2018 Sarah Walker. - * Copyright 2018 TheCollector1995. + * Copyright 2012-2018 Sarah Walker. + * Copyright 2018 TheCollector1995. */ -#include +#include #include -#include +#include #include +#include #include -#include + #include <86box/86box.h> +#include <86box/device.h> +#include <86box/dma.h> #include <86box/io.h> -#include <86box/timer.h> #include <86box/mca.h> #include <86box/pic.h> -#include <86box/dma.h> -#include <86box/device.h> #include <86box/sound.h> +#include <86box/timer.h> #include <86box/snd_ad1848.h> #include <86box/snd_opl.h> +/* 530, 11, 3 - 530=23 + * 530, 11, 1 - 530=22 + * 530, 11, 0 - 530=21 + * 530, 10, 1 - 530=1a + * 530, 9, 1 - 530=12 + * 530, 7, 1 - 530=0a + * 604, 11, 1 - 530=22 + * e80, 11, 1 - 530=22 + * f40, 11, 1 - 530=22 + */ -/*530, 11, 3 - 530=23*/ -/*530, 11, 1 - 530=22*/ -/*530, 11, 0 - 530=21*/ -/*530, 10, 1 - 530=1a*/ -/*530, 9, 1 - 530=12*/ -/*530, 7, 1 - 530=0a*/ -/*604, 11, 1 - 530=22*/ -/*e80, 11, 1 - 530=22*/ -/*f40, 11, 1 - 530=22*/ +static const int wss_dma[4] = { 0, 0, 1, 3 }; +static const int wss_irq[8] = { 5, 7, 9, 10, 11, 12, 14, 15 }; /* W95 only uses 7-9, others may be wrong */ +typedef struct wss_t { + uint8_t config; -static int wss_dma[4] = {0, 0, 1, 3}; -static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ + ad1848_t ad1848; + fm_drv_t opl; -typedef struct wss_t -{ - uint8_t config; - - ad1848_t ad1848; - opl_t opl; - - int opl_enabled; - uint8_t pos_regs[8]; + int opl_enabled; + uint8_t pos_regs[8]; } wss_t; -uint8_t wss_read(uint16_t addr, void *p) +uint8_t +wss_read(uint16_t addr, void *priv) { - wss_t *wss = (wss_t *)p; - uint8_t temp; - temp = 4 | (wss->config & 0x40); - return temp; + wss_t *wss = (wss_t *) priv; + return 4 | (wss->config & 0x40); } -void wss_write(uint16_t addr, uint8_t val, void *p) +void +wss_write(uint16_t addr, uint8_t val, void *priv) { - wss_t *wss = (wss_t *)p; + wss_t *wss = (wss_t *) priv; - wss->config = val; - ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); - ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); } -static void wss_get_buffer(int32_t *buffer, int len, void *p) +static void +wss_get_buffer(int32_t *buffer, int len, void *priv) { - wss_t *wss = (wss_t *)p; - int c; + wss_t *wss = (wss_t *) priv; + int c; - opl3_update2(&wss->opl); - ad1848_update(&wss->ad1848); - for (c = 0; c < len * 2; c++) { - buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); - } + int32_t *opl_buf = wss->opl.update(wss->opl.priv); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) { + buffer[c] += opl_buf[c]; + buffer[c] += wss->ad1848.buffer[c] / 2; + } - wss->opl.pos = 0; - wss->ad1848.pos = 0; + wss->opl.reset_buffer(wss->opl.priv); + wss->ad1848.pos = 0; } -void *wss_init(const device_t *info) +void * +wss_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - uint16_t addr = device_get_config_hex16("base"); - wss->opl_enabled = device_get_config_int("opl"); + uint16_t addr = device_get_config_hex16("base"); + wss->opl_enabled = device_get_config_int("opl"); - if (wss->opl_enabled) - opl3_init(&wss->opl); - - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); + if (wss->opl_enabled) + fm_driver_get(FM_YMF262, &wss->opl); - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - if (wss->opl_enabled) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - sound_add_handler(wss_get_buffer, wss); + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, + wss->opl.read, NULL, NULL, + wss->opl.write, NULL, NULL, + wss->opl.priv); - return wss; + io_sethandler(addr, 0x0004, + wss_read, NULL, NULL, + wss_write, NULL, NULL, + wss); + io_sethandler(addr + 4, 0x0004, + ad1848_read, NULL, NULL, + ad1848_write, NULL, NULL, + &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; } -static uint8_t ncr_audio_mca_read(int port, void *p) +static uint8_t +ncr_audio_mca_read(int port, void *priv) { - wss_t *wss = (wss_t *)p; - - return wss->pos_regs[port & 7]; + wss_t *wss = (wss_t *) priv; + return wss->pos_regs[port & 7]; } -static void ncr_audio_mca_write(int port, uint8_t val, void *p) +static void +ncr_audio_mca_write(int port, uint8_t val, void *priv) { - wss_t *wss = (wss_t *)p; - uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; - uint16_t addr; + wss_t *wss = (wss_t *) priv; + uint16_t ports[4] = { 0x530, 0xE80, 0xF40, 0x604 }; + uint16_t addr; - if (port < 0x102) - return; + if (port < 0x102) + return; - wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; - - io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; - wss->pos_regs[port & 7] = val; + io_removehandler(0x0388, 0x0004, + wss->opl.read, NULL, NULL, + wss->opl.write, NULL, NULL, + wss->opl.priv); + io_removehandler(addr, 0x0004, + wss_read, NULL, NULL, + wss_write, NULL, NULL, + wss); + io_removehandler(addr + 4, 0x0004, + ad1848_read, NULL, NULL, + ad1848_write, NULL, NULL, + &wss->ad1848); - if (wss->pos_regs[2] & 1) { - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + wss->pos_regs[port & 7] = val; - if (wss->opl_enabled) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - } + if (wss->pos_regs[2] & 1) { + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, + wss->opl.read, NULL, NULL, + wss->opl.write, NULL, NULL, + wss->opl.priv); + + io_sethandler(addr, 0x0004, + wss_read, NULL, NULL, + wss_write, NULL, NULL, + wss); + io_sethandler(addr + 4, 0x0004, + ad1848_read, NULL, NULL, + ad1848_write, NULL, NULL, + &wss->ad1848); + } } -static uint8_t ncr_audio_mca_feedb(void *p) +static uint8_t +ncr_audio_mca_feedb(void *priv) { - wss_t *wss = (wss_t *)p; - - return (wss->pos_regs[2] & 1); + wss_t *wss = (wss_t *) priv; + return (wss->pos_regs[2] & 1); } -void *ncr_audio_init(const device_t *info) +void * +ncr_audio_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + fm_driver_get(FM_YMF262, &wss->opl); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); + wss->pos_regs[0] = 0x16; + wss->pos_regs[1] = 0x51; - mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); - wss->pos_regs[0] = 0x16; - wss->pos_regs[1] = 0x51; - - sound_add_handler(wss_get_buffer, wss); + sound_add_handler(wss_get_buffer, wss); - return wss; + return wss; } -void wss_close(void *p) +void +wss_close(void *priv) { - wss_t *wss = (wss_t *)p; - - free(wss); + wss_t *wss = (wss_t *) priv; + free(wss); } -void wss_speed_changed(void *p) +void +wss_speed_changed(void *priv) { - wss_t *wss = (wss_t *)p; - - ad1848_speed_changed(&wss->ad1848); + wss_t *wss = (wss_t *) priv; + ad1848_speed_changed(&wss->ad1848); } -static const device_config_t wss_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x530, - { - { - "0x530", 0x530 - }, - { - "0x604", 0x604 - }, - { - "0xe80", 0xe80 - }, - { - "0xf40", 0xf40 - }, - { - "" - } - } - }, - { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 +static const device_config_t wss_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x530, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x530", + .value = 0x530 + }, + { + .description = "0x604", + .value = 0x604 + }, + { + .description = "0xe80", + .value = 0xe80 + }, + { + .description = "0xf40", + .value = 0xf40 + }, + { .description = "" } } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; -const device_t wss_device = -{ - "Windows Sound System", - DEVICE_ISA | DEVICE_AT, 0, - wss_init, wss_close, NULL, - NULL, - wss_speed_changed, - NULL, - wss_config +const device_t wss_device = { + .name = "Windows Sound System", + .internal_name = "wss", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = wss_init, + .close = wss_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = wss_speed_changed, + .force_redraw = NULL, + .config = wss_config }; -const device_t ncr_business_audio_device = -{ - "NCR Business Audio", - DEVICE_MCA, 0, - ncr_audio_init, wss_close, NULL, - NULL, - wss_speed_changed, - NULL, - NULL +const device_t ncr_business_audio_device = { + .name = "NCR Business Audio", + .internal_name = "ncraudio", + .flags = DEVICE_MCA, + .local = 0, + .init = ncr_audio_init, + .close = wss_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = wss_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sound/snd_ym7128.c b/src/sound/snd_ym7128.c index 42d21ba63..a6398628a 100644 --- a/src/sound/snd_ym7128.c +++ b/src/sound/snd_ym7128.c @@ -1,138 +1,153 @@ -#include #include +#include #include #include + #include <86box/86box.h> #include <86box/snd_ym7128.h> - static int attenuation[32]; static int tap_position[32]; - -void ym7128_init(ym7128_t *ym7128) +void +ym7128_init(ym7128_t *ym7128) { - int c; - double out = 65536.0; - - for (c = 0; c < 32; c++) - tap_position[c] = c * (2400 / 31); + int c; + double out = 65536.0; - for (c = 31; c >= 1; c--) - { - attenuation[c] = (int)out; - out /= 1.25963; /*2 dB steps*/ - } - attenuation[0] = 0; + for (c = 0; c < 32; c++) + tap_position[c] = c * (2400 / 31); + + for (c = 31; c >= 1; c--) { + attenuation[c] = (int) out; + out /= 1.25963; /*2 dB steps*/ + } + attenuation[0] = 0; } #define GET_ATTENUATION(val) (val & 0x20) ? -attenuation[val & 0x1f] : attenuation[val & 0x1f] -void ym7128_write(ym7128_t *ym7128, uint8_t val) +void +ym7128_write(ym7128_t *ym7128, uint8_t val) { - int new_dat = val & 1; - int new_sci = val & 2; - int new_a0 = val & 4; - if (!ym7128->sci && new_sci) - ym7128->dat = (ym7128->dat << 1) | new_dat; - - if (ym7128->a0 != new_a0) - { - if (!ym7128->a0) - ym7128->reg_sel = ym7128->dat & 0x1f; - else - { - switch (ym7128->reg_sel) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); - break; - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); - break; - - case 0x10: - ym7128->vm = GET_ATTENUATION(ym7128->dat); - break; - case 0x11: - ym7128->vc = GET_ATTENUATION(ym7128->dat); - break; - case 0x12: - ym7128->vl = GET_ATTENUATION(ym7128->dat); - break; - case 0x13: - ym7128->vr = GET_ATTENUATION(ym7128->dat); - break; + int new_dat = val & 1; + int new_sci = val & 2; + int new_a0 = val & 4; + if (!ym7128->sci && new_sci) + ym7128->dat = (ym7128->dat << 1) | new_dat; - case 0x14: - ym7128->c0 = (ym7128->dat & 0x3f) << 6; - if (ym7128->dat & 0x20) - ym7128->c0 |= 0xfffff000; - break; - case 0x15: - ym7128->c1 = (ym7128->dat & 0x3f) << 6; - if (ym7128->dat & 0x20) - ym7128->c1 |= 0xfffff000; - break; + if (ym7128->a0 != new_a0) { + if (!ym7128->a0) + ym7128->reg_sel = ym7128->dat & 0x1f; + else { + switch (ym7128->reg_sel) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); + break; - case 0x16: case 0x17: case 0x18: case 0x19: - case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: - ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; - break; - } - ym7128->regs[ym7128->reg_sel] = ym7128->dat; - } - ym7128->dat = 0; + case 0x10: + ym7128->vm = GET_ATTENUATION(ym7128->dat); + break; + case 0x11: + ym7128->vc = GET_ATTENUATION(ym7128->dat); + break; + case 0x12: + ym7128->vl = GET_ATTENUATION(ym7128->dat); + break; + case 0x13: + ym7128->vr = GET_ATTENUATION(ym7128->dat); + break; + + case 0x14: + ym7128->c0 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c0 |= 0xfffff000; + break; + case 0x15: + ym7128->c1 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c1 |= 0xfffff000; + break; + + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; + break; + } + ym7128->regs[ym7128->reg_sel] = ym7128->dat; } + ym7128->dat = 0; + } - ym7128->sci = new_sci; - ym7128->a0 = new_a0; + ym7128->sci = new_sci; + ym7128->a0 = new_a0; } #define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) -void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) +void +ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) { - int c, d; - - for (c = 0; c < len*2; c += 4) - { - /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ - int32_t samp = ((int32_t)buffer[c] + (int32_t)buffer[c+1] + (int32_t)buffer[c+2] + (int32_t)buffer[c+3]) / 4; - int32_t filter_temp, filter_out; - int32_t samp_l = 0, samp_r = 0; + int c, d; - filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); - filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); - filter_out = (filter_out * ym7128->vc) >> 16; + for (c = 0; c < len * 2; c += 4) { + /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ + int32_t samp = ((int32_t) buffer[c] + (int32_t) buffer[c + 1] + (int32_t) buffer[c + 2] + (int32_t) buffer[c + 3]) / 4; + int32_t filter_temp, filter_out; + int32_t samp_l = 0, samp_r = 0; - samp = (samp * ym7128->vm) >> 16; - samp += filter_out; - - ym7128->delay_buffer[ym7128->delay_pos] = samp; - - for (d = 0; d < 8; d++) - { - samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gl[d]) >> 16; - samp_r += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gr[d]) >> 16; - } - - samp_l = (samp_l * ym7128->vl*2) >> 16; - samp_r = (samp_r * ym7128->vr*2) >> 16; - - buffer[c] += ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2; - buffer[c+1] += ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2; - buffer[c+2] += samp_l; - buffer[c+3] += samp_r; - - ym7128->delay_pos++; - if (ym7128->delay_pos >= 2400) - ym7128->delay_pos = 0; - - ym7128->filter_dat = filter_temp; - ym7128->prev_l = samp_l; - ym7128->prev_r = samp_r; + filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); + filter_out = (filter_out * ym7128->vc) >> 16; + + samp = (samp * ym7128->vm) >> 16; + samp += filter_out; + + ym7128->delay_buffer[ym7128->delay_pos] = samp; + + for (d = 0; d < 8; d++) { + samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d + 1]) * ym7128->gl[d]) >> 16; + samp_r += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d + 1]) * ym7128->gr[d]) >> 16; } + + samp_l = (samp_l * ym7128->vl * 2) >> 16; + samp_r = (samp_r * ym7128->vr * 2) >> 16; + + buffer[c] += ((int32_t) samp_l + (int32_t) ym7128->prev_l) / 2; + buffer[c + 1] += ((int32_t) samp_r + (int32_t) ym7128->prev_r) / 2; + buffer[c + 2] += samp_l; + buffer[c + 3] += samp_r; + + ym7128->delay_pos++; + if (ym7128->delay_pos >= 2400) + ym7128->delay_pos = 0; + + ym7128->filter_dat = filter_temp; + ym7128->prev_l = samp_l; + ym7128->prev_r = samp_r; + } } diff --git a/src/sound/sound.c b/src/sound/sound.c index f6ade1f98..604dac38f 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -1,196 +1,223 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Sound emulation core. + * Sound emulation core. * * * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Sarah Walker, + * Miran Grca, * - * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ +#include #include #include #include -#include #include +#include #include #define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/device.h> -#include <86box/timer.h> -#include <86box/cdrom.h> -#include <86box/hdc_ide.h> -#include <86box/plat.h> -#include <86box/machine.h> -#include <86box/sound.h> -#include <86box/midi.h> -#include <86box/snd_opl.h> -#include <86box/snd_mpu401.h> -#include <86box/snd_sb_dsp.h> -#include <86box/snd_azt2316a.h> -#include <86box/filters.h> +#include <86box/86box.h> +#include <86box/cdrom.h> +#include <86box/device.h> +#include <86box/filters.h> +#include <86box/hdc_ide.h> +#include <86box/machine.h> +#include <86box/midi.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/snd_ac97.h> +#include <86box/snd_azt2316a.h> +#include <86box/timer.h> +#include <86box/snd_mpu401.h> +#include <86box/sound.h> +#include <86box/snd_opl.h> +#include <86box/snd_sb_dsp.h> typedef struct { - const char *name; - const char *internal_name; - const device_t *device; + const device_t *device; } SOUND_CARD; typedef struct { - void (*get_buffer)(int32_t *buffer, int len, void *p); - void *priv; + void (*get_buffer)(int32_t *buffer, int len, void *p); + void *priv; } sound_handler_t; - int sound_card_current = 0; -int sound_pos_global = 0; -int sound_gain = 0; - +int sound_pos_global = 0; +int sound_gain = 0; static sound_handler_t sound_handlers[8]; -static thread_t *sound_cd_thread_h; -static event_t *sound_cd_event; -static event_t *sound_cd_start_event; -static int32_t *outbuffer; -static float *outbuffer_ex; -static int16_t *outbuffer_ex_int16; -static int sound_handlers_num; +static thread_t *sound_cd_thread_h; +static event_t *sound_cd_event; +static event_t *sound_cd_start_event; +static int32_t *outbuffer; +static float *outbuffer_ex; +static int16_t *outbuffer_ex_int16; +static int sound_handlers_num; static pc_timer_t sound_poll_timer; -static uint64_t sound_poll_latch; +static uint64_t sound_poll_latch; -static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; -static float cd_out_buffer[CD_BUFLEN * 2]; -static int16_t cd_out_buffer_int16[CD_BUFLEN * 2]; +static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; +static float cd_out_buffer[CD_BUFLEN * 2]; +static int16_t cd_out_buffer_int16[CD_BUFLEN * 2]; static unsigned int cd_vol_l, cd_vol_r; -static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN; -static volatile int cdaudioon = 0; -static int cd_thread_enable = 0; +static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN; +static volatile int cdaudioon = 0; +static int cd_thread_enable = 0; +static void (*filter_cd_audio)(int channel, double *buffer, void *p) = NULL; +static void *filter_cd_audio_p = NULL; -static const SOUND_CARD sound_cards[] = -{ - { "None", "none", NULL }, - { "Internal", "internal", NULL }, - { "[ISA] Adlib", "adlib", &adlib_device }, - { "[ISA] Adlib Gold", "adlibgold", &adgold_device }, - { "[ISA] Aztech Sound Galaxy Pro 16 AB (Washington)", "azt2316a", &azt2316a_device }, - { "[ISA] Aztech Sound Galaxy Nova 16 Extra (Clinton)", "azt1605", &azt1605_device }, - { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, - { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, - { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, - { "[ISA] Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, - { "[ISA] Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, - { "[ISA] Sound Blaster 16", "sb16", &sb_16_device }, - { "[ISA] Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, -#if defined(DEV_BRANCH) && defined(USE_PAS16) - { "[ISA] Pro Audio Spectrum 16", "pas16", &pas16_device }, -#endif - { "[ISA] Windows Sound System", "wss", &wss_device }, - { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, - { "[MCA] NCR Business Audio", "ncraudio", &ncr_business_audio_device }, - { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, - { "[MCA] Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device }, - { "[PCI] Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device }, - { "", "", NULL } +static const device_t sound_none_device = { + "None", + "none", + 0, + 0, + NULL, + NULL, + NULL, + { NULL }, + NULL, + NULL, + NULL +}; +static const device_t sound_internal_device = { + "Internal", + "internal", + 0, + 0, + NULL, + NULL, + NULL, + { NULL }, + NULL, + NULL, + NULL }; +static const SOUND_CARD sound_cards[] = { + // clang-format off + { &sound_none_device }, + { &sound_internal_device }, + { &adlib_device }, + { &adgold_device }, + { &azt2316a_device }, + { &azt1605_device }, + { &cs4235_device }, + { &cs4236b_device }, + { &sb_1_device }, + { &sb_15_device }, + { &sb_2_device }, + { &sb_pro_v1_device }, + { &sb_pro_v2_device }, + { &sb_16_device }, + { &sb_16_pnp_device }, + { &sb_32_pnp_device }, + { &sb_awe32_device }, + { &sb_awe32_pnp_device }, + { &sb_awe64_value_device }, + { &sb_awe64_device }, + { &sb_awe64_gold_device }, +#if defined(DEV_BRANCH) && defined(USE_PAS16) + { &pas16_device }, +#endif +#if defined(DEV_BRANCH) && defined(USE_TANDY_ISA) + { &pssj_isa_device }, + { &tndy_device }, +#endif + { &wss_device }, + { &adlib_mca_device }, + { &ncr_business_audio_device }, + { &sb_mcv_device }, + { &sb_pro_mcv_device }, + { &sb_16_reply_mca_device }, + { &cmi8338_device }, + { &cmi8738_device }, + { &es1371_device }, + { &ad1881_device }, + { &cs4297a_device }, + { NULL } + // clang-format on +}; #ifdef ENABLE_SOUND_LOG int sound_do_log = ENABLE_SOUND_LOG; - static void sound_log(const char *fmt, ...) { va_list ap; if (sound_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else -#define sound_log(fmt, ...) +# define sound_log(fmt, ...) #endif - int sound_card_available(int card) { - if ((card == SOUND_INTERNAL) && !(machines[machine].flags & MACHINE_SOUND)) - return 0; - if (sound_cards[card].device) - return device_available(sound_cards[card].device); + return device_available(sound_cards[card].device); return 1; } - -char * -sound_card_getname(int card) -{ - return (char *) sound_cards[card].name; -} - - const device_t * sound_card_getdevice(int card) { return sound_cards[card].device; } - int sound_card_has_config(int card) { if (!sound_cards[card].device) - return 0; - return sound_cards[card].device->config ? 1 : 0; + return 0; + return device_has_config(sound_cards[card].device) ? 1 : 0; } - char * sound_card_get_internal_name(int card) { - return (char *) sound_cards[card].internal_name; + return device_get_internal_name(sound_cards[card].device); } - int sound_card_get_from_internal_name(char *s) { int c = 0; - while (strlen((char *) sound_cards[c].internal_name)) { - if (!strcmp((char *) sound_cards[c].internal_name, s)) - return c; - c++; + while (sound_cards[c].device != NULL) { + if (!strcmp((char *) sound_cards[c].device->internal_name, s)) + return c; + c++; } return 0; } - void sound_card_init(void) { if (sound_cards[sound_card_current].device) - device_add(sound_cards[sound_card_current].device); + device_add(sound_cards[sound_card_current].device); } - void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) { @@ -198,185 +225,208 @@ sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) cd_vol_r = vol_r; } - static void sound_cd_clean_buffers(void) { if (sound_is_float) - memset(cd_out_buffer, 0, (CD_BUFLEN * 2) * sizeof(float)); + memset(cd_out_buffer, 0, (CD_BUFLEN * 2) * sizeof(float)); else - memset(cd_out_buffer_int16, 0, (CD_BUFLEN * 2) * sizeof(int16_t)); + memset(cd_out_buffer_int16, 0, (CD_BUFLEN * 2) * sizeof(int16_t)); } - static void sound_cd_thread(void *param) { - int c, r, i, channel_select[2]; - float audio_vol_l, audio_vol_r; - float cd_buffer_temp[2] = {0.0, 0.0}; + uint32_t lba; + int c, r, i, pre, channel_select[2]; + double audio_vol_l, audio_vol_r; + double cd_buffer_temp[2] = { 0.0, 0.0 }; thread_set_event(sound_cd_start_event); while (cdaudioon) { - thread_wait_event(sound_cd_event, -1); - thread_reset_event(sound_cd_event); + thread_wait_event(sound_cd_event, -1); + thread_reset_event(sound_cd_event); - if (!cdaudioon) - return; + if (!cdaudioon) + return; - sound_cd_clean_buffers(); + sound_cd_clean_buffers(); - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || - (cdrom[i].cd_status == CD_STATUS_EMPTY)) - continue; - r = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); - if (!cdrom[i].bus_type || !cdrom[i].sound_on || !r) - continue; + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || (cdrom[i].cd_status == CD_STATUS_EMPTY)) + continue; + lba = cdrom[i].seek_pos; + r = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); + if (!cdrom[i].bus_type || !cdrom[i].sound_on || !r) + continue; + pre = cdrom_is_pre(&(cdrom[i]), lba); - if (cdrom[i].get_volume) { - audio_vol_l = (float) (cdrom[i].get_volume(cdrom[i].priv, 0)); - audio_vol_r = (float) (cdrom[i].get_volume(cdrom[i].priv, 1)); - } else { - audio_vol_l = 255.0; - audio_vol_r = 255.0; - } + if (cdrom[i].get_volume) { + audio_vol_l = (float) (cdrom[i].get_volume(cdrom[i].priv, 0)); + audio_vol_r = (float) (cdrom[i].get_volume(cdrom[i].priv, 1)); + } else { + audio_vol_l = 255.0; + audio_vol_r = 255.0; + } - audio_vol_l /= 511.0; - audio_vol_r /= 511.0; + /* Calculate attenuation per the specification. */ + if (audio_vol_l >= 255.0) + audio_vol_l = 1.0; + else if (audio_vol_l > 0.0) + audio_vol_l = (48.0 + (20.0 * log(audio_vol_l / 256.0))) / 48.0; + else + audio_vol_l = 0.0; - if (cdrom[i].get_channel) { - channel_select[0] = cdrom[i].get_channel(cdrom[i].priv, 0); - channel_select[1] = cdrom[i].get_channel(cdrom[i].priv, 1); - } else { - channel_select[0] = 1; - channel_select[1] = 2; - } + if (audio_vol_r >= 255.0) + audio_vol_r = 1.0; + else if (audio_vol_r > 0.0) + audio_vol_r = (48.0 + (20.0 * log(audio_vol_r / 256.0))) / 48.0; + else + audio_vol_r = 0.0; - for (c = 0; c < CD_BUFLEN*2; c += 2) { - /*Apply ATAPI channel select*/ - cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; + if (cdrom[i].get_channel) { + channel_select[0] = cdrom[i].get_channel(cdrom[i].priv, 0); + channel_select[1] = cdrom[i].get_channel(cdrom[i].priv, 1); + } else { + channel_select[0] = 1; + channel_select[1] = 2; + } -#if 0 - if (channel_select[0] & 1) - cd_buffer_temp[0] += ((float) cd_buffer[i][c]) * audio_vol_l; - if (channel_select[0] & 2) - cd_buffer_temp[1] += ((float) cd_buffer[i][c]) * audio_vol_l; - if (channel_select[1] & 1) - cd_buffer_temp[0] += ((float) cd_buffer[i][c + 1]) * audio_vol_r; - if (channel_select[1] & 2) - cd_buffer_temp[1] += ((float) cd_buffer[i][c + 1]) * audio_vol_r; -#else - if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { - if (channel_select[0] & 1) - cd_buffer_temp[0] += ((float) cd_buffer[i][c]); /* Channel 0 => Port 0 */ - if (channel_select[0] & 2) - cd_buffer_temp[0] += ((float) cd_buffer[i][c + 1]); /* Channel 1 => Port 0 */ + for (c = 0; c < CD_BUFLEN * 2; c += 2) { + /*Apply ATAPI channel select*/ + cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; - cd_buffer_temp[0] *= audio_vol_l; /* Multiply Port 0 by Port 0 volume */ - } + if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { + if (channel_select[0] & 1) + cd_buffer_temp[0] += ((double) cd_buffer[i][c]); /* Channel 0 => Port 0 */ + if (channel_select[0] & 2) + cd_buffer_temp[0] += ((double) cd_buffer[i][c + 1]); /* Channel 1 => Port 0 */ - if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { - if (channel_select[1] & 1) - cd_buffer_temp[1] += ((float) cd_buffer[i][c]); /* Channel 0 => Port 1 */ - if (channel_select[1] & 2) - cd_buffer_temp[1] += ((float) cd_buffer[i][c + 1]); /* Channel 1 => Port 1 */ + cd_buffer_temp[0] *= audio_vol_l; /* Multiply Port 0 by Port 0 volume */ - cd_buffer_temp[1] *= audio_vol_r; /* Multiply Port 1 by Port 1 volume */ - } -#endif + if (pre) + cd_buffer_temp[0] = deemph_iir(0, cd_buffer_temp[0]); /* De-emphasize if necessary */ + } - /*Apply sound card CD volume*/ - cd_buffer_temp[0] *= ((float) cd_vol_l) / 65535.0; - cd_buffer_temp[1] *= ((float) cd_vol_r) / 65535.0; + if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { + if (channel_select[1] & 1) + cd_buffer_temp[1] += ((double) cd_buffer[i][c]); /* Channel 0 => Port 1 */ + if (channel_select[1] & 2) + cd_buffer_temp[1] += ((double) cd_buffer[i][c + 1]); /* Channel 1 => Port 1 */ - if (sound_is_float) { - cd_out_buffer[c] += (cd_buffer_temp[0] / 32768.0); - cd_out_buffer[c+1] += (cd_buffer_temp[1] / 32768.0); - } else { - if (cd_buffer_temp[0] > 32767) - cd_buffer_temp[0] = 32767; - if (cd_buffer_temp[0] < -32768) - cd_buffer_temp[0] = -32768; - if (cd_buffer_temp[1] > 32767) - cd_buffer_temp[1] = 32767; - if (cd_buffer_temp[1] < -32768) - cd_buffer_temp[1] = -32768; + cd_buffer_temp[1] *= audio_vol_r; /* Multiply Port 1 by Port 1 volume */ - cd_out_buffer_int16[c] += cd_buffer_temp[0]; - cd_out_buffer_int16[c+1] += cd_buffer_temp[1]; - } - } - } + if (pre) + cd_buffer_temp[1] = deemph_iir(1, cd_buffer_temp[1]); /* De-emphasize if necessary */ + } - if (sound_is_float) - givealbuffer_cd(cd_out_buffer); - else - givealbuffer_cd(cd_out_buffer_int16); + /* Apply sound card CD volume and filters */ + if (filter_cd_audio != NULL) { + filter_cd_audio(0, &(cd_buffer_temp[0]), filter_cd_audio_p); + filter_cd_audio(1, &(cd_buffer_temp[1]), filter_cd_audio_p); + } + + if (sound_is_float) { + cd_out_buffer[c] += (float) (cd_buffer_temp[0] / 32768.0); + cd_out_buffer[c + 1] += (float) (cd_buffer_temp[1] / 32768.0); + } else { + if (cd_buffer_temp[0] > 32767) + cd_buffer_temp[0] = 32767; + if (cd_buffer_temp[0] < -32768) + cd_buffer_temp[0] = -32768; + if (cd_buffer_temp[1] > 32767) + cd_buffer_temp[1] = 32767; + if (cd_buffer_temp[1] < -32768) + cd_buffer_temp[1] = -32768; + + cd_out_buffer_int16[c] += (int16_t) cd_buffer_temp[0]; + cd_out_buffer_int16[c + 1] += (int16_t) cd_buffer_temp[1]; + } + } + } + + if (sound_is_float) + givealbuffer_cd(cd_out_buffer); + else + givealbuffer_cd(cd_out_buffer_int16); } } - static void sound_realloc_buffers(void) { - if (outbuffer_ex != NULL) - free(outbuffer_ex); + if (outbuffer_ex != NULL) { + free(outbuffer_ex); + outbuffer_ex = NULL; + } - if (outbuffer_ex_int16 != NULL) - free(outbuffer_ex_int16); + if (outbuffer_ex_int16 != NULL) { + free(outbuffer_ex_int16); + outbuffer_ex_int16 = NULL; + } - if (sound_is_float) - outbuffer_ex = malloc(SOUNDBUFLEN * 2 * sizeof(float)); - else - outbuffer_ex_int16 = malloc(SOUNDBUFLEN * 2 * sizeof(int16_t)); + if (sound_is_float) { + outbuffer_ex = calloc(SOUNDBUFLEN * 2, sizeof(float)); + memset(outbuffer_ex, 0x00, SOUNDBUFLEN * 2 * sizeof(float)); + } else { + outbuffer_ex_int16 = calloc(SOUNDBUFLEN * 2, sizeof(int16_t)); + memset(outbuffer_ex_int16, 0x00, SOUNDBUFLEN * 2 * sizeof(int16_t)); + } } - void sound_init(void) { - int i = 0; + int i = 0; int available_cdrom_drives = 0; - outbuffer_ex = NULL; + outbuffer_ex = NULL; outbuffer_ex_int16 = NULL; - outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + outbuffer = NULL; + outbuffer = calloc(SOUNDBUFLEN * 2, sizeof(int32_t)); + memset(outbuffer, 0x00, SOUNDBUFLEN * 2 * sizeof(int32_t)); for (i = 0; i < CDROM_NUM; i++) { - if (cdrom[i].bus_type != CDROM_BUS_DISABLED) - available_cdrom_drives++; + if (cdrom[i].bus_type != CDROM_BUS_DISABLED) + available_cdrom_drives++; } if (available_cdrom_drives) { - cdaudioon = 1; + cdaudioon = 1; - sound_cd_start_event = thread_create_event(); + sound_cd_start_event = thread_create_event(); - sound_cd_event = thread_create_event(); - sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); - sound_log("Waiting for CD start event...\n"); - thread_wait_event(sound_cd_start_event, -1); - thread_reset_event(sound_cd_start_event); - sound_log("Done!\n"); + sound_log("Waiting for CD start event...\n"); + thread_wait_event(sound_cd_start_event, -1); + thread_reset_event(sound_cd_start_event); + sound_log("Done!\n"); } else - cdaudioon = 0; + cdaudioon = 0; cd_thread_enable = available_cdrom_drives ? 1 : 0; } - void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) { sound_handlers[sound_handlers_num].get_buffer = get_buffer; - sound_handlers[sound_handlers_num].priv = p; + sound_handlers[sound_handlers_num].priv = p; sound_handlers_num++; } +void +sound_set_cd_audio_filter(void (*filter)(int channel, double *buffer, void *p), void *p) +{ + if ((filter_cd_audio == NULL) || (filter == NULL)) { + filter_cd_audio = filter; + filter_cd_audio_p = p; + } +} void sound_poll(void *priv) @@ -387,68 +437,70 @@ sound_poll(void *priv) sound_pos_global++; if (sound_pos_global == SOUNDBUFLEN) { - int c; + int c; - memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); + memset(outbuffer, 0x00, SOUNDBUFLEN * 2 * sizeof(int32_t)); - for (c = 0; c < sound_handlers_num; c++) - sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); + for (c = 0; c < sound_handlers_num; c++) + sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); - for (c = 0; c < SOUNDBUFLEN * 2; c++) { - if (sound_is_float) - outbuffer_ex[c] = ((float) outbuffer[c]) / 32768.0; - else { - if (outbuffer[c] > 32767) - outbuffer[c] = 32767; - if (outbuffer[c] < -32768) - outbuffer[c] = -32768; + for (c = 0; c < SOUNDBUFLEN * 2; c++) { + if (sound_is_float) + outbuffer_ex[c] = ((float) outbuffer[c]) / 32768.0; + else { + if (outbuffer[c] > 32767) + outbuffer[c] = 32767; + if (outbuffer[c] < -32768) + outbuffer[c] = -32768; - outbuffer_ex_int16[c] = outbuffer[c]; - } - } + outbuffer_ex_int16[c] = outbuffer[c]; + } + } - if (sound_is_float) - givealbuffer(outbuffer_ex); - else - givealbuffer(outbuffer_ex_int16); + if (sound_is_float) + givealbuffer(outbuffer_ex); + else + givealbuffer(outbuffer_ex_int16); - if (cd_thread_enable) { - cd_buf_update--; - if (!cd_buf_update) { - cd_buf_update = (48000 / SOUNDBUFLEN) / (CD_FREQ / CD_BUFLEN); - thread_set_event(sound_cd_event); - } - } + if (cd_thread_enable) { + cd_buf_update--; + if (!cd_buf_update) { + cd_buf_update = (48000 / SOUNDBUFLEN) / (CD_FREQ / CD_BUFLEN); + thread_set_event(sound_cd_event); + } + } - sound_pos_global = 0; + sound_pos_global = 0; } } - void sound_speed_changed(void) { - sound_poll_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); + sound_poll_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 48000.0)); } - void sound_reset(void) { sound_realloc_buffers(); - midi_device_init(); + midi_out_device_init(); midi_in_device_init(); + inital(); timer_add(&sound_poll_timer, sound_poll, NULL, 1); sound_handlers_num = 0; + memset(sound_handlers, 0x00, 8 * sizeof(sound_handler_t)); + + filter_cd_audio = NULL; + filter_cd_audio_p = NULL; sound_set_cd_volume(65535, 65535); } - void sound_card_reset(void) { @@ -458,70 +510,68 @@ sound_card_reset(void) sound_card_init(); if (mpu401_standalone_enable) - mpu401_device_add(); + mpu401_device_add(); if (GUS) - device_add(&gus_device); + device_add(&gus_device); if (GAMEBLASTER) - device_add(&cms_device); + device_add(&cms_device); if (SSI2001) - device_add(&ssi2001_device); + device_add(&ssi2001_device); } - void sound_cd_thread_end(void) { if (cdaudioon) { - cdaudioon = 0; + cdaudioon = 0; - sound_log("Waiting for CD Audio thread to terminate...\n"); - thread_set_event(sound_cd_event); - thread_wait(sound_cd_thread_h, -1); - sound_log("CD Audio thread terminated...\n"); + sound_log("Waiting for CD Audio thread to terminate...\n"); + thread_set_event(sound_cd_event); + thread_wait(sound_cd_thread_h); + sound_log("CD Audio thread terminated...\n"); - if (sound_cd_event) { - thread_destroy_event(sound_cd_event); - sound_cd_event = NULL; - } + if (sound_cd_event) { + thread_destroy_event(sound_cd_event); + sound_cd_event = NULL; + } - sound_cd_thread_h = NULL; + sound_cd_thread_h = NULL; - if (sound_cd_start_event) { - thread_destroy_event(sound_cd_start_event); - sound_cd_event = NULL; - } + if (sound_cd_start_event) { + thread_destroy_event(sound_cd_start_event); + sound_cd_event = NULL; + } } } - void sound_cd_thread_reset(void) { - int i = 0; + int i = 0; int available_cdrom_drives = 0; for (i = 0; i < CDROM_NUM; i++) { - cdrom_stop(&(cdrom[i])); + cdrom_stop(&(cdrom[i])); - if (cdrom[i].bus_type != CDROM_BUS_DISABLED) - available_cdrom_drives++; + if (cdrom[i].bus_type != CDROM_BUS_DISABLED) + available_cdrom_drives++; } if (available_cdrom_drives && !cd_thread_enable) { - cdaudioon = 1; + cdaudioon = 1; - sound_cd_start_event = thread_create_event(); + sound_cd_start_event = thread_create_event(); - sound_cd_event = thread_create_event(); - sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); - thread_wait_event(sound_cd_start_event, -1); - thread_reset_event(sound_cd_start_event); + thread_wait_event(sound_cd_start_event, -1); + thread_reset_event(sound_cd_start_event); } else if (!available_cdrom_drives && cd_thread_enable) - sound_cd_thread_end(); + sound_cd_thread_end(); cd_thread_enable = available_cdrom_drives ? 1 : 0; } diff --git a/src/sound/xaudio2.c b/src/sound/xaudio2.c new file mode 100644 index 000000000..b26bb9c9f --- /dev/null +++ b/src/sound/xaudio2.c @@ -0,0 +1,285 @@ +/* + * 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. + * + * Interface to the XAudio2 audio processing library. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2022 Cacodemon345. + */ +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(USE_FAUDIO) +# define COBJMACROS +# include +#else +# include +# include +#endif + +#include <86box/86box.h> +#include <86box/midi.h> +#include <86box/plat_dynld.h> +#include <86box/sound.h> + +#if defined(_WIN32) && !defined(USE_FAUDIO) +static void *xaudio2_handle = NULL; +static HRESULT(WINAPI *pXAudio2Create)(IXAudio2 **ppXAudio2, uint32_t Flags, XAUDIO2_PROCESSOR XAudio2Processor); +static dllimp_t xaudio2_imports[] = { + {"XAudio2Create", &pXAudio2Create}, + { NULL, NULL }, +}; +# define XAudio2Create pXAudio2Create +#endif + +static int midi_freq = 44100; +static int midi_buf_size = 4410; +static int initialized = 0; +static IXAudio2 *xaudio2 = NULL; +static IXAudio2MasteringVoice *mastervoice = NULL; +static IXAudio2SourceVoice *srcvoice = NULL; +static IXAudio2SourceVoice *srcvoicemidi = NULL; +static IXAudio2SourceVoice *srcvoicecd = NULL; + +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + +static void WINAPI +OnVoiceProcessingPassStart(IXAudio2VoiceCallback *callback, uint32_t bytesRequired) +{ +} +static void WINAPI +OnVoiceProcessingPassEnd(IXAudio2VoiceCallback *callback) +{ +} +static void WINAPI +OnStreamEnd(IXAudio2VoiceCallback *callback) +{ +} +static void WINAPI +OnBufferStart(IXAudio2VoiceCallback *callback, void *pBufferContext) +{ +} +static void WINAPI +OnLoopEnd(IXAudio2VoiceCallback *callback, void *pBufferContext) +{ +} +static void WINAPI +OnVoiceError(IXAudio2VoiceCallback *callback, void *pBufferContext, HRESULT error) +{ +} + +static void WINAPI +OnBufferEnd(IXAudio2VoiceCallback *callback, void *pBufferContext) +{ + free(pBufferContext); +} + +#if defined(_WIN32) && !defined(USE_FAUDIO) +static IXAudio2VoiceCallbackVtbl callbacksVtbl = +#else +static FAudioVoiceCallback callbacks = +#endif + { + .OnVoiceProcessingPassStart = OnVoiceProcessingPassStart, + .OnVoiceProcessingPassEnd = OnVoiceProcessingPassEnd, + .OnStreamEnd = OnStreamEnd, + .OnBufferStart = OnBufferStart, + .OnBufferEnd = OnBufferEnd, + .OnLoopEnd = OnLoopEnd, + .OnVoiceError = OnVoiceError + }; + +#if defined(_WIN32) && !defined(USE_FAUDIO) +static IXAudio2VoiceCallback callbacks = { &callbacksVtbl }; +#endif + +void +inital() +{ +#if defined(_WIN32) && !defined(USE_FAUDIO) + if (xaudio2_handle == NULL) { + xaudio2_handle = dynld_module("xaudio2_9.dll", xaudio2_imports); + } + + if (xaudio2_handle == NULL) { + xaudio2_handle = dynld_module("xaudio2_9redist.dll", xaudio2_imports); + } + + if (xaudio2_handle == NULL) { + return; + } +#endif + + if (XAudio2Create(&xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)) { + return; + } + + if (IXAudio2_CreateMasteringVoice(xaudio2, &mastervoice, 2, FREQ, 0, 0, NULL, 0)) { + IXAudio2_Release(xaudio2); + xaudio2 = NULL; + return; + } + + WAVEFORMATEX fmt; + fmt.nChannels = 2; + + if (sound_is_float) { + fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + fmt.wBitsPerSample = 32; + } else { + fmt.wFormatTag = WAVE_FORMAT_PCM; + fmt.wBitsPerSample = 16; + } + + fmt.nSamplesPerSec = FREQ; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + fmt.cbSize = 0; + + if (IXAudio2_CreateSourceVoice(xaudio2, &srcvoice, &fmt, 0, 2.0f, &callbacks, NULL, NULL)) { + IXAudio2MasteringVoice_DestroyVoice(mastervoice); + IXAudio2_Release(xaudio2); + xaudio2 = NULL; + mastervoice = NULL; + return; + } + + fmt.nSamplesPerSec = CD_FREQ; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicecd, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + + IXAudio2SourceVoice_SetVolume(srcvoice, 1, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_Start(srcvoice, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_Start(srcvoicecd, 0, XAUDIO2_COMMIT_NOW); + + char *mdn = midi_out_device_get_internal_name(midi_output_device_current); + + if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) { + fmt.nSamplesPerSec = midi_freq; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicemidi, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + IXAudio2SourceVoice_Start(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + } + + initialized = 1; + atexit(closeal); +} + +void +closeal() +{ + if (!initialized) + return; + initialized = 0; + IXAudio2SourceVoice_Stop(srcvoice, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoice); + IXAudio2SourceVoice_Stop(srcvoicecd, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicecd); + if (srcvoicemidi) { + IXAudio2SourceVoice_Stop(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi); + IXAudio2SourceVoice_DestroyVoice(srcvoicemidi); + } + IXAudio2SourceVoice_DestroyVoice(srcvoice); + IXAudio2SourceVoice_DestroyVoice(srcvoicecd); + IXAudio2MasteringVoice_DestroyVoice(mastervoice); + IXAudio2_Release(xaudio2); + srcvoice = srcvoicecd = srcvoicemidi = NULL; + mastervoice = NULL; + xaudio2 = NULL; + +#if defined(_WIN32) && !defined(USE_FAUDIO) + dynld_close(xaudio2_handle); + xaudio2_handle = NULL; +#endif +} + +void +givealbuffer_common(void *buf, IXAudio2SourceVoice *sourcevoice, size_t buflen) +{ + if (!initialized) + return; + + IXAudio2MasteringVoice_SetVolume(mastervoice, pow(10.0, (double) sound_gain / 20.0), XAUDIO2_COMMIT_NOW); + XAUDIO2_BUFFER buffer = { 0 }; + buffer.Flags = 0; + if (sound_is_float) { + buffer.pAudioData = calloc(buflen, sizeof(float)); + buffer.AudioBytes = (buflen) * sizeof(float); + } else { + buffer.pAudioData = calloc(buflen, sizeof(int16_t)); + buffer.AudioBytes = (buflen) * sizeof(int16_t); + } + if (buffer.pAudioData == NULL) { + fatal("xaudio2: Out Of Memory!"); + } + memcpy((void *) buffer.pAudioData, buf, buffer.AudioBytes); + buffer.PlayBegin = buffer.PlayLength = 0; + buffer.PlayLength = buflen >> 1; + buffer.pContext = (void *) buffer.pAudioData; + IXAudio2SourceVoice_SubmitSourceBuffer(sourcevoice, &buffer, NULL); +} + +void +givealbuffer(void *buf) +{ + givealbuffer_common(buf, srcvoice, BUFLEN << 1); +} + +void +givealbuffer_cd(void *buf) +{ + if (srcvoicecd) + givealbuffer_common(buf, srcvoicecd, CD_BUFLEN << 1); +} + +void +al_set_midi(int freq, int buf_size) +{ + midi_freq = freq; + midi_buf_size = buf_size; + + if (initialized && srcvoicemidi) { + IXAudio2SourceVoice_Stop(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi); + IXAudio2SourceVoice_DestroyVoice(srcvoicemidi); + srcvoicemidi = NULL; + WAVEFORMATEX fmt; + fmt.nChannels = 2; + if (sound_is_float) { + fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + fmt.wBitsPerSample = 32; + } else { + fmt.wFormatTag = WAVE_FORMAT_PCM; + fmt.wBitsPerSample = 16; + } + fmt.nSamplesPerSec = midi_freq; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + fmt.cbSize = 0; + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicemidi, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + IXAudio2SourceVoice_Start(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + } +} + +void +givealbuffer_midi(void *buf, uint32_t size) +{ + givealbuffer_common(buf, srcvoicemidi, size); +} diff --git a/src/sound/ymfm/CMakeLists.txt b/src/sound/ymfm/CMakeLists.txt new file mode 100644 index 000000000..2041719ae --- /dev/null +++ b/src/sound/ymfm/CMakeLists.txt @@ -0,0 +1 @@ +add_library(ymfm STATIC ymfm_misc.cpp ymfm_opl.cpp ymfm_opm.cpp ymfm_opn.cpp ymfm_opq.cpp ymfm_opz.cpp ymfm_pcm.cpp ymfm_adpcm.cpp) \ No newline at end of file diff --git a/src/sound/ymfm/ymfm.h b/src/sound/ymfm/ymfm.h new file mode 100644 index 000000000..ae13faedd --- /dev/null +++ b/src/sound/ymfm/ymfm.h @@ -0,0 +1,573 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_H +#define YMFM_H + +#pragma once + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ymfm +{ + +//********************************************************* +// DEBUGGING +//********************************************************* + +class debug +{ +public: + // masks to help isolate specific channels + static constexpr uint32_t GLOBAL_FM_CHANNEL_MASK = 0xffffffff; + static constexpr uint32_t GLOBAL_ADPCM_A_CHANNEL_MASK = 0xffffffff; + static constexpr uint32_t GLOBAL_ADPCM_B_CHANNEL_MASK = 0xffffffff; + static constexpr uint32_t GLOBAL_PCM_CHANNEL_MASK = 0xffffffff; + + // types of logging + static constexpr bool LOG_FM_WRITES = false; + static constexpr bool LOG_KEYON_EVENTS = false; + static constexpr bool LOG_UNEXPECTED_READ_WRITES = false; + + // helpers to write based on the log type + template static void log_fm_write(Params &&... args) { if (LOG_FM_WRITES) log(args...); } + template static void log_keyon(Params &&... args) { if (LOG_KEYON_EVENTS) log(args...); } + template static void log_unexpected_read_write(Params &&... args) { if (LOG_UNEXPECTED_READ_WRITES) log(args...); } + + // downstream helper to output log data; defaults to printf + template static void log(Params &&... args) { printf(args...); } +}; + + + +//********************************************************* +// GLOBAL HELPERS +//********************************************************* + +//------------------------------------------------- +// bitfield - extract a bitfield from the given +// value, starting at bit 'start' for a length of +// 'length' bits +//------------------------------------------------- + +inline uint32_t bitfield(uint32_t value, int start, int length = 1) +{ + return (value >> start) & ((1 << length) - 1); +} + + +//------------------------------------------------- +// clamp - clamp between the minimum and maximum +// values provided +//------------------------------------------------- + +inline int32_t clamp(int32_t value, int32_t minval, int32_t maxval) +{ + if (value < minval) + return minval; + if (value > maxval) + return maxval; + return value; +} + + +//------------------------------------------------- +// array_size - return the size of an array +//------------------------------------------------- + +template +constexpr uint32_t array_size(ArrayType (&array)[ArraySize]) +{ + return ArraySize; +} + + +//------------------------------------------------- +// count_leading_zeros - return the number of +// leading zeros in a 32-bit value; CPU-optimized +// versions for various architectures are included +// below +//------------------------------------------------- + +#if defined(__GNUC__) + +inline uint8_t count_leading_zeros(uint32_t value) +{ + if (value == 0) + return 32; + return __builtin_clz(value); +} + +#elif defined(_MSC_VER) + +inline uint8_t count_leading_zeros(uint32_t value) +{ + unsigned long index; + return _BitScanReverse(&index, value) ? uint8_t(31U - index) : 32U; +} + +#else + +inline uint8_t count_leading_zeros(uint32_t value) +{ + if (value == 0) + return 32; + uint8_t count; + for (count = 0; int32_t(value) >= 0; count++) + value <<= 1; + return count; +} + +#endif + + +// Many of the Yamaha FM chips emit a floating-point value, which is sent to +// a DAC for processing. The exact format of this floating-point value is +// documented below. This description only makes sense if the "internal" +// format treats sign as 1=positive and 0=negative, so the helpers below +// presume that. +// +// Internal OPx data 16-bit signed data Exp Sign Mantissa +// ================= ================= === ==== ======== +// 1 1xxxxxxxx------ -> 0 1xxxxxxxx------ -> 111 1 1xxxxxxx +// 1 01xxxxxxxx----- -> 0 01xxxxxxxx----- -> 110 1 1xxxxxxx +// 1 001xxxxxxxx---- -> 0 001xxxxxxxx---- -> 101 1 1xxxxxxx +// 1 0001xxxxxxxx--- -> 0 0001xxxxxxxx--- -> 100 1 1xxxxxxx +// 1 00001xxxxxxxx-- -> 0 00001xxxxxxxx-- -> 011 1 1xxxxxxx +// 1 000001xxxxxxxx- -> 0 000001xxxxxxxx- -> 010 1 1xxxxxxx +// 1 000000xxxxxxxxx -> 0 000000xxxxxxxxx -> 001 1 xxxxxxxx +// 0 111111xxxxxxxxx -> 1 111111xxxxxxxxx -> 001 0 xxxxxxxx +// 0 111110xxxxxxxx- -> 1 111110xxxxxxxx- -> 010 0 0xxxxxxx +// 0 11110xxxxxxxx-- -> 1 11110xxxxxxxx-- -> 011 0 0xxxxxxx +// 0 1110xxxxxxxx--- -> 1 1110xxxxxxxx--- -> 100 0 0xxxxxxx +// 0 110xxxxxxxx---- -> 1 110xxxxxxxx---- -> 101 0 0xxxxxxx +// 0 10xxxxxxxx----- -> 1 10xxxxxxxx----- -> 110 0 0xxxxxxx +// 0 0xxxxxxxx------ -> 1 0xxxxxxxx------ -> 111 0 0xxxxxxx + +//------------------------------------------------- +// encode_fp - given a 32-bit signed input value +// convert it to a signed 3.10 floating-point +// value +//------------------------------------------------- + +inline int16_t encode_fp(int32_t value) +{ + // handle overflows first + if (value < -32768) + return (7 << 10) | 0x000; + if (value > 32767) + return (7 << 10) | 0x3ff; + + // we need to count the number of leading sign bits after the sign + // we can use count_leading_zeros if we invert negative values + int32_t scanvalue = value ^ (int32_t(value) >> 31); + + // exponent is related to the number of leading bits starting from bit 14 + int exponent = 7 - count_leading_zeros(scanvalue << 17); + + // smallest exponent value allowed is 1 + exponent = std::max(exponent, 1); + + // mantissa + int32_t mantissa = value >> (exponent - 1); + + // assemble into final form, inverting the sign + return ((exponent << 10) | (mantissa & 0x3ff)) ^ 0x200; +} + + +//------------------------------------------------- +// decode_fp - given a 3.10 floating-point value, +// convert it to a signed 16-bit value +//------------------------------------------------- + +inline int16_t decode_fp(int16_t value) +{ + // invert the sign and the exponent + value ^= 0x1e00; + + // shift mantissa up to 16 bits then apply inverted exponent + return int16_t(value << 6) >> bitfield(value, 10, 3); +} + + +//------------------------------------------------- +// roundtrip_fp - compute the result of a round +// trip through the encode/decode process above +//------------------------------------------------- + +inline int16_t roundtrip_fp(int32_t value) +{ + // handle overflows first + if (value < -32768) + return -32768; + if (value > 32767) + return 32767; + + // we need to count the number of leading sign bits after the sign + // we can use count_leading_zeros if we invert negative values + int32_t scanvalue = value ^ (int32_t(value) >> 31); + + // exponent is related to the number of leading bits starting from bit 14 + int exponent = 7 - count_leading_zeros(scanvalue << 17); + + // smallest exponent value allowed is 1 + exponent = std::max(exponent, 1); + + // apply the shift back and forth to zero out bits that are lost + exponent -= 1; + return (value >> exponent) << exponent; +} + + + +//********************************************************* +// HELPER CLASSES +//********************************************************* + +// various envelope states +enum envelope_state : uint32_t +{ + EG_DEPRESS = 0, // OPLL only; set EG_HAS_DEPRESS to enable + EG_ATTACK = 1, + EG_DECAY = 2, + EG_SUSTAIN = 3, + EG_RELEASE = 4, + EG_REVERB = 5, // OPQ/OPZ only; set EG_HAS_REVERB to enable + EG_STATES = 6 +}; + +// external I/O access classes +enum access_class : uint32_t +{ + ACCESS_IO = 0, + ACCESS_ADPCM_A, + ACCESS_ADPCM_B, + ACCESS_PCM, + ACCESS_CLASSES +}; + + + +//********************************************************* +// HELPER CLASSES +//********************************************************* + +// ======================> ymfm_output + +// struct containing an array of output values +template +struct ymfm_output +{ + // clear all outputs to 0 + ymfm_output &clear() + { + for (uint32_t index = 0; index < NumOutputs; index++) + data[index] = 0; + return *this; + } + + // clamp all outputs to a 16-bit signed value + ymfm_output &clamp16() + { + for (uint32_t index = 0; index < NumOutputs; index++) + data[index] = clamp(data[index], -32768, 32767); + return *this; + } + + // run each output value through the floating-point processor + ymfm_output &roundtrip_fp() + { + for (uint32_t index = 0; index < NumOutputs; index++) + data[index] = ymfm::roundtrip_fp(data[index]); + return *this; + } + + // internal state + int32_t data[NumOutputs]; +}; + + +// ======================> ymfm_wavfile + +// this class is a debugging helper that accumulates data and writes it to wav files +template +class ymfm_wavfile +{ +public: + // construction + ymfm_wavfile(uint32_t samplerate = 44100) : + m_samplerate(samplerate) + { + } + + // configuration + ymfm_wavfile &set_index(uint32_t index) { m_index = index; return *this; } + ymfm_wavfile &set_samplerate(uint32_t samplerate) { m_samplerate = samplerate; return *this; } + + // destruction + ~ymfm_wavfile() + { + if (!m_buffer.empty()) + { + // create file + char name[20]; + sprintf(name, "wavlog-%02d.wav", m_index); + FILE *out = fopen(name, "wb"); + + // make the wav file header + uint8_t header[44]; + memcpy(&header[0], "RIFF", 4); + *(uint32_t *)&header[4] = m_buffer.size() * 2 + 44 - 8; + memcpy(&header[8], "WAVE", 4); + memcpy(&header[12], "fmt ", 4); + *(uint32_t *)&header[16] = 16; + *(uint16_t *)&header[20] = 1; + *(uint16_t *)&header[22] = _Channels; + *(uint32_t *)&header[24] = m_samplerate; + *(uint32_t *)&header[28] = m_samplerate * 2 * _Channels; + *(uint16_t *)&header[32] = 2 * _Channels; + *(uint16_t *)&header[34] = 16; + memcpy(&header[36], "data", 4); + *(uint32_t *)&header[40] = m_buffer.size() * 2 + 44 - 44; + + // write header then data + fwrite(&header[0], 1, sizeof(header), out); + fwrite(&m_buffer[0], 2, m_buffer.size(), out); + fclose(out); + } + } + + // add data to the file + template + void add(ymfm_output<_Outputs> output) + { + int16_t sum[_Channels] = { 0 }; + for (int index = 0; index < _Outputs; index++) + sum[index % _Channels] += output.data[index]; + for (int index = 0; index < _Channels; index++) + m_buffer.push_back(sum[index]); + } + + // add data to the file, using a reference + template + void add(ymfm_output<_Outputs> output, ymfm_output<_Outputs> const &ref) + { + int16_t sum[_Channels] = { 0 }; + for (int index = 0; index < _Outputs; index++) + sum[index % _Channels] += output.data[index] - ref.data[index]; + for (int index = 0; index < _Channels; index++) + m_buffer.push_back(sum[index]); + } + +private: + // internal state + uint32_t m_index; + uint32_t m_samplerate; + std::vector m_buffer; +}; + + +// ======================> ymfm_saved_state + +// this class contains a managed vector of bytes that is used to save and +// restore state +class ymfm_saved_state +{ +public: + // construction + ymfm_saved_state(std::vector &buffer, bool saving) : + m_buffer(buffer), + m_offset(saving ? -1 : 0) + { + if (saving) + buffer.resize(0); + } + + // are we saving or restoring? + bool saving() const { return (m_offset < 0); } + + // generic save/restore + template + void save_restore(DataType &data) + { + if (saving()) + save(data); + else + restore(data); + } + +public: + // save data to the buffer + void save(bool &data) { write(data ? 1 : 0); } + void save(int8_t &data) { write(data); } + void save(uint8_t &data) { write(data); } + void save(int16_t &data) { write(uint8_t(data)).write(data >> 8); } + void save(uint16_t &data) { write(uint8_t(data)).write(data >> 8); } + void save(int32_t &data) { write(data).write(data >> 8).write(data >> 16).write(data >> 24); } + void save(uint32_t &data) { write(data).write(data >> 8).write(data >> 16).write(data >> 24); } + void save(envelope_state &data) { write(uint8_t(data)); } + template + void save(DataType (&data)[Count]) { for (uint32_t index = 0; index < Count; index++) save(data[index]); } + + // restore data from the buffer + void restore(bool &data) { data = read() ? true : false; } + void restore(int8_t &data) { data = read(); } + void restore(uint8_t &data) { data = read(); } + void restore(int16_t &data) { data = read(); data |= read() << 8; } + void restore(uint16_t &data) { data = read(); data |= read() << 8; } + void restore(int32_t &data) { data = read(); data |= read() << 8; data |= read() << 16; data |= read() << 24; } + void restore(uint32_t &data) { data = read(); data |= read() << 8; data |= read() << 16; data |= read() << 24; } + void restore(envelope_state &data) { data = envelope_state(read()); } + template + void restore(DataType (&data)[Count]) { for (uint32_t index = 0; index < Count; index++) restore(data[index]); } + + // internal helper + ymfm_saved_state &write(uint8_t data) { m_buffer.push_back(data); return *this; } + uint8_t read() { return (m_offset < int32_t(m_buffer.size())) ? m_buffer[m_offset++] : 0; } + + // internal state + std::vector &m_buffer; + int32_t m_offset; +}; + + + +//********************************************************* +// INTERFACE CLASSES +//********************************************************* + +// ======================> ymfm_engine_callbacks + +// this class represents functions in the engine that the ymfm_interface +// needs to be able to call; it is represented here as a separate interface +// that is independent of the actual engine implementation +class ymfm_engine_callbacks +{ +public: + // timer callback; called by the interface when a timer fires + virtual void engine_timer_expired(uint32_t tnum) = 0; + + // check interrupts; called by the interface after synchronization + virtual void engine_check_interrupts() = 0; + + // mode register write; called by the interface after synchronization + virtual void engine_mode_write(uint8_t data) = 0; +}; + + +// ======================> ymfm_interface + +// this class represents the interface between the fm_engine and the outside +// world; it provides hooks for timers, synchronization, and I/O +class ymfm_interface +{ + // the engine is our friend + template friend class fm_engine_base; + +public: + // the following functions must be implemented by any derived classes; the + // default implementations are sufficient for some minimal operation, but will + // likely need to be overridden to integrate with the outside world; they are + // all prefixed with ymfm_ to reduce the likelihood of namespace collisions + + // + // timing and synchronizaton + // + + // the chip implementation calls this when a write happens to the mode + // register, which could affect timers and interrupts; our responsibility + // is to ensure the system is up to date before calling the engine's + // engine_mode_write() method + virtual void ymfm_sync_mode_write(uint8_t data) { m_engine->engine_mode_write(data); } + + // the chip implementation calls this when the chip's status has changed, + // which may affect the interrupt state; our responsibility is to ensure + // the system is up to date before calling the engine's + // engine_check_interrupts() method + virtual void ymfm_sync_check_interrupts() { m_engine->engine_check_interrupts(); } + + // the chip implementation calls this when one of the two internal timers + // has changed state; our responsibility is to arrange to call the engine's + // engine_timer_expired() method after the provided number of clocks; if + // duration_in_clocks is negative, we should cancel any outstanding timers + virtual void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) { } + + // the chip implementation calls this to indicate that the chip should be + // considered in a busy state until the given number of clocks has passed; + // our responsibility is to compute and remember the ending time based on + // the chip's clock for later checking + virtual void ymfm_set_busy_end(uint32_t clocks) { } + + // the chip implementation calls this to see if the chip is still currently + // is a busy state, as specified by a previous call to ymfm_set_busy_end(); + // our responsibility is to compare the current time against the previously + // noted busy end time and return true if we haven't yet passed it + virtual bool ymfm_is_busy() { return false; } + + virtual uint32_t get_special_flags(void) { return 0x0000; } + + // + // I/O functions + // + + // the chip implementation calls this when the state of the IRQ signal has + // changed due to a status change; our responsibility is to respond as + // needed to the change in IRQ state, signaling any consumers + virtual void ymfm_update_irq(bool asserted) { } + + // the chip implementation calls this whenever data is read from outside + // of the chip; our responsibility is to provide the data requested + virtual uint8_t ymfm_external_read(access_class type, uint32_t address) { return 0; } + + // the chip implementation calls this whenever data is written outside + // of the chip; our responsibility is to pass the written data on to any consumers + virtual void ymfm_external_write(access_class type, uint32_t address, uint8_t data) { } + +protected: + // pointer to engine callbacks -- this is set directly by the engine at + // construction time + ymfm_engine_callbacks *m_engine; +}; + +} + +#endif // YMFM_H diff --git a/src/sound/ymfm/ymfm_adpcm.cpp b/src/sound/ymfm/ymfm_adpcm.cpp new file mode 100644 index 000000000..4bc22beb2 --- /dev/null +++ b/src/sound/ymfm/ymfm_adpcm.cpp @@ -0,0 +1,807 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_adpcm.h" + +namespace ymfm +{ + +//********************************************************* +// ADPCM "A" REGISTERS +//********************************************************* + +//------------------------------------------------- +// reset - reset the register state +//------------------------------------------------- + +void adpcm_a_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + + // initialize the pans to on by default, and max instrument volume; + // some neogeo homebrews (for example ffeast) rely on this + m_regdata[0x08] = m_regdata[0x09] = m_regdata[0x0a] = + m_regdata[0x0b] = m_regdata[0x0c] = m_regdata[0x0d] = 0xdf; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void adpcm_a_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_regdata); +} + + +//********************************************************* +// ADPCM "A" CHANNEL +//********************************************************* + +//------------------------------------------------- +// adpcm_a_channel - constructor +//------------------------------------------------- + +adpcm_a_channel::adpcm_a_channel(adpcm_a_engine &owner, uint32_t choffs, uint32_t addrshift) : + m_choffs(choffs), + m_address_shift(addrshift), + m_playing(0), + m_curnibble(0), + m_curbyte(0), + m_curaddress(0), + m_accumulator(0), + m_step_index(0), + m_regs(owner.regs()), + m_owner(owner) +{ +} + + +//------------------------------------------------- +// reset - reset the channel state +//------------------------------------------------- + +void adpcm_a_channel::reset() +{ + m_playing = 0; + m_curnibble = 0; + m_curbyte = 0; + m_curaddress = 0; + m_accumulator = 0; + m_step_index = 0; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void adpcm_a_channel::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_playing); + state.save_restore(m_curnibble); + state.save_restore(m_curbyte); + state.save_restore(m_curaddress); + state.save_restore(m_accumulator); + state.save_restore(m_step_index); +} + + +//------------------------------------------------- +// keyonoff - signal key on/off +//------------------------------------------------- + +void adpcm_a_channel::keyonoff(bool on) +{ + // QUESTION: repeated key ons restart the sample? + m_playing = on; + if (m_playing) + { + m_curaddress = m_regs.ch_start(m_choffs) << m_address_shift; + m_curnibble = 0; + m_curbyte = 0; + m_accumulator = 0; + m_step_index = 0; + + // don't log masked channels + if (((debug::GLOBAL_ADPCM_A_CHANNEL_MASK >> m_choffs) & 1) != 0) + debug::log_keyon("KeyOn ADPCM-A%d: pan=%d%d start=%04X end=%04X level=%02X\n", + m_choffs, + m_regs.ch_pan_left(m_choffs), + m_regs.ch_pan_right(m_choffs), + m_regs.ch_start(m_choffs), + m_regs.ch_end(m_choffs), + m_regs.ch_instrument_level(m_choffs)); + } +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +bool adpcm_a_channel::clock() +{ + // if not playing, just output 0 + if (m_playing == 0) + { + m_accumulator = 0; + return false; + } + + // if we're about to read nibble 0, fetch the data + uint8_t data; + if (m_curnibble == 0) + { + // stop when we hit the end address; apparently only low 20 bits are used for + // comparison on the YM2610: this affects sample playback in some games, for + // example twinspri character select screen music will skip some samples if + // this is not correct + // + // note also: end address is inclusive, so wait until we are about to fetch + // the sample just after the end before stopping; this is needed for nitd's + // jump sound, for example + uint32_t end = (m_regs.ch_end(m_choffs) + 1) << m_address_shift; + if (((m_curaddress ^ end) & 0xfffff) == 0) + { + m_playing = m_accumulator = 0; + return true; + } + + m_curbyte = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_A, m_curaddress++); + data = m_curbyte >> 4; + m_curnibble = 1; + } + + // otherwise just extract from the previosuly-fetched byte + else + { + data = m_curbyte & 0xf; + m_curnibble = 0; + } + + // compute the ADPCM delta + static uint16_t const s_steps[49] = + { + 16, 17, 19, 21, 23, 25, 28, + 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, + 118, 130, 143, 157, 173, 190, 209, + 230, 253, 279, 307, 337, 371, 408, + 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552 + }; + int32_t delta = (2 * bitfield(data, 0, 3) + 1) * s_steps[m_step_index] / 8; + if (bitfield(data, 3)) + delta = -delta; + + // the 12-bit accumulator wraps on the ym2610 and ym2608 (like the msm5205) + m_accumulator = (m_accumulator + delta) & 0xfff; + + // adjust ADPCM step + static int8_t const s_step_inc[8] = { -1, -1, -1, -1, 2, 5, 7, 9 }; + m_step_index = clamp(m_step_index + s_step_inc[bitfield(data, 0, 3)], 0, 48); + + return false; +} + + +//------------------------------------------------- +// output - return the computed output value, with +// panning applied +//------------------------------------------------- + +template +void adpcm_a_channel::output(ymfm_output &output) const +{ + // volume combines instrument and total levels + int vol = (m_regs.ch_instrument_level(m_choffs) ^ 0x1f) + (m_regs.total_level() ^ 0x3f); + + // if combined is maximum, don't add to outputs + if (vol >= 63) + return; + + // convert into a shift and a multiplier + // QUESTION: verify this from other sources + int8_t mul = 15 - (vol & 7); + uint8_t shift = 4 + 1 + (vol >> 3); + + // m_accumulator is a 12-bit value; shift up to sign-extend; + // the downshift is incorporated into 'shift' + int16_t value = ((int16_t(m_accumulator << 4) * mul) >> shift) & ~3; + + // apply to left/right as appropriate + if (NumOutputs == 1 || m_regs.ch_pan_left(m_choffs)) + output.data[0] += value; + if (NumOutputs > 1 && m_regs.ch_pan_right(m_choffs)) + output.data[1] += value; +} + + + +//********************************************************* +// ADPCM "A" ENGINE +//********************************************************* + +//------------------------------------------------- +// adpcm_a_engine - constructor +//------------------------------------------------- + +adpcm_a_engine::adpcm_a_engine(ymfm_interface &intf, uint32_t addrshift) : + m_intf(intf) +{ + // create the channels + for (int chnum = 0; chnum < CHANNELS; chnum++) + m_channel[chnum] = std::make_unique(*this, chnum, addrshift); +} + + +//------------------------------------------------- +// reset - reset the engine state +//------------------------------------------------- + +void adpcm_a_engine::reset() +{ + // reset register state + m_regs.reset(); + + // reset each channel + for (auto &chan : m_channel) + chan->reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void adpcm_a_engine::save_restore(ymfm_saved_state &state) +{ + // save register state + m_regs.save_restore(state); + + // save channel state + for (int chnum = 0; chnum < CHANNELS; chnum++) + m_channel[chnum]->save_restore(state); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +uint32_t adpcm_a_engine::clock(uint32_t chanmask) +{ + // clock each channel, setting a bit in result if it finished + uint32_t result = 0; + for (int chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + if (m_channel[chnum]->clock()) + result |= 1 << chnum; + + // return the bitmask of completed samples + return result; +} + + +//------------------------------------------------- +// update - master update function +//------------------------------------------------- + +template +void adpcm_a_engine::output(ymfm_output &output, uint32_t chanmask) +{ + // mask out some channels for debug purposes + chanmask &= debug::GLOBAL_ADPCM_A_CHANNEL_MASK; + + // compute the output of each channel + for (int chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + m_channel[chnum]->output(output); +} + +template void adpcm_a_engine::output<1>(ymfm_output<1> &output, uint32_t chanmask); +template void adpcm_a_engine::output<2>(ymfm_output<2> &output, uint32_t chanmask); + + +//------------------------------------------------- +// write - handle writes to the ADPCM-A registers +//------------------------------------------------- + +void adpcm_a_engine::write(uint32_t regnum, uint8_t data) +{ + // store the raw value to the register array; + // most writes are passive, consumed only when needed + m_regs.write(regnum, data); + + // actively handle writes to the control register + if (regnum == 0x00) + for (int chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(data, chnum)) + m_channel[chnum]->keyonoff(bitfield(~data, 7)); +} + + + +//********************************************************* +// ADPCM "B" REGISTERS +//********************************************************* + +//------------------------------------------------- +// reset - reset the register state +//------------------------------------------------- + +void adpcm_b_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + + // default limit to wide open + m_regdata[0x0c] = m_regdata[0x0d] = 0xff; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void adpcm_b_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_regdata); +} + + + +//********************************************************* +// ADPCM "B" CHANNEL +//********************************************************* + +//------------------------------------------------- +// adpcm_b_channel - constructor +//------------------------------------------------- + +adpcm_b_channel::adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift) : + m_address_shift(addrshift), + m_status(STATUS_BRDY), + m_curnibble(0), + m_curbyte(0), + m_dummy_read(0), + m_position(0), + m_curaddress(0), + m_accumulator(0), + m_prev_accum(0), + m_adpcm_step(STEP_MIN), + m_regs(owner.regs()), + m_owner(owner) +{ +} + + +//------------------------------------------------- +// reset - reset the channel state +//------------------------------------------------- + +void adpcm_b_channel::reset() +{ + m_status = STATUS_BRDY; + m_curnibble = 0; + m_curbyte = 0; + m_dummy_read = 0; + m_position = 0; + m_curaddress = 0; + m_accumulator = 0; + m_prev_accum = 0; + m_adpcm_step = STEP_MIN; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void adpcm_b_channel::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_status); + state.save_restore(m_curnibble); + state.save_restore(m_curbyte); + state.save_restore(m_dummy_read); + state.save_restore(m_position); + state.save_restore(m_curaddress); + state.save_restore(m_accumulator); + state.save_restore(m_prev_accum); + state.save_restore(m_adpcm_step); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +void adpcm_b_channel::clock() +{ + // only process if active and not recording (which we don't support) + if (!m_regs.execute() || m_regs.record() || (m_status & STATUS_PLAYING) == 0) + { + m_status &= ~STATUS_PLAYING; + return; + } + + // otherwise, advance the step + uint32_t position = m_position + m_regs.delta_n(); + m_position = uint16_t(position); + if (position < 0x10000) + return; + + // if we're about to process nibble 0, fetch sample + if (m_curnibble == 0) + { + // playing from RAM/ROM + if (m_regs.external()) + m_curbyte = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress); + } + + // extract the nibble from our current byte + uint8_t data = uint8_t(m_curbyte << (4 * m_curnibble)) >> 4; + m_curnibble ^= 1; + + // we just processed the last nibble + if (m_curnibble == 0) + { + // if playing from RAM/ROM, check the end/limit address or advance + if (m_regs.external()) + { + // handle the sample end, either repeating or stopping + if (at_end()) + { + // if repeating, go back to the start + if (m_regs.repeat()) + load_start(); + + // otherwise, done; set the EOS bit + else + { + m_accumulator = 0; + m_prev_accum = 0; + m_status = (m_status & ~STATUS_PLAYING) | STATUS_EOS; + debug::log_keyon("%s\n", "ADPCM EOS"); + return; + } + } + + // wrap at the limit address + else if (at_limit()) + m_curaddress = 0; + + // otherwise, advance the current address + else + { + m_curaddress++; + m_curaddress &= 0xffffff; + } + } + + // if CPU-driven, copy the next byte and request more + else + { + m_curbyte = m_regs.cpudata(); + m_status |= STATUS_BRDY; + } + } + + // remember previous value for interpolation + m_prev_accum = m_accumulator; + + // forecast to next forecast: 1/8, 3/8, 5/8, 7/8, 9/8, 11/8, 13/8, 15/8 + int32_t delta = (2 * bitfield(data, 0, 3) + 1) * m_adpcm_step / 8; + if (bitfield(data, 3)) + delta = -delta; + + // add and clamp to 16 bits + m_accumulator = clamp(m_accumulator + delta, -32768, 32767); + + // scale the ADPCM step: 0.9, 0.9, 0.9, 0.9, 1.2, 1.6, 2.0, 2.4 + static uint8_t const s_step_scale[8] = { 57, 57, 57, 57, 77, 102, 128, 153 }; + m_adpcm_step = clamp((m_adpcm_step * s_step_scale[bitfield(data, 0, 3)]) / 64, STEP_MIN, STEP_MAX); +} + + +//------------------------------------------------- +// output - return the computed output value, with +// panning applied +//------------------------------------------------- + +template +void adpcm_b_channel::output(ymfm_output &output, uint32_t rshift) const +{ + // mask out some channels for debug purposes + if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) == 0) + return; + + // do a linear interpolation between samples + int32_t result = (m_prev_accum * int32_t((m_position ^ 0xffff) + 1) + m_accumulator * int32_t(m_position)) >> 16; + + // apply volume (level) in a linear fashion and reduce + result = (result * int32_t(m_regs.level())) >> (8 + rshift); + + // apply to left/right + if (NumOutputs == 1 || m_regs.pan_left()) + output.data[0] += result; + if (NumOutputs > 1 && m_regs.pan_right()) + output.data[1] += result; +} + + +//------------------------------------------------- +// read - handle special register reads +//------------------------------------------------- + +uint8_t adpcm_b_channel::read(uint32_t regnum) +{ + uint8_t result = 0; + + // register 8 reads over the bus under some conditions + if (regnum == 0x08 && !m_regs.execute() && !m_regs.record() && m_regs.external()) + { + // two dummy reads are consumed first + if (m_dummy_read != 0) + { + load_start(); + m_dummy_read--; + } + + // read the data + else + { + // read from outside of the chip + result = m_owner.intf().ymfm_external_read(ACCESS_ADPCM_B, m_curaddress++); + + // did we hit the end? if so, signal EOS + if (at_end()) + { + m_status = STATUS_EOS | STATUS_BRDY; + debug::log_keyon("%s\n", "ADPCM EOS"); + } + else + { + // signal ready + m_status = STATUS_BRDY; + } + + // wrap at the limit address + if (at_limit()) + m_curaddress = 0; + } + } + return result; +} + + +//------------------------------------------------- +// write - handle special register writes +//------------------------------------------------- + +void adpcm_b_channel::write(uint32_t regnum, uint8_t value) +{ + // register 0 can do a reset; also use writes here to reset the + // dummy read counter + if (regnum == 0x00) + { + if (m_regs.execute()) + { + load_start(); + + // don't log masked channels + if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) != 0) + debug::log_keyon("KeyOn ADPCM-B: rep=%d spk=%d pan=%d%d dac=%d 8b=%d rom=%d ext=%d rec=%d start=%04X end=%04X pre=%04X dn=%04X lvl=%02X lim=%04X\n", + m_regs.repeat(), + m_regs.speaker(), + m_regs.pan_left(), + m_regs.pan_right(), + m_regs.dac_enable(), + m_regs.dram_8bit(), + m_regs.rom_ram(), + m_regs.external(), + m_regs.record(), + m_regs.start(), + m_regs.end(), + m_regs.prescale(), + m_regs.delta_n(), + m_regs.level(), + m_regs.limit()); + } + else + m_status &= ~STATUS_EOS; + if (m_regs.resetflag()) + reset(); + if (m_regs.external()) + m_dummy_read = 2; + } + + // register 8 writes over the bus under some conditions + else if (regnum == 0x08) + { + // if writing from the CPU during execute, clear the ready flag + if (m_regs.execute() && !m_regs.record() && !m_regs.external()) + m_status &= ~STATUS_BRDY; + + // if writing during "record", pass through as data + else if (!m_regs.execute() && m_regs.record() && m_regs.external()) + { + // clear out dummy reads and set start address + if (m_dummy_read != 0) + { + load_start(); + m_dummy_read = 0; + } + + // did we hit the end? if so, signal EOS + if (at_end()) + { + debug::log_keyon("%s\n", "ADPCM EOS"); + m_status = STATUS_EOS | STATUS_BRDY; + } + + // otherwise, write the data and signal ready + else + { + m_owner.intf().ymfm_external_write(ACCESS_ADPCM_B, m_curaddress++, value); + m_status = STATUS_BRDY; + } + } + } +} + + +//------------------------------------------------- +// address_shift - compute the current address +// shift amount based on register settings +//------------------------------------------------- + +uint32_t adpcm_b_channel::address_shift() const +{ + // if a constant address shift, just provide that + if (m_address_shift != 0) + return m_address_shift; + + // if ROM or 8-bit DRAM, shift is 5 bits + if (m_regs.rom_ram()) + return 5; + if (m_regs.dram_8bit()) + return 5; + + // otherwise, shift is 2 bits + return 2; +} + + +//------------------------------------------------- +// load_start - load the start address and +// initialize the state +//------------------------------------------------- + +void adpcm_b_channel::load_start() +{ + m_status = (m_status & ~STATUS_EOS) | STATUS_PLAYING; + m_curaddress = m_regs.external() ? (m_regs.start() << address_shift()) : 0; + m_curnibble = 0; + m_curbyte = 0; + m_position = 0; + m_accumulator = 0; + m_prev_accum = 0; + m_adpcm_step = STEP_MIN; +} + + + +//********************************************************* +// ADPCM "B" ENGINE +//********************************************************* + +//------------------------------------------------- +// adpcm_b_engine - constructor +//------------------------------------------------- + +adpcm_b_engine::adpcm_b_engine(ymfm_interface &intf, uint32_t addrshift) : + m_intf(intf) +{ + // create the channel (only one supported for now, but leaving possibilities open) + m_channel = std::make_unique(*this, addrshift); +} + + +//------------------------------------------------- +// reset - reset the engine state +//------------------------------------------------- + +void adpcm_b_engine::reset() +{ + // reset registers + m_regs.reset(); + + // reset each channel + m_channel->reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void adpcm_b_engine::save_restore(ymfm_saved_state &state) +{ + // save our state + m_regs.save_restore(state); + + // save channel state + m_channel->save_restore(state); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +void adpcm_b_engine::clock() +{ + // clock each channel, setting a bit in result if it finished + m_channel->clock(); +} + + +//------------------------------------------------- +// output - master output function +//------------------------------------------------- + +template +void adpcm_b_engine::output(ymfm_output &output, uint32_t rshift) +{ + // compute the output of each channel + m_channel->output(output, rshift); +} + +template void adpcm_b_engine::output<1>(ymfm_output<1> &output, uint32_t rshift); +template void adpcm_b_engine::output<2>(ymfm_output<2> &output, uint32_t rshift); + + +//------------------------------------------------- +// write - handle writes to the ADPCM-B registers +//------------------------------------------------- + +void adpcm_b_engine::write(uint32_t regnum, uint8_t data) +{ + // store the raw value to the register array; + // most writes are passive, consumed only when needed + m_regs.write(regnum, data); + + // let the channel handle any special writes + m_channel->write(regnum, data); +} + +} diff --git a/src/sound/ymfm/ymfm_adpcm.h b/src/sound/ymfm/ymfm_adpcm.h new file mode 100644 index 000000000..d74e24f27 --- /dev/null +++ b/src/sound/ymfm/ymfm_adpcm.h @@ -0,0 +1,411 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_ADPCM_H +#define YMFM_ADPCM_H + +#pragma once + +#include "ymfm.h" + +namespace ymfm +{ + +//********************************************************* +// INTERFACE CLASSES +//********************************************************* + +// forward declarations +class adpcm_a_engine; +class adpcm_b_engine; + + +// ======================> adpcm_a_registers + +// +// ADPCM-A register map: +// +// System-wide registers: +// 00 x------- Dump (disable=1) or keyon (0) control +// --xxxxxx Mask of channels to dump or keyon +// 01 --xxxxxx Total level +// 02 xxxxxxxx Test register +// 08-0D x------- Pan left +// -x------ Pan right +// ---xxxxx Instrument level +// 10-15 xxxxxxxx Start address (low) +// 18-1D xxxxxxxx Start address (high) +// 20-25 xxxxxxxx End address (low) +// 28-2D xxxxxxxx End address (high) +// +class adpcm_a_registers +{ +public: + // constants + static constexpr uint32_t OUTPUTS = 2; + static constexpr uint32_t CHANNELS = 6; + static constexpr uint32_t REGISTERS = 0x30; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + + // constructor + adpcm_a_registers() { } + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + return chnum; + } + + // direct read/write access + void write(uint32_t index, uint8_t data) { m_regdata[index] = data; } + + // system-wide registers + uint32_t dump() const { return bitfield(m_regdata[0x00], 7); } + uint32_t dump_mask() const { return bitfield(m_regdata[0x00], 0, 6); } + uint32_t total_level() const { return bitfield(m_regdata[0x01], 0, 6); } + uint32_t test() const { return m_regdata[0x02]; } + + // per-channel registers + uint32_t ch_pan_left(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x08], 7); } + uint32_t ch_pan_right(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x08], 6); } + uint32_t ch_instrument_level(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x08], 0, 5); } + uint32_t ch_start(uint32_t choffs) const { return m_regdata[choffs + 0x10] | (m_regdata[choffs + 0x18] << 8); } + uint32_t ch_end(uint32_t choffs) const { return m_regdata[choffs + 0x20] | (m_regdata[choffs + 0x28] << 8); } + + // per-channel writes + void write_start(uint32_t choffs, uint32_t address) + { + write(choffs + 0x10, address); + write(choffs + 0x18, address >> 8); + } + void write_end(uint32_t choffs, uint32_t address) + { + write(choffs + 0x20, address); + write(choffs + 0x28, address >> 8); + } + +private: + // internal state + uint8_t m_regdata[REGISTERS]; // register data +}; + + +// ======================> adpcm_a_channel + +class adpcm_a_channel +{ +public: + // constructor + adpcm_a_channel(adpcm_a_engine &owner, uint32_t choffs, uint32_t addrshift); + + // reset the channel state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // signal key on/off + void keyonoff(bool on); + + // master clockingfunction + bool clock(); + + // return the computed output value, with panning applied + template + void output(ymfm_output &output) const; + +private: + // internal state + uint32_t const m_choffs; // channel offset + uint32_t const m_address_shift; // address bits shift-left + uint32_t m_playing; // currently playing? + uint32_t m_curnibble; // index of the current nibble + uint32_t m_curbyte; // current byte of data + uint32_t m_curaddress; // current address + int32_t m_accumulator; // accumulator + int32_t m_step_index; // index in the stepping table + adpcm_a_registers &m_regs; // reference to registers + adpcm_a_engine &m_owner; // reference to our owner +}; + + +// ======================> adpcm_a_engine + +class adpcm_a_engine +{ +public: + static constexpr int CHANNELS = adpcm_a_registers::CHANNELS; + + // constructor + adpcm_a_engine(ymfm_interface &intf, uint32_t addrshift); + + // reset our status + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // master clocking function + uint32_t clock(uint32_t chanmask); + + // compute sum of channel outputs + template + void output(ymfm_output &output, uint32_t chanmask); + + // write to the ADPCM-A registers + void write(uint32_t regnum, uint8_t data); + + // set the start/end address for a channel (for hardcoded YM2608 percussion) + void set_start_end(uint8_t chnum, uint16_t start, uint16_t end) + { + uint32_t choffs = adpcm_a_registers::channel_offset(chnum); + m_regs.write_start(choffs, start); + m_regs.write_end(choffs, end); + } + + // return a reference to our interface + ymfm_interface &intf() { return m_intf; } + + // return a reference to our registers + adpcm_a_registers ®s() { return m_regs; } + +private: + // internal state + ymfm_interface &m_intf; // reference to the interface + std::unique_ptr m_channel[CHANNELS]; // array of channels + adpcm_a_registers m_regs; // registers +}; + + +// ======================> adpcm_b_registers + +// +// ADPCM-B register map: +// +// System-wide registers: +// 00 x------- Start of synthesis/analysis +// -x------ Record +// --x----- External/manual driving +// ---x---- Repeat playback +// ----x--- Speaker off +// -------x Reset +// 01 x------- Pan left +// -x------ Pan right +// ----x--- Start conversion +// -----x-- DAC enable +// ------x- DRAM access (1=8-bit granularity; 0=1-bit) +// -------x RAM/ROM (1=ROM, 0=RAM) +// 02 xxxxxxxx Start address (low) +// 03 xxxxxxxx Start address (high) +// 04 xxxxxxxx End address (low) +// 05 xxxxxxxx End address (high) +// 06 xxxxxxxx Prescale value (low) +// 07 -----xxx Prescale value (high) +// 08 xxxxxxxx CPU data/buffer +// 09 xxxxxxxx Delta-N frequency scale (low) +// 0a xxxxxxxx Delta-N frequency scale (high) +// 0b xxxxxxxx Level control +// 0c xxxxxxxx Limit address (low) +// 0d xxxxxxxx Limit address (high) +// 0e xxxxxxxx DAC data [YM2608/10] +// 0f xxxxxxxx PCM data [YM2608/10] +// 0e xxxxxxxx DAC data high [Y8950] +// 0f xx------ DAC data low [Y8950] +// 10 -----xxx DAC data exponent [Y8950] +// +class adpcm_b_registers +{ +public: + // constants + static constexpr uint32_t REGISTERS = 0x11; + + // constructor + adpcm_b_registers() { } + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // direct read/write access + void write(uint32_t index, uint8_t data) { m_regdata[index] = data; } + + // system-wide registers + uint32_t execute() const { return bitfield(m_regdata[0x00], 7); } + uint32_t record() const { return bitfield(m_regdata[0x00], 6); } + uint32_t external() const { return bitfield(m_regdata[0x00], 5); } + uint32_t repeat() const { return bitfield(m_regdata[0x00], 4); } + uint32_t speaker() const { return bitfield(m_regdata[0x00], 3); } + uint32_t resetflag() const { return bitfield(m_regdata[0x00], 0); } + uint32_t pan_left() const { return bitfield(m_regdata[0x01], 7); } + uint32_t pan_right() const { return bitfield(m_regdata[0x01], 6); } + uint32_t start_conversion() const { return bitfield(m_regdata[0x01], 3); } + uint32_t dac_enable() const { return bitfield(m_regdata[0x01], 2); } + uint32_t dram_8bit() const { return bitfield(m_regdata[0x01], 1); } + uint32_t rom_ram() const { return bitfield(m_regdata[0x01], 0); } + uint32_t start() const { return m_regdata[0x02] | (m_regdata[0x03] << 8); } + uint32_t end() const { return m_regdata[0x04] | (m_regdata[0x05] << 8); } + uint32_t prescale() const { return m_regdata[0x06] | (bitfield(m_regdata[0x07], 0, 3) << 8); } + uint32_t cpudata() const { return m_regdata[0x08]; } + uint32_t delta_n() const { return m_regdata[0x09] | (m_regdata[0x0a] << 8); } + uint32_t level() const { return m_regdata[0x0b]; } + uint32_t limit() const { return m_regdata[0x0c] | (m_regdata[0x0d] << 8); } + uint32_t dac() const { return m_regdata[0x0e]; } + uint32_t pcm() const { return m_regdata[0x0f]; } + +private: + // internal state + uint8_t m_regdata[REGISTERS]; // register data +}; + + +// ======================> adpcm_b_channel + +class adpcm_b_channel +{ + static constexpr int32_t STEP_MIN = 127; + static constexpr int32_t STEP_MAX = 24576; + +public: + static constexpr uint8_t STATUS_EOS = 0x01; + static constexpr uint8_t STATUS_BRDY = 0x02; + static constexpr uint8_t STATUS_PLAYING = 0x04; + + // constructor + adpcm_b_channel(adpcm_b_engine &owner, uint32_t addrshift); + + // reset the channel state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // signal key on/off + void keyonoff(bool on); + + // master clocking function + void clock(); + + // return the computed output value, with panning applied + template + void output(ymfm_output &output, uint32_t rshift) const; + + // return the status register + uint8_t status() const { return m_status; } + + // handle special register reads + uint8_t read(uint32_t regnum); + + // handle special register writes + void write(uint32_t regnum, uint8_t value); + +private: + // helper - return the current address shift + uint32_t address_shift() const; + + // load the start address + void load_start(); + + // limit checker; stops at the last byte of the chunk described by address_shift() + bool at_limit() const { return (m_curaddress == (((m_regs.limit() + 1) << address_shift()) - 1)); } + + // end checker; stops at the last byte of the chunk described by address_shift() + bool at_end() const { return (m_curaddress == (((m_regs.end() + 1) << address_shift()) - 1)); } + + // internal state + uint32_t const m_address_shift; // address bits shift-left + uint32_t m_status; // currently playing? + uint32_t m_curnibble; // index of the current nibble + uint32_t m_curbyte; // current byte of data + uint32_t m_dummy_read; // dummy read tracker + uint32_t m_position; // current fractional position + uint32_t m_curaddress; // current address + int32_t m_accumulator; // accumulator + int32_t m_prev_accum; // previous accumulator (for linear interp) + int32_t m_adpcm_step; // next forecast + adpcm_b_registers &m_regs; // reference to registers + adpcm_b_engine &m_owner; // reference to our owner +}; + + +// ======================> adpcm_b_engine + +class adpcm_b_engine +{ +public: + // constructor + adpcm_b_engine(ymfm_interface &intf, uint32_t addrshift = 0); + + // reset our status + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // master clocking function + void clock(); + + // compute sum of channel outputs + template + void output(ymfm_output &output, uint32_t rshift); + + // read from the ADPCM-B registers + uint32_t read(uint32_t regnum) { return m_channel->read(regnum); } + + // write to the ADPCM-B registers + void write(uint32_t regnum, uint8_t data); + + // status + uint8_t status() const { return m_channel->status(); } + + // return a reference to our interface + ymfm_interface &intf() { return m_intf; } + + // return a reference to our registers + adpcm_b_registers ®s() { return m_regs; } + +private: + // internal state + ymfm_interface &m_intf; // reference to our interface + std::unique_ptr m_channel; // channel pointer + adpcm_b_registers m_regs; // registers +}; + +} + +#endif // YMFM_ADPCM_H diff --git a/src/sound/ymfm/ymfm_fm.h b/src/sound/ymfm/ymfm_fm.h new file mode 100644 index 000000000..7c92c0f82 --- /dev/null +++ b/src/sound/ymfm/ymfm_fm.h @@ -0,0 +1,463 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_FM_H +#define YMFM_FM_H + +#pragma once + +#define DEBUG_LOG_WAVFILES (0) + +namespace ymfm +{ + +//********************************************************* +// GLOBAL ENUMERATORS +//********************************************************* + +// three different keyon sources; actual keyon is an OR over all of these +enum keyon_type : uint32_t +{ + KEYON_NORMAL = 0, + KEYON_RHYTHM = 1, + KEYON_CSM = 2 +}; + + + +//********************************************************* +// CORE IMPLEMENTATION +//********************************************************* + +// ======================> opdata_cache + +// this class holds data that is computed once at the start of clocking +// and remains static during subsequent sound generation +struct opdata_cache +{ + // set phase_step to this value to recalculate it each sample; needed + // in the case of PM LFO changes + static constexpr uint32_t PHASE_STEP_DYNAMIC = 1; + + uint16_t const *waveform; // base of sine table + uint32_t phase_step; // phase step, or PHASE_STEP_DYNAMIC if PM is active + uint32_t total_level; // total level * 8 + KSL + uint32_t block_freq; // raw block frequency value (used to compute phase_step) + int32_t detune; // detuning value (used to compute phase_step) + uint32_t multiple; // multiple value (x.1, used to compute phase_step) + uint32_t eg_sustain; // sustain level, shifted up to envelope values + uint8_t eg_rate[EG_STATES]; // envelope rate, including KSR + uint8_t eg_shift = 0; // envelope shift amount +}; + + +// ======================> fm_registers_base + +// base class for family-specific register classes; this provides a few +// constants, common defaults, and helpers, but mostly each derived class is +// responsible for defining all commonly-called methods +class fm_registers_base +{ +public: + // this value is returned from the write() function for rhythm channels + static constexpr uint32_t RHYTHM_CHANNEL = 0xff; + + // this is the size of a full sin waveform + static constexpr uint32_t WAVEFORM_LENGTH = 0x400; + + // + // the following constants need to be defined per family: + // uint32_t OUTPUTS: The number of outputs exposed (1-4) + // uint32_t CHANNELS: The number of channels on the chip + // uint32_t ALL_CHANNELS: A bitmask of all channels + // uint32_t OPERATORS: The number of operators on the chip + // uint32_t WAVEFORMS: The number of waveforms offered + // uint32_t REGISTERS: The number of 8-bit registers allocated + // uint32_t DEFAULT_PRESCALE: The starting clock prescale + // uint32_t EG_CLOCK_DIVIDER: The clock divider of the envelope generator + // uint32_t CSM_TRIGGER_MASK: Mask of channels to trigger in CSM mode + // uint32_t REG_MODE: The address of the "mode" register controlling timers + // uint8_t STATUS_TIMERA: Status bit to set when timer A fires + // uint8_t STATUS_TIMERB: Status bit to set when tiemr B fires + // uint8_t STATUS_BUSY: Status bit to set when the chip is busy + // uint8_t STATUS_IRQ: Status bit to set when an IRQ is signalled + // + // the following constants are uncommon: + // bool DYNAMIC_OPS: True if ops/channel can be changed at runtime (OPL3+) + // bool EG_HAS_DEPRESS: True if the chip has a DP ("depress"?) envelope stage (OPLL) + // bool EG_HAS_REVERB: True if the chip has a faux reverb envelope stage (OPQ/OPZ) + // bool EG_HAS_SSG: True if the chip has SSG envelope support (OPN) + // bool MODULATOR_DELAY: True if the modulator is delayed by 1 sample (OPL pre-OPL3) + // + static constexpr bool DYNAMIC_OPS = false; + static constexpr bool EG_HAS_DEPRESS = false; + static constexpr bool EG_HAS_REVERB = false; + static constexpr bool EG_HAS_SSG = false; + static constexpr bool MODULATOR_DELAY = false; + + // system-wide register defaults + uint32_t status_mask() const { return 0; } // OPL only + uint32_t irq_reset() const { return 0; } // OPL only + uint32_t noise_enable() const { return 0; } // OPM only + uint32_t rhythm_enable() const { return 0; } // OPL only + + // per-operator register defaults + uint32_t op_ssg_eg_enable(uint32_t opoffs) const { return 0; } // OPN(A) only + uint32_t op_ssg_eg_mode(uint32_t opoffs) const { return 0; } // OPN(A) only + +protected: + // helper to encode four operator numbers into a 32-bit value in the + // operator maps for each register class + static constexpr uint32_t operator_list(uint8_t o1 = 0xff, uint8_t o2 = 0xff, uint8_t o3 = 0xff, uint8_t o4 = 0xff) + { + return o1 | (o2 << 8) | (o3 << 16) | (o4 << 24); + } + + // helper to apply KSR to the raw ADSR rate, ignoring ksr if the + // raw value is 0, and clamping to 63 + static constexpr uint32_t effective_rate(uint32_t rawrate, uint32_t ksr) + { + return (rawrate == 0) ? 0 : std::min(rawrate + ksr, 63); + } +}; + + + +//********************************************************* +// CORE ENGINE CLASSES +//********************************************************* + +// forward declarations +template class fm_engine_base; + +// ======================> fm_operator + +// fm_operator represents an FM operator (or "slot" in FM parlance), which +// produces an output sine wave modulated by an envelope +template +class fm_operator +{ + // "quiet" value, used to optimize when we can skip doing work + static constexpr uint32_t EG_QUIET = 0x380; + +public: + // constructor + fm_operator(fm_engine_base &owner, uint32_t opoffs); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // reset the operator state + void reset(); + + // return the operator/channel offset + uint32_t opoffs() const { return m_opoffs; } + uint32_t choffs() const { return m_choffs; } + + // set the current channel + void set_choffs(uint32_t choffs) { m_choffs = choffs; } + + // prepare prior to clocking + bool prepare(); + + // master clocking function + void clock(uint32_t env_counter, int32_t lfo_raw_pm); + + // return the current phase value + uint32_t phase() const { return m_phase >> 10; } + + // compute operator volume + int32_t compute_volume(uint32_t phase, uint32_t am_offset) const; + + // compute volume for the OPM noise channel + int32_t compute_noise_volume(uint32_t am_offset) const; + + // key state control + void keyonoff(uint32_t on, keyon_type type); + + // return a reference to our registers + RegisterType ®s() const { return m_regs; } + + // simple getters for debugging + envelope_state debug_eg_state() const { return m_env_state; } + uint16_t debug_eg_attenuation() const { return m_env_attenuation; } + uint8_t debug_ssg_inverted() const { return m_ssg_inverted; } + opdata_cache &debug_cache() { return m_cache; } + +private: + // start the attack phase + void start_attack(bool is_restart = false); + + // start the release phase + void start_release(); + + // clock phases + void clock_keystate(uint32_t keystate); + void clock_ssg_eg_state(); + void clock_envelope(uint32_t env_counter); + void clock_phase(int32_t lfo_raw_pm); + + // return effective attenuation of the envelope + uint32_t envelope_attenuation(uint32_t am_offset) const; + + // internal state + uint32_t m_choffs; // channel offset in registers + uint32_t m_opoffs; // operator offset in registers + uint32_t m_phase; // current phase value (10.10 format) + uint16_t m_env_attenuation; // computed envelope attenuation (4.6 format) + envelope_state m_env_state; // current envelope state + uint8_t m_ssg_inverted; // non-zero if the output should be inverted (bit 0) + uint8_t m_key_state; // current key state: on or off (bit 0) + uint8_t m_keyon_live; // live key on state (bit 0 = direct, bit 1 = rhythm, bit 2 = CSM) + opdata_cache m_cache; // cached values for performance + RegisterType &m_regs; // direct reference to registers + fm_engine_base &m_owner; // reference to the owning engine +}; + + +// ======================> fm_channel + +// fm_channel represents an FM channel which combines the output of 2 or 4 +// operators into a final result +template +class fm_channel +{ + using output_data = ymfm_output; + +public: + // constructor + fm_channel(fm_engine_base &owner, uint32_t choffs); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // reset the channel state + void reset(); + + // return the channel offset + uint32_t choffs() const { return m_choffs; } + + // assign operators + void assign(uint32_t index, fm_operator *op) + { + assert(index < array_size(m_op)); + m_op[index] = op; + if (op != nullptr) + op->set_choffs(m_choffs); + } + + // signal key on/off to our operators + void keyonoff(uint32_t states, keyon_type type, uint32_t chnum); + + // prepare prior to clocking + bool prepare(); + + // master clocking function + void clock(uint32_t env_counter, int32_t lfo_raw_pm); + + // specific 2-operator and 4-operator output handlers + void output_2op(output_data &output, uint32_t rshift, int32_t clipmax) const; + void output_4op(output_data &output, uint32_t rshift, int32_t clipmax) const; + + // compute the special OPL rhythm channel outputs + void output_rhythm_ch6(output_data &output, uint32_t rshift, int32_t clipmax) const; + void output_rhythm_ch7(uint32_t phase_select, output_data &output, uint32_t rshift, int32_t clipmax) const; + void output_rhythm_ch8(uint32_t phase_select, output_data &output, uint32_t rshift, int32_t clipmax) const; + + // are we a 4-operator channel or a 2-operator one? + bool is4op() const + { + if (RegisterType::DYNAMIC_OPS) + return (m_op[2] != nullptr); + return (RegisterType::OPERATORS / RegisterType::CHANNELS == 4); + } + + // return a reference to our registers + RegisterType ®s() const { return m_regs; } + + // simple getters for debugging + fm_operator *debug_operator(uint32_t index) const { return m_op[index]; } + +private: + // helper to add values to the outputs based on channel enables + void add_to_output(uint32_t choffs, output_data &output, int32_t value) const + { + // create these constants to appease overzealous compilers checking array + // bounds in unreachable code (looking at you, clang) + constexpr int out0_index = 0; + constexpr int out1_index = 1 % RegisterType::OUTPUTS; + constexpr int out2_index = 2 % RegisterType::OUTPUTS; + constexpr int out3_index = 3 % RegisterType::OUTPUTS; + + if (RegisterType::OUTPUTS == 1 || m_regs.ch_output_0(choffs)) + output.data[out0_index] += value; + if (RegisterType::OUTPUTS >= 2 && m_regs.ch_output_1(choffs)) + output.data[out1_index] += value; + if (RegisterType::OUTPUTS >= 3 && m_regs.ch_output_2(choffs)) + output.data[out2_index] += value; + if (RegisterType::OUTPUTS >= 4 && m_regs.ch_output_3(choffs)) + output.data[out3_index] += value; + } + + // internal state + uint32_t m_choffs; // channel offset in registers + int16_t m_feedback[2]; // feedback memory for operator 1 + mutable int16_t m_feedback_in; // next input value for op 1 feedback (set in output) + fm_operator *m_op[4]; // up to 4 operators + RegisterType &m_regs; // direct reference to registers + fm_engine_base &m_owner; // reference to the owning engine +}; + + +// ======================> fm_engine_base + +// fm_engine_base represents a set of operators and channels which together +// form a Yamaha FM core; chips that implement other engines (ADPCM, wavetable, +// etc) take this output and combine it with the others externally +template +class fm_engine_base : public ymfm_engine_callbacks +{ +public: + // expose some constants from the registers + static constexpr uint32_t OUTPUTS = RegisterType::OUTPUTS; + static constexpr uint32_t CHANNELS = RegisterType::CHANNELS; + static constexpr uint32_t ALL_CHANNELS = RegisterType::ALL_CHANNELS; + static constexpr uint32_t OPERATORS = RegisterType::OPERATORS; + + // also expose status flags for consumers that inject additional bits + static constexpr uint8_t STATUS_TIMERA = RegisterType::STATUS_TIMERA; + static constexpr uint8_t STATUS_TIMERB = RegisterType::STATUS_TIMERB; + static constexpr uint8_t STATUS_BUSY = RegisterType::STATUS_BUSY; + static constexpr uint8_t STATUS_IRQ = RegisterType::STATUS_IRQ; + + // expose the correct output class + using output_data = ymfm_output; + + // constructor + fm_engine_base(ymfm_interface &intf); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // reset the overall state + void reset(); + + // master clocking function + uint32_t clock(uint32_t chanmask); + + // compute sum of channel outputs + void output(output_data &output, uint32_t rshift, int32_t clipmax, uint32_t chanmask) const; + + // write to the OPN registers + void write(uint16_t regnum, uint8_t data); + + // return the current status + uint8_t status() const; + + // set/reset bits in the status register, updating the IRQ status + uint8_t set_reset_status(uint8_t set, uint8_t reset) + { + m_status = (m_status | set) & ~(reset | STATUS_BUSY); + m_intf.ymfm_sync_check_interrupts(); + return m_status & ~m_regs.status_mask(); + } + + // set the IRQ mask + void set_irq_mask(uint8_t mask) { m_irq_mask = mask; m_intf.ymfm_sync_check_interrupts(); } + + // return the current clock prescale + uint32_t clock_prescale() const { return m_clock_prescale; } + + // set prescale factor (2/3/6) + void set_clock_prescale(uint32_t prescale) { m_clock_prescale = prescale; } + + // compute sample rate + uint32_t sample_rate(uint32_t baseclock) const + { +#if (DEBUG_LOG_WAVFILES) + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + m_wavfile[chnum].set_samplerate(baseclock / (m_clock_prescale * OPERATORS)); +#endif + return baseclock / (m_clock_prescale * OPERATORS); + } + + // return the owning device + ymfm_interface &intf() const { return m_intf; } + + // return a reference to our registers + RegisterType ®s() { return m_regs; } + + // invalidate any caches + void invalidate_caches() { m_modified_channels = RegisterType::ALL_CHANNELS; } + + // simple getters for debugging + fm_channel *debug_channel(uint32_t index) const { return m_channel[index].get(); } + fm_operator *debug_operator(uint32_t index) const { return m_operator[index].get(); } + +public: + // timer callback; called by the interface when a timer fires + virtual void engine_timer_expired(uint32_t tnum) override; + + // check interrupts; called by the interface after synchronization + virtual void engine_check_interrupts() override; + + // mode register write; called by the interface after synchronization + virtual void engine_mode_write(uint8_t data) override; + +protected: + // assign the current set of operators to channels + void assign_operators(); + + // update the state of the given timer + void update_timer(uint32_t which, uint32_t enable, int32_t delta_clocks); + + // internal state + ymfm_interface &m_intf; // reference to the system interface + uint32_t m_env_counter; // envelope counter; low 2 bits are sub-counter + uint8_t m_status; // current status register + uint8_t m_clock_prescale; // prescale factor (2/3/6) + uint8_t m_irq_mask; // mask of which bits signal IRQs + uint8_t m_irq_state; // current IRQ state + uint8_t m_timer_running[2]; // current timer running state + uint8_t m_total_clocks; // low 8 bits of the total number of clocks processed + uint32_t m_active_channels; // mask of active channels (computed by prepare) + uint32_t m_modified_channels; // mask of channels that have been modified + uint32_t m_prepare_count; // counter to do periodic prepare sweeps + RegisterType m_regs; // register accessor + std::unique_ptr> m_channel[CHANNELS]; // channel pointers + std::unique_ptr> m_operator[OPERATORS]; // operator pointers +#if (DEBUG_LOG_WAVFILES) + mutable ymfm_wavfile<1> m_wavfile[CHANNELS]; // for debugging +#endif +}; + +} + +#endif // YMFM_FM_H diff --git a/src/sound/ymfm/ymfm_fm.ipp b/src/sound/ymfm/ymfm_fm.ipp new file mode 100644 index 000000000..7e5109d59 --- /dev/null +++ b/src/sound/ymfm/ymfm_fm.ipp @@ -0,0 +1,1595 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +namespace ymfm +{ + +//********************************************************* +// GLOBAL TABLE LOOKUPS +//********************************************************* + +//------------------------------------------------- +// abs_sin_attenuation - given a sin (phase) input +// where the range 0-2*PI is mapped onto 10 bits, +// return the absolute value of sin(input), +// logarithmically-adjusted and treated as an +// attenuation value, in 4.8 fixed point format +//------------------------------------------------- + +inline uint32_t abs_sin_attenuation(uint32_t input) +{ + // the values here are stored as 4.8 logarithmic values for 1/4 phase + // this matches the internal format of the OPN chip, extracted from the die + static uint16_t const s_sin_table[256] = + { + 0x859,0x6c3,0x607,0x58b,0x52e,0x4e4,0x4a6,0x471,0x443,0x41a,0x3f5,0x3d3,0x3b5,0x398,0x37e,0x365, + 0x34e,0x339,0x324,0x311,0x2ff,0x2ed,0x2dc,0x2cd,0x2bd,0x2af,0x2a0,0x293,0x286,0x279,0x26d,0x261, + 0x256,0x24b,0x240,0x236,0x22c,0x222,0x218,0x20f,0x206,0x1fd,0x1f5,0x1ec,0x1e4,0x1dc,0x1d4,0x1cd, + 0x1c5,0x1be,0x1b7,0x1b0,0x1a9,0x1a2,0x19b,0x195,0x18f,0x188,0x182,0x17c,0x177,0x171,0x16b,0x166, + 0x160,0x15b,0x155,0x150,0x14b,0x146,0x141,0x13c,0x137,0x133,0x12e,0x129,0x125,0x121,0x11c,0x118, + 0x114,0x10f,0x10b,0x107,0x103,0x0ff,0x0fb,0x0f8,0x0f4,0x0f0,0x0ec,0x0e9,0x0e5,0x0e2,0x0de,0x0db, + 0x0d7,0x0d4,0x0d1,0x0cd,0x0ca,0x0c7,0x0c4,0x0c1,0x0be,0x0bb,0x0b8,0x0b5,0x0b2,0x0af,0x0ac,0x0a9, + 0x0a7,0x0a4,0x0a1,0x09f,0x09c,0x099,0x097,0x094,0x092,0x08f,0x08d,0x08a,0x088,0x086,0x083,0x081, + 0x07f,0x07d,0x07a,0x078,0x076,0x074,0x072,0x070,0x06e,0x06c,0x06a,0x068,0x066,0x064,0x062,0x060, + 0x05e,0x05c,0x05b,0x059,0x057,0x055,0x053,0x052,0x050,0x04e,0x04d,0x04b,0x04a,0x048,0x046,0x045, + 0x043,0x042,0x040,0x03f,0x03e,0x03c,0x03b,0x039,0x038,0x037,0x035,0x034,0x033,0x031,0x030,0x02f, + 0x02e,0x02d,0x02b,0x02a,0x029,0x028,0x027,0x026,0x025,0x024,0x023,0x022,0x021,0x020,0x01f,0x01e, + 0x01d,0x01c,0x01b,0x01a,0x019,0x018,0x017,0x017,0x016,0x015,0x014,0x014,0x013,0x012,0x011,0x011, + 0x010,0x00f,0x00f,0x00e,0x00d,0x00d,0x00c,0x00c,0x00b,0x00a,0x00a,0x009,0x009,0x008,0x008,0x007, + 0x007,0x007,0x006,0x006,0x005,0x005,0x005,0x004,0x004,0x004,0x003,0x003,0x003,0x002,0x002,0x002, + 0x002,0x001,0x001,0x001,0x001,0x001,0x001,0x001,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000 + }; + + // if the top bit is set, we're in the second half of the curve + // which is a mirror image, so invert the index + if (bitfield(input, 8)) + input = ~input; + + // return the value from the table + return s_sin_table[input & 0xff]; +} + + +//------------------------------------------------- +// attenuation_to_volume - given a 5.8 fixed point +// logarithmic attenuation value, return a 13-bit +// linear volume +//------------------------------------------------- + +inline uint32_t attenuation_to_volume(uint32_t input) +{ + // the values here are 10-bit mantissas with an implied leading bit + // this matches the internal format of the OPN chip, extracted from the die + + // as a nod to performance, the implicit 0x400 bit is pre-incorporated, and + // the values are left-shifted by 2 so that a simple right shift is all that + // is needed; also the order is reversed to save a NOT on the input +#define X(a) (((a) | 0x400) << 2) + static uint16_t const s_power_table[256] = + { + X(0x3fa),X(0x3f5),X(0x3ef),X(0x3ea),X(0x3e4),X(0x3df),X(0x3da),X(0x3d4), + X(0x3cf),X(0x3c9),X(0x3c4),X(0x3bf),X(0x3b9),X(0x3b4),X(0x3ae),X(0x3a9), + X(0x3a4),X(0x39f),X(0x399),X(0x394),X(0x38f),X(0x38a),X(0x384),X(0x37f), + X(0x37a),X(0x375),X(0x370),X(0x36a),X(0x365),X(0x360),X(0x35b),X(0x356), + X(0x351),X(0x34c),X(0x347),X(0x342),X(0x33d),X(0x338),X(0x333),X(0x32e), + X(0x329),X(0x324),X(0x31f),X(0x31a),X(0x315),X(0x310),X(0x30b),X(0x306), + X(0x302),X(0x2fd),X(0x2f8),X(0x2f3),X(0x2ee),X(0x2e9),X(0x2e5),X(0x2e0), + X(0x2db),X(0x2d6),X(0x2d2),X(0x2cd),X(0x2c8),X(0x2c4),X(0x2bf),X(0x2ba), + X(0x2b5),X(0x2b1),X(0x2ac),X(0x2a8),X(0x2a3),X(0x29e),X(0x29a),X(0x295), + X(0x291),X(0x28c),X(0x288),X(0x283),X(0x27f),X(0x27a),X(0x276),X(0x271), + X(0x26d),X(0x268),X(0x264),X(0x25f),X(0x25b),X(0x257),X(0x252),X(0x24e), + X(0x249),X(0x245),X(0x241),X(0x23c),X(0x238),X(0x234),X(0x230),X(0x22b), + X(0x227),X(0x223),X(0x21e),X(0x21a),X(0x216),X(0x212),X(0x20e),X(0x209), + X(0x205),X(0x201),X(0x1fd),X(0x1f9),X(0x1f5),X(0x1f0),X(0x1ec),X(0x1e8), + X(0x1e4),X(0x1e0),X(0x1dc),X(0x1d8),X(0x1d4),X(0x1d0),X(0x1cc),X(0x1c8), + X(0x1c4),X(0x1c0),X(0x1bc),X(0x1b8),X(0x1b4),X(0x1b0),X(0x1ac),X(0x1a8), + X(0x1a4),X(0x1a0),X(0x19c),X(0x199),X(0x195),X(0x191),X(0x18d),X(0x189), + X(0x185),X(0x181),X(0x17e),X(0x17a),X(0x176),X(0x172),X(0x16f),X(0x16b), + X(0x167),X(0x163),X(0x160),X(0x15c),X(0x158),X(0x154),X(0x151),X(0x14d), + X(0x149),X(0x146),X(0x142),X(0x13e),X(0x13b),X(0x137),X(0x134),X(0x130), + X(0x12c),X(0x129),X(0x125),X(0x122),X(0x11e),X(0x11b),X(0x117),X(0x114), + X(0x110),X(0x10c),X(0x109),X(0x106),X(0x102),X(0x0ff),X(0x0fb),X(0x0f8), + X(0x0f4),X(0x0f1),X(0x0ed),X(0x0ea),X(0x0e7),X(0x0e3),X(0x0e0),X(0x0dc), + X(0x0d9),X(0x0d6),X(0x0d2),X(0x0cf),X(0x0cc),X(0x0c8),X(0x0c5),X(0x0c2), + X(0x0be),X(0x0bb),X(0x0b8),X(0x0b5),X(0x0b1),X(0x0ae),X(0x0ab),X(0x0a8), + X(0x0a4),X(0x0a1),X(0x09e),X(0x09b),X(0x098),X(0x094),X(0x091),X(0x08e), + X(0x08b),X(0x088),X(0x085),X(0x082),X(0x07e),X(0x07b),X(0x078),X(0x075), + X(0x072),X(0x06f),X(0x06c),X(0x069),X(0x066),X(0x063),X(0x060),X(0x05d), + X(0x05a),X(0x057),X(0x054),X(0x051),X(0x04e),X(0x04b),X(0x048),X(0x045), + X(0x042),X(0x03f),X(0x03c),X(0x039),X(0x036),X(0x033),X(0x030),X(0x02d), + X(0x02a),X(0x028),X(0x025),X(0x022),X(0x01f),X(0x01c),X(0x019),X(0x016), + X(0x014),X(0x011),X(0x00e),X(0x00b),X(0x008),X(0x006),X(0x003),X(0x000) + }; +#undef X + + // look up the fractional part, then shift by the whole + return s_power_table[input & 0xff] >> (input >> 8); +} + + +//------------------------------------------------- +// attenuation_increment - given a 6-bit ADSR +// rate value and a 3-bit stepping index, +// return a 4-bit increment to the attenutaion +// for this step (or for the attack case, the +// fractional scale factor to decrease by) +//------------------------------------------------- + +inline uint32_t attenuation_increment(uint32_t rate, uint32_t index) +{ + static uint32_t const s_increment_table[64] = + { + 0x00000000, 0x00000000, 0x10101010, 0x10101010, // 0-3 (0x00-0x03) + 0x10101010, 0x10101010, 0x11101110, 0x11101110, // 4-7 (0x04-0x07) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 8-11 (0x08-0x0B) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 12-15 (0x0C-0x0F) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 16-19 (0x10-0x13) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 20-23 (0x14-0x17) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 24-27 (0x18-0x1B) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 28-31 (0x1C-0x1F) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 32-35 (0x20-0x23) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 36-39 (0x24-0x27) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 40-43 (0x28-0x2B) + 0x10101010, 0x10111010, 0x11101110, 0x11111110, // 44-47 (0x2C-0x2F) + 0x11111111, 0x21112111, 0x21212121, 0x22212221, // 48-51 (0x30-0x33) + 0x22222222, 0x42224222, 0x42424242, 0x44424442, // 52-55 (0x34-0x37) + 0x44444444, 0x84448444, 0x84848484, 0x88848884, // 56-59 (0x38-0x3B) + 0x88888888, 0x88888888, 0x88888888, 0x88888888 // 60-63 (0x3C-0x3F) + }; + return bitfield(s_increment_table[rate], 4*index, 4); +} + + +//------------------------------------------------- +// detune_adjustment - given a 5-bit key code +// value and a 3-bit detune parameter, return a +// 6-bit signed phase displacement; this table +// has been verified against Nuked's equations, +// but the equations are rather complicated, so +// we'll keep the simplicity of the table +//------------------------------------------------- + +inline int32_t detune_adjustment(uint32_t detune, uint32_t keycode) +{ + static uint8_t const s_detune_adjustment[32][4] = + { + { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, { 0, 0, 1, 2 }, + { 0, 1, 2, 2 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 2, 3 }, + { 0, 1, 2, 4 }, { 0, 1, 3, 4 }, { 0, 1, 3, 4 }, { 0, 1, 3, 5 }, + { 0, 2, 4, 5 }, { 0, 2, 4, 6 }, { 0, 2, 4, 6 }, { 0, 2, 5, 7 }, + { 0, 2, 5, 8 }, { 0, 3, 6, 8 }, { 0, 3, 6, 9 }, { 0, 3, 7, 10 }, + { 0, 4, 8, 11 }, { 0, 4, 8, 12 }, { 0, 4, 9, 13 }, { 0, 5, 10, 14 }, + { 0, 5, 11, 16 }, { 0, 6, 12, 17 }, { 0, 6, 13, 19 }, { 0, 7, 14, 20 }, + { 0, 8, 16, 22 }, { 0, 8, 16, 22 }, { 0, 8, 16, 22 }, { 0, 8, 16, 22 } + }; + int32_t result = s_detune_adjustment[keycode][detune & 3]; + return bitfield(detune, 2) ? -result : result; +} + + +//------------------------------------------------- +// opm_key_code_to_phase_step - converts an +// OPM concatenated block (3 bits), keycode +// (4 bits) and key fraction (6 bits) to a 0.10 +// phase step, after applying the given delta; +// this applies to OPM and OPZ, so it lives here +// in a central location +//------------------------------------------------- + +inline uint32_t opm_key_code_to_phase_step(uint32_t block_freq, int32_t delta) +{ + // The phase step is essentially the fnum in OPN-speak. To compute this table, + // we used the standard formula for computing the frequency of a note, and + // then converted that frequency to fnum using the formula documented in the + // YM2608 manual. + // + // However, the YM2608 manual describes everything in terms of a nominal 8MHz + // clock, which produces an FM clock of: + // + // 8000000 / 24(operators) / 6(prescale) = 55555Hz FM clock + // + // Whereas the descriptions for the YM2151 use a nominal 3.579545MHz clock: + // + // 3579545 / 32(operators) / 2(prescale) = 55930Hz FM clock + // + // To correct for this, the YM2608 formula was adjusted to use a clock of + // 8053920Hz, giving this equation for the fnum: + // + // fnum = (double(144) * freq * (1 << 20)) / double(8053920) / 4; + // + // Unfortunately, the computed table differs in a few spots from the data + // verified from an actual chip. The table below comes from David Viens' + // analysis, used with his permission. + static const uint32_t s_phase_step[12*64] = + { + 41568,41600,41632,41664,41696,41728,41760,41792,41856,41888,41920,41952,42016,42048,42080,42112, + 42176,42208,42240,42272,42304,42336,42368,42400,42464,42496,42528,42560,42624,42656,42688,42720, + 42784,42816,42848,42880,42912,42944,42976,43008,43072,43104,43136,43168,43232,43264,43296,43328, + 43392,43424,43456,43488,43552,43584,43616,43648,43712,43744,43776,43808,43872,43904,43936,43968, + 44032,44064,44096,44128,44192,44224,44256,44288,44352,44384,44416,44448,44512,44544,44576,44608, + 44672,44704,44736,44768,44832,44864,44896,44928,44992,45024,45056,45088,45152,45184,45216,45248, + 45312,45344,45376,45408,45472,45504,45536,45568,45632,45664,45728,45760,45792,45824,45888,45920, + 45984,46016,46048,46080,46144,46176,46208,46240,46304,46336,46368,46400,46464,46496,46528,46560, + 46656,46688,46720,46752,46816,46848,46880,46912,46976,47008,47072,47104,47136,47168,47232,47264, + 47328,47360,47392,47424,47488,47520,47552,47584,47648,47680,47744,47776,47808,47840,47904,47936, + 48032,48064,48096,48128,48192,48224,48288,48320,48384,48416,48448,48480,48544,48576,48640,48672, + 48736,48768,48800,48832,48896,48928,48992,49024,49088,49120,49152,49184,49248,49280,49344,49376, + 49440,49472,49504,49536,49600,49632,49696,49728,49792,49824,49856,49888,49952,49984,50048,50080, + 50144,50176,50208,50240,50304,50336,50400,50432,50496,50528,50560,50592,50656,50688,50752,50784, + 50880,50912,50944,50976,51040,51072,51136,51168,51232,51264,51328,51360,51424,51456,51488,51520, + 51616,51648,51680,51712,51776,51808,51872,51904,51968,52000,52064,52096,52160,52192,52224,52256, + 52384,52416,52448,52480,52544,52576,52640,52672,52736,52768,52832,52864,52928,52960,52992,53024, + 53120,53152,53216,53248,53312,53344,53408,53440,53504,53536,53600,53632,53696,53728,53792,53824, + 53920,53952,54016,54048,54112,54144,54208,54240,54304,54336,54400,54432,54496,54528,54592,54624, + 54688,54720,54784,54816,54880,54912,54976,55008,55072,55104,55168,55200,55264,55296,55360,55392, + 55488,55520,55584,55616,55680,55712,55776,55808,55872,55936,55968,56032,56064,56128,56160,56224, + 56288,56320,56384,56416,56480,56512,56576,56608,56672,56736,56768,56832,56864,56928,56960,57024, + 57120,57152,57216,57248,57312,57376,57408,57472,57536,57568,57632,57664,57728,57792,57824,57888, + 57952,57984,58048,58080,58144,58208,58240,58304,58368,58400,58464,58496,58560,58624,58656,58720, + 58784,58816,58880,58912,58976,59040,59072,59136,59200,59232,59296,59328,59392,59456,59488,59552, + 59648,59680,59744,59776,59840,59904,59936,60000,60064,60128,60160,60224,60288,60320,60384,60416, + 60512,60544,60608,60640,60704,60768,60800,60864,60928,60992,61024,61088,61152,61184,61248,61280, + 61376,61408,61472,61536,61600,61632,61696,61760,61824,61856,61920,61984,62048,62080,62144,62208, + 62272,62304,62368,62432,62496,62528,62592,62656,62720,62752,62816,62880,62944,62976,63040,63104, + 63200,63232,63296,63360,63424,63456,63520,63584,63648,63680,63744,63808,63872,63904,63968,64032, + 64096,64128,64192,64256,64320,64352,64416,64480,64544,64608,64672,64704,64768,64832,64896,64928, + 65024,65056,65120,65184,65248,65312,65376,65408,65504,65536,65600,65664,65728,65792,65856,65888, + 65984,66016,66080,66144,66208,66272,66336,66368,66464,66496,66560,66624,66688,66752,66816,66848, + 66944,66976,67040,67104,67168,67232,67296,67328,67424,67456,67520,67584,67648,67712,67776,67808, + 67904,67936,68000,68064,68128,68192,68256,68288,68384,68448,68512,68544,68640,68672,68736,68800, + 68896,68928,68992,69056,69120,69184,69248,69280,69376,69440,69504,69536,69632,69664,69728,69792, + 69920,69952,70016,70080,70144,70208,70272,70304,70400,70464,70528,70560,70656,70688,70752,70816, + 70912,70976,71040,71104,71136,71232,71264,71360,71424,71488,71552,71616,71648,71744,71776,71872, + 71968,72032,72096,72160,72192,72288,72320,72416,72480,72544,72608,72672,72704,72800,72832,72928, + 72992,73056,73120,73184,73216,73312,73344,73440,73504,73568,73632,73696,73728,73824,73856,73952, + 74080,74144,74208,74272,74304,74400,74432,74528,74592,74656,74720,74784,74816,74912,74944,75040, + 75136,75200,75264,75328,75360,75456,75488,75584,75648,75712,75776,75840,75872,75968,76000,76096, + 76224,76288,76352,76416,76448,76544,76576,76672,76736,76800,76864,76928,77024,77120,77152,77248, + 77344,77408,77472,77536,77568,77664,77696,77792,77856,77920,77984,78048,78144,78240,78272,78368, + 78464,78528,78592,78656,78688,78784,78816,78912,78976,79040,79104,79168,79264,79360,79392,79488, + 79616,79680,79744,79808,79840,79936,79968,80064,80128,80192,80256,80320,80416,80512,80544,80640, + 80768,80832,80896,80960,80992,81088,81120,81216,81280,81344,81408,81472,81568,81664,81696,81792, + 81952,82016,82080,82144,82176,82272,82304,82400,82464,82528,82592,82656,82752,82848,82880,82976 + }; + + // extract the block (octave) first + uint32_t block = bitfield(block_freq, 10, 3); + + // the keycode (bits 6-9) is "gappy", mapping 12 values over 16 in each + // octave; to correct for this, we multiply the 4-bit value by 3/4 (or + // rather subtract 1/4); note that a (invalid) value of 15 will bleed into + // the next octave -- this is confirmed + uint32_t adjusted_code = bitfield(block_freq, 6, 4) - bitfield(block_freq, 8, 2); + + // now re-insert the 6-bit fraction + int32_t eff_freq = (adjusted_code << 6) | bitfield(block_freq, 0, 6); + + // now that the gaps are removed, add the delta + eff_freq += delta; + + // handle over/underflow by adjusting the block: + if (uint32_t(eff_freq) >= 768) + { + // minimum delta is -512 (PM), so we can only underflow by 1 octave + if (eff_freq < 0) + { + eff_freq += 768; + if (block-- == 0) + return s_phase_step[0] >> 7; + } + + // maximum delta is +512+608 (PM+detune), so we can overflow by up to 2 octaves + else + { + eff_freq -= 768; + if (eff_freq >= 768) + block++, eff_freq -= 768; + if (block++ >= 7) + return s_phase_step[767]; + } + } + + // look up the phase shift for the key code, then shift by octave + return s_phase_step[eff_freq] >> (block ^ 7); +} + + +//------------------------------------------------- +// opn_lfo_pm_phase_adjustment - given the 7 most +// significant frequency number bits, plus a 3-bit +// PM depth value and a signed 5-bit raw PM value, +// return a signed PM adjustment to the frequency; +// algorithm written to match Nuked behavior +//------------------------------------------------- + +inline int32_t opn_lfo_pm_phase_adjustment(uint32_t fnum_bits, uint32_t pm_sensitivity, int32_t lfo_raw_pm) +{ + // this table encodes 2 shift values to apply to the top 7 bits + // of fnum; it is effectively a cheap multiply by a constant + // value containing 0-2 bits + static uint8_t const s_lfo_pm_shifts[8][8] = + { + { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77 }, + { 0x77, 0x77, 0x77, 0x77, 0x72, 0x72, 0x72, 0x72 }, + { 0x77, 0x77, 0x77, 0x72, 0x72, 0x72, 0x17, 0x17 }, + { 0x77, 0x77, 0x72, 0x72, 0x17, 0x17, 0x12, 0x12 }, + { 0x77, 0x77, 0x72, 0x17, 0x17, 0x17, 0x12, 0x07 }, + { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 }, + { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 }, + { 0x77, 0x77, 0x17, 0x12, 0x07, 0x07, 0x02, 0x01 } + }; + + // look up the relevant shifts + int32_t abs_pm = (lfo_raw_pm < 0) ? -lfo_raw_pm : lfo_raw_pm; + uint32_t const shifts = s_lfo_pm_shifts[pm_sensitivity][bitfield(abs_pm, 0, 3)]; + + // compute the adjustment + int32_t adjust = (fnum_bits >> bitfield(shifts, 0, 4)) + (fnum_bits >> bitfield(shifts, 4, 4)); + if (pm_sensitivity > 5) + adjust <<= pm_sensitivity - 5; + adjust >>= 2; + + // every 16 cycles it inverts sign + return (lfo_raw_pm < 0) ? -adjust : adjust; +} + + + +//********************************************************* +// FM OPERATOR +//********************************************************* + +//------------------------------------------------- +// fm_operator - constructor +//------------------------------------------------- + +template +fm_operator::fm_operator(fm_engine_base &owner, uint32_t opoffs) : + m_choffs(0), + m_opoffs(opoffs), + m_phase(0), + m_env_attenuation(0x3ff), + m_env_state(EG_RELEASE), + m_ssg_inverted(false), + m_key_state(0), + m_keyon_live(0), + m_regs(owner.regs()), + m_owner(owner) +{ +} + + +//------------------------------------------------- +// reset - reset the channel state +//------------------------------------------------- + +template +void fm_operator::reset() +{ + // reset our data + m_phase = 0; + m_env_attenuation = 0x3ff; + m_env_state = EG_RELEASE; + m_ssg_inverted = 0; + m_key_state = 0; + m_keyon_live = 0; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +template +void fm_operator::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_phase); + state.save_restore(m_env_attenuation); + state.save_restore(m_env_state); + state.save_restore(m_ssg_inverted); + state.save_restore(m_key_state); + state.save_restore(m_keyon_live); +} + + +//------------------------------------------------- +// prepare - prepare for clocking +//------------------------------------------------- + +template +bool fm_operator::prepare() +{ + // cache the data + m_regs.cache_operator_data(m_choffs, m_opoffs, m_cache); + + // clock the key state + clock_keystate(uint32_t(m_keyon_live != 0)); + m_keyon_live &= ~(1 << KEYON_CSM); + + // we're active until we're quiet after the release + return (m_env_state != (RegisterType::EG_HAS_REVERB ? EG_REVERB : EG_RELEASE) || m_env_attenuation < EG_QUIET); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +template +void fm_operator::clock(uint32_t env_counter, int32_t lfo_raw_pm) +{ + // clock the SSG-EG state (OPN/OPNA) + if (m_regs.op_ssg_eg_enable(m_opoffs)) + clock_ssg_eg_state(); + else + m_ssg_inverted = false; + + // clock the envelope if on an envelope cycle; env_counter is a x.2 value + if (bitfield(env_counter, 0, 2) == 0) + clock_envelope(env_counter >> 2); + + // clock the phase + clock_phase(lfo_raw_pm); +} + + +//------------------------------------------------- +// compute_volume - compute the 14-bit signed +// volume of this operator, given a phase +// modulation and an AM LFO offset +//------------------------------------------------- + +template +int32_t fm_operator::compute_volume(uint32_t phase, uint32_t am_offset) const +{ + // the low 10 bits of phase represents a full 2*PI period over + // the full sin wave + + // early out if the envelope is effectively off + if (m_env_attenuation > EG_QUIET) + return 0; + + // get the absolute value of the sin, as attenuation, as a 4.8 fixed point value + uint32_t sin_attenuation = m_cache.waveform[phase & (RegisterType::WAVEFORM_LENGTH - 1)]; + + // get the attenuation from the evelope generator as a 4.6 value, shifted up to 4.8 + uint32_t env_attenuation = envelope_attenuation(am_offset) << 2; + + // combine into a 5.8 value, then convert from attenuation to 13-bit linear volume + int32_t result = attenuation_to_volume((sin_attenuation & 0x7fff) + env_attenuation); + + // negate if in the negative part of the sin wave (sign bit gives 14 bits) + return bitfield(sin_attenuation, 15) ? -result : result; +} + + +//------------------------------------------------- +// compute_noise_volume - compute the 14-bit +// signed noise volume of this operator, given a +// noise input value and an AM offset +//------------------------------------------------- + +template +int32_t fm_operator::compute_noise_volume(uint32_t am_offset) const +{ + // application manual says the logarithmic transform is not applied here, so we + // just use the raw envelope attenuation, inverted (since 0 attenuation should be + // maximum), and shift it up from a 10-bit value to an 11-bit value + int32_t result = (envelope_attenuation(am_offset) ^ 0x3ff) << 1; + + // QUESTION: is AM applied still? + + // negate based on the noise state + return bitfield(m_regs.noise_state(), 0) ? -result : result; +} + + +//------------------------------------------------- +// keyonoff - signal a key on/off event +//------------------------------------------------- + +template +void fm_operator::keyonoff(uint32_t on, keyon_type type) +{ + m_keyon_live = (m_keyon_live & ~(1 << int(type))) | (bitfield(on, 0) << int(type)); +} + + +//------------------------------------------------- +// start_attack - start the attack phase; called +// when a keyon happens or when an SSG-EG cycle +// is complete and restarts +//------------------------------------------------- + +template +void fm_operator::start_attack(bool is_restart) +{ + // don't change anything if already in attack state + if (m_env_state == EG_ATTACK) + return; + m_env_state = EG_ATTACK; + + // generally not inverted at start, except if SSG-EG is enabled and + // one of the inverted modes is specified; leave this alone on a + // restart, as it is managed by the clock_ssg_eg_state() code + if (RegisterType::EG_HAS_SSG && !is_restart) + m_ssg_inverted = m_regs.op_ssg_eg_enable(m_opoffs) & bitfield(m_regs.op_ssg_eg_mode(m_opoffs), 2); + + // reset the phase when we start an attack due to a key on + // (but not when due to an SSG-EG restart except in certain cases + // managed directly by the SSG-EG code) + if (!is_restart) + m_phase = 0; + + // if the attack rate >= 62 then immediately go to max attenuation + if (m_cache.eg_rate[EG_ATTACK] >= 62) + m_env_attenuation = 0; +} + + +//------------------------------------------------- +// start_release - start the release phase; +// called when a keyoff happens +//------------------------------------------------- + +template +void fm_operator::start_release() +{ + // don't change anything if already in release state + if (m_env_state >= EG_RELEASE) + return; + m_env_state = EG_RELEASE; + + // if attenuation if inverted due to SSG-EG, snap the inverted attenuation + // as the starting point + if (RegisterType::EG_HAS_SSG && m_ssg_inverted) + { + m_env_attenuation = (0x200 - m_env_attenuation) & 0x3ff; + m_ssg_inverted = false; + } +} + + +//------------------------------------------------- +// clock_keystate - clock the keystate to match +// the incoming keystate +//------------------------------------------------- + +template +void fm_operator::clock_keystate(uint32_t keystate) +{ + assert(keystate == 0 || keystate == 1); + + // has the key changed? + if ((keystate ^ m_key_state) != 0) + { + m_key_state = keystate; + + // if the key has turned on, start the attack + if (keystate != 0) + { + // OPLL has a DP ("depress"?) state to bring the volume + // down before starting the attack + if (RegisterType::EG_HAS_DEPRESS && m_env_attenuation < 0x200) + m_env_state = EG_DEPRESS; + else + start_attack(); + } + + // otherwise, start the release + else + start_release(); + } +} + + +//------------------------------------------------- +// clock_ssg_eg_state - clock the SSG-EG state; +// should only be called if SSG-EG is enabled +//------------------------------------------------- + +template +void fm_operator::clock_ssg_eg_state() +{ + // work only happens once the attenuation crosses above 0x200 + if (!bitfield(m_env_attenuation, 9)) + return; + + // 8 SSG-EG modes: + // 000: repeat normally + // 001: run once, hold low + // 010: repeat, alternating between inverted/non-inverted + // 011: run once, hold high + // 100: inverted repeat normally + // 101: inverted run once, hold low + // 110: inverted repeat, alternating between inverted/non-inverted + // 111: inverted run once, hold high + uint32_t mode = m_regs.op_ssg_eg_mode(m_opoffs); + + // hold modes (1/3/5/7) + if (bitfield(mode, 0)) + { + // set the inverted flag to the end state (0 for modes 1/7, 1 for modes 3/5) + m_ssg_inverted = bitfield(mode, 2) ^ bitfield(mode, 1); + + // if holding, force the attenuation to the expected value once we're + // past the attack phase + if (m_env_state != EG_ATTACK) + m_env_attenuation = m_ssg_inverted ? 0x200 : 0x3ff; + } + + // continuous modes (0/2/4/6) + else + { + // toggle invert in alternating mode (even in attack state) + m_ssg_inverted ^= bitfield(mode, 1); + + // restart attack if in decay/sustain states + if (m_env_state == EG_DECAY || m_env_state == EG_SUSTAIN) + start_attack(true); + + // phase is reset to 0 in modes 0/4 + if (bitfield(mode, 1) == 0) + m_phase = 0; + } + + // in all modes, once we hit release state, attenuation is forced to maximum + if (m_env_state == EG_RELEASE) + m_env_attenuation = 0x3ff; +} + + +//------------------------------------------------- +// clock_envelope - clock the envelope state +// according to the given count +//------------------------------------------------- + +template +void fm_operator::clock_envelope(uint32_t env_counter) +{ + // handle attack->decay transitions + if (m_env_state == EG_ATTACK && m_env_attenuation == 0) + m_env_state = EG_DECAY; + + // handle decay->sustain transitions; it is important to do this immediately + // after the attack->decay transition above in the event that the sustain level + // is set to 0 (in which case we will skip right to sustain without doing any + // decay); as an example where this can be heard, check the cymbals sound + // in channel 0 of shinobi's test mode sound #5 + if (m_env_state == EG_DECAY && m_env_attenuation >= m_cache.eg_sustain) + m_env_state = EG_SUSTAIN; + + // fetch the appropriate 6-bit rate value from the cache + uint32_t rate = m_cache.eg_rate[m_env_state]; + + // compute the rate shift value; this is the shift needed to + // apply to the env_counter such that it becomes a 5.11 fixed + // point number + uint32_t rate_shift = rate >> 2; + env_counter <<= rate_shift; + + // see if the fractional part is 0; if not, it's not time to clock + if (bitfield(env_counter, 0, 11) != 0) + return; + + // determine the increment based on the non-fractional part of env_counter + uint32_t relevant_bits = bitfield(env_counter, (rate_shift <= 11) ? 11 : rate_shift, 3); + uint32_t increment = attenuation_increment(rate, relevant_bits); + + // attack is the only one that increases + if (m_env_state == EG_ATTACK) + { + // glitch means that attack rates of 62/63 don't increment if + // changed after the initial key on (where they are handled + // specially); nukeykt confirms this happens on OPM, OPN, OPL/OPLL + // at least so assuming it is true for everyone + if (rate < 62) + m_env_attenuation += (~m_env_attenuation * increment) >> 4; + } + + // all other cases are similar + else + { + // non-SSG-EG cases just apply the increment + if (!m_regs.op_ssg_eg_enable(m_opoffs)) + m_env_attenuation += increment; + + // SSG-EG only applies if less than mid-point, and then at 4x + else if (m_env_attenuation < 0x200) + m_env_attenuation += 4 * increment; + + // clamp the final attenuation + if (m_env_attenuation >= 0x400) + m_env_attenuation = 0x3ff; + + // transition from depress to attack + if (RegisterType::EG_HAS_DEPRESS && m_env_state == EG_DEPRESS && m_env_attenuation >= 0x200) + start_attack(); + + // transition from release to reverb, should switch at -18dB + if (RegisterType::EG_HAS_REVERB && m_env_state == EG_RELEASE && m_env_attenuation >= 0xc0) + m_env_state = EG_REVERB; + } +} + + +//------------------------------------------------- +// clock_phase - clock the 10.10 phase value; the +// OPN version of the logic has been verified +// against the Nuked phase generator +//------------------------------------------------- + +template +void fm_operator::clock_phase(int32_t lfo_raw_pm) +{ + // read from the cache, or recalculate if PM active + uint32_t phase_step = m_cache.phase_step; + if (phase_step == opdata_cache::PHASE_STEP_DYNAMIC) + phase_step = m_regs.compute_phase_step(m_choffs, m_opoffs, m_cache, lfo_raw_pm); + + // finally apply the step to the current phase value + m_phase += phase_step; +} + + +//------------------------------------------------- +// envelope_attenuation - return the effective +// attenuation of the envelope +//------------------------------------------------- + +template +uint32_t fm_operator::envelope_attenuation(uint32_t am_offset) const +{ + uint32_t result = m_env_attenuation >> m_cache.eg_shift; + + // invert if necessary due to SSG-EG + if (RegisterType::EG_HAS_SSG && m_ssg_inverted) + result = (0x200 - result) & 0x3ff; + + // add in LFO AM modulation + if (m_regs.op_lfo_am_enable(m_opoffs)) + result += am_offset; + + // add in total level and KSL from the cache + result += m_cache.total_level; + + // clamp to max, apply shift, and return + return std::min(result, 0x3ff); +} + + + +//********************************************************* +// FM CHANNEL +//********************************************************* + +//------------------------------------------------- +// fm_channel - constructor +//------------------------------------------------- + +template +fm_channel::fm_channel(fm_engine_base &owner, uint32_t choffs) : + m_choffs(choffs), + m_feedback{ 0, 0 }, + m_feedback_in(0), + m_op{ nullptr, nullptr, nullptr, nullptr }, + m_regs(owner.regs()), + m_owner(owner) +{ +} + + +//------------------------------------------------- +// reset - reset the channel state +//------------------------------------------------- + +template +void fm_channel::reset() +{ + // reset our data + m_feedback[0] = m_feedback[1] = 0; + m_feedback_in = 0; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +template +void fm_channel::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_feedback[0]); + state.save_restore(m_feedback[1]); + state.save_restore(m_feedback_in); +} + + +//------------------------------------------------- +// keyonoff - signal key on/off to our operators +//------------------------------------------------- + +template +void fm_channel::keyonoff(uint32_t states, keyon_type type, uint32_t chnum) +{ + for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) + if (m_op[opnum] != nullptr) + m_op[opnum]->keyonoff(bitfield(states, opnum), type); + + if (debug::LOG_KEYON_EVENTS && ((debug::GLOBAL_FM_CHANNEL_MASK >> chnum) & 1) != 0) + for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) + if (m_op[opnum] != nullptr) + debug::log_keyon("%c%s\n", bitfield(states, opnum) ? '+' : '-', m_regs.log_keyon(m_choffs, m_op[opnum]->opoffs()).c_str()); +} + + +//------------------------------------------------- +// prepare - prepare for clocking +//------------------------------------------------- + +template +bool fm_channel::prepare() +{ + uint32_t active_mask = 0; + + // prepare all operators and determine if they are active + for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) + if (m_op[opnum] != nullptr) + if (m_op[opnum]->prepare()) + active_mask |= 1 << opnum; + + return (active_mask != 0); +} + + +//------------------------------------------------- +// clock - master clock of all operators +//------------------------------------------------- + +template +void fm_channel::clock(uint32_t env_counter, int32_t lfo_raw_pm) +{ + // clock the feedback through + m_feedback[0] = m_feedback[1]; + m_feedback[1] = m_feedback_in; + + for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) + if (m_op[opnum] != nullptr) + m_op[opnum]->clock(env_counter, lfo_raw_pm); + +/* +useful temporary code for envelope debugging +if (m_choffs == 0x101) +{ + for (uint32_t opnum = 0; opnum < array_size(m_op); opnum++) + { + auto &op = *m_op[((opnum & 1) << 1) | ((opnum >> 1) & 1)]; + printf(" %c%03X%c%c ", + "PADSRV"[op.debug_eg_state()], + op.debug_eg_attenuation(), + op.debug_ssg_inverted() ? '-' : '+', + m_regs.op_ssg_eg_enable(op.opoffs()) ? '0' + m_regs.op_ssg_eg_mode(op.opoffs()) : ' '); + } +printf(" -- "); +} +*/ +} + + +//------------------------------------------------- +// output_2op - combine 4 operators according to +// the specified algorithm, returning a sum +// according to the rshift and clipmax parameters, +// which vary between different implementations +//------------------------------------------------- + +template +void fm_channel::output_2op(output_data &output, uint32_t rshift, int32_t clipmax) const +{ + // The first 2 operators should be populated + assert(m_op[0] != nullptr); + assert(m_op[1] != nullptr); + + // AM amount is the same across all operators; compute it once + uint32_t am_offset = m_regs.lfo_am_offset(m_choffs); + + // operator 1 has optional self-feedback + int32_t opmod = 0; + uint32_t feedback = m_regs.ch_feedback(m_choffs); + if (feedback != 0) + opmod = (m_feedback[0] + m_feedback[1]) >> (10 - feedback); + + // compute the 14-bit volume/value of operator 1 and update the feedback + int32_t op1value = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase() + opmod, am_offset); + + // now that the feedback has been computed, skip the rest if all volumes + // are clear; no need to do all this work for nothing + if (m_regs.ch_output_any(m_choffs) == 0) + return; + + // Algorithms for two-operator case: + // 0: O1 -> O2 -> out + // 1: (O1 + O2) -> out + int32_t result; + if (bitfield(m_regs.ch_algorithm(m_choffs), 0) == 0) + { + // some OPL chips use the previous sample for modulation instead of + // the current sample + opmod = (RegisterType::MODULATOR_DELAY ? m_feedback[1] : op1value) >> 1; + result = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset) >> rshift; + } + else + { + result = (RegisterType::MODULATOR_DELAY ? m_feedback[1] : op1value) >> rshift; + result += m_op[1]->compute_volume(m_op[1]->phase(), am_offset) >> rshift; + int32_t clipmin = -clipmax - 1; + result = clamp(result, clipmin, clipmax); + } + + // add to the output + add_to_output(m_choffs, output, result); +} + + +//------------------------------------------------- +// output_4op - combine 4 operators according to +// the specified algorithm, returning a sum +// according to the rshift and clipmax parameters, +// which vary between different implementations +//------------------------------------------------- + +template +void fm_channel::output_4op(output_data &output, uint32_t rshift, int32_t clipmax) const +{ + // all 4 operators should be populated + assert(m_op[0] != nullptr); + assert(m_op[1] != nullptr); + assert(m_op[2] != nullptr); + assert(m_op[3] != nullptr); + + // AM amount is the same across all operators; compute it once + uint32_t am_offset = m_regs.lfo_am_offset(m_choffs); + + // operator 1 has optional self-feedback + int32_t opmod = 0; + uint32_t feedback = m_regs.ch_feedback(m_choffs); + if (feedback != 0) + opmod = (m_feedback[0] + m_feedback[1]) >> (10 - feedback); + + // compute the 14-bit volume/value of operator 1 and update the feedback + int32_t op1value = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase() + opmod, am_offset); + + // now that the feedback has been computed, skip the rest if all volumes + // are clear; no need to do all this work for nothing + if (m_regs.ch_output_any(m_choffs) == 0) + return; + + // OPM/OPN offer 8 different connection algorithms for 4 operators, + // and OPL3 offers 4 more, which we designate here as 8-11. + // + // The operators are computed in order, with the inputs pulled from + // an array of values (opout) that is populated as we go: + // 0 = 0 + // 1 = O1 + // 2 = O2 + // 3 = O3 + // 4 = (O4) + // 5 = O1+O2 + // 6 = O1+O3 + // 7 = O2+O3 + // + // The s_algorithm_ops table describes the inputs and outputs of each + // algorithm as follows: + // + // ---------x use opout[x] as operator 2 input + // ------xxx- use opout[x] as operator 3 input + // ---xxx---- use opout[x] as operator 4 input + // --x------- include opout[1] in final sum + // -x-------- include opout[2] in final sum + // x--------- include opout[3] in final sum + #define ALGORITHM(op2in, op3in, op4in, op1out, op2out, op3out) \ + ((op2in) | ((op3in) << 1) | ((op4in) << 4) | ((op1out) << 7) | ((op2out) << 8) | ((op3out) << 9)) + static uint16_t const s_algorithm_ops[8+4] = + { + ALGORITHM(1,2,3, 0,0,0), // 0: O1 -> O2 -> O3 -> O4 -> out (O4) + ALGORITHM(0,5,3, 0,0,0), // 1: (O1 + O2) -> O3 -> O4 -> out (O4) + ALGORITHM(0,2,6, 0,0,0), // 2: (O1 + (O2 -> O3)) -> O4 -> out (O4) + ALGORITHM(1,0,7, 0,0,0), // 3: ((O1 -> O2) + O3) -> O4 -> out (O4) + ALGORITHM(1,0,3, 0,1,0), // 4: ((O1 -> O2) + (O3 -> O4)) -> out (O2+O4) + ALGORITHM(1,1,1, 0,1,1), // 5: ((O1 -> O2) + (O1 -> O3) + (O1 -> O4)) -> out (O2+O3+O4) + ALGORITHM(1,0,0, 0,1,1), // 6: ((O1 -> O2) + O3 + O4) -> out (O2+O3+O4) + ALGORITHM(0,0,0, 1,1,1), // 7: (O1 + O2 + O3 + O4) -> out (O1+O2+O3+O4) + ALGORITHM(1,2,3, 0,0,0), // 8: O1 -> O2 -> O3 -> O4 -> out (O4) [same as 0] + ALGORITHM(0,2,3, 1,0,0), // 9: (O1 + (O2 -> O3 -> O4)) -> out (O1+O4) [unique] + ALGORITHM(1,0,3, 0,1,0), // 10: ((O1 -> O2) + (O3 -> O4)) -> out (O2+O4) [same as 4] + ALGORITHM(0,2,0, 1,0,1) // 11: (O1 + (O2 -> O3) + O4) -> out (O1+O3+O4) [unique] + }; + uint32_t algorithm_ops = s_algorithm_ops[m_regs.ch_algorithm(m_choffs)]; + + // populate the opout table + int16_t opout[8]; + opout[0] = 0; + opout[1] = op1value; + + // compute the 14-bit volume/value of operator 2 + opmod = opout[bitfield(algorithm_ops, 0, 1)] >> 1; + opout[2] = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset); + opout[5] = opout[1] + opout[2]; + + // compute the 14-bit volume/value of operator 3 + opmod = opout[bitfield(algorithm_ops, 1, 3)] >> 1; + opout[3] = m_op[2]->compute_volume(m_op[2]->phase() + opmod, am_offset); + opout[6] = opout[1] + opout[3]; + opout[7] = opout[2] + opout[3]; + + // compute the 14-bit volume/value of operator 4; this could be a noise + // value on the OPM; all algorithms consume OP4 output at a minimum + int32_t result; + if (m_regs.noise_enable() && m_choffs == 7) + result = m_op[3]->compute_noise_volume(am_offset); + else + { + opmod = opout[bitfield(algorithm_ops, 4, 3)] >> 1; + result = m_op[3]->compute_volume(m_op[3]->phase() + opmod, am_offset); + } + result >>= rshift; + + // optionally add OP1, OP2, OP3 + int32_t clipmin = -clipmax - 1; + if (bitfield(algorithm_ops, 7) != 0) + result = clamp(result + (opout[1] >> rshift), clipmin, clipmax); + if (bitfield(algorithm_ops, 8) != 0) + result = clamp(result + (opout[2] >> rshift), clipmin, clipmax); + if (bitfield(algorithm_ops, 9) != 0) + result = clamp(result + (opout[3] >> rshift), clipmin, clipmax); + + // add to the output + add_to_output(m_choffs, output, result); +} + + +//------------------------------------------------- +// output_rhythm_ch6 - special case output +// computation for OPL channel 6 in rhythm mode, +// which outputs a Bass Drum instrument +//------------------------------------------------- + +template +void fm_channel::output_rhythm_ch6(output_data &output, uint32_t rshift, int32_t clipmax) const +{ + // AM amount is the same across all operators; compute it once + uint32_t am_offset = m_regs.lfo_am_offset(m_choffs); + + // Bass Drum: this uses operators 12 and 15 (i.e., channel 6) + // in an almost-normal way, except that if the algorithm is 1, + // the first operator is ignored instead of added in + + // operator 1 has optional self-feedback + int32_t opmod = 0; + uint32_t feedback = m_regs.ch_feedback(m_choffs); + if (feedback != 0) + opmod = (m_feedback[0] + m_feedback[1]) >> (10 - feedback); + + // compute the 14-bit volume/value of operator 1 and update the feedback + int32_t opout1 = m_feedback_in = m_op[0]->compute_volume(m_op[0]->phase() + opmod, am_offset); + + // compute the 14-bit volume/value of operator 2, which is the result + opmod = bitfield(m_regs.ch_algorithm(m_choffs), 0) ? 0 : (opout1 >> 1); + int32_t result = m_op[1]->compute_volume(m_op[1]->phase() + opmod, am_offset) >> rshift; + + // add to the output + add_to_output(m_choffs, output, result * 2); +} + + +//------------------------------------------------- +// output_rhythm_ch7 - special case output +// computation for OPL channel 7 in rhythm mode, +// which outputs High Hat and Snare Drum +// instruments +//------------------------------------------------- + +template +void fm_channel::output_rhythm_ch7(uint32_t phase_select, output_data &output, uint32_t rshift, int32_t clipmax) const +{ + // AM amount is the same across all operators; compute it once + uint32_t am_offset = m_regs.lfo_am_offset(m_choffs); + uint32_t noise_state = bitfield(m_regs.noise_state(), 0); + + // High Hat: this uses the envelope from operator 13 (channel 7), + // and a combination of noise and the operator 13/17 phase select + // to compute the phase + uint32_t phase = (phase_select << 9) | (0xd0 >> (2 * (noise_state ^ phase_select))); + int32_t result = m_op[0]->compute_volume(phase, am_offset) >> rshift; + + // Snare Drum: this uses the envelope from operator 16 (channel 7), + // and a combination of noise and operator 13 phase to pick a phase + uint32_t op13phase = m_op[0]->phase(); + phase = (0x100 << bitfield(op13phase, 8)) ^ (noise_state << 8); + result += m_op[1]->compute_volume(phase, am_offset) >> rshift; + result = clamp(result, -clipmax - 1, clipmax); + + // add to the output + add_to_output(m_choffs, output, result * 2); +} + + +//------------------------------------------------- +// output_rhythm_ch8 - special case output +// computation for OPL channel 8 in rhythm mode, +// which outputs Tom Tom and Top Cymbal instruments +//------------------------------------------------- + +template +void fm_channel::output_rhythm_ch8(uint32_t phase_select, output_data &output, uint32_t rshift, int32_t clipmax) const +{ + // AM amount is the same across all operators; compute it once + uint32_t am_offset = m_regs.lfo_am_offset(m_choffs); + + // Tom Tom: this is just a single operator processed normally + int32_t result = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift; + + // Top Cymbal: this uses the envelope from operator 17 (channel 8), + // and the operator 13/17 phase select to compute the phase + uint32_t phase = 0x100 | (phase_select << 9); + result += m_op[1]->compute_volume(phase, am_offset) >> rshift; + result = clamp(result, -clipmax - 1, clipmax); + + // add to the output + add_to_output(m_choffs, output, result * 2); +} + + + +//********************************************************* +// FM ENGINE BASE +//********************************************************* + +//------------------------------------------------- +// fm_engine_base - constructor +//------------------------------------------------- + +template +fm_engine_base::fm_engine_base(ymfm_interface &intf) : + m_intf(intf), + m_env_counter(0), + m_status(0), + m_clock_prescale(RegisterType::DEFAULT_PRESCALE), + m_irq_mask(STATUS_TIMERA | STATUS_TIMERB), + m_irq_state(0), + m_timer_running{0,0}, + m_active_channels(ALL_CHANNELS), + m_modified_channels(ALL_CHANNELS), + m_prepare_count(0) +{ + // inform the interface of their engine + m_intf.m_engine = this; + + // create the channels + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + m_channel[chnum] = std::make_unique>(*this, RegisterType::channel_offset(chnum)); + + // create the operators + for (uint32_t opnum = 0; opnum < OPERATORS; opnum++) + m_operator[opnum] = std::make_unique>(*this, RegisterType::operator_offset(opnum)); + +#if (DEBUG_LOG_WAVFILES) + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + m_wavfile[chnum].set_index(chnum); +#endif + + // do the initial operator assignment + assign_operators(); +} + + +//------------------------------------------------- +// reset - reset the overall state +//------------------------------------------------- + +template +void fm_engine_base::reset() +{ + // reset all status bits + set_reset_status(0, 0xff); + + // register type-specific initialization + m_regs.reset(); + + // explicitly write to the mode register since it has side-effects + // QUESTION: old cores initialize this to 0x30 -- who is right? + write(RegisterType::REG_MODE, 0); + + // reset the channels + for (auto &chan : m_channel) + chan->reset(); + + // reset the operators + for (auto &op : m_operator) + op->reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +template +void fm_engine_base::save_restore(ymfm_saved_state &state) +{ + // save our data + state.save_restore(m_env_counter); + state.save_restore(m_status); + state.save_restore(m_clock_prescale); + state.save_restore(m_irq_mask); + state.save_restore(m_irq_state); + state.save_restore(m_timer_running[0]); + state.save_restore(m_timer_running[1]); + state.save_restore(m_total_clocks); + + // save the register/family data + m_regs.save_restore(state); + + // save channel data + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + m_channel[chnum]->save_restore(state); + + // save operator data + for (uint32_t opnum = 0; opnum < OPERATORS; opnum++) + m_operator[opnum]->save_restore(state); + + // invalidate any caches + invalidate_caches(); +} + + +//------------------------------------------------- +// clock - iterate over all channels, clocking +// them forward one step +//------------------------------------------------- + +template +uint32_t fm_engine_base::clock(uint32_t chanmask) +{ + // update the clock counter + m_total_clocks++; + + // if something was modified, prepare + // also prepare every 4k samples to catch ending notes + if (m_modified_channels != 0 || m_prepare_count++ >= 4096) + { + // reassign operators to channels if dynamic + if (RegisterType::DYNAMIC_OPS) + assign_operators(); + + // call each channel to prepare + m_active_channels = 0; + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + if (m_channel[chnum]->prepare()) + m_active_channels |= 1 << chnum; + + // reset the modified channels and prepare count + m_modified_channels = m_prepare_count = 0; + } + + // if the envelope clock divider is 1, just increment by 4; + // otherwise, increment by 1 and manually wrap when we reach the divide count + if (RegisterType::EG_CLOCK_DIVIDER == 1) + m_env_counter += 4; + else if (bitfield(++m_env_counter, 0, 2) == RegisterType::EG_CLOCK_DIVIDER) + m_env_counter += 4 - RegisterType::EG_CLOCK_DIVIDER; + + // clock the noise generator + int32_t lfo_raw_pm = m_regs.clock_noise_and_lfo(); + + // now update the state of all the channels and operators + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + m_channel[chnum]->clock(m_env_counter, lfo_raw_pm); + + // return the envelope counter as it is used to clock ADPCM-A + return m_env_counter; +} + + +//------------------------------------------------- +// output - compute a sum over the relevant +// channels +//------------------------------------------------- + +template +void fm_engine_base::output(output_data &output, uint32_t rshift, int32_t clipmax, uint32_t chanmask) const +{ + // mask out some channels for debug purposes + chanmask &= debug::GLOBAL_FM_CHANNEL_MASK; + + // mask out inactive channels + if (!DEBUG_LOG_WAVFILES) + chanmask &= m_active_channels; + + // handle the rhythm case, where some of the operators are dedicated + // to percussion (this is an OPL-specific feature) + if (m_regs.rhythm_enable()) + { + // we don't support the OPM noise channel here; ensure it is off + assert(m_regs.noise_enable() == 0); + + // precompute the operator 13+17 phase selection value + uint32_t op13phase = m_operator[13]->phase(); + uint32_t op17phase = m_operator[17]->phase(); + uint32_t phase_select = (bitfield(op13phase, 2) ^ bitfield(op13phase, 7)) | bitfield(op13phase, 3) | (bitfield(op17phase, 5) ^ bitfield(op17phase, 3)); + + // sum over all the desired channels + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + { +#if (DEBUG_LOG_WAVFILES) + auto reference = output; +#endif + if (chnum == 6) + m_channel[chnum]->output_rhythm_ch6(output, rshift, clipmax); + else if (chnum == 7) + m_channel[chnum]->output_rhythm_ch7(phase_select, output, rshift, clipmax); + else if (chnum == 8) + m_channel[chnum]->output_rhythm_ch8(phase_select, output, rshift, clipmax); + else if (m_channel[chnum]->is4op()) + m_channel[chnum]->output_4op(output, rshift, clipmax); + else + m_channel[chnum]->output_2op(output, rshift, clipmax); +#if (DEBUG_LOG_WAVFILES) + m_wavfile[chnum].add(output, reference); +#endif + } + } + else + { + // sum over all the desired channels + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + { +#if (DEBUG_LOG_WAVFILES) + auto reference = output; +#endif + if (m_channel[chnum]->is4op()) + m_channel[chnum]->output_4op(output, rshift, clipmax); + else + m_channel[chnum]->output_2op(output, rshift, clipmax); +#if (DEBUG_LOG_WAVFILES) + m_wavfile[chnum].add(output, reference); +#endif + } + } +} + + +//------------------------------------------------- +// write - handle writes to the OPN registers +//------------------------------------------------- + +template +void fm_engine_base::write(uint16_t regnum, uint8_t data) +{ + debug::log_fm_write("%03X = %02X\n", regnum, data); + + // special case: writes to the mode register can impact IRQs; + // schedule these writes to ensure ordering with timers + if (regnum == RegisterType::REG_MODE) + { + m_intf.ymfm_sync_mode_write(data); + return; + } + + // for now just mark all channels as modified + m_modified_channels = ALL_CHANNELS; + + // most writes are passive, consumed only when needed + uint32_t keyon_channel; + uint32_t keyon_opmask; + if (m_regs.write(regnum, data, keyon_channel, keyon_opmask)) + { + // handle writes to the keyon register(s) + if (keyon_channel < CHANNELS) + { + // normal channel on/off + m_channel[keyon_channel]->keyonoff(keyon_opmask, KEYON_NORMAL, keyon_channel); + } + else if (CHANNELS >= 9 && keyon_channel == RegisterType::RHYTHM_CHANNEL) + { + // special case for the OPL rhythm channels + m_channel[6]->keyonoff(bitfield(keyon_opmask, 4) ? 3 : 0, KEYON_RHYTHM, 6); + m_channel[7]->keyonoff(bitfield(keyon_opmask, 0) | (bitfield(keyon_opmask, 3) << 1), KEYON_RHYTHM, 7); + m_channel[8]->keyonoff(bitfield(keyon_opmask, 2) | (bitfield(keyon_opmask, 1) << 1), KEYON_RHYTHM, 8); + } + } +} + + +//------------------------------------------------- +// status - return the current state of the +// status flags +//------------------------------------------------- + +template +uint8_t fm_engine_base::status() const +{ + return m_status & ~STATUS_BUSY & ~m_regs.status_mask(); +} + + +//------------------------------------------------- +// assign_operators - get the current mapping of +// operators to channels and assign them all +//------------------------------------------------- + +template +void fm_engine_base::assign_operators() +{ + typename RegisterType::operator_mapping map; + m_regs.operator_map(map); + + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + for (uint32_t index = 0; index < 4; index++) + { + uint32_t opnum = bitfield(map.chan[chnum], 8 * index, 8); + m_channel[chnum]->assign(index, (opnum == 0xff) ? nullptr : m_operator[opnum].get()); + } +} + + +//------------------------------------------------- +// update_timer - update the state of the given +// timer +//------------------------------------------------- + +template +void fm_engine_base::update_timer(uint32_t tnum, uint32_t enable, int32_t delta_clocks) +{ + uint32_t subtract = !!(tnum >> 15); + tnum &= 0x7fff; + + // if the timer is live, but not currently enabled, set the timer + if (enable && !m_timer_running[tnum]) + { + // period comes from the registers, and is different for each + uint32_t period = (tnum == 0) ? (1024 - subtract - m_regs.timer_a_value()) : 16 * (256 - subtract - m_regs.timer_b_value()); + + // caller can also specify a delta to account for other effects + period += delta_clocks; + + // reset it + m_intf.ymfm_set_timer(tnum, period * OPERATORS * m_clock_prescale); + m_timer_running[tnum] = 1; + } + + // if the timer is not live, ensure it is not enabled + else if (!enable) + { + m_intf.ymfm_set_timer(tnum, -1); + m_timer_running[tnum] = 0; + } +} + + +//------------------------------------------------- +// engine_timer_expired - timer has expired - signal +// status and possibly IRQs +//------------------------------------------------- + +template +void fm_engine_base::engine_timer_expired(uint32_t tnum) +{ + // update status + if (tnum == 0 && m_regs.enable_timer_a()) + set_reset_status(STATUS_TIMERA, 0); + else if (tnum == 1 && m_regs.enable_timer_b()) + set_reset_status(STATUS_TIMERB, 0); + + // if timer A fired in CSM mode, trigger CSM on all relevant channels + if (tnum == 0 && m_regs.csm()) + for (uint32_t chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(RegisterType::CSM_TRIGGER_MASK, chnum)) + { + m_channel[chnum]->keyonoff(1, KEYON_CSM, chnum); + m_modified_channels |= 1 << chnum; + } + + // reset + m_timer_running[tnum] = false; + update_timer(tnum, 1, 0); +} + + +//------------------------------------------------- +// check_interrupts - check the interrupt sources +// for interrupts +//------------------------------------------------- + +template +void fm_engine_base::engine_check_interrupts() +{ + // update the state + uint8_t old_state = m_irq_state; + m_irq_state = ((m_status & m_irq_mask & ~m_regs.status_mask()) != 0); + + // set the IRQ status bit + if (m_irq_state) + m_status |= STATUS_IRQ; + else + m_status &= ~STATUS_IRQ; + + // if changed, signal the new state + if (old_state != m_irq_state) + m_intf.ymfm_update_irq(m_irq_state ? true : false); +} + + +//------------------------------------------------- +// engine_mode_write - handle a mode register write +// via timer callback +//------------------------------------------------- + +template +void fm_engine_base::engine_mode_write(uint8_t data) +{ + // mark all channels as modified + m_modified_channels = ALL_CHANNELS; + + // actually write the mode register now + uint32_t dummy1, dummy2; + m_regs.write(RegisterType::REG_MODE, data, dummy1, dummy2); + + // reset IRQ status -- when written, all other bits are ignored + // QUESTION: should this maybe just reset the IRQ bit and not all the bits? + // That is, check_interrupts would only set, this would only clear? + if (m_regs.irq_reset()) + set_reset_status(0, 0x78); + else + { + // reset timer status + uint8_t reset_mask = 0; + if (m_regs.reset_timer_b()) + reset_mask |= RegisterType::STATUS_TIMERB; + if (m_regs.reset_timer_a()) + reset_mask |= RegisterType::STATUS_TIMERA; + set_reset_status(0, reset_mask); + + // load timers; note that timer B gets a small negative adjustment because + // the *16 multiplier is free-running, so the first tick of the clock + // is a bit shorter + // OPL3 begins counting immediately instead of after the first period is over. + // We use bit 15 of the timer number on those chips to inform that this was a + // control register write, and to therefore, subtract 1 counting cycle. + update_timer(1 | m_intf.get_special_flags(), m_regs.load_timer_b(), -(m_total_clocks & 15)); + update_timer(0 | m_intf.get_special_flags(), m_regs.load_timer_a(), 0); + } +} + +} diff --git a/src/sound/ymfm/ymfm_misc.cpp b/src/sound/ymfm/ymfm_misc.cpp new file mode 100644 index 000000000..fd0575f55 --- /dev/null +++ b/src/sound/ymfm/ymfm_misc.cpp @@ -0,0 +1,175 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_misc.h" + +namespace ymfm +{ + +//********************************************************* +// YM2149 +//********************************************************* + +//------------------------------------------------- +// ym2149 - constructor +//------------------------------------------------- + +ym2149::ym2149(ymfm_interface &intf) : + m_address(0), + m_ssg(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2149::reset() +{ + // reset the engines + m_ssg.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2149::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + m_ssg.save_restore(state); +} + + +//------------------------------------------------- +// read_data - read the data register +//------------------------------------------------- + +uint8_t ym2149::read_data() +{ + return m_ssg.read(m_address & 0x0f); +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2149::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 3) // BC2,BC1 + { + case 0: // inactive + break; + + case 1: // address + break; + + case 2: // inactive + break; + + case 3: // read + result = read_data(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2149::write_address(uint8_t data) +{ + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2149::write_data(uint8_t data) +{ + m_ssg.write(m_address & 0x0f, data); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2149::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) // BC2,BC1 + { + case 0: // address + write_address(data); + break; + + case 1: // inactive + break; + + case 2: // write + write_data(data); + break; + + case 3: // address + write_address(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate samples of SSG sound +//------------------------------------------------- + +void ym2149::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the SSG + m_ssg.clock(); + + // YM2149 keeps the three SSG outputs independent + m_ssg.output(*output); + } +} + +} diff --git a/src/sound/ymfm/ymfm_misc.h b/src/sound/ymfm/ymfm_misc.h new file mode 100644 index 000000000..628d128f6 --- /dev/null +++ b/src/sound/ymfm/ymfm_misc.h @@ -0,0 +1,93 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_MISC_H +#define YMFM_MISC_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_adpcm.h" +#include "ymfm_ssg.h" + +namespace ymfm +{ + +//********************************************************* +// SSG IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym2149 + +// ym2149 is just an SSG with no FM part, but we expose FM-like parts so that it +// integrates smoothly with everything else; they just don't do anything +class ym2149 +{ +public: + static constexpr uint32_t OUTPUTS = ssg_engine::OUTPUTS; + static constexpr uint32_t SSG_OUTPUTS = ssg_engine::OUTPUTS; + using output_data = ymfm_output; + + // constructor + ym2149(ymfm_interface &intf); + + // configuration + void ssg_override(ssg_override &intf) { m_ssg.override(intf); } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return input_clock / ssg_engine::CLOCK_DIVIDER / 8; } + + // read access + uint8_t read_data(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint8_t m_address; // address register + ssg_engine m_ssg; // SSG engine +}; + +} + +#endif // YMFM_MISC_H diff --git a/src/sound/ymfm/ymfm_opl.cpp b/src/sound/ymfm/ymfm_opl.cpp new file mode 100644 index 000000000..86215c5b2 --- /dev/null +++ b/src/sound/ymfm/ymfm_opl.cpp @@ -0,0 +1,2209 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_opl.h" +#include "ymfm_fm.ipp" + +namespace ymfm +{ + +//------------------------------------------------- +// opl_key_scale_atten - converts an +// OPL concatenated block (3 bits) and fnum +// (10 bits) into an attenuation offset; values +// here are for 6dB/octave, in 0.75dB units +// (matching total level LSB) +//------------------------------------------------- + +inline uint32_t opl_key_scale_atten(uint32_t block, uint32_t fnum_4msb) +{ + // this table uses the top 4 bits of FNUM and are the maximal values + // (for when block == 7). Values for other blocks can be computed by + // subtracting 8 for each block below 7. + static uint8_t const fnum_to_atten[16] = { 0,24,32,37,40,43,45,47,48,50,51,52,53,54,55,56 }; + int32_t result = fnum_to_atten[fnum_4msb] - 8 * (block ^ 7); + return std::max(0, result); +} + + +//********************************************************* +// OPL REGISTERS +//********************************************************* + +//------------------------------------------------- +// opl_registers_base - constructor +//------------------------------------------------- + +template +opl_registers_base::opl_registers_base() : + m_lfo_am_counter(0), + m_lfo_pm_counter(0), + m_noise_lfsr(1), + m_lfo_am(0) +{ + // create these pointers to appease overzealous compilers checking array + // bounds in unreachable code (looking at you, clang) + uint16_t *wf0 = &m_waveform[0][0]; + uint16_t *wf1 = &m_waveform[1 % WAVEFORMS][0]; + uint16_t *wf2 = &m_waveform[2 % WAVEFORMS][0]; + uint16_t *wf3 = &m_waveform[3 % WAVEFORMS][0]; + uint16_t *wf4 = &m_waveform[4 % WAVEFORMS][0]; + uint16_t *wf5 = &m_waveform[5 % WAVEFORMS][0]; + uint16_t *wf6 = &m_waveform[6 % WAVEFORMS][0]; + uint16_t *wf7 = &m_waveform[7 % WAVEFORMS][0]; + + // create the waveforms + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + wf0[index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); + + if (WAVEFORMS >= 4) + { + uint16_t zeroval = wf0[0]; + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + { + wf1[index] = bitfield(index, 9) ? zeroval : wf0[index]; + wf2[index] = wf0[index] & 0x7fff; + wf3[index] = bitfield(index, 8) ? zeroval : (wf0[index] & 0x7fff); + if (WAVEFORMS >= 8) + { + wf4[index] = bitfield(index, 9) ? zeroval : wf0[index * 2]; + wf5[index] = bitfield(index, 9) ? zeroval : wf0[(index * 2) & 0x1ff]; + wf6[index] = bitfield(index, 9) << 15; + wf7[index] = (bitfield(index, 9) ? (index ^ 0x13ff) : index) << 3; + } + } + } +} + + +//------------------------------------------------- +// reset - reset to initial state +//------------------------------------------------- + +template +void opl_registers_base::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +template +void opl_registers_base::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_lfo_am_counter); + state.save_restore(m_lfo_pm_counter); + state.save_restore(m_lfo_am); + state.save_restore(m_noise_lfsr); + state.save_restore(m_regdata); +} + + +//------------------------------------------------- +// operator_map - return an array of operator +// indices for each channel; for OPL this is fixed +//------------------------------------------------- + +template +void opl_registers_base::operator_map(operator_mapping &dest) const +{ + if (Revision <= 2) + { + // OPL/OPL2 has a fixed map, all 2 operators + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 3 ), // Channel 0 operators + operator_list( 1, 4 ), // Channel 1 operators + operator_list( 2, 5 ), // Channel 2 operators + operator_list( 6, 9 ), // Channel 3 operators + operator_list( 7, 10 ), // Channel 4 operators + operator_list( 8, 11 ), // Channel 5 operators + operator_list( 12, 15 ), // Channel 6 operators + operator_list( 13, 16 ), // Channel 7 operators + operator_list( 14, 17 ), // Channel 8 operators + } }; + dest = s_fixed_map; + } + else + { + // OPL3/OPL4 can be configured for 2 or 4 operators + uint32_t fourop = fourop_enable(); + + dest.chan[ 0] = bitfield(fourop, 0) ? operator_list( 0, 3, 6, 9 ) : operator_list( 0, 3 ); + dest.chan[ 1] = bitfield(fourop, 1) ? operator_list( 1, 4, 7, 10 ) : operator_list( 1, 4 ); + dest.chan[ 2] = bitfield(fourop, 2) ? operator_list( 2, 5, 8, 11 ) : operator_list( 2, 5 ); + dest.chan[ 3] = bitfield(fourop, 0) ? operator_list() : operator_list( 6, 9 ); + dest.chan[ 4] = bitfield(fourop, 1) ? operator_list() : operator_list( 7, 10 ); + dest.chan[ 5] = bitfield(fourop, 2) ? operator_list() : operator_list( 8, 11 ); + dest.chan[ 6] = operator_list( 12, 15 ); + dest.chan[ 7] = operator_list( 13, 16 ); + dest.chan[ 8] = operator_list( 14, 17 ); + + dest.chan[ 9] = bitfield(fourop, 3) ? operator_list( 18, 21, 24, 27 ) : operator_list( 18, 21 ); + dest.chan[10] = bitfield(fourop, 4) ? operator_list( 19, 22, 25, 28 ) : operator_list( 19, 22 ); + dest.chan[11] = bitfield(fourop, 5) ? operator_list( 20, 23, 26, 29 ) : operator_list( 20, 23 ); + dest.chan[12] = bitfield(fourop, 3) ? operator_list() : operator_list( 24, 27 ); + dest.chan[13] = bitfield(fourop, 4) ? operator_list() : operator_list( 25, 28 ); + dest.chan[14] = bitfield(fourop, 5) ? operator_list() : operator_list( 26, 29 ); + dest.chan[15] = operator_list( 30, 33 ); + dest.chan[16] = operator_list( 31, 34 ); + dest.chan[17] = operator_list( 32, 35 ); + } +} + + +//------------------------------------------------- +// write - handle writes to the register array +//------------------------------------------------- + +template +bool opl_registers_base::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) +{ + assert(index < REGISTERS); + + // writes to the mode register with high bit set ignore the low bits + if (index == REG_MODE && bitfield(data, 7) != 0) + m_regdata[index] |= 0x80; + else + m_regdata[index] = data; + + // handle writes to the rhythm keyons + if (index == 0xbd) + { + channel = RHYTHM_CHANNEL; + opmask = bitfield(data, 5) ? bitfield(data, 0, 5) : 0; + return true; + } + + // handle writes to the channel keyons + if ((index & 0xf0) == 0xb0) + { + channel = index & 0x0f; + if (channel < 9) + { + if (IsOpl3Plus) + channel += 9 * bitfield(index, 8); + opmask = bitfield(data, 5) ? 15 : 0; + return true; + } + } + return false; +} + + +//------------------------------------------------- +// clock_noise_and_lfo - clock the noise and LFO, +// handling clock division, depth, and waveform +// computations +//------------------------------------------------- + +static int32_t opl_clock_noise_and_lfo(uint32_t &noise_lfsr, uint16_t &lfo_am_counter, uint16_t &lfo_pm_counter, uint8_t &lfo_am, uint32_t am_depth, uint32_t pm_depth) +{ + // OPL has a 23-bit noise generator for the rhythm section, running at + // a constant rate, used only for percussion input + noise_lfsr <<= 1; + noise_lfsr |= bitfield(noise_lfsr, 23) ^ bitfield(noise_lfsr, 9) ^ bitfield(noise_lfsr, 8) ^ bitfield(noise_lfsr, 1); + + // OPL has two fixed-frequency LFOs, one for AM, one for PM + + // the AM LFO has 210*64 steps; at a nominal 50kHz output, + // this equates to a period of 50000/(210*64) = 3.72Hz + uint32_t am_counter = lfo_am_counter++; + if (am_counter >= 210*64 - 1) + lfo_am_counter = 0; + + // low 8 bits are fractional; depth 0 is divided by 2, while depth 1 is times 2 + int shift = 9 - 2 * am_depth; + + // AM value is the upper bits of the value, inverted across the midpoint + // to produce a triangle + lfo_am = ((am_counter < 105*64) ? am_counter : (210*64+63 - am_counter)) >> shift; + + // the PM LFO has 8192 steps, or a nominal period of 6.1Hz + uint32_t pm_counter = lfo_pm_counter++; + + // PM LFO is broken into 8 chunks, each lasting 1024 steps; the PM value + // depends on the upper bits of FNUM, so this value is a fraction and + // sign to apply to that value, as a 1.3 value + static int8_t const pm_scale[8] = { 8, 4, 0, -4, -8, -4, 0, 4 }; + return pm_scale[bitfield(pm_counter, 10, 3)] >> (pm_depth ^ 1); +} + +template +int32_t opl_registers_base::clock_noise_and_lfo() +{ + return opl_clock_noise_and_lfo(m_noise_lfsr, m_lfo_am_counter, m_lfo_pm_counter, m_lfo_am, lfo_am_depth(), lfo_pm_depth()); +} + + +//------------------------------------------------- +// cache_operator_data - fill the operator cache +// with prefetched data; note that this code is +// also used by ymopna_registers, so it must +// handle upper channels cleanly +//------------------------------------------------- + +template +void opl_registers_base::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) +{ + // set up the easy stuff + cache.waveform = &m_waveform[op_waveform(opoffs) % WAVEFORMS][0]; + + // get frequency from the channel + uint32_t block_freq = cache.block_freq = ch_block_freq(choffs); + + // compute the keycode: block_freq is: + // + // 111 | + // 21098|76543210 + // BBBFF|FFFFFFFF + // ^^^?? + // + // the 4-bit keycode uses the top 3 bits plus one of the next two bits + uint32_t keycode = bitfield(block_freq, 10, 3) << 1; + + // lowest bit is determined by note_select(); note that it is + // actually reversed from what the manual says, however + keycode |= bitfield(block_freq, 9 - note_select(), 1); + + // no detune adjustment on OPL + cache.detune = 0; + + // multiple value, as an x.1 value (0 means 0.5) + // replace the low bit with a table lookup to give 0,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 + uint32_t multiple = op_multiple(opoffs); + cache.multiple = ((multiple & 0xe) | bitfield(0xc2aa, multiple)) * 2; + if (cache.multiple == 0) + cache.multiple = 1; + + // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on block_freq, detune, + // and multiple, so compute it after we've done those + if (op_lfo_pm_enable(opoffs) == 0) + cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0); + else + cache.phase_step = opdata_cache::PHASE_STEP_DYNAMIC; + + // total level, scaled by 8 + cache.total_level = op_total_level(opoffs) << 3; + + // pre-add key scale level + uint32_t ksl = op_ksl(opoffs); + if (ksl != 0) + cache.total_level += opl_key_scale_atten(bitfield(block_freq, 10, 3), bitfield(block_freq, 6, 4)) << ksl; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = op_sustain_level(opoffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // determine KSR adjustment for enevlope rates + uint32_t ksrval = keycode >> (2 * (op_ksr(opoffs) ^ 1)); + cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 4, ksrval); + cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 4, ksrval); + cache.eg_rate[EG_SUSTAIN] = op_eg_sustain(opoffs) ? 0 : effective_rate(op_release_rate(opoffs) * 4, ksrval); + cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4, ksrval); + cache.eg_rate[EG_DEPRESS] = 0x3f; +} + + +//------------------------------------------------- +// compute_phase_step - compute the phase step +//------------------------------------------------- + +static uint32_t opl_compute_phase_step(uint32_t block_freq, uint32_t multiple, int32_t lfo_raw_pm) +{ + // OPL phase calculation has no detuning, but uses FNUMs like + // the OPN version, and computes PM a bit differently + + // extract frequency number as a 12-bit fraction + uint32_t fnum = bitfield(block_freq, 0, 10) << 2; + + // apply the phase adjustment based on the upper 3 bits + // of FNUM and the PM depth parameters + fnum += (lfo_raw_pm * bitfield(block_freq, 7, 3)) >> 1; + + // keep fnum to 12 bits + fnum &= 0xfff; + + // apply block shift to compute phase step + uint32_t block = bitfield(block_freq, 10, 3); + uint32_t phase_step = (fnum << block) >> 2; + + // apply frequency multiplier (which is cached as an x.1 value) + return (phase_step * multiple) >> 1; +} + +template +uint32_t opl_registers_base::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm) +{ + return opl_compute_phase_step(cache.block_freq, cache.multiple, op_lfo_pm_enable(opoffs) ? lfo_raw_pm : 0); +} + + +//------------------------------------------------- +// log_keyon - log a key-on event +//------------------------------------------------- + +template +std::string opl_registers_base::log_keyon(uint32_t choffs, uint32_t opoffs) +{ + uint32_t chnum = (choffs & 15) + 9 * bitfield(choffs, 8); + uint32_t opnum = (opoffs & 31) - 2 * ((opoffs & 31) / 8) + 18 * bitfield(opoffs, 8); + + char buffer[256]; + char *end = &buffer[0]; + + end += sprintf(end, "%2u.%02u freq=%04X fb=%u alg=%X mul=%X tl=%02X ksr=%u ns=%u ksl=%u adr=%X/%X/%X sl=%X sus=%u", + chnum, opnum, + ch_block_freq(choffs), + ch_feedback(choffs), + ch_algorithm(choffs), + op_multiple(opoffs), + op_total_level(opoffs), + op_ksr(opoffs), + note_select(), + op_ksl(opoffs), + op_attack_rate(opoffs), + op_decay_rate(opoffs), + op_release_rate(opoffs), + op_sustain_level(opoffs), + op_eg_sustain(opoffs)); + + if (OUTPUTS > 1) + end += sprintf(end, " out=%c%c%c%c", + ch_output_0(choffs) ? 'L' : '-', + ch_output_1(choffs) ? 'R' : '-', + ch_output_2(choffs) ? '0' : '-', + ch_output_3(choffs) ? '1' : '-'); + if (op_lfo_am_enable(opoffs) != 0) + end += sprintf(end, " am=%u", lfo_am_depth()); + if (op_lfo_pm_enable(opoffs) != 0) + end += sprintf(end, " pm=%u", lfo_pm_depth()); + if (waveform_enable() && op_waveform(opoffs) != 0) + end += sprintf(end, " wf=%u", op_waveform(opoffs)); + if (is_rhythm(choffs)) + end += sprintf(end, " rhy=1"); + if (DYNAMIC_OPS) + { + operator_mapping map; + operator_map(map); + if (bitfield(map.chan[chnum], 16, 8) != 0xff) + end += sprintf(end, " 4op"); + } + + return buffer; +} + + +//********************************************************* +// OPLL SPECIFICS +//********************************************************* + +//------------------------------------------------- +// opll_registers - constructor +//------------------------------------------------- + +opll_registers::opll_registers() : + m_lfo_am_counter(0), + m_lfo_pm_counter(0), + m_noise_lfsr(1), + m_lfo_am(0) +{ + // create the waveforms + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[0][index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); + + uint16_t zeroval = m_waveform[0][0]; + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[1][index] = bitfield(index, 9) ? zeroval : m_waveform[0][index]; + + // initialize the instruments to something sane + for (uint32_t choffs = 0; choffs < CHANNELS; choffs++) + m_chinst[choffs] = &m_regdata[0]; + for (uint32_t opoffs = 0; opoffs < OPERATORS; opoffs++) + m_opinst[opoffs] = &m_regdata[bitfield(opoffs, 0)]; +} + + +//------------------------------------------------- +// reset - reset to initial state +//------------------------------------------------- + +void opll_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void opll_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_lfo_am_counter); + state.save_restore(m_lfo_pm_counter); + state.save_restore(m_lfo_am); + state.save_restore(m_noise_lfsr); + state.save_restore(m_regdata); +} + + +//------------------------------------------------- +// operator_map - return an array of operator +// indices for each channel; for OPLL this is fixed +//------------------------------------------------- + +void opll_registers::operator_map(operator_mapping &dest) const +{ + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 1 ), // Channel 0 operators + operator_list( 2, 3 ), // Channel 1 operators + operator_list( 4, 5 ), // Channel 2 operators + operator_list( 6, 7 ), // Channel 3 operators + operator_list( 8, 9 ), // Channel 4 operators + operator_list( 10, 11 ), // Channel 5 operators + operator_list( 12, 13 ), // Channel 6 operators + operator_list( 14, 15 ), // Channel 7 operators + operator_list( 16, 17 ), // Channel 8 operators + } }; + dest = s_fixed_map; +} + + +//------------------------------------------------- +// write - handle writes to the register array; +// note that this code is also used by +// ymopl3_registers, so it must handle upper +// channels cleanly +//------------------------------------------------- + +bool opll_registers::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) +{ + // unclear the address is masked down to 6 bits or if writes above + // the register top are ignored; assuming the latter for now + if (index >= REGISTERS) + return false; + + // write the new data + m_regdata[index] = data; + + // handle writes to the rhythm keyons + if (index == 0x0e) + { + channel = RHYTHM_CHANNEL; + opmask = bitfield(data, 5) ? bitfield(data, 0, 5) : 0; + return true; + } + + // handle writes to the channel keyons + if ((index & 0xf0) == 0x20) + { + channel = index & 0x0f; + if (channel < CHANNELS) + { + opmask = bitfield(data, 4) ? 3 : 0; + return true; + } + } + return false; +} + + +//------------------------------------------------- +// clock_noise_and_lfo - clock the noise and LFO, +// handling clock division, depth, and waveform +// computations +//------------------------------------------------- + +int32_t opll_registers::clock_noise_and_lfo() +{ + // implementation is the same as OPL with fixed depths + return opl_clock_noise_and_lfo(m_noise_lfsr, m_lfo_am_counter, m_lfo_pm_counter, m_lfo_am, 1, 1); +} + + +//------------------------------------------------- +// cache_operator_data - fill the operator cache +// with prefetched data; note that this code is +// also used by ymopna_registers, so it must +// handle upper channels cleanly +//------------------------------------------------- + +void opll_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) +{ + // first set up the instrument data + uint32_t instrument = ch_instrument(choffs); + if (rhythm_enable() && choffs >= 6) + m_chinst[choffs] = &m_instdata[8 * (15 + (choffs - 6))]; + else + m_chinst[choffs] = (instrument == 0) ? &m_regdata[0] : &m_instdata[8 * (instrument - 1)]; + m_opinst[opoffs] = m_chinst[choffs] + bitfield(opoffs, 0); + + // set up the easy stuff + cache.waveform = &m_waveform[op_waveform(opoffs) % WAVEFORMS][0]; + + // get frequency from the channel + uint32_t block_freq = cache.block_freq = ch_block_freq(choffs); + + // compute the keycode: block_freq is: + // + // 11 | + // 1098|76543210 + // BBBF|FFFFFFFF + // ^^^^ + // + // the 4-bit keycode uses the top 4 bits + uint32_t keycode = bitfield(block_freq, 8, 4); + + // no detune adjustment on OPLL + cache.detune = 0; + + // multiple value, as an x.1 value (0 means 0.5) + // replace the low bit with a table lookup to give 0,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 + uint32_t multiple = op_multiple(opoffs); + cache.multiple = ((multiple & 0xe) | bitfield(0xc2aa, multiple)) * 2; + if (cache.multiple == 0) + cache.multiple = 1; + + // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on + // block_freq, detune, and multiple, so compute it after we've done those + if (op_lfo_pm_enable(opoffs) == 0) + cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0); + else + cache.phase_step = opdata_cache::PHASE_STEP_DYNAMIC; + + // total level, scaled by 8; for non-rhythm operator 0, this is the total + // level from the instrument data; for other operators it is 4*volume + if (bitfield(opoffs, 0) == 1 || (rhythm_enable() && choffs >= 7)) + cache.total_level = op_volume(opoffs) * 4; + else + cache.total_level = ch_total_level(choffs); + cache.total_level <<= 3; + + // pre-add key scale level + uint32_t ksl = op_ksl(opoffs); + if (ksl != 0) + cache.total_level += opl_key_scale_atten(bitfield(block_freq, 9, 3), bitfield(block_freq, 5, 4)) << ksl; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = op_sustain_level(opoffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // The envelope diagram in the YM2413 datasheet gives values for these + // in ms from 0->48dB. The attack/decay tables give values in ms from + // 0->96dB, so to pick an equivalent decay rate, we want to find the + // closest match that is 2x the 0->48dB value: + // + // DP = 10ms (0->48db) -> 20ms (0->96db); decay of 12 gives 19.20ms + // RR = 310ms (0->48db) -> 620ms (0->96db); decay of 7 gives 613.76ms + // RS = 1200ms (0->48db) -> 2400ms (0->96db); decay of 5 gives 2455.04ms + // + // The envelope diagram for percussive sounds (eg_sustain() == 0) also uses + // "RR" to mean both the constant RR above and the Release Rate specified in + // the instrument data. In this case, Relief Pitcher's credit sound bears out + // that the Release Rate is used during sustain, and that the constant RR + // (or RS) is used during the release phase. + constexpr uint8_t DP = 12 * 4; + constexpr uint8_t RR = 7 * 4; + constexpr uint8_t RS = 5 * 4; + + // determine KSR adjustment for envelope rates + uint32_t ksrval = keycode >> (2 * (op_ksr(opoffs) ^ 1)); + cache.eg_rate[EG_DEPRESS] = DP; + cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 4, ksrval); + cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 4, ksrval); + if (op_eg_sustain(opoffs)) + { + cache.eg_rate[EG_SUSTAIN] = 0; + cache.eg_rate[EG_RELEASE] = ch_sustain(choffs) ? RS : effective_rate(op_release_rate(opoffs) * 4, ksrval); + } + else + { + cache.eg_rate[EG_SUSTAIN] = effective_rate(op_release_rate(opoffs) * 4, ksrval); + cache.eg_rate[EG_RELEASE] = ch_sustain(choffs) ? RS : RR; + } +} + + +//------------------------------------------------- +// compute_phase_step - compute the phase step +//------------------------------------------------- + +uint32_t opll_registers::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm) +{ + // phase step computation is the same as OPL but the block_freq has one + // more bit, which we shift in + return opl_compute_phase_step(cache.block_freq << 1, cache.multiple, op_lfo_pm_enable(opoffs) ? lfo_raw_pm : 0); +} + + +//------------------------------------------------- +// log_keyon - log a key-on event +//------------------------------------------------- + +std::string opll_registers::log_keyon(uint32_t choffs, uint32_t opoffs) +{ + uint32_t chnum = choffs; + uint32_t opnum = opoffs; + + char buffer[256]; + char *end = &buffer[0]; + + end += sprintf(end, "%u.%02u freq=%04X inst=%X fb=%u mul=%X", + chnum, opnum, + ch_block_freq(choffs), + ch_instrument(choffs), + ch_feedback(choffs), + op_multiple(opoffs)); + + if (bitfield(opoffs, 0) == 1 || (is_rhythm(choffs) && choffs >= 6)) + end += sprintf(end, " vol=%X", op_volume(opoffs)); + else + end += sprintf(end, " tl=%02X", ch_total_level(choffs)); + + end += sprintf(end, " ksr=%u ksl=%u adr=%X/%X/%X sl=%X sus=%u/%u", + op_ksr(opoffs), + op_ksl(opoffs), + op_attack_rate(opoffs), + op_decay_rate(opoffs), + op_release_rate(opoffs), + op_sustain_level(opoffs), + op_eg_sustain(opoffs), + ch_sustain(choffs)); + + if (op_lfo_am_enable(opoffs)) + end += sprintf(end, " am=1"); + if (op_lfo_pm_enable(opoffs)) + end += sprintf(end, " pm=1"); + if (op_waveform(opoffs) != 0) + end += sprintf(end, " wf=1"); + if (is_rhythm(choffs)) + end += sprintf(end, " rhy=1"); + + return buffer; +} + + + +//********************************************************* +// YM3526 +//********************************************************* + +//------------------------------------------------- +// ym3526 - constructor +//------------------------------------------------- + +ym3526::ym3526(ymfm_interface &intf) : + m_address(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym3526::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym3526::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym3526::read_status() +{ + return m_fm.status() | 0x06; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym3526::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 1) + { + case 0: // status port + result = read_status(); + break; + + case 1: // when A0=1 datasheet says "the data on the bus are not guaranteed" + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym3526::write_address(uint8_t data) +{ + // YM3526 doesn't expose a busy signal, and the datasheets don't indicate + // delays, but all other OPL chips need 12 cycles for address writes + m_fm.intf().ymfm_set_busy_end(12 * m_fm.clock_prescale()); + + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym3526::write_data(uint8_t data) +{ + // YM3526 doesn't expose a busy signal, and the datasheets don't indicate + // delays, but all other OPL chips need 84 cycles for data writes + m_fm.intf().ymfm_set_busy_end(84 * m_fm.clock_prescale()); + + // write to FM + m_fm.write(m_address, data); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym3526::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate samples of sound +//------------------------------------------------- + +void ym3526::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; mixing details for YM3526 need verification + m_fm.output(output->clear(), 1, 32767, fm_engine::ALL_CHANNELS); + + // YM3526 uses an external DAC (YM3014) with mantissa/exponent format + // convert to 10.3 floating point value and back to simulate truncation + output->roundtrip_fp(); + } +} + + + +//********************************************************* +// Y8950 +//********************************************************* + +//------------------------------------------------- +// y8950 - constructor +//------------------------------------------------- + +y8950::y8950(ymfm_interface &intf) : + m_address(0), + m_io_ddr(0), + m_fm(intf), + m_adpcm_b(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void y8950::reset() +{ + // reset the engines + m_fm.reset(); + m_adpcm_b.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void y8950::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_io_ddr); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t y8950::read_status() +{ + // start with current FM status, masking out bits we might set + uint8_t status = m_fm.status() & ~(STATUS_ADPCM_B_EOS | STATUS_ADPCM_B_BRDY | STATUS_ADPCM_B_PLAYING); + + // insert the live ADPCM status bits + uint8_t adpcm_status = m_adpcm_b.status(); + if ((adpcm_status & adpcm_b_channel::STATUS_EOS) != 0) + status |= STATUS_ADPCM_B_EOS; + if ((adpcm_status & adpcm_b_channel::STATUS_BRDY) != 0) + status |= STATUS_ADPCM_B_BRDY; + if ((adpcm_status & adpcm_b_channel::STATUS_PLAYING) != 0) + status |= STATUS_ADPCM_B_PLAYING; + + // run it through the FM engine to handle interrupts for us + return m_fm.set_reset_status(status, ~status); +} + + +//------------------------------------------------- +// read_data - read the data port +//------------------------------------------------- + +uint8_t y8950::read_data() +{ + uint8_t result = 0xff; + switch (m_address) + { + case 0x05: // keyboard in + result = m_fm.intf().ymfm_external_read(ACCESS_IO, 1); + break; + + case 0x09: // ADPCM data + case 0x1a: + result = m_adpcm_b.read(m_address - 0x07); + break; + + case 0x19: // I/O data + result = m_fm.intf().ymfm_external_read(ACCESS_IO, 0); + break; + + default: + debug::log_unexpected_read_write("Unexpected read from Y8950 data port %02X\n", m_address); + break; + } + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t y8950::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 1) + { + case 0: // status port + result = read_status(); + break; + + case 1: // when A0=1 datasheet says "the data on the bus are not guaranteed" + result = read_data(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void y8950::write_address(uint8_t data) +{ + // Y8950 doesn't expose a busy signal, but it does indicate that + // address writes should be no faster than every 12 clocks + m_fm.intf().ymfm_set_busy_end(12 * m_fm.clock_prescale()); + + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void y8950::write_data(uint8_t data) +{ + // Y8950 doesn't expose a busy signal, but it does indicate that + // data writes should be no faster than every 12 clocks for + // registers 00-1A, or every 84 clocks for other registers + m_fm.intf().ymfm_set_busy_end(((m_address <= 0x1a) ? 12 : 84) * m_fm.clock_prescale()); + + // handle special addresses + switch (m_address) + { + case 0x04: // IRQ control + m_fm.write(m_address, data); + read_status(); + break; + + case 0x06: // keyboard out + m_fm.intf().ymfm_external_write(ACCESS_IO, 1, data); + break; + + case 0x08: // split FM/ADPCM-B + m_adpcm_b.write(m_address - 0x07, (data & 0x0f) | 0x80); + m_fm.write(m_address, data & 0xc0); + break; + + case 0x07: // ADPCM-B registers + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x15: + case 0x16: + case 0x17: + m_adpcm_b.write(m_address - 0x07, data); + break; + + case 0x18: // I/O direction + m_io_ddr = data & 0x0f; + break; + + case 0x19: // I/O data + m_fm.intf().ymfm_external_write(ACCESS_IO, 0, data & m_io_ddr); + break; + + default: // everything else to FM + m_fm.write(m_address, data); + break; + } +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void y8950::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate samples of sound +//------------------------------------------------- + +void y8950::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + m_adpcm_b.clock(); + + // update the FM content; clipping need verification + m_fm.output(output->clear(), 1, 32767, fm_engine::ALL_CHANNELS); + + // mix in the ADPCM; ADPCM-B is stereo, but only one channel + // not sure how it's wired up internally + m_adpcm_b.output(*output, 3); + + // Y8950 uses an external DAC (YM3014) with mantissa/exponent format + // convert to 10.3 floating point value and back to simulate truncation + output->roundtrip_fp(); + } +} + + + +//********************************************************* +// YM3812 +//********************************************************* + +//------------------------------------------------- +// ym3812 - constructor +//------------------------------------------------- + +ym3812::ym3812(ymfm_interface &intf) : + m_address(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym3812::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym3812::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym3812::read_status() +{ + return m_fm.status() | 0x06; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym3812::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 1) + { + case 0: // status port + result = read_status(); + break; + + case 1: // "inhibit" according to datasheet + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym3812::write_address(uint8_t data) +{ + // YM3812 doesn't expose a busy signal, but it does indicate that + // address writes should be no faster than every 12 clocks + m_fm.intf().ymfm_set_busy_end(12 * m_fm.clock_prescale()); + + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym3812::write_data(uint8_t data) +{ + // YM3812 doesn't expose a busy signal, but it does indicate that + // data writes should be no faster than every 84 clocks + m_fm.intf().ymfm_set_busy_end(84 * m_fm.clock_prescale()); + + // write to FM + m_fm.write(m_address, data); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym3812::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate samples of sound +//------------------------------------------------- + +void ym3812::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; mixing details for YM3812 need verification + m_fm.output(output->clear(), 1, 32767, fm_engine::ALL_CHANNELS); + + // YM3812 uses an external DAC (YM3014) with mantissa/exponent format + // convert to 10.3 floating point value and back to simulate truncation + output->roundtrip_fp(); + } +} + + + +//********************************************************* +// YMF262 +//********************************************************* + +//------------------------------------------------- +// ymf262 - constructor +//------------------------------------------------- + +ymf262::ymf262(ymfm_interface &intf) : + m_address(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ymf262::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ymf262::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ymf262::read_status() +{ + return m_fm.status(); +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ymf262::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 3) + { + case 0: // status port + result = read_status(); + break; + + case 1: + case 2: + case 3: + debug::log_unexpected_read_write("Unexpected read from YMF262 offset %d\n", offset & 3); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ymf262::write_address(uint8_t data) +{ + // YMF262 doesn't expose a busy signal, but it does indicate that + // address writes should be no faster than every 32 clocks + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); + + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write_data - handle a write to the data +// register +//------------------------------------------------- + +void ymf262::write_data(uint8_t data) +{ + // YMF262 doesn't expose a busy signal, but it does indicate that + // data writes should be no faster than every 32 clocks + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); + + // write to FM + m_fm.write(m_address, data); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ymf262::write_address_hi(uint8_t data) +{ + // YMF262 doesn't expose a busy signal, but it does indicate that + // address writes should be no faster than every 32 clocks + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); + + // just set the address + m_address = data | 0x100; + + // tests reveal that in compatibility mode, upper bit is masked + // except for register 0x105 + if (m_fm.regs().newflag() == 0 && m_address != 0x105) + m_address &= 0xff; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ymf262::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // address port + write_address_hi(data); + break; + + case 3: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate samples of sound +//------------------------------------------------- + +void ymf262::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; mixing details for YMF262 need verification + m_fm.output(output->clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // YMF262 output is 16-bit offset serial via YAC512 DAC + output->clamp16(); + } +} + + + +//********************************************************* +// YMF289B +//********************************************************* + +// YMF289B is a YMF262 with the following changes: +// * "Power down" mode added +// * Bulk register clear added +// * Busy flag added to the status register +// * Shorter busy times +// * All registers can be read +// * Only 2 outputs exposed + +//------------------------------------------------- +// ymf289b - constructor +//------------------------------------------------- + +ymf289b::ymf289b(ymfm_interface &intf) : + m_address(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ymf289b::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ymf289b::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ymf289b::read_status() +{ + uint8_t result = m_fm.status(); + + // YMF289B adds a busy flag + if (ymf289b_mode() && m_fm.intf().ymfm_is_busy()) + result |= STATUS_BUSY_FLAGS; + return result; +} + + +//------------------------------------------------- +// read_data - read the data register +//------------------------------------------------- + +uint8_t ymf289b::read_data() +{ + uint8_t result = 0xff; + + // YMF289B can read register data back + if (ymf289b_mode()) + result = m_fm.regs().read(m_address); + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ymf289b::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 3) + { + case 0: // status port + result = read_status(); + break; + + case 1: // data port + result = read_data(); + break; + + case 2: + case 3: + debug::log_unexpected_read_write("Unexpected read from YMF289B offset %d\n", offset & 3); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ymf289b::write_address(uint8_t data) +{ + m_address = data; + + // count busy time + m_fm.intf().ymfm_set_busy_end(56); +} + + +//------------------------------------------------- +// write_data - handle a write to the data +// register +//------------------------------------------------- + +void ymf289b::write_data(uint8_t data) +{ + // write to FM + m_fm.write(m_address, data); + + // writes to 0x108 with the CLR flag set clear the registers + if (m_address == 0x108 && bitfield(data, 2) != 0) + m_fm.regs().reset(); + + // count busy time + m_fm.intf().ymfm_set_busy_end(56); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ymf289b::write_address_hi(uint8_t data) +{ + // just set the address + m_address = data | 0x100; + + // tests reveal that in compatibility mode, upper bit is masked + // except for register 0x105 + if (m_fm.regs().newflag() == 0 && m_address != 0x105) + m_address &= 0xff; + + // count busy time + m_fm.intf().ymfm_set_busy_end(56); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ymf289b::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // address port + write_address_hi(data); + break; + + case 3: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate samples of sound +//------------------------------------------------- + +void ymf289b::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; mixing details for YMF262 need verification + fm_engine::output_data full; + m_fm.output(full.clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // YMF278B output is 16-bit offset serial via YAC512 DAC, but + // only 2 of the 4 outputs are exposed + output->data[0] = full.data[0]; + output->data[1] = full.data[1]; + output->clamp16(); + } +} + + + +//********************************************************* +// YMF278B +//********************************************************* + +//------------------------------------------------- +// ymf278b - constructor +//------------------------------------------------- + +ymf278b::ymf278b(ymfm_interface &intf) : + m_address(0), + m_fm_pos(0), + m_load_remaining(0), + m_next_status_id(false), + m_fm(intf), + m_pcm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ymf278b::reset() +{ + // reset the engines + m_fm.reset(); + m_pcm.reset(); + + // next status read will return ID + m_next_status_id = true; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ymf278b::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_fm_pos); + state.save_restore(m_load_remaining); + state.save_restore(m_next_status_id); + m_fm.save_restore(state); + m_pcm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ymf278b::read_status() +{ + uint8_t result; + + // first status read after initialization returns a chip ID, which + // varies based on the "new" flags, indicating the mode + if (m_next_status_id) + { + if (m_fm.regs().new2flag()) + result = 0x02; + else if (m_fm.regs().newflag()) + result = 0x00; + else + result = 0x06; + m_next_status_id = false; + } + else + { + result = m_fm.status(); + if (m_fm.intf().ymfm_is_busy()) + result |= STATUS_BUSY; + if (m_load_remaining != 0) + result |= STATUS_LD; + + // if new2 flag is not set, we're in OPL2 or OPL3 mode + if (!m_fm.regs().new2flag()) + result &= ~(STATUS_BUSY | STATUS_LD); + } + return result; +} + + +//------------------------------------------------- +// write_data_pcm - handle a write to the PCM data +// register +//------------------------------------------------- + +uint8_t ymf278b::read_data_pcm() +{ + // write to FM + if (bitfield(m_address, 9) != 0) + return m_pcm.read(m_address & 0xff); + return 0; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ymf278b::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 7) + { + case 0: // status port + result = read_status(); + break; + + case 5: // PCM data port + result = read_data_pcm(); + break; + + default: + debug::log_unexpected_read_write("Unexpected read from ymf278b offset %d\n", offset & 3); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ymf278b::write_address(uint8_t data) +{ + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write_data - handle a write to the data +// register +//------------------------------------------------- + +void ymf278b::write_data(uint8_t data) +{ + // write to FM + if (bitfield(m_address, 9) == 0) + { + uint8_t old = m_fm.regs().new2flag(); + m_fm.write(m_address, data); + + // changing NEW2 from 0->1 causes the next status read to + // return the chip ID + if (old == 0 && m_fm.regs().new2flag() != 0) + m_next_status_id = true; + } + + // BUSY goes for 56 clocks on FM writes + m_fm.intf().ymfm_set_busy_end(56); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ymf278b::write_address_hi(uint8_t data) +{ + // just set the address + m_address = data | 0x100; + + // YMF262, in compatibility mode, treats the upper bit as masked + // except for register 0x105; assuming YMF278B works the same way? + if (m_fm.regs().newflag() == 0 && m_address != 0x105) + m_address &= 0xff; +} + + +//------------------------------------------------- +// write_address_pcm - handle a write to the upper +// address register +//------------------------------------------------- + +void ymf278b::write_address_pcm(uint8_t data) +{ + // just set the address + m_address = data | 0x200; +} + + +//------------------------------------------------- +// write_data_pcm - handle a write to the PCM data +// register +//------------------------------------------------- + +void ymf278b::write_data_pcm(uint8_t data) +{ + // ignore data writes if new2 is not yet set + if (m_fm.regs().new2flag() == 0) + return; + + // write to FM + if (bitfield(m_address, 9) != 0) + { + uint8_t addr = m_address & 0xff; + m_pcm.write(addr, data); + + // writes to the waveform number cause loads to happen for "about 300usec" + // which is ~13 samples at the nominal output frequency of 44.1kHz + if (addr >= 0x08 && addr <= 0x1f) + m_load_remaining = 13; + } + + // BUSY goes for 88 clocks on PCM writes + m_fm.intf().ymfm_set_busy_end(88); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ymf278b::write(uint32_t offset, uint8_t data) +{ + switch (offset & 7) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // address port + write_address_hi(data); + break; + + case 3: // data port + write_data(data); + break; + + case 4: // PCM address port + write_address_pcm(data); + break; + + case 5: // PCM address port + write_data_pcm(data); + break; + + default: + debug::log_unexpected_read_write("Unexpected write to ymf278b offset %d\n", offset & 7); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ymf278b::generate(output_data *output, uint32_t numsamples) +{ + static const int16_t s_mix_scale[8] = { 0x7fa, 0x5a4, 0x3fd, 0x2d2, 0x1fe, 0x169, 0xff, 0 }; + int32_t const pcm_l = s_mix_scale[m_pcm.regs().mix_pcm_l()]; + int32_t const pcm_r = s_mix_scale[m_pcm.regs().mix_pcm_r()]; + int32_t const fm_l = s_mix_scale[m_pcm.regs().mix_fm_l()]; + int32_t const fm_r = s_mix_scale[m_pcm.regs().mix_fm_r()]; + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm_pos += FM_EXTRA_SAMPLE_STEP; + if (m_fm_pos >= FM_EXTRA_SAMPLE_THRESH) + { + m_fm.clock(fm_engine::ALL_CHANNELS); + m_fm_pos -= FM_EXTRA_SAMPLE_THRESH; + } + m_fm.clock(fm_engine::ALL_CHANNELS); + m_pcm.clock(pcm_engine::ALL_CHANNELS); + + // update the FM content; mixing details for YMF278B need verification + fm_engine::output_data fmout; + m_fm.output(fmout.clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // update the PCM content + pcm_engine::output_data pcmout; + m_pcm.output(pcmout.clear(), pcm_engine::ALL_CHANNELS); + + // DO0 output: FM channels 2+3 only + output->data[0] = fmout.data[2]; + output->data[1] = fmout.data[3]; + + // DO1 output: wavetable channels 2+3 only + output->data[2] = pcmout.data[2]; + output->data[3] = pcmout.data[3]; + + // DO2 output: mixed FM channels 0+1 and wavetable channels 0+1 + output->data[4] = (fmout.data[0] * fm_l + pcmout.data[0] * pcm_l) >> 11; + output->data[5] = (fmout.data[1] * fm_r + pcmout.data[1] * pcm_r) >> 11; + + // YMF278B output is 16-bit 2s complement serial + output->clamp16(); + } + + // decrement the load waiting count + if (m_load_remaining > 0) + m_load_remaining -= std::min(m_load_remaining, numsamples); +} + + + +//********************************************************* +// OPLL BASE +//********************************************************* + +//------------------------------------------------- +// opll_base - constructor +//------------------------------------------------- + +opll_base::opll_base(ymfm_interface &intf, uint8_t const *instrument_data) : + m_address(0), + m_fm(intf) +{ + m_fm.regs().set_instrument_data(instrument_data); +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void opll_base::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void opll_base::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void opll_base::write_address(uint8_t data) +{ + // OPLL doesn't expose a busy signal, but datasheets are pretty consistent + // in indicating that address writes should be no faster than every 12 clocks + m_fm.intf().ymfm_set_busy_end(12); + + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void opll_base::write_data(uint8_t data) +{ + // OPLL doesn't expose a busy signal, but datasheets are pretty consistent + // in indicating that address writes should be no faster than every 84 clocks + m_fm.intf().ymfm_set_busy_end(84); + + // write to FM + m_fm.write(m_address, data); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void opll_base::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void opll_base::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; OPLL has a built-in 9-bit DAC + m_fm.output(output->clear(), 5, 256, fm_engine::ALL_CHANNELS); + + // final output is multiplexed; we don't simulate that here except + // to average over everything + output->data[0] = (output->data[0] * 128) / 9; + output->data[1] = (output->data[1] * 128) / 9; + } +} + + + +//********************************************************* +// YM2413 +//********************************************************* + +//------------------------------------------------- +// ym2413 - constructor +//------------------------------------------------- + +ym2413::ym2413(ymfm_interface &intf, uint8_t const *instrument_data) : + opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) +{ +}; + +// table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches +uint8_t const ym2413::s_default_instruments[] = +{ + //April 2015 David Viens, tweaked May 19-21th 2015 Hubert Lamontagne + 0x71, 0x61, 0x1E, 0x17, 0xEF, 0x7F, 0x00, 0x17, //Violin + 0x13, 0x41, 0x1A, 0x0D, 0xF8, 0xF7, 0x23, 0x13, //Guitar + 0x13, 0x01, 0x99, 0x00, 0xF2, 0xC4, 0x11, 0x23, //Piano + 0x31, 0x61, 0x0E, 0x07, 0x98, 0x64, 0x70, 0x27, //Flute + 0x22, 0x21, 0x1E, 0x06, 0xBF, 0x76, 0x00, 0x28, //Clarinet + 0x31, 0x22, 0x16, 0x05, 0xE0, 0x71, 0x0F, 0x18, //Oboe + 0x21, 0x61, 0x1D, 0x07, 0x82, 0x8F, 0x10, 0x07, //Trumpet + 0x23, 0x21, 0x2D, 0x14, 0xFF, 0x7F, 0x00, 0x07, //Organ + 0x41, 0x61, 0x1B, 0x06, 0x64, 0x65, 0x10, 0x17, //Horn + 0x61, 0x61, 0x0B, 0x18, 0x85, 0xFF, 0x81, 0x07, //Synthesizer + 0x13, 0x01, 0x83, 0x11, 0xFA, 0xE4, 0x10, 0x04, //Harpsichord + 0x17, 0x81, 0x23, 0x07, 0xF8, 0xF8, 0x22, 0x12, //Vibraphone + 0x61, 0x50, 0x0C, 0x05, 0xF2, 0xF5, 0x29, 0x42, //Synthesizer Bass + 0x01, 0x01, 0x54, 0x03, 0xC3, 0x92, 0x03, 0x02, //Acoustic Bass + 0x41, 0x41, 0x89, 0x03, 0xF1, 0xE5, 0x11, 0x13, //Electric Guitar + 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 + 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 + 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 +}; + + + +//********************************************************* +// YM2423 +//********************************************************* + +//------------------------------------------------- +// ym2423 - constructor +//------------------------------------------------- + +ym2423::ym2423(ymfm_interface &intf, uint8_t const *instrument_data) : + opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) +{ +}; + +// table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches +uint8_t const ym2423::s_default_instruments[] = +{ + // May 4-6 2016 Hubert Lamontagne + // Doesn't seem to have any diff between opllx-x and opllx-y + // Drums seem identical to regular opll + 0x61, 0x61, 0x1B, 0x07, 0x94, 0x5F, 0x10, 0x06, //1 Strings Saw wave with vibrato Violin + 0x93, 0xB1, 0x51, 0x04, 0xF3, 0xF2, 0x70, 0xFB, //2 Guitar Jazz GuitarPiano + 0x41, 0x21, 0x11, 0x85, 0xF2, 0xF2, 0x70, 0x75, //3 Electric Guitar Same as OPLL No.15 Synth + 0x93, 0xB2, 0x28, 0x07, 0xF3, 0xF2, 0x70, 0xB4, //4 Electric Piano 2 Slow attack, tremoloDing-a-ling + 0x72, 0x31, 0x97, 0x05, 0x51, 0x6F, 0x60, 0x09, //5 Flute Same as OPLL No.4Clarinet + 0x13, 0x30, 0x18, 0x06, 0xF7, 0xF4, 0x50, 0x85, //6 Marimba Also be used as steel drumXyophone + 0x51, 0x31, 0x1C, 0x07, 0x51, 0x71, 0x20, 0x26, //7 Trumpet Same as OPLL No.7Trumpet + 0x41, 0xF4, 0x1B, 0x07, 0x74, 0x34, 0x00, 0x06, //8 Harmonica Harmonica synth + 0x50, 0x30, 0x4D, 0x03, 0x42, 0x65, 0x20, 0x06, //9 Tuba Tuba + 0x40, 0x20, 0x10, 0x85, 0xF3, 0xF5, 0x20, 0x04, //10 Synth Brass 2 Synth sweep + 0x61, 0x61, 0x1B, 0x07, 0xC5, 0x96, 0xF3, 0xF6, //11 Short Saw Saw wave with short envelopeSynth hit + 0xF9, 0xF1, 0xDC, 0x00, 0xF5, 0xF3, 0x77, 0xF2, //12 Vibraphone Bright vibraphoneVibes + 0x60, 0xA2, 0x91, 0x03, 0x94, 0xC1, 0xF7, 0xF7, //13 Electric Guitar 2 Clean guitar with feedbackHarmonic bass + 0x30, 0x30, 0x17, 0x06, 0xF3, 0xF1, 0xB7, 0xFC, //14 Synth Bass 2Snappy bass + 0x31, 0x36, 0x0D, 0x05, 0xF2, 0xF4, 0x27, 0x9C, //15 Sitar Also be used as ShamisenBanjo + 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 + 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 + 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 +}; + + + +//********************************************************* +// YMF281 +//********************************************************* + +//------------------------------------------------- +// ymf281 - constructor +//------------------------------------------------- + +ymf281::ymf281(ymfm_interface &intf, uint8_t const *instrument_data) : + opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) +{ +}; + +// table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches +uint8_t const ymf281::s_default_instruments[] = +{ + // May 14th 2015 Hubert Lamontagne + 0x72, 0x21, 0x1A, 0x07, 0xF6, 0x64, 0x01, 0x16, // Clarinet ~~ Electric String Square wave with vibrato + 0x00, 0x10, 0x45, 0x00, 0xF6, 0x83, 0x73, 0x63, // Synth Bass ~~ Bow wow Triangular wave + 0x13, 0x01, 0x96, 0x00, 0xF1, 0xF4, 0x31, 0x23, // Piano ~~ Electric Guitar Despite of its name, same as Piano of YM2413. + 0x71, 0x21, 0x0B, 0x0F, 0xF9, 0x64, 0x70, 0x17, // Flute ~~ Organ Sine wave + 0x02, 0x21, 0x1E, 0x06, 0xF9, 0x76, 0x00, 0x28, // Square Wave ~~ Clarinet Same as ones of YM2413. + 0x00, 0x61, 0x82, 0x0E, 0xF9, 0x61, 0x20, 0x27, // Space Oboe ~~ Saxophone Saw wave with vibrato + 0x21, 0x61, 0x1B, 0x07, 0x84, 0x8F, 0x10, 0x07, // Trumpet ~~ Trumpet Same as ones of YM2413. + 0x37, 0x32, 0xCA, 0x02, 0x66, 0x64, 0x47, 0x29, // Wow Bell ~~ Street Organ Calliope + 0x41, 0x41, 0x07, 0x03, 0xF5, 0x70, 0x51, 0xF5, // Electric Guitar ~~ Synth Brass Same as Synthesizer of YM2413. + 0x36, 0x01, 0x5E, 0x07, 0xF2, 0xF3, 0xF7, 0xF7, // Vibes ~~ Electric Piano Simulate of Rhodes Piano + 0x00, 0x00, 0x18, 0x06, 0xC5, 0xF3, 0x20, 0xF2, // Bass ~~ Bass Electric bass + 0x17, 0x81, 0x25, 0x07, 0xF7, 0xF3, 0x21, 0xF7, // Vibraphone ~~ Vibraphone Same as ones of YM2413. + 0x35, 0x64, 0x00, 0x00, 0xFF, 0xF3, 0x77, 0xF5, // Vibrato Bell ~~ Chime Bell + 0x11, 0x31, 0x00, 0x07, 0xDD, 0xF3, 0xFF, 0xFB, // Click Sine ~~ Tom Tom II Tom + 0x3A, 0x21, 0x00, 0x07, 0x95, 0x84, 0x0F, 0xF5, // Noise and Tone ~~ Noise for S.E. + 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 + 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 + 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 +}; + + + +//********************************************************* +// DS1001 +//********************************************************* + +//------------------------------------------------- +// ds1001 - constructor +//------------------------------------------------- + +ds1001::ds1001(ymfm_interface &intf, uint8_t const *instrument_data) : + opll_base(intf, (instrument_data != nullptr) ? instrument_data : s_default_instruments) +{ +}; + +// table below taken from https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches +uint8_t const ds1001::s_default_instruments[] = +{ + // May 15th 2015 Hubert Lamontagne & David Viens + 0x03, 0x21, 0x05, 0x06, 0xC8, 0x81, 0x42, 0x27, // Buzzy Bell + 0x13, 0x41, 0x14, 0x0D, 0xF8, 0xF7, 0x23, 0x12, // Guitar + 0x31, 0x11, 0x08, 0x08, 0xFA, 0xC2, 0x28, 0x22, // Wurly + 0x31, 0x61, 0x0C, 0x07, 0xF8, 0x64, 0x60, 0x27, // Flute + 0x22, 0x21, 0x1E, 0x06, 0xFF, 0x76, 0x00, 0x28, // Clarinet + 0x02, 0x01, 0x05, 0x00, 0xAC, 0xF2, 0x03, 0x02, // Synth + 0x21, 0x61, 0x1D, 0x07, 0x82, 0x8F, 0x10, 0x07, // Trumpet + 0x23, 0x21, 0x22, 0x17, 0xFF, 0x73, 0x00, 0x17, // Organ + 0x15, 0x11, 0x25, 0x00, 0x41, 0x71, 0x00, 0xF1, // Bells + 0x95, 0x01, 0x10, 0x0F, 0xB8, 0xAA, 0x50, 0x02, // Vibes + 0x17, 0xC1, 0x5E, 0x07, 0xFA, 0xF8, 0x22, 0x12, // Vibraphone + 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x10, 0x16, // Tutti + 0x01, 0x02, 0xD3, 0x05, 0xF3, 0x92, 0x83, 0xF2, // Fretless + 0x61, 0x63, 0x0C, 0x00, 0xA4, 0xFF, 0x30, 0x06, // Synth Bass + 0x21, 0x62, 0x0D, 0x00, 0xA1, 0xFF, 0x50, 0x08, // Sweep + 0x01, 0x01, 0x18, 0x0F, 0xDF, 0xF8, 0x6A, 0x6D, //rhythm 1 + 0x01, 0x01, 0x00, 0x00, 0xC8, 0xD8, 0xA7, 0x48, //rhythm 2 + 0x05, 0x01, 0x00, 0x00, 0xF8, 0xAA, 0x59, 0x55 //rhythm 3 +}; + + +//********************************************************* +// EXPLICIT INSTANTIATION +//********************************************************* + +template class opl_registers_base<4>; +template class fm_engine_base>; + +} diff --git a/src/sound/ymfm/ymfm_opl.h b/src/sound/ymfm/ymfm_opl.h new file mode 100644 index 000000000..843e5b274 --- /dev/null +++ b/src/sound/ymfm/ymfm_opl.h @@ -0,0 +1,902 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_OPL_H +#define YMFM_OPL_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_adpcm.h" +#include "ymfm_fm.h" +#include "ymfm_pcm.h" + +namespace ymfm +{ + +//********************************************************* +// REGISTER CLASSES +//********************************************************* + +// ======================> opl_registers_base + +// +// OPL/OPL2/OPL3/OPL4 register map: +// +// System-wide registers: +// 01 xxxxxxxx Test register +// --x----- Enable OPL compatibility mode [OPL2 only] (1 = enable) +// 02 xxxxxxxx Timer A value (4 * OPN) +// 03 xxxxxxxx Timer B value +// 04 x------- RST +// -x------ Mask timer A +// --x----- Mask timer B +// ------x- Load timer B +// -------x Load timer A +// 08 x------- CSM mode [OPL/OPL2 only] +// -x------ Note select +// BD x------- AM depth +// -x------ PM depth +// --x----- Rhythm enable +// ---x---- Bass drum key on +// ----x--- Snare drum key on +// -----x-- Tom key on +// ------x- Top cymbal key on +// -------x High hat key on +// 101 --xxxxxx Test register 2 [OPL3 only] +// 104 --x----- Channel 6 4-operator mode [OPL3 only] +// ---x---- Channel 5 4-operator mode [OPL3 only] +// ----x--- Channel 4 4-operator mode [OPL3 only] +// -----x-- Channel 3 4-operator mode [OPL3 only] +// ------x- Channel 2 4-operator mode [OPL3 only] +// -------x Channel 1 4-operator mode [OPL3 only] +// 105 -------x New [OPL3 only] +// ------x- New2 [OPL4 only] +// +// Per-channel registers (channel in address bits 0-3) +// Note that all these apply to address+100 as well on OPL3+ +// A0-A8 xxxxxxxx F-number (low 8 bits) +// B0-B8 --x----- Key on +// ---xxx-- Block (octvate, 0-7) +// ------xx F-number (high two bits) +// C0-C8 x------- CHD output (to DO0 pin) [OPL3+ only] +// -x------ CHC output (to DO0 pin) [OPL3+ only] +// --x----- CHB output (mixed right, to DO2 pin) [OPL3+ only] +// ---x---- CHA output (mixed left, to DO2 pin) [OPL3+ only] +// ----xxx- Feedback level for operator 1 (0-7) +// -------x Operator connection algorithm +// +// Per-operator registers (operator in bits 0-5) +// Note that all these apply to address+100 as well on OPL3+ +// 20-35 x------- AM enable +// -x------ PM enable (VIB) +// --x----- EG type +// ---x---- Key scale rate +// ----xxxx Multiple value (0-15) +// 40-55 xx------ Key scale level (0-3) +// --xxxxxx Total level (0-63) +// 60-75 xxxx---- Attack rate (0-15) +// ----xxxx Decay rate (0-15) +// 80-95 xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// E0-F5 ------xx Wave select (0-3) [OPL2 only] +// -----xxx Wave select (0-7) [OPL3+ only] +// + +template +class opl_registers_base : public fm_registers_base +{ + static constexpr bool IsOpl2 = (Revision == 2); + static constexpr bool IsOpl2Plus = (Revision >= 2); + static constexpr bool IsOpl3Plus = (Revision >= 3); + static constexpr bool IsOpl4Plus = (Revision >= 4); + +public: + // constants + static constexpr uint32_t OUTPUTS = IsOpl3Plus ? 4 : 1; + static constexpr uint32_t CHANNELS = IsOpl3Plus ? 18 : 9; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 2; + static constexpr uint32_t WAVEFORMS = IsOpl3Plus ? 8 : (IsOpl2Plus ? 4 : 1); + static constexpr uint32_t REGISTERS = IsOpl3Plus ? 0x200 : 0x100; + static constexpr uint32_t REG_MODE = 0x04; + static constexpr uint32_t DEFAULT_PRESCALE = IsOpl4Plus ? 19 : (IsOpl3Plus ? 8 : 4); + static constexpr uint32_t EG_CLOCK_DIVIDER = 1; + static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS; + static constexpr bool DYNAMIC_OPS = IsOpl3Plus; + static constexpr bool MODULATOR_DELAY = !IsOpl3Plus; + static constexpr uint8_t STATUS_TIMERA = 0x40; + static constexpr uint8_t STATUS_TIMERB = 0x20; + static constexpr uint8_t STATUS_BUSY = 0; + static constexpr uint8_t STATUS_IRQ = 0x80; + + // constructor + opl_registers_base(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + if (!IsOpl3Plus) + return chnum; + else + return (chnum % 9) + 0x100 * (chnum / 9); + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + if (!IsOpl3Plus) + return opnum + 2 * (opnum / 6); + else + return (opnum % 18) + 2 * ((opnum % 18) / 6) + 0x100 * (opnum / 18); + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // OPL4 apparently can read back FM registers? + uint8_t read(uint16_t index) const { return m_regdata[index]; } + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // reset the LFO + void reset_lfo() { m_lfo_am_counter = m_lfo_pm_counter = 0; } + + // return the AM offset from LFO for the given channel + // on OPL this is just a fixed value + uint32_t lfo_am_offset(uint32_t choffs) const { return m_lfo_am; } + + // return LFO/noise states + uint32_t noise_state() const { return m_noise_lfsr >> 23; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // system-wide registers + uint32_t test() const { return byte(0x01, 0, 8); } + uint32_t waveform_enable() const { return IsOpl2 ? byte(0x01, 5, 1) : (IsOpl3Plus ? 1 : 0); } + uint32_t timer_a_value() const { return byte(0x02, 0, 8) * 4; } // 8->10 bits + uint32_t timer_b_value() const { return byte(0x03, 0, 8); } + uint32_t status_mask() const { return byte(0x04, 0, 8) & 0x78; } + uint32_t irq_reset() const { return byte(0x04, 7, 1); } + uint32_t reset_timer_b() const { return byte(0x04, 7, 1) | byte(0x04, 5, 1); } + uint32_t reset_timer_a() const { return byte(0x04, 7, 1) | byte(0x04, 6, 1); } + uint32_t enable_timer_b() const { return 1; } + uint32_t enable_timer_a() const { return 1; } + uint32_t load_timer_b() const { return byte(0x04, 1, 1); } + uint32_t load_timer_a() const { return byte(0x04, 0, 1); } + uint32_t csm() const { return IsOpl3Plus ? 0 : byte(0x08, 7, 1); } + uint32_t note_select() const { return byte(0x08, 6, 1); } + uint32_t lfo_am_depth() const { return byte(0xbd, 7, 1); } + uint32_t lfo_pm_depth() const { return byte(0xbd, 6, 1); } + uint32_t rhythm_enable() const { return byte(0xbd, 5, 1); } + uint32_t rhythm_keyon() const { return byte(0xbd, 4, 0); } + uint32_t newflag() const { return IsOpl3Plus ? byte(0x105, 0, 1) : 0; } + uint32_t new2flag() const { return IsOpl4Plus ? byte(0x105, 1, 1) : 0; } + uint32_t fourop_enable() const { return IsOpl3Plus ? byte(0x104, 0, 6) : 0; } + + // per-channel registers + uint32_t ch_block_freq(uint32_t choffs) const { return word(0xb0, 0, 5, 0xa0, 0, 8, choffs); } + uint32_t ch_feedback(uint32_t choffs) const { return byte(0xc0, 1, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return byte(0xc0, 0, 1, choffs) | (IsOpl3Plus ? (8 | (byte(0xc3, 0, 1, choffs) << 1)) : 0); } + uint32_t ch_output_any(uint32_t choffs) const { return newflag() ? byte(0xc0 + choffs, 4, 4) : 1; } + uint32_t ch_output_0(uint32_t choffs) const { return newflag() ? byte(0xc0 + choffs, 4, 1) : 1; } + uint32_t ch_output_1(uint32_t choffs) const { return newflag() ? byte(0xc0 + choffs, 5, 1) : (IsOpl3Plus ? 1 : 0); } + uint32_t ch_output_2(uint32_t choffs) const { return newflag() ? byte(0xc0 + choffs, 6, 1) : 0; } + uint32_t ch_output_3(uint32_t choffs) const { return newflag() ? byte(0xc0 + choffs, 7, 1) : 0; } + + // per-operator registers + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return byte(0x20, 7, 1, opoffs); } + uint32_t op_lfo_pm_enable(uint32_t opoffs) const { return byte(0x20, 6, 1, opoffs); } + uint32_t op_eg_sustain(uint32_t opoffs) const { return byte(0x20, 5, 1, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return byte(0x20, 4, 1, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return byte(0x20, 0, 4, opoffs); } + uint32_t op_ksl(uint32_t opoffs) const { uint32_t temp = byte(0x40, 6, 2, opoffs); return bitfield(temp, 1) | (bitfield(temp, 0) << 1); } + uint32_t op_total_level(uint32_t opoffs) const { return byte(0x40, 0, 6, opoffs); } + uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x60, 4, 4, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return byte(0x60, 0, 4, opoffs); } + uint32_t op_sustain_level(uint32_t opoffs) const { return byte(0x80, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return byte(0x80, 0, 4, opoffs); } + uint32_t op_waveform(uint32_t opoffs) const { return IsOpl2Plus ? byte(0xe0, 0, newflag() ? 3 : 2, opoffs) : 0; } + +protected: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // helper to determine if the this channel is an active rhythm channel + bool is_rhythm(uint32_t choffs) const + { + return rhythm_enable() && (choffs >= 6 && choffs <= 8); + } + + // internal state + uint16_t m_lfo_am_counter; // LFO AM counter + uint16_t m_lfo_pm_counter; // LFO PM counter + uint32_t m_noise_lfsr; // noise LFSR state + uint8_t m_lfo_am; // current LFO AM value + uint8_t m_regdata[REGISTERS]; // register data + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + +using opl_registers = opl_registers_base<1>; +using opl2_registers = opl_registers_base<2>; +using opl3_registers = opl_registers_base<3>; +using opl4_registers = opl_registers_base<4>; + + + +// ======================> opll_registers + +// +// OPLL register map: +// +// System-wide registers: +// 0E --x----- Rhythm enable +// ---x---- Bass drum key on +// ----x--- Snare drum key on +// -----x-- Tom key on +// ------x- Top cymbal key on +// -------x High hat key on +// 0F xxxxxxxx Test register +// +// Per-channel registers (channel in address bits 0-3) +// 10-18 xxxxxxxx F-number (low 8 bits) +// 20-28 --x----- Sustain on +// ---x---- Key on +// --- xxx- Block (octvate, 0-7) +// -------x F-number (high bit) +// 30-38 xxxx---- Instrument selection +// ----xxxx Volume +// +// User instrument registers (for carrier, modulator operators) +// 00-01 x------- AM enable +// -x------ PM enable (VIB) +// --x----- EG type +// ---x---- Key scale rate +// ----xxxx Multiple value (0-15) +// 02 xx------ Key scale level (carrier, 0-3) +// --xxxxxx Total level (modulator, 0-63) +// 03 xx------ Key scale level (modulator, 0-3) +// ---x---- Rectified wave (carrier) +// ----x--- Rectified wave (modulator) +// -----xxx Feedback level for operator 1 (0-7) +// 04-05 xxxx---- Attack rate (0-15) +// ----xxxx Decay rate (0-15) +// 06-07 xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// +// Internal (fake) registers: +// 40-48 xxxxxxxx Current instrument base address +// 4E-5F xxxxxxxx Current instrument base address + operator slot (0/1) +// 70-FF xxxxxxxx Data for instruments (1-16 plus 3 drums) +// + +class opll_registers : public fm_registers_base +{ +public: + static constexpr uint32_t OUTPUTS = 2; + static constexpr uint32_t CHANNELS = 9; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 2; + static constexpr uint32_t WAVEFORMS = 2; + static constexpr uint32_t REGISTERS = 0x40; + static constexpr uint32_t REG_MODE = 0x3f; + static constexpr uint32_t DEFAULT_PRESCALE = 4; + static constexpr uint32_t EG_CLOCK_DIVIDER = 1; + static constexpr uint32_t CSM_TRIGGER_MASK = 0; + static constexpr bool EG_HAS_DEPRESS = true; + static constexpr bool MODULATOR_DELAY = true; + static constexpr uint8_t STATUS_TIMERA = 0; + static constexpr uint8_t STATUS_TIMERB = 0; + static constexpr uint8_t STATUS_BUSY = 0; + static constexpr uint8_t STATUS_IRQ = 0; + + // OPLL-specific constants + static constexpr uint32_t INSTDATA_SIZE = 0x90; + + // constructor + opll_registers(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + return chnum; + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + return opnum; + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // read a register value + uint8_t read(uint16_t index) const { return m_regdata[index]; } + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // reset the LFO + void reset_lfo() { m_lfo_am_counter = m_lfo_pm_counter = 0; } + + // return the AM offset from LFO for the given channel + // on OPL this is just a fixed value + uint32_t lfo_am_offset(uint32_t choffs) const { return m_lfo_am; } + + // return LFO/noise states + uint32_t noise_state() const { return m_noise_lfsr >> 23; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // set the instrument data + void set_instrument_data(uint8_t const *data) + { + std::copy_n(data, INSTDATA_SIZE, &m_instdata[0]); + } + + // system-wide registers + uint32_t rhythm_enable() const { return byte(0x0e, 5, 1); } + uint32_t rhythm_keyon() const { return byte(0x0e, 4, 0); } + uint32_t test() const { return byte(0x0f, 0, 8); } + uint32_t waveform_enable() const { return 1; } + uint32_t timer_a_value() const { return 0; } + uint32_t timer_b_value() const { return 0; } + uint32_t status_mask() const { return 0; } + uint32_t irq_reset() const { return 0; } + uint32_t reset_timer_b() const { return 0; } + uint32_t reset_timer_a() const { return 0; } + uint32_t enable_timer_b() const { return 0; } + uint32_t enable_timer_a() const { return 0; } + uint32_t load_timer_b() const { return 0; } + uint32_t load_timer_a() const { return 0; } + uint32_t csm() const { return 0; } + + // per-channel registers + uint32_t ch_block_freq(uint32_t choffs) const { return word(0x20, 0, 4, 0x10, 0, 8, choffs); } + uint32_t ch_sustain(uint32_t choffs) const { return byte(0x20, 5, 1, choffs); } + uint32_t ch_total_level(uint32_t choffs) const { return instchbyte(0x02, 0, 6, choffs); } + uint32_t ch_feedback(uint32_t choffs) const { return instchbyte(0x03, 0, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return 0; } + uint32_t ch_instrument(uint32_t choffs) const { return byte(0x30, 4, 4, choffs); } + uint32_t ch_output_any(uint32_t choffs) const { return 1; } + uint32_t ch_output_0(uint32_t choffs) const { return !is_rhythm(choffs); } + uint32_t ch_output_1(uint32_t choffs) const { return is_rhythm(choffs); } + uint32_t ch_output_2(uint32_t choffs) const { return 0; } + uint32_t ch_output_3(uint32_t choffs) const { return 0; } + + // per-operator registers + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return instopbyte(0x00, 7, 1, opoffs); } + uint32_t op_lfo_pm_enable(uint32_t opoffs) const { return instopbyte(0x00, 6, 1, opoffs); } + uint32_t op_eg_sustain(uint32_t opoffs) const { return instopbyte(0x00, 5, 1, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return instopbyte(0x00, 4, 1, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return instopbyte(0x00, 0, 4, opoffs); } + uint32_t op_ksl(uint32_t opoffs) const { return instopbyte(0x02, 6, 2, opoffs); } + uint32_t op_waveform(uint32_t opoffs) const { return instchbyte(0x03, 3 + bitfield(opoffs, 0), 1, opoffs >> 1); } + uint32_t op_attack_rate(uint32_t opoffs) const { return instopbyte(0x04, 4, 4, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return instopbyte(0x04, 0, 4, opoffs); } + uint32_t op_sustain_level(uint32_t opoffs) const { return instopbyte(0x06, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return instopbyte(0x06, 0, 4, opoffs); } + uint32_t op_volume(uint32_t opoffs) const { return byte(0x30, 4 * bitfield(~opoffs, 0), 4, opoffs >> 1); } + +private: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // helpers to read from instrument channel/operator data + uint32_t instchbyte(uint32_t offset, uint32_t start, uint32_t count, uint32_t choffs) const { return bitfield(m_chinst[choffs][offset], start, count); } + uint32_t instopbyte(uint32_t offset, uint32_t start, uint32_t count, uint32_t opoffs) const { return bitfield(m_opinst[opoffs][offset], start, count); } + + // helper to determine if the this channel is an active rhythm channel + bool is_rhythm(uint32_t choffs) const + { + return rhythm_enable() && choffs >= 6; + } + + // internal state + uint16_t m_lfo_am_counter; // LFO AM counter + uint16_t m_lfo_pm_counter; // LFO PM counter + uint32_t m_noise_lfsr; // noise LFSR state + uint8_t m_lfo_am; // current LFO AM value + uint8_t const *m_chinst[CHANNELS]; // pointer to instrument data for each channel + uint8_t const *m_opinst[OPERATORS]; // pointer to instrument data for each operator + uint8_t m_regdata[REGISTERS]; // register data + uint8_t m_instdata[INSTDATA_SIZE]; // instrument data + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + + + +//********************************************************* +// OPL IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym3526 + +class ym3526 +{ +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + + // constructor + ym3526(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); +protected: + // internal state + uint8_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + + +// ======================> y8950 + +class y8950 +{ +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + + static constexpr uint8_t STATUS_ADPCM_B_PLAYING = 0x01; + static constexpr uint8_t STATUS_ADPCM_B_BRDY = 0x08; + static constexpr uint8_t STATUS_ADPCM_B_EOS = 0x10; + static constexpr uint8_t ALL_IRQS = STATUS_ADPCM_B_BRDY | STATUS_ADPCM_B_EOS | fm_engine::STATUS_TIMERA | fm_engine::STATUS_TIMERB; + + // constructor + y8950(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint8_t m_address; // address register + uint8_t m_io_ddr; // data direction register for I/O + fm_engine m_fm; // core FM engine + adpcm_b_engine m_adpcm_b; // ADPCM-B engine +}; + + + +//********************************************************* +// OPL2 IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym3812 + +class ym3812 +{ +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + + // constructor + ym3812(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint8_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + + + +//********************************************************* +// OPL3 IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ymf262 + +class ymf262 +{ +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + + // constructor + ymf262(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint16_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + + +// ======================> ymf289b + +class ymf289b +{ + static constexpr uint8_t STATUS_BUSY_FLAGS = 0x05; + +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = 2; + + // constructor + ymf289b(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal helpers + bool ymf289b_mode() { return ((m_fm.regs().read(0x105) & 0x04) != 0); } + + // internal state + uint16_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + + + +//********************************************************* +// OPL4 IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ymf278b + +class ymf278b +{ + // Using the nominal datasheet frequency of 33.868MHz, the output of the + // chip will be clock/768 = 44.1kHz. However, the FM engine is clocked + // internally at clock/(19*36), or 49.515kHz, so the FM output needs to + // be downsampled. We treat this as needing to clock the FM engine an + // extra tick every few samples. The exact ratio is 768/(19*36) or + // 768/684 = 192/171. So if we always clock the FM once, we'll have + // 192/171 - 1 = 21/171 left. Thus we count 21 for each sample and when + // it gets above 171, we tick an extra time. + static constexpr uint32_t FM_EXTRA_SAMPLE_THRESH = 171; + static constexpr uint32_t FM_EXTRA_SAMPLE_STEP = 192 - FM_EXTRA_SAMPLE_THRESH; + +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t OUTPUTS = 6; + using output_data = ymfm_output; + + static constexpr uint8_t STATUS_BUSY = 0x01; + static constexpr uint8_t STATUS_LD = 0x02; + + // constructor + ymf278b(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return input_clock / 768; } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data_pcm(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write_address_pcm(uint8_t data); + void write_data_pcm(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint16_t m_address; // address register + uint32_t m_fm_pos; // FM resampling position + uint32_t m_load_remaining; // how many more samples until LD flag clears + bool m_next_status_id; // flag to track which status ID to return + fm_engine m_fm; // core FM engine + pcm_engine m_pcm; // core PCM engine +}; + + + +//********************************************************* +// OPLL IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> opll_base + +class opll_base +{ +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + + // constructor + opll_base(ymfm_interface &intf, uint8_t const *data); + + // configuration + void set_instrument_data(uint8_t const *data) { m_fm.regs().set_instrument_data(data); } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access -- doesn't really have any, but provide these for consistency + uint8_t read_status() { return 0x00; } + uint8_t read(uint32_t offset) { return 0x00; } + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate samples of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint8_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + + +// ======================> ym2413 + +class ym2413 : public opll_base +{ +public: + // constructor + ym2413(ymfm_interface &intf, uint8_t const *instrument_data = nullptr); + +private: + // internal state + static uint8_t const s_default_instruments[]; +}; + + +// ======================> ym2413 + +class ym2423 : public opll_base +{ +public: + // constructor + ym2423(ymfm_interface &intf, uint8_t const *instrument_data = nullptr); + +private: + // internal state + static uint8_t const s_default_instruments[]; +}; + + +// ======================> ymf281 + +class ymf281 : public opll_base +{ +public: + // constructor + ymf281(ymfm_interface &intf, uint8_t const *instrument_data = nullptr); + +private: + // internal state + static uint8_t const s_default_instruments[]; +}; + + +// ======================> ds1001 + +class ds1001 : public opll_base +{ +public: + // constructor + ds1001(ymfm_interface &intf, uint8_t const *instrument_data = nullptr); + +private: + // internal state + static uint8_t const s_default_instruments[]; +}; + +} + +#endif // YMFM_OPL_H diff --git a/src/sound/ymfm/ymfm_opm.cpp b/src/sound/ymfm/ymfm_opm.cpp new file mode 100644 index 000000000..544bbe89a --- /dev/null +++ b/src/sound/ymfm/ymfm_opm.cpp @@ -0,0 +1,539 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_opm.h" +#include "ymfm_fm.ipp" + +namespace ymfm +{ + +//********************************************************* +// OPM REGISTERS +//********************************************************* + +//------------------------------------------------- +// opm_registers - constructor +//------------------------------------------------- + +opm_registers::opm_registers() : + m_lfo_counter(0), + m_noise_lfsr(1), + m_noise_counter(0), + m_noise_state(0), + m_noise_lfo(0), + m_lfo_am(0) +{ + // create the waveforms + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[0][index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); + + // create the LFO waveforms; AM in the low 8 bits, PM in the upper 8 + // waveforms are adjusted to match the pictures in the application manual + for (uint32_t index = 0; index < LFO_WAVEFORM_LENGTH; index++) + { + // waveform 0 is a sawtooth + uint8_t am = index ^ 0xff; + int8_t pm = int8_t(index); + m_lfo_waveform[0][index] = am | (pm << 8); + + // waveform 1 is a square wave + am = bitfield(index, 7) ? 0 : 0xff; + pm = int8_t(am ^ 0x80); + m_lfo_waveform[1][index] = am | (pm << 8); + + // waveform 2 is a triangle wave + am = bitfield(index, 7) ? (index << 1) : ((index ^ 0xff) << 1); + pm = int8_t(bitfield(index, 6) ? am : ~am); + m_lfo_waveform[2][index] = am | (pm << 8); + + // waveform 3 is noise; it is filled in dynamically + m_lfo_waveform[3][index] = 0; + } +} + + +//------------------------------------------------- +// reset - reset to initial state +//------------------------------------------------- + +void opm_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + + // enable output on both channels by default + m_regdata[0x20] = m_regdata[0x21] = m_regdata[0x22] = m_regdata[0x23] = 0xc0; + m_regdata[0x24] = m_regdata[0x25] = m_regdata[0x26] = m_regdata[0x27] = 0xc0; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void opm_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_lfo_counter); + state.save_restore(m_lfo_am); + state.save_restore(m_noise_lfsr); + state.save_restore(m_noise_counter); + state.save_restore(m_noise_state); + state.save_restore(m_noise_lfo); + state.save_restore(m_regdata); +} + + +//------------------------------------------------- +// operator_map - return an array of operator +// indices for each channel; for OPM this is fixed +//------------------------------------------------- + +void opm_registers::operator_map(operator_mapping &dest) const +{ + // Note that the channel index order is 0,2,1,3, so we bitswap the index. + // + // This is because the order in the map is: + // carrier 1, carrier 2, modulator 1, modulator 2 + // + // But when wiring up the connections, the more natural order is: + // carrier 1, modulator 1, carrier 2, modulator 2 + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 16, 8, 24 ), // Channel 0 operators + operator_list( 1, 17, 9, 25 ), // Channel 1 operators + operator_list( 2, 18, 10, 26 ), // Channel 2 operators + operator_list( 3, 19, 11, 27 ), // Channel 3 operators + operator_list( 4, 20, 12, 28 ), // Channel 4 operators + operator_list( 5, 21, 13, 29 ), // Channel 5 operators + operator_list( 6, 22, 14, 30 ), // Channel 6 operators + operator_list( 7, 23, 15, 31 ), // Channel 7 operators + } }; + dest = s_fixed_map; +} + + +//------------------------------------------------- +// write - handle writes to the register array +//------------------------------------------------- + +bool opm_registers::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) +{ + assert(index < REGISTERS); + + // LFO AM/PM depth are written to the same register (0x19); + // redirect the PM depth to an unused neighbor (0x1a) + if (index == 0x19) + m_regdata[index + bitfield(data, 7)] = data; + else if (index != 0x1a) + m_regdata[index] = data; + + // handle writes to the key on index + if (index == 0x08) + { + channel = bitfield(data, 0, 3); + opmask = bitfield(data, 3, 4); + return true; + } + return false; +} + + +//------------------------------------------------- +// clock_noise_and_lfo - clock the noise and LFO, +// handling clock division, depth, and waveform +// computations +//------------------------------------------------- + +int32_t opm_registers::clock_noise_and_lfo() +{ + // base noise frequency is measured at 2x 1/2 FM frequency; this + // means each tick counts as two steps against the noise counter + uint32_t freq = noise_frequency(); + for (int rep = 0; rep < 2; rep++) + { + // evidence seems to suggest the LFSR is clocked continually and just + // sampled at the noise frequency for output purposes; note that the + // low 8 bits are the most recent 8 bits of history while bits 8-24 + // contain the 17 bit LFSR state + m_noise_lfsr <<= 1; + m_noise_lfsr |= bitfield(m_noise_lfsr, 17) ^ bitfield(m_noise_lfsr, 14) ^ 1; + + // compare against the frequency and latch when we exceed it + if (m_noise_counter++ >= freq) + { + m_noise_counter = 0; + m_noise_state = bitfield(m_noise_lfsr, 17); + } + } + + // treat the rate as a 4.4 floating-point step value with implied + // leading 1; this matches exactly the frequencies in the application + // manual, though it might not be implemented exactly this way on chip + uint32_t rate = lfo_rate(); + m_lfo_counter += (0x10 | bitfield(rate, 0, 4)) << bitfield(rate, 4, 4); + + // bit 1 of the test register is officially undocumented but has been + // discovered to hold the LFO in reset while active + if (lfo_reset()) + m_lfo_counter = 0; + + // now pull out the non-fractional LFO value + uint32_t lfo = bitfield(m_lfo_counter, 22, 8); + + // fill in the noise entry 1 ahead of our current position; this + // ensures the current value remains stable for a full LFO clock + // and effectively latches the running value when the LFO advances + uint32_t lfo_noise = bitfield(m_noise_lfsr, 17, 8); + m_lfo_waveform[3][(lfo + 1) & 0xff] = lfo_noise | (lfo_noise << 8); + + // fetch the AM/PM values based on the waveform; AM is unsigned and + // encoded in the low 8 bits, while PM signed and encoded in the upper + // 8 bits + int32_t ampm = m_lfo_waveform[lfo_waveform()][lfo]; + + // apply depth to the AM value and store for later + m_lfo_am = ((ampm & 0xff) * lfo_am_depth()) >> 7; + + // apply depth to the PM value and return it + return ((ampm >> 8) * int32_t(lfo_pm_depth())) >> 7; +} + + +//------------------------------------------------- +// lfo_am_offset - return the AM offset from LFO +// for the given channel +//------------------------------------------------- + +uint32_t opm_registers::lfo_am_offset(uint32_t choffs) const +{ + // OPM maps AM quite differently from OPN + + // shift value for AM sensitivity is [*, 0, 1, 2], + // mapping to values of [0, 23.9, 47.8, and 95.6dB] + uint32_t am_sensitivity = ch_lfo_am_sens(choffs); + if (am_sensitivity == 0) + return 0; + + // QUESTION: see OPN note below for the dB range mapping; it applies + // here as well + + // raw LFO AM value on OPM is 0-FF, which is already a factor of 2 + // larger than the OPN below, putting our staring point at 2x theirs; + // this works out since our minimum is 2x their maximum + return m_lfo_am << (am_sensitivity - 1); +} + + +//------------------------------------------------- +// cache_operator_data - fill the operator cache +// with prefetched data +//------------------------------------------------- + +void opm_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) +{ + // set up the easy stuff + cache.waveform = &m_waveform[0][0]; + + // get frequency from the channel + uint32_t block_freq = cache.block_freq = ch_block_freq(choffs); + + // compute the keycode: block_freq is: + // + // BBBCCCCFFFFFF + // ^^^^^ + // + // the 5-bit keycode is just the top 5 bits (block + top 2 bits + // of the key code) + uint32_t keycode = bitfield(block_freq, 8, 5); + + // detune adjustment + cache.detune = detune_adjustment(op_detune(opoffs), keycode); + + // multiple value, as an x.1 value (0 means 0.5) + cache.multiple = op_multiple(opoffs) * 2; + if (cache.multiple == 0) + cache.multiple = 1; + + // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on + // block_freq, detune, and multiple, so compute it after we've done those + if (lfo_pm_depth() == 0 || ch_lfo_pm_sens(choffs) == 0) + cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0); + else + cache.phase_step = opdata_cache::PHASE_STEP_DYNAMIC; + + // total level, scaled by 8 + cache.total_level = op_total_level(opoffs) << 3; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = op_sustain_level(opoffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // determine KSR adjustment for enevlope rates + uint32_t ksrval = keycode >> (op_ksr(opoffs) ^ 3); + cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval); +} + + +//------------------------------------------------- +// compute_phase_step - compute the phase step +//------------------------------------------------- + +uint32_t opm_registers::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm) +{ + // OPM logic is rather unique here, due to extra detune + // and the use of key codes (not to be confused with keycode) + + // start with coarse detune delta; table uses cents value from + // manual, converted into 1/64ths + static const int16_t s_detune2_delta[4] = { 0, (600*64+50)/100, (781*64+50)/100, (950*64+50)/100 }; + int32_t delta = s_detune2_delta[op_detune2(opoffs)]; + + // add in the PM delta + uint32_t pm_sensitivity = ch_lfo_pm_sens(choffs); + if (pm_sensitivity != 0) + { + // raw PM value is -127..128 which is +/- 200 cents + // manual gives these magnitudes in cents: + // 0, +/-5, +/-10, +/-20, +/-50, +/-100, +/-400, +/-700 + // this roughly corresponds to shifting the 200-cent value: + // 0 >> 5, >> 4, >> 3, >> 2, >> 1, << 1, << 2 + if (pm_sensitivity < 6) + delta += lfo_raw_pm >> (6 - pm_sensitivity); + else + delta += lfo_raw_pm << (pm_sensitivity - 5); + } + + // apply delta and convert to a frequency number + uint32_t phase_step = opm_key_code_to_phase_step(cache.block_freq, delta); + + // apply detune based on the keycode + phase_step += cache.detune; + + // apply frequency multiplier (which is cached as an x.1 value) + return (phase_step * cache.multiple) >> 1; +} + + +//------------------------------------------------- +// log_keyon - log a key-on event +//------------------------------------------------- + +std::string opm_registers::log_keyon(uint32_t choffs, uint32_t opoffs) +{ + uint32_t chnum = choffs; + uint32_t opnum = opoffs; + + char buffer[256]; + char *end = &buffer[0]; + + end += sprintf(end, "%u.%02u freq=%04X dt2=%u dt=%u fb=%u alg=%X mul=%X tl=%02X ksr=%u adsr=%02X/%02X/%02X/%X sl=%X out=%c%c", + chnum, opnum, + ch_block_freq(choffs), + op_detune2(opoffs), + op_detune(opoffs), + ch_feedback(choffs), + ch_algorithm(choffs), + op_multiple(opoffs), + op_total_level(opoffs), + op_ksr(opoffs), + op_attack_rate(opoffs), + op_decay_rate(opoffs), + op_sustain_rate(opoffs), + op_release_rate(opoffs), + op_sustain_level(opoffs), + ch_output_0(choffs) ? 'L' : '-', + ch_output_1(choffs) ? 'R' : '-'); + + bool am = (lfo_am_depth() != 0 && ch_lfo_am_sens(choffs) != 0 && op_lfo_am_enable(opoffs) != 0); + if (am) + end += sprintf(end, " am=%u/%02X", ch_lfo_am_sens(choffs), lfo_am_depth()); + bool pm = (lfo_pm_depth() != 0 && ch_lfo_pm_sens(choffs) != 0); + if (pm) + end += sprintf(end, " pm=%u/%02X", ch_lfo_pm_sens(choffs), lfo_pm_depth()); + if (am || pm) + end += sprintf(end, " lfo=%02X/%c", lfo_rate(), "WQTN"[lfo_waveform()]); + if (noise_enable() && opoffs == 31) + end += sprintf(end, " noise=1"); + + return buffer; +} + + + +//********************************************************* +// YM2151 +//********************************************************* + +//------------------------------------------------- +// ym2151 - constructor +//------------------------------------------------- + +ym2151::ym2151(ymfm_interface &intf, opm_variant variant) : + m_variant(variant), + m_address(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2151::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2151::save_restore(ymfm_saved_state &state) +{ + m_fm.save_restore(state); + state.save_restore(m_address); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym2151::read_status() +{ + uint8_t result = m_fm.status(); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2151::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 1) + { + case 0: // data port (unused) + debug::log_unexpected_read_write("Unexpected read from YM2151 offset %d\n", offset & 3); + break; + + case 1: // status port, YM2203 compatible + result = read_status(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2151::write_address(uint8_t data) +{ + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2151::write_data(uint8_t data) +{ + // write the FM register + m_fm.write(m_address, data); + + // special cases + if (m_address == 0x1b) + { + // writes to register 0x1B send the upper 2 bits to the output lines + m_fm.intf().ymfm_external_write(ACCESS_IO, 0, data >> 6); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2151::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym2151::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; OPM is full 14-bit with no intermediate clipping + m_fm.output(output->clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // YM2151 uses an external DAC (YM3012) with mantissa/exponent format + // convert to 10.3 floating point value and back to simulate truncation + output->roundtrip_fp(); + } +} + +} diff --git a/src/sound/ymfm/ymfm_opm.h b/src/sound/ymfm/ymfm_opm.h new file mode 100644 index 000000000..b126135d4 --- /dev/null +++ b/src/sound/ymfm/ymfm_opm.h @@ -0,0 +1,322 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_OPM_H +#define YMFM_OPM_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_fm.h" + +namespace ymfm +{ + +//********************************************************* +// REGISTER CLASSES +//********************************************************* + +// ======================> opm_registers + +// +// OPM register map: +// +// System-wide registers: +// 01 xxxxxx-x Test register +// ------x- LFO reset +// 08 -x------ Key on/off operator 4 +// --x----- Key on/off operator 3 +// ---x---- Key on/off operator 2 +// ----x--- Key on/off operator 1 +// -----xxx Channel select +// 0F x------- Noise enable +// ---xxxxx Noise frequency +// 10 xxxxxxxx Timer A value (upper 8 bits) +// 11 ------xx Timer A value (lower 2 bits) +// 12 xxxxxxxx Timer B value +// 14 x------- CSM mode +// --x----- Reset timer B +// ---x---- Reset timer A +// ----x--- Enable timer B +// -----x-- Enable timer A +// ------x- Load timer B +// -------x Load timer A +// 18 xxxxxxxx LFO frequency +// 19 0xxxxxxx AM LFO depth +// 1xxxxxxx PM LFO depth +// 1B xx------ CT (2 output data lines) +// ------xx LFO waveform +// +// Per-channel registers (channel in address bits 0-2) +// 20-27 x------- Pan right +// -x------ Pan left +// --xxx--- Feedback level for operator 1 (0-7) +// -----xxx Operator connection algorithm (0-7) +// 28-2F -xxxxxxx Key code +// 30-37 xxxxxx-- Key fraction +// 38-3F -xxx---- LFO PM sensitivity +// ------xx LFO AM shift +// +// Per-operator registers (channel in address bits 0-2, operator in bits 3-4) +// 40-5F -xxx---- Detune value (0-7) +// ----xxxx Multiple value (0-15) +// 60-7F -xxxxxxx Total level (0-127) +// 80-9F xx------ Key scale rate (0-3) +// ---xxxxx Attack rate (0-31) +// A0-BF x------- LFO AM enable +// ---xxxxx Decay rate (0-31) +// C0-DF xx------ Detune 2 value (0-3) +// ---xxxxx Sustain rate (0-31) +// E0-FF xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// +// Internal (fake) registers: +// 1A -xxxxxxx PM depth +// + +class opm_registers : public fm_registers_base +{ + // LFO waveforms are 256 entries long + static constexpr uint32_t LFO_WAVEFORM_LENGTH = 256; + +public: + // constants + static constexpr uint32_t OUTPUTS = 2; + static constexpr uint32_t CHANNELS = 8; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 4; + static constexpr uint32_t WAVEFORMS = 1; + static constexpr uint32_t REGISTERS = 0x100; + static constexpr uint32_t DEFAULT_PRESCALE = 2; + static constexpr uint32_t EG_CLOCK_DIVIDER = 3; + static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS; + static constexpr uint32_t REG_MODE = 0x14; + static constexpr uint8_t STATUS_TIMERA = 0x01; + static constexpr uint8_t STATUS_TIMERB = 0x02; + static constexpr uint8_t STATUS_BUSY = 0x80; + static constexpr uint8_t STATUS_IRQ = 0; + + // constructor + opm_registers(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + return chnum; + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + return opnum; + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // return the AM offset from LFO for the given channel + uint32_t lfo_am_offset(uint32_t choffs) const; + + // return the current noise state, gated by the noise clock + uint32_t noise_state() const { return m_noise_state; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // system-wide registers + uint32_t test() const { return byte(0x01, 0, 8); } + uint32_t lfo_reset() const { return byte(0x01, 1, 1); } + uint32_t noise_frequency() const { return byte(0x0f, 0, 5) ^ 0x1f; } + uint32_t noise_enable() const { return byte(0x0f, 7, 1); } + uint32_t timer_a_value() const { return word(0x10, 0, 8, 0x11, 0, 2); } + uint32_t timer_b_value() const { return byte(0x12, 0, 8); } + uint32_t csm() const { return byte(0x14, 7, 1); } + uint32_t reset_timer_b() const { return byte(0x14, 5, 1); } + uint32_t reset_timer_a() const { return byte(0x14, 4, 1); } + uint32_t enable_timer_b() const { return byte(0x14, 3, 1); } + uint32_t enable_timer_a() const { return byte(0x14, 2, 1); } + uint32_t load_timer_b() const { return byte(0x14, 1, 1); } + uint32_t load_timer_a() const { return byte(0x14, 0, 1); } + uint32_t lfo_rate() const { return byte(0x18, 0, 8); } + uint32_t lfo_am_depth() const { return byte(0x19, 0, 7); } + uint32_t lfo_pm_depth() const { return byte(0x1a, 0, 7); } + uint32_t output_bits() const { return byte(0x1b, 6, 2); } + uint32_t lfo_waveform() const { return byte(0x1b, 0, 2); } + + // per-channel registers + uint32_t ch_output_any(uint32_t choffs) const { return byte(0x20, 6, 2, choffs); } + uint32_t ch_output_0(uint32_t choffs) const { return byte(0x20, 6, 1, choffs); } + uint32_t ch_output_1(uint32_t choffs) const { return byte(0x20, 7, 1, choffs); } + uint32_t ch_output_2(uint32_t choffs) const { return 0; } + uint32_t ch_output_3(uint32_t choffs) const { return 0; } + uint32_t ch_feedback(uint32_t choffs) const { return byte(0x20, 3, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return byte(0x20, 0, 3, choffs); } + uint32_t ch_block_freq(uint32_t choffs) const { return word(0x28, 0, 7, 0x30, 2, 6, choffs); } + uint32_t ch_lfo_pm_sens(uint32_t choffs) const { return byte(0x38, 4, 3, choffs); } + uint32_t ch_lfo_am_sens(uint32_t choffs) const { return byte(0x38, 0, 2, choffs); } + + // per-operator registers + uint32_t op_detune(uint32_t opoffs) const { return byte(0x40, 4, 3, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return byte(0x40, 0, 4, opoffs); } + uint32_t op_total_level(uint32_t opoffs) const { return byte(0x60, 0, 7, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return byte(0x80, 6, 2, opoffs); } + uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x80, 0, 5, opoffs); } + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return byte(0xa0, 7, 1, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return byte(0xa0, 0, 5, opoffs); } + uint32_t op_detune2(uint32_t opoffs) const { return byte(0xc0, 6, 2, opoffs); } + uint32_t op_sustain_rate(uint32_t opoffs) const { return byte(0xc0, 0, 5, opoffs); } + uint32_t op_sustain_level(uint32_t opoffs) const { return byte(0xe0, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return byte(0xe0, 0, 4, opoffs); } + +protected: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // internal state + uint32_t m_lfo_counter; // LFO counter + uint32_t m_noise_lfsr; // noise LFSR state + uint8_t m_noise_counter; // noise counter + uint8_t m_noise_state; // latched noise state + uint8_t m_noise_lfo; // latched LFO noise value + uint8_t m_lfo_am; // current LFO AM value + uint8_t m_regdata[REGISTERS]; // register data + int16_t m_lfo_waveform[4][LFO_WAVEFORM_LENGTH]; // LFO waveforms; AM in low 8, PM in upper 8 + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + + + +//********************************************************* +// OPM IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym2151 + +class ym2151 +{ +public: + using fm_engine = fm_engine_base; + using output_data = fm_engine::output_data; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + + // constructor + ym2151(ymfm_interface &intf) : ym2151(intf, VARIANT_YM2151) { } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // variants + enum opm_variant + { + VARIANT_YM2151, + VARIANT_YM2164 + }; + + // internal constructor + ym2151(ymfm_interface &intf, opm_variant variant); + + // internal state + opm_variant m_variant; // chip variant + uint8_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + + + +//********************************************************* +// OPP IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym2164 + +// the YM2164 is almost 100% functionally identical to the YM2151, except +// it apparently has some mystery registers in the 00-07 range, and timer +// B's frequency is half that of the 2151 +class ym2164 : public ym2151 +{ +public: + // constructor + ym2164(ymfm_interface &intf) : ym2151(intf, VARIANT_YM2164) { } +}; + +} + + +#endif // YMFM_OPM_H diff --git a/src/sound/ymfm/ymfm_opn.cpp b/src/sound/ymfm/ymfm_opn.cpp new file mode 100644 index 000000000..053ad9770 --- /dev/null +++ b/src/sound/ymfm/ymfm_opn.cpp @@ -0,0 +1,2488 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_opn.h" +#include "ymfm_fm.ipp" + +namespace ymfm +{ + +//********************************************************* +// OPN/OPNA REGISTERS +//********************************************************* + +//------------------------------------------------- +// opn_registers_base - constructor +//------------------------------------------------- + +template +opn_registers_base::opn_registers_base() : + m_lfo_counter(0), + m_lfo_am(0) +{ + // create the waveforms + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[0][index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); +} + + +//------------------------------------------------- +// reset - reset to initial state +//------------------------------------------------- + +template +void opn_registers_base::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + if (IsOpnA) + { + // enable output on both channels by default + m_regdata[0xb4] = m_regdata[0xb5] = m_regdata[0xb6] = 0xc0; + m_regdata[0x1b4] = m_regdata[0x1b5] = m_regdata[0x1b6] = 0xc0; + } +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +template +void opn_registers_base::save_restore(ymfm_saved_state &state) +{ + if (IsOpnA) + { + state.save_restore(m_lfo_counter); + state.save_restore(m_lfo_am); + } + state.save_restore(m_regdata); +} + + +//------------------------------------------------- +// operator_map - return an array of operator +// indices for each channel; for OPN this is fixed +//------------------------------------------------- + +template<> +void opn_registers_base::operator_map(operator_mapping &dest) const +{ + // Note that the channel index order is 0,2,1,3, so we bitswap the index. + // + // This is because the order in the map is: + // carrier 1, carrier 2, modulator 1, modulator 2 + // + // But when wiring up the connections, the more natural order is: + // carrier 1, modulator 1, carrier 2, modulator 2 + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 6, 3, 9 ), // Channel 0 operators + operator_list( 1, 7, 4, 10 ), // Channel 1 operators + operator_list( 2, 8, 5, 11 ), // Channel 2 operators + } }; + dest = s_fixed_map; +} + +template<> +void opn_registers_base::operator_map(operator_mapping &dest) const +{ + // Note that the channel index order is 0,2,1,3, so we bitswap the index. + // + // This is because the order in the map is: + // carrier 1, carrier 2, modulator 1, modulator 2 + // + // But when wiring up the connections, the more natural order is: + // carrier 1, modulator 1, carrier 2, modulator 2 + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 6, 3, 9 ), // Channel 0 operators + operator_list( 1, 7, 4, 10 ), // Channel 1 operators + operator_list( 2, 8, 5, 11 ), // Channel 2 operators + operator_list( 12, 18, 15, 21 ), // Channel 3 operators + operator_list( 13, 19, 16, 22 ), // Channel 4 operators + operator_list( 14, 20, 17, 23 ), // Channel 5 operators + } }; + dest = s_fixed_map; +} + + +//------------------------------------------------- +// write - handle writes to the register array +//------------------------------------------------- + +template +bool opn_registers_base::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) +{ + assert(index < REGISTERS); + + // writes in the 0xa0-af/0x1a0-af region are handled as latched pairs + // borrow unused registers 0xb8-bf/0x1b8-bf as temporary holding locations + if ((index & 0xf0) == 0xa0) + { + if (bitfield(index, 0, 2) == 3) + return false; + + uint32_t latchindex = 0xb8 | bitfield(index, 3); + if (IsOpnA) + latchindex |= index & 0x100; + + // writes to the upper half just latch (only low 6 bits matter) + if (bitfield(index, 2)) + m_regdata[latchindex] = data | 0x80; + + // writes to the lower half only commit if the latch is there + else if (bitfield(m_regdata[latchindex], 7)) + { + m_regdata[index] = data; + m_regdata[index | 4] = m_regdata[latchindex] & 0x3f; + m_regdata[latchindex] = 0; + } + return false; + } + else if ((index & 0xf8) == 0xb8) + { + // registers 0xb8-0xbf are used internally + return false; + } + + // everything else is normal + m_regdata[index] = data; + + // handle writes to the key on index + if (index == 0x28) + { + channel = bitfield(data, 0, 2); + if (channel == 3) + return false; + if (IsOpnA) + channel += bitfield(data, 2, 1) * 3; + opmask = bitfield(data, 4, 4); + return true; + } + return false; +} + + +//------------------------------------------------- +// clock_noise_and_lfo - clock the noise and LFO, +// handling clock division, depth, and waveform +// computations +//------------------------------------------------- + +template +int32_t opn_registers_base::clock_noise_and_lfo() +{ + // OPN has no noise generation + + // if LFO not enabled (not present on OPN), quick exit with 0s + if (!IsOpnA || !lfo_enable()) + { + m_lfo_counter = 0; + + // special case: if LFO is disabled on OPNA, it basically just keeps the counter + // at 0; since position 0 gives an AM value of 0x3f, it is important to reflect + // that here; for example, MegaDrive Venom plays some notes with LFO globally + // disabled but enabling LFO on the operators, and it expects this added attenutation + m_lfo_am = IsOpnA ? 0x3f : 0x00; + return 0; + } + + // this table is based on converting the frequencies in the applications + // manual to clock dividers, based on the assumption of a 7-bit LFO value + static uint8_t const lfo_max_count[8] = { 109, 78, 72, 68, 63, 45, 9, 6 }; + uint32_t subcount = uint8_t(m_lfo_counter++); + + // when we cross the divider count, add enough to zero it and cause an + // increment at bit 8; the 7-bit value lives from bits 8-14 + if (subcount >= lfo_max_count[lfo_rate()]) + { + // note: to match the published values this should be 0x100 - subcount; + // however, tests on the hardware and nuked bear out an off-by-one + // error exists that causes the max LFO rate to be faster than published + m_lfo_counter += 0x101 - subcount; + } + + // AM value is 7 bits, staring at bit 8; grab the low 6 directly + m_lfo_am = bitfield(m_lfo_counter, 8, 6); + + // first half of the AM period (bit 6 == 0) is inverted + if (bitfield(m_lfo_counter, 8+6) == 0) + m_lfo_am ^= 0x3f; + + // PM value is 5 bits, starting at bit 10; grab the low 3 directly + int32_t pm = bitfield(m_lfo_counter, 10, 3); + + // PM is reflected based on bit 3 + if (bitfield(m_lfo_counter, 10+3)) + pm ^= 7; + + // PM is negated based on bit 4 + return bitfield(m_lfo_counter, 10+4) ? -pm : pm; +} + + +//------------------------------------------------- +// lfo_am_offset - return the AM offset from LFO +// for the given channel +//------------------------------------------------- + +template +uint32_t opn_registers_base::lfo_am_offset(uint32_t choffs) const +{ + // shift value for AM sensitivity is [7, 3, 1, 0], + // mapping to values of [0, 1.4, 5.9, and 11.8dB] + uint32_t am_shift = (1 << (ch_lfo_am_sens(choffs) ^ 3)) - 1; + + // QUESTION: max sensitivity should give 11.8dB range, but this value + // is directly added to an x.8 attenuation value, which will only give + // 126/256 or ~4.9dB range -- what am I missing? The calculation below + // matches several other emulators, including the Nuked implemenation. + + // raw LFO AM value on OPN is 0-3F, scale that up by a factor of 2 + // (giving 7 bits) before applying the final shift + return (m_lfo_am << 1) >> am_shift; +} + + +//------------------------------------------------- +// cache_operator_data - fill the operator cache +// with prefetched data +//------------------------------------------------- + +template +void opn_registers_base::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) +{ + // set up the easy stuff + cache.waveform = &m_waveform[0][0]; + + // get frequency from the channel + uint32_t block_freq = cache.block_freq = ch_block_freq(choffs); + + // if multi-frequency mode is enabled and this is channel 2, + // fetch one of the special frequencies + if (multi_freq() && choffs == 2) + { + if (opoffs == 2) + block_freq = cache.block_freq = multi_block_freq(1); + else if (opoffs == 10) + block_freq = cache.block_freq = multi_block_freq(2); + else if (opoffs == 6) + block_freq = cache.block_freq = multi_block_freq(0); + } + + // compute the keycode: block_freq is: + // + // BBBFFFFFFFFFFF + // ^^^^??? + // + // the 5-bit keycode uses the top 4 bits plus a magic formula + // for the final bit + uint32_t keycode = bitfield(block_freq, 10, 4) << 1; + + // lowest bit is determined by a mix of next lower FNUM bits + // according to this equation from the YM2608 manual: + // + // (F11 & (F10 | F9 | F8)) | (!F11 & F10 & F9 & F8) + // + // for speed, we just look it up in a 16-bit constant + keycode |= bitfield(0xfe80, bitfield(block_freq, 7, 4)); + + // detune adjustment + cache.detune = detune_adjustment(op_detune(opoffs), keycode); + + // multiple value, as an x.1 value (0 means 0.5) + cache.multiple = op_multiple(opoffs) * 2; + if (cache.multiple == 0) + cache.multiple = 1; + + // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on + // block_freq, detune, and multiple, so compute it after we've done those + if (!IsOpnA || lfo_enable() == 0 || ch_lfo_pm_sens(choffs) == 0) + cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0); + else + cache.phase_step = opdata_cache::PHASE_STEP_DYNAMIC; + + // total level, scaled by 8 + cache.total_level = op_total_level(opoffs) << 3; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = op_sustain_level(opoffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // determine KSR adjustment for enevlope rates + uint32_t ksrval = keycode >> (op_ksr(opoffs) ^ 3); + cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval); +} + + +//------------------------------------------------- +// compute_phase_step - compute the phase step +//------------------------------------------------- + +template +uint32_t opn_registers_base::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm) +{ + // OPN phase calculation has only a single detune parameter + // and uses FNUMs instead of keycodes + + // extract frequency number (low 11 bits of block_freq) + uint32_t fnum = bitfield(cache.block_freq, 0, 11) << 1; + + // if there's a non-zero PM sensitivity, compute the adjustment + uint32_t pm_sensitivity = ch_lfo_pm_sens(choffs); + if (pm_sensitivity != 0) + { + // apply the phase adjustment based on the upper 7 bits + // of FNUM and the PM depth parameters + fnum += opn_lfo_pm_phase_adjustment(bitfield(cache.block_freq, 4, 7), pm_sensitivity, lfo_raw_pm); + + // keep fnum to 12 bits + fnum &= 0xfff; + } + + // apply block shift to compute phase step + uint32_t block = bitfield(cache.block_freq, 11, 3); + uint32_t phase_step = (fnum << block) >> 2; + + // apply detune based on the keycode + phase_step += cache.detune; + + // clamp to 17 bits in case detune overflows + // QUESTION: is this specific to the YM2612/3438? + phase_step &= 0x1ffff; + + // apply frequency multiplier (which is cached as an x.1 value) + return (phase_step * cache.multiple) >> 1; +} + + +//------------------------------------------------- +// log_keyon - log a key-on event +//------------------------------------------------- + +template +std::string opn_registers_base::log_keyon(uint32_t choffs, uint32_t opoffs) +{ + uint32_t chnum = (choffs & 3) + 3 * bitfield(choffs, 8); + uint32_t opnum = (opoffs & 15) - ((opoffs & 15) / 4) + 12 * bitfield(opoffs, 8); + + uint32_t block_freq = ch_block_freq(choffs); + if (multi_freq() && choffs == 2) + { + if (opoffs == 2) + block_freq = multi_block_freq(1); + else if (opoffs == 10) + block_freq = multi_block_freq(2); + else if (opoffs == 6) + block_freq = multi_block_freq(0); + } + + char buffer[256]; + char *end = &buffer[0]; + + end += sprintf(end, "%u.%02u freq=%04X dt=%u fb=%u alg=%X mul=%X tl=%02X ksr=%u adsr=%02X/%02X/%02X/%X sl=%X", + chnum, opnum, + block_freq, + op_detune(opoffs), + ch_feedback(choffs), + ch_algorithm(choffs), + op_multiple(opoffs), + op_total_level(opoffs), + op_ksr(opoffs), + op_attack_rate(opoffs), + op_decay_rate(opoffs), + op_sustain_rate(opoffs), + op_release_rate(opoffs), + op_sustain_level(opoffs)); + + if (OUTPUTS > 1) + end += sprintf(end, " out=%c%c", + ch_output_0(choffs) ? 'L' : '-', + ch_output_1(choffs) ? 'R' : '-'); + if (op_ssg_eg_enable(opoffs)) + end += sprintf(end, " ssg=%X", op_ssg_eg_mode(opoffs)); + bool am = (op_lfo_am_enable(opoffs) && ch_lfo_am_sens(choffs) != 0); + if (am) + end += sprintf(end, " am=%u", ch_lfo_am_sens(choffs)); + bool pm = (ch_lfo_pm_sens(choffs) != 0); + if (pm) + end += sprintf(end, " pm=%u", ch_lfo_pm_sens(choffs)); + if (am || pm) + end += sprintf(end, " lfo=%02X", lfo_rate()); + if (multi_freq() && choffs == 2) + end += sprintf(end, " multi=1"); + + return buffer; +} + + + +//********************************************************* +// SSG RESAMPLER +//********************************************************* + +//------------------------------------------------- +// add_last - helper to add the last computed +// value to the sums, applying the given scale +//------------------------------------------------- + +template +void ssg_resampler::add_last(int32_t &sum0, int32_t &sum1, int32_t &sum2, int32_t scale) +{ + sum0 += m_last.data[0] * scale; + sum1 += m_last.data[1] * scale; + sum2 += m_last.data[2] * scale; +} + + +//------------------------------------------------- +// clock_and_add - helper to clock a new value +// and then add it to the sums, applying the +// given scale +//------------------------------------------------- + +template +void ssg_resampler::clock_and_add(int32_t &sum0, int32_t &sum1, int32_t &sum2, int32_t scale) +{ + m_ssg.clock(); + m_ssg.output(m_last); + add_last(sum0, sum1, sum2, scale); +} + + +//------------------------------------------------- +// write_to_output - helper to write the sums to +// the appropriate outputs, applying the given +// divisor to the final result +//------------------------------------------------- + +template +void ssg_resampler::write_to_output(OutputType *output, int32_t sum0, int32_t sum1, int32_t sum2, int32_t divisor) +{ + if (MixTo1) + { + // mixing to one, apply a 2/3 factor to prevent overflow + output->data[FirstOutput] = (sum0 + sum1 + sum2) * 2 / (3 * divisor); + } + else + { + // write three outputs in a row + output->data[FirstOutput + 0] = sum0 / divisor; + output->data[FirstOutput + 1] = sum1 / divisor; + output->data[FirstOutput + 2] = sum2 / divisor; + } + + // track the sample index here + m_sampindex++; +} + + +//------------------------------------------------- +// ssg_resampler - constructor +//------------------------------------------------- + +template +ssg_resampler::ssg_resampler(ssg_engine &ssg) : + m_ssg(ssg), + m_sampindex(0), + m_resampler(&ssg_resampler::resample_nop) +{ + m_last.clear(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +template +void ssg_resampler::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_sampindex); + state.save_restore(m_last.data); +} + + +//------------------------------------------------- +// configure - configure a new ratio +//------------------------------------------------- + +template +void ssg_resampler::configure(uint8_t outsamples, uint8_t srcsamples) +{ + switch (outsamples * 10 + srcsamples) + { + case 4*10 + 1: /* 4:1 */ m_resampler = &ssg_resampler::resample_n_1<4>; break; + case 2*10 + 1: /* 2:1 */ m_resampler = &ssg_resampler::resample_n_1<2>; break; + case 4*10 + 3: /* 4:3 */ m_resampler = &ssg_resampler::resample_4_3; break; + case 1*10 + 1: /* 1:1 */ m_resampler = &ssg_resampler::resample_n_1<1>; break; + case 2*10 + 3: /* 2:3 */ m_resampler = &ssg_resampler::resample_2_3; break; + case 1*10 + 3: /* 1:3 */ m_resampler = &ssg_resampler::resample_1_n<3>; break; + case 2*10 + 9: /* 2:9 */ m_resampler = &ssg_resampler::resample_2_9; break; + case 1*10 + 6: /* 1:6 */ m_resampler = &ssg_resampler::resample_1_n<6>; break; + case 0*10 + 0: /* 0:0 */ m_resampler = &ssg_resampler::resample_nop; break; + default: assert(false); break; + } +} + + +//------------------------------------------------- +// resample_n_1 - resample SSG output to the +// target at a rate of 1 SSG sample to every +// n output sample +//------------------------------------------------- + +template +template +void ssg_resampler::resample_n_1(OutputType *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + if (m_sampindex % Multiplier == 0) + { + m_ssg.clock(); + m_ssg.output(m_last); + } + write_to_output(output, m_last.data[0], m_last.data[1], m_last.data[2]); + } +} + + +//------------------------------------------------- +// resample_1_n - resample SSG output to the +// target at a rate of n SSG samples to every +// 1 output sample +//------------------------------------------------- + +template +template +void ssg_resampler::resample_1_n(OutputType *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + int32_t sum0 = 0, sum1 = 0, sum2 = 0; + for (int rep = 0; rep < Divisor; rep++) + clock_and_add(sum0, sum1, sum2); + write_to_output(output, sum0, sum1, sum2, Divisor); + } +} + + +//------------------------------------------------- +// resample_2_9 - resample SSG output to the +// target at a rate of 9 SSG samples to every +// 2 output samples +//------------------------------------------------- + +template +void ssg_resampler::resample_2_9(OutputType *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + int32_t sum0 = 0, sum1 = 0, sum2 = 0; + if (bitfield(m_sampindex, 0) != 0) + add_last(sum0, sum1, sum2, 1); + clock_and_add(sum0, sum1, sum2, 2); + clock_and_add(sum0, sum1, sum2, 2); + clock_and_add(sum0, sum1, sum2, 2); + clock_and_add(sum0, sum1, sum2, 2); + if (bitfield(m_sampindex, 0) == 0) + clock_and_add(sum0, sum1, sum2, 1); + write_to_output(output, sum0, sum1, sum2, 9); + } +} + + +//------------------------------------------------- +// resample_2_3 - resample SSG output to the +// target at a rate of 3 SSG samples to every +// 2 output samples +//------------------------------------------------- + +template +void ssg_resampler::resample_2_3(OutputType *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + int32_t sum0 = 0, sum1 = 0, sum2 = 0; + if (bitfield(m_sampindex, 0) == 0) + { + clock_and_add(sum0, sum1, sum2, 2); + clock_and_add(sum0, sum1, sum2, 1); + } + else + { + add_last(sum0, sum1, sum2, 1); + clock_and_add(sum0, sum1, sum2, 2); + } + write_to_output(output, sum0, sum1, sum2, 3); + } +} + + +//------------------------------------------------- +// resample_4_3 - resample SSG output to the +// target at a rate of 3 SSG samples to every +// 4 output samples +//------------------------------------------------- + +template +void ssg_resampler::resample_4_3(OutputType *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + int32_t sum0 = 0, sum1 = 0, sum2 = 0; + int32_t step = bitfield(m_sampindex, 0, 2); + add_last(sum0, sum1, sum2, step); + if (step != 3) + clock_and_add(sum0, sum1, sum2, 3 - step); + write_to_output(output, sum0, sum1, sum2, 3); + } +} + + +//------------------------------------------------- +// resample_nop - no-op resampler +//------------------------------------------------- + +template +void ssg_resampler::resample_nop(OutputType *output, uint32_t numsamples) +{ + // nothing to do except increment the sample index + m_sampindex += numsamples; +} + + + +//********************************************************* +// YM2203 +//********************************************************* + +//------------------------------------------------- +// ym2203 - constructor +//------------------------------------------------- + +ym2203::ym2203(ymfm_interface &intf) : + m_fidelity(OPN_FIDELITY_MAX), + m_address(0), + m_fm(intf), + m_ssg(intf), + m_ssg_resampler(m_ssg) +{ + m_last_fm.clear(); + update_prescale(m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2203::reset() +{ + // reset the engines + m_fm.reset(); + m_ssg.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2203::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_last_fm.data); + + m_fm.save_restore(state); + m_ssg.save_restore(state); + m_ssg_resampler.save_restore(state); + + update_prescale(m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym2203::read_status() +{ + uint8_t result = m_fm.status(); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read_data - read the data register +//------------------------------------------------- + +uint8_t ym2203::read_data() +{ + uint8_t result = 0; + if (m_address < 0x10) + { + // 00-0F: Read from SSG + result = m_ssg.read(m_address & 0x0f); + } + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2203::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 1) + { + case 0: // status port + result = read_status(); + break; + + case 1: // data port (only SSG) + result = read_data(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2203::write_address(uint8_t data) +{ + // just set the address + m_address = data; + + // special case: update the prescale + if (m_address >= 0x2d && m_address <= 0x2f) + { + // 2D-2F: prescaler select + if (m_address == 0x2d) + update_prescale(6); + else if (m_address == 0x2e && m_fm.clock_prescale() == 6) + update_prescale(3); + else if (m_address == 0x2f) + update_prescale(2); + } +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2203::write_data(uint8_t data) +{ + if (m_address < 0x10) + { + // 00-0F: write to SSG + m_ssg.write(m_address & 0x0f, data); + } + else + { + // 10-FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2203::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym2203::generate(output_data *output, uint32_t numsamples) +{ + // FM output is just repeated the prescale number of times; note that + // 0 is a special 1.5 case + if (m_fm_samples_per_output != 0) + { + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + if ((m_ssg_resampler.sampindex() + samp) % m_fm_samples_per_output == 0) + clock_fm(); + output->data[0] = m_last_fm.data[0]; + } + } + else + { + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + uint32_t step = (m_ssg_resampler.sampindex() + samp) % 3; + if (step == 0) + clock_fm(); + output->data[0] = m_last_fm.data[0]; + if (step == 1) + { + clock_fm(); + output->data[0] = (output->data[0] + m_last_fm.data[0]) / 2; + } + } + } + + // resample the SSG as configured + m_ssg_resampler.resample(output - numsamples, numsamples); +} + + +//------------------------------------------------- +// update_prescale - update the prescale value, +// recomputing derived values +//------------------------------------------------- + +void ym2203::update_prescale(uint8_t prescale) +{ + // tell the FM engine + m_fm.set_clock_prescale(prescale); + m_ssg.prescale_changed(); + + // Fidelity: ---- minimum ---- ---- medium ----- ---- maximum----- + // rate = clock/24 rate = clock/12 rate = clock/4 + // Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate + // 6 3:1 2:3 6:1 4:3 18:1 4:1 + // 3 1.5:1 1:3 3:1 2:3 9:1 2:1 + // 2 1:1 1:6 2:1 1:3 6:1 1:1 + + // compute the number of FM samples per output sample, and select the + // resampler function + if (m_fidelity == OPN_FIDELITY_MIN) + { + switch (prescale) + { + default: + case 6: m_fm_samples_per_output = 3; m_ssg_resampler.configure(2, 3); break; + case 3: m_fm_samples_per_output = 0; m_ssg_resampler.configure(1, 3); break; + case 2: m_fm_samples_per_output = 1; m_ssg_resampler.configure(1, 6); break; + } + } + else if (m_fidelity == OPN_FIDELITY_MED) + { + switch (prescale) + { + default: + case 6: m_fm_samples_per_output = 6; m_ssg_resampler.configure(4, 3); break; + case 3: m_fm_samples_per_output = 3; m_ssg_resampler.configure(2, 3); break; + case 2: m_fm_samples_per_output = 2; m_ssg_resampler.configure(1, 3); break; + } + } + else + { + switch (prescale) + { + default: + case 6: m_fm_samples_per_output = 18; m_ssg_resampler.configure(4, 1); break; + case 3: m_fm_samples_per_output = 9; m_ssg_resampler.configure(2, 1); break; + case 2: m_fm_samples_per_output = 6; m_ssg_resampler.configure(1, 1); break; + } + } + + // if overriding the SSG, override the configuration with the nop + // resampler to at least keep the sample index moving forward + if (m_ssg.overridden()) + m_ssg_resampler.configure(0, 0); +} + + +//------------------------------------------------- +// clock_fm - clock FM state +//------------------------------------------------- + +void ym2203::clock_fm() +{ + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; OPN is full 14-bit with no intermediate clipping + m_fm.output(m_last_fm.clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // convert to 10.3 floating point value for the DAC and back + m_last_fm.roundtrip_fp(); +} + + + +//********************************************************* +// YM2608 +//********************************************************* + +//------------------------------------------------- +// ym2608 - constructor +//------------------------------------------------- + +ym2608::ym2608(ymfm_interface &intf) : + m_fidelity(OPN_FIDELITY_MAX), + m_address(0), + m_irq_enable(0x1f), + m_flag_control(0x1c), + m_fm(intf), + m_ssg(intf), + m_ssg_resampler(m_ssg), + m_adpcm_a(intf, 0), + m_adpcm_b(intf) +{ + m_last_fm.clear(); + update_prescale(m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2608::reset() +{ + // reset the engines + m_fm.reset(); + m_ssg.reset(); + m_adpcm_a.reset(); + m_adpcm_b.reset(); + + // configure ADPCM percussion sounds; these are present in an embedded ROM + m_adpcm_a.set_start_end(0, 0x0000, 0x01bf); // bass drum + m_adpcm_a.set_start_end(1, 0x01c0, 0x043f); // snare drum + m_adpcm_a.set_start_end(2, 0x0440, 0x1b7f); // top cymbal + m_adpcm_a.set_start_end(3, 0x1b80, 0x1cff); // high hat + m_adpcm_a.set_start_end(4, 0x1d00, 0x1f7f); // tom tom + m_adpcm_a.set_start_end(5, 0x1f80, 0x1fff); // rim shot + + // initialize our special interrupt states, then read the upper status + // register, which updates the IRQs + m_irq_enable = 0x1f; + m_flag_control = 0x1c; + read_status_hi(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2608::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_irq_enable); + state.save_restore(m_flag_control); + state.save_restore(m_last_fm.data); + + m_fm.save_restore(state); + m_ssg.save_restore(state); + m_ssg_resampler.save_restore(state); + m_adpcm_a.save_restore(state); + m_adpcm_b.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym2608::read_status() +{ + uint8_t result = m_fm.status() & (fm_engine::STATUS_TIMERA | fm_engine::STATUS_TIMERB); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read_data - read the data register +//------------------------------------------------- + +uint8_t ym2608::read_data() +{ + uint8_t result = 0; + if (m_address < 0x10) + { + // 00-0F: Read from SSG + result = m_ssg.read(m_address & 0x0f); + } + else if (m_address == 0xff) + { + // FF: ID code + result = 1; + } + return result; +} + + +//------------------------------------------------- +// read_status_hi - read the extended status +// register +//------------------------------------------------- + +uint8_t ym2608::read_status_hi() +{ + // fetch regular status + uint8_t status = m_fm.status() & ~(STATUS_ADPCM_B_EOS | STATUS_ADPCM_B_BRDY | STATUS_ADPCM_B_PLAYING); + + // fetch ADPCM-B status, and merge in the bits + uint8_t adpcm_status = m_adpcm_b.status(); + if ((adpcm_status & adpcm_b_channel::STATUS_EOS) != 0) + status |= STATUS_ADPCM_B_EOS; + if ((adpcm_status & adpcm_b_channel::STATUS_BRDY) != 0) + status |= STATUS_ADPCM_B_BRDY; + if ((adpcm_status & adpcm_b_channel::STATUS_PLAYING) != 0) + status |= STATUS_ADPCM_B_PLAYING; + + // turn off any bits that have been requested to be masked + status &= ~(m_flag_control & 0x1f); + + // update the status so that IRQs are propagated + m_fm.set_reset_status(status, ~status); + + // merge in the busy flag + if (m_fm.intf().ymfm_is_busy()) + status |= fm_engine::STATUS_BUSY; + return status; +} + + +//------------------------------------------------- +// read_data_hi - read the upper data register +//------------------------------------------------- + +uint8_t ym2608::read_data_hi() +{ + uint8_t result = 0; + if ((m_address & 0xff) < 0x10) + { + // 00-0F: Read from ADPCM-B + result = m_adpcm_b.read(m_address & 0x0f); + } + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2608::read(uint32_t offset) +{ + uint8_t result = 0; + switch (offset & 3) + { + case 0: // status port, YM2203 compatible + result = read_status(); + break; + + case 1: // data port (only SSG) + result = read_data(); + break; + + case 2: // status port, extended + result = read_status_hi(); + break; + + case 3: // ADPCM-B data + result = read_data_hi(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2608::write_address(uint8_t data) +{ + // just set the address + m_address = data; + + // special case: update the prescale + if (m_address >= 0x2d && m_address <= 0x2f) + { + // 2D-2F: prescaler select + if (m_address == 0x2d) + update_prescale(6); + else if (m_address == 0x2e && m_fm.clock_prescale() == 6) + update_prescale(3); + else if (m_address == 0x2f) + update_prescale(2); + } +} + + +//------------------------------------------------- +// write - handle a write to the data register +//------------------------------------------------- + +void ym2608::write_data(uint8_t data) +{ + // ignore if paired with upper address + if (bitfield(m_address, 8)) + return; + + if (m_address < 0x10) + { + // 00-0F: write to SSG + m_ssg.write(m_address & 0x0f, data); + } + else if (m_address < 0x20) + { + // 10-1F: write to ADPCM-A + m_adpcm_a.write(m_address & 0x0f, data); + } + else if (m_address == 0x29) + { + // 29: special IRQ mask register + m_irq_enable = data; + m_fm.set_irq_mask(m_irq_enable & ~m_flag_control & 0x1f); + } + else + { + // 20-28, 2A-FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ym2608::write_address_hi(uint8_t data) +{ + // just set the address + m_address = 0x100 | data; +} + + +//------------------------------------------------- +// write_data_hi - handle a write to the upper +// data register +//------------------------------------------------- + +void ym2608::write_data_hi(uint8_t data) +{ + // ignore if paired with upper address + if (!bitfield(m_address, 8)) + return; + + if (m_address < 0x110) + { + // 100-10F: write to ADPCM-B + m_adpcm_b.write(m_address & 0x0f, data); + } + else if (m_address == 0x110) + { + // 110: IRQ flag control + if (bitfield(data, 7)) + m_fm.set_reset_status(0, 0xff); + else + { + m_flag_control = data; + m_fm.set_irq_mask(m_irq_enable & ~m_flag_control & 0x1f); + } + } + else + { + // 111-1FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2608::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // upper address port + write_address_hi(data); + break; + + case 3: // upper data port + write_data_hi(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym2608::generate(output_data *output, uint32_t numsamples) +{ + // FM output is just repeated the prescale number of times; note that + // 0 is a special 1.5 case + if (m_fm_samples_per_output != 0) + { + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + if ((m_ssg_resampler.sampindex() + samp) % m_fm_samples_per_output == 0) + clock_fm_and_adpcm(); + output->data[0] = m_last_fm.data[0]; + output->data[1] = m_last_fm.data[1]; + } + } + else + { + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + uint32_t step = (m_ssg_resampler.sampindex() + samp) % 3; + if (step == 0) + clock_fm_and_adpcm(); + output->data[0] = m_last_fm.data[0]; + output->data[1] = m_last_fm.data[1]; + if (step == 1) + { + clock_fm_and_adpcm(); + output->data[0] = (output->data[0] + m_last_fm.data[0]) / 2; + output->data[1] = (output->data[1] + m_last_fm.data[1]) / 2; + } + } + } + + // resample the SSG as configured + m_ssg_resampler.resample(output - numsamples, numsamples); +} + + +//------------------------------------------------- +// update_prescale - update the prescale value, +// recomputing derived values +//------------------------------------------------- + +void ym2608::update_prescale(uint8_t prescale) +{ + // tell the FM engine + m_fm.set_clock_prescale(prescale); + m_ssg.prescale_changed(); + + // Fidelity: ---- minimum ---- ---- medium ----- ---- maximum----- + // rate = clock/48 rate = clock/24 rate = clock/8 + // Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate + // 6 3:1 2:3 6:1 4:3 18:1 4:1 + // 3 1.5:1 1:3 3:1 2:3 9:1 2:1 + // 2 1:1 1:6 2:1 1:3 6:1 1:1 + + // compute the number of FM samples per output sample, and select the + // resampler function + if (m_fidelity == OPN_FIDELITY_MIN) + { + switch (prescale) + { + default: + case 6: m_fm_samples_per_output = 3; m_ssg_resampler.configure(2, 3); break; + case 3: m_fm_samples_per_output = 0; m_ssg_resampler.configure(1, 3); break; + case 2: m_fm_samples_per_output = 1; m_ssg_resampler.configure(1, 6); break; + } + } + else if (m_fidelity == OPN_FIDELITY_MED) + { + switch (prescale) + { + default: + case 6: m_fm_samples_per_output = 6; m_ssg_resampler.configure(4, 3); break; + case 3: m_fm_samples_per_output = 3; m_ssg_resampler.configure(2, 3); break; + case 2: m_fm_samples_per_output = 2; m_ssg_resampler.configure(1, 3); break; + } + } + else + { + switch (prescale) + { + default: + case 6: m_fm_samples_per_output = 18; m_ssg_resampler.configure(4, 1); break; + case 3: m_fm_samples_per_output = 9; m_ssg_resampler.configure(2, 1); break; + case 2: m_fm_samples_per_output = 6; m_ssg_resampler.configure(1, 1); break; + } + } + + // if overriding the SSG, override the configuration with the nop + // resampler to at least keep the sample index moving forward + if (m_ssg.overridden()) + m_ssg_resampler.configure(0, 0); +} + + +//------------------------------------------------- +// clock_fm_and_adpcm - clock FM and ADPCM state +//------------------------------------------------- + +void ym2608::clock_fm_and_adpcm() +{ + // top bit of the IRQ enable flags controls 3-channel vs 6-channel mode + uint32_t fmmask = bitfield(m_irq_enable, 7) ? 0x3f : 0x07; + + // clock the system + uint32_t env_counter = m_fm.clock(fm_engine::ALL_CHANNELS); + + // clock the ADPCM-A engine on every envelope cycle + // (channels 4 and 5 clock every 2 envelope clocks) + if (bitfield(env_counter, 0, 2) == 0) + m_adpcm_a.clock(bitfield(env_counter, 2) ? 0x0f : 0x3f); + + // clock the ADPCM-B engine every cycle + m_adpcm_b.clock(); + + // update the FM content; OPNA is 13-bit with no intermediate clipping + m_fm.output(m_last_fm.clear(), 1, 32767, fmmask); + + // mix in the ADPCM and clamp + m_adpcm_a.output(m_last_fm, 0x3f); + m_adpcm_b.output(m_last_fm, 1); + m_last_fm.clamp16(); +} + + +//********************************************************* +// YMF288 +//********************************************************* + +// YMF288 is a YM2608 with the following changes: +// * ADPCM-B part removed +// * prescaler removed (fixed at 6) +// * CSM removed +// * Low power mode added +// * SSG tone frequency is altered in some way? (explicitly DC for Tp 0-7, also double volume in some cases) +// * I/O ports removed +// * Shorter busy times +// * All registers can be read + +//------------------------------------------------- +// ymf288 - constructor +//------------------------------------------------- + +ymf288::ymf288(ymfm_interface &intf) : + m_fidelity(OPN_FIDELITY_MAX), + m_address(0), + m_irq_enable(0x03), + m_flag_control(0x03), + m_fm(intf), + m_ssg(intf), + m_ssg_resampler(m_ssg), + m_adpcm_a(intf, 0) +{ + m_last_fm.clear(); + update_prescale(); +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ymf288::reset() +{ + // reset the engines + m_fm.reset(); + m_ssg.reset(); + m_adpcm_a.reset(); + + // configure ADPCM percussion sounds; these are present in an embedded ROM + m_adpcm_a.set_start_end(0, 0x0000, 0x01bf); // bass drum + m_adpcm_a.set_start_end(1, 0x01c0, 0x043f); // snare drum + m_adpcm_a.set_start_end(2, 0x0440, 0x1b7f); // top cymbal + m_adpcm_a.set_start_end(3, 0x1b80, 0x1cff); // high hat + m_adpcm_a.set_start_end(4, 0x1d00, 0x1f7f); // tom tom + m_adpcm_a.set_start_end(5, 0x1f80, 0x1fff); // rim shot + + // initialize our special interrupt states, then read the upper status + // register, which updates the IRQs + m_irq_enable = 0x03; + m_flag_control = 0x00; + read_status_hi(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ymf288::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_irq_enable); + state.save_restore(m_flag_control); + state.save_restore(m_last_fm.data); + + m_fm.save_restore(state); + m_ssg.save_restore(state); + m_ssg_resampler.save_restore(state); + m_adpcm_a.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ymf288::read_status() +{ + uint8_t result = m_fm.status() & (fm_engine::STATUS_TIMERA | fm_engine::STATUS_TIMERB); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read_data - read the data register +//------------------------------------------------- + +uint8_t ymf288::read_data() +{ + uint8_t result = 0; + if (m_address < 0x0e) + { + // 00-0D: Read from SSG + result = m_ssg.read(m_address & 0x0f); + } + else if (m_address < 0x10) + { + // 0E-0F: I/O ports not supported + result = 0xff; + } + else if (m_address == 0xff) + { + // FF: ID code + result = 2; + } + else if (ymf288_mode()) + { + // registers are readable in YMF288 mode + result = m_fm.regs().read(m_address); + } + return result; +} + + +//------------------------------------------------- +// read_status_hi - read the extended status +// register +//------------------------------------------------- + +uint8_t ymf288::read_status_hi() +{ + // fetch regular status + uint8_t status = m_fm.status() & (fm_engine::STATUS_TIMERA | fm_engine::STATUS_TIMERB); + + // turn off any bits that have been requested to be masked + status &= ~(m_flag_control & 0x03); + + // update the status so that IRQs are propagated + m_fm.set_reset_status(status, ~status); + + // merge in the busy flag + if (m_fm.intf().ymfm_is_busy()) + status |= fm_engine::STATUS_BUSY; + return status; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ymf288::read(uint32_t offset) +{ + uint8_t result = 0; + switch (offset & 3) + { + case 0: // status port, YM2203 compatible + result = read_status(); + break; + + case 1: // data port + result = read_data(); + break; + + case 2: // status port, extended + result = read_status_hi(); + break; + + case 3: // unmapped + debug::log_unexpected_read_write("Unexpected read from YMF288 offset %d\n", offset & 3); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ymf288::write_address(uint8_t data) +{ + // just set the address + m_address = data; + + // in YMF288 mode, busy is signaled after address writes too + if (ymf288_mode()) + m_fm.intf().ymfm_set_busy_end(16); +} + + +//------------------------------------------------- +// write - handle a write to the data register +//------------------------------------------------- + +void ymf288::write_data(uint8_t data) +{ + // ignore if paired with upper address + if (bitfield(m_address, 8)) + return; + + // wait times are shorter in YMF288 mode + int busy_cycles = ymf288_mode() ? 16 : 32 * m_fm.clock_prescale(); + if (m_address < 0x0e) + { + // 00-0D: write to SSG + m_ssg.write(m_address & 0x0f, data); + } + else if (m_address < 0x10) + { + // 0E-0F: I/O ports not supported + } + else if (m_address < 0x20) + { + // 10-1F: write to ADPCM-A + m_adpcm_a.write(m_address & 0x0f, data); + busy_cycles = 32 * m_fm.clock_prescale(); + } + else if (m_address == 0x27) + { + // 27: mode register; CSM isn't supported so disable it + data &= 0x7f; + m_fm.write(m_address, data); + } + else if (m_address == 0x29) + { + // 29: special IRQ mask register + m_irq_enable = data; + m_fm.set_irq_mask(m_irq_enable & ~m_flag_control & 0x03); + } + else + { + // 20-27, 2A-FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(busy_cycles); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ymf288::write_address_hi(uint8_t data) +{ + // just set the address + m_address = 0x100 | data; + + // in YMF288 mode, busy is signaled after address writes too + if (ymf288_mode()) + m_fm.intf().ymfm_set_busy_end(16); +} + + +//------------------------------------------------- +// write_data_hi - handle a write to the upper +// data register +//------------------------------------------------- + +void ymf288::write_data_hi(uint8_t data) +{ + // ignore if paired with upper address + if (!bitfield(m_address, 8)) + return; + + // wait times are shorter in YMF288 mode + int busy_cycles = ymf288_mode() ? 16 : 32 * m_fm.clock_prescale(); + if (m_address == 0x110) + { + // 110: IRQ flag control + if (bitfield(data, 7)) + m_fm.set_reset_status(0, 0xff); + else + { + m_flag_control = data; + m_fm.set_irq_mask(m_irq_enable & ~m_flag_control & 0x03); + } + } + else + { + // 100-10F,111-1FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(busy_cycles); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ymf288::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // upper address port + write_address_hi(data); + break; + + case 3: // upper data port + write_data_hi(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ymf288::generate(output_data *output, uint32_t numsamples) +{ + // FM output is just repeated the prescale number of times; note that + // 0 is a special 1.5 case + if (m_fm_samples_per_output != 0) + { + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + if ((m_ssg_resampler.sampindex() + samp) % m_fm_samples_per_output == 0) + clock_fm_and_adpcm(); + output->data[0] = m_last_fm.data[0]; + output->data[1] = m_last_fm.data[1]; + } + } + else + { + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + uint32_t step = (m_ssg_resampler.sampindex() + samp) % 3; + if (step == 0) + clock_fm_and_adpcm(); + output->data[0] = m_last_fm.data[0]; + output->data[1] = m_last_fm.data[1]; + if (step == 1) + { + clock_fm_and_adpcm(); + output->data[0] = (output->data[0] + m_last_fm.data[0]) / 2; + output->data[1] = (output->data[1] + m_last_fm.data[1]) / 2; + } + } + } + + // resample the SSG as configured + m_ssg_resampler.resample(output - numsamples, numsamples); +} + + +//------------------------------------------------- +// update_prescale - update the prescale value, +// recomputing derived values +//------------------------------------------------- + +void ymf288::update_prescale() +{ + // Fidelity: ---- minimum ---- ---- medium ----- ---- maximum----- + // rate = clock/144 rate = clock/144 rate = clock/16 + // Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate + // 6 1:1 2:9 1:1 2:9 9:1 2:1 + + // compute the number of FM samples per output sample, and select the + // resampler function + if (m_fidelity == OPN_FIDELITY_MIN || m_fidelity == OPN_FIDELITY_MED) + { + m_fm_samples_per_output = 1; + m_ssg_resampler.configure(2, 9); + } + else + { + m_fm_samples_per_output = 9; + m_ssg_resampler.configure(2, 1); + } + + // if overriding the SSG, override the configuration with the nop + // resampler to at least keep the sample index moving forward + if (m_ssg.overridden()) + m_ssg_resampler.configure(0, 0); +} + + +//------------------------------------------------- +// clock_fm_and_adpcm - clock FM and ADPCM state +//------------------------------------------------- + +void ymf288::clock_fm_and_adpcm() +{ + // top bit of the IRQ enable flags controls 3-channel vs 6-channel mode + uint32_t fmmask = bitfield(m_irq_enable, 7) ? 0x3f : 0x07; + + // clock the system + uint32_t env_counter = m_fm.clock(fm_engine::ALL_CHANNELS); + + // clock the ADPCM-A engine on every envelope cycle + // (channels 4 and 5 clock every 2 envelope clocks) + if (bitfield(env_counter, 0, 2) == 0) + m_adpcm_a.clock(bitfield(env_counter, 2) ? 0x0f : 0x3f); + + // update the FM content; OPNA is 13-bit with no intermediate clipping + m_fm.output(m_last_fm.clear(), 1, 32767, fmmask); + + // mix in the ADPCM + m_adpcm_a.output(m_last_fm, 0x3f); +} + + + +//********************************************************* +// YM2610 +//********************************************************* + +//------------------------------------------------- +// ym2610 - constructor +//------------------------------------------------- + +ym2610::ym2610(ymfm_interface &intf, uint8_t channel_mask) : + m_fidelity(OPN_FIDELITY_MAX), + m_address(0), + m_fm_mask(channel_mask), + m_eos_status(0x00), + m_flag_mask(EOS_FLAGS_MASK), + m_fm(intf), + m_ssg(intf), + m_ssg_resampler(m_ssg), + m_adpcm_a(intf, 8), + m_adpcm_b(intf, 8) +{ + update_prescale(); +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2610::reset() +{ + // reset the engines + m_fm.reset(); + m_ssg.reset(); + m_adpcm_a.reset(); + m_adpcm_b.reset(); + + // initialize our special interrupt states + m_eos_status = 0x00; + m_flag_mask = EOS_FLAGS_MASK; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2610::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_eos_status); + state.save_restore(m_flag_mask); + + m_fm.save_restore(state); + m_ssg.save_restore(state); + m_ssg_resampler.save_restore(state); + m_adpcm_a.save_restore(state); + m_adpcm_b.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym2610::read_status() +{ + uint8_t result = m_fm.status() & (fm_engine::STATUS_TIMERA | fm_engine::STATUS_TIMERB); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read_data - read the data register +//------------------------------------------------- + +uint8_t ym2610::read_data() +{ + uint8_t result = 0; + if (m_address < 0x0e) + { + // 00-0D: Read from SSG + result = m_ssg.read(m_address & 0x0f); + } + else if (m_address < 0x10) + { + // 0E-0F: I/O ports not supported + result = 0xff; + } + else if (m_address == 0xff) + { + // FF: ID code + result = 1; + } + return result; +} + + +//------------------------------------------------- +// read_status_hi - read the extended status +// register +//------------------------------------------------- + +uint8_t ym2610::read_status_hi() +{ + return m_eos_status & m_flag_mask; +} + + +//------------------------------------------------- +// read_data_hi - read the upper data register +//------------------------------------------------- + +uint8_t ym2610::read_data_hi() +{ + uint8_t result = 0; + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2610::read(uint32_t offset) +{ + uint8_t result = 0; + switch (offset & 3) + { + case 0: // status port, YM2203 compatible + result = read_status(); + break; + + case 1: // data port (only SSG) + result = read_data(); + break; + + case 2: // status port, extended + result = read_status_hi(); + break; + + case 3: // ADPCM-B data + result = read_data_hi(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2610::write_address(uint8_t data) +{ + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the data register +//------------------------------------------------- + +void ym2610::write_data(uint8_t data) +{ + // ignore if paired with upper address + if (bitfield(m_address, 8)) + return; + + if (m_address < 0x0e) + { + // 00-0D: write to SSG + m_ssg.write(m_address & 0x0f, data); + } + else if (m_address < 0x10) + { + // 0E-0F: I/O ports not supported + } + else if (m_address < 0x1c) + { + // 10-1B: write to ADPCM-B + // YM2610 effectively forces external mode on, and disables recording + if (m_address == 0x10) + data = (data | 0x20) & ~0x40; + m_adpcm_b.write(m_address & 0x0f, data); + } + else if (m_address == 0x1c) + { + // 1C: EOS flag reset + m_flag_mask = ~data & EOS_FLAGS_MASK; + m_eos_status &= ~(data & EOS_FLAGS_MASK); + } + else + { + // 1D-FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ym2610::write_address_hi(uint8_t data) +{ + // just set the address + m_address = 0x100 | data; +} + + +//------------------------------------------------- +// write_data_hi - handle a write to the upper +// data register +//------------------------------------------------- + +void ym2610::write_data_hi(uint8_t data) +{ + // ignore if paired with upper address + if (!bitfield(m_address, 8)) + return; + + if (m_address < 0x130) + { + // 100-12F: write to ADPCM-A + m_adpcm_a.write(m_address & 0x3f, data); + } + else + { + // 130-1FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2610::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // upper address port + write_address_hi(data); + break; + + case 3: // upper data port + write_data_hi(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym2610::generate(output_data *output, uint32_t numsamples) +{ + // FM output is just repeated the prescale number of times + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + if ((m_ssg_resampler.sampindex() + samp) % m_fm_samples_per_output == 0) + clock_fm_and_adpcm(); + output->data[0] = m_last_fm.data[0]; + output->data[1] = m_last_fm.data[1]; + } + + // resample the SSG as configured + m_ssg_resampler.resample(output - numsamples, numsamples); +} + + +//------------------------------------------------- +// update_prescale - update the prescale value, +// recomputing derived values +//------------------------------------------------- + +void ym2610::update_prescale() +{ + // Fidelity: ---- minimum ---- ---- medium ----- ---- maximum----- + // rate = clock/144 rate = clock/144 rate = clock/16 + // Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate + // 6 1:1 2:9 1:1 2:9 9:1 2:1 + + // compute the number of FM samples per output sample, and select the + // resampler function + if (m_fidelity == OPN_FIDELITY_MIN || m_fidelity == OPN_FIDELITY_MED) + { + m_fm_samples_per_output = 1; + m_ssg_resampler.configure(2, 9); + } + else + { + m_fm_samples_per_output = 9; + m_ssg_resampler.configure(2, 1); + } + + // if overriding the SSG, override the configuration with the nop + // resampler to at least keep the sample index moving forward + if (m_ssg.overridden()) + m_ssg_resampler.configure(0, 0); +} + + +//------------------------------------------------- +// clock_fm_and_adpcm - clock FM and ADPCM state +//------------------------------------------------- + +void ym2610::clock_fm_and_adpcm() +{ + // clock the system + uint32_t env_counter = m_fm.clock(m_fm_mask); + + // clock the ADPCM-A engine on every envelope cycle + if (bitfield(env_counter, 0, 2) == 0) + m_eos_status |= m_adpcm_a.clock(0x3f); + + // clock the ADPCM-B engine every cycle + m_adpcm_b.clock(); + + // we track the last ADPCM-B EOS value in bit 6 (which is hidden from callers); + // if it changed since the last sample, update the visible EOS state in bit 7 + uint8_t live_eos = ((m_adpcm_b.status() & adpcm_b_channel::STATUS_EOS) != 0) ? 0x40 : 0x00; + if (((live_eos ^ m_eos_status) & 0x40) != 0) + m_eos_status = (m_eos_status & ~0xc0) | live_eos | (live_eos << 1); + + // update the FM content; OPNB is 13-bit with no intermediate clipping + m_fm.output(m_last_fm.clear(), 1, 32767, m_fm_mask); + + // mix in the ADPCM and clamp + m_adpcm_a.output(m_last_fm, 0x3f); + m_adpcm_b.output(m_last_fm, 1); + m_last_fm.clamp16(); +} + + + +//********************************************************* +// YM2612 +//********************************************************* + +//------------------------------------------------- +// ym2612 - constructor +//------------------------------------------------- + +ym2612::ym2612(ymfm_interface &intf) : + m_address(0), + m_dac_data(0), + m_dac_enable(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2612::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2612::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_address); + state.save_restore(m_dac_data); + state.save_restore(m_dac_enable); + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym2612::read_status() +{ + uint8_t result = m_fm.status(); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2612::read(uint32_t offset) +{ + uint8_t result = 0; + switch (offset & 3) + { + case 0: // status port, YM2203 compatible + result = read_status(); + break; + + case 1: // data port (unused) + case 2: // status port, extended + case 3: // data port (unused) + debug::log_unexpected_read_write("Unexpected read from YM2612 offset %d\n", offset & 3); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2612::write_address(uint8_t data) +{ + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write_data - handle a write to the data +// register +//------------------------------------------------- + +void ym2612::write_data(uint8_t data) +{ + // ignore if paired with upper address + if (bitfield(m_address, 8)) + return; + + if (m_address == 0x2a) + { + // 2A: DAC data (most significant 8 bits) + m_dac_data = (m_dac_data & ~0x1fe) | ((data ^ 0x80) << 1); + } + else if (m_address == 0x2b) + { + // 2B: DAC enable (bit 7) + m_dac_enable = bitfield(data, 7); + } + else if (m_address == 0x2c) + { + // 2C: test/low DAC bit + m_dac_data = (m_dac_data & ~1) | bitfield(data, 3); + } + else + { + // 00-29, 2D-FF: write to FM + m_fm.write(m_address, data); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write_address_hi - handle a write to the upper +// address register +//------------------------------------------------- + +void ym2612::write_address_hi(uint8_t data) +{ + // just set the address + m_address = 0x100 | data; +} + + +//------------------------------------------------- +// write_data_hi - handle a write to the upper +// data register +//------------------------------------------------- + +void ym2612::write_data_hi(uint8_t data) +{ + // ignore if paired with upper address + if (!bitfield(m_address, 8)) + return; + + // 100-1FF: write to FM + m_fm.write(m_address, data); + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2612::write(uint32_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + + case 2: // upper address port + write_address_hi(data); + break; + + case 3: // upper data port + write_data_hi(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym2612::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // sum individual channels to apply DAC discontinuity on each + output->clear(); + output_data temp; + + // first do FM-only channels; OPN2 is 9-bit with intermediate clipping + int const last_fm_channel = m_dac_enable ? 5 : 6; + for (int chan = 0; chan < last_fm_channel; chan++) + { + m_fm.output(temp.clear(), 5, 256, 1 << chan); + output->data[0] += dac_discontinuity(temp.data[0]); + output->data[1] += dac_discontinuity(temp.data[1]); + } + + // add in DAC + if (m_dac_enable) + { + // DAC enabled: start with DAC value then add the first 5 channels only + int32_t dacval = dac_discontinuity(int16_t(m_dac_data << 7) >> 7); + output->data[0] += m_fm.regs().ch_output_0(0x102) ? dacval : dac_discontinuity(0); + output->data[1] += m_fm.regs().ch_output_1(0x102) ? dacval : dac_discontinuity(0); + } + + // output is technically multiplexed rather than mixed, but that requires + // a better sound mixer than we usually have, so just average over the six + // channels; also apply a 64/65 factor to account for the discontinuity + // adjustment above + output->data[0] = (output->data[0] * 128) * 64 / (6 * 65); + output->data[1] = (output->data[1] * 128) * 64 / (6 * 65); + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym3438::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // first do FM-only channels; OPN2C is 9-bit with intermediate clipping + if (!m_dac_enable) + { + // DAC disabled: all 6 channels sum together + m_fm.output(output->clear(), 5, 256, fm_engine::ALL_CHANNELS); + } + else + { + // DAC enabled: start with DAC value then add the first 5 channels only + int32_t dacval = int16_t(m_dac_data << 7) >> 7; + output->data[0] = m_fm.regs().ch_output_0(0x102) ? dacval : 0; + output->data[1] = m_fm.regs().ch_output_1(0x102) ? dacval : 0; + m_fm.output(*output, 5, 256, fm_engine::ALL_CHANNELS ^ (1 << 5)); + } + + // YM3438 doesn't have the same DAC discontinuity, though its output is + // multiplexed like the YM2612 + output->data[0] = (output->data[0] * 128) / 6; + output->data[1] = (output->data[1] * 128) / 6; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ymf276::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // first do FM-only channels; OPN2L is 14-bit with intermediate clipping + if (!m_dac_enable) + { + // DAC disabled: all 6 channels sum together + m_fm.output(output->clear(), 0, 8191, fm_engine::ALL_CHANNELS); + } + else + { + // DAC enabled: start with DAC value then add the first 5 channels only + int32_t dacval = int16_t(m_dac_data << 7) >> 7; + output->data[0] = m_fm.regs().ch_output_0(0x102) ? dacval : 0; + output->data[1] = m_fm.regs().ch_output_1(0x102) ? dacval : 0; + m_fm.output(*output, 0, 8191, fm_engine::ALL_CHANNELS ^ (1 << 5)); + } + + // YMF276 is properly mixed; it shifts down 1 bit before clamping + output->data[0] = clamp(output->data[0] >> 1, -32768, 32767); + output->data[1] = clamp(output->data[1] >> 1, -32768, 32767); + } +} + +} diff --git a/src/sound/ymfm/ymfm_opn.h b/src/sound/ymfm/ymfm_opn.h new file mode 100644 index 000000000..bab68ed93 --- /dev/null +++ b/src/sound/ymfm/ymfm_opn.h @@ -0,0 +1,802 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_OPN_H +#define YMFM_OPN_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_adpcm.h" +#include "ymfm_fm.h" +#include "ymfm_ssg.h" + +namespace ymfm +{ + +//********************************************************* +// REGISTER CLASSES +//********************************************************* + +// ======================> opn_registers_base + +// +// OPN register map: +// +// System-wide registers: +// 21 xxxxxxxx Test register +// 22 ----x--- LFO enable [OPNA+ only] +// -----xxx LFO rate [OPNA+ only] +// 24 xxxxxxxx Timer A value (upper 8 bits) +// 25 ------xx Timer A value (lower 2 bits) +// 26 xxxxxxxx Timer B value +// 27 xx------ CSM/Multi-frequency mode for channel #2 +// --x----- Reset timer B +// ---x---- Reset timer A +// ----x--- Enable timer B +// -----x-- Enable timer A +// ------x- Load timer B +// -------x Load timer A +// 28 x------- Key on/off operator 4 +// -x------ Key on/off operator 3 +// --x----- Key on/off operator 2 +// ---x---- Key on/off operator 1 +// ------xx Channel select +// +// Per-channel registers (channel in address bits 0-1) +// Note that all these apply to address+100 as well on OPNA+ +// A0-A3 xxxxxxxx Frequency number lower 8 bits +// A4-A7 --xxx--- Block (0-7) +// -----xxx Frequency number upper 3 bits +// B0-B3 --xxx--- Feedback level for operator 1 (0-7) +// -----xxx Operator connection algorithm (0-7) +// B4-B7 x------- Pan left [OPNA] +// -x------ Pan right [OPNA] +// --xx---- LFO AM shift (0-3) [OPNA+ only] +// -----xxx LFO PM depth (0-7) [OPNA+ only] +// +// Per-operator registers (channel in address bits 0-1, operator in bits 2-3) +// Note that all these apply to address+100 as well on OPNA+ +// 30-3F -xxx---- Detune value (0-7) +// ----xxxx Multiple value (0-15) +// 40-4F -xxxxxxx Total level (0-127) +// 50-5F xx------ Key scale rate (0-3) +// ---xxxxx Attack rate (0-31) +// 60-6F x------- LFO AM enable [OPNA] +// ---xxxxx Decay rate (0-31) +// 70-7F ---xxxxx Sustain rate (0-31) +// 80-8F xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// 90-9F ----x--- SSG-EG enable +// -----xxx SSG-EG envelope (0-7) +// +// Special multi-frequency registers (channel implicitly #2; operator in address bits 0-1) +// A8-AB xxxxxxxx Frequency number lower 8 bits +// AC-AF --xxx--- Block (0-7) +// -----xxx Frequency number upper 3 bits +// +// Internal (fake) registers: +// B8-BB --xxxxxx Latched frequency number upper bits (from A4-A7) +// BC-BF --xxxxxx Latched frequency number upper bits (from AC-AF) +// + +template +class opn_registers_base : public fm_registers_base +{ +public: + // constants + static constexpr uint32_t OUTPUTS = IsOpnA ? 2 : 1; + static constexpr uint32_t CHANNELS = IsOpnA ? 6 : 3; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 4; + static constexpr uint32_t WAVEFORMS = 1; + static constexpr uint32_t REGISTERS = IsOpnA ? 0x200 : 0x100; + static constexpr uint32_t REG_MODE = 0x27; + static constexpr uint32_t DEFAULT_PRESCALE = 6; + static constexpr uint32_t EG_CLOCK_DIVIDER = 3; + static constexpr bool EG_HAS_SSG = true; + static constexpr bool MODULATOR_DELAY = false; + static constexpr uint32_t CSM_TRIGGER_MASK = 1 << 2; + static constexpr uint8_t STATUS_TIMERA = 0x01; + static constexpr uint8_t STATUS_TIMERB = 0x02; + static constexpr uint8_t STATUS_BUSY = 0x80; + static constexpr uint8_t STATUS_IRQ = 0; + + // constructor + opn_registers_base(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + if (!IsOpnA) + return chnum; + else + return (chnum % 3) + 0x100 * (chnum / 3); + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + if (!IsOpnA) + return opnum + opnum / 3; + else + return (opnum % 12) + ((opnum % 12) / 3) + 0x100 * (opnum / 12); + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // read a register value + uint8_t read(uint16_t index) const { return m_regdata[index]; } + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // reset the LFO + void reset_lfo() { m_lfo_counter = 0; } + + // return the AM offset from LFO for the given channel + uint32_t lfo_am_offset(uint32_t choffs) const; + + // return LFO/noise states + uint32_t noise_state() const { return 0; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // system-wide registers + uint32_t test() const { return byte(0x21, 0, 8); } + uint32_t lfo_enable() const { return IsOpnA ? byte(0x22, 3, 1) : 0; } + uint32_t lfo_rate() const { return IsOpnA ? byte(0x22, 0, 3) : 0; } + uint32_t timer_a_value() const { return word(0x24, 0, 8, 0x25, 0, 2); } + uint32_t timer_b_value() const { return byte(0x26, 0, 8); } + uint32_t csm() const { return (byte(0x27, 6, 2) == 2); } + uint32_t multi_freq() const { return (byte(0x27, 6, 2) != 0); } + uint32_t reset_timer_b() const { return byte(0x27, 5, 1); } + uint32_t reset_timer_a() const { return byte(0x27, 4, 1); } + uint32_t enable_timer_b() const { return byte(0x27, 3, 1); } + uint32_t enable_timer_a() const { return byte(0x27, 2, 1); } + uint32_t load_timer_b() const { return byte(0x27, 1, 1); } + uint32_t load_timer_a() const { return byte(0x27, 0, 1); } + uint32_t multi_block_freq(uint32_t num) const { return word(0xac, 0, 6, 0xa8, 0, 8, num); } + + // per-channel registers + uint32_t ch_block_freq(uint32_t choffs) const { return word(0xa4, 0, 6, 0xa0, 0, 8, choffs); } + uint32_t ch_feedback(uint32_t choffs) const { return byte(0xb0, 3, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return byte(0xb0, 0, 3, choffs); } + uint32_t ch_output_any(uint32_t choffs) const { return IsOpnA ? byte(0xb4, 6, 2, choffs) : 1; } + uint32_t ch_output_0(uint32_t choffs) const { return IsOpnA ? byte(0xb4, 7, 1, choffs) : 1; } + uint32_t ch_output_1(uint32_t choffs) const { return IsOpnA ? byte(0xb4, 6, 1, choffs) : 0; } + uint32_t ch_output_2(uint32_t choffs) const { return 0; } + uint32_t ch_output_3(uint32_t choffs) const { return 0; } + uint32_t ch_lfo_am_sens(uint32_t choffs) const { return IsOpnA ? byte(0xb4, 4, 2, choffs) : 0; } + uint32_t ch_lfo_pm_sens(uint32_t choffs) const { return IsOpnA ? byte(0xb4, 0, 3, choffs) : 0; } + + // per-operator registers + uint32_t op_detune(uint32_t opoffs) const { return byte(0x30, 4, 3, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return byte(0x30, 0, 4, opoffs); } + uint32_t op_total_level(uint32_t opoffs) const { return byte(0x40, 0, 7, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return byte(0x50, 6, 2, opoffs); } + uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x50, 0, 5, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return byte(0x60, 0, 5, opoffs); } + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return IsOpnA ? byte(0x60, 7, 1, opoffs) : 0; } + uint32_t op_sustain_rate(uint32_t opoffs) const { return byte(0x70, 0, 5, opoffs); } + uint32_t op_sustain_level(uint32_t opoffs) const { return byte(0x80, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return byte(0x80, 0, 4, opoffs); } + uint32_t op_ssg_eg_enable(uint32_t opoffs) const { return byte(0x90, 3, 1, opoffs); } + uint32_t op_ssg_eg_mode(uint32_t opoffs) const { return byte(0x90, 0, 3, opoffs); } + +protected: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // internal state + uint32_t m_lfo_counter; // LFO counter + uint8_t m_lfo_am; // current LFO AM value + uint8_t m_regdata[REGISTERS]; // register data + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + +using opn_registers = opn_registers_base; +using opna_registers = opn_registers_base; + + + +//********************************************************* +// OPN IMPLEMENTATION CLASSES +//********************************************************* + +// A note about prescaling and sample rates. +// +// YM2203, YM2608, and YM2610 contain an onboard SSG (basically, a YM2149). +// In order to properly generate sound at fully fidelity, the output sample +// rate of the YM2149 must be input_clock / 8. This is much higher than the +// FM needs, but in the interest of keeping things simple, the OPN generate +// functions will output at the higher rate and just replicate the last FM +// sample as many times as needed. +// +// To make things even more complicated, the YM2203 and YM2608 allow for +// software-controlled prescaling, which affects the FM and SSG clocks in +// different ways. There are three settings: divide by 6/4 (FM/SSG); divide +// by 3/2; and divide by 2/1. +// +// Thus, the minimum output sample rate needed by each part of the chip +// varies with the prescale as follows: +// +// ---- YM2203 ----- ---- YM2608 ----- ---- YM2610 ----- +// Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate +// 6 /72 /16 /144 /32 /144 /32 +// 3 /36 /8 /72 /16 +// 2 /24 /4 /48 /8 +// +// If we standardized on the fastest SSG rate, we'd end up with the following +// (ratios are output_samples:source_samples): +// +// ---- YM2203 ----- ---- YM2608 ----- ---- YM2610 ----- +// rate = clock/4 rate = clock/8 rate = clock/16 +// Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate +// 6 18:1 4:1 18:1 4:1 9:1 2:1 +// 3 9:1 2:1 9:1 2:1 +// 2 6:1 1:1 6:1 1:1 +// +// However, that's a pretty big performance hit for minimal gain. Going to +// the other extreme, we could standardize on the fastest FM rate, but then +// at least one prescale case (3) requires the FM to be smeared across two +// output samples: +// +// ---- YM2203 ----- ---- YM2608 ----- ---- YM2610 ----- +// rate = clock/24 rate = clock/48 rate = clock/144 +// Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate +// 6 3:1 2:3 3:1 2:3 1:1 2:9 +// 3 1.5:1 1:3 1.5:1 1:3 +// 2 1:1 1:6 1:1 1:6 +// +// Stepping back one factor of 2 addresses that issue: +// +// ---- YM2203 ----- ---- YM2608 ----- ---- YM2610 ----- +// rate = clock/12 rate = clock/24 rate = clock/144 +// Prescale FM rate SSG rate FM rate SSG rate FM rate SSG rate +// 6 6:1 4:3 6:1 4:3 1:1 2:9 +// 3 3:1 2:3 3:1 2:3 +// 2 2:1 1:3 2:1 1:3 +// +// This gives us three levels of output fidelity: +// OPN_FIDELITY_MAX -- highest sample rate, using fastest SSG rate +// OPN_FIDELITY_MIN -- lowest sample rate, using fastest FM rate +// OPN_FIDELITY_MED -- medium sample rate such that FM is never smeared +// +// At the maximum clocks for YM2203/YM2608 (4Mhz/8MHz), these rates will +// end up as: +// OPN_FIDELITY_MAX = 1000kHz +// OPN_FIDELITY_MIN = 166kHz +// OPN_FIEDLITY_MED = 333kHz + + +// ======================> opn_fidelity + +enum opn_fidelity : uint8_t +{ + OPN_FIDELITY_MAX, + OPN_FIDELITY_MIN, + OPN_FIDELITY_MED, + + OPN_FIDELITY_DEFAULT = OPN_FIDELITY_MAX +}; + + +// ======================> ssg_resampler + +template +class ssg_resampler +{ +private: + // helper to add the last computed value to the sums, applying the given scale + void add_last(int32_t &sum0, int32_t &sum1, int32_t &sum2, int32_t scale = 1); + + // helper to clock a new value and then add it to the sums, applying the given scale + void clock_and_add(int32_t &sum0, int32_t &sum1, int32_t &sum2, int32_t scale = 1); + + // helper to write the sums to the appropriate outputs, applying the given + // divisor to the final result + void write_to_output(OutputType *output, int32_t sum0, int32_t sum1, int32_t sum2, int32_t divisor = 1); + +public: + // constructor + ssg_resampler(ssg_engine &ssg); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // get the current sample index + uint32_t sampindex() const { return m_sampindex; } + + // configure the ratio + void configure(uint8_t outsamples, uint8_t srcsamples); + + // resample + void resample(OutputType *output, uint32_t numsamples) + { + (this->*m_resampler)(output, numsamples); + } + +private: + // resample SSG output to the target at a rate of 1 SSG sample + // to every n output samples + template + void resample_n_1(OutputType *output, uint32_t numsamples); + + // resample SSG output to the target at a rate of n SSG samples + // to every 1 output sample + template + void resample_1_n(OutputType *output, uint32_t numsamples); + + // resample SSG output to the target at a rate of 9 SSG samples + // to every 2 output samples + void resample_2_9(OutputType *output, uint32_t numsamples); + + // resample SSG output to the target at a rate of 3 SSG samples + // to every 1 output sample + void resample_1_3(OutputType *output, uint32_t numsamples); + + // resample SSG output to the target at a rate of 3 SSG samples + // to every 2 output samples + void resample_2_3(OutputType *output, uint32_t numsamples); + + // resample SSG output to the target at a rate of 3 SSG samples + // to every 4 output samples + void resample_4_3(OutputType *output, uint32_t numsamples); + + // no-op resampler + void resample_nop(OutputType *output, uint32_t numsamples); + + // define a pointer type + using resample_func = void (ssg_resampler::*)(OutputType *output, uint32_t numsamples); + + // internal state + ssg_engine &m_ssg; + uint32_t m_sampindex; + resample_func m_resampler; + ssg_engine::output_data m_last; +}; + + +// ======================> ym2203 + +class ym2203 +{ +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t FM_OUTPUTS = fm_engine::OUTPUTS; + static constexpr uint32_t SSG_OUTPUTS = ssg_engine::OUTPUTS; + static constexpr uint32_t OUTPUTS = FM_OUTPUTS + SSG_OUTPUTS; + using output_data = ymfm_output; + + // constructor + ym2203(ymfm_interface &intf); + + // configuration + void ssg_override(ssg_override &intf) { m_ssg.override(intf); } + void set_fidelity(opn_fidelity fidelity) { m_fidelity = fidelity; update_prescale(m_fm.clock_prescale()); } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const + { + switch (m_fidelity) + { + case OPN_FIDELITY_MIN: return input_clock / 24; + case OPN_FIDELITY_MED: return input_clock / 12; + default: + case OPN_FIDELITY_MAX: return input_clock / 4; + } + } + uint32_t ssg_effective_clock(uint32_t input_clock) const { uint32_t scale = m_fm.clock_prescale() * 2 / 3; return input_clock * 2 / scale; } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal helpers + void update_prescale(uint8_t prescale); + void clock_fm(); + + // internal state + opn_fidelity m_fidelity; // configured fidelity + uint8_t m_address; // address register + uint8_t m_fm_samples_per_output; // how many samples to repeat + fm_engine::output_data m_last_fm; // last FM output + fm_engine m_fm; // core FM engine + ssg_engine m_ssg; // SSG engine + ssg_resampler m_ssg_resampler; // SSG resampler helper +}; + + + +//********************************************************* +// OPNA IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym2608 + +class ym2608 +{ + static constexpr uint8_t STATUS_ADPCM_B_EOS = 0x04; + static constexpr uint8_t STATUS_ADPCM_B_BRDY = 0x08; + static constexpr uint8_t STATUS_ADPCM_B_ZERO = 0x10; + static constexpr uint8_t STATUS_ADPCM_B_PLAYING = 0x20; + +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t FM_OUTPUTS = fm_engine::OUTPUTS; + static constexpr uint32_t SSG_OUTPUTS = 1; + static constexpr uint32_t OUTPUTS = FM_OUTPUTS + SSG_OUTPUTS; + using output_data = ymfm_output; + + // constructor + ym2608(ymfm_interface &intf); + + // configuration + void ssg_override(ssg_override &intf) { m_ssg.override(intf); } + void set_fidelity(opn_fidelity fidelity) { m_fidelity = fidelity; update_prescale(m_fm.clock_prescale()); } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const + { + switch (m_fidelity) + { + case OPN_FIDELITY_MIN: return input_clock / 48; + case OPN_FIDELITY_MED: return input_clock / 24; + default: + case OPN_FIDELITY_MAX: return input_clock / 8; + } + } + uint32_t ssg_effective_clock(uint32_t input_clock) const { uint32_t scale = m_fm.clock_prescale() * 2 / 3; return input_clock / scale; } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data(); + uint8_t read_status_hi(); + uint8_t read_data_hi(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write_data_hi(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal helpers + void update_prescale(uint8_t prescale); + void clock_fm_and_adpcm(); + + // internal state + opn_fidelity m_fidelity; // configured fidelity + uint16_t m_address; // address register + uint8_t m_fm_samples_per_output; // how many samples to repeat + uint8_t m_irq_enable; // IRQ enable register + uint8_t m_flag_control; // flag control register + fm_engine::output_data m_last_fm; // last FM output + fm_engine m_fm; // core FM engine + ssg_engine m_ssg; // SSG engine + ssg_resampler m_ssg_resampler; // SSG resampler helper + adpcm_a_engine m_adpcm_a; // ADPCM-A engine + adpcm_b_engine m_adpcm_b; // ADPCM-B engine +}; + + +// ======================> ymf288 + +class ymf288 +{ +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t FM_OUTPUTS = fm_engine::OUTPUTS; + static constexpr uint32_t SSG_OUTPUTS = 1; + static constexpr uint32_t OUTPUTS = FM_OUTPUTS + SSG_OUTPUTS; + using output_data = ymfm_output; + + // constructor + ymf288(ymfm_interface &intf); + + // configuration + void ssg_override(ssg_override &intf) { m_ssg.override(intf); } + void set_fidelity(opn_fidelity fidelity) { m_fidelity = fidelity; update_prescale(); } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const + { + switch (m_fidelity) + { + case OPN_FIDELITY_MIN: return input_clock / 144; + case OPN_FIDELITY_MED: return input_clock / 144; + default: + case OPN_FIDELITY_MAX: return input_clock / 16; + } + } + uint32_t ssg_effective_clock(uint32_t input_clock) const { return input_clock / 4; } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data(); + uint8_t read_status_hi(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write_data_hi(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal helpers + bool ymf288_mode() { return ((m_fm.regs().read(0x20) & 0x02) != 0); } + void update_prescale(); + void clock_fm_and_adpcm(); + + // internal state + opn_fidelity m_fidelity; // configured fidelity + uint16_t m_address; // address register + uint8_t m_fm_samples_per_output; // how many samples to repeat + uint8_t m_irq_enable; // IRQ enable register + uint8_t m_flag_control; // flag control register + fm_engine::output_data m_last_fm; // last FM output + fm_engine m_fm; // core FM engine + ssg_engine m_ssg; // SSG engine + ssg_resampler m_ssg_resampler; // SSG resampler helper + adpcm_a_engine m_adpcm_a; // ADPCM-A engine +}; + + +// ======================> ym2610/ym2610b + +class ym2610 +{ + static constexpr uint8_t EOS_FLAGS_MASK = 0xbf; + +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t FM_OUTPUTS = fm_engine::OUTPUTS; + static constexpr uint32_t SSG_OUTPUTS = 1; + static constexpr uint32_t OUTPUTS = FM_OUTPUTS + SSG_OUTPUTS; + using output_data = ymfm_output; + + // constructor + ym2610(ymfm_interface &intf, uint8_t channel_mask = 0x36); + + // configuration + void ssg_override(ssg_override &intf) { m_ssg.override(intf); } + void set_fidelity(opn_fidelity fidelity) { m_fidelity = fidelity; update_prescale(); } + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const + { + switch (m_fidelity) + { + case OPN_FIDELITY_MIN: return input_clock / 144; + case OPN_FIDELITY_MED: return input_clock / 144; + default: + case OPN_FIDELITY_MAX: return input_clock / 16; + } + } + uint32_t ssg_effective_clock(uint32_t input_clock) const { return input_clock / 4; } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read_data(); + uint8_t read_status_hi(); + uint8_t read_data_hi(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write_data_hi(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal helpers + void update_prescale(); + void clock_fm_and_adpcm(); + + // internal state + opn_fidelity m_fidelity; // configured fidelity + uint16_t m_address; // address register + uint8_t const m_fm_mask; // FM channel mask + uint8_t m_fm_samples_per_output; // how many samples to repeat + uint8_t m_eos_status; // end-of-sample signals + uint8_t m_flag_mask; // flag mask control + fm_engine::output_data m_last_fm; // last FM output + fm_engine m_fm; // core FM engine + ssg_engine m_ssg; // core FM engine + ssg_resampler m_ssg_resampler; // SSG resampler helper + adpcm_a_engine m_adpcm_a; // ADPCM-A engine + adpcm_b_engine m_adpcm_b; // ADPCM-B engine +}; + +class ym2610b : public ym2610 +{ +public: + // constructor + ym2610b(ymfm_interface &intf) : ym2610(intf, 0x3f) { } +}; + + +// ======================> ym2612 + +class ym2612 +{ +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + using output_data = fm_engine::output_data; + + // constructor + ym2612(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write_address_hi(uint8_t data); + void write_data_hi(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // simulate the DAC discontinuity + constexpr int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 3) : (value + 4); } + + // internal state + uint16_t m_address; // address register + uint16_t m_dac_data; // 9-bit DAC data + uint8_t m_dac_enable; // DAC enabled? + fm_engine m_fm; // core FM engine +}; + + +// ======================> ym3438 + +class ym3438 : public ym2612 +{ +public: + ym3438(ymfm_interface &intf) : ym2612(intf) { } + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); +}; + + +// ======================> ymf276 + +class ymf276 : public ym2612 +{ +public: + ymf276(ymfm_interface &intf) : ym2612(intf) { } + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples); +}; + +} + + +#endif // YMFM_OPN_H diff --git a/src/sound/ymfm/ymfm_opq.cpp b/src/sound/ymfm/ymfm_opq.cpp new file mode 100644 index 000000000..3467c0ddf --- /dev/null +++ b/src/sound/ymfm/ymfm_opq.cpp @@ -0,0 +1,480 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_opq.h" +#include "ymfm_fm.ipp" + +#define TEMPORARY_DEBUG_PRINTS (0) + +// +// OPQ (aka YM3806/YM3533) +// +// This chip is not officially documented as far as I know. What I have +// comes from Jari Kangas' work on reverse engineering the PSR70: +// +// https://github.com/JKN0/PSR70-reverse +// +// OPQ appears be bsaically a mixture of OPM and OPN. +// + +namespace ymfm +{ + +//********************************************************* +// OPQ SPECIFICS +//********************************************************* + +//------------------------------------------------- +// opq_registers - constructor +//------------------------------------------------- + +opq_registers::opq_registers() : + m_lfo_counter(0), + m_lfo_am(0) +{ + // create the waveforms + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[0][index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); + + uint16_t zeroval = m_waveform[0][0]; + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[1][index] = bitfield(index, 9) ? zeroval : m_waveform[0][index]; +} + + +//------------------------------------------------- +// reset - reset to initial state +//------------------------------------------------- + +void opq_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + + // enable output on both channels by default + m_regdata[0x10] = m_regdata[0x11] = m_regdata[0x12] = m_regdata[0x13] = 0xc0; + m_regdata[0x14] = m_regdata[0x15] = m_regdata[0x16] = m_regdata[0x17] = 0xc0; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void opq_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_lfo_counter); + state.save_restore(m_lfo_am); + state.save_restore(m_regdata); +} + + +//------------------------------------------------- +// operator_map - return an array of operator +// indices for each channel; for OPM this is fixed +//------------------------------------------------- + +void opq_registers::operator_map(operator_mapping &dest) const +{ + // seems like the operators are not swizzled like they are on OPM/OPN? + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 8, 16, 24 ), // Channel 0 operators + operator_list( 1, 9, 17, 25 ), // Channel 1 operators + operator_list( 2, 10, 18, 26 ), // Channel 2 operators + operator_list( 3, 11, 19, 27 ), // Channel 3 operators + operator_list( 4, 12, 20, 28 ), // Channel 4 operators + operator_list( 5, 13, 21, 29 ), // Channel 5 operators + operator_list( 6, 14, 22, 30 ), // Channel 6 operators + operator_list( 7, 15, 23, 31 ), // Channel 7 operators + } }; + dest = s_fixed_map; +} + + +//------------------------------------------------- +// write - handle writes to the register array +//------------------------------------------------- + +bool opq_registers::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) +{ + assert(index < REGISTERS); + + // detune/multiple share a register based on the MSB of what is written + // remap the multiple values to 100-11F + if ((index & 0xe0) == 0x40 && bitfield(data, 7) != 0) + index += 0xc0; + + m_regdata[index] = data; + + // handle writes to the key on index + if (index == 0x05) + { + channel = bitfield(data, 0, 3); + opmask = bitfield(data, 3, 4); + return true; + } + return false; +} + + +//------------------------------------------------- +// clock_noise_and_lfo - clock the noise and LFO, +// handling clock division, depth, and waveform +// computations +//------------------------------------------------- + +int32_t opq_registers::clock_noise_and_lfo() +{ + // OPQ LFO is not well-understood, but the enable and rate values + // look a lot like OPN, so we'll crib from there as a starting point + + // if LFO not enabled (not present on OPN), quick exit with 0s + if (!lfo_enable()) + { + m_lfo_counter = 0; + m_lfo_am = 0; + return 0; + } + + // this table is based on converting the frequencies in the applications + // manual to clock dividers, based on the assumption of a 7-bit LFO value + static uint8_t const lfo_max_count[8] = { 109, 78, 72, 68, 63, 45, 9, 6 }; + uint32_t subcount = uint8_t(m_lfo_counter++); + + // when we cross the divider count, add enough to zero it and cause an + // increment at bit 8; the 7-bit value lives from bits 8-14 + if (subcount >= lfo_max_count[lfo_rate()]) + m_lfo_counter += 0x101 - subcount; + + // AM value is 7 bits, staring at bit 8; grab the low 6 directly + m_lfo_am = bitfield(m_lfo_counter, 8, 6); + + // first half of the AM period (bit 6 == 0) is inverted + if (bitfield(m_lfo_counter, 8+6) == 0) + m_lfo_am ^= 0x3f; + + // PM value is 5 bits, starting at bit 10; grab the low 3 directly + int32_t pm = bitfield(m_lfo_counter, 10, 3); + + // PM is reflected based on bit 3 + if (bitfield(m_lfo_counter, 10+3)) + pm ^= 7; + + // PM is negated based on bit 4 + return bitfield(m_lfo_counter, 10+4) ? -pm : pm; +} + + +//------------------------------------------------- +// lfo_am_offset - return the AM offset from LFO +// for the given channel +//------------------------------------------------- + +uint32_t opq_registers::lfo_am_offset(uint32_t choffs) const +{ + // OPM maps AM quite differently from OPN + + // shift value for AM sensitivity is [*, 0, 1, 2], + // mapping to values of [0, 23.9, 47.8, and 95.6dB] + uint32_t am_sensitivity = ch_lfo_am_sens(choffs); + if (am_sensitivity == 0) + return 0; + + // QUESTION: see OPN note below for the dB range mapping; it applies + // here as well + + // raw LFO AM value on OPM is 0-FF, which is already a factor of 2 + // larger than the OPN below, putting our staring point at 2x theirs; + // this works out since our minimum is 2x their maximum + return m_lfo_am << (am_sensitivity - 1); +} + + +//------------------------------------------------- +// cache_operator_data - fill the operator cache +// with prefetched data +//------------------------------------------------- + +void opq_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) +{ + // set up the easy stuff + cache.waveform = &m_waveform[op_waveform(opoffs)][0]; + + // get frequency from the appropriate registers + uint32_t block_freq = cache.block_freq = (opoffs & 8) ? ch_block_freq_24(choffs) : ch_block_freq_13(choffs); + + // compute the keycode: block_freq is: + // + // BBBFFFFFFFFFFFF + // ^^^^??? + // + // keycode is not understood, so just guessing it is like OPN: + // the 5-bit keycode uses the top 4 bits plus a magic formula + // for the final bit + uint32_t keycode = bitfield(block_freq, 11, 4) << 1; + + // lowest bit is determined by a mix of next lower FNUM bits + // according to this equation from the YM2608 manual: + // + // (F11 & (F10 | F9 | F8)) | (!F11 & F10 & F9 & F8) + // + // for speed, we just look it up in a 16-bit constant + keycode |= bitfield(0xfe80, bitfield(block_freq, 8, 4)); + + // detune adjustment: the detune values supported by the OPQ are + // a much larger range (6 bits vs 3 bits) compared to any other + // known FM chip; based on experiments, it seems that the extra + // bits provide a bigger detune range rather than finer control, + // so until we get true measurements just assemble a net detune + // value by summing smaller detunes + int32_t detune = int32_t(op_detune(opoffs)) - 0x20; + int32_t abs_detune = std::abs(detune); + int32_t adjust = (abs_detune / 3) * detune_adjustment(3, keycode) + detune_adjustment(abs_detune % 3, keycode); + cache.detune = (detune >= 0) ? adjust : -adjust; + + // multiple value, as an x.1 value (0 means 0.5) + static const uint8_t s_multiple_map[16] = { 1,2,4,6,8,10,12,14,16,18,20,24,30,32,34,36 }; + cache.multiple = s_multiple_map[op_multiple(opoffs)]; + + // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on + // block_freq, detune, and multiple, so compute it after we've done those + if (lfo_enable() == 0 || ch_lfo_pm_sens(choffs) == 0) + cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0); + else + cache.phase_step = opdata_cache::PHASE_STEP_DYNAMIC; + + // total level, scaled by 8 + cache.total_level = op_total_level(opoffs) << 3; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = op_sustain_level(opoffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // determine KSR adjustment for enevlope rates + uint32_t ksrval = keycode >> (op_ksr(opoffs) ^ 3); + cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval); + cache.eg_rate[EG_REVERB] = (ch_reverb(choffs) != 0) ? 5*4 : cache.eg_rate[EG_RELEASE]; + cache.eg_shift = 0; +} + + +//------------------------------------------------- +// compute_phase_step - compute the phase step +//------------------------------------------------- + +uint32_t opq_registers::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm) +{ + // OPN phase calculation has only a single detune parameter + // and uses FNUMs instead of keycodes + + // extract frequency number (low 12 bits of block_freq) + uint32_t fnum = bitfield(cache.block_freq, 0, 12); + + // if there's a non-zero PM sensitivity, compute the adjustment + uint32_t pm_sensitivity = ch_lfo_pm_sens(choffs); + if (pm_sensitivity != 0) + { + // apply the phase adjustment based on the upper 7 bits + // of FNUM and the PM depth parameters + fnum += opn_lfo_pm_phase_adjustment(bitfield(cache.block_freq, 5, 7), pm_sensitivity, lfo_raw_pm); + + // keep fnum to 12 bits + fnum &= 0xfff; + } + + // apply block shift to compute phase step + uint32_t block = bitfield(cache.block_freq, 12, 3); + uint32_t phase_step = (fnum << block) >> 2; + + // apply detune based on the keycode + phase_step += cache.detune; + + // clamp to 17 bits in case detune overflows + // QUESTION: is this specific to the YM2612/3438? + phase_step &= 0x1ffff; + + // apply frequency multiplier (which is cached as an x.1 value) + return (phase_step * cache.multiple) >> 1; +} + + +//------------------------------------------------- +// log_keyon - log a key-on event +//------------------------------------------------- + +std::string opq_registers::log_keyon(uint32_t choffs, uint32_t opoffs) +{ + uint32_t chnum = choffs; + uint32_t opnum = opoffs; + + char buffer[256]; + char *end = &buffer[0]; + + end += sprintf(end, "%u.%02u freq=%04X dt=%+2d fb=%u alg=%X mul=%X tl=%02X ksr=%u adsr=%02X/%02X/%02X/%X sl=%X out=%c%c", + chnum, opnum, + (opoffs & 1) ? ch_block_freq_24(choffs) : ch_block_freq_13(choffs), + int32_t(op_detune(opoffs)) - 0x20, + ch_feedback(choffs), + ch_algorithm(choffs), + op_multiple(opoffs), + op_total_level(opoffs), + op_ksr(opoffs), + op_attack_rate(opoffs), + op_decay_rate(opoffs), + op_sustain_rate(opoffs), + op_release_rate(opoffs), + op_sustain_level(opoffs), + ch_output_0(choffs) ? 'L' : '-', + ch_output_1(choffs) ? 'R' : '-'); + + bool am = (lfo_enable() && op_lfo_am_enable(opoffs) && ch_lfo_am_sens(choffs) != 0); + if (am) + end += sprintf(end, " am=%u", ch_lfo_am_sens(choffs)); + bool pm = (lfo_enable() && ch_lfo_pm_sens(choffs) != 0); + if (pm) + end += sprintf(end, " pm=%u", ch_lfo_pm_sens(choffs)); + if (am || pm) + end += sprintf(end, " lfo=%02X", lfo_rate()); + if (ch_reverb(choffs)) + end += sprintf(end, " reverb"); + + return buffer; +} + + + +//********************************************************* +// YM3806 +//********************************************************* + +//------------------------------------------------- +// ym3806 - constructor +//------------------------------------------------- + +ym3806::ym3806(ymfm_interface &intf) : + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym3806::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym3806::save_restore(ymfm_saved_state &state) +{ + m_fm.save_restore(state); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym3806::read_status() +{ + uint8_t result = m_fm.status(); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym3806::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset) + { + case 0: // status port + result = read_status(); + break; + + default: // unknown + debug::log_unexpected_read_write("Unexpected read from YM3806 offset %02X\n", offset); + break; + } +if (TEMPORARY_DEBUG_PRINTS && offset != 0) printf("Read %02X = %02X\n", offset, result); + return result; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym3806::write(uint32_t offset, uint8_t data) +{ +if (TEMPORARY_DEBUG_PRINTS && (offset != 3 || data != 0x71)) printf("Write %02X = %02X\n", offset, data); + // write the FM register + m_fm.write(offset, data); +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym3806::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; YM3806 is full 14-bit with no intermediate clipping + m_fm.output(output->clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // YM3608 appears to go through a YM3012 DAC, which means we want to apply + // the FP truncation logic to the outputs + output->roundtrip_fp(); + } +} + +} diff --git a/src/sound/ymfm/ymfm_opq.h b/src/sound/ymfm/ymfm_opq.h new file mode 100644 index 000000000..f530ac070 --- /dev/null +++ b/src/sound/ymfm/ymfm_opq.h @@ -0,0 +1,293 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_OPQ_H +#define YMFM_OPQ_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_fm.h" + +namespace ymfm +{ + +//********************************************************* +// REGISTER CLASSES +//********************************************************* + +// ======================> opq_registers + +// +// OPQ register map: +// +// System-wide registers: +// 03 xxxxxxxx Timer control (unknown; 0x71 causes interrupts at ~10ms) +// 04 ----x--- LFO disable +// -----xxx LFO frequency (0=~4Hz, 6=~10Hz, 7=~47Hz) +// 05 -x------ Key on/off operator 4 +// --x----- Key on/off operator 3 +// ---x---- Key on/off operator 2 +// ----x--- Key on/off operator 1 +// -----xxx Channel select +// +// Per-channel registers (channel in address bits 0-2) +// 10-17 x------- Pan right +// -x------ Pan left +// --xxx--- Feedback level for operator 1 (0-7) +// -----xxx Operator connection algorithm (0-7) +// 18-1F x------- Reverb +// -xxx---- PM sensitivity +// ------xx AM shift +// 20-27 -xxx---- Block (0-7), Operator 2 & 4 +// ----xxxx Frequency number upper 4 bits, Operator 2 & 4 +// 28-2F -xxx---- Block (0-7), Operator 1 & 3 +// ----xxxx Frequency number upper 4 bits, Operator 1 & 3 +// 30-37 xxxxxxxx Frequency number lower 8 bits, Operator 2 & 4 +// 38-3F xxxxxxxx Frequency number lower 8 bits, Operator 1 & 3 +// +// Per-operator registers (channel in address bits 0-2, operator in bits 3-4) +// 40-5F 0-xxxxxx Detune value (0-63) +// 1---xxxx Multiple value (0-15) +// 60-7F -xxxxxxx Total level (0-127) +// 80-9F xx------ Key scale rate (0-3) +// ---xxxxx Attack rate (0-31) +// A0-BF x------- LFO AM enable, retrigger disable +// x------ Waveform select +// ---xxxxx Decay rate (0-31) +// C0-DF ---xxxxx Sustain rate (0-31) +// E0-FF xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// +// Diffs from OPM: +// - 2 frequencies/channel +// - retrigger disable +// - 2 waveforms +// - uses FNUM +// - reverb behavior +// - larger detune range +// +// Questions: +// - timer information is pretty light +// - how does echo work? +// - + +class opq_registers : public fm_registers_base +{ +public: + // constants + static constexpr uint32_t OUTPUTS = 2; + static constexpr uint32_t CHANNELS = 8; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 4; + static constexpr uint32_t WAVEFORMS = 2; + static constexpr uint32_t REGISTERS = 0x120; + static constexpr uint32_t REG_MODE = 0x03; + static constexpr uint32_t DEFAULT_PRESCALE = 2; + static constexpr uint32_t EG_CLOCK_DIVIDER = 3; + static constexpr bool EG_HAS_REVERB = true; + static constexpr bool MODULATOR_DELAY = false; + static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS; + static constexpr uint8_t STATUS_TIMERA = 0; + static constexpr uint8_t STATUS_TIMERB = 0x04; + static constexpr uint8_t STATUS_BUSY = 0x80; + static constexpr uint8_t STATUS_IRQ = 0; + + // constructor + opq_registers(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + return chnum; + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + return opnum; + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // reset the LFO + void reset_lfo() { m_lfo_counter = 0; } + + // return the AM offset from LFO for the given channel + uint32_t lfo_am_offset(uint32_t choffs) const; + + // return the current noise state, gated by the noise clock + uint32_t noise_state() const { return 0; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // system-wide registers + uint32_t timer_a_value() const { return 0; } + uint32_t timer_b_value() const { return byte(0x03, 2, 6) | 0xc0; } // ??? + uint32_t csm() const { return 0; } + uint32_t reset_timer_b() const { return byte(0x03, 0, 1); } // ??? + uint32_t reset_timer_a() const { return 0; } + uint32_t enable_timer_b() const { return byte(0x03, 0, 1); } // ??? + uint32_t enable_timer_a() const { return 0; } + uint32_t load_timer_b() const { return byte(0x03, 0, 1); } // ??? + uint32_t load_timer_a() const { return 0; } + uint32_t lfo_enable() const { return byte(0x04, 3, 1) ^ 1; } + uint32_t lfo_rate() const { return byte(0x04, 0, 3); } + + // per-channel registers + uint32_t ch_output_any(uint32_t choffs) const { return byte(0x10, 6, 2, choffs); } + uint32_t ch_output_0(uint32_t choffs) const { return byte(0x10, 6, 1, choffs); } + uint32_t ch_output_1(uint32_t choffs) const { return byte(0x10, 7, 1, choffs); } + uint32_t ch_output_2(uint32_t choffs) const { return 0; } + uint32_t ch_output_3(uint32_t choffs) const { return 0; } + uint32_t ch_feedback(uint32_t choffs) const { return byte(0x10, 3, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return byte(0x10, 0, 3, choffs); } + uint32_t ch_reverb(uint32_t choffs) const { return byte(0x18, 7, 1, choffs); } + uint32_t ch_lfo_pm_sens(uint32_t choffs) const { return byte(0x18, 4, 3, choffs); } + uint32_t ch_lfo_am_sens(uint32_t choffs) const { return byte(0x18, 0, 2, choffs); } + uint32_t ch_block_freq_24(uint32_t choffs) const { return word(0x20, 0, 7, 0x30, 0, 8, choffs); } + uint32_t ch_block_freq_13(uint32_t choffs) const { return word(0x28, 0, 7, 0x38, 0, 8, choffs); } + + // per-operator registers + uint32_t op_detune(uint32_t opoffs) const { return byte(0x40, 0, 6, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return byte(0x100, 0, 4, opoffs); } + uint32_t op_total_level(uint32_t opoffs) const { return byte(0x60, 0, 7, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return byte(0x80, 6, 2, opoffs); } + uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x80, 0, 5, opoffs); } + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return byte(0xa0, 7, 1, opoffs); } + uint32_t op_waveform(uint32_t opoffs) const { return byte(0xa0, 6, 1, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return byte(0xa0, 0, 5, opoffs); } + uint32_t op_sustain_rate(uint32_t opoffs) const { return byte(0xc0, 0, 5, opoffs); } + uint32_t op_sustain_level(uint32_t opoffs) const { return byte(0xe0, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return byte(0xe0, 0, 4, opoffs); } + +protected: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // internal state + uint32_t m_lfo_counter; // LFO counter + uint8_t m_lfo_am; // current LFO AM value + uint8_t m_regdata[REGISTERS]; // register data + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + + + +//********************************************************* +// IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym3806 + +class ym3806 +{ +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + using output_data = fm_engine::output_data; + + // constructor + ym3806(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data) { /* not supported; only direct writes */ } + void write_data(uint8_t data) { /* not supported; only direct writes */ } + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + fm_engine m_fm; // core FM engine +}; + + +// ======================> ym3533 + +class ym3533 : public ym3806 +{ +public: + // constructor + ym3533(ymfm_interface &intf) : + ym3806(intf) { } +}; + +} + + +#endif // YMFM_OPQ_H diff --git a/src/sound/ymfm/ymfm_opx.h b/src/sound/ymfm/ymfm_opx.h new file mode 100644 index 000000000..9f9bbdba7 --- /dev/null +++ b/src/sound/ymfm/ymfm_opx.h @@ -0,0 +1,290 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_OPX_H +#define YMFM_OPX_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_fm.h" + +namespace ymfm +{ + +//********************************************************* +// REGISTER CLASSES +//********************************************************* + +// ======================> opx_registers + +// +// OPX register map: +// +// System-wide registers: +// +// Per-channel registers (channel in address bits 0-2) +// +// Per-operator registers (4 banks): +// 00-0F x------- Enable +// -xxxx--- EXT out +// -------x Key on +// 10-1F xxxxxxxx LFO frequency +// 20-2F xx------ AM sensitivity (0-3) +// --xxx--- PM sensitivity (0-7) +// ------xx LFO waveform (0=disable, 1=saw, 2= +// 30-3F -xxx---- Detune (0-7) +// ----xxxx Multiple (0-15) +// 40-4F -xxxxxxx Total level (0-127) +// 50-5F xxx----- Key scale (0-7) +// ---xxxxx Attack rate (0-31) +// 60-6F ---xxxxx Decay rate (0-31) +// 70-7F ---xxxxx Sustain rate (0-31) +// 80-8F xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// 90-9F xxxxxxxx Frequency number (low 8 bits) +// A0-AF xxxx---- Block (0-15) +// ----xxxx Frequency number (high 4 bits) +// B0-BF x------- Acc on +// -xxx---- Feedback level (0-7) +// -----xxx Waveform (0-7, 7=PCM) +// C0-CF ----xxxx Algorithm (0-15) +// D0-DF xxxx---- CH0 level (0-15) +// ----xxxx CH1 level (0-15) +// E0-EF xxxx---- CH2 level (0-15) +// ----xxxx CH3 level (0-15) +// + +class opx_registers : public fm_registers_base +{ + // LFO waveforms are 256 entries long + static constexpr uint32_t LFO_WAVEFORM_LENGTH = 256; + +public: + // constants + static constexpr uint32_t OUTPUTS = 8; + static constexpr uint32_t CHANNELS = 24; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 2; + static constexpr uint32_t WAVEFORMS = 8; + static constexpr uint32_t REGISTERS = 0x800; + static constexpr uint32_t DEFAULT_PRESCALE = 8; + static constexpr uint32_t EG_CLOCK_DIVIDER = 2; + static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS; + static constexpr uint32_t REG_MODE = 0x14; + static constexpr uint8_t STATUS_TIMERA = 0x01; + static constexpr uint8_t STATUS_TIMERB = 0x02; + static constexpr uint8_t STATUS_BUSY = 0x80; + static constexpr uint8_t STATUS_IRQ = 0; + + // constructor + opz_registers(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + return chnum; + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + return opnum; + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // return the AM offset from LFO for the given channel + uint32_t lfo_am_offset(uint32_t choffs) const; + + // return the current noise state, gated by the noise clock + uint32_t noise_state() const { return m_noise_state; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // system-wide registers + uint32_t noise_frequency() const { return byte(0x0f, 0, 5); } + uint32_t noise_enable() const { return byte(0x0f, 7, 1); } + uint32_t timer_a_value() const { return word(0x10, 0, 8, 0x11, 0, 2); } + uint32_t timer_b_value() const { return byte(0x12, 0, 8); } + uint32_t csm() const { return byte(0x14, 7, 1); } + uint32_t reset_timer_b() const { return byte(0x14, 5, 1); } + uint32_t reset_timer_a() const { return byte(0x14, 4, 1); } + uint32_t enable_timer_b() const { return byte(0x14, 3, 1); } + uint32_t enable_timer_a() const { return byte(0x14, 2, 1); } + uint32_t load_timer_b() const { return byte(0x14, 1, 1); } + uint32_t load_timer_a() const { return byte(0x14, 0, 1); } + uint32_t lfo2_pm_depth() const { return byte(0x148, 0, 7); } // fake + uint32_t lfo2_rate() const { return byte(0x16, 0, 8); } + uint32_t lfo2_am_depth() const { return byte(0x17, 0, 7); } + uint32_t lfo_rate() const { return byte(0x18, 0, 8); } + uint32_t lfo_am_depth() const { return byte(0x19, 0, 7); } + uint32_t lfo_pm_depth() const { return byte(0x149, 0, 7); } // fake + uint32_t output_bits() const { return byte(0x1b, 6, 2); } + uint32_t lfo2_sync() const { return byte(0x1b, 5, 1); } + uint32_t lfo_sync() const { return byte(0x1b, 4, 1); } + uint32_t lfo2_waveform() const { return byte(0x1b, 2, 2); } + uint32_t lfo_waveform() const { return byte(0x1b, 0, 2); } + + // per-channel registers + uint32_t ch_volume(uint32_t choffs) const { return byte(0x00, 0, 8, choffs); } + uint32_t ch_output_any(uint32_t choffs) const { return byte(0x20, 7, 1, choffs) | byte(0x30, 0, 1, choffs); } + uint32_t ch_output_0(uint32_t choffs) const { return byte(0x30, 0, 1, choffs); } + uint32_t ch_output_1(uint32_t choffs) const { return byte(0x20, 7, 1, choffs) | byte(0x30, 0, 1, choffs); } + uint32_t ch_output_2(uint32_t choffs) const { return 0; } + uint32_t ch_output_3(uint32_t choffs) const { return 0; } + uint32_t ch_key_on(uint32_t choffs) const { return byte(0x20, 6, 1, choffs); } + uint32_t ch_feedback(uint32_t choffs) const { return byte(0x20, 3, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return byte(0x20, 0, 3, choffs); } + uint32_t ch_block_freq(uint32_t choffs) const { return word(0x28, 0, 7, 0x30, 2, 6, choffs); } + uint32_t ch_lfo_pm_sens(uint32_t choffs) const { return byte(0x38, 4, 3, choffs); } + uint32_t ch_lfo_am_sens(uint32_t choffs) const { return byte(0x38, 0, 2, choffs); } + uint32_t ch_lfo2_pm_sens(uint32_t choffs) const { return byte(0x140, 4, 3, choffs); } // fake + uint32_t ch_lfo2_am_sens(uint32_t choffs) const { return byte(0x140, 0, 2, choffs); } // fake + + // per-operator registers + uint32_t op_detune(uint32_t opoffs) const { return byte(0x40, 4, 3, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return byte(0x40, 0, 4, opoffs); } + uint32_t op_fix_range(uint32_t opoffs) const { return byte(0x40, 4, 3, opoffs); } + uint32_t op_fix_frequency(uint32_t opoffs) const { return byte(0x40, 0, 4, opoffs); } + uint32_t op_waveform(uint32_t opoffs) const { return byte(0x100, 4, 3, opoffs); } // fake + uint32_t op_fine(uint32_t opoffs) const { return byte(0x100, 0, 4, opoffs); } // fake + uint32_t op_total_level(uint32_t opoffs) const { return byte(0x60, 0, 7, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return byte(0x80, 6, 2, opoffs); } + uint32_t op_fix_mode(uint32_t opoffs) const { return byte(0x80, 5, 1, opoffs); } + uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x80, 0, 5, opoffs); } + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return byte(0xa0, 7, 1, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return byte(0xa0, 0, 5, opoffs); } + uint32_t op_detune2(uint32_t opoffs) const { return byte(0xc0, 6, 2, opoffs); } + uint32_t op_sustain_rate(uint32_t opoffs) const { return byte(0xc0, 0, 5, opoffs); } + uint32_t op_eg_shift(uint32_t opoffs) const { return byte(0x120, 6, 2, opoffs); } // fake + uint32_t op_reverb_rate(uint32_t opoffs) const { return byte(0x120, 0, 3, opoffs); } // fake + uint32_t op_sustain_level(uint32_t opoffs) const { return byte(0xe0, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return byte(0xe0, 0, 4, opoffs); } + +protected: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // internal state + uint32_t m_lfo_counter[2]; // LFO counter + uint32_t m_noise_lfsr; // noise LFSR state + uint8_t m_noise_counter; // noise counter + uint8_t m_noise_state; // latched noise state + uint8_t m_noise_lfo; // latched LFO noise value + uint8_t m_lfo_am[2]; // current LFO AM value + uint8_t m_regdata[REGISTERS]; // register data + uint16_t m_phase_substep[OPERATORS]; // phase substep for fixed frequency + int16_t m_lfo_waveform[4][LFO_WAVEFORM_LENGTH]; // LFO waveforms; AM in low 8, PM in upper 8 + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + + + +//********************************************************* +// IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym2414 + +class ym2414 +{ +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + using output_data = fm_engine::output_data; + + // constructor + ym2414(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint8_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + +} + + +#endif // YMFM_OPZ_H diff --git a/src/sound/ymfm/ymfm_opz.cpp b/src/sound/ymfm/ymfm_opz.cpp new file mode 100644 index 000000000..adeefd79f --- /dev/null +++ b/src/sound/ymfm/ymfm_opz.cpp @@ -0,0 +1,808 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_opz.h" +#include "ymfm_fm.ipp" + +#define TEMPORARY_DEBUG_PRINTS (0) + +// +// OPZ (aka YM2414) +// +// This chip is not officially documented as far as I know. What I have +// comes from this site: +// +// http://sr4.sakura.ne.jp/fmsound/opz.html +// +// and from reading the TX81Z operator manual, which describes how a number +// of these new features work. +// +// OPZ appears be bsaically OPM with a bunch of extra features. +// +// For starters, there are two LFO generators. I have presumed that they +// operate identically since identical parameters are offered for each. I +// have also presumed the effects are additive between them. The LFOs on +// the OPZ have an extra "sync" option which apparently causes the LFO to +// reset whenever a key on is received. +// +// At the channel level, there is an additional 8-bit volume control. This +// might work as an addition to total level, or some other way. Completely +// unknown, and unimplemented. +// +// At the operator level, there are a number of extra features. First, there +// are 8 different waveforms to choose from. These are different than the +// waveforms introduced in the OPL2 and later chips. +// +// Second, there is an additional "reverb" stage added to the envelope +// generator, which kicks in when the envelope reaches -18dB. It specifies +// a slower decay rate to produce a sort of faux reverb effect. +// +// The envelope generator also supports a 2-bit shift value, which can be +// used to reduce the effect of the envelope attenuation. +// +// OPZ supports a "fixed frequency" mode for each operator, with a 3-bit +// range and 4-bit frequency value, plus a 1-bit enable. Not sure how that +// works at all, so it's not implemented. +// +// There are also several mystery fields in the operators which I have no +// clue about: "fine" (4 bits), "eg_shift" (2 bits), and "rev" (3 bits). +// eg_shift is some kind of envelope generator effect, but how it works is +// unknown. +// +// Also, according to the site above, the panning controls are changed from +// OPM, with a "mono" bit and only one control bit for the right channel. +// Current implementation is just a guess. +// + +namespace ymfm +{ + +//********************************************************* +// OPZ REGISTERS +//********************************************************* + +//------------------------------------------------- +// opz_registers - constructor +//------------------------------------------------- + +opz_registers::opz_registers() : + m_lfo_counter{ 0, 0 }, + m_noise_lfsr(1), + m_noise_counter(0), + m_noise_state(0), + m_noise_lfo(0), + m_lfo_am{ 0, 0 } +{ + // create the waveforms + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[0][index] = abs_sin_attenuation(index) | (bitfield(index, 9) << 15); + + // we only have the diagrams to judge from, but suspecting waveform 1 (and + // derived waveforms) are sin^2, based on OPX description of similar wave- + // forms; since our sin table is logarithmic, this ends up just being + // 2*existing value + uint16_t zeroval = m_waveform[0][0]; + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + m_waveform[1][index] = std::min(2 * (m_waveform[0][index] & 0x7fff), zeroval) | (bitfield(index, 9) << 15); + + // remaining waveforms are just derivations of the 2 main ones + for (uint32_t index = 0; index < WAVEFORM_LENGTH; index++) + { + m_waveform[2][index] = bitfield(index, 9) ? zeroval : m_waveform[0][index]; + m_waveform[3][index] = bitfield(index, 9) ? zeroval : m_waveform[1][index]; + m_waveform[4][index] = bitfield(index, 9) ? zeroval : m_waveform[0][index * 2]; + m_waveform[5][index] = bitfield(index, 9) ? zeroval : m_waveform[1][index * 2]; + m_waveform[6][index] = bitfield(index, 9) ? zeroval : m_waveform[0][(index * 2) & 0x1ff]; + m_waveform[7][index] = bitfield(index, 9) ? zeroval : m_waveform[1][(index * 2) & 0x1ff]; + } + + // create the LFO waveforms; AM in the low 8 bits, PM in the upper 8 + // waveforms are adjusted to match the pictures in the application manual + for (uint32_t index = 0; index < LFO_WAVEFORM_LENGTH; index++) + { + // waveform 0 is a sawtooth + uint8_t am = index ^ 0xff; + int8_t pm = int8_t(index); + m_lfo_waveform[0][index] = am | (pm << 8); + + // waveform 1 is a square wave + am = bitfield(index, 7) ? 0 : 0xff; + pm = int8_t(am ^ 0x80); + m_lfo_waveform[1][index] = am | (pm << 8); + + // waveform 2 is a triangle wave + am = bitfield(index, 7) ? (index << 1) : ((index ^ 0xff) << 1); + pm = int8_t(bitfield(index, 6) ? am : ~am); + m_lfo_waveform[2][index] = am | (pm << 8); + + // waveform 3 is noise; it is filled in dynamically + } +} + + +//------------------------------------------------- +// reset - reset to initial state +//------------------------------------------------- + +void opz_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + + // enable output on both channels by default + m_regdata[0x30] = m_regdata[0x31] = m_regdata[0x32] = m_regdata[0x33] = 0x01; + m_regdata[0x34] = m_regdata[0x35] = m_regdata[0x36] = m_regdata[0x37] = 0x01; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void opz_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_lfo_counter); + state.save_restore(m_lfo_am); + state.save_restore(m_noise_lfsr); + state.save_restore(m_noise_counter); + state.save_restore(m_noise_state); + state.save_restore(m_noise_lfo); + state.save_restore(m_regdata); + state.save_restore(m_phase_substep); +} + + +//------------------------------------------------- +// operator_map - return an array of operator +// indices for each channel; for OPZ this is fixed +//------------------------------------------------- + +void opz_registers::operator_map(operator_mapping &dest) const +{ + // Note that the channel index order is 0,2,1,3, so we bitswap the index. + // + // This is because the order in the map is: + // carrier 1, carrier 2, modulator 1, modulator 2 + // + // But when wiring up the connections, the more natural order is: + // carrier 1, modulator 1, carrier 2, modulator 2 + static const operator_mapping s_fixed_map = + { { + operator_list( 0, 16, 8, 24 ), // Channel 0 operators + operator_list( 1, 17, 9, 25 ), // Channel 1 operators + operator_list( 2, 18, 10, 26 ), // Channel 2 operators + operator_list( 3, 19, 11, 27 ), // Channel 3 operators + operator_list( 4, 20, 12, 28 ), // Channel 4 operators + operator_list( 5, 21, 13, 29 ), // Channel 5 operators + operator_list( 6, 22, 14, 30 ), // Channel 6 operators + operator_list( 7, 23, 15, 31 ), // Channel 7 operators + } }; + dest = s_fixed_map; +} + + +//------------------------------------------------- +// write - handle writes to the register array +//------------------------------------------------- + +bool opz_registers::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask) +{ + assert(index < REGISTERS); + + // special mappings: + // 0x16 -> 0x188 if bit 7 is set + // 0x19 -> 0x189 if bit 7 is set + // 0x38..0x3F -> 0x180..0x187 if bit 7 is set + // 0x40..0x5F -> 0x100..0x11F if bit 7 is set + // 0xC0..0xDF -> 0x120..0x13F if bit 5 is set + if (index == 0x17 && bitfield(data, 7) != 0) + m_regdata[0x188] = data; + else if (index == 0x19 && bitfield(data, 7) != 0) + m_regdata[0x189] = data; + else if ((index & 0xf8) == 0x38 && bitfield(data, 7) != 0) + m_regdata[0x180 + (index & 7)] = data; + else if ((index & 0xe0) == 0x40 && bitfield(data, 7) != 0) + m_regdata[0x100 + (index & 0x1f)] = data; + else if ((index & 0xe0) == 0xc0 && bitfield(data, 5) != 0) + m_regdata[0x120 + (index & 0x1f)] = data; + else if (index < 0x100) + m_regdata[index] = data; + + // preset writes restore some values from a preset memory; not sure + // how this really works but the TX81Z will overwrite the sustain level/ + // release rate register and the envelope shift/reverb rate register to + // dampen sound, then write the preset number to register 8 to restore them + if (index == 0x08) + { + int chan = bitfield(data, 0, 3); + if (TEMPORARY_DEBUG_PRINTS) + printf("Loading preset %d\n", chan); + m_regdata[0xe0 + chan + 0] = m_regdata[0x140 + chan + 0]; + m_regdata[0xe0 + chan + 8] = m_regdata[0x140 + chan + 8]; + m_regdata[0xe0 + chan + 16] = m_regdata[0x140 + chan + 16]; + m_regdata[0xe0 + chan + 24] = m_regdata[0x140 + chan + 24]; + m_regdata[0x120 + chan + 0] = m_regdata[0x160 + chan + 0]; + m_regdata[0x120 + chan + 8] = m_regdata[0x160 + chan + 8]; + m_regdata[0x120 + chan + 16] = m_regdata[0x160 + chan + 16]; + m_regdata[0x120 + chan + 24] = m_regdata[0x160 + chan + 24]; + } + + // store the presets under some unknown condition; the pattern of writes + // when setting a new preset is: + // + // 08 (0-7), 80-9F, A0-BF, C0-DF, C0-DF (alt), 20-27, 40-5F, 40-5F (alt), + // C0-DF (alt -- again?), 38-3F, 1B, 18, E0-FF + // + // So it writes 0-7 to 08 to either reset all presets or to indicate + // that we're going to be loading them. Immediately after all the writes + // above, the very next write will be temporary values to blow away the + // values loaded into E0-FF, so somehow it also knows that anything after + // that point is not part of the preset. + // + // For now, try using the 40-5F (alt) writes as flags that presets are + // being loaded until the E0-FF writes happen. + bool is_setting_preset = (bitfield(m_regdata[0x100 + (index & 0x1f)], 7) != 0); + if (is_setting_preset) + { + if ((index & 0xe0) == 0xe0) + { + m_regdata[0x140 + (index & 0x1f)] = data; + m_regdata[0x100 + (index & 0x1f)] &= 0x7f; + } + else if ((index & 0xe0) == 0xc0 && bitfield(data, 5) != 0) + m_regdata[0x160 + (index & 0x1f)] = data; + } + + // handle writes to the key on index + if ((index & 0xf8) == 0x20 && bitfield(index, 0, 3) == bitfield(m_regdata[0x08], 0, 3)) + { + channel = bitfield(index, 0, 3); + opmask = ch_key_on(channel) ? 0xf : 0; + + // according to the TX81Z manual, the sync option causes the LFOs + // to reset at each note on + if (opmask != 0) + { + if (lfo_sync()) + m_lfo_counter[0] = 0; + if (lfo2_sync()) + m_lfo_counter[1] = 0; + } + return true; + } + return false; +} + + +//------------------------------------------------- +// clock_noise_and_lfo - clock the noise and LFO, +// handling clock division, depth, and waveform +// computations +//------------------------------------------------- + +int32_t opz_registers::clock_noise_and_lfo() +{ + // base noise frequency is measured at 2x 1/2 FM frequency; this + // means each tick counts as two steps against the noise counter + uint32_t freq = noise_frequency(); + for (int rep = 0; rep < 2; rep++) + { + // evidence seems to suggest the LFSR is clocked continually and just + // sampled at the noise frequency for output purposes; note that the + // low 8 bits are the most recent 8 bits of history while bits 8-24 + // contain the 17 bit LFSR state + m_noise_lfsr <<= 1; + m_noise_lfsr |= bitfield(m_noise_lfsr, 17) ^ bitfield(m_noise_lfsr, 14) ^ 1; + + // compare against the frequency and latch when we exceed it + if (m_noise_counter++ >= freq) + { + m_noise_counter = 0; + m_noise_state = bitfield(m_noise_lfsr, 17); + } + } + + // treat the rate as a 4.4 floating-point step value with implied + // leading 1; this matches exactly the frequencies in the application + // manual, though it might not be implemented exactly this way on chip + uint32_t rate0 = lfo_rate(); + uint32_t rate1 = lfo2_rate(); + m_lfo_counter[0] += (0x10 | bitfield(rate0, 0, 4)) << bitfield(rate0, 4, 4); + m_lfo_counter[1] += (0x10 | bitfield(rate1, 0, 4)) << bitfield(rate1, 4, 4); + uint32_t lfo0 = bitfield(m_lfo_counter[0], 22, 8); + uint32_t lfo1 = bitfield(m_lfo_counter[1], 22, 8); + + // fill in the noise entry 1 ahead of our current position; this + // ensures the current value remains stable for a full LFO clock + // and effectively latches the running value when the LFO advances + uint32_t lfo_noise = bitfield(m_noise_lfsr, 17, 8); + m_lfo_waveform[3][(lfo0 + 1) & 0xff] = lfo_noise | (lfo_noise << 8); + m_lfo_waveform[3][(lfo1 + 1) & 0xff] = lfo_noise | (lfo_noise << 8); + + // fetch the AM/PM values based on the waveform; AM is unsigned and + // encoded in the low 8 bits, while PM signed and encoded in the upper + // 8 bits + int32_t ampm0 = m_lfo_waveform[lfo_waveform()][lfo0]; + int32_t ampm1 = m_lfo_waveform[lfo2_waveform()][lfo1]; + + // apply depth to the AM values and store for later + m_lfo_am[0] = ((ampm0 & 0xff) * lfo_am_depth()) >> 7; + m_lfo_am[1] = ((ampm1 & 0xff) * lfo2_am_depth()) >> 7; + + // apply depth to the PM values and return them combined into two + int32_t pm0 = ((ampm0 >> 8) * int32_t(lfo_pm_depth())) >> 7; + int32_t pm1 = ((ampm1 >> 8) * int32_t(lfo2_pm_depth())) >> 7; + return (pm0 & 0xff) | (pm1 << 8); +} + + +//------------------------------------------------- +// lfo_am_offset - return the AM offset from LFO +// for the given channel +//------------------------------------------------- + +uint32_t opz_registers::lfo_am_offset(uint32_t choffs) const +{ + // not sure how this works for real, but just adding the two + // AM LFOs together + uint32_t result = 0; + + // shift value for AM sensitivity is [*, 0, 1, 2], + // mapping to values of [0, 23.9, 47.8, and 95.6dB] + uint32_t am_sensitivity = ch_lfo_am_sens(choffs); + if (am_sensitivity != 0) + result = m_lfo_am[0] << (am_sensitivity - 1); + + // QUESTION: see OPN note below for the dB range mapping; it applies + // here as well + + // raw LFO AM value on OPZ is 0-FF, which is already a factor of 2 + // larger than the OPN below, putting our staring point at 2x theirs; + // this works out since our minimum is 2x their maximum + uint32_t am_sensitivity2 = ch_lfo2_am_sens(choffs); + if (am_sensitivity2 != 0) + result += m_lfo_am[1] << (am_sensitivity2 - 1); + + return result; +} + + +//------------------------------------------------- +// cache_operator_data - fill the operator cache +// with prefetched data +//------------------------------------------------- + +void opz_registers::cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache) +{ + // TODO: how does fixed frequency mode work? appears to be enabled by + // op_fix_mode(), and controlled by op_fix_range(), op_fix_frequency() + + // TODO: what is op_rev()? + + // set up the easy stuff + cache.waveform = &m_waveform[op_waveform(opoffs)][0]; + + // get frequency from the channel + uint32_t block_freq = cache.block_freq = ch_block_freq(choffs); + + // compute the keycode: block_freq is: + // + // BBBCCCCFFFFFF + // ^^^^^ + // + // the 5-bit keycode is just the top 5 bits (block + top 2 bits + // of the key code) + uint32_t keycode = bitfield(block_freq, 8, 5); + + // detune adjustment + cache.detune = detune_adjustment(op_detune(opoffs), keycode); + + // multiple value, as an x.4 value (0 means 0.5) + // the "fine" control provides the fractional bits + cache.multiple = op_multiple(opoffs) << 4; + if (cache.multiple == 0) + cache.multiple = 0x08; + cache.multiple |= op_fine(opoffs); + + // phase step, or PHASE_STEP_DYNAMIC if PM is active; this depends on + // block_freq, detune, and multiple, so compute it after we've done those; + // note that fix frequency mode is also treated as dynamic + if (!op_fix_mode(opoffs) && (lfo_pm_depth() == 0 || ch_lfo_pm_sens(choffs) == 0) && (lfo2_pm_depth() == 0 || ch_lfo2_pm_sens(choffs) == 0)) + cache.phase_step = compute_phase_step(choffs, opoffs, cache, 0); + else + cache.phase_step = opdata_cache::PHASE_STEP_DYNAMIC; + + // total level, scaled by 8 + // TODO: how does ch_volume() fit into this? + cache.total_level = op_total_level(opoffs) << 3; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = op_sustain_level(opoffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // determine KSR adjustment for enevlope rates + uint32_t ksrval = keycode >> (op_ksr(opoffs) ^ 3); + cache.eg_rate[EG_ATTACK] = effective_rate(op_attack_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_DECAY] = effective_rate(op_decay_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_SUSTAIN] = effective_rate(op_sustain_rate(opoffs) * 2, ksrval); + cache.eg_rate[EG_RELEASE] = effective_rate(op_release_rate(opoffs) * 4 + 2, ksrval); + cache.eg_rate[EG_REVERB] = cache.eg_rate[EG_RELEASE]; + uint32_t reverb = op_reverb_rate(opoffs); + if (reverb != 0) + cache.eg_rate[EG_REVERB] = std::min(effective_rate(reverb * 4 + 2, ksrval), cache.eg_rate[EG_REVERB]); + + // set the envelope shift; TX81Z manual says operator 1 shift is fixed at "off" + cache.eg_shift = ((opoffs & 0x18) == 0) ? 0 : op_eg_shift(opoffs); +} + + +//------------------------------------------------- +// compute_phase_step - compute the phase step +//------------------------------------------------- + +uint32_t opz_registers::compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm) +{ + // OPZ has a fixed frequency mode; it is unclear whether the + // detune and multiple parameters affect things + + uint32_t phase_step; + if (op_fix_mode(opoffs)) + { + // the baseline frequency in hz comes from the fix frequency and fine + // registers, which can specify values 8-255Hz in 1Hz increments; that + // value is then shifted up by the 3-bit range + uint32_t freq = op_fix_frequency(opoffs) << 4; + if (freq == 0) + freq = 8; + freq |= op_fine(opoffs); + freq <<= op_fix_range(opoffs); + + // there is not enough resolution in the plain phase step to track the + // full range of frequencies, so we keep a per-operator sub step with an + // additional 12 bits of resolution; this calculation gives us, for + // example, a frequency of 8.0009Hz when 8Hz is requested + uint32_t substep = m_phase_substep[opoffs]; + substep += 75 * freq; + phase_step = substep >> 12; + m_phase_substep[opoffs] = substep & 0xfff; + + // detune/multiple occupy the same space as fix_range/fix_frequency so + // don't apply them in addition + return phase_step; + } + else + { + // start with coarse detune delta; table uses cents value from + // manual, converted into 1/64ths + static const int16_t s_detune2_delta[4] = { 0, (600*64+50)/100, (781*64+50)/100, (950*64+50)/100 }; + int32_t delta = s_detune2_delta[op_detune2(opoffs)]; + + // add in the PM deltas + uint32_t pm_sensitivity = ch_lfo_pm_sens(choffs); + if (pm_sensitivity != 0) + { + // raw PM value is -127..128 which is +/- 200 cents + // manual gives these magnitudes in cents: + // 0, +/-5, +/-10, +/-20, +/-50, +/-100, +/-400, +/-700 + // this roughly corresponds to shifting the 200-cent value: + // 0 >> 5, >> 4, >> 3, >> 2, >> 1, << 1, << 2 + if (pm_sensitivity < 6) + delta += int8_t(lfo_raw_pm) >> (6 - pm_sensitivity); + else + delta += int8_t(lfo_raw_pm) << (pm_sensitivity - 5); + } + uint32_t pm_sensitivity2 = ch_lfo2_pm_sens(choffs); + if (pm_sensitivity2 != 0) + { + // raw PM value is -127..128 which is +/- 200 cents + // manual gives these magnitudes in cents: + // 0, +/-5, +/-10, +/-20, +/-50, +/-100, +/-400, +/-700 + // this roughly corresponds to shifting the 200-cent value: + // 0 >> 5, >> 4, >> 3, >> 2, >> 1, << 1, << 2 + if (pm_sensitivity2 < 6) + delta += int8_t(lfo_raw_pm >> 8) >> (6 - pm_sensitivity2); + else + delta += int8_t(lfo_raw_pm >> 8) << (pm_sensitivity2 - 5); + } + + // apply delta and convert to a frequency number; this translation is + // the same as OPM so just re-use that helper + phase_step = opm_key_code_to_phase_step(cache.block_freq, delta); + + // apply detune based on the keycode + phase_step += cache.detune; + + // apply frequency multiplier (which is cached as an x.4 value) + return (phase_step * cache.multiple) >> 4; + } +} + + +//------------------------------------------------- +// log_keyon - log a key-on event +//------------------------------------------------- + +std::string opz_registers::log_keyon(uint32_t choffs, uint32_t opoffs) +{ + uint32_t chnum = choffs; + uint32_t opnum = opoffs; + + char buffer[256]; + char *end = &buffer[0]; + + end += sprintf(end, "%u.%02u", chnum, opnum); + + if (op_fix_mode(opoffs)) + end += sprintf(end, " fixfreq=%X fine=%X shift=%X", op_fix_frequency(opoffs), op_fine(opoffs), op_fix_range(opoffs)); + else + end += sprintf(end, " freq=%04X dt2=%u fine=%X", ch_block_freq(choffs), op_detune2(opoffs), op_fine(opoffs)); + + end += sprintf(end, " dt=%u fb=%u alg=%X mul=%X tl=%02X ksr=%u adsr=%02X/%02X/%02X/%X sl=%X out=%c%c", + op_detune(opoffs), + ch_feedback(choffs), + ch_algorithm(choffs), + op_multiple(opoffs), + op_total_level(opoffs), + op_ksr(opoffs), + op_attack_rate(opoffs), + op_decay_rate(opoffs), + op_sustain_rate(opoffs), + op_release_rate(opoffs), + op_sustain_level(opoffs), + ch_output_0(choffs) ? 'L' : '-', + ch_output_1(choffs) ? 'R' : '-'); + + if (op_eg_shift(opoffs) != 0) + end += sprintf(end, " egshift=%u", op_eg_shift(opoffs)); + + bool am = (lfo_am_depth() != 0 && ch_lfo_am_sens(choffs) != 0 && op_lfo_am_enable(opoffs) != 0); + if (am) + end += sprintf(end, " am=%u/%02X", ch_lfo_am_sens(choffs), lfo_am_depth()); + bool pm = (lfo_pm_depth() != 0 && ch_lfo_pm_sens(choffs) != 0); + if (pm) + end += sprintf(end, " pm=%u/%02X", ch_lfo_pm_sens(choffs), lfo_pm_depth()); + if (am || pm) + end += sprintf(end, " lfo=%02X/%c", lfo_rate(), "WQTN"[lfo_waveform()]); + + bool am2 = (lfo2_am_depth() != 0 && ch_lfo2_am_sens(choffs) != 0 && op_lfo_am_enable(opoffs) != 0); + if (am2) + end += sprintf(end, " am2=%u/%02X", ch_lfo2_am_sens(choffs), lfo2_am_depth()); + bool pm2 = (lfo2_pm_depth() != 0 && ch_lfo2_pm_sens(choffs) != 0); + if (pm2) + end += sprintf(end, " pm2=%u/%02X", ch_lfo2_pm_sens(choffs), lfo2_pm_depth()); + if (am2 || pm2) + end += sprintf(end, " lfo2=%02X/%c", lfo2_rate(), "WQTN"[lfo2_waveform()]); + + if (op_reverb_rate(opoffs) != 0) + end += sprintf(end, " rev=%u", op_reverb_rate(opoffs)); + if (op_waveform(opoffs) != 0) + end += sprintf(end, " wf=%u", op_waveform(opoffs)); + if (noise_enable() && opoffs == 31) + end += sprintf(end, " noise=1"); + + return buffer; +} + + + +//********************************************************* +// YM2414 +//********************************************************* + +//------------------------------------------------- +// ym2414 - constructor +//------------------------------------------------- + +ym2414::ym2414(ymfm_interface &intf) : + m_address(0), + m_fm(intf) +{ +} + + +//------------------------------------------------- +// reset - reset the system +//------------------------------------------------- + +void ym2414::reset() +{ + // reset the engines + m_fm.reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ym2414::save_restore(ymfm_saved_state &state) +{ + m_fm.save_restore(state); + state.save_restore(m_address); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +uint8_t ym2414::read_status() +{ + uint8_t result = m_fm.status(); + if (m_fm.intf().ymfm_is_busy()) + result |= fm_engine::STATUS_BUSY; + return result; +} + + +//------------------------------------------------- +// read - handle a read from the device +//------------------------------------------------- + +uint8_t ym2414::read(uint32_t offset) +{ + uint8_t result = 0xff; + switch (offset & 1) + { + case 0: // data port (unused) + debug::log_unexpected_read_write("Unexpected read from YM2414 offset %d\n", offset & 3); + break; + + case 1: // status port, YM2203 compatible + result = read_status(); + break; + } + return result; +} + + +//------------------------------------------------- +// write_address - handle a write to the address +// register +//------------------------------------------------- + +void ym2414::write_address(uint8_t data) +{ + // just set the address + m_address = data; +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2414::write_data(uint8_t data) +{ + // write the FM register + m_fm.write(m_address, data); + if (TEMPORARY_DEBUG_PRINTS) + { + switch (m_address & 0xe0) + { + case 0x00: + printf("CTL %02X = %02X\n", m_address, data); + break; + + case 0x20: + switch (m_address & 0xf8) + { + case 0x20: printf("R/FBL/ALG %d = %02X\n", m_address & 7, data); break; + case 0x28: printf("KC %d = %02X\n", m_address & 7, data); break; + case 0x30: printf("KF/M %d = %02X\n", m_address & 7, data); break; + case 0x38: printf("PMS/AMS %d = %02X\n", m_address & 7, data); break; + } + break; + + case 0x40: + if (bitfield(data, 7) == 0) + printf("DT1/MUL %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + else + printf("OW/FINE %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + break; + + case 0x60: + printf("TL %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + break; + + case 0x80: + printf("KRS/FIX/AR %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + break; + + case 0xa0: + printf("A/D1R %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + break; + + case 0xc0: + if (bitfield(data, 5) == 0) + printf("DT2/D2R %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + else + printf("EGS/REV %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + break; + + case 0xe0: + printf("D1L/RR %d.%d = %02X\n", m_address & 7, (m_address >> 3) & 3, data); + break; + } + } + + // special cases + if (m_address == 0x1b) + { + // writes to register 0x1B send the upper 2 bits to the output lines + m_fm.intf().ymfm_external_write(ACCESS_IO, 0, data >> 6); + } + + // mark busy for a bit + m_fm.intf().ymfm_set_busy_end(32 * m_fm.clock_prescale()); +} + + +//------------------------------------------------- +// write - handle a write to the register +// interface +//------------------------------------------------- + +void ym2414::write(uint32_t offset, uint8_t data) +{ + switch (offset & 1) + { + case 0: // address port + write_address(data); + break; + + case 1: // data port + write_data(data); + break; + } +} + + +//------------------------------------------------- +// generate - generate one sample of sound +//------------------------------------------------- + +void ym2414::generate(output_data *output, uint32_t numsamples) +{ + for (uint32_t samp = 0; samp < numsamples; samp++, output++) + { + // clock the system + m_fm.clock(fm_engine::ALL_CHANNELS); + + // update the FM content; YM2414 is full 14-bit with no intermediate clipping + m_fm.output(output->clear(), 0, 32767, fm_engine::ALL_CHANNELS); + + // unsure about YM2414 outputs; assume it is like YM2151 + output->roundtrip_fp(); + } +} + +} diff --git a/src/sound/ymfm/ymfm_opz.h b/src/sound/ymfm/ymfm_opz.h new file mode 100644 index 000000000..997ba32f9 --- /dev/null +++ b/src/sound/ymfm/ymfm_opz.h @@ -0,0 +1,332 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_OPZ_H +#define YMFM_OPZ_H + +#pragma once + +#include "ymfm.h" +#include "ymfm_fm.h" + +namespace ymfm +{ + +//********************************************************* +// REGISTER CLASSES +//********************************************************* + +// ======================> opz_registers + +// +// OPZ register map: +// +// System-wide registers: +// 08 -----xxx Load preset (not sure how it gets saved) +// 0F x------- Noise enable +// ---xxxxx Noise frequency +// 10 xxxxxxxx Timer A value (upper 8 bits) +// 11 ------xx Timer A value (lower 2 bits) +// 12 xxxxxxxx Timer B value +// 14 x------- CSM mode +// --x----- Reset timer B +// ---x---- Reset timer A +// ----x--- Enable timer B +// -----x-- Enable timer A +// ------x- Load timer B +// -------x Load timer A +// 16 xxxxxxxx LFO #2 frequency +// 17 0xxxxxxx AM LFO #2 depth +// 1xxxxxxx PM LFO #2 depth +// 18 xxxxxxxx LFO frequency +// 19 0xxxxxxx AM LFO depth +// 1xxxxxxx PM LFO depth +// 1B xx------ CT (2 output data lines) +// --x----- LFO #2 sync +// ---x---- LFO sync +// ----xx-- LFO #2 waveform +// ------xx LFO waveform +// +// Per-channel registers (channel in address bits 0-2) +// 00-07 xxxxxxxx Channel volume +// 20-27 x------- Pan right +// -x------ Key on (0)/off(1) +// --xxx--- Feedback level for operator 1 (0-7) +// -----xxx Operator connection algorithm (0-7) +// 28-2F -xxxxxxx Key code +// 30-37 xxxxxx-- Key fraction +// -------x Mono? mode +// 38-3F 0xxx---- LFO PM sensitivity +// -----0xx LFO AM shift +// 1xxx---- LFO #2 PM sensitivity +// -----1xx LFO #2 AM shift +// +// Per-operator registers (channel in address bits 0-2, operator in bits 3-4) +// 40-5F 0xxx---- Detune value (0-7) +// 0---xxxx Multiple value (0-15) +// 0xxx---- Fix range (0-15) +// 0---xxxx Fix frequency (0-15) +// 1xxx---- Oscillator waveform (0-7) +// 1---xxxx Fine? (0-15) +// 60-7F -xxxxxxx Total level (0-127) +// 80-9F xx------ Key scale rate (0-3) +// --x----- Fix frequency mode +// ---xxxxx Attack rate (0-31) +// A0-BF x------- LFO AM enable +// ---xxxxx Decay rate (0-31) +// C0-DF xx0----- Detune 2 value (0-3) +// --0xxxxx Sustain rate (0-31) +// xx1----- Envelope generator shift? (0-3) +// --1--xxx Rev? (0-7) +// E0-FF xxxx---- Sustain level (0-15) +// ----xxxx Release rate (0-15) +// +// Internal (fake) registers: +// 100-11F -xxx---- Oscillator waveform (0-7) +// ----xxxx Fine? (0-15) +// 120-13F xx------ Envelope generator shift (0-3) +// -----xxx Reverb rate (0-7) +// 140-15F xxxx---- Preset sustain level (0-15) +// ----xxxx Preset release rate (0-15) +// 160-17F xx------ Envelope generator shift (0-3) +// -----xxx Reverb rate (0-7) +// 180-187 -xxx---- LFO #2 PM sensitivity +// ---- xxx LFO #2 AM shift +// 188 -xxxxxxx LFO #2 PM depth +// 189 -xxxxxxx LFO PM depth +// + +class opz_registers : public fm_registers_base +{ + // LFO waveforms are 256 entries long + static constexpr uint32_t LFO_WAVEFORM_LENGTH = 256; + +public: + // constants + static constexpr uint32_t OUTPUTS = 2; + static constexpr uint32_t CHANNELS = 8; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + static constexpr uint32_t OPERATORS = CHANNELS * 4; + static constexpr uint32_t WAVEFORMS = 8; + static constexpr uint32_t REGISTERS = 0x190; + static constexpr uint32_t DEFAULT_PRESCALE = 2; + static constexpr uint32_t EG_CLOCK_DIVIDER = 3; + static constexpr bool EG_HAS_REVERB = true; + static constexpr uint32_t CSM_TRIGGER_MASK = ALL_CHANNELS; + static constexpr uint32_t REG_MODE = 0x14; + static constexpr uint8_t STATUS_TIMERA = 0x01; + static constexpr uint8_t STATUS_TIMERB = 0x02; + static constexpr uint8_t STATUS_BUSY = 0x80; + static constexpr uint8_t STATUS_IRQ = 0; + + // constructor + opz_registers(); + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // map channel number to register offset + static constexpr uint32_t channel_offset(uint32_t chnum) + { + assert(chnum < CHANNELS); + return chnum; + } + + // map operator number to register offset + static constexpr uint32_t operator_offset(uint32_t opnum) + { + assert(opnum < OPERATORS); + return opnum; + } + + // return an array of operator indices for each channel + struct operator_mapping { uint32_t chan[CHANNELS]; }; + void operator_map(operator_mapping &dest) const; + + // handle writes to the register array + bool write(uint16_t index, uint8_t data, uint32_t &chan, uint32_t &opmask); + + // clock the noise and LFO, if present, returning LFO PM value + int32_t clock_noise_and_lfo(); + + // return the AM offset from LFO for the given channel + uint32_t lfo_am_offset(uint32_t choffs) const; + + // return the current noise state, gated by the noise clock + uint32_t noise_state() const { return m_noise_state; } + + // caching helpers + void cache_operator_data(uint32_t choffs, uint32_t opoffs, opdata_cache &cache); + + // compute the phase step, given a PM value + uint32_t compute_phase_step(uint32_t choffs, uint32_t opoffs, opdata_cache const &cache, int32_t lfo_raw_pm); + + // log a key-on event + std::string log_keyon(uint32_t choffs, uint32_t opoffs); + + // system-wide registers + uint32_t noise_frequency() const { return byte(0x0f, 0, 5); } + uint32_t noise_enable() const { return byte(0x0f, 7, 1); } + uint32_t timer_a_value() const { return word(0x10, 0, 8, 0x11, 0, 2); } + uint32_t timer_b_value() const { return byte(0x12, 0, 8); } + uint32_t csm() const { return byte(0x14, 7, 1); } + uint32_t reset_timer_b() const { return byte(0x14, 5, 1); } + uint32_t reset_timer_a() const { return byte(0x14, 4, 1); } + uint32_t enable_timer_b() const { return byte(0x14, 3, 1); } + uint32_t enable_timer_a() const { return byte(0x14, 2, 1); } + uint32_t load_timer_b() const { return byte(0x14, 1, 1); } + uint32_t load_timer_a() const { return byte(0x14, 0, 1); } + uint32_t lfo2_pm_depth() const { return byte(0x188, 0, 7); } // fake + uint32_t lfo2_rate() const { return byte(0x16, 0, 8); } + uint32_t lfo2_am_depth() const { return byte(0x17, 0, 7); } + uint32_t lfo_rate() const { return byte(0x18, 0, 8); } + uint32_t lfo_am_depth() const { return byte(0x19, 0, 7); } + uint32_t lfo_pm_depth() const { return byte(0x189, 0, 7); } // fake + uint32_t output_bits() const { return byte(0x1b, 6, 2); } + uint32_t lfo2_sync() const { return byte(0x1b, 5, 1); } + uint32_t lfo_sync() const { return byte(0x1b, 4, 1); } + uint32_t lfo2_waveform() const { return byte(0x1b, 2, 2); } + uint32_t lfo_waveform() const { return byte(0x1b, 0, 2); } + + // per-channel registers + uint32_t ch_volume(uint32_t choffs) const { return byte(0x00, 0, 8, choffs); } + uint32_t ch_output_any(uint32_t choffs) const { return byte(0x20, 7, 1, choffs) | byte(0x30, 0, 1, choffs); } + uint32_t ch_output_0(uint32_t choffs) const { return byte(0x30, 0, 1, choffs); } + uint32_t ch_output_1(uint32_t choffs) const { return byte(0x20, 7, 1, choffs) | byte(0x30, 0, 1, choffs); } + uint32_t ch_output_2(uint32_t choffs) const { return 0; } + uint32_t ch_output_3(uint32_t choffs) const { return 0; } + uint32_t ch_key_on(uint32_t choffs) const { return byte(0x20, 6, 1, choffs); } + uint32_t ch_feedback(uint32_t choffs) const { return byte(0x20, 3, 3, choffs); } + uint32_t ch_algorithm(uint32_t choffs) const { return byte(0x20, 0, 3, choffs); } + uint32_t ch_block_freq(uint32_t choffs) const { return word(0x28, 0, 7, 0x30, 2, 6, choffs); } + uint32_t ch_lfo_pm_sens(uint32_t choffs) const { return byte(0x38, 4, 3, choffs); } + uint32_t ch_lfo_am_sens(uint32_t choffs) const { return byte(0x38, 0, 2, choffs); } + uint32_t ch_lfo2_pm_sens(uint32_t choffs) const { return byte(0x180, 4, 3, choffs); } // fake + uint32_t ch_lfo2_am_sens(uint32_t choffs) const { return byte(0x180, 0, 2, choffs); } // fake + + // per-operator registers + uint32_t op_detune(uint32_t opoffs) const { return byte(0x40, 4, 3, opoffs); } + uint32_t op_multiple(uint32_t opoffs) const { return byte(0x40, 0, 4, opoffs); } + uint32_t op_fix_range(uint32_t opoffs) const { return byte(0x40, 4, 3, opoffs); } + uint32_t op_fix_frequency(uint32_t opoffs) const { return byte(0x40, 0, 4, opoffs); } + uint32_t op_waveform(uint32_t opoffs) const { return byte(0x100, 4, 3, opoffs); } // fake + uint32_t op_fine(uint32_t opoffs) const { return byte(0x100, 0, 4, opoffs); } // fake + uint32_t op_total_level(uint32_t opoffs) const { return byte(0x60, 0, 7, opoffs); } + uint32_t op_ksr(uint32_t opoffs) const { return byte(0x80, 6, 2, opoffs); } + uint32_t op_fix_mode(uint32_t opoffs) const { return byte(0x80, 5, 1, opoffs); } + uint32_t op_attack_rate(uint32_t opoffs) const { return byte(0x80, 0, 5, opoffs); } + uint32_t op_lfo_am_enable(uint32_t opoffs) const { return byte(0xa0, 7, 1, opoffs); } + uint32_t op_decay_rate(uint32_t opoffs) const { return byte(0xa0, 0, 5, opoffs); } + uint32_t op_detune2(uint32_t opoffs) const { return byte(0xc0, 6, 2, opoffs); } + uint32_t op_sustain_rate(uint32_t opoffs) const { return byte(0xc0, 0, 5, opoffs); } + uint32_t op_eg_shift(uint32_t opoffs) const { return byte(0x120, 6, 2, opoffs); } // fake + uint32_t op_reverb_rate(uint32_t opoffs) const { return byte(0x120, 0, 3, opoffs); } // fake + uint32_t op_sustain_level(uint32_t opoffs) const { return byte(0xe0, 4, 4, opoffs); } + uint32_t op_release_rate(uint32_t opoffs) const { return byte(0xe0, 0, 4, opoffs); } + +protected: + // return a bitfield extracted from a byte + uint32_t byte(uint32_t offset, uint32_t start, uint32_t count, uint32_t extra_offset = 0) const + { + return bitfield(m_regdata[offset + extra_offset], start, count); + } + + // return a bitfield extracted from a pair of bytes, MSBs listed first + uint32_t word(uint32_t offset1, uint32_t start1, uint32_t count1, uint32_t offset2, uint32_t start2, uint32_t count2, uint32_t extra_offset = 0) const + { + return (byte(offset1, start1, count1, extra_offset) << count2) | byte(offset2, start2, count2, extra_offset); + } + + // internal state + uint32_t m_lfo_counter[2]; // LFO counter + uint32_t m_noise_lfsr; // noise LFSR state + uint8_t m_noise_counter; // noise counter + uint8_t m_noise_state; // latched noise state + uint8_t m_noise_lfo; // latched LFO noise value + uint8_t m_lfo_am[2]; // current LFO AM value + uint8_t m_regdata[REGISTERS]; // register data + uint16_t m_phase_substep[OPERATORS]; // phase substep for fixed frequency + int16_t m_lfo_waveform[4][LFO_WAVEFORM_LENGTH]; // LFO waveforms; AM in low 8, PM in upper 8 + uint16_t m_waveform[WAVEFORMS][WAVEFORM_LENGTH]; // waveforms +}; + + + +//********************************************************* +// IMPLEMENTATION CLASSES +//********************************************************* + +// ======================> ym2414 + +class ym2414 +{ +public: + using fm_engine = fm_engine_base; + static constexpr uint32_t OUTPUTS = fm_engine::OUTPUTS; + using output_data = fm_engine::output_data; + + // constructor + ym2414(ymfm_interface &intf); + + // reset + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // pass-through helpers + uint32_t sample_rate(uint32_t input_clock) const { return m_fm.sample_rate(input_clock); } + void invalidate_caches() { m_fm.invalidate_caches(); } + + // read access + uint8_t read_status(); + uint8_t read(uint32_t offset); + + // write access + void write_address(uint8_t data); + void write_data(uint8_t data); + void write(uint32_t offset, uint8_t data); + + // generate one sample of sound + void generate(output_data *output, uint32_t numsamples = 1); + +protected: + // internal state + uint8_t m_address; // address register + fm_engine m_fm; // core FM engine +}; + +} + + +#endif // YMFM_OPZ_H diff --git a/src/sound/ymfm/ymfm_pcm.cpp b/src/sound/ymfm/ymfm_pcm.cpp new file mode 100644 index 000000000..50595133b --- /dev/null +++ b/src/sound/ymfm/ymfm_pcm.cpp @@ -0,0 +1,715 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_pcm.h" +#include "ymfm_fm.h" +#include "ymfm_fm.ipp" + +namespace ymfm +{ + +//********************************************************* +// PCM REGISTERS +//********************************************************* + +//------------------------------------------------- +// reset - reset the register state +//------------------------------------------------- + +void pcm_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); + m_regdata[0x02] = 0x20; + m_regdata[0xf8] = 0x1b; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void pcm_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_regdata); +} + + +//------------------------------------------------- +// cache_channel_data - update the cache with +// data from the registers +//------------------------------------------------- + +void pcm_registers::cache_channel_data(uint32_t choffs, pcm_cache &cache) +{ + // compute step from octave and fnumber; the math here implies + // a .18 fraction but .16 should be perfectly fine + int32_t octave = int8_t(ch_octave(choffs) << 4) >> 4; + uint32_t fnum = ch_fnumber(choffs); + cache.step = ((0x400 | fnum) << (octave + 7)) >> 2; + + // total level is computed as a .10 value for interpolation + cache.total_level = ch_total_level(choffs) << 10; + + // compute panning values in terms of envelope attenuation + int32_t panpot = int8_t(ch_panpot(choffs) << 4) >> 4; + if (panpot >= 0) + { + cache.pan_left = (panpot == 7) ? 0x3ff : 0x20 * panpot; + cache.pan_right = 0; + } + else if (panpot >= -7) + { + cache.pan_left = 0; + cache.pan_right = (panpot == -7) ? 0x3ff : -0x20 * panpot; + } + else + cache.pan_left = cache.pan_right = 0x3ff; + + // determine the LFO stepping value; this how much to add to a running + // x.18 value for the LFO; steps were derived from frequencies in the + // manual and come out very close with these values + static const uint8_t s_lfo_steps[8] = { 1, 12, 19, 25, 31, 35, 37, 42 }; + cache.lfo_step = s_lfo_steps[ch_lfo_speed(choffs)]; + + // AM LFO depth values, derived from the manual; note each has at most + // 2 bits to make the "multiply" easy in hardware + static const uint8_t s_am_depth[8] = { 0, 0x14, 0x20, 0x28, 0x30, 0x40, 0x50, 0x80 }; + cache.am_depth = s_am_depth[ch_am_depth(choffs)]; + + // PM LFO depth values; these are converted from the manual's cents values + // into f-numbers; the computations come out quite cleanly so pretty sure + // these are correct + static const uint8_t s_pm_depth[8] = { 0, 2, 3, 4, 6, 12, 24, 48 }; + cache.pm_depth = s_pm_depth[ch_vibrato(choffs)]; + + // 4-bit sustain level, but 15 means 31 so effectively 5 bits + cache.eg_sustain = ch_sustain_level(choffs); + cache.eg_sustain |= (cache.eg_sustain + 1) & 0x10; + cache.eg_sustain <<= 5; + + // compute the key scaling correction factor; 15 means don't do any correction + int32_t correction = ch_rate_correction(choffs); + if (correction == 15) + correction = 0; + else + correction = (octave + correction) * 2 + bitfield(fnum, 9); + + // compute the envelope generator rates + cache.eg_rate[EG_ATTACK] = effective_rate(ch_attack_rate(choffs), correction); + cache.eg_rate[EG_DECAY] = effective_rate(ch_decay_rate(choffs), correction); + cache.eg_rate[EG_SUSTAIN] = effective_rate(ch_sustain_rate(choffs), correction); + cache.eg_rate[EG_RELEASE] = effective_rate(ch_release_rate(choffs), correction); + cache.eg_rate[EG_REVERB] = 5; + + // if damping is on, override some things; essentially decay at a hardcoded + // rate of 48 until -12db (0x80), then at maximum rate for the rest + if (ch_damp(choffs) != 0) + { + cache.eg_rate[EG_DECAY] = 48; + cache.eg_rate[EG_SUSTAIN] = 63; + cache.eg_rate[EG_RELEASE] = 63; + cache.eg_sustain = 0x80; + } +} + + +//------------------------------------------------- +// effective_rate - return the effective rate, +// clamping and applying corrections as needed +//------------------------------------------------- + +uint32_t pcm_registers::effective_rate(uint32_t raw, uint32_t correction) +{ + // raw rates of 0 and 15 just pin to min/max + if (raw == 0) + return 0; + if (raw == 15) + return 63; + + // otherwise add the correction and clamp to range + return clamp(raw * 4 + correction, 0, 63); +} + + + +//********************************************************* +// PCM CHANNEL +//********************************************************* + +//------------------------------------------------- +// pcm_channel - constructor +//------------------------------------------------- + +pcm_channel::pcm_channel(pcm_engine &owner, uint32_t choffs) : + m_choffs(choffs), + m_baseaddr(0), + m_endpos(0), + m_looppos(0), + m_curpos(0), + m_nextpos(0), + m_lfo_counter(0), + m_eg_state(EG_RELEASE), + m_env_attenuation(0x3ff), + m_total_level(0x7f << 10), + m_format(0), + m_key_state(0), + m_regs(owner.regs()), + m_owner(owner) +{ +} + + +//------------------------------------------------- +// reset - reset the channel state +//------------------------------------------------- + +void pcm_channel::reset() +{ + m_baseaddr = 0; + m_endpos = 0; + m_looppos = 0; + m_curpos = 0; + m_nextpos = 0; + m_lfo_counter = 0; + m_eg_state = EG_RELEASE; + m_env_attenuation = 0x3ff; + m_total_level = 0x7f << 10; + m_format = 0; + m_key_state = 0; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void pcm_channel::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_baseaddr); + state.save_restore(m_endpos); + state.save_restore(m_looppos); + state.save_restore(m_curpos); + state.save_restore(m_nextpos); + state.save_restore(m_lfo_counter); + state.save_restore(m_eg_state); + state.save_restore(m_env_attenuation); + state.save_restore(m_total_level); + state.save_restore(m_format); + state.save_restore(m_key_state); +} + + +//------------------------------------------------- +// prepare - prepare for clocking +//------------------------------------------------- + +bool pcm_channel::prepare() +{ + // cache the data + m_regs.cache_channel_data(m_choffs, m_cache); + + // clock the key state + if ((m_key_state & KEY_PENDING) != 0) + { + uint8_t oldstate = m_key_state; + m_key_state = (m_key_state >> 1) & KEY_ON; + if (((oldstate ^ m_key_state) & KEY_ON) != 0) + { + if ((m_key_state & KEY_ON) != 0) + start_attack(); + else + start_release(); + } + } + + // set the total level directly if not interpolating + if (m_regs.ch_level_direct(m_choffs)) + m_total_level = m_cache.total_level; + + // we're active until we're quiet after the release + return (m_eg_state < EG_RELEASE || m_env_attenuation < EG_QUIET); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +void pcm_channel::clock(uint32_t env_counter) +{ + // clock the LFO, which is an x.18 value incremented based on the + // LFO speed value + m_lfo_counter += m_cache.lfo_step; + + // clock the envelope + clock_envelope(env_counter); + + // determine the step after applying vibrato + uint32_t step = m_cache.step; + if (m_cache.pm_depth != 0) + { + // shift the LFO by 1/4 cycle for PM so that it starts at 0 + uint32_t lfo_shifted = m_lfo_counter + (1 << 16); + int32_t lfo_value = bitfield(lfo_shifted, 10, 7); + if (bitfield(lfo_shifted, 17) != 0) + lfo_value ^= 0x7f; + lfo_value -= 0x40; + step += (lfo_value * int32_t(m_cache.pm_depth)) >> 7; + } + + // advance the sample step and loop as needed + m_curpos = m_nextpos; + m_nextpos = m_curpos + step; + if (m_nextpos >= m_endpos) + m_nextpos += m_looppos - m_endpos; + + // interpolate total level if needed + if (m_total_level != m_cache.total_level) + { + // max->min volume takes 156.4ms, or pretty close to 19/1024 per 44.1kHz sample + // min->max volume is half that, so advance by 38/1024 per sample + if (m_total_level < m_cache.total_level) + m_total_level = std::min(m_total_level + 19, m_cache.total_level); + else + m_total_level = std::max(m_total_level - 38, m_cache.total_level); + } +} + + +//------------------------------------------------- +// output - return the computed output value, with +// panning applied +//------------------------------------------------- + +void pcm_channel::output(output_data &output) const +{ + // early out if the envelope is effectively off + uint32_t envelope = m_env_attenuation; + if (envelope > EG_QUIET) + return; + + // add in LFO AM modulation + if (m_cache.am_depth != 0) + { + uint32_t lfo_value = bitfield(m_lfo_counter, 10, 7); + if (bitfield(m_lfo_counter, 17) != 0) + lfo_value ^= 0x7f; + envelope += (lfo_value * m_cache.am_depth) >> 7; + } + + // add in the current interpolated total level value, which is a .10 + // value shifted left by 2 + envelope += m_total_level >> 8; + + // add in panning effect and clamp + uint32_t lenv = std::min(envelope + m_cache.pan_left, 0x3ff); + uint32_t renv = std::min(envelope + m_cache.pan_right, 0x3ff); + + // convert to volume as a .11 fraction + int32_t lvol = attenuation_to_volume(lenv << 2); + int32_t rvol = attenuation_to_volume(renv << 2); + + // fetch current sample and add + int16_t sample = fetch_sample(); + uint32_t outnum = m_regs.ch_output_channel(m_choffs) * 2; + output.data[outnum + 0] += (lvol * sample) >> 15; + output.data[outnum + 1] += (rvol * sample) >> 15; +} + + +//------------------------------------------------- +// keyonoff - signal key on/off +//------------------------------------------------- + +void pcm_channel::keyonoff(bool on) +{ + // mark the key state as pending + m_key_state |= KEY_PENDING | (on ? KEY_PENDING_ON : 0); + + // don't log masked channels + if ((m_key_state & (KEY_PENDING_ON | KEY_ON)) == KEY_PENDING_ON && ((debug::GLOBAL_PCM_CHANNEL_MASK >> m_choffs) & 1) != 0) + { + debug::log_keyon("KeyOn PCM-%02d: num=%3d oct=%2d fnum=%03X level=%02X%c ADSR=%X/%X/%X/%X SL=%X", + m_choffs, + m_regs.ch_wave_table_num(m_choffs), + int8_t(m_regs.ch_octave(m_choffs) << 4) >> 4, + m_regs.ch_fnumber(m_choffs), + m_regs.ch_total_level(m_choffs), + m_regs.ch_level_direct(m_choffs) ? '!' : '/', + m_regs.ch_attack_rate(m_choffs), + m_regs.ch_decay_rate(m_choffs), + m_regs.ch_sustain_rate(m_choffs), + m_regs.ch_release_rate(m_choffs), + m_regs.ch_sustain_level(m_choffs)); + + if (m_regs.ch_rate_correction(m_choffs) != 15) + debug::log_keyon(" RC=%X", m_regs.ch_rate_correction(m_choffs)); + + if (m_regs.ch_pseudo_reverb(m_choffs) != 0) + debug::log_keyon(" %s", "REV"); + if (m_regs.ch_damp(m_choffs) != 0) + debug::log_keyon(" %s", "DAMP"); + + if (m_regs.ch_vibrato(m_choffs) != 0 || m_regs.ch_am_depth(m_choffs) != 0) + { + if (m_regs.ch_vibrato(m_choffs) != 0) + debug::log_keyon(" VIB=%d", m_regs.ch_vibrato(m_choffs)); + if (m_regs.ch_am_depth(m_choffs) != 0) + debug::log_keyon(" AM=%d", m_regs.ch_am_depth(m_choffs)); + debug::log_keyon(" LFO=%d", m_regs.ch_lfo_speed(m_choffs)); + } + debug::log_keyon("%s", "\n"); + } +} + + +//------------------------------------------------- +// load_wavetable - load a wavetable by fetching +// its data from external memory +//------------------------------------------------- + +void pcm_channel::load_wavetable() +{ + // determine the address of the wave table header + uint32_t wavnum = m_regs.ch_wave_table_num(m_choffs); + uint32_t wavheader = 12 * wavnum; + + // above 384 it may be in a different bank + if (wavnum >= 384) + { + uint32_t bank = m_regs.wave_table_header(); + if (bank != 0) + wavheader = 512*1024 * bank + (wavnum - 384) * 12; + } + + // fetch the 22-bit base address and 2-bit format + uint8_t byte = read_pcm(wavheader + 0); + m_format = bitfield(byte, 6, 2); + m_baseaddr = bitfield(byte, 0, 6) << 16; + m_baseaddr |= read_pcm(wavheader + 1) << 8; + m_baseaddr |= read_pcm(wavheader + 2) << 0; + + // fetch the 16-bit loop position + m_looppos = read_pcm(wavheader + 3) << 8; + m_looppos |= read_pcm(wavheader + 4); + m_looppos <<= 16; + + // fetch the 16-bit end position, which is stored as a negative value + // for some reason that is unclear + m_endpos = read_pcm(wavheader + 5) << 8; + m_endpos |= read_pcm(wavheader + 6); + m_endpos = -int32_t(m_endpos) << 16; + + // remaining data values set registers + m_owner.write(0x80 + m_choffs, read_pcm(wavheader + 7)); + m_owner.write(0x98 + m_choffs, read_pcm(wavheader + 8)); + m_owner.write(0xb0 + m_choffs, read_pcm(wavheader + 9)); + m_owner.write(0xc8 + m_choffs, read_pcm(wavheader + 10)); + m_owner.write(0xe0 + m_choffs, read_pcm(wavheader + 11)); + + // reset the envelope so we don't continue playing mid-sample from previous key ons + m_env_attenuation = 0x3ff; +} + + +//------------------------------------------------- +// read_pcm - read a byte from the external PCM +// memory interface +//------------------------------------------------- + +uint8_t pcm_channel::read_pcm(uint32_t address) const +{ + return m_owner.intf().ymfm_external_read(ACCESS_PCM, address); +} + + +//------------------------------------------------- +// start_attack - start the attack phase +//------------------------------------------------- + +void pcm_channel::start_attack() +{ + // don't change anything if already in attack state + if (m_eg_state == EG_ATTACK) + return; + m_eg_state = EG_ATTACK; + + // reset the LFO if requested + if (m_regs.ch_lfo_reset(m_choffs)) + m_lfo_counter = 0; + + // if the attack rate == 63 then immediately go to max attenuation + if (m_cache.eg_rate[EG_ATTACK] == 63) + m_env_attenuation = 0; + + // reset the positions + m_curpos = m_nextpos = 0; +} + + +//------------------------------------------------- +// start_release - start the release phase +//------------------------------------------------- + +void pcm_channel::start_release() +{ + // don't change anything if already in release or reverb state + if (m_eg_state >= EG_RELEASE) + return; + m_eg_state = EG_RELEASE; +} + + +//------------------------------------------------- +// clock_envelope - clock the envelope generator +//------------------------------------------------- + +void pcm_channel::clock_envelope(uint32_t env_counter) +{ + // handle attack->decay transitions + if (m_eg_state == EG_ATTACK && m_env_attenuation == 0) + m_eg_state = EG_DECAY; + + // handle decay->sustain transitions + if (m_eg_state == EG_DECAY && m_env_attenuation >= m_cache.eg_sustain) + m_eg_state = EG_SUSTAIN; + + // fetch the appropriate 6-bit rate value from the cache + uint32_t rate = m_cache.eg_rate[m_eg_state]; + + // compute the rate shift value; this is the shift needed to + // apply to the env_counter such that it becomes a 5.11 fixed + // point number + uint32_t rate_shift = rate >> 2; + env_counter <<= rate_shift; + + // see if the fractional part is 0; if not, it's not time to clock + if (bitfield(env_counter, 0, 11) != 0) + return; + + // determine the increment based on the non-fractional part of env_counter + uint32_t relevant_bits = bitfield(env_counter, (rate_shift <= 11) ? 11 : rate_shift, 3); + uint32_t increment = attenuation_increment(rate, relevant_bits); + + // attack is the only one that increases + if (m_eg_state == EG_ATTACK) + m_env_attenuation += (~m_env_attenuation * increment) >> 4; + + // all other cases are similar + else + { + // apply the increment + m_env_attenuation += increment; + + // clamp the final attenuation + if (m_env_attenuation >= 0x400) + m_env_attenuation = 0x3ff; + + // transition to reverb at -18dB if enabled + if (m_env_attenuation >= 0xc0 && m_eg_state < EG_REVERB && m_regs.ch_pseudo_reverb(m_choffs)) + m_eg_state = EG_REVERB; + } +} + + +//------------------------------------------------- +// fetch_sample - fetch a sample at the current +// position +//------------------------------------------------- + +int16_t pcm_channel::fetch_sample() const +{ + uint32_t addr = m_baseaddr; + uint32_t pos = m_curpos >> 16; + + // 8-bit PCM: shift up by 8 + if (m_format == 0) + return read_pcm(addr + pos) << 8; + + // 16-bit PCM: assemble from 2 halves + if (m_format == 2) + { + addr += pos * 2; + return (read_pcm(addr) << 8) | read_pcm(addr + 1); + } + + // 12-bit PCM: assemble out of half of 3 bytes + addr += (pos / 2) * 3; + if ((pos & 1) == 0) + return (read_pcm(addr + 0) << 8) | ((read_pcm(addr + 1) << 4) & 0xf0); + else + return (read_pcm(addr + 2) << 8) | ((read_pcm(addr + 1) << 0) & 0xf0); +} + + + +//********************************************************* +// PCM ENGINE +//********************************************************* + +//------------------------------------------------- +// pcm_engine - constructor +//------------------------------------------------- + +pcm_engine::pcm_engine(ymfm_interface &intf) : + m_intf(intf), + m_env_counter(0), + m_modified_channels(ALL_CHANNELS), + m_active_channels(ALL_CHANNELS) +{ + // create the channels + for (int chnum = 0; chnum < CHANNELS; chnum++) + m_channel[chnum] = std::make_unique(*this, chnum); +} + + +//------------------------------------------------- +// reset - reset the engine state +//------------------------------------------------- + +void pcm_engine::reset() +{ + // reset register state + m_regs.reset(); + + // reset each channel + for (auto &chan : m_channel) + chan->reset(); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void pcm_engine::save_restore(ymfm_saved_state &state) +{ + // save our data + state.save_restore(m_env_counter); + + // save channel state + for (int chnum = 0; chnum < CHANNELS; chnum++) + m_channel[chnum]->save_restore(state); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +void pcm_engine::clock(uint32_t chanmask) +{ + // if something was modified, prepare + // also prepare every 4k samples to catch ending notes + if (m_modified_channels != 0 || m_prepare_count++ >= 4096) + { + // call each channel to prepare + m_active_channels = 0; + for (int chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + if (m_channel[chnum]->prepare()) + m_active_channels |= 1 << chnum; + + // reset the modified channels and prepare count + m_modified_channels = m_prepare_count = 0; + } + + // increment the envelope counter; the envelope generator + // only clocks every other sample in order to make the PCM + // envelopes line up with the FM envelopes (after taking into + // account the different FM sampling rate) + m_env_counter++; + + // now update the state of all the channels and operators + for (int chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + m_channel[chnum]->clock(m_env_counter >> 1); +} + + +//------------------------------------------------- +// update - master update function +//------------------------------------------------- + +void pcm_engine::output(output_data &output, uint32_t chanmask) +{ + // mask out some channels for debug purposes + chanmask &= debug::GLOBAL_PCM_CHANNEL_MASK; + + // compute the output of each channel + for (int chnum = 0; chnum < CHANNELS; chnum++) + if (bitfield(chanmask, chnum)) + m_channel[chnum]->output(output); +} + + +//------------------------------------------------- +// read - handle reads from the PCM registers +//------------------------------------------------- + +uint8_t pcm_engine::read(uint32_t regnum) +{ + // handle reads from the data register + if (regnum == 0x06 && m_regs.memory_access_mode() != 0) + return m_intf.ymfm_external_read(ACCESS_PCM, m_regs.memory_address_autoinc()); + + return m_regs.read(regnum); +} + + +//------------------------------------------------- +// write - handle writes to the PCM registers +//------------------------------------------------- + +void pcm_engine::write(uint32_t regnum, uint8_t data) +{ + // handle reads to the data register + if (regnum == 0x06 && m_regs.memory_access_mode() != 0) + { + m_intf.ymfm_external_write(ACCESS_PCM, m_regs.memory_address_autoinc(), data); + return; + } + + // for now just mark all channels as modified + m_modified_channels = ALL_CHANNELS; + + // most writes are passive, consumed only when needed + m_regs.write(regnum, data); + + // however, process keyons immediately + if (regnum >= 0x68 && regnum <= 0x7f) + m_channel[regnum - 0x68]->keyonoff(bitfield(data, 7)); + + // and also wavetable writes + else if (regnum >= 0x08 && regnum <= 0x1f) + m_channel[regnum - 0x08]->load_wavetable(); +} + +} diff --git a/src/sound/ymfm/ymfm_pcm.h b/src/sound/ymfm/ymfm_pcm.h new file mode 100644 index 000000000..2022a69b9 --- /dev/null +++ b/src/sound/ymfm/ymfm_pcm.h @@ -0,0 +1,347 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_PCM_H +#define YMFM_PCM_H + +#pragma once + +#include "ymfm.h" + +namespace ymfm +{ + +/* +Note to self: Sega "Multi-PCM" is almost identical to this + +28 channels + +Writes: +00 = data reg, causes write +01 = target slot = data - (data / 8) +02 = address (clamped to 7) + +Slot data (registers with ADSR/KSR seem to be inaccessible): +0: xxxx---- panpot +1: xxxxxxxx wavetable low +2: xxxxxx-- pitch low + -------x wavetable high +3: xxxx---- octave + ----xxxx pitch hi +4: x------- key on +5: xxxxxxx- total level + -------x level direct (0=interpolate) +6: --xxx--- LFO frequency + -----xxx PM sensitivity +7: -----xxx AM sensitivity + +Sample data: ++00: start hi ++01: start mid ++02: start low ++03: loop hi ++04: loop low ++05: -end hi ++06: -end low ++07: vibrato (reg 6) ++08: attack/decay ++09: sustain level/rate ++0A: ksr/release ++0B: LFO amplitude (reg 7) + +*/ + +//********************************************************* +// INTERFACE CLASSES +//********************************************************* + +class pcm_engine; + + +// ======================> pcm_cache + +// this class holds data that is computed once at the start of clocking +// and remains static during subsequent sound generation +struct pcm_cache +{ + uint32_t step; // sample position step, as a .16 value + uint32_t total_level; // target total level, as a .10 value + uint32_t pan_left; // left panning attenuation + uint32_t pan_right; // right panning attenuation + uint32_t eg_sustain; // sustain level, shifted up to envelope values + uint8_t eg_rate[EG_STATES]; // envelope rate, including KSR + uint8_t lfo_step; // stepping value for LFO + uint8_t am_depth; // scale value for AM LFO + uint8_t pm_depth; // scale value for PM LFO +}; + + +// ======================> pcm_registers + +// +// PCM register map: +// +// System-wide registers: +// 00-01 xxxxxxxx LSI Test +// 02 -------x Memory access mode (0=sound gen, 1=read/write) +// ------x- Memory type (0=ROM, 1=ROM+SRAM) +// ---xxx-- Wave table header +// xxx----- Device ID (=1 for YMF278B) +// 03 --xxxxxx Memory address high +// 04 xxxxxxxx Memory address mid +// 05 xxxxxxxx Memory address low +// 06 xxxxxxxx Memory data +// F8 --xxx--- Mix control (FM_R) +// -----xxx Mix control (FM_L) +// F9 --xxx--- Mix control (PCM_R) +// -----xxx Mix control (PCM_L) +// +// Channel-specific registers: +// 08-1F xxxxxxxx Wave table number low +// 20-37 -------x Wave table number high +// xxxxxxx- F-number low +// 38-4F -----xxx F-number high +// ----x--- Pseudo-reverb +// xxxx---- Octave +// 50-67 xxxxxxx- Total level +// -------x Level direct +// 68-7F x------- Key on +// -x------ Damp +// --x----- LFO reset +// ---x---- Output channel +// ----xxxx Panpot +// 80-97 --xxx--- LFO speed +// -----xxx Vibrato +// 98-AF xxxx---- Attack rate +// ----xxxx Decay rate +// B0-C7 xxxx---- Sustain level +// ----xxxx Sustain rate +// C8-DF xxxx---- Rate correction +// ----xxxx Release rate +// E0-F7 -----xxx AM depth + +class pcm_registers +{ +public: + // constants + static constexpr uint32_t OUTPUTS = 4; + static constexpr uint32_t CHANNELS = 24; + static constexpr uint32_t REGISTERS = 0x100; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + + // constructor + pcm_registers() { } + + // save/restore + void save_restore(ymfm_saved_state &state); + + // reset to initial state + void reset(); + + // update cache information + void cache_channel_data(uint32_t choffs, pcm_cache &cache); + + // direct read/write access + uint8_t read(uint32_t index ) { return m_regdata[index]; } + void write(uint32_t index, uint8_t data) { m_regdata[index] = data; } + + // system-wide registers + uint32_t memory_access_mode() const { return bitfield(m_regdata[0x02], 0); } + uint32_t memory_type() const { return bitfield(m_regdata[0x02], 1); } + uint32_t wave_table_header() const { return bitfield(m_regdata[0x02], 2, 3); } + uint32_t device_id() const { return bitfield(m_regdata[0x02], 5, 3); } + uint32_t memory_address() const { return (bitfield(m_regdata[0x03], 0, 6) << 16) | (m_regdata[0x04] << 8) | m_regdata[0x05]; } + uint32_t memory_data() const { return m_regdata[0x06]; } + uint32_t mix_fm_r() const { return bitfield(m_regdata[0xf8], 3, 3); } + uint32_t mix_fm_l() const { return bitfield(m_regdata[0xf8], 0, 3); } + uint32_t mix_pcm_r() const { return bitfield(m_regdata[0xf9], 3, 3); } + uint32_t mix_pcm_l() const { return bitfield(m_regdata[0xf9], 0, 3); } + + // per-channel registers + uint32_t ch_wave_table_num(uint32_t choffs) const { return m_regdata[choffs + 0x08] | (bitfield(m_regdata[choffs + 0x20], 0) << 8); } + uint32_t ch_fnumber(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x20], 1, 7) | (bitfield(m_regdata[choffs + 0x38], 0, 3) << 7); } + uint32_t ch_pseudo_reverb(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x38], 3); } + uint32_t ch_octave(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x38], 4, 4); } + uint32_t ch_total_level(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x50], 1, 7); } + uint32_t ch_level_direct(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x50], 0); } + uint32_t ch_keyon(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x68], 7); } + uint32_t ch_damp(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x68], 6); } + uint32_t ch_lfo_reset(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x68], 5); } + uint32_t ch_output_channel(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x68], 4); } + uint32_t ch_panpot(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x68], 0, 4); } + uint32_t ch_lfo_speed(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x80], 3, 3); } + uint32_t ch_vibrato(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x80], 0, 3); } + uint32_t ch_attack_rate(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x98], 4, 4); } + uint32_t ch_decay_rate(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0x98], 0, 4); } + uint32_t ch_sustain_level(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0xb0], 4, 4); } + uint32_t ch_sustain_rate(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0xb0], 0, 4); } + uint32_t ch_rate_correction(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0xc8], 4, 4); } + uint32_t ch_release_rate(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0xc8], 0, 4); } + uint32_t ch_am_depth(uint32_t choffs) const { return bitfield(m_regdata[choffs + 0xe0], 0, 3); } + + // return the memory address and increment it + uint32_t memory_address_autoinc() + { + uint32_t result = memory_address(); + uint32_t newval = result + 1; + m_regdata[0x05] = newval >> 0; + m_regdata[0x06] = newval >> 8; + m_regdata[0x07] = (newval >> 16) & 0x3f; + return result; + } + +private: + // internal helpers + uint32_t effective_rate(uint32_t raw, uint32_t correction); + + // internal state + uint8_t m_regdata[REGISTERS]; // register data +}; + + +// ======================> pcm_channel + +class pcm_channel +{ + static constexpr uint8_t KEY_ON = 0x01; + static constexpr uint8_t KEY_PENDING_ON = 0x02; + static constexpr uint8_t KEY_PENDING = 0x04; + + // "quiet" value, used to optimize when we can skip doing working + static constexpr uint32_t EG_QUIET = 0x200; + +public: + using output_data = ymfm_output; + + // constructor + pcm_channel(pcm_engine &owner, uint32_t choffs); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // reset the channel state + void reset(); + + // return the channel offset + uint32_t choffs() const { return m_choffs; } + + // prepare prior to clocking + bool prepare(); + + // master clocking function + void clock(uint32_t env_counter); + + // return the computed output value, with panning applied + void output(output_data &output) const; + + // signal key on/off + void keyonoff(bool on); + + // load a new wavetable entry + void load_wavetable(); + +private: + // internal helpers + void start_attack(); + void start_release(); + void clock_envelope(uint32_t env_counter); + int16_t fetch_sample() const; + uint8_t read_pcm(uint32_t address) const; + + // internal state + uint32_t const m_choffs; // channel offset + uint32_t m_baseaddr; // base address + uint32_t m_endpos; // ending position + uint32_t m_looppos; // loop position + uint32_t m_curpos; // current position + uint32_t m_nextpos; // next position + uint32_t m_lfo_counter; // LFO counter + envelope_state m_eg_state; // envelope state + uint16_t m_env_attenuation; // computed envelope attenuation + uint32_t m_total_level; // total level with as 7.10 for interp + uint8_t m_format; // sample format + uint8_t m_key_state; // current key state + pcm_cache m_cache; // cached data + pcm_registers &m_regs; // reference to registers + pcm_engine &m_owner; // reference to our owner +}; + + +// ======================> pcm_engine + +class pcm_engine +{ +public: + static constexpr int OUTPUTS = pcm_registers::OUTPUTS; + static constexpr int CHANNELS = pcm_registers::CHANNELS; + static constexpr uint32_t ALL_CHANNELS = pcm_registers::ALL_CHANNELS; + using output_data = pcm_channel::output_data; + + // constructor + pcm_engine(ymfm_interface &intf); + + // reset our status + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // master clocking function + void clock(uint32_t chanmask); + + // compute sum of channel outputs + void output(output_data &output, uint32_t chanmask); + + // read from the PCM registers + uint8_t read(uint32_t regnum); + + // write to the PCM registers + void write(uint32_t regnum, uint8_t data); + + // return a reference to our interface + ymfm_interface &intf() { return m_intf; } + + // return a reference to our registers + pcm_registers ®s() { return m_regs; } + +private: + // internal state + ymfm_interface &m_intf; // reference to the interface + uint32_t m_env_counter; // envelope counter + uint32_t m_modified_channels; // bitmask of modified channels + uint32_t m_active_channels; // bitmask of active channels + uint32_t m_prepare_count; // counter to do periodic prepare sweeps + std::unique_ptr m_channel[CHANNELS]; // array of channels + pcm_registers m_regs; // registers +}; + +} + +#endif // YMFM_PCM_H diff --git a/src/sound/ymfm/ymfm_ssg.cpp b/src/sound/ymfm/ymfm_ssg.cpp new file mode 100644 index 000000000..1c477d0de --- /dev/null +++ b/src/sound/ymfm/ymfm_ssg.cpp @@ -0,0 +1,279 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "ymfm_ssg.h" + +namespace ymfm +{ + +//********************************************************* +// SSG REGISTERS +//********************************************************* + +//------------------------------------------------- +// reset - reset the register state +//------------------------------------------------- + +void ssg_registers::reset() +{ + std::fill_n(&m_regdata[0], REGISTERS, 0); +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ssg_registers::save_restore(ymfm_saved_state &state) +{ + state.save_restore(m_regdata); +} + + + +//********************************************************* +// SSG ENGINE +//********************************************************* + +//------------------------------------------------- +// ssg_engine - constructor +//------------------------------------------------- + +ssg_engine::ssg_engine(ymfm_interface &intf) : + m_intf(intf), + m_tone_count{ 0,0,0 }, + m_tone_state{ 0,0,0 }, + m_envelope_count(0), + m_envelope_state(0), + m_noise_count(0), + m_noise_state(1), + m_override(nullptr) +{ +} + + +//------------------------------------------------- +// reset - reset the engine state +//------------------------------------------------- + +void ssg_engine::reset() +{ + // defer to the override if present + if (m_override != nullptr) + return m_override->ssg_reset(); + + // reset register state + m_regs.reset(); + + // reset engine state + for (int chan = 0; chan < 3; chan++) + { + m_tone_count[chan] = 0; + m_tone_state[chan] = 0; + } + m_envelope_count = 0; + m_envelope_state = 0; + m_noise_count = 0; + m_noise_state = 1; +} + + +//------------------------------------------------- +// save_restore - save or restore the data +//------------------------------------------------- + +void ssg_engine::save_restore(ymfm_saved_state &state) +{ + // save register state + m_regs.save_restore(state); + + // save engine state + state.save_restore(m_tone_count); + state.save_restore(m_tone_state); + state.save_restore(m_envelope_count); + state.save_restore(m_envelope_state); + state.save_restore(m_noise_count); + state.save_restore(m_noise_state); +} + + +//------------------------------------------------- +// clock - master clocking function +//------------------------------------------------- + +void ssg_engine::clock() +{ + // clock tones; tone period units are clock/16 but since we run at clock/8 + // that works out for us to toggle the state (50% duty cycle) at twice the + // programmed period + for (int chan = 0; chan < 3; chan++) + { + m_tone_count[chan]++; + if (m_tone_count[chan] >= m_regs.ch_tone_period(chan)) + { + m_tone_state[chan] ^= 1; + m_tone_count[chan] = 0; + } + } + + // clock noise; noise period units are clock/16 but since we run at clock/8, + // our counter needs a right shift prior to compare; note that a period of 0 + // should produce an indentical result to a period of 1, so add a special + // check against that case + m_noise_count++; + if ((m_noise_count >> 1) >= m_regs.noise_period() && m_noise_count != 1) + { + m_noise_state ^= (bitfield(m_noise_state, 0) ^ bitfield(m_noise_state, 3)) << 17; + m_noise_state >>= 1; + m_noise_count = 0; + } + + // clock envelope; envelope period units are clock/8 (manual says clock/256 + // but that's for all 32 steps) + m_envelope_count++; + if (m_envelope_count >= m_regs.envelope_period()) + { + m_envelope_state++; + m_envelope_count = 0; + } +} + + +//------------------------------------------------- +// output - output the current state +//------------------------------------------------- + +void ssg_engine::output(output_data &output) +{ + // volume to amplitude table, taken from MAME's implementation but biased + // so that 0 == 0 + static int16_t const s_amplitudes[32] = + { + 0, 32, 78, 141, 178, 222, 262, 306, + 369, 441, 509, 585, 701, 836, 965, 1112, + 1334, 1595, 1853, 2146, 2576, 3081, 3576, 4135, + 5000, 6006, 7023, 8155, 9963,11976,14132,16382 + }; + + // compute the envelope volume + uint32_t envelope_volume; + if ((m_regs.envelope_hold() | (m_regs.envelope_continue() ^ 1)) && m_envelope_state >= 32) + { + m_envelope_state = 32; + envelope_volume = ((m_regs.envelope_attack() ^ m_regs.envelope_alternate()) & m_regs.envelope_continue()) ? 31 : 0; + } + else + { + uint32_t attack = m_regs.envelope_attack(); + if (m_regs.envelope_alternate()) + attack ^= bitfield(m_envelope_state, 5); + envelope_volume = (m_envelope_state & 31) ^ (attack ? 0 : 31); + } + + // iterate over channels + for (int chan = 0; chan < 3; chan++) + { + // noise depends on the noise state, which is the LSB of m_noise_state + uint32_t noise_on = m_regs.ch_noise_enable_n(chan) | m_noise_state; + + // tone depends on the current tone state + uint32_t tone_on = m_regs.ch_tone_enable_n(chan) | m_tone_state[chan]; + + // if neither tone nor noise enabled, return 0 + uint32_t volume; + if ((noise_on & tone_on) == 0) + volume = 0; + + // if the envelope is enabled, use its amplitude + else if (m_regs.ch_envelope_enable(chan)) + volume = envelope_volume; + + // otherwise, scale the tone amplitude up to match envelope values + // according to the datasheet, amplitude 15 maps to envelope 31 + else + { + volume = m_regs.ch_amplitude(chan) * 2; + if (volume != 0) + volume |= 1; + } + + // convert to amplitude + output.data[chan] = s_amplitudes[volume]; + } +} + + +//------------------------------------------------- +// read - handle reads from the SSG registers +//------------------------------------------------- + +uint8_t ssg_engine::read(uint32_t regnum) +{ + // defer to the override if present + if (m_override != nullptr) + return m_override->ssg_read(regnum); + + // read from the I/O ports call the handlers if they are configured for input + if (regnum == 0x0e && !m_regs.io_a_out()) + return m_intf.ymfm_external_read(ACCESS_IO, 0); + else if (regnum == 0x0f && !m_regs.io_b_out()) + return m_intf.ymfm_external_read(ACCESS_IO, 1); + + // otherwise just return the register value + return m_regs.read(regnum); +} + + +//------------------------------------------------- +// write - handle writes to the SSG registers +//------------------------------------------------- + +void ssg_engine::write(uint32_t regnum, uint8_t data) +{ + // defer to the override if present + if (m_override != nullptr) + return m_override->ssg_write(regnum, data); + + // store the raw value to the register array; + // most writes are passive, consumed only when needed + m_regs.write(regnum, data); + + // writes to the envelope shape register reset the state + if (regnum == 0x0d) + m_envelope_state = 0; + + // writes to the I/O ports call the handlers if they are configured for output + else if (regnum == 0x0e && m_regs.io_a_out()) + m_intf.ymfm_external_write(ACCESS_IO, 0, data); + else if (regnum == 0x0f && m_regs.io_b_out()) + m_intf.ymfm_external_write(ACCESS_IO, 1, data); +} + +} diff --git a/src/sound/ymfm/ymfm_ssg.h b/src/sound/ymfm/ymfm_ssg.h new file mode 100644 index 000000000..749ad146f --- /dev/null +++ b/src/sound/ymfm/ymfm_ssg.h @@ -0,0 +1,205 @@ +// BSD 3-Clause License +// +// Copyright (c) 2021, Aaron Giles +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef YMFM_SSG_H +#define YMFM_SSG_H + +#pragma once + +#include "ymfm.h" + +namespace ymfm +{ + +//********************************************************* +// OVERRIDE INTERFACE +//********************************************************* + +// ======================> ssg_override + +// this class describes a simple interface to allow the internal SSG to be +// overridden with another implementation +class ssg_override +{ +public: + // reset our status + virtual void ssg_reset() = 0; + + // read/write to the SSG registers + virtual uint8_t ssg_read(uint32_t regnum) = 0; + virtual void ssg_write(uint32_t regnum, uint8_t data) = 0; + + // notification when the prescale has changed + virtual void ssg_prescale_changed() = 0; +}; + + +//********************************************************* +// REGISTER CLASS +//********************************************************* + +// ======================> ssg_registers + +// +// SSG register map: +// +// System-wide registers: +// 06 ---xxxxx Noise period +// 07 x------- I/O B in(0) or out(1) +// -x------ I/O A in(0) or out(1) +// --x----- Noise enable(0) or disable(1) for channel C +// ---x---- Noise enable(0) or disable(1) for channel B +// ----x--- Noise enable(0) or disable(1) for channel A +// -----x-- Tone enable(0) or disable(1) for channel C +// ------x- Tone enable(0) or disable(1) for channel B +// -------x Tone enable(0) or disable(1) for channel A +// 0B xxxxxxxx Envelope period fine +// 0C xxxxxxxx Envelope period coarse +// 0D ----x--- Envelope shape: continue +// -----x-- Envelope shape: attack/decay +// ------x- Envelope shape: alternate +// -------x Envelope shape: hold +// 0E xxxxxxxx 8-bit parallel I/O port A +// 0F xxxxxxxx 8-bit parallel I/O port B +// +// Per-channel registers: +// 00,02,04 xxxxxxxx Tone period (fine) for channel A,B,C +// 01,03,05 ----xxxx Tone period (coarse) for channel A,B,C +// 08,09,0A ---x---- Mode: fixed(0) or variable(1) for channel A,B,C +// ----xxxx Amplitude for channel A,B,C +// +class ssg_registers +{ +public: + // constants + static constexpr uint32_t OUTPUTS = 3; + static constexpr uint32_t CHANNELS = 3; + static constexpr uint32_t REGISTERS = 0x10; + static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1; + + // constructor + ssg_registers() { } + + // reset to initial state + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // direct read/write access + uint8_t read(uint32_t index) { return m_regdata[index]; } + void write(uint32_t index, uint8_t data) { m_regdata[index] = data; } + + // system-wide registers + uint32_t noise_period() const { return bitfield(m_regdata[0x06], 0, 5); } + uint32_t io_b_out() const { return bitfield(m_regdata[0x07], 7); } + uint32_t io_a_out() const { return bitfield(m_regdata[0x07], 6); } + uint32_t envelope_period() const { return m_regdata[0x0b] | (m_regdata[0x0c] << 8); } + uint32_t envelope_continue() const { return bitfield(m_regdata[0x0d], 3); } + uint32_t envelope_attack() const { return bitfield(m_regdata[0x0d], 2); } + uint32_t envelope_alternate() const { return bitfield(m_regdata[0x0d], 1); } + uint32_t envelope_hold() const { return bitfield(m_regdata[0x0d], 0); } + uint32_t io_a_data() const { return m_regdata[0x0e]; } + uint32_t io_b_data() const { return m_regdata[0x0f]; } + + // per-channel registers + uint32_t ch_noise_enable_n(uint32_t choffs) const { return bitfield(m_regdata[0x07], 3 + choffs); } + uint32_t ch_tone_enable_n(uint32_t choffs) const { return bitfield(m_regdata[0x07], 0 + choffs); } + uint32_t ch_tone_period(uint32_t choffs) const { return m_regdata[0x00 + 2 * choffs] | (bitfield(m_regdata[0x01 + 2 * choffs], 0, 4) << 8); } + uint32_t ch_envelope_enable(uint32_t choffs) const { return bitfield(m_regdata[0x08 + choffs], 4); } + uint32_t ch_amplitude(uint32_t choffs) const { return bitfield(m_regdata[0x08 + choffs], 0, 4); } + +private: + // internal state + uint8_t m_regdata[REGISTERS]; // register data +}; + + +// ======================> ssg_engine + +class ssg_engine +{ +public: + static constexpr int OUTPUTS = ssg_registers::OUTPUTS; + static constexpr int CHANNELS = ssg_registers::CHANNELS; + static constexpr int CLOCK_DIVIDER = 8; + + using output_data = ymfm_output; + + // constructor + ssg_engine(ymfm_interface &intf); + + // configure an override + void override(ssg_override &override) { m_override = &override; } + + // reset our status + void reset(); + + // save/restore + void save_restore(ymfm_saved_state &state); + + // master clocking function + void clock(); + + // compute sum of channel outputs + void output(output_data &output); + + // read/write to the SSG registers + uint8_t read(uint32_t regnum); + void write(uint32_t regnum, uint8_t data); + + // return a reference to our interface + ymfm_interface &intf() { return m_intf; } + + // return a reference to our registers + ssg_registers ®s() { return m_regs; } + + // true if we are overridden + bool overridden() const { return (m_override != nullptr); } + + // indicate the prescale has changed + void prescale_changed() { if (m_override != nullptr) m_override->ssg_prescale_changed(); } + +private: + // internal state + ymfm_interface &m_intf; // reference to the interface + uint32_t m_tone_count[3]; // current tone counter + uint32_t m_tone_state[3]; // current tone state + uint32_t m_envelope_count; // envelope counter + uint32_t m_envelope_state; // envelope state + uint32_t m_noise_count; // current noise counter + uint32_t m_noise_state; // current noise state + ssg_registers m_regs; // registers + ssg_override *m_override; // override interface +}; + +} + +#endif // YMFM_SSG_H diff --git a/src/thread.cpp b/src/thread.cpp new file mode 100644 index 000000000..67bf8d5e6 --- /dev/null +++ b/src/thread.cpp @@ -0,0 +1,139 @@ +#include +#include +#include + +#include <86box/plat.h> +#include <86box/thread.h> + +struct event_cpp11_t +{ + std::condition_variable cond; + std::mutex mutex; + bool state = false; +}; + +extern "C" { + +thread_t * +thread_create(void (*thread_rout)(void *param), void *param) +{ + auto thread = new std::thread([thread_rout, param] { + thread_rout(param); + }); + return thread; +} + +int +thread_wait(thread_t *arg) +{ + if (!arg) return 0; + auto thread = reinterpret_cast(arg); + thread->join(); + return 0; +} + +mutex_t * +thread_create_mutex(void) +{ + auto mutex = new std::mutex; + return mutex; +} + +int +thread_test_mutex(mutex_t *_mutex) +{ + if (_mutex == nullptr) + return 0; + + auto mutex = reinterpret_cast(_mutex); + return mutex->try_lock() ? 1 : 0; +} + +int +thread_wait_mutex(mutex_t *_mutex) +{ + if (_mutex == nullptr) + return 0; + + auto mutex = reinterpret_cast(_mutex); + mutex->lock(); + return 1; +} + + +int +thread_release_mutex(mutex_t *_mutex) +{ + if (_mutex == nullptr) + return 0; + + auto mutex = reinterpret_cast(_mutex); + mutex->unlock(); + return 1; +} + + +void +thread_close_mutex(mutex_t *_mutex) +{ + auto mutex = reinterpret_cast(_mutex); + delete mutex; +} + +event_t * +thread_create_event() +{ + auto ev = new event_cpp11_t; + return ev; +} + +int +thread_wait_event(event_t *handle, int timeout) +{ + auto event = reinterpret_cast(handle); + auto lock = std::unique_lock(event->mutex); + + if (timeout < 0) { + event->cond.wait(lock, [event] { return event->state; }); + } else { + auto to = std::chrono::system_clock::now() + std::chrono::milliseconds(timeout); + std::cv_status status; + + do { + status = event->cond.wait_until(lock, to); + } while ((status != std::cv_status::timeout) && !event->state); + + if (status == std::cv_status::timeout) { + return 1; + } + } + return 0; +} + +void +thread_set_event(event_t *handle) +{ + auto event = reinterpret_cast(handle); + { + auto lock = std::unique_lock(event->mutex); + event->state = true; + } + event->cond.notify_all(); +} + +void +thread_reset_event(event_t *handle) +{ + auto event = reinterpret_cast(handle); + auto lock = std::unique_lock(event->mutex); + event->state = false; +} + +void +thread_destroy_event(event_t *handle) +{ + auto event = reinterpret_cast(handle); + delete event; +} + +} diff --git a/src/timer.c b/src/timer.c index 9d88c67e0..32d382d54 100644 --- a/src/timer.c +++ b/src/timer.c @@ -11,10 +11,10 @@ uint32_t timer_target; /*Enabled timers are stored in a linked list, with the first timer to expire at the head.*/ -static pc_timer_t *timer_head = NULL; +pc_timer_t *timer_head = NULL; /* Are we initialized? */ -static int timer_inited = 0; +int timer_inited = 0; void @@ -37,11 +37,7 @@ timer_enable(pc_timer_t *timer) if (!timer_head) { timer_head = timer; timer->next = timer->prev = NULL; -#if 0 - timer_target = timer_head->ts_integer; -#else timer_target = timer_head->ts.ts32.integer; -#endif return; } @@ -57,11 +53,7 @@ timer_enable(pc_timer_t *timer) timer->prev->next = timer; else { timer_head = timer; -#if 0 - timer_target = timer_head->ts_integer; -#else timer_target = timer_head->ts.ts32.integer; -#endif } return; } @@ -99,7 +91,7 @@ timer_disable(pc_timer_t *timer) } -static void +void timer_remove_head(void) { pc_timer_t *timer; @@ -142,11 +134,7 @@ timer_process(void) timer->callback(timer->p); } -#if 0 - timer_target = timer_head->ts_integer; -#else timer_target = timer_head->ts.ts32.integer; -#endif } @@ -233,6 +221,8 @@ timer_advance_ex(pc_timer_t *timer, int start) } else { if (timer->period > 0.0) timer_do_period(timer, (uint64_t) (timer->period * ((double) TIMER_USEC)), start); + else + timer_disable(timer); timer->period = 0.0; timer->flags &= ~TIMER_SPLIT; } @@ -256,5 +246,8 @@ timer_on_auto(pc_timer_t *timer, double period) if (!timer_inited || (timer == NULL)) return; - timer_on(timer, period, (timer->period == 0.0)); + if (period > 0.0) + timer_on(timer, period, (timer->period == 0.0)); + else + timer_stop(timer); } diff --git a/src/unix/CMakeLists.txt b/src/unix/CMakeLists.txt new file mode 100644 index 000000000..6d1c01a34 --- /dev/null +++ b/src/unix/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# 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. +# +# CMake build script. +# +# Authors: Cacodemon345 +# David Hrdlička, +# +# Copyright 2021 Cacodemon345. +# Copyright 2021 David Hrdlička. +# + +add_library(plat OBJECT unix.c) + +if (NOT CPPTHREADS) + target_sources(plat PRIVATE unix_thread.c) +endif() + +set(THREADS_PREFER_PTHREAD_FLAG TRUE) +find_package(Threads REQUIRED) +target_link_libraries(86Box Threads::Threads) + +add_library(ui OBJECT unix_sdl.c unix_cdrom.c) +target_compile_definitions(ui PUBLIC _FILE_OFFSET_BITS=64) +target_link_libraries(ui ${CMAKE_DL_LIBS}) + +if(APPLE) + target_sources(plat PRIVATE macOSXGlue.m) +endif() diff --git a/src/unix/assets/128x128/net.86box.86Box.png b/src/unix/assets/128x128/net.86box.86Box.png new file mode 100644 index 000000000..bf521d3ec Binary files /dev/null and b/src/unix/assets/128x128/net.86box.86Box.png differ diff --git a/src/unix/assets/192x192/net.86box.86Box.png b/src/unix/assets/192x192/net.86box.86Box.png new file mode 100644 index 000000000..4bed7df13 Binary files /dev/null and b/src/unix/assets/192x192/net.86box.86Box.png differ diff --git a/src/unix/assets/256x256/net.86box.86Box.png b/src/unix/assets/256x256/net.86box.86Box.png new file mode 100644 index 000000000..4ef8b2120 Binary files /dev/null and b/src/unix/assets/256x256/net.86box.86Box.png differ diff --git a/src/unix/assets/48x48/net.86box.86Box.png b/src/unix/assets/48x48/net.86box.86Box.png new file mode 100644 index 000000000..75411ba16 Binary files /dev/null and b/src/unix/assets/48x48/net.86box.86Box.png differ diff --git a/src/unix/assets/512x512/net.86box.86Box.png b/src/unix/assets/512x512/net.86box.86Box.png new file mode 100644 index 000000000..2fef558d6 Binary files /dev/null and b/src/unix/assets/512x512/net.86box.86Box.png differ diff --git a/src/unix/assets/64x64/net.86box.86Box.png b/src/unix/assets/64x64/net.86box.86Box.png new file mode 100644 index 000000000..24d668e0c Binary files /dev/null and b/src/unix/assets/64x64/net.86box.86Box.png differ diff --git a/src/unix/assets/72x72/net.86box.86Box.png b/src/unix/assets/72x72/net.86box.86Box.png new file mode 100644 index 000000000..e01c47829 Binary files /dev/null and b/src/unix/assets/72x72/net.86box.86Box.png differ diff --git a/src/unix/assets/86Box.spec b/src/unix/assets/86Box.spec new file mode 100644 index 000000000..55df4b7d9 --- /dev/null +++ b/src/unix/assets/86Box.spec @@ -0,0 +1,124 @@ +# Fedora RPM spec file for 86Box including roms +# +# To create RPM files from this spec file, run the following commands: +# sudo dnf install rpm-build +# mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} +# +# copy this 86Box.spec file to ~/rpmbuild/SPECS and run the following commands: +# cd ~/rpmbuild +# sudo dnf builddep SPECS/86Box.spec +# rpmbuild --undefine=_disable_source_fetch -ba SPECS/86Box.spec +# +# After a successful build, you can install the RPMs as follows: +# sudo dnf install RPMS/$(uname -m)/86Box-3* RPMS/noarch/86Box-roms* + +%global romver 20220701 + +Name: 86Box +Version: 3.6 +Release: 1%{?dist} +Summary: Classic PC emulator +License: GPLv2+ +URL: https://86box.net + +Source0: https://github.com/86Box/86Box/archive/refs/tags/v%%{version}.tar.gz +Source1: https://github.com/86Box/roms/archive/refs/tags/%{romver}.tar.gz + +BuildRequires: cmake +BuildRequires: desktop-file-utils +BuildRequires: extra-cmake-modules +BuildRequires: freetype-devel +BuildRequires: gcc-c++ +BuildRequires: libFAudio-devel +BuildRequires: libappstream-glib +BuildRequires: libevdev-devel +BuildRequires: libXi-devel +BuildRequires: ninja-build +BuildRequires: qt5-linguist +BuildRequires: qt5-qtconfiguration-devel +BuildRequires: qt5-qtbase-private-devel +BuildRequires: qt5-qtbase-static +BuildRequires: rtmidi-devel +BuildRequires: wayland-devel +BuildRequires: SDL2-devel + +Requires: hicolor-icon-theme +Requires: fluid-soundfont-gm +Requires: 86Box-roms + +%description +86Box is 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. + +It supports various models of PCs, graphics and sound cards, and CPUs. + +%package roms +Summary: ROMs for use with 86Box +Version: %{romver} +License: Proprietary +BuildArch: noarch + +%description roms +Collection of ROMs for use with 86Box. + +%prep +%autosetup -p1 -a1 + +%build +%ifarch i386 x86_64 + %cmake -DRELEASE=on +%else + %ifarch arm aarch64 + %cmake -DRELEASE=on -DNEW_DYNAREC=on + %else + %cmake -DRELEASE=on -DDYNAREC=off + %endif +%endif +%cmake_build + +%install +# install base package +%cmake_install + +# install icons +for i in 48 64 72 96 128 192 256 512; do + mkdir -p $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/${i}x${i}/apps + cp src/unix/assets/${i}x${i}/net.86box.86Box.png $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/${i}x${i}/apps +done + +# install desktop file +desktop-file-install --dir=%{buildroot}%{_datadir}/applications src/unix/assets/net.86box.86Box.desktop + +# install metadata +mkdir -p %{buildroot}%{_metainfodir} +cp src/unix/assets/net.86box.86Box.metainfo.xml %{buildroot}%{_metainfodir} +appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/net.86box.86Box.metainfo.xml + +# install roms +pushd roms-%{romver} + mkdir -p %{buildroot}%{_datadir}/%{name}/roms + cp -a * %{buildroot}%{_datadir}/%{name}/roms/ + # hack to create symlink in /usr/bin + cd %{buildroot}%{_bindir} + ln -s ../share/%{name}/roms roms +popd + +# files part of the main package +%files +%license COPYING +%{_bindir}/86Box +%{_datadir}/applications/net.86box.86Box.desktop +%{_metainfodir}/net.86box.86Box.metainfo.xml +%{_datadir}/icons/hicolor/*/apps/net.86box.86Box.png + +# files part of the rom package +%files roms +%license roms-%{romver}/LICENSE +%{_datadir}/%{name}/roms +%{_bindir}/roms + +%changelog +* Fri Jul 01 2022 Robert de Rooy 3.6-1 +- Bump release diff --git a/src/unix/assets/96x96/net.86box.86Box.png b/src/unix/assets/96x96/net.86box.86Box.png new file mode 100644 index 000000000..ee24db6ea Binary files /dev/null and b/src/unix/assets/96x96/net.86box.86Box.png differ diff --git a/src/unix/assets/net.86box.86Box.desktop b/src/unix/assets/net.86box.86Box.desktop new file mode 100644 index 000000000..83d20b9e7 --- /dev/null +++ b/src/unix/assets/net.86box.86Box.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=86Box +GenericName=Classic PC emulator +Comment=An emulator for classic IBM PC clones +Exec=86Box +Icon=net.86box.86Box +Terminal=false +Type=Application +Categories=System;Emulator; diff --git a/src/unix/assets/net.86box.86Box.metainfo.xml b/src/unix/assets/net.86box.86Box.metainfo.xml new file mode 100644 index 000000000..982ae9b4d --- /dev/null +++ b/src/unix/assets/net.86box.86Box.metainfo.xml @@ -0,0 +1,37 @@ + + + net.86box.86Box + CC0-1.0 + GPL-2.0-or-later + 86Box + An emulator for classic IBM PC clones + + Emulation + + net.86box.86Box.desktop + + + + + +

+ 86Box is 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. + + It supports various models of PCs, graphics and sound + cards, and CPUs. +

+

+ To use 86Box you will need to dump BIOS ROMs for each machine you + want to emulate. +

+
+ + + https://raw.githubusercontent.com/86Box/86Box/master/src/unix/assets/screenshots/86Box.png + + + https://86box.net +
diff --git a/src/unix/assets/screenshots/86Box.png b/src/unix/assets/screenshots/86Box.png new file mode 100644 index 000000000..5f72485f3 Binary files /dev/null and b/src/unix/assets/screenshots/86Box.png differ diff --git a/src/unix/macOSXGlue.h b/src/unix/macOSXGlue.h new file mode 100644 index 000000000..cd3a880bd --- /dev/null +++ b/src/unix/macOSXGlue.h @@ -0,0 +1,23 @@ +// +// macOSXGlue.h +// TestSDL +// +// Created by Jerome Vernet on 18/11/2021. +// Copyright © 2021 Jerome Vernet. All rights reserved. +// + +#ifndef macOSXGlue_h +#define macOSXGlue_h + +#include + +CF_IMPLICIT_BRIDGING_ENABLED +CF_EXTERN_C_BEGIN +void getDefaultROMPath(char*); +int toto(); + +CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED + + +#endif /* macOSXGlue_h */ diff --git a/src/unix/macOSXGlue.m b/src/unix/macOSXGlue.m new file mode 100644 index 000000000..b170dea5f --- /dev/null +++ b/src/unix/macOSXGlue.m @@ -0,0 +1,43 @@ +// +// macOSXGlue.m +// 86BOx MacoSx Glue.... +// Todo: so much +// Created by Jerome Vernet on 18/11/2021. +// Copyright © 2021 Jerome Vernet. All rights reserved. +// + +#import + +void getDefaultROMPath(char* Path) +{ + NSFileManager* sharedFM = [NSFileManager defaultManager]; + NSArray* possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory + inDomains:NSUserDomainMask]; + NSURL* appSupportDir = nil; + NSURL* appDirectory = nil; + + if ([possibleURLs count] >= 1) { + // Use the first directory (if multiple are returned) + appSupportDir = [possibleURLs objectAtIndex:0]; + } + + // If a valid app support directory exists, add the + // app's bundle ID to it to specify the final directory. + if (appSupportDir) { + NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier]; + appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID]; + appDirectory=[appDirectory URLByAppendingPathComponent:@"roms"]; + } + // create ~/Library/Application Support/... stuff + + NSError* theError = nil; + if (![sharedFM createDirectoryAtURL:appDirectory withIntermediateDirectories:YES + attributes:nil error:&theError]) + { + // Handle the error. + NSLog(@"Error creating user library rom path"); + } else NSLog(@"Create user rom path sucessfull"); + + strcpy(Path,[appDirectory fileSystemRepresentation]); + // return appDirectory; +} diff --git a/src/unix/unix.c b/src/unix/unix.c new file mode 100644 index 000000000..9185fae47 --- /dev/null +++ b/src/unix/unix.c @@ -0,0 +1,1365 @@ +#ifdef __linux__ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE64_SOURCE 1 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/keyboard.h> +#include <86box/mouse.h> +#include <86box/config.h> +#include <86box/path.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/thread.h> +#include <86box/device.h> +#include <86box/gameport.h> +#include <86box/unix_sdl.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/ui.h> +#include <86box/gdbstub.h> + +#ifdef __APPLE__ +#include "macOSXGlue.h" +#endif + +static int first_use = 1; +static uint64_t StartingTime; +static uint64_t Frequency; +int rctrl_is_lalt; +int update_icons; +int kbd_req_capture; +int hide_status_bar; +int hide_tool_bar; +int fixed_size_x = 640; +int fixed_size_y = 480; +extern int title_set; +extern wchar_t sdl_win_title[512]; +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; +int joysticks_present; +SDL_mutex *blitmtx; +SDL_threadID eventthread; +static int exit_event = 0; +static int fullscreen_pending = 0; +uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US +char icon_set[256] = ""; /* name of the iconset to be used */ + +static const uint16_t sdl_to_xt[0x200] = +{ + [SDL_SCANCODE_ESCAPE] = 0x01, + [SDL_SCANCODE_1] = 0x02, + [SDL_SCANCODE_2] = 0x03, + [SDL_SCANCODE_3] = 0x04, + [SDL_SCANCODE_4] = 0x05, + [SDL_SCANCODE_5] = 0x06, + [SDL_SCANCODE_6] = 0x07, + [SDL_SCANCODE_7] = 0x08, + [SDL_SCANCODE_8] = 0x09, + [SDL_SCANCODE_9] = 0x0A, + [SDL_SCANCODE_0] = 0x0B, + [SDL_SCANCODE_MINUS] = 0x0C, + [SDL_SCANCODE_EQUALS] = 0x0D, + [SDL_SCANCODE_BACKSPACE] = 0x0E, + [SDL_SCANCODE_TAB] = 0x0F, + [SDL_SCANCODE_Q] = 0x10, + [SDL_SCANCODE_W] = 0x11, + [SDL_SCANCODE_E] = 0x12, + [SDL_SCANCODE_R] = 0x13, + [SDL_SCANCODE_T] = 0x14, + [SDL_SCANCODE_Y] = 0x15, + [SDL_SCANCODE_U] = 0x16, + [SDL_SCANCODE_I] = 0x17, + [SDL_SCANCODE_O] = 0x18, + [SDL_SCANCODE_P] = 0x19, + [SDL_SCANCODE_LEFTBRACKET] = 0x1A, + [SDL_SCANCODE_RIGHTBRACKET] = 0x1B, + [SDL_SCANCODE_RETURN] = 0x1C, + [SDL_SCANCODE_LCTRL] = 0x1D, + [SDL_SCANCODE_A] = 0x1E, + [SDL_SCANCODE_S] = 0x1F, + [SDL_SCANCODE_D] = 0x20, + [SDL_SCANCODE_F] = 0x21, + [SDL_SCANCODE_G] = 0x22, + [SDL_SCANCODE_H] = 0x23, + [SDL_SCANCODE_J] = 0x24, + [SDL_SCANCODE_K] = 0x25, + [SDL_SCANCODE_L] = 0x26, + [SDL_SCANCODE_SEMICOLON] = 0x27, + [SDL_SCANCODE_APOSTROPHE] = 0x28, + [SDL_SCANCODE_GRAVE] = 0x29, + [SDL_SCANCODE_LSHIFT] = 0x2A, + [SDL_SCANCODE_BACKSLASH] = 0x2B, + [SDL_SCANCODE_Z] = 0x2C, + [SDL_SCANCODE_X] = 0x2D, + [SDL_SCANCODE_C] = 0x2E, + [SDL_SCANCODE_V] = 0x2F, + [SDL_SCANCODE_B] = 0x30, + [SDL_SCANCODE_N] = 0x31, + [SDL_SCANCODE_M] = 0x32, + [SDL_SCANCODE_COMMA] = 0x33, + [SDL_SCANCODE_PERIOD] = 0x34, + [SDL_SCANCODE_SLASH] = 0x35, + [SDL_SCANCODE_RSHIFT] = 0x36, + [SDL_SCANCODE_KP_MULTIPLY] = 0x37, + [SDL_SCANCODE_LALT] = 0x38, + [SDL_SCANCODE_SPACE] = 0x39, + [SDL_SCANCODE_CAPSLOCK] = 0x3A, + [SDL_SCANCODE_F1] = 0x3B, + [SDL_SCANCODE_F2] = 0x3C, + [SDL_SCANCODE_F3] = 0x3D, + [SDL_SCANCODE_F4] = 0x3E, + [SDL_SCANCODE_F5] = 0x3F, + [SDL_SCANCODE_F6] = 0x40, + [SDL_SCANCODE_F7] = 0x41, + [SDL_SCANCODE_F8] = 0x42, + [SDL_SCANCODE_F9] = 0x43, + [SDL_SCANCODE_F10] = 0x44, + [SDL_SCANCODE_NUMLOCKCLEAR] = 0x45, + [SDL_SCANCODE_SCROLLLOCK] = 0x46, + [SDL_SCANCODE_HOME] = 0x147, + [SDL_SCANCODE_UP] = 0x148, + [SDL_SCANCODE_PAGEUP] = 0x149, + [SDL_SCANCODE_KP_MINUS] = 0x4A, + [SDL_SCANCODE_LEFT] = 0x14B, + [SDL_SCANCODE_KP_5] = 0x4C, + [SDL_SCANCODE_RIGHT] = 0x14D, + [SDL_SCANCODE_KP_PLUS] = 0x4E, + [SDL_SCANCODE_END] = 0x14F, + [SDL_SCANCODE_DOWN] = 0x150, + [SDL_SCANCODE_PAGEDOWN] = 0x151, + [SDL_SCANCODE_INSERT] = 0x152, + [SDL_SCANCODE_DELETE] = 0x153, + [SDL_SCANCODE_F11] = 0x57, + [SDL_SCANCODE_F12] = 0x58, + + [SDL_SCANCODE_KP_ENTER] = 0x11c, + [SDL_SCANCODE_RCTRL] = 0x11d, + [SDL_SCANCODE_KP_DIVIDE] = 0x135, + [SDL_SCANCODE_RALT] = 0x138, + [SDL_SCANCODE_KP_9] = 0x49, + [SDL_SCANCODE_KP_8] = 0x48, + [SDL_SCANCODE_KP_7] = 0x47, + [SDL_SCANCODE_KP_6] = 0x4D, + [SDL_SCANCODE_KP_4] = 0x4B, + [SDL_SCANCODE_KP_3] = 0x51, + [SDL_SCANCODE_KP_2] = 0x50, + [SDL_SCANCODE_KP_1] = 0x4F, + [SDL_SCANCODE_KP_0] = 0x52, + [SDL_SCANCODE_KP_PERIOD] = 0x53, + + [SDL_SCANCODE_LGUI] = 0x15B, + [SDL_SCANCODE_RGUI] = 0x15C, + [SDL_SCANCODE_APPLICATION] = 0x15D, + [SDL_SCANCODE_PRINTSCREEN] = 0x137 +}; + +typedef struct sdl_blit_params +{ + int x, y, w, h; +} sdl_blit_params; + +sdl_blit_params params = { 0, 0, 0, 0 }; +int blitreq = 0; + +void* dynld_module(const char *name, dllimp_t *table) +{ + dllimp_t* imp; + void* modhandle = dlopen(name, RTLD_LAZY | RTLD_GLOBAL); + if (modhandle) + { + for (imp = table; imp->name != NULL; imp++) + { + if ((*(void**)imp->func = dlsym(modhandle, imp->name)) == NULL) + { + dlclose(modhandle); + return NULL; + } + } + } + return modhandle; +} + +void +plat_tempfile(char *bufp, char *prefix, char *suffix) +{ + struct tm* calendertime; + struct timeval t; + time_t curtime; + + if (prefix != NULL) + sprintf(bufp, "%s-", prefix); + else + strcpy(bufp, ""); + gettimeofday(&t, NULL); + curtime = time(NULL); + calendertime = localtime(&curtime); + sprintf(&bufp[strlen(bufp)], "%d%02d%02d-%02d%02d%02d-%03ld%s", calendertime->tm_year, calendertime->tm_mon, calendertime->tm_mday, calendertime->tm_hour, calendertime->tm_min, calendertime->tm_sec, t.tv_usec / 1000, suffix); +} + +int +plat_getcwd(char *bufp, int max) +{ + return getcwd(bufp, max) != 0; +} + +int +plat_chdir(char* str) +{ + return chdir(str); +} + +void dynld_close(void *handle) +{ + dlclose(handle); +} + +wchar_t* plat_get_string(int i) +{ + switch (i) + { + case IDS_2077: + return L"Click to capture mouse"; + case IDS_2078: + return L"Press CTRL-END to release mouse"; + case IDS_2079: + return L"Press CTRL-END or middle button to release mouse"; + case IDS_2080: + return L"Failed to initialize FluidSynth"; + case IDS_2130: + return L"Invalid configuration"; + case IDS_4099: + return L"MFM/RLL or ESDI CD-ROM drives never existed"; + case IDS_2093: + return L"Failed to set up PCap"; + case IDS_2094: + return L"No PCap devices found"; + case IDS_2095: + return L"Invalid PCap device"; + case IDS_2110: + return L"Unable to initialize FreeType"; + case IDS_2111: + return L"Unable to initialize SDL, libsdl2 is required"; + case IDS_2131: + return L"libfreetype is required for ESC/P printer emulation."; + case IDS_2132: + return L"libgs is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files."; + case IDS_2133: + return L"libfluidsynth is required for FluidSynth MIDI output."; + case IDS_2129: + return L"Make sure libpcap is installed and that you are on a libpcap-compatible network connection."; + case IDS_2114: + return L"Unable to initialize Ghostscript"; + case IDS_2063: + return L"Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine."; + case IDS_2064: + return L"Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card."; + case IDS_2128: + return L"Hardware not available"; + case IDS_2142: + return L"Monitor in sleep mode"; + } + return L""; +} + +FILE * +plat_fopen(const char *path, const char *mode) +{ + return fopen(path, mode); +} + +FILE * +plat_fopen64(const char *path, const char *mode) +{ + return fopen(path, mode); +} + +int +path_abs(char *path) +{ + return path[0] == '/'; +} + +void +path_normalize(char* path) +{ + /* No-op. */ +} + +void +path_slash(char *path) +{ + if ((path[strlen(path)-1] != '/')) { + strcat(path, "/"); + } + path_normalize(path); +} + +void +plat_put_backslash(char *s) +{ + int c = strlen(s) - 1; + + if (s[c] != '/') + s[c] = '/'; +} + +/* Return the last element of a pathname. */ +char * +plat_get_basename(const char *path) +{ + int c = (int)strlen(path); + + while (c > 0) { + if (path[c] == '/') + return((char *)&path[c + 1]); + c--; + } + + return((char *)path); +} +char * +path_get_filename(char *s) +{ + int c = strlen(s) - 1; + + while (c > 0) { + if (s[c] == '/' || s[c] == '\\') + return(&s[c+1]); + c--; + } + + return(s); +} + + +char * +path_get_extension(char *s) +{ + int c = strlen(s) - 1; + + if (c <= 0) + return(s); + + while (c && s[c] != '.') + c--; + + if (!c) + return(&s[strlen(s)]); + + return(&s[c+1]); +} + + +void +path_append_filename(char *dest, const char *s1, const char *s2) +{ + strcpy(dest, s1); + path_slash(dest); + strcat(dest, s2); +} + +int +plat_dir_check(char *path) +{ + struct stat dummy; + if (stat(path, &dummy) < 0) + { + return 0; + } + return S_ISDIR(dummy.st_mode); +} + +int +plat_dir_create(char *path) +{ + return mkdir(path, S_IRWXU); +} + +void * +plat_mmap(size_t size, uint8_t executable) +{ +#if defined __APPLE__ && defined MAP_JIT + void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE | (executable ? MAP_JIT : 0), -1, 0); +#else + void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + return (ret < 0) ? NULL : ret; +} + +void +plat_munmap(void *ptr, size_t size) +{ + munmap(ptr, size); +} + +uint64_t +plat_timer_read(void) +{ + return SDL_GetPerformanceCounter(); +} + +static uint64_t +plat_get_ticks_common(void) +{ + uint64_t EndingTime, ElapsedMicroseconds; + if (first_use) { + Frequency = SDL_GetPerformanceFrequency(); + StartingTime = SDL_GetPerformanceCounter(); + first_use = 0; + } + EndingTime = SDL_GetPerformanceCounter(); + ElapsedMicroseconds = ((EndingTime - StartingTime) * 1000000) / Frequency; + return ElapsedMicroseconds; +} + +uint32_t +plat_get_ticks(void) +{ + return (uint32_t)(plat_get_ticks_common() / 1000); +} + +uint32_t +plat_get_micro_ticks(void) +{ + return (uint32_t)plat_get_ticks_common(); +} + +void plat_remove(char* path) +{ + remove(path); +} + +void +ui_sb_update_icon_state(int tag, int state) +{ + +} + +void +ui_sb_update_icon(int tag, int active) +{ + +} + +void +plat_delay_ms(uint32_t count) +{ + SDL_Delay(count); +} + +void +ui_sb_update_tip(int arg) +{ + +} + +void +ui_sb_update_panes() +{ + +} + +void +ui_sb_update_text() +{ + +} + +void +path_get_dirname(char *dest, const char *path) +{ + int c = (int)strlen(path); + char *ptr; + + ptr = (char *)path; + + while (c > 0) { + if (path[c] == '/' || path[c] == '\\') { + ptr = (char *)&path[c]; + break; + } + c--; + } + + /* Copy to destination. */ + while (path < ptr) + *dest++ = *path++; + *dest = '\0'; +} +volatile int cpu_thread_run = 1; +void ui_sb_set_text_w(wchar_t *wstr) +{ + +} + +int stricmp(const char* s1, const char* s2) +{ + return strcasecmp(s1, s2); +} + +int strnicmp(const char *s1, const char *s2, size_t n) +{ + return strncasecmp(s1, s2, n); +} + +void +main_thread(void *param) +{ + uint32_t old_time, new_time; + int drawits, frames; + + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); + framecountx = 0; + //title_update = 1; + old_time = SDL_GetTicks(); + drawits = frames = 0; + while (!is_quit && cpu_thread_run) { + /* See if it is time to run a frame of code. */ + new_time = SDL_GetTicks(); +#ifdef USE_GDBSTUB + if (gdbstub_next_asap && (drawits <= 0)) + drawits = 10; + else +#endif + drawits += (new_time - old_time); + old_time = new_time; + if (drawits > 0 && !dopause) { + /* Yes, so do one frame now. */ + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + pc_run(); + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + nvr_save(); + nvr_dosave = 0; + frames = 0; + } + } else /* Just so we dont overload the host OS. */ + SDL_Delay(1); + + /* If needed, handle a screen resize. */ + if (atomic_load(&doresize_monitors[0]) && !video_fullscreen && !is_quit) { + if (vid_resize & 2) + plat_resize(fixed_size_x, fixed_size_y); + else + plat_resize(scrnsz_x, scrnsz_y); + atomic_store(&doresize_monitors[0], 1); + } + } + + is_quit = 1; +} + +thread_t* thMain = NULL; + +void +do_start(void) +{ + /* We have not stopped yet. */ + is_quit = 0; + + /* Initialize the high-precision timer. */ + SDL_InitSubSystem(SDL_INIT_TIMER); + timer_freq = SDL_GetPerformanceFrequency(); + + /* Start the emulator, really. */ + thMain = thread_create(main_thread, NULL); +} + +void +do_stop(void) +{ + if (SDL_ThreadID() != eventthread) + { + exit_event = 1; + return; + } + if (blitreq) + { + blitreq = 0; + extern void video_blit_complete(); + video_blit_complete(); + } + + while(SDL_TryLockMutex(blitmtx) == SDL_MUTEX_TIMEDOUT) + { + if (blitreq) + { + blitreq = 0; + extern void video_blit_complete(); + video_blit_complete(); + } + } + startblit(); + + is_quit = 1; + sdl_close(); + + pc_close(thMain); + + thMain = NULL; +} + +int ui_msgbox(int flags, void *message) +{ + return ui_msgbox_header(flags, NULL, message); +} + +int ui_msgbox_header(int flags, void *header, void* message) +{ + SDL_MessageBoxData msgdata; + SDL_MessageBoxButtonData msgbtn; + if (!header) header = (flags & MBX_ANSI) ? "86Box" : L"86Box"; + if (header <= (void*)7168) header = plat_get_string(header); + if (message <= (void*)7168) message = plat_get_string(message); + msgbtn.buttonid = 1; + msgbtn.text = "OK"; + msgbtn.flags = 0; + memset(&msgdata, 0, sizeof(SDL_MessageBoxData)); + msgdata.numbuttons = 1; + msgdata.buttons = &msgbtn; + int msgflags = 0; + if (msgflags & MBX_FATAL) msgflags |= SDL_MESSAGEBOX_ERROR; + else if (msgflags & MBX_ERROR || msgflags & MBX_WARNING) msgflags |= SDL_MESSAGEBOX_WARNING; + else msgflags |= SDL_MESSAGEBOX_INFORMATION; + msgdata.flags = msgflags; + if (flags & MBX_ANSI) + { + int button = 0; + msgdata.title = header; + msgdata.message = message; + SDL_ShowMessageBox(&msgdata, &button); + return button; + } + else + { + int button = 0; + char *res = SDL_iconv_string("UTF-8", sizeof(wchar_t) == 2 ? "UTF-16LE" : "UTF-32LE", (char *)message, wcslen(message) * sizeof(wchar_t) + sizeof(wchar_t)); + char *res2 = SDL_iconv_string("UTF-8", sizeof(wchar_t) == 2 ? "UTF-16LE" : "UTF-32LE", (char *)header, wcslen(header) * sizeof(wchar_t) + sizeof(wchar_t)); + msgdata.message = res; + msgdata.title = res2; + SDL_ShowMessageBox(&msgdata, &button); + free(res); + free(res2); + return button; + } + + return 0; +} + +void plat_get_exe_name(char *s, int size) +{ + char* basepath = SDL_GetBasePath(); + snprintf(s, size, "%s%s", basepath, basepath[strlen(basepath) - 1] == '/' ? "86box" : "/86box"); +} + +void +plat_power_off(void) +{ + confirm_exit = 0; + nvr_save(); + config_save(); + + /* Deduct a sufficiently large number of cycles that no instructions will + run before the main thread is terminated */ + cycles -= 99999999; + + cpu_thread_run = 0; +} + +void ui_sb_bugui(char *str) +{ + +} + +extern void sdl_blit(int x, int y, int w, int h); + +typedef struct mouseinputdata +{ + int deltax, deltay, deltaz; + int mousebuttons; +} mouseinputdata; +SDL_mutex* mousemutex; +static mouseinputdata mousedata; +void mouse_poll() +{ + SDL_LockMutex(mousemutex); + mouse_x = mousedata.deltax; + mouse_y = mousedata.deltay; + mouse_z = mousedata.deltaz; + mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0; + mouse_buttons = mousedata.mousebuttons; + SDL_UnlockMutex(mousemutex); +} + + +int real_sdl_w, real_sdl_h; +void ui_sb_set_ready(int ready) {} +char* xargv[512]; + +// From musl. +char *local_strsep(char **str, const char *sep) +{ + char *s = *str, *end; + if (!s) return NULL; + end = s + strcspn(s, sep); + if (*end) *end++ = 0; + else end = 0; + *str = end; + return s; +} + +void +plat_pause(int p) +{ + static wchar_t oldtitle[512]; + wchar_t title[512]; + + if ((p == 0) && (time_sync & TIME_SYNC_ENABLED)) + nvr_time_sync(); + + dopause = p; + if (p) { + wcsncpy(oldtitle, ui_window_title(NULL), sizeof_w(oldtitle) - 1); + wcscpy(title, oldtitle); + wcscat(title, L" - PAUSED"); + ui_window_title(title); + } else { + ui_window_title(oldtitle); + } +} + +void +plat_init_rom_paths() +{ +#ifndef __APPLE__ + if (getenv("XDG_DATA_HOME")) { + char xdg_rom_path[1024] = { 0 }; + strncpy(xdg_rom_path, getenv("XDG_DATA_HOME"), 1024); + path_slash(xdg_rom_path); + strncat(xdg_rom_path, "86Box/", 1024); + + if (!plat_dir_check(xdg_rom_path)) + plat_dir_create(xdg_rom_path); + strcat(xdg_rom_path, "roms/"); + + if (!plat_dir_check(xdg_rom_path)) + plat_dir_create(xdg_rom_path); + rom_add_path(xdg_rom_path); + } else { + char home_rom_path[1024] = { 0 }; + snprintf(home_rom_path, 1024, "%s/.local/share/86Box/", getenv("HOME") ? getenv("HOME") : getpwuid(getuid())->pw_dir); + + if (!plat_dir_check(home_rom_path)) + plat_dir_create(home_rom_path); + strcat(home_rom_path, "roms/"); + + if (!plat_dir_check(home_rom_path)) + plat_dir_create(home_rom_path); + rom_add_path(home_rom_path); + } + if (getenv("XDG_DATA_DIRS")) { + char* xdg_rom_paths = strdup(getenv("XDG_DATA_DIRS")); + char* xdg_rom_paths_orig = xdg_rom_paths; + char* cur_xdg_rom_path = NULL; + if (xdg_rom_paths) { + while (xdg_rom_paths[strlen(xdg_rom_paths) - 1] == ':') { + xdg_rom_paths[strlen(xdg_rom_paths) - 1] = '\0'; + } + while ((cur_xdg_rom_path = local_strsep(&xdg_rom_paths, ";")) != NULL) { + char real_xdg_rom_path[1024] = { '\0' }; + strcat(real_xdg_rom_path, cur_xdg_rom_path); + path_slash(real_xdg_rom_path); + strcat(real_xdg_rom_path, "86Box/roms/"); + rom_add_path(real_xdg_rom_path); + } + } + free(xdg_rom_paths_orig); + } else { + rom_add_path("/usr/local/share/86Box/roms/"); + rom_add_path("/usr/share/86Box/roms/"); + } +#else + char default_rom_path[1024] = { '\0 '}; + getDefaultROMPath(default_rom_path); + rom_add_path(default_rom_path); +#endif +} + +bool process_media_commands_3(uint8_t* id, char* fn, uint8_t* wp, int cmdargc) +{ + bool err = false; + *id = atoi(xargv[1]); + if (xargv[2][0] == '\'' || xargv[2][0] == '"') + { + int curarg = 2; + for (curarg = 2; curarg < cmdargc; curarg++) + { + if (strlen(fn) + strlen(xargv[curarg]) >= PATH_MAX) + { + err = true; + fprintf(stderr, "Path name too long.\n"); + } + strcat(fn, xargv[curarg] + (xargv[curarg][0] == '\'' || xargv[curarg][0] == '"')); + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') + { + if (curarg + 1 < cmdargc) + { + *wp = atoi(xargv[curarg + 1]); + } + break; + } + strcat(fn, " "); + } + } + else + { + if (strlen(xargv[2]) < PATH_MAX) + { + strcpy(fn, xargv[2]); + *wp = atoi(xargv[3]); + } + else + { + fprintf(stderr, "Path name too long.\n"); + err = true; + } + } + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') fn[strlen(fn) - 1] = '\0'; + return err; +} +char* (*f_readline)(const char*) = NULL; +int (*f_add_history)(const char *) = NULL; +void (*f_rl_callback_handler_remove)(void) = NULL; + +#ifdef __APPLE__ +#define LIBEDIT_LIBRARY "libedit.dylib" +#else +#define LIBEDIT_LIBRARY "libedit.so" +#endif +uint32_t timer_onesec(uint32_t interval, void* param) +{ + pc_onesec(); + return interval; +} + +void monitor_thread(void* param) +{ +#ifndef USE_CLI + if (isatty(fileno(stdin)) && isatty(fileno(stdout))) + { + char* line = NULL; + size_t n; + printf("86Box monitor console.\n"); + while (!exit_event) + { + if (feof(stdin)) break; + if (f_readline) + line = f_readline("(86Box) "); + else + { + printf("(86Box) "); + getline(&line, &n, stdin); + } + if (line) + { + int cmdargc = 0; + char* linecpy; + line[strcspn(line, "\r\n")] = '\0'; + linecpy = strdup(line); + if (!linecpy) + { + free(line); + line = NULL; + continue; + } + if (f_add_history) f_add_history(line); + memset(xargv, 0, sizeof(xargv)); + while(1) + { + xargv[cmdargc++] = local_strsep(&linecpy, " "); + if (xargv[cmdargc - 1] == NULL || cmdargc >= 512) break; + } + cmdargc--; + if (strncasecmp(xargv[0], "help", 4) == 0) + { + printf( + "fddload - Load floppy disk image into drive .\n" + "cdload - Load CD-ROM image into drive .\n" + "zipload - Load ZIP image into ZIP drive .\n" + "cartload - Load cartridge image into cartridge drive .\n" + "moload - Load MO image into MO drive .\n\n" + "fddeject - eject disk from floppy drive .\n" + "cdeject - eject disc from CD-ROM drive .\n" + "zipeject - eject ZIP image from ZIP drive .\n" + "carteject - eject cartridge from drive .\n" + "moeject - eject image from MO drive .\n\n" + "hardreset - hard reset the emulated system.\n" + "pause - pause the the emulated system.\n" + "fullscreen - toggle fullscreen.\n" + "exit - exit 86Box.\n"); + } + else if (strncasecmp(xargv[0], "exit", 4) == 0) + { + exit_event = 1; + } + else if (strncasecmp(xargv[0], "fullscreen", 10) == 0) + { + video_fullscreen = video_fullscreen ? 0 : 1; + fullscreen_pending = 1; + } + else if (strncasecmp(xargv[0], "pause", 5) == 0) + { + plat_pause(dopause ^ 1); + printf("%s", dopause ? "Paused.\n" : "Unpaused.\n"); + } + else if (strncasecmp(xargv[0], "hardreset", 9) == 0) + { + pc_reset_hard(); + } + else if (strncasecmp(xargv[0], "cdload", 6) == 0 && cmdargc >= 3) + { + uint8_t id; + bool err = false; + char fn[PATH_MAX]; + + if (!xargv[2] || !xargv[1]) + { + free(line); + free(linecpy); + line = NULL; + continue; + } + id = atoi(xargv[1]); + memset(fn, 0, sizeof(fn)); + if (xargv[2][0] == '\'' || xargv[2][0] == '"') + { + int curarg = 2; + for (curarg = 2; curarg < cmdargc; curarg++) + { + if (strlen(fn) + strlen(xargv[curarg]) >= PATH_MAX) + { + err = true; + fprintf(stderr, "Path name too long.\n"); + } + strcat(fn, xargv[curarg] + (xargv[curarg][0] == '\'' || xargv[curarg][0] == '"')); + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') + { + break; + } + strcat(fn, " "); + } + } + else + { + if (strlen(xargv[2]) < PATH_MAX) + { + strcpy(fn, xargv[2]); + } + else + { + fprintf(stderr, "Path name too long.\n"); + } + } + if (!err) + { + + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') fn[strlen(fn) - 1] = '\0'; + printf("Inserting disc into CD-ROM drive %hhu: %s\n", id, fn); + cdrom_mount(id, fn); + } + } + else if (strncasecmp(xargv[0], "fddeject", 8) == 0 && cmdargc >= 2) + { + floppy_eject(atoi(xargv[1])); + } + else if (strncasecmp(xargv[0], "cdeject", 8) == 0 && cmdargc >= 2) + { + cdrom_mount(atoi(xargv[1]), ""); + } + else if (strncasecmp(xargv[0], "moeject", 8) == 0 && cmdargc >= 2) + { + mo_eject(atoi(xargv[1])); + } + else if (strncasecmp(xargv[0], "carteject", 8) == 0 && cmdargc >= 2) + { + cartridge_eject(atoi(xargv[1])); + } + else if (strncasecmp(xargv[0], "zipeject", 8) == 0 && cmdargc >= 2) + { + zip_eject(atoi(xargv[1])); + } + else if (strncasecmp(xargv[0], "fddload", 7) == 0 && cmdargc >= 4) + { + uint8_t id, wp; + bool err = false; + char fn[PATH_MAX]; + memset(fn, 0, sizeof(fn)); + if (!xargv[2] || !xargv[1]) + { + free(line); + free(linecpy); + line = NULL; + continue; + } + err = process_media_commands_3(&id, fn, &wp, cmdargc); + if (!err) + { + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') fn[strlen(fn) - 1] = '\0'; + printf("Inserting disk into floppy drive %c: %s\n", id + 'A', fn); + floppy_mount(id, fn, wp); + } + } + else if (strncasecmp(xargv[0], "moload", 7) == 0 && cmdargc >= 4) + { + uint8_t id, wp; + bool err = false; + char fn[PATH_MAX]; + memset(fn, 0, sizeof(fn)); + if (!xargv[2] || !xargv[1]) + { + free(line); + free(linecpy); + line = NULL; + continue; + } + err = process_media_commands_3(&id, fn, &wp, cmdargc); + if (!err) + { + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') fn[strlen(fn) - 1] = '\0'; + printf("Inserting into mo drive %hhu: %s\n", id, fn); + mo_mount(id, fn, wp); + } + } + else if (strncasecmp(xargv[0], "cartload", 7) == 0 && cmdargc >= 4) + { + uint8_t id, wp; + bool err = false; + char fn[PATH_MAX]; + memset(fn, 0, sizeof(fn)); + if (!xargv[2] || !xargv[1]) + { + free(line); + free(linecpy); + line = NULL; + continue; + } + err = process_media_commands_3(&id, fn, &wp, cmdargc); + if (!err) + { + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') fn[strlen(fn) - 1] = '\0'; + printf("Inserting tape into cartridge holder %hhu: %s\n", id, fn); + cartridge_mount(id, fn, wp); + } + } + else if (strncasecmp(xargv[0], "zipload", 7) == 0 && cmdargc >= 4) + { + uint8_t id, wp; + bool err = false; + char fn[PATH_MAX]; + memset(fn, 0, sizeof(fn)); + if (!xargv[2] || !xargv[1]) + { + free(line); + free(linecpy); + line = NULL; + continue; + } + err = process_media_commands_3(&id, fn, &wp, cmdargc); + if (!err) + { + if (fn[strlen(fn) - 1] == '\'' + || fn[strlen(fn) - 1] == '"') fn[strlen(fn) - 1] = '\0'; + printf("Inserting disk into ZIP drive %c: %s\n", id + 'A', fn); + zip_mount(id, fn, wp); + } + } + free(line); + free(linecpy); + line = NULL; + } + } + } +#endif +} + +extern int gfxcard_2; +int main(int argc, char** argv) +{ + SDL_Event event; + void* libedithandle; + + SDL_Init(0); + pc_init(argc, argv); + if (! pc_init_modules()) { + ui_msgbox_header(MBX_FATAL, L"No ROMs found.", L"86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory."); + SDL_Quit(); + return 6; + } + + gfxcard_2 = 0; + eventthread = SDL_ThreadID(); + blitmtx = SDL_CreateMutex(); + if (!blitmtx) + { + fprintf(stderr, "Failed to create blit mutex: %s", SDL_GetError()); + return -1; + } + libedithandle = dlopen(LIBEDIT_LIBRARY, RTLD_LOCAL | RTLD_LAZY); + if (libedithandle) + { + f_readline = dlsym(libedithandle, "readline"); + f_add_history = dlsym(libedithandle, "add_history"); + if (!f_readline) + { + fprintf(stderr, "readline in libedit not found, line editing will be limited.\n"); + } + f_rl_callback_handler_remove = dlsym(libedithandle, "rl_callback_handler_remove"); + } + else fprintf(stderr, "libedit not found, line editing will be limited.\n"); + mousemutex = SDL_CreateMutex(); + sdl_initho(); + + if (start_in_fullscreen) + { + video_fullscreen = 1; + sdl_set_fs(1); + } + /* Fire up the machine. */ + pc_reset_hard_init(); + + /* Set the PAUSE mode depending on the renderer. */ + //plat_pause(0); + + /* Initialize the rendering window, or fullscreen. */ + + do_start(); +#ifndef USE_CLI + thread_create(monitor_thread, NULL); +#endif + SDL_AddTimer(1000, timer_onesec, NULL); + while (!is_quit) + { + static int mouse_inside = 0; + while (SDL_PollEvent(&event)) + { + switch(event.type) + { + case SDL_QUIT: + exit_event = 1; + break; + case SDL_MOUSEWHEEL: + { + if (mouse_capture || video_fullscreen) + { + if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) + { + event.wheel.x *= -1; + event.wheel.y *= -1; + } + SDL_LockMutex(mousemutex); + mousedata.deltaz = event.wheel.y; + SDL_UnlockMutex(mousemutex); + } + break; + } + case SDL_MOUSEMOTION: + { + if (mouse_capture || video_fullscreen) + { + SDL_LockMutex(mousemutex); + mousedata.deltax += event.motion.xrel; + mousedata.deltay += event.motion.yrel; + SDL_UnlockMutex(mousemutex); + } + break; + } + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + if ((event.button.button == SDL_BUTTON_LEFT) + && !(mouse_capture || video_fullscreen) + && event.button.state == SDL_RELEASED + && mouse_inside) + { + plat_mouse_capture(1); + break; + } + if (mouse_get_buttons() < 3 && event.button.button == SDL_BUTTON_MIDDLE && !video_fullscreen) + { + plat_mouse_capture(0); + break; + } + if (mouse_capture || video_fullscreen) + { + int buttonmask = 0; + + switch(event.button.button) + { + case SDL_BUTTON_LEFT: + buttonmask = 1; + break; + case SDL_BUTTON_RIGHT: + buttonmask = 2; + break; + case SDL_BUTTON_MIDDLE: + buttonmask = 4; + break; + } + SDL_LockMutex(mousemutex); + if (event.button.state == SDL_PRESSED) + { + mousedata.mousebuttons |= buttonmask; + } + else mousedata.mousebuttons &= ~buttonmask; + SDL_UnlockMutex(mousemutex); + } + break; + } + case SDL_RENDER_DEVICE_RESET: + case SDL_RENDER_TARGETS_RESET: + { + extern void sdl_reinit_texture(); + sdl_reinit_texture(); + break; + } + case SDL_KEYDOWN: + case SDL_KEYUP: + { + uint16_t xtkey = 0; + switch(event.key.keysym.scancode) + { + default: + xtkey = sdl_to_xt[event.key.keysym.scancode]; + break; + } + keyboard_input(event.key.state == SDL_PRESSED, xtkey); + } + case SDL_WINDOWEVENT: + { + switch (event.window.event) + { + case SDL_WINDOWEVENT_ENTER: + mouse_inside = 1; + break; + case SDL_WINDOWEVENT_LEAVE: + mouse_inside = 0; + break; + } + } + } + } + if (mouse_capture && keyboard_ismsexit()) + { + plat_mouse_capture(0); + } + if (blitreq) + { + extern void sdl_blit(int x, int y, int w, int h); + sdl_blit(params.x, params.y, params.w, params.h); + } + if (title_set) + { + extern void ui_window_title_real(); + ui_window_title_real(); + } + if (video_fullscreen && keyboard_isfsexit()) + { + sdl_set_fs(0); + video_fullscreen = 0; + } + if (fullscreen_pending) + { + sdl_set_fs(video_fullscreen); + fullscreen_pending = 0; + } + if (exit_event) + { + do_stop(); + break; + } + } + printf("\n"); + SDL_DestroyMutex(blitmtx); + SDL_DestroyMutex(mousemutex); + SDL_Quit(); + if (f_rl_callback_handler_remove) f_rl_callback_handler_remove(); + return 0; +} +char* plat_vidapi_name(int i) +{ + return "default"; +} + +void +set_language(uint32_t id) +{ + lang_id = id; +} + + +/* Sets up the program language before initialization. */ +uint32_t plat_language_code(char* langcode) +{ + /* or maybe not */ + return 0; +} + +/* Converts back the language code to LCID */ +void +plat_language_code_r(uint32_t lcid, char* outbuf, int len) +{ + /* or maybe not */ + return; +} + +void joystick_init(void) {} +void joystick_close(void) {} +void joystick_process(void) {} +void startblit() +{ + SDL_LockMutex(blitmtx); +} + +void endblit() +{ + SDL_UnlockMutex(blitmtx); +} + +/* API */ +void +ui_sb_mt32lcd(char* str) +{ +} diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c new file mode 100644 index 000000000..9eb3d962a --- /dev/null +++ b/src/unix/unix_cdrom.c @@ -0,0 +1,264 @@ +/* + * 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. + * + * Handle the platform-side of CDROM/ZIP/MO drives. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> +#include <86box/fdd.h> +#include <86box/hdd.h> +#include <86box/scsi_device.h> +#include <86box/cdrom.h> +#include <86box/mo.h> +#include <86box/zip.h> +#include <86box/scsi_disk.h> +#include <86box/plat.h> +#include <86box/ui.h> + + + +void +cassette_mount(char *fn, uint8_t wp) +{ + pc_cas_set_fname(cassette, NULL); + memset(cassette_fname, 0, sizeof(cassette_fname)); + cassette_ui_writeprot = wp; + pc_cas_set_fname(cassette, fn); + if (fn != NULL) + memcpy(cassette_fname, fn, MIN(511, strlen(fn))); + ui_sb_update_icon_state(SB_CASSETTE, (fn == NULL) ? 1 : 0); + //media_menu_update_cassette(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + + +void +cassette_eject(void) +{ + pc_cas_set_fname(cassette, NULL); + memset(cassette_fname, 0x00, sizeof(cassette_fname)); + ui_sb_update_icon_state(SB_CASSETTE, 1); + //media_menu_update_cassette(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + + +void +cartridge_mount(uint8_t id, char *fn, uint8_t wp) +{ + cart_close(id); + cart_load(id, fn); + ui_sb_update_icon_state(SB_CARTRIDGE | id, strlen(cart_fns[id]) ? 0 : 1); + //media_menu_update_cartridge(id); + ui_sb_update_tip(SB_CARTRIDGE | id); + config_save(); +} + + +void +cartridge_eject(uint8_t id) +{ + cart_close(id); + ui_sb_update_icon_state(SB_CARTRIDGE | id, 1); + //media_menu_update_cartridge(id); + ui_sb_update_tip(SB_CARTRIDGE | id); + config_save(); +} + + +void +floppy_mount(uint8_t id, char *fn, uint8_t wp) +{ + fdd_close(id); + ui_writeprot[id] = wp; + fdd_load(id, fn); + ui_sb_update_icon_state(SB_FLOPPY | id, strlen(floppyfns[id]) ? 0 : 1); + //media_menu_update_floppy(id); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); +} + + +void +floppy_eject(uint8_t id) +{ + fdd_close(id); + ui_sb_update_icon_state(SB_FLOPPY | id, 1); + //media_menu_update_floppy(id); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); +} + + +void +plat_cdrom_ui_update(uint8_t id, uint8_t reload) +{ + cdrom_t *drv = &cdrom[id]; + + if (drv->host_drive == 0) { + ui_sb_update_icon_state(SB_CDROM|id, 1); + } else { + ui_sb_update_icon_state(SB_CDROM|id, 0); + } + + //media_menu_update_cdrom(id); + ui_sb_update_tip(SB_CDROM|id); +} + +void +cdrom_mount(uint8_t id, char *fn) +{ + cdrom[id].prev_host_drive = cdrom[id].host_drive; + strcpy(cdrom[id].prev_image_path, cdrom[id].image_path); + if (cdrom[id].ops && cdrom[id].ops->exit) + cdrom[id].ops->exit(&(cdrom[id])); + cdrom[id].ops = NULL; + memset(cdrom[id].image_path, 0, sizeof(cdrom[id].image_path)); + cdrom_image_open(&(cdrom[id]), fn); + /* Signal media change to the emulated machine. */ + if (cdrom[id].insert) + cdrom[id].insert(cdrom[id].priv); + cdrom[id].host_drive = (strlen(cdrom[id].image_path) == 0) ? 0 : 200; + if (cdrom[id].host_drive == 200) { + ui_sb_update_icon_state(SB_CDROM | id, 0); + } else { + ui_sb_update_icon_state(SB_CDROM | id, 1); + } + //media_menu_update_cdrom(id); + ui_sb_update_tip(SB_CDROM | id); + config_save(); +} + +void +mo_eject(uint8_t id) +{ + mo_t *dev = (mo_t *) mo_drives[id].priv; + + mo_disk_close(dev); + if (mo_drives[id].bus_type) { + /* Signal disk change to the emulated machine. */ + mo_insert(dev); + } + + ui_sb_update_icon_state(SB_MO | id, 1); + //media_menu_update_mo(id); + ui_sb_update_tip(SB_MO | id); + config_save(); +} + + +void +mo_mount(uint8_t id, char *fn, uint8_t wp) +{ + mo_t *dev = (mo_t *) mo_drives[id].priv; + + mo_disk_close(dev); + mo_drives[id].read_only = wp; + mo_load(dev, fn); + mo_insert(dev); + + ui_sb_update_icon_state(SB_MO | id, strlen(mo_drives[id].image_path) ? 0 : 1); + //media_menu_update_mo(id); + ui_sb_update_tip(SB_MO | id); + + config_save(); +} + + +void +mo_reload(uint8_t id) +{ + mo_t *dev = (mo_t *) mo_drives[id].priv; + + mo_disk_reload(dev); + if (strlen(mo_drives[id].image_path) == 0) { + ui_sb_update_icon_state(SB_MO|id, 1); + } else { + ui_sb_update_icon_state(SB_MO|id, 0); + } + + //media_menu_update_mo(id); + ui_sb_update_tip(SB_MO|id); + + config_save(); +} + +void +zip_eject(uint8_t id) +{ + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_close(dev); + if (zip_drives[id].bus_type) { + /* Signal disk change to the emulated machine. */ + zip_insert(dev); + } + + ui_sb_update_icon_state(SB_ZIP | id, 1); + //media_menu_update_zip(id); + ui_sb_update_tip(SB_ZIP | id); + config_save(); +} + + +void +zip_mount(uint8_t id, char *fn, uint8_t wp) +{ + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_close(dev); + zip_drives[id].read_only = wp; + zip_load(dev, fn); + zip_insert(dev); + + ui_sb_update_icon_state(SB_ZIP | id, strlen(zip_drives[id].image_path) ? 0 : 1); + //media_menu_update_zip(id); + ui_sb_update_tip(SB_ZIP | id); + + config_save(); +} + + +void +zip_reload(uint8_t id) +{ + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_reload(dev); + if (strlen(zip_drives[id].image_path) == 0) { + ui_sb_update_icon_state(SB_ZIP|id, 1); + } else { + ui_sb_update_icon_state(SB_ZIP|id, 0); + } + + //media_menu_update_zip(id); + ui_sb_update_tip(SB_ZIP|id); + + config_save(); +} diff --git a/src/unix/unix_sdl.c b/src/unix/unix_sdl.c new file mode 100644 index 000000000..3d989bf53 --- /dev/null +++ b/src/unix/unix_sdl.c @@ -0,0 +1,526 @@ +#include +#include + +#include +#include +#include +#include +#include +/* This #undef is needed because a SDL include header redefines HAVE_STDARG_H. */ +#undef HAVE_STDARG_H +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/video.h> +#include <86box/ui.h> +#include <86box/version.h> +#include <86box/unix_sdl.h> + +#define RENDERER_FULL_SCREEN 1 +#define RENDERER_HARDWARE 2 +#define RENDERER_OPENGL 4 + +typedef struct sdl_blit_params +{ + int x, y, w, h; +} sdl_blit_params; +extern sdl_blit_params params; +extern int blitreq; + +SDL_Window *sdl_win = NULL; +SDL_Renderer *sdl_render = NULL; +static SDL_Texture *sdl_tex = NULL; +int sdl_w = SCREEN_RES_X, sdl_h = SCREEN_RES_Y; +static int sdl_fs, sdl_flags = -1; +static int cur_w, cur_h; +static int cur_wx = 0, cur_wy = 0, cur_ww =0, cur_wh = 0; +static volatile int sdl_enabled = 1; +static SDL_mutex* sdl_mutex = NULL; +int mouse_capture; +int title_set = 0; +int resize_pending = 0; +int resize_w = 0; +int resize_h = 0; +double mouse_sensitivity = 1.0; /* Unused. */ +static uint8_t interpixels[17842176]; + +extern void RenderImGui(); +static void +sdl_integer_scale(double *d, double *g) +{ + double ratio; + + if (*d > *g) { + ratio = floor(*d / *g); + *d = *g * ratio; + } else { + ratio = ceil(*d / *g); + *d = *g / ratio; + } +} + +void sdl_reinit_texture(); + +static void +sdl_stretch(int *w, int *h, int *x, int *y) +{ + double hw, gw, hh, gh, dx, dy, dw, dh, gsr, hsr; + int real_sdl_w, real_sdl_h; + + SDL_GL_GetDrawableSize(sdl_win, &real_sdl_w, &real_sdl_h); + + hw = (double) real_sdl_w; + hh = (double) real_sdl_h; + gw = (double) *w; + gh = (double) *h; + hsr = hw / hh; + + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_FULL: + default: + *w = real_sdl_w; + *h = real_sdl_h; + *x = 0; + *y = 0; + break; + case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = (int) dy; + break; + case FULLSCR_SCALE_INT: + gsr = gw / gh; + if (gsr <= hsr) { + dw = hh * gsr; + dh = hh; + } else { + dw = hw; + dh = hw / gsr; + } + sdl_integer_scale(&dw, &gw); + sdl_integer_scale(&dh, &gh); + dx = (hw - dw) / 2.0; + dy = (hh - dh) / 2.0; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = (int) dy; + break; + } +} + + +void +sdl_blit_shim(int x, int y, int w, int h, int monitor_index) +{ + params.x = x; + params.y = y; + params.w = w; + params.h = h; + if (!(!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) || (monitor_index >= 1)) + video_copy(interpixels, &(buffer32->line[y][x]), h * 2048 * sizeof(uint32_t)); + if (screenshots) + video_screenshot(interpixels, 0, 0, 2048); + blitreq = 1; + video_blit_complete_monitor(monitor_index); +} + +void ui_window_title_real(); + +void +sdl_real_blit(SDL_Rect* r_src) +{ + SDL_Rect r_dst; + int ret, winx, winy; + SDL_GL_GetDrawableSize(sdl_win, &winx, &winy); + SDL_RenderClear(sdl_render); + + r_dst = *r_src; + r_dst.x = r_dst.y = 0; + + if (sdl_fs) + { + sdl_stretch(&r_dst.w, &r_dst.h, &r_dst.x, &r_dst.y); + } + else + { + r_dst.w *= ((float)winx / (float) r_dst.w); + r_dst.h *= ((float)winy / (float) r_dst.h); + } + + + ret = SDL_RenderCopy(sdl_render, sdl_tex, r_src, &r_dst); + if (ret) + fprintf(stderr, "SDL: unable to copy texture to renderer (%s)\n", SDL_GetError()); + + SDL_RenderPresent(sdl_render); +} + +void +sdl_blit(int x, int y, int w, int h) +{ + SDL_Rect r_src; + + if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) { + r_src.x = x; + r_src.y = y; + r_src.w = w; + r_src.h = h; + sdl_real_blit(&r_src); + blitreq = 0; + return; + } + + SDL_LockMutex(sdl_mutex); + + if (resize_pending) + { + if (!video_fullscreen) sdl_resize(resize_w, resize_h); + resize_pending = 0; + } + r_src.x = x; + r_src.y = y; + r_src.w = w; + r_src.h = h; + SDL_UpdateTexture(sdl_tex, &r_src, interpixels, 2048 * 4); + blitreq = 0; + + sdl_real_blit(&r_src); + SDL_UnlockMutex(sdl_mutex); +} + +static void +sdl_destroy_window(void) +{ + if (sdl_win != NULL) { + if (window_remember) + { + SDL_GetWindowSize(sdl_win, &window_w, &window_h); + if (strncasecmp(SDL_GetCurrentVideoDriver(), "wayland", 7) != 0) + { + SDL_GetWindowPosition(sdl_win, &window_x, &window_y); + } + } + SDL_DestroyWindow(sdl_win); + sdl_win = NULL; + } +} + + +static void +sdl_destroy_texture(void) +{ + /* SDL_DestroyRenderer also automatically destroys all associated textures. */ + if (sdl_render != NULL) { + SDL_DestroyRenderer(sdl_render); + sdl_render = NULL; + } +} + +void +sdl_close(void) +{ + if (sdl_mutex != NULL) + SDL_LockMutex(sdl_mutex); + + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_enabled) + sdl_enabled = 0; + + if (sdl_mutex != NULL) { + SDL_DestroyMutex(sdl_mutex); + sdl_mutex = NULL; + } + + sdl_destroy_texture(); + sdl_destroy_window(); + + /* Quit. */ + SDL_Quit(); + sdl_flags = -1; +} + +static int old_capture = 0; + +void +sdl_enable(int enable) +{ + if (sdl_flags == -1) + return; + + SDL_LockMutex(sdl_mutex); + sdl_enabled = !!enable; + + if (enable == 1) { + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + sdl_reinit_texture(); + } + + SDL_UnlockMutex(sdl_mutex); +} + +static void +sdl_select_best_hw_driver(void) +{ + int i; + SDL_RendererInfo renderInfo; + + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) + { + SDL_GetRenderDriverInfo(i, &renderInfo); + if (renderInfo.flags & SDL_RENDERER_ACCELERATED) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, renderInfo.name); + return; + } + } +} + +void +sdl_reinit_texture() +{ + sdl_destroy_texture(); + + if (sdl_flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + } else + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + + sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); + +} + +void +sdl_set_fs(int fs) +{ + SDL_LockMutex(sdl_mutex); + SDL_SetWindowFullscreen(sdl_win, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_SetRelativeMouseMode((SDL_bool)mouse_capture); + + sdl_fs = fs; + + if (fs) + sdl_flags |= RENDERER_FULL_SCREEN; + else + sdl_flags &= ~RENDERER_FULL_SCREEN; + + sdl_reinit_texture(); + SDL_UnlockMutex(sdl_mutex); +} + +void +sdl_resize(int x, int y) +{ + int ww = 0, wh = 0, wx = 0, wy = 0; + + if (video_fullscreen & 2) + return; + + if ((x == cur_w) && (y == cur_h)) + return; + + SDL_LockMutex(sdl_mutex); + + ww = x; + wh = y; + + cur_w = x; + cur_h = y; + + cur_wx = wx; + cur_wy = wy; + cur_ww = ww; + cur_wh = wh; + + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + SDL_GL_GetDrawableSize(sdl_win, &sdl_w, &sdl_h); + + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); +} +void +sdl_reload(void) +{ + if (sdl_flags & RENDERER_HARDWARE) + { + SDL_LockMutex(sdl_mutex); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); + } +} + +int +plat_vidapi(char* api) +{ + return 0; +} + +static int +sdl_init_common(int flags) +{ + wchar_t temp[128]; + SDL_version ver; + + /* Get and log the version of the DLL we are using. */ + SDL_GetVersion(&ver); + fprintf(stderr, "SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "SDL: initialization failed (%s)\n", SDL_GetError()); + return(0); + } + + if (flags & RENDERER_HARDWARE) { + if (flags & RENDERER_OPENGL) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "OpenGL"); + } + else + sdl_select_best_hw_driver(); + } + + sdl_mutex = SDL_CreateMutex(); + sdl_win = SDL_CreateWindow("86Box", strncasecmp(SDL_GetCurrentVideoDriver(), "wayland", 7) != 0 && window_remember ? window_x : SDL_WINDOWPOS_CENTERED, strncasecmp(SDL_GetCurrentVideoDriver(), "wayland", 7) != 0 && window_remember ? window_y : SDL_WINDOWPOS_CENTERED, scrnsz_x, scrnsz_y, SDL_WINDOW_OPENGL | (vid_resize & 1 ? SDL_WINDOW_RESIZABLE : 0)); + sdl_set_fs(video_fullscreen); + if (!(video_fullscreen & 1)) + { + if (vid_resize & 2) + plat_resize(fixed_size_x, fixed_size_y); + else + plat_resize(scrnsz_x, scrnsz_y); + } + if ((vid_resize < 2) && window_remember) + { + SDL_SetWindowSize(sdl_win, window_w, window_h); + } + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit_shim); + + sdl_enabled = 1; + + return(1); +} + +int +sdl_inits() +{ + return sdl_init_common(0); +} + + +int +sdl_inith() +{ + return sdl_init_common(RENDERER_HARDWARE); +} + + +int +sdl_initho() +{ + return sdl_init_common(RENDERER_HARDWARE | RENDERER_OPENGL); +} + + +int +sdl_pause(void) +{ + return(0); +} + +void +plat_mouse_capture(int on) +{ + SDL_LockMutex(sdl_mutex); + SDL_SetRelativeMouseMode((SDL_bool)on); + mouse_capture = on; + SDL_UnlockMutex(sdl_mutex); +} + +void plat_resize(int w, int h) +{ + SDL_LockMutex(sdl_mutex); + resize_w = w; + resize_h = h; + resize_pending = 1; + SDL_UnlockMutex(sdl_mutex); +} + +wchar_t sdl_win_title[512] = { L'8', L'6', L'B', L'o', L'x', 0 }; +SDL_mutex* titlemtx = NULL; + +void ui_window_title_real() +{ + char* res; + if (sizeof(wchar_t) == 1) + { + SDL_SetWindowTitle(sdl_win, (char*)sdl_win_title); + return; + } + res = SDL_iconv_string("UTF-8", sizeof(wchar_t) == 2 ? "UTF-16LE" : "UTF-32LE", (char*)sdl_win_title, wcslen(sdl_win_title) * sizeof(wchar_t) + sizeof(wchar_t)); + if (res) + { + SDL_SetWindowTitle(sdl_win, res); + SDL_free((void*)res); + } + title_set = 0; +} +extern SDL_threadID eventthread; + +/* Only activate threading path on macOS, otherwise it will softlock Xorg. + Wayland doesn't seem to have this issue. */ +wchar_t* ui_window_title(wchar_t* str) +{ + if (!str) return sdl_win_title; +#ifdef __APPLE__ + if (eventthread == SDL_ThreadID()) +#endif + { + memset(sdl_win_title, 0, sizeof(sdl_win_title)); + wcsncpy(sdl_win_title, str, 512); + ui_window_title_real(); + return str; + } +#ifdef __APPLE__ + memset(sdl_win_title, 0, sizeof(sdl_win_title)); + wcsncpy(sdl_win_title, str, 512); + title_set = 1; +#endif + return str; +} + +void ui_init_monitor(int monitor_index) {} +void ui_deinit_monitor(int monitor_index) {} + +void plat_resize_request(int w, int h, int monitor_index) +{ + atomic_store((&doresize_monitors[monitor_index]), 1); +} diff --git a/src/unix/unix_thread.c b/src/unix/unix_thread.c new file mode 100644 index 000000000..5221d90eb --- /dev/null +++ b/src/unix/unix_thread.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/thread.h> + + +typedef struct event_pthread_t +{ + pthread_cond_t cond; + pthread_mutex_t mutex; + int state; +} event_pthread_t; + + +typedef struct thread_param +{ + void (*thread_rout)(void*); + void * param; +} thread_param; + + +typedef struct pt_mutex_t +{ + pthread_mutex_t mutex; +} pt_mutex_t; + + +void * +thread_run_wrapper(thread_param* arg) +{ + thread_param localparam = *arg; + free(arg); + localparam.thread_rout(localparam.param); + return NULL; +} + + +thread_t * +thread_create(void (*thread_rout)(void *param), void *param) +{ + pthread_t *thread = malloc(sizeof(pthread_t)); + thread_param *thrparam = malloc(sizeof(thread_param)); + thrparam->thread_rout = thread_rout; + thrparam->param = param; + + pthread_create(thread, NULL, (void* (*)(void*))thread_run_wrapper, thrparam); + + return thread; +} + + +int +thread_wait(thread_t *arg) +{ + return pthread_join(*(pthread_t*)(arg), NULL); +} + + +event_t * +thread_create_event() +{ + event_pthread_t *event = malloc(sizeof(event_pthread_t)); + + pthread_cond_init(&event->cond, NULL); + pthread_mutex_init(&event->mutex, NULL); + event->state = 0; + + return (event_t *)event; +} + + +void +thread_set_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + event->state = 1; + pthread_cond_broadcast(&event->cond); + pthread_mutex_unlock(&event->mutex); +} + + +void +thread_reset_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + event->state = 0; + pthread_mutex_unlock(&event->mutex); +} + + +int +thread_wait_event(event_t *handle, int timeout) +{ + event_pthread_t *event = (event_pthread_t *)handle; + struct timespec abstime; + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_nsec += (timeout % 1000) * 1000000; + abstime.tv_sec += (timeout / 1000); + if (abstime.tv_nsec > 1000000000) { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + pthread_mutex_lock(&event->mutex); + if (timeout == -1) { + while (!event->state) + pthread_cond_wait(&event->cond, &event->mutex); + } else if (!event->state) + pthread_cond_timedwait(&event->cond, &event->mutex, &abstime); + pthread_mutex_unlock(&event->mutex); + + return 0; +} + + +void +thread_destroy_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_cond_destroy(&event->cond); + pthread_mutex_destroy(&event->mutex); + + free(event); +} + + +mutex_t * +thread_create_mutex(void) +{ + pt_mutex_t *mutex = malloc(sizeof(pt_mutex_t)); + + pthread_mutex_init(&mutex->mutex, NULL); + + return mutex; +} + + +int +thread_wait_mutex(mutex_t *_mutex) +{ + if (_mutex == NULL) + return(0); + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + return + pthread_mutex_lock(&mutex->mutex) != 0; +} + + +int +thread_test_mutex(mutex_t *_mutex) +{ + if (_mutex == NULL) + return(0); + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + return + pthread_mutex_trylock(&mutex->mutex) != 0; +} + + +int +thread_release_mutex(mutex_t *_mutex) +{ + if (_mutex == NULL) + return(0); + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + return pthread_mutex_unlock(&mutex->mutex) != 0; +} + + +void +thread_close_mutex(mutex_t *_mutex) +{ + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + pthread_mutex_destroy(&mutex->mutex); + + free(mutex); +} diff --git a/src/upi42.c b/src/upi42.c new file mode 100644 index 000000000..8b8e4b72e --- /dev/null +++ b/src/upi42.c @@ -0,0 +1,1454 @@ +/* + * 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. + * + * Intel UPI-42/MCS-48 microcontroller emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2022 RichardG. + */ +#include +#include +#include +#include + +#ifdef UPI42_STANDALONE +# define fatal(...) \ + { \ + upi42_log(__VA_ARGS__); \ + abort(); \ + } +# define upi42_log(...) \ + { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } +#else +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/timer.h> + + +#ifdef ENABLE_UPI42_LOG +int upi42_do_log = ENABLE_UPI42_LOG; + + +void +upi42_log(const char *fmt, ...) +{ + va_list ap; + + if (upi42_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define upi42_log(fmt, ...) +#endif +#endif + +#define UPI42_REG(upi42, r, op) ((upi42->psw & 0x10) ? (upi42->ram[24 + ((r) &7)] op) : (upi42->ram[(r) &7] op)) + +#define UPI42_ROM_SHIFT 0 /* actually the mask */ +#define UPI42_RAM_SHIFT 16 /* actually the mask */ +#define UPI42_TYPE_MCS (0 << 24) +#define UPI42_TYPE_UPI (1 << 24) +#define UPI42_EXT_C42 (1 << 25) + +#define UPI42_8048 ((1023 << UPI42_ROM_SHIFT) | (63 << UPI42_RAM_SHIFT) | UPI42_TYPE_MCS) +#define UPI42_8049 ((2047 << UPI42_ROM_SHIFT) | (127 << UPI42_RAM_SHIFT) | UPI42_TYPE_MCS) +#define UPI42_8041 ((1023 << UPI42_ROM_SHIFT) | (127 << UPI42_RAM_SHIFT) | UPI42_TYPE_UPI) +#define UPI42_8042 ((2047 << UPI42_ROM_SHIFT) | (255 << UPI42_RAM_SHIFT) | UPI42_TYPE_UPI) +#define UPI42_80C42 ((4095 << UPI42_ROM_SHIFT) | (255 << UPI42_RAM_SHIFT) | UPI42_TYPE_UPI | UPI42_EXT_C42) + +typedef struct _upi42_ { + int (*ops[256])(struct _upi42_ *upi42, uint32_t fetchdat); + uint32_t type; + uint8_t ram[256], *rom, /* memory */ + ports_in[8], ports_out[8], /* I/O ports */ + dbb_in, dbb_out; /* UPI-42 data buffer */ + + uint8_t rammask, /* RAM mask */ + a, /* accumulator */ + t, /* timer counter */ + psw, /* program status word */ + sts; /* UPI-42 status */ + + uint16_t pc, rommask; /* program counter and ROM mask */ + + unsigned int prescaler : 5, tf : 1, skip_timer_inc : 1, /* timer/counter */ + run_timer : 1, run_counter : 1, tcnti : 1, /* timer/counter enables */ + i : 1, i_raise : 1, tcnti_raise : 1, irq_mask : 1, /* interrupts */ + t0 : 1, t1 : 1, /* T0/T1 signals */ + flags : 1, dbf : 1, suspend : 1; /* UPI-42 flags */ + + int cycs; /* cycle counter */ + +#ifndef UPI42_STANDALONE + uint8_t ram_index; + uint16_t rom_index; +#endif +} upi42_t; + +static inline void +upi42_mirror_f0(upi42_t *upi42) +{ + /* Update status register F0 flag to match PSW F0 flag. */ + upi42->sts = ((upi42->psw & 0x20) >> 3) | (upi42->sts & ~0x04); +} + +static int +upi42_op_MOV_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = UPI42_REG(upi42, fetchdat, ); + return 1; +} + +static int +upi42_op_MOV_Rr_A(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG(upi42, fetchdat, = upi42->a); + return 1; +} + +static int +upi42_op_MOV_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_MOV_indRr_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask] = upi42->a; + return 1; +} + +static int +upi42_op_MOV_Rr_imm(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG(upi42, fetchdat, = fetchdat >> 8); + upi42->cycs--; + return 2; +} + +static int +upi42_op_MOV_indRr_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask] = fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_MOV_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_MOV_A_PSW(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->psw; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_MOV_PSW_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw = upi42->a; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_MOV_A_T(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->t; + return 1; +} + +static int +upi42_op_MOV_T_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->t = upi42->a; + return 1; +} + +static int +upi42_op_MOV_STS_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->sts = (upi42->a & 0xf0) | (upi42->sts & 0x0f); + return 1; +} + +static int +upi42_op_MOVP_A_indA(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->rom[(upi42->pc & 0xff00) | upi42->a]; + upi42->cycs--; + return 1; +} + +static int +upi42_op_MOVP3_A_indA(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->rom[0x300 | upi42->a]; + upi42->cycs--; + return 1; +} + +static int +upi42_op_XCH_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a; + upi42->a = UPI42_REG(upi42, fetchdat, ); + UPI42_REG(upi42, fetchdat, = temp); + return 1; +} + +static int +upi42_op_XCH_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a, addr = upi42->ram[fetchdat & 1] & upi42->rammask; + upi42->a = upi42->ram[addr]; + upi42->ram[addr] = temp; + return 1; +} + +static int +upi42_op_XCHD_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a, addr = upi42->ram[fetchdat & 1] & upi42->rammask; + upi42->a = (upi42->a & 0xf0) | (upi42->ram[addr] & 0x0f); + upi42->ram[addr] = (upi42->ram[addr] & 0xf0) | (temp & 0x0f); + return 1; +} + +static int +upi42_op_SWAP_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = (upi42->a << 4) | (upi42->a >> 4); + return 1; +} + +static int +upi42_op_IN_A_Pp(upi42_t *upi42, uint32_t fetchdat) +{ + int port = fetchdat & 3; + upi42->a = upi42->ports_in[port] & upi42->ports_out[port]; + upi42->cycs--; + return 1; +} + +static int +upi42_op_IN_A_DBB(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = upi42->dbb_in; + upi42->sts &= ~0x02; /* clear IBF */ + return 1; +} + +static int +upi42_op_OUTL_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports_out[fetchdat & 3] = upi42->a; + upi42->cycs--; + return 1; +} + +static int +upi42_op_OUT_DBB_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->dbb_out = upi42->a; + upi42->sts |= 0x01; /* set OBF */ + return 1; +} + +static int +upi42_op_MOVD_A_Pp(upi42_t *upi42, uint32_t fetchdat) +{ + int port = 4 | (fetchdat & 3); + upi42->a = (upi42->ports_in[port] & upi42->ports_out[port]) & 0x0f; + upi42->cycs--; + return 1; +} + +static int +upi42_op_MOVD_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports_out[4 | (fetchdat & 3)] = upi42->a & 0x0f; + upi42->cycs--; + return 1; +} + +static int +upi42_op_ANL_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a &= UPI42_REG(upi42, fetchdat, ); + return 1; +} + +static int +upi42_op_ORL_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a |= UPI42_REG(upi42, fetchdat, ); + return 1; +} + +static int +upi42_op_XRL_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a ^= UPI42_REG(upi42, fetchdat, ); + return 1; +} + +static int +upi42_op_ANL_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a &= upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_ORL_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a |= upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_XRL_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a ^= upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]; + return 1; +} + +static int +upi42_op_ANL_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a &= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ORL_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a |= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_XRL_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a ^= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ANL_Pp_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports_out[fetchdat & 3] &= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ORL_Pp_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports_out[fetchdat & 3] |= fetchdat >> 8; + upi42->cycs--; + return 2; +} + +static int +upi42_op_ANLD_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports_out[4 | (fetchdat & 3)] &= upi42->a; + upi42->cycs--; + return 1; +} + +static int +upi42_op_ORLD_Pp_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ports_out[4 | (fetchdat & 3)] |= upi42->a; + upi42->cycs--; + return 1; +} + +static int +upi42_op_RR_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = (upi42->a << 7) | (upi42->a >> 1); + return 1; +} + +static int +upi42_op_RL_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = (upi42->a >> 7) | (upi42->a << 1); + return 1; +} + +static int +upi42_op_RRC_A(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a; + upi42->a = (upi42->psw & 0x80) | (temp >> 1); + upi42->psw = (temp << 7) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_RLC_A(upi42_t *upi42, uint32_t fetchdat) +{ + uint8_t temp = upi42->a; + upi42->a = (temp << 1) | (upi42->psw >> 7); + upi42->psw = (temp & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_INC_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a++; + return 1; +} + +static int +upi42_op_INC_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG(upi42, fetchdat, ++); + return 1; +} + +static int +upi42_op_INC_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->ram[upi42->ram[fetchdat & 1] & upi42->rammask]++; + return 1; +} + +static int +upi42_op_DEC_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a--; + return 1; +} + +static int +upi42_op_DEC_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + UPI42_REG(upi42, fetchdat, --); + return 1; +} + +static int +upi42_op_DJNZ_Rr_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->cycs--; + UPI42_REG(upi42, fetchdat, --); + if (UPI42_REG(upi42, fetchdat, )) { + upi42->pc = (upi42->pc & 0xff00) | ((fetchdat >> 8) & 0xff); + return 0; + } else { + return 2; + } +} + +static int +upi42_op_ADD_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + UPI42_REG(upi42, fetchdat, ); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADDC_A_Rr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (upi42->psw >> 7) + UPI42_REG(upi42, fetchdat, ); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADD_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + upi42->ram[UPI42_REG(upi42, fetchdat, ) & upi42->rammask]; + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADDC_A_indRr(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (upi42->psw >> 7) + upi42->ram[UPI42_REG(upi42, fetchdat, ) & upi42->rammask]; + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + return 1; +} + +static int +upi42_op_ADD_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (fetchdat >> 8); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + upi42->cycs--; + return 2; +} + +static int +upi42_op_ADDC_A_imm(upi42_t *upi42, uint32_t fetchdat) +{ + int res = upi42->a + (upi42->psw >> 7) + (fetchdat >> 8); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + upi42->cycs--; + return 2; +} + +static int +upi42_op_CLR_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = 0; + return 1; +} + +static int +upi42_op_CPL_A(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->a = ~upi42->a; + return 1; +} + +static int +upi42_op_DA_A(upi42_t *upi42, uint32_t fetchdat) +{ + if (((upi42->a & 0x0f) > 9) || (upi42->psw & 0x40)) + upi42->a += 6; + if (((upi42->a >> 4) > 9) || (upi42->psw & 0x80)) { + int res = upi42->a + (6 << 4); + upi42->a = res; + upi42->psw = ((res >> 1) & 0x80) | (upi42->psw & ~0x80); + } + return 1; +} + +static int +upi42_op_CLR_C(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw &= ~0x80; + return 1; +} + +static int +upi42_op_CPL_C(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw ^= 0x80; + return 1; +} + +static int +upi42_op_CLR_F0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw &= ~0x20; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_CPL_F0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw ^= 0x20; + upi42_mirror_f0(upi42); + return 1; +} + +static int +upi42_op_CLR_F1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->sts &= ~0x08; + return 1; +} + +static int +upi42_op_CPL_F1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->sts ^= 0x08; + return 1; +} + +static int +upi42_op_EN_I(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->i = 1; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_DIS_I(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->i = 0; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_EN_TCNTI(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->tcnti = 1; + return 1; +} + +static int +upi42_op_DIS_TCNTI(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->tcnti = upi42->tcnti_raise = 0; + return 1; +} + +static int +upi42_op_STRT_T(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->run_timer = 1; + upi42->prescaler = 0; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_STRT_CNT(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->run_counter = 1; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_STOP_TCNT(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->run_timer = upi42->run_counter = 0; + upi42->skip_timer_inc = 1; + return 1; +} + +static int +upi42_op_SEL_PMB0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->dbf = 0; + return 1; +} + +static int +upi42_op_SEL_PMB1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->dbf = 1; + return 1; +} + +static int +upi42_op_SEL_RB0(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw &= ~0x10; + return 1; +} + +static int +upi42_op_SEL_RB1(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->psw |= 0x10; + return 1; +} + +static int +upi42_op_NOP(upi42_t *upi42, uint32_t fetchdat) +{ + return 1; +} + +static int +upi42_op_CALL_imm(upi42_t *upi42, uint32_t fetchdat) +{ + /* Push new frame onto stack. */ + uint8_t sp = (upi42->psw & 0x07) << 1; + upi42->ram[8 + sp++] = upi42->pc + 2; /* stack frame format is undocumented! */ + upi42->ram[8 + sp++] = (upi42->psw & 0xf0) | ((upi42->pc >> 8) & 0x07); + upi42->psw = (upi42->psw & 0xf8) | (sp >> 1); + + /* Load new program counter. */ + upi42->pc = (upi42->dbf << 11) | ((fetchdat << 3) & 0x0700) | ((fetchdat >> 8) & 0x00ff); + + upi42->cycs--; + return 0; +} + +static int +upi42_op_RET(upi42_t *upi42, uint32_t fetchdat) +{ + /* Pop frame off the stack. */ + uint8_t sp = (upi42->psw & 0x07) << 1; + uint8_t frame1 = upi42->ram[8 + --sp]; + uint8_t frame0 = upi42->ram[8 + --sp]; + upi42->psw = (upi42->psw & 0xf8) | (sp >> 1); + + /* Load new program counter. */ + upi42->pc = ((frame1 & 0x0f) << 8) | frame0; + + /* Load new Program Status Word and unmask interrupts if this is RETR. */ + if (fetchdat & 0x10) { + upi42->psw = (frame1 & 0xf0) | (upi42->psw & 0x0f); + upi42_mirror_f0(upi42); + + upi42->irq_mask = 0; + } + + upi42->cycs--; + return 0; +} + +static int +upi42_op_JMP_imm(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->pc = (upi42->dbf << 11) | ((fetchdat << 3) & 0x0700) | ((fetchdat >> 8) & 0x00ff); + upi42->cycs--; + return 0; +} + +static int +upi42_op_JMPP_indA(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->pc = (upi42->pc & 0xff00) | upi42->a; + upi42->cycs--; + return 0; +} + +#define UPI42_COND_JMP_IMM(insn, cond, post) \ + static int \ + upi42_op_##insn##_imm(upi42_t *upi42, uint32_t fetchdat) \ + { \ + if (cond) \ + upi42->pc = (upi42->pc & 0xff00) | ((fetchdat >> 8) & 0x00ff); \ + post; \ + upi42->cycs--; \ + return 2 * !(cond); \ + } +UPI42_COND_JMP_IMM(JC, upi42->psw & 0x80, ) +UPI42_COND_JMP_IMM(JNC, !(upi42->psw & 0x80), ) +UPI42_COND_JMP_IMM(JZ, !upi42->a, ) +UPI42_COND_JMP_IMM(JNZ, upi42->a, ) +UPI42_COND_JMP_IMM(JT0, upi42->t0, ) +UPI42_COND_JMP_IMM(JNT0, !upi42->t0, ) +UPI42_COND_JMP_IMM(JT1, upi42->t1, ) +UPI42_COND_JMP_IMM(JNT1, !upi42->t1, ) +UPI42_COND_JMP_IMM(JF0, upi42->psw & 0x20, ) +UPI42_COND_JMP_IMM(JF1, upi42->sts & 0x08, ) +UPI42_COND_JMP_IMM(JTF, !upi42->tf, upi42->tf = 0) +UPI42_COND_JMP_IMM(JBb, upi42->a &(1 << ((fetchdat >> 5) & 7)), ) +UPI42_COND_JMP_IMM(JNIBF, !(upi42->sts & 0x02), ) +UPI42_COND_JMP_IMM(JOBF, upi42->sts & 0x01, ) + +static int +upi42_op_EN_A20(upi42_t *upi42, uint32_t fetchdat) +{ + /* Enable fast A20 until reset. */ + return 1; +} + +static int +upi42_op_EN_DMA(upi42_t *upi42, uint32_t fetchdat) +{ + return 1; +} + +static int +upi42_op_EN_FLAGS(upi42_t *upi42, uint32_t fetchdat) +{ + upi42->flags = 1; + return 1; +} + +static int +upi42_op_SUSPEND(upi42_t *upi42, uint32_t fetchdatr) +{ + /* Inhibit execution until reset. */ + upi42->suspend = 1; + return 1; +} + +static const int (*ops_80c42[256])(upi42_t *upi42, uint32_t fetchdat) = { + // clang-format off + /* 0 / 8 */ /* 1 / 9 */ /* 2 / a */ /* 3 / b */ /* 4 / c */ /* 5 / d */ /* 6 / e */ /* 7 / f */ + /* 00 */ upi42_op_NOP, NULL, upi42_op_OUT_DBB_A, upi42_op_ADD_A_imm, upi42_op_JMP_imm, upi42_op_EN_I, NULL, upi42_op_DEC_A, + /* 08 */ upi42_op_IN_A_Pp, upi42_op_IN_A_Pp, upi42_op_IN_A_Pp, NULL, upi42_op_MOVD_A_Pp, upi42_op_MOVD_A_Pp, upi42_op_MOVD_A_Pp, upi42_op_MOVD_A_Pp, + /* 10 */ upi42_op_INC_indRr, upi42_op_INC_indRr, upi42_op_JBb_imm, upi42_op_ADDC_A_imm, upi42_op_CALL_imm, upi42_op_DIS_I, upi42_op_JTF_imm, upi42_op_INC_A, + /* 18 */ upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, upi42_op_INC_Rr, + /* 20 */ upi42_op_XCH_A_indRr, upi42_op_XCH_A_indRr, upi42_op_IN_A_DBB, upi42_op_MOV_A_imm, upi42_op_JMP_imm, upi42_op_EN_TCNTI, upi42_op_JNT0_imm, upi42_op_CLR_A, + /* 28 */ upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, upi42_op_XCH_A_Rr, + /* 30 */ upi42_op_XCHD_A_indRr, upi42_op_XCHD_A_indRr, upi42_op_JBb_imm, upi42_op_EN_A20, upi42_op_CALL_imm, upi42_op_DIS_TCNTI, upi42_op_JT0_imm, upi42_op_CPL_A, + /* 38 */ upi42_op_OUTL_Pp_A, upi42_op_OUTL_Pp_A, upi42_op_OUTL_Pp_A, upi42_op_OUTL_Pp_A, upi42_op_MOVD_Pp_A, upi42_op_MOVD_Pp_A, upi42_op_MOVD_Pp_A, upi42_op_MOVD_Pp_A, + /* 40 */ upi42_op_ORL_A_indRr, upi42_op_ORL_A_indRr, upi42_op_MOV_A_T, upi42_op_ORL_A_imm, upi42_op_JMP_imm, upi42_op_STRT_CNT, upi42_op_JNT1_imm, upi42_op_SWAP_A, + /* 48 */ upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, upi42_op_ORL_A_Rr, + /* 50 */ upi42_op_ANL_A_indRr, upi42_op_ANL_A_indRr, upi42_op_JBb_imm, upi42_op_ANL_A_imm, upi42_op_CALL_imm, upi42_op_STRT_T, upi42_op_JT1_imm, upi42_op_DA_A, + /* 58 */ upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, upi42_op_ANL_A_Rr, + /* 60 */ upi42_op_ADD_A_indRr, upi42_op_ADD_A_indRr, upi42_op_MOV_T_A, upi42_op_SEL_PMB0, upi42_op_JMP_imm, upi42_op_STOP_TCNT, NULL, upi42_op_RRC_A, + /* 68 */ upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, upi42_op_ADD_A_Rr, + /* 70 */ upi42_op_ADDC_A_indRr, upi42_op_ADDC_A_indRr, upi42_op_JBb_imm, upi42_op_SEL_PMB1, upi42_op_CALL_imm, NULL, upi42_op_JF1_imm, upi42_op_RR_A, + /* 78 */ upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, upi42_op_ADDC_A_Rr, + /* 80 */ NULL, NULL, upi42_op_SUSPEND, upi42_op_RET, upi42_op_JMP_imm, upi42_op_CLR_F0, upi42_op_JOBF_imm, NULL, + /* 88 */ upi42_op_ORL_Pp_imm, upi42_op_ORL_Pp_imm, upi42_op_ORL_Pp_imm, upi42_op_ORL_Pp_imm, upi42_op_ORLD_Pp_A, upi42_op_ORLD_Pp_A, upi42_op_ORLD_Pp_A, upi42_op_ORLD_Pp_A, + /* 90 */ upi42_op_MOV_STS_A, NULL, upi42_op_JBb_imm, upi42_op_RET, upi42_op_CALL_imm, upi42_op_CPL_F0, upi42_op_JNZ_imm, upi42_op_CLR_C, + /* 98 */ upi42_op_ANL_Pp_imm, upi42_op_ANL_Pp_imm, upi42_op_ANL_Pp_imm, upi42_op_ANL_Pp_imm, upi42_op_ANLD_Pp_A, upi42_op_ANLD_Pp_A, upi42_op_ANLD_Pp_A, upi42_op_ANLD_Pp_A, + /* a0 */ upi42_op_MOV_indRr_A, upi42_op_MOV_indRr_A, NULL, upi42_op_MOVP_A_indA, upi42_op_JMP_imm, upi42_op_CLR_F1, NULL, upi42_op_CPL_C, + /* a8 */ upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, upi42_op_MOV_Rr_A, + /* b0 */ upi42_op_MOV_indRr_imm,upi42_op_MOV_indRr_imm,upi42_op_JBb_imm, upi42_op_JMPP_indA, upi42_op_CALL_imm, upi42_op_CPL_F1, upi42_op_JF0_imm, NULL, + /* b8 */ upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, upi42_op_MOV_Rr_imm, + /* c0 */ NULL, NULL, NULL, NULL, upi42_op_JMP_imm, NULL, upi42_op_JZ_imm, upi42_op_MOV_A_PSW, + /* c8 */ upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, upi42_op_DEC_Rr, + /* d0 */ upi42_op_XRL_A_indRr, upi42_op_XRL_A_indRr, upi42_op_JBb_imm, upi42_op_XRL_A_imm, upi42_op_CALL_imm, NULL, upi42_op_JNIBF_imm, upi42_op_MOV_PSW_A, + /* d8 */ upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, upi42_op_XRL_A_Rr, + /* e0 */ NULL, NULL, upi42_op_SUSPEND, upi42_op_MOVP3_A_indA, upi42_op_JMP_imm, upi42_op_EN_DMA, upi42_op_JNC_imm, upi42_op_RL_A, + /* e8 */ upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, upi42_op_DJNZ_Rr_imm, + /* f0 */ upi42_op_MOV_A_indRr, upi42_op_MOV_A_indRr, upi42_op_JBb_imm, NULL, upi42_op_CALL_imm, upi42_op_EN_FLAGS, upi42_op_JC_imm, upi42_op_RLC_A, + /* f8 */ upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr, upi42_op_MOV_A_Rr + // clang-format on +}; + +static void +upi42_exec(void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + + /* Skip everything if we're suspended, or just process timer if we're in a multi-cycle instruction. */ + if (upi42->suspend) + return; + else if (++upi42->cycs < 0) + goto timer; + + /* Trigger interrupt if requested. */ + if (upi42->irq_mask) { + /* Masked, we're currently in an ISR. */ + } else if (upi42->i_raise) { + /* External interrupt. Higher priority than the timer interrupt. */ + upi42->irq_mask = 1; + upi42->i_raise = 0; + + upi42->pc -= 2; + upi42->cycs++; + upi42_op_CALL_imm(upi42, 3 << 8); + return; + } else if (upi42->tcnti_raise) { + /* Timer interrupt. */ + upi42->irq_mask = 1; + upi42->tcnti_raise = 0; + + upi42->pc -= 2; + upi42->cycs++; + upi42_op_CALL_imm(upi42, 7 << 8); + return; + } + + /* Fetch instruction. */ + uint32_t fetchdat = *((uint32_t *) &upi42->rom[upi42->pc]); + + /* Decode instruction. */ + uint8_t insn = fetchdat & 0xff; + if (upi42->ops[insn]) { + /* Execute instruction. */ + int pc_inc = upi42->ops[insn](upi42, fetchdat); + + /* Increment lower 11 bits of the program counter. */ + upi42->pc = (upi42->pc & 0xf800) | ((upi42->pc + pc_inc) & 0x07ff); + + /* Decrement cycle counter. Multi-cycle instructions also decrement within their code. */ + upi42->cycs--; + } else { + fatal("UPI42: Unknown opcode %02X (%08X)\n", insn, fetchdat); + return; + } + +timer: + /* Process timer. */ + if (!upi42->run_timer) { + /* Timer disabled. */ + } else if (upi42->skip_timer_inc) { + /* Some instructions don't increment the timer. */ + upi42->skip_timer_inc = 0; + } else { + /* Increment counter once the prescaler overflows, + and set timer flag once the main value overflows. */ + if ((++upi42->prescaler == 0) && (++upi42->t == 0)) { + upi42->tf = 1; + + /* Fire counter interrupt if enabled. */ + if (upi42->tcnti) + upi42->tcnti_raise = 1; + } + } +} + +uint8_t +upi42_port_read(void *priv, int port) +{ + upi42_t *upi42 = (upi42_t *) priv; + + /* Read base port value. */ + port &= 7; + uint8_t ret = upi42->ports_in[port] & upi42->ports_out[port]; + + /* Apply special meanings. */ + switch (port) { + } + + upi42_log("UPI42: port_read(%d) = %02X\n", port, ret); + return ret; +} + +void +upi42_port_write(void *priv, int port, uint8_t val) +{ + upi42_t *upi42 = (upi42_t *) priv; + + port &= 7; + upi42_log("UPI42: port_write(%d, %02X)\n", port, val); + + /* Set input level. */ + upi42->ports_in[port] = val; +} + +/* NOTE: The dbb/sts/cmd functions use I/O handler signatures; port is ignored. */ + +uint8_t +upi42_dbb_read(uint16_t port, void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + + uint8_t ret = upi42->dbb_out; + upi42_log("UPI42: dbb_read(%04X) = %02X\n", port, ret); + upi42->sts &= ~0x01; /* clear OBF */ + return ret; +} + +void +upi42_dbb_write(uint16_t port, uint8_t val, void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + + upi42_log("UPI42: dbb_write(%04X, %02X)\n", port, val); + upi42->dbb_in = val; + upi42->sts = (upi42->sts & ~0x08) | 0x02; /* clear F1 and set IBF */ + if (upi42->i) /* fire IBF interrupt if enabled */ + upi42->i_raise = 1; +} + +uint8_t +upi42_sts_read(uint16_t port, void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + + uint8_t ret = upi42->sts; + upi42_log("UPI42: sts_read(%04X) = %02X\n", port, ret); + return ret; +} + +void +upi42_cmd_write(uint16_t port, uint8_t val, void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + + upi42_log("UPI42: cmd_write(%04X, %02X)\n", port, val); + upi42->dbb_in = val; + upi42->sts |= 0x0a; /* set F1 and IBF */ + if (upi42->i) /* fire IBF interrupt if enabled */ + upi42->i_raise = 1; +} + +void +upi42_reset(upi42_t *upi42) +{ + upi42->pc = 0; /* program counter */ + upi42->psw = 0; /* stack pointer, register bank and F0 */ + upi42->dbf = 0; /* ROM bank */ + upi42->i = 0; /* external interrupt */ + upi42->tcnti = 0; /* timer/counter interrupt */ + upi42->tf = 0; /* timer flag */ + upi42->sts = 0; /* F1 */ + upi42->flags = 0; /* UPI-42 buffer interrupts */ + upi42->suspend = 0; /* 80C42 suspend flag */ +} + +void +upi42_do_init(upi32_t type, uint8_t *rom) +{ + memset(upi42, 0, sizeof(upi42_t)); + upi42->rom = rom; + + /* Set chip type. */ + upi42->type = type; + upi42->rommask = type >> UPI42_ROM_SHIFT; + upi42->rammask = type >> UPI42_RAM_SHIFT; + + /* Build instruction table. */ + memcpy(upi42->ops, ops_80c42, sizeof(ops_80c42)); + if (!(type & UPI42_EXT_C42)) { + /* Remove 80C42-only instructions. */ + upi42->ops[0x33] = NULL; /* EN A20 */ + upi42->ops[0x63] = NULL; /* SEL PMB0 */ + upi42->ops[0x73] = NULL; /* SEL PMB1 */ + upi42->ops[0x42] = NULL; /* SUSPEND */ + upi42->ops[0xe2] = NULL; /* SUSPEND */ + } + + memset(upi42_t->ports_in, 0xff, 0x08); + upi42_t->t0 = 1; + upi42_t->t1 = 1; +} + +void * +upi42_init(uint32_t type, uint8_t *rom) +{ + /* Allocate state structure. */ + upi42_t *upi42 = (upi42_t *) malloc(sizeof(upi42_t)); + upi42_do_init(type, rom); + + return upi42; +} + +#ifdef UPI42_STANDALONE +static const char *flags_8042[] = { "OBF", "IBF", "F0", "F1", "ST4", "ST5", "ST6", "ST7" }; + +int +main(int argc, char **argv) +{ + /* Check arguments. */ + if (argc < 2) { + upi42_log("Specify a ROM file to execute.\n"); + return 1; + } + + /* Load ROM. */ + uint8_t rom[4096] = { 0 }; + FILE *f = fopen(argv[1], "rb"); + if (!f) { + upi42_log("Could not read ROM file.\n"); + return 2; + } + size_t rom_size = fread(rom, sizeof(rom[0]), sizeof(rom), f); + fclose(f); + + /* Determine chip type from ROM. */ + upi42_log("%d-byte ROM, ", rom_size); + uint32_t type; + switch (rom_size) { + case 0 ... 1024: + upi42_log("emulating 8041"); + type = UPI42_8041; + break; + + case 1025 ... 2048: + upi42_log("emulating 8042"); + type = UPI42_8042; + break; + + case 2049 ... 4096: + upi42_log("emulating 80C42"); + type = UPI42_80C42; + break; + + default: + upi42_log("unknown!\n"); + return 3; + } + upi42_log(".\n"); + + /* Initialize emulator. */ + upi42_t *upi42 = (upi42_t *) upi42_init(type, rom); + + /* Start execution. */ + char cmd, cmd_buf[256]; + int val, go_until = -1; + while (1) { + /* Output status. */ + upi42_log("PC=%04X I=%02X(%02X) A=%02X", upi42->pc, upi42->rom[upi42->pc], upi42->rom[upi42->pc + 1], upi42->a); + for (val = 0; val < 8; val++) + upi42_log(" R%d=%02X", val, UPI42_REG(upi42, val, )); + upi42_log(" T=%02X PSW=%02X TF=%d I=%d TCNTI=%d", upi42->t, upi42->psw, upi42->tf, upi42->i, upi42->tcnti); + if (type & UPI42_TYPE_UPI) { + upi42_log(" STS=%02X", upi42->sts); + for (val = 0; val < 8; val++) { + if (upi42->sts & (1 << val)) { + upi42_log(" [%s]", flags_8042[val]); + } else { + upi42_log(" %s ", flags_8042[val]); + } + } + } + upi42_log("\n"); + + /* Break for command only if stepping. */ + if ((go_until < 0) || (upi42->pc == go_until)) { +retry: + go_until = -1; + upi42_log("> "); + + /* Read command. */ + cmd = '\0'; + scanf("%c", &cmd); + + /* Execute command. */ + switch (cmd) { + case 'c': /* write command */ + if (scanf("%X%*c", &val, &cmd_buf)) + upi42_cmd_write(0, val, upi42); + goto retry; + + case 'd': /* write data */ + if (scanf("%X%*c", &val, &cmd_buf)) + upi42_dbb_write(0, val, upi42); + goto retry; + + case 'g': /* go until */ + if (!scanf("%X%*c", &go_until, &cmd_buf)) + go_until = -1; + break; + + case 'r': /* read data */ + upi42_dbb_read(0, upi42); /* return value will be logged */ + goto skip_and_retry; + + case 'q': /* exit */ + return 0; + + case '\r': /* step */ + case '\n': + case '\0': + break; + + default: + upi42_log("Monitor commands:\n"); + upi42_log("- Return (no command) - Step execution\n"); + upi42_log("- q (or Ctrl+C) - Exit\n"); + upi42_log("- gXXXX - Execute until PC is hex value XXXX\n"); + upi42_log("- dXX - Write hex value XX to data port\n"); + upi42_log("- cXX - Write hex value XX to command port\n"); + upi42_log("- r - Read from data port and reset OBF\n"); +skip_and_retry: + scanf("%*c", &cmd_buf); + goto retry; + } + } + + /* Execute a cycle. */ + upi42_exec(upi42); + } + + return 0; +} +#else +static void +upi42_write(uint16_t port, uint8_t val, void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + uint32_t temp_type, uint8_t *temp_rom; + int i; + + switch (port) { + /* Write to data port. */ + case 0x0060: + case 0x0160: + upi42_dbb_write(0, val, upi42); + break; + + /* RAM Index. */ + case 0x0162: + upi42->ram_index = val & upi42->rammask; + break; + + /* RAM. */ + case 0x0163: + upi42->ram[upi42->ram_index & upi42->rammask] = val; + break; + + /* Write to command port. */ + case 0x0064: + case 0x0164: + upi42_cmd_write(0, val, upi42); + break; + + /* Input ports. */ + case 0x0180 ... 0x0187: + upi42->ports_in[addr & 0x0007] = val; + break; + + /* Output ports. */ + case 0x0188 ... 0x018f: + upi42->ports_out[addr & 0x0007] = val; + break; + + /* 4 = T0, 5 = T1. */ + case 0x0194: + upi42->t0 = (val >> 4) & 0x01; + upi42->t1 = (val >> 5) & 0x01; + break; + + /* Program counter. */ + case 0x0196: + upi42->pc = (upi42->pc & 0xff00) | val; + break; + case 0x0197: + upi42->pc = (upi42->pc & 0x00ff) | (val << 8); + break; + + /* Input data buffer. */ + case 0x019a: + upi42->dbb_in = val; + break; + + /* Output data buffer. */ + case 0x019b: + upi42->dbb_out = val; + break; + + /* ROM Index. */ + case 0x01a0: + upi42->rom_index = (upi42->rom_index & 0xff00) | val; + break; + case 0x01a1: + upi42->rom_index = (upi42->rom_index & 0x00ff) | (val << 8); + break; + + /* Hard reset. */ + case 0x01a2: + temp_type = upi42->type; + temp_rom = upi42->rom; + upi42_do_init(temp_type, temp_rom); + break; + + /* Soft reset. */ + case 0x01a3: + upi42_reset(upi42); + break; + + /* ROM. */ + case 0x01a4: + upi42->rom[upi42->rom_index & upi42->rommask] = val; + break; + case 0x01a5: + upi42->rom[(upi42->rom_index + 1) & upi42->rommask] = val; + break; + case 0x01a6: + upi42->rom[(upi42->rom_index + 2) & upi42->rommask] = val; + break; + case 0x01a7: + upi42->rom[(upi42->rom_index + 3) & upi42->rommask] = val; + break; + + /* Pause. */ + case 0x01a8: + break; + + /* Resume. */ + case 0x01a9: + break; + + /* Bus master ROM: 0 = direction (0 = to memory, 1 = from memory). */ + case 0x01aa: + if (val & 0x01) { + for (i = 0; i <= upi42->rommask; i += 4) + *(uint32_t *) &(upi42->rom[i]) = mem_readl_phys(upi42->ram_addr + i); + } else { + for (i = 0; i <= upi42->rommask; i += 4) + mem_writel_phys(upi42->ram_addr + i, *(uint32_t *) &(upi42->rom[i])); + } + upi42->bm_stat = (val & 0x01) | 0x02; + break; + } +} + + +static uint8_t +upi42_read(uint16_t port, void *priv) +{ + upi42_t *upi42 = (upi42_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + /* Type. */ + case 0x015c: + ret = upi42->type & 0xff; + break; + case 0x015d: + ret = upi42->type >> 8; + break; + case 0x015e: + ret = upi42->type >> 16; + break; + case 0x015f: + ret = upi42->type >> 24; + break; + + /* Read from data port and reset OBF. */ + case 0x0060: + case 0x0160: + ret = upi42->dbb_out; + upi42->sts &= ~0x01; /* clear OBF */ + break; + + /* RAM Mask. */ + case 0x0161: + ret = upi42->rammask; + break; + + /* RAM Index. */ + case 0x0162: + ret = upi42->ram_index; + break; + + /* RAM. */ + case 0x0163: + ret = upi42->ram[upi42->ram_index & upi42->rammask]; + break; + + /* Read status. */ + case 0x0064: + case 0x0164: + ret = upi42->sts; + break; + + /* Input ports. */ + case 0x0180 ... 0x0187: + ret = upi42->ports_in[addr & 0x0007]; + break; + + /* Output ports. */ + case 0x0188 ... 0x018f: + ret = upi42->ports_out[addr & 0x0007]; + break; + + /* Accumulator. */ + case 0x0190: + ret = upi42->a; + break; + + /* Timer counter. */ + case 0x0191: + ret = upi42->t; + break; + + /* Program status word. */ + case 0x0192: + ret = upi42->psw; + break; + + /* 0-4 = Prescaler, 5 = TF, 6 = Skip Timer Inc, 7 = Run Timer. */ + case 0x0193: + ret = (upi42->prescaler & 0x1f) || ((upi42->tf & 0x01) << 5) || ((upi42->skip_timer_inc & 0x01) << 6) || ((upi42->run_timer & 0x01) << 7); + break; + + /* 0 = I, 1 = I Raise, 2 = TCNTI Raise, 3 = IRQ Mask, 4 = T0, 5 = T1, 6 = Flags, 7 = DBF. */ + case 0x0194: + ret = (upi42->i & 0x01) || ((upi42->i_raise & 0x01) << 1) || ((upi42->tcnti_raise & 0x01) << 2) || ((upi42->irq_mask & 0x01) << 3) || + ((upi42->t0 & 0x01) << 4) || ((upi42->t1 & 0x01) << 5) || ((upi42->flags & 0x01) << 6) || ((upi42->dbf & 0x01) << 7); + break; + + /* 0 = Suspend. */ + case 0x0195: + ret = (upi42->suspend & 0x01); + break; + + /* Program counter. */ + case 0x0196: + ret = upi42->pc & 0xff; + break; + case 0x0197: + ret = upi42->pc >> 8; + break; + + /* ROM Mask. */ + case 0x0198: + ret = upi42->rommask & 0xff; + break; + case 0x0199: + ret = upi42->rommask >> 8; + break; + + /* Input data buffer. */ + case 0x019a: + ret = upi42->dbb_in; + break; + + /* Output data buffer. */ + case 0x019b: + ret = upi42->dbb_out; + break; + + /* Cycle counter. */ + case 0x019c: + ret = upi42->cycs & 0xff; + break; + case 0x019d: + ret = upi42->cycs >> 8; + break; + case 0x019e: + ret = upi42->cycs >> 16; + break; + case 0x019f: + ret = upi42->cycs >> 24; + break; + + /* ROM Index. */ + case 0x01a0: + ret = upi42->rom_index & 0xff; + break; + case 0x01a1: + ret = upi42->rom_index >> 8; + break; + + /* ROM. */ + case 0x01a4: + ret = upi42->rom[upi42->rom_index & upi42->rommask]; + break; + case 0x01a5: + ret = upi42->rom[(upi42->rom_index + 1) & upi42->rommask]; + break; + case 0x01a6: + ret = upi42->rom[(upi42->rom_index + 2) & upi42->rommask]; + break; + case 0x01a7: + ret = upi42->rom[(upi42->rom_index + 3) & upi42->rommask]; + break; + + /* Bus master status: 0 = direction, 1 = finished. */ + case 0x01ab: + ret = upi42->bm_stat; + break; + } + + return ret; +} +#endif diff --git a/src/usb.c b/src/usb.c index 067294496..c70fc2d63 100644 --- a/src/usb.c +++ b/src/usb.c @@ -53,14 +53,12 @@ usb_log(const char *fmt, ...) static uint8_t uhci_reg_read(uint16_t addr, void *p) { - uint8_t ret = 0xff; + usb_t *dev = (usb_t *) p; + uint8_t ret, *regs = dev->uhci_io; - switch (addr & 0x1f) { - case 0x10: case 0x11: case 0x12: case 0x13: - /* Port status */ - ret = 0x00; - break; - } + addr &= 0x0000001f; + + ret = regs[addr]; return ret; } @@ -69,6 +67,58 @@ uhci_reg_read(uint16_t addr, void *p) static void uhci_reg_write(uint16_t addr, uint8_t val, void *p) { + usb_t *dev = (usb_t *) p; + uint8_t *regs = dev->uhci_io; + + addr &= 0x0000001f; + + switch (addr) { + case 0x02: + regs[0x02] &= ~(val & 0x3f); + break; + case 0x04: + regs[0x04] = (val & 0x0f); + break; + case 0x09: + regs[0x09] = (val & 0xf0); + break; + case 0x0a: case 0x0b: + regs[addr] = val; + break; + case 0x0c: + regs[0x0c] = (val & 0x7f); + break; + } +} + + +static void +uhci_reg_writew(uint16_t addr, uint16_t val, void *p) +{ + usb_t *dev = (usb_t *) p; + uint16_t *regs = (uint16_t *) dev->uhci_io; + + addr &= 0x0000001f; + + switch (addr) { + case 0x00: + if ((val & 0x0001) && !(regs[0x00] & 0x0001)) + regs[0x01] &= ~0x20; + else if (!(val & 0x0001)) + regs[0x01] |= 0x20; + regs[0x00] = (val & 0x00ff); + break; + case 0x06: + regs[0x03] = (val & 0x07ff); + break; + case 0x10: case 0x12: + regs[addr >> 1] = ((regs[addr >> 1] & 0xedbb) | (val & 0x1244)) & ~(val & 0x080a); + break; + default: + uhci_reg_write(addr, val & 0xff, p); + uhci_reg_write(addr + 1, (val >> 8) & 0xff, p); + break; + } } @@ -76,13 +126,13 @@ void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable) { if (dev->uhci_enable && (dev->uhci_io_base != 0x0000)) - io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, NULL, NULL, dev); + io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev); dev->uhci_io_base = base_l | (base_h << 8); dev->uhci_enable = enable; if (dev->uhci_enable && (dev->uhci_io_base != 0x0000)) - io_sethandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, NULL, NULL, dev); + io_sethandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev); } @@ -96,6 +146,9 @@ ohci_mmio_read(uint32_t addr, void *p) ret = dev->ohci_mmio[addr]; + if (addr == 0x101) + ret = (ret & 0xfe) | (!!mem_a20_key); + return ret; } @@ -120,7 +173,7 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) if (val & 0x08) { dev->ohci_mmio[0x0f] = 0x40; if ((dev->ohci_mmio[0x13] & 0xc0) == 0xc0) - smi_line = 1; + smi_raise(); } /* bit HostControllerReset must be cleared for the controller to be seen as initialized */ @@ -298,6 +351,28 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, } +static void +usb_reset(void *priv) +{ + usb_t *dev = (usb_t *) priv; + + memset(dev->uhci_io, 0x00, 128); + dev->uhci_io[0x0c] = 0x40; + dev->uhci_io[0x10] = dev->uhci_io[0x12] = 0x80; + + memset(dev->ohci_mmio, 0x00, 4096); + dev->ohci_mmio[0x00] = 0x10; + dev->ohci_mmio[0x01] = 0x01; + dev->ohci_mmio[0x48] = 0x02; + + io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev); + dev->uhci_enable = 0; + + mem_mapping_disable(&dev->ohci_mmio_mapping); + dev->ohci_enable = 0; +} + + static void usb_close(void *priv) { @@ -316,6 +391,10 @@ usb_init(const device_t *info) if (dev == NULL) return(NULL); memset(dev, 0x00, sizeof(usb_t)); + memset(dev->uhci_io, 0x00, 128); + dev->uhci_io[0x0c] = 0x40; + dev->uhci_io[0x10] = dev->uhci_io[0x12] = 0x80; + memset(dev->ohci_mmio, 0x00, 4096); dev->ohci_mmio[0x00] = 0x10; dev->ohci_mmio[0x01] = 0x01; @@ -325,22 +404,21 @@ usb_init(const device_t *info) ohci_mmio_read, NULL, NULL, ohci_mmio_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->ohci_mmio_mapping); + usb_reset(dev); return dev; } - -const device_t usb_device = -{ - "Universal Serial Bus", - DEVICE_PCI, - 0, - usb_init, - usb_close, - NULL, - NULL, - NULL, - NULL, - NULL +const device_t usb_device = { + .name = "Universal Serial Bus", + .internal_name = "usb", + .flags = DEVICE_PCI, + .local = 0, + .init = usb_init, + .close = usb_close, + .reset = usb_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt new file mode 100644 index 000000000..fd88103c7 --- /dev/null +++ b/src/video/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c + vid_compaq_cga.c vid_mda.c vid_hercules.c vid_herculesplus.c + vid_incolor.c vid_colorplus.c vid_genius.c vid_pgc.c vid_im1024.c + vid_sigma.c vid_wy700.c vid_ega.c vid_ega_render.c vid_svga.c vid_8514a.c + vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c + vid_ati28800.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c + vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c + vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c vid_et4000w32.c + vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c + vid_f82c425.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c + vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c + vid_sdac_ramdac.c vid_ogc.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c + vid_xga.c) + +if(MGA) + target_compile_definitions(vid PRIVATE USE_MGA) + target_sources(vid PRIVATE vid_mga.c) +endif() + +if(VGAWONDER) + target_compile_definitions(vid PRIVATE USE_VGAWONDER) +endif() + +if(XL24) + target_compile_definitions(vid PRIVATE USE_XL24) +endif() + +add_library(voodoo OBJECT vid_voodoo.c vid_voodoo_banshee.c + vid_voodoo_banshee_blitter.c vid_voodoo_blitter.c vid_voodoo_display.c + vid_voodoo_fb.c vid_voodoo_fifo.c vid_voodoo_reg.c vid_voodoo_render.c + vid_voodoo_setup.c vid_voodoo_texture.c) + +if(NOT MSVC AND (ARCH STREQUAL "i386" OR ARCH STREQUAL "x86_64")) + target_compile_options(voodoo PRIVATE "-msse2") +endif() diff --git a/src/video/agpgart.c b/src/video/agpgart.c new file mode 100644 index 000000000..b115d0b54 --- /dev/null +++ b/src/video/agpgart.c @@ -0,0 +1,194 @@ +/* + * 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. + * + * AGP Graphics Address Remapping Table remapping emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> + + +typedef struct { + int aperture_enable; + uint32_t aperture_base, aperture_size, aperture_mask, gart_base; + mem_mapping_t aperture_mapping; +} agpgart_t; + + +#ifdef ENABLE_AGPGART_LOG +int agpgart_do_log = ENABLE_AGPGART_LOG; + +static void +agpgart_log(const char *fmt, ...) +{ + va_list ap; + + if (agpgart_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define agpgart_log(fmt, ...) +#endif + + +void +agpgart_set_aperture(void *handle, uint32_t base, uint32_t size, int enable) +{ + agpgart_t *dev = (agpgart_t *) handle; + + agpgart_log("AGP GART: set_aperture(%08X, %d, %d)\n", base, size, enable); + + /* Disable old aperture mapping. */ + mem_mapping_disable(&dev->aperture_mapping); + + /* Set new aperture base address, size and mask. */ + dev->aperture_base = base; + dev->aperture_size = size; + dev->aperture_mask = size - 1; + + /* Enable new aperture mapping if requested. */ + if (dev->aperture_base && dev->aperture_size && dev->aperture_enable) { + mem_mapping_set_addr(&dev->aperture_mapping, dev->aperture_base, dev->aperture_size); + mem_mapping_enable(&dev->aperture_mapping); + } +} + + +void +agpgart_set_gart(void *handle, uint32_t base) +{ + agpgart_t *dev = (agpgart_t *) handle; + + agpgart_log("AGP GART: set_gart(%08X)\n", base); + + /* Set GART base address. */ + dev->gart_base = base; +} + + +static uint32_t +agpgart_translate(uint32_t addr, agpgart_t *dev) +{ + /* Extract the bits we care about. */ + addr &= dev->aperture_mask; + + /* Get the GART pointer for this page. */ + register uint32_t gart_ptr = mem_readl_phys(dev->gart_base + ((addr >> 10) & 0xfffffffc)) & 0xfffff000; + + /* Return remapped address with the page offset. */ + return gart_ptr | (addr & 0x00000fff); +} + + +static uint8_t +agpgart_aperture_readb(uint32_t addr, void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + return mem_readb_phys(agpgart_translate(addr, dev)); +} + + +static uint16_t +agpgart_aperture_readw(uint32_t addr, void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + return mem_readw_phys(agpgart_translate(addr, dev)); +} + + +static uint32_t +agpgart_aperture_readl(uint32_t addr, void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + return mem_readl_phys(agpgart_translate(addr, dev)); +} + + +static void +agpgart_aperture_writeb(uint32_t addr, uint8_t val, void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + mem_writeb_phys(agpgart_translate(addr, dev), val); +} + + +static void +agpgart_aperture_writew(uint32_t addr, uint16_t val, void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + mem_writew_phys(agpgart_translate(addr, dev), val); +} + + +static void +agpgart_aperture_writel(uint32_t addr, uint32_t val, void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + mem_writel_phys(agpgart_translate(addr, dev), val); +} + + +static void * +agpgart_init(const device_t *info) +{ + agpgart_t *dev = malloc(sizeof(agpgart_t)); + memset(dev, 0, sizeof(agpgart_t)); + + agpgart_log("AGP GART: init()\n"); + + /* Create aperture mapping. */ + mem_mapping_add(&dev->aperture_mapping, 0, 0, + agpgart_aperture_readb, agpgart_aperture_readw, agpgart_aperture_readl, + agpgart_aperture_writeb, agpgart_aperture_writew, agpgart_aperture_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + + return dev; +} + + +static void +agpgart_close(void *priv) +{ + agpgart_t *dev = (agpgart_t *) priv; + + agpgart_log("AGP GART: close()\n"); + + /* Disable aperture. */ + mem_mapping_disable(&dev->aperture_mapping); + + free(dev); +} + +const device_t agpgart_device = { + .name = "AGP Graphics Address Remapping Table", + .internal_name = "agpgart", + .flags = DEVICE_PCI, + .local = 0, + .init = agpgart_init, + .close = agpgart_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c new file mode 100644 index 000000000..1cb0a5407 --- /dev/null +++ b/src/video/vid_8514a.c @@ -0,0 +1,3475 @@ +/* + * 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 the 8514/A card from IBM for the MCA bus and + * generic ISA bus clones without vendor extensions. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/mca.h> +#include <86box/rom.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include "cpu.h" + +static void ibm8514_accel_out_fifo(ibm8514_t *dev, uint16_t port, uint32_t val, int len); +static void ibm8514_accel_outb(uint16_t port, uint8_t val, void *p); +static void ibm8514_accel_outw(uint16_t port, uint16_t val, void *p); +static uint8_t ibm8514_accel_inb(uint16_t port, void *p); +static uint16_t ibm8514_accel_inw(uint16_t port, void *p); + +static void ibm8514_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, ibm8514_t *dev, uint8_t ssv, int len); +static void ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, ibm8514_t *dev, int len); + +#define READ_PIXTRANS_WORD(cx, n) \ + if (cmd <= 1 || (cmd == 5)) { \ + temp = dev->vram[((dev->accel.cy * dev->h_disp) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((dev->accel.cy * dev->h_disp) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } else { \ + temp = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[(dev->accel.dest + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } + +#define READ(addr, dat) \ + dat = dev->vram[(addr) & (dev->vram_mask)]; + +#define MIX(mixmode, dest_dat, src_dat) { \ + switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ + case 0x00: dest_dat = ~dest_dat; break; \ + case 0x01: dest_dat = 0; break; \ + case 0x02: dest_dat = ~0; break; \ + case 0x03: dest_dat = dest_dat; break; \ + case 0x04: dest_dat = ~src_dat; break; \ + case 0x05: dest_dat = src_dat ^ dest_dat; break; \ + case 0x06: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x07: dest_dat = src_dat; break; \ + case 0x08: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x09: dest_dat = ~src_dat | dest_dat; break; \ + case 0x0a: dest_dat = src_dat | ~dest_dat; break; \ + case 0x0b: dest_dat = src_dat | dest_dat; break; \ + case 0x0c: dest_dat = src_dat & dest_dat; break; \ + case 0x0d: dest_dat = src_dat & ~dest_dat; break; \ + case 0x0e: dest_dat = ~src_dat & dest_dat; break; \ + case 0x0f: dest_dat = ~(src_dat | dest_dat); break; \ + case 0x10: dest_dat = MIN(src_dat, dest_dat); break; \ + case 0x11: dest_dat = dest_dat - src_dat; break; \ + case 0x12: dest_dat = src_dat - dest_dat; break; \ + case 0x13: dest_dat = src_dat + dest_dat; break; \ + case 0x14: dest_dat = MAX(src_dat, dest_dat); break; \ + case 0x15: dest_dat = (dest_dat - src_dat) / 2; break; \ + case 0x16: dest_dat = (src_dat - dest_dat) / 2; break; \ + case 0x17: dest_dat = (dest_dat + src_dat) / 2; break; \ + case 0x18: dest_dat = MAX(0, (dest_dat - src_dat)); break; \ + case 0x19: dest_dat = MAX(0, (dest_dat - src_dat)); break; \ + case 0x1a: dest_dat = MAX(0, (src_dat - dest_dat)); break; \ + case 0x1b: dest_dat = MIN(0xff, (dest_dat + src_dat)); break; \ + case 0x1c: dest_dat = MAX(0, (dest_dat - src_dat)) / 2; break; \ + case 0x1d: dest_dat = MAX(0, (dest_dat - src_dat)) / 2; break; \ + case 0x1e: dest_dat = MAX(0, (src_dat - dest_dat)) / 2; break; \ + case 0x1f: dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); break; \ + } \ + } + +#define WRITE(addr, dat) \ + dev->vram[((addr)) & (dev->vram_mask)] = dat; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; + + +static int +ibm8514_cpu_src(ibm8514_t *dev) +{ + if (!(dev->accel.cmd & 0x100)) + return 0; + + if (dev->accel.cmd & 1) + return 1; + + return 0; +} + +static int +ibm8514_cpu_dest(ibm8514_t *dev) +{ + if (!(dev->accel.cmd & 0x100)) + return 0; + + if (dev->accel.cmd & 1) + return 0; + + return 1; +} + + +static void +ibm8514_accel_out_pixtrans(ibm8514_t *dev, uint16_t port, uint16_t val, int len) +{ + uint8_t nibble = 0; + uint32_t pixelxfer = 0, monoxfer = 0xffffffff; + int pixcnt = 0; + int pixcntl = (dev->accel.multifunc[0x0a] >> 6) & 3; + int frgd_mix = (dev->accel.frgd_mix >> 5) & 3; + int bkgd_mix = (dev->accel.bkgd_mix >> 5) & 3; + int cmd = dev->accel.cmd >> 13; + int and3 = dev->accel.cur_x & 3; + + if (dev->accel.cmd & 0x100) { + if (len != 1) { + /*Bus size*/ + if (dev->accel.cmd & 0x200) /*16-bit*/ + pixcnt = 16; + else /*8-bit*/ + pixcnt = 8; + + /*Pixel transfer data mode, can't be the same as Foreground/Background CPU data*/ + if (pixcntl == 2) { + if ((frgd_mix == 2) || (bkgd_mix == 2)) { + pixelxfer = val; + } else { + if (dev->accel.cmd & 2) { + if (pixcnt == 16) { + if ((cmd >= 2) && (dev->accel.cmd & 0x1000)) + val = (val >> 8) | (val << 8); + } + if (and3 == 3) { + if (dev->accel.cmd & 0x1000) + goto regular_nibble; + if (val & 0x02) + nibble |= 0x10; + if (val & 0x04) + nibble |= 0x08; + if (val & 0x08) + nibble |= 0x04; + if (val & 0x10) + nibble |= 0x02; + if (val & 0x200) + nibble |= 0x01; + if (val & 0x400) + nibble |= 0x80; + if (val & 0x800) + nibble |= 0x40; + if (val & 0x1000) + nibble |= 0x20; + } else if (and3 == 2) { + if (dev->accel.cmd & 0x1000) + goto regular_nibble; + if (val & 0x02) + nibble |= 0x20; + if (val & 0x04) + nibble |= 0x10; + if (val & 0x08) + nibble |= 0x08; + if (val & 0x10) + nibble |= 0x04; + if (val & 0x200) + nibble |= 0x02; + if (val & 0x400) + nibble |= 0x01; + if (val & 0x800) + nibble |= 0x80; + if (val & 0x1000) + nibble |= 0x40; + } else if (and3 == 1) { + if (dev->accel.cmd & 0x1000) + goto regular_nibble; + if (val & 0x02) + nibble |= 0x40; + if (val & 0x04) + nibble |= 0x20; + if (val & 0x08) + nibble |= 0x10; + if (val & 0x10) + nibble |= 0x08; + if (val & 0x200) + nibble |= 0x04; + if (val & 0x400) + nibble |= 0x02; + if (val & 0x800) + nibble |= 0x01; + if (val & 0x1000) + nibble |= 0x80; + } else { +regular_nibble: + if (val & 0x02) + nibble |= 0x80; + if (val & 0x04) + nibble |= 0x40; + if (val & 0x08) + nibble |= 0x20; + if (val & 0x10) + nibble |= 0x10; + if (val & 0x200) + nibble |= 0x08; + if (val & 0x400) + nibble |= 0x04; + if (val & 0x800) + nibble |= 0x02; + if (val & 0x1000) + nibble |= 0x01; + } + + if ((and3 == 0) || (dev->accel.cmd & 0x1000) || ((dev->accel.cmd & 8) && ibm8514_cpu_src(dev))) { + if ((dev->accel.cmd & 8) && ibm8514_cpu_src(dev)) { + monoxfer = val; + } else + monoxfer = nibble; + ibm8514_accel_start(pixcnt, 1, monoxfer, pixelxfer, dev, len); + if (dev->accel.nibbleset != NULL) { + free(dev->accel.nibbleset); + dev->accel.nibbleset = NULL; + } + if (dev->accel.writemono != NULL) { + free(dev->accel.writemono); + dev->accel.writemono = NULL; + } + return; + } + + dev->accel.writemono[dev->accel.x_count] = nibble; + if (val & 0x1c00) { + if (and3 == 1) { + if (val & 0x1000) + dev->accel.nibbleset[dev->accel.x_count] = 0x80; + else + dev->accel.nibbleset[dev->accel.x_count] = 0; + } else if (and3 == 2) { + if (val & 0x1000) { + if (val & 0x800) + dev->accel.nibbleset[dev->accel.x_count] = 0xc0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0x40; + } else if (val & 0x800) { + if (val & 0x1000) + dev->accel.nibbleset[dev->accel.x_count] = 0xc0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0x80; + } else + dev->accel.nibbleset[dev->accel.x_count] = 0; + } else if (and3 == 3) { + if (val & 0x1000) { + if (val & 0x800) { + if (val & 0x400) + dev->accel.nibbleset[dev->accel.x_count] = 0xe0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0x60; + } else if (val & 0x400) { + if (val & 0x800) + dev->accel.nibbleset[dev->accel.x_count] = 0xe0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0xa0; + } else + dev->accel.nibbleset[dev->accel.x_count] = 0x20; + } else if (val & 0x800) { + if (val & 0x400) { + if (val & 0x1000) + dev->accel.nibbleset[dev->accel.x_count] = 0xe0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0xc0; + } else if (val & 0x1000) { + if (val & 0x400) + dev->accel.nibbleset[dev->accel.x_count] = 0xe0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0x60; + } else + dev->accel.nibbleset[dev->accel.x_count] = 0x40; + } else if (val & 0x400) { + if (val & 0x800) { + if (val & 0x1000) + dev->accel.nibbleset[dev->accel.x_count] = 0xe0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0xc0; + } else if (val & 0x1000) { + if (val & 0x800) + dev->accel.nibbleset[dev->accel.x_count] = 0xe0; + else + dev->accel.nibbleset[dev->accel.x_count] = 0xa0; + } else + dev->accel.nibbleset[dev->accel.x_count] = 0x80; + } else + dev->accel.nibbleset[dev->accel.x_count] = 0; + } + } else + dev->accel.nibbleset[dev->accel.x_count] = 0; + + dev->accel.x_count++; + if (dev->accel.x_count == dev->accel.sys_cnt) { + for (int i = 0; i < dev->accel.x_count; i++) { + dev->accel.writemono[i] &= ~dev->accel.nibbleset[i]; + dev->accel.writemono[i] |= dev->accel.nibbleset[i + 1]; + ibm8514_accel_start(pixcnt, 1, dev->accel.writemono[i], pixelxfer, dev, len); + } + + dev->accel.x_count = 0; + if (dev->accel.nibbleset != NULL) { + free(dev->accel.nibbleset); + dev->accel.nibbleset = NULL; + } + if (dev->accel.writemono != NULL) { + free(dev->accel.writemono); + dev->accel.writemono = NULL; + } + } + return; + } + monoxfer = val; + } + } else { + pixelxfer = val; + } + ibm8514_accel_start(pixcnt, 1, monoxfer, pixelxfer, dev, len); + } + } +} + +static void +ibm8514_accel_out_fifo(ibm8514_t *dev, uint16_t port, uint32_t val, int len) +{ + switch (port) { + case 0x82e8: + case 0xc2e8: + if (len == 1) { + dev->accel.cur_y = (dev->accel.cur_y & 0x700) | val; + } else { + dev->accel.cur_y = val & 0x7ff; + } + break; + case 0x82e9: + case 0xc2e9: + if (len == 1) { + dev->accel.cur_y = (dev->accel.cur_y & 0xff) | ((val & 0x07) << 8); + } + break; + + case 0x86e8: + case 0xc6e8: + if (len == 1) { + dev->accel.cur_x = (dev->accel.cur_x & 0x700) | val; + } else { + dev->accel.cur_x = val & 0x7ff; + } + break; + case 0x86e9: + case 0xc6e9: + if (len == 1) { + dev->accel.cur_x = (dev->accel.cur_x & 0xff) | ((val & 0x07) << 8); + } + break; + + case 0x8ae8: + case 0xcae8: + if (len == 1) + dev->accel.desty_axstp = (dev->accel.desty_axstp & 0x3f00) | val; + else { + dev->accel.desty_axstp = val & 0x3fff; + if (val & 0x2000) + dev->accel.desty_axstp |= ~0x1fff; + } + break; + case 0x8ae9: + case 0xcae9: + if (len == 1) { + dev->accel.desty_axstp = (dev->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + dev->accel.desty_axstp |= ~0x1fff; + } + break; + + case 0x8ee8: + case 0xcee8: + if (len == 1) + dev->accel.destx_distp = (dev->accel.destx_distp & 0x3f00) | val; + else { + dev->accel.destx_distp = val & 0x3fff; + if (val & 0x2000) + dev->accel.destx_distp |= ~0x1fff; + } + break; + case 0x8ee9: + case 0xcee9: + if (len == 1) { + dev->accel.destx_distp = (dev->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + dev->accel.destx_distp |= ~0x1fff; + } + break; + + case 0x92e8: + if (len != 1) + dev->test = val; + case 0xd2e8: + if (len == 1) + dev->accel.err_term = (dev->accel.err_term & 0x3f00) | val; + else { + dev->accel.err_term = val & 0x3fff; + if (val & 0x2000) + dev->accel.err_term |= ~0x1fff; + } + break; + case 0x92e9: + case 0xd2e9: + if (len == 1) { + dev->accel.err_term = (dev->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + dev->accel.err_term |= ~0x1fff; + } + break; + + case 0x96e8: + case 0xd6e8: + if (len == 1) + dev->accel.maj_axis_pcnt = (dev->accel.maj_axis_pcnt & 0x700) | val; + else { + dev->accel.maj_axis_pcnt = val & 0x7ff; + } + break; + case 0x96e9: + case 0xd6e9: + if (len == 1) { + dev->accel.maj_axis_pcnt = (dev->accel.maj_axis_pcnt & 0xff) | ((val & 0x07) << 8); + } + break; + + case 0x9ae8: + case 0xdae8: + dev->accel.ssv_state = 0; + if (len == 1) + dev->accel.cmd = (dev->accel.cmd & 0xff00) | val; + else { + dev->data_available = 0; + dev->data_available2 = 0; + dev->accel.cmd = val; + if (dev->accel.cmd & 0x100) + dev->accel.cmd_back = 0; + ibm8514_accel_start(-1, 0, -1, 0, dev, len); + } + break; + case 0x9ae9: + case 0xdae9: + if (len == 1) { + dev->data_available = 0; + dev->data_available2 = 0; + dev->accel.cmd = (dev->accel.cmd & 0xff) | (val << 8); + if (port == 0xdae9) { + if (dev->accel.cmd & 0x100) + dev->accel.cmd_back = 0; + } + ibm8514_accel_start(-1, 0, -1, 0, dev, len); + } + break; + + case 0x9ee8: + case 0xdee8: + dev->accel.ssv_state = 1; + if (len == 1) + dev->accel.short_stroke = (dev->accel.short_stroke & 0xff00) | val; + else { + dev->accel.short_stroke = val; + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + if (dev->accel.cur_x & 0x400) + dev->accel.cx |= ~0x3ff; + if (dev->accel.cur_y & 0x400) + dev->accel.cy |= ~0x3ff; + if (dev->accel.cmd & 0x1000) { + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke & 0xff, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke >> 8, len); + } else { + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke >> 8, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke & 0xff, len); + } + } + break; + case 0x9ee9: + case 0xdee9: + if (len == 1) { + dev->accel.short_stroke = (dev->accel.short_stroke & 0xff) | (val << 8); + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + if (dev->accel.cur_x & 0x400) + dev->accel.cx |= ~0x3ff; + if (dev->accel.cur_y & 0x400) + dev->accel.cy |= ~0x3ff; + + if (dev->accel.cmd & 0x1000) { + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke & 0xff, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke >> 8, len); + } else { + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke >> 8, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, dev, dev->accel.short_stroke & 0xff, len); + } + } + break; + + case 0xa2e8: + case 0xe2e8: + if (port == 0xe2e8) { + if (dev->accel.cmd_back) { + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0x00ff) | val; + else + dev->accel.bkgd_color = val; + } else { + if (ibm8514_cpu_dest(dev)) + break; + ibm8514_accel_out_pixtrans(dev, port, val, len); + } + } else { + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0x00ff) | val; + else + dev->accel.bkgd_color = val; + } + break; + case 0xa2e9: + case 0xe2e9: + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0xff00) | (val << 8); + break; + + case 0xa6e8: + case 0xe6e8: + if (port == 0xe6e8) { + if (dev->accel.cmd_back) { + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0x00ff) | val; + else + dev->accel.frgd_color = val; + } else { + if (ibm8514_cpu_dest(dev)) + break; + ibm8514_accel_out_pixtrans(dev, port, val, len); + } + } else { + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0x00ff) | val; + else + dev->accel.frgd_color = val; + } + break; + case 0xa6e9: + case 0xe6e9: + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0xff00) | (val << 8); + break; + + case 0xaae8: + case 0xeae8: + if (len == 1) + dev->accel.wrt_mask = (dev->accel.wrt_mask & 0x00ff) | val; + else + dev->accel.wrt_mask = val; + break; + case 0xaae9: + case 0xeae9: + if (len == 1) + dev->accel.wrt_mask = (dev->accel.wrt_mask & 0xff00) | (val << 8); + break; + + case 0xaee8: + case 0xeee8: + if (len == 1) + dev->accel.rd_mask = (dev->accel.rd_mask & 0x00ff) | val; + else + dev->accel.rd_mask = val; + break; + case 0xaee9: + case 0xeee9: + if (len == 1) + dev->accel.rd_mask = (dev->accel.rd_mask & 0xff00) | (val << 8); + break; + + case 0xb2e8: + case 0xf2e8: + if (len == 1) + dev->accel.color_cmp = (dev->accel.color_cmp & 0x00ff) | val; + else + dev->accel.color_cmp = val; + break; + case 0xb2e9: + case 0xf2e9: + if (len == 1) + dev->accel.color_cmp = (dev->accel.color_cmp & 0xff00) | (val << 8); + break; + + case 0xb6e8: + case 0xf6e8: + dev->accel.bkgd_mix = val & 0xff; + break; + + case 0xbae8: + case 0xfae8: + dev->accel.frgd_mix = val & 0xff; + break; + + case 0xbee8: + case 0xfee8: + if (len == 1) + dev->accel.multifunc_cntl = (dev->accel.multifunc_cntl & 0xff00) | val; + else { + dev->accel.multifunc_cntl = val; + dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; + if ((dev->accel.multifunc_cntl >> 12) == 1) { + dev->accel.clip_top = val & 0x3ff; + } + if ((dev->accel.multifunc_cntl >> 12) == 2) { + dev->accel.clip_left = val & 0x3ff; + } + if (port == 0xfee8) + dev->accel.cmd_back = 1; + else + dev->accel.cmd_back = 0; + } + break; + case 0xbee9: + case 0xfee9: + if (len == 1) { + dev->accel.multifunc_cntl = (dev->accel.multifunc_cntl & 0xff) | (val << 8); + dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; + if (port == 0xfee9) + dev->accel.cmd_back = 1; + else + dev->accel.cmd_back = 0; + } + break; + } +} + +static void +ibm8514_ramdac_out(uint16_t port, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + switch (port) { + case 0x2ea: + svga_out(0x3c6, val, svga); + break; + case 0x2eb: + svga_out(0x3c7, val, svga); + break; + case 0x2ec: + svga_out(0x3c8, val, svga); + break; + case 0x2ed: + svga_out(0x3c9, val, svga); + break; + } +} + +static uint8_t +ibm8514_ramdac_in(uint16_t port, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t ret = 0xff; + + switch (port) { + case 0x2ea: + ret = svga_in(0x3c6, svga); + break; + case 0x2eb: + ret = svga_in(0x3c7, svga); + break; + case 0x2ec: + ret = svga_in(0x3c8, svga); + break; + case 0x2ed: + ret = svga_in(0x3c9, svga); + break; + + } + return ret; +} + +static void +ibm8514_io_set(svga_t *svga) +{ + io_sethandler(0x2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x2ea, 0x0004, ibm8514_ramdac_in, NULL, NULL, ibm8514_ramdac_out, NULL, NULL, svga); + io_sethandler(0x6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x12e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x16e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x1ae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x1ee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x22e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x26e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x2ee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x42e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x4ae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x52e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x56e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x5ae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x5ee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x82e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x86e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x8ae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x8ee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x92e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x96e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x9ae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0x9ee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xa2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xa6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xaae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xaee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xb2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xb6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xbae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xbee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xe2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + + io_sethandler(0xc2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xc6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xcae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xcee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xd2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xd6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xdae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xdee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xe6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xeae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xeee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xf2e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xf6e8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xfae8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); + io_sethandler(0xfee8, 0x0002, ibm8514_accel_inb, ibm8514_accel_inw, NULL, ibm8514_accel_outb, ibm8514_accel_outw, NULL, svga); +} + +static void +ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) +{ + ibm8514_t *dev = &svga->dev8514; + + if (port & 0x8000) { + ibm8514_accel_out_fifo(dev, port, val, len); + } else { + switch (port) { + case 0x2e8: + if (len == 1) + dev->htotal = (dev->htotal & 0xff00) | val; + else { + dev->htotal = val; + svga_recalctimings(svga); + } + break; + case 0x2e9: + if (len != 1) { + dev->htotal = (dev->htotal & 0xff) | (val << 8); + //pclog("IBM 8514/A: H_TOTAL write 02E8 = %d\n", dev->htotal + 1); + svga_recalctimings(svga); + } + break; + + case 0x6e8: + dev->hdisp = val; + //pclog("IBM 8514/A: H_DISP write 06E8 = %d\n", dev->hdisp + 1); + svga_recalctimings(svga); + break; + + case 0xae8: + //pclog("IBM 8514/A: H_SYNC_STRT write 0AE8 = %d\n", val + 1); + svga_recalctimings(svga); + break; + + case 0xee8: + //pclog("IBM 8514/A: H_SYNC_WID write 0EE8 = %d\n", val + 1); + svga_recalctimings(svga); + break; + + case 0x12e8: + if (len == 1) + dev->vtotal = (dev->vtotal & 0x1f00) | val; + else { + dev->vtotal = val & 0x1fff; + svga_recalctimings(svga); + } + break; + case 0x12e9: + if (len == 1) { + dev->vtotal = (dev->vtotal & 0xff) | ((val & 0x1f) << 8); + //pclog("IBM 8514/A: V_TOTAL write 12E8 = %d\n", dev->vtotal); + svga_recalctimings(svga); + } + break; + + case 0x16e8: + if (len == 1) + dev->vdisp = (dev->vdisp & 0x1f00) | val; + else { + dev->vdisp = val & 0x1fff; + svga_recalctimings(svga); + } + break; + case 0x16e9: + if (len == 1) { + dev->vdisp = (dev->vdisp & 0xff) | ((val & 0x1f) << 8); + //pclog("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->vdisp); + svga_recalctimings(svga); + } + break; + + case 0x1ae8: + if (len == 1) + dev->vsyncstart = (dev->vsyncstart & 0x1f00) | val; + else { + dev->vsyncstart = val & 0x1fff; + svga_recalctimings(svga); + } + break; + case 0x1ae9: + if (len == 1) { + dev->vsyncstart = (dev->vsyncstart & 0xff) | ((val & 0x1f) << 8); + //pclog("IBM 8514/A: V_SYNC_STRT write 1AE8 = %d\n", dev->vsyncstart); + svga_recalctimings(svga); + } + break; + + case 0x1ee8: + dev->vsyncwidth = val; + //pclog("IBM 8514/A: V_SYNC_WID write 1EE8 = %02x\n", val); + svga_recalctimings(svga); + break; + + case 0x22e8: + dev->disp_cntl = val & 0x7e; + dev->interlace = !!(val & 0x10); + //pclog("IBM 8514/A: DISP_CNTL write 22E8 = %02x, SCANMODULOS = %d\n", dev->disp_cntl, dev->scanmodulos); + svga_recalctimings(svga); + break; + + case 0x42e8: + if (len == 1) { + dev->subsys_stat &= ~val; + } else { + dev->subsys_stat &= ~(val & 0xff); + dev->subsys_cntl = (val >> 8); + } + break; + case 0x42e9: + if (len == 1) { + dev->subsys_cntl = val; + } + break; + + case 0x4ae8: + dev->accel.advfunc_cntl = val & 7; + vga_on = ((dev->accel.advfunc_cntl & 1) == 0) ? 1 : 0; + ibm8514_on = !vga_on; + //pclog("IBM 8514/A: VGA ON = %i, val = %02x\n", vga_on, val); + svga_recalctimings(svga); + break; + } + } +} + +static void +ibm8514_accel_outb(uint16_t port, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + ibm8514_accel_out(port, val, svga, 1); +} + +static void +ibm8514_accel_outw(uint16_t port, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + ibm8514_accel_out(port, val, svga, 2); +} + +static uint32_t +ibm8514_accel_in(uint16_t port, svga_t *svga, int len) +{ + ibm8514_t *dev = &svga->dev8514; + uint32_t temp = 0; + int cmd; + + switch (port) { + case 0x6e8: + temp = dev->hdisp; + break; + + case 0x22e8: + temp = dev->disp_cntl; + break; + + case 0x26e8: + if (len == 1) + temp = dev->htotal & 0xff; + else + temp = dev->htotal; + break; + case 0x26e9: + if (len == 1) + temp = dev->htotal >> 8; + break; + + case 0x2ee8: + temp = dev->subsys_cntl; + break; + + case 0x42e8: + if (len != 1) { + temp = dev->subsys_stat | 0xa0 | 0x8000; + } else + temp = dev->subsys_stat | 0xa0; + break; + + case 0x42e9: + if (len == 1) + temp |= 0x80; + break; + + case 0x92e8: + if (len != 1) { + temp = dev->test; + } + break; + + case 0x9ae8: + case 0xdae8: + temp = 0; + if (len != 1) { + if (dev->force_busy) + temp |= 0x200; /*Hardware busy*/ + dev->force_busy = 0; + if (dev->data_available) { + temp |= 0x100; /*Read Data available*/ + dev->data_available = 0; + } + } + break; + case 0x9ae9: + case 0xdae9: + temp = 0; + if (len == 1) { + if (dev->force_busy2) + temp |= 2; /*Hardware busy*/ + dev->force_busy2 = 0; + if (dev->data_available2) { + temp |= 1; /*Read Data available*/ + dev->data_available2 = 0; + } + } + break; + + case 0xe2e8: + case 0xe6e8: + if (ibm8514_cpu_dest(dev)) { + if (len == 1) { + ;//READ_PIXTRANS_BYTE_IO(0) + } else { + cmd = (dev->accel.cmd >> 13); + READ_PIXTRANS_WORD(dev->accel.cx, 0) + if (dev->accel.input && !dev->accel.odd_in && !dev->accel.sx) { + temp &= ~0xff00; + temp |= (dev->vram[(dev->accel.newdest_in + dev->accel.cur_x) & dev->vram_mask] << 8); + } + } + ibm8514_accel_out_pixtrans(dev, port, temp, len); + } + break; + case 0xe2e9: + case 0xe6e9: + if (ibm8514_cpu_dest(dev)) { + if (len == 1) { + ;//READ_PIXTRANS_BYTE_IO(1) + ibm8514_accel_out_pixtrans(dev, port, temp, len); + } + } + break; + } + return temp; +} + + +static uint8_t +ibm8514_accel_inb(uint16_t port, void *p) +{ + svga_t *svga = (svga_t *)p; + return ibm8514_accel_in(port, svga, 1); +} + +static uint16_t +ibm8514_accel_inw(uint16_t port, void *p) +{ + svga_t *svga = (svga_t *)p; + return ibm8514_accel_in(port, svga, 2); +} + + +static void +ibm8514_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, ibm8514_t *dev, uint8_t ssv, int len) +{ + if (!cpu_input) { + dev->accel.ssv_len = ssv & 0x0f; + dev->accel.ssv_dir = ssv & 0xe0; + dev->accel.ssv_draw = ssv & 0x10; + + if (ibm8514_cpu_src(dev)) { + return; /*Wait for data from CPU*/ + } + } + + ibm8514_accel_start(count, cpu_input, mix_dat, cpu_dat, dev, len); +} + +static void +ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, ibm8514_t *dev, int len) +{ + uint8_t src_dat = 0, dest_dat, old_dest_dat; + int frgd_mix, bkgd_mix; + uint16_t clip_b = dev->accel.multifunc[3] & 0x7ff; + uint16_t clip_r = dev->accel.multifunc[4] & 0x7ff; + int pixcntl = (dev->accel.multifunc[0x0a] >> 6) & 3; + uint8_t mix_mask = 0x80; + uint8_t compare = dev->accel.color_cmp & 0xff; + int compare_mode = dev->accel.multifunc[0x0a] & 0x38; + int cmd = dev->accel.cmd >> 13; + uint8_t wrt_mask = dev->accel.wrt_mask & 0xff; + uint8_t rd_mask = ((dev->accel.rd_mask & 0x01) << 7) | ((dev->accel.rd_mask & 0xfe) >> 1); + uint8_t rd_mask_polygon = dev->accel.rd_mask & 0xff; + uint8_t frgd_color = dev->accel.frgd_color; + uint8_t bkgd_color = dev->accel.bkgd_color; + uint32_t old_mix_dat; + int and3 = dev->accel.cur_x & 3; + uint8_t poly_src = 0; + + if (dev->accel.cmd & 0x100) { + dev->force_busy = 1; + dev->force_busy2 = 1; + } + + frgd_mix = (dev->accel.frgd_mix >> 5) & 3; + bkgd_mix = (dev->accel.bkgd_mix >> 5) & 3; + + if (cpu_input) { + if ((dev->accel.cmd & 2) || (pixcntl == 2)) { + if ((frgd_mix == 2) || (bkgd_mix == 2)) { + count >>= 3; + } else if (pixcntl == 2) { + if (dev->accel.cmd & 2) { + count >>= 1; + } else + count >>= 3; + } + } else { + count >>= 3; + } + } + + if (pixcntl == 1) { + mix_dat = 0; + if (and3 == 3) { + if (dev->accel.multifunc[8] & 0x02) + mix_dat |= 0x10; + if (dev->accel.multifunc[8] & 0x04) + mix_dat |= 0x08; + if (dev->accel.multifunc[8] & 0x08) + mix_dat |= 0x04; + if (dev->accel.multifunc[8] & 0x10) + mix_dat |= 0x02; + if (dev->accel.multifunc[9] & 0x02) + mix_dat |= 0x01; + if (dev->accel.multifunc[9] & 0x04) + mix_dat |= 0x80; + if (dev->accel.multifunc[9] & 0x08) + mix_dat |= 0x40; + if (dev->accel.multifunc[9] & 0x10) + mix_dat |= 0x20; + } + if (and3 == 2) { + if (dev->accel.multifunc[8] & 0x02) + mix_dat |= 0x20; + if (dev->accel.multifunc[8] & 0x04) + mix_dat |= 0x10; + if (dev->accel.multifunc[8] & 0x08) + mix_dat |= 0x08; + if (dev->accel.multifunc[8] & 0x10) + mix_dat |= 0x04; + if (dev->accel.multifunc[9] & 0x02) + mix_dat |= 0x02; + if (dev->accel.multifunc[9] & 0x04) + mix_dat |= 0x01; + if (dev->accel.multifunc[9] & 0x08) + mix_dat |= 0x80; + if (dev->accel.multifunc[9] & 0x10) + mix_dat |= 0x40; + } + if (and3 == 1) { + if (dev->accel.multifunc[8] & 0x02) + mix_dat |= 0x40; + if (dev->accel.multifunc[8] & 0x04) + mix_dat |= 0x20; + if (dev->accel.multifunc[8] & 0x08) + mix_dat |= 0x10; + if (dev->accel.multifunc[8] & 0x10) + mix_dat |= 0x08; + if (dev->accel.multifunc[9] & 0x02) + mix_dat |= 0x04; + if (dev->accel.multifunc[9] & 0x04) + mix_dat |= 0x02; + if (dev->accel.multifunc[9] & 0x08) + mix_dat |= 0x01; + if (dev->accel.multifunc[9] & 0x10) + mix_dat |= 0x80; + } + if (and3 == 0) { + if (dev->accel.multifunc[8] & 0x02) + mix_dat |= 0x80; + if (dev->accel.multifunc[8] & 0x04) + mix_dat |= 0x40; + if (dev->accel.multifunc[8] & 0x08) + mix_dat |= 0x20; + if (dev->accel.multifunc[8] & 0x10) + mix_dat |= 0x10; + if (dev->accel.multifunc[9] & 0x02) + mix_dat |= 0x08; + if (dev->accel.multifunc[9] & 0x04) + mix_dat |= 0x04; + if (dev->accel.multifunc[9] & 0x08) + mix_dat |= 0x02; + if (dev->accel.multifunc[9] & 0x10) + mix_dat |= 0x01; + } + } + + old_mix_dat = mix_dat; + + /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. + When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on + the NOP command)*/ + switch (cmd) { + case 0: /*NOP (Short Stroke Vectors)*/ + if (dev->accel.ssv_state == 0) + break; + + if (dev->accel.cmd & 8) { + while (count-- && dev->accel.ssv_len >= 0) { + if (dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + MIX(mix_dat & mix_mask, dest_dat, src_dat); + + if (dev->accel.ssv_draw) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (!dev->accel.ssv_len) + break; + + switch (dev->accel.ssv_dir & 0xe0) { + case 0x00: dev->accel.cx++; break; + case 0x20: dev->accel.cx++; dev->accel.cy--; break; + case 0x40: dev->accel.cy--; break; + case 0x60: dev->accel.cx--; dev->accel.cy--; break; + case 0x80: dev->accel.cx--; break; + case 0xa0: dev->accel.cx--; dev->accel.cy++; break; + case 0xc0: dev->accel.cy++; break; + case 0xe0: dev->accel.cx++; dev->accel.cy++; break; + } + + dev->accel.ssv_len--; + } + + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + } + break; + + case 1: /*Draw line*/ + if (!cpu_input) { + dev->accel.xx_count = 0; + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + + if (dev->accel.cur_x & 0x400) { + dev->accel.cx |= ~0x3ff; + } + if (dev->accel.cur_y & 0x400) { + dev->accel.cy |= ~0x3ff; + } + + dev->accel.sy = dev->accel.maj_axis_pcnt; + + if (ibm8514_cpu_src(dev)) { + if (dev->accel.cmd & 2) { + if (dev->accel.cmd & 8) { + if (and3 == 1) { + dev->accel.sy += 4; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 4; + else + dev->accel.cx -= 4; + } else if (and3 == 2) { + dev->accel.sy += 5; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 5; + else + dev->accel.cx -= 5; + } else if (and3 == 3) { + dev->accel.sy += 6; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 6; + else + dev->accel.cx -= 6; + } else { + dev->accel.sy += 3; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 3; + else + dev->accel.cx -= 3; + } + } + } + dev->data_available = 0; + dev->data_available2 = 0; + return; /*Wait for data from CPU*/ + } else if (ibm8514_cpu_dest(dev)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; + } + } + + if (dev->accel.cmd & 8) { /*Vector Line*/ + if (ibm8514_cpu_dest(dev) && cpu_input && (dev->accel.cmd & 2)) + count >>= 1; + dev->accel.xx_count++; + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + if (ibm8514_cpu_dest(dev) && (pixcntl == 0)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + } else if (ibm8514_cpu_dest(dev) && (pixcntl == 3)) { + /* Mix data = current video memory value. */ + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (ibm8514_cpu_dest(dev)) { + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, src_dat); + if (pixcntl == 3) + src_dat = ((src_dat & rd_mask) == rd_mask); + } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if ((dev->accel.cmd & 2) && ibm8514_cpu_src(dev)) { + if (and3 == 1) { + if (dev->accel.xx_count >= 2) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } else if (and3 == 2) { + if (dev->accel.xx_count == 2) { + if (count <= 2) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } else if (dev->accel.xx_count >= 3) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } else if (and3 == 3) { + if (dev->accel.xx_count == 2) { + if (count <= 1) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } else if (dev->accel.xx_count >= 3) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } else { + if (dev->accel.xx_count == 1) { + if (!count) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } else if (dev->accel.xx_count >= 2) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } + } else { + if (ibm8514_cpu_src(dev) || !cpu_input) { + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.sy == 0) { + break; + } + + switch (dev->accel.cmd & 0xe0) { + case 0x00: dev->accel.cx++; break; + case 0x20: dev->accel.cx++; dev->accel.cy--; break; + case 0x40: dev->accel.cy--; break; + case 0x60: dev->accel.cx--; dev->accel.cy--; break; + case 0x80: dev->accel.cx--; break; + case 0xa0: dev->accel.cx--; dev->accel.cy++; break; + case 0xc0: dev->accel.cy++; break; + case 0xe0: dev->accel.cx++; dev->accel.cy++; break; + } + + dev->accel.sy--; + } + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + } else { /*Bresenham*/ + if (pixcntl == 1) { + dev->accel.temp_cnt = 8; + while (count-- && (dev->accel.sy >= 0)) { + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat = old_mix_dat; + } + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + if (ibm8514_cpu_dest(dev)) { + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, src_dat); + } else switch ((mix_dat & 1) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & 1, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } + + dev->accel.temp_cnt--; + mix_dat >>= 1; + cpu_dat >>= 8; + + if (dev->accel.sy == 0) { + break; + } + + if (dev->accel.err_term >= dev->accel.maj_axis_pcnt) { + dev->accel.err_term += dev->accel.destx_distp; + /*Step minor axis*/ + switch (dev->accel.cmd & 0xe0) { + case 0x00: dev->accel.cy--; break; + case 0x20: dev->accel.cy--; break; + case 0x40: dev->accel.cx--; break; + case 0x60: dev->accel.cx++; break; + case 0x80: dev->accel.cy++; break; + case 0xa0: dev->accel.cy++; break; + case 0xc0: dev->accel.cx--; break; + case 0xe0: dev->accel.cx++; break; + } + } else + dev->accel.err_term += dev->accel.desty_axstp; + + /*Step major axis*/ + switch (dev->accel.cmd & 0xe0) { + case 0x00: dev->accel.cx--; break; + case 0x20: dev->accel.cx++; break; + case 0x40: dev->accel.cy--; break; + case 0x60: dev->accel.cy--; break; + case 0x80: dev->accel.cx--; break; + case 0xa0: dev->accel.cx++; break; + case 0xc0: dev->accel.cy++; break; + case 0xe0: dev->accel.cy++; break; + } + + dev->accel.sy--; + } + } else { + while (count-- && (dev->accel.sy >= 0)) { + if (((dev->accel.cx) >= dev->accel.clip_left && (dev->accel.cx) <= clip_r && + (dev->accel.cy) >= dev->accel.clip_top && (dev->accel.cy) <= clip_b)) { + if (ibm8514_cpu_dest(dev) && (pixcntl == 0)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + } else if (ibm8514_cpu_dest(dev) && (pixcntl == 3)) { + /* Mix data = current video memory value. */ + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (ibm8514_cpu_dest(dev)) { + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, src_dat); + if (pixcntl == 3) + src_dat = ((src_dat & rd_mask) == rd_mask); + } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if ((dev->accel.cmd & 4) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.sy == 0) { + break; + } + + if (dev->accel.err_term >= dev->accel.maj_axis_pcnt) { + dev->accel.err_term += dev->accel.destx_distp; + /*Step minor axis*/ + switch (dev->accel.cmd & 0xe0) { + case 0x00: dev->accel.cy--; break; + case 0x20: dev->accel.cy--; break; + case 0x40: dev->accel.cx--; break; + case 0x60: dev->accel.cx++; break; + case 0x80: dev->accel.cy++; break; + case 0xa0: dev->accel.cy++; break; + case 0xc0: dev->accel.cx--; break; + case 0xe0: dev->accel.cx++; break; + } + } else + dev->accel.err_term += dev->accel.desty_axstp; + + /*Step major axis*/ + switch (dev->accel.cmd & 0xe0) { + case 0x00: dev->accel.cx--; break; + case 0x20: dev->accel.cx++; break; + case 0x40: dev->accel.cy--; break; + case 0x60: dev->accel.cy--; break; + case 0x80: dev->accel.cx--; break; + case 0xa0: dev->accel.cx++; break; + case 0xc0: dev->accel.cy++; break; + case 0xe0: dev->accel.cy++; break; + } + + dev->accel.sy--; + } + } + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + } + break; + + case 2: /*Rectangle fill (X direction)*/ + case 3: /*Rectangle fill (Y direction)*/ + case 4: /*Rectangle fill (Y direction using nibbles)*/ + if (!cpu_input) { + dev->accel.x_count = 0; + dev->accel.xx_count = 0; + dev->accel.odd_out = 0; + dev->accel.odd_in = 0; + dev->accel.input = 0; + dev->accel.output = 0; + dev->accel.newdest_out = 0; + dev->accel.newdest_in = 0; + + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; + + dev->accel.cx = dev->accel.cur_x & 0x3ff; + if (dev->accel.cur_x & 0x400) + dev->accel.cx |= ~0x3ff; + dev->accel.cy = dev->accel.cur_y & 0x3ff; + if (dev->accel.cur_y & 0x400) + dev->accel.cy |= ~0x3ff; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.fill_state = 0; + + if (cmd == 4) + dev->accel.cmd |= 2; + else if (cmd == 3) + dev->accel.cmd &= ~2; + + if (ibm8514_cpu_src(dev)) { + if (dev->accel.cmd & 2) { + if (!(dev->accel.cmd & 0x1000)) { + if (!(dev->accel.cmd & 8)) { + dev->accel.sx += and3; + dev->accel.nibbleset = (uint8_t *)calloc(1, (dev->accel.sx >> 3) + 1); + dev->accel.writemono = (uint8_t *)calloc(1, (dev->accel.sx >> 3) + 1); + dev->accel.sys_cnt = (dev->accel.sx >> 3) + 1; + } else { + if (and3 == 1) { + dev->accel.sx += 4; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 4; + else + dev->accel.cx -= 4; + } else if (and3 == 2) { + dev->accel.sx += 5; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 5; + else + dev->accel.cx -= 5; + } else if (and3 == 3) { + dev->accel.sx += 6; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 6; + else + dev->accel.cx -= 6; + } else { + dev->accel.sx += 3; + if (dev->accel.cmd & 0x20) + dev->accel.cx += 3; + else + dev->accel.cx -= 3; + } + } + } + } else { + if (!(dev->accel.cmd & 0x40) && (frgd_mix == 2) && (bkgd_mix == 2) && (pixcntl == 0) && (cmd == 2)) { + if (!(dev->accel.sx & 1)) { + dev->accel.output = 1; + dev->accel.newdest_out = (dev->accel.cy + 1) * dev->h_disp; + } + } + } + dev->data_available = 0; + dev->data_available2 = 0; + return; /*Wait for data from CPU*/ + } else if (ibm8514_cpu_dest(dev)) { + if (!(dev->accel.cmd & 2) && (frgd_mix == 2) && (pixcntl == 0) && (cmd == 2)) { + if (!(dev->accel.sx & 1)) { + dev->accel.input = 1; + dev->accel.newdest_in = (dev->accel.cy + 1) * dev->h_disp; + } + } else if (dev->accel.cmd & 2) { + if (dev->accel.cmd & 8) { + dev->accel.sx += and3; + dev->accel.nibbleset = (uint8_t *)calloc(1, (dev->accel.sx >> 3) + 1); + dev->accel.writemono = (uint8_t *)calloc(1, (dev->accel.sx >> 3) + 1); + dev->accel.sys_cnt = (dev->accel.sx >> 3) + 1; + } + } + dev->data_available = 1; + dev->data_available2 = 1; + return; /*Wait for data from CPU*/ + } + } + + if (dev->accel.cmd & 2) { + if (cpu_input) { +rect_fill_pix: + if ((dev->accel.cmd & 8) && ibm8514_cpu_src(dev)) { + dev->accel.xx_count++; + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if (and3 == 1) { + if (dev->accel.xx_count >= 2) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } else if (and3 == 2) { + if (dev->accel.xx_count == 2) { + if (count <= 2) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } else if (dev->accel.xx_count >= 3) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } else if (and3 == 3) { + if (dev->accel.xx_count == 2) { + if (count <= 1) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } else if (dev->accel.xx_count >= 3) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } else { + if (dev->accel.xx_count == 1) { + if (!count) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } else if (dev->accel.xx_count >= 2) { + if ((dev->accel.cmd & 4) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + switch (dev->accel.cmd & 0xe0) { + case 0x00: dev->accel.cx++; break; + case 0x20: dev->accel.cx++; break; + case 0x60: dev->accel.cx--; break; + case 0x80: dev->accel.cx--; break; + case 0xa0: dev->accel.cx--; break; + case 0xe0: dev->accel.cx++; break; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + if (and3 == 1) { + dev->accel.sx += 4; + } else if (and3 == 2) { + dev->accel.sx += 5; + } else if (and3 == 3) { + dev->accel.sx += 6; + } else { + dev->accel.sx += 3; + } + + if (dev->accel.cmd & 0x20) + dev->accel.cx -= (dev->accel.sx + 1); + else + dev->accel.cx += (dev->accel.sx + 1); + + switch (dev->accel.cmd & 0xe0) { + case 0x20: dev->accel.cy--; break; + case 0x40: dev->accel.cy--; break; + case 0x60: dev->accel.cy--; break; + case 0xa0: dev->accel.cy++; break; + case 0xc0: dev->accel.cy++; break; + case 0xe0: dev->accel.cy++; break; + } + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + break; + } + if (count < 8) { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + if (ibm8514_cpu_dest(dev) && (pixcntl == 0)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + } else if (ibm8514_cpu_dest(dev) && (pixcntl == 3)) { + /* Mix data = current video memory value. */ + READ(dev->accel.dest + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (ibm8514_cpu_dest(dev)) { + READ(dev->accel.dest + dev->accel.cx, src_dat); + if (pixcntl == 3) + src_dat = ((src_dat & rd_mask) == rd_mask); + } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 2) { + dev->accel.sx += (dev->accel.cur_x & 3); + } + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } else { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + if (ibm8514_cpu_dest(dev) && (pixcntl == 0)) { + mix_dat = 1; /* Mix data = forced to foreground register. */ + } else if (ibm8514_cpu_dest(dev) && (pixcntl == 3)) { + /* Mix data = current video memory value. */ + READ(dev->accel.dest + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? 1 : 0; + } + + if (ibm8514_cpu_dest(dev)) { + READ(dev->accel.dest + dev->accel.cx, src_dat); + if (pixcntl == 3) + src_dat = ((src_dat & rd_mask) == rd_mask); + } else { + switch ((mix_dat & 1) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & 1, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + mix_dat >>= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 2) { + if (!(dev->accel.cmd & 0x1000)) + dev->accel.sx += (dev->accel.cur_x & 3); + } + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 2) { + if (dev->accel.cmd & 0x1000) { + dev->accel.cx = dev->accel.cur_x & 0x3ff; + if (dev->accel.cur_x & 0x400) + dev->accel.cx |= ~0x3ff; + } + } + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } + } else { + goto rect_fill; + } + } else { + if (cpu_input) { + if (pixcntl == 2) { + goto rect_fill_pix; + } else { + if (dev->accel.input && !dev->accel.output) { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + if (!dev->accel.odd_in && !dev->accel.sx) { + READ(dev->accel.newdest_in + dev->accel.cur_x, src_dat); + READ(dev->accel.newdest_in + dev->accel.cur_x, dest_dat); + } else { + READ(dev->accel.dest + dev->accel.cx, src_dat); + READ(dev->accel.dest + dev->accel.cx, dest_dat); + } + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if (!dev->accel.odd_in && !dev->accel.sx) { + WRITE(dev->accel.newdest_in + dev->accel.cur_x, dest_dat); + } else { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } + mix_dat <<= 1; + mix_dat |= 1; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.odd_in) { + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.odd_in = 0; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.newdest_in = (dev->accel.cy + 1) * dev->h_disp; + dev->accel.sy--; + return; + } + } else { + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.sx--; + dev->accel.cx = dev->accel.cur_x; + dev->accel.odd_in = 1; + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.newdest_in = (dev->accel.cy + 1) * dev->h_disp; + dev->accel.sy--; + return; + } + } + } + } else if (dev->accel.output && !dev->accel.input) { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + src_dat = cpu_dat; + if (!dev->accel.odd_out && !dev->accel.sx) { + READ(dev->accel.newdest_out + dev->accel.cur_x, dest_dat); + } else { + READ(dev->accel.dest + dev->accel.cx, dest_dat); + } + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if (!dev->accel.odd_out && !dev->accel.sx) { + WRITE(dev->accel.newdest_out + dev->accel.cur_x, dest_dat); + } else { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.odd_out) { + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.odd_out = 0; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.newdest_out = (dev->accel.cy + 1) * dev->h_disp; + dev->accel.sy--; + return; + } + } else { + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.odd_out = 1; + dev->accel.sx--; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.newdest_out = (dev->accel.cy + 1) * dev->h_disp; + dev->accel.sy--; + return; + } + } + } + } else { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + if (ibm8514_cpu_dest(dev) && (pixcntl == 0)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + } else if (ibm8514_cpu_dest(dev) && (pixcntl == 3)) { + /* Mix data = current video memory value. */ + READ(dev->accel.dest + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (ibm8514_cpu_dest(dev)) { + READ(dev->accel.dest + dev->accel.cx, src_dat); + if (pixcntl == 3) { + src_dat = ((src_dat & rd_mask) == rd_mask); + } + } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + if (ibm8514_cpu_dest(dev)) { + if (pixcntl == 3) { + MIX(mix_dat & mix_mask, dest_dat, src_dat); + } + } else { + MIX(mix_dat & mix_mask, dest_dat, src_dat); + } + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } + } + } else { +rect_fill: + if (pixcntl == 1) { + if (dev->accel.cmd & 0x40) { + count = dev->accel.maj_axis_pcnt + 1; + dev->accel.temp_cnt = 8; + while (count-- && dev->accel.sy >= 0) { + if (dev->accel.temp_cnt == 0) { + mix_dat >>= 8; + dev->accel.temp_cnt = 8; + } + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + + if (dev->accel.temp_cnt > 0) { + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + return; + } + } + } else { + dev->accel.temp_cnt = 8; + while (count-- && dev->accel.sy >= 0) { + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat = old_mix_dat; + } + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + switch ((mix_dat & 1) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & 1, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + + dev->accel.temp_cnt--; + mix_dat >>= 1; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + + if (dev->accel.sy < 0) { + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + return; + } + } + } + } + } else { + if (dev->accel.multifunc[0x0a] & 6) { + while (count-- && dev->accel.sy >= 0) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, poly_src); + if (dev->accel.multifunc[0x0a] & 2) { + poly_src = ((poly_src & wrt_mask) == wrt_mask); + } else { + poly_src = ((poly_src & rd_mask_polygon) == rd_mask_polygon); + } + + if (poly_src) { + dev->accel.fill_state = !dev->accel.fill_state; + } + + if (dev->accel.fill_state) { + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + + if (dev->accel.cmd & 0x20) { + dev->accel.cx++; + } else { + dev->accel.cx--; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.fill_state = 0; + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else { + dev->accel.cx += (dev->accel.sx) + 1; + } + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + + if (dev->accel.sy < 0) { + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + return; + } + } + } + } else { + while (count-- && dev->accel.sy >= 0) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && + dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: src_dat = 0; break; + } + + READ(dev->accel.dest + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + + if (dev->accel.sy < 0) { + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + return; + } + } + } + } + } + } + } + break; + + case 5: /*Draw Polygon Boundary Line*/ + if (!cpu_input) { + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + dev->accel.oldcy = dev->accel.cy; + + dev->accel.xdir = (dev->accel.cmd & 0x20) ? 1 : -1; + dev->accel.ydir = (dev->accel.cmd & 0x80) ? 1 : -1; + + dev->accel.sy = 0; + + if (ibm8514_cpu_src(dev)) { + dev->data_available = 0; + dev->data_available2 = 0; + return; /*Wait for data from CPU*/ + } else if (ibm8514_cpu_dest(dev)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; + } + } + + while (count-- && (dev->accel.sy >= 0)) { + if (((dev->accel.cx) >= dev->accel.clip_left && (dev->accel.cx <= clip_r) && + (dev->accel.cy) >= dev->accel.clip_top && (dev->accel.cy) <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: src_dat = 0; break; + } + + READ((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if ((dev->accel.cmd & 4) && (dev->accel.sy < dev->accel.maj_axis_pcnt)) { + if (!dev->accel.sy) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if ((dev->accel.cmd & 0x40) && dev->accel.sy && (dev->accel.cy == dev->accel.oldcy + 1)) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x40) && dev->accel.sy && (dev->accel.err_term >= 0) && (dev->accel.cy == (dev->accel.oldcy + 1))) { + WRITE((dev->accel.cy * dev->h_disp) + dev->accel.cx, dest_dat); + } + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.sy == dev->accel.maj_axis_pcnt) { + return; + } + + if (dev->accel.cmd & 0x40) { + dev->accel.oldcy = dev->accel.cy; + dev->accel.cy += dev->accel.ydir; + if (dev->accel.err_term >= 0) { + dev->accel.err_term += dev->accel.destx_distp; + dev->accel.cx += dev->accel.xdir; + } else { + dev->accel.err_term += dev->accel.desty_axstp; + } + } else { + dev->accel.cx += dev->accel.xdir; + if (dev->accel.err_term >= 0) { + dev->accel.err_term += dev->accel.destx_distp; + dev->accel.oldcy = dev->accel.cy; + dev->accel.cy += dev->accel.ydir; + } else { + dev->accel.err_term += dev->accel.desty_axstp; + } + } + + dev->accel.sy++; + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + dev->accel.x_count = 0; + dev->accel.output = 0; + + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; + + dev->accel.dx = dev->accel.destx_distp & 0x3ff; + dev->accel.dy = dev->accel.desty_axstp & 0x3ff; + + if (dev->accel.destx_distp & 0x400) + dev->accel.dx |= ~0x3ff; + if (dev->accel.desty_axstp & 0x400) + dev->accel.dy |= ~0x3ff; + + dev->accel.cx = dev->accel.cur_x & 0x3ff; + dev->accel.cy = dev->accel.cur_y & 0x3ff; + + if (dev->accel.cur_x & 0x400) + dev->accel.cx |= ~0x3ff; + if (dev->accel.cur_y & 0x400) + dev->accel.cy |= ~0x3ff; + + dev->accel.src = dev->accel.cy * dev->h_disp; + dev->accel.dest = dev->accel.dy * dev->h_disp; + + if (ibm8514_cpu_src(dev)) { + if (dev->accel.cmd & 2) { + if (!(dev->accel.cmd & 0x1000)) { + dev->accel.sx += (dev->accel.cur_x & 3); + dev->accel.nibbleset = (uint8_t *)calloc(1, (dev->accel.sx >> 3) + 1); + dev->accel.writemono = (uint8_t *)calloc(1, (dev->accel.sx >> 3) + 1); + dev->accel.sys_cnt = (dev->accel.sx >> 3) + 1; + } + } + dev->data_available = 0; + dev->data_available2 = 0; + return; /*Wait for data from CPU*/ + } else if (ibm8514_cpu_dest(dev)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; /*Wait for data from CPU*/ + } + } + + if (dev->accel.cmd & 2) { + if (cpu_input) { +bitblt_pix: + if (count < 8) { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && + dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b)) { + if (pixcntl == 3) { + if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } else if (dev->accel.cmd & 0x10) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); + if (pixcntl == 3) { + if (dev->accel.cmd & 0x10) { + src_dat = ((src_dat & rd_mask) == rd_mask); + } + } + break; + } + + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) + dev->accel.cx++; + else + dev->accel.cx--; + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 2) { + dev->accel.sx += (dev->accel.cur_x & 3); + } + + if (dev->accel.cmd & 0x20) { + dev->accel.cx -= (dev->accel.sx) + 1; + } else + dev->accel.cx += (dev->accel.sx) + 1; + + if (dev->accel.cmd & 0x80) + dev->accel.cy++; + else + dev->accel.cy--; + + dev->accel.dest = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } else { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && + dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b)) { + if (pixcntl == 3) { + if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? 1 : 0; + } else if (dev->accel.cmd & 0x10) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? 1 : 0; + } + } + switch ((mix_dat & 1) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); + if (pixcntl == 3) { + if (dev->accel.cmd & 0x10) { + src_dat = ((src_dat & rd_mask) == rd_mask); + } + } + break; + } + + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & 1, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } + mix_dat >>= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx++; + dev->accel.cx++; + } else { + dev->accel.dx--; + dev->accel.cx--; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 2) { + if (!(dev->accel.cmd & 0x1000)) + dev->accel.sx += (dev->accel.cur_x & 3); + } + + if (dev->accel.cmd & 0x20) { + dev->accel.dx -= (dev->accel.sx) + 1; + dev->accel.cx -= (dev->accel.sx) + 1; + } else { + dev->accel.dx += (dev->accel.sx) + 1; + dev->accel.cx += (dev->accel.sx) + 1; + } + + if (dev->accel.cmd & 2) { + if (dev->accel.cmd & 0x1000) { + dev->accel.cx = dev->accel.cur_x & 0x3ff; + if (dev->accel.cur_x & 0x400) + dev->accel.cx |= ~0x3ff; + dev->accel.dx = dev->accel.destx_distp & 0x3ff; + if (dev->accel.destx_distp & 0x400) + dev->accel.dx |= ~0x3ff; + } + } + + if (dev->accel.cmd & 0x80) { + dev->accel.dy++; + dev->accel.cy++; + } else { + dev->accel.dy--; + dev->accel.cy--; + } + + dev->accel.dest = dev->accel.dy * dev->h_disp; + dev->accel.src = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } + } else { + goto bitblt; + } + } else { + if (cpu_input) { + if (pixcntl == 2) { + goto bitblt_pix; + } else { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && + dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b)) { + if (pixcntl == 3) { + if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } else if (dev->accel.cmd & 0x10) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = cpu_dat & 0xff; break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); + if (pixcntl == 3) { + if (dev->accel.cmd & 0x10) { + src_dat = ((src_dat & rd_mask) == rd_mask); + } + } + break; + } + + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } + mix_dat <<= 1; + mix_dat |= 1; + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx++; + dev->accel.cx++; + } else { + dev->accel.dx--; + dev->accel.cx--; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx -= (dev->accel.sx) + 1; + dev->accel.cx -= (dev->accel.sx) + 1; + } else { + dev->accel.dx += (dev->accel.sx) + 1; + dev->accel.cx += (dev->accel.sx) + 1; + } + + if (dev->accel.cmd & 0x80) { + dev->accel.dy++; + dev->accel.cy++; + } else { + dev->accel.dy--; + dev->accel.cy--; + } + + dev->accel.dest = dev->accel.dy * dev->h_disp; + dev->accel.src = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } + } else { +bitblt: + if (pixcntl == 1) { + if (dev->accel.cmd & 0x40) { + count = dev->accel.maj_axis_pcnt + 1; + dev->accel.temp_cnt = 8; + while (count-- && dev->accel.sy >= 0) { + if (dev->accel.temp_cnt == 0) { + mix_dat >>= 8; + dev->accel.temp_cnt = 8; + } + if ((dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && + dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); + break; + } + + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } + + if (dev->accel.temp_cnt > 0) { + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + + if (dev->accel.cmd & 0x20) { + dev->accel.dx++; + dev->accel.cx++; + } else { + dev->accel.dx--; + dev->accel.cx--; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx -= (dev->accel.sx) + 1; + dev->accel.cx -= (dev->accel.sx) + 1; + } else { + dev->accel.dx += (dev->accel.sx) + 1; + dev->accel.cx += (dev->accel.sx) + 1; + } + + if (dev->accel.cmd & 0x80) { + dev->accel.dy++; + dev->accel.cy++; + } else { + dev->accel.dy--; + dev->accel.cy--; + } + + dev->accel.dest = dev->accel.dy * dev->h_disp; + dev->accel.src = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + return; + } + } + } else { + dev->accel.temp_cnt = 8; + while (count-- && dev->accel.sy >= 0) { + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat = old_mix_dat; + } + if ((dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && + dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b)) { + switch ((mix_dat & 1) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); + break; + } + + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & 1, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } + dev->accel.temp_cnt--; + mix_dat >>= 1; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx++; + dev->accel.cx++; + } else { + dev->accel.dx--; + dev->accel.cx--; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx -= (dev->accel.sx) + 1; + dev->accel.cx -= (dev->accel.sx) + 1; + } else { + dev->accel.dx += (dev->accel.sx) + 1; + dev->accel.cx += (dev->accel.sx) + 1; + } + + if (dev->accel.cmd & 0x80) { + dev->accel.dy++; + dev->accel.cy++; + } else { + dev->accel.dy--; + dev->accel.cy--; + } + + dev->accel.dest = dev->accel.dy * dev->h_disp; + dev->accel.src = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + + if (dev->accel.sy < 0) { + return; + } + } + } + } + } else { + while (count-- && dev->accel.sy >= 0) { + if ((dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && + dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b)) { + if (pixcntl == 3) { + if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } else if (dev->accel.cmd & 0x10) { + READ(dev->accel.src + dev->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: src_dat = bkgd_color; break; + case 1: src_dat = frgd_color; break; + case 2: src_dat = 0; break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); + if (pixcntl == 3) { + if (dev->accel.cmd & 0x10) { + src_dat = ((src_dat & rd_mask) == rd_mask); + } + } + break; + } + + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } + mix_dat <<= 1; + mix_dat |= 1; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx++; + dev->accel.cx++; + } else { + dev->accel.dx--; + dev->accel.cx--; + } + + dev->accel.sx--; + if (dev->accel.sx < 0) { + dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx -= (dev->accel.sx) + 1; + dev->accel.cx -= (dev->accel.sx) + 1; + } else { + dev->accel.dx += (dev->accel.sx) + 1; + dev->accel.cx += (dev->accel.sx) + 1; + } + + if (dev->accel.cmd & 0x80) { + dev->accel.dy++; + dev->accel.cy++; + } else { + dev->accel.dy--; + dev->accel.cy--; + } + + dev->accel.dest = dev->accel.dy * dev->h_disp; + dev->accel.src = dev->accel.cy * dev->h_disp; + dev->accel.sy--; + + if (dev->accel.sy < 0) { + return; + } + } + } + } + } + } + break; + } +} + +static void +ibm8514_render_8bpp(svga_t *svga) +{ + ibm8514_t *dev = &svga->dev8514; + int x; + uint32_t *p; + uint32_t dat; + + if ((dev->displine + svga->y_add) < 0) { + return; + } + + if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; + + if (dev->firstline_draw == 2000) + dev->firstline_draw = dev->displine; + dev->lastline_draw = dev->displine; + + for (x = 0; x <= dev->h_disp; x += 8) { + dat = *(uint32_t *)(&dev->vram[dev->ma & dev->vram_mask]); + p[0] = dev->map8[dat & 0xff]; + p[1] = dev->map8[(dat >> 8) & 0xff]; + p[2] = dev->map8[(dat >> 16) & 0xff]; + p[3] = dev->map8[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&dev->vram[(dev->ma + 4) & dev->vram_mask]); + p[4] = dev->map8[dat & 0xff]; + p[5] = dev->map8[(dat >> 8) & 0xff]; + p[6] = dev->map8[(dat >> 16) & 0xff]; + p[7] = dev->map8[(dat >> 24) & 0xff]; + + dev->ma += 8; + p += 8; + } + dev->ma &= dev->vram_mask; + } +} + +static void +ibm8514_render_overscan_left(ibm8514_t *dev, svga_t *svga) +{ + int i; + + if ((dev->displine + svga->y_add) < 0) + return; + + if (svga->scrblank || (dev->h_disp == 0)) + return; + + for (i = 0; i < svga->x_add; i++) + buffer32->line[dev->displine + svga->y_add][i] = svga->overscan_color; +} + + +static void +ibm8514_render_overscan_right(ibm8514_t *dev, svga_t *svga) +{ + int i, right; + + if ((dev->displine + svga->y_add) < 0) + return; + + if (svga->scrblank || (dev->h_disp == 0)) + return; + + right = (overscan_x >> 1); + for (i = 0; i < right; i++) + buffer32->line[dev->displine + svga->y_add][svga->x_add + dev->h_disp + i] = svga->overscan_color; +} + +void +ibm8514_poll(ibm8514_t *dev, svga_t *svga) +{ + uint32_t x; + int wx, wy; + + if (!dev->linepos) { + timer_advance_u64(&svga->timer, svga->dispofftime); + dev->linepos = 1; + + if (dev->dispon) { + dev->hdisp_on = 1; + + dev->ma &= dev->vram_mask; + + if (dev->firstline == 2000) { + dev->firstline = dev->displine; + video_wait_for_buffer(); + } + + ibm8514_render_8bpp(svga); + + svga->x_add = (overscan_x >> 1); + ibm8514_render_overscan_left(dev, svga); + ibm8514_render_overscan_right(dev, svga); + svga->x_add = (overscan_x >> 1); + + if (dev->lastline < dev->displine) + dev->lastline = dev->displine; + } + + dev->displine++; + if (dev->interlace) + dev->displine++; + if (dev->displine > 1500) + dev->displine = 0; + } else { + timer_advance_u64(&svga->timer, svga->dispontime); + dev->hdisp_on = 0; + + dev->linepos = 0; + if (dev->dispon) { + if (dev->sc == dev->rowcount) { + dev->linecountff = 0; + dev->sc = 0; + + dev->maback += (dev->rowoffset << 3); + if (dev->interlace) + dev->maback += (dev->rowoffset << 3); + dev->maback &= dev->vram_mask; + dev->ma = dev->maback; + } else { + dev->linecountff = 0; + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; + } + } + + dev->vc++; + dev->vc &= 2047; + + if (dev->vc == dev->dispend) { + dev->dispon = 0; + + for (x = 0; x < ((dev->vram_mask + 1) >> 12); x++) { + if (dev->changedvram[x]) + dev->changedvram[x]--; + } + + if (svga->fullchange) + svga->fullchange--; + } + if (dev->vc == dev->v_syncstart) { + dev->dispon = 0; + x = dev->h_disp; + + if (dev->interlace && !dev->oddeven) + dev->lastline++; + if (dev->interlace && dev->oddeven) + dev->firstline--; + + wx = x; + + wy = dev->lastline - dev->firstline; + svga_doblit(wx, wy, svga); + + dev->firstline = 2000; + dev->lastline = 0; + + dev->firstline_draw = 2000; + dev->lastline_draw = 0; + + dev->oddeven ^= 1; + + changeframecount = dev->interlace ? 3 : 2; + + if (dev->interlace && dev->oddeven) + dev->ma = dev->maback = 0 + (dev->rowoffset << 1); + else + dev->ma = dev->maback = 0; + + dev->ma = (dev->ma << 2); + dev->maback = (dev->maback << 2); + } + if (dev->vc == dev->v_total) { + dev->vc = 0; + dev->sc = 0; + dev->dispon = 1; + dev->displine = (dev->interlace && dev->oddeven) ? 1 : 0; + + svga->x_add = (overscan_x >> 1); + + dev->linecountff = 0; + } + } +} + +void +ibm8514_recalctimings(svga_t *svga) +{ + ibm8514_t *dev = &svga->dev8514; + + dev->h_disp_time = dev->h_disp = (dev->hdisp + 1) << 3; + dev->rowoffset = (dev->hdisp + 1); + dev->h_total = (dev->htotal + 1); + dev->v_total = (dev->vtotal + 1); + dev->v_syncstart = (dev->vsyncstart + 1); + dev->rowcount = !!(dev->disp_cntl & 0x08); + + if (dev->accel.advfunc_cntl & 4) { + if (dev->hdisp == 0) { + dev->rowoffset = 128; + dev->h_disp = 1024; + } + + if (dev->vtotal == 0) + dev->v_total = 1632; + + if (dev->vsyncstart == 0) + dev->v_syncstart = 1536; + + if (dev->interlace) { + dev->dispend = 384; /*Interlaced*/ + dev->v_total >>= 2; + dev->v_syncstart >>= 2; + } else { + dev->dispend = 768; + dev->v_total >>= 1; + dev->v_syncstart >>= 1; + } + //pclog("1024x768 clock mode, hdisp = %d, htotal = %d, vtotal = %d, vsyncstart = %d, interlace = %02x\n", dev->h_disp, dev->h_total, dev->v_total, dev->v_syncstart, dev->interlace); + svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; + } else { + //pclog("640x480 clock mode\n"); + dev->dispend = 480; + dev->v_total >>= 1; + dev->v_syncstart >>= 1; + svga->clock = (cpuclock * (double)(1ull << 32)) / 25175000.0; + } + //pclog("8514 enabled, hdisp=%d, vtotal=%d, htotal=%d, dispend=%d, rowoffset=%d, split=%d, vsyncstart=%d, split=%08x\n", dev->hdisp, dev->vtotal, dev->htotal, dev->dispend, dev->rowoffset, dev->split, dev->vsyncstart, dev->split); +} + +static uint8_t +ibm8514_mca_read(int port, void *priv) +{ + svga_t *svga = (svga_t *)priv; + ibm8514_t *dev = &svga->dev8514; + + return(dev->pos_regs[port & 7]); +} + + +static void +ibm8514_mca_write(int port, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *)priv; + ibm8514_t *dev = &svga->dev8514; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; +} + + +static uint8_t +ibm8514_mca_feedb(void *priv) +{ + svga_t *svga = (svga_t *)priv; + ibm8514_t *dev = &svga->dev8514; + + return dev->pos_regs[2] & 1; +} + + +static void +*ibm8514_init(const device_t *info) +{ + svga_t *svga = svga_get_pri(); + ibm8514_t *dev = &svga->dev8514; + + dev->vram_size = 1024 << 10; + dev->vram = calloc(dev->vram_size, 1); + dev->changedvram = calloc(dev->vram_size >> 12, 1); + dev->vram_mask = dev->vram_size - 1; + dev->map8 = svga->pallook; + + dev->type = info->flags; + + ibm8514_io_set(svga); + + if (info->flags & DEVICE_MCA) { + dev->pos_regs[0] = 0x7f; + dev->pos_regs[1] = 0xef; + mca_add(ibm8514_mca_read, ibm8514_mca_write, ibm8514_mca_feedb, NULL, svga); + } + + return svga; +} + +static void +ibm8514_close(void *p) +{ + svga_t *svga = (svga_t *)p; + ibm8514_t *dev = &svga->dev8514; + + if (dev) { + free(dev->vram); + free(dev->changedvram); + } +} + +static void +ibm8514_speed_changed(void *p) +{ + svga_t *svga = (svga_t *)p; + + svga_recalctimings(svga); +} + +static void +ibm8514_force_redraw(void *p) +{ + svga_t *svga = (svga_t *)p; + + svga->fullchange = changeframecount; +} + +// clang-format off +const device_t gen8514_isa_device = { + .name = "Generic 8514/A clone (ISA)", + .internal_name = "8514_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = 0, + .init = ibm8514_init, + .close = ibm8514_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ibm8514_speed_changed, + .force_redraw = ibm8514_force_redraw, + .config = NULL +}; + +const device_t ibm8514_mca_device = { + .name = "IBM 8514/A (MCA)", + .internal_name = "8514_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = ibm8514_init, + .close = ibm8514_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ibm8514_speed_changed, + .force_redraw = ibm8514_force_redraw, + .config = NULL +}; + + +void +ibm8514_device_add(void) +{ + if (!ibm8514_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&ibm8514_mca_device); + else + device_add(&gen8514_isa_device); +} diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index f9b2a3a8b..4c5f8cb24 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -34,10 +34,10 @@ #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) -#define BIOS_ROM_PATH_WONDER L"roms/video/ati18800/VGA_Wonder_V3-1.02.bin" +#define BIOS_ROM_PATH_WONDER "roms/video/ati18800/VGA_Wonder_V3-1.02.bin" #endif -#define BIOS_ROM_PATH_VGA88 L"roms/video/ati18800/vga88.bin" -#define BIOS_ROM_PATH_EDGE16 L"roms/video/ati18800/vgaedge16.vbi" +#define BIOS_ROM_PATH_VGA88 "roms/video/ati18800/vga88.bin" +#define BIOS_ROM_PATH_EDGE16 "roms/video/ati18800/vgaedge16.vbi" enum { #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) @@ -57,7 +57,7 @@ typedef struct ati18800_t ati_eeprom_t eeprom; rom_t bios_rom; - + uint8_t regs[256]; int index; } ati18800_t; @@ -101,7 +101,7 @@ static void ati18800_out(uint16_t addr, uint8_t val, void *p) break; } break; - + case 0x3D4: svga->crtcreg = val & 0x3f; return; @@ -116,8 +116,13 @@ static void ati18800_out(uint16_t addr, uint8_t val, void *p) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } break; @@ -132,7 +137,7 @@ static uint8_t ati18800_in(uint16_t addr, void *p) uint8_t temp = 0xff; if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; - + switch (addr) { case 0x1ce: @@ -230,7 +235,7 @@ static void *ati18800_init(const device_t *info) ati18800->svga.miscout = 1; - ati_eeprom_load(&ati18800->eeprom, L"ati18800.nvr", 0); + ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); return ati18800; } @@ -257,14 +262,14 @@ static void ati18800_close(void *p) ati18800_t *ati18800 = (ati18800_t *)p; svga_close(&ati18800->svga); - + free(ati18800); } static void ati18800_speed_changed(void *p) { ati18800_t *ati18800 = (ati18800_t *)p; - + svga_recalctimings(&ati18800->svga); } @@ -276,42 +281,47 @@ static void ati18800_force_redraw(void *p) } #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) -const device_t ati18800_wonder_device = -{ - "ATI-18800", - DEVICE_ISA, ATI18800_WONDER, - ati18800_init, - ati18800_close, - NULL, - ati18800_wonder_available, - ati18800_speed_changed, - ati18800_force_redraw, - NULL +const device_t ati18800_wonder_device = { + .name = "ATI-18800", + .internal_name = "ati18800w", + .flags = DEVICE_ISA, + .local = ATI18800_WONDER, + .init = ati18800_init, + .close = ati18800_close, + .reset = NULL, + { .available = ati18800_wonder_available }, + .speed_changed = ati18800_speed_changed, + .force_redraw = ati18800_force_redraw, + .config = NULL }; #endif const device_t ati18800_vga88_device = { - "ATI-18800-1", - DEVICE_ISA, ATI18800_VGA88, - ati18800_init, - ati18800_close, - NULL, - ati18800_vga88_available, - ati18800_speed_changed, - ati18800_force_redraw, - NULL + .name = "ATI-18800-1", + .internal_name = "ati18800v", + .flags = DEVICE_ISA, + .local = ATI18800_VGA88, + .init = ati18800_init, + .close = ati18800_close, + .reset = NULL, + { .available = ati18800_vga88_available }, + .speed_changed = ati18800_speed_changed, + .force_redraw = ati18800_force_redraw, + .config = NULL }; const device_t ati18800_device = { - "ATI-18800-5", - DEVICE_ISA, ATI18800_EDGE16, - ati18800_init, - ati18800_close, - NULL, - ati18800_available, - ati18800_speed_changed, - ati18800_force_redraw, - NULL + .name = "ATI-18800-5", + .internal_name = "ati18800", + .flags = DEVICE_ISA, + .local = ATI18800_EDGE16, + .init = ati18800_init, + .close = ati18800_close, + .reset = NULL, + { .available = ati18800_available }, + .speed_changed = ati18800_speed_changed, + .force_redraw = ati18800_force_redraw, + .config = NULL }; diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 3545cb69d..87abb7da8 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -42,18 +42,24 @@ #define VGAWONDERXL24 2 #endif -#define BIOS_ATIKOR_PATH L"roms/video/ati28800/atikorvga.bin" -#define FONT_ATIKOR_PATH L"roms/video/ati28800/ati_ksc5601.rom" +#define BIOS_ATIKOR_PATH "roms/video/ati28800/atikorvga.bin" +#define BIOS_ATIKOR_4620P_PATH_L "roms/machines/spc4620p/31005h.u8" +#define BIOS_ATIKOR_4620P_PATH_H "roms/machines/spc4620p/31005h.u10" +#define BIOS_ATIKOR_6033P_PATH "roms/machines/spc6033p/phoenix.BIN" +#define FONT_ATIKOR_PATH "roms/video/ati28800/ati_ksc5601.rom" +#define FONT_ATIKOR_4620P_PATH "roms/machines/spc4620p/svb6120a_font.rom" +#define FONT_ATIKOR_6033P_PATH "roms/machines/spc6033p/svb6120a_font.rom" -#define BIOS_VGAXL_EVEN_PATH L"roms/video/ati28800/xleven.bin" -#define BIOS_VGAXL_ODD_PATH L"roms/video/ati28800/xlodd.bin" +#define BIOS_VGAXL_EVEN_PATH "roms/video/ati28800/xleven.bin" +#define BIOS_VGAXL_ODD_PATH "roms/video/ati28800/xlodd.bin" #if defined(DEV_BRANCH) && defined(USE_XL24) -#define BIOS_XL24_EVEN_PATH L"roms/video/ati28800/112-14318-102.bin" -#define BIOS_XL24_ODD_PATH L"roms/video/ati28800/112-14319-102.bin" +#define BIOS_XL24_EVEN_PATH "roms/video/ati28800/112-14318-102.bin" +#define BIOS_XL24_ODD_PATH "roms/video/ati28800/112-14319-102.bin" #endif -#define BIOS_ROM_PATH L"roms/video/ati28800/bios.bin" +#define BIOS_ROM_PATH "roms/video/ati28800/bios.bin" +#define BIOS_VGAXL_ROM_PATH "roms/video/ati28800/ATI_VGAWonder_XL.bin" typedef struct ati28800_t @@ -77,10 +83,13 @@ typedef struct ati28800_t int get_korean_font_index; uint16_t get_korean_font_base; int ksc5601_mode_enabled; + + int type, type_korean; } ati28800_t; -static video_timings_t timing_ati28800 = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; +static video_timings_t timing_ati28800 = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; +static video_timings_t timing_ati28800_spc = {VIDEO_ISA, 2, 2, 4, 4, 4, 8}; #ifdef ENABLE_ATI28800_LOG @@ -105,7 +114,6 @@ ati28800_log(const char *fmt, ...) static void ati28800_recalctimings(svga_t *svga); - static void ati28800_out(uint16_t addr, uint8_t val, void *p) { @@ -128,41 +136,40 @@ ati28800_out(uint16_t addr, uint8_t val, void *p) ati28800_log("ATI 28800 write reg=0x%02X, val=0x%02X\n", ati28800->index, val); switch (ati28800->index) { case 0xa3: - ati28800->regs[0xa3] = val & 0x1f; - svga_recalctimings(svga); + if ((old ^ val) & 0x10) + svga_recalctimings(svga); break; - case 0xa6: - ati28800->regs[0xa6] = val & 0xc9; - break; - case 0xab: - ati28800->regs[0xab] = val & 0xdf; + case 0xa7: + if ((old ^ val) & 0x80) + svga_recalctimings(svga); break; case 0xb0: - ati28800->regs[0xb0] = val & 0x7d; - svga_recalctimings(svga); - break; - case 0xb1: - ati28800->regs[0xb0] = val & 0x7f; + if ((old ^ val) & 0x60) + svga_recalctimings(svga); break; case 0xb2: + case 0xbe: if (ati28800->regs[0xbe] & 0x08) { /* Read/write bank mode */ - svga->read_bank = (((val & 0x01) << 3) | ((val & 0xe0) >> 5)) * 0x10000; - svga->write_bank = ((val & 0x1e) >> 1) * 0x10000; + svga->read_bank = (((ati28800->regs[0xb2] & 0x01) << 3) | ((ati28800->regs[0xb2] & 0xe0) >> 5)) * 0x10000; + svga->write_bank = ((ati28800->regs[0xb2] & 0x1e) >> 1) * 0x10000; } else { /* Single bank mode */ - svga->read_bank = ((val & 0x1e) >> 1) * 0x10000; - svga->write_bank = ((val & 0x1e) >> 1) * 0x10000; + svga->read_bank = ((ati28800->regs[0xb2] & 0x1e) >> 1) * 0x10000; + svga->write_bank = ((ati28800->regs[0xb2] & 0x1e) >> 1) * 0x10000; + } + if (ati28800->index == 0xbe) { + if ((old ^ val) & 0x10) + svga_recalctimings(svga); } break; case 0xb3: - ati28800->regs[0xb3] = val & 0xef; ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); break; case 0xb6: - if ((old ^ val) & 0x10) + if ((old ^ val) & 0x10) svga_recalctimings(svga); break; case 0xb8: - if ((old ^ val) & 0x40) + if ((old ^ val) & 0x40) svga_recalctimings(svga); break; case 0xb9: @@ -173,8 +180,11 @@ ati28800_out(uint16_t addr, uint8_t val, void *p) break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - sc1502x_ramdac_out(addr, val, svga->ramdac, svga); - return; + if (ati28800->type == 1) + sc1148x_ramdac_out(addr, 0, val, svga->ramdac, svga); + else + svga_out(addr, val, svga); + return; case 0x3D4: svga->crtcreg = val & 0x3f; @@ -184,21 +194,22 @@ ati28800_out(uint16_t addr, uint8_t val, void *p) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); - if ((ati28800->regs[0xb4] & 0x10) && ((svga->crtcreg == 0x0a) || (svga->crtcreg == 0x0b))) - return; - if ((ati28800->regs[0xb4] & 0x20) && ((svga->crtc[0x08] & 0x7f) && (svga->crtc[0x14] & 0x1f))) - return; - if ((ati28800->regs[0xb4] & 0x40) && ((svga->crtcreg <= 0x06) && (svga->crtc[0x07] & 0x10) != 0x10)) - return; old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; - if (old != val) { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } break; } svga_out(addr, val, svga); @@ -212,9 +223,9 @@ ati28800k_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &ati28800->svga; uint16_t oldaddr = addr; - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; - + switch (addr) { case 0x1CF: if (ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) { @@ -259,6 +270,7 @@ ati28800k_out(uint16_t addr, uint8_t val, void *p) } break; } + break; default: ati28800_out(oldaddr, val, p); break; @@ -275,7 +287,7 @@ ati28800_in(uint16_t addr, void *p) if (addr != 0x3da) ati28800_log("ati28800_in : %04X ", addr); - + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; @@ -285,22 +297,23 @@ ati28800_in(uint16_t addr, void *p) break; case 0x1cf: switch (ati28800->index) { - case 0xa0: - temp = 0x10; - break; case 0xaa: temp = ati28800->id; break; case 0xb0: - if (ati28800->memory == 1024) - temp = 0x08; - else if (ati28800->memory == 512) - temp = 0x10; - else - temp = 0x00; + temp = ati28800->regs[0xb0] | 0x80; + if (ati28800->memory == 1024) { + temp &= ~0x10; + temp |= 0x08; + } else if (ati28800->memory == 512) { + temp |= 0x10; + temp &= ~0x08; + } else { + temp &= ~0x18; + } break; case 0xb7: - temp = ati28800->regs[ati28800->index] & ~8; + temp = ati28800->regs[0xb7] & ~8; if (ati_eeprom_read(&ati28800->eeprom)) temp |= 8; break; @@ -319,7 +332,9 @@ ati28800_in(uint16_t addr, void *p) break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return sc1502x_ramdac_in(addr, svga->ramdac, svga); + if (ati28800->type == 1) + return sc1148x_ramdac_in(addr, 0, svga->ramdac, svga); + return svga_in(addr, svga); case 0x3D4: temp = svga->crtcreg; @@ -387,8 +402,14 @@ ati28800_recalctimings(svga_t *svga) { ati28800_t *ati28800 = (ati28800_t *)svga->p; - switch (((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | - ((svga->miscout & 0x0C) >> 2)) { + if (ati28800->regs[0xa3] & 0x10) + svga->ma_latch |= 0x10000; + + if (ati28800->regs[0xb0] & 0x40) + svga->ma_latch |= 0x20000; + + switch (((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | + ((svga->miscout & 0x0C) >> 2)) { case 0x00: svga->clock = (cpuclock * (double)(1ull << 32)) / 42954000.0; break; case 0x01: svga->clock = (cpuclock * (double)(1ull << 32)) / 48771000.0; break; case 0x02: ati28800_log ("clock 2\n"); break; @@ -401,51 +422,72 @@ ati28800_recalctimings(svga_t *svga) case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 32000000.0; break; case 0x0A: svga->clock = (cpuclock * (double)(1ull << 32)) / 37500000.0; break; case 0x0B: svga->clock = (cpuclock * (double)(1ull << 32)) / 39000000.0; break; - case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; case 0x0D: svga->clock = (cpuclock * (double)(1ull << 32)) / 56644000.0; break; case 0x0E: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; case 0x0F: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; default: break; - } + } - if (ati28800->regs[0xb8] & 0x40) + if (ati28800->regs[0xb8] & 0x40) svga->clock *= 2; - if (ati28800->regs[0xa3] & 0x10) - svga->ma |= 0x10000; + if (ati28800->regs[0xa7] & 0x80) + svga->clock *= 3; - if (ati28800->regs[0xb0] & 0x40) - svga->ma |= 0x20000; - - if (ati28800->regs[0xb6] & 0x10) { + if (ati28800->regs[0xb6] & 0x10) { svga->hdisp <<= 1; svga->htotal <<= 1; svga->rowoffset <<= 1; - } - - if (svga->crtc[0x17] & 4) { - svga->vtotal <<= 1; - svga->dispend <<= 1; - svga->vsyncstart <<= 1; - svga->split <<= 1; - svga->vblankstart <<= 1; - } - - if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) { /* Extended 256 colour modes */ - switch (svga->bpp) { - case 8: - svga->render = svga_render_8bpp_highres; - svga->rowoffset <<= 1; - svga->ma <<= 1; - break; - case 15: - svga->render = svga_render_15bpp_highres; - svga->hdisp >>= 1; - svga->rowoffset <<= 1; - svga->ma <<= 1; - break; + svga->gdcreg[5] &= ~0x40; + } + + if (ati28800->regs[0xb0] & 0x20) { + svga->gdcreg[5] |= 0x40; + } + + if (!svga->scrblank && svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else { + svga->render = svga_render_8bpp_highres; + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else { + svga->render = svga_render_15bpp_highres; + svga->hdisp >>= 1; + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + break; + } + break; + } + } } - } } @@ -460,16 +502,21 @@ ati28800k_recalctimings(svga_t *svga) svga->render = svga_render_text_80_ksc5601; } - void * ati28800k_init(const device_t *info) { ati28800_t *ati28800 = (ati28800_t *) malloc(sizeof(ati28800_t)); memset(ati28800, 0, sizeof(ati28800_t)); - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800); + ati28800->type_korean = info->local; - ati28800->memory = device_get_config_int("memory"); + if (ati28800->type_korean == 0) { + ati28800->memory = device_get_config_int("memory"); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800); + } else { + ati28800->memory = 512; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800_spc); + } ati28800->port_03dd_val = 0; ati28800->get_korean_font_base = 0; @@ -479,8 +526,22 @@ ati28800k_init(const device_t *info) ati28800->in_get_korean_font_kind_set = 0; ati28800->ksc5601_mode_enabled = 0; - rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont(FONT_ATIKOR_PATH, 6); + switch(ati28800->type_korean) { + case 0: + default: + rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont(FONT_ATIKOR_PATH, 6); + break; + case 1: + rom_init_interleaved(&ati28800->bios_rom, BIOS_ATIKOR_4620P_PATH_L, BIOS_ATIKOR_4620P_PATH_H, 0xc0000, + 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont(FONT_ATIKOR_4620P_PATH, 6); + break; + case 2: + rom_init(&ati28800->bios_rom, BIOS_ATIKOR_6033P_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont(FONT_ATIKOR_6033P_PATH, 6); + break; + } svga_init(info, &ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/ ati28800k_recalctimings, @@ -488,19 +549,19 @@ ati28800k_init(const device_t *info) NULL, NULL); - ati28800->svga.ramdac = device_add(&sc1502x_ramdac_device); - io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); ati28800->svga.miscout = 1; + ati28800->svga.bpp = 8; + ati28800->svga.packed_chain4 = 1; ati28800->svga.ksc5601_sbyte_mask = 0; ati28800->svga.ksc5601_udc_area_msb[0] = 0xC9; ati28800->svga.ksc5601_udc_area_msb[1] = 0xFE; ati28800->svga.ksc5601_swap_mode = 0; ati28800->svga.ksc5601_english_font_type = 0; - ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + ati_eeprom_load(&ati28800->eeprom, "atikorvga.nvr", 0); return ati28800; } @@ -517,14 +578,16 @@ ati28800_init(const device_t *info) ati28800->memory = device_get_config_int("memory"); - switch(info->local) { + ati28800->type = info->local; + + switch(ati28800->type) { case VGAWONDERXL: - ati28800->id = 6; - rom_init_interleaved(&ati28800->bios_rom, - BIOS_VGAXL_EVEN_PATH, - BIOS_VGAXL_ODD_PATH, - 0xc0000, 0x10000, 0xffff, - 0, MEM_MAPPING_EXTERNAL); + ati28800->id = 5; + rom_init(&ati28800->bios_rom, + BIOS_VGAXL_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + ati28800->svga.ramdac = device_add(&sc11486_ramdac_device); break; #if defined(DEV_BRANCH) && defined(USE_XL24) @@ -553,8 +616,6 @@ ati28800_init(const device_t *info) NULL, NULL); - ati28800->svga.ramdac = device_add(&sc1502x_ramdac_device); - io_sethandler(0x01ce, 2, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, ati28800); @@ -563,22 +624,24 @@ ati28800_init(const device_t *info) ati28800_out, NULL, NULL, ati28800); ati28800->svga.miscout = 1; + ati28800->svga.bpp = 8; + ati28800->svga.packed_chain4 = 1; - switch (info->local) { + switch (ati28800->type) { case VGAWONDERXL: - ati_eeprom_load(&ati28800->eeprom, L"ati28800xl.nvr", 0); + ati_eeprom_load(&ati28800->eeprom, "ati28800xl.nvr", 0); break; #if defined(DEV_BRANCH) && defined(USE_XL24) case VGAWONDERXL24: - ati_eeprom_load(&ati28800->eeprom, L"ati28800xl24.nvr", 0); + ati_eeprom_load(&ati28800->eeprom, "ati28800xl24.nvr", 0); break; #endif default: - ati_eeprom_load(&ati28800->eeprom, L"ati28800.nvr", 0); + ati_eeprom_load(&ati28800->eeprom, "ati28800.nvr", 0); break; - } + } return(ati28800); } @@ -592,7 +655,7 @@ ati28800_available(void) static int -ati28800k_available() +ati28800k_available(void) { return ((rom_present(BIOS_ATIKOR_PATH) && rom_present(FONT_ATIKOR_PATH))); } @@ -601,7 +664,7 @@ ati28800k_available() static int compaq_ati28800_available(void) { - return((rom_present(BIOS_VGAXL_EVEN_PATH) && rom_present(BIOS_VGAXL_ODD_PATH))); + return((rom_present(BIOS_VGAXL_ROM_PATH))); } @@ -629,7 +692,7 @@ static void ati28800_speed_changed(void *p) { ati28800_t *ati28800 = (ati28800_t *)p; - + svga_recalctimings(&ati28800->svga); } @@ -642,103 +705,150 @@ ati28800_force_redraw(void *priv) ati28800->svga.fullchange = changeframecount; } - -static const device_config_t ati28800_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 512, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 +// clang-format off +static const device_config_t ati28800_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } }; #if defined(DEV_BRANCH) && defined(USE_XL24) -static const device_config_t ati28800_wonderxl_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 512, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 +static const device_config_t ati28800_wonderxl_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } }; #endif +// clang-format on -const device_t ati28800_device = -{ - "ATI-28800", - DEVICE_ISA, - 0, - ati28800_init, ati28800_close, NULL, - ati28800_available, - ati28800_speed_changed, - ati28800_force_redraw, - ati28800_config +const device_t ati28800_device = { + .name = "ATI 28800-5 (ATI VGA Charger)", + .internal_name = "ati28800", + .flags = DEVICE_ISA, + .local = 0, + .init = ati28800_init, + .close = ati28800_close, + .reset = NULL, + { .available = ati28800_available }, + .speed_changed = ati28800_speed_changed, + .force_redraw = ati28800_force_redraw, + .config = ati28800_config }; -const device_t ati28800k_device = -{ - "ATI Korean VGA", - DEVICE_ISA, - 0, - ati28800k_init, ati28800_close, NULL, - ati28800k_available, - ati28800_speed_changed, - ati28800_force_redraw, - ati28800_config +const device_t ati28800k_device = { + .name = "ATI Korean VGA", + .internal_name = "ati28800k", + .flags = DEVICE_ISA, + .local = 0, + .init = ati28800k_init, + .close = ati28800_close, + .reset = NULL, + { .available = ati28800k_available }, + .speed_changed = ati28800_speed_changed, + .force_redraw = ati28800_force_redraw, + .config = ati28800_config }; -const device_t compaq_ati28800_device = -{ - "Compaq ATI-28800", - DEVICE_ISA, - VGAWONDERXL, - ati28800_init, ati28800_close, NULL, - compaq_ati28800_available, - ati28800_speed_changed, - ati28800_force_redraw, - ati28800_config +const device_t ati28800k_spc4620p_device = { + .name = "ATI Korean VGA On-Board SPC-4620P", + .internal_name = "ati28800k_spc4620p", + .flags = DEVICE_ISA, + .local = 1, + .init = ati28800k_init, + .close = ati28800_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ati28800_speed_changed, + .force_redraw = ati28800_force_redraw, + .config = NULL +}; + +const device_t ati28800k_spc6033p_device = { + .name = "ATI Korean VGA On-Board SPC-6033P", + .internal_name = "ati28800k_spc6033p", + .flags = DEVICE_ISA, + .local = 2, + .init = ati28800k_init, + .close = ati28800_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ati28800_speed_changed, + .force_redraw = ati28800_force_redraw, + .config = NULL +}; + +const device_t compaq_ati28800_device = { + .name = "ATI 28800-5 (ATI VGA Wonder XL)", + .internal_name = "compaq_ati28800", + .flags = DEVICE_ISA, + .local = VGAWONDERXL, + .init = ati28800_init, + .close = ati28800_close, + .reset = NULL, + { .available = compaq_ati28800_available }, + .speed_changed = ati28800_speed_changed, + .force_redraw = ati28800_force_redraw, + .config = ati28800_config }; #if defined(DEV_BRANCH) && defined(USE_XL24) -const device_t ati28800_wonderxl24_device = -{ - "ATI-28800 (VGA Wonder XL24)", - DEVICE_ISA, - VGAWONDERXL24, - ati28800_init, ati28800_close, NULL, - ati28800_wonderxl24_available, - ati28800_speed_changed, - ati28800_force_redraw, - ati28800_wonderxl_config +const device_t ati28800_wonderxl24_device = { + .name = "ATI-28800 (VGA Wonder XL24)", + .internal_name = "ati28800w", + .flags = DEVICE_ISA, + .local = VGAWONDERXL24, + .init = ati28800_init, + .close = ati28800_close, + .reset = NULL, + { .available = ati28800_wonderxl24_available }, + .speed_changed = ati28800_speed_changed, + .force_redraw = ati28800_force_redraw, + .config = ati28800_wonderxl_config }; #endif diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/vid_ati68860_ramdac.c index b6703a310..46967ce3d 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/vid_ati68860_ramdac.c @@ -19,7 +19,7 @@ * bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, * A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, * E3h: 32bpp (80h for VGA modes ?) - * + * * REG0C (R/W): Device Setup Register A * bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT * 2-3 Depends on Video memory (= VRAM width ?) . @@ -70,17 +70,17 @@ ati68860_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga) ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) p; switch (addr) { - case 0: + case 0: svga_out(0x3c8, val, svga); break; - case 1: - svga_out(0x3c9, val, svga); + case 1: + svga_out(0x3c9, val, svga); break; - case 2: - svga_out(0x3c6, val, svga); + case 2: + svga_out(0x3c6, val, svga); break; - case 3: - svga_out(0x3c7, val, svga); + case 3: + svga_out(0x3c7, val, svga); break; default: ramdac->regs[addr & 0xf] = val; @@ -93,18 +93,18 @@ ati68860_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga) switch (ramdac->dac_pos) { case 0: ramdac->dac_r = val; - ramdac->dac_pos++; + ramdac->dac_pos++; break; case 1: ramdac->dac_g = val; - ramdac->dac_pos++; + ramdac->dac_pos++; break; case 2: if (ramdac->dac_addr > 1) break; - ramdac->pal[ramdac->dac_addr].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_addr].r = ramdac->dac_r; ramdac->pal[ramdac->dac_addr].g = ramdac->dac_g; - ramdac->pal[ramdac->dac_addr].b = val; + ramdac->pal[ramdac->dac_addr].b = val; if (ramdac->ramdac_type == RAMDAC_8BIT) ramdac->pallook[ramdac->dac_addr] = makecol32(ramdac->pal[ramdac->dac_addr].r, ramdac->pal[ramdac->dac_addr].g, @@ -114,7 +114,7 @@ ati68860_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga) video_6to8[ramdac->pal[ramdac->dac_addr].g & 0x3f], video_6to8[ramdac->pal[ramdac->dac_addr].b & 0x3f]); ramdac->dac_pos = 0; - ramdac->dac_addr = (ramdac->dac_addr + 1) & 255; + ramdac->dac_addr = (ramdac->dac_addr + 1) & 255; break; } break; @@ -177,7 +177,7 @@ ati68860_ramdac_in(uint16_t addr, void *p, svga_t *svga) temp = svga_in(0x3c7, svga); break; case 4: case 8: - temp = 2; + temp = 2; break; case 6: case 0xa: temp = 0x1d; @@ -210,7 +210,7 @@ ati68860_set_ramdac_type(void *p, int type) ramdac->pal[c].b); else ramdac->pallook[c] = makecol32(video_6to8[ramdac->pal[c].r & 0x3f], video_6to8[ramdac->pal[c].g & 0x3f], - video_6to8[ramdac->pal[c].b & 0x3f]); + video_6to8[ramdac->pal[c].b & 0x3f]); } } } @@ -286,11 +286,16 @@ ati68860_ramdac_close(void *priv) free(ramdac); } - -const device_t ati68860_ramdac_device = -{ - "ATI-68860 RAMDAC", - 0, 0, - ati68860_ramdac_init, ati68860_ramdac_close, - NULL, NULL, NULL, NULL +const device_t ati68860_ramdac_device = { + .name = "ATI-68860 RAMDAC", + .internal_name = "ati68860_ramdac", + .flags = 0, + .local = 0, + .init = ati68860_ramdac_init, + .close = ati68860_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 83f713c89..561f6229b 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -28,43 +28,13 @@ #include <86box/vid_ati_eeprom.h> -enum -{ - EEPROM_IDLE, - EEPROM_WAIT, - EEPROM_OPCODE, - EEPROM_INPUT, - EEPROM_OUTPUT -}; - -enum -{ - EEPROM_OP_EW = 4, - EEPROM_OP_WRITE = 5, - EEPROM_OP_READ = 6, - EEPROM_OP_ERASE = 7, - - EEPROM_OP_WRALMAIN = -1 -}; - -enum -{ - EEPROM_OP_EWDS = 0, - EEPROM_OP_WRAL = 1, - EEPROM_OP_ERAL = 2, - EEPROM_OP_EWEN = 3 -}; - -void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) +void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) { FILE *f; int size; eeprom->type = type; - if (wcslen(fn) <= 256) - wcscpy(eeprom->fn, fn); - else - wcsncpy(eeprom->fn, fn, 256); - f = nvr_fopen(eeprom->fn, L"rb"); + strncpy(eeprom->fn, fn, sizeof(eeprom->fn) - 1); + f = nvr_fopen(eeprom->fn, "rb"); size = eeprom->type ? 512 : 128; if (!f) { memset(eeprom->data, 0xff, size); @@ -77,7 +47,7 @@ void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) void ati_eeprom_save(ati_eeprom_t *eeprom) { - FILE *f = nvr_fopen(eeprom->fn, L"wb"); + FILE *f = nvr_fopen(eeprom->fn, "wb"); if (!f) return; fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); fclose(f); @@ -138,7 +108,7 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) } } break; - + case EEPROM_INPUT: eeprom->dat = (eeprom->dat << 1) | (dat ? 1 : 0); eeprom->count--; @@ -210,7 +180,7 @@ void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) } break; } - } + } eeprom->oldena = ena; } else if (!clk && eeprom->oldclk) @@ -238,4 +208,3 @@ int ati_eeprom_read(ati_eeprom_t *eeprom) { return eeprom->out; } - diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index a96184b2b..7f4e2c7c9 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -31,7 +31,10 @@ #include <86box/pci.h> #include <86box/rom.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> #include <86box/vid_ati_eeprom.h> @@ -40,10 +43,10 @@ #undef CLAMP #endif -#define BIOS_ROM_PATH L"roms/video/mach64/bios.bin" -#define BIOS_ISA_ROM_PATH L"roms/video/mach64/M64-1994.VBI" -#define BIOS_VLB_ROM_PATH L"roms/video/mach64/mach64_vlb_vram.bin" -#define BIOS_ROMVT2_PATH L"roms/video/mach64/atimach64vt2pci.bin" +#define BIOS_ROM_PATH "roms/video/mach64/bios.bin" +#define BIOS_ISA_ROM_PATH "roms/video/mach64/M64-1994.VBI" +#define BIOS_VLB_ROM_PATH "roms/video/mach64/mach64_vlb_vram.bin" +#define BIOS_ROMVT2_PATH "roms/video/mach64/atimach64vt2pci.bin" #define FIFO_SIZE 65536 @@ -86,15 +89,14 @@ typedef struct mach64_t ati_eeprom_t eeprom; svga_t svga; - + rom_t bios_rom; - + uint8_t regs[256]; int index; - int type, pci, - bit32; - + int type, pci; + uint8_t pci_regs[256]; uint8_t int_line; int card; @@ -104,12 +106,12 @@ typedef struct mach64_t uint32_t vram_size; uint32_t vram_mask; - + uint32_t config_cntl; uint32_t context_load_cntl; uint32_t context_mask; - + uint32_t crtc_gen_cntl; uint8_t crtc_int_cntl; uint32_t crtc_h_total_disp; @@ -123,45 +125,45 @@ typedef struct mach64_t uint32_t clr_cmp_cntl; uint32_t clr_cmp_mask; - uint32_t cur_horz_vert_off; + uint32_t cur_horz_vert_off; uint32_t cur_horz_vert_posn; uint32_t cur_offset; - + uint32_t dac_cntl; - + uint32_t dp_bkgd_clr; uint32_t dp_frgd_clr; uint32_t dp_mix; uint32_t dp_pix_width; uint32_t dp_src; - + uint32_t dst_bres_lnth; uint32_t dst_bres_dec; uint32_t dst_bres_err; uint32_t dst_bres_inc; - + uint32_t dst_cntl; uint32_t dst_height_width; uint32_t dst_off_pitch; uint32_t dst_y_x; uint32_t gen_test_cntl; - + uint32_t gui_traj_cntl; uint32_t host_cntl; - + uint32_t mem_cntl; uint32_t ovr_clr; uint32_t ovr_wid_left_right; uint32_t ovr_wid_top_bottom; - - uint32_t pat_cntl; + + uint32_t pat_cntl; uint32_t pat_reg0, pat_reg1; - + uint32_t sc_left_right, sc_top_bottom; - + uint32_t scratch_reg0, scratch_reg1; uint32_t src_cntl; @@ -170,14 +172,16 @@ typedef struct mach64_t uint32_t src_y_x_start; uint32_t src_height1_width1, src_height2_width2; + uint32_t write_mask; + uint32_t chain_mask; uint32_t linear_base, old_linear_base; - uint32_t io_base; + uint32_t io_base; struct { int op; - + int dst_x, dst_y; int dst_x_start, dst_y_start; int src_x, src_y; @@ -188,25 +192,28 @@ typedef struct mach64_t int src_width1, src_height1; int src_width2, src_height2; uint32_t src_offset, src_pitch; - uint32_t dst_offset, dst_pitch; + uint32_t dst_offset, dst_pitch; int mix_bg, mix_fg; int source_bg, source_fg, source_mix; - int source_host; + int source_host; int dst_width, dst_height; int busy; int pattern[8][8]; + uint8_t pattern_clr4x2[2][4]; + uint8_t pattern_clr8x1[8]; int sc_left, sc_right, sc_top, sc_bottom; int dst_pix_width, src_pix_width, host_pix_width; int dst_size, src_size, host_size; uint32_t dp_bkgd_clr; uint32_t dp_frgd_clr; + uint32_t write_mask; uint32_t clr_cmp_clr; uint32_t clr_cmp_mask; int clr_cmp_fn; int clr_cmp_src; - + int err; int poly_draw; } accel; @@ -217,24 +224,24 @@ typedef struct mach64_t thread_t *fifo_thread; event_t *wake_fifo_thread; event_t *fifo_not_full_event; - + int blitter_busy; uint64_t blitter_time; uint64_t status_time; - + uint16_t pci_id; uint32_t config_chip_id; uint32_t block_decoded_io; int use_block_decoded_io; - + int pll_addr; uint8_t pll_regs[16]; double pll_freq[4]; - + uint32_t config_stat0; - + uint32_t cur_clr0, cur_clr1; - + uint32_t overlay_dat[1024]; uint32_t overlay_graphics_key_clr, overlay_graphics_key_msk; uint32_t overlay_video_key_clr, overlay_video_key_msk; @@ -242,14 +249,17 @@ typedef struct mach64_t uint32_t overlay_scale_inc; uint32_t overlay_scale_cntl; uint32_t overlay_y_x_start, overlay_y_x_end; - + uint32_t scaler_height_width; int scaler_format; int scaler_update; - + uint32_t buf_offset[2], buf_pitch[2]; - + int overlay_v_acc; + + uint8_t thread_run; + void *i2c, *ddc; } mach64_t; static video_timings_t timing_mach64_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; @@ -280,7 +290,8 @@ enum BPP_8 = 2, BPP_15 = 3, BPP_16 = 4, - BPP_32 = 5 + BPP_24 = 5, + BPP_32 = 6 }; enum @@ -368,8 +379,8 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) mach64_t *mach64 = p; svga_t *svga = &mach64->svga; uint8_t old; - - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -380,16 +391,16 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) case 0x1cf: mach64->regs[mach64->index & 0x3f] = val; if ((mach64->index & 0x3f) == 0x36) - mach64_recalctimings(svga); + svga_recalctimings(svga); break; - + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: if (mach64->type == MACH64_GX) ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, mach64->svga.ramdac, svga); else svga_out(addr, val, svga); return; - + case 0x3cf: if (svga->gdcaddr == 6) { @@ -400,7 +411,7 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) return; } break; - + case 0x3D4: svga->crtcreg = val & 0x3f; return; @@ -414,12 +425,17 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; - if (old!=val) + if (old != val) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } break; @@ -432,9 +448,9 @@ uint8_t mach64_in(uint16_t addr, void *p) mach64_t *mach64 = p; svga_t *svga = &mach64->svga; - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; - + switch (addr) { case 0x1ce: @@ -446,7 +462,7 @@ uint8_t mach64_in(uint16_t addr, void *p) if (mach64->type == MACH64_GX) return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, svga); return svga_in(addr, svga); - + case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -480,36 +496,36 @@ void mach64_recalctimings(svga_t *svga) ati68860_ramdac_set_render(svga->ramdac, svga); switch ((mach64->crtc_gen_cntl >> 8) & 7) { - case 1: + case BPP_4: if (mach64->type != MACH64_GX) - svga->render = svga_render_4bpp_highres; + svga->render = svga_render_4bpp_highres; svga->hdisp *= 8; break; - case 2: + case BPP_8: if (mach64->type != MACH64_GX) - svga->render = svga_render_8bpp_highres; + svga->render = svga_render_8bpp_highres; svga->hdisp *= 8; svga->rowoffset /= 2; break; - case 3: + case BPP_15: if (mach64->type != MACH64_GX) - svga->render = svga_render_15bpp_highres; + svga->render = svga_render_15bpp_highres; svga->hdisp *= 8; break; - case 4: + case BPP_16: if (mach64->type != MACH64_GX) - svga->render = svga_render_16bpp_highres; + svga->render = svga_render_16bpp_highres; svga->hdisp *= 8; break; - case 5: + case BPP_24: if (mach64->type != MACH64_GX) - svga->render = svga_render_24bpp_highres; + svga->render = svga_render_24bpp_highres; svga->hdisp *= 8; svga->rowoffset = (svga->rowoffset * 3) / 2; break; - case 6: + case BPP_32: if (mach64->type != MACH64_GX) - svga->render = svga_render_32bpp_highres; + svga->render = svga_render_32bpp_highres; svga->hdisp *= 8; svga->rowoffset *= 2; break; @@ -542,38 +558,26 @@ void mach64_updatemapping(mach64_t *mach64) switch (svga->gdcreg[6] & 0xc) { case 0x0: /*128k at A0000*/ - if (mach64->bit32) - mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); - else - mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, NULL, mach64_write, mach64_writew, NULL); + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); mem_mapping_set_p(&mach64->svga.mapping, mach64); mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); mem_mapping_enable(&mach64->mmio_mapping); svga->banked_mask = 0xffff; break; case 0x4: /*64k at A0000*/ - if (mach64->bit32) - mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); - else - mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, NULL, mach64_write, mach64_writew, NULL); + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); mem_mapping_set_p(&mach64->svga.mapping, mach64); mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; break; case 0x8: /*32k at B0000*/ - if (mach64->bit32) - mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); - else - mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, NULL, svga_write, svga_writew, NULL); + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); mem_mapping_set_p(&mach64->svga.mapping, svga); mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); svga->banked_mask = 0x7fff; break; case 0xC: /*32k at B8000*/ - if (mach64->bit32) - mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); - else - mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, NULL, svga_write, svga_writew, NULL); + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); mem_mapping_set_p(&mach64->svga.mapping, svga); mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); svga->banked_mask = 0x7fff; @@ -646,7 +650,7 @@ static void mach64_wait_fifo_idle(mach64_t *mach64) case 2: ret = ((var) >> 16) & 0xff; break; \ case 3: ret = ((var) >> 24) & 0xff; break; \ } - + #define WRITE8(addr, var, val) switch ((addr) & 3) \ { \ case 0: var = (var & 0xffffff00) | (val); break; \ @@ -687,8 +691,8 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val mach64_log("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); - if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && - ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) mach64_blit(0, -1, mach64); } @@ -701,7 +705,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val mach64_start_line(mach64); if ((mach64->dst_bres_lnth & 0x7fff) && - ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) mach64_blit(0, -1, mach64); } @@ -782,7 +786,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val case 0x23c: case 0x23d: case 0x23e: case 0x23f: mach64_blit(val, 8, mach64); break; - + case 0x240: case 0x241: case 0x242: case 0x243: WRITE8(addr, mach64->host_cntl, val); break; @@ -794,13 +798,17 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val WRITE8(addr, mach64->pat_reg1, val); break; + case 0x288: case 0x289: case 0x28a: case 0x28b: + WRITE8(addr, mach64->pat_cntl, val); + break; + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: WRITE8(addr, mach64->sc_left_right, val); break; case 0x2a4: case 0x2a5: addr += 2; /*FALLTHROUGH*/ - case 0x2aa: case 0x2ab: + case 0x2aa: case 0x2ab: WRITE8(addr, mach64->sc_left_right, val); break; @@ -820,6 +828,12 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: WRITE8(addr, mach64->dp_frgd_clr, val); break; + case 0x2c8: case 0x2c9: case 0x2ca: case 0x2cb: + WRITE8(addr, mach64->write_mask, val); + break; + case 0x2cc: case 0x2cd: case 0x2ce: case 0x2cf: + WRITE8(addr, mach64->chain_mask, val); + break; case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: WRITE8(addr, mach64->dp_pix_width, val); @@ -900,7 +914,7 @@ static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t if (val & 0x30000) mach64_load_context(mach64); break; - + case 0x200: case 0x204: case 0x208: case 0x20c: case 0x210: case 0x214: case 0x218: case 0x21c: case 0x220: case 0x224: case 0x228: case 0x22c: @@ -921,8 +935,8 @@ static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t static void fifo_thread(void *param) { mach64_t *mach64 = (mach64_t *)param; - - while (1) + + while (mach64->thread_run) { thread_set_event(mach64->fifo_not_full_event); thread_wait_event(mach64->wake_fifo_thread, -1); @@ -946,7 +960,7 @@ static void fifo_thread(void *param) mach64_accel_write_fifo_l(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); break; } - + mach64->fifo_read_idx++; fifo->addr_type = FIFO_INVALID; @@ -977,27 +991,23 @@ static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t fifo->addr_type = (addr & FIFO_ADDR) | type; mach64->fifo_write_idx++; - + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) wake_fifo_thread(mach64); } -void mach64_cursor_dump(mach64_t *mach64) -{ - return; -} void mach64_start_fill(mach64_t *mach64) { int x, y; - + mach64->accel.dst_x = 0; mach64->accel.dst_y = 0; mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; - mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) { @@ -1006,7 +1016,7 @@ void mach64_start_fill(mach64_t *mach64) } mach64->accel.x_count = mach64->accel.dst_width; - + mach64->accel.src_x = 0; mach64->accel.src_y = 0; mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; @@ -1021,9 +1031,9 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff; mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff; - mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; + mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; - mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; + mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; mach64_log("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, mach64->accel.src_y_count, @@ -1031,24 +1041,24 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_height1, mach64->src_height1_width1, mach64->src_height2_width2); - + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; - + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; mach64->accel.mix_bg = mach64->dp_mix & 0x1f; - + mach64->accel.source_bg = mach64->dp_src & 7; mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; - + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; @@ -1057,42 +1067,63 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_offset <<= 3; else mach64->accel.src_offset >>= mach64->accel.src_size; - + if (mach64->accel.dst_size == WIDTH_1BIT) mach64->accel.dst_offset <<= 3; else mach64->accel.dst_offset >>= mach64->accel.dst_size; - + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; - mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; - + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); - - + + for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; - mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + mach64->accel.pattern[y][7 - x] = (temp >> (x + ((y & 3) * 8))) & 1; } } - + + if (mach64->pat_cntl & 2) { + mach64->accel.pattern_clr4x2[0][0] = (mach64->pat_reg0 & 0xff); + mach64->accel.pattern_clr4x2[0][1] = ((mach64->pat_reg0 >> 8) & 0xff); + mach64->accel.pattern_clr4x2[0][2] = ((mach64->pat_reg0 >> 16) & 0xff); + mach64->accel.pattern_clr4x2[0][3] = ((mach64->pat_reg0 >> 24) & 0xff); + mach64->accel.pattern_clr4x2[1][0] = (mach64->pat_reg1 & 0xff); + mach64->accel.pattern_clr4x2[1][1] = ((mach64->pat_reg1 >> 8) & 0xff); + mach64->accel.pattern_clr4x2[1][2] = ((mach64->pat_reg1 >> 16) & 0xff); + mach64->accel.pattern_clr4x2[1][3] = ((mach64->pat_reg1 >> 24) & 0xff); + } else if (mach64->pat_cntl & 4) { + mach64->accel.pattern_clr8x1[0] = (mach64->pat_reg0 & 0xff); + mach64->accel.pattern_clr8x1[1] = ((mach64->pat_reg0 >> 8) & 0xff); + mach64->accel.pattern_clr8x1[2] = ((mach64->pat_reg0 >> 16) & 0xff); + mach64->accel.pattern_clr8x1[3] = ((mach64->pat_reg0 >> 24) & 0xff); + mach64->accel.pattern_clr8x1[4] = (mach64->pat_reg1 & 0xff); + mach64->accel.pattern_clr8x1[5] = ((mach64->pat_reg1 >> 8) & 0xff); + mach64->accel.pattern_clr8x1[6] = ((mach64->pat_reg1 >> 16) & 0xff); + mach64->accel.pattern_clr8x1[7] = ((mach64->pat_reg1 >> 24) & 0xff); + } + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; - mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + mach64->accel.write_mask = mach64->write_mask; mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); - + mach64->accel.poly_draw = 0; - + mach64->accel.busy = 1; mach64_log("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); @@ -1102,7 +1133,7 @@ void mach64_start_fill(mach64_t *mach64) void mach64_start_line(mach64_t *mach64) { int x, y; - + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y = mach64->dst_y_x & 0xfff; @@ -1114,27 +1145,27 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; - + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; mach64->accel.mix_bg = mach64->dp_mix & 0x1f; - + mach64->accel.source_bg = mach64->dp_src & 7; mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; - + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; - + if (mach64->accel.src_size == WIDTH_1BIT) mach64->accel.src_offset <<= 3; else mach64->accel.src_offset >>= mach64->accel.src_size; - + if (mach64->accel.dst_size == WIDTH_1BIT) mach64->accel.dst_offset <<= 3; else @@ -1142,34 +1173,38 @@ void mach64_start_line(mach64_t *mach64) /* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ - + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); - + for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; - mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + mach64->accel.pattern[y][7 - x] = (temp >> (x + ((y & 3) * 8))) & 1; } } - + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; - + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; - mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; - + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + mach64->accel.write_mask = mach64->write_mask; + mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff; mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0); - + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + mach64->accel.busy = 1; mach64_log("mach64_start_line\n"); @@ -1181,7 +1216,7 @@ void mach64_start_line(mach64_t *mach64) else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; - + #define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ { \ case 0x0: dest_dat = ~dest_dat; break; \ @@ -1200,8 +1235,9 @@ void mach64_start_line(mach64_t *mach64) case 0xd: dest_dat = src_dat & ~dest_dat; break; \ case 0xe: dest_dat = ~src_dat & dest_dat; break; \ case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + case 0x17: dest_dat = (dest_dat + src_dat) >> 1; \ } - + #define WRITE(addr, width) if (width == 0) \ { \ svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ @@ -1237,7 +1273,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) { svga_t *svga = &mach64->svga; int cmp_clr = 0; - + if (!mach64->accel.busy) { mach64_log("mach64_blit : return as not busy\n"); @@ -1246,16 +1282,17 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) switch (mach64->accel.op) { case OP_RECT: - while (count) + while (count) { - uint32_t src_dat, dest_dat; + uint32_t src_dat = 0, dest_dat; uint32_t host_dat = 0; + uint32_t old_dest_dat; int mix = 0; int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff; int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; int src_x; int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; - + if (mach64->src_cntl & SRC_LINEAR_EN) src_x = mach64->accel.src_x; else @@ -1316,7 +1353,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) - { + { switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) { case SRC_HOST: @@ -1326,15 +1363,40 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); break; case SRC_FG: - src_dat = mach64->accel.dp_frgd_clr; + if ((mach64->dst_cntl & (DST_LAST_PEL | DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)) == (DST_LAST_PEL | DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)) { + if ((mach64->accel.x_count % 3) == 2) + src_dat = mach64->accel.dp_frgd_clr & 0xff; + else if ((mach64->accel.x_count % 3) == 1) + src_dat = (mach64->accel.dp_frgd_clr >> 8) & 0xff; + else if ((mach64->accel.x_count % 3) == 0) + src_dat = (mach64->accel.dp_frgd_clr >> 16) & 0xff; + } else + src_dat = mach64->accel.dp_frgd_clr; break; case SRC_BG: - src_dat = mach64->accel.dp_bkgd_clr; + if ((mach64->dst_cntl & (DST_LAST_PEL | DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)) == (DST_LAST_PEL | DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)) { + if ((mach64->accel.x_count % 3) == 2) + src_dat = mach64->accel.dp_bkgd_clr & 0xff; + else if ((mach64->accel.x_count % 3) == 1) + src_dat = (mach64->accel.dp_bkgd_clr >> 8) & 0xff; + else if ((mach64->accel.x_count % 3) == 0) + src_dat = (mach64->accel.dp_bkgd_clr >> 16) & 0xff; + } else + src_dat = mach64->accel.dp_bkgd_clr; break; + case SRC_PAT: + if (mach64->pat_cntl & 2) { + src_dat = mach64->accel.pattern_clr4x2[dst_y & 1][dst_x & 3]; + break; + } else if (mach64->pat_cntl & 4) { + src_dat = mach64->accel.pattern_clr8x1[dst_x & 7]; + break; + } default: src_dat = 0; break; } + if (mach64->dst_cntl & DST_POLYGON_EN) { int poly_src; @@ -1342,6 +1404,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (poly_src) mach64->accel.poly_draw = !mach64->accel.poly_draw; } + if (!(mach64->dst_cntl & DST_POLYGON_EN) || mach64->accel.poly_draw) { READ(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, dest_dat, mach64->accel.dst_size); @@ -1358,20 +1421,25 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; break; } - - if (!cmp_clr) - MIX + + if (!cmp_clr) { + old_dest_dat = dest_dat; + MIX + dest_dat = (dest_dat & mach64->accel.write_mask) | (old_dest_dat & ~mach64->accel.write_mask); + } WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size); } } - - if (mach64->dst_cntl & DST_24_ROT_EN) - { + + if (((mach64->crtc_gen_cntl >> 8) & 7) == BPP_24) { + if ((mach64->dst_cntl & (DST_LAST_PEL | DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)) != (DST_LAST_PEL | DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)) { mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); + mach64->accel.write_mask = ((mach64->accel.write_mask >> 8) & 0xffff) | (mach64->accel.write_mask << 16); + } } - + mach64->accel.src_x += mach64->accel.xinc; mach64->accel.dst_x += mach64->accel.xinc; if (!(mach64->src_cntl & SRC_LINEAR_EN)) @@ -1389,9 +1457,8 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.src_x_count = mach64->accel.src_width1; } } - + mach64->accel.x_count--; - if (mach64->accel.x_count <= 0) { mach64->accel.x_count = mach64->accel.dst_width; @@ -1403,7 +1470,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (!(mach64->src_cntl & SRC_LINEAR_EN)) { mach64->accel.src_x = 0; - mach64->accel.src_y += mach64->accel.yinc; + mach64->accel.src_y += mach64->accel.yinc; mach64->accel.src_y_count--; if (mach64->accel.src_y_count <= 0) { @@ -1419,9 +1486,9 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) } mach64->accel.poly_draw = 0; - + mach64->accel.dst_height--; - + if (mach64->accel.dst_height <= 0) { /*Blit finished*/ @@ -1445,17 +1512,17 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) } } } - } + } break; - + case OP_LINE: - while (count) - { + if (((mach64->crtc_gen_cntl >> 8) & 7) == BPP_24) { + int x = 0; + while (count) { uint32_t src_dat = 0, dest_dat; uint32_t host_dat = 0; int mix = 0; - int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); - + if (mach64->accel.source_host) { host_dat = cpu_dat; @@ -1480,129 +1547,266 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) switch (mach64->accel.source_mix) { case MONO_SRC_HOST: - mix = cpu_dat >> 31; - cpu_dat <<= 1; + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + { + mix = cpu_dat & 1; + cpu_dat >>= 1; + } + else + { + mix = cpu_dat >> 31; + cpu_dat <<= 1; + } break; case MONO_SRC_PAT: mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; break; case MONO_SRC_1: - default: mix = 1; break; - } - - if (mach64->dst_cntl & DST_POLYGON_EN) - { - if (mach64->dst_cntl & DST_Y_MAJOR) - draw_pixel = 1; - else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ - draw_pixel = 1; - else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ - draw_pixel = 1; - } - - if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL)) - draw_pixel = 0; - - if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right && - mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel) - { - switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) - { - case SRC_HOST: - src_dat = host_dat; - break; - case SRC_BLITSRC: - READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); - break; - case SRC_FG: - src_dat = mach64->accel.dp_frgd_clr; - break; - case SRC_BG: - src_dat = mach64->accel.dp_bkgd_clr; - break; - default: - src_dat = 0; - break; - } - - READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); - - switch (mach64->accel.clr_cmp_fn) - { - case 1: /*TRUE*/ - cmp_clr = 1; - break; - case 4: /*DST_CLR != CLR_CMP_CLR*/ - cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; - break; - case 5: /*DST_CLR == CLR_CMP_CLR*/ - cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; - break; - } - - if (!cmp_clr) - MIX - - WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); - } - - mach64->accel.x_count--; - if (mach64->accel.x_count <= 0) - { - /*Blit finished*/ - mach64_log("mach64 blit finished\n"); - mach64->accel.busy = 0; - return; - } - - switch (mach64->dst_cntl & 7) - { - case 0: case 2: - mach64->accel.src_x--; - mach64->accel.dst_x--; - break; - case 1: case 3: - mach64->accel.src_x++; - mach64->accel.dst_x++; - break; - case 4: case 5: - mach64->accel.src_y--; - mach64->accel.dst_y--; - break; - case 6: case 7: - mach64->accel.src_y++; - mach64->accel.dst_y++; + case MONO_SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, mix, WIDTH_1BIT); break; } - mach64_log("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); - if (mach64->accel.err >= 0) - { + + if ((mach64->accel.dst_x >= mach64->accel.sc_left) && (mach64->accel.dst_x <= mach64->accel.sc_right) && + (mach64->accel.dst_y >= mach64->accel.sc_top) && (mach64->accel.dst_y <= mach64->accel.sc_bottom)) { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + case SRC_PAT: + if (mach64->pat_cntl & 2) { + src_dat = mach64->accel.pattern_clr4x2[mach64->accel.dst_y & 1][mach64->accel.dst_x & 3]; + break; + } else if (mach64->pat_cntl & 4) { + src_dat = mach64->accel.pattern_clr8x1[mach64->accel.dst_x & 7]; + break; + } + default: + src_dat = 0; + break; + } + + READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + if (!(mach64->dst_cntl & DST_Y_MAJOR)) { + if (x == 0) + dest_dat &= ~1; + } else { + if (x == (mach64->accel.x_count - 1)) + dest_dat &= ~1; + } + + WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); + } + + x++; + if (x >= mach64->accel.x_count) { + mach64->accel.busy = 0; + mach64_log("mach64 line24 finished\n"); + return; + } + + if (mach64->dst_cntl & DST_Y_MAJOR) { + mach64->accel.dst_y += mach64->accel.yinc; + if (mach64->accel.err >= 0) { mach64->accel.err += mach64->dst_bres_dec; - - switch (mach64->dst_cntl & 7) - { - case 0: case 1: - mach64->accel.src_y--; - mach64->accel.dst_y--; - break; - case 2: case 3: - mach64->accel.src_y++; - mach64->accel.dst_y++; - break; - case 4: case 6: - mach64->accel.src_x--; - mach64->accel.dst_x--; - break; - case 5: case 7: - mach64->accel.src_x++; - mach64->accel.dst_x++; - break; - } - } - else + mach64->accel.dst_x += mach64->accel.xinc; + } else { mach64->accel.err += mach64->dst_bres_inc; + } + } else { + mach64->accel.dst_x += mach64->accel.xinc; + if (mach64->accel.err >= 0) { + mach64->accel.err += mach64->dst_bres_dec; + mach64->accel.dst_y += mach64->accel.yinc; + } else { + mach64->accel.err += mach64->dst_bres_inc; + } + } + } + } else { + while (count) + { + uint32_t src_dat = 0, dest_dat; + uint32_t host_dat = 0; + int mix = 0; + int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64->dst_cntl & DST_POLYGON_EN) + { + if (mach64->dst_cntl & DST_Y_MAJOR) + draw_pixel = 1; + else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ + draw_pixel = 1; + else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ + draw_pixel = 1; + } + + if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL)) + draw_pixel = 0; + + if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right && + mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); + } + + mach64->accel.x_count--; + if (mach64->accel.x_count <= 0) + { + /*Blit finished*/ + mach64_log("mach64 blit finished\n"); + mach64->accel.busy = 0; + return; + } + + switch (mach64->dst_cntl & 7) + { + case 0: case 2: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 1: case 3: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + case 4: case 5: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 6: case 7: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + } + mach64_log("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); + if (mach64->accel.err >= 0) + { + mach64->accel.err += mach64->dst_bres_dec; + + switch (mach64->dst_cntl & 7) + { + case 0: case 1: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 2: case 3: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + case 4: case 6: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 5: case 7: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + } + } + else + mach64->accel.err += mach64->dst_bres_inc; + } } break; } @@ -1612,7 +1816,7 @@ void mach64_load_context(mach64_t *mach64) { svga_t *svga = &mach64->svga; uint32_t addr; - + while (mach64->context_load_cntl & 0x30000) { addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; @@ -1671,7 +1875,7 @@ void mach64_load_context(mach64_t *mach64) mach64_accel_write_fifo_l(mach64, 0x308, *(uint32_t *)&svga->vram[addr + 0x68]); if (mach64->context_mask & (1 << 27)) mach64_accel_write_fifo_l(mach64, 0x330, *(uint32_t *)&svga->vram[addr + 0x6c]); - + mach64->context_load_cntl = *(uint32_t *)&svga->vram[addr + 0x70]; } } @@ -1683,7 +1887,7 @@ void mach64_load_context(mach64_t *mach64) static void pll_write(mach64_t *mach64, uint32_t addr, uint8_t val) { int c; - + switch (addr & 3) { case 0: /*Clock sel*/ @@ -1696,12 +1900,12 @@ static void pll_write(mach64_t *mach64, uint32_t addr, uint8_t val) mach64_log("pll_write %02x,%02x\n", mach64->pll_addr, val); for (c = 0; c < 4; c++) - { + { double m = (double)mach64->pll_regs[PLL_REF_DIV]; double n = (double)mach64->pll_regs[VCLK0_FB_DIV+c]; double r = 14318184.0; double p = (double)(1 << ((mach64->pll_regs[VCLK_POST_DIV] >> (c*2)) & 3)); - + mach64_log("PLLfreq %i = %g %g m=%02x n=%02x p=%02x\n", c, (2.0 * r * n) / (m * p), p, mach64->pll_regs[PLL_REF_DIV], mach64->pll_regs[VCLK0_FB_DIV+c], mach64->pll_regs[VCLK_POST_DIV]); mach64->pll_freq[c] = (2.0 * r * n) / (m * p); mach64_log(" %g\n", mach64->pll_freq[c]); @@ -1715,21 +1919,21 @@ static void mach64_vblank_start(svga_t *svga) { mach64_t *mach64 = (mach64_t *)svga->p; int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; - + mach64->crtc_int_cntl |= 4; mach64_update_irqs(mach64); - + svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff; svga->overlay.y = mach64->overlay_y_x_start & 0x7ff; - - svga->overlay.xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; - svga->overlay.ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; - + + svga->overlay.cur_xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; + svga->overlay.cur_ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; + svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; - + svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1); - + mach64->overlay_v_acc = 0; mach64->scaler_update = 1; } @@ -1738,7 +1942,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) { mach64_t *mach64 = (mach64_t *)p; - uint8_t ret; + uint8_t ret = 0xff; if (!(addr & 0x400)) { mach64_log("nmach64_ext_readb: addr=%04x\n", addr); @@ -1775,11 +1979,11 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0x28: case 0x29: case 0x2a: case 0x2b: READ8(addr, mach64->scaler_height_width); break; - + case 0x4a: ret = mach64->scaler_format; break; - + default: ret = 0xff; break; @@ -1800,11 +2004,11 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0x12: case 0x13: READ8(addr - 2, mach64->svga.vc); break; - + case 0x14: case 0x15: case 0x16: case 0x17: READ8(addr, mach64->crtc_off_pitch); break; - + case 0x18: ret = mach64->crtc_int_cntl & ~1; if (mach64->svga.cgastat & 8) @@ -1844,7 +2048,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0x79: ret = 0x30; break; - + case 0x80: case 0x81: case 0x82: case 0x83: READ8(addr, mach64->scratch_reg0); break; @@ -1866,12 +2070,21 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) else ret = ati68860_ramdac_in(addr & 3, mach64->svga.ramdac, &mach64->svga); break; - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - if (mach64->type == MACH64_VT2) - mach64->dac_cntl |= (4 << 24); + case 0xc4: case 0xc5: case 0xc6: READ8(addr, mach64->dac_cntl); break; + case 0xc7: + READ8(addr, mach64->dac_cntl); + if (mach64->type == MACH64_VT2) { + ret &= 0xf9; + if (i2c_gpio_get_scl(mach64->i2c)) + ret |= 0x04; + if (i2c_gpio_get_sda(mach64->i2c)) + ret |= 0x02; + } + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: READ8(addr, mach64->gen_test_cntl); break; @@ -1889,7 +2102,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0xe4: case 0xe5: case 0xe6: case 0xe7: READ8(addr, mach64->config_stat0); break; - + case 0x100: case 0x101: case 0x102: case 0x103: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dst_off_pitch); @@ -2008,6 +2221,11 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0x284: case 0x285: case 0x286: case 0x287: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->pat_reg1); + break; + + case 0x288: case 0x289: case 0x28a: case 0x28b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_cntl); break; case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: @@ -2017,7 +2235,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0x2a4: case 0x2a5: addr += 2; /*FALLTHROUGH*/ - case 0x2aa: case 0x2ab: + case 0x2aa: case 0x2ab: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->sc_left_right); break; @@ -2042,7 +2260,17 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dp_frgd_clr); break; - + + case 0x2c8: case 0x2c9: case 0x2ca: case 0x2cb: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->write_mask); + break; + + case 0x2cc: case 0x2cd: case 0x2ce: case 0x2cf: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->chain_mask); + break; + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dp_pix_width); @@ -2068,15 +2296,16 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_wait_fifo_idle(mach64); READ8(addr, mach64->clr_cmp_cntl); break; - - case 0x310: case 0x311: + + case 0x310: + case 0x311: if (!FIFO_EMPTY) wake_fifo_thread(mach64); ret = 0; if (FIFO_FULL) ret = 0xff; break; - + case 0x320: case 0x321: case 0x322: case 0x323: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->context_mask); @@ -2094,7 +2323,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_wait_fifo_idle(mach64); READ8(addr - 3, mach64->pat_cntl); break; - + case 0x338: ret = FIFO_EMPTY ? 0 : 1; break; @@ -2130,7 +2359,7 @@ uint16_t mach64_ext_readw(uint32_t addr, void *p) break; } if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readw : addr %08X ret %04X\n", addr, ret); - return ret; + return ret; } uint32_t mach64_ext_readl(uint32_t addr, void *p) { @@ -2255,7 +2484,7 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) svga_recalctimings(&mach64->svga); svga->fullchange = changeframecount; break; - + case 0x18: mach64->crtc_int_cntl = (mach64->crtc_int_cntl & 0x75) | (val & ~0x75); if (val & 4) @@ -2269,6 +2498,7 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) svga->fb_only = 1; else svga->fb_only = 0; + svga->dpms = !!(mach64->crtc_gen_cntl & 0x0c); svga_recalctimings(&mach64->svga); break; @@ -2295,19 +2525,16 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) case 0x68: case 0x69: case 0x6a: case 0x6b: WRITE8(addr, mach64->cur_offset, val); svga->dac_hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; - mach64_cursor_dump(mach64); break; case 0x6c: case 0x6d: case 0x6e: case 0x6f: WRITE8(addr, mach64->cur_horz_vert_posn, val); svga->dac_hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; svga->dac_hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; - mach64_cursor_dump(mach64); break; case 0x70: case 0x71: case 0x72: case 0x73: WRITE8(addr, mach64->cur_horz_vert_off, val); svga->dac_hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; svga->dac_hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; - mach64_cursor_dump(mach64); break; case 0x80: case 0x81: case 0x82: case 0x83: @@ -2360,6 +2587,7 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) WRITE8(addr, mach64->dac_cntl, val); svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); ati68860_set_ramdac_type(mach64->svga.ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + i2c_gpio_set(mach64->i2c, !(mach64->dac_cntl & 0x20000000) || (mach64->dac_cntl & 0x04000000), !(mach64->dac_cntl & 0x10000000) || (mach64->dac_cntl & 0x02000000)); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: @@ -2367,7 +2595,6 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); svga->dac_hwcursor.ena = mach64->gen_test_cntl & 0x80; - mach64_cursor_dump(mach64); break; case 0xdc: case 0xdd: case 0xde: case 0xdf: @@ -2387,7 +2614,7 @@ void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) mach64_log("mach64_ext_writew : addr %08X val %04X\n", addr, val); if (!(addr & 0x400)) { - mach64_log("nmach64_ext_writew: addr=%04x val=%04x\n", addr, val); + mach64_log("mach64_ext_writew: addr=%04x val=%04x\n", addr, val); mach64_ext_writeb(addr, val, p); mach64_ext_writeb(addr + 1, val >> 8, p); @@ -2411,7 +2638,7 @@ void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) mach64_log("mach64_ext_writel : addr %08X val %08X\n", addr, val); if (!(addr & 0x400)) { - mach64_log("nmach64_ext_writel: addr=%04x val=%08x\n", addr, val); + mach64_log("mach64_ext_writel: addr=%04x val=%08x\n", addr, val); mach64_ext_writew(addr, val, p); mach64_ext_writew(addr + 2, val >> 16, p); @@ -2431,7 +2658,7 @@ void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) uint8_t mach64_ext_inb(uint16_t port, void *p) { - mach64_t *mach64 = (mach64_t *)p; + mach64_t *mach64 = (mach64_t *)p; uint8_t ret; switch (port) @@ -2502,7 +2729,7 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: ret = mach64_ext_readb(0x400 | 0xb0 | (port & 3), p); break; - + case 0x56ec: ret = mach64_ext_readb(0x400 | 0xb4, p); break; @@ -2522,11 +2749,11 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) else ret = ati68860_ramdac_in(port & 3, mach64->svga.ramdac, &mach64->svga); break; - + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: ret = mach64_ext_readb(0x400 | 0xc4 | (port & 3), p); break; - + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: ret = mach64_ext_readb(0x400 | 0xd0 | (port & 3), p); break; @@ -2535,7 +2762,7 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); READ8(port, mach64->config_cntl); break; - + case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: ret = mach64_ext_readb(0x400 | 0xe0 | (port & 3), p); break; @@ -2562,7 +2789,7 @@ uint16_t mach64_ext_inw(uint16_t port, void *p) break; } mach64_log("mach64_ext_inw : port %04X ret %04X\n", port, ret); - return ret; + return ret; } uint32_t mach64_ext_inl(uint16_t port, void *p) { @@ -2606,7 +2833,7 @@ void mach64_ext_outb(uint16_t port, uint8_t val, void *p) case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: mach64_ext_writeb(0x400 | 0x14 | (port & 3), val, p); break; - + case 0x1aec: mach64_ext_writeb(0x400 | 0x18, val, p); break; @@ -2716,7 +2943,7 @@ static uint8_t mach64_block_inb(uint16_t port, void *p) { mach64_t *mach64 = (mach64_t *)p; uint8_t ret; - + ret = mach64_ext_readb(0x400 | (port & 0x3ff), mach64); mach64_log("mach64_block_inb : port %04X ret %02X\n", port, ret); return ret; @@ -2725,7 +2952,7 @@ static uint16_t mach64_block_inw(uint16_t port, void *p) { mach64_t *mach64 = (mach64_t *)p; uint16_t ret; - + ret = mach64_ext_readw(0x400 | (port & 0x3ff), mach64); mach64_log("mach64_block_inw : port %04X ret %04X\n", port, ret); return ret; @@ -2734,7 +2961,7 @@ static uint32_t mach64_block_inl(uint16_t port, void *p) { mach64_t *mach64 = (mach64_t *)p; uint32_t ret; - + ret = mach64_ext_readl(0x400 | (port & 0x3ff), mach64); mach64_log("mach64_block_inl : port %04X ret %08X\n", port, ret); return ret; @@ -2743,21 +2970,21 @@ static uint32_t mach64_block_inl(uint16_t port, void *p) static void mach64_block_outb(uint16_t port, uint8_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; - + mach64_log("mach64_block_outb : port %04X val %02X\n ", port, val); mach64_ext_writeb(0x400 | (port & 0x3ff), val, mach64); } static void mach64_block_outw(uint16_t port, uint16_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; - + mach64_log("mach64_block_outw : port %04X val %04X\n ", port, val); mach64_ext_writew(0x400 | (port & 0x3ff), val, mach64); } static void mach64_block_outl(uint16_t port, uint32_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; - + mach64_log("mach64_block_outl : port %04X val %08X\n ", port, val); mach64_ext_writel(0x400 | (port & 0x3ff), val, mach64); } @@ -2793,7 +3020,7 @@ uint8_t mach64_read(uint32_t addr, void *p) uint8_t ret; addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; ret = svga_read_linear(addr, svga); - return ret; + return ret; } uint16_t mach64_readw(uint32_t addr, void *p) { @@ -2823,7 +3050,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_ARGB1555() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) \ { \ uint16_t dat = ((uint16_t *)src)[x]; \ \ @@ -2842,7 +3069,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_RGB565() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) \ { \ uint16_t dat = ((uint16_t *)src)[x]; \ \ @@ -2861,7 +3088,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_ARGB8888() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) \ { \ int b = src[0]; \ int g = src[1]; \ @@ -2875,7 +3102,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_VYUY422() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x += 2) \ { \ uint8_t y1, y2; \ int8_t u, v; \ @@ -2913,7 +3140,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_YVYU422() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x += 2) \ { \ uint8_t y1, y2; \ int8_t u, v; \ @@ -2986,11 +3213,11 @@ void mach64_overlay_draw(svga_t *svga, int displine) case 0xc: DECODE_YVYU422(); break; - + default: mach64_log("Unknown Mach64 scaler format %x\n", mach64->scaler_format); /*Fill buffer with something recognisably wrong*/ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) mach64->overlay_dat[x] = 0xff00ff; break; } @@ -2998,7 +3225,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) if (overlay_cmp_mix == 2) { - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) { int h = h_acc >> 12; @@ -3011,7 +3238,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) { int h = h_acc >> 12; int gr_cmp = 0, vid_cmp = 0; @@ -3033,7 +3260,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) } vid_cmp = vid_cmp ? -1 : 0; gr_cmp = gr_cmp ? -1 : 0; - + switch (overlay_cmp_mix) { case 0x0: use_video = gr_cmp; break; @@ -3062,18 +3289,18 @@ void mach64_overlay_draw(svga_t *svga, int displine) h_acc = (h_max << 12); } } - + mach64->overlay_v_acc += v_inc; if (mach64->overlay_v_acc > (v_max << 12)) mach64->overlay_v_acc = v_max << 12; - + y_diff = (mach64->overlay_v_acc >> 12) - (old_y >> 12); if (mach64->scaler_format == 6) svga->overlay.addr += svga->overlay.pitch*4*y_diff; else svga->overlay.addr += svga->overlay.pitch*2*y_diff; - + mach64->scaler_update = y_diff; } @@ -3100,7 +3327,7 @@ static void mach64_io_remove(mach64_t *mach64) } io_removehandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); - + for (c = 0; c < 8; c++) { io_removehandler((c * 0x1000) + 0x0000 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); @@ -3118,11 +3345,11 @@ static void mach64_io_remove(mach64_t *mach64) static void mach64_io_set(mach64_t *mach64) { int c; - + mach64_io_remove(mach64); - + io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); - + if (!mach64->use_block_decoded_io) { for (c = 0; c < 8; c++) @@ -3148,25 +3375,25 @@ uint8_t mach64_pci_read(int func, int addr, void *p) { case 0x00: return 0x02; /*ATi*/ case 0x01: return 0x10; - + case 0x02: return mach64->pci_id & 0xff; case 0x03: return mach64->pci_id >> 8; - + case PCI_REG_COMMAND: return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ - + case 0x08: /*Revision ID*/ if (mach64->type == MACH64_GX) return 0; return 0x40; - + case 0x09: return 0; /*Programming interface*/ - + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ case 0x0b: return 0x03; - + case 0x10: return 0x00; /*Linear frame buffer address*/ case 0x11: return 0x00; case 0x12: return mach64->linear_base >> 16; @@ -3193,10 +3420,10 @@ uint8_t mach64_pci_read(int func, int addr, void *p) case 0x31: return 0x00; case 0x32: return mach64->pci_regs[0x32]; case 0x33: return mach64->pci_regs[0x33]; - + case 0x3c: return mach64->int_line; case 0x3d: return PCI_INTA; - + case 0x40: return mach64->use_block_decoded_io | mach64->io_base; } return 0; @@ -3277,7 +3504,7 @@ void mach64_pci_write(int func, int addr, uint8_t val, void *p) case 0x3c: mach64->int_line = val; break; - + case 0x40: if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) mach64_io_remove(mach64); @@ -3294,32 +3521,21 @@ static void *mach64_common_init(const device_t *info) { mach64_t *mach64 = malloc(sizeof(mach64_t)); memset(mach64, 0, sizeof(mach64_t)); - + mach64->vram_size = device_get_config_int("memory"); mach64->vram_mask = (mach64->vram_size << 20) - 1; - + svga_init(info, &mach64->svga, mach64, mach64->vram_size << 20, mach64_recalctimings, mach64_in, mach64_out, NULL, mach64_overlay_draw); + mach64->svga.dac_hwcursor.cur_ysize = 64; - if (info->flags & DEVICE_PCI) - mem_mapping_disable(&mach64->bios_rom.mapping); - - mach64->bit32 = (info->flags & DEVICE_PCI) || (info->flags & DEVICE_VLB); - - if (mach64->bit32) { - mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &mach64->svga); - mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); - mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); - mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); - } else { - mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, NULL, svga_write_linear, svga_writew_linear, NULL, NULL, MEM_MAPPING_EXTERNAL, &mach64->svga); - mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, NULL, mach64_ext_writeb, mach64_ext_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, mach64); - mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, NULL, mach64_ext_writeb, mach64_ext_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, mach64); - mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, NULL, mach64_ext_writeb, mach64_ext_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, mach64); - } + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); + mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); mem_mapping_disable(&mach64->mmio_mapping); mach64_io_set(mach64); @@ -3335,16 +3551,20 @@ static void *mach64_common_init(const device_t *info) mach64->pci_regs[0x33] = 0x00; mach64->svga.ramdac = device_add(&ati68860_ramdac_device); - mach64->svga.dac_hwcursor_draw = ati68860_hwcursor_draw; + mach64->svga.dac_hwcursor_draw = ati68860_hwcursor_draw; - mach64->svga.clock_gen = device_add(&ics2595_device); + mach64->svga.clock_gen = device_add(&ics2595_device); mach64->dst_cntl = 3; + mach64->i2c = i2c_gpio_init("ddc_ati_mach64"); + mach64->ddc = ddc_init(i2c_gpio_get_bus(mach64->i2c)); + mach64->wake_fifo_thread = thread_create_event(); mach64->fifo_not_full_event = thread_create_event(); + mach64->thread_run = 1; mach64->fifo_thread = thread_create(fifo_thread, mach64); - + return mach64; } @@ -3367,10 +3587,12 @@ static void *mach64gx_init(const device_t *info) mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/ if (info->flags & DEVICE_PCI) mach64->config_stat0 |= 0; /*PCI, 256Kx16 DRAM*/ - else if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_ISA)) + else if (info->flags & DEVICE_VLB) mach64->config_stat0 |= 1; /*VLB, 256Kx16 DRAM*/ + else if (info->flags & DEVICE_ISA) + mach64->config_stat0 |= 7; /*ISA 16-bit, 256k16 DRAM*/ - ati_eeprom_load(&mach64->eeprom, L"mach64.nvr", 1); + ati_eeprom_load(&mach64->eeprom, "mach64.nvr", 1); if (info->flags & DEVICE_PCI) rom_init(&mach64->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -3378,7 +3600,10 @@ static void *mach64gx_init(const device_t *info) rom_init(&mach64->bios_rom, BIOS_VLB_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); else if (info->flags & DEVICE_ISA) rom_init(&mach64->bios_rom, BIOS_ISA_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&mach64->bios_rom.mapping); + return mach64; } static void *mach64vt2_init(const device_t *info) @@ -3398,13 +3623,16 @@ static void *mach64vt2_init(const device_t *info) mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ mach64->config_stat0 = 4; mach64->use_block_decoded_io = 4; - - ati_eeprom_load(&mach64->eeprom, L"mach64vt.nvr", 1); + + ati_eeprom_load(&mach64->eeprom, "mach64vt.nvr", 1); rom_init(&mach64->bios_rom, BIOS_ROMVT2_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&mach64->bios_rom.mapping); + svga->vblank_start = mach64_vblank_start; - + return mach64; } @@ -3429,11 +3657,16 @@ void mach64_close(void *p) { mach64_t *mach64 = (mach64_t *)p; - svga_close(&mach64->svga); - - thread_kill(mach64->fifo_thread); - thread_destroy_event(mach64->wake_fifo_thread); + mach64->thread_run = 0; + thread_set_event(mach64->wake_fifo_thread); + thread_wait(mach64->fifo_thread); thread_destroy_event(mach64->fifo_not_full_event); + thread_destroy_event(mach64->wake_fifo_thread); + + svga_close(&mach64->svga); + + ddc_close(mach64->ddc); + i2c_gpio_close(mach64->i2c); free(mach64); } @@ -3441,7 +3674,7 @@ void mach64_close(void *p) void mach64_speed_changed(void *p) { mach64_t *mach64 = (mach64_t *)p; - + svga_recalctimings(&mach64->svga); } @@ -3452,95 +3685,114 @@ void mach64_force_redraw(void *p) mach64->svga.fullchange = changeframecount; } -static const device_config_t mach64gx_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - } - }, - { - "", "", -1 +// clang-format off +static const device_config_t mach64gx_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } }; -static const device_config_t mach64vt2_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - } - }, - { - "", "", -1 +static const device_config_t mach64vt2_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } +}; +// clang-format on + +const device_t mach64gx_isa_device = { + .name = "ATI Mach64GX ISA", + .internal_name = "mach64gx_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = 0, + .init = mach64gx_init, + .close = mach64_close, + .reset = NULL, + { .available = mach64gx_isa_available }, + .speed_changed = mach64_speed_changed, + .force_redraw = mach64_force_redraw, + .config = mach64gx_config }; -const device_t mach64gx_isa_device = -{ - "ATI Mach64GX ISA", - DEVICE_AT | DEVICE_ISA, - 0, - mach64gx_init, mach64_close, NULL, - mach64gx_isa_available, - mach64_speed_changed, - mach64_force_redraw, - mach64gx_config +const device_t mach64gx_vlb_device = { + .name = "ATI Mach64GX VLB", + .internal_name = "mach64gx_vlb", + .flags = DEVICE_VLB, + .local = 0, + .init = mach64gx_init, + .close = mach64_close, + .reset = NULL, + { .available = mach64gx_vlb_available }, + .speed_changed = mach64_speed_changed, + .force_redraw = mach64_force_redraw, + .config = mach64gx_config }; -const device_t mach64gx_vlb_device = -{ - "ATI Mach64GX VLB", - DEVICE_VLB, - 0, - mach64gx_init, mach64_close, NULL, - mach64gx_vlb_available, - mach64_speed_changed, - mach64_force_redraw, - mach64gx_config +const device_t mach64gx_pci_device = { + .name = "ATI Mach64GX PCI", + .internal_name = "mach64gx_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = mach64gx_init, + .close = mach64_close, + .reset = NULL, + { .available = mach64gx_available }, + .speed_changed = mach64_speed_changed, + .force_redraw = mach64_force_redraw, + .config = mach64gx_config }; -const device_t mach64gx_pci_device = -{ - "ATI Mach64GX PCI", - DEVICE_PCI, - 0, - mach64gx_init, mach64_close, NULL, - mach64gx_available, - mach64_speed_changed, - mach64_force_redraw, - mach64gx_config -}; - -const device_t mach64vt2_device = -{ - "ATI Mach64VT2", - DEVICE_PCI, - 0, - mach64vt2_init, mach64_close, NULL, - mach64vt2_available, - mach64_speed_changed, - mach64_force_redraw, - mach64vt2_config +const device_t mach64vt2_device = { + .name = "ATI Mach64VT2", + .internal_name = "mach64vt2", + .flags = DEVICE_PCI, + .local = 0, + .init = mach64vt2_init, + .close = mach64_close, + .reset = NULL, + { .available = mach64vt2_available }, + .speed_changed = mach64_speed_changed, + .force_redraw = mach64_force_redraw, + .config = mach64vt2_config }; diff --git a/src/video/vid_att20c49x_ramdac.c b/src/video/vid_att20c49x_ramdac.c index 0709fd0e1..509256f19 100644 --- a/src/video/vid_att20c49x_ramdac.c +++ b/src/video/vid_att20c49x_ramdac.c @@ -39,88 +39,112 @@ typedef struct enum { - ATT_490_1 = 0, - ATT_492_3 + ATT_490 = 0, + ATT_491, + ATT_492 }; +static void +att49x_ramdac_control(uint8_t val, void *p, svga_t *svga) +{ + att49x_ramdac_t *ramdac = (att49x_ramdac_t *) p; + ramdac->ctrl = val; + switch ((ramdac->ctrl >> 5) & 7) { + case 0: + case 1: + case 2: + case 3: + svga->bpp = 8; + break; + case 4: + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + svga->bpp = 24; + break; + } + if (ramdac->type == ATT_490 || ramdac->type == ATT_491) + svga_set_ramdac_type(svga, (val & 2) ? RAMDAC_8BIT : RAMDAC_6BIT); + svga_recalctimings(svga); +} + void -att49x_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga) +att49x_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) { att49x_ramdac_t *ramdac = (att49x_ramdac_t *) p; + uint8_t rs = (addr & 0x03); + rs |= ((!!rs2) << 2); - switch (addr) { - case 0x3C6: - if (ramdac->state == 4) { - ramdac->state = 0; - ramdac->ctrl = val; - if (ramdac->type == ATT_490_1) - svga_set_ramdac_type(svga, (val & 2) ? RAMDAC_8BIT : RAMDAC_6BIT); - switch (val) - { - case 0: - svga->bpp = 8; - break; - - case 0x20: - svga->bpp = 15; - break; - - case 0x40: - svga->bpp = 24; - break; - - case 0x60: - svga->bpp = 16; - break; - - case 0x80: - case 0xa0: - svga->bpp = 15; - break; - - case 0xc0: - svga->bpp = 16; - break; - - case 0xe0: - svga->bpp = 24; - break; - } - svga_recalctimings(svga); - return; - } + switch (rs) { + case 0x00: + case 0x01: + case 0x03: + case 0x04: + case 0x05: + case 0x07: + svga_out(addr, val, svga); ramdac->state = 0; break; - case 0x3C7: - case 0x3C8: - case 0x3C9: + case 0x02: + switch (ramdac->state) { + case 4: + att49x_ramdac_control(val, ramdac, svga); + break; + default: + svga_out(addr, val, svga); + break; + } + break; + case 0x06: + att49x_ramdac_control(val, ramdac, svga); ramdac->state = 0; break; } - - svga_out(addr, val, svga); } uint8_t -att49x_ramdac_in(uint16_t addr, void *p, svga_t *svga) +att49x_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) { att49x_ramdac_t *ramdac = (att49x_ramdac_t *) p; - uint8_t temp = svga_in(addr, svga); + uint8_t temp = 0xff; + uint8_t rs = (addr & 0x03); + rs |= ((!!rs2) << 2); - switch (addr) { - case 0x3C6: - if (ramdac->state == 4) { - ramdac->state = 0; - temp = ramdac->ctrl; - break; - } - ramdac->state++; + switch (rs) { + case 0x00: + case 0x01: + case 0x03: + case 0x04: + case 0x05: + case 0x07: + temp = svga_in(addr, svga); + ramdac->state = 0; break; - case 0x3C7: - case 0x3C8: - case 0x3C9: + case 0x02: + switch (ramdac->state) { + case 1: + case 2: case 3: + temp = 0x00; + ramdac->state++; + break; + case 4: + temp = ramdac->ctrl; + ramdac->state = 0; + break; + default: + temp = svga_in(addr, svga); + ramdac->state++; + break; + } + break; + case 0x06: + temp = ramdac->ctrl; ramdac->state = 0; break; } @@ -136,7 +160,7 @@ att49x_ramdac_init(const device_t *info) memset(ramdac, 0, sizeof(att49x_ramdac_t)); ramdac->type = info->local; - + return ramdac; } @@ -150,19 +174,44 @@ att49x_ramdac_close(void *priv) free(ramdac); } - -const device_t att490_ramdac_device = -{ - "AT&T 20c490/20c491 RAMDAC", - 0, ATT_490_1, - att49x_ramdac_init, att49x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t att490_ramdac_device = { + .name = "AT&T 20c490 RAMDAC", + .internal_name = "att490_ramdac", + .flags = 0, + .local = ATT_490, + .init = att49x_ramdac_init, + .close = att49x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t att492_ramdac_device = -{ - "AT&T 20c492/20c493 RAMDAC", - 0, ATT_492_3, - att49x_ramdac_init, att49x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t att491_ramdac_device = { + .name = "AT&T 20c491 RAMDAC", + .internal_name = "att491_ramdac", + .flags = 0, + .local = ATT_491, + .init = att49x_ramdac_init, + .close = att49x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t att492_ramdac_device = { + .name = "AT&T 20c492 RAMDAC", + .internal_name = "att492_ramdac", + .flags = 0, + .local = ATT_492, + .init = att49x_ramdac_init, + .close = att49x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_att2xc498_ramdac.c b/src/video/vid_att2xc498_ramdac.c new file mode 100644 index 000000000..3e4617f8c --- /dev/null +++ b/src/video/vid_att2xc498_ramdac.c @@ -0,0 +1,191 @@ +/* + * 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 a AT&T 2xc498 RAMDAC. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> + + +typedef struct +{ + int type; + int state; + int loop; + uint8_t ctrl; +} att498_ramdac_t; + +static void +att498_ramdac_control(uint8_t val, void *p, svga_t *svga) +{ + att498_ramdac_t *ramdac = (att498_ramdac_t *) p; + ramdac->ctrl = val; + + if (val == 0xff) + return; + + switch ((ramdac->ctrl >> 4) & 0x0f) { + default: + svga->bpp = 8; + break; + case 1: + if (ramdac->ctrl & 4) + svga->bpp = 15; + else + svga->bpp = 8; + break; + case 3: + case 6: + svga->bpp = 16; + break; + case 5: + case 7: + svga->bpp = 32; + break; + case 0x0e: + svga->bpp = 24; + break; + } + + svga_set_ramdac_type(svga, (ramdac->ctrl & 2) ? RAMDAC_8BIT : RAMDAC_6BIT); + svga_recalctimings(svga); +} + +void +att498_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) +{ + att498_ramdac_t *ramdac = (att498_ramdac_t *) p; + uint8_t rs = (addr & 0x03); + rs |= ((!!rs2) << 2); + + switch (rs) { + case 0x00: + case 0x01: + case 0x03: + case 0x04: + case 0x05: + case 0x07: + svga_out(addr, val, svga); + ramdac->state = 0; + break; + case 0x02: + switch (ramdac->state) { + case 4: + att498_ramdac_control(val, ramdac, svga); + break; + default: + svga_out(addr, val, svga); + break; + } + break; + case 0x06: + att498_ramdac_control(val, ramdac, svga); + break; + } +} + + +uint8_t +att498_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) +{ + att498_ramdac_t *ramdac = (att498_ramdac_t *) p; + uint8_t temp = 0xff; + uint8_t rs = (addr & 0x03); + rs |= ((!!rs2) << 2); + + switch (rs) { + case 0x00: + case 0x01: + case 0x03: + case 0x04: + case 0x05: + case 0x07: + temp = svga_in(addr, svga); + ramdac->state = 0; + break; + case 0x02: + switch (ramdac->state) { + case 4: + temp = ramdac->ctrl; + ramdac->state++; + break; + case 5: + temp = 0x84; + ramdac->state++; + break; + case 6: + temp = ramdac->ctrl; + ramdac->state = 0; + break; + default: + temp = svga_in(addr, svga); + ramdac->state++; + break; + } + break; + case 0x06: + temp = ramdac->ctrl; + ramdac->state = 0; + break; + } + + return temp; +} + + +static void * +att498_ramdac_init(const device_t *info) +{ + att498_ramdac_t *ramdac = (att498_ramdac_t *) malloc(sizeof(att498_ramdac_t)); + memset(ramdac, 0, sizeof(att498_ramdac_t)); + + ramdac->type = info->local; + + return ramdac; +} + + +static void +att498_ramdac_close(void *priv) +{ + att498_ramdac_t *ramdac = (att498_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + +const device_t att498_ramdac_device = { + .name = "AT&T 22c498 RAMDAC", + .internal_name = "att498_ramdac", + .flags = 0, + .local = 0, + .init = att498_ramdac_init, + .close = att498_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_av9194.c b/src/video/vid_av9194.c index 0d89b2086..a736effa2 100644 --- a/src/video/vid_av9194.c +++ b/src/video/vid_av9194.c @@ -33,7 +33,7 @@ float av9194_getclock(int clock, void *p) { float ret = 0.0; - + switch (clock & 0x0f) { case 0: @@ -82,7 +82,7 @@ av9194_getclock(int clock, void *p) ret = 94500000.0; break; } - + return ret; } @@ -95,11 +95,16 @@ av9194_init(const device_t *info) } -const device_t av9194_device = -{ - "AV9194 Clock Generator", - 0, 0, - av9194_init, NULL, - NULL, NULL, NULL, NULL +const device_t av9194_device = { + .name = "AV9194 Clock Generator", + .internal_name = "av9194", + .flags = 0, + .local = 0, + .init = av9194_init, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/vid_bt48x_ramdac.c index 310d72a2e..43b02fa6e 100644 --- a/src/video/vid_bt48x_ramdac.c +++ b/src/video/vid_bt48x_ramdac.c @@ -169,10 +169,9 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t * ramdac->cmd_r3 = val; if (ramdac->type >= BT485A) bt48x_set_bpp(ramdac, svga); - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = (val & 4) ? 64 : 32; - svga->dac_hwcursor.yoff = (svga->dac_hwcursor.ysize == 32) ? 32 : 0; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = (val & 4) ? 64 : 32; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; svga->dac_addr = (svga->dac_addr & 0x00ff) | ((val & 0x03) << 8); svga_recalctimings(svga); break; @@ -192,7 +191,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t * break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ index = svga->dac_addr & da_mask; - if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.cur_xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; else { index &= 0xff; @@ -205,19 +204,19 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t * break; case 0x0c: /* Cursor X Low Register (RS value = 1100) */ ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 0x0d: /* Cursor X High Register (RS value = 1101) */ ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; case 0x0f: /* Cursor Y High Register (RS value = 1111) */ ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; } @@ -319,7 +318,7 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga) break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ index = (svga->dac_addr - 1) & da_mask; - if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.cur_xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; else { index &= 0xff; @@ -377,21 +376,21 @@ bt48x_hwcursor_draw(svga_t *svga, int displine) /* The planes come in two parts, and each plane is 1bpp, so a 32x32 cursor has 4 bytes per line, and a 64x64 cursor has 8 bytes per line. */ - pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */ /* A 32x32 cursor has 128 bytes per line, and a 64x64 cursor has 512 bytes per line. */ - bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */ mode = ramdac->cmd_r2 & 0x03; if (svga->interlace && svga->dac_hwcursor_oddeven) svga->dac_hwcursor_latch.addr += pitch; - if (svga->dac_hwcursor_latch.xsize == 64) + if (svga->dac_hwcursor_latch.cur_xsize == 64) cd = (uint8_t *) ramdac->cursor64_data; else cd = (uint8_t *) ramdac->cursor32_data; - for (x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + for (x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) { dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1]; dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | @@ -500,43 +499,72 @@ bt48x_ramdac_close(void *priv) free(ramdac); } - -const device_t bt484_ramdac_device = -{ - "Brooktree Bt484 RAMDAC", - 0, BT484, - bt48x_ramdac_init, bt48x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t bt484_ramdac_device = { + .name = "Brooktree Bt484 RAMDAC", + .internal_name = "bt484_ramdac", + .flags = 0, + .local = BT484, + .init = bt48x_ramdac_init, + .close = bt48x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t att20c504_ramdac_device = -{ - "AT&T 20c504 RAMDAC", - 0, ATT20C504, - bt48x_ramdac_init, bt48x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t att20c504_ramdac_device = { + .name = "AT&T 20c504 RAMDAC", + .internal_name = "att20c504_ramdac", + .flags = 0, + .local = ATT20C504, + .init = bt48x_ramdac_init, + .close = bt48x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t bt485_ramdac_device = -{ - "Brooktree Bt485 RAMDAC", - 0, BT485, - bt48x_ramdac_init, bt48x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t bt485_ramdac_device = { + .name = "Brooktree Bt485 RAMDAC", + .internal_name = "bt485_ramdac", + .flags = 0, + .local = BT485, + .init = bt48x_ramdac_init, + .close = bt48x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t att20c505_ramdac_device = -{ - "AT&T 20c505 RAMDAC", - 0, ATT20C505, - bt48x_ramdac_init, bt48x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t att20c505_ramdac_device = { + .name = "AT&T 20c505 RAMDAC", + .internal_name = "att20c505_ramdac", + .flags = 0, + .local = ATT20C505, + .init = bt48x_ramdac_init, + .close = bt48x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const device_t bt485a_ramdac_device = -{ - "Brooktree Bt485A RAMDAC", - 0, BT485A, - bt48x_ramdac_init, bt48x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t bt485a_ramdac_device = { + .name = "Brooktree Bt485A RAMDAC", + .internal_name = "bt485a_ramdac", + .flags = 0, + .local = BT485A, + .init = bt48x_ramdac_init, + .close = bt48x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index c62e12582..d7827732d 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -41,7 +41,7 @@ #define COMPOSITE_OLD 0 #define COMPOSITE_NEW 1 -static uint8_t crtcmask[32] = +static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -58,6 +58,9 @@ cga_out(uint16_t addr, uint8_t val, void *p) cga_t *cga = (cga_t *) p; uint8_t old; + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + switch (addr) { case 0x3D4: cga->crtcreg = val & 31; @@ -67,7 +70,7 @@ cga_out(uint16_t addr, uint8_t val, void *p) cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; if (old != val) { if ((cga->crtcreg < 0xe) || (cga->crtcreg > 0x10)) { - fullchange = changeframecount; + cga->fullchange = changeframecount; cga_recalctimings(cga); } } @@ -100,6 +103,9 @@ cga_in(uint16_t addr, void *p) uint8_t ret = 0xff; + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + switch (addr) { case 0x3D4: ret = cga->crtcreg; @@ -123,7 +129,7 @@ cga_waitstates(void *p) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + cycles -= ws; } @@ -138,7 +144,6 @@ cga_write(uint32_t addr, uint8_t val, void *p) cga->charbuffer[offset] = cga->vram[addr & 0x3fff]; cga->charbuffer[offset | 1] = cga->vram[addr & 0x3fff]; } - egawrites++; cga_waitstates(cga); } @@ -154,7 +159,6 @@ cga_read(uint32_t addr, void *p) cga->charbuffer[offset] = cga->vram[addr & 0x3fff]; cga->charbuffer[offset | 1] = cga->vram[addr & 0x3fff]; } - egareads++; return cga->vram[addr & 0x3fff]; } @@ -200,7 +204,7 @@ cga_poll(void *p) cga->cgastat |= 1; cga->linepos = 1; oldsc = cga->sc; - if ((cga->crtc[8] & 3) == 3) + if ((cga->crtc[8] & 3) == 3) cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; if (cga->cgadispon) { if (cga->displine < cga->firstline) { @@ -233,7 +237,7 @@ cga_poll(void *p) } if (cga->cgamode & 1) { for (x = 0; x < cga->crtc[1]; x++) { - if (cga->cgamode & 8) { + if (cga->cgamode & 8) { chr = cga->charbuffer[x << 1]; attr = cga->charbuffer[(x << 1) + 1]; } else @@ -242,7 +246,7 @@ cga_poll(void *p) cols[1] = (attr & 15) + 16; if (cga->cgamode & 0x20) { cols[0] = ((attr >> 4) & 7) + 16; - if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) cols[1] = cols[0]; } else cols[0] = (attr >> 4) + 16; @@ -329,7 +333,7 @@ cga_poll(void *p) } else { cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; for (x = 0; x < cga->crtc[1]; x++) { - if (cga->cgamode & 8) + if (cga->cgamode & 8) dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; else dat = 0; @@ -372,7 +376,7 @@ cga_poll(void *p) if (cga->vc == cga->crtc[7] && !cga->sc) cga->cgastat |= 8; cga->displine++; - if (cga->displine >= 360) + if (cga->displine >= 360) cga->displine = 0; } else { timer_advance_u64(&cga->timer, cga->dispontime); @@ -383,8 +387,8 @@ cga_poll(void *p) cga->cgastat &= ~8; } if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) { - cga->con = 0; - cga->coff = 1; + cga->con = 0; + cga->coff = 1; } if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) cga->maback = cga->ma; @@ -405,7 +409,7 @@ cga_poll(void *p) cga->vc++; cga->vc &= 127; - if (cga->vc == cga->crtc[6]) + if (cga->vc == cga->crtc[6]) cga->cgadispon = 0; if (oldvc == cga->crtc[4]) { @@ -458,18 +462,18 @@ cga_poll(void *p) } if (enable_overscan) { - if (cga->composite) - video_blit_memtoscreen(0, (cga->firstline - 4) << 1, 0, ((cga->lastline - cga->firstline) + 8) << 1, + if (cga->composite) + video_blit_memtoscreen(0, (cga->firstline - 4) << 1, xsize, ((cga->lastline - cga->firstline) + 8) << 1); else - video_blit_memtoscreen_8(0, (cga->firstline - 4) << 1, 0, ((cga->lastline - cga->firstline) + 8) << 1, + video_blit_memtoscreen_8(0, (cga->firstline - 4) << 1, xsize, ((cga->lastline - cga->firstline) + 8) << 1); } else { - if (cga->composite) - video_blit_memtoscreen(8, cga->firstline << 1, 0, (cga->lastline - cga->firstline) << 1, + if (cga->composite) + video_blit_memtoscreen(8, cga->firstline << 1, xsize, (cga->lastline - cga->firstline) << 1); else - video_blit_memtoscreen_8(8, cga->firstline << 1, 0, (cga->lastline - cga->firstline) << 1, + video_blit_memtoscreen_8(8, cga->firstline << 1, xsize, (cga->lastline - cga->firstline) << 1); } } @@ -504,7 +508,7 @@ cga_poll(void *p) } if (cga->cgadispon) cga->cgastat &= ~1; - if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) cga->con = 1; if (cga->cgadispon && (cga->cgamode & 1)) { for (x = 0; x < (cga->crtc[1] << 1); x++) @@ -571,78 +575,99 @@ cga_speed_changed(void *p) cga_recalctimings(cga); } - -const device_config_t cga_config[] = -{ - { - "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, - { - { - "RGB", CGA_RGB - }, - { - "Composite", CGA_COMPOSITE - }, - { - "" - } - } - }, - { - "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, - { - { - "Old", COMPOSITE_OLD - }, - { - "New", COMPOSITE_NEW - }, - { - "" - } - } - }, - { - "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, - { - { - "Color", 0 - }, - { - "Green Monochrome", 1 - }, - { - "Amber Monochrome", 2 - }, - { - "Gray Monochrome", 3 - }, - { - "Color (no brown)", 4 - }, - { - "" - } - } - }, - { - "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 +// clang-format off +const device_config_t cga_config[] = { + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_int = CGA_RGB, + .selection = { + { + .description = "RGB", + .value = CGA_RGB + }, + { + .description = "Composite", + .value = CGA_COMPOSITE + }, + { + .description = "" + } } + }, + { + .name = "composite_type", + .description = "Composite type", + .type = CONFIG_SELECTION, + .default_int = COMPOSITE_OLD, + .selection = { + { + .description = "Old", + .value = COMPOSITE_OLD + }, + { + .description = "New", + .value = COMPOSITE_NEW + }, + { + .description = "" + } + } + }, + { + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "Color", + .value = 0 + }, + { + .description = "Green Monochrome", + .value = 1 + }, + { + .description = "Amber Monochrome", + .value = 2 + }, + { + .description = "Gray Monochrome", + .value = 3 + }, + { + .description = "Color (no brown)", + .value = 4 + }, + { + .description = "" + } + } + }, + { + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = CONFIG_END + } }; +// clang-format on - -const device_t cga_device = -{ - "CGA", - DEVICE_ISA, 0, - cga_standalone_init, - cga_close, - NULL, - NULL, - cga_speed_changed, - NULL, - cga_config +const device_t cga_device = { + .name = "CGA", + .internal_name = "cga", + .flags = DEVICE_ISA, + .local = 0, + .init = cga_standalone_init, + .close = cga_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = cga_speed_changed, + .force_redraw = NULL, + .config = cga_config }; diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 09acdc3e0..709e2a972 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -11,11 +11,13 @@ * * * - * Authors: TheCollector1995, - * Miran Grca, + * Authors: Miran Grca, + * tonioni, + * TheCollector1995, * - * Copyright 2016-2020 TheCollector1995. * Copyright 2016-2020 Miran Grca. + * Copyright 2020 tonioni. + * Copyright 2016-2020 TheCollector1995. */ #include #include @@ -33,30 +35,32 @@ #include <86box/device.h> #include <86box/timer.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> -#define BIOS_GD5401_PATH L"roms/video/cirruslogic/avga1.rom" -#define BIOS_GD5402_PATH L"roms/video/cirruslogic/avga2.rom" -#define BIOS_GD5402_ONBOARD_PATH L"roms/video/machines/cbm_sl386sx25/Commodore386SX-25_AVGA2.bin" -#define BIOS_GD5420_PATH L"roms/video/cirruslogic/5420.vbi" - -#if defined(DEV_BRANCH) && defined(USE_CL5422) -#define BIOS_GD5422_PATH L"roms/video/cirruslogic/cl5422.bin" -#endif - -#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" -#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.bin" -#define BIOS_GD5428_PATH L"roms/video/cirruslogic/vlbusjapan.BIN" -#define BIOS_GD5429_PATH L"roms/video/cirruslogic/5429.vbi" -#define BIOS_GD5430_VLB_PATH L"roms/video/cirruslogic/diamondvlbus.bin" -#define BIOS_GD5430_PCI_PATH L"roms/video/cirruslogic/pci.bin" -#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" -#define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" -#define BIOS_GD5440_PATH L"roms/video/cirruslogic/BIOS.BIN" -#define BIOS_GD5446_PATH L"roms/video/cirruslogic/5446BV.VBI" -#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" -#define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" +#define BIOS_GD5401_PATH "roms/video/cirruslogic/avga1.rom" +#define BIOS_GD5402_PATH "roms/video/cirruslogic/avga2.rom" +#define BIOS_GD5402_ONBOARD_PATH "roms/machines/cmdsl386sx25/c000.rom" +#define BIOS_GD5420_PATH "roms/video/cirruslogic/5420.vbi" +#define BIOS_GD5422_PATH "roms/video/cirruslogic/cl5422.bin" +#define BIOS_GD5426_DIAMOND_A1_ISA_PATH "roms/video/cirruslogic/diamond5426.vbi" +#define BIOS_GD5426_MCA_PATH "roms/video/cirruslogic/Reply.BIN" +#define BIOS_GD5428_DIAMOND_B1_VLB_PATH "roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_ISA_PATH "roms/video/cirruslogic/5428.bin" +#define BIOS_GD5428_MCA_PATH "roms/video/cirruslogic/SVGA141.ROM" +#define BIOS_GD5428_PATH "roms/video/cirruslogic/vlbusjapan.BIN" +#define BIOS_GD5429_PATH "roms/video/cirruslogic/5429.vbi" +#define BIOS_GD5430_DIAMOND_A8_VLB_PATH "roms/video/cirruslogic/diamondvlbus.bin" +#define BIOS_GD5430_PATH "roms/video/cirruslogic/pci.bin" +#define BIOS_GD5434_DIAMOND_A3_ISA_PATH "roms/video/cirruslogic/Diamond Multimedia SpeedStar 64 v2.02 EPROM Backup from ST M27C256B-12F1.BIN" +#define BIOS_GD5434_PATH "roms/video/cirruslogic/gd5434.BIN" +#define BIOS_GD5436_PATH "roms/video/cirruslogic/5436.vbi" +#define BIOS_GD5440_PATH "roms/video/cirruslogic/BIOS.BIN" +#define BIOS_GD5446_PATH "roms/video/cirruslogic/5446bv.vbi" +#define BIOS_GD5446_STB_PATH "roms/video/cirruslogic/stb nitro64v.BIN" +#define BIOS_GD5480_PATH "roms/video/cirruslogic/clgd5480.rom" #define CIRRUS_ID_CLGD5401 0x88 #define CIRRUS_ID_CLGD5402 0x89 @@ -67,6 +71,8 @@ #define CIRRUS_ID_CLGD5428 0x98 #define CIRRUS_ID_CLGD5429 0x9c #define CIRRUS_ID_CLGD5430 0xa0 +#define CIRRUS_ID_CLGD5432 0xa2 +#define CIRRUS_ID_CLGD5434_4 0xa4 #define CIRRUS_ID_CLGD5434 0xa8 #define CIRRUS_ID_CLGD5436 0xac #define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */ @@ -89,7 +95,7 @@ #define CIRRUS_CURSOR_HIDDENPEL 0x02 #define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ -// sequencer 0x17 +/* sequencer 0x17 */ #define CIRRUS_BUSTYPE_VLBFAST 0x10 #define CIRRUS_BUSTYPE_PCI 0x20 #define CIRRUS_BUSTYPE_VLBSLOW 0x30 @@ -98,7 +104,7 @@ #define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */ #define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 -// control 0x0b +/* control 0x0b */ #define CIRRUS_BANKING_DUAL 0x01 #define CIRRUS_BANKING_GRANULARITY_16K 0x20 /* set:16k, clear:4k */ @@ -115,7 +121,7 @@ #define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 #define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 -// control 0x31 +/* control 0x31 */ #define CIRRUS_BLT_BUSY 0x01 #define CIRRUS_BLT_START 0x02 #define CIRRUS_BLT_RESET 0x04 @@ -124,7 +130,7 @@ #define CIRRUS_BLT_APERTURE2 0x40 #define CIRRUS_BLT_AUTOSTART 0x80 -// control 0x33 +/* control 0x33 */ #define CIRRUS_BLTMODEEXT_BACKGROUNDONLY 0x08 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 @@ -146,6 +152,7 @@ typedef struct gd54xx_t mem_mapping_t mmio_mapping; mem_mapping_t linear_mapping; mem_mapping_t aperture2_mapping; + mem_mapping_t vgablt_mapping; svga_t svga; @@ -157,16 +164,16 @@ typedef struct gd54xx_t uint32_t vram_mask; uint8_t vclk_n[4]; - uint8_t vclk_d[4]; + uint8_t vclk_d[4]; struct { uint8_t state; int ctrl; - } ramdac; - + } ramdac; + struct { uint16_t width, height; - uint16_t dst_pitch, src_pitch; + uint16_t dst_pitch, src_pitch; uint16_t trans_col, trans_mask; uint16_t height_internal; uint16_t msd_buf_pos, msd_buf_cnt; @@ -187,25 +194,39 @@ typedef struct gd54xx_t int unlock_special; } blt; - int pci, vlb, mca; - int countminusone; + struct { + int mode; + uint16_t stride, r1sz, r1adjust, r2sz, + r2adjust, r2sdz, wvs, wve, + hzoom, vzoom; + uint8_t occlusion, colorkeycomparemask, + colorkeycompare; + int region1size, region2size, + colorkeymode; + uint32_t ck; + } overlay; + + int pci, vlb, mca, countminusone; + int vblank_irq, vportsync; uint8_t pci_regs[256]; - uint8_t int_line, unlocked; + uint8_t int_line, unlocked, status, extensions; + uint8_t crtcreg_mask; uint8_t fc; /* Feature Connector */ - int card; - - uint8_t pos_regs[8]; - svga_t *mb_vga; + int card, id; - uint32_t lfb_base; + uint8_t pos_regs[8]; + + uint32_t lfb_base, vgablt_base; int mmio_vram_overlap; uint32_t extpallook[256]; PALETTE extpal; + + void *i2c, *ddc; } gd54xx_t; @@ -214,13 +235,13 @@ static video_timings_t timing_gd54xx_vlb = {VIDEO_BUS, 4, 4, 8, 10, 10, 20}; static video_timings_t timing_gd54xx_pci = {VIDEO_PCI, 4, 4, 8, 10, 10, 20}; -static void +static void gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); -static void +static void gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *p); -static void +static void gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); -static void +static void gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); static uint8_t gd543x_mmio_read(uint32_t addr, void *p); @@ -229,18 +250,278 @@ gd543x_mmio_readw(uint32_t addr, void *p); static uint32_t gd543x_mmio_readl(uint32_t addr, void *p); -static void +static void gd54xx_recalc_banking(gd54xx_t *gd54xx); -static void +static void gd543x_recalc_mapping(gd54xx_t *gd54xx); static void gd54xx_reset_blit(gd54xx_t *gd54xx); -static void +static void gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga); +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y3 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y3 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y3 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y4 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y4 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y4 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_CLUT() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint8_t dat; \ + \ + dat = *(uint8_t *)src; \ + src++; \ + \ + r[x_write + c] = svga->pallook[dat] >> 0; \ + g[x_write + c] = svga->pallook[dat] >> 8; \ + b[x_write + c] = svga->pallook[dat] >> 16; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + + + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (gd54xx->overlay.mode) \ + { \ + case 0: \ + DECODE_YUV422(); \ + break; \ + case 2: \ + DECODE_CLUT(); \ + break; \ + case 3: \ + DECODE_YUV211(); \ + break; \ + case 4: \ + DECODE_RGB555(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + } \ + } while (0) + + +static int +gd54xx_interrupt_enabled(gd54xx_t *gd54xx) +{ + return !gd54xx->pci || (gd54xx->svga.gdcreg[0x17] & 0x04); +} + + +static int +gd54xx_vga_vsync_enabled(gd54xx_t *gd54xx) +{ + if (!(gd54xx->svga.crtc[0x11] & 0x20) && (gd54xx->svga.crtc[0x11] & 0x10) && + gd54xx_interrupt_enabled(gd54xx)) + return 1; + return 0; +} + + +static void +gd54xx_update_irqs(gd54xx_t *gd54xx) +{ + if (!gd54xx->pci) + return; + + if ((gd54xx->vblank_irq > 0) && gd54xx_vga_vsync_enabled(gd54xx)) + pci_set_irq(gd54xx->card, PCI_INTA); + else + pci_clear_irq(gd54xx->card, PCI_INTA); +} + + +static void +gd54xx_vblank_start(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t*) svga->p; + if (gd54xx->vblank_irq >= 0) { + gd54xx->vblank_irq = 1; + gd54xx_update_irqs(gd54xx); + } +} + + /* Returns 1 if the card is a 5422+ */ static int gd54xx_is_5422(svga_t *svga) @@ -252,6 +533,86 @@ gd54xx_is_5422(svga_t *svga) } +static void +gd54xx_overlay_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *) svga->p; + int shift = (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446) ? 2 : 0; + int h_acc = svga->overlay_latch.h_acc; + int r[8], g[8], b[8]; + int x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[(svga->overlay_latch.addr << shift) & svga->vram_mask]; + int bpp = svga->bpp; + int bytesperpix = (bpp + 7) / 8; + uint8_t *src2 = &svga->vram[(svga->ma - (svga->hdisp * bytesperpix)) & svga->vram_display_mask]; + int occl, ckval; + + p = &((uint32_t *)buffer32->line[displine])[gd54xx->overlay.region1size + svga->x_add]; + src2 += gd54xx->overlay.region1size * bytesperpix; + + OVERLAY_SAMPLE(); + + for (x = 0; (x < gd54xx->overlay.region2size) && + ((x + gd54xx->overlay.region1size) < svga->hdisp); x++) { + if (gd54xx->overlay.occlusion) { + occl = 1; + ckval = gd54xx->overlay.ck; + if (bytesperpix == 1) { + if (*src2 == ckval) + occl = 0; + } else if (bytesperpix == 2) { + if (*((uint16_t*)src2) == ckval) + occl = 0; + } else + occl = 0; + if (!occl) + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + src2 += bytesperpix; + } else + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += gd54xx->overlay.hzoom; + if (h_acc >= 256) { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc -= 256; + } + } + + svga->overlay_latch.v_acc += gd54xx->overlay.vzoom; + if (svga->overlay_latch.v_acc >= 256) { + svga->overlay_latch.v_acc -= 256; + svga->overlay_latch.addr += svga->overlay.pitch << 1; + } +} + + +static void +gd54xx_update_overlay(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + int bpp = svga->bpp; + + svga->overlay.cur_ysize = gd54xx->overlay.wve - gd54xx->overlay.wvs + 1; + gd54xx->overlay.region1size = 32 * gd54xx->overlay.r1sz / bpp + (gd54xx->overlay.r1adjust * 8 / bpp); + gd54xx->overlay.region2size = 32 * gd54xx->overlay.r2sz / bpp + (gd54xx->overlay.r2adjust * 8 / bpp); + + gd54xx->overlay.occlusion = (svga->crtc[0x3e] & 0x80) != 0 && svga->bpp <= 16; + + /* Mask and chroma key ignored. */ + if (gd54xx->overlay.colorkeymode == 0) + gd54xx->overlay.ck = gd54xx->overlay.colorkeycompare; + else if (gd54xx->overlay.colorkeymode == 1) + gd54xx->overlay.ck = gd54xx->overlay.colorkeycompare | (gd54xx->overlay.colorkeycomparemask << 8); + else + gd54xx->overlay.occlusion = 0; +} + + /* Returns 1 if the card supports the 8-bpp/16-bpp transparency color or mask. */ static int gd54xx_has_transp(svga_t *svga, int mask) @@ -287,7 +648,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) uint8_t o, index; uint32_t o32; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { @@ -303,7 +664,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } else { o = svga->attrregs[svga->attraddr & 31]; svga->attrregs[svga->attraddr & 31] = val; - if (svga->attraddr < 16) + if (svga->attraddr < 16) svga->fullchange = changeframecount; if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { for (c = 0; c < 16; c++) { @@ -328,6 +689,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } svga->attrff ^= 1; return; + case 0x3c4: svga->seqaddr = val; break; @@ -353,6 +715,10 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429) gd54xx->unlocked = (svga->seqregs[6] == 0x12); break; + case 0x08: + if (gd54xx->i2c) + i2c_gpio_set(gd54xx->i2c, !!(val & 0x01), !!(val & 0x02)); + break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ gd54xx->vclk_n[svga->seqaddr-0x0b] = val; break; @@ -376,11 +742,10 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga_recalctimings(svga); svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) - svga->hwcursor.xsize = svga->hwcursor.ysize = + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((val & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) ? 64 : 32; else - svga->hwcursor.xsize = 32; - svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; + svga->hwcursor.cur_xsize = 32; if ((svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); @@ -394,12 +759,15 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((val & 0x3f) * 256)); break; case 0x07: + svga->packed_chain4 = svga->seqregs[7] & 1; + svga_recalctimings(svga); if (gd54xx_is_5422(svga)) gd543x_recalc_mapping(gd54xx); else svga->seqregs[svga->seqaddr] &= 0x0f; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) svga->set_reset_disabled = svga->seqregs[7] & 1; + break; case 0x17: if (gd54xx_is_5422(svga)) gd543x_recalc_mapping(gd54xx); @@ -431,11 +799,11 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) switch (svga->dac_pos) { case 0: svga->dac_r = val; - svga->dac_pos++; + svga->dac_pos++; break; case 1: svga->dac_g = val; - svga->dac_pos++; + svga->dac_pos++; break; case 2: index = svga->dac_addr & 0xff; @@ -443,7 +811,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) index &= 0x0f; gd54xx->extpal[index].r = svga->dac_r; gd54xx->extpal[index].g = svga->dac_g; - gd54xx->extpal[index].b = val; + gd54xx->extpal[index].b = val; gd54xx->extpallook[index] = makecol32(video_6to8[gd54xx->extpal[index].r & 0x3f], video_6to8[gd54xx->extpal[index].g & 0x3f], video_6to8[gd54xx->extpal[index].b & 0x3f]); if (svga->ext_overscan && (index == 2)) { o32 = svga->overscan_color; @@ -454,11 +822,11 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } else { svga->vgapal[index].r = svga->dac_r; svga->vgapal[index].g = svga->dac_g; - svga->vgapal[index].b = val; + svga->vgapal[index].b = val; svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); } svga->dac_addr = (svga->dac_addr + 1) & 255; - svga->dac_pos = 0; + svga->dac_pos = 0; break; } return; @@ -480,7 +848,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (svga->gdcaddr <= 8) { switch (svga->gdcaddr) { - case 0: + case 0: gd543x_mmio_write(0xb8000, val, gd54xx); break; case 1: @@ -509,8 +877,12 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) break; } - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - !svga->gdcreg[1]) && svga->chain4; + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424)) + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || svga->fb_only) && !(svga->adv_flags & FLAG_ADDR_BY8); /*TODO: needs verification on other Cirrus chips*/ + else + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || svga->fb_only); if (((svga->gdcaddr == 5) && ((val ^ o) & 0x70)) || ((svga->gdcaddr == 6) && ((val ^ o) & 1))) svga_recalctimings(svga); @@ -526,11 +898,31 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->adv_flags = FLAG_EXTRA_BANKS; if (svga->gdcreg[0xb] & 0x02) svga->adv_flags |= FLAG_ADDR_BY8; + if (svga->gdcreg[0xb] & 0x04) + svga->adv_flags |= FLAG_EXT_WRITE; if (svga->gdcreg[0xb] & 0x08) svga->adv_flags |= FLAG_LATCH8; + if (svga->gdcreg[0xb] & 0x10) + svga->adv_flags |= FLAG_ADDR_BY16; gd54xx_recalc_banking(gd54xx); break; + case 0x0c: + gd54xx->overlay.colorkeycompare = val; + gd54xx_update_overlay(gd54xx); + break; + case 0x0d: + gd54xx->overlay.colorkeycomparemask = val; + gd54xx_update_overlay(gd54xx); + break; + + case 0x0e: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) { + svga->dpms = (val & 0x06) && ((svga->miscout & ((val & 0x06) << 5)) != 0xc0); + svga_recalctimings(svga); + } + break; + case 0x10: gd543x_mmio_write(0xb8001, val, gd54xx); break; @@ -632,8 +1024,9 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } } return; + case 0x3d4: - svga->crtcreg = val & 0x3f; + svga->crtcreg = val & gd54xx->crtcreg_mask; return; case 0x3d5: if (((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) || @@ -648,11 +1041,114 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; + if (svga->crtcreg == 0x11) { + if (!(val & 0x10)) { + if (gd54xx->vblank_irq > 0) + gd54xx->vblank_irq = -1; + } else if (gd54xx->vblank_irq < 0) + gd54xx->vblank_irq = 0; + gd54xx_update_irqs(gd54xx); + if ((val & ~0x30) == (old & ~0x30)) + old = val; + } + if (old != val) { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + /* Overlay registers */ + switch (svga->crtcreg) { + case 0x1d: + if (((old >> 3) & 7) != ((val >> 3) & 7)) { + gd54xx->overlay.colorkeymode = (val >> 3) & 7; + gd54xx_update_overlay(gd54xx); + } + break; + case 0x31: + gd54xx->overlay.hzoom = val == 0 ? 256 : val; + gd54xx_update_overlay(gd54xx); + break; + case 0x32: + gd54xx->overlay.vzoom = val == 0 ? 256 : val; + gd54xx_update_overlay(gd54xx); + break; + case 0x33: + gd54xx->overlay.r1sz &= ~0xff; + gd54xx->overlay.r1sz |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x34: + gd54xx->overlay.r2sz &= ~0xff; + gd54xx->overlay.r2sz |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x35: + gd54xx->overlay.r2sdz &= ~0xff; + gd54xx->overlay.r2sdz |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x36: + gd54xx->overlay.r1sz &= 0xff; + gd54xx->overlay.r1sz |= (val << 8) & 0x300; + gd54xx->overlay.r2sz &= 0xff; + gd54xx->overlay.r2sz |= (val << 6) & 0x300; + gd54xx->overlay.r2sdz &= 0xff; + gd54xx->overlay.r2sdz |= (val << 4) & 0x300; + gd54xx_update_overlay(gd54xx); + break; + case 0x37: + gd54xx->overlay.wvs &= ~0xff; + gd54xx->overlay.wvs |= val; + svga->overlay.y = gd54xx->overlay.wvs; + break; + case 0x38: + gd54xx->overlay.wve &= ~0xff; + gd54xx->overlay.wve |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x39: + gd54xx->overlay.wvs &= 0xff; + gd54xx->overlay.wvs |= (val << 8) & 0x300; + gd54xx->overlay.wve &= 0xff; + gd54xx->overlay.wve |= (val << 6) & 0x300; + gd54xx_update_overlay(gd54xx); + break; + case 0x3a: + svga->overlay.addr &= ~0xff; + svga->overlay.addr |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x3b: + svga->overlay.addr &= ~0xff00; + svga->overlay.addr |= val << 8; + gd54xx_update_overlay(gd54xx); + break; + case 0x3c: + svga->overlay.addr &= ~0x0f0000; + svga->overlay.addr |= (val << 16) & 0x0f0000; + svga->overlay.pitch &= ~0x100; + svga->overlay.pitch |= (val & 0x20) << 3; + gd54xx_update_overlay(gd54xx); + break; + case 0x3d: + svga->overlay.pitch &= ~0xff; + svga->overlay.pitch |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x3e: + gd54xx->overlay.mode = (val >> 1) & 7; + svga->overlay.ena = (val & 1) != 0; + gd54xx_update_overlay(gd54xx); + break; } + + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } } break; } @@ -668,10 +1164,15 @@ gd54xx_in(uint16_t addr, void *p) uint8_t index, ret = 0xff; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { + case 0x3c2: + ret = svga_in(addr, svga); + ret |= gd54xx->vblank_irq > 0 ? 0x80 : 0x00; + break; + case 0x3c4: if (svga->seqregs[6] == 0x12) { ret = svga->seqaddr; @@ -696,13 +1197,73 @@ gd54xx_in(uint16_t addr, void *p) case 6: ret = svga->seqregs[6]; break; + case 0x08: + if (gd54xx->i2c) { + ret &= 0x7b; + if (i2c_gpio_get_scl(gd54xx->i2c)) + ret |= 0x04; + if (i2c_gpio_get_sda(gd54xx->i2c)) + ret |= 0x80; + } + break; + case 0x0a: /*Scratch Pad 1 (Memory size for 5402/542x)*/ + ret = svga->seqregs[0x0a] & ~0x1a; + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5402) { + ret |= 0x01; /*512K of memory*/ + } else if (svga->crtc[0x27] > CIRRUS_ID_CLGD5402) { + switch (gd54xx->vram_size >> 10) { + case 512: + ret |= 0x08; + break; + case 1024: + ret |= 0x10; + break; + case 2048: + ret |= 0x18; + break; + } + } + break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: ret = gd54xx->vclk_n[svga->seqaddr-0x0b]; break; + case 0x0f: /*DRAM control*/ + ret = svga->seqregs[0x0f] & ~0x98; + switch (gd54xx->vram_size >> 10) { + case 512: + ret |= 0x08; /*16-bit DRAM data bus width*/ + break; + case 1024: + ret |= 0x10; /*32-bit DRAM data bus width for 1M of memory*/ + break; + case 2048: + ret |= (gd54xx_is_5434(svga)) ? 0x98 : 0x18; /*32-bit (Pre-5434)/64-bit (5434 and up) DRAM data bus width for 2M of memory*/ + break; + case 4096: + ret |= 0x98; /*64-bit (5434 and up) DRAM data bus width for 4M of memory*/ + break; + } + break; + case 0x15: /*Scratch Pad 3 (Memory size for 543x)*/ + ret = svga->seqregs[0x15] & ~0x0f; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) { + switch (gd54xx->vram_size >> 20) { + case 1: + ret |= 0x02; + break; + case 2: + ret |= 0x03; + break; + case 4: + ret |= 0x04; + break; + } + } + break; case 0x17: - ret = svga->gdcreg[0x17] & ~(7 << 3); + ret = svga->seqregs[0x17] & ~(7 << 3); if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { - if (svga->crtc[0x27] == CIRRUS_ID_CLGD5428) { + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5428) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) { if (gd54xx->vlb) ret |= (CL_GD5428_SYSTEM_BUS_VESA << 3); else if (gd54xx->mca) @@ -769,14 +1330,14 @@ gd54xx_in(uint16_t addr, void *p) else ret = svga->vgapal[index].r & 0x3f; break; - case 1: + case 1: svga->dac_pos++; if (svga->seqregs[0x12] & 2) ret = gd54xx->extpal[index].g & 0x3f; else ret = svga->vgapal[index].g & 0x3f; break; - case 2: + case 2: svga->dac_pos=0; svga->dac_addr = (svga->dac_addr + 1) & 255; if (svga->seqregs[0x12] & 2) @@ -895,6 +1456,12 @@ gd54xx_in(uint16_t addr, void *p) case 0x39: ret = gd543x_mmio_read(0xb8021, gd54xx); break; + + case 0x3f: + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5446) + gd54xx->vportsync = !gd54xx->vportsync; + ret = gd54xx->vportsync ? 0x80 : 0x00; + break; } } else { if ((svga->gdcaddr < 2) && !gd54xx->unlocked) @@ -928,7 +1495,7 @@ gd54xx_in(uint16_t addr, void *p) ret = svga->attrff << 7; break; case 0x26: /*Attribute controller index readback (R)*/ - ret = svga->attraddr & 0x3f; + ret = svga->attraddr & 0x3f; break; case 0x27: /*ID*/ ret = svga->crtc[0x27]; /*GD542x/GD543x*/ @@ -981,7 +1548,7 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx) } -static void +static void gd543x_recalc_mapping(gd54xx_t *gd54xx) { svga_t *svga = &gd54xx->svga; @@ -994,7 +1561,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) mem_mapping_disable(&gd54xx->mmio_mapping); return; } - + gd54xx->mmio_vram_overlap = 0; if (!gd54xx_is_5422(svga) || !(svga->seqregs[7] & 0xf0) || !(svga->seqregs[0x07] & 0x01)) { @@ -1040,7 +1607,9 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) } } else if (gd54xx->pci) { base = gd54xx->lfb_base; - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + /* if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + size = 32 * 1024 * 1024; + else */ if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) size = 16 * 1024 * 1024; else size = 4 * 1024 * 1024; @@ -1064,9 +1633,12 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_APERTURE2) && ((gd54xx->blt.mode & (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC)) == - (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) - mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000); - else + (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) { + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + mem_mapping_set_addr(&gd54xx->aperture2_mapping, gd54xx->lfb_base + (16777216), 16777216); + else + mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000); + } else mem_mapping_disable(&gd54xx->aperture2_mapping); } } @@ -1075,17 +1647,24 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) static void gd54xx_recalctimings(svga_t *svga) { - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; uint8_t clocksel, rdmask; + uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp; - svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + svga->rowoffset = (svga->crtc[0x13]) | (((int) (uint32_t) (svga->crtc[0x1b] & 0x10)) << 4); svga->interlace = (svga->crtc[0x1a] & 0x01); svga->map8 = svga->pallook; - if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) - svga->render = svga_render_8bpp_highres; - else if (svga->gdcreg[5] & 0x40) + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) { + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else { + svga->render = svga_render_8bpp_highres; + if ((svga->dispend == 512) && !svga->interlace && gd54xx_is_5434(svga)) + svga->hdisp <<= 1; + } + } else if (svga->gdcreg[5] & 0x40) svga->render = svga_render_8bpp_lowres; svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); @@ -1102,81 +1681,126 @@ gd54xx_recalctimings(svga_t *svga) switch (gd54xx->ramdac.ctrl & rdmask) { case 0: svga->bpp = 15; - if (gd54xx->ramdac.ctrl & 0x10) - svga->render = svga_render_15bpp_mix_highres; - else - svga->render = svga_render_15bpp_highres; + if (linedbl) { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_lowres; + } else { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_highres; + else + svga->render = svga_render_15bpp_highres; + } break; case 1: svga->bpp = 16; - svga->render = svga_render_16bpp_highres; + if (linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; break; case 5: if (gd54xx_is_5434(svga) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) { svga->bpp = 32; - svga->render = svga_render_32bpp_highres; - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + if (linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) { svga->rowoffset *= 2; + } } else { svga->bpp = 24; - svga->render = svga_render_24bpp_highres; + if (linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; } break; case 8: svga->bpp = 8; svga->map8 = video_8togs; - svga->render = svga_render_8bpp_highres; + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; case 9: svga->bpp = 8; svga->map8 = video_8to32; - svga->render = svga_render_8bpp_highres; + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; - case 0xf: - switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) { - case CIRRUS_SR7_BPP_32: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) { - svga->bpp = 32; - svga->render = svga_render_32bpp_highres; - svga->rowoffset *= 2; - } - break; + case 0xf: + switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) { + case CIRRUS_SR7_BPP_32: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) { + svga->bpp = 32; + if (linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + svga->rowoffset *= 2; + } + break; - case CIRRUS_SR7_BPP_24: - svga->bpp = 24; - svga->render = svga_render_24bpp_highres; - break; + case CIRRUS_SR7_BPP_24: + svga->bpp = 24; + if (linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; - case CIRRUS_SR7_BPP_16: - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5428) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) { - svga->bpp = 16; - svga->render = svga_render_16bpp_highres; - } - break; + case CIRRUS_SR7_BPP_16: + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5428) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) { + svga->bpp = 16; + if (linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + } + break; - case CIRRUS_SR7_BPP_16_DOUBLEVCLK: - svga->bpp = 16; - svga->render = svga_render_16bpp_highres; - break; + case CIRRUS_SR7_BPP_16_DOUBLEVCLK: + svga->bpp = 16; + if (linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; - case CIRRUS_SR7_BPP_8: - svga->bpp = 8; - svga->render = svga_render_8bpp_highres; - break; - } + case CIRRUS_SR7_BPP_8: + svga->bpp = 8; + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + } break; } } else { svga->bpp = 15; - if (gd54xx->ramdac.ctrl & 0x10) - svga->render = svga_render_15bpp_mix_highres; - else - svga->render = svga_render_15bpp_highres; + if (linedbl) { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_lowres; + } else { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_highres; + else + svga->render = svga_render_15bpp_highres; + } } } @@ -1196,7 +1820,7 @@ gd54xx_recalctimings(svga_t *svga) break; case 4: if (!gd54xx_is_5434(svga)) - freq /= 3.0; + freq /= 3.0; break; } } @@ -1210,23 +1834,26 @@ gd54xx_recalctimings(svga_t *svga) static void gd54xx_hwcursor_draw(svga_t *svga, int displine) { - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; int x, xx, comb, b0, b1; uint8_t dat[2]; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; + int pitch = (svga->hwcursor.cur_xsize == 64) ? 16 : 4; uint32_t bgcol = gd54xx->extpallook[0x00]; uint32_t fgcol = gd54xx->extpallook[0x0f]; + uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp; + + offset <<= linedbl; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += pitch; - for (x = 0; x < svga->hwcursor.xsize; x += 8) { - dat[0] = svga->vram[svga->hwcursor_latch.addr]; - if (svga->hwcursor.xsize == 64) - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + for (x = 0; x < svga->hwcursor.cur_xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr & svga->vram_display_mask]; + if (svga->hwcursor.cur_xsize == 64) + dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x08) & svga->vram_display_mask]; else - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x80) & svga->vram_display_mask]; for (xx = 0; xx < 8; xx++) { b0 = (dat[0] >> (7 - xx)) & 1; b1 = (dat[1] >> (7 - xx)) & 1; @@ -1251,13 +1878,13 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) break; } } - + offset++; } svga->hwcursor_latch.addr++; } - if (svga->hwcursor.xsize == 64) + if (svga->hwcursor.cur_xsize == 64) svga->hwcursor_latch.addr += 8; if (svga->interlace && !svga->hwcursor_oddeven) @@ -1338,7 +1965,7 @@ static void gd54xx_write(uint32_t addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + svga_t *svga = &gd54xx->svga; if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { @@ -1357,7 +1984,7 @@ gd54xx_write(uint32_t addr, uint8_t val, void *p) } -static void +static void gd54xx_writew(uint32_t addr, uint16_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; @@ -1377,7 +2004,7 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *p) addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; - if (svga->writemode < 4) + if (svga->writemode < 4) svga_writew_linear(addr, val, svga); else { svga_write_linear(addr, val, svga); @@ -1427,8 +2054,8 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) switch (svga->writemode) { case 4: - if (svga->gdcreg[0xb] & 0x10) { - addr <<= 2; + if (svga->adv_flags & FLAG_ADDR_BY16) { + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { if (val & svga->seqregs[2] & (0x80 >> i)) { @@ -1438,6 +2065,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) } } else { addr <<= 1; + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { if (val & svga->seqregs[2] & (0x80 >> i)) @@ -1447,8 +2075,8 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) break; case 5: - if (svga->gdcreg[0xb] & 0x10) { - addr <<= 2; + if (svga->adv_flags & FLAG_ADDR_BY16) { + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { j = (0x80 >> i); @@ -1461,6 +2089,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) } } else { addr <<= 1; + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { j = (0x80 >> i); @@ -1525,7 +2154,7 @@ gd54xx_readb_linear(uint32_t addr, void *p) switch (ap) { case 0: - default: + default: break; case 1: /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ @@ -1574,7 +2203,7 @@ gd54xx_readw_linear(uint32_t addr, void *p) switch (ap) { case 0: - default: + default: return svga_readw_linear(addr, svga); case 2: /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ @@ -1584,7 +2213,7 @@ gd54xx_readw_linear(uint32_t addr, void *p) temp |= (svga_readb_linear(addr, svga) << 8); if (svga->fast) - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; return temp; case 3: @@ -1626,7 +2255,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) switch (ap) { case 0: - default: + default: return svga_readl_linear(addr, svga); case 1: temp = svga_readb_linear(addr + 1, svga); @@ -1635,7 +2264,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) temp |= (svga_readb_linear(addr + 2, svga) << 24); if (svga->fast) - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; return temp; case 2: @@ -1645,7 +2274,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) temp |= (svga_readb_linear(addr, svga) << 24); if (svga->fast) - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; return temp; case 3: @@ -1791,7 +2420,7 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) } -static void +static void gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; @@ -1834,7 +2463,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) svga_writeb_linear(addr, val >> 8, svga); if (svga->fast) - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; case 3: return; } @@ -1857,7 +2486,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) } -static void +static void gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; @@ -2143,14 +2772,14 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) break; case 0x1b: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) gd54xx->blt.modeext = val; break; case 0x1c: gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; break; - case 0x1d: + case 0x1d: gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); break; @@ -2226,14 +2855,14 @@ gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) gd543x_mmio_write(addr, val & 0xff, gd54xx); gd543x_mmio_write(addr+1, val >> 8, gd54xx); gd543x_mmio_write(addr+2, val >> 16, gd54xx); - gd543x_mmio_write(addr+3, val >> 24, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); } else if (gd54xx->mmio_vram_overlap) { if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { gd543x_mmio_write(addr, val & 0xff, gd54xx); gd543x_mmio_write(addr+1, val >> 8, gd54xx); gd543x_mmio_write(addr+2, val >> 16, gd54xx); - gd543x_mmio_write(addr+3, val >> 24, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); } else { gd54xx_write(addr, val, gd54xx); gd54xx_write(addr+1, val >> 8, gd54xx); @@ -2352,21 +2981,21 @@ gd543x_mmio_read(uint32_t addr, void *p) break; case 0x1b: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) ret = gd54xx->blt.modeext; break; case 0x1c: ret = gd54xx->blt.trans_col & 0xff; break; - case 0x1d: + case 0x1d: ret = (gd54xx->blt.trans_col >> 8) & 0xff; break; case 0x20: ret = gd54xx->blt.trans_mask & 0xff; break; - case 0x21: + case 0x21: ret = (gd54xx->blt.trans_mask >> 8) & 0xff; break; @@ -2431,6 +3060,98 @@ gd543x_mmio_readl(uint32_t addr, void *p) } +static void +gd5480_vgablt_write(uint32_t addr, uint8_t val, void *p) +{ + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + gd543x_mmio_writeb((addr & 0x000000ff) | 0x000b8000, val, p); + else if (addr < 0x00000100) + gd54xx_out(0x03c0 + addr, val, p); +} + + +static void +gd5480_vgablt_writew(uint32_t addr, uint16_t val, void *p) +{ + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + gd543x_mmio_writew((addr & 0x000000ff) | 0x000b8000, val, p); + else if (addr < 0x00000100) { + gd5480_vgablt_write(addr, val & 0xff, p); + gd5480_vgablt_write(addr + 1, val >> 8, p); + } +} + + +static void +gd5480_vgablt_writel(uint32_t addr, uint32_t val, void *p) +{ + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + gd543x_mmio_writel((addr & 0x000000ff) | 0x000b8000, val, p); + else if (addr < 0x00000100) { + gd5480_vgablt_writew(addr, val & 0xffff, p); + gd5480_vgablt_writew(addr + 2, val >> 16, p); + } +} + + +static uint8_t +gd5480_vgablt_read(uint32_t addr, void *p) +{ + uint8_t ret = 0xff; + + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + ret = gd543x_mmio_read((addr & 0x000000ff) | 0x000b8000, p); + else if (addr < 0x00000100) + ret = gd54xx_in(0x03c0 + addr, p); + + return ret; +} + + +static uint16_t +gd5480_vgablt_readw(uint32_t addr, void *p) +{ + uint16_t ret = 0xffff; + + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + ret = gd543x_mmio_readw((addr & 0x000000ff) | 0x000b8000, p); + else if (addr < 0x00000100) { + ret = gd5480_vgablt_read(addr, p); + ret |= (gd5480_vgablt_read(addr + 1, p) << 8); + } + + return ret; +} + + +static uint32_t +gd5480_vgablt_readl(uint32_t addr, void *p) +{ + uint32_t ret = 0xffffffff; + + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + ret = gd543x_mmio_readl((addr & 0x000000ff) | 0x000b8000, p); + else if (addr < 0x00000100) { + ret = gd5480_vgablt_readw(addr, p); + ret |= (gd5480_vgablt_readw(addr + 2, p) << 16); + } + + return ret; +} + + static uint8_t gd54xx_color_expand(gd54xx_t *gd54xx, int mask, int shift) { @@ -2838,7 +3559,7 @@ request_more_data: } -static void +static void gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga) { if ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) && @@ -2870,55 +3591,111 @@ gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *sv } -static uint8_t +static uint8_t cl_pci_read(int func, int addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint8_t ret = 0x00; if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) - return 0; - - switch (addr) { - case 0x00: return 0x13; /*Cirrus Logic*/ - case 0x01: return 0x10; + ret = 0x00; + else switch (addr) { + case 0x00: + ret = 0x13; /*Cirrus Logic*/ + break; + case 0x01: + ret = 0x10; + break; case 0x02: - return svga->crtc[0x27]; - case 0x03: return 0x00; - + ret = svga->crtc[0x27]; + break; + case 0x03: + ret = 0x00; + break; + case PCI_REG_COMMAND: - return gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + ret = gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + break; - case 0x07: return 0x02; /*Fast DEVSEL timing*/ - - case 0x08: return gd54xx->rev; /*Revision ID*/ - case 0x09: return 0x00; /*Programming interface*/ - - case 0x0a: return 0x00; /*Supports VGA interface*/ - case 0x0b: return 0x03; + case 0x07: + ret = 0x02; /*Fast DEVSEL timing*/ + break; - case 0x10: return 0x08; /*Linear frame buffer address*/ - case 0x11: return 0x00; - case 0x12: return 0x00; - case 0x13: return gd54xx->lfb_base >> 24; + case 0x08: + ret = gd54xx->rev; /*Revision ID*/ + break; + case 0x09: + ret = 0x00; /*Programming interface*/ + break; - case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ - case 0x31: return 0x00; - case 0x32: return gd54xx->pci_regs[0x32]; - case 0x33: return gd54xx->pci_regs[0x33]; + case 0x0a: + ret = 0x00; /*Supports VGA interface*/ + break; + case 0x0b: + ret = 0x03; + break; - case 0x3c: return gd54xx->int_line; - case 0x3d: return PCI_INTA; + case 0x10: + ret = 0x08; /*Linear frame buffer address*/ + break; + case 0x11: + ret = 0x00; + break; + case 0x12: + ret = 0x00; + break; + case 0x13: + ret = gd54xx->lfb_base >> 24; + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + ret = 0xfe; + break; + + case 0x14: + ret = 0x00; /*PCI VGA/BitBLT Register Base Address*/ + break; + case 0x15: + ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 8) & 0xf0) : 0x00; + break; + case 0x16: + ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 16) & 0xff) : 0x00; + break; + case 0x17: + ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 24) & 0xff) : 0x00; + break; + + case 0x30: + ret = (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + break; + case 0x31: + ret = 0x00; + break; + case 0x32: + ret = gd54xx->pci_regs[0x32]; + break; + case 0x33: + ret = gd54xx->pci_regs[0x33]; + break; + + case 0x3c: + ret = gd54xx->int_line; + break; + case 0x3d: + ret = PCI_INTA; + break; } - return 0; + + return ret; } -static void +static void cl_pci_write(int func, int addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint32_t byte; if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) return; @@ -2926,20 +3703,45 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) switch (addr) { case PCI_REG_COMMAND: gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + mem_mapping_disable(&gd54xx->vgablt_mapping); io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); if (val & PCI_COMMAND_IO) io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if ((val & PCI_COMMAND_MEM) && (gd54xx->vgablt_base != 0x00000000) && (gd54xx->vgablt_base < 0xfff00000)) + mem_mapping_set_addr(&gd54xx->vgablt_mapping, gd54xx->vgablt_base, 0x1000); + if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) && (gd54xx->pci_regs[0x30] & 0x01)) { + uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&gd54xx->bios_rom.mapping); gd543x_recalc_mapping(gd54xx); break; - case 0x13: + case 0x13: + /* 5480, like 5446 rev. B, has a 32 MB aperture, with the second set used for + BitBLT transfers. */ + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + val &= 0xfe; gd54xx->lfb_base = val << 24; gd543x_recalc_mapping(gd54xx); - break; + break; + + case 0x15: case 0x16: case 0x17: + if (svga->crtc[0x27] != CIRRUS_ID_CLGD5480) + return; + byte = (addr & 3) << 3; + gd54xx->vgablt_base &= ~(0xff << byte); + if (addr == 0x15) + val &= 0xf0; + gd54xx->vgablt_base |= (val << byte); + mem_mapping_disable(&gd54xx->vgablt_mapping); + if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) && (gd54xx->vgablt_base != 0x00000000) && (gd54xx->vgablt_base < 0xfff00000)) + mem_mapping_set_addr(&gd54xx->vgablt_mapping, gd54xx->vgablt_base, 0x1000); + break; case 0x30: case 0x32: case 0x33: gd54xx->pci_regs[addr] = val; - if (gd54xx->pci_regs[0x30] & 0x01) { + if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) && (gd54xx->pci_regs[0x30] & 0x01)) { uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); } else @@ -2952,15 +3754,15 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) } } -static uint8_t +static uint8_t gd5428_mca_read(int port, void *p) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)p; - return gd54xx->pos_regs[port & 7]; + return gd54xx->pos_regs[port & 7]; } -static void +static void gd5428_mca_write(int port, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; @@ -2968,18 +3770,89 @@ gd5428_mca_write(int port, uint8_t val, void *p) if (port < 0x102) return; - gd54xx->pos_regs[port & 7] = val; + gd54xx->pos_regs[port & 7] = val; gd543x_recalc_mapping(gd54xx); } -static uint8_t +static uint8_t gd5428_mca_feedb(void *p) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - - return gd54xx->pos_regs[2] & 1; + return 1; } +static void +gd54xx_reset(void *priv) +{ + gd54xx_t *gd54xx = (gd54xx_t *) priv; + svga_t *svga = &gd54xx->svga; + + memset(svga->crtc, 0x00, sizeof(svga->crtc)); + memset(svga->seqregs, 0x00, sizeof(svga->seqregs)); + memset(svga->gdcreg, 0x00, sizeof(svga->gdcreg)); + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = 1000ull << 32; + svga->dispofftime = 1000ull << 32; + svga->bpp = 8; + + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + mem_mapping_disable(&gd54xx->vgablt_mapping); + if (gd54xx->has_bios && gd54xx->pci) + mem_mapping_disable(&gd54xx->bios_rom.mapping); + + memset(gd54xx->pci_regs, 0x00, 256); + + mem_mapping_set_p(&svga->mapping, gd54xx); + mem_mapping_disable(&gd54xx->mmio_mapping); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->aperture2_mapping); + mem_mapping_disable(&gd54xx->vgablt_mapping); + + gd543x_recalc_mapping(gd54xx); + gd54xx_recalc_banking(gd54xx); + + svga->hwcursor.yoff = svga->hwcursor.xoff = 0; + + if (gd54xx->id >= CIRRUS_ID_CLGD5420) { + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x30; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; + } else { + gd54xx->vclk_n[0] = 0x66; + gd54xx->vclk_d[0] = 0x3b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x2c; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; + } + + svga->extra_banks[1] = 0x8000; + + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + + gd54xx->pci_regs[0x30] = 0x00; + gd54xx->pci_regs[0x32] = 0x0c; + gd54xx->pci_regs[0x33] = 0x00; + + svga->crtc[0x27] = gd54xx->id; + + svga->seqregs[6] = 0x0f; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) + gd54xx->unlocked = 1; + else + gd54xx->unlocked = 0; +} + + static void *gd54xx_init(const device_t *info) { @@ -2987,10 +3860,10 @@ static void svga_t *svga = &gd54xx->svga; int id = info->local & 0xff; int vram; - wchar_t *romfn = NULL; + char *romfn = NULL; memset(gd54xx, 0, sizeof(gd54xx_t)); - gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->pci = !!(info->flags & DEVICE_PCI); gd54xx->vlb = !!(info->flags & DEVICE_VLB); gd54xx->mca = !!(info->flags & DEVICE_MCA); gd54xx->bit32 = gd54xx->pci || gd54xx->vlb; @@ -2998,12 +3871,13 @@ static void gd54xx->rev = 0; gd54xx->has_bios = 1; + gd54xx->id = id; + switch (id) { - case CIRRUS_ID_CLGD5401: romfn = BIOS_GD5401_PATH; break; - + case CIRRUS_ID_CLGD5402: if (info->local & 0x200) romfn = BIOS_GD5402_ONBOARD_PATH; @@ -3015,32 +3889,65 @@ static void romfn = BIOS_GD5420_PATH; break; -#if defined(DEV_BRANCH) && defined(USE_CL5422) case CIRRUS_ID_CLGD5422: case CIRRUS_ID_CLGD5424: romfn = BIOS_GD5422_PATH; - break; -#endif + break; case CIRRUS_ID_CLGD5426: - romfn = BIOS_GD5426_PATH; + if (info->local & 0x200) + romfn = NULL; + else { + if (info->local & 0x100) + romfn = BIOS_GD5426_DIAMOND_A1_ISA_PATH; + else { + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else if (gd54xx->mca) + romfn = BIOS_GD5426_MCA_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + } + } break; case CIRRUS_ID_CLGD5428: - if (gd54xx->vlb) - romfn = BIOS_GD5428_PATH; - else - romfn = BIOS_GD5428_ISA_PATH; + if (info->local & 0x100) + romfn = BIOS_GD5428_DIAMOND_B1_VLB_PATH; + else { + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else if (gd54xx->mca) + romfn = BIOS_GD5428_MCA_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + } break; case CIRRUS_ID_CLGD5429: romfn = BIOS_GD5429_PATH; break; - case CIRRUS_ID_CLGD5434: - romfn = BIOS_GD5434_PATH; + case CIRRUS_ID_CLGD5432: + case CIRRUS_ID_CLGD5434_4: + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } break; - + + case CIRRUS_ID_CLGD5434: + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else { + if (info->local & 0x100) + romfn = BIOS_GD5434_DIAMOND_A3_ISA_PATH; + else + romfn = BIOS_GD5434_PATH; + } + break; + case CIRRUS_ID_CLGD5436: romfn = BIOS_GD5436_PATH; break; @@ -3056,10 +3963,13 @@ static void romfn = BIOS_GD5440_PATH; } else { /* CL-GD 5430 */ - if (gd54xx->pci) - romfn = BIOS_GD5430_PCI_PATH; + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else if (gd54xx->pci) + romfn = BIOS_GD5430_PATH; else - romfn = BIOS_GD5430_VLB_PATH; + romfn = BIOS_GD5430_DIAMOND_A8_VLB_PATH; } break; @@ -3074,28 +3984,31 @@ static void romfn = BIOS_GD5480_PATH; break; } - - if (info->flags & DEVICE_MCA) { - vram = 1; - gd54xx->vram_size = 1 << 20; - } else { - if (id >= CIRRUS_ID_CLGD5420) - vram = device_get_config_int("memory"); - else - vram = 0; - - if (vram) - gd54xx->vram_size = vram << 20; - else - gd54xx->vram_size = 1 << 19; - } + if (info->flags & DEVICE_MCA) { + vram = 1024; + gd54xx->vram_size = vram << 10; + } else { + if (id <= CIRRUS_ID_CLGD5428) { + if ((id == CIRRUS_ID_CLGD5426) && (info->local & 0x200)) + vram = 1024; + else if (id == CIRRUS_ID_CLGD5401) + vram = 256; + else if (id == CIRRUS_ID_CLGD5402) + vram = 512; + else + vram = device_get_config_int("memory"); + gd54xx->vram_size = vram << 10; + } else { + vram = device_get_config_int("memory"); + gd54xx->vram_size = vram << 20; + } + } gd54xx->vram_mask = gd54xx->vram_size - 1; if (romfn) rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_ISA) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); else if (info->flags & DEVICE_PCI) @@ -3103,12 +4016,19 @@ static void else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb); - svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size, - gd54xx_recalctimings, gd54xx_in, gd54xx_out, - gd54xx_hwcursor_draw, NULL); + if (id >= CIRRUS_ID_CLGD5426) { + svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, gd54xx_overlay_draw); + } else { + svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + } + svga->vblank_start = gd54xx_vblank_start; svga->ven_write = gd54xx_write_modes45; - if (vram <= 1) - svga->decode_mask = gd54xx->vram_mask; + if ((vram == 1) || (vram >= 256 && vram <= 1024)) + svga->decode_mask = gd54xx->vram_mask; if (gd54xx->bit32) { mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); @@ -3124,6 +4044,10 @@ static void gd5436_aperture2_readb, gd5436_aperture2_readw, gd5436_aperture2_readl, gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->vgablt_mapping, 0, 0, + gd5480_vgablt_read, gd5480_vgablt_readw, gd5480_vgablt_readl, + gd5480_vgablt_write, gd5480_vgablt_writew, gd5480_vgablt_writel, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); } else { mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, NULL, gd54xx_write, gd54xx_writew, NULL); mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, @@ -3138,16 +4062,25 @@ static void gd5436_aperture2_readb, gd5436_aperture2_readw, NULL, gd5436_aperture2_writeb, gd5436_aperture2_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->vgablt_mapping, 0, 0, + gd5480_vgablt_read, gd5480_vgablt_readw, NULL, + gd5480_vgablt_write, gd5480_vgablt_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); } + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) { + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + mem_mapping_disable(&gd54xx->bios_rom.mapping); + } + mem_mapping_set_p(&svga->mapping, gd54xx); mem_mapping_disable(&gd54xx->mmio_mapping); mem_mapping_disable(&gd54xx->linear_mapping); mem_mapping_disable(&gd54xx->aperture2_mapping); + mem_mapping_disable(&gd54xx->vgablt_mapping); - io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - - svga->hwcursor.yoff = 32; - svga->hwcursor.xoff = 0; + svga->hwcursor.yoff = svga->hwcursor.xoff = 0; if (id >= CIRRUS_ID_CLGD5420) { gd54xx->vclk_n[0] = 0x4a; @@ -3171,27 +4104,38 @@ static void svga->extra_banks[1] = 0x8000; - if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) - pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); - gd54xx->pci_regs[PCI_REG_COMMAND] = 7; gd54xx->pci_regs[0x30] = 0x00; gd54xx->pci_regs[0x32] = 0x0c; gd54xx->pci_regs[0x33] = 0x00; - + svga->crtc[0x27] = id; svga->seqregs[6] = 0x0f; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) gd54xx->unlocked = 1; if (gd54xx->mca) { - gd54xx->pos_regs[0] = 0x7b; - gd54xx->pos_regs[1] = 0x91; + gd54xx->pos_regs[0] = svga->crtc[0x27] == CIRRUS_ID_CLGD5426 ? 0x82 : 0x7b; + gd54xx->pos_regs[1] = svga->crtc[0x27] == CIRRUS_ID_CLGD5426 ? 0x81 : 0x91; mca_add(gd5428_mca_read, gd5428_mca_write, gd5428_mca_feedb, NULL, gd54xx); + io_sethandler(0x46e8, 0x0001, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); } + if (gd54xx_is_5434(svga)) { + gd54xx->i2c = i2c_gpio_init("ddc_cl54xx"); + gd54xx->ddc = ddc_init(i2c_gpio_get_bus(gd54xx->i2c)); + } + + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446) + gd54xx->crtcreg_mask = 0x7f; + else + gd54xx->crtcreg_mask = 0x3f; + + gd54xx->overlay.colorkeycompare = 0xff; + return gd54xx; } @@ -3213,18 +4157,16 @@ gd5420_available(void) return rom_present(BIOS_GD5420_PATH); } -#if defined(DEV_BRANCH) && defined(USE_CL5422) static int gd5422_available(void) { return rom_present(BIOS_GD5422_PATH); } -#endif static int -gd5426_available(void) +gd5426_diamond_a1_available(void) { - return rom_present(BIOS_GD5426_PATH); + return rom_present(BIOS_GD5426_DIAMOND_A1_ISA_PATH); } static int @@ -3233,12 +4175,30 @@ gd5428_available(void) return rom_present(BIOS_GD5428_PATH); } +static int +gd5428_diamond_b1_available(void) +{ + return rom_present(BIOS_GD5428_DIAMOND_B1_VLB_PATH); +} + static int gd5428_isa_available(void) { return rom_present(BIOS_GD5428_ISA_PATH); } +static int +gd5426_mca_available(void) +{ + return rom_present(BIOS_GD5426_MCA_PATH); +} + +static int +gd5428_mca_available(void) +{ + return rom_present(BIOS_GD5428_MCA_PATH); +} + static int gd5429_available(void) { @@ -3246,15 +4206,15 @@ gd5429_available(void) } static int -gd5430_vlb_available(void) +gd5430_diamond_a8_available(void) { - return rom_present(BIOS_GD5430_VLB_PATH); + return rom_present(BIOS_GD5430_DIAMOND_A8_VLB_PATH); } static int -gd5430_pci_available(void) +gd5430_available(void) { - return rom_present(BIOS_GD5430_PCI_PATH); + return rom_present(BIOS_GD5430_PATH); } static int @@ -3263,6 +4223,12 @@ gd5434_available(void) return rom_present(BIOS_GD5434_PATH); } +static int +gd5434_diamond_a3_available(void) +{ + return rom_present(BIOS_GD5434_DIAMOND_A3_ISA_PATH); +} + static int gd5436_available(void) { @@ -3299,7 +4265,12 @@ gd54xx_close(void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_close(&gd54xx->svga); - + + if (gd54xx->i2c) { + ddc_close(gd54xx->ddc); + i2c_gpio_close(gd54xx->i2c); + } + free(gd54xx); } @@ -3308,7 +4279,7 @@ void gd54xx_speed_changed(void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - + svga_recalctimings(&gd54xx->svga); } @@ -3321,461 +4292,658 @@ gd54xx_force_redraw(void *p) gd54xx->svga.fullchange = changeframecount; } -static const device_config_t gd5422_config[] = -{ - { - "memory","Memory size",CONFIG_SELECTION,"",1, - { - { - "512 KB",0 - }, - { - "1 MB",1 - }, - { - "" - } - }, +// clang-format off +static const device_config_t gd542x_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } }, - { - "","",-1 - } + .default_int = 512 + }, + { + .type = CONFIG_END + } }; -static const device_config_t gd5428_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } - }, - .default_int = 2 +static const device_config_t gd5426_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "" + } }, - { - .type = -1 - } + .default_int = 2048 + }, + { + .type = CONFIG_END + } }; -static const device_config_t gd5428_a1g_config[] = -{ - { - .name = "memory", - .description = "Onboard Video RAM size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } - }, - .default_int = 2 +static const device_config_t gd5428_onboard_config[] = { + { + .name = "memory", + .description = "Onboard memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "" + } }, - { - .type = -1 - } + .default_int = 2048 + }, + { + .type = CONFIG_END + } }; -static const device_config_t gd5440_onboard_config[] = -{ - { - .name = "memory", - .description = "Video memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } - }, - .default_int = 2 +static const device_config_t gd5429_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } }, - { - .type = -1 - } + .default_int = 2 + }, + { + .type = CONFIG_END + } }; -static const device_config_t gd5434_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 4 +static const device_config_t gd5440_onboard_config[] = { + { + .name = "memory", + .description = "Onboard memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } }, - { - .type = -1 - } + .default_int = 2 + }, + { + .type = CONFIG_END + } }; -const device_t gd5401_isa_device = -{ - "Cirrus Logic GD-5401 (ACUMOS AVGA1)", - DEVICE_ISA, - CIRRUS_ID_CLGD5401, - gd54xx_init, gd54xx_close, - NULL, - gd5401_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - NULL, +static const device_config_t gd5434_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = CONFIG_END + } }; -const device_t gd5402_isa_device = -{ - "Cirrus Logic GD-5402 (ACUMOS AVGA2)", - DEVICE_ISA, - CIRRUS_ID_CLGD5402, - gd54xx_init, gd54xx_close, - NULL, - gd5402_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - NULL, +static const device_config_t gd5434_onboard_config[] = { + { + .name = "memory", + .description = "Onboard memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = CONFIG_END + } }; -const device_t gd5402_onboard_device = -{ - "Cirrus Logic GD-5402 (ACUMOS AVGA2) (On-Board)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5402 | 0x200, - gd54xx_init, gd54xx_close, - NULL, - NULL, - gd54xx_speed_changed, - gd54xx_force_redraw, - NULL, +static const device_config_t gd5480_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; +// clang-format on + +const device_t gd5401_isa_device = { + .name = "Cirrus Logic GD5401 (ISA) (ACUMOS AVGA1)", + .internal_name = "cl_gd5401_isa", + .flags = DEVICE_ISA, + .local = CIRRUS_ID_CLGD5401, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5401_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = NULL, }; -const device_t gd5420_isa_device = -{ - "Cirrus Logic GD-5420", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5420, - gd54xx_init, gd54xx_close, - NULL, - gd5420_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5422_config, +const device_t gd5402_isa_device = { + .name = "Cirrus Logic GD5402 (ISA) (ACUMOS AVGA2)", + .internal_name = "cl_gd5402_isa", + .flags = DEVICE_ISA, + .local = CIRRUS_ID_CLGD5402, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5402_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = NULL, +}; + +const device_t gd5402_onboard_device = { + .name = "Cirrus Logic GD5402 (ISA) (ACUMOS AVGA2) (On-Board)", + .internal_name = "cl_gd5402_onboard", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5402 | 0x200, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = NULL }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = NULL, +}; + +const device_t gd5420_isa_device = { + .name = "Cirrus Logic GD5420 (ISA)", + .internal_name = "cl_gd5420_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5420, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5420_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd542x_config, }; -#if defined(DEV_BRANCH) && defined(USE_CL5422) const device_t gd5422_isa_device = { - "Cirrus Logic GD-5422", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5422, - gd54xx_init, gd54xx_close, - NULL, - gd5422_available, /* Common BIOS between 5422 and 5424 */ - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5422_config, + .name = "Cirrus Logic GD5422 (ISA)", + .internal_name = "cl_gd5422_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5422, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5422_available }, /* Common BIOS between 5422 and 5424 */ + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd542x_config, }; const device_t gd5424_vlb_device = { - "Cirrus Logic GD-5424", - DEVICE_VLB, - CIRRUS_ID_CLGD5424, - gd54xx_init, gd54xx_close, - NULL, - gd5422_available, /* Common BIOS between 5422 and 5424 */ - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5422_config, -}; -#endif - -const device_t gd5426_vlb_device = -{ - "Cirrus Logic CL-GD 5426 (VLB)", - DEVICE_VLB, - CIRRUS_ID_CLGD5426, - gd54xx_init, - gd54xx_close, - NULL, - gd5426_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config + .name = "Cirrus Logic GD5424 (VLB)", + .internal_name = "cl_gd5424_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5424, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5422_available }, /* Common BIOS between 5422 and 5424 */ + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd542x_config, }; -const device_t gd5428_isa_device = -{ - "Cirrus Logic CL-GD 5428 (ISA)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5428, - gd54xx_init, - gd54xx_close, - NULL, - gd5428_isa_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +const device_t gd5426_isa_device = { + .name = "Cirrus Logic GD5426 (ISA)", + .internal_name = "cl_gd5426_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5426, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_isa_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5428_vlb_device = -{ - "Cirrus Logic CL-GD 5428 (VLB)", - DEVICE_VLB, - CIRRUS_ID_CLGD5428, - gd54xx_init, - gd54xx_close, - NULL, - gd5428_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +/*According to a Diamond bios file listing and vgamuseum*/ +const device_t gd5426_diamond_speedstar_pro_a1_isa_device = { + .name = "Cirrus Logic GD5426 (ISA) (Diamond SpeedStar Pro Rev. A1)", + .internal_name = "cl_gd5426_diamond_a1_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5426 | 0x100, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5426_diamond_a1_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5428_mca_device = -{ - "Cirrus Logic CL-GD 5428 (IBM SVGA Adapter/A)", - DEVICE_MCA, - CIRRUS_ID_CLGD5428, - gd54xx_init, - gd54xx_close, - NULL, - gd5428_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - NULL +const device_t gd5426_vlb_device = { + .name = "Cirrus Logic GD5426 (VLB)", + .internal_name = "cl_gd5426_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5426, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5428_a1g_device = -{ - "Cirrus Logic CL-GD 5428 (Onboard)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5428, - gd54xx_init, - gd54xx_close, - NULL, - gd5428_isa_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_a1g_config +const device_t gd5426_onboard_device = { + .name = "Cirrus Logic GD5426 (VLB) (On-Board)", + .internal_name = "cl_gd5426_onboard", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5426 | 0x200, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = NULL }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = NULL }; -const device_t gd5429_isa_device = -{ - "Cirrus Logic CL-GD 5429 (ISA)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5429, - gd54xx_init, - gd54xx_close, - NULL, - gd5429_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +const device_t gd5428_isa_device = { + .name = "Cirrus Logic GD5428 (ISA)", + .internal_name = "cl_gd5428_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5428, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_isa_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5429_vlb_device = -{ - "Cirrus Logic CL-GD 5429 (VLB)", - DEVICE_VLB, - CIRRUS_ID_CLGD5429, - gd54xx_init, - gd54xx_close, - NULL, - gd5429_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +const device_t gd5428_vlb_device = { + .name = "Cirrus Logic GD5428 (VLB)", + .internal_name = "cl_gd5428_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5428, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5430_vlb_device = -{ - "Cirrus Logic CL-GD 5430 (VLB)", - DEVICE_VLB, - CIRRUS_ID_CLGD5430, - gd54xx_init, - gd54xx_close, - NULL, - gd5430_vlb_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +/*According to a Diamond bios file listing and vgamuseum*/ +const device_t gd5428_diamond_speedstar_pro_b1_vlb_device = { + .name = "Cirrus Logic GD5428 (VLB) (Diamond SpeedStar Pro Rev. B1)", + .internal_name = "cl_gd5428_diamond_b1_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5428 | 0x100, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_diamond_b1_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5430_pci_device = -{ - "Cirrus Logic CL-GD 5430 (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5430, - gd54xx_init, - gd54xx_close, - NULL, - gd5430_pci_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +const device_t gd5428_mca_device = { + .name = "Cirrus Logic GD5428 (MCA) (IBM SVGA Adapter/A)", + .internal_name = "ibm1mbsvga", + .flags = DEVICE_MCA, + .local = CIRRUS_ID_CLGD5428, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_mca_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = NULL }; -const device_t gd5434_isa_device = -{ - "Cirrus Logic CL-GD 5434 (ISA)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5434, - gd54xx_init, - gd54xx_close, - NULL, - gd5434_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +const device_t gd5426_mca_device = { + .name = "Cirrus Logic GD5426 (MCA) (Reply Video Adapter)", + .internal_name = "replymcasvga", + .flags = DEVICE_MCA, + .local = CIRRUS_ID_CLGD5426, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5426_mca_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5426_config }; -const device_t gd5434_vlb_device = -{ - "Cirrus Logic CL-GD 5434 (VLB)", - DEVICE_VLB, - CIRRUS_ID_CLGD5434, - gd54xx_init, - gd54xx_close, - NULL, - gd5434_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +const device_t gd5428_onboard_device = { + .name = "Cirrus Logic GD5428 (ISA) (On-Board)", + .internal_name = "cl_gd5428_onboard", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5428, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5428_isa_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5428_onboard_config }; -const device_t gd5434_pci_device = -{ - "Cirrus Logic CL-GD 5434 (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5434, - gd54xx_init, - gd54xx_close, - NULL, - gd5434_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +const device_t gd5429_isa_device = { + .name = "Cirrus Logic GD5429 (ISA)", + .internal_name = "cl_gd5429_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5429, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5429_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5429_config }; -const device_t gd5436_pci_device = -{ - "Cirrus Logic CL-GD 5436 (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5436, - gd54xx_init, - gd54xx_close, - NULL, - gd5436_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +const device_t gd5429_vlb_device = { + .name = "Cirrus Logic GD5429 (VLB)", + .internal_name = "cl_gd5429_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5429, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5429_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5429_config }; -const device_t gd5440_onboard_pci_device = -{ - "Cirrus Logic CL-GD 5440 (On-Board PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5440 | 0x600, - gd54xx_init, - gd54xx_close, - NULL, - NULL, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5440_onboard_config +/*According to a Diamond bios file listing and vgamuseum*/ +const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device = { + .name = "Cirrus Logic GD5430 (VLB) (Diamond SpeedStar Pro SE Rev. A8)", + .internal_name = "cl_gd5430_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5430, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5430_diamond_a8_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5429_config }; -const device_t gd5440_pci_device = -{ - "Cirrus Logic CL-GD 5440 (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5440 | 0x400, - gd54xx_init, - gd54xx_close, - NULL, - gd5440_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5428_config +const device_t gd5430_pci_device = { + .name = "Cirrus Logic GD5430 (PCI)", + .internal_name = "cl_gd5430_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5430, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5430_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5429_config }; -const device_t gd5446_pci_device = -{ - "Cirrus Logic CL-GD 5446 (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5446, - gd54xx_init, - gd54xx_close, - NULL, - gd5446_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +const device_t gd5434_isa_device = { + .name = "Cirrus Logic GD5434 (ISA)", + .internal_name = "cl_gd5434_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5434, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5434_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_config }; -const device_t gd5446_stb_pci_device = -{ - "STB Nitro 64V (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5446 | 0x100, - gd54xx_init, - gd54xx_close, - NULL, - gd5446_stb_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +/*According to a Diamond bios file listing and vgamuseum*/ +const device_t gd5434_diamond_speedstar_64_a3_isa_device = { + .name = "Cirrus Logic GD5434 (ISA) (Diamond SpeedStar 64 Rev. A3)", + .internal_name = "cl_gd5434_diamond_a3_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = CIRRUS_ID_CLGD5434 | 0x100, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5434_diamond_a3_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5429_config }; -const device_t gd5480_pci_device = -{ - "Cirrus Logic CL-GD 5480 (PCI)", - DEVICE_PCI, - CIRRUS_ID_CLGD5480, - gd54xx_init, - gd54xx_close, - NULL, - gd5480_available, - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5434_config +const device_t gd5434_onboard_pci_device = { + .name = "Cirrus Logic GD5434-4 (PCI) (On-Board)", + .internal_name = "cl_gd5434_onboard_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5434 | 0x200, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = NULL }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_onboard_config +}; + +const device_t gd5434_vlb_device = { + .name = "Cirrus Logic GD5434 (VLB)", + .internal_name = "cl_gd5434_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5434, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5434_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_config +}; + +const device_t gd5434_pci_device = { + .name = "Cirrus Logic GD5434 (PCI)", + .internal_name = "cl_gd5434_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5434, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5434_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_config +}; + +const device_t gd5436_pci_device = { + .name = "Cirrus Logic GD5436 (PCI)", + .internal_name = "cl_gd5436_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5436, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5436_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_config +}; + +const device_t gd5440_onboard_pci_device = { + .name = "Cirrus Logic GD5440 (PCI) (On-Board)", + .internal_name = "cl_gd5440_onboard_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5440 | 0x600, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = NULL }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5440_onboard_config +}; + +const device_t gd5440_pci_device = { + .name = "Cirrus Logic GD5440 (PCI)", + .internal_name = "cl_gd5440_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5440 | 0x400, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5440_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5429_config +}; + +const device_t gd5446_pci_device = { + .name = "Cirrus Logic GD5446 (PCI)", + .internal_name = "cl_gd5446_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5446, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5446_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_config +}; + +const device_t gd5446_stb_pci_device = { + .name = "Cirrus Logic GD5446 (PCI) (STB Nitro 64V)", + .internal_name = "cl_gd5446_stb_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5446 | 0x100, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5446_stb_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5434_config +}; + +const device_t gd5480_pci_device = { + .name = "Cirrus Logic GD5480 (PCI)", + .internal_name = "cl_gd5480_pci", + .flags = DEVICE_PCI, + .local = CIRRUS_ID_CLGD5480, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + { .available = gd5480_available }, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd5480_config }; diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index 934fec827..2dc2d2308 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -99,8 +99,7 @@ void colorplus_write(uint32_t addr, uint8_t val, void *p) colorplus->cga.charbuffer[offset] = colorplus->cga.vram[addr & 0x7fff]; colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } - egawrites++; - sub_cycles(4); + cycles -= 4; } uint8_t colorplus_read(uint32_t addr, void *p) @@ -112,19 +111,18 @@ uint8_t colorplus_read(uint32_t addr, void *p) (colorplus->cga.cgamode & CGA_GRAPHICS_MODE)) { addr ^= 0x4000; - } + } else if (!(colorplus->control & COLORPLUS_EITHER_MODE)) { addr &= 0x3FFF; } - sub_cycles(4); + cycles -= 4; if (colorplus->cga.snow_enabled) { int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc; colorplus->cga.charbuffer[offset] = colorplus->cga.vram[addr & 0x7fff]; colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } - egareads++; return colorplus->cga.vram[addr & 0x7fff]; } @@ -164,7 +162,7 @@ void colorplus_poll(void *p) colorplus->cga.cgastat |= 1; colorplus->cga.linepos = 1; oldsc = colorplus->cga.sc; - if ((colorplus->cga.crtc[8] & 3) == 3) + if ((colorplus->cga.crtc[8] & 3) == 3) colorplus->cga.sc = ((colorplus->cga.sc << 1) + colorplus->cga.oddeven) & 7; if (colorplus->cga.cgadispon) { @@ -193,7 +191,7 @@ void colorplus_poll(void *p) for (c = 0; c < 8; c++) { buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = - buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; dat0 <<= 2; dat1 <<= 2; @@ -254,7 +252,7 @@ void colorplus_poll(void *p) if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) colorplus->cga.cgastat |= 8; colorplus->cga.displine++; - if (colorplus->cga.displine >= 360) + if (colorplus->cga.displine >= 360) colorplus->cga.displine = 0; } else @@ -267,10 +265,10 @@ void colorplus_poll(void *p) if (!colorplus->cga.vsynctime) colorplus->cga.cgastat &= ~8; } - if (colorplus->cga.sc == (colorplus->cga.crtc[11] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[11] & 31) >> 1))) - { - colorplus->cga.con = 0; - colorplus->cga.coff = 1; + if (colorplus->cga.sc == (colorplus->cga.crtc[11] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[11] & 31) >> 1))) + { + colorplus->cga.con = 0; + colorplus->cga.coff = 1; } if ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == (colorplus->cga.crtc[9] >> 1)) colorplus->cga.maback = colorplus->cga.ma; @@ -295,7 +293,7 @@ void colorplus_poll(void *p) colorplus->cga.vc++; colorplus->cga.vc &= 127; - if (colorplus->cga.vc == colorplus->cga.crtc[6]) + if (colorplus->cga.vc == colorplus->cga.crtc[6]) colorplus->cga.cgadispon = 0; if (oldvc == colorplus->cga.crtc[4]) @@ -326,11 +324,11 @@ void colorplus_poll(void *p) if (ysize < 32) ysize = 200; set_screen_size(xsize, (ysize << 1) + 16); } - - if (colorplus->cga.composite) - video_blit_memtoscreen(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); - else - video_blit_memtoscreen_8(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + + if (colorplus->cga.composite) + video_blit_memtoscreen(0, colorplus->cga.firstline - 4, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + else + video_blit_memtoscreen_8(0, colorplus->cga.firstline - 4, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); frames++; video_res_x = xsize - 16; @@ -371,7 +369,7 @@ void colorplus_poll(void *p) } if (colorplus->cga.cgadispon) colorplus->cga.cgastat &= ~1; - if ((colorplus->cga.sc == (colorplus->cga.crtc[10] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[10] & 31) >> 1)))) + if ((colorplus->cga.sc == (colorplus->cga.crtc[10] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[10] & 31) >> 1)))) colorplus->cga.con = 1; if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & 1)) { @@ -395,7 +393,7 @@ void *colorplus_standalone_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_CGA, &timing_colorplus); - /* Copied from the CGA init. Ideally this would be done by + /* Copied from the CGA init. Ideally this would be done by * calling a helper function rather than duplicating code */ display_type = device_get_config_int("display_type"); colorplus->cga.composite = (display_type != CGA_RGB); @@ -403,12 +401,12 @@ void *colorplus_standalone_init(const device_t *info) colorplus->cga.snow_enabled = device_get_config_int("snow_enabled"); colorplus->cga.vram = malloc(0x8000); - + cga_comp_init(colorplus->cga.revision); timer_add(&colorplus->cga.timer, colorplus_poll, colorplus, 1); mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, colorplus); io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); - + lpt3_init(0x3BC); return colorplus; @@ -425,56 +423,73 @@ void colorplus_close(void *p) void colorplus_speed_changed(void *p) { colorplus_t *colorplus = (colorplus_t *)p; - + cga_recalctimings(&colorplus->cga); } -static const device_config_t colorplus_config[] = -{ - { - "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, - { - { - "RGB", CGA_RGB - }, - { - "Composite", CGA_COMPOSITE - }, - { - "" - } - } - }, - { - "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, - { - { - "Old", COMPOSITE_OLD - }, - { - "New", COMPOSITE_NEW - }, - { - "" - } - } - }, - { - "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 +static const device_config_t colorplus_config[] = { +// clang-format off + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_int = CGA_RGB, + .selection = { + { + .description = "RGB", + .value = CGA_RGB + }, + { + .description = "Composite", + .value = CGA_COMPOSITE + }, + { + .description = "" + } } + }, + { + .name = "composite_type", + .description = "Composite type", + .type = CONFIG_SELECTION, + .default_int = COMPOSITE_OLD, + .selection = { + { + .description = "Old", + .value = COMPOSITE_OLD + }, + { + .description = "New", + .value = COMPOSITE_NEW + }, + { + .description = "" + } + } + }, + { + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = CONFIG_END + } +// clang-format on }; const device_t colorplus_device = { - "Colorplus", - DEVICE_ISA, 0, - colorplus_standalone_init, - colorplus_close, - NULL, NULL, - colorplus_speed_changed, - NULL, - colorplus_config + .name = "Colorplus", + .internal_name = "plantronics", + .flags = DEVICE_ISA, + .local = 0, + .init = colorplus_standalone_init, + .close = colorplus_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = colorplus_speed_changed, + .force_redraw = NULL, + .config = colorplus_config }; diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_compaq_cga.c index 007bbca09..052fcfb7d 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_compaq_cga.c @@ -45,7 +45,7 @@ static uint32_t vflags; static uint8_t mdaattr[256][2][2]; -typedef struct compaq_cga_t +typedef struct compaq_cga_t { cga_t cga; } compaq_cga_t; @@ -115,7 +115,7 @@ compaq_cga_poll(void *p) self->cga.cgastat |= 1; self->cga.linepos = 1; oldsc = self->cga.sc; - if ((self->cga.crtc[8] & 3) == 3) + if ((self->cga.crtc[8] & 3) == 3) self->cga.sc = ((self->cga.sc << 1) + self->cga.oddeven) & 7; if (self->cga.cgadispon) { if (self->cga.displine < self->cga.firstline) { @@ -160,7 +160,7 @@ compaq_cga_poll(void *p) if (blink) cols[1] = cols[0]; } else { - if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) cols[1] = cols[0]; } } else { @@ -203,7 +203,7 @@ compaq_cga_poll(void *p) if (blink) cols[1] = cols[0]; } else { - if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) cols[1] = cols[0]; } } else { @@ -255,7 +255,7 @@ compaq_cga_poll(void *p) if (self->cga.vc == self->cga.crtc[7] && !self->cga.sc) self->cga.cgastat |= 8; self->cga.displine++; - if (self->cga.displine >= 500) + if (self->cga.displine >= 500) self->cga.displine = 0; } else { timer_advance_u64(&self->cga.timer, self->cga.dispontime); @@ -266,9 +266,9 @@ compaq_cga_poll(void *p) self->cga.cgastat &= ~8; } - if (self->cga.sc == (self->cga.crtc[11] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[11] & 31) >> 1))) { - self->cga.con = 0; - self->cga.coff = 1; + if (self->cga.sc == (self->cga.crtc[11] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[11] & 31) >> 1))) { + self->cga.con = 0; + self->cga.coff = 1; } if ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == (self->cga.crtc[9] >> 1)) self->cga.maback = self->cga.ma; @@ -289,7 +289,7 @@ compaq_cga_poll(void *p) self->cga.vc++; self->cga.vc &= 127; - if (self->cga.vc == self->cga.crtc[6]) + if (self->cga.vc == self->cga.crtc[6]) self->cga.cgadispon = 0; if (oldvc == self->cga.crtc[4]) { @@ -315,8 +315,8 @@ compaq_cga_poll(void *p) compaq_cga_log("Lastline %i Firstline %i %i\n", self->cga.lastline, self->cga.firstline ,self->cga.lastline - self->cga.firstline); - if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3); - else x = (self->cga.crtc[1] << 4); + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; + else x = (self->cga.crtc[1] << 4) + 16; self->cga.lastline++; @@ -324,10 +324,10 @@ compaq_cga_poll(void *p) ys_temp = (self->cga.lastline - self->cga.firstline); if ((xs_temp > 0) && (ys_temp > 0)) { - if (xsize < 64) xs_temp = 656; - if (ysize < 32) ys_temp = 400; + if (xs_temp < 64) xs_temp = 656; + if (ys_temp < 32) ys_temp = 400; if (!enable_overscan) - xsize -= 16; + xs_temp -= 16; if ((self->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { xsize = xs_temp; @@ -339,15 +339,15 @@ compaq_cga_poll(void *p) } if (enable_overscan) { - if (self->cga.composite) - video_blit_memtoscreen(0, self->cga.firstline - 8, 0, ysize + 16, xsize + 16, ysize + 16); - else - video_blit_memtoscreen_8(0, self->cga.firstline - 8, 0, ysize + 16, xsize + 16, ysize + 16); + if (self->cga.composite) + video_blit_memtoscreen(0, self->cga.firstline - 8, xsize, (self->cga.lastline - self->cga.firstline) + 16); + else + video_blit_memtoscreen_8(0, self->cga.firstline - 8, xsize, (self->cga.lastline - self->cga.firstline) + 16); } else { - if (self->cga.composite) - video_blit_memtoscreen(8, self->cga.firstline, 0, ysize, xsize, ysize); - else - video_blit_memtoscreen_8(8, self->cga.firstline, 0, ysize, xsize, ysize); + if (self->cga.composite) + video_blit_memtoscreen(8, self->cga.firstline, xsize, self->cga.lastline - self->cga.firstline); + else + video_blit_memtoscreen_8(8, self->cga.firstline, xsize, self->cga.lastline - self->cga.firstline); } } @@ -386,7 +386,7 @@ compaq_cga_poll(void *p) if (self->cga.cgadispon) self->cga.cgastat &= ~1; - if ((self->cga.sc == (self->cga.crtc[10] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[10] & 31) >> 1)))) + if ((self->cga.sc == (self->cga.crtc[10] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[10] & 31) >> 1)))) self->cga.con = 1; if (self->cga.cgadispon && (self->cga.cgamode & 1)) { @@ -476,28 +476,30 @@ compaq_cga_speed_changed(void *p) extern const device_config_t cga_config[]; -const device_t compaq_cga_device = -{ - "Compaq CGA", - DEVICE_ISA, 0, - compaq_cga_init, - compaq_cga_close, - NULL, - NULL, - compaq_cga_speed_changed, - NULL, - cga_config +const device_t compaq_cga_device = { + .name = "Compaq CGA", + .internal_name = "compaq_cga", + .flags = DEVICE_ISA, + .local = 0, + .init = compaq_cga_init, + .close = compaq_cga_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = compaq_cga_speed_changed, + .force_redraw = NULL, + .config = cga_config }; -const device_t compaq_cga_2_device = -{ - "Compaq CGA 2", - DEVICE_ISA, 1, - compaq_cga_init, - compaq_cga_close, - NULL, - NULL, - compaq_cga_speed_changed, - NULL, - cga_config +const device_t compaq_cga_2_device = { + .name = "Compaq CGA 2", + .internal_name = "compaq_cga_2", + .flags = DEVICE_ISA, + .local = 1, + .init = compaq_cga_init, + .close = compaq_cga_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = compaq_cga_speed_changed, + .force_redraw = NULL, + .config = cga_config }; diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c new file mode 100644 index 000000000..6fc8276e4 --- /dev/null +++ b/src/video/vid_ddc.c @@ -0,0 +1,233 @@ +/* + * 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. + * + * DDC monitor emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/i2c.h> + + +#define PIXEL_MM(px) ((uint16_t) (((px) * 25.4) / 96)) +#define STANDARD_TIMING(slot, width, aspect_ratio, refresh) do { \ + edid->slot.horiz_pixels = ((width) >> 3) - 31; \ + edid->slot.aspect_ratio_refresh_rate = ((aspect_ratio) << 6) | ((refresh) - 60); \ + } while (0) +#define DETAILED_TIMING(slot, clk, width, height, hblank, vblank, hfp, hsp, vfp, vsp) do { \ + edid->slot.pixel_clock_lsb = ((clk) / 10) & 0xff; \ + edid->slot.pixel_clock_msb = ((clk) / 10) >> 8; \ + edid->slot.h_active_lsb = (width) & 0xff; \ + edid->slot.h_blank_lsb = (hblank) & 0xff; \ + edid->slot.h_active_blank_msb = (((width) >> 4) & 0xf0) | (((hblank) >> 8) & 0x0f); \ + edid->slot.v_active_lsb = (height) & 0xff; \ + edid->slot.v_blank_lsb = (vblank) & 0xff; \ + edid->slot.v_active_blank_msb = (((height) >> 4) & 0xf0) | (((vblank) >> 8) & 0x0f); \ + edid->slot.h_front_porch_lsb = (hfp) & 0xff; \ + edid->slot.h_sync_pulse_lsb = (hsp) & 0xff; \ + edid->slot.v_front_porch_sync_pulse_lsb = (((vfp) & 0x0f) << 4) | ((vsp) & 0x0f); \ + edid->slot.hv_front_porch_sync_pulse_msb = (((hfp) >> 2) & 0xc0) | (((hsp) >> 4) & 0x30) | (((vfp) >> 2) & 0x0c) | (((vsp) >> 4) & 0x03); \ + edid->slot.h_size_lsb = horiz_mm & 0xff; \ + edid->slot.v_size_lsb = vert_mm & 0xff; \ + edid->slot.hv_size_msb = ((horiz_mm >> 4) & 0xf0) | ((vert_mm >> 8) & 0x0f); \ + } while (0) + + +enum { + STD_ASPECT_16_10 = 0x0, + STD_ASPECT_4_3, + STD_ASPECT_5_4, + STD_ASPECT_16_9 +}; + +typedef struct { + uint8_t horiz_pixels, aspect_ratio_refresh_rate; +} edid_standard_timing_t; + +typedef struct { + uint8_t pixel_clock_lsb, pixel_clock_msb, h_active_lsb, h_blank_lsb, + h_active_blank_msb, v_active_lsb, v_blank_lsb, v_active_blank_msb, + h_front_porch_lsb, h_sync_pulse_lsb, v_front_porch_sync_pulse_lsb, + hv_front_porch_sync_pulse_msb, h_size_lsb, v_size_lsb, hv_size_msb, + h_border, v_border, features; +} edid_detailed_timing_t; + +typedef struct { + uint8_t magic[2], reserved, tag, range_limit_offsets; + union { + char ascii[13]; + struct { + uint8_t min_v_field, max_v_field, min_h_line, max_h_line, max_pixel_clock, + timing_type; + union { + uint8_t padding[7]; + struct { + uint8_t reserved, gtf_start_freq, gtf_c, gtf_m_lsb, gtf_m_msb, + gtf_k, gtf_j; + }; + struct { + uint8_t cvt_version, add_clock_precision, max_active_pixels, + aspect_ratios, aspect_ratio_pref, scaling_support, + refresh_pref; + }; + }; + } range_limits; + struct { + edid_standard_timing_t timings[6]; + uint8_t padding; + } ext_standard_timings; + struct { + uint8_t version; + struct { + uint8_t lines_lsb, lines_msb_aspect_ratio, refresh_rate; + } timings[4]; + } cvt_timings; + struct { + uint8_t version, timings[6], reserved[6]; + } established_timings3; + }; +} edid_descriptor_t; + +typedef struct { + uint8_t magic[8], mfg[2], mfg_product[2], serial[4], mfg_week, mfg_year, + edid_version, edid_rev; + uint8_t input_params, horiz_size, vert_size, gamma, features; + uint8_t red_green_lsb, blue_white_lsb, red_x_msb, red_y_msb, green_x_msb, + green_y_msb, blue_x_msb, blue_y_msb, white_x_msb, white_y_msb; + uint8_t established_timings[3]; + edid_standard_timing_t standard_timings[8]; + union { + edid_detailed_timing_t detailed_timings[4]; + edid_descriptor_t descriptors[4]; + }; + uint8_t extensions, checksum; + + uint8_t ext_tag, ext_rev, ext_dtd_offset, ext_native_dtds; + union { + edid_detailed_timing_t ext_detailed_timings[6]; + edid_descriptor_t ext_descriptors[6]; + }; + uint8_t padding[15], checksum2; +} edid_t; + + +void * +ddc_init(void *i2c) +{ + edid_t *edid = malloc(sizeof(edid_t)); + memset(edid, 0, sizeof(edid_t)); + + uint8_t *edid_bytes = (uint8_t *) edid; + uint16_t horiz_mm = PIXEL_MM(1366), vert_mm = PIXEL_MM(768); + + memset(&edid->magic[1], 0xff, sizeof(edid->magic) - 2); + + edid->mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */ + edid->mfg[1] = 0xf8; + edid->mfg_week = 48; + edid->mfg_year = 2020 - 1990; + edid->edid_version = 0x01; + edid->edid_rev = 0x03; /* EDID 1.3 */ + + edid->input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */ + edid->horiz_size = horiz_mm / 10; + edid->vert_size = vert_mm / 10; + edid->features = 0xeb; /* DPMS standby/suspend/active-off; RGB color; first timing is preferred; GTF/CVT */ + + edid->red_green_lsb = 0x81; + edid->blue_white_lsb = 0xf1; + edid->red_x_msb = 0xa3; + edid->red_y_msb = 0x57; + edid->green_x_msb = 0x53; + edid->green_y_msb = 0x9f; + edid->blue_x_msb = 0x27; + edid->blue_y_msb = 0x0a; + edid->white_x_msb = 0x50; + edid->white_y_msb = 0x00; + + memset(&edid->established_timings, 0xff, sizeof(edid->established_timings)); /* all enabled */ + + /* 60 Hz timings */ + STANDARD_TIMING(standard_timings[0], 1280, STD_ASPECT_16_9, 60); /* 1280x720 */ + STANDARD_TIMING(standard_timings[1], 1280, STD_ASPECT_16_10, 60); /* 1280x800 */ + STANDARD_TIMING(standard_timings[2], 1366, STD_ASPECT_16_9, 60); /* 1360x768 (closest to 1366x768) */ + STANDARD_TIMING(standard_timings[3], 1440, STD_ASPECT_16_10, 60); /* 1440x900 */ + STANDARD_TIMING(standard_timings[4], 1600, STD_ASPECT_16_9, 60); /* 1600x900 */ + STANDARD_TIMING(standard_timings[5], 1680, STD_ASPECT_16_10, 60); /* 1680x1050 */ + STANDARD_TIMING(standard_timings[6], 1920, STD_ASPECT_16_9, 60); /* 1920x1080 */ + STANDARD_TIMING(standard_timings[7], 2048, STD_ASPECT_4_3, 60); /* 2048x1536 */ + + /* Detailed timing for the preferred mode of 800x600 @ 60 Hz */ + DETAILED_TIMING(detailed_timings[0], 40000, 800, 600, 256, 28, 40, 128, 1, 4); + + edid->descriptors[1].tag = 0xf7; /* established timings 3 */ + edid->descriptors[1].established_timings3.version = 0x0a; + memset(&edid->descriptors[1].established_timings3.timings, 0xff, sizeof(edid->descriptors[1].established_timings3.timings)); /* all enabled */ + edid->descriptors[1].established_timings3.timings[5] &= 0xf0; /* reserved bits */ + + edid->descriptors[2].tag = 0xfd; /* range limits */ + edid->descriptors[2].range_limits.min_v_field = 45; + edid->descriptors[2].range_limits.max_v_field = 125; + edid->descriptors[2].range_limits.min_h_line = 30; /* 640x480 = ~31.5 KHz */ + edid->descriptors[2].range_limits.max_h_line = 115; /* 1920x1440 = 112.5 KHz */ + edid->descriptors[2].range_limits.max_pixel_clock = 30; /* 1920x1440 = 297 MHz */ + edid->descriptors[2].range_limits.timing_type = 0x00; /* default GTF */ + edid->descriptors[2].range_limits.padding[0] = 0x0a; + memset(&edid->descriptors[2].range_limits.padding[1], 0x20, sizeof(edid->descriptors[2].range_limits.padding) - 1); + + edid->descriptors[3].tag = 0xfc; /* display name */ + memcpy(&edid->descriptors[3].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */ + + edid->extensions = 1; + for (uint8_t c = 0; c < 127; c++) + edid->checksum += edid_bytes[c]; + edid->checksum = 256 - edid->checksum; + + edid->ext_tag = 0x02; + edid->ext_rev = 0x03; + edid->ext_native_dtds = 0x80; /* underscans IT; no native extended modes */ + edid->ext_dtd_offset = 0x04; + + /* Detailed timing for 1366x768 */ + DETAILED_TIMING(ext_detailed_timings[0], 85500, 1366, 768, 426, 30, 70, 143, 3, 3); + + /* High refresh rate timings (VGA is limited to 85 Hz) */ + edid->ext_descriptors[1].tag = 0xfa; /* standard timing identifiers */ +#define ext_standard_timings0 ext_descriptors[1].ext_standard_timings.timings + STANDARD_TIMING(ext_standard_timings0[0], 640, STD_ASPECT_4_3, 90); /* 640x480 @ 90 Hz */ + STANDARD_TIMING(ext_standard_timings0[1], 640, STD_ASPECT_4_3, 120); /* 640x480 @ 120 Hz */ + STANDARD_TIMING(ext_standard_timings0[2], 800, STD_ASPECT_4_3, 90); /* 800x600 @ 90 Hz */ + STANDARD_TIMING(ext_standard_timings0[3], 800, STD_ASPECT_4_3, 120); /* 800x600 @ 120 Hz */ + STANDARD_TIMING(ext_standard_timings0[4], 1024, STD_ASPECT_4_3, 90); /* 1024x768 @ 90 Hz */ + STANDARD_TIMING(ext_standard_timings0[5], 1280, STD_ASPECT_5_4, 90); /* 1280x1024 @ 90 Hz */ + edid->ext_descriptors[1].ext_standard_timings.padding = 0x0a; + + for (uint8_t c = 128; c < 255; c++) + edid->checksum2 += edid_bytes[c]; + edid->checksum2 = 256 - edid->checksum2; + + return i2c_eeprom_init(i2c, 0x50, edid_bytes, sizeof(edid_t), 0); +} + + +void +ddc_close(void *eeprom) +{ + i2c_eeprom_close(eeprom); +} diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index b740f11f0..a8f23b7b8 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -35,27 +35,31 @@ #include <86box/vid_ega.h> -void ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega); +void ega_doblit(int wx, int wy, ega_t *ega); -#define BIOS_IBM_PATH L"roms/video/ega/ibm_6277356_ega_card_u44_27128.bin" -#define BIOS_CPQ_PATH L"roms/video/ega/108281-001.bin" -#define BIOS_SEGA_PATH L"roms/video/ega/lega.vbi" -#define BIOS_ATIEGA_PATH L"roms/video/ega/ATI EGA Wonder 800+ N1.00.BIN" +#define BIOS_IBM_PATH "roms/video/ega/ibm_6277356_ega_card_u44_27128.bin" +#define BIOS_CPQ_PATH "roms/video/ega/108281-001.bin" +#define BIOS_SEGA_PATH "roms/video/ega/lega.vbi" +#define BIOS_ATIEGA_PATH "roms/video/ega/ATI EGA Wonder 800+ N1.00.BIN" +#define BIOS_ISKRA_PATH "roms/video/ega/143-02.bin", "roms/video/ega/143-03.bin" +#define BIOS_TSENG_PATH "roms/video/ega/EGA ET2000.BIN" enum { EGA_IBM = 0, EGA_COMPAQ, EGA_SUPEREGA, - EGA_ATI + EGA_ATI, + EGA_ISKRA, + EGA_TSENG }; static video_timings_t timing_ega = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; static uint8_t ega_rotate[8][256]; static uint32_t pallook16[256], pallook64[256]; -static int old_overscan_color = 0; +static int ega_type = 0, old_overscan_color = 0; extern uint8_t edatlookup[4][4]; @@ -65,6 +69,9 @@ int egaswitchread, egaswitches=9; int update_overscan = 0; +uint8_t ega_in(uint16_t addr, void *p); + + void ega_out(uint16_t addr, uint8_t val, void *p) { @@ -72,7 +79,7 @@ ega_out(uint16_t addr, uint8_t val, void *p) int c; uint8_t o, old; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; switch (addr) { @@ -104,20 +111,21 @@ ega_out(uint16_t addr, uint8_t val, void *p) if (!ega->attrff) { ega->attraddr = val & 31; if ((val & 0x20) != ega->attr_palette_enable) { - fullchange = 3; + ega->fullchange = 3; ega->attr_palette_enable = val & 0x20; ega_recalctimings(ega); } } else { o = ega->attrregs[ega->attraddr & 31]; ega->attrregs[ega->attraddr & 31] = val; - if (ega->attraddr < 16) - fullchange = changeframecount; + if (ega->attraddr < 16) + ega->fullchange = changeframecount; if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) { for (c = 0; c < 16; c++) { if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); } + ega->fullchange = changeframecount; } /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ @@ -141,22 +149,25 @@ ega_out(uint16_t addr, uint8_t val, void *p) ega->vidclock = val & 4; ega->miscout = val; ega->overscan_color = ega->vres ? pallook16[ega->attrregs[0x11] & 0x0f] : pallook64[ega->attrregs[0x11] & 0x3f]; + io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + if (!(val & 1)) + io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); if ((o ^ val) & 0x80) ega_recalctimings(ega); break; - case 0x3c4: - ega->seqaddr = val; + case 0x3c4: + ega->seqaddr = val; break; case 0x3c5: o = ega->seqregs[ega->seqaddr & 0xf]; ega->seqregs[ega->seqaddr & 0xf] = val; - if (o != val && (ega->seqaddr & 0xf) == 1) + if (o != val && (ega->seqaddr & 0xf) == 1) ega_recalctimings(ega); switch (ega->seqaddr & 0xf) { case 1: - if (ega->scrblank && !(val & 0x20)) - fullchange = 3; - ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + if (ega->scrblank && !(val & 0x20)) + ega->fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); break; case 2: ega->writemask = val & 0xf; @@ -170,21 +181,21 @@ ega_out(uint16_t addr, uint8_t val, void *p) break; } break; - case 0x3ce: - ega->gdcaddr = val; + case 0x3ce: + ega->gdcaddr = val; break; case 0x3cf: ega->gdcreg[ega->gdcaddr & 15] = val; switch (ega->gdcaddr & 15) { case 2: - ega->colourcompare = val; + ega->colourcompare = val; break; case 4: - ega->readplane = val & 3; + ega->readplane = val & 3; break; case 5: ega->writemode = val & 3; - ega->readmode = val & 8; + ega->readmode = val & 8; ega->chain2_read = val & 0x10; break; case 6: @@ -203,8 +214,8 @@ ega_out(uint16_t addr, uint8_t val, void *p) break; } break; - case 7: - ega->colournocare = val; + case 7: + ega->colournocare = val; break; } break; @@ -220,20 +231,27 @@ ega_out(uint16_t addr, uint8_t val, void *p) ega->crtc[ega->crtcreg] = val; if (old != val) { if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) { - fullchange = changeframecount; - ega_recalctimings(ega); + if ((ega->crtcreg == 0xc) || (ega->crtcreg == 0xd)) { + ega->fullchange = 3; + ega->ma_latch = ((ega->crtc[0xc] << 8) | ega->crtc[0xd]) + ((ega->crtc[8] & 0x60) >> 5); + } else { + ega->fullchange = changeframecount; + ega_recalctimings(ega); + } } } break; } } -uint8_t ega_in(uint16_t addr, void *p) + +uint8_t +ega_in(uint16_t addr, void *p) { ega_t *ega = (ega_t *)p; uint8_t ret = 0xff; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; switch (addr) { @@ -253,39 +271,49 @@ uint8_t ega_in(uint16_t addr, void *p) } break; - case 0x3c0: - ret = ega->attraddr | ega->attr_palette_enable; + case 0x3c0: + if (ega_type) + ret = ega->attraddr | ega->attr_palette_enable; break; - case 0x3c1: - ret = ega->attrregs[ega->attraddr]; + case 0x3c1: + if (ega_type) + ret = ega->attrregs[ega->attraddr]; break; case 0x3c2: ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; break; - case 0x3c4: - ret = ega->seqaddr; + case 0x3c4: + if (ega_type) + ret = ega->seqaddr; break; case 0x3c5: - ret = ega->seqregs[ega->seqaddr & 0xf]; + if (ega_type) + ret = ega->seqregs[ega->seqaddr & 0xf]; break; case 0x3c8: - ret = 2; + if (ega_type) + ret = 2; break; - case 0x3cc: - ret = ega->miscout; + case 0x3cc: + if (ega_type) + ret = ega->miscout; break; - case 0x3ce: - ret = ega->gdcaddr; + case 0x3ce: + if (ega_type) + ret = ega->gdcaddr; break; case 0x3cf: - ret = ega->gdcreg[ega->gdcaddr & 0xf]; + if (ega_type) + ret = ega->gdcreg[ega->gdcaddr & 0xf]; break; case 0x3d0: case 0x3d4: - ret = ega->crtcreg; + if (ega_type) + ret = ega->crtcreg; break; case 0x3d1: case 0x3d5: - ret = ega->crtc[ega->crtcreg]; + if (ega_type) + ret = ega->crtc[ega->crtcreg]; break; case 0x3da: ega->attrff = 0; @@ -410,7 +438,7 @@ ega_recalctimings(ega_t *ega) overscan_x = (ega->seqregs[1] & 1) ? 16 : 18; - if (ega->seqregs[1] & 8) + if (ega->seqregs[1] & 8) overscan_x <<= 1; ega->y_add = (overscan_y >> 1) - (ega->crtc[8] & 0x1f); @@ -433,6 +461,8 @@ ega_recalctimings(ega_t *ega) ega->dispontime = TIMER_USEC; if (ega->dispofftime < TIMER_USEC) ega->dispofftime = TIMER_USEC; + + ega_recalc_remap_func(ega); } @@ -490,7 +520,7 @@ ega_poll(void *p) ega_render_overscan_right(ega); } - if (ega->lastline < ega->displine) + if (ega->lastline < ega->displine) ega->lastline = ega->displine; } @@ -500,18 +530,18 @@ ega_poll(void *p) if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) ega->stat &= ~8; ega->vslines++; - if (ega->displine > 500) + if (ega->displine > 500) ega->displine = 0; } else { timer_advance_u64(&ega->timer, ega->dispontime); - if (ega->dispon) + if (ega->dispon) ega->stat &= ~1; ega->hdisp_on = 0; ega->linepos = 0; if ((ega->sc == (ega->crtc[11] & 31)) || (ega->sc == ega->rowcount)) - ega->con = 0; + ega->con = 0; if (ega->dispon) { if (ega->linedbl && !ega->linecountff) { ega->linecountff = 1; @@ -533,9 +563,14 @@ ega_poll(void *p) } } ega->vc++; - ega->vc &= 1023; + ega->vc &= 511; if (ega->vc == ega->split) { - ega->ma = ega->maback = 0; + if (ega->interlace && ega->oddeven) + ega->ma = ega->maback = ega->ma_latch + (ega->rowoffset << 1); + else + ega->ma = ega->maback = ega->ma_latch; + ega->ma <<= 2; + ega->maback <<= 2; ega->sc = 0; if (ega->attrregs[0x10] & 0x20) { ega->scrollcache = 0; @@ -552,12 +587,12 @@ ega_poll(void *p) else ega->cursoron = ega->blink & (16 + (16 * blink_delay)); - if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) - fullchange = 2; + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + ega->fullchange = 2; ega->blink = (ega->blink + 1) & 0x7f; - if (fullchange) - fullchange--; + if (ega->fullchange) + ega->fullchange--; } if (ega->vc == ega->vsyncstart) { ega->dispon = 0; @@ -573,10 +608,10 @@ ega_poll(void *p) if (ega->vres) { wy = (ega->lastline - ega->firstline) << 1; - ega_doblit(ega->firstline_draw << 1, (ega->lastline_draw + 1) << 1, wx, wy, ega); + ega_doblit(wx, wy, ega); } else { wy = ega->lastline - ega->firstline; - ega_doblit(ega->firstline_draw, ega->lastline_draw + 1, wx, wy, ega); + ega_doblit(wx, wy, ega); } frames++; @@ -627,14 +662,14 @@ ega_poll(void *p) ega->linecountff = 0; } - if (ega->sc == (ega->crtc[10] & 31)) + if (ega->sc == (ega->crtc[10] & 31)) ega->con = 1; } } void -ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega) +ega_doblit(int wx, int wy, ega_t *ega) { int y_add = (enable_overscan) ? overscan_y : 0; int x_add = (enable_overscan) ? overscan_x : 0; @@ -651,15 +686,8 @@ ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega) bottom <<= 1; } - if ((wx <= 0) || (wy <= 0)) { - video_blit_memtoscreen(x_start, y_start, 0, 0, 0, 0); + if ((wx <= 0) || (wy <= 0)) return; - } - - if (y1 > y2) { - video_blit_memtoscreen(x_start, y_start, 0, 0, xsize + x_add, ysize + y_add); - return; - } if (ega->vres) ega->y_add <<= 1; @@ -673,7 +701,7 @@ ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega) if (ys_temp < 32) ys_temp = 200; - if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + if ((ega->crtc[0x17] & 0x80) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { /* Screen res has changed.. fix up, and let them know. */ xsize = xs_temp; ysize = ys_temp; @@ -710,7 +738,7 @@ ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega) } } - video_blit_memtoscreen(x_start, y_start, y1, y2 + y_add, xsize + x_add, ysize + y_add); + video_blit_memtoscreen(x_start, y_start, xsize + x_add, ysize + y_add); if (ega->vres) ega->y_add >>= 1; @@ -724,8 +752,7 @@ ega_write(uint32_t addr, uint8_t val, void *p) uint8_t vala, valb, valc, vald; int writemask2 = ega->writemask; - egawrites++; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; if (addr >= 0xB0000) addr &= 0x7fff; else addr &= 0xffff; @@ -745,8 +772,8 @@ ega_write(uint32_t addr, uint8_t val, void *p) if (addr >= ega->vram_limit) return; - if (!(ega->gdcreg[6] & 1)) - fullchange = 2; + if (!(ega->gdcreg[6] & 1)) + ega->fullchange = 2; switch (ega->writemode) { case 1: @@ -756,7 +783,7 @@ ega_write(uint32_t addr, uint8_t val, void *p) if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; break; case 0: - if (ega->gdcreg[3] & 7) + if (ega->gdcreg[3] & 7) val = ega_rotate[ega->gdcreg[3] & 7][val]; if ((ega->gdcreg[8] == 0xff) && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) { @@ -851,8 +878,7 @@ ega_read(uint32_t addr, void *p) uint8_t temp, temp2, temp3, temp4; int readplane = ega->readplane; - egareads++; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; if (addr >= 0xb0000) addr &= 0x7fff; else addr &= 0xffff; @@ -964,15 +990,19 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) break; } } + + io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); } else { for (c = 0; c < 256; c++) { pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); - if ((c & 0x17) == 6) + if ((c & 0x17) == 6) pallook16[c] = makecol32(0xaa, 0x55, 0); } + + ega->miscout |= 1; } ega->pallook = pallook16; @@ -1014,6 +1044,12 @@ ega_standalone_init(const device_t *info) ega->x_add = 8; ega->y_add = 14; + if ((info->local == EGA_IBM) || (info->local == EGA_ISKRA) || + (info->local == EGA_TSENG)) + ega_type = 0; + else + ega_type = 1; + switch(info->local) { case EGA_IBM: default: @@ -1032,6 +1068,14 @@ ega_standalone_init(const device_t *info) rom_init(&ega->bios_rom, BIOS_ATIEGA_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); break; + case EGA_ISKRA: + rom_init_interleaved(&ega->bios_rom, BIOS_ISKRA_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_TSENG: + rom_init(&ega->bios_rom, BIOS_TSENG_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; } if ((ega->bios_rom.rom[0x3ffe] == 0xaa) && (ega->bios_rom.rom[0x3fff] == 0x55)) { @@ -1049,13 +1093,13 @@ ega_standalone_init(const device_t *info) ega->vrammask = ega->vram_limit - 1; mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); - io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); if (info->local == EGA_ATI) { io_sethandler(0x01ce, 0x0002, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); ega->eeprom = malloc(sizeof(ati_eeprom_t)); memset(ega->eeprom, 0, sizeof(ati_eeprom_t)); - ati_eeprom_load((ati_eeprom_t *) ega->eeprom, L"egawonder800.nvr", 0); + ati_eeprom_load((ati_eeprom_t *) ega->eeprom, "egawonder800.nvr", 0); } return ega; @@ -1090,6 +1134,20 @@ atiega_standalone_available(void) } +static int +iskra_ega_standalone_available(void) +{ + return rom_present("roms/video/ega/143-02.bin") && rom_present("roms/video/ega/143-03.bin"); +} + + +static int +et2000_standalone_available(void) +{ + return rom_present(BIOS_TSENG_PATH); +} + + static void ega_close(void *p) { @@ -1120,115 +1178,160 @@ ega_speed_changed(void *p) 0 = Switch closed (ON); 1 = Switch open (OFF). */ -static const device_config_t ega_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 256, - { - { - "64 kB", 64 - }, - { - "128 kB", 128 - }, - { - "256 kB", 256 - }, - { - "" - } - } - }, - { - .name = "monitor_type", - .description = "Monitor type", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Monochrome (5151/MDA) (white)", - .value = 0x0B | (DISPLAY_WHITE << 4) - }, - { - .description = "Monochrome (5151/MDA) (green)", - .value = 0x0B | (DISPLAY_GREEN << 4) - }, - { - .description = "Monochrome (5151/MDA) (amber)", - .value = 0x0B | (DISPLAY_AMBER << 4) - }, - { - .description = "Color 40x25 (5153/CGA)", - .value = 0x06 - }, - { - .description = "Color 80x25 (5153/CGA)", - .value = 0x07 - }, - { - .description = "Enhanced Color - Normal Mode (5154/ECD)", - .value = 0x08 - }, - { - .description = "Enhanced Color - Enhanced Mode (5154/ECD)", - .value = 0x09 - }, - { - .description = "" - } - }, - .default_int = 9 - }, - { - .type = -1 +static const device_config_t ega_config[] = { +// clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 256, + .selection = { + { + .description = "32 kB", + .value = 32 + }, + { + .description = "64 kB", + .value = 64 + }, + { + .description = "128 kB", + .value = 128 + }, + { + .description = "256 kB", + .value = 256 + }, + { + .description = "" + } } + }, + { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "Monochrome (5151/MDA) (white)", + .value = 0x0B | (DISPLAY_WHITE << 4) + }, + { + .description = "Monochrome (5151/MDA) (green)", + .value = 0x0B | (DISPLAY_GREEN << 4) + }, + { + .description = "Monochrome (5151/MDA) (amber)", + .value = 0x0B | (DISPLAY_AMBER << 4) + }, + { + .description = "Color 40x25 (5153/CGA)", + .value = 0x06 + }, + { + .description = "Color 80x25 (5153/CGA)", + .value = 0x07 + }, + { + .description = "Enhanced Color - Normal Mode (5154/ECD)", + .value = 0x08 + }, + { + .description = "Enhanced Color - Enhanced Mode (5154/ECD)", + .value = 0x09 + }, + { + .description = "" + } + }, + .default_int = 9 + }, + { + .type = CONFIG_END + } +// clang-format on }; - -const device_t ega_device = -{ - "EGA", - DEVICE_ISA, - EGA_IBM, - ega_standalone_init, ega_close, NULL, - ega_standalone_available, - ega_speed_changed, - NULL, - ega_config +const device_t ega_device = { + .name = "EGA", + .internal_name = "ega", + .flags = DEVICE_ISA, + .local = EGA_IBM, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = ega_standalone_available }, + .speed_changed = ega_speed_changed, + .force_redraw = NULL, + .config = ega_config }; -const device_t cpqega_device = -{ - "Compaq EGA", - DEVICE_ISA, - EGA_COMPAQ, - ega_standalone_init, ega_close, NULL, - cpqega_standalone_available, - ega_speed_changed, - NULL, - ega_config +const device_t cpqega_device = { + .name = "Compaq EGA", + .internal_name = "compaq_ega", + .flags = DEVICE_ISA, + .local = EGA_COMPAQ, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = cpqega_standalone_available }, + .speed_changed = ega_speed_changed, + .force_redraw = NULL, + .config = ega_config }; -const device_t sega_device = -{ - "SuperEGA", - DEVICE_ISA, - EGA_SUPEREGA, - ega_standalone_init, ega_close, NULL, - sega_standalone_available, - ega_speed_changed, - NULL, - ega_config +const device_t sega_device = { + .name = "SuperEGA", + .internal_name = "superega", + .flags = DEVICE_ISA, + .local = EGA_SUPEREGA, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = sega_standalone_available }, + .speed_changed = ega_speed_changed, + .force_redraw = NULL, + .config = ega_config }; -const device_t atiega_device = -{ - "ATI EGA Wonder 800+", - DEVICE_ISA, - EGA_ATI, - ega_standalone_init, ega_close, NULL, - atiega_standalone_available, - ega_speed_changed, - NULL, - ega_config +const device_t atiega_device = { + .name = "ATI EGA Wonder 800+", + .internal_name = "egawonder800", + .flags = DEVICE_ISA, + .local = EGA_ATI, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = atiega_standalone_available }, + .speed_changed = ega_speed_changed, + .force_redraw = NULL, + .config = ega_config +}; + +const device_t iskra_ega_device = { + .name = "Iskra EGA (Cyrillic ROM)", + .internal_name = "iskra_ega", + .flags = DEVICE_ISA, + .local = EGA_ISKRA, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = iskra_ega_standalone_available }, + .speed_changed = ega_speed_changed, + .force_redraw = NULL, + .config = ega_config +}; + +const device_t et2000_device = { + .name = "Tseng Labs ET2000", + .internal_name = "et2000", + .flags = DEVICE_ISA, + .local = EGA_TSENG, + .init = ega_standalone_init, + .close = ega_close, + .reset = NULL, + { .available = et2000_standalone_available }, + .speed_changed = ega_speed_changed, + .force_redraw = NULL, + .config = ega_config }; diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 0ab9b5b3f..b925ab944 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -27,6 +27,7 @@ #include <86box/rom.h> #include <86box/video.h> #include <86box/vid_ega.h> +#include <86box/vid_ega_render_remap.h> int @@ -106,60 +107,69 @@ ega_render_overscan_right(ega_t *ega) void ega_render_text_40(ega_t *ega) -{ +{ uint32_t *p; int x, xx; int drawcursor, xinc; uint8_t chr, attr, dat; uint32_t charaddr; int fg, bg; + uint32_t addr; if ((ega->displine + ega->y_add) < 0) return; - if (ega->firstline_draw == 2000) + if (ega->firstline_draw == 2000) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; - if (fullchange) { + if (ega->fullchange) { p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; xinc = (ega->seqregs[1] & 1) ? 16 : 18; for (x = 0; x < (ega->hdisp + ega->scrollcache); x += xinc) { - drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); - chr = ega->vram[(ega->ma << 1) & ega->vrammask]; - attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + addr = ega->remap_func(ega, ega->ma) & ega->vrammask; - if (attr & 8) charaddr = ega->charsetb + (chr * 128); - else charaddr = ega->charseta + (chr * 128); + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + + if (ega->crtc[0x17] & 0x80) { + chr = ega->vram[addr]; + attr = ega->vram[addr + 1]; + } else + chr = attr = 0; + + if (attr & 8) + charaddr = ega->charsetb + ((chr * 0x80)); + else + charaddr = ega->charseta + ((chr * 0x80)); if (drawcursor) { - bg = ega->pallook[ega->egapal[attr & 15]]; - fg = ega->pallook[ega->egapal[attr >> 4]]; + bg = ega->pallook[ega->egapal[attr & 0x0f]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; } else { - fg = ega->pallook[ega->egapal[attr & 15]]; + fg = ega->pallook[ega->egapal[attr & 0x0f]]; bg = ega->pallook[ega->egapal[attr >> 4]]; - if (attr & 0x80 && ega->attrregs[0x10] & 8) { + if ((attr & 0x80) && ega->attrregs[0x10] & 8) { bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; - if (ega->blink & 16) + if (ega->blink & 0x10) fg = bg; } } dat = ega->vram[charaddr + (ega->sc << 2)]; if (ega->seqregs[1] & 1) { - for (xx = 0; xx < 16; xx += 2) + for (xx = 0; xx < 16; xx += 2) p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; } else { for (xx = 0; xx < 16; xx += 2) p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) p[16] = p[17] = bg; else p[16] = p[17] = (dat & 1) ? fg : bg; } - ega->ma += 4; + ega->ma += 4; p += xinc; } ega->ma &= ega->vrammask; @@ -176,55 +186,64 @@ ega_render_text_80(ega_t *ega) uint8_t chr, attr, dat; uint32_t charaddr; int fg, bg; + uint32_t addr; if ((ega->displine + ega->y_add) < 0) return; - if (ega->firstline_draw == 2000) + if (ega->firstline_draw == 2000) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; - if (fullchange) { - p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; - xinc = (ega->seqregs[1] & 1) ? 8 : 9; + if (ega->fullchange) { + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; + xinc = (ega->seqregs[1] & 1) ? 8 : 9; - for (x = 0; x < (ega->hdisp + ega->scrollcache); x += xinc) { - drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); - chr = ega->vram[(ega->ma << 1) & ega->vrammask]; - attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + for (x = 0; x < (ega->hdisp + ega->scrollcache); x += xinc) { + addr = ega->remap_func(ega, ega->ma) & ega->vrammask; - if (attr & 8) charaddr = ega->charsetb + (chr * 128); - else charaddr = ega->charseta + (chr * 128); + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); - if (drawcursor) { - bg = ega->pallook[ega->egapal[attr & 15]]; - fg = ega->pallook[ega->egapal[attr >> 4]]; - } else { - fg = ega->pallook[ega->egapal[attr & 15]]; - bg = ega->pallook[ega->egapal[attr >> 4]]; - if (attr & 0x80 && ega->attrregs[0x10] & 8) { - bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; - if (ega->blink & 16) - fg = bg; - } - } + if (ega->crtc[0x17] & 0x80) { + chr = ega->vram[addr]; + attr = ega->vram[addr + 1]; + } else + chr = attr = 0; - dat = ega->vram[charaddr + (ega->sc << 2)]; - if (ega->seqregs[1] & 1) { - for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - } else { - for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1F) != 0xC0 || !(ega->attrregs[0x10] & 4)) - p[8] = bg; - else - p[8] = (dat & 1) ? fg : bg; - } - ega->ma += 4; - p += xinc; - } - ega->ma &= ega->vrammask; + if (attr & 0x08) + charaddr = ega->charsetb + (chr * 0x80); + else + charaddr = ega->charseta + (chr * 0x80); + + if (drawcursor) { + bg = ega->pallook[ega->egapal[attr & 0x0f]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; + } else { + fg = ega->pallook[ega->egapal[attr & 0x0f]]; + bg = ega->pallook[ega->egapal[attr >> 4]]; + if ((attr & 0x80) && ega->attrregs[0x10] & 8) { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; + } + } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 1) { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + } else { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(ega->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + ega->ma += 4; + p += xinc; + } + ega->ma &= ega->vrammask; } } @@ -242,48 +261,34 @@ ega_render_2bpp_lowres(ega_t *ega) p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; if (ega->firstline_draw == 2000) - ega->firstline_draw = ega->displine; + ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 16) { - addr = ega->ma; + addr = ega->remap_func(ega, ega->ma); - if (!(ega->crtc[0x17] & 0x40)) { - addr = (addr << 1) & ega->vrammask; - addr &= ~7; + dat[0] = ega->vram[addr]; + dat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; - if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) - addr |= 4; + ega->ma &= ega->vrammask; - if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) - addr |= 4; - } + if (ega->crtc[0x17] & 0x80) { + p[0] = p[1] = ega->pallook[ega->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = ega->pallook[ega->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = ega->pallook[ega->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = ega->pallook[ega->egapal[dat[0] & 3]]; + p[8] = p[9] = ega->pallook[ega->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = ega->pallook[ega->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = ega->pallook[ega->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = ega->pallook[ega->egapal[dat[1] & 3]]; + } else + memset(p, 0x00, 16 * sizeof(uint32_t)); - if (!(ega->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); - - if (!(ega->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); - - dat[0] = ega->vram[addr]; - dat[1] = ega->vram[addr | 0x1]; - if (ega->seqregs[1] & 4) - ega->ma += 2; - else - ega->ma += 4; - - ega->ma &= ega->vrammask; - - p[0] = p[1] = ega->pallook[ega->egapal[(dat[0] >> 6) & 3]]; - p[2] = p[3] = ega->pallook[ega->egapal[(dat[0] >> 4) & 3]]; - p[4] = p[5] = ega->pallook[ega->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = ega->pallook[ega->egapal[dat[0] & 3]]; - p[8] = p[9] = ega->pallook[ega->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = ega->pallook[ega->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = ega->pallook[ega->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = ega->pallook[ega->egapal[dat[1] & 3]]; - - p += 16; + p += 16; } } @@ -301,48 +306,34 @@ ega_render_2bpp_highres(ega_t *ega) p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; if (ega->firstline_draw == 2000) - ega->firstline_draw = ega->displine; + ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 8) { - addr = ega->ma; + addr = ega->remap_func(ega, ega->ma); - if (!(ega->crtc[0x17] & 0x40)) { - addr = (addr << 1) & ega->vrammask; - addr &= ~7; + dat[0] = ega->vram[addr]; + dat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; - if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) - addr |= 4; + ega->ma &= ega->vrammask; - if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) - addr |= 4; - } + if (ega->crtc[0x17] & 0x80) { + p[0] = ega->pallook[ega->egapal[(dat[0] >> 6) & 3]]; + p[1] = ega->pallook[ega->egapal[(dat[0] >> 4) & 3]]; + p[2] = ega->pallook[ega->egapal[(dat[0] >> 2) & 3]]; + p[3] = ega->pallook[ega->egapal[dat[0] & 3]]; + p[4] = ega->pallook[ega->egapal[(dat[1] >> 6) & 3]]; + p[5] = ega->pallook[ega->egapal[(dat[1] >> 4) & 3]]; + p[6] = ega->pallook[ega->egapal[(dat[1] >> 2) & 3]]; + p[7] = ega->pallook[ega->egapal[dat[1] & 3]]; + } else + memset(p, 0x00, 8 * sizeof(uint32_t)); - if (!(ega->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); - - if (!(ega->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); - - dat[0] = ega->vram[addr]; - dat[1] = ega->vram[addr | 0x1]; - if (ega->seqregs[1] & 4) - ega->ma += 2; - else - ega->ma += 4; - - ega->ma &= ega->vrammask; - - p[0] = ega->pallook[ega->egapal[(dat[0] >> 6) & 3]]; - p[1] = ega->pallook[ega->egapal[(dat[0] >> 4) & 3]]; - p[2] = ega->pallook[ega->egapal[(dat[0] >> 2) & 3]]; - p[3] = ega->pallook[ega->egapal[dat[0] & 3]]; - p[4] = ega->pallook[ega->egapal[(dat[1] >> 6) & 3]]; - p[5] = ega->pallook[ega->egapal[(dat[1] >> 4) & 3]]; - p[6] = ega->pallook[ega->egapal[(dat[1] >> 2) & 3]]; - p[7] = ega->pallook[ega->egapal[dat[1] & 3]]; - - p += 8; + p += 8; } } @@ -360,62 +351,42 @@ ega_render_4bpp_lowres(ega_t *ega) p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; if (ega->firstline_draw == 2000) - ega->firstline_draw = ega->displine; + ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 16) { - addr = ega->ma; - oddeven = 0; + addr = ega->remap_func(ega, ega->ma); + oddeven = 0; - if (!(ega->crtc[0x17] & 0x40)) { - addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) { + oddeven = (addr & 4) ? 1 : 0; + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&ega->vram[addr]); + ega->ma += 4; + } + ega->ma &= ega->vrammask; - if (ega->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; + if (ega->crtc[0x17] & 0x80) { + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[2] = p[3] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[6] = p[7] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[10] = p[11] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[14] = p[15] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + } else + memset(p, 0x00, 16 * sizeof(uint32_t)); - addr &= ~7; - - if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) - addr |= 4; - if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) - addr |= 4; - } - - if (!(ega->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); - - if (!(ega->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); - - if (ega->seqregs[1] & 4) { - edat[0] = ega->vram[addr | oddeven]; - edat[2] = ega->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - ega->ma += 2; - } else { - edat[0] = ega->vram[addr]; - edat[1] = ega->vram[addr | 0x1]; - edat[2] = ega->vram[addr | 0x2]; - edat[3] = ega->vram[addr | 0x3]; - ega->ma += 4; - } - - ega->ma &= ega->vrammask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[2] = p[3] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[6] = p[7] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[10] = p[11] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[14] = p[15] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - - p += 16; + p += 16; } } @@ -433,56 +404,41 @@ ega_render_4bpp_highres(ega_t *ega) p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; if (ega->firstline_draw == 2000) - ega->firstline_draw = ega->displine; + ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 8) { - addr = ega->ma; - oddeven = 0; + addr = ega->remap_func(ega, ega->ma); + oddeven = 0; - if (!(ega->crtc[0x17] & 0x40)) { - addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) { + oddeven = (addr & 4) ? 1 : 0; + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&ega->vram[addr]); + ega->ma += 4; + } + ega->ma &= ega->vrammask; - if (ega->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; + if (ega->crtc[0x17] & 0x80) { + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[1] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[3] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[5] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[7] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + } else + memset(p, 0x00, 8 * sizeof(uint32_t)); - addr &= ~7; - - if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) - addr |= 4; - if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) - addr |= 4; - } - - if (!(ega->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); - if (!(ega->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); - - if (ega->seqregs[1] & 4) { - edat[0] = ega->vram[addr | oddeven]; - edat[2] = ega->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - ega->ma += 2; - } else { - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&ega->vram[addr]); - ega->ma += 4; - } - ega->ma &= ega->vrammask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[1] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[3] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[5] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; - p[7] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; - - p += 8; + p += 8; } } diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index a86632094..c18a422a3 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -54,11 +54,11 @@ #include <86box/vid_svga_render.h> -#define BIOS_ROM_PATH L"roms/video/et4000/et4000.bin" -#define KOREAN_BIOS_ROM_PATH L"roms/video/et4000/tgkorvga.bin" -#define KOREAN_FONT_ROM_PATH L"roms/video/et4000/tg_ksc5601.rom" -#define KASAN_BIOS_ROM_PATH L"roms/video/et4000/et4000_kasan16.bin" -#define KASAN_FONT_ROM_PATH L"roms/video/et4000/kasan_ksc5601.rom" +#define BIOS_ROM_PATH "roms/video/et4000/ET4000.BIN" +#define KOREAN_BIOS_ROM_PATH "roms/video/et4000/tgkorvga.bin" +#define KOREAN_FONT_ROM_PATH "roms/video/et4000/tg_ksc5601.rom" +#define KASAN_BIOS_ROM_PATH "roms/video/et4000/et4000_kasan16.bin" +#define KASAN_FONT_ROM_PATH "roms/video/et4000/kasan_ksc5601.rom" typedef struct { const char *name; @@ -79,7 +79,7 @@ typedef struct { int get_korean_font_enabled; int get_korean_font_index; uint16_t get_korean_font_base; - + uint8_t kasan_cfg_index; uint8_t kasan_cfg_regs[16]; uint16_t kasan_access_addr; @@ -119,7 +119,7 @@ et4000_in(uint16_t addr, void *priv) if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) return 0; else - return 0x10; + return 0x10; } break; @@ -153,7 +153,7 @@ et4000k_in(uint16_t addr, void *priv) { et4000_t *dev = (et4000_t *)priv; uint8_t val = 0xff; - + switch (addr) { case 0x22cb: return dev->port_22cb_val; @@ -245,6 +245,15 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; } else svga->write_bank = svga->read_bank = 0; + + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) + { + /*override mask - ET4000 supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; } break; @@ -272,11 +281,17 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) } if (old != val) { - if (svga->crtcreg < 0x0e || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } break; } @@ -383,7 +398,7 @@ et4000_kasan_in(uint16_t addr, void *priv) } } else val = et4000_in(addr, priv); - + return val; } @@ -556,7 +571,7 @@ et4000_recalctimings(svga_t *svga) svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; } - + switch (svga->bpp) { case 15: case 16: @@ -629,7 +644,7 @@ et4000_mca_feedb(void *priv) static void * et4000_init(const device_t *info) { - const wchar_t *fn; + const char *fn; et4000_t *dev; int i; @@ -659,7 +674,7 @@ et4000_init(const device_t *info) io_sethandler(0x03c0, 32, et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); dev->pos_regs[0] = 0xf2; /* ET4000 MCA board ID */ - dev->pos_regs[1] = 0x80; + dev->pos_regs[1] = 0x80; mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, NULL, dev); break; @@ -714,25 +729,27 @@ et4000_init(const device_t *info) NULL, NULL); io_sethandler(0x03c0, 32, et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); - io_sethandler(0x0250, 8, + io_sethandler(0x0250, 8, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, dev); - io_sethandler(0x0258, 2, + io_sethandler(0x0258, 2, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, dev); loadfont(KASAN_FONT_ROM_PATH, 6); fn = KASAN_BIOS_ROM_PATH; break; - + } dev->svga.ramdac = device_add(&sc1502x_ramdac_device); dev->vram_mask = dev->vram_size - 1; - rom_init(&dev->bios_rom, (wchar_t *) fn, + rom_init(&dev->bios_rom, (char *) fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); dev->svga.translate_address = get_et4000_addr; + dev->svga.packed_chain4 = 1; + return(dev); } @@ -787,81 +804,103 @@ et4000_kasan_available(void) rom_present(KASAN_FONT_ROM_PATH); } -static const device_config_t et4000_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 1024, - { - { - "256 KB", 256 - }, - { - "512 KB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t et4000_config[] = { +// clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "256 KB", + .value = 256 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +// clang-format on }; const device_t et4000_isa_device = { - "Tseng Labs ET4000AX (ISA)", - DEVICE_ISA, - 0, - et4000_init, et4000_close, NULL, - et4000_available, - et4000_speed_changed, - et4000_force_redraw, - et4000_config + .name = "Tseng Labs ET4000AX (ISA)", + .internal_name = "et4000ax", + .flags = DEVICE_ISA, + .local = 0, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config }; const device_t et4000_mca_device = { - "Tseng Labs ET4000AX (MCA)", - DEVICE_MCA, - 1, - et4000_init, et4000_close, NULL, - et4000_available, - et4000_speed_changed, - et4000_force_redraw, - et4000_config + .name = "Tseng Labs ET4000AX (MCA)", + .internal_name = "et4000mca", + .flags = DEVICE_MCA, + .local = 1, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config }; const device_t et4000k_isa_device = { - "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", - DEVICE_ISA, - 2, - et4000_init, et4000_close, NULL, - et4000k_available, - et4000_speed_changed, - et4000_force_redraw, - et4000_config + .name = "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", + .internal_name = "tgkorvga", + .flags = DEVICE_ISA, + .local = 2, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000k_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config }; const device_t et4000k_tg286_isa_device = { - "Trigem Korean VGA (Trigem 286M)", - DEVICE_ISA, - 3, - et4000_init, et4000_close, NULL, - et4000k_available, - et4000_speed_changed, - et4000_force_redraw, - et4000_config + .name = "Trigem Korean VGA (Trigem 286M)", + .internal_name = "et4000k_tg286_isa", + .flags = DEVICE_ISA, + .local = 3, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000k_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config }; const device_t et4000_kasan_isa_device = { - "Kasan Hangulmadang-16 VGA (Tseng Labs ET4000AX Korean)", - DEVICE_ISA, - 4, - et4000_init, et4000_close, NULL, - et4000_kasan_available, - et4000_speed_changed, - et4000_force_redraw, - et4000_config + .name = "Kasan Hangulmadang-16 VGA (Tseng Labs ET4000AX Korean)", + .internal_name = "kasan16vga", + .flags = DEVICE_ISA, + .local = 4, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000_kasan_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config }; diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 1568eb008..5a897fcc1 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * ET4000/W32p emulation (Diamond Stealth 32) + * ET4000/W32 series emulation. * * Known bugs: Accelerator doesn't work in planar modes * @@ -38,119 +38,114 @@ #include <86box/vid_svga_render.h> -#define BIOS_ROM_PATH_DIAMOND L"roms/video/et4000w32/et4000w32.bin" -#define BIOS_ROM_PATH_CARDEX L"roms/video/et4000w32/cardex.vbi" +#define BIOS_ROM_PATH_DIAMOND "roms/video/et4000w32/et4000w32.bin" +#define BIOS_ROM_PATH_CARDEX "roms/video/et4000w32/cardex.vbi" +#define BIOS_ROM_PATH_W32 "roms/video/et4000w32/ET4000W32VLB_bios_MX27C512.BIN" +#define BIOS_ROM_PATH_W32I_ISA "roms/video/et4000w32/ET4KW32I.VBI" +#define BIOS_ROM_PATH_W32I_VLB "roms/video/et4000w32/tseng.u41.bin" +#define BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB "roms/video/et4000w32/VideoMagic-BioS-HXIRTW32PWSRL.BIN" +#define BIOS_ROM_PATH_W32P "roms/video/et4000w32/ET4K_W32.BIN" +#define BIOS_ROM_PATH_W32P_REVC "roms/video/et4000w32/et4000w32pcardex.BIN" -#define FIFO_SIZE 65536 -#define FIFO_MASK (FIFO_SIZE - 1) -#define FIFO_ENTRY_SIZE (1 << 31) +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 -#define FIFO_ENTRIES (et4000->fifo_write_idx - et4000->fifo_read_idx) -#define FIFO_FULL ((et4000->fifo_write_idx - et4000->fifo_read_idx) >= (FIFO_SIZE-1)) -#define FIFO_EMPTY (et4000->fifo_read_idx == et4000->fifo_write_idx) - -#define FIFO_TYPE 0xff000000 -#define FIFO_ADDR 0x00ffffff enum { - ET4000W32_CARDEX = 0, - ET4000W32_DIAMOND + ET4000W32, + ET4000W32I, + ET4000W32P_REVC, + ET4000W32P_VIDEOMAGIC_REVB, + ET4000W32P, + ET4000W32P_CARDEX, + ET4000W32P_DIAMOND }; -enum -{ - FIFO_INVALID = (0x00 << 24), - FIFO_WRITE_BYTE = (0x01 << 24), - FIFO_WRITE_MMU = (0x02 << 24) -}; - -typedef struct -{ - uint32_t addr_type; - uint32_t val; -} fifo_entry_t; typedef struct et4000w32p_t { - mem_mapping_t linear_mapping; - mem_mapping_t mmu_mapping; - - rom_t bios_rom; - - svga_t svga; + mem_mapping_t linear_mapping; + mem_mapping_t mmu_mapping; - int index; - int pci; - uint8_t regs[256]; - uint32_t linearbase, linearbase_old; - uint32_t vram_mask; + rom_t bios_rom; - uint8_t banking, banking2; + svga_t svga; - uint8_t pci_regs[256]; - - int interleaved; + uint8_t banking, banking2, adjust_cursor, rev; - /*Accelerator*/ - struct - { - struct - { - uint32_t pattern_addr,source_addr,dest_addr,mix_addr; - uint16_t pattern_off,source_off,dest_off,mix_off; - uint8_t pixel_depth,xy_dir; - uint8_t pattern_wrap,source_wrap; - uint16_t count_x,count_y; - uint8_t ctrl_routing,ctrl_reload; - uint8_t rop_fg,rop_bg; - uint16_t pos_x,pos_y; - uint16_t error; - uint16_t dmin,dmaj; - } queued,internal; - uint32_t pattern_addr,source_addr,dest_addr,mix_addr; - uint32_t pattern_back,source_back,dest_back,mix_back; - int pattern_x,source_x; - int pattern_x_back,source_x_back; - int pattern_y,source_y; - uint8_t status; - uint64_t cpu_dat; - int cpu_dat_pos; - int pix_pos; - } acl; + uint8_t regs[256], pci_regs[256]; - struct - { - uint32_t base[3]; - uint8_t ctrl; - } mmu; + int index, vlb, pci, interleaved, + bank, type; - fifo_entry_t fifo[FIFO_SIZE]; - volatile int fifo_read_idx, fifo_write_idx; + uint32_t linearbase; + uint32_t vram_mask; - thread_t *fifo_thread; - event_t *wake_fifo_thread; - event_t *fifo_not_full_event; - - int blitter_busy; - uint64_t blitter_time; - uint64_t status_time; - int type; - uint8_t hcr, mcr; - uint32_t key; + /* Accelerator */ + struct { + struct { + uint8_t vbus, pixel_depth, xy_dir, pattern_wrap, + source_wrap, ctrl_routing, ctrl_reload, rop_fg, + rop_bg; + + uint16_t pattern_off, source_off, dest_off, mix_off, + count_x,count_y, pos_x, pos_y, + error, dmin, dmaj; + + uint32_t pattern_addr, source_addr, dest_addr, mix_addr; + } queued, internal; + + uint8_t suspend_terminate, osr; + uint8_t status; + uint16_t x_count, y_count; + + int pattern_x, source_x, pattern_x_back, source_x_back, + pattern_y, source_y, cpu_dat_pos, pix_pos, + cpu_input_num, fifo_queue; + int pattern_x_diff, pattern_y_diff, pattern_x_diff2, pattern_y_diff2; + int patcnt, mmu_start; + + uint32_t pattern_addr, source_addr, dest_addr, mix_addr, + pattern_back, source_back, dest_back, mix_back, + cpu_input; + + uint64_t cpu_dat; + } acl; + + struct { + uint32_t base[3]; + uint8_t ctrl; + } mmu; + + volatile int busy; } et4000w32p_t; -static video_timings_t timing_et4000w32_vlb = {VIDEO_BUS, 4, 4, 4, 10, 10, 10}; -static video_timings_t timing_et4000w32_pci = {VIDEO_PCI, 4, 4, 4, 10, 10, 10}; -void et4000w32p_recalcmapping(et4000w32p_t *et4000); +static int et4000w32_vbus[4] = {1, 2, 4, 4}; -uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); -void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p); +static int et4000w32_max_x[8] = {0,0,4,8,0x10,0x20,0x40,0x70000000}; +static int et4000w32_wrap_x[8] = {0,0,3,7,0x0F,0x1F,0x3F,~0}; +static int et4000w32_wrap_y[8] = {1,2,4,8,~0,~0,~0,~0}; -void et4000w32_blit_start(et4000w32p_t *et4000); -void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); +static video_timings_t timing_et4000w32_vlb = {VIDEO_BUS, 4, 4, 4, 10, 10, 10}; +static video_timings_t timing_et4000w32_pci = {VIDEO_PCI, 4, 4, 4, 10, 10, 10}; +static video_timings_t timing_et4000w32_isa = {VIDEO_ISA, 4, 4, 4, 10, 10, 10}; + + +void et4000w32p_recalcmapping(et4000w32p_t *et4000); + +static uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); +static void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p); + +static void et4000w32_blit_start(et4000w32p_t *et4000); +static void et4000w32p_blit_start(et4000w32p_t *et4000); +static void et4000w32_blit(int count, int cpu_input, uint32_t src_dat, uint32_t mix_dat, et4000w32p_t *et4000); +static void et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); +uint8_t et4000w32p_in(uint16_t addr, void *p); #ifdef ENABLE_ET4000W32_LOG @@ -173,1286 +168,2233 @@ et4000w32_log(const char *fmt, ...) #endif -uint8_t et4000w32p_in(uint16_t addr, void *p); - -void et4000w32p_out(uint16_t addr, uint8_t val, void *p) +void +et4000w32p_out(uint16_t addr, uint8_t val, void *p) { - et4000w32p_t *et4000 = (et4000w32p_t *)p; - svga_t *svga = &et4000->svga; - uint8_t old; + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t old; + uint32_t add2addr = 0; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c2: - if (et4000->type == ET4000W32_DIAMOND) - icd2061_write(svga->clock_gen, (val >> 2) & 3); - break; - - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - stg_ramdac_out(addr, val, svga->ramdac, svga); - return; - - case 0x3CB: /*Banking extension*/ - if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { - svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); - svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); - } - et4000->banking2 = val; - return; - case 0x3CD: /*Banking*/ - if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { - svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); - svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); - } - et4000->banking = val; - return; - case 0x3CF: - switch (svga->gdcaddr & 15) - { - case 6: - if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { - svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); - svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); - } else - svga->write_bank = svga->read_bank = 0; + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; - svga->gdcreg[svga->gdcaddr & 15] = val; - et4000w32p_recalcmapping(et4000); - return; - } - break; - case 0x3D4: - svga->crtcreg = val & 63; - return; - case 0x3D5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; + switch (addr) { + case 0x3c2: + if (et4000->type == ET4000W32P_DIAMOND) + icd2061_write(svga->clock_gen, (val >> 2) & 3); + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (et4000->type <= ET4000W32P_REVC) + sdac_ramdac_out(addr, 0, val, svga->ramdac, svga); + else + stg_ramdac_out(addr, val, svga->ramdac, svga); + return; + + case 0x3cb: /* Banking extension */ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + } + et4000->banking2 = val; + return; + case 0x3cd: /* Banking */ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + } + et4000->banking = val; + return; + case 0x3cf: + switch (svga->gdcaddr & 15) { + case 6: + if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { + svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); + svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); + } else + svga->write_bank = svga->read_bank = 0; + + svga->gdcreg[svga->gdcaddr & 15] = val; + et4000w32p_recalcmapping(et4000); + return; + } + break; + case 0x3d4: + svga->crtcreg = val & 0x3f; + return; + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; if (svga->crtcreg == 0x36) { if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) { - svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); - svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); + svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); + svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); } else svga->write_bank = svga->read_bank = 0; } - if (old != val) - { + if (old != val) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } - } - if (svga->crtcreg == 0x30) - { - if (et4000->pci) - { - et4000->linearbase &= 0xc0000000; - et4000->linearbase |= (val & 0xfc) << 22; - } + } + if (svga->crtcreg == 0x30) { + if (et4000->pci && (et4000->rev != 5)) + et4000->linearbase = (et4000->linearbase & 0xc0000000) | ((val & 0xfc) << 22); else - { et4000->linearbase = val << 22; + et4000w32p_recalcmapping(et4000); + } + if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) + et4000w32p_recalcmapping(et4000); + break; + + case 0x210a: case 0x211a: case 0x212a: case 0x213a: + case 0x214a: case 0x215a: case 0x216a: case 0x217a: + et4000->index = val; + return; + case 0x210b: case 0x211b: case 0x212b: case 0x213b: + case 0x214b: case 0x215b: case 0x216b: case 0x217b: + et4000->regs[et4000->index] = val; + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((et4000->regs[0xEF] & 4) || (et4000->type == ET4000W32)) ? 128 : 64; + svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); + svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); + svga->hwcursor.ena = !!(et4000->regs[0xF7] & 0x80); + svga->hwcursor.xoff = et4000->regs[0xE2]; + svga->hwcursor.yoff = et4000->regs[0xE6]; + + if (et4000->type == ET4000W32) { + switch (svga->bpp) { + case 8: + svga->hwcursor.xoff += 32; + break; } - et4000w32p_recalcmapping(et4000); - } - if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) - et4000w32p_recalcmapping(et4000); - break; + } - case 0x210A: case 0x211A: case 0x212A: case 0x213A: - case 0x214A: case 0x215A: case 0x216A: case 0x217A: - et4000->index=val; - return; - case 0x210B: case 0x211B: case 0x212B: case 0x213B: - case 0x214B: case 0x215B: case 0x216B: case 0x217B: - et4000->regs[et4000->index] = val; - svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); - svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); - svga->hwcursor.addr = (et4000->regs[0xE8] | (et4000->regs[0xE9] << 8) | ((et4000->regs[0xEA] & 7) << 16)) << 2; - svga->hwcursor.addr += (et4000->regs[0xE6] & 63) * 16; - svga->hwcursor.ena = et4000->regs[0xF7] & 0x80; - svga->hwcursor.xoff = et4000->regs[0xE2] & 63; - svga->hwcursor.yoff = et4000->regs[0xE6] & 63; - return; + if (svga->hwcursor.cur_xsize == 128) { + svga->hwcursor.xoff &= 0x7f; + svga->hwcursor.yoff &= 0x7f; + if (et4000->type > ET4000W32P_REVC) { + if (svga->bpp == 24) { + et4000->adjust_cursor = 2; + } + } + } else { + if (et4000->type > ET4000W32P_REVC) { + if (svga->bpp == 24 && et4000->adjust_cursor) { + et4000->adjust_cursor = 0; + } + } + svga->hwcursor.xoff &= 0x3f; + svga->hwcursor.yoff &= 0x3f; + } + svga->hwcursor.addr = (et4000->regs[0xe8] | (et4000->regs[0xe9] << 8) | ((et4000->regs[0xea] & 7) << 16)) << 2; - } - svga_out(addr, val, svga); + add2addr = svga->hwcursor.yoff * ((svga->hwcursor.cur_xsize == 128) ? 32 : 16); + svga->hwcursor.addr += add2addr; + return; + } + + svga_out(addr, val, svga); } -uint8_t et4000w32p_in(uint16_t addr, void *p) + +uint8_t +et4000w32p_in(uint16_t addr, void *p) { - et4000w32p_t *et4000 = (et4000w32p_t *)p; - svga_t *svga = &et4000->svga; + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c5: - if ((svga->seqaddr & 0xf) == 7) - return svga->seqregs[svga->seqaddr & 0xf] | 4; - break; + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return stg_ramdac_in(addr, svga->ramdac, svga); + switch (addr) { + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; - case 0x3CB: - return et4000->banking2; - case 0x3CD: - return et4000->banking; - case 0x3D4: - return svga->crtcreg; - case 0x3D5: - return svga->crtc[svga->crtcreg]; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (et4000->type <= ET4000W32P_REVC) + return sdac_ramdac_in(addr, 0, svga->ramdac, svga); + else + return stg_ramdac_in(addr, svga->ramdac, svga); + break; - case 0x210A: case 0x211A: case 0x212A: case 0x213A: - case 0x214A: case 0x215A: case 0x216A: case 0x217A: - return et4000->index; - case 0x210B: case 0x211B: case 0x212B: case 0x213B: - case 0x214B: case 0x215B: case 0x216B: case 0x217B: - if (et4000->index==0xec) - return (et4000->regs[0xec] & 0xf) | 0x60; /*ET4000/W32p rev D*/ - if (et4000->index == 0xee) /*Preliminary implementation*/ - { - if (svga->bpp == 8) - return 3; - else if (svga->bpp == 16) - return 4; - else + case 0x3cb: + return et4000->banking2; + case 0x3cd: + return et4000->banking; + case 0x3d4: + return svga->crtcreg; + case 0x3d5: + if (et4000->type == ET4000W32) { + if (svga->crtcreg == 0x37) + return 0x09; + } + return svga->crtc[svga->crtcreg]; + + case 0x3da: + svga->attrff = 0; + + /*Bit 1 of the Input Status Register is required by the OS/2 and NT ET4000W32/I drivers to be set otherwise + the guest will loop infinitely upon reaching the GUI*/ + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x32; + else + svga->cgastat ^= 0x32; + return svga->cgastat; + + case 0x210a: case 0x211a: case 0x212a: case 0x213a: + case 0x214a: case 0x215a: case 0x216a: case 0x217a: + return et4000->index; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000->index == 0xec) { + return (et4000->regs[0xec] & 0xf) | (et4000->rev << 4); + } + if (et4000->index == 0xee) { + if (svga->bpp == 8) { + if ((svga->gdcreg[5] & 0x60) >= 0x40) + return 3; + else if ((svga->gdcreg[5] & 0x60) == 0x20) + return 1; + else + return 2; + } else if (svga->bpp == 15 || svga->bpp == 16) + return 4; + else + break; + } + if (et4000->index == 0xef) { + if (et4000->pci) + return (et4000->regs[0xef] & 0x0f) | (et4000->rev << 4) | et4000->pci; + else + return (et4000->regs[0xef] & 0x8f) | (et4000->rev << 4) | et4000->vlb; + } + return et4000->regs[et4000->index]; + } + + return svga_in(addr, svga); +} + + +void +et4000w32p_recalctimings(svga_t *svga) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + + svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; + if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x35] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (svga->crtc[0x3F] & 0x80) svga->rowoffset += 0x100; + if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + + if (et4000->type != ET4000W32P_DIAMOND) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (svga->gdcreg[5] & 0x40) { + switch (svga->bpp) { + case 8: + svga->clock /= 2; + break; + case 15: case 16: + svga->clock /= 3; + break; + case 24: + svga->clock /= 4; break; } - if (et4000->index == 0xef) - { - if (et4000->pci) return et4000->regs[0xef] | 0xe0; /*PCI*/ - else return et4000->regs[0xef] | 0x60; /*VESA local bus*/ - } - return et4000->regs[et4000->index]; - } - return svga_in(addr, svga); + } + } + } + + if (svga->adv_flags & FLAG_NOSKEW) { + /* On the Cardex ET4000/W32p-based cards, adjust text mode clocks by 1. */ + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */ + svga->ma_latch--; + + if ((svga->seqregs[1] & 8)) /*40 column*/ + svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; + else + svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; + } else { + /* Also adjust the graphics mode clocks in some cases. */ + if ((svga->gdcreg[5] & 0x40) && (svga->bpp != 32)) { + if ((svga->bpp == 15) || (svga->bpp == 16) || (svga->bpp == 24)) + svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; + else + svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; + } else if ((svga->gdcreg[5] & 0x40) == 0) { + svga->hdisp += (svga->seqregs[1] & 1) ? 8 : 9; + if (svga->hdisp == 648 || svga->hdisp == 808 || svga->hdisp == 1032) + svga->hdisp -= 8; + } + } + } + + if (et4000->type == ET4000W32) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (svga->gdcreg[5] & 0x40) { + switch (svga->bpp) { + case 8: + if (svga->hdisp == 640 || svga->hdisp == 800 || svga->hdisp == 1024) + break; + svga->hdisp -= 24; + break; + } + } + } + } + + et4000->adjust_cursor = 0; + + switch (svga->bpp) { + case 15: case 16: + svga->hdisp >>= 1; + if (et4000->type <= ET4000W32P_REVC) { + if (et4000->type == ET4000W32P_REVC) { + if (svga->hdisp != 1024) + et4000->adjust_cursor = 1; + } else + et4000->adjust_cursor = 1; + } + break; + case 24: + svga->hdisp /= 3; + if (et4000->type <= ET4000W32P_REVC) + et4000->adjust_cursor = 2; + if (et4000->type == ET4000W32P_DIAMOND && (svga->hdisp == 640/2 || svga->hdisp == 1232)) { + svga->hdisp = 640; + } + break; + } + + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */ + if (svga->seqregs[1] & 8) /* 40 column */ + svga->render = svga_render_text_40; + else + svga->render = svga_render_text_80; + } else { + if (svga->adv_flags & FLAG_NOSKEW) { + svga->ma_latch--; + } + + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (et4000->rev == 5) + svga->ma_latch++; + + if (svga->seqregs[1] & 8) /* Low res (320) */ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /* 4 colours */ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /* 256+ colours */ + if (et4000->type <= ET4000W32P_REVC) + svga->clock /= 2; + + switch (svga->bpp) { + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 17: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_mix_highres; + break; + case 24: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } } -void et4000w32p_recalctimings(svga_t *svga) + +void +et4000w32p_recalcmapping(et4000w32p_t *et4000) { - svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; - if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; - if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; - if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; - if (svga->crtc[0x35] & 0x08) svga->vsyncstart += 0x400; - if (svga->crtc[0x35] & 0x10) svga->split += 0x400; - if (svga->crtc[0x3F] & 0x80) svga->rowoffset += 0x100; - if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; - if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; - - svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga_t *svga = &et4000->svga; + int map; - switch (svga->bpp) - { - case 15: case 16: - svga->hdisp >>= 1; - break; - case 24: - svga->hdisp /= 3; - break; - } + if (et4000->pci && !(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->linear_mapping); + mem_mapping_disable(&et4000->mmu_mapping); + return; + } - svga->render = svga_render_blank; - if (!svga->scrblank && svga->attr_palette_enable) { - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) /*40 column*/ - svga->render = svga_render_text_40; - else - svga->render = svga_render_text_80; + if (svga->crtc[0x36] & 0x10) { /* Linear frame buffer */ + mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->mmu_mapping); + } else { + map = (svga->gdcreg[6] & 0xc) >> 2; + if (svga->crtc[0x36] & 0x20) map |= 4; + if (svga->crtc[0x36] & 0x08) map |= 8; + mem_mapping_disable(&et4000->linear_mapping); + switch (map) { + case 0x0: case 0x4: case 0x8: case 0xc: /* 128k at A0000 */ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x1ffff; + break; + case 0x1: /* 64k at A0000 */ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x2: /* 32k at B0000 */ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x3: /* 32k at B8000 */ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x5: case 0x9: case 0xd: /* 64k at A0000, MMU at B8000 */ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xb8000, 0x08000); + svga->banked_mask = 0xffff; + break; + case 0x6: case 0xa: case 0xe: /* 32k at B0000, MMU at A8000 */ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x7: case 0xb: case 0xf: /* 32k at B8000, MMU at A8000 */ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + + if (!et4000->interleaved && (svga->crtc[0x32] & 0x80)) + mem_mapping_disable(&svga->mapping); +} + + +static void +et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + et4000->acl.fifo_queue++; + switch (addr & 0xff) { + case 0x80: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x3fff00) | val; + break; + case 0x81: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x3f00ff) | (val << 8); + break; + case 0x82: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00ffff) | ((val & 0x3f) << 16); + break; + case 0x84: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x3fff00) | val; + break; + case 0x85: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x3f00ff) | (val << 8); + break; + case 0x86: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00ffff) | ((val & 0x3f) << 16); + break; + case 0x88: + et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x0f00) | val; + break; + case 0x89: + et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00ff) | ((val & 0x0f) << 8); + break; + case 0x8a: + et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x0f00) | val; + break; + case 0x8b: + et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00ff) | ((val & 0x0f) << 8); + break; + case 0x8c: + et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x0f00) | val; + break; + case 0x8d: + et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00ff) | ((val & 0x0f) << 8); + break; + case 0x8e: + if (et4000->type >= ET4000W32P_REVC) + et4000->acl.queued.pixel_depth = val & 0x30; + else + et4000->acl.queued.vbus = val & 0x03; + break; + case 0x8f: + if (et4000->type >= ET4000W32P_REVC) + et4000->acl.queued.xy_dir = val & 0xb7; + else + et4000->acl.queued.xy_dir = val & 0x03; + break; + case 0x90: + et4000->acl.queued.pattern_wrap = val & 0x77; + break; + case 0x92: + et4000->acl.queued.source_wrap = val & 0x77; + break; + case 0x98: + et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x0f00) | val; + break; + case 0x99: + et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00ff) | ((val & 0x0f) << 8); + break; + case 0x9a: + et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x0f00) | val; + break; + case 0x9b: + et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00ff) | ((val & 0x0f) << 8); + break; + case 0x9c: + if (et4000->type >= ET4000W32P_REVC) + et4000->acl.queued.ctrl_routing = val & 0xdb; + else + et4000->acl.queued.ctrl_routing = val & 0xb7; + break; + case 0x9d: + et4000->acl.queued.ctrl_reload = val & 0x03; + break; + case 0x9e: + et4000->acl.queued.rop_bg = val; + break; + case 0x9f: + et4000->acl.queued.rop_fg = val; + break; + case 0xa0: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x3fff00) | val; + break; + case 0xa1: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x3f00ff) | (val << 8); + break; + case 0xa2: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00ffff) | ((val & 0x3f) << 16); + break; + case 0xa3: + et4000->acl.internal = et4000->acl.queued; + if (et4000->type >= ET4000W32P_REVC) { + et4000w32p_blit_start(et4000); + et4000w32_log("Destination Address write and start XY Block, xcnt = %i, ycnt = %i\n", et4000->acl.x_count + 1, et4000->acl.y_count + 1); + if (!(et4000->acl.queued.ctrl_routing & 0x43)) { + et4000w32p_blit(0xffffff, ~0, 0, 0, et4000); + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) { + et4000w32p_blit(4, ~0, 0, 0, et4000); + } } else { - switch (svga->gdcreg[5] & 0x60) { - case 0x00: - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_4bpp_lowres; - else - svga->render = svga_render_4bpp_highres; + et4000w32_blit_start(et4000); + et4000->acl.cpu_input_num = 0; + if (!(et4000->acl.queued.ctrl_routing & 0x37)) { + et4000->acl.mmu_start = 0; + et4000w32_blit(-1, 0, 0, 0xffffffff, et4000); + } + } + break; + case 0xa4: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; + break; + case 0xa5: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); + break; + case 0xa6: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); + break; + case 0xa7: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); + break; + case 0xa8: + et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; + break; + case 0xa9: + et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); + break; + case 0xaa: + et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; + break; + case 0xab: + et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); + break; + case 0xac: + et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; + break; + case 0xad: + et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); + break; + case 0xae: + et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; + break; + case 0xaf: + et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); + break; + } +} + +static void +et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val, uint8_t bank) +{ + if (et4000->type >= ET4000W32P_REVC) { + if (!(et4000->acl.status & ACL_XYST)) { + et4000w32_log("XY MMU block not started\n"); + return; + } + if (et4000->acl.internal.ctrl_routing & 3) { + et4000->acl.fifo_queue++; + if ((et4000->acl.internal.ctrl_routing & 3) == 2) /*CPU data is Mix data*/ + et4000w32p_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); + else if ((et4000->acl.internal.ctrl_routing & 3) == 1) /*CPU data is Source data*/ + et4000w32p_blit(1, ~0, val, 2, et4000); + } + } else { + if (!(et4000->acl.status & ACL_XYST)) { + et4000->acl.fifo_queue++; + et4000->acl.queued.dest_addr = ((addr & 0x1fff) + et4000->mmu.base[bank]); + et4000->acl.internal = et4000->acl.queued; + et4000w32_blit_start(et4000); + et4000w32_log("ET4000W32 Accelerated MMU aperture start XY Block (Implicit): bank = %i, patx = %i, paty = %i, wrap y = %i\n", et4000->bank, et4000->acl.pattern_x, et4000->acl.pattern_y, et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]); + et4000->acl.cpu_input_num = 0; + if (!(et4000->acl.queued.ctrl_routing & 0x37)) { + et4000->acl.mmu_start = 1; + et4000w32_blit(-1, 0, 0, 0xffffffff, et4000); + } + } + + if (et4000->acl.internal.ctrl_routing & 7) { + et4000->acl.fifo_queue++; + et4000->acl.cpu_input = (et4000->acl.cpu_input & ~(0xff << (et4000->acl.cpu_input_num << 3))) | + (val << (et4000->acl.cpu_input_num << 3)); + et4000->acl.cpu_input_num++; + + if (et4000->acl.cpu_input_num == et4000w32_vbus[et4000->acl.internal.vbus]) { + if ((et4000->acl.internal.ctrl_routing & 7) == 2) /*CPU data is Mix data*/ + et4000w32_blit(et4000->acl.cpu_input_num << 3, 2, 0, et4000->acl.cpu_input, et4000); + else if ((et4000->acl.internal.ctrl_routing & 7) == 1) /*CPU data is Source data*/ + et4000w32_blit(et4000->acl.cpu_input_num, 1, et4000->acl.cpu_input, 0xffffffff, et4000); + + et4000->acl.cpu_input_num = 0; + } + + if ((et4000->acl.internal.ctrl_routing & 7) == 4) /*CPU data is X Count*/ + et4000w32_blit(val | (et4000->acl.queued.count_x << 8), 0, 0, 0xffffffff, et4000); + if ((et4000->acl.internal.ctrl_routing & 7) == 5) /*CPU data is Y Count*/ + et4000w32_blit(val | (et4000->acl.queued.count_y << 8), 0, 0, 0xffffffff, et4000); + } + } +} + +static void +et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + + switch (addr & 0x6000) { + case 0x0000: /* MMU 0 */ + case 0x2000: /* MMU 1 */ + case 0x4000: /* MMU 2 */ + et4000->bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << et4000->bank)) { + et4000w32p_accel_write_mmu(et4000, addr & 0x7fff, val, et4000->bank); + } else { + if (((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) < svga->vram_max) { + svga->vram[((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) & et4000->vram_mask] = val; + svga->changedvram[(((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) & et4000->vram_mask) >> 12] = changeframecount; + } + } + break; + case 0x6000: + if ((addr & 0xff) >= 0x80) { + et4000w32p_accel_write_fifo(et4000, addr & 0x7fff, val); + } else { + switch (addr & 0xff) { + case 0x00: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x3fff00) | val; break; - case 0x20: /*4 colours*/ - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_2bpp_lowres; - else - svga->render = svga_render_2bpp_highres; + case 0x01: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x3f00ff) | (val << 8); break; - case 0x40: case 0x60: /*256+ colours*/ - switch (svga->bpp) { - case 8: - svga->map8 = svga->pallook; - if (svga->lowres) - svga->render = svga_render_8bpp_lowres; - else - svga->render = svga_render_8bpp_highres; - break; - case 15: - if (svga->lowres || (svga->seqregs[1] & 8)) - svga->render = svga_render_15bpp_lowres; - else - svga->render = svga_render_15bpp_highres; - break; - case 16: - if (svga->lowres || (svga->seqregs[1] & 8)) - svga->render = svga_render_16bpp_lowres; - else - svga->render = svga_render_16bpp_highres; - break; - case 24: - if (svga->lowres || (svga->seqregs[1] & 8)) - svga->render = svga_render_24bpp_lowres; - else - svga->render = svga_render_24bpp_highres; - break; - case 32: - if (svga->lowres || (svga->seqregs[1] & 8)) - svga->render = svga_render_32bpp_lowres; - else - svga->render = svga_render_32bpp_highres; - break; - } + case 0x02: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00ffff) | ((val & 0x3f) << 16); + break; + case 0x04: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x3fff00) | val; + break; + case 0x05: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x3f00ff) | (val << 8); + break; + case 0x06: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00ffff) | ((val & 0x3f) << 16); + break; + case 0x08: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x3fff00) | val; + break; + case 0x09: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x3f00ff) | (val << 8); + break; + case 0x0a: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00ffff) | ((val & 0x3f) << 16); + break; + case 0x13: + et4000->mmu.ctrl = val; + break; + case 0x30: + et4000->acl.suspend_terminate = val; + break; + case 0x31: + et4000->acl.osr = val; break; } } + break; + } +} + +static uint8_t +et4000w32p_mmu_read(uint32_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t temp; + + switch (addr & 0x6000) { + case 0x0000: /* MMU 0 */ + case 0x2000: /* MMU 1 */ + case 0x4000: /* MMU 2 */ + et4000->bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << et4000->bank)) { + temp = 0xff; + if (et4000->acl.cpu_dat_pos) { + et4000->acl.cpu_dat_pos--; + temp = et4000->acl.cpu_dat & 0xff; + et4000->acl.cpu_dat >>= 8; + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32p_blit(4, ~0, 0, 0, et4000); + + /* ???? */ + return temp; + } + + if ((addr & 0x1fff) + et4000->mmu.base[et4000->bank] >= svga->vram_max) + return 0xff; + + return svga->vram[(addr & 0x1fff) + et4000->mmu.base[et4000->bank]]; + + case 0x6000: + switch (addr & 0xff) { + case 0x00: + return et4000->mmu.base[0] & 0xff; + case 0x01: + return et4000->mmu.base[0] >> 8; + case 0x02: + return et4000->mmu.base[0] >> 16; + case 0x03: + return et4000->mmu.base[0] >> 24; + case 0x04: + return et4000->mmu.base[1] & 0xff; + case 0x05: + return et4000->mmu.base[1] >> 8; + case 0x06: + return et4000->mmu.base[1] >> 16; + case 0x07: + return et4000->mmu.base[1] >> 24; + case 0x08: + return et4000->mmu.base[2] & 0xff; + case 0x09: + return et4000->mmu.base[2] >> 8; + case 0x0a: + return et4000->mmu.base[2] >> 16; + case 0x0b: + return et4000->mmu.base[2] >> 24; + case 0x13: + return et4000->mmu.ctrl; + + case 0x36: + if (et4000->acl.fifo_queue) { + et4000->acl.status |= ACL_RDST; + et4000->acl.fifo_queue = 0; + } else + et4000->acl.status &= ~ACL_RDST; + return et4000->acl.status; + + case 0x80: + return et4000->acl.internal.pattern_addr & 0xff; + case 0x81: + return et4000->acl.internal.pattern_addr >> 8; + case 0x82: + return et4000->acl.internal.pattern_addr >> 16; + case 0x83: + return et4000->acl.internal.pattern_addr >> 24; + case 0x84: + return et4000->acl.internal.source_addr & 0xff; + case 0x85: + return et4000->acl.internal.source_addr >> 8; + case 0x86: + return et4000->acl.internal.source_addr >> 16; + case 0x87: + return et4000->acl.internal.source_addr >> 24; + case 0x88: + return et4000->acl.internal.pattern_off & 0xff; + case 0x89: + return et4000->acl.internal.pattern_off >> 8; + case 0x8a: + return et4000->acl.internal.source_off & 0xff; + case 0x8b: + return et4000->acl.internal.source_off >> 8; + case 0x8c: + return et4000->acl.internal.dest_off & 0xff; + case 0x8d: + return et4000->acl.internal.dest_off >> 8; + case 0x8e: + if (et4000->type >= ET4000W32P_REVC) + return et4000->acl.internal.pixel_depth; + else + return et4000->acl.internal.vbus; + break; + case 0x8f: return et4000->acl.internal.xy_dir; + case 0x90: return et4000->acl.internal.pattern_wrap; + case 0x92: return et4000->acl.internal.source_wrap; + case 0x98: return et4000->acl.internal.count_x & 0xff; + case 0x99: return et4000->acl.internal.count_x >> 8; + case 0x9a: return et4000->acl.internal.count_y & 0xff; + case 0x9b: return et4000->acl.internal.count_y >> 8; + case 0x9c: return et4000->acl.internal.ctrl_routing; + case 0x9d: return et4000->acl.internal.ctrl_reload; + case 0x9e: return et4000->acl.internal.rop_bg; + case 0x9f: return et4000->acl.internal.rop_fg; + case 0xa0: return et4000->acl.internal.dest_addr & 0xff; + case 0xa1: return et4000->acl.internal.dest_addr >> 8; + case 0xa2: return et4000->acl.internal.dest_addr >> 16; + case 0xa3: return et4000->acl.internal.dest_addr >> 24; + } + + return 0xff; + } + + return 0xff; +} + + +void +et4000w32_blit_start(et4000w32p_t *et4000) +{ + et4000->acl.x_count = et4000->acl.internal.count_x; + et4000->acl.y_count = et4000->acl.internal.count_y; + + et4000->acl.pattern_addr = et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + + et4000->acl.status |= ACL_XYST; + et4000->acl.status &= ~ACL_SSO; + + if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + + if (!(et4000->acl.internal.pattern_wrap & 0x40)) { + if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) == 0x00) { /*This is to avoid a division by zero crash*/ + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + } else + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + + if (!(et4000->acl.internal.source_wrap & 0x40)) { + if ((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) == 0x00) { /*This is to avoid a division by zero crash*/ + et4000->acl.source_y = (et4000->acl.source_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + } else + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; +} + + +static void +et4000w32p_blit_start(et4000w32p_t *et4000) +{ + et4000->acl.x_count = et4000->acl.internal.count_x; + et4000->acl.y_count = et4000->acl.internal.count_y; + + if (!(et4000->acl.queued.xy_dir & 0x20)) + et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; + et4000->acl.pattern_addr = et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.mix_addr = et4000->acl.internal.mix_addr; + et4000->acl.mix_back = et4000->acl.mix_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + et4000->acl.status |= ACL_XYST; + + et4000w32_log("ACL status XYST set\n"); + if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + if (!(et4000->acl.internal.pattern_wrap & 0x40)) { + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + + if (!(et4000->acl.internal.source_wrap & 0x40)) { + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + et4000w32_max_x[2] = (et4000->acl.internal.pixel_depth == 0x20) ? 3 : 4; + + et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; + et4000->acl.cpu_dat_pos = 0; + et4000->acl.cpu_dat = 0; + + et4000->acl.pix_pos = 0; +} + + +void +et4000w32_incx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr += c; + et4000->acl.pattern_x += c; + et4000->acl.source_x += c; + et4000->acl.mix_addr += c; + if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) + et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) + et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} + + +void +et4000w32_decx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr -= c; + et4000->acl.pattern_x -= c; + et4000->acl.source_x -= c; + et4000->acl.mix_addr -= c; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x < 0) + et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} + + +void +et4000w32_incy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr += et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } +} + + +void +et4000w32_decy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y--; + if (et4000->acl.pattern_y < 0 && !(et4000->acl.internal.pattern_wrap & 0x40)) { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if (et4000->acl.source_y < 0 && !(et4000->acl.internal.source_wrap & 0x40)) { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] *(et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1)); + } +} + + +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: out = 0; break; \ + case 0x01: out = ~(D | (P | S)); break; \ + case 0x02: out = D & ~(P | S); break; \ + case 0x03: out = ~(P | S); break; \ + case 0x04: out = S & ~(D | P); break; \ + case 0x05: out = ~(D | P); break; \ + case 0x06: out = ~(P | ~(D ^ S)); break; \ + case 0x07: out = ~(P | (D & S)); break; \ + case 0x08: out = S & (D & ~P); break; \ + case 0x09: out = ~(P | (D ^ S)); break; \ + case 0x0a: out = D & ~P; break; \ + case 0x0b: out = ~(P | (S & ~D)); break; \ + case 0x0c: out = S & ~P; break; \ + case 0x0d: out = ~(P | (D & ~S)); break; \ + case 0x0e: out = ~(P | ~(D | S)); break; \ + case 0x0f: out = ~P; break; \ + case 0x10: out = P & ~(D | S); break; \ + case 0x11: out = ~(D | S); break; \ + case 0x12: out = ~(S | ~(D ^ P)); break; \ + case 0x13: out = ~(S | (D & P)); break; \ + case 0x14: out = ~(D | ~(P ^ S)); break; \ + case 0x15: out = ~(D | (P & S)); break; \ + case 0x16: out = P ^ (S ^ (D & ~(P & S))); break; \ + case 0x17: out = ~(S ^ ((S ^ P) & (D ^ S))); break; \ + case 0x18: out = (S ^ P) & (P ^ D); break; \ + case 0x19: out = ~(S ^ (D & ~(P & S))); break; \ + case 0x1a: out = P ^ (D | (S & P)); break; \ + case 0x1b: out = ~(S ^ (D & (P ^ S))); break; \ + case 0x1c: out = P ^ (S | (D & P)); break; \ + case 0x1d: out = ~(D ^ (S & (P ^ D))); break; \ + case 0x1e: out = P ^ (D | S); break; \ + case 0x1f: out = ~(P & (D | S)); break; \ + case 0x20: out = D & (P & ~S); break; \ + case 0x21: out = ~(S | (D ^ P)); break; \ + case 0x22: out = D & ~S; break; \ + case 0x23: out = ~(S | (P & ~D)); break; \ + case 0x24: out = (S ^ P) & (D ^ S); break; \ + case 0x25: out = ~(P ^ (D & ~(S & P))); break; \ + case 0x26: out = S ^ (D | (P & S)); break; \ + case 0x27: out = S ^ (D | ~(P ^ S)); break; \ + case 0x28: out = D & (P ^ S); break; \ + case 0x29: out = ~(P ^ (S ^ (D | (P & S)))); break; \ + case 0x2a: out = D & ~(P & S); break; \ + case 0x2b: out = ~(S ^ ((S ^ P) & (P ^ D))); break; \ + case 0x2c: out = S ^ (P & (D | S)); break; \ + case 0x2d: out = P ^ (S | ~D); break; \ + case 0x2e: out = P ^ (S | (D ^ P)); break; \ + case 0x2f: out = ~(P & (S | ~D)); break; \ + case 0x30: out = P & ~S; break; \ + case 0x31: out = ~(S | (D & ~P)); break; \ + case 0x32: out = S ^ (D | (P | S)); break; \ + case 0x33: out = ~S; break; \ + case 0x34: out = S ^ (P | (D & S)); break; \ + case 0x35: out = S ^ (P | ~(D ^ S)); break; \ + case 0x36: out = S ^ (D | P); break; \ + case 0x37: out = ~(S & (D | P)); break; \ + case 0x38: out = P ^ (S & (D | P)); break; \ + case 0x39: out = S ^ (P | ~D); break; \ + case 0x3a: out = S ^ (P | (D ^ S)); break; \ + case 0x3b: out = ~(S & (P | ~D)); break; \ + case 0x3c: out = P ^ S; break; \ + case 0x3d: out = S ^ (P | ~(D | S)); break; \ + case 0x3e: out = S ^ (P | (D & ~S)); break; \ + case 0x3f: out = ~(P & S); break; \ + case 0x40: out = P & (S & ~D); break; \ + case 0x41: out = ~(D | (P ^ S)); break; \ + case 0x42: out = (S ^ D) & (P ^ D); break; \ + case 0x43: out = ~(S ^ (P & ~(D & S))); break; \ + case 0x44: out = S & ~D; break; \ + case 0x45: out = ~(D | (P & ~S)); break; \ + case 0x46: out = D ^ (S | (P & D)); break; \ + case 0x47: out = ~(P ^ (S & (D ^ P))); break; \ + case 0x48: out = S & (D ^ P); break; \ + case 0x49: out = ~(P ^ (D ^ (S | (P & D)))); break; \ + case 0x4a: out = D ^ (P & (S | D)); break; \ + case 0x4b: out = P ^ (D | ~S); break; \ + case 0x4c: out = S & ~(D & P); break; \ + case 0x4d: out = ~(S ^ ((S ^ P) | (D ^ S))); break; \ + case 0x4e: out = P ^ (D | (S ^ P)); break; \ + case 0x4f: out = ~(P & (D | ~S)); break; \ + case 0x50: out = P & ~D; break; \ + case 0x51: out = ~(D | (S & ~P)); break; \ + case 0x52: out = D ^ (P | (S & D)); break; \ + case 0x53: out = ~(S ^ (P & (D ^ S))); break; \ + case 0x54: out = ~(D | ~(P | S)); break; \ + case 0x55: out = ~D; break; \ + case 0x56: out = D ^ (P | S); break; \ + case 0x57: out = ~(D & (P | S)); break; \ + case 0x58: out = P ^ (D & (S | P)); break; \ + case 0x59: out = D ^ (P | ~S); break; \ + case 0x5a: out = D ^ P; break; \ + case 0x5b: out = D ^ (P | ~(S | D)); break; \ + case 0x5c: out = D ^ (P | (S ^ D)); break; \ + case 0x5d: out = ~(D & (P | ~S)); break; \ + case 0x5e: out = D ^ (P | (S & ~D)); break; \ + case 0x5f: out = ~(D & P); break; \ + case 0x60: out = P & (D ^ S); break; \ + case 0x61: out = ~(D ^ (S ^ (P | (D & S)))); break; \ + case 0x62: out = D ^ (S & (P | D)); break; \ + case 0x63: out = S ^ (D | ~P); break; \ + case 0x64: out = S ^ (D & (P | S)); break; \ + case 0x65: out = D ^ (S | ~P); break; \ + case 0x66: out = D ^ S; break; \ + case 0x67: out = S ^ (D | ~(P | S)); break; \ + case 0x68: out = ~(D ^ (S ^ (P | ~(D | S)))); break; \ + case 0x69: out = ~(P ^ (D ^ S)); break; \ + case 0x6a: out = D ^ (P & S); break; \ + case 0x6b: out = ~(P ^ (S ^ (D & (P | S)))); break; \ + case 0x6c: out = S ^ (D & P); break; \ + case 0x6d: out = ~(P ^ (D ^ (S & (P | D)))); break; \ + case 0x6e: out = S ^ (D & (P | ~S)); break; \ + case 0x6f: out = ~(P & ~(D ^ S)); break; \ + case 0x70: out = P & ~(D & S); break; \ + case 0x71: out = ~(S ^ ((S ^ D) & (P ^ D))); break; \ + case 0x72: out = S ^ (D | (P ^ S)); break; \ + case 0x73: out = ~(S & (D | ~P)); break; \ + case 0x74: out = D ^ (S | (P ^ D)); break; \ + case 0x75: out = ~(D & (S | ~P)); break; \ + case 0x76: out = S ^ (D | (P & ~S)); break; \ + case 0x77: out = ~(D & S); break; \ + case 0x78: out = P ^ (D & S); break; \ + case 0x79: out = ~(D ^ (S ^ (P & (D | S)))); break; \ + case 0x7a: out = D ^ (P & (S | ~D)); break; \ + case 0x7b: out = ~(S & ~(D ^ P)); break; \ + case 0x7c: out = S ^ (P & (D | ~S)); break; \ + case 0x7d: out = ~(D & ~(P ^ S)); break; \ + case 0x7e: out = (S ^ P) | (D ^ S); break; \ + case 0x7f: out = ~(D & (P & S)); break; \ + case 0x80: out = D & (P & S); break; \ + case 0x81: out = ~((S ^ P) | (D ^ S)); break; \ + case 0x82: out = D & ~(P ^ S); break; \ + case 0x83: out = ~(S ^ (P & (D | ~S))); break; \ + case 0x84: out = S & ~(D ^ P); break; \ + case 0x85: out = ~(P ^ (D & (S | ~P))); break; \ + case 0x86: out = D ^ (S ^ (P & (D | S))); break; \ + case 0x87: out = ~(P ^ (D & S)); break; \ + case 0x88: out = D & S; break; \ + case 0x89: out = ~(S ^ (D | (P & ~S))); break; \ + case 0x8a: out = D & (S | ~P); break; \ + case 0x8b: out = ~(D ^ (S | (P ^ D))); break; \ + case 0x8c: out = S & (D | ~P); break; \ + case 0x8d: out = ~(S ^ (D | (P ^ S))); break; \ + case 0x8e: out = S ^ ((S ^ D) & (P ^ D)); break; \ + case 0x8f: out = ~(P & ~(D & S)); break; \ + case 0x90: out = P & ~(D ^ S); break; \ + case 0x91: out = ~(S ^ (D & (P | ~S))); break; \ + case 0x92: out = D ^ (P ^ (S & (D | P))); break; \ + case 0x93: out = ~(S ^ (P & D)); break; \ + case 0x94: out = P ^ (S ^ (D & (P | S))); break; \ + case 0x95: out = ~(D ^ (P & S)); break; \ + case 0x96: out = D ^ (P ^ S); break; \ + case 0x97: out = P ^ (S ^ (D | ~(P | S))); break; \ + case 0x98: out = ~(S ^ (D | ~(P | S))); break; \ + case 0x99: out = ~(D ^ S); break; \ + case 0x9a: out = D ^ (P & ~S); break; \ + case 0x9b: out = ~(S ^ (D & (P | S))); break; \ + case 0x9c: out = S ^ (P & ~D); break; \ + case 0x9d: out = ~(D ^ (S & (P | D))); break; \ + case 0x9e: out = D ^ (S ^ (P | (D & S))); break; \ + case 0x9f: out = ~(P & (D ^ S)); break; \ + case 0xa0: out = D & P; break; \ + case 0xa1: out = ~(P ^ (D | (S & ~P))); break; \ + case 0xa2: out = D & (P | ~S); break; \ + case 0xa3: out = ~(D ^ (P | (S ^ D))); break; \ + case 0xa4: out = ~(P ^ (D | ~(S | P))); break; \ + case 0xa5: out = ~(P ^ D); break; \ + case 0xa6: out = D ^ (S & ~P); break; \ + case 0xa7: out = ~(P ^ (D & (S | P))); break; \ + case 0xa8: out = D & (P | S); break; \ + case 0xa9: out = ~(D ^ (P | S)); break; \ + case 0xaa: out = D; break; \ + case 0xab: out = D | ~(P | S); break; \ + case 0xac: out = S ^ (P & (D ^ S)); break; \ + case 0xad: out = ~(D ^ (P | (S & D))); break; \ + case 0xae: out = D | (S & ~P); break; \ + case 0xaf: out = D | ~P; break; \ + case 0xb0: out = P & (D | ~S); break; \ + case 0xb1: out = ~(P ^ (D | (S ^ P))); break; \ + case 0xb2: out = S ^ ((S ^ P) | (D ^ S)); break; \ + case 0xb3: out = ~(S & ~(D & P)); break; \ + case 0xb4: out = P ^ (S & ~D); break; \ + case 0xb5: out = ~(D ^ (P & (S | D))); break; \ + case 0xb6: out = D ^ (P ^ (S | (D & P))); break; \ + case 0xb7: out = ~(S & (D ^ P)); break; \ + case 0xb8: out = P ^ (S & (D ^ P)); break; \ + case 0xb9: out = ~(D ^ (S | (P & D))); break; \ + case 0xba: out = D | (P & ~S); break; \ + case 0xbb: out = D | ~S; break; \ + case 0xbc: out = S ^ (P & ~(D & S)); break; \ + case 0xbd: out = ~((S ^ D) & (P ^ D)); break; \ + case 0xbe: out = D | (P ^ S); break; \ + case 0xbf: out = D | ~(P & S); break; \ + case 0xc0: out = P & S; break; \ + case 0xc1: out = ~(S ^ (P | (D & ~S))); break; \ + case 0xc2: out = ~(S ^ (P | ~(D | S))); break; \ + case 0xc3: out = ~(P ^ S); break; \ + case 0xc4: out = S & (P | ~D); break; \ + case 0xc5: out = ~(S ^ (P | (D ^ S))); break; \ + case 0xc6: out = S ^ (D & ~P); break; \ + case 0xc7: out = ~(P ^ (S & (D | P))); break; \ + case 0xc8: out = S & (D | P); break; \ + case 0xc9: out = ~(S ^ (P | D)); break; \ + case 0xca: out = D ^ (P & (S ^ D)); break; \ + case 0xcb: out = ~(S ^ (P | (D & S))); break; \ + case 0xcc: out = S; break; \ + case 0xcd: out = S | ~(D | P); break; \ + case 0xce: out = S | (D & ~P); break; \ + case 0xcf: out = S | ~P; break; \ + case 0xd0: out = P & (S | ~D); break; \ + case 0xd1: out = ~(P ^ (S | (D ^ P))); break; \ + case 0xd2: out = P ^ (D & ~S); break; \ + case 0xd3: out = ~(S ^ (P & (D | S))); break; \ + case 0xd4: out = S ^ ((S ^ P) & (P ^ D)); break; \ + case 0xd5: out = ~(D & ~(P & S)); break; \ + case 0xd6: out = P ^ (S ^ (D | (P & S))); break; \ + case 0xd7: out = ~(D & (P ^ S)); break; \ + case 0xd8: out = P ^ (D & (S ^ P)); break; \ + case 0xd9: out = ~(S ^ (D | (P & S))); break; \ + case 0xda: out = D ^ (P & ~(S & D)); break; \ + case 0xdb: out = ~((S ^ P) & (D ^ S)); break; \ + case 0xdc: out = S | (P & ~D); break; \ + case 0xdd: out = S | ~D; break; \ + case 0xde: out = S | (D ^ P); break; \ + case 0xdf: out = S | ~(D & P); break; \ + case 0xe0: out = P & (D | S); break; \ + case 0xe1: out = ~(P ^ (D | S)); break; \ + case 0xe2: out = D ^ (S & (P ^ D)); break; \ + case 0xe3: out = ~(P ^ (S | (D & P))); break; \ + case 0xe4: out = S ^ (D & (P ^ S)); break; \ + case 0xe5: out = ~(P ^ (D | (S & P))); break; \ + case 0xe6: out = S ^ (D & ~(P & S)); break; \ + case 0xe7: out = ~((S ^ P) & (P ^ D)); break; \ + case 0xe8: out = S ^ ((S ^ P) & (D ^ S)); break; \ + case 0xe9: out = ~(D ^ (S ^ (P & ~(D & S)))); break; \ + case 0xea: out = D | (P & S); break; \ + case 0xeb: out = D | ~(P ^ S); break; \ + case 0xec: out = S | (D & P); break; \ + case 0xed: out = S | ~(D ^ P); break; \ + case 0xee: out = D | S; break; \ + case 0xef: out = S | (D | ~P); break; \ + case 0xf0: out = P; break; \ + case 0xf1: out = P | ~(D | S); break; \ + case 0xf2: out = P | (D & ~S); break; \ + case 0xf3: out = P | ~S; break; \ + case 0xf4: out = P | (S & ~D); break; \ + case 0xf5: out = P | ~D; break; \ + case 0xf6: out = P | (D ^ S); break; \ + case 0xf7: out = P | ~(D & S); break; \ + case 0xf8: out = P | (D & S); break; \ + case 0xf9: out = P | ~(D ^ S); break; \ + case 0xfa: out = D | P; break; \ + case 0xfb: out = D | (P | ~S); break; \ + case 0xfc: out = P | S; break; \ + case 0xfd: out = P | (S | ~D); break; \ + case 0xfe: out = D | (P | S); break; \ + case 0xff: out = ~0; break; \ + } \ + } + +static void +et4000w32_blit(int count, int cpu_input, uint32_t src_dat, uint32_t mix_dat, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + uint8_t pattern, source, dest; + uint8_t rop; + uint8_t out; + int mixmap; + + while (count-- && et4000->acl.y_count >= 0) { + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + + if (cpu_input == 1) { + source = src_dat & 0xff; + src_dat >>= 8; + } else /*The source data is from the display memory if the Control Routing register is not set to 1*/ + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + mixmap = mix_dat & 1; + + /*Now determine the Raster Operation*/ + rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + mix_dat >>= 1; + mix_dat |= 0x80000000; + + ROPMIX(rop, dest, pattern, source, out); + + /*Write the data*/ + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + + if (et4000->acl.internal.xy_dir & 1) { + et4000->acl.dest_addr--; + et4000->acl.pattern_x--; + et4000->acl.source_x--; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1); + if (et4000->acl.source_x < 0) + et4000->acl.source_x += (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1); + } else { + et4000->acl.dest_addr++; + et4000->acl.pattern_x++; + et4000->acl.source_x++; + if (et4000->acl.pattern_x >= (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) + et4000->acl.pattern_x -= (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1); + if (et4000->acl.source_x >= (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) + et4000->acl.source_x -= (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1); + } + + et4000->acl.x_count--; + if (et4000->acl.x_count == 0xffff) { + et4000->acl.x_count = et4000->acl.internal.count_x; + + if (et4000->acl.internal.xy_dir & 2) { + et4000->acl.pattern_addr -= (et4000->acl.internal.pattern_off + 1); + et4000->acl.source_addr -= (et4000->acl.internal.source_off + 1); + et4000->acl.dest_addr -= (et4000->acl.internal.dest_off + 1); + et4000->acl.pattern_y--; + if ((et4000->acl.pattern_y < 0) && !(et4000->acl.internal.pattern_wrap & 0x40)) { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if ((et4000->acl.source_y < 0) && !(et4000->acl.internal.source_wrap & 0x40)) { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1)); + } + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } else { + et4000->acl.pattern_addr += (et4000->acl.internal.pattern_off + 1); + et4000->acl.source_addr += (et4000->acl.internal.source_off + 1); + et4000->acl.dest_addr += (et4000->acl.internal.dest_off + 1); + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + (et4000->acl.internal.dest_off + 1); + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.y_count--; + if (et4000->acl.y_count == 0xffff) { + et4000->acl.status &= ~ACL_XYST; + if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) { + et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count); + et4000->acl.status &= ~ACL_SSO; + } + et4000->acl.cpu_input_num = 0; + return; + } + + if (cpu_input) + return; + } } } -void et4000w32p_recalcmapping(et4000w32p_t *et4000) +static void +et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) { - svga_t *svga = &et4000->svga; - - if (!(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) - { - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&et4000->linear_mapping); - mem_mapping_disable(&et4000->mmu_mapping); - return; - } + svga_t *svga = &et4000->svga; + uint8_t pattern, source, dest, out; + uint8_t rop; + int mixdat; - if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ - { - mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&et4000->mmu_mapping); - } - else - { - int map = (svga->gdcreg[6] & 0xc) >> 2; - if (svga->crtc[0x36] & 0x20) map |= 4; - if (svga->crtc[0x36] & 0x08) map |= 8; - switch (map) - { - case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); - mem_mapping_disable(&et4000->mmu_mapping); - svga->banked_mask = 0xffff; - break; - case 0x1: /*64k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - mem_mapping_disable(&et4000->mmu_mapping); - svga->banked_mask = 0xffff; - break; - case 0x2: /*32k at B0000*/ - mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - mem_mapping_disable(&et4000->mmu_mapping); - svga->banked_mask = 0x7fff; - break; - case 0x3: /*32k at B8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - mem_mapping_disable(&et4000->mmu_mapping); - svga->banked_mask = 0x7fff; - break; - case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - mem_mapping_set_addr(&et4000->mmu_mapping, 0xb8000, 0x08000); - svga->banked_mask = 0xffff; - break; - case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); - svga->banked_mask = 0x7fff; - break; - case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); - svga->banked_mask = 0x7fff; - break; - } - - mem_mapping_disable(&et4000->linear_mapping); - } - et4000->linearbase_old = et4000->linearbase; - - if (!et4000->interleaved && (et4000->svga.crtc[0x32] & 0x80)) - mem_mapping_disable(&svga->mapping); -} + if (!(et4000->acl.status & ACL_XYST)) { + et4000w32_log("XY Block not started\n"); + return; + } -#define ACL_WRST 1 -#define ACL_RDST 2 -#define ACL_XYST 4 -#define ACL_SSO 8 + if (et4000->acl.internal.xy_dir & 0x80) { /* Line draw */ + et4000w32_log("Line draw\n"); + while (count--) { + et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + et4000w32_log("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask, (et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask); + if (cpu_input == 2) { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + out = 0; + et4000w32_log("%06X ", et4000->acl.dest_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask] & (1 << (et4000->acl.mix_addr & 7)); + et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask]); + } else { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + et4000->acl.mix_addr++; + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; -static void et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) -{ - switch (addr & 0x7fff) - { - case 0x7f80: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFFFF00) | val; break; - case 0x7f81: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFF00FF) | (val << 8); break; - case 0x7f82: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFF00FFFF) | (val << 16); break; - case 0x7f83: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00FFFFFF) | (val << 24); break; - case 0x7f84: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFFFF00) | val; break; - case 0x7f85: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFF00FF) | (val << 8); break; - case 0x7f86: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFF00FFFF) | (val << 16); break; - case 0x7f87: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00FFFFFF) | (val << 24); break; - case 0x7f88: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xFF00) | val; break; - case 0x7f89: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00FF) | (val << 8); break; - case 0x7f8a: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xFF00) | val; break; - case 0x7f8b: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00FF) | (val << 8); break; - case 0x7f8c: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xFF00) | val; break; - case 0x7f8d: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00FF) | (val << 8); break; - case 0x7f8e: et4000->acl.queued.pixel_depth = val; break; - case 0x7f8f: et4000->acl.queued.xy_dir = val; break; - case 0x7f90: et4000->acl.queued.pattern_wrap = val; break; - case 0x7f92: et4000->acl.queued.source_wrap = val; break; - case 0x7f98: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xFF00) | val; break; - case 0x7f99: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00FF) | (val << 8); break; - case 0x7f9a: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xFF00) | val; break; - case 0x7f9b: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00FF) | (val << 8); break; - case 0x7f9c: et4000->acl.queued.ctrl_routing = val; break; - case 0x7f9d: et4000->acl.queued.ctrl_reload = val; break; - case 0x7f9e: et4000->acl.queued.rop_bg = val; break; - case 0x7f9f: et4000->acl.queued.rop_fg = val; break; - case 0x7fa0: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFFFF00) | val; break; - case 0x7fa1: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFF00FF) | (val << 8); break; - case 0x7fa2: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFF00FFFF) | (val << 16); break; - case 0x7fa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00FFFFFF) | (val << 24); - et4000->acl.internal = et4000->acl.queued; - et4000w32_blit_start(et4000); - if (!(et4000->acl.queued.ctrl_routing & 0x43)) - { - et4000w32_blit(0xFFFFFF, ~0, 0, 0, et4000); - } - if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) - et4000w32_blit(4, ~0, 0, 0, et4000); - break; - case 0x7fa4: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; break; - case 0x7fa5: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); break; - case 0x7fa6: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); break; - case 0x7fa7: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); break; - case 0x7fa8: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; break; - case 0x7fa9: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); break; - case 0x7faa: et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; break; - case 0x7fab: et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); break; - case 0x7fac: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; break; - case 0x7fad: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); break; - case 0x7fae: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; break; - case 0x7faf: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); break; - } -} + ROPMIX(rop, dest, pattern, source, out); -static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val) -{ - if (!(et4000->acl.status & ACL_XYST)) return; - if (et4000->acl.internal.ctrl_routing & 3) - { - if ((et4000->acl.internal.ctrl_routing & 3) == 2) - { - if (et4000->acl.mix_addr & 7) - et4000w32_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); - else - et4000w32_blit(8, val, 0, 1, et4000); - } - else if ((et4000->acl.internal.ctrl_routing & 3) == 1) - et4000w32_blit(1, ~0, val, 2, et4000); - } -} + et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & et4000->vram_mask, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) { + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + } else { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } -static void fifo_thread(void *param) -{ - et4000w32p_t *et4000 = (et4000w32p_t *)param; + et4000->acl.pix_pos++; + et4000->acl.internal.pos_x++; + if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) { + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + } else { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + else + et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + et4000->acl.pix_pos = 0; - uint64_t start_time = 0; - uint64_t end_time = 0; + /*Next pixel*/ + switch (et4000->acl.internal.xy_dir & 7) { + case 0: case 1: /* Y+ */ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 2: case 3: /* Y- */ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 4: case 6: /* X+ */ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + case 5: case 7: /* X- */ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + } + et4000->acl.internal.error += et4000->acl.internal.dmin; + if (et4000->acl.internal.error > et4000->acl.internal.dmaj) { + et4000->acl.internal.error -= et4000->acl.internal.dmaj; + switch (et4000->acl.internal.xy_dir & 7) { + case 0: case 2: /* X+ */ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 1: case 3: /* X- */ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 4: case 5: /* Y+ */ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + break; + case 6: case 7: /* Y- */ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + break; + } + } + if ((et4000->acl.internal.pos_x > et4000->acl.internal.count_x) || + (et4000->acl.internal.pos_y > et4000->acl.internal.count_y)) { + et4000w32_log("ACL status linedraw 0\n"); + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + } + } + } else { + et4000w32_log("BitBLT: count = %i\n", count); + while (count-- && et4000->acl.y_count >= 0) { + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; - fifo_entry_t *fifo; - - while (1) - { - thread_set_event(et4000->fifo_not_full_event); - thread_wait_event(et4000->wake_fifo_thread, -1); - thread_reset_event(et4000->wake_fifo_thread); - et4000->blitter_busy = 1; - while (!FIFO_EMPTY) - { - start_time = plat_timer_read(); - fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; + if (cpu_input == 2) { + source = sdat & 0xff; + sdat >>= 8; + } else + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; - switch (fifo->addr_type & FIFO_TYPE) - { - case FIFO_WRITE_BYTE: - et4000w32p_accel_write_fifo(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_MMU: - et4000w32p_accel_write_mmu(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - } - - et4000->fifo_read_idx++; - fifo->addr_type = FIFO_INVALID; + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + out = 0; - if (FIFO_ENTRIES > 0xe000) - thread_set_event(et4000->fifo_not_full_event); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask] & (1 << (et4000->acl.mix_addr & 7)); + } else { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } - end_time = plat_timer_read(); - et4000->blitter_time += end_time - start_time; - } - et4000->blitter_busy = 0; - } -} + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; -static __inline void wake_fifo_thread(et4000w32p_t *et4000) -{ - thread_set_event(et4000->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} + ROPMIX(rop, dest, pattern, source, out); -static void et4000w32p_wait_fifo_idle(et4000w32p_t *et4000) -{ - while (!FIFO_EMPTY) - { - wake_fifo_thread(et4000); - thread_wait_event(et4000->fifo_not_full_event, 1); - } -} + if (!(et4000->acl.internal.ctrl_routing & 0x40)) { + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + } else { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } -static void et4000w32p_queue(et4000w32p_t *et4000, uint32_t addr, uint32_t val, uint32_t type) -{ - fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_write_idx & FIFO_MASK]; + if (et4000->acl.internal.xy_dir & 1) + et4000w32_decx(1, et4000); + else + et4000w32_incx(1, et4000); - if (FIFO_FULL) - { - thread_reset_event(et4000->fifo_not_full_event); - if (FIFO_FULL) - { - thread_wait_event(et4000->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ - } - } + et4000->acl.x_count--; + if (et4000->acl.x_count == 0xffff) { + if (et4000->acl.internal.xy_dir & 2) { + et4000w32_decy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } else { + et4000w32_incy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } - fifo->val = val; - fifo->addr_type = (addr & FIFO_ADDR) | type; + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; - et4000->fifo_write_idx++; - - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) - wake_fifo_thread(et4000); -} + et4000->acl.y_count--; + et4000->acl.x_count = et4000->acl.internal.count_x; + if (et4000->acl.y_count == 0xffff) { + et4000w32_log("BitBLT end\n"); + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } -void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) -{ - et4000w32p_t *et4000 = (et4000w32p_t *)p; - svga_t *svga = &et4000->svga; - int bank; - switch (addr & 0x6000) - { - case 0x0000: /*MMU 0*/ - case 0x2000: /*MMU 1*/ - case 0x4000: /*MMU 2*/ - bank = (addr >> 13) & 3; - if (et4000->mmu.ctrl & (1 << bank)) - { - et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_MMU); - } - else - { - if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_max) - { - svga->vram[(addr & 0x1fff) + et4000->mmu.base[bank]] = val; - svga->changedvram[((addr & 0x1fff) + et4000->mmu.base[bank]) >> 12] = changeframecount; - } - } - break; - case 0x6000: - if ((addr & 0x7fff) >= 0x7f80) - { - et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_BYTE); - } - else switch (addr & 0x7fff) - { - case 0x7f00: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFFFF00) | val; break; - case 0x7f01: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFF00FF) | (val << 8); break; - case 0x7f02: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFF00FFFF) | (val << 16); break; - case 0x7f03: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00FFFFFF) | (val << 24); break; - case 0x7f04: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFFFF00) | val; break; - case 0x7f05: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFF00FF) | (val << 8); break; - case 0x7f06: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFF00FFFF) | (val << 16); break; - case 0x7f07: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00FFFFFF) | (val << 24); break; - case 0x7f08: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFFFF00) | val; break; - case 0x7f09: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFF00FF) | (val << 8); break; - case 0x7f0a: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFF00FFFF) | (val << 16); break; - case 0x7f0d: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00FFFFFF) | (val << 24); break; - case 0x7f13: et4000->mmu.ctrl=val; break; - } - break; - } -} + if (cpu_input) + return; -uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) -{ - et4000w32p_t *et4000 = (et4000w32p_t *)p; - svga_t *svga = &et4000->svga; - int bank; - uint8_t temp; - switch (addr & 0x6000) - { - case 0x0000: /*MMU 0*/ - case 0x2000: /*MMU 1*/ - case 0x4000: /*MMU 2*/ - bank = (addr >> 13) & 3; - if (et4000->mmu.ctrl & (1 << bank)) - { - et4000w32p_wait_fifo_idle(et4000); - temp = 0xff; - if (et4000->acl.cpu_dat_pos) - { - et4000->acl.cpu_dat_pos--; - temp = et4000->acl.cpu_dat & 0xff; - et4000->acl.cpu_dat >>= 8; - } - if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) - et4000w32_blit(4, ~0, 0, 0, et4000); - /*???*/ - return temp; - } - if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_max) - return 0xff; - return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; - - case 0x6000: - if ((addr & 0x7fff) >= 0x7f80) - et4000w32p_wait_fifo_idle(et4000); - switch (addr&0x7fff) - { - case 0x7f00: return et4000->mmu.base[0]; - case 0x7f01: return et4000->mmu.base[0] >> 8; - case 0x7f02: return et4000->mmu.base[0] >> 16; - case 0x7f03: return et4000->mmu.base[0] >> 24; - case 0x7f04: return et4000->mmu.base[1]; - case 0x7f05: return et4000->mmu.base[1] >> 8; - case 0x7f06: return et4000->mmu.base[1] >> 16; - case 0x7f07: return et4000->mmu.base[1] >> 24; - case 0x7f08: return et4000->mmu.base[2]; - case 0x7f09: return et4000->mmu.base[2] >> 8; - case 0x7f0a: return et4000->mmu.base[2] >> 16; - case 0x7f0b: return et4000->mmu.base[2] >> 24; - case 0x7f13: return et4000->mmu.ctrl; - - case 0x7f36: - temp = et4000->acl.status; - temp &= ~0x03; - if (!FIFO_EMPTY) - temp |= 0x02; - if (FIFO_FULL) - temp |= 0x01; - return temp; - case 0x7f80: return et4000->acl.internal.pattern_addr; - case 0x7f81: return et4000->acl.internal.pattern_addr >> 8; - case 0x7f82: return et4000->acl.internal.pattern_addr >> 16; - case 0x7f83: return et4000->acl.internal.pattern_addr >> 24; - case 0x7f84: return et4000->acl.internal.source_addr; - case 0x7f85: return et4000->acl.internal.source_addr >> 8; - case 0x7f86: return et4000->acl.internal.source_addr >> 16; - case 0x7f87: return et4000->acl.internal.source_addr >> 24; - case 0x7f88: return et4000->acl.internal.pattern_off; - case 0x7f89: return et4000->acl.internal.pattern_off >> 8; - case 0x7f8a: return et4000->acl.internal.source_off; - case 0x7f8b: return et4000->acl.internal.source_off >> 8; - case 0x7f8c: return et4000->acl.internal.dest_off; - case 0x7f8d: return et4000->acl.internal.dest_off >> 8; - case 0x7f8e: return et4000->acl.internal.pixel_depth; - case 0x7f8f: return et4000->acl.internal.xy_dir; - case 0x7f90: return et4000->acl.internal.pattern_wrap; - case 0x7f92: return et4000->acl.internal.source_wrap; - case 0x7f98: return et4000->acl.internal.count_x; - case 0x7f99: return et4000->acl.internal.count_x >> 8; - case 0x7f9a: return et4000->acl.internal.count_y; - case 0x7f9b: return et4000->acl.internal.count_y >> 8; - case 0x7f9c: return et4000->acl.internal.ctrl_routing; - case 0x7f9d: return et4000->acl.internal.ctrl_reload; - case 0x7f9e: return et4000->acl.internal.rop_bg; - case 0x7f9f: return et4000->acl.internal.rop_fg; - case 0x7fa0: return et4000->acl.internal.dest_addr; - case 0x7fa1: return et4000->acl.internal.dest_addr >> 8; - case 0x7fa2: return et4000->acl.internal.dest_addr >> 16; - case 0x7fa3: return et4000->acl.internal.dest_addr >> 24; - } - return 0xff; - } - return 0xff; -} - -static int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000}; -static int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; -static int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - -/* int bltout=0; */ -void et4000w32_blit_start(et4000w32p_t *et4000) -{ - if (!(et4000->acl.queued.xy_dir & 0x20)) - et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; - et4000->acl.pattern_addr= et4000->acl.internal.pattern_addr; - et4000->acl.source_addr = et4000->acl.internal.source_addr; - et4000->acl.mix_addr = et4000->acl.internal.mix_addr; - et4000->acl.mix_back = et4000->acl.mix_addr; - et4000->acl.dest_addr = et4000->acl.internal.dest_addr; - et4000->acl.dest_back = et4000->acl.dest_addr; - et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; - et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; - et4000->acl.status |= ACL_XYST; - if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) - et4000->acl.status |= ACL_SSO; - - if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) - { - et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; - et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; - } - et4000->acl.pattern_back = et4000->acl.pattern_addr; - if (!(et4000->acl.internal.pattern_wrap & 0x40)) - { - et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); - et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); - } - et4000->acl.pattern_x_back = et4000->acl.pattern_x; - - if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) - { - et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; - et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; - } - et4000->acl.source_back = et4000->acl.source_addr; - if (!(et4000->acl.internal.source_wrap & 0x40)) - { - et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); - et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); - } - et4000->acl.source_x_back = et4000->acl.source_x; - - et4000w32_max_x[2] = ((et4000->acl.internal.pixel_depth & 0x30) == 0x20) ? 3 : 4; - - et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; - et4000->acl.cpu_dat_pos = 0; - et4000->acl.cpu_dat = 0; - - et4000->acl.pix_pos = 0; -} - -void et4000w32_incx(int c, et4000w32p_t *et4000) -{ - et4000->acl.dest_addr += c; - et4000->acl.pattern_x += c; - et4000->acl.source_x += c; - et4000->acl.mix_addr += c; - if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) - et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; - if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) - et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; -} -void et4000w32_decx(int c, et4000w32p_t *et4000) -{ - et4000->acl.dest_addr -= c; - et4000->acl.pattern_x -= c; - et4000->acl.source_x -= c; - et4000->acl.mix_addr -= c; - if (et4000->acl.pattern_x < 0) - et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; - if (et4000->acl.source_x < 0) - et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; -} -void et4000w32_incy(et4000w32p_t *et4000) -{ - et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; - et4000->acl.source_addr += et4000->acl.internal.source_off + 1; - et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; - et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; - et4000->acl.pattern_y++; - if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - { - et4000->acl.pattern_y = 0; - et4000->acl.pattern_addr = et4000->acl.pattern_back; - } - et4000->acl.source_y++; - if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - { - et4000->acl.source_y = 0; - et4000->acl.source_addr = et4000->acl.source_back; - } -} -void et4000w32_decy(et4000w32p_t *et4000) -{ - et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; - et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; - et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; - et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; - et4000->acl.pattern_y--; - if (et4000->acl.pattern_y < 0 && !(et4000->acl.internal.pattern_wrap & 0x40)) - { - et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; - et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); - } - et4000->acl.source_y--; - if (et4000->acl.source_y < 0 && !(et4000->acl.internal.source_wrap & 0x40)) - { - et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; - et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] *(et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1));; - } -} - -void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) -{ - svga_t *svga = &et4000->svga; - int c,d; - uint8_t pattern, source, dest, out; - uint8_t rop; - int mixdat; - - if (!(et4000->acl.status & ACL_XYST)) return; - if (et4000->acl.internal.xy_dir & 0x80) /*Line draw*/ - { - while (count--) - { - et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); - pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; - source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; - et4000w32_log("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff); - if (cpu_input == 2) - { - source = sdat & 0xff; - sdat >>= 8; - } - dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; - out = 0; - et4000w32_log("%06X ", et4000->acl.dest_addr); - if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) - { - mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); - et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); - } - else - { - mixdat = mix & 1; - mix >>= 1; - mix |= 0x80000000; - } - et4000->acl.mix_addr++; - rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; - for (c = 0; c < 8; c++) - { - d = (dest & (1 << c)) ? 1 : 0; - if (source & (1 << c)) d |= 2; - if (pattern & (1 << c)) d |= 4; - if (rop & (1 << d)) out |= (1 << c); - } - et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); - if (!(et4000->acl.internal.ctrl_routing & 0x40)) - { - svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; - svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; - } - else - { - et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); - et4000->acl.cpu_dat_pos++; - } - - et4000->acl.pix_pos++; - et4000->acl.internal.pos_x++; - if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) - { - if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); - else et4000w32_incx(1, et4000); - } - else - { - if (et4000->acl.internal.xy_dir & 1) - et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); - else - et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); - et4000->acl.pix_pos = 0; - /*Next pixel*/ - switch (et4000->acl.internal.xy_dir & 7) - { - case 0: case 1: /*Y+*/ - et4000w32_incy(et4000); - et4000->acl.internal.pos_y++; - et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; - break; - case 2: case 3: /*Y-*/ - et4000w32_decy(et4000); - et4000->acl.internal.pos_y++; - et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; - break; - case 4: case 6: /*X+*/ - et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); - break; - case 5: case 7: /*X-*/ - et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); - break; - } - et4000->acl.internal.error += et4000->acl.internal.dmin; - if (et4000->acl.internal.error > et4000->acl.internal.dmaj) - { - et4000->acl.internal.error -= et4000->acl.internal.dmaj; - switch (et4000->acl.internal.xy_dir & 7) - { - case 0: case 2: /*X+*/ - et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); - et4000->acl.internal.pos_x++; - break; - case 1: case 3: /*X-*/ - et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); - et4000->acl.internal.pos_x++; - break; - case 4: case 5: /*Y+*/ - et4000w32_incy(et4000); - et4000->acl.internal.pos_y++; - break; - case 6: case 7: /*Y-*/ - et4000w32_decy(et4000); - et4000->acl.internal.pos_y++; - break; - } - } - if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x || - et4000->acl.internal.pos_y > et4000->acl.internal.count_y) - { - et4000->acl.status &= ~(ACL_XYST | ACL_SSO); - return; - } - } - } - } - else - { - while (count--) - { - et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); - - pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; - source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; - et4000w32_log("%i %06X %06X %02X %02X ", et4000->acl.pattern_y, (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff, pattern, source); - - if (cpu_input == 2) - { - source = sdat & 0xff; - sdat >>= 8; - } - dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; - out = 0; - et4000w32_log("%06X %02X %i %08X %08X ", dest, et4000->acl.dest_addr, mix & 1, mix, et4000->acl.mix_addr); - if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) - { - mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); - et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); - } - else - { - mixdat = mix & 1; - mix >>= 1; - mix |= 0x80000000; - } - - rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; - for (c = 0; c < 8; c++) - { - d = (dest & (1 << c)) ? 1 : 0; - if (source & (1 << c)) d |= 2; - if (pattern & (1 << c)) d |= 4; - if (rop & (1 << d)) out |= (1 << c); - } - et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); - if (!(et4000->acl.internal.ctrl_routing & 0x40)) - { - svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; - svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; - } - else - { - et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); - et4000->acl.cpu_dat_pos++; - } - - if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); - else et4000w32_incx(1, et4000); - - et4000->acl.internal.pos_x++; - if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x) - { - if (et4000->acl.internal.xy_dir & 2) - { - et4000w32_decy(et4000); - et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); - et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); - } - else - { - et4000w32_incy(et4000); - et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; - et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; - } - - et4000->acl.pattern_x = et4000->acl.pattern_x_back; - et4000->acl.source_x = et4000->acl.source_x_back; - - et4000->acl.internal.pos_y++; - et4000->acl.internal.pos_x = 0; - if (et4000->acl.internal.pos_y > et4000->acl.internal.count_y) - { - et4000->acl.status &= ~(ACL_XYST | ACL_SSO); - return; - } - if (cpu_input) return; - if (et4000->acl.internal.ctrl_routing & 0x40) - { - if (et4000->acl.cpu_dat_pos & 3) - et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); - return; - } - } - } - } + if (et4000->acl.internal.ctrl_routing & 0x40) { + if (et4000->acl.cpu_dat_pos & 3) + et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); + return; + } + } + } + } } -void et4000w32p_hwcursor_draw(svga_t *svga, int displine) +void +et4000w32p_hwcursor_draw(svga_t *svga, int displine) { - int x, offset; - uint8_t dat; - offset = svga->hwcursor_latch.xoff; + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + int x, offset, xx, xx2; + int shift = (et4000->adjust_cursor + 1); + int width = (svga->hwcursor_latch.cur_xsize - svga->hwcursor_latch.xoff); + int pitch = (svga->hwcursor_latch.cur_xsize == 128) ? 32 : 16; + int x_acc = 4; + int minus_width = 0; + uint8_t dat; + offset = svga->hwcursor_latch.xoff; - for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) - { - dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x] ^= 0xFFFFFF; - dat >>= 2; - if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 1] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 1] ^= 0xFFFFFF; - dat >>= 2; - if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 2] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 2] ^= 0xFFFFFF; - dat >>= 2; - if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 3] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 3] ^= 0xFFFFFF; - dat >>= 2; - offset += 4; - } - svga->hwcursor_latch.addr += 16; + if (et4000->type == ET4000W32) { + switch (svga->bpp) { + case 8: + minus_width = 0; + x_acc = 2; + break; + case 15: case 16: + minus_width = 64; + x_acc = 2; + break; + } + } + + for (x = 0; x < (width - minus_width); x += x_acc) { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + + xx = svga->hwcursor_latch.x + svga->x_add + x; + + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + xx++; + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + xx++; + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + xx++; + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + + offset += 4; + } + + svga->hwcursor_latch.addr += pitch; } -static void et4000w32p_io_remove(et4000w32p_t *et4000) -{ - io_removehandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_removehandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +static void +et4000w32p_io_remove(et4000w32p_t *et4000) +{ + io_removehandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_removehandler(0x210a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x211a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x212a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x213a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x214a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x215a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x216a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x217a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); } -static void et4000w32p_io_set(et4000w32p_t *et4000) -{ - et4000w32p_io_remove(et4000); - - io_sethandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); - io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +static void +et4000w32p_io_set(et4000w32p_t *et4000) +{ + et4000w32p_io_remove(et4000); + + io_sethandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_sethandler(0x210a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x211a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x212a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x213a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x214a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x215a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x216a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x217a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); } -uint8_t et4000w32p_pci_read(int func, int addr, void *p) + +uint8_t +et4000w32p_pci_read(int func, int addr, void *p) { - et4000w32p_t *et4000 = (et4000w32p_t *)p; + et4000w32p_t *et4000 = (et4000w32p_t *)p; - addr &= 0xff; + addr &= 0xff; - switch (addr) - { - case 0x00: return 0x0c; /*Tseng Labs*/ - case 0x01: return 0x10; - - case 0x02: return 0x06; /*ET4000W32p Rev D*/ - case 0x03: return 0x32; - - case PCI_REG_COMMAND: - return et4000->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ + switch (addr) { + case 0x00: return 0x0c; /* Tseng Labs */ + case 0x01: return 0x10; - case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ - - case 0x08: return 0; /*Revision ID*/ - case 0x09: return 0; /*Programming interface*/ - - case 0x0a: return 0x00; /*Supports VGA interface, XGA compatible*/ - case 0x0b: return cpu_64bitbus ? 0x03 : 0x00; /* This has to be done in order to make this card work with the two 486 PCI machines. */ - - case 0x10: return 0x00; /*Linear frame buffer address*/ - case 0x11: return 0x00; - case 0x12: return 0x00; - case 0x13: return (et4000->linearbase >> 24); + case 0x02: return (et4000->rev); + case 0x03: return 0x32; - case 0x30: return et4000->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ - case 0x31: return 0x00; - case 0x32: return 0x00; - case 0x33: return (et4000->pci_regs[0x33]) & 0xf0; + case PCI_REG_COMMAND: + return et4000->pci_regs[PCI_REG_COMMAND] | 0x80; /* Respond to IO and memory accesses */ - } - return 0; + case 0x07: return 1 << 1; /* Medium DEVSEL timing */ + + case 0x08: return (et4000->rev); /* Revision ID */ + case 0x09: return 0; /* Programming interface */ + + case 0x0a: return 0x00; /* Supports VGA interface */ + case 0x0b: return 0x03; /* This has to be done in order to make this card work with the two 486 PCI machines. */ + + case 0x10: return 0x00; /* Linear frame buffer address */ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return (et4000->linearbase >> 24); + + case 0x30: return et4000->pci_regs[0x30] & 0x01; /* BIOS ROM address */ + case 0x31: return 0x00; + case 0x32: return 0x00; + case 0x33: return et4000->pci_regs[0x33] & 0xf0; + } + + return 0; } -void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) + +void +et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) { - et4000w32p_t *et4000 = (et4000w32p_t *)p; - svga_t *svga = &et4000->svga; + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; - addr &= 0xff; + addr &= 0xff; - switch (addr) - { - case PCI_REG_COMMAND: - et4000->pci_regs[PCI_REG_COMMAND] = (val & 0x23) | 0x80; - if (val & PCI_COMMAND_IO) - et4000w32p_io_set(et4000); - else - et4000w32p_io_remove(et4000); - et4000w32p_recalcmapping(et4000); - break; + switch (addr) { + case PCI_REG_COMMAND: + et4000->pci_regs[PCI_REG_COMMAND] = (val & 0x23) | 0x80; + if (val & PCI_COMMAND_IO) + et4000w32p_io_set(et4000); + else + et4000w32p_io_remove(et4000); + et4000w32p_recalcmapping(et4000); + break; - case 0x13: - et4000->linearbase &= 0x00c00000; - et4000->linearbase |= (et4000->pci_regs[0x13] << 24); + case 0x13: + et4000->linearbase &= 0x00c00000; + et4000->linearbase |= (et4000->pci_regs[0x13] << 24); svga->crtc[0x30] &= 3; svga->crtc[0x30] |= ((et4000->linearbase & 0x3f000000) >> 22); - et4000w32p_recalcmapping(et4000); - break; + et4000w32p_recalcmapping(et4000); + break; - case 0x30: case 0x31: case 0x32: case 0x33: - et4000->pci_regs[addr] = val; + case 0x30: case 0x31: case 0x32: case 0x33: + et4000->pci_regs[addr] = val; et4000->pci_regs[0x30] = 1; et4000->pci_regs[0x31] = 0; et4000->pci_regs[0x32] = 0; et4000->pci_regs[0x33] &= 0xf0; - if (et4000->pci_regs[0x30] & 0x01) - { - uint32_t addr = (et4000->pci_regs[0x33] << 24); - if (!addr) - { - addr = 0xC0000; - } - et4000w32_log("ET4000 bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&et4000->bios_rom.mapping, addr, 0x8000); - } - else - { - et4000w32_log("ET4000 bios_rom disabled\n"); - mem_mapping_disable(&et4000->bios_rom.mapping); - } - return; - } + if (et4000->pci_regs[0x30] & 0x01) { + uint32_t biosaddr = (et4000->pci_regs[0x33] << 24); + if (!biosaddr) + biosaddr = 0xc0000; + et4000w32_log("ET4000 bios_rom enabled at %08x\n", biosaddr); + mem_mapping_set_addr(&et4000->bios_rom.mapping, biosaddr, 0x8000); + } else { + et4000w32_log("ET4000 bios_rom disabled\n"); + mem_mapping_disable(&et4000->bios_rom.mapping); + } + return; + } } -void *et4000w32p_init(const device_t *info) + +void * +et4000w32p_init(const device_t *info) { - int vram_size; - et4000w32p_t *et4000 = malloc(sizeof(et4000w32p_t)); - memset(et4000, 0, sizeof(et4000w32p_t)); + int vram_size; + et4000w32p_t *et4000 = malloc(sizeof(et4000w32p_t)); + memset(et4000, 0, sizeof(et4000w32p_t)); - vram_size = device_get_config_int("memory"); - - et4000->interleaved = (vram_size == 2) ? 1 : 0; + et4000->pci = (info->flags & DEVICE_PCI) ? 0x80 : 0x00; + et4000->vlb = (info->flags & DEVICE_VLB) ? 0x40 : 0x00; - if (info->flags & DEVICE_PCI) - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_pci); + /*The ET4000/W32i ISA BIOS seems to not support 2MB of VRAM*/ + if ((info->local == ET4000W32) || ((info->local == ET4000W32I) && !(et4000->vlb))) + vram_size = 1; else - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_vlb); + vram_size = device_get_config_int("memory"); - svga_init(info, &et4000->svga, et4000, vram_size << 20, - et4000w32p_recalctimings, - et4000w32p_in, et4000w32p_out, - et4000w32p_hwcursor_draw, - NULL); + /*The interleaved VRAM was introduced by the ET4000/W32i*/ + et4000->interleaved = ((vram_size == 2) && (info->local != ET4000W32)) ? 1 : 0; - et4000->svga.ramdac = device_add(&stg_ramdac_device); + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_pci); + else if (info->flags & DEVICE_VLB) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_vlb); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_isa); - et4000->vram_mask = (vram_size << 20) - 1; + svga_init(info, &et4000->svga, et4000, vram_size << 20, + et4000w32p_recalctimings, + et4000w32p_in, et4000w32p_out, + et4000w32p_hwcursor_draw, + NULL); - et4000->type = info->local; + et4000->vram_mask = (vram_size << 20) - 1; + et4000->svga.decode_mask = (vram_size << 20) - 1; - switch(et4000->type) { - case ET4000W32_CARDEX: - rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0, - MEM_MAPPING_EXTERNAL); + et4000->type = info->local; - et4000->svga.clock_gen = et4000->svga.ramdac; - et4000->svga.getclock = stg_getclock; - break; + switch(et4000->type) { + case ET4000W32: + /* ET4000/W32 */ + et4000->rev = 0; - case ET4000W32_DIAMOND: - rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0, - MEM_MAPPING_EXTERNAL); + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); - et4000->svga.clock_gen = device_add(&icd2061_device); - et4000->svga.getclock = icd2061_getclock; - break; - } - et4000->pci = !!(info->flags & DEVICE_PCI); - if (info->flags & DEVICE_PCI) - mem_mapping_disable(&et4000->bios_rom.mapping); + et4000->svga.ramdac = device_add(&tseng_ics5301_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; + break; - mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &et4000->svga); - mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, et4000); + case ET4000W32I: + /* ET4000/W32i rev B */ + et4000->rev = 3; - et4000w32p_io_set(et4000); - - if (info->flags & DEVICE_PCI) - pci_add_card(PCI_ADD_VIDEO, et4000w32p_pci_read, et4000w32p_pci_write, et4000); + if (et4000->vlb) { + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32I_VLB, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + } else { + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32I_ISA, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + } - /* Hardwired bits: 00000000 1xx0x0xx */ - /* R/W bits: xx xxxx */ - /* PCem bits: 111 */ - et4000->pci_regs[0x04] = 0x83; - - et4000->pci_regs[0x10] = 0x00; - et4000->pci_regs[0x11] = 0x00; - et4000->pci_regs[0x12] = 0xff; - et4000->pci_regs[0x13] = 0xff; - - et4000->pci_regs[0x30] = 0x00; - et4000->pci_regs[0x31] = 0x00; - et4000->pci_regs[0x32] = 0x00; - et4000->pci_regs[0x33] = 0xf0; - - et4000->wake_fifo_thread = thread_create_event(); - et4000->fifo_not_full_event = thread_create_event(); - et4000->fifo_thread = thread_create(fifo_thread, et4000); + et4000->svga.ramdac = device_add(&tseng_ics5301_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; + break; - return et4000; + case ET4000W32P_VIDEOMAGIC_REVB: + /* ET4000/W32p rev B */ + et4000->rev = 5; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; + et4000->svga.adv_flags |= FLAG_NOSKEW; + break; + + case ET4000W32P_REVC: + /* ET4000/W32p rev C */ + et4000->rev = 7; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVC, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&tseng_ics5341_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; + break; + + case ET4000W32P: + /* ET4000/W32p rev D */ + et4000->rev = 6; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; + et4000->svga.adv_flags |= FLAG_NOSKEW; + break; + + case ET4000W32P_CARDEX: + /* ET4000/W32p rev D */ + et4000->rev = 6; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; + et4000->svga.adv_flags |= FLAG_NOSKEW; + break; + + case ET4000W32P_DIAMOND: + /* ET4000/W32p rev D */ + et4000->rev = 6; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = device_add(&icd2061_device); + et4000->svga.getclock = icd2061_getclock; + break; + } + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&et4000->bios_rom.mapping); + + mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &et4000->svga); + mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, et4000); + + et4000w32p_io_set(et4000); + + if (info->flags & DEVICE_PCI) + pci_add_card(PCI_ADD_VIDEO, et4000w32p_pci_read, et4000w32p_pci_write, et4000); + + /* Hardwired bits: 00000000 1xx0x0xx */ + /* R/W bits: xx xxxx */ + /* PCem bits: 111 */ + et4000->pci_regs[0x04] = 0x83; + + et4000->pci_regs[0x10] = 0x00; + et4000->pci_regs[0x11] = 0x00; + et4000->pci_regs[0x12] = 0xff; + et4000->pci_regs[0x13] = 0xff; + + et4000->pci_regs[0x30] = 0x00; + et4000->pci_regs[0x31] = 0x00; + et4000->pci_regs[0x32] = 0x00; + et4000->pci_regs[0x33] = 0xf0; + + et4000->svga.packed_chain4 = 1; + + return et4000; } -int et4000w32p_available(void) + +int +et4000w32_available(void) { - return rom_present(BIOS_ROM_PATH_DIAMOND); + return rom_present(BIOS_ROM_PATH_W32); } -int et4000w32p_cardex_available(void) + +int +et4000w32i_isa_available(void) { - return rom_present(BIOS_ROM_PATH_CARDEX); + return rom_present(BIOS_ROM_PATH_W32I_ISA); } -void et4000w32p_close(void *p) + +int +et4000w32i_vlb_available(void) { - et4000w32p_t *et4000 = (et4000w32p_t *)p; - - svga_close(&et4000->svga); - - thread_kill(et4000->fifo_thread); - thread_destroy_event(et4000->wake_fifo_thread); - thread_destroy_event(et4000->fifo_not_full_event); - - free(et4000); + return rom_present(BIOS_ROM_PATH_W32I_VLB); } -void et4000w32p_speed_changed(void *p) +int +et4000w32p_videomagic_revb_vlb_available(void) { - et4000w32p_t *et4000 = (et4000w32p_t *)p; - - svga_recalctimings(&et4000->svga); + return rom_present(BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB); } -void et4000w32p_force_redraw(void *p) -{ - et4000w32p_t *et4000w32p = (et4000w32p_t *)p; - et4000w32p->svga.fullchange = changeframecount; +int +et4000w32p_revc_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P_REVC); } -static const device_config_t et4000w32p_config[] = + +int +et4000w32p_noncardex_available(void) { - { - "memory", "Memory size", CONFIG_SELECTION, "", 2, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "" - } - } - }, - { - "", "", -1 + return rom_present(BIOS_ROM_PATH_W32P); +} + + +int +et4000w32p_available(void) +{ + return rom_present(BIOS_ROM_PATH_DIAMOND); +} + + +int +et4000w32p_cardex_available(void) +{ + return rom_present(BIOS_ROM_PATH_CARDEX); +} + + +void +et4000w32p_close(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + + +void +et4000w32p_speed_changed(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_recalctimings(&et4000->svga); +} + + +void +et4000w32p_force_redraw(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + et4000->svga.fullchange = changeframecount; +} + +static const device_config_t et4000w32p_config[] = { +// clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } +// clang-format on }; -const device_t et4000w32p_cardex_vlb_device = -{ - "Tseng Labs ET4000/w32p VLB (Cardex)", - DEVICE_VLB, ET4000W32_CARDEX, - et4000w32p_init, et4000w32p_close, NULL, - et4000w32p_cardex_available, - et4000w32p_speed_changed, - et4000w32p_force_redraw, - et4000w32p_config +const device_t et4000w32_device = { + .name = "Tseng Labs ET4000/w32 ISA", + .internal_name = "et4000w32", + .flags = DEVICE_ISA | DEVICE_AT, ET4000W32, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = NULL }; -const device_t et4000w32p_cardex_pci_device = -{ - "Tseng Labs ET4000/w32p PCI (Cardex)", - DEVICE_PCI, ET4000W32_CARDEX, - et4000w32p_init, et4000w32p_close, NULL, - et4000w32p_cardex_available, - et4000w32p_speed_changed, - et4000w32p_force_redraw, - et4000w32p_config +const device_t et4000w32_onboard_device = { + .name = "Tseng Labs ET4000/w32 (ISA) (On-Board)", + .internal_name = "et4000w32_onboard", + .flags = DEVICE_ISA | DEVICE_AT, ET4000W32, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = NULL }; -const device_t et4000w32p_vlb_device = -{ - "Tseng Labs ET4000/w32p VLB (Diamond)", - DEVICE_VLB, ET4000W32_DIAMOND, - et4000w32p_init, et4000w32p_close, NULL, - et4000w32p_available, - et4000w32p_speed_changed, - et4000w32p_force_redraw, - et4000w32p_config +const device_t et4000w32i_isa_device = { + .name = "Tseng Labs ET4000/w32i Rev. B ISA", + .internal_name = "et4000w32i", + .flags = DEVICE_ISA | DEVICE_AT, ET4000W32I, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32i_isa_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = NULL }; -const device_t et4000w32p_pci_device = -{ - "Tseng Labs ET4000/w32p PCI (Diamond)", - DEVICE_PCI, ET4000W32_DIAMOND, - et4000w32p_init, et4000w32p_close, NULL, - et4000w32p_available, - et4000w32p_speed_changed, - et4000w32p_force_redraw, - et4000w32p_config +const device_t et4000w32i_vlb_device = { + .name = "Tseng Labs ET4000/w32i Rev. B VLB", + .internal_name = "et4000w32i_vlb", + .flags = DEVICE_VLB, ET4000W32I, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32i_vlb_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_videomagic_revb_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. B VLB (VideoMagic)", + .internal_name = "et4000w32p_videomagic_revb_vlb", + .flags = DEVICE_VLB, ET4000W32P_VIDEOMAGIC_REVB, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_videomagic_revb_vlb_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_videomagic_revb_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. B PCI (VideoMagic)", + .internal_name = "et4000w32p_videomagic_revb_pci", + .flags = DEVICE_PCI, ET4000W32P_VIDEOMAGIC_REVB, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_videomagic_revb_vlb_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_revc_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. C VLB (Cardex)", + .internal_name = "et4000w32p_revc_vlb", + .flags = DEVICE_VLB, ET4000W32P_REVC, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_revc_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_revc_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. C PCI (Cardex)", + .internal_name = "et4000w32p_revc_pci", + .flags = DEVICE_PCI, ET4000W32P_REVC, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_revc_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_noncardex_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. D VLB", + .internal_name = "et4000w32p_nc_vlb", + .flags = DEVICE_VLB, ET4000W32P, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_noncardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_noncardex_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. D PCI", + .internal_name = "et4000w32p_nc_pci", + .flags = DEVICE_PCI, ET4000W32P, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_noncardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_cardex_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. D VLB (Cardex)", + .internal_name = "et4000w32p_vlb", + .flags = DEVICE_VLB, ET4000W32P_CARDEX, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_cardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_cardex_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. D PCI (Cardex)", + .internal_name = "et4000w32p_pci", + .flags = DEVICE_PCI, ET4000W32P_CARDEX, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_cardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. D VLB (Diamond Stealth32)", + .internal_name = "stealth32_vlb", + .flags = DEVICE_VLB, ET4000W32P_DIAMOND, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. D PCI (Diamond Stealth32)", + .internal_name = "stealth32_pci", + .flags = DEVICE_PCI, ET4000W32P_DIAMOND, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config }; diff --git a/src/video/vid_f82c425.c b/src/video/vid_f82c425.c new file mode 100644 index 000000000..1e36ea5aa --- /dev/null +++ b/src/video/vid_f82c425.c @@ -0,0 +1,676 @@ +/* + * 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. + * + * Chips & Technologies 82C425 display controller emulation, + * with support for 640x200 LCD and SMARTMAP text contrast + * enhancement. + * + * Relevant literature: + * + * [1] Chips and Technologies, Inc., 82C425 CGA LCD/CRT Controller, + * Data Sheet, Revision No. 2.2, September 1991. + * + * + * [2] Pleva et al., COLOR TO MONOCHROME CONVERSION, + * U.S. Patent 4,977,398, Dec. 11, 1990. + * + * + * Based on Toshiba T1000 plasma display emulation code. + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * Lubomir Rintel, + * + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Miran Grca. + * Copyright 2018,2019 Sarah Walker. + * Copyright 2021 Lubomir Rintel. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include "cpu.h" +#include <86box/video.h> +#include <86box/vid_cga.h> + +#define F82C425_XSIZE 640 +#define F82C425_YSIZE 200 + +/* Mapping of attributes to colours */ +static uint32_t smartmap[256][2]; +static uint32_t colormap[4]; + +static video_timings_t timing_f82c425 = {VIDEO_ISA, 8,16,32, 8,16,32}; + +static uint8_t st_video_options; +static uint8_t st_enabled = 1; +static int8_t st_display_internal = -1; + +void f82c425_video_options_set(uint8_t options) +{ + st_video_options = options; +} + +void f82c425_video_enable(uint8_t enabled) +{ + st_enabled = enabled; +} + +void f82c425_display_set(uint8_t internal) +{ + st_display_internal = (int8_t)internal; +} + +uint8_t f82c425_display_get() +{ + return (uint8_t)st_display_internal; +} + + +typedef struct f82c425_t +{ + mem_mapping_t mapping; + cga_t cga; + uint8_t crtcreg; + + uint64_t dispontime, dispofftime; + + int linepos, displine; + int dispon; + uint8_t video_options; + + uint8_t *vram; + + /* Registers specific to 82C425. */ + uint8_t ac_limit; + uint8_t threshold; + uint8_t shift; + uint8_t hsync; + uint8_t vsync_blink; + uint8_t timing; + uint8_t function; +} f82c425_t; + + +/* Convert IRGB representation to RGBI, + * useful in SMARTMAP calculations. */ +static inline uint8_t f82c425_rgbi(uint8_t irgb) +{ + return ((irgb & 0x7) << 1) | (irgb >> 3); +} + +/* Convert IRGB SMARTMAP output to a RGB representation of one of 4/8 grey + * shades we'd see on an actual V86P display: with some bias toward lighter + * shades and a backlight with yellow/green-ish tint. */ +static inline uint32_t f82c425_makecol(uint8_t rgbi, int gs4, int inv) +{ + uint8_t c; + + gs4 = 1 + !!gs4; + if (!inv) + { + rgbi = 15 - rgbi; + } + c = 0x10 * gs4 * ((rgbi >> gs4) + 2); + +#ifdef NO_BLUE + return makecol(c, c + 0x08, c - 0x20); +#else + return makecol(c, c + 0x08, 0x70); +#endif +} + +/* Saturating/non-saturating addition for SMARTMAP(see below). */ +static inline int f82c425_smartmap_add(int a, int b, int sat) +{ + int c = a + b; + + /* (SATURATING OR NON SATURATING) */ + if (sat) + { + if (c < 0) + c = 0; + else if (c > 15) + c = 15; + } + + return c & 0xf; +} + +/* Calculate and cache mapping of CGA text color attribute to a + * shade of gray enhanced via the SMARTMAP algorithm. + * + * This is a straightforward implementation of the algorithm as described + * in U.S. Patent 4,977,398 [2]. The comments in capitals refer to portions + * of a figure on page 4. */ +static void f82c425_smartmap(f82c425_t *f82c425) +{ + int i; + + for (i = 0; i < 256; i++) { + uint8_t bg = f82c425_rgbi(i >> 4); + uint8_t fg = f82c425_rgbi(i & 0xf); + + /* FIG._4. */ + if (abs(bg - fg) <= (f82c425->threshold & 0x0f)) + { + /* FOREGROUND=BACKGROUND */ + if (bg == fg) + { + /* SPECIAL CASE */ + if (f82c425->shift == 0xff) + { + /* CHECK MOST SIGNIFICANT BIT */ + if (fg & 0x8) + { + /* FULL WHITE */ + fg = bg = 15; + } + else + { + /* FULL BLACK */ + fg = bg = 0; + } + } + } + else + { + uint8_t sat = f82c425->threshold & 0x10; + + /* DETERMINE WHICH IS LIGHT */ + if (fg > bg) + { + fg = f82c425_smartmap_add(fg, f82c425->shift & 0x0f, sat); + bg = f82c425_smartmap_add(bg, -(f82c425->shift >> 4), sat); + } + else + { + fg = f82c425_smartmap_add(fg, -(f82c425->shift & 0x0f), sat); + bg = f82c425_smartmap_add(bg, f82c425->shift >> 4, sat); + } + } + } + + smartmap[i][0] = f82c425_makecol(bg, f82c425->threshold & 0x20, f82c425->function & 0x80); + smartmap[i][1] = f82c425_makecol(fg, f82c425->threshold & 0x20, f82c425->function & 0x80); + } +} + +/* Calculate mapping of 320x200 graphical mode colors. */ +static void f82c425_colormap(f82c425_t *f82c425) +{ + int i; + + for (i = 0; i < 4; i++) + colormap[i] = f82c425_makecol(5 * i, 0, f82c425->function & 0x80); +} + +static void f82c425_out(uint16_t addr, uint8_t val, void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + + if (addr == 0x3d4) + f82c425->crtcreg = val; + + if (((f82c425->function & 0x01) == 0) && ((f82c425->crtcreg != 0xdf) || (addr != 0x3d5))) + return; + + if (addr != 0x3d5 || f82c425->crtcreg <= 31) + { + cga_out(addr, val, &f82c425->cga); + return; + } + + switch (f82c425->crtcreg) + { + case 0xd9: + f82c425->ac_limit = val; + break; + case 0xda: + f82c425->threshold = val; + f82c425_smartmap(f82c425); + break; + case 0xdb: + f82c425->shift = val; + f82c425_smartmap(f82c425); + break; + case 0xdc: + f82c425->hsync = val; + break; + case 0xdd: + f82c425->vsync_blink = val; + break; + case 0xde: + f82c425->timing = val; + break; + case 0xdf: + f82c425->function = val; + f82c425_smartmap(f82c425); + f82c425_colormap(f82c425); + break; + } +} + +static uint8_t f82c425_in(uint16_t addr, void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + + if ((f82c425->function & 0x01) == 0) + return 0xff; + + if (addr == 0x3d4) + return f82c425->crtcreg; + + if (addr != 0x3d5 || f82c425->crtcreg <= 31) + return cga_in(addr, &f82c425->cga); + + switch (f82c425->crtcreg) + { + case 0xd9: + return f82c425->ac_limit; + case 0xda: + return f82c425->threshold; + case 0xdb: + return f82c425->shift; + case 0xdc: + return f82c425->hsync; + case 0xdd: + return f82c425->vsync_blink; + case 0xde: + return f82c425->timing; + case 0xdf: + return f82c425->function; + } + + return 0xff; +} + +static void f82c425_write(uint32_t addr, uint8_t val, void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + + f82c425->vram[addr & 0x3fff] = val; + cycles -= 4; +} + +static uint8_t f82c425_read(uint32_t addr, void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + cycles -= 4; + + return f82c425->vram[addr & 0x3fff]; +} + +static void f82c425_recalctimings(f82c425_t *f82c425) +{ + double disptime; + double _dispontime, _dispofftime; + + if (f82c425->function & 0x08) + { + cga_recalctimings(&f82c425->cga); + return; + } + + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + f82c425->dispontime = (uint64_t)(_dispontime * xt_cpu_multi); + f82c425->dispofftime = (uint64_t)(_dispofftime * xt_cpu_multi); +} + +/* Draw a row of text. */ +static void f82c425_text_row(f82c425_t *f82c425) +{ + uint32_t colors[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + int blink; + uint16_t addr; + uint8_t sc; + uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + uint16_t ca = (f82c425->cga.crtc[0x0f] | (f82c425->cga.crtc[0x0e] << 8)) & 0x3fff; + uint8_t sl = f82c425->cga.crtc[9] + 1; + int columns = f82c425->cga.crtc[1]; + + sc = (f82c425->displine) & 7; + addr = ((ma & ~1) + (f82c425->displine >> 3) * columns) * 2; + ma += (f82c425->displine >> 3) * columns; + + if ((f82c425->cga.crtc[0x0a] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((f82c425->cga.crtc[0x0a] & 0x0F) <= sc) && + ((f82c425->cga.crtc[0x0b] & 0x0F) >= sc); + } + + for (x = 0; x < columns; x++) + { + chr = f82c425->vram[(addr + 2 * x) & 0x3FFF]; + attr = f82c425->vram[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && + (f82c425->cga.cgamode & 0x8) && (f82c425->cga.cgablink & 0x10)); + + blink = ((f82c425->cga.cgablink & 0x10) && (f82c425->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (drawcursor) + { + colors[0] = smartmap[~attr & 0xff][0]; + colors[1] = smartmap[~attr & 0xff][1]; + } + else + { + colors[0] = smartmap[attr][0]; + colors[1] = smartmap[attr][1]; + } + + if (blink) + colors[1] = colors[0]; + + if (f82c425->cga.cgamode & 0x01) + { + /* High resolution (80 cols) */ + for (c = 0; c < sl; c++) + { + ((uint32_t *)buffer32->line[f82c425->displine])[(x << 3) + c] = + colors[(fontdat[chr][sc] & (1 <<(c ^ 7))) ? 1 : 0]; + } + } + else + { + /* Low resolution (40 columns, stretch pixels horizontally) */ + for (c = 0; c < sl; c++) + { + ((uint32_t *)buffer32->line[f82c425->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[f82c425->displine])[(x << 4) + c*2+1] = + colors[(fontdat[chr][sc] & (1 <<(c ^ 7))) ? 1 : 0]; + } + } + + ++ma; + } +} + +/* Draw a line in CGA 640x200 mode */ +static void f82c425_cgaline6(f82c425_t *f82c425) +{ + int x, c; + uint8_t dat; + uint16_t addr; + + uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + + addr = ((f82c425->displine) & 1) * 0x2000 + + (f82c425->displine >> 1) * 80 + + ((ma & ~1) << 1); + + for (x = 0; x < 80; x++) + { + dat = f82c425->vram[addr & 0x3FFF]; + addr++; + + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[f82c425->displine])[x*8+c] = + colormap[dat & 0x80 ? 3 : 0]; + + dat = dat << 1; + } + } +} + +/* Draw a line in CGA 320x200 mode. */ +static void f82c425_cgaline4(f82c425_t *f82c425) +{ + int x, c; + uint8_t dat, pattern; + uint16_t addr; + + uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + addr = ((f82c425->displine) & 1) * 0x2000 + + (f82c425->displine >> 1) * 80 + + ((ma & ~1) << 1); + + for (x = 0; x < 80; x++) + { + dat = f82c425->vram[addr & 0x3FFF]; + addr++; + + for (c = 0; c < 4; c++) + { + pattern = (dat & 0xC0) >> 6; + if (!(f82c425->cga.cgamode & 0x08)) pattern = 0; + + ((uint32_t *)buffer32->line[f82c425->displine])[x*8+2*c] = + ((uint32_t *)buffer32->line[f82c425->displine])[x*8+2*c+1] = + colormap[pattern & 3]; + + dat = dat << 2; + } + } +} + +static void f82c425_poll(void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + + if (f82c425->video_options != st_video_options || + !!(f82c425->function & 1) != st_enabled) + { + f82c425->video_options = st_video_options; + f82c425->function &= ~1; + f82c425->function |= st_enabled ? 1 : 0; + + if (f82c425->function & 0x01) + mem_mapping_enable(&f82c425->mapping); + else + mem_mapping_disable(&f82c425->mapping); + } + /* Switch between internal LCD and external CRT display. */ + if (st_display_internal != -1 && st_display_internal != !!(f82c425->function & 0x08)) + { + if (st_display_internal) + { + f82c425->function &= ~0x08; + f82c425->timing &= ~0x20; + } + else + { + f82c425->function |= 0x08; + f82c425->timing |= 0x20; + } + f82c425_recalctimings(f82c425); + } + + if (f82c425->function & 0x08) + { + cga_poll(&f82c425->cga); + return; + } + + if (!f82c425->linepos) + { + timer_advance_u64(&f82c425->cga.timer, f82c425->dispofftime); + f82c425->cga.cgastat |= 1; + f82c425->linepos = 1; + if (f82c425->dispon) + { + if (f82c425->displine == 0) + { + video_wait_for_buffer(); + } + + switch (f82c425->cga.cgamode & 0x13) + { + case 0x12: + f82c425_cgaline6(f82c425); + break; + case 0x02: + f82c425_cgaline4(f82c425); + break; + case 0x00: + case 0x01: + f82c425_text_row(f82c425); + break; + } + } + f82c425->displine++; + + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (f82c425->displine >= 216) + { + /* End of VSYNC */ + f82c425->displine = 0; + f82c425->cga.cgastat &= ~8; + f82c425->dispon = 1; + } + else + if (f82c425->displine == (f82c425->cga.crtc[9] + 1) * f82c425->cga.crtc[6]) + { + /* Start of VSYNC */ + f82c425->cga.cgastat |= 8; + f82c425->dispon = 0; + } + } + else + { + if (f82c425->dispon) + f82c425->cga.cgastat &= ~1; + timer_advance_u64(&f82c425->cga.timer, f82c425->dispontime); + f82c425->linepos = 0; + + if (f82c425->displine == 200) + { + /* Hardcode 640x200 window size */ + if ((F82C425_XSIZE != xsize) || (F82C425_YSIZE != ysize) || video_force_resize_get()) + { + xsize = F82C425_XSIZE; + ysize = F82C425_YSIZE; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, 0, xsize, ysize); + frames++; + + /* Fixed 640x200 resolution */ + video_res_x = F82C425_XSIZE; + video_res_y = F82C425_YSIZE; + + switch (f82c425->cga.cgamode & 0x12) + { + case 0x12: + video_bpp = 1; + break; + case 0x02: + video_bpp = 2; + break; + default: + video_bpp = 0; + } + + f82c425->cga.cgablink++; + } + } +} + +static void *f82c425_init(const device_t *info) +{ + f82c425_t *f82c425 = malloc(sizeof(f82c425_t)); + memset(f82c425, 0, sizeof(f82c425_t)); + cga_init(&f82c425->cga); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_f82c425); + + /* Initialize registers that don't default to zero. */ + f82c425->hsync = 0x40; + f82c425->vsync_blink = 0x72; + + /* 16k video RAM */ + f82c425->vram = malloc(0x4000); + + timer_set_callback(&f82c425->cga.timer, f82c425_poll); + timer_set_p(&f82c425->cga.timer, f82c425); + + /* Occupy memory between 0xB8000 and 0xBFFFF */ + mem_mapping_add(&f82c425->mapping, 0xb8000, 0x8000, f82c425_read, NULL, NULL, f82c425_write, NULL, NULL, NULL, 0, f82c425); + /* Respond to CGA I/O ports */ + io_sethandler(0x03d0, 0x000c, f82c425_in, NULL, NULL, f82c425_out, NULL, NULL, f82c425); + + /* Initialize color maps for text & graphic modes */ + f82c425_smartmap(f82c425); + f82c425_colormap(f82c425); + + /* Start off in 80x25 text mode */ + f82c425->cga.cgastat = 0xF4; + f82c425->cga.vram = f82c425->vram; + f82c425->video_options = 0x01; + + return f82c425; +} + +static void f82c425_close(void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + + free(f82c425->vram); + free(f82c425); +} + +static void f82c425_speed_changed(void *p) +{ + f82c425_t *f82c425 = (f82c425_t *)p; + + f82c425_recalctimings(f82c425); +} + +const device_t f82c425_video_device = { + .name = "82C425 CGA LCD/CRT Controller", + .internal_name = "f82c425_video", + .flags = 0, + .local = 0, + .init = f82c425_init, + .close = f82c425_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = f82c425_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index befc61f71..c275eeb35 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -33,7 +33,7 @@ #include <86box/video.h> -#define BIOS_ROM_PATH L"roms/video/genius/8x12.bin" +#define BIOS_ROM_PATH "roms/video/genius/8x12.bin" #define GENIUS_XSIZE 728 @@ -46,9 +46,9 @@ static video_timings_t timing_genius = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; /* I'm at something of a disadvantage writing this emulation: I don't have an - * MDSI Genius card, nor do I have the BIOS extension (VHRBIOS.SYS) that came + * MDSI Genius card, nor do I have the BIOS extension (VHRBIOS.SYS) that came * with it. What I do have are the GEM and Windows 1.04 drivers, plus a driver - * for a later MCA version of the card. The latter can be found at + * for a later MCA version of the card. The latter can be found at * and is necessary if you * want the Windows driver to work. * @@ -57,9 +57,9 @@ static video_timings_t timing_genius = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; * The GEM driver SDGEN9.VGA * The Windows 1.04 driver GENIUS.DRV * - * As far as I can see, the card uses a fixed resolution of 728x1008 pixels. + * As far as I can see, the card uses a fixed resolution of 728x1008 pixels. * It has the following modes of operation: - * + * * > MDA-compatible: 80x25 text, each character 9x15 pixels. * > CGA-compatible: 640x200 mono graphics * > Dual: MDA text in the top half, CGA graphics in the bottom @@ -67,16 +67,16 @@ static video_timings_t timing_genius = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; * > Native graphics: 728x1008 mono graphics. * * Under the covers, this seems to translate to: - * > Text framebuffer. At B000:0000, 16k. Displayed if enable bit is set + * > Text framebuffer. At B000:0000, 16k. Displayed if enable bit is set * in the MDA control register. * > Graphics framebuffer. In native modes goes from A000:0000 to A000:FFFF - * and B800:0000 to B800:FFFF. In CGA-compatible + * and B800:0000 to B800:FFFF. In CGA-compatible * mode only the section at B800:0000 to B800:7FFF * is visible. Displayed if enable bit is set in the * CGA control register. - * + * * Two card-specific registers control text and graphics display: - * + * * 03B0: Control register. * Bit 0: Map all graphics framebuffer into memory. * Bit 2: Unknown. Set by GMC /M; cleared by mode set or GMC /T. @@ -88,14 +88,14 @@ static video_timings_t timing_genius = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; * Bit 4: Set to double character cell height (scanlines are doubled) * Bit 7: Unknown, seems to be set for all modes except 80x66 * - * Not having the card also means I don't have its font. According to the - * card brochure the font is an 8x12 bitmap in a 9x15 character cell. I - * therefore generated it by taking the MDA font, increasing graphics to + * Not having the card also means I don't have its font. According to the + * card brochure the font is an 8x12 bitmap in a 9x15 character cell. I + * therefore generated it by taking the MDA font, increasing graphics to * 16 pixels in height and reducing the height of characters so they fit * in an 8x12 cell if necessary. */ - + typedef struct genius_t { @@ -105,14 +105,14 @@ typedef struct genius_t int mda_crtcreg; /* Current CRTC register */ uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ int cga_crtcreg; /* Current CRTC register */ - uint8_t genius_control; /* Native control register - * I think bit 0 enables the full - * framebuffer. + uint8_t genius_control; /* Native control register + * I think bit 0 enables the full + * framebuffer. */ - uint8_t genius_charh; /* Native character height register: - * 00h => chars are 15 pixels high + uint8_t genius_charh; /* Native character height register: + * 00h => chars are 15 pixels high * 81h => chars are 14 pixels high - * 83h => chars are 12 pixels high + * 83h => chars are 12 pixels high * 90h => chars are 30 pixels high [15 x 2] * 93h => chars are 24 pixels high [12 x 2] */ @@ -130,7 +130,7 @@ typedef struct genius_t uint64_t dispontime, dispofftime; pc_timer_t timer; - + int linepos, displine; int vc; int dispon, blink; @@ -179,7 +179,7 @@ genius_out(uint16_t addr, uint8_t val, void *p) return; /* Emulated MDA control register */ - case 0x3b8: + case 0x3b8: genius->mda_ctrl = val; return; @@ -219,10 +219,10 @@ genius_in(uint16_t addr, void *p) case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: ret = genius->mda_crtc[genius->mda_crtcreg]; break; - case 0x3b8: + case 0x3b8: ret = genius->mda_ctrl; break; - case 0x3ba: + case 0x3ba: ret = genius->mda_stat; break; case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: @@ -253,7 +253,7 @@ genius_waitstates(void) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + cycles -= ws; } @@ -261,7 +261,6 @@ void genius_write(uint32_t addr, uint8_t val, void *p) { genius_t *genius = (genius_t *)p; - egawrites++; genius_waitstates(); if (genius->genius_control & 1) { @@ -288,7 +287,6 @@ genius_read(uint32_t addr, void *p) { genius_t *genius = (genius_t *)p; uint8_t ret; - egareads++; genius_waitstates(); if (genius->genius_control & 1) { @@ -390,15 +388,15 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) #if 0 if (genius->genius_charh & 0x10) { - row = ((dl >> 1) / charh); - sc = ((dl >> 1) % charh); + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); } else { - row = (dl / charh); - sc = (dl % charh); + row = (dl / charh); + sc = (dl % charh); } #else - row = (dl / charh); - sc = (dl % charh); + row = (dl / charh); + sc = (dl % charh); #endif } else { if ((genius->displine < 512) || (genius->displine >= 912)) @@ -413,8 +411,8 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) cw = 8; charh = crtc[9] + 1; - row = ((dl >> 1) / charh); - sc = ((dl >> 1) % charh); + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); } ma = (crtc[13] | (crtc[12] << 8)) & 0x3fff; @@ -509,7 +507,7 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) buffer32->line[dl][((x * cw) << 1) + 17] = col; } } - } else { /* Otherwise fill with background */ + } else { /* Otherwise fill with background */ col = mdaattr[attr][blink][0]; if (genius->genius_control & 0x20) col ^= 15; @@ -691,7 +689,7 @@ genius_poll(void *p) video_force_resize_set(0); } - video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + video_blit_memtoscreen_8(0, 0, xsize, ysize); frames++; /* Fixed 728x1008 resolution */ @@ -735,7 +733,7 @@ void genius_pal[3] = 15 + 16; /* F */ /* MDA attributes */ - /* I don't know if the Genius's MDA emulation actually does + /* I don't know if the Genius's MDA emulation actually does * emulate bright / non-bright. For the time being pretend it does. */ for (c = 0; c < 256; c++) { mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = genius_pal[0]; @@ -790,14 +788,16 @@ genius_speed_changed(void *p) genius_recalctimings(genius); } - -const device_t genius_device = -{ - "Genius VHR", - DEVICE_ISA, 0, - genius_init, genius_close, NULL, - genius_available, - genius_speed_changed, - NULL, - NULL +const device_t genius_device = { + .name = "Genius VHR", + .internal_name = "genius", + .flags = DEVICE_ISA, + .local = 0, + .init = genius_init, + .close = genius_close, + .reset = NULL, + { .available = genius_available }, + .speed_changed = genius_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 5a836109f..8e1ab4f8b 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -31,43 +31,9 @@ #include <86box/pit.h> #include <86box/device.h> #include <86box/video.h> +#include <86box/vid_hercules.h> -typedef struct { - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; - - uint8_t ctrl, - ctrl2, - stat; - - uint64_t dispontime, - dispofftime; - pc_timer_t timer; - - int firstline, - lastline; - - int linepos, - displine; - int vc, - sc; - uint16_t ma, - maback; - int con, coff, - cursoron; - int dispon, - blink; - int vsynctime; - int vadj; - - int cols[256][2][2]; - - uint8_t *vram; -} hercules_t; - static video_timings_t timing_hercules = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; @@ -88,7 +54,7 @@ recalc_timings(hercules_t *dev) } -static uint8_t crtcmask[32] = +static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -100,6 +66,7 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) hercules_t *dev = (hercules_t *)priv; uint8_t old; + VIDEO_MONITOR_PROLOGUE() switch (addr) { case 0x03b0: case 0x03b2: @@ -123,41 +90,65 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) dev->crtc[10] = 0xb; dev->crtc[11] = 0xc; } -#if 0 - if (old ^ val) - recalc_timings(dev); -#else + if (old != val) { if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) { - fullchange = changeframecount; + dev->fullchange = changeframecount; recalc_timings(dev); } } -#endif break; case 0x03b8: old = dev->ctrl; - if (!(dev->ctrl2 & 0x01) && !(val & 0x02)) - val = (val & 0xfd) | (dev->ctrl & 0x02); - if (!(dev->ctrl2 & 0x02) && !(val & 0x80)) - val = (val & 0x7f) | (dev->ctrl & 0x80); - dev->ctrl = val; + + /* Prevent setting of bits if they are disabled in CTRL2. */ + if ((old & 0x02) && !(val & 0x02)) + dev->ctrl &= 0xfd; + else if ((val & 0x02) && (dev->ctrl2 & 0x01)) + dev->ctrl |= 0x02; + + if ((old & 0x80) && !(val & 0x80)) + dev->ctrl &= 0x7f; + else if ((val & 0x80) && (dev->ctrl2 & 0x02)) + dev->ctrl |= 0x80; + + dev->ctrl = (dev->ctrl & 0x82) | (val & 0x7d); + if (old ^ val) recalc_timings(dev); break; + case 0x03b9: + case 0x03bb: + dev->lp_ff = !(addr & 0x0002); + break; + case 0x03bf: + old = dev->ctrl2; dev->ctrl2 = val; + /* According to the Programmer's guide to the Hercules graphics cars + by David B. Doty from 1988, the CTRL2 modes (bits 1,0) are as follow: + - 00: DIAG: Text mode only, only page 0 accessible; + - 01: HALF: Graphics mode allowed, only page 0 accessible; + - 11: FULL: Graphics mode allowed, both pages accessible. */ + if (val & 0x01) + mem_mapping_set_exec(&dev->mapping, dev->vram); + else + mem_mapping_set_exec(&dev->mapping, NULL); if (val & 0x02) mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000); else mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000); + if (old ^ val) + recalc_timings(dev); break; default: break; } + + VIDEO_MONITOR_EPILOGUE() } @@ -179,20 +170,20 @@ hercules_in(uint16_t addr, void *priv) case 0x03b3: case 0x03b5: case 0x03b7: - ret = dev->crtc[dev->crtcreg]; + if (dev->crtcreg == 0x0c) + ret = (dev->ma >> 8) & 0x3f; + else if (dev->crtcreg == 0x0d) + ret = dev->ma & 0xff; + else + ret = dev->crtc[dev->crtcreg]; break; case 0x03ba: - ret = 0x72; /* Hercules ident */ -#if 0 - if (dev->stat & 0x08) - ret |= 0x88; -#else + ret = 0x70; /* Hercules ident */ + ret |= (dev->lp_ff ? 2 : 0); + ret |= (dev->stat & 0x01); if (dev->stat & 0x08) ret |= 0x80; -#endif - if ((dev->stat & 0x09) == 0x01) - ret |= (dev->stat & 0x01); if ((ret & 0x81) == 0x80) ret |= 0x08; break; @@ -212,7 +203,7 @@ hercules_waitstates(void *p) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + cycles -= ws; } @@ -222,9 +213,11 @@ hercules_write(uint32_t addr, uint8_t val, void *priv) hercules_t *dev = (hercules_t *)priv; if (dev->ctrl2 & 0x01) - dev->vram[addr & 0xffff] = val; + addr &= 0xffff; else - dev->vram[addr & 0x0fff] = val; + addr &= 0x0fff; + + dev->vram[addr] = val; hercules_waitstates(dev); } @@ -234,13 +227,62 @@ static uint8_t hercules_read(uint32_t addr, void *priv) { hercules_t *dev = (hercules_t *)priv; + uint8_t ret = 0xff; if (dev->ctrl2 & 0x01) - return(dev->vram[addr & 0xffff]); + addr &= 0xffff; else - return(dev->vram[addr & 0x0fff]); + addr &= 0x0fff; hercules_waitstates(dev); + + ret = dev->vram[addr]; + + return ret; +} + + +static void +hercules_render_overscan_left(hercules_t *dev) +{ + int i; + uint32_t width; + + if (dev->ctrl & 0x02) + width = (((uint32_t) dev->crtc[1]) << 4); + else + width = (((uint32_t) dev->crtc[1]) * 9); + + if ((dev->displine + 14) < 0) + return; + + if (width == 0) + return; + + for (i = 0; i < 8; i++) + buffer32->line[dev->displine + 14][i] = 0x00000000; +} + + +static void +hercules_render_overscan_right(hercules_t *dev) +{ + int i; + uint32_t width; + + if (dev->ctrl & 0x02) + width = (((uint32_t) dev->crtc[1]) << 4); + else + width = (((uint32_t) dev->crtc[1]) * 9); + + if ((dev->displine + 14) < 0) + return; + + if (width == 0) + return; + + for (i = 0; i < 8; i++) + buffer32->line[dev->displine + 14][8 + width + i] = 0x00000000; } @@ -250,10 +292,13 @@ hercules_poll(void *priv) hercules_t *dev = (hercules_t *)priv; uint8_t chr, attr; uint16_t ca, dat; + uint16_t pa; int oldsc, blink; - int x, c, oldvc; + int x, xx, y, yy, c, oldvc; int drawcursor; + uint32_t *p; + VIDEO_MONITOR_PROLOGUE() ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; if (! dev->linepos) { @@ -262,40 +307,41 @@ hercules_poll(void *priv) dev->linepos = 1; oldsc = dev->sc; - if ((dev->crtc[8] & 3) == 3) + if ((dev->crtc[8] & 3) == 3) dev->sc = (dev->sc << 1) & 7; if (dev->dispon) { if (dev->displine < dev->firstline) { - dev->firstline = dev->displine; - video_wait_for_buffer(); + dev->firstline = dev->displine; + video_wait_for_buffer(); } dev->lastline = dev->displine; - // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { - if (dev->ctrl & 2) { + hercules_render_overscan_left(dev); + + if (dev->ctrl & 0x02) { ca = (dev->sc & 3) * 0x2000; - // if ((dev->ctrl & 0x80) && (dev->ctrl2 & 2)) if (dev->ctrl & 0x80) ca += 0x8000; for (x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) - // dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; else dat = 0; dev->ma++; for (c = 0; c < 16; c++) - buffer32->line[dev->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; + buffer32->line[dev->displine + 14][(x << 4) + c + 8] = (dat & (32768 >> c)) ? 7 : 0; for (c = 0; c < 16; c += 8) - video_blend((x << 4) + c, dev->displine); + video_blend((x << 4) + c + 8, dev->displine + 14); } } else { for (x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) { - chr = dev->vram[(dev->ma << 1) & 0xfff]; - attr = dev->vram[((dev->ma << 1) + 1) & 0xfff]; + /* Undocumented behavior: page 1 in text mode means characters are read + from page 1 and attributes from page 0. */ + chr = dev->charbuffer[x << 1]; + attr = dev->charbuffer[(x << 1) + 1]; } else chr = attr = 0; drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); @@ -303,35 +349,43 @@ hercules_poll(void *priv) if (dev->sc == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) - buffer32->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][1]; + buffer32->line[dev->displine + 14][(x * 9) + c + 8] = dev->cols[attr][blink][1]; } else { for (c = 0; c < 8; c++) - buffer32->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][(fontdatm[chr][dev->sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[dev->displine + 14][(x * 9) + c + 8] = dev->cols[attr][blink][(fontdatm[chr][dev->sc] & (1 << (c ^ 7))) ? 1 : 0]; if ((chr & ~0x1f) == 0xc0) - buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][fontdatm[chr][dev->sc] & 1]; + buffer32->line[dev->displine + 14][(x * 9) + 8 + 8] = dev->cols[attr][blink][fontdatm[chr][dev->sc] & 1]; else - buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][0]; + buffer32->line[dev->displine + 14][(x * 9) + 8 + 8] = dev->cols[attr][blink][0]; } - dev->ma++; + if (dev->ctrl2 & 0x01) + dev->ma = (dev->ma + 1) & 0x3fff; + else + dev->ma = (dev->ma + 1) & 0x7ff; if (drawcursor) { for (c = 0; c < 9; c++) - buffer32->line[dev->displine][(x * 9) + c] ^= dev->cols[attr][0][1]; + buffer32->line[dev->displine + 14][(x * 9) + c + 8] ^= dev->cols[attr][0][1]; } } } + + hercules_render_overscan_right(dev); } dev->sc = oldsc; if (dev->vc == dev->crtc[7] && !dev->sc) dev->stat |= 8; dev->displine++; - if (dev->displine >= 500) + if (dev->displine >= 500) dev->displine = 0; } else { timer_advance_u64(&dev->timer, dev->dispontime); + if (dev->dispon) + dev->stat &= ~1; + dev->linepos = 0; if (dev->vsynctime) { dev->vsynctime--; @@ -341,70 +395,102 @@ hercules_poll(void *priv) if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3)==3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; - dev->coff = 1; + dev->con = 0; + dev->coff = 1; } if (dev->vadj) { dev->sc++; dev->sc &= 31; dev->ma = dev->maback; - dev->vadj--; if (! dev->vadj) { dev->dispon = 1; dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; dev->sc = 0; } - } else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { + } else if (((dev->crtc[8] & 3) != 3 && dev->sc == dev->crtc[9]) || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { dev->maback = dev->ma; dev->sc = 0; oldvc = dev->vc; dev->vc++; dev->vc &= 127; - if (dev->vc == dev->crtc[6]) + + if (dev->vc == dev->crtc[6]) dev->dispon = 0; if (oldvc == dev->crtc[4]) { dev->vc = 0; dev->vadj = dev->crtc[5]; - if (! dev->vadj) + if (! dev->vadj) { dev->dispon = 1; - if (! dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - if ((dev->crtc[10] & 0x60) == 0x20) - dev->cursoron = 0; - else - dev->cursoron = dev->blink & 16; + } + switch (dev->crtc[10] & 0x60) { + case 0x20: + dev->cursoron = 0; + break; + case 0x60: + dev->cursoron = dev->blink & 0x10; + break; + default: + dev->cursoron = dev->blink & 0x08; + break; + } } if (dev->vc == dev->crtc[7]) { dev->dispon = 0; dev->displine = 0; - dev->vsynctime = 16;//(crtcm[3]>>4)+1; + if ((dev->crtc[8] & 3) == 3) + dev->vsynctime = ((int32_t)dev->crtc[4] * ((dev->crtc[9] >> 1) + 1)) + dev->crtc[5] - dev->crtc[7] + 1; + else + dev->vsynctime = ((int32_t)dev->crtc[4] * (dev->crtc[9] + 1)) + dev->crtc[5] - dev->crtc[7] + 1; if (dev->crtc[7]) { - // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) - if (dev->ctrl & 2) + if (dev->ctrl & 0x02) x = dev->crtc[1] << 4; else x = dev->crtc[1] * 9; dev->lastline++; - if ((dev->ctrl & 8) && x && (dev->lastline - dev->firstline) && - ((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get())) { + y = (dev->lastline - dev->firstline); + + if ((dev->ctrl & 8) && x && y && ((x != xsize) || (y != ysize) || video_force_resize_get())) { xsize = x; - ysize = dev->lastline - dev->firstline; - if (xsize < 64) xsize = 656; + ysize = y; + if (xsize < 64) xsize = enable_overscan ? 640 : 656; if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); + + set_screen_size(xsize + (enable_overscan ? 16 : 0), ysize + (enable_overscan ? 28 : 0)); if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen_8(0, dev->firstline, 0, ysize, xsize, ysize); + if ((x >= 160) && ((y + 1) >= 120)) { + /* Draw (overscan_size) lines of overscan on top and bottom. */ + for (yy = 0; yy < 14; yy++) { + p = &(buffer32->line[(dev->firstline + yy) & 0x7ff][0]); + + for (xx = 0; xx < (x + 16); xx++) + p[xx] = 0x00000000; + } + + for (yy = 0; yy < 14; yy++) { + p = &(buffer32->line[(dev->firstline + 14 + y + yy) & 0x7ff][0]); + + for (xx = 0; xx < (x + 16); xx++) + p[xx] = 0x00000000; + } + } + + if (enable_overscan) + video_blit_memtoscreen_8(0, dev->firstline, xsize + 16, ysize + 28); + else + video_blit_memtoscreen_8(8, dev->firstline + 14, xsize, ysize); frames++; - if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { + // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { + if (dev->ctrl & 0x02) { video_res_x = dev->crtc[1] * 16; video_res_y = dev->crtc[6] * 4; video_bpp = 1; @@ -424,13 +510,17 @@ hercules_poll(void *priv) dev->ma = dev->maback; } - if (dev->dispon) - dev->stat &= ~1; - if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3)==3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) dev->con = 1; + if (dev->dispon && !(dev->ctrl & 0x02)) { + for (x = 0; x < (dev->crtc[1] << 1); x++) { + pa = (dev->ctrl & 0x80) ? ((x & 1) ? 0x0000 : 0x8000) : 0x0000; + dev->charbuffer[x] = dev->vram[(((dev->ma << 1) + x) & 0x3fff) + pa]; + } + } } + VIDEO_MONITOR_EPILOGUE() } @@ -442,14 +532,18 @@ hercules_init(const device_t *info) dev = (hercules_t *)malloc(sizeof(hercules_t)); memset(dev, 0x00, sizeof(hercules_t)); + dev->monitor_index = monitor_index_global; + + overscan_x = 16; + overscan_y = 28; dev->vram = (uint8_t *)malloc(0x10000); timer_add(&dev->timer, hercules_poll, dev, 1); - mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, + mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, hercules_read,NULL,NULL, hercules_write,NULL,NULL, - dev->vram, MEM_MAPPING_EXTERNAL, dev); + NULL /*dev->vram*/, MEM_MAPPING_EXTERNAL, dev); io_sethandler(0x03b0, 16, hercules_in,NULL,NULL, hercules_out,NULL,NULL, dev); @@ -516,47 +610,61 @@ static void speed_changed(void *priv) { hercules_t *dev = (hercules_t *)priv; - + recalc_timings(dev); } - static const device_config_t hercules_config[] = { +// clang-format off { - "rgb_type", "Display type", CONFIG_SELECTION, "", 0, - { - { - "Default", 0 - }, - { - "Green", 1 - }, - { - "Amber", 2 - }, - { - "Gray", 3 - }, - { - "" - } - } + .name = "rgb_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "Default", + .value = 0 + }, + { + .description = "Green", + .value = 1 + }, + { + .description = "Amber", + .value = 2 + }, + { + .description = "Gray", + .value = 3 + }, + { + .description = "" + } + } }, { - "blend", "Blend", CONFIG_BINARY, "", 1 + .name = "blend", + .description = "Blend", + .type = CONFIG_BINARY, + .default_int = 1 }, { - "", "", -1 + .type = CONFIG_END } +// clang-format on }; const device_t hercules_device = { - "Hercules", - DEVICE_ISA, - 0, - hercules_init, hercules_close, NULL, - NULL, - speed_changed, - NULL, - hercules_config + .name = "Hercules", + .internal_name = "hercules", + .flags = DEVICE_ISA, + .local = 0, + .init = hercules_init, + .close = hercules_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = speed_changed, + .force_redraw = NULL, + .config = hercules_config }; diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index 14c229d47..b4a514422 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -80,14 +80,18 @@ typedef struct { uint16_t ma, maback; int con, coff, cursoron; int dispon, blink; - int vsynctime; + int vsynctime; int vadj; + int monitor_index, prev_monitor_index; int cols[256][2][2]; uint8_t *vram; } herculesplus_t; +#define VIDEO_MONITOR_PROLOGUE() { dev->prev_monitor_index = monitor_index_global; monitor_index_global = dev->monitor_index; } +#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = dev->prev_monitor_index; } + static video_timings_t timing_herculesplus = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; @@ -180,7 +184,7 @@ herculesplus_in(uint16_t port, void *priv) break; case 0x3ba: - /* 0x50: InColor card identity */ + /* 0x10: Hercules Plus card identity */ ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x10; break; } @@ -217,7 +221,7 @@ draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) blk = 0; if (dev->ctrl & HERCULESPLUS_CTRL_BLINK) { - if (attr & 0x80) + if (attr & 0x80) blk = (dev->blink & 16); attr &= 0x7f; } @@ -228,18 +232,18 @@ draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) if ((attr & 0x77) == 0x70) { /* Invert */ ifg = 0; ibg = 7; - } - if (attr & 8) + } + if (attr & 8) ifg |= 8; /* High intensity FG */ - if (attr & 0x80) + if (attr & 0x80) ibg |= 8; /* High intensity BG */ if ((attr & 0x77) == 0) /* Blank */ ifg = ibg; ull = ((attr & 0x07) == 1) ? 13 : 0xffff; - if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) elg = 0; - else + else elg = ((chr >= 0xc0) && (chr <= 0xdf)); fnt = &(fontdatm[chr][dev->sc]); @@ -250,8 +254,8 @@ draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) val = 0x1ff; /* Underscore, draw all foreground */ } else { val = fnt[0] << 1; - - if (elg) + + if (elg) val |= (val >> 1) & 1; } @@ -265,7 +269,7 @@ draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) static void draw_char_ram4(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) { - unsigned ull, val, ifg, ibg, cfg; + unsigned ull, val, ibg, cfg; const uint8_t *fnt; int i, elg, blk; int cw = HERCULESPLUS_CW; @@ -273,41 +277,37 @@ draw_char_ram4(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) blk = 0; if (blink) { - if (attr & 0x80) + if (attr & 0x80) blk = (dev->blink & 16); attr &= 0x7f; } /* MDA-compatible attributes */ ibg = 0; - ifg = 7; if ((attr & 0x77) == 0x70) { /* Invert */ - ifg = 0; ibg = 7; - } - if (attr & 8) - ifg |= 8; /* High intensity FG */ - if (attr & 0x80) + } + if (attr & 8) + if (attr & 0x80) ibg |= 8; /* High intensity BG */ if ((attr & 0x77) == 0) /* Blank */ - ifg = ibg; ull = ((attr & 0x07) == 1) ? 13 : 0xffff; - if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) elg = 0; - else + else elg = ((chr >= 0xc0) && (chr <= 0xdf)); fnt = dev->vram + 0x4000 + 16 * chr + dev->sc; if (blk) { /* Blinking, draw all background */ - val = 0x000; + val = 0x000; } else if (dev->sc == ull) { /* Underscore, draw all foreground */ val = 0x1ff; } else { val = fnt[0x00000] << 1; - - if (elg) + + if (elg) val |= (val >> 1) & 1; } @@ -340,7 +340,7 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) blk = 0; if (blink) { - if (attr & 0x40) + if (attr & 0x40) blk = (dev->blink & 16); attr &= 0x7f; } @@ -358,7 +358,7 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) ul = (attr & 0x10) ? 1 : 0; } - if (ul) { + if (ul) { ull = dev->crtc[HERCULESPLUS_CRTC_UNDER] & 0x0F; ulc = (dev->crtc[HERCULESPLUS_CRTC_UNDER] >> 4) & 0x0F; if (ulc == 0) ulc = 7; @@ -366,7 +366,7 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) ull = 0xFFFF; } - if (ol) { + if (ol) { oll = dev->crtc[HERCULESPLUS_CRTC_OVER] & 0x0F; olc = (dev->crtc[HERCULESPLUS_CRTC_OVER] >> 4) & 0x0F; if (olc == 0) olc = 7; @@ -374,23 +374,23 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) oll = 0xFFFF; } - if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) elg = 0; - else + else elg = ((chr >= 0xc0) && (chr <= 0xdf)); fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->sc; if (blk) { /* Blinking, draw all background */ - val = 0x000; + val = 0x000; } else if (dev->sc == ull) { /* Underscore, draw all foreground */ val = 0x1ff; } else { val = fnt[0x00000] << 1; - - if (elg) + + if (elg) val |= (val >> 1) & 1; - if (bld) + if (bld) val |= (val >> 1); } @@ -403,7 +403,7 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) cfg = ulc ^ ibg; /* Underline */ else cfg |= ibg; - + buffer32->line[dev->displine][(x * cw) + i] = dev->cols[attr][blink][cfg]; val = val << 1; } @@ -475,9 +475,9 @@ graphics_line(herculesplus_t *dev) dev->ma++; for (c = 0; c < 16; c++) { - val >>= 1; + buffer32->line[dev->displine][(x << 4) + c] = (val & 0x8000) ? 7 : 0; - buffer32->line[dev->displine][(x << 4) + c] = (val & 1) ? 7 : 0; + val <<= 1; } for (c = 0; c < 16; c += 8) @@ -493,12 +493,13 @@ herculesplus_poll(void *priv) uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; int x, oldvc, oldsc; + VIDEO_MONITOR_PROLOGUE(); if (! dev->linepos) { timer_advance_u64(&dev->timer, dev->dispofftime); dev->stat |= 1; dev->linepos = 1; oldsc = dev->sc; - if ((dev->crtc[8] & 3) == 3) + if ((dev->crtc[8] & 3) == 3) dev->sc = (dev->sc << 1) & 7; if (dev->dispon) { if (dev->displine < dev->firstline) { @@ -515,11 +516,11 @@ herculesplus_poll(void *priv) if (dev->vc == dev->crtc[7] && !dev->sc) dev->stat |= 8; dev->displine++; - if (dev->displine >= 500) + if (dev->displine >= 500) dev->displine = 0; } else { timer_advance_u64(&dev->timer, dev->dispontime); - if (dev->dispon) + if (dev->dispon) dev->stat &= ~1; dev->linepos = 0; if (dev->vsynctime) { @@ -528,9 +529,9 @@ herculesplus_poll(void *priv) dev->stat &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; - dev->coff = 1; + if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { + dev->con = 0; + dev->coff = 1; } if (dev->vadj) { dev->sc++; @@ -548,7 +549,7 @@ herculesplus_poll(void *priv) oldvc = dev->vc; dev->vc++; dev->vc &= 127; - if (dev->vc == dev->crtc[6]) + if (dev->vc == dev->crtc[6]) dev->dispon = 0; if (oldvc == dev->crtc[4]) { dev->vc = 0; @@ -565,7 +566,7 @@ herculesplus_poll(void *priv) dev->displine = 0; dev->vsynctime = 16; if (dev->crtc[7]) { - if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) x = dev->crtc[1] << 4; else x = dev->crtc[1] * 9; @@ -581,7 +582,7 @@ herculesplus_poll(void *priv) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen_8(0, dev->firstline, 0, dev->lastline - dev->firstline, xsize, dev->lastline - dev->firstline); + video_blit_memtoscreen_8(0, dev->firstline, xsize, dev->lastline - dev->firstline); frames++; if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) { video_res_x = dev->crtc[1] * 16; @@ -606,6 +607,8 @@ herculesplus_poll(void *priv) if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) dev->con = 1; } + + VIDEO_MONITOR_EPILOGUE(); } @@ -619,10 +622,11 @@ herculesplus_init(const device_t *info) memset(dev, 0, sizeof(herculesplus_t)); dev->vram = (uint8_t *)malloc(0x10000); /* 64k VRAM */ + dev->monitor_index = monitor_index_global; timer_add(&dev->timer, herculesplus_poll, dev, 1); - mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, + mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, herculesplus_read,NULL,NULL, herculesplus_write,NULL,NULL, dev->vram, MEM_MAPPING_EXTERNAL, dev); @@ -693,43 +697,57 @@ speed_changed(void *priv) recalc_timings(dev); } - static const device_config_t herculesplus_config[] = { +// clang-format off { - "rgb_type", "Display type", CONFIG_SELECTION, "", 0, - { - { - "Default", 0 - }, - { - "Green", 1 - }, - { - "Amber", 2 - }, - { - "Gray", 3 - }, - { - "" - } - } + .name = "rgb_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "Default", + .value = 0 + }, + { + .description = "Green", + .value = 1 + }, + { + .description = "Amber", + .value = 2 + }, + { + .description = "Gray", + .value = 3 + }, + { + .description = "" + } + } }, { - "blend", "Blend", CONFIG_BINARY, "", 1 + .name = "blend", + .description = "Blend", + .type = CONFIG_BINARY, + .default_int = 1 }, { - "", "", -1 + .type = CONFIG_END } +// clang-format on }; const device_t herculesplus_device = { - "Hercules Plus", - DEVICE_ISA, - 0, - herculesplus_init, herculesplus_close, NULL, - NULL, - speed_changed, - NULL, - herculesplus_config + .name = "Hercules Plus", + .internal_name = "hercules_plus", + .flags = DEVICE_ISA, + .local = 0, + .init = herculesplus_init, + .close = herculesplus_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = speed_changed, + .force_redraw = NULL, + .config = herculesplus_config }; diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 5f271e0ea..8ef6fc9e0 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -24,6 +24,7 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/io.h> +#include <86box/mca.h> #include <86box/mem.h> #include <86box/timer.h> #include <86box/pic.h> @@ -42,29 +43,36 @@ typedef struct ht216_t rom_t bios_rom; - uint32_t vram_mask; + uint32_t vram_mask, linear_base; + uint8_t adjust_cursor, monitor_type; int ext_reg_enable; - int clk_sel; - + int isabus; + int mca; + uint8_t read_bank_reg[2], write_bank_reg[2]; - uint32_t read_bank[2], write_bank[2]; - uint8_t misc, pad; - uint16_t id; - + uint16_t id, misc; + uint32_t read_banks[2], write_banks[2]; + uint8_t bg_latch[8]; - + uint8_t fg_latch[4]; + uint8_t bg_plane_sel, fg_plane_sel; + uint8_t ht_regs[256]; + uint8_t extensions, reg_3cb; + + uint8_t pos_regs[8]; } ht216_t; #define HT_MISC_PAGE_SEL (1 << 5) -/*Shifts CPU VRAM read address by 3 bits, for use with fat pixel colour expansion*/ +/*Shifts CPU VRAM read address by 3 bits, for use with fat pixel color expansion*/ #define HT_REG_C8_MOVSB (1 << 0) #define HT_REG_C8_E256 (1 << 4) #define HT_REG_C8_XLAM (1 << 6) +#define HT_REG_CD_P8PCEXP (1 << 0) #define HT_REG_CD_FP8PCEXP (1 << 1) #define HT_REG_CD_BMSKSL (3 << 2) #define HT_REG_CD_RMWMDE (1 << 5) @@ -90,11 +98,14 @@ void ht216_out(uint16_t addr, uint8_t val, void *p); uint8_t ht216_in(uint16_t addr, void *p); -#define BIOS_G2_GC205_PATH L"roms/video/video7/BIOS.BIN" -#define BIOS_VIDEO7_VGA_1024I_PATH L"roms/video/video7/Video Seven VGA 1024i - BIOS - v2.19 - 435-0062-05 - U17 - 27C256.BIN" +#define BIOS_G2_GC205_PATH "roms/video/video7/BIOS.BIN" +#define BIOS_VIDEO7_VGA_1024I_PATH "roms/video/video7/Video Seven VGA 1024i - BIOS - v2.19 - 435-0062-05 - U17 - 27C256.BIN" +#define BIOS_RADIUS_SVGA_MULTIVIEW_PATH "roms/video/video7/U18.BIN" +#define BIOS_HT216_32_PATH "roms/video/video7/HT21632.BIN" static video_timings_t timing_v7vga_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; -static video_timings_t timing_v7vga_vlb = {VIDEO_ISA, 5, 5, 9, 20, 20, 30}; +static video_timings_t timing_v7vga_mca = {VIDEO_MCA, 4, 5, 10, 5, 5, 10}; +static video_timings_t timing_v7vga_vlb = {VIDEO_BUS, 5, 5, 9, 20, 20, 30}; #ifdef ENABLE_HT216_LOG @@ -116,6 +127,47 @@ ht216_log(const char *fmt, ...) #define ht216_log(fmt, ...) #endif +/*Remap address for chain-4/doubleword style layout*/ +static __inline uint32_t +dword_remap(svga_t *svga, uint32_t in_addr) +{ + if (svga->packed_chain4) + return in_addr; + return ((in_addr & 0xfffc) << 2) | ((in_addr & 0x30000) >> 14) | (in_addr & ~0x3ffff); +} + +static void +ht216_recalc_bank_regs(ht216_t *ht216, int mode) +{ + svga_t *svga = &ht216->svga; + + if (mode) { + ht216->read_bank_reg[0] = ht216->ht_regs[0xe8]; + ht216->write_bank_reg[0] = ht216->ht_regs[0xe8]; + ht216->read_bank_reg[1] = ht216->ht_regs[0xe9]; + ht216->write_bank_reg[1] = ht216->ht_regs[0xe9]; + } else { + ht216->read_bank_reg[0] = ((ht216->ht_regs[0xf6] & 0xc) << 4); + ht216->read_bank_reg[1] = ((ht216->ht_regs[0xf6] & 0xc) << 4); + ht216->write_bank_reg[0] = ((ht216->ht_regs[0xf6] & 0x3) << 6); + ht216->write_bank_reg[1] = ((ht216->ht_regs[0xf6] & 0x3) << 6); + + if (svga->packed_chain4 || (ht216->ht_regs[0xfc] & HT_REG_FC_ECOLRE)) { + ht216->read_bank_reg[0] |= (ht216->misc & 0x20); + ht216->read_bank_reg[1] |= (ht216->misc & 0x20); + ht216->write_bank_reg[0] |= (ht216->misc & 0x20); + ht216->write_bank_reg[1] |= (ht216->misc & 0x20); + } + + if (svga->packed_chain4 || ((ht216->ht_regs[0xfc] & 0x06) == 0x04)) { + ht216->read_bank_reg[0] |= ((ht216->ht_regs[0xf9] & 1) << 4); + ht216->read_bank_reg[1] |= ((ht216->ht_regs[0xf9] & 1) << 4); + ht216->write_bank_reg[0] |= ((ht216->ht_regs[0xf9] & 1) << 4); + ht216->write_bank_reg[1] |= ((ht216->ht_regs[0xf9] & 1) << 4); + } + } +} + void ht216_out(uint16_t addr, uint8_t val, void *p) @@ -125,22 +177,28 @@ ht216_out(uint16_t addr, uint8_t val, void *p) uint8_t old; ht216_log("ht216 %i out %04X %02X %04X:%04X\n", svga->miscout & 1, addr, val, CS, cpu_state.pc); - + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { case 0x3c2: - ht216->clk_sel = (ht216->clk_sel & ~3) | ((val & 0x0c) >> 2); + /*Bit 17 of the display memory address, only active on odd/even modes, has no effect on graphics modes.*/ ht216->misc = val; - ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0x20) | ((val & HT_MISC_PAGE_SEL) ? 0x20 : 0); - ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0x20) | ((val & HT_MISC_PAGE_SEL) ? 0x20 : 0); + svga->miscout = val; + ht216_log("HT216 misc val = %02x, mode = 0, chain4 = %x\n", val, svga->chain4); + ht216_recalc_bank_regs(ht216, 0); ht216_remap(ht216); - svga_recalctimings(&ht216->svga); + svga_recalctimings(svga); + break; + + case 0x3c4: + svga->seqaddr = val; break; case 0x3c5: if (svga->seqaddr == 4) { + svga->chain2_write = !(val & 4); svga->chain4 = val & 8; ht216_remap(ht216); } else if (svga->seqaddr == 6) { @@ -148,17 +206,69 @@ ht216_out(uint16_t addr, uint8_t val, void *p) ht216->ext_reg_enable = 1; else if (val == 0xae) ht216->ext_reg_enable = 0; +#ifdef ENABLE_HT216_LOG + /* Functionality to output to the console a dump of all registers for debugging purposes. */ + } else if (svga->seqaddr == 0x7f) { + ht216_log(" 8 | 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); + ht216_log("----+-------------------------------------------------\n"); + ht216_log(" 8 | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0x80], ht216->ht_regs[0x81], ht216->ht_regs[0x82], ht216->ht_regs[0x83], + ht216->ht_regs[0x84], ht216->ht_regs[0x85], ht216->ht_regs[0x86], ht216->ht_regs[0x87], + ht216->ht_regs[0x88], ht216->ht_regs[0x89], ht216->ht_regs[0x8a], ht216->ht_regs[0x8b], + ht216->ht_regs[0x8c], ht216->ht_regs[0x8d], ht216->ht_regs[0x8e], ht216->ht_regs[0x8f]); + ht216_log(" 9 | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0x90], ht216->ht_regs[0x91], ht216->ht_regs[0x92], ht216->ht_regs[0x93], + ht216->ht_regs[0x94], ht216->ht_regs[0x95], ht216->ht_regs[0x96], ht216->ht_regs[0x97], + ht216->ht_regs[0x98], ht216->ht_regs[0x99], ht216->ht_regs[0x9a], ht216->ht_regs[0x9b], + ht216->ht_regs[0x9c], ht216->ht_regs[0x9d], ht216->ht_regs[0x9e], ht216->ht_regs[0x9f]); + ht216_log(" A | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0xa0], ht216->ht_regs[0xa1], ht216->ht_regs[0xa2], ht216->ht_regs[0xa3], + ht216->ht_regs[0xa4], ht216->ht_regs[0xa5], ht216->ht_regs[0xa6], ht216->ht_regs[0xa7], + ht216->ht_regs[0xa8], ht216->ht_regs[0xa9], ht216->ht_regs[0xaa], ht216->ht_regs[0xab], + ht216->ht_regs[0xac], ht216->ht_regs[0xad], ht216->ht_regs[0xae], ht216->ht_regs[0xaf]); + ht216_log(" B | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0xb0], ht216->ht_regs[0xb1], ht216->ht_regs[0xb2], ht216->ht_regs[0xb3], + ht216->ht_regs[0xb4], ht216->ht_regs[0xb5], ht216->ht_regs[0xb6], ht216->ht_regs[0xb7], + ht216->ht_regs[0xb8], ht216->ht_regs[0xb9], ht216->ht_regs[0xba], ht216->ht_regs[0xbb], + ht216->ht_regs[0xbc], ht216->ht_regs[0xbd], ht216->ht_regs[0xbe], ht216->ht_regs[0xbf]); + ht216_log(" C | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0xc0], ht216->ht_regs[0xc1], ht216->ht_regs[0xc2], ht216->ht_regs[0xc3], + ht216->ht_regs[0xc4], ht216->ht_regs[0xc5], ht216->ht_regs[0xc6], ht216->ht_regs[0xc7], + ht216->ht_regs[0xc8], ht216->ht_regs[0xc9], ht216->ht_regs[0xca], ht216->ht_regs[0xcb], + ht216->ht_regs[0xcc], ht216->ht_regs[0xcd], ht216->ht_regs[0xce], ht216->ht_regs[0xcf]); + ht216_log(" D | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0xd0], ht216->ht_regs[0xd1], ht216->ht_regs[0xd2], ht216->ht_regs[0xd3], + ht216->ht_regs[0xd4], ht216->ht_regs[0xd5], ht216->ht_regs[0xd6], ht216->ht_regs[0xd7], + ht216->ht_regs[0xd8], ht216->ht_regs[0xd9], ht216->ht_regs[0xda], ht216->ht_regs[0xdb], + ht216->ht_regs[0xdc], ht216->ht_regs[0xdd], ht216->ht_regs[0xde], ht216->ht_regs[0xdf]); + ht216_log(" E | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0xe0], ht216->ht_regs[0xe1], ht216->ht_regs[0xe2], ht216->ht_regs[0xe3], + ht216->ht_regs[0xe4], ht216->ht_regs[0xe5], ht216->ht_regs[0xe6], ht216->ht_regs[0xe7], + ht216->ht_regs[0xe8], ht216->ht_regs[0xe9], ht216->ht_regs[0xea], ht216->ht_regs[0xeb], + ht216->ht_regs[0xec], ht216->ht_regs[0xed], ht216->ht_regs[0xee], ht216->ht_regs[0xef]); + ht216_log(" F | %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + ht216->ht_regs[0xf0], ht216->ht_regs[0xf1], ht216->ht_regs[0xf2], ht216->ht_regs[0xf3], + ht216->ht_regs[0xf4], ht216->ht_regs[0xf5], ht216->ht_regs[0xf6], ht216->ht_regs[0xf7], + ht216->ht_regs[0xf8], ht216->ht_regs[0xf9], ht216->ht_regs[0xfa], ht216->ht_regs[0xfb], + ht216->ht_regs[0xfc], ht216->ht_regs[0xfd], ht216->ht_regs[0xfe], ht216->ht_regs[0xff]); + return; +#endif } else if (svga->seqaddr >= 0x80 && ht216->ext_reg_enable) { old = ht216->ht_regs[svga->seqaddr & 0xff]; ht216->ht_regs[svga->seqaddr & 0xff] = val; + switch (svga->seqaddr & 0xff) { case 0x83: svga->attraddr = val & 0x1f; - svga->attrff = (val & 0x80) ? 1 : 0; + svga->attrff = !!(val & 0x80); break; case 0x94: - svga->hwcursor.addr = ((val << 6) | (3 << 14) | ((ht216->ht_regs[0xff] & 0x60) << 11)) << 2; + case 0xff: + svga->hwcursor.addr = ((ht216->ht_regs[0x94] << 6) | 0xc000 | ((ht216->ht_regs[0xff] & 0x60) << 11)) << 2; + svga->hwcursor.addr &= svga->vram_mask; + if (svga->crtc[0x17] == 0xeb) /*Looks like that 1024x768 mono mode expects 512K of video memory*/ + svga->hwcursor.addr += 0x40000; break; case 0x9c: case 0x9d: svga->hwcursor.x = ht216->ht_regs[0x9d] | ((ht216->ht_regs[0x9c] & 7) << 8); @@ -179,98 +289,174 @@ ht216_out(uint16_t addr, uint8_t val, void *p) case 0xa3: svga->latch.b[3] = val; break; + case 0xa4: - ht216->clk_sel = (val >> 2) & 0xf; - svga->miscout = (svga->miscout & ~0xc) | ((ht216->clk_sel & 3) << 2); + case 0xf8: + svga->fullchange = changeframecount; + svga_recalctimings(svga); break; + case 0xa5: - svga->hwcursor.ena = val & 0x80; + svga->hwcursor.ena = !!(val & 0x80); + break; + + case 0xc0: + break; + + case 0xc1: break; case 0xc8: - if ((old ^ val) & 0x10) { + if ((old ^ val) & HT_REG_C8_E256) { svga->fullchange = changeframecount; svga_recalctimings(svga); } + ht216_remap(ht216); break; - case 0xe8: - ht216->read_bank_reg[0] = val; - ht216->write_bank_reg[0] = val; - break; - case 0xe9: - ht216->read_bank_reg[1] = val; - ht216->write_bank_reg[1] = val; - break; - case 0xf6: - svga->vram_display_mask = (val & 0x40) ? ht216->vram_mask : 0x3ffff; - ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0xc0) | ((val & 0xc) << 4); - ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0xc0) | ((val & 0x3) << 6); - break; - case 0xf9: - ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0x10) | ((val & 1) ? 0x10 : 0); - ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0x10) | ((val & 1) ? 0x10 : 0); - break; - case 0xff: - svga->hwcursor.addr = ((ht216->ht_regs[0x94] << 6) | (3 << 14) | ((val & 0x60) << 11)) << 2; - break; - } - switch (svga->seqaddr & 0xff) { - case 0xa4: case 0xf6: case 0xfc: - svga->fullchange = changeframecount; - svga_recalctimings(&ht216->svga); - break; - } - switch (svga->seqaddr & 0xff) { - case 0xc8: case 0xc9: case 0xcf: - case 0xe0: case 0xe8: case 0xe9: - case 0xf6: case 0xf9: + case 0xc9: case 0xcf: ht216_remap(ht216); break; + + case 0xe0: + svga->adv_flags &= ~FLAG_RAMDAC_SHIFT; + if (val & 0x04) + svga->adv_flags |= FLAG_RAMDAC_SHIFT; + /* FALLTHROUGH */ + /*Bank registers*/ + case 0xe8: case 0xe9: + ht216_log("HT216 reg 0x%02x write = %02x, mode = 1, chain4 = %x\n", svga->seqaddr & 0xff, val, svga->chain4); + ht216_recalc_bank_regs(ht216, 1); + ht216_remap(ht216); + break; + + case 0xec: + ht216->fg_latch[0] = val; + break; + case 0xed: + ht216->fg_latch[1] = val; + break; + case 0xee: + ht216->fg_latch[2] = val; + break; + case 0xef: + ht216->fg_latch[3] = val; + break; + + case 0xf0: + ht216->fg_latch[ht216->fg_plane_sel] = val; + ht216->fg_plane_sel = (ht216->fg_plane_sel + 1) & 3; + break; + + case 0xf1: + ht216->bg_plane_sel = val & 3; + ht216->fg_plane_sel = (val & 0x30) >> 4; + break; + + case 0xf2: + svga->latch.b[ht216->bg_plane_sel] = val; + ht216->bg_plane_sel = (ht216->bg_plane_sel + 1) & 3; + break; + + case 0xf6: + /*Bits 18 and 19 of the display memory address*/ + ht216_log("HT216 reg 0xf6 write = %02x, mode = 0, chain4 = %x, vram mask = %08x, cr17 = %02x\n", val, svga->chain4, svga->vram_display_mask, svga->crtc[0x17]); + ht216_recalc_bank_regs(ht216, 0); + ht216_remap(ht216); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + + case 0xf9: + /*Bit 16 of the display memory address, only active when in chain4 mode and 256 color mode.*/ + ht216_log("HT216 reg 0xf9 write = %02x, mode = 0, chain4 = %x\n", val & HT_REG_F9_XPSEL, svga->chain4); + ht216_recalc_bank_regs(ht216, 0); + ht216_remap(ht216); + break; + + case 0xfc: + ht216_log("HT216 reg 0xfc write = %02x, mode = 0, chain4 = %x, bit 7 = %02x, packedchain = %02x\n", val, svga->chain4, val & 0x80, val & 0x20); + svga->packed_chain4 = !!(val & 0x20); + ht216_recalc_bank_regs(ht216, 0); + ht216_remap(ht216); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; } return; } break; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (ht216->id == 0x7152) + sc1148x_ramdac_out(addr, 0, val, svga->ramdac, svga); + else + svga_out(addr, val, svga); + return; + + case 0x3cb: + if (ht216->id == 0x7152) { + ht216->reg_3cb = val; + svga_set_ramdac_type(svga, (val & 0x20) ? RAMDAC_6BIT : RAMDAC_8BIT); + } + break; + case 0x3cf: - if (svga->gdcaddr == 6) { + if (svga->gdcaddr == 5) { + svga->chain2_read = val & 0x10; + ht216_remap(ht216); + } else if (svga->gdcaddr == 6) { if (val & 8) svga->banked_mask = 0x7fff; else svga->banked_mask = 0xffff; } + + if (svga->gdcaddr <= 8) { + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4 && svga->packed_chain4; + } break; - case 0x3D4: - svga->crtcreg = val & 0x3f; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; - case 0x3D5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; - if (old != val) { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { svga->fullchange = changeframecount; - svga_recalctimings(&ht216->svga); + svga_recalctimings(svga); } } - break; + } + break; - case 0x46e8: - io_removehandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); - mem_mapping_disable(&ht216->svga.mapping); - mem_mapping_disable(&ht216->linear_mapping); - if (val & 8) { - io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); - mem_mapping_enable(&ht216->svga.mapping); - ht216_remap(ht216); - } - break; + case 0x46e8: + if ((ht216->id == 0x7152) && ht216->isabus) + io_removehandler(0x0105, 0x0001, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + io_removehandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&ht216->linear_mapping); + if (val & 8) { + if ((ht216->id == 0x7152) && ht216->isabus) + io_sethandler(0x0105, 0x0001, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + mem_mapping_enable(&svga->mapping); + ht216_remap(ht216); + } + break; } svga_out(addr, val, svga); @@ -282,43 +468,85 @@ ht216_in(uint16_t addr, void *p) { ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; + uint8_t ret = 0xff; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; + addr ^= 0x60; + + if ((ht216->id == 0x7152) && ht216->isabus) { + if (addr == 0x105) + return ht216->extensions; + } switch (addr) { - case 0x3c2: - break; + case 0x3c4: + return svga->seqaddr; case 0x3c5: if (svga->seqaddr == 6) return ht216->ext_reg_enable; - if (svga->seqaddr >= 0x80) { + else if (svga->seqaddr >= 0x80) { if (ht216->ext_reg_enable) { + ret = ht216->ht_regs[svga->seqaddr & 0xff]; + switch (svga->seqaddr & 0xff) { case 0x83: if (svga->attrff) - return svga->attraddr | 0x80; - return svga->attraddr; + ret = svga->attraddr | 0x80; + else + ret = svga->attraddr; + break; - case 0x8e: return ht216->id & 0xff; - case 0x8f: return (ht216->id >> 8) & 0xff; + case 0x8e: + ret = ht216->id & 0xff; + break; + case 0x8f: + ret = (ht216->id >> 8) & 0xff; + break; case 0xa0: - return svga->latch.b[0]; + ret = svga->latch.b[0]; + break; case 0xa1: - return svga->latch.b[1]; + ret = svga->latch.b[1]; + break; case 0xa2: - return svga->latch.b[2]; + ret = svga->latch.b[2]; + break; case 0xa3: - return svga->latch.b[3]; + ret = svga->latch.b[3]; + break; + + case 0xf0: + ret = ht216->fg_latch[ht216->fg_plane_sel]; + ht216->fg_plane_sel = 0; + break; + + case 0xf2: + ret = svga->latch.b[ht216->bg_plane_sel]; + ht216->bg_plane_sel = 0; + break; } - return ht216->ht_regs[svga->seqaddr & 0xff]; + + return ret; } else return 0xff; } break; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (ht216->id == 0x7152) + return sc1148x_ramdac_in(addr, 0, svga->ramdac, svga); + return svga_in(addr, svga); + + case 0x3cb: + if (ht216->id == 0x7152) + return ht216->reg_3cb; + break; + + case 0x3cc: + return svga->miscout; + case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -330,7 +558,6 @@ ht216_in(uint16_t addr, void *p) return svga_in(addr, svga); } - void ht216_remap(ht216_t *ht216) { @@ -338,40 +565,40 @@ ht216_remap(ht216_t *ht216) mem_mapping_disable(&ht216->linear_mapping); if (ht216->ht_regs[0xc8] & HT_REG_C8_XLAM) { - uint32_t linear_base = ((ht216->ht_regs[0xc9] & 0xf) << 20) | (ht216->ht_regs[0xcf] << 24); - - mem_mapping_set_addr(&ht216->linear_mapping, linear_base, 0x100000); - /*Linear mapping enabled*/ - } else { - uint8_t read_bank_reg[2] = {ht216->read_bank_reg[0], ht216->read_bank_reg[1]}; - uint8_t write_bank_reg[2] = {ht216->write_bank_reg[0], ht216->write_bank_reg[1]}; - - if (!svga->chain4 || !(ht216->ht_regs[0xfc] & HT_REG_FC_ECOLRE)) { - read_bank_reg[0] &= ~0x30; - read_bank_reg[1] &= ~0x30; - write_bank_reg[0] &= ~0x30; - write_bank_reg[1] &= ~0x30; - } - - ht216->read_bank[0] = read_bank_reg[0] << 12; - ht216->write_bank[0] = write_bank_reg[0] << 12; - if (ht216->ht_regs[0xe0] & HT_REG_E0_SBAE) { - /*Split bank*/ - ht216->read_bank[1] = read_bank_reg[1] << 12; - ht216->write_bank[1] = write_bank_reg[1] << 12; - } else { - ht216->read_bank[1] = ht216->read_bank[0] + (svga->chain4 ? 0x8000 : 0x20000); - ht216->write_bank[1] = ht216->write_bank[0] + (svga->chain4 ? 0x8000 : 0x20000); - } - - if (!svga->chain4) { - ht216->read_bank[0] >>= 2; - ht216->read_bank[1] >>= 2; - ht216->write_bank[0] >>= 2; - ht216->write_bank[1] >>= 2; - } + ht216_log("Linear mapping enabled\n"); + ht216->linear_base = ((ht216->ht_regs[0xc9] & 0xf) << 20) | (ht216->ht_regs[0xcf] << 24); + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&ht216->linear_mapping, ht216->linear_base, 0x100000); } + + ht216->read_banks[0] = ht216->read_bank_reg[0] << 12; + ht216->write_banks[0] = ht216->write_bank_reg[0] << 12; + + /* Split bank: two banks used */ + if (ht216->ht_regs[0xe0] & HT_REG_E0_SBAE) { + ht216->read_banks[1] = ht216->read_bank_reg[1] << 12; + ht216->write_banks[1] = ht216->write_bank_reg[1] << 12; + } + + if (!svga->chain4) { + ht216->read_banks[0] = ((ht216->read_banks[0] & 0xc0000) >> 2) | (ht216->read_banks[0] & 0xffff); + ht216->read_banks[1] = ((ht216->read_banks[1] & 0xc0000) >> 2) | (ht216->read_banks[1] & 0xffff); + ht216->write_banks[0] = ((ht216->write_banks[0] & 0xc0000) >> 2) | (ht216->write_banks[0] & 0xffff); + ht216->write_banks[1] = ((ht216->write_banks[1] & 0xc0000) >> 2) | (ht216->write_banks[1] & 0xffff); + } + + if (!(ht216->ht_regs[0xe0] & HT_REG_E0_SBAE)) { + ht216->read_banks[1] = ht216->read_banks[0] + 0x8000; + ht216->write_banks[1] = ht216->write_banks[0] + 0x8000; + } + +#ifdef ENABLE_HT216_LOG + ht216_log("Registers: %02X, %02X, %02X, %02X, %02X\n", ht216->misc, ht216->ht_regs[0xe8], ht216->ht_regs[0xe9], + ht216->ht_regs[0xf6], ht216->ht_regs[0xf9]); + ht216_log("Banks: %08X, %08X, %08X, %08X\n", ht216->read_banks[0], ht216->read_banks[1], + ht216->write_banks[0], ht216->write_banks[1]); +#endif } @@ -379,27 +606,112 @@ void ht216_recalctimings(svga_t *svga) { ht216_t *ht216 = (ht216_t *)svga->p; + int high_res_256 = 0; + + switch ((((((svga->miscout >> 2) & 3) || ((ht216->ht_regs[0xa4] >> 2) & 3)) | + ((ht216->ht_regs[0xa4] >> 2) & 4)) || ((ht216->ht_regs[0xf8] >> 5) & 0x0f)) | + ((ht216->ht_regs[0xf8] << 1) & 8)) { + case 0: + case 1: + break; + case 4: + svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; + break; + case 5: + svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; + break; + case 7: + svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; + break; + default: + svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; + break; + } - switch (ht216->clk_sel) { - case 5: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; - case 6: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; - case 10: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; - } - svga->lowres = !(ht216->ht_regs[0xc8] & HT_REG_C8_E256); svga->ma_latch |= ((ht216->ht_regs[0xf6] & 0x30) << 12); + svga->interlace = ht216->ht_regs[0xe0] & 1; - if ((svga->bpp == 8) && !svga->lowres) - svga->render = svga_render_8bpp_highres; + if (svga->interlace) + high_res_256 = (svga->htotal * 8) > (svga->vtotal * 4); + else + high_res_256 = (svga->htotal * 8) > (svga->vtotal * 2); + + ht216->adjust_cursor = 0; + + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) /*40 column*/ { + svga->render = svga_render_text_40; + } else { + svga->render = svga_render_text_80; + } + } else { + if (svga->crtc[0x17] == 0xeb) { + svga->rowoffset <<= 1; + svga->render = svga_render_2bpp_headland_highres; + } + + if (svga->bpp == 8) { + ht216_log("regC8 = %02x, gdcreg5 bit 6 = %02x, no lowres = %02x, regf8 bit 7 = %02x, regfc = %02x\n", ht216->ht_regs[0xc8] & HT_REG_C8_E256, svga->gdcreg[5] & 0x40, !svga->lowres, ht216->ht_regs[0xf6] & 0x80, ht216->ht_regs[0xfc] & HT_REG_FC_ECOLRE); + if (((ht216->ht_regs[0xc8] & HT_REG_C8_E256) || (svga->gdcreg[5] & 0x40)) && (!svga->lowres || (ht216->ht_regs[0xf6] & 0x80))) { + if (high_res_256) { + svga->hdisp >>= 1; + ht216->adjust_cursor = 1; + } + svga->render = svga_render_8bpp_highres; + } else if (svga->lowres) { + if (high_res_256) { + svga->hdisp >>= 1; + ht216->adjust_cursor = 1; + svga->render = svga_render_8bpp_highres; + } else { + ht216_log("8bpp low, packed = %02x, chain4 = %02x\n", svga->packed_chain4, svga->chain4); + svga->render = svga_render_8bpp_lowres; + } + } else if (ht216->ht_regs[0xfc] & HT_REG_FC_ECOLRE) { + if (ht216->id == 0x7152) { + svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); + if (!(svga->crtc[1] & 1)) + svga->hdisp--; + svga->hdisp++; + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->rowoffset <<= 1; + if ((svga->crtc[0x17] & 0x60) == 0x20) /*Would result in a garbled screen with trailing cursor glitches*/ + svga->crtc[0x17] |= 0x40; + } + svga->render = svga_render_8bpp_highres; + } + } else if (svga->bpp == 15) { + svga->rowoffset <<= 1; + svga->hdisp >>= 1; + if ((svga->crtc[0x17] & 0x60) == 0x20) /*Would result in a garbled screen with trailing cursor glitches*/ + svga->crtc[0x17] |= 0x40; + svga->render = svga_render_15bpp_highres; + } + } + } + + svga->ma_latch |= ((ht216->ht_regs[0xf6] & 0x30) << 14); + + if (svga->crtc[0x17] == 0xeb) /*Looks like 1024x768 mono mode expects 512K of video memory*/ + svga->vram_display_mask = 0x7ffff; + else + svga->vram_display_mask = (ht216->ht_regs[0xf6] & 0x40) ? ht216->vram_mask : 0x3ffff; } static void ht216_hwcursor_draw(svga_t *svga, int displine) { - int x; + ht216_t *ht216 = (ht216_t *)svga->p; + int x, shift = (ht216->adjust_cursor ? 2 : 1); uint32_t dat[2]; - int offset = svga->hwcursor_latch.x + svga->x_add; + int offset = svga->hwcursor_latch.x + svga->hwcursor_latch.xoff; + int width = (ht216->adjust_cursor ? 16 : 32); + + if (ht216->adjust_cursor) + offset >>= 1; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 4; @@ -413,14 +725,14 @@ ht216_hwcursor_draw(svga_t *svga, int displine) (svga->vram[svga->hwcursor_latch.addr+128+2] << 8) | svga->vram[svga->hwcursor_latch.addr+128+3]; - for (x = 0; x < 32; x++) { + for (x = 0; x < width; x++) { if (!(dat[0] & 0x80000000)) - ((uint32_t *)buffer32->line[displine])[offset + x] = 0; + ((uint32_t *)buffer32->line[displine])[svga->x_add + offset + x] = 0; if (dat[1] & 0x80000000) - ((uint32_t *)buffer32->line[displine])[offset + x] ^= 0xffffff; + ((uint32_t *)buffer32->line[displine])[svga->x_add + offset + x] ^= 0xffffff; - dat[0] <<= 1; - dat[1] <<= 1; + dat[0] <<= shift; + dat[1] <<= shift; } svga->hwcursor_latch.addr += 4; @@ -456,206 +768,180 @@ extalu(int op, uint8_t input_a, uint8_t input_b) return val; } - static void ht216_dm_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t cpu_dat_unexpanded) { svga_t *svga = &ht216->svga; - uint8_t vala, valb, valc, vald, wm = svga->writemask; - int writemask2 = svga->writemask; - uint8_t fg_data[4] = {0, 0, 0, 0}; + int writemask2 = svga->writemask, reset_wm = 0; + latch_t vall; + uint8_t i, wm = svga->writemask; + uint8_t count = 4, fg_data[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) + writemask2 = svga->seqregs[2]; if (!(svga->gdcreg[6] & 1)) - svga->fullchange = 2; - if (svga->chain4 || svga->fb_only) { - writemask2=1<<(addr&3); - addr&=~3; - } else if (svga->chain2_write) { + svga->fullchange = 2; + + if (svga->chain4) { + writemask2 = 1 << (addr & 3); + addr = dword_remap(svga, addr) & ~3; + } else if (svga->chain2_write && (svga->crtc[0x17] != 0xeb)) { writemask2 &= ~0xa; if (addr & 1) writemask2 <<= 1; addr &= ~1; addr <<= 2; } else - addr<<=2; + addr <<= 2; + if (addr >= svga->vram_max) return; - svga->changedvram[addr >> 12]=changeframecount; + svga->changedvram[addr >> 12] = changeframecount; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) + count = 8; switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBMC) { case 0x00: - fg_data[0] = fg_data[1] = fg_data[2] = fg_data[3] = cpu_dat; + for (i = 0; i < count; i++) + fg_data[i] = cpu_dat; break; case 0x04: if (ht216->ht_regs[0xfe] & HT_REG_FE_FBRC) { - if (addr & 4) { - fg_data[0] = (cpu_dat_unexpanded & (1 << (((addr + 4) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[1] = (cpu_dat_unexpanded & (1 << (((addr + 5) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[2] = (cpu_dat_unexpanded & (1 << (((addr + 6) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[3] = (cpu_dat_unexpanded & (1 << (((addr + 7) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - } else { - fg_data[0] = (cpu_dat_unexpanded & (1 << (((addr + 0) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[1] = (cpu_dat_unexpanded & (1 << (((addr + 1) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[2] = (cpu_dat_unexpanded & (1 << (((addr + 2) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[3] = (cpu_dat_unexpanded & (1 << (((addr + 3) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xfa] & (1 << i)) + fg_data[i] = cpu_dat_unexpanded; + else if (ht216->ht_regs[0xfb] & (1 << i)) + fg_data[i] = 0xff - cpu_dat_unexpanded; } } else { - if (addr & 4) { - fg_data[0] = (ht216->ht_regs[0xf5] & (1 << (((addr + 4) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[1] = (ht216->ht_regs[0xf5] & (1 << (((addr + 5) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[2] = (ht216->ht_regs[0xf5] & (1 << (((addr + 6) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[3] = (ht216->ht_regs[0xf5] & (1 << (((addr + 7) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - } else { - fg_data[0] = (ht216->ht_regs[0xf5] & (1 << (((addr + 0) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[1] = (ht216->ht_regs[0xf5] & (1 << (((addr + 1) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[2] = (ht216->ht_regs[0xf5] & (1 << (((addr + 2) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; - fg_data[3] = (ht216->ht_regs[0xf5] & (1 << (((addr + 3) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xfa] & (1 << i)) + fg_data[i] = ht216->ht_regs[0xf5]; + else if (ht216->ht_regs[0xfb] & (1 << i)) + fg_data[i] = 0xff - ht216->ht_regs[0xf5]; } } break; case 0x08: - fg_data[0] = ht216->ht_regs[0xec]; - fg_data[1] = ht216->ht_regs[0xed]; - fg_data[2] = ht216->ht_regs[0xee]; - fg_data[3] = ht216->ht_regs[0xef]; - break; case 0x0c: - fg_data[0] = ht216->ht_regs[0xec]; - fg_data[1] = ht216->ht_regs[0xed]; - fg_data[2] = ht216->ht_regs[0xee]; - fg_data[3] = ht216->ht_regs[0xef]; + for (i = 0; i < count; i++) + fg_data[i] = ht216->fg_latch[i]; break; } switch (svga->writemode) { - case 1: - if (writemask2 & 1) svga->vram[addr] = svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = svga->latch.b[3]; - break; case 0: - if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - (!svga->gdcreg[1] || svga->set_reset_disabled)) { - if (writemask2 & 1) svga->vram[addr] = fg_data[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = fg_data[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = fg_data[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = fg_data[3]; + if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = fg_data[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = fg_data[i]; + } + } + return; } else { - if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - else vala = fg_data[0]; - if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - else valb = fg_data[1]; - if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - else valc = fg_data[2]; - if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - else vald = fg_data[3]; - - switch (svga->gdcreg[3] & 0x18) { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->latch.b[0] & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->latch.b[3]; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->latch.b[3]; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->latch.b[3]; - break; + for (i = 0; i < count; i++) { + if (svga->gdcreg[1] & (1 << i)) + vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff; + else + vall.b[i] = fg_data[i]; } } break; - case 2: - if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { - if (writemask2 & 1) svga->vram[addr] = (((cpu_dat & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[0] & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (((cpu_dat & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (((cpu_dat & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (((cpu_dat & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); - } else { - vala = ((cpu_dat & 1) ? 0xff : 0); - valb = ((cpu_dat & 2) ? 0xff : 0); - valc = ((cpu_dat & 4) ? 0xff : 0); - vald = ((cpu_dat & 8) ? 0xff : 0); - switch (svga->gdcreg[3] & 0x18) { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->latch.b[0] & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->latch.b[3]; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->latch.b[3]; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->latch.b[3]; - break; + case 1: + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = svga->latch.b[i]; } } + return; + case 2: + for (i = 0; i < count; i++) + vall.b[i] = !!(cpu_dat & (1 << i)) * 0xff; + + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } + } + return; + } break; case 3: - wm = svga->gdcreg[8]; - svga->gdcreg[8] &= cpu_dat; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= cpu_dat; - vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - switch (svga->gdcreg[3] & 0x18) { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->latch.b[0] & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->latch.b[3]; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->latch.b[3]; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->latch.b[0]; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->latch.b[1]; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->latch.b[2]; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->latch.b[3]; - break; + for (i = 0; i < count; i++) + vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff; + + reset_wm = 1; + break; + } + + switch (svga->gdcreg[3] & 0x18) { + case 0x00: /* Set */ + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } + } + break; + case 0x08: /* AND */ + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } + } + break; + case 0x10: /* OR */ + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } + } + break; + case 0x18: /* XOR */ + for (i = 0; i < count; i++) { + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } } - svga->gdcreg[8] = wm; break; } + + if (reset_wm) + svga->gdcreg[8] = wm; } @@ -678,9 +964,10 @@ ht216_dm_extalu_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t bi uint8_t input_a = 0, input_b = 0; uint8_t fg, bg; uint8_t output; + uint32_t remapped_addr = dword_remap(svga, addr); if (ht216->ht_regs[0xcd] & HT_REG_CD_RMWMDE) /*RMW*/ - input_b = svga->vram[addr]; + input_b = svga->vram[remapped_addr]; else input_b = ht216->bg_latch[addr & 7]; @@ -695,7 +982,7 @@ ht216_dm_extalu_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t bi input_a = (ht216->ht_regs[0xf5] & (1 << ((addr & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; break; case 0x08: - input_a = ht216->ht_regs[0xec + (addr & 3)]; + input_a = ht216->fg_latch[addr & 3]; break; case 0x0c: input_a = ht216->bg_latch[addr & 7]; @@ -705,8 +992,69 @@ ht216_dm_extalu_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t bi fg = extalu(ht216->ht_regs[0xce] >> 4, input_a, input_b); bg = extalu(ht216->ht_regs[0xce] & 0xf, input_a, input_b); output = (fg & rop_select) | (bg & ~rop_select); - svga->vram[addr] = (svga->vram[addr] & ~bit_mask) | (output & bit_mask); + svga->vram[addr] = (svga->vram[remapped_addr] & ~bit_mask) | (output & bit_mask); + svga->changedvram[remapped_addr >> 12] = changeframecount; +} + +static void +ht216_dm_masked_write(ht216_t *ht216, uint32_t addr, uint8_t val, uint8_t bit_mask) +{ + svga_t *svga = &ht216->svga; + int writemask2 = svga->writemask; + uint8_t count = 4, i; + uint8_t full_mask = 0x0f; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) + writemask2 = svga->seqregs[2]; + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + + if (svga->chain4) { + writemask2 = 1 << (addr & 3); + addr = dword_remap(svga, addr) & ~3; + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + if (addr >= svga->vram_max) + return; + + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return; + + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_P8PCEXP) { + count = 8; + full_mask = 0xff; + } + + if (bit_mask == 0xff) { + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = val; + } + } else { + if (writemask2 == full_mask) { + for (i = 0; i < count; i++) + svga->vram[addr | i] = (svga->latch.b[i] & bit_mask) | (svga->vram[addr | i] & ~bit_mask); + } else { + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (val & bit_mask) | (svga->vram[addr | i] & ~bit_mask); + } + } + } } @@ -727,15 +1075,14 @@ ht216_write_common(ht216_t *ht216, uint32_t addr, uint8_t val) 1x = (3C4:F5) */ svga_t *svga = &ht216->svga; + int i; uint8_t bit_mask = 0, rop_select = 0; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; - egawrites++; + addr &= svga->vram_mask; - addr &= 0xfffff; - - val = svga_rotate[svga->gdcreg[3] & 7][val]; + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); if (ht216->ht_regs[0xcd] & HT_REG_CD_EXALU) { /*Extended ALU*/ @@ -764,29 +1111,24 @@ ht216_write_common(ht216_t *ht216, uint32_t addr, uint8_t val) if (ht216->ht_regs[0xcd] & HT_REG_CD_FP8PCEXP) { /*1->8 bit expansion*/ addr = (addr << 3) & 0xfffff; - ht216_dm_extalu_write(ht216, addr, (val & 0x80) ? 0xff : 0, (bit_mask & 0x80) ? 0xff : 0, val, (rop_select & 0x80) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 1, (val & 0x40) ? 0xff : 0, (bit_mask & 0x40) ? 0xff : 0, val, (rop_select & 0x40) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 2, (val & 0x20) ? 0xff : 0, (bit_mask & 0x20) ? 0xff : 0, val, (rop_select & 0x20) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 3, (val & 0x10) ? 0xff : 0, (bit_mask & 0x10) ? 0xff : 0, val, (rop_select & 0x10) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 4, (val & 0x08) ? 0xff : 0, (bit_mask & 0x08) ? 0xff : 0, val, (rop_select & 0x08) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 5, (val & 0x04) ? 0xff : 0, (bit_mask & 0x04) ? 0xff : 0, val, (rop_select & 0x04) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 6, (val & 0x02) ? 0xff : 0, (bit_mask & 0x02) ? 0xff : 0, val, (rop_select & 0x02) ? 0xff : 0); - ht216_dm_extalu_write(ht216, addr + 7, (val & 0x01) ? 0xff : 0, (bit_mask & 0x01) ? 0xff : 0, val, (rop_select & 0x01) ? 0xff : 0); - } else + for (i = 0; i < 8; i++) + ht216_dm_extalu_write(ht216, addr + i, (val & (0x80 >> i)) ? 0xff : 0, (bit_mask & (0x80 >> i)) ? 0xff : 0, val, (rop_select & (0x80 >> i)) ? 0xff : 0); + } else { ht216_dm_extalu_write(ht216, addr, val, bit_mask, val, rop_select); + } + } else if (ht216->ht_regs[0xf3]) { + if (ht216->ht_regs[0xf3] & 2) { + ht216_dm_masked_write(ht216, addr, val, val); + } else + ht216_dm_masked_write(ht216, addr, val, ht216->ht_regs[0xf4]); } else { if (ht216->ht_regs[0xcd] & HT_REG_CD_FP8PCEXP) { /*1->8 bit expansion*/ addr = (addr << 3) & 0xfffff; - ht216_dm_write(ht216, addr, (val & 0x80) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 1, (val & 0x40) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 2, (val & 0x20) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 3, (val & 0x10) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 4, (val & 0x08) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 5, (val & 0x04) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 6, (val & 0x02) ? 0xff : 0, val); - ht216_dm_write(ht216, addr + 7, (val & 0x01) ? 0xff : 0, val); - } else + for (i = 0; i < 8; i++) + ht216_dm_write(ht216, addr + i, (val & (0x80 >> i)) ? 0xff : 0, val); + } else { ht216_dm_write(ht216, addr, val, val); + } } } @@ -796,13 +1138,19 @@ ht216_write(uint32_t addr, uint8_t val, void *p) { ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; + uint32_t prev_addr = addr; addr &= svga->banked_mask; - addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + ht216->write_banks[(addr >> 15) & 1]; - if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) - svga_write_linear(addr, val, &ht216->svga); - else + if (svga->crtc[0x17] == 0xeb && !(svga->gdcreg[6] & 0xc) && prev_addr >= 0xb0000) + addr += 0x10000; + else if (svga->chain4 && ((ht216->ht_regs[0xfc] & 0x06) == 0x06)) + addr = (addr & 0xfffeffff) | (prev_addr & 0x10000); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe] && !ht216->ht_regs[0xf3] && svga->crtc[0x17] != 0xeb) { + svga_write_linear(addr, val, svga); + } else ht216_write_common(ht216, addr, val); } @@ -812,11 +1160,18 @@ ht216_writew(uint32_t addr, uint16_t val, void *p) { ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; + uint32_t prev_addr = addr; addr &= svga->banked_mask; - addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; - if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) - svga_writew_linear(addr, val, &ht216->svga); + addr = (addr & 0x7fff) + ht216->write_banks[(addr >> 15) & 1]; + + if (svga->crtc[0x17] == 0xeb && !(svga->gdcreg[6] & 0xc) && prev_addr >= 0xb0000) + addr += 0x10000; + else if (svga->chain4 && ((ht216->ht_regs[0xfc] & 0x06) == 0x06)) + addr = (addr & 0xfffeffff) | (prev_addr & 0x10000); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe] && !ht216->ht_regs[0xf3] && svga->crtc[0x17] != 0xeb) + svga_writew_linear(addr, val, svga); else { ht216_write_common(ht216, addr, val); ht216_write_common(ht216, addr+1, val >> 8); @@ -829,11 +1184,18 @@ ht216_writel(uint32_t addr, uint32_t val, void *p) { ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; + uint32_t prev_addr = addr; addr &= svga->banked_mask; - addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; - if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) - svga_writel_linear(addr, val, &ht216->svga); + addr = (addr & 0x7fff) + ht216->write_banks[(addr >> 15) & 1]; + + if (svga->crtc[0x17] == 0xeb && !(svga->gdcreg[6] & 0xc) && prev_addr >= 0xb0000) + addr += 0x10000; + else if (svga->chain4 && ((ht216->ht_regs[0xfc] & 0x06) == 0x06)) + addr = (addr & 0xfffeffff) | (prev_addr & 0x10000); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe] && !ht216->ht_regs[0xf3] && svga->crtc[0x17] != 0xeb) + svga_writel_linear(addr, val, svga); else { ht216_write_common(ht216, addr, val); ht216_write_common(ht216, addr+1, val >> 8); @@ -849,11 +1211,13 @@ ht216_write_linear(uint32_t addr, uint8_t val, void *p) ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; - if (!svga->chain4) /*Bits 16 and 17 of linear address seem to be unused in planar modes*/ + addr -= ht216->linear_base; + if (!svga->chain4) /*Bits 16 and 17 of linear address are unused in planar modes*/ addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + addr += ht216->write_banks[0]; if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) - svga_write_linear(addr, val, &ht216->svga); + svga_write_linear(addr, val, svga); else ht216_write_common(ht216, addr, val); } @@ -865,11 +1229,13 @@ ht216_writew_linear(uint32_t addr, uint16_t val, void *p) ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; - if (!svga->chain4) + addr -= ht216->linear_base; + if (!svga->chain4) /*Bits 16 and 17 of linear address are unused in planar modes*/ addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + addr += ht216->write_banks[0]; if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) - svga_writew_linear(addr, val, &ht216->svga); + svga_writew_linear(addr, val, svga); else { ht216_write_common(ht216, addr, val); ht216_write_common(ht216, addr+1, val >> 8); @@ -883,11 +1249,13 @@ ht216_writel_linear(uint32_t addr, uint32_t val, void *p) ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; - if (!svga->chain4) + addr -= ht216->linear_base; + if (!svga->chain4) /*Bits 16 and 17 of linear address are unused in planar modes*/ addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + addr += ht216->write_banks[0]; if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) - svga_writel_linear(addr, val, &ht216->svga); + svga_writel_linear(addr, val, svga); else { ht216_write_common(ht216, addr, val); ht216_write_common(ht216, addr+1, val >> 8); @@ -901,39 +1269,36 @@ static uint8_t ht216_read_common(ht216_t *ht216, uint32_t addr) { svga_t *svga = &ht216->svga; - uint8_t temp, temp2, temp3, temp4, or; - int readplane = svga->readplane; - int offset; - uint32_t latch_addr; + uint32_t latch_addr = 0; + int offset, readplane = svga->readplane; + uint8_t or, i; + uint8_t count = 2; + uint8_t plane, pixel; + uint8_t temp, ret; if (ht216->ht_regs[0xc8] & HT_REG_C8_MOVSB) addr <<= 3; - addr &= 0xfffff; + addr &= svga->vram_mask; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; - egareads++; + count = (1 << count); - if (svga->chain4 || svga->fb_only) { + if (svga->chain4 && svga->packed_chain4) { addr &= svga->decode_mask; if (addr >= svga->vram_max) return 0xff; - latch_addr = (addr & svga->vram_mask) & ~7; if (ht216->ht_regs[0xcd] & HT_REG_CD_ASTODE) latch_addr += (svga->gdcreg[3] & 7); - ht216->bg_latch[0] = svga->vram[latch_addr]; - ht216->bg_latch[1] = svga->vram[latch_addr + 1]; - ht216->bg_latch[2] = svga->vram[latch_addr + 2]; - ht216->bg_latch[3] = svga->vram[latch_addr + 3]; - ht216->bg_latch[4] = svga->vram[latch_addr + 4]; - ht216->bg_latch[5] = svga->vram[latch_addr + 5]; - ht216->bg_latch[6] = svga->vram[latch_addr + 6]; - ht216->bg_latch[7] = svga->vram[latch_addr + 7]; - - return svga->vram[addr & svga->vram_mask]; - } else if (svga->chain2_read) { + for (i = 0; i < 8; i++) + ht216->bg_latch[i] = svga->vram[dword_remap(svga, latch_addr + i)]; + return svga->vram[dword_remap(svga, addr) & svga->vram_mask]; + } else if (svga->chain4) { + readplane = addr & 3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); + } else if (svga->chain2_read && (svga->crtc[0x17] != 0xeb)) { readplane = (readplane & 2) | (addr & 1); addr &= ~1; addr <<= 2; @@ -950,45 +1315,35 @@ ht216_read_common(ht216_t *ht216, uint32_t addr) latch_addr = addr & ~7; if (ht216->ht_regs[0xcd] & HT_REG_CD_ASTODE) { offset = addr & 7; - - ht216->bg_latch[0] = svga->vram[latch_addr | offset]; - ht216->bg_latch[1] = svga->vram[latch_addr | ((offset + 1) & 7)]; - ht216->bg_latch[2] = svga->vram[latch_addr | ((offset + 2) & 7)]; - ht216->bg_latch[3] = svga->vram[latch_addr | ((offset + 3) & 7)]; - ht216->bg_latch[4] = svga->vram[latch_addr | ((offset + 4) & 7)]; - ht216->bg_latch[5] = svga->vram[latch_addr | ((offset + 5) & 7)]; - ht216->bg_latch[6] = svga->vram[latch_addr | ((offset + 6) & 7)]; - ht216->bg_latch[7] = svga->vram[latch_addr | ((offset + 7) & 7)]; + for (i = 0; i < 8; i++) + ht216->bg_latch[i] = svga->vram[latch_addr | ((offset + i) & 7)]; } else { - ht216->bg_latch[0] = svga->vram[latch_addr]; - ht216->bg_latch[1] = svga->vram[latch_addr | 1]; - ht216->bg_latch[2] = svga->vram[latch_addr | 2]; - ht216->bg_latch[3] = svga->vram[latch_addr | 3]; - ht216->bg_latch[4] = svga->vram[latch_addr | 4]; - ht216->bg_latch[5] = svga->vram[latch_addr | 5]; - ht216->bg_latch[6] = svga->vram[latch_addr | 6]; - ht216->bg_latch[7] = svga->vram[latch_addr | 7]; - } - or = addr & 4; - svga->latch.d[0] = ht216->bg_latch[0 | or] | (ht216->bg_latch[1 | or] << 8) | - (ht216->bg_latch[2 | or] << 16) | (ht216->bg_latch[3 | or] << 24); - if (svga->readmode) { - temp = svga->latch.b[0]; - temp ^= (svga->colourcompare & 1) ? 0xff : 0; - temp &= (svga->colournocare & 1) ? 0xff : 0; - temp2 = svga->latch.b[1]; - temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; - temp2 &= (svga->colournocare & 2) ? 0xff : 0; - temp3 = svga->latch.b[2]; - temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; - temp3 &= (svga->colournocare & 4) ? 0xff : 0; - temp4 = svga->latch.b[3]; - temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; - temp4 &= (svga->colournocare & 8) ? 0xff : 0; - return ~(temp | temp2 | temp3 | temp4); + for (i = 0; i < 8; i++) + ht216->bg_latch[i] = svga->vram[latch_addr | i]; } - return svga->vram[addr | readplane]; + or = addr & 4; + for (i = 0; i < 4; i++) + svga->latch.b[i] = ht216->bg_latch[i | or]; + + if (svga->readmode) { + temp = 0xff; + + for (pixel = 0; pixel < 8; pixel++) { + for (plane = 0; plane < (1 << count); plane++) { + if (svga->colournocare & (1 << plane)) { + /* If we care about a plane, and the pixel has a mismatch on it, clear its bit. */ + if (((svga->latch.b[plane] >> pixel) & 1) != ((svga->colourcompare >> plane) & 1)) + temp &= ~(1 << pixel); + } + } + } + + ret = temp; + } else + ret = svga->vram[addr | readplane]; + + return ret; } @@ -997,9 +1352,15 @@ ht216_read(uint32_t addr, void *p) { ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; + uint32_t prev_addr = addr; addr &= svga->banked_mask; - addr = (addr & 0x7fff) + ht216->read_bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + ht216->read_banks[(addr >> 15) & 1]; + + if (svga->crtc[0x17] == 0xeb && !(svga->gdcreg[6] & 0xc) && prev_addr >= 0xb0000) + addr += 0x10000; + else if (svga->chain4 && ((ht216->ht_regs[0xfc] & 0x06) == 0x06)) + addr = (addr & 0xfffeffff) | (prev_addr & 0x10000); return ht216_read_common(ht216, addr); } @@ -1011,12 +1372,41 @@ ht216_read_linear(uint32_t addr, void *p) ht216_t *ht216 = (ht216_t *)p; svga_t *svga = &ht216->svga; - if (svga->chain4) - return ht216_read_common(ht216, addr); - else - return ht216_read_common(ht216, (addr & 0xffff) | ((addr & 0xc0000) >> 2)); + addr -= ht216->linear_base; + if (!svga->chain4) /*Bits 16 and 17 of linear address are unused in planar modes*/ + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + addr += ht216->read_banks[0]; + + return ht216_read_common(ht216, addr); } +static uint8_t +radius_mca_read(int port, void *priv) +{ + ht216_t *ht216 = (ht216_t *)priv; + ht216_log("Port %03x MCA read = %02x\n", port, ht216->pos_regs[port & 7]); + return (ht216->pos_regs[port & 7]); +} + +static void +radius_mca_write(int port, uint8_t val, void *priv) +{ + ht216_t *ht216 = (ht216_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + ht216_log("Port %03x MCA write = %02x, setup mode = %02x\n", port, val, ht216->ht_regs[0xfc] & 0x80); + + /* Save the MCA register value. */ + ht216->pos_regs[port & 7] = val; +} + +static uint8_t +radius_mca_feedb(void *priv) +{ + return 1; +} void *ht216_init(const device_t *info, uint32_t mem_size, int has_rom) @@ -1027,42 +1417,106 @@ void memset(ht216, 0, sizeof(ht216_t)); svga = &ht216->svga; - io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); - io_sethandler(0x46e8, 0x0001, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); - - if (has_rom == 1) - rom_init(&ht216->bios_rom, BIOS_VIDEO7_VGA_1024I_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - else if (has_rom == 2) - rom_init(&ht216->bios_rom, BIOS_G2_GC205_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_VLB) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_v7vga_vlb); + else if (info->flags & DEVICE_MCA) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_v7vga_mca); else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_v7vga_isa); - svga_init(info, &ht216->svga, ht216, mem_size, + svga_init(info, svga, ht216, mem_size, ht216_recalctimings, ht216_in, ht216_out, ht216_hwcursor_draw, NULL); - svga->hwcursor.ysize = 32; + + switch (has_rom) { + case 1: + rom_init(&ht216->bios_rom, BIOS_G2_GC205_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case 2: + rom_init(&ht216->bios_rom, BIOS_VIDEO7_VGA_1024I_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case 3: + ht216->monitor_type = device_get_config_int("monitor_type"); + rom_init(&ht216->bios_rom, BIOS_HT216_32_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + /* Patch the BIOS for monitor type. */ + if (ht216->monitor_type & 0x10) { + /* Color */ + ht216->bios_rom.rom[0x0526] = 0x0c; + ht216->bios_rom.rom[0x0528] = 0xeb; + ht216->bios_rom.rom[0x7fff] += 0x26; + } else { + /* Mono */ + ht216->bios_rom.rom[0x0526] = 0x24; + ht216->bios_rom.rom[0x0527] = 0xef; + ht216->bios_rom.rom[0x0528] = ht216->bios_rom.rom[0x0529] = 0x90; + ht216->bios_rom.rom[0x7fff] += 0xfe; + } + /* Patch bios for interlaced/non-interlaced. */ + if (ht216->monitor_type & 0x08) { + /* Non-Interlaced */ + ht216->bios_rom.rom[0x170b] = 0x0c; + ht216->bios_rom.rom[0x170d] = ht216->bios_rom.rom[0x170e] = 0x90; + ht216->bios_rom.rom[0x7fff] += 0xf4; + } else { + /* Interlaced */ + ht216->bios_rom.rom[0x170b] = 0x24; + ht216->bios_rom.rom[0x170c] = 0xf7; + ht216->bios_rom.rom[0x170d] = 0xeb; + ht216->bios_rom.rom[0x7fff] += 0x1e; + } + break; + case 4: + if ((info->local == 0x7152) && (info->flags & DEVICE_ISA)) + ht216->extensions = device_get_config_int("extensions"); + else if ((info->local == 0x7152) && (info->flags & DEVICE_MCA)) { + ht216->pos_regs[0] = 0xb7; + ht216->pos_regs[1] = 0x80; + mca_add(radius_mca_read, radius_mca_write, radius_mca_feedb, NULL, ht216); + } + rom_init(&ht216->bios_rom, BIOS_RADIUS_SVGA_MULTIVIEW_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + } + + svga->hwcursor.cur_ysize = 32; ht216->vram_mask = mem_size - 1; svga->decode_mask = mem_size - 1; - if (info->flags & DEVICE_VLB) { - mem_mapping_set_handler(&ht216->svga.mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, ht216_writel); - mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, ht216_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &ht216->svga); + if (has_rom == 4) + svga->ramdac = device_add(&sc11484_nors2_ramdac_device); + + if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { + mem_mapping_set_handler(&svga->mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, ht216_writel); + mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, ht216_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga); } else { - mem_mapping_set_handler(&ht216->svga.mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, NULL); - mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, NULL, NULL, MEM_MAPPING_EXTERNAL, &ht216->svga); + mem_mapping_set_handler(&svga->mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, NULL); + mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, NULL, NULL, MEM_MAPPING_EXTERNAL, svga); } - mem_mapping_set_p(&ht216->svga.mapping, ht216); + mem_mapping_set_p(&svga->mapping, ht216); + mem_mapping_disable(&ht216->linear_mapping); + + ht216->id = info->local; + ht216->isabus = (info->flags & DEVICE_ISA); + ht216->mca = (info->flags & DEVICE_MCA); + + io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + io_sethandler(0x46e8, 0x0001, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); svga->bpp = 8; svga->miscout = 1; - ht216->ht_regs[0xb4] = 0x08; /*32-bit DRAM bus*/ - ht216->id = info->local; + if (ht216->id == 0x7861) + ht216->ht_regs[0xb4] = 0x08; /*32-bit DRAM bus*/ + + if (ht216->id == 0x7152) + ht216->reg_3cb = 0x20; + + /* Initialize the cursor pointer towards the end of its segment, needed for ht256sf.drv to work correctly + when Windows 3.1 is started after boot. */ + ht216->ht_regs[0x94] = 0xff; + + svga->adv_flags = 0; return ht216; } @@ -1071,7 +1525,7 @@ void static void * g2_gc205_init(const device_t *info) { - ht216_t *ht216 = ht216_init(info, 1 << 19, 2); + ht216_t *ht216 = ht216_init(info, 1 << 19, 1); return ht216; } @@ -1080,7 +1534,7 @@ g2_gc205_init(const device_t *info) static void * v7_vga_1024i_init(const device_t *info) { - ht216_t *ht216 = ht216_init(info, device_get_config_int("memory") << 10, 1); + ht216_t *ht216 = ht216_init(info, device_get_config_int("memory") << 10, 2); return ht216; } @@ -1095,6 +1549,23 @@ ht216_pb410a_init(const device_t *info) } +static void * +ht216_standalone_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, 1 << 20, 3); + + return ht216; +} + +static void * +radius_svga_multiview_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, 1 << 20, 4); + + return ht216; +} + + static int g2_gc205_available(void) { @@ -1109,6 +1580,19 @@ v7_vga_1024i_available(void) } +static int +ht216_standalone_available(void) +{ + return rom_present(BIOS_HT216_32_PATH); +} + +static int +radius_svga_multiview_available(void) +{ + return rom_present(BIOS_RADIUS_SVGA_MULTIVIEW_PATH); +} + + void ht216_close(void *p) { @@ -1137,64 +1621,171 @@ ht216_force_redraw(void *p) ht216->svga.fullchange = changeframecount; } - -static const device_config_t v7_vga_1024i_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 512, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "" - } - } - }, - { - "", "", -1 +static const device_config_t v7_vga_1024i_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } }; -const device_t g2_gc205_device = -{ - "G2 GC205", - DEVICE_ISA, - 0x7070, - g2_gc205_init, - ht216_close, - NULL, - g2_gc205_available, - ht216_speed_changed, - ht216_force_redraw +// clang-format off +static const device_config_t ht216_32_standalone_config[] = { + { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_int = 0x18, + .selection = { + { + .description = "Mono Interlaced", + .value = 0x00 + }, + { + .description = "Mono Non-Interlaced", + .value = 0x08 + }, + { + .description = "Color Interlaced", + .value = 0x10 + }, + { + .description = "Color Non-Interlaced", + .value = 0x18 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; -const device_t v7_vga_1024i_device = -{ - "Video 7 VGA 1024i", - DEVICE_ISA, - 0x7140, - v7_vga_1024i_init, - ht216_close, - NULL, - v7_vga_1024i_available, - ht216_speed_changed, - ht216_force_redraw, - v7_vga_1024i_config +static const device_config_t radius_svga_multiview_config[] = { + { + .name = "extensions", + .description = "Extensions", + .type = CONFIG_SELECTION, + .default_int = 0x00, + .selection = { + { + .description = "Extensions Enabled", + .value = 0x00 + }, + { + .description = "Extensions Disabled", + .value = 0x02 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +}; +// clang-format on + +const device_t g2_gc205_device = { + .name = "G2 GC205", + .internal_name = "g2_gc205", + .flags = DEVICE_ISA, + .local = 0x7070, + .init = g2_gc205_init, + .close = ht216_close, + .reset = NULL, + { .available = g2_gc205_available }, + .speed_changed = ht216_speed_changed, + .force_redraw = ht216_force_redraw, + .config = NULL }; -const device_t ht216_32_pb410a_device = -{ - "Headland HT216-32 (Packard Bell PB410A)", - DEVICE_VLB, - 0x7861, /*HT216-32*/ - ht216_pb410a_init, - ht216_close, - NULL, - NULL, - ht216_speed_changed, - ht216_force_redraw +const device_t v7_vga_1024i_device = { + .name = "Video 7 VGA 1024i (HT208)", + .internal_name = "v7_vga_1024i", + .flags = DEVICE_ISA, + .local = 0x7140, + .init = v7_vga_1024i_init, + .close = ht216_close, + .reset = NULL, + { .available = v7_vga_1024i_available }, + .speed_changed = ht216_speed_changed, + .force_redraw = ht216_force_redraw, + .config = v7_vga_1024i_config +}; + +const device_t ht216_32_pb410a_device = { + .name = "Headland HT216-32 (Packard Bell PB410A)", + .internal_name = "ht216_32_pb410a", + .flags = DEVICE_VLB, + .local = 0x7861, /*HT216-32*/ + .init = ht216_pb410a_init, + .close = ht216_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ht216_speed_changed, + .force_redraw = ht216_force_redraw, + .config = NULL +}; + +const device_t ht216_32_standalone_device = { + .name = "Headland HT216-32", + .internal_name = "ht216_32", + .flags = DEVICE_VLB, + .local = 0x7861, /*HT216-32*/ + .init = ht216_standalone_init, + .close = ht216_close, + .reset = NULL, + { .available = ht216_standalone_available }, + .speed_changed = ht216_speed_changed, + .force_redraw = ht216_force_redraw, + .config = ht216_32_standalone_config +}; + +const device_t radius_svga_multiview_isa_device = { + .name = "Radius SVGA Multiview ISA (HT209)", + .internal_name = "radius_isa", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0x7152, /*HT209*/ + .init = radius_svga_multiview_init, + .close = ht216_close, + .reset = NULL, + { .available = radius_svga_multiview_available }, + .speed_changed = ht216_speed_changed, + .force_redraw = ht216_force_redraw, + .config = radius_svga_multiview_config +}; + +const device_t radius_svga_multiview_mca_device = { + .name = "Radius SVGA Multiview MCA (HT209)", + .internal_name = "radius_mc", + .flags = DEVICE_MCA, + .local = 0x7152, /*HT209*/ + .init = radius_svga_multiview_init, + .close = ht216_close, + .reset = NULL, + { .available = radius_svga_multiview_available }, + .speed_changed = ht216_speed_changed, + .force_redraw = ht216_force_redraw, + .config = NULL }; diff --git a/src/video/vid_ibm_rgb528_ramdac.c b/src/video/vid_ibm_rgb528_ramdac.c new file mode 100644 index 000000000..f119e722e --- /dev/null +++ b/src/video/vid_ibm_rgb528_ramdac.c @@ -0,0 +1,953 @@ +/* + * 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 the IBM RGB 528 true colour RAMDAC. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> + + +typedef union { + uint8_t pixel; + struct { + uint8_t b :2, g :3, r :2; + }; +} ibm_rgb528_pixel8_t; + +typedef union { + uint16_t pixel; + struct { + uint16_t b_ :5, g_ :6, r_ :5; + }; + struct { + uint16_t b :5, g :5, r :5, c :1; + }; +} ibm_rgb528_pixel16_t; + +typedef union { + uint32_t pixel; + struct { + uint8_t b, g, r, a; + }; +} ibm_rgb528_pixel32_t; + +typedef struct +{ + PALETTE extpal; + uint32_t extpallook[256]; + uint8_t indexed_data[2048]; + uint8_t cursor32_data[256]; + uint8_t cursor64_data[1024]; + uint8_t palettes[3][256]; + ibm_rgb528_pixel32_t extra_pal[4]; + int16_t hwc_y, hwc_x; + uint16_t index, smlc_part; + uint8_t cmd_r0; + uint8_t cmd_r1; + uint8_t cmd_r2; + uint8_t cmd_r3; + uint8_t cmd_r4; + uint8_t status, indx_cntl; + uint8_t cursor_array, + cursor_hotspot_x, cursor_hotspot_y; +} ibm_rgb528_ramdac_t; + + +void +ibm_rgb528_render_4bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb528_pixel32_t dat_out; + uint8_t dat; + uint32_t dat32 = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac; + uint8_t b8_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t partition = (ramdac->indexed_data[0x07] & 0x0f) << 4; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t swap_nib = ramdac->indexed_data[0x72] & 0x21; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x03; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + if (vram_size == 3) { + if (!(x & 31)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); + } + } + if (swap_nib) + dat = (((x & 16) ? dat642 : dat64) >> ((x & 15) << 2)) & 0xf; + else + dat = (((x & 16) ? dat642 : dat64) >> (((x & 15) << 2) ^ 4)) & 0xf; + } else if (vram_size == 1) { + if (!(x & 15)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + if (swap_nib) + dat = (dat64 >> ((x & 15) << 2)) & 0xf; + else + dat = (dat64 >> (((x & 15) << 2) ^ 4)) & 0xf; + } else { + if (!(x & 7)) + dat32 = *(uint32_t *)(&svga->vram[svga->ma]); + if (swap_nib) + dat = (dat32 >> ((x & 7) << 2)) & 0xf; + else + dat = (dat32 >> (((x & 7) << 2) ^ 4)) & 0xf; + } + if (b8_dcol == 0x00) { + dat_out.a = 0x00; + dat_out.r = ramdac->palettes[0][partition | dat]; + dat_out.g = ramdac->palettes[1][partition | dat]; + dat_out.b = ramdac->palettes[2][partition | dat]; + } else + dat_out.pixel = video_8togs[dat]; + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff; + } else + p[x] = dat_out.pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 31) == 31)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + if ((vram_size == 1) && ((x & 15) == 15)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if ((!vram_size) && ((x & 7) == 7)) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb528_render_8bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb528_pixel32_t dat_out; + uint8_t dat; + uint32_t dat32 = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac; + uint8_t b8_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x03; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + if (vram_size == 3) { + if (!(x & 15)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); + } + } + dat = (((x & 8) ? dat642 : dat64) >> ((x & 7) << 3)) & 0xff; + } else if (vram_size == 1) { + if (!(x & 7)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + dat = (dat64 >> ((x & 7) << 3)) & 0xff; + } else { + if (!(x & 3)) + dat32 = *(uint32_t *)(&svga->vram[svga->ma]); + dat = (dat32 >> ((x & 3) << 3)) & 0xff; + } + if (b8_dcol == 0x00) { + dat_out.a = 0x00; + dat_out.r = ramdac->palettes[0][dat]; + dat_out.g = ramdac->palettes[1][dat]; + dat_out.b = ramdac->palettes[2][dat]; + } else + dat_out.pixel = video_8togs[dat]; + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff; + } else + p[x] = dat_out.pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 15) == 15)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 7) == 7)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if ((!vram_size) && ((x & 3) == 3)) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb528_render_15_16bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb528_pixel16_t *dat_ex; + ibm_rgb528_pixel32_t dat_out; + uint16_t dat; + uint32_t dat32 = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac; + uint8_t b16_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t by16_pol = ramdac->indexed_data[0x0c] & 0x20; + uint8_t b555_565 = ramdac->indexed_data[0x0c] & 0x02; + uint8_t bspr_cnt = ramdac->indexed_data[0x0c] & 0x01; + uint8_t partition = (ramdac->indexed_data[0x07] & 0x0e) << 4; + uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80; + uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01, temp; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (b555_565 && (b16_dcol != 0x01)) + partition &= 0xc0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + if (vram_size == 2) { + if (!(x & 7)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat64 << 32ULL) | (dat642 >> 32ULL); + } + } + dat = (((x & 4) ? dat642 : dat64) >> ((x & 3) << 4)) & 0xffff; + } else if (vram_size == 1) { + if (!(x & 3)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + dat = (dat64 >> ((x & 3) << 4)) & 0xffff; + } else { + if (!(x & 1)) + dat32 = *(uint32_t *)(&svga->vram[svga->ma]); + dat = (dat32 >> ((x & 1) << 4)) & 0xffff; + } + dat_ex = (ibm_rgb528_pixel16_t *) &dat; + if (b555_565 && (b16_dcol != 0x01)) { + if (swaprb) { + temp = dat_ex->r_; + dat_ex->r_ = dat_ex->b_; + dat_ex->b_ = temp; + } + if (b16_dcol == 0x00) { + dat_out.a = 0x00; + if (bspr_cnt) { + dat_out.r = ramdac->palettes[0][partition | dat_ex->r_]; + dat_out.g = ramdac->palettes[1][partition | dat_ex->g_]; + dat_out.b = ramdac->palettes[2][partition | dat_ex->b_]; + } else { + dat_out.r = ramdac->palettes[0][dat_ex->r_ << 3]; + dat_out.g = ramdac->palettes[1][dat_ex->g_ << 2]; + dat_out.b = ramdac->palettes[2][dat_ex->b_ << 3]; + } + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_out.r |= ((dat_out.r & 0xc0) >> 6); + dat_out.g |= ((dat_out.g & 0xc0) >> 6); + dat_out.b |= ((dat_out.b & 0xc0) >> 6); + } + } else + dat_out.pixel = video_16to32[dat_ex->pixel]; + } else { + if (swaprb) { + temp = dat_ex->r; + dat_ex->r = dat_ex->b; + dat_ex->b = temp; + } + if (by16_pol) + dat ^= 0x8000; + if ((b16_dcol == 0x00) || ((b16_dcol == 0x01) && !(dat & 0x8000))) { + dat_out.a = 0x00; + if (bspr_cnt) { + dat_out.r = ramdac->palettes[0][partition | dat_ex->r]; + dat_out.g = ramdac->palettes[1][partition | dat_ex->g]; + dat_out.b = ramdac->palettes[2][partition | dat_ex->b]; + } else { + dat_out.r = ramdac->palettes[0][dat_ex->r << 3]; + dat_out.g = ramdac->palettes[1][dat_ex->g << 3]; + dat_out.b = ramdac->palettes[2][dat_ex->b << 3]; + } + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_out.r |= ((dat_out.r & 0xc0) >> 6); + dat_out.g |= ((dat_out.g & 0xc0) >> 6); + dat_out.b |= ((dat_out.b & 0xc0) >> 6); + } + } else + dat_out.pixel = video_15to32[dat_ex->pixel & 0x7fff]; + } + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff; + } else + p[x] = dat_out.pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 7) == 7)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 3) == 3)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if (!vram_size && ((x & 1) == 1)) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb528_render_24bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb528_pixel32_t *dat_ex; + uint32_t dat; + uint64_t dat64[6]; + uint8_t *dat8 = (uint8_t *) dat64; + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac; + uint8_t b24_dcol = ramdac->indexed_data[0x0d] & 0x01; + uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01; + uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80, temp; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat_ex = (ibm_rgb528_pixel32_t *) &dat; + if (vram_size == 3) { + if ((x & 15) == 0) { + dat64[0] = *(uint64_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + dat64[1] = *(uint64_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + dat64[2] = *(uint64_t *)(&svga->vram[(svga->ma + 16) & svga->vram_display_mask]); + dat64[3] = *(uint64_t *)(&svga->vram[(svga->ma + 24) & svga->vram_display_mask]); + dat64[4] = *(uint64_t *)(&svga->vram[(svga->ma + 32) & svga->vram_display_mask]); + dat64[5] = *(uint64_t *)(&svga->vram[(svga->ma + 40) & svga->vram_display_mask]); + if (swap_word) { + dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL); + dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL); + dat64[2] = (dat64[2] << 32ULL) | (dat64[2] >> 32ULL); + dat64[3] = (dat64[3] << 32ULL) | (dat64[3] >> 32ULL); + dat64[4] = (dat64[4] << 32ULL) | (dat64[4] >> 32ULL); + dat64[5] = (dat64[5] << 32ULL) | (dat64[5] >> 32ULL); + } + } + dat_ex = (ibm_rgb528_pixel32_t *) &(dat8[((x & 15) * 3)]); + } else if (vram_size == 1) { + if ((x & 7) == 0) { + dat64[0] = *(uint64_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + dat64[1] = *(uint64_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + dat64[2] = *(uint64_t *)(&svga->vram[(svga->ma + 16) & svga->vram_display_mask]); + if (swap_word) { + dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL); + dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL); + dat64[2] = (dat64[2] << 32ULL) | (dat64[2] >> 32ULL); + } + } + dat_ex = (ibm_rgb528_pixel32_t *) &(dat8[((x & 7) * 3)]); + } else + dat = 0x00000000; + if (swaprb) { + temp = dat_ex->r; + dat_ex->r = dat_ex->b; + dat_ex->b = temp; + } + if (b24_dcol == 0x00) { + dat_ex->a = 0x00; + dat_ex->r = ramdac->palettes[0][dat_ex->r]; + dat_ex->g = ramdac->palettes[1][dat_ex->g]; + dat_ex->g = ramdac->palettes[2][dat_ex->b]; + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_ex->r |= ((dat_ex->r & 0xc0) >> 6); + dat_ex->g |= ((dat_ex->g & 0xc0) >> 6); + dat_ex->b |= ((dat_ex->b & 0xc0) >> 6); + } + } + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_ex->pixel & 0xffffff; + } else + p[x] = dat_ex->pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 15) == 15)) + svga->ma = (svga->ma + 48) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 7) == 7)) + svga->ma = (svga->ma + 24) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb528_render_32bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb528_pixel32_t *dat_ex; + uint32_t dat = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac; + uint8_t b32_dcol = ramdac->indexed_data[0x0e] & 0x03; + uint8_t by32_pol = ramdac->indexed_data[0x0e] & 0x04; + uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01; + uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80, temp; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + if (vram_size == 3) { + if (!(x & 3)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); + } + } + dat = (((x & 2) ? dat642 : dat64) >> ((x & 1ULL) << 5ULL)) & 0xffffffff; + } else if (vram_size == 1) { + if (!(x & 1)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + dat = (dat64 >> ((x & 1ULL) << 5ULL)) & 0xffffffff; + } else + dat = *(uint32_t *)(&svga->vram[svga->ma]); + dat_ex = (ibm_rgb528_pixel32_t *) &dat; + if (swaprb) { + temp = dat_ex->r; + dat_ex->r = dat_ex->b; + dat_ex->b = temp; + } + if ((b32_dcol < 0x03) && (by32_pol)) + dat ^= 0x01000000; + if ((b32_dcol == 0x00) || ((b32_dcol == 0x01) && !(dat & 0x01000000))) { + dat_ex->a = 0x00; + dat_ex->r = ramdac->palettes[0][dat_ex->r]; + dat_ex->g = ramdac->palettes[1][dat_ex->g]; + dat_ex->g = ramdac->palettes[2][dat_ex->b]; + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_ex->r |= ((dat_ex->r & 0xc0) >> 6); + dat_ex->g |= ((dat_ex->g & 0xc0) >> 6); + dat_ex->b |= ((dat_ex->b & 0xc0) >> 6); + } + } + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_ex->pixel & 0xffffff; + } else + p[x] = dat_ex->pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 3) == 3)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 1) == 1)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if (!vram_size) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +static void +ibm_rgb528_set_bpp(ibm_rgb528_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t b16_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t b555_565 = ramdac->indexed_data[0x0c] & 0x02; + + if (ramdac->indexed_data[0x071] & 0x01) + switch (ramdac->indexed_data[0x00a] & 0x07) { + case 0x02: + svga->bpp = 4; + break; + case 0x03: + default: + svga->bpp = 8; + break; + case 0x04: + if (b555_565 && (b16_dcol != 0x01)) + svga->bpp = 16; + else + svga->bpp = 15; + break; + case 0x05: + svga->bpp = 24; + break; + case 0x06: + svga->bpp = 32; + break; + } else + svga->bpp = 8; + + svga_recalctimings(svga); +} + + +void +ibm_rgb528_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) +{ + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) p; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + uint8_t updt_cntl = (ramdac->indexed_data[0x30] & 0x08); + rs |= (!!rs2 << 2); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x03: + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + if (svga->dac_status) + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + index = svga->dac_addr & 255; + if (svga->ramdac_type == RAMDAC_8BIT) + ramdac->palettes[svga->dac_pos][index] = val; + else + ramdac->palettes[svga->dac_pos][index] = (val & 0x3f) << 2; + svga_out(addr, val, svga); + break; + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + svga_out(addr, val, svga); + break; + case 0x04: + ramdac->index = (ramdac->index & 0x0700) | val; + if ((ramdac->index >= 0x0100) && (ramdac->index <= 0x04ff)) + ramdac->cursor_array = 1; + break; + case 0x05: + ramdac->index = (ramdac->index & 0x00ff) | ((val & 0x07) << 0x08); + if ((ramdac->index >= 0x0100) && (ramdac->index <= 0x04ff)) + ramdac->cursor_array = 1; + break; + case 0x06: + if ((ramdac->index < 0x0100) || (ramdac->index > 0x04ff) || ramdac->cursor_array) + ramdac->indexed_data[ramdac->index] = val; + switch (ramdac->index) { + case 0x00a: case 0x00c: + ibm_rgb528_set_bpp(ramdac, svga); + break; + case 0x030: + switch (val & 0xc0) { + case 0x00: + ramdac->smlc_part = 0x0100; + break; + case 0x40: + ramdac->smlc_part = 0x0200; + break; + case 0x80: + ramdac->smlc_part = 0x0300; + break; + case 0xc0: + ramdac->smlc_part = 0x0400; + break; + } + svga->dac_hwcursor.addr = ramdac->smlc_part; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = (val & 0x04) ? 64 : 32; + svga->dac_hwcursor.ena = ((val & 0x03) != 0x00); + break; + case 0x031: + if (!updt_cntl) + break; + ramdac->hwc_x = (ramdac->hwc_x & 0xff00) | val; + svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x; + break; + case 0x032: + /* Sign-extend the sign bit (7) to the remaining bits (6-4). */ + val &= 0x8f; + if (val & 0x80) + val |= 0x70; + ramdac->indexed_data[ramdac->index] = val; + if (!updt_cntl) + break; + ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | (val << 8); + svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x; + break; + case 0x033: + if (!updt_cntl) + break; + ramdac->hwc_y = (ramdac->hwc_y & 0xff00) | val; + svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y; + break; + case 0x034: + /* Sign-extend the sign bit (7) to the remaining bits (6-4). */ + val &= 0x8f; + if (val & 0x80) + val |= 0x70; + ramdac->indexed_data[ramdac->index] = val; + if (updt_cntl) { + ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | (val << 8); + svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y; + } else { + ramdac->hwc_x = ramdac->indexed_data[0x031]; + ramdac->hwc_x |= (ramdac->indexed_data[0x032] << 8); + ramdac->hwc_y = ramdac->indexed_data[0x033]; + ramdac->hwc_y |= (val << 8); + svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x; + svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y; + } + break; + case 0x035: + if (svga->dac_hwcursor.cur_xsize == 64) + ramdac->cursor_hotspot_x = (val & 0x3f); + else + ramdac->cursor_hotspot_x = (val & 0x1f); + svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x; + break; + case 0x036: + if (svga->dac_hwcursor.cur_xsize == 64) + ramdac->cursor_hotspot_y = (val & 0x3f); + else + ramdac->cursor_hotspot_y = (val & 0x1f); + svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y; + break; + case 0x040: case 0x043: case 0x046: + ramdac->extra_pal[(ramdac->index - 0x40) / 3].r = val; + break; + case 0x041: case 0x044: case 0x047: + ramdac->extra_pal[(ramdac->index - 0x41) / 3].g = val; + break; + case 0x042: case 0x045: case 0x048: + ramdac->extra_pal[(ramdac->index - 0x42) / 3].b = val; + break; + case 0x060: + ramdac->extra_pal[3].r = val; + break; + case 0x061: + ramdac->extra_pal[3].g = val; + break; + case 0x062: + ramdac->extra_pal[3].b = val; + break; + case 0x071: + svga->ramdac_type = (val & 0x04) ? RAMDAC_8BIT : RAMDAC_6BIT; + ibm_rgb528_set_bpp(ramdac, svga); + break; + default: + break; + } + if (ramdac->indx_cntl) { + if (ramdac->index == 0x00ff) + ramdac->cursor_array = 0; + ramdac->index = (ramdac->index + 1) & 0x07ff; + } + break; + case 0x07: + ramdac->indx_cntl = val & 0x01; + break; + } + + return; +} + + +uint8_t +ibm_rgb528_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) +{ + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) p; + uint8_t temp = 0xff; + uint8_t rs = (addr & 0x03); + uint8_t loc_read = (ramdac->indexed_data[0x30] & 0x10); + rs |= (!!rs2 << 2); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + temp = svga->dac_addr & 0xff; + if (ramdac->indexed_data[0x070] & 0x20) + temp = (temp & 0xfc) | svga->dac_status; + break; + case 0x04: + temp = ramdac->index & 0xff; + break; + case 0x05: + temp = ramdac->index >> 8; + break; + case 0x06: + temp = ramdac->indexed_data[ramdac->index]; + switch (ramdac->index) { + case 0x0000: /* Revision */ + temp = 0xe0; + break; + case 0x0001: /* ID */ + temp = 0x02; + break; + case 0x0031: + if (loc_read) + temp = ramdac->hwc_x & 0xff; + break; + case 0x0032: + if (loc_read) + temp = ramdac->hwc_x >> 8; + break; + case 0x0033: + if (loc_read) + temp = ramdac->hwc_y & 0xff; + break; + case 0x0034: + if (loc_read) + temp = ramdac->hwc_y >> 8; + break; + default: + temp = ramdac->indexed_data[ramdac->index]; + break; + } + if (ramdac->indx_cntl) { + if (ramdac->index == 0x00ff) + ramdac->cursor_array = 0; + ramdac->index = (ramdac->index + 1) & 0x07ff; + } + break; + case 0x07: + temp = ramdac->indx_cntl; + break; + } + + return temp; +} + + +void +ibm_rgb528_recalctimings(void *p, svga_t *svga) +{ + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) p; + + svga->interlace = ramdac->indexed_data[0x071] & 0x20; + + if (svga->scrblank || !svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (((svga->gdcreg[5] & 0x60) == 0x40) || ((svga->gdcreg[5] & 0x60) == 0x60)) { + if (ramdac->indexed_data[0x071] & 0x01) { + switch (svga->bpp) { + case 4: + svga->render = ibm_rgb528_render_4bpp; + break; + case 8: + svga->render = ibm_rgb528_render_8bpp; + break; + case 15: case 16: + svga->render = ibm_rgb528_render_15_16bpp; + break; + case 24: + svga->render = ibm_rgb528_render_24bpp; + break; + case 32: + svga->render = ibm_rgb528_render_32bpp; + break; + } + } + } + } + } +} + + +void +ibm_rgb528_hwcursor_draw(svga_t *svga, int displine) +{ + uint8_t dat, four_pixels = 0x00; + int x, pitch, x_pos, y_pos, offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff; + uint32_t *p; + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac; + uint8_t pix_ordr = ramdac->indexed_data[0x30] & 0x20; + uint8_t cursor_mode = ramdac->indexed_data[0x30] & 0x03; + + /* The planes come in one part, and each plane is 2bpp, + so a 32x32 cursor has 8 bytes per line, and a 64x64 + cursor has 16 bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 2); /* Bytes per line. */ + + if ((ramdac->indexed_data[0x071] & 0x20) && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + for (x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x++) { + if (!(x & 3)) + four_pixels = ramdac->indexed_data[svga->dac_hwcursor_latch.addr]; + + if (pix_ordr) + dat = (four_pixels >> (((3 - x) & 3) << 1)) & 0x03; + else + dat = (four_pixels >> ((x & 3) << 1)) & 0x03; + + x_pos = offset + svga->x_add + x; + + switch (cursor_mode) { + case 0x01: + switch (dat) { + case 0x01: + /* Cursor Color 1 */ + p[x_pos] = ramdac->extra_pal[0].pixel; + break; + case 0x02: + /* Cursor Color 2 */ + p[x_pos] = ramdac->extra_pal[1].pixel; + break; + case 0x03: + /* Cursor Color 3 */ + p[x_pos] = ramdac->extra_pal[2].pixel; + break; + } + break; + case 0x02: + switch (dat) { + case 0x00: + /* Cursor Color 1 */ + p[x_pos] = ramdac->extra_pal[0].pixel; + break; + case 0x01: + /* Cursor Color 2 */ + p[x_pos] = ramdac->extra_pal[1].pixel; + break; + case 0x03: + /* Complement */ + p[x_pos] ^= 0xffffff; + break; + } + break; + case 0x03: + switch (dat) { + case 0x02: + /* Cursor Color 1 */ + p[x_pos] = ramdac->extra_pal[0].pixel; + break; + case 0x03: + /* Cursor Color 2 */ + p[x_pos] = ramdac->extra_pal[1].pixel; + break; + } + break; + } + + if ((x & 3) == 3) + svga->dac_hwcursor_latch.addr++; + } + + if ((ramdac->indexed_data[0x071] & 0x20) && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; +} + + +void * +ibm_rgb528_ramdac_init(const device_t *info) +{ + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) malloc(sizeof(ibm_rgb528_ramdac_t)); + memset(ramdac, 0, sizeof(ibm_rgb528_ramdac_t)); + + ramdac->smlc_part = 0x0100; + + ramdac->indexed_data[0x0008] = 0x0001; + ramdac->indexed_data[0x0015] = 0x0008; + ramdac->indexed_data[0x0016] = 0x0041; + + return ramdac; +} + + +static void +ibm_rgb528_ramdac_close(void *priv) +{ + ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + +const device_t ibm_rgb528_ramdac_device = { + .name = "IBM RGB528 RAMDAC", + .internal_name = "ibm_rgb528_ramdac", + .flags = 0, + .local = 0, + .init = ibm_rgb528_ramdac_init, + .close = ibm_rgb528_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_icd2061.c b/src/video/vid_icd2061.c index 460ee6242..cb7ffecbe 100644 --- a/src/video/vid_icd2061.c +++ b/src/video/vid_icd2061.c @@ -98,7 +98,7 @@ icd2061_write(void *p, int val) if (icd2061->bit_count == 26) { icd2061_log("26 bits received, data = %08X\n", icd2061->data); - + a = ((icd2061->data >> 22) & 0x07); /* A */ icd2061_log("A = %01X\n", a); @@ -165,20 +165,30 @@ icd2061_close(void *priv) free(icd2061); } - -const device_t icd2061_device = -{ - "ICD2061 Clock Generator", - 0, 0, - icd2061_init, icd2061_close, - NULL, NULL, NULL, NULL +const device_t icd2061_device = { + .name = "ICD2061 Clock Generator", + .internal_name = "icd2061", + .flags = 0, + .local = 0, + .init = icd2061_init, + .close = icd2061_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t ics9161_device = -{ - "ICS9161 Clock Generator", - 0, 0, - icd2061_init, icd2061_close, - NULL, NULL, NULL, NULL +const device_t ics9161_device = { + .name = "ICS9161 Clock Generator", + .internal_name = "ics9161", + .flags = 0, + .local = 0, + .init = icd2061_init, + .close = icd2061_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_ics2494.c b/src/video/vid_ics2494.c new file mode 100644 index 000000000..f06726e02 --- /dev/null +++ b/src/video/vid_ics2494.c @@ -0,0 +1,119 @@ +/* + * 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. + * + * ICS2494 clock generator emulation. + * + * Used by the AMI S3 924. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> + + +typedef struct ics2494_t +{ + float freq[16]; +} ics2494_t; + + +#ifdef ENABLE_ics2494_LOG +int ics2494_do_log = ENABLE_ics2494_LOG; + + +static void +ics2494_log(const char *fmt, ...) +{ + va_list ap; + + if (ics2494_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ics2494_log(fmt, ...) +#endif + + +float +ics2494_getclock(int clock, void *p) +{ + ics2494_t *ics2494 = (ics2494_t *) p; + + if (clock > 16) + clock = 16; + + return ics2494->freq[clock]; +} + + +static void * +ics2494_init(const device_t *info) +{ + ics2494_t *ics2494 = (ics2494_t *) malloc(sizeof(ics2494_t)); + memset(ics2494, 0, sizeof(ics2494_t)); + + switch (info->local) { + case 305: + /* ICS2494A(N)-205 for S3 86C924 */ + ics2494->freq[0x0] = 25175000.0; + ics2494->freq[0x1] = 28322000.0; + ics2494->freq[0x2] = 40000000.0; + ics2494->freq[0x3] = 0.0; + ics2494->freq[0x4] = 50000000.0; + ics2494->freq[0x5] = 77000000.0; + ics2494->freq[0x6] = 36000000.0; + ics2494->freq[0x7] = 44889000.0; + ics2494->freq[0x8] = 130000000.0; + ics2494->freq[0x9] = 120000000.0; + ics2494->freq[0xa] = 80000000.0; + ics2494->freq[0xb] = 31500000.0; + ics2494->freq[0xc] = 110000000.0; + ics2494->freq[0xd] = 65000000.0; + ics2494->freq[0xe] = 75000000.0; + ics2494->freq[0xf] = 94500000.0; + break; + } + + return ics2494; +} + + +static void +ics2494_close(void *priv) +{ + ics2494_t *ics2494 = (ics2494_t *) priv; + + if (ics2494) + free(ics2494); +} + +const device_t ics2494an_305_device = { + .name = "ICS2494AN-305 Clock Generator", + .internal_name = "ics2494an_305", + .flags = 0, + .local = 305, + .init = ics2494_init, + .close = ics2494_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_ics2595.c b/src/video/vid_ics2595.c index 0aaef288f..e36c4048e 100644 --- a/src/video/vid_ics2595.c +++ b/src/video/vid_ics2595.c @@ -74,7 +74,7 @@ ics2595_write(void *p, int strobe, int dat) ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; ics2595->state = ICS2595_IDLE; } - break; + break; } } @@ -123,11 +123,16 @@ ics2595_setclock(void *p, double clock) ics2595->output_clock = clock; } - -const device_t ics2595_device = -{ - "ICS2595 clock chip", - 0, 0, - ics2595_init, ics2595_close, - NULL, NULL, NULL, NULL +const device_t ics2595_device = { + .name = "ICS2595 clock chip", + .internal_name = "ics2595", + .flags = 0, + .local = 0, + .init = ics2595_init, + .close = ics2595_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c index 33c3d491d..932faecb7 100644 --- a/src/video/vid_im1024.c +++ b/src/video/vid_im1024.c @@ -22,12 +22,12 @@ * As well as the usual PGC ring buffer at 0xC6000, the IM1024 * appears to have an alternate method of passing commands. This * is enabled by setting 0xC6330 to 1, and then: - * + * * CX = count to write * SI -> bytes to write - * + * * Set pending bytes to 0 - * Read [C6331]. This gives number of bytes that can be written: + * Read [C6331]. This gives number of bytes that can be written: * 0xFF => 0, 0xFE => 1, 0xFD => 2 etc. * Write that number of bytes to C6000. * If there are more to come, go back to reading [C6331]. @@ -62,11 +62,12 @@ #include <86box/device.h> #include <86box/pit.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> #include <86box/vid_pgc.h> -#define BIOS_ROM_PATH L"roms/video/im1024/im1024font.bin" +#define BIOS_ROM_PATH "roms/video/im1024/im1024font.bin" typedef struct { @@ -129,7 +130,7 @@ fifo_write(im1024_t *dev, uint8_t val) dev->fifo_len *= 2; } - /* Append to the queue. */ + /* Append to the queue. */ dev->fifo[dev->fifo_wrptr++] = val; /* Wrap if end of buffer reached. */ @@ -171,7 +172,7 @@ input_byte(pgc_t *pgc, uint8_t *result) while (!pgc->stopped && (dev->fifo_wrptr == dev->fifo_rdptr) && (pgc->mapram[0x300] == pgc->mapram[0x301])) { pgc->waiting_input_fifo = 1; - pgc_sleep(pgc); + pgc_sleep(pgc); } if (pgc->stopped) @@ -205,13 +206,13 @@ input_byte(pgc_t *pgc, uint8_t *result) pgc->vp_x2 = pgc->maxw - 1; \ pgc->vp_y2 = pgc->maxh - 1; \ -/* And to restore clip state */ +/* And to restore clip state */ #define POPCLIP \ pgc->vp_x1 = vp_x1; \ pgc->vp_y1 = vp_y1; \ pgc->vp_x2 = vp_x2; \ pgc->vp_y2 = vp_y2; \ - } + } /* Override memory read to return FIFO space. */ @@ -296,8 +297,8 @@ hndl_iprec(pgc_t *pgc) /* - * Set drawing mode. - * + * Set drawing mode. + * * 0 => Draw * 1 => Invert * 2 => XOR (IM-1024) @@ -539,8 +540,8 @@ hndl_poly(pgc_t *pgc) } if (count + realcount >= as) { - nx = (int32_t *)realloc(x, 2 * as * sizeof(int32_t)); - ny = (int32_t *)realloc(y, 2 * as * sizeof(int32_t)); + nx = (int32_t *)realloc(x, 2 * as * sizeof(int32_t)); + ny = (int32_t *)realloc(y, 2 * as * sizeof(int32_t)); if (!x || !y) { #ifdef ENABLE_IM1024_LOG im1024_log("IM1024: poly: realloc failed\n"); @@ -569,7 +570,7 @@ hndl_poly(pgc_t *pgc) } /* Skip degenerate line segments. */ - if (realcount > 0 && + if (realcount > 0 && (xw << 16) == x[realcount - 1] && (yw << 16) == y[realcount - 1]) continue; @@ -631,7 +632,7 @@ parse_poly(pgc_t *pgc, pgc_cl_t *cl, int c) im1024_log("IM1024: parse_poly: count=%02x\n", count); if (! pgc_cl_append(cl, count)) { pgc_error(pgc, PGC_ERROR_OVERFLOW); - return 0; + return 0; } im1024_log("IM1024: parse_poly: parse %i words\n", 2 * count); @@ -669,10 +670,10 @@ hndl_rect(pgc_t *pgc) } else { /* Outline: 4 lines. */ p = pgc->line_pattern; - p = pgc_draw_line_r(pgc, x0, y0, x1, y0, p); - p = pgc_draw_line_r(pgc, x1, y0, x1, y1, p); - p = pgc_draw_line_r(pgc, x1, y1, x0, y1, p); - p = pgc_draw_line_r(pgc, x0, y1, x0, y0, p); + p = pgc_draw_line_r(pgc, x0, y0, x1, y0, p); + p = pgc_draw_line_r(pgc, x1, y0, x1, y1, p); + p = pgc_draw_line_r(pgc, x1, y1, x0, y1, p); + p = pgc_draw_line_r(pgc, x0, y1, x0, y0, p); } } @@ -746,7 +747,7 @@ hndl_twrite(pgc_t *pgc) for (n = 0; n < count; n++) { wb = (dev->fontx[buf[n]] + 7) / 8; - im1024_log("IM1024: ch=0x%02x w=%i h=%i wb=%i\n", + im1024_log("IM1024: ch=0x%02x w=%i h=%i wb=%i\n", buf[n], dev->fontx[buf[n]], dev->fonty[buf[n]], wb); for (y = 0; y < dev->fonty[buf[n]]; y++) { @@ -851,7 +852,7 @@ hndl_imagew(pgc_t *pgc) if (v1 & 0x80) { /* Literal run. */ v1 -= 0x7f; - while (col1 <= col2 && v1 != 0) { + while (col1 <= col2 && v1 != 0) { if (! pgc_param_byte(pgc, &v2)) return; pgc_write_pixel(pgc, col1, row1, v2); col1++; @@ -862,12 +863,12 @@ hndl_imagew(pgc_t *pgc) if (! pgc_param_byte(pgc, &v2)) return; v1++; - while (col1 <= col2 && v1 != 0) { + while (col1 <= col2 && v1 != 0) { pgc_write_pixel(pgc, col1, row1, v2); col1++; v1--; } - } + } } } @@ -890,7 +891,7 @@ hndl_dot(pgc_t *pgc) int16_t x = pgc->x >> 16, y = pgc->y >> 16; - pgc_sto_raster(pgc, &x, &y); + pgc_sto_raster(pgc, &x, &y); im1024_log("IM1024: DOT @ %i,%i ink=%i mode=%i\n", x, y, pgc->color, pgc->draw_mode); @@ -900,9 +901,9 @@ hndl_dot(pgc_t *pgc) /* - * This command (which I have called IMAGEX, since I don't know its real + * This command (which I have called IMAGEX, since I don't know its real * name) is a screen-to-memory blit. It reads a rectangle of bytes, rather - * than the single row read by IMAGER, and does not attempt to compress + * than the single row read by IMAGER, and does not attempt to compress * the result. */ static void @@ -1007,7 +1008,7 @@ im1024_close(void *priv) { im1024_t *dev = (im1024_t *)priv; - pgc_close(&dev->pgc); + pgc_close_common(&dev->pgc); free(dev); } @@ -1030,11 +1031,15 @@ im1024_speed_changed(void *priv) const device_t im1024_device = { - "ImageManager 1024", - DEVICE_ISA, 0, - im1024_init, im1024_close, NULL, - im1024_available, - im1024_speed_changed, - NULL, - NULL + .name = "ImageManager 1024", + .internal_name = "im1024", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = im1024_init, + .close = im1024_close, + .reset = NULL, + { .available = im1024_available }, + .speed_changed = im1024_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_incolor.c b/src/video/vid_incolor.c index 763b62a4e..d44321863 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_incolor.c @@ -225,7 +225,7 @@ incolor_out(uint16_t port, uint8_t val, void *priv) if (dev->crtcreg == INCOLOR_CRTC_PALETTE) { dev->palette[dev->palette_idx % 16] = val; ++dev->palette_idx; - } + } old = dev->crtc[dev->crtcreg]; dev->crtc[dev->crtcreg] = val; @@ -320,7 +320,7 @@ incolor_write(uint32_t addr, uint8_t val, void *priv) * 0: 1 => foreground, 0 => background * 1: 1 => foreground, 0 => source latch * 2: 1 => source latch, 0 => background - * 3: 1 => source latch, 0 => ~source latch + * 3: 1 => source latch, 0 => ~source latch */ pmask = 1; for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, plane++) { @@ -354,7 +354,7 @@ incolor_write(uint32_t addr, uint8_t val, void *priv) /* w is nonzero to write a 1, zero to write a 0 */ if (w) dev->vram[addr] |= vmask; - else dev->vram[addr] &= ~vmask; + else dev->vram[addr] &= ~vmask; } } } @@ -394,15 +394,15 @@ incolor_read(uint32_t addr, void *priv) bg = (dev->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) { if (dc & pmask) { - fg |= (bg & pmask); + fg |= (bg & pmask); } else if (dev->latch[plane] & mask) { fg |= pmask; } - } + } if (bg == fg) value |= mask; - } + } - if (dev->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) + if (dev->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) value = ~value; return value; @@ -422,16 +422,16 @@ draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) int cw = INCOLOR_CW; blk = 0; - if (dev->ctrl & INCOLOR_CTRL_BLINK) + if (dev->ctrl & INCOLOR_CTRL_BLINK) { - if (attr & 0x80) + if (attr & 0x80) { blk = (dev->blink & 16); } attr &= 0x7f; } - if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) { /* MDA-compatible attributes */ ibg = 0; @@ -440,12 +440,12 @@ draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) { ifg = 0; ibg = 7; - } - if (attr & 8) + } + if (attr & 8) { ifg |= 8; /* High intensity FG */ } - if (attr & 0x80) + if (attr & 0x80) { ibg |= 8; /* High intensity BG */ } @@ -454,31 +454,31 @@ draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) ifg = ibg; } ull = ((attr & 0x07) == 1) ? 13 : 0xffff; - } - else + } + else { /* CGA-compatible attributes */ ull = 0xffff; ifg = attr & 0x0F; ibg = (attr >> 4) & 0x0F; } - if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) { fg = dev->rgb[dev->palette[ifg]]; bg = dev->rgb[dev->palette[ibg]]; - } - else + } + else { fg = dev->rgb[defpal[ifg]]; bg = dev->rgb[defpal[ibg]]; } /* ELG set to stretch 8px character to 9px */ - if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; - } - else + } + else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } @@ -489,20 +489,20 @@ draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) { val = 0x000; /* Blinking, draw all background */ } - else if (dev->sc == ull) + else if (dev->sc == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } - else + else { val = fnt[0] << 1; - - if (elg) + + if (elg) { val |= (val >> 1) & 1; } } - for (i = 0; i < cw; i++) + for (i = 0; i < cw; i++) { buffer32->line[dev->displine][x * cw + i] = (val & 0x100) ? fg : bg; val = val << 1; @@ -528,7 +528,7 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) blk = 0; if (blink) { - if (attr & 0x80) + if (attr & 0x80) { blk = (dev->blink & 16); } @@ -544,12 +544,12 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) { ifg = 0; ibg = 7; - } - if (attr & 8) + } + if (attr & 8) { ifg |= 8; /* High intensity FG */ } - if (attr & 0x80) + if (attr & 0x80) { ibg |= 8; /* High intensity BG */ } @@ -558,19 +558,19 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) ifg = ibg; } ull = ((attr & 0x07) == 1) ? 13 : 0xffff; - } - else + } + else { /* CGA-compatible attributes */ ull = 0xffff; ifg = attr & 0x0F; ibg = (attr >> 4) & 0x0F; } - if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; - } - else + } + else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } @@ -579,21 +579,21 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) if (blk) { /* Blinking, draw all background */ - val[0] = val[1] = val[2] = val[3] = 0x000; + val[0] = val[1] = val[2] = val[3] = 0x000; } - else if (dev->sc == ull) + else if (dev->sc == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; } - else + else { val[0] = fnt[0x00000] << 1; val[1] = fnt[0x10000] << 1; val[2] = fnt[0x20000] << 1; val[3] = fnt[0x30000] << 1; - - if (elg) + + if (elg) { val[0] |= (val[0] >> 1) & 1; val[1] |= (val[1] >> 1) & 1; @@ -601,7 +601,7 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) val[3] |= (val[3] >> 1) & 1; } } - for (i = 0; i < cw; i++) + for (i = 0; i < cw; i++) { /* Generate pixel colour */ cfg = 0; @@ -616,12 +616,12 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) if (palette) { fg = dev->rgb[dev->palette[cfg]]; - } - else + } + else { fg = dev->rgb[defpal[cfg]]; } - + buffer32->line[dev->displine][x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; @@ -652,31 +652,31 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) blk = 0; if (blink && altattr) { - if (attr & 0x40) + if (attr & 0x40) { blk = (dev->blink & 16); } attr &= 0x7f; } - if (altattr) + if (altattr) { /* MDA-compatible attributes */ - if (blink) + if (blink) { ibg = (attr & 0x80) ? 8 : 0; bld = 0; ol = (attr & 0x20) ? 1 : 0; ul = (attr & 0x10) ? 1 : 0; - } - else + } + else { bld = (attr & 0x80) ? 1 : 0; ibg = (attr & 0x40) ? 0x0F : 0; ol = (attr & 0x20) ? 1 : 0; ul = (attr & 0x10) ? 1 : 0; } - } - else + } + else { /* CGA-compatible attributes */ ibg = 0; @@ -685,32 +685,32 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) ul = 0; bld = 0; } - if (ul) - { + if (ul) + { ull = dev->crtc[INCOLOR_CRTC_UNDER] & 0x0F; ulc = (dev->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; if (ulc == 0) ulc = 7; - } - else + } + else { ull = 0xFFFF; } - if (ol) - { + if (ol) + { oll = dev->crtc[INCOLOR_CRTC_OVER] & 0x0F; olc = (dev->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; if (olc == 0) olc = 7; - } - else + } + else { oll = 0xFFFF; } - if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; - } - else + } + else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } @@ -719,28 +719,28 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) if (blk) { /* Blinking, draw all background */ - val[0] = val[1] = val[2] = val[3] = 0x000; + val[0] = val[1] = val[2] = val[3] = 0x000; } - else if (dev->sc == ull) + else if (dev->sc == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; } - else + else { val[0] = fnt[0x00000] << 1; val[1] = fnt[0x10000] << 1; val[2] = fnt[0x20000] << 1; val[3] = fnt[0x30000] << 1; - - if (elg) + + if (elg) { val[0] |= (val[0] >> 1) & 1; val[1] |= (val[1] >> 1) & 1; val[2] |= (val[2] >> 1) & 1; val[3] |= (val[3] >> 1) & 1; } - if (bld) + if (bld) { val[0] |= (val[0] >> 1); val[1] |= (val[1] >> 1); @@ -748,7 +748,7 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) val[3] |= (val[3] >> 1); } } - for (i = 0; i < cw; i++) + for (i = 0; i < cw; i++) { /* Generate pixel colour */ cfg = 0; @@ -776,12 +776,12 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) if (palette) { fg = dev->rgb[dev->palette[cfg]]; - } - else + } + else { fg = dev->rgb[defpal[cfg]]; } - + buffer32->line[dev->displine][x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; @@ -829,17 +829,17 @@ text_line(incolor_t *dev, uint16_t ca) uint8_t ink = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; if (ink == 0) ink = (attr & 0x08) | 7; - /* In MDA-compatible mode, cursor brightness comes from + /* In MDA-compatible mode, cursor brightness comes from * background */ - if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) { ink = (attr & 0x08) | (ink & 7); } - if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) { col = dev->rgb[dev->palette[ink]]; - } - else + } + else { col = dev->rgb[defpal[ink]]; } @@ -871,8 +871,8 @@ graphics_line(incolor_t *dev) for (plane = 0; plane < 4; plane++, mask = mask >> 1) { if (dev->ctrl & 8) { - if (mask & 1) - val[plane] = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | + if (mask & 1) + val[plane] = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; else val[plane] = 0; } else @@ -914,7 +914,7 @@ incolor_poll(void *priv) dev->stat |= 1; dev->linepos = 1; oldsc = dev->sc; - if ((dev->crtc[8] & 3) == 3) + if ((dev->crtc[8] & 3) == 3) dev->sc = (dev->sc << 1) & 7; if (dev->dispon) { @@ -932,11 +932,11 @@ incolor_poll(void *priv) if (dev->vc == dev->crtc[7] && !dev->sc) dev->stat |= 8; dev->displine++; - if (dev->displine >= 500) + if (dev->displine >= 500) dev->displine = 0; } else { timer_advance_u64(&dev->timer, dev->dispontime); - if (dev->dispon) + if (dev->dispon) dev->stat &= ~1; dev->linepos = 0; if (dev->vsynctime) { @@ -945,9 +945,9 @@ incolor_poll(void *priv) dev->stat &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; - dev->coff = 1; + if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { + dev->con = 0; + dev->coff = 1; } if (dev->vadj) { @@ -966,7 +966,7 @@ incolor_poll(void *priv) oldvc = dev->vc; dev->vc++; dev->vc &= 127; - if (dev->vc == dev->crtc[6]) + if (dev->vc == dev->crtc[6]) dev->dispon = 0; if (oldvc == dev->crtc[4]) { dev->vc = 0; @@ -982,7 +982,7 @@ incolor_poll(void *priv) dev->displine = 0; dev->vsynctime = 16; if (dev->crtc[7]) { - if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) + if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) x = dev->crtc[1] << 4; else x = dev->crtc[1] * 9; @@ -998,7 +998,7 @@ incolor_poll(void *priv) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen(0, dev->firstline, 0, dev->lastline - dev->firstline, xsize, dev->lastline - dev->firstline); + video_blit_memtoscreen(0, dev->firstline, xsize, dev->lastline - dev->firstline); frames++; if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) { video_res_x = dev->crtc[1] * 16; @@ -1055,7 +1055,7 @@ incolor_init(const device_t *info) dev->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; dev->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ dev->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; - for (c = 0; c < 16; c++) + for (c = 0; c < 16; c++) dev->palette[c] = defpal[c]; dev->palette_idx = 0; @@ -1087,18 +1087,20 @@ static void speed_changed(void *priv) { incolor_t *dev = (incolor_t *)priv; - + recalc_timings(dev); } - const device_t incolor_device = { - "Hercules InColor", - DEVICE_ISA, - 0, - incolor_init, incolor_close, NULL, - NULL, - speed_changed, - NULL, - NULL + .name = "Hercules InColor", + .internal_name = "incolor", + .flags = DEVICE_ISA, + .local = 0, + .init = incolor_init, + .close = incolor_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 002f082e5..0a4ed3c47 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -79,14 +79,12 @@ uint8_t mda_in(uint16_t addr, void *p) void mda_write(uint32_t addr, uint8_t val, void *p) { mda_t *mda = (mda_t *)p; - egawrites++; mda->vram[addr & 0xfff] = val; } uint8_t mda_read(uint32_t addr, void *p) { mda_t *mda = (mda_t *)p; - egareads++; return mda->vram[addr & 0xfff]; } @@ -112,13 +110,15 @@ void mda_poll(void *p) uint8_t chr, attr; int oldsc; int blink; + + VIDEO_MONITOR_PROLOGUE() if (!mda->linepos) { timer_advance_u64(&mda->timer, mda->dispofftime); mda->stat |= 1; mda->linepos = 1; oldsc = mda->sc; - if ((mda->crtc[8] & 3) == 3) + if ((mda->crtc[8] & 3) == 3) mda->sc = (mda->sc << 1) & 7; if (mda->dispon) { @@ -160,7 +160,7 @@ void mda_poll(void *p) mda->stat |= 8; } mda->displine++; - if (mda->displine >= 500) + if (mda->displine >= 500) mda->displine=0; } else @@ -176,10 +176,10 @@ void mda_poll(void *p) mda->stat&=~8; } } - if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) - { - mda->con = 0; - mda->coff = 1; + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) + { + mda->con = 0; + mda->coff = 1; } if (mda->vadj) { @@ -201,7 +201,7 @@ void mda_poll(void *p) oldvc = mda->vc; mda->vc++; mda->vc &= 127; - if (mda->vc == mda->crtc[6]) + if (mda->vc == mda->crtc[6]) mda->dispon=0; if (oldvc == mda->crtc[4]) { @@ -232,7 +232,7 @@ void mda_poll(void *p) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen_8(0, mda->firstline, 0, ysize, xsize, ysize); + video_blit_memtoscreen_8(0, mda->firstline, xsize, ysize); frames++; video_res_x = mda->crtc[1]; video_res_y = mda->crtc[6]; @@ -254,6 +254,7 @@ void mda_poll(void *p) mda->con = 1; } } + VIDEO_MONITOR_EPILOGUE(); } void mda_init(mda_t *mda) @@ -280,13 +281,14 @@ void mda_init(mda_t *mda) mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; overscan_x = overscan_y = 0; + mda->monitor_index = monitor_index_global; cga_palette = device_get_config_int("rgb_type") << 1; if (cga_palette > 6) { cga_palette = 0; } - cgapal_rebuild(); + cgapal_rebuild(); timer_add(&mda->timer, mda_poll, mda, 1); } @@ -325,45 +327,55 @@ void mda_close(void *p) void mda_speed_changed(void *p) { mda_t *mda = (mda_t *)p; - + mda_recalctimings(mda); } -static const device_config_t mda_config[] = -{ - { - "rgb_type", "Display type", CONFIG_SELECTION, "", 0, - { - { - "Default", 0 - }, - { - "Green", 1 - }, - { - "Amber", 2 - }, - { - "Gray", 3 - }, - { - "" - } - } - }, - { - "", "", -1 +static const device_config_t mda_config[] = { +// clang-format off + { + .name = "rgb_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "Default", + .value = 0 + }, + { + .description = "Green", + .value = 1 + }, + { + .description = "Amber", + .value = 2 + }, + { + .description = "Gray", + .value = 3 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } +// clang-format on }; - -const device_t mda_device = -{ - "MDA", - DEVICE_ISA, 0, - mda_standalone_init, mda_close, NULL, - NULL, - mda_speed_changed, - NULL, - mda_config +const device_t mda_device = { + .name = "MDA", + .internal_name = "mda", + .flags = DEVICE_ISA, + .local = 0, + .init = mda_standalone_init, + .close = mda_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = mda_speed_changed, + .force_redraw = NULL, + .config = mda_config }; diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 4cc3885d1..87ed16ba5 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -27,13 +27,17 @@ #include <86box/device.h> #include <86box/dma.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> -#define ROM_MYSTIQUE L"roms/video/matrox/MYSTIQUE.VBI" -#define ROM_MYSTIQUE_220 L"roms/video/matrox/Myst220_66-99mhz.vbi" +#define ROM_MILLENNIUM "roms/video/matrox/matrox2064wr2.BIN" +#define ROM_MYSTIQUE "roms/video/matrox/MYSTIQUE.VBI" +#define ROM_MYSTIQUE_220 "roms/video/matrox/Myst220_66-99mhz.vbi" #define FIFO_SIZE 65536 #define FIFO_MASK (FIFO_SIZE - 1) @@ -134,6 +138,7 @@ #define REG_CRTCEXT_DATA 0x1fdf #define REG_CACHEFLUSH 0x1fff +/*Mystique only*/ #define REG_TMR0 0x2c00 #define REG_TMR1 0x2c04 #define REG_TMR2 0x2c08 @@ -152,6 +157,7 @@ #define REG_SECEND 0x2c44 #define REG_SOFTRAP 0x2c48 +/*Mystique only*/ #define REG_PALWTADD 0x3c00 #define REG_PALDATA 0x3c01 #define REG_PIXRDMSK 0x3c02 @@ -258,6 +264,7 @@ #define DWGCTRL_OPCODE_BITBLT (0x8 << 0) #define DWGCTRL_OPCODE_ILOAD (0x9 << 0) #define DWGCTRL_OPCODE_IDUMP (0xa << 0) +#define DWGCTRL_OPCODE_FBITBLT (0xc << 0) #define DWGCTRL_OPCODE_ILOAD_SCALE (0xd << 0) #define DWGCTRL_OPCODE_ILOAD_HIGHV (0xe << 0) #define DWGCTRL_OPCODE_ILOAD_FILTER (0xf << 0) /* Not implemented. */ @@ -367,6 +374,15 @@ #define DITHER_555 2 #define DITHER_NONE_555 3 +/*PCI configuration registers*/ +#define OPTION_INTERLEAVE (1 << 12) + +enum +{ + MGA_2064W, /*Millennium*/ + MGA_1064SG, /*Mystique*/ + MGA_1164SG, /*Mystique 220*/ +}; enum { @@ -396,6 +412,8 @@ typedef struct mystique_t rom_t bios_rom; + int type; + mem_mapping_t lfb_mapping, ctrl_mapping, iload_mapping; @@ -418,7 +436,7 @@ typedef struct mystique_t pixel_count, trap_count; volatile int busy, blitter_submit_refcount, - blitter_submit_dma_refcount, blitter_complete_refcount, + blitter_submit_dma_refcount, blitter_complete_refcount, endprdmasts_pending, softrap_pending, fifo_read_idx, fifo_write_idx; @@ -499,6 +517,10 @@ typedef struct mystique_t mutex_t *lock; } dma; + + uint8_t thread_run; + + void *i2c, *i2c_ddc, *ddc; } mystique_t; @@ -606,9 +628,9 @@ static const uint8_t trans_masks[16][16] = static int8_t dither5[256][2][2]; static int8_t dither6[256][2][2]; +static video_timings_t timing_matrox_millennium = {VIDEO_PCI, 2, 2, 1, 10, 10, 10}; static video_timings_t timing_matrox_mystique = {VIDEO_PCI, 4, 4, 4, 10, 10, 10}; - static void mystique_start_blit(mystique_t *mystique); static void mystique_update_irqs(mystique_t *mystique); @@ -642,12 +664,18 @@ mystique_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &mystique->svga; uint8_t old; - if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { case 0x3c8: mystique->xreg_idx = val; + case 0x3c6: case 0x3c7: case 0x3c9: + if (mystique->type == MGA_2064W) + { + tvp3026_ramdac_out(addr, 0, 0, val, svga->ramdac, svga); + return; + } break; case 0x3cf: @@ -670,8 +698,13 @@ mystique_out(uint16_t addr, uint8_t val, void *p) svga->crtc[svga->crtcreg & 0x3f] = val; if (old != val) { if ((svga->crtcreg & 0x3f) < 0xE || (svga->crtcreg & 0x3f) > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if (((svga->crtcreg & 0x3f) == 0xc) || ((svga->crtcreg & 0x3f) == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } if (svga->crtcreg == 0x11) { if (!(val & 0x10)) @@ -687,6 +720,8 @@ mystique_out(uint16_t addr, uint8_t val, void *p) case 0x3df: if (mystique->crtcext_idx < 6) mystique->crtcext_regs[mystique->crtcext_idx] = val; + if (mystique->crtcext_idx == 1) + svga->dpms = !!(val & 0x30); if (mystique->crtcext_idx < 4) { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -723,15 +758,37 @@ mystique_in(uint16_t addr, void *p) svga_t *svga = &mystique->svga; uint8_t temp = 0xff; - if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { + case 0x3c1: + if (svga->attraddr >= 0x15) + temp = 0; + else + temp = svga->attrregs[svga->attraddr]; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (mystique->type == MGA_2064W) + temp = tvp3026_ramdac_in(addr, 0, 0, svga->ramdac, svga); + else + temp = svga_in(addr, svga); + break; + case 0x3D4: temp = svga->crtcreg; break; case 0x3D5: - temp = svga->crtc[svga->crtcreg & 0x3f]; + if ((svga->crtcreg >= 0x19 && svga->crtcreg <= 0x21) || + svga->crtcreg == 0x23 || svga->crtcreg == 0x25 || svga->crtcreg >= 0x27) + temp = 0; + else + temp = svga->crtc[svga->crtcreg & 0x3f]; + break; + + case 0x3de: + temp = mystique->crtcext_idx; break; case 0x3df: @@ -759,7 +816,7 @@ mystique_line_compare(svga_t *svga) return 0; } -static void +static void mystique_vsync_callback(svga_t *svga) { mystique_t *mystique = (mystique_t *)svga->p; @@ -767,9 +824,26 @@ mystique_vsync_callback(svga_t *svga) if (svga->crtc[0x11] & 0x10) { mystique->status |= STATUS_VSYNCPEN; mystique_update_irqs(mystique); - } + } } +static float +mystique_getclock(int clock, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + + int m = mystique->xpixpll[2].m; + int n = mystique->xpixpll[2].n; + int pl = mystique->xpixpll[2].p; + + float fvco = 14318181.0 * (n + 1) / (m + 1); + float fo = fvco / (pl + 1); + + return fo; +} void mystique_recalctimings(svga_t *svga) @@ -777,16 +851,7 @@ mystique_recalctimings(svga_t *svga) mystique_t *mystique = (mystique_t *)svga->p; int clk_sel = (svga->miscout >> 2) & 3; - if (clk_sel & 2) { - int m = mystique->xpixpll[2].m; - int n = mystique->xpixpll[2].n; - int p = mystique->xpixpll[2].p; - - double fvco = 14318181.0 * (n + 1) / (m + 1); - double fo = fvco / (p + 1); - - svga->clock = (cpuclock * (float)(1ull << 32)) / fo; - } + svga->clock = (cpuclock * (float)(1ull << 32)) / svga->getclock(clk_sel & 2, svga->clock_gen); if (mystique->crtcext_regs[1] & CRTCX_R1_HTOTAL8) svga->htotal += 0x100; @@ -807,70 +872,87 @@ mystique_recalctimings(svga_t *svga) if (mystique->crtcext_regs[2] & CRTCX_R2_LINECOMP10) svga->split += 0x400; - svga->interlace = !!(mystique->crtcext_regs[0] & 0x80); + if (mystique->type == MGA_2064W) + tvp3026_recalctimings(svga->ramdac, svga); + else + svga->interlace = !!(mystique->crtcext_regs[0] & 0x80); if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) { - int row_offset = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); - + svga->packed_chain4 = 1; svga->lowres = 0; - svga->char_width = 8; - svga->hdisp = (svga->crtc[1] + 1) * 8; - svga->hdisp_time = svga->hdisp; - if (svga->interlace) - svga->rowoffset = row_offset; - else - svga->rowoffset = row_offset * 2; - svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 17) | - (svga->crtc[0xc] << 9) | (svga->crtc[0xd] << 1); - - /*Mystique, unlike most SVGA cards, allows display start to take - effect mid-screen*/ - if (svga->ma_latch != mystique->ma_latch_old) { - if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2) + (svga->rowoffset << 1); - else - svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2); - mystique->ma_latch_old = svga->ma_latch; + svga->char_width = 8; + svga->hdisp = (svga->crtc[1] + 1) * 8; + svga->hdisp_time = svga->hdisp; + svga->rowoffset = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); + svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | + (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + if (mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8)) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; } + if (mystique->type >= MGA_1064SG) { + /*Mystique, unlike most SVGA cards, allows display start to take + effect mid-screen*/ + if (svga->ma_latch != mystique->ma_latch_old) { + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2) + (svga->rowoffset << 1); + else + svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2); + mystique->ma_latch_old = svga->ma_latch; + } - switch (mystique->xmulctrl & XMULCTRL_DEPTH_MASK) { - case XMULCTRL_DEPTH_8: - case XMULCTRL_DEPTH_2G8V16: - svga->render = svga_render_8bpp_highres; - svga->bpp = 8; - break; - case XMULCTRL_DEPTH_15: - case XMULCTRL_DEPTH_G16V16: - svga->render = svga_render_15bpp_highres; - svga->bpp = 15; - break; - case XMULCTRL_DEPTH_16: - svga->render = svga_render_16bpp_highres; - svga->bpp = 16; - break; - case XMULCTRL_DEPTH_24: - svga->render = svga_render_24bpp_highres; - svga->bpp = 24; - break; - case XMULCTRL_DEPTH_32: - case XMULCTRL_DEPTH_32_OVERLAYED: - svga->render = svga_render_32bpp_highres; - svga->bpp = 32; - break; + switch (mystique->xmulctrl & XMULCTRL_DEPTH_MASK) { + case XMULCTRL_DEPTH_8: + case XMULCTRL_DEPTH_2G8V16: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case XMULCTRL_DEPTH_15: + case XMULCTRL_DEPTH_G16V16: + svga->render = svga_render_15bpp_highres; + svga->bpp = 15; + break; + case XMULCTRL_DEPTH_16: + svga->render = svga_render_16bpp_highres; + svga->bpp = 16; + break; + case XMULCTRL_DEPTH_24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case XMULCTRL_DEPTH_32: + case XMULCTRL_DEPTH_32_OVERLAYED: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + } + } else { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } } - svga->line_compare = mystique_line_compare; - - mem_mapping_set_handler(&mystique->lfb_mapping, - mystique_readb_linear, mystique_readw_linear, mystique_readl_linear, - mystique_writeb_linear, mystique_writew_linear, mystique_writel_linear); } else { + svga->packed_chain4 = 0; svga->line_compare = NULL; - svga->bpp = 8; - - mem_mapping_set_handler(&mystique->lfb_mapping, - svga_read_linear, svga_readw_linear, svga_readl_linear, - svga_write_linear, svga_writew_linear, svga_writel_linear); + if (mystique->type >= MGA_1064SG) + svga->bpp = 8; } } @@ -1019,7 +1101,15 @@ mystique_read_xreg(mystique_t *mystique, int reg) ret = mystique->xgenioctrl; break; case XREG_XGENIODATA: - ret = mystique->xgeniodata; + ret = mystique->xgeniodata & 0xf0; + if (i2c_gpio_get_scl(mystique->i2c_ddc)) + ret |= 0x08; + if (i2c_gpio_get_scl(mystique->i2c)) + ret |= 0x04; + if (i2c_gpio_get_sda(mystique->i2c_ddc)) + ret |= 0x02; + if (i2c_gpio_get_sda(mystique->i2c)) + ret |= 0x01; break; case XREG_XSYSPLLM: @@ -1045,7 +1135,7 @@ mystique_read_xreg(mystique_t *mystique, int reg) if (mystique->svga.vgapal[0].r < 0x80) ret |= 4; break; - + case XREG_XCRCREML: /*CRC not implemented*/ ret = 0; break; @@ -1154,6 +1244,8 @@ mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val) case XREG_XGENIOCTRL: mystique->xgenioctrl = val; + i2c_gpio_set(mystique->i2c_ddc, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02)); + i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x04) || (mystique->xgeniodata & 0x04), !(mystique->xgenioctrl & 0x01) || (mystique->xgeniodata & 0x01)); break; case XREG_XGENIODATA: mystique->xgeniodata = val; @@ -1238,8 +1330,37 @@ mystique_ctrl_read_b(uint32_t addr, void *p) svga_t *svga = &mystique->svga; uint8_t ret = 0xff; int fifocount; + uint16_t addr_0x0f = 0; + uint16_t addr_0x03 = 0; + int rs2 = 0, rs3 = 0; - switch (addr & 0x3fff) { + if ((mystique->type == MGA_2064W) && (addr & 0x3e00) == 0x3c00) + { + /*RAMDAC*/ + addr_0x0f = addr & 0x0f; + + if ((addr_0x0f & 3) == 0) + addr_0x03 = 0x3c8; + else if ((addr_0x0f & 3) == 1) + addr_0x03 = 0x3c9; + else if ((addr_0x0f & 3) == 2) + addr_0x03 = 0x3c6; + else if ((addr_0x0f & 3) == 3) + addr_0x03 = 0x3c7; + + if ((addr_0x0f >= 0x04) && (addr_0x0f <= 0x07)) { + rs2 = 1; + rs3 = 0; + } else if ((addr_0x0f >= 0x08) && (addr_0x0f <= 0x0b)) { + rs2 = 0; + rs3 = 1; + } else if ((addr_0x0f >= 0x0c) && (addr_0x0f <= 0x0f)) { + rs2 = 1; + rs3 = 1; + } + + ret = tvp3026_ramdac_in(addr_0x03, rs2, rs3, svga->ramdac, svga); + } else switch (addr & 0x3fff) { case REG_FIFOSTATUS: fifocount = FIFO_SIZE - FIFO_ENTRIES; if (fifocount > 64) @@ -1292,6 +1413,7 @@ mystique_ctrl_read_b(uint32_t addr, void *p) ret = mystique->dirdatasiz; break; case REG_OPMODE+3: + ret = 0; break; case REG_PRIMADDRESS: case REG_PRIMADDRESS+1: case REG_PRIMADDRESS+2: case REG_PRIMADDRESS+3: @@ -1373,15 +1495,17 @@ mystique_ctrl_read_b(uint32_t addr, void *p) ret = mystique_read_xreg(mystique, mystique->xreg_idx); break; + case 0x1c40: case 0x1c41: case 0x1c42: case 0x1c43: + case 0x1d44: case 0x1d45: case 0x1d46: case 0x1d47: case 0x1e50: case 0x1e51: case 0x1e52: case 0x1e53: case REG_ICLEAR: case REG_ICLEAR+1: case REG_ICLEAR+2: case REG_ICLEAR+3: case 0x2c30: case 0x2c31: case 0x2c32: case 0x2c33: - case 0x3e08: + case 0x3e08: break; case 0x3c08: case 0x3c09: case 0x3c0b: break; - + default: if ((addr & 0x3fff) >= 0x2c00 && (addr & 0x3fff) < 0x2c40) @@ -1601,6 +1725,7 @@ mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *p) WRITE8(addr, mystique->dwgreg.textrans, val); break; + case 0x1c18: case 0x1c19: case 0x1c1a: case 0x1c1b: case 0x1c28: case 0x1c29: case 0x1c2a: case 0x1c2b: case 0x1c2c: case 0x1c2d: case 0x1c2e: case 0x1c2f: case 0x1cc4: case 0x1cc5: case 0x1cc6: case 0x1cc7: @@ -1630,6 +1755,38 @@ mystique_ctrl_write_b(uint32_t addr, uint8_t val, void *p) { mystique_t *mystique = (mystique_t *)p; svga_t *svga = &mystique->svga; + uint16_t addr_0x0f = 0; + uint16_t addr_0x03 = 0; + int rs2 = 0, rs3 = 0; + + if ((mystique->type == MGA_2064W) && (addr & 0x3e00) == 0x3c00) + { + /*RAMDAC*/ + addr_0x0f = addr & 0x0f; + + if ((addr & 3) == 0) + addr_0x03 = 0x3c8; + else if ((addr & 3) == 1) + addr_0x03 = 0x3c9; + else if ((addr & 3) == 2) + addr_0x03 = 0x3c6; + else if ((addr & 3) == 3) + addr_0x03 = 0x3c7; + + if ((addr_0x0f >= 0x04) && (addr_0x0f <= 0x07)) { + rs2 = 1; + rs3 = 0; + } else if ((addr_0x0f >= 0x08) && (addr_0x0f <= 0x0b)) { + rs2 = 0; + rs3 = 1; + } else if ((addr_0x0f >= 0x0c) && (addr_0x0f <= 0x0f)) { + rs2 = 1; + rs3 = 1; + } + + tvp3026_ramdac_out(addr_0x03, rs2, rs3, val, svga->ramdac, svga); + return; + } if ((addr & 0x3fff) < 0x1c00) { mystique_iload_write_b(addr, val, p); @@ -1816,6 +1973,40 @@ mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *p) switch (addr & 0x3ffc) { case REG_DWGCTL: mystique->dwgreg.dwgctrl = val; + + if (val & DWGCTRL_SOLID) { + int x, y; + + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) + mystique->dwgreg.pattern[y][x] = 1; + } + mystique->dwgreg.src[0] = 0xffffffff; + mystique->dwgreg.src[1] = 0xffffffff; + mystique->dwgreg.src[2] = 0xffffffff; + mystique->dwgreg.src[3] = 0xffffffff; + } + if (val & DWGCTRL_ARZERO) { + mystique->dwgreg.ar[0] = 0; + mystique->dwgreg.ar[1] = 0; + mystique->dwgreg.ar[2] = 0; + mystique->dwgreg.ar[4] = 0; + mystique->dwgreg.ar[5] = 0; + mystique->dwgreg.ar[6] = 0; + } + if (val & DWGCTRL_SGNZERO) { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.sgn.scanleft = 0; + mystique->dwgreg.sgn.sdxl = 0; + mystique->dwgreg.sgn.sdy = 0; + mystique->dwgreg.sgn.sdxr = 0; + } + if (val & DWGCTRL_SHTZERO) { + mystique->dwgreg.funcnt = 0; + mystique->dwgreg.stylelen = 0; + mystique->dwgreg.xoff = 0; + mystique->dwgreg.yoff = 0; + } break; case REG_ZORG: @@ -2116,9 +2307,7 @@ mystique_readb_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - egareads++; - - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2133,9 +2322,7 @@ mystique_readw_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - egareads += 2; - - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2150,9 +2337,7 @@ mystique_readl_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - egareads += 4; - - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2167,9 +2352,7 @@ mystique_writeb_linear(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; - egawrites++; - - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2185,9 +2368,7 @@ mystique_writew_linear(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; - egawrites += 2; - - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2203,9 +2384,7 @@ mystique_writel_linear(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; - egawrites += 4; - - sub_cycles(video_timing_write_l); + cycles -= video_timing_write_l; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2345,7 +2524,7 @@ fifo_thread(void *p) { mystique_t *mystique = (mystique_t *)p; - while (1) { + while (mystique->thread_run) { thread_set_event(mystique->fifo_not_full_event); thread_wait_event(mystique->wake_fifo_thread, -1); thread_reset_event(mystique->wake_fifo_thread); @@ -2479,19 +2658,19 @@ bitop(uint32_t src, uint32_t dst, uint32_t dwgctrl) case BOP(0x0): return 0; case BOP(0x1): return ~(dst | src); case BOP(0x2): return dst & ~src; - case BOP(0x3): return ~src; + case BOP(0x3): return ~src; case BOP(0x4): return ~dst & src; - case BOP(0x5): return ~dst; - case BOP(0x6): return dst ^ src; + case BOP(0x5): return ~dst; + case BOP(0x6): return dst ^ src; case BOP(0x7): return ~(dst & src); - case BOP(0x8): return dst & src; + case BOP(0x8): return dst & src; case BOP(0x9): return ~(dst ^ src); - case BOP(0xa): return dst; + case BOP(0xa): return dst; case BOP(0xb): return dst | ~src; - case BOP(0xc): return src; + case BOP(0xc): return src; case BOP(0xd): return ~dst | src; - case BOP(0xe): return dst | src; - case BOP(0xf): return ~0; + case BOP(0xe): return dst | src; + case BOP(0xf): return ~0; } return 0; @@ -2530,6 +2709,7 @@ blit_idump_idump(mystique_t *mystique) case DWGCTRL_ATYPE_RPL: switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { case DWGCTRL_BLTMOD_BU32RGB: + case DWGCTRL_BLTMOD_BFCOL: switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { case MACCESS_PWIDTH_8: while (count < 32) { @@ -2603,7 +2783,7 @@ blit_idump_idump(mystique_t *mystique) while ((count < 32) && !mystique->dwgreg.idump_end_of_line) { val64 |= (uint64_t)((*(uint32_t *)&svga->vram[(mystique->dwgreg.src_addr * 3) & mystique->vram_mask]) & 0xffffff) << count; - + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; @@ -2705,6 +2885,88 @@ blit_idump_read(mystique_t *mystique) return ret; } +static void +blit_fbitblt(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t src_addr; + int y; + int x_dir = mystique->dwgreg.sgn.scanleft ? -1 : 1; + int16_t x_start = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft; + int16_t x_end = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright; + + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) + { + int16_t x = x_start; + while (1) + { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint32_t src, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + src = svga->vram[src_addr & mystique->vram_mask]; + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = src; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = ((uint16_t *)svga->vram)[src_addr & mystique->vram_mask_w]; + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = src; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = *(uint32_t *)&svga->vram[(src_addr * 3) & mystique->vram_mask]; + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (src & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = ((uint32_t *)svga->vram)[src_addr & mystique->vram_mask_l]; + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = src; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + break; + } + else + src_addr += x_dir; + + if (x != x_end) + x += x_dir; + else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + + mystique->blitter_complete_refcount++; +} static void blit_iload_iload(mystique_t *mystique, uint32_t data, int size) @@ -2861,7 +3123,7 @@ blit_iload_iload(mystique_t *mystique, uint32_t data, int size) case DWGCTRL_BLTMOD_BMONOWF: data = (data >> 24) | ((data & 0x00ff0000) >> 8) | ((data & 0x0000ff00) << 8) | (data << 24); data_mask = (1 << 31); - case DWGCTRL_BLTMOD_BMONOLEF: + case DWGCTRL_BLTMOD_BMONOLEF: while (size) { if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && @@ -2979,40 +3241,44 @@ blit_iload_iload(mystique_t *mystique, uint32_t data, int size) case DWGCTRL_BLTMOD_BU32RGB: size += mystique->dwgreg.iload_rem_count; - while (size >= 32) { - if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && - mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { - switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { - case MACCESS_PWIDTH_32: + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t)data << mystique->dwgreg.iload_rem_count); + while (size >= 32) + { + int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3]; + + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) + { dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; dst = bitop(data, dst, mystique->dwgreg.dwgctrl_running); - ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + size = 0; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; break; - - default: - fatal("ILOAD RSTR/RPL BU32RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); } - } - - size = 0; - if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { - mystique->dwgreg.xdst = mystique->dwgreg.fxleft; - mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); - mystique->dwgreg.length_cur--; - if (!mystique->dwgreg.length_cur) { - mystique->busy = 0; - mystique->blitter_complete_refcount++; - break; - } - break; - } else - mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; } - mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; break; case DWGCTRL_BLTMOD_BU32BGR: @@ -3147,9 +3413,13 @@ blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) size -= 16; } - if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { - mystique->dwgreg.xdst = mystique->dwgreg.fxleft; - mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); mystique->dwgreg.length_cur--; if (!mystique->dwgreg.length_cur) { @@ -3158,8 +3428,7 @@ blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) break; } break; - } else - mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } } break; @@ -3180,9 +3449,13 @@ blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) size -= 32; } - if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { mystique->dwgreg.xdst = mystique->dwgreg.fxleft; mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); mystique->dwgreg.length_cur--; if (!mystique->dwgreg.length_cur) { @@ -3191,8 +3464,7 @@ blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) break; } break; - } else - mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } } break; @@ -4280,7 +4552,7 @@ blit_bitblt(mystique_t *mystique) dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); - + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; break; @@ -4444,7 +4716,7 @@ blit_bitblt(mystique_t *mystique) static void blit_iload(mystique_t *mystique) -{ +{ switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { case DWGCTRL_ATYPE_RPL: case DWGCTRL_ATYPE_RSTR: @@ -4597,40 +4869,6 @@ mystique_start_blit(mystique_t *mystique) mystique->dwgreg.dwgctrl_running = mystique->dwgreg.dwgctrl; mystique->maccess_running = mystique->maccess; - if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SOLID) { - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - mystique->dwgreg.pattern[y][x] = 1; - } - mystique->dwgreg.src[0] = 0xffffffff; - mystique->dwgreg.src[1] = 0xffffffff; - mystique->dwgreg.src[2] = 0xffffffff; - mystique->dwgreg.src[3] = 0xffffffff; - } - if (mystique->dwgreg.dwgctrl_running & DWGCTRL_ARZERO) { - mystique->dwgreg.ar[0] = 0; - mystique->dwgreg.ar[1] = 0; - mystique->dwgreg.ar[2] = 0; - mystique->dwgreg.ar[4] = 0; - mystique->dwgreg.ar[5] = 0; - mystique->dwgreg.ar[6] = 0; - } - if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SGNZERO) { - mystique->dwgreg.sgn.sdydxl = 0; - mystique->dwgreg.sgn.scanleft = 0; - mystique->dwgreg.sgn.sdxl = 0; - mystique->dwgreg.sgn.sdy = 0; - mystique->dwgreg.sgn.sdxr = 0; - } - if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SHTZERO) { - mystique->dwgreg.funcnt = 0; - mystique->dwgreg.stylelen = 0; - mystique->dwgreg.xoff = 0; - mystique->dwgreg.yoff = 0; - } - switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { case DWGCTRL_OPCODE_LINE_OPEN: blit_line(mystique, 0); @@ -4639,10 +4877,10 @@ mystique_start_blit(mystique_t *mystique) case DWGCTRL_OPCODE_AUTOLINE_OPEN: blit_autoline(mystique, 0); break; - + case DWGCTRL_OPCODE_LINE_CLOSE: blit_line(mystique, 1); - break; + break; case DWGCTRL_OPCODE_AUTOLINE_CLOSE: blit_autoline(mystique, 1); @@ -4664,6 +4902,10 @@ mystique_start_blit(mystique_t *mystique) blit_bitblt(mystique); break; + case DWGCTRL_OPCODE_FBITBLT: + blit_fbitblt(mystique); + break; + case DWGCTRL_OPCODE_ILOAD: blit_iload(mystique); break; @@ -4740,7 +4982,7 @@ uint8_t mystique_pci_read(int func, int addr, void *p) case 0x00: ret = 0x2b; break; /*Matrox*/ case 0x01: ret = 0x10; break; - case 0x02: ret = 0x1a; break; /*MGA-1064SG*/ + case 0x02: ret = (mystique->type == MGA_2064W) ? 0x19 : 0x1a; break; /*MGA*/ case 0x03: ret = 0x05; break; case PCI_REG_COMMAND: @@ -4915,14 +5157,18 @@ mystique_init(const device_t *info) { int c; mystique_t *mystique = malloc(sizeof(mystique_t)); - wchar_t *romfn; + char *romfn; memset(mystique, 0, sizeof(mystique_t)); - if (info->local == 1) - romfn = ROM_MYSTIQUE_220; - else - romfn = ROM_MYSTIQUE; + mystique->type = info->local; + + if (mystique->type == MGA_2064W) + romfn = ROM_MILLENNIUM; + else if (mystique->type == MGA_1064SG) + romfn = ROM_MYSTIQUE; + else + romfn = ROM_MYSTIQUE_220; rom_init(&mystique->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); mem_mapping_disable(&mystique->bios_rom.mapping); @@ -4934,11 +5180,27 @@ mystique_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); - svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20, - mystique_recalctimings, - mystique_in, mystique_out, - mystique_hwcursor_draw, - NULL); + if (mystique->type == MGA_2064W) { + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_millennium); + svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20, + mystique_recalctimings, + mystique_in, mystique_out, + NULL, + NULL); + mystique->svga.dac_hwcursor_draw = tvp3026_hwcursor_draw; + mystique->svga.ramdac = device_add(&tvp3026_ramdac_device); + mystique->svga.clock_gen = mystique->svga.ramdac; + mystique->svga.getclock = tvp3026_getclock; + } else { + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); + svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20, + mystique_recalctimings, + mystique_in, mystique_out, + mystique_hwcursor_draw, + NULL); + mystique->svga.clock_gen = mystique; + mystique->svga.getclock = mystique_getclock; + } io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); mem_mapping_add(&mystique->ctrl_mapping, 0, 0, @@ -4948,8 +5210,8 @@ mystique_init(const device_t *info) mem_mapping_disable(&mystique->ctrl_mapping); mem_mapping_add(&mystique->lfb_mapping, 0, 0, - svga_read_linear, svga_readw_linear, svga_readl_linear, - svga_write_linear, svga_writew_linear, svga_writel_linear, + mystique_readb_linear, mystique_readw_linear, mystique_readl_linear, + mystique_writeb_linear, mystique_writew_linear, mystique_writel_linear, NULL, 0, mystique); mem_mapping_disable(&mystique->lfb_mapping); @@ -4999,6 +5261,7 @@ mystique_init(const device_t *info) mystique->wake_fifo_thread = thread_create_event(); mystique->fifo_not_full_event = thread_create_event(); + mystique->thread_run = 1; mystique->fifo_thread = thread_create(fifo_thread, mystique); mystique->dma.lock = thread_create_mutex(); @@ -5009,7 +5272,11 @@ mystique_init(const device_t *info) mystique->svga.vsync_callback = mystique_vsync_callback; - return mystique; + mystique->i2c = i2c_gpio_init("i2c_mga"); + mystique->i2c_ddc = i2c_gpio_init("ddc_mga"); + mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c_ddc)); + + return mystique; } @@ -5018,16 +5285,27 @@ mystique_close(void *p) { mystique_t *mystique = (mystique_t *)p; - thread_kill(mystique->fifo_thread); + mystique->thread_run = 0; + thread_set_event(mystique->wake_fifo_thread); + thread_wait(mystique->fifo_thread); thread_destroy_event(mystique->wake_fifo_thread); thread_destroy_event(mystique->fifo_not_full_event); thread_close_mutex(mystique->dma.lock); svga_close(&mystique->svga); + ddc_close(mystique->ddc); + i2c_gpio_close(mystique->i2c_ddc); + i2c_gpio_close(mystique->i2c); + free(mystique); } +static int +millennium_available(void) +{ + return rom_present(ROM_MILLENNIUM); +} static int mystique_available(void) @@ -5035,7 +5313,6 @@ mystique_available(void) return rom_present(ROM_MYSTIQUE); } - static int mystique_220_available(void) { @@ -5060,64 +5337,81 @@ mystique_force_redraw(void *p) mystique->svga.fullchange = changeframecount; } - -static const device_config_t mystique_config[] = -{ +static const device_config_t mystique_config[] = { +// clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "" - } - }, - .default_int = 8 + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 8 }, { - .type = -1 + .type = CONFIG_END } +// clang-format on +}; + +const device_t millennium_device = +{ + .name = "Matrox Millennium", + .internal_name = "millennium", + .flags = DEVICE_PCI, + .local = MGA_2064W, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + { .available = millennium_available }, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + .config = mystique_config }; const device_t mystique_device = { - "Matrox Mystique", - DEVICE_PCI, - 0, - mystique_init, - mystique_close, - NULL, - mystique_available, - mystique_speed_changed, - mystique_force_redraw, - mystique_config + .name = "Matrox Mystique", + .internal_name = "mystique", + .flags = DEVICE_PCI, + .local = MGA_1064SG, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + { .available = mystique_available }, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + .config = mystique_config }; const device_t mystique_220_device = { - "Matrox Mystique 220", - DEVICE_PCI, - 1, - mystique_init, - mystique_close, - NULL, - mystique_220_available, - mystique_speed_changed, - mystique_force_redraw, - mystique_config + .name = "Matrox Mystique 220", + .internal_name = "mystique_220", + .flags = DEVICE_PCI, + .local = MGA_1164SG, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + { .available = mystique_220_available }, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + .config = mystique_config }; diff --git a/src/video/vid_nga.c b/src/video/vid_nga.c new file mode 100644 index 000000000..befe01671 --- /dev/null +++ b/src/video/vid_nga.c @@ -0,0 +1,704 @@ +/* + * 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 the NCR NGA (K511, K201) video cards. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ + +#include +#include +#include +#include +#include +#include +#include <86box/io.h> +#include <86box/video.h> +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/mem.h> +#include <86box/pit.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/vid_cga.h> +#include <86box/vid_nga.h> +#include <86box/vid_cga_comp.h> + + + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + + + +static video_timings_t timing_nga = {VIDEO_ISA, 8,16,32, 8,16,32}; + +void +nga_recalctimings(nga_t *nga) +{ + double _dispontime, _dispofftime, disptime; + + if ((nga->cga.cgamode & 1) ) { + disptime = nga->cga.crtc[0] + 1; + _dispontime = nga->cga.crtc[1]; + } else { + disptime = (nga->cga.crtc[0] + 1) << 1; + _dispontime = nga->cga.crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST / 2; + _dispofftime *= CGACONST / 2; + nga->cga.dispontime = (uint64_t)(_dispontime); + nga->cga.dispofftime = (uint64_t)(_dispofftime); +} + +void +nga_out(uint16_t addr, uint8_t val, void *priv) +{ + nga_t *nga = (nga_t *)priv; + + cga_out(addr, val, &nga->cga); + +} + +uint8_t +nga_in(uint16_t addr, void *priv) +{ + nga_t *nga = (nga_t *)priv; + + return cga_in(addr, &nga->cga); +} + + +void +nga_waitstates(void *p) +{ + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + + +void +nga_write(uint32_t addr, uint8_t val, void *priv) +{ + nga_t *nga = (nga_t *)priv; + int offset; + /* a8000-affff */ + if(!(addr & 0x10000)) + nga->vram_64k[addr & 0x7FFF]=val; + /* b8000-bffff */ + else + nga->cga.vram[addr & 0x7FFF]=val; + + if (nga->cga.snow_enabled) { + /* recreate snow effect */ + offset = ((timer_get_remaining_u64(&nga->cga.timer) / CGACONST) * 4) & 0xfc; + nga->cga.charbuffer[offset] = nga->cga.vram[addr & 0x7fff]; + nga->cga.charbuffer[offset | 1] = nga->cga.vram[addr & 0x7fff]; + } + nga_waitstates(&nga->cga); +} + +uint8_t +nga_read(uint32_t addr, void *priv) +{ + + nga_t *nga = (nga_t *)priv; + int offset; + uint8_t ret; + /* a8000-affff */ + if(!(addr & 0x10000)) + ret = nga->vram_64k[addr & 0x7FFF]; + else + ret = nga->cga.vram[addr & 0x7FFF]; + + nga_waitstates(&nga->cga); + + if (nga->cga.snow_enabled) { + /* recreate snow effect */ + offset = ((timer_get_remaining_u64(&nga->cga.timer) / CGACONST) * 4) & 0xfc; + nga->cga.charbuffer[offset] = nga->cga.vram[addr & 0x7fff]; + nga->cga.charbuffer[offset | 1] = nga->cga.vram[addr & 0x7fff]; + } + + return(ret); +} + +void +nga_poll(void *priv) +{ + nga_t *nga = (nga_t *)priv; + /* set cursor position in memory */ + uint16_t ca = (nga->cga.crtc[15] | (nga->cga.crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c, xs_temp, ys_temp; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2; + int cols[4]; + int col; + int oldsc; + + /* graphic mode and not high-res modes */ + if ((nga->cga.cgamode & 2) && !(nga->cga.cgamode & 0x40)) { + /* standard cga mode */ + cga_poll(&nga->cga); + return; + } else { + /* high-res or text mode */ + if (!nga->cga.linepos) { + timer_advance_u64(&nga->cga.timer, nga->cga.dispofftime); + nga->cga.cgastat |= 1; + nga->cga.linepos = 1; + oldsc = nga->cga.sc; + /* if interlaced */ + if ((nga->cga.crtc[8] & 3) == 3) + nga->cga.sc = ((nga->cga.sc << 1) + nga->cga.oddeven) & 7; + if (nga->cga.cgadispon) { + if (nga->cga.displine < nga->cga.firstline) { + nga->cga.firstline = nga->cga.displine; + video_wait_for_buffer(); + } + nga->cga.lastline = nga->cga.displine; + /* 80-col */ + if ((nga->cga.cgamode & 1) && !(nga->cga.cgamode & 2)) { + /* for each text column */ + for (x = 0; x < nga->cga.crtc[1]; x++) { + /* video output enabled */ + if (nga->cga.cgamode & 8) { + /* character */ + chr = nga->cga.charbuffer[x << 1]; + /* text attributes */ + attr = nga->cga.charbuffer[(x << 1) + 1]; + } else + chr = attr = 0; + /* check if cursor has to be drawn */ + drawcursor = ((nga->cga.ma == ca) && nga->cga.con && nga->cga.cursoron); + /* set foreground */ + cols[1] = (attr & 15) + 16; + /* blink active */ + if (nga->cga.cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + /* attribute 7 active and not cursor */ + if ((nga->cga.cgablink & 8) && (attr & 0x80) && !nga->cga.drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + } + } else { + /* Set intensity bit */ + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + + nga->cga.ma++; + } + } + /* 40-col */ + else if (!(nga->cga.cgamode & 2)) { + /* for each text column */ + for (x = 0; x < nga->cga.crtc[1]; x++) { + if (nga->cga.cgamode & 8) { + chr = nga->cga.vram[((nga->cga.ma << 1) & 0x3fff) + nga->base]; + attr = nga->cga.vram[(((nga->cga.ma << 1) + 1) & 0x3fff) + nga->base]; + } else { + chr = attr = 0; + } + drawcursor = ((nga->cga.ma == ca) && nga->cga.con && nga->cga.cursoron); + /* set foreground */ + cols[1] = (attr & 15) + 16; + /* blink active */ + if (nga->cga.cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((nga->cga.cgablink & 8) && (attr & 0x80) && !nga->cga.drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + } + } else { + /* Set intensity bit */ + cols[0] = (attr >> 4) + 16; + } + + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + + nga->cga.ma++; + + } + } else { + /* high res modes */ + if (nga->cga.cgamode & 0x40) { + /* 640x400x2 mode */ + if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & 0x10) { + /* + * Scanlines are read in the following order: + * 0b8000-0b9f3f even scans (0,4,...) + * 0ba000-0bbf3f odd scans (2,6,...) + * 0bc000-0bdf3f even scans (1,5,...) + * 0be000-0bff3f odd scans (3,7,...) + */ + dat2 = ((nga->cga.sc & 1) * 0x2000) | (nga->lineff * 0x4000); + cols[0] = 0; cols[1] = 15 + 16; + /* 640x400x4 mode */ + } else { + cols[0] = (nga->cga.cgacol & 15) | 16; + col = (nga->cga.cgacol & 16) ? 24 : 16; + if (nga->cga.cgamode & 4) { + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 7; /* White */ + } else if (nga->cga.cgacol & 32) { + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 5; /* Magenta */ + cols[3] = col | 7; /* White */ + } else { + cols[1] = col | 2; /* Green */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 6; /* Yellow */ + } + /* + * Scanlines are read in the following order: + * 0b8000-0bbf3f even scans (0,4,...) + * 0bc000-0bff3f odd scans (1,5,...) + * 0a8000-0abf3f even scans (2,6,...) + * 0ac000-0aff3f odd scans (3,7,...) + */ + dat2 = (nga->cga.sc & 1) * 0x4000; + } + } + else { + dat2 = (nga->cga.sc & 1) * 0x2000; + cols[0] = 0; cols[1] = (nga->cga.cgacol & 15) + 16; + } + + /* for each text column */ + for (x = 0; x < nga->cga.crtc[1]; x++) { + /* video out */ + if (nga->cga.cgamode & 8) { + /* 640x400x2 */ + if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & 0x10) { + /* read two bytes at a time */ + dat = (nga->cga.vram[((nga->cga.ma << 1) & 0x1fff) + dat2] << 8) | nga->cga.vram[((nga->cga.ma << 1) & 0x1fff) + dat2 + 1]; + /* each pixel is represented by one bit, so draw 16 pixels at a time */ + /* crtc[1] is 40 column, so 40x16=640 pixels */ + for (c = 0; c < 16; c++) { + buffer32->line[nga->cga.displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + /* 640x400x4 */ + } else { + /* lines 2,3,6,7,etc. */ + if (nga->cga.sc & 2) + /* read two bytes at a time */ + dat = (nga->vram_64k[((nga->cga.ma << 1) & 0x7fff) + dat2] << 8) | nga->vram_64k[((nga->cga.ma << 1) & 0x7fff) + dat2 + 1]; + /* lines 0,1,4,5,etc. */ + else + /* read two bytes at a time */ + dat = (nga->cga.vram[((nga->cga.ma << 1) & 0x7fff) + dat2] << 8) | nga->cga.vram[((nga->cga.ma << 1) & 0x7fff) + dat2 + 1]; + /* each pixel is represented by two bits, so draw 8 pixels at a time */ + /* crtc[1] is 80 column, so 80x8=640 pixels */ + for (c = 0; c < 8; c++) { + buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + dat = 0; + } + nga->cga.ma++; + } + } + } else { + + /* nga specific */ + cols[0] = ((nga->cga.cgamode & 0x12) == 0x12) ? 0 : (nga->cga.cgacol & 15) + 16; + /* 80-col */ + if ((nga->cga.cgamode & 1) ) { + hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[1] << 3) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[1] << 3) + 16) << 2, cols[0]); + } else { + hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[1] << 4) + 16) << 2, cols[0]); + } + + } + + nga->cga.sc = oldsc; + /* vertical sync */ + if (nga->cga.vc == nga->cga.crtc[7] && !nga->cga.sc) + nga->cga.cgastat |= 8; + nga->cga.displine++; + if (nga->cga.displine >= 720) + nga->cga.displine = 0; + } else { + timer_advance_u64(&nga->cga.timer, nga->cga.dispontime); + if (nga->cga.cgadispon) nga->cga.cgastat &= ~1; + nga->cga.linepos = 0; + /* nga specific */ + nga->lineff ^= 1; + + /* text mode or 640x400x2 */ + if (nga->lineff && !((nga->cga.cgamode & 1) && (nga->cga.cgamode & 0x40))) { + nga->cga.ma = nga->cga.maback; + /* 640x400x4 */ + } else { + if (nga->cga.vsynctime) { + nga->cga.vsynctime--; + if (!nga->cga.vsynctime) + nga->cga.cgastat &= ~8; + } + /* cursor stop scanline */ + if (nga->cga.sc == (nga->cga.crtc[11] & 31) || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[11] & 31) >> 1))) { + nga->cga.con = 0; + nga->cga.coff = 1; + } + /* interlaced and max scanline per char reached */ + if ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[9] >> 1)) + nga->cga.maback = nga->cga.ma; + + if (nga->cga.vadj) { + nga->cga.sc++; + nga->cga.sc &= 31; + nga->cga.ma = nga->cga.maback; + nga->cga.vadj--; + if (!nga->cga.vadj) { + nga->cga.cgadispon = 1; + /* change start of displayed page (crtc 12-13) */ + nga->cga.ma = nga->cga.maback = (nga->cga.crtc[13] | (nga->cga.crtc[12] << 8)) & 0x7fff; + nga->cga.sc = 0; + } + /* nga specific */ + /* end of character line reached */ + } else if (nga->cga.sc == nga->cga.crtc[9] || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[9] >> 1))) { + nga->cga.maback = nga->cga.ma; + nga->cga.sc = 0; + oldvc = nga->cga.vc; + nga->cga.vc++; + nga->cga.vc &= 127; + + /* lines of character displayed */ + if (nga->cga.vc == nga->cga.crtc[6]) + nga->cga.cgadispon=0; + + /* total vertical lines */ + if (oldvc == nga->cga.crtc[4]) { + nga->cga.vc = 0; + /* adjust vertical lines */ + nga->cga.vadj = nga->cga.crtc[5]; + if (!nga->cga.vadj) { + nga->cga.cgadispon = 1; + /* change start of displayed page (crtc 12-13) */ + nga->cga.ma = nga->cga.maback = (nga->cga.crtc[13] | (nga->cga.crtc[12] << 8)) & 0x7fff; + } + /* cursor start */ + switch (nga->cga.crtc[10] & 0x60) { + case 0x20: + nga->cga.cursoron = 0; + break; + case 0x60: + nga->cga.cursoron = nga->cga.cgablink & 0x10; + break; + default: + nga->cga.cursoron = nga->cga.cgablink & 0x08; + break; + } + } + /* vertical line position */ + if (nga->cga.vc == nga->cga.crtc[7]) { + nga->cga.cgadispon = 0; + nga->cga.displine = 0; + /* nga specific */ + nga->cga.vsynctime = 16; + /* vsync pos */ + if (nga->cga.crtc[7]) { + if ((nga->cga.cgamode & 1)) + /* set screen width */ + x = (nga->cga.crtc[1] << 3) + 16; + else + x = (nga->cga.crtc[1] << 4) + 16; + nga->cga.lastline++; + + xs_temp = x; + ys_temp = (nga->cga.lastline - nga->cga.firstline); + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xsize < 64) xs_temp = 656; + /* nga specific */ + if (ysize < 32) ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; + + + if ((nga->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + /* nga specific */ + if (enable_overscan) { + if (nga->cga.composite) + video_blit_memtoscreen(0, (nga->cga.firstline - 8), + xsize, (nga->cga.lastline - nga->cga.firstline) + 16); + else + video_blit_memtoscreen_8(0, (nga->cga.firstline - 8), + xsize, (nga->cga.lastline - nga->cga.firstline) + 16); + } else { + if (nga->cga.composite) + video_blit_memtoscreen(8, nga->cga.firstline, + xsize, (nga->cga.lastline - nga->cga.firstline)); + else + video_blit_memtoscreen_8(8, nga->cga.firstline, + xsize, (nga->cga.lastline - nga->cga.firstline)); + } + } + frames++; + + video_res_x = xsize; + video_res_y = ysize; + /* 80-col */ + if ((nga->cga.cgamode & 1) && !(nga->cga.cgamode & 0x40)) { + video_res_x /= 8; + video_res_y /= (nga->cga.crtc[9] + 1) * 2; + video_bpp = 0; + /* 40-col */ + } else if (!(nga->cga.cgamode & 2)) { + video_res_x /= 16; + video_res_y /= (nga->cga.crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (nga->cga.cgamode & 0x40) { + video_res_x /= 8; + video_res_y /= 2; + video_bpp = 1; + } + } + nga->cga.firstline = 1000; + nga->cga.lastline = 0; + nga->cga.cgablink++; + nga->cga.oddeven ^= 1; + } + } else { + nga->cga.sc++; + nga->cga.sc &= 31; + nga->cga.ma = nga->cga.maback; + } + + if (nga->cga.cgadispon) + nga->cga.cgastat &= ~1; + + /* enable cursor if its scanline was reached */ + if ((nga->cga.sc == (nga->cga.crtc[10] & 31) || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[10] & 31) >> 1)))) + nga->cga.con = 1; + } + /* 80-columns */ + if (nga->cga.cgadispon && (nga->cga.cgamode & 1) ) { + /* for each character per line */ + for (x = 0; x < (nga->cga.crtc[1] << 1); x++) + nga->cga.charbuffer[x] = nga->cga.vram[(((nga->cga.ma << 1) + x) & 0x3fff) + nga->base]; + } + } + } +} + +void +nga_close(void *priv) +{ + nga_t *nga = (nga_t *)priv; + free(nga->vram_64k); + free(nga->cga.vram); + free(nga); +} + +void +nga_speed_changed(void *priv) +{ + nga_t *nga = (nga_t *)priv; + + nga_recalctimings(nga); +} + +void * +nga_init(const device_t *info) +{ + int mem; + uint8_t charset; + nga_t *nga = (nga_t *)malloc(sizeof(nga_t)); + + memset(nga, 0x00, sizeof(nga_t)); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_nga); + + charset = device_get_config_int("charset"); + + loadfont_ex("roms/video/nga/ncr_nga_35122.bin", 1, 4096 * charset); + + nga->cga.composite = 0; + nga->cga.snow_enabled = device_get_config_int("snow_enabled"); + + nga->cga.vram = malloc(0x8000); + nga->vram_64k = malloc(0x8000); + + timer_add(&nga->cga.timer, nga_poll, nga, 1); + mem_mapping_add(&nga->cga.mapping, 0xb8000, 0x8000, + nga_read, NULL, NULL, + nga_write, NULL, NULL, NULL, 0, nga); + + mem = device_get_config_int("memory"); + + if (mem > 32) { + /* make optional 32KB addessable */ + mem_mapping_add(&nga->mapping_64k, 0xa8000, 0x8000, + nga_read, NULL, NULL, + nga_write, NULL, NULL, NULL, 0, nga); + } + + io_sethandler(0x03d0, 16, nga_in, NULL, NULL, nga_out, NULL, NULL, nga); + + overscan_x = overscan_y = 16; + nga->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (nga->cga.rgb_type << 1); + cgapal_rebuild(); + + return nga; +} + +const device_config_t nga_config[] = { +// clang-format off + { + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "Color", + .value = 0 + }, + { + .description = "Green Monochrome", + .value = 1 + }, + { + .description = "Amber Monochrome", + .value = 2 + }, + { + .description = "Gray Monochrome", + .value = 3 + }, + { + .description = "Color (no brown)", + .value = 4 + }, + { + .description = "" + } + } + }, + { + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 64, + .selection = { + { + .description = "32 KB", + .value = 32 + }, + { + .description = "64 KB", + .value = 64 + }, + { + .description = "" + } + } + }, + { + .name = "charset", + .description = "Character set", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "U.S. English", + .value = 0 + }, + { + .description = "Scandinavian", + .value = 1 + }, + { + .description = "Other languages", + .value = 2 + }, + { + .description = "E.F. Hutton", + .value = 3 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +// clang-format on +}; + +const device_t nga_device = { + .name = "NCR NGA", + .internal_name = "nga", + .flags = DEVICE_ISA, + .local = 0, + .init = nga_init, + .close = nga_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = nga_speed_changed, + .force_redraw = NULL, + .config = nga_config +}; diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index c3e5b11af..210afc2b2 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -28,16 +28,20 @@ #include <86box/device.h> #include <86box/video.h> #include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> -#define BIOS_037C_PATH L"roms/video/oti/bios.bin" -#define BIOS_067_AMA932J_PATH L"roms/machines/ama932j/oti067.bin" -#define BIOS_077_PATH L"roms/video/oti/oti077.vbi" +#define BIOS_037C_PATH "roms/video/oti/bios.bin" +#define BIOS_067_AMA932J_PATH "roms/machines/ama932j/OTI067.BIN" +#define BIOS_067_M300_08_PATH "roms/machines/m30008/EVC_BIOS.ROM" +#define BIOS_067_M300_15_PATH "roms/machines/m30015/EVC_BIOS.ROM" +#define BIOS_077_PATH "roms/video/oti/oti077.vbi" enum { OTI_037C, OTI_067 = 2, OTI_067_AMA932J, + OTI_067_M300 = 4, OTI_077 = 5 }; @@ -53,7 +57,7 @@ typedef struct { uint8_t pos; uint8_t enable_register; uint8_t dipswitch_val; - + uint32_t vram_size; uint32_t vram_mask; } oti_t; @@ -82,6 +86,14 @@ oti_out(uint16_t addr, uint8_t val, void *p) return; } else break; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (oti->chip_id == OTI_077) + sc1148x_ramdac_out(addr, 0, val, svga->ramdac, svga); + else + svga_out(addr, val, svga); + return; case 0x3D4: if (oti->chip_id) @@ -104,13 +116,18 @@ oti_out(uint16_t addr, uint8_t val, void *p) svga->crtc[idx] = val; if (old != val) { if ((idx < 0x0e) || (idx > 0x10)) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if (idx == 0x0c || idx == 0x0d) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } break; - case 0x3DE: + case 0x3DE: if (oti->chip_id) oti->index = val & 0x1f; else @@ -125,7 +142,7 @@ oti_out(uint16_t addr, uint8_t val, void *p) switch (idx) { case 0xD: if (oti->chip_id == OTI_067) { - svga->vram_display_mask = (val & 0xc) ? oti->vram_mask : 0x3ffff; + svga->vram_display_mask = (val & 0x0c) ? oti->vram_mask : 0x3ffff; if (!(val & 0x80)) svga->vram_display_mask = 0x3ffff; @@ -134,24 +151,24 @@ oti_out(uint16_t addr, uint8_t val, void *p) else mem_mapping_enable(&svga->mapping); } else if (oti->chip_id == OTI_077) { - svga->vram_display_mask = (val & 0xc) ? oti->vram_mask : 0x3ffff; + svga->vram_display_mask = (val & 0x0c) ? oti->vram_mask : 0x3ffff; switch ((val & 0xc0) >> 6) { case 0x00: /* 256 kB of memory */ default: enable = (oti->vram_size >= 256); - if (val & 0xc) + if (val & 0x0c) svga->vram_display_mask = MIN(oti->vram_mask, 0x3ffff); break; case 0x01: /* 1 MB of memory */ case 0x03: enable = (oti->vram_size >= 1024); - if (val & 0xc) + if (val & 0x0c) svga->vram_display_mask = MIN(oti->vram_mask, 0xfffff); break; case 0x02: /* 512 kB of memory */ enable = (oti->vram_size >= 512); - if (val & 0xc) + if (val & 0x0c) svga->vram_display_mask = MIN(oti->vram_mask, 0x7ffff); break; } @@ -186,13 +203,13 @@ oti_in(uint16_t addr, void *p) oti_t *oti = (oti_t *)p; svga_t *svga = &oti->svga; uint8_t idx, temp; - + if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3C3)) return 0xff; if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; - + switch (addr) { case 0x3C2: if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) @@ -208,6 +225,11 @@ oti_in(uint16_t addr, void *p) temp = oti->enable_register; break; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (oti->chip_id == OTI_077) + return sc1148x_ramdac_in(addr, 0, svga->ramdac, svga); + return svga_in(addr, svga); + case 0x3CF: return svga->gdcreg[svga->gdcaddr & 0xf]; @@ -272,12 +294,12 @@ oti_in(uint16_t addr, void *p) temp = oti->index; if (oti->chip_id) temp |= (oti->chip_id << 5); - break; + break; case 0x3DF: idx = oti->index; if (!oti->chip_id) - idx &= 0x1f; + idx &= 0x1f; if (idx == 0x10) temp = oti->dipswitch_val; else @@ -317,7 +339,7 @@ oti_pos_in(uint16_t addr, void *p) oti_t *oti = (oti_t *)p; return(oti->pos); -} +} static void @@ -326,10 +348,23 @@ oti_recalctimings(svga_t *svga) oti_t *oti = (oti_t *)svga->p; if (oti->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; + if (oti->regs[0x16] & 0x08) svga->ma_latch |= 0x20000; - if (oti->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; + if (oti->regs[0x14] & 0x01) svga->vtotal += 0x400; + if (oti->regs[0x14] & 0x02) svga->dispend += 0x400; + if (oti->regs[0x14] & 0x04) svga->vsyncstart += 0x400; + + if ((oti->regs[0x0d] & 0x0c) && !(oti->regs[0x0d] & 0x10)) svga->rowoffset <<= 1; svga->interlace = oti->regs[0x14] & 0x80; + + if (svga->bpp == 16) { + svga->render = svga_render_16bpp_highres; + svga->hdisp >>= 1; + } else if (svga->bpp == 15) { + svga->render = svga_render_15bpp_highres; + svga->hdisp >>= 1; + } } @@ -337,7 +372,7 @@ static void * oti_init(const device_t *info) { oti_t *oti = malloc(sizeof(oti_t)); - wchar_t *romfn = NULL; + char *romfn = NULL; memset(oti, 0x00, sizeof(oti_t)); oti->chip_id = info->local; @@ -351,7 +386,7 @@ oti_init(const device_t *info) oti->regs[0] = 0x08; /* FIXME: The BIOS wants to read this at index 0? This index is undocumented. */ /* io_sethandler(0x03c0, 32, oti_in, NULL, NULL, oti_out, NULL, NULL, oti); */ - break; + break; case OTI_067_AMA932J: romfn = BIOS_067_AMA932J_PATH; @@ -362,6 +397,16 @@ oti_init(const device_t *info) io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); break; + case OTI_067_M300: + if (rom_present(BIOS_067_M300_15_PATH)) + romfn = BIOS_067_M300_15_PATH; + else + romfn = BIOS_067_M300_08_PATH; + oti->vram_size = device_get_config_int("memory"); + oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */ + io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); + break; + case OTI_067: case OTI_077: romfn = BIOS_077_PATH; @@ -383,10 +428,14 @@ oti_init(const device_t *info) svga_init(info, &oti->svga, oti, oti->vram_size << 10, oti_recalctimings, oti_in, oti_out, NULL, NULL); + if (oti->chip_id == OTI_077) + oti->svga.ramdac = device_add(&sc11487_ramdac_device); /*Actually a 82c487, probably a clone.*/ + io_sethandler(0x03c0, 32, oti_in, NULL, NULL, oti_out, NULL, NULL, oti); oti->svga.miscout = 1; + oti->svga.packed_chain4 = 1; return(oti); } @@ -410,7 +459,7 @@ oti_speed_changed(void *p) svga_recalctimings(&oti->svga); } - + static void oti_force_redraw(void *p) @@ -427,12 +476,14 @@ oti037c_available(void) return(rom_present(BIOS_037C_PATH)); } + static int oti067_ama932j_available(void) { return(rom_present(BIOS_067_AMA932J_PATH)); } + static int oti067_077_available(void) { @@ -440,117 +491,162 @@ oti067_077_available(void) } -static const device_config_t oti067_config[] = +static int +oti067_m300_available(void) { - { - "memory", "Memory size", CONFIG_SELECTION, "", 512, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "" - } - } - }, - { - "", "", -1 - } + if (rom_present(BIOS_067_M300_15_PATH)) + return(rom_present(BIOS_067_M300_15_PATH)); + else + return(rom_present(BIOS_067_M300_08_PATH)); +} + +// clang-format off +static const device_config_t oti067_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; - -static const device_config_t oti067_ama932j_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 256, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t oti067_ama932j_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 256, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; +static const device_config_t oti077_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +}; +// clang-format on -static const device_config_t oti077_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 1024, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 - } +const device_t oti037c_device = { + .name = "Oak OTI-037C", + .internal_name = "oti037c", + .flags = DEVICE_ISA, + .local = 0, + .init = oti_init, + .close = oti_close, + .reset = NULL, + { .available = oti037c_available }, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = NULL }; -const device_t oti037c_device = -{ - "Oak OTI-037C", - DEVICE_ISA, - 0, - oti_init, oti_close, NULL, - oti037c_available, - oti_speed_changed, - oti_force_redraw +const device_t oti067_device = { + .name = "Oak OTI-067", + .internal_name = "oti067", + .flags = DEVICE_ISA, + .local = 2, + .init = oti_init, + .close = oti_close, + .reset = NULL, + { .available = oti067_077_available }, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = oti067_config }; -const device_t oti067_device = -{ - "Oak OTI-067", - DEVICE_ISA, - 2, - oti_init, oti_close, NULL, - oti067_077_available, - oti_speed_changed, - oti_force_redraw, - oti067_config +const device_t oti067_m300_device = { + .name = "Oak OTI-067 (Olivetti M300-08/15)", + .internal_name = "oti067_m300", + .flags = DEVICE_ISA, + .local = 4, + .init = oti_init, + .close = oti_close, + .reset = NULL, + { .available = oti067_m300_available }, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = oti067_config }; -const device_t oti067_ama932j_device = -{ - "Oak OTI-067 (AMA-932J)", - DEVICE_ISA, - 3, - oti_init, oti_close, NULL, - oti067_ama932j_available, - oti_speed_changed, - oti_force_redraw, - oti067_ama932j_config +const device_t oti067_ama932j_device = { + .name = "Oak OTI-067 (AMA-932J)", + .internal_name = "oti067_ama932j", + .flags = DEVICE_ISA, + .local = 3, + .init = oti_init, + .close = oti_close, + .reset = NULL, + { .available = oti067_ama932j_available }, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = oti067_ama932j_config }; -const device_t oti077_device = -{ - "Oak OTI-077", - DEVICE_ISA, - 5, - oti_init, oti_close, NULL, - oti067_077_available, - oti_speed_changed, - oti_force_redraw, - oti077_config +const device_t oti077_device = { + .name = "Oak OTI-077", + .internal_name = "oti077", + .flags = DEVICE_ISA, + .local = 5, + .init = oti_init, + .close = oti_close, + .reset = NULL, + { .available = oti067_077_available }, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = oti077_config }; diff --git a/src/video/vid_ogc.c b/src/video/vid_ogc.c new file mode 100644 index 000000000..0487d691d --- /dev/null +++ b/src/video/vid_ogc.c @@ -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. + * + * Emulation of the Olivetti OGC 8-bit ISA (GO708) and + * M21/M24/M28 16-bit bus (GO317/318/380/709) video cards. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ + +#include +#include +#include +#include +#include +#include +#include <86box/io.h> +#include <86box/video.h> +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/mem.h> +#include <86box/pit.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/vid_cga.h> +#include <86box/vid_ogc.h> +#include <86box/vid_cga_comp.h> + + + +/* + * Current bugs: + * - Olivetti diagnostics fail with errors: 6845 crtc write / read error out 0000 in 00ff + * - Dark blue (almost black) picture in composite mode + */ + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + + + +static video_timings_t timing_ogc = {VIDEO_ISA, 8,16,32, 8,16,32}; + +static uint8_t mdaattr[256][2][2]; + +void +ogc_recalctimings(ogc_t *ogc) +{ + double _dispontime, _dispofftime, disptime; + + if (ogc->cga.cgamode & 1) { + disptime = ogc->cga.crtc[0] + 1; + _dispontime = ogc->cga.crtc[1]; + } else { + disptime = (ogc->cga.crtc[0] + 1) << 1; + _dispontime = ogc->cga.crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST / 2; + _dispofftime *= CGACONST / 2; + ogc->cga.dispontime = (uint64_t)(_dispontime); + ogc->cga.dispofftime = (uint64_t)(_dispofftime); +} + +void +ogc_out(uint16_t addr, uint8_t val, void *priv) +{ + ogc_t *ogc = (ogc_t *)priv; + + // if (addr >= 0x3c0 && addr <= 0x3cf){ + // addr = addr + 16; + // } + + switch (addr) { + case 0x3d4: + case 0x3d5: + case 0x3d8: + case 0x3d9: + cga_out(addr, val, &ogc->cga); + break; + + case 0x3de: + /* set control register */ + ogc->ctrl_3de = val; + /* select 1st or 2nd 16k vram block to be used */ + ogc->base = (val & 0x08) ? 0x4000 : 0; + break; + } +} + +uint8_t +ogc_in(uint16_t addr, void *priv) +{ + ogc_t *ogc = (ogc_t *)priv; + + // if (addr >= 0x3c0 && addr <= 0x3cf){ + // addr = addr + 16; + // } + + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d4: + case 0x3d5: + case 0x3da: + /* + * bits 6-7: 3 = no DEB expansion board installed + * bits 4-5: 2 color, 3 mono + * bit 3: high during 1st half of vertical retrace in character mode (CCA standard) + * bit 2: lightpen switch (CGA standard) + * bit 1: lightpen strobe (CGA standard) + * bit 0: high during retrace (CGA standard) + */ + ret = cga_in(addr, &ogc->cga); + if (addr == 0x3da){ + ret = ret | 0xe0; + if (ogc->mono_display) + ret = ret | 0x10; + break; + } + } + + return(ret); +} + + +void +ogc_waitstates(void *p) +{ + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + + +void +ogc_write(uint32_t addr, uint8_t val, void *priv) +{ + ogc_t *ogc = (ogc_t *)priv; + int offset; + + ogc->cga.vram[addr & 0x7FFF]=val; + if (ogc->cga.snow_enabled) { + /* recreate snow effect */ + offset = ((timer_get_remaining_u64(&ogc->cga.timer) / CGACONST) * 4) & 0xfc; + ogc->cga.charbuffer[offset] = ogc->cga.vram[addr & 0x7fff]; + ogc->cga.charbuffer[offset | 1] = ogc->cga.vram[addr & 0x7fff]; + } + ogc_waitstates(&ogc->cga); +} + +uint8_t +ogc_read(uint32_t addr, void *priv) +{ + + ogc_t *ogc = (ogc_t *)priv; + int offset; + + ogc_waitstates(&ogc->cga); + + if (ogc->cga.snow_enabled) { + /* recreate snow effect */ + offset = ((timer_get_remaining_u64(&ogc->cga.timer) / CGACONST) * 4) & 0xfc; + ogc->cga.charbuffer[offset] = ogc->cga.vram[addr & 0x7fff]; + ogc->cga.charbuffer[offset | 1] = ogc->cga.vram[addr & 0x7fff]; + } + + return(ogc->cga.vram[addr & 0x7FFF]); +} + +void +ogc_poll(void *priv) +{ + ogc_t *ogc = (ogc_t *)priv; + uint16_t ca = (ogc->cga.crtc[15] | (ogc->cga.crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c, xs_temp, ys_temp; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2; + int cols[4]; + int oldsc; + int blink = 0; + int underline = 0; + uint8_t border; + + //composito colore appare blu scuro + + /* graphic mode and not mode 40h */ + if (!(ogc->ctrl_3de & 0x1 || !(ogc->cga.cgamode & 2))) { + /* standard cga mode */ + cga_poll(&ogc->cga); + return; + } else { + /* mode 40h or text mode */ + if (!ogc->cga.linepos) { + timer_advance_u64(&ogc->cga.timer, ogc->cga.dispofftime); + ogc->cga.cgastat |= 1; + ogc->cga.linepos = 1; + oldsc = ogc->cga.sc; + if ((ogc->cga.crtc[8] & 3) == 3) + ogc->cga.sc = ((ogc->cga.sc << 1) + ogc->cga.oddeven) & 7; + if (ogc->cga.cgadispon) { + if (ogc->cga.displine < ogc->cga.firstline) { + ogc->cga.firstline = ogc->cga.displine; + video_wait_for_buffer(); + } + ogc->cga.lastline = ogc->cga.displine; + /* 80-col */ + if (ogc->cga.cgamode & 1) { + /* for each text column */ + for (x = 0; x < ogc->cga.crtc[1]; x++) { + /* video output enabled */ + if (ogc->cga.cgamode & 8) { + /* character */ + chr = ogc->cga.charbuffer[x << 1]; + /* text attributes */ + attr = ogc->cga.charbuffer[(x << 1) + 1]; + } else + chr = attr = 0; + /* check if cursor has to be drawn */ + drawcursor = ((ogc->cga.ma == ca) && ogc->cga.con && ogc->cga.cursoron); + /* check if character underline mode should be set */ + underline = ((ogc->ctrl_3de & 0x40) && (attr & 0x1) && !(attr & 0x6)); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = (attr & 15) + 16; + /* blink active */ + if (ogc->cga.cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + /* attribute 7 active and not cursor */ + if ((ogc->cga.cgablink & 8) && (attr & 0x80) && !ogc->cga.drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[0] = (attr >> 4) + 16; + blink = (attr & 0x80) * 8 + 7 + 16; + } + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (ogc->cga.sc == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + + ogc->cga.ma++; + } + } + /* 40-col */ + else if (!(ogc->cga.cgamode & 2)) { + for (x = 0; x < ogc->cga.crtc[1]; x++) { + if (ogc->cga.cgamode & 8) { + chr = ogc->cga.vram[((ogc->cga.ma << 1) & 0x3fff) + ogc->base]; + attr = ogc->cga.vram[(((ogc->cga.ma << 1) + 1) & 0x3fff) + ogc->base]; + } else { + chr = attr = 0; + } + drawcursor = ((ogc->cga.ma == ca) && ogc->cga.con && ogc->cga.cursoron); + /* check if character underline mode should be set */ + underline = ((ogc->ctrl_3de & 0x40) && (attr & 0x1) && !(attr & 0x6)); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = (attr & 15) + 16; + /* blink active */ + if (ogc->cga.cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((ogc->cga.cgablink & 8) && (attr & 0x80) && !ogc->cga.drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[0] = (attr >> 4) + 16; + blink = (attr & 0x80) * 8 + 7 + 16; + } + + + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (ogc->cga.sc == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + + ogc->cga.ma++; + + } + } else { + /* 640x400 mode */ + if (ogc->ctrl_3de & 1 ) { + dat2 = ((ogc->cga.sc & 1) * 0x4000) | (ogc->lineff * 0x2000); + cols[0] = 0; cols[1] = 15 + 16; + } + else { + dat2 = (ogc->cga.sc & 1) * 0x2000; + cols[0] = 0; cols[1] = (ogc->cga.cgacol & 15) + 16; + } + + for (x = 0; x < ogc->cga.crtc[1]; x++) { + /* video out */ + if (ogc->cga.cgamode & 8) { + dat = (ogc->cga.vram[((ogc->cga.ma << 1) & 0x1fff) + dat2] << 8) | ogc->cga.vram[((ogc->cga.ma << 1) & 0x1fff) + dat2 + 1]; + } else { + dat = 0; + } + ogc->cga.ma++; + + for (c = 0; c < 16; c++) { + buffer32->line[ogc->cga.displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + + /* ogc specific */ + cols[0] = ((ogc->cga.cgamode & 0x12) == 0x12) ? 0 : (ogc->cga.cgacol & 15) + 16; + if (ogc->cga.cgamode & 1) { + hline(buffer32, 0, (ogc->cga.displine << 1), ((ogc->cga.crtc[1] << 3) + 16) << 2, cols[0]); + hline(buffer32, 0, (ogc->cga.displine << 1) + 1, ((ogc->cga.crtc[1] << 3) + 16) << 2, cols[0]); + } else { + hline(buffer32, 0, (ogc->cga.displine << 1), ((ogc->cga.crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (ogc->cga.displine << 1) + 1, ((ogc->cga.crtc[1] << 4) + 16) << 2, cols[0]); + } + + } + + /* 80 columns */ + if (ogc->cga.cgamode & 1) + x = (ogc->cga.crtc[1] << 3) + 16; + else + x = (ogc->cga.crtc[1] << 4) + 16; + + if (ogc->cga.composite) { + if (ogc->cga.cgamode & 0x10) + border = 0x00; + else + border = ogc->cga.cgacol & 0x0f; + + Composite_Process(ogc->cga.cgamode, border, x >> 2, buffer32->line[(ogc->cga.displine << 1)]); + Composite_Process(ogc->cga.cgamode, border, x >> 2, buffer32->line[(ogc->cga.displine << 1) + 1]); + } + + + ogc->cga.sc = oldsc; + if (ogc->cga.vc == ogc->cga.crtc[7] && !ogc->cga.sc) + ogc->cga.cgastat |= 8; + ogc->cga.displine++; + if (ogc->cga.displine >= 720) + ogc->cga.displine = 0; + } else { + timer_advance_u64(&ogc->cga.timer, ogc->cga.dispontime); + if (ogc->cga.cgadispon) ogc->cga.cgastat &= ~1; + ogc->cga.linepos = 0; + /* ogc specific */ + ogc->lineff ^= 1; + if (ogc->lineff) { + ogc->cga.ma = ogc->cga.maback; + } else { + if (ogc->cga.vsynctime) { + ogc->cga.vsynctime--; + if (!ogc->cga.vsynctime) + ogc->cga.cgastat &= ~8; + } + if (ogc->cga.sc == (ogc->cga.crtc[11] & 31) || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[11] & 31) >> 1))) { + ogc->cga.con = 0; + ogc->cga.coff = 1; + } + if ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[9] >> 1)) + ogc->cga.maback = ogc->cga.ma; + if (ogc->cga.vadj) { + ogc->cga.sc++; + ogc->cga.sc &= 31; + ogc->cga.ma = ogc->cga.maback; + ogc->cga.vadj--; + if (!ogc->cga.vadj) { + ogc->cga.cgadispon = 1; + ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[13] | (ogc->cga.crtc[12] << 8)) & 0x3fff; + ogc->cga.sc = 0; + } + // potrebbe dare problemi con composito + } else if (ogc->cga.sc == ogc->cga.crtc[9] || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[9] >> 1))) { + ogc->cga.maback = ogc->cga.ma; + ogc->cga.sc = 0; + oldvc = ogc->cga.vc; + ogc->cga.vc++; + ogc->cga.vc &= 127; + + if (ogc->cga.vc == ogc->cga.crtc[6]) + ogc->cga.cgadispon=0; + + if (oldvc == ogc->cga.crtc[4]) { + ogc->cga.vc = 0; + ogc->cga.vadj = ogc->cga.crtc[5]; + if (!ogc->cga.vadj) { + ogc->cga.cgadispon = 1; + ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[13] | (ogc->cga.crtc[12] << 8)) & 0x3fff; + } + switch (ogc->cga.crtc[10] & 0x60) { + case 0x20: + ogc->cga.cursoron = 0; + break; + case 0x60: + ogc->cga.cursoron = ogc->cga.cgablink & 0x10; + break; + default: + ogc->cga.cursoron = ogc->cga.cgablink & 0x08; + break; + } + } + if (ogc->cga.vc == ogc->cga.crtc[7]) { + ogc->cga.cgadispon = 0; + ogc->cga.displine = 0; + /* ogc specific */ + ogc->cga.vsynctime = (ogc->cga.crtc[3] >> 4) + 1; + if (ogc->cga.crtc[7]) { + if (ogc->cga.cgamode & 1) + x = (ogc->cga.crtc[1] << 3) + 16; + else + x = (ogc->cga.crtc[1] << 4) + 16; + ogc->cga.lastline++; + + xs_temp = x; + ys_temp = (ogc->cga.lastline - ogc->cga.firstline); + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xsize < 64) xs_temp = 656; + /* ogc specific */ + if (ysize < 32) ys_temp = 200; + if (!enable_overscan) + xs_temp -= 16; + + + if ((ogc->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + /* ogc specific */ + if (enable_overscan) { + if (ogc->cga.composite) + video_blit_memtoscreen(0, (ogc->cga.firstline - 8), + xsize, (ogc->cga.lastline - ogc->cga.firstline) + 16); + else + video_blit_memtoscreen_8(0, (ogc->cga.firstline - 8), + xsize, (ogc->cga.lastline - ogc->cga.firstline) + 16); + } else { + if (ogc->cga.composite) + video_blit_memtoscreen(8, ogc->cga.firstline, + xsize, (ogc->cga.lastline - ogc->cga.firstline)); + else + video_blit_memtoscreen_8(8, ogc->cga.firstline, + xsize, (ogc->cga.lastline - ogc->cga.firstline)); + } + } + frames++; + + video_res_x = xsize; + video_res_y = ysize; + /* 80-col */ + if (ogc->cga.cgamode & 1) { + video_res_x /= 8; + video_res_y /= (ogc->cga.crtc[9] + 1) * 2; + video_bpp = 0; + /* 40-col */ + } else if (!(ogc->cga.cgamode & 2)) { + video_res_x /= 16; + video_res_y /= (ogc->cga.crtc[9] + 1) * 2; + video_bpp = 0; + } else if (!(ogc->ctrl_3de & 1)) { + video_res_y /= 2; + video_bpp = 1; + } + } + ogc->cga.firstline = 1000; + ogc->cga.lastline = 0; + ogc->cga.cgablink++; + ogc->cga.oddeven ^= 1; + } + } else { + ogc->cga.sc++; + ogc->cga.sc &= 31; + ogc->cga.ma = ogc->cga.maback; + } + + if (ogc->cga.cgadispon) + ogc->cga.cgastat &= ~1; + + if ((ogc->cga.sc == (ogc->cga.crtc[10] & 31) || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[10] & 31) >> 1)))) + ogc->cga.con = 1; + } + /* 80-columns */ + if (ogc->cga.cgadispon && (ogc->cga.cgamode & 1)) { + for (x = 0; x < (ogc->cga.crtc[1] << 1); x++) + ogc->cga.charbuffer[x] = ogc->cga.vram[(((ogc->cga.ma << 1) + x) & 0x3fff) + ogc->base]; + } + } + } +} + +void +ogc_close(void *priv) +{ + ogc_t *ogc = (ogc_t *)priv; + + free(ogc->cga.vram); + free(ogc); +} + +void +ogc_speed_changed(void *priv) +{ + ogc_t *ogc = (ogc_t *)priv; + + ogc_recalctimings(ogc); +} + +void +ogc_mdaattr_rebuild(){ + int c; + + for (c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; + if (c & 8) mdaattr[c][0][1] = 15 + 16; + else mdaattr[c][0][1] = 7 + 16; + } + + mdaattr[0x70][0][1] = 16; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; + mdaattr[0xF0][0][1] = 16; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; + mdaattr[0x78][0][1] = 16 + 7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; + mdaattr[0xF8][0][1] = 16 + 7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; +} + +/* + * Missing features + * - Composite video mode not working + * - Optional EGC expansion board (which handles 640x400x16) not implemented + */ +void * +ogc_init(const device_t *info) +{ + // int display_type; + ogc_t *ogc = (ogc_t *)malloc(sizeof(ogc_t)); + + memset(ogc, 0x00, sizeof(ogc_t)); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_ogc); + + loadfont("roms/video/ogc/ogc graphics board go380 258 pqbq.bin", 1); + + /* composite is not working yet */ + // display_type = device_get_config_int("display_type"); + ogc->cga.composite = 0; // (display_type != CGA_RGB); + ogc->cga.revision = device_get_config_int("composite_type"); + ogc->cga.snow_enabled = device_get_config_int("snow_enabled"); + + ogc->cga.vram = malloc(0x8000); + + cga_comp_init(ogc->cga.revision); + timer_add(&ogc->cga.timer, ogc_poll, ogc, 1); + mem_mapping_add(&ogc->cga.mapping, 0xb8000, 0x08000, + ogc_read, NULL, NULL, + ogc_write, NULL, NULL, NULL, 0, ogc); + io_sethandler(0x03d0, 16, ogc_in, NULL, NULL, ogc_out, NULL, NULL, ogc); + + overscan_x = overscan_y = 16; + ogc->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (ogc->cga.rgb_type << 1); + cgapal_rebuild(); + ogc_mdaattr_rebuild(); + + /* color display */ + if (device_get_config_int("rgb_type")==0 || device_get_config_int("rgb_type") == 4) + ogc->mono_display = 0; + else + ogc->mono_display = 1; + + return ogc; +} + +const device_config_t ogc_m24_config[] = { +// clang-format off + { + /* Olivetti / ATT compatible displays */ + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_int = CGA_RGB, + .selection = { + { + .description = "Color", + .value = 0 + }, + { + .description = "Green Monochrome", + .value = 1 + }, + { + .description = "Amber Monochrome", + .value = 2 + }, + { + .description = "Gray Monochrome", + .value = 3 + }, + { + .description = "" + } + } + }, + { + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_int = 1, + }, + { + .type = CONFIG_END + } +// clang-format on +}; + +const device_t ogc_m24_device = { + .name = "Olivetti M21/M24/M28 (GO317/318/380/709) video card", + .internal_name = "ogc_m24", + .flags = DEVICE_ISA, + .local = 0, + .init = ogc_init, + .close = ogc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ogc_speed_changed, + .force_redraw = NULL, + .config = ogc_m24_config +}; + +const device_t ogc_device = { + .name = "Olivetti OGC (GO708)", + .internal_name = "ogc", + .flags = DEVICE_ISA, + .local = 0, + .init = ogc_init, + .close = ogc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ogc_speed_changed, + .force_redraw = NULL, + .config = cga_config +}; diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 3b6f3acab..3ca44746c 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -37,9 +37,11 @@ typedef struct paradise_t { svga_t svga; - + rom_t bios_rom; - + + uint8_t bank_mask; + enum { PVGA1A = 0, @@ -47,7 +49,27 @@ typedef struct paradise_t WD90C30 } type; + uint32_t vram_mask; + uint32_t read_bank[4], write_bank[4]; + + int interlace; + int check, check2; + + struct { + uint8_t reg_block_ptr; + uint8_t reg_idx; + uint8_t disable_autoinc; + + uint16_t int_status; + uint16_t blt_ctrl1, blt_ctrl2; + uint16_t srclow, srchigh; + uint16_t dstlow, dsthigh; + + uint32_t srcaddr, dstaddr; + + int invalid_block; + } accel; } paradise_t; static video_timings_t timing_paradise_pvga1a = {VIDEO_ISA, 6, 8, 16, 6, 8, 16}; @@ -55,77 +77,143 @@ static video_timings_t timing_paradise_wd90c = {VIDEO_ISA, 3, 3, 6, 5, 5, 1 void paradise_remap(paradise_t *paradise); +uint8_t paradise_in(uint16_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return 0xff; + if (svga->seqaddr > 0x12) + return 0xff; + return svga->seqregs[svga->seqaddr & 0x1f]; + } + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (paradise->type == WD90C30) + return sc1148x_ramdac_in(addr, 0, svga->ramdac, svga); + return svga_in(addr, svga); + + case 0x3cf: + if (svga->gdcaddr >= 9 && svga->gdcaddr <= 0x0e) { + if (svga->gdcreg[0x0f] & 0x10) + return 0xff; + } + switch (svga->gdcaddr) { + case 0x0b: + if (paradise->type == WD90C30) { + if (paradise->vram_mask == ((512 << 10) - 1)) { + svga->gdcreg[0x0b] |= 0xc0; + svga->gdcreg[0x0b] &= ~0x40; + } + } + return svga->gdcreg[0x0b]; + + case 0x0f: + return (svga->gdcreg[0x0f] & 0x17) | 0x80; + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return 0xff; + if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} void paradise_out(uint16_t addr, uint8_t val, void *p) { paradise_t *paradise = (paradise_t *)p; svga_t *svga = ¶dise->svga; uint8_t old; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + + if (paradise->vram_mask <= ((512 << 10) - 1)) + paradise->bank_mask = 0x7f; + else + paradise->bank_mask = 0xff; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + switch (addr) { case 0x3c5: - if (svga->seqaddr > 7) - { - if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) - return; - svga->seqregs[svga->seqaddr & 0x1f] = val; - if (svga->seqaddr == 0x11) - paradise_remap(paradise); - return; + if (svga->seqaddr > 7) { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return; + svga->seqregs[svga->seqaddr & 0x1f] = val; + if (svga->seqaddr == 0x11) { + paradise_remap(paradise); + } + return; } break; + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (paradise->type == WD90C30) + sc1148x_ramdac_out(addr, 0, val, svga->ramdac, svga); + else + svga_out(addr, val, svga); + return; + case 0x3cf: - if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) - { - if ((svga->gdcreg[0xf] & 7) != 5) - return; - } - if (svga->gdcaddr == 6) - { - if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) - { - switch (val&0xC) - { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); - svga->banked_mask = 0xffff; - break; - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - svga->banked_mask = 0xffff; - break; - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - svga->banked_mask = 0x7fff; - break; - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - svga->banked_mask = 0x7fff; - break; - } - } - svga->gdcreg[6] = val; - paradise_remap(paradise); - return; - } - if (svga->gdcaddr == 0x9 || svga->gdcaddr == 0xa) - { - svga->gdcreg[svga->gdcaddr] = val; - paradise_remap(paradise); - return; - } - if (svga->gdcaddr == 0xe) - { - svga->gdcreg[0xe] = val; - paradise_remap(paradise); - return; + if (svga->gdcaddr >= 9 && svga->gdcaddr <= 0x0e) { + if ((svga->gdcreg[0x0f] & 7) != 5) + return; } + + switch (svga->gdcaddr) { + case 6: + if ((svga->gdcreg[6] & 0x0c) != (val & 0x0c)) { + switch (val & 0x0c) { + case 0x00: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x04: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x08: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x0c: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + svga->gdcreg[6] = val; + paradise_remap(paradise); + return; + + case 9: + case 0x0a: + svga->gdcreg[svga->gdcaddr] = val & paradise->bank_mask; + paradise_remap(paradise); + return; + case 0x0b: + svga->gdcreg[0x0b] = val; + paradise_remap(paradise); + return; + } break; - + case 0x3D4: svga->crtcreg = val & 0x3f; return; @@ -145,142 +233,302 @@ void paradise_out(uint16_t addr, uint8_t val, void *p) if (old != val) { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(¶dise->svga); - } - } - break; - } - svga_out(addr, val, svga); -} - -uint8_t paradise_in(uint16_t addr, void *p) -{ - paradise_t *paradise = (paradise_t *)p; - svga_t *svga = ¶dise->svga; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c2: - return 0x10; - - case 0x3c5: - if (svga->seqaddr > 7) - { - if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) - return 0xff; - if (svga->seqaddr > 0x12) - return 0xff; - return svga->seqregs[svga->seqaddr & 0x1f]; - } - break; - - case 0x3cf: - if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) - { - if (svga->gdcreg[0xf] & 0x10) - return 0xff; - switch (svga->gdcaddr) - { - case 0xf: - return (svga->gdcreg[0xf] & 0x17) | 0x80; + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } break; - case 0x3D4: - return svga->crtcreg; - case 0x3D5: - if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) - return 0xff; - if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) - return 0xff; - return svga->crtc[svga->crtcreg]; + case 0x46e8: + io_removehandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + mem_mapping_disable(¶dise->svga.mapping); + if (val & 8) + { + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + mem_mapping_enable(¶dise->svga.mapping); + } + break; } - return svga_in(addr, svga); + + svga_out(addr, val, svga); } void paradise_remap(paradise_t *paradise) { - svga_t *svga = ¶dise->svga; + svga_t *svga = ¶dise->svga; + paradise->check = 0; - uint8_t mask = (paradise->type == WD90C11) ? 0x7f : 0xff; - - if (svga->seqregs[0x11] & 0x80) - { - paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12; - paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12; - paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - } - else if (svga->gdcreg[0xe] & 0x08) - { - if (svga->gdcreg[0x6] & 0xc) - { - paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & mask) << 12; - paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12; - paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - } - else - { - paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & mask) << 12; - paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12; - paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - } - } - else - { - paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12; - paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12; - paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); - } + if (svga->seqregs[0x11] & 0x80) { + paradise->read_bank[0] = paradise->read_bank[2] = svga->gdcreg[9] << 12; + paradise->read_bank[1] = paradise->read_bank[3] = (svga->gdcreg[9] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = svga->gdcreg[0x0a] << 12; + paradise->write_bank[1] = paradise->write_bank[3] = (svga->gdcreg[0x0a] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } else if (svga->gdcreg[0x0b] & 0x08) { + if (svga->gdcreg[6] & 0x0c) { + paradise->read_bank[0] = paradise->read_bank[2] = svga->gdcreg[0x0a] << 12; + paradise->write_bank[0] = paradise->write_bank[2] = svga->gdcreg[0x0a] << 12; + paradise->read_bank[1] = paradise->read_bank[3] = (svga->gdcreg[9] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[1] = paradise->write_bank[3] = (svga->gdcreg[9] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } else { + paradise->read_bank[0] = paradise->write_bank[0] = svga->gdcreg[0x0a] << 12; + paradise->read_bank[1] = paradise->write_bank[1] = (svga->gdcreg[0xa] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->read_bank[2] = paradise->write_bank[2] = svga->gdcreg[9] << 12; + paradise->read_bank[3] = paradise->write_bank[3] = (svga->gdcreg[9] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + } else { + paradise->read_bank[0] = paradise->read_bank[2] = svga->gdcreg[9] << 12; + paradise->read_bank[1] = paradise->read_bank[3] = (svga->gdcreg[9] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = svga->gdcreg[9] << 12; + paradise->write_bank[1] = paradise->write_bank[3] = (svga->gdcreg[9] << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + + if ((((svga->gdcreg[0x0b] & 0xc0) == 0xc0) && !svga->chain4 && (svga->crtc[0x14] & 0x40) && ((svga->gdcreg[6] >> 2) & 3) == 1)) + paradise->check = 1; + + if (paradise->bank_mask == 0x7f) { + paradise->read_bank[1] &= 0x7ffff; + paradise->write_bank[1] &= 0x7ffff; + } } void paradise_recalctimings(svga_t *svga) { paradise_t *paradise = (paradise_t *) svga->p; - if (paradise->type == WD90C30) - svga->interlace = (svga->crtc[0x2d] & 0x20); + svga->lowres = !(svga->gdcreg[0x0e] & 0x01); - svga->lowres = !(svga->gdcreg[0xe] & 0x01); - if (svga->bpp == 8 && !svga->lowres) - svga->render = svga_render_8bpp_highres; + if (paradise->type == WD90C30) { + if (svga->crtc[0x3e] & 0x01) svga->vtotal |= 0x400; + if (svga->crtc[0x3e] & 0x02) svga->dispend |= 0x400; + if (svga->crtc[0x3e] & 0x04) svga->vsyncstart |= 0x400; + if (svga->crtc[0x3e] & 0x08) svga->vblankstart |= 0x400; + if (svga->crtc[0x3e] & 0x10) svga->split |= 0x400; + + svga->interlace = !!(svga->crtc[0x2d] & 0x20); + + if (!svga->interlace && svga->lowres && (svga->hdisp >= 1024) && + ((svga->gdcreg[5] & 0x60) == 0) && (svga->miscout >= 0x27) && + (svga->miscout <= 0x2f) && ((svga->gdcreg[6] & 1) || + (svga->attrregs[0x10] & 1))) { /*Horrible tweak to re-enable the interlace after returning to + a windowed DOS box in Win3.x*/ + svga->interlace = 1; + } + } + + if (paradise->type < WD90C30) { + if (svga->bpp >= 8 && !svga->lowres) { + svga->render = svga_render_8bpp_highres; + } + } else { + if (svga->bpp >= 8 && !svga->lowres) { + if (svga->bpp == 16) { + svga->render = svga_render_16bpp_highres; + svga->hdisp >>= 1; + } else if (svga->bpp == 15) { + svga->render = svga_render_15bpp_highres; + svga->hdisp >>= 1; + } else { + svga->render = svga_render_8bpp_highres; + } + } + } } static void paradise_write(uint32_t addr, uint8_t val, void *p) { paradise_t *paradise = (paradise_t *)p; - addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + svga_t *svga = ¶dise->svga; + uint32_t prev_addr, prev_addr2; - svga_write_linear(addr, val, ¶dise->svga); + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + + /*Could be done in a better way but it works.*/ + if (!svga->lowres) { + if (paradise->check) { + prev_addr = addr & 3; + prev_addr2 = addr & 0xfffc; + if ((addr & 3) == 3) { + if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 2) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 1) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 0) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } + } + } + + svga_write_linear(addr, val, svga); } static void paradise_writew(uint32_t addr, uint16_t val, void *p) { paradise_t *paradise = (paradise_t *)p; - addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; - svga_writew_linear(addr, val, ¶dise->svga); + svga_t *svga = ¶dise->svga; + uint32_t prev_addr, prev_addr2; + + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + + /*Could be done in a better way but it works.*/ + if (!svga->lowres) { + if (paradise->check) { + prev_addr = addr & 3; + prev_addr2 = addr & 0xfffc; + if ((addr & 3) == 3) { + if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 2) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 1) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 0) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } + } + } + + svga_writew_linear(addr, val, svga); } static uint8_t paradise_read(uint32_t addr, void *p) { paradise_t *paradise = (paradise_t *)p; - addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; - return svga_read_linear(addr, ¶dise->svga); + svga_t *svga = ¶dise->svga; + uint32_t prev_addr, prev_addr2; + + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + + /*Could be done in a better way but it works.*/ + if (!svga->lowres) { + if (paradise->check) { + prev_addr = addr & 3; + prev_addr2 = addr & 0xfffc; + if ((addr & 3) == 3) { + if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 2) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 1) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 0) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } + } + } + + return svga_read_linear(addr, svga); } static uint16_t paradise_readw(uint32_t addr, void *p) { paradise_t *paradise = (paradise_t *)p; - addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; - return svga_readw_linear(addr, ¶dise->svga); + svga_t *svga = ¶dise->svga; + uint32_t prev_addr, prev_addr2; + + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + + /*Could be done in a better way but it works.*/ + if (!svga->lowres) { + if (paradise->check) { + prev_addr = addr & 3; + prev_addr2 = addr & 0xfffc; + if ((addr & 3) == 3) { + if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 2) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 1) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x00000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } else if ((addr & 3) == 0) { + if ((addr & 0x30000) == 0x30000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x20000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + else if ((addr & 0x30000) == 0x10000) + addr = (addr >> 16) | (prev_addr << 16) | prev_addr2; + } + } + } + + return svga_readw_linear(addr, svga); } void *paradise_init(const device_t *info, uint32_t memsize) @@ -288,8 +536,6 @@ void *paradise_init(const device_t *info, uint32_t memsize) paradise_t *paradise = malloc(sizeof(paradise_t)); svga_t *svga = ¶dise->svga; memset(paradise, 0, sizeof(paradise_t)); - - io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); if (info->local == PVGA1A) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_paradise_pvga1a); @@ -298,30 +544,39 @@ void *paradise_init(const device_t *info, uint32_t memsize) switch(info->local) { case PVGA1A: - svga_init(info, ¶dise->svga, paradise, memsize, /*256kb*/ - NULL, + svga_init(info, svga, paradise, memsize, /*256kb*/ + paradise_recalctimings, paradise_in, paradise_out, NULL, NULL); + paradise->vram_mask = memsize - 1; + svga->decode_mask = memsize - 1; break; case WD90C11: - svga_init(info, ¶dise->svga, paradise, 1 << 19, /*512kb*/ + svga_init(info, svga, paradise, 1 << 19, /*512kb*/ paradise_recalctimings, paradise_in, paradise_out, NULL, NULL); + paradise->vram_mask = (1 << 19) - 1; + svga->decode_mask = (1 << 19) - 1; break; case WD90C30: - svga_init(info, ¶dise->svga, paradise, memsize, + svga_init(info, svga, paradise, memsize, paradise_recalctimings, paradise_in, paradise_out, NULL, NULL); + paradise->vram_mask = memsize - 1; + svga->decode_mask = memsize - 1; + svga->ramdac = device_add(&sc11487_ramdac_device); /*Actually a Winbond W82c487-80, probably a clone.*/ break; } - mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); - mem_mapping_set_p(¶dise->svga.mapping, paradise); + mem_mapping_set_handler(&svga->mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(&svga->mapping, paradise); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); /* Common to all three types. */ svga->crtc[0x31] = 'W'; @@ -334,6 +589,7 @@ void *paradise_init(const device_t *info, uint32_t memsize) case WD90C11: svga->crtc[0x36] = '1'; svga->crtc[0x37] = '1'; + io_sethandler(0x46e8, 0x0001, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); break; case WD90C30: svga->crtc[0x36] = '3'; @@ -341,30 +597,41 @@ void *paradise_init(const device_t *info, uint32_t memsize) break; } - svga->bpp = 8; - svga->miscout = 1; + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = info->local; + + return paradise; +} + +static void *paradise_pvga1a_ncr3302_init(const device_t *info) +{ + paradise_t *paradise = paradise_init(info, 1 << 18); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/machines/3302/c000-wd_1987-1989-740011-003058-019c.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - paradise->type = info->local; - return paradise; } static void *paradise_pvga1a_pc2086_init(const device_t *info) { paradise_t *paradise = paradise_init(info, 1 << 18); - + if (paradise) - rom_init(¶dise->bios_rom, L"roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + rom_init(¶dise->bios_rom, "roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + return paradise; } + static void *paradise_pvga1a_pc3086_init(const device_t *info) { paradise_t *paradise = paradise_init(info, 1 << 18); if (paradise) - rom_init(¶dise->bios_rom, L"roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + rom_init(¶dise->bios_rom, "roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + return paradise; } @@ -377,44 +644,44 @@ static void *paradise_pvga1a_standalone_init(const device_t *info) memory <<= 10; paradise = paradise_init(info, memory); - + if (paradise) - rom_init(¶dise->bios_rom, L"roms/video/pvga1a/BIOS.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + rom_init(¶dise->bios_rom, "roms/video/pvga1a/BIOS.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + return paradise; } static int paradise_pvga1a_standalone_available(void) { - return rom_present(L"roms/video/pvga1a/BIOS.BIN"); + return rom_present("roms/video/pvga1a/BIOS.BIN"); } static void *paradise_wd90c11_megapc_init(const device_t *info) { paradise_t *paradise = paradise_init(info, 0); - + if (paradise) rom_init_interleaved(¶dise->bios_rom, - L"roms/machines/megapc/41651-bios lo.u18", - L"roms/machines/megapc/211253-bios hi.u19", + "roms/machines/megapc/41651-bios lo.u18", + "roms/machines/megapc/211253-bios hi.u19", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + return paradise; } static void *paradise_wd90c11_standalone_init(const device_t *info) { paradise_t *paradise = paradise_init(info, 0); - + if (paradise) - rom_init(¶dise->bios_rom, L"roms/video/wd90c11/WD90C11.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + rom_init(¶dise->bios_rom, "roms/video/wd90c11/WD90C11.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + return paradise; } static int paradise_wd90c11_standalone_available(void) { - return rom_present(L"roms/video/wd90c11/WD90C11.VBI"); + return rom_present("roms/video/wd90c11/WD90C11.VBI"); } static void *paradise_wd90c30_standalone_init(const device_t *info) @@ -426,16 +693,16 @@ static void *paradise_wd90c30_standalone_init(const device_t *info) memory <<= 10; paradise = paradise_init(info, memory); - + if (paradise) - rom_init(¶dise->bios_rom, L"roms/video/wd90c30/90C30-LR.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, "roms/video/wd90c30/90C30-LR.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } static int paradise_wd90c30_standalone_available(void) { - return rom_present(L"roms/video/wd90c30/90C30-LR.VBI"); + return rom_present("roms/video/wd90c30/90C30-LR.VBI"); } void paradise_close(void *p) @@ -443,14 +710,14 @@ void paradise_close(void *p) paradise_t *paradise = (paradise_t *)p; svga_close(¶dise->svga); - + free(paradise); } void paradise_speed_changed(void *p) { paradise_t *paradise = (paradise_t *)p; - + svga_recalctimings(¶dise->svga); } @@ -461,129 +728,152 @@ void paradise_force_redraw(void *p) paradise->svga.fullchange = changeframecount; } - -const device_t paradise_pvga1a_pc2086_device = -{ - "Paradise PVGA1A (Amstrad PC2086)", - 0, - PVGA1A, - paradise_pvga1a_pc2086_init, - paradise_close, - NULL, - NULL, - paradise_speed_changed, - paradise_force_redraw, - NULL -}; -const device_t paradise_pvga1a_pc3086_device = -{ - "Paradise PVGA1A (Amstrad PC3086)", - 0, - PVGA1A, - paradise_pvga1a_pc3086_init, - paradise_close, - NULL, - NULL, - paradise_speed_changed, - paradise_force_redraw, - NULL +const device_t paradise_pvga1a_pc2086_device = { + .name = "Paradise PVGA1A (Amstrad PC2086)", + .internal_name = "pvga1a_pc2086", + .flags = 0, + .local = PVGA1A, + .init = paradise_pvga1a_pc2086_init, + .close = paradise_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = NULL }; -static const device_config_t paradise_pvga1a_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 512, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 +const device_t paradise_pvga1a_pc3086_device = { + .name = "Paradise PVGA1A (Amstrad PC3086)", + .internal_name = "pvga1a_pc3086", + .flags = 0, + .local = PVGA1A, + .init = paradise_pvga1a_pc3086_init, + .close = paradise_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = NULL +}; + +static const device_config_t paradise_pvga1a_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } }; -const device_t paradise_pvga1a_device = -{ - "Paradise PVGA1A", - DEVICE_ISA, - PVGA1A, - paradise_pvga1a_standalone_init, - paradise_close, - NULL, - paradise_pvga1a_standalone_available, - paradise_speed_changed, - paradise_force_redraw, - paradise_pvga1a_config -}; -const device_t paradise_wd90c11_megapc_device = -{ - "Paradise WD90C11 (Amstrad MegaPC)", - 0, - WD90C11, - paradise_wd90c11_megapc_init, - paradise_close, - NULL, - NULL, - paradise_speed_changed, - paradise_force_redraw, - NULL -}; -const device_t paradise_wd90c11_device = -{ - "Paradise WD90C11-LR", - DEVICE_ISA, - WD90C11, - paradise_wd90c11_standalone_init, - paradise_close, - NULL, - paradise_wd90c11_standalone_available, - paradise_speed_changed, - paradise_force_redraw, - NULL +const device_t paradise_pvga1a_ncr3302_device = { + .name = "Paradise PVGA1A (NCR 3302)", + .internal_name = "pvga1a_ncr3302", + .flags = 0, + .local = PVGA1A, + .init = paradise_pvga1a_ncr3302_init, + .close = paradise_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = paradise_pvga1a_config }; -static const device_config_t paradise_wd90c30_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 1024, - { - { - "512 kB", 512 - }, - { - "1 MB", 1024 - }, - { - "" - } - } - }, - { - "", "", -1 +const device_t paradise_pvga1a_device = { + .name = "Paradise PVGA1A", + .internal_name = "pvga1a", + .flags = DEVICE_ISA, + .local = PVGA1A, + .init = paradise_pvga1a_standalone_init, + .close = paradise_close, + .reset = NULL, + { .available = paradise_pvga1a_standalone_available }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = paradise_pvga1a_config +}; + +const device_t paradise_wd90c11_megapc_device = { + .name = "Paradise WD90C11 (Amstrad MegaPC)", + .internal_name = "wd90c11_megapc", + .flags = 0, + .local = WD90C11, + .init = paradise_wd90c11_megapc_init, + .close = paradise_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = NULL +}; + +const device_t paradise_wd90c11_device = { + .name = "Paradise WD90C11-LR", + .internal_name = "wd90c11", + .flags = DEVICE_ISA, + .local = WD90C11, + .init = paradise_wd90c11_standalone_init, + .close = paradise_close, + .reset = NULL, + { .available = paradise_wd90c11_standalone_available }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = NULL +}; + +static const device_config_t paradise_wd90c30_config[] = { +// clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } } + }, + { + .type = CONFIG_END + } +// clang-format on }; -const device_t paradise_wd90c30_device = -{ - "Paradise WD90C30-LR", - DEVICE_ISA, - WD90C30, - paradise_wd90c30_standalone_init, - paradise_close, - NULL, - paradise_wd90c30_standalone_available, - paradise_speed_changed, - paradise_force_redraw, - paradise_wd90c30_config +const device_t paradise_wd90c30_device = { + .name = "Paradise WD90C30-LR", + .internal_name = "wd90c30", + .flags = DEVICE_ISA, + .local = WD90C30, + .init = paradise_wd90c30_standalone_init, + .close = paradise_close, + .reset = NULL, + { .available = paradise_wd90c30_standalone_available }, + .speed_changed = paradise_speed_changed, + .force_redraw = paradise_force_redraw, + .config = paradise_wd90c30_config }; diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c index 8f92bbd0d..d810536b3 100644 --- a/src/video/vid_pgc.c +++ b/src/video/vid_pgc.c @@ -8,13 +8,13 @@ * * This implements just enough of the Professional Graphics * Controller to act as a basis for the Vermont Microsystems - * IM-1024. + * IM-1024. * * PGC features implemented include: * > The CGA-compatible display modes * > Switching to and from native mode * > Communicating with the host PC - * + * * Numerous features are implemented partially or not at all, * such as: * > 2D drawing @@ -87,6 +87,7 @@ #include <86box/device.h> #include <86box/pit.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> #include <86box/vid_cga.h> #include <86box/vid_pgc.h> @@ -113,7 +114,7 @@ static const char *pgc_err_msgs[] = { "Too long\r", "Area \r", "Missing \r", - "Unknown \r" + "Unknown \r" }; @@ -167,7 +168,7 @@ output_byte(pgc_t *dev, uint8_t val) pgc_log("PGC: output buffer state: %02x %02x Sleeping\n", dev->mapram[0x302], dev->mapram[0x303]); dev->waiting_output_fifo = 1; - pgc_sleep(dev); + pgc_sleep(dev); } if (dev->mapram[0x3ff]) { @@ -206,7 +207,7 @@ error_byte(pgc_t *dev, uint8_t val) /* If error buffer full, wait for it to empty. */ while (!dev->stopped && dev->mapram[0x304] == dev->mapram[0x305] - 1) { dev->waiting_error_fifo = 1; - pgc_sleep(dev); + pgc_sleep(dev); } if (dev->mapram[0x3ff]) { @@ -238,7 +239,7 @@ error_string(pgc_t *dev, const char *s) /* * Read next byte from the input buffer. * - * If no byte available will sleep until one is. Returns 0 if + * If no byte available will sleep until one is. Returns 0 if * a PGC reset has been triggered by a write to 0xC63FF. */ static int @@ -247,7 +248,7 @@ input_byte(pgc_t *dev, uint8_t *result) /* If input buffer empty, wait for it to fill. */ while (!dev->stopped && (dev->mapram[0x300] == dev->mapram[0x301])) { dev->waiting_input_fifo = 1; - pgc_sleep(dev); + pgc_sleep(dev); } if (dev->stopped) @@ -303,7 +304,7 @@ read_command(pgc_t *dev) return pgc_clist_byte(dev, &dev->hex_command); if (dev->ascii_mode) { - char ch; + char ch; int count = 0; while (count < 7) { @@ -359,7 +360,7 @@ parse_command(pgc_t *dev, const pgc_cmd_t **pcmd) /* If in ASCII mode match on the ASCII command. */ if (dev->ascii_mode && !dev->clcur) { - sprintf(match, "%-6.6s", cmd->ascii); + sprintf(match, "%-6.6s", cmd->ascii); if (! strncmp(match, dev->asc_command, 6)) { *pcmd = cmd; dev->hex_command = cmd->hex; @@ -400,20 +401,20 @@ hndl_clbeg(pgc_t *dev) while (1) { if (! parse_command(dev, &cmd)) { /* PGC has been reset. */ - return; - } + return; + } if (!cmd) { pgc_error(dev, PGC_ERROR_OPCODE); - return; + return; } else if (dev->hex_command == 0x71) { /* CLEND */ dev->clist[param] = cl; return; - } else { + } else { if (! pgc_cl_append(&cl, dev->hex_command)) { pgc_error(dev, PGC_ERROR_OVERFLOW); return; - } + } if (cmd->parser) { if (! (*cmd->parser)(dev, &cl, cmd->p)) @@ -526,8 +527,8 @@ hndl_color(pgc_t *dev) /* - * Set drawing mode. - * + * Set drawing mode. + * * 0 => Draw * 1 => Invert */ @@ -667,7 +668,7 @@ pgc_write_pixel(pgc_t *dev, uint16_t x, uint16_t y, uint8_t ink) uint8_t *vram; /* Suppress out-of-range writes; clip to viewport. */ - if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || + if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || y < dev->vp_y1 || y > dev->vp_y2 || y >= dev->maxh) { pgc_log("PGC: write_pixel clipped: (%i,%i) " "vp_x1=%i vp_y1=%i vp_x2=%i vp_y2=%i " @@ -689,7 +690,7 @@ pgc_read_pixel(pgc_t *dev, uint16_t x, uint16_t y) uint8_t *vram; /* Suppress out-of-range reads. */ - if (x >= dev->maxw || y >= dev->maxh) + if (x >= dev->maxw || y >= dev->maxh) return 0; vram = pgc_vram_addr(dev, x, y); @@ -712,10 +713,10 @@ pgc_plot(pgc_t *dev, uint16_t x, uint16_t y) uint8_t *vram; /* Only allow plotting within the current viewport. */ - if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || + if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || y < dev->vp_y1 || y > dev->vp_y2 || y >= dev->maxh) { pgc_log("PGC: plot clipped: (%i,%i) %i <= x <= %i; %i <= y <= %i; " - "mode=%i ink=0x%02x\n", x, y, + "mode=%i ink=0x%02x\n", x, y, dev->vp_x1, dev->vp_x2, dev->vp_y1, dev->vp_y2, dev->draw_mode, dev->color); return; @@ -752,7 +753,7 @@ pgc_plot(pgc_t *dev, uint16_t x, uint16_t y) * Draw a line (using raster coordinates). * * Bresenham's Algorithm from: - * + * * * The line pattern mask to use is passed in. Return value is the * line pattern mask, rotated by the number of points drawn. @@ -813,7 +814,7 @@ pgc_draw_line(pgc_t *dev, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16 /* - * Draw a horizontal line in the current fill pattern + * Draw a horizontal line in the current fill pattern * (using raster coordinates). */ void @@ -832,8 +833,8 @@ pgc_fill_line_r(pgc_t *dev, int32_t x0, int32_t x1, int32_t y0) if (dev->fill_pattern[y0 & 0x0F] & mask) pgc_plot(dev, x, y0); mask = mask >> 1; - if (mask == 0) mask = 0x8000; - } + if (mask == 0) mask = 0x8000; + } } @@ -896,8 +897,8 @@ pgc_fill_polygon(pgc_t *dev, unsigned corners, int32_t *x, int32_t *y) } /* Polygon fill. Based on */ - /* For each row, work out where the polygon lines intersect with - * that row. */ + /* For each row, work out where the polygon lines intersect with + * that row. */ for (ypos = ymin; ypos <= ymax; ypos++) { nodes = 0; j = corners - 1; @@ -907,7 +908,7 @@ pgc_fill_polygon(pgc_t *dev, unsigned corners, int32_t *x, int32_t *y) nodex[nodes++] = dx[i] + (ypos-dy[i])/(dy[j]-dy[i]) * (dx[j] - dx[i]); } j = i; - } + } /* Sort the intersections. */ if (nodes) @@ -1041,14 +1042,14 @@ parse_poly(pgc_t *dev, pgc_cl_t *cl, int c) if (! pgc_cl_append(cl, count)) { pgc_error(dev, PGC_ERROR_OVERFLOW); - return 0; + return 0; } pgc_log("PCG: parse_poly: parse %i coords\n", 2 * count); return pgc_parse_coords(dev, cl, 2 * count); } - + /* Handle the DISPLAY command. */ static void hndl_display(pgc_t *dev) @@ -1059,7 +1060,7 @@ hndl_display(pgc_t *dev) pgc_log("PGC: DISPLAY(%i)\n", param); - if (param > 1) + if (param > 1) pgc_error(dev, PGC_ERROR_RANGE); else pgc_setdisplay(dev, param); @@ -1101,7 +1102,7 @@ hndl_imagew(pgc_t *dev) if (v1 & 0x80) { /* Literal run. */ v1 -= 0x7f; - while (col1 <= col2 && v1 != 0) { + while (col1 <= col2 && v1 != 0) { if (! pgc_param_byte(dev, &v2)) return; pgc_write_pixel(dev, col1, row, v2); col1++; @@ -1110,14 +1111,14 @@ hndl_imagew(pgc_t *dev) } else { /* Repeated run. */ if (! pgc_param_byte(dev, &v2)) return; - + v1++; - while (col1 <= col2 && v1 != 0) { + while (col1 <= col2 && v1 != 0) { pgc_write_pixel(dev, col1, row, v2); col1++; v1--; } - } + } } } @@ -1166,9 +1167,9 @@ hndl_lutrd(pgc_t *dev) col = dev->palette[param]; - pgc_result_byte(dev, (col >> 20) & 0x0f); - pgc_result_byte(dev, (col >> 12) & 0x0f); - pgc_result_byte(dev, (col >> 4) & 0x0f); + pgc_result_byte(dev, (col >> 20) & 0x0f); + pgc_result_byte(dev, (col >> 12) & 0x0f); + pgc_result_byte(dev, (col >> 4) & 0x0f); } @@ -1195,7 +1196,7 @@ hndl_lut(pgc_t *dev) /* * LUT8RD and LUT8 are extensions implemented by several PGC clones, - * so here are functions that implement them even though they aren't + * so here are functions that implement them even though they aren't * used by the PGC. */ void @@ -1208,8 +1209,8 @@ pgc_hndl_lut8rd(pgc_t *dev) col = dev->palette[param]; - pgc_result_byte(dev, (col >> 16) & 0xff); - pgc_result_byte(dev, (col >> 8) & 0xff); + pgc_result_byte(dev, (col >> 16) & 0xff); + pgc_result_byte(dev, (col >> 8) & 0xff); pgc_result_byte(dev, col & 0xff); } @@ -1363,7 +1364,7 @@ hndl_window(pgc_t *dev) * * In order to support the original PGC and clones, we support two lists; * core commands (listed below) and subclass commands (listed in the clone). - * + * * Each row has five parameters: * ASCII-mode command * Hex-mode command @@ -1373,7 +1374,7 @@ hndl_window(pgc_t *dev) * * TODO: This list omits numerous commands present in a genuine PGC * (ARC, AREA, AREABC, BUFFER, CIRCLE etc etc). - * TODO: Some commands don't have a parse function (for example, IMAGEW) + * TODO: Some commands don't have a parse function (for example, IMAGEW) * * The following ASCII entries have special meaning: * ~~~~~~ command is valid only in hex mode @@ -1438,7 +1439,7 @@ static const pgc_cmd_t pgc_commands[] = { { "VWPORT", 0xb2, hndl_vwport, pgc_parse_words, 4 }, { "VWP", 0xb2, hndl_vwport, pgc_parse_words, 4 }, { "WINDOW", 0xb3, hndl_window, pgc_parse_words, 4 }, - { "WI", 0xb3, hndl_window, pgc_parse_words, 4 }, + { "WI", 0xb3, hndl_window, pgc_parse_words, 4 }, { "@@@@@@", 0x00, NULL, NULL, 0 } }; @@ -1452,7 +1453,7 @@ wake_timer(void *priv) pgc_t *dev = (pgc_t *)priv; #ifdef ENABLE_PGC_LOG - pgc_log("PGC: woke up\n"); + pgc_log("PGC: woke up\n"); #endif thread_set_event(dev->pgc_wake_thread); @@ -1487,9 +1488,9 @@ pgc_thread(void *priv) /* Nope, just a reset. */ continue; - } + } - pgc_log("PGC: Command: [%02x] '%s' found = %i\n", + pgc_log("PGC: Command: [%02x] '%s' found = %i\n", dev->hex_command, dev->asc_command, (cmd != NULL)); if (cmd) { @@ -1514,7 +1515,7 @@ err_digit(pgc_t *dev) do { /* Swallow everything until the next separator */ if (! dev->inputbyte(dev, &asc)) return 0; - } while (! is_whitespace(asc)); + } while (! is_whitespace(asc)); pgc_error(dev, PGC_ERROR_DIGIT); @@ -1537,7 +1538,7 @@ pgc_result_byte(pgc_t *dev, uint8_t val) sprintf(buf, "%i", val); dev->result_count++; - return output_string(dev, buf); + return output_string(dev, buf); } @@ -1558,7 +1559,7 @@ pgc_result_word(pgc_t *dev, int16_t val) sprintf(buf, "%i", val); dev->result_count++; - return output_string(dev, buf); + return output_string(dev, buf); } @@ -1665,7 +1666,7 @@ pgc_setdisplay(pgc_t *dev, int cga) /* * When idle, the PGC drawing thread sleeps. pgc_wake() awakens it - but - * not immediately. Like the Voodoo, it has a short delay so that writes + * not immediately. Like the Voodoo, it has a short delay so that writes * can be batched. */ void @@ -1683,7 +1684,7 @@ pgc_sleep(pgc_t *dev) pgc_log("PGC: sleeping on %i %i %i %i 0x%02x 0x%02x\n", dev->stopped, dev->waiting_input_fifo, dev->waiting_output_fifo, - dev->waiting_error_fifo, dev->mapram[0x300], dev->mapram[0x301]); + dev->waiting_error_fifo, dev->mapram[0x300], dev->mapram[0x301]); /* Avoid entering waiting state. */ if (dev->stopped) { @@ -1720,7 +1721,7 @@ pgc_clist_byte(pgc_t *dev, uint8_t *val) if (dev->clcur->rdptr < dev->clcur->wrptr) *val = dev->clcur->list[dev->clcur->rdptr++]; - else + else *val = 0; /* If we've reached the end, reset to the beginning and @@ -1844,7 +1845,7 @@ pgc_param_coord(pgc_t *dev, int32_t *value) return 1; } - /* If in hex mode, read in the encoded integer and fraction parts + /* If in hex mode, read in the encoded integer and fraction parts * from the hex stream */ if (! dev->ascii_mode) { for (n = 0; n < 4; n++) @@ -1860,7 +1861,7 @@ pgc_param_coord(pgc_t *dev, int32_t *value) do { if (! dev->inputbyte(dev, &asc)) return 0; if (asc == '-') sign = -1; - } while (is_whitespace(asc)); + } while (is_whitespace(asc)); /* There had better be a digit next. */ if (! isdigit(asc)) { @@ -1888,7 +1889,7 @@ pgc_param_coord(pgc_t *dev, int32_t *value) case 'D': case 'e': case 'E': - esign = 1; + esign = 1; if (! dev->inputbyte(dev, &asc)) return 0; if (asc == '-') { sign = -1; @@ -1907,12 +1908,12 @@ pgc_param_coord(pgc_t *dev, int32_t *value) asc -= '0'; /* asc is digit */ switch (state) { - case PS_MAIN: + case PS_MAIN: integer = (integer * 10)+asc; if (integer & 0x8000) { /* Overflow */ pgc_error(dev, PGC_ERROR_RANGE); - integer = 0x7fff; + integer = 0x7fff; } break; @@ -1925,11 +1926,11 @@ pgc_param_coord(pgc_t *dev, int32_t *value) exponent = (exponent * 10)+asc; break; } - + } if (! dev->inputbyte(dev, &asc)) return 0; - } while (! is_whitespace(asc)); + } while (! is_whitespace(asc)); res = (frac << 16) / dp; pgc_log("PGC: integer=%u frac=%u exponent=%u dp=%i res=0x%08lx\n", @@ -1944,7 +1945,7 @@ pgc_param_coord(pgc_t *dev, int32_t *value) res /= 10; } } - *value = sign*res; + *value = sign*res; return 1; } @@ -1998,7 +1999,7 @@ pgc_parse_bytes(pgc_t *dev, pgc_cl_t *cl, int count) if (! param) { pgc_error(dev, PGC_ERROR_OVERFLOW); - return 0; + return 0; } for (n = 0; n < count; n++) { @@ -2010,7 +2011,7 @@ pgc_parse_bytes(pgc_t *dev, pgc_cl_t *cl, int count) if (! pgc_cl_append(cl, param[n])) { pgc_error(dev, PGC_ERROR_OVERFLOW); free(param); - return 0; + return 0; } } @@ -2029,7 +2030,7 @@ pgc_parse_words(pgc_t *dev, pgc_cl_t *cl, int count) if (! param) { pgc_error(dev, PGC_ERROR_OVERFLOW); - return 0; + return 0; } for (n = 0; n < count; n++) { @@ -2042,7 +2043,7 @@ pgc_parse_words(pgc_t *dev, pgc_cl_t *cl, int count) !pgc_cl_append(cl, param[n] >> 8)) { pgc_error(dev, PGC_ERROR_OVERFLOW); free(param); - return 0; + return 0; } } @@ -2061,7 +2062,7 @@ pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) if (! param) { pgc_error(dev, PGC_ERROR_OVERFLOW); - return 0; + return 0; } for (n = 0; n < count; n++) { @@ -2073,7 +2074,7 @@ pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) /* Here is how the real PGC serializes coords: * - * 100.5 -> 64 00 00 80 ie 0064.8000 + * 100.5 -> 64 00 00 80 ie 0064.8000 * 100.3 -> 64 00 CD 4C ie 0064.4CCD */ for (n = 0; n < count; n++) { @@ -2086,7 +2087,7 @@ pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) !pgc_cl_append(cl, (param[n] >> 8) & 0xff)) { pgc_error(dev, PGC_ERROR_OVERFLOW); free(param); - return 0; + return 0; } } @@ -2096,7 +2097,7 @@ pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) } -/* Convert coordinates based on the current window / viewport to raster +/* Convert coordinates based on the current window / viewport to raster * coordinates. */ void pgc_dto_raster(pgc_t *dev, double *x, double *y) @@ -2171,7 +2172,7 @@ pgc_out(uint16_t addr, uint8_t val, void *priv) case 0x03d5: case 0x03d7: if (dev->mapram[0x03d0] < 18) - dev->mapram[0x03e0 + dev->mapram[0x03d0]] = val; + dev->mapram[0x03e0 + dev->mapram[0x03d0]] = val; break; case 0x03d8: /* CRTC Mode Control register */ @@ -2235,7 +2236,7 @@ pgc_write(uint32_t addr, uint8_t val, void *priv) pgc_t *dev = (pgc_t *)priv; /* - * It seems variable whether the PGC maps 1K or 2K at 0xc6000. + * It seems variable whether the PGC maps 1K or 2K at 0xc6000. * * Map 2K here in case a clone requires it. */ @@ -2264,7 +2265,7 @@ pgc_write(uint32_t addr, uint8_t val, void *priv) pgc_wake(dev); } break; - + case 0x305: /* error read pointer */ if (dev->waiting_error_fifo && dev->mapram[0x304] != (uint8_t)(dev->mapram[0x305] - 1)) { @@ -2333,13 +2334,13 @@ pgc_cga_text(pgc_t *dev, int w) int cw = (w == 80) ? 8 : 16; addr = &dev->cga_vram[((ma + ((dev->displine / pitch) * w)) * 2) & 0x3ffe]; - ma += (dev->displine / pitch) * w; + ma += (dev->displine / pitch) * w; for (x = 0; x < w; x++) { chr = *addr++; attr = *addr++; - /* Cursor enabled? */ + /* Cursor enabled? */ if (ma == ca && (dev->cgablink & 8) && (dev->mapram[0x3ea] & 0x60) != 0x20) { drawcursor = ((dev->mapram[0x3ea] & 0x1f) <= (sc >> 1)) && @@ -2350,19 +2351,24 @@ pgc_cga_text(pgc_t *dev, int w) if (dev->mapram[0x3d8] & 0x20) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; - if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor) + if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; - } else { + } else { cols[1] = (attr & 15) + 16; cols[0] = (attr >> 4) + 16; } - for (c = 0; c < cw; c++) { + for (c = 0; c < cw; c++) { if (drawcursor) val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; else val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; - buffer32->line[dev->displine][(x * cw) + c] = val; + if (cw == 8) /* 80x25 CGA text screen. */ + buffer32->line[dev->displine][(x * cw) + c] = val; + else { /* 40x25 CGA text screen. */ + buffer32->line[dev->displine][(x * cw) + (c * 2)] = val; + buffer32->line[dev->displine][(x * cw) + (c * 2) + 1] = val; + } } ma++; @@ -2390,26 +2396,26 @@ pgc_cga_gfx40(pgc_t *dev) magenta/cyan/white. You still get red/cyan/white if bit 5 of port 03D9h is not set. This is a firmware issue rather than hardware. */ if (dev->mapram[0x3d9] & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } else if (dev->mapram[0x3d8] & 4) { - cols[1] = col | 3; - cols[2] = col | 4; + cols[1] = col | 3; + cols[2] = col | 5; cols[3] = col | 7; - } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; + } else if (dev->mapram[0x3d8] & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; } for (x = 0; x < 40; x++) { addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; dat = (addr[0] << 8) | addr[1]; dev->ma++; - for (c = 0; c < 8; c++) { - buffer32->line[dev->displine][(x << 4) + (c << 1)] = - buffer32->line[dev->displine][(x << 4) + (c << 1) + 1] = cols[dat >> 14]; + for (c = 0; c < 8; c++) { + buffer32->line[dev->displine][(x << 4) + (c << 1)] = + buffer32->line[dev->displine][(x << 4) + (c << 1) + 1] = cols[dat >> 14]; dat <<= 2; } } @@ -2433,8 +2439,8 @@ pgc_cga_gfx80(pgc_t *dev) addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; dat = (addr[0] << 8) | addr[1]; dev->ma++; - for (c = 0; c < 16; c++) { - buffer32->line[dev->displine][(x << 4) + c] = cols[dat >> 15]; + for (c = 0; c < 16; c++) { + buffer32->line[dev->displine][(x << 4) + c] = cols[dat >> 15]; dat <<= 1; } } @@ -2457,12 +2463,12 @@ pgc_cga_poll(pgc_t *dev) video_wait_for_buffer(); if ((dev->mapram[0x03d8] & 0x12) == 0x12) - pgc_cga_gfx80(dev); + pgc_cga_gfx80(dev); else if (dev->mapram[0x03d8] & 0x02) pgc_cga_gfx40(dev); else if (dev->mapram[0x03d8] & 0x01) pgc_cga_text(dev, 80); - else + else pgc_cga_text(dev, 40); } else { cols[0] = ((dev->mapram[0x03d8] & 0x12) == 0x12) ? 0 : ((dev->mapram[0x03d9] & 15) + 16); @@ -2492,13 +2498,13 @@ pgc_cga_poll(pgc_t *dev) if (video_force_resize_get()) video_force_resize_set(0); - } - video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + } + video_blit_memtoscreen_8(0, 0, xsize, ysize); frames++; /* We have a fixed 640x400 screen for CGA modes. */ - video_res_x = PGC_CGA_WIDTH; - video_res_y = PGC_CGA_HEIGHT; + video_res_x = PGC_CGA_WIDTH; + video_res_y = PGC_CGA_HEIGHT; switch (dev->mapram[0x3d8] & 0x12) { case 0x12: video_bpp = 1; @@ -2540,7 +2546,7 @@ pgc_poll(void *priv) video_wait_for_buffer(); /* Don't know why pan needs to be multiplied by -2, but - * the IM1024 driver uses PAN -112 for an offset of + * the IM1024 driver uses PAN -112 for an offset of * 224. */ y = dev->displine - 2 * dev->pan_y; for (x = 0; x < dev->screenw; x++) { @@ -2577,8 +2583,8 @@ pgc_poll(void *priv) if (video_force_resize_get()) video_force_resize_set(0); - } - video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + } + video_blit_memtoscreen(0, 0, xsize, ysize); frames++; video_res_x = dev->screenw; @@ -2600,7 +2606,7 @@ pgc_speed_changed(void *priv) void -pgc_close(void *priv) +pgc_close_common(void *priv) { pgc_t *dev = (pgc_t *)priv; @@ -2624,7 +2630,7 @@ pgc_close(void *priv) pgc_log("PGC: waiting for thread to stop...\n"); #endif // while (dev->stopped); - thread_wait(dev->pgc_thread, -1); + thread_wait(dev->pgc_thread); #ifdef ENABLE_PGC_LOG pgc_log("PGC: thread stopped, closing up.\n"); #endif @@ -2633,16 +2639,25 @@ pgc_close(void *priv) free(dev->cga_vram); if (dev->vram) free(dev->vram); +} + + +void +pgc_close(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + pgc_close_common(priv); free(dev); } /* - * Initialization code common to the PGC and its subclasses. + * Initialization code common to the PGC and its subclasses. * - * Pass the 'input byte' function in since this is overridden in - * the IM-1024, and needs to be set before the drawing thread is + * Pass the 'input byte' function in since this is overridden in + * the IM-1024, and needs to be set before the drawing thread is * launched. */ void @@ -2657,7 +2672,7 @@ pgc_init(pgc_t *dev, int maxw, int maxh, int visw, int vish, mem_mapping_add(&dev->mapping, 0xc4000, 16384, pgc_read,NULL,NULL, pgc_write,NULL,NULL, NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_add(&dev->cga_mapping, 0xb8000, 32768, + mem_mapping_add(&dev->cga_mapping, 0xb8000, 32768, pgc_read,NULL,NULL, pgc_write,NULL,NULL, NULL, MEM_MAPPING_EXTERNAL, dev); @@ -2696,7 +2711,7 @@ pgc_init(pgc_t *dev, int maxw, int maxh, int visw, int vish, dev->pgc_thread = thread_create(pgc_thread, dev); timer_add(&dev->timer, pgc_poll, dev, 1); - + timer_add(&dev->wake_timer, wake_timer, dev, 0); } @@ -2720,13 +2735,15 @@ pgc_standalone_init(const device_t *info) const device_t pgc_device = { - "PGC", - DEVICE_ISA, 0, - pgc_standalone_init, - pgc_close, - NULL, - NULL, - pgc_speed_changed, - NULL, - NULL + .name = "PGC", + .internal_name = "pgc", + .flags = DEVICE_ISA, + .local = 0, + .init = pgc_standalone_init, + .close = pgc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = pgc_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_rtg310x.c b/src/video/vid_rtg310x.c new file mode 100644 index 000000000..2eb82626b --- /dev/null +++ b/src/video/vid_rtg310x.c @@ -0,0 +1,404 @@ +/* + * 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 the Realtek RTG series of VGA ISA chips. + * + * + * + * Authors: TheCollector1995, + * + * Copyright 2021 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> + + +#define BIOS_ROM_PATH "roms/video/rtg/realtekrtg3106.BIN" + +typedef struct { + const char *name; + int type; + + svga_t svga; + + rom_t bios_rom; + + uint8_t bank3d6, + bank3d7; + + uint32_t vram_size, + vram_mask; +} rtg_t; + + +static video_timings_t timing_rtg_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; + +static void rtg_recalcbanking(rtg_t *dev) +{ + svga_t *svga = &dev->svga; + + svga->write_bank = (dev->bank3d7 & 0x0f) * 65536; + + if (svga->gdcreg[0x0f] & 4) + svga->read_bank = (dev->bank3d6 & 0x0f) * 65536; + else + svga->read_bank = svga->write_bank; +} + + +static uint8_t +rtg_in(uint16_t addr, void *priv) +{ + rtg_t *dev = (rtg_t *)priv; + svga_t *svga = &dev->svga; + uint8_t ret = 0; + + if (((addr & 0xfff0) == 0x3d0 || + (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3ce: + return svga->gdcaddr; + + case 0x3cf: + if (svga->gdcaddr == 0x0c) + return svga->gdcreg[0x0c] | 4; + else if ((svga->gdcaddr > 8) && (svga->gdcaddr != 0x0c)) + return svga->gdcreg[svga->gdcaddr]; + break; + + case 0x3d4: + return svga->crtcreg; + + case 0x3d5: + if (!(svga->crtc[0x1e] & 0x80) && (svga->crtcreg > 0x18)) + return 0xff; + if (svga->crtcreg == 0x1a) + return dev->type << 6; + if (svga->crtcreg == 0x1e) { + if (dev->vram_size == 1024) + ret = 2; + else if (dev->vram_size == 512) + ret = 1; + else + ret = 0; + return svga->crtc[0x1e] | ret; + } + return svga->crtc[svga->crtcreg]; + + case 0x3d6: + return dev->bank3d6; + + case 0x3d7: + return dev->bank3d7; + } + + return svga_in(addr, svga); +} + +static void +rtg_out(uint16_t addr, uint8_t val, void *priv) +{ + rtg_t *dev = (rtg_t *)priv; + svga_t *svga = &dev->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || + (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3ce: + svga->gdcaddr = val; + return; + + case 0x3cf: + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr] = val; + + switch (svga->gdcaddr) { + case 0x0b: + case 0x0c: + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + + case 0x0f: + rtg_recalcbanking(dev); + return; + } + } + break; + + case 0x3d4: + svga->crtcreg = val & 0x3f; + return; + + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (svga->crtc[0x1e] & 0x80) { + switch (svga->crtcreg) { + case 0x19: + svga->vram_display_mask = (val & 0x20) ? dev->vram_mask : 0x3ffff; + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + } + } + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } + break; + + case 0x3d6: + dev->bank3d6 = val; + rtg_recalcbanking(dev); + return; + + case 0x3d7: + dev->bank3d7 = val; + rtg_recalcbanking(dev); + return; + } + + svga_out(addr, val, svga); +} + +static void +rtg_recalctimings(svga_t *svga) +{ + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->ma_latch |= ((svga->crtc[0x19] & 0x10) << 16) | ((svga->crtc[0x19] & 0x40) << 17); + + svga->interlace = (svga->crtc[0x19] & 1); + + svga->lowres = svga->attrregs[0x10] & 0x40; + + /*Clock table not available, currently a guesswork*/ + switch (((svga->miscout >> 2) & 3) | ((svga->gdcreg[0x0c] & 0x20) >> 3)) { + case 0: + case 1: + break; + case 2: + svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; + break; + case 3: + svga->clock = (cpuclock * (double)(1ull << 32)) / 65100000.0; + break; + case 4: + svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; + break; + case 5: + svga->clock = (cpuclock * (double)(1ull << 32)) / 50000000.0; + break; + case 6: + svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; + break; + case 7: + svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; + break; + } + + switch (svga->gdcreg[0x0c] & 3) { + case 1: + svga->clock /= 1.5; + break; + case 2: + svga->clock /= 2; + break; + case 3: + svga->clock /= 4; + break; + } + + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else { + svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); + svga->hdisp++; + svga->hdisp *= 8; + + if (svga->hdisp == 1280) + svga->rowoffset >>= 1; + + svga->render = svga_render_4bpp_highres; + } + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: + svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); + svga->hdisp++; + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + if (svga->crtc[0x19] & 2) { + if (svga->hdisp == 1280) { + svga->hdisp >>= 1; + } else + svga->rowoffset <<= 1; + + svga->render = svga_render_8bpp_highres; + } else { + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + } + break; + } + } +} + +static void * +rtg_init(const device_t *info) +{ + const char *fn; + rtg_t *dev; + + dev = (rtg_t *)malloc(sizeof(rtg_t)); + memset(dev, 0x00, sizeof(rtg_t)); + dev->name = info->name; + dev->type = info->local; + fn = BIOS_ROM_PATH; + + switch(dev->type) { + case 2: /* ISA RTG3106 */ + dev->vram_size = device_get_config_int("memory") << 10; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_rtg_isa); + svga_init(info, &dev->svga, dev, dev->vram_size, + rtg_recalctimings, rtg_in, rtg_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + rtg_in,NULL,NULL, rtg_out,NULL,NULL, dev); + break; + } + + dev->svga.bpp = 8; + dev->svga.miscout = 1; + + dev->vram_mask = dev->vram_size - 1; + + rom_init(&dev->bios_rom, (char *) fn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return(dev); +} + + +static void +rtg_close(void *priv) +{ + rtg_t *dev = (rtg_t *)priv; + + svga_close(&dev->svga); + + free(dev); +} + + +static void +rtg_speed_changed(void *priv) +{ + rtg_t *dev = (rtg_t *)priv; + + svga_recalctimings(&dev->svga); +} + + +static void +rtg_force_redraw(void *priv) +{ + rtg_t *dev = (rtg_t *)priv; + + dev->svga.fullchange = changeframecount; +} + + +static int +rtg_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} + +static const device_config_t rtg_config[] = { +// clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "256 KB", + .value = 256 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +// clang-format on +}; + +const device_t realtek_rtg3106_device = { + .name = "Realtek RTG3106 (ISA)", + .internal_name = "rtg3106", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 2, + .init = rtg_init, + .close = rtg_close, + .reset = NULL, + { .available = rtg_available }, + .speed_changed = rtg_speed_changed, + .force_redraw = rtg_force_redraw, + .config = rtg_config +}; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 551229513..b6a1af232 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include <86box/86box.h> #include <86box/device.h> @@ -29,22 +30,46 @@ #include <86box/pci.h> #include <86box/rom.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> #include "cpu.h" -#define ROM_ORCHID_86C911 L"roms/video/s3/BIOS.BIN" -#define ROM_METHEUS_86C928 L"roms/video/s3/928.vbi" -#define ROM_V7MIRAGE_86C801 L"roms/video/s3/v7mirage.vbi" -#define ROM_PHOENIX_86C805 L"roms/video/s3/805.vbi" -#define ROM_PARADISE_BAHAMAS64 L"roms/video/s3/bahamas64.bin" -#define ROM_PHOENIX_VISION864 L"roms/video/s3/86c864p.bin" -#define ROM_DIAMOND_STEALTH64_964 L"roms/video/s3/964_107h.rom" -#define ROM_PHOENIX_TRIO32 L"roms/video/s3/86c732p.bin" -#define ROM_NUMBER9_9FX L"roms/video/s3/s3_764.bin" -#define ROM_PHOENIX_TRIO64 L"roms/video/s3/86c764x1.bin" -#define ROM_DIAMOND_STEALTH64_764 L"roms/video/s3/stealt64.bin" +#define ROM_ORCHID_86C911 "roms/video/s3/BIOS.BIN" +#define ROM_DIAMOND_STEALTH_VRAM "roms/video/s3/Diamond Stealth VRAM BIOS v2.31 U14.BIN" +#define ROM_AMI_86C924 "roms/video/s3/S3924AMI.BIN" +#define ROM_METHEUS_86C928 "roms/video/s3/928.VBI" +#define ROM_SPEA_MERCURY_LITE_PCI "roms/video/s3/SPEAVGA.VBI" +#define ROM_SPEA_MIRAGE_86C801 "roms/video/s3/V7MIRAGE.VBI" +#define ROM_SPEA_MIRAGE_86C805 "roms/video/s3/86c805pspeavlbus.BIN" +#define ROM_MIROCRYSTAL8S_805 "roms/video/s3/S3_805VL_ATT20C491_miroCRYSTAL_8s_ver1.4.BIN" +#define ROM_MIROCRYSTAL10SD_805 "roms/video/s3/MIROcrystal10SD_VLB.VBI" +#define ROM_MIROCRYSTAL20SV_964_VLB "roms/video/s3/S3_964VL_BT485_27C256_miroCRYSTAL_20sv_ver1.2.bin" +#define ROM_MIROCRYSTAL20SV_964_PCI "roms/video/s3/mirocrystal.VBI" +#define ROM_MIROCRYSTAL20SD_864_VLB "roms/video/s3/Miro20SD.BIN" +#define ROM_PHOENIX_86C80X "roms/video/s3/805.VBI" +#define ROM_PARADISE_BAHAMAS64 "roms/video/s3/bahamas64.bin" +#define ROM_PHOENIX_VISION864 "roms/video/s3/86c864p.bin" +#define ROM_DIAMOND_STEALTH64_964 "roms/video/s3/964_107h.rom" +#define ROM_PHOENIX_TRIO32 "roms/video/s3/86c732p.bin" +#define ROM_SPEA_MIRAGE_P64 "roms/video/s3/S3_764VL_SPEAMirageP64VL_ver5_03.BIN" +#define ROM_NUMBER9_9FX "roms/video/s3/s3_764.bin" +#define ROM_PHOENIX_TRIO64 "roms/video/s3/86c764x1.bin" +#define ROM_DIAMOND_STEALTH64_764 "roms/video/s3/stealt64.bin" +#define ROM_TRIO64V2_DX_VBE20 "roms/video/s3/86c775_2.bin" +#define ROM_PHOENIX_TRIO64VPLUS "roms/video/s3/64V1506.ROM" +#define ROM_DIAMOND_STEALTH_SE "roms/video/s3/DiamondStealthSE.VBI" +#define ROM_ELSAWIN2KPROX_964 "roms/video/s3/elsaw20004m.BIN" +#define ROM_ELSAWIN2KPROX "roms/video/s3/elsaw20008m.BIN" +#define ROM_NUMBER9_9FX_531 "roms/video/s3/numbernine.BIN" +#define ROM_PHOENIX_VISION868 "roms/video/s3/1-DSV3868.BIN" +#define ROM_MIROVIDEO40SV_ERGO_968_PCI "roms/video/s3/S3_968PCI_TVP3026_miroVideo40SV_PCI_1.04.BIN" +#define ROM_SPEA_MERCURY_P64V "roms/video/s3/S3_968PCI_TVP3026_SPEAMecuryP64V_ver1.01.BIN" +#define ROM_NUMBER9_9FX_771 "roms/video/s3/no9motionfx771.BIN" +#define ROM_PHOENIX_VISION968 "roms/video/s3/1-DSV3968P.BIN" enum { @@ -56,33 +81,70 @@ enum S3_PHOENIX_TRIO64_ONBOARD, S3_PHOENIX_VISION864, S3_DIAMOND_STEALTH64_764, - S3_V7MIRAGE_86C801, + S3_SPEA_MIRAGE_86C801, + S3_SPEA_MIRAGE_86C805, + S3_PHOENIX_86C801, S3_PHOENIX_86C805, S3_ORCHID_86C911, - S3_METHEUS_86C928 + S3_METHEUS_86C928, + S3_AMI_86C924, + S3_TRIO64V2_DX, + S3_TRIO64V2_DX_ONBOARD, + S3_PHOENIX_TRIO64VPLUS, + S3_PHOENIX_TRIO64VPLUS_ONBOARD, + S3_DIAMOND_STEALTH_SE, + S3_DIAMOND_STEALTH_VRAM, + S3_ELSAWIN2KPROX_964, + S3_ELSAWIN2KPROX, + S3_PHOENIX_VISION868, + S3_MIROVIDEO40SV_ERGO_968, + S3_MIROCRYSTAL10SD_805, + S3_SPEA_MIRAGE_P64, + S3_SPEA_MERCURY_P64V, + S3_MIROCRYSTAL20SV_964, + S3_MIROCRYSTAL20SD_864, + S3_PHOENIX_VISION968, + S3_MIROCRYSTAL8S_805, + S3_NUMBER9_9FX_531, + S3_NUMBER9_9FX_771, + S3_SPEA_MERCURY_LITE_PCI, + S3_86C805_ONBOARD }; + enum { - S3_86C801, - S3_86C805, - S3_86C928, - S3_86C911, - S3_VISION864, - S3_VISION964, - S3_TRIO32, - S3_TRIO64 + S3_86C911 = 0x00, + S3_86C924 = 0x02, + S3_86C928 = 0x04, + S3_86C928PCI = 0x06, + S3_86C801 = 0x07, + S3_86C805 = 0x08, + S3_VISION964 = 0x18, + S3_VISION968 = 0x20, + S3_VISION864 = 0x28, + S3_VISION868 = 0x30, + S3_TRIO32 = 0x38, + S3_TRIO64 = 0x40, + S3_TRIO64V = 0x48, + S3_TRIO64V2 = 0x50 }; + static video_timings_t timing_s3_86c911 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_86c801 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_86c805 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_86c928pci = {VIDEO_PCI, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_stealth64_vlb = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_stealth64_pci = {VIDEO_PCI, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_s3_vision864_vlb = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_vision864_pci = {VIDEO_PCI, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_vision868_vlb = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_vision868_pci = {VIDEO_PCI, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_vision964_vlb = {VIDEO_BUS, 2, 2, 4, 20, 20, 35}; static video_timings_t timing_s3_vision964_pci = {VIDEO_PCI, 2, 2, 4, 20, 20, 35}; +static video_timings_t timing_s3_vision968_vlb = {VIDEO_BUS, 2, 2, 4, 20, 20, 35}; +static video_timings_t timing_s3_vision968_pci = {VIDEO_PCI, 2, 2, 4, 20, 20, 35}; static video_timings_t timing_s3_trio32_vlb = {VIDEO_BUS, 4, 3, 5, 26, 26, 42}; static video_timings_t timing_s3_trio32_pci = {VIDEO_PCI, 4, 3, 5, 26, 26, 42}; static video_timings_t timing_s3_trio64_vlb = {VIDEO_BUS, 3, 2, 4, 25, 25, 40}; @@ -102,7 +164,7 @@ enum #define FIFO_ENTRY_SIZE (1 << 31) #define FIFO_ENTRIES (s3->fifo_write_idx - s3->fifo_read_idx) -#define FIFO_FULL ((s3->fifo_write_idx - s3->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_FULL ((s3->fifo_write_idx - s3->fifo_read_idx) >= (FIFO_SIZE - 4)) #define FIFO_EMPTY (s3->fifo_read_idx == s3->fifo_write_idx) #define FIFO_TYPE 0xff000000 @@ -129,7 +191,8 @@ typedef struct s3_t { mem_mapping_t linear_mapping; mem_mapping_t mmio_mapping; - + mem_mapping_t new_mmio_mapping; + uint8_t has_bios; rom_t bios_rom; @@ -141,36 +204,40 @@ typedef struct s3_t int chip; int pci, vlb; - + int atbus; + uint8_t id, id_ext, id_ext_pci; - + uint8_t int_line; - + int packed_mmio; - + uint32_t linear_base, linear_size; - + uint8_t pci_regs[256]; int card; uint32_t vram_mask; - uint8_t status_9ae8; uint8_t data_available; - + + int card_type; + struct { uint16_t subsys_cntl; uint16_t setup_md; uint8_t advfunc_cntl; - uint16_t cur_y, cur_y2; - uint16_t cur_x, cur_x2; - uint16_t x2; - int16_t desty_axstp, desty_axstp2; - int16_t destx_distp; - int16_t err_term, err_term2; - int16_t maj_axis_pcnt, maj_axis_pcnt2; - uint16_t cmd; + uint16_t cur_y, cur_y2, cur_y_bitres; + uint16_t cur_x, cur_x2, cur_x_bitres; + uint16_t x2, ropmix; + uint16_t pat_x, pat_y; + int16_t desty_axstp, desty_axstp2; + int16_t destx_distp; + int16_t err_term, err_term2; + int16_t maj_axis_pcnt, maj_axis_pcnt2; + uint16_t cmd, cmd2; uint16_t short_stroke; + uint32_t pat_bg_color, pat_fg_color; uint32_t bkgd_color; uint32_t frgd_color; uint32_t wrt_mask; @@ -181,40 +248,125 @@ typedef struct s3_t uint16_t multifunc_cntl; uint16_t multifunc[16]; uint8_t pix_trans[4]; - + int ssv_state; + int cx, cy; + int px, py; int sx, sy; int dx, dy; uint32_t src, dest, pattern; - int pix_trans_count; int poly_cx, poly_cx2; int poly_cy, poly_cy2; + int poly_line_cx; int point_1_updated, point_2_updated; int poly_dx1, poly_dx2; int poly_x; uint32_t dat_buf; int dat_count; + int b2e8_pix, temp_cnt; + uint8_t cur_x_bit12, cur_y_bit12; + int ssv_len; + uint8_t ssv_dir; + uint8_t ssv_draw; + + /*For non-threaded FIFO*/ + int setup_fifo_slot; + int draw_fifo_slot; + int setup_fifo, setup_fifo2; + int draw_fifo, draw_fifo2; } accel; + struct { + uint32_t nop; + uint32_t cntl; + uint32_t stretch_filt_const; + uint32_t src_dst_step; + uint32_t crop; + uint32_t src_base, dest_base; + uint32_t src, dest; + uint32_t srcbase, dstbase; + int32_t dda_init_accumulator; + int32_t k1, k2; + int dm_index; + int dither_matrix_idx; + int src_step, dst_step; + int sx, sx_backup, sy; + double cx, dx; + double cy, dy; + int sx_scale_int, sx_scale_int_backup; + double sx_scale; + double sx_scale_dec; + double sx_scale_inc; + double sx_scale_backup; + double sx_scale_len; + int dither, host_data, scale_down; + int input; + int len, start; + int odf, idf, yuv; + volatile int busy; + } videoengine; + + struct + { + uint32_t pri_ctrl; + uint32_t chroma_ctrl; + uint32_t sec_ctrl; + uint32_t chroma_upper_bound; + uint32_t sec_filter; + uint32_t blend_ctrl; + uint32_t pri_fb0, pri_fb1; + uint32_t pri_stride; + uint32_t buffer_ctrl; + uint32_t sec_fb0, sec_fb1; + uint32_t sec_stride; + uint32_t overlay_ctrl; + int32_t k1_vert_scale; + int32_t k2_vert_scale; + int32_t dda_vert_accumulator; + int32_t k1_horiz_scale; + int32_t k2_horiz_scale; + int32_t dda_horiz_accumulator; + uint32_t fifo_ctrl; + uint32_t pri_start; + uint32_t pri_size; + uint32_t sec_start; + uint32_t sec_size; + + int sdif; + + int pri_x, pri_y, pri_w, pri_h; + int sec_x, sec_y, sec_w, sec_h; + } streams; + fifo_entry_t fifo[FIFO_SIZE]; volatile int fifo_read_idx, fifo_write_idx; + uint8_t fifo_thread_run; + thread_t *fifo_thread; event_t *wake_fifo_thread; event_t *fifo_not_full_event; - + int blitter_busy; uint64_t blitter_time; uint64_t status_time; - + uint8_t subsys_cntl, subsys_stat; - + uint32_t hwc_fg_col, hwc_bg_col; int hwc_col_stack_pos; int translate; + int enable_8514; + int color_16bit; + volatile int busy, force_busy; + + uint8_t thread_run, serialport; + void *i2c, *ddc; + + int vram; } s3_t; #define INT_VSY (1 << 0) @@ -223,51 +375,117 @@ typedef struct s3_t #define INT_FIFO_EMP (1 << 3) #define INT_MASK 0xf -void s3_updatemapping(); +#define SERIAL_PORT_SCW (1 << 0) +#define SERIAL_PORT_SDW (1 << 1) +#define SERIAL_PORT_SCR (1 << 2) +#define SERIAL_PORT_SDR (1 << 3) -void s3_accel_write(uint32_t addr, uint8_t val, void *p); -void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); -void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); -uint8_t s3_accel_read(uint32_t addr, void *p); -uint16_t s3_accel_read_w(uint32_t addr, void *p); -uint32_t s3_accel_read_l(uint32_t addr, void *p); +static void s3_updatemapping(s3_t *s3); -void s3_out(uint16_t addr, uint8_t val, void *p); -uint8_t s3_in(uint16_t addr, void *p); +static void s3_accel_write(uint32_t addr, uint8_t val, void *p); +static void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); +static void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); +static uint8_t s3_accel_read(uint32_t addr, void *p); +static uint16_t s3_accel_read_w(uint32_t addr, void *p); +static uint32_t s3_accel_read_l(uint32_t addr, void *p); -void s3_accel_out(uint16_t port, uint8_t val, void *p); -void s3_accel_out_w(uint16_t port, uint16_t val, void *p); -void s3_accel_out_l(uint16_t port, uint32_t val, void *p); -uint8_t s3_accel_in(uint16_t port, void *p); +static void s3_out(uint16_t addr, uint8_t val, void *p); +static uint8_t s3_in(uint16_t addr, void *p); -static inline void wake_fifo_thread(s3_t *s3) +static void s3_accel_out(uint16_t port, uint8_t val, void *p); +static void s3_accel_out_w(uint16_t port, uint16_t val, void *p); +static void s3_accel_out_l(uint16_t port, uint32_t val, void *p); +static uint8_t s3_accel_in(uint16_t port, void *p); +static uint16_t s3_accel_in_w(uint16_t port, void *p); +static uint32_t s3_accel_in_l(uint16_t port, void *p); +static uint8_t s3_pci_read(int func, int addr, void *p); +static void s3_pci_write(int func, int addr, uint8_t val, void *p); + +/*Remap address for chain-4/doubleword style layout. + These will stay for convenience.*/ +static __inline uint32_t +dword_remap(svga_t *svga, uint32_t in_addr) +{ + if (svga->packed_chain4 || svga->force_old_addr) + return in_addr; + + return ((in_addr << 2) & 0x3fff0) | + ((in_addr >> 14) & 0xc) | + (in_addr & ~0x3fffc); +} +static __inline uint32_t +dword_remap_w(svga_t *svga, uint32_t in_addr) +{ + if (svga->packed_chain4 || svga->force_old_addr) + return in_addr; + + return ((in_addr << 2) & 0x1fff8) | + ((in_addr >> 14) & 0x6) | + (in_addr & ~0x1fffe); +} +static __inline uint32_t +dword_remap_l(svga_t *svga, uint32_t in_addr) +{ + if (svga->packed_chain4 || svga->force_old_addr) + return in_addr; + + return ((in_addr << 2) & 0xfffc) | + ((in_addr >> 14) & 0x3) | + (in_addr & ~0xffff); +} + +static __inline void +wake_fifo_thread(s3_t *s3) { thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } -static void s3_wait_fifo_idle(s3_t *s3) +static void +s3_wait_fifo_idle(s3_t *s3) { - while (!FIFO_EMPTY) - { + while (!FIFO_EMPTY) { wake_fifo_thread(s3); thread_wait_event(s3->fifo_not_full_event, 1); } } -static void s3_update_irqs(s3_t *s3) +static void +s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) { - if (!s3->pci) - { - return; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) { + thread_reset_event(s3->fifo_not_full_event); + if (FIFO_FULL) { + thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } } - if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + s3->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(s3); +} + +static void +s3_update_irqs(s3_t *s3) +{ + if (!s3->pci) + return; + + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) { pci_set_irq(s3->card, PCI_INTA); - else + } else { pci_clear_irq(s3->card, PCI_INTA); + } } void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); +void s3_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3, uint8_t ssv); +static void s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3); #define WRITE8(addr, var, val) switch ((addr) & 3) \ { \ @@ -277,173 +495,386 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ } -int s3_cpu_src(s3_t *s3) + +#define READ_PIXTRANS_BYTE_IO(n) \ + s3->accel.pix_trans[n] = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + n)) & s3->vram_mask]; \ + +#define READ_PIXTRANS_BYTE_MM \ + temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ + +#define READ_PIXTRANS_WORD \ + if (s3->bpp == 0 && !s3->color_16bit) { \ + temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ + temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 1)) & s3->vram_mask] << 8); \ + } else { \ + temp = vram_w[dword_remap_w(svga, (s3->accel.dest + s3->accel.cx)) & (s3->vram_mask >> 1)]; \ + } + +#define READ_PIXTRANS_LONG \ + if (s3->bpp == 0 && !s3->color_16bit) { \ + temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ + temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 1)) & s3->vram_mask] << 8); \ + temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 2)) & s3->vram_mask] << 16); \ + temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 3)) & s3->vram_mask] << 24); \ + } else { \ + temp = vram_w[dword_remap_w(svga, (s3->accel.dest + s3->accel.cx)) & (s3->vram_mask >> 1)]; \ + temp |= (vram_w[dword_remap_w(svga, (s3->accel.dest + s3->accel.cx + 2)) & (s3->vram_mask >> 1)] << 16); \ + } + +static int +s3_cpu_src(s3_t *s3) { if (!(s3->accel.cmd & 0x100)) return 0; - - if (s3->chip > S3_86C911) + + if (s3->chip >= S3_VISION964) return 1; - + if (s3->accel.cmd & 1) return 1; - + return 0; } - -int s3_cpu_dest(s3_t *s3) + +static int +s3_cpu_dest(s3_t *s3) { if (!(s3->accel.cmd & 0x100)) return 0; - - if (s3->chip > S3_86C911) + + if (s3->chip >= S3_VISION964) return 0; - + if (s3->accel.cmd & 1) return 0; - + return 1; } -static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) +static int +s3_enable_fifo(s3_t *s3) { - switch (port) - { - case 0x8148: case 0x82e8: + svga_t *svga = &s3->svga; + + if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64) || + (s3->chip == S3_TRIO64V) || (s3->chip == S3_TRIO64V2) || + (s3->chip == S3_VISION864) || (s3->chip == S3_VISION964) || + (s3->chip == S3_VISION968) || (s3->chip == S3_VISION868)) + return 1; /* FIFO always enabled on these chips. */ + + return !!((svga->crtc[0x40] & 0x08) || (s3->accel.advfunc_cntl & 0x40)); +} + +static void +s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) +{ + svga_t *svga = &s3->svga; + + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(8, 1, val | (val << 16), 0, s3); + } else + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + } else { + if (s3->color_16bit) + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + } + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } else { + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + break; + case 0x400: + if (svga->crtc[0x53] & 0x08) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(32, 1, val | (val << 16), 0, s3); + } else + s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + } else + s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + } else { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } else + s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + } else + s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + } + break; + case 0x600: + if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + } + } + break; + } + } +} + +static void +s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) +{ + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + } else { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } else { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); + } else { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + } else { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + break; + case 0x400: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(32, 1, val, 0, s3); + } else + s3_accel_start(4, 1, 0xffffffff, val, s3); + } else + s3_accel_start(4, 1, 0xffffffff, val, s3); + break; + case 0x600: + if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + } + } + break; + } + } +} + +static void +s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) +{ + svga_t *svga = &s3->svga; + + switch (port) { + case 0x8148: case 0x82e8: + s3->accel.cur_y_bitres = (s3->accel.cur_y_bitres & 0xff00) | val; s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; s3->accel.poly_cy = s3->accel.cur_y; break; - case 0x8149: case 0x82e9: - s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + case 0x8149: case 0x82e9: + s3->accel.cur_y_bitres = (s3->accel.cur_y_bitres & 0xff) | (val << 8); + s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x0f) << 8); + s3->accel.cur_y_bit12 = val & 0x10; s3->accel.poly_cy = s3->accel.cur_y; break; - case 0x814a: case 0x82ea: + case 0x814a: case 0x82ea: s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; s3->accel.poly_cy2 = s3->accel.cur_y2; break; - case 0x814b: case 0x82eb: - s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); + case 0x814b: case 0x82eb: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x0f) << 8); s3->accel.poly_cy2 = s3->accel.cur_y2; break; - - case 0x8548: case 0x86e8: + + case 0x8548: case 0x86e8: + s3->accel.cur_x_bitres = (s3->accel.cur_x_bitres & 0xff00) | val; s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; s3->accel.poly_cx = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; break; - case 0x8549: case 0x86e9: - s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + case 0x8549: case 0x86e9: + s3->accel.cur_x_bitres = (s3->accel.cur_x_bitres & 0xff) | (val << 8); + s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x0f) << 8); + s3->accel.cur_x_bit12 = val & 0x10; s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; break; - case 0x854a: case 0x86ea: + case 0x854a: case 0x86ea: s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; break; - case 0x854b: case 0x86eb: - s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8); + case 0x854b: case 0x86eb: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x0f) << 8); s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; break; - - case 0x8948: case 0x8ae8: + + case 0xcae8: + case 0x8948: case 0x8ae8: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; s3->accel.point_1_updated = 1; break; - case 0x8949: case 0x8ae9: + case 0xcae9: + case 0x8949: case 0x8ae9: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.desty_axstp |= ~0x3fff; s3->accel.point_1_updated = 1; break; - case 0x894a: case 0x8aea: + case 0x894a: case 0x8aea: s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; s3->accel.point_2_updated = 1; break; - case 0x849b: case 0x8aeb: + case 0x849b: case 0x8aeb: s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.desty_axstp2 |= ~0x3fff; s3->accel.point_2_updated = 1; break; - - case 0x8d48: case 0x8ee8: + + case 0x8d48: case 0x8ee8: s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; s3->accel.point_1_updated = 1; break; - case 0x8d49: case 0x8ee9: + case 0x8d49: case 0x8ee9: s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.destx_distp |= ~0x3fff; s3->accel.point_1_updated = 1; break; - case 0x8d4a: case 0x8eea: + case 0x8d4a: case 0x8eea: s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; s3->accel.point_2_updated = 1; break; - case 0x8d4b: case 0x8eeb: - s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); + case 0x8d4b: case 0x8eeb: + s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0x0f) << 8); s3->accel.point_2_updated = 1; break; - - case 0x9148: case 0x92e8: + + case 0x9148: case 0x92e8: s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; break; - case 0x9149: case 0x92e9: + case 0x9149: case 0x92e9: s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) - s3->accel.err_term |= ~0x3fff; + s3->accel.err_term |= ~0x3fff; break; - case 0x914a: case 0x92ea: + case 0x914a: case 0x92ea: s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; break; - case 0x914b: case 0x92eb: + case 0x914b: case 0x92eb: s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.err_term2 |= ~0x3fff; break; - case 0x9548: case 0x96e8: - s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; + case 0x9548: case 0x96e8: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xf00) | val; break; - case 0x9459: case 0x96e9: + case 0x9459: case 0x96e9: s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); if (val & 0x08) - s3->accel.maj_axis_pcnt |= ~0x0fff; + s3->accel.maj_axis_pcnt |= ~0x0fff; break; - case 0x954a: case 0x96ea: + case 0x954a: case 0x96ea: s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; break; - case 0x954b: case 0x96eb: + case 0x954b: case 0x96eb: s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8); if (val & 0x08) s3->accel.maj_axis_pcnt2 |= ~0x0fff; break; - case 0x9948: case 0x9ae8: + case 0x9948: case 0x9ae8: s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; s3->data_available = 0; + s3->accel.b2e8_pix = 0; break; - case 0x9949: case 0x9ae9: + case 0x9949: case 0x9ae9: s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3->accel.ssv_state = 0; s3_accel_start(-1, 0, 0xffffffff, 0, s3); - s3->accel.pix_trans_count = 0; s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ break; - case 0x9d48: case 0x9ee8: - s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + case 0x994a: case 0x9aea: + s3->accel.cmd2 = (s3->accel.cmd2 & 0xff00) | val; break; - case 0x9d49: case 0x9ee9: - s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + case 0x994b: case 0x9aeb: + s3->accel.cmd2 = (s3->accel.cmd2 & 0xff) | (val << 8); break; - case 0xa148: case 0xa2e8: + case 0x9d48: case 0x9ee8: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + break; + case 0x9d49: case 0x9ee9: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + s3->accel.ssv_state = 1; + + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x_bit12) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y_bit12) s3->accel.cy |= ~0xfff; + + if (s3->accel.cmd & 0x1000) { + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke & 0xff); + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke >> 8); + } else { + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke >> 8); + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke & 0xff); + } + break; + + case 0xa148: case 0xa2e8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); else s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; break; - case 0xa149: case 0xa2e9: + case 0xa149: case 0xa2e9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); else @@ -451,22 +882,20 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xa14a: case 0xa2ea: + case 0xa14a: case 0xa2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); else s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; } break; - case 0xa14b: case 0xa2eb: + case 0xa14b: case 0xa2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); else @@ -475,13 +904,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xa548: case 0xa6e8: + case 0xa548: case 0xa6e8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); else s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; break; - case 0xa549: case 0xa6e9: + case 0xa549: case 0xa6e9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); else @@ -489,22 +918,20 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xa54a: case 0xa6ea: + case 0xa54a: case 0xa6ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); else s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; } break; - case 0xa54b: case 0xa6eb: + case 0xa54b: case 0xa6eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); else @@ -513,13 +940,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xa948: case 0xaae8: + case 0xa948: case 0xaae8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); else s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; break; - case 0xa949: case 0xaae9: + case 0xa949: case 0xaae9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); else @@ -527,22 +954,20 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xa94a: case 0xaaea: + case 0xa94a: case 0xaaea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); else s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; } break; - case 0xa94b: case 0xaaeb: + case 0xa94b: case 0xaaeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); else @@ -551,13 +976,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xad48: case 0xaee8: + case 0xad48: case 0xaee8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); else s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; break; - case 0xad49: case 0xaee9: + case 0xad49: case 0xaee9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); else @@ -565,22 +990,20 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xad4a: case 0xaeea: + case 0xad4a: case 0xaeea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); else s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; } break; - case 0xad4b: case 0xaeeb: + case 0xad4b: case 0xaeeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); else @@ -589,13 +1012,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xb148: case 0xb2e8: + case 0xb148: case 0xb2e8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); else s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; break; - case 0xb149: case 0xb2e9: + case 0xb149: case 0xb2e9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); else @@ -603,22 +1026,20 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xb14a: case 0xb2ea: + case 0xb14a: case 0xb2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); else s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; } break; - case 0xb14b: case 0xb2eb: + case 0xb14b: case 0xb2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); - else if (s3->bpp == 3) - { + else if (s3->bpp == 3) { if (s3->accel.multifunc[0xe] & 0x10) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); else @@ -627,411 +1048,784 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xb548: case 0xb6e8: + case 0xb548: case 0xb6e8: s3->accel.bkgd_mix = val; break; - case 0xb948: case 0xbae8: + case 0xb948: case 0xbae8: s3->accel.frgd_mix = val; break; - - case 0xbd48: case 0xbee8: + + case 0xbd48: case 0xbee8: s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; break; - case 0xbd49: case 0xbee9: + case 0xbd49: case 0xbee9: s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; break; - case 0xe148: case 0xe2e8: + case 0xd148: case 0xd2e8: + s3->accel.ropmix = (s3->accel.ropmix & 0xff00) | val; + break; + case 0xd149: case 0xd2e9: + s3->accel.ropmix = (s3->accel.ropmix & 0x00ff) | (val << 8); + break; + case 0xe548: case 0xe6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x000000ff) | val; + break; + case 0xe549: case 0xe6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xe54a: case 0xe6ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x000000ff) | val; + } + break; + case 0xe54b: case 0xe6eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + case 0xe948: case 0xeae8: + s3->accel.pat_y = (s3->accel.pat_y & 0xf00) | val; + break; + case 0xe949: case 0xeae9: + s3->accel.pat_y = (s3->accel.pat_y & 0xff) | ((val & 0x1f) << 8); + break; + case 0xe94a: case 0xeaea: + s3->accel.pat_x = (s3->accel.pat_x & 0xf00) | val; + break; + case 0xe94b: case 0xeaeb: + s3->accel.pat_x = (s3->accel.pat_x & 0xff) | ((val & 0x1f) << 8); + break; + case 0xed48: case 0xeee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x000000ff) | val; + break; + case 0xed49: case 0xeee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xed4a: case 0xeeea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x000000ff) | val; + } + break; + case 0xed4b: case 0xeeeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xe148: case 0xe2e8: + s3->accel.b2e8_pix = 0; if (s3_cpu_dest(s3)) break; s3->accel.pix_trans[0] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); - else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } else { + if (s3->color_16bit) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[0] << 8), 0, s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[0] << 8), s3); + } else { + if (s3->chip != S3_86C928PCI && s3->chip != S3_86C928) { + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[0] << 8), s3); + } + } + break; + } + } break; - case 0xe149: case 0xe2e9: + case 0xe149: case 0xe2e9: + s3->accel.b2e8_pix = 0; if (s3_cpu_dest(s3)) break; s3->accel.pix_trans[1] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) - { - if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); - else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); - } - else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) - { - if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); - else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } else { + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0x200: + /*Windows 95's built-in driver expects this to be loaded regardless of the byte swap bit (0xE2E9) in the 86c928 ISA/VLB*/ + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else + s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } else { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { + s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8)); + } else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + } + } else { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { + s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8)); + } else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + } + break; + case 0x400: + if (svga->crtc[0x53] & 0x08) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + else + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } else + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0x600: + if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + } + } + } + break; + } } break; - case 0xe14a: case 0xe2ea: + case 0xe14a: case 0xe2ea: if (s3_cpu_dest(s3)) break; s3->accel.pix_trans[2] = val; break; - case 0xe14b: case 0xe2eb: + case 0xe14b: case 0xe2eb: if (s3_cpu_dest(s3)) break; s3->accel.pix_trans[3] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32) - { - s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); - s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); - s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + case 0x200: + /*Windows 95's built-in driver expects the upper 16 bits to be loaded instead of the whole 32-bit one, regardless of the byte swap bit (0xE2EB) in the 86c928 ISA/VLB card*/ + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + s3_accel_start(16, 1, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), 0, s3); + else + s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + } else { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { + s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8)); + } else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } + } + } else { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { + s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8)); + } else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } + } + break; + case 0x400: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } else + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + case 0x600: + if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + } + } + } + break; + } } - else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) - s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); - else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) - s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); break; } } -static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) +static void +s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if (s3->accel.cmd & 0x1000) - val = (val >> 8) | (val << 8); - if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) - { - s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); - s3_accel_start(8, 1, val & 0xff, 0, s3); - } - if ((s3->accel.cmd & 0x600) == 0x000) - s3_accel_start(8, 1, val | (val << 16), 0, s3); - else - s3_accel_start(16, 1, val | (val << 16), 0, s3); + if (port != 0x9ee8 && port != 0x9d48) { + if (port == 0xb2e8 || port == 0xb148) { + s3->accel.b2e8_pix = 1; + } else { + s3->accel.b2e8_pix = 0; } - else - { - if ((s3->accel.cmd & 0x600) == 0x000) - s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); - else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + s3_accel_out_pixtrans_w(s3, val); + } else { + s3->accel.short_stroke = val; + s3->accel.ssv_state = 1; + + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x_bit12) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y_bit12) s3->accel.cy |= ~0xfff; + + if (s3->accel.cmd & 0x1000) { + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke & 0xff); + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke >> 8); + } else { + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke >> 8); + s3_short_stroke_start(-1, 0, 0xffffffff, 0, s3, s3->accel.short_stroke & 0xff); } } } -static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) + +static void +s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); - s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); - s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); - s3_accel_start(8, 1, val & 0xff, 0, s3); - } - else if (s3->accel.cmd & 0x400) - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - s3_accel_start(32, 1, val, 0, s3); - } - else if ((s3->accel.cmd & 0x600) == 0x200) - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); - s3_accel_start(16, 1, val, 0, s3); - s3_accel_start(16, 1, val >> 16, 0, s3); - } - else - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); - s3_accel_start(8, 1, val, 0, s3); - s3_accel_start(8, 1, val >> 16, 0, s3); - } - } - else - { - if (s3->accel.cmd & 0x400) - s3_accel_start(4, 1, 0xffffffff, val, s3); - else if ((s3->accel.cmd & 0x600) == 0x200) - { - s3_accel_start(2, 1, 0xffffffff, val, s3); - s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); - } - else - { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - } - } + if (port == 0xb2e8 || port == 0xb148) { + s3->accel.b2e8_pix = 1; + } else { + s3->accel.b2e8_pix = 0; } + + s3_accel_out_pixtrans_l(s3, val); } -static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) +static void +s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) { - if (s3->packed_mmio) - { - int addr_lo = addr & 1; - switch (addr & 0xfffe) - { - case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ - case 0x8102: addr = 0x86e8; break; - - case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ - case 0x8106: addr = 0x86ea; break; - - case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ - case 0x810a: addr = 0x8ee8; break; - - case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ - case 0x810e: addr = 0x8eea; break; + svga_t *svga = &s3->svga; - case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ - case 0x8112: addr = 0x92ee; break; + if (s3->packed_mmio) { + int addr_lo = addr & 1; + if (svga->crtc[0x53] & 0x08) { + if ((addr >= 0x08000) && (addr <= 0x0803f)) + s3_pci_write(0, addr & 0xff, val, s3); + } - case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ - case 0x811a: addr = 0x9aea; break; - - case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ - - case 0x8120: case 0x8122: /*BKGD_COLOR*/ + switch (addr & 0x1fffe) { + case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ + case 0x8102: addr = 0x86e8; break; + + case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ + case 0x8106: addr = 0x86ea; break; + + case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ + case 0x810a: addr = 0x8ee8; break; + + case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ + case 0x810e: addr = 0x8eea; break; + + case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ + case 0x8112: addr = 0x92ee; break; + + case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ + case 0x811a: addr = 0x9aea; break; + + case 0x811c: addr = 0x9ee8; break; + + case 0x8120: case 0x8122: /*BKGD_COLOR*/ WRITE8(addr, s3->accel.bkgd_color, val); return; - - case 0x8124: case 0x8126: /*FRGD_COLOR*/ + + case 0x8124: case 0x8126: /*FRGD_COLOR*/ WRITE8(addr, s3->accel.frgd_color, val); return; - case 0x8128: case 0x812a: /*WRT_MASK*/ + case 0x8128: case 0x812a: /*WRT_MASK*/ WRITE8(addr, s3->accel.wrt_mask, val); return; - case 0x812c: case 0x812e: /*RD_MASK*/ + case 0x812c: case 0x812e: /*RD_MASK*/ WRITE8(addr, s3->accel.rd_mask, val); return; - case 0x8130: case 0x8132: /*COLOR_CMP*/ + case 0x8130: case 0x8132: /*COLOR_CMP*/ WRITE8(addr, s3->accel.color_cmp, val); return; - case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ - case 0x8136: addr = 0xbae8; break; - - case 0x8138: /*SCISSORS_T*/ + case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ + case 0x8136: addr = 0xbae8; break; + + case 0x8138: /*SCISSORS_T*/ WRITE8(addr & 1, s3->accel.multifunc[1], val); return; - case 0x813a: /*SCISSORS_L*/ + case 0x813a: /*SCISSORS_L*/ WRITE8(addr & 1, s3->accel.multifunc[2], val); return; - case 0x813c: /*SCISSORS_B*/ + case 0x813c: /*SCISSORS_B*/ WRITE8(addr & 1, s3->accel.multifunc[3], val); return; - case 0x813e: /*SCISSORS_R*/ + case 0x813e: /*SCISSORS_R*/ WRITE8(addr & 1, s3->accel.multifunc[4], val); return; - case 0x8140: /*PIX_CNTL*/ + case 0x8140: /*PIX_CNTL*/ WRITE8(addr & 1, s3->accel.multifunc[0xa], val); return; - case 0x8142: /*MULT_MISC2*/ + case 0x8142: /*MULT_MISC2*/ WRITE8(addr & 1, s3->accel.multifunc[0xd], val); return; - case 0x8144: /*MULT_MISC*/ + case 0x8144: /*MULT_MISC*/ WRITE8(addr & 1, s3->accel.multifunc[0xe], val); return; - case 0x8146: /*READ_SEL*/ + case 0x8146: /*READ_SEL*/ WRITE8(addr & 1, s3->accel.multifunc[0xf], val); return; - case 0x8148: /*ALT_PCNT*/ + case 0x8148: /*ALT_PCNT*/ WRITE8(addr & 1, s3->accel.multifunc[0], val); return; - case 0x814a: addr = 0x96e8; break; - case 0x814c: addr = 0x96ea; break; + case 0x814a: addr = 0x96e8; break; + case 0x814c: addr = 0x96ea; break; - case 0x8168: addr = 0xeae8; break; - case 0x816a: addr = 0xeaea; break; - } - addr |= addr_lo; - } - + case 0x8150: addr = 0xd2e8; break; - if (addr & 0x8000) - { - s3_accel_out_fifo(s3, addr & 0xffff, val); + case 0x8154: addr = 0x8ee8; break; + case 0x8156: addr = 0x96e8; break; + + case 0x8164: case 0x8166: + WRITE8(addr, s3->accel.pat_bg_color, val); + return; + + case 0x8168: addr = 0xeae8; break; + case 0x816a: addr = 0xeaea; break; + + case 0x816c: case 0x816e: + WRITE8(addr, s3->accel.pat_fg_color, val); + return; } - else - { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); - else + addr |= addr_lo; + } + + if (svga->crtc[0x53] & 0x08) { + if ((addr & 0x1ffff) < 0x8000) { + if (s3->accel.cmd & 0x100) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } else s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } + } else { + switch (addr & 0x1ffff) { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + s3_out(addr & 0x3ff, val, s3); + break; + case 0x8504: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); + break; + case 0x8505: + s3->subsys_cntl = val; + s3_update_irqs(s3); + break; + case 0x850c: + s3->accel.advfunc_cntl = val; + s3_updatemapping(s3); + break; + case 0xff20: + s3->serialport = val; + i2c_gpio_set(s3->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); + break; + default: + s3_accel_out_fifo(s3, addr & 0xffff, val); + break; + } } + } else { + if (addr & 0x8000) { + s3_accel_out_fifo(s3, addr & 0xffff, val); + } else { + if (s3->accel.cmd & 0x100) { + if ((s3->accel.cmd & 0x600) == 0x200) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(16, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } else + s3_accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } else { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } + } + } + } } -static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) +static void +s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { - if (addr & 0x8000) - { - s3_accel_write_fifo(s3, addr, val); - s3_accel_write_fifo(s3, addr + 1, val >> 8); - } - else - { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if (s3->accel.cmd & 0x1000) - val = (val >> 8) | (val << 8); - if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) - { - s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); - s3_accel_start(8, 1, val & 0xff, 0, s3); + svga_t *svga = &s3->svga; + + if (svga->crtc[0x53] & 0x08) { + if ((addr & 0x1fffe) < 0x8000) { + s3_accel_out_pixtrans_w(s3, val); + } else { + switch (addr & 0x1fffe) { + case 0x83d4: + default: + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + break; + case 0xff20: + s3_accel_write_fifo(s3, addr, val); + break; + case 0x811c: + s3_accel_out_fifo_w(s3, 0x9ee8, val); + break; + } + } + } else { + if (addr & 0x8000) { + if (addr == 0x811c) + s3_accel_out_fifo_w(s3, 0x9ee8, val); + else { + if (addr == 0xe2e8 || addr == 0xe2ea) { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) + s3_accel_out_pixtrans_w(s3, val); + else { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + } + } else { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); } - else if ((s3->accel.cmd & 0x600) == 0x000) - s3_accel_start(8, 1, val | (val << 16), 0, s3); - else - s3_accel_start(16, 1, val | (val << 16), 0, s3); - } - else - { - if ((s3->accel.cmd & 0x600) == 0x000) - s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); - else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } + } else { + s3_accel_out_pixtrans_w(s3, val); } } } -static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) + +static void +s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) { - if (addr & 0x8000) - { - s3_accel_write_fifo(s3, addr, val); - s3_accel_write_fifo(s3, addr + 1, val >> 8); - s3_accel_write_fifo(s3, addr + 2, val >> 16); - s3_accel_write_fifo(s3, addr + 3, val >> 24); - } - else - { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); - s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); - s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); - s3_accel_start(8, 1, val & 0xff, 0, s3); - } - else if (s3->accel.cmd & 0x400) - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - s3_accel_start(32, 1, val, 0, s3); - } - else if ((s3->accel.cmd & 0x600) == 0x200) - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); - s3_accel_start(16, 1, val, 0, s3); - s3_accel_start(16, 1, val >> 16, 0, s3); - } - else - { - if (s3->accel.cmd & 0x1000) - val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); - s3_accel_start(8, 1, val, 0, s3); - s3_accel_start(8, 1, val >> 16, 0, s3); - } - } - else - { - if (s3->accel.cmd & 0x400) - s3_accel_start(4, 1, 0xffffffff, val, s3); - else if ((s3->accel.cmd & 0x600) == 0x200) - { - s3_accel_start(2, 1, 0xffffffff, val, s3); - s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); - } - else - { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - } - } + svga_t *svga = &s3->svga; + + if (svga->crtc[0x53] & 0x08) { + if ((addr & 0x1fffc) < 0x8000 || ((addr & 0x1fffc) >= 0x10000 && (addr & 0x1fffc) < 0x18000)) { + if ((addr & 0x1fffc) >= 0x10000 && (addr & 0x1fffc) < 0x18000) { + s3_visionx68_video_engine_op(val, s3); + } else if ((addr & 0x1fffc) < 0x8000) { + s3_accel_out_pixtrans_l(s3, val); + } + } else { + switch (addr & 0x1fffc) { + case 0x8180: + s3->streams.pri_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x8184: + s3->streams.chroma_ctrl = val; + break; + case 0x8190: + s3->streams.sec_ctrl = val; + s3->streams.dda_horiz_accumulator = val & 0xfff; + if (val & (1 << 11)) + s3->streams.dda_horiz_accumulator |= 0xfffff800; + s3->streams.sdif = (val >> 24) & 7; + break; + case 0x8194: + s3->streams.chroma_upper_bound = val; + break; + case 0x8198: + s3->streams.sec_filter = val; + s3->streams.k1_horiz_scale = val & 0x7ff; + if (val & (1 << 10)) + s3->streams.k1_horiz_scale |= 0xfffff800; + s3->streams.k2_horiz_scale = (val >> 16) & 0x7ff; + if ((val >> 16) & (1 << 10)) + s3->streams.k2_horiz_scale |= 0xfffff800; + break; + case 0x81a0: + s3->streams.blend_ctrl = val; + break; + case 0x81c0: + s3->streams.pri_fb0 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c4: + s3->streams.pri_fb1 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c8: + s3->streams.pri_stride = val & 0xfff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81cc: + s3->streams.buffer_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d0: + s3->streams.sec_fb0 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d4: + s3->streams.sec_fb1 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d8: + s3->streams.sec_stride = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81dc: + s3->streams.overlay_ctrl = val; + break; + case 0x81e0: + s3->streams.k1_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + s3->streams.k1_vert_scale |= 0xfffff800; + break; + case 0x81e4: + s3->streams.k2_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + s3->streams.k2_vert_scale |= 0xfffff800; + break; + case 0x81e8: + s3->streams.dda_vert_accumulator = val & 0xfff; + if (val & (1 << 11)) + s3->streams.dda_vert_accumulator |= 0xfffff800; + break; + case 0x81ec: + s3->streams.fifo_ctrl = val; + break; + case 0x81f0: + s3->streams.pri_start = val; + s3->streams.pri_x = (val >> 16) & 0x7ff; + s3->streams.pri_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f4: + s3->streams.pri_size = val; + s3->streams.pri_w = (val >> 16) & 0x7ff; + s3->streams.pri_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f8: + s3->streams.sec_start = val; + s3->streams.sec_x = (val >> 16) & 0x7ff; + s3->streams.sec_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81fc: + s3->streams.sec_size = val; + s3->streams.sec_w = (val >> 16) & 0x7ff; + s3->streams.sec_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + + case 0x8504: + s3->subsys_stat &= ~(val & 0xff); + s3->subsys_cntl = (val >> 8); + s3_update_irqs(s3); + break; + + case 0x850c: + s3->accel.advfunc_cntl = val & 0xff; + s3_updatemapping(s3); + break; + + case 0xff20: + s3_accel_write_fifo(s3, addr, val); + break; + + case 0x18080: + s3->videoengine.nop = 1; + break; + + case 0x18088: + s3->videoengine.cntl = val; + s3->videoengine.dda_init_accumulator = val & 0xfff; + s3->videoengine.odf = (val >> 16) & 7; + s3->videoengine.yuv = !!(val & (1 << 19)); + s3->videoengine.idf = (val >> 20) & 7; + s3->videoengine.dither = !!(val & (1 << 29)); + s3->videoengine.dm_index = (val >> 23) & 7; + break; + + case 0x1808c: + s3->videoengine.stretch_filt_const = val; + s3->videoengine.k2 = val & 0x7ff; + s3->videoengine.k1 = (val >> 16) & 0x7ff; + s3->videoengine.host_data = !!(val & (1 << 30)); + s3->videoengine.scale_down = !!(val & (1 << 31)); + break; + + case 0x18090: + s3->videoengine.src_dst_step = val; + s3->videoengine.dst_step = val & 0x1fff; + s3->videoengine.src_step = (val >> 16) & 0x1fff; + break; + + case 0x18094: + s3->videoengine.crop = val; + s3->videoengine.len = val & 0xfff; + s3->videoengine.start = (val >> 16) & 0xfff; + s3->videoengine.input = 1; + break; + + case 0x18098: + s3->videoengine.src_base = val & 0xffffff; + break; + + case 0x1809c: + s3->videoengine.dest_base = val & 0xffffff; + break; + + default: + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); + break; } } -} - -static void fifo_thread(void *param) -{ - s3_t *s3 = (s3_t *)param; - - while (1) - { - thread_set_event(s3->fifo_not_full_event); - thread_wait_event(s3->wake_fifo_thread, -1); - thread_reset_event(s3->wake_fifo_thread); - s3->blitter_busy = 1; - while (!FIFO_EMPTY) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; - - switch (fifo->addr_type & FIFO_TYPE) - { - case FIFO_WRITE_BYTE: - s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_WORD: - s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_DWORD: - s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_OUT_BYTE: - s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_OUT_WORD: - s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_OUT_DWORD: - s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; + } else { + if (addr & 0x8000) { + if (addr == 0xe2e8) { + if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) + s3_accel_out_pixtrans_l(s3, val); + else { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); } - - s3->fifo_read_idx++; - fifo->addr_type = FIFO_INVALID; - - if (FIFO_ENTRIES > 0xe000) - thread_set_event(s3->fifo_not_full_event); - - end_time = plat_timer_read(); - s3->blitter_time += end_time - start_time; + } else { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); } - s3->blitter_busy = 0; - s3->subsys_stat |= INT_FIFO_EMP; - s3_update_irqs(s3); + } else { + s3_accel_out_pixtrans_l(s3, val); } + } } -static void s3_vblank_start(svga_t *svga) + +static void +s3_vblank_start(svga_t *svga) { s3_t *s3 = (s3_t *)svga->p; @@ -1039,56 +1833,80 @@ static void s3_vblank_start(svga_t *svga) s3_update_irqs(s3); } -static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) + +static uint32_t +s3_hwcursor_convert_addr(svga_t *svga) { - fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; - - if (FIFO_FULL) - { - thread_reset_event(s3->fifo_not_full_event); - if (FIFO_FULL) - { - thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ - } - } - - fifo->val = val; - fifo->addr_type = (addr & FIFO_ADDR) | type; - - s3->fifo_write_idx++; - - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) - wake_fifo_thread(s3); + if ((svga->bpp == 8) && ((svga->gdcreg[5] & 0x60) >= 0x20) && (svga->crtc[0x45] & 0x10)) { + if ((svga->gdcreg[5] & 0x60) >= 0x40) + return ((svga->hwcursor_latch.addr & 0xfffff1ff) | ((svga->hwcursor_latch.addr & 0x200) << 2)) | 0x600; + else if ((svga->gdcreg[5] & 0x60) == 0x20) + return ((svga->hwcursor_latch.addr & 0xfffff0ff) | ((svga->hwcursor_latch.addr & 0x300) << 2)) | 0x300; + else + return svga->hwcursor_latch.addr; + } else + return svga->hwcursor_latch.addr; } -void s3_hwcursor_draw(svga_t *svga, int displine) + + +static void +s3_hwcursor_draw(svga_t *svga, int displine) { s3_t *s3 = (s3_t *)svga->p; - int x; + int x, shift = 1; + int width = 16; uint16_t dat[2]; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; uint32_t fg, bg; + uint32_t real_addr; + uint32_t remapped_addr; switch (svga->bpp) - { + { case 15: fg = video_15to32[s3->hwc_fg_col & 0xffff]; bg = video_15to32[s3->hwc_bg_col & 0xffff]; + if (s3->chip >= S3_86C928 && s3->chip <= S3_86C805) { + if (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805) { + if (!(svga->crtc[0x45] & 0x04)) { + shift = 2; + width = 8; + } + } + } break; - + case 16: fg = video_16to32[s3->hwc_fg_col & 0xffff]; bg = video_16to32[s3->hwc_bg_col & 0xffff]; + if (s3->chip >= S3_86C928 && s3->chip <= S3_86C805) { + if (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805) { + if (!(svga->crtc[0x45] & 0x04)) { + shift = 2; + width = 8; + } + } else if (s3->card_type == S3_MIROCRYSTAL10SD_805) { + if (!(svga->crtc[0x45] & 0x04)) { + offset <<= 1; + } + } + } break; - - case 24: case 32: + + case 24: + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + break; + + case 32: fg = s3->hwc_fg_col; bg = s3->hwc_bg_col; break; default: - if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + if (s3->chip >= S3_TRIO32) { fg = svga->pallook[s3->hwc_fg_col & 0xff]; bg = svga->pallook[s3->hwc_bg_col & 0xff]; @@ -1104,31 +1922,329 @@ void s3_hwcursor_draw(svga_t *svga, int displine) if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; + real_addr = s3_hwcursor_convert_addr(svga); + for (x = 0; x < 64; x += 16) { - dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; - dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; - for (xx = 0; xx < 16; xx++) - { - if (offset >= svga->hwcursor_latch.x) - { - if (!(dat[0] & 0x8000)) - buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; - else if (dat[1] & 0x8000) - buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; - } - - offset++; - dat[0] <<= 1; - dat[1] <<= 1; - } + remapped_addr = dword_remap(svga, real_addr); + + dat[0] = (svga->vram[remapped_addr & s3->vram_mask] << 8) | svga->vram[(remapped_addr + 1) & s3->vram_mask]; + dat[1] = (svga->vram[(remapped_addr + 2) & s3->vram_mask] << 8) | svga->vram[(remapped_addr + 3) & s3->vram_mask]; + + if (svga->crtc[0x55] & 0x10) { + /*X11*/ + for (xx = 0; xx < 16; xx++) { + if (offset >= 0) { + if (dat[0] & 0x8000) + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; + } + + offset++; + dat[0] <<= shift; + dat[1] <<= shift; + } + } else { + /*Windows*/ + for (xx = 0; xx < width; xx++) { + if (offset >= 0) { + if (!(dat[0] & 0x8000)) + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= shift; + dat[1] <<= shift; + } + } svga->hwcursor_latch.addr += 4; + real_addr = s3_hwcursor_convert_addr(svga); } if (svga->interlace && !svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; } -static void s3_io_remove_alt(s3_t *s3) +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y3 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y3 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y3 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y4 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y4 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y4 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 3; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_XRGB8888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 4; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (s3->streams.sdif) \ + { \ + case 1: \ + DECODE_YCbCr(); \ + break; \ + case 2: \ + DECODE_YUV422(); \ + break; \ + case 3: \ + DECODE_RGB555(); \ + break; \ + case 4: \ + DECODE_YUV211(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + case 6: \ + DECODE_RGB888(); \ + break; \ + case 7: \ + default: \ + DECODE_XRGB8888(); \ + break; \ + } \ + } while (0) + + +static void s3_trio64v_overlay_draw(svga_t *svga, int displine) +{ + s3_t *s3 = (s3_t *)svga->p; + int offset = (s3->streams.sec_x - s3->streams.pri_x) + 1; + int h_acc = s3->streams.dda_horiz_accumulator; + int r[8], g[8], b[8]; + int x_size, x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay_latch.addr]; + + p = &(buffer32->line[displine][offset + svga->x_add]); + + if ((offset + s3->streams.sec_w) > s3->streams.pri_w) + x_size = (s3->streams.pri_w - s3->streams.sec_x) + 1; + else + x_size = s3->streams.sec_w + 1; + + OVERLAY_SAMPLE(); + + for (x = 0; x < x_size; x++) + { + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += s3->streams.k1_horiz_scale; + if (h_acc >= 0) + { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc += (s3->streams.k2_horiz_scale - s3->streams.k1_horiz_scale); + } + } + + svga->overlay_latch.v_acc += s3->streams.k1_vert_scale; + if (svga->overlay_latch.v_acc >= 0) + { + svga->overlay_latch.v_acc += (s3->streams.k2_vert_scale - s3->streams.k1_vert_scale); + svga->overlay_latch.addr += s3->streams.sec_stride; + } +} + +static void +s3_io_remove_alt(s3_t *s3) { if (!s3->translate) return; @@ -1142,20 +2258,28 @@ static void s3_io_remove_alt(s3_t *s3) io_removehandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9d48, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_removehandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xad48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip >= S3_86C928) + io_removehandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_removehandler(0xb148, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); io_removehandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0xd148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe148, 0x0004, s3_accel_in, s3_accel_in_w, s3_accel_in_l, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0xe548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xed48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } -static void s3_io_remove(s3_t *s3) +static void +s3_io_remove(s3_t *s3) { io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); @@ -1169,29 +2293,45 @@ static void s3_io_remove(s3_t *s3) io_removehandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip >= S3_86C928) + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_removehandler(0xb2e8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0xcae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xd2e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, s3_accel_in_w, s3_accel_in_l, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0xe6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xeae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xeee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xfee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); s3_io_remove_alt(s3); } -void s3_io_set_alt(s3_t *s3) +static void +s3_io_set_alt(s3_t *s3) { + svga_t *svga = &s3->svga; + if (!s3->translate) return; + if ((s3->chip == S3_VISION968 || s3->chip == S3_VISION868) && (svga->seqregs[9] & 0x80)) { + return; + } + io_sethandler(0x4148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - if (s3->chip == S3_TRIO64) + if (s3->chip == S3_TRIO64 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) { io_sethandler(0x8148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x8548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1209,29 +2349,48 @@ void s3_io_set_alt(s3_t *s3) io_sethandler(0x9148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x9548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } - io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) + io_sethandler(0x9948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9d48, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_sethandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xad48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip >= S3_86C928) + io_sethandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_sethandler(0xb148, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); io_sethandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_sethandler(0xe148, 0x0004, s3_accel_in, s3_accel_in_w, s3_accel_in_l, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) { + io_sethandler(0xd148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xed48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } } -static void s3_io_set(s3_t *s3) +static void +s3_io_set(s3_t *s3) { + svga_t *svga = &s3->svga; + s3_io_remove(s3); io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + if ((s3->chip == S3_VISION968 || s3->chip == S3_VISION868) && (svga->seqregs[9] & 0x80)) { + return; + } + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - if (s3->chip == S3_TRIO64) + if (s3->chip == S3_TRIO64 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) { io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1249,37 +2408,54 @@ static void s3_io_set(s3_t *s3) io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } - io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) + io_sethandler(0x9ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, NULL, s3); io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip >= S3_86C928) + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_sethandler(0xb2e8, 0x0002, s3_accel_in, s3_accel_in_w, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_sethandler(0xcae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, s3_accel_in_w, s3_accel_in_l, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) { + io_sethandler(0xd2e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xeae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xeee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + io_sethandler(0xfee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); s3_io_set_alt(s3); } -void s3_out(uint16_t addr, uint8_t val, void *p) +static void +s3_out(uint16_t addr, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; uint8_t old, mask; int rs2, rs3; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) - { + { case 0x3c2: - if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { - if (((val >> 2) & 3) != 3) - icd2061_write(svga->clock_gen, (val >> 2) & 3); + if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968) || (s3->chip == S3_86C928)) { + if ((s3->card_type != S3_SPEA_MERCURY_P64V) && (s3->card_type != S3_MIROVIDEO40SV_ERGO_968)) { + if (((val >> 2) & 3) != 3) + icd2061_write(svga->clock_gen, (val >> 2) & 3); + } } break; @@ -1296,34 +2472,63 @@ void s3_out(uint16_t addr, uint8_t val, void *p) } if (svga->seqaddr == 4) /*Chain-4 - update banking*/ { - if (val & 8) + if (val & 0x08) svga->write_bank = svga->read_bank = s3->bank << 16; else svga->write_bank = svga->read_bank = s3->bank << 14; + } else if (svga->seqaddr == 9) { + svga->seqregs[svga->seqaddr] = val & 0x80; + s3_io_set(s3); + return; + } else if (svga->seqaddr == 0xa) { + svga->seqregs[svga->seqaddr] = val & 0x80; + return; + } else if (s3->chip >= S3_VISION964) { + if (svga->seqaddr == 0x08) { + svga->seqregs[svga->seqaddr] = val & 0x0f; + return; + } else if ((svga->seqaddr == 0x0d) && (svga->seqregs[0x08] == 0x06)) { + svga->seqregs[svga->seqaddr] = val; + svga->dpms = ((s3->chip >= S3_VISION964) && (svga->seqregs[0x0d] & 0x50)) || (svga->crtc[0x56] & ((s3->chip >= S3_TRIO32) ? 0x06 : 0x20)); + svga_recalctimings(svga); + return; + } } break; - + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: if ((svga->crtc[0x55] & 0x03) == 0x00) rs2 = !!(svga->crtc[0x43] & 0x02); else rs2 = (svga->crtc[0x55] & 0x01); - if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + if (s3->chip >= S3_TRIO32) svga_out(addr, val, svga); - else if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + else if ((s3->chip == S3_VISION964 && s3->card_type != S3_ELSAWIN2KPROX_964) || (s3->chip == S3_86C928)) { if (!(svga->crtc[0x45] & 0x20) || (s3->chip == S3_86C928)) rs3 = !!(svga->crtc[0x55] & 0x02); else - rs3 = 0; + rs3 = 0; bt48x_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C911) - att49x_ramdac_out(addr, val, svga->ramdac, svga); + } else if ((s3->chip == S3_VISION964 && s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->chip == S3_VISION968 && (s3->card_type == S3_ELSAWIN2KPROX || + s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_NUMBER9_9FX_771))) + ibm_rgb528_ramdac_out(addr, rs2, val, svga->ramdac, svga); + else if ((s3->chip == S3_VISION968 && (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968))) { + rs3 = !!(svga->crtc[0x55] & 0x02); + tvp3026_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); + } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) && (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805)) + att49x_ramdac_out(addr, rs2, val, svga->ramdac, svga); + else if (s3->chip <= S3_86C924) { + sc1148x_ramdac_out(addr, rs2, val, svga->ramdac, svga); + } else if (s3->card_type == S3_NUMBER9_9FX_531) + att498_ramdac_out(addr, rs2, val, svga->ramdac, svga); + else if ((s3->chip == S3_86C928PCI) && (s3->card_type == S3_SPEA_MERCURY_LITE_PCI)) + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); else sdac_ramdac_out(addr, rs2, val, svga->ramdac, svga); return; case 0x3D4: - svga->crtcreg = val & 0x7f; + svga->crtcreg = (s3->chip == S3_TRIO64V2) ? val : (val & 0x7f); return; case 0x3D5: if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) @@ -1338,38 +2543,63 @@ void s3_out(uint16_t addr, uint8_t val, void *p) return; if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) return; + if ((s3->chip == S3_TRIO64V2) && (svga->crtcreg >= 0x80)) + return; + if ((s3->chip <= S3_86C924) && (svga->crtcreg >= 0x50)) + return; old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) { case 0x31: s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + svga->force_dword_mode = !!(val & 0x08); break; case 0x32: - svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + if ((svga->crtc[0x31] & 0x30) && (svga->crtc[0x51] & 0x01) && (val & 0x40)) + svga->vram_display_mask = 0x3ffff; + else + svga->vram_display_mask = s3->vram_mask; + break; + + case 0x40: + s3->enable_8514 = (val & 0x01); break; case 0x50: mask = 0xc0; - if (s3->chip > S3_86C805) + if (s3->chip != S3_86C801) mask |= 0x01; switch (svga->crtc[0x50] & mask) { case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; case 0x01: s3->width = 1152; break; case 0x40: s3->width = 640; break; - case 0x80: s3->width = 800; break; + case 0x80: s3->width = ((s3->chip > S3_86C805) && (s3->accel.advfunc_cntl & 4)) ? 1600 : 800; break; case 0x81: s3->width = 1600; break; case 0xc0: s3->width = 1280; break; } s3->bpp = (svga->crtc[0x50] >> 4) & 3; break; + + case 0x5c: + if ((val & 0xa0) == 0x80) + i2c_gpio_set(s3->i2c, !!(val & 0x40), !!(val & 0x10)); + if (s3->card_type == S3_PHOENIX_VISION868 || s3->card_type == S3_PHOENIX_VISION968) { + if ((val & 0x20) && (!(svga->crtc[0x55] & 0x01) && !(svga->crtc[0x43] & 2))) + svga->dac_addr |= 0x20; + } else if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968) { + if ((val & 0x80) && (!(svga->crtc[0x55] & 0x01) && !(svga->crtc[0x43] & 2))) + svga->dac_addr |= 0x02; + } + break; + case 0x69: - if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && - (s3->chip != S3_86C911) && (s3->chip != S3_86C928)) + if (s3->chip >= S3_VISION964) s3->ma_ext = val & 0x1f; break; - + case 0x35: s3->bank = (s3->bank & 0x70) | (val & 0xf); if (svga->chain4) @@ -1377,23 +2607,23 @@ void s3_out(uint16_t addr, uint8_t val, void *p) else svga->write_bank = svga->read_bank = s3->bank << 14; break; + case 0x51: - if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) + if (s3->chip == S3_86C801 || s3->chip == S3_86C805) { s3->bank = (s3->bank & 0x6f) | ((val & 0x4) << 2); - else + s3->ma_ext = (s3->ma_ext & ~0x4) | ((val & 1) << 2); + } else { s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + } if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; else svga->write_bank = svga->read_bank = s3->bank << 14; - if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) - s3->ma_ext = (s3->ma_ext & ~0x4) | ((val & 1) << 2); - else - s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); break; + case 0x6a: - if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && - (s3->chip != S3_86C911) && (s3->chip != S3_86C928)) { + if (s3->chip >= S3_VISION964) { s3->bank = val; if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; @@ -1401,30 +2631,31 @@ void s3_out(uint16_t addr, uint8_t val, void *p) svga->write_bank = svga->read_bank = s3->bank << 14; } break; - - case 0x3a: - if (val & 0x10) - svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ - break; - + case 0x45: - if (s3->chip == S3_VISION964) + if (s3->chip == S3_VISION964 || s3->chip == S3_VISION968) break; svga->hwcursor.ena = val & 1; break; - case 0x48: - if (s3->chip == S3_VISION964) + case 0x46: case 0x47: case 0x48: case 0x49: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + if (s3->chip == S3_VISION964 || s3->chip == S3_VISION968) break; svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; if (svga->bpp == 32) svga->hwcursor.x >>= 1; svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; - svga->hwcursor.xoff = svga->crtc[0x4e] & 63; - svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.xoff = svga->crtc[0x4e] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x4f] & 0x3f; svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); - if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) + if ((s3->chip >= S3_TRIO32) && svga->bpp == 32) svga->hwcursor.x <<= 1; - else if ((s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C928) && (svga->bpp == 15 || svga->bpp == 16)) - svga->hwcursor.x >>= 1; + else if ((s3->chip >= S3_86C928 && s3->chip <= S3_86C805) && (svga->bpp == 15 || svga->bpp == 16)) { + if ((s3->card_type == S3_MIROCRYSTAL10SD_805) && !(svga->crtc[0x45] & 0x04) && svga->bpp == 16) + svga->hwcursor.x >>= 2; + else + svga->hwcursor.x >>= 1; + } else if ((s3->chip >= S3_86C928 && s3->chip <= S3_86C805) && (svga->bpp == 24)) + svga->hwcursor.x /= 3; break; case 0x4a: @@ -1440,7 +2671,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) s3->hwc_fg_col = (s3->hwc_fg_col & 0x00ffff) | (val << 16); break; } - s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) & 3; break; case 0x4b: switch (s3->hwc_col_stack_pos) @@ -1455,18 +2686,17 @@ void s3_out(uint16_t addr, uint8_t val, void *p) s3->hwc_bg_col = (s3->hwc_bg_col & 0x00ffff) | (val << 16); break; } - s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) & 3; break; case 0x53: case 0x58: case 0x59: case 0x5a: - if (s3->chip != S3_86C911) - s3_updatemapping(s3); + s3_updatemapping(s3); break; case 0x55: if (s3->chip == S3_86C928) { - if (val & 0x08) { + if ((val & 0x08) || ((val & 0x20) == 0x20)) { svga->hwcursor_draw = NULL; svga->dac_hwcursor_draw = bt48x_hwcursor_draw; } else { @@ -1477,24 +2707,27 @@ void s3_out(uint16_t addr, uint8_t val, void *p) break; case 0x42: - if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968) || (s3->chip == S3_86C928)) { if (((svga->miscout >> 2) & 3) == 3) icd2061_write(svga->clock_gen, svga->crtc[0x42] & 0x0f); } break; case 0x43: - if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || - s3->chip == S3_86C911 || s3->chip == S3_86C928) { + if (s3->chip < S3_VISION964) { s3_io_remove_alt(s3); - s3->translate = !!(svga->crtc[0x43] & 0x10); + s3->translate = !!(val & 0x10); s3_io_set_alt(s3); } break; + case 0x56: + svga->dpms = ((s3->chip >= S3_VISION964) && (svga->seqregs[0x0d] & 0x50)) || (svga->crtc[0x56] & ((s3->chip >= S3_TRIO32) ? 0x06 : 0x20)); + old = ~val; /* force recalc */ + break; + case 0x67: - if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) - { + if (s3->chip >= S3_TRIO32) { switch (val >> 4) { case 3: svga->bpp = 15; break; @@ -1504,29 +2737,37 @@ void s3_out(uint16_t addr, uint8_t val, void *p) default: svga->bpp = 8; break; } } - break; - } - if (old != val) - { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } + break; } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + if ((((svga->crtc[0x67] & 0xc) != 0xc) && (s3->chip >= S3_TRIO64V)) || (s3->chip < S3_TRIO64V)) + svga->ma_latch |= (s3->ma_ext << 16); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } break; } svga_out(addr, val, svga); } -uint8_t s3_in(uint16_t addr, void *p) +static uint8_t +s3_in(uint16_t addr, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; int rs2, rs3; uint8_t temp; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -1535,28 +2776,46 @@ uint8_t s3_in(uint16_t addr, void *p) if (svga->attraddr > 0x14) return 0xff; break; - + case 0x3c2: - if (s3->chip == S3_86C911) + if (s3->chip <= S3_86C924) return svga_in(addr, svga) | 0x10; break; case 0x3c5: - if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) - return svga->seqregs[svga->seqaddr]; + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) { + temp = svga->seqregs[svga->seqaddr]; + /* This is needed for the Intel Advanced/ATX's built-in S3 Trio64V+ BIOS to not + get stuck in an infinite loop. */ + if ((s3->card_type == S3_PHOENIX_TRIO64VPLUS_ONBOARD) && (svga->seqaddr == 0x17)) + svga->seqregs[svga->seqaddr] ^= 0x01; + return temp; + } break; - + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: rs2 = (svga->crtc[0x55] & 0x01) || !!(svga->crtc[0x43] & 2); - if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + if (s3->chip >= S3_TRIO32) return svga_in(addr, svga); - else if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + else if ((s3->chip == S3_VISION964 && s3->card_type != S3_ELSAWIN2KPROX_964) || (s3->chip == S3_86C928)) { rs3 = !!(svga->crtc[0x55] & 0x02); return bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C911) - return att49x_ramdac_in(addr, svga->ramdac, svga); + } else if ((s3->chip == S3_VISION964 && s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->chip == S3_VISION968 && (s3->card_type == S3_ELSAWIN2KPROX || + s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_NUMBER9_9FX_771))) + return ibm_rgb528_ramdac_in(addr, rs2, svga->ramdac, svga); + else if ((s3->chip == S3_VISION968 && (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968))) { + rs3 = !!(svga->crtc[0x55] & 0x02); + return tvp3026_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); + } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) && (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805)) + return att49x_ramdac_in(addr, rs2, svga->ramdac, svga); + else if (s3->chip <= S3_86C924) + return sc1148x_ramdac_in(addr, rs2, svga->ramdac, svga); + else if (s3->card_type == S3_NUMBER9_9FX_531) + return att498_ramdac_in(addr, rs2, svga->ramdac, svga); + else if ((s3->chip == S3_86C928PCI) && (s3->card_type == S3_SPEA_MERCURY_LITE_PCI)) + return sc1502x_ramdac_in(addr, svga->ramdac, svga); else - return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); + return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); break; case 0x3d4: @@ -1564,121 +2823,485 @@ uint8_t s3_in(uint16_t addr, void *p) case 0x3d5: switch (svga->crtcreg) { - case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2d: return (s3->chip == S3_TRIO64V2) ? 0x89 : 0x88; /*Extended chip ID*/ case 0x2e: return s3->id_ext; /*New chip ID*/ - case 0x2f: return 0; /*Revision level*/ + case 0x2f: return (s3->chip == S3_TRIO64V) ? 0x40 : 0; /*Revision level*/ case 0x30: return s3->id; /*Chip ID*/ case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); case 0x45: s3->hwc_col_stack_pos = 0; break; case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); case 0x5c: /* General Output Port Register */ - temp = svga->crtc[svga->crtcreg] & 0xf0; - if (((svga->miscout >> 2) & 3) == 3) + temp = svga->crtc[svga->crtcreg] & 0xa0; + if (((svga->miscout >> 2) & 3) == 3) temp |= svga->crtc[0x42] & 0x0f; - else + else temp |= ((svga->miscout >> 2) & 3); - return temp; + if ((temp & 0xa0) == 0xa0) { + if ((svga->crtc[0x5c] & 0x40) && i2c_gpio_get_scl(s3->i2c)) + temp |= 0x40; + if ((svga->crtc[0x5c] & 0x10) && i2c_gpio_get_sda(s3->i2c)) + temp |= 0x10; + } + return temp; case 0x69: return s3->ma_ext; case 0x6a: return s3->bank; /* Phoenix S3 video BIOS'es seem to expect CRTC registers 6B and 6C to be mirrors of 59 and 5A. */ - case 0x6b: return svga->crtc[0x59]; - case 0x6c: return svga->crtc[0x5a] & 0x80; + case 0x6b: + if (s3->chip != S3_TRIO64V2) { + if (svga->crtc[0x53] & 0x08) { + return (s3->chip == S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : (svga->crtc[0x59] & 0xfe); + } else { + return svga->crtc[0x59]; + } + } else + return svga->crtc[0x6b]; + break; + case 0x6c: + if (s3->chip != S3_TRIO64V2) { + if (svga->crtc[0x53] & 0x08) { + return 0x00; + } else + return (svga->crtc[0x5a] & 0x80); + } else + return svga->crtc[0x6c]; + break; } return svga->crtc[svga->crtcreg]; } return svga_in(addr, svga); } -void s3_recalctimings(svga_t *svga) +static void s3_recalctimings(svga_t *svga) { s3_t *s3 = (s3_t *)svga->p; int clk_sel = (svga->miscout >> 2) & 3; - svga->hdisp = svga->hdisp_old; + if (!svga->scrblank && svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (svga->crtc[0x3a] & 0x10) { /*256+ color register*/ + svga->gdcreg[5] |= 0x40; + } + } + } svga->ma_latch |= (s3->ma_ext << 16); - if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; - if (svga->crtc[0x5d] & 0x02) - { - svga->hdisp_time += 0x100; - svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + if (s3->chip >= S3_86C928) { + svga->hdisp = svga->hdisp_old; + + if (svga->crtc[0x5d] & 0x01) svga->htotal |= 0x100; + if (svga->crtc[0x5d] & 0x02) { + svga->hdisp_time |= 0x100; + svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend |= 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart |= 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart |= 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split |= 0x400; + if (s3->accel.advfunc_cntl & 0x01) + svga->split = 0x7fff; + if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; } - if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; - if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; - if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; - if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; - if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; - if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; - else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; if (!svga->rowoffset) svga->rowoffset = 256; - if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) - bt48x_recalctimings(svga->ramdac, svga); - else - svga->interlace = svga->crtc[0x42] & 0x20; + if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { + if (s3->card_type == S3_ELSAWIN2KPROX_964) + ibm_rgb528_recalctimings(svga->ramdac, svga); + else + bt48x_recalctimings(svga->ramdac, svga); + } else if (s3->chip == S3_VISION968) { + if (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968) + tvp3026_recalctimings(svga->ramdac, svga); + else + ibm_rgb528_recalctimings(svga->ramdac, svga); + } else + svga->interlace = !!(svga->crtc[0x42] & 0x20); - if ((((svga->miscout >> 2) & 3) == 3) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64)) + if ((((svga->miscout >> 2) & 3) == 3) && s3->chip < S3_TRIO32) clk_sel = svga->crtc[0x42] & 0x0f; svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock(clk_sel, svga->clock_gen); - - switch (svga->crtc[0x67] >> 4) - { + + switch (svga->crtc[0x67] >> 4) { case 3: case 5: case 7: svga->clock /= 2; break; } svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); - if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) - { - switch (svga->bpp) - { + + if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL20SD_864 || + s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_SPEA_MIRAGE_86C801 || + s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_MIROCRYSTAL8S_805 || + s3->card_type == S3_NUMBER9_9FX_531 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { + if (!(svga->crtc[0x5e] & 0x04)) + svga->vblankstart = svga->dispend; + if (svga->bpp != 32) { + if (svga->crtc[0x31] & 2) /*This is needed if the pixel width gets set with delays*/ + s3->width = 2048; + else { + if (s3->card_type == S3_MIROCRYSTAL10SD_805) { + if (svga->hdisp == 1280 && s3->width == 1024) { + s3->width = 1280; + } + } + } + } else { + if (s3->card_type == S3_NUMBER9_9FX_531) { + if (svga->hdisp == 1600 && s3->width == 1600) + s3->width = 800; + } + } + } else if (s3->chip == S3_86C928) { + if (svga->bpp == 15) { + if (s3->width == 800) + s3->width = 1024; + } + } + + if ((svga->crtc[0x43] & 0x08) && (s3->color_16bit == 0) && (s3->chip <= S3_86C805)) { + s3->color_16bit = 1; + s3->width = 1024; + } else if (!(svga->crtc[0x43] & 0x08) && (s3->color_16bit == 1) && (s3->chip <= S3_86C805)) { + s3->color_16bit = 0; + if (s3->chip <= S3_86C924) { + if (s3->accel.advfunc_cntl & 4) + s3->width = 1024; + else + s3->width = 640; + } + } + + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) { + switch (svga->bpp) { case 8: svga->render = svga_render_8bpp_highres; + if (s3->chip != S3_VISION868) { + if (s3->chip == S3_86C928) { + if (s3->width == 2048 || s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + } else if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && (s3->chip != S3_TRIO32) && + (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968)) { + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + } else if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) { + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + } else if (s3->card_type == S3_SPEA_MERCURY_P64V) { + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + } else if (s3->card_type == S3_NUMBER9_9FX_771) + svga->hdisp <<= 1; + + if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_MIROCRYSTAL20SD_864 || + s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) { + if (svga->hdisp != 1408) + svga->hdisp = s3->width; + if (s3->card_type == S3_MIROCRYSTAL20SD_864) { + if (s3->width == 2048 || s3->width == 1600 || s3->width == 800) { + switch (svga->dispend) { + case 400: + case 480: + svga->hdisp = 640; + break; + + case 576: + svga->hdisp = 768; + break; + + case 600: + if (s3->width == 1600) + s3->width = 800; + svga->hdisp = 800; + break; + + case 768: + svga->hdisp = 1024; + break; + + case 864: + svga->hdisp = 1152; + break; + + case 1024: + if (svga->vtotal == 1066) + svga->hdisp = 1280; + break; + } + } + } + } + if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL8S_805) { + if (svga->rowoffset == 256 && (((svga->crtc[0x51] & 0x30) == 0x00 && !(svga->crtc[0x43] & 0x04)))) + svga->rowoffset >>= 1; + } + } break; case 15: svga->render = svga_render_15bpp_highres; - if (s3->chip != S3_VISION964 && s3->chip != S3_86C801 && s3->chip != S3_86C928) - svga->hdisp /= 2; - break; - case 16: - svga->render = svga_render_16bpp_highres; - if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) - { + if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && + (s3->card_type != S3_SPEA_MIRAGE_86C805)) { if (s3->chip == S3_86C928) - svga->hdisp *= 2; - else - svga->hdisp /= 2; + svga->hdisp <<= 1; + else if (s3->chip != S3_VISION968) + svga->hdisp >>= 1; } + if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && + (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) { + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + else if (s3->card_type == S3_NUMBER9_9FX_771) + svga->hdisp <<= 1; + } + if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || + s3->card_type == S3_SPEA_MERCURY_P64V) { + if (svga->hdisp == (1408*2)) + svga->hdisp >>= 1; + else + svga->hdisp = s3->width; + } + + if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || + s3->card_type == S3_SPEA_MERCURY_LITE_PCI) + svga->hdisp = s3->width; + break; + case 16: + svga->render = svga_render_16bpp_highres; + if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) { + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + } + if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && + (s3->card_type != S3_SPEA_MIRAGE_86C805)) { + if (s3->chip == S3_86C928) + svga->hdisp <<= 1; + else if (s3->chip != S3_VISION968) + svga->hdisp >>= 1; + } else if ((s3->card_type == S3_SPEA_MIRAGE_86C801) || (s3->card_type == S3_SPEA_MIRAGE_86C805)) + svga->hdisp >>= 1; + if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && + (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) { + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp <<= 1; + else if (s3->card_type == S3_NUMBER9_9FX_771) + svga->hdisp <<= 1; + } + if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || + s3->card_type == S3_SPEA_MERCURY_P64V) { + if (svga->hdisp == (1408*2)) + svga->hdisp >>= 1; + else + svga->hdisp = s3->width; + } + + if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || + s3->card_type == S3_SPEA_MERCURY_LITE_PCI) + svga->hdisp = s3->width; break; case 24: - svga->render = svga_render_24bpp_highres; - if (s3->chip != S3_86C801 && s3->chip != S3_86C805 && s3->chip != S3_86C928) - svga->hdisp /= 3; - else - svga->hdisp = (svga->hdisp * 2) / 3; + svga->render = svga_render_24bpp_highres; + if (s3->chip != S3_VISION968) { + if (s3->chip != S3_86C928 && s3->chip != S3_86C801 && s3->chip != S3_86C805) + svga->hdisp /= 3; + else + svga->hdisp = (svga->hdisp * 2) / 3; + + if (s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { + if (s3->width == 2048) + switch (svga->dispend) { + case 480: + svga->hdisp = 640; + break; + } + } + } else { + if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || + s3->card_type == S3_SPEA_MERCURY_P64V) + svga->hdisp = s3->width; + } break; case 32: - svga->render = svga_render_32bpp_highres; - if ((s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_86C928)) - svga->hdisp /= 4; + svga->render = svga_render_32bpp_highres; + if ((s3->chip < S3_TRIO32) && (s3->chip != S3_VISION964) && + (s3->chip != S3_VISION968) && (s3->chip != S3_86C928)) { + if (s3->chip == S3_VISION868) + svga->hdisp >>= 1; + else + svga->hdisp >>= 2; + } + if (s3->width == 1280 || s3->width == 1600 || (s3->card_type == S3_SPEA_MERCURY_P64V || + s3->card_type == S3_NUMBER9_9FX_771)) + svga->hdisp <<= 1; + if (s3->card_type == S3_NUMBER9_9FX_771) { + if (svga->hdisp == 832) + svga->hdisp -= 32; + } + if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_MIROCRYSTAL20SV_964 || + s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_PHOENIX_VISION968 || + s3->card_type == S3_SPEA_MERCURY_P64V) { + svga->hdisp = s3->width; + if (s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964) { + if (s3->width == 800 || s3->width == 1024 || s3->width == 1600) { + switch (svga->dispend) { + case 400: + case 480: + svga->hdisp = 640; + break; + + case 576: + if (s3->width == 1600) + s3->width = 800; + svga->hdisp = 768; + break; + + case 600: + if (s3->width == 1600) + s3->width = 800; + svga->hdisp = 800; + break; + } + } + } + } break; } + } else { + if (!svga->scrblank && svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if ((svga->crtc[0x31] & 0x08) && ((svga->gdcreg[5] & 0x60) == 0x00)) { + if (svga->bpp == 8) { + svga->render = svga_render_8bpp_highres; /*Enhanced 4bpp mode, just like the 8bpp mode per spec.*/ + if (svga->hdisp <= 1024) + s3->width = 1024; + } + } + } else { + if (s3->chip <= S3_86C924) + s3->width = 1024; + } + } } } -void s3_updatemapping(s3_t *s3) +static void s3_trio64v_recalctimings(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + int clk_sel = (svga->miscout >> 2) & 3; + + if (!svga->scrblank && svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (svga->crtc[0x3a] & 0x10) /*256+ color register*/ + svga->gdcreg[5] |= 0x40; + } + } + svga->hdisp = svga->hdisp_old; + if (svga->crtc[0x5d] & 0x01) svga->htotal |= 0x100; + if (svga->crtc[0x5d] & 0x02) { + svga->hdisp_time |= 0x100; + svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend |= 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart |= 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart |= 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split |= 0x400; + svga->interlace = svga->crtc[0x42] & 0x20; + + svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock(clk_sel, svga->clock_gen); + + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ + { + svga->ma_latch |= (s3->ma_ext << 16); + if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) { + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp >>= 1; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp >>= 1; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + } + else /*Streams mode*/ + { + if (s3->streams.buffer_ctrl & 1) + svga->ma_latch = s3->streams.pri_fb1 >> 2; + else + svga->ma_latch = s3->streams.pri_fb0 >> 2; + + svga->hdisp = s3->streams.pri_w + 1; + if (s3->streams.pri_h < svga->dispend) + svga->dispend = s3->streams.pri_h; + + svga->overlay.x = s3->streams.sec_x - s3->streams.pri_x; + svga->overlay.y = s3->streams.sec_y - s3->streams.pri_y; + svga->overlay.cur_ysize = s3->streams.sec_h; + + if (s3->streams.buffer_ctrl & 2) + svga->overlay.addr = s3->streams.sec_fb1; + else + svga->overlay.addr = s3->streams.sec_fb0; + + svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.v_acc = s3->streams.dda_vert_accumulator; + svga->rowoffset = s3->streams.pri_stride >> 3; + + switch ((s3->streams.pri_ctrl >> 24) & 0x7) + { + case 0: /*RGB-8 (CLUT)*/ + svga->render = svga_render_8bpp_highres; + break; + case 3: /*KRGB-16 (1.5.5.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_15bpp_highres; + break; + case 5: /*RGB-16 (5.6.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_16bpp_highres; + break; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; + break; + case 7: /*XRGB-32 (X.8.8.8)*/ + svga->render = svga_render_32bpp_highres; + break; + } + } +} + +static void +s3_updatemapping(s3_t *s3) { svga_t *svga = &s3->svga; - if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + if (s3->pci && !(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { mem_mapping_disable(&svga->mapping); mem_mapping_disable(&s3->linear_mapping); mem_mapping_disable(&s3->mmio_mapping); + mem_mapping_disable(&s3->new_mmio_mapping); return; } @@ -1708,72 +3331,95 @@ void s3_updatemapping(s3_t *s3) svga->banked_mask = 0x7fff; break; } - - if ((svga->crtc[0x58] & 0x10) || (s3->accel.advfunc_cntl & 0x10)) - { - /*Linear framebuffer*/ - mem_mapping_disable(&svga->mapping); + if (s3->chip >= S3_86C928) { s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); - if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || - (s3->chip == S3_86C911) || (s3->chip == S3_86C928)) { + + if (s3->chip >= S3_86C928 && s3->chip <= S3_86C805) { if (s3->vlb) s3->linear_base &= 0x03ffffff; else s3->linear_base &= 0x00ffffff; } - switch (svga->crtc[0x58] & 3) + + if ((svga->crtc[0x58] & 0x10) || (s3->accel.advfunc_cntl & 0x10)) { - case 0: /*64k*/ - s3->linear_size = 0x10000; - break; - case 1: /*1mb*/ - s3->linear_size = 0x100000; - break; - case 2: /*2mb*/ - s3->linear_size = 0x200000; - break; - case 3: /*8mb*/ - switch (s3->chip) { - case S3_TRIO32: - case S3_TRIO64: - case S3_86C801: - case S3_86C805: - case S3_86C928: - s3->linear_size = 0x400000; - break; - default: - s3->linear_size = 0x800000; - break; - } - break; - } - s3->linear_base &= ~(s3->linear_size - 1); - if (s3->linear_base == 0xa0000) - { - mem_mapping_disable(&s3->linear_mapping); - if (!(svga->crtc[0x53] & 0x10)) + /*Linear framebuffer*/ + mem_mapping_disable(&svga->mapping); + + switch (svga->crtc[0x58] & 3) { - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - svga->banked_mask = 0xffff; + case 0: /*64k*/ + s3->linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3->linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3->linear_size = 0x200000; + break; + case 3: /*8mb*/ + switch (s3->chip) { /* Not on video cards that don't support 4MB*/ + case S3_TRIO64: + case S3_TRIO64V: + case S3_TRIO64V2: + case S3_86C928: + case S3_86C928PCI: + s3->linear_size = 0x400000; + break; + default: + s3->linear_size = 0x800000; + break; + } + break; } + s3->linear_base &= ~(s3->linear_size - 1); + if (s3->linear_base == 0xa0000) { + mem_mapping_disable(&s3->linear_mapping); + if (!(svga->crtc[0x53] & 0x10)) { + mem_mapping_set_addr(&svga->mapping, s3->linear_base, 0x10000); + svga->banked_mask = 0xffff; + } + } else { + if (s3->chip >= S3_TRIO64V) { + s3->linear_base &= 0xfc000000; + } else if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) { + s3->linear_base &= 0xfe000000; + } + + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + } + svga->fb_only = 1; + } else { + svga->fb_only = 0; + mem_mapping_disable(&s3->linear_mapping); } + + /* Memory mapped I/O. */ + if ((svga->crtc[0x53] & 0x10) || (s3->accel.advfunc_cntl & 0x20)) { + mem_mapping_disable(&svga->mapping); + if (s3->chip >= S3_TRIO64V) { + if (svga->crtc[0x53] & 0x20) + mem_mapping_set_addr(&s3->mmio_mapping, 0xb8000, 0x8000); + else + mem_mapping_set_addr(&s3->mmio_mapping, 0xa0000, 0x10000); + } else { + mem_mapping_enable(&s3->mmio_mapping); + } + } else { + mem_mapping_disable(&s3->mmio_mapping); + } + + /* New MMIO. */ + if (svga->crtc[0x53] & 0x08) + mem_mapping_set_addr(&s3->new_mmio_mapping, s3->linear_base + 0x1000000, 0x20000); else - mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + mem_mapping_disable(&s3->new_mmio_mapping); } - else - mem_mapping_disable(&s3->linear_mapping); - - /* Memory mapped I/O. */ - if ((svga->crtc[0x53] & 0x10) || (s3->accel.advfunc_cntl & 0x20)) { - /* Old MMIO. */ - mem_mapping_disable(&svga->mapping); - mem_mapping_enable(&s3->mmio_mapping); - } else - mem_mapping_disable(&s3->mmio_mapping); } -static float s3_trio64_getclock(int clock, void *p) +static float +s3_trio64_getclock(int clock, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; @@ -1788,37 +3434,21 @@ static float s3_trio64_getclock(int clock, void *p) return t; } - -int s3_enable_fifo(s3_t *s3) -{ -/* FIXME: See why the Windows 3.x drivers break in non-FIFO mode - maybe FIFO is not disablable there? */ -#if 0 - svga_t *svga = &s3->svga; - - if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64) || - (s3->chip == S3_VISION864) || (s3->chip == S3_VISION964)) - return 1; /* FIFO always enabled on these chips. */ - - return !!((svga->crtc[0x40] & 0x08) || (s3->accel.advfunc_cntl & 0x40)); -#else - return 1; -#endif -} - - -void s3_accel_out(uint16_t port, uint8_t val, void *p) +static void +s3_accel_out(uint16_t port, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (port >= 0x8000) { + if (!s3->enable_8514) + return; - if (port >= 0x8000) - { if (s3_enable_fifo(s3)) s3_queue(s3, port, val, FIFO_OUT_BYTE); else s3_accel_out_fifo(s3, port, val); - } - else - { + } else { switch (port) { case 0x4148: case 0x42e8: @@ -1834,416 +3464,1029 @@ void s3_accel_out(uint16_t port, uint8_t val, void *p) break; case 0x4948: case 0x4ae8: s3->accel.advfunc_cntl = val; - s3_updatemapping(s3); + if ((s3->chip > S3_86C805) && ((svga->crtc[0x50] & 0xc1) == 0x80)) { + s3->width = (val & 4) ? 1600 : 800; + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } else if (s3->chip <= S3_86C805) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + if (s3->chip > S3_86C924) + s3_updatemapping(s3); break; } } } -void s3_accel_out_w(uint16_t port, uint16_t val, void *p) +static void +s3_accel_out_w(uint16_t port, uint16_t val, void *p) { s3_t *s3 = (s3_t *)p; + if (!s3->enable_8514) + return; + if (s3_enable_fifo(s3)) s3_queue(s3, port, val, FIFO_OUT_WORD); else s3_accel_out_fifo_w(s3, port, val); } -void s3_accel_out_l(uint16_t port, uint32_t val, void *p) +static void +s3_accel_out_l(uint16_t port, uint32_t val, void *p) { s3_t *s3 = (s3_t *)p; + if (!s3->enable_8514) + return; + if (s3_enable_fifo(s3)) s3_queue(s3, port, val, FIFO_OUT_DWORD); else s3_accel_out_fifo_l(s3, port, val); } -uint8_t s3_accel_in(uint16_t port, void *p) +static uint8_t +s3_accel_in(uint16_t port, void *p) { s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; int temp; - switch (port) - { + if (!s3->enable_8514) + return 0xff; + + switch (port) { case 0x4148: case 0x42e8: return s3->subsys_stat; case 0x4149: case 0x42e9: return s3->subsys_cntl; case 0x8148: case 0x82e8: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.cur_y & 0xff; - case 8149: case 0x82e9: - s3_wait_fifo_idle(s3); - return s3->accel.cur_y >> 8; + case 0x8149: case 0x82e9: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.cur_y >> 8; case 0x8548: case 0x86e8: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.cur_x & 0xff; case 0x8549: case 0x86e9: - s3_wait_fifo_idle(s3); - return s3->accel.cur_x >> 8; + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.cur_x >> 8; case 0x8948: case 0x8ae8: - s3_wait_fifo_idle(s3); - return s3->accel.desty_axstp & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp & 0xff; + } + break; case 0x8949: case 0x8ae9: - s3_wait_fifo_idle(s3); - return s3->accel.desty_axstp >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp >> 8; + } + break; case 0x8d48: case 0x8ee8: - s3_wait_fifo_idle(s3); - return s3->accel.destx_distp & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp & 0xff; + } + break; case 0x8d49: case 0x8ee9: - s3_wait_fifo_idle(s3); - return s3->accel.destx_distp >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp >> 8; + } + break; case 0x9148: case 0x92e8: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.err_term & 0xff; case 0x9149: case 0x92e9: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.err_term >> 8; case 0x9548: case 0x96e8: - s3_wait_fifo_idle(s3); - return s3->accel.maj_axis_pcnt & 0xff; + if (s3->chip >= S3_86C928) { + return s3->accel.maj_axis_pcnt & 0xff; + } + break; case 0x9549: case 0x96e9: - s3_wait_fifo_idle(s3); - return s3->accel.maj_axis_pcnt >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt >> 8; + } + break; + case 0x8118: case 0x9948: case 0x9ae8: temp = 0; /* FIFO empty */ - if (!s3->blitter_busy) - wake_fifo_thread(s3); - if (FIFO_FULL && s3->chip >= S3_VISION864) - temp = 0xff; /*FIFO full*/ - return temp; /*FIFO empty*/ - case 0x9949: case 0x9ae9: - if (!s3->blitter_busy) - wake_fifo_thread(s3); - temp = 0; - if (s3->chip < S3_VISION864) - { - if (!FIFO_EMPTY) - temp |= 0x02; - else - temp |= s3->status_9ae8; /*FIFO empty*/ - if (s3->data_available) { - temp |= 0x01; - s3->data_available = 0; /* Clear to avoid overblits. */ - } + if (s3_enable_fifo(s3)) { + if (!s3->blitter_busy) + wake_fifo_thread(s3); + if (FIFO_FULL) + temp = 0xff; } - else - { - if (!FIFO_EMPTY) + return temp; + case 0x8119: + case 0x9949: case 0x9ae9: + temp = 0; + if (s3_enable_fifo(s3)) { + if (!s3->blitter_busy) + wake_fifo_thread(s3); + + if (!FIFO_EMPTY || s3->force_busy) temp |= 0x02; /*Hardware busy*/ else - temp |= s3->status_9ae8; /*FIFO empty*/ - if (FIFO_FULL) - temp |= 0xf8; /*FIFO full*/ + temp |= 0x04; /*FIFO empty*/ + s3->force_busy = 0; + + if (s3->chip >= S3_VISION964) { + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + } + + if (s3->data_available) { + temp |= 0x01; /*Read Data available*/ + s3->data_available = 0; + } + } else { + if (s3->force_busy) { + temp |= 0x02; /*Hardware busy*/ + } + s3->force_busy = 0; + if (s3->data_available) { + temp |= 0x01; /*Read Data available*/ + s3->data_available = 0; + } } return temp; + case 0x9d48: case 0x9ee8: + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.short_stroke & 0xff; + } + break; + case 0x9d49: case 0x9ee9: + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.short_stroke >> 8; + } + break; + case 0xa148: case 0xa2e8: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_color & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color & 0xff; + } + break; case 0xa149: case 0xa2e9: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_color >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 8; + } + break; case 0xa14a: case 0xa2ea: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.bkgd_color >> 16; case 0xa14b: case 0xa2eb: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.bkgd_color >> 24; case 0xa548: case 0xa6e8: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_color & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color & 0xff; + } + break; case 0xa549: case 0xa6e9: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_color >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 8; + } + break; case 0xa54a: case 0xa6ea: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.frgd_color >> 16; case 0xa54b: case 0xa6eb: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.frgd_color >> 24; case 0xa948: case 0xaae8: - s3_wait_fifo_idle(s3); - return s3->accel.wrt_mask & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask & 0xff; + } + break; case 0xa949: case 0xaae9: - s3_wait_fifo_idle(s3); - return s3->accel.wrt_mask >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 8; + } + break; case 0xa94a: case 0xaaea: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.wrt_mask >> 16; case 0xa94b: case 0xaaeb: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.wrt_mask >> 24; case 0xad48: case 0xaee8: - s3_wait_fifo_idle(s3); - return s3->accel.rd_mask & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask & 0xff; + } + break; case 0xad49: case 0xaee9: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.rd_mask >> 8; case 0xad4a: case 0xaeea: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.rd_mask >> 16; case 0xad4b: case 0xaeeb: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.rd_mask >> 24; case 0xb148: case 0xb2e8: - s3_wait_fifo_idle(s3); - return s3->accel.color_cmp & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp & 0xff; + } + break; case 0xb149: case 0xb2e9: - s3_wait_fifo_idle(s3); - return s3->accel.color_cmp >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 8; + } + break; case 0xb14a: case 0xb2ea: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.color_cmp >> 16; case 0xb14b: case 0xb2eb: - s3_wait_fifo_idle(s3); + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); return s3->accel.color_cmp >> 24; case 0xb548: case 0xb6e8: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_mix; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_mix; + } + break; case 0xb948: case 0xbae8: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_mix; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.frgd_mix; + } + break; case 0xbd48: case 0xbee8: - s3_wait_fifo_idle(s3); - temp = s3->accel.multifunc[0xf] & 0xf; - switch (temp) - { - case 0x0: return s3->accel.multifunc[0x0] & 0xff; - case 0x1: return s3->accel.multifunc[0x1] & 0xff; - case 0x2: return s3->accel.multifunc[0x2] & 0xff; - case 0x3: return s3->accel.multifunc[0x3] & 0xff; - case 0x4: return s3->accel.multifunc[0x4] & 0xff; - case 0x5: return s3->accel.multifunc[0xa] & 0xff; - case 0x6: return s3->accel.multifunc[0xe] & 0xff; - case 0x7: return s3->accel.cmd & 0xff; - case 0x8: return s3->accel.subsys_cntl & 0xff; - case 0x9: return s3->accel.setup_md & 0xff; - case 0xa: return s3->accel.multifunc[0xd] & 0xff; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] & 0xff; + case 0x1: return s3->accel.multifunc[0x1] & 0xff; + case 0x2: return s3->accel.multifunc[0x2] & 0xff; + case 0x3: return s3->accel.multifunc[0x3] & 0xff; + case 0x4: return s3->accel.multifunc[0x4] & 0xff; + case 0x5: return s3->accel.multifunc[0xa] & 0xff; + case 0x6: return s3->accel.multifunc[0xe] & 0xff; + case 0x7: return s3->accel.cmd & 0xff; + case 0x8: return s3->accel.subsys_cntl & 0xff; + case 0x9: return s3->accel.setup_md & 0xff; + case 0xa: return s3->accel.multifunc[0xd] & 0xff; + } + return 0xff; } - return 0xff; + break; case 0xbd49: case 0xbee9: - s3_wait_fifo_idle(s3); - temp = s3->accel.multifunc[0xf] & 0xf; - s3->accel.multifunc[0xf]++; - switch (temp) - { - case 0x0: return s3->accel.multifunc[0x0] >> 8; - case 0x1: return s3->accel.multifunc[0x1] >> 8; - case 0x2: return s3->accel.multifunc[0x2] >> 8; - case 0x3: return s3->accel.multifunc[0x3] >> 8; - case 0x4: return s3->accel.multifunc[0x4] >> 8; - case 0x5: return s3->accel.multifunc[0xa] >> 8; - case 0x6: return s3->accel.multifunc[0xe] >> 8; - case 0x7: return s3->accel.cmd >> 8; - case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; - case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; - case 0xa: return s3->accel.multifunc[0xd] >> 8; + if (s3->chip >= S3_86C928) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + s3->accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] >> 8; + case 0x1: return s3->accel.multifunc[0x1] >> 8; + case 0x2: return s3->accel.multifunc[0x2] >> 8; + case 0x3: return s3->accel.multifunc[0x3] >> 8; + case 0x4: return s3->accel.multifunc[0x4] >> 8; + case 0x5: return s3->accel.multifunc[0xa] >> 8; + case 0x6: return s3->accel.multifunc[0xe] >> 8; + case 0x7: return s3->accel.cmd >> 8; + case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3->accel.multifunc[0xd] >> 8; + } + return 0xff; } - return 0xff; + break; + + case 0xd148: case 0xd2e8: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.ropmix & 0xff; + + case 0xd149: case 0xd2e9: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.ropmix >> 8; + + case 0xe548: case 0xe6e8: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_bg_color & 0xff; + + case 0xe549: case 0xe6e9: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_bg_color >> 8; + + case 0xe54a: case 0xe6ea: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_bg_color >> 16; + + case 0xe54b: case 0xe6eb: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_bg_color >> 24; + + case 0xe948: case 0xeae8: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_y & 0xff; + + case 0xe949: case 0xeae9: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_y >> 8; + + case 0xe94a: case 0xeaea: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_x & 0xff; + + case 0xe94b: case 0xeaeb: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_x >> 8; + + case 0xed48: case 0xeee8: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_fg_color & 0xff; + + case 0xed49: case 0xeee9: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_fg_color >> 8; + + case 0xed4a: case 0xeeea: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_fg_color >> 16; + + case 0xed4b: case 0xeeeb: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.pat_fg_color >> 24; case 0xe148: case 0xe2e8: if (!s3_cpu_dest(s3)) break; - temp = s3->accel.pix_trans[0]; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - s3_accel_start(8, 1, 0xffffffff, 0, s3); - else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); - return temp; + READ_PIXTRANS_BYTE_IO(0) + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(16, 1, s3->accel.pix_trans[0], 0, s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } else { + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } + break; + } + } + return s3->accel.pix_trans[0]; + case 0xe149: case 0xe2e9: if (!s3_cpu_dest(s3)) break; - temp = s3->accel.pix_trans[1]; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) - s3_accel_start(16, 1, 0xffffffff, 0, s3); - else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) - s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); - return temp; + READ_PIXTRANS_BYTE_IO(1); + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else + s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + } else { + if (s3->accel.cmd & 0x1000) + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + } + } + return s3->accel.pix_trans[1]; + case 0xe14a: case 0xe2ea: if (!s3_cpu_dest(s3)) break; - temp = s3->accel.pix_trans[2]; - return temp; + READ_PIXTRANS_BYTE_IO(2); + return s3->accel.pix_trans[2]; + case 0xe14b: case 0xe2eb: if (!s3_cpu_dest(s3)) break; - temp = s3->accel.pix_trans[3]; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) - s3_accel_start(32, 1, 0xffffffff, 0, s3); - else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) - s3_accel_start(4, 1, 0xffffffff, 0xffffffff, s3); + READ_PIXTRANS_BYTE_IO(3) + if (s3->accel.cmd & 0x100) { + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } else + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + } else + s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + } + } + return s3->accel.pix_trans[3]; + + case 0xff20: case 0xff21: + temp = s3->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); + if ((s3->serialport & SERIAL_PORT_SCW) && i2c_gpio_get_scl(s3->i2c)) + temp |= SERIAL_PORT_SCR; + if ((s3->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(s3->i2c)) + temp |= SERIAL_PORT_SDR; return temp; } - return 0; + + return 0xff; } -void s3_accel_write(uint32_t addr, uint8_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); -} -void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); -} -void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); -} - -uint8_t s3_accel_read(uint32_t addr, void *p) -{ - s3_t *s3 = (s3_t *)p; - uint8_t temp = 0x00; - - if (addr & 0x8000) - { - temp = s3_accel_in(addr & 0xffff, p); - } - else if (s3_cpu_dest(s3)) - { - temp = s3->accel.pix_trans[addr & 3]; - - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - s3_accel_start(8, 1, 0xffffffff, 0, s3); - else - s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); - } - } - - return temp; -} - -uint16_t s3_accel_read_w(uint32_t addr, void *p) +static uint16_t +s3_accel_in_w(uint16_t port, void *p) { s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; uint16_t temp = 0x0000; + uint16_t *vram_w = (uint16_t *)svga->vram; - if (addr & 0x8000) - { - temp = s3_accel_read((addr & 0xfffe), p); - temp |= s3_accel_read((addr & 0xfffe) + 1, p) << 8; - } - else if (s3_cpu_dest(s3)) - { - temp = s3->accel.pix_trans[addr & 2]; - temp |= s3->accel.pix_trans[(addr & 2) + 1] << 8; + if (!s3->enable_8514) + return 0xffff; - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) - { - s3_accel_start(8, 1, 0xff, 0, s3); - s3_accel_start(8, 1, 0xff, 0, s3); - } - else if ((s3->accel.cmd & 0x600) == 0x000) - s3_accel_start(8, 1, 0xffff, 0, s3); - else - s3_accel_start(16, 1, 0xffff, 0, s3); - } - else - { - if ((s3->accel.cmd & 0x600) == 0x000) - s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); - else - s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + if (port != 0x9ee8 && port != 0x9d48) { + if (s3_cpu_dest(s3)) { + READ_PIXTRANS_WORD + + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + temp = (temp >> 8) | (temp << 8); + s3_accel_start(8, 1, temp | (temp << 16), 0, s3); + } else { + s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + } + } else { + if (s3->color_16bit) { + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + } else { + s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + } + } + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + temp = (temp >> 8) | (temp << 8); + s3_accel_start(16, 1, temp | (temp << 16), 0, s3); + } else + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + } else { + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + } + break; } } + } else { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->accel.short_stroke; } return temp; } -uint32_t s3_accel_read_l(uint32_t addr, void *p) +static uint32_t +s3_accel_in_l(uint16_t port, void *p) { s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; uint32_t temp = 0x00000000; + uint16_t *vram_w = (uint16_t *)svga->vram; - if (addr & 0x8000) - { - temp = s3_accel_read((addr & 0xfffc), p); - temp |= s3_accel_read((addr & 0xfffc) + 1, p) << 8; - temp |= s3_accel_read((addr & 0xfffc) + 2, p) << 16; - temp |= s3_accel_read((addr & 0xfffc) + 3, p) << 24; - } - else if (s3_cpu_dest(s3)) - { - temp = s3->accel.pix_trans[0]; - temp |= s3->accel.pix_trans[1] << 8; - temp |= s3->accel.pix_trans[2] << 16; - temp |= s3->accel.pix_trans[3] << 24; + if (!s3->enable_8514) + return 0xffffffff; - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) - { - s3_accel_start(8, 1, 0xff, 0, s3); - s3_accel_start(8, 1, 0xff, 0, s3); - s3_accel_start(8, 1, 0xff, 0, s3); - s3_accel_start(8, 1, 0xff, 0, s3); + if (s3_cpu_dest(s3)) { + READ_PIXTRANS_LONG + + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + temp = ((temp & 0xff00ff00) >> 8) | ((temp & 0x00ff00ff) << 8); + s3_accel_start(8, 1, temp, 0, s3); + s3_accel_start(8, 1, temp >> 16, 0, s3); + } else { + s3_accel_start(1, 1, 0xffffffff, temp, s3); + s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + } + } else { + s3_accel_start(1, 1, 0xffffffff, temp, s3); + s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); } - else if (s3->accel.cmd & 0x400) - { - s3_accel_start(32, 1, 0xffffffff, 0, s3); + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + if (s3->accel.cmd & 0x1000) + temp = ((temp & 0xff00ff00) >> 8) | ((temp & 0x00ff00ff) << 8); + s3_accel_start(16, 1, temp, 0, s3); + s3_accel_start(16, 1, temp >> 16, 0, s3); + } else { + s3_accel_start(2, 1, 0xffffffff, temp, s3); + s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + } + } else { + s3_accel_start(2, 1, 0xffffffff, temp, s3); + s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); } - else if ((s3->accel.cmd & 0x600) == 0x200) - { - s3_accel_start(16, 1, 0xffff, 0, s3); - s3_accel_start(16, 1, 0xffff, 0, s3); - } - else - { - s3_accel_start(8, 1, 0xffff, 0, s3); - s3_accel_start(8, 1, 0xffff, 0, s3); - } - } - else - { - if (s3->accel.cmd & 0x400) - s3_accel_start(4, 1, 0xffffffff, 0xffffffff, s3); - else if ((s3->accel.cmd & 0x600) == 0x200) - { - s3_accel_start(2, 1, 0xffffffff, 0xffff, s3); - s3_accel_start(2, 1, 0xffffffff, 0xffff, s3); - } - else - { - s3_accel_start(1, 1, 0xffffffff, 0xffff, s3); - s3_accel_start(1, 1, 0xffffffff, 0xffff, s3); - } - } + break; } } return temp; } -static void polygon_setup(s3_t *s3) + +static void +s3_accel_write(uint32_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (!s3->enable_8514) + return; + + if (s3_enable_fifo(s3)) { + if (svga->crtc[0x53] & 0x08) + s3_queue(s3, addr & 0x1ffff, val, FIFO_WRITE_BYTE); + else + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); + } else + s3_accel_write_fifo(s3, addr & 0xffff, val); +} + +static void +s3_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (!s3->enable_8514) + return; + + if (s3_enable_fifo(s3)) { + if (svga->crtc[0x53] & 0x08) + s3_queue(s3, addr & 0x1ffff, val, FIFO_WRITE_WORD); + else + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); + } else + s3_accel_write_fifo_w(s3, addr & 0xffff, val); +} + +static void +s3_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (!s3->enable_8514) + return; + + if (s3_enable_fifo(s3)) { + if (svga->crtc[0x53] & 0x08) + s3_queue(s3, addr & 0x1ffff, val, FIFO_WRITE_DWORD); + else + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); + } else + s3_accel_write_fifo_l(s3, addr & 0xffff, val); +} + +static uint8_t +s3_accel_read(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint8_t temp = 0x00; + + if (!s3->enable_8514) + return 0xff; + + if (svga->crtc[0x53] & 0x08) { + if ((addr >= 0x08000) && (addr <= 0x0803f)) + return s3_pci_read(0, addr & 0xff, s3); + switch (addr & 0x1ffff) { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + return s3_in(addr & 0x3ff, s3); + case 0x8504: + return s3->subsys_stat; + case 0x8505: + return s3->subsys_cntl; + default: + return s3_accel_in(addr & 0xffff, p); + } + return 0xff; + } else { + if (addr & 0x8000) { + temp = s3_accel_in(addr & 0xffff, p); + } else if (s3_cpu_dest(s3)) { + READ_PIXTRANS_BYTE_MM + + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + } else + s3_accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(16, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3); + else + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + } else + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + break; + } + } + } + + return temp; +} + +static uint16_t +s3_accel_read_w(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint16_t temp = 0x0000; + uint16_t *vram_w = (uint16_t *)svga->vram; + + if (!s3->enable_8514) + return 0xffff; + + if (svga->crtc[0x53] & 0x08) { + switch (addr & 0x1fffe) { + case 0x811c: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + return s3->accel.short_stroke; + + default: + return s3_accel_read(addr, p) | + s3_accel_read(addr + 1, p) << 8; + } + return 0xffff; + } else { + if (addr & 0x8000) { + if (addr == 0x811c) { + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->accel.short_stroke; + } else { + temp = s3_accel_read((addr & 0xfffe), p); + temp |= s3_accel_read((addr & 0xfffe) + 1, p) << 8; + } + } else if (s3_cpu_dest(s3)) { + READ_PIXTRANS_WORD + + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(8, 1, temp | (temp << 16), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + } else + s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) + s3_accel_start(16, 1, temp | (temp << 16), 0, s3); + else + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + } else + s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + break; + } + } + } + + return temp; +} + + +static uint32_t +s3_accel_read_l(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint32_t temp = 0x00000000; + uint16_t *vram_w = (uint16_t *)svga->vram; + + if (!s3->enable_8514) + return 0xffffffff; + + if (svga->crtc[0x53] & 0x08) { + switch (addr & 0x1fffc) { + case 0x8180: + temp = s3->streams.pri_ctrl; + break; + case 0x8184: + temp = s3->streams.chroma_ctrl; + break; + case 0x8190: + temp = s3->streams.sec_ctrl; + break; + case 0x8194: + temp = s3->streams.chroma_upper_bound; + break; + case 0x8198: + temp = s3->streams.sec_filter; + break; + case 0x81a0: + temp = s3->streams.blend_ctrl; + break; + case 0x81c0: + temp = s3->streams.pri_fb0; + break; + case 0x81c4: + temp = s3->streams.pri_fb1; + break; + case 0x81c8: + temp = s3->streams.pri_stride; + break; + case 0x81cc: + temp = s3->streams.buffer_ctrl; + break; + case 0x81d0: + temp = s3->streams.sec_fb0; + break; + case 0x81d4: + temp = s3->streams.sec_fb1; + break; + case 0x81d8: + temp = s3->streams.sec_stride; + break; + case 0x81dc: + temp = s3->streams.overlay_ctrl; + break; + case 0x81e0: + temp = s3->streams.k1_vert_scale; + break; + case 0x81e4: + temp = s3->streams.k2_vert_scale; + break; + case 0x81e8: + temp = s3->streams.dda_vert_accumulator; + break; + case 0x81ec: + temp = s3->streams.fifo_ctrl; + break; + case 0x81f0: + temp = s3->streams.pri_start; + break; + case 0x81f4: + temp = s3->streams.pri_size; + break; + case 0x81f8: + temp = s3->streams.sec_start; + break; + case 0x81fc: + temp = s3->streams.sec_size; + break; + + case 0x18080: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = 0; + break; + case 0x18088: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->videoengine.cntl; + if (s3->bpp == 1) { /*The actual bpp is decided by the guest when idf is the same as odf*/ + if (s3->videoengine.idf == 0 && s3->videoengine.odf == 0) { + if (svga->bpp == 15) + temp |= 0x600000; + else + temp |= 0x700000; + } + } else if (s3->bpp > 1) { + if (s3->videoengine.idf == 0 && s3->videoengine.odf == 0) + temp |= 0x300000; + } + break; + case 0x1808c: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->videoengine.stretch_filt_const; + break; + case 0x18090: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->videoengine.src_dst_step; + break; + case 0x18094: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->videoengine.crop; + break; + case 0x18098: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->videoengine.src_base; + break; + case 0x1809c: + if (s3_enable_fifo(s3)) + s3_wait_fifo_idle(s3); + temp = s3->videoengine.dest_base; + if (s3->videoengine.busy) { + temp |= (1 << 31); + } else { + temp &= ~(1 << 31); + } + break; + + default: + temp = s3_accel_read_w(addr, p) | (s3_accel_read_w(addr + 2, p) << 16); + break; + } + } else { + if (addr & 0x8000) { + temp = s3_accel_read((addr & 0xfffc), p); + temp |= s3_accel_read((addr & 0xfffc) + 1, p) << 8; + temp |= s3_accel_read((addr & 0xfffc) + 2, p) << 16; + temp |= s3_accel_read((addr & 0xfffc) + 3, p) << 24; + } else if (s3_cpu_dest(s3)) { + READ_PIXTRANS_LONG + + switch (s3->accel.cmd & 0x600) { + case 0x000: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + s3_accel_start(8, 1, temp, 0, s3); + s3_accel_start(8, 1, temp >> 16, 0, s3); + } else { + s3_accel_start(1, 1, 0xffffffff, temp, s3); + s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + } + } else { + s3_accel_start(1, 1, 0xffffffff, temp, s3); + s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + } + break; + case 0x200: + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { + s3_accel_start(16, 1, temp, 0, s3); + s3_accel_start(16, 1, temp >> 16, 0, s3); + } else { + s3_accel_start(2, 1, 0xffffffff, temp, s3); + s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + } + } else { + s3_accel_start(2, 1, 0xffffffff, temp, s3); + s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + } + break; + } + } + } + + return temp; +} + +static void +polygon_setup(s3_t *s3) { if (s3->accel.point_1_updated) { @@ -2251,12 +4494,12 @@ static void polygon_setup(s3_t *s3) int start_y = s3->accel.poly_cy; int end_x = s3->accel.destx_distp << 20; int end_y = s3->accel.desty_axstp; - + if (end_y - start_y) s3->accel.poly_dx1 = (end_x - start_x) / (end_y - start_y); else s3->accel.poly_dx1 = 0; - + s3->accel.point_1_updated = 0; if (end_y == s3->accel.poly_cy) @@ -2272,27 +4515,22 @@ static void polygon_setup(s3_t *s3) int end_x = s3->accel.x2 << 20; int end_y = s3->accel.desty_axstp2; - if (end_y - start_y) + if (end_y - start_y) s3->accel.poly_dx2 = (end_x - start_x) / (end_y - start_y); else s3->accel.poly_dx2 = 0; s3->accel.point_2_updated = 0; - + if (end_y == s3->accel.poly_cy) s3->accel.poly_cx2 = end_x; } } -#define READ_SRC(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ - else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ - else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; \ - if (vram_mask) \ - dat = ((dat & rd_mask) == rd_mask); - -#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ - else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ - else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; +#define READ(addr, dat) if (s3->bpp == 0 && !s3->color_16bit) dat = svga->vram[dword_remap(svga, addr) & s3->vram_mask]; \ + else if (s3->bpp == 1 || s3->color_16bit) dat = vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)]; \ + else if (s3->bpp == 2) dat = svga->vram[dword_remap(svga, addr) & s3->vram_mask]; \ + else dat = vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)]; #define MIX_READ { \ switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ @@ -2318,61 +4556,679 @@ static void polygon_setup(s3_t *s3) #define MIX { \ - uint32_t old_dest_dat = dest_dat; \ + old_dest_dat = dest_dat; \ MIX_READ \ dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ } -#define WRITE(addr) if (s3->bpp == 0) \ + +#define ROPMIX_READ(D, P, S) \ + { \ + switch (rop) { \ + case 0x00: out = 0; break; \ + case 0x01: out = ~(D | (P | S)); break; \ + case 0x02: out = D & ~(P | S); break; \ + case 0x03: out = ~(P | S); break; \ + case 0x04: out = S & ~(D | P); break; \ + case 0x05: out = ~(D | P); break; \ + case 0x06: out = ~(P | ~(D ^ S)); break; \ + case 0x07: out = ~(P | (D & S)); break; \ + case 0x08: out = S & (D & ~P); break; \ + case 0x09: out = ~(P | (D ^ S)); break; \ + case 0x0a: out = D & ~P; break; \ + case 0x0b: out = ~(P | (S & ~D)); break; \ + case 0x0c: out = S & ~P; break; \ + case 0x0d: out = ~(P | (D & ~S)); break; \ + case 0x0e: out = ~(P | ~(D | S)); break; \ + case 0x0f: out = ~P; break; \ + case 0x10: out = P & ~(D | S); break; \ + case 0x11: out = ~(D | S); break; \ + case 0x12: out = ~(S | ~(D ^ P)); break; \ + case 0x13: out = ~(S | (D & P)); break; \ + case 0x14: out = ~(D | ~(P ^ S)); break; \ + case 0x15: out = ~(D | (P & S)); break; \ + case 0x16: out = P ^ (S ^ (D & ~(P & S))); break; \ + case 0x17: out = ~(S ^ ((S ^ P) & (D ^ S))); break; \ + case 0x18: out = (S ^ P) & (P ^ D); break; \ + case 0x19: out = ~(S ^ (D & ~(P & S))); break; \ + case 0x1a: out = P ^ (D | (S & P)); break; \ + case 0x1b: out = ~(S ^ (D & (P ^ S))); break; \ + case 0x1c: out = P ^ (S | (D & P)); break; \ + case 0x1d: out = ~(D ^ (S & (P ^ D))); break; \ + case 0x1e: out = P ^ (D | S); break; \ + case 0x1f: out = ~(P & (D | S)); break; \ + case 0x20: out = D & (P & ~S); break; \ + case 0x21: out = ~(S | (D ^ P)); break; \ + case 0x22: out = D & ~S; break; \ + case 0x23: out = ~(S | (P & ~D)); break; \ + case 0x24: out = (S ^ P) & (D ^ S); break; \ + case 0x25: out = ~(P ^ (D & ~(S & P))); break; \ + case 0x26: out = S ^ (D | (P & S)); break; \ + case 0x27: out = S ^ (D | ~(P ^ S)); break; \ + case 0x28: out = D & (P ^ S); break; \ + case 0x29: out = ~(P ^ (S ^ (D | (P & S)))); break; \ + case 0x2a: out = D & ~(P & S); break; \ + case 0x2b: out = ~(S ^ ((S ^ P) & (P ^ D))); break; \ + case 0x2c: out = S ^ (P & (D | S)); break; \ + case 0x2d: out = P ^ (S | ~D); break; \ + case 0x2e: out = P ^ (S | (D ^ P)); break; \ + case 0x2f: out = ~(P & (S | ~D)); break; \ + case 0x30: out = P & ~S; break; \ + case 0x31: out = ~(S | (D & ~P)); break; \ + case 0x32: out = S ^ (D | (P | S)); break; \ + case 0x33: out = ~S; break; \ + case 0x34: out = S ^ (P | (D & S)); break; \ + case 0x35: out = S ^ (P | ~(D ^ S)); break; \ + case 0x36: out = S ^ (D | P); break; \ + case 0x37: out = ~(S & (D | P)); break; \ + case 0x38: out = P ^ (S & (D | P)); break; \ + case 0x39: out = S ^ (P | ~D); break; \ + case 0x3a: out = S ^ (P | (D ^ S)); break; \ + case 0x3b: out = ~(S & (P | ~D)); break; \ + case 0x3c: out = P ^ S; break; \ + case 0x3d: out = S ^ (P | ~(D | S)); break; \ + case 0x3e: out = S ^ (P | (D & ~S)); break; \ + case 0x3f: out = ~(P & S); break; \ + case 0x40: out = P & (S & ~D); break; \ + case 0x41: out = ~(D | (P ^ S)); break; \ + case 0x42: out = (S ^ D) & (P ^ D); break; \ + case 0x43: out = ~(S ^ (P & ~(D & S))); break; \ + case 0x44: out = S & ~D; break; \ + case 0x45: out = ~(D | (P & ~S)); break; \ + case 0x46: out = D ^ (S | (P & D)); break; \ + case 0x47: out = ~(P ^ (S & (D ^ P))); break; \ + case 0x48: out = S & (D ^ P); break; \ + case 0x49: out = ~(P ^ (D ^ (S | (P & D)))); break; \ + case 0x4a: out = D ^ (P & (S | D)); break; \ + case 0x4b: out = P ^ (D | ~S); break; \ + case 0x4c: out = S & ~(D & P); break; \ + case 0x4d: out = ~(S ^ ((S ^ P) | (D ^ S))); break; \ + case 0x4e: out = P ^ (D | (S ^ P)); break; \ + case 0x4f: out = ~(P & (D | ~S)); break; \ + case 0x50: out = P & ~D; break; \ + case 0x51: out = ~(D | (S & ~P)); break; \ + case 0x52: out = D ^ (P | (S & D)); break; \ + case 0x53: out = ~(S ^ (P & (D ^ S))); break; \ + case 0x54: out = ~(D | ~(P | S)); break; \ + case 0x55: out = ~D; break; \ + case 0x56: out = D ^ (P | S); break; \ + case 0x57: out = ~(D & (P | S)); break; \ + case 0x58: out = P ^ (D & (S | P)); break; \ + case 0x59: out = D ^ (P | ~S); break; \ + case 0x5a: out = D ^ P; break; \ + case 0x5b: out = D ^ (P | ~(S | D)); break; \ + case 0x5c: out = D ^ (P | (S ^ D)); break; \ + case 0x5d: out = ~(D & (P | ~S)); break; \ + case 0x5e: out = D ^ (P | (S & ~D)); break; \ + case 0x5f: out = ~(D & P); break; \ + case 0x60: out = P & (D ^ S); break; \ + case 0x61: out = ~(D ^ (S ^ (P | (D & S)))); break; \ + case 0x62: out = D ^ (S & (P | D)); break; \ + case 0x63: out = S ^ (D | ~P); break; \ + case 0x64: out = S ^ (D & (P | S)); break; \ + case 0x65: out = D ^ (S | ~P); break; \ + case 0x66: out = D ^ S; break; \ + case 0x67: out = S ^ (D | ~(P | S)); break; \ + case 0x68: out = ~(D ^ (S ^ (P | ~(D | S)))); break; \ + case 0x69: out = ~(P ^ (D ^ S)); break; \ + case 0x6a: out = D ^ (P & S); break; \ + case 0x6b: out = ~(P ^ (S ^ (D & (P | S)))); break; \ + case 0x6c: out = S ^ (D & P); break; \ + case 0x6d: out = ~(P ^ (D ^ (S & (P | D)))); break; \ + case 0x6e: out = S ^ (D & (P | ~S)); break; \ + case 0x6f: out = ~(P & ~(D ^ S)); break; \ + case 0x70: out = P & ~(D & S); break; \ + case 0x71: out = ~(S ^ ((S ^ D) & (P ^ D))); break; \ + case 0x72: out = S ^ (D | (P ^ S)); break; \ + case 0x73: out = ~(S & (D | ~P)); break; \ + case 0x74: out = D ^ (S | (P ^ D)); break; \ + case 0x75: out = ~(D & (S | ~P)); break; \ + case 0x76: out = S ^ (D | (P & ~S)); break; \ + case 0x77: out = ~(D & S); break; \ + case 0x78: out = P ^ (D & S); break; \ + case 0x79: out = ~(D ^ (S ^ (P & (D | S)))); break; \ + case 0x7a: out = D ^ (P & (S | ~D)); break; \ + case 0x7b: out = ~(S & ~(D ^ P)); break; \ + case 0x7c: out = S ^ (P & (D | ~S)); break; \ + case 0x7d: out = ~(D & ~(P ^ S)); break; \ + case 0x7e: out = (S ^ P) | (D ^ S); break; \ + case 0x7f: out = ~(D & (P & S)); break; \ + case 0x80: out = D & (P & S); break; \ + case 0x81: out = ~((S ^ P) | (D ^ S)); break; \ + case 0x82: out = D & ~(P ^ S); break; \ + case 0x83: out = ~(S ^ (P & (D | ~S))); break; \ + case 0x84: out = S & ~(D ^ P); break; \ + case 0x85: out = ~(P ^ (D & (S | ~P))); break; \ + case 0x86: out = D ^ (S ^ (P & (D | S))); break; \ + case 0x87: out = ~(P ^ (D & S)); break; \ + case 0x88: out = D & S; break; \ + case 0x89: out = ~(S ^ (D | (P & ~S))); break; \ + case 0x8a: out = D & (S | ~P); break; \ + case 0x8b: out = ~(D ^ (S | (P ^ D))); break; \ + case 0x8c: out = S & (D | ~P); break; \ + case 0x8d: out = ~(S ^ (D | (P ^ S))); break; \ + case 0x8e: out = S ^ ((S ^ D) & (P ^ D)); break; \ + case 0x8f: out = ~(P & ~(D & S)); break; \ + case 0x90: out = P & ~(D ^ S); break; \ + case 0x91: out = ~(S ^ (D & (P | ~S))); break; \ + case 0x92: out = D ^ (P ^ (S & (D | P))); break; \ + case 0x93: out = ~(S ^ (P & D)); break; \ + case 0x94: out = P ^ (S ^ (D & (P | S))); break; \ + case 0x95: out = ~(D ^ (P & S)); break; \ + case 0x96: out = D ^ (P ^ S); break; \ + case 0x97: out = P ^ (S ^ (D | ~(P | S))); break; \ + case 0x98: out = ~(S ^ (D | ~(P | S))); break; \ + case 0x99: out = ~(D ^ S); break; \ + case 0x9a: out = D ^ (P & ~S); break; \ + case 0x9b: out = ~(S ^ (D & (P | S))); break; \ + case 0x9c: out = S ^ (P & ~D); break; \ + case 0x9d: out = ~(D ^ (S & (P | D))); break; \ + case 0x9e: out = D ^ (S ^ (P | (D & S))); break; \ + case 0x9f: out = ~(P & (D ^ S)); break; \ + case 0xa0: out = D & P; break; \ + case 0xa1: out = ~(P ^ (D | (S & ~P))); break; \ + case 0xa2: out = D & (P | ~S); break; \ + case 0xa3: out = ~(D ^ (P | (S ^ D))); break; \ + case 0xa4: out = ~(P ^ (D | ~(S | P))); break; \ + case 0xa5: out = ~(P ^ D); break; \ + case 0xa6: out = D ^ (S & ~P); break; \ + case 0xa7: out = ~(P ^ (D & (S | P))); break; \ + case 0xa8: out = D & (P | S); break; \ + case 0xa9: out = ~(D ^ (P | S)); break; \ + case 0xaa: out = D; break; \ + case 0xab: out = D | ~(P | S); break; \ + case 0xac: out = S ^ (P & (D ^ S)); break; \ + case 0xad: out = ~(D ^ (P | (S & D))); break; \ + case 0xae: out = D | (S & ~P); break; \ + case 0xaf: out = D | ~P; break; \ + case 0xb0: out = P & (D | ~S); break; \ + case 0xb1: out = ~(P ^ (D | (S ^ P))); break; \ + case 0xb2: out = S ^ ((S ^ P) | (D ^ S)); break; \ + case 0xb3: out = ~(S & ~(D & P)); break; \ + case 0xb4: out = P ^ (S & ~D); break; \ + case 0xb5: out = ~(D ^ (P & (S | D))); break; \ + case 0xb6: out = D ^ (P ^ (S | (D & P))); break; \ + case 0xb7: out = ~(S & (D ^ P)); break; \ + case 0xb8: out = P ^ (S & (D ^ P)); break; \ + case 0xb9: out = ~(D ^ (S | (P & D))); break; \ + case 0xba: out = D | (P & ~S); break; \ + case 0xbb: out = D | ~S; break; \ + case 0xbc: out = S ^ (P & ~(D & S)); break; \ + case 0xbd: out = ~((S ^ D) & (P ^ D)); break; \ + case 0xbe: out = D | (P ^ S); break; \ + case 0xbf: out = D | ~(P & S); break; \ + case 0xc0: out = P & S; break; \ + case 0xc1: out = ~(S ^ (P | (D & ~S))); break; \ + case 0xc2: out = ~(S ^ (P | ~(D | S))); break; \ + case 0xc3: out = ~(P ^ S); break; \ + case 0xc4: out = S & (P | ~D); break; \ + case 0xc5: out = ~(S ^ (P | (D ^ S))); break; \ + case 0xc6: out = S ^ (D & ~P); break; \ + case 0xc7: out = ~(P ^ (S & (D | P))); break; \ + case 0xc8: out = S & (D | P); break; \ + case 0xc9: out = ~(S ^ (P | D)); break; \ + case 0xca: out = D ^ (P & (S ^ D)); break; \ + case 0xcb: out = ~(S ^ (P | (D & S))); break; \ + case 0xcc: out = S; break; \ + case 0xcd: out = S | ~(D | P); break; \ + case 0xce: out = S | (D & ~P); break; \ + case 0xcf: out = S | ~P; break; \ + case 0xd0: out = P & (S | ~D); break; \ + case 0xd1: out = ~(P ^ (S | (D ^ P))); break; \ + case 0xd2: out = P ^ (D & ~S); break; \ + case 0xd3: out = ~(S ^ (P & (D | S))); break; \ + case 0xd4: out = S ^ ((S ^ P) & (P ^ D)); break; \ + case 0xd5: out = ~(D & ~(P & S)); break; \ + case 0xd6: out = P ^ (S ^ (D | (P & S))); break; \ + case 0xd7: out = ~(D & (P ^ S)); break; \ + case 0xd8: out = P ^ (D & (S ^ P)); break; \ + case 0xd9: out = ~(S ^ (D | (P & S))); break; \ + case 0xda: out = D ^ (P & ~(S & D)); break; \ + case 0xdb: out = ~((S ^ P) & (D ^ S)); break; \ + case 0xdc: out = S | (P & ~D); break; \ + case 0xdd: out = S | ~D; break; \ + case 0xde: out = S | (D ^ P); break; \ + case 0xdf: out = S | ~(D & P); break; \ + case 0xe0: out = P & (D | S); break; \ + case 0xe1: out = ~(P ^ (D | S)); break; \ + case 0xe2: out = D ^ (S & (P ^ D)); break; \ + case 0xe3: out = ~(P ^ (S | (D & P))); break; \ + case 0xe4: out = S ^ (D & (P ^ S)); break; \ + case 0xe5: out = ~(P ^ (D | (S & P))); break; \ + case 0xe6: out = S ^ (D & ~(P & S)); break; \ + case 0xe7: out = ~((S ^ P) & (P ^ D)); break; \ + case 0xe8: out = S ^ ((S ^ P) & (D ^ S)); break; \ + case 0xe9: out = ~(D ^ (S ^ (P & ~(D & S)))); break; \ + case 0xea: out = D | (P & S); break; \ + case 0xeb: out = D | ~(P ^ S); break; \ + case 0xec: out = S | (D & P); break; \ + case 0xed: out = S | ~(D ^ P); break; \ + case 0xee: out = D | S; break; \ + case 0xef: out = S | (D | ~P); break; \ + case 0xf0: out = P; break; \ + case 0xf1: out = P | ~(D | S); break; \ + case 0xf2: out = P | (D & ~S); break; \ + case 0xf3: out = P | ~S; break; \ + case 0xf4: out = P | (S & ~D); break; \ + case 0xf5: out = P | ~D; break; \ + case 0xf6: out = P | (D ^ S); break; \ + case 0xf7: out = P | ~(D & S); break; \ + case 0xf8: out = P | (D & S); break; \ + case 0xf9: out = P | ~(D ^ S); break; \ + case 0xfa: out = D | P; break; \ + case 0xfb: out = D | (P | ~S); break; \ + case 0xfc: out = P | S; break; \ + case 0xfd: out = P | (S | ~D); break; \ + case 0xfe: out = D | (P | S); break; \ + case 0xff: out = ~0; break; \ + } \ + } + + +#define ROPMIX { \ + old_dest_dat = dest_dat; \ + ROPMIX_READ(dest_dat, pat_dat, src_dat); \ + out = (out & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ + } + + +#define WRITE(addr, dat) if (s3->bpp == 0 && !s3->color_16bit) \ { \ - svga->vram[(addr) & s3->vram_mask] = dest_dat; \ - svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \ + svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ + svga->changedvram[(dword_remap(svga, addr) & s3->vram_mask) >> 12] = changeframecount; \ } \ - else if (s3->bpp == 1) \ + else if (s3->bpp == 1 || s3->color_16bit) \ { \ - vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ - svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)] = dat; \ + svga->changedvram[(dword_remap_w(svga, addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ } \ + else if (s3->bpp == 2) \ + { \ + svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ + svga->changedvram[(dword_remap(svga, addr) & s3->vram_mask) >> 12] = changeframecount; \ + } \ else \ { \ - vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ - svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)] = dat; \ + svga->changedvram[(dword_remap_l(svga, addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ } -int s3_accel_count(s3_t *s3) + +static __inline void +convert_to_rgb32(int idf, int is_yuv, uint32_t val, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *r2, uint8_t *g2, uint8_t *b2) { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - return 8; - else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - return 1; - else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && ((s3->accel.cmd & 0x600) == 0x200) && (s3->accel.cmd & 0x100)) - return 16; - else if (((s3->accel.cmd & 0x600) == 0x200) && (s3->accel.cmd & 0x100)) - return 2; - else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x100)) - return 32; - else if (s3->accel.cmd & 0x100) - return 4; - else - return -1; + static double dr = 0.0, dg = 0.0, db = 0.0; + static double dY1 = 0.0, dCr = 0.0, dY2 = 0.0, dCb = 0.0; + static double dU = 0.0, dV = 0.0; + + switch (idf) { + case 0: /* 8 bpp, RGB 3-3-2 */ + dr = (double) ((val >> 5) & 0x07); + dg = (double) ((val >> 2) & 0x07); + db = (double) (val & 0x03); + dr = (dr / 7.0) * 255.0; + dg = (dg / 7.0) * 255.0; + db = (db / 3.0) * 255.0; + break; + case 3: /* 32bpp, RGB 8-8-8 */ + dr = (double) ((val >> 16) & 0xff); + dg = (double) ((val >> 8) & 0xff); + db = (double) (val & 0xff); + break; + case 4: /* YCbCr */ + if (is_yuv) { + dU = ((double) (val & 0xff)) - 128.0; + dY1 = (double) ((val >> 8) & 0xff); + dY1 = (298.0 * (dY1 - 16.0)) / 256.0; + dV = ((double) ((val >> 16) & 0xff)) - 128.0; + dY2 = (double) ((val >> 24) & 0xff); + dY2 = (298.0 * (dY2 - 16.0)) / 256.0; + + dr = (309.0 * dV) / 256.0; + dg = ((100.0 * dU) + (208.0 * dV)) / 256.0; + db = (516.0 * dU) / 256.0; + } else { + dY1 = (double) (val & 0xff); + dCr = ((double) ((val >> 8) & 0xff)) - 128.0; + dY2 = (double) ((val >> 16) & 0xff); + dCb = ((double) ((val >> 24) & 0xff)) - 128.0; + + dr = (359.0 * dCr) / 256.0; + dg = ((88.0 * dCb) + (183.0 * dCr)) / 2560.0; + db = (453.0 * dCr) / 256.0; + } + + *r = (uint8_t) round(dY1 + dr); + CLAMP(*r); + *g = (uint8_t) round(dY1 - dg); + CLAMP(*g); + *b = (uint8_t) round(dY1 + db); + CLAMP(*b); + + *r2 = (uint8_t) round(dY2 + dr); + CLAMP(*r2); + *g2 = (uint8_t) round(dY2 - dg); + CLAMP(*g2); + *b2 = (uint8_t) round(dY2 + db); + CLAMP(*b2); + return; + case 5: /* 16bpp, raw */ + case 7: /* 16bpp, RGB 5-6-5 */ + dr = (double) ((val >> 11) & 0x1f); + dg = (double) ((val >> 5) & 0x03f); + db = (double) (val & 0x1f); + dr = (dr / 31.0) * 255.0; + dg = (dg / 63.0) * 255.0; + db = (db / 31.0) * 255.0; + break; + case 6: /* 15bpp, RGB 5-5-5 */ + dr = (double) ((val >> 10) & 0x1f); + dg = (double) ((val >> 5) & 0x01f); + db = (double) (val & 0x1f); + dr = (dr / 31.0) * 255.0; + dg = (dg / 31.0) * 255.0; + db = (db / 31.0) * 255.0; + break; + } + + *r = (uint8_t) round(dr); + *g = (uint8_t) round(dg); + *b = (uint8_t) round(db); } -int s3_data_len(s3_t *s3) + +static __inline void +convert_from_rgb32(int idf, int odf, int is_yuv, uint32_t *val, uint8_t r, uint8_t g, uint8_t b, uint8_t r2, uint8_t g2, uint8_t b2) { - if (!(s3->accel.cmd & 0x600)) - return 1; + static double dr = 0.0, dg = 0.0, db = 0.0; + static double dr2 = 0.0, dg2 = 0.0, db2 = 0.0; + static double dY1 = 0.0, dCr = 0.0, dY2 = 0.0, dCb = 0.0; + static double dU = 0.0, dV = 0.0; - if ((s3->accel.cmd & 0x600) == 0x200) - return 2; + dr = (double) r; + dg = (double) g; + db = (double) b; - return 4; + switch (odf) { + case 0: /* 8 bpp, RGB 3-3-2 */ + switch (idf) { + case 3: + *val = (((uint32_t) round(dr)) << 16) + (((uint32_t) round(dg)) << 8) + ((uint32_t) round(db)); + break; + case 5: + case 7: + dr = (dr / 255.0) * 31.0; + dg = (dg / 255.0) * 63.0; + db = (db / 255.0) * 31.0; + *val = (((uint32_t) round(dr)) << 11) + (((uint32_t) round(dg)) << 5) + ((uint32_t) round(db)); + break; + case 6: + dr = (dr / 255.0) * 31.0; + dg = (dg / 255.0) * 31.0; + db = (db / 255.0) * 31.0; + *val = (((uint32_t) round(dr)) << 10) + (((uint32_t) round(dg)) << 5) + ((uint32_t) round(db)); + break; + case 0: + default: + dr = (dr / 255.0) * 7.0; + dg = (dg / 255.0) * 7.0; + db = (db / 255.0) * 3.0; + *val = (((uint32_t) round(dr)) << 5) + (((uint32_t) round(dg)) << 2) + ((uint32_t) round(db)); + break; + } + break; + case 3: /* 32bpp, RGB 8-8-8 */ + *val = (((uint32_t) round(dr)) << 16) + (((uint32_t) round(dg)) << 8) + ((uint32_t) round(db)); + break; + case 4: /* YCbCr */ + dr2 = (double) r2; + dg2 = (double) g2; + db2 = (double) b2; + + if (is_yuv) { + dU = ((113046.0 * dg2) - (71552.0 * dr2) - (69488.0 * db2)) / 28509.0; + dV = ((3328.0 * dr2) + (800.0 * db2) - (4128.0 * dg2)) / 663.0; + dY1 = dr - ((309 * dV) / 256.0); + dY2 = dr2 - ((309 * dV) / 256.0); + + *val = ((uint32_t) round(dU)) + (((uint32_t) round(dY1)) << 8) + (((uint32_t) round(dV)) << 16) + (((uint32_t) round(dY2)) << 24); + } else { + dCr = ((128.0 * db2) - (128.0 * dr2)) / 47.0; + dCb = ((128.0 * dr2) - (128.0 * dg2) - (271.0 * dCr)) / 44.0; + dY1 = dr - ((359.0 * dCr) / 256.0); + dY2 = dr2 - ((359.0 * dCr) / 256.0); + + *val = ((uint32_t) round(dY1)) + (((uint32_t) round(dCr)) << 8) + (((uint32_t) round(dY2)) << 16) + (((uint32_t) round(dCb)) << 24); + } + return; + case 5: /* 16bpp, raw */ + case 7: /* 16bpp, RGB 5-6-5 */ + dr = (dr / 255.0) * 31.0; + dg = (dg / 255.0) * 63.0; + db = (db / 255.0) * 31.0; + *val = (((uint32_t) round(dr)) << 11) + (((uint32_t) round(dg)) << 5) + ((uint32_t) round(db)); + break; + case 6: /* 15bpp, RGB 5-5-5 */ + dr = (dr / 255.0) * 31.0; + dg = (dg / 255.0) * 31.0; + db = (db / 255.0) * 31.0; + *val = (((uint32_t) round(dr)) << 10) + (((uint32_t) round(dg)) << 5) + ((uint32_t) round(db)); + break; + } } -void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +/*To Do: Dithering, color space conversion.*/ +static void +s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3) { svga_t *svga = &s3->svga; - uint32_t src_dat = 0, dest_dat; + int idf, odf, host; + int is_yuv; + uint32_t src, dest = 0x00000000; + uint8_t r = 0x00, g = 0x00, b = 0x00, r2 = 0x00, g2 = 0x00, b2 = 0x00; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + uint32_t k2 = 0, dda = 0, diff = 0; + int count = -1; + + idf = s3->videoengine.idf; + odf = s3->videoengine.odf; + is_yuv = s3->videoengine.yuv; + host = s3->videoengine.host_data; + + k2 = s3->videoengine.k2 - 0x700; + dda = s3->videoengine.dda_init_accumulator - 0xf00; + diff = 0xff - k2; + + s3->videoengine.busy = 1; + + if (host) { + if (idf == 0 && odf == 0) { + if (s3->bpp == 0) + count = 4; + else if (s3->bpp == 1) + count = 2; + else + count = 1; + } else { + if (idf == 0) + count = 4; + else if (idf == 3) + count = 1; + else + count = 2; + } + } + + if (s3->videoengine.input == 1) { + if (s3->videoengine.scale_down) { + if (s3->bpp > 1) { + s3->videoengine.sx = k2 - dda + diff; + s3->videoengine.sx_backup = s3->videoengine.len - s3->videoengine.start; + } else { + s3->videoengine.sx = k2 - dda + diff - 1; + s3->videoengine.sx_backup = s3->videoengine.len - s3->videoengine.start - 1; + } + s3->videoengine.sx_scale_inc = (double)((s3->videoengine.sx_backup >> 1)); + s3->videoengine.sx_scale_inc = s3->videoengine.sx_scale_inc / (double)((s3->videoengine.sx >> 1)); + } else { + s3->videoengine.sx_scale = (double)(s3->videoengine.k1 - 2); + s3->videoengine.sx_scale_dec = (s3->videoengine.sx_scale / (double)(s3->videoengine.len - s3->videoengine.start - 2)); + + if (s3->videoengine.sx_scale_dec >= 0.5) { + s3->videoengine.sx_scale++; + } + } + + if (s3->bpp == 0) { + s3->videoengine.dest = s3->videoengine.dest_base + s3->width; + s3->videoengine.src = s3->videoengine.src_base + s3->width; + } else if (s3->bpp == 1) { + s3->videoengine.dest = (s3->videoengine.dest_base >> 1) + s3->width; + s3->videoengine.src = (s3->videoengine.src_base >> 1) + s3->width; + } else { + s3->videoengine.dest = (s3->videoengine.dest_base >> 2) + s3->width; + s3->videoengine.src = (s3->videoengine.src_base >> 2) + s3->width; + } + s3->videoengine.input = 2; + s3->videoengine.cx = 0.0; + s3->videoengine.dx = 0.0; + } + + while (count) { + if (host) { /*Source data is CPU*/ + src = cpu_dat; + } else { /*Source data is display memory*/ + READ(s3->videoengine.src + lround(s3->videoengine.cx), src); + } + + convert_to_rgb32(idf, is_yuv, src, &r, &g, &b, &r2, &g2, &b2); + + convert_from_rgb32(idf, odf, is_yuv, &dest, r, g, b, r2, g2, b2); + + WRITE(s3->videoengine.dest + lround(s3->videoengine.dx), dest); + + if (s3->videoengine.scale_down) { /*Data shrink*/ + s3->videoengine.dx += s3->videoengine.sx_scale_inc; + if (!host) + s3->videoengine.cx += s3->videoengine.sx_scale_inc; + + s3->videoengine.sx--; + + if (host) { + if (s3->bpp == 0) { + cpu_dat >>= 8; + } else { + cpu_dat >>= 16; + } + count--; + } + + if (s3->videoengine.sx < 0) { + if (s3->bpp > 1) { + s3->videoengine.sx = k2 - dda + diff; + s3->videoengine.sx_backup = s3->videoengine.len - s3->videoengine.start; + } else { + s3->videoengine.sx = k2 - dda + diff - 1; + s3->videoengine.sx_backup = s3->videoengine.len - s3->videoengine.start - 1; + } + s3->videoengine.sx_scale_inc = (double)((s3->videoengine.sx_backup >> 1)); + s3->videoengine.sx_scale_inc = s3->videoengine.sx_scale_inc / (double)((s3->videoengine.sx >> 1)); + + s3->videoengine.cx = 0.0; + s3->videoengine.dx = 0.0; + + if (s3->bpp == 0) { + s3->videoengine.dest = s3->videoengine.dest_base + s3->width; + s3->videoengine.src = s3->videoengine.src_base + s3->width; + } else if (s3->bpp == 1) { + s3->videoengine.dest = (s3->videoengine.dest_base >> 1) + s3->width; + s3->videoengine.src = (s3->videoengine.src_base >> 1) + s3->width; + } else { + s3->videoengine.dest = (s3->videoengine.dest_base >> 2) + s3->width; + s3->videoengine.src = (s3->videoengine.src_base >> 2) + s3->width; + } + + if (s3->videoengine.input >= 1) { + s3->videoengine.busy = 0; + return; + } + } + } else { /*Data stretch*/ + s3->videoengine.dx++; + + s3->videoengine.sx_scale -= s3->videoengine.sx_scale_dec; + s3->videoengine.sx_scale_backup = (s3->videoengine.sx_scale - s3->videoengine.sx_scale_dec); + + s3->videoengine.sx = lround(s3->videoengine.sx_scale); + s3->videoengine.sx_scale_int = lround(s3->videoengine.sx_scale_backup); + + if (s3->videoengine.sx > s3->videoengine.sx_scale_int) { + if (host) { + if (s3->bpp == 0) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + count--; + } else { + s3->videoengine.cx++; + } + } + + if (s3->videoengine.sx < 0) { + s3->videoengine.sx_scale = (double)(s3->videoengine.k1 - 2); + s3->videoengine.sx_scale_dec = (s3->videoengine.sx_scale / (double)(s3->videoengine.len - s3->videoengine.start - 2)); + + if (s3->videoengine.sx_scale_dec >= 0.5) { + s3->videoengine.sx_scale++; + } + + s3->videoengine.cx = 0.0; + s3->videoengine.dx = 0.0; + + if (s3->bpp == 0) { + s3->videoengine.dest = s3->videoengine.dest_base + s3->width; + s3->videoengine.src = s3->videoengine.src_base + s3->width; + } else if (s3->bpp == 1) { + s3->videoengine.dest = (s3->videoengine.dest_base >> 1) + s3->width; + s3->videoengine.src = (s3->videoengine.src_base >> 1) + s3->width; + } else { + s3->videoengine.dest = (s3->videoengine.dest_base >> 2) + s3->width; + s3->videoengine.src = (s3->videoengine.src_base >> 2) + s3->width; + } + + if (s3->videoengine.input >= 1) { + s3->videoengine.busy = 0; + return; + } + } + } + } +} + +void +s3_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3, uint8_t ssv) +{ + if (!cpu_input) { + s3->accel.ssv_len = ssv & 0x0f; + s3->accel.ssv_dir = ssv & 0xe0; + s3->accel.ssv_draw = ssv & 0x10; + + if (s3_cpu_src(s3)) { + return; /*Wait for data from CPU*/ + } + } + + s3_accel_start(count, cpu_input, mix_dat, cpu_dat, s3); +} + +void +s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +{ + svga_t *svga = &s3->svga; + uint32_t src_dat = 0, dest_dat, old_dest_dat; + uint32_t out, pat_dat = 0; int frgd_mix, bkgd_mix; int clip_t = s3->accel.multifunc[1] & 0xfff; int clip_l = s3->accel.multifunc[2] & 0xfff; @@ -2383,78 +5239,156 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat uint16_t *vram_w = (uint16_t *)svga->vram; uint32_t *vram_l = (uint32_t *)svga->vram; uint32_t compare = s3->accel.color_cmp; + uint8_t rop = s3->accel.ropmix & 0xff; int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; uint32_t rd_mask = s3->accel.rd_mask; int cmd = s3->accel.cmd >> 13; - int read = 0, byte_cnt = 0, i; + uint32_t srcbase, dstbase; - if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + if ((s3->chip >= S3_TRIO64 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) && (s3->accel.cmd & (1 << 11))) { cmd |= 8; + } - if (!cpu_input) s3->accel.dat_count = 0; - if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) - { - if (s3->bpp == 3 && count == 2) - { - if (s3->accel.dat_count) - { + // SRC-BASE/DST-BASE + if ((s3->accel.multifunc[0xd] >> 4) & 7) { + srcbase = 0x100000 * ((s3->accel.multifunc[0xd] >> 4) & 3); + } else { + srcbase = 0x100000 * ((s3->accel.multifunc[0xe] >> 2) & 3); + } + if ((s3->accel.multifunc[0xd] >> 0) & 7) { + dstbase = 0x100000 * ((s3->accel.multifunc[0xd] >> 0) & 3); + } else { + dstbase = 0x100000 * ((s3->accel.multifunc[0xe] >> 0) & 3); + } + if (s3->bpp == 1) { + srcbase >>= 1; + dstbase >>= 1; + } else if (s3->bpp == 3) { + srcbase >>= 2; + dstbase >>= 2; + } + + if ((s3->accel.cmd & 0x100) && ((s3_cpu_src(s3) || (s3_cpu_dest(s3)))) && (!cpu_input || (s3_enable_fifo(s3) == 0))) { + s3->force_busy = 1; + } + + if (!cpu_input) + s3->accel.dat_count = 0; + + if (cpu_input && (((s3->accel.multifunc[0xa] & 0xc0) != 0x80) || (!(s3->accel.cmd & 2)))) { + if ((s3->bpp == 3) && count == 2) { + if (s3->accel.dat_count) { cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; count = 4; s3->accel.dat_count = 0; - } - else - { + } else { s3->accel.dat_buf = cpu_dat & 0xffff; s3->accel.dat_count = 1; } } - if (s3->bpp == 1) count >>= 1; - if (s3->bpp == 3) count >>= 2; + if (s3->bpp == 1 || s3->color_16bit) + count >>= 1; + if (s3->bpp == 3) + count >>= 2; } - if (s3->bpp == 0) + if (s3->bpp == 0 && !s3->color_16bit) rd_mask &= 0xff; - else if (s3->bpp == 1) + else if (s3->bpp == 1 || s3->color_16bit) rd_mask &= 0xffff; + if (s3->bpp == 0 && !s3->color_16bit) compare &= 0xff; + if (s3->bpp == 1 || s3->color_16bit) compare &= 0xffff; + switch (s3->accel.cmd & 0x600) { case 0x000: mix_mask = 0x80; break; case 0x200: mix_mask = 0x8000; break; case 0x400: mix_mask = 0x80000000; break; - case 0x600: mix_mask = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; + case 0x600: mix_mask = (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? 0x80 : 0x80000000; break; } - if (s3->bpp == 0) compare &= 0xff; - if (s3->bpp == 1) compare &= 0xffff; - + /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. + When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on + the NOP command)*/ switch (cmd) { - case 1: /*Draw line*/ - if (!cpu_input) /*!cpu_input is trigger to start operation*/ + case 0: /*NOP (Short Stroke Vectors)*/ + if (s3->accel.ssv_state == 0) + break; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) /*Radial*/ { - s3->accel.cx = s3->accel.cur_x; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; - s3->accel.cy = s3->accel.cur_y; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - - s3->accel.sy = s3->accel.maj_axis_pcnt; + while (count-- && s3->accel.ssv_len >= 0) + { + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + if (s3->accel.ssv_draw) { + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + if (!s3->accel.ssv_len) + break; + + switch (s3->accel.ssv_dir & 0xe0) + { + case 0x00: s3->accel.cx++; break; + case 0x20: s3->accel.cx++; s3->accel.cy--; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cx--; s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx--; s3->accel.cy++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cx++; s3->accel.cy++; break; + } + + s3->accel.ssv_len--; + } + + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; } + break; - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + case 1: /*Draw line*/ + if (!cpu_input) { + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x_bit12) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y_bit12) s3->accel.cy |= ~0xfff; - if (s3_cpu_dest(s3)) - s3->data_available = 0; - - - if (s3_cpu_src(s3) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - - if (s3_cpu_src(s3) && !cpu_input) return; /*Wait for data from CPU*/ + s3->accel.sy = s3->accel.maj_axis_pcnt; + if (s3_cpu_src(s3)) { + return; /*Wait for data from CPU*/ + } + } frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; @@ -2462,8 +5396,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { while (count-- && s3->accel.sy >= 0) { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -2477,20 +5411,25 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); MIX - WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); } } mix_dat <<= 1; mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - if (!s3->accel.sy) + if (s3->bpp == 0 && !s3->color_16bit) + cpu_dat >>= 8; + else { + cpu_dat >>= 16; + } + + if (!s3->accel.sy) { break; + } switch (s3->accel.cmd & 0xe0) { @@ -2510,10 +5449,20 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } else /*Bresenham*/ { + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && count == 16) { /*Stupid undocumented 0xB2E8 on 911/924*/ + count = s3->accel.maj_axis_pcnt + 1; + s3->accel.temp_cnt = 16; + } + while (count-- && s3->accel.sy >= 0) { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && s3->accel.temp_cnt == 0) { + mix_dat >>= 16; + s3->accel.temp_cnt = 16; + } + + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -2527,24 +5476,35 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); MIX - WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); } } - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; + if (s3->accel.b2e8_pix && s3_cpu_src(s3)) { + if (s3->accel.temp_cnt > 0) { + s3->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + } else { + mix_dat <<= 1; + mix_dat |= 1; + } + if (s3->bpp == 0 && !s3->color_16bit) + cpu_dat >>= 8; + else { + cpu_dat >>= 16; + } - if (!s3->accel.sy) + if (!s3->accel.sy) { break; + } - if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) - { + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) { s3->accel.err_term += s3->accel.destx_distp; /*Step minor axis*/ switch (s3->accel.cmd & 0xe0) @@ -2558,9 +5518,9 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 0xc0: s3->accel.cx--; break; case 0xe0: s3->accel.cx++; break; } + } else { + s3->accel.err_term += s3->accel.desty_axstp; } - else - s3->accel.err_term += s3->accel.desty_axstp; /*Step major axis*/ switch (s3->accel.cmd & 0xe0) @@ -2580,54 +5540,72 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cur_y = s3->accel.cy; } break; - + case 2: /*Rectangle fill*/ - byte_cnt = s3_data_len(s3); - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - s3->data_available = 0; - if (!cpu_input) /*!cpu_input is trigger to start operation*/ { s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; s3->accel.sy = s3->accel.multifunc[0] & 0xfff; s3->accel.cx = s3->accel.cur_x; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; s3->accel.cy = s3->accel.cur_y; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - - s3->accel.dest = s3->accel.cy * s3->width; + + if (s3->accel.cur_x_bit12) { + if (s3->accel.cx <= 0x7ff) { + s3->accel.cx = s3->accel.cur_x_bitres & 0xfff; + } else { + s3->accel.cx |= ~0xfff; + } + } + if (s3->accel.cur_y_bit12) { + if (s3->accel.cy <= 0x7ff) { + s3->accel.cy = s3->accel.cur_y_bitres & 0xfff; + } else { + s3->accel.cy |= ~0xfff; + } + } + + s3->accel.dest = dstbase + s3->accel.cy * s3->width; if (s3_cpu_src(s3)) { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 0; return; /*Wait for data from CPU*/ - } else if (s3_cpu_dest(s3)) - count = s3_accel_count(s3); + } else if (s3_cpu_dest(s3)) { + s3->data_available = 1; + return; + } } frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - s3->accel.pix_trans[0] = 0xff; - s3->accel.pix_trans[1] = 0xff; - s3->accel.pix_trans[2] = 0xff; - s3->accel.pix_trans[3] = 0xff; + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && count == 16) { /*Stupid undocumented 0xB2E8 on 911/924*/ + count = s3->accel.maj_axis_pcnt + 1; + s3->accel.temp_cnt = 16; + } while (count-- && s3->accel.sy >= 0) { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && s3->accel.temp_cnt == 0) { + mix_dat >>= 16; + s3->accel.temp_cnt = 16; + } + + if (((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b)) { - if (s3_cpu_dest(s3) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x00)) - mix_dat = mix_mask; /* Mix data = forced to foreground register. */ - else if (s3_cpu_dest(s3) && vram_mask) { + if (s3_cpu_dest(s3) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x00)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + } else if (s3_cpu_dest(s3) && vram_mask) { /* Mix data = current video memory value. */ - READ_SRC(s3->accel.dest + s3->accel.cx, mix_dat); + READ(s3->accel.dest + s3->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); mix_dat = mix_dat ? mix_mask : 0; } if (s3_cpu_dest(s3)) { - READ_SRC(s3->accel.dest + s3->accel.cx, src_dat); + READ(s3->accel.dest + s3->accel.cx, src_dat); + if (vram_mask) + src_dat = ((src_dat & rd_mask) == rd_mask); } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = s3->accel.bkgd_color; break; @@ -2636,73 +5614,153 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 3: src_dat = 0; break; } - if ((compare_mode == 2 && src_dat != compare) || + if (((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) + compare_mode < 2)) { - if (s3_cpu_dest(s3)) - dest_dat = 0xffffffff; - else { - READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); - } + READ(s3->accel.dest + s3->accel.cx, dest_dat); MIX - if (s3_cpu_dest(s3)) { - for (i = 0; i <= s3->bpp; i++) - s3->accel.pix_trans[read + i] = (src_dat >> (i << 3)) & 0xff; - /* Yes, src_dat is correct, there is no mixing/ROP's done on PIX_TRANS reads. */ - } else - WRITE(s3->accel.dest + s3->accel.cx); + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.cx, dest_dat); + } } } - if (s3_cpu_dest(s3)) { - read += (s3->bpp + 1); - if (read >= byte_cnt) - s3->data_available = 1; /* Read data available. */ + if (s3->accel.b2e8_pix && s3_cpu_src(s3)) { + if (s3->accel.temp_cnt > 0) { + s3->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + } else { + mix_dat <<= 1; + mix_dat |= 1; } - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - - if (s3->accel.cmd & 0x20) s3->accel.cx++; - else s3->accel.cx--; + if (s3->bpp == 0 && !s3->color_16bit) + cpu_dat >>= 8; + else { + cpu_dat >>= 16; + } + + if (s3->accel.cmd & 0x20) + s3->accel.cx++; + else + s3->accel.cx--; + s3->accel.sx--; if (s3->accel.sx < 0) { - if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + if (s3->accel.cmd & 0x20) + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - if (s3->accel.cmd & 0x80) s3->accel.cy++; - else s3->accel.cy--; - - s3->accel.dest = s3->accel.cy * s3->width; + if (s3->accel.cmd & 0x80) + s3->accel.cy++; + else + s3->accel.cy--; + + s3->accel.dest = dstbase + s3->accel.cy * s3->width; s3->accel.sy--; - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) { - if (s3_cpu_dest(s3)) - s3->data_available = 1; + if (cpu_input) { + if (s3->accel.b2e8_pix) { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } return; } - if (s3->accel.sy < 0) - { + if (s3->accel.sy < 0) { s3->accel.cur_x = s3->accel.cx; s3->accel.cur_y = s3->accel.cy; - if (s3_cpu_dest(s3)) - s3->data_available = 1; return; } } - - if (s3_cpu_dest(s3) && s3->data_available) - return; } break; + + case 3: /*Polygon Fill Solid (Vision868/968 and Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64 && s3->chip != S3_VISION968 && s3->chip != S3_VISION868) + break; + + polygon_setup(s3); + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.dest = dstbase + y * s3->width; + + while (x_count-- && count--) + { + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) + { + switch (frgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; /*Not supported?*/ break; + } + + if (((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2)) + { + READ(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.poly_x, dest_dat); + } + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + + case 6: /*BitBlt*/ if (!cpu_input) /*!cpu_input is trigger to start operation*/ { @@ -2714,48 +5772,67 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy = s3->accel.desty_axstp & 0xfff; if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; - s3->accel.cx = s3->accel.cur_x & 0xfff; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; - s3->accel.cy = s3->accel.cur_y & 0xfff; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + s3->accel.cx = s3->accel.cur_x; + s3->accel.cy = s3->accel.cur_y; - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + if (s3->accel.destx_distp >= 0xfffff000) { /* avoid overflow */ + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.cur_x_bit12) { + if (s3->accel.cx <= 0x7ff) { + s3->accel.cx = s3->accel.cur_x_bitres & 0xfff; + } else { + s3->accel.cx |= ~0xfff; + } + } + if (s3->accel.cur_y_bitres > 0xfff) + s3->accel.cy = s3->accel.cur_y_bitres; + } else { + if (s3->accel.cur_x_bit12) { + if (s3->accel.cx <= 0x7ff) { /* overlap x */ + s3->accel.cx = s3->accel.cur_x_bitres & 0xfff; + } else { /* x end is negative */ + s3->accel.cx |= ~0xfff; + } + } + if (s3->accel.cur_y_bit12) { + if (s3->accel.cy <= 0x7ff) { /* overlap y */ + s3->accel.cy = s3->accel.cur_y_bitres & 0xfff; + } else { /* y end is negative */ + s3->accel.cy |= ~0xfff; + } + } + } + + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; } - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + if ((s3->accel.cmd & 0x100) && !cpu_input) { return; /*Wait for data from CPU*/ - } - - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - - if (s3->accel.sy < 0) - return; + } frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7 && - (s3->accel.bkgd_mix & 0xf) == 7) + (s3->accel.bkgd_mix & 0xf) == 7) { while (1) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + if (((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b)) { - READ_SRC(s3->accel.src + s3->accel.cx, src_dat); - READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + READ(s3->accel.src + s3->accel.cx, src_dat); + READ(s3->accel.dest + s3->accel.dx, dest_dat); dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask); - WRITE(s3->accel.dest + s3->accel.dx); + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.dx, dest_dat); + } } - + s3->accel.cx++; s3->accel.dx++; s3->accel.sx--; @@ -2764,32 +5841,33 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - + s3->accel.cy++; s3->accel.dy++; - - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; - + + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; + s3->accel.sy--; - - if (s3->accel.sy < 0) - { + + if (s3->accel.sy < 0) { return; } } } } else - { + { while (count-- && s3->accel.sy >= 0) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + /*This is almost required by OS/2's software cursor or we will risk writing/reading garbage around it.*/ + if ((s3->accel.dx) >= clip_l && (s3->accel.dx) <= clip_r && + ((s3->accel.dy) >= clip_t && (s3->accel.dy) <= clip_b)) { - if (vram_mask) + if (vram_mask && (s3->accel.cmd & 0x10)) { - READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + READ(s3->accel.src + s3->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -2797,25 +5875,34 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 0: src_dat = s3->accel.bkgd_color; break; case 1: src_dat = s3->accel.frgd_color; break; case 2: src_dat = cpu_dat; break; - case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); + if (vram_mask && (s3->accel.cmd & 0x10)) + src_dat = ((src_dat & rd_mask) == rd_mask); + break; } - if ((compare_mode == 2 && src_dat != compare) || - (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) + if ((((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2))) { - READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + READ(s3->accel.dest + s3->accel.dx, dest_dat); MIX - WRITE(s3->accel.dest + s3->accel.dx); + if ((!(s3->accel.cmd & 0x10) && vram_mask) || (s3->accel.cmd & 0x10)) { + WRITE(s3->accel.dest + s3->accel.dx, dest_dat); + } } } mix_dat <<= 1; mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; + + if (s3->bpp == 0 && !s3->color_16bit) + cpu_dat >>= 8; + else { + cpu_dat >>= 16; + } if (s3->accel.cmd & 0x20) { @@ -2840,6 +5927,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; if (s3->accel.cmd & 0x80) @@ -2853,14 +5941,16 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy--; } - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; - if (s3->accel.sy < 0) - { + if (cpu_input) { + return; + } + + if (s3->accel.sy < 0) { return; } } @@ -2880,41 +5970,36 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; s3->accel.cx = s3->accel.cur_x & 0xfff; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + if (s3->accel.cur_x_bit12) s3->accel.cx |= ~0xfff; s3->accel.cy = s3->accel.cur_y & 0xfff; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - + if (s3->accel.cur_y_bit12) s3->accel.cy |= ~0xfff; + /*Align source with destination*/ s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; - s3->accel.dest = s3->accel.dy * s3->width; - + s3->accel.dest = dstbase + s3->accel.dy * s3->width; + s3->accel.cx = s3->accel.dx & 7; s3->accel.cy = s3->accel.dy & 7; - - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + + s3->accel.src = srcbase + s3->accel.pattern + (s3->accel.cy * s3->width); } - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + if ((s3->accel.cmd & 0x100) && !cpu_input) { return; /*Wait for data from CPU*/ - } - - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + } frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; while (count-- && s3->accel.sy >= 0) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { if (vram_mask) { - READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + READ(s3->accel.src + s3->accel.cx, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -2922,18 +6007,23 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 0: src_dat = s3->accel.bkgd_color; break; case 1: src_dat = s3->accel.frgd_color; break; case 2: src_dat = cpu_dat; break; - case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); + if (vram_mask) + src_dat = ((src_dat & rd_mask) == rd_mask); + break; } - if ((compare_mode == 2 && src_dat != compare) || + if (((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) + compare_mode < 2)) { - READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + READ(s3->accel.dest + s3->accel.dx, dest_dat); MIX - WRITE(s3->accel.dest + s3->accel.dx); + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.dx, dest_dat); + } } } @@ -2978,143 +6068,160 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy--; } - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; - if (s3->accel.sy < 0) + if (cpu_input) { return; + } + if (s3->accel.sy < 0) { + return; + } } } break; - case 3: /*Polygon Fill Solid (Trio64 only)*/ - { - int end_y1, end_y2; - - if (s3->chip != S3_TRIO64) + case 9: /*Polyline/2-Point Line (Vision868/968 and Trio64 only)*/ + { + int error; + + if (s3->chip != S3_TRIO64 && s3->chip != S3_VISION968 && s3->chip != S3_VISION868) break; - polygon_setup(s3); + if (!cpu_input) { + s3->accel.dx = ABS(s3->accel.destx_distp - s3->accel.cur_x); + if (s3->accel.destx_distp & 0x1000) + s3->accel.dx |= ~0xfff; + s3->accel.dy = ABS(s3->accel.desty_axstp - s3->accel.cur_y); + if (s3->accel.desty_axstp & 0x1000) + s3->accel.dy |= ~0xfff; - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x_bit12) + s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y_bit12) + s3->accel.cy |= ~0xfff; + } if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - - end_y1 = s3->accel.desty_axstp; - end_y2 = s3->accel.desty_axstp2; - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - - while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) - { - int y = s3->accel.poly_cy; - int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; - - s3->accel.dest = y * s3->width; - - while (x_count-- && count--) - { - if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && - s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + if (s3->accel.dx > s3->accel.dy) { + error = s3->accel.dx / 2; + while (s3->accel.cx != s3->accel.destx_distp && count--) { + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { - switch (frgd_mix) - { - case 0: src_dat = s3->accel.bkgd_color; break; - case 1: src_dat = s3->accel.frgd_color; break; - case 2: src_dat = cpu_dat; break; - case 3: src_dat = 0; /*Nor supported?*/ break; - } + src_dat = s3->accel.frgd_color; - if ((compare_mode == 2 && src_dat != compare) || + if (((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) + compare_mode < 2) && (s3->accel.cmd & 0x10)) { - READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); - + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + MIX - WRITE(s3->accel.dest + s3->accel.poly_x); + if (s3->accel.cmd & 0x10) { + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + } } } - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) - s3->accel.poly_x++; + error -= s3->accel.dy; + if (error < 0) { + error += s3->accel.dx; + if (s3->accel.desty_axstp > s3->accel.cur_y) + s3->accel.cy++; + else + s3->accel.cy--; + } + + if (s3->accel.destx_distp > s3->accel.cur_x) + s3->accel.cx++; else - s3->accel.poly_x--; + s3->accel.cx--; + } + } else { + error = s3->accel.dy / 2; + while (s3->accel.cy != s3->accel.desty_axstp && count--) { + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) + { + src_dat = s3->accel.frgd_color; + + if (((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2)) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + if (s3->accel.cmd & 0x10) { + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + } + } + } + + error -= s3->accel.dx; + if (error < 0) { + error += s3->accel.dy; + if (s3->accel.destx_distp > s3->accel.cur_x) + s3->accel.cx++; + else + s3->accel.cx--; + } + if (s3->accel.desty_axstp > s3->accel.cur_y) + s3->accel.cy++; + else + s3->accel.cy--; + } - - s3->accel.poly_cx += s3->accel.poly_dx1; - s3->accel.poly_cx2 += s3->accel.poly_dx2; - s3->accel.poly_x = s3->accel.poly_cx >> 20; - - s3->accel.poly_cy++; - s3->accel.poly_cy2++; - - if (!count) - break; } - - s3->accel.cur_x = s3->accel.poly_cx & 0xfff; - s3->accel.cur_y = s3->accel.poly_cy & 0xfff; - s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; - s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; } break; - case 11: /*Polygon Fill Pattern (Trio64 only)*/ - { + + case 11: /*Polygon Fill Pattern (Vision868/968 and Trio64 only)*/ + { int end_y1, end_y2; - - if (s3->chip != S3_TRIO64) + + if (s3->chip != S3_TRIO64 && s3->chip != S3_VISION968 && s3->chip != S3_VISION868) break; polygon_setup(s3); - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - + end_y1 = s3->accel.desty_axstp; end_y2 = s3->accel.desty_axstp2; frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) { int y = s3->accel.poly_cy; int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; - s3->accel.src = s3->accel.pattern + ((y & 7) * s3->width); - s3->accel.dest = y * s3->width; - + s3->accel.src = srcbase + s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = dstbase + y * s3->width; + while (x_count-- && count--) { int pat_x = s3->accel.poly_x & 7; - - if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && - s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) { - if (vram_mask) - { - READ_SRC(s3->accel.src + pat_x, mix_dat) + if (vram_mask) { + READ(s3->accel.src + pat_x, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -3122,18 +6229,23 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 0: src_dat = s3->accel.bkgd_color; break; case 1: src_dat = s3->accel.frgd_color; break; case 2: src_dat = cpu_dat; break; - case 3: READ_SRC(s3->accel.src + pat_x, src_dat); break; + case 3: READ(s3->accel.src + pat_x, src_dat); + if (vram_mask) + src_dat = ((src_dat & rd_mask) == rd_mask); + break; } - if ((compare_mode == 2 && src_dat != compare) || + if (((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) + compare_mode < 2)) { - READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); - + READ(s3->accel.dest + s3->accel.poly_x, dest_dat); + MIX - WRITE(s3->accel.dest + s3->accel.poly_x); + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.poly_x, dest_dat); + } } } if (s3->bpp == 0) cpu_dat >>= 8; @@ -3147,95 +6259,290 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat else s3->accel.poly_x--; } - + s3->accel.poly_cx += s3->accel.poly_dx1; s3->accel.poly_cx2 += s3->accel.poly_dx2; s3->accel.poly_x = s3->accel.poly_cx >> 20; - + s3->accel.poly_cy++; s3->accel.poly_cy2++; - + if (!count) break; } - + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; s3->accel.cur_y = s3->accel.poly_cy & 0xfff; s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; } break; + + case 14: /*ROPBlt (Vision868/968 only)*/ + if (s3->chip != S3_VISION968 && s3->chip != S3_VISION868) + break; + + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x_bit12) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y_bit12) s3->accel.cy |= ~0xfff; + + s3->accel.px = s3->accel.pat_x & 0xfff; + if (s3->accel.pat_x & 0x1000) s3->accel.px |= ~0xfff; + s3->accel.py = s3->accel.pat_y & 0xfff; + if (s3->accel.pat_y & 0x1000) s3->accel.py |= ~0xfff; + + s3->accel.dest = dstbase + (s3->accel.dy * s3->width); + s3->accel.src = srcbase + (s3->accel.cy * s3->width); + s3->accel.pattern = (s3->accel.py * s3->width); + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if (s3->accel.ropmix & 0x100) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: pat_dat = s3->accel.pat_bg_color; break; + case 1: pat_dat = s3->accel.pat_fg_color; break; + case 2: pat_dat = cpu_dat; break; + case 3: READ(s3->accel.pattern + s3->accel.px, pat_dat); break; + } + } else { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: pat_dat = s3->accel.bkgd_color; break; + case 1: pat_dat = s3->accel.frgd_color; break; + case 2: pat_dat = cpu_dat; break; + case 3: READ(s3->accel.pattern + s3->accel.px, pat_dat); break; + } + } + + if (((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2)) + { + READ(s3->accel.dest + s3->accel.dx, dest_dat); + + ROPMIX + + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.dx, out); + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + s3->accel.px++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + s3->accel.px--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.px -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.px += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + s3->accel.py++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + s3->accel.py--; + } + + s3->accel.src = srcbase + (s3->accel.cy * s3->width); + s3->accel.dest = dstbase + (s3->accel.dy * s3->width); + s3->accel.pattern = (s3->accel.py * s3->width); + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) { + return; + } + } + } + break; } } -uint8_t s3_pci_read(int func, int addr, void *p) +static uint8_t +s3_pci_read(int func, int addr, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; + switch (addr) { case 0x00: return 0x33; /*'S3'*/ case 0x01: return 0x53; - - case 0x02: return s3->id_ext_pci; - case 0x03: return 0x88; - - case PCI_REG_COMMAND: - return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ - case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ - - case 0x08: return 0; /*Revision ID*/ + case 0x02: return s3->id_ext_pci; + case 0x03: return (s3->chip == S3_TRIO64V2) ? 0x89 : 0x88; + + case PCI_REG_COMMAND: + if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) + return s3->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ + else + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + break; + + case 0x07: return (s3->chip == S3_TRIO64V2) ? (s3->pci_regs[0x07] & 0x36) : (1 << 1); /*Medium DEVSEL timing*/ + + case 0x08: return (s3->chip == S3_TRIO64V) ? 0x40 : 0; /*Revision ID*/ case 0x09: return 0; /*Programming interface*/ - + case 0x0a: - if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64)) + if (s3->chip >= S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) return 0x00; /*Supports VGA interface*/ else return 0x01; + break; case 0x0b: - if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64)) + if (s3->chip >= S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) return 0x03; else return 0x00; - + break; + + case 0x0d: return (s3->chip == S3_TRIO64V2) ? (s3->pci_regs[0x0d] & 0xf8) : 0x00; break; + case 0x10: return 0x00; /*Linear frame buffer address*/ case 0x11: return 0x00; - case 0x12: return svga->crtc[0x5a] & 0x80; - case 0x13: return svga->crtc[0x59]; + case 0x12: + if (svga->crtc[0x53] & 0x08) + return 0x00; + else + return (svga->crtc[0x5a] & 0x80); + break; + + case 0x13: + if (svga->crtc[0x53] & 0x08) { + return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : (svga->crtc[0x59] & 0xfe); + } else { + return svga->crtc[0x59]; + } + break; case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ case 0x31: return 0x00; case 0x32: return s3->has_bios ? s3->pci_regs[0x32] : 0x00; case 0x33: return s3->has_bios ? s3->pci_regs[0x33] : 0x00; - + case 0x3c: return s3->int_line; case 0x3d: return PCI_INTA; + + case 0x3e: return (s3->chip == S3_TRIO64V2) ? 0x04 : 0x00; break; + case 0x3f: return (s3->chip == S3_TRIO64V2) ? 0xff : 0x00; break; } return 0; } -void s3_pci_write(int func, int addr, uint8_t val, void *p) +static void +s3_pci_write(int func, int addr, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + if (s3->chip == S3_TRIO64V2) + return; + break; + case PCI_REG_COMMAND: - s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; if (val & PCI_COMMAND_IO) s3_io_set(s3); else s3_io_remove(s3); + s3->pci_regs[PCI_REG_COMMAND] = (val & 0x23); s3_updatemapping(s3); break; - + + case 0x07: + if (s3->chip == S3_TRIO64V2) { + s3->pci_regs[0x07] = val & 0x3e; + return; + } + break; + + case 0x0d: + if (s3->chip == S3_TRIO64V2) { + s3->pci_regs[0x0d] = val & 0xf8; + return; + } + break; + case 0x12: - svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); - s3_updatemapping(s3); + if (!(svga->crtc[0x53] & 0x08)) { + svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); + s3_updatemapping(s3); + } break; + case 0x13: - svga->crtc[0x59] = val; + if (svga->crtc[0x53] & 0x08) { + svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : (val & 0xfe); + } else { + svga->crtc[0x59] = val; + } s3_updatemapping(s3); break; @@ -3245,21 +6552,72 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) s3->pci_regs[addr] = val; if (s3->pci_regs[0x30] & 0x01) { - uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); - mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); + uint32_t biosaddr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); + mem_mapping_set_addr(&s3->bios_rom.mapping, biosaddr, 0x8000); } else { mem_mapping_disable(&s3->bios_rom.mapping); } return; - + case 0x3c: s3->int_line = val; return; } } +static void +fifo_thread(void *param) +{ + s3_t *s3 = (s3_t *)param; + uint64_t start_time, end_time; + + while (s3->fifo_thread_run) { + thread_set_event(s3->fifo_not_full_event); + thread_wait_event(s3->wake_fifo_thread, -1); + thread_reset_event(s3->wake_fifo_thread); + s3->blitter_busy = 1; + while (!FIFO_EMPTY) { + start_time = plat_timer_read(); + fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) { + case FIFO_WRITE_BYTE: + s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_BYTE: + s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_WORD: + s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_DWORD: + s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + s3->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(s3->fifo_not_full_event); + + end_time = plat_timer_read(); + s3->blitter_time += (end_time - start_time); + } + s3->blitter_busy = 0; + s3->subsys_stat |= INT_FIFO_EMP; + s3_update_irqs(s3); + } +} + static int vram_sizes[] = { 7, /*512 kB*/ @@ -3268,14 +6626,157 @@ static int vram_sizes[] = 0, 0, /*4 MB*/ 0, - 0, + 0, /*6 MB*/ 0, 3 /*8 MB*/ }; +static void s3_reset(void *priv) +{ + s3_t *s3 = (s3_t *) priv; + svga_t *svga = &s3->svga; + + memset(svga->crtc, 0x00, sizeof(svga->crtc)); + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = 1000ull << 32; + svga->dispofftime = 1000ull << 32; + svga->bpp = 8; + + if (s3->pci) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4); + else if (s3->vlb) + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4); + else + svga->crtc[0x36] = 3 | (1 << 4); + + if (s3->chip >= S3_86C928) + svga->crtc[0x36] |= (vram_sizes[s3->vram] << 5); + else + svga->crtc[0x36] |= ((s3->vram == 1) ? 0x00 : 0x20) | 0x80; + + svga->crtc[0x37] = 1 | (7 << 5); + + if (s3->chip >= S3_86C928) + svga->crtc[0x37] |= 0x04; + + s3_io_set(s3); + + memset(s3->pci_regs, 0x00, 256); + + s3->pci_regs[PCI_REG_COMMAND] = 7; + + s3->pci_regs[0x30] = 0x00; + s3->pci_regs[0x32] = 0x0c; + s3->pci_regs[0x33] = 0x00; + + switch(s3->card_type) { + case S3_MIROCRYSTAL8S_805: + case S3_MIROCRYSTAL10SD_805: + svga->crtc[0x5a] = 0x0a; + svga->getclock = sdac_getclock; + break; + + case S3_SPEA_MIRAGE_86C801: + case S3_SPEA_MIRAGE_86C805: + svga->crtc[0x5a] = 0x0a; + break; + + case S3_PHOENIX_86C801: + case S3_PHOENIX_86C805: + svga->crtc[0x5a] = 0x0a; + break; + + case S3_METHEUS_86C928: + case S3_SPEA_MERCURY_LITE_PCI: + svga->crtc[0x5a] = 0x0a; + break; + + case S3_PARADISE_BAHAMAS64: + case S3_PHOENIX_VISION864: + case S3_MIROCRYSTAL20SD_864: + svga->crtc[0x5a] = 0x0a; + break; + + case S3_DIAMOND_STEALTH64_964: + case S3_ELSAWIN2KPROX_964: + case S3_MIROCRYSTAL20SV_964: + svga->crtc[0x5a] = 0x0a; + break; + + case S3_ELSAWIN2KPROX: + case S3_SPEA_MERCURY_P64V: + case S3_MIROVIDEO40SV_ERGO_968: + case S3_NUMBER9_9FX_771: + case S3_PHOENIX_VISION968: + if (s3->pci) { + svga->crtc[0x53] = 0x18; + svga->crtc[0x58] = 0x10; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + } else { + svga->crtc[0x53] = 0x00; + svga->crtc[0x59] = 0x00; + svga->crtc[0x5a] = 0x0a; + } + break; + + case S3_NUMBER9_9FX_531: + case S3_PHOENIX_VISION868: + if (s3->pci) { + svga->crtc[0x53] = 0x18; + svga->crtc[0x58] = 0x10; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + } else { + svga->crtc[0x53] = 0x00; + svga->crtc[0x59] = 0x00; + svga->crtc[0x5a] = 0x0a; + } + break; + + case S3_PHOENIX_TRIO64: + case S3_PHOENIX_TRIO64_ONBOARD: + case S3_PHOENIX_TRIO64VPLUS: + case S3_PHOENIX_TRIO64VPLUS_ONBOARD: + case S3_DIAMOND_STEALTH64_764: + case S3_SPEA_MIRAGE_P64: + case S3_NUMBER9_9FX: + if (s3->card_type == S3_PHOENIX_TRIO64VPLUS || s3->card_type == S3_PHOENIX_TRIO64VPLUS_ONBOARD) + svga->crtc[0x53] = 0x08; + break; + + case S3_TRIO64V2_DX: + svga->crtc[0x53] = 0x08; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + s3->pci_regs[0x05] = 0; + s3->pci_regs[0x06] = 0; + s3->pci_regs[0x07] = 2; + s3->pci_regs[0x3d] = 1; + s3->pci_regs[0x3e] = 4; + s3->pci_regs[0x3f] = 0xff; + break; + } + + if (s3->has_bios) { + if (s3->pci) + mem_mapping_disable(&s3->bios_rom.mapping); + } + + s3_updatemapping(s3); + + mem_mapping_disable(&s3->mmio_mapping); + mem_mapping_disable(&s3->new_mmio_mapping); +} + + static void *s3_init(const device_t *info) { - const wchar_t *bios_fn; + const char *bios_fn; int chip, stepping; s3_t *s3 = malloc(sizeof(s3_t)); svga_t *svga = &s3->svga; @@ -3287,14 +6788,49 @@ static void *s3_init(const device_t *info) bios_fn = ROM_ORCHID_86C911; chip = S3_86C911; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c911); - break; - case S3_V7MIRAGE_86C801: - bios_fn = ROM_V7MIRAGE_86C801; + break; + case S3_DIAMOND_STEALTH_VRAM: + bios_fn = ROM_DIAMOND_STEALTH_VRAM; + chip = S3_86C911; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c911); + break; + case S3_AMI_86C924: + bios_fn = ROM_AMI_86C924; + chip = S3_86C924; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c911); + break; + case S3_SPEA_MIRAGE_86C801: + bios_fn = ROM_SPEA_MIRAGE_86C801; + chip = S3_86C801; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); + break; + case S3_86C805_ONBOARD: + bios_fn = NULL; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; + case S3_SPEA_MIRAGE_86C805: + bios_fn = ROM_SPEA_MIRAGE_86C805; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; + case S3_MIROCRYSTAL8S_805: + bios_fn = ROM_MIROCRYSTAL8S_805; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; + case S3_MIROCRYSTAL10SD_805: + bios_fn = ROM_MIROCRYSTAL10SD_805; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; + case S3_PHOENIX_86C801: + bios_fn = ROM_PHOENIX_86C80X; chip = S3_86C801; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); break; case S3_PHOENIX_86C805: - bios_fn = ROM_PHOENIX_86C805; + bios_fn = ROM_PHOENIX_86C80X; chip = S3_86C805; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); break; @@ -3306,6 +6842,16 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); break; + case S3_SPEA_MERCURY_LITE_PCI: + bios_fn = ROM_SPEA_MERCURY_LITE_PCI; + chip = S3_86C928PCI; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c928pci); + break; + case S3_MIROCRYSTAL20SD_864: + bios_fn = ROM_MIROCRYSTAL20SD_864_VLB; + chip = S3_VISION864; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision864_vlb); + break; case S3_PARADISE_BAHAMAS64: bios_fn = ROM_PARADISE_BAHAMAS64; chip = S3_VISION864; @@ -3322,6 +6868,19 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision864_vlb); break; + case S3_NUMBER9_9FX_531: + bios_fn = ROM_NUMBER9_9FX_531; + chip = S3_VISION868; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision868_pci); + break; + case S3_PHOENIX_VISION868: + bios_fn = ROM_PHOENIX_VISION868; + chip = S3_VISION868; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision868_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision868_vlb); + break; case S3_DIAMOND_STEALTH64_964: bios_fn = ROM_DIAMOND_STEALTH64_964; chip = S3_VISION964; @@ -3330,6 +6889,49 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_vlb); break; + case S3_MIROCRYSTAL20SV_964: + chip = S3_VISION964; + if (info->flags & DEVICE_PCI) { + bios_fn = ROM_MIROCRYSTAL20SV_964_PCI; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_pci); + } else { + bios_fn = ROM_MIROCRYSTAL20SV_964_VLB; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_vlb); + } + break; + case S3_MIROVIDEO40SV_ERGO_968: + bios_fn = ROM_MIROVIDEO40SV_ERGO_968_PCI; + chip = S3_VISION968; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_pci); + break; + case S3_NUMBER9_9FX_771: + bios_fn = ROM_NUMBER9_9FX_771; + chip = S3_VISION968; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_pci); + break; + case S3_PHOENIX_VISION968: + bios_fn = ROM_PHOENIX_VISION968; + chip = S3_VISION968; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_vlb); + break; + case S3_ELSAWIN2KPROX_964: + bios_fn = ROM_ELSAWIN2KPROX_964; + chip = S3_VISION964; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_pci); + break; + case S3_ELSAWIN2KPROX: + bios_fn = ROM_ELSAWIN2KPROX; + chip = S3_VISION968; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_pci); + break; + case S3_SPEA_MERCURY_P64V: + bios_fn = ROM_SPEA_MERCURY_P64V; + chip = S3_VISION968; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_pci); + break; case S3_PHOENIX_TRIO32: bios_fn = ROM_PHOENIX_TRIO32; chip = S3_TRIO32; @@ -3338,6 +6940,14 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_vlb); break; + case S3_DIAMOND_STEALTH_SE: + bios_fn = ROM_DIAMOND_STEALTH_SE; + chip = S3_TRIO32; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_vlb); + break; case S3_PHOENIX_TRIO64: bios_fn = ROM_PHOENIX_TRIO64; chip = S3_TRIO64; @@ -3346,6 +6956,11 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_vlb); break; + case S3_SPEA_MIRAGE_P64: + bios_fn = ROM_SPEA_MIRAGE_P64; + chip = S3_TRIO64; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_vlb); + break; case S3_PHOENIX_TRIO64_ONBOARD: bios_fn = NULL; chip = S3_TRIO64; @@ -3354,6 +6969,22 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_vlb); break; + case S3_PHOENIX_TRIO64VPLUS: + bios_fn = ROM_PHOENIX_TRIO64VPLUS; + chip = S3_TRIO64V; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_vlb); + break; + case S3_PHOENIX_TRIO64VPLUS_ONBOARD: + bios_fn = NULL; + chip = S3_TRIO64V; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_vlb); + break; case S3_DIAMOND_STEALTH64_764: bios_fn = ROM_DIAMOND_STEALTH64_764; chip = S3_TRIO64; @@ -3370,6 +7001,16 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_vlb); break; + case S3_TRIO64V2_DX: + bios_fn = ROM_TRIO64V2_DX_VBE20; + chip = S3_TRIO64V2; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_pci); + break; + case S3_TRIO64V2_DX_ONBOARD: + bios_fn = NULL; + chip = S3_TRIO64V2; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64_pci); + break; default: free(s3); return NULL; @@ -3378,16 +7019,17 @@ static void *s3_init(const device_t *info) memset(s3, 0, sizeof(s3_t)); vram = device_get_config_int("memory"); - + if (vram) vram_size = vram << 20; else vram_size = 512 << 10; s3->vram_mask = vram_size - 1; + s3->vram = vram; s3->has_bios = (bios_fn != NULL); if (s3->has_bios) { - rom_init(&s3->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&s3->bios_rom, (char *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (info->flags & DEVICE_PCI) mem_mapping_disable(&s3->bios_rom.mapping); } @@ -3395,44 +7037,61 @@ static void *s3_init(const device_t *info) s3->pci = !!(info->flags & DEVICE_PCI); s3->vlb = !!(info->flags & DEVICE_VLB); - if (s3->pci || s3->vlb) { - mem_mapping_add(&s3->linear_mapping, 0, 0, - svga_read_linear, svga_readw_linear, svga_readl_linear, - svga_write_linear, svga_writew_linear, svga_writel_linear, - NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + mem_mapping_add(&s3->linear_mapping, 0, 0, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear, + NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + /*It's hardcoded to 0xa0000 before the Trio64V+ and expects so*/ + if (chip >= S3_TRIO64V) + mem_mapping_add(&s3->mmio_mapping, 0, 0, + s3_accel_read, s3_accel_read_w, s3_accel_read_l, + s3_accel_write, s3_accel_write_w, s3_accel_write_l, + NULL, MEM_MAPPING_EXTERNAL, s3); + else mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, s3_accel_read_w, s3_accel_read_l, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); - } else { - mem_mapping_add(&s3->linear_mapping, 0, 0, - svga_read_linear, svga_readw_linear, NULL, - svga_write_linear, svga_writew_linear, NULL, - NULL, MEM_MAPPING_EXTERNAL, &s3->svga); - mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, - s3_accel_read, s3_accel_read_w, NULL, - s3_accel_write, s3_accel_write_w, NULL, - NULL, MEM_MAPPING_EXTERNAL, s3); - } + mem_mapping_add(&s3->new_mmio_mapping, 0, 0, + s3_accel_read, s3_accel_read_w, s3_accel_read_l, + s3_accel_write, s3_accel_write_w, s3_accel_write_l, + NULL, MEM_MAPPING_EXTERNAL, s3); mem_mapping_disable(&s3->mmio_mapping); - - if (chip == S3_VISION964) + mem_mapping_disable(&s3->new_mmio_mapping); + + if (chip == S3_VISION964 || chip == S3_VISION968) svga_init(info, &s3->svga, s3, vram_size, s3_recalctimings, s3_in, s3_out, NULL, NULL); - else - svga_init(info, &s3->svga, s3, vram_size, - s3_recalctimings, - s3_in, s3_out, - s3_hwcursor_draw, - NULL); + else { + if (chip >= S3_TRIO64V) { + svga_init(info, svga, s3, vram_size, + s3_trio64v_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + s3_trio64v_overlay_draw); + } else { + svga_init(info, svga, s3, vram_size, + s3_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + NULL); + } + } - if (chip == S3_VISION964) + svga->hwcursor.cur_ysize = 64; + + if (chip == S3_VISION964 && info->local != S3_ELSAWIN2KPROX_964) svga->dac_hwcursor_draw = bt48x_hwcursor_draw; + else if ((chip == S3_VISION964 && info->local == S3_ELSAWIN2KPROX_964) || (chip == S3_VISION968 && (info->local == S3_ELSAWIN2KPROX || + info->local == S3_PHOENIX_VISION968 || info->local == S3_NUMBER9_9FX_771))) + svga->dac_hwcursor_draw = ibm_rgb528_hwcursor_draw; + else if (chip == S3_VISION968 && (info->local == S3_SPEA_MERCURY_P64V || info->local == S3_MIROVIDEO40SV_ERGO_968)) + svga->dac_hwcursor_draw = tvp3026_hwcursor_draw; - if (s3->chip >= S3_VISION864) { + if (chip >= S3_VISION964) { switch (vram) { case 0: /* 512 kB */ svga->vram_mask = (1 << 19) - 1; @@ -3463,22 +7122,30 @@ static void *s3_init(const device_t *info) } } - if (info->flags & DEVICE_PCI) - svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); - else if (info->flags & DEVICE_VLB) - svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + if (s3->pci) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4); + else if (s3->vlb) + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4); else - svga->crtc[0x36] = 3 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + svga->crtc[0x36] = 3 | (1 << 4); + + if (chip >= S3_86C928) + svga->crtc[0x36] |= (vram_sizes[vram] << 5); + else { + svga->crtc[0x36] |= ((vram == 1) ? 0x00 : 0x20) | 0x98; + svga->crtc[0x41] = (vram == 1) ? 0x10 : 0x00; + } + svga->crtc[0x37] = 1 | (7 << 5); + if (chip >= S3_86C928) + svga->crtc[0x37] |= 0x04; + svga->vblank_start = s3_vblank_start; s3_io_set(s3); - if (info->flags & DEVICE_PCI) - s3->card = pci_add_card(PCI_ADD_VIDEO, s3_pci_read, s3_pci_write, s3); - - s3->pci_regs[0x04] = 7; + s3->pci_regs[PCI_REG_COMMAND] = 7; s3->pci_regs[0x30] = 0x00; s3->pci_regs[0x32] = 0x0c; @@ -3486,14 +7153,15 @@ static void *s3_init(const device_t *info) s3->chip = chip; - s3->wake_fifo_thread = thread_create_event(); - s3->fifo_not_full_event = thread_create_event(); - s3->fifo_thread = thread_create(fifo_thread, s3); - s3->int_line = 0; - switch(info->local) { + s3->card_type = info->local; + + svga->force_old_addr = 1; + + switch(s3->card_type) { case S3_ORCHID_86C911: + case S3_DIAMOND_STEALTH_VRAM: svga->decode_mask = (1 << 20) - 1; stepping = 0x81; /*86C911*/ s3->id = stepping; @@ -3501,13 +7169,28 @@ static void *s3_init(const device_t *info) s3->id_ext_pci = 0; s3->packed_mmio = 0; s3->width = 1024; - - svga->ramdac = device_add(&att490_ramdac_device); + + svga->ramdac = device_add(&sc11483_ramdac_device); svga->clock_gen = device_add(&av9194_device); svga->getclock = av9194_getclock; break; - - case S3_V7MIRAGE_86C801: + + case S3_AMI_86C924: + svga->decode_mask = (1 << 20) - 1; + stepping = 0x82; /*86C911A/86C924*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + s3->width = 1024; + + svga->ramdac = device_add(&sc11487_ramdac_device); + svga->clock_gen = device_add(&ics2494an_305_device); + svga->getclock = ics2494_getclock; + break; + + case S3_MIROCRYSTAL8S_805: + case S3_MIROCRYSTAL10SD_805: svga->decode_mask = (2 << 20) - 1; stepping = 0xa0; /*86C801/86C805*/ s3->id = stepping; @@ -3515,12 +7198,42 @@ static void *s3_init(const device_t *info) s3->id_ext_pci = 0; s3->packed_mmio = 0; svga->crtc[0x5a] = 0x0a; - + + svga->ramdac = device_add(&gendac_ramdac_device); + svga->clock_gen = svga->ramdac; + svga->getclock = sdac_getclock; + break; + + case S3_SPEA_MIRAGE_86C801: + case S3_SPEA_MIRAGE_86C805: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + svga->ramdac = device_add(&att490_ramdac_device); svga->clock_gen = device_add(&av9194_device); svga->getclock = av9194_getclock; break; + case S3_86C805_ONBOARD: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att490_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + + case S3_PHOENIX_86C801: case S3_PHOENIX_86C805: svga->decode_mask = (2 << 20) - 1; stepping = 0xa0; /*86C801/86C805*/ @@ -3529,56 +7242,139 @@ static void *s3_init(const device_t *info) s3->id_ext_pci = 0; s3->packed_mmio = 0; svga->crtc[0x5a] = 0x0a; - + svga->ramdac = device_add(&att492_ramdac_device); svga->clock_gen = device_add(&av9194_device); svga->getclock = av9194_getclock; break; - + case S3_METHEUS_86C928: svga->decode_mask = (4 << 20) - 1; - stepping = 0x90; /*86C928*/ + stepping = 0x91; /*86C928*/ s3->id = stepping; s3->id_ext = stepping; s3->id_ext_pci = 0; s3->packed_mmio = 0; svga->crtc[0x5a] = 0x0a; - svga->ramdac = device_add(&bt485_ramdac_device); svga->clock_gen = device_add(&icd2061_device); svga->getclock = icd2061_getclock; - break; - + break; + + case S3_SPEA_MERCURY_LITE_PCI: + svga->decode_mask = (4 << 20) - 1; + stepping = 0xb0; /*86C928PCI*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = stepping; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + svga->ramdac = device_add(&sc1502x_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + case S3_PARADISE_BAHAMAS64: case S3_PHOENIX_VISION864: + case S3_MIROCRYSTAL20SD_864: /*BIOS 3.xx has a SDAC ramdac.*/ svga->decode_mask = (8 << 20) - 1; - if (info->local == S3_PARADISE_BAHAMAS64) + if (info->local == S3_PARADISE_BAHAMAS64 || info->local == S3_MIROCRYSTAL20SD_864) stepping = 0xc0; /*Vision864*/ else stepping = 0xc1; /*Vision864P*/ s3->id = stepping; s3->id_ext = s3->id_ext_pci = stepping; s3->packed_mmio = 0; - + svga->crtc[0x5a] = 0x0a; svga->ramdac = device_add(&sdac_ramdac_device); svga->clock_gen = svga->ramdac; svga->getclock = sdac_getclock; break; case S3_DIAMOND_STEALTH64_964: + case S3_ELSAWIN2KPROX_964: + case S3_MIROCRYSTAL20SV_964: svga->decode_mask = (8 << 20) - 1; - stepping = 0xd0; /*Vision964P*/ + stepping = 0xd0; /*Vision964*/ s3->id = stepping; s3->id_ext = s3->id_ext_pci = stepping; s3->packed_mmio = 1; svga->crtc[0x5a] = 0x0a; - svga->ramdac = device_add(&bt485_ramdac_device); + if (info->local == S3_ELSAWIN2KPROX_964) + svga->ramdac = device_add(&ibm_rgb528_ramdac_device); + else + svga->ramdac = device_add(&bt485_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); svga->getclock = icd2061_getclock; - break; + break; + + case S3_ELSAWIN2KPROX: + case S3_SPEA_MERCURY_P64V: + case S3_MIROVIDEO40SV_ERGO_968: + case S3_NUMBER9_9FX_771: + case S3_PHOENIX_VISION968: + svga->decode_mask = (8 << 20) - 1; + s3->id = 0xe1; /*Vision968*/ + s3->id_ext = s3->id_ext_pci = 0xf0; + s3->packed_mmio = 1; + if (s3->pci) { + svga->crtc[0x53] = 0x18; + svga->crtc[0x58] = 0x10; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + } else { + svga->crtc[0x53] = 0x00; + svga->crtc[0x59] = 0x00; + svga->crtc[0x5a] = 0x0a; + } + + if (info->local == S3_ELSAWIN2KPROX || info->local == S3_PHOENIX_VISION968 || + info->local == S3_NUMBER9_9FX_771) { + svga->ramdac = device_add(&ibm_rgb528_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + } else { + svga->ramdac = device_add(&tvp3026_ramdac_device); + svga->clock_gen = svga->ramdac; + svga->getclock = tvp3026_getclock; + } + break; + + case S3_NUMBER9_9FX_531: + case S3_PHOENIX_VISION868: + svga->decode_mask = (8 << 20) - 1; + s3->id = 0xe1; /*Vision868*/ + s3->id_ext = 0x90; + s3->id_ext_pci = 0x80; + s3->packed_mmio = 1; + if (s3->pci) { + svga->crtc[0x53] = 0x18; + svga->crtc[0x58] = 0x10; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + } else { + svga->crtc[0x53] = 0x00; + svga->crtc[0x59] = 0x00; + svga->crtc[0x5a] = 0x0a; + } + + if (info->local == S3_NUMBER9_9FX_531) { + svga->ramdac = device_add(&att498_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + } else { + svga->ramdac = device_add(&sdac_ramdac_device); + svga->clock_gen = svga->ramdac; + svga->getclock = sdac_getclock; + } + break; case S3_PHOENIX_TRIO32: + case S3_DIAMOND_STEALTH_SE: svga->decode_mask = (4 << 20) - 1; s3->id = 0xe1; /*Trio32*/ s3->id_ext = 0x10; @@ -3591,9 +7387,12 @@ static void *s3_init(const device_t *info) case S3_PHOENIX_TRIO64: case S3_PHOENIX_TRIO64_ONBOARD: + case S3_PHOENIX_TRIO64VPLUS: + case S3_PHOENIX_TRIO64VPLUS_ONBOARD: case S3_DIAMOND_STEALTH64_764: + case S3_SPEA_MIRAGE_P64: if (device_get_config_int("memory") == 1) - s3->svga.vram_max = 1 << 20; /* Phoenix BIOS does not expect VRAM to be mirrored. */ + svga->vram_max = 1 << 20; /* Phoenix BIOS does not expect VRAM to be mirrored. */ /* Fall over. */ case S3_NUMBER9_9FX: @@ -3602,6 +7401,31 @@ static void *s3_init(const device_t *info) s3->id_ext = s3->id_ext_pci = 0x11; s3->packed_mmio = 1; + if (info->local == S3_PHOENIX_TRIO64VPLUS || info->local == S3_PHOENIX_TRIO64VPLUS_ONBOARD) { + svga->crtc[0x53] = 0x08; + } + + svga->clock_gen = s3; + svga->getclock = s3_trio64_getclock; + break; + + case S3_TRIO64V2_DX: + case S3_TRIO64V2_DX_ONBOARD: + svga->decode_mask = (4 << 20) - 1; + s3->id = 0xe1; /*Trio64V2*/ + s3->id_ext = s3->id_ext_pci = 0x01; + s3->packed_mmio = 1; + svga->crtc[0x53] = 0x08; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + s3->pci_regs[0x05] = 0; + s3->pci_regs[0x06] = 0; + s3->pci_regs[0x07] = 2; + s3->pci_regs[0x3d] = 1; + s3->pci_regs[0x3e] = 4; + s3->pci_regs[0x3f] = 0xff; + svga->clock_gen = s3; svga->getclock = s3_trio64_getclock; break; @@ -3610,6 +7434,17 @@ static void *s3_init(const device_t *info) return NULL; } + if (s3->pci) + s3->card = pci_add_card(PCI_ADD_VIDEO, s3_pci_read, s3_pci_write, s3); + + s3->i2c = i2c_gpio_init("ddc_s3"); + s3->ddc = ddc_init(i2c_gpio_get_bus(s3->i2c)); + + s3->wake_fifo_thread = thread_create_event(); + s3->fifo_not_full_event = thread_create_event(); + s3->fifo_thread_run = 1; + s3->fifo_thread = thread_create(fifo_thread, s3); + return s3; } @@ -3618,14 +7453,39 @@ static int s3_orchid_86c911_available(void) return rom_present(ROM_ORCHID_86C911); } -static int s3_v7mirage_86c801_available(void) +static int s3_diamond_stealth_vram_available(void) { - return rom_present(ROM_V7MIRAGE_86C801); + return rom_present(ROM_DIAMOND_STEALTH_VRAM); } -static int s3_phoenix_86c805_available(void) +static int s3_ami_86c924_available(void) { - return rom_present(ROM_PHOENIX_86C805); + return rom_present(ROM_AMI_86C924); +} + +static int s3_spea_mirage_86c801_available(void) +{ + return rom_present(ROM_SPEA_MIRAGE_86C801); +} + +static int s3_spea_mirage_86c805_available(void) +{ + return rom_present(ROM_SPEA_MIRAGE_86C805); +} + +static int s3_phoenix_86c80x_available(void) +{ + return rom_present(ROM_PHOENIX_86C80X); +} + +static int s3_mirocrystal_8s_805_available(void) +{ + return rom_present(ROM_MIROCRYSTAL8S_805); +} + +static int s3_mirocrystal_10sd_805_available(void) +{ + return rom_present(ROM_MIROCRYSTAL10SD_805); } static int s3_metheus_86c928_available(void) @@ -3633,6 +7493,11 @@ static int s3_metheus_86c928_available(void) return rom_present(ROM_METHEUS_86C928); } +static int s3_spea_mercury_lite_pci_available(void) +{ + return rom_present(ROM_SPEA_MERCURY_LITE_PCI); +} + static int s3_bahamas64_available(void) { return rom_present(ROM_PARADISE_BAHAMAS64); @@ -3643,40 +7508,120 @@ static int s3_phoenix_vision864_available(void) return rom_present(ROM_PHOENIX_VISION864); } +static int s3_9fx_531_available(void) +{ + return rom_present(ROM_NUMBER9_9FX_531); +} + +static int s3_phoenix_vision868_available(void) +{ + return rom_present(ROM_PHOENIX_VISION868); +} + +static int s3_mirocrystal_20sv_964_vlb_available(void) +{ + return rom_present(ROM_MIROCRYSTAL20SV_964_VLB); +} + +static int s3_mirocrystal_20sv_964_pci_available(void) +{ + return rom_present(ROM_MIROCRYSTAL20SV_964_PCI); +} + static int s3_diamond_stealth64_964_available(void) { return rom_present(ROM_DIAMOND_STEALTH64_964); } +static int s3_mirovideo_40sv_ergo_968_pci_available(void) +{ + return rom_present(ROM_MIROVIDEO40SV_ERGO_968_PCI); +} + +static int s3_9fx_771_available(void) +{ + return rom_present(ROM_NUMBER9_9FX_771); +} + +static int s3_phoenix_vision968_available(void) +{ + return rom_present(ROM_PHOENIX_VISION968); +} + +static int s3_mirocrystal_20sd_864_vlb_available(void) +{ + return rom_present(ROM_MIROCRYSTAL20SD_864_VLB); +} + +static int s3_spea_mercury_p64v_pci_available(void) +{ + return rom_present(ROM_SPEA_MERCURY_P64V); +} + +static int s3_elsa_winner2000_pro_x_964_available(void) +{ + return rom_present(ROM_ELSAWIN2KPROX_964); +} + +static int s3_elsa_winner2000_pro_x_available(void) +{ + return rom_present(ROM_ELSAWIN2KPROX); +} + static int s3_phoenix_trio32_available(void) { return rom_present(ROM_PHOENIX_TRIO32); } +static int s3_diamond_stealth_se_available(void) +{ + return rom_present(ROM_DIAMOND_STEALTH_SE); +} + static int s3_9fx_available(void) { return rom_present(ROM_NUMBER9_9FX); } +static int s3_spea_mirage_p64_vlb_available(void) +{ + return rom_present(ROM_SPEA_MIRAGE_P64); +} + static int s3_phoenix_trio64_available(void) { return rom_present(ROM_PHOENIX_TRIO64); } +static int s3_phoenix_trio64vplus_available(void) +{ + return rom_present(ROM_PHOENIX_TRIO64VPLUS); +} + static int s3_diamond_stealth64_764_available(void) { return rom_present(ROM_DIAMOND_STEALTH64_764); } +static int s3_trio64v2_dx_available(void) +{ + return rom_present(ROM_TRIO64V2_DX_VBE20); +} + static void s3_close(void *p) { s3_t *s3 = (s3_t *)p; - svga_close(&s3->svga); - - thread_kill(s3->fifo_thread); - thread_destroy_event(s3->wake_fifo_thread); + s3->fifo_thread_run = 0; + thread_set_event(s3->wake_fifo_thread); + thread_wait(s3->fifo_thread); thread_destroy_event(s3->fifo_not_full_event); + thread_destroy_event(s3->wake_fifo_thread); + + svga_close(&s3->svga); + + ddc_close(s3->ddc); + i2c_gpio_close(s3->i2c); free(s3); } @@ -3684,7 +7629,7 @@ static void s3_close(void *p) static void s3_speed_changed(void *p) { s3_t *s3 = (s3_t *)p; - + svga_recalctimings(&s3->svga); } @@ -3695,400 +7640,816 @@ static void s3_force_redraw(void *p) s3->svga.fullchange = changeframecount; } -static const device_config_t s3_orchid_86c911_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 1, - { - { - "512 KB", 0 - }, - { - "1 MB", 1 - }, - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t s3_orchid_86c911_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1, + .selection = { + { + .description = "512 KB", + .value = 0 + }, + { + .description = "1 MB", + .value = 1 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; -static const device_config_t s3_9fx_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 2, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t s3_9fx_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; -static const device_config_t s3_phoenix_trio32_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 2, - { - { - "512 KB", 0 - }, - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t s3_phoenix_trio32_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { + .description = "512 KB", + .value = 0 + }, + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; -static const device_config_t s3_phoenix_trio64_onboard_config[] = -{ - { - "memory", "Video memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t s3_standard_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; -static const device_config_t s3_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "8 MB", 8 - }, - { - "" - } - } - }, - { - "", "", -1 - } +static const device_config_t s3_968_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } }; -const device_t s3_orchid_86c911_isa_device = -{ - "Orchid Fahrenheit 1280 (S3 86c911) ISA", - DEVICE_AT | DEVICE_ISA, - S3_ORCHID_86C911, - s3_init, - s3_close, - NULL, - s3_orchid_86c911_available, - s3_speed_changed, - s3_force_redraw, - s3_orchid_86c911_config +const device_t s3_orchid_86c911_isa_device = { + .name = "S3 86c911 ISA (Orchid Fahrenheit 1280)", + .internal_name = "orchid_s3_911", + .flags = DEVICE_AT | DEVICE_ISA, + .local = S3_ORCHID_86C911, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_orchid_86c911_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_orchid_86c911_config }; -const device_t s3_v7mirage_86c801_isa_device = -{ - "SPEA V7 Mirage (S3 86c801) ISA", - DEVICE_AT | DEVICE_ISA, - S3_V7MIRAGE_86C801, - s3_init, - s3_close, - NULL, - s3_v7mirage_86c801_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config +const device_t s3_diamond_stealth_vram_isa_device = { + .name = "S3 86c911 ISA (Diamond Stealth VRAM)", + .internal_name = "stealthvram_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = S3_DIAMOND_STEALTH_VRAM, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth_vram_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_orchid_86c911_config }; -const device_t s3_phoenix_86c805_vlb_device = -{ - "Phoenix S3 86c805 VLB", - DEVICE_VLB, - S3_PHOENIX_86C805, - s3_init, - s3_close, - NULL, - s3_phoenix_86c805_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config +const device_t s3_ami_86c924_isa_device = { + .name = "S3 86c924 ISA (AMI)", + .internal_name = "ami_s3_924", + .flags = DEVICE_AT | DEVICE_ISA, + .local = S3_AMI_86C924, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_ami_86c924_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_orchid_86c911_config }; -const device_t s3_metheus_86c928_isa_device = -{ - "Metheus Premier 928 (S3 86c928) ISA", - DEVICE_AT | DEVICE_ISA, - S3_METHEUS_86C928, - s3_init, - s3_close, - NULL, - s3_metheus_86c928_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_spea_mirage_86c801_isa_device = { + .name = "S3 86c801 ISA (SPEA Mirage ISA)", + .internal_name = "px_s3_v7_801_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = S3_SPEA_MIRAGE_86C801, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_spea_mirage_86c801_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_metheus_86c928_vlb_device = -{ - "Metheus Premier 928 (S3 86c928) VLB", - DEVICE_VLB, - S3_METHEUS_86C928, - s3_init, - s3_close, - NULL, - s3_metheus_86c928_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_86c805_onboard_vlb_device = { + .name = "S3 86c805 VLB On-Board", + .internal_name = "px_s3_805_onboard_vlb", + .flags = DEVICE_VLB, + .local = S3_86C805_ONBOARD, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = NULL }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_bahamas64_vlb_device = -{ - "Paradise Bahamas 64 (S3 Vision864) VLB", - DEVICE_VLB, - S3_PARADISE_BAHAMAS64, - s3_init, - s3_close, - NULL, - s3_bahamas64_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config +const device_t s3_spea_mirage_86c805_vlb_device = { + .name = "S3 86c805 VLB (SPEA Mirage VL)", + .internal_name = "px_s3_v7_805_vlb", + .flags = DEVICE_VLB, + .local = S3_SPEA_MIRAGE_86C805, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_spea_mirage_86c805_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_bahamas64_pci_device = -{ - "Paradise Bahamas 64 (S3 Vision864) PCI", - DEVICE_PCI, - S3_PARADISE_BAHAMAS64, - s3_init, - s3_close, - NULL, - s3_bahamas64_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config +const device_t s3_mirocrystal_8s_805_vlb_device = { + .name = "S3 86c805 VLB (MiroCRYSTAL 8S)", + .internal_name = "mirocrystal8s_vlb", + .flags = DEVICE_VLB, + .local = S3_MIROCRYSTAL8S_805, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_mirocrystal_8s_805_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_diamond_stealth64_964_vlb_device = -{ - "S3 Vision964 (Diamond Stealth64 VRAM) VLB", - DEVICE_VLB, - S3_DIAMOND_STEALTH64_964, - s3_init, - s3_close, - NULL, - s3_diamond_stealth64_964_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_mirocrystal_10sd_805_vlb_device = { + .name = "S3 86c805 VLB (MiroCRYSTAL 10SD)", + .internal_name = "mirocrystal10sd_vlb", + .flags = DEVICE_VLB, + .local = S3_MIROCRYSTAL10SD_805, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_mirocrystal_10sd_805_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_diamond_stealth64_964_pci_device = -{ - "S3 Vision964 (Diamond Stealth64 VRAM) PCI", - DEVICE_PCI, - S3_DIAMOND_STEALTH64_964, - s3_init, - s3_close, - NULL, - s3_diamond_stealth64_964_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_phoenix_86c801_isa_device = { + .name = "S3 86c801 ISA (Phoenix)", + .internal_name = "px_86c801_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = S3_PHOENIX_86C801, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_86c80x_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_9fx_vlb_device = -{ - "Number 9 9FX (S3 Trio64) VLB", - DEVICE_VLB, - S3_NUMBER9_9FX, - s3_init, - s3_close, - NULL, - s3_9fx_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config +const device_t s3_phoenix_86c805_vlb_device = { + .name = "S3 86c805 VLB (Phoenix)", + .internal_name = "px_86c805_vlb", + .flags = DEVICE_VLB, + .local = S3_PHOENIX_86C805, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_86c80x_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_9fx_pci_device = -{ - "Number 9 9FX (S3 Trio64) PCI", - DEVICE_PCI, - S3_NUMBER9_9FX, - s3_init, - s3_close, - NULL, - s3_9fx_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config +const device_t s3_metheus_86c928_isa_device = { + .name = "S3 86c928 ISA (Metheus Premier 928)", + .internal_name = "metheus928_isa", + .flags = DEVICE_AT | DEVICE_ISA, + .local = S3_METHEUS_86C928, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_metheus_86c928_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config }; -const device_t s3_phoenix_trio32_vlb_device = -{ - "Phoenix S3 Trio32 VLB", - DEVICE_VLB, - S3_PHOENIX_TRIO32, - s3_init, - s3_close, - NULL, - s3_phoenix_trio32_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio32_config +const device_t s3_metheus_86c928_vlb_device = { + .name = "S3 86c928 VLB (Metheus Premier 928)", + .internal_name = "metheus928_vlb", + .flags = DEVICE_VLB, + .local = S3_METHEUS_86C928, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_metheus_86c928_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config }; -const device_t s3_phoenix_trio32_pci_device = -{ - "Phoenix S3 Trio32 PCI", - DEVICE_PCI, - S3_PHOENIX_TRIO32, - s3_init, - s3_close, - NULL, - s3_phoenix_trio32_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio32_config +const device_t s3_spea_mercury_lite_86c928_pci_device = { + .name = "S3 86c928 PCI (SPEA Mercury Lite)", + .internal_name = "spea_mercurylite_pci", + .flags = DEVICE_PCI, + .local = S3_SPEA_MERCURY_LITE_PCI, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_spea_mercury_lite_pci_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config }; -const device_t s3_phoenix_trio64_vlb_device = -{ - "Phoenix S3 Trio64 VLB", - DEVICE_VLB, - S3_PHOENIX_TRIO64, - s3_init, - s3_close, - NULL, - s3_phoenix_trio64_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_mirocrystal_20sd_864_vlb_device = { + .name = "S3 Vision864 VLB (MiroCRYSTAL 20SD)", + .internal_name = "mirocrystal20sd_vlb", + .flags = DEVICE_VLB, + .local = S3_MIROCRYSTAL20SD_864, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_mirocrystal_20sd_864_vlb_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_phoenix_trio64_onboard_pci_device = -{ - "Phoenix S3 Trio64 On-Board PCI", - DEVICE_PCI, - S3_PHOENIX_TRIO64_ONBOARD, - s3_init, - s3_close, - NULL, - NULL, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio64_onboard_config +const device_t s3_bahamas64_vlb_device = { + .name = "S3 Vision864 VLB (Paradise Bahamas 64)", + .internal_name = "bahamas64_vlb", + .flags = DEVICE_VLB, + .local = S3_PARADISE_BAHAMAS64, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_bahamas64_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_phoenix_trio64_pci_device = -{ - "Phoenix S3 Trio64 PCI", - DEVICE_PCI, - S3_PHOENIX_TRIO64, - s3_init, - s3_close, - NULL, - s3_phoenix_trio64_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_bahamas64_pci_device = { + .name = "S3 Vision864 PCI (Paradise Bahamas 64)", + .internal_name = "bahamas64_pci", + .flags = DEVICE_PCI, + .local = S3_PARADISE_BAHAMAS64, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_bahamas64_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_phoenix_vision864_vlb_device = -{ - "Phoenix S3 Vision864 VLB", - DEVICE_VLB, - S3_PHOENIX_VISION864, - s3_init, - s3_close, - NULL, - s3_phoenix_vision864_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_mirocrystal_20sv_964_vlb_device = { + .name = "S3 Vision964 VLB (MiroCRYSTAL 20SV)", + .internal_name = "mirocrystal20sv_vlb", + .flags = DEVICE_VLB, + .local = S3_MIROCRYSTAL20SV_964, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_mirocrystal_20sv_964_vlb_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_phoenix_vision864_pci_device = -{ - "Phoenix S3 Vision864 PCI", - DEVICE_PCI, - S3_PHOENIX_VISION864, - s3_init, - s3_close, - NULL, - s3_phoenix_vision864_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_mirocrystal_20sv_964_pci_device = { + .name = "S3 Vision964 PCI (MiroCRYSTAL 20SV)", + .internal_name = "mirocrystal20sv_pci", + .flags = DEVICE_PCI, + .local = S3_MIROCRYSTAL20SV_964, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_mirocrystal_20sv_964_pci_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config }; -const device_t s3_diamond_stealth64_vlb_device = -{ - "S3 Trio64 (Diamond Stealth64 DRAM) VLB", - DEVICE_VLB, - S3_DIAMOND_STEALTH64_764, - s3_init, - s3_close, - NULL, - s3_diamond_stealth64_764_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_diamond_stealth64_964_vlb_device = { + .name = "S3 Vision964 VLB (Diamond Stealth64 VRAM)", + .internal_name = "stealth64v_vlb", + .flags = DEVICE_VLB, + .local = S3_DIAMOND_STEALTH64_964, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth64_964_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config }; -const device_t s3_diamond_stealth64_pci_device = -{ - "S3 Trio64 (Diamond Stealth64 DRAM) PCI", - DEVICE_PCI, - S3_DIAMOND_STEALTH64_764, - s3_init, - s3_close, - NULL, - s3_diamond_stealth64_764_available, - s3_speed_changed, - s3_force_redraw, - s3_config +const device_t s3_diamond_stealth64_964_pci_device = { + .name = "S3 Vision964 PCI (Diamond Stealth64 VRAM)", + .internal_name = "stealth64v_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH64_964, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth64_964_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_9fx_771_pci_device = { + .name = "S3 Vision968 PCI (Number 9 9FX 771)", + .internal_name = "n9_9fx_771_pci", + .flags = DEVICE_PCI, + .local = S3_NUMBER9_9FX_771, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_9fx_771_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_vision968_pci_device = { + .name = "S3 Vision968 PCI (Phoenix)", + .internal_name = "px_vision968_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_VISION968, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_vision968_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_vision968_vlb_device = { + .name = "S3 Vision968 VLB (Phoenix)", + .internal_name = "px_vision968_vlb", + .flags = DEVICE_VLB, + .local = S3_PHOENIX_VISION968, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_vision968_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_mirovideo_40sv_ergo_968_pci_device = { + .name = "S3 Vision968 PCI (MiroVIDEO 40SV Ergo)", + .internal_name = "mirovideo40sv_pci", + .flags = DEVICE_PCI, + .local = S3_MIROVIDEO40SV_ERGO_968, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_mirovideo_40sv_ergo_968_pci_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_spea_mercury_p64v_pci_device = { + .name = "S3 Vision968 PCI (SPEA Mercury P64V)", + .internal_name = "spea_mercury64p_pci", + .flags = DEVICE_PCI, + .local = S3_SPEA_MERCURY_P64V, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_spea_mercury_p64v_pci_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_9fx_vlb_device = { + .name = "S3 Trio64 VLB (Number 9 9FX 330)", + .internal_name = "n9_9fx_vlb", + .flags = DEVICE_VLB, + .local = S3_NUMBER9_9FX, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_9fx_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + +const device_t s3_9fx_pci_device = { + .name = "S3 Trio64 PCI (Number 9 9FX 330)", + .internal_name = "n9_9fx_pci", + .flags = DEVICE_PCI, + .local = S3_NUMBER9_9FX, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_9fx_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + +const device_t s3_phoenix_trio32_vlb_device = { + .name = "S3 Trio32 VLB (Phoenix)", + .internal_name = "px_trio32_vlb", + .flags = DEVICE_VLB, + .local = S3_PHOENIX_TRIO32, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_trio32_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_phoenix_trio32_config +}; + +const device_t s3_phoenix_trio32_pci_device = { + .name = "S3 Trio32 PCI (Phoenix)", + .internal_name = "px_trio32_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_TRIO32, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_trio32_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_phoenix_trio32_config +}; + +const device_t s3_diamond_stealth_se_vlb_device = { + .name = "S3 Trio32 VLB (Diamond Stealth SE)", + .internal_name = "stealthse_vlb", + .flags = DEVICE_VLB, + .local = S3_DIAMOND_STEALTH_SE, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth_se_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_phoenix_trio32_config +}; + +const device_t s3_diamond_stealth_se_pci_device = { + .name = "S3 Trio32 PCI (Diamond Stealth SE)", + .internal_name = "stealthse_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH_SE, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth_se_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_phoenix_trio32_config +}; + +const device_t s3_phoenix_trio64_vlb_device = { + .name = "S3 Trio64 VLB (Phoenix)", + .internal_name = "px_trio64_vlb", + .flags = DEVICE_VLB, + .local = S3_PHOENIX_TRIO64, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_trio64_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_trio64_onboard_pci_device = { + .name = "S3 Trio64 PCI On-Board (Phoenix)", + .internal_name = "px_trio64_onboard_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_TRIO64_ONBOARD, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = NULL }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_trio64_pci_device = { + .name = "S3 Trio64 PCI (Phoenix)", + .internal_name = "px_trio64_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_TRIO64, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_trio64_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_trio64vplus_onboard_pci_device = { + .name = "S3 Trio64V+ PCI On-Board (Phoenix)", + .internal_name = "px_trio64vplus_onboard_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_TRIO64VPLUS_ONBOARD, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = NULL }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_trio64vplus_pci_device = { + .name = "S3 Trio64V+ PCI (Phoenix)", + .internal_name = "px_trio64vplus_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_TRIO64VPLUS, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_trio64vplus_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_vision864_vlb_device = { + .name = "S3 Vision864 VLB (Phoenix)", + .internal_name = "px_vision864_vlb", + .flags = DEVICE_VLB, + .local = S3_PHOENIX_VISION864, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_vision864_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_vision864_pci_device = { + .name = "S3 Vision864 PCI (Phoenix)", + .internal_name = "px_vision864_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_VISION864, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_vision864_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_9fx_531_pci_device = { + .name = "S3 Vision868 PCI (Number 9 9FX 531)", + .internal_name = "n9_9fx_531_pci", + .flags = DEVICE_PCI, + .local = S3_NUMBER9_9FX_531, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_9fx_531_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + +const device_t s3_phoenix_vision868_vlb_device = { + .name = "S3 Vision868 VLB (Phoenix)", + .internal_name = "px_vision868_vlb", + .flags = DEVICE_VLB, + .local = S3_PHOENIX_VISION868, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_vision868_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_phoenix_vision868_pci_device = { + .name = "S3 Vision868 PCI (Phoenix)", + .internal_name = "px_vision868_pci", + .flags = DEVICE_PCI, + .local = S3_PHOENIX_VISION868, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_phoenix_vision868_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_diamond_stealth64_vlb_device = { + .name = "S3 Trio64 VLB (Diamond Stealth64 DRAM)", + .internal_name = "stealth64d_vlb", + .flags = DEVICE_VLB, + .local = S3_DIAMOND_STEALTH64_764, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth64_764_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + +const device_t s3_diamond_stealth64_pci_device = { + .name = "S3 Trio64 PCI (Diamond Stealth64 DRAM)", + .internal_name = "stealth64d_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH64_764, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_diamond_stealth64_764_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + +const device_t s3_spea_mirage_p64_vlb_device = { + .name = "S3 Trio64 VLB (SPEA Mirage P64)", + .internal_name = "spea_miragep64_vlb", + .flags = DEVICE_VLB, + .local = S3_SPEA_MIRAGE_P64, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_spea_mirage_p64_vlb_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + +const device_t s3_elsa_winner2000_pro_x_964_pci_device = { + .name = "S3 Vision964 PCI (ELSA Winner 2000 Pro/X)", + .internal_name = "elsawin2kprox_964_pci", + .flags = DEVICE_PCI, + .local = S3_ELSAWIN2KPROX_964, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_elsa_winner2000_pro_x_964_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_968_config +}; + +const device_t s3_elsa_winner2000_pro_x_pci_device = { + .name = "S3 Vision968 PCI (ELSA Winner 2000 Pro/X)", + .internal_name = "elsawin2kprox_pci", + .flags = DEVICE_PCI, + .local = S3_ELSAWIN2KPROX, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_elsa_winner2000_pro_x_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_968_config +}; + +const device_t s3_trio64v2_dx_pci_device = { + .name = "S3 Trio64V2/DX PCI", + .internal_name = "trio64v2dx_pci", + .flags = DEVICE_PCI, + .local = S3_TRIO64V2_DX, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + { .available = s3_trio64v2_dx_available }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config +}; + +const device_t s3_trio64v2_dx_onboard_pci_device = { + .name = "S3 Trio64V2/DX On-Board PCI", + .internal_name = "trio64v2dx_onboard_pci", + .flags = DEVICE_PCI, + .local = S3_TRIO64V2_DX_ONBOARD, + .init = s3_init, + .close = s3_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_standard_config }; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 45ffce9bf..475269f93 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -26,19 +26,20 @@ #include <86box/86box.h> #include <86box/io.h> #include <86box/timer.h> +#include <86box/dma.h> #include <86box/mem.h> #include <86box/pci.h> #include <86box/rom.h> #include <86box/device.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> -static uint64_t virge_time = 0; -static int reg_writes = 0, reg_reads = 0; - static int dither[4][4] = { {0, 4, 1, 5}, @@ -59,30 +60,44 @@ static int dither[4][4] = #define FIFO_ENTRY_SIZE (1 << 31) #define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) -#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= (FIFO_SIZE - 4)) #define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) #define FIFO_TYPE 0xff000000 #define FIFO_ADDR 0x00ffffff -#define ROM_DIAMOND_STEALTH3D_2000 L"roms/video/s3virge/s3virge.bin" -#define ROM_DIAMOND_STEALTH3D_3000 L"roms/video/s3virge/diamondstealth3000.vbi" -#define ROM_VIRGE_DX L"roms/video/s3virge/86c375_1.bin" -#define ROM_VIRGE_DX_VBE20 L"roms/video/s3virge/86c375_4.bin" +#define ROM_VIRGE_325 "roms/video/s3virge/86c325.bin" +#define ROM_DIAMOND_STEALTH3D_2000 "roms/video/s3virge/s3virge.bin" +#define ROM_DIAMOND_STEALTH3D_3000 "roms/video/s3virge/diamondstealth3000.vbi" +#define ROM_STB_VELOCITY_3D "roms/video/s3virge/stb_velocity3d_110.BIN" +#define ROM_VIRGE_DX "roms/video/s3virge/86c375_1.bin" +#define ROM_DIAMOND_STEALTH3D_2000PRO "roms/video/s3virge/virgedxdiamond.vbi" +#define ROM_VIRGE_GX "roms/video/s3virge/86c375_4.bin" +#define ROM_VIRGE_GX2 "roms/video/s3virge/flagpoint.VBI" +#define ROM_DIAMOND_STEALTH3D_4000 "roms/video/s3virge/86c357.bin" +#define ROM_TRIO3D2X "roms/video/s3virge/TRIO3D2X_8mbsdr.VBI" enum { + S3_VIRGE_325, S3_DIAMOND_STEALTH3D_2000, S3_DIAMOND_STEALTH3D_3000, + S3_STB_VELOCITY_3D, S3_VIRGE_DX, - S3_VIRGE_DX_VBE20 + S3_DIAMOND_STEALTH3D_2000PRO, + S3_VIRGE_GX, + S3_VIRGE_GX2, + S3_DIAMOND_STEALTH3D_4000, + S3_TRIO_3D2X }; enum { S3_VIRGE, S3_VIRGEVX, - S3_VIRGEDX + S3_VIRGEDX, + S3_VIRGEGX2, + S3_TRIO3D2X }; enum @@ -103,10 +118,10 @@ typedef struct s3d_t { uint32_t cmd_set; int clip_l, clip_r, clip_t, clip_b; - + uint32_t dest_base; uint32_t dest_str; - + uint32_t z_base; uint32_t z_str; @@ -122,14 +137,14 @@ typedef struct s3d_t int32_t TdWdX, TdWdY; uint32_t tws; - + int32_t TdDdX, TdDdY; uint32_t tds; - + int16_t TdGdX, TdBdX, TdRdX, TdAdX; int16_t TdGdY, TdBdY, TdRdY, TdAdY; uint32_t tgs, tbs, trs, tas; - + uint32_t TdXdY12; uint32_t txend12; uint32_t TdXdY01; @@ -138,23 +153,28 @@ typedef struct s3d_t uint32_t txs; uint32_t tys; int ty01, ty12, tlr; + + uint8_t fog_r, fog_g, fog_b; } s3d_t; - + typedef struct virge_t { mem_mapping_t linear_mapping; mem_mapping_t mmio_mapping; mem_mapping_t new_mmio_mapping; - + rom_t bios_rom; - + svga_t svga; - + uint8_t bank; uint8_t ma_ext; + uint8_t reg6b, lfb_bios; uint8_t virge_id, virge_id_high, virge_id_low, virge_rev; + uint8_t int_line; + uint32_t linear_base, linear_size; uint8_t pci_regs[256]; @@ -162,21 +182,21 @@ typedef struct virge_t int pci; int chip; + int is_agp; int bilinear_enabled; int dithering_enabled; - int memory_size; - - int pixel_count, tri_count; - + uint32_t memory_size; + uint32_t vram_mask; + thread_t *render_thread; event_t *wake_render_thread; - event_t *wake_main_thread; + event_t *wake_main_thread; event_t *not_full_event; - + uint32_t hwc_fg_col, hwc_bg_col; int hwc_col_stack_pos; - + struct { uint32_t src_base; @@ -193,21 +213,21 @@ typedef struct virge_t int r_width, r_height; int rsrc_x, rsrc_y; int rdest_x, rdest_y; - + int lxend0, lxend1; int32_t ldx; uint32_t lxstart, lystart; int lycnt; int line_dir; - + int src_x, src_y; int dest_x, dest_y; int w, h; uint8_t rop; - + int data_left_count; uint32_t data_left; - + uint32_t pattern_8[8*8]; uint32_t pattern_16[8*8]; uint32_t pattern_24[8*8]; @@ -221,13 +241,14 @@ typedef struct virge_t uint32_t pycnt; uint32_t dest_l, dest_r; } s3d; - + s3d_t s3d_tri; s3d_t s3d_buffer[RB_SIZE]; int s3d_read_idx, s3d_write_idx; int s3d_busy; - + int render_idx; + struct { uint32_t pri_ctrl; @@ -253,38 +274,40 @@ typedef struct virge_t uint32_t pri_size; uint32_t sec_start; uint32_t sec_size; - + int sdif; - + int pri_x, pri_y, pri_w, pri_h; int sec_x, sec_y, sec_w, sec_h; } streams; - fifo_entry_t fifo[FIFO_SIZE]; - volatile int fifo_read_idx, fifo_write_idx; + uint8_t cmd_dma; + uint32_t cmd_dma_base; + uint32_t dma_ptr; + uint64_t blitter_time; + volatile int fifo_slot; - thread_t *fifo_thread; - event_t *wake_fifo_thread; - event_t *fifo_not_full_event; - - int virge_busy; + pc_timer_t tri_timer; - uint8_t subsys_stat, subsys_cntl; + int virge_busy, local; + + uint8_t subsys_stat, subsys_cntl, advfunc_cntl; + + uint8_t render_thread_run; + + uint8_t serialport; + + void *i2c, *ddc; + + int waiting; } virge_t; -static video_timings_t timing_diamond_stealth3d_2000_vlb = {VIDEO_BUS, 2, 2, 3, 28, 28, 45}; static video_timings_t timing_diamond_stealth3d_2000_pci = {VIDEO_PCI, 2, 2, 3, 28, 28, 45}; -static video_timings_t timing_diamond_stealth3d_3000_vlb = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; static video_timings_t timing_diamond_stealth3d_3000_pci = {VIDEO_PCI, 2, 2, 4, 26, 26, 42}; -static video_timings_t timing_virge_dx_vlb = {VIDEO_BUS, 2, 2, 3, 28, 28, 45}; static video_timings_t timing_virge_dx_pci = {VIDEO_PCI, 2, 2, 3, 28, 28, 45}; +static video_timings_t timing_virge_agp = {VIDEO_AGP, 2, 2, 3, 28, 28, 45}; -static __inline void wake_fifo_thread(virge_t *virge) -{ - thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} - -static void queue_triangle(virge_t *virge); +static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri); static void s3_virge_recalctimings(svga_t *svga); static void s3_virge_updatemapping(virge_t *virge); @@ -302,32 +325,33 @@ enum { CMD_SET_AE = 1, CMD_SET_HC = (1 << 1), - + CMD_SET_FORMAT_MASK = (7 << 2), CMD_SET_FORMAT_8 = (0 << 2), CMD_SET_FORMAT_16 = (1 << 2), CMD_SET_FORMAT_24 = (2 << 2), - + CMD_SET_MS = (1 << 6), CMD_SET_IDS = (1 << 7), CMD_SET_MP = (1 << 8), CMD_SET_TP = (1 << 9), - + CMD_SET_ITA_MASK = (3 << 10), CMD_SET_ITA_BYTE = (0 << 10), CMD_SET_ITA_WORD = (1 << 10), CMD_SET_ITA_DWORD = (2 << 10), - + CMD_SET_ZUP = (1 << 23), - + CMD_SET_ZB_MODE = (3 << 24), CMD_SET_XP = (1 << 25), CMD_SET_YP = (1 << 26), - + CMD_SET_COMMAND_MASK = (15 << 27) }; +#define CMD_SET_FE (1 << 17) #define CMD_SET_ABC_SRC (1 << 18) #define CMD_SET_ABC_ENABLE (1 << 19) #define CMD_SET_TWE (1 << 26) @@ -348,6 +372,11 @@ enum #define INT_3DF_EMP (1 << 6) #define INT_MASK 0xff +#define SERIAL_PORT_SCW (1 << 0) +#define SERIAL_PORT_SDW (1 << 1) +#define SERIAL_PORT_SCR (1 << 2) +#define SERIAL_PORT_SDR (1 << 3) + #ifdef ENABLE_S3_VIRGE_LOG int s3_virge_do_log = ENABLE_S3_VIRGE_LOG; @@ -369,58 +398,129 @@ s3_virge_log(const char *fmt, ...) #endif -static void s3_virge_update_irqs(virge_t *virge) +static void +s3_virge_tri_timer(void *p) { - if (!virge->pci) - { - return; - } + virge_t *virge = (virge_t *)p; - if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK)) + thread_set_event(virge->wake_render_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void +queue_triangle(virge_t *virge) +{ + if (RB_FULL) + { + thread_reset_event(virge->not_full_event); + thread_reset_event(virge->wake_main_thread); + if (RB_FULL) { + thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ + thread_wait_event(virge->wake_main_thread, -1); + } + } + virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; + virge->s3d_write_idx++; + + if (!virge->s3d_busy) { + if (!(timer_is_enabled(&virge->tri_timer))) + timer_set_delay_u64(&virge->tri_timer, 100 * TIMER_USEC); + } +} + +static void +s3_virge_update_irqs(virge_t *virge) +{ + if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & (virge->subsys_cntl & INT_MASK))) pci_set_irq(virge->card, PCI_INTA); else pci_clear_irq(virge->card, PCI_INTA); } + +static void +render_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (virge->render_thread_run) { + thread_wait_event(virge->wake_render_thread, -1); + thread_reset_event(virge->wake_render_thread); + virge->s3d_busy = 1; + while (!RB_EMPTY) { + s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]); + virge->s3d_read_idx++; + if (RB_ENTRIES == RB_MASK) { + thread_set_event(virge->not_full_event); + thread_set_event(virge->wake_main_thread); + } + } + virge->s3d_busy = 0; + virge->subsys_stat |= INT_S3D_DONE; + s3_virge_update_irqs(virge); + } +} + + static void s3_virge_out(uint16_t addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; svga_t *svga = &virge->svga; uint8_t old; + uint32_t cursoraddr; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; - + switch (addr) { - case 0x3c5: + case 0x3c5: if (svga->seqaddr >= 0x10) { svga->seqregs[svga->seqaddr & 0x1f]=val; svga_recalctimings(svga); return; } - if (svga->seqaddr == 4) /*Chain-4 - update banking*/ - { - if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16; - else svga->write_bank = svga->read_bank = virge->bank << 14; - } - break; - + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) + svga->write_bank = svga->read_bank = virge->bank << 16; + else + svga->write_bank = svga->read_bank = virge->bank << 14; + } else if (svga->seqaddr == 0x08) { + svga->seqregs[svga->seqaddr] = val & 0x0f; + return; + } else if ((svga->seqaddr == 0x0d) && (svga->seqregs[0x08] == 0x06)) { + svga->seqregs[svga->seqaddr] = val; + svga->dpms = (svga->seqregs[0x0d] & 0x50) || (svga->crtc[0x56] & 0x06); + svga_recalctimings(svga); + return; + } + break; + case 0x3d4: svga->crtcreg = val; return; case 0x3d5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) - return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if ((svga->crtcreg >= 0x20) && (svga->crtcreg < 0x40) && + (svga->crtcreg != 0x36) && (svga->crtcreg != 0x38) && + (svga->crtcreg != 0x39) && ((svga->crtc[0x38] & 0xcc) != 0x48)) + return; + if ((svga->crtcreg >= 0x40) && ((svga->crtc[0x39] & 0xe0) != 0xa0)) + return; + if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) + return; if (svga->crtcreg >= 0x80) return; old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; + + if (svga->crtcreg > 0x18) + s3_virge_log("OUTB VGA reg = %02x, val = %02x\n", svga->crtcreg, val); + switch (svga->crtcreg) { case 0x31: @@ -429,32 +529,39 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 0x32: s3_virge_update_irqs(virge); break; - + case 0x69: virge->ma_ext = val & 0x1f; break; - + case 0x35: - virge->bank = (virge->bank & 0x70) | (val & 0xf); - if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; - else svga->write_bank = svga->read_bank = virge->bank << 14; + virge->bank = (virge->bank & 0x70) | (val & 0xf); + if (svga->chain4) + svga->write_bank = svga->read_bank = virge->bank << 16; + else + svga->write_bank = svga->read_bank = virge->bank << 14; break; case 0x51: virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2); - if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; - else svga->write_bank = svga->read_bank = virge->bank << 14; + if (svga->chain4) + svga->write_bank = svga->read_bank = virge->bank << 16; + else + svga->write_bank = svga->read_bank = virge->bank << 14; virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2); break; case 0x6a: virge->bank = val; - if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; - else svga->write_bank = svga->read_bank = virge->bank << 14; + if (svga->chain4) + svga->write_bank = svga->read_bank = virge->bank << 16; + else + svga->write_bank = svga->read_bank = virge->bank << 14; break; - + case 0x3a: - if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + if (val & 0x10) + svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ break; - + case 0x45: svga->hwcursor.ena = val & 1; break; @@ -462,11 +569,12 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 0x4c: case 0x4d: case 0x4e: case 0x4f: svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; - svga->hwcursor.xoff = svga->crtc[0x4e] & 63; - svga->hwcursor.yoff = svga->crtc[0x4f] & 63; - svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + svga->hwcursor.xoff = svga->crtc[0x4e] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x4f] & 0x3f; + cursoraddr = (virge->memory_size == 8) ? 0x1fff : 0x0fff; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & cursoraddr) * 1024) + (svga->hwcursor.yoff * 16); break; - + case 0x4a: switch (virge->hwc_col_stack_pos) { @@ -489,7 +597,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; break; case 1: - virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); + virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); break; case 2: virge->hwc_bg_col = (virge->hwc_bg_col & 0x00ffff) | (val << 16); @@ -502,24 +610,45 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 0x58: case 0x59: case 0x5a: s3_virge_updatemapping(virge); break; - + + case 0x56: + svga->dpms = (svga->seqregs[0x0d] & 0x50) || (svga->crtc[0x56] & 0x06); + old = ~val; /* force recalc */ + break; + + case 0x5c: + if ((val & 0xa0) == 0x80) + i2c_gpio_set(virge->i2c, !!(val & 0x40), !!(val & 0x10)); + break; + case 0x67: switch (val >> 4) { - case 2: case 3: svga->bpp = 15; break; - case 4: case 5: svga->bpp = 16; break; + case 2: case 3: svga->bpp = 15; break; + case 4: case 5: svga->bpp = 16; break; case 7: svga->bpp = 24; break; case 13: svga->bpp = (virge->chip == S3_VIRGEVX) ? 24 : 32; break; default: svga->bpp = 8; break; } break; + + case 0xaa: + i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); + break; } if (old != val) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + if ((svga->crtc[0x67] & 0xc) != 0xc) + svga->ma_latch |= (virge->ma_ext << 16); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } break; @@ -531,9 +660,9 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) { virge_t *virge = (virge_t *)p; svga_t *svga = &virge->svga; - uint8_t ret; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -543,7 +672,7 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) ret = 0xff; else ret = svga_in(addr, svga); - break; + break; case 0x3c5: if (svga->seqaddr >= 8) @@ -556,28 +685,56 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) case 0x3D4: ret = svga->crtcreg; - break; + break; case 0x3D5: switch (svga->crtcreg) { case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/ case 0x2e: ret = virge->virge_id_low; break; /*New chip ID*/ - case 0x2f: ret = virge->virge_rev; break; + case 0x2f: ret = virge->virge_rev; break; case 0x30: ret = virge->virge_id; break; /*Chip ID*/ case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break; + case 0x33: ret = (svga->crtc[0x33] | 0x04); break; case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break; - case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/ case 0x45: virge->hwc_col_stack_pos = 0; ret = svga->crtc[0x45]; break; case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break; + case 0x5c: /* General Output Port Register */ + ret = svga->crtc[svga->crtcreg] & 0xa0; + if (((svga->miscout >> 2) & 3) == 3) + ret |= svga->crtc[0x42] & 0x0f; + else + ret |= ((svga->miscout >> 2) & 3); + if ((ret & 0xa0) == 0xa0) { + if ((svga->crtc[0x5c] & 0x40) && i2c_gpio_get_scl(virge->i2c)) + ret |= 0x40; + if ((svga->crtc[0x5c] & 0x10) && i2c_gpio_get_sda(virge->i2c)) + ret |= 0x10; + } + break; case 0x69: ret = virge->ma_ext; break; case 0x6a: ret = virge->bank; break; - default: ret = svga->crtc[svga->crtcreg]; break; + + case 0xaa: /* DDC */ + if (virge->chip >= S3_VIRGEGX2) { + ret = svga->crtc[0xaa] & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); + if ((svga->crtc[0xaa] & SERIAL_PORT_SCW) && i2c_gpio_get_scl(virge->i2c)) + ret |= SERIAL_PORT_SCR; + if ((svga->crtc[0xaa] & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c)) + ret |= SERIAL_PORT_SDR; + break; + } else + ret = svga->crtc[0xaa]; + break; + + default: + ret = svga->crtc[svga->crtcreg]; + break; } break; - + default: ret = svga_in(addr, svga); - break; + break; } return ret; } @@ -586,8 +743,13 @@ static void s3_virge_recalctimings(svga_t *svga) { virge_t *virge = (virge_t *)svga->p; - if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; - if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100; + svga->hdisp = svga->hdisp_old; + + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) { + svga->hdisp_time += 0x100; + svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; @@ -595,6 +757,24 @@ static void s3_virge_recalctimings(svga_t *svga) if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; svga->interlace = svga->crtc[0x42] & 0x20; + if (((svga->miscout >> 2) & 3) == 3) { + int n = svga->seqregs[0x12] & 0x1f; + int r = (svga->seqregs[0x12] >> 5); + + if (virge->chip == S3_VIRGEVX || virge->chip == S3_VIRGEDX) + r &= 7; + else if (virge->chip >= S3_VIRGEGX2) + r &= 10; + else + r &= 3; + + int m = svga->seqregs[0x13] & 0x7f; + double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; + + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; + } + + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ { svga->ma_latch |= (virge->ma_ext << 16); @@ -602,41 +782,40 @@ static void s3_virge_recalctimings(svga_t *svga) else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; if (!svga->rowoffset) svga->rowoffset = 256; - if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) - { - switch (svga->bpp) - { - case 8: - svga->render = svga_render_8bpp_highres; + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) { + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; break; - case 15: - svga->render = svga_render_15bpp_highres; + case 15: + svga->render = svga_render_15bpp_highres; + if (virge->chip != S3_VIRGEVX && virge->chip < S3_VIRGEGX2) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } break; - case 16: - svga->render = svga_render_16bpp_highres; + case 16: + svga->render = svga_render_16bpp_highres; + if (virge->chip != S3_VIRGEVX && virge->chip < S3_VIRGEGX2) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } break; - case 24: - svga->render = svga_render_24bpp_highres; + case 24: + svga->render = svga_render_24bpp_highres; + if (virge->chip != S3_VIRGEVX && virge->chip < S3_VIRGEGX2) + svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ break; - case 32: - svga->render = svga_render_32bpp_highres; + case 32: + svga->render = svga_render_32bpp_highres; break; } } - - if (virge->chip != S3_VIRGEVX) - { - if ((svga->bpp == 15) || (svga->bpp == 16)) - { - svga->htotal >>= 1; - svga->hdisp >>= 1; - } - if (svga->bpp == 24) - { - svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ - } - } - svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : ((virge->memory_size << 20) - 1); + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; + s3_virge_log("VGA mode\n"); } else /*Streams mode*/ { @@ -644,14 +823,14 @@ static void s3_virge_recalctimings(svga_t *svga) svga->ma_latch = virge->streams.pri_fb1 >> 2; else svga->ma_latch = virge->streams.pri_fb0 >> 2; - + svga->hdisp = virge->streams.pri_w + 1; if (virge->streams.pri_h < svga->dispend) svga->dispend = virge->streams.pri_h; - + svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; - svga->overlay.ysize = virge->streams.sec_h; + svga->overlay.cur_ysize = virge->streams.sec_h; if (virge->streams.buffer_ctrl & 2) svga->overlay.addr = virge->streams.sec_fb1; @@ -665,34 +844,24 @@ static void s3_virge_recalctimings(svga_t *svga) switch ((virge->streams.pri_ctrl >> 24) & 0x7) { case 0: /*RGB-8 (CLUT)*/ - svga->render = svga_render_8bpp_highres; + svga->render = svga_render_8bpp_highres; break; - case 3: /*KRGB-16 (1.5.5.5)*/ + case 3: /*KRGB-16 (1.5.5.5)*/ svga->htotal >>= 1; - svga->render = svga_render_15bpp_highres; + svga->render = svga_render_15bpp_highres; break; - case 5: /*RGB-16 (5.6.5)*/ + case 5: /*RGB-16 (5.6.5)*/ svga->htotal >>= 1; - svga->render = svga_render_16bpp_highres; + svga->render = svga_render_16bpp_highres; break; - case 6: /*RGB-24 (8.8.8)*/ - svga->render = svga_render_24bpp_highres; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; break; case 7: /*XRGB-32 (X.8.8.8)*/ - svga->render = svga_render_32bpp_highres; + svga->render = svga_render_32bpp_highres; break; } - svga->vram_display_mask = (virge->memory_size << 20) - 1; - } - - if (((svga->miscout >> 2) & 3) == 3) - { - int n = svga->seqregs[0x12] & 0x1f; - int r = (svga->seqregs[0x12] >> 5) & (((virge->chip == S3_VIRGEVX) || (virge->chip == S3_VIRGEDX)) ? 7 : 3); - int m = svga->seqregs[0x13] & 0x7f; - double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; - - svga->clock = (cpuclock * (float)(1ull << 32)) / freq; + svga->vram_display_mask = virge->vram_mask; } } @@ -709,34 +878,32 @@ static void s3_virge_updatemapping(virge_t *virge) return; } - s3_virge_log("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); - switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ - { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); - svga->banked_mask = 0xffff; - break; - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - svga->banked_mask = 0xffff; - break; - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - svga->banked_mask = 0x7fff; - break; - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - svga->banked_mask = 0x7fff; - break; - } - - virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); - - s3_virge_log("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); - if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ - { - switch (svga->crtc[0x58] & 3) - { + s3_virge_log("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + /*Banked framebuffer*/ + switch (svga->gdcreg[6] & 0xc) { /*VGA mapping*/ + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + + s3_virge_log("Linear framebuffer %02X, linear base = %08x, display mask = %08x\n", svga->crtc[0x58] & 0x17, virge->linear_base, svga->vram_display_mask); + if ((svga->crtc[0x58] & 0x10) || (virge->advfunc_cntl & 0x10)) { /*Linear framebuffer*/ + switch (svga->crtc[0x58] & 7) { case 0: /*64k*/ virge->linear_size = 0x10000; break; @@ -746,33 +913,41 @@ static void s3_virge_updatemapping(virge_t *virge) case 2: /*2mb*/ virge->linear_size = 0x200000; break; - case 3: /*8mb*/ - virge->linear_size = 0x400000; + case 3: /*4mb on other than ViRGE/VX, 8mb on ViRGE/VX*/ + if (virge->chip == S3_VIRGEVX || virge->chip == S3_TRIO3D2X) + virge->linear_size = 0x800000; + else + virge->linear_size = 0x400000; break; + case 7: + virge->linear_size = 0x800000; + break; } virge->linear_base &= ~(virge->linear_size - 1); - s3_virge_log("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); - if (virge->linear_base == 0xa0000) - { - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - mem_mapping_disable(&virge->linear_mapping); - } - else - mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size); - svga->fb_only = 1; - } - else - { + s3_virge_log("Linear framebuffer at %08X size %08X, mask = %08x, CRTC58 sel = %02x\n", virge->linear_base, virge->linear_size, virge->vram_mask, svga->crtc[0x58] & 7); + if (virge->linear_base == 0xa0000) { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&virge->linear_mapping); + } else { + if (virge->chip == S3_VIRGEVX || virge->chip == S3_TRIO3D2X) { + virge->linear_base &= 0xfe000000; + } else { + virge->linear_base &= 0xfc000000; + } + + mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size); + } + svga->fb_only = 1; + } else { mem_mapping_disable(&virge->linear_mapping); - svga->fb_only = 0; + svga->fb_only = 0; } - - s3_virge_log("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18); + + s3_virge_log("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x38); /* Memory mapped I/O. */ - /* Old MMIO. */ - if (svga->crtc[0x53] & 0x10) { + if ((svga->crtc[0x53] & 0x10) || (virge->advfunc_cntl & 0x20)) { if (svga->crtc[0x53] & 0x20) mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); else @@ -781,13 +956,14 @@ static void s3_virge_updatemapping(virge_t *virge) mem_mapping_disable(&virge->mmio_mapping); /* New MMIO. */ - if (svga->crtc[0x53] & 0x08) /*New MMIO*/ + if (svga->crtc[0x53] & 0x08) mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); else mem_mapping_disable(&virge->new_mmio_mapping); } -static void s3_virge_vblank_start(svga_t *svga) +static void +s3_virge_vblank_start(svga_t *svga) { virge_t *virge = (virge_t *)svga->p; @@ -795,606 +971,396 @@ static void s3_virge_vblank_start(svga_t *svga) s3_virge_update_irqs(virge); } -static void s3_virge_wait_fifo_idle(virge_t *virge) + +static void +s3_virge_mmio_fifo_write(uint32_t addr, uint8_t val, virge_t *virge) { - while (!FIFO_EMPTY) - { - wake_fifo_thread(virge); - thread_wait_event(virge->fifo_not_full_event, 1); - } + if ((addr & 0xffff) < 0x8000) { + s3_virge_bitblt(virge, 8, val); + } else { + switch (addr & 0xffff) { + case 0x859c: + virge->cmd_dma = val; + break; + } + } } -static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) +static void +s3_virge_mmio_fifo_write_w(uint32_t addr, uint16_t val, virge_t *virge) +{ + if ((addr & 0xfffe) < 0x8000) { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } else { + if ((addr & 0xfffe) == 0x859c) + virge->cmd_dma = val; + } +} + +static void +s3_virge_mmio_fifo_write_l(uint32_t addr, uint32_t val, virge_t *virge) +{ + if ((addr & 0xfffc) < 0x8000) { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } else { + virge->fifo_slot++; + switch (addr & 0xfffc) { + case 0x8590: + virge->cmd_dma_base = val; + break; + + case 0x8594: + virge->dma_ptr = val; + break; + + case 0x8598: + break; + + case 0x859c: + virge->cmd_dma = val; + break; + + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = addr & 4; + int y = (addr >> 3) & 7; + int color, xx; + int byte; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + addr &= 0x00ff; + for (xx = 0; xx < 4; xx++) { + x = ((addr + xx) / 3) % 8; + y = ((addr + xx) / 24) % 8; + color = ((addr + xx) % 3) << 3; + byte = (xx << 3); + virge->s3d.pattern_24[y*8 + x] &= ~(0xff << color); + virge->s3d.pattern_24[y*8 + x] |= ((val >> byte) & 0xff) << color; + } + + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = (virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8); + s3_virge_log("PortWrite = %04x, SRC Base = %08x, memsize = %i\n", addr & 0xfffc, val, virge->memory_size); + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = (virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8); + s3_virge_log("PortWrite = %04x, DST Base = %08x, memsize = %i\n", addr & 0xfffc, val, virge->memory_size); + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) { + s3_virge_bitblt(virge, -1, 0); + } + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) { + s3_virge_bitblt(virge, -1, 0); + } + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb0f4: case 0xb4f4: + virge->s3d_tri.fog_b = val & 0xff; + virge->s3d_tri.fog_g = (val >> 8) & 0xff; + virge->s3d_tri.fog_r = (val >> 16) & 0xff; + break; + case 0xb4d4: + virge->s3d_tri.z_base = (virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8); + break; + case 0xb4d8: + virge->s3d_tri.dest_base = (virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8); + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = (virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8); + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) { + queue_triangle(virge); + } + break; + } + } +} + +static uint8_t +s3_virge_mmio_read(uint32_t addr, void *p) { virge_t *virge = (virge_t *)p; - uint8_t ret; + uint8_t ret = 0xff; + + s3_virge_log("[%04X:%08X]: MMIO ReadB addr = %04x\n", CS, cpu_state.pc, addr & 0xffff); - reg_reads++; switch (addr & 0xffff) { case 0x8505: - if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) - ret = 0x10; - else - ret = 0x10 | (1 << 5); - if (!virge->virge_busy) - wake_fifo_thread(virge); + ret = 0; + if (virge->s3d_busy || virge->fifo_slot) { + ret = 0x10; + } else { + ret = 0x30; + } + if (virge->fifo_slot) + virge->fifo_slot--; return ret; - - case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: - case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: - case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: - case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: - case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: - case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: - case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: - case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: - case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: - case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: - case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: - case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: - return s3_virge_in(addr & 0x3ff, p); - } - return 0xff; -} -static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) -{ - reg_reads++; - switch (addr & 0xfffe) - { - default: - return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8); - } - return 0xffff; -} -static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) -{ - virge_t *virge = (virge_t *)p; - uint32_t ret = 0xffffffff; - reg_reads++; - switch (addr & 0xfffc) - { - case 0x8180: - ret = virge->streams.pri_ctrl; - break; - case 0x8184: - ret = virge->streams.chroma_ctrl; - break; - case 0x8190: - ret = virge->streams.sec_ctrl; - break; - case 0x8194: - ret = virge->streams.chroma_upper_bound; - break; - case 0x8198: - ret = virge->streams.sec_filter; - break; - case 0x81a0: - ret = virge->streams.blend_ctrl; - break; - case 0x81c0: - ret = virge->streams.pri_fb0; - break; - case 0x81c4: - ret = virge->streams.pri_fb1; - break; - case 0x81c8: - ret = virge->streams.pri_stride; - break; - case 0x81cc: - ret = virge->streams.buffer_ctrl; - break; - case 0x81d0: - ret = virge->streams.sec_fb0; - break; - case 0x81d4: - ret = virge->streams.sec_fb1; - break; - case 0x81d8: - ret = virge->streams.sec_stride; - break; - case 0x81dc: - ret = virge->streams.overlay_ctrl; - break; - case 0x81e0: - ret = virge->streams.k1_vert_scale; - break; - case 0x81e4: - ret = virge->streams.k2_vert_scale; - break; - case 0x81e8: - ret = virge->streams.dda_vert_accumulator; - break; - case 0x81ec: - ret = virge->streams.fifo_ctrl; - break; - case 0x81f0: - ret = virge->streams.pri_start; - break; - case 0x81f4: - ret = virge->streams.pri_size; - break; - case 0x81f8: - ret = virge->streams.sec_start; - break; - case 0x81fc: - ret = virge->streams.sec_size; - break; - - case 0x8504: - if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) - ret = (0x10 << 8); - else - ret = (0x10 << 8) | (1 << 13); - ret |= virge->subsys_stat; - if (!virge->virge_busy) - wake_fifo_thread(virge); - break; - case 0xa4d4: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.src_base; - break; - case 0xa4d8: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.dest_base; - break; - case 0xa4dc: - s3_virge_wait_fifo_idle(virge); - ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; - break; - case 0xa4e0: - s3_virge_wait_fifo_idle(virge); - ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; - break; - case 0xa4e4: - s3_virge_wait_fifo_idle(virge); - ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; - break; - case 0xa4e8: case 0xace8: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.mono_pat_0; - break; - case 0xa4ec: case 0xacec: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.mono_pat_1; - break; - case 0xa4f0: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.pat_bg_clr; - break; - case 0xa4f4: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.pat_fg_clr; - break; - case 0xa4f8: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.src_bg_clr; - break; - case 0xa4fc: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.src_fg_clr; - break; - case 0xa500: - s3_virge_wait_fifo_idle(virge); - ret = virge->s3d.cmd_set; - break; - case 0xa504: - s3_virge_wait_fifo_idle(virge); - ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; - break; - case 0xa508: - s3_virge_wait_fifo_idle(virge); - ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; - break; - case 0xa50c: - s3_virge_wait_fifo_idle(virge); - ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; - break; - - default: - ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16); - } - return ret; -} -static void fifo_thread(void *param) -{ - virge_t *virge = (virge_t *)param; - - while (1) - { - thread_set_event(virge->fifo_not_full_event); - thread_wait_event(virge->wake_fifo_thread, -1); - thread_reset_event(virge->wake_fifo_thread); - virge->virge_busy = 1; - while (!FIFO_EMPTY) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; - - switch (fifo->addr_type & FIFO_TYPE) - { - case FIFO_WRITE_BYTE: - if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) - s3_virge_bitblt(virge, 8, val); - break; - case FIFO_WRITE_WORD: - if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) - { - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); - else - s3_virge_bitblt(virge, 16, val); - } - break; - case FIFO_WRITE_DWORD: - if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) - { - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); - else - s3_virge_bitblt(virge, 32, val); - } - else - { - switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc) - { - case 0xa000: case 0xa004: case 0xa008: case 0xa00c: - case 0xa010: case 0xa014: case 0xa018: case 0xa01c: - case 0xa020: case 0xa024: case 0xa028: case 0xa02c: - case 0xa030: case 0xa034: case 0xa038: case 0xa03c: - case 0xa040: case 0xa044: case 0xa048: case 0xa04c: - case 0xa050: case 0xa054: case 0xa058: case 0xa05c: - case 0xa060: case 0xa064: case 0xa068: case 0xa06c: - case 0xa070: case 0xa074: case 0xa078: case 0xa07c: - case 0xa080: case 0xa084: case 0xa088: case 0xa08c: - case 0xa090: case 0xa094: case 0xa098: case 0xa09c: - case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: - case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: - case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: - case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: - case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: - case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: - case 0xa100: case 0xa104: case 0xa108: case 0xa10c: - case 0xa110: case 0xa114: case 0xa118: case 0xa11c: - case 0xa120: case 0xa124: case 0xa128: case 0xa12c: - case 0xa130: case 0xa134: case 0xa138: case 0xa13c: - case 0xa140: case 0xa144: case 0xa148: case 0xa14c: - case 0xa150: case 0xa154: case 0xa158: case 0xa15c: - case 0xa160: case 0xa164: case 0xa168: case 0xa16c: - case 0xa170: case 0xa174: case 0xa178: case 0xa17c: - case 0xa180: case 0xa184: case 0xa188: case 0xa18c: - case 0xa190: case 0xa194: case 0xa198: case 0xa19c: - case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: - case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: - case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: - case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: - case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: - case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: - { - int x = (fifo->addr_type & FIFO_ADDR) & 4; - int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7; - int color, xx; - int byte, addr; - - virge->s3d.pattern_8[y*8 + x] = val & 0xff; - virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; - virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; - virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; - - x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6; - y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7; - virge->s3d.pattern_16[y*8 + x] = val & 0xffff; - virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; - - addr = ((fifo->addr_type & FIFO_ADDR) & 0x00ff); - for (xx = 0; xx < 4; xx++) { - x = ((addr + xx) / 3) % 8; - y = ((addr + xx) / 24) % 8; - color = ((addr + xx) % 3) << 3; - byte = (xx << 3); - virge->s3d.pattern_24[y*8 + x] &= ~(0xff << color); - virge->s3d.pattern_24[y*8 + x] |= ((val >> byte) & 0xff) << color; - } - - x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7; - y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7; - virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; - } - break; - - case 0xa4d4: case 0xa8d4: - virge->s3d.src_base = val & 0x3ffff8; - break; - case 0xa4d8: case 0xa8d8: - virge->s3d.dest_base = val & 0x3ffff8; - break; - case 0xa4dc: case 0xa8dc: - virge->s3d.clip_l = (val >> 16) & 0x7ff; - virge->s3d.clip_r = val & 0x7ff; - break; - case 0xa4e0: case 0xa8e0: - virge->s3d.clip_t = (val >> 16) & 0x7ff; - virge->s3d.clip_b = val & 0x7ff; - break; - case 0xa4e4: case 0xa8e4: - virge->s3d.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; - break; - case 0xa4e8: case 0xace8: - virge->s3d.mono_pat_0 = val; - break; - case 0xa4ec: case 0xacec: - virge->s3d.mono_pat_1 = val; - break; - case 0xa4f0: case 0xacf0: - virge->s3d.pat_bg_clr = val; - break; - case 0xa4f4: case 0xa8f4: case 0xacf4: - virge->s3d.pat_fg_clr = val; - break; - case 0xa4f8: - virge->s3d.src_bg_clr = val; - break; - case 0xa4fc: - virge->s3d.src_fg_clr = val; - break; - case 0xa500: case 0xa900: - virge->s3d.cmd_set = val; - if (!(val & CMD_SET_AE)) - s3_virge_bitblt(virge, -1, 0); - break; - case 0xa504: - virge->s3d.r_width = (val >> 16) & 0x7ff; - virge->s3d.r_height = val & 0x7ff; - break; - case 0xa508: - virge->s3d.rsrc_x = (val >> 16) & 0x7ff; - virge->s3d.rsrc_y = val & 0x7ff; - break; - case 0xa50c: - virge->s3d.rdest_x = (val >> 16) & 0x7ff; - virge->s3d.rdest_y = val & 0x7ff; - if (virge->s3d.cmd_set & CMD_SET_AE) - s3_virge_bitblt(virge, -1, 0); - break; - case 0xa96c: - virge->s3d.lxend0 = (val >> 16) & 0x7ff; - virge->s3d.lxend1 = val & 0x7ff; - break; - case 0xa970: - virge->s3d.ldx = (int32_t)val; - break; - case 0xa974: - virge->s3d.lxstart = val; - break; - case 0xa978: - virge->s3d.lystart = val & 0x7ff; - break; - case 0xa97c: - virge->s3d.lycnt = val & 0x7ff; - virge->s3d.line_dir = val >> 31; - if (virge->s3d.cmd_set & CMD_SET_AE) - s3_virge_bitblt(virge, -1, 0); - break; - - case 0xad00: - virge->s3d.cmd_set = val; - if (!(val & CMD_SET_AE)) - s3_virge_bitblt(virge, -1, 0); - break; - case 0xad68: - virge->s3d.prdx = val; - break; - case 0xad6c: - virge->s3d.prxstart = val; - break; - case 0xad70: - virge->s3d.pldx = val; - break; - case 0xad74: - virge->s3d.plxstart = val; - break; - case 0xad78: - virge->s3d.pystart = val & 0x7ff; - break; - case 0xad7c: - virge->s3d.pycnt = val & 0x300007ff; - if (virge->s3d.cmd_set & CMD_SET_AE) - s3_virge_bitblt(virge, -1, 0); - break; - - case 0xb4d4: - virge->s3d_tri.z_base = val & 0x3ffff8; - break; - case 0xb4d8: - virge->s3d_tri.dest_base = val & 0x3ffff8; - break; - case 0xb4dc: - virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; - virge->s3d_tri.clip_r = val & 0x7ff; - break; - case 0xb4e0: - virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; - virge->s3d_tri.clip_b = val & 0x7ff; - break; - case 0xb4e4: - virge->s3d_tri.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; - break; - case 0xb4e8: - virge->s3d_tri.z_str = val & 0xff8; - break; - case 0xb4ec: - virge->s3d_tri.tex_base = val & 0x3ffff8; - break; - case 0xb4f0: - virge->s3d_tri.tex_bdr_clr = val & 0xffffff; - break; - case 0xb500: - virge->s3d_tri.cmd_set = val; - if (!(val & CMD_SET_AE)) - queue_triangle(virge); - break; - case 0xb504: - virge->s3d_tri.tbv = val & 0xfffff; - break; - case 0xb508: - virge->s3d_tri.tbu = val & 0xfffff; - break; - case 0xb50c: - virge->s3d_tri.TdWdX = val; - break; - case 0xb510: - virge->s3d_tri.TdWdY = val; - break; - case 0xb514: - virge->s3d_tri.tws = val; - break; - case 0xb518: - virge->s3d_tri.TdDdX = val; - break; - case 0xb51c: - virge->s3d_tri.TdVdX = val; - break; - case 0xb520: - virge->s3d_tri.TdUdX = val; - break; - case 0xb524: - virge->s3d_tri.TdDdY = val; - break; - case 0xb528: - virge->s3d_tri.TdVdY = val; - break; - case 0xb52c: - virge->s3d_tri.TdUdY = val; - break; - case 0xb530: - virge->s3d_tri.tds = val; - break; - case 0xb534: - virge->s3d_tri.tvs = val; - break; - case 0xb538: - virge->s3d_tri.tus = val; - break; - case 0xb53c: - virge->s3d_tri.TdGdX = val >> 16; - virge->s3d_tri.TdBdX = val & 0xffff; - break; - case 0xb540: - virge->s3d_tri.TdAdX = val >> 16; - virge->s3d_tri.TdRdX = val & 0xffff; - break; - case 0xb544: - virge->s3d_tri.TdGdY = val >> 16; - virge->s3d_tri.TdBdY = val & 0xffff; - break; - case 0xb548: - virge->s3d_tri.TdAdY = val >> 16; - virge->s3d_tri.TdRdY = val & 0xffff; - break; - case 0xb54c: - virge->s3d_tri.tgs = (val >> 16) & 0xffff; - virge->s3d_tri.tbs = val & 0xffff; - break; - case 0xb550: - virge->s3d_tri.tas = (val >> 16) & 0xffff; - virge->s3d_tri.trs = val & 0xffff; - break; - - case 0xb554: - virge->s3d_tri.TdZdX = val; - break; - case 0xb558: - virge->s3d_tri.TdZdY = val; - break; - case 0xb55c: - virge->s3d_tri.tzs = val; - break; - case 0xb560: - virge->s3d_tri.TdXdY12 = val; - break; - case 0xb564: - virge->s3d_tri.txend12 = val; - break; - case 0xb568: - virge->s3d_tri.TdXdY01 = val; - break; - case 0xb56c: - virge->s3d_tri.txend01 = val; - break; - case 0xb570: - virge->s3d_tri.TdXdY02 = val; - break; - case 0xb574: - virge->s3d_tri.txs = val; - break; - case 0xb578: - virge->s3d_tri.tys = val; - break; - case 0xb57c: - virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; - virge->s3d_tri.ty12 = val & 0x7ff; - virge->s3d_tri.tlr = val >> 31; - if (virge->s3d_tri.cmd_set & CMD_SET_AE) - queue_triangle(virge); - break; - } - } - break; - } - - virge->fifo_read_idx++; - fifo->addr_type = FIFO_INVALID; - - if (FIFO_ENTRIES > 0xe000) - thread_set_event(virge->fifo_not_full_event); - - end_time = plat_timer_read(); - virge_time += end_time - start_time; - } - virge->virge_busy = 0; - } -} - -static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) -{ - fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; - - if (FIFO_FULL) - { - thread_reset_event(virge->fifo_not_full_event); - if (FIFO_FULL) - { - thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ - } - } - - fifo->val = val; - fifo->addr_type = (addr & FIFO_ADDR) | type; - - virge->fifo_write_idx++; - - /* if (FIFO_ENTRIES > 0xe000) - wake_fifo_thread(virge); */ - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) - wake_fifo_thread(virge); -} - -static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) -{ - virge_t *virge = (virge_t *)p; - - reg_writes++; - if ((addr & 0xfffc) < 0x8000) - { - s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); - } - else switch (addr & 0xffff) - { case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: @@ -1407,504 +1373,423 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: - s3_virge_out(addr & 0x3ff, val, p); - break; - } + return s3_virge_in(addr & 0x3ff, virge); - + case 0x859c: + return virge->cmd_dma; + + case 0xff20: case 0xff21: + ret = virge->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); + if ((virge->serialport & SERIAL_PORT_SCW) && i2c_gpio_get_scl(virge->i2c)) + ret |= SERIAL_PORT_SCR; + if ((virge->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c)) + ret |= SERIAL_PORT_SDR; + return ret; + } + return 0xff; } -static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) +static uint16_t +s3_virge_mmio_read_w(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint16_t ret = 0xffff; + + s3_virge_log("[%04X:%08X]: MMIO ReadW addr = %04x\n", CS, cpu_state.pc, addr & 0xfffe); + + switch (addr & 0xfffe) { + case 0x8504: + if (!virge->fifo_slot) + virge->subsys_stat |= INT_FIFO_EMP; + ret |= virge->subsys_stat; + if (virge->fifo_slot) + virge->fifo_slot--; + ret |= 0x30; /*A bit of a workaround at the moment.*/ + s3_virge_update_irqs(virge); + return ret; + + case 0x859c: + return virge->cmd_dma; + + default: + return s3_virge_mmio_read(addr, virge) | + (s3_virge_mmio_read(addr + 1, virge) << 8); + } + + return 0xffff; +} + +static uint32_t +s3_virge_mmio_read_l(uint32_t addr, void *p) { virge_t *virge = (virge_t *)p; - reg_writes++; - if ((addr & 0xfffc) < 0x8000) - { - s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); - } - else switch (addr & 0xfffe) - { - case 0x83d4: - s3_virge_mmio_write(addr, val, p); - s3_virge_mmio_write(addr + 1, val >> 8, p); - break; - } -} -static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) -{ - virge_t *virge = (virge_t *)p; - svga_t *svga = &virge->svga; - reg_writes++; + uint32_t ret = 0xffffffff; - if ((addr & 0xfffc) < 0x8000) - { - if ((addr & 0xe000) == 0) - { - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); - else - s3_virge_bitblt(virge, 32, val); - } - else - { - s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); - } - } - else switch (addr & 0xfffc) - { - case 0: - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); - else - s3_virge_bitblt(virge, 32, val); + s3_virge_log("[%04X:%08X]: MMIO ReadL addr = %04x\n", CS, cpu_state.pc, addr & 0xfffc); + + switch (addr & 0xfffc) { + case 0x8180: + ret = virge->streams.pri_ctrl; + break; + case 0x8184: + ret = virge->streams.chroma_ctrl; + break; + case 0x8190: + ret = virge->streams.sec_ctrl; + break; + case 0x8194: + ret = virge->streams.chroma_upper_bound; + break; + case 0x8198: + ret = virge->streams.sec_filter; + break; + case 0x81a0: + ret = virge->streams.blend_ctrl; + break; + case 0x81c0: + ret = virge->streams.pri_fb0; + break; + case 0x81c4: + ret = virge->streams.pri_fb1; + break; + case 0x81c8: + ret = virge->streams.pri_stride; + break; + case 0x81cc: + ret = virge->streams.buffer_ctrl; + break; + case 0x81d0: + ret = virge->streams.sec_fb0; + break; + case 0x81d4: + ret = virge->streams.sec_fb1; + break; + case 0x81d8: + ret = virge->streams.sec_stride; + break; + case 0x81dc: + ret = virge->streams.overlay_ctrl; + break; + case 0x81e0: + ret = virge->streams.k1_vert_scale; + break; + case 0x81e4: + ret = virge->streams.k2_vert_scale; + break; + case 0x81e8: + ret = virge->streams.dda_vert_accumulator; + break; + case 0x81ec: + ret = virge->streams.fifo_ctrl; + break; + case 0x81f0: + ret = virge->streams.pri_start; + break; + case 0x81f4: + ret = virge->streams.pri_size; + break; + case 0x81f8: + ret = virge->streams.sec_start; + break; + case 0x81fc: + ret = virge->streams.sec_size; + break; + + case 0x8504: + if (virge->s3d_busy || virge->fifo_slot) { + ret = (0x10 << 8); + } else { + ret = (0x10 << 8) | (1 << 13); + if (!virge->s3d_busy) + virge->subsys_stat |= INT_3DF_EMP; + if (!virge->fifo_slot) + virge->subsys_stat |= INT_FIFO_EMP; + } + ret |= virge->subsys_stat; + if (virge->fifo_slot) + virge->fifo_slot--; + s3_virge_update_irqs(virge); + break; + + case 0x8590: + ret = virge->cmd_dma_base; + break; + case 0x8594: + break; + case 0x8598: + ret = virge->dma_ptr; + break; + case 0x859c: + ret = virge->cmd_dma; + break; + + case 0xa4d4: + ret = virge->s3d.src_base; + break; + case 0xa4d8: + ret = virge->s3d.dest_base; + break; + case 0xa4dc: + ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; + break; + case 0xa4e0: + ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; + break; + case 0xa4e4: + ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; + break; + case 0xa4e8: case 0xace8: + ret = virge->s3d.mono_pat_0; + break; + case 0xa4ec: case 0xacec: + ret = virge->s3d.mono_pat_1; + break; + case 0xa4f0: + ret = virge->s3d.pat_bg_clr; + break; + case 0xa4f4: + ret = virge->s3d.pat_fg_clr; + break; + case 0xa4f8: + ret = virge->s3d.src_bg_clr; + break; + case 0xa4fc: + ret = virge->s3d.src_fg_clr; + break; + case 0xa500: + ret = virge->s3d.cmd_set; + break; + case 0xa504: + ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; + break; + case 0xa508: + ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; + break; + case 0xa50c: + ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; + break; + + default: + ret = s3_virge_mmio_read(addr, virge) | + (s3_virge_mmio_read(addr + 1, virge) << 8) | + (s3_virge_mmio_read(addr + 2, virge) << 16) | + (s3_virge_mmio_read(addr + 3, virge) << 24); + break; + } + + s3_virge_log("MMIO ReadL addr = %04x, val = %08x\n", addr & 0xfffc, ret); + return ret; +} + +static void +s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + s3_virge_log("MMIO WriteB addr = %04x, val = %02x\n", addr & 0xffff, val); + if (((addr & 0xffff) >= 0x8590) || ((addr & 0xffff) < 0x8000)) { + if ((addr & 0xffff) == 0xff20) { + virge->serialport = val; + i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); + } else + s3_virge_mmio_fifo_write(addr, val, virge); + } else { + switch (addr & 0xffff) { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + s3_virge_out(addr & 0x3ff, val, virge); break; - - case 0x8180: - virge->streams.pri_ctrl = val; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x8184: - virge->streams.chroma_ctrl = val; - break; - case 0x8190: - virge->streams.sec_ctrl = val; - virge->streams.dda_horiz_accumulator = val & 0xfff; - if (val & (1 << 11)) - virge->streams.dda_horiz_accumulator |= 0xfffff800; - virge->streams.sdif = (val >> 24) & 7; - break; - case 0x8194: - virge->streams.chroma_upper_bound = val; - break; - case 0x8198: - virge->streams.sec_filter = val; - virge->streams.k1_horiz_scale = val & 0x7ff; - if (val & (1 << 10)) - virge->streams.k1_horiz_scale |= 0xfffff800; - virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; - if ((val >> 16) & (1 << 10)) - virge->streams.k2_horiz_scale |= 0xfffff800; - break; - case 0x81a0: - virge->streams.blend_ctrl = val; - break; - case 0x81c0: - virge->streams.pri_fb0 = val & 0x3fffff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81c4: - virge->streams.pri_fb1 = val & 0x3fffff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81c8: - virge->streams.pri_stride = val & 0xfff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81cc: - virge->streams.buffer_ctrl = val; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81d0: - virge->streams.sec_fb0 = val; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81d4: - virge->streams.sec_fb1 = val; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81d8: - virge->streams.sec_stride = val; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81dc: - virge->streams.overlay_ctrl = val; - break; - case 0x81e0: - virge->streams.k1_vert_scale = val & 0x7ff; - if (val & (1 << 10)) - virge->streams.k1_vert_scale |= 0xfffff800; - break; - case 0x81e4: - virge->streams.k2_vert_scale = val & 0x7ff; - if (val & (1 << 10)) - virge->streams.k2_vert_scale |= 0xfffff800; - break; - case 0x81e8: - virge->streams.dda_vert_accumulator = val & 0xfff; - if (val & (1 << 11)) - virge->streams.dda_vert_accumulator |= 0xfffff800; - break; - case 0x81ec: - virge->streams.fifo_ctrl = val; - break; - case 0x81f0: - virge->streams.pri_start = val; - virge->streams.pri_x = (val >> 16) & 0x7ff; - virge->streams.pri_y = val & 0x7ff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81f4: - virge->streams.pri_size = val; - virge->streams.pri_w = (val >> 16) & 0x7ff; - virge->streams.pri_h = val & 0x7ff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81f8: - virge->streams.sec_start = val; - virge->streams.sec_x = (val >> 16) & 0x7ff; - virge->streams.sec_y = val & 0x7ff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; - case 0x81fc: - virge->streams.sec_size = val; - virge->streams.sec_w = (val >> 16) & 0x7ff; - virge->streams.sec_h = val & 0x7ff; - svga_recalctimings(svga); - svga->fullchange = changeframecount; - break; + } + } +} - case 0x8504: - virge->subsys_stat &= ~(val & 0xff); - virge->subsys_cntl = (val >> 8); - s3_virge_update_irqs(virge); - break; - - case 0xa000: case 0xa004: case 0xa008: case 0xa00c: - case 0xa010: case 0xa014: case 0xa018: case 0xa01c: - case 0xa020: case 0xa024: case 0xa028: case 0xa02c: - case 0xa030: case 0xa034: case 0xa038: case 0xa03c: - case 0xa040: case 0xa044: case 0xa048: case 0xa04c: - case 0xa050: case 0xa054: case 0xa058: case 0xa05c: - case 0xa060: case 0xa064: case 0xa068: case 0xa06c: - case 0xa070: case 0xa074: case 0xa078: case 0xa07c: - case 0xa080: case 0xa084: case 0xa088: case 0xa08c: - case 0xa090: case 0xa094: case 0xa098: case 0xa09c: - case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: - case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: - case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: - case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: - case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: - case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: - case 0xa100: case 0xa104: case 0xa108: case 0xa10c: - case 0xa110: case 0xa114: case 0xa118: case 0xa11c: - case 0xa120: case 0xa124: case 0xa128: case 0xa12c: - case 0xa130: case 0xa134: case 0xa138: case 0xa13c: - case 0xa140: case 0xa144: case 0xa148: case 0xa14c: - case 0xa150: case 0xa154: case 0xa158: case 0xa15c: - case 0xa160: case 0xa164: case 0xa168: case 0xa16c: - case 0xa170: case 0xa174: case 0xa178: case 0xa17c: - case 0xa180: case 0xa184: case 0xa188: case 0xa18c: - case 0xa190: case 0xa194: case 0xa198: case 0xa19c: - case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: - case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: - case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: - case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: - case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: - case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: - { - int x = addr & 4; - int y = (addr >> 3) & 7; - int color, xx; - int byte; - virge->s3d.pattern_8[y*8 + x] = val & 0xff; - virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; - virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; - virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; - - x = (addr >> 1) & 6; - y = (addr >> 4) & 7; - virge->s3d.pattern_16[y*8 + x] = val & 0xffff; - virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; +static void +s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + s3_virge_log("[%04X:%08X]: MMIO WriteW addr = %04x, val = %04x\n", CS, cpu_state.pc, addr & 0xfffe, val); + if (((addr & 0xfffe) >= 0x8590) || ((addr & 0xfffe) < 0x8000)) + if ((addr & 0xfffe) == 0xff20) + s3_virge_mmio_write(addr, val, virge); + else + s3_virge_mmio_fifo_write_w(addr, val, virge); + else { + if ((addr & 0xfffe) == 0x83d4) { + s3_virge_mmio_write(addr, val, virge); + s3_virge_mmio_write(addr + 1, val >> 8, virge); + } + } +} - addr &= 0x00ff; - for (xx = 0; xx < 4; xx++) { - x = ((addr + xx) / 3) % 8; - y = ((addr + xx) / 24) % 8; - color = ((addr + xx) % 3) << 3; - byte = (xx << 3); - virge->s3d.pattern_24[y*8 + x] &= ~(0xff << color); - virge->s3d.pattern_24[y*8 + x] |= ((val >> byte) & 0xff) << color; - } +static void +s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; - x = (addr >> 2) & 7; - y = (addr >> 5) & 7; - virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; - } - break; + s3_virge_log("[%04X:%08X]: MMIO WriteL addr = %04x, val = %04x\n", CS, cpu_state.pc, addr & 0xfffc, val); + if (((addr & 0xfffc) >= 0x8590) || ((addr & 0xfffc) < 0x8000)) + if ((addr & 0xfffc) == 0xff20) + s3_virge_mmio_write(addr, val, virge); + else { + s3_virge_mmio_fifo_write_l(addr, val, virge); + } + else { + switch (addr & 0xfffc) { + case 0x8180: + virge->streams.pri_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x8184: + virge->streams.chroma_ctrl = val; + break; + case 0x8190: + virge->streams.sec_ctrl = val; + virge->streams.dda_horiz_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_horiz_accumulator |= 0xfffff800; + virge->streams.sdif = (val >> 24) & 7; + break; + case 0x8194: + virge->streams.chroma_upper_bound = val; + break; + case 0x8198: + virge->streams.sec_filter = val; + virge->streams.k1_horiz_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_horiz_scale |= 0xfffff800; + virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; + if ((val >> 16) & (1 << 10)) + virge->streams.k2_horiz_scale |= 0xfffff800; + break; + case 0x81a0: + virge->streams.blend_ctrl = val; + break; + case 0x81c0: + virge->streams.pri_fb0 = val & 0x7fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c4: + virge->streams.pri_fb1 = val & 0x7fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c8: + virge->streams.pri_stride = val & 0xfff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81cc: + virge->streams.buffer_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d0: + virge->streams.sec_fb0 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d4: + virge->streams.sec_fb1 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d8: + virge->streams.sec_stride = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81dc: + virge->streams.overlay_ctrl = val; + break; + case 0x81e0: + virge->streams.k1_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_vert_scale |= 0xfffff800; + break; + case 0x81e4: + virge->streams.k2_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k2_vert_scale |= 0xfffff800; + break; + case 0x81e8: + virge->streams.dda_vert_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_vert_accumulator |= 0xfffff800; + break; + case 0x81ec: + virge->streams.fifo_ctrl = val; + break; + case 0x81f0: + virge->streams.pri_start = val; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f4: + virge->streams.pri_size = val; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f8: + virge->streams.sec_start = val; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81fc: + virge->streams.sec_size = val; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; - case 0xa4d4: case 0xa8d4: - virge->s3d.src_base = val & 0x3ffff8; - break; - case 0xa4d8: case 0xa8d8: - virge->s3d.dest_base = val & 0x3ffff8; - break; - case 0xa4dc: case 0xa8dc: - virge->s3d.clip_l = (val >> 16) & 0x7ff; - virge->s3d.clip_r = val & 0x7ff; - break; - case 0xa4e0: case 0xa8e0: - virge->s3d.clip_t = (val >> 16) & 0x7ff; - virge->s3d.clip_b = val & 0x7ff; - break; - case 0xa4e4: case 0xa8e4: - virge->s3d.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; - break; - case 0xa4e8: case 0xace8: - virge->s3d.mono_pat_0 = val; - break; - case 0xa4ec: case 0xacec: - virge->s3d.mono_pat_1 = val; - break; - case 0xa4f0: case 0xacf0: - virge->s3d.pat_bg_clr = val; - break; - case 0xa4f4: case 0xa8f4: case 0xacf4: - virge->s3d.pat_fg_clr = val; - break; - case 0xa4f8: - virge->s3d.src_bg_clr = val; - break; - case 0xa4fc: - virge->s3d.src_fg_clr = val; - break; - case 0xa500: case 0xa900: - virge->s3d.cmd_set = val; - if (!(val & CMD_SET_AE)) - s3_virge_bitblt(virge, -1, 0); - break; - case 0xa504: - virge->s3d.r_width = (val >> 16) & 0x7ff; - virge->s3d.r_height = val & 0x7ff; - break; - case 0xa508: - virge->s3d.rsrc_x = (val >> 16) & 0x7ff; - virge->s3d.rsrc_y = val & 0x7ff; - break; - case 0xa50c: - virge->s3d.rdest_x = (val >> 16) & 0x7ff; - virge->s3d.rdest_y = val & 0x7ff; - if (virge->s3d.cmd_set & CMD_SET_AE) - s3_virge_bitblt(virge, -1, 0); - break; - case 0xa96c: - virge->s3d.lxend0 = (val >> 16) & 0x7ff; - virge->s3d.lxend1 = val & 0x7ff; - break; - case 0xa970: - virge->s3d.ldx = (int32_t)val; - break; - case 0xa974: - virge->s3d.lxstart = val; - break; - case 0xa978: - virge->s3d.lystart = val & 0x7ff; - break; - case 0xa97c: - virge->s3d.lycnt = val & 0x7ff; - virge->s3d.line_dir = val >> 31; - if (virge->s3d.cmd_set & CMD_SET_AE) - s3_virge_bitblt(virge, -1, 0); - break; + case 0x8504: + virge->subsys_stat &= ~(val & 0xff); + virge->subsys_cntl = (val >> 8); + s3_virge_update_irqs(virge); + break; - case 0xad00: - virge->s3d.cmd_set = val; - if (!(val & CMD_SET_AE)) - s3_virge_bitblt(virge, -1, 0); - break; - case 0xad68: - virge->s3d.prdx = val; - break; - case 0xad6c: - virge->s3d.prxstart = val; - break; - case 0xad70: - virge->s3d.pldx = val; - break; - case 0xad74: - virge->s3d.plxstart = val; - break; - case 0xad78: - virge->s3d.pystart = val & 0x7ff; - break; - case 0xad7c: - virge->s3d.pycnt = val & 0x300007ff; - if (virge->s3d.cmd_set & CMD_SET_AE) - s3_virge_bitblt(virge, -1, 0); - break; - - case 0xb4d4: - virge->s3d_tri.z_base = val & 0x3ffff8; - break; - case 0xb4d8: - virge->s3d_tri.dest_base = val & 0x3ffff8; - break; - case 0xb4dc: - virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; - virge->s3d_tri.clip_r = val & 0x7ff; - break; - case 0xb4e0: - virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; - virge->s3d_tri.clip_b = val & 0x7ff; - break; - case 0xb4e4: - virge->s3d_tri.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; - break; - case 0xb4e8: - virge->s3d_tri.z_str = val & 0xff8; - break; - case 0xb4ec: - virge->s3d_tri.tex_base = val & 0x3ffff8; - break; - case 0xb4f0: - virge->s3d_tri.tex_bdr_clr = val & 0xffffff; - break; - case 0xb500: - virge->s3d_tri.cmd_set = val; - if (!(val & CMD_SET_AE)) - queue_triangle(virge); - break; - case 0xb504: - virge->s3d_tri.tbv = val & 0xfffff; - break; - case 0xb508: - virge->s3d_tri.tbu = val & 0xfffff; - break; - case 0xb50c: - virge->s3d_tri.TdWdX = val; - break; - case 0xb510: - virge->s3d_tri.TdWdY = val; - break; - case 0xb514: - virge->s3d_tri.tws = val; - break; - case 0xb518: - virge->s3d_tri.TdDdX = val; - break; - case 0xb51c: - virge->s3d_tri.TdVdX = val; - break; - case 0xb520: - virge->s3d_tri.TdUdX = val; - break; - case 0xb524: - virge->s3d_tri.TdDdY = val; - break; - case 0xb528: - virge->s3d_tri.TdVdY = val; - break; - case 0xb52c: - virge->s3d_tri.TdUdY = val; - break; - case 0xb530: - virge->s3d_tri.tds = val; - break; - case 0xb534: - virge->s3d_tri.tvs = val; - break; - case 0xb538: - virge->s3d_tri.tus = val; - break; - case 0xb53c: - virge->s3d_tri.TdGdX = val >> 16; - virge->s3d_tri.TdBdX = val & 0xffff; - break; - case 0xb540: - virge->s3d_tri.TdAdX = val >> 16; - virge->s3d_tri.TdRdX = val & 0xffff; - break; - case 0xb544: - virge->s3d_tri.TdGdY = val >> 16; - virge->s3d_tri.TdBdY = val & 0xffff; - break; - case 0xb548: - virge->s3d_tri.TdAdY = val >> 16; - virge->s3d_tri.TdRdY = val & 0xffff; - break; - case 0xb54c: - virge->s3d_tri.tgs = (val >> 16) & 0xffff; - virge->s3d_tri.tbs = val & 0xffff; - break; - case 0xb550: - virge->s3d_tri.tas = (val >> 16) & 0xffff; - virge->s3d_tri.trs = val & 0xffff; - break; - - case 0xb554: - virge->s3d_tri.TdZdX = val; - break; - case 0xb558: - virge->s3d_tri.TdZdY = val; - break; - case 0xb55c: - virge->s3d_tri.tzs = val; - break; - case 0xb560: - virge->s3d_tri.TdXdY12 = val; - break; - case 0xb564: - virge->s3d_tri.txend12 = val; - break; - case 0xb568: - virge->s3d_tri.TdXdY01 = val; - break; - case 0xb56c: - virge->s3d_tri.txend01 = val; - break; - case 0xb570: - virge->s3d_tri.TdXdY02 = val; - break; - case 0xb574: - virge->s3d_tri.txs = val; - break; - case 0xb578: - virge->s3d_tri.tys = val; - break; - case 0xb57c: - virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; - virge->s3d_tri.ty12 = val & 0x7ff; - virge->s3d_tri.tlr = val >> 31; - if (virge->s3d_tri.cmd_set & CMD_SET_AE) - queue_triangle(virge); - break; - } + case 0x850c: + virge->advfunc_cntl = val & 0xff; + s3_virge_updatemapping(virge); + break; + } + } } #define READ(addr, val) \ - do \ { \ switch (bpp) \ { \ case 0: /*8 bpp*/ \ - val = vram[addr & svga->vram_mask]; \ + val = vram[addr & virge->vram_mask]; \ break; \ case 1: /*16 bpp*/ \ - val = *(uint16_t *)&vram[addr & svga->vram_mask]; \ + val = *(uint16_t *)&vram[addr & virge->vram_mask]; \ break; \ case 2: /*24 bpp*/ \ - val = (*(uint32_t *)&vram[addr & svga->vram_mask]) & 0xffffff; \ + val = (*(uint32_t *)&vram[addr & virge->vram_mask]) & 0xffffff; \ break; \ } \ - } while (0) - -#define Z_READ(addr) *(uint16_t *)&vram[addr & svga->vram_mask] - -#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & svga->vram_mask] = val + } #define CLIP(x, y) \ - do \ { \ if ((virge->s3d.cmd_set & CMD_SET_HC) && \ (x < virge->s3d.clip_l || \ @@ -1912,10 +1797,9 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) y < virge->s3d.clip_t || \ y > virge->s3d.clip_b)) \ update = 0; \ - } while (0) + } #define CLIP_3D(x, y) \ - do \ { \ if ((s3d_tri->cmd_set & CMD_SET_HC) && \ (x < s3d_tri->clip_l || \ @@ -1923,27 +1807,10 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) y < s3d_tri->clip_t || \ y > s3d_tri->clip_b)) \ update = 0; \ - } while (0) + } + -#define Z_CLIP(Zzb, Zs) \ - do \ - { \ - if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ - switch ((s3d_tri->cmd_set >> 20) & 7) \ - { \ - case 0: update = 0; break; \ - case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break; \ - case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break; \ - case 3: if (Zs < Zzb) update = 0; else Zzb = Zs; break; \ - case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break; \ - case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break; \ - case 6: if (Zs > Zzb) update = 0; else Zzb = Zs; break; \ - case 7: update = 1; Zzb = Zs; break; \ - } \ - } while (0) - #define MIX() \ - do \ { \ int c; \ for (c = 0; c < 24; c++) \ @@ -1953,28 +1820,27 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) if (pattern & (1 << c)) d |= 4; \ if (virge->s3d.rop & (1 << d)) out |= (1 << c); \ } \ - } while (0) + } #define WRITE(addr, val) \ - do \ { \ switch (bpp) \ { \ case 0: /*8 bpp*/ \ - vram[addr & svga->vram_mask] = val; \ - virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + vram[addr & virge->vram_mask] = val; \ + svga->changedvram[(addr & virge->vram_mask) >> 12] = changeframecount; \ break; \ case 1: /*16 bpp*/ \ - *(uint16_t *)&vram[addr & svga->vram_mask] = val; \ - virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + *(uint16_t *)&vram[addr & virge->vram_mask] = val; \ + svga->changedvram[(addr & virge->vram_mask) >> 12] = changeframecount; \ break; \ case 2: /*24 bpp*/ \ - *(uint32_t *)&vram[addr & svga->vram_mask] = (val & 0xffffff) | \ - (vram[(addr + 3) & svga->vram_mask] << 24); \ - virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + *(uint32_t *)&vram[addr & virge->vram_mask] = (val & 0xffffff) | \ + (vram[(addr + 3) & virge->vram_mask] << 24); \ + svga->changedvram[(addr & virge->vram_mask) >> 12] = changeframecount; \ break; \ } \ - } while (0) + } static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) { @@ -1994,7 +1860,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0, dest = 0, pattern; uint32_t out = 0; int update; - + switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) { case CMD_SET_FORMAT_8: @@ -2014,7 +1880,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) src_bg_clr = virge->s3d.src_bg_clr & 0xffff; break; case CMD_SET_FORMAT_24: - default: + default: bpp = 2; x_mul = 3; cpu_dat_shift = 24; @@ -2025,7 +1891,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) } if (virge->s3d.cmd_set & CMD_SET_MP) pattern_data = mono_pattern; - + switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) { case CMD_SET_ITA_BYTE: @@ -2035,7 +1901,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) count_mask = ~0xf; break; case CMD_SET_ITA_DWORD: - default: + default: count_mask = ~0x1f; break; } @@ -2047,21 +1913,18 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) for (x = 0; x < 8; x++) { if (virge->s3d.mono_pat_0 & (1 << (x + y*8))) - mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr; + mono_pattern[y*8 + (7 - x)] = virge->s3d.pat_fg_clr; else - mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr; + mono_pattern[y*8 + (7 - x)] = virge->s3d.pat_bg_clr; if (virge->s3d.mono_pat_1 & (1 << (x + y*8))) - mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr; + mono_pattern[(y+4)*8 + (7 - x)] = virge->s3d.pat_fg_clr; else - mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr; + mono_pattern[(y+4)*8 + (7 - x)] = virge->s3d.pat_bg_clr; } } } switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) { - case CMD_SET_COMMAND_NOP: - break; - case CMD_SET_COMMAND_BITBLT: if (count == -1) { @@ -2073,8 +1936,8 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.h = virge->s3d.r_height; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; virge->s3d.data_left_count = 0; - - s3_virge_log("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n", + + s3_virge_log("BitBlt start src_x=%i,src_y=%i,dest_x=%i,dest_y=%i,w=%i,h=%i,rop=%02X,src_base=%x,dest_base=%x\n", virge->s3d.src_x, virge->s3d.src_y, virge->s3d.dest_x, @@ -2084,7 +1947,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.rop, virge->s3d.src_base, virge->s3d.dest_base); - + if (virge->s3d.cmd_set & CMD_SET_IDS) return; } @@ -2155,7 +2018,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) WRITE(dest_addr, out); } - + virge->s3d.src_x += x_inc; virge->s3d.src_x &= 0x7ff; virge->s3d.dest_x += x_inc; @@ -2169,7 +2032,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; virge->s3d.h--; - + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) { case CMD_SET_IDS: @@ -2189,10 +2052,10 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) } } else - virge->s3d.w--; + virge->s3d.w--; } break; - + case CMD_SET_COMMAND_RECTFILL: /*No source, pattern = pat_fg_clr*/ if (count == -1) @@ -2204,7 +2067,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.w = virge->s3d.r_width; virge->s3d.h = virge->s3d.r_height; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; - + s3_virge_log("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x, virge->s3d.dest_y, virge->s3d.w, @@ -2214,10 +2077,11 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) while (count && virge->s3d.h) { - uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); - uint32_t source = 0, dest = 0, pattern = virge->s3d.pat_fg_clr; - uint32_t out = 0; - int update = 1; + source = virge->s3d.pat_fg_clr; + dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + pattern = virge->s3d.pat_fg_clr; + out = 0; + update = 1; CLIP(virge->s3d.dest_x, virge->s3d.dest_y); @@ -2249,11 +2113,11 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) } } else - virge->s3d.w--; + virge->s3d.w--; count--; } break; - + case CMD_SET_COMMAND_LINE: if (count == -1) { @@ -2267,7 +2131,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) int x; int new_x; int first_pixel = 1; - + x = virge->s3d.dest_x >> 20; if (virge->s3d.h == virge->s3d.lycnt && @@ -2280,11 +2144,11 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) else new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; - + if ((virge->s3d.line_dir && x > new_x) || (!virge->s3d.line_dir && x < new_x)) goto skip_line; - + do { uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); @@ -2313,7 +2177,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) WRITE(dest_addr, out); } - + if (x < new_x) x++; else if (x > new_x) @@ -2359,7 +2223,7 @@ skip_line: WRITE(dest_addr, out); } - + x = (x + xdir) & 0x7ff; } while (x != (xend + xdir)); @@ -2371,8 +2235,8 @@ skip_line: } break; - default: - fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set); + case CMD_SET_COMMAND_NOP: + break; } } @@ -2408,21 +2272,21 @@ typedef struct s3d_state_t int32_t r, g, b, a, u, v, d, w; int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w; - + uint32_t base_z; uint32_t tbu, tbv; uint32_t cmd_set; int max_d; - + uint16_t *texture[10]; - + uint32_t tex_bdr_clr; - + int32_t x1, x2; int y; - + rgba_t dest_rgba; } s3d_state_t; @@ -2430,7 +2294,7 @@ typedef struct s3d_texture_state_t { int level; int texture_shift; - + int32_t u, v; } s3d_texture_state_t; @@ -2526,7 +2390,7 @@ static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture static void tex_sample_normal(s3d_state_t *state) { s3d_texture_state_t texture_state; - + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); texture_state.u = state->u + state->tbu; @@ -2564,12 +2428,12 @@ static void tex_sample_normal_filter(s3d_state_t *state) texture_state.u = state->u + state->tbu + tex_offset; texture_state.v = state->v + state->tbv + tex_offset; tex_read(state, &texture_state, &tex_samples[3]); - + d[0] = (256 - du) * (256 - dv); d[1] = du * (256 - dv); d[2] = (256 - du) * dv; d[3] = du * dv; - + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; @@ -2603,7 +2467,7 @@ static void tex_sample_mipmap_filter(s3d_state_t *state) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); tex_offset = 1 << texture_state.texture_shift; - + texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &tex_samples[0]); @@ -2626,7 +2490,7 @@ static void tex_sample_mipmap_filter(s3d_state_t *state) d[1] = du * (256 - dv); d[2] = (256 - du) * dv; d[3] = du * dv; - + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; @@ -2640,9 +2504,9 @@ static void tex_sample_persp_normal(s3d_state_t *state) if (state->w) w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); - + texture_state.level = state->max_d; - texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.texture_shift = 18 + (9 - texture_state.level); texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; @@ -2667,7 +2531,7 @@ static void tex_sample_persp_normal_filter(s3d_state_t *state) texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); tex_offset = 1 << texture_state.texture_shift; - + texture_state.u = u; texture_state.v = v; tex_read(state, &texture_state, &tex_samples[0]); @@ -2690,7 +2554,7 @@ static void tex_sample_persp_normal_filter(s3d_state_t *state) d[1] = du * (256 - dv); d[2] = (256 - du) * dv; d[3] = du * dv; - + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; @@ -2704,9 +2568,9 @@ static void tex_sample_persp_normal_375(s3d_state_t *state) if (state->w) w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); - + texture_state.level = state->max_d; - texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.texture_shift = 18 + (9 - texture_state.level); texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; @@ -2727,7 +2591,7 @@ static void tex_sample_persp_normal_filter_375(s3d_state_t *state) u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; - + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); tex_offset = 1 << texture_state.texture_shift; @@ -2754,7 +2618,7 @@ static void tex_sample_persp_normal_filter_375(s3d_state_t *state) d[1] = du * (256 - dv); d[2] = (256 - du) * dv; d[3] = du * dv; - + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; @@ -2769,7 +2633,7 @@ static void tex_sample_persp_mipmap(s3d_state_t *state) if (state->w) w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); - + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; @@ -2794,7 +2658,7 @@ static void tex_sample_persp_mipmap_filter(s3d_state_t *state) u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; - + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; @@ -2823,7 +2687,7 @@ static void tex_sample_persp_mipmap_filter(s3d_state_t *state) d[1] = du * (256 - dv); d[2] = (256 - du) * dv; d[3] = du * dv; - + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; @@ -2837,7 +2701,7 @@ static void tex_sample_persp_mipmap_375(s3d_state_t *state) if (state->w) w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); - + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; @@ -2862,13 +2726,13 @@ static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; - + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); tex_offset = 1 << texture_state.texture_shift; - + texture_state.u = u; texture_state.v = v; tex_read(state, &texture_state, &tex_samples[0]); @@ -2891,7 +2755,7 @@ static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) d[1] = du * (256 - dv); d[2] = (256 - du) * dv; d[3] = du * dv; - + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; @@ -2915,7 +2779,7 @@ static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) b = ((b) < 0) ? 0 : 0xff; \ if ((a) & ~0xff) \ a = ((a) < 0) ? 0 : 0xff; - + #define CLAMP_RGB(r, g, b) do \ { \ if ((r) < 0) \ @@ -2980,11 +2844,11 @@ static void dest_pixel_lit_texture_reflection(s3d_state_t *state) static void dest_pixel_lit_texture_modulate(s3d_state_t *state) { int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7; - + tex_sample(state); - + CLAMP_RGBA(r, g, b, a); - + state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8; state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8; state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8; @@ -2996,16 +2860,16 @@ static void dest_pixel_lit_texture_modulate(s3d_state_t *state) static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) { svga_t *svga = &virge->svga; - uint8_t *vram = svga->vram; + uint8_t *vram = (uint8_t *)svga->vram; int x_dir = s3d_tri->tlr ? 1 : -1; - + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); int y_count = yc; - + int bpp = (s3d_tri->cmd_set >> 2) & 7; - + uint32_t dest_offset = 0, z_offset = 0; uint32_t src_col; @@ -3015,7 +2879,8 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 int xe; uint32_t z; - uint32_t dest_addr, z_addr; + uint32_t dest_addr; + uint32_t z_addr; int dx; int x_offset; int xz_offset; @@ -3030,10 +2895,10 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (state->y > s3d_tri->clip_b) { int diff_y = state->y - s3d_tri->clip_b; - + if (diff_y > y_count) diff_y = y_count; - + state->base_u += (s3d_tri->TdUdY * diff_y); state->base_v += (s3d_tri->TdVdY * diff_y); state->base_z += (s3d_tri->TdZdY * diff_y); @@ -3046,7 +2911,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 state->x1 += (dx1 * diff_y); state->x2 += (dx2 * diff_y); state->y -= diff_y; - dest_offset -= s3d_tri->dest_str; + dest_offset -= s3d_tri->dest_str * diff_y; z_offset -= s3d_tri->z_str; y_count -= diff_y; } @@ -3056,16 +2921,16 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); - - for (; y_count > 0; y_count--) + + while (y_count > 0) { x = (state->x1 + ((1 << 20) - 1)) >> 20; xe = (state->x2 + ((1 << 20) - 1)) >> 20; z = (state->base_z > 0) ? (state->base_z << 1) : 0; if (x_dir < 0) { - x--; - xe--; + x--; + xe--; } if (((x != xe) && ((x_dir > 0) && (x < xe))) || ((x_dir < 0) && (x > xe))) @@ -3098,7 +2963,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (x < s3d_tri->clip_l) { int diff_x = s3d_tri->clip_l - x; - + z += (s3d_tri->TdZdX * diff_x); state->u += (s3d_tri->TdUdX * diff_x); state->v += (s3d_tri->TdVdX * diff_x); @@ -3108,7 +2973,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 state->a += (s3d_tri->TdAdX * diff_x); state->d += (s3d_tri->TdDdX * diff_x); state->w += (s3d_tri->TdWdX * diff_x); - + x = s3d_tri->clip_l; } } @@ -3123,7 +2988,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (x > s3d_tri->clip_r) { int diff_x = x - s3d_tri->clip_r; - + z += (s3d_tri->TdZdX * diff_x); state->u += (s3d_tri->TdUdX * diff_x); state->v += (s3d_tri->TdVdX * diff_x); @@ -3133,79 +2998,133 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 state->a += (s3d_tri->TdAdX * diff_x); state->d += (s3d_tri->TdDdX * diff_x); state->w += (s3d_tri->TdWdX * diff_x); - + x = s3d_tri->clip_r; } } } - virge->svga.changedvram[(dest_offset & svga->vram_mask) >> 12] = changeframecount; + svga->changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; dest_addr = dest_offset + (x * (bpp + 1)); z_addr = z_offset + (x << 1); x &= 0xfff; - xe &= 0xfff; - - for (; x != xe; x = (x + x_dir) & 0xfff) - { + xe &= 0xfff; + + while (x != xe) { update = 1; _x = x; _y = state->y; if (use_z) { - src_z = Z_READ(z_addr); - Z_CLIP(src_z, z >> 16); - } + src_z = *(uint16_t *)&vram[z_addr & virge->vram_mask]; + switch ((s3d_tri->cmd_set >> 20) & 7) { + case 0: + update = 0; + break; + case 1: + if ((z >> 16) > src_z) { + src_z = (z >> 16); + } else + update = 0; + break; + case 2: + if ((z >> 16) == src_z) { + src_z = (z >> 16); + } else + update = 0; + break; + case 3: + if ((z >> 16) >= src_z) { + src_z = (z >> 16); + } else + update = 0; + break; + case 4: + if ((z >> 16) < src_z) { + src_z = (z >> 16); + } else + update = 0; + break; + case 5: + if ((z >> 16) != src_z) { + src_z = (z >> 16); + } else + update = 0; + break; + case 6: + if ((z >> 16) <= src_z) { + src_z = (z >> 16); + } else + update = 0; + break; + case 7: + src_z = (z >> 16); + break; + } + } if (update) { - uint32_t dest_col; + uint32_t dest_col; - dest_pixel(state); + dest_pixel(state); - if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) - { - switch (bpp) - { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - src_col = *(uint16_t *)&vram[dest_addr & svga->vram_mask]; - RGB15_TO_24(src_col, src_r, src_g, src_b); - break; - case 2: /*24 bpp*/ - src_col = (*(uint32_t *)&vram[dest_addr & svga->vram_mask]) & 0xffffff; - RGB24_TO_24(src_col, src_r, src_g, src_b); - break; - } + if (s3d_tri->cmd_set & CMD_SET_FE) + { + int a = state->a >> 7; + state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; + } - state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; - } + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) + { + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *)&vram[dest_addr & virge->vram_mask]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *)&vram[dest_addr & virge->vram_mask]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } - switch (bpp) - { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); - *(uint16_t *)&vram[dest_addr] = dest_col; - break; - case 2: /*24 bpp*/ - dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); - *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; - *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; - *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; - break; - } + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } - if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) - Z_WRITE(z_addr, src_z); - } + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *)&vram[dest_addr & virge->vram_mask] = dest_col; + svga->changedvram[(dest_addr & virge->vram_mask) >> 12] = changeframecount; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *)&vram[dest_addr & virge->vram_mask] = dest_col & 0xff; + *(uint8_t *)&vram[(dest_addr + 1) & virge->vram_mask] = (dest_col >> 8) & 0xff; + *(uint8_t *)&vram[(dest_addr + 2) & virge->vram_mask] = (dest_col >> 16) & 0xff; + svga->changedvram[(dest_addr & virge->vram_mask) >> 12] = changeframecount; + break; + } + } + + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) { + *(uint16_t *)&vram[z_addr & virge->vram_mask] = src_z; + svga->changedvram[(z_addr & virge->vram_mask) >> 12] = changeframecount; + } z += s3d_tri->TdZdX; state->u += s3d_tri->TdUdX; @@ -3218,9 +3137,13 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 state->w += s3d_tri->TdWdX; dest_addr += x_offset; z_addr += xz_offset; - virge->pixel_count++; + + x = (x + x_dir) & 0xfff; } } + + y_count--; + tri_skip_line: state->x1 += dx1; state->x2 += dx2; @@ -3263,11 +3186,11 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) state.tbu = s3d_tri->tbu << 11; state.tbv = s3d_tri->tbv << 11; - + state.max_d = (s3d_tri->cmd_set >> 8) & 15; - + state.tex_bdr_clr = s3d_tri->tex_bdr_clr; - + state.cmd_set = s3d_tri->cmd_set; state.base_u = s3d_tri->tus; @@ -3279,7 +3202,7 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) state.base_a = (int32_t)s3d_tri->tas; state.base_d = s3d_tri->tds; state.base_w = s3d_tri->tws; - + tex_base = s3d_tri->tex_base; for (c = 9; c >= 0; c--) { @@ -3318,8 +3241,8 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) default: s3_virge_log("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); return; - } - + } + switch (((s3d_tri->cmd_set >> 12) & 7) | ((s3d_tri->cmd_set & (1 << 29)) ? 8 : 0)) { case 0: case 1: @@ -3335,31 +3258,31 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; break; case (0 | 8): case (1 | 8): - if (virge->chip == S3_VIRGEDX) + if (virge->chip == S3_VIRGEDX || virge->chip >= S3_VIRGEGX2) tex_sample = tex_sample_persp_mipmap_375; else tex_sample = tex_sample_persp_mipmap; break; case (2 | 8): case (3 | 8): - if (virge->chip == S3_VIRGEDX) + if (virge->chip == S3_VIRGEDX || virge->chip >= S3_VIRGEGX2) tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; else tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; break; case (4 | 8): case (5 | 8): - if (virge->chip == S3_VIRGEDX) + if (virge->chip == S3_VIRGEDX || virge->chip >= S3_VIRGEGX2) tex_sample = tex_sample_persp_normal_375; else tex_sample = tex_sample_persp_normal; break; case (6 | 8): case (7 | 8): - if (virge->chip == S3_VIRGEDX) + if (virge->chip == S3_VIRGEDX || virge->chip >= S3_VIRGEGX2) tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; else tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; break; } - + switch ((s3d_tri->cmd_set >> 5) & 7) { case 0: @@ -3384,48 +3307,9 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) state.x2 = s3d_tri->txend12; tri(virge, s3d_tri, &state, s3d_tri->ty12, s3d_tri->TdXdY02, s3d_tri->TdXdY12); - virge->tri_count++; - end_time = plat_timer_read(); - - virge_time += end_time - start_time; -} -static void render_thread(void *param) -{ - virge_t *virge = (virge_t *)param; - - while (1) - { - thread_wait_event(virge->wake_render_thread, -1); - thread_reset_event(virge->wake_render_thread); - virge->s3d_busy = 1; - while (!RB_EMPTY) - { - s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]); - virge->s3d_read_idx++; - - if (RB_ENTRIES == RB_SIZE - 1) - thread_set_event(virge->not_full_event); - } - virge->s3d_busy = 0; - virge->subsys_stat |= INT_S3D_DONE; - s3_virge_update_irqs(virge); - } -} - -static void queue_triangle(virge_t *virge) -{ - if (RB_FULL) - { - thread_reset_event(virge->not_full_event); - if (RB_FULL) - thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ - } - virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; - virge->s3d_write_idx++; - if (!virge->s3d_busy) - thread_set_event(virge->wake_render_thread); /*Wake up render thread if moving from idle*/ + virge->blitter_time += end_time - start_time; } static void s3_virge_hwcursor_draw(svga_t *svga, int displine) @@ -3436,22 +3320,23 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; uint32_t fg, bg; + uint32_t vram_mask = virge->vram_mask; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; switch (svga->bpp) - { + { case 15: fg = video_15to32[virge->hwc_fg_col & 0xffff]; bg = video_15to32[virge->hwc_bg_col & 0xffff]; break; - + case 16: fg = video_16to32[virge->hwc_fg_col & 0xffff]; bg = video_16to32[virge->hwc_bg_col & 0xffff]; break; - + case 24: case 32: fg = virge->hwc_fg_col; bg = virge->hwc_bg_col; @@ -3465,19 +3350,19 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) for (x = 0; x < 64; x += 16) { - dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; - dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + dat[0] = (svga->vram[svga->hwcursor_latch.addr & vram_mask] << 8) | svga->vram[(svga->hwcursor_latch.addr + 1) & vram_mask]; + dat[1] = (svga->vram[(svga->hwcursor_latch.addr + 2) & vram_mask] << 8) | svga->vram[(svga->hwcursor_latch.addr + 3) & vram_mask]; if (svga->crtc[0x55] & 0x10) { /*X11*/ for (xx = 0; xx < 16; xx++) { - if (offset >= svga->hwcursor_latch.x) + if (offset >= 0) { if (dat[0] & 0x8000) buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; } - + offset++; dat[0] <<= 1; dat[1] <<= 1; @@ -3488,14 +3373,14 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) /*Windows*/ for (xx = 0; xx < 16; xx++) { - if (offset >= svga->hwcursor_latch.x) + if (offset >= 0) { if (!(dat[0] & 0x8000)) buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; else if (dat[1] & 0x8000) buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; } - + offset++; dat[0] <<= 1; dat[1] <<= 1; @@ -3744,7 +3629,7 @@ static void s3_virge_overlay_draw(svga_t *svga, int displine) int x; uint32_t *p; uint8_t *src = &svga->vram[svga->overlay_latch.addr]; - + p = &(buffer32->line[displine][offset + svga->x_add]); if ((offset + virge->streams.sec_w) > virge->streams.pri_w) @@ -3753,7 +3638,7 @@ static void s3_virge_overlay_draw(svga_t *svga, int displine) x_size = virge->streams.sec_w + 1; OVERLAY_SAMPLE(); - + for (x = 0; x < x_size; x++) { *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); @@ -3781,44 +3666,71 @@ static uint8_t s3_virge_pci_read(int func, int addr, void *p) { virge_t *virge = (virge_t *)p; svga_t *svga = &virge->svga; - uint8_t ret = 0; - switch (addr) - { + uint8_t ret = 0; + + switch (addr) { case 0x00: ret = 0x33; break; /*'S3'*/ case 0x01: ret = 0x53; break; - + case 0x02: ret = virge->virge_id_low; break; case 0x03: ret = virge->virge_id_high; break; - case 0x04: ret = virge->pci_regs[0x04] & 0x27; break; - + case PCI_REG_COMMAND: ret = virge->pci_regs[PCI_REG_COMMAND] & 0x27; break; + case 0x07: ret = virge->pci_regs[0x07] & 0x36; break; - - case 0x08: ret = 0; break; /*Revision ID*/ + + case 0x08: ret = virge->virge_rev; break; /*Revision ID*/ case 0x09: ret = 0; break; /*Programming interface*/ - + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ - case 0x0b: ret = 0x03; /*output = 3; */break; + case 0x0b: ret = 0x03; break; case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break; - + case 0x10: ret = 0x00; break;/*Linear frame buffer address*/ case 0x11: ret = 0x00; break; case 0x12: ret = 0x00; break; - case 0x13: ret = svga->crtc[0x59] & 0xfc; break; + case 0x13: ret = (virge->chip == S3_VIRGEVX || virge->chip == S3_TRIO3D2X) ? (svga->crtc[0x59] & 0xfe) : (svga->crtc[0x59] & 0xfc); break; + + case 0x2c: ret = 0x33; break; /* Subsystem vendor ID */ + case 0x2d: ret = 0x53; break; + case 0x2e: ret = virge->virge_id_low; break; + case 0x2f: ret = virge->virge_id_high; break; case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ case 0x31: ret = 0x00; break; case 0x32: ret = virge->pci_regs[0x32]; break; case 0x33: ret = virge->pci_regs[0x33]; break; + case 0x34: ret = (virge->chip >= S3_VIRGEGX2) ? 0xdc : 0x00; break; + case 0x3c: ret = virge->pci_regs[0x3c]; break; - - case 0x3d: ret = 0x01; break; /*INTA*/ - + + case 0x3d: ret = PCI_INTA; break; /*INTA*/ + case 0x3e: ret = 0x04; break; case 0x3f: ret = 0xff; break; - + + case 0x80: ret = 0x02; break; /* AGP capability */ + case 0x81: ret = 0x00; break; + case 0x82: ret = 0x10; break; /* assumed AGP 1.0 */ + + case 0x84: ret = (virge->chip >= S3_TRIO3D2X) ? 0x03 : 0x01; break; + case 0x87: ret = 0x1f; break; + + case 0x88: ret = virge->pci_regs[0x88]; break; + case 0x89: ret = virge->pci_regs[0x89]; break; + case 0x8a: ret = virge->pci_regs[0x8a]; break; + case 0x8b: ret = virge->pci_regs[0x8b]; break; + + case 0xdc: ret = 0x01; break; /* PCI Power Management capability */ + case 0xdd: ret = virge->is_agp ? 0x80 : 0x00; break; + case 0xde: ret = 0x21; break; + + case 0xe0: ret = virge->pci_regs[0xe0]; break; + case 0xe1: ret = virge->pci_regs[0xe1]; break; + case 0xe2: ret = virge->pci_regs[0xe2]; break; + case 0xe3: ret = virge->pci_regs[0xe3]; break; } return ret; } @@ -3832,8 +3744,8 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x3d: case 0x3e: case 0x3f: - return; - + return; + case PCI_REG_COMMAND: if (val & PCI_COMMAND_IO) { @@ -3842,63 +3754,199 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) } else io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); - virge->pci_regs[PCI_REG_COMMAND] = val & 0x27; - s3_virge_updatemapping(virge); + virge->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3_virge_updatemapping(virge); return; case 0x07: virge->pci_regs[0x07] = val & 0x3e; return; - case 0x0d: + case 0x0d: virge->pci_regs[0x0d] = val & 0xf8; return; - - case 0x13: - svga->crtc[0x59] = val & 0xfc; - s3_virge_updatemapping(virge); - return; + + case 0x13: + svga->crtc[0x59] = (virge->chip == S3_VIRGEVX || virge->chip == S3_TRIO3D2X) ? (val & 0xfe) : (val & 0xfc); + s3_virge_updatemapping(virge); + return; case 0x30: case 0x32: case 0x33: virge->pci_regs[addr] = val; if (virge->pci_regs[0x30] & 0x01) { - uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); - mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000); - mem_mapping_enable(&virge->bios_rom.mapping); + uint32_t biosaddr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); + if (virge->chip == S3_VIRGEGX2) + mem_mapping_set_addr(&virge->bios_rom.mapping, biosaddr, 0x10000); + else + mem_mapping_set_addr(&virge->bios_rom.mapping, biosaddr, 0x8000); } else { mem_mapping_disable(&virge->bios_rom.mapping); } return; - case 0x3c: + case 0x3c: virge->pci_regs[0x3c] = val; return; + + case 0x88: + virge->pci_regs[0x88] = val & 0x27; + return; + + case 0x89: + virge->pci_regs[0x89] = val & 0x03; + return; + + case 0x8b: case 0xe1: case 0xe3: + virge->pci_regs[addr] = val; + return; + + case 0xe0: + virge->pci_regs[0xe0] = val & 0x03; + return; + + case 0xe2: + virge->pci_regs[0xe2] = val & 0xc0; + return; } } +static void s3_virge_reset(void *priv) +{ + virge_t *virge = (virge_t *) priv; + svga_t *svga = &virge->svga; + + memset(svga->crtc, 0x00, sizeof(svga->crtc)); + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = 1000ull << 32; + svga->dispofftime = 1000ull << 32; + svga->bpp = 8; + + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + memset(virge->pci_regs, 0x00, 256); + + virge->pci_regs[PCI_REG_COMMAND] = 3; + virge->pci_regs[0x05] = 0; + virge->pci_regs[0x06] = 0; + virge->pci_regs[0x07] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + switch(virge->local) { + case S3_VIRGE_325: + case S3_DIAMOND_STEALTH3D_2000: + virge->svga.crtc[0x59] = 0x70; + break; + case S3_DIAMOND_STEALTH3D_3000: + case S3_STB_VELOCITY_3D: + virge->svga.crtc[0x59] = 0x70; + break; + case S3_VIRGE_GX2: + case S3_DIAMOND_STEALTH3D_4000: + virge->svga.crtc[0x6c] = 1; + virge->svga.crtc[0x59] = 0x70; + break; + + case S3_TRIO_3D2X: + virge->svga.crtc[0x6c] = 1; + virge->svga.crtc[0x59] = 0x70; + break; + + default: + virge->svga.crtc[0x6c] = 1; + virge->svga.crtc[0x59] = 0x70; + break; + } + + if (virge->chip == S3_VIRGEGX2) + virge->svga.crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (1 << 5); + else { + switch (virge->memory_size) { + case 2: + if (virge->chip == S3_VIRGEVX) { + virge->svga.crtc[0x36] = (0 << 5); + } else + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 8: + if (virge->chip == S3_TRIO3D2X) + virge->svga.crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (0 << 5); + else + virge->svga.crtc[0x36] = (3 << 5); + break; + case 4: + if (virge->chip == S3_VIRGEVX) + virge->svga.crtc[0x36] = (1 << 5); + else if (virge->chip == S3_TRIO3D2X) + virge->svga.crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (2 << 5); + else + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + if (virge->local == S3_VIRGE_GX) + virge->svga.crtc[0x36] |= (1 << 2); + } + + virge->svga.crtc[0x37] = 1 | (7 << 5); + virge->svga.crtc[0x53] = 8; + + mem_mapping_disable(&virge->bios_rom.mapping); + + s3_virge_updatemapping(virge); + + mem_mapping_disable(&virge->mmio_mapping); + mem_mapping_disable(&virge->new_mmio_mapping); +} + static void *s3_virge_init(const device_t *info) { - const wchar_t *bios_fn; + const char *bios_fn; virge_t *virge = malloc(sizeof(virge_t)); memset(virge, 0, sizeof(virge_t)); virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); - virge->memory_size = device_get_config_int("memory"); - + if (info->local >= S3_VIRGE_GX2) + virge->memory_size = 4; + else + virge->memory_size = device_get_config_int("memory"); + + switch(info->local) { + case S3_VIRGE_325: + bios_fn = ROM_VIRGE_325; + break; case S3_DIAMOND_STEALTH3D_2000: bios_fn = ROM_DIAMOND_STEALTH3D_2000; break; case S3_DIAMOND_STEALTH3D_3000: bios_fn = ROM_DIAMOND_STEALTH3D_3000; break; + case S3_STB_VELOCITY_3D: + bios_fn = ROM_STB_VELOCITY_3D; + break; case S3_VIRGE_DX: bios_fn = ROM_VIRGE_DX; break; - case S3_VIRGE_DX_VBE20: - bios_fn = ROM_VIRGE_DX_VBE20; + case S3_DIAMOND_STEALTH3D_2000PRO: + bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; + break; + case S3_VIRGE_GX: + bios_fn = ROM_VIRGE_GX; + break; + case S3_VIRGE_GX2: + bios_fn = ROM_VIRGE_GX2; + break; + case S3_DIAMOND_STEALTH3D_4000: + bios_fn = ROM_DIAMOND_STEALTH3D_4000; + break; + case S3_TRIO_3D2X: + bios_fn = ROM_TRIO3D2X; break; default: free(virge); @@ -3910,14 +3958,24 @@ static void *s3_virge_init(const device_t *info) s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, s3_virge_overlay_draw); - virge->svga.vblank_start = s3_virge_vblank_start; + virge->svga.hwcursor.cur_ysize = 64; - virge->pci = !!(info->flags & DEVICE_PCI); + if (info->local == S3_VIRGE_GX2) + rom_init(&virge->bios_rom, (char *) bios_fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + else + rom_init(&virge->bios_rom, (char *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - rom_init(&virge->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_PCI) - mem_mapping_disable(&virge->bios_rom.mapping); + mem_mapping_disable(&virge->bios_rom.mapping); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + MEM_MAPPING_EXTERNAL, + &virge->svga); mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, s3_virge_mmio_read_w, s3_virge_mmio_read_l, @@ -3936,134 +3994,217 @@ static void *s3_virge_init(const device_t *info) NULL, MEM_MAPPING_EXTERNAL, virge); - mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - MEM_MAPPING_EXTERNAL, - &virge->svga); io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); - virge->pci_regs[4] = 3; - virge->pci_regs[5] = 0; - virge->pci_regs[6] = 0; - virge->pci_regs[7] = 2; + virge->pci_regs[PCI_REG_COMMAND] = 3; + virge->pci_regs[0x05] = 0; + virge->pci_regs[0x06] = 0; + virge->pci_regs[0x07] = 2; virge->pci_regs[0x32] = 0x0c; - virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3d] = 1; virge->pci_regs[0x3e] = 4; virge->pci_regs[0x3f] = 0xff; - + virge->virge_rev = 0; virge->virge_id = 0xe1; - - switch (virge->memory_size) - { - case 2: - virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); - break; - case 4: - default: - virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); - break; - } - - virge->svga.crtc[0x37] = 1; - virge->svga.crtc[0x53] = 1 << 3; - virge->svga.crtc[0x59] = 0x70; + virge->is_agp = !!(info->flags & DEVICE_AGP); switch(info->local) { + case S3_VIRGE_325: case S3_DIAMOND_STEALTH3D_2000: - virge->svga.vblank_start = s3_virge_vblank_start; - virge->virge_id_high = 0x56; - virge->virge_id_low = 0x31; + virge->svga.decode_mask = (4 << 20) - 1; + virge->virge_id_high = 0x56; + virge->virge_id_low = 0x31; + virge->svga.crtc[0x59] = 0x70; virge->chip = S3_VIRGE; - if (info->flags & DEVICE_PCI) - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_2000_pci); - else - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_2000_vlb); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_2000_pci); break; case S3_DIAMOND_STEALTH3D_3000: - virge->virge_id_high = 0x88; - virge->virge_id_low = 0x3d; + case S3_STB_VELOCITY_3D: + virge->svga.decode_mask = (8 << 20) - 1; + virge->virge_id_high = 0x88; + virge->virge_id_low = 0x3d; + virge->svga.crtc[0x59] = 0x70; virge->chip = S3_VIRGEVX; - if (info->flags & DEVICE_PCI) - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_3000_pci); - else - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_3000_vlb); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_3000_pci); break; + case S3_VIRGE_GX2: + case S3_DIAMOND_STEALTH3D_4000: + virge->svga.decode_mask = (4 << 20) - 1; + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x10; + virge->svga.crtc[0x6c] = 1; + virge->svga.crtc[0x59] = 0x70; + virge->svga.vblank_start = s3_virge_vblank_start; + virge->chip = S3_VIRGEGX2; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, virge->is_agp ? &timing_virge_agp : &timing_virge_dx_pci); + break; + + case S3_TRIO_3D2X: + virge->svga.decode_mask = (8 << 20) - 1; + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x13; + virge->virge_rev = 0x01; + virge->svga.crtc[0x6c] = 1; + virge->svga.crtc[0x59] = 0x70; + virge->svga.vblank_start = s3_virge_vblank_start; + virge->chip = S3_TRIO3D2X; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, virge->is_agp ? &timing_virge_agp : &timing_virge_dx_pci); + break; + + case S3_VIRGE_GX: + virge->virge_rev = 0x01; + /*FALLTHROUGH*/ default: - virge->svga.crtc[0x6c] = 0x01; - virge->virge_id_high = 0x8a; - virge->virge_id_low = 0x01; + virge->svga.decode_mask = (4 << 20) - 1; + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x01; + virge->svga.crtc[0x6c] = 1; + virge->svga.crtc[0x59] = 0x70; + virge->svga.vblank_start = s3_virge_vblank_start; virge->chip = S3_VIRGEDX; - if (info->flags & DEVICE_PCI) - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_virge_dx_pci); - else - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_virge_dx_vlb); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_virge_dx_pci); break; } - if (info->flags & DEVICE_PCI) - virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + if (virge->chip == S3_VIRGEGX2) { + virge->vram_mask = (4 << 20) - 1; + virge->svga.vram_mask = (4 << 20) - 1; + virge->svga.vram_max = 4 << 20; + virge->svga.crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (1 << 5); + } else { + switch (virge->memory_size) { + case 2: + virge->vram_mask = (2 << 20) - 1; + virge->svga.vram_mask = (2 << 20) - 1; + virge->svga.vram_max = 2 << 20; + if (virge->chip == S3_VIRGEVX) { + virge->svga.crtc[0x36] = (0 << 5); + } else + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 8: + virge->vram_mask = (8 << 20) - 1; + virge->svga.vram_mask = (8 << 20) - 1; + virge->svga.vram_max = 8 << 20; + if (virge->chip == S3_TRIO3D2X) + virge->svga.crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (0 << 5); + else + virge->svga.crtc[0x36] = (3 << 5); + break; + case 4: + virge->vram_mask = (4 << 20) - 1; + virge->svga.vram_mask = (4 << 20) - 1; + virge->svga.vram_max = 4 << 20; + if (virge->chip == S3_VIRGEVX) + virge->svga.crtc[0x36] = (1 << 5); + else if (virge->chip == S3_TRIO3D2X) + virge->svga.crtc[0x36] = 2 | (2 << 2) | (1 << 4) | (2 << 5); + else + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + if (info->local == S3_VIRGE_GX) + virge->svga.crtc[0x36] |= (1 << 2); + } - virge->wake_render_thread = thread_create_event(); - virge->wake_main_thread = thread_create_event(); - virge->not_full_event = thread_create_event(); - virge->render_thread = thread_create(render_thread, virge); + virge->svga.crtc[0x37] = 1 | (7 << 5); + virge->svga.crtc[0x53] = 8; - virge->wake_fifo_thread = thread_create_event(); - virge->fifo_not_full_event = thread_create_event(); - virge->fifo_thread = thread_create(fifo_thread, virge); - - return virge; + virge->card = pci_add_card(virge->is_agp ? PCI_ADD_AGP : PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + + virge->i2c = i2c_gpio_init("ddc_s3_virge"); + virge->ddc = ddc_init(i2c_gpio_get_bus(virge->i2c)); + + virge->svga.force_old_addr = 1; + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread_run = 1; + virge->render_thread = thread_create(render_thread, virge); + + timer_add(&virge->tri_timer, s3_virge_tri_timer, virge, 0); + + virge->local = info->local; + + return virge; } static void s3_virge_close(void *p) { virge_t *virge = (virge_t *)p; - thread_kill(virge->render_thread); - thread_destroy_event(virge->not_full_event); - thread_destroy_event(virge->wake_main_thread); + virge->render_thread_run = 0; + thread_set_event(virge->wake_render_thread); + thread_wait(virge->render_thread); + thread_destroy_event(virge->not_full_event); + thread_destroy_event(virge->wake_main_thread); thread_destroy_event(virge->wake_render_thread); - - thread_kill(virge->fifo_thread); - thread_destroy_event(virge->wake_fifo_thread); - thread_destroy_event(virge->fifo_not_full_event); svga_close(&virge->svga); - + + ddc_close(virge->ddc); + i2c_gpio_close(virge->i2c); + free(virge); } -static int s3_virge_available(void) +static int s3_virge_325_diamond_available(void) { return rom_present(ROM_DIAMOND_STEALTH3D_2000); } -static int s3_virge_988_available(void) +static int s3_virge_325_available(void) +{ + return rom_present(ROM_VIRGE_325); +} + +static int s3_virge_988_diamond_available(void) { return rom_present(ROM_DIAMOND_STEALTH3D_3000); } -static int s3_virge_375_1_available(void) +static int s3_virge_988_stb_available(void) +{ + return rom_present(ROM_STB_VELOCITY_3D); +} + +static int s3_virge_375_available(void) { return rom_present(ROM_VIRGE_DX); } -static int s3_virge_375_4_available(void) +static int s3_virge_375_diamond_available(void) { - return rom_present(ROM_VIRGE_DX_VBE20); + return rom_present(ROM_DIAMOND_STEALTH3D_2000PRO); +} + +static int s3_virge_385_available(void) +{ + return rom_present(ROM_VIRGE_GX); +} + +static int s3_virge_357_available(void) +{ + return rom_present(ROM_VIRGE_GX2); +} + +static int s3_virge_357_diamond_available(void) +{ + return rom_present(ROM_DIAMOND_STEALTH3D_4000); +} + +static int s3_trio3d2x_available(void) +{ + return rom_present(ROM_TRIO3D2X); } static void s3_virge_speed_changed(void *p) { virge_t *virge = (virge_t *)p; - + svga_recalctimings(&virge->svga); } @@ -4074,141 +4215,317 @@ static void s3_virge_force_redraw(void *p) virge->svga.fullchange = changeframecount; } -static const device_config_t s3_virge_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - } - }, - { - "bilinear", "Bilinear filtering", CONFIG_BINARY, "", 1 - }, - { - "dithering", "Dithering", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 +static const device_config_t s3_virge_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } } + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = CONFIG_END + } }; -const device_t s3_virge_vlb_device = -{ - "Diamond Stealth 3D 2000 (S3 ViRGE) VLB", - DEVICE_VLB, - S3_DIAMOND_STEALTH3D_2000, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +static const device_config_t s3_virge_stb_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + } + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = CONFIG_END + } }; -const device_t s3_virge_pci_device = -{ - "Diamond Stealth 3D 2000 (S3 ViRGE) PCI", - DEVICE_PCI, - S3_DIAMOND_STEALTH3D_2000, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +static const device_config_t s3_virge_357_config[] = { + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = CONFIG_END + } }; -const device_t s3_virge_988_vlb_device = -{ - "Diamond Stealth 3D 3000 (S3 ViRGE/VX) VLB", - DEVICE_VLB, - S3_DIAMOND_STEALTH3D_3000, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_988_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +static const device_config_t s3_trio3d2x_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + } + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = CONFIG_END + } }; -const device_t s3_virge_988_pci_device = -{ - "Diamond Stealth 3D 3000 (S3 ViRGE/VX) PCI", - DEVICE_PCI, - S3_DIAMOND_STEALTH3D_3000, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_988_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +const device_t s3_virge_325_pci_device = { + .name = "S3 ViRGE (325) PCI", + .internal_name = "virge325_pci", + .flags = DEVICE_PCI, + .local = S3_VIRGE_325, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_325_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_config }; -const device_t s3_virge_375_vlb_device = -{ - "S3 ViRGE/DX VLB", - DEVICE_VLB, - S3_VIRGE_DX, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_375_1_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +const device_t s3_diamond_stealth_2000_pci_device = { + .name = "S3 ViRGE (Diamond Stealth 3D 2000) PCI", + .internal_name = "stealth3d_2000_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH3D_2000, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_325_diamond_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_config }; -const device_t s3_virge_375_pci_device = -{ - "S3 ViRGE/DX PCI", - DEVICE_PCI, - S3_VIRGE_DX, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_375_1_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +const device_t s3_diamond_stealth_3000_pci_device = { + .name = "S3 ViRGE/VX (Diamond Stealth 3D 3000) PCI", + .internal_name = "stealth3d_3000_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH3D_3000, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_988_diamond_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_stb_config }; -const device_t s3_virge_375_4_vlb_device = -{ - "S3 ViRGE/DX (VBE 2.0) VLB", - DEVICE_VLB, - S3_VIRGE_DX_VBE20, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_375_4_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +const device_t s3_stb_velocity_3d_pci_device = { + .name = "S3 ViRGE/VX (STB Velocity 3D) PCI", + .internal_name = "stb_velocity3d_pci", + .flags = DEVICE_PCI, + .local = S3_STB_VELOCITY_3D, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_988_stb_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_stb_config }; -const device_t s3_virge_375_4_pci_device = -{ - "S3 ViRGE/DX (VBE 2.0) PCI", - DEVICE_PCI, - S3_VIRGE_DX_VBE20, - s3_virge_init, - s3_virge_close, - NULL, - s3_virge_375_4_available, - s3_virge_speed_changed, - s3_virge_force_redraw, - s3_virge_config +const device_t s3_virge_375_pci_device = { + .name = "S3 ViRGE/DX (375) PCI", + .internal_name = "virge375_pci", + .flags = DEVICE_PCI, + .local = S3_VIRGE_DX, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_375_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_config +}; + +const device_t s3_diamond_stealth_2000pro_pci_device = { + .name = "S3 ViRGE/DX (Diamond Stealth 3D 2000 Pro) PCI", + .internal_name = "stealth3d_2000pro_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH3D_2000PRO, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_375_diamond_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_config +}; + +const device_t s3_virge_385_pci_device = { + .name = "S3 ViRGE/GX (385) PCI", + .internal_name = "virge385_pci", + .flags = DEVICE_PCI, + .local = S3_VIRGE_GX, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_385_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_config +}; + +const device_t s3_virge_357_pci_device = { + .name = "S3 ViRGE/GX2 (357) PCI", + .internal_name = "virge357_pci", + .flags = DEVICE_PCI, + .local = S3_VIRGE_GX2, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_357_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_357_config +}; + +const device_t s3_virge_357_agp_device = { + .name = "S3 ViRGE/GX2 (357) AGP", + .internal_name = "virge357_agp", + .flags = DEVICE_AGP, + .local = S3_VIRGE_GX2, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_357_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_357_config +}; + +const device_t s3_diamond_stealth_4000_pci_device = { + .name = "S3 ViRGE/GX2 (Diamond Stealth 3D 4000) PCI", + .internal_name = "stealth3d_4000_pci", + .flags = DEVICE_PCI, + .local = S3_DIAMOND_STEALTH3D_4000, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_357_diamond_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_357_config +}; + +const device_t s3_diamond_stealth_4000_agp_device = { + .name = "S3 ViRGE/GX2 (Diamond Stealth 3D 4000) AGP", + .internal_name = "stealth3d_4000_agp", + .flags = DEVICE_AGP, + .local = S3_DIAMOND_STEALTH3D_4000, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_virge_357_diamond_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_357_config +}; + +const device_t s3_trio3d2x_pci_device = { + .name = "S3 Trio3D/2X (362) PCI", + .internal_name = "trio3d2x", + .flags = DEVICE_PCI, + .local = S3_TRIO_3D2X, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_trio3d2x_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_trio3d2x_config +}; + +const device_t s3_trio3d2x_agp_device = { + .name = "S3 Trio3D/2X (362) AGP", + .internal_name = "trio3d2x_agp", + .flags = DEVICE_AGP, + .local = S3_TRIO_3D2X, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_trio3d2x_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_trio3d2x_config }; diff --git a/src/video/vid_sc1148x_ramdac.c b/src/video/vid_sc1148x_ramdac.c new file mode 100644 index 000000000..202147d14 --- /dev/null +++ b/src/video/vid_sc1148x_ramdac.c @@ -0,0 +1,204 @@ +/* + * 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 Sierra SC1148x RAMDACs and clones (e.g.: Winbond). + * + * Used by the S3 911 and 924 chips. + * + * + * + * Authors: TheCollector1995, + * + * Copyright 2020 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> + + +typedef struct +{ + int type; + int state; + int rs2; + uint8_t ctrl; +} sc1148x_ramdac_t; + + +void +sc1148x_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) +{ + sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) p; + uint8_t rs = (addr & 0x03) | ((!!rs2) << 2); + int oldbpp = 0; + + switch (rs) { + case 2: case 6: + switch (ramdac->state) { + case 4: + ramdac->state = 0; + if (val == 0xff) + break; + ramdac->ctrl = val; + ramdac->ctrl = (ramdac->ctrl & ~1) | ((((val >> 2) ^ val) & (val & 0x20)) >> 5); + oldbpp = svga->bpp; + switch (ramdac->type) { + case 0: /* Sierra Mark 2 (11483)*/ + case 2: /* Sierra Mark 2 (11484)*/ + case 3: /* Sierra Mark 1 (11486)*/ + if (val & 0xa0) { + svga->bpp = 15; + } else if (val == 0x00) + svga->bpp = 8; + break; + case 1: /* Sierra Mark 3 (11487)*/ + if (val & 0xa0) { + if (val & 0x40) + svga->bpp = 16; + else + svga->bpp = 15; + } else if (val == 0x00) + svga->bpp = 8; + break; + } + if (oldbpp != svga->bpp) + svga_recalctimings(svga); + return; + default: + svga_out(addr, val, svga); + break; + } + break; + + default: + ramdac->state = 0; + svga_out(addr, val, svga); + break; + } +} + + +uint8_t +sc1148x_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) +{ + sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) p; + uint8_t ret = 0xff, rs = (addr & 0x03) | ((!!rs2) << 2); + + switch (rs) { + case 2: case 6: + switch (ramdac->state) { + case 1: + case 2: case 3: + ret = 0x00; + ramdac->state++; + break; + case 4: + ret = ramdac->ctrl; + ret = (ret & ~0x18) | (svga->dac_mask & 0x18); + break; + default: + ret = svga_in(addr, svga); + ramdac->state++; + break; + } + break; + + default: + ret = svga_in(addr, svga); + ramdac->state = 0; + break; + } + + return ret; +} + + +static void * +sc1148x_ramdac_init(const device_t *info) +{ + sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) malloc(sizeof(sc1148x_ramdac_t)); + memset(ramdac, 0, sizeof(sc1148x_ramdac_t)); + + ramdac->type = info->local; + + return ramdac; +} + + +static void +sc1148x_ramdac_close(void *priv) +{ + sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + +const device_t sc11483_ramdac_device = { + .name = "Sierra SC11483 RAMDAC", + .internal_name = "sc11483_ramdac", + .flags = 0, + .local = 0, + .init = sc1148x_ramdac_init, + .close = sc1148x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sc11487_ramdac_device = { + .name = "Sierra SC11487 RAMDAC", + .internal_name = "sc11487_ramdac", + .flags = 0, + .local = 1, + .init = sc1148x_ramdac_init, + .close = sc1148x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sc11484_nors2_ramdac_device = { + .name = "Sierra SC11484 RAMDAC (no RS2 signal)", + .internal_name = "sc11484_nors2_ramdac", + .flags = 0, + .local = 2, + .init = sc1148x_ramdac_init, + .close = sc1148x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sc11486_ramdac_device = { + .name = "Sierra SC11486 RAMDAC", + .internal_name = "sc11486_ramdac", + .flags = 0, + .local = 3, + .init = sc1148x_ramdac_init, + .close = sc1148x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_sc1502x_ramdac.c b/src/video/vid_sc1502x_ramdac.c index ea4725c9c..10b4594e4 100644 --- a/src/video/vid_sc1502x_ramdac.c +++ b/src/video/vid_sc1502x_ramdac.c @@ -153,11 +153,16 @@ sc1502x_ramdac_close(void *priv) free(ramdac); } - -const device_t sc1502x_ramdac_device = -{ - "Sierra SC1502x RAMDAC", - 0, 0, - sc1502x_ramdac_init, sc1502x_ramdac_close, - NULL, NULL, NULL, NULL +const device_t sc1502x_ramdac_device = { + .name = "Sierra SC1502x RAMDAC", + .internal_name = "sc1502x_ramdac", + .flags = 0, + .local = 0, + .init = sc1502x_ramdac_init, + .close = sc1502x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_sdac_ramdac.c b/src/video/vid_sdac_ramdac.c index 37bfa7104..f127572ac 100644 --- a/src/video/vid_sdac_ramdac.c +++ b/src/video/vid_sdac_ramdac.c @@ -29,6 +29,23 @@ #include <86box/vid_svga.h> +enum +{ + ICS_5300 = 0, + ICS_5301, + ICS_5340, + ICS_5341, + ICS_5342 +}; + + +#define ICS_S3_MASK 7 +#define ICS_S3 8 + +#define S3_86C708 (ICS_5300 | ICS_S3) +#define S3_86C716 (ICS_5342 | ICS_S3) + + typedef struct sdac_ramdac_t { uint16_t regs[256]; @@ -43,32 +60,63 @@ static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) { ramdac->command = val; - switch (val >> 4) { - case 0x2: - case 0x3: - case 0xa: - case 0x8: - svga->bpp = 15; + + switch (ramdac->type & ICS_S3_MASK) { + case ICS_5300: + case ICS_5301: + switch (val >> 5) { + case 0x00: + default: + svga->bpp = 8; + break; + case 0x01: + case 0x04: + case 0x05: + svga->bpp = 15; + break; + case 0x03: + case 0x06: + svga->bpp = 16; + break; + case 0x02: + case 0x07: + svga->bpp = 24; + break; + } break; - case 0x4: - case 0x9: - case 0xe: - svga->bpp = 24; - break; - case 0x5: - case 0x6: - case 0xc: - svga->bpp = 16; - break; - case 0x7: - svga->bpp = 32; - break; - case 0x0: - case 0x1: - default: - svga->bpp = 8; + case ICS_5340: + case ICS_5341: + case ICS_5342: + switch (val >> 4) { + case 0x00: + case 0x01: /* This is actually 8bpp with two pixels read at a time. */ + default: + svga->bpp = 8; + break; + case 0x02: + case 0x03: + case 0x08: + case 0x0a: + svga->bpp = 15; + break; + case 0x05: + case 0x06: + case 0x0c: + svga->bpp = 16; + break; + case 0x04: + case 0x09: + case 0x0e: + svga->bpp = 24; + break; + case 0x07: + svga->bpp = 32; + break; + } break; } + + svga_recalctimings(svga); } @@ -109,17 +157,27 @@ sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) { sdac_ramdac_t *ramdac = (sdac_ramdac_t *) p; uint8_t rs = (addr & 0x03); - rs |= (!!rs2 << 8); + rs |= ((!!rs2) << 2); - if ((rs >= 0x04) || (ramdac->type == 7)) switch (rs) { + if (rs != 0x02) + ramdac->magic_count = 0; + + switch (rs) { case 0x02: - if (ramdac->magic_count == 4) - sdac_control_write(ramdac, svga, val); - /* Fall through. */ + switch (ramdac->magic_count) { + case 4: + sdac_control_write(ramdac, svga, val); + ramdac->magic_count = 0; + break; + default: + svga_out(addr, val, svga); + break; + } + break; case 0x00: case 0x01: case 0x03: - ramdac->magic_count = 0; + svga_out(addr, val, svga); break; case 0x04: ramdac->windex = val; @@ -136,8 +194,6 @@ sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) ramdac->reg_ff = 0; break; } - - svga_out(addr, val, svga); } @@ -147,26 +203,35 @@ sdac_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) sdac_ramdac_t *ramdac = (sdac_ramdac_t *) p; uint8_t temp = 0xff; uint8_t rs = (addr & 0x03); - rs |= (!!rs2 << 8); + rs |= ((!!rs2) << 2); - if ((rs < 0x04) && (ramdac->type != 7)) - temp = svga_in(addr, svga); - else switch (rs) { + if (rs != 0x02) + ramdac->magic_count = 0; + + switch (rs) { case 0x02: - if (ramdac->magic_count < 5) - ramdac->magic_count++; - if (ramdac->magic_count == 4) - temp = 0x70; /*SDAC ID*/ - else if (ramdac->magic_count == 5) { - temp = ramdac->command; - ramdac->magic_count = 0; - } else - temp = svga_in(addr, svga); + switch (ramdac->magic_count) { + case 1: case 2: + temp = 0x00; + ramdac->magic_count++; + break; + case 3: + temp = (ramdac->type & ICS_S3) ? 0x70 : 0x00; + ramdac->magic_count++; + break; + case 4: + temp = ramdac->command; + ramdac->magic_count = 0; + break; + default: + temp = svga_in(addr, svga); + ramdac->magic_count++; + break; + } break; case 0x00: case 0x01: case 0x03: - ramdac->magic_count = 0; temp = svga_in(addr, svga); break; case 0x04: @@ -238,20 +303,58 @@ sdac_ramdac_close(void *priv) free(ramdac); } - -const device_t gendac_ramdac_device = -{ - "S3 GENDAC 86c708 RAMDAC", - 0, 0, - sdac_ramdac_init, sdac_ramdac_close, - NULL, NULL, NULL, NULL +const device_t gendac_ramdac_device = { + .name = "S3 GENDAC 86c708 RAMDAC", + .internal_name = "gendac_ramdac", + .flags = 0, + .local = S3_86C708, + .init = sdac_ramdac_init, + .close = sdac_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; - -const device_t sdac_ramdac_device = -{ - "S3 SDAC 86c716 RAMDAC", - 0, 7, - sdac_ramdac_init, sdac_ramdac_close, - NULL, NULL, NULL, NULL +const device_t tseng_ics5301_ramdac_device = { + .name = "Tseng ICS5301 GENDAC RAMDAC", + .internal_name = "tseng_ics5301_ramdac", + .flags = 0, + .local = ICS_5301, + .init = sdac_ramdac_init, + .close = sdac_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t tseng_ics5341_ramdac_device = { + .name = "Tseng ICS5341 GENDAC RAMDAC", + .internal_name = "tseng_ics5341_ramdac", + .flags = 0, + .local = ICS_5341, + .init = sdac_ramdac_init, + .close = sdac_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t sdac_ramdac_device = { + .name = "S3 SDAC 86c716 RAMDAC", + .internal_name = "sdac_ramdac", + .flags = 0, + .local = S3_86C716, + .init = sdac_ramdac_init, + .close = sdac_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index 6bd475c4b..73a9363e8 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -31,35 +31,35 @@ #include <86box/video.h> -#define ROM_SIGMA_FONT L"roms/video/sigma/sigma400_font.rom" -#define ROM_SIGMA_BIOS L"roms/video/sigma/sigma400_bios.rom" +#define ROM_SIGMA_FONT "roms/video/sigma/sigma400_font.rom" +#define ROM_SIGMA_BIOS "roms/video/sigma/sigma400_bios.rom" /* The Sigma Designs Color 400 is a video card from 1985, presumably intended * as an EGA competitor. - * - * The hardware seems to have gone through various iterations; I've seen + * + * The hardware seems to have gone through various iterations; I've seen * pictures of full-length and half-length versions. - * TH99 describes the jumpers / switches: + * TH99 describes the jumpers / switches: * * - * The card is CGA-compatible at BIOS level, but to improve compatibility - * attempts to write to the CGA I/O ports at 0x3D0-0x3DF trigger an NMI. The + * The card is CGA-compatible at BIOS level, but to improve compatibility + * attempts to write to the CGA I/O ports at 0x3D0-0x3DF trigger an NMI. The * card's BIOS handles the NMI and translates the CGA writes into commands * to its own hardware at 0x2D0-0x2DF. (DIP switches on the card allow the * base address to be changed, but since the BIOS dump I have doesn't support * this I haven't emulated it. Likewise the BIOS ROM address can be changed, * but I'm going with the default of 0xC0000). * - * The BIOS still functions if the NMI system isn't operational. There + * The BIOS still functions if the NMI system isn't operational. There * doesn't seem to be a jumper or DIP switch to lock it out, but at startup * the BIOS tests for its presence and configures itself to work or not * as required. I've therefore added a configuration option to handle this. * - * The card's real CRTC at 0x2D0/0x2D1 appears to be a 6845. One oddity is - * that all its horizontal counts are halved compared to what a real CGA - * uses; 40-column modes have a width of 20, and 80-column modes have a + * The card's real CRTC at 0x2D0/0x2D1 appears to be a 6845. One oddity is + * that all its horizontal counts are halved compared to what a real CGA + * uses; 40-column modes have a width of 20, and 80-column modes have a * width of 40. This means that the CRTC cursor position (registers 14/15) can - * only address even-numbered columns, so the top bit of the control + * only address even-numbered columns, so the top bit of the control * register at 0x2D9 is used to adjust the position. * * Apart from the CRTC, registers are: @@ -72,7 +72,7 @@ * Graphics 320x200: 0x0F * Graphics 640x200: 0x1F * Graphics 640x400: 0x7F - * + * * I have assumed this is a bitmap with the following meaning: */ #define MODE_80COLS 0x01 /* For text modes, 80 columns across */ #define MODE_GRAPHICS 0x02 /* Graphics mode */ @@ -89,7 +89,7 @@ #define CTL_SET_LPEN 0x04 /* Strobe 0 to set lightpen latch */ #define CTL_PALETTE 0x01 /* 0x2DE writes to palette (1) or plane (0) */ /* - * The card BIOS seems to support two variants of the hardware: One where + * The card BIOS seems to support two variants of the hardware: One where * bits 2 and 3 are normally 1 and are set to 0 to set/clear the latch, and * one where they are normally 0 and are set to 1. Behaviour is selected by * whether the byte at C000:17FFh is greater than 2Fh. @@ -103,9 +103,9 @@ #define STATUS_LPEN_A 0x02 /* Edge from lightpen has set trigger */ #define STATUS_RETR_H 0x01 /* Horizontal retrace */ /* - * 0x2DB: On read: Byte written to the card that triggered NMI + * 0x2DB: On read: Byte written to the card that triggered NMI * 0x2DB: On write: Resets the 'card raised NMI' flag. - * 0x2DC: On read: Bit 7 set if the card raised NMI. If so, bits 0-3 + * 0x2DC: On read: Bit 7 set if the card raised NMI. If so, bits 0-3 * give the low 4 bits of the I/O port address. * 0x2DC: On write: Resets the NMI. * 0x2DD: Memory paging. The memory from 0xC1800 to 0xC1FFF can be either: @@ -120,28 +120,28 @@ * Writing port 2DD switches to RAM. * * 0x2DE: Meaning depends on bottom bit of value written to port 0x2D9. - * Bit 0 set: Write to palette. High 4 bits of value = register, + * Bit 0 set: Write to palette. High 4 bits of value = register, * low 4 bits = RGBI values (active low) * Bit 0 clear: Write to plane select. Low 2 bits of value select - * plane 0-3 + * plane 0-3 */ - + typedef struct sigma_t { mem_mapping_t mapping, bios_ram; - rom_t bios_rom; + rom_t bios_rom; uint8_t crtc[32]; /* CRTC: Real values */ uint8_t lastport; /* Last I/O port written */ uint8_t lastwrite; /* Value written to that port */ uint8_t sigma_ctl; /* Controls register: - * Bit 7 is low bit of cursor position + * Bit 7 is low bit of cursor position * Bit 5 set if writes to CGA ports trigger NMI * Bit 3 clears lightpen latch * Bit 2 sets lightpen latch - * Bit 1 controls meaning of port 2DE + * Bit 1 controls meaning of port 2DE */ uint8_t enable_nmi; /* Enable the NMI mechanism for CGA emulation?*/ uint8_t rom_paged; /* Is ROM paged in at 0xC1800? */ @@ -155,7 +155,7 @@ typedef struct sigma_t uint16_t ma, maback; - int crtcreg; /* CRTC: Real selected register */ + int crtcreg; /* CRTC: Real selected register */ int linepos, displine; int sc, vc; @@ -173,18 +173,19 @@ typedef struct sigma_t pc_timer_t timer; uint8_t *vram; - uint8_t bram[2048]; + uint8_t bram[2048]; uint8_t palette[16]; int plane; int revision; + int fullchange; } sigma_t; #define COMPOSITE_OLD 0 #define COMPOSITE_NEW 1 -static uint8_t crtcmask[32] = +static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -207,7 +208,7 @@ sigma_out(uint16_t addr, uint8_t val, void *p) /* If set to NMI on video I/O... */ if (sigma->enable_nmi && (sigma->sigma_ctl & CTL_NMI)) { sigma->lastport |= 0x80; /* Card raised NMI */ - nmi = 1; + nmi_raise(); } /* For CRTC emulation, the card BIOS sets the value to be * read from port 0x3D1 like this */ @@ -228,9 +229,9 @@ sigma_out(uint16_t addr, uint8_t val, void *p) sigma->crtc[sigma->crtcreg] = val & crtcmask[sigma->crtcreg]; if (old != val) { if (sigma->crtcreg < 0xe || sigma->crtcreg > 0x10) { - fullchange = changeframecount; + sigma->fullchange = changeframecount; sigma_recalctimings(sigma); - } + } } return; @@ -283,13 +284,13 @@ sigma_in(uint16_t addr, void *p) result = sigma->crtc[sigma->crtcreg & 0x1F]; break; case 0x2DA: - result = (sigma->sigma_ctl & 0xE0) | + result = (sigma->sigma_ctl & 0xE0) | (sigma->sigmastat & 0x1F); break; - case 0x2DB: + case 0x2DB: result = sigma->lastwrite; /* Value that triggered NMI */ break; - case 0x2DC: + case 0x2DC: result = sigma->lastport; /* Port that triggered NMI */ break; case 0x2DD: /* Page in ROM at 0xC1800 */ @@ -343,8 +344,7 @@ sigma_write(uint32_t addr, uint8_t val, void *p) sigma_t *sigma = (sigma_t *)p; sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)] = val; - egawrites++; - sub_cycles(4); + cycles -= 4; } @@ -353,8 +353,7 @@ sigma_read(uint32_t addr, void *p) { sigma_t *sigma = (sigma_t *)p; - sub_cycles(4); - egareads++; + cycles -= 4; return sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)]; } @@ -418,10 +417,10 @@ static void sigma_text80(sigma_t *sigma) int x, c; uint8_t chr, attr; uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); - uint16_t ma = ((sigma->ma << 1) & 0x3FFF); + uint16_t ma = ((sigma->ma & 0x3FFF) << 1); int drawcursor; uint32_t cols[4]; - uint8_t *vram = sigma->vram + (ma & 0x3FFF); + uint8_t *vram = sigma->vram + (ma << 1); ca = ca << 1; if (sigma->sigma_ctl & CTL_CURSOR) @@ -438,7 +437,7 @@ static void sigma_text80(sigma_t *sigma) if (!(sigma->sigmamode & MODE_NOBLINK)) { cols[1] = (attr & 15) | 16; cols[0] = ((attr >> 4) & 7) | 16; - if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) + if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) cols[1] = cols[0]; } else { /* No blink */ cols[1] = (attr & 15) | 16; @@ -474,10 +473,10 @@ sigma_text40(sigma_t *sigma) int x, c; uint8_t chr, attr; uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); - uint16_t ma = ((sigma->ma << 1) & 0x3FFF); + uint16_t ma = ((sigma->ma & 0x3FFF) << 1); int drawcursor; uint32_t cols[4]; - uint8_t *vram = sigma->vram + (ma & 0x3FFF); + uint8_t *vram = sigma->vram + ((ma << 1) & 0x3FFF); ca = ca << 1; if (sigma->sigma_ctl & CTL_CURSOR) @@ -494,7 +493,7 @@ sigma_text40(sigma_t *sigma) if (!(sigma->sigmamode & MODE_NOBLINK)) { cols[1] = (attr & 15) | 16; cols[0] = ((attr >> 4) & 7) | 16; - if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) + if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) cols[1] = cols[0]; } else { /* No blink */ cols[1] = (attr & 15) | 16; @@ -502,13 +501,13 @@ sigma_text40(sigma_t *sigma) } if (drawcursor) { - for (c = 0; c < 8; c++) { - buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = + for (c = 0; c < 8; c++) { + buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = buffer32->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; } } else { for (c = 0; c < 8; c++) { - buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = + buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = buffer32->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; } } @@ -527,18 +526,18 @@ sigma_gfx400(sigma_t *sigma) unsigned char *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + (sigma->sc & 3) * 0x2000]; uint8_t plane[4]; - uint8_t mask, col, c; + uint8_t mask, col, c; for (x = 0; x < (sigma->crtc[1] << 1); x++) { - plane[0] = vram[x]; - plane[1] = vram[0x8000 + x]; - plane[2] = vram[0x10000 + x]; - plane[3] = vram[0x18000 + x]; + plane[0] = vram[x]; + plane[1] = vram[0x8000 + x]; + plane[2] = vram[0x10000 + x]; + plane[3] = vram[0x18000 + x]; for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) { - col = ((plane[3] & mask) ? 8 : 0) | - ((plane[2] & mask) ? 4 : 0) | - ((plane[1] & mask) ? 2 : 0) | + col = ((plane[3] & mask) ? 8 : 0) | + ((plane[2] & mask) ? 4 : 0) | + ((plane[1] & mask) ? 2 : 0) | ((plane[0] & mask) ? 1 : 0); col |= 16; buffer32->line[sigma->displine][(x << 3) + c + 8] = col; @@ -560,18 +559,18 @@ sigma_gfx200(sigma_t *sigma) unsigned char *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + (sigma->sc & 2) * 0x1000]; uint8_t plane[4]; - uint8_t mask, col, c; + uint8_t mask, col, c; for (x = 0; x < (sigma->crtc[1] << 1); x++) { - plane[0] = vram[x]; - plane[1] = vram[0x8000 + x]; - plane[2] = vram[0x10000 + x]; - plane[3] = vram[0x18000 + x]; + plane[0] = vram[x]; + plane[1] = vram[0x8000 + x]; + plane[2] = vram[0x10000 + x]; + plane[3] = vram[0x18000 + x]; for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) { - col = ((plane[3] & mask) ? 8 : 0) | - ((plane[2] & mask) ? 4 : 0) | - ((plane[1] & mask) ? 2 : 0) | + col = ((plane[3] & mask) ? 8 : 0) | + ((plane[2] & mask) ? 4 : 0) | + ((plane[1] & mask) ? 2 : 0) | ((plane[0] & mask) ? 1 : 0); col |= 16; buffer32->line[sigma->displine][(x << 3) + c + 8] = col; @@ -591,25 +590,25 @@ sigma_gfx4col(sigma_t *sigma) unsigned char *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + (sigma->sc & 2) * 0x1000]; uint8_t plane[4]; - uint8_t mask, col, c; + uint8_t mask, col, c; for (x = 0; x < (sigma->crtc[1] << 1); x++) { - plane[0] = vram[x]; - plane[1] = vram[0x8000 + x]; - plane[2] = vram[0x10000 + x]; - plane[3] = vram[0x18000 + x]; + plane[0] = vram[x]; + plane[1] = vram[0x8000 + x]; + plane[2] = vram[0x10000 + x]; + plane[3] = vram[0x18000 + x]; mask = 0x80; for (c = 0; c < 4; c++) { - col = ((plane[3] & mask) ? 2 : 0) | + col = ((plane[3] & mask) ? 2 : 0) | ((plane[2] & mask) ? 1 : 0); mask = mask >> 1; - col |= ((plane[3] & mask) ? 8 : 0) | + col |= ((plane[3] & mask) ? 8 : 0) | ((plane[2] & mask) ? 4 : 0); col |= 16; mask = mask >> 1; - buffer32->line[sigma->displine][(x << 3) + (c << 1) + 8] = + buffer32->line[sigma->displine][(x << 3) + (c << 1) + 8] = buffer32->line[sigma->displine][(x << 3) + (c << 1) + 9] = col; } @@ -633,7 +632,7 @@ sigma_poll(void *p) sigma->sigmastat |= STATUS_RETR_H; sigma->linepos = 1; oldsc = sigma->sc; - if ((sigma->crtc[8] & 3) == 3) + if ((sigma->crtc[8] & 3) == 3) sigma->sc = ((sigma->sc << 1) + sigma->oddeven) & 7; if (sigma->cgadispon) { if (sigma->displine < sigma->firstline) { @@ -666,13 +665,13 @@ sigma_poll(void *p) } } else { cols[0] = 16; - if (sigma->sigmamode & MODE_80COLS) + if (sigma->sigmamode & MODE_80COLS) hline(buffer32, 0, sigma->displine, (sigma->crtc[1] << 4) + 16, cols[0]); else hline(buffer32, 0, sigma->displine, (sigma->crtc[1] << 5) + 16, cols[0]); } - if (sigma->sigmamode & MODE_80COLS) + if (sigma->sigmamode & MODE_80COLS) x = (sigma->crtc[1] << 4) + 16; else x = (sigma->crtc[1] << 5) + 16; @@ -684,7 +683,7 @@ sigma_poll(void *p) if (sigma->vc == sigma->crtc[7] && !sigma->sc) sigma->sigmastat |= STATUS_RETR_V; sigma->displine++; - if (sigma->displine >= 560) + if (sigma->displine >= 560) sigma->displine = 0; } else { timer_advance_u64(&sigma->timer, sigma->dispontime); @@ -695,9 +694,9 @@ sigma_poll(void *p) sigma->sigmastat &= ~STATUS_RETR_V; } if (sigma->sc == (sigma->crtc[11] & 31) || - ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[11] & 31) >> 1))) { - sigma->con = 0; - sigma->coff = 1; + ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[11] & 31) >> 1))) { + sigma->con = 0; + sigma->coff = 1; } if ((sigma->crtc[8] & 3) == 3 && sigma->sc == (sigma->crtc[9] >> 1)) sigma->maback = sigma->ma; @@ -718,7 +717,7 @@ sigma_poll(void *p) sigma->vc++; sigma->vc &= 127; - if (sigma->vc == sigma->crtc[6]) + if (sigma->vc == sigma->crtc[6]) sigma->cgadispon = 0; if (oldvc == sigma->crtc[4]) { @@ -738,7 +737,7 @@ sigma_poll(void *p) sigma->displine = 0; sigma->vsynctime = 16; if (sigma->crtc[7]) { - if (sigma->sigmamode & MODE_80COLS) + if (sigma->sigmamode & MODE_80COLS) x = (sigma->crtc[1] << 4) + 16; else x = (sigma->crtc[1] << 5) + 16; @@ -760,7 +759,7 @@ sigma_poll(void *p) video_force_resize_set(0); } - video_blit_memtoscreen_8(0, sigma->firstline - 4, 0, (sigma->lastline - sigma->firstline) + 8, xsize, (sigma->lastline - sigma->firstline) + 8); + video_blit_memtoscreen_8(0, sigma->firstline - 4, xsize, (sigma->lastline - sigma->firstline) + 8); frames++; video_res_x = xsize - 16; @@ -797,7 +796,7 @@ sigma_poll(void *p) if (sigma->cgadispon) sigma->sigmastat &= ~STATUS_RETR_H; if ((sigma->sc == (sigma->crtc[10] & 31) || - ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[10] & 31) >> 1)))) + ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[10] & 31) >> 1)))) sigma->con = 1; } } @@ -817,7 +816,7 @@ static void sigma->enable_nmi = device_get_config_int("enable_nmi"); loadfont(ROM_SIGMA_FONT, 7); - rom_init(&sigma->bios_rom, ROM_SIGMA_BIOS, bios_addr, 0x2000, + rom_init(&sigma->bios_rom, ROM_SIGMA_BIOS, bios_addr, 0x2000, 0x1FFF, 0, MEM_MAPPING_EXTERNAL); /* The BIOS ROM is overlaid by RAM, so remove its default mapping and access it through sigma_bread() / sigma_bwrite() below */ @@ -827,19 +826,19 @@ static void sigma->vram = malloc(0x8000 * 4); timer_add(&sigma->timer, sigma_poll, sigma, 1); - mem_mapping_add(&sigma->mapping, 0xb8000, 0x08000, - sigma_read, NULL, NULL, - sigma_write, NULL, NULL, + mem_mapping_add(&sigma->mapping, 0xb8000, 0x08000, + sigma_read, NULL, NULL, + sigma_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, sigma); mem_mapping_add(&sigma->bios_ram, bios_addr, 0x2000, - sigma_bread, NULL, NULL, - sigma_bwrite, NULL, NULL, + sigma_bread, NULL, NULL, + sigma_bwrite, NULL, NULL, sigma->bios_rom.rom, MEM_MAPPING_EXTERNAL, sigma); - io_sethandler(0x03d0, 0x0010, - sigma_in, NULL, NULL, + io_sethandler(0x03d0, 0x0010, + sigma_in, NULL, NULL, sigma_out, NULL, NULL, sigma); - io_sethandler(0x02d0, 0x0010, - sigma_in, NULL, NULL, + io_sethandler(0x02d0, 0x0010, + sigma_in, NULL, NULL, sigma_out, NULL, NULL, sigma); /* Start with ROM paged in, BIOS RAM paged out */ @@ -882,90 +881,116 @@ sigma_speed_changed(void *p) sigma_recalctimings(sigma); } - -device_config_t sigma_config[] = -{ +device_config_t sigma_config[] = { +// clang-format off { - "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, - { - { - "Color", 0 - }, - { - "Green Monochrome", 1 - }, - { - "Amber Monochrome", 2 - }, - { - "Gray Monochrome", 3 - }, - { - "Color (no brown)", 4 - }, - { - "" - } - } + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_int = 0, + .selection = { + { + .description = "Color", + .value = 0 + }, + { + .description = "Green Monochrome", + .value = 1 + }, + { + .description = "Amber Monochrome", + .value = 2 + }, + { + .description = "Gray Monochrome", + .value = 3 + }, + { + .description = "Color (no brown)", + .value = 4 + }, + { + .description = "" + } + } }, { - "enable_nmi", "Enable NMI for CGA emulation", CONFIG_BINARY, "", 1 + .name = "enable_nmi", + .description = "Enable NMI for CGA emulation", + .type = CONFIG_BINARY, + .default_int = 1 }, { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xc0000, - { - { - "C000H", 0xc0000 - }, - { - "C800H", 0xc8000 - }, - { - "CC00H", 0xcc000 - }, - { - "D000H", 0xd0000 - }, - { - "D400H", 0xd4000 - }, - { - "D800H", 0xd8000 - }, - { - "DC00H", 0xdc000 - }, - { - "E000H", 0xe0000 - }, - { - "E400H", 0xe4000 - }, - { - "E800H", 0xe8000 - }, - { - "EC00H", 0xec000 - }, - { - "" - } - }, + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_int = 0xc0000, + .selection = { + { + .description = "C000H", + .value = 0xc0000 + }, + { + .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 = "E000H", + .value = 0xe0000 + }, + { + .description = "E400H", + .value = 0xe4000 + }, + { + .description = "E800H", + .value = 0xe8000 + }, + { + .description = "EC00H", + .value = 0xec000 + }, + { + .description = "" + } + }, }, { - "", "", -1 + .type = CONFIG_END } +// clang-format on }; -const device_t sigma_device = -{ - "Sigma Color 400", - DEVICE_ISA, 0, - sigma_init, - sigma_close, - NULL, - sigma_available, - sigma_speed_changed, - NULL, - sigma_config +const device_t sigma_device = { + .name = "Sigma Color 400", + .internal_name = "sigma400", + .flags = DEVICE_ISA, + .local = 0, + .init = sigma_init, + .close = sigma_close, + .reset = NULL, + { .available = sigma_available }, + .speed_changed = sigma_speed_changed, + .force_redraw = NULL, + .config = sigma_config }; diff --git a/src/video/vid_stg_ramdac.c b/src/video/vid_stg_ramdac.c index b61ee886c..49216dba2 100644 --- a/src/video/vid_stg_ramdac.c +++ b/src/video/vid_stg_ramdac.c @@ -102,11 +102,11 @@ stg_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga) case 0: case 1: case 2: - case 3: + case 3: break; case 4: /* REG06 */ old = ramdac->command; - ramdac->command = val; + ramdac->command = val; if ((old ^ val) & 8) stg_ramdac_set_bpp(svga, ramdac); else { @@ -114,11 +114,11 @@ stg_ramdac_out(uint16_t addr, uint8_t val, void *p, svga_t *svga) stg_ramdac_set_bpp(svga, ramdac); } break; - case 5: - ramdac->index = (ramdac->index & 0xff00) | val; + case 5: + ramdac->index = (ramdac->index & 0xff00) | val; break; case 6: - ramdac->index = (ramdac->index & 0xff) | (val << 8); + ramdac->index = (ramdac->index & 0xff) | (val << 8); break; case 7: if (ramdac->index < 0x100) @@ -160,13 +160,13 @@ stg_ramdac_in(uint16_t addr, void *p, svga_t *svga) temp = 0xff; break; case 4: - temp = ramdac->command; + temp = ramdac->command; break; case 5: - temp = ramdac->index & 0xff; + temp = ramdac->index & 0xff; break; case 6: - temp = ramdac->index >> 8; + temp = ramdac->index >> 8; break; case 7: switch (ramdac->index) { @@ -246,11 +246,16 @@ stg_ramdac_close(void *priv) free(ramdac); } - -const device_t stg_ramdac_device = -{ - "SGS-Thompson STG170x RAMDAC", - 0, 0, - stg_ramdac_init, stg_ramdac_close, - NULL, NULL, NULL, NULL +const device_t stg_ramdac_device = { + .name = "SGS-Thompson STG170x RAMDAC", + .internal_name = "stg_ramdac", + .flags = 0, + .local = 0, + .init = stg_ramdac_init, + .close = stg_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index aedaf58a9..ea70248dc 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -9,7 +9,7 @@ * Generic SVGA handling. * * This is intended to be used by another SVGA driver, - * and not as a card in it's own right. + * and not as a card in its own right. * * * @@ -34,22 +34,25 @@ #include <86box/pit.h> #include <86box/mem.h> #include <86box/rom.h> +#include <86box/plat.h> +#include <86box/ui.h> #include <86box/video.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> +void svga_doblit(int wx, int wy, svga_t *svga); -void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); +svga_t *svga_8514; extern int cyc_total; extern uint8_t edatlookup[4][4]; -uint8_t svga_rotate[8][256]; +uint8_t svga_rotate[8][256]; /*Primary SVGA device. As multiple video cards are not yet supported this is the only SVGA device.*/ -static svga_t *svga_pri; - +static svga_t *svga_pri; +int vga_on, ibm8514_on; svga_t *svga_get_pri() @@ -76,7 +79,7 @@ svga_set_override(svga_t *svga, int val) overscan_x = (svga->seqregs[1] & 1) ? 16 : 18; - if (svga->seqregs[1] & 8) + if (svga->seqregs[1] & 8) overscan_x <<= 1; } else overscan_x = overscan_y = 16; @@ -106,7 +109,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga->fullchange = changeframecount; o = svga->attrregs[svga->attraddr & 31]; svga->attrregs[svga->attraddr & 31] = val; - if (svga->attraddr < 16) + if (svga->attraddr < 16) svga->fullchange = changeframecount; if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { for (c = 0; c < 16; c++) { @@ -118,6 +121,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) ((svga->attrregs[0x14] & 0xc) << 4); } } + svga->fullchange = changeframecount; } /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ @@ -144,8 +148,8 @@ svga_out(uint16_t addr, uint8_t val, void *p) io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); svga_recalctimings(svga); break; - case 0x3c4: - svga->seqaddr = val; + case 0x3c4: + svga->seqaddr = val; break; case 0x3c5: if (svga->seqaddr > 0xf) @@ -156,9 +160,9 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga_recalctimings(svga); switch (svga->seqaddr & 0xf) { case 1: - if (svga->scrblank && !(val & 0x20)) - svga->fullchange = 3; - svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); svga_recalctimings(svga); break; case 2: @@ -172,16 +176,16 @@ svga_out(uint16_t addr, uint8_t val, void *p) if (val & 0x20) svga->charsetb += 0x8000; break; - case 4: + case 4: svga->chain2_write = !(val & 4); svga->chain4 = val & 8; svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); + !svga->gdcreg[1]) && ((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) && !(svga->adv_flags & FLAG_ADDR_BY8); break; } break; - case 0x3c6: - svga->dac_mask = val; + case 0x3c6: + svga->dac_mask = val; break; case 0x3c7: case 0x3c8: @@ -190,32 +194,34 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga->dac_addr = (val + (addr & 0x01)) & 255; break; case 0x3c9: + if (svga->adv_flags & FLAG_RAMDAC_SHIFT) + val <<= 2; svga->fullchange = changeframecount; switch (svga->dac_pos) { case 0: svga->dac_r = val; - svga->dac_pos++; + svga->dac_pos++; break; case 1: svga->dac_g = val; - svga->dac_pos++; + svga->dac_pos++; break; case 2: index = svga->dac_addr & 255; svga->vgapal[index].r = svga->dac_r; svga->vgapal[index].g = svga->dac_g; - svga->vgapal[index].b = val; + svga->vgapal[index].b = val; if (svga->ramdac_type == RAMDAC_8BIT) svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b); else svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); - svga->dac_pos = 0; - svga->dac_addr = (svga->dac_addr + 1) & 255; + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 255; break; } break; case 0x3ce: - svga->gdcaddr = val; + svga->gdcaddr = val; break; case 0x3cf: o = svga->gdcreg[svga->gdcaddr & 15]; @@ -257,9 +263,9 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga->colournocare = val; break; } - svga->gdcreg[svga->gdcaddr & 15] = val; + svga->gdcreg[svga->gdcaddr & 15] = val; svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - !svga->gdcreg[1]) && svga->chain4; + !svga->gdcreg[1]) && ((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only); if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) svga_recalctimings(svga); @@ -306,28 +312,30 @@ svga_in(uint16_t addr, void *p) index = (svga->dac_addr - 1) & 255; switch (svga->dac_pos) { case 0: - svga->dac_pos++; + svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) ret = svga->vgapal[index].r; else ret = svga->vgapal[index].r & 0x3f; break; case 1: - svga->dac_pos++; + svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) ret = svga->vgapal[index].g; else ret = svga->vgapal[index].g & 0x3f; break; case 2: - svga->dac_pos=0; - svga->dac_addr = (svga->dac_addr + 1) & 255; + svga->dac_pos=0; + svga->dac_addr = (svga->dac_addr + 1) & 255; if (svga->ramdac_type == RAMDAC_8BIT) ret = svga->vgapal[index].b; else ret = svga->vgapal[index].b & 0x3f; break; } + if (svga->adv_flags & FLAG_RAMDAC_SHIFT) + ret >>= 2; break; case 0x3cc: ret = svga->miscout; @@ -448,13 +456,18 @@ svga_recalctimings(svga_t *svga) svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); svga->ca_adj = 0; + svga->rowcount = svga->crtc[9] & 31; + svga->hdisp_time = svga->hdisp; svga->render = svga_render_blank; - if (!svga->scrblank && svga->attr_palette_enable) { + if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ if (svga->seqregs[1] & 8) /*40 column*/ { svga->render = svga_render_text_40; svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + /* Character clock is off by 1 now in 40-line modes, on all cards. */ + svga->ma_latch--; + svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18; } else { svga->render = svga_render_text_80; svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; @@ -462,10 +475,10 @@ svga_recalctimings(svga_t *svga) svga->hdisp_old = svga->hdisp; } else { svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; - svga->hdisp_old = svga->hdisp; + svga->hdisp_old = svga->hdisp; switch (svga->gdcreg[5] & 0x60) { - case 0x00: + case 0x00: if (svga->seqregs[1] & 8) /*Low res (320)*/ svga->render = svga_render_4bpp_lowres; else @@ -498,6 +511,12 @@ svga_recalctimings(svga_t *svga) else svga->render = svga_render_16bpp_highres; break; + case 17: + if (svga->lowres) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_mix_highres; + break; case 24: if (svga->lowres) svga->render = svga_render_24bpp_lowres; @@ -517,7 +536,6 @@ svga_recalctimings(svga_t *svga) } svga->linedbl = svga->crtc[9] & 0x80; - svga->rowcount = svga->crtc[9] & 31; svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9; if (enable_overscan) { @@ -530,13 +548,21 @@ svga_recalctimings(svga_t *svga) if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { overscan_x = (svga->seqregs[1] & 1) ? 16 : 18; - if (svga->seqregs[1] & 8) + if (svga->seqregs[1] & 8) overscan_x <<= 1; } else overscan_x = 16; - if (svga->recalctimings_ex) - svga->recalctimings_ex(svga); + if (vga_on) { + if (svga->recalctimings_ex) { + svga->recalctimings_ex(svga); + } + } else { + if (ibm8514_on && ibm8514_enabled) + ibm8514_recalctimings(svga); + if (xga_enabled) + xga_recalctimings(svga); + } svga->y_add = (overscan_y >> 1) - (svga->crtc[8] & 0x1f); svga->x_add = (overscan_x >> 1); @@ -563,13 +589,33 @@ svga_recalctimings(svga_t *svga) if (svga->dispontime < TIMER_USEC) svga->dispontime = TIMER_USEC; if (svga->dispofftime < TIMER_USEC) - svga->dispofftime = TIMER_USEC; + svga->dispofftime = TIMER_USEC; + + if (!svga->force_old_addr) + svga_recalc_remap_func(svga); + + /* Inform the user interface of any DPMS mode changes. */ + if (svga->dpms) { + if (!svga->dpms_ui) { + svga->dpms_ui = 1; + ui_sb_set_text_w(plat_get_string(IDS_2142)); + } + } else if (svga->dpms_ui) { + svga->dpms_ui = 0; + ui_sb_set_text_w(NULL); + } } static void svga_do_render(svga_t *svga) { + /* Always render a blank screen and nothing else while in DPMS mode. */ + if (svga->dpms) { + svga_render_blank(svga); + return; + } + if (!svga->override) { svga->render(svga); @@ -613,36 +659,44 @@ svga_poll(void *p) int wx, wy; int ret, old_ma; + if (!vga_on && ibm8514_enabled && ibm8514_on) { + ibm8514_poll(&svga->dev8514, svga); + return; + } else if (!vga_on && xga_enabled && svga->xga.on) { + xga_poll(&svga->xga, svga); + return; + } + if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { - svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff; svga->hwcursor_oddeven = 0; } if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && svga->interlace) { - svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_on = svga->hwcursor.cur_ysize - (svga->hwcursor_latch.yoff + 1); svga->hwcursor_oddeven = 1; } if (svga->displine == svga->dac_hwcursor_latch.y && svga->dac_hwcursor_latch.ena) { - svga->dac_hwcursor_on = 64 - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_on = svga->dac_hwcursor.cur_ysize - svga->dac_hwcursor_latch.yoff; svga->dac_hwcursor_oddeven = 0; } if (svga->displine == (svga->dac_hwcursor_latch.y + 1) && svga->dac_hwcursor_latch.ena && svga->interlace) { - svga->dac_hwcursor_on = 64 - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_on = svga->dac_hwcursor.cur_ysize - (svga->dac_hwcursor_latch.yoff + 1); svga->dac_hwcursor_oddeven = 1; } if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 0; } if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 1; } @@ -661,7 +715,7 @@ svga_poll(void *p) if (svga->hwcursor_on || svga->dac_hwcursor_on || svga->overlay_on) { svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = - svga->interlace ? 3 : 2; + svga->interlace ? 3 : 2; } if (svga->vertical_linedbl) { @@ -683,12 +737,12 @@ svga_poll(void *p) } else svga_do_render(svga); - if (svga->lastline < svga->displine) + if (svga->lastline < svga->displine) svga->lastline = svga->displine; } svga->displine++; - if (svga->interlace) + if (svga->interlace) svga->displine++; if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) svga->cgastat &= ~8; @@ -698,7 +752,7 @@ svga_poll(void *p) } else { timer_advance_u64(&svga->timer, svga->dispontime); - if (svga->dispon) + if (svga->dispon) svga->cgastat &= ~1; svga->hdisp_on = 0; @@ -736,12 +790,18 @@ svga_poll(void *p) if (svga->vc == svga->split) { ret = 1; - + if (svga->line_compare) ret = svga->line_compare(svga); - + if (ret) { - svga->ma = svga->maback = 0; + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); + else + svga->ma = svga->maback = ((svga->crtc[5] & 0x60) >> 5); + svga->ma = (svga->ma << 2); + svga->maback = (svga->maback << 2); + svga->sc = 0; if (svga->attrregs[0x10] & 0x20) { svga->scrollcache = 0; @@ -761,15 +821,15 @@ svga_poll(void *p) else svga->cursoron = svga->blink & (16 + (16 * blink_delay)); - if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) svga->fullchange = 2; svga->blink = (svga->blink + 1) & 0x7f; for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { - if (svga->changedvram[x]) + if (svga->changedvram[x]) svga->changedvram[x]--; } - if (svga->fullchange) + if (svga->fullchange) svga->fullchange--; } if (svga->vc == svga->vsyncstart) { @@ -787,10 +847,10 @@ svga_poll(void *p) if (!svga->override) { if (svga->vertical_linedbl) { wy = (svga->lastline - svga->firstline) << 1; - svga_doblit(svga->firstline_draw << 1, (svga->lastline_draw + 1) << 1, wx, wy, svga); + svga_doblit(wx, wy, svga); } else { wy = svga->lastline - svga->firstline; - svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + svga_doblit(wx, wy, svga); } } @@ -805,7 +865,7 @@ svga_poll(void *p) changeframecount = svga->interlace ? 3 : 2; svga->vslines = 0; - if (svga->interlace && svga->oddeven) + if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); else svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[5] & 0x60) >> 5); @@ -855,14 +915,14 @@ svga_poll(void *p) svga->overlay_on = 0; svga->overlay_latch = svga->overlay; } - if (svga->sc == (svga->crtc[10] & 31)) + if (svga->sc == (svga->crtc[10] & 31)) svga->con = 1; } } int -svga_init(const device_t *info, svga_t *svga, void *p, int memsize, +svga_init(const device_t *info, svga_t *svga, void *p, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), void (*video_out)(uint16_t addr, uint8_t val, void *p), @@ -895,27 +955,27 @@ svga_init(const device_t *info, svga_t *svga, void *p, int memsize, svga->dispontime = 1000ull << 32; svga->dispofftime = 1000ull << 32; svga->bpp = 8; - svga->vram = malloc(memsize); + svga->vram = calloc(memsize, 1); svga->vram_max = memsize; svga->vram_display_mask = svga->vram_mask = memsize - 1; svga->decode_mask = 0x7fffff; - svga->changedvram = malloc(memsize >> 12); + svga->changedvram = calloc(memsize >> 12, 1); svga->recalctimings_ex = recalctimings_ex; - svga->video_in = video_in; + svga->video_in = video_in; svga->video_out = video_out; svga->hwcursor_draw = hwcursor_draw; svga->overlay_draw = overlay_draw; - svga->hwcursor.xsize = svga->hwcursor.ysize = 32; - svga->hwcursor.yoff = 32; + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = 32; + + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 32; - svga->dac_hwcursor.yoff = 32; - svga->translate_address = NULL; - svga->ksc5601_english_font_type = 0; + svga->ksc5601_english_font_type = 0; - if ((info->flags & DEVICE_PCI) || (info->flags & DEVICE_VLB)) { + vga_on = 1; + + if ((info->flags & DEVICE_PCI) || (info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, @@ -950,6 +1010,9 @@ svga_close(svga_t *svga) free(svga->changedvram); free(svga->vram); + if (svga->dpms_ui) + ui_sb_set_text_w(NULL); + svga_pri = NULL; } @@ -996,7 +1059,7 @@ svga_decode_addr(svga_t *svga, uint32_t addr, int write) } -void +static __inline void svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) { svga_t *svga = (svga_t *)p; @@ -1009,11 +1072,26 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (svga->adv_flags & FLAG_ADDR_BY8) writemask2 = svga->seqregs[2]; - egawrites++; - - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; if (!linear) { + if (xga_enabled) { + if (((svga->xga.op_mode & 7) >= 4) && (svga->xga.aperture_cntl == 1)) { + if (val == 0xa5) { /*Memory size test of XGA*/ + svga->xga.test = val; + return; + } else if (val == 0x5a) { + svga->xga.test = val; + return; + } else if (val == 0x12 || val == 0x34) { + addr += svga->xga.write_bank; + svga->xga.vram[addr & svga->xga.vram_mask] = val; + svga->xga.linear_endian_reverse = 1; + return; + } + } else + svga->xga.on = 0; + } addr = svga_decode_addr(svga, addr, 1); if (addr == 0xffffffff) @@ -1021,13 +1099,20 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) } if (!(svga->gdcreg[6] & 1)) - svga->fullchange = 2; + svga->fullchange = 2; - if ((svga->adv_flags & FLAG_ADDR_BY8) && (svga->writemode < 4)) + if ((svga->adv_flags & FLAG_ADDR_BY16) && (svga->writemode == 4 || svga->writemode == 5)) + addr <<= 4; + else if ((svga->adv_flags & FLAG_ADDR_BY8) && (svga->writemode < 4)) addr <<= 3; - else if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { + else if (((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) && (svga->writemode < 4)) { writemask2 = 1 << (addr & 3); addr &= ~3; + } else if (svga->chain4 && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + if (!linear) + addr &= ~3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); } else if (svga->chain2_write) { writemask2 &= ~0xa; if (addr & 1) @@ -1053,14 +1138,21 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (svga->adv_flags & FLAG_LATCH8) count = 8; + /* Undocumented Cirrus Logic behavior: The datasheet says that, with EXT_WRITE and FLAG_ADDR_BY8, the write mask only + changes meaning in write modes 4 and 5, as well as write mode 1. In reality, however, all other write modes are also + affected, as proven by the Windows 3.1 CL-GD 5422/4 drivers in 8bpp modes. */ switch (svga->writemode) { case 0: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = val; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = val; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = val; + } } return; } else { @@ -1074,8 +1166,13 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) break; case 1: for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = svga->latch.b[i]; + } } return; case 2: @@ -1084,15 +1181,19 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } } return; } break; case 3: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); wm = svga->gdcreg[8]; svga->gdcreg[8] &= val; @@ -1110,26 +1211,46 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) switch (svga->gdcreg[3] & 0x18) { case 0x00: /* Set */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } } break; case 0x08: /* AND */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } } break; case 0x10: /* OR */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } } break; case 0x18: /* XOR */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } } break; } @@ -1139,7 +1260,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) } -uint8_t +static __inline uint8_t svga_read_common(uint32_t addr, uint8_t linear, void *p) { svga_t *svga = (svga_t *)p; @@ -1152,11 +1273,24 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) if (svga->adv_flags & FLAG_ADDR_BY8) readplane = svga->gdcreg[4] & 7; - sub_cycles(video_timing_read_b); - - egareads++; + cycles -= video_timing_read_b; if (!linear) { + if (xga_enabled) { + if (((svga->xga.op_mode & 7) >= 4) && (svga->xga.aperture_cntl == 1)) { + if (svga->xga.test == 0xa5) { /*Memory size test of XGA*/ + svga->xga.on = 1; + return svga->xga.test; + } else if (svga->xga.test == 0x5a) { + svga->xga.on = 1; + return svga->xga.test; + } else if (addr == 0xa0000 || addr == 0xa0010) { + addr += svga->xga.read_bank; + return svga->xga.vram[addr & svga->xga.vram_mask]; + } + } else + svga->xga.on = 0; + } addr = svga_decode_addr(svga, addr, 0); if (addr == 0xffffffff) @@ -1170,15 +1304,23 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) latch_addr = (addr << count) & svga->decode_mask; count = (1 << count); - if (svga->adv_flags & FLAG_ADDR_BY8) + if (svga->adv_flags & FLAG_ADDR_BY16) + addr <<= 4; + else if (svga->adv_flags & FLAG_ADDR_BY8) addr <<= 3; - else if (svga->chain4 || svga->fb_only) { + else if ((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) { addr &= svga->decode_mask; if (svga->translate_address) addr = svga->translate_address(addr, p); if (addr >= svga->vram_max) return 0xff; + latch_addr = (addr & svga->vram_mask) & ~3; + for (i = 0; i < count; i++) + svga->latch.b[i] = svga->vram[latch_addr | i]; return svga->vram[addr & svga->vram_mask]; + } else if (svga->chain4 && !svga->force_old_addr) { + readplane = addr & 3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); } else if (svga->chain2_read) { readplane = (readplane & 2) | (addr & 1); addr &= ~1; @@ -1258,7 +1400,7 @@ svga_read_linear(uint32_t addr, void *p) void -svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +svga_doblit(int wx, int wy, svga_t *svga) { int y_add, x_add, y_start, x_start, bottom; uint32_t *p; @@ -1277,15 +1419,8 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) bottom <<= 1; } - if ((wx <= 0) || (wy <= 0)) { - video_blit_memtoscreen(x_start, y_start, 0, 0, 0, 0); + if ((wx <= 0) || (wy <= 0)) return; - } - - if (y1 > y2) { - video_blit_memtoscreen(x_start, y_start, 0, 0, xsize + x_add, ysize + y_add); - return; - } if (svga->vertical_linedbl) svga->y_add <<= 1; @@ -1299,7 +1434,7 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) if (ys_temp < 32) ys_temp = 200; - if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + if ((svga->crtc[0x17] & 0x80) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { /* Screen res has changed.. fix up, and let them know. */ xsize = xs_temp; ysize = ys_temp; @@ -1313,7 +1448,10 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) } else suppress_overscan = 0; - set_screen_size(xsize + x_add, ysize + y_add); + /* Block resolution changes while in DPMS mode to avoid getting a bogus + screen width (320). We're already rendering a blank screen anyway. */ + if (!svga->dpms) + set_screen_size(xsize + x_add, ysize + y_add); if (video_force_resize_get()) video_force_resize_set(0); @@ -1336,7 +1474,7 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) } } - video_blit_memtoscreen(x_start, y_start, y1, y2 + y_add, xsize + x_add, ysize + y_add); + video_blit_memtoscreen(x_start, y_start, xsize + x_add, ysize + y_add); if (svga->vertical_linedbl) svga->vertical_linedbl >>= 1; @@ -1353,8 +1491,6 @@ svga_writeb_linear(uint32_t addr, uint8_t val, void *p) return; } - egawrites++; - addr &= svga->decode_mask; if (addr >= svga->vram_max) return; @@ -1375,9 +1511,7 @@ svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) return; } - egawrites += 2; - - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; if (!linear) { addr = svga_decode_addr(svga, addr, 1); @@ -1436,9 +1570,7 @@ svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) return; } - egawrites += 4; - - sub_cycles(video_timing_write_l); + cycles -= video_timing_write_l; if (!linear) { addr = svga_decode_addr(svga, addr, 1); @@ -1502,8 +1634,6 @@ svga_readb_linear(uint32_t addr, void *p) if (!svga->fast) return svga_read_linear(addr, p); - egareads++; - addr &= svga->decode_mask; if (addr >= svga->vram_max) return 0xff; @@ -1520,9 +1650,7 @@ svga_readw_common(uint32_t addr, uint8_t linear, void *p) if (!svga->fast) return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8); - egareads += 2; - - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; if (!linear) { addr = svga_decode_addr(svga, addr, 0); @@ -1573,9 +1701,7 @@ svga_readl_common(uint32_t addr, uint8_t linear, void *p) (svga_read_common(addr + 2, linear, p) << 16) | (svga_read_common(addr + 3, linear, p) << 24); } - egareads += 4; - - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; if (!linear) { addr = svga_decode_addr(svga, addr, 0); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index c76bf2d72..17b4c4981 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -27,7 +27,18 @@ #include <86box/video.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> +#include <86box/vid_svga_render_remap.h> +void +svga_render_null(svga_t *svga) +{ + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; +} void svga_render_blank(svga_t *svga) @@ -37,7 +48,7 @@ svga_render_blank(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -99,18 +110,19 @@ svga_render_overscan_right(svga_t *svga) void svga_render_text_40(svga_t *svga) -{ +{ uint32_t *p; int x, xx; int drawcursor, xinc; uint8_t chr, attr, dat; uint32_t charaddr; int fg, bg; + uint32_t addr = 0; if ((svga->displine + svga->y_add) < 0) return; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -119,40 +131,49 @@ svga_render_text_40(svga_t *svga) xinc = (svga->seqregs[1] & 1) ? 16 : 18; for (x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { + if (!svga->force_old_addr) + addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + if (svga->force_old_addr) { + chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + } else { + chr = svga->vram[addr]; + attr = svga->vram[addr+1]; + } if (attr & 8) charaddr = svga->charsetb + (chr * 128); else charaddr = svga->charseta + (chr * 128); if (drawcursor) { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; } else { fg = svga->pallook[svga->egapal[attr & 15]]; bg = svga->pallook[svga->egapal[attr >> 4]]; if (attr & 0x80 && svga->attrregs[0x10] & 8) { bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) + if (svga->blink & 16) fg = bg; } } dat = svga->vram[charaddr + (svga->sc << 2)]; if (svga->seqregs[1] & 1) { - for (xx = 0; xx < 16; xx += 2) + for (xx = 0; xx < 16; xx += 2) p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; } else { for (xx = 0; xx < 16; xx += 2) p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(svga->attrregs[0x10] & 4)) + if ((chr & ~0x1f) != 0xc0 || !(svga->attrregs[0x10] & 4)) p[16] = p[17] = bg; else p[16] = p[17] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->ma += 4; p += xinc; } svga->ma &= svga->vram_display_mask; @@ -169,11 +190,12 @@ svga_render_text_80(svga_t *svga) uint8_t chr, attr, dat; uint32_t charaddr; int fg, bg; + uint32_t addr = 0; if ((svga->displine + svga->y_add) < 0) return; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -182,46 +204,55 @@ svga_render_text_80(svga_t *svga) xinc = (svga->seqregs[1] & 1) ? 8 : 9; for (x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { + if (!svga->force_old_addr) + addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + if (svga->force_old_addr) { + chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + } else { + chr = svga->vram[addr]; + attr = svga->vram[addr+1]; + } if (attr & 8) charaddr = svga->charsetb + (chr * 128); else charaddr = svga->charseta + (chr * 128); if (drawcursor) { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; } else { fg = svga->pallook[svga->egapal[attr & 15]]; bg = svga->pallook[svga->egapal[attr >> 4]]; if (attr & 0x80 && svga->attrregs[0x10] & 8) { bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) + if (svga->blink & 16) fg = bg; } } dat = svga->vram[charaddr + (svga->sc << 2)]; - if (svga->seqregs[1] & 1) { - for (xx = 0; xx < 8; xx++) + if (svga->seqregs[1] & 1) { + for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; } else { - for (xx = 0; xx < 8; xx++) + for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) p[8] = bg; - else + else p[8] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->ma += 4; p += xinc; } svga->ma &= svga->vram_display_mask; } } - +/*Not available on most generic cards.*/ void svga_render_text_80_ksc5601(svga_t *svga) { @@ -235,7 +266,7 @@ svga_render_text_80_ksc5601(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -245,20 +276,21 @@ svga_render_text_80_ksc5601(svga_t *svga) xinc = (svga->seqregs[1] & 1) ? 8 : 9; for (x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { + uint32_t addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + chr = svga->vram[addr]; + nextchr = svga->vram[addr + 8]; + attr = svga->vram[addr + 1]; - if (drawcursor) { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; + if (drawcursor) { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; } else { fg = svga->pallook[svga->egapal[attr & 15]]; bg = svga->pallook[svga->egapal[attr >> 4]]; if (attr & 0x80 && svga->attrregs[0x10] & 8) { bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) + if (svga->blink & 16) fg = bg; } } @@ -278,38 +310,38 @@ svga_render_text_80_ksc5601(svga_t *svga) if (attr & 8) charaddr = svga->charsetb + (chr * 128); else charaddr = svga->charseta + (chr * 128); - if ((svga->ksc5601_english_font_type >> 8) == 1) + if ((svga->ksc5601_english_font_type >> 8) == 1) dat = fontdatksc5601[((svga->ksc5601_english_font_type & 0x7F) << 7) | (chr >> 1)].chr[((chr & 1) << 4) | svga->sc]; - else + else dat = svga->vram[charaddr + (svga->sc << 2)]; } if (svga->seqregs[1] & 1) { - for (xx = 0; xx < 8; xx++) + for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; } else { - for (xx = 0; xx < 8; xx++) + for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - if (((chr & ~0x1f) != 0xc0) || !(svga->attrregs[0x10] & 4)) + if (((chr & ~0x1f) != 0xc0) || !(svga->attrregs[0x10] & 4)) p[8] = bg; - else + else p[8] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->ma += 4; p += xinc; if ((x + xinc) < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80)) { attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; - if (drawcursor) { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; + if (drawcursor) { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; } else { fg = svga->pallook[svga->egapal[attr & 15]]; bg = svga->pallook[svga->egapal[attr >> 4]]; if (attr & 0x80 && svga->attrregs[0x10] & 8) { bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) + if (svga->blink & 16) fg = bg; } } @@ -321,19 +353,19 @@ svga_render_text_80_ksc5601(svga_t *svga) else dat = 0xff; - if (svga->seqregs[1] & 1) { - for (xx = 0; xx < 8; xx++) + if (svga->seqregs[1] & 1) { + for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; } else { - for (xx = 0; xx < 8; xx++) + for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - if (((chr & ~0x1f) != 0xc0) || !(svga->attrregs[0x10] & 4)) + if (((chr & ~0x1f) != 0xc0) || !(svga->attrregs[0x10] & 4)) p[8] = bg; - else + else p[8] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->ma += 4; p += xinc; x += xinc; } @@ -346,61 +378,96 @@ svga_render_text_80_ksc5601(svga_t *svga) void svga_render_2bpp_lowres(svga_t *svga) { - int changed_offset, x; + int changed_offset; + int x; uint8_t dat[2]; uint32_t addr, *p; + uint32_t changed_addr; if ((svga->displine + svga->y_add) < 0) return; - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + if (svga->force_old_addr) { + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { + addr = svga->ma; - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - addr &= ~7; + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + addr &= ~7; - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr | 0x1]; + if (svga->seqregs[1] & 4) + svga->ma += 2; + else + svga->ma += 4; + svga->ma &= svga->vram_mask; + p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + p += 16; } + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { + addr = svga->remap_func(svga, svga->ma); - svga->ma &= svga->vram_mask; + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr | 0x1]; + if (svga->seqregs[1] & 4) + svga->ma += 2; + else + svga->ma += 4; - p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + svga->ma &= svga->vram_mask; - p += 16; + p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 16; + } } } } @@ -409,16 +476,117 @@ svga_render_2bpp_lowres(svga_t *svga) void svga_render_2bpp_highres(svga_t *svga) { - int changed_offset, x; + int changed_offset; + int x; uint8_t dat[2]; uint32_t addr, *p; + uint32_t changed_addr; if ((svga->displine + svga->y_add) < 0) return; - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + if (svga->force_old_addr) { + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->ma; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr | 0x1]; + if (svga->seqregs[1] & 4) + svga->ma += 2; + else + svga->ma += 4; + svga->ma &= svga->vram_mask; + p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; + p += 8; + } + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->remap_func(svga, svga->ma); + + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr | 0x1]; + if (svga->seqregs[1] & 4) + svga->ma += 2; + else + svga->ma += 4; + + svga->ma &= svga->vram_mask; + + p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 8; + } + } + } +} + + +void +svga_render_2bpp_headland_highres(svga_t *svga) +{ + int x; + int oddeven; + uint32_t addr, *p; + uint8_t edat[4]; + uint8_t dat; + uint32_t changed_addr; + + if ((svga->displine + svga->y_add) < 0) + return; + + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -426,173 +594,18 @@ svga_render_2bpp_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - - svga->ma &= svga->vram_mask; - - p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; - - p += 8; - } - } -} - - -void -svga_render_4bpp_lowres(svga_t *svga) -{ - int x, oddeven; - uint32_t addr, *p; - uint8_t edat[4]; - uint8_t dat; - - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; + addr = svga->remap_func(svga, svga->ma); oddeven = 0; - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - if (svga->seqregs[1] & 4) { + oddeven = (addr & 4) ? 1 : 0; edat[0] = svga->vram[addr | oddeven]; edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; + edat[1] = edat[3] = 0; } else { *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 16; - } - } -} - - -void -svga_render_4bpp_highres(svga_t *svga) -{ - int changed_offset, x; - int oddeven; - uint32_t addr, *p; - uint8_t edat[4]; - uint8_t dat; - - if ((svga->displine + svga->y_add) < 0) - return; - - changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; - oddeven = 0; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - if (svga->seqregs[1] & 4) { - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); - svga->ma += 4; } + svga->ma += 4; svga->ma &= svga->vram_mask; dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); @@ -613,9 +626,399 @@ svga_render_4bpp_highres(svga_t *svga) } } +void +svga_render_4bpp_lowres(svga_t *svga) +{ + int x, oddeven; + uint32_t addr, *p; + uint8_t edat[4]; + uint8_t dat; + uint32_t changed_addr; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { + addr = svga->ma; + oddeven = 0; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + if (svga->seqregs[1] & 4) { + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 16; + } + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { + addr = svga->remap_func(svga, svga->ma); + oddeven = 0; + + if (svga->seqregs[1] & 4) { + oddeven = (addr & 4) ? 1 : 0; + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 16; + } + } + } +} + + +void +svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset; + int x, oddeven; + uint32_t addr, *p; + uint8_t edat[4]; + uint8_t dat; + uint32_t changed_addr; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->force_old_addr) { + changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->ma; + oddeven = 0; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + if (svga->seqregs[1] & 4) { + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->remap_func(svga, svga->ma); + oddeven = 0; + + if (svga->seqregs[1] & 4) { + oddeven = (addr & 4) ? 1 : 0; + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } + } +} + void svga_render_8bpp_lowres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + uint32_t changed_addr; + uint32_t addr; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + + p[0] = p[1] = svga->map8[dat & 0xff]; + p[2] = p[3] = svga->map8[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->map8[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = p[1] = svga->map8[dat & 0xff]; + p[2] = p[3] = svga->map8[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->map8[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + p[0] = p[1] = svga->map8[dat & 0xff]; + p[2] = p[3] = svga->map8[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->map8[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + } + svga->ma &= svga->vram_display_mask; + } + } +} + + +void +svga_render_8bpp_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + uint32_t changed_addr; + uint32_t addr; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp/* + svga->scrollcache*/); x += 8) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = svga->map8[dat & 0xff]; + p[1] = svga->map8[(dat >> 8) & 0xff]; + p[2] = svga->map8[(dat >> 16) & 0xff]; + p[3] = svga->map8[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + p[4] = svga->map8[dat & 0xff]; + p[5] = svga->map8[(dat >> 8) & 0xff]; + p[6] = svga->map8[(dat >> 16) & 0xff]; + p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp/* + svga->scrollcache*/); x += 8) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = svga->map8[dat & 0xff]; + p[1] = svga->map8[(dat >> 8) & 0xff]; + p[2] = svga->map8[(dat >> 16) & 0xff]; + p[3] = svga->map8[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + p[4] = svga->map8[dat & 0xff]; + p[5] = svga->map8[(dat >> 8) & 0xff]; + p[6] = svga->map8[(dat >> 16) & 0xff]; + p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 8; + p += 8; + } + } else { + for (x = 0; x <= (svga->hdisp/* + svga->scrollcache*/); x += 4) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + p[0] = svga->map8[dat & 0xff]; + p[1] = svga->map8[(dat >> 8) & 0xff]; + p[2] = svga->map8[(dat >> 16) & 0xff]; + p[3] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 4; + } + } + svga->ma &= svga->vram_display_mask; + } + } +} + +void +svga_render_8bpp_tseng_lowres(svga_t *svga) { int x; uint32_t *p; @@ -627,17 +1030,27 @@ svga_render_8bpp_lowres(svga_t *svga) if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); - + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[0] = p[1] = svga->map8[dat & 0xff]; - p[2] = p[3] = svga->map8[(dat >> 8) & 0xff]; - p[4] = p[5] = svga->map8[(dat >> 16) & 0xff]; - p[6] = p[7] = svga->map8[(dat >> 24) & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[2] = p[3] = svga->map8[dat & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[4] = p[5] = svga->map8[dat & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[6] = p[7] = svga->map8[dat & 0xff]; svga->ma += 4; p += 8; @@ -648,7 +1061,7 @@ svga_render_8bpp_lowres(svga_t *svga) void -svga_render_8bpp_highres(svga_t *svga) +svga_render_8bpp_tseng_highres(svga_t *svga) { int x; uint32_t *p; @@ -660,22 +1073,44 @@ svga_render_8bpp_highres(svga_t *svga) if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp/* + svga->scrollcache*/); x += 8) { dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[0] = svga->map8[dat & 0xff]; - p[1] = svga->map8[(dat >> 8) & 0xff]; - p[2] = svga->map8[(dat >> 16) & 0xff]; - p[3] = svga->map8[(dat >> 24) & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[1] = svga->map8[dat & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[2] = svga->map8[dat & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[3] = svga->map8[dat & 0xff]; dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[4] = svga->map8[dat & 0xff]; - p[5] = svga->map8[(dat >> 8) & 0xff]; - p[6] = svga->map8[(dat >> 16) & 0xff]; - p[7] = svga->map8[(dat >> 24) & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[5] = svga->map8[dat & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[6] = svga->map8[dat & 0xff]; + dat >>= 8; + if (svga->attrregs[0x10] & 0x80) + dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); + p[7] = svga->map8[dat & 0xff]; svga->ma += 8; p += 8; @@ -691,32 +1126,68 @@ svga_render_15bpp_lowres(svga_t *svga) int x; uint32_t *p; uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[(x << 1)] = p[(x << 1) + 1] = video_15to32[dat & 0xffff]; + p[(x << 1)] = p[(x << 1) + 1] = video_15to32[dat & 0xffff]; + p[(x << 1) + 2] = p[(x << 1) + 3] = video_15to32[dat >> 16]; - p[(x << 1) + 2] = p[(x << 1) + 3] = video_15to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - - p[(x << 1) + 4] = p[(x << 1) + 5] = video_15to32[dat & 0xffff]; - - p[(x << 1) + 6] = p[(x << 1) + 7] = video_15to32[dat >> 16]; + p[(x << 1) + 4] = p[(x << 1) + 5] = video_15to32[dat & 0xffff]; + p[(x << 1) + 6] = p[(x << 1) + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; } } @@ -727,36 +1198,80 @@ svga_render_15bpp_highres(svga_t *svga) int x; uint32_t *p; uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x + 2] = video_15to32[dat & 0xffff]; - p[x + 3] = video_15to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = video_15to32[dat & 0xffff]; + p[x + 3] = video_15to32[dat >> 16]; - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); - p[x + 4] = video_15to32[dat & 0xffff]; - p[x + 5] = video_15to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = video_15to32[dat & 0xffff]; + p[x + 5] = video_15to32[dat >> 16]; - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); - p[x + 6] = video_15to32[dat & 0xffff]; - p[x + 7] = video_15to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = video_15to32[dat & 0xffff]; + p[x + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; } } @@ -774,7 +1289,7 @@ svga_render_15bpp_mix_lowres(svga_t *svga) if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -810,7 +1325,7 @@ svga_render_15bpp_mix_highres(svga_t *svga) if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -835,7 +1350,7 @@ svga_render_15bpp_mix_highres(svga_t *svga) dat >>= 16; p[x + 7] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; } - svga->ma += x << 1; + svga->ma += x << 1; svga->ma &= svga->vram_display_mask; } } @@ -847,29 +1362,67 @@ svga_render_16bpp_lowres(svga_t *svga) int x; uint32_t *p; uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[(x << 1)] = p[(x << 1) + 1] = video_16to32[dat & 0xffff]; - p[(x << 1) + 2] = p[(x << 1) + 3] = video_16to32[dat >> 16]; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[(x << 1)] = p[(x << 1) + 1] = video_16to32[dat & 0xffff]; + p[(x << 1) + 2] = p[(x << 1) + 3] = video_16to32[dat >> 16]; - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[(x << 1) + 4] = p[(x << 1) + 5] = video_16to32[dat & 0xffff]; - p[(x << 1) + 6] = p[(x << 1) + 7] = video_16to32[dat >> 16]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[(x << 1) + 4] = p[(x << 1) + 5] = video_16to32[dat & 0xffff]; + p[(x << 1) + 6] = p[(x << 1) + 7] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + } + svga->ma += 4; + } + svga->ma &= svga->vram_display_mask; + } } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; - } } @@ -878,14 +1431,17 @@ svga_render_16bpp_highres(svga_t *svga) { int x; uint32_t *p; + uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; + if (svga->force_old_addr) { if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -906,9 +1462,52 @@ svga_render_16bpp_highres(svga_t *svga) p[x + 6] = video_16to32[dat & 0xffff]; p[x + 7] = video_16to32[dat >> 16]; } - svga->ma += x << 1; + svga->ma += x << 1; svga->ma &= svga->vram_display_mask; } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; + } + } } @@ -916,24 +1515,74 @@ void svga_render_24bpp_lowres(svga_t *svga) { int x; - uint32_t fg; + uint32_t *p; + uint32_t changed_addr, addr; + uint32_t dat0, dat1, dat2; + uint32_t fg; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->force_old_addr) { + if ((svga->displine + svga->y_add) < 0) + return; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); - svga->ma += 3; + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vram_display_mask; + buffer32->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = + buffer32->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = fg; + } + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat0 = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + dat1 = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat2 = *(uint32_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + + p[0] = p[1] = dat0 & 0xffffff; + p[2] = p[3] = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + p[4] = p[5] = (dat1 >> 16) | ((dat2 & 0xff) << 16); + p[6] = p[7] = dat2 >> 8; + + svga->ma += 12; + } + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + addr = svga->remap_func(svga, svga->ma); + dat0 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 4); + dat1 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 8); + dat2 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + p[0] = p[1] = dat0 & 0xffffff; + p[2] = p[3] = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + p[4] = p[5] = (dat1 >> 16) | ((dat2 & 0xff) << 16); + p[6] = p[7] = dat2 >> 8; + + svga->ma += 12; + } + } svga->ma &= svga->vram_display_mask; - buffer32->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = - buffer32->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = fg; + } } - } } @@ -942,35 +1591,81 @@ svga_render_24bpp_highres(svga_t *svga) { int x; uint32_t *p; - uint32_t dat; + uint32_t changed_addr, addr; + uint32_t dat0, dat1, dat2; + uint32_t dat; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); - p[x] = dat & 0xffffff; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[x] = dat & 0xffffff; - dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); - p[x + 1] = dat & 0xffffff; + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + p[x + 1] = dat & 0xffffff; - dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); - p[x + 2] = dat & 0xffffff; + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + p[x + 2] = dat & 0xffffff; - dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); - p[x + 3] = dat & 0xffffff; + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + p[x + 3] = dat & 0xffffff; - svga->ma += 12; + svga->ma += 12; + } + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat0 = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + dat1 = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat2 = *(uint32_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + + *p++ = dat0 & 0xffffff; + *p++ = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + *p++ = (dat1 >> 16) | ((dat2 & 0xff) << 16); + *p++ = dat2 >> 8; + + svga->ma += 12; + } + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + addr = svga->remap_func(svga, svga->ma); + dat0 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 4); + dat1 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 8); + dat2 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = dat0 & 0xffffff; + *p++ = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + *p++ = (dat1 >> 16) | ((dat2 & 0xff) << 16); + *p++ = dat2 >> 8; + + svga->ma += 12; + } + } + svga->ma &= svga->vram_display_mask; + } } - svga->ma &= svga->vram_display_mask; - } } @@ -978,24 +1673,56 @@ void svga_render_32bpp_lowres(svga_t *svga) { int x; - uint32_t fg; + uint32_t *p; + uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); - svga->ma += 4; - svga->ma &= svga->vram_display_mask; - buffer32->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = - buffer32->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = fg; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + buffer32->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = + buffer32->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = dat; + } + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + *p++ = dat & 0xffffff; + } + svga->ma += (x * 4); + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + *p++ = dat & 0xffffff; + svga->ma += 4; + } + svga->ma &= svga->vram_display_mask; + } + } } - } } @@ -1005,24 +1732,54 @@ svga_render_32bpp_highres(svga_t *svga) int x; uint32_t *p; uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { - p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->force_old_addr) { + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - p[x] = dat & 0xffffff; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = dat & 0xffffff; + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } + } else { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + } + svga->ma += (x * 4); + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; + } } - svga->ma += 4; - svga->ma &= svga->vram_display_mask; - } } @@ -1032,22 +1789,35 @@ svga_render_ABGR8888_highres(svga_t *svga) int x; uint32_t *p; uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) + + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += x*4; + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + + svga->ma += 4; + } } - svga->ma += 4; svga->ma &= svga->vram_display_mask; } } @@ -1059,22 +1829,35 @@ svga_render_RGBA8888_highres(svga_t *svga) int x; uint32_t *p; uint32_t dat; + uint32_t changed_addr, addr; if ((svga->displine + svga->y_add) < 0) - return; + return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) + + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - p[x] = dat >> 8; + if (!svga->remap_required) { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = dat >> 8; + } + svga->ma += (x * 4); + } else { + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + addr = svga->remap_func(svga, svga->ma); + dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = dat >> 8; + + svga->ma += 4; + } } - svga->ma += 4; svga->ma &= svga->vram_display_mask; } } diff --git a/src/video/vid_table.c b/src/video/vid_table.c index acff552ea..94d4601a8 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -1,20 +1,20 @@ /* - * 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. + * 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. + * This file is part of the 86Box distribution. * - * Define all known video cards. + * Define all known video cards. * * * - * Authors: Miran Grca, - * Fred N. van Kempen, + * Authors: Miran Grca, + * Fred N. van Kempen, * - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -39,9 +39,8 @@ typedef struct { - const char *name; - const char *internal_name; - const device_t *device; + const device_t *device; + int flags; } VIDEO_CARD; @@ -49,120 +48,209 @@ static video_timings_t timing_default = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; static int was_reset = 0; +static const device_t vid_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; +static const device_t vid_internal_device = { + .name = "Internal", + .internal_name = "internal", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; static const VIDEO_CARD video_cards[] = { - { "None", "none", NULL }, - { "Internal", "internal", NULL }, - { "[ISA] ATI EGA Wonder 800+", "egawonder800", &atiega_device }, - { "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device }, - { "[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device }, - { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device }, - { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device }, - { "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device }, -#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) - { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device }, -#endif +// clang-format off + { &vid_none_device }, + { &vid_internal_device }, + { &atiega_device }, + { &mach64gx_isa_device }, + { &ati28800k_device }, + { &ati18800_vga88_device }, + { &ati28800_device }, + { &compaq_ati28800_device }, #if defined(DEV_BRANCH) && defined(USE_XL24) - { "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device }, + { &ati28800_wonderxl24_device }, #endif - { "[ISA] CGA", "cga", &cga_device }, - { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device }, - { "[ISA] Cirrus Logic CL-GD 5401", "cl_gd5401_isa", &gd5401_isa_device }, - { "[ISA] Cirrus Logic CL-GD 5402", "cl_gd5402_isa", &gd5402_isa_device }, - { "[ISA] Cirrus Logic CL-GD 5420", "cl_gd5420_isa", &gd5420_isa_device }, -#if defined(DEV_BRANCH) && defined(USE_CL5422) - { "[ISA] Cirrus Logic CL-GD 5422", "cl_gd5422_isa", &gd5422_isa_device }, + { &ati18800_device }, +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + { &ati18800_wonder_device }, #endif - { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device }, - { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device }, - { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device }, - { "[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)", "compaq_ati28800", &compaq_ati28800_device }, - { "[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device }, - { "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device }, - { "[ISA] Compaq EGA", "compaq_ega", &cpqega_device }, - { "[ISA] EGA", "ega", &ega_device }, - { "[ISA] G2 GC205", "g2_gc205", &g2_gc205_device }, - { "[ISA] Hercules", "hercules", &hercules_device }, - { "[ISA] Hercules Plus", "hercules_plus", &herculesplus_device }, - { "[ISA] Hercules InColor", "incolor", &incolor_device }, - { "[ISA] Image Manager 1024", "im1024", &im1024_device }, - { "[ISA] Kasan Hangulmadang-16 VGA (ET4000AX)", "kasan16vga", &et4000_kasan_isa_device }, - { "[ISA] MDA", "mda", &mda_device }, - { "[ISA] MDSI Genius", "genius", &genius_device }, - { "[ISA] OAK OTI-037C", "oti037c", &oti037c_device }, - { "[ISA] OAK OTI-067", "oti067", &oti067_device }, - { "[ISA] OAK OTI-077", "oti077", &oti077_device }, - { "[ISA] Orchid Fahrenheit 1280 (S3 86c911)", "orchid_s3_911", &s3_orchid_86c911_isa_device }, - { "[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device }, - { "[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device }, - { "[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device }, - { "[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device }, - { "[ISA] Professional Graphics Controller", "pgc", &pgc_device }, - { "[ISA] Sigma Color 400", "sigma400", &sigma_device }, - { "[ISA] SPEA V7 Mirage (S3 86c801)", "px_s3_v7_801_isa", &s3_v7mirage_86c801_isa_device }, - { "[ISA] Trident TVGA8900B", "tvga8900b", &tvga8900b_device }, - { "[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device }, - { "[ISA] Trigem Korean VGA (ET4000AX)", "tgkorvga", &et4000k_isa_device }, - { "[ISA] Tseng ET4000AX", "et4000ax", &et4000_isa_device }, - { "[ISA] VGA", "vga", &vga_device }, - { "[ISA] Video 7 VGA 1024i", "v7_vga_1024i", &v7_vga_1024i_device }, - { "[ISA] Wyse 700", "wy700", &wy700_device }, - { "[MCA] IBM 1MB SVGA Adapter/A (CL-GD 5428)", "ibm1mbsvga", &gd5428_mca_device }, - { "[MCA] Tseng ET4000AX", "et4000mca", &et4000_mca_device }, - { "[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device }, - { "[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device }, - { "[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device }, - { "[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, }, - { "[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device }, - { "[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device }, - { "[PCI] Cirrus Logic CL-GD 5440", "cl_gd5440_pci", &gd5440_pci_device }, - { "[PCI] Cirrus Logic CL-GD 5446", "cl_gd5446_pci", &gd5446_pci_device }, - { "[PCI] Cirrus Logic CL-GD 5480", "cl_gd5480_pci", &gd5480_pci_device }, - { "[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_pci", &et4000w32p_pci_device }, - { "[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci", &s3_virge_pci_device }, - { "[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci", &s3_virge_988_pci_device }, - { "[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device }, - { "[PCI] Diamond Stealth 64 VRAM (S3 Vision964)", "stealth64v_pci", &s3_diamond_stealth64_964_pci_device }, + { &cga_device }, + { &sega_device }, + { &gd5401_isa_device }, + { &gd5402_isa_device }, + { &gd5420_isa_device }, + { &gd5422_isa_device }, + { &gd5426_isa_device }, + { &gd5426_diamond_speedstar_pro_a1_isa_device }, + { &gd5428_isa_device }, + { &gd5429_isa_device }, + { &gd5434_isa_device }, + { &gd5434_diamond_speedstar_64_a3_isa_device }, + { &compaq_cga_device }, + { &compaq_cga_2_device }, + { &cpqega_device }, + { &ega_device }, + { &g2_gc205_device }, + { &hercules_device, VIDEO_FLAG_TYPE_MDA }, + { &herculesplus_device, VIDEO_FLAG_TYPE_MDA }, + { &incolor_device }, + { &im1024_device }, + { &iskra_ega_device }, + { &et4000_kasan_isa_device }, + { &mda_device, VIDEO_FLAG_TYPE_MDA }, + { &genius_device }, + { &nga_device }, + { &ogc_device }, + { &oti037c_device }, + { &oti067_device }, + { &oti077_device }, + { ¶dise_pvga1a_device }, + { ¶dise_wd90c11_device }, + { ¶dise_wd90c30_device }, + { &colorplus_device }, + { &pgc_device }, + { &radius_svga_multiview_isa_device }, + { &realtek_rtg3106_device }, + { &s3_diamond_stealth_vram_isa_device }, + { &s3_orchid_86c911_isa_device }, + { &s3_ami_86c924_isa_device }, + { &s3_metheus_86c928_isa_device }, + { &s3_phoenix_86c801_isa_device }, + { &s3_spea_mirage_86c801_isa_device }, + { &sigma_device }, + { &tvga8900b_device }, + { &tvga8900d_device }, + { &tvga9000b_device }, + { &et4000k_isa_device }, + { &et2000_device }, + { &et4000_isa_device }, + { &et4000w32_device }, + { &et4000w32i_isa_device }, + { &vga_device }, + { &v7_vga_1024i_device }, + { &wy700_device }, + { &gd5426_mca_device }, + { &gd5428_mca_device }, + { &et4000_mca_device }, + { &radius_svga_multiview_mca_device }, + { &mach64gx_pci_device }, + { &mach64vt2_device }, + { &et4000w32p_videomagic_revb_pci_device }, + { &et4000w32p_revc_pci_device }, + { &et4000w32p_cardex_pci_device }, + { &et4000w32p_noncardex_pci_device }, + { &et4000w32p_pci_device }, + { &gd5430_pci_device, }, + { &gd5434_pci_device }, + { &gd5436_pci_device }, + { &gd5440_pci_device }, + { &gd5446_pci_device }, + { &gd5446_stb_pci_device }, + { &gd5480_pci_device }, + { &s3_spea_mercury_lite_86c928_pci_device }, + { &s3_diamond_stealth64_964_pci_device }, + { &s3_elsa_winner2000_pro_x_964_pci_device }, + { &s3_mirocrystal_20sv_964_pci_device }, + { &s3_bahamas64_pci_device }, + { &s3_phoenix_vision864_pci_device }, + { &s3_diamond_stealth_se_pci_device }, + { &s3_phoenix_trio32_pci_device }, + { &s3_diamond_stealth64_pci_device }, + { &s3_9fx_pci_device }, + { &s3_phoenix_trio64_pci_device }, + { &s3_elsa_winner2000_pro_x_pci_device }, + { &s3_mirovideo_40sv_ergo_968_pci_device }, + { &s3_9fx_771_pci_device }, + { &s3_phoenix_vision968_pci_device }, + { &s3_spea_mercury_p64v_pci_device }, + { &s3_9fx_531_pci_device }, + { &s3_phoenix_vision868_pci_device }, + { &s3_phoenix_trio64vplus_pci_device }, + { &s3_trio64v2_dx_pci_device }, + { &s3_virge_325_pci_device }, + { &s3_diamond_stealth_2000_pci_device }, + { &s3_diamond_stealth_3000_pci_device }, + { &s3_stb_velocity_3d_pci_device }, + { &s3_virge_375_pci_device }, + { &s3_diamond_stealth_2000pro_pci_device }, + { &s3_virge_385_pci_device }, + { &s3_virge_357_pci_device }, + { &s3_diamond_stealth_4000_pci_device }, + { &s3_trio3d2x_pci_device }, #if defined(DEV_BRANCH) && defined(USE_MGA) - { "[PCI] Matrox Mystique", "mystique", &mystique_device }, - { "[PCI] Matrox Mystique 220", "mystique_220", &mystique_220_device }, + { &millennium_device }, + { &mystique_device }, + { &mystique_220_device }, #endif - { "[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device }, - { "[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device }, - { "[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device }, - { "[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device }, - { "[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device }, - { "[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device }, - { "[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci", &s3_virge_375_4_pci_device }, - { "[PCI] STB Nitro 64V (CL-GD 5446)", "cl_gd5446_stb_pci", &gd5446_stb_pci_device }, - { "[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device }, - { "[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device }, - { "[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device }, -#if defined(DEV_BRANCH) && defined(USE_CL5422) - { "[VLB] Cirrus Logic CL-GD 5424", "cl_gd5424_vlb", &gd5424_vlb_device }, -#endif - { "[VLB] Cirrus Logic CL-GD 5428", "cl_gd5428_vlb", &gd5428_vlb_device }, - { "[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device }, - { "[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device }, - { "[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_vlb", &et4000w32p_vlb_device }, - { "[VLB] Diamond SpeedStar PRO (CL-GD 5426)", "cl_gd5426_vlb", &gd5426_vlb_device }, - { "[VLB] Diamond SpeedStar PRO SE (CL-GD 5430)", "cl_gd5430_vlb", &gd5430_vlb_device }, - { "[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb", &s3_virge_vlb_device }, - { "[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb", &s3_virge_988_vlb_device }, - { "[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device }, - { "[VLB] Diamond Stealth 64 VRAM (S3 Vision964)", "stealth64v_vlb", &s3_diamond_stealth64_964_vlb_device }, - { "[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device }, - { "[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device }, - { "[VLB] Phoenix S3 86c805", "px_86c805_vlb", &s3_phoenix_86c805_vlb_device }, - { "[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device }, - { "[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device }, - { "[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device }, - { "[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device }, - { "[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb", &s3_virge_375_4_vlb_device }, - { "[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device }, - { "[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device }, - { "", "", NULL } + { &tgui9440_pci_device }, + { &tgui9660_pci_device }, + { &tgui9680_pci_device }, + { &voodoo_banshee_device }, + { &creative_voodoo_banshee_device }, + { &voodoo_3_2000_device }, + { &voodoo_3_3000_device }, + { &mach64gx_vlb_device }, + { &et4000w32i_vlb_device }, + { &et4000w32p_videomagic_revb_vlb_device }, + { &et4000w32p_revc_vlb_device }, + { &et4000w32p_cardex_vlb_device }, + { &et4000w32p_vlb_device }, + { &et4000w32p_noncardex_vlb_device }, + { &gd5424_vlb_device }, + { &gd5426_vlb_device }, + { &gd5428_vlb_device }, + { &gd5428_diamond_speedstar_pro_b1_vlb_device }, + { &gd5429_vlb_device }, + { &gd5430_diamond_speedstar_pro_se_a8_vlb_device }, + { &gd5434_vlb_device }, + { &s3_metheus_86c928_vlb_device }, + { &s3_mirocrystal_8s_805_vlb_device }, + { &s3_mirocrystal_10sd_805_vlb_device }, + { &s3_phoenix_86c805_vlb_device }, + { &s3_spea_mirage_86c805_vlb_device }, + { &s3_diamond_stealth64_964_vlb_device }, + { &s3_mirocrystal_20sv_964_vlb_device }, + { &s3_mirocrystal_20sd_864_vlb_device }, + { &s3_bahamas64_vlb_device }, + { &s3_phoenix_vision864_vlb_device }, + { &s3_diamond_stealth_se_vlb_device }, + { &s3_phoenix_trio32_vlb_device }, + { &s3_diamond_stealth64_vlb_device }, + { &s3_9fx_vlb_device }, + { &s3_phoenix_trio64_vlb_device }, + { &s3_spea_mirage_p64_vlb_device }, + { &s3_phoenix_vision968_vlb_device }, + { &s3_phoenix_vision868_vlb_device }, + { &ht216_32_standalone_device }, + { &tgui9400cxi_device }, + { &tgui9440_vlb_device }, + { &s3_virge_357_agp_device }, + { &s3_diamond_stealth_4000_agp_device }, + { &s3_trio3d2x_agp_device }, + { &velocity_100_agp_device }, + { &voodoo_3_2000_agp_device }, + { &voodoo_3_3000_agp_device }, + { NULL } +// clang-format off }; @@ -176,9 +264,9 @@ vid_table_log(const char *fmt, ...) va_list ap; if (vid_table_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else @@ -189,52 +277,86 @@ vid_table_log(const char *fmt, ...) void video_reset_close(void) { + for (int i = 1; i < MONITORS_NUM; i++) + video_monitor_close(i); + + monitor_index_global = 0; video_inform(VIDEO_FLAG_TYPE_NONE, &timing_default); was_reset = 0; } +static void +video_prepare(void) +{ + /* Reset (deallocate) the video font arrays. */ + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + + /* Reset the blend. */ + herc_blend = 0; + + for (int i = 0; i < MONITORS_NUM; i++) { + /* Reset the CGA palette. */ + if (monitors[i].mon_cga_palette) *monitors[i].mon_cga_palette = 0; + cgapal_rebuild_monitor(i); + + /* Do an inform on the default values, so that that there's some sane values initialized + even if the device init function does not do an inform of its own. */ + video_inform_monitor(VIDEO_FLAG_TYPE_SPECIAL, &timing_default, i); + } +} + + +void +video_pre_reset(int card) +{ + if ((card == VID_NONE) || \ + (card == VID_INTERNAL) || machine_has_flags(machine, MACHINE_VIDEO_ONLY)) + video_prepare(); +} + + void video_reset(int card) { /* This is needed to avoid duplicate resets. */ if ((video_get_type() != VIDEO_FLAG_TYPE_NONE) && was_reset) - return; + return; vid_table_log("VIDEO: reset (gfxcard=%d, internal=%d)\n", - card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + card, machine_has_flags(machine, MACHINE_VIDEO) ? 1 : 0); - loadfont(L"roms/video/mda/mda.rom", 0); - - /* Reset (deallocate) the video font arrays. */ - if (fontdatksc5601) { - free(fontdatksc5601); - fontdatksc5601 = NULL; - } - - /* Reset the CGA palette. */ - cga_palette = 0; - cgapal_rebuild(); - - /* Reset the blend. */ - herc_blend = 0; + monitor_index_global = 0; + loadfont("roms/video/mda/mda.rom", 0); /* Do not initialize internal cards here. */ if (!(card == VID_NONE) && \ - !(card == VID_INTERNAL) && !(machines[machine].flags & MACHINE_VIDEO_FIXED)) { - vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); + !(card == VID_INTERNAL) && !machine_has_flags(machine, MACHINE_VIDEO_ONLY)) { + vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); - /* Do an inform on the default values, so that that there's some sane values initialized - even if the device init function does not do an inform of its own. */ - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_default); + video_prepare(); - /* Initialize the video card. */ - device_add(video_cards[card].device); + /* Initialize the video card. */ + device_add(video_cards[card].device); + } + + if (!(card == VID_NONE) + && !machine_has_flags(machine, MACHINE_VIDEO_ONLY) + && gfxcard_2 != 0 + && (video_cards[gfxcard_2].flags != video_cards[gfxcard].flags) + && device_is_valid(video_card_getdevice(gfxcard_2), machine)) { + video_monitor_init(1); + monitor_index_global = 1; + device_add(video_cards[gfxcard_2].device); + monitor_index_global = 0; } /* Enable the Voodoo if configured. */ if (voodoo_enabled) - device_add(&voodoo_device); + device_add(&voodoo_device); was_reset = 1; } @@ -244,19 +366,17 @@ int video_card_available(int card) { if (video_cards[card].device) - return(device_available(video_cards[card].device)); + return(device_available(video_cards[card].device)); return(1); } - -char * -video_card_getname(int card) +int +video_card_get_flags(int card) { - return((char *) video_cards[card].name); + return video_cards[card].flags; } - const device_t * video_card_getdevice(int card) { @@ -269,29 +389,14 @@ video_card_has_config(int card) { if (video_cards[card].device == NULL) return(0); - return(video_cards[card].device->config ? 1 : 0); -} - - -int -video_card_getid(char *s) -{ - int c = 0; - - while (video_cards[c].name != NULL) { - if (!strcmp((char *) video_cards[c].name, s)) - return(c); - c++; - } - - return(0); + return(device_has_config(video_cards[card].device) ? 1 : 0); } char * video_get_internal_name(int card) { - return((char *) video_cards[card].internal_name); + return device_get_internal_name(video_cards[card].device); } @@ -300,10 +405,10 @@ video_get_video_from_internal_name(char *s) { int c = 0; - while (video_cards[c].name != NULL) { - if (!strcmp((char *) video_cards[c].internal_name, s)) - return(c); - c++; + while (video_cards[c].device != NULL) { + if (!strcmp((char *) video_cards[c].device->internal_name, s)) + return(c); + c++; } return(0); diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 718def535..bac0242e1 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -70,164 +70,130 @@ #include "cpu.h" #include <86box/plat.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> -/*TGUI9400CXi has extended write modes, controlled by extended GDC registers : - - GDC[0x10] - Control - bit 0 - pixel width (1 = 16 bit, 0 = 8 bit) - bit 1 - mono->colour expansion (1 = enabled, 0 = disabled) - bit 2 - mono->colour expansion transparency (1 = tranparent, 0 = opaque) - bit 3 - extended latch copy - GDC[0x11] - Background colour (low byte) - GDC[0x12] - Background colour (high byte) - GDC[0x14] - Foreground colour (low byte) - GDC[0x15] - Foreground colour (high byte) - GDC[0x17] - Write mask (low byte) - GDC[0x18] - Write mask (high byte) - - Mono->colour expansion will expand written data 8:1 to 8/16 consecutive bytes. - MSB is processed first. On word writes, low byte is processed first. 1 bits write - foreground colour, 0 bits write background colour unless transparency is enabled. - If the relevant bit is clear in the write mask then the data is not written. - - With 16-bit pixel width, each bit still expands to one byte, so the TGUI driver - doubles up monochrome data. - - While there is room in the register map for three byte colours, I don't believe - 24-bit colour is supported. The TGUI9440 blitter has the same limitation. - - I don't think double word writes are supported. - - Extended latch copy uses an internal 16 byte latch. Reads load the latch, writing - writes out 16 bytes. I don't think the access size or host data has any affect, - but the Windows 3.1 driver always reads bytes and write words of 0xffff.*/ - -#define ROM_TGUI_9400CXI L"roms/video/tgui9440/9400CXI.vbi" -#define ROM_TGUI_9440 L"roms/video/tgui9440/9440.vbi" +#define ROM_TGUI_9400CXI "roms/video/tgui9440/9400CXI.VBI" +#define ROM_TGUI_9440 "roms/video/tgui9440/BIOS.BIN" +#define ROM_TGUI_96xx "roms/video/tgui9660/Union.VBI" #define EXT_CTRL_16BIT 0x01 #define EXT_CTRL_MONO_EXPANSION 0x02 #define EXT_CTRL_MONO_TRANSPARENT 0x04 #define EXT_CTRL_LATCH_COPY 0x08 -#define FIFO_SIZE 65536 -#define FIFO_MASK (FIFO_SIZE - 1) -#define FIFO_ENTRY_SIZE (1 << 31) - -#define FIFO_ENTRIES (tgui->fifo_write_idx - tgui->fifo_read_idx) -#define FIFO_FULL ((tgui->fifo_write_idx - tgui->fifo_read_idx) >= FIFO_SIZE) -#define FIFO_EMPTY (tgui->fifo_read_idx == tgui->fifo_write_idx) - -#define FIFO_TYPE 0xff000000 -#define FIFO_ADDR 0x00ffffff - enum { TGUI_9400CXI = 0, - TGUI_9440 + TGUI_9440, + TGUI_9660, + TGUI_9680 }; -enum -{ - FIFO_INVALID = (0x00 << 24), - FIFO_WRITE_BYTE = (0x01 << 24), - FIFO_WRITE_FB_BYTE = (0x04 << 24), - FIFO_WRITE_FB_WORD = (0x05 << 24), - FIFO_WRITE_FB_LONG = (0x06 << 24) -}; - -typedef struct -{ - uint32_t addr_type; - uint32_t val; -} fifo_entry_t; +#define ONBOARD 0x0100 typedef struct tgui_t { mem_mapping_t linear_mapping; mem_mapping_t accel_mapping; + mem_mapping_t mmio_mapping; rom_t bios_rom; - + svga_t svga; int pci; - - int type; + + int type, card; + + uint8_t int_line; + uint8_t pci_regs[256]; struct { - uint16_t src_x, src_y; - uint16_t dst_x, dst_y; - uint16_t size_x, size_y; - uint16_t fg_col, bg_col; + int16_t src_x, src_y; + int16_t src_x_clip, src_y_clip; + int16_t dst_x, dst_y; + int16_t dst_y_clip, dst_x_clip; + int16_t size_x, size_y; + uint16_t sv_size_y; + uint16_t patloc; + uint32_t fg_col, bg_col; + uint32_t style, ckey; uint8_t rop; - uint16_t flags; + uint32_t flags; uint8_t pattern[0x80]; int command; int offset; - uint8_t ger22; - - int x, y; + uint16_t ger22; + + int16_t err, top, left, bottom, right; + int x, y, dx, dy; uint32_t src, dst, src_old, dst_old; int pat_x, pat_y; int use_src; - - int pitch, bpp; - uint16_t tgui_pattern[8][8]; + int pitch, bpp; + uint32_t fill_pattern[8*8]; + uint32_t mono_pattern[8*8]; + uint32_t pattern_8[8*8]; + uint32_t pattern_16[8*8]; + uint32_t pattern_32[8*8]; } accel; - + uint8_t ext_gdc_regs[16]; /*TGUI9400CXi only*/ uint8_t copy_latch[16]; uint8_t tgui_3d8, tgui_3d9; int oldmode; - uint8_t oldctrl1; - uint8_t oldctrl2,newctrl2; + uint8_t oldctrl1, newctrl1; + uint8_t oldctrl2, newctrl2; + uint8_t oldgr0e, newgr0e; + + uint32_t linear_base, linear_size, ge_base, + mmio_base; + uint32_t hwc_fg_col, hwc_bg_col; - uint32_t linear_base, linear_size; - int ramdac_state; uint8_t ramdac_ctrl; - + int clock_m, clock_n, clock_k; - + uint32_t vram_size, vram_mask; - fifo_entry_t fifo[FIFO_SIZE]; - volatile int fifo_read_idx, fifo_write_idx; - - thread_t *fifo_thread; - event_t *wake_fifo_thread; - event_t *fifo_not_full_event; - - int blitter_busy; - uint64_t blitter_time; - uint64_t status_time; - volatile int write_blitter; + void *i2c, *ddc; + + int has_bios; } tgui_t; video_timings_t timing_tgui_vlb = {VIDEO_BUS, 4, 8, 16, 4, 8, 16}; video_timings_t timing_tgui_pci = {VIDEO_PCI, 4, 8, 16, 4, 8, 16}; -void tgui_recalcmapping(tgui_t *tgui); +static void tgui_out(uint16_t addr, uint8_t val, void *p); +static uint8_t tgui_in(uint16_t addr, void *p); -static void fifo_thread(void *param); +static void tgui_recalcmapping(tgui_t *tgui); -uint8_t tgui_accel_read(uint32_t addr, void *priv); -uint16_t tgui_accel_read_w(uint32_t addr, void *priv); -uint32_t tgui_accel_read_l(uint32_t addr, void *priv); +static void tgui_accel_out(uint16_t addr, uint8_t val, void *p); +static void tgui_accel_out_w(uint16_t addr, uint16_t val, void *p); +static void tgui_accel_out_l(uint16_t addr, uint32_t val, void *p); +static uint8_t tgui_accel_in(uint16_t addr, void *p); +static uint16_t tgui_accel_in_w(uint16_t addr, void *p); +static uint32_t tgui_accel_in_l(uint16_t addr, void *p); -void tgui_accel_write(uint32_t addr, uint8_t val, void *priv); -void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv); -void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv); +static uint8_t tgui_accel_read(uint32_t addr, void *priv); +static uint16_t tgui_accel_read_w(uint32_t addr, void *priv); +static uint32_t tgui_accel_read_l(uint32_t addr, void *priv); -void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv); -void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv); -void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv); +static void tgui_accel_write(uint32_t addr, uint8_t val, void *priv); +static void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv); +static void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv); + +static void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv); +static void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv); +static void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv); static uint8_t tgui_ext_linear_read(uint32_t addr, void *p); static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p); @@ -239,11 +205,99 @@ static void tgui_ext_write(uint32_t addr, uint8_t val, void *p); static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p); static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p); -void tgui_out(uint16_t addr, uint8_t val, void *p) + +/*Remap address for chain-4/doubleword style layout*/ +static __inline uint32_t +dword_remap(svga_t *svga, uint32_t in_addr) +{ + if (svga->packed_chain4) + return in_addr; + + return ((in_addr << 2) & 0x3fff0) | + ((in_addr >> 14) & 0xc) | + (in_addr & ~0x3fffc); +} + +static void +tgui_update_irqs(tgui_t *tgui) +{ + if (!tgui->pci) + return; + + if (!(tgui->oldctrl1 & 0x40)) { + pci_set_irq(tgui->card, PCI_INTA); + } else { + pci_clear_irq(tgui->card, PCI_INTA); + } +} + +static void +tgui_remove_io(tgui_t *tgui) +{ + io_removehandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + if (tgui->type >= TGUI_9440) { + io_removehandler(0x43c6, 0x0004, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + io_removehandler(0x83c6, 0x0003, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + io_removehandler(0x2120, 0x0001, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2122, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2124, 0x0001, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2127, 0x0001, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2128, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x212c, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2130, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2134, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2138, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x213a, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x213c, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x213e, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2140, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2142, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2144, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2148, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2168, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2178, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x217c, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_removehandler(0x2180, 0x0080, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + } +} + +static void +tgui_set_io(tgui_t *tgui) +{ + tgui_remove_io(tgui); + + io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + if (tgui->type >= TGUI_9440) { + io_sethandler(0x43c6, 0x0004, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + io_sethandler(0x83c6, 0x0003, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + io_sethandler(0x2120, 0x0001, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2122, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2124, 0x0001, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2127, 0x0001, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2128, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x212c, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2130, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2134, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2138, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x213a, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x213c, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x213e, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2140, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2142, 0x0002, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2144, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2148, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2168, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2178, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x217c, 0x0004, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + io_sethandler(0x2180, 0x0080, tgui_accel_in, tgui_accel_in_w, tgui_accel_in_l, tgui_accel_out, tgui_accel_out_w, tgui_accel_out_l, tgui); + } +} + +static void +tgui_out(uint16_t addr, uint8_t val, void *p) { tgui_t *tgui = (tgui_t *)p; svga_t *svga = &tgui->svga; - uint8_t old; if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; @@ -251,31 +305,32 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3C5: - switch (svga->seqaddr & 0xf) + switch (svga->seqaddr) { - case 0xB: - tgui->oldmode=1; + case 0xB: + tgui->oldmode = 1; break; - case 0xC: - if (svga->seqregs[0xe] & 0x80) - svga->seqregs[0xc] = val; + case 0xC: + if (svga->seqregs[0x0e] & 0x80) + svga->seqregs[0x0c] = val; break; - case 0xd: + case 0xd: if (tgui->oldmode) - tgui->oldctrl2 = val; - else - tgui->newctrl2=val; + tgui->oldctrl2 = val; + else + tgui->newctrl2 = val; break; case 0xE: - if (tgui->oldmode) - tgui->oldctrl1 = val; - else - { + if (tgui->oldmode) { + tgui->oldctrl1 = val; + tgui_update_irqs(tgui); + svga->write_bank = (tgui->oldctrl1) * 65536; + } else { svga->seqregs[0xe] = val ^ 2; - svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; - if (!(svga->gdcreg[0xf] & 1)) - svga->read_bank = svga->write_bank; + svga->write_bank = (svga->seqregs[0xe]) * 65536; } + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = svga->write_bank; return; } break; @@ -290,34 +345,41 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) { tgui->ramdac_state = 0; tgui->ramdac_ctrl = val; - switch (tgui->ramdac_ctrl & 0xf0) + switch ((tgui->ramdac_ctrl >> 4) & 0x0f) { - case 0x10: + case 1: svga->bpp = 15; break; - case 0x30: + case 3: svga->bpp = 16; break; - case 0xd0: - svga->bpp = 24; - break; + case 0x0d: + svga->bpp = (tgui->type >= TGUI_9660) ? 32 : 24; + break; default: svga->bpp = 8; break; } + svga_recalctimings(svga); return; } - /*FALLTHROUGH*/ + break; + case 0x3C7: case 0x3C8: case 0x3C9: if (tgui->type == TGUI_9400CXI) { tkd8001_ramdac_out(addr, val, svga->ramdac, svga); return; } - tgui->ramdac_state = 0; - break; + tgui->ramdac_state = 0; + break; case 0x3CF: + if (svga->gdcaddr == 0x23) + { + svga->dpms = !!(val & 0x03); + svga_recalctimings(svga); + } if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) { old = tgui->ext_gdc_regs[svga->gdcaddr & 15]; @@ -326,30 +388,49 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) tgui_recalcmapping(tgui); return; } - switch (svga->gdcaddr & 15) + switch (svga->gdcaddr) { - case 0x6: - if (svga->gdcreg[6] != val) - { - svga->gdcreg[6] = val; - tgui_recalcmapping(tgui); - } - return; - - case 0xE: + case 0x6: + if (svga->gdcreg[6] != val) + { + svga->gdcreg[6] = val; + tgui_recalcmapping(tgui); + } + return; + + case 0x0e: svga->gdcreg[0xe] = val ^ 2; if ((svga->gdcreg[0xf] & 1) == 1) - svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536; + svga->read_bank = (svga->gdcreg[0xe]) * 65536; break; - case 0xF: - if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536; - else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536; - svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + case 0x0f: + if (val & 1) + svga->read_bank = (svga->gdcreg[0xe]) * 65536; + else { + if (tgui->oldmode) + svga->read_bank = (tgui->oldctrl1) * 65536; + else + svga->read_bank = (svga->seqregs[0xe]) * 65536; + } + + if (tgui->oldmode) + svga->write_bank = (tgui->oldctrl1) * 65536; + else + svga->write_bank = (svga->seqregs[0xe]) * 65536; break; + + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + svga->gdcreg[svga->gdcaddr] = val; + break; } break; case 0x3D4: - svga->crtcreg = val & 0x7f; + svga->crtcreg = val; return; case 0x3D5: if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) @@ -358,66 +439,92 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) val = (svga->crtc[7] & ~0x10) | (val & 0x10); old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; + if (old != val) { - if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } - switch (svga->crtcreg) - { - case 0x21: - if (old != val) - { - if (!tgui->pci) - { - tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; - tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; - tgui->svga.decode_mask = (val & 0x10) ? 0x1fffff : 0xfffff; - } - tgui_recalcmapping(tgui); - } - break; + switch (svga->crtcreg) { + case 0x1e: + svga->vram_display_mask = (val & 0x80) ? tgui->vram_mask : 0x3ffff; + break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - if (tgui->type >= TGUI_9440) - { - svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff; - svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff; - svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f; - svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f; - svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x7) << 18) | (svga->hwcursor.yoff * 8); + case 0x21: + if (old != val) { + if (!tgui->pci) { + tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; + tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; + svga->decode_mask = (val & 0x10) ? 0x1fffff : 0xfffff; + } + tgui_recalcmapping(tgui); + } + break; + + case 0x34: + case 0x35: + if (tgui->type >= TGUI_9440) { + tgui->ge_base = ((svga->crtc[0x35] << 0x18) | (svga->crtc[0x34] << 0x10)); + tgui_recalcmapping(tgui); + } + break; + + case 0x36: + case 0x39: + tgui_recalcmapping(tgui); + break; + + case 0x37: + if (tgui->type >= TGUI_9440) + i2c_gpio_set(tgui->i2c, (val & 0x02) || !(val & 0x04), (val & 0x01) || !(val & 0x08)); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + if (tgui->type >= TGUI_9440) { + svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff; + svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff; + if (tgui->type >= TGUI_9660 && (tgui->accel.ger22 & 0xff) == 8) { + svga->hwcursor.x <<= 1; + } + svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f; + svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x0f) << 18) | (svga->hwcursor.yoff * 8); } - break; - - case 0x50: - if (tgui->type >= TGUI_9440) - { - svga->hwcursor.ena = val & 0x80; - svga->hwcursor.xsize = (val & 1) ? 64 : 32; - svga->hwcursor.ysize = (val & 1) ? 64 : 32; - } - break; - } - return; + break; + + case 0x50: + if (tgui->type >= TGUI_9440) { + svga->hwcursor.ena = !!(val & 0x80); + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((val & 1) ? 64 : 32); + } + break; + } + return; + case 0x3D8: tgui->tgui_3d8 = val; - if (svga->gdcreg[0xf] & 4) - { - svga->write_bank = (val & 0x1f) * 65536; - if (!(svga->gdcreg[0xf] & 1)) - svga->read_bank = (val & 0x1f) * 65536; + if (svga->gdcreg[0xf] & 4) { + svga->write_bank = (val & 0x3f) * 65536; + if (!(svga->gdcreg[0xf] & 1)) { + svga->read_bank = (val & 0x3f) * 65536; + } } return; case 0x3D9: tgui->tgui_3d9 = val; if ((svga->gdcreg[0xf] & 5) == 5) - svga->read_bank = (val & 0x1F) * 65536; + svga->read_bank = (val & 0x3f) * 65536; return; - + case 0x43c8: tgui->clock_n = val & 0x7f; tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7); @@ -430,17 +537,23 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) svga_out(addr, val, svga); } -uint8_t tgui_in(uint16_t addr, void *p) +static uint8_t +tgui_in(uint16_t addr, void *p) { tgui_t *tgui = (tgui_t *)p; svga_t *svga = &tgui->svga; + uint8_t temp; if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; - + switch (addr) { case 0x3C5: - if ((svga->seqaddr & 0xf) == 0xb) + if (svga->seqaddr == 9) { + if (tgui->type == TGUI_9680) + return 0x01; /*TGUI9680XGi*/ + } + if (svga->seqaddr == 0x0b) { tgui->oldmode = 0; switch (tgui->type) @@ -449,40 +562,67 @@ uint8_t tgui_in(uint16_t addr, void *p) return 0x93; /*TGUI9400CXi*/ case TGUI_9440: return 0xe3; /*TGUI9440AGi*/ + case TGUI_9660: + case TGUI_9680: + return 0xd3; /*TGUI9660XGi*/ } } - if ((svga->seqaddr & 0xf) == 0xd) + if (svga->seqaddr == 0x0d) { if (tgui->oldmode) return tgui->oldctrl2; return tgui->newctrl2; } - if ((svga->seqaddr & 0xf) == 0xe) + if (svga->seqaddr == 0x0c) + { + if (svga->seqregs[0x0e] & 0x80) + return svga->seqregs[0x0c]; + } + if (svga->seqaddr == 0x0e) { if (tgui->oldmode) - return tgui->oldctrl1; + return tgui->oldctrl1 | 0x88; + return svga->seqregs[0x0e]; } break; + case 0x3C6: if (tgui->type == TGUI_9400CXI) - return tkd8001_ramdac_in(addr, svga->ramdac, svga); + return tkd8001_ramdac_in(addr, svga->ramdac, svga); if (tgui->ramdac_state == 4) - return tgui->ramdac_ctrl; - tgui->ramdac_state++; + return tgui->ramdac_ctrl; + tgui->ramdac_state++; break; + case 0x3C7: case 0x3C8: case 0x3C9: if (tgui->type == TGUI_9400CXI) return tkd8001_ramdac_in(addr, svga->ramdac, svga); tgui->ramdac_state = 0; break; + case 0x3CF: if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) return tgui->ext_gdc_regs[svga->gdcaddr & 15]; - break; + if (svga->gdcaddr >= 0x5a && svga->gdcaddr <= 0x5f) + return svga->gdcreg[svga->gdcaddr]; + break; case 0x3D4: return svga->crtcreg; case 0x3D5: - return svga->crtc[svga->crtcreg]; + temp = svga->crtc[svga->crtcreg]; + if ((svga->crtcreg == 0x37) && (tgui->type >= TGUI_9440)) { + if (!(temp & 0x04)) { + temp &= ~0x02; + if (i2c_gpio_get_scl(tgui->i2c)) + temp |= 0x02; + } + if (!(temp & 0x08)) { + temp &= ~0x01; + if (i2c_gpio_get_sda(tgui->i2c)) + temp |= 0x01; + } + } + return temp; case 0x3d8: return tgui->tgui_3d8; case 0x3d9: @@ -495,35 +635,60 @@ void tgui_recalctimings(svga_t *svga) { tgui_t *tgui = (tgui_t *)svga->p; - if (svga->crtc[0x29] & 0x10) - svga->rowoffset += 0x100; + if (!svga->rowoffset) + svga->rowoffset = 0x100; + + if (svga->crtc[0x29] & 0x10) + svga->rowoffset |= 0x100; + + if (tgui->type >= TGUI_9440 && svga->bpp >= 24) { + if ((tgui->accel.bpp == 0) && (tgui->accel.ger22 & 0xff) != 14 && (svga->bpp == 24)) + svga->hdisp = (svga->crtc[1] + 1) * 8; + if (tgui->accel.bpp == 3 && (tgui->accel.ger22 & 0xff) == 14 && (svga->bpp == 32) && (tgui->type == TGUI_9440)) + svga->rowoffset <<= 1; + } + + + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) + svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) + svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) + svga->ma_latch |= 0x40000; + if ((svga->crtc[0x27] & 0x04) == 0x04) + svga->ma_latch |= 0x80000; + + if (svga->crtc[0x27] & 0x08) + svga->split |= 0x400; + if (svga->crtc[0x27] & 0x10) + svga->dispend |= 0x400; + if (svga->crtc[0x27] & 0x20) + svga->vsyncstart |= 0x400; + if (svga->crtc[0x27] & 0x40) + svga->vblankstart |= 0x400; + if (svga->crtc[0x27] & 0x80) + svga->vtotal |= 0x400; + + if (tgui->oldctrl2 & 0x10) { + svga->rowoffset <<= 1; + svga->lowres = 0; + } - if (tgui->type >= TGUI_9440 && svga->bpp == 24) - svga->hdisp = (svga->crtc[1] + 1) * 8; - - if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; - if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; - if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; - - if (tgui->oldctrl2 & 0x10) - svga->rowoffset <<= 1; if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) - svga->ma_latch <<= 1; + svga->ma_latch <<= 1; - if (tgui->oldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/ - svga->lowres=0; + svga->lowres = !(svga->crtc[0x2a] & 0x40); - svga->lowres = !(svga->crtc[0x2a] & 0x40); - - svga->interlace = svga->crtc[0x1e] & 4; + svga->interlace = !!(svga->crtc[0x1e] & 4); if (svga->interlace && tgui->type < TGUI_9440) svga->rowoffset >>= 1; - + if (tgui->type >= TGUI_9440) { if (svga->miscout & 8) - svga->clock = (cpuclock * (double)(1ull << 32)) / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); - + svga->clock = (cpuclock * (double)(1ull << 32)) / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + if (svga->gdcreg[0xf] & 0x08) svga->clock *= 2; else if (svga->gdcreg[0xf] & 0x40) @@ -550,39 +715,54 @@ void tgui_recalctimings(svga_t *svga) } if (svga->gdcreg[0xf] & 0x08) { - svga->htotal *= 2; - svga->hdisp *= 2; - svga->hdisp_time *= 2; + svga->htotal <<= 1; + svga->hdisp <<= 1; + svga->hdisp_time <<= 1; } } - + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) { switch (svga->bpp) { - case 8: - svga->render = svga_render_8bpp_highres; + case 8: + svga->render = svga_render_8bpp_highres; + if (tgui->type >= TGUI_9660) { + if (svga->dispend == 512) + svga->hdisp = 1280; + else if (svga->dispend == 600 && svga->hdisp == 800 && svga->vtotal == 651) + svga->hdisp = 1600; + } break; - case 15: + case 15: svga->render = svga_render_15bpp_highres; if (tgui->type < TGUI_9440) - svga->hdisp /= 2; + svga->hdisp >>= 1; break; - case 16: - svga->render = svga_render_16bpp_highres; + case 16: + svga->render = svga_render_16bpp_highres; if (tgui->type < TGUI_9440) - svga->hdisp /= 2; + svga->hdisp >>= 1; break; - case 24: + case 24: svga->render = svga_render_24bpp_highres; if (tgui->type < TGUI_9440) - svga->hdisp = (svga->hdisp * 2) / 3; + svga->hdisp = (svga->hdisp << 1) / 3; break; + case 32: + svga->render = svga_render_32bpp_highres; + if (tgui->type >= TGUI_9660) { + if (svga->hdisp == 1024) { + svga->rowoffset <<= 1; + } + } + break; } } } -void tgui_recalcmapping(tgui_t *tgui) +static void +tgui_recalcmapping(tgui_t *tgui) { svga_t *svga = &tgui->svga; @@ -617,13 +797,27 @@ void tgui_recalcmapping(tgui_t *tgui) } } + if (tgui->pci && !(tgui->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&tgui->linear_mapping); + mem_mapping_disable(&tgui->accel_mapping); + mem_mapping_disable(&tgui->mmio_mapping); + return; + } + if (svga->crtc[0x21] & 0x20) { mem_mapping_disable(&svga->mapping); - mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); + mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); if (tgui->type >= TGUI_9440) { - mem_mapping_enable(&tgui->accel_mapping); + if ((svga->crtc[0x36] & 0x03) == 0x01) + mem_mapping_set_addr(&tgui->accel_mapping, 0xb4000, 0x4000); + else if ((svga->crtc[0x36] & 0x03) == 0x02) + mem_mapping_set_addr(&tgui->accel_mapping, 0xbc000, 0x4000); + else if ((svga->crtc[0x36] & 0x03) == 0x03) + mem_mapping_set_addr(&tgui->accel_mapping, tgui->ge_base, 0x4000); mem_mapping_disable(&svga->mapping); } else @@ -661,7 +855,12 @@ void tgui_recalcmapping(tgui_t *tgui) break; case 0x4: /*64k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - mem_mapping_enable(&tgui->accel_mapping); + if ((svga->crtc[0x36] & 0x03) == 0x01) + mem_mapping_set_addr(&tgui->accel_mapping, 0xb4000, 0x4000); + else if ((svga->crtc[0x36] & 0x03) == 0x02) + mem_mapping_set_addr(&tgui->accel_mapping, 0xbc000, 0x4000); + else if ((svga->crtc[0x36] & 0x03) == 0x03) + mem_mapping_set_addr(&tgui->accel_mapping, tgui->ge_base, 0x4000); svga->banked_mask = 0xffff; break; case 0x8: /*32k at B0000*/ @@ -673,38 +872,53 @@ void tgui_recalcmapping(tgui_t *tgui) svga->banked_mask = 0x7fff; break; } - } + } + + if (tgui->type >= TGUI_9440) { + if ((tgui->mmio_base != 0x00000000) && (svga->crtc[0x39] & 1)) + mem_mapping_set_addr(&tgui->mmio_mapping, tgui->mmio_base, 0x10000); + else + mem_mapping_disable(&tgui->mmio_mapping); + } } -void tgui_hwcursor_draw(svga_t *svga, int displine) +static void +tgui_hwcursor_draw(svga_t *svga, int displine) { - uint32_t dat[2]; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - - if (svga->interlace && svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 8; + uint32_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x + svga->hwcursor_latch.xoff; + int pitch = (svga->hwcursor_latch.cur_xsize == 64) ? 16 : 8; - dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; - dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7]; - for (xx = 0; xx < 32; xx++) - { - if (offset >= svga->hwcursor_latch.x) - { - if (!(dat[0] & 0x80000000)) - buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; - else if (dat[1] & 0x80000000) - buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; - } - - offset++; - dat[0] <<= 1; - dat[1] <<= 1; - } - svga->hwcursor_latch.addr += 8; - - if (svga->interlace && !svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 8; + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7]; + for (xx = 0; xx < 32; xx++) { + if (svga->crtc[0x50] & 0x40) { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[0] & 0x80000000) + ((uint32_t *)buffer32->line[displine])[svga->x_add + offset] = (dat[1] & 0x80000000) ? 0xffffff : 0; + } + } else { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine])[svga->x_add + offset] = (dat[1] & 0x80000000) ? 0xffffff : 0; + else if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine])[svga->x_add + offset] ^= 0xffffff; + } + } + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += pitch; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; } uint8_t tgui_pci_read(int func, int addr, void *p) @@ -715,29 +929,37 @@ uint8_t tgui_pci_read(int func, int addr, void *p) { case 0x00: return 0x23; /*Trident*/ case 0x01: return 0x10; - - case 0x02: return 0x40; /*TGUI9440 (9682)*/ - case 0x03: return 0x94; - - case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x02: return (tgui->type == TGUI_9440) ? 0x40 : 0x60; /*TGUI9440AGi or TGUI9660XGi*/ + case 0x03: return (tgui->type == TGUI_9440) ? 0x94 : 0x96; + + case PCI_REG_COMMAND: return tgui->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ - + case 0x08: return 0; /*Revision ID*/ case 0x09: return 0; /*Programming interface*/ - + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ case 0x0b: return 0x03; - + case 0x10: return 0x00; /*Linear frame buffer address*/ case 0x11: return 0x00; case 0x12: return tgui->linear_base >> 16; case 0x13: return tgui->linear_base >> 24; - case 0x30: return 0x01; /*BIOS ROM address*/ - case 0x31: return 0x00; - case 0x32: return 0x0C; - case 0x33: return 0x00; + case 0x14: return 0x00; /*MMIO address*/ + case 0x15: return 0x00; + case 0x16: return tgui->mmio_base >> 16; + case 0x17: return tgui->mmio_base >> 24; + + case 0x30: return tgui->has_bios ? (tgui->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return tgui->has_bios ? tgui->pci_regs[0x32] : 0x00; + case 0x33: return tgui->has_bios ? tgui->pci_regs[0x33] : 0x00; + + case 0x3c: return tgui->int_line; + case 0x3d: return PCI_INTA; } return 0; } @@ -749,20 +971,67 @@ void tgui_pci_write(int func, int addr, uint8_t val, void *p) switch (addr) { + case PCI_REG_COMMAND: + tgui->pci_regs[PCI_REG_COMMAND] = (val & 0x23); + if (val & PCI_COMMAND_IO) { + tgui_set_io(tgui); + } else + tgui_remove_io(tgui); + tgui_recalcmapping(tgui); + break; + case 0x12: - tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); - tgui->linear_size = 2 << 20; - tgui->svga.decode_mask = 0x1fffff; - svga->crtc[0x21] = (svga->crtc[0x21] & ~0xf) | (val >> 4); + if (tgui->type >= TGUI_9660) + tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xc0) << 16); + else + tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); + tgui->linear_size = tgui->vram_size; + svga->decode_mask = tgui->vram_mask; tgui_recalcmapping(tgui); break; case 0x13: - tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24); - tgui->linear_size = 2 << 20; - tgui->svga.decode_mask = 0x1fffff; - svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6); + if (tgui->type >= TGUI_9660) + tgui->linear_base = (tgui->linear_base & 0xc00000) | (val << 24); + else + tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24); + tgui->linear_size = tgui->vram_size; + svga->decode_mask = tgui->vram_mask; tgui_recalcmapping(tgui); break; + + case 0x16: + if (tgui->type >= TGUI_9660) + tgui->mmio_base = (tgui->mmio_base & 0xff000000) | ((val & 0xc0) << 16); + else + tgui->mmio_base = (tgui->mmio_base & 0xff000000) | ((val & 0xe0) << 16); + tgui_recalcmapping(tgui); + break; + case 0x17: + if (tgui->type >= TGUI_9660) + tgui->mmio_base = (tgui->mmio_base & 0x00c00000) | (val << 24); + else + tgui->mmio_base = (tgui->mmio_base & 0x00e00000) | (val << 24); + tgui_recalcmapping(tgui); + break; + + case 0x30: case 0x32: case 0x33: + if (tgui->has_bios) { + tgui->pci_regs[addr] = val; + if (tgui->pci_regs[0x30] & 0x01) + { + uint32_t biosaddr = (tgui->pci_regs[0x32] << 16) | (tgui->pci_regs[0x33] << 24); + mem_mapping_set_addr(&tgui->bios_rom.mapping, biosaddr, 0x8000); + } + else + { + mem_mapping_disable(&tgui->bios_rom.mapping); + } + } + return; + + case 0x3c: + tgui->int_line = val; + return; } } @@ -772,25 +1041,29 @@ static uint8_t tgui_ext_linear_read(uint32_t addr, void *p) tgui_t *tgui = (tgui_t *)svga->p; int c; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) return 0xff; - - addr &= ~0xf; - for (c = 0; c < 16; c++) - tgui->copy_latch[c] = svga->vram[addr+c]; - return svga->vram[addr & svga->vram_mask]; + addr &= ~0xf; + addr = dword_remap(svga, addr); + + for (c = 0; c < 16; c++) { + tgui->copy_latch[c] = svga->vram[addr+c]; + addr += ((c & 3) == 3) ? 13 : 1; + } + + return svga->vram[addr & svga->vram_mask]; } static uint8_t tgui_ext_read(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - + addr = (addr & svga->banked_mask) + svga->read_bank; - + return tgui_ext_linear_read(addr, svga); } @@ -803,15 +1076,17 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; uint8_t mask = tgui->ext_gdc_regs[7]; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) return; addr &= svga->vram_mask; - addr &= ~0x7; + addr &= (tgui->ext_gdc_regs[0] & 8) ? ~0xf : ~0x7; + + addr = dword_remap(svga, addr); svga->changedvram[addr >> 12] = changeframecount; - + switch (tgui->ext_gdc_regs[0] & 0xf) { /*8-bit mono->colour expansion, unmasked*/ @@ -820,7 +1095,7 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) { if (mask & (1 << c)) *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; - addr++; + addr += (c == 4) ? 13 : 1; } break; @@ -830,7 +1105,7 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) { if (mask & (1 << c)) *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; - addr++; + addr += (c == 4) ? 13 : 1; } break; @@ -840,25 +1115,26 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) { if ((val & mask) & (1 << c)) *(uint8_t *)&svga->vram[addr] = fg[0]; - addr++; + addr += (c == 4) ? 13 : 1; } break; - + /*16-bit mono->colour expansion, masked*/ case 7: for (c = 7; c >= 0; c--) { if ((val & mask) & (1 << c)) *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; - addr++; + addr += (c == 4) ? 13 : 1; } break; case 0x8: case 0x9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: - addr &= ~0xf; - for (c = 0; c < 16; c++) - *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c]; + for (c = 0; c < 16; c++) { + *(uint8_t *)&svga->vram[addr] = tgui->copy_latch[c]; + addr += ((c & 3) == 3) ? 13 : 1; + } break; } } @@ -871,16 +1147,18 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8]; - - sub_cycles(video_timing_write_w); + + cycles -= video_timing_write_w; addr &= svga->decode_mask; if (addr >= svga->vram_max) return; addr &= svga->vram_mask; addr &= ~0xf; + + addr = dword_remap(svga, addr); svga->changedvram[addr >> 12] = changeframecount; - + val = (val >> 8) | (val << 8); switch (tgui->ext_gdc_regs[0] & 0xf) @@ -891,7 +1169,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) { if (mask & (1 << c)) *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; - addr++; + addr += (c & 3) ? 1 : 13; } break; @@ -901,7 +1179,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) { if (mask & (1 << c)) *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; - addr++; + addr += (c & 3) ? 1 : 13; } break; @@ -911,7 +1189,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) { if ((val & mask) & (1 << c)) *(uint8_t *)&svga->vram[addr] = fg[0]; - addr++; + addr += (c & 3) ? 1 : 13; } break; @@ -921,14 +1199,16 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) { if ((val & mask) & (1 << c)) *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; - addr++; + addr += (c & 3) ? 1 : 13; } break; - + case 0x8: case 0x9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: - for (c = 0; c < 16; c++) + for (c = 0; c < 16; c++) { *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c]; + addr += ((c & 3) == 3) ? 13 : 1; + } break; } } @@ -938,10 +1218,11 @@ static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p) tgui_ext_linear_writew(addr, val, p); } + static void tgui_ext_write(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; - + addr = (addr & svga->banked_mask) + svga->read_bank; tgui_ext_linear_write(addr, val, svga); @@ -949,7 +1230,7 @@ static void tgui_ext_write(uint32_t addr, uint8_t val, void *p) static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; - + addr = (addr & svga->banked_mask) + svga->read_bank; tgui_ext_linear_writew(addr, val, svga); @@ -957,7 +1238,7 @@ static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p) static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; - + addr = (addr & svga->banked_mask) + svga->read_bank; tgui_ext_linear_writel(addr, val, svga); @@ -966,334 +1247,1302 @@ static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p) enum { - TGUI_BITBLT = 1 + TGUI_BITBLT = 1, + TGUI_SCANLINE = 3, + TGUI_BRESENHAMLINE = 4, + TGUI_SHORTVECTOR = 5, + TGUI_FASTLINE = 6 }; enum { - TGUI_SRCCPU = 0, - + TGUI_SRCCPU = 0, + TGUI_SRCPAT = 0x02, /*Source is from pattern*/ TGUI_SRCDISP = 0x04, /*Source is from display*/ TGUI_PATMONO = 0x20, /*Pattern is monochrome and needs expansion*/ TGUI_SRCMONO = 0x40, /*Source is monochrome from CPU and needs expansion*/ TGUI_TRANSENA = 0x1000, /*Transparent (no draw when source == bg col)*/ TGUI_TRANSREV = 0x2000, /*Reverse fg/bg for transparent*/ - TGUI_SOLIDFILL = 0x4000 /*Pattern all zero?*/ + TGUI_SOLIDFILL = 0x4000, /*Pattern set to foreground color*/ + TGUI_STENCIL = 0x8000 /*Stencil*/ }; -#define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[addr & 0x1fffff]; \ - else dat = vram_w[addr & 0xfffff]; - +#define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[(addr) & tgui->vram_mask]; \ + else if (tgui->accel.bpp == 1) dat = vram_w[(addr) & (tgui->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (tgui->vram_mask >> 2)]; \ + #define MIX() do \ { \ - out = 0; \ - for (c=0;c<16;c++) \ + out = 0; \ + for (c=0;c<32;c++) \ { \ - d=(dst_dat & (1<accel.rop & (1<accel.rop & (1<accel.bpp == 0) \ { \ - svga->vram[addr & 0x1fffff] = dat; \ - svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \ + svga->vram[(addr) & tgui->vram_mask] = dat; \ + svga->changedvram[((addr) & (tgui->vram_mask)) >> 12] = changeframecount; \ } \ - else \ + else if (tgui->accel.bpp == 1) \ { \ - vram_w[addr & 0xfffff] = dat; \ - svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \ + vram_w[(addr) & (tgui->vram_mask >> 1)] = dat; \ + svga->changedvram[((addr) & (tgui->vram_mask >> 1)) >> 11] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & (tgui->vram_mask >> 2)] = dat; \ + svga->changedvram[((addr) & (tgui->vram_mask >> 2)) >> 10] = changeframecount; \ } - -void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) + +static void +tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { - svga_t *svga = &tgui->svga; + svga_t *svga = &tgui->svga; + uint32_t *pattern_data; int x, y; int c, d; - uint16_t src_dat, dst_dat, pat_dat; - uint16_t out; + uint32_t out; + uint32_t src_dat = 0, dst_dat, pat_dat; int xdir = (tgui->accel.flags & 0x200) ? -1 : 1; int ydir = (tgui->accel.flags & 0x100) ? -1 : 1; - uint16_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col; - uint16_t *vram_w = (uint16_t *)svga->vram; - - if (tgui->accel.bpp == 0) - trans_col &= 0xff; - + uint32_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + + if (tgui->accel.bpp == 0) { + trans_col &= 0xff; + } else if (tgui->accel.bpp == 1) { + trans_col &= 0xffff; + } + if (count != -1 && !tgui->accel.x && (tgui->accel.flags & TGUI_SRCMONO)) { - count -= tgui->accel.offset; - cpu_dat <<= tgui->accel.offset; + count -= (tgui->accel.flags >> 24) & 7; + cpu_dat <<= (tgui->accel.flags >> 24) & 7; } + if (count == -1) - { tgui->accel.x = tgui->accel.y = 0; - } - if (tgui->accel.flags & TGUI_SOLIDFILL) - { + + if (tgui->accel.flags & TGUI_SOLIDFILL) { for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { - tgui->accel.tgui_pattern[y][x] = tgui->accel.fg_col; + tgui->accel.fill_pattern[(y*8) + (7 - x)] = tgui->accel.fg_col; } } - } - else if (tgui->accel.flags & TGUI_PATMONO) - { + pattern_data = tgui->accel.fill_pattern; + } else if (tgui->accel.flags & TGUI_PATMONO) { for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { - tgui->accel.tgui_pattern[y][x] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col; + tgui->accel.mono_pattern[(y*8) + (7 - x)] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col; } } - } - else - { - if (tgui->accel.bpp == 0) - { - for (y = 0; y < 8; y++) - { - for (x = 0; x < 8; x++) - { - tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x + y*8]; - } - } - } - else - { - for (y = 0; y < 8; y++) - { - for (x = 0; x < 8; x++) - { - tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8); - } - } + pattern_data = tgui->accel.mono_pattern; + } else { + if (tgui->accel.bpp == 0) { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.pattern_8[(y*8) + (7 - x)] = tgui->accel.pattern[x + y*8]; + } + } + pattern_data = tgui->accel.pattern_8; + } else if (tgui->accel.bpp == 1) { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.pattern_16[(y*8) + (7 - x)] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8); + } + } + pattern_data = tgui->accel.pattern_16; + } else { + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.pattern_32[(y*8) + (7 - x)] = tgui->accel.pattern[x*4 + y*32] | (tgui->accel.pattern[x*4 + y*32 + 1] << 8) | (tgui->accel.pattern[x*4 + y*32 + 2] << 16) | (tgui->accel.pattern[x*4 + y*32 + 3] << 24); + tgui->accel.pattern_32[((y+4)*8) + (7 - x)] = tgui->accel.pattern[x*4 + y*32] | (tgui->accel.pattern[x*4 + y*32 + 1] << 8) | (tgui->accel.pattern[x*4 + y*32 + 2] << 16) | (tgui->accel.pattern[x*4 + y*32 + 3] << 24); + } + } + pattern_data = tgui->accel.pattern_32; } } - switch (tgui->accel.command) + + /*Other than mode stuff, this bit is undocumented*/ + switch (tgui->accel.ger22 & 0xff) { + case 0: + switch (tgui->accel.ger22 >> 8) { + case 0x41: + tgui->accel.pitch = 640; + break; + } + break; + + case 4: + switch (tgui->accel.ger22 >> 8) { + case 0: + tgui->accel.pitch = 1024; + break; + case 0x40: + tgui->accel.pitch = 640; + break; + case 0x50: + tgui->accel.pitch = 832; + break; + } + break; + case 8: + switch (tgui->accel.ger22 >> 8) { + case 0: + tgui->accel.pitch = 2048; + break; + case 0x60: + tgui->accel.pitch = 1280; + break; + } + break; + case 9: + switch (tgui->accel.ger22 >> 8) { + case 0: + tgui->accel.pitch = svga->hdisp; + if (tgui->type == TGUI_9440) + tgui->accel.pitch = 1024; + break; + case 0x40: + tgui->accel.pitch = 640; + break; + case 0x50: + tgui->accel.pitch = 832; + break; + } + break; + case 13: + switch (tgui->accel.ger22 >> 8) { + case 0x60: + tgui->accel.pitch = 2048; + if (tgui->type >= TGUI_9660) { + if (svga->hdisp == 1280) + tgui->accel.pitch = svga->hdisp; + } + break; + } + break; + case 14: + switch (tgui->accel.ger22 >> 8) { + case 0: + tgui->accel.pitch = 1024; + break; + case 0x40: + tgui->accel.pitch = 640; + break; + case 0x50: + tgui->accel.pitch = 832; + break; + } + break; + } + + switch (tgui->accel.command) { case TGUI_BITBLT: - if (count == -1) - { - tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); - tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + if (count == -1) { + tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); + tgui->accel.src = tgui->accel.src_old; + + tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old; + tgui->accel.pat_x = tgui->accel.dst_x; tgui->accel.pat_y = tgui->accel.dst_y; + + tgui->accel.dx = tgui->accel.dst_x & 0xfff; + tgui->accel.dy = tgui->accel.dst_y & 0xfff; + + tgui->accel.left = tgui->accel.src_x_clip & 0xfff; + tgui->accel.right = tgui->accel.dst_x_clip & 0xfff; + tgui->accel.top = tgui->accel.src_y_clip & 0xfff; + tgui->accel.bottom = tgui->accel.dst_y_clip & 0xfff; + + if (tgui->accel.bpp == 1) { + tgui->accel.left >>= 1; + tgui->accel.right >>= 1; + } else if (tgui->accel.bpp == 3) { + tgui->accel.left >>= 2; + tgui->accel.right >>= 2; + } } switch (tgui->accel.flags & (TGUI_SRCMONO|TGUI_SRCDISP)) { case TGUI_SRCCPU: - if (count == -1) - { + if (count == -1) { if (svga->crtc[0x21] & 0x20) - { - tgui->write_blitter = 1; - } + tgui->write_blitter = 1; if (tgui->accel.use_src) - return; - } - else - count >>= 3; - while (count) - { - if (tgui->accel.bpp == 0) - { - src_dat = cpu_dat >> 24; - cpu_dat <<= 8; - } - else - { - src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00); - cpu_dat <<= 16; - count--; - } - READ(tgui->accel.dst, dst_dat); - pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; - - if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) - { - MIX(); - - WRITE(tgui->accel.dst, out); - } + return; + } else + count >>= 3; + + while (count) { + if ((tgui->type == TGUI_9440) || ((tgui->type >= TGUI_9660) && tgui->accel.dx >= tgui->accel.left && tgui->accel.dx <= tgui->accel.right && + tgui->accel.dy >= tgui->accel.top && tgui->accel.dy <= tgui->accel.bottom)) { + if (tgui->accel.bpp == 0) { + src_dat = cpu_dat >> 24; + cpu_dat <<= 8; + } else if (tgui->accel.bpp == 1) { + src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00); + cpu_dat <<= 16; + count--; + } else { + src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0x0000ff00) | ((cpu_dat << 8) & 0x00ff0000); + cpu_dat <<= 16; + count -= 3; + } + + READ(tgui->accel.dst, dst_dat); + + pat_dat = pattern_data[((tgui->accel.pat_y & 7)*8) + (tgui->accel.pat_x & 7)]; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + if ((((tgui->accel.flags & (TGUI_PATMONO|TGUI_TRANSENA)) == (TGUI_TRANSENA|TGUI_PATMONO)) && (pat_dat != trans_col)) || !(tgui->accel.flags & TGUI_PATMONO) || + ((tgui->accel.flags & (TGUI_PATMONO|TGUI_TRANSENA)) == TGUI_PATMONO) || (tgui->accel.ger22 & 0x200)) { + MIX(); + + WRITE(tgui->accel.dst, out); + } + } tgui->accel.src += xdir; tgui->accel.dst += xdir; tgui->accel.pat_x += xdir; - + if (tgui->type >= TGUI_9660) + tgui->accel.dx += xdir; + tgui->accel.x++; - if (tgui->accel.x > tgui->accel.size_x) - { + if (tgui->accel.x > tgui->accel.size_x) { tgui->accel.x = 0; - tgui->accel.y++; - + tgui->accel.pat_x = tgui->accel.dst_x; - - tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); - tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); tgui->accel.pat_y += ydir; - - if (tgui->accel.y > tgui->accel.size_y) - { + + if (tgui->type >= TGUI_9660) { + tgui->accel.dx = tgui->accel.dst_x & 0xfff; + tgui->accel.dy += ydir; + } + + tgui->accel.src_old += (ydir * tgui->accel.pitch); + tgui->accel.dst_old += (ydir * tgui->accel.pitch); + + tgui->accel.src = tgui->accel.src_old; + tgui->accel.dst = tgui->accel.dst_old; + + tgui->accel.y++; + + if (tgui->accel.y > tgui->accel.size_y) { if (svga->crtc[0x21] & 0x20) - { - tgui->write_blitter = 0; - } + tgui->write_blitter = 0; return; } if (tgui->accel.use_src) - return; + return; } count--; } break; - + case TGUI_SRCMONO | TGUI_SRCCPU: - if (count == -1) - { + if (count == -1) { if (svga->crtc[0x21] & 0x20) - tgui->write_blitter = 1; - + tgui->write_blitter = 1; if (tgui->accel.use_src) - return; + return; } - while (count) - { - src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); - if (tgui->accel.bpp == 0) - src_dat &= 0xff; - - READ(tgui->accel.dst, dst_dat); - pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; - if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) - { - MIX(); + while (count--) { + if ((tgui->type == TGUI_9440) || ((tgui->type >= TGUI_9660) && tgui->accel.dx >= tgui->accel.left && tgui->accel.dx <= tgui->accel.right && + tgui->accel.dy >= tgui->accel.top && tgui->accel.dy <= tgui->accel.bottom)) { + src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); + if (tgui->accel.bpp == 0) + src_dat &= 0xff; + else if (tgui->accel.bpp == 1) + src_dat &= 0xffff; + + READ(tgui->accel.dst, dst_dat); + + pat_dat = pattern_data[((tgui->accel.pat_y & 7)*8) + (tgui->accel.pat_x & 7)]; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || (src_dat != trans_col)) { + MIX(); + + WRITE(tgui->accel.dst, out); + } + } - WRITE(tgui->accel.dst, out); - } cpu_dat <<= 1; tgui->accel.src += xdir; tgui->accel.dst += xdir; tgui->accel.pat_x += xdir; - + if (tgui->type >= TGUI_9660) + tgui->accel.dx += xdir; + tgui->accel.x++; - if (tgui->accel.x > tgui->accel.size_x) - { + if (tgui->accel.x > tgui->accel.size_x) { tgui->accel.x = 0; - tgui->accel.y++; - + tgui->accel.pat_x = tgui->accel.dst_x; - + tgui->accel.pat_y += ydir; + + if (tgui->type >= TGUI_9660) { + tgui->accel.dx = tgui->accel.dst_x & 0xfff; + tgui->accel.dy += ydir; + } + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); - tgui->accel.pat_y += ydir; - - if (tgui->accel.y > tgui->accel.size_y) - { + + tgui->accel.y++; + + if (tgui->accel.y > tgui->accel.size_y) { if (svga->crtc[0x21] & 0x20) - { - tgui->write_blitter = 0; - } + tgui->write_blitter = 0; return; } if (tgui->accel.use_src) - return; + return; } - count--; } break; default: - while (count) - { + while (count--) { READ(tgui->accel.src, src_dat); - READ(tgui->accel.dst, dst_dat); - pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; - - if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) - { - MIX(); - - WRITE(tgui->accel.dst, out); - } + READ(tgui->accel.dst, dst_dat); + + pat_dat = pattern_data[((tgui->accel.pat_y & 7)*8) + (tgui->accel.pat_x & 7)]; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || (src_dat != trans_col)) { + MIX(); + + WRITE(tgui->accel.dst, out); + } tgui->accel.src += xdir; tgui->accel.dst += xdir; tgui->accel.pat_x += xdir; - + tgui->accel.x++; if (tgui->accel.x > tgui->accel.size_x) { tgui->accel.x = 0; tgui->accel.y++; - + tgui->accel.pat_x = tgui->accel.dst_x; - + tgui->accel.pat_y += ydir; + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); - tgui->accel.pat_y += ydir; - + if (tgui->accel.y > tgui->accel.size_y) return; } - count--; } break; } break; + + case TGUI_SCANLINE: + { + if (count == -1) { + tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); + tgui->accel.src = tgui->accel.src_old; + + tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old; + + tgui->accel.pat_x = tgui->accel.dst_x; + tgui->accel.pat_y = tgui->accel.dst_y; + } + + while (count--) { + READ(tgui->accel.src, src_dat); + READ(tgui->accel.dst, dst_dat); + + pat_dat = pattern_data[((tgui->accel.pat_y & 7)*8) + (tgui->accel.pat_x & 7)]; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || (src_dat != trans_col)) { + MIX(); + + WRITE(tgui->accel.dst, out); + } + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + + tgui->accel.pat_x = tgui->accel.dst_x; + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + return; + } + } + } + break; + + case TGUI_BRESENHAMLINE: + { + int steep = 1; + int16_t dminor, dmajor, destxtmp, tmpswap; + int16_t cx, cy, dx, dy, err; + +#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap; + + dminor = tgui->accel.src_y; + if (tgui->accel.src_y & 0x1000) + dminor |= ~0xfff; + dminor >>= 1; + + destxtmp = tgui->accel.src_x; + if (tgui->accel.src_x & 0x1000) + destxtmp |= ~0xfff; + + dmajor = -(destxtmp - (dminor << 1)) >> 1; + + cx = dmajor; + cy = dminor; + + dx = tgui->accel.dst_x & 0xfff; + dy = tgui->accel.dst_y & 0xfff; + + tgui->accel.left = tgui->accel.src_x_clip & 0xfff; + tgui->accel.right = tgui->accel.dst_x_clip & 0xfff; + tgui->accel.top = tgui->accel.src_y_clip & 0xfff; + tgui->accel.bottom = tgui->accel.dst_y_clip & 0xfff; + + if (tgui->accel.bpp == 1) { + tgui->accel.left >>= 1; + tgui->accel.right >>= 1; + } else if (tgui->accel.bpp == 3) { + tgui->accel.left >>= 2; + tgui->accel.right >>= 2; + } + + err = tgui->accel.size_x + tgui->accel.src_y; + if ((tgui->accel.size_x + tgui->accel.src_y) & 0x1000) + err |= ~0xfff; + + if (tgui->accel.flags & 0x400) { + steep = 0; + SWAP(dx, dy); + SWAP(xdir, ydir); + } + + while (count--) { + READ(tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch), src_dat); + + /*Note by TC1995: I suppose the x/y clipping max is always more than 0 in the TGUI 96xx, but the TGUI 9440 lacks clipping*/ + if (steep) { + if ((tgui->type == TGUI_9440) || ((tgui->type >= TGUI_9660) && dx >= tgui->accel.left && dx <= tgui->accel.right && + dy >= tgui->accel.top && dy <= tgui->accel.bottom)) { + READ(dx + (dy * tgui->accel.pitch), dst_dat); + + pat_dat = tgui->accel.fg_col; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + MIX(); + + WRITE(dx + (dy * tgui->accel.pitch), out); + } + } else { + if ((tgui->type == TGUI_9440) || ((tgui->type >= TGUI_9660) && dy >= tgui->accel.left && dy <= tgui->accel.right && + dx >= tgui->accel.top && dx <= tgui->accel.bottom)) { + READ(dy + (dx * tgui->accel.pitch), dst_dat); + + pat_dat = tgui->accel.fg_col; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + MIX(); + + WRITE(dy + (dx * tgui->accel.pitch), out); + } + } + + if (tgui->accel.y == tgui->accel.size_y) + break; + + while (err > 0) { + dy += ydir; + err -= (cx << 1); + } + dx += xdir; + err += (cy << 1); + + tgui->accel.y++; + } + } + break; + + case TGUI_SHORTVECTOR: + { + int16_t dx, dy; + + dx = tgui->accel.dst_x & 0xfff; + dy = tgui->accel.dst_y & 0xfff; + + tgui->accel.left = tgui->accel.src_x_clip & 0xfff; + tgui->accel.right = tgui->accel.dst_x_clip & 0xfff; + tgui->accel.top = tgui->accel.src_y_clip & 0xfff; + tgui->accel.bottom = tgui->accel.dst_y_clip & 0xfff; + + if (tgui->accel.bpp == 1) { + tgui->accel.left >>= 1; + tgui->accel.right >>= 1; + } else if (tgui->accel.bpp == 3) { + tgui->accel.left >>= 2; + tgui->accel.right >>= 2; + } + + while (count--) { + READ(tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch), src_dat); + + /*Note by TC1995: I suppose the x/y clipping max is always more than 0 in the TGUI 96xx, but the TGUI 9440 lacks clipping*/ + if ((tgui->type == TGUI_9440) || ((tgui->type >= TGUI_9660) && dx >= tgui->accel.left && dx <= tgui->accel.right && + dy >= tgui->accel.top && dy <= tgui->accel.bottom)) { + READ(dx + (dy * tgui->accel.pitch), dst_dat); + + pat_dat = tgui->accel.fg_col; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + MIX(); + + WRITE(dx + (dy * tgui->accel.pitch), out); + } + + if (tgui->accel.y == (tgui->accel.sv_size_y & 0xfff)) + break; + + switch ((tgui->accel.sv_size_y >> 8) & 0xe0) { + case 0x00: + dx++; + break; + case 0x20: + dx++; + dy--; + break; + case 0x40: + dy--; + break; + case 0x60: + dx--; + dy--; + break; + case 0x80: + dx--; + break; + case 0xa0: + dx--; + dy++; + break; + case 0xc0: + dy++; + break; + case 0xe0: + dx++; + dy++; + break; + } + + tgui->accel.y++; + } + } + break; + + case TGUI_FASTLINE: + { + if (tgui->type < TGUI_9660) + break; + + int16_t dx, dy; + + dx = tgui->accel.dst_x & 0xfff; + dy = tgui->accel.dst_y & 0xfff; + + tgui->accel.left = tgui->accel.src_x_clip & 0xfff; + tgui->accel.right = tgui->accel.dst_x_clip & 0xfff; + tgui->accel.top = tgui->accel.src_y_clip & 0xfff; + tgui->accel.bottom = tgui->accel.dst_y_clip & 0xfff; + + if (tgui->accel.bpp == 1) { + tgui->accel.left >>= 1; + tgui->accel.right >>= 1; + } else if (tgui->accel.bpp == 3) { + tgui->accel.left >>= 2; + tgui->accel.right >>= 2; + } + + while (count--) { + READ(tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch), src_dat); + + /*Note by TC1995: I suppose the x/y clipping max is always more than 0 in the TGUI 96xx, but the TGUI 9440 lacks clipping*/ + if ((tgui->type == TGUI_9440) || ((tgui->type >= TGUI_9660) && dx >= tgui->accel.left && dx <= tgui->accel.right && + dy >= tgui->accel.top && dy <= tgui->accel.bottom)) { + READ(dx + (dy * tgui->accel.pitch), dst_dat); + + pat_dat = tgui->accel.fg_col; + + if (tgui->accel.bpp == 0) + pat_dat &= 0xff; + else if (tgui->accel.bpp == 1) + pat_dat &= 0xffff; + + MIX(); + + WRITE(dx + (dy * tgui->accel.pitch), out); + } + + if (tgui->accel.y == (tgui->accel.size_y & 0xfff)) + break; + + switch ((tgui->accel.size_y >> 8) & 0xe0) { + case 0x00: + dx++; + break; + case 0x20: + dx++; + dy--; + break; + case 0x40: + dy--; + break; + case 0x60: + dx--; + dy--; + break; + case 0x80: + dx--; + break; + case 0xa0: + dx--; + dy++; + break; + case 0xc0: + dy++; + break; + case 0xe0: + dx++; + dy++; + break; + } + + tgui->accel.y++; + } + } + break; } } -static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) +static void +tgui_accel_out(uint16_t addr, uint8_t val, void *p) { + tgui_t *tgui = (tgui_t *)p; + + switch (addr) + { + case 0x2122: + tgui->accel.ger22 = (tgui->accel.ger22 & 0xff00) | val; + switch (val & 0xff) { + case 4: + case 8: + tgui->accel.bpp = 0; + break; + + case 9: + tgui->accel.bpp = 1; + break; + + case 13: + case 14: + switch (tgui->svga.bpp) { + case 15: + case 16: + tgui->accel.bpp = 1; + break; + + case 24: + tgui->accel.bpp = 0; + break; + + case 32: + tgui->accel.bpp = 3; + break; + } + break; + } + break; + + case 0x2123: + tgui->accel.ger22 = (tgui->accel.ger22 & 0xff) | (val << 8); + break; + + case 0x2124: /*Command*/ + tgui->accel.command = val; + tgui_accel_command(-1, 0, tgui); + break; + + case 0x2127: /*ROP*/ + tgui->accel.rop = val; + tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); + break; + + case 0x2128: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xffffff00) | val; + break; + case 0x2129: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xffff00ff) | (val << 8); + break; + case 0x212a: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff00ffff) | (val << 16); + break; + case 0x212b: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0x0000ffff) | (val << 24); + break; + + case 0x212c: /*Foreground colour*/ + case 0x2178: + tgui->accel.fg_col = (tgui->accel.fg_col & 0xffffff00) | val; + break; + case 0x212d: /*Foreground colour*/ + case 0x2179: + tgui->accel.fg_col = (tgui->accel.fg_col & 0xffff00ff) | (val << 8); + break; + case 0x212e: /*Foreground colour*/ + case 0x217a: + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x212f: /*Foreground colour*/ + case 0x217b: + tgui->accel.fg_col = (tgui->accel.fg_col & 0x00ffffff) | (val << 24); + break; + + case 0x2130: /*Background colour*/ + case 0x217c: + tgui->accel.bg_col = (tgui->accel.bg_col & 0xffffff00) | val; + break; + case 0x2131: /*Background colour*/ + case 0x217d: + tgui->accel.bg_col = (tgui->accel.bg_col & 0xffff00ff) | (val << 8); + break; + case 0x2132: /*Background colour*/ + case 0x217e: + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x2133: /*Background colour*/ + case 0x217f: + tgui->accel.bg_col = (tgui->accel.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x2134: /*Pattern location*/ + tgui->accel.patloc = (tgui->accel.patloc & 0xff00) | val; + break; + case 0x2135: /*Pattern location*/ + tgui->accel.patloc = (tgui->accel.patloc & 0xff) | (val << 8); + break; + + case 0x2138: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff00) | val; + break; + case 0x2139: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff) | (val << 8); + break; + case 0x213a: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff00) | val; + break; + case 0x213b: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff) | (val << 8); + break; + + case 0x213c: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff00) | val; + break; + case 0x213d: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff) | (val << 8); + break; + case 0x213e: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff00) | val; + break; + case 0x213f: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff) | (val << 8); + break; + + case 0x2140: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff00) | val; + break; + case 0x2141: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff) | (val << 8); + break; + case 0x2142: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val; + tgui->accel.sv_size_y = (tgui->accel.sv_size_y & 0xff00) | val; + break; + case 0x2143: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8); + tgui->accel.sv_size_y = (tgui->accel.sv_size_y & 0xff) | (val << 8); + break; + + case 0x2144: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0xffffff00) | val; + break; + case 0x2145: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0xffff00ff) | (val << 8); + break; + case 0x2146: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0xff00ffff) | (val << 16); + break; + case 0x2147: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0x00ffffff) | (val << 24); + break; + + case 0x2148: /*Clip Src X*/ + tgui->accel.src_x_clip = (tgui->accel.src_x_clip & 0xff00) | val; + break; + case 0x2149: /*Clip Src X*/ + tgui->accel.src_x_clip = (tgui->accel.src_x_clip & 0xff) | (val << 8); + break; + case 0x214a: /*Clip Src Y*/ + tgui->accel.src_y_clip = (tgui->accel.src_y_clip & 0xff00) | val; + break; + case 0x214b: /*Clip Src Y*/ + tgui->accel.src_y_clip = (tgui->accel.src_y_clip & 0xff) | (val << 8); + break; + + case 0x214c: /*Clip Dest X*/ + tgui->accel.dst_x_clip = (tgui->accel.dst_x_clip & 0xff00) | val; + break; + case 0x214d: /*Clip Dest X*/ + tgui->accel.dst_x_clip = (tgui->accel.dst_x_clip & 0xff) | (val << 8); + break; + case 0x214e: /*Clip Dest Y*/ + tgui->accel.dst_y_clip = (tgui->accel.dst_y_clip & 0xff00) | val; + break; + case 0x214f: /*Clip Dest Y*/ + tgui->accel.dst_y_clip = (tgui->accel.dst_y_clip & 0xff) | (val << 8); + break; + + case 0x2168: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0xffffff00) | val; + break; + case 0x2169: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0xffff00ff) | (val << 8); + break; + case 0x216a: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0xff00ffff) | (val << 16); + break; + case 0x216b: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0x00ffffff) | (val << 24); + break; + + case 0x2180: case 0x2181: case 0x2182: case 0x2183: + case 0x2184: case 0x2185: case 0x2186: case 0x2187: + case 0x2188: case 0x2189: case 0x218a: case 0x218b: + case 0x218c: case 0x218d: case 0x218e: case 0x218f: + case 0x2190: case 0x2191: case 0x2192: case 0x2193: + case 0x2194: case 0x2195: case 0x2196: case 0x2197: + case 0x2198: case 0x2199: case 0x219a: case 0x219b: + case 0x219c: case 0x219d: case 0x219e: case 0x219f: + case 0x21a0: case 0x21a1: case 0x21a2: case 0x21a3: + case 0x21a4: case 0x21a5: case 0x21a6: case 0x21a7: + case 0x21a8: case 0x21a9: case 0x21aa: case 0x21ab: + case 0x21ac: case 0x21ad: case 0x21ae: case 0x21af: + case 0x21b0: case 0x21b1: case 0x21b2: case 0x21b3: + case 0x21b4: case 0x21b5: case 0x21b6: case 0x21b7: + case 0x21b8: case 0x21b9: case 0x21ba: case 0x21bb: + case 0x21bc: case 0x21bd: case 0x21be: case 0x21bf: + case 0x21c0: case 0x21c1: case 0x21c2: case 0x21c3: + case 0x21c4: case 0x21c5: case 0x21c6: case 0x21c7: + case 0x21c8: case 0x21c9: case 0x21ca: case 0x21cb: + case 0x21cc: case 0x21cd: case 0x21ce: case 0x21cf: + case 0x21d0: case 0x21d1: case 0x21d2: case 0x21d3: + case 0x21d4: case 0x21d5: case 0x21d6: case 0x21d7: + case 0x21d8: case 0x21d9: case 0x21da: case 0x21db: + case 0x21dc: case 0x21dd: case 0x21de: case 0x21df: + case 0x21e0: case 0x21e1: case 0x21e2: case 0x21e3: + case 0x21e4: case 0x21e5: case 0x21e6: case 0x21e7: + case 0x21e8: case 0x21e9: case 0x21ea: case 0x21eb: + case 0x21ec: case 0x21ed: case 0x21ee: case 0x21ef: + case 0x21f0: case 0x21f1: case 0x21f2: case 0x21f3: + case 0x21f4: case 0x21f5: case 0x21f6: case 0x21f7: + case 0x21f8: case 0x21f9: case 0x21fa: case 0x21fb: + case 0x21fc: case 0x21fd: case 0x21fe: case 0x21ff: + tgui->accel.pattern[addr & 0x7f] = val; + break; + } +} + +static void +tgui_accel_out_w(uint16_t addr, uint16_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + tgui_accel_out(addr, val, tgui); + tgui_accel_out(addr + 1, val >> 8, tgui); +} + +static void +tgui_accel_out_l(uint16_t addr, uint32_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + switch (addr) { + case 0x2124: /*Long version of Command and ROP together*/ + tgui->accel.command = val & 0xff; + tgui->accel.rop = val >> 24; + tgui->accel.use_src = (tgui->accel.rop & 0x33) ^ ((tgui->accel.rop >> 2) & 0x33); + tgui_accel_command(-1, 0, tgui); + break; + + default: + tgui_accel_out(addr, val, tgui); + tgui_accel_out(addr + 1, val >> 8, tgui); + tgui_accel_out(addr + 2, val >> 16, tgui); + tgui_accel_out(addr + 3, val >> 24, tgui); + break; + } +} + +static uint8_t +tgui_accel_in(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + switch (addr) + { + case 0x2120: /*Status*/ + return 0; + + case 0x2122: + return tgui->accel.ger22 & 0xff; + + case 0x2123: + return tgui->accel.ger22 >> 8; + + case 0x2127: /*ROP*/ + return tgui->accel.rop; + + case 0x2128: /*Flags*/ + return tgui->accel.flags & 0xff; + case 0x2129: /*Flags*/ + return tgui->accel.flags >> 8; + case 0x212a: /*Flags*/ + return tgui->accel.flags >> 16; + case 0x212b: + return tgui->accel.flags >> 24; + + case 0x212c: /*Foreground colour*/ + case 0x2178: + return tgui->accel.fg_col & 0xff; + case 0x212d: /*Foreground colour*/ + case 0x2179: + return tgui->accel.fg_col >> 8; + case 0x212e: /*Foreground colour*/ + case 0x217a: + return tgui->accel.fg_col >> 16; + case 0x212f: /*Foreground colour*/ + case 0x217b: + return tgui->accel.fg_col >> 24; + + case 0x2130: /*Background colour*/ + case 0x217c: + return tgui->accel.bg_col & 0xff; + case 0x2131: /*Background colour*/ + case 0x217d: + return tgui->accel.bg_col >> 8; + case 0x2132: /*Background colour*/ + case 0x217e: + return tgui->accel.bg_col >> 16; + case 0x2133: /*Background colour*/ + case 0x217f: + return tgui->accel.bg_col >> 24; + + case 0x2134: /*Pattern location*/ + return tgui->accel.patloc & 0xff; + case 0x2135: /*Pattern location*/ + return tgui->accel.patloc >> 8; + + case 0x2138: /*Dest X*/ + return tgui->accel.dst_x & 0xff; + case 0x2139: /*Dest X*/ + return tgui->accel.dst_x >> 8; + case 0x213a: /*Dest Y*/ + return tgui->accel.dst_y & 0xff; + case 0x213b: /*Dest Y*/ + return tgui->accel.dst_y >> 8; + + case 0x213c: /*Src X*/ + return tgui->accel.src_x & 0xff; + case 0x213d: /*Src X*/ + return tgui->accel.src_x >> 8; + case 0x213e: /*Src Y*/ + return tgui->accel.src_y & 0xff; + case 0x213f: /*Src Y*/ + return tgui->accel.src_y >> 8; + + case 0x2140: /*Size X*/ + return tgui->accel.size_x & 0xff; + case 0x2141: /*Size X*/ + return tgui->accel.size_x >> 8; + case 0x2142: /*Size Y*/ + return tgui->accel.size_y & 0xff; + case 0x2143: /*Size Y*/ + return tgui->accel.size_y >> 8; + + case 0x2144: /*Style*/ + return tgui->accel.style & 0xff; + case 0x2145: /*Style*/ + return tgui->accel.style >> 8; + case 0x2146: /*Style*/ + return tgui->accel.style >> 16; + case 0x2147: /*Style*/ + return tgui->accel.style >> 24; + + case 0x2148: /*Clip Src X*/ + return tgui->accel.src_x_clip & 0xff; + case 0x2149: /*Clip Src X*/ + return tgui->accel.src_x_clip >> 8; + case 0x214a: /*Clip Src Y*/ + return tgui->accel.src_y_clip & 0xff; + case 0x214b: /*Clip Src Y*/ + return tgui->accel.src_y_clip >> 8; + + case 0x214c: /*Clip Dest X*/ + return tgui->accel.dst_x_clip & 0xff; + case 0x214d: /*Clip Dest X*/ + return tgui->accel.dst_x_clip >> 8; + case 0x214e: /*Clip Dest Y*/ + return tgui->accel.dst_y_clip & 0xff; + case 0x214f: /*Clip Dest Y*/ + return tgui->accel.dst_y_clip >> 8; + + case 0x2168: /*CKey*/ + return tgui->accel.ckey & 0xff; + case 0x2169: /*CKey*/ + return tgui->accel.ckey >> 8; + case 0x216a: /*CKey*/ + return tgui->accel.ckey >> 16; + case 0x216b: /*CKey*/ + return tgui->accel.ckey >> 24; + + case 0x2180: case 0x2181: case 0x2182: case 0x2183: + case 0x2184: case 0x2185: case 0x2186: case 0x2187: + case 0x2188: case 0x2189: case 0x218a: case 0x218b: + case 0x218c: case 0x218d: case 0x218e: case 0x218f: + case 0x2190: case 0x2191: case 0x2192: case 0x2193: + case 0x2194: case 0x2195: case 0x2196: case 0x2197: + case 0x2198: case 0x2199: case 0x219a: case 0x219b: + case 0x219c: case 0x219d: case 0x219e: case 0x219f: + case 0x21a0: case 0x21a1: case 0x21a2: case 0x21a3: + case 0x21a4: case 0x21a5: case 0x21a6: case 0x21a7: + case 0x21a8: case 0x21a9: case 0x21aa: case 0x21ab: + case 0x21ac: case 0x21ad: case 0x21ae: case 0x21af: + case 0x21b0: case 0x21b1: case 0x21b2: case 0x21b3: + case 0x21b4: case 0x21b5: case 0x21b6: case 0x21b7: + case 0x21b8: case 0x21b9: case 0x21ba: case 0x21bb: + case 0x21bc: case 0x21bd: case 0x21be: case 0x21bf: + case 0x21c0: case 0x21c1: case 0x21c2: case 0x21c3: + case 0x21c4: case 0x21c5: case 0x21c6: case 0x21c7: + case 0x21c8: case 0x21c9: case 0x21ca: case 0x21cb: + case 0x21cc: case 0x21cd: case 0x21ce: case 0x21cf: + case 0x21d0: case 0x21d1: case 0x21d2: case 0x21d3: + case 0x21d4: case 0x21d5: case 0x21d6: case 0x21d7: + case 0x21d8: case 0x21d9: case 0x21da: case 0x21db: + case 0x21dc: case 0x21dd: case 0x21de: case 0x21df: + case 0x21e0: case 0x21e1: case 0x21e2: case 0x21e3: + case 0x21e4: case 0x21e5: case 0x21e6: case 0x21e7: + case 0x21e8: case 0x21e9: case 0x21ea: case 0x21eb: + case 0x21ec: case 0x21ed: case 0x21ee: case 0x21ef: + case 0x21f0: case 0x21f1: case 0x21f2: case 0x21f3: + case 0x21f4: case 0x21f5: case 0x21f6: case 0x21f7: + case 0x21f8: case 0x21f9: case 0x21fa: case 0x21fb: + case 0x21fc: case 0x21fd: case 0x21fe: case 0x21ff: + return tgui->accel.pattern[addr & 0x7f]; + } + return 0; +} + +static uint16_t +tgui_accel_in_w(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + return tgui_accel_in(addr, tgui) | (tgui_accel_in(addr + 1, tgui) << 8); +} + +static uint32_t +tgui_accel_in_l(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + return tgui_accel_in_w(addr, tgui) | (tgui_accel_in_w(addr + 2, tgui) << 16); +} + + +static void +tgui_accel_write(uint32_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + if ((svga->crtc[0x36] & 0x03) == 0x02) { + if ((addr & ~0xff) != 0xbff00) + return; + } else if ((svga->crtc[0x36] & 0x03) == 0x01) { + if ((addr & ~0xff) != 0xb7f00) + return; + } + switch (addr & 0xff) { - case 0x22: - tgui->accel.ger22 = val; - tgui->accel.pitch = 512 << ((val >> 2) & 3); - tgui->accel.bpp = (val & 3) ? 1 : 0; - tgui->accel.pitch >>= tgui->accel.bpp; - break; - + case 0x22: + tgui->accel.ger22 = (tgui->accel.ger22 & 0xff00) | val; + switch (val & 0xff) { + case 4: + case 8: + tgui->accel.bpp = 0; + break; + + case 9: + tgui->accel.bpp = 1; + break; + + case 13: + case 14: + switch (tgui->svga.bpp) { + case 15: + case 16: + tgui->accel.bpp = 1; + break; + + case 24: + tgui->accel.bpp = 0; + break; + + case 32: + tgui->accel.bpp = 3; + break; + } + break; + } + break; + + case 0x23: + tgui->accel.ger22 = (tgui->accel.ger22 & 0xff) | (val << 8); + break; + case 0x24: /*Command*/ tgui->accel.command = val; tgui_accel_command(-1, 0, tgui); break; - + case 0x27: /*ROP*/ tgui->accel.rop = val; tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); break; - + case 0x28: /*Flags*/ - tgui->accel.flags = (tgui->accel.flags & 0xff00) | val; + tgui->accel.flags = (tgui->accel.flags & 0xffffff00) | val; break; case 0x29: /*Flags*/ - tgui->accel.flags = (tgui->accel.flags & 0xff) | (val << 8); + tgui->accel.flags = (tgui->accel.flags & 0xffff00ff) | (val << 8); + break; + case 0x2a: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff00ffff) | (val << 16); + break; + case 0x2b: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0x0000ffff) | (val << 24); break; - case 0x2b: - tgui->accel.offset = val & 7; - break; - case 0x2c: /*Foreground colour*/ - tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00) | val; + case 0x78: + tgui->accel.fg_col = (tgui->accel.fg_col & 0xffffff00) | val; break; case 0x2d: /*Foreground colour*/ - tgui->accel.fg_col = (tgui->accel.fg_col & 0xff) | (val << 8); + case 0x79: + tgui->accel.fg_col = (tgui->accel.fg_col & 0xffff00ff) | (val << 8); + break; + case 0x2e: /*Foreground colour*/ + case 0x7a: + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x2f: /*Foreground colour*/ + case 0x7b: + tgui->accel.fg_col = (tgui->accel.fg_col & 0x00ffffff) | (val << 24); break; case 0x30: /*Background colour*/ - tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00) | val; + case 0x7c: + tgui->accel.bg_col = (tgui->accel.bg_col & 0xffffff00) | val; break; case 0x31: /*Background colour*/ - tgui->accel.bg_col = (tgui->accel.bg_col & 0xff) | (val << 8); + case 0x7d: + tgui->accel.bg_col = (tgui->accel.bg_col & 0xffff00ff) | (val << 8); + break; + case 0x32: /*Background colour*/ + case 0x7e: + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x33: /*Background colour*/ + case 0x7f: + tgui->accel.bg_col = (tgui->accel.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x34: /*Pattern location*/ + tgui->accel.patloc = (tgui->accel.patloc & 0xff00) | val; + break; + case 0x35: /*Pattern location*/ + tgui->accel.patloc = (tgui->accel.patloc & 0xff) | (val << 8); break; case 0x38: /*Dest X*/ @@ -1330,11 +2579,65 @@ static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) break; case 0x42: /*Size Y*/ tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val; + tgui->accel.sv_size_y = (tgui->accel.sv_size_y & 0xff00) | val; break; case 0x43: /*Size Y*/ tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8); + tgui->accel.sv_size_y = (tgui->accel.sv_size_y & 0xff) | (val << 8); break; - + + case 0x44: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0xffffff00) | val; + break; + case 0x45: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0xffff00ff) | (val << 8); + break; + case 0x46: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0xff00ffff) | (val << 16); + break; + case 0x47: /*Style*/ + tgui->accel.style = (tgui->accel.style & 0x00ffffff) | (val << 24); + break; + + case 0x48: /*Clip Src X*/ + tgui->accel.src_x_clip = (tgui->accel.src_x_clip & 0xff00) | val; + break; + case 0x49: /*Clip Src X*/ + tgui->accel.src_x_clip = (tgui->accel.src_x_clip & 0xff) | (val << 8); + break; + case 0x4a: /*Clip Src Y*/ + tgui->accel.src_y_clip = (tgui->accel.src_y_clip & 0xff00) | val; + break; + case 0x4b: /*Clip Src Y*/ + tgui->accel.src_y_clip = (tgui->accel.src_y_clip & 0xff) | (val << 8); + break; + + case 0x4c: /*Clip Dest X*/ + tgui->accel.dst_x_clip = (tgui->accel.dst_x_clip & 0xff00) | val; + break; + case 0x4d: /*Clip Dest X*/ + tgui->accel.dst_x_clip = (tgui->accel.dst_x_clip & 0xff) | (val << 8); + break; + case 0x4e: /*Clip Dest Y*/ + tgui->accel.dst_y_clip = (tgui->accel.dst_y_clip & 0xff00) | val; + break; + case 0x4f: /*Clip Dest Y*/ + tgui->accel.dst_y_clip = (tgui->accel.dst_y_clip & 0xff) | (val << 8); + break; + + case 0x68: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0xffffff00) | val; + break; + case 0x69: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0xffff00ff) | (val << 8); + break; + case 0x6a: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0xff00ffff) | (val << 16); + break; + case 0x6b: /*CKey*/ + tgui->accel.ckey = (tgui->accel.ckey & 0x00ffffff) | (val << 24); + break; + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: @@ -1372,159 +2675,110 @@ static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) } } -static void tgui_accel_write_fifo_fb_b(tgui_t *tgui, uint32_t addr, uint8_t val) +static void +tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) { - tgui_accel_command(8, val << 24, tgui); -} -static void tgui_accel_write_fifo_fb_w(tgui_t *tgui, uint32_t addr, uint16_t val) -{ - tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui); -} -static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val) -{ - tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui); -} + tgui_t *tgui = (tgui_t *)p; -static void fifo_thread(void *param) -{ - tgui_t *tgui = (tgui_t *)param; - - while (1) - { - thread_set_event(tgui->fifo_not_full_event); - thread_wait_event(tgui->wake_fifo_thread, -1); - thread_reset_event(tgui->wake_fifo_thread); - tgui->blitter_busy = 1; - while (!FIFO_EMPTY) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; - - switch (fifo->addr_type & FIFO_TYPE) - { - case FIFO_WRITE_BYTE: - tgui_accel_write_fifo(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_FB_BYTE: - tgui_accel_write_fifo_fb_b(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_FB_WORD: - tgui_accel_write_fifo_fb_w(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_FB_LONG: - tgui_accel_write_fifo_fb_l(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - } - - tgui->fifo_read_idx++; - fifo->addr_type = FIFO_INVALID; - - if (FIFO_ENTRIES > 0xe000) - thread_set_event(tgui->fifo_not_full_event); - - end_time = plat_timer_read(); - tgui->blitter_time += end_time - start_time; - } - tgui->blitter_busy = 0; - } -} - -static inline void wake_fifo_thread(tgui_t *tgui) -{ - thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} - -static void tgui_wait_fifo_idle(tgui_t *tgui) -{ - while (!FIFO_EMPTY) - { - wake_fifo_thread(tgui); - thread_wait_event(tgui->fifo_not_full_event, 1); - } -} - -static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) -{ - fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK]; - - if (FIFO_FULL) - { - thread_reset_event(tgui->fifo_not_full_event); - if (FIFO_FULL) - { - thread_wait_event(tgui->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ - } - } - - fifo->val = val; - fifo->addr_type = (addr & FIFO_ADDR) | type; - - tgui->fifo_write_idx++; - - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) - wake_fifo_thread(tgui); -} - - -void tgui_accel_write(uint32_t addr, uint8_t val, void *p) -{ - tgui_t *tgui = (tgui_t *)p; - if ((addr & ~0xff) != 0xbff00) - return; - tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE); -} - -void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) -{ - tgui_t *tgui = (tgui_t *)p; tgui_accel_write(addr, val, tgui); tgui_accel_write(addr + 1, val >> 8, tgui); } -void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) +static void +tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) { - tgui_t *tgui = (tgui_t *)p; - tgui_accel_write(addr, val, tgui); - tgui_accel_write(addr + 1, val >> 8, tgui); - tgui_accel_write(addr + 2, val >> 16, tgui); - tgui_accel_write(addr + 3, val >> 24, tgui); + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + switch (addr & 0xff) { + case 0x24: /*Long version of Command and ROP together*/ + if ((svga->crtc[0x36] & 0x03) == 0x02) { + if ((addr & ~0xff) != 0xbff00) + return; + } else if ((svga->crtc[0x36] & 0x03) == 0x01) { + if ((addr & ~0xff) != 0xb7f00) + return; + } + tgui->accel.command = val & 0xff; + tgui->accel.rop = val >> 24; + tgui->accel.use_src = ((val >> 24) & 0x33) ^ (((val >> 24) >> 2) & 0x33); + tgui_accel_command(-1, 0, tgui); + break; + + default: + tgui_accel_write_w(addr, val, tgui); + tgui_accel_write_w(addr + 2, val >> 16, tgui); + break; + } } -uint8_t tgui_accel_read(uint32_t addr, void *p) +static uint8_t +tgui_accel_read(uint32_t addr, void *p) { - tgui_t *tgui = (tgui_t *)p; - if ((addr & ~0xff) != 0xbff00) - return 0xff; - if ((addr & 0xff) != 0x20) - tgui_wait_fifo_idle(tgui); + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + if ((svga->crtc[0x36] & 0x03) == 0x02) { + if ((addr & ~0xff) != 0xbff00) + return 0xff; + } else if ((svga->crtc[0x36] & 0x03) == 0x01) { + if ((addr & ~0xff) != 0xb7f00) + return 0xff; + } + switch (addr & 0xff) { case 0x20: /*Status*/ - if (!FIFO_EMPTY) - return 1 << 5; return 0; - + + case 0x22: + return tgui->accel.ger22 & 0xff; + + case 0x23: + return tgui->accel.ger22 >> 8; + case 0x27: /*ROP*/ return tgui->accel.rop; - + case 0x28: /*Flags*/ return tgui->accel.flags & 0xff; case 0x29: /*Flags*/ return tgui->accel.flags >> 8; - + case 0x2a: /*Flags*/ + return tgui->accel.flags >> 16; case 0x2b: - return tgui->accel.offset; - - case 0x2c: /*Background colour*/ - return tgui->accel.bg_col & 0xff; - case 0x2d: /*Background colour*/ - return tgui->accel.bg_col >> 8; + return tgui->accel.flags >> 24; - case 0x30: /*Foreground colour*/ + case 0x2c: /*Foreground colour*/ + case 0x78: return tgui->accel.fg_col & 0xff; - case 0x31: /*Foreground colour*/ + case 0x2d: /*Foreground colour*/ + case 0x79: return tgui->accel.fg_col >> 8; + case 0x2e: /*Foreground colour*/ + case 0x7a: + return tgui->accel.fg_col >> 16; + case 0x2f: /*Foreground colour*/ + case 0x7b: + return tgui->accel.fg_col >> 24; + + case 0x30: /*Background colour*/ + case 0x7c: + return tgui->accel.bg_col & 0xff; + case 0x31: /*Background colour*/ + case 0x7d: + return tgui->accel.bg_col >> 8; + case 0x32: /*Background colour*/ + case 0x7e: + return tgui->accel.bg_col >> 16; + case 0x33: /*Background colour*/ + case 0x7f: + return tgui->accel.bg_col >> 24; + + case 0x34: /*Pattern location*/ + return tgui->accel.patloc & 0xff; + case 0x35: /*Pattern location*/ + return tgui->accel.patloc >> 8; case 0x38: /*Dest X*/ return tgui->accel.dst_x & 0xff; @@ -1552,7 +2806,43 @@ uint8_t tgui_accel_read(uint32_t addr, void *p) return tgui->accel.size_y & 0xff; case 0x43: /*Size Y*/ return tgui->accel.size_y >> 8; - + + case 0x44: /*Style*/ + return tgui->accel.style & 0xff; + case 0x45: /*Style*/ + return tgui->accel.style >> 8; + case 0x46: /*Style*/ + return tgui->accel.style >> 16; + case 0x47: /*Style*/ + return tgui->accel.style >> 24; + + case 0x48: /*Clip Src X*/ + return tgui->accel.src_x_clip & 0xff; + case 0x49: /*Clip Src X*/ + return tgui->accel.src_x_clip >> 8; + case 0x4a: /*Clip Src Y*/ + return tgui->accel.src_y_clip & 0xff; + case 0x4b: /*Clip Src Y*/ + return tgui->accel.src_y_clip >> 8; + + case 0x4c: /*Clip Dest X*/ + return tgui->accel.dst_x_clip & 0xff; + case 0x4d: /*Clip Dest X*/ + return tgui->accel.dst_x_clip >> 8; + case 0x4e: /*Clip Dest Y*/ + return tgui->accel.dst_y_clip & 0xff; + case 0x4f: /*Clip Dest Y*/ + return tgui->accel.dst_y_clip >> 8; + + case 0x68: /*CKey*/ + return tgui->accel.ckey & 0xff; + case 0x69: /*CKey*/ + return tgui->accel.ckey >> 8; + case 0x6a: /*CKey*/ + return tgui->accel.ckey >> 16; + case 0x6b: /*CKey*/ + return tgui->accel.ckey >> 24; + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: @@ -1590,139 +2880,293 @@ uint8_t tgui_accel_read(uint32_t addr, void *p) return 0xff; } -uint16_t tgui_accel_read_w(uint32_t addr, void *p) +static uint16_t +tgui_accel_read_w(uint32_t addr, void *p) { tgui_t *tgui = (tgui_t *)p; return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8); } -uint32_t tgui_accel_read_l(uint32_t addr, void *p) +static uint32_t +tgui_accel_read_l(uint32_t addr, void *p) { tgui_t *tgui = (tgui_t *)p; return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16); } -void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) +static void +tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; - if (tgui->write_blitter) - tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); - else - svga_write_linear(addr, val, svga); + if (tgui->write_blitter) { + tgui_accel_command(8, val << 24, tgui); + } else + svga_write_linear(addr, val, svga); } -void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) +static void +tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; if (tgui->write_blitter) - tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); + tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui); else - svga_writew_linear(addr, val, svga); + svga_writew_linear(addr, val, svga); } -void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) +static void +tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; if (tgui->write_blitter) - tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); + tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui); else - svga_writel_linear(addr, val, svga); + svga_writel_linear(addr, val, svga); +} + +static void +tgui_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + addr &= 0x0000ffff; + + if (((svga->crtc[0x36] & 0x03) == 0x00) && (addr >= 0x2100 && addr <= 0x21ff)) + tgui_accel_out(addr, val, p); + else if (((svga->crtc[0x36] & 0x03) > 0x00) && (addr <= 0xff)) + tgui_accel_write(addr, val, p); + else + tgui_out(addr, val, p); +} + + +static void +tgui_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + addr &= 0x0000ffff; + + if (((svga->crtc[0x36] & 0x03) == 0x00) && (addr >= 0x2100 && addr <= 0x21ff)) + tgui_accel_out_w(addr, val, p); + else if (((svga->crtc[0x36] & 0x03) > 0x00) && (addr <= 0xff)) + tgui_accel_write_w(addr, val, p); + else { + tgui_out(addr, val & 0xff, p); + tgui_out(addr + 1, val >> 8, p); + } +} + + +static void +tgui_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + addr &= 0x0000ffff; + + if (((svga->crtc[0x36] & 0x03) == 0x00) && (addr >= 0x2100 && addr <= 0x21ff)) + tgui_accel_out_l(addr, val, p); + else if (((svga->crtc[0x36] & 0x03) > 0x00) && (addr <= 0xff)) + tgui_accel_write_l(addr, val, p); + else { + tgui_out(addr, val & 0xff, p); + tgui_out(addr + 1, val >> 8, p); + tgui_out(addr + 2, val >> 16, p); + tgui_out(addr + 3, val >> 24, p); + } +} + + +static uint8_t +tgui_mmio_read(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + uint8_t ret = 0xff; + + addr &= 0x0000ffff; + + if (((svga->crtc[0x36] & 0x03) == 0x00) && (addr >= 0x2100 && addr <= 0x21ff)) + ret = tgui_accel_in(addr, p); + else if (((svga->crtc[0x36] & 0x03) > 0x00) && (addr <= 0xff)) + ret = tgui_accel_read(addr, p); + else + ret = tgui_in(addr, p); + + return ret; +} + + +static uint16_t +tgui_mmio_read_w(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + uint16_t ret = 0xffff; + + addr &= 0x0000ffff; + + if (((svga->crtc[0x36] & 0x03) == 0x00) && (addr >= 0x2100 && addr <= 0x21ff)) + ret = tgui_accel_in_w(addr, p); + else if (((svga->crtc[0x36] & 0x03) > 0x00) && (addr <= 0xff)) + ret = tgui_accel_read_w(addr, p); + else + ret = tgui_in(addr, p) | (tgui_in(addr + 1, p) << 8); + + return ret; +} + + +static uint32_t +tgui_mmio_read_l(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + uint32_t ret = 0xffffffff; + + addr &= 0x0000ffff; + + if (((svga->crtc[0x36] & 0x03) == 0x00) && (addr >= 0x2100 && addr <= 0x21ff)) + ret = tgui_accel_in_l(addr, p); + else if (((svga->crtc[0x36] & 0x03) > 0x00) && (addr <= 0xff)) + ret = tgui_accel_read_l(addr, p); + else + ret = tgui_in(addr, p) | (tgui_in(addr + 1, p) << 8) | (tgui_in(addr + 2, p) << 16) | (tgui_in(addr + 3, p) << 24); + + return ret; } static void *tgui_init(const device_t *info) { - const wchar_t *bios_fn; - int type = info->local; + const char *bios_fn; tgui_t *tgui = malloc(sizeof(tgui_t)); + svga_t *svga = &tgui->svga; memset(tgui, 0, sizeof(tgui_t)); - + tgui->vram_size = device_get_config_int("memory") << 20; tgui->vram_mask = tgui->vram_size - 1; - - tgui->type = type; + + tgui->type = info->local & 0xff; tgui->pci = !!(info->flags & DEVICE_PCI); - switch(info->local) { + switch(tgui->type) { case TGUI_9400CXI: bios_fn = ROM_TGUI_9400CXI; break; case TGUI_9440: - bios_fn = ROM_TGUI_9440; + bios_fn = (info->local & ONBOARD) ? NULL : ROM_TGUI_9440; + break; + case TGUI_9660: + case TGUI_9680: + bios_fn = ROM_TGUI_96xx; break; default: free(tgui); return NULL; } - rom_init(&tgui->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + tgui->has_bios = (bios_fn != NULL); - if (info->flags & DEVICE_PCI) + if (tgui->has_bios) { + rom_init(&tgui->bios_rom, (char *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (tgui->pci) + mem_mapping_disable(&tgui->bios_rom.mapping); + } + + if (tgui->pci) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tgui_pci); else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tgui_vlb); - svga_init(info, &tgui->svga, tgui, tgui->vram_size, + svga_init(info, svga, tgui, tgui->vram_size, tgui_recalctimings, tgui_in, tgui_out, tgui_hwcursor_draw, NULL); if (tgui->type == TGUI_9400CXI) - tgui->svga.ramdac = device_add(&tkd8001_ramdac_device); + svga->ramdac = device_add(&tkd8001_ramdac_device); - mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, NULL, MEM_MAPPING_EXTERNAL, &tgui->svga); - mem_mapping_add(&tgui->accel_mapping, 0xbc000, 0x4000, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, tgui); + mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, NULL, MEM_MAPPING_EXTERNAL, svga); + mem_mapping_add(&tgui->accel_mapping, 0, 0, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, tgui); + if (tgui->type >= TGUI_9440) + mem_mapping_add(&tgui->mmio_mapping, 0, 0, tgui_mmio_read, tgui_mmio_read_w, tgui_mmio_read_l, tgui_mmio_write, tgui_mmio_write_w, tgui_mmio_write_l, NULL, MEM_MAPPING_EXTERNAL, tgui); mem_mapping_disable(&tgui->accel_mapping); + mem_mapping_disable(&tgui->mmio_mapping); - io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); - if (tgui->type >= TGUI_9440) - io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + tgui_set_io(tgui); - if ((info->flags & DEVICE_PCI) && (tgui->type >= TGUI_9440)) - pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); + if (tgui->pci && (tgui->type >= TGUI_9440)) { + if (tgui->has_bios) + tgui->card = pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); + else + tgui->card = pci_add_card(PCI_ADD_VIDEO | PCI_ADD_STRICT, tgui_pci_read, tgui_pci_write, tgui); + } - tgui->wake_fifo_thread = thread_create_event(); - tgui->fifo_not_full_event = thread_create_event(); - tgui->fifo_thread = thread_create(fifo_thread, tgui); + tgui->pci_regs[PCI_REG_COMMAND] = 7; + + if (tgui->has_bios) { + tgui->pci_regs[0x30] = 0x00; + tgui->pci_regs[0x32] = 0x0c; + tgui->pci_regs[0x33] = 0x00; + } + + if (tgui->type >= TGUI_9440) { + svga->packed_chain4 = 1; + + tgui->i2c = i2c_gpio_init("ddc_tgui"); + tgui->ddc = ddc_init(i2c_gpio_get_bus(tgui->i2c)); + } return tgui; } -static int tgui9400cxi_available() +static int tgui9400cxi_available(void) { - return rom_present(L"roms/video/tgui9440/9400CXI.vbi"); + return rom_present(ROM_TGUI_9400CXI); } -static int tgui9440_available() +static int tgui9440_available(void) { - return rom_present(L"roms/video/tgui9440/9440.vbi"); + return rom_present(ROM_TGUI_9440); +} + +static int tgui96xx_available(void) +{ + return rom_present(ROM_TGUI_96xx); } void tgui_close(void *p) { - tgui_t *tgui = (tgui_t *)p; - - svga_close(&tgui->svga); - - thread_kill(tgui->fifo_thread); - thread_destroy_event(tgui->wake_fifo_thread); - thread_destroy_event(tgui->fifo_not_full_event); + tgui_t *tgui = (tgui_t *)p; - free(tgui); + svga_close(&tgui->svga); + + if (tgui->type >= TGUI_9440) { + ddc_close(tgui->ddc); + i2c_gpio_close(tgui->i2c); + }; + + free(tgui); } void tgui_speed_changed(void *p) { tgui_t *tgui = (tgui_t *)p; - + svga_recalctimings(&tgui->svga); } @@ -1733,72 +3177,142 @@ void tgui_force_redraw(void *p) tgui->svga.fullchange = changeframecount; } - -static const device_config_t tgui9440_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } - }, - .default_int = 2 +// clang-format off +static const device_config_t tgui9440_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } }, - { - .type = -1 - } + .default_int = 2 + }, + { + .type = CONFIG_END + } }; -const device_t tgui9400cxi_device = -{ - "Trident TGUI 9400CXi", - DEVICE_VLB, - TGUI_9400CXI, - tgui_init, - tgui_close, - NULL, - tgui9400cxi_available, - tgui_speed_changed, - tgui_force_redraw, - tgui9440_config +static const device_config_t tgui96xx_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = CONFIG_END + } +}; +// clang-format on + +const device_t tgui9400cxi_device = { + .name = "Trident TGUI 9400CXi", + .internal_name = "tgui9400cxi_vlb", + .flags = DEVICE_VLB, + .local = TGUI_9400CXI, + .init = tgui_init, + .close = tgui_close, + .reset = NULL, + { .available = tgui9400cxi_available }, + .speed_changed = tgui_speed_changed, + .force_redraw = tgui_force_redraw, + .config = tgui9440_config }; -const device_t tgui9440_vlb_device = -{ - "Trident TGUI 9440 VLB", - DEVICE_VLB, - TGUI_9440, - tgui_init, - tgui_close, - NULL, - tgui9440_available, - tgui_speed_changed, - tgui_force_redraw, - tgui9440_config +const device_t tgui9440_vlb_device = { + .name = "Trident TGUI 9440AGi VLB", + .internal_name = "tgui9440_vlb", + .flags = DEVICE_VLB, + .local = TGUI_9440, + .init = tgui_init, + .close = tgui_close, + .reset = NULL, + { .available = tgui9440_available }, + .speed_changed = tgui_speed_changed, + .force_redraw = tgui_force_redraw, + .config = tgui9440_config }; -const device_t tgui9440_pci_device = -{ - "Trident TGUI 9440 PCI", - DEVICE_PCI, - TGUI_9440, - tgui_init, - tgui_close, - NULL, - tgui9440_available, - tgui_speed_changed, - tgui_force_redraw, - tgui9440_config +const device_t tgui9440_pci_device = { + .name = "Trident TGUI 9440AGi PCI", + .internal_name = "tgui9440_pci", + .flags = DEVICE_PCI, + .local = TGUI_9440, + .init = tgui_init, + .close = tgui_close, + .reset = NULL, + { .available = tgui9440_available }, + .speed_changed = tgui_speed_changed, + .force_redraw = tgui_force_redraw, + .config = tgui9440_config +}; + +const device_t tgui9440_onboard_pci_device = { + .name = "Trident TGUI 9440AGi On-Board PCI", + .internal_name = "tgui9440_onboard_pci", + .flags = DEVICE_PCI, + .local = TGUI_9440 | ONBOARD, + .init = tgui_init, + .close = tgui_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = tgui_speed_changed, + .force_redraw = tgui_force_redraw, + .config = tgui9440_config +}; + +const device_t tgui9660_pci_device = { + .name = "Trident TGUI 9660XGi PCI", + .internal_name = "tgui9660_pci", + .flags = DEVICE_PCI, + .local = TGUI_9660, + .init = tgui_init, + .close = tgui_close, + .reset = NULL, + { .available = tgui96xx_available }, + .speed_changed = tgui_speed_changed, + .force_redraw = tgui_force_redraw, + .config = tgui96xx_config +}; + +const device_t tgui9680_pci_device = { + .name = "Trident TGUI 9680XGi PCI", + .internal_name = "tgui9680_pci", + .flags = DEVICE_PCI, + .local = TGUI_9680, + .init = tgui_init, + .close = tgui_close, + .reset = NULL, + { .available = tgui96xx_available }, + .speed_changed = tgui_speed_changed, + .force_redraw = tgui_force_redraw, + .config = tgui96xx_config }; diff --git a/src/video/vid_ti_cf62011.c b/src/video/vid_ti_cf62011.c index 964b0ed9b..36db5b89d 100644 --- a/src/video/vid_ti_cf62011.c +++ b/src/video/vid_ti_cf62011.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -262,14 +262,16 @@ vid_init(const device_t *info) return(ti); } - const device_t ibm_ps1_2121_device = { - "IBM PS/1 Model 2121 SVGA", - DEVICE_ISA, - 512, - vid_init, vid_close, NULL, - NULL, - vid_speed_changed, - vid_force_redraw, - NULL + .name = "IBM PS/1 Model 2121 SVGA", + .internal_name = "ibm_ps1_2121", + .flags = DEVICE_ISA, + .local = 512, + .init = vid_init, + .close = vid_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = vid_speed_changed, + .force_redraw = vid_force_redraw, + .config = NULL }; diff --git a/src/video/vid_tkd8001_ramdac.c b/src/video/vid_tkd8001_ramdac.c index c02403512..e2b7ed498 100644 --- a/src/video/vid_tkd8001_ramdac.c +++ b/src/video/vid_tkd8001_ramdac.c @@ -117,11 +117,16 @@ tkd8001_ramdac_close(void *priv) free(ramdac); } - -const device_t tkd8001_ramdac_device = -{ - "Trident TKD8001 RAMDAC", - 0, 0, - tkd8001_ramdac_init, tkd8001_ramdac_close, - NULL, NULL, NULL, NULL +const device_t tkd8001_ramdac_device = { + .name = "Trident TKD8001 RAMDAC", + .internal_name = "tkd8001_ramdac", + .flags = 0, + .local = 0, + .init = tkd8001_ramdac_init, + .close = tkd8001_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 3c149a145..8d488552e 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -32,10 +32,12 @@ #include <86box/vid_svga_render.h> #define TVGA8900B_ID 0x03 +#define TVGA9000B_ID 0x23 #define TVGA8900CLD_ID 0x33 -#define ROM_TVGA_8900B L"roms/video/tvga/tvga8900B.VBI" -#define ROM_TVGA_8900CLD L"roms/video/tvga/trident.bin" +#define ROM_TVGA_8900B "roms/video/tvga/tvga8900b.vbi" +#define ROM_TVGA_8900CLD "roms/video/tvga/trident.bin" +#define ROM_TVGA_9000B "roms/video/tvga/tvga9000b.bin" typedef struct tvga_t { @@ -51,12 +53,13 @@ typedef struct tvga_t int oldmode; uint8_t oldctrl1; uint8_t oldctrl2, newctrl2; - + int vram_size; uint32_t vram_mask; } tvga_t; -video_timings_t timing_tvga = {VIDEO_ISA, 3, 3, 6, 8, 8, 12}; +video_timings_t timing_tvga8900 = {VIDEO_ISA, 3, 3, 6, 8, 8, 12}; +video_timings_t timing_tvga9000 = {VIDEO_ISA, 7, 7, 12, 7, 7, 12}; static uint8_t crtc_mask[0x40] = { @@ -85,16 +88,16 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) case 0x3C5: switch (svga->seqaddr & 0xf) { - case 0xB: - tvga->oldmode=1; + case 0xB: + tvga->oldmode=1; break; - case 0xC: - if (svga->seqregs[0xe] & 0x80) - svga->seqregs[0xc] = val; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; break; - case 0xd: - if (tvga->oldmode) - tvga->oldctrl2 = val; + case 0xd: + if (tvga->oldmode) + tvga->oldctrl2 = val; else { tvga->newctrl2 = val; @@ -102,9 +105,9 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) } break; case 0xE: - if (tvga->oldmode) - tvga->oldctrl1 = val; - else + if (tvga->oldmode) + tvga->oldctrl1 = val; + else { svga->seqregs[0xe] = val ^ 2; tvga->tvga_3d8 = svga->seqregs[0xe] & 0xf; @@ -115,12 +118,24 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - tkd8001_ramdac_out(addr, val, svga->ramdac, svga); - return; + if (tvga->card_id != TVGA9000B_ID) { + tkd8001_ramdac_out(addr, val, svga->ramdac, svga); + return; + } + break; case 0x3CF: switch (svga->gdcaddr & 15) { + case 0x6: + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) + { + /*override mask - TVGA supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; case 0xE: svga->gdcreg[0xe] = val ^ 2; tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; @@ -143,35 +158,45 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) old = svga->crtc[svga->crtcreg]; val &= crtc_mask[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; - if (old != val) - { - if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } - switch (svga->crtcreg) - { + switch (svga->crtcreg) { case 0x1e: svga->vram_display_mask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; break; } return; case 0x3D8: - if (svga->gdcreg[0xf] & 4) - { + if (svga->gdcreg[0xf] & 4) { tvga->tvga_3d8 = val; tvga_recalcbanking(tvga); } return; case 0x3D9: - if (svga->gdcreg[0xf] & 4) - { + if (svga->gdcreg[0xf] & 4) { tvga->tvga_3d9 = val; tvga_recalcbanking(tvga); } return; + case 0x3DB: + if (tvga->card_id != TVGA9000B_ID) { + /*3db appears to be a 4 bit clock select register on 8900D*/ + svga->miscout = (svga->miscout & ~0x0c) | ((val & 3) << 2); + tvga->newctrl2 = (tvga->newctrl2 & ~0x01) | ((val & 4) >> 2); + tvga->oldctrl1 = (tvga->oldctrl1 & ~0x10) | ((val & 8) << 1); + svga_recalctimings(svga); + } + break; } svga_out(addr, val, svga); } @@ -182,7 +207,7 @@ uint8_t tvga_in(uint16_t addr, void *p) svga_t *svga = &tvga->svga; if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; - + switch (addr) { case 0x3C5: @@ -198,12 +223,15 @@ uint8_t tvga_in(uint16_t addr, void *p) } if ((svga->seqaddr & 0xf) == 0xe) { - if (tvga->oldmode) - return tvga->oldctrl1; + if (tvga->oldmode) + return tvga->oldctrl1; } break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return tkd8001_ramdac_in(addr, svga->ramdac, svga); + if (tvga->card_id != TVGA9000B_ID) { + return tkd8001_ramdac_in(addr, svga->ramdac, svga); + } + break; case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -221,7 +249,7 @@ uint8_t tvga_in(uint16_t addr, void *p) static void tvga_recalcbanking(tvga_t *tvga) { svga_t *svga = &tvga->svga; - + svga->write_bank = (tvga->tvga_3d8 & 0x1f) * 65536; if (svga->gdcreg[0xf] & 1) @@ -233,6 +261,9 @@ static void tvga_recalcbanking(tvga_t *tvga) void tvga_recalctimings(svga_t *svga) { tvga_t *tvga = (tvga_t *)svga->p; + int clksel; + int high_res_256 = 0; + if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled, given that TVGA8900D has no overflow bits. Some sort of overflow is required for 320x200x24 and 1024x768x16*/ @@ -241,55 +272,80 @@ void tvga_recalctimings(svga_t *svga) if (svga->bpp == 24) svga->hdisp = (svga->crtc[1] + 1) * 8; - + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; - + if (tvga->oldctrl2 & 0x10) { svga->rowoffset <<= 1; svga->ma_latch <<= 1; } - + if (svga->gdcreg[0xf] & 0x08) { svga->htotal *= 2; svga->hdisp *= 2; svga->hdisp_time *= 2; } - + svga->interlace = (svga->crtc[0x1e] & 4); - + if (svga->interlace) svga->rowoffset >>= 1; - switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) - { - case 2: svga->clock = (cpuclock * (double)(1ull << 32))/44900000.0; break; - case 3: svga->clock = (cpuclock * (double)(1ull << 32))/36000000.0; break; - case 4: svga->clock = (cpuclock * (double)(1ull << 32))/57272000.0; break; - case 5: svga->clock = (cpuclock * (double)(1ull << 32))/65000000.0; break; - case 6: svga->clock = (cpuclock * (double)(1ull << 32))/50350000.0; break; - case 7: svga->clock = (cpuclock * (double)(1ull << 32))/40000000.0; break; + if (tvga->card_id == TVGA8900CLD_ID) + clksel = ((svga->miscout >> 2) & 3) | ((tvga->newctrl2 & 0x01) << 2) | ((tvga->oldctrl1 & 0x10) >> 1); + else + clksel = ((svga->miscout >> 2) & 3) | ((tvga->newctrl2 & 0x01) << 2) | ((tvga->newctrl2 & 0x40) >> 3); + + switch (clksel) { + case 0x2: svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; break; + case 0x3: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + case 0x4: svga->clock = (cpuclock * (double)(1ull << 32)) / 57272000.0; break; + case 0x5: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + case 0x6: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x7: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x8: svga->clock = (cpuclock * (double)(1ull << 32)) / 88000000.0; break; + case 0x9: svga->clock = (cpuclock * (double)(1ull << 32)) / 98000000.0; break; + case 0xa: svga->clock = (cpuclock * (double)(1ull << 32)) / 118800000.0; break; + case 0xb: svga->clock = (cpuclock * (double)(1ull << 32)) / 108000000.0; break; + case 0xc: svga->clock = (cpuclock * (double)(1ull << 32)) / 72000000.0; break; + case 0xd: svga->clock = (cpuclock * (double)(1ull << 32)) / 77000000.0; break; + case 0xe: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; + case 0xf: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; } - if (tvga->oldctrl2 & 0x10) + if (tvga->card_id != TVGA8900CLD_ID) { + /*TVGA9000 doesn't seem to have support for a 'high res' 256 colour mode + (without the VGA pixel doubling). Instead it implements these modes by + doubling the horizontal pixel count and pixel clock. Hence we use a + basic heuristic to detect this*/ + if (svga->interlace) + high_res_256 = (svga->htotal * 8) > (svga->vtotal * 4); + else + high_res_256 = (svga->htotal * 8) > (svga->vtotal * 2); + } + + if ((tvga->oldctrl2 & 0x10) || high_res_256) { + if (high_res_256) + svga->hdisp /= 2; switch (svga->bpp) { - case 8: + case 8: svga->render = svga_render_8bpp_highres; break; - case 15: - svga->render = svga_render_15bpp_highres; + case 15: + svga->render = svga_render_15bpp_highres; svga->hdisp /= 2; break; - case 16: - svga->render = svga_render_16bpp_highres; + case 16: + svga->render = svga_render_16bpp_highres; svga->hdisp /= 2; break; - case 24: + case 24: svga->render = svga_render_24bpp_highres; svga->hdisp /= 3; break; @@ -301,17 +357,22 @@ void tvga_recalctimings(svga_t *svga) static void *tvga_init(const device_t *info) { - const wchar_t *bios_fn; + const char *bios_fn; tvga_t *tvga = malloc(sizeof(tvga_t)); memset(tvga, 0, sizeof(tvga_t)); - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tvga); - - tvga->vram_size = device_get_config_int("memory") << 10; - tvga->vram_mask = tvga->vram_size - 1; + if (info->local == TVGA9000B_ID) { + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tvga9000); + tvga->vram_size = 512 << 10; + } else { + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tvga8900); + tvga->vram_size = device_get_config_int("memory") << 10; + } + + tvga->vram_mask = tvga->vram_size - 1; tvga->card_id = info->local; - + switch (info->local) { case TVGA8900B_ID: @@ -320,21 +381,25 @@ static void *tvga_init(const device_t *info) case TVGA8900CLD_ID: bios_fn = ROM_TVGA_8900CLD; break; + case TVGA9000B_ID: + bios_fn = ROM_TVGA_9000B; + break; default: free(tvga); return NULL; } - - rom_init(&tvga->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + + rom_init(&tvga->bios_rom, (char *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + svga_init(info, &tvga->svga, tvga, tvga->vram_size, tvga_recalctimings, tvga_in, tvga_out, NULL, NULL); - tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); - + if (info->local != TVGA9000B_ID) + tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); + io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga); return tvga; @@ -350,19 +415,24 @@ static int tvga8900d_available(void) return rom_present(ROM_TVGA_8900CLD); } +static int tvga9000b_available(void) +{ + return rom_present(ROM_TVGA_9000B); +} + void tvga_close(void *p) { tvga_t *tvga = (tvga_t *)p; - + svga_close(&tvga->svga); - + free(tvga); } void tvga_speed_changed(void *p) { tvga_t *tvga = (tvga_t *)p; - + svga_recalctimings(&tvga->svga); } @@ -373,55 +443,76 @@ void tvga_force_redraw(void *p) tvga->svga.fullchange = changeframecount; } -static const device_config_t tvga_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 1024, - { - { - "256 kB", 256 - }, - { - "512 kB", 512 - }, - { - "1 MB", 1024 - }, - /*Chip supports 2mb, but drivers are buggy*/ - { - "" - } - } - }, - { - "", "", -1 +static const device_config_t tvga_config[] = { +// clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + /*Chip supports 2mb, but drivers are buggy*/ + { + .description = "" + } } + }, + { + .type = CONFIG_END + } +// clang-format off }; -const device_t tvga8900b_device = -{ - "Trident TVGA 8900B", - DEVICE_ISA, - TVGA8900B_ID, - tvga_init, - tvga_close, - NULL, - tvga8900b_available, - tvga_speed_changed, - tvga_force_redraw, - tvga_config +const device_t tvga8900b_device = { + .name = "Trident TVGA 8900B", + .internal_name = "tvga8900b", + .flags = DEVICE_ISA, + .local = TVGA8900B_ID, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + { .available = tvga8900b_available }, + .speed_changed = tvga_speed_changed, + .force_redraw = tvga_force_redraw, + .config = tvga_config }; -const device_t tvga8900d_device = -{ - "Trident TVGA 8900D", - DEVICE_ISA, - TVGA8900CLD_ID, - tvga_init, - tvga_close, - NULL, - tvga8900d_available, - tvga_speed_changed, - tvga_force_redraw, - tvga_config +const device_t tvga8900d_device = { + .name = "Trident TVGA 8900D", + .internal_name = "tvga8900d", + .flags = DEVICE_ISA, + .local = TVGA8900CLD_ID, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + { .available = tvga8900d_available }, + .speed_changed = tvga_speed_changed, + .force_redraw = tvga_force_redraw, + .config = tvga_config +}; + +const device_t tvga9000b_device = { + .name = "Trident TVGA 9000B", + .internal_name = "tvga9000b", + .flags = DEVICE_ISA, + .local = TVGA9000B_ID, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + { .available = tvga9000b_available }, + .speed_changed = tvga_speed_changed, + .force_redraw = tvga_force_redraw, + .config = NULL }; diff --git a/src/video/vid_tvp3026_ramdac.c b/src/video/vid_tvp3026_ramdac.c new file mode 100644 index 000000000..580e96990 --- /dev/null +++ b/src/video/vid_tvp3026_ramdac.c @@ -0,0 +1,605 @@ +/* + * 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 the Texas Instruments TVP3026 true colour RAMDAC + * family. + * + * + * TODO: Clock and other parts. + * + * Authors: TheCollector1995, + * + * Copyright 2021 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> + + +typedef struct +{ + PALETTE extpal; + uint32_t extpallook[256]; + uint8_t cursor64_data[1024]; + int hwc_y, hwc_x; + uint8_t ind_idx; + uint8_t dcc, dc_init; + uint8_t ccr; + uint8_t true_color; + uint8_t latch_cntl; + uint8_t mcr; + uint8_t ppr; + uint8_t general_cntl; + uint8_t mclk; + uint8_t misc; + uint8_t type; + uint8_t mode; + uint8_t pll_addr; + uint8_t clock_sel; + struct + { + uint8_t m, n, p; + } pix, mem, loop; +} tvp3026_ramdac_t; + +static void +tvp3026_set_bpp(tvp3026_ramdac_t *ramdac, svga_t *svga) +{ + if ((ramdac->true_color & 0x80) == 0x80) { + if (ramdac->mcr & 0x08) + svga->bpp = 8; + else + svga->bpp = 4; + } else { + switch (ramdac->true_color & 0x0f) { + case 0x01: + case 0x03: + case 0x05: + svga->bpp = 16; + break; + case 0x04: + svga->bpp = 15; + break; + case 0x06: + case 0x07: + if (ramdac->true_color & 0x10) + svga->bpp = 24; + else + svga->bpp = 32; + break; + case 0x0e: + case 0x0f: + svga->bpp = 24; + break; + } + } + svga_recalctimings(svga); +} + + +void +tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t *svga) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) p; + uint32_t o32; + uint8_t *cd; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + ramdac->ind_idx = val; + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + case 0x03: + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + if (svga->dac_status) + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + svga_out(addr, val, svga); + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + index = svga->dac_addr & 3; + ramdac->extpal[index].r = svga->dac_r; + ramdac->extpal[index].g = svga->dac_g; + ramdac->extpal[index].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b); + else + ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]); + + if (svga->ext_overscan && !index) { + o32 = svga->overscan_color; + svga->overscan_color = ramdac->extpallook[0]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + svga->dac_pos = 0; + break; + } + break; + case 0x09: /* Direct Cursor Control (RS value = 1001) */ + ramdac->dcc = val; + if (ramdac->ccr & 0x80) { + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + svga->dac_hwcursor.ena = !!(val & 0x03); + ramdac->mode = val & 0x03; + } + break; + case 0x0a: /* Indexed Data (RS value = 1010) */ + switch (ramdac->ind_idx) { + case 0x06: /* Indirect Cursor Control */ + ramdac->ccr = val; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + svga->dac_hwcursor.ena = !!(val & 0x03); + ramdac->mode = val & 0x03; + break; + case 0x0f: /* Latch Control */ + ramdac->latch_cntl = val; + break; + case 0x18: /* True Color Control */ + ramdac->true_color = val; + tvp3026_set_bpp(ramdac, svga); + break; + case 0x19: /* Multiplex Control */ + ramdac->mcr = val; + tvp3026_set_bpp(ramdac, svga); + break; + case 0x1a: /* Clock Selection */ + ramdac->clock_sel = val; + break; + case 0x1c: /* Palette-Page Register */ + ramdac->ppr = val; + break; + case 0x1d: /* General Control Register */ + ramdac->general_cntl = val; + break; + case 0x1e: /* Miscellaneous Control */ + ramdac->misc = val; + svga->ramdac_type = (val & 0x08) ? RAMDAC_8BIT : RAMDAC_6BIT; + break; + case 0x2c: /* PLL Address */ + ramdac->pll_addr = val; + break; + case 0x2d: /* Pixel clock PLL data */ + switch (ramdac->pll_addr & 3) { + case 0: + ramdac->pix.n = val; + break; + case 1: + ramdac->pix.m = val; + break; + case 2: + ramdac->pix.p = val; + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 1) & 3) | (ramdac->pll_addr & 0xfc); + break; + case 0x2e: /* Memory Clock PLL Data */ + switch ((ramdac->pll_addr >> 2) & 3) { + case 0: + ramdac->mem.n = val; + break; + case 1: + ramdac->mem.m = val; + break; + case 2: + ramdac->mem.p = val; + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 4) & 0x0c) | (ramdac->pll_addr & 0xf3); + break; + case 0x2f: /* Loop Clock PLL Data */ + switch ((ramdac->pll_addr >> 4) & 3) { + case 0: + ramdac->loop.n = val; + break; + case 1: + ramdac->loop.m = val; + break; + case 2: + ramdac->loop.p = val; + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 0x10) & 0x30) | (ramdac->pll_addr & 0xcf); + break; + case 0x39: /* MCLK/Loop Clock Control */ + ramdac->mclk = val; + break; + + } + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + index = svga->dac_addr & da_mask; + cd = (uint8_t *) ramdac->cursor64_data; + cd[index] = val; + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + break; + } + + return; +} + + +uint8_t +tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) p; + uint8_t temp = 0xff; + uint8_t *cd; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + temp = svga->dac_addr & 0xff; + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + index = (svga->dac_addr - 1) & 3; + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].r; + else + temp = ramdac->extpal[index].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].g; + else + temp = ramdac->extpal[index].g & 0x3f; + break; + case 2: + svga->dac_pos=0; + svga->dac_addr = svga->dac_addr + 1; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].b; + else + temp = ramdac->extpal[index].b & 0x3f; + break; + } + break; + case 0x09: /* Direct Cursor Control (RS value = 1001) */ + temp = ramdac->dcc; + break; + case 0x0a: /* Indexed Data (RS value = 1010) */ + switch (ramdac->ind_idx) { + case 0x01: /* Silicon Revision */ + temp = 0x00; + break; + case 0x06: /* Indirect Cursor Control */ + temp = ramdac->ccr; + break; + case 0x0f: /* Latch Control */ + temp = ramdac->latch_cntl; + break; + case 0x18: /* True Color Control */ + temp = ramdac->true_color; + break; + case 0x19: /* Multiplex Control */ + temp = ramdac->mcr; + break; + case 0x1a: /* Clock Selection */ + temp = ramdac->clock_sel; + break; + case 0x1c: /* Palette-Page Register */ + temp = ramdac->ppr; + break; + case 0x1d: /* General Control Register */ + temp = ramdac->general_cntl; + break; + case 0x1e: /* Miscellaneous Control */ + temp = ramdac->misc; + break; + case 0x2c: /* PLL Address */ + temp = ramdac->pll_addr; + break; + case 0x2d: /* Pixel clock PLL data */ + switch (ramdac->pll_addr & 3) { + case 0: + temp = ramdac->pix.n; + break; + case 1: + temp = ramdac->pix.m; + break; + case 2: + temp = ramdac->pix.p; + break; + case 3: + temp = 0x40; /*PLL locked to frequency*/ + break; + } + break; + case 0x2e: /* Memory Clock PLL Data */ + switch ((ramdac->pll_addr >> 2) & 3) { + case 0: + temp = ramdac->mem.n; + break; + case 1: + temp = ramdac->mem.m; + break; + case 2: + temp = ramdac->mem.p; + break; + case 3: + temp = 0x40; /*PLL locked to frequency*/ + break; + } + break; + case 0x2f: /* Loop Clock PLL Data */ + switch ((ramdac->pll_addr >> 4) & 3) { + case 0: + temp = ramdac->loop.n; + break; + case 1: + temp = ramdac->loop.m; + break; + case 2: + temp = ramdac->loop.p; + break; + } + break; + case 0x39: /* MCLK/Loop Clock Control */ + temp = ramdac->mclk; + break; + case 0x3f: /* ID */ + temp = 0x26; + break; + } + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + index = (svga->dac_addr - 1) & da_mask; + cd = (uint8_t *) ramdac->cursor64_data; + temp = cd[index]; + + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + temp = ramdac->hwc_x & 0xff; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + temp = (ramdac->hwc_x >> 8) & 0xff; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + temp = ramdac->hwc_y & 0xff; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + temp = (ramdac->hwc_y >> 8) & 0xff; + break; + } + + return temp; +} + +void +tvp3026_recalctimings(void *p, svga_t *svga) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) p; + + svga->interlace = (ramdac->ccr & 0x40); +} + + +void +tvp3026_hwcursor_draw(svga_t *svga, int displine) +{ + int x, xx, comb, b0, b1; + uint16_t dat[2]; + int offset = svga->dac_hwcursor_latch.x + svga->dac_hwcursor_latch.xoff; + int pitch, bppl, mode, x_pos, y_pos; + uint32_t clr1, clr2, clr3, *p; + uint8_t *cd; + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) svga->ramdac; + + clr1 = ramdac->extpallook[1]; + clr2 = ramdac->extpallook[2]; + clr3 = ramdac->extpallook[3]; + + /* The planes come in two parts, and each plane is 1bpp, + so a 32x32 cursor has 4 bytes per line, and a 64x64 + cursor has 8 bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */ + /* A 32x32 cursor has 128 bytes per line, and a 64x64 + cursor has 512 bytes per line. */ + bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */ + mode = ramdac->mode; + + if (svga->interlace && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; + + cd = (uint8_t *) ramdac->cursor64_data; + + for (x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) { + dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | + cd[svga->dac_hwcursor_latch.addr + 1]; + dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | + cd[svga->dac_hwcursor_latch.addr + bppl + 1]; + + for (xx = 0; xx < 16; xx++) { + b0 = (dat[0] >> (15 - xx)) & 1; + b1 = (dat[1] >> (15 - xx)) & 1; + comb = (b0 | (b1 << 1)); + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + if (offset >= svga->dac_hwcursor_latch.x) { + switch (mode) { + case 1: /* Three Color */ + switch (comb) { + case 1: + p[x_pos] = clr1; + break; + case 2: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] = clr3; + break; + } + break; + case 2: /* XGA */ + switch (comb) { + case 0: + p[x_pos] = clr1; + break; + case 1: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] ^= 0xffffff; + break; + } + break; + case 3: /* X-Windows */ + switch (comb) { + case 2: + p[x_pos] = clr1; + break; + case 3: + p[x_pos] = clr2; + break; + } + break; + } + } + offset++; + } + svga->dac_hwcursor_latch.addr += 2; + } + + if (svga->interlace && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; +} + + +float +tvp3026_getclock(int clock, void *p) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) p; + int n, m, pl; + float f_vco, f_pll; + + if (clock == 0) + return 25175000.0; + if (clock == 1) + return 28322000.0; + +/*Fvco = 8 x Fref x (65 - M) / (65 - N)*/ +/*Fpll = Fvco / 2^P*/ + n = ramdac->pix.n & 0x3f; + m = ramdac->pix.m & 0x3f; + pl = ramdac->pix.p & 0x03; + f_vco = 8.0 * 14318184 * (float)(65 - m) / (float)(65 - n); + f_pll = f_vco / (float)(1 << pl); + + return f_pll; +} + +void * +tvp3026_ramdac_init(const device_t *info) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) malloc(sizeof(tvp3026_ramdac_t)); + memset(ramdac, 0, sizeof(tvp3026_ramdac_t)); + + ramdac->type = info->local; + + ramdac->latch_cntl = 0x06; + ramdac->true_color = 0x80; + ramdac->mcr = 0x98; + ramdac->clock_sel = 0x07; + ramdac->mclk = 0x18; + + return ramdac; +} + + +static void +tvp3026_ramdac_close(void *priv) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + +const device_t tvp3026_ramdac_device = { + .name = "TI TVP3026 RAMDAC", + .internal_name = "tvp3026_ramdac", + .flags = 0, + .local = 0, + .init = tvp3026_ramdac_init, + .close = tvp3026_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 4411be1b6..6dd81416f 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -29,16 +29,9 @@ #include <86box/timer.h> #include <86box/video.h> #include <86box/vid_svga.h> +#include <86box/vid_vga.h> -typedef struct vga_t -{ - svga_t svga; - - rom_t bios_rom; -} vga_t; - -static video_timings_t timing_vga = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; static video_timings_t timing_ps1_svga_isa = {VIDEO_ISA, 6, 8, 16, 6, 8, 16}; static video_timings_t timing_ps1_svga_mca = {VIDEO_MCA, 6, 8, 16, 6, 8, 16}; @@ -48,7 +41,7 @@ void vga_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &vga->svga; uint8_t old; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) @@ -69,8 +62,13 @@ void vga_out(uint16_t addr, uint8_t val, void *p) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } } } break; @@ -84,9 +82,9 @@ uint8_t vga_in(uint16_t addr, void *p) svga_t *svga = &vga->svga; uint8_t temp; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; - + switch (addr) { case 0x3D4: @@ -111,7 +109,7 @@ static void *vga_init(const device_t *info) vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); - rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + rom_init(&vga->bios_rom, "roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga); @@ -125,7 +123,7 @@ static void *vga_init(const device_t *info) vga->svga.bpp = 8; vga->svga.miscout = 1; - + return vga; } @@ -135,7 +133,7 @@ void *ps1vga_init(const device_t *info) { vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); - + if (info->flags & DEVICE_MCA) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_mca); else @@ -151,13 +149,13 @@ void *ps1vga_init(const device_t *info) vga->svga.bpp = 8; vga->svga.miscout = 1; - + return vga; } static int vga_available(void) { - return rom_present(L"roms/video/vga/ibm_vga.bin"); + return rom_present("roms/video/vga/ibm_vga.bin"); } void vga_close(void *p) @@ -165,14 +163,14 @@ void vga_close(void *p) vga_t *vga = (vga_t *)p; svga_close(&vga->svga); - + free(vga); } void vga_speed_changed(void *p) { vga_t *vga = (vga_t *)p; - + svga_recalctimings(&vga->svga); } @@ -183,44 +181,44 @@ void vga_force_redraw(void *p) vga->svga.fullchange = changeframecount; } -const device_t vga_device = -{ - "VGA", - DEVICE_ISA, - 0, - vga_init, - vga_close, - NULL, - vga_available, - vga_speed_changed, - vga_force_redraw, - NULL +const device_t vga_device = { + .name = "VGA", + .internal_name = "vga", + .flags = DEVICE_ISA, + .local = 0, + .init = vga_init, + .close = vga_close, + .reset = NULL, + { .available = vga_available }, + .speed_changed = vga_speed_changed, + .force_redraw = vga_force_redraw, + .config = NULL }; -const device_t ps1vga_device = -{ - "PS/1 VGA", - DEVICE_ISA, - 0, - ps1vga_init, - vga_close, - NULL, - vga_available, - vga_speed_changed, - vga_force_redraw, - NULL +const device_t ps1vga_device = { + .name = "PS/1 VGA", + .internal_name = "ps1vga", + .flags = DEVICE_ISA, + .local = 0, + .init = ps1vga_init, + .close = vga_close, + .reset = NULL, + { .available = vga_available }, + .speed_changed = vga_speed_changed, + .force_redraw = vga_force_redraw, + .config = NULL }; -const device_t ps1vga_mca_device = -{ - "PS/1 VGA", - DEVICE_MCA, - 0, - ps1vga_init, - vga_close, - NULL, - vga_available, - vga_speed_changed, - vga_force_redraw, - NULL +const device_t ps1vga_mca_device = { + .name = "PS/1 VGA", + .internal_name = "ps1vga_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = ps1vga_init, + .close = vga_close, + .reset = NULL, + { .available = vga_available }, + .speed_changed = vga_speed_changed, + .force_redraw = vga_force_redraw, + .config = NULL }; diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index fbac9453c..df3d59076 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -6,14 +6,14 @@ * * This file is part of the 86Box distribution. * - * Emulation of the 3DFX Voodoo Graphics controller. + * Voodoo Graphics, 2, Banshee, 3 emulation. * * * * Authors: Sarah Walker, * leilei * - * Copyright 2008-2018 Sarah Walker. + * Copyright 2008-2020 Sarah Walker. */ #include #include @@ -32,1016 +32,23 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/plat.h> +#include <86box/thread.h> #include <86box/video.h> #include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_blitter.h> +#include <86box/vid_voodoo_display.h> #include <86box/vid_voodoo_dither.h> +#include <86box/vid_voodoo_fb.h> +#include <86box/vid_voodoo_fifo.h> +#include <86box/vid_voodoo_reg.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_texture.h> -#ifdef CLAMP -#undef CLAMP -#endif +rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; -#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) -#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) - -#define LOD_MAX 8 - -#define TEX_DIRTY_SHIFT 10 - -#define TEX_CACHE_MAX 64 - -enum -{ - VOODOO_1 = 0, - VOODOO_SB50 = 1, - VOODOO_2 = 2 -}; - -static uint32_t texture_offset[LOD_MAX+3] = -{ - 0, - 256*256, - 256*256 + 128*128, - 256*256 + 128*128 + 64*64, - 256*256 + 128*128 + 64*64 + 32*32, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1 -}; - -static int tris = 0; - -typedef union { - uint32_t i; - float f; -} int_float; - -typedef struct { - uint8_t b, g, r; - uint8_t pad; -} rgbp_t; -typedef struct { - uint8_t b, g, r, a; -} rgba8_t; - -typedef union { - struct { - uint8_t b, g, r, a; - } rgba; - uint32_t u; -} rgba_u; - -#define FIFO_SIZE 65536 -#define FIFO_MASK (FIFO_SIZE - 1) -#define FIFO_ENTRY_SIZE (1 << 31) - -#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx) -#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE-4) -#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) - -#define FIFO_TYPE 0xff000000 -#define FIFO_ADDR 0x00ffffff - -enum -{ - FIFO_INVALID = (0x00 << 24), - FIFO_WRITEL_REG = (0x01 << 24), - FIFO_WRITEW_FB = (0x02 << 24), - FIFO_WRITEL_FB = (0x03 << 24), - FIFO_WRITEL_TEX = (0x04 << 24) -}; - -#define PARAM_SIZE 1024 -#define PARAM_MASK (PARAM_SIZE - 1) -#define PARAM_ENTRY_SIZE (1 << 31) - -#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0]) -#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1]) -#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE) -#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE) -#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx) -#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx) - -typedef struct -{ - uint32_t addr_type; - uint32_t val; -} fifo_entry_t; - -static rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; - -typedef struct voodoo_params_t -{ - int command; - - int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; - - uint32_t startR, startG, startB, startZ, startA; - - int32_t dBdX, dGdX, dRdX, dAdX, dZdX; - - int32_t dBdY, dGdY, dRdY, dAdY, dZdY; - - int64_t startW, dWdX, dWdY; - - struct - { - int64_t startS, startT, startW, p1; - int64_t dSdX, dTdX, dWdX, p2; - int64_t dSdY, dTdY, dWdY, p3; - } tmu[2]; - - uint32_t color0, color1; - - uint32_t fbzMode; - uint32_t fbzColorPath; - - uint32_t fogMode; - rgbp_t fogColor; - struct - { - uint8_t fog, dfog; - } fogTable[64]; - - uint32_t alphaMode; - - uint32_t zaColor; - - int chromaKey_r, chromaKey_g, chromaKey_b; - uint32_t chromaKey; - - uint32_t textureMode[2]; - uint32_t tLOD[2]; - - uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; - - uint32_t tex_base[2][LOD_MAX+2]; - uint32_t tex_end[2][LOD_MAX+2]; - int tex_width[2]; - int tex_w_mask[2][LOD_MAX+2]; - int tex_w_nmask[2][LOD_MAX+2]; - int tex_h_mask[2][LOD_MAX+2]; - int tex_shift[2][LOD_MAX+2]; - int tex_lod[2][LOD_MAX+2]; - int tex_entry[2]; - int detail_max[2], detail_bias[2], detail_scale[2]; - - uint32_t draw_offset, aux_offset; - - int tformat[2]; - - int clipLeft, clipRight, clipLowY, clipHighY; - - int sign; - - uint32_t front_offset; - - uint32_t swapbufferCMD; - - uint32_t stipple; -} voodoo_params_t; - -typedef struct texture_t -{ - uint32_t base; - uint32_t tLOD; - volatile int refcount, refcount_r[2]; - int is16; - uint32_t palette_checksum; - uint32_t addr_start[4], addr_end[4]; - uint32_t *data; -} texture_t; - -typedef struct vert_t -{ - float sVx, sVy; - float sRed, sGreen, sBlue, sAlpha; - float sVz, sWb; - float sW0, sS0, sT0; - float sW1, sS1, sT1; -} vert_t; - -typedef struct voodoo_t -{ - mem_mapping_t mapping; - - int pci_enable; - - uint8_t dac_data[8]; - int dac_reg, dac_reg_ff; - uint8_t dac_readdata; - uint16_t dac_pll_regs[16]; - - float pixel_clock; - uint64_t line_time; - - voodoo_params_t params; - - uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; - uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/ - - uint32_t initEnable; - - uint32_t lfbMode; - - uint32_t memBaseAddr; - - int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy; - - uint32_t front_offset, back_offset; - - uint32_t fb_read_offset, fb_write_offset; - - int row_width; - int block_width; - - uint8_t *fb_mem, *tex_mem[2]; - uint16_t *tex_mem_w[2]; - - int rgb_sel; - - uint32_t trexInit1[2]; - - uint32_t tmuConfig; - - int swap_count; - - int disp_buffer, draw_buffer; - pc_timer_t timer; - - int line; - svga_t *svga; - - uint32_t backPorch; - uint32_t videoDimensions; - uint32_t hSync, vSync; - - int h_total, v_total, v_disp; - int h_disp; - int v_retrace; - - struct - { - uint32_t y[4], i[4], q[4]; - } nccTable[2][2]; - - rgba_u palette[2][256]; - - rgba_u ncc_lookup[2][2][256]; - int ncc_dirty[2]; - - thread_t *fifo_thread; - thread_t *render_thread[2]; - event_t *wake_fifo_thread; - event_t *wake_main_thread; - event_t *fifo_not_full_event; - event_t *render_not_full_event[2]; - event_t *wake_render_thread[2]; - - int voodoo_busy; - int render_voodoo_busy[2]; - - int render_threads; - int odd_even_mask; - - int pixel_count[2], texel_count[2], tri_count, frame_count; - int pixel_count_old[2], texel_count_old[2]; - int wr_count, rd_count, tex_count; - - int retrace_count; - int swap_interval; - uint32_t swap_offset; - int swap_pending; - - int bilinear_enabled; - - int fb_size; - uint32_t fb_mask; - - int texture_size; - uint32_t texture_mask; - - int dual_tmus; - int type; - - fifo_entry_t fifo[FIFO_SIZE]; - volatile int fifo_read_idx, fifo_write_idx; - volatile int cmd_read, cmd_written, cmd_written_fifo; - - voodoo_params_t params_buffer[PARAM_SIZE]; - volatile int params_read_idx[2], params_write_idx; - - uint32_t cmdfifo_base, cmdfifo_end; - int cmdfifo_rp; - volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; - uint32_t cmdfifo_amin, cmdfifo_amax; - - uint32_t sSetupMode; - vert_t verts[4]; - int vertex_num; - int num_verticies; - - int flush; - - int scrfilter; - int scrfilterEnabled; - int scrfilterThreshold; - int scrfilterThresholdOld; - - uint32_t last_write_addr; - - uint32_t fbiPixelsIn; - uint32_t fbiChromaFail; - uint32_t fbiZFuncFail; - uint32_t fbiAFuncFail; - uint32_t fbiPixelsOut; - - uint32_t bltSrcBaseAddr; - uint32_t bltDstBaseAddr; - int bltSrcXYStride, bltDstXYStride; - uint32_t bltSrcChromaRange, bltDstChromaRange; - int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB; - int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB; - int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB; - int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB; - - int bltClipRight, bltClipLeft; - int bltClipHighY, bltClipLowY; - - int bltSrcX, bltSrcY; - int bltDstX, bltDstY; - int bltSizeX, bltSizeY; - int bltRop[4]; - uint16_t bltColorFg, bltColorBg; - - uint32_t bltCommand; - - struct - { - int dst_x, dst_y; - int cur_x; - int size_x, size_y; - int x_dir, y_dir; - int dst_stride; - } blt; - - rgbp_t clutData[64]; - int clutData_dirty; - rgbp_t clutData256[256]; - uint32_t video_16to32[0x10000]; - - uint8_t dirty_line[1024]; - int dirty_line_low, dirty_line_high; - - int fb_write_buffer, fb_draw_buffer; - int buffer_cutoff; - - int read_time, write_time, burst_time; - - pc_timer_t wake_timer; - - uint8_t thefilter[256][256]; // pixel filter, feeding from one or two - uint8_t thefilterg[256][256]; // for green - uint8_t thefilterb[256][256]; // for blue - - /* the voodoo adds purple lines for some reason */ - uint16_t purpleline[256][3]; - - texture_t texture_cache[2][TEX_CACHE_MAX]; - uint8_t texture_present[2][4096]; - int texture_last_removed; - - uint32_t palette_checksum[2]; - int palette_dirty[2]; - - uint64_t time; - int render_time[2]; - - int use_recompiler; - void *codegen_data; - - struct voodoo_set_t *set; -} voodoo_t; - -typedef struct voodoo_set_t -{ - voodoo_t *voodoos[2]; - - mem_mapping_t snoop_mapping; - - int nr_cards; -} voodoo_set_t; - -static inline void wait_for_render_thread_idle(voodoo_t *voodoo); - -enum -{ - SST_status = 0x000, - SST_intrCtrl = 0x004, - - SST_vertexAx = 0x008, - SST_vertexAy = 0x00c, - SST_vertexBx = 0x010, - SST_vertexBy = 0x014, - SST_vertexCx = 0x018, - SST_vertexCy = 0x01c, - - SST_startR = 0x0020, - SST_startG = 0x0024, - SST_startB = 0x0028, - SST_startZ = 0x002c, - SST_startA = 0x0030, - SST_startS = 0x0034, - SST_startT = 0x0038, - SST_startW = 0x003c, - - SST_dRdX = 0x0040, - SST_dGdX = 0x0044, - SST_dBdX = 0x0048, - SST_dZdX = 0x004c, - SST_dAdX = 0x0050, - SST_dSdX = 0x0054, - SST_dTdX = 0x0058, - SST_dWdX = 0x005c, - - SST_dRdY = 0x0060, - SST_dGdY = 0x0064, - SST_dBdY = 0x0068, - SST_dZdY = 0x006c, - SST_dAdY = 0x0070, - SST_dSdY = 0x0074, - SST_dTdY = 0x0078, - SST_dWdY = 0x007c, - - SST_triangleCMD = 0x0080, - - SST_fvertexAx = 0x088, - SST_fvertexAy = 0x08c, - SST_fvertexBx = 0x090, - SST_fvertexBy = 0x094, - SST_fvertexCx = 0x098, - SST_fvertexCy = 0x09c, - - SST_fstartR = 0x00a0, - SST_fstartG = 0x00a4, - SST_fstartB = 0x00a8, - SST_fstartZ = 0x00ac, - SST_fstartA = 0x00b0, - SST_fstartS = 0x00b4, - SST_fstartT = 0x00b8, - SST_fstartW = 0x00bc, - - SST_fdRdX = 0x00c0, - SST_fdGdX = 0x00c4, - SST_fdBdX = 0x00c8, - SST_fdZdX = 0x00cc, - SST_fdAdX = 0x00d0, - SST_fdSdX = 0x00d4, - SST_fdTdX = 0x00d8, - SST_fdWdX = 0x00dc, - - SST_fdRdY = 0x00e0, - SST_fdGdY = 0x00e4, - SST_fdBdY = 0x00e8, - SST_fdZdY = 0x00ec, - SST_fdAdY = 0x00f0, - SST_fdSdY = 0x00f4, - SST_fdTdY = 0x00f8, - SST_fdWdY = 0x00fc, - - SST_ftriangleCMD = 0x0100, - - SST_fbzColorPath = 0x104, - SST_fogMode = 0x108, - - SST_alphaMode = 0x10c, - SST_fbzMode = 0x110, - SST_lfbMode = 0x114, - - SST_clipLeftRight = 0x118, - SST_clipLowYHighY = 0x11c, - - SST_nopCMD = 0x120, - SST_fastfillCMD = 0x124, - SST_swapbufferCMD = 0x128, - - SST_fogColor = 0x12c, - SST_zaColor = 0x130, - SST_chromaKey = 0x134, - - SST_userIntrCMD = 0x13c, - SST_stipple = 0x140, - SST_color0 = 0x144, - SST_color1 = 0x148, - - SST_fbiPixelsIn = 0x14c, - SST_fbiChromaFail = 0x150, - SST_fbiZFuncFail = 0x154, - SST_fbiAFuncFail = 0x158, - SST_fbiPixelsOut = 0x15c, - - SST_fogTable00 = 0x160, - SST_fogTable01 = 0x164, - SST_fogTable02 = 0x168, - SST_fogTable03 = 0x16c, - SST_fogTable04 = 0x170, - SST_fogTable05 = 0x174, - SST_fogTable06 = 0x178, - SST_fogTable07 = 0x17c, - SST_fogTable08 = 0x180, - SST_fogTable09 = 0x184, - SST_fogTable0a = 0x188, - SST_fogTable0b = 0x18c, - SST_fogTable0c = 0x190, - SST_fogTable0d = 0x194, - SST_fogTable0e = 0x198, - SST_fogTable0f = 0x19c, - SST_fogTable10 = 0x1a0, - SST_fogTable11 = 0x1a4, - SST_fogTable12 = 0x1a8, - SST_fogTable13 = 0x1ac, - SST_fogTable14 = 0x1b0, - SST_fogTable15 = 0x1b4, - SST_fogTable16 = 0x1b8, - SST_fogTable17 = 0x1bc, - SST_fogTable18 = 0x1c0, - SST_fogTable19 = 0x1c4, - SST_fogTable1a = 0x1c8, - SST_fogTable1b = 0x1cc, - SST_fogTable1c = 0x1d0, - SST_fogTable1d = 0x1d4, - SST_fogTable1e = 0x1d8, - SST_fogTable1f = 0x1dc, - - SST_cmdFifoBaseAddr = 0x1e0, - SST_cmdFifoBump = 0x1e4, - SST_cmdFifoRdPtr = 0x1e8, - SST_cmdFifoAMin = 0x1ec, - SST_cmdFifoAMax = 0x1f0, - SST_cmdFifoDepth = 0x1f4, - SST_cmdFifoHoles = 0x1f8, - - SST_fbiInit4 = 0x200, - SST_vRetrace = 0x204, - SST_backPorch = 0x208, - SST_videoDimensions = 0x20c, - SST_fbiInit0 = 0x210, - SST_fbiInit1 = 0x214, - SST_fbiInit2 = 0x218, - SST_fbiInit3 = 0x21c, - SST_hSync = 0x220, - SST_vSync = 0x224, - SST_clutData = 0x228, - SST_dacData = 0x22c, - - SST_scrFilter = 0x230, - - SST_hvRetrace = 0x240, - SST_fbiInit5 = 0x244, - SST_fbiInit6 = 0x248, - SST_fbiInit7 = 0x24c, - - SST_sSetupMode = 0x260, - SST_sVx = 0x264, - SST_sVy = 0x268, - SST_sARGB = 0x26c, - SST_sRed = 0x270, - SST_sGreen = 0x274, - SST_sBlue = 0x278, - SST_sAlpha = 0x27c, - SST_sVz = 0x280, - SST_sWb = 0x284, - SST_sW0 = 0x288, - SST_sS0 = 0x28c, - SST_sT0 = 0x290, - SST_sW1 = 0x294, - SST_sS1 = 0x298, - SST_sT1 = 0x29c, - - SST_sDrawTriCMD = 0x2a0, - SST_sBeginTriCMD = 0x2a4, - - SST_bltSrcBaseAddr = 0x2c0, - SST_bltDstBaseAddr = 0x2c4, - SST_bltXYStrides = 0x2c8, - SST_bltSrcChromaRange = 0x2cc, - SST_bltDstChromaRange = 0x2d0, - SST_bltClipX = 0x2d4, - SST_bltClipY = 0x2d8, - - SST_bltSrcXY = 0x2e0, - SST_bltDstXY = 0x2e4, - SST_bltSize = 0x2e8, - SST_bltRop = 0x2ec, - SST_bltColor = 0x2f0, - - SST_bltCommand = 0x2f8, - SST_bltData = 0x2fc, - - SST_textureMode = 0x300, - SST_tLOD = 0x304, - SST_tDetail = 0x308, - SST_texBaseAddr = 0x30c, - SST_texBaseAddr1 = 0x310, - SST_texBaseAddr2 = 0x314, - SST_texBaseAddr38 = 0x318, - - SST_trexInit1 = 0x320, - - SST_nccTable0_Y0 = 0x324, - SST_nccTable0_Y1 = 0x328, - SST_nccTable0_Y2 = 0x32c, - SST_nccTable0_Y3 = 0x330, - SST_nccTable0_I0 = 0x334, - SST_nccTable0_I1 = 0x338, - SST_nccTable0_I2 = 0x33c, - SST_nccTable0_I3 = 0x340, - SST_nccTable0_Q0 = 0x344, - SST_nccTable0_Q1 = 0x348, - SST_nccTable0_Q2 = 0x34c, - SST_nccTable0_Q3 = 0x350, - - SST_nccTable1_Y0 = 0x354, - SST_nccTable1_Y1 = 0x358, - SST_nccTable1_Y2 = 0x35c, - SST_nccTable1_Y3 = 0x360, - SST_nccTable1_I0 = 0x364, - SST_nccTable1_I1 = 0x368, - SST_nccTable1_I2 = 0x36c, - SST_nccTable1_I3 = 0x370, - SST_nccTable1_Q0 = 0x374, - SST_nccTable1_Q1 = 0x378, - SST_nccTable1_Q2 = 0x37c, - SST_nccTable1_Q3 = 0x380, - - SST_remap_status = 0x000 | 0x400, - - SST_remap_vertexAx = 0x008 | 0x400, - SST_remap_vertexAy = 0x00c | 0x400, - SST_remap_vertexBx = 0x010 | 0x400, - SST_remap_vertexBy = 0x014 | 0x400, - SST_remap_vertexCx = 0x018 | 0x400, - SST_remap_vertexCy = 0x01c | 0x400, - - SST_remap_startR = 0x0020 | 0x400, - SST_remap_startG = 0x002c | 0x400, - SST_remap_startB = 0x0038 | 0x400, - SST_remap_startZ = 0x0044 | 0x400, - SST_remap_startA = 0x0050 | 0x400, - SST_remap_startS = 0x005c | 0x400, - SST_remap_startT = 0x0068 | 0x400, - SST_remap_startW = 0x0074 | 0x400, - - SST_remap_dRdX = 0x0024 | 0x400, - SST_remap_dGdX = 0x0030 | 0x400, - SST_remap_dBdX = 0x003c | 0x400, - SST_remap_dZdX = 0x0048 | 0x400, - SST_remap_dAdX = 0x0054 | 0x400, - SST_remap_dSdX = 0x0060 | 0x400, - SST_remap_dTdX = 0x006c | 0x400, - SST_remap_dWdX = 0x0078 | 0x400, - - SST_remap_dRdY = 0x0028 | 0x400, - SST_remap_dGdY = 0x0034 | 0x400, - SST_remap_dBdY = 0x0040 | 0x400, - SST_remap_dZdY = 0x004c | 0x400, - SST_remap_dAdY = 0x0058 | 0x400, - SST_remap_dSdY = 0x0064 | 0x400, - SST_remap_dTdY = 0x0070 | 0x400, - SST_remap_dWdY = 0x007c | 0x400, - - SST_remap_triangleCMD = 0x0080 | 0x400, - - SST_remap_fvertexAx = 0x088 | 0x400, - SST_remap_fvertexAy = 0x08c | 0x400, - SST_remap_fvertexBx = 0x090 | 0x400, - SST_remap_fvertexBy = 0x094 | 0x400, - SST_remap_fvertexCx = 0x098 | 0x400, - SST_remap_fvertexCy = 0x09c | 0x400, - - SST_remap_fstartR = 0x00a0 | 0x400, - SST_remap_fstartG = 0x00ac | 0x400, - SST_remap_fstartB = 0x00b8 | 0x400, - SST_remap_fstartZ = 0x00c4 | 0x400, - SST_remap_fstartA = 0x00d0 | 0x400, - SST_remap_fstartS = 0x00dc | 0x400, - SST_remap_fstartT = 0x00e8 | 0x400, - SST_remap_fstartW = 0x00f4 | 0x400, - - SST_remap_fdRdX = 0x00a4 | 0x400, - SST_remap_fdGdX = 0x00b0 | 0x400, - SST_remap_fdBdX = 0x00bc | 0x400, - SST_remap_fdZdX = 0x00c8 | 0x400, - SST_remap_fdAdX = 0x00d4 | 0x400, - SST_remap_fdSdX = 0x00e0 | 0x400, - SST_remap_fdTdX = 0x00ec | 0x400, - SST_remap_fdWdX = 0x00f8 | 0x400, - - SST_remap_fdRdY = 0x00a8 | 0x400, - SST_remap_fdGdY = 0x00b4 | 0x400, - SST_remap_fdBdY = 0x00c0 | 0x400, - SST_remap_fdZdY = 0x00cc | 0x400, - SST_remap_fdAdY = 0x00d8 | 0x400, - SST_remap_fdSdY = 0x00e4 | 0x400, - SST_remap_fdTdY = 0x00f0 | 0x400, - SST_remap_fdWdY = 0x00fc | 0x400, -}; - -enum -{ - LFB_WRITE_FRONT = 0x0000, - LFB_WRITE_BACK = 0x0010, - LFB_WRITE_MASK = 0x0030 -}; - -enum -{ - LFB_READ_FRONT = 0x0000, - LFB_READ_BACK = 0x0040, - LFB_READ_AUX = 0x0080, - LFB_READ_MASK = 0x00c0 -}; - -enum -{ - LFB_FORMAT_RGB565 = 0, - LFB_FORMAT_RGB555 = 1, - LFB_FORMAT_ARGB1555 = 2, - LFB_FORMAT_ARGB8888 = 5, - LFB_FORMAT_DEPTH = 15, - LFB_FORMAT_MASK = 15 -}; - -enum -{ - LFB_WRITE_COLOUR = 1, - LFB_WRITE_DEPTH = 2 -}; - -enum -{ - FBZ_CHROMAKEY = (1 << 1), - FBZ_W_BUFFER = (1 << 3), - FBZ_DEPTH_ENABLE = (1 << 4), - - FBZ_DITHER = (1 << 8), - FBZ_RGB_WMASK = (1 << 9), - FBZ_DEPTH_WMASK = (1 << 10), - FBZ_DITHER_2x2 = (1 << 11), - - FBZ_DRAW_FRONT = 0x0000, - FBZ_DRAW_BACK = 0x4000, - FBZ_DRAW_MASK = 0xc000, - - FBZ_DEPTH_BIAS = (1 << 16), - - FBZ_DEPTH_SOURCE = (1 << 20), - - FBZ_PARAM_ADJUST = (1 << 26) -}; - -enum -{ - TEX_RGB332 = 0x0, - TEX_Y4I2Q2 = 0x1, - TEX_A8 = 0x2, - TEX_I8 = 0x3, - TEX_AI8 = 0x4, - TEX_PAL8 = 0x5, - TEX_APAL8 = 0x6, - TEX_ARGB8332 = 0x8, - TEX_A8Y4I2Q2 = 0x9, - TEX_R5G6B5 = 0xa, - TEX_ARGB1555 = 0xb, - TEX_ARGB4444 = 0xc, - TEX_A8I8 = 0xd, - TEX_APAL88 = 0xe -}; - -enum -{ - TEXTUREMODE_NCC_SEL = (1 << 5), - TEXTUREMODE_TCLAMPS = (1 << 6), - TEXTUREMODE_TCLAMPT = (1 << 7), - TEXTUREMODE_TRILINEAR = (1 << 30) -}; - -enum -{ - FBIINIT0_VGA_PASS = 1, - FBIINIT0_GRAPHICS_RESET = (1 << 1) -}; - -enum -{ - FBIINIT1_MULTI_SST = (1 << 2), /*Voodoo Graphics only*/ - FBIINIT1_VIDEO_RESET = (1 << 8), - FBIINIT1_SLI_ENABLE = (1 << 23) -}; - -enum -{ - FBIINIT2_SWAP_ALGORITHM_MASK = (3 << 9) -}; - -enum -{ - FBIINIT2_SWAP_ALGORITHM_DAC_VSYNC = (0 << 9), - FBIINIT2_SWAP_ALGORITHM_DAC_DATA = (1 << 9), - FBIINIT2_SWAP_ALGORITHM_PCI_FIFO_STALL = (2 << 9), - FBIINIT2_SWAP_ALGORITHM_SLI_SYNC = (3 << 9) -}; - -enum -{ - FBIINIT3_REMAP = 1 -}; - -enum -{ - FBIINIT5_MULTI_CVG = (1 << 14) -}; - -enum -{ - FBIINIT7_CMDFIFO_ENABLE = (1 << 8) -}; - -enum -{ - CC_LOCALSELECT_ITER_RGB = 0, - CC_LOCALSELECT_TEX = 1, - CC_LOCALSELECT_COLOR1 = 2, - CC_LOCALSELECT_LFB = 3 -}; - -enum -{ - CCA_LOCALSELECT_ITER_A = 0, - CCA_LOCALSELECT_COLOR0 = 1, - CCA_LOCALSELECT_ITER_Z = 2 -}; - -enum -{ - C_SEL_ITER_RGB = 0, - C_SEL_TEX = 1, - C_SEL_COLOR1 = 2, - C_SEL_LFB = 3 -}; - -enum -{ - A_SEL_ITER_A = 0, - A_SEL_TEX = 1, - A_SEL_COLOR1 = 2, - A_SEL_LFB = 3 -}; - -enum -{ - CC_MSELECT_ZERO = 0, - CC_MSELECT_CLOCAL = 1, - CC_MSELECT_AOTHER = 2, - CC_MSELECT_ALOCAL = 3, - CC_MSELECT_TEX = 4, - CC_MSELECT_TEXRGB = 5 -}; - -enum -{ - CCA_MSELECT_ZERO = 0, - CCA_MSELECT_ALOCAL = 1, - CCA_MSELECT_AOTHER = 2, - CCA_MSELECT_ALOCAL2 = 3, - CCA_MSELECT_TEX = 4 -}; - -enum -{ - TC_MSELECT_ZERO = 0, - TC_MSELECT_CLOCAL = 1, - TC_MSELECT_AOTHER = 2, - TC_MSELECT_ALOCAL = 3, - TC_MSELECT_DETAIL = 4, - TC_MSELECT_LOD_FRAC = 5 -}; - -enum -{ - TCA_MSELECT_ZERO = 0, - TCA_MSELECT_CLOCAL = 1, - TCA_MSELECT_AOTHER = 2, - TCA_MSELECT_ALOCAL = 3, - TCA_MSELECT_DETAIL = 4, - TCA_MSELECT_LOD_FRAC = 5 -}; - -enum -{ - CC_ADD_CLOCAL = 1, - CC_ADD_ALOCAL = 2 -}; - -enum -{ - CCA_ADD_CLOCAL = 1, - CCA_ADD_ALOCAL = 2 -}; - -enum -{ - AFUNC_AZERO = 0x0, - AFUNC_ASRC_ALPHA = 0x1, - AFUNC_A_COLOR = 0x2, - AFUNC_ADST_ALPHA = 0x3, - AFUNC_AONE = 0x4, - AFUNC_AOMSRC_ALPHA = 0x5, - AFUNC_AOM_COLOR = 0x6, - AFUNC_AOMDST_ALPHA = 0x7, - AFUNC_ASATURATE = 0xf -}; - -enum -{ - AFUNC_ACOLORBEFOREFOG = 0xf -}; - -enum -{ - AFUNC_NEVER = 0, - AFUNC_LESSTHAN = 1, - AFUNC_EQUAL = 2, - AFUNC_LESSTHANEQUAL = 3, - AFUNC_GREATERTHAN = 4, - AFUNC_NOTEQUAL = 5, - AFUNC_GREATERTHANEQUAL = 6, - AFUNC_ALWAYS = 7 -}; - -enum -{ - DEPTHOP_NEVER = 0, - DEPTHOP_LESSTHAN = 1, - DEPTHOP_EQUAL = 2, - DEPTHOP_LESSTHANEQUAL = 3, - DEPTHOP_GREATERTHAN = 4, - DEPTHOP_NOTEQUAL = 5, - DEPTHOP_GREATERTHANEQUAL = 6, - DEPTHOP_ALWAYS = 7 -}; - -enum -{ - FOG_ENABLE = 0x01, - FOG_ADD = 0x02, - FOG_MULT = 0x04, - FOG_ALPHA = 0x08, - FOG_Z = 0x10, - FOG_W = 0x18, - FOG_CONSTANT = 0x20 -}; - -enum -{ - LOD_ODD = (1 << 18), - LOD_SPLIT = (1 << 19), - LOD_S_IS_WIDER = (1 << 20), - LOD_TMULTIBASEADDR = (1 << 24), - LOD_TMIRROR_S = (1 << 28), - LOD_TMIRROR_T = (1 << 29) -}; -enum -{ - CMD_INVALID = 0, - CMD_DRAWTRIANGLE, - CMD_FASTFILL, - CMD_SWAPBUF -}; - -enum -{ - FBZCP_TEXTURE_ENABLED = (1 << 27) -}; - -enum -{ - BLTCMD_SRC_TILED = (1 << 14), - BLTCMD_DST_TILED = (1 << 15) -}; - -enum -{ - INITENABLE_SLI_MASTER_SLAVE = (1 << 11) -}; - -#define TEXTUREMODE_MASK 0x3ffff000 -#define TEXTUREMODE_PASSTHROUGH 0 - -#define TEXTUREMODE_LOCAL_MASK 0x00643000 -#define TEXTUREMODE_LOCAL 0x00241000 +int tris = 0; #ifdef ENABLE_VOODOO_LOG int voodoo_do_log = ENABLE_VOODOO_LOG; @@ -1063,58 +70,13 @@ voodoo_log(const char *fmt, ...) #endif -static void voodoo_threshold_check(voodoo_t *voodoo); - -static void voodoo_update_ncc(voodoo_t *voodoo, int tmu) -{ - int tbl; - - for (tbl = 0; tbl < 2; tbl++) - { - int col; - - for (col = 0; col < 256; col++) - { - int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; - int i_r, i_g, i_b; - int q_r, q_g, q_b; - - y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; - - i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff; - if (i_r & 0x100) - i_r |= 0xfffffe00; - i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff; - if (i_g & 0x100) - i_g |= 0xfffffe00; - i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff; - if (i_b & 0x100) - i_b |= 0xfffffe00; - - q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff; - if (q_r & 0x100) - q_r |= 0xfffffe00; - q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff; - if (q_g & 0x100) - q_g |= 0xfffffe00; - q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff; - if (q_b & 0x100) - q_b |= 0xfffffe00; - - voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r); - voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g); - voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b); - voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff; - } - } -} - -#define SLI_ENABLED (voodoo->fbiInit1 & FBIINIT1_SLI_ENABLE) -#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400) -static void voodoo_recalc(voodoo_t *voodoo) +void voodoo_recalc(voodoo_t *voodoo) { uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; - + + if (voodoo->type >= VOODOO_BANSHEE) + return; + voodoo->params.front_offset = voodoo->disp_buffer*buffer_offset; voodoo->back_offset = voodoo->draw_buffer*buffer_offset; @@ -1156,7 +118,7 @@ static void voodoo_recalc(voodoo_t *voodoo) default: fatal("voodoo_recalc : unknown lfb source\n"); } - + switch (voodoo->params.fbzMode & FBZ_DRAW_MASK) { case FBZ_DRAW_FRONT: @@ -1171,4805 +133,34 @@ static void voodoo_recalc(voodoo_t *voodoo) default: fatal("voodoo_recalc : unknown draw buffer\n"); } - + voodoo->block_width = ((voodoo->fbiInit1 >> 4) & 15) * 2; if (voodoo->fbiInit6 & (1 << 30)) voodoo->block_width += 1; if (voodoo->fbiInit1 & (1 << 24)) voodoo->block_width += 32; voodoo->row_width = voodoo->block_width * 32 * 2; - -/* voodoo_log("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset); - voodoo_log(" fb_read_offset %08X fb_write_offset %08X row_width %i %08x %08x\n", voodoo->fb_read_offset, voodoo->fb_write_offset, voodoo->row_width, voodoo->lfbMode, voodoo->params.fbzMode);*/ + voodoo->params.row_width = voodoo->row_width; + voodoo->aux_row_width = voodoo->row_width; + voodoo->params.aux_row_width = voodoo->aux_row_width; } -static void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) -{ - int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; - int width = 256, height = 256; - int shift = 8; - int lod; - uint32_t base = voodoo->params.texBaseAddr[tmu]; - uint32_t offset = 0; - int tex_lod = 0; - - if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER) - height >>= aspect; - else - { - width >>= aspect; - shift -= aspect; - } - - if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD)) - { - width >>= 1; - height >>= 1; - shift--; - tex_lod++; - if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) - base = voodoo->params.texBaseAddr1[tmu]; - } - - for (lod = 0; lod <= LOD_MAX+1; lod++) - { - if (!width) - width = 1; - if (!height) - height = 1; - if (shift < 0) - shift = 0; - voodoo->params.tex_base[tmu][lod] = base + offset; - if (voodoo->params.tformat[tmu] & 8) - voodoo->params.tex_end[tmu][lod] = base + offset + (width * height * 2); - else - voodoo->params.tex_end[tmu][lod] = base + offset + (width * height); - voodoo->params.tex_w_mask[tmu][lod] = width - 1; - voodoo->params.tex_w_nmask[tmu][lod] = ~(width - 1); - voodoo->params.tex_h_mask[tmu][lod] = height - 1; - voodoo->params.tex_shift[tmu][lod] = shift; - voodoo->params.tex_lod[tmu][lod] = tex_lod; - - if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) || ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) - { - if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0) - { - if (voodoo->params.tformat[tmu] & 8) - offset += width * height * 2; - else - offset += width * height; - - if (voodoo->params.tLOD[tmu] & LOD_SPLIT) - { - width >>= 2; - height >>= 2; - shift -= 2; - tex_lod += 2; - } - else - { - width >>= 1; - height >>= 1; - shift--; - tex_lod++; - } - - if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) - { - switch (tex_lod) - { - case 0: - base = voodoo->params.texBaseAddr[tmu]; - break; - case 1: - base = voodoo->params.texBaseAddr1[tmu]; - break; - case 2: - base = voodoo->params.texBaseAddr2[tmu]; - break; - default: - base = voodoo->params.texBaseAddr38[tmu]; - break; - } - } - } - } - } - - voodoo->params.tex_width[tmu] = width; -} - -#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24)) - -static void use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) -{ - int c, d; - int lod; - int lod_min, lod_max; - uint32_t addr = 0, addr_end; - uint32_t palette_checksum; - - lod_min = (params->tLOD[tmu] >> 2) & 15; - lod_max = (params->tLOD[tmu] >> 8) & 15; - - if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) - { - if (voodoo->palette_dirty[tmu]) - { - palette_checksum = 0; - - for (c = 0; c < 256; c++) - palette_checksum ^= voodoo->palette[tmu][c].u; - - voodoo->palette_checksum[tmu] = palette_checksum; - voodoo->palette_dirty[tmu] = 0; - } - else - palette_checksum = voodoo->palette_checksum[tmu]; - } - else - palette_checksum = 0; - - if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) - addr = params->texBaseAddr1[tmu]; - else - addr = params->texBaseAddr[tmu]; - - /*Try to find texture in cache*/ - for (c = 0; c < TEX_CACHE_MAX; c++) - { - if (voodoo->texture_cache[tmu][c].base == addr && - voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) && - voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum) - { - params->tex_entry[tmu] = c; - voodoo->texture_cache[tmu][c].refcount++; - return; - } - } - - /*Texture not found, search for unused texture*/ - do - { - for (c = 0; c < TEX_CACHE_MAX; c++) - { - voodoo->texture_last_removed++; - voodoo->texture_last_removed &= (TEX_CACHE_MAX-1); - if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] && - (voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1])) - break; - } - if (c == TEX_CACHE_MAX) - wait_for_render_thread_idle(voodoo); - } while (c == TEX_CACHE_MAX); - if (c == TEX_CACHE_MAX) - fatal("Texture cache full!\n"); - - c = voodoo->texture_last_removed; - - - if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) - voodoo->texture_cache[tmu][c].base = params->texBaseAddr1[tmu]; - else - voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu]; - voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff; - - lod_min = (params->tLOD[tmu] >> 2) & 15; - lod_max = (params->tLOD[tmu] >> 8) & 15; -// voodoo_log(" add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max, tmu); - - lod_min = MIN(lod_min, 8); - lod_max = MIN(lod_max, 8); - for (lod = lod_min; lod <= lod_max; lod++) - { - uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]]; - uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask; - int x, y; - int shift = 8 - params->tex_lod[tmu][lod]; - rgba_u *pal; - - //voodoo_log(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]); - - - switch (params->tformat[tmu]) - { - case TEX_RGB332: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_Y4I2Q2: - pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_A8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(dat, dat, dat, dat); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_I8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(dat, dat, dat, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_AI8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f)); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_PAL8: - pal = voodoo->palette[tmu]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_APAL8: - pal = voodoo->palette[tmu]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3); - int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2); - int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4); - int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6); - - base[x] = makergba(r, g, b, a); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_ARGB8332: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_A8Y4I2Q2: - pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_R5G6B5: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_ARGB1555: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_ARGB4444: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_A8I8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_APAL88: - pal = voodoo->palette[tmu]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - default: - fatal("Unknown texture format %i\n", params->tformat[tmu]); - } - } - - voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8; - - if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) - voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum; - else - voodoo->texture_cache[tmu][c].palette_checksum = 0; - - if (lod_min == 0) - { - voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->params.tex_base[tmu][0]; - voodoo->texture_cache[tmu][c].addr_end[0] = voodoo->params.tex_end[tmu][0]; - } - else - voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->texture_cache[tmu][c].addr_end[0] = 0; - - if (lod_min <= 1 && lod_max >= 1) - { - voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->params.tex_base[tmu][1]; - voodoo->texture_cache[tmu][c].addr_end[1] = voodoo->params.tex_end[tmu][1]; - } - else - voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->texture_cache[tmu][c].addr_end[1] = 0; - - if (lod_min <= 2 && lod_max >= 2) - { - voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->params.tex_base[tmu][2]; - voodoo->texture_cache[tmu][c].addr_end[2] = voodoo->params.tex_end[tmu][2]; - } - else - voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->texture_cache[tmu][c].addr_end[2] = 0; - - if (lod_max >= 3) - { - voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->params.tex_base[tmu][(lod_min > 3) ? lod_min : 3]; - voodoo->texture_cache[tmu][c].addr_end[3] = voodoo->params.tex_end[tmu][(lod_max < 8) ? lod_max : 8]; - } - else - voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->texture_cache[tmu][c].addr_end[3] = 0; - - - for (d = 0; d < 4; d++) - { - addr = voodoo->texture_cache[tmu][c].addr_start[d]; - addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; - - if (addr_end != 0) - { - for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) - voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; - } - } - - params->tex_entry[tmu] = c; - voodoo->texture_cache[tmu][c].refcount++; -} - -static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) -{ - int wait_for_idle = 0; - int c; - - memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0])); -// voodoo_log("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present)); - for (c = 0; c < TEX_CACHE_MAX; c++) - { - if (voodoo->texture_cache[tmu][c].base != -1) - { - int d; - - for (d = 0; d < 4; d++) - { - int addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; - int addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; - - if (addr_end != 0) - { - int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; - int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; - - if (addr_end_masked < addr_start_masked) - addr_end_masked = voodoo->texture_mask+1; - if (dirty_addr >= addr_start_masked && dirty_addr < addr_end_masked) - { -// voodoo_log(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base); - - if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] || - (voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1])) - wait_for_idle = 1; - - voodoo->texture_cache[tmu][c].base = -1; - } - else - { - for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT)) - voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; - } - } - } - } - } - if (wait_for_idle) - wait_for_render_thread_idle(voodoo); -} - -typedef struct voodoo_state_t -{ - int xstart, xend, xdir; - uint32_t base_r, base_g, base_b, base_a, base_z; - struct - { - int64_t base_s, base_t, base_w; - int lod; - } tmu[2]; - int64_t base_w; - int lod; - int lod_min[2], lod_max[2]; - int dx1, dx2; - int y, yend, ydir; - int32_t dxAB, dxAC, dxBC; - int tex_b[2], tex_g[2], tex_r[2], tex_a[2]; - int tex_s, tex_t; - int clamp_s[2], clamp_t[2]; - - int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; - - uint32_t *tex[2][LOD_MAX+1]; - int tformat; - - int *tex_w_mask[2]; - int *tex_h_mask[2]; - int *tex_shift[2]; - int *tex_lod[2]; - - uint16_t *fb_mem, *aux_mem; - - int32_t ib, ig, ir, ia; - int32_t z; - - int32_t new_depth; - - int64_t tmu0_s, tmu0_t; - int64_t tmu0_w; - int64_t tmu1_s, tmu1_t; - int64_t tmu1_w; - int64_t w; - - int pixel_count, texel_count; - int x, x2; - - uint32_t w_depth; - - float log_temp; - uint32_t ebp_store; - uint32_t texBaseAddr; - - int lod_frac[2]; -} voodoo_state_t; - -static int voodoo_output = 0; - -static uint8_t logtable[256] = -{ - 0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15, - 0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a, - 0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e, - 0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51, - 0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63, - 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, - 0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85, - 0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94, - 0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3, - 0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2, - 0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0, - 0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd, - 0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda, - 0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7, - 0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3, - 0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff -}; - -static inline int fastlog(uint64_t val) -{ - uint64_t oldval = val; - int exp = 63; - int frac; - - if (!val || val & (1ULL << 63)) - return 0x80000000; - - if (!(val & 0xffffffff00000000)) - { - exp -= 32; - val <<= 32; - } - if (!(val & 0xffff000000000000)) - { - exp -= 16; - val <<= 16; - } - if (!(val & 0xff00000000000000)) - { - exp -= 8; - val <<= 8; - } - if (!(val & 0xf000000000000000)) - { - exp -= 4; - val <<= 4; - } - if (!(val & 0xc000000000000000)) - { - exp -= 2; - val <<= 2; - } - if (!(val & 0x8000000000000000)) - { - exp -= 1; - val <<= 1; - } - - if (exp >= 8) - frac = (oldval >> (exp - 8)) & 0xff; - else - frac = (oldval << (8 - exp)) & 0xff; - - return (exp << 8) | logtable[frac]; -} - -static inline int voodoo_fls(uint16_t val) -{ - int num = 0; - -//voodoo_log("fls(%04x) = ", val); - if (!(val & 0xff00)) - { - num += 8; - val <<= 8; - } - if (!(val & 0xf000)) - { - num += 4; - val <<= 4; - } - if (!(val & 0xc000)) - { - num += 2; - val <<= 2; - } - if (!(val & 0x8000)) - { - num += 1; - val <<= 1; - } -//voodoo_log("%i %04x\n", num, val); - return num; -} - -typedef struct voodoo_texture_state_t -{ - int s, t; - int w_mask, h_mask; - int tex_shift; -} voodoo_texture_state_t; - -static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int tmu) -{ - uint32_t dat; - - if (texture_state->s & ~texture_state->w_mask) - { - if (state->clamp_s[tmu]) - { - if (texture_state->s < 0) - texture_state->s = 0; - if (texture_state->s > texture_state->w_mask) - texture_state->s = texture_state->w_mask; - } - else - texture_state->s &= texture_state->w_mask; - } - if (texture_state->t & ~texture_state->h_mask) - { - if (state->clamp_t[tmu]) - { - if (texture_state->t < 0) - texture_state->t = 0; - if (texture_state->t > texture_state->h_mask) - texture_state->t = texture_state->h_mask; - } - else - texture_state->t &= texture_state->h_mask; - } - - dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; - - state->tex_b[tmu] = dat & 0xff; - state->tex_g[tmu] = (dat >> 8) & 0xff; - state->tex_r[tmu] = (dat >> 16) & 0xff; - state->tex_a[tmu] = (dat >> 24) & 0xff; -} - -#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4)) -#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4)) - -static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d, int tmu, int x) -{ - rgba_u dat[4]; - - if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask)) - { - int c; - for (c = 0; c < 4; c++) - { - int _s = s + (c & 1); - int _t = t + ((c & 2) >> 1); - - if (_s & ~texture_state->w_mask) - { - if (state->clamp_s[tmu]) - { - if (_s < 0) - _s = 0; - if (_s > texture_state->w_mask) - _s = texture_state->w_mask; - } - else - _s &= texture_state->w_mask; - } - if (_t & ~texture_state->h_mask) - { - if (state->clamp_t[tmu]) - { - if (_t < 0) - _t = 0; - if (_t > texture_state->h_mask) - _t = texture_state->h_mask; - } - else - _t &= texture_state->h_mask; - } - dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)]; - } - } - else - { - dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)]; - dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)]; - dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)]; - dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; - } - - state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8; - state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8; - state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8; - state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8; -} - -static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) -{ - voodoo_texture_state_t texture_state; - int d[4]; - int s, t; - int tex_lod = state->tex_lod[tmu][state->lod]; - - texture_state.w_mask = state->tex_w_mask[tmu][state->lod]; - texture_state.h_mask = state->tex_h_mask[tmu][state->lod]; - texture_state.tex_shift = 8 - tex_lod; - - if (params->tLOD[tmu] & LOD_TMIRROR_S) - { - if (state->tex_s & 0x1000) - state->tex_s = ~state->tex_s; - } - if (params->tLOD[tmu] & LOD_TMIRROR_T) - { - if (state->tex_t & 0x1000) - state->tex_t = ~state->tex_t; - } - - if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6) - { - int _ds, dt; - - state->tex_s -= 1 << (3+tex_lod); - state->tex_t -= 1 << (3+tex_lod); - - s = state->tex_s >> tex_lod; - t = state->tex_t >> tex_lod; - - _ds = s & 0xf; - dt = t & 0xf; - - s >>= 4; - t >>= 4; -//if (x == 80) -//if (voodoo_output) -// voodoo_log("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt); - d[0] = (16 - _ds) * (16 - dt); - d[1] = _ds * (16 - dt); - d[2] = (16 - _ds) * dt; - d[3] = _ds * dt; - -// texture_state.s = s; -// texture_state.t = t; - tex_read_4(state, &texture_state, s, t, d, tmu, x); - - -/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8; - state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8; - state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8; - state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/ -/* state->tex_r = tex_samples[0].r; - state->tex_g = tex_samples[0].g; - state->tex_b = tex_samples[0].b; - state->tex_a = tex_samples[0].a;*/ - } - else - { - // rgba_t tex_samples; - // voodoo_texture_state_t texture_state; -// int s = state->tex_s >> (18+state->lod); -// int t = state->tex_t >> (18+state->lod); - // int s, t; - -// state->tex_s -= 1 << (17+state->lod); -// state->tex_t -= 1 << (17+state->lod); - - s = state->tex_s >> (4+tex_lod); - t = state->tex_t >> (4+tex_lod); - - texture_state.s = s; - texture_state.t = t; - tex_read(state, &texture_state, tmu); - -/* state->tex_r = tex_samples[0].rgba.r; - state->tex_g = tex_samples[0].rgba.g; - state->tex_b = tex_samples[0].rgba.b; - state->tex_a = tex_samples[0].rgba.a;*/ - } -} - -static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) -{ - if (params->textureMode[tmu] & 1) - { - int64_t _w = 0; - - if (tmu) - { - if (state->tmu1_w) - _w = (int64_t)((1ULL << 48) / state->tmu1_w); - state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - } - else - { - if (state->tmu0_w) - _w = (int64_t)((1ULL << 48) / state->tmu0_w); - state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - } - - state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8)); - } - else - { - if (tmu) - { - state->tex_s = (int32_t)(state->tmu1_s >> (14+14)); - state->tex_t = (int32_t)(state->tmu1_t >> (14+14)); - } - else - { - state->tex_s = (int32_t)(state->tmu0_s >> (14+14)); - state->tex_t = (int32_t)(state->tmu0_t >> (14+14)); - } - state->lod = state->tmu[tmu].lod; - } - - if (state->lod < state->lod_min[tmu]) - state->lod = state->lod_min[tmu]; - else if (state->lod > state->lod_max[tmu]) - state->lod = state->lod_max[tmu]; - state->lod_frac[tmu] = state->lod & 0xff; - state->lod >>= 8; - - voodoo_get_texture(voodoo, params, state, tmu, x); -} - -#define DEPTH_TEST(comp_depth) \ - do \ - { \ - switch (depth_op) \ - { \ - case DEPTHOP_NEVER: \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - case DEPTHOP_LESSTHAN: \ - if (!(comp_depth < old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_EQUAL: \ - if (!(comp_depth == old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_LESSTHANEQUAL: \ - if (!(comp_depth <= old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_GREATERTHAN: \ - if (!(comp_depth > old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_NOTEQUAL: \ - if (!(comp_depth != old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_GREATERTHANEQUAL: \ - if (!(comp_depth >= old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_ALWAYS: \ - break; \ - } \ - } while (0) - -#define APPLY_FOG(src_r, src_g, src_b, z, ia, w) \ - do \ - { \ - if (params->fogMode & FOG_CONSTANT) \ - { \ - src_r += params->fogColor.r; \ - src_g += params->fogColor.g; \ - src_b += params->fogColor.b; \ - } \ - else \ - { \ - int fog_r, fog_g, fog_b, fog_a = 0; \ - int fog_idx; \ - \ - if (!(params->fogMode & FOG_ADD)) \ - { \ - fog_r = params->fogColor.r; \ - fog_g = params->fogColor.g; \ - fog_b = params->fogColor.b; \ - } \ - else \ - fog_r = fog_g = fog_b = 0; \ - \ - if (!(params->fogMode & FOG_MULT)) \ - { \ - fog_r -= src_r; \ - fog_g -= src_g; \ - fog_b -= src_b; \ - } \ - \ - switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \ - { \ - case 0: \ - fog_idx = (w_depth >> 10) & 0x3f; \ - \ - fog_a = params->fogTable[fog_idx].fog; \ - fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \ - break; \ - case FOG_Z: \ - fog_a = (z >> 20) & 0xff; \ - break; \ - case FOG_ALPHA: \ - fog_a = CLAMP(ia >> 12); \ - break; \ - case FOG_W: \ - fog_a = CLAMP((w >> 32) & 0xff); \ - break; \ - } \ - fog_a++; \ - \ - fog_r = (fog_r * fog_a) >> 8; \ - fog_g = (fog_g * fog_a) >> 8; \ - fog_b = (fog_b * fog_a) >> 8; \ - \ - if (params->fogMode & FOG_MULT) \ - { \ - src_r = fog_r; \ - src_g = fog_g; \ - src_b = fog_b; \ - } \ - else \ - { \ - src_r += fog_r; \ - src_g += fog_g; \ - src_b += fog_b; \ - } \ - } \ - \ - src_r = CLAMP(src_r); \ - src_g = CLAMP(src_g); \ - src_b = CLAMP(src_b); \ - } while (0) - -#define ALPHA_TEST(src_a) \ - do \ - { \ - switch (alpha_func) \ - { \ - case AFUNC_NEVER: \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - case AFUNC_LESSTHAN: \ - if (!(src_a < a_ref)) \ - { \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case AFUNC_EQUAL: \ - if (!(src_a == a_ref)) \ - { \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case AFUNC_LESSTHANEQUAL: \ - if (!(src_a <= a_ref)) \ - { \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case AFUNC_GREATERTHAN: \ - if (!(src_a > a_ref)) \ - { \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case AFUNC_NOTEQUAL: \ - if (!(src_a != a_ref)) \ - { \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case AFUNC_GREATERTHANEQUAL: \ - if (!(src_a >= a_ref)) \ - { \ - voodoo->fbiAFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case AFUNC_ALWAYS: \ - break; \ - } \ - } while (0) - -#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \ - do \ - { \ - int _a; \ - int newdest_r = 0, newdest_g = 0, newdest_b = 0; \ - \ - switch (dest_afunc) \ - { \ - case AFUNC_AZERO: \ - newdest_r = newdest_g = newdest_b = 0; \ - break; \ - case AFUNC_ASRC_ALPHA: \ - newdest_r = (dest_r * src_a) / 255; \ - newdest_g = (dest_g * src_a) / 255; \ - newdest_b = (dest_b * src_a) / 255; \ - break; \ - case AFUNC_A_COLOR: \ - newdest_r = (dest_r * src_r) / 255; \ - newdest_g = (dest_g * src_g) / 255; \ - newdest_b = (dest_b * src_b) / 255; \ - break; \ - case AFUNC_ADST_ALPHA: \ - newdest_r = (dest_r * dest_a) / 255; \ - newdest_g = (dest_g * dest_a) / 255; \ - newdest_b = (dest_b * dest_a) / 255; \ - break; \ - case AFUNC_AONE: \ - newdest_r = dest_r; \ - newdest_g = dest_g; \ - newdest_b = dest_b; \ - break; \ - case AFUNC_AOMSRC_ALPHA: \ - newdest_r = (dest_r * (255-src_a)) / 255; \ - newdest_g = (dest_g * (255-src_a)) / 255; \ - newdest_b = (dest_b * (255-src_a)) / 255; \ - break; \ - case AFUNC_AOM_COLOR: \ - newdest_r = (dest_r * (255-src_r)) / 255; \ - newdest_g = (dest_g * (255-src_g)) / 255; \ - newdest_b = (dest_b * (255-src_b)) / 255; \ - break; \ - case AFUNC_AOMDST_ALPHA: \ - newdest_r = (dest_r * (255-dest_a)) / 255; \ - newdest_g = (dest_g * (255-dest_a)) / 255; \ - newdest_b = (dest_b * (255-dest_a)) / 255; \ - break; \ - case AFUNC_ASATURATE: \ - _a = MIN(src_a, 1-dest_a); \ - newdest_r = (dest_r * _a) / 255; \ - newdest_g = (dest_g * _a) / 255; \ - newdest_b = (dest_b * _a) / 255; \ - break; \ - } \ - \ - switch (src_afunc) \ - { \ - case AFUNC_AZERO: \ - src_r = src_g = src_b = 0; \ - break; \ - case AFUNC_ASRC_ALPHA: \ - src_r = (src_r * src_a) / 255; \ - src_g = (src_g * src_a) / 255; \ - src_b = (src_b * src_a) / 255; \ - break; \ - case AFUNC_A_COLOR: \ - src_r = (src_r * dest_r) / 255; \ - src_g = (src_g * dest_g) / 255; \ - src_b = (src_b * dest_b) / 255; \ - break; \ - case AFUNC_ADST_ALPHA: \ - src_r = (src_r * dest_a) / 255; \ - src_g = (src_g * dest_a) / 255; \ - src_b = (src_b * dest_a) / 255; \ - break; \ - case AFUNC_AONE: \ - break; \ - case AFUNC_AOMSRC_ALPHA: \ - src_r = (src_r * (255-src_a)) / 255; \ - src_g = (src_g * (255-src_a)) / 255; \ - src_b = (src_b * (255-src_a)) / 255; \ - break; \ - case AFUNC_AOM_COLOR: \ - src_r = (src_r * (255-dest_r)) / 255; \ - src_g = (src_g * (255-dest_g)) / 255; \ - src_b = (src_b * (255-dest_b)) / 255; \ - break; \ - case AFUNC_AOMDST_ALPHA: \ - src_r = (src_r * (255-dest_a)) / 255; \ - src_g = (src_g * (255-dest_a)) / 255; \ - src_b = (src_b * (255-dest_a)) / 255; \ - break; \ - case AFUNC_ACOLORBEFOREFOG: \ - fatal("AFUNC_ACOLORBEFOREFOG\n"); \ - break; \ - } \ - \ - src_r += newdest_r; \ - src_g += newdest_g; \ - src_b += newdest_b; \ - \ - src_r = CLAMP(src_r); \ - src_g = CLAMP(src_g); \ - src_b = CLAMP(src_b); \ - } while(0) - - -#define _rgb_sel ( params->fbzColorPath & 3) -#define a_sel ( (params->fbzColorPath >> 2) & 3) -#define cc_localselect ( params->fbzColorPath & (1 << 4)) -#define cca_localselect ( (params->fbzColorPath >> 5) & 3) -#define cc_localselect_override ( params->fbzColorPath & (1 << 7)) -#define cc_zero_other ( params->fbzColorPath & (1 << 8)) -#define cc_sub_clocal ( params->fbzColorPath & (1 << 9)) -#define cc_mselect ( (params->fbzColorPath >> 10) & 7) -#define cc_reverse_blend ( params->fbzColorPath & (1 << 13)) -#define cc_add ( (params->fbzColorPath >> 14) & 3) -#define cc_add_alocal ( params->fbzColorPath & (1 << 15)) -#define cc_invert_output ( params->fbzColorPath & (1 << 16)) -#define cca_zero_other ( params->fbzColorPath & (1 << 17)) -#define cca_sub_clocal ( params->fbzColorPath & (1 << 18)) -#define cca_mselect ( (params->fbzColorPath >> 19) & 7) -#define cca_reverse_blend ( params->fbzColorPath & (1 << 22)) -#define cca_add ( (params->fbzColorPath >> 23) & 3) -#define cca_invert_output ( params->fbzColorPath & (1 << 25)) -#define tc_zero_other (params->textureMode[0] & (1 << 12)) -#define tc_sub_clocal (params->textureMode[0] & (1 << 13)) -#define tc_mselect ((params->textureMode[0] >> 14) & 7) -#define tc_reverse_blend (params->textureMode[0] & (1 << 17)) -#define tc_add_clocal (params->textureMode[0] & (1 << 18)) -#define tc_add_alocal (params->textureMode[0] & (1 << 19)) -#define tc_invert_output (params->textureMode[0] & (1 << 20)) -#define tca_zero_other (params->textureMode[0] & (1 << 21)) -#define tca_sub_clocal (params->textureMode[0] & (1 << 22)) -#define tca_mselect ((params->textureMode[0] >> 23) & 7) -#define tca_reverse_blend (params->textureMode[0] & (1 << 26)) -#define tca_add_clocal (params->textureMode[0] & (1 << 27)) -#define tca_add_alocal (params->textureMode[0] & (1 << 28)) -#define tca_invert_output (params->textureMode[0] & (1 << 29)) - -#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13)) -#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7) -#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17)) -#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18)) -#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19)) -#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22)) -#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7) -#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26)) -#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27)) -#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28)) - -#define src_afunc ( (params->alphaMode >> 8) & 0xf) -#define dest_afunc ( (params->alphaMode >> 12) & 0xf) -#define alpha_func ( (params->alphaMode >> 1) & 7) -#define a_ref ( params->alphaMode >> 24) -#define depth_op ( (params->fbzMode >> 5) & 7) -#define dither ( params->fbzMode & FBZ_DITHER) -#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) - -/*Perform texture fetch and blending for both TMUs*/ -static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) -{ - int r,g,b,a; - int c_reverse, a_reverse; -// int c_reverse1, a_reverse1; - int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; - - voodoo_tmu_fetch(voodoo, params, state, 1, x); - - if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) - { - c_reverse = tc_reverse_blend; - a_reverse = tca_reverse_blend; - } - else - { - c_reverse = !tc_reverse_blend; - a_reverse = !tca_reverse_blend; - } -/* c_reverse1 = c_reverse; - a_reverse1 = a_reverse;*/ - if (tc_sub_clocal_1) - { - switch (tc_mselect_1) - { - case TC_MSELECT_ZERO: - factor_r = factor_g = factor_b = 0; - break; - case TC_MSELECT_CLOCAL: - factor_r = state->tex_r[1]; - factor_g = state->tex_g[1]; - factor_b = state->tex_b[1]; - break; - case TC_MSELECT_AOTHER: - factor_r = factor_g = factor_b = 0; - break; - case TC_MSELECT_ALOCAL: - factor_r = factor_g = factor_b = state->tex_a[1]; - break; - case TC_MSELECT_DETAIL: - factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; - if (factor_r > params->detail_max[1]) - factor_r = params->detail_max[1]; - factor_g = factor_b = factor_r; - break; - case TC_MSELECT_LOD_FRAC: - factor_r = factor_g = factor_b = state->lod_frac[1]; - break; - } - if (!c_reverse) - { - r = (-state->tex_r[1] * (factor_r + 1)) >> 8; - g = (-state->tex_g[1] * (factor_g + 1)) >> 8; - b = (-state->tex_b[1] * (factor_b + 1)) >> 8; - } - else - { - r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8; - g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8; - b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8; - } - if (tc_add_clocal_1) - { - r += state->tex_r[1]; - g += state->tex_g[1]; - b += state->tex_b[1]; - } - else if (tc_add_alocal_1) - { - r += state->tex_a[1]; - g += state->tex_a[1]; - b += state->tex_a[1]; - } - state->tex_r[1] = CLAMP(r); - state->tex_g[1] = CLAMP(g); - state->tex_b[1] = CLAMP(b); - } - if (tca_sub_clocal_1) - { - switch (tca_mselect_1) - { - case TCA_MSELECT_ZERO: - factor_a = 0; - break; - case TCA_MSELECT_CLOCAL: - factor_a = state->tex_a[1]; - break; - case TCA_MSELECT_AOTHER: - factor_a = 0; - break; - case TCA_MSELECT_ALOCAL: - factor_a = state->tex_a[1]; - break; - case TCA_MSELECT_DETAIL: - factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; - if (factor_a > params->detail_max[1]) - factor_a = params->detail_max[1]; - break; - case TCA_MSELECT_LOD_FRAC: - factor_a = state->lod_frac[1]; - break; - } - if (!a_reverse) - a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8; - else - a = (-state->tex_a[1] * (factor_a + 1)) >> 8; - if (tca_add_clocal_1 || tca_add_alocal_1) - a += state->tex_a[1]; - state->tex_a[1] = CLAMP(a); - } - - - voodoo_tmu_fetch(voodoo, params, state, 0, x); - - if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) - { - c_reverse = tc_reverse_blend; - a_reverse = tca_reverse_blend; - } - else - { - c_reverse = !tc_reverse_blend; - a_reverse = !tca_reverse_blend; - } - - if (!tc_zero_other) - { - r = state->tex_r[1]; - g = state->tex_g[1]; - b = state->tex_b[1]; - } - else - r = g = b = 0; - if (tc_sub_clocal) - { - r -= state->tex_r[0]; - g -= state->tex_g[0]; - b -= state->tex_b[0]; - } - switch (tc_mselect) - { - case TC_MSELECT_ZERO: - factor_r = factor_g = factor_b = 0; - break; - case TC_MSELECT_CLOCAL: - factor_r = state->tex_r[0]; - factor_g = state->tex_g[0]; - factor_b = state->tex_b[0]; - break; - case TC_MSELECT_AOTHER: - factor_r = factor_g = factor_b = state->tex_a[1]; - break; - case TC_MSELECT_ALOCAL: - factor_r = factor_g = factor_b = state->tex_a[0]; - break; - case TC_MSELECT_DETAIL: - factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; - if (factor_r > params->detail_max[0]) - factor_r = params->detail_max[0]; - factor_g = factor_b = factor_r; - break; - case TC_MSELECT_LOD_FRAC: - factor_r = factor_g = factor_b = state->lod_frac[0]; - break; - } - if (!c_reverse) - { - r = (r * (factor_r + 1)) >> 8; - g = (g * (factor_g + 1)) >> 8; - b = (b * (factor_b + 1)) >> 8; - } - else - { - r = (r * ((factor_r^0xff) + 1)) >> 8; - g = (g * ((factor_g^0xff) + 1)) >> 8; - b = (b * ((factor_b^0xff) + 1)) >> 8; - } - if (tc_add_clocal) - { - r += state->tex_r[0]; - g += state->tex_g[0]; - b += state->tex_b[0]; - } - else if (tc_add_alocal) - { - r += state->tex_a[0]; - g += state->tex_a[0]; - b += state->tex_a[0]; - } - - if (!tca_zero_other) - a = state->tex_a[1]; - else - a = 0; - if (tca_sub_clocal) - a -= state->tex_a[0]; - switch (tca_mselect) - { - case TCA_MSELECT_ZERO: - factor_a = 0; - break; - case TCA_MSELECT_CLOCAL: - factor_a = state->tex_a[0]; - break; - case TCA_MSELECT_AOTHER: - factor_a = state->tex_a[1]; - break; - case TCA_MSELECT_ALOCAL: - factor_a = state->tex_a[0]; - break; - case TCA_MSELECT_DETAIL: - factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; - if (factor_a > params->detail_max[0]) - factor_a = params->detail_max[0]; - break; - case TCA_MSELECT_LOD_FRAC: - factor_a = state->lod_frac[0]; - break; - } - if (a_reverse) - a = (a * ((factor_a ^ 0xff) + 1)) >> 8; - else - a = (a * (factor_a + 1)) >> 8; - if (tca_add_clocal || tca_add_alocal) - a += state->tex_a[0]; - - - state->tex_r[0] = CLAMP(r); - state->tex_g[0] = CLAMP(g); - state->tex_b[0] = CLAMP(b); - state->tex_a[0] = CLAMP(a); - - if (tc_invert_output) - { - state->tex_r[0] ^= 0xff; - state->tex_g[0] ^= 0xff; - state->tex_b[0] ^= 0xff; - } - if (tca_invert_output) - state->tex_a[0] ^= 0xff; -} - -#if ((defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86) && !(defined __amd64__ || defined _M_X64) && (defined USE_DYNAREC)) -#include <86box/vid_voodoo_codegen_x86.h> -#elif ((defined __amd64__ || defined _M_X64) && (defined USE_DYNAREC)) -#include <86box/vid_voodoo_codegen_x86-64.h> -#else -#define NO_CODEGEN -#endif - -static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even) -{ -/* int rgb_sel = params->fbzColorPath & 3; - int a_sel = (params->fbzColorPath >> 2) & 3; - int cc_localselect = params->fbzColorPath & (1 << 4); - int cca_localselect = (params->fbzColorPath >> 5) & 3; - int cc_localselect_override = params->fbzColorPath & (1 << 7); - int cc_zero_other = params->fbzColorPath & (1 << 8); - int cc_sub_clocal = params->fbzColorPath & (1 << 9); - int cc_mselect = (params->fbzColorPath >> 10) & 7; - int cc_reverse_blend = params->fbzColorPath & (1 << 13); - int cc_add = (params->fbzColorPath >> 14) & 3; - int cc_add_alocal = params->fbzColorPath & (1 << 15); - int cc_invert_output = params->fbzColorPath & (1 << 16); - int cca_zero_other = params->fbzColorPath & (1 << 17); - int cca_sub_clocal = params->fbzColorPath & (1 << 18); - int cca_mselect = (params->fbzColorPath >> 19) & 7; - int cca_reverse_blend = params->fbzColorPath & (1 << 22); - int cca_add = (params->fbzColorPath >> 23) & 3; - int cca_invert_output = params->fbzColorPath & (1 << 25); - int src_afunc = (params->alphaMode >> 8) & 0xf; - int dest_afunc = (params->alphaMode >> 12) & 0xf; - int alpha_func = (params->alphaMode >> 1) & 7; - int a_ref = params->alphaMode >> 24; - int depth_op = (params->fbzMode >> 5) & 7; - int dither = params->fbzMode & FBZ_DITHER;*/ - int texels; - int c; -#ifndef NO_CODEGEN - uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); -#endif - uint8_t cother_r = 0, cother_g = 0, cother_b = 0; - int y_diff = SLI_ENABLED ? 2 : 1; - - if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || - (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) - texels = 1; - else - texels = 2; - - state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS; - state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT; - state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS; - state->clamp_t[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPT; -// int last_x; -// voodoo_log("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); - - for (c = 0; c <= LOD_MAX; c++) - { - state->tex[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]]; - state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]]; - } - - state->tformat = params->tformat[0]; - - state->tex_w_mask[0] = params->tex_w_mask[0]; - state->tex_h_mask[0] = params->tex_h_mask[0]; - state->tex_shift[0] = params->tex_shift[0]; - state->tex_lod[0] = params->tex_lod[0]; - state->tex_w_mask[1] = params->tex_w_mask[1]; - state->tex_h_mask[1] = params->tex_h_mask[1]; - state->tex_shift[1] = params->tex_shift[1]; - state->tex_lod[1] = params->tex_lod[1]; - - if ((params->fbzMode & 1) && (ystart < params->clipLowY)) - { - int dy = params->clipLowY - ystart; - - state->base_r += params->dRdY*dy; - state->base_g += params->dGdY*dy; - state->base_b += params->dBdY*dy; - state->base_a += params->dAdY*dy; - state->base_z += params->dZdY*dy; - state->tmu[0].base_s += params->tmu[0].dSdY*dy; - state->tmu[0].base_t += params->tmu[0].dTdY*dy; - state->tmu[0].base_w += params->tmu[0].dWdY*dy; - state->tmu[1].base_s += params->tmu[1].dSdY*dy; - state->tmu[1].base_t += params->tmu[1].dTdY*dy; - state->tmu[1].base_w += params->tmu[1].dWdY*dy; - state->base_w += params->dWdY*dy; - state->xstart += state->dx1*dy; - state->xend += state->dx2*dy; - - ystart = params->clipLowY; - } - - if ((params->fbzMode & 1) && (yend >= params->clipHighY)) - yend = params->clipHighY-1; - - state->y = ystart; -// yend--; - - if (SLI_ENABLED) - { - int test_y; - - if (params->fbzMode & (1 << 17)) - test_y = (voodoo->v_disp-1) - state->y; - else - test_y = state->y; - - if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (test_y & 1)) || - ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(test_y & 1))) - { - state->y++; - - state->base_r += params->dRdY; - state->base_g += params->dGdY; - state->base_b += params->dBdY; - state->base_a += params->dAdY; - state->base_z += params->dZdY; - state->tmu[0].base_s += params->tmu[0].dSdY; - state->tmu[0].base_t += params->tmu[0].dTdY; - state->tmu[0].base_w += params->tmu[0].dWdY; - state->tmu[1].base_s += params->tmu[1].dSdY; - state->tmu[1].base_t += params->tmu[1].dTdY; - state->tmu[1].base_w += params->tmu[1].dWdY; - state->base_w += params->dWdY; - state->xstart += state->dx1; - state->xend += state->dx2; - } - } -#ifndef NO_CODEGEN - if (voodoo->use_recompiler) - voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); - else - voodoo_draw = NULL; -#endif - - if (voodoo_output) - voodoo_log("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); -// voodoo_log("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); - - for (; state->y < yend; state->y += y_diff) - { - int x, x2; - int real_y = (state->y << 4) + 8; - int start_x; -#ifdef ENABLE_VOODOO_LOG - int start_x2; -#endif - int dx; - uint16_t *fb_mem, *aux_mem; - - state->ir = state->base_r; - state->ig = state->base_g; - state->ib = state->base_b; - state->ia = state->base_a; - state->z = state->base_z; - state->tmu0_s = state->tmu[0].base_s; - state->tmu0_t = state->tmu[0].base_t; - state->tmu0_w = state->tmu[0].base_w; - state->tmu1_s = state->tmu[1].base_s; - state->tmu1_t = state->tmu[1].base_t; - state->tmu1_w = state->tmu[1].base_w; - state->w = state->base_w; - - x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4); - - if (real_y < state->vertexBy) - x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4); - else - x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4); - - if (params->fbzMode & (1 << 17)) - real_y = (voodoo->v_disp-1) - (real_y >> 4); - else - real_y >>= 4; - - if (SLI_ENABLED) - { - if (((real_y >> 1) & voodoo->odd_even_mask) != odd_even) - goto next_line; - } - else - { - if ((real_y & voodoo->odd_even_mask) != odd_even) - goto next_line; - } - - start_x = x; - - if (state->xdir > 0) - x2 -= (1 << 16); - else - x -= (1 << 16); - dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); -#ifdef ENABLE_VOODOO_LOG - start_x2 = x + 0x7000; -#endif - x = (x + 0x7000) >> 16; - x2 = (x2 + 0x7000) >> 16; - - if (voodoo_output) - voodoo_log("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t); - - state->ir += (params->dRdX * dx); - state->ig += (params->dGdX * dx); - state->ib += (params->dBdX * dx); - state->ia += (params->dAdX * dx); - state->z += (params->dZdX * dx); - state->tmu0_s += (params->tmu[0].dSdX * dx); - state->tmu0_t += (params->tmu[0].dTdX * dx); - state->tmu0_w += (params->tmu[0].dWdX * dx); - state->tmu1_s += (params->tmu[1].dSdX * dx); - state->tmu1_t += (params->tmu[1].dTdX * dx); - state->tmu1_w += (params->tmu[1].dWdX * dx); - state->w += (params->dWdX * dx); - - if (voodoo_output) - voodoo_log("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << (17+state->lod))) >> (18+state->lod)); - - if (params->fbzMode & 1) - { - if (state->xdir > 0) - { - if (x < params->clipLeft) - { - int dx = params->clipLeft - x; - - state->ir += params->dRdX*dx; - state->ig += params->dGdX*dx; - state->ib += params->dBdX*dx; - state->ia += params->dAdX*dx; - state->z += params->dZdX*dx; - state->tmu0_s += params->tmu[0].dSdX*dx; - state->tmu0_t += params->tmu[0].dTdX*dx; - state->tmu0_w += params->tmu[0].dWdX*dx; - state->tmu1_s += params->tmu[1].dSdX*dx; - state->tmu1_t += params->tmu[1].dTdX*dx; - state->tmu1_w += params->tmu[1].dWdX*dx; - state->w += params->dWdX*dx; - - x = params->clipLeft; - } - if (x2 >= params->clipRight) - x2 = params->clipRight-1; - } - else - { - if (x >= params->clipRight) - { - int dx = (params->clipRight-1) - x; - - state->ir += params->dRdX*dx; - state->ig += params->dGdX*dx; - state->ib += params->dBdX*dx; - state->ia += params->dAdX*dx; - state->z += params->dZdX*dx; - state->tmu0_s += params->tmu[0].dSdX*dx; - state->tmu0_t += params->tmu[0].dTdX*dx; - state->tmu0_w += params->tmu[0].dWdX*dx; - state->tmu1_s += params->tmu[1].dSdX*dx; - state->tmu1_t += params->tmu[1].dTdX*dx; - state->tmu1_w += params->tmu[1].dWdX*dx; - state->w += params->dWdX*dx; - - x = params->clipRight-1; - } - if (x2 < params->clipLeft) - x2 = params->clipLeft; - } - } - - if (x2 < x && state->xdir > 0) - goto next_line; - if (x2 > x && state->xdir < 0) - goto next_line; - - if (SLI_ENABLED) - { - state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + ((real_y >> 1) * voodoo->row_width)]; - state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + ((real_y >> 1) * voodoo->row_width)) & voodoo->fb_mask]; - } - else - { - state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; - state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * voodoo->row_width)) & voodoo->fb_mask]; - } - - if (voodoo_output) - voodoo_log("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2); - - state->pixel_count = 0; - state->texel_count = 0; - state->x = x; - state->x2 = x2; -#ifndef NO_CODEGEN - if (voodoo->use_recompiler) - { - voodoo_draw(state, params, x, real_y); - } - else -#endif - do - { - start_x = x; - state->x = x; - voodoo->pixel_count[odd_even]++; - voodoo->texel_count[odd_even] += texels; - voodoo->fbiPixelsIn++; - - if (voodoo_output) - voodoo_log(" X=%03i T=%08x\n", x, state->tmu0_t); -// if (voodoo->fbzMode & FBZ_RGB_WMASK) - { - int update = 1; - uint8_t aother; - uint8_t clocal_r, clocal_g, clocal_b, alocal; - int src_r = 0, src_g = 0, src_b = 0, src_a = 0; - int msel_r, msel_g, msel_b, msel_a; - uint8_t dest_r, dest_g, dest_b, dest_a; - uint16_t dat; - int sel; - int32_t new_depth, w_depth; - - if (state->w & 0xffff00000000) - w_depth = 0; - else if (!(state->w & 0xffff0000)) - w_depth = 0xf001; - else - { - int exp = voodoo_fls((uint16_t)((uint32_t)state->w >> 16)); - int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; - w_depth = (exp << 12) + mant + 1; - if (w_depth > 0xffff) - w_depth = 0xffff; - } - -// w_depth = CLAMP16(w_depth); - - if (params->fbzMode & FBZ_W_BUFFER) - new_depth = w_depth; - else - new_depth = CLAMP16(state->z >> 12); - - if (params->fbzMode & FBZ_DEPTH_BIAS) - new_depth = CLAMP16(new_depth + (int16_t)params->zaColor); - - if (params->fbzMode & FBZ_DEPTH_ENABLE) - { - uint16_t old_depth = aux_mem[x]; - - DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth); - } - - dat = fb_mem[x]; - dest_r = (dat >> 8) & 0xf8; - dest_g = (dat >> 3) & 0xfc; - dest_b = (dat << 3) & 0xf8; - dest_r |= (dest_r >> 5); - dest_g |= (dest_g >> 6); - dest_b |= (dest_b >> 5); - dest_a = 0xff; - - if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) - { - if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) - { - /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ - voodoo_tmu_fetch(voodoo, params, state, 0, x); - } - else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) - { - /*TMU0 in pass-through mode, only sample TMU1*/ - voodoo_tmu_fetch(voodoo, params, state, 1, x); - - state->tex_r[0] = state->tex_r[1]; - state->tex_g[0] = state->tex_g[1]; - state->tex_b[0] = state->tex_b[1]; - state->tex_a[0] = state->tex_a[1]; - } - else - { - voodoo_tmu_fetch_and_blend(voodoo, params, state, x); - } - - if ((params->fbzMode & FBZ_CHROMAKEY) && - state->tex_r[0] == params->chromaKey_r && - state->tex_g[0] == params->chromaKey_g && - state->tex_b[0] == params->chromaKey_b) - { - voodoo->fbiChromaFail++; - goto skip_pixel; - } - } - - if (voodoo->trexInit1[0] & (1 << 18)) - { - state->tex_r[0] = state->tex_g[0] = 0; - state->tex_b[0] = voodoo->tmuConfig; - } - - if (cc_localselect_override) - sel = (state->tex_a[0] & 0x80) ? 1 : 0; - else - sel = cc_localselect; - - if (sel) - { - clocal_r = (params->color0 >> 16) & 0xff; - clocal_g = (params->color0 >> 8) & 0xff; - clocal_b = params->color0 & 0xff; - } - else - { - clocal_r = CLAMP(state->ir >> 12); - clocal_g = CLAMP(state->ig >> 12); - clocal_b = CLAMP(state->ib >> 12); - } - - switch (_rgb_sel) - { - case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/ - cother_r = CLAMP(state->ir >> 12); - cother_g = CLAMP(state->ig >> 12); - cother_b = CLAMP(state->ib >> 12); - break; - - case CC_LOCALSELECT_TEX: /*TREX Color Output*/ - cother_r = state->tex_r[0]; - cother_g = state->tex_g[0]; - cother_b = state->tex_b[0]; - break; - - case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/ - cother_r = (params->color1 >> 16) & 0xff; - cother_g = (params->color1 >> 8) & 0xff; - cother_b = params->color1 & 0xff; - break; - - case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/ - cother_r = src_r; - cother_g = src_g; - cother_b = src_b; - break; - } - - switch (cca_localselect) - { - case CCA_LOCALSELECT_ITER_A: - alocal = CLAMP(state->ia >> 12); - break; - - case CCA_LOCALSELECT_COLOR0: - alocal = (params->color0 >> 24) & 0xff; - break; - - case CCA_LOCALSELECT_ITER_Z: - alocal = CLAMP(state->z >> 20); - break; - - default: - fatal("Bad cca_localselect %i\n", cca_localselect); - alocal = 0xff; - break; - } - - switch (a_sel) - { - case A_SEL_ITER_A: - aother = CLAMP(state->ia >> 12); - break; - case A_SEL_TEX: - aother = state->tex_a[0]; - break; - case A_SEL_COLOR1: - aother = (params->color1 >> 24) & 0xff; - break; - default: - fatal("Bad a_sel %i\n", a_sel); - aother = 0; - break; - } - - if (cc_zero_other) - { - src_r = 0; - src_g = 0; - src_b = 0; - } - else - { - src_r = cother_r; - src_g = cother_g; - src_b = cother_b; - } - - if (cca_zero_other) - src_a = 0; - else - src_a = aother; - - if (cc_sub_clocal) - { - src_r -= clocal_r; - src_g -= clocal_g; - src_b -= clocal_b; - } - - if (cca_sub_clocal) - src_a -= alocal; - - switch (cc_mselect) - { - case CC_MSELECT_ZERO: - msel_r = 0; - msel_g = 0; - msel_b = 0; - break; - case CC_MSELECT_CLOCAL: - msel_r = clocal_r; - msel_g = clocal_g; - msel_b = clocal_b; - break; - case CC_MSELECT_AOTHER: - msel_r = aother; - msel_g = aother; - msel_b = aother; - break; - case CC_MSELECT_ALOCAL: - msel_r = alocal; - msel_g = alocal; - msel_b = alocal; - break; - case CC_MSELECT_TEX: - msel_r = state->tex_a[0]; - msel_g = state->tex_a[0]; - msel_b = state->tex_a[0]; - break; - case CC_MSELECT_TEXRGB: - msel_r = state->tex_r[0]; - msel_g = state->tex_g[0]; - msel_b = state->tex_b[0]; - break; - - default: - fatal("Bad cc_mselect %i\n", cc_mselect); - msel_r = 0; - msel_g = 0; - msel_b = 0; - break; - } - - switch (cca_mselect) - { - case CCA_MSELECT_ZERO: - msel_a = 0; - break; - case CCA_MSELECT_ALOCAL: - msel_a = alocal; - break; - case CCA_MSELECT_AOTHER: - msel_a = aother; - break; - case CCA_MSELECT_ALOCAL2: - msel_a = alocal; - break; - case CCA_MSELECT_TEX: - msel_a = state->tex_a[0]; - break; - - default: - fatal("Bad cca_mselect %i\n", cca_mselect); - msel_a = 0; - break; - } - - if (!cc_reverse_blend) - { - msel_r ^= 0xff; - msel_g ^= 0xff; - msel_b ^= 0xff; - } - msel_r++; - msel_g++; - msel_b++; - - if (!cca_reverse_blend) - msel_a ^= 0xff; - msel_a++; - - src_r = (src_r * msel_r) >> 8; - src_g = (src_g * msel_g) >> 8; - src_b = (src_b * msel_b) >> 8; - src_a = (src_a * msel_a) >> 8; - - switch (cc_add) - { - case CC_ADD_CLOCAL: - src_r += clocal_r; - src_g += clocal_g; - src_b += clocal_b; - break; - case CC_ADD_ALOCAL: - src_r += alocal; - src_g += alocal; - src_b += alocal; - break; - case 0: - break; - default: - fatal("Bad cc_add %i\n", cc_add); - } - - if (cca_add) - src_a += alocal; - - src_r = CLAMP(src_r); - src_g = CLAMP(src_g); - src_b = CLAMP(src_b); - src_a = CLAMP(src_a); - - if (cc_invert_output) - { - src_r ^= 0xff; - src_g ^= 0xff; - src_b ^= 0xff; - } - if (cca_invert_output) - src_a ^= 0xff; - - if (params->fogMode & FOG_ENABLE) - APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w); - - if (params->alphaMode & 1) - ALPHA_TEST(src_a); - - if (params->alphaMode & (1 << 4)) - ALPHA_BLEND(src_r, src_g, src_b, src_a); - - if (update) - { - if (dither) - { - if (dither2x2) - { - src_r = dither_rb2x2[src_r][real_y & 1][x & 1]; - src_g = dither_g2x2[src_g][real_y & 1][x & 1]; - src_b = dither_rb2x2[src_b][real_y & 1][x & 1]; - } - else - { - src_r = dither_rb[src_r][real_y & 3][x & 3]; - src_g = dither_g[src_g][real_y & 3][x & 3]; - src_b = dither_rb[src_b][real_y & 3][x & 3]; - } - } - else - { - src_r >>= 3; - src_g >>= 2; - src_b >>= 3; - } - - if (params->fbzMode & FBZ_RGB_WMASK) - fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); - - if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) - aux_mem[x] = new_depth; - } - } - voodoo_output &= ~2; - voodoo->fbiPixelsOut++; -skip_pixel: - if (state->xdir > 0) - { - state->ir += params->dRdX; - state->ig += params->dGdX; - state->ib += params->dBdX; - state->ia += params->dAdX; - state->z += params->dZdX; - state->tmu0_s += params->tmu[0].dSdX; - state->tmu0_t += params->tmu[0].dTdX; - state->tmu0_w += params->tmu[0].dWdX; - state->tmu1_s += params->tmu[1].dSdX; - state->tmu1_t += params->tmu[1].dTdX; - state->tmu1_w += params->tmu[1].dWdX; - state->w += params->dWdX; - } - else - { - state->ir -= params->dRdX; - state->ig -= params->dGdX; - state->ib -= params->dBdX; - state->ia -= params->dAdX; - state->z -= params->dZdX; - state->tmu0_s -= params->tmu[0].dSdX; - state->tmu0_t -= params->tmu[0].dTdX; - state->tmu0_w -= params->tmu[0].dWdX; - state->tmu1_s -= params->tmu[1].dSdX; - state->tmu1_t -= params->tmu[1].dTdX; - state->tmu1_w -= params->tmu[1].dWdX; - state->w -= params->dWdX; - } - - x += state->xdir; - } while (start_x != x2); - - voodoo->pixel_count[odd_even] += state->pixel_count; - voodoo->texel_count[odd_even] += state->texel_count; - voodoo->fbiPixelsIn += state->pixel_count; - - if (voodoo->params.draw_offset == voodoo->params.front_offset) - voodoo->dirty_line[real_y >> 1] = 1; -next_line: - if (SLI_ENABLED) - { - state->base_r += params->dRdY; - state->base_g += params->dGdY; - state->base_b += params->dBdY; - state->base_a += params->dAdY; - state->base_z += params->dZdY; - state->tmu[0].base_s += params->tmu[0].dSdY; - state->tmu[0].base_t += params->tmu[0].dTdY; - state->tmu[0].base_w += params->tmu[0].dWdY; - state->tmu[1].base_s += params->tmu[1].dSdY; - state->tmu[1].base_t += params->tmu[1].dTdY; - state->tmu[1].base_w += params->tmu[1].dWdY; - state->base_w += params->dWdY; - state->xstart += state->dx1; - state->xend += state->dx2; - } - state->base_r += params->dRdY; - state->base_g += params->dGdY; - state->base_b += params->dBdY; - state->base_a += params->dAdY; - state->base_z += params->dZdY; - state->tmu[0].base_s += params->tmu[0].dSdY; - state->tmu[0].base_t += params->tmu[0].dTdY; - state->tmu[0].base_w += params->tmu[0].dWdY; - state->tmu[1].base_s += params->tmu[1].dSdY; - state->tmu[1].base_t += params->tmu[1].dTdY; - state->tmu[1].base_w += params->tmu[1].dWdY; - state->base_w += params->dWdY; - state->xstart += state->dx1; - state->xend += state->dx2; - } - - voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++; - voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++; -} - -static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) -{ - voodoo_state_t state; - int vertexAy_adjusted; - int vertexCy_adjusted; - int dx, dy; - - uint64_t tempdx, tempdy; - uint64_t tempLOD; - int LOD; - int lodbias; - - memset(&state, 0x00, sizeof(voodoo_state_t)); - voodoo->tri_count++; - - dx = 8 - (params->vertexAx & 0xf); - if ((params->vertexAx & 0xf) > 8) - dx += 16; - dy = 8 - (params->vertexAy & 0xf); - if ((params->vertexAy & 0xf) > 8) - dy += 16; - -/* voodoo_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, - (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, - (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, - (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0, - (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ - - state.base_r = params->startR; - state.base_g = params->startG; - state.base_b = params->startB; - state.base_a = params->startA; - state.base_z = params->startZ; - state.tmu[0].base_s = params->tmu[0].startS; - state.tmu[0].base_t = params->tmu[0].startT; - state.tmu[0].base_w = params->tmu[0].startW; - state.tmu[1].base_s = params->tmu[1].startS; - state.tmu[1].base_t = params->tmu[1].startT; - state.tmu[1].base_w = params->tmu[1].startW; - state.base_w = params->startW; - - if (params->fbzColorPath & FBZ_PARAM_ADJUST) - { - state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4; - state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4; - state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4; - state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4; - state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4; - state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4; - state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4; - state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4; - state.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4; - state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4; - state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].dWdY) >> 4; - state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4; - } - - tris++; - - state.vertexAy = params->vertexAy & ~0xffff0000; - if (state.vertexAy & 0x8000) - state.vertexAy |= 0xffff0000; - state.vertexBy = params->vertexBy & ~0xffff0000; - if (state.vertexBy & 0x8000) - state.vertexBy |= 0xffff0000; - state.vertexCy = params->vertexCy & ~0xffff0000; - if (state.vertexCy & 0x8000) - state.vertexCy |= 0xffff0000; - - state.vertexAx = params->vertexAx & ~0xffff0000; - if (state.vertexAx & 0x8000) - state.vertexAx |= 0xffff0000; - state.vertexBx = params->vertexBx & ~0xffff0000; - if (state.vertexBx & 0x8000) - state.vertexBx |= 0xffff0000; - state.vertexCx = params->vertexCx & ~0xffff0000; - if (state.vertexCx & 0x8000) - state.vertexCx |= 0xffff0000; - - vertexAy_adjusted = (state.vertexAy+7) >> 4; - vertexCy_adjusted = (state.vertexCy+7) >> 4; - - if (state.vertexBy - state.vertexAy) - state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy); - else - state.dxAB = 0; - if (state.vertexCy - state.vertexAy) - state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy); - else - state.dxAC = 0; - if (state.vertexCy - state.vertexBy) - state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy); - else - state.dxBC = 0; - - state.lod_min[0] = (params->tLOD[0] & 0x3f) << 6; - state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6; - if (state.lod_max[0] > 0x800) - state.lod_max[0] = 0x800; - state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6; - state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6; - if (state.lod_max[1] > 0x800) - state.lod_max[1] = 0x800; - - state.xstart = state.xend = state.vertexAx << 8; - state.xdir = params->sign ? -1 : 1; - - state.y = (state.vertexAy + 8) >> 4; - state.ydir = 1; - - - tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14); - tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14); - - if (tempdx > tempdy) - tempLOD = tempdx; - else - tempLOD = tempdy; - - LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); - LOD >>= 2; - - lodbias = (params->tLOD[0] >> 12) & 0x3f; - if (lodbias & 0x20) - lodbias |= ~0x3f; - state.tmu[0].lod = LOD + (lodbias << 6); - - - tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14); - tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14); - - if (tempdx > tempdy) - tempLOD = tempdx; - else - tempLOD = tempdy; - - LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); - LOD >>= 2; - - lodbias = (params->tLOD[1] >> 12) & 0x3f; - if (lodbias & 0x20) - lodbias |= ~0x3f; - state.tmu[1].lod = LOD + (lodbias << 6); - - - voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); -} - -static inline void wake_render_thread(voodoo_t *voodoo) -{ - thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/ - if (voodoo->render_threads == 2) - thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/ -} - -static inline void wait_for_render_thread_idle(voodoo_t *voodoo) -{ - while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1])) - { - wake_render_thread(voodoo); - if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0]) - thread_wait_event(voodoo->render_not_full_event[0], 1); - if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1])) - thread_wait_event(voodoo->render_not_full_event[1], 1); - } -} - -static void render_thread(void *param, int odd_even) -{ - voodoo_t *voodoo = (voodoo_t *)param; - - while (1) - { - thread_set_event(voodoo->render_not_full_event[odd_even]); - thread_wait_event(voodoo->wake_render_thread[odd_even], -1); - thread_reset_event(voodoo->wake_render_thread[odd_even]); - voodoo->render_voodoo_busy[odd_even] = 1; - - while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1)) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK]; - - voodoo_triangle(voodoo, params, odd_even); - - voodoo->params_read_idx[odd_even]++; - - if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10)) - thread_set_event(voodoo->render_not_full_event[odd_even]); - - end_time = plat_timer_read(); - voodoo->render_time[odd_even] += end_time - start_time; - } - - voodoo->render_voodoo_busy[odd_even] = 0; - } -} - -static void render_thread_1(void *param) -{ - render_thread(param, 0); -} -static void render_thread_2(void *param) -{ - render_thread(param, 1); -} - -static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) -{ - voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK]; - - while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2)) - { - thread_reset_event(voodoo->render_not_full_event[0]); - if (voodoo->render_threads == 2) - thread_reset_event(voodoo->render_not_full_event[1]); - if (PARAM_FULL_1) - { - thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ - } - if (voodoo->render_threads == 2 && PARAM_FULL_2) - { - thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ - } - } - - use_texture(voodoo, params, 0); - if (voodoo->dual_tmus) - use_texture(voodoo, params, 1); - - memcpy(params_new, params, sizeof(voodoo_params_t)); - - voodoo->params_write_idx++; - - if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4)) - wake_render_thread(voodoo); -} - -static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) -{ - int y; - int low_y, high_y; - - if (params->fbzMode & (1 << 17)) - { - high_y = voodoo->v_disp - params->clipLowY; - low_y = voodoo->v_disp - params->clipHighY; - } - else - { - low_y = params->clipLowY; - high_y = params->clipHighY; - } - - if (params->fbzMode & FBZ_RGB_WMASK) - { - int r, g, b; - uint16_t col; - - r = ((params->color1 >> 16) >> 3) & 0x1f; - g = ((params->color1 >> 8) >> 2) & 0x3f; - b = (params->color1 >> 3) & 0x1f; - col = b | (g << 5) | (r << 11); - - if (SLI_ENABLED) - { - for (y = low_y; y < high_y; y += 2) - { - uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; - int x; - - for (x = params->clipLeft; x < params->clipRight; x++) - cbuf[x] = col; - } - } - else - { - for (y = low_y; y < high_y; y++) - { - uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y*voodoo->row_width) & voodoo->fb_mask]; - int x; - - for (x = params->clipLeft; x < params->clipRight; x++) - cbuf[x] = col; - } - } - } - if (params->fbzMode & FBZ_DEPTH_WMASK) - { - if (SLI_ENABLED) - { - for (y = low_y; y < high_y; y += 2) - { - uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; - int x; - - for (x = params->clipLeft; x < params->clipRight; x++) - abuf[x] = params->zaColor & 0xffff; - } - } - else - { - for (y = low_y; y < high_y; y++) - { - uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask]; - int x; - - for (x = params->clipLeft; x < params->clipRight; x++) - abuf[x] = params->zaColor & 0xffff; - } - } - } -} - -enum -{ - SETUPMODE_RGB = (1 << 0), - SETUPMODE_ALPHA = (1 << 1), - SETUPMODE_Z = (1 << 2), - SETUPMODE_Wb = (1 << 3), - SETUPMODE_W0 = (1 << 4), - SETUPMODE_S0_T0 = (1 << 5), - SETUPMODE_W1 = (1 << 6), - SETUPMODE_S1_T1 = (1 << 7), - - SETUPMODE_STRIP_MODE = (1 << 16), - SETUPMODE_CULLING_ENABLE = (1 << 17), - SETUPMODE_CULLING_SIGN = (1 << 18), - SETUPMODE_DISABLE_PINGPONG = (1 << 19) -}; - -static void triangle_setup(voodoo_t *voodoo) -{ - float dxAB, dxBC, dyAB, dyBC; - float area; - int va = 0, vb = 1, vc = 2; - int reverse_cull = 0; - - vert_t verts[3]; - - verts[0] = voodoo->verts[0]; - verts[1] = voodoo->verts[1]; - verts[2] = voodoo->verts[2]; - - if (verts[0].sVy < verts[1].sVy) - { - if (verts[1].sVy < verts[2].sVy) - { - /* V1>V0, V2>V1, V2>V1>V0*/ - va = 0; /*OK*/ - vb = 1; - vc = 2; - } - else - { - /* V1>V0, V1>V2*/ - if (verts[0].sVy < verts[2].sVy) - { - /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ - va = 0; - vb = 2; - vc = 1; - reverse_cull = 1; - } - else - { - /* V1>V0, V1>V2, V0>V2, V1>V0>V2*/ - va = 2; - vb = 0; - vc = 1; - } - } - } - else - { - if (verts[1].sVy < verts[2].sVy) - { - /* V0>V1, V2>V1*/ - if (verts[0].sVy < verts[2].sVy) - { - /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ - va = 1; - vb = 0; - vc = 2; - reverse_cull = 1; - } - else - { - /* V0>V1, V2>V1, V0>V2, V0>V2>V1*/ - va = 1; - vb = 2; - vc = 0; - } - } - else - { - /*V0>V1>V2*/ - va = 2; - vb = 1; - vc = 0; - reverse_cull = 1; - } - } - - dxAB = verts[va].sVx - verts[vb].sVx; - dxBC = verts[vb].sVx - verts[vc].sVx; - dyAB = verts[va].sVy - verts[vb].sVy; - dyBC = verts[vb].sVy - verts[vc].sVy; - - area = dxAB * dyBC - dxBC * dyAB; - - if (area == 0.0) - { - if ((voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) && - !(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) - voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; - - return; - } - - dxAB /= area; - dxBC /= area; - dyAB /= area; - dyBC /= area; - - if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) - { - int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; - int sign = (area < 0.0); - - if (!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) - voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; - - if (reverse_cull) - sign = !sign; - - if (cull_sign && sign) - return; - if (!cull_sign && !sign) - return; - } - - voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(verts[va].sVx * 16.0f) & 0xffff); - voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(verts[va].sVy * 16.0f) & 0xffff); - voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(verts[vb].sVx * 16.0f) & 0xffff); - voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(verts[vb].sVy * 16.0f) & 0xffff); - voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff); - voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff); - - if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) - fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); - - if (voodoo->sSetupMode & SETUPMODE_RGB) - { - voodoo->params.startR = (int32_t)(verts[va].sRed * 4096.0f); - voodoo->params.dRdX = (int32_t)(((verts[va].sRed - verts[vb].sRed) * dyBC - (verts[vb].sRed - verts[vc].sRed) * dyAB) * 4096.0f); - voodoo->params.dRdY = (int32_t)(((verts[vb].sRed - verts[vc].sRed) * dxAB - (verts[va].sRed - verts[vb].sRed) * dxBC) * 4096.0f); - voodoo->params.startG = (int32_t)(verts[va].sGreen * 4096.0f); - voodoo->params.dGdX = (int32_t)(((verts[va].sGreen - verts[vb].sGreen) * dyBC - (verts[vb].sGreen - verts[vc].sGreen) * dyAB) * 4096.0f); - voodoo->params.dGdY = (int32_t)(((verts[vb].sGreen - verts[vc].sGreen) * dxAB - (verts[va].sGreen - verts[vb].sGreen) * dxBC) * 4096.0f); - voodoo->params.startB = (int32_t)(verts[va].sBlue * 4096.0f); - voodoo->params.dBdX = (int32_t)(((verts[va].sBlue - verts[vb].sBlue) * dyBC - (verts[vb].sBlue - verts[vc].sBlue) * dyAB) * 4096.0f); - voodoo->params.dBdY = (int32_t)(((verts[vb].sBlue - verts[vc].sBlue) * dxAB - (verts[va].sBlue - verts[vb].sBlue) * dxBC) * 4096.0f); - } - if (voodoo->sSetupMode & SETUPMODE_ALPHA) - { - voodoo->params.startA = (int32_t)(verts[va].sAlpha * 4096.0f); - voodoo->params.dAdX = (int32_t)(((verts[va].sAlpha - verts[vb].sAlpha) * dyBC - (verts[vb].sAlpha - verts[vc].sAlpha) * dyAB) * 4096.0f); - voodoo->params.dAdY = (int32_t)(((verts[vb].sAlpha - verts[vc].sAlpha) * dxAB - (verts[va].sAlpha - verts[vb].sAlpha) * dxBC) * 4096.0f); - } - if (voodoo->sSetupMode & SETUPMODE_Z) - { - voodoo->params.startZ = (int32_t)(verts[va].sVz * 4096.0f); - voodoo->params.dZdX = (int32_t)(((verts[va].sVz - verts[vb].sVz) * dyBC - (verts[vb].sVz - verts[vc].sVz) * dyAB) * 4096.0f); - voodoo->params.dZdY = (int32_t)(((verts[vb].sVz - verts[vc].sVz) * dxAB - (verts[va].sVz - verts[vb].sVz) * dxBC) * 4096.0f); - } - if (voodoo->sSetupMode & SETUPMODE_Wb) - { - voodoo->params.startW = (int64_t)(verts[va].sWb * 4294967296.0f); - voodoo->params.dWdX = (int64_t)(((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f); - voodoo->params.dWdY = (int64_t)(((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f); - voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; - voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; - voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; - } - if (voodoo->sSetupMode & SETUPMODE_W0) - { - voodoo->params.tmu[0].startW = (int64_t)(verts[va].sW0 * 4294967296.0f); - voodoo->params.tmu[0].dWdX = (int64_t)(((verts[va].sW0 - verts[vb].sW0) * dyBC - (verts[vb].sW0 - verts[vc].sW0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dWdY = (int64_t)(((verts[vb].sW0 - verts[vc].sW0) * dxAB - (verts[va].sW0 - verts[vb].sW0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; - voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; - voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; - } - if (voodoo->sSetupMode & SETUPMODE_S0_T0) - { - voodoo->params.tmu[0].startS = (int64_t)(verts[va].sS0 * 4294967296.0f); - voodoo->params.tmu[0].dSdX = (int64_t)(((verts[va].sS0 - verts[vb].sS0) * dyBC - (verts[vb].sS0 - verts[vc].sS0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dSdY = (int64_t)(((verts[vb].sS0 - verts[vc].sS0) * dxAB - (verts[va].sS0 - verts[vb].sS0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[0].startT = (int64_t)(verts[va].sT0 * 4294967296.0f); - voodoo->params.tmu[0].dTdX = (int64_t)(((verts[va].sT0 - verts[vb].sT0) * dyBC - (verts[vb].sT0 - verts[vc].sT0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dTdY = (int64_t)(((verts[vb].sT0 - verts[vc].sT0) * dxAB - (verts[va].sT0 - verts[vb].sT0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; - voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; - voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; - voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT; - voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX; - voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY; - } - if (voodoo->sSetupMode & SETUPMODE_W1) - { - voodoo->params.tmu[1].startW = (int64_t)(verts[va].sW1 * 4294967296.0f); - voodoo->params.tmu[1].dWdX = (int64_t)(((verts[va].sW1 - verts[vb].sW1) * dyBC - (verts[vb].sW1 - verts[vc].sW1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dWdY = (int64_t)(((verts[vb].sW1 - verts[vc].sW1) * dxAB - (verts[va].sW1 - verts[vb].sW1) * dxBC) * 4294967296.0f); - } - if (voodoo->sSetupMode & SETUPMODE_S1_T1) - { - voodoo->params.tmu[1].startS = (int64_t)(verts[va].sS1 * 4294967296.0f); - voodoo->params.tmu[1].dSdX = (int64_t)(((verts[va].sS1 - verts[vb].sS1) * dyBC - (verts[vb].sS1 - verts[vc].sS1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dSdY = (int64_t)(((verts[vb].sS1 - verts[vc].sS1) * dxAB - (verts[va].sS1 - verts[vb].sS1) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startT = (int64_t)(verts[va].sT1 * 4294967296.0f); - voodoo->params.tmu[1].dTdX = (int64_t)(((verts[va].sT1 - verts[vb].sT1) * dyBC - (verts[vb].sT1 - verts[vc].sT1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dTdY = (int64_t)(((verts[vb].sT1 - verts[vc].sT1) * dxAB - (verts[va].sT1 - verts[vb].sT1) * dxBC) * 4294967296.0f); - } - - voodoo->params.sign = (area < 0.0); - - if (voodoo->ncc_dirty[0]) - voodoo_update_ncc(voodoo, 0); - if (voodoo->ncc_dirty[1]) - voodoo_update_ncc(voodoo, 1); - voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; - - queue_triangle(voodoo, &voodoo->params); -} - -enum -{ - BLIT_COMMAND_SCREEN_TO_SCREEN = 0, - BLIT_COMMAND_CPU_TO_SCREEN = 1, - BLIT_COMMAND_RECT_FILL = 2, - BLIT_COMMAND_SGRAM_FILL = 3 -}; - -enum -{ - BLIT_SRC_1BPP = (0 << 3), - BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3), - BLIT_SRC_16BPP = (2 << 3), - BLIT_SRC_24BPP = (3 << 3), - BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3), - BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3) -}; - -enum -{ - BLIT_SRC_RGB_ARGB = (0 << 6), - BLIT_SRC_RGB_ABGR = (1 << 6), - BLIT_SRC_RGB_RGBA = (2 << 6), - BLIT_SRC_RGB_BGRA = (3 << 6) -}; - -enum -{ - BLIT_COMMAND_MASK = 7, - BLIT_SRC_FORMAT = (7 << 3), - BLIT_SRC_RGB_FORMAT = (3 << 6), - BLIT_SRC_CHROMA = (1 << 10), - BLIT_DST_CHROMA = (1 << 12), - BLIT_CLIPPING_ENABLED = (1 << 16) -}; - -enum -{ - BLIT_ROP_DST_PASS = (1 << 0), - BLIT_ROP_SRC_PASS = (1 << 1) -}; - -#define MIX(src_dat, dst_dat, rop) \ - switch (rop) \ - { \ - case 0x0: dst_dat = 0; break; \ - case 0x1: dst_dat = ~(src_dat | dst_dat); break; \ - case 0x2: dst_dat = ~src_dat & dst_dat; break; \ - case 0x3: dst_dat = ~src_dat; break; \ - case 0x4: dst_dat = src_dat & ~dst_dat; break; \ - case 0x5: dst_dat = ~dst_dat; break; \ - case 0x6: dst_dat = src_dat ^ dst_dat; break; \ - case 0x7: dst_dat = ~(src_dat & dst_dat); break; \ - case 0x8: dst_dat = src_dat & dst_dat; break; \ - case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \ - case 0xa: dst_dat = dst_dat; break; \ - case 0xb: dst_dat = ~src_dat | dst_dat; break; \ - case 0xc: dst_dat = src_dat; break; \ - case 0xd: dst_dat = src_dat | ~dst_dat; break; \ - case 0xe: dst_dat = src_dat | dst_dat; break; \ - case 0xf: dst_dat = 0xffff; break; \ - } - -static void blit_start(voodoo_t *voodoo) -{ - uint64_t dat64; - int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); - int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; - int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; - int dst_x; - int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; - int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); - int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); - uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8); - uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); - int x, y; - -/* voodoo_log("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n", - voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/ - - wait_for_render_thread_idle(voodoo); - - switch (voodoo->bltCommand & BLIT_COMMAND_MASK) - { - case BLIT_COMMAND_SCREEN_TO_SCREEN: - for (y = 0; y <= size_y; y++) - { - uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride]; - uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; - int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX; - - for (x = 0; x <= size_x; x++) - { - uint16_t src_dat = src[src_x]; - uint16_t dst_dat = dst[dst_x]; - int rop = 0; - - if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) - { - if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || - dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) - goto skip_pixel_blit; - } - - if (voodoo->bltCommand & BLIT_SRC_CHROMA) - { - int r = (src_dat >> 11); - int g = (src_dat >> 5) & 0x3f; - int b = src_dat & 0x1f; - - if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && - g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && - b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) - rop |= BLIT_ROP_SRC_PASS; - } - if (voodoo->bltCommand & BLIT_DST_CHROMA) - { - int r = (dst_dat >> 11); - int g = (dst_dat >> 5) & 0x3f; - int b = dst_dat & 0x1f; - - if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && - g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && - b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) - rop |= BLIT_ROP_DST_PASS; - } - - MIX(src_dat, dst_dat, voodoo->bltRop[rop]); - - dst[dst_x] = dst_dat; -skip_pixel_blit: - src_x += x_dir; - dst_x += x_dir; - } - - src_y += y_dir; - dst_y += y_dir; - } - break; - - case BLIT_COMMAND_CPU_TO_SCREEN: - voodoo->blt.dst_x = voodoo->bltDstX; - voodoo->blt.dst_y = voodoo->bltDstY; - voodoo->blt.cur_x = 0; - voodoo->blt.size_x = size_x; - voodoo->blt.size_y = size_y; - voodoo->blt.x_dir = x_dir; - voodoo->blt.y_dir = y_dir; - voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); - break; - - case BLIT_COMMAND_RECT_FILL: - for (y = 0; y <= size_y; y++) - { - uint16_t *dst; - int dst_x = voodoo->bltDstX; - - if (SLI_ENABLED) - { - if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || - ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) - goto skip_line_fill; - dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride]; - } - else - dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; - - for (x = 0; x <= size_x; x++) - { - if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) - { - if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || - dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) - goto skip_pixel_fill; - } - - dst[dst_x] = voodoo->bltColorFg; -skip_pixel_fill: - dst_x += x_dir; - } -skip_line_fill: - dst_y += y_dir; - } - break; - - case BLIT_COMMAND_SGRAM_FILL: - /*32x32 tiles - 2kb*/ - dst_y = voodoo->bltDstY & 0x3ff; - size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb - size_y = voodoo->bltSizeY & 0x3ff; - - dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) | - ((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48); - - for (y = 0; y <= size_y; y++) - { - uint64_t *dst; - - /*This may be wrong*/ - if (!y) - { - dst_x = voodoo->bltDstX & 0x1ff; - size_x = 511 - dst_x; - } - else if (y < size_y) - { - dst_x = 0; - size_x = 511; - } - else - { - dst_x = 0; - size_x = voodoo->bltSizeX & 0x1ff; - } - - dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; - - for (x = 0; x <= size_x; x++) - dst[x] = dat64; - - dst_y++; - } - break; - - default: - fatal("bad blit command %08x\n", voodoo->bltCommand); - } -} - -static void blit_data(voodoo_t *voodoo, uint32_t data) -{ - int src_bits = 32; - uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); - uint32_t addr; - uint16_t *dst; - - if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) - return; - - if (SLI_ENABLED) - { - addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; - dst = (uint16_t *)&voodoo->fb_mem[addr]; - } - else - { - addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride; - dst = (uint16_t *)&voodoo->fb_mem[addr]; - } - - if (addr >= voodoo->front_offset && voodoo->row_width) - { - int y = (addr - voodoo->front_offset) / voodoo->row_width; - if (y < voodoo->v_disp) - voodoo->dirty_line[y] = 2; - } - - while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) - { - int r = 0, g = 0, b = 0; - uint16_t src_dat = 0, dst_dat; - int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); - int rop = 0; - - switch (voodoo->bltCommand & BLIT_SRC_FORMAT) - { - case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED: - src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg; - data >>= 1; - src_bits--; - break; - case BLIT_SRC_16BPP: - switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) - { - case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA: - src_dat = data & 0xffff; - break; - case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA: - src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11); - break; - } - data >>= 16; - src_bits -= 16; - break; - case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4: - switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) - { - case BLIT_SRC_RGB_ARGB: - r = (data >> 16) & 0xff; - g = (data >> 8) & 0xff; - b = data & 0xff; - break; - case BLIT_SRC_RGB_ABGR: - r = data & 0xff; - g = (data >> 8) & 0xff; - b = (data >> 16) & 0xff; - break; - case BLIT_SRC_RGB_RGBA: - r = (data >> 24) & 0xff; - g = (data >> 16) & 0xff; - b = (data >> 8) & 0xff; - break; - case BLIT_SRC_RGB_BGRA: - r = (data >> 8) & 0xff; - g = (data >> 16) & 0xff; - b = (data >> 24) & 0xff; - break; - } - switch (voodoo->bltCommand & BLIT_SRC_FORMAT) - { - case BLIT_SRC_24BPP: - src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); - break; - case BLIT_SRC_24BPP_DITHER_2X2: - r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1]; - g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1]; - b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1]; - src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); - break; - case BLIT_SRC_24BPP_DITHER_4X4: - r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3]; - g = dither_g[g][voodoo->blt.dst_y & 3][x & 3]; - b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3]; - src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); - break; - } - src_bits = 0; - break; - } - - if (SLI_ENABLED) - { - if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || - ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) - goto skip_pixel; - } - - if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) - { - if (x < voodoo->bltClipLeft || x >= voodoo->bltClipRight || - voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y >= voodoo->bltClipHighY) - goto skip_pixel; - } - - dst_dat = dst[x]; - - if (voodoo->bltCommand & BLIT_SRC_CHROMA) - { - r = (src_dat >> 11); - g = (src_dat >> 5) & 0x3f; - b = src_dat & 0x1f; - - if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && - g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && - b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) - rop |= BLIT_ROP_SRC_PASS; - } - if (voodoo->bltCommand & BLIT_DST_CHROMA) - { - r = (dst_dat >> 11); - g = (dst_dat >> 5) & 0x3f; - b = dst_dat & 0x1f; - - if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && - g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && - b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) - rop |= BLIT_ROP_DST_PASS; - } - - MIX(src_dat, dst_dat, voodoo->bltRop[rop]); - - dst[x] = dst_dat; - -skip_pixel: - voodoo->blt.cur_x++; - } - - if (voodoo->blt.cur_x > voodoo->blt.size_x) - { - voodoo->blt.size_y--; - if (voodoo->blt.size_y >= 0) - { - voodoo->blt.cur_x = 0; - voodoo->blt.dst_y += voodoo->blt.y_dir; - } - } -} - -enum -{ - CHIP_FBI = 0x1, - CHIP_TREX0 = 0x2, - CHIP_TREX1 = 0x4, - CHIP_TREX2 = 0x8 -}; - -static void wait_for_swap_complete(voodoo_t *voodoo) -{ - while (voodoo->swap_pending) - { - thread_wait_event(voodoo->wake_fifo_thread, -1); - thread_reset_event(voodoo->wake_fifo_thread); - if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL) - { - /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ - memset(voodoo->dirty_line, 1, 1024); - voodoo->front_offset = voodoo->params.front_offset; - if (voodoo->swap_count > 0) - voodoo->swap_count--; - voodoo->swap_pending = 0; - break; - } - } -} - -static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - union - { - uint32_t i; - float f; - } tempif; - int ad21 = addr & (1 << 21); - int chip = (addr >> 10) & 0xf; - if (!chip) - chip = 0xf; - - tempif.i = val; -//voodoo_log("voodoo_reg_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip); - addr &= 0x3fc; - - if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21) - addr |= 0x400; - switch (addr) - { - case SST_swapbufferCMD: -// voodoo_log(" start swap buffer command\n"); - - if (TRIPLE_BUFFER) - { - voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3; - voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3; - } - else - { - voodoo->disp_buffer = !voodoo->disp_buffer; - voodoo->draw_buffer = !voodoo->draw_buffer; - } - voodoo_recalc(voodoo); - - voodoo->params.swapbufferCMD = val; - - voodoo_log("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); -// voodoo->front_offset = params->front_offset; - wait_for_render_thread_idle(voodoo); - if (!(val & 1)) - { - memset(voodoo->dirty_line, 1, 1024); - voodoo->front_offset = voodoo->params.front_offset; - if (voodoo->swap_count > 0) - voodoo->swap_count--; - } - else if (TRIPLE_BUFFER) - { - if (voodoo->swap_pending) - wait_for_swap_complete(voodoo); - - voodoo->swap_interval = (val >> 1) & 0xff; - voodoo->swap_offset = voodoo->params.front_offset; - voodoo->swap_pending = 1; - } - else - { - voodoo->swap_interval = (val >> 1) & 0xff; - voodoo->swap_offset = voodoo->params.front_offset; - voodoo->swap_pending = 1; - - wait_for_swap_complete(voodoo); - } - voodoo->cmd_read++; - break; - - case SST_vertexAx: case SST_remap_vertexAx: - voodoo->params.vertexAx = val & 0xffff; - break; - case SST_vertexAy: case SST_remap_vertexAy: - voodoo->params.vertexAy = val & 0xffff; - break; - case SST_vertexBx: case SST_remap_vertexBx: - voodoo->params.vertexBx = val & 0xffff; - break; - case SST_vertexBy: case SST_remap_vertexBy: - voodoo->params.vertexBy = val & 0xffff; - break; - case SST_vertexCx: case SST_remap_vertexCx: - voodoo->params.vertexCx = val & 0xffff; - break; - case SST_vertexCy: case SST_remap_vertexCy: - voodoo->params.vertexCy = val & 0xffff; - break; - - case SST_startR: case SST_remap_startR: - voodoo->params.startR = val & 0xffffff; - break; - case SST_startG: case SST_remap_startG: - voodoo->params.startG = val & 0xffffff; - break; - case SST_startB: case SST_remap_startB: - voodoo->params.startB = val & 0xffffff; - break; - case SST_startZ: case SST_remap_startZ: - voodoo->params.startZ = val; - break; - case SST_startA: case SST_remap_startA: - voodoo->params.startA = val & 0xffffff; - break; - case SST_startS: case SST_remap_startS: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].startS = ((int64_t)(int32_t)val) << 14; - break; - case SST_startT: case SST_remap_startT: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].startT = ((int64_t)(int32_t)val) << 14; - break; - case SST_startW: case SST_remap_startW: - if (chip & CHIP_FBI) - voodoo->params.startW = (int64_t)(int32_t)val << 2; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].startW = (int64_t)(int32_t)val << 2; - break; - - case SST_dRdX: case SST_remap_dRdX: - voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dGdX: case SST_remap_dGdX: - voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dBdX: case SST_remap_dBdX: - voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dZdX: case SST_remap_dZdX: - voodoo->params.dZdX = val; - break; - case SST_dAdX: case SST_remap_dAdX: - voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dSdX: case SST_remap_dSdX: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dSdX = ((int64_t)(int32_t)val) << 14; - break; - case SST_dTdX: case SST_remap_dTdX: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dTdX = ((int64_t)(int32_t)val) << 14; - break; - case SST_dWdX: case SST_remap_dWdX: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dWdX = (int64_t)(int32_t)val << 2; - if (chip & CHIP_FBI) - voodoo->params.dWdX = (int64_t)(int32_t)val << 2; - break; - - case SST_dRdY: case SST_remap_dRdY: - voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dGdY: case SST_remap_dGdY: - voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dBdY: case SST_remap_dBdY: - voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dZdY: case SST_remap_dZdY: - voodoo->params.dZdY = val; - break; - case SST_dAdY: case SST_remap_dAdY: - voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); - break; - case SST_dSdY: case SST_remap_dSdY: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dSdY = ((int64_t)(int32_t)val) << 14; - break; - case SST_dTdY: case SST_remap_dTdY: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dTdY = ((int64_t)(int32_t)val) << 14; - break; - case SST_dWdY: case SST_remap_dWdY: - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dWdY = (int64_t)(int32_t)val << 2; - if (chip & CHIP_FBI) - voodoo->params.dWdY = (int64_t)(int32_t)val << 2; - break; - - case SST_triangleCMD: case SST_remap_triangleCMD: - voodoo->params.sign = val & (1 << 31); - - if (voodoo->ncc_dirty[0]) - voodoo_update_ncc(voodoo, 0); - if (voodoo->ncc_dirty[1]) - voodoo_update_ncc(voodoo, 1); - voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; - - queue_triangle(voodoo, &voodoo->params); - - voodoo->cmd_read++; - break; - - case SST_fvertexAx: case SST_remap_fvertexAx: - voodoo->fvertexAx.i = val; - voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff; - break; - case SST_fvertexAy: case SST_remap_fvertexAy: - voodoo->fvertexAy.i = val; - voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff; - break; - case SST_fvertexBx: case SST_remap_fvertexBx: - voodoo->fvertexBx.i = val; - voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff; - break; - case SST_fvertexBy: case SST_remap_fvertexBy: - voodoo->fvertexBy.i = val; - voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff; - break; - case SST_fvertexCx: case SST_remap_fvertexCx: - voodoo->fvertexCx.i = val; - voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff; - break; - case SST_fvertexCy: case SST_remap_fvertexCy: - voodoo->fvertexCy.i = val; - voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff; - break; - - case SST_fstartR: case SST_remap_fstartR: - tempif.i = val; - voodoo->params.startR = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fstartG: case SST_remap_fstartG: - tempif.i = val; - voodoo->params.startG = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fstartB: case SST_remap_fstartB: - tempif.i = val; - voodoo->params.startB = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fstartZ: case SST_remap_fstartZ: - tempif.i = val; - voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fstartA: case SST_remap_fstartA: - tempif.i = val; - voodoo->params.startA = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fstartS: case SST_remap_fstartS: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].startS = (int64_t)(tempif.f * 4294967296.0f); - break; - case SST_fstartT: case SST_remap_fstartT: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].startT = (int64_t)(tempif.f * 4294967296.0f); - break; - case SST_fstartW: case SST_remap_fstartW: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].startW = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_FBI) - voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f); - break; - - case SST_fdRdX: case SST_remap_fdRdX: - tempif.i = val; - voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdGdX: case SST_remap_fdGdX: - tempif.i = val; - voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdBdX: case SST_remap_fdBdX: - tempif.i = val; - voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdZdX: case SST_remap_fdZdX: - tempif.i = val; - voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdAdX: case SST_remap_fdAdX: - tempif.i = val; - voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdSdX: case SST_remap_fdSdX: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dSdX = (int64_t)(tempif.f * 4294967296.0f); - break; - case SST_fdTdX: case SST_remap_fdTdX: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dTdX = (int64_t)(tempif.f * 4294967296.0f); - break; - case SST_fdWdX: case SST_remap_fdWdX: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dWdX = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_FBI) - voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f); - break; - - case SST_fdRdY: case SST_remap_fdRdY: - tempif.i = val; - voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdGdY: case SST_remap_fdGdY: - tempif.i = val; - voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdBdY: case SST_remap_fdBdY: - tempif.i = val; - voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdZdY: case SST_remap_fdZdY: - tempif.i = val; - voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdAdY: case SST_remap_fdAdY: - tempif.i = val; - voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f); - break; - case SST_fdSdY: case SST_remap_fdSdY: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dSdY = (int64_t)(tempif.f * 4294967296.0f); - break; - case SST_fdTdY: case SST_remap_fdTdY: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dTdY = (int64_t)(tempif.f * 4294967296.0f); - break; - case SST_fdWdY: case SST_remap_fdWdY: - tempif.i = val; - if (chip & CHIP_TREX0) - voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].dWdY = (int64_t)(tempif.f * 4294967296.0f); - if (chip & CHIP_FBI) - voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f); - break; - - case SST_ftriangleCMD: - voodoo->params.sign = val & (1 << 31); - - if (voodoo->ncc_dirty[0]) - voodoo_update_ncc(voodoo, 0); - if (voodoo->ncc_dirty[1]) - voodoo_update_ncc(voodoo, 1); - voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; - - queue_triangle(voodoo, &voodoo->params); - - voodoo->cmd_read++; - break; - - case SST_fbzColorPath: - voodoo->params.fbzColorPath = val; - voodoo->rgb_sel = val & 3; - break; - - case SST_fogMode: - voodoo->params.fogMode = val; - break; - case SST_alphaMode: - voodoo->params.alphaMode = val; - break; - case SST_fbzMode: - voodoo->params.fbzMode = val; - voodoo_recalc(voodoo); - break; - case SST_lfbMode: - voodoo->lfbMode = val; - voodoo_recalc(voodoo); - break; - - case SST_clipLeftRight: - if (voodoo->type >= VOODOO_2) - { - voodoo->params.clipRight = val & 0xfff; - voodoo->params.clipLeft = (val >> 16) & 0xfff; - } - else - { - voodoo->params.clipRight = val & 0x3ff; - voodoo->params.clipLeft = (val >> 16) & 0x3ff; - } - break; - case SST_clipLowYHighY: - if (voodoo->type >= VOODOO_2) - { - voodoo->params.clipHighY = val & 0xfff; - voodoo->params.clipLowY = (val >> 16) & 0xfff; - } - else - { - voodoo->params.clipHighY = val & 0x3ff; - voodoo->params.clipLowY = (val >> 16) & 0x3ff; - } - break; - - case SST_nopCMD: - voodoo->cmd_read++; - voodoo->fbiPixelsIn = 0; - voodoo->fbiChromaFail = 0; - voodoo->fbiZFuncFail = 0; - voodoo->fbiAFuncFail = 0; - voodoo->fbiPixelsOut = 0; - break; - case SST_fastfillCMD: - wait_for_render_thread_idle(voodoo); - voodoo_fastfill(voodoo, &voodoo->params); - voodoo->cmd_read++; - break; - - case SST_fogColor: - voodoo->params.fogColor.r = (val >> 16) & 0xff; - voodoo->params.fogColor.g = (val >> 8) & 0xff; - voodoo->params.fogColor.b = val & 0xff; - break; - - case SST_zaColor: - voodoo->params.zaColor = val; - break; - case SST_chromaKey: - voodoo->params.chromaKey_r = (val >> 16) & 0xff; - voodoo->params.chromaKey_g = (val >> 8) & 0xff; - voodoo->params.chromaKey_b = val & 0xff; - voodoo->params.chromaKey = val & 0xffffff; - break; - case SST_stipple: - voodoo->params.stipple = val; - break; - case SST_color0: - voodoo->params.color0 = val; - break; - case SST_color1: - voodoo->params.color1 = val; - break; - - case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03: - case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07: - case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b: - case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f: - case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13: - case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17: - case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b: - case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f: - addr = (addr - SST_fogTable00) >> 1; - voodoo->params.fogTable[addr].dfog = val & 0xff; - voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff; - voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; - voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; - break; - - case SST_clutData: - voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; - voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; - voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; - if (val & 0x20000000) - { - voodoo->clutData[(val >> 24) & 0x3f].b = 255; - voodoo->clutData[(val >> 24) & 0x3f].g = 255; - voodoo->clutData[(val >> 24) & 0x3f].r = 255; - } - voodoo->clutData_dirty = 1; - break; - - case SST_sSetupMode: - voodoo->sSetupMode = val; - break; - case SST_sVx: - tempif.i = val; - voodoo->verts[3].sVx = tempif.f; -// voodoo_log("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f); - break; - case SST_sVy: - tempif.i = val; - voodoo->verts[3].sVy = tempif.f; -// voodoo_log("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f); - break; - case SST_sARGB: - voodoo->verts[3].sBlue = (float)(val & 0xff); - voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); - voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); - voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); - break; - case SST_sRed: - tempif.i = val; - voodoo->verts[3].sRed = tempif.f; - break; - case SST_sGreen: - tempif.i = val; - voodoo->verts[3].sGreen = tempif.f; - break; - case SST_sBlue: - tempif.i = val; - voodoo->verts[3].sBlue = tempif.f; - break; - case SST_sAlpha: - tempif.i = val; - voodoo->verts[3].sAlpha = tempif.f; - break; - case SST_sVz: - tempif.i = val; - voodoo->verts[3].sVz = tempif.f; - break; - case SST_sWb: - tempif.i = val; - voodoo->verts[3].sWb = tempif.f; - break; - case SST_sW0: - tempif.i = val; - voodoo->verts[3].sW0 = tempif.f; - break; - case SST_sS0: - tempif.i = val; - voodoo->verts[3].sS0 = tempif.f; - break; - case SST_sT0: - tempif.i = val; - voodoo->verts[3].sT0 = tempif.f; - break; - case SST_sW1: - tempif.i = val; - voodoo->verts[3].sW1 = tempif.f; - break; - case SST_sS1: - tempif.i = val; - voodoo->verts[3].sS1 = tempif.f; - break; - case SST_sT1: - tempif.i = val; - voodoo->verts[3].sT1 = tempif.f; - break; - - case SST_sBeginTriCMD: -// voodoo_log("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx); - voodoo->verts[0] = voodoo->verts[3]; - voodoo->vertex_num = 1; - voodoo->num_verticies = 1; - break; - case SST_sDrawTriCMD: -// voodoo_log("sDrawTriCMD %i %i %i\n", voodoo->num_verticies, voodoo->vertex_num, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); - if (voodoo->vertex_num == 3) - voodoo->vertex_num = (voodoo->sSetupMode & SETUPMODE_STRIP_MODE) ? 1 : 0; - voodoo->verts[voodoo->vertex_num] = voodoo->verts[3]; - - voodoo->num_verticies++; - voodoo->vertex_num++; - if (voodoo->num_verticies == 3) - { -// voodoo_log("triangle_setup\n"); - triangle_setup(voodoo); - - voodoo->num_verticies = 2; - } - if (voodoo->vertex_num == 4) - fatal("sDrawTriCMD overflow\n"); - break; - - case SST_bltSrcBaseAddr: - voodoo->bltSrcBaseAddr = val & 0x3fffff; - break; - case SST_bltDstBaseAddr: -// voodoo_log("Write bltDstBaseAddr %08x\n", val); - voodoo->bltDstBaseAddr = val & 0x3fffff; - break; - case SST_bltXYStrides: - voodoo->bltSrcXYStride = val & 0xfff; - voodoo->bltDstXYStride = (val >> 16) & 0xfff; -// voodoo_log("Write bltXYStrides %08x\n", val); - break; - case SST_bltSrcChromaRange: - voodoo->bltSrcChromaRange = val; - voodoo->bltSrcChromaMinB = val & 0x1f; - voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; - voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; - voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; - voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; - voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; - break; - case SST_bltDstChromaRange: - voodoo->bltDstChromaRange = val; - voodoo->bltDstChromaMinB = val & 0x1f; - voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; - voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; - voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; - voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; - voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; - break; - case SST_bltClipX: - voodoo->bltClipRight = val & 0xfff; - voodoo->bltClipLeft = (val >> 16) & 0xfff; - break; - case SST_bltClipY: - voodoo->bltClipHighY = val & 0xfff; - voodoo->bltClipLowY = (val >> 16) & 0xfff; - break; - - case SST_bltSrcXY: - voodoo->bltSrcX = val & 0x7ff; - voodoo->bltSrcY = (val >> 16) & 0x7ff; - break; - case SST_bltDstXY: -// voodoo_log("Write bltDstXY %08x\n", val); - voodoo->bltDstX = val & 0x7ff; - voodoo->bltDstY = (val >> 16) & 0x7ff; - if (val & (1 << 31)) - blit_start(voodoo); - break; - case SST_bltSize: -// voodoo_log("Write bltSize %08x\n", val); - voodoo->bltSizeX = val & 0xfff; - if (voodoo->bltSizeX & 0x800) - voodoo->bltSizeX |= 0xfffff000; - voodoo->bltSizeY = (val >> 16) & 0xfff; - if (voodoo->bltSizeY & 0x800) - voodoo->bltSizeY |= 0xfffff000; - if (val & (1 << 31)) - blit_start(voodoo); - break; - case SST_bltRop: - voodoo->bltRop[0] = val & 0xf; - voodoo->bltRop[1] = (val >> 4) & 0xf; - voodoo->bltRop[2] = (val >> 8) & 0xf; - voodoo->bltRop[3] = (val >> 12) & 0xf; - break; - case SST_bltColor: -// voodoo_log("Write bltColor %08x\n", val); - voodoo->bltColorFg = val & 0xffff; - voodoo->bltColorBg = (val >> 16) & 0xffff; - break; - - case SST_bltCommand: - voodoo->bltCommand = val; -// voodoo_log("Write bltCommand %08x\n", val); - if (val & (1 << 31)) - blit_start(voodoo); - break; - case SST_bltData: - blit_data(voodoo, val); - break; - - case SST_textureMode: - if (chip & CHIP_TREX0) - { - voodoo->params.textureMode[0] = val; - voodoo->params.tformat[0] = (val >> 8) & 0xf; - } - if (chip & CHIP_TREX1) - { - voodoo->params.textureMode[1] = val; - voodoo->params.tformat[1] = (val >> 8) & 0xf; - } - break; - case SST_tLOD: - if (chip & CHIP_TREX0) - { - voodoo->params.tLOD[0] = val; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.tLOD[1] = val; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_tDetail: - if (chip & CHIP_TREX0) - { - voodoo->params.detail_max[0] = val & 0xff; - voodoo->params.detail_bias[0] = (val >> 8) & 0x3f; - voodoo->params.detail_scale[0] = (val >> 14) & 7; - } - if (chip & CHIP_TREX1) - { - voodoo->params.detail_max[1] = val & 0xff; - voodoo->params.detail_bias[1] = (val >> 8) & 0x3f; - voodoo->params.detail_scale[1] = (val >> 14) & 7; - } - break; - case SST_texBaseAddr: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_texBaseAddr1: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_texBaseAddr2: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_texBaseAddr38: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - - case SST_trexInit1: - if (chip & CHIP_TREX0) - voodoo->trexInit1[0] = val; - if (chip & CHIP_TREX1) - voodoo->trexInit1[1] = val; - break; - - case SST_nccTable0_Y0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable0_Y1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable0_Y2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable0_Y3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - - case SST_nccTable0_I0: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_I2: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q0: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].q[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].q[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q2: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - if (val & (1 << 31)) - { - int p = (val >> 23) & 0xfe; - if (chip & CHIP_TREX0) - { - voodoo->palette[0][p].u = val | 0xff000000; - voodoo->palette_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->palette[1][p].u = val | 0xff000000; - voodoo->palette_dirty[1] = 1; - } - } - break; - - case SST_nccTable0_I1: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_I3: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q1: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].q[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].q[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q3: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].q[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].q[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - if (val & (1 << 31)) - { - int p = ((val >> 23) & 0xfe) | 0x01; - if (chip & CHIP_TREX0) - { - voodoo->palette[0][p].u = val | 0xff000000; - voodoo->palette_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->palette[1][p].u = val | 0xff000000; - voodoo->palette_dirty[1] = 1; - } - } - break; - - case SST_nccTable1_Y0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Y1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Y2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Y3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - - case SST_userIntrCMD: - fatal("userIntrCMD write %08x from FIFO\n", val); - break; - } -} - - -static uint16_t voodoo_fb_readw(uint32_t addr, void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - int x, y; - uint32_t read_addr; - uint16_t temp; - - x = (addr >> 1) & 0x3ff; - y = (addr >> 11) & 0x3ff; - - if (SLI_ENABLED) - { - voodoo_set_t *set = voodoo->set; - - if (y & 1) - voodoo = set->voodoos[1]; - else - voodoo = set->voodoos[0]; - - y >>= 1; - } - - read_addr = voodoo->fb_read_offset + (x << 1) + (y * voodoo->row_width); - - if (read_addr > voodoo->fb_mask) - return 0xffff; - - temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); - -// voodoo_log("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++); - return temp; -} -static uint32_t voodoo_fb_readl(uint32_t addr, void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - int x, y; - uint32_t read_addr; - uint32_t temp; - - x = addr & 0x7fe; - y = (addr >> 11) & 0x3ff; - - if (SLI_ENABLED) - { - voodoo_set_t *set = voodoo->set; - - if (y & 1) - voodoo = set->voodoos[1]; - else - voodoo = set->voodoos[0]; - - y >>= 1; - } - - read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); - - if (read_addr > voodoo->fb_mask) - return 0xffffffff; - - temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); - -// voodoo_log("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width); - return temp; -} - -static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y) -{ - int r, g, b; - - if (dither) - { - if (dither2x2) - { - r = dither_rb2x2[col.r][y & 1][x & 1]; - g = dither_g2x2[col.g][y & 1][x & 1]; - b = dither_rb2x2[col.b][y & 1][x & 1]; - } - else - { - r = dither_rb[col.r][y & 3][x & 3]; - g = dither_g[col.g][y & 3][x & 3]; - b = dither_rb[col.b][y & 3][x & 3]; - } - } - else - { - r = col.r >> 3; - g = col.g >> 2; - b = col.b >> 3; - } - - return b | (g << 5) | (r << 11); -} - -static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - voodoo_params_t *params = &voodoo->params; - int x, y; - uint32_t write_addr, write_addr_aux; - rgba8_t colour_data; - uint16_t depth_data; - uint8_t alpha_data; - int write_mask = 0; - - colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; - - depth_data = voodoo->params.zaColor & 0xffff; - alpha_data = voodoo->params.zaColor >> 24; - -// while (!RB_EMPTY) -// thread_reset_event(voodoo->not_full_event); - -// voodoo_log("voodoo_fb_writew : %08X %04X\n", addr, val); - - - switch (voodoo->lfbMode & LFB_FORMAT_MASK) - { - case LFB_FORMAT_RGB565: - colour_data = rgb565[val]; - alpha_data = 0xff; - write_mask = LFB_WRITE_COLOUR; - break; - case LFB_FORMAT_RGB555: - colour_data = argb1555[val]; - alpha_data = 0xff; - write_mask = LFB_WRITE_COLOUR; - break; - case LFB_FORMAT_ARGB1555: - colour_data = argb1555[val]; - alpha_data = colour_data.a; - write_mask = LFB_WRITE_COLOUR; - break; - case LFB_FORMAT_DEPTH: - depth_data = val; - write_mask = LFB_WRITE_DEPTH; - break; - - default: - fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); - } - - x = addr & 0x7fe; - y = (addr >> 11) & 0x3ff; - - if (SLI_ENABLED) - { - if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || - ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) - return; - y >>= 1; - } - - - if (voodoo->fb_write_offset == voodoo->params.front_offset) - voodoo->dirty_line[y] = 1; - - write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); - write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); - -// voodoo_log("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr); - - if (voodoo->lfbMode & 0x100) - { - { - rgba8_t write_data = colour_data; - uint16_t new_depth = depth_data; - - if (params->fbzMode & FBZ_DEPTH_ENABLE) - { - uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); - - DEPTH_TEST(new_depth); - } - - if ((params->fbzMode & FBZ_CHROMAKEY) && - write_data.r == params->chromaKey_r && - write_data.g == params->chromaKey_g && - write_data.b == params->chromaKey_b) - goto skip_pixel; - - if (params->fogMode & FOG_ENABLE) - { - int32_t z = new_depth << 12; - int64_t w_depth = (int64_t)(int32_t)new_depth; - int32_t ia = alpha_data << 12; - - APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); - } - - if (params->alphaMode & 1) - ALPHA_TEST(alpha_data); - - if (params->alphaMode & (1 << 4)) - { - uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); - int dest_r, dest_g, dest_b, dest_a; - - dest_r = (dat >> 8) & 0xf8; - dest_g = (dat >> 3) & 0xfc; - dest_b = (dat << 3) & 0xf8; - dest_r |= (dest_r >> 5); - dest_g |= (dest_g >> 6); - dest_b |= (dest_b >> 5); - dest_a = 0xff; - - ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data); - } - - if (params->fbzMode & FBZ_RGB_WMASK) - *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y); - if (params->fbzMode & FBZ_DEPTH_WMASK) - *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; - -skip_pixel: - (void)x; - } - } - else - { - if (write_mask & LFB_WRITE_COLOUR) - *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y); - if (write_mask & LFB_WRITE_DEPTH) - *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data; - } -} - - -static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - voodoo_params_t *params = &voodoo->params; - int x, y; - uint32_t write_addr, write_addr_aux; - rgba8_t colour_data[2]; - uint16_t depth_data[2]; - uint8_t alpha_data[2]; - int write_mask = 0, count = 1; - - depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; - alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; -// while (!RB_EMPTY) -// thread_reset_event(voodoo->not_full_event); - -// voodoo_log("voodoo_fb_writel : %08X %08X\n", addr, val); - - switch (voodoo->lfbMode & LFB_FORMAT_MASK) - { - case LFB_FORMAT_RGB565: - colour_data[0] = rgb565[val & 0xffff]; - colour_data[1] = rgb565[val >> 16]; - write_mask = LFB_WRITE_COLOUR; - count = 2; - break; - case LFB_FORMAT_RGB555: - colour_data[0] = argb1555[val & 0xffff]; - colour_data[1] = argb1555[val >> 16]; - write_mask = LFB_WRITE_COLOUR; - count = 2; - break; - case LFB_FORMAT_ARGB1555: - colour_data[0] = argb1555[val & 0xffff]; - alpha_data[0] = colour_data[0].a; - colour_data[1] = argb1555[val >> 16]; - alpha_data[1] = colour_data[1].a; - write_mask = LFB_WRITE_COLOUR; - count = 2; - break; - - case LFB_FORMAT_ARGB8888: - colour_data[0].b = val & 0xff; - colour_data[0].g = (val >> 8) & 0xff; - colour_data[0].r = (val >> 16) & 0xff; - colour_data[0].a = alpha_data[0] = (val >> 24) & 0xff; - write_mask = LFB_WRITE_COLOUR; - addr >>= 1; - break; - - case LFB_FORMAT_DEPTH: - depth_data[0] = val; - depth_data[1] = val >> 16; - write_mask = LFB_WRITE_DEPTH; - count = 2; - break; - - default: - fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); - } - - x = addr & 0x7fe; - y = (addr >> 11) & 0x3ff; - - if (SLI_ENABLED) - { - if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || - ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) - return; - y >>= 1; - } - - if (voodoo->fb_write_offset == voodoo->params.front_offset) - voodoo->dirty_line[y] = 1; - - write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); - write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); - -// voodoo_log("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset); - - if (voodoo->lfbMode & 0x100) - { - int c; - - for (c = 0; c < count; c++) - { - rgba8_t write_data = colour_data[c]; - uint16_t new_depth = depth_data[c]; - - if (params->fbzMode & FBZ_DEPTH_ENABLE) - { - uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); - - DEPTH_TEST(new_depth); - } - - if ((params->fbzMode & FBZ_CHROMAKEY) && - write_data.r == params->chromaKey_r && - write_data.g == params->chromaKey_g && - write_data.b == params->chromaKey_b) - goto skip_pixel; - - if (params->fogMode & FOG_ENABLE) - { - int32_t z = new_depth << 12; - int64_t w_depth = new_depth; - int32_t ia = alpha_data[c] << 12; - - APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); - } - - if (params->alphaMode & 1) - ALPHA_TEST(alpha_data[c]); - - if (params->alphaMode & (1 << 4)) - { - uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); - int dest_r, dest_g, dest_b, dest_a; - - dest_r = (dat >> 8) & 0xf8; - dest_g = (dat >> 3) & 0xfc; - dest_b = (dat << 3) & 0xf8; - dest_r |= (dest_r >> 5); - dest_g |= (dest_g >> 6); - dest_b |= (dest_b >> 5); - dest_a = 0xff; - - ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]); - } - - if (params->fbzMode & FBZ_RGB_WMASK) - *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y); - if (params->fbzMode & FBZ_DEPTH_WMASK) - *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; - -skip_pixel: - write_addr += 2; - write_addr_aux += 2; - } - } - else - { - int c; - - for (c = 0; c < count; c++) - { - if (write_mask & LFB_WRITE_COLOUR) - *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y); - if (write_mask & LFB_WRITE_DEPTH) - *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c]; - - write_addr += 2; - write_addr_aux += 2; - } - } -} - -static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) -{ - int lod, s, t; - voodoo_t *voodoo = (voodoo_t *)p; - int tmu; - - if (addr & 0x400000) - return; /*TREX != 0*/ - - tmu = (addr & 0x200000) ? 1 : 0; - - if (tmu && !voodoo->dual_tmus) - return; - -// voodoo_log("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat); - - lod = (addr >> 17) & 0xf; - t = (addr >> 9) & 0xff; - if (voodoo->params.tformat[tmu] & 8) - s = (addr >> 1) & 0xfe; - else - { - if (voodoo->params.textureMode[tmu] & (1 << 31)) - s = addr & 0xfc; - else - s = (addr >> 1) & 0xfc; - } - - if (lod > LOD_MAX) - return; - -// if (addr >= 0x200000) -// return; - - if (voodoo->params.tformat[tmu] & 8) - addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; - else - addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); - if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) - { -// voodoo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); - flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); - } - *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; -} - -#define WAKE_DELAY (TIMER_USEC * 100) -static inline void wake_fifo_thread(voodoo_t *voodoo) -{ - if (!timer_is_enabled(&voodoo->wake_timer)) - { - /*Don't wake FIFO thread immediately - if we do that it will probably - process one word and go back to sleep, requiring it to be woken on - almost every write. Instead, wait a short while so that the CPU - emulation writes more data so we have more batched-up work.*/ - timer_set_delay_u64(&voodoo->wake_timer, WAKE_DELAY); - } -} - -static inline void wake_fifo_thread_now(voodoo_t *voodoo) -{ - thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} - -static void voodoo_wake_timer(void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - - thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} - -static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) -{ - fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; - - while (FIFO_FULL) - { - thread_reset_event(voodoo->fifo_not_full_event); - if (FIFO_FULL) - { - thread_wait_event(voodoo->fifo_not_full_event, 1); /*Wait for room in ringbuffer*/ - if (FIFO_FULL) - wake_fifo_thread_now(voodoo); - } - } - - fifo->val = val; - fifo->addr_type = addr_type; - - voodoo->fifo_write_idx++; - - if (FIFO_ENTRIES > 0xe000) - wake_fifo_thread(voodoo); -} static uint16_t voodoo_readw(uint32_t addr, void *p) { voodoo_t *voodoo = (voodoo_t *)p; - + addr &= 0xffffff; - sub_cycles(voodoo->read_time); - + cycles -= voodoo->read_time; + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ { if (SLI_ENABLED) { voodoo_set_t *set = voodoo->set; int y = (addr >> 11) & 0x3ff; - + if (y & 1) voodoo = set->voodoos[1]; else @@ -5979,46 +170,28 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) voodoo->flush = 1; while (!FIFO_EMPTY) { - wake_fifo_thread_now(voodoo); + voodoo_wake_fifo_thread_now(voodoo); thread_wait_event(voodoo->fifo_not_full_event, 1); } - wait_for_render_thread_idle(voodoo); + voodoo_wait_for_render_thread_idle(voodoo); voodoo->flush = 0; - + return voodoo_fb_readw(addr, voodoo); } return 0xffff; } -static void voodoo_flush(voodoo_t *voodoo) -{ - voodoo->flush = 1; - while (!FIFO_EMPTY) - { - wake_fifo_thread_now(voodoo); - thread_wait_event(voodoo->fifo_not_full_event, 1); - } - wait_for_render_thread_idle(voodoo); - voodoo->flush = 0; -} - -static void wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo) -{ - wake_fifo_thread(voodoo); - if (SLI_ENABLED && voodoo->type != VOODOO_2 && set->voodoos[0] == voodoo) - wake_fifo_thread(set->voodoos[1]); -} static uint32_t voodoo_readl(uint32_t addr, void *p) { voodoo_t *voodoo = (voodoo_t *)p; - uint32_t temp = 0; + uint32_t temp = 0xffffffff; int fifo_size; voodoo->rd_count++; addr &= 0xffffff; - - sub_cycles(voodoo->read_time); + + cycles -= voodoo->read_time; if (addr & 0x800000) /*Texture*/ { @@ -6029,7 +202,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) { voodoo_set_t *set = voodoo->set; int y = (addr >> 11) & 0x3ff; - + if (y & 1) voodoo = set->voodoos[1]; else @@ -6039,12 +212,12 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) voodoo->flush = 1; while (!FIFO_EMPTY) { - wake_fifo_thread_now(voodoo); + voodoo_wake_fifo_thread_now(voodoo); thread_wait_event(voodoo->fifo_not_full_event, 1); } - wait_for_render_thread_idle(voodoo); + voodoo_wait_for_render_thread_idle(voodoo); voodoo->flush = 0; - + temp = voodoo_fb_readl(addr, voodoo); } else switch (addr & 0x3fc) @@ -6060,7 +233,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) { voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0]; int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo; - + if (voodoo_other->swap_count > swap_count) swap_count = voodoo_other->swap_count; if ((voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx) > fifo_entries) @@ -6069,9 +242,9 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) (voodoo_other->cmdfifo_depth_rd != voodoo_other->cmdfifo_depth_wr)) busy = 1; if (!voodoo_other->voodoo_busy) - wake_fifo_thread(voodoo_other); + voodoo_wake_fifo_thread(voodoo_other); } - + fifo_size = 0xffff - fifo_entries; temp = fifo_size << 12; if (fifo_size < 0x40) @@ -6089,7 +262,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp |= 0x380; /*Busy*/ if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_thread(voodoo); } break; @@ -6108,7 +281,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) case SST_fbzMode: voodoo_flush(voodoo); temp = voodoo->params.fbzMode; - break; + break; case SST_lfbMode: voodoo_flush(voodoo); temp = voodoo->lfbMode; @@ -6134,7 +307,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) voodoo_flush(voodoo); temp = voodoo->params.color1; break; - + case SST_fbiPixelsIn: temp = voodoo->fbiPixelsIn & 0xffffff; break; @@ -6159,7 +332,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) break; case SST_fbiInit1: temp = voodoo->fbiInit1; - break; + break; case SST_fbiInit2: if (voodoo->initEnable & 0x04) temp = voodoo->dac_readdata; @@ -6174,20 +347,20 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp = voodoo->line & 0x1fff; break; case SST_hvRetrace: - { - uint32_t line_time = (uint32_t)(voodoo->line_time >> 32); - uint32_t diff = (timer_get_ts_int(&voodoo->timer) > (tsc & 0xffffffff)) ? (timer_get_ts_int(&voodoo->timer) - (tsc & 0xffffffff)) : 0; - uint32_t pre_div = diff * voodoo->h_total; - uint32_t post_div = pre_div / line_time; - uint32_t h_pos = (voodoo->h_total - 1) - post_div; - - if (h_pos >= voodoo->h_total) - h_pos = 0; - - temp = voodoo->line & 0x1fff; - temp |= (h_pos << 16); + { + uint32_t line_time = (uint32_t)(voodoo->line_time >> 32); + uint32_t diff = (timer_get_ts_int(&voodoo->timer) > (tsc & 0xffffffff)) ? (timer_get_ts_int(&voodoo->timer) - (tsc & 0xffffffff)) : 0; + uint32_t pre_div = diff * voodoo->h_total; + uint32_t post_div = pre_div / line_time; + uint32_t h_pos = (voodoo->h_total - 1) - post_div; + + if (h_pos >= voodoo->h_total) + h_pos = 0; + + temp = voodoo->line & 0x1fff; + temp |= (h_pos << 16); } - break; + break; case SST_fbiInit5: temp = voodoo->fbiInit5 & ~0x1ff; @@ -6203,7 +376,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp = voodoo->cmdfifo_base >> 12; temp |= (voodoo->cmdfifo_end >> 12) << 16; break; - + case SST_cmdFifoRdPtr: temp = voodoo->cmdfifo_rp; break; @@ -6216,12 +389,12 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) case SST_cmdFifoDepth: temp = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; break; - + default: - fatal("voodoo_readl : bad addr %08X\n", addr); + voodoo_log("voodoo_readl : bad addr %08X\n", addr); temp = 0xffffffff; } - + return temp; } @@ -6231,38 +404,10 @@ static void voodoo_writew(uint32_t addr, uint16_t val, void *p) voodoo->wr_count++; addr &= 0xffffff; - if (addr == voodoo->last_write_addr+4) - sub_cycles(voodoo->burst_time); - else - sub_cycles(voodoo->write_time); - voodoo->last_write_addr = addr; + cycles -= voodoo->write_time; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ - queue_command(voodoo, addr | FIFO_WRITEW_FB, val); -} - -static void voodoo_pixelclock_update(voodoo_t *voodoo) -{ - int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; - int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; - int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); - float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); - double clock_const; - int line_length; - - if ((voodoo->dac_data[6] & 0xf0) == 0x20 || - (voodoo->dac_data[6] & 0xf0) == 0x60 || - (voodoo->dac_data[6] & 0xf0) == 0x70) - t /= 2.0f; - - line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff); - -// voodoo_log("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length); - - voodoo->pixel_clock = t; - - clock_const = cpuclock / t; - voodoo->line_time = (uint64_t)((double)line_length * clock_const * (double)(1ULL << 32)); + voodoo_queue_command(voodoo, addr | FIFO_WRITEW_FB, val); } static void voodoo_writel(uint32_t addr, uint32_t val, void *p) @@ -6272,21 +417,21 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) voodoo->wr_count++; addr &= 0xffffff; - + if (addr == voodoo->last_write_addr+4) - sub_cycles(voodoo->burst_time); + cycles -= voodoo->burst_time; else - sub_cycles(voodoo->write_time); + cycles -= voodoo->write_time; voodoo->last_write_addr = addr; if (addr & 0x800000) /*Texture*/ { voodoo->tex_count++; - queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); } else if (addr & 0x400000) /*Framebuffer*/ { - queue_command(voodoo, addr | FIFO_WRITEL_FB, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_FB, val); } else if ((addr & 0x200000) && (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)) { @@ -6294,7 +439,7 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) *(uint32_t *)&voodoo->fb_mem[(voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask] = val; voodoo->cmdfifo_depth_wr++; if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_thread(voodoo); } else switch (addr & 0x3fc) { @@ -6305,49 +450,51 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) case SST_userIntrCMD: fatal("userIntrCMD write %08x\n", val); break; - + case SST_swapbufferCMD: voodoo->cmd_written++; + thread_wait_mutex(voodoo->swap_mutex); voodoo->swap_count++; + thread_release_mutex(voodoo->swap_mutex); if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_threads(voodoo->set, voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_triangleCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_threads(voodoo->set, voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_ftriangleCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_threads(voodoo->set, voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_fastfillCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_threads(voodoo->set, voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_nopCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_threads(voodoo->set, voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; - + case SST_fbiInit4: if (voodoo->initEnable & 0x01) { @@ -6368,6 +515,12 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) if (voodoo->initEnable & 0x01) { voodoo->fbiInit0 = val; + thread_wait_mutex(voodoo->force_blit_mutex); + voodoo->can_blit = (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) ? 1 : 0; + if (!voodoo->can_blit) + voodoo->force_blit_count = 0; + thread_release_mutex(voodoo->force_blit_mutex); + if (voodoo->set->nr_cards == 2) svga_set_override(voodoo->svga, (voodoo->set->voodoos[0]->fbiInit0 | voodoo->set->voodoos[1]->fbiInit0) & 1); else @@ -6389,7 +542,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) if ((voodoo->fbiInit1 & FBIINIT1_VIDEO_RESET) && !(val & FBIINIT1_VIDEO_RESET)) { voodoo->line = 0; + thread_wait_mutex(voodoo->swap_mutex); voodoo->swap_count = 0; + thread_release_mutex(voodoo->swap_mutex); voodoo->retrace_count = 0; } voodoo->fbiInit1 = (val & ~5) | (voodoo->fbiInit1 & 5); @@ -6419,7 +574,7 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) voodoo->vSync = val; voodoo->v_total = (val & 0xffff) + (val >> 16); break; - + case SST_clutData: voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; @@ -6479,10 +634,10 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) { voodoo->scrfilterEnabled = 1; voodoo->scrfilterThreshold = val; /* update the threshold values and generate a new lookup table if necessary */ - - if (val < 1) + + if (val < 1) voodoo->scrfilterEnabled = 0; - voodoo_threshold_check(voodoo); + voodoo_threshold_check(voodoo); voodoo_log("Voodoo Filter: %06x\n", val); } break; @@ -6497,7 +652,10 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) break; case SST_fbiInit7: if (voodoo->initEnable & 0x01) + { voodoo->fbiInit7 = val; + voodoo->cmdfifo_enabled = val & 0x100; + } break; case SST_cmdFifoBaseAddr: @@ -6527,7 +685,7 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) } else { - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); } break; } @@ -6536,13 +694,13 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) static uint16_t voodoo_snoop_readw(uint32_t addr, void *p) { voodoo_set_t *set = (voodoo_set_t *)p; - + return voodoo_readw(addr, set->voodoos[0]); } static uint32_t voodoo_snoop_readl(uint32_t addr, void *p) { voodoo_set_t *set = (voodoo_set_t *)p; - + return voodoo_readl(addr, set->voodoos[0]); } @@ -6561,274 +719,6 @@ static void voodoo_snoop_writel(uint32_t addr, uint32_t val, void *p) voodoo_writel(addr, val, set->voodoos[1]); } -static uint32_t cmdfifo_get(voodoo_t *voodoo) -{ - uint32_t val; - - while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) - { - thread_wait_event(voodoo->wake_fifo_thread, -1); - thread_reset_event(voodoo->wake_fifo_thread); - } - - val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; - - voodoo->cmdfifo_depth_rd++; - voodoo->cmdfifo_rp += 4; - -// voodoo_log(" CMDFIFO get %08x\n", val); - return val; -} - -static inline float cmdfifo_get_f(voodoo_t *voodoo) -{ - union - { - uint32_t i; - float f; - } tempif; - - tempif.i = cmdfifo_get(voodoo); - return tempif.f; -} - -enum -{ - CMDFIFO3_PC_MASK_RGB = (1 << 10), - CMDFIFO3_PC_MASK_ALPHA = (1 << 11), - CMDFIFO3_PC_MASK_Z = (1 << 12), - CMDFIFO3_PC_MASK_Wb = (1 << 13), - CMDFIFO3_PC_MASK_W0 = (1 << 14), - CMDFIFO3_PC_MASK_S0_T0 = (1 << 15), - CMDFIFO3_PC_MASK_W1 = (1 << 16), - CMDFIFO3_PC_MASK_S1_T1 = (1 << 17), - - CMDFIFO3_PC = (1 << 28) -}; - -static void fifo_thread(void *param) -{ - voodoo_t *voodoo = (voodoo_t *)param; - - while (1) - { - thread_set_event(voodoo->fifo_not_full_event); - thread_wait_event(voodoo->wake_fifo_thread, -1); - thread_reset_event(voodoo->wake_fifo_thread); - voodoo->voodoo_busy = 1; - while (!FIFO_EMPTY) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; - - switch (fifo->addr_type & FIFO_TYPE) - { - case FIFO_WRITEL_REG: - voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); - break; - case FIFO_WRITEW_FB: - wait_for_render_thread_idle(voodoo); - voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); - break; - case FIFO_WRITEL_FB: - wait_for_render_thread_idle(voodoo); - voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); - break; - case FIFO_WRITEL_TEX: - if (!(fifo->addr_type & 0x400000)) - voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); - break; - } - voodoo->fifo_read_idx++; - fifo->addr_type = FIFO_INVALID; - - if (FIFO_ENTRIES > 0xe000) - thread_set_event(voodoo->fifo_not_full_event); - - end_time = plat_timer_read(); - voodoo->time += end_time - start_time; - } - - while (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - uint32_t header = cmdfifo_get(voodoo); - uint32_t addr; - uint32_t mask; - int smode; - int num; - int num_verticies; - int v_num; - -// voodoo_log(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); - - switch (header & 7) - { - case 0: -// voodoo_log("CMDFIFO0\n"); - switch ((header >> 3) & 7) - { - case 0: /*NOP*/ - break; - - case 3: /*JMP local frame buffer*/ - voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; -// voodoo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); - break; - - default: - fatal("Bad CMDFIFO0 %08x\n", header); - } - break; - - case 1: - num = header >> 16; - addr = (header & 0x7ff8) >> 1; -// voodoo_log("CMDFIFO1 addr=%08x\n",addr); - while (num--) - { - uint32_t val = cmdfifo_get(voodoo); - if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || - (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) - voodoo->cmd_written_fifo++; - - voodoo_reg_writel(addr, val, voodoo); - - if (header & (1 << 15)) - addr += 4; - } - break; - - case 3: - num = (header >> 29) & 7; - mask = header;//(header >> 10) & 0xff; - smode = (header >> 22) & 0xf; - voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); - num_verticies = (header >> 6) & 0xf; - v_num = 0; - if (((header >> 3) & 7) == 2) - v_num = 1; -// voodoo_log("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); -// voodoo_log("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); - - while (num_verticies--) - { - voodoo->verts[3].sVx = cmdfifo_get_f(voodoo); - voodoo->verts[3].sVy = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_RGB) - { - if (header & CMDFIFO3_PC) - { - uint32_t val = cmdfifo_get(voodoo); - voodoo->verts[3].sBlue = (float)(val & 0xff); - voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); - voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); - voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); - } - else - { - voodoo->verts[3].sRed = cmdfifo_get_f(voodoo); - voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo); - voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo); - } - } - if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) - voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_Z) - voodoo->verts[3].sVz = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_Wb) - voodoo->verts[3].sWb = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_W0) - voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_S0_T0) - { - voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo); - voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo); - } - if (mask & CMDFIFO3_PC_MASK_W1) - voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_S1_T1) - { - voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo); - voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); - } - if (v_num) - voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); - else - voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); - v_num++; - if (v_num == 3 && ((header >> 3) & 7) == 0) - v_num = 0; - } - break; - - case 4: - num = (header >> 29) & 7; - mask = (header >> 15) & 0x3fff; - addr = (header & 0x7ff8) >> 1; -// voodoo_log("CMDFIFO4 addr=%08x\n",addr); - while (mask) - { - if (mask & 1) - { - uint32_t val = cmdfifo_get(voodoo); - if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || - (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) - voodoo->cmd_written_fifo++; - - voodoo_reg_writel(addr, val, voodoo); - } - - addr += 4; - mask >>= 1; - } - while (num--) - cmdfifo_get(voodoo); - break; - - case 5: - if (header & 0x3fc0000) - fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); - num = (header >> 3) & 0x7ffff; - addr = cmdfifo_get(voodoo) & 0xffffff; -// voodoo_log("CMDFIFO5 addr=%08x num=%i\n", addr, num); - switch (header >> 30) - { - case 2: /*Framebuffer*/ - while (num--) - { - uint32_t val = cmdfifo_get(voodoo); - voodoo_fb_writel(addr, val, voodoo); - addr += 4; - } - break; - case 3: /*Texture*/ - while (num--) - { - uint32_t val = cmdfifo_get(voodoo); - voodoo_tex_writel(addr, val, voodoo); - addr += 4; - } - break; - - default: - fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); - } - break; - - default: - voodoo_log("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); - } - - end_time = plat_timer_read(); - voodoo->time += end_time - start_time; - } - voodoo->voodoo_busy = 0; - } -} - static void voodoo_recalcmapping(voodoo_set_t *set) { if (set->nr_cards == 2) @@ -6876,7 +766,7 @@ static void voodoo_recalcmapping(voodoo_set_t *set) else { voodoo_t *voodoo = set->voodoos[0]; - + if (voodoo->pci_enable && voodoo->memBaseAddr) { voodoo_log("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); @@ -6903,21 +793,21 @@ uint8_t voodoo_pci_read(int func, int addr, void *p) { case 0x00: return 0x1a; /*3dfx*/ case 0x01: return 0x12; - + case 0x02: if (voodoo->type == VOODOO_2) return 0x02; /*Voodoo 2*/ else return 0x01; /*SST-1 (Voodoo Graphics)*/ case 0x03: return 0x00; - + case 0x04: return voodoo->pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/ case 0x08: return 2; /*Revision ID*/ case 0x09: return 0; /*Programming interface*/ case 0x0a: return 0; case 0x0b: return 0x04; - + case 0x10: return 0x00; /*memBaseAddr*/ case 0x11: return 0x00; case 0x12: return 0x00; @@ -6940,7 +830,7 @@ uint8_t voodoo_pci_read(int func, int addr, void *p) void voodoo_pci_write(int func, int addr, uint8_t val, void *p) { voodoo_t *voodoo = (voodoo_t *)p; - + if (func) return; @@ -6952,12 +842,12 @@ void voodoo_pci_write(int func, int addr, uint8_t val, void *p) voodoo->pci_enable = val & 2; voodoo_recalcmapping(voodoo->set); break; - + case 0x13: voodoo->memBaseAddr = val << 24; voodoo_recalcmapping(voodoo->set); break; - + case 0x40: voodoo->initEnable = (voodoo->initEnable & ~0x000000ff) | val; break; @@ -6975,551 +865,11 @@ void voodoo_pci_write(int func, int addr, uint8_t val, void *p) } } -static void voodoo_calc_clutData(voodoo_t *voodoo) -{ - int c; - - for (c = 0; c < 256; c++) - { - voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) + - voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3; - voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) + - voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3; - voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) + - voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3; - } - - for (c = 0; c < 65536; c++) - { - int r = (c >> 8) & 0xf8; - int g = (c >> 3) & 0xfc; - int b = (c << 3) & 0xf8; -// r |= (r >> 5); -// g |= (g >> 6); -// b |= (b >> 5); - - voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b; - } -} - - - -#define FILTDIV 256 - -static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ - -static void voodoo_generate_filter_v1(voodoo_t *voodoo) -{ - int g, h; - float difference, diffg, diffb; - float thiscol, thiscolg, thiscolb, lined; - float fcr, fcg, fcb; - - fcr = FILTCAP * 5; - fcg = FILTCAPG * 6; - fcb = FILTCAPB * 5; - - for (g=0;g FILTCAP) - difference = FILTCAP; - if (difference < -FILTCAP) - difference = -FILTCAP; - - if (diffg > FILTCAPG) - diffg = FILTCAPG; - if (diffg < -FILTCAPG) - diffg = -FILTCAPG; - - if (diffb > FILTCAPB) - diffb = FILTCAPB; - if (diffb < -FILTCAPB) - diffb = -FILTCAPB; - - // hack - to make it not bleed onto black - //if (g == 0){ - //difference = diffg = diffb = 0; - //} - - if ((difference < fcr) || (-difference > -fcr)) - thiscol = g + (difference / 2); - if ((diffg < fcg) || (-diffg > -fcg)) - thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ - if ((diffb < fcb) || (-diffb > -fcb)) - thiscolb = g + (diffb / 2); - - if (thiscol < 0) - thiscol = 0; - if (thiscol > FILTDIV-1) - thiscol = FILTDIV-1; - - if (thiscolg < 0) - thiscolg = 0; - if (thiscolg > FILTDIV-1) - thiscolg = FILTDIV-1; - - if (thiscolb < 0) - thiscolb = 0; - if (thiscolb > FILTDIV-1) - thiscolb = FILTDIV-1; - - voodoo->thefilter[g][h] = thiscol; - voodoo->thefilterg[g][h] = thiscolg; - voodoo->thefilterb[g][h] = thiscolb; - } - - lined = g + 4; - if (lined > 255) - lined = 255; - voodoo->purpleline[g][0] = lined; - voodoo->purpleline[g][2] = lined; - - lined = g + 0; - if (lined > 255) - lined = 255; - voodoo->purpleline[g][1] = lined; - } -} - -static void voodoo_generate_filter_v2(voodoo_t *voodoo) -{ - int g, h; - float difference; - float thiscol, thiscolg, thiscolb, lined; - float clr, clg, clb = 0; - float fcr, fcg, fcb = 0; - - // pre-clamping - - fcr = FILTCAP; - fcg = FILTCAPG; - fcb = FILTCAPB; - - if (fcr > 32) fcr = 32; - if (fcg > 32) fcg = 32; - if (fcb > 32) fcb = 32; - - for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into - { - for (h=0;h<256;h++) // pixel 2 - our main pixel - { - float avg; - float avgdiff; - - difference = (float)(g - h); - avg = (float)((g + g + g + g + h) / 5); - avgdiff = avg - (float)((g + h + h + h + h) / 5); - if (avgdiff < 0) avgdiff *= -1; - if (difference < 0) difference *= -1; - - thiscol = thiscolg = thiscolb = g; - - // try lighten - if (h > g) - { - clr = clg = clb = avgdiff; - - if (clr>fcr) clr=fcr; - if (clg>fcg) clg=fcg; - if (clb>fcb) clb=fcb; - - - thiscol = g + clr; - thiscolg = g + clg; - thiscolb = g + clb; - - if (thiscol>g+FILTCAP) - thiscol=g+FILTCAP; - if (thiscolg>g+FILTCAPG) - thiscolg=g+FILTCAPG; - if (thiscolb>g+FILTCAPB) - thiscolb=g+FILTCAPB; - - - if (thiscol>g+avgdiff) - thiscol=g+avgdiff; - if (thiscolg>g+avgdiff) - thiscolg=g+avgdiff; - if (thiscolb>g+avgdiff) - thiscolb=g+avgdiff; - - } - - if (difference > FILTCAP) - thiscol = g; - if (difference > FILTCAPG) - thiscolg = g; - if (difference > FILTCAPB) - thiscolb = g; - - // clamp - if (thiscol < 0) thiscol = 0; - if (thiscolg < 0) thiscolg = 0; - if (thiscolb < 0) thiscolb = 0; - - if (thiscol > 255) thiscol = 255; - if (thiscolg > 255) thiscolg = 255; - if (thiscolb > 255) thiscolb = 255; - - // add to the table - voodoo->thefilter[g][h] = (thiscol); - voodoo->thefilterg[g][h] = (thiscolg); - voodoo->thefilterb[g][h] = (thiscolb); - - // debug the ones that don't give us much of a difference - //if (difference < FILTCAP) - //voodoo_log("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); - } - - lined = g + 3; - if (lined > 255) - lined = 255; - voodoo->purpleline[g][0] = lined; - voodoo->purpleline[g][1] = 0; - voodoo->purpleline[g][2] = lined; - } -} - -static void voodoo_threshold_check(voodoo_t *voodoo) -{ - int r, g, b; - - if (!voodoo->scrfilterEnabled) - return; /* considered disabled; don't check and generate */ - - /* Check for changes, to generate anew table */ - if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld) - { - r = (voodoo->scrfilterThreshold >> 16) & 0xFF; - g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF; - b = voodoo->scrfilterThreshold & 0xFF; - - FILTCAP = r; - FILTCAPG = g; - FILTCAPB = b; - - voodoo_log("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); - - voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; - - if (voodoo->type == VOODOO_2) - voodoo_generate_filter_v2(voodoo); - else - voodoo_generate_filter_v1(voodoo); - } -} - -static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) -{ - int x; - - // Scratchpad for avoiding feedback streaks - uint8_t *fil3 = malloc((voodoo->h_disp) * 3); - if (fil3 == NULL) fatal("fil3 = NULL"); - - /* 16 to 32-bit */ - for (x=0; x> 5) & 63) << 2); - fil[x*3+2] = (((src[x] >> 11) & 31) << 3); - - // Copy to our scratchpads - fil3[x*3+0] = fil[x*3+0]; - fil3[x*3+1] = fil[x*3+1]; - fil3[x*3+2] = fil[x*3+2]; - } - - - /* lines */ - - if (line & 1) - { - for (x=0; xpurpleline[fil[x*3]][0]; - fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; - fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; - } - } - - - /* filtering time */ - - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; - } - - for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; - fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; - fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; - } - - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; - } - - for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; - fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; - fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; - } - - free(fil3); -} - - -static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) -{ - int x; - - // Scratchpad for blending filter - uint8_t *fil3 = malloc((voodoo->h_disp) * 3); - if (fil3 == NULL) fatal("fil3 = NULL"); - - /* 16 to 32-bit */ - for (x=0; x> 5) & 63) << 2); - fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); - } - - /* filtering time */ - - for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; - fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; - fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; - - fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; - fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; - fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; - - fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; - fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; - fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; - - fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; - fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; - fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; - } - - // unroll for edge cases - - fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; - fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; - fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; - - fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; - fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; - fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; - - fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; - fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; - fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; - - fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; - fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; - fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; - - fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; - fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; - fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; - - fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; - fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; - fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; - - free(fil3); -} - -void voodoo_callback(void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - - if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) - { - if (voodoo->line < voodoo->v_disp) - { - voodoo_t *draw_voodoo; - int draw_line; - - if (SLI_ENABLED) - { - if (voodoo == voodoo->set->voodoos[1]) - goto skip_draw; - - if (((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) ? 1 : 0) == (voodoo->line & 1)) - draw_voodoo = voodoo; - else - draw_voodoo = voodoo->set->voodoos[1]; - draw_line = voodoo->line >> 1; - } - else - { - if (!(voodoo->fbiInit0 & 1)) - goto skip_draw; - draw_voodoo = voodoo; - draw_line = voodoo->line; - } - - if (draw_voodoo->dirty_line[draw_line]) - { - uint32_t *p = &buffer32->line[voodoo->line + 8][8]; - uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width]; - int x; - - draw_voodoo->dirty_line[draw_line] = 0; - - if (voodoo->line < voodoo->dirty_line_low) - { - voodoo->dirty_line_low = voodoo->line; - video_wait_for_buffer(); - } - if (voodoo->line > voodoo->dirty_line_high) - voodoo->dirty_line_high = voodoo->line; - - /* Draw left overscan. */ - for (x = 0; x < 8; x++) - buffer32->line[voodoo->line + 8][x] = 0x00000000; - - if (voodoo->scrfilter && voodoo->scrfilterEnabled) - { - uint8_t *fil = malloc((voodoo->h_disp) * 3); /* interleaved 24-bit RGB */ - if (fil == NULL) fatal("fil = NULL"); - - if (voodoo->type == VOODOO_2) - voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); - else - voodoo_filterline_v1(voodoo, fil, voodoo->h_disp, src, voodoo->line); - - for (x = 0; x < voodoo->h_disp; x++) - { - p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16); - } - - free(fil); - } - else - { - for (x = 0; x < voodoo->h_disp; x++) - { - p[x] = draw_voodoo->video_16to32[src[x]]; - } - } - - /* Draw right overscan. */ - for (x = 0; x < 8; x++) - buffer32->line[voodoo->line + 8][voodoo->h_disp + x + 8] = 0x00000000; - } - } - } -skip_draw: - if (voodoo->line == voodoo->v_disp) - { -// voodoo_log("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending); - voodoo->retrace_count++; - if (SLI_ENABLED && (voodoo->fbiInit2 & FBIINIT2_SWAP_ALGORITHM_MASK) == FBIINIT2_SWAP_ALGORITHM_SLI_SYNC) - { - if (voodoo == voodoo->set->voodoos[0]) - { - voodoo_t *voodoo_1 = voodoo->set->voodoos[1]; - - /*Only swap if both Voodoos are waiting for buffer swap*/ - if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) && - voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval)) - { - memset(voodoo->dirty_line, 1, 1024); - voodoo->retrace_count = 0; - voodoo->front_offset = voodoo->swap_offset; - if (voodoo->swap_count > 0) - voodoo->swap_count--; - voodoo->swap_pending = 0; - - memset(voodoo_1->dirty_line, 1, 1024); - voodoo_1->retrace_count = 0; - voodoo_1->front_offset = voodoo_1->swap_offset; - if (voodoo_1->swap_count > 0) - voodoo_1->swap_count--; - voodoo_1->swap_pending = 0; - - thread_set_event(voodoo->wake_fifo_thread); - thread_set_event(voodoo_1->wake_fifo_thread); - - voodoo->frame_count++; - voodoo_1->frame_count++; - } - } - } - else - { - if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) - { - memset(voodoo->dirty_line, 1, 1024); - voodoo->retrace_count = 0; - voodoo->front_offset = voodoo->swap_offset; - if (voodoo->swap_count > 0) - voodoo->swap_count--; - voodoo->swap_pending = 0; - thread_set_event(voodoo->wake_fifo_thread); - voodoo->frame_count++; - } - } - voodoo->v_retrace = 1; - } - voodoo->line++; - - if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) - { - if (voodoo->line == voodoo->v_disp) - { - if (voodoo->dirty_line_high > voodoo->dirty_line_low) - svga_doblit(0, voodoo->v_disp, voodoo->h_disp, voodoo->v_disp-1, voodoo->svga); - if (voodoo->clutData_dirty) - { - voodoo->clutData_dirty = 0; - voodoo_calc_clutData(voodoo); - } - voodoo->dirty_line_high = -1; - voodoo->dirty_line_low = 2000; - } - } - - if (voodoo->line >= voodoo->v_total) - { - voodoo->line = 0; - voodoo->v_retrace = 0; - } - if (voodoo->line_time) - timer_advance_u64(&voodoo->timer, voodoo->line_time); - else - timer_advance_u64(&voodoo->timer, TIMER_USEC * 32); -} static void voodoo_speed_changed(void *p) { voodoo_set_t *voodoo_set = (voodoo_set_t *)p; - + voodoo_pixelclock_update(voodoo_set->voodoos[0]); voodoo_set->voodoos[0]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit4 & 1) ? 2 : 1); voodoo_set->voodoos[0]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 1 : 0); @@ -7534,6 +884,24 @@ static void voodoo_speed_changed(void *p) // voodoo_log("Voodoo read_time=%i write_time=%i burst_time=%i %08x %08x\n", voodoo->read_time, voodoo->write_time, voodoo->burst_time, voodoo->fbiInit1, voodoo->fbiInit4); } +static void voodoo_force_blit(void *p) +{ + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + + thread_wait_mutex(voodoo_set->voodoos[0]->force_blit_mutex); + if(voodoo_set->voodoos[0]->can_blit) { + voodoo_set->voodoos[0]->force_blit_count++; + } + thread_release_mutex(voodoo_set->voodoos[0]->force_blit_mutex); + if(voodoo_set->nr_cards == 2) { + thread_wait_mutex(voodoo_set->voodoos[1]->force_blit_mutex); + if(voodoo_set->voodoos[1]->can_blit) { + voodoo_set->voodoos[1]->force_blit_count++; + } + thread_release_mutex(voodoo_set->voodoos[1]->force_blit_mutex); + } +} + void *voodoo_card_init() { int c; @@ -7541,6 +909,7 @@ void *voodoo_card_init() memset(voodoo, 0, sizeof(voodoo_t)); voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->dithersub_enabled = device_get_config_int("dithersub"); voodoo->scrfilter = device_get_config_int("dacfilter"); voodoo->texture_size = device_get_config_int("texture_memory"); voodoo->texture_mask = (voodoo->texture_size << 20) - 1; @@ -7550,10 +919,9 @@ void *voodoo_card_init() voodoo->odd_even_mask = voodoo->render_threads - 1; #ifndef NO_CODEGEN voodoo->use_recompiler = device_get_config_int("recompiler"); -#endif +#endif voodoo->type = device_get_config_int("type"); - switch (voodoo->type) - { + switch (voodoo->type) { case VOODOO_1: voodoo->dual_tmus = 0; break; @@ -7564,12 +932,12 @@ void *voodoo_card_init() voodoo->dual_tmus = 1; break; } - + if (voodoo->type == VOODOO_2) /*generate filter lookup tables*/ voodoo_generate_filter_v2(voodoo); else voodoo_generate_filter_v1(voodoo); - + pci_add_card(PCI_ADD_NORMAL, voodoo_pci_read, voodoo_pci_write, voodoo); mem_mapping_add(&voodoo->mapping, 0, 0, NULL, voodoo_readw, voodoo_readl, NULL, voodoo_writew, voodoo_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo); @@ -7580,9 +948,8 @@ void *voodoo_card_init() voodoo->tex_mem[1] = malloc(voodoo->texture_size * 1024 * 1024); voodoo->tex_mem_w[0] = (uint16_t *)voodoo->tex_mem[0]; voodoo->tex_mem_w[1] = (uint16_t *)voodoo->tex_mem[1]; - - for (c = 0; c < TEX_CACHE_MAX; c++) - { + + for (c = 0; c < TEX_CACHE_MAX; c++) { voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); voodoo->texture_cache[0][c].base = -1; /*invalid*/ voodoo->texture_cache[0][c].refcount = 0; @@ -7595,26 +962,39 @@ void *voodoo_card_init() } timer_add(&voodoo->timer, voodoo_callback, voodoo, 1); - + voodoo->svga = svga_get_pri(); voodoo->fbiInit0 = 0; voodoo->wake_fifo_thread = thread_create_event(); voodoo->wake_render_thread[0] = thread_create_event(); voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_render_thread[2] = thread_create_event(); + voodoo->wake_render_thread[3] = thread_create_event(); voodoo->wake_main_thread = thread_create_event(); voodoo->fifo_not_full_event = thread_create_event(); voodoo->render_not_full_event[0] = thread_create_event(); voodoo->render_not_full_event[1] = thread_create_event(); - voodoo->fifo_thread = thread_create(fifo_thread, voodoo); - voodoo->render_thread[0] = thread_create(render_thread_1, voodoo); - if (voodoo->render_threads == 2) - voodoo->render_thread[1] = thread_create(render_thread_2, voodoo); - + voodoo->render_not_full_event[2] = thread_create_event(); + voodoo->render_not_full_event[3] = thread_create_event(); + voodoo->fifo_thread_run = 1; + voodoo->fifo_thread = thread_create(voodoo_fifo_thread, voodoo); + voodoo->render_thread_run[0] = 1; + voodoo->render_thread[0] = thread_create(voodoo_render_thread_1, voodoo); + if (voodoo->render_threads >= 2) { + voodoo->render_thread_run[1] = 1; + voodoo->render_thread[1] = thread_create(voodoo_render_thread_2, voodoo); + } + if (voodoo->render_threads == 4) { + voodoo->render_thread_run[2] = 1; + voodoo->render_thread[2] = thread_create(voodoo_render_thread_3, voodoo); + voodoo->render_thread_run[3] = 1; + voodoo->render_thread[3] = thread_create(voodoo_render_thread_4, voodoo); + } + voodoo->swap_mutex = thread_create_mutex(); timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); - - for (c = 0; c < 0x100; c++) - { + + for (c = 0; c < 0x100; c++) { rgb332[c].r = c & 0xe0; rgb332[c].g = (c << 3) & 0xe0; rgb332[c].b = (c << 6) & 0xc0; @@ -7623,14 +1003,13 @@ void *voodoo_card_init() rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); rgb332[c].a = 0xff; - + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); ai44[c].g = ai44[c].b = ai44[c].r; } - - for (c = 0; c < 0x10000; c++) - { + + for (c = 0; c < 0x10000; c++) { rgb565[c].r = (c >> 8) & 0xf8; rgb565[c].g = (c >> 3) & 0xfc; rgb565[c].b = (c << 3) & 0xf8; @@ -7655,7 +1034,7 @@ void *voodoo_card_init() argb4444[c].r |= (argb4444[c].r >> 4); argb4444[c].g |= (argb4444[c].g >> 4); argb4444[c].b |= (argb4444[c].b >> 4); - + ai88[c].a = (c >> 8); ai88[c].r = c & 0xff; ai88[c].g = c & 0xff; @@ -7667,7 +1046,135 @@ void *voodoo_card_init() voodoo->disp_buffer = 0; voodoo->draw_buffer = 1; - + + voodoo->force_blit_count = 0; + voodoo->can_blit = 0; + voodoo->force_blit_mutex = thread_create_mutex(); + + return voodoo; +} + +void *voodoo_2d3d_card_init(int type) +{ + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->dithersub_enabled = device_get_config_int("dithersub"); + voodoo->scrfilter = device_get_config_int("dacfilter"); + voodoo->render_threads = device_get_config_int("render_threads"); + voodoo->odd_even_mask = voodoo->render_threads - 1; +#ifndef NO_CODEGEN + voodoo->use_recompiler = device_get_config_int("recompiler"); +#endif + voodoo->type = type; + voodoo->dual_tmus = (type == VOODOO_3) ? 1 : 0; + + /*generate filter lookup tables*/ + voodoo_generate_filter_v2(voodoo); + + for (c = 0; c < TEX_CACHE_MAX; c++) { + voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[0][c].base = -1; /*invalid*/ + voodoo->texture_cache[0][c].refcount = 0; + if (voodoo->dual_tmus) + { + voodoo->texture_cache[1][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[1][c].base = -1; /*invalid*/ + voodoo->texture_cache[1][c].refcount = 0; + } + } + + timer_add(&voodoo->timer, voodoo_callback, voodoo, 1); + + voodoo->fbiInit0 = 0; + + voodoo->wake_fifo_thread = thread_create_event(); + voodoo->wake_render_thread[0] = thread_create_event(); + voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_render_thread[2] = thread_create_event(); + voodoo->wake_render_thread[3] = thread_create_event(); + voodoo->wake_main_thread = thread_create_event(); + voodoo->fifo_not_full_event = thread_create_event(); + voodoo->render_not_full_event[0] = thread_create_event(); + voodoo->render_not_full_event[1] = thread_create_event(); + voodoo->render_not_full_event[2] = thread_create_event(); + voodoo->render_not_full_event[3] = thread_create_event(); + voodoo->fifo_thread_run = 1; + voodoo->fifo_thread = thread_create(voodoo_fifo_thread, voodoo); + voodoo->render_thread_run[0] = 1; + voodoo->render_thread[0] = thread_create(voodoo_render_thread_1, voodoo); + if (voodoo->render_threads >= 2) { + voodoo->render_thread_run[1] = 1; + voodoo->render_thread[1] = thread_create(voodoo_render_thread_2, voodoo); + } + if (voodoo->render_threads == 4) { + voodoo->render_thread_run[2] = 1; + voodoo->render_thread[2] = thread_create(voodoo_render_thread_3, voodoo); + voodoo->render_thread_run[3] = 1; + voodoo->render_thread[3] = thread_create(voodoo_render_thread_4, voodoo); + } + voodoo->swap_mutex = thread_create_mutex(); + timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); + + for (c = 0; c < 0x100; c++) { + rgb332[c].r = c & 0xe0; + rgb332[c].g = (c << 3) & 0xe0; + rgb332[c].b = (c << 6) & 0xc0; + rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6); + rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); + rgb332[c].a = 0xff; + + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); + ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); + ai44[c].g = ai44[c].b = ai44[c].r; + } + + for (c = 0; c < 0x10000; c++) { + rgb565[c].r = (c >> 8) & 0xf8; + rgb565[c].g = (c >> 3) & 0xfc; + rgb565[c].b = (c << 3) & 0xf8; + rgb565[c].r |= (rgb565[c].r >> 5); + rgb565[c].g |= (rgb565[c].g >> 6); + rgb565[c].b |= (rgb565[c].b >> 5); + rgb565[c].a = 0xff; + + argb1555[c].r = (c >> 7) & 0xf8; + argb1555[c].g = (c >> 2) & 0xf8; + argb1555[c].b = (c << 3) & 0xf8; + argb1555[c].r |= (argb1555[c].r >> 5); + argb1555[c].g |= (argb1555[c].g >> 5); + argb1555[c].b |= (argb1555[c].b >> 5); + argb1555[c].a = (c & 0x8000) ? 0xff : 0; + + argb4444[c].a = (c >> 8) & 0xf0; + argb4444[c].r = (c >> 4) & 0xf0; + argb4444[c].g = c & 0xf0; + argb4444[c].b = (c << 4) & 0xf0; + argb4444[c].a |= (argb4444[c].a >> 4); + argb4444[c].r |= (argb4444[c].r >> 4); + argb4444[c].g |= (argb4444[c].g >> 4); + argb4444[c].b |= (argb4444[c].b >> 4); + + ai88[c].a = (c >> 8); + ai88[c].r = c & 0xff; + ai88[c].g = c & 0xff; + ai88[c].b = c & 0xff; + } +#ifndef NO_CODEGEN + voodoo_codegen_init(voodoo); +#endif + + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + + voodoo->force_blit_count = 0; + voodoo->can_blit = 0; + voodoo->force_blit_mutex = thread_create_mutex(); + return voodoo; } @@ -7677,16 +1184,16 @@ void *voodoo_init() uint32_t tmuConfig = 1; int type; memset(voodoo_set, 0, sizeof(voodoo_set_t)); - + type = device_get_config_int("type"); - + voodoo_set->nr_cards = device_get_config_int("sli") ? 2 : 1; voodoo_set->voodoos[0] = voodoo_card_init(); voodoo_set->voodoos[0]->set = voodoo_set; if (voodoo_set->nr_cards == 2) { voodoo_set->voodoos[1] = voodoo_card_init(); - + voodoo_set->voodoos[1]->set = voodoo_set; if (type == VOODOO_2) @@ -7719,39 +1226,39 @@ void *voodoo_init() tmuConfig = 1 | (3 << 6); break; } - + voodoo_set->voodoos[0]->tmuConfig = tmuConfig; if (voodoo_set->nr_cards == 2) voodoo_set->voodoos[1]->tmuConfig = tmuConfig; mem_mapping_add(&voodoo_set->snoop_mapping, 0, 0, NULL, voodoo_snoop_readw, voodoo_snoop_readl, NULL, voodoo_snoop_writew, voodoo_snoop_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo_set); - + return voodoo_set; } void voodoo_card_close(voodoo_t *voodoo) { -#ifndef RELEASE_BUILD - FILE *f; -#endif int c; - -#ifndef RELEASE_BUILD - f = rom_fopen(L"texram.dmp", L"wb"); - fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); - fclose(f); - if (voodoo->dual_tmus) - { - f = rom_fopen(L"texram2.dmp", L"wb"); - fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); - fclose(f); - } -#endif - thread_kill(voodoo->fifo_thread); - thread_kill(voodoo->render_thread[0]); - if (voodoo->render_threads == 2) - thread_kill(voodoo->render_thread[1]); + voodoo->fifo_thread_run = 0; + thread_set_event(voodoo->wake_fifo_thread); + thread_wait(voodoo->fifo_thread); + voodoo->render_thread_run[0] = 0; + thread_set_event(voodoo->wake_render_thread[0]); + thread_wait(voodoo->render_thread[0]); + if (voodoo->render_threads >= 2) { + voodoo->render_thread_run[1] = 0; + thread_set_event(voodoo->wake_render_thread[1]); + thread_wait(voodoo->render_thread[1]); + } + if (voodoo->render_threads == 4) { + voodoo->render_thread_run[2] = 0; + thread_set_event(voodoo->wake_render_thread[2]); + thread_wait(voodoo->render_thread[2]); + voodoo->render_thread_run[3] = 0; + thread_set_event(voodoo->wake_render_thread[3]); + thread_wait(voodoo->render_thread[3]); + } thread_destroy_event(voodoo->fifo_not_full_event); thread_destroy_event(voodoo->wake_main_thread); thread_destroy_event(voodoo->wake_fifo_thread); @@ -7769,151 +1276,165 @@ void voodoo_card_close(voodoo_t *voodoo) #ifndef NO_CODEGEN voodoo_codegen_close(voodoo); #endif - free(voodoo->fb_mem); - if (voodoo->dual_tmus) - free(voodoo->tex_mem[1]); - free(voodoo->tex_mem[0]); + if (voodoo->type < VOODOO_BANSHEE && voodoo->fb_mem) + { + free(voodoo->fb_mem); + if (voodoo->dual_tmus) + free(voodoo->tex_mem[1]); + free(voodoo->tex_mem[0]); + } + + thread_close_mutex(voodoo->force_blit_mutex); + free(voodoo); } void voodoo_close(void *p) { voodoo_set_t *voodoo_set = (voodoo_set_t *)p; - + if (voodoo_set->nr_cards == 2) voodoo_card_close(voodoo_set->voodoos[1]); voodoo_card_close(voodoo_set->voodoos[0]); - + free(voodoo_set); } -static const device_config_t voodoo_config[] = -{ - { - .name = "type", - .description = "Voodoo type", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Voodoo Graphics", - .value = VOODOO_1 - }, - { - .description = "Obsidian SB50 + Amethyst (2 TMUs)", - .value = VOODOO_SB50 - }, - { - .description = "Voodoo 2", - .value = VOODOO_2 - }, - { - .description = "" - } - }, - .default_int = 0 +static const device_config_t voodoo_config[] = { +// clang-format off + { + .name = "type", + .description = "Voodoo type", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "Voodoo Graphics", + .value = VOODOO_1 + }, + { + .description = "Obsidian SB50 + Amethyst (2 TMUs)", + .value = VOODOO_SB50 + }, + { + .description = "Voodoo 2", + .value = VOODOO_2 + }, + { + .description = "" + } }, - { - .name = "framebuffer_memory", - .description = "Framebuffer memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 + .default_int = 0 + }, + { + .name = "framebuffer_memory", + .description = "Framebuffer memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } }, - { - .name = "texture_memory", - .description = "Texture memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 + .default_int = 2 + }, + { + .name = "texture_memory", + .description = "Texture memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } }, - { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dacfilter", - .description = "Screen Filter", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "render_threads", - .description = "Render threads", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1", - .value = 1 - }, - { - .description = "2", - .value = 2 - }, - { - .description = "" - } - }, - .default_int = 2 - }, - { - .name = "sli", - .description = "SLI", - .type = CONFIG_BINARY, - .default_int = 0 + .default_int = 2 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "4", + .value = 4 + }, + { + .description = "" + } }, + .default_int = 2 + }, + { + .name = "sli", + .description = "SLI", + .type = CONFIG_BINARY, + .default_int = 0 + }, #ifndef NO_CODEGEN - { - .name = "recompiler", - .description = "Recompiler", - .type = CONFIG_BINARY, - .default_int = 1 - }, + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, #endif - { - .type = -1 - } + { + .type = CONFIG_END + } +// clang-format on }; const device_t voodoo_device = { - "3DFX Voodoo Graphics", - DEVICE_PCI, - 0, - voodoo_init, - voodoo_close, - NULL, - NULL, - voodoo_speed_changed, - NULL, - voodoo_config + .name = "3DFX Voodoo Graphics", + .internal_name = "voodoo", + .flags = DEVICE_PCI, + .local = 0, + .init = voodoo_init, + .close = voodoo_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = voodoo_speed_changed, + .force_redraw = voodoo_force_blit, + .config = voodoo_config }; diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c new file mode 100644 index 000000000..42b06eb4b --- /dev/null +++ b/src/video/vid_voodoo_banshee.c @@ -0,0 +1,3066 @@ +/* + * 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. + * + * Voodoo Banshee and 3 specific emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_display.h> +#include <86box/vid_voodoo_fifo.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> + + +static video_timings_t timing_banshee = {VIDEO_PCI, 2, 2, 1, 20, 20, 21}; +static video_timings_t timing_banshee_agp = {VIDEO_AGP, 2, 2, 1, 20, 20, 21}; + + +#ifdef CLAMP +#undef CLAMP +#endif + +static uint8_t vb_filter_v1_rb[256][256]; +static uint8_t vb_filter_v1_g [256][256]; + +static uint8_t vb_filter_bx_rb[256][256]; +static uint8_t vb_filter_bx_g [256][256]; + +enum +{ + TYPE_BANSHEE = 0, + TYPE_V3_2000, + TYPE_V3_3000, + TYPE_VELOCITY100 +}; + +typedef struct banshee_t +{ + svga_t svga; + + rom_t bios_rom; + + uint8_t pci_regs[256]; + + uint32_t memBaseAddr0; + uint32_t memBaseAddr1; + uint32_t ioBaseAddr; + + uint32_t agpInit0; + uint32_t dramInit0, dramInit1; + uint32_t lfbMemoryConfig; + uint32_t miscInit0, miscInit1; + uint32_t pciInit0; + uint32_t vgaInit0, vgaInit1; + + uint32_t command_2d; + uint32_t srcBaseAddr_2d; + + uint32_t pllCtrl0, pllCtrl1, pllCtrl2; + + uint32_t dacMode; + int dacAddr; + + uint32_t vidDesktopOverlayStride; + uint32_t vidDesktopStartAddr; + uint32_t vidProcCfg; + uint32_t vidScreenSize; + uint32_t vidSerialParallelPort; + + int overlay_pix_fmt; + + uint32_t hwCurPatAddr, hwCurLoc, hwCurC0, hwCurC1; + + uint32_t intrCtrl; + + uint32_t overlay_buffer[2][4096]; + + mem_mapping_t linear_mapping; + + mem_mapping_t reg_mapping_low; /*0000000-07fffff*/ + mem_mapping_t reg_mapping_high; /*0c00000-1ffffff - Windows 2000 puts the BIOS ROM in between these two areas*/ + + voodoo_t *voodoo; + + uint32_t desktop_addr; + int desktop_y; + uint32_t desktop_stride_tiled; + + int type, card, agp, has_bios; + int vblank_irq; + + void *i2c, *i2c_ddc, *ddc; +} banshee_t; + +enum +{ + Init_status = 0x00, + Init_pciInit0 = 0x04, + Init_lfbMemoryConfig = 0x0c, + Init_miscInit0 = 0x10, + Init_miscInit1 = 0x14, + Init_dramInit0 = 0x18, + Init_dramInit1 = 0x1c, + Init_agpInit0 = 0x20, + Init_vgaInit0 = 0x28, + Init_vgaInit1 = 0x2c, + Init_2dCommand = 0x30, + Init_2dSrcBaseAddr = 0x34, + Init_strapInfo = 0x38, + + PLL_pllCtrl0 = 0x40, + PLL_pllCtrl1 = 0x44, + PLL_pllCtrl2 = 0x48, + + DAC_dacMode = 0x4c, + DAC_dacAddr = 0x50, + DAC_dacData = 0x54, + + Video_vidProcCfg = 0x5c, + Video_maxRgbDelta = 0x58, + Video_hwCurPatAddr = 0x60, + Video_hwCurLoc = 0x64, + Video_hwCurC0 = 0x68, + Video_hwCurC1 = 0x6c, + Video_vidSerialParallelPort = 0x78, + Video_vidScreenSize = 0x98, + Video_vidOverlayStartCoords = 0x9c, + Video_vidOverlayEndScreenCoords = 0xa0, + Video_vidOverlayDudx = 0xa4, + Video_vidOverlayDudxOffsetSrcWidth = 0xa8, + Video_vidOverlayDvdy = 0xac, + Video_vidOverlayDvdyOffset = 0xe0, + Video_vidDesktopStartAddr = 0xe4, + Video_vidDesktopOverlayStride = 0xe8 +}; + +enum +{ + cmdBaseAddr0 = 0x20, + cmdBaseSize0 = 0x24, + cmdBump0 = 0x28, + cmdRdPtrL0 = 0x2c, + cmdRdPtrH0 = 0x30, + cmdAMin0 = 0x34, + cmdAMax0 = 0x3c, + cmdFifoDepth0 = 0x44, + cmdHoleCnt0 = 0x48 +}; + +#define VGAINIT0_EXTENDED_SHIFT_OUT (1 << 12) + +#define VIDPROCCFG_VIDPROC_ENABLE (1 << 0) +#define VIDPROCCFG_CURSOR_MODE (1 << 1) +#define VIDPROCCFG_INTERLACE (1 << 3) +#define VIDPROCCFG_HALF_MODE (1 << 4) +#define VIDPROCCFG_OVERLAY_ENABLE (1 << 8) +#define VIDPROCCFG_OVERLAY_CLUT_BYPASS (1 << 11) +#define VIDPROCCFG_OVERLAY_CLUT_SEL (1 << 13) +#define VIDPROCCFG_H_SCALE_ENABLE (1 << 14) +#define VIDPROCCFG_V_SCALE_ENABLE (1 << 15) +#define VIDPROCCFG_FILTER_MODE_MASK (3 << 16) +#define VIDPROCCFG_FILTER_MODE_POINT (0 << 16) +#define VIDPROCCFG_FILTER_MODE_DITHER_2X2 (1 << 16) +#define VIDPROCCFG_FILTER_MODE_DITHER_4X4 (2 << 16) +#define VIDPROCCFG_FILTER_MODE_BILINEAR (3 << 16) +#define VIDPROCCFG_DESKTOP_PIX_FORMAT ((banshee->vidProcCfg >> 18) & 7) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT ((banshee->vidProcCfg >> 21) & 7) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT (21) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT_MASK (7 << VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT) +#define VIDPROCCFG_DESKTOP_TILE (1 << 24) +#define VIDPROCCFG_OVERLAY_TILE (1 << 25) +#define VIDPROCCFG_2X_MODE (1 << 26) +#define VIDPROCCFG_HWCURSOR_ENA (1 << 27) + +#define OVERLAY_FMT_565 (1) +#define OVERLAY_FMT_YUYV422 (5) +#define OVERLAY_FMT_UYVY422 (6) +#define OVERLAY_FMT_565_DITHER (7) + +#define OVERLAY_START_X_MASK (0xfff) +#define OVERLAY_START_Y_SHIFT (12) +#define OVERLAY_START_Y_MASK (0xfff << OVERLAY_START_Y_SHIFT) + +#define OVERLAY_END_X_MASK (0xfff) +#define OVERLAY_END_Y_SHIFT (12) +#define OVERLAY_END_Y_MASK (0xfff << OVERLAY_END_Y_SHIFT) + +#define OVERLAY_SRC_WIDTH_SHIFT (19) +#define OVERLAY_SRC_WIDTH_MASK (0x1fff << OVERLAY_SRC_WIDTH_SHIFT) + +#define VID_STRIDE_OVERLAY_SHIFT (16) +#define VID_STRIDE_OVERLAY_MASK (0x7fff << VID_STRIDE_OVERLAY_SHIFT) + +#define VID_DUDX_MASK (0xffffff) +#define VID_DVDY_MASK (0xffffff) + +#define PIX_FORMAT_8 0 +#define PIX_FORMAT_RGB565 1 +#define PIX_FORMAT_RGB24 2 +#define PIX_FORMAT_RGB32 3 + +#define VIDSERIAL_DDC_EN (1 << 18) +#define VIDSERIAL_DDC_DCK_W (1 << 19) +#define VIDSERIAL_DDC_DDA_W (1 << 20) +#define VIDSERIAL_DDC_DCK_R (1 << 21) +#define VIDSERIAL_DDC_DDA_R (1 << 22) +#define VIDSERIAL_I2C_EN (1 << 23) +#define VIDSERIAL_I2C_SCK_W (1 << 24) +#define VIDSERIAL_I2C_SDA_W (1 << 25) +#define VIDSERIAL_I2C_SCK_R (1 << 26) +#define VIDSERIAL_I2C_SDA_R (1 << 27) + +#define MISCINIT0_Y_ORIGIN_SWAP_SHIFT (18) +#define MISCINIT0_Y_ORIGIN_SWAP_MASK (0xfff << MISCINIT0_Y_ORIGIN_SWAP_SHIFT) + +#ifdef ENABLE_BANSHEE_LOG +int banshee_do_log = ENABLE_BANSHEE_LOG; + + +static void +banshee_log(const char *fmt, ...) +{ + va_list ap; + + if (banshee_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define banshee_log(fmt, ...) +#endif + +static uint32_t banshee_status(banshee_t *banshee); + +static int banshee_vga_vsync_enabled(banshee_t *banshee) +{ + if (!(banshee->svga.crtc[0x11] & 0x20) && (banshee->svga.crtc[0x11] & 0x10) && ((banshee->pciInit0 >> 18) & 1) != 0) + return 1; + return 0; +} + +static void banshee_update_irqs(banshee_t *banshee) +{ + if (banshee->vblank_irq > 0 && banshee_vga_vsync_enabled(banshee)) { + pci_set_irq(banshee->card, PCI_INTA); + } else { + pci_clear_irq(banshee->card, PCI_INTA); + } +} + +static void banshee_vblank_start(svga_t* svga) +{ + banshee_t *banshee = (banshee_t*)svga->p; + if (banshee->vblank_irq >= 0) { + banshee->vblank_irq = 1; + banshee_update_irqs(banshee); + } +} + + +static void banshee_out(uint16_t addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + svga_t *svga = &banshee->svga; + uint8_t old; + +// /*if (addr != 0x3c9) */banshee_log("banshee_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg == 0x11) { + if (!(val & 0x10)) { + if (banshee->vblank_irq > 0) + banshee->vblank_irq = -1; + } else if (banshee->vblank_irq < 0) { + banshee->vblank_irq = 0; + } + banshee_update_irqs(banshee); + if ((val & ~0x30) == (old & ~0x30)) + old = val; + } + if (svga->crtcreg < 0xe || svga->crtcreg > 0x11 || (svga->crtcreg == 0x11 && old != val)) + { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t banshee_in(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + svga_t *svga = &banshee->svga; + uint8_t temp; + +// if (addr != 0x3da) banshee_log("banshee_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x40) + temp = 0; + else + temp = 0x10; + if (banshee->vblank_irq > 0) + temp |= 0x80; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) banshee_log("%02X %04X:%04X %i\n", temp, CS,cpu_state.pc, ins); + return temp; +} + +static void banshee_updatemapping(banshee_t *banshee) +{ + svga_t *svga = &banshee->svga; + + if (!(banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// banshee_log("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&banshee->linear_mapping); + mem_mapping_disable(&banshee->reg_mapping_low); + mem_mapping_disable(&banshee->reg_mapping_high); + return; + } + + banshee_log("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + banshee_log("Linear framebuffer %08X ", banshee->memBaseAddr1); + mem_mapping_set_addr(&banshee->linear_mapping, banshee->memBaseAddr1, 32 << 20); + banshee_log("registers %08X\n", banshee->memBaseAddr0); + mem_mapping_set_addr(&banshee->reg_mapping_low, banshee->memBaseAddr0, 8 << 20); + mem_mapping_set_addr(&banshee->reg_mapping_high, banshee->memBaseAddr0 + 0xc00000, 20 << 20); +} + +static void banshee_render_16bpp_tiled(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + int x; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + svga->y_add])[svga->x_add]; + uint32_t addr; + int drawn = 0; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE) + addr = banshee->desktop_addr + ((banshee->desktop_y >> 1) & 31) * 128 + ((banshee->desktop_y >> 6) * banshee->desktop_stride_tiled); + else + addr = banshee->desktop_addr + (banshee->desktop_y & 31) * 128 + ((banshee->desktop_y >> 5) * banshee->desktop_stride_tiled); + + for (x = 0; x <= svga->hdisp; x += 64) + { + if (svga->hwcursor_on || svga->overlay_on) + svga->changedvram[addr >> 12] = 2; + if (svga->changedvram[addr >> 12] || svga->fullchange) + { + uint16_t *vram_p = (uint16_t *)&svga->vram[addr & svga->vram_display_mask]; + int xx; + + for (xx = 0; xx < 64; xx++) + *p++ = video_16to32[*vram_p++]; + + drawn = 1; + } + else + p += 64; + addr += 128*32; + } + + if (drawn) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + } + + banshee->desktop_y++; +} + +static void banshee_recalctimings(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + +/*7 R/W Horizontal Retrace End bit 5. - + 6 R/W Horizontal Retrace Start bit 8 0x4 + 5 R/W Horizontal Blank End bit 6. - + 4 R/W Horizontal Blank Start bit 8. 0x3 + 3 R/W Reserved. - + 2 R/W Horizontal Display Enable End bit 8. 0x1 + 1 R/W Reserved. - + 0 R/W Horizontal Total bit 8. 0x0*/ + if (svga->crtc[0x1a] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x1a] & 0x04) svga->hdisp += 0x100; +/*6 R/W Vertical Retrace Start bit 10 0x10 + 5 R/W Reserved. - + 4 R/W Vertical Blank Start bit 10. 0x15 + 3 R/W Reserved. - + 2 R/W Vertical Display Enable End bit 10 0x12 + 1 R/W Reserved. - + 0 R/W Vertical Total bit 10. 0x6*/ + if (svga->crtc[0x1b] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x1b] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x1b] & 0x10) svga->vblankstart += 0x400; + if (svga->crtc[0x1b] & 0x40) svga->vsyncstart += 0x400; +// banshee_log("svga->hdisp=%i\n", svga->hdisp); + + svga->interlace = 0; + + if (banshee->vgaInit0 & VGAINIT0_EXTENDED_SHIFT_OUT) + { + switch (VIDPROCCFG_DESKTOP_PIX_FORMAT) + { + case PIX_FORMAT_8: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case PIX_FORMAT_RGB565: + svga->render = (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) ? banshee_render_16bpp_tiled : svga_render_16bpp_highres; + svga->bpp = 16; + break; + case PIX_FORMAT_RGB24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case PIX_FORMAT_RGB32: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + default: + fatal("Unknown pixel format %08x\n", banshee->vgaInit0); + } + if (!(banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) && (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE)) + svga->rowcount = 1; + else + svga->rowcount = 0; + if (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) + svga->rowoffset = ((banshee->vidDesktopOverlayStride & 0x3fff) * 128) >> 3; + else + svga->rowoffset = (banshee->vidDesktopOverlayStride & 0x3fff) >> 3; + svga->ma_latch = banshee->vidDesktopStartAddr >> 2; + banshee->desktop_stride_tiled = (banshee->vidDesktopOverlayStride & 0x3fff) * 128 * 32; +// banshee_log("Extended shift out %i rowoffset=%i %02x\n", VIDPROCCFG_DESKTOP_PIX_FORMAT, svga->rowoffset, svga->crtc[1]); + + svga->char_width = 8; + svga->split = 99999; + + if (banshee->vidProcCfg & VIDPROCCFG_2X_MODE) + { + svga->hdisp *= 2; + svga->htotal *= 2; + } + + svga->interlace = !!(banshee->vidProcCfg & VIDPROCCFG_INTERLACE); + + svga->overlay.ena = banshee->vidProcCfg & VIDPROCCFG_OVERLAY_ENABLE; + + svga->overlay.x = voodoo->overlay.start_x; + svga->overlay.y = voodoo->overlay.start_y; + svga->overlay.cur_xsize = voodoo->overlay.size_x; + svga->overlay.cur_ysize = voodoo->overlay.size_y; + svga->overlay.pitch = (banshee->vidDesktopOverlayStride & VID_STRIDE_OVERLAY_MASK) >> VID_STRIDE_OVERLAY_SHIFT; + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) + svga->overlay.pitch *= 128*32; + if (svga->overlay.cur_xsize <= 0 || svga->overlay.cur_ysize <= 0) + svga->overlay.ena = 0; + if (svga->overlay.ena) + { +/* banshee_log("Overlay enabled : start=%i,%i end=%i,%i size=%i,%i pitch=%x\n", + voodoo->overlay.start_x, voodoo->overlay.start_y, + voodoo->overlay.end_x, voodoo->overlay.end_y, + voodoo->overlay.size_x, voodoo->overlay.size_y, + svga->overlay.pitch);*/ + if (!voodoo->overlay.start_x && !voodoo->overlay.start_y && + svga->hdisp == voodoo->overlay.size_x && svga->dispend == voodoo->overlay.size_y) + { + /*Overlay is full screen, so don't bother rendering the desktop + behind it*/ + svga->render = svga_render_null; + svga->bpp = 0; + } + } + } + else + { +// banshee_log("Normal shift out\n"); + svga->bpp = 8; + } + + svga->fb_only = (banshee->vidProcCfg & VIDPROCCFG_VIDPROC_ENABLE); + + if (((svga->miscout >> 2) & 3) == 3) + { + int k = banshee->pllCtrl0 & 3; + int m = (banshee->pllCtrl0 >> 2) & 0x3f; + int n = (banshee->pllCtrl0 >> 8) & 0xff; + double freq = (((double)n + 2) / (((double)m + 2) * (double)(1 << k))) * 14318184.0; + + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; +// svga->clock = cpuclock / freq; + +// banshee_log("svga->clock = %g %g m=%i k=%i n=%i\n", freq, freq / 1000000.0, m, k, n); + } +} + +static void banshee_ext_out(uint16_t addr, uint8_t val, void *p) +{ +// banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + +// banshee_log("banshee_ext_out: addr=%04x val=%02x\n", addr, val); + + switch (addr & 0xff) + { + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + banshee_out((addr & 0xff)+0x300, val, p); + break; + + default: + banshee_log("bad banshee_ext_out: addr=%04x val=%02x\n", addr, val); + } +} +static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + +// banshee_log("banshee_ext_outl: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); + + switch (addr & 0xff) + { + case Init_pciInit0: + banshee->pciInit0 = val; + voodoo->read_time = (banshee->agp ? agp_nonburst_time : pci_nonburst_time) + (banshee->agp ? agp_burst_time : pci_burst_time) * ((val & 0x100) ? 2 : 1); + voodoo->burst_time = (banshee->agp ? agp_burst_time : pci_burst_time) * ((val & 0x200) ? 1 : 0); + voodoo->write_time = (banshee->agp ? agp_nonburst_time : pci_nonburst_time) + voodoo->burst_time; + break; + + case Init_lfbMemoryConfig: + banshee->lfbMemoryConfig = val; +// banshee_log("lfbMemoryConfig=%08x\n", val); + voodoo->tile_base = (val & 0x1fff) << 12; + voodoo->tile_stride = 1024 << ((val >> 13) & 7); + voodoo->tile_stride_shift = 10 + ((val >> 13) & 7); + voodoo->tile_x = ((val >> 16) & 0x7f) * 128; + voodoo->tile_x_real = ((val >> 16) & 0x7f) * 128*32; + break; + + case Init_miscInit0: + banshee->miscInit0 = val; + voodoo->y_origin_swap = (val & MISCINIT0_Y_ORIGIN_SWAP_MASK) >> MISCINIT0_Y_ORIGIN_SWAP_SHIFT; + break; + case Init_miscInit1: + banshee->miscInit1 = val; + break; + case Init_dramInit0: + banshee->dramInit0 = val; + break; + case Init_dramInit1: + banshee->dramInit1 = val; + break; + case Init_agpInit0: + banshee->agpInit0 = val; + break; + + case Init_2dCommand: + banshee->command_2d = val; + break; + case Init_2dSrcBaseAddr: + banshee->srcBaseAddr_2d = val; + break; + case Init_vgaInit0: + banshee->vgaInit0 = val; + break; + case Init_vgaInit1: + banshee->vgaInit1 = val; + svga->write_bank = (val & 0x3ff) << 15; + svga->read_bank = ((val >> 10) & 0x3ff) << 15; + svga->packed_chain4 = !!(val & 0x00100000); + break; + + case PLL_pllCtrl0: + banshee->pllCtrl0 = val; + break; + case PLL_pllCtrl1: + banshee->pllCtrl1 = val; + break; + case PLL_pllCtrl2: + banshee->pllCtrl2 = val; + break; + + case DAC_dacMode: + banshee->dacMode = val; + svga->dpms = !!(val & 0x0a); + svga_recalctimings(svga); + break; + case DAC_dacAddr: + banshee->dacAddr = val & 0x1ff; + break; + case DAC_dacData: + svga->pallook[banshee->dacAddr] = val & 0xffffff; + svga->fullchange = changeframecount; + break; + + case Video_vidProcCfg: + banshee->vidProcCfg = val; +// banshee_log("vidProcCfg=%08x\n", val); + banshee->overlay_pix_fmt = (val & VIDPROCCFG_OVERLAY_PIX_FORMAT_MASK) >> VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT; + svga->hwcursor.ena = val & VIDPROCCFG_HWCURSOR_ENA; + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + + case Video_maxRgbDelta: + banshee->voodoo->scrfilterThreshold = val; + if (val > 0x00) + banshee->voodoo->scrfilterEnabled = 1; + else + banshee->voodoo->scrfilterEnabled = 0; + voodoo_threshold_check(banshee->voodoo); + banshee_log("Banshee Filter: %06x\n", val); + break; + + case Video_hwCurPatAddr: + banshee->hwCurPatAddr = val; + svga->hwcursor.addr = (val & 0xfffff0) + (svga->hwcursor.yoff * 16); + break; + case Video_hwCurLoc: + banshee->hwCurLoc = val; + svga->hwcursor.x = (val & 0x7ff) - 64; + svga->hwcursor.y = ((val >> 16) & 0x7ff) - 64; + if (svga->hwcursor.y < 0) + { + svga->hwcursor.yoff = -svga->hwcursor.y; + svga->hwcursor.y = 0; + } + else + svga->hwcursor.yoff = 0; + svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16); + svga->hwcursor.cur_xsize = 64; + svga->hwcursor.cur_ysize = 64; +// banshee_log("hwCurLoc %08x %i\n", val, svga->hwcursor.y); + break; + case Video_hwCurC0: + banshee->hwCurC0 = val; + break; + case Video_hwCurC1: + banshee->hwCurC1 = val; + break; + + case Video_vidSerialParallelPort: + banshee->vidSerialParallelPort = val; +// banshee_log("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc); + i2c_gpio_set(banshee->i2c_ddc, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W)); + i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_I2C_SCK_W), !!(val & VIDSERIAL_I2C_SDA_W)); + break; + + case Video_vidScreenSize: + banshee->vidScreenSize = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 12) & 0xfff; + break; + case Video_vidOverlayStartCoords: + voodoo->overlay.vidOverlayStartCoords = val; + voodoo->overlay.start_x = val & OVERLAY_START_X_MASK; + voodoo->overlay.start_y = (val & OVERLAY_START_Y_MASK) >> OVERLAY_START_Y_SHIFT; + voodoo->overlay.size_x = voodoo->overlay.end_x - voodoo->overlay.start_x; + voodoo->overlay.size_y = voodoo->overlay.end_y - voodoo->overlay.start_y; + svga_recalctimings(svga); + break; + case Video_vidOverlayEndScreenCoords: + voodoo->overlay.vidOverlayEndScreenCoords = val; + voodoo->overlay.end_x = val & OVERLAY_END_X_MASK; + voodoo->overlay.end_y = (val & OVERLAY_END_Y_MASK) >> OVERLAY_END_Y_SHIFT; + voodoo->overlay.size_x = (voodoo->overlay.end_x - voodoo->overlay.start_x) + 1; + voodoo->overlay.size_y = (voodoo->overlay.end_y - voodoo->overlay.start_y) + 1; + svga_recalctimings(svga); + break; + case Video_vidOverlayDudx: + voodoo->overlay.vidOverlayDudx = val & VID_DUDX_MASK; +// banshee_log("vidOverlayDudx=%08x\n", val); + break; + case Video_vidOverlayDudxOffsetSrcWidth: + voodoo->overlay.vidOverlayDudxOffsetSrcWidth = val; + voodoo->overlay.overlay_bytes = (val & OVERLAY_SRC_WIDTH_MASK) >> OVERLAY_SRC_WIDTH_SHIFT; +// banshee_log("vidOverlayDudxOffsetSrcWidth=%08x\n", val); + break; + case Video_vidOverlayDvdy: + voodoo->overlay.vidOverlayDvdy = val & VID_DVDY_MASK; +// banshee_log("vidOverlayDvdy=%08x\n", val); + break; + case Video_vidOverlayDvdyOffset: + voodoo->overlay.vidOverlayDvdyOffset = val; + break; + + + case Video_vidDesktopStartAddr: + banshee->vidDesktopStartAddr = val & 0xffffff; +// banshee_log("vidDesktopStartAddr=%08x\n", val); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + case Video_vidDesktopOverlayStride: + banshee->vidDesktopOverlayStride = val; +// banshee_log("vidDesktopOverlayStride=%08x\n", val); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; +// default: +// fatal("bad banshee_ext_outl: addr=%04x val=%08x\n", addr, val); + } +} + +static uint8_t banshee_ext_in(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + uint8_t ret = 0xff; + + switch (addr & 0xff) + { + case Init_status: case Init_status+1: case Init_status+2: case Init_status+3: + ret = (banshee_status(banshee) >> ((addr & 3) * 8)) & 0xff; +// banshee_log("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + ret = banshee_in((addr & 0xff)+0x300, p); + break; + + default: + banshee_log("bad banshee_ext_in: addr=%04x\n", addr); + break; + } + +// banshee_log("banshee_ext_in: addr=%04x val=%02x\n", addr, ret); + + return ret; +} + +static uint32_t banshee_status(banshee_t *banshee) +{ + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + int fifo_entries = FIFO_ENTRIES; + int swap_count = voodoo->swap_count; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) || + voodoo->render_voodoo_busy[0] || voodoo->render_voodoo_busy[1] || + voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3] || + voodoo->voodoo_busy; + uint32_t ret; + + ret = 0; + if (fifo_entries < 0x20) + ret |= 0x1f - fifo_entries; + else + ret |= 0x1f; + if (fifo_entries) + ret |= 0x20; + if (swap_count < 7) + ret |= (swap_count << 28); + else + ret |= (7 << 28); + if (!(svga->cgastat & 8)) + ret |= 0x40; + + if (busy) + ret |= 0x780; /*Busy*/ + + if (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + ret |= (1 << 11); + + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_thread(voodoo); + +// banshee_log("banshee_status: busy %i %i (%i %i) %i %i %i %04x(%08x):%08x %08x\n", busy, written, voodoo->cmd_written, voodoo->cmd_written_fifo, voodoo->cmd_read, voodoo->cmdfifo_depth_rd, voodoo->cmdfifo_depth_wr, CS,cs,cpu_state.pc, ret); + + return ret; +} + +static uint32_t banshee_ext_inl(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + uint32_t ret = 0xffffffff; + + cycles -= voodoo->read_time; + + switch (addr & 0xff) + { + case Init_status: + ret = banshee_status(banshee); +// banshee_log("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + case Init_pciInit0: + ret = banshee->pciInit0; + break; + case Init_lfbMemoryConfig: + ret = banshee->lfbMemoryConfig; + break; + + case Init_miscInit0: + ret = banshee->miscInit0; + break; + case Init_miscInit1: + ret = banshee->miscInit1; + break; + case Init_dramInit0: + ret = banshee->dramInit0; + break; + case Init_dramInit1: + ret = banshee->dramInit1; + break; + case Init_agpInit0: + ret = banshee->agpInit0; + break; + + case Init_vgaInit0: + ret = banshee->vgaInit0; + break; + case Init_vgaInit1: + ret = banshee->vgaInit1; + break; + + case Init_2dCommand: + ret = banshee->command_2d; + break; + case Init_2dSrcBaseAddr: + ret = banshee->srcBaseAddr_2d; + break; + case Init_strapInfo: + ret = 0x00000040; /*8 MB SGRAM, PCI, IRQ enabled, 32kB BIOS*/ + break; + + case PLL_pllCtrl0: + ret = banshee->pllCtrl0; + break; + case PLL_pllCtrl1: + ret = banshee->pllCtrl1; + break; + case PLL_pllCtrl2: + ret = banshee->pllCtrl2; + break; + + case DAC_dacMode: + ret = banshee->dacMode; + break; + case DAC_dacAddr: + ret = banshee->dacAddr; + break; + case DAC_dacData: + ret = svga->pallook[banshee->dacAddr]; + break; + + case Video_vidProcCfg: + ret = banshee->vidProcCfg; + break; + + case Video_hwCurPatAddr: + ret = banshee->hwCurPatAddr; + break; + case Video_hwCurLoc: + ret = banshee->hwCurLoc; + break; + case Video_hwCurC0: + ret = banshee->hwCurC0; + break; + case Video_hwCurC1: + ret = banshee->hwCurC1; + break; + + case Video_vidSerialParallelPort: + ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R | VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R); + if (banshee->vidSerialParallelPort & VIDSERIAL_DDC_EN) { + if (i2c_gpio_get_scl(banshee->i2c_ddc)) + ret |= VIDSERIAL_DDC_DCK_R; + if (i2c_gpio_get_sda(banshee->i2c_ddc)) + ret |= VIDSERIAL_DDC_DDA_R; + } + if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_EN) { + if (i2c_gpio_get_scl(banshee->i2c)) + ret |= VIDSERIAL_I2C_SCK_R; + if (i2c_gpio_get_sda(banshee->i2c)) + ret |= VIDSERIAL_I2C_SDA_R; + } +// banshee_log("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc); + break; + + case Video_vidScreenSize: + ret = banshee->vidScreenSize; + break; + case Video_vidOverlayStartCoords: + ret = voodoo->overlay.vidOverlayStartCoords; + break; + case Video_vidOverlayEndScreenCoords: + ret = voodoo->overlay.vidOverlayEndScreenCoords; + break; + case Video_vidOverlayDudx: + ret = voodoo->overlay.vidOverlayDudx; + break; + case Video_vidOverlayDudxOffsetSrcWidth: + ret = voodoo->overlay.vidOverlayDudxOffsetSrcWidth; + break; + case Video_vidOverlayDvdy: + ret = voodoo->overlay.vidOverlayDvdy; + break; + case Video_vidOverlayDvdyOffset: + ret = voodoo->overlay.vidOverlayDvdyOffset; + break; + + case Video_vidDesktopStartAddr: + ret = banshee->vidDesktopStartAddr; + break; + case Video_vidDesktopOverlayStride: + ret = banshee->vidDesktopOverlayStride; + break; + + default: +// fatal("bad banshee_ext_inl: addr=%04x\n", addr); + break; + } + +// /*if (addr) */banshee_log("banshee_ext_inl: addr=%04x val=%08x\n", addr, ret); + + return ret; +} + + +static uint32_t banshee_reg_readl(uint32_t addr, void *p); + +static uint8_t banshee_reg_read(uint32_t addr, void *p) +{ +// banshee_log("banshee_reg_read: addr=%08x\n", addr); + return banshee_reg_readl(addr & ~3, p) >> (8*(addr & 3)); +} + +static uint16_t banshee_reg_readw(uint32_t addr, void *p) +{ +// banshee_log("banshee_reg_readw: addr=%08x\n", addr); + return banshee_reg_readl(addr & ~3, p) >> (8*(addr & 2)); +} + +static uint32_t banshee_cmd_read(banshee_t *banshee, uint32_t addr) +{ + voodoo_t *voodoo = banshee->voodoo; + uint32_t ret = 0xffffffff; + + switch (addr & 0x1fc) + { + case cmdBaseAddr0: + ret = voodoo->cmdfifo_base >> 12; +// banshee_log("Read cmdfifo_base %08x\n", ret); + break; + + case cmdRdPtrL0: + ret = voodoo->cmdfifo_rp; +// banshee_log("Read cmdfifo_rp %08x\n", ret); + break; + + case cmdFifoDepth0: + ret = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; +// banshee_log("Read cmdfifo_depth %08x\n", ret); + break; + + case 0x108: + break; + + default: + fatal("Unknown banshee_cmd_read %08x\n", addr); + } + + return ret; +} + +static uint32_t banshee_reg_readl(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + uint32_t ret = 0xffffffff; + + cycles -= voodoo->read_time; + + switch (addr & 0x1f00000) + { + case 0x0000000: /*IO remap*/ + if (!(addr & 0x80000)) + ret = banshee_ext_inl(addr & 0xff, banshee); + else + ret = banshee_cmd_read(banshee, addr); + break; + + case 0x0100000: /*2D registers*/ + voodoo_flush(voodoo); + switch (addr & 0x1fc) + { + case SST_status: + ret = banshee_status(banshee); + break; + + case SST_intrCtrl: + ret = banshee->intrCtrl & 0x0030003f; + break; + + case 0x08: + ret = voodoo->banshee_blt.clip0Min; + break; + case 0x0c: + ret = voodoo->banshee_blt.clip0Max; + break; + case 0x10: + ret = voodoo->banshee_blt.dstBaseAddr; + break; + case 0x14: + ret = voodoo->banshee_blt.dstFormat; + break; + case 0x34: + ret = voodoo->banshee_blt.srcBaseAddr; + break; + case 0x38: + ret = voodoo->banshee_blt.commandExtra; + break; + case 0x5c: + ret = voodoo->banshee_blt.srcXY; + break; + case 0x60: + ret = voodoo->banshee_blt.colorBack; + break; + case 0x64: + ret = voodoo->banshee_blt.colorFore; + break; + case 0x68: + ret = voodoo->banshee_blt.dstSize; + break; + case 0x6c: + ret = voodoo->banshee_blt.dstXY; + break; + case 0x70: + ret = voodoo->banshee_blt.command; + break; + default: + banshee_log("banshee_reg_readl: addr=%08x\n", addr); + } + break; + + case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ + switch (addr & 0x3fc) + { + case SST_status: + ret = banshee_status(banshee); + break; + + case SST_intrCtrl: + ret = banshee->intrCtrl & 0x0030003f; + break; + + case SST_fbzColorPath: + voodoo_flush(voodoo); + ret = voodoo->params.fbzColorPath; + break; + case SST_fogMode: + voodoo_flush(voodoo); + ret = voodoo->params.fogMode; + break; + case SST_alphaMode: + voodoo_flush(voodoo); + ret = voodoo->params.alphaMode; + break; + case SST_fbzMode: + voodoo_flush(voodoo); + ret = voodoo->params.fbzMode; + break; + case SST_lfbMode: + voodoo_flush(voodoo); + ret = voodoo->lfbMode; + break; + case SST_clipLeftRight: + ret = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); + break; + case SST_clipLowYHighY: + ret = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); + break; + + case SST_clipLeftRight1: + ret = voodoo->params.clipRight1 | (voodoo->params.clipLeft1 << 16); + break; + case SST_clipTopBottom1: + ret = voodoo->params.clipHighY1 | (voodoo->params.clipLowY1 << 16); + break; + + case SST_stipple: + voodoo_flush(voodoo); + ret = voodoo->params.stipple; + break; + case SST_color0: + voodoo_flush(voodoo); + ret = voodoo->params.color0; + break; + case SST_color1: + voodoo_flush(voodoo); + ret = voodoo->params.color1; + break; + + case SST_fbiPixelsIn: + ret = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + ret = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + ret = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + ret = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + ret = voodoo->fbiPixelsOut & 0xffffff; + break; + + default: + banshee_log("banshee_reg_readl: 3D addr=%08x\n", addr); + break; + } + break; + } + +// /*if (addr != 0xe0000000) */banshee_log("banshee_reg_readl: addr=%08x ret=%08x %04x(%08x):%08x\n", addr, ret, CS,cs,cpu_state.pc); + + return ret; +} + +static void banshee_reg_write(uint32_t addr, uint8_t val, void *p) +{ +// banshee_log("banshee_reg_writeb: addr=%08x val=%02x\n", addr, val); +} + +static void banshee_reg_writew(uint32_t addr, uint16_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + cycles -= voodoo->write_time; + +// banshee_log("banshee_reg_writew: addr=%08x val=%04x\n", addr, val); + switch (addr & 0x1f00000) + { + case 0x1000000: case 0x1100000: case 0x1200000: case 0x1300000: /*3D LFB*/ + case 0x1400000: case 0x1500000: case 0x1600000: case 0x1700000: + case 0x1800000: case 0x1900000: case 0x1a00000: case 0x1b00000: + case 0x1c00000: case 0x1d00000: case 0x1e00000: case 0x1f00000: + voodoo_queue_command(voodoo, (addr & 0xffffff) | FIFO_WRITEW_FB, val); + break; + } +} + +static void banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) +{ + voodoo_t *voodoo = banshee->voodoo; +// banshee_log("banshee_cmd_write: addr=%03x val=%08x\n", addr & 0x1fc, val); + switch (addr & 0x1fc) + { + case cmdBaseAddr0: + voodoo->cmdfifo_base = (val & 0xfff) << 12; + voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); +// banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x %08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end, val); + break; + + case cmdBaseSize0: + voodoo->cmdfifo_size = val; + voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); + voodoo->cmdfifo_enabled = val & 0x100; + if (!voodoo->cmdfifo_enabled) + voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/ +// banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); + break; + +// voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12; +// banshee_log("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); +// break; + + case cmdRdPtrL0: + voodoo->cmdfifo_rp = val; + break; + case cmdAMin0: + voodoo->cmdfifo_amin = val; + break; + case cmdAMax0: + voodoo->cmdfifo_amax = val; + break; + case cmdFifoDepth0: + voodoo->cmdfifo_depth_rd = 0; + voodoo->cmdfifo_depth_wr = val & 0xffff; + break; + + default: + banshee_log("Unknown banshee_cmd_write: addr=%08x val=%08x\n", addr, val); + break; + } + +/* cmdBaseSize0 = 0x24, + cmdBump0 = 0x28, + cmdRdPtrL0 = 0x2c, + cmdRdPtrH0 = 0x30, + cmdAMin0 = 0x34, + cmdAMax0 = 0x3c, + cmdFifoDepth0 = 0x44, + cmdHoleCnt0 = 0x48 + }*/ +} + +static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + +// banshee_log("banshee_reg_writel: addr=%08x val=%08x\n", addr, val); + + switch (addr & 0x1f00000) + { + case 0x0000000: /*IO remap*/ + if (!(addr & 0x80000)) + banshee_ext_outl(addr & 0xff, val, banshee); + else + banshee_cmd_write(banshee, addr, val); +// banshee_log("CMD!!! write %08x %08x\n", addr, val); + break; + + case 0x0100000: /*2D registers*/ + if ((addr & 0x3fc) == SST_intrCtrl) { + banshee->intrCtrl = val & 0x0030003f; + } else { + voodoo_queue_command(voodoo, (addr & 0x1fc) | FIFO_WRITEL_2DREG, val); + } + break; + + case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ + switch (addr & 0x3fc) + { + case SST_intrCtrl: + banshee->intrCtrl = val & 0x0030003f; +// banshee_log("intrCtrl=%08x\n", val); + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x\n", val); + break; + + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); +// banshee_log("SST_swapbufferCMD write: %i %i\n", voodoo->cmd_written, voodoo->cmd_written_fifo); + break; + case SST_triangleCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_ftriangleCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_fastfillCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_nopCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + + case SST_swapPending: + thread_wait_mutex(voodoo->swap_mutex); + voodoo->swap_count++; + thread_release_mutex(voodoo->swap_mutex); +// voodoo->cmd_written++; + break; + + default: + voodoo_queue_command(voodoo, (addr & 0x3ffffc) | FIFO_WRITEL_REG, val); + break; + } + break; + + case 0x0600000: case 0x0700000: /*Texture download*/ + voodoo->tex_count++; + voodoo_queue_command(voodoo, (addr & 0x1ffffc) | FIFO_WRITEL_TEX, val); + break; + + case 0x1000000: case 0x1100000: case 0x1200000: case 0x1300000: /*3D LFB*/ + case 0x1400000: case 0x1500000: case 0x1600000: case 0x1700000: + case 0x1800000: case 0x1900000: case 0x1a00000: case 0x1b00000: + case 0x1c00000: case 0x1d00000: case 0x1e00000: case 0x1f00000: + voodoo_queue_command(voodoo, (addr & 0xfffffc) | FIFO_WRITEL_FB, val); + break; + } +} + +static uint8_t banshee_read_linear(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// banshee_log(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + cycles -= video_timing_read_b; + +// banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return svga->vram[addr & svga->vram_mask]; +} + +static uint16_t banshee_read_linear_w(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr & 1) + return banshee_read_linear(addr, p) | (banshee_read_linear(addr+1, p) << 8); + + cycles -= voodoo->read_time; + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// banshee_log(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + cycles -= video_timing_read_w; + +// banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} + +static uint32_t banshee_read_linear_l(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr & 3) + return banshee_read_linear_w(addr, p) | (banshee_read_linear_w(addr+2, p) << 16); + + cycles -= voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// banshee_log(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + cycles -= video_timing_read_l; + +// banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + +static void banshee_write_linear(uint32_t addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->write_time; + +// banshee_log("write_linear: addr=%08x val=%02x\n", addr, val); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// banshee_log(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return; + + cycles -= video_timing_write_b; + + svga->changedvram[addr >> 12] = changeframecount; + svga->vram[addr & svga->vram_mask] = val; +} + +static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr & 1) + { + banshee_write_linear(addr, val, p); + banshee_write_linear(addr + 1, val >> 8, p); + return; + } + + cycles -= voodoo->write_time; +// banshee_log("write_linear: addr=%08x val=%02x\n", addr, val); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// banshee_log(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return; + + cycles -= video_timing_write_w; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr & svga->vram_mask] = val; +} + +static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + int timing; + + if (addr & 3) + { + banshee_write_linear_w(addr, val, p); + banshee_write_linear_w(addr + 2, val >> 16, p); + return; + } + + if (addr == voodoo->last_write_addr+4) + timing = voodoo->burst_time; + else + timing = voodoo->write_time; + cycles -= timing; + voodoo->last_write_addr = addr; + +// /*if (val) */banshee_log("write_linear_l: addr=%08x val=%08x %08x\n", addr, val, voodoo->tile_base); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// banshee_log(" Tile %08x->%08x->%08x->%08x %i %i tile_x=%i\n", old_addr, addr_off, addr2, addr, x, y, voodoo->tile_x_real); + } + + if (addr >= svga->vram_max) + return; + + cycles -= video_timing_write_l; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr & svga->vram_mask] = val; + if (voodoo->cmdfifo_enabled && addr >= voodoo->cmdfifo_base && addr < voodoo->cmdfifo_end) + { +// banshee_log("CMDFIFO write %08x %08x old amin=%08x amax=%08x hlcnt=%i depth_wr=%i rp=%08x\n", addr, val, voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount, voodoo->cmdfifo_depth_wr, voodoo->cmdfifo_rp); + if (addr == voodoo->cmdfifo_base && !voodoo->cmdfifo_holecount) + { +// if (voodoo->cmdfifo_holecount) +// fatal("CMDFIFO reset pointers while outstanding holes\n"); + /*Reset pointers*/ + voodoo->cmdfifo_amin = voodoo->cmdfifo_base; + voodoo->cmdfifo_amax = voodoo->cmdfifo_base; + voodoo->cmdfifo_depth_wr++; + voodoo_wake_fifo_thread(voodoo); + } + else if (voodoo->cmdfifo_holecount) + { +// if ((addr <= voodoo->cmdfifo_amin && voodoo->cmdfifo_amin != -4) || addr >= voodoo->cmdfifo_amax) +// fatal("CMDFIFO holecount write outside of amin/amax - amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); +// banshee_log("holecount %i\n", voodoo->cmdfifo_holecount); + voodoo->cmdfifo_holecount--; + if (!voodoo->cmdfifo_holecount) + { + /*Filled in holes, resume normal operation*/ + voodoo->cmdfifo_depth_wr += ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2); + voodoo->cmdfifo_amin = voodoo->cmdfifo_amax; + voodoo_wake_fifo_thread(voodoo); +// banshee_log("hole filled! amin=%08x amax=%08x added %i words\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, words_to_add); + } + } + else if (addr == voodoo->cmdfifo_amax+4) + { + /*In-order write*/ + voodoo->cmdfifo_amin = addr; + voodoo->cmdfifo_amax = addr; + voodoo->cmdfifo_depth_wr++; + voodoo_wake_fifo_thread(voodoo); + } + else + { + /*Out-of-order write*/ + if (addr < voodoo->cmdfifo_amin) + { + /*Reset back to start. Note that write is still out of order!*/ + voodoo->cmdfifo_amin = voodoo->cmdfifo_base-4; + + } +// else if (addr < voodoo->cmdfifo_amax) +// fatal("Out-of-order write really out of order\n"); + voodoo->cmdfifo_amax = addr; + voodoo->cmdfifo_holecount = ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2) - 1; +// banshee_log("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); + } + } +} + +void banshee_hwcursor_draw(svga_t *svga, int displine) +{ + banshee_t *banshee = (banshee_t *)svga->p; + int x, c; + int x_off; + int xx; + uint32_t col0 = banshee->hwCurC0; + uint32_t col1 = banshee->hwCurC1; + uint8_t plane0[8], plane1[8]; + + for (c = 0; c < 8; c++) + plane0[c] = svga->vram[svga->hwcursor_latch.addr + c]; + for (c = 0; c < 8; c++) + plane1[c] = svga->vram[svga->hwcursor_latch.addr + c + 8]; + svga->hwcursor_latch.addr += 16; + + x_off = svga->hwcursor_latch.x; + + if (banshee->vidProcCfg & VIDPROCCFG_CURSOR_MODE) + { + /*X11 mode*/ + for (x = 0; x < 64; x += 8) + { + if (x_off > -8) + { + for (xx = 0; xx < 8; xx++) + { + if (plane0[x >> 3] & (1 << 7)) + ((uint32_t *)buffer32->line[displine])[x_off + xx + svga->x_add] = (plane1[x >> 3] & (1 << 7)) ? col1 : col0; + + plane0[x >> 3] <<= 1; + plane1[x >> 3] <<= 1; + } + } + + x_off += 8; + } + } + else + { + /*Windows mode*/ + for (x = 0; x < 64; x += 8) + { + if (x_off > -8) + { + for (xx = 0; xx < 8; xx++) + { + if (!(plane0[x >> 3] & (1 << 7))) + ((uint32_t *)buffer32->line[displine])[x_off + xx + svga->x_add] = (plane1[x >> 3] & (1 << 7)) ? col1 : col0; + else if (plane1[x >> 3] & (1 << 7)) + ((uint32_t *)buffer32->line[displine])[x_off + xx + svga->x_add] ^= 0xffffff; + + plane0[x >> 3] <<= 1; + plane1[x >> 3] <<= 1; + } + } + + x_off += 8; + } + } +} + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_RGB565(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ + { \ + uint16_t data = *(uint16_t *)src; \ + int r = data & 0x1f; \ + int g = (data >> 5) & 0x3f; \ + int b = data >> 11; \ + \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ + buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + else \ + buf[wp++] = (clut[r << 3] & 0x0000ff) | \ + (clut[g << 2] & 0x00ff00) | \ + (clut[b << 3] & 0xff0000); \ + src += 2; \ + } \ + } while (0) + +#define DECODE_RGB565_TILED(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + uint32_t base_addr = (buf == banshee->overlay_buffer[1]) ? src_addr2 : src_addr; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ + { \ + uint16_t data = *(uint16_t *)&svga->vram[(base_addr + (c & 127) + (c >> 7)*128*32) & svga->vram_mask]; \ + int r = data & 0x1f; \ + int g = (data >> 5) & 0x3f; \ + int b = data >> 11; \ + \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ + buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + else \ + buf[wp++] = (clut[r << 3] & 0x0000ff) | \ + (clut[g << 2] & 0x00ff00) | \ + (clut[b << 3] & 0xff0000); \ + } \ + } while (0) + +#define DECODE_YUYV422(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 4) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + } \ + } while (0) + +#define DECODE_UYUV422(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 4) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + Cr = src[0] - 0x80; \ + y1 = src[1]; \ + Cb = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + } \ + } while (0) + + +#define OVERLAY_SAMPLE(buf) \ + do \ + { \ + switch (banshee->overlay_pix_fmt) \ + { \ + case 0: \ + break; \ + \ + case OVERLAY_FMT_YUYV422: \ + DECODE_YUYV422(buf); \ + break; \ + \ + case OVERLAY_FMT_UYVY422: \ + DECODE_UYUV422(buf); \ + break; \ + \ + case OVERLAY_FMT_565: \ + case OVERLAY_FMT_565_DITHER: \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) \ + DECODE_RGB565_TILED(buf); \ + else \ + DECODE_RGB565(buf); \ + break; \ + \ + default: \ + fatal("Unknown overlay pix fmt %i\n", banshee->overlay_pix_fmt); \ + } \ + } while (0) + +/* generate both filters for the static table here */ +void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg) +{ + int g, h; + float difference, diffg; + float thiscol, thiscolg; + float clr, clg = 0; + float hack = 1.0f; + // pre-clamping + + fcr *= hack; + fcg *= hack; + + + /* box prefilter */ + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = g; + avgdiff = avg - h; + + avgdiff = avgdiff * 0.75f; + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = g; + + if (h > g) + { + clr = clg = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + + thiscol = g; + thiscolg = g; + + if (thiscol>g+fcr) + thiscol=g+fcr; + if (thiscolg>g+fcg) + thiscolg=g+fcg; + + if (thiscol>g+difference) + thiscol=g+difference; + if (thiscolg>g+difference) + thiscolg=g+difference; + + // hmm this might not be working out.. + int ugh = g - h; + if (ugh < fcr) + thiscol = h; + if (ugh < fcg) + thiscolg = h; + } + + if (difference > fcr) + thiscol = g; + if (difference > fcg) + thiscolg = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + + vb_filter_bx_rb[g][h] = (thiscol); + vb_filter_bx_g [g][h] = (thiscolg); + + } + float lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } + + /* 4x1 and 2x2 filter */ + //fcr *= 5; + //fcg *= 6; + + for (g=0;g<256;g++) // pixel 1 + { + for (h=0;h<256;h++) // pixel 2 + { + difference = (float)(h - g); + diffg = difference; + + thiscol = thiscolg = g; + + if (difference > fcr) + difference = fcr; + if (difference < -fcr) + difference = -fcr; + + if (diffg > fcg) + diffg = fcg; + if (diffg < -fcg) + diffg = -fcg; + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > 255) + thiscol = 255; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > 255) + thiscolg = 255; + + vb_filter_v1_rb[g][h] = thiscol; + vb_filter_v1_g [g][h] = thiscolg; + + } + } + +} + + +static void banshee_overlay_draw(svga_t *svga, int displine) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + uint32_t *p; + int x; + int y = voodoo->overlay.src_y >> 20; + uint32_t src_addr = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? + ((y & 31) * 128 + (y >> 5) * svga->overlay_latch.pitch) : + y * svga->overlay_latch.pitch); + uint32_t src_addr2 = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? + (((y + 1) & 31) * 128 + ((y + 1) >> 5) * svga->overlay_latch.pitch) : + (y + 1) * svga->overlay_latch.pitch); + uint8_t *src = &svga->vram[src_addr & svga->vram_mask]; + uint32_t src_x = 0; + unsigned int y_coeff = (voodoo->overlay.src_y & 0xfffff) >> 4; + int skip_filtering; + uint32_t *clut = &svga->pallook[(banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_SEL) ? 256 : 0]; + + if (svga->render == svga_render_null && + !svga->changedvram[src_addr >> 12] && !svga->changedvram[src_addr2 >> 12] && + !svga->fullchange && + ((voodoo->overlay.src_y >> 20) < 2048 && !voodoo->dirty_line[voodoo->overlay.src_y >> 20]) && + !(banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE)) + { + voodoo->overlay.src_y += (1 << 20); + return; + } + + if ((voodoo->overlay.src_y >> 20) < 2048) + voodoo->dirty_line[voodoo->overlay.src_y >> 20] = 0; +// pclog("displine=%i addr=%08x %08x %08x %08x\n", displine, svga->overlay_latch.addr, src_addr, voodoo->overlay.vidOverlayDvdy, *(uint32_t *)src); +// if (src_addr >= 0x800000) +// fatal("overlay out of range!\n"); + p = &((uint32_t *)buffer32->line[displine])[svga->overlay_latch.x + svga->x_add]; + + if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) + skip_filtering = ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) != VIDPROCCFG_FILTER_MODE_BILINEAR && + !(banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) && !(banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_DITHER_4X4) && + !(banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_DITHER_2X2)); + else + skip_filtering = ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) != VIDPROCCFG_FILTER_MODE_BILINEAR && + !(banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)); + + if (skip_filtering) + { + /*No scaling or filtering required, just write straight to output buffer*/ + OVERLAY_SAMPLE(p); + } + else + { + OVERLAY_SAMPLE(banshee->overlay_buffer[0]); + + switch (banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) + { + case VIDPROCCFG_FILTER_MODE_BILINEAR: + src = &svga->vram[src_addr2 & svga->vram_mask]; + OVERLAY_SAMPLE(banshee->overlay_buffer[1]); + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + { + unsigned int x_coeff = (src_x & 0xfffff) >> 4; + unsigned int coeffs[4] = { + ((0x10000 - x_coeff) * (0x10000 - y_coeff)) >> 16, + ( x_coeff * (0x10000 - y_coeff)) >> 16, + ((0x10000 - x_coeff) * y_coeff) >> 16, + ( x_coeff * y_coeff) >> 16 + }; + uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; + uint32_t samp1 = banshee->overlay_buffer[0][(src_x >> 20) + 1]; + uint32_t samp2 = banshee->overlay_buffer[1][src_x >> 20]; + uint32_t samp3 = banshee->overlay_buffer[1][(src_x >> 20) + 1]; + int r = (((samp0 >> 16) & 0xff) * coeffs[0] + + ((samp1 >> 16) & 0xff) * coeffs[1] + + ((samp2 >> 16) & 0xff) * coeffs[2] + + ((samp3 >> 16) & 0xff) * coeffs[3]) >> 16; + int g = (((samp0 >> 8) & 0xff) * coeffs[0] + + ((samp1 >> 8) & 0xff) * coeffs[1] + + ((samp2 >> 8) & 0xff) * coeffs[2] + + ((samp3 >> 8) & 0xff) * coeffs[3]) >> 16; + int b = ((samp0 & 0xff) * coeffs[0] + + (samp1 & 0xff) * coeffs[1] + + (samp2 & 0xff) * coeffs[2] + + (samp3 & 0xff) * coeffs[3]) >> 16; + p[x] = (r << 16) | (g << 8) | b; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + { + uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; + uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20]; + int r = (((samp0 >> 16) & 0xff) * (0x10000 - y_coeff) + + ((samp1 >> 16) & 0xff) * y_coeff) >> 16; + int g = (((samp0 >> 8) & 0xff) * (0x10000 - y_coeff) + + ((samp1 >> 8) & 0xff) * y_coeff) >> 16; + int b = ((samp0 & 0xff) * (0x10000 - y_coeff) + + (samp1 & 0xff) * y_coeff) >> 16; + p[x] = (r << 16) | (g << 8) | b; + } + } + break; + + case VIDPROCCFG_FILTER_MODE_DITHER_4X4: + if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) + { + uint8_t *fil = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *fil3 = malloc((svga->overlay_latch.cur_xsize) * 3); + + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* leilei HACK - don't know of real 4x1 hscaled behavior yet, double for now */ + { + for (x=0; xoverlay_latch.cur_xsize;x++) + { + fil[x*3] = ((banshee->overlay_buffer[0][src_x >> 20])); + fil[x*3+1] = ((banshee->overlay_buffer[0][src_x >> 20] >> 8)); + fil[x*3+2] = ((banshee->overlay_buffer[0][src_x >> 20] >> 16)); + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x=0; xoverlay_latch.cur_xsize;x++) + { + fil[x*3] = ((banshee->overlay_buffer[0][x])); + fil[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); + fil[x*3+2] = ((banshee->overlay_buffer[0][x] >> 16)); + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + } + } + if (y % 2 == 0) + { + for (x=0; xoverlay_latch.cur_xsize;x++) + { + fil[x*3] = banshee->voodoo->purpleline[fil[x*3+0]][0]; + fil[x*3+1] = banshee->voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = banshee->voodoo->purpleline[fil[x*3+2]][2]; + } + } + + for (x=1; xoverlay_latch.cur_xsize;x++) + { + fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; + fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; + fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; + } + for (x=1; xoverlay_latch.cur_xsize;x++) + { + fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x-1) *3]]; + fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x-1) *3+1]]; + fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x-1) *3+2]]; + } + for (x=1; xoverlay_latch.cur_xsize;x++) + { + fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; + fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; + fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; + } + for (x=0; xoverlay_latch.cur_xsize;x++) + { + fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x+1) *3]]; + fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x+1) *3+1]]; + fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x+1) *3+2]]; + p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; + } + + free(fil); + free(fil3); + } + else /* filter disabled by emulator option */ + { + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + { + p[x] = banshee->overlay_buffer[0][src_x >> 20]; + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + p[x] = banshee->overlay_buffer[0][x]; + } + } + break; + + case VIDPROCCFG_FILTER_MODE_DITHER_2X2: + if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) + { + uint8_t *fil = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *soak = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *soak2 = malloc((svga->overlay_latch.cur_xsize) * 3); + + uint8_t *samp1 = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *samp2 = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *samp3 = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *samp4 = malloc((svga->overlay_latch.cur_xsize) * 3); + + src = &svga->vram[src_addr2 & svga->vram_mask]; + OVERLAY_SAMPLE(banshee->overlay_buffer[1]); + for (x=0; xoverlay_latch.cur_xsize;x++) + { + samp1[x*3] = ((banshee->overlay_buffer[0][x])); + samp1[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); + samp1[x*3+2] = ((banshee->overlay_buffer[0][x] >> 16)); + + samp2[x*3+0] = ((banshee->overlay_buffer[0][x+1])); + samp2[x*3+1] = ((banshee->overlay_buffer[0][x+1] >> 8)); + samp2[x*3+2] = ((banshee->overlay_buffer[0][x+1] >> 16)); + + samp3[x*3+0] = ((banshee->overlay_buffer[1][x])); + samp3[x*3+1] = ((banshee->overlay_buffer[1][x] >> 8)); + samp3[x*3+2] = ((banshee->overlay_buffer[1][x] >> 16)); + + samp4[x*3+0] = ((banshee->overlay_buffer[1][x+1])); + samp4[x*3+1] = ((banshee->overlay_buffer[1][x+1] >> 8)); + samp4[x*3+2] = ((banshee->overlay_buffer[1][x+1] >> 16)); + + /* sample two lines */ + + soak[x*3+0] = vb_filter_bx_rb [samp1[x*3+0]] [samp2[x*3+0]]; + soak[x*3+1] = vb_filter_bx_g [samp1[x*3+1]] [samp2[x*3+1]]; + soak[x*3+2] = vb_filter_bx_rb [samp1[x*3+2]] [samp2[x*3+2]]; + + soak2[x*3+0] = vb_filter_bx_rb[samp3[x*3+0]] [samp4[x*3+0]]; + soak2[x*3+1] = vb_filter_bx_g [samp3[x*3+1]] [samp4[x*3+1]]; + soak2[x*3+2] = vb_filter_bx_rb[samp3[x*3+2]] [samp4[x*3+2]]; + + /* then pour it on the rest */ + + fil[x*3+0] = vb_filter_v1_rb[soak[x*3+0]] [soak2[x*3+0]]; + fil[x*3+1] = vb_filter_v1_g [soak[x*3+1]] [soak2[x*3+1]]; + fil[x*3+2] = vb_filter_v1_rb[soak[x*3+2]] [soak2[x*3+2]]; + } + + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* 2x2 on a scaled low res */ + { + for (x=0; xoverlay_latch.cur_xsize;x++) + { + p[x] = (fil[(src_x >> 20)*3+2] << 16) | (fil[(src_x >> 20)*3+1] << 8) | fil[(src_x >> 20)*3]; + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x=0; xoverlay_latch.cur_xsize;x++) + { + p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; + } + } + + free(fil); + free(soak); + free(soak2); + free(samp1); + free(samp2); + free(samp3); + free(samp4); + } + else /* filter disabled by emulator option */ + { + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + { + p[x] = banshee->overlay_buffer[0][src_x >> 20]; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + p[x] = banshee->overlay_buffer[0][x]; + } + } + break; + + case VIDPROCCFG_FILTER_MODE_POINT: + default: + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + { + p[x] = banshee->overlay_buffer[0][src_x >> 20]; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) + p[x] = banshee->overlay_buffer[0][x]; + } + break; + } + } + + if (banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE) + voodoo->overlay.src_y += voodoo->overlay.vidOverlayDvdy; + else + voodoo->overlay.src_y += (1 << 20); +} + +void banshee_set_overlay_addr(void *p, uint32_t addr) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + banshee->svga.overlay.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; + banshee->svga.overlay_latch.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); +} + +static void banshee_vsync_callback(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + + voodoo->retrace_count++; + thread_wait_mutex(voodoo->swap_mutex); + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_release_mutex(voodoo->swap_mutex); + + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + voodoo->retrace_count = 0; + banshee_set_overlay_addr(banshee, voodoo->swap_offset); + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + else + thread_release_mutex(voodoo->swap_mutex); + + voodoo->overlay.src_y = 0; + banshee->desktop_addr = banshee->vidDesktopStartAddr; + banshee->desktop_y = 0; +} + +static uint8_t banshee_pci_read(int func, int addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + uint8_t ret = 0; + + if (func) + return 0xff; +// banshee_log("Banshee PCI read %08X ", addr); + switch (addr) + { + case 0x00: ret = 0x1a; break; /*3DFX*/ + case 0x01: ret = 0x12; break; + + case 0x02: ret = (banshee->type == TYPE_BANSHEE) ? 0x03 : 0x05; break; + case 0x03: ret = 0x00; break; + + case 0x04: ret = banshee->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = banshee->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = (banshee->type == TYPE_BANSHEE) ? 3 : 1; break; /*Revision ID*/ + case 0x09: ret = 0; break; /*Programming interface*/ + + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ + case 0x0b: ret = 0x03; break; + + case 0x0d: ret = banshee->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break; /*memBaseAddr0*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = banshee->memBaseAddr0 >> 24; break; + + case 0x14: ret = 0x00; break; /*memBaseAddr1*/ + case 0x15: ret = 0x00; break; + case 0x16: ret = 0x00; break; + case 0x17: ret = banshee->memBaseAddr1 >> 24; break; + + case 0x18: ret = 0x01; break; /*ioBaseAddr*/ + case 0x19: ret = banshee->ioBaseAddr >> 8; break; + case 0x1a: ret = banshee->ioBaseAddr >> 16; break; + case 0x1b: ret = banshee->ioBaseAddr >> 24; break; + + /*Subsystem vendor ID*/ + case 0x2c: ret = banshee->pci_regs[0x2c]; break; + case 0x2d: ret = banshee->pci_regs[0x2d]; break; + case 0x2e: ret = banshee->pci_regs[0x2e]; break; + case 0x2f: ret = banshee->pci_regs[0x2f]; break; + + case 0x30: ret = banshee->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = banshee->pci_regs[0x32]; break; + case 0x33: ret = banshee->pci_regs[0x33]; break; + + case 0x34: ret = banshee->agp ? 0x54 : 0x60; break; + + case 0x3c: ret = banshee->pci_regs[0x3c]; break; + + case 0x3d: ret = 0x01; break; /*INTA*/ + + case 0x3e: ret = 0x04; break; + case 0x3f: ret = 0xff; break; + + case 0x40: ret = 0x01; break; + + case 0x50: ret = banshee->pci_regs[0x50]; break; + + case 0x54: ret = 0x02; break; + case 0x55: ret = 0x60; break; + case 0x56: ret = 0x10; break; /* assumed AGP 1.0 */ + + case 0x58: ret = (banshee->type == TYPE_BANSHEE) ? 0x21 : 0x23; break; + case 0x59: ret = 0x02; break; + case 0x5b: ret = 0x07; break; + + case 0x5c: ret = banshee->pci_regs[0x5c]; break; + case 0x5d: ret = banshee->pci_regs[0x5d]; break; + case 0x5e: ret = banshee->pci_regs[0x5e]; break; + case 0x5f: ret = banshee->pci_regs[0x5f]; break; + + case 0x60: ret = 0x01; break; + case 0x62: ret = 0x21; break; + + case 0x64: ret = banshee->pci_regs[0x64]; break; + case 0x65: ret = banshee->pci_regs[0x65]; break; + case 0x66: ret = banshee->pci_regs[0x66]; break; + case 0x67: ret = banshee->pci_regs[0x67]; break; + } +// banshee_log("%02X\n", ret); + return ret; +} + +static void banshee_pci_write(int func, int addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + + if (func) + return; +// banshee_log("Banshee write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + return; + + case PCI_REG_COMMAND: + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + if (banshee->ioBaseAddr) + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + + io_sethandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + if (banshee->ioBaseAddr) + io_sethandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + } + else + { + io_removehandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + } + banshee->pci_regs[PCI_REG_COMMAND] = val & 0x27; + banshee_updatemapping(banshee); + return; + case 0x07: + banshee->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + banshee->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + banshee->memBaseAddr0 = (val & 0xfe) << 24; + banshee_updatemapping(banshee); + return; + + case 0x17: + banshee->memBaseAddr1 = (val & 0xfe) << 24; + banshee_updatemapping(banshee); + return; + + case 0x19: + if (banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + banshee->ioBaseAddr &= 0xffff00ff; + banshee->ioBaseAddr |= val << 8; + if ((banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && banshee->ioBaseAddr) + io_sethandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + banshee_log("Banshee ioBaseAddr=%08x\n", banshee->ioBaseAddr); + return; + + case 0x1a: + banshee->ioBaseAddr &= 0xff00ffff; + banshee->ioBaseAddr |= val << 16; + break; + + case 0x1b: + banshee->ioBaseAddr &= 0x00ffffff; + banshee->ioBaseAddr |= val << 24; + break; + + case 0x30: case 0x32: case 0x33: + if (!banshee->has_bios) + return; + banshee->pci_regs[addr] = val; + if (banshee->pci_regs[0x30] & 0x01) + { + uint32_t biosaddr = (banshee->pci_regs[0x32] << 16) | (banshee->pci_regs[0x33] << 24); + banshee_log("Banshee bios_rom enabled at %08x\n", biosaddr); + mem_mapping_set_addr(&banshee->bios_rom.mapping, biosaddr, 0x10000); + mem_mapping_enable(&banshee->bios_rom.mapping); + } + else + { + banshee_log("Banshee bios_rom disabled\n"); + mem_mapping_disable(&banshee->bios_rom.mapping); + } + return; + case 0x3c: case 0x50: case 0x65: case 0x67: + banshee->pci_regs[addr] = val; + return; + + case 0x5c: + banshee->pci_regs[0x5c] = val & 0x27; + return; + + case 0x5d: + banshee->pci_regs[0x5d] = val & 0x03; + return; + + case 0x5f: + banshee->pci_regs[0x5e] = val; + return; + + case 0x64: + banshee->pci_regs[0x64] = val & 0x03; + return; + + case 0x66: + banshee->pci_regs[0x66] = val & 0xc0; + return; + } +} + +// clang-format off +static const device_config_t banshee_sgram_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "8 MB", + .value = 8 + }, + { + .description = "16 MB", + .value = 16 + }, + { + .description = "" + } + }, + .default_int = 16 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "4", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = CONFIG_END + } +}; + +static const device_config_t banshee_sdram_config[] = { + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "4", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = CONFIG_END + } +}; +// clang-format on + +static void *banshee_init_common(const device_t *info, char *fn, int has_sgram, int type, int voodoo_type, int agp) +{ + int mem_size; + banshee_t *banshee = malloc(sizeof(banshee_t)); + memset(banshee, 0, sizeof(banshee_t)); + + banshee->type = type; + banshee->agp = agp; + banshee->has_bios = !!fn; + + if (banshee->has_bios) { + rom_init(&banshee->bios_rom, fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&banshee->bios_rom.mapping); + } + + if (!banshee->has_bios) + mem_size = info->local; /* fixed size for on-board chips */ + else if (has_sgram) { + if (banshee->type == TYPE_VELOCITY100) + mem_size = 8; /* Velocity 100 only supports 8 MB */ + else + mem_size = device_get_config_int("memory"); + } else + mem_size = 16; /* SDRAM Banshee only supports 16 MB */ + + svga_init(info, &banshee->svga, banshee, mem_size << 20, + banshee_recalctimings, + banshee_in, banshee_out, + banshee_hwcursor_draw, + banshee_overlay_draw); + banshee->svga.vsync_callback = banshee_vsync_callback; + + mem_mapping_add(&banshee->linear_mapping, 0, 0, banshee_read_linear, + banshee_read_linear_w, + banshee_read_linear_l, + banshee_write_linear, + banshee_write_linear_w, + banshee_write_linear_l, + NULL, + MEM_MAPPING_EXTERNAL, + &banshee->svga); + mem_mapping_add(&banshee->reg_mapping_low, 0, 0,banshee_reg_read, + banshee_reg_readw, + banshee_reg_readl, + banshee_reg_write, + banshee_reg_writew, + banshee_reg_writel, + NULL, + MEM_MAPPING_EXTERNAL, + banshee); + mem_mapping_add(&banshee->reg_mapping_high, 0,0,banshee_reg_read, + banshee_reg_readw, + banshee_reg_readl, + banshee_reg_write, + banshee_reg_writew, + banshee_reg_writel, + NULL, + MEM_MAPPING_EXTERNAL, + banshee); + + banshee->svga.vblank_start = banshee_vblank_start; + +// io_sethandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + + banshee->svga.bpp = 8; + banshee->svga.miscout = 1; + + banshee->dramInit0 = 1 << 27; + if (has_sgram && mem_size == 16) + banshee->dramInit0 |= (1 << 26); /*2xSGRAM = 16 MB*/ + if (!has_sgram) + banshee->dramInit1 = 1 << 30; /*SDRAM*/ + banshee->svga.decode_mask = 0x1ffffff; + + banshee->card = pci_add_card(banshee->agp ? PCI_ADD_AGP : PCI_ADD_VIDEO, banshee_pci_read, banshee_pci_write, banshee); + + banshee->voodoo = voodoo_2d3d_card_init(voodoo_type); + banshee->voodoo->p = banshee; + banshee->voodoo->vram = banshee->svga.vram; + banshee->voodoo->changedvram = banshee->svga.changedvram; + banshee->voodoo->fb_mem = banshee->svga.vram; + banshee->voodoo->fb_mask = banshee->svga.vram_mask; + banshee->voodoo->tex_mem[0] = banshee->svga.vram; + banshee->voodoo->tex_mem_w[0] = (uint16_t *)banshee->svga.vram; + banshee->voodoo->tex_mem[1] = banshee->svga.vram; + banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram; + banshee->voodoo->texture_mask = banshee->svga.vram_mask; + voodoo_generate_filter_v1(banshee->voodoo); + + banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; + + banshee->i2c = i2c_gpio_init("i2c_voodoo_banshee"); + banshee->i2c_ddc = i2c_gpio_init("ddc_voodoo_banshee"); + banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c_ddc)); + + switch (type) + { + case TYPE_BANSHEE: + if (has_sgram) { + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x04; + banshee->pci_regs[0x2f] = 0x00; + } else { + banshee->pci_regs[0x2c] = 0x02; + banshee->pci_regs[0x2d] = 0x11; + banshee->pci_regs[0x2e] = 0x17; + banshee->pci_regs[0x2f] = 0x10; + } + break; + + case TYPE_V3_2000: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x30; + banshee->pci_regs[0x2f] = 0x00; + break; + + case TYPE_V3_3000: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x3a; + banshee->pci_regs[0x2f] = 0x00; + break; + + case TYPE_VELOCITY100: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x4b; + banshee->pci_regs[0x2f] = 0x00; + break; + } + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, banshee->agp ? &timing_banshee_agp : &timing_banshee); + + return banshee; +} + +static void *banshee_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/Pci_sg.rom", 1, TYPE_BANSHEE, VOODOO_BANSHEE, 0); +} +static void *creative_banshee_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/BlasterPCI.rom", 0, TYPE_BANSHEE, VOODOO_BANSHEE, 0); +} +static void *v3_2000_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3, 0); +} +static void *v3_2000_agp_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3, 1); +} +static void *v3_2000_agp_onboard_init(const device_t *info) +{ + return banshee_init_common(info, NULL, 0, TYPE_V3_2000, VOODOO_3, 1); +} +static void *v3_3000_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3, 0); +} +static void *v3_3000_agp_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3, 1); +} +static void *velocity_100_agp_init(const device_t *info) +{ + return banshee_init_common(info, "roms/video/voodoo/Velocity100.VBI", 1, TYPE_VELOCITY100, VOODOO_3, 1); +} + +static int banshee_available(void) +{ + return rom_present("roms/video/voodoo/Pci_sg.rom"); +} +static int creative_banshee_available(void) +{ + return rom_present("roms/video/voodoo/BlasterPCI.rom"); +} +static int v3_2000_available(void) +{ + return rom_present("roms/video/voodoo/2k11sd.rom"); +} +#define v3_2000_agp_available v3_2000_available +static int v3_3000_available(void) +{ + return rom_present("roms/video/voodoo/3k12sd.rom"); +} +#define v3_3000_agp_available v3_3000_available +static int velocity_100_available(void) +{ + return rom_present("roms/video/voodoo/Velocity100.VBI"); +} + +static void banshee_close(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + voodoo_card_close(banshee->voodoo); + svga_close(&banshee->svga); + ddc_close(banshee->ddc); + i2c_gpio_close(banshee->i2c_ddc); + i2c_gpio_close(banshee->i2c); + + free(banshee); +} + +static void banshee_speed_changed(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + svga_recalctimings(&banshee->svga); +} + +static void banshee_force_redraw(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + banshee->svga.fullchange = changeframecount; +} + +const device_t voodoo_banshee_device = { + .name = "3dfx Voodoo Banshee", + .internal_name = "voodoo_banshee_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = banshee_init, + .close = banshee_close, + .reset = NULL, + { .available = banshee_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sgram_config +}; + +const device_t creative_voodoo_banshee_device = { + .name = "Creative 3D Blaster Banshee", + .internal_name = "ctl3d_banshee_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = creative_banshee_init, + .close = banshee_close, + .reset = NULL, + { .available = creative_banshee_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; + +const device_t voodoo_3_2000_device = { + .name = "3dfx Voodoo3 2000", + .internal_name = "voodoo3_2k_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = v3_2000_init, + .close = banshee_close, + .reset = NULL, + { .available = v3_2000_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; + +const device_t voodoo_3_2000_agp_device = { + .name = "3dfx Voodoo3 2000", + .internal_name = "voodoo3_2k_agp", + .flags = DEVICE_AGP, + .local = 0, + .init = v3_2000_agp_init, + .close = banshee_close, + .reset = NULL, + { .available = v3_2000_agp_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; + +const device_t voodoo_3_2000_agp_onboard_8m_device = { + .name = "3dfx Voodoo3 2000 (On-Board 8MB SGRAM)", + .internal_name = "voodoo3_2k_agp_onboard_8m", + .flags = DEVICE_AGP, + .local = 8, + .init = v3_2000_agp_onboard_init, + .close = banshee_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; + +const device_t voodoo_3_3000_device = { + .name = "3dfx Voodoo3 3000", + .internal_name = "voodoo3_3k_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = v3_3000_init, + .close = banshee_close, + .reset = NULL, + { .available = v3_3000_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; + +const device_t voodoo_3_3000_agp_device = { + .name = "3dfx Voodoo3 3000", + .internal_name = "voodoo3_3k_agp", + .flags = DEVICE_AGP, + .local = 0, + .init = v3_3000_agp_init, + .close = banshee_close, + .reset = NULL, + { .available = v3_3000_agp_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; + +const device_t velocity_100_agp_device = { + .name = "3dfx Velocity 100", + .internal_name = "velocity100_agp", + .flags = DEVICE_AGP, + .local = 0, + .init = velocity_100_agp_init, + .close = banshee_close, + .reset = NULL, + { .available = velocity_100_available }, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + banshee_sdram_config +}; diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c new file mode 100644 index 000000000..4062acb3a --- /dev/null +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -0,0 +1,1472 @@ +/*Current issues : + - missing screen->screen scaled blits with format conversion + - missing YUV blits + - missing linestyle + - missing wait for vsync + - missing reversible lines + + Notes : + - 16 bpp runs with tiled framebuffer - to aid 3D? + 8 and 32 bpp use linear +*/ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_banshee_blitter.h> +#include <86box/vid_voodoo_render.h> + +#define COMMAND_CMD_MASK (0xf) +#define COMMAND_CMD_NOP (0 << 0) +#define COMMAND_CMD_SCREEN_TO_SCREEN_BLT (1 << 0) +#define COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT (2 << 0) +#define COMMAND_CMD_HOST_TO_SCREEN_BLT (3 << 0) +#define COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT (4 << 0) +#define COMMAND_CMD_RECTFILL (5 << 0) +#define COMMAND_CMD_LINE (6 << 0) +#define COMMAND_CMD_POLYLINE (7 << 0) +#define COMMAND_CMD_POLYFILL (8 << 0) +#define COMMAND_INITIATE (1 << 8) +#define COMMAND_INC_X_START (1 << 10) +#define COMMAND_INC_Y_START (1 << 11) +#define COMMAND_STIPPLE_LINE (1 << 12) +#define COMMAND_PATTERN_MONO (1 << 13) +#define COMMAND_DX (1 << 14) +#define COMMAND_DY (1 << 15) +#define COMMAND_TRANS_MONO (1 << 16) +#define COMMAND_PATOFF_X_MASK (7 << 17) +#define COMMAND_PATOFF_X_SHIFT (17) +#define COMMAND_PATOFF_Y_MASK (7 << 20) +#define COMMAND_PATOFF_Y_SHIFT (20) +#define COMMAND_CLIP_SEL (1 << 23) + +#define CMDEXTRA_SRC_COLORKEY (1 << 0) +#define CMDEXTRA_DST_COLORKEY (1 << 1) +#define CMDEXTRA_FORCE_PAT_ROW0 (1 << 3) + +#define SRC_FORMAT_STRIDE_MASK (0x1fff) +#define SRC_FORMAT_COL_MASK (0xf << 16) +#define SRC_FORMAT_COL_1_BPP (0 << 16) +#define SRC_FORMAT_COL_8_BPP (1 << 16) +#define SRC_FORMAT_COL_16_BPP (3 << 16) +#define SRC_FORMAT_COL_24_BPP (4 << 16) +#define SRC_FORMAT_COL_32_BPP (5 << 16) +#define SRC_FORMAT_COL_YUYV (8 << 16) +#define SRC_FORMAT_COL_UYVY (9 << 16) +#define SRC_FORMAT_BYTE_SWIZZLE (1 << 20) +#define SRC_FORMAT_WORD_SWIZZLE (1 << 21) +#define SRC_FORMAT_PACKING_MASK (3 << 22) +#define SRC_FORMAT_PACKING_STRIDE (0 << 22) +#define SRC_FORMAT_PACKING_BYTE (1 << 22) +#define SRC_FORMAT_PACKING_WORD (2 << 22) +#define SRC_FORMAT_PACKING_DWORD (3 << 22) + +#define DST_FORMAT_STRIDE_MASK (0x1fff) +#define DST_FORMAT_COL_MASK (0xf << 16) +#define DST_FORMAT_COL_8_BPP (1 << 16) +#define DST_FORMAT_COL_16_BPP (3 << 16) +#define DST_FORMAT_COL_24_BPP (4 << 16) +#define DST_FORMAT_COL_32_BPP (5 << 16) + +#define BRES_ERROR_MASK (0xffff) +#define BRES_ERROR_USE (1 << 31) + +enum +{ + COLORKEY_8, + COLORKEY_16, + COLORKEY_32 +}; + +#ifdef ENABLE_BANSHEEBLT_LOG +int bansheeblt_do_log = ENABLE_BANSHEEBLT_LOG; + +static void +bansheeblt_log(const char *fmt, ...) +{ + va_list ap; + + if (bansheeblt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define banshee_log(fmt, ...) +#endif + +static int colorkey(voodoo_t *voodoo, uint32_t src, int src_notdst, int color_format) +{ + uint32_t min = src_notdst ? voodoo->banshee_blt.srcColorkeyMin : voodoo->banshee_blt.dstColorkeyMin; + uint32_t max = src_notdst ? voodoo->banshee_blt.srcColorkeyMax : voodoo->banshee_blt.dstColorkeyMax; + + if (!(voodoo->banshee_blt.commandExtra & (src_notdst ? CMDEXTRA_SRC_COLORKEY : CMDEXTRA_DST_COLORKEY))) + return 0; + + switch (color_format) + { + case COLORKEY_8: + return ((src & 0xff) >= (min & 0xff)) && ((src & 0xff) <= (max & 0xff)); + + case COLORKEY_16: + { + int r = (src >> 11) & 0x1f, r_min = (min >> 11) & 0x1f, r_max = (max >> 11) & 0x1f; + int g = (src >> 5) & 0x3f, g_min = (min >> 5) & 0x3f, g_max = (max >> 5) & 0x3f; + int b = src & 0x1f, b_min = min & 0x1f, b_max = max & 0x1f; + + return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && + (b >= b_min) && (b <= b_max); + } + + case COLORKEY_32: + { + int r = (src >> 16) & 0xff, r_min = (min >> 16) & 0xff, r_max = (max >> 16) & 0xff; + int g = (src >> 8) & 0xff, g_min = (min >> 8) & 0xff, g_max = (max >> 8) & 0xff; + int b = src & 0xff, b_min = min & 0xff, b_max = max & 0xff; + + return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && + (b >= b_min) && (b <= b_max); + } + + default: + return 0; + } +} + +static uint32_t MIX(voodoo_t *voodoo, uint32_t dest, uint32_t src, uint32_t pattern, int colour_format_src, int colour_format_dest) +{ + int rop_nr = 0; + uint32_t result = 0; + uint32_t rop; + + if (colorkey(voodoo, src, 1, colour_format_src)) + rop_nr |= 2; + if (colorkey(voodoo, dest, 0, colour_format_dest)) + rop_nr |= 1; + + rop = voodoo->banshee_blt.rops[rop_nr]; + + if (rop & 0x01) + result |= (~pattern & ~src & ~dest); + if (rop & 0x02) + result |= (~pattern & ~src & dest); + if (rop & 0x04) + result |= (~pattern & src & ~dest); + if (rop & 0x08) + result |= (~pattern & src & dest); + if (rop & 0x10) + result |= ( pattern & ~src & ~dest); + if (rop & 0x20) + result |= ( pattern & ~src & dest); + if (rop & 0x40) + result |= ( pattern & src & ~dest); + if (rop & 0x80) + result |= ( pattern & src & dest); + + return result; +} + +static uint32_t get_addr(voodoo_t *voodoo, int x, int y, int src_notdst, uint32_t src_stride) +{ + uint32_t stride = src_notdst ? src_stride : voodoo->banshee_blt.dst_stride; + uint32_t base_addr = src_notdst ? voodoo->banshee_blt.srcBaseAddr : voodoo->banshee_blt.dstBaseAddr; + + if (src_notdst ? voodoo->banshee_blt.srcBaseAddr_tiled : voodoo->banshee_blt.dstBaseAddr_tiled) + return (base_addr + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*stride) & voodoo->fb_mask; + else + return (base_addr + x + y*stride) & voodoo->fb_mask; +} + +static void PLOT(voodoo_t *voodoo, int x, int y, int pat_x, int pat_y, uint8_t pattern_mask, uint8_t rop, uint32_t src, int src_colorkey) +{ + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t addr = get_addr(voodoo, x, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_8); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t addr = get_addr(voodoo, x*2, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint16_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_16); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t addr = get_addr(voodoo, x*3, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t addr = get_addr(voodoo, x*4, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + } +} + +static void PLOT_LINE(voodoo_t *voodoo, int x, int y, uint8_t rop, uint32_t pattern, int src_colorkey) +{ + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t addr = get_addr(voodoo, x, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = voodoo->vram[addr]; + + voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_8); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t addr = get_addr(voodoo, x*2, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint16_t *)&voodoo->vram[addr]; + + *(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_16); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t addr = get_addr(voodoo, x*3, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + + *(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t addr = get_addr(voodoo, x*4, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + + *(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + } +} + + +static void update_src_stride(voodoo_t *voodoo) +{ + int bpp; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + bpp = 1; + break; + case SRC_FORMAT_COL_8_BPP: + bpp = 8; + break; + case SRC_FORMAT_COL_16_BPP: + bpp = 16; + break; + case SRC_FORMAT_COL_24_BPP: + bpp = 24; + break; + case SRC_FORMAT_COL_32_BPP: + bpp = 32; + break; + + default: + bpp = 16; + break; + } + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) + { + case SRC_FORMAT_PACKING_STRIDE: + voodoo->banshee_blt.src_stride_src = voodoo->banshee_blt.src_stride; //voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + voodoo->banshee_blt.src_stride_dest = voodoo->banshee_blt.src_stride; //voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + voodoo->banshee_blt.host_data_size_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.host_data_size_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; +// bansheeblt_log("Stride packing %08x %08x bpp=%i dstSizeX=%i\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest, bpp, voodoo->banshee_blt.dstSizeX); + break; + + case SRC_FORMAT_PACKING_BYTE: + voodoo->banshee_blt.src_stride_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.src_stride_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// bansheeblt_log("Byte packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + + case SRC_FORMAT_PACKING_WORD: + voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 15) >> 4) * 2; + voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 15) >> 4) * 2; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// bansheeblt_log("Word packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + + case SRC_FORMAT_PACKING_DWORD: + voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 31) >> 5) * 4; + voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 31) >> 5) * 4; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// bansheeblt_log("Dword packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + } +} + +static void end_command(voodoo_t *voodoo) +{ + /*Update dest coordinates if required*/ + if (voodoo->banshee_blt.command & COMMAND_INC_X_START) + { + voodoo->banshee_blt.dstXY &= ~0x0000ffff; + voodoo->banshee_blt.dstXY |= (voodoo->banshee_blt.dstX & 0xffff); + } + + if (voodoo->banshee_blt.command & COMMAND_INC_Y_START) + { + voodoo->banshee_blt.dstXY &= ~0xffff0000; + voodoo->banshee_blt.dstXY |= (voodoo->banshee_blt.dstY << 16); + } +} + +static void banshee_do_rectfill(voodoo_t *voodoo) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + int dst_y = voodoo->banshee_blt.dstY; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + +// bansheeblt_log("banshee_do_rectfill: size=%i,%i dst=%i,%i\n", voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY); +// bansheeblt_log("clipping: %i,%i -> %i,%i\n", clip->x_min, clip->y_min, clip->x_max, clip->y_max); +// bansheeblt_log("colorFore=%08x\n", voodoo->banshee_blt.colorFore); + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + int dst_x = voodoo->banshee_blt.dstX; + + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + } + dst_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + if (!(voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0)) + pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + + end_command(voodoo); +} + +static void do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int src_x, int src_tiled) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + int dst_y = voodoo->banshee_blt.dstY; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int src_colorkey; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_8_BPP: + src_colorkey = COLORKEY_8; + break; + case SRC_FORMAT_COL_16_BPP: + src_colorkey = COLORKEY_16; + break; + default: + src_colorkey = COLORKEY_32; + break; + } +// bansheeblt_log("do_screen_to_screen_line: srcFormat=%08x dst=%08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.dstFormat); + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == + (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK)) + { + /*No conversion required*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + int src_x_real = (src_x * voodoo->banshee_blt.src_bpp) >> 3; + + if (src_tiled) + src_x_real = (src_x_real & 127) + ((src_x_real >> 7) * 128*32); + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = src_p[src_x_real]; + uint32_t dest = voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*2, dst_y, 0, 0);//dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint16_t *)&src_p[src_x_real]; + uint32_t dest = *(uint16_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*3, dst_y, 0, 0);//dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x_real]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*4, dst_y, 0, 0);//dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x_real]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + } + } + if (use_x_dir) + { + src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + else + { + src_x++; + dst_x++; + pat_x++; + } + } + } + voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + else + { + /*Conversion required*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { +// int src_x = voodoo->banshee_blt.srcX; + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + int src_x_real = (src_x * voodoo->banshee_blt.src_bpp) >> 3; + + if (src_tiled) + src_x_real = (src_x_real & 127) + ((src_x_real >> 7) * 128*32); + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + uint32_t src_data = 0; + int transparent = 0; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + { + uint8_t src_byte = src_p[src_x_real]; + src_data = (src_byte & (0x80 >> (src_x & 7))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack; + if (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) + transparent = !(src_byte & (0x80 >> (src_x & 7))); +// bansheeblt_log(" 1bpp src_byte=%02x src_x=%i src_data=%x transparent=%i\n", src_byte, src_x, src_data, transparent); + break; + } + case SRC_FORMAT_COL_8_BPP: + { + src_data = src_p[src_x_real]; + break; + } + case SRC_FORMAT_COL_16_BPP: + { + uint16_t src_16 = *(uint16_t *)&src_p[src_x_real]; + int r = (src_16 >> 11); + int g = (src_16 >> 5) & 0x3f; + int b = src_16 & 0x1f; + + r = (r << 3) | (r >> 2); + g = (g << 2) | (g >> 4); + b = (b << 3) | (b >> 2); + src_data = (r << 16) | (g << 8) | b; + break; + } + case SRC_FORMAT_COL_24_BPP: + { + src_data = *(uint32_t *)&src_p[src_x_real]; + break; + } + case SRC_FORMAT_COL_32_BPP: + { + src_data = *(uint32_t *)&src_p[src_x_real]; + break; + } + + default: + fatal("banshee_do_screen_to_screen_blt: unknown srcFormat %08x\n", voodoo->banshee_blt.srcFormat); + } + + if ((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_16_BPP && + (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) != SRC_FORMAT_COL_1_BPP) + { + int r = src_data >> 16; + int g = (src_data >> 8) & 0xff; + int b = src_data & 0xff; + + src_data = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); + } + + if (!transparent) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, src_data, src_colorkey); + } + if (use_x_dir) + { + src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + else + { + src_x++; + dst_x++; + pat_x++; + } + } + } + voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } +} + +static void banshee_do_screen_to_screen_blt(voodoo_t *voodoo) +{ +// bansheeblt_log("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); +// return; + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + uint32_t src_addr = get_addr(voodoo, 0, voodoo->banshee_blt.srcY, 1, voodoo->banshee_blt.src_stride_dest); +// if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) +// bansheeblt_log(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); + do_screen_to_screen_line(voodoo, &voodoo->vram[src_addr], 1, voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcBaseAddr_tiled); + } + end_command(voodoo); +} + +static void banshee_do_host_to_screen_blt(voodoo_t *voodoo, int count, uint32_t data) +{ +// if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) +// bansheeblt_log("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) + data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) + data = (data >> 16) | (data << 16); + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) + { + int last_byte; + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + last_byte = ((voodoo->banshee_blt.srcX & 31) + voodoo->banshee_blt.dstSizeX + 7) >> 3; + else + last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_dest; + + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + if (voodoo->banshee_blt.host_data_count >= last_byte) + { +// bansheeblt_log(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], 0, voodoo->banshee_blt.srcX & 7, 0); + else + do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, 0, 0); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; + else + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); + + voodoo->banshee_blt.host_data_count = 0; + } + } + else + { + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_dest) + { + voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_dest; + +// bansheeblt_log(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + do_screen_to_screen_line(voodoo, voodoo->banshee_blt.host_data, 0, 0, 0); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if (voodoo->banshee_blt.host_data_count) + { +// bansheeblt_log(" remaining=%i\n", voodoo->banshee_blt.host_data_count); + *(uint32_t *)&voodoo->banshee_blt.host_data[0] = data >> (4-voodoo->banshee_blt.host_data_count)*8; + } + } + } +} + +static void do_screen_to_screen_stretch_line(voodoo_t *voodoo,uint8_t *src_p, int src_x, int *src_y) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; +// int src_y = voodoo->banshee_blt.srcY; + int dst_y = voodoo->banshee_blt.dstY; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint32_t *colorPattern = voodoo->banshee_blt.colorPattern; + + //int error_y = voodoo->banshee_blt.dstSizeY / 2; + +/* bansheeblt_log("banshee_do_screen_to_screen_stretch_blt:\n"); + bansheeblt_log(" srcXY=%i,%i srcsizeXY=%i,%i\n", voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcY, voodoo->banshee_blt.srcSizeX, voodoo->banshee_blt.srcSizeY); + bansheeblt_log(" dstXY=%i,%i dstsizeXY=%i,%i\n", voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY, voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY);*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { +// int src_x = voodoo->banshee_blt.srcX; + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int error_x = voodoo->banshee_blt.dstSizeX / 2; + +// bansheeblt_log(" Plot dest line %03i : src line %03i\n", dst_y, src_y); + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = src_p[src_x]; + uint32_t dest = voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8); +// bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*2, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint16_t *)&src_p[src_x*2]; + uint32_t dest = *(uint16_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16); +// bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, *(uint16_t *)&voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*3, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*3]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (*(uint32_t *)&voodoo->vram[dst_addr] & 0xff000000); +// bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*4, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*4]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); +// bansheeblt_log("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + } + } + + error_x -= voodoo->banshee_blt.srcSizeX; + while (error_x < 0) + { + error_x += voodoo->banshee_blt.dstSizeX; + src_x++; + } + dst_x++; + pat_x++; + } + } + + voodoo->banshee_blt.bres_error_0 -= voodoo->banshee_blt.srcSizeY; + while (voodoo->banshee_blt.bres_error_0 < 0) + { + voodoo->banshee_blt.bres_error_0 += voodoo->banshee_blt.dstSizeY; + if (src_y) + (*src_y) += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; +// pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; +} + +static void banshee_do_screen_to_screen_stretch_blt(voodoo_t *voodoo) +{ +// bansheeblt_log("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); +// return; + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + uint32_t src_addr = get_addr(voodoo, 0, voodoo->banshee_blt.srcY, 1, voodoo->banshee_blt.src_stride_src);//(voodoo->banshee_blt.srcBaseAddr + voodoo->banshee_blt.srcY*voodoo->banshee_blt.src_stride_src) & voodoo->fb_mask; +// bansheeblt_log("scale_blit %i %08x %08x\n", voodoo->banshee_blt.cur_y, src_addr, voodoo->banshee_blt.command); +// if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) +// bansheeblt_log(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); + do_screen_to_screen_stretch_line(voodoo, &voodoo->vram[src_addr], voodoo->banshee_blt.srcX, &voodoo->banshee_blt.srcY); + } + end_command(voodoo); +} + +static void banshee_do_host_to_screen_stretch_blt(voodoo_t *voodoo, int count, uint32_t data) +{ +// if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) +// bansheeblt_log("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) + data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) + data = (data >> 16) | (data << 16); + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) + { + int last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_src; + + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + if (voodoo->banshee_blt.host_data_count >= last_byte) + { +// bansheeblt_log(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], voodoo->banshee_blt.srcX & 7, NULL); + else + do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, NULL); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; + else + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); + + voodoo->banshee_blt.host_data_count = 0; + } + } + else + { + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_src) + { + voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_src; + +// bansheeblt_log(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + do_screen_to_screen_stretch_line(voodoo, voodoo->banshee_blt.host_data, 0, NULL); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if (voodoo->banshee_blt.host_data_count) + { +// bansheeblt_log(" remaining=%i\n", voodoo->banshee_blt.host_data_count); + *(uint32_t *)&voodoo->banshee_blt.host_data[0] = data >> (4-voodoo->banshee_blt.host_data_count)*8; + } + } + } +} + +static void step_line(voodoo_t *voodoo) +{ + if (voodoo->banshee_blt.line_pix_pos == voodoo->banshee_blt.line_rep_cnt) + { + voodoo->banshee_blt.line_pix_pos = 0; + if (voodoo->banshee_blt.line_bit_pos == voodoo->banshee_blt.line_bit_mask_size) + voodoo->banshee_blt.line_bit_pos = 0; + else + voodoo->banshee_blt.line_bit_pos++; + } + else + voodoo->banshee_blt.line_pix_pos++; +} + + +static void banshee_do_line(voodoo_t *voodoo, int draw_last_pixel) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + uint8_t rop = voodoo->banshee_blt.command >> 24; + int dx = ABS(voodoo->banshee_blt.dstX - voodoo->banshee_blt.srcX); + int dy = ABS(voodoo->banshee_blt.dstY - voodoo->banshee_blt.srcY); + int x_inc = (voodoo->banshee_blt.dstX > voodoo->banshee_blt.srcX) ? 1 : -1; + int y_inc = (voodoo->banshee_blt.dstY > voodoo->banshee_blt.srcY) ? 1 : -1; + int x = voodoo->banshee_blt.srcX; + int y = voodoo->banshee_blt.srcY; + int error; + uint32_t stipple = (voodoo->banshee_blt.command & COMMAND_STIPPLE_LINE) ? + voodoo->banshee_blt.lineStipple : ~0; + + if (dx > dy) /*X major*/ + { + error = dx/2; + while (x != voodoo->banshee_blt.dstX) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + + error -= dy; + if (error < 0) + { + error += dx; + y += y_inc; + } + x += x_inc; + step_line(voodoo); + } + } + else /*Y major*/ + { + error = dy/2; + while (y != voodoo->banshee_blt.dstY) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + + error -= dx; + if (error < 0) + { + error += dy; + x += x_inc; + } + y += y_inc; + step_line(voodoo); + } + } + + if (draw_last_pixel) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + } + + voodoo->banshee_blt.srcXY = (x & 0xffff) | (y << 16); + voodoo->banshee_blt.srcX = x; + voodoo->banshee_blt.srcY = y; +} + +static void banshee_polyfill_start(voodoo_t *voodoo) +{ + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.srcY; + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.dstX; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.dstY; + voodoo->banshee_blt.lx[1] = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.ly[1] = voodoo->banshee_blt.srcY; + voodoo->banshee_blt.rx[1] = voodoo->banshee_blt.dstX; + voodoo->banshee_blt.ry[1] = voodoo->banshee_blt.dstY; + voodoo->banshee_blt.lx_cur = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.rx_cur = voodoo->banshee_blt.dstX; +} + +static void banshee_polyfill_continue(voodoo_t *voodoo, uint32_t data) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int y = MAX(voodoo->banshee_blt.ly[0], voodoo->banshee_blt.ry[0]); + int y_end; + +// bansheeblt_log("Polyfill : data %08x\n", data); + + /*if r1.y>=l1.y, next vertex is left*/ + if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[1] = ((int32_t)(data << 19)) >> 19; + voodoo->banshee_blt.ly[1] = ((int32_t)(data << 3)) >> 19; + voodoo->banshee_blt.dx[0] = ABS(voodoo->banshee_blt.lx[1] - voodoo->banshee_blt.lx[0]); + voodoo->banshee_blt.dy[0] = ABS(voodoo->banshee_blt.ly[1] - voodoo->banshee_blt.ly[0]); + voodoo->banshee_blt.x_inc[0] = (voodoo->banshee_blt.lx[1] > voodoo->banshee_blt.lx[0]) ? 1 : -1; + voodoo->banshee_blt.error[0] = voodoo->banshee_blt.dy[0] / 2; + } + else + { + voodoo->banshee_blt.rx[1] = ((int32_t)(data << 19)) >> 19; + voodoo->banshee_blt.ry[1] = ((int32_t)(data << 3)) >> 19; + voodoo->banshee_blt.dx[1] = ABS(voodoo->banshee_blt.rx[1] - voodoo->banshee_blt.rx[0]); + voodoo->banshee_blt.dy[1] = ABS(voodoo->banshee_blt.ry[1] - voodoo->banshee_blt.ry[0]); + voodoo->banshee_blt.x_inc[1] = (voodoo->banshee_blt.rx[1] > voodoo->banshee_blt.rx[0]) ? 1 : -1; + voodoo->banshee_blt.error[1] = voodoo->banshee_blt.dy[1] / 2; + } + +/* bansheeblt_log(" verts now : %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[0], voodoo->banshee_blt.ly[0], voodoo->banshee_blt.rx[0], voodoo->banshee_blt.ry[0]); + bansheeblt_log(" %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[1], voodoo->banshee_blt.ly[1], voodoo->banshee_blt.rx[1], voodoo->banshee_blt.ry[1]); + bansheeblt_log(" left dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[0],voodoo->banshee_blt.dy[0],voodoo->banshee_blt.x_inc[0],voodoo->banshee_blt.error[0]); + bansheeblt_log(" right dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[1],voodoo->banshee_blt.dy[1],voodoo->banshee_blt.x_inc[1],voodoo->banshee_blt.error[1]);*/ + y_end = MIN(voodoo->banshee_blt.ly[1], voodoo->banshee_blt.ry[1]); +// bansheeblt_log("Polyfill : draw spans from %i-%i\n", y, y_end); + for (; y < y_end; y++) + { +// bansheeblt_log(" %i: %i %i\n", y, voodoo->banshee_blt.lx_cur, voodoo->banshee_blt.rx_cur); + /*Draw span from lx_cur to rx_cur*/ + if (y >= clip->y_min && y < clip->y_max) + { + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + y); + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int x; + + for (x = voodoo->banshee_blt.lx_cur; x < voodoo->banshee_blt.rx_cur; x++) + { + int pat_x = voodoo->banshee_blt.patoff_x + x; + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + } + } + + voodoo->banshee_blt.error[0] -= voodoo->banshee_blt.dx[0]; + while (voodoo->banshee_blt.error[0] < 0) + { + voodoo->banshee_blt.error[0] += voodoo->banshee_blt.dy[0]; + voodoo->banshee_blt.lx_cur += voodoo->banshee_blt.x_inc[0]; + } + voodoo->banshee_blt.error[1] -= voodoo->banshee_blt.dx[1]; + while (voodoo->banshee_blt.error[1] < 0) + { + voodoo->banshee_blt.error[1] += voodoo->banshee_blt.dy[1]; + voodoo->banshee_blt.rx_cur += voodoo->banshee_blt.x_inc[1]; + } + } + + if (voodoo->banshee_blt.ry[1] == voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; + } + else if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; + } + else + { + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; + } +} + +static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data) +{ + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { + case COMMAND_CMD_NOP: + break; + + case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: + banshee_do_screen_to_screen_blt(voodoo); + break; + + case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: + banshee_do_screen_to_screen_stretch_blt(voodoo); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + banshee_do_host_to_screen_blt(voodoo, count, data); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + banshee_do_host_to_screen_stretch_blt(voodoo, count, data); + break; + + case COMMAND_CMD_RECTFILL: + banshee_do_rectfill(voodoo); + break; + + case COMMAND_CMD_LINE: + banshee_do_line(voodoo, 1); + break; + + case COMMAND_CMD_POLYLINE: + banshee_do_line(voodoo, 0); + break; + + default: + fatal("banshee_do_2d_blit: unknown command=%08x\n", voodoo->banshee_blt.command); + } +} + +void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) +{ +// /*if ((addr & 0x1fc) != 0x80) */bansheeblt_log("2D reg write %03x %08x\n", addr & 0x1fc, val); + switch (addr & 0x1fc) + { + case 0x08: + voodoo->banshee_blt.clip0Min = val; + voodoo->banshee_blt.clip[0].x_min = val & 0xfff; + voodoo->banshee_blt.clip[0].y_min = (val >> 16) & 0xfff; + break; + case 0x0c: + voodoo->banshee_blt.clip0Max = val; + voodoo->banshee_blt.clip[0].x_max = val & 0xfff; + voodoo->banshee_blt.clip[0].y_max = (val >> 16) & 0xfff; + break; + case 0x10: + voodoo->banshee_blt.dstBaseAddr = val & 0xffffff; + voodoo->banshee_blt.dstBaseAddr_tiled = val & 0x80000000; + if (voodoo->banshee_blt.dstBaseAddr_tiled) + voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; +// bansheeblt_log("dstBaseAddr=%08x\n", val); + break; + case 0x14: + voodoo->banshee_blt.dstFormat = val; + if (voodoo->banshee_blt.dstBaseAddr_tiled) + voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; +// bansheeblt_log("dstFormat=%08x\n", val); + break; + + case 0x18: + voodoo->banshee_blt.srcColorkeyMin = val & 0xffffff; + break; + case 0x1c: + voodoo->banshee_blt.srcColorkeyMax = val & 0xffffff; + break; + case 0x20: + voodoo->banshee_blt.dstColorkeyMin = val & 0xffffff; + break; + case 0x24: + voodoo->banshee_blt.dstColorkeyMax = val & 0xffffff; + break; + + case 0x28: + voodoo->banshee_blt.bresError0 = val; + voodoo->banshee_blt.bres_error_0 = val & 0xffff; + break; + case 0x2c: + voodoo->banshee_blt.bresError1 = val; + voodoo->banshee_blt.bres_error_1 = val & 0xffff; + break; + + case 0x30: + voodoo->banshee_blt.rop = val; + voodoo->banshee_blt.rops[1] = val & 0xff; + voodoo->banshee_blt.rops[2] = (val >> 8) & 0xff; + voodoo->banshee_blt.rops[3] = (val >> 16) & 0xff; +// bansheeblt_log("rop=%08x\n", val); + break; + case 0x34: + voodoo->banshee_blt.srcBaseAddr = val & 0xffffff; + voodoo->banshee_blt.srcBaseAddr_tiled = val & 0x80000000; + if (voodoo->banshee_blt.srcBaseAddr_tiled) + voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + update_src_stride(voodoo); +// bansheeblt_log("srcBaseAddr=%08x\n", val); + break; + case 0x38: + voodoo->banshee_blt.commandExtra = val; +// bansheeblt_log("commandExtra=%08x\n", val); + break; + case 0x3c: + voodoo->banshee_blt.lineStipple = val; + break; + case 0x40: + voodoo->banshee_blt.lineStyle = val; + voodoo->banshee_blt.line_rep_cnt = val & 0xff; + voodoo->banshee_blt.line_bit_mask_size = (val >> 8) & 0x1f; + voodoo->banshee_blt.line_pix_pos = (val >> 16) & 0xff; + voodoo->banshee_blt.line_bit_pos = (val >> 24) & 0x1f; + break; + case 0x44: + voodoo->banshee_blt.colorPattern[0] = val; +// bansheeblt_log("colorPattern0=%08x\n", val); + voodoo->banshee_blt.colorPattern24[0] = val & 0xffffff; + voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xffff00) | (val >> 24); + voodoo->banshee_blt.colorPattern16[0] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[1] = (val >> 16) & 0xffff; + voodoo->banshee_blt.colorPattern8[0] = val & 0xff; + voodoo->banshee_blt.colorPattern8[1] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[2] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[3] = (val >> 24) & 0xff; + break; + case 0x48: + voodoo->banshee_blt.colorPattern[1] = val; +// bansheeblt_log("colorPattern1=%08x\n", val); + voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xff) | ((val & 0xffff) << 8); + voodoo->banshee_blt.colorPattern24[2] = (voodoo->banshee_blt.colorPattern24[2] & 0xff0000) | (val >> 16); + voodoo->banshee_blt.colorPattern16[2] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[3] = (val >> 16) & 0xffff; + voodoo->banshee_blt.colorPattern8[4] = val & 0xff; + voodoo->banshee_blt.colorPattern8[5] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[6] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[7] = (val >> 24) & 0xff; + break; + case 0x4c: + voodoo->banshee_blt.clip1Min = val; + voodoo->banshee_blt.clip[1].x_min = val & 0xfff; + voodoo->banshee_blt.clip[1].y_min = (val >> 16) & 0xfff; + break; + case 0x50: + voodoo->banshee_blt.clip1Max = val; + voodoo->banshee_blt.clip[1].x_max = val & 0xfff; + voodoo->banshee_blt.clip[1].y_max = (val >> 16) & 0xfff; + break; + case 0x54: + voodoo->banshee_blt.srcFormat = val; + if (voodoo->banshee_blt.srcBaseAddr_tiled) + voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + update_src_stride(voodoo); + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + voodoo->banshee_blt.src_bpp = 1; + break; + case SRC_FORMAT_COL_8_BPP: + voodoo->banshee_blt.src_bpp = 8; + break; + case SRC_FORMAT_COL_24_BPP: + voodoo->banshee_blt.src_bpp = 24; + break; + case SRC_FORMAT_COL_32_BPP: + voodoo->banshee_blt.src_bpp = 32; + break; + case SRC_FORMAT_COL_16_BPP: default: + voodoo->banshee_blt.src_bpp = 16; + break; + } +// bansheeblt_log("srcFormat=%08x\n", val); + break; + case 0x58: + voodoo->banshee_blt.srcSize = val; + voodoo->banshee_blt.srcSizeX = voodoo->banshee_blt.srcSize & 0x1fff; + voodoo->banshee_blt.srcSizeY = (voodoo->banshee_blt.srcSize >> 16) & 0x1fff; + update_src_stride(voodoo); +// bansheeblt_log("srcSize=%08x\n", val); + break; + case 0x5c: + voodoo->banshee_blt.srcXY = val; + voodoo->banshee_blt.srcX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(val << 3)) >> 19; + update_src_stride(voodoo); +// bansheeblt_log("srcXY=%08x\n", val); + break; + case 0x60: + voodoo->banshee_blt.colorBack = val; + break; + case 0x64: + voodoo->banshee_blt.colorFore = val; + break; + case 0x68: + voodoo->banshee_blt.dstSize = val; + voodoo->banshee_blt.dstSizeX = voodoo->banshee_blt.dstSize & 0x1fff; + voodoo->banshee_blt.dstSizeY = (voodoo->banshee_blt.dstSize >> 16) & 0x1fff; + update_src_stride(voodoo); +// bansheeblt_log("dstSize=%08x\n", val); + break; + case 0x6c: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; +// bansheeblt_log("dstXY=%08x\n", val); + break; + case 0x70: + voodoo_wait_for_render_thread_idle(voodoo); + voodoo->banshee_blt.command = val; + voodoo->banshee_blt.rops[0] = val >> 24; +// bansheeblt_log("command=%x %08x\n", voodoo->banshee_blt.command & COMMAND_CMD_MASK, val); + voodoo->banshee_blt.patoff_x = (val & COMMAND_PATOFF_X_MASK) >> COMMAND_PATOFF_X_SHIFT; + voodoo->banshee_blt.patoff_y = (val & COMMAND_PATOFF_Y_MASK) >> COMMAND_PATOFF_Y_SHIFT; + voodoo->banshee_blt.cur_x = 0; + voodoo->banshee_blt.cur_y = 0; + voodoo->banshee_blt.dstX = ((int32_t)(voodoo->banshee_blt.dstXY << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(voodoo->banshee_blt.dstXY << 3)) >> 19; + voodoo->banshee_blt.srcX = ((int32_t)(voodoo->banshee_blt.srcXY << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(voodoo->banshee_blt.srcXY << 3)) >> 19; + voodoo->banshee_blt.old_srcX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.host_data_remainder = 0; + voodoo->banshee_blt.host_data_count = 0; + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { +/* case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: + if (voodoo->banshee_blt.bresError0 & BRES_ERROR_USE) + voodoo->banshee_blt.bres_error_0 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError0 & BRES_ERROR_MASK); + else + voodoo->banshee_blt.bres_error_0 = voodoo->banshee_blt.dstSizeY / 2; + if (voodoo->banshee_blt.bresError1 & BRES_ERROR_USE) + voodoo->banshee_blt.bres_error_1 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError1 & BRES_ERROR_MASK); + else + voodoo->banshee_blt.bres_error_1 = voodoo->banshee_blt.dstSizeX / 2; + + if (val & COMMAND_INITIATE) + banshee_do_2d_blit(voodoo, -1, 0); + break;*/ + + case COMMAND_CMD_POLYFILL: + if (val & COMMAND_INITIATE) + { + voodoo->banshee_blt.dstXY = voodoo->banshee_blt.srcXY; + voodoo->banshee_blt.dstX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.dstY = voodoo->banshee_blt.srcY; + } + banshee_polyfill_start(voodoo); + break; + + default: + if (val & COMMAND_INITIATE) + { + banshee_do_2d_blit(voodoo, -1, 0); + // fatal("Initiate command!\n"); + } + break; + } + break; + + case 0x80: case 0x84: case 0x88: case 0x8c: + case 0x90: case 0x94: case 0x98: case 0x9c: + case 0xa0: case 0xa4: case 0xa8: case 0xac: + case 0xb0: case 0xb4: case 0xb8: case 0xbc: + case 0xc0: case 0xc4: case 0xc8: case 0xcc: + case 0xd0: case 0xd4: case 0xd8: case 0xdc: + case 0xe0: case 0xe4: case 0xe8: case 0xec: + case 0xf0: case 0xf4: case 0xf8: case 0xfc: +// bansheeblt_log("launch %08x %08x %08x %08x\n", voodoo->banshee_blt.command, voodoo->banshee_blt.commandExtra, voodoo->banshee_blt.srcColorkeyMin, voodoo->banshee_blt.srcColorkeyMax); + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { + case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: + voodoo->banshee_blt.srcXY = val; + voodoo->banshee_blt.srcX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(val << 3)) >> 19; + banshee_do_screen_to_screen_blt(voodoo); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + banshee_do_2d_blit(voodoo, 32, val); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + banshee_do_2d_blit(voodoo, 32, val); + break; + + case COMMAND_CMD_RECTFILL: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_rectfill(voodoo); + break; + + case COMMAND_CMD_LINE: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_line(voodoo, 1); + break; + + case COMMAND_CMD_POLYLINE: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_line(voodoo, 0); + break; + + case COMMAND_CMD_POLYFILL: + banshee_polyfill_continue(voodoo, val); + break; + + default: + fatal("launch area write, command=%08x\n", voodoo->banshee_blt.command); + } + break; + + case 0x100: case 0x104: case 0x108: case 0x10c: + case 0x110: case 0x114: case 0x118: case 0x11c: + case 0x120: case 0x124: case 0x128: case 0x12c: + case 0x130: case 0x134: case 0x138: case 0x13c: + case 0x140: case 0x144: case 0x148: case 0x14c: + case 0x150: case 0x154: case 0x158: case 0x15c: + case 0x160: case 0x164: case 0x168: case 0x16c: + case 0x170: case 0x174: case 0x178: case 0x17c: + case 0x180: case 0x184: case 0x188: case 0x18c: + case 0x190: case 0x194: case 0x198: case 0x19c: + case 0x1a0: case 0x1a4: case 0x1a8: case 0x1ac: + case 0x1b0: case 0x1b4: case 0x1b8: case 0x1bc: + case 0x1c0: case 0x1c4: case 0x1c8: case 0x1cc: + case 0x1d0: case 0x1d4: case 0x1d8: case 0x1dc: + case 0x1e0: case 0x1e4: case 0x1e8: case 0x1ec: + case 0x1f0: case 0x1f4: case 0x1f8: case 0x1fc: + voodoo->banshee_blt.colorPattern[(addr >> 2) & 63] = val; + if ((addr & 0x1fc) < 0x1c0) + { + int base_addr = (addr & 0xfc) / 0xc; + uintptr_t src_p = (uintptr_t)&voodoo->banshee_blt.colorPattern[base_addr * 3]; + int col24 = base_addr * 4; + + voodoo->banshee_blt.colorPattern24[col24] = *(uint32_t *)src_p & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 1] = *(uint32_t *)(src_p + 3) & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 2] = *(uint32_t *)(src_p + 6) & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 3] = *(uint32_t *)(src_p + 9) & 0xffffff; + } + if ((addr & 0x1fc) < 0x180) + { + voodoo->banshee_blt.colorPattern16[(addr >> 1) & 62] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[((addr >> 1) & 62) + 1] = (val >> 16) & 0xffff; + } + if ((addr & 0x1fc) < 0x140) + { + voodoo->banshee_blt.colorPattern8[addr & 60] = val & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 1] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 2] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 3] = (val >> 24) & 0xff; + } +// bansheeblt_log("colorPattern%02x=%08x\n", (addr >> 2) & 63, val); + break; + + default: + fatal("Unknown 2D reg write %03x %08x\n", addr & 0x1fc, val); + } +} diff --git a/src/video/vid_voodoo_blitter.c b/src/video/vid_voodoo_blitter.c new file mode 100644 index 000000000..94fb9dfa1 --- /dev/null +++ b/src/video/vid_voodoo_blitter.c @@ -0,0 +1,557 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_blitter.h> +#include <86box/vid_voodoo_dither.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> + + +enum +{ + BLIT_COMMAND_SCREEN_TO_SCREEN = 0, + BLIT_COMMAND_CPU_TO_SCREEN = 1, + BLIT_COMMAND_RECT_FILL = 2, + BLIT_COMMAND_SGRAM_FILL = 3 +}; + +enum +{ + BLIT_SRC_1BPP = (0 << 3), + BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3), + BLIT_SRC_16BPP = (2 << 3), + BLIT_SRC_24BPP = (3 << 3), + BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3), + BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3) +}; + +enum +{ + BLIT_SRC_RGB_ARGB = (0 << 6), + BLIT_SRC_RGB_ABGR = (1 << 6), + BLIT_SRC_RGB_RGBA = (2 << 6), + BLIT_SRC_RGB_BGRA = (3 << 6) +}; + +enum +{ + BLIT_COMMAND_MASK = 7, + BLIT_SRC_FORMAT = (7 << 3), + BLIT_SRC_RGB_FORMAT = (3 << 6), + BLIT_SRC_CHROMA = (1 << 10), + BLIT_DST_CHROMA = (1 << 12), + BLIT_CLIPPING_ENABLED = (1 << 16) +}; + +enum +{ + BLIT_ROP_DST_PASS = (1 << 0), + BLIT_ROP_SRC_PASS = (1 << 1) +}; + + +#ifdef ENABLE_VOODOOBLT_LOG +int voodooblt_do_log = ENABLE_VOODOOBLT_LOG; + + +static void +voodooblt_log(const char *fmt, ...) +{ + va_list ap; + + if (voodooblt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodooblt_log(fmt, ...) +#endif + + +#define MIX(src_dat, dst_dat, rop) \ + switch (rop) \ + { \ + case 0x0: dst_dat = 0; break; \ + case 0x1: dst_dat = ~(src_dat | dst_dat); break; \ + case 0x2: dst_dat = ~src_dat & dst_dat; break; \ + case 0x3: dst_dat = ~src_dat; break; \ + case 0x4: dst_dat = src_dat & ~dst_dat; break; \ + case 0x5: dst_dat = ~dst_dat; break; \ + case 0x6: dst_dat = src_dat ^ dst_dat; break; \ + case 0x7: dst_dat = ~(src_dat & dst_dat); break; \ + case 0x8: dst_dat = src_dat & dst_dat; break; \ + case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \ + case 0xa: dst_dat = dst_dat; break; \ + case 0xb: dst_dat = ~src_dat | dst_dat; break; \ + case 0xc: dst_dat = src_dat; break; \ + case 0xd: dst_dat = src_dat | ~dst_dat; break; \ + case 0xe: dst_dat = src_dat | dst_dat; break; \ + case 0xf: dst_dat = 0xffff; break; \ + } + +void voodoo_v2_blit_start(voodoo_t *voodoo) +{ + uint64_t dat64; + int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); + int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; + int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; + int dst_x; + int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; + int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); + int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8); + uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + int x, y; + +/* voodooblt_log("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n", + voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/ + + voodoo_wait_for_render_thread_idle(voodoo); + + switch (voodoo->bltCommand & BLIT_COMMAND_MASK) + { + case BLIT_COMMAND_SCREEN_TO_SCREEN: + for (y = 0; y <= size_y; y++) + { + uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride]; + uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX; + + for (x = 0; x <= size_x; x++) + { + uint16_t src_dat = src[src_x]; + uint16_t dst_dat = dst[dst_x]; + int rop = 0; + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_blit; + } + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + int r = (src_dat >> 11); + int g = (src_dat >> 5) & 0x3f; + int b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + int r = (dst_dat >> 11); + int g = (dst_dat >> 5) & 0x3f; + int b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[dst_x] = dst_dat; +skip_pixel_blit: + src_x += x_dir; + dst_x += x_dir; + } + + src_y += y_dir; + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_CPU_TO_SCREEN: + voodoo->blt.dst_x = voodoo->bltDstX; + voodoo->blt.dst_y = voodoo->bltDstY; + voodoo->blt.cur_x = 0; + voodoo->blt.size_x = size_x; + voodoo->blt.size_y = size_y; + voodoo->blt.x_dir = x_dir; + voodoo->blt.y_dir = y_dir; + voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + break; + + case BLIT_COMMAND_RECT_FILL: + for (y = 0; y <= size_y; y++) + { + uint16_t *dst; + int dst_x = voodoo->bltDstX; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_line_fill; + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride]; + } + else + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + + for (x = 0; x <= size_x; x++) + { + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_fill; + } + + dst[dst_x] = voodoo->bltColorFg; +skip_pixel_fill: + dst_x += x_dir; + } +skip_line_fill: + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_SGRAM_FILL: + /*32x32 tiles - 2kb*/ + dst_y = voodoo->bltDstY & 0x3ff; + size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb + size_y = voodoo->bltSizeY & 0x3ff; + + dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) | + ((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48); + + for (y = 0; y <= size_y; y++) + { + uint64_t *dst; + + /*This may be wrong*/ + if (!y) + { + dst_x = voodoo->bltDstX & 0x1ff; + size_x = 511 - dst_x; + } + else if (y < size_y) + { + dst_x = 0; + size_x = 511; + } + else + { + dst_x = 0; + size_x = voodoo->bltSizeX & 0x1ff; + } + + dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; + + for (x = 0; x <= size_x; x++) + dst[x] = dat64; + + dst_y++; + } + break; + + default: + fatal("bad blit command %08x\n", voodoo->bltCommand); + } +} + +void voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data) +{ + int src_bits = 32; + uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + uint32_t addr; + uint16_t *dst; + + if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) + return; + + if (SLI_ENABLED) + { + addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + else + { + addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + + if (addr >= voodoo->front_offset && voodoo->row_width) + { + int y = (addr - voodoo->front_offset) / voodoo->row_width; + if (y < voodoo->v_disp) + voodoo->dirty_line[y] = 2; + } + + while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) + { + int r = 0, g = 0, b = 0; + uint16_t src_dat = 0, dst_dat; + int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); + int rop = 0; + + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED: + src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg; + data >>= 1; + src_bits--; + break; + case BLIT_SRC_16BPP: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA: + src_dat = data & 0xffff; + break; + case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA: + src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11); + break; + } + data >>= 16; + src_bits -= 16; + break; + case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: + r = (data >> 16) & 0xff; + g = (data >> 8) & 0xff; + b = data & 0xff; + break; + case BLIT_SRC_RGB_ABGR: + r = data & 0xff; + g = (data >> 8) & 0xff; + b = (data >> 16) & 0xff; + break; + case BLIT_SRC_RGB_RGBA: + r = (data >> 24) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 8) & 0xff; + break; + case BLIT_SRC_RGB_BGRA: + r = (data >> 8) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 24) & 0xff; + break; + } + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_24BPP: + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_2X2: + r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1]; + g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1]; + b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_4X4: + r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3]; + g = dither_g[g][voodoo->blt.dst_y & 3][x & 3]; + b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + } + src_bits = 0; + break; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_pixel; + } + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (x < voodoo->bltClipLeft || x >= voodoo->bltClipRight || + voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y >= voodoo->bltClipHighY) + goto skip_pixel; + } + + dst_dat = dst[x]; + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + r = (src_dat >> 11); + g = (src_dat >> 5) & 0x3f; + b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + r = (dst_dat >> 11); + g = (dst_dat >> 5) & 0x3f; + b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[x] = dst_dat; + +skip_pixel: + voodoo->blt.cur_x++; + } + + if (voodoo->blt.cur_x > voodoo->blt.size_x) + { + voodoo->blt.size_y--; + if (voodoo->blt.size_y >= 0) + { + voodoo->blt.cur_x = 0; + voodoo->blt.dst_y += voodoo->blt.y_dir; + } + } +} + + +void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) +{ + int y; + int low_y, high_y; + + if (params->fbzMode & (1 << 17)) + { + int y_origin = (voodoo->type >= VOODOO_BANSHEE) ? (voodoo->y_origin_swap+1) : voodoo->v_disp; + + high_y = y_origin - params->clipLowY; + low_y = y_origin - params->clipHighY; + } + else + { + low_y = params->clipLowY; + high_y = params->clipHighY; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + { + int r, g, b; + uint16_t col; + + r = ((params->color1 >> 16) >> 3) & 0x1f; + g = ((params->color1 >> 8) >> 2) & 0x3f; + b = (params->color1 >> 3) & 0x1f; + col = b | (g << 5) | (r << 11); + + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + if (voodoo->col_tiled) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 5) * voodoo->row_width + (y & 31) * 128) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + { + int x2 = (x & 63) | ((x >> 6) * 128*32/2); + cbuf[x2] = col; + } + } + else + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + } + } + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + if (voodoo->aux_tiled) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 5) * voodoo->aux_row_width + (y & 31) * 128) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + { + int x2 = (x & 63) | ((x >> 6) * 128*32/2); + abuf[x2] = params->zaColor & 0xffff; + } + } + else + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y * voodoo->aux_row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + } + } +} diff --git a/src/video/vid_voodoo_display.c b/src/video/vid_voodoo_display.c new file mode 100644 index 000000000..8e4e952d2 --- /dev/null +++ b/src/video/vid_voodoo_display.c @@ -0,0 +1,679 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_display.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> + + +#ifdef ENABLE_VOODOODISP_LOG +int voodoodisp_do_log = ENABLE_VOODOODISP_LOG; + + +static void +voodoodisp_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoodisp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoodisp_log(fmt, ...) +#endif + +void voodoo_update_ncc(voodoo_t *voodoo, int tmu) +{ + int tbl; + + for (tbl = 0; tbl < 2; tbl++) + { + int col; + + for (col = 0; col < 256; col++) + { + int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; + int i_r, i_g, i_b; + int q_r, q_g, q_b; + + y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; + + i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff; + if (i_r & 0x100) + i_r |= 0xfffffe00; + i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff; + if (i_g & 0x100) + i_g |= 0xfffffe00; + i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff; + if (i_b & 0x100) + i_b |= 0xfffffe00; + + q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff; + if (q_r & 0x100) + q_r |= 0xfffffe00; + q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff; + if (q_g & 0x100) + q_g |= 0xfffffe00; + q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff; + if (q_b & 0x100) + q_b |= 0xfffffe00; + + voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r); + voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g); + voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b); + voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff; + } + } +} + +void voodoo_pixelclock_update(voodoo_t *voodoo) +{ + int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; + int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; + int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); + float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + double clock_const; + int line_length; + + if ((voodoo->dac_data[6] & 0xf0) == 0x20 || + (voodoo->dac_data[6] & 0xf0) == 0x60 || + (voodoo->dac_data[6] & 0xf0) == 0x70) + t /= 2.0f; + + line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff); + +// voodoodisp_log("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length); + + voodoo->pixel_clock = t; + + clock_const = cpuclock / t; + voodoo->line_time = (uint64_t)((double)line_length * clock_const * (double)(1ull << 32)); +} + +static void voodoo_calc_clutData(voodoo_t *voodoo) +{ + int c; + + for (c = 0; c < 256; c++) + { + voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3; + voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3; + voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3; + } + + for (c = 0; c < 65536; c++) + { + int r = (c >> 8) & 0xf8; + int g = (c >> 3) & 0xfc; + int b = (c << 3) & 0xf8; +// r |= (r >> 5); +// g |= (g >> 6); +// b |= (b >> 5); + + voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b; + } +} + + + +#define FILTDIV 256 + +static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ + +void voodoo_generate_filter_v1(voodoo_t *voodoo) +{ + int g, h; + float difference, diffg, diffb; + float thiscol, thiscolg, thiscolb, lined; + float fcr, fcg, fcb; + + fcr = FILTCAP * 5; + fcg = FILTCAPG * 6; + fcb = FILTCAPB * 5; + + for (g=0;g FILTCAP) + difference = FILTCAP; + if (difference < -FILTCAP) + difference = -FILTCAP; + + if (diffg > FILTCAPG) + diffg = FILTCAPG; + if (diffg < -FILTCAPG) + diffg = -FILTCAPG; + + if (diffb > FILTCAPB) + diffb = FILTCAPB; + if (diffb < -FILTCAPB) + diffb = -FILTCAPB; + + // hack - to make it not bleed onto black + //if (g == 0){ + //difference = diffg = diffb = 0; + //} + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ + if ((diffb < fcb) || (-diffb > -fcb)) + thiscolb = g + (diffb / 2); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > FILTDIV-1) + thiscol = FILTDIV-1; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > FILTDIV-1) + thiscolg = FILTDIV-1; + + if (thiscolb < 0) + thiscolb = 0; + if (thiscolb > FILTDIV-1) + thiscolb = FILTDIV-1; + + voodoo->thefilter[g][h] = thiscol; + voodoo->thefilterg[g][h] = thiscolg; + voodoo->thefilterb[g][h] = thiscolb; + } + + lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } +} + +void voodoo_generate_filter_v2(voodoo_t *voodoo) +{ + int g, h; + float difference; + float thiscol, thiscolg, thiscolb; + float clr, clg, clb = 0; + float fcr, fcg, fcb = 0; + + // pre-clamping + + fcr = FILTCAP; + fcg = FILTCAPG; + fcb = FILTCAPB; + + if (fcr > 32) fcr = 32; + if (fcg > 32) fcg = 32; + if (fcb > 32) fcb = 32; + + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = (float)((g + g + g + g + h) / 5); + avgdiff = avg - (float)((g + h + h + h + h) / 5); + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = thiscolb = g; + + // try lighten + if (h > g) + { + clr = clg = clb = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + if (clb>fcb) clb=fcb; + + + thiscol = g + clr; + thiscolg = g + clg; + thiscolb = g + clb; + + if (thiscol>g+FILTCAP) + thiscol=g+FILTCAP; + if (thiscolg>g+FILTCAPG) + thiscolg=g+FILTCAPG; + if (thiscolb>g+FILTCAPB) + thiscolb=g+FILTCAPB; + + + if (thiscol>g+avgdiff) + thiscol=g+avgdiff; + if (thiscolg>g+avgdiff) + thiscolg=g+avgdiff; + if (thiscolb>g+avgdiff) + thiscolb=g+avgdiff; + + } + + if (difference > FILTCAP) + thiscol = g; + if (difference > FILTCAPG) + thiscolg = g; + if (difference > FILTCAPB) + thiscolb = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + if (thiscolb < 0) thiscolb = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + if (thiscolb > 255) thiscolb = 255; + + // add to the table + voodoo->thefilter[g][h] = (thiscol); + voodoo->thefilterg[g][h] = (thiscolg); + voodoo->thefilterb[g][h] = (thiscolb); + + // debug the ones that don't give us much of a difference + //if (difference < FILTCAP) + //voodoodisp_log("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); + } + + } +} + +void voodoo_threshold_check(voodoo_t *voodoo) +{ + int r, g, b; + + if (!voodoo->scrfilterEnabled) + return; /* considered disabled; don't check and generate */ + + /* Check for changes, to generate anew table */ + if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld) + { + r = (voodoo->scrfilterThreshold >> 16) & 0xFF; + g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF; + b = voodoo->scrfilterThreshold & 0xFF; + + FILTCAP = r; + FILTCAPG = g; + FILTCAPB = b; + + voodoodisp_log("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); + + voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; + + if (voodoo->type == VOODOO_2) + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); + + if (voodoo->type >= VOODOO_BANSHEE) + voodoo_generate_vb_filters(voodoo, FILTCAP, FILTCAPG); + } +} + +static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for avoiding feedback streaks + uint8_t *fil3 = malloc((voodoo->h_disp) * 3); + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + + // Copy to our scratchpads + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + } + + + /* lines */ + + if (line & 1) + { + for (x=0; xpurpleline[fil[x*3]][0]; + fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; + } + } + + + /* filtering time */ + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; + } + + free(fil3); +} + + +static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for blending filter + uint8_t *fil3 = malloc((voodoo->h_disp) * 3); + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + } + + /* filtering time */ + + for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; + fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; + fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; + + fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; + fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; + fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; + fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + } + + // unroll for edge cases + + fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; + fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; + fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + free(fil3); +} + +void voodoo_callback(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line < voodoo->v_disp) + { + voodoo_t *draw_voodoo; + int draw_line; + + if (SLI_ENABLED) + { + if (voodoo == voodoo->set->voodoos[1]) + goto skip_draw; + + if (((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) ? 1 : 0) == (voodoo->line & 1)) + draw_voodoo = voodoo; + else + draw_voodoo = voodoo->set->voodoos[1]; + draw_line = voodoo->line >> 1; + } + else + { + if (!(voodoo->fbiInit0 & 1)) + goto skip_draw; + draw_voodoo = voodoo; + draw_line = voodoo->line; + } + + if (draw_voodoo->dirty_line[draw_line]) + { + uint32_t *p = &buffer32->line[voodoo->line + 8][8]; + uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width]; + int x; + + draw_voodoo->dirty_line[draw_line] = 0; + + if (voodoo->line < voodoo->dirty_line_low) + { + voodoo->dirty_line_low = voodoo->line; + video_wait_for_buffer(); + } + if (voodoo->line > voodoo->dirty_line_high) + voodoo->dirty_line_high = voodoo->line; + + /* Draw left overscan. */ + for (x = 0; x < 8; x++) + buffer32->line[voodoo->line + 8][x] = 0x00000000; + + if (voodoo->scrfilter && voodoo->scrfilterEnabled) + { + uint8_t *fil = malloc((voodoo->h_disp) * 3); /* interleaved 24-bit RGB */ + + if (voodoo->type == VOODOO_2) + voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); + else + voodoo_filterline_v1(voodoo, fil, voodoo->h_disp, src, voodoo->line); + + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16); + } + + free(fil); + } + else + { + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = draw_voodoo->video_16to32[src[x]]; + } + } + + /* Draw right overscan. */ + for (x = 0; x < 8; x++) + buffer32->line[voodoo->line + 8][voodoo->h_disp + x + 8] = 0x00000000; + } + } + } +skip_draw: + if (voodoo->line == voodoo->v_disp) + { +// voodoodisp_log("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending); + voodoo->retrace_count++; + if (SLI_ENABLED && (voodoo->fbiInit2 & FBIINIT2_SWAP_ALGORITHM_MASK) == FBIINIT2_SWAP_ALGORITHM_SLI_SYNC) + { + if (voodoo == voodoo->set->voodoos[0]) + { + voodoo_t *voodoo_1 = voodoo->set->voodoos[1]; + + thread_wait_mutex(voodoo->swap_mutex); + /*Only swap if both Voodoos are waiting for buffer swap*/ + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) && + voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + + memset(voodoo_1->dirty_line, 1, 1024); + voodoo_1->retrace_count = 0; + voodoo_1->front_offset = voodoo_1->swap_offset; + if (voodoo_1->swap_count > 0) + voodoo_1->swap_count--; + voodoo_1->swap_pending = 0; + thread_release_mutex(voodoo->swap_mutex); + + thread_set_event(voodoo->wake_fifo_thread); + thread_set_event(voodoo_1->wake_fifo_thread); + + voodoo->frame_count++; + voodoo_1->frame_count++; + } + else + thread_release_mutex(voodoo->swap_mutex); + } + } + else + { + thread_wait_mutex(voodoo->swap_mutex); + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_release_mutex(voodoo->swap_mutex); + + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + else + thread_release_mutex(voodoo->swap_mutex); + } + voodoo->v_retrace = 1; + } + voodoo->line++; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line == voodoo->v_disp) + { + int force_blit = 0; + thread_wait_mutex(voodoo->force_blit_mutex); + if(voodoo->force_blit_count) { + force_blit = 1; + if(--voodoo->force_blit_count < 0) + voodoo->force_blit_count = 0; + } + thread_release_mutex(voodoo->force_blit_mutex); + + if (voodoo->dirty_line_high > voodoo->dirty_line_low || force_blit) + svga_doblit(voodoo->h_disp, voodoo->v_disp-1, voodoo->svga); + if (voodoo->clutData_dirty) + { + voodoo->clutData_dirty = 0; + voodoo_calc_clutData(voodoo); + } + voodoo->dirty_line_high = -1; + voodoo->dirty_line_low = 2000; + } + } + + if (voodoo->line >= voodoo->v_total) + { + voodoo->line = 0; + voodoo->v_retrace = 0; + } + if (voodoo->line_time) + timer_advance_u64(&voodoo->timer, voodoo->line_time); + else + timer_advance_u64(&voodoo->timer, TIMER_USEC * 32); +} diff --git a/src/video/vid_voodoo_fb.c b/src/video/vid_voodoo_fb.c new file mode 100644 index 000000000..3ab482bff --- /dev/null +++ b/src/video/vid_voodoo_fb.c @@ -0,0 +1,494 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_dither.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_fb.h> + + +#ifdef ENABLE_VOODOO_FB_LOG +int voodoo_fb_do_log = ENABLE_VOODOO_FB_LOG; + +static void +voodoo_fb_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_fb_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_fb_log(fmt, ...) +#endif + + +uint16_t voodoo_fb_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint16_t temp; + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + if (voodoo->col_tiled) + read_addr = voodoo->fb_read_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffff; + + temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// voodoo_fb_log("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++); + return temp; +} +uint32_t voodoo_fb_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint32_t temp; + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + if (voodoo->col_tiled) + read_addr = voodoo->fb_read_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffffffff; + + temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// voodoo_fb_log("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width); + return temp; +} + +static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y) +{ + int r, g, b; + + if (dither) + { + if (dither2x2) + { + r = dither_rb2x2[col.r][y & 1][x & 1]; + g = dither_g2x2[col.g][y & 1][x & 1]; + b = dither_rb2x2[col.b][y & 1][x & 1]; + } + else + { + r = dither_rb[col.r][y & 3][x & 3]; + g = dither_g[col.g][y & 3][x & 3]; + b = dither_rb[col.b][y & 3][x & 3]; + } + } + else + { + r = col.r >> 3; + g = col.g >> 2; + b = col.b >> 3; + } + + return b | (g << 5) | (r << 11); +} + +void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data; + uint16_t depth_data; + uint8_t alpha_data; + int write_mask = 0; + + colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; + + depth_data = voodoo->params.zaColor & 0xffff; + alpha_data = voodoo->params.zaColor >> 24; + +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// voodoo_fb_log("voodoo_fb_writew : %08X %04X\n", addr, val); + + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data = rgb565[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_RGB555: + colour_data = argb1555[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_ARGB1555: + colour_data = argb1555[val]; + alpha_data = colour_data.a; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_DEPTH: + depth_data = val; + write_mask = LFB_WRITE_DEPTH; + break; + + default: + fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); + } + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + + if (voodoo->fb_write_offset == voodoo->params.front_offset && y < 2048) + voodoo->dirty_line[y] = 1; + + if (voodoo->col_tiled) + write_addr = voodoo->fb_write_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + if (voodoo->aux_tiled) + write_addr_aux = voodoo->params.aux_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// voodoo_fb_log("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr); + + if (voodoo->lfbMode & 0x100) + { + { + rgba8_t write_data = colour_data; + uint16_t new_depth = depth_data; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(new_depth); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int64_t w_depth = (int64_t)(int32_t)new_depth; + int32_t ia = alpha_data << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + return; + } + } + else + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data; + } +} + + +void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data[2]; + uint16_t depth_data[2]; + uint8_t alpha_data[2]; + int write_mask = 0, count = 1; + + depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; + alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// voodoo_fb_log("voodoo_fb_writel : %08X %08X\n", addr, val); + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data[0] = rgb565[val & 0xffff]; + colour_data[1] = rgb565[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_RGB555: + colour_data[0] = argb1555[val & 0xffff]; + colour_data[1] = argb1555[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_ARGB1555: + colour_data[0] = argb1555[val & 0xffff]; + alpha_data[0] = colour_data[0].a; + colour_data[1] = argb1555[val >> 16]; + alpha_data[1] = colour_data[1].a; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + + case LFB_FORMAT_ARGB8888: + colour_data[0].b = val & 0xff; + colour_data[0].g = (val >> 8) & 0xff; + colour_data[0].r = (val >> 16) & 0xff; + alpha_data[0] = (val >> 24) & 0xff; + write_mask = LFB_WRITE_COLOUR; + addr >>= 1; + break; + + case LFB_FORMAT_DEPTH: + depth_data[0] = val; + depth_data[1] = val >> 16; + write_mask = LFB_WRITE_DEPTH; + count = 2; + break; + + default: + fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); + } + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + if (voodoo->fb_write_offset == voodoo->params.front_offset && y < 2048) + voodoo->dirty_line[y] = 1; + + if (voodoo->col_tiled) + write_addr = voodoo->fb_write_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + if (voodoo->aux_tiled) + write_addr_aux = voodoo->params.aux_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// voodoo_fb_log("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset); + + if (voodoo->lfbMode & 0x100) + { + int c; + + for (c = 0; c < count; c++) + { + rgba8_t write_data = colour_data[c]; + uint16_t new_depth = depth_data[c]; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(new_depth); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int64_t w_depth = new_depth; + int32_t ia = alpha_data[c] << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data[c]); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + write_addr += 2; + write_addr_aux += 2; + } + } + else + { + int c; + + for (c = 0; c < count; c++) + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c]; + + write_addr += 2; + write_addr_aux += 2; + } + } +} diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c new file mode 100644 index 000000000..013c21db3 --- /dev/null +++ b/src/video/vid_voodoo_fifo.c @@ -0,0 +1,546 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_banshee_blitter.h> +#include <86box/vid_voodoo_fb.h> +#include <86box/vid_voodoo_fifo.h> +#include <86box/vid_voodoo_reg.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_texture.h> + + +#ifdef ENABLE_VOODOO_FIFO_LOG +int voodoo_fifo_do_log = ENABLE_VOODOO_FIFO_LOG; + +static void +voodoo_fifo_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_fifo_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_fifo_log(fmt, ...) +#endif + +#define WAKE_DELAY (TIMER_USEC * 100) +void voodoo_wake_fifo_thread(voodoo_t *voodoo) +{ + if (!timer_is_enabled(&voodoo->wake_timer)) + { + /*Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work.*/ + timer_set_delay_u64(&voodoo->wake_timer, WAKE_DELAY); + } +} + +void voodoo_wake_fifo_thread_now(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +void voodoo_wake_timer(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) +{ + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + + while (FIFO_FULL) + { + thread_reset_event(voodoo->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(voodoo->fifo_not_full_event, 1); /*Wait for room in ringbuffer*/ + if (FIFO_FULL) + voodoo_wake_fifo_thread_now(voodoo); + } + } + + fifo->val = val; + fifo->addr_type = addr_type; + + voodoo->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + voodoo_wake_fifo_thread(voodoo); +} + +void voodoo_flush(voodoo_t *voodoo) +{ + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + voodoo_wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + voodoo_wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; +} + +void voodoo_wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo) +{ + voodoo_wake_fifo_thread(voodoo); + if (SLI_ENABLED && voodoo->type != VOODOO_2 && set->voodoos[0] == voodoo) + voodoo_wake_fifo_thread(set->voodoos[1]); +} + +void voodoo_wait_for_swap_complete(voodoo_t *voodoo) +{ + while (voodoo->swap_pending) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + + thread_wait_mutex(voodoo->swap_mutex); + if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL) + { + /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + voodoo->front_offset = voodoo->params.front_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_release_mutex(voodoo->swap_mutex);; + break; + } + else + thread_release_mutex(voodoo->swap_mutex);; + } +} + + +static uint32_t cmdfifo_get(voodoo_t *voodoo) +{ + uint32_t val; + + if (!voodoo->cmdfifo_in_sub) { + while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + } + } + + val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; + + if (!voodoo->cmdfifo_in_sub) + voodoo->cmdfifo_depth_rd++; + voodoo->cmdfifo_rp += 4; + +// voodoo_fifo_log(" CMDFIFO get %08x\n", val); + return val; +} + +static inline float cmdfifo_get_f(voodoo_t *voodoo) +{ + union + { + uint32_t i; + float f; + } tempif; + + tempif.i = cmdfifo_get(voodoo); + return tempif.f; +} + +enum +{ + CMDFIFO3_PC_MASK_RGB = (1 << 10), + CMDFIFO3_PC_MASK_ALPHA = (1 << 11), + CMDFIFO3_PC_MASK_Z = (1 << 12), + CMDFIFO3_PC_MASK_Wb = (1 << 13), + CMDFIFO3_PC_MASK_W0 = (1 << 14), + CMDFIFO3_PC_MASK_S0_T0 = (1 << 15), + CMDFIFO3_PC_MASK_W1 = (1 << 16), + CMDFIFO3_PC_MASK_S1_T1 = (1 << 17), + + CMDFIFO3_PC = (1 << 28) +}; + +void voodoo_fifo_thread(void *param) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (voodoo->fifo_thread_run) + { + thread_set_event(voodoo->fifo_not_full_event); + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + voodoo->voodoo_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITEL_REG: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_REG) + { + voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEW_FB: + voodoo_wait_for_render_thread_idle(voodoo); + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEW_FB) + { + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEL_FB: + voodoo_wait_for_render_thread_idle(voodoo); + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_FB) + { + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEL_TEX: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_TEX) + { + if (!(fifo->addr_type & 0x400000)) + voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEL_2DREG: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_2DREG) + { + voodoo_2d_reg_writel(voodoo, fifo->addr_type & FIFO_ADDR, fifo->val); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + + default: + fatal("Unknown fifo entry %08x\n", fifo->addr_type); + } + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(voodoo->fifo_not_full_event); + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + + while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub)) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + uint32_t header = cmdfifo_get(voodoo); + uint32_t addr; + uint32_t mask; + int smode; + int num; + int num_verticies; + int v_num; + +// voodoo_fifo_log(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); + + switch (header & 7) + { + case 0: +// voodoo_fifo_log("CMDFIFO0\n"); + switch ((header >> 3) & 7) + { + case 0: /*NOP*/ + break; + + case 1: /*JSR*/ +// voodoo_fifo_log("JSR %08x\n", (header >> 4) & 0xfffffc); + voodoo->cmdfifo_ret_addr = voodoo->cmdfifo_rp; + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_in_sub = 1; + break; + + case 2: /*RET*/ + voodoo->cmdfifo_rp = voodoo->cmdfifo_ret_addr; + voodoo->cmdfifo_in_sub = 0; + break; + + case 3: /*JMP local frame buffer*/ + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; +// voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); + break; + + default: + fatal("Bad CMDFIFO0 %08x\n", header); + } + break; + + case 1: + num = header >> 16; + addr = (header & 0x7ff8) >> 1; +// voodoo_fifo_log("CMDFIFO1 addr=%08x\n",addr); + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) + { +// if (voodoo->type != VOODOO_BANSHEE) +// fatal("CMDFIFO1: Not Banshee\n"); +// voodoo_fifo_log("CMDFIFO1: write %08x %08x\n", addr, val); + voodoo_2d_reg_writel(voodoo, addr, val); + } + else + { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo++; + voodoo_reg_writel(addr, val, voodoo); + } + + if (header & (1 << 15)) + addr += 4; + } + break; + + case 2: + if (voodoo->type < VOODOO_BANSHEE) + fatal("CMDFIFO2: Not Banshee\n"); + mask = (header >> 3); + addr = 8; + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + + voodoo_2d_reg_writel(voodoo, addr, val); + } + + addr += 4; + mask >>= 1; + } + break; + + case 3: + num = (header >> 29) & 7; + mask = header;//(header >> 10) & 0xff; + smode = (header >> 22) & 0xf; + voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + num_verticies = (header >> 6) & 0xf; + v_num = 0; + if (((header >> 3) & 7) == 2) + v_num = 1; +// voodoo_fifo_log("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); +// voodoo_fifo_log("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); + + while (num_verticies--) + { + voodoo->verts[3].sVx = cmdfifo_get_f(voodoo); + voodoo->verts[3].sVy = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_RGB) + { + if (header & CMDFIFO3_PC) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + } + else + { + voodoo->verts[3].sRed = cmdfifo_get_f(voodoo); + voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo); + voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo); + } + } + if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) + voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Z) + voodoo->verts[3].sVz = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Wb) + voodoo->verts[3].sWb = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_W0) + voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S0_T0) + { + voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo); + } + if (mask & CMDFIFO3_PC_MASK_W1) + voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S1_T1) + { + voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); + } + if (v_num) + voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + else + voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + v_num++; + if (v_num == 3 && ((header >> 3) & 7) == 0) + v_num = 0; + } + break; + + case 4: + num = (header >> 29) & 7; + mask = (header >> 15) & 0x3fff; + addr = (header & 0x7ff8) >> 1; +// voodoo_fifo_log("CMDFIFO4 addr=%08x\n",addr); + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) + { + if (voodoo->type < VOODOO_BANSHEE) + fatal("CMDFIFO1: Not Banshee\n"); +// voodoo_fifo_log("CMDFIFO1: write %08x %08x\n", addr, val); + voodoo_2d_reg_writel(voodoo, addr, val); + } + else + { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo++; + voodoo_reg_writel(addr, val, voodoo); + } + } + + addr += 4; + mask >>= 1; + } + while (num--) + cmdfifo_get(voodoo); + break; + + case 5: +// if (header & 0x3fc00000) +// fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); + num = (header >> 3) & 0x7ffff; + addr = cmdfifo_get(voodoo) & 0xffffff; + if (!num) + num = 1; +// voodoo_fifo_log("CMDFIFO5 addr=%08x num=%i\n", addr, num); + switch (header >> 30) + { + case 0: /*Linear framebuffer (Banshee)*/ + if (voodoo->texture_present[0][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// voodoo_fifo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0); + } + if (voodoo->texture_present[1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// voodoo_fifo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 1); + } + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if (addr <= voodoo->fb_mask) + *(uint32_t *)&voodoo->fb_mem[addr] = val; + addr += 4; + } + break; + case 2: /*Framebuffer*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_fb_writel(addr, val, voodoo); + addr += 4; + } + break; + case 3: /*Texture*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_tex_writel(addr, val, voodoo); + addr += 4; + } + break; + + default: + fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); + } + break; + + default: + fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + } + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + voodoo->voodoo_busy = 0; + } +} diff --git a/src/video/vid_voodoo_reg.c b/src/video/vid_voodoo_reg.c new file mode 100644 index 000000000..797fa130f --- /dev/null +++ b/src/video/vid_voodoo_reg.c @@ -0,0 +1,1366 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_banshee.h> +#include <86box/vid_voodoo_blitter.h> +#include <86box/vid_voodoo_dither.h> +#include <86box/vid_voodoo_fifo.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_setup.h> +#include <86box/vid_voodoo_texture.h> + + +enum +{ + CHIP_FBI = 0x1, + CHIP_TREX0 = 0x2, + CHIP_TREX1 = 0x4, + CHIP_TREX2 = 0x8 +}; + + +#ifdef ENABLE_VOODOO_REG_LOG +int voodoo_reg_do_log = ENABLE_VOODOO_REG_LOG; + +static void +voodoo_reg_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_reg_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_reg_log(fmt, ...) +#endif + + +void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + union + { + uint32_t i; + float f; + } tempif; + int ad21 = addr & (1 << 21); + int chip = (addr >> 10) & 0xf; + if (!chip) + chip = 0xf; + + tempif.i = val; +//voodoo_reg_log("voodoo_reg_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip); + addr &= 0x3fc; + + if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21) + addr |= 0x400; + switch (addr) + { + case SST_swapbufferCMD: + if (voodoo->type >= VOODOO_BANSHEE) + { +// voodoo_reg_log("swapbufferCMD %08x %08x\n", val, voodoo->leftOverlayBuf); + + voodoo_wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + banshee_set_overlay_addr(voodoo->p, voodoo->leftOverlayBuf); + thread_wait_mutex(voodoo->swap_mutex); + if (voodoo->swap_count > 0) + voodoo->swap_count--; + thread_release_mutex(voodoo->swap_mutex); + voodoo->frame_count++; + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + voodoo_wait_for_swap_complete(voodoo); + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->leftOverlayBuf; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->leftOverlayBuf; + voodoo->swap_pending = 1; + + voodoo_wait_for_swap_complete(voodoo); + } + + voodoo->cmd_read++; + break; + } + + if (TRIPLE_BUFFER) + { + voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3; + voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3; + } + else + { + voodoo->disp_buffer = !voodoo->disp_buffer; + voodoo->draw_buffer = !voodoo->draw_buffer; + } + voodoo_recalc(voodoo); + + voodoo->params.swapbufferCMD = val; + +// voodoo_reg_log("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); +// voodoo->front_offset = params->front_offset; + voodoo_wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + voodoo->front_offset = voodoo->params.front_offset; + thread_wait_mutex(voodoo->swap_mutex); + if (voodoo->swap_count > 0) + voodoo->swap_count--; + thread_release_mutex(voodoo->swap_mutex); + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + voodoo_wait_for_swap_complete(voodoo); + + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + + voodoo_wait_for_swap_complete(voodoo); + } + voodoo->cmd_read++; + break; + + case SST_vertexAx: case SST_remap_vertexAx: + voodoo->params.vertexAx = val & 0xffff; + break; + case SST_vertexAy: case SST_remap_vertexAy: + voodoo->params.vertexAy = val & 0xffff; + break; + case SST_vertexBx: case SST_remap_vertexBx: + voodoo->params.vertexBx = val & 0xffff; + break; + case SST_vertexBy: case SST_remap_vertexBy: + voodoo->params.vertexBy = val & 0xffff; + break; + case SST_vertexCx: case SST_remap_vertexCx: + voodoo->params.vertexCx = val & 0xffff; + break; + case SST_vertexCy: case SST_remap_vertexCy: + voodoo->params.vertexCy = val & 0xffff; + break; + + case SST_startR: case SST_remap_startR: + voodoo->params.startR = val & 0xffffff; + break; + case SST_startG: case SST_remap_startG: + voodoo->params.startG = val & 0xffffff; + break; + case SST_startB: case SST_remap_startB: + voodoo->params.startB = val & 0xffffff; + break; + case SST_startZ: case SST_remap_startZ: + voodoo->params.startZ = val; + break; + case SST_startA: case SST_remap_startA: + voodoo->params.startA = val & 0xffffff; + break; + case SST_startS: case SST_remap_startS: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startS = ((int64_t)(int32_t)val) << 14; + break; + case SST_startT: case SST_remap_startT: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startT = ((int64_t)(int32_t)val) << 14; + break; + case SST_startW: case SST_remap_startW: + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startW = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdX: case SST_remap_dRdX: + voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdX: case SST_remap_dGdX: + voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdX: case SST_remap_dBdX: + voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdX: case SST_remap_dZdX: + voodoo->params.dZdX = val; + break; + case SST_dAdX: case SST_remap_dAdX: + voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdX: case SST_remap_dSdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdX: case SST_remap_dTdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdX: case SST_remap_dWdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdY: case SST_remap_dRdY: + voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdY: case SST_remap_dGdY: + voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdY: case SST_remap_dBdY: + voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdY: case SST_remap_dZdY: + voodoo->params.dZdY = val; + break; + case SST_dAdY: case SST_remap_dAdY: + voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdY: case SST_remap_dSdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdY: case SST_remap_dTdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdY: case SST_remap_dWdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(int32_t)val << 2; + break; + + case SST_triangleCMD: case SST_remap_triangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + voodoo_queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fvertexAx: case SST_remap_fvertexAx: + voodoo->fvertexAx.i = val; + voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff; + break; + case SST_fvertexAy: case SST_remap_fvertexAy: + voodoo->fvertexAy.i = val; + voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff; + break; + case SST_fvertexBx: case SST_remap_fvertexBx: + voodoo->fvertexBx.i = val; + voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff; + break; + case SST_fvertexBy: case SST_remap_fvertexBy: + voodoo->fvertexBy.i = val; + voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff; + break; + case SST_fvertexCx: case SST_remap_fvertexCx: + voodoo->fvertexCx.i = val; + voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff; + break; + case SST_fvertexCy: case SST_remap_fvertexCy: + voodoo->fvertexCy.i = val; + voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff; + break; + + case SST_fstartR: case SST_remap_fstartR: + tempif.i = val; + voodoo->params.startR = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartG: case SST_remap_fstartG: + tempif.i = val; + voodoo->params.startG = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartB: case SST_remap_fstartB: + tempif.i = val; + voodoo->params.startB = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartZ: case SST_remap_fstartZ: + tempif.i = val; + voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartA: case SST_remap_fstartA: + tempif.i = val; + voodoo->params.startA = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartS: case SST_remap_fstartS: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startS = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartT: case SST_remap_fstartT: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startT = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartW: case SST_remap_fstartW: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdX: case SST_remap_fdRdX: + tempif.i = val; + voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdX: case SST_remap_fdGdX: + tempif.i = val; + voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdX: case SST_remap_fdBdX: + tempif.i = val; + voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdX: case SST_remap_fdZdX: + tempif.i = val; + voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdX: case SST_remap_fdAdX: + tempif.i = val; + voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdX: case SST_remap_fdSdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdX: case SST_remap_fdTdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdX: case SST_remap_fdWdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdY: case SST_remap_fdRdY: + tempif.i = val; + voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdY: case SST_remap_fdGdY: + tempif.i = val; + voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdY: case SST_remap_fdBdY: + tempif.i = val; + voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdY: case SST_remap_fdZdY: + tempif.i = val; + voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdY: case SST_remap_fdAdY: + tempif.i = val; + voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdY: case SST_remap_fdSdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdY: case SST_remap_fdTdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdY: case SST_remap_fdWdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_ftriangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + voodoo_queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fbzColorPath: + voodoo->params.fbzColorPath = val; + voodoo->rgb_sel = val & 3; + break; + + case SST_fogMode: + voodoo->params.fogMode = val; + break; + case SST_alphaMode: + voodoo->params.alphaMode = val; + break; + case SST_fbzMode: + voodoo->params.fbzMode = val; + voodoo_recalc(voodoo); + break; + case SST_lfbMode: + voodoo->lfbMode = val; + voodoo_recalc(voodoo); + break; + + case SST_clipLeftRight: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipRight = val & 0xfff; + voodoo->params.clipLeft = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + } + break; + case SST_clipLowYHighY: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipHighY = val & 0xfff; + voodoo->params.clipLowY = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipHighY = val & 0x3ff; + voodoo->params.clipLowY = (val >> 16) & 0x3ff; + } + break; + + case SST_nopCMD: + voodoo->cmd_read++; + voodoo->fbiPixelsIn = 0; + voodoo->fbiChromaFail = 0; + voodoo->fbiZFuncFail = 0; + voodoo->fbiAFuncFail = 0; + voodoo->fbiPixelsOut = 0; + break; + case SST_fastfillCMD: + voodoo_wait_for_render_thread_idle(voodoo); + voodoo_fastfill(voodoo, &voodoo->params); + voodoo->cmd_read++; + break; + + case SST_fogColor: + voodoo->params.fogColor.r = (val >> 16) & 0xff; + voodoo->params.fogColor.g = (val >> 8) & 0xff; + voodoo->params.fogColor.b = val & 0xff; + break; + + case SST_zaColor: + voodoo->params.zaColor = val; + break; + case SST_chromaKey: + voodoo->params.chromaKey_r = (val >> 16) & 0xff; + voodoo->params.chromaKey_g = (val >> 8) & 0xff; + voodoo->params.chromaKey_b = val & 0xff; + voodoo->params.chromaKey = val & 0xffffff; + break; + case SST_stipple: + voodoo->params.stipple = val; + break; + case SST_color0: + voodoo->params.color0 = val; + break; + case SST_color1: + voodoo->params.color1 = val; + break; + + case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03: + case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07: + case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b: + case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f: + case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13: + case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17: + case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b: + case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f: + addr = (addr - SST_fogTable00) >> 1; + voodoo->params.fogTable[addr].dfog = val & 0xff; + voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff; + voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; + voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; + break; + + case SST_clipLeftRight1: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.clipRight1 = val & 0xfff; + voodoo->params.clipLeft1 = (val >> 16) & 0xfff; + } + break; + case SST_clipTopBottom1: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.clipHighY1 = val & 0xfff; + voodoo->params.clipLowY1 = (val >> 16) & 0xfff; + } + break; + + case SST_colBufferAddr: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.draw_offset = val & 0xfffff0; + voodoo->fb_write_offset = voodoo->params.draw_offset; +// voodoo_reg_log("colorBufferAddr=%06x\n", voodoo->params.draw_offset); + } + break; + case SST_colBufferStride: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->col_tiled = val & (1 << 15); + voodoo->params.col_tiled = voodoo->col_tiled; + if (voodoo->col_tiled) + { + voodoo->row_width = (val & 0x7f) * 128*32; +// voodoo_reg_log("colBufferStride tiled = %i bytes, tiled %08x\n", voodoo->row_width, val); + } + else + { + voodoo->row_width = val & 0x3fff; +// voodoo_reg_log("colBufferStride linear = %i bytes, linear\n", voodoo->row_width); + } + voodoo->params.row_width = voodoo->row_width; + } + break; + case SST_auxBufferAddr: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.aux_offset = val & 0xfffff0; +// pclog("auxBufferAddr=%06x\n", voodoo->params.aux_offset); + } + break; + case SST_auxBufferStride: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->aux_tiled = val & (1 << 15); + voodoo->params.aux_tiled = voodoo->aux_tiled; + if (voodoo->aux_tiled) + { + voodoo->aux_row_width = (val & 0x7f) * 128*32; +// voodoo_reg_log("auxBufferStride tiled = %i bytes, tiled\n", voodoo->aux_row_width); + } + else + { + voodoo->aux_row_width = val & 0x3fff; +// voodoo_reg_log("auxBufferStride linear = %i bytes, linear\n", voodoo->aux_row_width); + } + voodoo->params.aux_row_width = voodoo->aux_row_width; + } + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + if (val & 0x20000000) + { + voodoo->clutData[(val >> 24) & 0x3f].b = 255; + voodoo->clutData[(val >> 24) & 0x3f].g = 255; + voodoo->clutData[(val >> 24) & 0x3f].r = 255; + } + voodoo->clutData_dirty = 1; + break; + + case SST_sSetupMode: + voodoo->sSetupMode = val; + break; + case SST_sVx: + tempif.i = val; + voodoo->verts[3].sVx = tempif.f; +// voodoo_reg_log("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sVy: + tempif.i = val; + voodoo->verts[3].sVy = tempif.f; +// voodoo_reg_log("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sARGB: + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + break; + case SST_sRed: + tempif.i = val; + voodoo->verts[3].sRed = tempif.f; + break; + case SST_sGreen: + tempif.i = val; + voodoo->verts[3].sGreen = tempif.f; + break; + case SST_sBlue: + tempif.i = val; + voodoo->verts[3].sBlue = tempif.f; + break; + case SST_sAlpha: + tempif.i = val; + voodoo->verts[3].sAlpha = tempif.f; + break; + case SST_sVz: + tempif.i = val; + voodoo->verts[3].sVz = tempif.f; + break; + case SST_sWb: + tempif.i = val; + voodoo->verts[3].sWb = tempif.f; + break; + case SST_sW0: + tempif.i = val; + voodoo->verts[3].sW0 = tempif.f; + break; + case SST_sS0: + tempif.i = val; + voodoo->verts[3].sS0 = tempif.f; + break; + case SST_sT0: + tempif.i = val; + voodoo->verts[3].sT0 = tempif.f; + break; + case SST_sW1: + tempif.i = val; + voodoo->verts[3].sW1 = tempif.f; + break; + case SST_sS1: + tempif.i = val; + voodoo->verts[3].sS1 = tempif.f; + break; + case SST_sT1: + tempif.i = val; + voodoo->verts[3].sT1 = tempif.f; + break; + + case SST_sBeginTriCMD: +// voodoo_reg_log("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx); + voodoo->verts[0] = voodoo->verts[3]; + voodoo->verts[1] = voodoo->verts[3]; + voodoo->verts[2] = voodoo->verts[3]; + voodoo->vertex_next_age = 0; + voodoo->vertex_ages[0] = voodoo->vertex_next_age++; + + voodoo->num_verticies = 1; + voodoo->cull_pingpong = 0; + break; + case SST_sDrawTriCMD: +// voodoo_reg_log("sDrawTriCMD %i %i\n", voodoo->num_verticies, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); + /*I'm not sure this is the vertex selection algorithm actually used in the 3dfx + chips, but this works with a number of games that switch between strip and fan + mode in the middle of a run (eg Black & White, Viper Racing)*/ + if (voodoo->vertex_next_age < 3) + { + /*Fewer than three vertices already written, store in next slot*/ + int vertex_nr = voodoo->vertex_next_age; + + voodoo->verts[vertex_nr] = voodoo->verts[3]; + voodoo->vertex_ages[vertex_nr] = voodoo->vertex_next_age++; + } + else + { + int vertex_nr = 0; + + if (!(voodoo->sSetupMode & SETUPMODE_STRIP_MODE)) + { + /*Strip - find oldest vertex*/ + if ((voodoo->vertex_ages[0] < voodoo->vertex_ages[1]) && + (voodoo->vertex_ages[0] < voodoo->vertex_ages[2])) + vertex_nr = 0; + else if ((voodoo->vertex_ages[1] < voodoo->vertex_ages[0]) && + (voodoo->vertex_ages[1] < voodoo->vertex_ages[2])) + vertex_nr = 1; + else + vertex_nr = 2; + } + else + { + /*Fan - find second oldest vertex (ie pivot around oldest)*/ + if ((voodoo->vertex_ages[1] < voodoo->vertex_ages[0]) && + (voodoo->vertex_ages[0] < voodoo->vertex_ages[2])) + vertex_nr = 0; + else if ((voodoo->vertex_ages[2] < voodoo->vertex_ages[0]) && + (voodoo->vertex_ages[0] < voodoo->vertex_ages[1])) + vertex_nr = 0; + else if ((voodoo->vertex_ages[0] < voodoo->vertex_ages[1]) && + (voodoo->vertex_ages[1] < voodoo->vertex_ages[2])) + vertex_nr = 1; + else if ((voodoo->vertex_ages[2] < voodoo->vertex_ages[1]) && + (voodoo->vertex_ages[1] < voodoo->vertex_ages[0])) + vertex_nr = 1; + else + vertex_nr = 2; + } + voodoo->verts[vertex_nr] = voodoo->verts[3]; + voodoo->vertex_ages[vertex_nr] = voodoo->vertex_next_age++; + } + + voodoo->num_verticies++; + if (voodoo->num_verticies == 3) + { +// voodoo_reg_log("triangle_setup\n"); + voodoo_triangle_setup(voodoo); + voodoo->cull_pingpong = !voodoo->cull_pingpong; + + voodoo->num_verticies = 2; + } + break; + + case SST_bltSrcBaseAddr: + voodoo->bltSrcBaseAddr = val & 0x3fffff; + break; + case SST_bltDstBaseAddr: +// voodoo_reg_log("Write bltDstBaseAddr %08x\n", val); + voodoo->bltDstBaseAddr = val & 0x3fffff; + break; + case SST_bltXYStrides: + voodoo->bltSrcXYStride = val & 0xfff; + voodoo->bltDstXYStride = (val >> 16) & 0xfff; +// voodoo_reg_log("Write bltXYStrides %08x\n", val); + break; + case SST_bltSrcChromaRange: + voodoo->bltSrcChromaRange = val; + voodoo->bltSrcChromaMinB = val & 0x1f; + voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; + voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; + voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltDstChromaRange: + voodoo->bltDstChromaRange = val; + voodoo->bltDstChromaMinB = val & 0x1f; + voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; + voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; + voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltClipX: + voodoo->bltClipRight = val & 0xfff; + voodoo->bltClipLeft = (val >> 16) & 0xfff; + break; + case SST_bltClipY: + voodoo->bltClipHighY = val & 0xfff; + voodoo->bltClipLowY = (val >> 16) & 0xfff; + break; + + case SST_bltSrcXY: + voodoo->bltSrcX = val & 0x7ff; + voodoo->bltSrcY = (val >> 16) & 0x7ff; + break; + case SST_bltDstXY: +// voodoo_reg_log("Write bltDstXY %08x\n", val); + voodoo->bltDstX = val & 0x7ff; + voodoo->bltDstY = (val >> 16) & 0x7ff; + if (val & (1 << 31)) + voodoo_v2_blit_start(voodoo); + break; + case SST_bltSize: +// voodoo_reg_log("Write bltSize %08x\n", val); + voodoo->bltSizeX = val & 0xfff; + if (voodoo->bltSizeX & 0x800) + voodoo->bltSizeX |= 0xfffff000; + voodoo->bltSizeY = (val >> 16) & 0xfff; + if (voodoo->bltSizeY & 0x800) + voodoo->bltSizeY |= 0xfffff000; + if (val & (1 << 31)) + voodoo_v2_blit_start(voodoo); + break; + case SST_bltRop: + voodoo->bltRop[0] = val & 0xf; + voodoo->bltRop[1] = (val >> 4) & 0xf; + voodoo->bltRop[2] = (val >> 8) & 0xf; + voodoo->bltRop[3] = (val >> 12) & 0xf; + break; + case SST_bltColor: +// voodoo_reg_log("Write bltColor %08x\n", val); + voodoo->bltColorFg = val & 0xffff; + voodoo->bltColorBg = (val >> 16) & 0xffff; + break; + + case SST_bltCommand: + voodoo->bltCommand = val; +// voodoo_reg_log("Write bltCommand %08x\n", val); + if (val & (1 << 31)) + voodoo_v2_blit_start(voodoo); + break; + case SST_bltData: + voodoo_v2_blit_data(voodoo, val); + break; + + case SST_textureMode: + if (chip & CHIP_TREX0) + { + voodoo->params.textureMode[0] = val; + voodoo->params.tformat[0] = (val >> 8) & 0xf; + } + if (chip & CHIP_TREX1) + { + voodoo->params.textureMode[1] = val; + voodoo->params.tformat[1] = (val >> 8) & 0xf; + } + break; + case SST_tLOD: + if (chip & CHIP_TREX0) + { + voodoo->params.tLOD[0] = val; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.tLOD[1] = val; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_tDetail: + if (chip & CHIP_TREX0) + { + voodoo->params.detail_max[0] = val & 0xff; + voodoo->params.detail_bias[0] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[0] = (val >> 14) & 7; + } + if (chip & CHIP_TREX1) + { + voodoo->params.detail_max[1] = val & 0xff; + voodoo->params.detail_bias[1] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[1] = (val >> 14) & 7; + } + break; + case SST_texBaseAddr: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; +// voodoo_reg_log("texBaseAddr = %08x %08x\n", voodoo->params.texBaseAddr[0], val); + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr1: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr1[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr1[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr2: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr2[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr2[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr38: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr38[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr38[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + + case SST_trexInit1: + if (chip & CHIP_TREX0) + voodoo->trexInit1[0] = val; + if (chip & CHIP_TREX1) + voodoo->trexInit1[1] = val; + break; + + case SST_nccTable0_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_nccTable0_I0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = (val >> 23) & 0xfe; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable0_I1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = ((val >> 23) & 0xfe) | 0x01; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable1_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x from FIFO\n", val); + break; + + + case SST_leftOverlayBuf: + voodoo->leftOverlayBuf = val; + break; + } +} diff --git a/src/video/vid_voodoo_render.c b/src/video/vid_voodoo_render.c new file mode 100644 index 000000000..362f45abe --- /dev/null +++ b/src/video/vid_voodoo_render.c @@ -0,0 +1,1690 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_dither.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_texture.h> + + +typedef struct voodoo_state_t +{ + int xstart, xend, xdir; + uint32_t base_r, base_g, base_b, base_a, base_z; + struct + { + int64_t base_s, base_t, base_w; + int lod; + } tmu[2]; + int64_t base_w; + int lod; + int lod_min[2], lod_max[2]; + int dx1, dx2; + int y, yend, ydir; + int32_t dxAB, dxAC, dxBC; + int tex_b[2], tex_g[2], tex_r[2], tex_a[2]; + int tex_s, tex_t; + int clamp_s[2], clamp_t[2]; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t *tex[2][LOD_MAX+1]; + int tformat; + + int *tex_w_mask[2]; + int *tex_h_mask[2]; + int *tex_shift[2]; + int *tex_lod[2]; + + uint16_t *fb_mem, *aux_mem; + + int32_t ib, ig, ir, ia; + int32_t z; + + int32_t new_depth; + + int64_t tmu0_s, tmu0_t; + int64_t tmu0_w; + int64_t tmu1_s, tmu1_t; + int64_t tmu1_w; + int64_t w; + + int pixel_count, texel_count; + int x, x2, x_tiled; + + uint32_t w_depth; + + float log_temp; + uint32_t ebp_store; + uint32_t texBaseAddr; + + int lod_frac[2]; +} voodoo_state_t; + +#ifdef ENABLE_VOODOO_RENDER_LOG +int voodoo_render_do_log = ENABLE_VOODOO_RENDER_LOG; + +static void +voodoo_render_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_render_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_render_log(fmt, ...) +#endif + + +static uint8_t logtable[256] = +{ + 0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15, + 0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a, + 0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e, + 0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51, + 0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63, + 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, + 0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85, + 0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94, + 0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3, + 0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2, + 0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0, + 0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd, + 0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda, + 0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7, + 0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3, + 0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff +}; + +static __inline int fastlog(uint64_t val) +{ + uint64_t oldval = val; + int exp = 63; + int frac; + + if (!val || val & (1ULL << 63)) + return 0x80000000; + + if (!(val & 0xffffffff00000000)) + { + exp -= 32; + val <<= 32; + } + if (!(val & 0xffff000000000000)) + { + exp -= 16; + val <<= 16; + } + if (!(val & 0xff00000000000000)) + { + exp -= 8; + val <<= 8; + } + if (!(val & 0xf000000000000000)) + { + exp -= 4; + val <<= 4; + } + if (!(val & 0xc000000000000000)) + { + exp -= 2; + val <<= 2; + } + if (!(val & 0x8000000000000000)) + { + exp -= 1; + val <<= 1; + } + + if (exp >= 8) + frac = (oldval >> (exp - 8)) & 0xff; + else + frac = (oldval << (8 - exp)) & 0xff; + + return (exp << 8) | logtable[frac]; +} + +static inline int voodoo_fls(uint16_t val) +{ + int num = 0; + +//voodoo_render_log("fls(%04x) = ", val); + if (!(val & 0xff00)) + { + num += 8; + val <<= 8; + } + if (!(val & 0xf000)) + { + num += 4; + val <<= 4; + } + if (!(val & 0xc000)) + { + num += 2; + val <<= 2; + } + if (!(val & 0x8000)) + { + num += 1; + val <<= 1; + } +//voodoo_render_log("%i %04x\n", num, val); + return num; +} + +typedef struct voodoo_texture_state_t +{ + int s, t; + int w_mask, h_mask; + int tex_shift; +} voodoo_texture_state_t; + +static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int tmu) +{ + uint32_t dat; + + if (texture_state->s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + if (texture_state->s < 0) + texture_state->s = 0; + if (texture_state->s > texture_state->w_mask) + texture_state->s = texture_state->w_mask; + } + else + texture_state->s &= texture_state->w_mask; + } + if (texture_state->t & ~texture_state->h_mask) + { + if (state->clamp_t[tmu]) + { + if (texture_state->t < 0) + texture_state->t = 0; + if (texture_state->t > texture_state->h_mask) + texture_state->t = texture_state->h_mask; + } + else + texture_state->t &= texture_state->h_mask; + } + + dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + + state->tex_b[tmu] = dat & 0xff; + state->tex_g[tmu] = (dat >> 8) & 0xff; + state->tex_r[tmu] = (dat >> 16) & 0xff; + state->tex_a[tmu] = (dat >> 24) & 0xff; +} + +#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4)) +#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4)) + +static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d, int tmu, int x) +{ + rgba_u dat[4]; + + if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask)) + { + int c; + for (c = 0; c < 4; c++) + { + int _s = s + (c & 1); + int _t = t + ((c & 2) >> 1); + + if (_s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + if (_s < 0) + _s = 0; + if (_s > texture_state->w_mask) + _s = texture_state->w_mask; + } + else + _s &= texture_state->w_mask; + } + if (_t & ~texture_state->h_mask) + { + if (state->clamp_t[tmu]) + { + if (_t < 0) + _t = 0; + if (_t > texture_state->h_mask) + _t = texture_state->h_mask; + } + else + _t &= texture_state->h_mask; + } + dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)]; + } + } + else + { + dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)]; + dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + + state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8; + state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8; + state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8; + state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8; +} + +static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + voodoo_texture_state_t texture_state; + int d[4]; + int s, t; + int tex_lod = state->tex_lod[tmu][state->lod]; + + texture_state.w_mask = state->tex_w_mask[tmu][state->lod]; + texture_state.h_mask = state->tex_h_mask[tmu][state->lod]; + texture_state.tex_shift = 8 - tex_lod; + + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + if (state->tex_s & 0x1000) + state->tex_s = ~state->tex_s; + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + if (state->tex_t & 0x1000) + state->tex_t = ~state->tex_t; + } + + if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6) + { + int _ds, dt; + + state->tex_s -= 1 << (3+tex_lod); + state->tex_t -= 1 << (3+tex_lod); + + s = state->tex_s >> tex_lod; + t = state->tex_t >> tex_lod; + + _ds = s & 0xf; + dt = t & 0xf; + + s >>= 4; + t >>= 4; +//if (x == 80) +//if (voodoo_output) +// voodoo_render_log("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt); + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + +// texture_state.s = s; +// texture_state.t = t; + tex_read_4(state, &texture_state, s, t, d, tmu, x); + + +/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8; + state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8; + state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8; + state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/ +/* state->tex_r = tex_samples[0].r; + state->tex_g = tex_samples[0].g; + state->tex_b = tex_samples[0].b; + state->tex_a = tex_samples[0].a;*/ + } + else + { + // rgba_t tex_samples; + // voodoo_texture_state_t texture_state; +// int s = state->tex_s >> (18+state->lod); +// int t = state->tex_t >> (18+state->lod); + // int s, t; + +// state->tex_s -= 1 << (17+state->lod); +// state->tex_t -= 1 << (17+state->lod); + + s = state->tex_s >> (4+tex_lod); + t = state->tex_t >> (4+tex_lod); + + texture_state.s = s; + texture_state.t = t; + tex_read(state, &texture_state, tmu); + +/* state->tex_r = tex_samples[0].rgba.r; + state->tex_g = tex_samples[0].rgba.g; + state->tex_b = tex_samples[0].rgba.b; + state->tex_a = tex_samples[0].rgba.a;*/ + } +} + +static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + if (params->textureMode[tmu] & 1) + { + int64_t _w = 0; + + if (tmu) + { + if (state->tmu1_w) + _w = (int64_t)((1ULL << 48) / state->tmu1_w); + state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + else + { + if (state->tmu0_w) + _w = (int64_t)((1ULL << 48) / state->tmu0_w); + state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + + state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8)); + } + else + { + if (tmu) + { + state->tex_s = (int32_t)(state->tmu1_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu1_t >> (14+14)); + } + else + { + state->tex_s = (int32_t)(state->tmu0_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu0_t >> (14+14)); + } + state->lod = state->tmu[tmu].lod; + } + + if (state->lod < state->lod_min[tmu]) + state->lod = state->lod_min[tmu]; + else if (state->lod > state->lod_max[tmu]) + state->lod = state->lod_max[tmu]; + state->lod_frac[tmu] = state->lod & 0xff; + state->lod >>= 8; + + voodoo_get_texture(voodoo, params, state, tmu, x); +} + + +/*Perform texture fetch and blending for both TMUs*/ +static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) +{ + int r,g,b,a; + int c_reverse, a_reverse; +// int c_reverse1, a_reverse1; + int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; + + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } +/* c_reverse1 = c_reverse; + a_reverse1 = a_reverse;*/ + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[1]; + factor_g = state->tex_g[1]; + factor_b = state->tex_b[1]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_r > params->detail_max[1]) + factor_r = params->detail_max[1]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[1]; + break; + } + if (!c_reverse) + { + r = (-state->tex_r[1] * (factor_r + 1)) >> 8; + g = (-state->tex_g[1] * (factor_g + 1)) >> 8; + b = (-state->tex_b[1] * (factor_b + 1)) >> 8; + } + else + { + r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8; + g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8; + b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal_1) + { + r += state->tex_r[1]; + g += state->tex_g[1]; + b += state->tex_b[1]; + } + else if (tc_add_alocal_1) + { + r += state->tex_a[1]; + g += state->tex_a[1]; + b += state->tex_a[1]; + } + state->tex_r[1] = CLAMP(r); + state->tex_g[1] = CLAMP(g); + state->tex_b[1] = CLAMP(b); + } + if (tca_sub_clocal_1) + { + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_AOTHER: + factor_a = 0; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_a > params->detail_max[1]) + factor_a = params->detail_max[1]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[1]; + break; + } + if (!a_reverse) + a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (-state->tex_a[1] * (factor_a + 1)) >> 8; + if (tca_add_clocal_1 || tca_add_alocal_1) + a += state->tex_a[1]; + state->tex_a[1] = CLAMP(a); + } + + + voodoo_tmu_fetch(voodoo, params, state, 0, x); + + if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } + + if (!tc_zero_other) + { + r = state->tex_r[1]; + g = state->tex_g[1]; + b = state->tex_b[1]; + } + else + r = g = b = 0; + if (tc_sub_clocal) + { + r -= state->tex_r[0]; + g -= state->tex_g[0]; + b -= state->tex_b[0]; + } + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[0]; + factor_g = state->tex_g[0]; + factor_b = state->tex_b[0]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[0]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_r > params->detail_max[0]) + factor_r = params->detail_max[0]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[0]; + break; + } + if (!c_reverse) + { + r = (r * (factor_r + 1)) >> 8; + g = (g * (factor_g + 1)) >> 8; + b = (b * (factor_b + 1)) >> 8; + } + else + { + r = (r * ((factor_r^0xff) + 1)) >> 8; + g = (g * ((factor_g^0xff) + 1)) >> 8; + b = (b * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal) + { + r += state->tex_r[0]; + g += state->tex_g[0]; + b += state->tex_b[0]; + } + else if (tc_add_alocal) + { + r += state->tex_a[0]; + g += state->tex_a[0]; + b += state->tex_a[0]; + } + + if (!tca_zero_other) + a = state->tex_a[1]; + else + a = 0; + if (tca_sub_clocal) + a -= state->tex_a[0]; + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_AOTHER: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_a > params->detail_max[0]) + factor_a = params->detail_max[0]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[0]; + break; + } + if (a_reverse) + a = (a * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (a * (factor_a + 1)) >> 8; + if (tca_add_clocal || tca_add_alocal) + a += state->tex_a[0]; + + + state->tex_r[0] = CLAMP(r); + state->tex_g[0] = CLAMP(g); + state->tex_b[0] = CLAMP(b); + state->tex_a[0] = CLAMP(a); + + if (tc_invert_output) + { + state->tex_r[0] ^= 0xff; + state->tex_g[0] ^= 0xff; + state->tex_b[0] ^= 0xff; + } + if (tca_invert_output) + state->tex_a[0] ^= 0xff; +} + +#if (defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86) && !(defined __amd64__ || defined _M_X64) +#include <86box/vid_voodoo_codegen_x86.h> +#elif (defined __amd64__ || defined _M_X64) +#include <86box/vid_voodoo_codegen_x86-64.h> +#else +int voodoo_recomp = 0; +#endif + +static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even) +{ +/* int rgb_sel = params->fbzColorPath & 3; + int a_sel = (params->fbzColorPath >> 2) & 3; + int cc_localselect = params->fbzColorPath & (1 << 4); + int cca_localselect = (params->fbzColorPath >> 5) & 3; + int cc_localselect_override = params->fbzColorPath & (1 << 7); + int cc_zero_other = params->fbzColorPath & (1 << 8); + int cc_sub_clocal = params->fbzColorPath & (1 << 9); + int cc_mselect = (params->fbzColorPath >> 10) & 7; + int cc_reverse_blend = params->fbzColorPath & (1 << 13); + int cc_add = (params->fbzColorPath >> 14) & 3; + int cc_add_alocal = params->fbzColorPath & (1 << 15); + int cc_invert_output = params->fbzColorPath & (1 << 16); + int cca_zero_other = params->fbzColorPath & (1 << 17); + int cca_sub_clocal = params->fbzColorPath & (1 << 18); + int cca_mselect = (params->fbzColorPath >> 19) & 7; + int cca_reverse_blend = params->fbzColorPath & (1 << 22); + int cca_add = (params->fbzColorPath >> 23) & 3; + int cca_invert_output = params->fbzColorPath & (1 << 25); + int src_afunc = (params->alphaMode >> 8) & 0xf; + int dest_afunc = (params->alphaMode >> 12) & 0xf; + int alpha_func = (params->alphaMode >> 1) & 7; + int a_ref = params->alphaMode >> 24; + int depth_op = (params->fbzMode >> 5) & 7; + int dither = params->fbzMode & FBZ_DITHER;*/ + int texels; + int c; +#ifndef NO_CODEGEN + uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); +#endif + int y_diff = SLI_ENABLED ? 2 : 1; + int y_origin = (voodoo->type >= VOODOO_BANSHEE) ? voodoo->y_origin_swap : (voodoo->v_disp-1); + + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + texels = 1; + else + texels = 2; + + state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS; + state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT; + state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS; + state->clamp_t[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPT; +// int last_x; +// voodoo_render_log("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); + + for (c = 0; c <= LOD_MAX; c++) + { + state->tex[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]]; + state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]]; + } + + state->tformat = params->tformat[0]; + + state->tex_w_mask[0] = params->tex_w_mask[0]; + state->tex_h_mask[0] = params->tex_h_mask[0]; + state->tex_shift[0] = params->tex_shift[0]; + state->tex_lod[0] = params->tex_lod[0]; + state->tex_w_mask[1] = params->tex_w_mask[1]; + state->tex_h_mask[1] = params->tex_h_mask[1]; + state->tex_shift[1] = params->tex_shift[1]; + state->tex_lod[1] = params->tex_lod[1]; + + if ((params->fbzMode & 1) && (ystart < params->clipLowY)) + { + int dy = params->clipLowY - ystart; + + state->base_r += params->dRdY*dy; + state->base_g += params->dGdY*dy; + state->base_b += params->dBdY*dy; + state->base_a += params->dAdY*dy; + state->base_z += params->dZdY*dy; + state->tmu[0].base_s += params->tmu[0].dSdY*dy; + state->tmu[0].base_t += params->tmu[0].dTdY*dy; + state->tmu[0].base_w += params->tmu[0].dWdY*dy; + state->tmu[1].base_s += params->tmu[1].dSdY*dy; + state->tmu[1].base_t += params->tmu[1].dTdY*dy; + state->tmu[1].base_w += params->tmu[1].dWdY*dy; + state->base_w += params->dWdY*dy; + state->xstart += state->dx1*dy; + state->xend += state->dx2*dy; + + ystart = params->clipLowY; + } + + if ((params->fbzMode & 1) && (yend >= params->clipHighY)) + yend = params->clipHighY; + + state->y = ystart; +// yend--; + + if (SLI_ENABLED) + { + int test_y; + + if (params->fbzMode & (1 << 17)) + test_y = y_origin - state->y; + else + test_y = state->y; + + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (test_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(test_y & 1))) + { + state->y++; + + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + } +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); + else + voodoo_draw = NULL; +#endif + + voodoo_render_log("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); +// voodoo_render_log("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); + + for (; state->y < yend; state->y += y_diff) + { + int x, x2; + int real_y = (state->y << 4) + 8; + int start_x; + int dx; + uint16_t *fb_mem, *aux_mem; + + state->ir = state->base_r; + state->ig = state->base_g; + state->ib = state->base_b; + state->ia = state->base_a; + state->z = state->base_z; + state->tmu0_s = state->tmu[0].base_s; + state->tmu0_t = state->tmu[0].base_t; + state->tmu0_w = state->tmu[0].base_w; + state->tmu1_s = state->tmu[1].base_s; + state->tmu1_t = state->tmu[1].base_t; + state->tmu1_w = state->tmu[1].base_w; + state->w = state->base_w; + + x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4); + + if (real_y < state->vertexBy) + x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4); + else + x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4); + + if (params->fbzMode & (1 << 17)) + real_y = y_origin - (real_y >> 4); + else + real_y >>= 4; + + if (SLI_ENABLED) + { + if (((real_y >> 1) & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + else + { + if ((real_y & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + + start_x = x; + + if (state->xdir > 0) + x2 -= (1 << 16); + else + x -= (1 << 16); + dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); + x = (x + 0x7000) >> 16; + x2 = (x2 + 0x7000) >> 16; + + voodoo_render_log("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t); + + state->ir += (params->dRdX * dx); + state->ig += (params->dGdX * dx); + state->ib += (params->dBdX * dx); + state->ia += (params->dAdX * dx); + state->z += (params->dZdX * dx); + state->tmu0_s += (params->tmu[0].dSdX * dx); + state->tmu0_t += (params->tmu[0].dTdX * dx); + state->tmu0_w += (params->tmu[0].dWdX * dx); + state->tmu1_s += (params->tmu[1].dSdX * dx); + state->tmu1_t += (params->tmu[1].dTdX * dx); + state->tmu1_w += (params->tmu[1].dWdX * dx); + state->w += (params->dWdX * dx); + + voodoo_render_log("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << (17+state->lod))) >> (18+state->lod)); + + if (params->fbzMode & 1) + { + if (state->xdir > 0) + { + if (x < params->clipLeft) + { + int dx = params->clipLeft - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipLeft; + } + if (x2 >= params->clipRight) + x2 = params->clipRight-1; + } + else + { + if (x >= params->clipRight) + { + int dx = (params->clipRight-1) - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipRight-1; + } + if (x2 < params->clipLeft) + x2 = params->clipLeft; + } + } + + if (x2 < x && state->xdir > 0) + goto next_line; + if (x2 > x && state->xdir < 0) + goto next_line; + + if (SLI_ENABLED) + { + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + ((real_y >> 1) * params->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + ((real_y >> 1) * params->row_width)) & voodoo->fb_mask]; + } + else + { + if (params->col_tiled) + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y >> 5) * params->row_width + (real_y & 31) * 128]; + else + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * params->row_width)]; + if (params->aux_tiled) + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y >> 5) * params->aux_row_width + (real_y & 31) * 128) & voodoo->fb_mask]; + else + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * params->row_width)) & voodoo->fb_mask]; + } + + voodoo_render_log("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x\n", state->y, x, x2, state->xstart, state->xend, dx); + + state->pixel_count = 0; + state->texel_count = 0; + state->x = x; + state->x2 = x2; +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + { + voodoo_draw(state, params, x, real_y); + } + else +#endif + do + { + int x_tiled = (x & 63) | ((x >> 6) * 128*32/2); + start_x = x; + state->x = x; + voodoo->pixel_count[odd_even]++; + voodoo->texel_count[odd_even] += texels; + voodoo->fbiPixelsIn++; + + voodoo_render_log(" X=%03i T=%08x\n", x, state->tmu0_t); +// if (voodoo->fbzMode & FBZ_RGB_WMASK) + { + int update = 1; + uint8_t cother_r = 0, cother_g = 0, cother_b = 0, aother; + uint8_t clocal_r, clocal_g, clocal_b, alocal; + int src_r = 0, src_g = 0, src_b = 0, src_a = 0; + int msel_r, msel_g, msel_b, msel_a; + uint8_t dest_r, dest_g, dest_b, dest_a; + uint16_t dat; + int sel; + int32_t new_depth, w_depth; + + if (state->w & 0xffff00000000) + w_depth = 0; + else if (!(state->w & 0xffff0000)) + w_depth = 0xf001; + else + { + int exp = voodoo_fls((uint16_t)((uint32_t)state->w >> 16)); + int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; + w_depth = (exp << 12) + mant + 1; + if (w_depth > 0xffff) + w_depth = 0xffff; + } + +// w_depth = CLAMP16(w_depth); + + if (params->fbzMode & FBZ_W_BUFFER) + new_depth = w_depth; + else + new_depth = CLAMP16(state->z >> 12); + + if (params->fbzMode & FBZ_DEPTH_BIAS) + new_depth = CLAMP16(new_depth + (int16_t)params->zaColor); + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = voodoo->params.aux_tiled ? aux_mem[x_tiled] : aux_mem[x]; + + DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth); + } + + dat = voodoo->params.col_tiled ? fb_mem[x_tiled] : fb_mem[x]; + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + voodoo_tmu_fetch(voodoo, params, state, 0, x); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + state->tex_r[0] = state->tex_r[1]; + state->tex_g[0] = state->tex_g[1]; + state->tex_b[0] = state->tex_b[1]; + state->tex_a[0] = state->tex_a[1]; + } + else + { + voodoo_tmu_fetch_and_blend(voodoo, params, state, x); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + state->tex_r[0] == params->chromaKey_r && + state->tex_g[0] == params->chromaKey_g && + state->tex_b[0] == params->chromaKey_b) + { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + state->tex_r[0] = state->tex_g[0] = 0; + state->tex_b[0] = voodoo->tmuConfig; + } + + if (cc_localselect_override) + sel = (state->tex_a[0] & 0x80) ? 1 : 0; + else + sel = cc_localselect; + + if (sel) + { + clocal_r = (params->color0 >> 16) & 0xff; + clocal_g = (params->color0 >> 8) & 0xff; + clocal_b = params->color0 & 0xff; + } + else + { + clocal_r = CLAMP(state->ir >> 12); + clocal_g = CLAMP(state->ig >> 12); + clocal_b = CLAMP(state->ib >> 12); + } + + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/ + cother_r = CLAMP(state->ir >> 12); + cother_g = CLAMP(state->ig >> 12); + cother_b = CLAMP(state->ib >> 12); + break; + + case CC_LOCALSELECT_TEX: /*TREX Color Output*/ + cother_r = state->tex_r[0]; + cother_g = state->tex_g[0]; + cother_b = state->tex_b[0]; + break; + + case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/ + cother_r = (params->color1 >> 16) & 0xff; + cother_g = (params->color1 >> 8) & 0xff; + cother_b = params->color1 & 0xff; + break; + + case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/ + cother_r = src_r; + cother_g = src_g; + cother_b = src_b; + break; + } + + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + alocal = CLAMP(state->ia >> 12); + break; + + case CCA_LOCALSELECT_COLOR0: + alocal = (params->color0 >> 24) & 0xff; + break; + + case CCA_LOCALSELECT_ITER_Z: + alocal = CLAMP(state->z >> 20); + break; + + default: + fatal("Bad cca_localselect %i\n", cca_localselect); + alocal = 0xff; + break; + } + + switch (a_sel) + { + case A_SEL_ITER_A: + aother = CLAMP(state->ia >> 12); + break; + case A_SEL_TEX: + aother = state->tex_a[0]; + break; + case A_SEL_COLOR1: + aother = (params->color1 >> 24) & 0xff; + break; + default: + fatal("Bad a_sel %i\n", a_sel); + aother = 0; + break; + } + + if (cc_zero_other) + { + src_r = 0; + src_g = 0; + src_b = 0; + } + else + { + src_r = cother_r; + src_g = cother_g; + src_b = cother_b; + } + + if (cca_zero_other) + src_a = 0; + else + src_a = aother; + + if (cc_sub_clocal) + { + src_r -= clocal_r; + src_g -= clocal_g; + src_b -= clocal_b; + } + + if (cca_sub_clocal) + src_a -= alocal; + + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + case CC_MSELECT_CLOCAL: + msel_r = clocal_r; + msel_g = clocal_g; + msel_b = clocal_b; + break; + case CC_MSELECT_AOTHER: + msel_r = aother; + msel_g = aother; + msel_b = aother; + break; + case CC_MSELECT_ALOCAL: + msel_r = alocal; + msel_g = alocal; + msel_b = alocal; + break; + case CC_MSELECT_TEX: + msel_r = state->tex_a[0]; + msel_g = state->tex_a[0]; + msel_b = state->tex_a[0]; + break; + case CC_MSELECT_TEXRGB: + msel_r = state->tex_r[0]; + msel_g = state->tex_g[0]; + msel_b = state->tex_b[0]; + break; + + default: + fatal("Bad cc_mselect %i\n", cc_mselect); + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + } + + switch (cca_mselect) + { + case CCA_MSELECT_ZERO: + msel_a = 0; + break; + case CCA_MSELECT_ALOCAL: + msel_a = alocal; + break; + case CCA_MSELECT_AOTHER: + msel_a = aother; + break; + case CCA_MSELECT_ALOCAL2: + msel_a = alocal; + break; + case CCA_MSELECT_TEX: + msel_a = state->tex_a[0]; + break; + + default: + fatal("Bad cca_mselect %i\n", cca_mselect); + msel_a = 0; + break; + } + + if (!cc_reverse_blend) + { + msel_r ^= 0xff; + msel_g ^= 0xff; + msel_b ^= 0xff; + } + msel_r++; + msel_g++; + msel_b++; + + if (!cca_reverse_blend) + msel_a ^= 0xff; + msel_a++; + + src_r = (src_r * msel_r) >> 8; + src_g = (src_g * msel_g) >> 8; + src_b = (src_b * msel_b) >> 8; + src_a = (src_a * msel_a) >> 8; + + switch (cc_add) + { + case CC_ADD_CLOCAL: + src_r += clocal_r; + src_g += clocal_g; + src_b += clocal_b; + break; + case CC_ADD_ALOCAL: + src_r += alocal; + src_g += alocal; + src_b += alocal; + break; + case 0: + break; + default: + fatal("Bad cc_add %i\n", cc_add); + } + + if (cca_add) + src_a += alocal; + + src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b); + src_a = CLAMP(src_a); + + if (cc_invert_output) + { + src_r ^= 0xff; + src_g ^= 0xff; + src_b ^= 0xff; + } + if (cca_invert_output) + src_a ^= 0xff; + + if (params->fogMode & FOG_ENABLE) + APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w); + + if (params->alphaMode & 1) + ALPHA_TEST(src_a); + + if (params->alphaMode & (1 << 4)) { + if (dithersub && !dither2x2 && voodoo->dithersub_enabled) + { + dest_r = dithersub_rb[dest_r][real_y & 3][x & 3]; + dest_g = dithersub_g [dest_g][real_y & 3][x & 3]; + dest_b = dithersub_rb[dest_b][real_y & 3][x & 3]; + } + if (dithersub && dither2x2 && voodoo->dithersub_enabled) + { + dest_r = dithersub_rb2x2[dest_r][real_y & 1][x & 1]; + dest_g = dithersub_g2x2 [dest_g][real_y & 1][x & 1]; + dest_b = dithersub_rb2x2[dest_b][real_y & 1][x & 1]; + } + ALPHA_BLEND(src_r, src_g, src_b, src_a); + } + + if (update) + { + if (dither) + { + if (dither2x2) + { + src_r = dither_rb2x2[src_r][real_y & 1][x & 1]; + src_g = dither_g2x2[src_g][real_y & 1][x & 1]; + src_b = dither_rb2x2[src_b][real_y & 1][x & 1]; + } + else + { + src_r = dither_rb[src_r][real_y & 3][x & 3]; + src_g = dither_g[src_g][real_y & 3][x & 3]; + src_b = dither_rb[src_b][real_y & 3][x & 3]; + } + } + else + { + src_r >>= 3; + src_g >>= 2; + src_b >>= 3; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + { + if (voodoo->params.col_tiled) + fb_mem[x_tiled] = src_b | (src_g << 5) | (src_r << 11); + else + fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); + } + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + { + if (voodoo->params.aux_tiled) + aux_mem[x_tiled] = new_depth; + else + aux_mem[x] = new_depth; + } + } + } + voodoo->fbiPixelsOut++; +skip_pixel: + if (state->xdir > 0) + { + state->ir += params->dRdX; + state->ig += params->dGdX; + state->ib += params->dBdX; + state->ia += params->dAdX; + state->z += params->dZdX; + state->tmu0_s += params->tmu[0].dSdX; + state->tmu0_t += params->tmu[0].dTdX; + state->tmu0_w += params->tmu[0].dWdX; + state->tmu1_s += params->tmu[1].dSdX; + state->tmu1_t += params->tmu[1].dTdX; + state->tmu1_w += params->tmu[1].dWdX; + state->w += params->dWdX; + } + else + { + state->ir -= params->dRdX; + state->ig -= params->dGdX; + state->ib -= params->dBdX; + state->ia -= params->dAdX; + state->z -= params->dZdX; + state->tmu0_s -= params->tmu[0].dSdX; + state->tmu0_t -= params->tmu[0].dTdX; + state->tmu0_w -= params->tmu[0].dWdX; + state->tmu1_s -= params->tmu[1].dSdX; + state->tmu1_t -= params->tmu[1].dTdX; + state->tmu1_w -= params->tmu[1].dWdX; + state->w -= params->dWdX; + } + + x += state->xdir; + } while (start_x != x2); + + voodoo->pixel_count[odd_even] += state->pixel_count; + voodoo->texel_count[odd_even] += state->texel_count; + voodoo->fbiPixelsIn += state->pixel_count; + + if (voodoo->params.draw_offset == voodoo->params.front_offset && (real_y >> 1) < 2048) + voodoo->dirty_line[real_y >> 1] = 1; + +next_line: + if (SLI_ENABLED) + { + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + + voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++; + voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++; +} + +void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) +{ + voodoo_state_t state; + int vertexAy_adjusted; + int vertexCy_adjusted; + int dx, dy; + + uint64_t tempdx, tempdy; + uint64_t tempLOD; + int LOD; + int lodbias; + + voodoo->tri_count++; + + dx = 8 - (params->vertexAx & 0xf); + if ((params->vertexAx & 0xf) > 8) + dx += 16; + dy = 8 - (params->vertexAy & 0xf); + if ((params->vertexAy & 0xf) > 8) + dy += 16; + +/* voodoo_render_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, + (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, + (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ + + state.base_r = params->startR; + state.base_g = params->startG; + state.base_b = params->startB; + state.base_a = params->startA; + state.base_z = params->startZ; + state.tmu[0].base_s = params->tmu[0].startS; + state.tmu[0].base_t = params->tmu[0].startT; + state.tmu[0].base_w = params->tmu[0].startW; + state.tmu[1].base_s = params->tmu[1].startS; + state.tmu[1].base_t = params->tmu[1].startT; + state.tmu[1].base_w = params->tmu[1].startW; + state.base_w = params->startW; + + if (params->fbzColorPath & FBZ_PARAM_ADJUST) + { + state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4; + state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4; + state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4; + state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4; + state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4; + state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4; + state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4; + state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4; + state.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4; + state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4; + state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].dWdY) >> 4; + state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4; + } + + tris++; + + state.vertexAy = params->vertexAy & ~0xffff0000; + if (state.vertexAy & 0x8000) + state.vertexAy |= 0xffff0000; + state.vertexBy = params->vertexBy & ~0xffff0000; + if (state.vertexBy & 0x8000) + state.vertexBy |= 0xffff0000; + state.vertexCy = params->vertexCy & ~0xffff0000; + if (state.vertexCy & 0x8000) + state.vertexCy |= 0xffff0000; + + state.vertexAx = params->vertexAx & ~0xffff0000; + if (state.vertexAx & 0x8000) + state.vertexAx |= 0xffff0000; + state.vertexBx = params->vertexBx & ~0xffff0000; + if (state.vertexBx & 0x8000) + state.vertexBx |= 0xffff0000; + state.vertexCx = params->vertexCx & ~0xffff0000; + if (state.vertexCx & 0x8000) + state.vertexCx |= 0xffff0000; + + vertexAy_adjusted = (state.vertexAy+7) >> 4; + vertexCy_adjusted = (state.vertexCy+7) >> 4; + + if (state.vertexBy - state.vertexAy) + state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy); + else + state.dxAB = 0; + if (state.vertexCy - state.vertexAy) + state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy); + else + state.dxAC = 0; + if (state.vertexCy - state.vertexBy) + state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy); + else + state.dxBC = 0; + + state.lod_min[0] = (params->tLOD[0] & 0x3f) << 6; + state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6; + if (state.lod_max[0] > 0x800) + state.lod_max[0] = 0x800; + state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6; + state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6; + if (state.lod_max[1] > 0x800) + state.lod_max[1] = 0x800; + + state.xstart = state.xend = state.vertexAx << 8; + state.xdir = params->sign ? -1 : 1; + + state.y = (state.vertexAy + 8) >> 4; + state.ydir = 1; + + + tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14); + tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[0] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[0].lod = LOD + (lodbias << 6); + + + tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14); + tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[1] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[1].lod = LOD + (lodbias << 6); + + + voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); +} + + +static void render_thread(void *param, int odd_even) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (voodoo->render_thread_run[odd_even]) + { + thread_set_event(voodoo->render_not_full_event[odd_even]); + thread_wait_event(voodoo->wake_render_thread[odd_even], -1); + thread_reset_event(voodoo->wake_render_thread[odd_even]); + voodoo->render_voodoo_busy[odd_even] = 1; + + while (!PARAM_EMPTY(odd_even)) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK]; + + voodoo_triangle(voodoo, params, odd_even); + + voodoo->params_read_idx[odd_even]++; + + if (PARAM_ENTRIES(odd_even) > (PARAM_SIZE - 10)) + thread_set_event(voodoo->render_not_full_event[odd_even]); + + end_time = plat_timer_read(); + voodoo->render_time[odd_even] += end_time - start_time; + } + + voodoo->render_voodoo_busy[odd_even] = 0; + } +} + +void voodoo_render_thread_1(void *param) +{ + render_thread(param, 0); +} +void voodoo_render_thread_2(void *param) +{ + render_thread(param, 1); +} +void voodoo_render_thread_3(void *param) +{ + render_thread(param, 2); +} +void voodoo_render_thread_4(void *param) +{ + render_thread(param, 3); +} + +void voodoo_queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) +{ + voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK]; + + while (PARAM_FULL(0) || (voodoo->render_threads >= 2 && PARAM_FULL(1)) || + (voodoo->render_threads == 4 && (PARAM_FULL(2) || PARAM_FULL(3)))) + { + thread_reset_event(voodoo->render_not_full_event[0]); + if (voodoo->render_threads >= 2) + thread_reset_event(voodoo->render_not_full_event[1]); + if (voodoo->render_threads == 4) + { + thread_reset_event(voodoo->render_not_full_event[2]); + thread_reset_event(voodoo->render_not_full_event[3]); + } + if (PARAM_FULL(0)) + thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ + if (voodoo->render_threads >= 2 && PARAM_FULL(1)) + thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ + if (voodoo->render_threads == 4 && PARAM_FULL(2)) + thread_wait_event(voodoo->render_not_full_event[2], -1); /*Wait for room in ringbuffer*/ + if (voodoo->render_threads == 4 && PARAM_FULL(3)) + thread_wait_event(voodoo->render_not_full_event[3], -1); /*Wait for room in ringbuffer*/ + } + + voodoo_use_texture(voodoo, params, 0); + if (voodoo->dual_tmus) + voodoo_use_texture(voodoo, params, 1); + + memcpy(params_new, params, sizeof(voodoo_params_t)); + + voodoo->params_write_idx++; + + if (PARAM_ENTRIES(0) < 4 || (voodoo->render_threads >= 2 && PARAM_ENTRIES(1) < 4) || + (voodoo->render_threads == 4 && (PARAM_ENTRIES(2) < 4 || PARAM_ENTRIES(3) < 4))) + voodoo_wake_render_thread(voodoo); +} diff --git a/src/video/vid_voodoo_setup.c b/src/video/vid_voodoo_setup.c new file mode 100644 index 000000000..92a984c87 --- /dev/null +++ b/src/video/vid_voodoo_setup.c @@ -0,0 +1,261 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_setup.h> + +#ifdef ENABLE_VOODOO_SETUP_LOG +int voodoo_setup_do_log = ENABLE_VOODOO_SETUP_LOG; + +static void +voodoo_setup_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_setup_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_setup_log(fmt, ...) +#endif + + +void voodoo_triangle_setup(voodoo_t *voodoo) +{ + float dxAB, dxBC, dyAB, dyBC; + float area; + int va = 0, vb = 1, vc = 2; + vert_t verts[3]; + + verts[0] = voodoo->verts[0]; + verts[1] = voodoo->verts[1]; + verts[2] = voodoo->verts[2]; + + if (verts[0].sVy < verts[1].sVy) + { + if (verts[1].sVy < verts[2].sVy) + { + /* V1>V0, V2>V1, V2>V1>V0*/ + va = 0; /*OK*/ + vb = 1; + vc = 2; + } + else + { + /* V1>V0, V1>V2*/ + if (verts[0].sVy < verts[2].sVy) + { + /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ + va = 0; + vb = 2; + vc = 1; + } + else + { + /* V1>V0, V1>V2, V0>V2, V1>V0>V2*/ + va = 2; + vb = 0; + vc = 1; + } + } + } + else + { + if (verts[1].sVy < verts[2].sVy) + { + /* V0>V1, V2>V1*/ + if (verts[0].sVy < verts[2].sVy) + { + /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ + va = 1; + vb = 0; + vc = 2; + } + else + { + /* V0>V1, V2>V1, V0>V2, V0>V2>V1*/ + va = 1; + vb = 2; + vc = 0; + } + } + else + { + /*V0>V1>V2*/ + va = 2; + vb = 1; + vc = 0; + } + } + + dxAB = verts[0].sVx - verts[1].sVx; + dxBC = verts[1].sVx - verts[2].sVx; + dyAB = verts[0].sVy - verts[1].sVy; + dyBC = verts[1].sVy - verts[2].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + if (area == 0.0) + return; + + if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) + { + int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; + int sign = (area < 0.0); + + if ((voodoo->sSetupMode & (SETUPMODE_CULLING_ENABLE | SETUPMODE_DISABLE_PINGPONG)) + == SETUPMODE_CULLING_ENABLE && voodoo->cull_pingpong) + cull_sign = !cull_sign; + + if (cull_sign && sign) + return; + if (!cull_sign && !sign) + return; + } + + + dxAB = verts[va].sVx - verts[vb].sVx; + dxBC = verts[vb].sVx - verts[vc].sVx; + dyAB = verts[va].sVy - verts[vb].sVy; + dyBC = verts[vb].sVy - verts[vc].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + dxAB /= area; + dxBC /= area; + dyAB /= area; + dyBC /= area; + + + + voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(verts[va].sVx * 16.0f) & 0xffff); + voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(verts[va].sVy * 16.0f) & 0xffff); + voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(verts[vb].sVx * 16.0f) & 0xffff); + voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(verts[vb].sVy * 16.0f) & 0xffff); + voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff); + voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff); + + if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) { + voodoo_setup_log("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); + return; + } + + if (voodoo->sSetupMode & SETUPMODE_RGB) + { + voodoo->params.startR = (int32_t)(verts[va].sRed * 4096.0f); + voodoo->params.dRdX = (int32_t)(((verts[va].sRed - verts[vb].sRed) * dyBC - (verts[vb].sRed - verts[vc].sRed) * dyAB) * 4096.0f); + voodoo->params.dRdY = (int32_t)(((verts[vb].sRed - verts[vc].sRed) * dxAB - (verts[va].sRed - verts[vb].sRed) * dxBC) * 4096.0f); + voodoo->params.startG = (int32_t)(verts[va].sGreen * 4096.0f); + voodoo->params.dGdX = (int32_t)(((verts[va].sGreen - verts[vb].sGreen) * dyBC - (verts[vb].sGreen - verts[vc].sGreen) * dyAB) * 4096.0f); + voodoo->params.dGdY = (int32_t)(((verts[vb].sGreen - verts[vc].sGreen) * dxAB - (verts[va].sGreen - verts[vb].sGreen) * dxBC) * 4096.0f); + voodoo->params.startB = (int32_t)(verts[va].sBlue * 4096.0f); + voodoo->params.dBdX = (int32_t)(((verts[va].sBlue - verts[vb].sBlue) * dyBC - (verts[vb].sBlue - verts[vc].sBlue) * dyAB) * 4096.0f); + voodoo->params.dBdY = (int32_t)(((verts[vb].sBlue - verts[vc].sBlue) * dxAB - (verts[va].sBlue - verts[vb].sBlue) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_ALPHA) + { + voodoo->params.startA = (int32_t)(verts[va].sAlpha * 4096.0f); + voodoo->params.dAdX = (int32_t)(((verts[va].sAlpha - verts[vb].sAlpha) * dyBC - (verts[vb].sAlpha - verts[vc].sAlpha) * dyAB) * 4096.0f); + voodoo->params.dAdY = (int32_t)(((verts[vb].sAlpha - verts[vc].sAlpha) * dxAB - (verts[va].sAlpha - verts[vb].sAlpha) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Z) + { + voodoo->params.startZ = (int32_t)(verts[va].sVz * 4096.0f); + voodoo->params.dZdX = (int32_t)(((verts[va].sVz - verts[vb].sVz) * dyBC - (verts[vb].sVz - verts[vc].sVz) * dyAB) * 4096.0f); + voodoo->params.dZdY = (int32_t)(((verts[vb].sVz - verts[vc].sVz) * dxAB - (verts[va].sVz - verts[vb].sVz) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Wb) + { + voodoo->params.startW = (int64_t)(verts[va].sWb * 4294967296.0f); + voodoo->params.dWdX = (int64_t)(((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f); + voodoo->params.dWdY = (int64_t)(((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; + voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; + voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_W0) + { + voodoo->params.tmu[0].startW = (int64_t)(verts[va].sW0 * 4294967296.0f); + voodoo->params.tmu[0].dWdX = (int64_t)(((verts[va].sW0 - verts[vb].sW0) * dyBC - (verts[vb].sW0 - verts[vc].sW0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dWdY = (int64_t)(((verts[vb].sW0 - verts[vc].sW0) * dxAB - (verts[va].sW0 - verts[vb].sW0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; + voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; + voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_S0_T0) + { + voodoo->params.tmu[0].startS = (int64_t)(verts[va].sS0 * 4294967296.0f); + voodoo->params.tmu[0].dSdX = (int64_t)(((verts[va].sS0 - verts[vb].sS0) * dyBC - (verts[vb].sS0 - verts[vc].sS0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dSdY = (int64_t)(((verts[vb].sS0 - verts[vc].sS0) * dxAB - (verts[va].sS0 - verts[vb].sS0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startT = (int64_t)(verts[va].sT0 * 4294967296.0f); + voodoo->params.tmu[0].dTdX = (int64_t)(((verts[va].sT0 - verts[vb].sT0) * dyBC - (verts[vb].sT0 - verts[vc].sT0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dTdY = (int64_t)(((verts[vb].sT0 - verts[vc].sT0) * dxAB - (verts[va].sT0 - verts[vb].sT0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; + voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; + voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; + voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT; + voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX; + voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY; + } + if (voodoo->sSetupMode & SETUPMODE_W1) + { + voodoo->params.tmu[1].startW = (int64_t)(verts[va].sW1 * 4294967296.0f); + voodoo->params.tmu[1].dWdX = (int64_t)(((verts[va].sW1 - verts[vb].sW1) * dyBC - (verts[vb].sW1 - verts[vc].sW1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dWdY = (int64_t)(((verts[vb].sW1 - verts[vc].sW1) * dxAB - (verts[va].sW1 - verts[vb].sW1) * dxBC) * 4294967296.0f); + } + if (voodoo->sSetupMode & SETUPMODE_S1_T1) + { + voodoo->params.tmu[1].startS = (int64_t)(verts[va].sS1 * 4294967296.0f); + voodoo->params.tmu[1].dSdX = (int64_t)(((verts[va].sS1 - verts[vb].sS1) * dyBC - (verts[vb].sS1 - verts[vc].sS1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dSdY = (int64_t)(((verts[vb].sS1 - verts[vc].sS1) * dxAB - (verts[va].sS1 - verts[vb].sS1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startT = (int64_t)(verts[va].sT1 * 4294967296.0f); + voodoo->params.tmu[1].dTdX = (int64_t)(((verts[va].sT1 - verts[vb].sT1) * dyBC - (verts[vb].sT1 - verts[vc].sT1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dTdY = (int64_t)(((verts[vb].sT1 - verts[vc].sT1) * dxAB - (verts[va].sT1 - verts[vb].sT1) * dxBC) * 4294967296.0f); + } + + voodoo->params.sign = (area < 0.0); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + voodoo_queue_triangle(voodoo, &voodoo->params); +} diff --git a/src/video/vid_voodoo_texture.c b/src/video/vid_voodoo_texture.c new file mode 100644 index 000000000..784ea17fe --- /dev/null +++ b/src/video/vid_voodoo_texture.c @@ -0,0 +1,628 @@ +/* + * 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. + * + * 3DFX Voodoo emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_dither.h> +#include <86box/vid_voodoo_regs.h> +#include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_texture.h> + + +#ifdef ENABLE_VOODOO_TEXTURE_LOG +int voodoo_texture_do_log = ENABLE_VOODOO_TEXTURE_LOG; + +static void +voodoo_texture_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_texture_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_texture_log(fmt, ...) +#endif + + +void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) +{ + int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; + int width = 256, height = 256; + int shift = 8; + int lod; + uint32_t base = voodoo->params.texBaseAddr[tmu]; + uint32_t offset = 0; + int tex_lod = 0; + uint32_t offsets[LOD_MAX+3]; + int widths[LOD_MAX+3], heights[LOD_MAX+3], shifts[LOD_MAX+3]; + + if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER) + height >>= aspect; + else + { + width >>= aspect; + shift -= aspect; + } + + for (lod = 0; lod <= LOD_MAX + 2; lod++) + { + offsets[lod] = offset; + widths[lod] = width >> lod; + heights[lod] = height >> lod; + shifts[lod] = shift - lod; + + if (!widths[lod]) + widths[lod] = 1; + if (!heights[lod]) + heights[lod] = 1; + if (shifts[lod] < 0) + shifts[lod] = 0; + + if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) || + ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || + (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) + { + if (voodoo->params.tformat[tmu] & 8) + offset += (width >> lod) * (height >> lod) * 2; + else + offset += (width >> lod) * (height >> lod); + } + } + + + if ((voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) && (voodoo->params.tLOD[tmu] & LOD_ODD)) + tex_lod++; /*Skip LOD 0*/ + +// voodoo_texture_log("TMU %i: %08x\n", tmu, voodoo->params.textureMode[tmu]); + for (lod = 0; lod <= LOD_MAX+1; lod++) + { + if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) + { + switch (tex_lod) + { + case 0: + base = voodoo->params.texBaseAddr[tmu]; + break; + case 1: + base = voodoo->params.texBaseAddr1[tmu]; + break; + case 2: + base = voodoo->params.texBaseAddr2[tmu]; + break; + default: + base = voodoo->params.texBaseAddr38[tmu]; + break; + } + } + + voodoo->params.tex_base[tmu][lod] = base + offsets[tex_lod]; + if (voodoo->params.tformat[tmu] & 8) + voodoo->params.tex_end[tmu][lod] = base + offsets[tex_lod] + (widths[tex_lod] * heights[tex_lod] * 2); + else + voodoo->params.tex_end[tmu][lod] = base + offsets[tex_lod] + (widths[tex_lod] * heights[tex_lod]); + voodoo->params.tex_w_mask[tmu][lod] = widths[tex_lod] - 1; + voodoo->params.tex_w_nmask[tmu][lod] = ~(widths[tex_lod] - 1); + voodoo->params.tex_h_mask[tmu][lod] = heights[tex_lod] - 1; + voodoo->params.tex_shift[tmu][lod] = shifts[tex_lod]; + voodoo->params.tex_lod[tmu][lod] = tex_lod; + + if (!(voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) || + ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || + (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) + { + if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0) + { + if (voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) + tex_lod += 2; + else + tex_lod++; + } + } + } + + voodoo->params.tex_width[tmu] = width; +} + +#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24)) + +void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) +{ + int c, d; + int lod; + int lod_min, lod_max; + uint32_t addr = 0, addr_end; + uint32_t palette_checksum; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + { + if (voodoo->palette_dirty[tmu]) + { + palette_checksum = 0; + + for (c = 0; c < 256; c++) + palette_checksum ^= voodoo->palette[tmu][c].u; + + voodoo->palette_checksum[tmu] = palette_checksum; + voodoo->palette_dirty[tmu] = 0; + } + else + palette_checksum = voodoo->palette_checksum[tmu]; + } + else + palette_checksum = 0; + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + addr = params->texBaseAddr1[tmu]; + else + addr = params->texBaseAddr[tmu]; + + /*Try to find texture in cache*/ + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base == addr && + voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) && + voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum) + { + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; + return; + } + } + + /*Texture not found, search for unused texture*/ + do + { + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_last_removed++; + voodoo->texture_last_removed &= (TEX_CACHE_MAX-1); + if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] && + (voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1])) + break; + } + if (c == TEX_CACHE_MAX) + voodoo_wait_for_render_thread_idle(voodoo); + } while (c == TEX_CACHE_MAX); + if (c == TEX_CACHE_MAX) + fatal("Texture cache full!\n"); + + c = voodoo->texture_last_removed; + + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + voodoo->texture_cache[tmu][c].base = params->texBaseAddr1[tmu]; + else + voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu]; + voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; +// voodoo_texture_log(" add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max, tmu); + lod_min = MIN(lod_min, 8); + lod_max = MIN(lod_max, 8); + for (lod = lod_min; lod <= lod_max; lod++) + { + uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]]; + uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask; + int x, y; + int shift = 8 - params->tex_lod[tmu][lod]; + rgba_u *pal; + + //voodoo_texture_log(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]); + + + switch (params->tformat[tmu]) + { + case TEX_RGB332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_A8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, dat); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_AI8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f)); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_PAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_APAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3); + int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2); + int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4); + int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6); + + base[x] = makergba(r, g, b, a); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_ARGB8332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_R5G6B5: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB1555: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB4444: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_APAL88: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + default: + fatal("Unknown texture format %i\n", params->tformat[tmu]); + } + } + + voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum; + else + voodoo->texture_cache[tmu][c].palette_checksum = 0; + + if (lod_min == 0) + { + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->params.tex_base[tmu][0]; + voodoo->texture_cache[tmu][c].addr_end[0] = voodoo->params.tex_end[tmu][0]; + } + else + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->texture_cache[tmu][c].addr_end[0] = 0; + + if (lod_min <= 1 && lod_max >= 1) + { + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->params.tex_base[tmu][1]; + voodoo->texture_cache[tmu][c].addr_end[1] = voodoo->params.tex_end[tmu][1]; + } + else + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->texture_cache[tmu][c].addr_end[1] = 0; + + if (lod_min <= 2 && lod_max >= 2) + { + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->params.tex_base[tmu][2]; + voodoo->texture_cache[tmu][c].addr_end[2] = voodoo->params.tex_end[tmu][2]; + } + else + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->texture_cache[tmu][c].addr_end[2] = 0; + + if (lod_max >= 3) + { + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->params.tex_base[tmu][(lod_min > 3) ? lod_min : 3]; + voodoo->texture_cache[tmu][c].addr_end[3] = voodoo->params.tex_end[tmu][(lod_max < 8) ? lod_max : 8]; + } + else + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->texture_cache[tmu][c].addr_end[3] = 0; + + + for (d = 0; d < 4; d++) + { + addr = voodoo->texture_cache[tmu][c].addr_start[d]; + addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; +} + +void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) +{ + int wait_for_idle = 0; + int c; + + memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0])); +// voodoo_texture_log("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present)); + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base != -1) + { + int d; + + for (d = 0; d < 4; d++) + { + int addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; + int addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; + int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; + + if (addr_end_masked < addr_start_masked) + addr_end_masked = voodoo->texture_mask+1; + if (dirty_addr >= addr_start_masked && dirty_addr < addr_end_masked) + { +// voodoo_texture_log(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base); + + if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] || + (voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1])) + wait_for_idle = 1; + + voodoo->texture_cache[tmu][c].base = -1; + } + else + { + for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + } + } + } + if (wait_for_idle) + voodoo_wait_for_render_thread_idle(voodoo); +} + +void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) +{ + int lod, s, t; + voodoo_t *voodoo = (voodoo_t *)p; + int tmu; + + if (addr & 0x400000) + return; /*TREX != 0*/ + + tmu = (addr & 0x200000) ? 1 : 0; + + if (tmu && !voodoo->dual_tmus) + return; + + if (voodoo->type < VOODOO_BANSHEE) + { + if (!(voodoo->params.tformat[tmu] & 8) && voodoo->type >= VOODOO_BANSHEE) + { + lod = (addr >> 16) & 0xf; + t = (addr >> 8) & 0xff; + } + else + { + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + } + if (voodoo->params.tformat[tmu] & 8) + s = (addr >> 1) & 0xfe; + else + { + if ((voodoo->params.textureMode[tmu] & (1 << 31)) || voodoo->type >= VOODOO_BANSHEE) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat[tmu] & 8) + addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; + else + addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); + } + else + addr = (addr & 0x1ffffc) + voodoo->params.tex_base[tmu][0]; + + if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// voodoo_texture_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); + } + if (voodoo->type == VOODOO_3 && voodoo->texture_present[tmu^1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// voodoo_texture_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu^1); + } + *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; +} diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index b8543a6ab..ef641627b 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -39,16 +39,16 @@ void updatewindowsize(int x, int y); /* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this * is not exposed directly to the host PC. Instead, the CRTC is controlled by - * an MC68705P3 microcontroller. + * an MC68705P3 microcontroller. * - * Rather than emulate the real CRTC, I'm writing this as more or less a + * Rather than emulate the real CRTC, I'm writing this as more or less a * fixed-frequency card with a 1280x800 display, and scaling its selection * of modes to that window. * - * By default, the card responds to both the CGA and MDA I/O and memory + * By default, the card responds to both the CGA and MDA I/O and memory * ranges. Either range can be disabled by means of jumpers; this allows - * the Wy700 to coexist with a CGA or MDA. - * + * the Wy700 to coexist with a CGA or MDA. + * * wy700->wy700_mode indicates which of the supported video modes is in use: * * 0x00: 40x 25 text (CGA compatible) [32x32 character cell] @@ -67,9 +67,9 @@ void updatewindowsize(int x, int y); /* What works (or appears to) : * MDA/CGA 80x25 text mode - * CGA 40x25 text mode - * CGA 640x200 graphics mode - * CGA 320x200 graphics mode + * CGA 40x25 text mode + * CGA 640x200 graphics mode + * CGA 320x200 graphics mode * Hi-res graphics modes * Font selection * Display enable / disable @@ -83,11 +83,11 @@ void updatewindowsize(int x, int y); /* The microcontroller sets up the real CRTC with one of five fixed mode - * definitions. As written, this is a fairly simplistic emulation that - * doesn't attempt to closely follow the actual working of the CRTC; but I've + * definitions. As written, this is a fairly simplistic emulation that + * doesn't attempt to closely follow the actual working of the CRTC; but I've * included the definitions here for information. */ -static uint8_t mode_1280x800[] = +static uint8_t mode_1280x800[] = { 0x31, /* Horizontal total */ 0x28, /* Horizontal displayed */ @@ -101,7 +101,7 @@ static uint8_t mode_1280x800[] = 0x0f, /* Maximum raster address */ }; -static uint8_t mode_1280x400[] = +static uint8_t mode_1280x400[] = { 0x31, /* Horizontal total */ 0x28, /* Horizontal displayed */ @@ -115,7 +115,7 @@ static uint8_t mode_1280x400[] = 0x0f, /* Maximum raster address */ }; -static uint8_t mode_640x400[] = +static uint8_t mode_640x400[] = { 0x18, /* Horizontal total */ 0x14, /* Horizontal displayed */ @@ -129,7 +129,7 @@ static uint8_t mode_640x400[] = 0x0f, /* Maximum raster address */ }; -static uint8_t mode_640x200[] = +static uint8_t mode_640x200[] = { 0x18, /* Horizontal total */ 0x14, /* Horizontal displayed */ @@ -143,7 +143,7 @@ static uint8_t mode_640x200[] = 0x07, /* Maximum raster address */ }; -static uint8_t mode_80x24[] = +static uint8_t mode_80x24[] = { 0x31, /* Horizontal total */ 0x28, /* Horizontal displayed */ @@ -157,7 +157,7 @@ static uint8_t mode_80x24[] = 0x0f, /* Maximum raster address */ }; -static uint8_t mode_40x24[] = +static uint8_t mode_40x24[] = { 0x18, /* Horizontal total */ 0x14, /* Horizontal displayed */ @@ -179,16 +179,16 @@ typedef struct wy700_t { mem_mapping_t mapping; - /* The microcontroller works by watching four ports: - * 0x3D8 / 0x3B8 (mode control register) + /* The microcontroller works by watching four ports: + * 0x3D8 / 0x3B8 (mode control register) * 0x3DD (top scanline address) * 0x3DF (Wy700 control register) * CRTC reg 14 (cursor location high) - * + * * It will do nothing until one of these registers is touched. When * one is, it then reconfigures the internal 6845 based on what it * sees. - */ + */ uint8_t last_03D8; /* Copies of values written to the listed */ uint8_t last_03DD; /* I/O ports */ uint8_t last_03DF; @@ -213,7 +213,7 @@ typedef struct wy700_t uint64_t dispontime, dispofftime; pc_timer_t timer; - + int linepos, displine; int vc; int dispon, blink; @@ -240,7 +240,7 @@ void wy700_out(uint16_t addr, uint8_t val, void *p) wy700_t *wy700 = (wy700_t *)p; switch (addr) { - /* These three registers are only mapped in the 3Dx range, + /* These three registers are only mapped in the 3Dx range, * not the 3Bx range. */ case 0x3DD: /* Base address (low) */ wy700->wy700_base &= 0xFF00; @@ -258,7 +258,7 @@ void wy700_out(uint16_t addr, uint8_t val, void *p) wy700->wy700_control = val; wy700_checkchanges(wy700); break; - + /* Emulated CRTC, register select */ case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: @@ -301,7 +301,7 @@ uint8_t wy700_in(uint16_t addr, void *p) return wy700->cga_ctrl; case 0x3d9: return wy700->cga_colour; - case 0x3ba: + case 0x3ba: return wy700->mda_stat; case 0x3da: return wy700->cga_stat; @@ -310,7 +310,7 @@ uint8_t wy700_in(uint16_t addr, void *p) } -/* Check if any of the four key registers has changed. If so, check for a +/* Check if any of the four key registers has changed. If so, check for a * mode change or cursor size change */ void wy700_checkchanges(wy700_t *wy700) { @@ -336,18 +336,18 @@ void wy700_checkchanges(wy700_t *wy700) wy700->enabled = 1; wy700->detach = 0; break; - + case 2: /* Font 1 */ wy700->font = 0; break; - + case 3: /* Font 2 */ wy700->font = 1; break; - -/* Even with the microprogram from an original card, I can't really work out + +/* Even with the microprogram from an original card, I can't really work out * what commands 4 and 5 (which I've called 'cursor detach' / 'cursor attach') - * do. Command 4 sets a flag in microcontroller RAM, and command 5 clears + * do. Command 4 sets a flag in microcontroller RAM, and command 5 clears * it. When the flag is set, the real cursor doesn't track the cursor in the * emulated CRTC, and its blink rate increases. Possibly it's a self-test * function of some kind. @@ -358,21 +358,21 @@ void wy700_checkchanges(wy700_t *wy700) case 4: /* Detach cursor */ wy700->detach = 1; break; - + case 5: /* Attach cursor */ wy700->detach = 0; break; - + case 6: /* Disable display */ wy700->enabled = 0; break; - + case 7: /* Enable display */ wy700->enabled = 1; break; } /* A control write with the top bit set selects graphics mode */ - if (wy700->wy700_control & 0x80) + if (wy700->wy700_control & 0x80) { /* Select hi-res graphics mode; map framebuffer at A0000 */ mem_mapping_set_addr(&wy700->mapping, 0xa0000, 0x20000); @@ -381,17 +381,17 @@ void wy700_checkchanges(wy700_t *wy700) /* Select appropriate preset timings */ if (wy700->wy700_mode & 0x40) { - memcpy(wy700->real_crtc, mode_1280x800, + memcpy(wy700->real_crtc, mode_1280x800, sizeof(mode_1280x800)); } else if (wy700->wy700_mode & 0x20) { - memcpy(wy700->real_crtc, mode_1280x400, + memcpy(wy700->real_crtc, mode_1280x400, sizeof(mode_1280x400)); } else { - memcpy(wy700->real_crtc, mode_640x400, + memcpy(wy700->real_crtc, mode_640x400, sizeof(mode_640x400)); } } @@ -400,15 +400,15 @@ void wy700_checkchanges(wy700_t *wy700) else if (wy700->last_03D8 != wy700->cga_ctrl) { wy700->last_03D8 = wy700->cga_ctrl; - /* Set lo-res text or graphics mode. - * (Strictly speaking, when not in hi-res mode the card - * should be mapped at B0000-B3FFF and B8000-BBFFF, leaving + /* Set lo-res text or graphics mode. + * (Strictly speaking, when not in hi-res mode the card + * should be mapped at B0000-B3FFF and B8000-BBFFF, leaving * a 16k hole between the two ranges) */ mem_mapping_set_addr(&wy700->mapping, 0xb0000, 0x0C000); if (wy700->cga_ctrl & 2) /* Graphics mode */ { wy700->wy700_mode = (wy700->cga_ctrl & 0x10) ? 6 : 4; - memcpy(wy700->real_crtc, mode_640x200, + memcpy(wy700->real_crtc, mode_640x200, sizeof(mode_640x200)); } else if (wy700->cga_ctrl & 1) /* Text mode 80x24 */ @@ -459,17 +459,16 @@ void wy700_checkchanges(wy700_t *wy700) void wy700_write(uint32_t addr, uint8_t val, void *p) { wy700_t *wy700 = (wy700_t *)p; - egawrites++; if (wy700->wy700_mode & 0x80) /* High-res mode. */ { addr &= 0xFFFF; /* In 800-line modes, bit 1 of the control register sets the high bit of the * write address. */ - if ((wy700->wy700_mode & 0x42) == 0x42) + if ((wy700->wy700_mode & 0x42) == 0x42) { - addr |= 0x10000; - } + addr |= 0x10000; + } wy700->vram[addr] = val; } else @@ -483,16 +482,15 @@ void wy700_write(uint32_t addr, uint8_t val, void *p) uint8_t wy700_read(uint32_t addr, void *p) { wy700_t *wy700 = (wy700_t *)p; - egareads++; if (wy700->wy700_mode & 0x80) /* High-res mode. */ { addr &= 0xFFFF; /* In 800-line modes, bit 0 of the control register sets the high bit of the * read address. */ - if ((wy700->wy700_mode & 0x41) == 0x41) + if ((wy700->wy700_mode & 0x41) == 0x41) { - addr |= 0x10000; - } + addr |= 0x10000; + } return wy700->vram[addr]; } else @@ -536,11 +534,11 @@ void wy700_textline(wy700_t *wy700) uint16_t ca = (wy700->cga_crtc[15] | (wy700->cga_crtc[14] << 8)) & 0x3fff; -/* The fake CRTC character height register selects whether MDA or CGA +/* The fake CRTC character height register selects whether MDA or CGA * attributes are used */ if (wy700->cga_crtc[9] == 0 || wy700->cga_crtc[9] == 13) { - mda = 1; + mda = 1; } if (wy700->font) @@ -568,8 +566,8 @@ void wy700_textline(wy700_t *wy700) attr = wy700->vram[(addr + 2 * x + 1) & 0x3FFF]; drawcursor = ((ma == ca) && cursorline && wy700->enabled && (wy700->cga_ctrl & 8) && (wy700->blink & 16)); - blink = ((wy700->blink & 16) && - (wy700->cga_ctrl & 0x20) && + blink = ((wy700->blink & 16) && + (wy700->cga_ctrl & 0x20) && (attr & 0x80) && !drawcursor); if (wy700->cga_ctrl & 0x20) attr &= 0x7F; @@ -592,7 +590,7 @@ void wy700_textline(wy700_t *wy700) else col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) col = mdacols[0][0][0]; - if (w == 40) + if (w == 40) { buffer32->line[wy700->displine][(x * cw) + 2*c] = col; buffer32->line[wy700->displine][(x * cw) + 2*c + 1] = col; @@ -624,11 +622,11 @@ void wy700_cgaline(wy700_t *wy700) (wy700->displine >> 3) * 80 + ((ma & ~1) << 1); - /* The fixed mode setting here programs the real CRTC with a screen + /* The fixed mode setting here programs the real CRTC with a screen * width to 20, so draw in 20 fixed chunks of 4 bytes each */ for (x = 0; x < 20; x++) { - dat = ((wy700->vram[addr & 0x3FFF] << 24) | + dat = ((wy700->vram[addr & 0x3FFF] << 24) | (wy700->vram[(addr+1) & 0x3FFF] << 16) | (wy700->vram[(addr+2) & 0x3FFF] << 8) | (wy700->vram[(addr+3) & 0x3FFF])); @@ -683,7 +681,7 @@ void wy700_medresline(wy700_t *wy700) for (x = 0; x < 20; x++) { - dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | (wy700->vram[(addr+1) & 0x1FFFF] << 16) | (wy700->vram[(addr+2) & 0x1FFFF] << 8) | (wy700->vram[(addr+3) & 0x1FFFF])); @@ -717,8 +715,8 @@ void wy700_medresline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; /* Display disabled? */ if (!(wy700->wy700_mode & 8)) ink = 16; - buffer32->line[wy700->displine][x*64 + 2*c] = - buffer32->line[wy700->displine][x*64 + 2*c+1] = + buffer32->line[wy700->displine][x*64 + 2*c] = + buffer32->line[wy700->displine][x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -740,12 +738,12 @@ void wy700_hiresline(wy700_t *wy700) addr = (wy700->displine >> 1) * 160 + 4 * wy700->wy700_base; if (wy700->wy700_mode & 0x40) /* 800-line interleaved modes */ - { + { if (wy700->displine & 1) addr += 0x10000; } for (x = 0; x < 40; x++) { - dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | (wy700->vram[(addr+1) & 0x1FFFF] << 16) | (wy700->vram[(addr+2) & 0x1FFFF] << 8) | (wy700->vram[(addr+3) & 0x1FFFF])); @@ -804,8 +802,8 @@ void wy700_poll(void *p) { video_wait_for_buffer(); } - - if (wy700->wy700_mode & 0x80) + + if (wy700->wy700_mode & 0x80) mode = wy700->wy700_mode & 0xF0; else mode = wy700->wy700_mode & 0x0F; @@ -872,25 +870,25 @@ void wy700_poll(void *p) if (video_force_resize_get()) video_force_resize_set(0); } - video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + video_blit_memtoscreen_8(0, 0, xsize, ysize); frames++; /* Fixed 1280x800 resolution */ video_res_x = WY700_XSIZE; video_res_y = WY700_YSIZE; - if (wy700->wy700_mode & 0x80) + if (wy700->wy700_mode & 0x80) mode = wy700->wy700_mode & 0xF0; else mode = wy700->wy700_mode & 0x0F; switch(mode) { - case 0x00: + case 0x00: case 0x02: video_bpp = 0; break; - case 0x04: - case 0x90: + case 0x04: + case 0x90: case 0xB0: case 0xD0: case 0xF0: video_bpp = 2; break; - default: video_bpp = 1; break; + default: video_bpp = 1; break; } wy700->blink++; } @@ -908,7 +906,7 @@ void *wy700_init(const device_t *info) /* 128k video RAM */ wy700->vram = malloc(0x20000); - loadfont(L"roms/video/wyse700/wy700.rom", 3); + loadfont("roms/video/wyse700/wy700.rom", 3); timer_add(&wy700->timer, wy700_poll, wy700, 1); @@ -919,7 +917,7 @@ void *wy700_init(const device_t *info) io_sethandler(0x03b0, 0x000C, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); io_sethandler(0x03d0, 0x0010, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); - /* Set up the emulated attributes. + /* Set up the emulated attributes. * CGA is done in four groups: 00-0F, 10-7F, 80-8F, 90-FF */ for (c = 0; c < 0x10; c++) { @@ -1005,19 +1003,20 @@ void wy700_close(void *p) void wy700_speed_changed(void *p) { wy700_t *wy700 = (wy700_t *)p; - + wy700_recalctimings(wy700); } -const device_t wy700_device = -{ - "Wyse 700", - DEVICE_ISA, 0, - wy700_init, - wy700_close, - NULL, - NULL, - wy700_speed_changed, - NULL, - NULL +const device_t wy700_device = { + .name = "Wyse 700", + .internal_name = "wy700", + .flags = DEVICE_ISA, + .local = 0, + .init = wy700_init, + .close = wy700_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = wy700_speed_changed, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c new file mode 100644 index 000000000..2941d9cb2 --- /dev/null +++ b/src/video/vid_xga.c @@ -0,0 +1,2865 @@ +/* + * 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. + * + * IBM XGA emulation. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include <86box/bswap.h> +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/dma.h> +#include <86box/rom.h> +#include <86box/mca.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include <86box/vid_xga_device.h> +#include "cpu.h" + +#define XGA_BIOS_PATH "roms/video/xga/XGA_37F9576_Ver200.BIN" +#define XGA2_BIOS_PATH "roms/video/xga/xga2_v300.bin" + +static void xga_ext_outb(uint16_t addr, uint8_t val, void *p); +static uint8_t xga_ext_inb(uint16_t addr, void *p); + +static void +xga_updatemapping(svga_t *svga) +{ + xga_t *xga = &svga->xga; + + //pclog("OpMode = %x, linear base = %08x, aperture cntl = %d, opmodereset1 = %d, access mode = %x, map = %x.\n", xga->op_mode, xga->linear_base, xga->aperture_cntl, xga->op_mode_reset, xga->access_mode, svga->gdcreg[6] & 0x0c); + if ((xga->op_mode & 7) >= 4) { + if (xga->aperture_cntl == 1) { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + xga->banked_mask = 0xffff; + if (!xga->linear_endian_reverse) + mem_mapping_disable(&xga->linear_mapping); + } else if (xga->aperture_cntl == 0) { +linear: + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + xga->banked_mask = 0xffff; + if ((xga->pos_regs[4] & 1) && !xga->base_addr_1mb) { + xga->linear_size = 0x400000; + mem_mapping_set_addr(&xga->linear_mapping, xga->linear_base, xga->linear_size); + } else { + if (xga->base_addr_1mb) { + xga->linear_size = 0x100000; + mem_mapping_set_addr(&xga->linear_mapping, xga->base_addr_1mb, xga->linear_size); + } else + mem_mapping_disable(&xga->linear_mapping); + } + xga->on = 0; + vga_on = 1; + } else { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + xga->banked_mask = 0xffff; + mem_mapping_disable(&xga->linear_mapping); + } + } else { + if (!(xga->op_mode & 7)) { + goto linear; + } + if (xga->aperture_cntl == 2) { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + xga->banked_mask = 0xffff; + } else { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + xga->banked_mask = 0xffff; + } + mem_mapping_disable(&xga->linear_mapping); + xga->on = 0; + vga_on = 1; + } +} + +void +xga_recalctimings(svga_t *svga) +{ + xga_t *xga = &svga->xga; + + if (xga->on) { + xga->v_total = xga->vtotal + 1; + xga->dispend = xga->vdispend + 1; + xga->v_syncstart = xga->vsyncstart + 1; + xga->split = xga->linecmp + 1; + xga->v_blankstart = xga->vblankstart + 1; + + xga->h_disp = (xga->hdisp + 1) << 3; + + xga->rowoffset = (xga->hdisp + 1); + + xga->interlace = !!(xga->disp_cntl_1 & 0x08); + xga->rowcount = (xga->disp_cntl_2 & 0xc0) >> 6; + + if (xga->interlace) { + xga->v_total >>= 1; + xga->dispend >>= 1; + xga->v_syncstart >>= 1; + xga->split >>= 1; + xga->v_blankstart >>= 1; + } + + xga->ma_latch = xga->disp_start_addr; + + switch (xga->clk_sel_1 & 0x0c) { + case 0: + if (xga->clk_sel_2 & 0x80) { + svga->clock = (cpuclock * (double)(1ull << 32)) / 41539000.0; + } else { + svga->clock = (cpuclock * (double)(1ull << 32)) / 25175000.0; + } + break; + case 4: + svga->clock = (cpuclock * (double)(1ull << 32)) / 28322000.0; + break; + case 0x0c: + svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; + break; + } + } else { + vga_on = 1; + } +} + +static void +xga_ext_out_reg(xga_t *xga, svga_t *svga, uint8_t idx, uint8_t val) +{ + uint8_t index; + + switch (idx) { + case 0x10: + xga->htotal = (xga->htotal & 0xff00) | val; + break; + case 0x11: + xga->htotal = (xga->htotal & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x12: + xga->hdisp = (xga->hdisp & 0xff00) | val; + break; + case 0x13: + xga->hdisp = (xga->hdisp & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x20: + xga->vtotal = (xga->vtotal & 0xff00) | val; + break; + case 0x21: + xga->vtotal = (xga->vtotal & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x22: + xga->vdispend = (xga->vdispend & 0xff00) | val; + break; + case 0x23: + xga->vdispend = (xga->vdispend & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x24: + xga->vblankstart = (xga->vblankstart & 0xff00) | val; + break; + case 0x25: + xga->vblankstart = (xga->vblankstart & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x28: + xga->vsyncstart = (xga->vsyncstart & 0xff00) | val; + break; + case 0x29: + xga->vsyncstart = (xga->vsyncstart & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x2c: + xga->linecmp = (xga->linecmp & 0xff00) | val; + break; + case 0x2d: + xga->linecmp = (xga->linecmp & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x30: + xga->hwc_pos_x = (xga->hwc_pos_x & 0x0700) | val; + xga->hwcursor.x = xga->hwc_pos_x; + break; + case 0x31: + xga->hwc_pos_x = (xga->hwc_pos_x & 0xff) | ((val & 0x07) << 8); + xga->hwcursor.x = xga->hwc_pos_x; + break; + + case 0x32: + xga->hwc_hotspot_x = val & 0x3f; + xga->hwcursor.xoff = val & 0x3f; + break; + + case 0x33: + xga->hwc_pos_y = (xga->hwc_pos_y & 0x0700) | val; + xga->hwcursor.y = xga->hwc_pos_y; + break; + case 0x34: + xga->hwc_pos_y = (xga->hwc_pos_y & 0xff) | ((val & 0x07) << 8); + xga->hwcursor.y = xga->hwc_pos_y; + break; + + case 0x35: + xga->hwc_hotspot_y = val & 0x3f; + xga->hwcursor.yoff = val & 0x3f; + break; + + case 0x36: + xga->hwc_control = val; + xga->hwcursor.ena = xga->hwc_control & 1; + break; + + case 0x38: + xga->hwc_color0 = (xga->hwc_color0 & 0xffff00) | val; + break; + case 0x39: + xga->hwc_color0 = (xga->hwc_color0 & 0xff00ff) | (val << 8); + break; + case 0x3a: + xga->hwc_color0 = (xga->hwc_color0 & 0x00ffff) | (val << 16); + break; + + case 0x3b: + xga->hwc_color1 = (xga->hwc_color1 & 0xffff00) | val; + break; + case 0x3c: + xga->hwc_color1 = (xga->hwc_color1 & 0xff00ff) | (val << 8); + break; + case 0x3d: + xga->hwc_color1 = (xga->hwc_color1 & 0x00ffff) | (val << 16); + break; + + case 0x40: + xga->disp_start_addr = (xga->disp_start_addr & 0x7ff00) | val; + break; + case 0x41: + xga->disp_start_addr = (xga->disp_start_addr & 0x700ff) | (val << 8); + break; + case 0x42: + xga->disp_start_addr = (xga->disp_start_addr & 0x0ffff) | ((val & 0x07) << 16); + svga_recalctimings(svga); + break; + + case 0x43: + xga->pix_map_width = (xga->pix_map_width & 0x700) | val; + break; + case 0x44: + xga->pix_map_width = (xga->pix_map_width & 0xff) | ((val & 0x07) << 8); + break; + + case 0x50: + xga->disp_cntl_1 = val; + svga_recalctimings(svga); + break; + + case 0x51: + xga->disp_cntl_2 = val; + svga_recalctimings(svga); + break; + + case 0x54: + xga->clk_sel_1 = val; + svga_recalctimings(svga); + break; + + case 0x59: + xga->direct_color = val; + break; + + case 0x60: + xga->sprite_pal_addr_idx = (xga->sprite_pal_addr_idx & 0x3f00) | val; + svga->dac_pos = 0; + svga->dac_addr = val & 0xff; + break; + case 0x61: + xga->sprite_pal_addr_idx = (xga->sprite_pal_addr_idx & 0xff) | ((val & 0x3f) << 8); + xga->sprite_pos = xga->sprite_pal_addr_idx & 0x1ff; + if ((xga->sprite_pos >= 0) && (xga->sprite_pos <= 16)) { + if ((xga->op_mode & 7) >= 5) + xga->cursor_data_on = 1; + else if (xga->sprite_pos >= 1) + xga->cursor_data_on = 1; + else if (xga->aperture_cntl == 0) { + if (xga->linear_endian_reverse) + xga->cursor_data_on = 0; + } + } + if ((xga->sprite_pos > 16) && (xga->sprite_pos <= 0x1ff)) + xga->cursor_data_on = 0; + break; + + case 0x62: + xga->sprite_pal_addr_idx_prefetch = (xga->sprite_pal_addr_idx_prefetch & 0x3f00) | val; + svga->dac_pos = 0; + svga->dac_addr = val & 0xff; + break; + case 0x63: + xga->sprite_pal_addr_idx_prefetch = (xga->sprite_pal_addr_idx_prefetch & 0xff) | ((val & 0x3f) << 8); + xga->sprite_pos_prefetch = xga->sprite_pal_addr_idx_prefetch & 0x1ff; + break; + + case 0x64: + svga->dac_mask = val; + break; + + case 0x65: + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + xga->pal_b = val; + index = svga->dac_addr & 0xff; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = xga->pal_b; + svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b); + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + break; + } + break; + + case 0x66: + xga->pal_seq = val; + break; + + case 0x67: + svga->dac_r = val; + break; + case 0x68: + xga->pal_b = val; + break; + case 0x69: + svga->dac_g = val; + break; + + case 0x6a: + xga->sprite_data[xga->sprite_pos] = val; + xga->sprite_pos = (xga->sprite_pos + 1) & 0x3ff; + break; + + case 0x70: + xga->clk_sel_2 = val; + svga_recalctimings(svga); + break; + } +} + +static void +xga_ext_outb(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + //pclog("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); + switch (addr & 0x0f) { + case 0: + xga->op_mode = val; + break; + case 1: + xga->aperture_cntl = val; + xga_updatemapping(svga); + break; + case 4: + xga->access_mode &= ~8; + if ((xga->disp_cntl_2 & 7) == 4) + xga->aperture_cntl = 0; + break; + case 6: + vga_on = 0; + xga->on = 1; + break; + case 8: + xga->ap_idx = val; + //pclog("Aperture CNTL = %d, val = %02x, up to bit6 = %02x\n", xga->aperture_cntl, val, val & 0x3f); + if ((xga->op_mode & 7) < 4) { + xga->write_bank = xga->read_bank = 0; + } else { + xga->write_bank = (xga->ap_idx & 0x3f) << 16; + xga->read_bank = xga->write_bank; + } + break; + case 9: + xga->access_mode = val; + break; + case 0x0a: + xga->regs_idx = val; + break; + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + xga->regs[xga->regs_idx] = val; + xga_ext_out_reg(xga, svga, xga->regs_idx, xga->regs[xga->regs_idx]); + break; + } +} + +static uint8_t +xga_ext_inb(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint8_t ret, index; + + switch (addr & 0x0f) { + case 0: + ret = xga->op_mode; + break; + case 1: + ret = xga->aperture_cntl; + break; + case 8: + ret = xga->ap_idx; + break; + case 9: + ret = xga->access_mode; + break; + case 0x0a: + ret = xga->regs_idx; + break; + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + switch (xga->regs_idx) { + case 4: + ret = (xga->bus & DEVICE_MCA) ? 1 : 0; + break; + case 0x10: + ret = xga->htotal & 0xff; + break; + case 0x11: + ret = xga->htotal >> 8; + break; + case 0x12: + ret = xga->hdisp & 0xff; + break; + case 0x13: + ret = xga->hdisp >> 8; + break; + case 0x20: + ret = xga->vtotal & 0xff; + break; + case 0x21: + ret = xga->vtotal >> 8; + break; + case 0x22: + ret = xga->vdispend & 0xff; + break; + case 0x23: + ret = xga->vdispend >> 8; + break; + case 0x24: + ret = xga->vblankstart & 0xff; + break; + case 0x25: + ret = xga->vblankstart >> 8; + break; + case 0x28: + ret = xga->vsyncstart & 0xff; + break; + case 0x29: + ret = xga->vsyncstart >> 8; + break; + case 0x2c: + ret = xga->linecmp & 0xff; + break; + case 0x2d: + ret = xga->linecmp >> 8; + break; + case 0x30: + ret = xga->hwc_pos_x & 0xff; + break; + case 0x31: + ret = xga->hwc_pos_x >> 8; + break; + case 0x32: + ret = xga->hwc_hotspot_x; + break; + case 0x33: + ret = xga->hwc_pos_y & 0xff; + break; + case 0x34: + ret = xga->hwc_pos_y >> 8; + break; + case 0x35: + ret = xga->hwc_hotspot_y; + break; + case 0x36: + ret = xga->hwc_control; + break; + case 0x38: + ret = xga->hwc_color0 & 0xff; + break; + case 0x39: + ret = xga->hwc_color0 >> 8; + break; + case 0x3a: + ret = xga->hwc_color0 >> 16; + break; + case 0x3b: + ret = xga->hwc_color1 & 0xff; + break; + case 0x3c: + ret = xga->hwc_color1 >> 8; + break; + case 0x3d: + ret = xga->hwc_color1 >> 16; + break; + case 0x40: + ret = xga->disp_start_addr & 0xff; + break; + case 0x41: + ret = xga->disp_start_addr >> 8; + break; + case 0x42: + ret = xga->disp_start_addr >> 16; + break; + case 0x43: + ret = xga->pix_map_width & 0xff; + break; + case 0x44: + ret = xga->pix_map_width >> 8; + break; + case 0x50: + ret = xga->disp_cntl_1 | 0x20; + break; + case 0x51: + ret = xga->disp_cntl_2; + break; + case 0x52: + ret = 0x0b; + break; + case 0x53: + ret = 0x70; + break; + case 0x54: + ret = xga->clk_sel_1; + break; + + case 0x59: + ret = xga->direct_color; + break; + + case 0x60: + ret = xga->sprite_pal_addr_idx & 0xff; + break; + case 0x61: + ret = xga->sprite_pal_addr_idx >> 8; + break; + + case 0x62: + ret = xga->sprite_pal_addr_idx_prefetch & 0xff; + break; + case 0x63: + ret = xga->sprite_pal_addr_idx_prefetch >> 8; + break; + + case 0x64: + ret = svga->dac_mask; + break; + + case 0x65: + index = svga->dac_addr & 0xff; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + ret = svga->vgapal[index].r; + break; + case 1: + svga->dac_pos++; + ret = svga->vgapal[index].g; + break; + case 2: + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + ret = svga->vgapal[index].b; + break; + } + break; + + case 0x66: + ret = xga->pal_seq; + break; + + case 0x67: + ret = svga->dac_r; + break; + case 0x68: + ret = xga->pal_b; + break; + case 0x69: + ret = svga->dac_g; + break; + + case 0x6a: + //pclog("Sprite POS Read = %d, addr idx = %04x\n", xga->sprite_pos, xga->sprite_pal_addr_idx_prefetch); + ret = xga->sprite_data[xga->sprite_pos_prefetch]; + xga->sprite_pos_prefetch = (xga->sprite_pos_prefetch + 1) & 0x3ff; + break; + + case 0x70: + ret = xga->clk_sel_2; + break; + + default: + ret = xga->regs[xga->regs_idx]; + break; + } + break; + } + + //pclog("[%04X:%08X]: EXT INB = %02x, ret = %02x\n", CS, cpu_state.pc, addr, ret); + return ret; +} + + +#define READ(addr, dat) \ + dat = xga->vram[(addr) & (xga->vram_mask)]; + +#define WRITE(addr, dat) \ + xga->vram[((addr)) & (xga->vram_mask)] = dat; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = changeframecount; + +#define READW(addr, dat) \ + dat = *(uint16_t *)&xga->vram[(addr) & (xga->vram_mask)]; + +#define READW_REVERSE(addr, dat) \ + dat = xga->vram[(addr + 1) & (xga->vram_mask - 1)] & 0xff; \ + dat |= (xga->vram[(addr) & (xga->vram_mask - 1)] << 8); + +#define WRITEW(addr, dat) \ + *(uint16_t *)&xga->vram[((addr)) & (xga->vram_mask)] = dat; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = changeframecount; + +#define WRITEW_REVERSE(addr, dat) \ + xga->vram[((addr + 1)) & (xga->vram_mask - 1)] = dat & 0xff; \ + xga->vram[((addr)) & (xga->vram_mask - 1)] = dat >> 8; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = changeframecount; + +#define ROP(mix, d, s) { \ + switch ((mix) ? (xga->accel.frgd_mix & 0x1f) : (xga->accel.bkgd_mix & 0x1f)) { \ + case 0x00: d = 0; break; \ + case 0x01: d = s & d; break; \ + case 0x02: d = s & ~d; break; \ + case 0x03: d = s; break; \ + case 0x04: d = ~s & d; break; \ + case 0x05: d = d; break; \ + case 0x06: d = s ^ d; break; \ + case 0x07: d = s | d; break; \ + case 0x08: d = ~s & ~d; break; \ + case 0x09: d = s ^ ~d; break; \ + case 0x0a: d = ~d; break; \ + case 0x0b: d = s | ~d; break; \ + case 0x0c: d = ~s; break; \ + case 0x0d: d = ~s | d; break; \ + case 0x0e: d = ~s | ~d; break; \ + case 0x0f: d = ~0; break; \ + case 0x10: d = MAX(s, d); break; \ + case 0x11: d = MIN(s, d); break; \ + case 0x12: d = MIN(0xff, s + d); break; \ + case 0x13: d = MAX(0, d - s); break; \ + case 0x14: d = MAX(0, s - d); break; \ + case 0x15: d = (s + d) >> 1; break; \ + } \ + } + +static uint32_t +xga_accel_read_pattern_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int width) +{ + xga_t *xga = &svga->xga; + uint32_t addr = base; + int bits; + uint32_t byte, byte2; + uint8_t px; + int skip = 0; + + if (xga->base_addr_1mb) { + if (addr < xga->base_addr_1mb || (addr > (xga->base_addr_1mb + 0xfffff))) + skip = 1; + } else { + if (addr < xga->linear_base || (addr > (xga->linear_base + 0xfffff))) + skip = 1; + } + + addr += (y * (width >> 3)); + addr += (x >> 3); + if (!skip) { + READ(addr, byte); + } else { + byte = mem_readb_phys(addr); + } + byte2 = byte; + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + if (xga->linear_endian_reverse) + bits = 7 - (x & 7); + else + bits = (x & 7); + else { + bits = 7 - (x & 7); + } + px = (byte2 >> bits) & 1; + return px; +} + + +static uint32_t +xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int width, int height) +{ + xga_t *xga = &svga->xga; + uint32_t addr = base; + int bits; + uint32_t byte, byte2; + uint8_t px; + int skip = 0; + + if (xga->base_addr_1mb) { + if (addr < xga->base_addr_1mb || (addr > (xga->base_addr_1mb + 0xfffff))) + skip = 1; + } else { + if (addr < xga->linear_base || (addr > (xga->linear_base + 0xfffff))) + skip = 1; + } + + switch (xga->accel.px_map_format[map] & 7) { + case 0: /*1-bit*/ + addr += (y * (width >> 3)); + addr += (x >> 3); + if (!skip) { + READ(addr, byte); + } else { + byte = mem_readb_phys(addr); + } + byte2 = byte; + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + if (xga->linear_endian_reverse) + bits = 7 - (x & 7); + else + bits = (x & 7); + else { + bits = 7 - (x & 7); + } + px = (byte2 >> bits) & 1; + return px; + case 3: /*8-bit*/ + addr += (y * width); + addr += x; + if (!skip) { + READ(addr, byte); + } else { + byte = mem_readb_phys(addr); + } + return byte; + case 4: /*16-bit*/ + addr += (y * (width << 1)); + addr += (x << 1); + if (!skip) { + if ((xga->accel.px_map_format[map] & 8)) { + if (xga->linear_endian_reverse) { + READW(addr, byte); + } else { + READW_REVERSE(addr, byte); + } + } else { + READW(addr, byte); + } + } else { + byte = mem_readw_phys(addr); + } + return byte; + } + + return 0; +} + +static void +xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, uint32_t pixel, int width, int height) +{ + xga_t *xga = &svga->xga; + uint32_t addr = base; + uint8_t byte, mask; + uint8_t byte2; + int skip = 0; + + if (xga->base_addr_1mb) { + if (addr < xga->base_addr_1mb || (addr > (xga->base_addr_1mb + 0xfffff))) + skip = 1; + } else { + if (addr < xga->linear_base || (addr > (xga->linear_base + 0xfffff))) + skip = 1; + } + + switch (xga->accel.px_map_format[map] & 7) { + case 0: /*1-bit*/ + addr += (y * (width) >> 3); + addr += (x >> 3); + if (!skip) { + READ(addr, byte); + } else { + byte = mem_readb_phys(addr); + } + byte2 = byte; + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) { + if (xga->linear_endian_reverse) + mask = 1 << (7 - (x & 7)); + else + mask = 1 << (x & 7); + } else { + mask = 1 << (7 - (x & 7)); + } + byte2 = (byte2 & ~mask) | ((pixel ? 0xff : 0) & mask); + if (!skip) { + WRITE(addr, byte2); + } + mem_writeb_phys(addr, byte2); + break; + case 3: /*8-bit*/ + addr += (y * width); + addr += x; + if (!skip) { + WRITE(addr, pixel & 0xff); + } + mem_writeb_phys(addr, pixel & 0xff); + break; + case 4: /*16-bit*/ + addr += (y * (width) << 1); + addr += (x << 1); + if (!skip) { + if ((xga->accel.px_map_format[map] & 8)) { + if (xga->linear_endian_reverse) { + WRITEW(addr, pixel); + } else { + WRITEW_REVERSE(addr, pixel); + } + } else { + WRITEW(addr, pixel); + } + } + mem_writew_phys(addr, pixel); + break; + } +} + +static void +xga_short_stroke(svga_t *svga, uint8_t ssv) +{ + xga_t *xga = &svga->xga; + uint32_t src_dat, dest_dat, old_dest_dat; + uint32_t color_cmp = xga->accel.color_cmp; + uint32_t plane_mask = xga->accel.plane_mask; + uint32_t dstbase = xga->accel.px_map_base[xga->accel.dst_map]; + uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; + int y = ssv & 0x0f; + int x = 0; + int dx, dy, dirx = 0, diry = 0; + + dx = xga->accel.dst_map_x & 0x1fff; + if (xga->accel.dst_map_x & 0x1800) + dx |= ~0x17ff; + + dy = xga->accel.dst_map_y & 0x1fff; + if (xga->accel.dst_map_y & 0x1800) + dy |= ~0x17ff; + + switch ((ssv >> 5) & 7) { + case 0: + dirx = 1; + diry = 0; + break; + case 1: + dirx = 1; + diry = -1; + break; + case 2: + dirx = 0; + diry = -1; + break; + case 3: + dirx = -1; + diry = -1; + break; + case 4: + dirx = -1; + diry = 0; + break; + case 5: + dirx = -1; + diry = 1; + break; + case 6: + dirx = 0; + diry = 1; + break; + case 7: + dirx = 1; + diry = 1; + break; + } + + if (xga->accel.pat_src == 8) { + while (y >= 0) { + if (xga->accel.command & 0xc0) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + if ((xga->accel.command & 0x30) == 0) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x10) && x) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x20) && y) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + } else { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + if ((xga->accel.command & 0x30) == 0) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x10) && x) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x20) && y) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + + if (!y) { + break; + } + + dx += dirx; + dy += diry; + + x++; + y--; + } + } + + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; +} + +#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap; + +static void +xga_line_draw_write(svga_t *svga) +{ + xga_t *xga = &svga->xga; + uint32_t src_dat, dest_dat, old_dest_dat; + uint32_t color_cmp = xga->accel.color_cmp; + uint32_t plane_mask = xga->accel.plane_mask; + uint32_t dstbase = xga->accel.px_map_base[xga->accel.dst_map]; + uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; + int dminor, destxtmp, dmajor, err, tmpswap; + int steep = 1; + int xdir, ydir; + int y = xga->accel.blt_width; + int x = 0; + int dx, dy; + + dminor = ((int16_t)xga->accel.bres_k1); + if (xga->accel.bres_k1 & 0x2000) + dminor |= ~0x1fff; + dminor >>= 1; + + destxtmp = ((int16_t)xga->accel.bres_k2); + if (xga->accel.bres_k2 & 0x2000) + destxtmp |= ~0x1fff; + + dmajor = -(destxtmp - (dminor << 1)) >> 1; + + err = ((int16_t)xga->accel.bres_err_term); + if (xga->accel.bres_err_term & 0x2000) + destxtmp |= ~0x1fff; + + if (xga->accel.octant & 0x02) { + ydir = -1; + } else { + ydir = 1; + } + + if (xga->accel.octant & 0x04) { + xdir = -1; + } else { + xdir = 1; + } + + dx = xga->accel.dst_map_x & 0x1fff; + if (xga->accel.dst_map_x & 0x1800) + dx |= ~0x17ff; + + dy = xga->accel.dst_map_y & 0x1fff; + if (xga->accel.dst_map_y & 0x1800) + dy |= ~0x17ff; + + if (xga->accel.octant & 0x01) { + steep = 0; + SWAP(dx, dy); + SWAP(xdir, ydir); + } + + if (xga->accel.pat_src == 8) { + while (y >= 0) { + if (xga->accel.command & 0xc0) { + if (steep) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } else { + if ((dy >= xga->accel.mask_map_origin_x_off) && (dy <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (dx >= xga->accel.mask_map_origin_y_off) && (dx <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + } else { + if (steep) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } else { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + + if (!y) { + break; + } + + while (err > 0) { + dy += ydir; + err -= (dmajor << 1); + } + + dx += xdir; + err += (dminor << 1); + + x++; + y--; + } + } + + if (steep) { + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; + } else { + xga->accel.dst_map_x = dy; + xga->accel.dst_map_y = dx; + } +} + + +static int16_t +xga_dst_wrap(int16_t addr) +{ + addr &= 0x1fff; + return (addr & 0x1800) == 0x1800 ? (addr | 0xf800) : addr; +} + +static void +xga_bitblt(svga_t *svga) +{ + xga_t *xga = &svga->xga; + uint32_t src_dat, dest_dat, old_dest_dat; + uint32_t color_cmp = xga->accel.color_cmp; + uint32_t plane_mask = xga->accel.plane_mask; + uint32_t patbase = xga->accel.px_map_base[xga->accel.pat_src]; + uint32_t dstbase = xga->accel.px_map_base[xga->accel.dst_map]; + uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; + uint32_t patwidth = xga->accel.px_map_width[xga->accel.pat_src]; + uint32_t dstwidth = xga->accel.px_map_width[xga->accel.dst_map]; + uint32_t srcwidth = xga->accel.px_map_width[xga->accel.src_map]; + uint32_t patheight = xga->accel.px_map_height[xga->accel.pat_src]; + uint32_t srcheight = xga->accel.px_map_height[xga->accel.src_map]; + int mix = 0; + int xdir, ydir; + + if (xga->accel.octant & 0x02) { + ydir = -1; + } else { + ydir = 1; + } + + if (xga->accel.octant & 0x04) { + xdir = -1; + } else { + xdir = 1; + } + + xga->accel.x = xga->accel.blt_width & 0xfff; + xga->accel.y = xga->accel.blt_height & 0xfff; + + xga->accel.sx = xga->accel.src_map_x & 0xfff; + xga->accel.sy = xga->accel.src_map_y & 0xfff; + xga->accel.px = xga->accel.pat_map_x & 0xfff; + xga->accel.py = xga->accel.pat_map_y & 0xfff; + xga->accel.dx = xga_dst_wrap(xga->accel.dst_map_x); + xga->accel.dy = xga_dst_wrap(xga->accel.dst_map_y); + + xga->accel.pattern = 0; + + if (xga->accel.pat_src == 8) { + if (srcheight == 7) + xga->accel.pattern = 1; + else { + if ((dstwidth == (xga->h_disp - 1)) && (srcwidth == 1)) { + if ((xga->accel.dst_map == 1) && (xga->accel.src_map == 2) && xga->linear_endian_reverse) { + if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px_map_format[xga->accel.src_map] >= 0x0b)) { + xga->accel.pattern = 1; + } + } + } + } + + //pclog("Pattern Map = 8: CMD = %08x: SRCBase = %08x, DSTBase = %08x, from/to vram dir = %d, cmd dir = %06x\n", xga->accel.command, srcbase, dstbase, xga->from_to_vram, xga->accel.dir_cmd); + //pclog("CMD = %08x: Y = %d, X = %d, patsrc = %02x, srcmap = %d, dstmap = %d, py = %d, sy = %d, dy = %d, width0 = %d, width1 = %d, width2 = %d, width3 = %d\n", xga->accel.command, xga->accel.y, xga->accel.x, xga->accel.pat_src, xga->accel.src_map, xga->accel.dst_map, xga->accel.py, xga->accel.sy, xga->accel.dy, xga->accel.px_map_width[0], xga->accel.px_map_width[1], xga->accel.px_map_width[2], xga->accel.px_map_width[3]); + while (xga->accel.y >= 0) { + if (xga->accel.command & 0xc0) { + if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } else { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + + if (xga->accel.pattern) + xga->accel.sx = ((xga->accel.sx + xdir) & srcwidth) | (xga->accel.sx & ~srcwidth); + else + xga->accel.sx += xdir; + xga->accel.dx = xga_dst_wrap(xga->accel.dx + xdir); + xga->accel.x--; + if (xga->accel.x < 0) { + xga->accel.x = (xga->accel.blt_width & 0xfff); + + xga->accel.dx = xga_dst_wrap(xga->accel.dst_map_x); + xga->accel.sx = xga->accel.src_map_x & 0xfff; + + xga->accel.dy = xga_dst_wrap(xga->accel.dy + ydir); + if (xga->accel.pattern) + xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); + else + xga->accel.sy += ydir; + + xga->accel.y--; + + if (xga->accel.y < 0) { + xga->accel.dst_map_x = xga->accel.dx; + xga->accel.dst_map_y = xga->accel.dy; + return; + } + } + } + } else if (xga->accel.pat_src >= 1) { + if (patheight == 7) + xga->accel.pattern = 1; + else { + if (dstwidth == (xga->h_disp - 1)) { + if (srcwidth == (xga->h_disp - 1)) { + if ((xga->accel.src_map == 1) && (xga->accel.dst_map == 1) && (xga->accel.pat_src == 2) && xga->linear_endian_reverse) { + if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px <= 7) && (xga->accel.py <= 3)) { + xga->accel.pattern = 1; + } + } + } else { + if (!xga->accel.src_map && (xga->accel.dst_map == 1) && (xga->accel.pat_src == 2) && xga->linear_endian_reverse) { + if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px <= 7) && (xga->accel.py <= 3)) { + if ((patwidth >= 7) && ((xga->accel.command & 0xc0) == 0x40)) + xga->accel.pattern = 0; + else + xga->accel.pattern = 1; + } + } + } + } + } + + //pclog("Pattern Map = %d: CMD = %08x: PATBase = %08x, SRCBase = %08x, DSTBase = %08x\n", xga->accel.pat_src, xga->accel.command, patbase, srcbase, dstbase); + //pclog("CMD = %08x: Y = %d, X = %d, patsrc = %02x, srcmap = %d, dstmap = %d, py = %d, sy = %d, dy = %d, width0 = %d, width1 = %d, width2 = %d, width3 = %d\n", xga->accel.command, xga->accel.y, xga->accel.x, xga->accel.pat_src, xga->accel.src_map, xga->accel.dst_map, xga->accel.py, xga->accel.sy, xga->accel.dy, xga->accel.px_map_width[0], xga->accel.px_map_width[1], xga->accel.px_map_width[2], xga->accel.px_map_width[3]); + while (xga->accel.y >= 0) { + mix = xga_accel_read_pattern_map_pixel(svga, xga->accel.px, xga->accel.py, xga->accel.pat_src, patbase, patwidth + 1); + + if (xga->accel.command & 0xc0) { + if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + if (mix) + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + else + src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.bkgd_color; + + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(mix, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } else { + if (mix) + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + else + src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.bkgd_color; + + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(mix, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + + + xga->accel.sx += xdir; + if (xga->accel.pattern) + xga->accel.px = ((xga->accel.px + xdir) & patwidth) | (xga->accel.px & ~patwidth); + else + xga->accel.px += xdir; + xga->accel.dx = xga_dst_wrap(xga->accel.dx + xdir); + xga->accel.x--; + if (xga->accel.x < 0) { + xga->accel.y--; + xga->accel.x = (xga->accel.blt_width & 0xfff); + + xga->accel.dx = xga_dst_wrap(xga->accel.dst_map_x); + xga->accel.sx = xga->accel.src_map_x & 0xfff; + xga->accel.px = xga->accel.pat_map_x & 0xfff; + + xga->accel.sy += ydir; + if (xga->accel.pattern) + xga->accel.py = ((xga->accel.py + ydir) & patheight) | (xga->accel.py & ~patheight); + else + xga->accel.py += ydir; + xga->accel.dy = xga_dst_wrap(xga->accel.dy + ydir); + + if (xga->accel.y < 0) { + xga->accel.dst_map_x = xga->accel.dx; + xga->accel.dst_map_y = xga->accel.dy; + return; + } + } + } + } +} + +static void +xga_mem_write(uint32_t addr, uint32_t val, xga_t *xga, svga_t *svga, int len) +{ + addr &= 0x1fff; + + if (addr >= 0x1800) { + switch (addr & 0x7f) { + case 0x12: + xga->accel.px_map_idx = val & 3; + break; + + case 0x14: + if (len == 4) + xga->accel.px_map_base[xga->accel.px_map_idx] = val; + else if (len == 2) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xffff0000) | val; + else + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xffffff00) | val; + break; + case 0x15: + if (len == 1) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xffff00ff) | (val << 8); + break; + case 0x16: + if (len == 2) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0x0000ffff) | (val << 16); + else + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xff00ffff) | (val << 16); + break; + case 0x17: + if (len == 1) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0x00ffffff) | (val << 24); + break; + + case 0x18: + if (len == 4) { + xga->accel.px_map_width[xga->accel.px_map_idx] = val & 0xffff; + xga->accel.px_map_height[xga->accel.px_map_idx] = (val >> 16) & 0xffff; + } else if (len == 2) { + xga->accel.px_map_width[xga->accel.px_map_idx] = val & 0xffff; + } else + xga->accel.px_map_width[xga->accel.px_map_idx] = (xga->accel.px_map_width[xga->accel.px_map_idx] & 0xff00) | val; + break; + case 0x19: + if (len == 1) + xga->accel.px_map_width[xga->accel.px_map_idx] = (xga->accel.px_map_width[xga->accel.px_map_idx] & 0xff) | (val << 8); + break; + + case 0x1a: + if (len == 2) + xga->accel.px_map_height[xga->accel.px_map_idx] = val & 0xffff; + else + xga->accel.px_map_height[xga->accel.px_map_idx] = (xga->accel.px_map_height[xga->accel.px_map_idx] & 0xff00) | val; + break; + case 0x1b: + if (len == 1) + xga->accel.px_map_height[xga->accel.px_map_idx] = (xga->accel.px_map_height[xga->accel.px_map_idx] & 0xff) | (val << 8); + break; + + case 0x1c: + xga->accel.px_map_format[xga->accel.px_map_idx] = val; + break; + + case 0x20: + if (len >= 2) { + xga->accel.bres_err_term = val & 0x3fff; + if (val & 0x2000) + xga->accel.bres_err_term |= ~0x3fff; + } else + xga->accel.bres_err_term = (xga->accel.bres_err_term & 0x3f00) | val; + break; + case 0x21: + if (len == 1) { + xga->accel.bres_err_term = (xga->accel.bres_err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + xga->accel.bres_err_term |= ~0x3fff; + } + break; + + case 0x24: + if (len >= 2) { + xga->accel.bres_k1 = val & 0x3fff; + if (val & 0x2000) + xga->accel.bres_k1 |= ~0x3fff; + } else + xga->accel.bres_k1 = (xga->accel.bres_k1 & 0x3f00) | val; + break; + case 0x25: + if (len == 1) { + xga->accel.bres_k1 = (xga->accel.bres_k1 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + xga->accel.bres_k1 |= ~0x3fff; + } + break; + + case 0x28: + if (len >= 2) { + xga->accel.bres_k2 = val & 0x3fff; + if (val & 0x2000) + xga->accel.bres_k2 |= ~0x3fff; + } else + xga->accel.bres_k2 = (xga->accel.bres_k2 & 0x3f00) | val; + break; + case 0x29: + if (len == 1) { + xga->accel.bres_k2 = (xga->accel.bres_k2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + xga->accel.bres_k2 |= ~0x3fff; + } + break; + + case 0x2c: + if (len == 4) { + xga->accel.short_stroke = val; + xga->accel.short_stroke_vector1 = xga->accel.short_stroke & 0xff; + xga->accel.short_stroke_vector2 = (xga->accel.short_stroke >> 8) & 0xff; + xga->accel.short_stroke_vector3 = (xga->accel.short_stroke >> 16) & 0xff; + xga->accel.short_stroke_vector4 = (xga->accel.short_stroke >> 24) & 0xff; + + //pclog("1Vector = %02x, 2Vector = %02x, 3Vector = %02x, 4Vector = %02x\n", xga->accel.short_stroke_vector1, xga->accel.short_stroke_vector2, xga->accel.short_stroke_vector3, xga->accel.short_stroke_vector4); + xga_short_stroke(svga, xga->accel.short_stroke_vector1); + xga_short_stroke(svga, xga->accel.short_stroke_vector2); + xga_short_stroke(svga, xga->accel.short_stroke_vector3); + xga_short_stroke(svga, xga->accel.short_stroke_vector4); + } else if (len == 2) + xga->accel.short_stroke = (xga->accel.short_stroke & 0xffff0000) | val; + else + xga->accel.short_stroke = (xga->accel.short_stroke & 0xffffff00) | val; + break; + case 0x2d: + if (len == 1) + xga->accel.short_stroke = (xga->accel.short_stroke & 0xffff00ff) | (val << 8); + break; + case 0x2e: + if (len == 2) { + xga->accel.short_stroke = (xga->accel.short_stroke & 0x0000ffff) | (val << 16); + } else + xga->accel.short_stroke = (xga->accel.short_stroke & 0xff00ffff) | (val << 16); + break; + case 0x2f: + if (len == 1) { + xga->accel.short_stroke = (xga->accel.short_stroke & 0x00ffffff) | (val << 24); + } + break; + + case 0x48: + xga->accel.frgd_mix = val & 0xff; + if (len == 4) { + xga->accel.bkgd_mix = (val >> 8) & 0xff; + xga->accel.cc_cond = (val >> 16) & 0x07; + } else if (len == 2) { + xga->accel.bkgd_mix = (val >> 8) & 0xff; + } + break; + + case 0x49: + xga->accel.bkgd_mix = val & 0xff; + break; + + case 0x4a: + xga->accel.cc_cond = val & 0x07; + break; + + case 0x4c: + if (len == 4) + xga->accel.color_cmp = val; + else if (len == 2) + xga->accel.color_cmp = (xga->accel.color_cmp & 0xffff0000) | val; + else + xga->accel.color_cmp = (xga->accel.color_cmp & 0xffffff00) | val; + break; + case 0x4d: + if (len == 1) + xga->accel.color_cmp = (xga->accel.color_cmp & 0xffff00ff) | (val << 8); + break; + case 0x4e: + if (len == 2) + xga->accel.color_cmp = (xga->accel.color_cmp & 0x0000ffff) | (val << 16); + else + xga->accel.color_cmp = (xga->accel.color_cmp & 0xff00ffff) | (val << 16); + break; + case 0x4f: + if (len == 1) + xga->accel.color_cmp = (xga->accel.color_cmp & 0x00ffffff) | (val << 24); + break; + + case 0x50: + if (len == 4) + xga->accel.plane_mask = val; + else if (len == 2) + xga->accel.plane_mask = (xga->accel.plane_mask & 0xffff0000) | val; + else + xga->accel.plane_mask = (xga->accel.plane_mask & 0xffffff00) | val; + break; + case 0x51: + if (len == 1) + xga->accel.plane_mask = (xga->accel.plane_mask & 0xffff00ff) | (val << 8); + break; + case 0x52: + if (len == 2) + xga->accel.plane_mask = (xga->accel.plane_mask & 0x0000ffff) | (val << 16); + else + xga->accel.plane_mask = (xga->accel.plane_mask & 0xff00ffff) | (val << 16); + break; + case 0x53: + if (len == 1) + xga->accel.plane_mask = (xga->accel.plane_mask & 0x00ffffff) | (val << 24); + break; + + case 0x58: + if (len == 4) + xga->accel.frgd_color = val; + else if (len == 2) + xga->accel.frgd_color = (xga->accel.frgd_color & 0xffff0000) | val; + else + xga->accel.frgd_color = (xga->accel.frgd_color & 0xffffff00) | val; + break; + case 0x59: + if (len == 1) + xga->accel.frgd_color = (xga->accel.frgd_color & 0xffff00ff) | (val << 8); + break; + case 0x5a: + if (len == 2) + xga->accel.frgd_color = (xga->accel.frgd_color & 0x0000ffff) | (val << 16); + else + xga->accel.frgd_color = (xga->accel.frgd_color & 0xff00ffff) | (val << 16); + break; + case 0x5b: + if (len == 1) + xga->accel.frgd_color = (xga->accel.frgd_color & 0x00ffffff) | (val << 24); + break; + + case 0x5c: + if (len == 4) + xga->accel.bkgd_color = val; + else if (len == 2) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xffff0000) | val; + else + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xffffff00) | val; + break; + case 0x5d: + if (len == 1) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xffff00ff) | (val << 8); + break; + case 0x5e: + if (len == 2) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0x0000ffff) | (val << 16); + else + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xff00ffff) | (val << 16); + break; + case 0x5f: + if (len == 1) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0x00ffffff) | (val << 24); + break; + + case 0x60: + if (len == 4) { + xga->accel.blt_width = val & 0xffff; + xga->accel.blt_height = (val >> 16) & 0xffff; + } else if (len == 2) { + xga->accel.blt_width = val; + } else + xga->accel.blt_width = (xga->accel.blt_width & 0xff00) | val; + break; + case 0x61: + if (len == 1) + xga->accel.blt_width = (xga->accel.blt_width & 0xff) | (val << 8); + break; + + case 0x62: + if (len == 2) + xga->accel.blt_height = val; + else + xga->accel.blt_height = (xga->accel.blt_height & 0xff00) | val; + break; + case 0x63: + if (len == 1) + xga->accel.blt_height = (xga->accel.blt_height & 0xff) | (val << 8); + break; + + case 0x6c: + if (len == 4) { + xga->accel.mask_map_origin_x_off = val & 0xffff; + xga->accel.mask_map_origin_y_off = (val >> 16) & 0xffff; + } else if (len == 2) { + xga->accel.mask_map_origin_x_off = val; + } else + xga->accel.mask_map_origin_x_off = (xga->accel.mask_map_origin_x_off & 0xff00) | val; + break; + case 0x6d: + if (len == 1) + xga->accel.mask_map_origin_x_off = (xga->accel.mask_map_origin_x_off & 0xff) | (val << 8); + break; + + case 0x6e: + if (len == 2) + xga->accel.mask_map_origin_y_off = val; + else + xga->accel.mask_map_origin_y_off = (xga->accel.mask_map_origin_y_off & 0xff00) | val; + break; + case 0x6f: + if (len == 1) + xga->accel.mask_map_origin_y_off = (xga->accel.mask_map_origin_y_off & 0xff) | (val << 8); + break; + + case 0x70: + if (len == 4) { + xga->accel.src_map_x = val & 0xffff; + xga->accel.src_map_y = (val >> 16) & 0xffff; + } else if (len == 2) + xga->accel.src_map_x = val; + else + xga->accel.src_map_x = (xga->accel.src_map_x & 0xff00) | val; + break; + case 0x71: + if (len == 1) + xga->accel.src_map_x = (xga->accel.src_map_x & 0xff) | (val << 8); + break; + + case 0x72: + if (len == 2) + xga->accel.src_map_y = val; + else + xga->accel.src_map_y = (xga->accel.src_map_y & 0xff00) | val; + break; + case 0x73: + if (len == 1) + xga->accel.src_map_y = (xga->accel.src_map_y & 0xff) | (val << 8); + break; + + case 0x74: + if (len == 4) { + xga->accel.pat_map_x = val & 0xffff; + xga->accel.pat_map_y = (val >> 16) & 0xffff; + } else if (len == 2) + xga->accel.pat_map_x = val; + else + xga->accel.pat_map_x = (xga->accel.pat_map_x & 0xff00) | val; + break; + case 0x75: + if (len == 1) + xga->accel.pat_map_x = (xga->accel.pat_map_x & 0xff) | (val << 8); + break; + + case 0x76: + if (len == 2) + xga->accel.pat_map_y = val; + else + xga->accel.pat_map_y = (xga->accel.pat_map_y & 0xff00) | val; + break; + case 0x77: + if (len == 1) + xga->accel.pat_map_y = (xga->accel.pat_map_y & 0xff) | (val << 8); + break; + + case 0x78: + if (len == 4) { + xga->accel.dst_map_x = val & 0xffff; + xga->accel.dst_map_y = (val >> 16) & 0xffff; + } else if (len == 2) + xga->accel.dst_map_x = val; + else + xga->accel.dst_map_x = (xga->accel.dst_map_x & 0xff00) | val; + break; + case 0x79: + if (len == 1) + xga->accel.dst_map_x = (xga->accel.dst_map_x & 0xff) | (val << 8); + break; + + case 0x7a: + if (len == 2) + xga->accel.dst_map_y = val; + else + xga->accel.dst_map_y = (xga->accel.dst_map_y & 0xff00) | val; + break; + case 0x7b: + if (len == 1) + xga->accel.dst_map_y = (xga->accel.dst_map_y & 0xff) | (val << 8); + break; + + case 0x7c: + if (len == 4) { + xga->accel.command = val; +exec_command: + xga->accel.octant = xga->accel.command & 0x07; + xga->accel.draw_mode = xga->accel.command & 0x30; + xga->accel.mask_mode = xga->accel.command & 0xc0; + xga->accel.pat_src = ((xga->accel.command >> 12) & 0x0f); + xga->accel.dst_map = ((xga->accel.command >> 16) & 0x0f); + xga->accel.src_map = ((xga->accel.command >> 20) & 0x0f); + + //if (xga->accel.pat_src) { + // pclog("[%04X:%08X]: Accel Command = %02x, full = %08x, patwidth = %d, dstwidth = %d, srcwidth = %d, patheight = %d, dstheight = %d, srcheight = %d, px = %d, py = %d, dx = %d, dy = %d, sx = %d, sy = %d, patsrc = %d, dstmap = %d, srcmap = %d, dstbase = %08x, srcbase = %08x, patbase = %08x, dstformat = %x, srcformat = %x\n", + // CS, cpu_state.pc, ((xga->accel.command >> 24) & 0x0f), xga->accel.command, xga->accel.px_map_width[xga->accel.pat_src], + // xga->accel.px_map_width[xga->accel.dst_map], xga->accel.px_map_width[xga->accel.src_map], + // xga->accel.px_map_height[xga->accel.pat_src], xga->accel.px_map_height[xga->accel.dst_map], + // xga->accel.px_map_height[xga->accel.src_map], + // xga->accel.pat_map_x, xga->accel.pat_map_y, + // xga->accel.dst_map_x, xga->accel.dst_map_y, + // xga->accel.src_map_x, xga->accel.src_map_y, + // xga->accel.pat_src, xga->accel.dst_map, xga->accel.src_map, + // xga->accel.px_map_base[xga->accel.dst_map], xga->accel.px_map_base[xga->accel.src_map], xga->accel.px_map_base[xga->accel.pat_src], + // xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.px_map_format[xga->accel.src_map] & 0x0f); + // pclog("\n"); + //} + switch ((xga->accel.command >> 24) & 0x0f) { + case 3: /*Bresenham Line Draw Read*/ + //pclog("Line Draw Read\n"); + break; + case 4: /*Short Stroke Vectors*/ + break; + case 5: /*Bresenham Line Draw Write*/ + xga_line_draw_write(svga); + break; + case 8: /*BitBLT*/ + xga_bitblt(svga); + break; + case 9: /*Inverting BitBLT*/ + //pclog("Inverting BitBLT\n"); + break; + } + } else if (len == 2) { + xga->accel.command = (xga->accel.command & 0xffff0000) | val; + } else + xga->accel.command = (xga->accel.command & 0xffffff00) | val; + break; + case 0x7d: + if (len == 1) + xga->accel.command = (xga->accel.command & 0xffff00ff) | (val << 8); + break; + case 0x7e: + if (len == 2) { + xga->accel.command = (xga->accel.command & 0x0000ffff) | (val << 16); + goto exec_command; + } else + xga->accel.command = (xga->accel.command & 0xff00ffff) | (val << 16); + break; + case 0x7f: + if (len == 1) { + xga->accel.command = (xga->accel.command & 0x00ffffff) | (val << 24); + goto exec_command; + } + break; + } + } +} + +static void +xga_memio_writeb(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_mem_write(addr, val, xga, svga, 1); + //pclog("Write MEMIOB = %04x, val = %02x\n", addr & 0x7f, val); +} + +static void +xga_memio_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_mem_write(addr, val, xga, svga, 2); + //pclog("Write MEMIOW = %04x, val = %04x\n", addr & 0x7f, val); +} + +static void +xga_memio_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_mem_write(addr, val, xga, svga, 4); + //pclog("Write MEMIOL = %04x, val = %08x\n", addr & 0x7f, val); +} + +static uint8_t +xga_mem_read(uint32_t addr, xga_t *xga, svga_t *svga) +{ + uint8_t temp = 0; + + addr &= 0x1fff; + + if (addr < 0x1800) { + temp = xga->bios_rom.rom[addr]; + } else { + switch (addr & 0x7f) { + case 0x20: + temp = xga->accel.bres_err_term & 0xff; + break; + case 0x21: + temp = xga->accel.bres_err_term >> 8; + break; + case 0x22: + temp = xga->accel.bres_err_term >> 16; + break; + case 0x23: + temp = xga->accel.bres_err_term >> 24; + break; + + case 0x70: + temp = xga->accel.src_map_x & 0xff; + break; + case 0x71: + temp = xga->accel.src_map_x >> 8; + break; + + case 0x72: + temp = xga->accel.src_map_y & 0xff; + break; + case 0x73: + temp = xga->accel.src_map_y >> 8; + break; + + case 0x74: + temp = xga->accel.pat_map_x & 0xff; + break; + case 0x75: + temp = xga->accel.pat_map_x >> 8; + break; + + case 0x76: + temp = xga->accel.pat_map_y & 0xff; + break; + case 0x77: + temp = xga->accel.pat_map_y >> 8; + break; + + case 0x78: + temp = xga->accel.dst_map_x & 0xff; + break; + case 0x79: + temp = xga->accel.dst_map_x >> 8; + break; + + case 0x7a: + temp = xga->accel.dst_map_y & 0xff; + break; + case 0x7b: + temp = xga->accel.dst_map_y >> 8; + break; + } + } + + return temp; +} + +static uint8_t +xga_memio_readb(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint8_t temp; + + temp = xga_mem_read(addr, xga, svga); + + //pclog("[%04X:%08X]: Read MEMIOB = %04x, temp = %02x\n", CS, cpu_state.pc, addr, temp); + return temp; +} + +static uint16_t +xga_memio_readw(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint16_t temp; + + temp = xga_mem_read(addr, xga, svga); + temp |= (xga_mem_read(addr + 1, xga, svga) << 8); + + //pclog("[%04X:%08X]: Read MEMIOW = %04x, temp = %04x\n", CS, cpu_state.pc, addr, temp); + return temp; +} + +static uint32_t +xga_memio_readl(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint32_t temp; + + temp = xga_mem_read(addr, xga, svga); + temp |= (xga_mem_read(addr + 1, xga, svga) << 8); + temp |= (xga_mem_read(addr + 2, xga, svga) << 16); + temp |= (xga_mem_read(addr + 3, xga, svga) << 24); + + //pclog("Read MEMIOL = %04x, temp = %08x\n", addr, temp); + return temp; +} + +static void +xga_hwcursor_draw(svga_t *svga, int displine) +{ + xga_t *xga = &svga->xga; + uint8_t dat = 0; + int offset = xga->hwcursor_latch.x - xga->hwcursor_latch.xoff; + int x, x_pos, y_pos; + int comb = 0; + uint32_t *p; + int idx = (xga->cursor_data_on) ? 32 : 0; + + if (xga->interlace && xga->hwcursor_oddeven) + xga->hwcursor_latch.addr += 16; + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + for (x = 0; x < xga->hwcursor_latch.cur_xsize; x++) { + if (x >= idx) { + if (!(x & 0x03)) + dat = xga->sprite_data[xga->hwcursor_latch.addr & 0x3ff]; + + comb = (dat >> ((x & 0x03) << 1)) & 0x03; + + x_pos = offset + svga->x_add + x; + + switch (comb) { + case 0x00: + /* Cursor Color 1 */ + p[x_pos] = xga->hwc_color0; + break; + case 0x01: + /* Cursor Color 2 */ + p[x_pos] = xga->hwc_color1; + break; + case 0x03: + /* Complement */ + p[x_pos] ^= 0xffffff; + break; + } + } + + if ((x & 0x03) == 0x03) + xga->hwcursor_latch.addr++; + } + + if (xga->interlace && !xga->hwcursor_oddeven) + xga->hwcursor_latch.addr += 16; +} + +static void +xga_render_overscan_left(xga_t *xga, svga_t *svga) +{ + int i; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (svga->scrblank || (xga->h_disp == 0)) + return; + + for (i = 0; i < svga->x_add; i++) + buffer32->line[xga->displine + svga->y_add][i] = svga->overscan_color; +} + +static void +xga_render_overscan_right(xga_t *xga, svga_t *svga) +{ + int i, right; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (svga->scrblank || (xga->h_disp == 0)) + return; + + right = (overscan_x >> 1); + for (i = 0; i < right; i++) + buffer32->line[xga->displine + svga->y_add][svga->x_add + xga->h_disp + i] = svga->overscan_color; +} + +static void +xga_render_8bpp(xga_t *xga, svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (xga->changedvram[xga->ma >> 12] || xga->changedvram[(xga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; + + if (xga->firstline_draw == 2000) + xga->firstline_draw = xga->displine; + xga->lastline_draw = xga->displine; + + for (x = 0; x <= xga->h_disp; x += 8) { + dat = *(uint32_t *)(&xga->vram[xga->ma & xga->vram_mask]); + p[0] = svga->pallook[dat & 0xff]; + p[1] = svga->pallook[(dat >> 8) & 0xff]; + p[2] = svga->pallook[(dat >> 16) & 0xff]; + p[3] = svga->pallook[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + 4) & xga->vram_mask]); + p[4] = svga->pallook[dat & 0xff]; + p[5] = svga->pallook[(dat >> 8) & 0xff]; + p[6] = svga->pallook[(dat >> 16) & 0xff]; + p[7] = svga->pallook[(dat >> 24) & 0xff]; + + xga->ma += 8; + p += 8; + } + xga->ma &= xga->vram_mask; + } +} + +static void +xga_render_16bpp(xga_t *xga, svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (xga->changedvram[xga->ma >> 12] || xga->changedvram[(xga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; + + if (xga->firstline_draw == 2000) + xga->firstline_draw = xga->displine; + xga->lastline_draw = xga->displine; + + for (x = 0; x <= (xga->h_disp); x += 8) { + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1)) & xga->vram_mask]); + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1) + 4) & xga->vram_mask]); + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1) + 8) & xga->vram_mask]); + p[x + 4] = video_16to32[dat & 0xffff]; + p[x + 5] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1) + 12) & xga->vram_mask]); + p[x + 6] = video_16to32[dat & 0xffff]; + p[x + 7] = video_16to32[dat >> 16]; + } + xga->ma += x << 1; + xga->ma &= xga->vram_mask; + } +} + +static void +xga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_write(addr, val, svga); + return; + } + + addr &= xga->banked_mask; + addr += xga->write_bank; + + if (addr >= xga->vram_size) + return; + + cycles -= video_timing_write_b; + + xga->changedvram[(addr & xga->vram_mask) >> 12] = changeframecount; + xga->vram[addr & xga->vram_mask] = val; +} + +static void +xga_writeb(uint32_t addr, uint8_t val, void *p) +{ + //pclog("[%04X:%08X]: WriteB\n", CS, cpu_state.pc); + xga_write(addr, val, p); +} + +static void +xga_writew(uint32_t addr, uint16_t val, void *p) +{ + //pclog("[%04X:%08X]: WriteW\n", CS, cpu_state.pc); + xga_write(addr, val, p); + xga_write(addr + 1, val >> 8, p); +} + +static void +xga_writel(uint32_t addr, uint32_t val, void *p) +{ + //pclog("[%04X:%08X]: WriteL\n", CS, cpu_state.pc); + xga_write(addr, val, p); + xga_write(addr + 1, val >> 8, p); + xga_write(addr + 2, val >> 16, p); + xga_write(addr + 3, val >> 24, p); +} + +static void +xga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_write_linear(addr, val, svga); + return; + } + + addr &= svga->decode_mask; + + if (addr >= xga->vram_size) + return; + + cycles -= video_timing_write_b; + + xga->changedvram[(addr & xga->vram_mask) >> 12] = changeframecount; + xga->vram[addr & xga->vram_mask] = val; +} + +static void +xga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_writew_linear(addr, val, svga); + return; + } + + if (xga->linear_endian_reverse) { + if (xga->accel.px_map_format[xga->accel.dst_map] == 0x0c) { + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); + } else if (xga->accel.px_map_format[xga->accel.dst_map] == 4) { + xga_write_linear(addr + 1, val, p); + xga_write_linear(addr, val >> 8, p); + } else { + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); + } + } else { + if (xga->accel.px_map_format[xga->accel.dst_map] == 0x0c) { + xga_write_linear(addr + 1, val, p); + xga_write_linear(addr, val >> 8, p); + } else if (xga->accel.px_map_format[xga->accel.dst_map] == 4) { + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); + } else { + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); + } + } +} + +static void +xga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_writel_linear(addr, val, svga); + return; + } + + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); + xga_write_linear(addr + 2, val >> 16, p); + xga_write_linear(addr + 3, val >> 24, p); +} + +static uint8_t +xga_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_read(addr, svga); + + addr &= xga->banked_mask; + addr += xga->read_bank; + + if (addr >= xga->vram_size) + return 0xff; + + cycles -= video_timing_read_b; + + return xga->vram[addr & xga->vram_mask]; +} + +static uint8_t +xga_readb(uint32_t addr, void *p) +{ + uint8_t ret; + + ret = xga_read(addr, p); + + return ret; +} + +static uint16_t +xga_readw(uint32_t addr, void *p) +{ + uint16_t ret; + + ret = xga_read(addr, p); + ret |= (xga_read(addr + 1, p) << 8); + + return ret; +} + +static uint32_t +xga_readl(uint32_t addr, void *p) +{ + uint32_t ret; + + ret = xga_read(addr, p); + ret |= (xga_read(addr + 1, p) << 8); + ret |= (xga_read(addr + 2, p) << 16); + ret |= (xga_read(addr + 3, p) << 24); + + return ret; +} + +static uint8_t +xga_read_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_read_linear(addr, svga); + + addr &= svga->decode_mask; + + if (addr >= xga->vram_size) + return 0xff; + + cycles -= video_timing_read_b; + + return xga->vram[addr & xga->vram_mask]; +} + +static uint16_t +xga_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint16_t ret; + + if (!xga->on) + return svga_readw_linear(addr, svga); + + if (xga->linear_endian_reverse) { + if (xga->accel.px_map_format[xga->accel.src_map] == 0x0c) { + ret = xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8); + } else if (xga->accel.px_map_format[xga->accel.src_map] == 4) { + ret = xga_read_linear(addr + 1, p) | (xga_read_linear(addr, p) << 8); + } else + ret = xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8); + } else { + if (xga->accel.px_map_format[xga->accel.src_map] == 0x0c) { + ret = xga_read_linear(addr + 1, p) | (xga_read_linear(addr, p) << 8); + } else if (xga->accel.px_map_format[xga->accel.src_map] == 4) { + ret = xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8); + } else + ret = xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8); + } + return ret; +} + +static uint32_t +xga_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_readl_linear(addr, svga); + + return xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8) | + (xga_read_linear(addr + 2, p) << 16) | (xga_read_linear(addr + 3, p) << 24); +} + +static void +xga_do_render(svga_t *svga) +{ + xga_t *xga = &svga->xga; + + switch (xga->disp_cntl_2 & 7) { + case 3: + xga_render_8bpp(xga, svga); + break; + case 4: + xga_render_16bpp(xga, svga); + break; + } + + svga->x_add = (overscan_x >> 1); + xga_render_overscan_left(xga, svga); + xga_render_overscan_right(xga, svga); + svga->x_add = (overscan_x >> 1); + + if (xga->hwcursor_on) { + xga_hwcursor_draw(svga, xga->displine + svga->y_add); + xga->hwcursor_on--; + if (xga->hwcursor_on && xga->interlace) + xga->hwcursor_on--; + } +} + +void +xga_poll(xga_t *xga, svga_t *svga) +{ + uint32_t x; + int wx, wy; + + if (!xga->linepos) { + if (xga->displine == xga->hwcursor_latch.y && xga->hwcursor_latch.ena) { + xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - (xga->cursor_data_on ? 32 : 0); + xga->hwcursor_oddeven = 0; + } + + if (xga->displine == (xga->hwcursor_latch.y + 1) && xga->hwcursor_latch.ena && + xga->interlace) { + xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - (xga->cursor_data_on ? 33 : 1); + xga->hwcursor_oddeven = 1; + } + + timer_advance_u64(&svga->timer, svga->dispofftime); + xga->linepos = 1; + + if (xga->dispon) { + xga->h_disp_on = 1; + + xga->ma &= xga->vram_mask; + + if (xga->firstline == 2000) { + xga->firstline = xga->displine; + video_wait_for_buffer(); + } + + if (xga->hwcursor_on) { + xga->changedvram[xga->ma >> 12] = xga->changedvram[(xga->ma >> 12) + 1] = + xga->interlace ? 3 : 2; + } + + xga_do_render(svga); + + if (xga->lastline < xga->displine) + xga->lastline = xga->displine; + } + + xga->displine++; + if (xga->interlace) + xga->displine++; + if (xga->displine > 1500) + xga->displine = 0; + } else { + timer_advance_u64(&svga->timer, svga->dispontime); + xga->h_disp_on = 0; + + xga->linepos = 0; + if (xga->dispon) { + if (xga->sc == xga->rowcount) { + xga->sc = 0; + + if ((xga->disp_cntl_2 & 7) == 4) { + xga->maback += (xga->rowoffset << 4); + if (xga->interlace) + xga->maback += (xga->rowoffset << 4); + } else { + xga->maback += (xga->rowoffset << 3); + if (xga->interlace) + xga->maback += (xga->rowoffset << 3); + } + xga->maback &= xga->vram_mask; + xga->ma = xga->maback; + } else { + xga->sc++; + xga->sc &= 0x1f; + xga->ma = xga->maback; + } + } + + xga->vc++; + xga->vc &= 2047; + + if (xga->vc == xga->split) { + if (xga->interlace && xga->oddeven) + xga->ma = xga->maback = (xga->rowoffset << 1); + else + xga->ma = xga->maback = 0; + xga->ma = (xga->ma << 2); + xga->maback = (xga->maback << 2); + + xga->sc = 0; + } + if (xga->vc == xga->dispend) { + xga->dispon = 0; + + for (x = 0; x < ((xga->vram_mask + 1) >> 12); x++) { + if (xga->changedvram[x]) + xga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (xga->vc == xga->v_syncstart) { + xga->dispon = 0; + x = xga->h_disp; + + if (xga->interlace && !xga->oddeven) + xga->lastline++; + if (xga->interlace && xga->oddeven) + xga->firstline--; + + wx = x; + + wy = xga->lastline - xga->firstline; + svga_doblit(wx, wy, svga); + + xga->firstline = 2000; + xga->lastline = 0; + + xga->firstline_draw = 2000; + xga->lastline_draw = 0; + + xga->oddeven ^= 1; + + changeframecount = xga->interlace ? 3 : 2; + + if (xga->interlace && xga->oddeven) + xga->ma = xga->maback = xga->ma_latch + (xga->rowoffset << 1); + else + xga->ma = xga->maback = xga->ma_latch; + + xga->ma = (xga->ma << 2); + xga->maback = (xga->maback << 2); + } + if (xga->vc == xga->v_total) { + xga->vc = 0; + xga->sc = 0; + xga->dispon = 1; + xga->displine = (xga->interlace && xga->oddeven) ? 1 : 0; + + svga->x_add = (overscan_x >> 1); + + xga->hwcursor_on = 0; + xga->hwcursor_latch = xga->hwcursor; + } + } +} + +static uint8_t +xga_mca_read(int port, void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + //pclog("[%04X:%08X]: POS Read Port = %x, val = %02x\n", CS, cpu_state.pc, port & 7, xga->pos_regs[port & 7]); + return (xga->pos_regs[port & 7]); +} + +static void +xga_mca_write(int port, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) + return; + + io_removehandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + mem_mapping_disable(&xga->bios_rom.mapping); + mem_mapping_disable(&xga->memio_mapping); + xga->on = 0; + vga_on = 1; + + /* Save the MCA register value. */ + xga->pos_regs[port & 7] = val; + if (!(xga->pos_regs[4] & 1)) /*MCA 4MB addressing on systems with more than 16MB of memory*/ + xga->pos_regs[4] |= 1; + + //pclog("[%04X:%08X]: POS Write Port = %x, val = %02x, linear base = %08x, instance = %d, rom addr = %05x\n", CS, cpu_state.pc, port & 7, val, xga->linear_base, xga->instance, xga->rom_addr); + if (xga->pos_regs[2] & 1) { + xga->instance = (xga->pos_regs[2] & 0x0e) >> 1; + xga->base_addr_1mb = (xga->pos_regs[5] & 0x0f) << 20; + xga->linear_base = ((xga->pos_regs[4] & 0xfe) * 0x1000000) + (xga->instance << 22); + xga->rom_addr = 0xc0000 + (((xga->pos_regs[2] & 0xf0) >> 4) * 0x2000); + + io_sethandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + mem_mapping_set_addr(&xga->bios_rom.mapping, xga->rom_addr, 0x2000); + mem_mapping_set_addr(&xga->memio_mapping, xga->rom_addr + 0x1c00 + (xga->instance * 0x80), 0x80); + } +} + +static uint8_t +xga_mca_feedb(void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + return xga->pos_regs[2] & 1; +} + +static void +xga_mca_reset(void *p) +{ + svga_t *svga = (svga_t *)p; + + xga_mca_write(0x102, 0, svga); +} + +static uint8_t +xga_pos_in(uint16_t addr, void *priv) +{ + svga_t *svga = (svga_t *)priv; + + return (xga_mca_read(addr, svga)); +} + +static void +*xga_init(const device_t *info) +{ + svga_t *svga = svga_get_pri(); + xga_t *xga = &svga->xga; + FILE *f; + uint32_t temp; + uint32_t initial_bios_addr = device_get_config_hex20("init_bios_addr"); + uint8_t *rom = NULL; + + xga->type = device_get_config_int("type"); + xga->bus = info->flags; + + xga->vram_size = (1024 << 10); + xga->vram_mask = xga->vram_size - 1; + xga->vram = calloc(xga->vram_size, 1); + xga->changedvram = calloc(xga->vram_size >> 12, 1); + xga->on = 0; + xga->hwcursor.cur_xsize = 64; + xga->hwcursor.cur_ysize = 64; + xga->bios_rom.sz = 0x2000; + + f = rom_fopen(xga->type ? XGA2_BIOS_PATH : XGA_BIOS_PATH, "rb"); + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + rom = malloc(xga->bios_rom.sz); + memset(rom, 0xff, xga->bios_rom.sz); + (void)fread(rom, xga->bios_rom.sz, 1, f); + temp -= xga->bios_rom.sz; + (void)fclose(f); + + xga->bios_rom.rom = rom; + xga->bios_rom.mask = xga->bios_rom.sz - 1; + if (f != NULL) { + free(rom); + } + + xga->base_addr_1mb = 0; + if (info->flags & DEVICE_MCA) { + xga->linear_base = 0; + xga->instance = 0; + xga->rom_addr = 0; + mem_mapping_add(&xga->bios_rom.mapping, + initial_bios_addr, xga->bios_rom.sz, + rom_read, rom_readw, rom_readl, + NULL, NULL, NULL, + xga->bios_rom.rom, MEM_MAPPING_EXTERNAL, &xga->bios_rom); + } else { + xga->pos_regs[2] = 1 | 0x0c | 0xf0; + xga->instance = (xga->pos_regs[2] & 0x0e) >> 1; + xga->pos_regs[4] = 1 | 2; + xga->linear_base = ((xga->pos_regs[4] & 0xfe) * 0x1000000) + (xga->instance << 22); + xga->rom_addr = 0xc0000 + (((xga->pos_regs[2] & 0xf0) >> 4) * 0x2000); + } + + mem_mapping_add(&xga->video_mapping, 0, 0, xga_readb, xga_readw, xga_readl, + xga_writeb, xga_writew, xga_writel, + NULL, MEM_MAPPING_EXTERNAL, svga); + mem_mapping_add(&xga->linear_mapping, 0, 0, xga_read_linear, xga_readw_linear, xga_readl_linear, + xga_write_linear, xga_writew_linear, xga_writel_linear, + NULL, MEM_MAPPING_EXTERNAL, svga); + mem_mapping_add(&xga->memio_mapping, 0, 0, xga_memio_readb, xga_memio_readw, xga_memio_readl, + xga_memio_writeb, xga_memio_writew, xga_memio_writel, + xga->bios_rom.rom, MEM_MAPPING_EXTERNAL, svga); + + mem_mapping_disable(&xga->video_mapping); + mem_mapping_disable(&xga->linear_mapping); + mem_mapping_disable(&xga->memio_mapping); + + xga->pos_regs[0] = xga->type ? 0xda : 0xdb; + xga->pos_regs[1] = 0x8f; + + if (xga->bus & DEVICE_MCA) { + mca_add(xga_mca_read, xga_mca_write, xga_mca_feedb, xga_mca_reset, svga); + } else { + io_sethandler(0x0100, 0x0008, xga_pos_in, NULL, NULL, NULL, NULL, NULL, svga); + io_sethandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + mem_mapping_set_addr(&xga->memio_mapping, xga->rom_addr + 0x1c00 + (xga->instance * 0x80), 0x80); + } + + return svga; +} + +static void +xga_close(void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (svga) { + free(xga->vram); + free(xga->changedvram); + } +} + +static int +xga_available(void) +{ + return rom_present(XGA_BIOS_PATH) && rom_present(XGA2_BIOS_PATH); +} + +static void +xga_speed_changed(void *p) +{ + svga_t *svga = (svga_t *)p; + + svga_recalctimings(svga); +} + +static void +xga_force_redraw(void *p) +{ + svga_t *svga = (svga_t *)p; + + svga->fullchange = changeframecount; +} + +static const device_config_t xga_configuration[] = { + // clang-format off + { + .name = "init_bios_addr", + .description = "Initial MCA BIOS Address (before POS configuration)", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xc0000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "C000H", .value = 0xc0000 }, + { .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 = "" } + }, + }, + { + .name = "type", + .description = "XGA type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "XGA-1", + .value = 0 + }, + { + .description = "XGA-2", + .value = 1 + }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t xga_device = { + .name = "XGA (MCA)", + .internal_name = "xga_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = xga_init, + .close = xga_close, + .reset = NULL, + { .available = xga_available }, + .speed_changed = xga_speed_changed, + .force_redraw = xga_force_redraw, + .config = xga_configuration +}; + +const device_t xga_isa_device = { + .name = "XGA (ISA)", + .internal_name = "xga_isa", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = xga_init, + .close = xga_close, + .reset = NULL, + { .available = xga_available }, + .speed_changed = xga_speed_changed, + .force_redraw = xga_force_redraw, + .config = xga_configuration +}; + +void +xga_device_add(void) +{ + if (!xga_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&xga_device); + else + device_add(&xga_isa_device); +} diff --git a/src/video/video.c b/src/video/video.c index ce77e9abf..1bfb148a3 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -48,6 +48,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ +#include #define PNG_DEBUG 0 #include #include @@ -66,54 +67,45 @@ #include <86box/rom.h> #include <86box/config.h> #include <86box/timer.h> +#include <86box/path.h> #include <86box/plat.h> +#include <86box/ui.h> +#include <86box/thread.h> #include <86box/video.h> #include <86box/vid_svga.h> +#include -volatile int screenshots = 0; -bitmap_t *buffer32 = NULL; -bitmap_t *render_buffer = NULL; -uint8_t fontdat[2048][8]; /* IBM CGA font */ -uint8_t fontdatm[2048][16]; /* IBM MDA font */ -uint8_t fontdatw[512][32]; /* Wyse700 font */ -uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ -uint8_t fontdat12x18[256][36]; /* IM1024 font */ -dbcs_font_t *fontdatksc5601 = NULL; /* Korean KSC-5601 font */ -dbcs_font_t *fontdatksc5601_user = NULL; /* Korean KSC-5601 user defined font */ -uint32_t pal_lookup[256]; -int xsize = 1, - ysize = 1; -int cga_palette = 0, - herc_blend = 0; -uint32_t *video_6to8 = NULL, - *video_8togs = NULL, - *video_8to32 = NULL, - *video_15to32 = NULL, - *video_16to32 = NULL; -int egareads = 0, - egawrites = 0, - changeframecount = 2; -int frames = 0; -int fullchange = 0; -uint8_t edatlookup[4][4]; -int overscan_x = 0, - overscan_y = 0; -int video_timing_read_b = 0, - video_timing_read_w = 0, - video_timing_read_l = 0; -int video_timing_write_b = 0, - video_timing_write_w = 0, - video_timing_write_l = 0; -int video_res_x = 0, - video_res_y = 0, - video_bpp = 0; -static int video_force_resize; -int video_grayscale = 0; -int video_graytype = 0; -static int vid_type; -static const video_timings_t *vid_timings; -static uint32_t cga_2_table[16]; +volatile int screenshots = 0; +uint8_t edatlookup[4][4]; +uint8_t fontdat[2048][8]; /* IBM CGA font */ +uint8_t fontdatm[2048][16]; /* IBM MDA font */ +uint8_t fontdatw[512][32]; /* Wyse700 font */ +uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ +uint8_t fontdat12x18[256][36]; /* IM1024 font */ +dbcs_font_t *fontdatksc5601 = NULL; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601_user = NULL; /* Korean KSC-5601 user defined font */ +int herc_blend = 0; +int frames = 0; +int fullchange = 0; +int video_grayscale = 0; +int video_graytype = 0; +int monitor_index_global = 0; +uint32_t *video_6to8 = NULL, + *video_8togs = NULL, + *video_8to32 = NULL, + *video_15to32 = NULL, + *video_16to32 = NULL; +monitor_t monitors[MONITORS_NUM]; +monitor_settings_t monitor_settings[MONITORS_NUM]; +atomic_bool doresize_monitors[MONITORS_NUM]; + + +#ifdef _WIN32 +void * __cdecl (*video_copy)(void *_Dst, const void *_Src, size_t _Size) = memcpy; +#else +void * (*video_copy)(void *__restrict, const void *__restrict, size_t); +#endif PALETTE cgapal = { @@ -131,7 +123,7 @@ PALETTE cgapal = { {42,0,21}, {21,10,21}, {42,0,42}, {42,0,63}, {21,21,21}, {21,63,21}, {42,21,42}, {21,63,63}, {63,0,0}, {42,42,0}, {63,21,42}, {41,41,41}, - + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, @@ -244,19 +236,24 @@ const uint32_t shade[5][256] = }; -static struct { - int x, y, y1, y2, w, h; +typedef struct blit_data_struct { + int x, y, w, h; int busy; int buffer_in_use; + int thread_run; + int monitor_index; thread_t *blit_thread; event_t *wake_blit_thread; event_t *blit_complete; event_t *buffer_not_in_use; -} blit_data; +} blit_data_t; -static void (*blit_func)(int x, int y, int y1, int y2, int w, int h); +static uint32_t cga_2_table[16]; + + +static void (*blit_func)(int x, int y, int w, int h, int monitor_index); #ifdef ENABLE_VIDEO_LOG @@ -279,125 +276,116 @@ video_log(const char *fmt, ...) #endif -static -void blit_thread(void *param) -{ - while (1) { - thread_wait_event(blit_data.wake_blit_thread, -1); - thread_reset_event(blit_data.wake_blit_thread); - - if (blit_func) - blit_func(blit_data.x, blit_data.y, - blit_data.y1, blit_data.y2, - blit_data.w, blit_data.h); - - blit_data.busy = 0; - thread_set_event(blit_data.blit_complete); - } -} - - void -video_setblit(void(*blit)(int,int,int,int,int,int)) +video_setblit(void(*blit)(int,int,int,int,int)) { blit_func = blit; } void -video_blit_complete(void) +video_blit_complete_monitor(int monitor_index) { - blit_data.buffer_in_use = 0; + blit_data_t* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; + blit_data_ptr->buffer_in_use = 0; - thread_set_event(blit_data.buffer_not_in_use); + thread_set_event(blit_data_ptr->buffer_not_in_use); } void -video_wait_for_blit(void) +video_wait_for_blit_monitor(int monitor_index) { - while (blit_data.busy) - thread_wait_event(blit_data.blit_complete, -1); - thread_reset_event(blit_data.blit_complete); + blit_data_t* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; + + while (blit_data_ptr->busy) + thread_wait_event(blit_data_ptr->blit_complete, -1); + thread_reset_event(blit_data_ptr->blit_complete); } void -video_wait_for_buffer(void) +video_wait_for_buffer_monitor(int monitor_index) { - while (blit_data.buffer_in_use) - thread_wait_event(blit_data.buffer_not_in_use, -1); - thread_reset_event(blit_data.buffer_not_in_use); + blit_data_t* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; + + while (blit_data_ptr->buffer_in_use) + thread_wait_event(blit_data_ptr->buffer_not_in_use, -1); + thread_reset_event(blit_data_ptr->buffer_not_in_use); } -static png_structp png_ptr; -static png_infop info_ptr; +static png_structp png_ptr[MONITORS_NUM]; +static png_infop info_ptr[MONITORS_NUM]; static void -video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h) +video_take_screenshot_monitor(const char *fn, uint32_t *buf, int start_x, int start_y, int row_len, int monitor_index) { int i, x, y; png_bytep *b_rgb = NULL; FILE *fp = NULL; uint32_t temp = 0x00000000; + blit_data_t* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; /* create file */ - fp = plat_fopen((wchar_t *) fn, (wchar_t *) L"wb"); + fp = plat_fopen((char *) fn, (char *) "wb"); if (!fp) { - video_log("[video_take_screenshot] File %ls could not be opened for writing", fn); + video_log("[video_take_screenshot] File %s could not be opened for writing", fn); return; } /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_ptr[monitor_index] = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { + if (!png_ptr[monitor_index]) { video_log("[video_take_screenshot] png_create_write_struct failed"); fclose(fp); return; } - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { + info_ptr[monitor_index] = png_create_info_struct(png_ptr[monitor_index]); + if (!info_ptr[monitor_index]) { video_log("[video_take_screenshot] png_create_info_struct failed"); fclose(fp); return; } - png_init_io(png_ptr, fp); + png_init_io(png_ptr[monitor_index], fp); - png_set_IHDR(png_ptr, info_ptr, w, h, + png_set_IHDR(png_ptr[monitor_index], info_ptr[monitor_index], blit_data_ptr->w, blit_data_ptr->h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * h); + b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * blit_data_ptr->h); if (b_rgb == NULL) { video_log("[video_take_screenshot] Unable to Allocate RGB Bitmap Memory"); fclose(fp); return; } - for (y = 0; y < h; ++y) { - b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); - for (x = 0; x < w; ++x) { - temp = render_buffer->line[y + starty][x + startx]; - - b_rgb[y][(x) * 3 + 0] = (temp >> 16) & 0xff; - b_rgb[y][(x) * 3 + 1] = (temp >> 8) & 0xff; - b_rgb[y][(x) * 3 + 2] = temp & 0xff; + for (y = 0; y < blit_data_ptr->h; ++y) { + b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr[monitor_index], info_ptr[monitor_index])); + for (x = 0; x < blit_data_ptr->w; ++x) { + if (buf == NULL) + memset(&(b_rgb[y][x * 3]), 0x00, 3); + else { + temp = buf[((start_y + y) * row_len) + start_x + x]; + b_rgb[y][x * 3] = (temp >> 16) & 0xff; + b_rgb[y][(x * 3) + 1] = (temp >> 8) & 0xff; + b_rgb[y][(x * 3) + 2] = temp & 0xff; + } } } - png_write_info(png_ptr, info_ptr); + png_write_info(png_ptr[monitor_index], info_ptr[monitor_index]); - png_write_image(png_ptr, b_rgb); + png_write_image(png_ptr[monitor_index], b_rgb); - png_write_end(png_ptr, NULL); + png_write_end(png_ptr[monitor_index], NULL); /* cleanup heap allocation */ - for (i = 0; i < h; i++) + for (i = 0; i < blit_data_ptr->h; i++) if (b_rgb[i]) free(b_rgb[i]); if (b_rgb) free(b_rgb); @@ -406,82 +394,106 @@ video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h) } -static void -video_screenshot(int x, int y, int w, int h) +void +video_screenshot_monitor(uint32_t *buf, int start_x, int start_y, int row_len, int monitor_index) { - wchar_t path[1024], fn[128]; + char path[1024], fn[256]; memset(fn, 0, sizeof(fn)); memset(path, 0, sizeof(path)); - plat_append_filename(path, usr_path, SCREENSHOT_PATH); + path_append_filename(path, usr_path, SCREENSHOT_PATH); if (! plat_dir_check(path)) - plat_dir_create(path); + plat_dir_create(path); - wcscat(path, L"\\"); + path_slash(path); + strcat(path, "Monitor_"); + snprintf(&path[strlen(path)], 42, "%d_", monitor_index + 1); - plat_tempfile(fn, NULL, L".png"); - wcscat(path, fn); + plat_tempfile(fn, NULL, ".png"); + strcat(path, fn); - video_log("taking screenshot to: %S\n", path); + video_log("taking screenshot to: %s\n", path); - video_take_screenshot((const wchar_t *) path, x, y, w, h); - png_destroy_write_struct(&png_ptr, &info_ptr); + video_take_screenshot_monitor((const char *) path, buf, start_x, start_y, row_len, monitor_index); + png_destroy_write_struct(&png_ptr[monitor_index], &info_ptr[monitor_index]); + + atomic_fetch_sub(&monitors[monitor_index].mon_screenshots, 1); +} + +void +video_screenshot(uint32_t *buf, int start_x, int start_y, int row_len) +{ + video_screenshot_monitor(buf, start_x, start_y, row_len, 0); } -static void -video_transform_copy(uint32_t *dst, uint32_t *src, int len) +#ifdef _WIN32 +void * __cdecl +video_transform_copy(void *_Dst, const void *_Src, size_t _Size) +#else +void * +video_transform_copy(void *__restrict _Dst, const void *__restrict _Src, size_t _Size) +#endif { int i; + uint32_t *dest_ex = (uint32_t *) _Dst; + uint32_t *src_ex = (uint32_t *) _Src; - for (i = 0; i < len; i++) { - *dst = video_color_transform(*src); - dst++; - src++; + _Size /= sizeof(uint32_t); + + if ((dest_ex != NULL) && (src_ex != NULL)) { + for (i = 0; i < _Size; i++) { + *dest_ex = video_color_transform(*src_ex); + dest_ex++; + src_ex++; + } + } + + return _Dst; +} + + +static +void blit_thread(void *param) +{ + blit_data_t* data = param; + while (data->thread_run) { + thread_wait_event(data->wake_blit_thread, -1); + thread_reset_event(data->wake_blit_thread); + MTR_BEGIN("video", "blit_thread"); + + if (blit_func) + blit_func(data->x, data->y, data->w, data->h, data->monitor_index); + + data->busy = 0; + + MTR_END("video", "blit_thread"); + thread_set_event(data->blit_complete); } } void -video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +video_blit_memtoscreen_monitor(int x, int y, int w, int h, int monitor_index) { - int yy; - - if ((w > 0) && (h > 0)) { - for (yy = 0; yy < h; yy++) { - if (((y + yy) >= 0) && ((y + yy) < buffer32->h)) { - if (video_grayscale || invert_display) - video_transform_copy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w); - else - memcpy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w << 2); - } - } - } - - if (screenshots) { - if (render_buffer != NULL) - video_screenshot(x, y, w, h); - screenshots--; - video_log("screenshot taken, %i left\n", screenshots); - } + MTR_BEGIN("video", "video_blit_memtoscreen"); if ((w <= 0) || (h <= 0)) - return; + return; - video_wait_for_blit(); + video_wait_for_blit_monitor(monitor_index); - blit_data.busy = 1; - blit_data.buffer_in_use = 1; - blit_data.x = x; - blit_data.y = y; - blit_data.y1 = y1; - blit_data.y2 = y2; - blit_data.w = w; - blit_data.h = h; + monitors[monitor_index].mon_blit_data_ptr->busy = 1; + monitors[monitor_index].mon_blit_data_ptr->buffer_in_use = 1; + monitors[monitor_index].mon_blit_data_ptr->x = x; + monitors[monitor_index].mon_blit_data_ptr->y = y; + monitors[monitor_index].mon_blit_data_ptr->w = w; + monitors[monitor_index].mon_blit_data_ptr->h = h; - thread_set_event(blit_data.wake_blit_thread); + thread_set_event(monitors[monitor_index].mon_blit_data_ptr->wake_blit_thread); + MTR_END("video", "video_blit_memtoscreen"); } @@ -514,7 +526,7 @@ uint32_t pixel_to_color(uint8_t *pixels32, uint8_t pos) void -video_blend(int x, int y) +video_blend_monitor(int x, int y, int monitor_index) { int xx; uint32_t pixels32_1, pixels32_2; @@ -522,145 +534,179 @@ video_blend(int x, int y) static unsigned int carry = 0; if (!herc_blend) - return; + return; if (!x) - carry = 0; + carry = 0; - val1 = pixels8(&(buffer32->line[y][x])); + val1 = pixels8(&(monitors[monitor_index].target_buffer->line[y][x])); val2 = (val1 >> 1) + carry; carry = (val1 & 1) << 7; pixels32_1 = cga_2_table[val1 >> 4] + cga_2_table[val2 >> 4]; pixels32_2 = cga_2_table[val1 & 0xf] + cga_2_table[val2 & 0xf]; for (xx = 0; xx < 4; xx++) { - buffer32->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); - buffer32->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); + monitors[monitor_index].target_buffer->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); + monitors[monitor_index].target_buffer->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); } } + void -video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h) +video_blit_memtoscreen_8_monitor(int x, int y, int w, int h, int monitor_index) { int yy, xx; if ((w > 0) && (h > 0)) { - for (yy = 0; yy < h; yy++) { - if ((y + yy) >= 0 && (y + yy) < buffer32->h) { - for (xx = 0; xx < w; xx++) { - if (buffer32->line[y + yy][x + xx] <= 0xff) - buffer32->line[y + yy][x + xx] = pal_lookup[buffer32->line[y + yy][x + xx]]; - else - buffer32->line[y + yy][x + xx] = 0x00000000; - } - } - } + for (yy = 0; yy < h; yy++) { + if ((y + yy) >= 0 && (y + yy) < monitors[monitor_index].target_buffer->h) { + for (xx = 0; xx < w; xx++) { + if (monitors[monitor_index].target_buffer->line[y + yy][x + xx] <= 0xff) + monitors[monitor_index].target_buffer->line[y + yy][x + xx] = monitors[monitor_index].mon_pal_lookup[monitors[monitor_index].target_buffer->line[y + yy][x + xx]]; + else + monitors[monitor_index].target_buffer->line[y + yy][x + xx] = 0x00000000; + } + } + } } - video_blit_memtoscreen(x, y, y1, y2, w, h); + video_blit_memtoscreen_monitor(x, y, w, h, monitor_index); } void -cgapal_rebuild(void) +cgapal_rebuild_monitor(int monitor_index) { int c; + uint32_t* palette_lookup = monitors[monitor_index].mon_pal_lookup; + int cga_palette_monitor = 0; /* We cannot do this (yet) if we have not been enabled yet. */ if (video_6to8 == NULL) return; + if (monitors[monitor_index].target_buffer == NULL || + monitors[monitor_index].mon_cga_palette == NULL) return; + + cga_palette_monitor = *monitors[monitor_index].mon_cga_palette; + for (c=0; c<256; c++) { - pal_lookup[c] = makecol(video_6to8[cgapal[c].r], + palette_lookup[c] = makecol(video_6to8[cgapal[c].r], video_6to8[cgapal[c].g], video_6to8[cgapal[c].b]); } - if ((cga_palette > 1) && (cga_palette < 7)) { + if ((cga_palette_monitor > 1) && (cga_palette_monitor < 7)) { if (vid_cga_contrast != 0) { for (c = 0; c < 16; c++) { - pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); - pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); - pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); - pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); + palette_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); + palette_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); + palette_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); + palette_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); } } else { for (c = 0; c < 16; c++) { - pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); - pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); - pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); - pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); + palette_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); + palette_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); + palette_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); + palette_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); } } } - if (cga_palette == 7) - pal_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); + if (cga_palette_monitor == 7) + palette_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); } void -video_inform(int type, const video_timings_t *ptr) +video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index) { - vid_type = type; - vid_timings = ptr; + monitor_t* monitor = &monitors[monitor_index]; + monitor->mon_vid_type = type; + monitor->mon_vid_timings = ptr; } int -video_get_type(void) +video_get_type_monitor(int monitor_index) { - return vid_type; + return monitors[monitor_index].mon_vid_type; } void video_update_timing(void) { - if (!vid_timings) - return; + const video_timings_t* monitor_vid_timings = NULL; + int *vid_timing_read_b = NULL; + int *vid_timing_read_l = NULL; + int *vid_timing_read_w = NULL; + int *vid_timing_write_b = NULL; + int *vid_timing_write_l = NULL; + int *vid_timing_write_w = NULL; + int i = 0; - if (vid_timings->type == VIDEO_ISA) { - video_timing_read_b = ISA_CYCLES(vid_timings->read_b); - video_timing_read_w = ISA_CYCLES(vid_timings->read_w); - video_timing_read_l = ISA_CYCLES(vid_timings->read_l); - video_timing_write_b = ISA_CYCLES(vid_timings->write_b); - video_timing_write_w = ISA_CYCLES(vid_timings->write_w); - video_timing_write_l = ISA_CYCLES(vid_timings->write_l); - } else if (vid_timings->type == VIDEO_PCI) { - video_timing_read_b = (int)(pci_timing * vid_timings->read_b); - video_timing_read_w = (int)(pci_timing * vid_timings->read_w); - video_timing_read_l = (int)(pci_timing * vid_timings->read_l); - video_timing_write_b = (int)(pci_timing * vid_timings->write_b); - video_timing_write_w = (int)(pci_timing * vid_timings->write_w); - video_timing_write_l = (int)(pci_timing * vid_timings->write_l); - } else { - video_timing_read_b = (int)(bus_timing * vid_timings->read_b); - video_timing_read_w = (int)(bus_timing * vid_timings->read_w); - video_timing_read_l = (int)(bus_timing * vid_timings->read_l); - video_timing_write_b = (int)(bus_timing * vid_timings->write_b); - video_timing_write_w = (int)(bus_timing * vid_timings->write_w); - video_timing_write_l = (int)(bus_timing * vid_timings->write_l); - } + for (i = 0; i < MONITORS_NUM; i++) { + monitor_vid_timings = monitors[i].mon_vid_timings; + if (!monitor_vid_timings) + continue; + vid_timing_read_b = &monitors[i].mon_video_timing_read_b; + vid_timing_read_l = &monitors[i].mon_video_timing_read_l; + vid_timing_read_w = &monitors[i].mon_video_timing_read_w; + vid_timing_write_b = &monitors[i].mon_video_timing_write_b; + vid_timing_write_l = &monitors[i].mon_video_timing_write_l; + vid_timing_write_w = &monitors[i].mon_video_timing_write_w; - if (cpu_16bitbus) { - video_timing_read_l = video_timing_read_w * 2; - video_timing_write_l = video_timing_write_w * 2; + if (monitor_vid_timings->type == VIDEO_ISA) { + *vid_timing_read_b = ISA_CYCLES(monitor_vid_timings->read_b); + *vid_timing_read_w = ISA_CYCLES(monitor_vid_timings->read_w); + *vid_timing_read_l = ISA_CYCLES(monitor_vid_timings->read_l); + *vid_timing_write_b = ISA_CYCLES(monitor_vid_timings->write_b); + *vid_timing_write_w = ISA_CYCLES(monitor_vid_timings->write_w); + *vid_timing_write_l = ISA_CYCLES(monitor_vid_timings->write_l); + } else if (monitor_vid_timings->type == VIDEO_PCI) { + *vid_timing_read_b = (int)(pci_timing * monitor_vid_timings->read_b); + *vid_timing_read_w = (int)(pci_timing * monitor_vid_timings->read_w); + *vid_timing_read_l = (int)(pci_timing * monitor_vid_timings->read_l); + *vid_timing_write_b = (int)(pci_timing * monitor_vid_timings->write_b); + *vid_timing_write_w = (int)(pci_timing * monitor_vid_timings->write_w); + *vid_timing_write_l = (int)(pci_timing * monitor_vid_timings->write_l); + } else if (monitor_vid_timings->type == VIDEO_AGP) { + *vid_timing_read_b = (int)(agp_timing * monitor_vid_timings->read_b); + *vid_timing_read_w = (int)(agp_timing * monitor_vid_timings->read_w); + *vid_timing_read_l = (int)(agp_timing * monitor_vid_timings->read_l); + *vid_timing_write_b = (int)(agp_timing * monitor_vid_timings->write_b); + *vid_timing_write_w = (int)(agp_timing * monitor_vid_timings->write_w); + *vid_timing_write_l = (int)(agp_timing * monitor_vid_timings->write_l); + } else { + *vid_timing_read_b = (int)(bus_timing * monitor_vid_timings->read_b); + *vid_timing_read_w = (int)(bus_timing * monitor_vid_timings->read_w); + *vid_timing_read_l = (int)(bus_timing * monitor_vid_timings->read_l); + *vid_timing_write_b = (int)(bus_timing * monitor_vid_timings->write_b); + *vid_timing_write_w = (int)(bus_timing * monitor_vid_timings->write_w); + *vid_timing_write_l = (int)(bus_timing * monitor_vid_timings->write_l); + } + + if (cpu_16bitbus) { + *vid_timing_read_l = *vid_timing_read_w * 2; + *vid_timing_write_l = *vid_timing_write_w * 2; + } } } @@ -748,7 +794,7 @@ hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) { int x; - if (y < 0 || y >= buffer32->h) + if (y < 0 || y >= b->h) return; for (x = x1; x < x2; x++) @@ -806,6 +852,56 @@ create_bitmap(int x, int y) return(b); } +void +video_monitor_init(int index) +{ + memset(&monitors[index], 0, sizeof(monitor_t)); + monitors[index].mon_xsize = 640; + monitors[index].mon_ysize = 480; + monitors[index].mon_res_x = 640; + monitors[index].mon_res_y = 480; + monitors[index].mon_scrnsz_x = 640; + monitors[index].mon_scrnsz_y = 480; + monitors[index].mon_efscrnsz_y = 480; + monitors[index].mon_unscaled_size_x = 480; + monitors[index].mon_unscaled_size_y = 480; + monitors[index].mon_bpp = 8; + monitors[index].mon_changeframecount = 2; + monitors[index].target_buffer = create_bitmap(2048, 2048); + monitors[index].mon_blit_data_ptr = calloc(1, sizeof(blit_data_t)); + monitors[index].mon_blit_data_ptr->wake_blit_thread = thread_create_event(); + monitors[index].mon_blit_data_ptr->blit_complete = thread_create_event(); + monitors[index].mon_blit_data_ptr->buffer_not_in_use = thread_create_event(); + monitors[index].mon_blit_data_ptr->thread_run = 1; + monitors[index].mon_blit_data_ptr->monitor_index = index; + monitors[index].mon_pal_lookup = calloc(sizeof(uint32_t), 256); + monitors[index].mon_cga_palette = calloc(1, sizeof(int)); + monitors[index].mon_force_resize = 1; + monitors[index].mon_vid_type = VIDEO_FLAG_TYPE_NONE; + atomic_init(&doresize_monitors[index], 0); + atomic_init(&monitors[index].mon_screenshots, 0); + if (index >= 1) ui_init_monitor(index); + monitors[index].mon_blit_data_ptr->blit_thread = thread_create(blit_thread, monitors[index].mon_blit_data_ptr); +} + +void +video_monitor_close(int monitor_index) +{ + if (monitors[monitor_index].target_buffer == NULL) { return; } + monitors[monitor_index].mon_blit_data_ptr->thread_run = 0; + thread_set_event(monitors[monitor_index].mon_blit_data_ptr->wake_blit_thread); + thread_wait(monitors[monitor_index].mon_blit_data_ptr->blit_thread); + if (monitor_index >= 1) ui_deinit_monitor(monitor_index); + thread_destroy_event(monitors[monitor_index].mon_blit_data_ptr->buffer_not_in_use); + thread_destroy_event(monitors[monitor_index].mon_blit_data_ptr->blit_complete); + thread_destroy_event(monitors[monitor_index].mon_blit_data_ptr->wake_blit_thread); + free(monitors[monitor_index].mon_blit_data_ptr); + if (!monitors[monitor_index].mon_pal_lookup_static) free(monitors[monitor_index].mon_pal_lookup); + if (!monitors[monitor_index].mon_cga_palette_static) free(monitors[monitor_index].mon_cga_palette); + destroy_bitmap(monitors[monitor_index].target_buffer); + monitors[monitor_index].target_buffer = NULL; + memset(&monitors[monitor_index], 0, sizeof(monitor_t)); +} void video_init(void) @@ -818,15 +914,11 @@ video_init(void) (total[(c >> 1) & 1] << 16) | (total[(c >> 0) & 1] << 24); } - /* Account for overscan. */ - buffer32 = create_bitmap(2048 + 64, 2048 + 64); - render_buffer = create_bitmap(2048 + 64, 2048 + 64); - for (c = 0; c < 64; c++) { cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; - if ((c & 0x17) == 6) + if ((c & 0x17) == 6) cgapal[c + 64].g >>= 1; } for (c = 0; c < 64; c++) { @@ -865,20 +957,15 @@ video_init(void) for (c = 0; c < 65536; c++) video_16to32[c] = calc_16to32(c); - blit_data.wake_blit_thread = thread_create_event(); - blit_data.blit_complete = thread_create_event(); - blit_data.buffer_not_in_use = thread_create_event(); - blit_data.blit_thread = thread_create(blit_thread, NULL); + memset(monitors, 0, sizeof(monitors)); + video_monitor_init(0); } void video_close(void) { - thread_kill(blit_data.blit_thread); - thread_destroy_event(blit_data.buffer_not_in_use); - thread_destroy_event(blit_data.blit_complete); - thread_destroy_event(blit_data.wake_blit_thread); + video_monitor_close(0); free(video_16to32); free(video_15to32); @@ -886,9 +973,6 @@ video_close(void) free(video_8togs); free(video_6to8); - destroy_bitmap(render_buffer); - destroy_bitmap(buffer32); - if (fontdatksc5601) { free(fontdatksc5601); fontdatksc5601 = NULL; @@ -900,32 +984,26 @@ video_close(void) } } - uint8_t -video_force_resize_get(void) +video_force_resize_get_monitor(int monitor_index) { - return video_force_resize; + return monitors[monitor_index].mon_force_resize; } void -video_force_resize_set(uint8_t res) +video_force_resize_set_monitor(uint8_t res, int monitor_index) { - video_force_resize = res; + monitors[monitor_index].mon_force_resize = res; } void -loadfont(wchar_t *s, int format) +loadfont_common(FILE *f, int format) { - FILE *f; int c, d; - f = rom_fopen(s, L"rb"); - if (f == NULL) - return; - - switch (format) { + switch (format) { case 0: /* MDA */ for (c=0; c<256; c++) for (d=0; d<8; d++) @@ -1038,11 +1116,31 @@ loadfont(wchar_t *s, int format) for (c = 0; c < 256; c++) fread(&fontdat12x18[c][0], 1, 36, f); break; - } + + } (void)fclose(f); } +void +loadfont_ex(char *s, int format, int offset) +{ + FILE *f; + + f = rom_fopen(s, "rb"); + if (f == NULL) + return; + + fseek(f, offset, SEEK_SET); + loadfont_common(f, format); + +} + +void +loadfont(char *s, int format) +{ + loadfont_ex(s, format, 0); +} uint32_t video_color_transform(uint32_t color) diff --git a/src/vnc.c b/src/vnc.c index 5813767fb..768b08b57 100644 --- a/src/vnc.c +++ b/src/vnc.c @@ -167,18 +167,24 @@ vnc_display(rfbClientPtr cl) static void -vnc_blit(int x, int y, int y1, int y2, int w, int h) +vnc_blit(int x, int y, int w, int h) { uint32_t *p; int yy; - for (yy=y1; yy 2048) || (h > 2048) || (buffer32 == NULL)) + return; + + for (yy=0; yyframeBuffer)[yy*VNC_MAX_X]); if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y) - memcpy(p, &(render_buffer->line[y+yy][x]), w*4); + video_copy(p, &(buffer32->line[yy]), w*sizeof(uint32_t)); } - + + if (screenshots) + video_screenshot((uint32_t *) rfb->frameBuffer, 0, 0, VNC_MAX_X); + video_blit_complete(); if (! updatingSize) @@ -211,7 +217,7 @@ vnc_init(UNUSED(void *arg)) updatingSize = 0; allowedX = scrnsz_x; allowedY = scrnsz_y; - + rfb = rfbGetScreen(0, NULL, VNC_MAX_X, VNC_MAX_Y, 8, 3, 4); rfb->desktopName = title; rfb->frameBuffer = (char *)malloc(VNC_MAX_X*VNC_MAX_Y*4); @@ -222,16 +228,16 @@ vnc_init(UNUSED(void *arg)) rfb->ptrAddEvent = vnc_ptrevent; rfb->kbdAddEvent = vnc_kbdevent; rfb->newClientHook = vnc_newclient; - + /* Set up our current resolution. */ rfb->width = allowedX; rfb->height = allowedY; - + rfbInitServer(rfb); rfbRunEventLoop(rfb, -1, TRUE); } - + /* Set up our BLIT handlers. */ video_setblit(vnc_blit); @@ -274,13 +280,13 @@ vnc_resize(int x, int y) if ((x != rfb->width || y != rfb->height) && x > 160 && y > 0) { vnc_log("VNC: updating resolution: %dx%d\n", x, y); - + allowedX = (rfb->width < x) ? rfb->width : x; allowedY = (rfb->width < y) ? rfb->width : y; - + rfb->width = x; rfb->height = y; - + iterator = rfbGetClientIterator(rfb); while ((cl = rfbClientIteratorNext(iterator)) != NULL) { LOCK(cl->updateMutex); @@ -289,7 +295,7 @@ vnc_resize(int x, int y) } } } - + /* Tell them to pause if we have no clients. */ int diff --git a/src/vnc_keymap.c b/src/vnc_keymap.c index 999466c9b..fd9769de9 100644 --- a/src/vnc_keymap.c +++ b/src/vnc_keymap.c @@ -619,7 +619,7 @@ static int keysyms_ff[] = { 0x0000, 0x0000, 0x0000, - 0xe071 /* 0xff (XK_Delete) */ + 0xe053 /* 0xff (XK_Delete) */ }; diff --git a/src/win/86Box-qt.rc b/src/win/86Box-qt.rc new file mode 100644 index 000000000..0d4d8158f --- /dev/null +++ b/src/win/86Box-qt.rc @@ -0,0 +1,123 @@ +/* + * 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. + * + * Application resource script for Windows. + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * David Hrdlička, + * + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 David Hrdlička. + * Copyright 2021 Laci bá' + */ +#define IN_RESOURCE_H +#include <86box/version.h> +#undef IN_RESOURCE_H + +#define APSTUDIO_READONLY_SYMBOLS +#define APSTUDIO_HIDDEN_SYMBOLS +#include +#undef APSTUDIO_HIDDEN_SYMBOLS +#undef APSTUDIO_READONLY_SYMBOLS + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) + +#ifndef NO_INCLUDE_MANIFEST +///////////////////////////////////////////////////////////////////////////// +// +// 24 +// + +1 24 MOVEABLE PURE "86Box.manifest" +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +#ifdef CMAKE +#define ICON_PATH +#else +#define ICON_PATH "win/" +#endif + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +// defining the icons depending on the build status +#ifdef RELEASE_BUILD +/* Icon by OBattler and laciba96 (green for release builds)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-green.ico" +#elif BETA_BUILD +/* Icon by OBattler and laciba96 (yellow for beta builds done by Jenkins)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-yellow.ico" +#elif ALPHA_BUILD +/* Icon by OBattler and laciba96 (red for alpha builds done by Jenkins)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-red.ico" +#else +/* Icon by OBattler and laciba96 (gray for builds of branches and from the git master)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-gray.ico" +#endif + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION EMU_VERSION_MAJ,EMU_VERSION_MIN,EMU_VERSION_PATCH,EMU_BUILD_NUM + PRODUCTVERSION EMU_VERSION_MAJ,EMU_VERSION_MIN,EMU_VERSION_PATCH,EMU_BUILD_NUM + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", EMU_NAME "\0" + VALUE "FileDescription", EMU_NAME "\0" + VALUE "FileVersion", EMU_VERSION "\0" + VALUE "InternalName", EMU_NAME "\0" + VALUE "LegalCopyright", "Copyright \xa9 2007-" COPYRIGHT_YEAR " " EMU_NAME " contributors\0" + VALUE "OriginalFilename", EMU_NAME ".exe\0" + VALUE "ProductName", EMU_NAME "\0" + VALUE "ProductVersion", EMU_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/win/86Box.manifest b/src/win/86Box.manifest index ebccd7674..58f2d4194 100644 --- a/src/win/86Box.manifest +++ b/src/win/86Box.manifest @@ -1,21 +1,49 @@  - - + + - + - + + + + + + + + + + + true + permonitorv2 + UTF-8 + + + + + + + + + + + + + + + + diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 6ceab5ab7..342870d62 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -8,20 +8,18 @@ * * Application resource script for Windows. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * David Hrdlička, * * Copyright 2016-2019 Miran Grca. * Copyright 2018,2019 David Hrdlička. + * Copyright 2021 Laci bá' */ -#include #define IN_RESOURCE_H #include <86box/resource.h> -#include <86box/86box.h> -#include <86box/plat.h> +#include <86box/language.h> +#include <86box/version.h> #undef IN_RESOURCE_H #define APSTUDIO_READONLY_SYMBOLS @@ -30,204 +28,7 @@ #undef APSTUDIO_HIDDEN_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(65001) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -MainMenu MENU DISCARDABLE -BEGIN - POPUP "&Action" - BEGIN - MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT - MENUITEM SEPARATOR - MENUITEM "&Hard Reset", IDM_ACTION_HRESET - MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD - MENUITEM SEPARATOR - MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC - MENUITEM SEPARATOR - MENUITEM "&Pause", IDM_ACTION_PAUSE - MENUITEM SEPARATOR - MENUITEM "E&xit", IDM_ACTION_EXIT - END - POPUP "&View" - BEGIN - MENUITEM "&Resizeable window", IDM_VID_RESIZE - MENUITEM "R&emember size && position", IDM_VID_REMEMBER - MENUITEM SEPARATOR - POPUP "Re&nderer" - BEGIN - MENUITEM "&SDL (Software)", IDM_VID_SDL_SW - MENUITEM "&SDL (Hardware)", IDM_VID_SDL_HW -#ifdef USE_VNC - MENUITEM "&VNC", IDM_VID_VNC -#endif - END - MENUITEM SEPARATOR - MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 - POPUP "&Window scale factor" - BEGIN - MENUITEM "&0.5x", IDM_VID_SCALE_1X - MENUITEM "&1x", IDM_VID_SCALE_2X - MENUITEM "1.&5x", IDM_VID_SCALE_3X - MENUITEM "&2x", IDM_VID_SCALE_4X - END - MENUITEM SEPARATOR - MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN - POPUP "Fullscreen &stretch mode" - BEGIN - MENUITEM "&Full screen stretch", IDM_VID_FS_FULL - MENUITEM "&4:3", IDM_VID_FS_43 - MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO - MENUITEM "&Integer scale", IDM_VID_FS_INT - END - POPUP "E&GA/(S)VGA settings" - BEGIN - MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT - POPUP "VGA screen &type" - BEGIN - MENUITEM "RGB &Color", IDM_VID_GRAY_RGB - MENUITEM "&RGB Grayscale", IDM_VID_GRAY_MONO - MENUITEM "&Amber monitor", IDM_VID_GRAY_AMBER - MENUITEM "&Green monitor", IDM_VID_GRAY_GREEN - MENUITEM "&White monitor", IDM_VID_GRAY_WHITE - END - POPUP "Grayscale &conversion type" - BEGIN - MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 - MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 - MENUITEM "&Average", IDM_VID_GRAYCT_AVE - END - END - MENUITEM SEPARATOR - MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN - MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON - END - MENUITEM "&Media", IDM_MEDIA - POPUP "&Tools" - BEGIN - MENUITEM "&Settings...", IDM_CONFIG - MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS -# ifdef USE_DISCORD - MENUITEM SEPARATOR - MENUITEM "Enable &Discord integration", IDM_DISCORD -# endif - MENUITEM SEPARATOR - MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT - END -#if defined(ENABLE_LOG_TOGGLES) || defined(ENABLE_LOG_COMMANDS) - POPUP "&Logging" - BEGIN -# ifdef ENABLE_BUSLOGIC_LOG - MENUITEM "Enable BusLogic logs\tCtrl+F4", IDM_LOG_BUSLOGIC -# endif -# ifdef ENABLE_CDROM_LOG - MENUITEM "Enable CD-ROM logs\tCtrl+F5", IDM_LOG_CDROM -# endif -# ifdef ENABLE_D86F_LOG - MENUITEM "Enable floppy (86F) logs\tCtrl+F6", IDM_LOG_D86F -# endif -# ifdef ENABLE_FDC_LOG - MENUITEM "Enable floppy controller logs\tCtrl+F7", IDM_LOG_FDC -# endif -# ifdef ENABLE_IDE_LOG - MENUITEM "Enable IDE logs\tCtrl+F8", IDM_LOG_IDE -# endif -# ifdef ENABLE_SERIAL_LOG - MENUITEM "Enable Serial Port logs\tCtrl+F3", IDM_LOG_SERIAL -# endif -# ifdef ENABLE_NIC_LOG - MENUITEM "Enable Network logs\tCtrl+F9", IDM_LOG_NIC -# endif -# ifdef ENABLE_LOG_COMMANDS -# ifdef ENABLE_LOG_TOGGLES - MENUITEM SEPARATOR -# endif -# ifdef ENABLE_LOG_BREAKPOINT - MENUITEM "&Log breakpoint\tCtrl+F10", IDM_LOG_BREAKPOINT -# endif -# ifdef ENABLE_VRAM_DUMP - MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM -# endif -# endif - END -#endif - POPUP "&Help" - BEGIN - MENUITEM "&About " EMU_NAME "...", IDM_ABOUT - END -END - -StatusBarMenu MENU DISCARDABLE -BEGIN - MENUITEM SEPARATOR -END - -FloppySubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_FLOPPY_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_FLOPPY_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_FLOPPY_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "E&xport to 86F...", IDM_FLOPPY_EXPORT_TO_86F - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_FLOPPY_EJECT - END -END - -CdromSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&Mute", IDM_CDROM_MUTE - MENUITEM SEPARATOR - MENUITEM "E&mpty", IDM_CDROM_EMPTY - MENUITEM "&Reload previous image", IDM_CDROM_RELOAD - MENUITEM SEPARATOR - MENUITEM "&Image", IDM_CDROM_IMAGE - END -END - -ZIPSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_ZIP_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_ZIP_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_ZIP_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_ZIP_EJECT - MENUITEM "&Reload previous image", IDM_ZIP_RELOAD - END -END - -MOSubmenu MENU DISCARDABLE -BEGIN - POPUP "" - BEGIN - MENUITEM "&New image...", IDM_MO_IMAGE_NEW - MENUITEM SEPARATOR - MENUITEM "&Existing image...", IDM_MO_IMAGE_EXISTING - MENUITEM "Existing image (&Write-protected)...", IDM_MO_IMAGE_EXISTING_WP - MENUITEM SEPARATOR - MENUITEM "E&ject", IDM_MO_EJECT - MENUITEM "&Reload previous image", IDM_MO_RELOAD - END -END - ///////////////////////////////////////////////////////////////////////////// // @@ -236,32 +37,8 @@ END MainAccel ACCELERATORS MOVEABLE PURE BEGIN -#ifdef ENABLE_VRAM_DUMP - VK_F1, IDM_DUMP_VRAM, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_SERIAL_LOG - VK_F3, IDM_LOG_SERIAL, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_BUSLOGIC_LOG - VK_F4, IDM_LOG_BUSLOGIC, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_CDROM_LOG - VK_F5, IDM_LOG_CDROM, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_D86F_LOG - VK_F6, IDM_LOG_D86F, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_FDC_LOG - VK_F7, IDM_LOG_FDC, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_IDE_LOG - VK_F8, IDM_LOG_IDE, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_NIC_LOG - VK_F9, IDM_LOG_NIC, CONTROL, VIRTKEY -#endif -#ifdef ENABLE_LOG_BREAKPOINT - VK_F10, IDM_LOG_BREAKPOINT, CONTROL, VIRTKEY +#ifdef MTR_ENABLED + "T", IDM_ACTION_TRACE, CONTROL, VIRTKEY #endif VK_PRIOR,IDM_VID_FULLSCREEN, VIRTKEY, CONTROL , ALT VK_F11, IDM_ACTION_SCREENSHOT, VIRTKEY, CONTROL @@ -270,455 +47,92 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// -DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 -STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Status" -FONT 9, "Segoe UI" -BEGIN - LTEXT "1",IDT_SDEVICE,16,16,180,1000 - LTEXT "1",IDT_STEXT,16,186,180,1000 -END - -DLG_SND_GAIN DIALOG DISCARDABLE 0, 0, 113, 136 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Sound Gain" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",IDOK,57,7,50,14 - PUSHBUTTON "Cancel",IDCANCEL,57,24,50,14 - CONTROL "Gain",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_VERT | - TBS_BOTH | TBS_AUTOTICKS | WS_TABSTOP,15,20,20,109 - CTEXT "Gain",IDT_1746,16,7,32,9,SS_CENTERIMAGE -END - -DLG_NEW_FLOPPY DIALOG DISCARDABLE 0, 0, 226, 86 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "New Floppy Image" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",IDOK,74,65,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,65,50,14 - LTEXT "File name:",IDT_1749,7,6,44,12,SS_CENTERIMAGE - LTEXT "Disk size:",IDT_1750,7,25,44,12,SS_CENTERIMAGE - LTEXT "RPM mode:",IDT_1751,7,45,44,12,SS_CENTERIMAGE - EDITTEXT IDC_EDIT_FILE_NAME,53,5,154,14,ES_AUTOHSCROLL | ES_READONLY - COMBOBOX IDC_COMBO_DISK_SIZE,53,25,166,14,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_COMBO_RPM_MODE,53,45,166,14,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "...",IDC_CFILE,206,5,13,14 - LTEXT "Progress:",IDT_1757,7,45,44,12,SS_CENTERIMAGE - CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | - WS_BORDER,53,45,166,14 -END - -DLG_CONFIG DIALOG DISCARDABLE 0, 0, 366, 251 -STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION EMU_NAME " Settings" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,246,230,50,14 - PUSHBUTTON "Cancel",IDCANCEL,307,230,50,14 - CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_LIST | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,90,207 - CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,221,363,1 -/* Leave this commented out until we get into localization. */ -#if 0 - LTEXT "Language:",IDT_1700,7,232,41,10 - COMBOBOX IDC_COMBO_LANG,48,231,108,120,CBS_DROPDOWN | WS_VSCROLL | - WS_TABSTOP -#endif -END - -DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 305, 199 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - COMBOBOX IDC_COMBO_MACHINE_TYPE,71,7,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Machine type:",IDT_1708,7,8,60,10 - COMBOBOX IDC_COMBO_MACHINE,71,26,138,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Machine:",IDT_1701,7,27,60,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,26,46,12 - COMBOBOX IDC_COMBO_CPU_TYPE,71,44,45,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "CPU type:",IDT_1702,7,45,59,10 - COMBOBOX IDC_COMBO_CPU,145,44,115,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "CPU:",IDT_1704,124,45,18,10 - COMBOBOX IDC_COMBO_FPU,71,63,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "FPU:",IDT_1707,7,63,59,10 - COMBOBOX IDC_COMBO_WS,71,82,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "Wait states:",IDT_1703,7,83,60,10 - EDITTEXT IDC_MEMTEXT,70,101,45,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | - UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,101, - 12,12 - LTEXT "MB",IDT_1705,123,102,10,10 - LTEXT "Memory:",IDT_1706,7,102,30,10 - GROUPBOX "Time synchronization",IDC_TIME_SYNC,7,134,100,56 - CONTROL "Disabled",IDC_RADIO_TS_DISABLED,"Button", - BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,146,84,10 - CONTROL "Enabled (local time)", IDC_RADIO_TS_LOCAL,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,160,84,10 - CONTROL "Enabled (UTC)", IDC_RADIO_TS_UTC,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,174,84,10 -#ifdef USE_DYNAREC - CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,119,94,10 -#endif -END - -DLG_CFG_VIDEO DIALOG DISCARDABLE 97, 0, 267, 45 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "Video:",IDT_1707,7,8,48,10 - COMBOBOX IDC_COMBO_VIDEO,64,7,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_VID,222,7,38,12 - CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,27,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,222,26,38,12 -END - -DLG_CFG_INPUT DIALOG DISCARDABLE 97, 0, 267, 65 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "Mouse :",IDT_1709,7,8,57,10 - COMBOBOX IDC_COMBO_MOUSE,71,7,140,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_MOUSE,214,7,46,12 - LTEXT "Joystick :",IDT_1710,7,26,58,10 - COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 - PUSHBUTTON "Joystick 2...",IDC_JOY2,74,44,50,14 - PUSHBUTTON "Joystick 3...",IDC_JOY3,141,44,50,14 - PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 -END - -DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 199 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "Sound card:",IDT_1711,7,8,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_SND,214,7,46,12 - - COMBOBOX IDC_COMBO_MIDI,71,25,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "MIDI Out Device:",IDT_1712,7,26,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,25,46,12 - - COMBOBOX IDC_COMBO_MIDI_IN,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - LTEXT "MIDI In Device:",IDT_1713,7,44,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,43,46,12 - - CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,65,199,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,64,46,12 - - CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,83,94,10 - CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,83,94,10 - - CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,99,46,12 - - CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,115,94,10 -END - -DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "Network type:",IDT_1714,7,8,59,10 - COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - - LTEXT "PCap device:",IDT_1715,7,26,59,10 - COMBOBOX IDC_COMBO_PCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - - LTEXT "Network adapter:",IDT_1716,7,44,59,10 - COMBOBOX IDC_COMBO_NET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 -END - -DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 117 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "LPT1 Device:",IDT_1717,7,8,61,10 - COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - - LTEXT "LPT2 Device:",IDT_1718,7,27,61,10 - COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - - LTEXT "LPT3 Device:",IDT_1719,7,46,61,10 - COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - - CONTROL "Serial port 1",IDC_CHECK_SERIAL1,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,64,94,10 - CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 - - CONTROL "Parallel port 1",IDC_CHECK_PARALLEL1,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 - CONTROL "Parallel port 2",IDC_CHECK_PARALLEL2,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,82,94,10 - CONTROL "Parallel port 3",IDC_CHECK_PARALLEL3,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 -END - -DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 220 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - LTEXT "SCSI Controller:",IDT_1717,7,8,48,10 - COMBOBOX IDC_COMBO_SCSI,64,7,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,222,7,38,12 - - LTEXT "HD Controller:",IDT_1718,7,26,48,10 - COMBOBOX IDC_COMBO_HDC,64,25,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,25,38,12 - - LTEXT "FD Controller:",IDT_1768,7,44,48,10 - COMBOBOX IDC_COMBO_FDC,64,43,155,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_FDC,222,43,38,12 - - CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,62,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,222,61,38,12 - - CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,80,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,222,79,38,12 - - CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,98,94,10 - - CONTROL "POST card",IDC_CHECK_POSTCARD,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,98,94,10 - - LTEXT "ISA RTC",IDT_1767,7,117,48,10 - COMBOBOX IDC_COMBO_ISARTC,64,116,155,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISARTC,222,116,38,12 - - GROUPBOX "ISA Memory Expansion",IDC_GROUP_ISAMEM,7,136,255,70 - LTEXT "#1:",IDT_1763,12,148,21,10 - COMBOBOX IDC_COMBO_ISAMEM_1,25,147,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_1,217,147,38,12 - LTEXT "#2:",IDT_1764,12,163,21,10 - COMBOBOX IDC_COMBO_ISAMEM_2,25,162,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_2,217,162,38,12 - LTEXT "#3:",IDT_1765,12,177,21,10 - COMBOBOX IDC_COMBO_ISAMEM_3,25,176,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_3,217,176,38,12 - LTEXT "#4:",IDT_1766,12,191,21,10 - COMBOBOX IDC_COMBO_ISAMEM_4,25,190,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,217,190,38,12 -END - -DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 97, 0, 267, 154 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,18,253,92 - LTEXT "Hard disks:",IDT_1720,7,7,34,8 - PUSHBUTTON "&New...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 - PUSHBUTTON "&Existing...",IDC_BUTTON_HDD_ADD,129,137,62,10 - PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 - COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1721,7,119,24,8 - COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1722,131,119,38,8 - COMBOBOX IDC_COMBO_HD_ID,170,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1723,131,119,38,8 - COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP -END - -DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 111 -STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Add Hard Disk" -FONT 9, "Segoe UI" -BEGIN - DEFPUSHBUTTON "OK",IDOK,55,89,50,14 - PUSHBUTTON "Cancel",IDCANCEL,112,89,50,14 - EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 - PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 - EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 - EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 - EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 - EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 - COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Sectors:",IDT_1726,154,35,27,10 - LTEXT "Heads:",IDT_1727,81,35,29,8 - LTEXT "Cylinders:",IDT_1728,7,35,32,12 - LTEXT "Size (MB):",IDT_1729,7,54,33,8 - LTEXT "Type:",IDT_1730,86,54,24,8 - LTEXT "File name:",IDT_1731,7,7,204,9 - COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1721,7,73,24,8 - COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1722,99,73,34,8 - COMBOBOX IDC_COMBO_HD_ID,134,71,77,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1723,99,73,34,8 - COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Progress:",IDT_1752,7,7,204,9 - CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | - WS_BORDER,7,16,204,12 -END - -DLG_CFG_FLOPPY_DRIVES DIALOG DISCARDABLE 97, 0, 267, 103 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,18,253,60 - LTEXT "Floppy drives:",IDT_1737,7,7,43,8 - COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Type:",IDT_1738,7,87,24,8 - CONTROL "Turbo timings",IDC_CHECKTURBO,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,131,86,64,10 - CONTROL "Check BPB",IDC_CHECKBPB,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,196,86,64,10 -END - -DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 97, 0, 267, 221 -STYLE DS_CONTROL | WS_CHILD -FONT 9, "Segoe UI" -BEGIN - CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,18,253,60 - LTEXT "CD-ROM drives:",IDT_1739,7,7,50,8 - COMBOBOX IDC_COMBO_CD_BUS,33,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1740,7,87,24,8 - COMBOBOX IDC_COMBO_CD_ID,170,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1741,131,87,38,8 - COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,85,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1742,131,87,38,8 - COMBOBOX IDC_COMBO_CD_SPEED,33,105,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Speed:",IDT_1758,7,107,24,8 - CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | - WS_TABSTOP,7,137,253,60 - LTEXT "ZIP drives:",IDT_1759,7,127,50,8 - COMBOBOX IDC_COMBO_ZIP_BUS,23,204,90,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Bus:",IDT_1753,7,206,14,8 - COMBOBOX IDC_COMBO_ZIP_ID,139,204,61,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "ID:",IDT_1754,120,206,28,8 - COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,149,204,61,12,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - LTEXT "Channel:",IDT_1755,120,206,28,8 - CONTROL "ZIP 250",IDC_CHECK250,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,218,204,44,10 -END - - +#ifndef NO_INCLUDE_MANIFEST ///////////////////////////////////////////////////////////////////////////// // // 24 // 1 24 MOVEABLE PURE "86Box.manifest" +#endif ///////////////////////////////////////////////////////////////////////////// // // Icon // +#ifdef CMAKE +#define ICON_PATH +#else +#define ICON_PATH "win/" +#endif + // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. +// defining the icons depending on the build status #ifdef RELEASE_BUILD -/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png */ - 10 ICON DISCARDABLE "win/icons/86Box-RB.ico" +/* Icon by OBattler and laciba96 (green for release builds)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-green.ico" +#elif BETA_BUILD +/* Icon by OBattler and laciba96 (yellow for beta builds done by Jenkins)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-yellow.ico" +#elif ALPHA_BUILD +/* Icon by OBattler and laciba96 (red for alpha builds done by Jenkins)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-red.ico" #else -/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ - 10 ICON DISCARDABLE "win/icons/86Box.ico" +/* Icon by OBattler and laciba96 (gray for builds of branches and from the git master)*/ + 10 ICON DISCARDABLE ICON_PATH "icons/86Box-gray.ico" #endif - 16 ICON DISCARDABLE "win/icons/floppy_525.ico" - 17 ICON DISCARDABLE "win/icons/floppy_525_active.ico" - 24 ICON DISCARDABLE "win/icons/floppy_35.ico" - 25 ICON DISCARDABLE "win/icons/floppy_35_active.ico" - 32 ICON DISCARDABLE "win/icons/cdrom.ico" - 33 ICON DISCARDABLE "win/icons/cdrom_active.ico" - 48 ICON DISCARDABLE "win/icons/zip.ico" - 49 ICON DISCARDABLE "win/icons/zip_active.ico" - 56 ICON DISCARDABLE "win/icons/mo.ico" - 57 ICON DISCARDABLE "win/icons/mo_active.ico" - 64 ICON DISCARDABLE "win/icons/hard_disk.ico" - 65 ICON DISCARDABLE "win/icons/hard_disk_active.ico" - 80 ICON DISCARDABLE "win/icons/network.ico" - 81 ICON DISCARDABLE "win/icons/network_active.ico" -144 ICON DISCARDABLE "win/icons/floppy_525_empty.ico" -145 ICON DISCARDABLE "win/icons/floppy_525_empty_active.ico" -152 ICON DISCARDABLE "win/icons/floppy_35_empty.ico" -153 ICON DISCARDABLE "win/icons/floppy_35_empty_active.ico" -160 ICON DISCARDABLE "win/icons/cdrom_empty.ico" -161 ICON DISCARDABLE "win/icons/cdrom_empty_active.ico" -176 ICON DISCARDABLE "win/icons/zip_empty.ico" -177 ICON DISCARDABLE "win/icons/zip_empty_active.ico" -183 ICON DISCARDABLE "win/icons/mo_empty.ico" -184 ICON DISCARDABLE "win/icons/mo_empty_active.ico" -240 ICON DISCARDABLE "win/icons/machine.ico" -241 ICON DISCARDABLE "win/icons/display.ico" -242 ICON DISCARDABLE "win/icons/input_devices.ico" -243 ICON DISCARDABLE "win/icons/sound.ico" -244 ICON DISCARDABLE "win/icons/ports.ico" -245 ICON DISCARDABLE "win/icons/other_peripherals.ico" -246 ICON DISCARDABLE "win/icons/floppy_drives.ico" -247 ICON DISCARDABLE "win/icons/other_removable_devices.ico" -248 ICON DISCARDABLE "win/icons/floppy_disabled.ico" -249 ICON DISCARDABLE "win/icons/cdrom_disabled.ico" -250 ICON DISCARDABLE "win/icons/zip_disabled.ico" -251 ICON DISCARDABLE "win/icons/mo_disabled.ico" + 16 ICON DISCARDABLE ICON_PATH "icons/floppy_525.ico" + 17 ICON DISCARDABLE ICON_PATH "icons/floppy_525_active.ico" + 24 ICON DISCARDABLE ICON_PATH "icons/floppy_35.ico" + 25 ICON DISCARDABLE ICON_PATH "icons/floppy_35_active.ico" + 32 ICON DISCARDABLE ICON_PATH "icons/cdrom.ico" + 33 ICON DISCARDABLE ICON_PATH "icons/cdrom_active.ico" + 48 ICON DISCARDABLE ICON_PATH "icons/zip.ico" + 49 ICON DISCARDABLE ICON_PATH "icons/zip_active.ico" + 56 ICON DISCARDABLE ICON_PATH "icons/mo.ico" + 57 ICON DISCARDABLE ICON_PATH "icons/mo_active.ico" + 64 ICON DISCARDABLE ICON_PATH "icons/cassette.ico" + 65 ICON DISCARDABLE ICON_PATH "icons/cassette_active.ico" + 80 ICON DISCARDABLE ICON_PATH "icons/hard_disk.ico" + 81 ICON DISCARDABLE ICON_PATH "icons/hard_disk_active.ico" + 96 ICON DISCARDABLE ICON_PATH "icons/network.ico" + 97 ICON DISCARDABLE ICON_PATH "icons/network_active.ico" +104 ICON DISCARDABLE ICON_PATH "icons/cartridge.ico" +144 ICON DISCARDABLE ICON_PATH "icons/floppy_525_empty.ico" +145 ICON DISCARDABLE ICON_PATH "icons/floppy_525_empty_active.ico" +152 ICON DISCARDABLE ICON_PATH "icons/floppy_35_empty.ico" +153 ICON DISCARDABLE ICON_PATH "icons/floppy_35_empty_active.ico" +160 ICON DISCARDABLE ICON_PATH "icons/cdrom_empty.ico" +161 ICON DISCARDABLE ICON_PATH "icons/cdrom_empty_active.ico" +176 ICON DISCARDABLE ICON_PATH "icons/zip_empty.ico" +177 ICON DISCARDABLE ICON_PATH "icons/zip_empty_active.ico" +184 ICON DISCARDABLE ICON_PATH "icons/mo_empty.ico" +185 ICON DISCARDABLE ICON_PATH "icons/mo_empty_active.ico" +192 ICON DISCARDABLE ICON_PATH "icons/cassette_empty.ico" +193 ICON DISCARDABLE ICON_PATH "icons/cassette_empty_active.ico" +200 ICON DISCARDABLE ICON_PATH "icons/run.ico" +201 ICON DISCARDABLE ICON_PATH "icons/pause.ico" +202 ICON DISCARDABLE ICON_PATH "icons/send_cad.ico" +203 ICON DISCARDABLE ICON_PATH "icons/send_cae.ico" +204 ICON DISCARDABLE ICON_PATH "icons/hard_reset.ico" +205 ICON DISCARDABLE ICON_PATH "icons/acpi_shutdown.ico" +206 ICON DISCARDABLE ICON_PATH "icons/settings.ico" +232 ICON DISCARDABLE ICON_PATH "icons/cartridge_empty.ico" +240 ICON DISCARDABLE ICON_PATH "icons/machine.ico" +241 ICON DISCARDABLE ICON_PATH "icons/display.ico" +242 ICON DISCARDABLE ICON_PATH "icons/input_devices.ico" +243 ICON DISCARDABLE ICON_PATH "icons/sound.ico" +244 ICON DISCARDABLE ICON_PATH "icons/ports.ico" +245 ICON DISCARDABLE ICON_PATH "icons/other_peripherals.ico" +246 ICON DISCARDABLE ICON_PATH "icons/floppy_and_cdrom_drives.ico" +247 ICON DISCARDABLE ICON_PATH "icons/other_removable_devices.ico" +248 ICON DISCARDABLE ICON_PATH "icons/floppy_disabled.ico" +249 ICON DISCARDABLE ICON_PATH "icons/cdrom_disabled.ico" +250 ICON DISCARDABLE ICON_PATH "icons/zip_disabled.ico" +251 ICON DISCARDABLE ICON_PATH "icons/mo_disabled.ico" +252 ICON DISCARDABLE ICON_PATH "icons/storage_controllers.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -786,7 +200,7 @@ BEGIN DLG_CFG_MACHINE, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 #ifdef USE_DYNAREC BOTTOMMARGIN, 87 @@ -798,7 +212,7 @@ BEGIN DLG_CFG_VIDEO, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 38 END @@ -806,7 +220,7 @@ BEGIN DLG_CFG_INPUT, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 58 END @@ -814,7 +228,7 @@ BEGIN DLG_CFG_SOUND, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 109 END @@ -822,7 +236,7 @@ BEGIN DLG_CFG_NETWORK, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 56 END @@ -830,7 +244,7 @@ BEGIN DLG_CFG_PORTS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 48 END @@ -838,7 +252,7 @@ BEGIN DLG_CFG_PERIPHERALS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 85 END @@ -846,7 +260,7 @@ BEGIN DLG_CFG_HARD_DISKS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 137 END @@ -854,7 +268,7 @@ BEGIN DLG_CFG_FLOPPY_DRIVES, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 96 END @@ -862,7 +276,7 @@ BEGIN DLG_CFG_OTHER_REMOVABLE_DEVICES, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 260 + RIGHTMARGIN, 300 TOPMARGIN, 7 BOTTOMMARGIN, 214 END @@ -870,212 +284,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE DISCARDABLE -BEGIN - 2048 EMU_NAME - IDS_2049 "Error" - IDS_2050 "Fatal error" - IDS_2051 "Are you sure you want to save the settings?" - IDS_2052 "Press CTRL+ALT+PAGE DOWN to return to windowed mode." - IDS_2053 "Speed" - IDS_2054 "ZIP %03i %i (%s): %ls" - IDS_2055 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" - IDS_2056 EMU_NAME " could not find any usable ROM images.\n\nPlease download a ROM set from " EMU_ROMS_URL " and extract it into the ""roms"" directory." - IDS_2057 "(empty)" - IDS_2058 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" - IDS_2059 "Turbo" - IDS_2060 "On" - IDS_2061 "Off" - IDS_2062 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" - IDS_2063 "Machine ""%S"" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -END - -STRINGTABLE DISCARDABLE -BEGIN - IDS_2064 "Video card ""%S"" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." - IDS_2065 "Machine" - IDS_2066 "Display" - IDS_2067 "Input devices" - IDS_2068 "Sound" - IDS_2069 "Network" - IDS_2070 "Ports (COM & LPT)" - IDS_2071 "Other peripherals" - IDS_2072 "Hard disks" - IDS_2073 "Floppy drives" - IDS_2074 "Other removable devices" - IDS_2075 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" - IDS_2076 "Surface images (*.86F)\0*.86F\0" - IDS_2077 "Click to capture mouse" - IDS_2078 "Press F8+F12 to release mouse" - IDS_2079 "Press F8+F12 or middle button to release mouse" -END - -STRINGTABLE DISCARDABLE -BEGIN - IDS_2080 "Unable to initialize FluidSynth" - IDS_2081 "Bus" - IDS_2082 "File" - IDS_2083 "C" - IDS_2084 "H" - IDS_2085 "S" - IDS_2086 "MB" - IDS_2087 "Check BPB" - IDS_2088 "KB" - IDS_2089 "Could not initialize the video renderer." - IDS_2090 "Default" - IDS_2091 "%i Wait state(s)" - IDS_2092 "Type" - IDS_2093 "Failed to set up PCap" - IDS_2094 "No PCap devices found" - IDS_2095 "Invalid PCap device" - IDS_2096 "Standard 2-button joystick(s)" - IDS_2097 "Standard 4-button joystick" - IDS_2098 "Standard 6-button joystick" - IDS_2099 "Standard 8-button joystick" - IDS_2100 "CH Flightstick Pro" - IDS_2101 "Microsoft SideWinder Pad" - IDS_2102 "Thrustmaster Flight Control System" - IDS_2103 "None" - IDS_2104 "Unable to load keyboard accelerators." - IDS_2105 "Unable to register raw input." - IDS_2106 "%u" - IDS_2107 "%u MB (CHS: %i, %i, %i)" - IDS_2108 "Floppy %i (%s): %ls" - IDS_2109 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" - IDS_2110 "Unable to initialize FreeType" - IDS_2111 "Unable to initialize SDL, SDL2.dll is required" - IDS_2112 "Are you sure you want to hard reset the emulated machine?" - IDS_2113 "Are you sure you want to exit " EMU_NAME "?" - IDS_2114 "Unable to initialize Ghostscript" - IDS_2115 "MO %i (%03i): %ls" - IDS_2116 "MO images (*.IM?)\0*.IM?\0All files (*.*)\0*.*\0" - IDS_2117 "Welcome to " EMU_NAME "!" - IDS_2118 "Internal controller" - IDS_2119 "Exit" - IDS_2120 "No ROMs found" - IDS_2121 "Save changes\nThis will hard reset the emulated machine." - IDS_2122 "Discard changes\nAll changes made to the settings will be lost." - IDS_2123 "Cancel\nGo back to the Settings window." - IDS_2124 "About " EMU_NAME - IDS_2125 EMU_NAME " v" EMU_VERSION - IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information." - IDS_2127 "OK" - IDS_2128 "Hardware not available" -#ifdef _WIN32 -#define LIB_NAME_PCAP "WinPcap" -#else -#define LIB_NAME_PCAP "libpcap" -#endif - IDS_2129 "Make sure " LIB_NAME_PCAP " is installed and that you are on a " LIB_NAME_PCAP "-compatible network connection." - IDS_2130 "Invalid configuration" -#ifdef _WIN32 -#define LIB_NAME_FREETYPE "freetype.dll" -#else -#define LIB_NAME_FREETYPE "libfreetype" -#endif - IDS_2131 LIB_NAME_FREETYPE " is required for ESC/P printer emulation." -#ifdef _WIN32 -#define LIB_NAME_GS "gsdll32.dll" -#else -#define LIB_NAME_GS "libgs" -#endif - IDS_2132 LIB_NAME_GS " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." -#ifdef _WIN32 -#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" -#else -#define LIB_NAME_FLUIDSYNTH "libfluidsynth" -#endif - IDS_2133 LIB_NAME_FLUIDSYNTH " is required for FluidSynth MIDI output." - IDS_2134 "Entering fullscreen mode" - IDS_2135 "Don't show this message again" - IDS_2136 "Don't Exit" - IDS_2137 "Reset" - IDS_2138 "Don't Reset" -END - -STRINGTABLE DISCARDABLE -BEGIN - IDS_4096 "Hard disk (%s)" - IDS_4097 "%01i:%01i" - IDS_4098 "%i" - IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" - IDS_4100 "Custom..." - IDS_4101 "Custom (large)..." - IDS_4102 "Add New Hard Disk" - IDS_4103 "Add Existing Hard Disk" - IDS_4104 "HDI disk images cannot be larger than 4 GB." - IDS_4105 "Disk images cannot be larger than 127 GB." - IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" - IDS_4107 "Unable to read file" - IDS_4108 "Unable to write file" - IDS_4109 "HDI or HDX images with a sector size other than 512 are not supported." - IDS_4110 "USB is not yet supported" - IDS_4111 "Disk image file already exists" - IDS_4112 "Please specify a valid file name." - IDS_4113 "Disk image created" - IDS_4114 "Make sure the file exists and is readable." - IDS_4115 "Make sure the file is being saved to a writable directory." - IDS_4116 "Disk image too large" - IDS_4117 "Remember to partition and format the newly-created drive." - IDS_4118 "The selected file will be overwritten. Are you sure you want to use it?" - IDS_4119 "Unsupported disk image" - IDS_4120 "Overwrite" - IDS_4121 "Don't Overwrite" - - IDS_4352 "MFM/RLL" - IDS_4353 "XTA" - IDS_4354 "ESDI" - IDS_4355 "IDE" - IDS_4356 "SCSI" - - IDS_4608 "MFM/RLL (%01i:%01i)" - IDS_4609 "XTA (%01i:%01i)" - IDS_4610 "ESDI (%01i:%01i)" - IDS_4611 "IDE (%01i:%01i)" - IDS_4612 "SCSI (ID %02i)" - - IDS_5120 "CD-ROM %i (%s): %s" - - IDS_5376 "Disabled" - IDS_5380 "ATAPI" - IDS_5381 "SCSI" - IDS_5382 "SCSI (Chinon)" - - IDS_5632 "Disabled" - IDS_5636 "ATAPI (%01i:%01i)" - IDS_5637 "SCSI (ID %02i)" - IDS_5638 "SCSI (ID %02i)" - - IDS_5888 "160 kB" - IDS_5889 "180 kB" - IDS_5890 "320 kB" - IDS_5891 "360 kB" - IDS_5892 "640 kB" - IDS_5893 "720 kB" - IDS_5894 "1.2 MB" - IDS_5895 "1.25 MB" - IDS_5896 "1.44 MB" - IDS_5897 "DMF (cluster 1024)" - IDS_5898 "DMF (cluster 2048)" - IDS_5899 "2.88 MB" - IDS_5900 "ZIP 100" - IDS_5901 "ZIP 250" - - IDS_6144 "Perfect RPM" - IDS_6145 "1%% below perfect RPM" - IDS_6146 "1.5%% below perfect RPM" - IDS_6147 "2%% below perfect RPM" - - IDS_7168 "English (United States)" -END -#define IDS_LANG_ENUS IDS_7168 - - #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // @@ -1083,8 +291,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION EMU_VERSION_MAJ,EMU_VERSION_MIN,0,0 - PRODUCTVERSION EMU_VERSION_MAJ,EMU_VERSION_MIN,0,0 + FILEVERSION EMU_VERSION_MAJ,EMU_VERSION_MIN,EMU_VERSION_PATCH,EMU_BUILD_NUM + PRODUCTVERSION EMU_VERSION_MAJ,EMU_VERSION_MIN,EMU_VERSION_PATCH,EMU_BUILD_NUM FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -1103,9 +311,9 @@ BEGIN VALUE "FileDescription", EMU_NAME "\0" VALUE "FileVersion", EMU_VERSION "\0" VALUE "InternalName", EMU_NAME "\0" - VALUE "LegalCopyright", "Copyright © 2007-" COPYRIGHT_YEAR " " EMU_NAME " contributors\0" + VALUE "LegalCopyright", "Copyright \xa9 2007-" COPYRIGHT_YEAR " " EMU_NAME " contributors\0" VALUE "OriginalFilename", EMU_NAME ".exe\0" - VALUE "ProductName", EMU_NAME " Emulator\0" + VALUE "ProductName", EMU_NAME "\0" VALUE "ProductVersion", EMU_VERSION "\0" END END @@ -1117,8 +325,7 @@ END #endif // !_MAC -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// +#endif @@ -1131,3 +338,25 @@ END ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED + + +#include "languages/zh-CN.rc" +#include "languages/cs-CZ.rc" +#include "languages/de-DE.rc" +#include "languages/en-US.rc" +#include "languages/en-GB.rc" +#include "languages/fr-FR.rc" +#include "languages/hr-HR.rc" +#include "languages/fi-FI.rc" +#include "languages/hu-HU.rc" +#include "languages/it-IT.rc" +#include "languages/ja-JP.rc" +#include "languages/ko-KR.rc" +#include "languages/pl-PL.rc" +#include "languages/pt-BR.rc" +#include "languages/pt-PT.rc" +#include "languages/ru-RU.rc" +#include "languages/sl-SI.rc" +#include "languages/es-ES.rc" +#include "languages/tr-TR.rc" +#include "languages/uk-UA.rc" diff --git a/src/win/CMakeLists.txt b/src/win/CMakeLists.txt new file mode 100644 index 000000000..7452f82dc --- /dev/null +++ b/src/win/CMakeLists.txt @@ -0,0 +1,61 @@ +# +# 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. +# +# CMake build script. +# +# Authors: David Hrdlička, +# +# Copyright 2020,2021 David Hrdlička. +# + +enable_language(RC) + +add_library(plat OBJECT win.c win_dynld.c win_cdrom.c win_keyboard.c + win_mouse.c) + +add_library(ui OBJECT win_ui.c win_icon.c win_stbar.c win_sdl.c win_dialog.c win_about.c + win_settings.c win_devconf.c win_snd_gain.c win_specify_dim.c win_new_floppy.c + win_jsconf.c win_media_menu.c win_preferences.c glad.c win_opengl.c + win_opengl_glslp.c win_toolbar.c 86Box.rc) + +if(NOT CPPTHREADS) + target_sources(plat PRIVATE win_thread.c) +endif() + +if(RTMIDI) + target_compile_definitions(ui PRIVATE USE_RTMIDI) +endif() + +# CMake 3.22 messed this up for clang/clang++ +# See https://gitlab.kitware.com/cmake/cmake/-/issues/23066 +if(MSVC OR (NOT MINGW AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)) + # MSVC linker adds its own manifest to the executable, which fails if + # we include ours in 86Box.rc. We therefore need to pass the manifest + # directly as as a source file, so the linker can use that instead. + set_property(SOURCE 86Box.rc PROPERTY COMPILE_DEFINITIONS NO_INCLUDE_MANIFEST) + target_sources(86Box PRIVATE 86Box.manifest) +endif() + +if(NOT MINGW) + # Append null to resource strings (fixes file dialogs) + set_property(SOURCE 86Box.rc PROPERTY COMPILE_FLAGS -n) + + # `opendir` is only included in MinGW, so include an implementation + # for other builds. + target_sources(plat PRIVATE win_opendir.c) +endif() + +if(DINPUT) + target_sources(plat PRIVATE win_joystick.cpp) + target_link_libraries(86Box dinput8) +else() + target_sources(plat PRIVATE win_joystick_rawinput.c) +endif() + +target_link_libraries(86Box advapi32 comctl32 comdlg32 gdi32 shell32 iphlpapi + dxguid imm32 hid setupapi uxtheme version winmm psapi ws2_32) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 3d48ac37a..75b847dde 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -1,4 +1,5 @@ # +# # 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 @@ -30,17 +31,35 @@ ifeq ($(DEV_BUILD), y) ifndef DEBUG DEBUG := y endif + ifndef GDBSTUB + GDBSTUB := n + endif ifndef DEV_BRANCH DEV_BRANCH := y endif - ifndef 596B - 596B := y - endif ifndef AMD_K5 AMD_K5 := y endif - ifndef CL5422 - CL5422 := y + ifndef AN430TX + AN430TX := y + endif + ifndef CYRIX_6X86 + CYRIX_6X86 := y + endif + ifndef DESKPRO386 + DESKPRO386 := y + endif + ifndef GUSMAX + GUSMAX := y + endif + ifndef ISAMEM_RAMPAGE + ISAMEM_RAMPAGE := y + endif + ifndef ISAMEM_IAB + ISAMEM_IAB := y + endif + ifndef ISAMEM_BRAT + ISAMEM_BRAT := y endif ifndef LASERXT LASERXT := y @@ -48,60 +67,63 @@ ifeq ($(DEV_BUILD), y) ifndef MGA MGA := y endif + ifndef OLIVETTI + OLIVETTI := y + endif + ifndef OPEN_AT + OPEN_AT := y + endif ifndef PAS16 - PAS16 := n + PAS16 := y endif - ifndef PORTABLE3 - PORTABLE3 := y + ifndef SIO_DETECT + SIO_DETECT := y endif - ifndef PS1M2133 - PS1M2133 := y - endif - ifndef PS2M70T4 - PS2M70T4 := y - endif - ifndef VECTRA54 - VECTRA54 := y - endif - ifndef VPP60 - VPP60 := y - endif - ifndef SIEMENS - SIEMENS := y + ifndef TANDY_ISA + TANDY_ISA := y endif ifndef VGAWONDER VGAWONDER := y endif - ifndef VNC - VNC := y - endif - ifndef WIN471 - WIN471 := y - endif ifndef XL24 XL24 := y endif - ifndef NO_SIO - NO_SIO := y - endif - ifndef GUSMAX - GUSMAX := y + ifndef NEW_KBC + NEW_KBC := n endif else ifndef DEBUG DEBUG := n endif + ifndef GDBSTUB + GDBSTUB := n + endif ifndef DEV_BRANCH DEV_BRANCH := n endif - ifndef 596B - 596B := n - endif ifndef AMD_K5 AMD_K5 := n endif - ifndef CL5422 - CL5422 := n + ifndef AN430TX + AN430TX := n + endif + ifndef CYRIX_6X86 + CYRIX_6X86 := n + endif + ifndef DESKPRO386 + DESKPRO386 := n + endif + ifndef GUSMAX + GUSMAX := n + endif + ifndef ISAMEM_RAMPAGE + ISAMEM_RAMPAGE := n + endif + ifndef ISAMEM_IAB + ISAMEM_IAB := n + endif + ifndef ISAMEM_BRAT + ISAMEM_BRAT := n endif ifndef LASERXT LASERXT := n @@ -109,44 +131,29 @@ else ifndef MGA MGA := n endif + ifndef OLIVETTI + OLIVETTI := n + endif + ifndef OPEN_AT + OPEN_AT := n + endif ifndef PAS16 PAS16 := n endif - ifndef PORTABLE3 - PORTABLE3 := n + ifndef SIO_DETECT + SIO_DETECT := n endif - ifndef PS1M2133 - PS1M2133 := n - endif - ifndef PS2M70T4 - PS2M70T4 := n - endif - ifndef VECTRA54 - VECTRA54 := n - endif - ifndef VPP60 - VPP60 := n - endif - ifndef SIEMENS - SIEMENS := n + ifndef TANDY_ISA + TANDY_ISA := n endif ifndef VGAWONDER VGAWONDER := n endif - ifndef VNC - VNC := n - endif - ifndef WIN471 - WIN471 := n - endif ifndef XL24 XL24 := n endif - ifndef NO_SIO - NO_SIO := n - endif - ifndef GUSMAX - GUSMAX := n + ifndef NEW_KBC + NEW_KBC := n endif endif @@ -169,42 +176,48 @@ endif ifndef ARM64 ARM64 := n endif -ifndef WX -WX := n -endif ifndef DINPUT DINPUT := n endif +ifndef FAUDIO + FAUDIO := n +endif ifndef OPENAL -OPENAL := y + OPENAL := n endif ifndef FLUIDSYNTH -FLUIDSYNTH := y + FLUIDSYNTH := y endif ifndef MUNT -MUNT := y + MUNT := y +endif +ifndef VNC + VNC := n endif ifndef NEW_DYNAREC NEW_DYNAREC := n endif ifndef DYNAREC - DYNAREC := y + DYNAREC := y +endif +ifndef CPPTHREADS + CPPTHREADS := y +endif +ifndef RTMIDI + RTMIDI := y endif ifeq ($(DYNAREC), y) ifeq ($(ARM), y) ifeq ($(NEW_DYNAREC), n) - DYNAREC := n + DYNAREC := n endif endif ifeq ($(ARM64), y) ifeq ($(NEW_DYNAREC), n) - DYNAREC := n + DYNAREC := n endif endif endif -ifndef DISCORD - DISCORD := y -endif # Path to the dynamic recompiler code. @@ -216,85 +229,64 @@ endif # Name of the executable. -ifndef PROG - ifneq ($(WX), n) - PROG := Wx86Box - else - PROG := 86Box - endif -endif - -# WxWidgets basic info. Extract using the config program. -ifneq ($(WX), n) - EXPATH += wx - WX_CONFIG := wx-config.exe - ifeq ($(WX), y) - WX_PATH := C:/MinGW32/WxWidgets - WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ - -I$(WX_PATH)/include/wx-3.0 \ - -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread -# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma - WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ - -lwx_mswu-3.0.dll \ - -lrpcrt4 -loleaut32 -lole32 -luuid \ - -lwinspool -lwinmm -lshell32 -lcomctl32 \ - -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 - endif - ifeq ($(WX), static) - WX_PATH := C:/MinGW32/WxWidgets - WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ - -I$(WX_PATH)/include/wx-3.0 \ - -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread -# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma - WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ - -lwx_mswu-3.0 -lwxscintilla-3.0 \ - -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 \ - -lwxregexu-3.0 -lwxexpat-3.0 \ - -lrpcrt4 -loleaut32 -lole32 -luuid \ - -lwinspool -lwinmm -lshell32 -lcomctl32 \ - -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 - endif -endif +PROG := 86Box ######################################################################### # Nothing should need changing from here on.. # ######################################################################### -VPATH := $(EXPATH) . $(CODEGEN) cpu \ - cdrom chipset device disk floppy \ +VPATH := $(EXPATH) . $(CODEGEN) minitrace cpu \ + cdrom chipset device disk disk/minivhd floppy \ game machine mem printer \ sio sound \ sound/munt sound/munt/c_interface sound/munt/sha1 \ sound/munt/srchelper sound/munt/srchelper/srctools/src \ - sound/resid-fp \ + sound/resid-fp sound/ymfm \ scsi video network network/slirp win ifeq ($(X64), y) TOOL_PREFIX := x86_64-w64-mingw32- else TOOL_PREFIX := i686-w64-mingw32- endif -CPP := ${TOOL_PREFIX}g++ -CC := ${TOOL_PREFIX}gcc WINDRES := windres STRIP := strip ifeq ($(ARM64), y) +WINDRES := aarch64-w64-mingw32-windres +STRIP := aarch64-w64-mingw32-strip +endif +ifeq ($(ARM), y) +WINDRES := armv7-w64-mingw32-windres +STRIP := armv7-w64-mingw32-strip +endif +ifeq ($(CLANG), y) +CPP := clang++ +CC := clang +ifeq ($(ARM64), y) +CPP := aarch64-w64-mingw32-clang++ +CC := aarch64-w64-mingw32-clang +endif +ifeq ($(ARM), y) +CPP := armv7-w64-mingw32-clang++ +CC := armv7-w64-mingw32-clang +endif +else +CPP := ${TOOL_PREFIX}g++ +CC := ${TOOL_PREFIX}gcc +ifeq ($(ARM64), y) CPP := aarch64-w64-mingw32-g++ CC := aarch64-w64-mingw32-gcc -WINDRES := aarch64-w64-mingw32-windres -STRIP := aarch64-w64-mingw32-strip endif ifeq ($(ARM), y) CPP := armv7-w64-mingw32-g++ CC := armv7-w64-mingw32-gcc -WINDRES := armv7-w64-mingw32-windres -STRIP := armv7-w64-mingw32-strip +endif endif DEPS = -MMD -MF $*.d -c $< DEPFILE := win/.depends # Set up the correct toolchain flags. OPTS := $(EXTRAS) $(STUFF) -OPTS += -Iinclude \ +OPTS += -Iinclude -Iinclude_make \ -iquote $(CODEGEN) -iquote cpu ifdef EXFLAGS OPTS += $(EXFLAGS) @@ -302,21 +294,17 @@ endif ifdef EXINC OPTS += -I$(EXINC) endif -ifeq ($(X64), y) - ifeq ($(OPTIM), y) - DFLAGS := -march=native - else - DFLAGS := - endif +ifeq ($(OPTIM), y) + DFLAGS := -march=native else - ifeq ($(OPTIM), y) - DFLAGS := -march=native + ifeq ($(X64), y) + DFLAGS := else DFLAGS := -march=i686 endif endif ifeq ($(DEBUG), y) - DFLAGS += -ggdb -DDEBUG + DFLAGS += -ggdb -DDEBUG -DUSE_ACYCS AOPTIM := ifndef COPTIM COPTIM := -Og @@ -336,24 +324,20 @@ else endif AFLAGS := -msse2 -mfpmath=sse ifeq ($(ARM), y) - DFLAGS := -march=armv7-a - AOPTIM := + DFLAGS := -march=armv7-a + AOPTIM := AFLAGS := -mfloat-abi=hard endif ifeq ($(ARM64), y) - DFLAGS := -march=armv8-a - AOPTIM := + DFLAGS := -march=armv8-a + AOPTIM := AFLAGS := -mfloat-abi=hard endif -RFLAGS := --input-format=rc -O coff -Iinclude +RFLAGS := --input-format=rc -O coff -Iinclude -Iinclude_make ifeq ($(RELEASE), y) OPTS += -DRELEASE_BUILD RFLAGS += -DRELEASE_BUILD endif -ifeq ($(VRAMDUMP), y) -OPTS += -DENABLE_VRAM_DUMP -RFLAGS += -DENABLE_VRAM_DUMP -endif # Optional modules. @@ -405,21 +389,6 @@ else endif endif -ifeq ($(WX), y) - OPTS += -DUSE_WX $(WX_FLAGS) - LIBS += $(WX_LIBS) - UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o -else - UIOBJ := win_ui.o win_stbar.o \ - win_sdl.o \ - win_dialog.o win_about.o \ - win_settings.o win_devconf.o win_snd_gain.o \ - win_new_floppy.o win_jsconf.o win_media_menu.o -endif - -ifeq ($(OPENAL), y) -OPTS += -DUSE_OPENAL -endif ifeq ($(FLUIDSYNTH), y) OPTS += -DUSE_FLUIDSYNTH FSYNTHOBJ := midi_fluidsynth.o @@ -437,6 +406,12 @@ MUNTOBJ := midi_mt32.o \ Synth.o Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o endif +ifeq ($(CPPTHREADS), y) +THREADOBJ := thread.o +else +THREADOBJ := win_thread.o +endif + ifeq ($(VNC), y) OPTS += -DUSE_VNC RFLAGS += -DUSE_VNC @@ -444,27 +419,56 @@ RFLAGS += -DUSE_VNC OPTS += -I$(VNC_PATH)\INCLUDE VNCLIB := -L$(VNC_PATH)\LIB endif -VNCLIB += -lvncserver +VNCLIB += -lvncserver VNCOBJ := vnc.o vnc_keymap.o endif -ifeq ($(DISCORD), y) -OPTS += -DUSE_DISCORD -RFLAGS += -DUSE_DISCORD -DISCORDOBJ := win_discord.o +ifeq ($(MINITRACE), y) +OPTS += -DMTR_ENABLED +RFLAGS += -DMTR_ENABLED +MINITRACEOBJ := minitrace.o +endif + +ifeq ($(FAUDIO), y) +OPTS += -DUSE_FAUDIO endif # Options for the DEV branch. ifeq ($(DEV_BRANCH), y) OPTS += -DDEV_BRANCH +RFLAGS += -DDEV_BRANCH DEVBROBJ := ifeq ($(AMD_K5), y) OPTS += -DUSE_AMD_K5 endif -ifeq ($(CL5422), y) -OPTS += -DUSE_CL5422 +ifeq ($(AN430TX), y) +OPTS += -DUSE_AN430TX +endif + +ifeq ($(CYRIX_6X86), y) +OPTS += -DUSE_CYRIX_6X86 +endif + +ifeq ($(DESKPRO386), y) +OPTS += -DUSE_DESKPRO386 +endif + +ifeq ($(GUSMAX), y) +OPTS += -DUSE_GUSMAX +endif + +ifeq ($(ISAMEM_RAMPAGE), y) +OPTS += -DUSE_ISAMEM_RAMPAGE +endif + +ifeq ($(ISAMEM_IAB), y) +OPTS += -DUSE_ISAMEM_IAB +endif + +ifeq ($(ISAMEM_BRAT), y) +OPTS += -DUSE_ISAMEM_BRAT endif ifeq ($(LASERXT), y) @@ -477,64 +481,47 @@ OPTS += -DUSE_MGA DEVBROBJ += vid_mga.o endif +ifeq ($(OPEN_AT), y) +OPTS += -DUSE_OPEN_AT +endif + ifeq ($(PAS16), y) OPTS += -DUSE_PAS16 DEVBROBJ += snd_pas16.o endif -ifeq ($(PORTABLE3), y) -OPTS += -DUSE_PORTABLE3 +ifeq ($(SIO_DETECT), y) +OPTS += -DUSE_SIO_DETECT +DEVBROBJ += sio_detect.o endif -ifeq ($(PS1M2133), y) -OPTS += -DUSE_PS1M2133 -endif - -ifeq ($(PS2M70T4), y) -OPTS += -DUSE_PS2M70T4 -endif - -ifeq ($(VECTRA54), y) -OPTS += -DUSE_VECTRA54 -endif - -ifeq ($(VPP60), y) -OPTS += -DUSE_VPP60 -endif - -ifeq ($(SIEMENS), y) -OPTS += -DUSE_SIEMENS -endif - -ifeq ($(596B), y) -OPTS += -DUSE_596B +ifeq ($(TANDY_ISA), y) +OPTS += -DUSE_TANDY_ISA endif ifeq ($(VGAWONDER), y) OPTS += -DUSE_VGAWONDER endif -ifeq ($(WIN471), y) -OPTS += -DUSE_WIN471 -endif - ifeq ($(XL24), y) OPTS += -DUSE_XL24 endif -ifeq ($(NO_SIO), y) -OPTS += -DNO_SIO +ifeq ($(OLIVETTI), y) +OPTS += -DUSE_OLIVETTI +DEVBROBJ += olivetti_eva.o endif -ifeq ($(GUSMAX), y) -OPTS += -DUSE_GUSMAX +ifeq ($(GDBSTUB), y) +OPTS += -DUSE_GDBSTUB +DEVBROBJ += gdbstub.o endif endif # Final versions of the toolchain flags. -CFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ +CFLAGS := $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ $(AFLAGS) -fomit-frame-pointer -mstackrealign -Wall \ -fno-strict-aliasing @@ -547,58 +534,89 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := pc.o config.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ - nmi.o pic.o pit.o port_92.o ppi.o pci.o mca.o \ - usb.o device.o nvr.o nvr_at.o nvr_ps2.o \ +MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ + nmi.o pic.o pit.o pit_fast.o port_6x.o port_92.o ppi.o pci.o mca.o fifo8.o \ + usb.o device.o nvr.o nvr_at.o nvr_ps2.o machine_status.o \ $(VNCOBJ) -MEMOBJ := intel_flash.o mem.o rom.o spd.o sst_flash.o +MEMOBJ := catalyst_flash.o i2c_eeprom.o intel_flash.o mem.o rom.o smram.o spd.o sst_flash.o -CPUOBJ := cpu.o cpu_table.o \ - 808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o $(CGTOBJ) \ - x86seg.o x87.o x87_timings.o \ - $(DYNARECOBJ) +CPUOBJ := $(DYNARECOBJ) \ + $(CGTOBJ) \ + cpu.o cpu_table.o fpu.o x86.o \ + 808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o \ + x86seg.o x87.o x87_timings.o -CHIPSETOBJ := acc2168.o acer_m3a.o cs8230.o ali1429.o headland.o \ - intel_420ex.o intel_4x0.o intel_sio.o intel_piix.o ioapic.o \ - neat.o opti495.o opti5x7.o scamp.o scat.o \ - sis_85c310.o sis_85c471.o sis_85c496.o \ - via_apollo.o via_vpx.o via_vt82c586b.o via_vt82c596b.o wd76c10.o +CHIPSETOBJ := 82c100.o acc2168.o \ + contaq_82c59x.o \ + cs4031.o cs8230.o \ + ali1429.o ali1489.o ali1531.o ali1541.o ali1543.o ali1621.o ali6117.o \ + gc100.o headland.o \ + ims8848.o intel_82335.o intel_420ex.o intel_4x0.o intel_i450kx.o intel_sio.o intel_piix.o \ + ioapic.o \ + neat.o \ + opti283.o opti291.o opti391.o opti495.o opti822.o opti895.o opti5x7.o \ + scamp.o scat.o \ + stpc.o \ + wd76c10.o vl82c480.o \ + umc_8886.o umc_hb4.o \ + via_vt82c49x.o via_vt82c505.o via_apollo.o via_pipc.o \ + sis_85c310.o sis_85c4xx.o sis_85c496.o sis_85c50x.o sis_5511.o sis_5571.o MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ + m_xt_philips.o \ m_xt_t1000.o m_xt_t1000_vid.o \ m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ m_amstrad.o m_europc.o \ - m_olivetti_m24.o m_tandy.o \ + m_xt_olivetti.o m_tandy.o m_v86p.o \ m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \ m_ps1.o m_ps1_hdc.o \ m_ps2_isa.o m_ps2_mca.o \ m_at_compaq.o \ m_at_286_386sx.o m_at_386dx_486.o \ - m_at_socket4_5.o m_at_socket7_s7.o m_at_sockets7.o \ - m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o + m_at_socket4.o m_at_socket5.o m_at_socket7_3v.o m_at_socket7.o m_at_sockets7.o \ + m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ + m_at_misc.o -DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o ibm_5161.o isamem.o isartc.o lpt.o postcard.o serial.o \ - smbus.o smbus_piix4.o \ +ifeq ($(NEW_KBC), y) +DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ + ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ + clock_ics9xxx.o isapnp.o \ + i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ + keyboard.o \ + keyboard_xt.o kbc_at.o kbd_at.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o \ + phoenix_486_jumper.o +else +DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ + ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ + clock_ics9xxx.o isapnp.o \ + i2c.o i2c_gpio.o smbus_ali7101.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ mouse.o \ - mouse_bus.o \ - mouse_serial.o mouse_ps2.o + mouse_bus.o \ + mouse_serial.o mouse_ps2.o \ + phoenix_486_jumper.o +endif -SIOOBJ := sio_acc3221.o \ - sio_f82c710.o \ - sio_fdc37c66x.o sio_fdc37c669.o \ - sio_fdc37c93x.o \ - sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87332.o \ +SIOOBJ := sio_acc3221.o sio_ali5123.o \ + sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \ + sio_fdc37c67x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \ + sio_it8661f.o \ + sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \ + sio_prime3b.o sio_prime3c.o \ sio_w83787f.o \ sio_w83877f.o sio_w83977f.o \ - sio_um8669f.o + sio_um8669f.o \ + sio_vt82c686.o -FDDOBJ := fdd.o fdc.o fdc_pii15xb.o \ +FDDOBJ := fdd.o fdc.o fdc_magitronic.o fdc_pii15xb.o \ fdi2raw.o \ fdd_common.o fdd_86f.o \ fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ @@ -615,8 +633,14 @@ HDDOBJ := hdd.o \ hdc_xta.o \ hdc_esdi_at.o hdc_esdi_mca.o \ hdc_xtide.o hdc_ide.o \ + hdc_ide_opti611.o \ + hdc_ide_cmd640.o hdc_ide_cmd646.o \ hdc_ide_sff8038i.o +MINIVHDOBJ := cwalk.o libxml2_encoding.o minivhd_convert.o \ + minivhd_create.o minivhd_io.o minivhd_manage.o \ + minivhd_struct_rw.o minivhd_util.o + CDROMOBJ := cdrom.o \ cdrom_image_backend.o cdrom_image.o @@ -629,37 +653,40 @@ SCSIOBJ := scsi.o scsi_device.o \ scsi_x54x.o \ scsi_aha154x.o scsi_buslogic.o \ scsi_ncr5380.o scsi_ncr53c8xx.o \ - scsi_spock.o + scsi_pcscsi.o scsi_spock.o NETOBJ := network.o \ net_pcap.o \ - net_slirp.o \ - bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ - ip_input.o queue.o tcp_input.o debug.o ip_output.o \ - sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_slirp.o tinyglib.o \ + arp_table.o bootp.o cksum.o dnssearch.o if.o ip_icmp.o ip_input.o \ + ip_output.o mbuf.o misc.o sbuf.o slirp.o socket.o tcp_input.o \ + tcp_output.o tcp_subr.o tcp_timer.o udp.o util.o version.o \ net_dp8390.o \ net_3c503.o net_ne2000.o \ - net_pcnet.o net_wd8003.o + net_pcnet.o net_wd8003.o \ + net_plip.o PRINTOBJ := png.o prt_cpmap.o \ prt_escp.o prt_text.o prt_ps.o - + SNDOBJ := sound.o \ - openal.o \ - snd_opl.o snd_opl_backend.o \ - nukedopl.o \ + snd_opl.o snd_opl_nuked.o snd_opl_ymfm.o \ + ymfm_adpcm.o ymfm_misc.o ymfm_opl.o ymfm_opm.o \ + ymfm_opn.o ymfm_opq.o ymfm_opz.o ymfm_pcm.o ymfm_ssg.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ filter.o pot.o sid.o voice.o wave6581__ST.o \ wave6581_P_T.o wave6581_PS_.o wave6581_PST.o \ wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \ wave8580_PST.o wave.o \ - midi.o midi_system.o \ + midi.o \ snd_speaker.o \ snd_pssj.o \ + snd_ps1.o \ snd_lpt_dac.o snd_lpt_dss.o \ snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ - snd_azt2316a.o \ + snd_ac97_codec.o snd_ac97_via.o \ + snd_azt2316a.o snd_cs423x.o snd_cmi8x38.o \ snd_cms.o \ snd_gus.o \ snd_sb.o snd_sb_dsp.o \ @@ -668,7 +695,7 @@ SNDOBJ := sound.o \ snd_wss.o \ snd_ym7128.o -VIDOBJ := video.o \ +VIDOBJ := agpgart.o video.o \ vid_table.o \ vid_cga.o vid_cga_comp.o \ vid_compaq_cga.o \ @@ -681,61 +708,103 @@ VIDOBJ := video.o \ vid_wy700.o \ vid_ega.o vid_ega_render.o \ vid_svga.o vid_svga_render.o \ + vid_8514a.o \ + vid_ddc.o \ vid_vga.o \ vid_ati_eeprom.o \ vid_ati18800.o vid_ati28800.o \ vid_ati_mach64.o vid_ati68860_ramdac.o \ vid_bt48x_ramdac.o \ - vid_av9194.o \ - vid_icd2061.o vid_ics2595.o \ + vid_av9194.o vid_icd2061.o vid_ics2494.o vid_ics2595.o \ vid_cl54xx.o \ - vid_et4000.o vid_sc1502x_ramdac.o \ + vid_et4000.o vid_sc1148x_ramdac.o \ + vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ vid_ht216.o \ vid_oak_oti.o \ vid_paradise.o \ + vid_rtg310x.o \ vid_ti_cf62011.o \ + vid_f82c425.o \ vid_tvga.o \ vid_tgui9440.o vid_tkd8001_ramdac.o \ vid_att20c49x_ramdac.o \ + vid_att2xc498_ramdac.o \ vid_s3.o vid_s3_virge.o \ - vid_sdac_ramdac.o \ - vid_voodoo.o + vid_ibm_rgb528_ramdac.o vid_sdac_ramdac.o \ + vid_ogc.o \ + vid_nga.o \ + vid_tvp3026_ramdac.o \ + vid_xga.o + +VOODOOOBJ := vid_voodoo.o vid_voodoo_banshee.o \ + vid_voodoo_banshee_blitter.o \ + vid_voodoo_blitter.o \ + vid_voodoo_display.o vid_voodoo_fb.o \ + vid_voodoo_fifo.o vid_voodoo_reg.o \ + vid_voodoo_render.o vid_voodoo_setup.o \ + vid_voodoo_texture.o PLATOBJ := win.o \ - win_dynld.o win_thread.o \ + win_dynld.o \ win_cdrom.o win_keyboard.o \ - win_crashdump.o win_midi.o \ win_mouse.o +UIOBJ := win_ui.o win_icon.o win_stbar.o discord.o \ + win_sdl.o win_opengl.o win_opengl_glslp.o glad.o \ + win_dialog.o win_about.o \ + win_settings.o win_devconf.o win_snd_gain.o win_specify_dim.o win_preferences.o \ + win_new_floppy.o win_jsconf.o \ + win_media_menu.o win_toolbar.o + ifeq ($(DINPUT), y) PLATOBJ += win_joystick.o else PLATOBJ += win_joystick_rawinput.o endif +ifeq ($(OPENAL), y) + SNDOBJ += openal.o +else + SNDOBJ += xaudio2.o +endif + OBJ := $(MAINOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) $(DEVOBJ) $(MEMOBJ) \ - $(FDDOBJ) $(GAMEOBJ) $(CDROMOBJ) $(ZIPOBJ) $(MOOBJ) $(HDDOBJ) \ - $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SIOOBJ) $(SNDOBJ) $(VIDOBJ) \ - $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) $(DEVBROBJ) \ - $(DISCORDOBJ) + $(FDDOBJ) $(GAMEOBJ) $(CDROMOBJ) $(ZIPOBJ) $(MOOBJ) $(HDDOBJ) $(MINIVHDOBJ) \ + $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SIOOBJ) $(SNDOBJ) $(VIDOBJ) $(VOODOOOBJ) \ + $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) $(DEVBROBJ) $(MINITRACEOBJ) $(THREADOBJ) ifdef EXOBJ OBJ += $(EXOBJ) endif -LIBS := -mwindows -lcomctl32 \ - -lopenal -lole32 +ifeq ($(OPENAL), y) +LIBS := -mwindows -lopenal -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +else +ifeq ($(FAUDIO), y) +LIBS := -mwindows -lfaudio -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +else +LIBS := -mwindows -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +endif +endif + +ifeq ($(RTMIDI), y) + SNDOBJ += midi_rtmidi.o + OPTS += -DUSE_RTMIDI + LIBS += -lrtmidi +endif ifeq ($(VNC), y) LIBS += $(VNCLIB) -lws2_32 endif -ifneq ($(WX), n) -LIBS += $(WX_LIBS) -lm -endif -LIBS += -lpng -lz -lwsock32 -lshell32 -liphlpapi -lpsapi -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -lversion -lwinmm -static -lstdc++ +LIBS += -lpng -lz -lwsock32 -liphlpapi -lpsapi -lhid -lsetupapi -luxtheme -static -lstdc++ ifneq ($(X64), y) +ifneq ($(ARM64), y) LIBS += -Wl,--large-address-aware endif +endif +ifeq ($(ARM64), y) +LIBS += -lgcc +endif ifeq ($(DINPUT), y) LIBS += -ldinput8 endif @@ -770,17 +839,22 @@ else %.d: %.c $(wildcard $*.d) @echo $< - @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL + @$(CC) $(CFLAGS) $(DEPS) -E $< >/dev/null %.d: %.cc $(wildcard $*.d) @echo $< - @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >/dev/null %.d: %.cpp $(wildcard $*.d) @echo $< - @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >/dev/null endif +# Suppress false positive warnings in vid_voodoo_codegen_x86[-64].h +# that cause ~3000 lines to be output into the logs each time. +ifneq ($(CLANG), y) + $(VOODOOOBJ): CFLAGS += -Wstringop-overflow=0 +endif all: $(PROG).exe @@ -808,7 +882,7 @@ ifneq ($(DEBUG), y) endif hello.exe: hello.o - $(CXX) $(LDFLAGS) -o hello.exe hello.o $(WXLIBS) $(LIBS) + $(CXX) $(LDFLAGS) -o hello.exe hello.o $(LIBS) ifneq ($(DEBUG), y) @$(STRIP) hello.exe endif @@ -816,18 +890,18 @@ endif clean: @echo Cleaning objects.. - @-rm -f *.o 2>NUL - @-rm -f *.res 2>NUL + @-rm -f *.o 2>/dev/null + @-rm -f *.res 2>/dev/null clobber: clean @echo Cleaning executables.. - @-rm -f *.d 2>NUL - @-rm -f *.exe 2>NUL -# @-rm -f $(DEPFILE) 2>NUL + @-rm -f *.d 2>/dev/null + @-rm -f *.exe 2>/dev/null +# @-rm -f $(DEPFILE) 2>/dev/null ifneq ($(AUTODEP), y) depclean: - @-rm -f $(DEPFILE) 2>NUL + @-rm -f $(DEPFILE) 2>/dev/null @echo Creating dependencies.. @echo # Run "make depends" to re-create this file. >$(DEPFILE) diff --git a/src/win/assets/86Box-green.png b/src/win/assets/86Box-green.png new file mode 100644 index 000000000..c1af649a1 Binary files /dev/null and b/src/win/assets/86Box-green.png differ diff --git a/src/win/assets/86box-rb.png b/src/win/assets/86box-rb.png new file mode 100644 index 000000000..a29748b8d Binary files /dev/null and b/src/win/assets/86box-rb.png differ diff --git a/src/win/assets/86box-red.png b/src/win/assets/86box-red.png new file mode 100644 index 000000000..0ddf9d3a4 Binary files /dev/null and b/src/win/assets/86box-red.png differ diff --git a/src/win/assets/86box-yellow.png b/src/win/assets/86box-yellow.png new file mode 100644 index 000000000..d8c74def7 Binary files /dev/null and b/src/win/assets/86box-yellow.png differ diff --git a/src/win/assets/86box.png b/src/win/assets/86box.png new file mode 100644 index 000000000..a29748b8d Binary files /dev/null and b/src/win/assets/86box.png differ diff --git a/src/win/assets/status-paused.png b/src/win/assets/status-paused.png new file mode 100644 index 000000000..e913fbf6c Binary files /dev/null and b/src/win/assets/status-paused.png differ diff --git a/src/win/assets/status-running.png b/src/win/assets/status-running.png new file mode 100644 index 000000000..f6cc5fec1 Binary files /dev/null and b/src/win/assets/status-running.png differ diff --git a/src/win/glad.c b/src/win/glad.c new file mode 100644 index 000000000..8e0da2f36 --- /dev/null +++ b/src/win/glad.c @@ -0,0 +1,983 @@ +/* + + OpenGL loader generated by glad 0.1.34 on Sat Dec 4 18:46:02 2021. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=3.0 + Profile: core + Extensions: + GL_ARB_buffer_storage, + GL_ARB_debug_output, + GL_ARB_sync + Loader: True + Local files: False + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="core" --api="gl=3.0" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_debug_output,GL_ARB_sync" + Online: + https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.0&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_debug_output&extensions=GL_ARB_sync +*/ + +#include +#include +#include +#include + +static void* get_proc(const char *namez); + +#if defined(_WIN32) || defined(__CYGWIN__) +#ifndef _WINDOWS_ +#undef APIENTRY +#endif +#include +static HMODULE libGL; + +typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); +static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; + +#ifdef _MSC_VER +#ifdef __has_include + #if __has_include() + #define HAVE_WINAPIFAMILY 1 + #endif +#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ + #define HAVE_WINAPIFAMILY 1 +#endif +#endif + +#ifdef HAVE_WINAPIFAMILY + #include + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #define IS_UWP 1 + #endif +#endif + +static +int open_gl(void) { +#ifndef IS_UWP + libGL = LoadLibraryW(L"opengl32.dll"); + if(libGL != NULL) { + void (* tmp)(void); + tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress"); + gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp; + return gladGetProcAddressPtr != NULL; + } +#endif + + return 0; +} + +static +void close_gl(void) { + if(libGL != NULL) { + FreeLibrary((HMODULE) libGL); + libGL = NULL; + } +} +#else +#include +static void* libGL; + +#if !defined(__APPLE__) && !defined(__HAIKU__) +typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); +static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; +#endif + +static +int open_gl(void) { +#ifdef __APPLE__ + static const char *NAMES[] = { + "../Frameworks/OpenGL.framework/OpenGL", + "/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" + }; +#else + static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; +#endif + + unsigned int index = 0; + for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) { + libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); + + if(libGL != NULL) { +#if defined(__APPLE__) || defined(__HAIKU__) + return 1; +#else + gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, + "glXGetProcAddressARB"); + return gladGetProcAddressPtr != NULL; +#endif + } + } + + return 0; +} + +static +void close_gl(void) { + if(libGL != NULL) { + dlclose(libGL); + libGL = NULL; + } +} +#endif + +static +void* get_proc(const char *namez) { + void* result = NULL; + if(libGL == NULL) return NULL; + +#if !defined(__APPLE__) && !defined(__HAIKU__) + if(gladGetProcAddressPtr != NULL) { + result = gladGetProcAddressPtr(namez); + } +#endif + if(result == NULL) { +#if defined(_WIN32) || defined(__CYGWIN__) + result = (void*)GetProcAddress((HMODULE) libGL, namez); +#else + result = dlsym(libGL, namez); +#endif + } + + return result; +} + +int gladLoadGL(void) { + int status = 0; + + if(open_gl()) { + status = gladLoadGLLoader(&get_proc); + close_gl(); + } + + return status; +} + +struct gladGLversionStruct GLVersion = { 0, 0 }; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + unsigned int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < (unsigned)num_exts_i; index++) { + const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp); + + char *local_str = (char*)malloc((len+1) * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); + } + exts_i[index] = local_str; + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + int index; + for(index = 0; index < num_exts_i; index++) { + free((char *)exts_i[index]); + } + free((void *)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + if(exts_i == NULL) return 0; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(exts_i[index] != NULL && strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_VERSION_1_0 = 0; +int GLAD_GL_VERSION_1_1 = 0; +int GLAD_GL_VERSION_1_2 = 0; +int GLAD_GL_VERSION_1_3 = 0; +int GLAD_GL_VERSION_1_4 = 0; +int GLAD_GL_VERSION_1_5 = 0; +int GLAD_GL_VERSION_2_0 = 0; +int GLAD_GL_VERSION_2_1 = 0; +int GLAD_GL_VERSION_3_0 = 0; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; +PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEIPROC glad_glDisablei = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEIPROC glad_glEnablei = NULL; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; +PFNGLENDQUERYPROC glad_glEndQuery = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENQUERIESPROC glad_glGenQueries = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; +PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; +PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISQUERYPROC glad_glIsQuery = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLLOGICOPPROC glad_glLogicOp = NULL; +PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; +PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; +PFNGLPOINTSIZEPROC glad_glPointSize = NULL; +PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +int GLAD_GL_ARB_buffer_storage = 0; +int GLAD_GL_ARB_debug_output = 0; +int GLAD_GL_ARB_sync = 0; +PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL; +PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL; +PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL; +PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL; +PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB = NULL; +PFNGLFENCESYNCPROC glad_glFenceSync = NULL; +PFNGLISSYNCPROC glad_glIsSync = NULL; +PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; +PFNGLWAITSYNCPROC glad_glWaitSync = NULL; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; +PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_ARB_buffer_storage(GLADloadproc load) { + if(!GLAD_GL_ARB_buffer_storage) return; + glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage"); +} +static void load_GL_ARB_debug_output(GLADloadproc load) { + if(!GLAD_GL_ARB_debug_output) return; + glad_glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC)load("glDebugMessageControlARB"); + glad_glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC)load("glDebugMessageInsertARB"); + glad_glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)load("glDebugMessageCallbackARB"); + glad_glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC)load("glGetDebugMessageLogARB"); +} +static void load_GL_ARB_sync(GLADloadproc load) { + if(!GLAD_GL_ARB_sync) return; + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); +} +static int find_extensionsGL(void) { + if (!get_exts()) return 0; + GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage"); + GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output"); + GLAD_GL_ARB_sync = has_ext("GL_ARB_sync"); + free_exts(); + return 1; +} + +static void find_coreGL(void) { + + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 0)) { + max_loaded_major = 3; + max_loaded_minor = 0; + } +} + +int gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + + if (!find_extensionsGL()) return 0; + load_GL_ARB_buffer_storage(load); + load_GL_ARB_debug_output(load); + load_GL_ARB_sync(load); + return GLVersion.major != 0 || GLVersion.minor != 0; +} diff --git a/src/win/icons/86Box-RB.ico b/src/win/icons/86Box-RB.ico deleted file mode 100644 index 2106da7e4..000000000 Binary files a/src/win/icons/86Box-RB.ico and /dev/null differ diff --git a/src/win/icons/86Box-gray.ico b/src/win/icons/86Box-gray.ico new file mode 100644 index 000000000..c9cbad17d Binary files /dev/null and b/src/win/icons/86Box-gray.ico differ diff --git a/src/win/icons/86Box-green.ico b/src/win/icons/86Box-green.ico new file mode 100644 index 000000000..5c783674d Binary files /dev/null and b/src/win/icons/86Box-green.ico differ diff --git a/src/win/icons/86Box-red.ico b/src/win/icons/86Box-red.ico new file mode 100644 index 000000000..6b4666c43 Binary files /dev/null and b/src/win/icons/86Box-red.ico differ diff --git a/src/win/icons/86Box-yellow.ico b/src/win/icons/86Box-yellow.ico new file mode 100644 index 000000000..c3822c89b Binary files /dev/null and b/src/win/icons/86Box-yellow.ico differ diff --git a/src/win/icons/86Box.ico b/src/win/icons/86Box.ico deleted file mode 100644 index 00ae0c3e8..000000000 Binary files a/src/win/icons/86Box.ico and /dev/null differ diff --git a/src/win/icons/acpi_shutdown.ico b/src/win/icons/acpi_shutdown.ico new file mode 100644 index 000000000..a2493b803 Binary files /dev/null and b/src/win/icons/acpi_shutdown.ico differ diff --git a/src/win/icons/cartridge.ico b/src/win/icons/cartridge.ico new file mode 100644 index 000000000..1c92e32c6 Binary files /dev/null and b/src/win/icons/cartridge.ico differ diff --git a/src/win/icons/cartridge_empty.ico b/src/win/icons/cartridge_empty.ico new file mode 100644 index 000000000..9ff90846e Binary files /dev/null and b/src/win/icons/cartridge_empty.ico differ diff --git a/src/win/icons/cassette.ico b/src/win/icons/cassette.ico new file mode 100644 index 000000000..d0ac9fb08 Binary files /dev/null and b/src/win/icons/cassette.ico differ diff --git a/src/win/icons/cassette_active.ico b/src/win/icons/cassette_active.ico new file mode 100644 index 000000000..32fca20b4 Binary files /dev/null and b/src/win/icons/cassette_active.ico differ diff --git a/src/win/icons/cassette_empty.ico b/src/win/icons/cassette_empty.ico new file mode 100644 index 000000000..16c6e8457 Binary files /dev/null and b/src/win/icons/cassette_empty.ico differ diff --git a/src/win/icons/cassette_empty_active.ico b/src/win/icons/cassette_empty_active.ico new file mode 100644 index 000000000..e1bf61f61 Binary files /dev/null and b/src/win/icons/cassette_empty_active.ico differ diff --git a/src/win/icons/cdrom.ico b/src/win/icons/cdrom.ico index bfb69e438..0b28c73fe 100644 Binary files a/src/win/icons/cdrom.ico and b/src/win/icons/cdrom.ico differ diff --git a/src/win/icons/cdrom_active.ico b/src/win/icons/cdrom_active.ico index 95d39b84d..6f2ef197c 100644 Binary files a/src/win/icons/cdrom_active.ico and b/src/win/icons/cdrom_active.ico differ diff --git a/src/win/icons/cdrom_disabled.ico b/src/win/icons/cdrom_disabled.ico index b755e789a..cd8b9b7a6 100644 Binary files a/src/win/icons/cdrom_disabled.ico and b/src/win/icons/cdrom_disabled.ico differ diff --git a/src/win/icons/cdrom_empty.ico b/src/win/icons/cdrom_empty.ico index 78e6d15b1..45580999c 100644 Binary files a/src/win/icons/cdrom_empty.ico and b/src/win/icons/cdrom_empty.ico differ diff --git a/src/win/icons/cdrom_empty_active.ico b/src/win/icons/cdrom_empty_active.ico index b3b27574c..a48371bd7 100644 Binary files a/src/win/icons/cdrom_empty_active.ico and b/src/win/icons/cdrom_empty_active.ico differ diff --git a/src/win/icons/display.ico b/src/win/icons/display.ico index ae0e1f861..65c6b85a9 100644 Binary files a/src/win/icons/display.ico and b/src/win/icons/display.ico differ diff --git a/src/win/icons/floppy_35.ico b/src/win/icons/floppy_35.ico index 38eade5ec..9f4412fcc 100644 Binary files a/src/win/icons/floppy_35.ico and b/src/win/icons/floppy_35.ico differ diff --git a/src/win/icons/floppy_35_active.ico b/src/win/icons/floppy_35_active.ico index 20b786f6c..9600a3af0 100644 Binary files a/src/win/icons/floppy_35_active.ico and b/src/win/icons/floppy_35_active.ico differ diff --git a/src/win/icons/floppy_35_empty.ico b/src/win/icons/floppy_35_empty.ico index 93de40cfd..ac47b4c55 100644 Binary files a/src/win/icons/floppy_35_empty.ico and b/src/win/icons/floppy_35_empty.ico differ diff --git a/src/win/icons/floppy_35_empty_active.ico b/src/win/icons/floppy_35_empty_active.ico index 45eeef7b5..4f0c928d6 100644 Binary files a/src/win/icons/floppy_35_empty_active.ico and b/src/win/icons/floppy_35_empty_active.ico differ diff --git a/src/win/icons/floppy_525.ico b/src/win/icons/floppy_525.ico index 7ea15d84d..017cae3a8 100644 Binary files a/src/win/icons/floppy_525.ico and b/src/win/icons/floppy_525.ico differ diff --git a/src/win/icons/floppy_525_active.ico b/src/win/icons/floppy_525_active.ico index 3bedb572a..e19baa8a2 100644 Binary files a/src/win/icons/floppy_525_active.ico and b/src/win/icons/floppy_525_active.ico differ diff --git a/src/win/icons/floppy_525_empty.ico b/src/win/icons/floppy_525_empty.ico index 017c9dc0e..8fa6c6b87 100644 Binary files a/src/win/icons/floppy_525_empty.ico and b/src/win/icons/floppy_525_empty.ico differ diff --git a/src/win/icons/floppy_525_empty_active.ico b/src/win/icons/floppy_525_empty_active.ico index 2224ae502..703d2a64f 100644 Binary files a/src/win/icons/floppy_525_empty_active.ico and b/src/win/icons/floppy_525_empty_active.ico differ diff --git a/src/win/icons/floppy_and_cdrom_drives.ico b/src/win/icons/floppy_and_cdrom_drives.ico new file mode 100644 index 000000000..eb0ab95ed Binary files /dev/null and b/src/win/icons/floppy_and_cdrom_drives.ico differ diff --git a/src/win/icons/floppy_disabled.ico b/src/win/icons/floppy_disabled.ico index 8b20f4f51..439996c81 100644 Binary files a/src/win/icons/floppy_disabled.ico and b/src/win/icons/floppy_disabled.ico differ diff --git a/src/win/icons/floppy_drives.ico b/src/win/icons/floppy_drives.ico deleted file mode 100644 index 58c96091f..000000000 Binary files a/src/win/icons/floppy_drives.ico and /dev/null differ diff --git a/src/win/icons/hard_disk.ico b/src/win/icons/hard_disk.ico index 36439eb31..ee0c378cf 100644 Binary files a/src/win/icons/hard_disk.ico and b/src/win/icons/hard_disk.ico differ diff --git a/src/win/icons/hard_disk_active.ico b/src/win/icons/hard_disk_active.ico index 52be00623..9946a7f2e 100644 Binary files a/src/win/icons/hard_disk_active.ico and b/src/win/icons/hard_disk_active.ico differ diff --git a/src/win/icons/hard_reset.ico b/src/win/icons/hard_reset.ico new file mode 100644 index 000000000..d0494f40b Binary files /dev/null and b/src/win/icons/hard_reset.ico differ diff --git a/src/win/icons/input_devices.ico b/src/win/icons/input_devices.ico index d18ad23d0..0272d6925 100644 Binary files a/src/win/icons/input_devices.ico and b/src/win/icons/input_devices.ico differ diff --git a/src/win/icons/machine.ico b/src/win/icons/machine.ico index a247316c3..a727d1991 100644 Binary files a/src/win/icons/machine.ico and b/src/win/icons/machine.ico differ diff --git a/src/win/icons/mo.ico b/src/win/icons/mo.ico index b84f5b919..de16a1482 100644 Binary files a/src/win/icons/mo.ico and b/src/win/icons/mo.ico differ diff --git a/src/win/icons/mo_active.ico b/src/win/icons/mo_active.ico index 26ffaa625..06b788b4d 100644 Binary files a/src/win/icons/mo_active.ico and b/src/win/icons/mo_active.ico differ diff --git a/src/win/icons/mo_disabled.ico b/src/win/icons/mo_disabled.ico index 08f66d4f7..4464b6b1c 100644 Binary files a/src/win/icons/mo_disabled.ico and b/src/win/icons/mo_disabled.ico differ diff --git a/src/win/icons/mo_empty.ico b/src/win/icons/mo_empty.ico index 9583502bd..30481522a 100644 Binary files a/src/win/icons/mo_empty.ico and b/src/win/icons/mo_empty.ico differ diff --git a/src/win/icons/mo_empty_active.ico b/src/win/icons/mo_empty_active.ico index a07edb47d..29c82845b 100644 Binary files a/src/win/icons/mo_empty_active.ico and b/src/win/icons/mo_empty_active.ico differ diff --git a/src/win/icons/network.ico b/src/win/icons/network.ico index 39920c3cf..dd9f4051b 100644 Binary files a/src/win/icons/network.ico and b/src/win/icons/network.ico differ diff --git a/src/win/icons/network_active.ico b/src/win/icons/network_active.ico index 2389fbe55..25caaadfa 100644 Binary files a/src/win/icons/network_active.ico and b/src/win/icons/network_active.ico differ diff --git a/src/win/icons/other_peripherals.ico b/src/win/icons/other_peripherals.ico index 111506318..78c52e199 100644 Binary files a/src/win/icons/other_peripherals.ico and b/src/win/icons/other_peripherals.ico differ diff --git a/src/win/icons/other_removable_devices.ico b/src/win/icons/other_removable_devices.ico index ff389b15c..ed5db133c 100644 Binary files a/src/win/icons/other_removable_devices.ico and b/src/win/icons/other_removable_devices.ico differ diff --git a/src/win/icons/pause.ico b/src/win/icons/pause.ico new file mode 100644 index 000000000..a57bc0a08 Binary files /dev/null and b/src/win/icons/pause.ico differ diff --git a/src/win/icons/ports.ico b/src/win/icons/ports.ico index eece4a7dc..bd7f3f518 100644 Binary files a/src/win/icons/ports.ico and b/src/win/icons/ports.ico differ diff --git a/src/win/icons/run.ico b/src/win/icons/run.ico new file mode 100644 index 000000000..90a7f2886 Binary files /dev/null and b/src/win/icons/run.ico differ diff --git a/src/win/icons/send_cad.ico b/src/win/icons/send_cad.ico new file mode 100644 index 000000000..e3e64a743 Binary files /dev/null and b/src/win/icons/send_cad.ico differ diff --git a/src/win/icons/send_cae.ico b/src/win/icons/send_cae.ico new file mode 100644 index 000000000..757f38d35 Binary files /dev/null and b/src/win/icons/send_cae.ico differ diff --git a/src/win/icons/settings.ico b/src/win/icons/settings.ico new file mode 100644 index 000000000..ed64740b2 Binary files /dev/null and b/src/win/icons/settings.ico differ diff --git a/src/win/icons/sound.ico b/src/win/icons/sound.ico index dfdc1b86c..70d0f28f9 100644 Binary files a/src/win/icons/sound.ico and b/src/win/icons/sound.ico differ diff --git a/src/win/icons/storage_controllers.ico b/src/win/icons/storage_controllers.ico new file mode 100644 index 000000000..3f2a4d99e Binary files /dev/null and b/src/win/icons/storage_controllers.ico differ diff --git a/src/win/icons/zip.ico b/src/win/icons/zip.ico index b84f5b919..eeeaa50ee 100644 Binary files a/src/win/icons/zip.ico and b/src/win/icons/zip.ico differ diff --git a/src/win/icons/zip_active.ico b/src/win/icons/zip_active.ico index 26ffaa625..40b3a5930 100644 Binary files a/src/win/icons/zip_active.ico and b/src/win/icons/zip_active.ico differ diff --git a/src/win/icons/zip_disabled.ico b/src/win/icons/zip_disabled.ico index 08f66d4f7..eb2dd9d1b 100644 Binary files a/src/win/icons/zip_disabled.ico and b/src/win/icons/zip_disabled.ico differ diff --git a/src/win/icons/zip_empty.ico b/src/win/icons/zip_empty.ico index 9583502bd..4123c7cc2 100644 Binary files a/src/win/icons/zip_empty.ico and b/src/win/icons/zip_empty.ico differ diff --git a/src/win/icons/zip_empty_active.ico b/src/win/icons/zip_empty_active.ico index a07edb47d..d57860b10 100644 Binary files a/src/win/icons/zip_empty_active.ico and b/src/win/icons/zip_empty_active.ico differ diff --git a/src/win/languages/cs-CZ.rc b/src/win/languages/cs-CZ.rc new file mode 100644 index 000000000..c7bdb3cb1 --- /dev/null +++ b/src/win/languages/cs-CZ.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Czech (Czech Republic) resources + +#ifdef _WIN32 +LANGUAGE LANG_CZECH, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Akce" + BEGIN + MENUITEM "&Klávesnice vyžaduje záběr", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Pravý Ctrl je levý Alt", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Resetovat", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "P&ozastavit", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Ukončit", IDM_ACTION_EXIT + END + POPUP "&Zobrazení" + BEGIN + MENUITEM "&Schovat stavový řádek", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Schovat panel &nástrojů", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Měnitelná velikost okna", IDM_VID_RESIZE + MENUITEM "&Pamatovat velikost a pozici", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Renderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "&Zadat velikost...", IDM_VID_SPECIFY_DIM + MENUITEM "&Dodržovat poměr stran 4:3", IDM_VID_FORCE43 + POPUP "&Násobek zvětšení okna" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Metoda &filtrování" + BEGIN + MENUITEM "&Nejbližší", IDM_VID_FILTER_NEAREST + MENUITEM "&Lineární", IDM_VID_FILTER_LINEAR + END + MENUITEM "Š&kálování HiDPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Celá obrazovka\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Režím roztá&hnutí při celé obrazovce" + BEGIN + MENUITEM "&Roztáhnout", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Zachovat poměr stran", IDM_VID_FS_KEEPRATIO + MENUITEM "&Celočíselné škálování", IDM_VID_FS_INT + END + POPUP "Nastavení pro E&GA a (S)VGA" + BEGIN + MENUITEM "&Převrátit barvy", IDM_VID_INVERT + POPUP "&Typ VGA monitoru" + BEGIN + MENUITEM "RGB &barevný", IDM_VID_GRAY_RGB + MENUITEM "&Odstíny šedi", IDM_VID_GRAY_MONO + MENUITEM "&Jantarová obrazovka", IDM_VID_GRAY_AMBER + MENUITEM "&Zelená obrazovka", IDM_VID_GRAY_GREEN + MENUITEM "&Bílá obrazovka", IDM_VID_GRAY_WHITE + END + POPUP "Převod na &odstíny šedi" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Průměr", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Přesah obrazu CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "&Upravit kontrast černobílé obrazovky", IDM_VID_CGACON + END + MENUITEM "&Média", IDM_MEDIA + POPUP "&Nástroje" + BEGIN + MENUITEM "&Nastavení...", IDM_CONFIG + MENUITEM "&Aktualizovat ikony stavového řádku", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Pořídit &screenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Předvolby...", IDM_PREFERENCES + MENUITEM "Povolit integraci s &Discordem", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Zesílení zvuku", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Začít trace\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Zastavit trace\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "Ná&pověda" + BEGIN + MENUITEM "&Dokumentace", IDM_DOCS + MENUITEM "&O programu 86Box", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nový obraz...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existující obraz...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Existující obraz (&ochrana proti zápisu)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Nahrávat", IDM_CASSETTE_RECORD + MENUITEM "&Přehrát", IDM_CASSETTE_PLAY + MENUITEM "Přetočit na &začátek", IDM_CASSETTE_REWIND + MENUITEM "Přetočit na &konec", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Vyjmout", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Obraz...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Vyjmout", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nový obraz...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existující obraz...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Existující obraz (&ochrana proti zápisu)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xportovat do 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Vyjmout", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Ztišit", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Vyjmout", IDM_CDROM_EMPTY + MENUITEM "&Načíst znova předchozí obraz", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Obraz...", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nový obraz...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existující obraz...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Existující obraz (&ochrana proti zápisu)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Vyjmout", IDM_ZIP_EJECT + MENUITEM "&Načíst znova předchozí obraz", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nový obraz...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existující obraz...", IDM_MO_IMAGE_EXISTING + MENUITEM "Existující obraz (&ochrana proti zápisu)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Vyjmout", IDM_MO_EJECT + MENUITEM "&Načíst znova předchozí obraz", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Cílová snímková frekvence" + BEGIN + MENUITEM "&Synchronizovat s obrazem", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Zvolit shader...", IDM_VID_GL_SHADER + MENUITEM "&Odebrat shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Předvolby" +#define STR_SND_GAIN "Zesílení zvuku" +#define STR_NEW_FLOPPY "Nový obraz" +#define STR_CONFIG "Nastavení" +#define STR_SPECIFY_DIM "Zadat rozměry hlavního okna" + +#define STR_OK "OK" +#define STR_CANCEL "Storno" +#define STR_GLOBAL "Uložit toto nastavení jako &globální výchozí stav" +#define STR_DEFAULT "&Výchozí" +#define STR_LANGUAGE "Jazyk:" +#define STR_ICONSET "Sada ikon:" + +#define STR_GAIN "Zesílení" + +#define STR_FILE_NAME "Název souboru:" +#define STR_DISK_SIZE "Velikost disku:" +#define STR_RPM_MODE "Režím ot./m:" +#define STR_PROGRESS "Průběh:" + +#define STR_WIDTH "Šířka:" +#define STR_HEIGHT "Výška:" +#define STR_LOCK_TO_SIZE "Uzamknout na tyto rozměry" + +#define STR_MACHINE_TYPE "Typ počítače:" +#define STR_MACHINE "Počítač:" +#define STR_CONFIGURE "Nastavit" +#define STR_CPU_TYPE "Procesor:" +#define STR_CPU_SPEED "Rychlost:" +#define STR_FPU "Koprocesor:" +#define STR_WAIT_STATES "Čekací stavy:" +#define STR_MB "MB" +#define STR_MEMORY "Pamět:" +#define STR_TIME_SYNC "Synchronizace času" +#define STR_DISABLED "Vypnuta" +#define STR_ENABLED_LOCAL "Zapnuta (místní čas)" +#define STR_ENABLED_UTC "Zapnuta (UTC)" +#define STR_DYNAREC "Dynamický překladač" + +#define STR_VIDEO "Grafika:" +#define STR_VOODOO "Použít grafický akcelerátor Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Myš:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Zvuková karta:" +#define STR_MIDI_OUT "MIDI výstup:" +#define STR_MIDI_IN "MIDI vstup:" +#define STR_MPU401 "Samostatný MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Použít zvuk FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Druh sítě:" +#define STR_PCAP "PCap zařízení:" +#define STR_NET "Síťový adaptér:" + +#define STR_COM1 "Zařízení na COM1:" +#define STR_COM2 "Zařízení na COM2:" +#define STR_COM3 "Zařízení na COM3:" +#define STR_COM4 "Zařízení na COM4:" +#define STR_LPT1 "Zařízení na LPT1:" +#define STR_LPT2 "Zařízení na LPT2:" +#define STR_LPT3 "Zařízení na LPT3:" +#define STR_LPT4 "Zařízení na LPT4:" +#define STR_SERIAL1 "Povolit port COM1" +#define STR_SERIAL2 "Povolit port COM2" +#define STR_SERIAL3 "Povolit port COM3" +#define STR_SERIAL4 "Povolit port COM4" +#define STR_PARALLEL1 "Povolit port LPT1" +#define STR_PARALLEL2 "Povolit port LPT2" +#define STR_PARALLEL3 "Povolit port LPT3" +#define STR_PARALLEL4 "Povolit port LPT4" + +#define STR_HDC "Řadič disku:" +#define STR_FDC "Disketový řadič:" +#define STR_IDE_TER "Třetí řadič IDE" +#define STR_IDE_QUA "Čtvrtý řadič IDE" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Řadič 1:" +#define STR_SCSI_2 "Řadič 2:" +#define STR_SCSI_3 "Řadič 3:" +#define STR_SCSI_4 "Řadič 4:" +#define STR_CASSETTE "Kazeta" + +#define STR_HDD "Pevné disky:" +#define STR_NEW "&Nový..." +#define STR_EXISTING "&Existující..." +#define STR_REMOVE "&Odebrat" +#define STR_BUS "Sběrnice:" +#define STR_CHANNEL "Kanál:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Zadat..." +#define STR_SECTORS "Sektory:" +#define STR_HEADS "Hlavy:" +#define STR_CYLS "Cylindry:" +#define STR_SIZE_MB "Velikost (MB):" +#define STR_TYPE "Typ:" +#define STR_IMG_FORMAT "Formát obrazu:" +#define STR_BLOCK_SIZE "Velikost bloků:" + +#define STR_FLOPPY_DRIVES "Disketové mechaniky:" +#define STR_TURBO "Turbo časování" +#define STR_CHECKBPB "Kontrola BPB" +#define STR_CDROM_DRIVES "Mechaniky CD-ROM:" +#define STR_CD_SPEED "Rychlost:" + +#define STR_MO_DRIVES "Magnetooptické mechaniky:" +#define STR_ZIP_DRIVES "Mechaniky ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA hodiny:" +#define STR_ISAMEM "ISA rozšíření paměti" +#define STR_ISAMEM_1 "Karta 1:" +#define STR_ISAMEM_2 "Karta 2:" +#define STR_ISAMEM_3 "Karta 3:" +#define STR_ISAMEM_4 "Karta 4:" +#define STR_BUGGER "Zařízení ISABugger" +#define STR_POSTCARD "Karta pro kódy POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Chyba" + IDS_2050 "Kritická chyba" + IDS_2051 " - PAUSED" + IDS_2052 "Stiskněte Ctrl+Alt+PgDn pro návrat z režimu celé obrazovky." + IDS_2053 "Rychlost" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Obrazy ZIP disků (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box nenalezl žádné použitelné image pamětí ROM.\n\nStáhněte sadu obrazů ROM a extrahujte ji do složky ""roms""." + IDS_2057 "(prázdné)" + IDS_2058 "Obrazy ZIP disků (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Zap." + IDS_2061 "Vyp." + IDS_2062 "Všechny obrazy disků (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Základní sektorové obrazy (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Obrazy povrchu (*.86F)\0*.86F\0" + IDS_2063 "Počítač ""%hs"" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce ""roms/machines"". Konfigurace se přepne na jiný dostupný počítač." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Video adaptér ""%hs"" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce ""roms/video"". Konfigurace se přepne na jiný dostupný adaptér." + IDS_2065 "Počítač" + IDS_2066 "Obraz" + IDS_2067 "Vstupní zařízení" + IDS_2068 "Zvuk" + IDS_2069 "Síť" + IDS_2070 "COM a LPT porty" + IDS_2071 "Řadiče úložiště" + IDS_2072 "Pevné disky" + IDS_2073 "Disketové a CD-ROM mechaniky" + IDS_2074 "Další vyměnitelná zařízení" + IDS_2075 "Jiné příslušenství" + IDS_2076 "Obrazy povrchu (*.86F)\0*.86F\0" + IDS_2077 "Klikněte pro zabraní myši" + IDS_2078 "Stiskněte F8+F12 pro uvolnění myši" + IDS_2079 "Stiskněte F8+F12 nebo prostřední tlačítko pro uvolnění myši" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Nastala chyba při inicializaci knihovny FluidSynth." + IDS_2081 "Sběrnice" + IDS_2082 "Soubor" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Kontrola BPB" + IDS_2088 "KB" + IDS_2089 "Nastala chyba při inicializaci video rendereru." + IDS_2090 "Výchozí" + IDS_2091 "%i čekací stav(y)" + IDS_2092 "Typ" + IDS_2093 "Nastala chyba při inicializaci knihovny PCap" + IDS_2094 "Nebyla nalezena žádná PCap zařízení" + IDS_2095 "Neplatné PCap zařízení" + IDS_2096 "Standardní 2tlačítkový joystick" + IDS_2097 "Standardní 4tlačítkový joystick" + IDS_2098 "Standardní 6tlačítkový joystick" + IDS_2099 "Standardní 8tlačítkový joystick" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Žadné" + IDS_2104 "Nebylo možné nahrát klávesnicové zkratky." + IDS_2105 "Nebylo možné zaregistrovat raw input." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Disketová mechanika %i (%s): %ls" + IDS_2109 "Všechny obrazy (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Rozšířené sektorové obrazy (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Základní sektorové obrazy (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Obrazy magnetického toku (*.FDI)\0*.FDI\0Obrazy povrchu (*.86F;*.MFM)\0*.86F;*.MFM\0Všechny soubory (*.*)\0*.*\0" + IDS_2110 "Nastala chyba při inicializaci knihovny FreeType" + IDS_2111 "Nastala chyba při inicializaci knihovny SDL, je potřeba SDL2.dll" + IDS_2112 "Opravdu chcete resetovat emulovaný počítač?" + IDS_2113 "Opravdu chcete ukončit 86Box?" + IDS_2114 "Nastala chyba při inicializaci knihovny Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "Obrazy MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0Všechny soubory (*.*)\0*.*\0" + IDS_2117 "Vítejte v programu 86Box!" + IDS_2118 "Vestavěný řadič" + IDS_2119 "Ukončit" + IDS_2120 "Nebyly nalezeny žádné obrazy ROM" + IDS_2121 "Chcete uložit nastavení?" + IDS_2122 "Pokračováním se resetuje emulovaný počítač." + IDS_2123 "Uložit" + IDS_2124 "O programu 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Emulátor starých počítačů\n\nAutoři: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nZveřejněno pod licencí GNU General Public License verze 2 nebo novější. Viz soubor LICENSE pro více informací." + IDS_2127 "OK" + IDS_2128 "Hardware není dostupný" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Ujistěte se, že je nainstalován " LIB_NAME_PCAP " a používáte síťové připojení s ním kompatibilní." + IDS_2130 "Neplatná konfigurace" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " je potřeba pro emulaci ESC/P tiskáren." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " je potřeba pro automatický převod PostScript dokumentů do PDF.\n\nJakékoliv dokumenty vytisknuté přes obecnou PostScriptovou tiskárnu budou uloženy jako PostScript (.ps) soubory." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " je potřeba pro MIDI výstup přes knihovnu FluidSynth." + IDS_2134 "Vstup do režimu celé obrazovky" + IDS_2135 "Nezobrazovat dále tuto zprávu" + IDS_2136 "Neukončovat" + IDS_2137 "Resetovat" + IDS_2138 "Neresetovat" + IDS_2139 "Obraz magnetooptického disku (*.IM?;*.MDI)\0*.IM?;*.MDI\0Všechny soubory (*.*)\0*.*\0" + IDS_2140 "Obraz CD-ROM disku (*.ISO;*.CUE)\0*.ISO;*.CUE\0Všechny soubory (*.*)\0*.*\0" + IDS_2141 "Konfigurace zařízení %hs" + IDS_2142 "Monitor je v režimu spánku" + IDS_2143 "Shadery OpenGL (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" + IDS_2144 "Možnosti OpenGL" + IDS_2145 "Pokoušíte se spustit nepodporovanou konfiguraci" + IDS_2146 "Pro tuto konfiguraci bylo vypnuto filtrování procesorů podle zvoleného počítače.\n\nToto umožňuje zvolit procesor, který by jinak se zvoleným počítačem nebyl kompatibilní. Můžou však nastat potíže s BIOSem nebo jiným softwarem.\n\nPovolení tohoto nastavení není oficiálně podporováno a jakákoliv hlášení o chybách mohou být uzavřeny jako neplatné." + IDS_2147 "Pokračovat" + IDS_2148 "Kazeta: %s" + IDS_2149 "Kazetové nahrávky (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Všechny soubory (*.*)\0*.*\0" + IDS_2150 "Cartridge %i: %ls" + IDS_2151 "Obrazy cartridge (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Všechny soubory (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Obnovit" + IDS_2155 "Pozastavit" + IDS_2156 "Stisknout Ctrl+Alt+Delete" + IDS_2157 "Stisknout Ctrl+Alt+Esc" + IDS_2158 "Resetovat" + IDS_2159 "Vypnout skrze rozhraní ACPI" + IDS_2160 "Nastavení" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Pevný disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "CD-ROM mechaniky pro rozhraní MFM/RLL nebo ESDI nikdy neexistovaly" + IDS_4100 "Vlastní..." + IDS_4101 "Vlastní (velký)..." + IDS_4102 "Přidat nový pevný disk" + IDS_4103 "Přidat existující pevný disk" + IDS_4104 "Obraz disku formátu HDI nemůžou být větší než 4 GB." + IDS_4105 "Obraz disku nemůžou být větší než 127 GB." + IDS_4106 "Obrazy pevného disku (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Všechny soubory (*.*)\0*.*\0" + IDS_4107 "Nebylo možné přečíst soubor" + IDS_4108 "Nebylo možné zapisovat do souboru" + IDS_4109 "Obraz disku ve formátu HDI nebo HDX s velikostí sektoru jinou než 512 bajtů nejsou podporovány." + IDS_4110 "USB zatím není podporováno." + IDS_4111 "Soubor obrazu disku již existuje" + IDS_4112 "Zadejte platný název souboru." + IDS_4113 "Obraz disku byl vytvořen" + IDS_4114 "Ujistěte se, že soubor existuje a lze jej přečíst." + IDS_4115 "Ujistěte se, že se do složky, kde se má soubor uložit, dá zapisovat." + IDS_4116 "Obraz disku je příliš velký" + IDS_4117 "Nezapomeňte nově vytvořený disk rozdělit a naformátovat." + IDS_4118 "Zvolený soubor bude přepsán. Opravdu jej chcete použít?" + IDS_4119 "Nepodporovaný obraz disku" + IDS_4120 "Přepsat" + IDS_4121 "Nepřepisovat" + IDS_4122 "Surový obraz (.img)" + IDS_4123 "HDI obraz (.hdi)" + IDS_4124 "HDX obraz (.hdx)" + IDS_4125 "VHD s pevnou velikostí (.vhd)" + IDS_4126 "VHD s dynamickou velikostí (.vhd)" + IDS_4127 "Rozdílový VHD (.vhd)" + IDS_4128 "Velké bloky (2 MB)" + IDS_4129 "Malé bloky (512 KB)" + IDS_4130 "Soubory VHD (*.VHD)\0*.VHD\0Všechny soubory (*.*)\0*.*\0" + IDS_4131 "Vyberte nadřazený virtuální disk" + IDS_4132 "To může znamenat, že se obsahy nadřazeného disku změnily po vytvoření rozdílového disku.\n\nTato chyba také může nastat, pokud byl obraz disku kopírován nebo přesunut, nebo kvůli chybě v programu, který jej vytvořil.\n\nChcete časová razítka opravit?" + IDS_4133 "Časová razítka nadřazeného a podřazeného disku nesouhlasí" + IDS_4134 "Nebylo možné opravit časové razítko VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Vypnuto" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Vypnuto" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "Dokonalé otáčky za minutu" + IDS_6145 "1% pod dokonalými ot./m" + IDS_6146 "1.5% pod dokonalými ot./m" + IDS_6147 "2% pod dokonalými ot./m" + + IDS_7168 "(Výchozí nastavení systému)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Czech (Czech Republic) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/de-DE.rc b/src/win/languages/de-DE.rc new file mode 100644 index 000000000..d99095d56 --- /dev/null +++ b/src/win/languages/de-DE.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// German (de-DE) resources + +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Aktionen" + BEGIN + MENUITEM "&Tastatur benötigt das Einfangen des Mauszeigers", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Die rechte Strg-Taste ist die Linke Alt-Taste", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard-Reset...", IDM_ACTION_HRESET + MENUITEM "&Strg+Alt+Entf\tStrg+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Strg+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pause", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "Be&enden...", IDM_ACTION_EXIT + END + POPUP "&Ansicht" + BEGIN + MENUITEM "&Statusleiste ausblenden", IDM_VID_HIDE_STATUS_BAR + MENUITEM "&Werkzeugleiste ausblenden", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Größenverstellbares Fenster", IDM_VID_RESIZE + MENUITEM "&Größe && Position merken", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0-Kern)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Fenstergröße einstellen...", IDM_VID_SPECIFY_DIM + MENUITEM "&4:3-Seitenverhältnis erzwingen", IDM_VID_FORCE43 + POPUP "&Fensterskalierungsfaktor" + BEGIN + MENUITEM "&0,5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1,&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Filteringmethode" + BEGIN + MENUITEM "&Nearest", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI-Skalierung", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Vollbild\tStrg+Alt+Bild auf", IDM_VID_FULLSCREEN + POPUP "&Stretching-Modus im Vollbildmodus" + BEGIN + MENUITEM "&Vollbild-Stretching", IDM_VID_FS_FULL + MENUITEM "&4:3-Seitenverhältnis erzwingen", IDM_VID_FS_43 + MENUITEM "&Quadratische Pixel (Seitenverhältnis beibehalten)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Integer-Skalierung", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA-Einstellungen" + BEGIN + MENUITEM "&Invertierte VGA-Anzeige", IDM_VID_INVERT + POPUP "&VGA-Bildschirmtyp" + BEGIN + MENUITEM "&RGB-Farbe", IDM_VID_GRAY_RGB + MENUITEM "&RGB-Graustufen", IDM_VID_GRAY_MONO + MENUITEM "&Bernstein-Monitor", IDM_VID_GRAY_AMBER + MENUITEM "&Grüner Monitor", IDM_VID_GRAY_GREEN + MENUITEM "&Weißer Monitor", IDM_VID_GRAY_WHITE + END + POPUP "Methode zur &Graustufenkonversion" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Durchschnittsmethode", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Overscan für CGA/PCjr/Tandy/E&GA/(S)VGA-Displays", IDM_VID_OVERSCAN + MENUITEM "Kontrast für &monochrome Displays ändern", IDM_VID_CGACON + END + MENUITEM "&Medien", IDM_MEDIA + POPUP "&Werkzeuge" + BEGIN + MENUITEM "&Optionen...", IDM_CONFIG + MENUITEM "&Statusleistenicons aktualisieren", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "S&creenshot aufnehmen\tStrg+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Einstellungen...", IDM_PREFERENCES + MENUITEM "&Discord-Integration aktivieren", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Klangverstärkung...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Tracing starten\tStrg+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Tracing beenden\tStrg+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Hilfe" + BEGIN + MENUITEM "&Dokumentation...", IDM_DOCS + MENUITEM "&Über 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Neues Image...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Bestehendes Image...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Bestehendes Image (&schreibgeschützt)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Aufnehmen", IDM_CASSETTE_RECORD + MENUITEM "&Abspielen", IDM_CASSETTE_PLAY + MENUITEM "&An den Anfang zurückspulen", IDM_CASSETTE_REWIND + MENUITEM "&An das Ende vorspulen", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "A&uswerfen", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Cartridgeimage...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "A&uswerfen", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Neues Image...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Bestehendes Image...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Bestehendes Image (&schreibgeschützt)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&In das 86F-Format e&xportieren...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Auswerfen", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Stummschalten", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "L&eer", IDM_CDROM_EMPTY + MENUITEM "&Voriges Image neu laden", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Neues Image...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Bestehendes Image...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Bestehendes Image (&schreibgeschützt)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "A&uswerfen", IDM_ZIP_EJECT + MENUITEM "&Voriges Image neu laden", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Neues Image...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Bestehendes Image...", IDM_MO_IMAGE_EXISTING + MENUITEM "Bestehendes Image (&schreibgeschützt)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Auswerfen", IDM_MO_EJECT + MENUITEM "&Bestehendes Image erneut laden", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Ziel&framerate" + BEGIN + MENUITEM "&Mit Videoausgabe synchronisieren", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Shader auswählen...", IDM_VID_GL_SHADER + MENUITEM "&Shader entfernen", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Einstellungen" +#define STR_SND_GAIN "Klangverstärkung" +#define STR_NEW_FLOPPY "Neues Image" +#define STR_CONFIG "Optionen" +#define STR_SPECIFY_DIM "Fenstergröße einstellen" + +#define STR_OK "OK" +#define STR_CANCEL "Abbrechen" +#define STR_GLOBAL "Einstellungen als &globalen Standard speichern" +#define STR_DEFAULT "&Standard" +#define STR_LANGUAGE "Sprache:" +#define STR_ICONSET "Icon-Satz:" + +#define STR_GAIN "Verstärkung" + +#define STR_FILE_NAME "Dateiname:" +#define STR_DISK_SIZE "Plattengröße:" +#define STR_RPM_MODE "Drehzahlmodus:" +#define STR_PROGRESS "Fortschritt:" + +#define STR_WIDTH "Breite:" +#define STR_HEIGHT "Höhe:" +#define STR_LOCK_TO_SIZE "Feste Größe" + +#define STR_MACHINE_TYPE "Systemtyp:" +#define STR_MACHINE "System:" +#define STR_CONFIGURE "Einstellen" +#define STR_CPU_TYPE "CPU-Typ:" +#define STR_CPU_SPEED "Takt:" +#define STR_FPU "FPU-Einheit:" +#define STR_WAIT_STATES "Wartezustände:" +#define STR_MB "MB" +#define STR_MEMORY "Hauptspeicher:" +#define STR_TIME_SYNC "Zeitsynchronisierung" +#define STR_DISABLED "Deaktiviert" +#define STR_ENABLED_LOCAL "Aktiviert (Lokale Uhrzeit)" +#define STR_ENABLED_UTC "Aktiviert (UTC)" +#define STR_DYNAREC "Dynamischer Recompiler" + +#define STR_VIDEO "Videokarte:" +#define STR_VOODOO "Voodoo-Grafik" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Maus:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Soundkarte:" +#define STR_MIDI_OUT "MIDI Out-Gerät:" +#define STR_MIDI_IN "MIDI In-Gerät:" +#define STR_MPU401 "Standalone-MPU-401-Gerät" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32-Wiedergabe benutzen" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Netzwerktyp:" +#define STR_PCAP "PCap-Gerät:" +#define STR_NET "Netzwerkadapter:" + +#define STR_COM1 "COM1-Gerät:" +#define STR_COM2 "COM2-Gerät:" +#define STR_COM3 "COM3-Gerät:" +#define STR_COM4 "COM4-Gerät:" +#define STR_LPT1 "LPT1-Gerät:" +#define STR_LPT2 "LPT2-Gerät:" +#define STR_LPT3 "LPT3-Gerät:" +#define STR_LPT4 "LPT4-Gerät:" +#define STR_SERIAL1 "Serielle Schnittstelle 1" +#define STR_SERIAL2 "Serielle Schnittstelle 2" +#define STR_SERIAL3 "Serielle Schnittstelle 3" +#define STR_SERIAL4 "Serielle Schnittstelle 4" +#define STR_PARALLEL1 "Parallelport 1" +#define STR_PARALLEL2 "Parallelport 2" +#define STR_PARALLEL3 "Parallelport 3" +#define STR_PARALLEL4 "Parallelport 4" + +#define STR_HDC "HDD-Controller:" +#define STR_FDC "FD-Controller:" +#define STR_IDE_TER "Tertiärer IDE-Controller" +#define STR_IDE_QUA "Quartärer IDE-Controller" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controller 1:" +#define STR_SCSI_2 "Controller 2:" +#define STR_SCSI_3 "Controller 3:" +#define STR_SCSI_4 "Controller 4:" +#define STR_CASSETTE "Kassette" + +#define STR_HDD "Festplatten:" +#define STR_NEW "&Neu..." +#define STR_EXISTING "&Vorhanden..." +#define STR_REMOVE "&Entfernen" +#define STR_BUS "Bus:" +#define STR_CHANNEL "Kanal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Festlegen..." +#define STR_SECTORS "Sektoren:" +#define STR_HEADS "Köpfe:" +#define STR_CYLS "Zylinder:" +#define STR_SIZE_MB "Größe (MB):" +#define STR_TYPE "Typ:" +#define STR_IMG_FORMAT "Imageformat:" +#define STR_BLOCK_SIZE "Blockgröße:" + +#define STR_FLOPPY_DRIVES "Diskettenlaufwerke:" +#define STR_TURBO "Turbo-Timings" +#define STR_CHECKBPB "BPB überprüfen" +#define STR_CDROM_DRIVES "CD-ROM-Laufwerke:" +#define STR_CD_SPEED "Takt:" + +#define STR_MO_DRIVES "MO-Laufwerke:" +#define STR_ZIP_DRIVES "ZIP-Laufwerke:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA-Echtzeituhr:" +#define STR_ISAMEM "ISA-Speichererweiterung:" +#define STR_ISAMEM_1 "Steckkarte 1:" +#define STR_ISAMEM_2 "Steckkarte 2:" +#define STR_ISAMEM_3 "Steckkarte 3:" +#define STR_ISAMEM_4 "Steckkarte 4:" +#define STR_BUGGER "ISABugger-Gerät" +#define STR_POSTCARD "POST-Code-Karte" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Fehler" + IDS_2050 "Fataler Fehler" + IDS_2051 " - PAUSED" + IDS_2052 "Bitte Strg+Alt+Bild ab zur Rückkehr in den Fenstermodus drücken." + IDS_2053 "Geschwindigkeit" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP-Images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box konnte keine nutzbaren ROM-Dateien finden.\n\nBitte besuchen Sie download, laden ein ROM-Set herunter und extrahieren dies in das ""roms""-Verzeichnis." + IDS_2057 "(leer)" + IDS_2058 "ZIP-Images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Alle Dateien (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "An" + IDS_2061 "Aus" + IDS_2062 "Alle Images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basissektorimages (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Oberflächenimages (*.86F)\0*.86F\0" + IDS_2063 "Das System ""%hs"" ist aufgrund von fehlenden ROMs im Verzeichnis roms/machines nicht verfügbar. Es wird auf ein verfügbares System gewechselt." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Die Videokarte ""%hs"" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." + IDS_2065 "System" + IDS_2066 "Anzeige" + IDS_2067 "Eingabegeräte" + IDS_2068 "Multimedia" + IDS_2069 "Netzwerk" + IDS_2070 "Anschlüsse (COM & LPT)" + IDS_2071 "Speichercontroller" + IDS_2072 "Festplatten" + IDS_2073 "Disketten- & CD-ROM-Laufwerke" + IDS_2074 "Andere Wechsellaufwerke" + IDS_2075 "Andere Peripheriegeräte" + IDS_2076 "Oberflächenimages (*.86F)\0*.86F\0" + IDS_2077 "Zum Einfangen des Mauszeigers bitte klicken" + IDS_2078 "Bitte F8+F12 zur Mausfreigabe drücken" + IDS_2079 "Bitte F8+F12 oder die mittlere Maustaste zur Mausfreigabe drücken" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "FluidSynth konnte nicht initialisiert werden" + IDS_2081 "Bus" + IDS_2082 "Datei" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "BPB prüfen" + IDS_2088 "KB" + IDS_2089 "Der Videorenderer konnte nicht initialisiert werden." + IDS_2090 "Standard" + IDS_2091 "%i Wartezustände" + IDS_2092 "Typ" + IDS_2093 "PCap konnte nicht eingerichtet werden" + IDS_2094 "Keine PCap-Geräte gefunden" + IDS_2095 "Ungültiges PCap-Gerät" + IDS_2096 "Standard 2-Tasten-Joystick(s)" + IDS_2097 "Standard 4-Tasten-Joystick" + IDS_2098 "Standard 6-Tasten-Joystick" + IDS_2099 "Standard 8-Tasten-Joystick" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Ohne" + IDS_2104 "Tastaturbeschleuniger konnten nicht geladen werden." + IDS_2105 "Roheingaben konnten nicht registriert werden." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Diskette %i (%s): %ls" + IDS_2109 "Alle Images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Fortgeschrittene Sektorimages (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basissektorimages (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Fluximages (*.FDI)\0*.FDI\0Oberflächenimages (*.86F;*.MFM)\0*.86F;*.MFM\0Alle Dateien (*.*)\0*.*\0" + IDS_2110 "FreeType konnte nicht initialisiert werden" + IDS_2111 "SDL konnte nicht initialisiert werden, die Datei SDL2.dll wird benötigt" + IDS_2112 "Sind Sie sich sicher, dass Sie einen Hard-Reset für das emulierte System durchführen wollen?" + IDS_2113 "Sind Sie sich sicher, dass Sie 86Box beenden wollen?" + IDS_2114 "Ghostscript konnte nicht initialisiert werden" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO-Images (*.IM?;*.MDI)\0*.IM?;*.MDI\0Alle Dateien (*.*)\0*.*\0" + IDS_2117 "Willkommen bei 86Box!" + IDS_2118 "Interner Controller" + IDS_2119 "Beenden" + IDS_2120 "Keine ROMs gefunden" + IDS_2121 "Möchten Sie die Einstellungen speichern?" + IDS_2122 "Dies wird zu einem Hard-Reset des emulierten Systems führen." + IDS_2123 "Speichern" + IDS_2124 "Über 86Box" + IDS_2125 "86Box Version " EMU_VERSION + + IDS_2126 "Ein Emulator für alte Computer\n\nAutoren: Sarah Walker, Miran Grča, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho sowie andere.\n\nÜbersetzt von: dob205\n\nVeröffentlicht unter der GNU General Public License in der Version 2 oder neuer. Siehe LICENSE für mehr Informationen." + IDS_2127 "OK" + IDS_2128 "Hardware nicht verfügbar" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Bitte stellen Sie sicher, dass " LIB_NAME_PCAP " installiert ist und sie eine " LIB_NAME_PCAP "-kompatible Netzwerkverbindung nutzen." + IDS_2130 "Ungültige Konfiguration" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " wird für die ESC/P-Druckeremulation benötigt." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " wird zur automatischen Konversion von PostScript-Dateien in das PDF-Format benötigt.\n\nSämtliche an den generischen PostScript-Drucker gesendete Dateien werden als PostScript (.ps)-Dateien gesichert." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " wird für die FluidSynth-MIDI-Ausgabe benötigt." + IDS_2134 "Vollbildmodus wird aktiviert" + IDS_2135 "Diese Nachricht nicht mehr anzeigen" + IDS_2136 "Nicht beenden" + IDS_2137 "Zurücksetzen" + IDS_2138 "Nicht zurücksetzen" + IDS_2139 "MO-Images (*.IM?;*.MDI)\0*.IM?;*.MDI\0Alle Dateien (*.*)\0*.*\0" + IDS_2140 "CD-ROM-Images (*.ISO;*.CUE)\0*.ISO;*.CUE\0Alle Dateien (*.*)\0*.*\0" + IDS_2141 "%hs-Gerätekonfiguration" + IDS_2142 "Monitor im Standbymodus" + IDS_2143 "OpenGL-Shader (*.GLSL)\0*.GLSL\0Alle Dateien (*.*)\0*.*\0" + IDS_2144 "OpenGL-Optionen" + IDS_2145 "Sie laden gerade eine nicht unterstützte Konfiguration" + IDS_2146 "Das Filtern der CPU-Typen basierend auf dem ausgewählten System ist für dieses System deaktiviert.\n\nDies ermöglicht es, dass man eine sonst nicht mit dem ausgewählten System inkompatible CPU auswählen kann. Allerdings kann dies zu Inkompatiblilitäten mit dem BIOS des Systems oder anderen Programmen kommen.\n\nDas Aktivieren dieser Einstellung wird nicht unterstützt und sämtliche Bugreports können als ""invalid"" geschlossen werden." + IDS_2147 "Fortfahren" + IDS_2148 "Kassette: %s" + IDS_2149 "Kassettenimages (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Alle Dateien (*.*)\0*.*\0" + IDS_2150 "Cartridge %i: %ls" + IDS_2151 "Cartridgeimages (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Alle Dateien (*.*)\0*.*\0" + IDS_2152 "Fehler bei der Rendererinitialisierung" + IDS_2153 "Der OpenGL (3.0-Kern)-Renderer konnte nicht initialisiert werden. Bitte benutzen Sie einen anderen Renderer." + IDS_2154 "Fortsetzen" + IDS_2155 "Pausieren" + IDS_2156 "Strg+Alt+Entf drücken" + IDS_2157 "Strg+Alt+Esc drücken" + IDS_2158 "Hard-Reset" + IDS_2159 "ACPI-basiertes Herunterfahren" + IDS_2160 "Optionen" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Festplatte (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL- oder ESDI CD-ROM-Laufwerke hat es niemals gegeben" + IDS_4100 "Angepasst..." + IDS_4101 "Angepasst (Groß)..." + IDS_4102 "Neue Festplatte hinzufügen" + IDS_4103 "Bestehende Festplatte hinzufügen" + IDS_4104 "HDI-Diskimages können nicht größer als 4 GB groß sein." + IDS_4105 "Festplattenimages können nicht größer als 127 GB groß sein." + IDS_4106 "Festplattenimages (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Alle Dateien (*.*)\0*.*\0" + IDS_4107 "Die Datei konnte nicht gelesen werden" + IDS_4108 "Die Datei konnte nicht beschrieben werden" + IDS_4109 "HDI- oder HDX-Images mit einer Sektorgröße größer als 512 kB werden nicht unterstützt." + IDS_4110 "USB wird noch nicht unterstützt" + IDS_4111 "Die Festplattenimagedatei existiert bereits" + IDS_4112 "Bitte geben Sie einen gültigen Dateinamen ein." + IDS_4113 "Disk-Image wurde erstellt" + IDS_4114 "Bitte stellen Sie sicher, dass die Datei existiert und lesbar ist." + IDS_4115 "Bitte stellen Sie sicher, dass die Datei in ein Verzeichnis mit Schreibberechtigungen gespeichert wird." + IDS_4116 "Festplattenimage ist zu groß" + IDS_4117 "Bitte denken Sie an das Partitionieren und Formatieren des neu erstellten Laufwerks." + IDS_4118 "Die ausgewählte Datei wird überschrieben. Möchten Sie diese Datei nutzen?" + IDS_4119 "Nicht unterstütztes Festplattenimage" + IDS_4120 "Überschreiben" + IDS_4121 "Nicht überschreiben" + IDS_4122 "Rohdatenimages (.img)" + IDS_4123 "HDI-Images (.hdi)" + IDS_4124 "HDX-Images (.hdx)" + IDS_4125 "VHD mit fester Größe (.vhd)" + IDS_4126 "VHD mit dynamischer Größe (.vhd)" + IDS_4127 "Differenzierende VHD (.vhd)" + IDS_4128 "Große Blöcke (2 MB)" + IDS_4129 "Kleine Blöcke (512 KB)" + IDS_4130 "VHD-Dateien (*.VHD)\0*.VHD\0Alle Dateien (*.*)\0*.*\0" + IDS_4131 "Eltern-VHD-Datei bitte auswählen" + IDS_4132 "Dies bedeutet, dass das Elternimage nach der Erstellung des differenzierenden Images erzeugt wurde.\n\nDies kann auch passieren, falls die Image-Dateien verschoben oder kopiert wurden. Ebenso kann auch dies durch einen Bug im Programm, welches das Image erstellt hat, passieren.\n\nMöchten Sie die Zeitstempel korrigieren?" + IDS_4133 "Die Zeitstempel der Eltern- und der Kindesplatte stimmen nicht überein" + IDS_4134 "Der Zeitstempel der VHD konnte nicht korrigiert werden." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Deaktiviert" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Deaktiviert" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1,2 MB" + IDS_5895 "1,25 MB" + IDS_5896 "1,44 MB" + IDS_5897 "DMF (1024 Cluster)" + IDS_5898 "DMF (2048 Cluster)" + IDS_5899 "2,88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3,5-Zoll 128 MB (ISO 10090)" + IDS_5903 "3,5-Zoll 230 MB (ISO 13963)" + IDS_5904 "3,5-Zoll 540 MB (ISO 15498)" + IDS_5905 "3,5-Zoll 640 MB (ISO 15498)" + IDS_5906 "3,5-Zoll 1,3 GB (GigaMO)" + IDS_5907 "3,5-Zoll 2,3 GB (GigaMO 2)" + IDS_5908 "5,25-Zoll 600 MB" + IDS_5909 "5,25-Zoll 650 MB" + IDS_5910 "5,25-Zoll 1 GB" + IDS_5911 "5,25-Zoll 1,3 GB" + + IDS_6144 "Perfekte Drehzahl" + IDS_6145 "1% unterhalb der perfekten Drehzahl" + IDS_6146 "1,5% unterhalb der perfekten Drehzahl" + IDS_6147 "2% unterhalb der perfekten Drehzahl" + + IDS_7168 "(Systemstandard)" +END +#define IDS_LANG_ENUS IDS_7168 + +// German (de-DE) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/dialogs.rc b/src/win/languages/dialogs.rc new file mode 100644 index 000000000..bd1eb87bd --- /dev/null +++ b/src/win/languages/dialogs.rc @@ -0,0 +1,1029 @@ +#define CFG_CHECKBOX_PRI_WIDTH 94 +#define CFG_CHECKBOX_HEIGHT 10 +#define CFG_BTN_WIDTH 46 +#define CFG_BTN_HEIGHT 14 +#define CFG_PANE_LTEXT_PRI_WIDTH 85 +#define CFG_PANE_LTEXT_HEIGHT 10 +#define CFG_COMBO_BTN_WIDTH 212 +#define CFG_COMBO_NOBTN_WIDTH CFG_COMBO_BTN_WIDTH + CFG_BTN_WIDTH + 8 +#define CFG_COMBO_BOX_LEFT CFG_PANE_LTEXT_PRI_WIDTH + 10 +#define CFG_COMBO_BTN_LEFT CFG_COMBO_BOX_LEFT + CFG_COMBO_BTN_WIDTH + 8 +#define CFG_COMBO_HEIGHT 120 +#define CFG_LIST_WIDTH 123 +#define CFG_LIST_HEIGHT 212 +#define CFG_PANE_TOP 0 +#define CFG_PANE_LEFT CFG_LIST_WIDTH + 8 +#define CFG_PANE_WIDTH CFG_COMBO_BOX_LEFT + CFG_COMBO_NOBTN_WIDTH +#define CFG_PANE_HEIGHT 221 +#define CFG_HMARGIN 7 +#define CFG_VMARGIN 9 +#define CFG_SYSLISTVIEW32_WIDTH CFG_PANE_WIDTH - 7 + +DLG_PREFERENCES DIALOG DISCARDABLE 0, 0, 240, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION STR_PREFERENCES +FONT FONT_SIZE, FONT_NAME +BEGIN + DEFPUSHBUTTON STR_OK, IDOK, + 123, 97, 50, CFG_BTN_HEIGHT + + PUSHBUTTON STR_CANCEL, IDCANCEL, + 179, 97, 50, CFG_BTN_HEIGHT + + LTEXT STR_LANGUAGE, + 2000, 13, 8, 100, 8 + COMBOBOX IDC_COMBO_LANG, + 13, 18, 213, 22, + CBS_DROPDOWNLIST | CBS_HASSTRINGS + PUSHBUTTON STR_DEFAULT, IDC_BUTTON_DEFAULT, + 162, 32, 60, CFG_BTN_HEIGHT + + LTEXT STR_ICONSET, + 2001, 13, 40, 100, 8 + COMBOBOX IDC_COMBO_ICON, + 13, 50, 213, 22, + CBS_DROPDOWNLIST | CBS_HASSTRINGS + PUSHBUTTON STR_DEFAULT, IDC_BUTTON_DEFICON, + 162, 64, 60, CFG_BTN_HEIGHT + + AUTOCHECKBOX STR_GLOBAL, IDC_CHECKBOX_GLOBAL, + 13, 82, 217, 8, + WS_DISABLED +END + +DLG_SND_GAIN DIALOG DISCARDABLE 0, 0, 113, 136 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION STR_SND_GAIN +FONT FONT_SIZE, FONT_NAME +BEGIN + DEFPUSHBUTTON STR_OK, IDOK, + 57, 7, 50, CFG_BTN_HEIGHT + + PUSHBUTTON STR_CANCEL, IDCANCEL, + 57, 24, 50, CFG_BTN_HEIGHT + + CONTROL STR_GAIN, IDC_SLIDER_GAIN, + "msctls_trackbar32", + TBS_VERT | TBS_BOTH | TBS_AUTOTICKS | WS_TABSTOP, + 15, 20, 20, 109 + CTEXT STR_GAIN,IDT_GAIN, + 10, 7, 32, 9, + SS_CENTERIMAGE +END + +DLG_NEW_FLOPPY DIALOG DISCARDABLE 0, 0, 226, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION STR_NEW_FLOPPY +FONT FONT_SIZE, FONT_NAME +BEGIN + DEFPUSHBUTTON STR_OK, IDOK, + 104, 65, 50, CFG_BTN_HEIGHT + + PUSHBUTTON STR_CANCEL, IDCANCEL, + 162, 65, 50, CFG_BTN_HEIGHT + + LTEXT STR_FILE_NAME, IDT_FLP_FILE_NAME, + 7, 6, 44, 12, + SS_CENTERIMAGE + EDITTEXT IDC_EDIT_FILE_NAME, + 53, 5, 150, 14, + ES_AUTOHSCROLL | ES_READONLY + + LTEXT STR_DISK_SIZE, IDT_FLP_DISK_SIZE, + 7, 25, 44, 12, + SS_CENTERIMAGE + COMBOBOX IDC_COMBO_DISK_SIZE, + 53, 25, 166, 14, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "...", IDC_CFILE, + 206, 5, 13, CFG_BTN_HEIGHT + + LTEXT STR_RPM_MODE, IDT_FLP_RPM_MODE, + 7, 45, 44, 12, + SS_CENTERIMAGE + COMBOBOX IDC_COMBO_RPM_MODE, + 53, 45, 166, 14, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_PROGRESS, IDT_FLP_PROGRESS, + 7, 45, 44, 12, + SS_CENTERIMAGE + CONTROL "IMGCreateProgress", IDC_PBAR_IMG_CREATE, + "msctls_progress32", + PBS_SMOOTH | WS_BORDER, + 53, 45, 166, 14 +END + +DLG_SPECIFY_DIM DIALOG DISCARDABLE 0, 0, 175, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION STR_SPECIFY_DIM +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_WIDTH, IDT_WIDTH, + 7, 9, 24, 12 + EDITTEXT IDC_EDIT_WIDTH, + 33, 7, 45, 12, + ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_WIDTHSPIN, + "msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS, + 76, 6, 12, 12 + + LTEXT STR_HEIGHT, IDT_HEIGHT, + 97, 9, 24, 12 + EDITTEXT IDC_EDIT_HEIGHT, + 123, 7, 45, 12, + ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_HEIGHTSPIN, + "msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS, + 166, 6, 12, 12 + + CONTROL STR_LOCK_TO_SIZE,IDC_CHECK_LOCK_SIZE, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 7, 26, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + DEFPUSHBUTTON STR_OK,IDOK, + 30, 45, 50, CFG_BTN_HEIGHT + + PUSHBUTTON STR_CANCEL, IDCANCEL, + 99, 45, 50, CFG_BTN_HEIGHT +END + +DLG_CONFIG DIALOG DISCARDABLE 0, 0, CFG_LIST_WIDTH + CFG_PANE_WIDTH + 18, 256 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION STR_CONFIG +FONT FONT_SIZE, FONT_NAME +BEGIN + DEFPUSHBUTTON STR_OK, IDOK, + CFG_LIST_WIDTH + CFG_PANE_WIDTH - 108, 235, 50, CFG_BTN_HEIGHT + + PUSHBUTTON STR_CANCEL, IDCANCEL, + CFG_LIST_WIDTH + CFG_PANE_WIDTH - 48 , 235, 50, CFG_BTN_HEIGHT + + CONTROL "List2", IDC_SETTINGSCATLIST, + "SysListView32", + LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | + WS_BORDER | WS_TABSTOP, + CFG_HMARGIN, CFG_VMARGIN, CFG_LIST_WIDTH, CFG_LIST_HEIGHT + + CONTROL "",-1, + "Static", SS_BLACKFRAME | SS_SUNKEN, + 1, 226, CFG_LIST_WIDTH + CFG_PANE_WIDTH + 16, 1 +END + +DLG_CFG_MACHINE DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_MACHINE_TYPE,IDT_MACHINE_TYPE, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MACHINE_TYPE, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_MACHINE, IDT_MACHINE, + CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MACHINE, + CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_MACHINE, + CFG_COMBO_BTN_LEFT, 25, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_CPU_TYPE, IDT_CPU_TYPE, + CFG_HMARGIN, 47, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_CPU_TYPE, + CFG_COMBO_BOX_LEFT, 45, 110, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CPU_SPEED, IDT_CPU_SPEED, + 216, 47, 34, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_CPU_SPEED, + 252, 45, 109, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_FPU,IDT_FPU, + CFG_HMARGIN, 66, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_FPU, + CFG_COMBO_BOX_LEFT, 64, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_WAIT_STATES, IDT_WAIT_STATES, + CFG_HMARGIN, 85, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_WS, + CFG_COMBO_BOX_LEFT, 83, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_MEMORY, IDT_MEMORY, + CFG_HMARGIN, 104, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + EDITTEXT IDC_MEMTEXT, + CFG_COMBO_BOX_LEFT, 102, 45, 12, + ES_AUTOHSCROLL | ES_NUMBER + CONTROL "", IDC_MEMSPIN, + "msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS, + 138, 101, 12, 12 + LTEXT STR_MB, IDT_MB, + 148, 104, 12, CFG_PANE_LTEXT_HEIGHT + +#ifdef USE_DYNAREC + CONTROL STR_DYNAREC, IDC_CHECK_DYNAREC, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 120, 120, CFG_CHECKBOX_HEIGHT +#endif + + GROUPBOX STR_TIME_SYNC, IDC_TIME_SYNC, + CFG_HMARGIN, 135, 110, 56 + + CONTROL STR_DISABLED, IDC_RADIO_TS_DISABLED, + "Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, + 14, 147, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_ENABLED_LOCAL, IDC_RADIO_TS_LOCAL, + "Button", BS_AUTORADIOBUTTON | WS_TABSTOP, + 14, 161, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_ENABLED_UTC, IDC_RADIO_TS_UTC, + "Button", BS_AUTORADIOBUTTON | WS_TABSTOP, + 14, 175, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT +END + +DLG_CFG_VIDEO DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_VIDEO, IDT_VIDEO, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_VIDEO, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_VID, + CFG_COMBO_BTN_LEFT, 6, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_VOODOO, IDC_CHECK_VOODOO, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 7, 27, 199, CFG_CHECKBOX_HEIGHT + PUSHBUTTON STR_CONFIGURE, IDC_BUTTON_VOODOO, + CFG_COMBO_BTN_LEFT, 25, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_IBM8514, IDC_CHECK_IBM8514, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 7, 46, 199, CFG_CHECKBOX_HEIGHT + + CONTROL STR_XGA, IDC_CHECK_XGA, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 7, 65, 199, CFG_CHECKBOX_HEIGHT + PUSHBUTTON STR_CONFIGURE, IDC_BUTTON_XGA, + CFG_COMBO_BTN_LEFT, 64, CFG_BTN_WIDTH, CFG_BTN_HEIGHT +END + +DLG_CFG_INPUT DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_MOUSE, IDT_MOUSE, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MOUSE, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_MOUSE, + CFG_COMBO_BTN_LEFT, 6, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_JOYSTICK, IDT_JOYSTICK, + CFG_HMARGIN, 27, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_JOYSTICK, + CFG_COMBO_BOX_LEFT, 25, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON STR_JOY1, IDC_JOY1, + CFG_HMARGIN, 44, 84, CFG_BTN_HEIGHT + + PUSHBUTTON STR_JOY2, IDC_JOY2, + 96, 44, 84, CFG_BTN_HEIGHT + + PUSHBUTTON STR_JOY3, IDC_JOY3, + 187, 44, 84, CFG_BTN_HEIGHT + + PUSHBUTTON STR_JOY4, IDC_JOY4, + 277, 44, 84, CFG_BTN_HEIGHT +END + +DLG_CFG_SOUND DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_SOUND, IDT_SOUND, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_SOUND, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SND, + CFG_COMBO_BTN_LEFT, 6, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_MIDI_OUT, IDT_MIDI_OUT, + CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MIDI_OUT, + CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, + IDC_CONFIGURE_MIDI_OUT, + CFG_COMBO_BTN_LEFT, 25, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_MIDI_IN, IDT_MIDI_IN, + CFG_HMARGIN, 47, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MIDI_IN, + CFG_COMBO_BOX_LEFT, 45, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_MIDI_IN, + CFG_COMBO_BTN_LEFT, 44, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_MPU401,IDC_CHECK_MPU401, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 66, 199, CFG_CHECKBOX_HEIGHT + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_MPU401, + CFG_COMBO_BTN_LEFT, 64, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_SSI,IDC_CHECK_SSI, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 84, 95, CFG_CHECKBOX_HEIGHT + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SSI, + CFG_COMBO_BTN_LEFT, 82, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_CMS,IDC_CHECK_CMS, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 102, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_CMS, + CFG_COMBO_BTN_LEFT, 100, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_GUS,IDC_CHECK_GUS, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 120, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_GUS, + CFG_COMBO_BTN_LEFT, 118, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_FLOAT, IDC_CHECK_FLOAT, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 138, 104, CFG_CHECKBOX_HEIGHT + + GROUPBOX STR_FM_DRIVER, IDC_FM_DRIVER, + CFG_HMARGIN, 154, 110, 42 + + CONTROL STR_FM_DRV_NUKED, IDC_RADIO_FM_DRV_NUKED, + "Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, + 14, 166, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_FM_DRV_YMFM, IDC_RADIO_FM_DRV_YMFM, + "Button", BS_AUTORADIOBUTTON | WS_TABSTOP, + 14, 180, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT +END + +DLG_CFG_NETWORK DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_NET_TYPE, IDT_NET_TYPE, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_NET_TYPE, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_PCAP, IDT_PCAP, + CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_PCAP, + CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_NET, IDT_NET, + CFG_HMARGIN, 47, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_NET, + CFG_COMBO_BOX_LEFT, 45, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_NET, + CFG_COMBO_BTN_LEFT, 44, CFG_BTN_WIDTH, CFG_BTN_HEIGHT +END + +DLG_CFG_PORTS DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN +/* + LTEXT STR_COM1, IDT_COM1, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_COM1, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_COM2, IDT_COM2, + CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_COM2, + CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_COM3, IDT_COM3, + CFG_HMARGIN, 47, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_COM3, + CFG_COMBO_BOX_LEFT, 45, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_COM4, IDT_COM4, + CFG_HMARGIN, 66, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_COM4, + CFG_COMBO_BOX_LEFT, 45, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +*/ + + LTEXT STR_LPT1, IDT_LPT1, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_LPT1, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_LPT2, IDT_LPT2, + CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_LPT2, + CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_LPT3, IDT_LPT3, + CFG_HMARGIN, 47, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_LPT3, + CFG_COMBO_BOX_LEFT, 45, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_LPT4, IDT_LPT4, + CFG_HMARGIN, 66, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_LPT4, + CFG_COMBO_BOX_LEFT, 64, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + CONTROL STR_SERIAL1, IDC_CHECK_SERIAL1, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 83, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_SERIAL2, IDC_CHECK_SERIAL2, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 102, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_SERIAL3, IDC_CHECK_SERIAL3, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 121, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_SERIAL4, IDC_CHECK_SERIAL4, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 140, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_PARALLEL1, IDC_CHECK_PARALLEL1, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 167, 83, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_PARALLEL2, IDC_CHECK_PARALLEL2, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 167, 102, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_PARALLEL3, IDC_CHECK_PARALLEL3, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 167, 121, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_PARALLEL4, IDC_CHECK_PARALLEL4, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 167, 140, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT +END + +DLG_CFG_STORAGE DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_HDC, IDT_HDC, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_HDC, + CFG_COMBO_BOX_LEFT, 7, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_HDC, + CFG_COMBO_BTN_LEFT, 6, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_FDC, IDT_FDC, + CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_FDC, + CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_FDC, + CFG_COMBO_BTN_LEFT, 25, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_IDE_TER,IDC_CHECK_IDE_TER, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 47, 239, 10 + PUSHBUTTON STR_CONFIGURE, IDC_BUTTON_IDE_TER, + CFG_COMBO_BTN_LEFT, 45, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_IDE_QUA, IDC_CHECK_IDE_QUA, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 66, 239, 10 + PUSHBUTTON STR_CONFIGURE, IDC_BUTTON_IDE_QUA, + CFG_COMBO_BTN_LEFT, 64, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + GROUPBOX STR_SCSI, IDC_GROUP_SCSI, + CFG_HMARGIN, 85, CFG_SYSLISTVIEW32_WIDTH, 93 + + LTEXT STR_SCSI_1, IDT_SCSI_1, + 16, 102, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_SCSI_1, + CFG_COMBO_BOX_LEFT, 100, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SCSI_1, + CFG_COMBO_BTN_LEFT - 10, 99, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_SCSI_2, IDT_SCSI_2, + 16, 121, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_SCSI_2, + CFG_COMBO_BOX_LEFT, 119, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SCSI_2, + CFG_COMBO_BTN_LEFT - 10, 118, CFG_BTN_WIDTH,CFG_BTN_HEIGHT + + LTEXT STR_SCSI_3,IDT_SCSI_3, + 16, 140, 64, 10 + COMBOBOX IDC_COMBO_SCSI_3, + CFG_COMBO_BOX_LEFT, 138, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SCSI_3, + CFG_COMBO_BTN_LEFT - 10, 137, CFG_BTN_WIDTH,CFG_BTN_HEIGHT + + LTEXT STR_SCSI_4, IDT_SCSI_4, + 16, 159, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_SCSI_4, + CFG_COMBO_BOX_LEFT, 157, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SCSI_4, + CFG_COMBO_BTN_LEFT - 10, 156, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_CASSETTE,IDC_CHECK_CASSETTE, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 185, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT +END + +DLG_CFG_HARD_DISKS DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_HDD, IDT_HDD, + CFG_HMARGIN, CFG_VMARGIN, 258, CFG_PANE_LTEXT_HEIGHT + CONTROL "List1", IDC_LIST_HARD_DISKS, + "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | + WS_BORDER | WS_TABSTOP, + CFG_HMARGIN, 18, CFG_SYSLISTVIEW32_WIDTH, 162 + + LTEXT STR_BUS,IDT_BUS, + CFG_HMARGIN, 188, 24, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_HD_BUS, + 33, 186, 130, 12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CHANNEL, IDT_CHANNEL, + 181, 188, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_HD_CHANNEL, + 221, 186, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE, + 221, 186, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_ID, IDT_ID, + 181, 188, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_HD_ID, + 221, 186, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON STR_NEW, IDC_BUTTON_HDD_ADD_NEW, + CFG_HMARGIN, 207, 112, CFG_BTN_HEIGHT + + PUSHBUTTON STR_EXISTING, IDC_BUTTON_HDD_ADD, + 128, 207, 112, CFG_BTN_HEIGHT + + PUSHBUTTON STR_REMOVE, IDC_BUTTON_HDD_REMOVE, + 249, 207, 112, CFG_BTN_HEIGHT + +END + +DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 239, 151 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add Hard Disk" +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_FILE_NAME, IDT_FILE_NAME, + 7, 7, 204, 12 + EDITTEXT IDC_EDIT_HD_FILE_NAME, + 7, 18, 173, 12 + PUSHBUTTON STR_SPECIFY, IDC_CFILE, + 187, 18, 44, CFG_BTN_HEIGHT + + LTEXT STR_CYLS, IDT_CYLS, + 7, 37, 42, 12 + EDITTEXT IDC_EDIT_HD_CYL, + 50, 36, 28, 12 + + LTEXT STR_HEADS, IDT_HEADS, + 86, 37, 29, 12 + EDITTEXT IDC_EDIT_HD_HPC, + 122, 36, 28, 12 + + LTEXT STR_SECTORS, IDT_SECTORS, + 164, 37, 33, 12 + EDITTEXT IDC_EDIT_HD_SPT, + 197, 36, 28, 12 + + LTEXT STR_SIZE_MB, IDT_SIZE_MB, + 7, 56, 48, 12 + EDITTEXT IDC_EDIT_HD_SIZE, + 50, 54, 28, 12 + + LTEXT STR_TYPE, IDT_TYPE, + 86, 56, 24, 12 + COMBOBOX IDC_COMBO_HD_TYPE, + 133, 54, 98, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_BUS,IDT_BUS, + 7, 75, 24, 12 + COMBOBOX IDC_COMBO_HD_BUS, + 43, 73, 58, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CHANNEL, IDT_CHANNEL, + 109, 75, 34, 12 + COMBOBOX IDC_COMBO_HD_CHANNEL, + 144, 73, 87, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE, + 144, 73, 87, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_ID, IDT_ID, + 109, 75, 34, 12 + COMBOBOX IDC_COMBO_HD_ID, + 144, 73, 87, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_IMG_FORMAT, IDT_IMG_FORMAT, + 7, 94, 70, 12 + COMBOBOX IDC_COMBO_HD_IMG_FORMAT, + 78, 92, 153, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_BLOCK_SIZE, IDT_BLOCK_SIZE, + 7, 113, 50, 12 + COMBOBOX IDC_COMBO_HD_BLOCK_SIZE, + 58, 111, 153, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_PROGRESS, IDT_PROGRESS, + 7, 7, 204, 12 + CONTROL "IMGCreateProgress", IDC_PBAR_IMG_CREATE, + "msctls_progress32", + PBS_SMOOTH | WS_BORDER, + 7, 16, 204, 12 + + DEFPUSHBUTTON STR_OK, IDOK, + 75, 129, 50, CFG_BTN_HEIGHT + PUSHBUTTON STR_CANCEL, IDCANCEL, + 132, 129, 50, CFG_BTN_HEIGHT +END + +DLG_CFG_FLOPPY_AND_CDROM_DRIVES DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_FLOPPY_DRIVES, IDT_FLOPPY_DRIVES, + CFG_HMARGIN, CFG_VMARGIN, 258, CFG_PANE_LTEXT_HEIGHT + CONTROL "List1", IDC_LIST_FLOPPY_DRIVES, + "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | + WS_BORDER | WS_TABSTOP, + CFG_HMARGIN, 18, CFG_SYSLISTVIEW32_WIDTH, 60 + + LTEXT STR_TYPE, IDT_FDD_TYPE, + CFG_HMARGIN, 87, 24, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_FD_TYPE, + 33, 85, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + CONTROL STR_TURBO, IDC_CHECKTURBO, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 186, 86, 84, CFG_CHECKBOX_HEIGHT + + CONTROL STR_CHECKBPB, IDC_CHECKBPB, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 272, 86, 84, CFG_CHECKBOX_HEIGHT + + LTEXT STR_CDROM_DRIVES, IDT_CD_DRIVES, + CFG_HMARGIN, 107, 258, CFG_PANE_LTEXT_HEIGHT + CONTROL "List1", IDC_LIST_CDROM_DRIVES, + "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | + WS_BORDER | WS_TABSTOP, + CFG_HMARGIN, 117, CFG_SYSLISTVIEW32_WIDTH, 60 + + LTEXT STR_BUS, IDT_CD_BUS, + CFG_HMARGIN, 187, 24, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_CD_BUS, + 33, 185, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CHANNEL, IDT_CD_CHANNEL, + 181, 187, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_CD_CHANNEL_IDE, + 221, 185, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_ID, IDT_CD_ID, + 181, 187, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_CD_ID, + 221, 185, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CD_SPEED, IDT_CD_SPEED, + CFG_HMARGIN, 207, 34, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_CD_SPEED, + 33, 205, 328, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + + LTEXT STR_MO_DRIVES, IDT_MO_DRIVES, + CFG_HMARGIN, CFG_VMARGIN, 258, CFG_PANE_LTEXT_HEIGHT + CONTROL "List1", IDC_LIST_MO_DRIVES, + "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | + WS_BORDER | WS_TABSTOP, + CFG_HMARGIN, 17, CFG_SYSLISTVIEW32_WIDTH, 60 + + LTEXT STR_BUS, IDT_MO_BUS, + CFG_HMARGIN, 87, 24, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MO_BUS, + 33, 85, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_ID, IDT_MO_ID, + 181, 87, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MO_ID, + 221, 85, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CHANNEL, IDT_MO_CHANNEL, + 181, 87, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MO_CHANNEL_IDE, + 221, 85, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_TYPE, IDT_MO_TYPE, + CFG_HMARGIN, 107, 24, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_MO_TYPE, + 33, 105, 328, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_ZIP_DRIVES, IDT_ZIP_DRIVES, + CFG_HMARGIN, 127, 258, CFG_PANE_LTEXT_HEIGHT + CONTROL "List1", IDC_LIST_ZIP_DRIVES, + "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | + WS_BORDER | WS_TABSTOP, + CFG_HMARGIN, 137, CFG_SYSLISTVIEW32_WIDTH, 60 + + LTEXT STR_BUS, IDT_ZIP_BUS, + CFG_HMARGIN, 207, 24, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ZIP_BUS, + 33, 205, 140, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_CHANNEL, IDT_ZIP_CHANNEL, + 181, 207, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE, + 221, 205, 105, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + LTEXT STR_ID, IDT_ZIP_ID, + 181, 207, 38, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ZIP_ID, + 221, 205, 105, 12, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + + CONTROL STR_250, IDC_CHECK250, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + 329, 206, 44, CFG_CHECKBOX_HEIGHT +END + +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT +STYLE DS_CONTROL | WS_CHILD +FONT FONT_SIZE, FONT_NAME +BEGIN + LTEXT STR_ISARTC, IDT_ISARTC, + CFG_HMARGIN, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ISARTC, + CFG_COMBO_BOX_LEFT, 7,CFG_COMBO_BTN_WIDTH, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_ISARTC, + CFG_COMBO_BTN_LEFT, 6, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + GROUPBOX STR_ISAMEM, IDC_GROUP_ISAMEM, + CFG_HMARGIN, 28, CFG_SYSLISTVIEW32_WIDTH, 93 + + LTEXT STR_ISAMEM_1, IDT_ISAMEM_1, + 16, 45, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ISAMEM_1, + CFG_COMBO_BOX_LEFT, 43, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_ISAMEM_1, + CFG_COMBO_BTN_LEFT - 10, 42, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_ISAMEM_2,IDT_ISAMEM_2, + 16, 64, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ISAMEM_2, + CFG_COMBO_BOX_LEFT, 62, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_ISAMEM_2, + CFG_COMBO_BTN_LEFT - 10, 61, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_ISAMEM_3, IDT_ISAMEM_3, + 16, 83, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ISAMEM_3, + CFG_COMBO_BOX_LEFT, 81, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_ISAMEM_3, + CFG_COMBO_BTN_LEFT - 10, 80, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + LTEXT STR_ISAMEM_4, IDT_ISAMEM_4, + 16, 102, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + COMBOBOX IDC_COMBO_ISAMEM_4, + CFG_COMBO_BOX_LEFT, 100, CFG_COMBO_BTN_WIDTH - 10, CFG_COMBO_HEIGHT, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_ISAMEM_4, + CFG_COMBO_BTN_LEFT - 10, 99, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + + CONTROL STR_BUGGER, IDC_CHECK_BUGGER, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 128, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT + + CONTROL STR_POSTCARD,IDC_CHECK_POSTCARD, + "Button", BS_AUTOCHECKBOX | WS_TABSTOP, + CFG_HMARGIN, 146, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT +END + +#undef CFG_CHECKBOX_PRI_WIDTH +#undef CFG_CHECKBOX_HEIGHT +#undef CFG_BTN_WIDTH +#undef CFG_BTN_HEIGHT +#undef CFG_PANE_LTEXT_PRI_WIDTH +#undef CFG_PANE_LTEXT_HEIGHT +#undef CFG_COMBO_BTN_WIDTH +#undef CFG_COMBO_NOBTN_WIDTH +#undef CFG_COMBO_BOX_LEFT +#undef CFG_COMBO_BTN_LEFT +#undef CFG_COMBO_HEIGHT +#undef CFG_LIST_WIDTH +#undef CFG_LIST_HEIGHT +#undef CFG_PANE_TOP +#undef CFG_PANE_LEFT +#undef CFG_PANE_WIDTH +#undef CFG_PANE_HEIGHT +#undef CFG_HMARGIN +#undef CFG_VMARGIN +#undef CFG_SYSLISTVIEW32_WIDTH + + +#undef STR_PREFERENCES +#undef STR_SND_GAIN +#undef STR_NEW_FLOPPY +#undef STR_CONFIG +#undef STR_SPECIFY_DIM + +#undef STR_OK +#undef STR_CANCEL +#undef STR_GLOBAL +#undef STR_DEFAULT +#undef STR_LANGUAGE +#undef STR_ICONSET + +#undef STR_GAIN + +#undef STR_FILE_NAME +#undef STR_DISK_SIZE +#undef STR_RPM_MODE +#undef STR_PROGRESS + +#undef STR_WIDTH +#undef STR_HEIGHT +#undef STR_LOCK_TO_SIZE + +#undef STR_MACHINE_TYPE +#undef STR_MACHINE +#undef STR_CONFIGURE +#undef STR_CPU_TYPE +#undef STR_CPU_SPEED +#undef STR_FPU +#undef STR_WAIT_STATES +#undef STR_MB +#undef STR_MEMORY +#undef STR_TIME_SYNC +#undef STR_DISABLED +#undef STR_ENABLED_LOCAL +#undef STR_ENABLED_UTC +#undef STR_DYNAREC + +#undef STR_VIDEO +#undef STR_VOODOO +#undef STR_IBM8514 +#undef STR_XGA + +#undef STR_MOUSE +#undef STR_JOYSTICK +#undef STR_JOY1 +#undef STR_JOY2 +#undef STR_JOY3 +#undef STR_JOY4 + +#undef STR_SOUND +#undef STR_MIDI_OUT +#undef STR_MIDI_IN +#undef STR_MPU401 +#undef STR_SSI +#undef STR_CMS +#undef STR_GUS +#undef STR_FLOAT +#undef STR_FM_DRIVER +#undef STR_FM_DRV_NUKED +#undef STR_FM_DRV_YMFM + +#undef STR_NET_TYPE +#undef STR_PCAP +#undef STR_NET + +#undef STR_COM1 +#undef STR_COM2 +#undef STR_COM3 +#undef STR_COM4 +#undef STR_LPT1 +#undef STR_LPT2 +#undef STR_LPT3 +#undef STR_LPT4 +#undef STR_SERIAL1 +#undef STR_SERIAL2 +#undef STR_SERIAL3 +#undef STR_SERIAL4 +#undef STR_PARALLEL1 +#undef STR_PARALLEL2 +#undef STR_PARALLEL3 +#undef STR_PARALLEL4 + +#undef STR_HDC +#undef STR_FDC +#undef STR_IDE_TER +#undef STR_IDE_QUA +#undef STR_SCSI +#undef STR_SCSI_1 +#undef STR_SCSI_2 +#undef STR_SCSI_3 +#undef STR_SCSI_4 +#undef STR_CASSETTE + +#undef STR_HDD +#undef STR_NEW +#undef STR_EXISTING +#undef STR_REMOVE +#undef STR_BUS +#undef STR_CHANNEL +#undef STR_ID + +#undef STR_SPECIFY +#undef STR_SECTORS +#undef STR_HEADS +#undef STR_CYLS +#undef STR_SIZE_MB +#undef STR_TYPE +#undef STR_IMG_FORMAT +#undef STR_BLOCK_SIZE + +#undef STR_FLOPPY_DRIVES +#undef STR_TURBO +#undef STR_CHECKBPB +#undef STR_CDROM_DRIVES +#undef STR_CD_SPEED + +#undef STR_MO_DRIVES +#undef STR_ZIP_DRIVES +#undef STR_250 + +#undef STR_ISARTC +#undef STR_ISAMEM +#undef STR_ISAMEM_1 +#undef STR_ISAMEM_2 +#undef STR_ISAMEM_3 +#undef STR_ISAMEM_4 +#undef STR_BUGGER +#undef STR_POSTCARD + +#undef FONT_SIZE +#undef FONT_NAME diff --git a/src/win/languages/en-GB.rc b/src/win/languages/en-GB.rc new file mode 100644 index 000000000..9c1e8acd7 --- /dev/null +++ b/src/win/languages/en-GB.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Keyboard requires capture", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard Reset...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pause", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "E&xit...", IDM_ACTION_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Hide status bar", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Resizeable window", IDM_VID_RESIZE + MENUITEM "R&emember size && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Specify dimensions...", IDM_VID_SPECIFY_DIM + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + POPUP "&Window scale factor" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Filter method" + BEGIN + MENUITEM "&Nearest", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Fullscreen\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA settings" + BEGIN + MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT + POPUP "VGA screen &type" + BEGIN + MENUITEM "RGB &Colour", IDM_VID_GRAY_RGB + MENUITEM "&RGB Greyscale", IDM_VID_GRAY_MONO + MENUITEM "&Amber monitor", IDM_VID_GRAY_AMBER + MENUITEM "&Green monitor", IDM_VID_GRAY_GREEN + MENUITEM "&White monitor", IDM_VID_GRAY_WHITE + END + POPUP "Grayscale &conversion type" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Average", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON + END + MENUITEM "&Media", IDM_MEDIA + POPUP "&Tools" + BEGIN + MENUITEM "&Settings...", IDM_CONFIG + MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferences...", IDM_PREFERENCES + MENUITEM "Enable &Discord integration", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "Sound &gain...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Begin trace\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "End trace\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Help" + BEGIN + MENUITEM "&Documentation...", IDM_DOCS + MENUITEM "&About 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Record", IDM_CASSETTE_RECORD + MENUITEM "&Play", IDM_CASSETTE_PLAY + MENUITEM "&Rewind to the beginning", IDM_CASSETTE_REWIND + MENUITEM "&Fast forward to the end", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Image...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xport to 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Mute", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_EMPTY + MENUITEM "&Reload previous image", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_ZIP_EJECT + MENUITEM "&Reload previous image", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_MO_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_MO_EJECT + MENUITEM "&Reload previous image", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Target &framerate" + BEGIN + MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Select shader...", IDM_VID_GL_SHADER + MENUITEM "&Remove shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferences" +#define STR_SND_GAIN "Sound Gain" +#define STR_NEW_FLOPPY "New Image" +#define STR_CONFIG "Settings" +#define STR_SPECIFY_DIM "Specify Main Window Dimensions" + +#define STR_OK "OK" +#define STR_CANCEL "Cancel" +#define STR_GLOBAL "Save these settings as &global defaults" +#define STR_DEFAULT "&Default" +#define STR_LANGUAGE "Language:" +#define STR_ICONSET "Icon set:" + +#define STR_GAIN "Gain" + +#define STR_FILE_NAME "File name:" +#define STR_DISK_SIZE "Disk size:" +#define STR_RPM_MODE "RPM mode:" +#define STR_PROGRESS "Progress:" + +#define STR_WIDTH "Width:" +#define STR_HEIGHT "Height:" +#define STR_LOCK_TO_SIZE "Lock to this size" + +#define STR_MACHINE_TYPE "Machine type:" +#define STR_MACHINE "Machine:" +#define STR_CONFIGURE "Configure" +#define STR_CPU_TYPE "CPU type:" +#define STR_CPU_SPEED "Speed:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Wait states:" +#define STR_MB "MB" +#define STR_MEMORY "Memory:" +#define STR_TIME_SYNC "Time synchronization" +#define STR_DISABLED "Disabled" +#define STR_ENABLED_LOCAL "Enabled (local time)" +#define STR_ENABLED_UTC "Enabled (UTC)" +#define STR_DYNAREC "Dynamic Recompiler" + +#define STR_VIDEO "Video:" +#define STR_VOODOO "Voodoo Graphics" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Mouse:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Sound card:" +#define STR_MIDI_OUT "MIDI Out Device:" +#define STR_MIDI_IN "MIDI In Device:" +#define STR_MPU401 "Standalone MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Use FLOAT32 sound" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Network type:" +#define STR_PCAP "PCap device:" +#define STR_NET "Network adapter:" + +#define STR_COM1 "COM1 Device:" +#define STR_COM2 "COM2 Device:" +#define STR_COM3 "COM3 Device:" +#define STR_COM4 "COM4 Device:" +#define STR_LPT1 "LPT1 Device:" +#define STR_LPT2 "LPT2 Device:" +#define STR_LPT3 "LPT3 Device:" +#define STR_LPT4 "LPT4 Device:" +#define STR_SERIAL1 "Serial port 1" +#define STR_SERIAL2 "Serial port 2" +#define STR_SERIAL3 "Serial port 3" +#define STR_SERIAL4 "Serial port 4" +#define STR_PARALLEL1 "Parallel port 1" +#define STR_PARALLEL2 "Parallel port 2" +#define STR_PARALLEL3 "Parallel port 3" +#define STR_PARALLEL4 "Parallel port 4" + +#define STR_HDC "HD Controller:" +#define STR_FDC "FD Controller:" +#define STR_IDE_TER "Tertiary IDE Controller" +#define STR_IDE_QUA "Quaternary IDE Controller" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controller 1:" +#define STR_SCSI_2 "Controller 2:" +#define STR_SCSI_3 "Controller 3:" +#define STR_SCSI_4 "Controller 4:" +#define STR_CASSETTE "Cassette" + +#define STR_HDD "Hard disks:" +#define STR_NEW "&New..." +#define STR_EXISTING "&Existing..." +#define STR_REMOVE "&Remove" +#define STR_BUS "Bus:" +#define STR_CHANNEL "Channel:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Specify..." +#define STR_SECTORS "Sectors:" +#define STR_HEADS "Heads:" +#define STR_CYLS "Cylinders:" +#define STR_SIZE_MB "Size (MB):" +#define STR_TYPE "Type:" +#define STR_IMG_FORMAT "Image Format:" +#define STR_BLOCK_SIZE "Block Size:" + +#define STR_FLOPPY_DRIVES "Floppy drives:" +#define STR_TURBO "Turbo timings" +#define STR_CHECKBPB "Check BPB" +#define STR_CDROM_DRIVES "CD-ROM drives:" +#define STR_CD_SPEED "Speed:" + +#define STR_MO_DRIVES "MO drives:" +#define STR_ZIP_DRIVES "ZIP drives:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "ISA Memory Expansion" +#define STR_ISAMEM_1 "Card 1:" +#define STR_ISAMEM_2 "Card 2:" +#define STR_ISAMEM_3 "Card 3:" +#define STR_ISAMEM_4 "Card 4:" +#define STR_BUGGER "ISABugger device" +#define STR_POSTCARD "POST card" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Error" + IDS_2050 "Fatal error" + IDS_2051 " - PAUSED" + IDS_2052 "Press Ctrl+Alt+PgDn to return to windowed mode." + IDS_2053 "Speed" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the ""roms"" directory." + IDS_2057 "(empty)" + IDS_2058 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "On" + IDS_2061 "Off" + IDS_2062 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" + IDS_2063 "Machine ""%hs"" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Video card ""%hs"" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." + IDS_2065 "Machine" + IDS_2066 "Display" + IDS_2067 "Input devices" + IDS_2068 "Sound" + IDS_2069 "Network" + IDS_2070 "Ports (COM & LPT)" + IDS_2071 "Storage controllers" + IDS_2072 "Hard disks" + IDS_2073 "Floppy & CD-ROM drives" + IDS_2074 "Other removable devices" + IDS_2075 "Other peripherals" + IDS_2076 "Surface images (*.86F)\0*.86F\0" + IDS_2077 "Click to capture mouse" + IDS_2078 "Press F8+F12 to release mouse" + IDS_2079 "Press F8+F12 or middle button to release mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Unable to initialize FluidSynth" + IDS_2081 "Bus" + IDS_2082 "File" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Check BPB" + IDS_2088 "KB" + IDS_2089 "Could not initialize the video renderer." + IDS_2090 "Default" + IDS_2091 "%i Wait state(s)" + IDS_2092 "Type" + IDS_2093 "Failed to set up PCap" + IDS_2094 "No PCap devices found" + IDS_2095 "Invalid PCap device" + IDS_2096 "Standard 2-button joystick(s)" + IDS_2097 "Standard 4-button joystick" + IDS_2098 "Standard 6-button joystick" + IDS_2099 "Standard 8-button joystick" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "None" + IDS_2104 "Unable to load keyboard accelerators." + IDS_2105 "Unable to register raw input." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Floppy %i (%s): %ls" + IDS_2109 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2110 "Unable to initialize FreeType" + IDS_2111 "Unable to initialize SDL, SDL2.dll is required" + IDS_2112 "Are you sure you want to hard reset the emulated machine?" + IDS_2113 "Are you sure you want to exit 86Box?" + IDS_2114 "Unable to initialize Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2117 "Welcome to 86Box!" + IDS_2118 "Internal controller" + IDS_2119 "Exit" + IDS_2120 "No ROMs found" + IDS_2121 "Do you want to save the settings?" + IDS_2122 "This will hard reset the emulated machine." + IDS_2123 "Save" + IDS_2124 "About 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." + IDS_2127 "OK" + IDS_2128 "Hardware not available" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Make sure " LIB_NAME_PCAP " is installed and that you are on a " LIB_NAME_PCAP "-compatible network connection." + IDS_2130 "Invalid configuration" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " is required for ESC/P printer emulation." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " is required for FluidSynth MIDI output." + IDS_2134 "Entering fullscreen mode" + IDS_2135 "Don't show this message again" + IDS_2136 "Don't exit" + IDS_2137 "Reset" + IDS_2138 "Don't reset" + IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2141 "%hs Device Configuration" + IDS_2142 "Monitor in sleep mode" + IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" + IDS_2144 "OpenGL options" + IDS_2145 "You are loading an unsupported configuration" + IDS_2146 "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." + IDS_2147 "Continue" + IDS_2148 "Cassette: %s" + IDS_2149 "Cassette images (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0All files (*.*)\0*.*\0" + IDS_2150 "Cartridge %i: %ls" + IDS_2151 "Cartridge images (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0All files (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Hard disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" + IDS_4100 "Custom..." + IDS_4101 "Custom (large)..." + IDS_4102 "Add New Hard Disk" + IDS_4103 "Add Existing Hard Disk" + IDS_4104 "HDI disk images cannot be larger than 4 GB." + IDS_4105 "Disk images cannot be larger than 127 GB." + IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" + IDS_4107 "Unable to read file" + IDS_4108 "Unable to write file" + IDS_4109 "HDI or HDX images with a sector size other than 512 are not supported." + IDS_4110 "USB is not yet supported" + IDS_4111 "Disk image file already exists" + IDS_4112 "Please specify a valid file name." + IDS_4113 "Disk image created" + IDS_4114 "Make sure the file exists and is readable." + IDS_4115 "Make sure the file is being saved to a writable directory." + IDS_4116 "Disk image too large" + IDS_4117 "Remember to partition and format the newly-created drive." + IDS_4118 "The selected file will be overwritten. Are you sure you want to use it?" + IDS_4119 "Unsupported disk image" + IDS_4120 "Overwrite" + IDS_4121 "Don't overwrite" + IDS_4122 "Raw image (.img)" + IDS_4123 "HDI image (.hdi)" + IDS_4124 "HDX image (.hdx)" + IDS_4125 "Fixed-size VHD (.vhd)" + IDS_4126 "Dynamic-size VHD (.vhd)" + IDS_4127 "Differencing VHD (.vhd)" + IDS_4128 "Large blocks (2 MB)" + IDS_4129 "Small blocks (512 KB)" + IDS_4130 "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" + IDS_4131 "Select the parent VHD" + IDS_4132 "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" + IDS_4133 "Parent and child disk timestamps do not match" + IDS_4134 "Could not fix VHD timestamp." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Disabled" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Disabled" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "Perfect RPM" + IDS_6145 "1% below perfect RPM" + IDS_6146 "1.5% below perfect RPM" + IDS_6147 "2% below perfect RPM" + + IDS_7168 "(System Default)" +END +#define IDS_LANG_ENUS IDS_7168 + +// English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/en-US.rc b/src/win/languages/en-US.rc new file mode 100644 index 000000000..5a5fa4fd2 --- /dev/null +++ b/src/win/languages/en-US.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Keyboard requires capture", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard Reset...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pause", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "E&xit...", IDM_ACTION_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Hide status bar", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Resizeable window", IDM_VID_RESIZE + MENUITEM "R&emember size && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Specify dimensions...", IDM_VID_SPECIFY_DIM + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + POPUP "&Window scale factor" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Filter method" + BEGIN + MENUITEM "&Nearest", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Fullscreen\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA settings" + BEGIN + MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT + POPUP "VGA screen &type" + BEGIN + MENUITEM "RGB &Color", IDM_VID_GRAY_RGB + MENUITEM "&RGB Grayscale", IDM_VID_GRAY_MONO + MENUITEM "&Amber monitor", IDM_VID_GRAY_AMBER + MENUITEM "&Green monitor", IDM_VID_GRAY_GREEN + MENUITEM "&White monitor", IDM_VID_GRAY_WHITE + END + POPUP "Grayscale &conversion type" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Average", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON + END + MENUITEM "&Media", IDM_MEDIA + POPUP "&Tools" + BEGIN + MENUITEM "&Settings...", IDM_CONFIG + MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferences...", IDM_PREFERENCES + MENUITEM "Enable &Discord integration", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "Sound &gain...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Begin trace\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "End trace\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Help" + BEGIN + MENUITEM "&Documentation...", IDM_DOCS + MENUITEM "&About 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Record", IDM_CASSETTE_RECORD + MENUITEM "&Play", IDM_CASSETTE_PLAY + MENUITEM "&Rewind to the beginning", IDM_CASSETTE_REWIND + MENUITEM "&Fast forward to the end", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Image...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xport to 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Mute", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_EMPTY + MENUITEM "&Reload previous image", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_ZIP_EJECT + MENUITEM "&Reload previous image", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&New image...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Existing image...", IDM_MO_IMAGE_EXISTING + MENUITEM "Existing image (&Write-protected)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ject", IDM_MO_EJECT + MENUITEM "&Reload previous image", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Target &framerate" + BEGIN + MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Select shader...", IDM_VID_GL_SHADER + MENUITEM "&Remove shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferences" +#define STR_SND_GAIN "Sound Gain" +#define STR_NEW_FLOPPY "New Image" +#define STR_CONFIG "Settings" +#define STR_SPECIFY_DIM "Specify Main Window Dimensions" + +#define STR_OK "OK" +#define STR_CANCEL "Cancel" +#define STR_GLOBAL "Save these settings as &global defaults" +#define STR_DEFAULT "&Default" +#define STR_LANGUAGE "Language:" +#define STR_ICONSET "Icon set:" + +#define STR_GAIN "Gain" + +#define STR_FILE_NAME "File name:" +#define STR_DISK_SIZE "Disk size:" +#define STR_RPM_MODE "RPM mode:" +#define STR_PROGRESS "Progress:" + +#define STR_WIDTH "Width:" +#define STR_HEIGHT "Height:" +#define STR_LOCK_TO_SIZE "Lock to this size" + +#define STR_MACHINE_TYPE "Machine type:" +#define STR_MACHINE "Machine:" +#define STR_CONFIGURE "Configure" +#define STR_CPU_TYPE "CPU type:" +#define STR_CPU_SPEED "Speed:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Wait states:" +#define STR_MB "MB" +#define STR_MEMORY "Memory:" +#define STR_TIME_SYNC "Time synchronization" +#define STR_DISABLED "Disabled" +#define STR_ENABLED_LOCAL "Enabled (local time)" +#define STR_ENABLED_UTC "Enabled (UTC)" +#define STR_DYNAREC "Dynamic Recompiler" + +#define STR_VIDEO "Video:" +#define STR_VOODOO "Voodoo Graphics" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Mouse:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Sound card:" +#define STR_MIDI_OUT "MIDI Out Device:" +#define STR_MIDI_IN "MIDI In Device:" +#define STR_MPU401 "Standalone MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Use FLOAT32 sound" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Network type:" +#define STR_PCAP "PCap device:" +#define STR_NET "Network adapter:" + +#define STR_COM1 "COM1 Device:" +#define STR_COM2 "COM2 Device:" +#define STR_COM3 "COM3 Device:" +#define STR_COM4 "COM4 Device:" +#define STR_LPT1 "LPT1 Device:" +#define STR_LPT2 "LPT2 Device:" +#define STR_LPT3 "LPT3 Device:" +#define STR_LPT4 "LPT4 Device:" +#define STR_SERIAL1 "Serial port 1" +#define STR_SERIAL2 "Serial port 2" +#define STR_SERIAL3 "Serial port 3" +#define STR_SERIAL4 "Serial port 4" +#define STR_PARALLEL1 "Parallel port 1" +#define STR_PARALLEL2 "Parallel port 2" +#define STR_PARALLEL3 "Parallel port 3" +#define STR_PARALLEL4 "Parallel port 4" + +#define STR_HDC "HD Controller:" +#define STR_FDC "FD Controller:" +#define STR_IDE_TER "Tertiary IDE Controller" +#define STR_IDE_QUA "Quaternary IDE Controller" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controller 1:" +#define STR_SCSI_2 "Controller 2:" +#define STR_SCSI_3 "Controller 3:" +#define STR_SCSI_4 "Controller 4:" +#define STR_CASSETTE "Cassette" + +#define STR_HDD "Hard disks:" +#define STR_NEW "&New..." +#define STR_EXISTING "&Existing..." +#define STR_REMOVE "&Remove" +#define STR_BUS "Bus:" +#define STR_CHANNEL "Channel:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Specify..." +#define STR_SECTORS "Sectors:" +#define STR_HEADS "Heads:" +#define STR_CYLS "Cylinders:" +#define STR_SIZE_MB "Size (MB):" +#define STR_TYPE "Type:" +#define STR_IMG_FORMAT "Image Format:" +#define STR_BLOCK_SIZE "Block Size:" + +#define STR_FLOPPY_DRIVES "Floppy drives:" +#define STR_TURBO "Turbo timings" +#define STR_CHECKBPB "Check BPB" +#define STR_CDROM_DRIVES "CD-ROM drives:" +#define STR_CD_SPEED "Speed:" + +#define STR_MO_DRIVES "MO drives:" +#define STR_ZIP_DRIVES "ZIP drives:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "ISA Memory Expansion" +#define STR_ISAMEM_1 "Card 1:" +#define STR_ISAMEM_2 "Card 2:" +#define STR_ISAMEM_3 "Card 3:" +#define STR_ISAMEM_4 "Card 4:" +#define STR_BUGGER "ISABugger device" +#define STR_POSTCARD "POST card" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Error" + IDS_2050 "Fatal error" + IDS_2051 " - PAUSED" + IDS_2052 "Press Ctrl+Alt+PgDn to return to windowed mode." + IDS_2053 "Speed" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the ""roms"" directory." + IDS_2057 "(empty)" + IDS_2058 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "On" + IDS_2061 "Off" + IDS_2062 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" + IDS_2063 "Machine ""%hs"" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Video card ""%hs"" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." + IDS_2065 "Machine" + IDS_2066 "Display" + IDS_2067 "Input devices" + IDS_2068 "Sound" + IDS_2069 "Network" + IDS_2070 "Ports (COM & LPT)" + IDS_2071 "Storage controllers" + IDS_2072 "Hard disks" + IDS_2073 "Floppy & CD-ROM drives" + IDS_2074 "Other removable devices" + IDS_2075 "Other peripherals" + IDS_2076 "Surface images (*.86F)\0*.86F\0" + IDS_2077 "Click to capture mouse" + IDS_2078 "Press F8+F12 to release mouse" + IDS_2079 "Press F8+F12 or middle button to release mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Unable to initialize FluidSynth" + IDS_2081 "Bus" + IDS_2082 "File" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Check BPB" + IDS_2088 "KB" + IDS_2089 "Could not initialize the video renderer." + IDS_2090 "Default" + IDS_2091 "%i Wait state(s)" + IDS_2092 "Type" + IDS_2093 "Failed to set up PCap" + IDS_2094 "No PCap devices found" + IDS_2095 "Invalid PCap device" + IDS_2096 "Standard 2-button joystick(s)" + IDS_2097 "Standard 4-button joystick" + IDS_2098 "Standard 6-button joystick" + IDS_2099 "Standard 8-button joystick" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "None" + IDS_2104 "Unable to load keyboard accelerators." + IDS_2105 "Unable to register raw input." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Floppy %i (%s): %ls" + IDS_2109 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2110 "Unable to initialize FreeType" + IDS_2111 "Unable to initialize SDL, SDL2.dll is required" + IDS_2112 "Are you sure you want to hard reset the emulated machine?" + IDS_2113 "Are you sure you want to exit 86Box?" + IDS_2114 "Unable to initialize Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2117 "Welcome to 86Box!" + IDS_2118 "Internal controller" + IDS_2119 "Exit" + IDS_2120 "No ROMs found" + IDS_2121 "Do you want to save the settings?" + IDS_2122 "This will hard reset the emulated machine." + IDS_2123 "Save" + IDS_2124 "About 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." + IDS_2127 "OK" + IDS_2128 "Hardware not available" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Make sure " LIB_NAME_PCAP " is installed and that you are on a " LIB_NAME_PCAP "-compatible network connection." + IDS_2130 "Invalid configuration" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " is required for ESC/P printer emulation." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " is required for FluidSynth MIDI output." + IDS_2134 "Entering fullscreen mode" + IDS_2135 "Don't show this message again" + IDS_2136 "Don't exit" + IDS_2137 "Reset" + IDS_2138 "Don't reset" + IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2141 "%hs Device Configuration" + IDS_2142 "Monitor in sleep mode" + IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" + IDS_2144 "OpenGL options" + IDS_2145 "You are loading an unsupported configuration" + IDS_2146 "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." + IDS_2147 "Continue" + IDS_2148 "Cassette: %s" + IDS_2149 "Cassette images (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0All files (*.*)\0*.*\0" + IDS_2150 "Cartridge %i: %ls" + IDS_2151 "Cartridge images (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0All files (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Hard disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" + IDS_4100 "Custom..." + IDS_4101 "Custom (large)..." + IDS_4102 "Add New Hard Disk" + IDS_4103 "Add Existing Hard Disk" + IDS_4104 "HDI disk images cannot be larger than 4 GB." + IDS_4105 "Disk images cannot be larger than 127 GB." + IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" + IDS_4107 "Unable to read file" + IDS_4108 "Unable to write file" + IDS_4109 "HDI or HDX images with a sector size other than 512 are not supported." + IDS_4110 "USB is not yet supported" + IDS_4111 "Disk image file already exists" + IDS_4112 "Please specify a valid file name." + IDS_4113 "Disk image created" + IDS_4114 "Make sure the file exists and is readable." + IDS_4115 "Make sure the file is being saved to a writable directory." + IDS_4116 "Disk image too large" + IDS_4117 "Remember to partition and format the newly-created drive." + IDS_4118 "The selected file will be overwritten. Are you sure you want to use it?" + IDS_4119 "Unsupported disk image" + IDS_4120 "Overwrite" + IDS_4121 "Don't overwrite" + IDS_4122 "Raw image (.img)" + IDS_4123 "HDI image (.hdi)" + IDS_4124 "HDX image (.hdx)" + IDS_4125 "Fixed-size VHD (.vhd)" + IDS_4126 "Dynamic-size VHD (.vhd)" + IDS_4127 "Differencing VHD (.vhd)" + IDS_4128 "Large blocks (2 MB)" + IDS_4129 "Small blocks (512 KB)" + IDS_4130 "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" + IDS_4131 "Select the parent VHD" + IDS_4132 "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" + IDS_4133 "Parent and child disk timestamps do not match" + IDS_4134 "Could not fix VHD timestamp." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Disabled" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Disabled" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "Perfect RPM" + IDS_6145 "1% below perfect RPM" + IDS_6146 "1.5% below perfect RPM" + IDS_6147 "2% below perfect RPM" + + IDS_7168 "(System Default)" +END +#define IDS_LANG_ENUS IDS_7168 + +// English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/es-ES.rc b/src/win/languages/es-ES.rc new file mode 100644 index 000000000..3dc9757ea --- /dev/null +++ b/src/win/languages/es-ES.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Spanish (Spain) resources + +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Acción" + BEGIN + MENUITEM "&Teclado requiere captura", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "CTRL &derecho es ALT izquierdo", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard Reset...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pausa", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Salir...", IDM_ACTION_EXIT + END + POPUP "&Vista" + BEGIN + MENUITEM "&Ocultar barra de estado", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Ventana redimensionable", IDM_VID_RESIZE + MENUITEM "&Recordar tamaño y posición", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderizador" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "E&specificar dimensiones...", IDM_VID_SPECIFY_DIM + MENUITEM "F&orzar ratio 4:3", IDM_VID_FORCE43 + POPUP "&Factor de escalado de ventana" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "&Método de filtrado" + BEGIN + MENUITEM "&Más cercano", IDM_VID_FILTER_NEAREST + MENUITEM "&Lineal", IDM_VID_FILTER_LINEAR + END + MENUITEM "&Escalado alta densidad", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Pantalla completa\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Escalado pantalla completa" + BEGIN + MENUITEM "&Estirar", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Píxeles cuadrados (Mant. aspecto)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Escalado valor entero", IDM_VID_FS_INT + END + POPUP "&Ajustes EGA/(S)VGA" + BEGIN + MENUITEM "&Monitor VGA invertido", IDM_VID_INVERT + POPUP "&Tipo de pantalla VGA" + BEGIN + MENUITEM "RGB &Color", IDM_VID_GRAY_RGB + MENUITEM "RGB &Grises", IDM_VID_GRAY_MONO + MENUITEM "Monitor &Ámbar", IDM_VID_GRAY_AMBER + MENUITEM "Monitor &Verde", IDM_VID_GRAY_GREEN + MENUITEM "Monitor &Blanco", IDM_VID_GRAY_WHITE + END + POPUP "&Conversión a grises" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Media", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "&Overscan CGA/PCjr/Tandy/EGA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Cambiar contraste para pantalla &monocroma", IDM_VID_CGACON + END + MENUITEM "&Medios", IDM_MEDIA + POPUP "&Herramientas" + BEGIN + MENUITEM "&Ajustes...", IDM_CONFIG + MENUITEM "&Actualizar iconos en barra de estado", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Tomar c&aptura\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferencias...", IDM_PREFERENCES + MENUITEM "Habilitar integración con &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Ganancia de sonido...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Comenzar traza\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Terminar traza\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Ayuda" + BEGIN + MENUITEM "&Documentación...", IDM_DOCS + MENUITEM "&Acerca de 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nueva imagen...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagen &Existente...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Imagen Existente (&Sólo-lectura)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Grabar", IDM_CASSETTE_RECORD + MENUITEM "&Reproducir", IDM_CASSETTE_PLAY + MENUITEM "&Rebobinar al inicio", IDM_CASSETTE_REWIND + MENUITEM "&Avance rápido al final", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&xtraer", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Imagen...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&xtraer", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nueva imagen...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagen &existente...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Imagen existente (&sólo-lectura)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xportar a 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&xtraer", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Silenciar", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "E&xtraer disco", IDM_CDROM_EMPTY + MENUITEM "&Recargar imagen previa", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Imagen...", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nueva imagen...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagen &existente...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Imagen existente (&sólo-lectura)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xtraer", IDM_ZIP_EJECT + MENUITEM "&Recargar imagen previa", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nueva imagen...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagen &existente...", IDM_MO_IMAGE_EXISTING + MENUITEM "Imagen existente (&sólo-lectura)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xtraer", IDM_MO_EJECT + MENUITEM "&Recargar imagen previa", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Tasa de refresco objetivo" + BEGIN + MENUITEM "&Sincronizar con vídeo", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Seleccionar shader...", IDM_VID_GL_SHADER + MENUITEM "&Eliminar shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferencias" +#define STR_SND_GAIN "Ganancia de Sonido" +#define STR_NEW_FLOPPY "Nueva Imagen" +#define STR_CONFIG "Ajustes" +#define STR_SPECIFY_DIM "Especificar Dimensiones de la Ventana Principal" + +#define STR_OK "Aceptar" +#define STR_CANCEL "Cancelar" +#define STR_GLOBAL "Salvar estos ajustes como por &defecto globalmente" +#define STR_DEFAULT "&Por defecto" +#define STR_LANGUAGE "Idioma:" +#define STR_ICONSET "Juego de iconos:" + +#define STR_GAIN "Ganancia" + +#define STR_FILE_NAME "Nombre de archivo:" +#define STR_DISK_SIZE "Tamaño de disco:" +#define STR_RPM_MODE "Modo RPM:" +#define STR_PROGRESS "Progreso:" + +#define STR_WIDTH "Ancho:" +#define STR_HEIGHT "Alto:" +#define STR_LOCK_TO_SIZE "Bloquear a este tamaño" + +#define STR_MACHINE_TYPE "Tipo de máquina:" +#define STR_MACHINE "Máquina:" +#define STR_CONFIGURE "Configurar" +#define STR_CPU_TYPE "Tipo de CPU:" +#define STR_CPU_SPEED "Velocidad:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Estados en espera:" +#define STR_MB "MB" +#define STR_MEMORY "Memoria:" +#define STR_TIME_SYNC "Sincronización horaria" +#define STR_DISABLED "Deshabilitado" +#define STR_ENABLED_LOCAL "Habilitado (hora local)" +#define STR_ENABLED_UTC "Habilitado (UTC)" +#define STR_DYNAREC "Recompilador Dinámico" + +#define STR_VIDEO "Vídeo:" +#define STR_VOODOO "Voodoo Graphics" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Ratón:" +#define STR_JOYSTICK "Mando:" +#define STR_JOY1 "Mando 1..." +#define STR_JOY2 "Mando 2..." +#define STR_JOY3 "Mando 3..." +#define STR_JOY4 "Mando 4..." + +#define STR_SOUND "Tarjeta de sonido:" +#define STR_MIDI_OUT "Dispositivo MIDI de salida:" +#define STR_MIDI_IN "Dispositivo MIDI de entrada:" +#define STR_MPU401 "MPU-401 independiente" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Usar sonido FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Tipo de red:" +#define STR_PCAP "Dispositivo PCap:" +#define STR_NET "Adaptador de red:" + +#define STR_COM1 "Dispositivo COM1:" +#define STR_COM2 "Dispositivo COM2:" +#define STR_COM3 "Dispositivo COM3:" +#define STR_COM4 "Dispositivo COM4:" +#define STR_LPT1 "Dispositivo LPT1:" +#define STR_LPT2 "Dispositivo LPT2:" +#define STR_LPT3 "Dispositivo LPT3:" +#define STR_LPT4 "Dispositivo LPT4:" +#define STR_SERIAL1 "Puerto serie 1" +#define STR_SERIAL2 "Puerto serie 2" +#define STR_SERIAL3 "Puerto serie 3" +#define STR_SERIAL4 "Puerto serie 4" +#define STR_PARALLEL1 "Puerto paralelo 1" +#define STR_PARALLEL2 "Puerto paralelo 2" +#define STR_PARALLEL3 "Puerto paralelo 3" +#define STR_PARALLEL4 "Puerto paralelo 4" + +#define STR_HDC "Controladora HD:" +#define STR_FDC "Controladora FD:" +#define STR_IDE_TER "Tercera controladora IDE" +#define STR_IDE_QUA "Cuarta controladora IDE" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controladora 1:" +#define STR_SCSI_2 "Controladora 2:" +#define STR_SCSI_3 "Controladora 3:" +#define STR_SCSI_4 "Controladora 4:" +#define STR_CASSETTE "Cassette" + +#define STR_HDD "Discos duros:" +#define STR_NEW "&Nuevo..." +#define STR_EXISTING "&Existente..." +#define STR_REMOVE "E&liminar" +#define STR_BUS "Bus:" +#define STR_CHANNEL "Canal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "E&specificar..." +#define STR_SECTORS "Sectores:" +#define STR_HEADS "Cabezas:" +#define STR_CYLS "Cilindros:" +#define STR_SIZE_MB "Tamaño (MB):" +#define STR_TYPE "Tipo:" +#define STR_IMG_FORMAT "Formato de imagen:" +#define STR_BLOCK_SIZE "Tamaño de bloque:" + +#define STR_FLOPPY_DRIVES "Unidades de disquete:" +#define STR_TURBO "Temporizaciones Turbo" +#define STR_CHECKBPB "Chequear BPB" +#define STR_CDROM_DRIVES "Unidades de CD-ROM:" +#define STR_CD_SPEED "Velocidad:" + +#define STR_MO_DRIVES "Unidades MO:" +#define STR_ZIP_DRIVES "Unidades ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "Expansión de Memoria ISA" +#define STR_ISAMEM_1 "Tarjeta 1:" +#define STR_ISAMEM_2 "Tarjeta 2:" +#define STR_ISAMEM_3 "Tarjeta 3:" +#define STR_ISAMEM_4 "Tarjeta 4:" +#define STR_BUGGER "Dispositivo ISABugger" +#define STR_POSTCARD "Tarjeta POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Error" + IDS_2050 "Error fatal" + IDS_2051 " - PAUSED" + IDS_2052 "Pulsa Ctrl+Alt+PgDn para volver a modo ventana." + IDS_2053 "Velocidad" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Imagenes ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box no pudo encontrar ninguna imagen ROM usable.\n\nPor favor descarga un grupo de imágenes y extráelas en el directorio ""roms""." + IDS_2057 "(vacío)" + IDS_2058 "Imagenes ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "On" + IDS_2061 "Off" + IDS_2062 "Todas las imagenes (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" + IDS_2063 "La máquina ""%hs"" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una máquina disponible." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "La tarjeta de vídeo ""%hs"" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una tarjeta de vídeo disponible." + IDS_2065 "Máquina" + IDS_2066 "Vídeo" + IDS_2067 "Dispositivos de Entrada" + IDS_2068 "Sonido" + IDS_2069 "Red" + IDS_2070 "Puertos (COM y LPT)" + IDS_2071 "Controladoras de Almacenamiento" + IDS_2072 "Discos Duros" + IDS_2073 "Disquetes y unidades de CD-ROM" + IDS_2074 "Otros dispositivos extraíbles" + IDS_2075 "Otros periféricos" + IDS_2076 "Imágenes de superficie (*.86F)\0*.86F\0" + IDS_2077 "Haz click para capturar el ratón" + IDS_2078 "Pulsa F8+F12 para liberar el ratón" + IDS_2079 "Pulsa F8+F12 o el botón central para liberar el ratón" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Incapaz de inicializar FluidSynth" + IDS_2081 "Bus" + IDS_2082 "Archivo" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Chequear BPB" + IDS_2088 "KB" + IDS_2089 "Incapaz de inicializar el renderizador de vídeo." + IDS_2090 "Por defecto" + IDS_2091 "%i estado(s) de Espera" + IDS_2092 "Tipo" + IDS_2093 "Incapaz de configurar PCap" + IDS_2094 "No se encontraron dispositivos PCap" + IDS_2095 "Dispositivo PCap inválido" + IDS_2096 "Mando(s) de 2 botones estándar" + IDS_2097 "Mando de 4 botones estándar" + IDS_2098 "Mando de 6 botones estándar" + IDS_2099 "Mando de 8 botones estándar" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Ninguno" + IDS_2104 "Incapaz de cargar aceleradores de teclado." + IDS_2105 "Incapaz de registrar entrada directa." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Disquete %i (%s): %ls" + IDS_2109 "Todas las Imágenes (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2110 "Incapaz de inicializar FreeType" + IDS_2111 "Incapaz de inicializar SDL, se requiere SDL2.dll" + IDS_2112 "¿Seguro que quieres resetear la máquina emulada?" + IDS_2113 "¿Seguro que quieres cerrar 86Box?" + IDS_2114 "Incapaz de inicializar Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "Imágenes de MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2117 "¡Bienvenido a 86Box!" + IDS_2118 "Controladora interna" + IDS_2119 "Salir" + IDS_2120 "No se encontraron ROMs" + IDS_2121 "¿Quieres guardar los ajustes?" + IDS_2122 "Se hará hard reset de la máquina emulada." + IDS_2123 "Guardar" + IDS_2124 "Acerca de 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Un emulador de ordenadores antigüos\n\nAutores: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, y otros.\n\nLiberado bajo la GNU General Public License versión 2 o posterior. Ver LICENSE para más información." + IDS_2127 "Aceptar" + IDS_2128 "Hardware no disponible" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Asegúrate de que " LIB_NAME_PCAP " está instalado y de que estás en una conexión de red compatible con " LIB_NAME_PCAP "." + IDS_2130 "Configuración inválida" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " es necesaria para emulación de impresión ESC/P." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " es necesaria para la conversión automática de archivos PostScript a PDF.\n\nCualquier documento enviado a la impresora genérica postScript se guardará como archivo PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " es necesario para salida MIDI FluidSynth." + IDS_2134 "Entrando en modo pantalla completa" + IDS_2135 "No mostrar más este mensaje" + IDS_2136 "No salir" + IDS_2137 "Resetear" + IDS_2138 "No resetear" + IDS_2139 "Imágenes de MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2140 "Imágenes de CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2141 "%hs Configuración de Dispositivo" + IDS_2142 "Monitor en modo ahorro" + IDS_2143 "Shaders OpenGL (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0" + IDS_2144 "Opciones OpenGL" + IDS_2145 "Estás cargando una configuración no soportada" + IDS_2146 "El Filtrado de tipo de CPU basado en máquina seleccionada está deshabilitado para la esta máquina.\n\nEsto hace posible seleccionar una CPU que sea incompatible con esta máquina. Por ello, pueden aparecer incompatibilidader con la BIOS de la máquina u otro software.\n\nActivar este ajuste no está oficialmente soportado y cualquier reporte de fallo puede ser cerrado como inválido." + IDS_2147 "Continuar" + IDS_2148 "Cassette: %s" + IDS_2149 "Imágenes de Cassette (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0All files (*.*)\0*.*\0" + IDS_2150 "Cartucho %i: %ls" + IDS_2151 "Imágenes de Cartucho (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0All files (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Disco duro (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "Nunca hubo unidades de CD-ROM MFM/RLL o ESDI" + IDS_4100 "A medida..." + IDS_4101 "A medida (grande)..." + IDS_4102 "Añadir Nuevo Disco Duro" + IDS_4103 "Añadir Disco Duro Existente" + IDS_4104 "Las imágenes de disco HDI no pueden superar los 4 GB." + IDS_4105 "Las imágenes de disco no pueden superar los 127 GB." + IDS_4106 "Imágenes de Disco Duro (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" + IDS_4107 "No se pudo leer el archivo" + IDS_4108 "No se pudo escribir el archivo" + IDS_4109 "No se soportan las imágenes HDI o HDX con un tamaño de sector diferente a 512." + IDS_4110 "No se soporta aún el USB" + IDS_4111 "La imagen de disco ya existe" + IDS_4112 "Por favor especifique un nombre de archivo válido." + IDS_4113 "Imagen de disco creada" + IDS_4114 "Asegúrese de que el archivo existe y es leíble." + IDS_4115 "Asegúrese de que el archivo en un directorio con permiso de escritura." + IDS_4116 "Imagen de disco demasiado grande" + IDS_4117 "Recuerde particionar y formatear la nueva unidad." + IDS_4118 "El archivo selecionado será sobreescrito. ¿Está seguro de querer usarlo?" + IDS_4119 "Imagen de disco no soportada" + IDS_4120 "Sobreescribir" + IDS_4121 "No sobreescribir" + IDS_4122 "Imagen plana (.img)" + IDS_4123 "Imagen HDI (.hdi)" + IDS_4124 "Imagen HDX (.hdx)" + IDS_4125 "VHD de tamaño fijo (.vhd)" + IDS_4126 "VHD de tamaño dinámico (.vhd)" + IDS_4127 "VHD diferencial (.vhd)" + IDS_4128 "Bloques grandes (2 MB)" + IDS_4129 "Bloques pequeños (512 KB)" + IDS_4130 "Archivos VHD (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" + IDS_4131 "Seleccione el VHD padre" + IDS_4132 "Esto puede deberse a que la imagen padre se modificó después de que la imagen diferencial se crease.\n\nTambién puede ocurrir si las imágenes fueron movidas o copiadas, o por un fallo en el programa que creó este disco.\n\n¿Quiere corregir los registros de tiempo?" + IDS_4133 "Las marcas de tiempo del padre e hijo no coinciden" + IDS_4134 "No se pudo corregir la marca de tiempo del VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Deshabilitado" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Deshabilitado" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "RPM perfectas" + IDS_6145 "1% por debajo de RPM perfectas" + IDS_6146 "1.5% por debajo de RPM perfectas" + IDS_6147 "2% por debajo de RPM perfectas" + + IDS_7168 "(Por defecto del sistema)" +END +#define IDS_LANG_ESES IDS_7168 + +// Spanish (Spain) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/fi-FI.rc b/src/win/languages/fi-FI.rc new file mode 100644 index 000000000..d1b390bcd --- /dev/null +++ b/src/win/languages/fi-FI.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Finnish resources + +#ifdef _WIN32 +LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Toiminto" + BEGIN + MENUITEM "&Vaadi näppäimistön kaappaus", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Oikea CTRL on vasen ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Uudelleenkäynnistys (kylmä)...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Tauko", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Poistu...", IDM_ACTION_EXIT + END + POPUP "&Näytä" + BEGIN + MENUITEM "&Piilota tilapalkki", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Piilota &työkalupalkki", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Salli koon muuttaminen", IDM_VID_RESIZE + MENUITEM "&Muista koko ja sijainti", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Renderöijä" + BEGIN + MENUITEM "&SDL (ohjelmistopohjainen)", IDM_VID_SDL_SW + MENUITEM "SDL (&laitteistokiihdytetty)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "&Määritä koko...", IDM_VID_SPECIFY_DIM + MENUITEM "Pakota 4:3-näyttösuhde", IDM_VID_FORCE43 + POPUP "&Ikkunan kokokerroin" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "&Suodatusmetodi" + BEGIN + MENUITEM "&Lähin naapuri", IDM_VID_FILTER_NEAREST + MENUITEM "Li&neaarinen interpolaatio", IDM_VID_FILTER_LINEAR + END + MENUITEM "&Suuri DPI-skaalaus", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Koko näytön tila\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Koko näytön &skaalaustila" + BEGIN + MENUITEM "&Venytä koko näyttöön", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Tasasivuiset kuvapisteet (säilytä kuvasuhde)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Kokonaislukuskaalaus", IDM_VID_FS_INT + END + POPUP "&EGA/(S)VGA-asetukset" + BEGIN + MENUITEM "&VGA-näyttö käänteisillä väreillä", IDM_VID_INVERT + POPUP "VGA-näytön &tyyppi" + BEGIN + MENUITEM "RGB, &värit", IDM_VID_GRAY_RGB + MENUITEM "&RGB, harmaasävy", IDM_VID_GRAY_MONO + MENUITEM "&Meripihkanvärinen", IDM_VID_GRAY_AMBER + MENUITEM "V&ihreä", IDM_VID_GRAY_GREEN + MENUITEM "V&alkoinen", IDM_VID_GRAY_WHITE + END + POPUP "&Harmaasävymuunnoksen tyyppi" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Keskiarvo", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA &yliskannaus", IDM_VID_OVERSCAN + MENUITEM "&Muuta harmaavärinäytön kontrastia", IDM_VID_CGACON + END + MENUITEM "&Media", IDM_MEDIA + POPUP "Työ&kalut" + BEGIN + MENUITEM "&Kokoonpano...", IDM_CONFIG + MENUITEM "&Päivitä tilapalkin kuvakkeita", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Ota &kuvakaappaus\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Sovellusasetukset...", IDM_PREFERENCES + MENUITEM "Käytä &Discord-integraatiota", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Äänitasot...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Aloita jäljitys\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Lopeta jäljitys\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Ohje" + BEGIN + MENUITEM "&Ohjekirja...", IDM_DOCS + MENUITEM "&Tietoja 86Boxista...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Uusi kasettikuva...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Olemassaoleva kasettikuva...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Olemassaoleva kasettikuva (&kirjoitussuojattu)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Nauhoita", IDM_CASSETTE_RECORD + MENUITEM "&Toista", IDM_CASSETTE_PLAY + MENUITEM "Kelaa &alkuun", IDM_CASSETTE_REWIND + MENUITEM "Kelaa &loppuun", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Poista kasettipesästä", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&ROM-moduulikuva...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Irrota", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Uusi levykekuva...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Olemassaoleva levykekuva...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Olemassaoleva levykekuva (&kirjoitussuojattu)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Vie 86F-tiedostoon...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Poista asemasta", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Mykistä", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Tyhjä", IDM_CDROM_EMPTY + MENUITEM "&Lataa edellinen levykuva uudelleen", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "L&evykuva", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Uusi levykuva...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Olemassaoleva levykuva...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Olemassaoleva levykuva (&kirjoitussuojattu)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Poista asemasta", IDM_ZIP_EJECT + MENUITEM "&Lataa edellinen levykuva uudelleen", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Uusi levykuva...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Olemassaoleva levykuva...", IDM_MO_IMAGE_EXISTING + MENUITEM "Olemassaoleva levykuva (&kirjoitussuojattu)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Poista asemasta", IDM_MO_EJECT + MENUITEM "&Lataa edellinen levykuva uudelleen", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Kuvataajuustavoite" + BEGIN + MENUITEM "&Synkronisoi videoon", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 ruutua/s", IDM_VID_GL_FPS_25 + MENUITEM "&30 ruutua/s", IDM_VID_GL_FPS_30 + MENUITEM "&50 ruutua/s", IDM_VID_GL_FPS_50 + MENUITEM "&60 ruutua/s", IDM_VID_GL_FPS_60 + MENUITEM "&75 ruutua/s", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "Valitse varjostin&ohjelma...", IDM_VID_GL_SHADER + MENUITEM "&Poista varjostinohjelma", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Sovellusasetukset" +#define STR_SND_GAIN "Äänen taso" +#define STR_NEW_FLOPPY "Uusi levykuva" +#define STR_CONFIG "Kokoonpano" +#define STR_SPECIFY_DIM "Määritä pääikkunan koko" + +#define STR_OK "OK" +#define STR_CANCEL "Peruuta" +#define STR_GLOBAL "Tallenna nämä asetukset &globaaleiksi oletuksiksi" +#define STR_DEFAULT "&Oletus" +#define STR_LANGUAGE "Kieli:" +#define STR_ICONSET "Kuvakkeet:" + +#define STR_GAIN "Taso" + +#define STR_FILE_NAME "Tiedostonimi:" +#define STR_DISK_SIZE "Levyn koko:" +#define STR_RPM_MODE "Kierroslukutila:" +#define STR_PROGRESS "Edistyminen:" + +#define STR_WIDTH "Leveys:" +#define STR_HEIGHT "Korkeus:" +#define STR_LOCK_TO_SIZE "Lukitse tähän kokoon" + +#define STR_MACHINE_TYPE "Tietokoneen tyyppi:" +#define STR_MACHINE "Tietokone:" +#define STR_CONFIGURE "Määritys" +#define STR_CPU_TYPE "Suorittimen tyyppi:" +#define STR_CPU_SPEED "Nopeus:" +#define STR_FPU "Apusuoritin:" +#define STR_WAIT_STATES "Odotustilat:" +#define STR_MB "Mt" +#define STR_MEMORY "Muisti:" +#define STR_TIME_SYNC "Kellon synkronointi" +#define STR_DISABLED "Ei käytössä" +#define STR_ENABLED_LOCAL "Käytössä (paikallinen)" +#define STR_ENABLED_UTC "Käytössä (UTC)" +#define STR_DYNAREC "Dynaaminen uudelleenkääntäjä" + +#define STR_VIDEO "Näytönohjain:" +#define STR_VOODOO "Voodoo-grafiikkasuoritin" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Hiiri:" +#define STR_JOYSTICK "Peliohjain:" +#define STR_JOY1 "Peliohjain 1..." +#define STR_JOY2 "Peliohjain 2..." +#define STR_JOY3 "Peliohjain 3..." +#define STR_JOY4 "Peliohjain 4..." + +#define STR_SOUND "Äänikortti:" +#define STR_MIDI_OUT "MIDI-ulostulo:" +#define STR_MIDI_IN "MIDI-sisääntulo:" +#define STR_MPU401 "Erillinen MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Käytä FLOAT32-ääntä" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Verkon tyyppi:" +#define STR_PCAP "PCap-laite:" +#define STR_NET "Verkkokortti:" + +#define STR_COM1 "COM1-laite:" +#define STR_COM2 "COM2-laite:" +#define STR_COM3 "COM3-laite:" +#define STR_COM4 "COM4-laite:" +#define STR_LPT1 "LPT1-laite:" +#define STR_LPT2 "LPT2-laite:" +#define STR_LPT3 "LPT3-laite:" +#define STR_LPT4 "LPT4-laite:" +#define STR_SERIAL1 "Sarjaportti 1" +#define STR_SERIAL2 "Sarjaportti 2" +#define STR_SERIAL3 "Sarjaportti 3" +#define STR_SERIAL4 "Sarjaportti 4" +#define STR_PARALLEL1 "Rinnakkaisportti 1" +#define STR_PARALLEL2 "Rinnakkaisportti 2" +#define STR_PARALLEL3 "Rinnakkaisportti 3" +#define STR_PARALLEL4 "Rinnakkaisportti 4" + +#define STR_HDC "Kiintolevyohjain:" +#define STR_FDC "Levykeohjain:" +#define STR_IDE_TER "Kolmas IDE-ohjain" +#define STR_IDE_QUA "Neljäs IDE-ohjain" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Ohjain 1:" +#define STR_SCSI_2 "Ohjain 2:" +#define STR_SCSI_3 "Ohjain 3:" +#define STR_SCSI_4 "Ohjain 4:" +#define STR_CASSETTE "Kasettiasema" + +#define STR_HDD "Kiintolevyt:" +#define STR_NEW "&Uusi..." +#define STR_EXISTING "&Olemassaoleva..." +#define STR_REMOVE "&Poista" +#define STR_BUS "Väylä:" +#define STR_CHANNEL "Kanava:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Määritä..." +#define STR_SECTORS "Sektorit:" +#define STR_HEADS "Lukupäät:" +#define STR_CYLS "Sylinterit:" +#define STR_SIZE_MB "Koko (Mt):" +#define STR_TYPE "Tyyppi:" +#define STR_IMG_FORMAT "Tiedostomuoto:" +#define STR_BLOCK_SIZE "Lohkon koko:" + +#define STR_FLOPPY_DRIVES "Levykeasemat:" +#define STR_TURBO "Turbo-ajoitukset" +#define STR_CHECKBPB "Tarkista BPB" +#define STR_CDROM_DRIVES "CD-ROM-asemat:" +#define STR_CD_SPEED "Nopeus:" + +#define STR_MO_DRIVES "Magneettisoptiset asemat (MO):" +#define STR_ZIP_DRIVES "ZIP-asemat:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA-RTC (kello):" +#define STR_ISAMEM "ISA-muistilaajennus" +#define STR_ISAMEM_1 "Kortti 1:" +#define STR_ISAMEM_2 "Kortti 2:" +#define STR_ISAMEM_3 "Kortti 3:" +#define STR_ISAMEM_4 "Kortti 4:" +#define STR_BUGGER "ISABugger-laite" +#define STR_POSTCARD "POST-kortti" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Virhe" + IDS_2050 "Vakava virhe" + IDS_2051 " - TAUKO" + IDS_2052 "Paina Ctrl+Alt+PgDn palataksesi ikkunoituun tilaan." + IDS_2053 "Nopeus" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP-levykuvat (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box ei löytänyt käyttökelpoisia ROM-tiedostoja.\n\nVoit ladata ROM-paketin ja purkaa sen ""roms""-hakemistoon." + IDS_2057 "(tyhjä)" + IDS_2058 "ZIP-levykuvat (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Päällä" + IDS_2061 "Pois" + IDS_2062 "Kaikki levykuvat (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Perussektorilevykuvat (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Pintalevykuvat (*.86F)\0*.86F\0" + IDS_2063 "Konetta ""%hs"" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen koneeseen." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Näytönohjainta ""%hs"" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen näytönohjaimeen." + IDS_2065 "Tietokone" + IDS_2066 "Näyttö" + IDS_2067 "Syöttölaitteet" + IDS_2068 "Ääni" + IDS_2069 "Verkko" + IDS_2070 "Portit (COM & LPT)" + IDS_2071 "Tallennusohjaimet" + IDS_2072 "Kiintolevyt" + IDS_2073 "Levyke ja CD-ROM" + IDS_2074 "Muut tallennuslaitteet" + IDS_2075 "Muut oheislaitteet" + IDS_2076 "Pintalevykuvat (*.86F)\0*.86F\0" + IDS_2077 "Kaappaa hiiri klikkaamalla" + IDS_2078 "Paina F8+F12 vapauttaaksesi hiiren" + IDS_2079 "Paina F8+F12 tai keskipainiketta vapauttaaksesi hiiren" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "FluidSynthin alustus epäonnistui" + IDS_2081 "Väylä" + IDS_2082 "Tiedosto" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "Mt" + IDS_2087 "Tarkista BPB" + IDS_2088 "kt" + IDS_2089 "Videorenderöijän alustus epäonnistui" + IDS_2090 "Oletus" + IDS_2091 "%i odotustilaa" + IDS_2092 "Tyyppi" + IDS_2093 "PCap-asennus epäonnistui" + IDS_2094 "PCap-laitteita ei löytynyt" + IDS_2095 "Virheellinen PCap-laite" + IDS_2096 "Standardi 2-painikkeinen peliohjain/-ohjaimet" + IDS_2097 "Standardi 4-painikkeinen peliohjain" + IDS_2098 "Standardi 6-painikkeinen peliohjain" + IDS_2099 "Standardi 8-painikkeinen peliohjain" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Ei mikään" + IDS_2104 "Näppäinkiihdyttimien lataus epäonnistui" + IDS_2105 "Raakasyötteen rekisteröinti epäonnistui" + IDS_2106 "%u" + IDS_2107 "%u Mt (CHS: %i, %i, %i)" + IDS_2108 "Levyke %i (%s): %ls" + IDS_2109 "Kaikki levykuvat (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Kehittyneet sektorilevykuvat (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Perussektorilevykuvat (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux-levykuvat (*.FDI)\0*.FDI\0Pintalevykuvat (*.86F;*.MFM)\0*.86F;*.MFM\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2110 "FreeType:n alustus epäonnistui" + IDS_2111 "SDL:n alustus epäonnistui. Tarvitaan SDL2.dll" + IDS_2112 "Haluatko varmasti käynnistää emuloidun tietokoneen uudelleen?" + IDS_2113 "Haluatko varmasti sulkea 86Boxin?" + IDS_2114 "Ghostscriptin alustus epäonnistui" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO-levykuvat (*.IM?;*.MDI)\0*.IM?;*.MDI\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2117 "Tervetuloa 86Boxiin!" + IDS_2118 "Sisäinen ohjain" + IDS_2119 "Poistu" + IDS_2120 "ROM-tiedostoja ei löytynyt" + IDS_2121 "Tallennetaanko asetukset?" + IDS_2122 "Tämä käynnistää emuloidun tietokoneen uudelleen." + IDS_2123 "Tallenna" + IDS_2124 "Tietoja 86Box:sta" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Vanhojen tietokoneiden emulaattori\n\nTekijät: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho ja muut.\n\nJulkaistu GNU General Public License 2. version tai myöhemmän alaisena. Tarkempia tietoja LICENSE-tiedostossa." + IDS_2127 "OK" + IDS_2128 "Laitteisto ei ole saatavilla" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Varmista, että " LIB_NAME_PCAP " on asennettu ja että verkkoyhteytesi on " LIB_NAME_PCAP "-yhteensopiva." + IDS_2130 "Virheelliset määritykset" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " vaaditaan ESC/P-tulostimen emuloimiseksi." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " vaaditaan PostScript-tiedostojen automaattiseen muuntamiseen PDF-tiedostoiksi.\n\nKaikki geneeriselle PostScript-tulostimelle lähetetyt asiakirjat tallennetaan PostScript (.ps) -tiedostoina." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " vaaditaan FluidSynth MIDI-ulostuloa varten." + IDS_2134 "Siirrytään koko näytön tilaan" + IDS_2135 "Älä näytä tätä viestiä uudelleen" + IDS_2136 "Älä poistu" + IDS_2137 "Käynnistä uudelleen" + IDS_2138 "Älä käynnistä uudelleen" + IDS_2139 "MO-levykuvat (*.IM?;*.MDI)\0*.IM?;*.MDI\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2140 "CD-ROM-levykuvat (*.ISO;*.CUE)\0*.ISO;*.CUE\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2141 "%hs - Laitteen määritykset" + IDS_2142 "Näyttö lepotilassa" + IDS_2143 "OpenGL-varjostinohjelmat (*.GLSL)\0*.GLSL\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2144 "OpenGL-asetukset" + IDS_2145 "Olet lataamassa ei-tuettuja määrittelyjä" + IDS_2146 "Valittuun tietokoneeseen perustuva suoritintyypin suodatus ei ole käytössä tällä emuloidulla koneella.\n\nTämä mahdollistaa muutoin yhteensopimattoman suorittimen valinnan kyseisen tietokoneen kanssa. Voit kuitenkin kohdata ongelmia tietokoneen BIOS:in tai muun ohjelmiston kanssa.\n\nTämän asetuksen käyttö ei ole virallisesti tuettua ja kaikki tehdyt virheraportit voidaan sulkea epäpätevinä." + IDS_2147 "Jatka" + IDS_2148 "Kasetti: %s" + IDS_2149 "Kasettitiedostot (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2150 "ROM-moduuli %i: %ls" + IDS_2151 "ROM-moduulikuvat (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_2152 "Virhe renderöijän alustuksessa" + IDS_2153 "OpenGL (3.0 Core) -renderöijän alustus epäonnistui. Käytä toista renderöijää." + IDS_2154 "Jatka suoritusta" + IDS_2155 "Pysäytä suoritus" + IDS_2156 "Paina Ctrl+Alt+Del" + IDS_2157 "Paina Ctrl+Alt+Esc" + IDS_2158 "Kylmä uudelleenkäynnistys" + IDS_2159 "ACPI-sammutus" + IDS_2160 "Asetukset" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Kiintolevy (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL- tai ESDI-CD-ROM-asemia ei ole koskaan ollut olemassa" + IDS_4100 "Mukautettu..." + IDS_4101 "Mukautettu (suuri)..." + IDS_4102 "Lisää uusi kiintolevy" + IDS_4103 "Lisää olemassaoleva kiintolevy" + IDS_4104 "HDI-levykuvan suurin mahdollinen koko on 4 Gt." + IDS_4105 "Levykuvien suurin mahdollinen koko on 127 Gt." + IDS_4106 "Kiintolevykuvat (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_4107 "Tiedostoa ei voi lukea" + IDS_4108 "Tiedostoon ei voi kirjoittaa" + IDS_4109 "HDI- ja HDX-levykuvien ainoa tuettu sektorikoko on 512" + IDS_4110 "USB-tukea ei vielä ole" + IDS_4111 "Levykuva on jo olemassa" + IDS_4112 "Anna kelvollinen tiedostonimi." + IDS_4113 "Levykuva luotu" + IDS_4114 "Varmista, että tiedosto on olemassa ja lukukelpoinen" + IDS_4115 "Varmista, että tiedoston tallennuskansioon on kirjoitusoikeus" + IDS_4116 "Liian suuri levykuva" + IDS_4117 "Muista osioida ja alustaa juuri luomasi asema." + IDS_4118 "Valittu tiedosto korvataan. Oletko varma, että haluat käyttää sitä?" + IDS_4119 "Levykuvaa ei tueta" + IDS_4120 "Korvaa" + IDS_4121 "Älä korvaa" + IDS_4122 "Raaka levykuva (.img)" + IDS_4123 "HDI-levykuva (.hdi)" + IDS_4124 "HDX-levykuva (.hdx)" + IDS_4125 "Kiinteä VHD (.vhd)" + IDS_4126 "Dynaaminen VHD (.vhd)" + IDS_4127 "Differentiaalinen VHD (.vhd)" + IDS_4128 "Suuret lohkot (2 Mt)" + IDS_4129 "Pienet lohkot (512 kt)" + IDS_4130 "VHD-tiedostot (*.VHD)\0*.VHD\0Kaikki tiedostot (*.*)\0*.*\0" + IDS_4131 "Valitse ylätason VHD" + IDS_4132 "Tämä saattaa tarkoittaa, että ylätason levykuvaa on muokattu differentiaalisen levykuvan luonnin jälkeen.\n\nNäin voi käydä myös, jos levykuvatiedostoja on siirretty tai kopioitu. Lisäksi syynä voi olla levyn luoneessa sovelluksessa oleva ohjelmistovirhe.\n\nKorjataanko aikaleimat?" + IDS_4133 "Ylä- ja alatason levyjen aikaleimat eivät täsmää" + IDS_4134 "VHD aikaleimaa ei pystytty korjaamaan." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Ei käytössä" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Ei käytössä" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kt" + IDS_5889 "180 kt" + IDS_5890 "320 kt" + IDS_5891 "360 kt" + IDS_5892 "640 kt" + IDS_5893 "720 kt" + IDS_5894 "1.2 Mt" + IDS_5895 "1.25 Mt" + IDS_5896 "1.44 Mt" + IDS_5897 "DMF (lohko 1024)" + IDS_5898 "DMF (lohko 2048)" + IDS_5899 "2.88 Mt" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 Mt (ISO 10090)" + IDS_5903 "3.5"" 230 Mt (ISO 13963)" + IDS_5904 "3.5"" 540 Mt (ISO 15498)" + IDS_5905 "3.5"" 640 Mt (ISO 15498)" + IDS_5906 "3.5"" 1.3 Gt (GigaMO)" + IDS_5907 "3.5"" 2.3 Gt (GigaMO 2)" + IDS_5908 "5.25"" 600 Mt" + IDS_5909 "5.25"" 650 Mt" + IDS_5910 "5.25"" 1 Gt" + IDS_5911 "5.25"" 1.3 Gt" + + IDS_6144 "Täydellinen RPM" + IDS_6145 "1% alle täydellisen RPM:n" + IDS_6146 "1.5% alle täydellisen RPM:n" + IDS_6147 "2% alle täydellisen RPM:n" + + IDS_7168 "(Järjestelmän oletus)" +END +#define IDS_LANG_ENUS IDS_7168 + +// English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/fr-FR.rc b/src/win/languages/fr-FR.rc new file mode 100644 index 000000000..eab96bf05 --- /dev/null +++ b/src/win/languages/fr-FR.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// French (fr-FR) resources + +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Capturer le clavier", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "CTRL &Droite devient ALT Gauche", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard Reset...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pause", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Quitter...", IDM_ACTION_EXIT + END + POPUP "&Vue" + BEGIN + MENUITEM "&Masquer la barre de status", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "Fenètre &Retaillable", IDM_VID_RESIZE + MENUITEM "S&auvegarder taille && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Moteur de &rendu vidéo" + BEGIN + MENUITEM "&SDL (Logiciel)", IDM_VID_SDL_SW + MENUITEM "SDL (&Materiel)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Specifier dimensions...", IDM_VID_SPECIFY_DIM + MENUITEM "F&orcer 4:3", IDM_VID_FORCE43 + POPUP "&Echelle facteur" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Methode Filtre" + BEGIN + MENUITEM "&Plus proche", IDM_VID_FILTER_NEAREST + MENUITEM "&Lineaire", IDM_VID_FILTER_LINEAR + END + MENUITEM "Mise à l'échelle Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Plein Ecran\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Mode &Elargi plein écran" + BEGIN + MENUITEM "&Plein écran étiré", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "pixels &Carrés(Keep ratio)", IDM_VID_FS_KEEPRATIO + MENUITEM "Echelle &Entière", IDM_VID_FS_INT + END + POPUP "Réglages E&GA/(S)VGA" + BEGIN + MENUITEM "Moniteur VGA &Inversé", IDM_VID_INVERT + POPUP "&Type Ecran VGA" + BEGIN + MENUITEM "RGB &Couleur", IDM_VID_GRAY_RGB + MENUITEM "&RGB Ton de Gris", IDM_VID_GRAY_MONO + MENUITEM "Moniteur &Ambre", IDM_VID_GRAY_AMBER + MENUITEM "Moniteur &Vert", IDM_VID_GRAY_GREEN + MENUITEM "Moniteur &Blanc", IDM_VID_GRAY_WHITE + END + POPUP "Grayscale &conversion type" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Moyenne", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + MENUITEM "Modifier contraste affichage &monochrome", IDM_VID_CGACON + END + MENUITEM "&Media", IDM_MEDIA + POPUP "Ou&tils" + BEGIN + MENUITEM "&Réglages...", IDM_CONFIG + MENUITEM "Mettre à jour la barre de stat&us", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Copie &Ecran\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Préférences...", IDM_PREFERENCES + MENUITEM "Activer intégration &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Gain Son...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Démarrer traces\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Finir traces\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Aide" + BEGIN + MENUITEM "&Documentation...", IDM_DOCS + MENUITEM "&A Propos de 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nouvelle image...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Image &Existante...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Image Existante(&Lecture seule)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "En®istrer", IDM_CASSETTE_RECORD + MENUITEM "&Jouer", IDM_CASSETTE_PLAY + MENUITEM "&Revenir au debut", IDM_CASSETTE_REWIND + MENUITEM "Aller à la &Fin", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&jecter", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Image...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&jecter", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nouvelle image...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Image &Existante...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Image Existante(&Lecture seule)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xport vers 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&jecter", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Couper", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "E&jecter", IDM_CDROM_EMPTY + MENUITEM "&Recharger image précedente", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nouvelle image...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Image &Existante...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Image Existante (&Lecture Seule)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&jecter", IDM_ZIP_EJECT + MENUITEM "&Recharger image précédente", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nouvelle image...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Image &Existante...", IDM_MO_IMAGE_EXISTING + MENUITEM "Image Existante (&Lecture Seule)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&jecter", IDM_MO_EJECT + MENUITEM "&Recharger image précédente", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Taux de rafraîchissement cible" + BEGIN + MENUITEM "&Synchronisation avec la vidéo", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 images par seconde", IDM_VID_GL_FPS_25 + MENUITEM "&30 images par seconde", IDM_VID_GL_FPS_30 + MENUITEM "&50 images par seconde", IDM_VID_GL_FPS_50 + MENUITEM "&60 images par seconde", IDM_VID_GL_FPS_60 + MENUITEM "&75 images par seconde", IDM_VID_GL_FPS_75 + END + MENUITEM "Synchronisation &verticale", IDM_VID_GL_VSYNC + MENUITEM "Sé&lectionnez le shader...", IDM_VID_GL_SHADER + MENUITEM "S&upprimer le shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Préférences" +#define STR_SND_GAIN "Gain son" +#define STR_NEW_FLOPPY "Nouvelle image" +#define STR_CONFIG "Réglages" +#define STR_SPECIFY_DIM "Spécifier le détournement de la fenêtre principale" + +#define STR_OK "OK" +#define STR_CANCEL "Annuler" +#define STR_GLOBAL "Sauvegarder ces paramètres comme valeurs par défaut &globales" +#define STR_DEFAULT "&Défaut" +#define STR_LANGUAGE "Langue:" +#define STR_ICONSET "Ensemble d'icônes:" + +#define STR_GAIN "Gain" + +#define STR_FILE_NAME "Nom fichier:" +#define STR_DISK_SIZE "Taille disque:" +#define STR_RPM_MODE "Mode RPM:" +#define STR_PROGRESS "Progrès:" + +#define STR_WIDTH "Largeur:" +#define STR_HEIGHT "Hauteur:" +#define STR_LOCK_TO_SIZE "Verrouiller à cette taille" + +#define STR_MACHINE_TYPE "Type de machine:" +#define STR_MACHINE "Machine:" +#define STR_CONFIGURE "Configurer" +#define STR_CPU_TYPE "Type du processeur:" +#define STR_CPU_SPEED "Vitesse:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "États d'attente:" +#define STR_MB "Mo" +#define STR_MEMORY "Mémoire:" +#define STR_TIME_SYNC "Synchronisation du temps" +#define STR_DISABLED "Désactivé" +#define STR_ENABLED_LOCAL "Activé (heure locale)" +#define STR_ENABLED_UTC "Activé (UTC)" +#define STR_DYNAREC "Recompilateur dynamique" + +#define STR_VIDEO "Vidéo:" +#define STR_VOODOO "Graphique Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Souris:" +#define STR_JOYSTICK "Manette de commande:" +#define STR_JOY1 "Manette 1..." +#define STR_JOY2 "Manette 2..." +#define STR_JOY3 "Manette 3..." +#define STR_JOY4 "Manette 4..." + +#define STR_SOUND "Carte son:" +#define STR_MIDI_OUT "Sortie MIDI:" +#define STR_MIDI_IN "Entrée MIDI:" +#define STR_MPU401 "MPU-401 autonome" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Utiliser le son FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Type de réseau:" +#define STR_PCAP "Dispositif PCap:" +#define STR_NET "Adaptateur de réseau:" + +#define STR_COM1 "Dispositif COM1:" +#define STR_COM2 "Dispositif COM2:" +#define STR_COM3 "Dispositif COM3:" +#define STR_COM4 "Dispositif COM4:" +#define STR_LPT1 "Dispositif LPT1:" +#define STR_LPT2 "Dispositif LPT2:" +#define STR_LPT3 "Dispositif LPT3:" +#define STR_LPT4 "Dispositif LPT4:" +#define STR_SERIAL1 "Port série 1" +#define STR_SERIAL2 "Port série 2" +#define STR_SERIAL3 "Port série 3" +#define STR_SERIAL4 "Port série 4" +#define STR_PARALLEL1 "Port parallèle 1" +#define STR_PARALLEL2 "Port parallèle 2" +#define STR_PARALLEL3 "Port parallèle 3" +#define STR_PARALLEL4 "Port parallèle 4" + +#define STR_HDC "Contrôleur HD:" +#define STR_FDC "Contrôleur FD:" +#define STR_IDE_TER "Contrôleur IDE tertiaire" +#define STR_IDE_QUA "Contrôleur IDE quaternair" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Contrôleur 1:" +#define STR_SCSI_2 "Contrôleur 2:" +#define STR_SCSI_3 "Contrôleur 3:" +#define STR_SCSI_4 "Contrôleur 4:" +#define STR_CASSETTE "Cassette" + +#define STR_HDD "Disques durs:" +#define STR_NEW "&Nouveau..." +#define STR_EXISTING "&Existant..." +#define STR_REMOVE "&Supprimer" +#define STR_BUS "Bus:" +#define STR_CHANNEL "Canal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Spécifier..." +#define STR_SECTORS "Secteurs:" +#define STR_HEADS "Têtes:" +#define STR_CYLS "Cylindres:" +#define STR_SIZE_MB "Taille (Mo):" +#define STR_TYPE "Type:" +#define STR_IMG_FORMAT "Format Image:" +#define STR_BLOCK_SIZE "Taille du bloc:" + +#define STR_FLOPPY_DRIVES "Lecteurs de disquettes:" +#define STR_TURBO "Turbo" +#define STR_CHECKBPB "Vérifier BPB" +#define STR_CDROM_DRIVES "Lecterus CD-ROM:" +#define STR_CD_SPEED "Vitesse:" + +#define STR_MO_DRIVES "Lecteurs magnéto-optiques:" +#define STR_ZIP_DRIVES "Lecteurs ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "Horloge temps réel ISA:" +#define STR_ISAMEM "Expansion de la mémoire ISA" +#define STR_ISAMEM_1 "Carte 1:" +#define STR_ISAMEM_2 "Carte 2:" +#define STR_ISAMEM_3 "Carte 3:" +#define STR_ISAMEM_4 "Carte 4:" +#define STR_BUGGER "Dispositif ISABugger" +#define STR_POSTCARD "Carte POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Erreur" + IDS_2050 "Erreur fatale" + IDS_2051 " - PAUSED" + IDS_2052 "Appuyez sur Ctrl+Alt+PgDn pour revenir au mode fenêtré." + IDS_2053 "Vitesse" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Images ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box n'a pas pu trouver d'images ROM utilisables.\n\nS'il vous plait, téléchargez un ensemble ROM et extrayez-le dans le répertoire ""roms""." + IDS_2057 "(vide)" + IDS_2058 "Images ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Tous les fichiers (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Activé" + IDS_2061 "Désactivé" + IDS_2062 "Tous les images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Images basiques du secteur (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Images de la surface (*.86F)\0*.86F\0" + IDS_2063 "La machine ""%hs"" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/machines. Basculer vers une machine disponible." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "La carte vidéo ""%hs"" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/video. Basculer vers une carte vidéo disponible." + IDS_2065 "Machine" + IDS_2066 "Affichage" + IDS_2067 "Dispositifs d'entrée" + IDS_2068 "Son" + IDS_2069 "Réseau" + IDS_2070 "Ports (COM et LPT)" + IDS_2071 "Contrôleurs de stockage" + IDS_2072 "Disques durs" + IDS_2073 "Lecteurs de disquette et CD-ROM" + IDS_2074 "Autres dispositifs amovibles" + IDS_2075 "Autres périfériques" + IDS_2076 "Images de surface (*.86F)\0*.86F\0" + IDS_2077 "Cliquer pour capturer la souris" + IDS_2078 "Appuyer sur F8+F12 pour libérer la souris" + IDS_2079 "Appuyer sur F8+F12 ou le bouton central pour libérer la souris" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Impossible d'initialiser FluidSynth" + IDS_2081 "Bus" + IDS_2082 "File" + IDS_2083 "C" + IDS_2084 "T" + IDS_2085 "S" + IDS_2086 "Mo" + IDS_2087 "Vérifier BPB" + IDS_2088 "Ko" + IDS_2089 "Impossible d'initialiser le moteur de rendu vidéo." + IDS_2090 "Défaut" + IDS_2091 "%i état(s) d'attente" + IDS_2092 "Type" + IDS_2093 "Impossible d'initialiser PCap" + IDS_2094 "Aucun dispositif PCap trouvé" + IDS_2095 "Dispositif PCap non valide" + IDS_2096 "Manette(s) standard avec 2 boutons" + IDS_2097 "Manette standard avec 4 boutons" + IDS_2098 "Manette standard avec 6 boutons" + IDS_2099 "Manette standard avec 6 boutons" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Système de contrôle de vol Thrustmaster" + IDS_2103 "Aucun" + IDS_2104 "Impossible de charger les accélérateurs de clavier." + IDS_2105 "Impossible de charger l'entrée raw." + IDS_2106 "%u" + IDS_2107 "%u Mo (CTS: %i, %i, %i)" + IDS_2108 "Disquette %i (%s): %ls" + IDS_2109 "Toutes les images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Images du secteur avancés (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Images du secteur basiques (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Images du flux (*.FDI)\0*.FDI\0Images de surface (*.86F;*.MFM)\0*.86F;*.MFM\0Tous les fichiers (*.*)\0*.*\0" + IDS_2110 "Impossible d'initialiser FreeType" + IDS_2111 "Impossible d'initialiser SDL, SDL2.dll est nécessaire" + IDS_2112 "Etes-vous sûr de vouloir réinitialiser la machine émulée ?" + IDS_2113 "Etes-vous sûr de vouloir quitter 86Box?" + IDS_2114 "Impossible d'initialiser Ghostscript" + IDS_2115 "Magnéto-optique %i (%ls): %ls" + IDS_2116 "Images magnéto-optiques (*.IM?;*.MDI)\0*.IM?;*.MDI\0Tous les fichiers (*.*)\0*.*\0" + IDS_2117 "Bienvenue dans 86Box !" + IDS_2118 "Côntrolleur interne" + IDS_2119 "Sortir" + IDS_2120 "Pas de ROMs trouvées" + IDS_2121 "Voulez-vous sauvegarder les paramètres ?" + IDS_2122 "Cela entraînera la réinitialisation complète de la machine émulée." + IDS_2123 "Sauvegarder" + IDS_2124 "À propos de 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Un émulateur de vieux ordinateurs\n\nAuteurs: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nLibéré sous la licence GNU General Public License version 2 ou ultérieure. Pour plus d'informations, voir le fichier LICENSE." + IDS_2127 "OK" + IDS_2128 "Matériel non disponible" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Assurez-vous que " LIB_NAME_PCAP " est installé et que vou utilisez une connexion réseau compatible avec " LIB_NAME_PCAP "." + IDS_2130 "Configuration non valide" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " est nécessaire pour l'émulation de l'imprimante ESC/P." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " est nécessair pour la conversion automatique des fichiers PostScript dans PDF.\n\nTous les documents envoyés à l'imprimante générique PostScript seront sauvés comme des fichiers PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " est nécessaire pour la sortie MIDI FluidSynth." + IDS_2134 "Entrer en mode plein écran" + IDS_2135 "Ne pas montrer ce message à nouveau" + IDS_2136 "Ne pas sortir" + IDS_2137 "Réinitialiser" + IDS_2138 "Ne pas réinitialiser" + IDS_2139 "Images magnéto-optiques (*.IM?;*.MDI)\0*.IM?;*.MDI\0Tous les fichiers (*.*)\0*.*\0" + IDS_2140 "Images CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Tous les fichiers (*.*)\0*.*\0" + IDS_2141 "Configuration du dispositif %hs" + IDS_2142 "Moniteur en mode veille" + IDS_2143 "Shaders OpenGL (*.GLSL)\0*.GLSL\0Tous les fichiers (*.*)\0*.*\0" + IDS_2144 "Options OpenGL" + IDS_2145 "Vous chargez une configuration non prise en charge" + IDS_2146 "La filtrage du type du processeur sur la base de la machine sélectionné est désactivé pur cette machine émulée.\n\nCela permet de sélectionner une processeur que est sinon incompatible avec la machine sélectionné. Cependant, il pourrait y avoir des incompatibilités avec le BIOS de la machine ou autres logiciels.\n\nL'activatione de cette configuration non est officiellement prise en charge et tout rapport de bogue peut être fermé comme étant invalide." + IDS_2147 "Continuer" + IDS_2148 "Cassette: %s" + IDS_2149 "Images cassette (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Tous les fichiers (*.*)\0*.*\0" + IDS_2150 "Cartouche %i: %ls" + IDS_2151 "Images cartouche (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Tous les fichiers (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Disque dur (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "Les lecteurs de CD-ROM MFM/RLL ou ESDI n'ont jamais existé" + IDS_4100 "Personnalisé..." + IDS_4101 "Personnalisé (grand)..." + IDS_4102 "Ajouter un nouveau disque dur" + IDS_4103 "Ajouter un disque dur existant" + IDS_4104 "Les images de disque HDI ne peuvent pas avoir une taille supériure à Go." + IDS_4105 "Les images de disque ne peuvent pas avoir un taille supérieure à 127 Go." + IDS_4106 "Images de dique dur (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Tous les fichiers (*.*)\0*.*\0" + IDS_4107 "Impossible de lire le fichier" + IDS_4108 "Impossible d'écrire le fichier" + IDS_4109 "Les images HDI ou HDX avec une taille de secteur différente de 512 non sont pas prises en charge." + IDS_4110 "USB n'est pas encore pris en charge." + IDS_4111 "Le fichier de l'image disque existe déjà." + IDS_4112 "Veuillez spécifier un nom de fichier valide." + IDS_4113 "Image de disque créée" + IDS_4114 "Assurez-vous que le fichier existe et est lisible." + IDS_4115 "Assurez-vous que le fichier en cours d'enregistrement se trouve dans un répertoire accessible en écriture." + IDS_4116 "Image disque trop grande" + IDS_4117 "N'oubliez pas de partitionner et de formater le nouveau disque créé." + IDS_4118 "Le fichier sélectionné sera écrasé. Etes-vous sûr de vouloir l'utiliser?" + IDS_4119 "Image disque non prise en charge" + IDS_4120 "Écraser" + IDS_4121 "Ne pas écraser" + IDS_4122 "Image brute (.img)" + IDS_4123 "Image HDI (.hdi)" + IDS_4124 "Image HDX (.hdx)" + IDS_4125 "VHD à taille fixe (.vhd)" + IDS_4126 "VHD à taille dynamique (.vhd)" + IDS_4127 "VHD à différenciation (.vhd)" + IDS_4128 "Blocs grands (2 Mo)" + IDS_4129 "Blocs petits (512 Ko)" + IDS_4130 "Fichiers VHD (*.VHD)\0*.VHD\0Tous les fichiers (*.*)\0*.*\0" + IDS_4131 "Sélectionnez le VHD parent" + IDS_4132 "Il est possible que l'image parente a été modifié après la création de l'image à différenciation.\n\nIl est même possible que les fichiers de l'mage ont été déplacés ou copiés ou il existe un bogue dans le programme que a créé ce disque.\n\nVoulez-vous réparer l'horodatage?" + IDS_4133 "Les horodatages des disques parent et enfant ne correspondent pas" + IDS_4134 "Impossible de réparer l'horodatage du VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Désactivé" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Désactivé" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 Ko" + IDS_5889 "180 Ko" + IDS_5890 "320 Ko" + IDS_5891 "360 Ko" + IDS_5892 "640 Ko" + IDS_5893 "720 Ko" + IDS_5894 "1.2 Mo" + IDS_5895 "1.25 Mo" + IDS_5896 "1.44 Mo" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 Mo" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 Mo (ISO 10090)" + IDS_5903 "3.5"" 230 Mo (ISO 13963)" + IDS_5904 "3.5"" 540 Mo (ISO 15498)" + IDS_5905 "3.5"" 640 Mo (ISO 15498)" + IDS_5906 "3.5"" 1.3 Go (GigaMO)" + IDS_5907 "3.5"" 2.3 Go (GigaMO 2)" + IDS_5908 "5.25"" 600 Mo" + IDS_5909 "5.25"" 650 Mo" + IDS_5910 "5.25"" 1 Go" + IDS_5911 "5.25"" 1.3 Go" + + IDS_6144 "RPM précis" + IDS_6145 "Précision RPM de moins 1%" + IDS_6146 "Précision RPM de moins 1.5%" + IDS_6147 "Précision RPM de moins 2%" + + IDS_7168 "(Défaut du système)" +END +#define IDS_LANG_ENUS IDS_7168 + +// French (F.R.) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/hr-HR.rc b/src/win/languages/hr-HR.rc new file mode 100644 index 000000000..3cb8eb6d3 --- /dev/null +++ b/src/win/languages/hr-HR.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Croatian (hr-HR) resources + +#ifdef _WIN32 +LANGUAGE LANG_CROATIAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Radnje" + BEGIN + MENUITEM "&Tipkovnica zahtijeva hvatanje miša", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Desni CTRL je lijevi ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Ponovno pokretanje...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pauza", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "Iz&laz...", IDM_ACTION_EXIT + END + POPUP "&Pogled" + BEGIN + MENUITEM "&Sakrij statusni redak", IDM_VID_HIDE_STATUS_BAR + MENUITEM "&Sakrij alatni redak", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Prozor s promjenjivim veličinama", IDM_VID_RESIZE + MENUITEM "&Zapamtite veličinu i položaj", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Renderer" + BEGIN + MENUITEM "&SDL (Softver)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardver)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 jezgra)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Odrediti veličinu...", IDM_VID_SPECIFY_DIM + MENUITEM "&4:3 omjer prikaza", IDM_VID_FORCE43 + POPUP "&Faktor skaliranja prozora" + BEGIN + MENUITEM "&0,5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1,&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Metoda filtriranja" + BEGIN + MENUITEM "&Najbliža", IDM_VID_FILTER_NEAREST + MENUITEM "&Linearna", IDM_VID_FILTER_LINEAR + END + MENUITEM "&HiDPI skaliranje", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Cijelozaslonski način\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "&Način cijelozaslonskog rastezanja" + BEGIN + MENUITEM "&Razvuci na cijeli zaslona", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Kvadratni pikseli (zadrži omjer)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Cijelobrojno skaliranje", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA postavke" + BEGIN + MENUITEM "&Obrni boje zaslona VGA", IDM_VID_INVERT + POPUP "&Tip zaslona VGA" + BEGIN + MENUITEM "RGB u &boji", IDM_VID_GRAY_RGB + MENUITEM "&RGB u nijansama sive boje", IDM_VID_GRAY_MONO + MENUITEM "&Jantarni zaslon", IDM_VID_GRAY_AMBER + MENUITEM "&Zeleni zaslon", IDM_VID_GRAY_GREEN + MENUITEM "&Bijeli zaslon", IDM_VID_GRAY_WHITE + END + POPUP "&Vrsta konverzije nijansa sive boje" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Prosjek", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "&Višak slike CGA/PCjr/Tandy/EGA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "&Promjeni kontrast za crno-bijeli zaslon", IDM_VID_CGACON + END + MENUITEM "&Mediji", IDM_MEDIA + POPUP "&Alati" + BEGIN + MENUITEM "&Opcije...", IDM_CONFIG + MENUITEM "&Ažuriraj ikone statusnog redka", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Napravi &snimku zaslona\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Postavke...", IDM_PREFERENCES + MENUITEM "Omogući integraciju sa programom &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Pojačanje zvuka...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Z&apočni praćenje\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "&Svrši praćenje\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Pomoć" + BEGIN + MENUITEM "&Dokumentacija...", IDM_DOCS + MENUITEM "&O programu 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Postojeća slika...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Postojeća slika (&zaštićena od pisanja)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Snimi", IDM_CASSETTE_RECORD + MENUITEM "&Pokreni", IDM_CASSETTE_PLAY + MENUITEM "P&remotaj na početak", IDM_CASSETTE_REWIND + MENUITEM "&Preskoči do kraja", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Izbaci", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Slika...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Izbaci", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Postojeća slika...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Postojeća slika (&zaštićena od pisanja)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Izvozi u 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Izbaci", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Isključi zvuk", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Prazno", IDM_CDROM_EMPTY + MENUITEM "&Ponovo učitaj prethodnu sliku", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Slika", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Postojeća slika...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Postojeća slika (&zaštićena od pisanja)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Izbaci", IDM_ZIP_EJECT + MENUITEM "&Ponovo učitaj prethodnu sliku", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Postojeća slika...", IDM_MO_IMAGE_EXISTING + MENUITEM "Postojeća slika (&zaštićena od pisanja)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Izbaci", IDM_MO_EJECT + MENUITEM "&Ponovo učitaj prethodnu sliku", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Ciljni broj okvira u sekundi" + BEGIN + MENUITEM "&Sinkroniziraj s videom", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Odaberi shader...", IDM_VID_GL_SHADER + MENUITEM "&Ukloni shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Postavke" +#define STR_SND_GAIN "Pojačavanje zvuka" +#define STR_NEW_FLOPPY "Nova slika" +#define STR_CONFIG "Opcije" +#define STR_SPECIFY_DIM "Odredite glavne dimenzije prozora" + +#define STR_OK "U redu" +#define STR_CANCEL "Otkaži" +#define STR_GLOBAL "Spremite ove postavke kao &globalne zadane postavke" +#define STR_DEFAULT "Zadano" +#define STR_LANGUAGE "Jezik:" +#define STR_ICONSET "Paket ikona:" + +#define STR_GAIN "Pojačavanje" + +#define STR_FILE_NAME "Ime datoteke:" +#define STR_DISK_SIZE "Veličina diska:" +#define STR_RPM_MODE "Način broja okretaja:" +#define STR_PROGRESS "Napredak:" + +#define STR_WIDTH "Širina:" +#define STR_HEIGHT "Visina:" +#define STR_LOCK_TO_SIZE "Zaključajte na ovu veličinu" + +#define STR_MACHINE_TYPE "Tip sistema:" +#define STR_MACHINE "Sistem:" +#define STR_CONFIGURE "Namjesti" +#define STR_CPU_TYPE "Tip procesora:" +#define STR_CPU_SPEED "Brzina:" +#define STR_FPU "FPU uređaj:" +#define STR_WAIT_STATES "Stanja čekanja:" +#define STR_MB "MB" +#define STR_MEMORY "Memorija:" +#define STR_TIME_SYNC "Sinkronizacija vremena" +#define STR_DISABLED "Isključeno" +#define STR_ENABLED_LOCAL "Uključeno (lokalno vrijeme)" +#define STR_ENABLED_UTC "Uključeno (UTC)" +#define STR_DYNAREC "Dinamički rekompilator" + +#define STR_VIDEO "Video:" +#define STR_VOODOO "Voodoo grafika" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Miš:" +#define STR_JOYSTICK "Palica za igru:" +#define STR_JOY1 "Palica za igru 1..." +#define STR_JOY2 "Palica za igru 2..." +#define STR_JOY3 "Palica za igru 3..." +#define STR_JOY4 "Palica za igru 4..." + +#define STR_SOUND "Zvučna kartica:" +#define STR_MIDI_OUT "Izlazni uređaj MIDI:" +#define STR_MIDI_IN "Ulazni uređaj MIDI:" +#define STR_MPU401 "Samostalni MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Koristi FLOAT32 za zvuk" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Tip mreže:" +#define STR_PCAP "Uređaj PCap:" +#define STR_NET "Mrežna kartica:" + +#define STR_COM1 "Uređaj COM1:" +#define STR_COM2 "Uređaj COM2:" +#define STR_COM3 "Uređaj COM3:" +#define STR_COM4 "Uređaj COM4:" +#define STR_LPT1 "Uređaj LPT1:" +#define STR_LPT2 "Uređaj LPT2:" +#define STR_LPT3 "Uređaj LPT3:" +#define STR_LPT4 "Uređaj LPT4:" +#define STR_SERIAL1 "Serijska vrata 1" +#define STR_SERIAL2 "Serijska vrata 2" +#define STR_SERIAL3 "Serijska vrata 3" +#define STR_SERIAL4 "Serijska vrata 4" +#define STR_PARALLEL1 "Paralelna vrata 1" +#define STR_PARALLEL2 "Paralelna vrata 2" +#define STR_PARALLEL3 "Paralelna vrata 3" +#define STR_PARALLEL4 "Paralelna vrata 4" + +#define STR_HDC "Kontroler tvrdog diska:" +#define STR_FDC "Kontroler diskete:" +#define STR_IDE_TER "Tercijarni IDE kontroler" +#define STR_IDE_QUA "Kvaternarni IDE kontroler" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Kontroler 1:" +#define STR_SCSI_2 "Kontroler 2:" +#define STR_SCSI_3 "Kontroler 3:" +#define STR_SCSI_4 "Kontroler 4:" +#define STR_CASSETTE "Audio kaseta" + +#define STR_HDD "Tvrdi diskovi:" +#define STR_NEW "&Novi..." +#define STR_EXISTING "&Postojeći..." +#define STR_REMOVE "&Ukloni" +#define STR_BUS "Sabirnica:" +#define STR_CHANNEL "Kanal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Odredi..." +#define STR_SECTORS "Sektori:" +#define STR_HEADS "Glave:" +#define STR_CYLS "Cilindri:" +#define STR_SIZE_MB "Veličina (MB):" +#define STR_TYPE "Tip:" +#define STR_IMG_FORMAT "Format slike:" +#define STR_BLOCK_SIZE "Veličina slike:" + +#define STR_FLOPPY_DRIVES "Disketni pogoni:" +#define STR_TURBO "Turbo vrijemena" +#define STR_CHECKBPB "Provjeraj BPB" +#define STR_CDROM_DRIVES "CD-ROM pogoni:" +#define STR_CD_SPEED "Brzina:" + +#define STR_MO_DRIVES "MO pogoni:" +#define STR_ZIP_DRIVES "ZIP pogoni:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "Sat stvarnog vremena (RTC):" +#define STR_ISAMEM "Proširenje memorije ISA" +#define STR_ISAMEM_1 "Kartica 1:" +#define STR_ISAMEM_2 "Kartica 2:" +#define STR_ISAMEM_3 "Kartica 3:" +#define STR_ISAMEM_4 "Kartica 4:" +#define STR_BUGGER "Uređaj ISABugger" +#define STR_POSTCARD "Kartica POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Greška" + IDS_2050 "Fatalna greška" + IDS_2051 " - PAUSED" + IDS_2052 "Pritisnite Ctrl+Alt+PgDn za povratak u prozorski način rada." + IDS_2053 "Brzina" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP slike (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box nije mogao pronaći upotrebljive ROM datoteke.\n\nMolimte posjetite sknite paket s ROM datotekama i ekstrahirajte paket u ""roms"" mapu." + IDS_2057 "(prazno)" + IDS_2058 "ZIP slike (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Sve datoteke (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Uključeno" + IDS_2061 "Isključeno" + IDS_2062 "Sve slike (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0BOsnovne sektorske slike (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Površinske slike (*.86F)\0*.86F\0" + IDS_2063 "Sistem ""%hs"" nije dostupan jer ne postoje potrebni ROM-ovi u mapu roms/machines. Prebacivanje na dostupno računalo." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Video kartica ""%hs"" nije dostupna jer ne postoje potrebni ROM-ovi u mapu roms/video. Prebacivanje na dostupnu video karticu." + IDS_2065 "Sistem" + IDS_2066 "Video" + IDS_2067 "Ulazni uređaji" + IDS_2068 "Zvuk" + IDS_2069 "Mreža" + IDS_2070 "Vrata (COM & LPT)" + IDS_2071 "Kontroleri za diskove" + IDS_2072 "Tvrdi diskovi" + IDS_2073 "Floppy & CD-ROM pogoni" + IDS_2074 "Ostali uklonjivi uređaji" + IDS_2075 "Ostali periferni uređaji" + IDS_2076 "Površinske slike (*.86F)\0*.86F\0" + IDS_2077 "Kliknite da uhvatite miš" + IDS_2078 "Pritisnite F8+F12 za otpustanje miša" + IDS_2079 "Pritisnite F8+F12 ili srednji gumb miša za otpuštanje miša" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Nije moguće inicijalizirati FluidSynth" + IDS_2081 "Bus" + IDS_2082 "Datoteka" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Provjeri BPB" + IDS_2088 "KB" + IDS_2089 "Nije moguće inicijalizirati renderer." + IDS_2090 "Standard" + IDS_2091 "%i stanje čekanja" + IDS_2092 "Tip" + IDS_2093 "Postavljanje PCap-a nije uspjelo" + IDS_2094 "Nema PCap uređaja" + IDS_2095 "Nevažeći PCap uređaj" + IDS_2096 "Standardna palica za igru s 2 tipke" + IDS_2097 "Standardna palica za igru s 4 tipke" + IDS_2098 "Standardna palica za igru s 6 tipke" + IDS_2099 "Standardna palica za igru s 8 tipke" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Bez" + IDS_2104 "Nije moguće učitati ubrzivače tipkovnice." + IDS_2105 "Nije moguće registrirati neobrađeni unos." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Disketa %i (%s): %ls" + IDS_2109 "Sve slike (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Napredne sektorske slike (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Osnovne sektorske slike (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux slike (*.FDI)\0*.FDI\0Površinske slike (*.86F;*.MFM)\0*.86F;*.MFM\0Sve datoteke (*.*)\0*.*\0" + IDS_2110 "Nije moguće inicijalizirati FreeType" + IDS_2111 "Nije moguće inicijalizirati SDL, SDL2.dll je potrebno" + IDS_2112 "Jeste li sigurni da želite hard resetirati emulirani sistem?" + IDS_2113 "Jeste li sigurni da želite zatvoriti 86Box?" + IDS_2114 "Nije moguće inicijalizirati GhostScript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO slike (*.IM?;*.MDI)\0*.IM?;*.MDI\0Svi datoteke (*.*)\0*.*\0" + IDS_2117 "Dobrodošli u 86Box!" + IDS_2118 "Uunutarnji kontroler" + IDS_2119 "Izlazi" + IDS_2120 "Nisu pronađene ROM datoteke" + IDS_2121 "Želite li spremiti postavke?" + IDS_2122 "Ovo će napraviti hard resetiranje emuliranog sistema." + IDS_2123 "Spremaj" + IDS_2124 "O programu 86Box" + IDS_2125 "86Box verzija " EMU_VERSION + + IDS_2126 "Emulator starih računala\n\nAutori: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, i drugi.\n\nPreveo: dob205\n\nObjavljeno pod licencom GNU General Public License, verzija 2 ili novije. Za više informacija pogledajte datoteku LICENCE." + IDS_2127 "U redu" + IDS_2128 "Hardver nije dostupan" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Provjerite je li " LIB_NAME_PCAP " instaliran i jeste li na mreži, kompadibilnoj s " LIB_NAME_PCAP "." + IDS_2130 "Nevažeća konfiguracija" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " je potrebno za emuliranje ESC/P pisača." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " je potrebno za automatsku konverziju PostScript datoteke u PDF datoteke.\n\nSvi dokumenti poslani na generički PostScript pisač bit će spremljeni kao PostScript (.ps) datoteke." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " je potrebno za FluidSynth MIDI izlaz." + IDS_2134 "Ulazim u cijelozaslonski način" + IDS_2135 "Ne pokazi više ovu poruku" + IDS_2136 "Ne izlazi" + IDS_2137 "Resetiraj" + IDS_2138 "Ne resetiraj" + IDS_2139 "MO slike (*.IM?;*.MDI)\0*.IM?;*.MDI\0Sve datoteke (*.*)\0*.*\0" + IDS_2140 "CD-ROM slike (*.ISO;*.CUE)\0*.ISO;*.CUE\0Sve datoteke (*.*)\0*.*\0" + IDS_2141 "Konfiguracija uređaja %hs " + IDS_2142 "Ekran u stanju mirovanja" + IDS_2143 "OpenGL shaderi (*.GLSL)\0*.GLSL\0Sve datoteke (*.*)\0*.*\0" + IDS_2144 "OpenGL opcije" + IDS_2145 "Učitavate nepodržanu konfiguraciju" + IDS_2146 "Filtriranje tipa CPU-a na temelju odabranog sistema onemogućeno je za ovaj emulirani sistem.\n\nOvo omogućuje odabir procesora koji inače nisu kompatibilne s odabranog sistem. Međutim, možete naići na na nekompatibilnosti s BIOS-om sustava ili drugim softverom.\n\nOmogućavanje ove postavke nije službeno podržano i sva prijava o greškama mogu biti zatvorena kao ""invalid""." + IDS_2147 "Nastavi" + IDS_2148 "Audio kaseta: %s" + IDS_2149 "Slike audio kasete (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Sve datoteke (*.*)\0*.*\0" + IDS_2150 "Kaseta %i: %ls" + IDS_2151 "Slike kasete (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Sve datoteke (*.*)\0*.*\0" + IDS_2152 "Nije moguće inicijalizirati renderer" + IDS_2153 "Nije moguće inicijalizirati OpenGL (3.0 jezgra) renderer. Molimte koristite drugi renderer." + IDS_2154 "Nastavi" + IDS_2155 "Pauziraj" + IDS_2156 "Stisni Ctrl+Alt+Del" + IDS_2157 "Stisni Ctrl+Alt+Esc" + IDS_2158 "Ponovno pokretanje" + IDS_2159 "ACPI bazirano gašenje" + IDS_2160 "Postavke" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Tvrdi disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL ili ESDI CD-ROM pogoni nisu nikada postojali" + IDS_4100 "Prilagođeno..." + IDS_4101 "Prilagođeno (veliko)..." + IDS_4102 "Dodajte novi tvrdi disk" + IDS_4103 "Dodajte postojeći tvrdi disk" + IDS_4104 "HDI disk image datoteke ne mogu biti veće od 4 GB." + IDS_4105 "Slike tvrdog diska ne mogu biti veće od 127 GB." + IDS_4106 "Slike za tvrde diskove (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Sve datoteke (*.*)\0*.*\0" + IDS_4107 "Nije moguće pročitati datoteku" + IDS_4108 "Nije moguće napisati datoteku" + IDS_4109 "HDI ili HDX slike s veličinom sektora koja nije 512 kB nisu podržane." + IDS_4110 "USB nije još podržano" + IDS_4111 "Slika diska već postoji" + IDS_4112 "Molimte unesite važeći naziv datoteke." + IDS_4113 "Slika je stvorena" + IDS_4114 "Provjerite je li postoji datoteka i je li čitljiva." + IDS_4115 "Provjerite je li se datoteka sprema u mapu s dopuštenjima za pisanje." + IDS_4116 "Slika diska je prevelika" + IDS_4117 "Ne zaboravite stvoriti particije i formatirati ih na novom disku." + IDS_4118 "Odabrana datoteka bit će prebrisana. Jeste li sigurni da želite koristiti ovu daoteku?" + IDS_4119 "Nepodržana slika diska" + IDS_4120 "Prepiši" + IDS_4121 "Ne prepiši" + IDS_4122 "Slika neobrađenih podataka (.img)" + IDS_4123 "HDI slika (.hdi)" + IDS_4124 "HDX slika (.hdx)" + IDS_4125 "VHD fiksne veličine (.vhd)" + IDS_4126 "VHD dinamičke veličine (.vhd)" + IDS_4127 "Različiti VHD (.vhd)" + IDS_4128 "Veliki blokovi (2 MB)" + IDS_4129 "Mali blokovi (512 KB)" + IDS_4130 "VHD slike (*.VHD)\0*.VHD\0Sve datoteke (*.*)\0*.*\0" + IDS_4131 "Izaberi matičnu sliku VHD" + IDS_4132 "To bi moglo značiti da je matična slika promijenjena nakon što je stvorena različita slika.\n\nTo se također može dogoditi ako su slike premještene ili kopirane, ili greška u programu koji je stvorio ovaj disk.\n\nŽelite li popraviti vremenske oznake?" + IDS_4133 "Vremenske ozanke matične i poređenog diska ne odgovaraju." + IDS_4134 "Ne mogu popraviti vremensku oznaku slike VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Deaktivirano" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Deaktivirano" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1,2 MB" + IDS_5895 "1,25 MB" + IDS_5896 "1,44 MB" + IDS_5897 "DMF (1024 clusteri)" + IDS_5898 "DMF (2048 clusteri)" + IDS_5899 "2,88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3,5"" 128 MB (ISO 10090)" + IDS_5903 "3,5"" 230 MB (ISO 13963)" + IDS_5904 "3,5"" 540 MB (ISO 15498)" + IDS_5905 "3,5"" 640 MB (ISO 15498)" + IDS_5906 "3,5"" 1.3 GB (GigaMO)" + IDS_5907 "3,5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5,25"" 600 MB" + IDS_5909 "5,25"" 650 MB" + IDS_5910 "5,25"" 1 GB" + IDS_5911 "5,25"" 1.3 GB" + + IDS_6144 "Savršeni broj okretaja u minuti" + IDS_6145 "1% ispod savršenog broja okretaja" + IDS_6146 "1,5% ispod savršenog broja okretaja" + IDS_6147 "2% ispod savršenog broja okretaja" + + IDS_7168 "(Zadana postavka operativnog sustava)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Croatian (hr-HR) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/hu-HU.rc b/src/win/languages/hu-HU.rc new file mode 100644 index 000000000..7c2e1cf5e --- /dev/null +++ b/src/win/languages/hu-HU.rc @@ -0,0 +1,626 @@ +//////////////////////////////////////////////////////////////////////////// +// Hungarian resources +// +// Translated by Laci bá', 2021 +// + +//#define TRANSLATORS_NAME "Laci bá'" + +#ifdef _WIN32 +LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Művelet" + BEGIN + MENUITEM "A &billentyűzet elfogást igényel", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "A &jobb oldali CTRL a bal ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "Hardveres &újraindítás...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Szüneteltetés", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Kilépés...", IDM_ACTION_EXIT + END + POPUP "&Nézet" + BEGIN + MENUITEM "Állapotsor &elrejtése", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Átméretezhető ablak", IDM_VID_RESIZE + MENUITEM "Méret és pozíció &megjegyzése", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Megjelenítő" + BEGIN + MENUITEM "&SDL (Szoftveres)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardveres)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Méretek kézi megadása...", IDM_VID_SPECIFY_DIM + MENUITEM "&Rögzített 4:3 képarány", IDM_VID_FORCE43 + POPUP "&Ablak méretezési tényező" + BEGIN + MENUITEM "&0,5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1,&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Szűrési mód" + BEGIN + MENUITEM "&Szomszédos", IDM_VID_FILTER_NEAREST + MENUITEM "&Lineáris", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI méretezés", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Teljes képernyő\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Teljes képernyős &méretezés" + BEGIN + MENUITEM "&Nyújtás a teljes képernyőre", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Négyzetes képpontok (aránytartás)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Egész tényezős nagyítás", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA beállítások" + BEGIN + MENUITEM "&Invertált VGA kijelző", IDM_VID_INVERT + POPUP "VGA képernyő &típusa" + BEGIN + MENUITEM "RGB &színes", IDM_VID_GRAY_RGB + MENUITEM "&RGB szürkeárnyalatos", IDM_VID_GRAY_MONO + MENUITEM "&Gyömbér kijelző", IDM_VID_GRAY_AMBER + MENUITEM "&Zöld kijelző", IDM_VID_GRAY_GREEN + MENUITEM "&Fehér kijelző", IDM_VID_GRAY_WHITE + END + POPUP "Szürkéskála &konzerziós eljárás" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Átlag szerint", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA túlpásztázás", IDM_VID_OVERSCAN + MENUITEM "Kontraszt illesztése &monokróm kijelzőhöz", IDM_VID_CGACON + END + MENUITEM "&Média", IDM_MEDIA + POPUP "&Eszközök" + BEGIN + MENUITEM "&Konfigurálás...", IDM_CONFIG + MENUITEM "Állapotsori ikonok &frissítése", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "&Képernyőkép készítése\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Beállítások...", IDM_PREFERENCES + MENUITEM "&Discord integráció engedélyezése", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Hangerőszabályzó...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Nyomkövetés megkezdése\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Nyomkövetés befejezése\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Súgó" + BEGIN + MENUITEM "&Dokumentáció...", IDM_DOCS + MENUITEM "A 86Box &névjegye...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Meglévő képfájl &megnyitása...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Felvétel", IDM_CASSETTE_RECORD + MENUITEM "&Lejátszás", IDM_CASSETTE_PLAY + MENUITEM "&Visszatekerés az elejére", IDM_CASSETTE_REWIND + MENUITEM "&Előretekerés a végére", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "Kép&fájl...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Meglévő képfájl &megnyitása...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xportálás 86F formátumba...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Némítás", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Kiadás", IDM_CDROM_EMPTY + MENUITEM "Előző képfájl &újratöltése", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Meglévő képfájl &megnyitása...", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Meglévő képfájl &megnyitása...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "Kiadás", IDM_ZIP_EJECT + MENUITEM "Előző képfájl &újratöltése", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Új képfájl létrehozása...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Meglévő képfájl &megnyitása...", IDM_MO_IMAGE_EXISTING + MENUITEM "Meglévő képfájl megnyitása (&írásvédett)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "Kiadás", IDM_MO_EJECT + MENUITEM "Előző képfájl &újratöltése", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Cél &képkockasebesség" + BEGIN + MENUITEM "&Szinkronizálás a videóval ", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "Shader &kiválasztása...", IDM_VID_GL_SHADER + MENUITEM "Shader &eltávolítása", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Beállítások" +#define STR_SND_GAIN "Hangerőszabályzó" +#define STR_NEW_FLOPPY "Új képfájl létrehozása" +#define STR_CONFIG "Konfigurálás" +#define STR_SPECIFY_DIM "Főablak méreteinek megadása" + +#define STR_OK "OK" +#define STR_CANCEL "Mégse" +#define STR_GLOBAL "Beállítások mentése &globális alapértékként" +#define STR_DEFAULT "&Alapértelmezett" +#define STR_LANGUAGE "Nyelv:" +#define STR_ICONSET "Ikonkészlet:" + +#define STR_GAIN "Hangerő" + +#define STR_FILE_NAME "Fájlnév:" +#define STR_DISK_SIZE "Méret:" +#define STR_RPM_MODE "RPM-mód:" +#define STR_PROGRESS "Folyamat:" + +#define STR_WIDTH "Szélesség:" +#define STR_HEIGHT "Magasság:" +#define STR_LOCK_TO_SIZE "Rögzítés a megadott méretre" + +#define STR_MACHINE_TYPE "Géptípus:" +#define STR_MACHINE "Számítógép:" +#define STR_CONFIGURE "Beállítások..." +#define STR_CPU_TYPE "Processzor:" +#define STR_CPU_SPEED "Seb.:" +#define STR_FPU "FPU-egység:" +#define STR_WAIT_STATES "Várak. ciklusok:" +#define STR_MB "MB" +#define STR_MEMORY "Memória:" +#define STR_TIME_SYNC "Idő szinkronizáció" +#define STR_DISABLED "Letiltva" +#define STR_ENABLED_LOCAL "Engedélyezve (helyi idő)" +#define STR_ENABLED_UTC "Engedélyezve (UTC)" +#define STR_DYNAREC "Dinamikus újrafordítás" + +#define STR_VIDEO "Videokártya:" +#define STR_VOODOO "Voodoo-gyorsítókártya" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Egér:" +#define STR_JOYSTICK "Játékvezérlő:" +#define STR_JOY1 "Játékvez. 1..." +#define STR_JOY2 "Játékvez. 2..." +#define STR_JOY3 "Játékvez. 3..." +#define STR_JOY4 "Játékvez. 4..." + +#define STR_SOUND "Hangkártya:" +#define STR_MIDI_OUT "MIDI-kimenet:" +#define STR_MIDI_IN "MIDI-bemenet:" +#define STR_MPU401 "Különálló MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32 használata" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Hálózati típusa:" +#define STR_PCAP "PCap eszköz:" +#define STR_NET "Hálózati kártya:" + +#define STR_COM1 "COM1 eszköz:" +#define STR_COM2 "COM2 eszköz:" +#define STR_COM3 "COM3 eszköz:" +#define STR_COM4 "COM4 eszköz:" +#define STR_LPT1 "LPT1 eszköz:" +#define STR_LPT2 "LPT2 eszköz:" +#define STR_LPT3 "LPT3 eszköz:" +#define STR_LPT4 "LPT4 eszköz:" +#define STR_SERIAL1 "Soros port 1" +#define STR_SERIAL2 "Soros port 2" +#define STR_SERIAL3 "Soros port 3" +#define STR_SERIAL4 "Soros port 4" +#define STR_PARALLEL1 "Párhuzamos port 1" +#define STR_PARALLEL2 "Párhuzamos port 2" +#define STR_PARALLEL3 "Párhuzamos port 3" +#define STR_PARALLEL4 "Párhuzamos port 4" + +#define STR_HDC "Merevl.-vezérlő:" +#define STR_FDC "Floppy-vezérlő:" +#define STR_IDE_TER "Harmadlagos IDE-vezérlő" +#define STR_IDE_QUA "Negyedleges IDE-vezérlő" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Gazdaadapt. 1:" +#define STR_SCSI_2 "Gazdaadapt. 2:" +#define STR_SCSI_3 "Gazdaadapt. 3:" +#define STR_SCSI_4 "Gazdaadapt. 4:" +#define STR_CASSETTE "Magnókazetta" + +#define STR_HDD "Merevlemezek:" +#define STR_NEW "&Új..." +#define STR_EXISTING "&Megnyitás..." +#define STR_REMOVE "&Eltávolítás" +#define STR_BUS "Busz:" +#define STR_CHANNEL "Csatorna:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Kiválasztás..." +#define STR_SECTORS "Szektor:" +#define STR_HEADS "Fej:" +#define STR_CYLS "Cilinder:" +#define STR_SIZE_MB "Méret (MB):" +#define STR_TYPE "Típus:" +#define STR_IMG_FORMAT "Formátum:" +#define STR_BLOCK_SIZE "Blokkméret:" + +#define STR_FLOPPY_DRIVES "Floppy-meghajtók:" +#define STR_TURBO "Turbó időzítés" +#define STR_CHECKBPB "BPB ellenőrzés" +#define STR_CDROM_DRIVES "CD-ROM meghajtók:" +#define STR_CD_SPEED "Seb.:" + +#define STR_MO_DRIVES "MO-meghajtók:" +#define STR_ZIP_DRIVES "ZIP-meghajtók:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC (óra):" +#define STR_ISAMEM "ISA memóriabővítők" +#define STR_ISAMEM_1 "Kártya 1:" +#define STR_ISAMEM_2 "Kártya 2:" +#define STR_ISAMEM_3 "Kártya 3:" +#define STR_ISAMEM_4 "Kártya 4:" +#define STR_BUGGER "ISABugger eszköz" +#define STR_POSTCARD "POST kártya" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Hiba" + IDS_2050 "Végzetes hiba" + IDS_2051 " - PAUSED" + IDS_2052 "Használja a Ctrl+Alt+PgDn gombokat az ablakhoz való visszatéréshez." + IDS_2053 "Sebesség" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP-lemezképek (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "A 86Box nem talált használható ROM-képeket\n\nKérem töltse le a ROM készletet és bontsa ki a ""roms"" könyvtárba." + IDS_2057 "(üres)" + IDS_2058 "ZIP-lemezképek (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Minden fájl (*.*)\0*.*\0" + IDS_2059 "Turbó" + IDS_2060 "Bekapcsolva" + IDS_2061 "Kikapcsolva" + IDS_2062 "Minden képfájl (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Alapvető szektor képfájlok (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Felületi képfájlok (*.86F)\0*.86F\0" + IDS_2063 "A számítógép ""%hs"" nem elérhető a ""roms/machines"" mappából hiányzó ROM-képek miatt. Ehelyett egy másik gép kerül futtatásra." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "A videokártya ""%hs"" nem elérhető a ""roms/video"" mappából hiányzó ROM-képek miatt. Ehelyett egy másik kártya kerül futtatásra." + IDS_2065 "Számítógép" + IDS_2066 "Megjelenítő" + IDS_2067 "Beviteli eszközök" + IDS_2068 "Hang" + IDS_2069 "Hálózat" + IDS_2070 "Portok (COM és LPT)" + IDS_2071 "Tárolóvezérlők" + IDS_2072 "Merevlemezek" + IDS_2073 "Floppy és CD-ROM meghajtók" + IDS_2074 "Egyéb cserélhető tárolók" + IDS_2075 "Egyéb perifériák" + IDS_2076 "Felületi képfájlok (*.86F)\0*.86F\0" + IDS_2077 "Kattintson az egér elfogásához" + IDS_2078 "Nyomja meg az F8+F12-t az egér elengédéséhez" + IDS_2079 "Nyomja meg az F8+F12-t vagy a középső gombot az egér elengédéséhez" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Nem sikerült a FluidSynth inicializálása" + IDS_2081 "Busz" + IDS_2082 "Fájl" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "BPB ellenőrzése" + IDS_2088 "KB" + IDS_2089 "Nem sikerült inicializálni a videó megjelenítőt." + IDS_2090 "Alapértelmezett" + IDS_2091 "%i várakozási ciklus(ok)" + IDS_2092 "Típus" + IDS_2093 "Nem sikerült a PCap beállítása" + IDS_2094 "Nem találhatóak PCap eszközök" + IDS_2095 "Érvénytelen PCap eszköz" + IDS_2096 "Szabványos 2-gombos játékvezérlő(k)" + IDS_2097 "Szabványos 4-gombos játékvezérlő" + IDS_2098 "Szabványos 6-gombos játékvezérlő" + IDS_2099 "Szabványos 8-gombos játékvezérlő" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Nincs" + IDS_2104 "Nem lehet betölteni a billentyűzetgyorsítókat." + IDS_2105 "A közvetlen nyers bevitel regisztrálása nem sikerült." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Floppy %i (%s): %ls" + IDS_2109 "Minden képfájl (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Továbbfejlesztett szektor képek (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Alapvető szektor képek (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux képekfájlok (*.FDI)\0*.FDI\0Felületi képfájlok (*.86F;*.MFM)\0*.86F;*.MFM\0Minden fájl (*.*)\0*.*\0" + IDS_2110 "A FreeType inicializálása nem lehetséges" + IDS_2111 "Az SDL inicializálása nem lehetséges, az SDL2.dll fájl szükséges" + IDS_2112 "Biztosan szeretné újraindítani az emulált gépet?" + IDS_2113 "Biztos benne, hogy ki szeretne lépni a 86Box-ból?" + IDS_2114 "Nem sikerült inicializálni a Ghostscript-et" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO-képfájlok (*.IM?;*.MDI)\0*.IM?;*.MDI\0Minden fájl (*.*)\0*.*\0" + IDS_2117 "Üdvözli önt az 86Box!" + IDS_2118 "Integrált vezérlő" + IDS_2119 "Kilépés" + IDS_2120 "Nem találhatóak meg a ROM-képek" + IDS_2121 "Szeretné menteni a beállításokat?" + IDS_2122 "Ezzel hardveresen újraindítja az emulált gépet." + IDS_2123 "Mentés" + IDS_2124 "A 86Box névjegye" + IDS_2125 "86Box v" EMU_VERSION + IDS_2126 "Régi számítógépek emulátora\n\nFejlesztők: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nFordította: Laci bá'\n\nMegjelent a GNU General Public License v2 vagy újabb alatt. További információért lásd a LICENSE fájlt." + IDS_2127 "OK" + IDS_2128 "Hardver nem elérhető" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Győződjön meg hogy a(z) " LIB_NAME_PCAP " telepítve van és jelenleg a " LIB_NAME_PCAP "-kompatibilis kapcsolatot használja." + IDS_2130 "Érvénytelen konfiguráció" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " szükséges az ESC/P nyomtató emulációhoz." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " szükséges a PostScript fájlok PDF formátumba való automatikus konvertálásához.\n\nAz általános PostScript nyomtatóra küldött dokumentumok PostScript (.ps) fájlként kerülnek mentésre." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " szükséges a FluidSynth MIDI kimenethez." + IDS_2134 "Teljes képernyős módra váltás" + IDS_2135 "Ne jelenítse meg újra ezt az üzenetet " + IDS_2136 "Ne lépjen ki" + IDS_2137 "Újraindítás" + IDS_2138 "Ne indítsa újra" + IDS_2139 "MO-képfájlok (*.IM?;*.MDI)\0*.IM?;*.MDI\0Minden fájl (*.*)\0*.*\0" + IDS_2140 "CD-ROM-képek (*.ISO;*.CUE)\0*.ISO;*.CUE\0Minden fájl (*.*)\0*.*\0" + IDS_2141 "%hs eszközkonfiguráció" + IDS_2142 "Képernyő alvó módban" + IDS_2143 "OpenGL Shaderek (*.GLSL)\0*.GLSL\0Minden fájl (*.*)\0*.*\0" + IDS_2144 "OpenGL beállítások" + IDS_2145 "Egy nem támogatott konfigurációt tölt be" + IDS_2146 "A kiválasztott gépen alapuló CPU-típusszűrés le van tiltva ezen az emulált gépen.\n\nEz lehetővé teszi olyan CPU kiválasztását, amely egyébként nem kompatibilis a kiválasztott géppel. Előfordulhat azonban, hogy nem kompatibilis a gép BIOS-ával vagy más szoftverekkel.\n\nA beállítás engedélyezése hivatalosan nem támogatott, és a benyújtott hibajelentéseket érvénytelenként lezárhatjuk." + IDS_2147 "Folytatás" + IDS_2148 "Magnókazetta: %s" + IDS_2149 "Magnókazetta-képek (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Minden fájl (*.*)\0*.*\0" + IDS_2150 "ROM-kazetta %i: %ls" + IDS_2151 "ROM-kazetta képek (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Minden fájl (*.*)\0*.*\0" + IDS_2152 "Hiba történt a renderelő inicializálásakor" + IDS_2153 "Az OpenGL (3.0 Core) megjelenítő-motort nem sikerült inicializálni. Kérem használjon másik renderelőt." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Merevlemez (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL vagy ESDI CD-ROM meghajtók soha nem léteztek" + IDS_4100 "Egyéni..." + IDS_4101 "Egyéni (nagy)..." + IDS_4102 "Új merevlemez hozzáadása" + IDS_4103 "Meglévő merevlemez hozzáadása" + IDS_4104 "A HDI lemezképek nem lehetnek nagyobbak 4 GB-nál." + IDS_4105 "A lemezképek mérete nem haladhatja meg a 127 GB-ot." + IDS_4106 "Merevlemez-képfájlok (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Minden fájl (*.*)\0*.*\0" + IDS_4107 "A fájl nem olvasható" + IDS_4108 "A fájl nem írható" + IDS_4109 "Az 512-től eltérő szektorméretű HDI vagy HDX képek nem támogatottak." + IDS_4110 "Az USB még nem támogatott" + IDS_4111 "A lemezképfájl már létezik" + IDS_4112 "Adjon meg egy érvényes fájlnevet." + IDS_4113 "A lemezképfájl létrehozásra került" + IDS_4114 "Győződjön meg arról, hogy a fájl létezik és olvasható." + IDS_4115 "Győződjön meg arról, hogy a fájlt egy írható könyvtárba menti." + IDS_4116 "A lemezképfájl túl nagy" + IDS_4117 "Ne felejtse el particionálni és formázni az újonnan létrehozott meghajtót." + IDS_4118 "A kiválasztott fájl felülírásra kerül. Biztos, hogy ezt kívánja használni?" + IDS_4119 "Nem támogatott lemezkép" + IDS_4120 "Felülírás" + IDS_4121 "Ne írja felül" + IDS_4122 "Nyers lemezkép (.img)" + IDS_4123 "HDI-lemezkép (.hdi)" + IDS_4124 "HDX-lemezkép (.hdx)" + IDS_4125 "Rögzített méretű VHD (.vhd)" + IDS_4126 "Dinamikusan bővülő VHD (.vhd)" + IDS_4127 "Különbség-VHD (.vhd)" + IDS_4128 "Nagy blokkméret (2 MB)" + IDS_4129 "Kis blokkméret (512 KB)" + IDS_4130 "VHD fájlok (*.VHD)\0*.VHD\0Minden fájl (*.*)\0*.*\0" + IDS_4131 "Válassza ki a szülő VHD-t" + IDS_4132 "Ez azt jelentheti, hogy a szülőkép módosult az eltérő kép létrehozása után.\n\nEz akkor is előfordulhat, ha a képfájlokat áthelyezték vagy másolták, vagy a lemezt létrehozó program hibája miatt.\n\nSzeretné kijavítani az időbélyegeket?" + IDS_4133 "A szülő- és a gyermeklemez időbélyegei nem egyeznek" + IDS_4134 "Nem sikerült kijavítani a VHD időbélyegét." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Letiltva" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Letiltva" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (1024 klaszter)" + IDS_5898 "DMF (2048 klaszter)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "Tökéletes RPM" + IDS_6145 "1%-kal a tökéletes RPM alatt" + IDS_6146 "1.5%-kal a tökéletes RPM alatt" + IDS_6147 "2%-kal a tökéletes RPM alatt" + + IDS_7168 "(A rendszer nyelve)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Hungarian resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/it-IT.rc b/src/win/languages/it-IT.rc new file mode 100644 index 000000000..ca24daed4 --- /dev/null +++ b/src/win/languages/it-IT.rc @@ -0,0 +1,623 @@ +//////////////////////////////////////////////////////////////////////////// +// Italian (IT-it) resources + +#ifdef _WIN32 +LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN +#pragma code_page(65001) +#endif //_WIN32 + +// explorerdotexe +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Azione" + BEGIN + MENUITEM "&Tastiera richiede la cattura", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&CTRL destro è ALT sinistro", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Riavvia...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pausa", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "E&sci...", IDM_ACTION_EXIT + END + POPUP "&Visualizza" + BEGIN + MENUITEM "&Nascondi barra di stato", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Finestra ridimensionabile", IDM_VID_RESIZE + MENUITEM "R&icorda dimensioni e posizione", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Specifica dimensioni...", IDM_VID_SPECIFY_DIM + MENUITEM "F&orza display 4:3", IDM_VID_FORCE43 + POPUP "&Fattore scalare della finestra" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Metodo filtro" + BEGIN + MENUITEM "&Dal più vicino", IDM_VID_FILTER_NEAREST + MENUITEM "&Lineare", IDM_VID_FILTER_LINEAR + END + MENUITEM "Scala Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Schermo intero\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Modalità adattamento &schermo intero" + BEGIN + MENUITEM "&Adatta a schermo intero", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Pixel quadrati (mantiene l'aspetto)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Scala intera", IDM_VID_FS_INT + END + POPUP "Impostazioni E&GA/(S)VGA" + BEGIN + MENUITEM "&Invertire monitor VGA", IDM_VID_INVERT + POPUP "Schermi VGA &" + BEGIN + MENUITEM "RGB &Color", IDM_VID_GRAY_RGB + MENUITEM "&RGB Monocroma", IDM_VID_GRAY_MONO + MENUITEM "&Monitor ambra", IDM_VID_GRAY_AMBER + MENUITEM "&Monitor verde", IDM_VID_GRAY_GREEN + MENUITEM "&Monitor bianco", IDM_VID_GRAY_WHITE + END + POPUP "Conversione &scala grigia" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&AMedia", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Sovrascansione CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Cambia il contrasto per &display monocromatici", IDM_VID_CGACON + END + MENUITEM "&Dispositivi", IDM_MEDIA + POPUP "&Strumenti" + BEGIN + MENUITEM "&Impostazioni...", IDM_CONFIG + MENUITEM "&Aggiorna icone della barra di stato", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Cattura schermata\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferenze...", IDM_PREFERENCES + MENUITEM "Abilita &integrazione Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "Guadagno &suono...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Inizia traccia\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Ferma traccia\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&?" + BEGIN + MENUITEM "&Documentazione...", IDM_DOCS + MENUITEM "&Informazioni su 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nuova immagine...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Immagine esistente...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Immagine esistente (&protezione contro scrittura)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Registra", IDM_CASSETTE_RECORD + MENUITEM "R&iproduci", IDM_CASSETTE_PLAY + MENUITEM "Ri&avvolgi all'inizio", IDM_CASSETTE_REWIND + MENUITEM "A&vanti veloce alla fine", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Espelli", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Immagine...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Espelli", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nuova immagine...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Immagine esistente...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Immagine esistente (&protezione contro scrittura)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&sporta in 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Espelli", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Muto", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Espelli", IDM_CDROM_EMPTY + MENUITEM "&Ricarica l'immagine precedente", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Immagine", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nuova immagine...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Immagine esistente...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Immagine esistente (&protezione contro scrittura)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Espelli", IDM_ZIP_EJECT + MENUITEM "&Ricarica l'immagine precedente", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nuova immagine...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Immagine esistente...", IDM_MO_IMAGE_EXISTING + MENUITEM "Immagine esistente (&protezione contro scrittura)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Espelli", IDM_MO_EJECT + MENUITEM "&Ricarica l'immagine precedente", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Imposta obiettivo &fotogrammi" + BEGIN + MENUITEM "&Sincronizza col video", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 FPS", IDM_VID_GL_FPS_25 + MENUITEM "&30 FPS", IDM_VID_GL_FPS_30 + MENUITEM "&50 FPS", IDM_VID_GL_FPS_50 + MENUITEM "&60 FPS", IDM_VID_GL_FPS_60 + MENUITEM "&75 FPS", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Seleziona shader...", IDM_VID_GL_SHADER + MENUITEM "&Rimuovi shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferenze" +#define STR_SND_GAIN "Guadagno del suono" +#define STR_NEW_FLOPPY "Nuova immagine" +#define STR_CONFIG "Impostazioni" +#define STR_SPECIFY_DIM "Specifica dimensioni della finestra principale" + +#define STR_OK "OK" +#define STR_CANCEL "Annulla" +#define STR_GLOBAL "Salva queste impostazioni come &predefinite globali" +#define STR_DEFAULT "&Predefinito" +#define STR_LANGUAGE "Lingua:" +#define STR_ICONSET "Pacchetto di icone:" + +#define STR_GAIN "Guadagno" + +#define STR_FILE_NAME "Nome file:" +#define STR_DISK_SIZE "Dimensioni disco:" +#define STR_RPM_MODE "Modalità RPM:" +#define STR_PROGRESS "Progresso:" + +#define STR_WIDTH "Larghezza:" +#define STR_HEIGHT "Altezza:" +#define STR_LOCK_TO_SIZE "Blocca in queste dimensioni" + +#define STR_MACHINE_TYPE "Tipo di piastra madre:" +#define STR_MACHINE "Piastra madre:" +#define STR_CONFIGURE "Configura" +#define STR_CPU_TYPE "Tipo del CPU:" +#define STR_CPU_SPEED "Veloc.:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Stati di attesa:" +#define STR_MB "MB" +#define STR_MEMORY "Memoria:" +#define STR_TIME_SYNC "Sincronizzazione dell'ora" +#define STR_DISABLED "Disabilitata" +#define STR_ENABLED_LOCAL "Abilitata (ora locale)" +#define STR_ENABLED_UTC "Abilitata (UTC)" +#define STR_DYNAREC "Ricompilatore dinamico" + +#define STR_VIDEO "Video:" +#define STR_VOODOO "Grafica Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Mouse:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Scheda audio:" +#define STR_MIDI_OUT "Uscita MIDI:" +#define STR_MIDI_IN "Entrata MIDI:" +#define STR_MPU401 "MPU-401 autonomo" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Usa suono FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Tipo di rete:" +#define STR_PCAP "Dispositivo PCap:" +#define STR_NET "Scheda di rete:" + +#define STR_COM1 "Dispositivo COM1:" +#define STR_COM2 "Dispositivo COM2:" +#define STR_COM3 "Dispositivo COM3:" +#define STR_COM4 "Dispositivo COM4:" +#define STR_LPT1 "Dispositivo LPT1:" +#define STR_LPT2 "Dispositivo LPT2:" +#define STR_LPT3 "Dispositivo LPT3:" +#define STR_LPT4 "Dispositivo LPT4:" +#define STR_SERIAL1 "Porta seriale 1" +#define STR_SERIAL2 "Porta seriale 2" +#define STR_SERIAL3 "Porta seriale 3" +#define STR_SERIAL4 "Porta seriale 4" +#define STR_PARALLEL1 "Porta parallela 1" +#define STR_PARALLEL2 "Porta parallela 2" +#define STR_PARALLEL3 "Porta parallela 3" +#define STR_PARALLEL4 "Porta parallela 4" + +#define STR_HDC "Controller HD:" +#define STR_FDC "Controller FD:" +#define STR_IDE_TER "Controller IDE terziario" +#define STR_IDE_QUA "Controller IDE quaternario" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controller 1:" +#define STR_SCSI_2 "Controller 2:" +#define STR_SCSI_3 "Controller 3:" +#define STR_SCSI_4 "Controller 4:" +#define STR_CASSETTE "Cassetta" + +#define STR_HDD "Hard disk:" +#define STR_NEW "&Nuovo..." +#define STR_EXISTING "&Esistente..." +#define STR_REMOVE "&Rimouvi" +#define STR_BUS "Bus:" +#define STR_CHANNEL "Canale:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Specifica..." +#define STR_SECTORS "Settori:" +#define STR_HEADS "Testine:" +#define STR_CYLS "Cilindri:" +#define STR_SIZE_MB "Dimensioni (MB):" +#define STR_TYPE "Tipo:" +#define STR_IMG_FORMAT "Formato immagine:" +#define STR_BLOCK_SIZE "Dimensioni blocco:" + +#define STR_FLOPPY_DRIVES "Unità floppy:" +#define STR_TURBO "Turbo" +#define STR_CHECKBPB "Verifica BPB" +#define STR_CDROM_DRIVES "Unità CD-ROM:" +#define STR_CD_SPEED "Veloc.:" + +#define STR_MO_DRIVES "Unità magneto-ottiche:" +#define STR_ZIP_DRIVES "Unità ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "RTC ISA:" +#define STR_ISAMEM "Espansione memoria ISA" +#define STR_ISAMEM_1 "Scheda 1:" +#define STR_ISAMEM_2 "Scheda 2:" +#define STR_ISAMEM_3 "Scheda 3:" +#define STR_ISAMEM_4 "Scheda 4:" +#define STR_BUGGER "Dispositivo ISABugger" +#define STR_POSTCARD "Scheda POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Errore" + IDS_2050 "Errore fatale" + IDS_2051 " - PAUSED" + IDS_2052 "Usa Ctrl+Alt+PgDn per tornare alla modalità finestra." + IDS_2053 "Velocità" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Immagini ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box non può trovare immagini ROM utilizzabili.\n\nPlease download a ROM set and extract it into the ""roms"" directory." + IDS_2057 "(empty)" + IDS_2058 "Immagini ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Tutti i file (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Acceso" + IDS_2061 "Spento" + IDS_2062 "Tutte le immagini (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Immagini di settori base (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Immagini di superficie (*.86F)\0*.86F\0" + IDS_2063 "La macchina ""%hs"" non è disponibile a causa di immagini ROM mancanti nella directory roms/machines. Cambiando ad una macchina disponibile." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "La scheda video ""%hs"" non è disponibile a causa di immagini ROM mancanti nella directory roms/video. Cambiando ad una scheda video disponibile." + IDS_2065 "Piastra madre" + IDS_2066 "Schermo" + IDS_2067 "Dispositivi di entrata" + IDS_2068 "Audio" + IDS_2069 "Rete" + IDS_2070 "Porte (COM & LPT)" + IDS_2071 "Controller memoria" + IDS_2072 "Hard disk" + IDS_2073 "Unità CD-ROM e Floppy" + IDS_2074 "Altri dispositivi rimuovibili" + IDS_2075 "Altre periferiche" + IDS_2076 "Immagini di superficie (*.86F)\0*.86F\0" + IDS_2077 "Fare clic per catturare mouse" + IDS_2078 "Premi F8+F12 per rilasciare il mouse" + IDS_2079 "Premi F8+F12 o pulsante centrale per rilasciare il mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Impossibile inizializzare FluidSynth" + IDS_2081 "Bus" + IDS_2082 "File" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Verifica BPB" + IDS_2088 "KB" + IDS_2089 "Impossibile inizializzare il renderer video." + IDS_2090 "Predefinito" + IDS_2091 "%i stati d'attesa" + IDS_2092 "Tipo" + IDS_2093 "Impossibile impostare PCap" + IDS_2094 "Nessun dispositivo PCap trovato" + IDS_2095 "Dispositivo PCap invalido" + IDS_2096 "Joystick comune da 2 pulsanti" + IDS_2097 "Joystick comune da 4 pulsanti" + IDS_2098 "Joystick comune da 6 pulsanti" + IDS_2099 "Joystick comune da 8 pulsanti" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Nessuno" + IDS_2104 "Impossibile caricare gli acceleratori da tastiera." + IDS_2105 "Impossibile registrare input raw." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Floppy %i (%s): %ls" + IDS_2109 "Tutte le immagini (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Immagini da settori avanzati (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Imagini da settori basilari (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Immagini flusso (*.FDI)\0*.FDI\0Immagini da superficie (*.86F;*.MFM)\0*.86F;*.MFM\0Tutti i file (*.*)\0*.*\0" + IDS_2110 "Impossibile inizializzare FreeType" + IDS_2111 "Impossibile inizializzare SDL, SDL2.dll è necessario" + IDS_2112 "Sei sicuro di voler riavviare la macchina emulata?" + IDS_2113 "Sei sicuro di voler uscire da 86Box?" + IDS_2114 "Impossibile inizializzare Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "Immagini MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0Tutti i file (*.*)\0*.*\0" + IDS_2117 "Benvenuti in 86Box!" + IDS_2118 "Controller interno" + IDS_2119 "Esci" + IDS_2120 "Nessune immagini ROM trovate" + IDS_2121 "Vuole salvare queste impostazioni?" + IDS_2122 "Questo riavvierà la macchina emulata." + IDS_2123 "Salva" + IDS_2124 "Informazioni su 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Un emulatore di computer vecchi\n\nAutori: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nTradotto da: explorerdotexe\n\nRilasciato sotto la Licenza Pubblica GNU versione 2 o dopo. Vedi LICENSE per maggior informazioni." + IDS_2127 "OK" + IDS_2128 "Hardware non disponibile" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Controlla se " LIB_NAME_PCAP " è installato e che tu sia connesso ad una connessione " LIB_NAME_PCAP " compatibile." + IDS_2130 "Configurazione invalida" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " è richesto per l'emuazione di stampanti ESC/P." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " è richiesto per la conversione automatica di file PostScript a file PDF.\n\nQualsiasi documento mandato alla stampante generica PostScript sarà salvato come file PostScript. (.ps)" +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " è richiesto per l'output FluidSynth MIDI." + IDS_2134 "Entrando nella modalità schermo intero" + IDS_2135 "Non mostrare più questo messaggio" + IDS_2136 "Non uscire" + IDS_2137 "Riavvia" + IDS_2138 "Non riavviare" + IDS_2139 "Immagini MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0Tutti i file (*.*)\0*.*\0" + IDS_2140 "Immagini CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Tutti i file (*.*)\0*.*\0" + IDS_2141 "Configurazione del dispositivo %hs" + IDS_2142 "Monitor in modalità riposo" + IDS_2143 "Shader OpenGL (*.GLSL)\0*.GLSL\0Tutti i file (*.*)\0*.*\0" + IDS_2144 "Impostazioni OpenGL" + IDS_2145 "Stai caricando una configurazione non supportata" + IDS_2146 "Il filtraggio della tipologia di CPU è disabilitato per la macchina selezionata.\n\nQuesto lo rende possibile scegliere un CPU che è altrimenti incompatibile con la macchina selezionata. Tuttavia, portresti incorrere in incompatibilità con il BIOS della macchina o altri programmi. \n\nL'abilitare di questa impostazione non è ufficialmente supportato e tutte le segnalazioni di errori saranno considerate invalide." + IDS_2147 "Continua" + IDS_2148 "Cassetta: %s" + IDS_2149 "Immagini cassetta (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Tutti i file (*.*)\0*.*\0" + IDS_2150 "Cartuccia %i: %ls" + IDS_2151 "Immagini cartuccia (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Tutti i file (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Hard disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "Le unità CD-ROM MFM/RLL o ESDI non sono mai esistite." + IDS_4100 "Personalizzata..." + IDS_4101 "Personalizzata (grande)..." + IDS_4102 "Aggiungi un nuovo disco rigido" + IDS_4103 "Aggiungi un disco rigido esistente" + IDS_4104 "Le immagini HDI non possono essere più grandi di 4 GB." + IDS_4105 "Le immmagini disco non possono essere più grandi di 127 GB." + IDS_4106 "Immagini disco rigido (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Tutti i file (*.*)\0*.*\0" + IDS_4107 "Impossibile leggere il file" + IDS_4108 "Impossibile scrivere al file" + IDS_4109 "Le immagini HDI o HDX con settori di dimensioni diverse da 512 non sono supportati." + IDS_4110 "USB non è ancora supportato" + IDS_4111 "Immagine disco già esiste" + IDS_4112 "Specifica un nome file valido." + IDS_4113 "Immagine disco creata" + IDS_4114 "Controlla che il file esiste e che sia leggibile." + IDS_4115 "Controlla che il file viene salvato ad un percorso con diritti di scrittura" + IDS_4116 "Immagine disco troppo grande" + IDS_4117 "Ricordati di partizionare e formattare il disco appena creato." + IDS_4118 "Il file selezionato sarà sovrascritto, sei sicuro di volerlo usare?" + IDS_4119 "Immagine disco non supportata" + IDS_4120 "Sovrascrivi" + IDS_4121 "Non sovrascrivere" + IDS_4122 "Immagine raw (.img)" + IDS_4123 "Immagine HDI (.hdi)" + IDS_4124 "Immagine HDX (.hdx)" + IDS_4125 "VHD di dimensioni fisse (.vhd)" + IDS_4126 "VHD di dimensioni dinamiche (.vhd)" + IDS_4127 "VHD differenziato (.vhd)" + IDS_4128 "Blocchi larghi (2 MB)" + IDS_4129 "Blocchi piccoli (512 KB)" + IDS_4130 "File VHD (*.VHD)\0*.VHD\0Tutti i file (*.*)\0*.*\0" + IDS_4131 "Seleziona il VHD padre." + IDS_4132 "Questo potrebbe significare che l'immagine padre sia stata modificata dopo la creazione dell'immagine di differenziazione.\n\nPuò anche succedere se i file immagini sono stati spostati o copiati, o da un errore nel programma che ha creato questo disco.\n\nVuoi aggiustare le marcature di tempo?" + IDS_4133 "Le marcature di tempo padre e figlio non corrispondono" + IDS_4134 "Impossibile aggiustare marcature di tempo VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Disabilitato" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Disabilitato" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "RPM perfette" + IDS_6145 "RPM 1% sotto perfezione" + IDS_6146 "RPM 1.5% sotto perfezione" + IDS_6147 "RPM 2% sotto perfezione" + + IDS_7168 "(Predefinito del sistema)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Italian (IT-it) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/ja-JP.rc b/src/win/languages/ja-JP.rc new file mode 100644 index 000000000..18017bfb4 --- /dev/null +++ b/src/win/languages/ja-JP.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Japanese resources + +#ifdef _WIN32 +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "動作(&A)" + BEGIN + MENUITEM "キーボードはキャプチャが必要(&K)", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "右CTRLを左ALTへ(&R)", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "ハードリセット(&H)...", IDM_ACTION_HRESET + MENUITEM "Ctrl+Alt+Del(&C)\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+Esc(&E)", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "一時停止(&P)", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "終了(&X)...", IDM_ACTION_EXIT + END + POPUP "表示(&V)" + BEGIN + MENUITEM "ステータスバーを隠す(&H)", IDM_VID_HIDE_STATUS_BAR + MENUITEM "ツールバーを隠す(&T)", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "ウィンドウのサイズをリサイズ可能(&R)", IDM_VID_RESIZE + MENUITEM "ウィンドウのサイズと位置を記憶(&E)", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "レンダラー(&N)" + BEGIN + MENUITEM "SDL (ソフトウェア)(&S)", IDM_VID_SDL_SW + MENUITEM "SDL (ハードウェア)(&H)", IDM_VID_SDL_HW + MENUITEM "SDL (OpenGL)(&O)", IDM_VID_SDL_OPENGL + MENUITEM "OpenGL (3.0コア)(&G)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "VNC(&V)", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "ウィンドウのサイズを指定...", IDM_VID_SPECIFY_DIM + MENUITEM "4:3アスペクト比を固定(&O)", IDM_VID_FORCE43 + POPUP "ウィンドウの表示倍率(&W)" + BEGIN + MENUITEM "0.5x(&0)", IDM_VID_SCALE_1X + MENUITEM "1x(&1)", IDM_VID_SCALE_2X + MENUITEM "1.5x(&5)", IDM_VID_SCALE_3X + MENUITEM "2x(&2)", IDM_VID_SCALE_4X + END + POPUP "フィルター方式" + BEGIN + MENUITEM "最近傍補間(&N)", IDM_VID_FILTER_NEAREST + MENUITEM "線形補間(&L)", IDM_VID_FILTER_LINEAR + END + MENUITEM "HiDPIスケーリング(&D)", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "フルスクリーン(&F)\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "フルスクリーンのスケール(&S)" + BEGIN + MENUITEM "フルスクリーンに拡大(&F)", IDM_VID_FS_FULL + MENUITEM "4:3(&4)", IDM_VID_FS_43 + MENUITEM "正方形ピクセル(アスペクト比を維持)(&S)", IDM_VID_FS_KEEPRATIO + MENUITEM "整数倍(&I)", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGAの設定" + BEGIN + MENUITEM "色を反転(&I)", IDM_VID_INVERT + POPUP "画面タイプ(&T)" + BEGIN + MENUITEM "RGB(カラー)(&C)", IDM_VID_GRAY_RGB + MENUITEM "RGB(グレースケール)(&R)", IDM_VID_GRAY_MONO + MENUITEM "モニター(琥珀色)(&A)", IDM_VID_GRAY_AMBER + MENUITEM "モニター(緑色)(&G)", IDM_VID_GRAY_GREEN + MENUITEM "モニター(白色)(&W)", IDM_VID_GRAY_WHITE + END + POPUP "グレースケール変換タイプ(&C)" + BEGIN + MENUITEM "BT601 (NTSC/PAL)(&6)", IDM_VID_GRAYCT_601 + MENUITEM "BT709 (HDTV)(&7)", IDM_VID_GRAYCT_709 + MENUITEM "平均(&A)", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/EGA/(S)VGAオーバースキャン(&G)", IDM_VID_OVERSCAN + MENUITEM "単色モニター用コントラストを変更(&M)", IDM_VID_CGACON + END + MENUITEM "メディア(&M)", IDM_MEDIA + POPUP "ツール(&T)" + BEGIN + MENUITEM "設定(&S)...", IDM_CONFIG + MENUITEM "ステータスバーのアイコンを更新(&U)", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "スクリーンショットを撮る(&C)\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "環境設定(&P)...", IDM_PREFERENCES + MENUITEM "Discordとの連携機能(&D)", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "音量を調節(&G)...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "トレース開始\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "トレース終了\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "ヘルプ(&H)" + BEGIN + MENUITEM "ドキュメント(&D)...", IDM_DOCS + MENUITEM "86Boxのバージョン情報(&A)...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新規イメージ(&N)...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "既存のイメージを開く(&E)...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "既存のイメージを開く(書き込み保護)(&W)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "録音(&R)", IDM_CASSETTE_RECORD + MENUITEM "再生(&P)", IDM_CASSETTE_PLAY + MENUITEM "冒頭に巻き戻す(&R)", IDM_CASSETTE_REWIND + MENUITEM "最後まで早送り(&F)", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "取り出す(&J)", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "イメージ(&I)...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "取り出す(&J)", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新規イメージ(&N)...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "既存のイメージを開く(&E)...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "既存のイメージを開く(書き込み保護)(&W)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "86Fイメージにエクスポート(&X)...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "取り出す(&J)", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "ミュート(&M)", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "空(&M)", IDM_CDROM_EMPTY + MENUITEM "前のイメージを再読み込み(&R)", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "イメージ(&I)", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新規イメージ(&N)...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "既存のイメージを開く(&E)...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "既存のイメージを開く(書き込み保護)(&W)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "取り出す(&J)", IDM_ZIP_EJECT + MENUITEM "前のイメージを再読み込み(&R)", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新規イメージ(&N)...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "既存のイメージを開く(&E)...", IDM_MO_IMAGE_EXISTING + MENUITEM "既存のイメージを開く(書き込み保護)(&W)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "取り出す(&J)", IDM_MO_EJECT + MENUITEM "前のイメージを再読み込み(&R)", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "目標フレームレート(&F)" + BEGIN + MENUITEM "ビデオと同期(&S)", IDM_VID_GL_FPS_BLITTER + MENUITEM "25 fps(&2)", IDM_VID_GL_FPS_25 + MENUITEM "30 fps(&3)", IDM_VID_GL_FPS_30 + MENUITEM "50 fps(&5)", IDM_VID_GL_FPS_50 + MENUITEM "60 fps(&6)", IDM_VID_GL_FPS_60 + MENUITEM "75 fps(&7)", IDM_VID_GL_FPS_75 + END + MENUITEM "垂直同期(VSync)(&V)", IDM_VID_GL_VSYNC + MENUITEM "シェーダーを選択(&S)...", IDM_VID_GL_SHADER + MENUITEM "シェーダーを削除(&R)", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "環境設定" +#define STR_SND_GAIN "音量ゲイン" +#define STR_NEW_FLOPPY "新規のイメージ" +#define STR_CONFIG "設定" +#define STR_SPECIFY_DIM "メインウィンドウのサイズ指定" + +#define STR_OK "OK" +#define STR_CANCEL "キャンセル" +#define STR_GLOBAL "これらの設定をグローバル既定値として保存する(&G)" +#define STR_DEFAULT "既定値(&D)" +#define STR_LANGUAGE "言語:" +#define STR_ICONSET "アイコンセット:" + +#define STR_GAIN "ゲイン値" + +#define STR_FILE_NAME "ファイル名:" +#define STR_DISK_SIZE "ディスクサイズ:" +#define STR_RPM_MODE "回転数モード:" +#define STR_PROGRESS "進行状況:" + +#define STR_WIDTH "幅:" +#define STR_HEIGHT "高さ:" +#define STR_LOCK_TO_SIZE "このサイズをロックする" + +#define STR_MACHINE_TYPE "マシンタイプ:" +#define STR_MACHINE "マシン:" +#define STR_CONFIGURE "設定" +#define STR_CPU_TYPE "CPUタイプ:" +#define STR_CPU_SPEED "速度:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "待機状態:" +#define STR_MB "MB" +#define STR_MEMORY "メモリ:" +#define STR_TIME_SYNC "時刻同期機能" +#define STR_DISABLED "無効にする" +#define STR_ENABLED_LOCAL "有効にする (現地時間)" +#define STR_ENABLED_UTC "有効にする (UTC)" +#define STR_DYNAREC "動的リコンパイラ" + +#define STR_VIDEO "ビデオカード:" +#define STR_VOODOO "Voodooグラフィック" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "マウス:" +#define STR_JOYSTICK "ジョイスティック:" +#define STR_JOY1 "ジョイスティック1..." +#define STR_JOY2 "ジョイスティック2..." +#define STR_JOY3 "ジョイスティック3..." +#define STR_JOY4 "ジョイスティック4..." + +#define STR_SOUND "サウンドカード:" +#define STR_MIDI_OUT "MIDI出力デバイス:" +#define STR_MIDI_IN "MIDI入力デバイス:" +#define STR_MPU401 "独立型MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32サウンドを使用する" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "ネットワークタイプ:" +#define STR_PCAP "PCapデバイス:" +#define STR_NET "ネットワークアダプター:" + +#define STR_COM1 "COM1デバイス:" +#define STR_COM2 "COM2デバイス:" +#define STR_COM3 "COM3デバイス:" +#define STR_COM4 "COM4デバイス:" +#define STR_LPT1 "LPT1デバイス:" +#define STR_LPT2 "LPT2デバイス:" +#define STR_LPT3 "LPT3デバイス:" +#define STR_LPT4 "LPT4デバイス:" +#define STR_SERIAL1 "シリアルポート1" +#define STR_SERIAL2 "シリアルポート2" +#define STR_SERIAL3 "シリアルポート3" +#define STR_SERIAL4 "シリアルポート4" +#define STR_PARALLEL1 "パラレルポート1" +#define STR_PARALLEL2 "パラレルポート2" +#define STR_PARALLEL3 "パラレルポート3" +#define STR_PARALLEL4 "パラレルポート4" + +#define STR_HDC "HDコントローラー:" +#define STR_FDC "FDコントローラー:" +#define STR_IDE_TER "第三のIDEコントローラー" +#define STR_IDE_QUA "第四のIDEコントローラー" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "コントローラー1:" +#define STR_SCSI_2 "コントローラー2:" +#define STR_SCSI_3 "コントローラー3:" +#define STR_SCSI_4 "コントローラー4:" +#define STR_CASSETTE "カセット" + +#define STR_HDD "ハードディスク:" +#define STR_NEW "新規(&N)..." +#define STR_EXISTING "既定(&E)..." +#define STR_REMOVE "除去(&R)" +#define STR_BUS "バス:" +#define STR_CHANNEL "チャンネル:" +#define STR_ID "ID:" + +#define STR_SPECIFY "参照(&S)..." +#define STR_SECTORS "セクター:" +#define STR_HEADS "ヘッド:" +#define STR_CYLS "シリンダー:" +#define STR_SIZE_MB "サイズ(MB):" +#define STR_TYPE "タイプ:" +#define STR_IMG_FORMAT "イメージ形式:" +#define STR_BLOCK_SIZE "ブロックサイズ:" + +#define STR_FLOPPY_DRIVES "フロッピードライブ:" +#define STR_TURBO "高速タイミング" +#define STR_CHECKBPB "BPBをチェック" +#define STR_CDROM_DRIVES "CD-ROMドライブ:" +#define STR_CD_SPEED "速度:" + +#define STR_MO_DRIVES "光磁気ドライブ:" +#define STR_ZIP_DRIVES "ZIPドライブ:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTCカード:" +#define STR_ISAMEM "ISAメモリー拡張カード" +#define STR_ISAMEM_1 "カード1:" +#define STR_ISAMEM_2 "カード2:" +#define STR_ISAMEM_3 "カード3:" +#define STR_ISAMEM_4 "カード4:" +#define STR_BUGGER "ISABuggerデバイス" +#define STR_POSTCARD "POSTカード" + +#define FONT_SIZE 9 +#define FONT_NAME "Meiryo UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "エラー" + IDS_2050 "致命的なエラー" + IDS_2051 " - 一時停止" + IDS_2052 "Ctrl+Alt+PgDnでウィンドウモードに戻ります。" + IDS_2053 "速度" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIPイメージ (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Boxで使用可能なROMイメージが見つかりませんでした。\n\nROMセットをダウンロードして、「roms」ディレクトリに解凍してください。" + IDS_2057 "(空)" + IDS_2058 "ZIPイメージ (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0すべてのファイル (*.*)\0*.*\0" + IDS_2059 "高速" + IDS_2060 "オン" + IDS_2061 "オフ" + IDS_2062 "すべてのイメージ (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0基本的なセクターイメージ (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0表面イメージ (*.86F)\0*.86F\0" + IDS_2063 "roms/machinesディレクトリにROMがないため、マシン「%hs」は使用できません。使用可能なマシンに切り替えます。" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "roms/videoディレクトリにROMがないため、ビデオカード「%hs」は使用できません。使用可能なビデオカードに切り替えます。" + IDS_2065 "マシン" + IDS_2066 "画面表示" + IDS_2067 "入力デバイス" + IDS_2068 "サウンド" + IDS_2069 "ネットワーク" + IDS_2070 "ポート (COM & LPT)" + IDS_2071 "ストレージコントローラ" + IDS_2072 "ハードディスク" + IDS_2073 "フロッピー/CD-ROMドライブ" + IDS_2074 "その他のリムーバブルデバイス" + IDS_2075 "その他の周辺装置" + IDS_2076 "表面イメージ (*.86F)\0*.86F\0" + IDS_2077 "クリックするとマウスをキャプチャします" + IDS_2078 "F8+F12キーでマウスを解放します" + IDS_2079 "F8+F12キーまたは中ボタンでマウスを解放します" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "FluidSynthが初期化できません" + IDS_2081 "バス" + IDS_2082 "ファイル" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "BPBをチェック" + IDS_2088 "KB" + IDS_2089 "ビデオレンダラーが初期化できません。" + IDS_2090 "既定値" + IDS_2091 "%iつの待機状態" + IDS_2092 "タイプ" + IDS_2093 "PCapのセットアップに失敗しました" + IDS_2094 "PCapデバイスがありません" + IDS_2095 "不正なPCapデバイスです" + IDS_2096 "標準ジョイスティック(2ボタン)" + IDS_2097 "標準ジョイスティック(4ボタン)" + IDS_2098 "標準ジョイスティック(6ボタン)" + IDS_2099 "標準ジョイスティック(8ボタン)" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "なし" + IDS_2104 "キーボードアクセラレータを読み込めません。" + IDS_2105 "生の入力が登録できません。" + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "フロッピー %i (%s): %ls" + IDS_2109 "すべてのイメージ (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0アドバンスドセクターイメージ (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0基本セクターイメージ (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0フラックスイメージ (*.FDI)\0*.FDI\0表面イメージ (*.86F;*.MFM)\0*.86F;*.MFM\0すべてのファイル (*.*)\0*.*\0" + IDS_2110 "FreeTypeが初期化できません" + IDS_2111 "SDLが初期化できません。SDL2.dllが必要です" + IDS_2112 "使用中のマシンをハードリセットしますか?" + IDS_2113 "86Boxを終了しますか?" + IDS_2114 "Ghostscriptが初期化できません" + IDS_2115 "光磁気 %i (%ls): %ls" + IDS_2116 "光磁気イメージ (*.IM?;*.MDI)\0*.IM?;*.MDI\0すべてのファイル (*.*)\0*.*\0" + IDS_2117 "86Boxへようこそ!" + IDS_2118 "内蔵コントローラー" + IDS_2119 "終了" + IDS_2120 "ROMが見つかりません" + IDS_2121 "設定を保存しますか?" + IDS_2122 "保存すると使用中のマシンがハードリセットされます。" + IDS_2123 "保存" + IDS_2124 "86Boxのバージョン情報" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "古いパソコンのエミュレーター\n\n著者: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nGNU General Public License version 2以降でリリースされています。詳しくは LICENSE をご覧ください。" + IDS_2127 "OK" + IDS_2128 "ハードウェアが利用できません" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 LIB_NAME_PCAP "がインストールされてるか、" LIB_NAME_PCAP "に対応したネットワークに接続されてるか確認してください。" + IDS_2130 "不正な設定です" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 "ESC/Pプリンタのエミュレーションには" LIB_NAME_FREETYPE "が必要です。" +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 "PostScriptファイルをPDFに自動変換するには" LIB_NAME_GS "が必要です。\n\n汎用PostScriptプリンターに送信されたドキュメントは、PostScript(.ps)ファイルとして保存されます。" +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 "FluidSynthのMIDI出力には" LIB_NAME_FLUIDSYNTH "が必要です。" + IDS_2134 "フルスクリーンに切り替えています" + IDS_2135 "今後、このメッセージを表示しない" + IDS_2136 "終了しない" + IDS_2137 "リセット" + IDS_2138 "リセットしない" + IDS_2139 "光磁気イメージ (*.IM?;*.MDI)\0*.IM?;*.MDI\0すべてのファイル (*.*)\0*.*\0" + IDS_2140 "CD-ROMイメージ (*.ISO;*.CUE)\0*.ISO;*.CUE\0すべてのファイル (*.*)\0*.*\0" + IDS_2141 "%hs デバイスの設定" + IDS_2142 "モニターのスリープモード" + IDS_2143 "OpenGLシェーダー (*.GLSL)\0*.GLSL\0すべてのファイル (*.*)\0*.*\0" + IDS_2144 "OpenGL設定" + IDS_2145 "サポートされていない設定を読み込んでいます" + IDS_2146 "選択したマシンに基づくCPUタイプのフィルタリングは、このエミュレートされたマシンでは無効になっています。\n\nこれにより、選択したマシンと互換性のないCPUが選択できます。ただし、マシンのBIOSまたは他のソフトウェアとの互換性が失われる可能性があります。\n\nこの設定の有効化は公式サポートができません。また、バグレポートが無効として閉じられる場合があります。" + IDS_2147 "続行" + IDS_2148 "カセット: %s" + IDS_2149 "カセットイメージ (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0すべてのファイル (*.*)\0*.*\0" + IDS_2150 "カートリッジ %i: %ls" + IDS_2151 "カートリッジイメージ (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0すべてのファイル (*.*)\0*.*\0" + IDS_2152 "レンダラーの初期化エラー" + IDS_2153 "OpenGL (3.0コア) レンダラーが初期化できませんでした。別のレンダラーを使用してください。" + IDS_2154 "実行を再開" + IDS_2155 "実行を一時停止" + IDS_2156 "Ctrl+Alt+DELを押し" + IDS_2157 "Ctrl+Alt+Escを押し" + IDS_2158 "ハードリセット" + IDS_2159 "ACPIシャットダウン" + IDS_2160 "設定" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "ハードディスク (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLLまたはESDIのCD-ROMドライブが存在しません" + IDS_4100 "カスタム..." + IDS_4101 "カスタム (大型)..." + IDS_4102 "新規のディスクを追加" + IDS_4103 "既定のディスクを追加" + IDS_4104 "HDIディスクイメージは4GBを超えることはできません。" + IDS_4105 "ディスクイメージは127GBを超えることはできません。" + IDS_4106 "ハードディスクイメージ (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0すべてのファイル (*.*)\0*.*\0" + IDS_4107 "ファイルの読み込みができません" + IDS_4108 "ファイルの書き込みができません" + IDS_4109 "512以外のセクタサイズを持つHDIまたはHDXイメージはサポートされていません。" + IDS_4110 "USBはまだサポートされていません" + IDS_4111 "ディスクイメージファイルが既に存在します" + IDS_4112 "有効なファイル名を指定してください。" + IDS_4113 "ディスクイメージが作成されました" + IDS_4114 "ファイルが存在し、読み取り可能であることを確認してください。" + IDS_4115 "ファイルが書き込み可能なディレクトリに保存されていることを確認してください。" + IDS_4116 "ディスクイメージのサイズが大きすぎます" + IDS_4117 "新規ドライブをパーティション分割し、フォーマットを必ずしといてください。" + IDS_4118 "選択したファイルが上書きされます。使っていいですか?" + IDS_4119 "サポートされていないディスクイメージ" + IDS_4120 "上書き" + IDS_4121 "上書きしない" + IDS_4122 "Rawイメージ (.img)" + IDS_4123 "HDIイメージ (.hdi)" + IDS_4124 "HDXイメージ (.hdx)" + IDS_4125 "VHD(容量固定)(.vhd)" + IDS_4126 "VHD(容量可変)(.vhd)" + IDS_4127 "VHD(差分)(.vhd)" + IDS_4128 "大型ブロック (2 MB)" + IDS_4129 "小型ブロック (512 KB)" + IDS_4130 "VHDファイル (*.VHD)\0*.VHD\0すべてのファイル (*.*)\0*.*\0" + IDS_4131 "親VHDの選択" + IDS_4132 "親イメージがディファレンシングイメージの作成の後に修正した可能性があります。\n\nイメージファイルの移動、コピーまたはこのディスクを作成したプログラムにバグが発生した可能性があります。\n\nタイムスタンプを修正しますか?" + IDS_4133 "親ディスクと子ディスクのタイムスタンプが一致しません" + IDS_4134 "VHD のタイムスタンプを修正できませんでした。" + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "使用しない" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "使用しない" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (クラスター1024)" + IDS_5898 "DMF (クラスター2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "規定の回転数" + IDS_6145 "1%低い回転数" + IDS_6146 "1.5%低い回転数" + IDS_6147 "2%低い回転数" + + IDS_7168 "(システム既定値)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Japanese resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/ko-KR.rc b/src/win/languages/ko-KR.rc new file mode 100644 index 000000000..961b00748 --- /dev/null +++ b/src/win/languages/ko-KR.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Korean resources + +#ifdef _WIN32 +LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "동작(&A)" + BEGIN + MENUITEM "키보드는 캡쳐가 필요함(&K)", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "우측CTRL로 좌측ALT 입력(&R)", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "재시작(&H)...", IDM_ACTION_HRESET + MENUITEM "Ctrl+Alt+Del(&C)\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+Esc(&E)", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "일시정지(&P)", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "끝내기(&X)...", IDM_ACTION_EXIT + END + POPUP "표시(&V)" + BEGIN + MENUITEM "상태 바 숨기기(&H)", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "창 크기 조절 가능하게 하기(&R)", IDM_VID_RESIZE + MENUITEM "창 크기와 위치를 기억하기(&E)", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "렌더러(&N)" + BEGIN + MENUITEM "SDL (소프트웨어)(&S)", IDM_VID_SDL_SW + MENUITEM "SDL (하드웨어)(&H)", IDM_VID_SDL_HW + MENUITEM "SDL (OpenGL)(&O)", IDM_VID_SDL_OPENGL + MENUITEM "OpenGL (3.0 코어)(&G)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "VNC(&V)", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "창 크기 지정하기...", IDM_VID_SPECIFY_DIM + MENUITEM "화면 비율을 4:3으로 맞추기(&O)", IDM_VID_FORCE43 + POPUP "창 표시 배율(&W)" + BEGIN + MENUITEM "0.5배(&0)", IDM_VID_SCALE_1X + MENUITEM "1배(&1)", IDM_VID_SCALE_2X + MENUITEM "1.5배(&5)", IDM_VID_SCALE_3X + MENUITEM "2배(&2)", IDM_VID_SCALE_4X + END + POPUP "필터 형식" + BEGIN + MENUITEM "최근방 이웃 보간법(&N)", IDM_VID_FILTER_NEAREST + MENUITEM "선형 보간법(&L)", IDM_VID_FILTER_LINEAR + END + MENUITEM "HiDPI 스케일링(&D)", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "전체 화면(&F)\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "전체 화면 비율(&S)" + BEGIN + MENUITEM "전체 화면으로 확대(&F)", IDM_VID_FS_FULL + MENUITEM "4:3(&4)", IDM_VID_FS_43 + MENUITEM "정사각형 픽셀 (비율 유지)(&S)", IDM_VID_FS_KEEPRATIO + MENUITEM "정수배 확대(&I)", IDM_VID_FS_INT + END + POPUP "E&GA/(S)VGA 설정" + BEGIN + MENUITEM "색상 반전된 VGA 모니터(&I)", IDM_VID_INVERT + POPUP "VGA 화면 종류(&T)" + BEGIN + MENUITEM "RGB 천연색(&C)", IDM_VID_GRAY_RGB + MENUITEM "RGB 회색조(&R)", IDM_VID_GRAY_MONO + MENUITEM "주황색 모니터(&A)", IDM_VID_GRAY_AMBER + MENUITEM "녹색 모니터(&G)", IDM_VID_GRAY_GREEN + MENUITEM "흰색 모니터(&W)", IDM_VID_GRAY_WHITE + END + POPUP "회색조 표현방식(&C)" + BEGIN + MENUITEM "BT601 (NTSC/PAL)(&6)", IDM_VID_GRAYCT_601 + MENUITEM "BT709 (HDTV)(&7)", IDM_VID_GRAYCT_709 + MENUITEM "평균값(&A)", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/EGA/(S)VGA 오버스캔(&G)", IDM_VID_OVERSCAN + MENUITEM "흑백 표시를 위한 밝기 조정(&M)", IDM_VID_CGACON + END + MENUITEM "미디어(&M)", IDM_MEDIA + POPUP "도구(&T)" + BEGIN + MENUITEM "설정(&S)...", IDM_CONFIG + MENUITEM "상태 바 아이콘 갱신하기(&U)", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "스크린샷 찍기(&C)\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "환경설정(&P)...", IDM_PREFERENCES + MENUITEM "디스코드 연동 활성화하기(&D)", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "음량 증폭(&G)...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "추적 시작하기\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "추적 끝내기\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "도움말(&H)" + BEGIN + MENUITEM "문서(&D)...", IDM_DOCS + MENUITEM "86Box에 대해(&A)...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "새 이미지(&N)...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "이미지 불러오기(&E)...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "이미지 불러오기 (쓰기방지)(&W)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "녹음하기(&R)", IDM_CASSETTE_RECORD + MENUITEM "재생하기(&P)", IDM_CASSETTE_PLAY + MENUITEM "맨앞으로 되감기(&R)", IDM_CASSETTE_REWIND + MENUITEM "맨끝으로 빨리감기(&F)", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "꺼내기(&J)", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "이미지(&I)...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "꺼내기(&J)", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "새 이미지(&N)...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "이미지 불러오기(&E)...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "이미지 불러오기 (쓰기방지)(&W)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "86F로 보내기(&X)...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "꺼내기(&J)", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "음소거(&M)", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "비었음(&M)", IDM_CDROM_EMPTY + MENUITEM "이전 이미지 다시 불러오기(&R)", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "이미지(&I)", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "새 이미지(&N)...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "이미지 불러오기(&E)...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "이미지 불러오기 (쓰기방지)(&W)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "꺼내기(&J)", IDM_ZIP_EJECT + MENUITEM "이전 이미지 다시 불러오기(&R)", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "새 이미지(&N)...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "이미지 불러오기(&E)...", IDM_MO_IMAGE_EXISTING + MENUITEM "이미지 불러오기 (쓰기방지)(&W)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "꺼내기(&J)", IDM_MO_EJECT + MENUITEM "이전 이미지 다시 불러오기(&R)", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "목표 프레임 레이트(&F)" + BEGIN + MENUITEM "비디오와 동기(&S)", IDM_VID_GL_FPS_BLITTER + MENUITEM "25 fps(&2)", IDM_VID_GL_FPS_25 + MENUITEM "30 fps(&3)", IDM_VID_GL_FPS_30 + MENUITEM "50 fps(&5)", IDM_VID_GL_FPS_50 + MENUITEM "60 fps(&6)", IDM_VID_GL_FPS_60 + MENUITEM "75 fps(&7)", IDM_VID_GL_FPS_75 + END + MENUITEM "수직 동기화(&V)", IDM_VID_GL_VSYNC + MENUITEM "쉐이더 불러오기(&S)...", IDM_VID_GL_SHADER + MENUITEM "쉐이더 끄기(&R)", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "환경설정" +#define STR_SND_GAIN "음량 증폭" +#define STR_NEW_FLOPPY "새 이미지" +#define STR_CONFIG "설정" +#define STR_SPECIFY_DIM "창 크기 지정" + +#define STR_OK "확인" +#define STR_CANCEL "취소" +#define STR_GLOBAL "이 설정들을 전역 기본값으로 저장하기(&G)" +#define STR_DEFAULT "기본값(&D)" +#define STR_LANGUAGE "언어:" +#define STR_ICONSET "아이콘셋:" + +#define STR_GAIN "증가값" + +#define STR_FILE_NAME "파일명:" +#define STR_DISK_SIZE "디스크 용량:" +#define STR_RPM_MODE "RPM 모드:" +#define STR_PROGRESS "진행:" + +#define STR_WIDTH "가로:" +#define STR_HEIGHT "세로:" +#define STR_LOCK_TO_SIZE "크기 고정" + +#define STR_MACHINE_TYPE "머신 종류:" +#define STR_MACHINE "기종:" +#define STR_CONFIGURE "설정" +#define STR_CPU_TYPE "CPU 종류:" +#define STR_CPU_SPEED "속도:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "대기 상태:" +#define STR_MB "MB" +#define STR_MEMORY "메모리:" +#define STR_TIME_SYNC "시간 동기화" +#define STR_DISABLED "사용하지 않음" +#define STR_ENABLED_LOCAL "사용 (현지 시간)" +#define STR_ENABLED_UTC "사용 (UTC)" +#define STR_DYNAREC "동적 재컴파일" + +#define STR_VIDEO "비디오 카드:" +#define STR_VOODOO "Voodoo 그래픽" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "마우스:" +#define STR_JOYSTICK "조이스틱:" +#define STR_JOY1 "조이스틱 1..." +#define STR_JOY2 "조이스틱 2..." +#define STR_JOY3 "조이스틱 3..." +#define STR_JOY4 "조이스틱 4..." + +#define STR_SOUND "사운드 카드:" +#define STR_MIDI_OUT "MIDI 출력 장치:" +#define STR_MIDI_IN "MIDI 입력 장치:" +#define STR_MPU401 "MPU-401 단독 사용" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32 사운드 사용" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "네트워크 종류:" +#define STR_PCAP "PCap 장치:" +#define STR_NET "네트워크 어댑터:" + +#define STR_COM1 "COM1 장치:" +#define STR_COM2 "COM2 장치:" +#define STR_COM3 "COM3 장치:" +#define STR_COM4 "COM4 장치:" +#define STR_LPT1 "LPT1 장치:" +#define STR_LPT2 "LPT2 장치:" +#define STR_LPT3 "LPT3 장치:" +#define STR_LPT4 "LPT4 장치:" +#define STR_SERIAL1 "직렬 포트 1" +#define STR_SERIAL2 "직렬 포트 2" +#define STR_SERIAL3 "직렬 포트 3" +#define STR_SERIAL4 "직렬 포트 4" +#define STR_PARALLEL1 "병렬 포트 1" +#define STR_PARALLEL2 "병렬 포트 2" +#define STR_PARALLEL3 "병렬 포트 3" +#define STR_PARALLEL4 "병렬 포트 4" + +#define STR_HDC "HD 컨트롤러:" +#define STR_FDC "FD 컨트롤러:" +#define STR_IDE_TER "제3의 IDE 컨트롤러" +#define STR_IDE_QUA "제4의 IDE 컨트롤러" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "컨트롤러 1:" +#define STR_SCSI_2 "컨트롤러 2:" +#define STR_SCSI_3 "컨트롤러 3:" +#define STR_SCSI_4 "컨트롤러 4:" +#define STR_CASSETTE "카세트 테이프" + +#define STR_HDD "하드 디스크:" +#define STR_NEW "새로 만들기(&N)..." +#define STR_EXISTING "불러오기(&E)..." +#define STR_REMOVE "목록에서 제거(&R)" +#define STR_BUS "버스:" +#define STR_CHANNEL "채널:" +#define STR_ID "ID:" + +#define STR_SPECIFY "열기(&S)..." +#define STR_SECTORS "섹터:" +#define STR_HEADS "헤드:" +#define STR_CYLS "실린더:" +#define STR_SIZE_MB "용량(MB):" +#define STR_TYPE "형식:" +#define STR_IMG_FORMAT "이미지 포맷:" +#define STR_BLOCK_SIZE "블록 크기:" + +#define STR_FLOPPY_DRIVES "플로피 드라이브:" +#define STR_TURBO "고속 동작" +#define STR_CHECKBPB "BPB 확인" +#define STR_CDROM_DRIVES "CD-ROM 드라이브:" +#define STR_CD_SPEED "속도:" + +#define STR_MO_DRIVES "광자기 드라이브:" +#define STR_ZIP_DRIVES "ZIP 드라이브:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC 카드:" +#define STR_ISAMEM "ISA 메모리 확장 카드" +#define STR_ISAMEM_1 "카드 1:" +#define STR_ISAMEM_2 "카드 2:" +#define STR_ISAMEM_3 "카드 3:" +#define STR_ISAMEM_4 "카드 4:" +#define STR_BUGGER "ISABugger 장치" +#define STR_POSTCARD "POST 카드" + +#define FONT_SIZE 9 +#define FONT_NAME "Malgun Gothic" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "오류" + IDS_2050 "치명적인 오류" + IDS_2051 " - PAUSED" + IDS_2052 "Ctrl+Alt+PgDn 키를 누르면 창 모드로 전환합니다." + IDS_2053 "속도" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP 이미지 (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box에서 사용 가능한 ROM 이미지를 찾을 수 없습니다.\n\nROM 세트를다운로드 후 ""roms"" 디렉토리에 압축을 풀어 주세요." + IDS_2057 "(비었음)" + IDS_2058 "ZIP 이미지 (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0모든 파일 (*.*)\0*.*\0" + IDS_2059 "터보" + IDS_2060 "켜짐" + IDS_2061 "꺼짐" + IDS_2062 "모든 이미지 (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0기본 섹터 이미지 (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0표면 이미지 (*.86F)\0*.86F\0" + IDS_2063 "roms/machines 디렉토리에 필요한 롬파일이 없어 기종 ""%hs""을(를) 사용할 수 없습니다. 사용 가능한 기종으로 변경합니다." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "roms/video 디렉토리에 필요한 롬파일이 없어 비디오 카드 ""%hs""을(를) 사용할 수 없습니다. 사용 가능한 기종으로 변경합니다." + IDS_2065 "기종" + IDS_2066 "디스플레이" + IDS_2067 "입력 장치" + IDS_2068 "사운드" + IDS_2069 "네트워크" + IDS_2070 "포트 (COM & LPT)" + IDS_2071 "장치 컨트롤러" + IDS_2072 "하드 디스크" + IDS_2073 "플로피 / CD-ROM" + IDS_2074 "기타 이동식 저장장치" + IDS_2075 "기타 주변기기" + IDS_2076 "표면 이미지 (*.86F)\0*.86F\0" + IDS_2077 "이 창을 클릭하면 마우스를 사용합니다" + IDS_2078 "F12+F8키를 누르면 마우스를 해제합니다" + IDS_2079 "F12+F8키 또는 가운데 버튼을 클릭하면 마우스를 해제합니다" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "FluidSynth를 초기화할 수 없습니다" + IDS_2081 "버스" + IDS_2082 "파일" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "BPB 확인" + IDS_2088 "KB" + IDS_2089 "비디오 렌더러를 초기화할 수 없습니다." + IDS_2090 "기본값" + IDS_2091 "%i 대기 상태" + IDS_2092 "형식" + IDS_2093 "PCap 설정에 실패했습니다" + IDS_2094 "PCap 장치가 없습니다" + IDS_2095 "PCap 장치가 올바르지 않습니다" + IDS_2096 "표준 2버튼 조이스틱" + IDS_2097 "표준 4버튼 조이스틱" + IDS_2098 "표준 6버튼 조이스틱" + IDS_2099 "표준 8버튼 조이스틱" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "없음" + IDS_2104 "키보드 가속기를 불러올 수 없습니다." + IDS_2105 "Raw 입력을 등록할 수 없습니다." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "플로피 %i (%s): %ls" + IDS_2109 "모든 이미지 (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0어드밴스드 섹터 이미지 (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0기본 섹터 이미지 (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0플럭스 이미지 (*.FDI)\0*.FDI\0표면 이미지 (*.86F;*.MFM)\0*.86F;*.MFM\0모든 파일 (*.*)\0*.*\0" + IDS_2110 "FreeType을 초기화할 수 없습니다" + IDS_2111 "SDL을 초기화할 수 없습니다. SDL2.dll이 필요합니다" + IDS_2112 "실행중인 머신을 재시작하시겠습니까?" + IDS_2113 "86Box를 끝내시겠습니까?" + IDS_2114 "Ghostscript를 초기화할 수 없습니다" + IDS_2115 "광자기 %i (%ls): %ls" + IDS_2116 "광자기 이미지 (*.IM?;*.MDI)\0*.IM?;*.MDI\0모든 파일 (*.*)\0*.*\0" + IDS_2117 "86Box에 어서오세요!" + IDS_2118 "내부 컨트롤러" + IDS_2119 "끝내기" + IDS_2120 "ROM을 불러올 수 없습니다" + IDS_2121 "설정을 저장하시겠습니까?" + IDS_2122 "사용중인 머신이 재부팅됩니다." + IDS_2123 "저장" + IDS_2124 "86Box에 대해" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "고전 컴퓨터 에뮬레이터\n\n저자: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nGNU General Public 라이선스 (버전 2 이상)에 의해 배포되었습니다. 자세한 내용은 LICENSE 파일을 읽어 주세요." + IDS_2127 "확인" + IDS_2128 "하드웨어를 이용할 수 없습니다" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 LIB_NAME_PCAP "이 설치되었는지 " LIB_NAME_PCAP "에 대응하는 네트워크에 접속되어 있는지 확인해 주세요." + IDS_2130 "올바르지 않은 설정입니다" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 "ESC/P 프린터 에뮬레이션에 " LIB_NAME_FREETYPE "이(가) 필요합니다." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS "은(는) PostScript 파일을 PDF로 자동변환하는 데에 필요합니다.\n\n표준 PostScript 프린터로 보내신 임의의 문서는 PostScript (.ps) 파일로 저장됩니다." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 "FluidSynth의 MIDI 출력에 " LIB_NAME_FLUIDSYNTH "이(가) 필요합니다." + IDS_2134 "전체 화면으로 전환" + IDS_2135 "이 메시지 그만 보기" + IDS_2136 "끝내지 않기" + IDS_2137 "재시작" + IDS_2138 "재시작 안함" + IDS_2139 "광자기 이미지 (*.IM?;*.MDI)\0*.IM?;*.MDI\0모든 파일 (*.*)\0*.*\0" + IDS_2140 "CD-ROM 이미지 (*.ISO;*.CUE)\0*.ISO;*.CUE\0모든 파일 (*.*)\0*.*\0" + IDS_2141 "%hs 장치 설정" + IDS_2142 "모니터 절전 모드" + IDS_2143 "OpenGL 쉐이더 (*.GLSL)\0*.GLSL\0모든 파일 (*.*)\0*.*\0" + IDS_2144 "OpenGL 설정" + IDS_2145 "지원하지 않는 설정입니다" + IDS_2146 "이 에뮬레이트된 기종에 대해 선택한 기종을 기반으로 하는 CPU 종류 필터링이 사용되지 않도록 설정되었습니다.\n\n따라서 선택된 머신과 호환되지 않는 CPU를 선택하실 수 있습니다. 하지만 BIOS 또는 다른 소프트웨어와 호환되지 않을 수 있습니다.\n\n이 설정을 활성화하는 것은 공식적으로 지원되지 않으며, 제출된 버그 보고서는 유효하지 않음으로 닫힐 수 있습니다." + IDS_2147 "계속" + IDS_2148 "카세트: %s" + IDS_2149 "카세트 이미지 (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0모든 파일 (*.*)\0*.*\0" + IDS_2150 "카트리지 %i: %ls" + IDS_2151 "카트리지 이미지 (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0모든 파일 (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "하드 디스크 (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL 또는 ESDI CD-ROM 드라이브가 존재하지 않습니다" + IDS_4100 "사용자 설정..." + IDS_4101 "사용자 설정 (대용량)..." + IDS_4102 "새로 생성" + IDS_4103 "기존 이미지 사용" + IDS_4104 "HDI 디스크 이미지는 4GB 이상으로 지정할 수 없습니다" + IDS_4105 "디스크 이미지는 127GB 이상으로 지정할 수 없습니다" + IDS_4106 "하드 디스크 이미지 (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0모든 파일 (*.*)\0*.*\0" + IDS_4107 "파일을 읽을 수 없습니다" + IDS_4108 "파일을 저장할 수 없습니다" + IDS_4109 "512 바이트 이외의 섹터 크기를 가진 HDI 또는 HDX 형식의 이미지를 생성할 수 없습니다" + IDS_4110 "USB는 아직 지원하지 않습니다" + IDS_4111 "디스크 이미지 파일이 이미 존재합니다" + IDS_4112 "올바른 파일명을 지정해 주세요." + IDS_4113 "디스크 이미지가 생성되었습니다" + IDS_4114 "파일이 존재하며 읽을 수 있는지 확인합니다." + IDS_4115 "파일이 쓰기 가능한 디렉토리에 저장되고 있는지 확인합니다." + IDS_4116 "디스크 이미지가 너무 큽니다" + IDS_4117 "새로 생성한 드라이브의 파티션 설정과 포맷을 꼭 해주세요." + IDS_4118 "선택하신 파일을 덮어씌웁니다. 사용하시겠습니까?" + IDS_4119 "지원하지 않는 디스크 이미지입니다" + IDS_4120 "덮어쓰기" + IDS_4121 "덮어쓰지 않음" + IDS_4122 "Raw 이미지 (.img)" + IDS_4123 "HDI 이미지 (.hdi)" + IDS_4124 "HDX 이미지 (.hdx)" + IDS_4125 "고정 사이즈 VHD (.vhd)" + IDS_4126 "동적 사이즈 VHD (.vhd)" + IDS_4127 "디퍼런싱 VHD (.vhd)" + IDS_4128 "대형 블록 (2 MB)" + IDS_4129 "소형 블록 (512 KB)" + IDS_4130 "VHD 파일 (*.VHD)\0*.VHD\0모든 파일 (*.*)\0*.*\0" + IDS_4131 "부모 VHD 선택" + IDS_4132 "이는 디퍼런싱 이미지가 생성된 후 부모 이미지가 수정되었음을 의미할 수 있습니다.\n\n이미지 파일이 이동 또는 복사된 경우 또는 이 디스크를 만든 프로그램의 버그로 인해 발생할 수도 있습니다.\n\n타임스탬프를 수정하시겠습니까?" + IDS_4133 "부모 디스크와 자식 디스크의 타임스탬프가 일치하지 않습니다" + IDS_4134 "VHD 타임스탬프를 고칠 수 없습니다" + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "사용하지 않음" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "사용하지 않음" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (클러스터 1024)" + IDS_5898 "DMF (클러스터 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "완벽한 회전수" + IDS_6145 "1% 낮은 회전수" + IDS_6146 "1.5% 낮은 회전수" + IDS_6147 "2% 낮은 회전수" + + IDS_7168 "(시스템 기본값)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Korean resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/pl-PL.rc b/src/win/languages/pl-PL.rc new file mode 100644 index 000000000..5405778d3 --- /dev/null +++ b/src/win/languages/pl-PL.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Polish (pl-PL) resources + +#ifdef _WIN32 +LANGUAGE LANG_POLISH, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Akcje" + BEGIN + MENUITEM "&Klawaitura wymaga przechwytu myszy", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Prawy CTRL to lewy Alt", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Twardy reset...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pauza", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "W&yjdź...", IDM_ACTION_EXIT + END + POPUP "&Widok" + BEGIN + MENUITEM "&Ukryj pasek statusu", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Ukryj &pasek narzędzi", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Okno o zmiennym rozmiarze", IDM_VID_RESIZE + MENUITEM "P&amiętaj rozmiar &i pozycję", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Określ rozmiary...", IDM_VID_SPECIFY_DIM + MENUITEM "&Wymuś proporcje wyświetlania 4:3", IDM_VID_FORCE43 + POPUP "&Czynnik skalowania okna" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Metoda filtrowania" + BEGIN + MENUITEM "&Nearest", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Skalowanie Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Pełny ekran\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Tryb rozciągania na pełnym ekranie", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Kwadratowe piksele (Zachowaj proporcje)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Skalowanie całkowite", IDM_VID_FS_INT + END + POPUP "Ustawienia E&GA/(S)VGA" + BEGIN + MENUITEM "&Odwrócony monitor VGA", IDM_VID_INVERT + POPUP "Rodzaj ekranu &VGA" + BEGIN + MENUITEM "RGB - &Kolorowy", IDM_VID_GRAY_RGB + MENUITEM "&RGB - Skala szarości", IDM_VID_GRAY_MONO + MENUITEM "&Bursztynowy monitor", IDM_VID_GRAY_AMBER + MENUITEM "&Zielony monitor", IDM_VID_GRAY_GREEN + MENUITEM "&Biały monitor", IDM_VID_GRAY_WHITE + END + POPUP "Typ konwersji &w skali szarości" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Średni", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Overscan dla CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Zmień kontrast dla &monochromatycznego ekranu", IDM_VID_CGACON + END + MENUITEM "&Nośnik", IDM_MEDIA + POPUP "&Narzędzia" + BEGIN + MENUITEM "&Ustawienia...", IDM_CONFIG + MENUITEM "&Aktualizuj ikony na pasku statusu", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Zrób &zrzut ekranu\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferencje...", IDM_PREFERENCES + MENUITEM "Włącz integrację z &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "Wzmocnienie &dźwięku...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Rozpocznij śledzenie\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Zakończ śledzenie\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Pomoc" + BEGIN + MENUITEM "&Dokumentacja...", IDM_DOCS + MENUITEM "&O 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nowy obraz...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Istniejący obraz...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Istniejący obraz (&Chroniony przed zapisem)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Nagraj", IDM_CASSETTE_RECORD + MENUITEM "&Odtwórz", IDM_CASSETTE_PLAY + MENUITEM "&Przewiń do początku", IDM_CASSETTE_REWIND + MENUITEM "&Przewiń do końca", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "W&yjmij", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Obraz...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "W&yjmij", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nowy obraz...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Istniejący obraz...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Istniejący obraz (&Chroniony przed zapisem)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&ksportuj do 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "W&yjmij", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Ścisz", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "P&usty", IDM_CDROM_EMPTY + MENUITEM "&Przeładuj poprzedni obraz", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Obraz", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nowy obraz...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Istniejący obraz...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Istniejący obraz (&Chroniony przed zapisem)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "W&yjmij", IDM_ZIP_EJECT + MENUITEM "&Przeładuj poprzedni obraz", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nowy obraz...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Istniejący obraz...", IDM_MO_IMAGE_EXISTING + MENUITEM "Istniejący obraz (&Chroniony przed zapisem)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "W&yjmij", IDM_MO_EJECT + MENUITEM "&Przeładuj poprzedni obraz", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Docelowa &liczba klatek na sekundę" + BEGIN + MENUITEM "&Zsynchronizuj z wideo", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Wybierz shader...", IDM_VID_GL_SHADER + MENUITEM "&Usuń shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferencje" +#define STR_SND_GAIN "Wzmocnienie dźwięku" +#define STR_NEW_FLOPPY "Nowy obraz" +#define STR_CONFIG "Ustawienia" +#define STR_SPECIFY_DIM "Określ rozmiary okna" + +#define STR_OK "OK" +#define STR_CANCEL "Anuluj" +#define STR_GLOBAL "Zapisz ustawienia jako &globalne ustawienia domyślne" +#define STR_DEFAULT "&Domyślny" +#define STR_LANGUAGE "Język:" +#define STR_ICONSET "Zestaw ikon:" + +#define STR_GAIN "Wzmacniacz" + +#define STR_FILE_NAME "Nazwa pliku:" +#define STR_DISK_SIZE "Rozmiar dysku:" +#define STR_RPM_MODE "Tryb RPM:" +#define STR_PROGRESS "Postęp:" + +#define STR_WIDTH "Szerokość:" +#define STR_HEIGHT "Wysokość:" +#define STR_LOCK_TO_SIZE "Stały rozmiar" + +#define STR_MACHINE_TYPE "Rodzaj maszyny:" +#define STR_MACHINE "Maszyna:" +#define STR_CONFIGURE "Konfiguruj" +#define STR_CPU_TYPE "Rodzaj procesora:" +#define STR_CPU_SPEED "Szybkość:" +#define STR_FPU "Jednostka FPU:" +#define STR_WAIT_STATES "Stany oczekiwania:" +#define STR_MB "MB" +#define STR_MEMORY "Pamięć:" +#define STR_TIME_SYNC "Synchronizacja czasu" +#define STR_DISABLED "Wyłączona" +#define STR_ENABLED_LOCAL "Włączona (czas lokalny)" +#define STR_ENABLED_UTC "Włączona (UTC)" +#define STR_DYNAREC "Dynamiczny rekompilator" + +#define STR_VIDEO "Wideo:" +#define STR_VOODOO "Grafika Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Mysz:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Karta dźwiękowa:" +#define STR_MIDI_OUT "Urządzenie wyjściowe MIDI:" +#define STR_MIDI_IN "Urządzenie wejściowe MIDI:" +#define STR_MPU401 "Samodzielne urządzenie MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Użyj dźwięku FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Rodzaj sieci:" +#define STR_PCAP "Urządzenie PCap:" +#define STR_NET "Karta sieciowa:" + +#define STR_COM1 "Urządzenie COM1:" +#define STR_COM2 "Urządzenie COM2:" +#define STR_COM3 "Urządzenie COM3:" +#define STR_COM4 "Urządzenie COM4:" +#define STR_LPT1 "Urządzenie LPT1:" +#define STR_LPT2 "Urządzenie LPT2:" +#define STR_LPT3 "Urządzenie LPT3:" +#define STR_LPT4 "Urządzenie LPT4:" +#define STR_SERIAL1 "Port szeregowy 1" +#define STR_SERIAL2 "Port szeregowy 2" +#define STR_SERIAL3 "Port szeregowy 3" +#define STR_SERIAL4 "Port Szeregowy 4" +#define STR_PARALLEL1 "Port równoległy 1" +#define STR_PARALLEL2 "Port równoległy 2" +#define STR_PARALLEL3 "Port równoległy 3" +#define STR_PARALLEL4 "Port równoległy 4" + +#define STR_HDC "Kontroler dysku twardego:" +#define STR_FDC "Kontroler dyskietek:" +#define STR_IDE_TER "Trzeciorzędowy kontroler IDE" +#define STR_IDE_QUA "Czwartorzędowy kontroler IDE" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Kontroler 1:" +#define STR_SCSI_2 "Kontroler 2:" +#define STR_SCSI_3 "Kontroler 3:" +#define STR_SCSI_4 "Kontroler 4:" +#define STR_CASSETTE "Kaseta" + +#define STR_HDD "Dyski twarde:" +#define STR_NEW "&Nowy..." +#define STR_EXISTING "&Istniejący..." +#define STR_REMOVE "&Usuń" +#define STR_BUS "Magistrala:" +#define STR_CHANNEL "Kanał:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Określ..." +#define STR_SECTORS "Sektory:" +#define STR_HEADS "Głowice:" +#define STR_CYLS "Cylindry:" +#define STR_SIZE_MB "Rozmiar (MB):" +#define STR_TYPE "Rodzaj:" +#define STR_IMG_FORMAT "Format obrazu:" +#define STR_BLOCK_SIZE "Rozmiar bloku:" + +#define STR_FLOPPY_DRIVES "Napędy dyskietek:" +#define STR_TURBO "Rozrządy Turbo" +#define STR_CHECKBPB "Sprawdzaj BPB" +#define STR_CDROM_DRIVES "Napędy CD-ROM:" +#define STR_CD_SPEED "Szybkość:" + +#define STR_MO_DRIVES "Napędy MO:" +#define STR_ZIP_DRIVES "Napędy ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "Rozszerzenie pamięci ISA" +#define STR_ISAMEM_1 "Karta 1:" +#define STR_ISAMEM_2 "Karta 2:" +#define STR_ISAMEM_3 "Karta 3:" +#define STR_ISAMEM_4 "Karta 4:" +#define STR_BUGGER "Urządzenie ISABugger" +#define STR_POSTCARD "Karta POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Błąd" + IDS_2050 "Fatalny błąd" + IDS_2051 " - PAUSED" + IDS_2052 "Naciśnij klawisze Ctrl+Alt+PgDn aby wrócić to trybu okna." + IDS_2053 "Szybkość" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Obrazy ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box nie może znaleźć obrazów ROM nadających się do użytku.\n\nProszę pobrać zestaw obrazów ROM ze strony download, i rozpakować je do katalogu ""roms""." + IDS_2057 "(pusty)" + IDS_2058 "Obrazy ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Wszystkie pliki (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Włącz" + IDS_2061 "Wyłącz" + IDS_2062 "Wszystkie obrazy (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Podstawowe obrazy sektorów(*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Obrazy powierzchniowe (*.86F)\0*.86F\0" + IDS_2063 "Maszyna ""%hs"" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/machines. Przełączanie na dostępną maszynę." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Karta wideo ""%hs"" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/video. Przełączanie na dostępną kartę wideo." + IDS_2065 "Maszyna" + IDS_2066 "Ekran" + IDS_2067 "Urządzenia wejściowe" + IDS_2068 "Dźwięk" + IDS_2069 "Sieć" + IDS_2070 "Porty (COM & LPT)" + IDS_2071 "Kontrolery pamięci" + IDS_2072 "Dyski twarde" + IDS_2073 "Napędy dyskietek i CD-ROM" + IDS_2074 "Inne urządzenia wymienne" + IDS_2075 "Inne urządzenia peryferyjne" + IDS_2076 "Obrazy powierzchniowe (*.86F)\0*.86F\0" + IDS_2077 "Kliknij w celu przechwycenia myszy" + IDS_2078 "Naciśnij klawisze F8+F12 w celu uwolnienia myszy" + IDS_2079 "Naciśnij klawisze F8+F12 lub środkowy przycisk w celu uwolnienia myszy" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Nie można zainicjować FluidSynth" + IDS_2081 "Magistrala" + IDS_2082 "Plik" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Sprawdzaj BPB" + IDS_2088 "KB" + IDS_2089 "Nie można zainicjować renderera wideo." + IDS_2090 "Domyślny" + IDS_2091 "%i Stany oczekiwania" + IDS_2092 "Rodzaj" + IDS_2093 "Nie udało się ustawić PCap" + IDS_2094 "Nie znaleziono urządzeń PCap" + IDS_2095 "Nieprawidłowe urządzenie PCap" + IDS_2096 "Standardowe joysticki 2-przyciskowe" + IDS_2097 "Standardowy joystick 4-przyciskowy" + IDS_2098 "Standardowy joystick 6-przyciskowy" + IDS_2099 "Standardowy joystick 8-przyciskowy" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Żaden" + IDS_2104 "Nie można załadować akceleratorów klawiaturowych." + IDS_2105 "Nie można zarejestrować surowych danych wejściowych." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Dyskietka %i (%s): %ls" + IDS_2109 "Wszystkie obrazy (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Zaawansowane obrazy sektorów (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Podstawowe obrazy sektorów (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Obrazy powierzchniowe (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2110 "Nie można zainicjować FreeType" + IDS_2111 "Nie można zainicjować SDL, wymagany SDL2.dll" + IDS_2112 "Jesteś pewien że chcesz wykonać twardy reset emulowanej maszyny?" + IDS_2113 "Jesteś pewien że chcesz zakończyć 86Box?" + IDS_2114 "Nie można zainicjować Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "Obrazy MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2117 "Witamy w 86Box!" + IDS_2118 "Kontroler wewnętrzny" + IDS_2119 "Zakończ" + IDS_2120 "Nie znaleziono obrazów ROM" + IDS_2121 "Czy chcesz zapisać ustawienia?" + IDS_2122 "To spowoduje twardy reset wirtualnej maszyny." + IDS_2123 "Zapisz" + IDS_2124 "O 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Emulator starych komputerów\n\nAutorzy: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, i inni.\n\nPrzetłumaczony przez: Fanta-Shokata\n\nWydany na licencji GNU General Public License w wersji 2 lub nowszej. Zobacz LICENSE aby uzyskać więcej informacji." + IDS_2127 "OK" + IDS_2128 "Sprzęt niedostępny" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Sprawdź, czy " LIB_NAME_PCAP " jest zainstalowany i czy posiadasz połączenie sieciowe kompatybilne z " LIB_NAME_PCAP "." + IDS_2130 "Nieprawidłowa konfiguracja" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " jest wymagany do emulacji drukarki ESC-P." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " jest wymagany do automatycznej konwersji plików PostScript do PDF.\n\nDokumenty wysłane do ogólnej drukarki PostScript zostaną zapisane jako pliki PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " jest wymagany dla wyjścia FluidSynth MIDI." + IDS_2134 "Przechodzenie do trybu pełnoekranowego" + IDS_2135 "Nie pokazuj więcej tego komunikatu" + IDS_2136 "Nie kończ" + IDS_2137 "Przywróć" + IDS_2138 "Nie przywracaj" + IDS_2139 "Obrazy MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2140 "Obrazy CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2141 "Konfiguracja urządzenia %hs" + IDS_2142 "Monitor w trybie czuwania" + IDS_2143 "Shadery OpenGL (*.GLSL)\0*.GLSL\0Wszystkie pliki (*.*)\0*.*\0" + IDS_2144 "Opcje OpenGL" + IDS_2145 "Ładujesz nieobsługiwaną konfigurację" + IDS_2146 "Wybór rodzaju procesora oparty na wybranej maszynie jest wyłączony dla tej emulowanej maszyny.\n\nPozwala to na wybór procesora który jest niekompatybilny z wybraną maszyną. Jednak możesz napotkać niezgodności z BIOS-em maszyny lub innym oprogramowaniem.\n\nAktywacja tego ustawienia nie jest wspierana i każde zgłoszenie błędu może zostać zamknięte jako nieważne." + IDS_2147 "Kontynuuj" + IDS_2148 "Kaseta: %s" + IDS_2149 "Obrazy kaset (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Wszystkie pliki (*.*)\0*.*\0" + IDS_2150 "Kartrydż %i: %ls" + IDS_2151 "Obrazy kartrydżu (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Wszystkie pliki (*.*)\0*.*\0" + IDS_2152 "Błąd inicjalizacji renderera" + IDS_2153 "Nie można zainicjować renderera OpenGL (3.0 Core). Użyj innego." + IDS_2154 "Wznów wykonywanie" + IDS_2155 "Zatrzymaj wykonywanie" + IDS_2156 "Naciśnij Ctrl+Alt+Del" + IDS_2157 "Naciśnij Ctrl+Alt+Esc" + IDS_2158 "Twardy reset" + IDS_2159 "Wyłączenie ACPI" + IDS_2160 "Ustawienia" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Dysk twardy (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "Napędy CD-ROM MFM/RLL lub ESDI nigdy nie istniały" + IDS_4100 "Niestandardowy..." + IDS_4101 "Niestandardowy (duży)..." + IDS_4102 "Dodaj nowy dysk twardy" + IDS_4103 "Dodaj istniejący dysk twardy" + IDS_4104 "Obrazy dysków HDI nie mogą być większe niż 4 GB." + IDS_4105 "Obrazy dysków nie mogą być większe niż 127 GB." + IDS_4106 "Obrazy dysku twardego (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Wszystkie pliki (*.*)\0*.*\0" + IDS_4107 "Nie można odczytać pliku" + IDS_4108 "Nie można zapisać pliku" + IDS_4109 "Obrazy HDI lub HDX z rozmiarem sektora innym niż 512 nie są wspierane." + IDS_4110 "USB nie jest jeszcze wspierane" + IDS_4111 "Plik obrazu dysku już istnieje" + IDS_4112 "Określ prawidłową nazwę pliku." + IDS_4113 "Utworzono obraz dysku" + IDS_4114 "Sprawdź, czy plik istnieje i nadaje się do odczytu." + IDS_4115 "Sprawdź, czy plik jest zapiyswany w katalogu z możliwością zapisu." + IDS_4116 "Obraz dysku jest za duży" + IDS_4117 "Nie zapomnij o partycjonowaniu i sformatowaniu nowo utworzego dysku" + IDS_4118 "Wybrany plik zostanie nadpisany. Czy na pewno chcesz użyć tego pliku?" + IDS_4119 "Niewspierany obraz dysku" + IDS_4120 "Nadpisz" + IDS_4121 "Nie nadpisuj" + IDS_4122 "Obraz surowy (.img)" + IDS_4123 "Obraz HDI (.hdi)" + IDS_4124 "Obraz HDX (.hdx)" + IDS_4125 "VHD o stałym rozmiarze (.vhd)" + IDS_4126 "VHD o dynamicznym rozmiarze (.vhd)" + IDS_4127 "VHD różnicujący (.vhd)" + IDS_4128 "Duże bloki (2 MB)" + IDS_4129 "Małe bloki (512 KB)" + IDS_4130 "Pliki VHD (*.VHD)\0*.VHD\0Wszystkie pliki (*.*)\0*.*\0" + IDS_4131 "Wybierz nadrzędny plik VHD" + IDS_4132 "Może to oznaczać, że obraz nadrzędny został zmodyfikowany po utworzeniu obrazu różnicującego.\n\nMoże się to również zdarzyć, jeśli pliki obrazów zostały przeniesione lub skopiowane, lub wystąpił błąd w programie, który utworzył ten dysk\n\nCzy chcesz naprawić sygnatury czasowe?" + IDS_4133 "Sygnatury czasowe dysku nadrzędnego i podrzędnego nie zgadzają się" + IDS_4134 "Nie można naprawić sygnatury czasowej VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Wyłączony" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Wyłączony" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1,2 MB" + IDS_5895 "1,25 MB" + IDS_5896 "1,44 MB" + IDS_5897 "DMF (klaster 1024)" + IDS_5898 "DMF (klaster 2048)" + IDS_5899 "2,88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1,3 GB (GigaMO)" + IDS_5907 "3.5"" 2,3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1,3 GB" + + IDS_6144 "Idealne obroty" + IDS_6145 "1% poniżej idealnych obrotów" + IDS_6146 "1.5% poniżej idealnych obrotów" + IDS_6147 "2% poniżej idealnych obrotów" + + IDS_7168 "(Domyślne ustawienie systemowe)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Polish (pl-PL) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/pt-BR.rc b/src/win/languages/pt-BR.rc new file mode 100644 index 000000000..538472293 --- /dev/null +++ b/src/win/languages/pt-BR.rc @@ -0,0 +1,625 @@ +//////////////////////////////////////////////////////////////////////////// +// Portuguese (pt-BR) resources +// +// Translated by Altieres Lima da Silva, 2021 +// + +#ifdef _WIN32 +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Ação" + BEGIN + MENUITEM "&Teclado requer captura", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "CTRL &direito é o ALT esquerdo", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Reinicialização completa...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pausar", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Sair...", IDM_ACTION_EXIT + END + POPUP "&Exibir" + BEGIN + MENUITEM "&Ocultar barra de status", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Ocultar &barra de ferramenta", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Janela redimensionável", IDM_VID_RESIZE + MENUITEM "&Lembrar tamanho e posição", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Renderizador" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (Núcleo 3.0)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Especificar as dimensões...", IDM_VID_SPECIFY_DIM + MENUITEM "F&orçar proporção de tela em 4:3", IDM_VID_FORCE43 + POPUP "&Fator de redimensionamento da janela" + BEGIN + MENUITEM "&0,5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1,&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Método de filtragem" + BEGIN + MENUITEM "&Mais próximo", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Escala Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Tela cheia\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Modo de &redimensionamento da tela cheia" + BEGIN + MENUITEM "&Tela cheia esticada", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "Pixel&s quadrados (manter proporção)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Redimensionamento com valores inteiros", IDM_VID_FS_INT + END + POPUP "Configurações E&GA/(S)VGA" + BEGIN + MENUITEM "Monitor VGA &invertido", IDM_VID_INVERT + POPUP "&Tipo de tela VGA" + BEGIN + MENUITEM "&Cores RGB", IDM_VID_GRAY_RGB + MENUITEM "Tons de cinza &RGB", IDM_VID_GRAY_MONO + MENUITEM "Monitor &âmbar", IDM_VID_GRAY_AMBER + MENUITEM "Monitor &verde", IDM_VID_GRAY_GREEN + MENUITEM "Monitor &branco", IDM_VID_GRAY_WHITE + END + POPUP "Tipo de &conversão de tons de cinza" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Média", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Overscan do CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Alterar contraste para exibição &monocromática", IDM_VID_CGACON + END + MENUITEM "&Mídia", IDM_MEDIA + POPUP "&Ferramentas" + BEGIN + MENUITEM "&Configurações...", IDM_CONFIG + MENUITEM "&Atualizar ícones da barra de status", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Capturar &tela\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferências...", IDM_PREFERENCES + MENUITEM "Ativar integração com o &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Ganho de som...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Inicio do rastreamento\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Fim do rastreamento\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Ajuda" + BEGIN + MENUITEM "&Documentação...", IDM_DOCS + MENUITEM "&Sobre o 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Imagem existente...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Imagem existente (&protegida contra escrita)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Gravar", IDM_CASSETTE_RECORD + MENUITEM "&Reproduzir", IDM_CASSETTE_PLAY + MENUITEM "&Rebobinar até o começo", IDM_CASSETTE_REWIND + MENUITEM "&Avançar até o fim", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Imagem...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Imagem existente...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Imagem existente (&protegida contra escrita)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xportar para 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Sem som", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Vazio", IDM_CDROM_EMPTY + MENUITEM "&Recarregar imagem anterior", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Imagem", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Imagem existente...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Imagem existente (&protegida contra escrita)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_ZIP_EJECT + MENUITEM "&Recarregar imagem anterior", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Imagem existente...", IDM_MO_IMAGE_EXISTING + MENUITEM "Imagem existente (&protegida contra escrita)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_MO_EJECT + MENUITEM "&Recarregar imagem anterior", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Taxa de quadro pretendida" + BEGIN + MENUITEM "&Sincronizar com vídeo", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 qps", IDM_VID_GL_FPS_25 + MENUITEM "&30 qps", IDM_VID_GL_FPS_30 + MENUITEM "&50 qps", IDM_VID_GL_FPS_50 + MENUITEM "&60 qps", IDM_VID_GL_FPS_60 + MENUITEM "&75 qps", IDM_VID_GL_FPS_75 + END + MENUITEM "Sincronização &vertical", IDM_VID_GL_VSYNC + MENUITEM "&Selecionar shader...", IDM_VID_GL_SHADER + MENUITEM "&Remover shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferências" +#define STR_SND_GAIN "Ganho de som" +#define STR_NEW_FLOPPY "Nova imagem de disquete" +#define STR_CONFIG "Configurações" +#define STR_SPECIFY_DIM "Especifique as dimensões da janela principal" + +#define STR_OK "OK" +#define STR_CANCEL "Cancelar" +#define STR_GLOBAL "Usar estas configurações como &padrões globais" +#define STR_DEFAULT "&Padrão" +#define STR_LANGUAGE "Idioma:" +#define STR_ICONSET "Pacote de ícones:" + +#define STR_GAIN "Ganho" + +#define STR_FILE_NAME "Nome:" +#define STR_DISK_SIZE "Tamanho:" +#define STR_RPM_MODE "Modo RPM:" +#define STR_PROGRESS "Progresso:" + +#define STR_WIDTH "Largura:" +#define STR_HEIGHT "Altura:" +#define STR_LOCK_TO_SIZE "Travar nesse tamanho" + +#define STR_MACHINE_TYPE "Tipo de máquina:" +#define STR_MACHINE "Máquina:" +#define STR_CONFIGURE "Configurar" +#define STR_CPU_TYPE "Tipo de CPU:" +#define STR_CPU_SPEED "Veloc.:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Estados de espera:" +#define STR_MB "MB" +#define STR_MEMORY "Memória:" +#define STR_TIME_SYNC "Sincronização da hora" +#define STR_DISABLED "Desativar" +#define STR_ENABLED_LOCAL "Ativar (hora local)" +#define STR_ENABLED_UTC "Ativar (UTC)" +#define STR_DYNAREC "Recompilador dinâmico" + +#define STR_VIDEO "Vídeo:" +#define STR_VOODOO "3DFX Voodoo" +#define STR_IBM8514 "Gráficos IBM 8514/a" +#define STR_XGA "Gráficos XGA" + +#define STR_MOUSE "Mouse:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Placa de som:" +#define STR_MIDI_OUT "Disp. saída MIDI:" +#define STR_MIDI_IN "Disp. entrada MIDI:" +#define STR_MPU401 "MPU-401 autônomo" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Usar som FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Tipo de rede:" +#define STR_PCAP "Dispositivo PCap:" +#define STR_NET "Adaptador de rede:" + +#define STR_COM1 "Dispositivo COM1:" +#define STR_COM2 "Dispositivo COM2:" +#define STR_COM3 "Dispositivo COM3:" +#define STR_COM4 "Dispositivo COM4:" +#define STR_LPT1 "Dispositivo LPT1:" +#define STR_LPT2 "Dispositivo LPT2:" +#define STR_LPT3 "Dispositivo LPT3:" +#define STR_LPT4 "Dispositivo LPT4:" +#define STR_SERIAL1 "Porta serial 1" +#define STR_SERIAL2 "Porta serial 2" +#define STR_SERIAL3 "Porta serial 3" +#define STR_SERIAL4 "Porta serial 4" +#define STR_PARALLEL1 "Porta paralela 1" +#define STR_PARALLEL2 "Porta paralela 2" +#define STR_PARALLEL3 "Porta paralela 3" +#define STR_PARALLEL4 "Porta paralela 4" + +#define STR_HDC "Controlador HD:" +#define STR_FDC "Controlador FD:" +#define STR_IDE_TER "Controlador IDE terciário" +#define STR_IDE_QUA "Controlador IDE quaternário" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controlador 1:" +#define STR_SCSI_2 "Controlador 2:" +#define STR_SCSI_3 "Controlador 3:" +#define STR_SCSI_4 "Controlador 4:" +#define STR_CASSETTE "Cassete" + +#define STR_HDD "Discos rígidos:" +#define STR_NEW "&Novo..." +#define STR_EXISTING "&Existente..." +#define STR_REMOVE "&Remover" +#define STR_BUS "Bar.:" +#define STR_CHANNEL "Canal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Especificar..." +#define STR_SECTORS "Setores:" +#define STR_HEADS "Cabeças:" +#define STR_CYLS "Cilindros:" +#define STR_SIZE_MB "Tamanho (MB):" +#define STR_TYPE "Tipo:" +#define STR_IMG_FORMAT "Formato:" +#define STR_BLOCK_SIZE "Blocos:" + +#define STR_FLOPPY_DRIVES "Unidades de disquete:" +#define STR_TURBO "Turbo" +#define STR_CHECKBPB "Verificar BPB" +#define STR_CDROM_DRIVES "Unidades de CD-ROM:" +#define STR_CD_SPEED "Veloc.:" + +#define STR_MO_DRIVES "Unidades magneto-ópticas:" +#define STR_ZIP_DRIVES "Unidades ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "RTC ISA:" +#define STR_ISAMEM "Expansão de memória ISA" +#define STR_ISAMEM_1 "Placa 1:" +#define STR_ISAMEM_2 "Placa 2:" +#define STR_ISAMEM_3 "Placa 3:" +#define STR_ISAMEM_4 "Placa 4:" +#define STR_BUGGER "Dispositivo ISABugger" +#define STR_POSTCARD "Placa de diagnóstico" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Erro" + IDS_2050 "Erro fatal" + IDS_2051 " - PAUSADO" + IDS_2052 "Use Ctrl+Alt+PgDn para retornar ao modo janela" + IDS_2053 "Velocidade" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Imagens ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "O 86Box não conseguiu encontrar nenhuma imagem de ROM utilizável.\n\nPor favor, baixe um conjunto de ROM e extraia no diretório ""roms""." + IDS_2057 "(vazio)" + IDS_2058 "Imagens ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Todos os arquivos (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Lig." + IDS_2061 "Desl." + IDS_2062 "Todas as imagens (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Imagens de setor básico (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Imagens de superfície (*.86F)\0*.86F\0" + IDS_2063 "A máquina ""%hs"" não está disponível devido à falta de ROMs no diretório roms/machines. Mudando para uma máquina disponível." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "A placa de vídeo ""%hs"" não está disponível devido à falta de ROMs no diretório roms/video. Mudando para uma placa de vídeo disponível." + IDS_2065 "Máquina" + IDS_2066 "Vídeo" + IDS_2067 "Dispositivos de entrada" + IDS_2068 "Som" + IDS_2069 "Rede" + IDS_2070 "Portas (COM & LPT)" + IDS_2071 "Controladores de armaz." + IDS_2072 "Discos rígidos" + IDS_2073 "Disquete & CD-ROM" + IDS_2074 "Dispos. removíveis" + IDS_2075 "Outros periféricos" + IDS_2076 "Imagens de superfície (*.86F)\0*.86F\0" + IDS_2077 "Clique para capturar o mouse" + IDS_2078 "Aperte F8+F12 para liberar o mouse" + IDS_2079 "Aperte F8+F12 ou botão do meio para liberar o mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Não foi possível inicializar o FluidSynth" + IDS_2081 "Barramento" + IDS_2082 "Arquivo" + IDS_2083 "CI" + IDS_2084 "CA" + IDS_2085 "SE" + IDS_2086 "MB" + IDS_2087 "Verificar BPB" + IDS_2088 "KB" + IDS_2089 "Não foi possível inicializar o renderizador de vídeo." + IDS_2090 "Padrão" + IDS_2091 "%i estado(s) de espera" + IDS_2092 "Tipo" + IDS_2093 "Não foi possível configurar o PCap" + IDS_2094 "Nenhum dispositivo PCap encontrado" + IDS_2095 "Dispositivo PCap inválido" + IDS_2096 "Joystick padrão de 2 botões" + IDS_2097 "Joystick padrão de 4 botões" + IDS_2098 "Joystick padrão de 6 botões" + IDS_2099 "Joystick padrão de 8 botões" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Sistema de Controle de Voo Thrustmaster" + IDS_2103 "Nada" + IDS_2104 "Não foi possível carregar os aceleradores do teclado." + IDS_2105 "Não foi possível registrar a entrada bruta." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Disquete %i (%s): %ls" + IDS_2109 "Todas as imagens (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Imagens de setor avançado (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Imagens de setor básico (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Imagens de fluxo (*.FDI)\0*.FDI\0Imagens de superfície (*.86F;*.MFM)\0*.86F;*.MFM\0Todos os arquivos (*.*)\0*.*\0" + IDS_2110 "Não foi possível inicializar o FreeType" + IDS_2111 "Não é possível inicializar o SDL, é necessário o SDL2.dll" + IDS_2112 "Tem certeza de que deseja reiniciar completamente a máquina emulada?" + IDS_2113 "Tem certeza de que deseja sair do 86Box?" + IDS_2114 "Não é possível inicializar o Ghostscript" + IDS_2115 "Magneto-óptico %i (%ls): %ls" + IDS_2116 "Imagens magneto-ópticas (*.IM?;*.MDI)\0*.IM?;*.MDI\0Todos os arquivos (*.*)\0*.*\0" + IDS_2117 "Bem-vindo ao 86Box!" + IDS_2118 "Controlador interno" + IDS_2119 "Sair" + IDS_2120 "Nenhum ROM encontrada" + IDS_2121 "Você deseja salvar as configurações?" + IDS_2122 "Isto fará com que a máquina emulada seja reinicializada." + IDS_2123 "Salvar" + IDS_2124 "Sobre o 86Box" + IDS_2125 "86Box versão" EMU_VERSION + + IDS_2126 "Um emulador de computadores antigos\n\nAutores: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, e outros.\n\nTraduzido por: Altieres Lima da Silva\n\nLançado sob a Licença Pública Geral GNU versão 2 ou posterior. Veja o arquivo LICENSE para mais informações." + IDS_2127 "OK" + IDS_2128 "Hardware não disponível" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Certifique-se de que " LIB_NAME_PCAP " esteja instalado e que você tenha uma conexão de rede compatível com " LIB_NAME_PCAP "." + IDS_2130 "Configuração inválida" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " é necessário para emulação de impressora ESC/P." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " é necessário para a conversão automática de arquivos PostScript para PDF.\n\nQualquer documento enviado para a impressora genérica PostScript será salvo como arquivos PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " é necessário para a saída MIDI FluidSynth." + IDS_2134 "Entrando no modo de tela cheia" + IDS_2135 "Não exibir esta mensagem novamente" + IDS_2136 "Não sair" + IDS_2137 "Reiniciar" + IDS_2138 "Não reiniciar" + IDS_2139 "Imagens magneto-ópticas (*.IM?;*.MDI)\0*.IM?;*.MDI\0Todos os arquivos (*.*)\0*.*\0" + IDS_2140 "Imagens de CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Todos os arquivos (*.*)\0*.*\0" + IDS_2141 "Configuração do dispositivo %hs" + IDS_2142 "Monitor em modo de suspensão" + IDS_2143 "Shaders OpenGL (*.GLSL)\0*.GLSL\0Todos os arquivos (*.*)\0*.*\0" + IDS_2144 "Opções do OpenGL" + IDS_2145 "Você está carregando uma configuração não suportada" + IDS_2146 "A filtragem do tipo CPU baseada na máquina selecionada é desativada para esta máquina emulada.\n\nIsto torna possível escolher uma CPU que de outra forma seria incompatível com a máquina selecionada. Entretanto, você pode encontrar incompatibilidades com a BIOS da máquina ou outro software.\n\nA ativação desta configuração não é oficialmente suportada e qualquer relatório de erro arquivado pode ser fechado como inválido." + IDS_2147 "Continuar" + IDS_2148 "Cassete: %s" + IDS_2149 "Imagens de cassete (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Todos os arquivos (*.*)\0*.*\0" + IDS_2150 "Cartucho %i: %ls" + IDS_2151 "Imagens de cartucho (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Todos os arquivos (*.*)\0*.*\0" + IDS_2152 "Erro ao inicializar o renderizador" + IDS_2153 "O renderizador OpenGL (Núcleo 3.0) não pôde ser inicializado. Use outro renderizador." + IDS_2154 "Continuar a execução" + IDS_2155 "Pausar a execução" + IDS_2156 "Pressionar Ctrl+Alt+Del" + IDS_2157 "Pressionar Ctrl+Alt+Esc" + IDS_2158 "Reinicialização completa" + IDS_2159 "Desligamento por ACPI" + IDS_2160 "Configurações" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Disco rígido (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "As unidades de CD-ROM MFM/RLL ou ESDI nunca existiram" + IDS_4100 "Personalizado..." + IDS_4101 "Personalizado (grande)..." + IDS_4102 "Adicionar novo disco rígido" + IDS_4103 "Adicionar disco rígido existente" + IDS_4104 "As imagens de disco HDI não podem ser maiores do que 4GB." + IDS_4105 "As imagens de disco não podem ser maiores do que 127GB." + IDS_4106 "Imagens de disco rígido (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Todos os arquivos (*.*)\0*.*\0" + IDS_4107 "Não foi possível ler o arquivo" + IDS_4108 "Não foi possível escrever o arquivo" + IDS_4109 "Imagens HDI ou HDX com um tamanho de setor que não seja 512 não são suportadas." + IDS_4110 "O USB ainda não é suportado" + IDS_4111 "Esta imagem existe" + IDS_4112 "Digite um nome de arquivo válido." + IDS_4113 "A imagem foi criada com sucesso" + IDS_4114 "Certifique-se de que o arquivo existe e é legível." + IDS_4115 "Certifique-se de que o arquivo está sendo salvo em um diretório gravável." + IDS_4116 "A imagem do disco é muito grande" + IDS_4117 "Lembre-se de particionar e formatar a unidade recém-criada." + IDS_4118 "O arquivo selecionado será sobrescrito. Você tem certeza de que deseja usá-lo?" + IDS_4119 "Imagem de disco sem suporte" + IDS_4120 "Sobrescrever" + IDS_4121 "Não sobrescrever" + IDS_4122 "Imagem bruta (.img)" + IDS_4123 "Imagem HDI (.hdi)" + IDS_4124 "Imagem HDX (.hdx)" + IDS_4125 "VHD de tamanho fixo (.vhd)" + IDS_4126 "VHD de tamanho dinâmico (.vhd)" + IDS_4127 "VHD diferencial (.vhd)" + IDS_4128 "Blocos grandes (2 MB)" + IDS_4129 "Blocos pequenos (512 KB)" + IDS_4130 "Arquivos VHD (*.VHD)\0*.VHD\0Todos os arquivos (*.*)\0*.*\0" + IDS_4131 "Selecione o VHD pai" + IDS_4132 "Isto pode significar que a imagem de origem foi modificada após a criação da imagem diferencial.\n\nTambém pode acontecer caso os arquivos de imagem tenham sido movidos ou copiados, ou por um erro no programa que criou este disco.\n\nVocê quer consertar os marcadores de tempo?" + IDS_4133 "A data/hora dos arquivos de pais e filhos não correspondem" + IDS_4134 "Não foi possível consertar o carimbo de data/hora da VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Desativado" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Desativado" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "RPM perfeita" + IDS_6145 "1% abaixo das RPM perfeita" + IDS_6146 "1.5% abaixo das RPM perfeita" + IDS_6147 "2% abaixo das RPM perfeita" + + IDS_7168 "(Padrão do sistema)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Portuguese (pt-BR) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/pt-PT.rc b/src/win/languages/pt-PT.rc new file mode 100644 index 000000000..314f7ed56 --- /dev/null +++ b/src/win/languages/pt-PT.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Portuguese (Portugal) resources + +#ifdef _WIN32 +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Ação" + BEGIN + MENUITEM "&Teclado requere captura", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&CTRL direito é ALT esquerdo",IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Reinicialização completa...",IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pausa", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Sair...", IDM_ACTION_EXIT + END + POPUP "&Ver" + BEGIN + MENUITEM "&Ocultar barra de estado", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Janela redimensionável", IDM_VID_RESIZE + MENUITEM "&Lembrar tamanho e posição", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Renderizador" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (Núcleo 3.0)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "&Especificar dimensões...", IDM_VID_SPECIFY_DIM + MENUITEM "&Forçar rácio de visualização 4:3", IDM_VID_FORCE43 + POPUP "F&actor de escala de janela" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Método de filtragem" + BEGIN + MENUITEM "&Mais próximo", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear", IDM_VID_FILTER_LINEAR + END + MENUITEM "Escala Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "E&crã cheio\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Modo &de estiramento em ecrã cheio" + BEGIN + MENUITEM "&Estiramento em ecrã cheio", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "Pixels &quadrados (Manter rácio)", IDM_VID_FS_KEEPRATIO + MENUITEM "Escala &inteira", IDM_VID_FS_INT + END + POPUP "Definições E&GA/(S)VGA" + BEGIN + MENUITEM "Monitor VGA &invertido", IDM_VID_INVERT + POPUP "&Tipo de ecrã VGA" + BEGIN + MENUITEM "&Cores RGB", IDM_VID_GRAY_RGB + MENUITEM "&RGB em escala de cinzentos", IDM_VID_GRAY_MONO + MENUITEM "Monitor âmb&ar", IDM_VID_GRAY_AMBER + MENUITEM "Monitor &verde", IDM_VID_GRAY_GREEN + MENUITEM "Monitor &branco", IDM_VID_GRAY_WHITE + END + POPUP "Tipo de &conversão para escala de cinzentos" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Media", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Overscan de CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Mudar &contraste para ecrã monocromático", IDM_VID_CGACON + END + MENUITEM "&Media", IDM_MEDIA + POPUP "&Ferramentas" + BEGIN + MENUITEM "&Definições...", IDM_CONFIG + MENUITEM "&Atualizar ícones da barra de estado", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Gravar imagem de ecrã\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Preferências...", IDM_PREFERENCES + MENUITEM "Ativar integração com &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Ganho de som...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Iniciar o rastreio\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Terminar o rastreio\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Ajuda" + BEGIN + MENUITEM "&Documentação...", IDM_DOCS + MENUITEM "&Acerca do 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagem &existente...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Imagem existente (&Proteção contra escrita)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Gravar", IDM_CASSETTE_RECORD + MENUITEM "&Reproduzir", IDM_CASSETTE_PLAY + MENUITEM "Re&bobinar para o início", IDM_CASSETTE_REWIND + MENUITEM "&Avanço rápido para o fim", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Imagem...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagem &existente...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Imagem existente (&Proteção contra escrita)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&xportar para 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Mute", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&CDROM vazio", IDM_CDROM_EMPTY + MENUITEM "&Recarregar imagem anterior", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Imagem", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagem &existente...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Imagem existente (&Proteção contra escrita)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_ZIP_EJECT + MENUITEM "&Recarregar imagem anterior", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova imagem...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "Imagem &existente...", IDM_MO_IMAGE_EXISTING + MENUITEM "Imagem existente (&Proteção contra escrita)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "E&jetar", IDM_MO_EJECT + MENUITEM "&Recarregar imagem anterior", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Taxa de quadros de destino" + BEGIN + MENUITEM "&Sincronizar com vídeo", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 q/s", IDM_VID_GL_FPS_25 + MENUITEM "&30 q/s", IDM_VID_GL_FPS_30 + MENUITEM "&50 q/s", IDM_VID_GL_FPS_50 + MENUITEM "&60 q/s", IDM_VID_GL_FPS_60 + MENUITEM "&75 q/s", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Selecionar shader...", IDM_VID_GL_SHADER + MENUITEM "&Remover shader", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Preferências" +#define STR_SND_GAIN "Ganho de som" +#define STR_NEW_FLOPPY "Nova imagem" +#define STR_CONFIG "Definições" +#define STR_SPECIFY_DIM "Especificar dimensões da janela principal" + +#define STR_OK "OK" +#define STR_CANCEL "Cancelar" +#define STR_GLOBAL "Guardar estas definições como padrões &globais" +#define STR_DEFAULT "&Padrão" +#define STR_LANGUAGE "Idioma:" +#define STR_ICONSET "Pacote de ícones:" + +#define STR_GAIN "Ganho" + +#define STR_FILE_NAME "Nome:" +#define STR_DISK_SIZE "Tamanho:" +#define STR_RPM_MODE "Modo RPM:" +#define STR_PROGRESS "Progresso:" + +#define STR_WIDTH "Largura:" +#define STR_HEIGHT "Altura:" +#define STR_LOCK_TO_SIZE "Fixar neste tamanho" + +#define STR_MACHINE_TYPE "Tipo de máquina:" +#define STR_MACHINE "Máquina:" +#define STR_CONFIGURE "Configurar" +#define STR_CPU_TYPE "Tipo do CPU:" +#define STR_CPU_SPEED "Velocidade:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Estados de espera:" +#define STR_MB "MB" +#define STR_MEMORY "Memória:" +#define STR_TIME_SYNC "Sincronização da hora" +#define STR_DISABLED "Desativada" +#define STR_ENABLED_LOCAL "Ativada (hora local)" +#define STR_ENABLED_UTC "Ativada (UTC)" +#define STR_DYNAREC "Recompilador dinâmico" + +#define STR_VIDEO "Vídeo:" +#define STR_VOODOO "Gráficos Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Rato:" +#define STR_JOYSTICK "Joystick:" +#define STR_JOY1 "Joystick 1..." +#define STR_JOY2 "Joystick 2..." +#define STR_JOY3 "Joystick 3..." +#define STR_JOY4 "Joystick 4..." + +#define STR_SOUND "Placa de som:" +#define STR_MIDI_OUT "Disp. saída MIDI:" +#define STR_MIDI_IN "Disp. entrada MIDI:" +#define STR_MPU401 "MPU-401 autónomo" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Utilizar som FLOAT32" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Tipo de rede:" +#define STR_PCAP "Dispositivo PCap:" +#define STR_NET "Placa de rede:" + +#define STR_COM1 "Dispositivo COM1:" +#define STR_COM2 "Dispositivo COM2:" +#define STR_COM3 "Dispositivo COM3:" +#define STR_COM4 "Dispositivo COM4:" +#define STR_LPT1 "Dispositivo LPT1:" +#define STR_LPT2 "Dispositivo LPT2:" +#define STR_LPT3 "Dispositivo LPT3:" +#define STR_LPT4 "Dispositivo LPT4:" +#define STR_SERIAL1 "Porta de série 1" +#define STR_SERIAL2 "Porta de série 2" +#define STR_SERIAL3 "Porta de série 3" +#define STR_SERIAL4 "Porta de série 4" +#define STR_PARALLEL1 "Porta paralela 1" +#define STR_PARALLEL2 "Porta paralela 2" +#define STR_PARALLEL3 "Porta paralela 3" +#define STR_PARALLEL4 "Porta paralela 4" + +#define STR_HDC "Controlador HD:" +#define STR_FDC "Controlador FD:" +#define STR_IDE_TER "Controlador IDE terciário" +#define STR_IDE_QUA "Controlador IDE quaternário" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Controlador 1:" +#define STR_SCSI_2 "Controlador 2:" +#define STR_SCSI_3 "Controlador 3:" +#define STR_SCSI_4 "Controlador 4:" +#define STR_CASSETTE "Cassete" + +#define STR_HDD "Discos rígidos:" +#define STR_NEW "&Novo..." +#define STR_EXISTING "&Existente..." +#define STR_REMOVE "&Remover" +#define STR_BUS "Barram.:" +#define STR_CHANNEL "Canal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Especificar..." +#define STR_SECTORS "Sectores:" +#define STR_HEADS "Cabeças:" +#define STR_CYLS "Cilindros:" +#define STR_SIZE_MB "Tamanho (MB):" +#define STR_TYPE "Tipo:" +#define STR_IMG_FORMAT "Formato de imagem:" +#define STR_BLOCK_SIZE "Tamanho de bloco:" + +#define STR_FLOPPY_DRIVES "Unidades de disquete:" +#define STR_TURBO "Velocidade turbo" +#define STR_CHECKBPB "Verificar BPB" +#define STR_CDROM_DRIVES "Unidades CD-ROM:" +#define STR_CD_SPEED "Velocidade:" + +#define STR_MO_DRIVES "Unidades magneto-ópticas:" +#define STR_ZIP_DRIVES "Unidades ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "Expansão de memória ISA" +#define STR_ISAMEM_1 "Placa 1:" +#define STR_ISAMEM_2 "Placa 2:" +#define STR_ISAMEM_3 "Placa 3:" +#define STR_ISAMEM_4 "Placa 4:" +#define STR_BUGGER "Dispositivo ISABugger" +#define STR_POSTCARD "Placa POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Erro" + IDS_2050 "Erro fatal" + IDS_2051 " - PAUSED" + IDS_2052 "Pressione Ctrl+Alt+PgDn para voltar ao modo de janela." + IDS_2053 "Velocidade" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Imagens ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "O 86Box não conseguiu encontrar nenhuma imagem ROM utilizável.\n\nPor favor, vá a href=""https://github.com/86Box/roms/releases/latest"">descarregue um pacote ROM e instale-o na pasta ""roms""." + IDS_2057 "(empty)" + IDS_2058 "Imagens ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Ativado" + IDS_2061 "Desativado" + IDS_2062 "Todas as imagens (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Imagens básicas de sector (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Imagens de superfície (*.86F)\0*.86F\0" + IDS_2063 "A máquina ""%hs"" não está disponível devido à falta de ROMs na pasta roms/machines. A mudar para uma máquina disponível." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "A placa vídeo ""%hs"" não está disponível devido à falta de ROMs na pasta roms/video. A mudar para uma placa vídeo disponível." + IDS_2065 "Máquina" + IDS_2066 "Apresentação" + IDS_2067 "Dispositivos de entrada" + IDS_2068 "Som" + IDS_2069 "Rede" + IDS_2070 "Portas (COM e LPT)" + IDS_2071 "Dispositivos de armazenamento" + IDS_2072 "Discos rígidos" + IDS_2073 "Unidades de disquete e CD-ROM" + IDS_2074 "Outros dispostivos removíveis" + IDS_2075 "Outros dispositivos" + IDS_2076 "Imagens de superfície (*.86F)\0*.86F\0" + IDS_2077 "Clique para capturar o rato" + IDS_2078 "Pressione F8+F12 para soltar o rato" + IDS_2079 "Pressione F8+F12 ou tecla média para soltar o rato" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Não foi possível inicializar o FluidSynth" + IDS_2081 "Barramento" + IDS_2082 "Ficheiro" + IDS_2083 "C" + IDS_2084 "C" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Verificar BPB" + IDS_2088 "KB" + IDS_2089 "Não foi possível inicializar o renderizador vídeo." + IDS_2090 "Padrão" + IDS_2091 "%i estado(s) de espera" + IDS_2092 "Tipo" + IDS_2093 "Falha na configuração de PCap" + IDS_2094 "Não foi encontrado um dispositivo PCap" + IDS_2095 "Dispositivo PCap inválido" + IDS_2096 "Joystick(s) standard de 2 botões" + IDS_2097 "Joystick(s) standard de 4 botões" + IDS_2098 "Joystick(s) standard de 6 botões" + IDS_2099 "Joystick(s) standard de 8 botões" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Nenhum" + IDS_2104 "Não foi possível inicializar os aceleradores de teclado." + IDS_2105 "Não foi possível registar a entrada bruta." + IDS_2106 "%u" + IDS_2107 "%u MB (CCS: %i, %i, %i)" + IDS_2108 "Disquete %i (%s): %ls" + IDS_2109 "Todas as imagens (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Imagens avançadas de sector (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Imagens básicas de sector (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Imagens de fluxo (*.FDI)\0*.FDI\0Imagens de superfície (*.86F;*.MFM)\0*.86F;*.MFM\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2110 "Não foi possível inicializar o FreeType" + IDS_2111 "Não foi possível inicializar o SDL. O ficheiro SDL2.dll é necessário!" + IDS_2112 "Tem a certeza de que quer um reinício completo da máquina emulada?" + IDS_2113 "Tem a certeza de que quer sair do 86Box?" + IDS_2114 "Não foi possível inicializar o Ghostscript" + IDS_2115 "Magneto-óptico %i (%ls): %ls" + IDS_2116 "Imagens magneto-ópticas (*.IM?;*.MDI)\0*.IM?;*.MDI\0Todas as imagens (*.*)\0*.*\0" + IDS_2117 "Bem-vindos ao 86Box!" + IDS_2118 "Controlador interno" + IDS_2119 "Sair" + IDS_2120 "Não foi encontrada nenhuma ROM" + IDS_2121 "Deseja guardar as definições?" + IDS_2122 "Isto irá causar um reinício completo da máquina emulada." + IDS_2123 "Guardar" + IDS_2124 "Acerca do 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Um emulador de computadores antigos\n\nAutores: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nUsado sob a licença GNU General Public License versão 2 ou posterior. Veja o ficheiro LICENSE para mais informações." + IDS_2127 "OK" + IDS_2128 "Hardware não disponível" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Certifique-se de que a biblioteca " LIB_NAME_PCAP " está instalada e de que está a utilizar uma ligação de rede compatível com a biblioteca " LIB_NAME_PCAP "." + IDS_2130 "Configuração inválida" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " é requerida para a emulação de impressora ESC/P." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " é requerido para a conversão automática de ficheiros PostScript para ficheiros PDF.\n\nQualquer documento enviado para a impressora PostScript genérica será gravado como um ficheiro PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " é necessário para a saída MIDI FluidSynth MIDI." + IDS_2134 "A entrar no modo de ecrã cheio" + IDS_2135 "Não mostrar mais esta mensagem" + IDS_2136 "Não sair" + IDS_2137 "Reiniciar" + IDS_2138 "Não reiniciar" + IDS_2139 "Imagens magneto-ópticas (*.IM?;*.MDI)\0*.IM?;*.MDI\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2140 "Imagens CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2141 "Configuração de dispositivo %hs" + IDS_2142 "Ecrã em modo de sono" + IDS_2143 "Shaders OpenGL (*.GLSL)\0*.GLSL\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2144 "Opções de OpenGL" + IDS_2145 "Está a carregar uma configuração sem suporte!" + IDS_2146 "A filtragem do tipo de CPU baseada na máquina escolhida está desativada para esta máquina emulada.\n\nIsto torna possível escolher um CPU que, de outra forma, não seria compatível com a máquina escolhida. No entanto, pode não ser compatível com a BIOS da máquina ou outros programas.\n\nA activação desta definição não tem suporte oficial e qualquer relatório de erros pode ser fechado como inválido." + IDS_2147 "Continuar" + IDS_2148 "Cassete: %s" + IDS_2149 "Imagens de cassete (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2150 "Cartucho %i: %ls" + IDS_2151 "Imagens de cartucho (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Todos os ficheiros (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Disco rígido (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "Unidades CD-ROM com barramento MFM/RLL ou ESDI nunca existiram!" + IDS_4100 "Personalizado..." + IDS_4101 "Personalizado (grande)..." + IDS_4102 "Adicionar novo disco rígido" + IDS_4103 "Adicionar disco rígido existente" + IDS_4104 "As imagens de disco HDI não podem ter mais de 4 GB." + IDS_4105 "As imagens de disco não podem ter mais de 127 GB." + IDS_4106 "Imagens de disco rígido (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Todos os ficheiros (*.*)\0*.*\0" + IDS_4107 "Não foi possível ler o ficheiro" + IDS_4108 "Não foi possível escrever o ficheiro" + IDS_4109 "Imagens HDI ou HDX com um tamanho de sector diferente de 512 não são suportadas." + IDS_4110 "O barramento USB ainda não tem suporte" + IDS_4111 "A imagem de disco já existe" + IDS_4112 "Por favor, especifique um nome de ficheiro válido." + IDS_4113 "Imagem de disco criada" + IDS_4114 "Certifique-se de que o ficheiro existe e é legível." + IDS_4115 "Certifique-se de que o ficheiro está a ser guardado numa pasta editável." + IDS_4116 "Imagem de disco muito grande" + IDS_4117 "Lembre-se de particionar e formatar o novo disco criado." + IDS_4118 "O ficheiro selecionado será sobrescrito. Tem a certeza de que quer utilizá-lo?" + IDS_4119 "Imagem de disco sem suporte" + IDS_4120 "Sobrescrever" + IDS_4121 "Não sobrescrever" + IDS_4122 "Imagem bruta (.img)" + IDS_4123 "Imagem HDI (.hdi)" + IDS_4124 "Imagem HDX (.hdx)" + IDS_4125 "VHD com tamanho fixo (.vhd)" + IDS_4126 "VHD com tamanho dinâmico (.vhd)" + IDS_4127 "VHD diferenciador (.vhd)" + IDS_4128 "Blocos grandes (2 MB)" + IDS_4129 "Blocos pequenos (512 KB)" + IDS_4130 "Ficheiros VHD (*.VHD)\0*.VHD\0Todos os ficheiros (*.*)\0*.*\0" + IDS_4131 "Seleccione o VHD pai" + IDS_4132 "Isto pode significar que a imagem pai foi modificada depois da criação da imagem diferenciadora.\n\nTambém pode acontecer se os ficheiros da imagem foram movidos ou copiados ou por causa de um erro no programa que criou este disco.\n\nQuer corrigir os carimbos de data/hora?" + IDS_4133 "Os carimbos de data/hora dos discos pai e filho não correspondem!" + IDS_4134 "Não foi possível corrigir o carimbo de data/hora do VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Desativado" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Desativado" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "RPM perfeito" + IDS_6145 "RPM 1% abaixo do RPM perfeito" + IDS_6146 "RPM 1.5% abaixo do RPM perfeito" + IDS_6147 "RPM 2% abaixo do RPM perfeito" + + IDS_7168 "(Padrão do sistema)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Portuguese (Portugal) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/ru-RU.rc b/src/win/languages/ru-RU.rc new file mode 100644 index 000000000..e88d9668e --- /dev/null +++ b/src/win/languages/ru-RU.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Russian resources + +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Действие" + BEGIN + MENUITEM "&Клавиатура требует захвата", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Правый CTRL - это левый ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Холодная перезагрузка...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Пауза", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Выход...", IDM_ACTION_EXIT + END + POPUP "&Вид" + BEGIN + MENUITEM "&Скрыть строку состояния", IDM_VID_HIDE_STATUS_BAR + MENUITEM "С&крыть панель инструментов", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Изменяемый размер окна", IDM_VID_RESIZE + MENUITEM "&Запомнить размер и положение", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Рендеринг" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "&Указать размеры...", IDM_VID_SPECIFY_DIM + MENUITEM "У&становить соотношение сторон 4:3", IDM_VID_FORCE43 + POPUP "&Масштаб окна" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Метод фильтрации" + BEGIN + MENUITEM "&Ближайший", IDM_VID_FILTER_NEAREST + MENUITEM "&Линейный", IDM_VID_FILTER_LINEAR + END + MENUITEM "Масштабирование Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Полноэкранный режим\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "&Растягивание в полноэкранном режиме" + BEGIN + MENUITEM "&На весь экран", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Квадратные пиксели (сохранить соотношение)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Целочисленное масштабирование", IDM_VID_FS_INT + END + POPUP "Настройки E&GA/(S)VGA" + BEGIN + MENUITEM "&Инвертировать цвета VGA", IDM_VID_INVERT + POPUP "&Тип экрана VGA" + BEGIN + MENUITEM "RGB &цветной", IDM_VID_GRAY_RGB + MENUITEM "&RGB монохромный", IDM_VID_GRAY_MONO + MENUITEM "&Янтарный оттенок", IDM_VID_GRAY_AMBER + MENUITEM "&Зелёный оттенок", IDM_VID_GRAY_GREEN + MENUITEM "&Белый оттенок", IDM_VID_GRAY_WHITE + END + POPUP "Тип монохромного &конвертирования" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Усреднённый", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Вылеты развёртки CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Изменить контрастность &монохромного дисплея", IDM_VID_CGACON + END + MENUITEM "&Носители", IDM_MEDIA + POPUP "&Инструменты" + BEGIN + MENUITEM "&Настройки машины...", IDM_CONFIG + MENUITEM "&Обновление значков строки состояния", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Сделать с&криншот\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Параметры...", IDM_PREFERENCES + MENUITEM "Включить интеграцию &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Усиление звука...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Начать трассировку\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Завершить трассировку\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Помощь" + BEGIN + MENUITEM "&Документация...", IDM_DOCS + MENUITEM "&О программе 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новый образ...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Выбрать образ...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Выбрать образ (&Защита от записи)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Запись", IDM_CASSETTE_RECORD + MENUITEM "&Воспроизведение", IDM_CASSETTE_PLAY + MENUITEM "&Перемотка на начало", IDM_CASSETTE_REWIND + MENUITEM "&Перемотка в конец", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "И&звлечь", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Образ...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "И&звлечь", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новый образ...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Выбрать образ...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Выбрать образ (&Защита от записи)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "Э&кспорт в 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "И&звлечь", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "О&тключить звук", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "П&устой", IDM_CDROM_EMPTY + MENUITEM "&Снова загрузить предыдущий образ", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Образ...", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новый образ...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Выбрать образ...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Выбрать образ (&Защита от записи)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "И&звлечь", IDM_ZIP_EJECT + MENUITEM "&Снова загрузить предыдущий образ", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новый образ...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Выбрать образ...", IDM_MO_IMAGE_EXISTING + MENUITEM "Выбрать образ (&Защита от записи)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "И&звлечь", IDM_MO_EJECT + MENUITEM "&Снова загрузить предыдущий образ", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Целевая &частота кадров" + BEGIN + MENUITEM "&Синхронизация с видео", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 кадров в секунду", IDM_VID_GL_FPS_25 + MENUITEM "&30 кадров в секунду", IDM_VID_GL_FPS_30 + MENUITEM "&50 кадров в секунду", IDM_VID_GL_FPS_50 + MENUITEM "&60 кадров в секунду", IDM_VID_GL_FPS_60 + MENUITEM "&75 кадров в секунду", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Выбрать шейдер...", IDM_VID_GL_SHADER + MENUITEM "&Удалить шейдер", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Параметры" +#define STR_SND_GAIN "Усиление звука" +#define STR_NEW_FLOPPY "Новый образ" +#define STR_CONFIG "Настройки" +#define STR_SPECIFY_DIM "Указать размеры главного окна" + +#define STR_OK "OK" +#define STR_CANCEL "Отмена" +#define STR_GLOBAL "Сохранить эти параметры как &глобальные по умолчанию" +#define STR_DEFAULT "&По умолчанию" +#define STR_LANGUAGE "Язык:" +#define STR_ICONSET "Набор иконок:" + +#define STR_GAIN "Усиление" + +#define STR_FILE_NAME "Имя файла:" +#define STR_DISK_SIZE "Размер диска:" +#define STR_RPM_MODE "RPM режим:" +#define STR_PROGRESS "Прогресс:" + +#define STR_WIDTH "Ширина:" +#define STR_HEIGHT "Высота:" +#define STR_LOCK_TO_SIZE "Зафиксировать размер" + +#define STR_MACHINE_TYPE "Тип машины:" +#define STR_MACHINE "Системная плата:" +#define STR_CONFIGURE "Настройка" +#define STR_CPU_TYPE "Тип ЦП:" +#define STR_CPU_SPEED "Скорость:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Циклы ожидания:" +#define STR_MB "МБ" +#define STR_MEMORY "Память:" +#define STR_TIME_SYNC "Синхронизация времени" +#define STR_DISABLED "Отключить" +#define STR_ENABLED_LOCAL "Включить (местное)" +#define STR_ENABLED_UTC "Включить (UTC)" +#define STR_DYNAREC "Динамический рекомпилятор" + +#define STR_VIDEO "Видеокарта:" +#define STR_VOODOO "Ускоритель Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Мышь:" +#define STR_JOYSTICK "Джойстик:" +#define STR_JOY1 "Джойстик 1..." +#define STR_JOY2 "Джойстик 2..." +#define STR_JOY3 "Джойстик 3..." +#define STR_JOY4 "Джойстик 4..." + +#define STR_SOUND "Звуковая карта:" +#define STR_MIDI_OUT "MIDI Out устр-во:" +#define STR_MIDI_IN "MIDI In устр-во:" +#define STR_MPU401 "Отдельный MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32 звук" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Тип сети:" +#define STR_PCAP "Устройство PCap:" +#define STR_NET "Сетевая карта:" + +#define STR_COM1 "Устройство COM1:" +#define STR_COM2 "Устройство COM2:" +#define STR_COM3 "Устройство COM3:" +#define STR_COM4 "Устройство COM4:" +#define STR_LPT1 "Устройство LPT1:" +#define STR_LPT2 "Устройство LPT2:" +#define STR_LPT3 "Устройство LPT3:" +#define STR_LPT4 "Устройство LPT4:" +#define STR_SERIAL1 "Последов. порт COM1" +#define STR_SERIAL2 "Последов. порт COM2" +#define STR_SERIAL3 "Последов. порт COM3" +#define STR_SERIAL4 "Последов. порт COM4" +#define STR_PARALLEL1 "Параллельный порт LPT1" +#define STR_PARALLEL2 "Параллельный порт LPT2" +#define STR_PARALLEL3 "Параллельный порт LPT3" +#define STR_PARALLEL4 "Параллельный порт LPT4" + +#define STR_HDC "Контроллер HD:" +#define STR_FDC "Контроллер FD:" +#define STR_IDE_TER "Третичный IDE контроллер" +#define STR_IDE_QUA "Четвертичный IDE контроллер" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Контроллер 1:" +#define STR_SCSI_2 "Контроллер 2:" +#define STR_SCSI_3 "Контроллер 3:" +#define STR_SCSI_4 "Контроллер 4:" +#define STR_CASSETTE "Кассета" + +#define STR_HDD "Жёсткие диски:" +#define STR_NEW "&Создать..." +#define STR_EXISTING "&Выбрать..." +#define STR_REMOVE "&Убрать" +#define STR_BUS "Шина:" +#define STR_CHANNEL "Канал:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Указать..." +#define STR_SECTORS "Сектора:" +#define STR_HEADS "Головки:" +#define STR_CYLS "Цилиндры:" +#define STR_SIZE_MB "Размер (МБ):" +#define STR_TYPE "Тип:" +#define STR_IMG_FORMAT "Тип образа:" +#define STR_BLOCK_SIZE "Размер блока:" + +#define STR_FLOPPY_DRIVES "Гибкие диски:" +#define STR_TURBO "Турбо тайминги" +#define STR_CHECKBPB "Проверять BPB" +#define STR_CDROM_DRIVES "Дисководы CD-ROM:" +#define STR_CD_SPEED "Скорость:" + +#define STR_MO_DRIVES "Магнитооптические дисководы:" +#define STR_ZIP_DRIVES "ZIP дисководы:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "Карта расширения памяти (ISA)" +#define STR_ISAMEM_1 "Карта 1:" +#define STR_ISAMEM_2 "Карта 2:" +#define STR_ISAMEM_3 "Карта 3:" +#define STR_ISAMEM_4 "Карта 4:" +#define STR_BUGGER "Устройство ISABugger" +#define STR_POSTCARD "Карта POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Ошибка" + IDS_2050 "Неустранимая ошибка" + IDS_2051 " - ПАУЗА" + IDS_2052 "Нажмите Ctrl+Alt+PgDn для возврата в оконный режим." + IDS_2053 "Скорость" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Образы ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box не смог найти ни одного подходящего для использования файла с ПЗУ.\n\nПожалуйста скачайте набор ПЗУ и извлеките его в каталог ""roms""." + IDS_2057 "(пусто)" + IDS_2058 "Образы ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Все файлы (*.*)\0*.*\0" + IDS_2059 "Турбо" + IDS_2060 "Вкл" + IDS_2061 "Выкл" + IDS_2062 "Все образы (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Простые посекторные образы (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface образы (*.86F)\0*.86F\0" + IDS_2063 "Системная плата ""%hs"" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/machines. Переключение на доступную системную плату." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Видеокарта ""%hs"" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Переключение на доступную видеокарту." + IDS_2065 "Компьютер" + IDS_2066 "Дисплей" + IDS_2067 "Устройства ввода" + IDS_2068 "Звук" + IDS_2069 "Сеть" + IDS_2070 "Порты (COM и LPT)" + IDS_2071 "Контроллеры дисков" + IDS_2072 "Жёсткие диски" + IDS_2073 "Гибкие диски и CD-ROM" + IDS_2074 "Другие съёмные устр-ва" + IDS_2075 "Другая периферия" + IDS_2076 "Образы Surface (*.86F)\0*.86F\0" + IDS_2077 "Щёлкните мышью для захвата курсора" + IDS_2078 "Нажмите F8+F12 чтобы освободить курсор" + IDS_2079 "Нажмите F8+F12 или среднюю кнопку мыши чтобы освободить курсор" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Невозможно инициализировать FluidSynth" + IDS_2081 "Шина" + IDS_2082 "Файл" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "МБ" + IDS_2087 "Проверять BPB" + IDS_2088 "КБ" + IDS_2089 "Не удалось инициализировать рендерер видео." + IDS_2090 "По умолчанию" + IDS_2091 "%i WS" + IDS_2092 "Тип" + IDS_2093 "Не удалось настроить PCap" + IDS_2094 "Устройства PCap не найдены" + IDS_2095 "Неверное устройство PCap" + IDS_2096 "Стандартный 2-кнопочный джойстик" + IDS_2097 "Стандартный 4-кнопочный джойстик" + IDS_2098 "Стандартный 6-кнопочный джойстик" + IDS_2099 "Стандартный 8-кнопочный джойстик" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Система управления полетом Thrustmaster" + IDS_2103 "Нет" + IDS_2104 "Невозможно загрузить ускорители клавиатуры." + IDS_2105 "Невозможно зарегистрировать необработанный (RAW) ввод." + IDS_2106 "%u" + IDS_2107 "%u МБ (CHS: %i, %i, %i)" + IDS_2108 "Дисковод %i (%s): %ls" + IDS_2109 "Все образы (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Расширенные образы секторов (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Основные образы секторов (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Образы Flux (*.FDI)\0*.FDI\0Образы Surface (*.86F;*.MFM)\0*.86F;*.MFM\0Все файлы (*.*)\0*.*\0" + IDS_2110 "Невозможно инициализировать FreeType" + IDS_2111 "Невозможно инициализировать SDL, требуется SDL2.dll" + IDS_2112 "Вы уверены, что хотите выполнить холодную перезагрузку эмулируемой машины?" + IDS_2113 "Вы уверены, что хотите выйти из 86Box?" + IDS_2114 "Невозможно инициализировать Ghostscript" + IDS_2115 "Магнитооптический %i (%ls): %ls" + IDS_2116 "Образы магнитооптических дисков (*.IM?;*.MDI)\0*.IM?;*.MDI\0Все файлы (*.*)\0*.*\0" + IDS_2117 "Добро пожаловать в 86Box!" + IDS_2118 "Встроенный контроллер" + IDS_2119 "Выход" + IDS_2120 "ПЗУ не найдены" + IDS_2121 "Хотите ли вы сохранить настройки?" + IDS_2122 "Это приведет к холодной перезагрузке эмулируемой машины." + IDS_2123 "Сохранить" + IDS_2124 "О 86Box" + IDS_2125 "86Box v." EMU_VERSION + + IDS_2126 "Эмулятор старых компьютеров\n\nАвторы: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nВыпускается под лицензией GNU General Public License версии 2 или более поздней. Дополнительную информацию см. в файле LICENSE." + IDS_2127 "OK" + IDS_2128 "Оборудование недоступно" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Убедитесь, что " LIB_NAME_PCAP " установлен и ваше сетевое соединение, совместимо с " LIB_NAME_PCAP "." + IDS_2130 "Недопустимая конфигурация" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 "Для эмуляции принтера ESC/P требуется " LIB_NAME_FREETYPE "." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " требуется для автоматического преобразования файлов PostScript в PDF.\n\nВсе документы, отправленные на общий принтер PostScript, будут сохранены в виде файлов PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 "Для FluidSynth MIDI-вывода требуется " LIB_NAME_FLUIDSYNTH "." + IDS_2134 "Вход в полноэкранный режим" + IDS_2135 "Больше не показывать это сообщение" + IDS_2136 "Не выходить" + IDS_2137 "Перезагрузить" + IDS_2138 "Не перезагружать" + IDS_2139 "Образы магнитооптических дисков (*.IM?;*.MDI)\0*.IM?;*.MDI\0Все файлы (*.*)\0*.*\0" + IDS_2140 "Образы CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Все файлы (*.*)\0*.*\0" + IDS_2141 "Конфигурация устройства %hs" + IDS_2142 "Монитор в спящем режиме" + IDS_2143 "Шейдеры OpenGL (*.GLSL)\0*.GLSL\0Все файлы (*.*)\0*.*\0" + IDS_2144 "Параметры OpenGL" + IDS_2145 "Вы загружаете неподдерживаемую конфигурацию" + IDS_2146 "Выбор типов ЦП для этой системной платы на данной эмулируемой машине отключен.\n\nЭто позволяет выбрать процессор, который в противном случае несовместим с выбранной материнской платой. Однако, вы можете столкнуться с несовместимостью с BIOS материнской платы или другим ПО.\n\nВключение этого параметра официально не поддерживается, и все поданные отчеты об ошибках могут быть закрыты как недействительные." + IDS_2147 "Продолжить" + IDS_2148 "Кассета: %s" + IDS_2149 "Образы кассет (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Все файлы (*.*)\0*.*\0" + IDS_2150 "Картридж %i: %ls" + IDS_2151 "Образы картриджей (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Все файлы (*.*)\0*.*\0" + IDS_2152 "Ошибка инициализации рендерера" + IDS_2153 "Невозможно инициализировать рендерер OpenGL (3.0). Пожалуйста, используйте другой рендерер." + IDS_2154 "Возобновить выполнение" + IDS_2155 "Приостановить выполнение" + IDS_2156 "Нажать Ctrl+Alt+Del" + IDS_2157 "Нажать Ctrl+Alt+Esc" + IDS_2158 "Холодная перезагрузка" + IDS_2159 "Сигнал завершения ACPI" + IDS_2160 "Настройки машины" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Жёсткий диск (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL или ESDI дисководов CD-ROM никогда не существовало" + IDS_4100 "Задать вручную..." + IDS_4101 "Задать вручную (large)..." + IDS_4102 "Создать новый жёсткий диск" + IDS_4103 "Выбрать существующий жёсткий диск" + IDS_4104 "Размер образов дисков HDI не может превышать 4 ГБ." + IDS_4105 "Размер образов дисков не может превышать 127 ГБ." + IDS_4106 "Образы жёстких дисков (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Все файлы (*.*)\0*.*\0" + IDS_4107 "Невозможно прочитать файл" + IDS_4108 "Невозможно записать файл" + IDS_4109 "Образы HDI или HDX с размером сектора, отличным от 512, не поддерживаются." + IDS_4110 "USB пока не поддерживается" + IDS_4111 "Файл образа диска уже существует" + IDS_4112 "Пожалуйста, укажите правильное имя файла." + IDS_4113 "Образ диска создан" + IDS_4114 "Убедитесь, что файл существует и доступен для чтения." + IDS_4115 "Убедитесь, что файл сохраняется в директории доступной для записи." + IDS_4116 "Слишком большой образ диска" + IDS_4117 "Не забудьте разметить и отформатировать вновь созданный диск." + IDS_4118 "Выбранный файл будет перезаписан. Вы уверены, что хотите использовать его?" + IDS_4119 "Неподдерживаемый образ диска" + IDS_4120 "Перезаписать" + IDS_4121 "Не перезаписывать" + IDS_4122 "RAW образ (.img)" + IDS_4123 "Образ HDI (.hdi)" + IDS_4124 "Образ HDX (.hdx)" + IDS_4125 "VHD фиксированного размера (.vhd)" + IDS_4126 "VHD динамического размера (.vhd)" + IDS_4127 "Дифференцированный образ VHD (.vhd)" + IDS_4128 "Большие блоки (2 МБ)" + IDS_4129 "Маленькие блоки (512 КБ)" + IDS_4130 "Файлы VHD (*.VHD)\0*.VHD\0Все файлы (*.*)\0*.*\0" + IDS_4131 "Выберите родительский VHD" + IDS_4132 "Это может означать, что родительский образ был изменён после того, как был создан дифференцированный образ.\n\nЭто также может произойти, если файлы образа были перемещены или скопированы, или из-за ошибки в программе, создавшей этот диск.\n\nВы хотите исправить временные метки?" + IDS_4133 "Временные метки родительского и дочернего дисков не совпадают" + IDS_4134 "Не удалось исправить временную метку VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Отключён" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Отключён" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 кБ" + IDS_5889 "180 кБ" + IDS_5890 "320 кБ" + IDS_5891 "360 кБ" + IDS_5892 "640 кБ" + IDS_5893 "720 кБ" + IDS_5894 "1.2 МБ" + IDS_5895 "1.25 МБ" + IDS_5896 "1.44 МБ" + IDS_5897 "DMF (кластер 1024)" + IDS_5898 "DMF (кластер 2048)" + IDS_5899 "2.88 МБ" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 МБ (ISO 10090)" + IDS_5903 "3.5"" 230 МБ (ISO 13963)" + IDS_5904 "3.5"" 540 МБ (ISO 15498)" + IDS_5905 "3.5"" 640 МБ (ISO 15498)" + IDS_5906 "3.5"" 1.3 ГБ (GigaMO)" + IDS_5907 "3.5"" 2.3 ГБ (GigaMO 2)" + IDS_5908 "5.25"" 600 МБ" + IDS_5909 "5.25"" 650 МБ" + IDS_5910 "5.25"" 1 ГБ" + IDS_5911 "5.25"" 1.3 ГБ" + + IDS_6144 "Точный RPM" + IDS_6145 "На 1% медленнее точного RPM" + IDS_6146 "На 1.5% медленнее точного RPM" + IDS_6147 "На 2% медленнее точного RPM" + + IDS_7168 "(Системный)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Russian resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/sl-SI.rc b/src/win/languages/sl-SI.rc new file mode 100644 index 000000000..e8672235f --- /dev/null +++ b/src/win/languages/sl-SI.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Slovenian resources + +#ifdef _WIN32 +LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Dejanja" + BEGIN + MENUITEM "&Tipkovnica potrebuje zajem", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Desni CTRL je levi ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Ponovni zagon...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Premor", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "Iz&hod...", IDM_ACTION_EXIT + END + POPUP "&Pogled" + BEGIN + MENUITEM "&Skrij statusno vrstico", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "S&premenljiva velikost okna", IDM_VID_RESIZE + MENUITEM "&Zapomni si velikost in položaj", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Upodabljanje" + BEGIN + MENUITEM "&SDL (programsko)", IDM_VID_SDL_SW + MENUITEM "SDL (s&trojno)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (Jedro 3.0)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "&Določi velikost...", IDM_VID_SPECIFY_DIM + MENUITEM "&Vsili 4:3 razmerje zaslona", IDM_VID_FORCE43 + POPUP "&Faktor velikosti okna" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "&Metoda filtriranja" + BEGIN + MENUITEM "&Najbližja", IDM_VID_FILTER_NEAREST + MENUITEM "&Linearna", IDM_VID_FILTER_LINEAR + END + MENUITEM "&Raztezanje za visok DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Celozaslonski način\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "&Način celozaslonskega raztezanja" + BEGIN + MENUITEM "&Raztegni na celoten zaslon", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Kvadratni piksli (ohrani razmerje)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Celoštevilsko raztezanje", IDM_VID_FS_INT + END + POPUP "Nastavitve E&GA/(S)VGA" + BEGIN + MENUITEM "&Obrni barve zaslona VGA", IDM_VID_INVERT + POPUP "&Vrsta zaslona VGA" + BEGIN + MENUITEM "&Barvni RGB", IDM_VID_GRAY_RGB + MENUITEM "&Sivinski RGB", IDM_VID_GRAY_MONO + MENUITEM "&Rumeni zaslon", IDM_VID_GRAY_AMBER + MENUITEM "&Zeleni zaslon", IDM_VID_GRAY_GREEN + MENUITEM "B&eli zaslon", IDM_VID_GRAY_WHITE + END + POPUP "V&rsta pretvorbe sivin" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Povprečje", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "&Presežek slike CGA/PCjr/Tandy/EGA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "&Spremeni contrast za črno-beli zaslon", IDM_VID_CGACON + END + MENUITEM "&Mediji", IDM_MEDIA + POPUP "&Orodja" + BEGIN + MENUITEM "&Nastavitve...", IDM_CONFIG + MENUITEM "&Posodabljaj ikone statusne vrstice", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "&Zajemi posnetek zaslona\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Možnosti...", IDM_PREFERENCES + MENUITEM "Omogoči integracijo s programom &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Ojačanje zvoka...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Z&ačni sledenje\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "&Končaj sledenje\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Pomoč" + BEGIN + MENUITEM "&Dokumentacija...", IDM_DOCS + MENUITEM "&O programu 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Obstoječa slika...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Obstoječa slika (&samo za branje)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "Snemaj", IDM_CASSETTE_RECORD + MENUITEM "Predvajaj", IDM_CASSETTE_PLAY + MENUITEM "Previj na začetek", IDM_CASSETTE_REWIND + MENUITEM "Preskoči na konec", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "Izvrzi", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "Slika...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "Izvrzi", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Obstoječa slika...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Obstoječa slika (&samo za branje)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Izvozi v 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "I&zvrzi", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Utišaj", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Prazen", IDM_CDROM_EMPTY + MENUITEM "&Naloži zadnjo sliko", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Slika", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Obstoječa slika...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Obstoječa slika (&samo za branje)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "I&zvrzi", IDM_ZIP_EJECT + MENUITEM "&Naloži zadnjo sliko", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nova slika...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Obstoječa slika...", IDM_MO_IMAGE_EXISTING + MENUITEM "Obstoječa slika (&samo za branje)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "I&zvrzi", IDM_MO_EJECT + MENUITEM "&Naloži zadnjo sliko", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "&Ciljno št. sličic na sekundo" + BEGIN + MENUITEM "&Sinhroniziraj z videom", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Izberi senčilnik...", IDM_VID_GL_SHADER + MENUITEM "&Odstrani senčilnik", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Možnosti" +#define STR_SND_GAIN "Ojačanje zvoka" +#define STR_NEW_FLOPPY "Nova slika" +#define STR_CONFIG "Nastavitve" +#define STR_SPECIFY_DIM "Določi velikost glavnega okna" + +#define STR_OK "V redu" +#define STR_CANCEL "Prekliči" +#define STR_GLOBAL "Shrani te nastavitve kot globalne privzete" +#define STR_DEFAULT "Privzeto" +#define STR_LANGUAGE "Jezik:" +#define STR_ICONSET "Komplet ikon:" + +#define STR_GAIN "Ojačanje" + +#define STR_FILE_NAME "Ime datoteke:" +#define STR_DISK_SIZE "Velikost diska:" +#define STR_RPM_MODE "Način števila obratov:" +#define STR_PROGRESS "Napredek:" + +#define STR_WIDTH "Širina:" +#define STR_HEIGHT "Višina:" +#define STR_LOCK_TO_SIZE "Zakleni na to velikost" + +#define STR_MACHINE_TYPE "Vrsta sistema:" +#define STR_MACHINE "Sistem:" +#define STR_CONFIGURE "Nastavi" +#define STR_CPU_TYPE "Vrsta procesorja:" +#define STR_CPU_SPEED "Hitrost:" +#define STR_FPU "Procesor plavajoče vejice:" +#define STR_WAIT_STATES "Čakalna stanja:" +#define STR_MB "MB" +#define STR_MEMORY "Spomin:" +#define STR_TIME_SYNC "Sinhronizacija časa" +#define STR_DISABLED "Onemogočeno" +#define STR_ENABLED_LOCAL "Omogočeno (lokalni čas)" +#define STR_ENABLED_UTC "Omogočeno (UTC)" +#define STR_DYNAREC "Dinamični prevajalnik" + +#define STR_VIDEO "Video:" +#define STR_VOODOO "Voodoo grafika" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Miška:" +#define STR_JOYSTICK "Igralna palica:" +#define STR_JOY1 "Igralna palica 1..." +#define STR_JOY2 "Igralna palica 2..." +#define STR_JOY3 "Igralna palica 3..." +#define STR_JOY4 "Igralna palica 4..." + +#define STR_SOUND "Zvočna kartica:" +#define STR_MIDI_OUT "Izhodna naprava MIDI:" +#define STR_MIDI_IN "Vhodna naprava MIDI:" +#define STR_MPU401 "Samostojen MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "Uporabi FLOAT32 za zvok" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Vrsta omrežja:" +#define STR_PCAP "Naprava PCap:" +#define STR_NET "Omrežna kartica:" + +#define STR_COM1 "Naprava COM1:" +#define STR_COM2 "Naprava COM2:" +#define STR_COM3 "Naprava COM3:" +#define STR_COM4 "Naprava COM4:" +#define STR_LPT1 "Naprava LPT1:" +#define STR_LPT2 "Naprava LPT2:" +#define STR_LPT3 "Naprava LPT3:" +#define STR_LPT4 "Naprava LPT4:" +#define STR_SERIAL1 "Serijska vrata 1" +#define STR_SERIAL2 "Serijska vrata 2" +#define STR_SERIAL3 "Serijska vrata 3" +#define STR_SERIAL4 "Serijska vrata 4" +#define STR_PARALLEL1 "Paralelna vrata 1" +#define STR_PARALLEL2 "Paralelna vrata 2" +#define STR_PARALLEL3 "Paralelna vrata 3" +#define STR_PARALLEL4 "Paralelna vrata 4" + +#define STR_HDC "Krmilnik trdega diska:" +#define STR_FDC "Krmilnik disketnika:" +#define STR_IDE_TER "Terciarni krmilnik IDE" +#define STR_IDE_QUA "Kvartarni krmilnik IDE" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Krmilnik 1:" +#define STR_SCSI_2 "Krmilnik 2:" +#define STR_SCSI_3 "Krmilnik 3:" +#define STR_SCSI_4 "Krmilnik 4:" +#define STR_CASSETTE "Kasetnik" + +#define STR_HDD "Trdi diski:" +#define STR_NEW "Nov..." +#define STR_EXISTING "Obstoječ..." +#define STR_REMOVE "Odstrani" +#define STR_BUS "Vodilo:" +#define STR_CHANNEL "Kanal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "Določi..." +#define STR_SECTORS "Sektorji:" +#define STR_HEADS "Glave:" +#define STR_CYLS "Cilindri:" +#define STR_SIZE_MB "Velikost (MB):" +#define STR_TYPE "Vrsta:" +#define STR_IMG_FORMAT "Format slike:" +#define STR_BLOCK_SIZE "Velikost bloka:" + +#define STR_FLOPPY_DRIVES "Disketni pogoni:" +#define STR_TURBO "Turbo časovniki" +#define STR_CHECKBPB "Preverjaj BPB" +#define STR_CDROM_DRIVES "Pogoni CD-ROM:" +#define STR_CD_SPEED "Hitrost:" + +#define STR_MO_DRIVES "Magnetno-optični pogoni:" +#define STR_ZIP_DRIVES "Pogoni ZIP:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "Ura v realnem času ISA:" +#define STR_ISAMEM "Razširitev spomina ISA" +#define STR_ISAMEM_1 "Kartica 1:" +#define STR_ISAMEM_2 "Kartica 2:" +#define STR_ISAMEM_3 "Kartica 3:" +#define STR_ISAMEM_4 "Kartica 4:" +#define STR_BUGGER "Naprava ISABugger" +#define STR_POSTCARD "Kartica POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Napaka" + IDS_2050 "Kritična napaka" + IDS_2051 " - PAUSED" + IDS_2052 "Pritisnite Ctrl+Alt+PgDn za povratek iz celozaslonskega načina." + IDS_2053 "Hitrost" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP slike (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box ni našel nobenih uporabnih ROM slik.\n\nProsim prenesite set ROM-ov in ga razširite v mapo ""roms""." + IDS_2057 "(prazno)" + IDS_2058 "ZIP slike (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Vse datoteke (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Vključeno" + IDS_2061 "Izključeno" + IDS_2062 "Vse slike (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Osnovne sektorske slike (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Površinske slike (*.86F)\0*.86F\0" + IDS_2063 "Sistem ""%hs"" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/machines. Preklapljam na drug sistem, ki je na voljo." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Grafična kartica ""%hs"" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/video. Preklapljam na drugo grafično kartico, ki je na voljo.." + IDS_2065 "Sistem" + IDS_2066 "Zaslon" + IDS_2067 "Vhodne naprave" + IDS_2068 "Zvok" + IDS_2069 "Omrežje" + IDS_2070 "Vrata (COM & LPT)" + IDS_2071 "Krmilniki shrambe" + IDS_2072 "Trdi diski" + IDS_2073 "Disketni in CD-ROM pogoni" + IDS_2074 "Druge odstranljive naprave" + IDS_2075 "Druga periferija" + IDS_2076 "Površinske slike (*.86F)\0*.86F\0" + IDS_2077 "Kliknite za zajem miške" + IDS_2078 "Pritisnite F8+F12 za izpust miške" + IDS_2079 "Pritisnite F8+F12 ali srednji gumb za izpust miške" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Ne morem inicializirati FluidSynth" + IDS_2081 "Vodilo" + IDS_2082 "Datoteka" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "Preveri BPB" + IDS_2088 "KB" + IDS_2089 "Ne morem inicializirati pogona upodabljanja." + IDS_2090 "Privzeto" + IDS_2091 "%i stanj čakanja" + IDS_2092 "Vrsta" + IDS_2093 "Nastavitev PCap ni uspela" + IDS_2094 "Nobena naprava PCap ni bila najdena" + IDS_2095 "Neveljavna naprava PCap" + IDS_2096 "Standardna krmilna palica z 2 gumboma" + IDS_2097 "Standardna krmilna palica s 4 gumbi" + IDS_2098 "Standardna krmilna palica s 6 gumbi" + IDS_2099 "Standardna krmilna palica z 8 gumbi" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "Brez" + IDS_2104 "Ne morem naložiti pospeševalnikov tipkovnice." + IDS_2105 "Ne morem registrirati neobdelanega vnosa." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Disketa %i (%s): %ls" + IDS_2109 "Vse slike (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Napredne sektorske slike (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Osnovne sektorske slike (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Tokovne slike (*.FDI)\0*.FDI\0Površinske slike (*.86F;*.MFM)\0*.86F;*.MFM\0Vse datoteke (*.*)\0*.*\0" + IDS_2110 "Ne morem inicializirati FreeType" + IDS_2111 "Ne morem inicializirati SDL, potrebna je knjižica SDL2.dll" + IDS_2112 "Ste prepričani, da želite ponovno zagnati emulirani sistem?" + IDS_2113 "Ste prepričani, da želite zapreti 86Box?" + IDS_2114 "Ne morem inicializirati Ghostscript" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "Slike MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0Vse datoteke (*.*)\0*.*\0" + IDS_2117 "Dobrodošli v 86Box!" + IDS_2118 "Notranji krmilnik" + IDS_2119 "Izhod" + IDS_2120 "Nobeni ROM-i niso bili najdeni" + IDS_2121 "Želite shraniti nastavitve?" + IDS_2122 "To bo ponovno zagnalo emuliran sistem." + IDS_2123 "Shrani" + IDS_2124 "O programu 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Emulator starih računalnikov\n\nAvtorji: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho in drugi.\n\nIzdano pod licenco GNU General Public License različica 2 ali novejša. Glej datoteko LICENSE za več informacij." + IDS_2127 "V redu" + IDS_2128 "Strojna oprema ni na voljo" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Prepičajte se, da je nameščen " LIB_NAME_PCAP " in da ste na omrežni povezavi, združljivi z " LIB_NAME_PCAP + IDS_2130 "Neveljavna konfiguracija" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " je potreben za emuliranje ESC/P tiskalnika." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " je potreben za samodejno pretvorbo PostScript datotek v PDF.\n\nVsi dokumenti, poslani generičnemu PostScript tiskalniku bodo shranjeni kot PostScript (.ps) datoteke." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " je potreben za FluidSynth MIDI izhod." + IDS_2134 "Preklapljam v celozaslonski način" + IDS_2135 "Ne pokaži več tega sporočila" + IDS_2136 "Prekliči izhod" + IDS_2137 "Resetiraj" + IDS_2138 "Ne resetiraj" + IDS_2139 "Slike MO (*.IM?;*.MDI)\0*.IM?;*.MDI\0Vse datoteke (*.*)\0*.*\0" + IDS_2140 "Slike CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Vse datoteke (*.*)\0*.*\0" + IDS_2141 "Konfiguracija naprave %hs" + IDS_2142 "Zaslon v načinu spanja" + IDS_2143 "Senčilniki OpenGL (*.GLSL)\0*.GLSL\0Vse datoteke (*.*)\0*.*\0" + IDS_2144 "Možnosti OpenGL" + IDS_2145 "Nalagate nepodprto konfiguracijo" + IDS_2146 "Filtriranje vrste procesorja glede na izbran sistem je onemogočeno za ta emuliran sistem.\n\nTako lahko izberete procesor, ki je sicer nezdružljiv z izbranim sistemom. Vendar lahko naletite na nezdružljivosti z BIOS-om sistema ali drugo programsko opremo\n\nOmogočanje te nastavitve ni uradno podprto, vsa poročila o hroščih iz tega naslova pa bodo zaprta kot neveljavna." + IDS_2147 "Nadaljuj" + IDS_2148 "Kaseta: %s" + IDS_2149 "Slike kaset (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Vse datoteke (*.*)\0*.*\0" + IDS_2150 "Spominski vložek %i: %ls" + IDS_2151 "Slike spominskega vložka (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Vse datoteke (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Trdi disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL ali ESDI pogoni CD-ROM niso nikoli obstajali" + IDS_4100 "Po meri..." + IDS_4101 "Po meri (velik)..." + IDS_4102 "Dodaj nov trdi disk" + IDS_4103 "Dodaj obstoječ trdi disk" + IDS_4104 "Slike diska HDI ne morejo biti večje od 4 GB." + IDS_4105 "Slike diska ne morejo biti večje od 127 GB." + IDS_4106 "Slike trdega diska (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Vse datoteke (*.*)\0*.*\0" + IDS_4107 "Ne morem prebrati datoteke" + IDS_4108 "Ne morem pisati v datoteko" + IDS_4109 "Slike HDI ali HDX, ki nimajo sektorjev velikosti 512 bajtov, niso podprte." + IDS_4110 "USB še ni podprt" + IDS_4111 "Datoteka s sliko diska že obstaja" + IDS_4112 "Prosim, navedite veljavno ime datoteke." + IDS_4113 "Slika diska ustvarjena" + IDS_4114 "Prepričajte se, da datoteka obstaja in je berljiva." + IDS_4115 "Prepričajte se, da datoteko shranjujete v zapisljivo mapo." + IDS_4116 "Slika diska je prevelika" + IDS_4117 "Ne pozabite na novem disku ustvariti particij in jih formatirati." + IDS_4118 "Izbrana datoteka bo prepisana. Ali jo res želite uporabiti?" + IDS_4119 "Nepodprta slika diska" + IDS_4120 "Prepiši" + IDS_4121 "Ne prepiši" + IDS_4122 "Surova slika (.img)" + IDS_4123 "Slika HDI (.hdi)" + IDS_4124 "Slika HDX (.hdx)" + IDS_4125 "VHD fiksne velikosti (.vhd)" + IDS_4126 "Dinamičen VHD (.vhd)" + IDS_4127 "Diferencialni VHD (.vhd)" + IDS_4128 "Veliki bloki (2 MB)" + IDS_4129 "Mali bloki (512 KB)" + IDS_4130 "Datoteke VHD (*.VHD)\0*.VHD\0Vse datoteke (*.*)\0*.*\0" + IDS_4131 "Izberite starševsko sliko VHD" + IDS_4132 "To lahko pomeni, da je bila starševska slika spremenjena potem, ko je že bila ustvarjena diferencialna slika.\n\nDo tega lahko pride tudi kadar so datoteke slik diska premaknjene ali kopirane, ali pa gre za hrošča v programu, ki je ustvaril ta disk.\n\nŽelite popraviti časovni žig?" + IDS_4133 "Časovna žiga starševske slike diska in slike diska otroka se ne ujemata" + IDS_4134 "Ne morem popraviti časovnega žiga slike VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Onemogočeno" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Onemogočeno" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (grozd 1024)" + IDS_5898 "DMF (grozd 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "Popolni obrati na minuto" + IDS_6145 "1% pod popolnimi obrati" + IDS_6146 "1.5% pod popolnimi obrati" + IDS_6147 "2% pod popolnimi obrati" + + IDS_7168 "(Sistemsko privzeto)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Slovenian resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/tr-TR.rc b/src/win/languages/tr-TR.rc new file mode 100644 index 000000000..3d1cffc97 --- /dev/null +++ b/src/win/languages/tr-TR.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Turkish (TR) resources + +#ifdef _WIN32 +LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Komutlar" + BEGIN + MENUITEM "&Klavye sadece fare yakalandığında çalışsın", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Sağ CTRL tuşunu sol ALT tuşu olarak ayarla", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Makineyi yeniden başlat...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Duraklat", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "Emülatörden &çık...", IDM_ACTION_EXIT + END + POPUP "&Görüntüleme" + BEGIN + MENUITEM "&Durum çubuğunu gizle", IDM_VID_HIDE_STATUS_BAR + MENUITEM "Hide &toolbar", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Yeniden boyutlandırılabilir pencere", IDM_VID_RESIZE + MENUITEM "&Pencere boyut ve pozisyonunu hatırla", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&İşleyici" + BEGIN + MENUITEM "&SDL (Yazılım)", IDM_VID_SDL_SW + MENUITEM "SDL (&Donanım)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0 Core)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "Pencere &boyutunu belirle...", IDM_VID_SPECIFY_DIM + MENUITEM "&4:3 görüntüleme oranına zorla", IDM_VID_FORCE43 + POPUP "Pencere &ölçek çarpanı" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "&Filtre metodu" + BEGIN + MENUITEM "&Nearest (En yakın)", IDM_VID_FILTER_NEAREST + MENUITEM "&Linear (Doğrusal)", IDM_VID_FILTER_LINEAR + END + MENUITEM "Hi&DPI ölçeklemesi", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Tam ekran\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "Tam ekran &germe modu" + BEGIN + MENUITEM "&Tam ekrana ger", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Kare piksel (ölçeği koru)", IDM_VID_FS_KEEPRATIO + MENUITEM "Tam &sayı ölçeklemesi", IDM_VID_FS_INT + END + POPUP "EGA/&(S)VGA ayarları" + BEGIN + MENUITEM "Ters &renk VGA monitör", IDM_VID_INVERT + POPUP "VGA ekran &tipi" + BEGIN + MENUITEM "RGB (&renkli)", IDM_VID_GRAY_RGB + MENUITEM "RGB (&gri tonlama)", IDM_VID_GRAY_MONO + MENUITEM "&Kehribar rengi monitör", IDM_VID_GRAY_AMBER + MENUITEM "&Yeşil renk monitör", IDM_VID_GRAY_GREEN + MENUITEM "&Beyaz renk monitör", IDM_VID_GRAY_WHITE + END + POPUP "&Gri tonlama dönüştürme tipi" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Ortalama", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA aşırı taraması", IDM_VID_OVERSCAN + MENUITEM "Gri to&nlamalı görüntü için kontrastı değiştir", IDM_VID_CGACON + END + MENUITEM "&Medya", IDM_MEDIA + POPUP "&Araçlar" + BEGIN + MENUITEM "&Ayarlar...", IDM_CONFIG + MENUITEM "Durum &çubuğu ikonlarını güncelle", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "&Ekran görüntüsü al\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Tercihler...", IDM_PREFERENCES + MENUITEM "&Discord entegrasyonunu etkinleştir", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Ses yükseltici...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Begin trace\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "End trace\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Yardım" + BEGIN + MENUITEM "&Dökümanlar...", IDM_DOCS + MENUITEM "&86Box Hakkında...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Yeni imaj oluştur...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&İmaj seç...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "İmaj &seç (Yazma-korumalı)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Kaydet", IDM_CASSETTE_RECORD + MENUITEM "&Oynat", IDM_CASSETTE_PLAY + MENUITEM "&Başlangıca geri sar", IDM_CASSETTE_REWIND + MENUITEM "Sona doğru &ileri sar", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Çıkar", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&İmaj...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Çıkar", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Yeni imaj oluştur...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&İmaj seç...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "İmaj &seç (Yazma-korumalı)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&86F dosyası olarak aktar...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Çıkar", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Sesi kapat", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "İmajı &çıkar", IDM_CDROM_EMPTY + MENUITEM "&Önceki imajı seç", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&İmaj seç", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Yeni imaj...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&İmaj seç...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "İmaj &seç (Yazma-korumalı)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Çıkar", IDM_ZIP_EJECT + MENUITEM "&Önceki imajı seç", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Yeni imaj...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&İmaj seç...", IDM_MO_IMAGE_EXISTING + MENUITEM "İmaj &seç (Yazma-korumalı)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Çıkar", IDM_MO_EJECT + MENUITEM "&Önceki imajı seç", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Hedef &kare oranı" + BEGIN + MENUITEM "Video ile &senkronize et", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 fps", IDM_VID_GL_FPS_25 + MENUITEM "&30 fps", IDM_VID_GL_FPS_30 + MENUITEM "&50 fps", IDM_VID_GL_FPS_50 + MENUITEM "&60 fps", IDM_VID_GL_FPS_60 + MENUITEM "&75 fps", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "Gölgelendirici &seç...", IDM_VID_GL_SHADER + MENUITEM "&Gölgelendiriciyi kaldır", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Tercihler" +#define STR_SND_GAIN "Ses Artırma" +#define STR_NEW_FLOPPY "Yeni İmaj" +#define STR_CONFIG "Ayarlar" +#define STR_SPECIFY_DIM "Ana Pencere Boyutunu Belirle" + +#define STR_OK "Tamam" +#define STR_CANCEL "İptal et" +#define STR_GLOBAL "Bu ayarları &varsayılan olarak kaydet" +#define STR_DEFAULT "&Varsayılan" +#define STR_LANGUAGE "Dil:" +#define STR_ICONSET "Simge seti:" + +#define STR_GAIN "Artırma" + +#define STR_FILE_NAME "Dosya adı:" +#define STR_DISK_SIZE "Disk boyutu:" +#define STR_RPM_MODE "RPM modu:" +#define STR_PROGRESS "İşlem:" + +#define STR_WIDTH "Genişlik:" +#define STR_HEIGHT "Yükseklik:" +#define STR_LOCK_TO_SIZE "Bu boyuta kilitle" + +#define STR_MACHINE_TYPE "Makine türü:" +#define STR_MACHINE "Makine:" +#define STR_CONFIGURE "Ayarla" +#define STR_CPU_TYPE "CPU türü:" +#define STR_CPU_SPEED "Hız:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Bekleme süreleri:" +#define STR_MB "MB" +#define STR_MEMORY "Bellek:" +#define STR_TIME_SYNC "Zaman senkronizasyonu" +#define STR_DISABLED "Devre dışı" +#define STR_ENABLED_LOCAL "Etkin (yerel zaman)" +#define STR_ENABLED_UTC "Etkin (UTC)" +#define STR_DYNAREC "Dinamik Derleyici" + +#define STR_VIDEO "Ekran kartı:" +#define STR_VOODOO "Voodoo Grafikleri" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Fare:" +#define STR_JOYSTICK "Oyun kolu:" +#define STR_JOY1 "Oyun kolu 1..." +#define STR_JOY2 "Oyun kolu 2..." +#define STR_JOY3 "Oyun kolu 3..." +#define STR_JOY4 "Oyun kolu 4..." + +#define STR_SOUND "Ses kartı:" +#define STR_MIDI_OUT "MIDI Çıkış Cihazı:" +#define STR_MIDI_IN "MIDI Giriş Cihazı:" +#define STR_MPU401 "Bağımsız MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32 ses kullan" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Ağ tipi:" +#define STR_PCAP "PCap cihazı:" +#define STR_NET "Ağ cihazı:" + +#define STR_COM1 "COM1 Cihazı:" +#define STR_COM2 "COM2 Cihazı:" +#define STR_COM3 "COM3 Cihazı:" +#define STR_COM4 "COM4 Cihazı:" +#define STR_LPT1 "LPT1 Cihazı:" +#define STR_LPT2 "LPT2 Cihazı:" +#define STR_LPT3 "LPT3 Cihazı:" +#define STR_LPT4 "LPT4 Cihazı:" +#define STR_SERIAL1 "Seri port 1" +#define STR_SERIAL2 "Seri port 2" +#define STR_SERIAL3 "Seri port 3" +#define STR_SERIAL4 "Seri port 4" +#define STR_PARALLEL1 "Paralel port 1" +#define STR_PARALLEL2 "Paralel port 2" +#define STR_PARALLEL3 "Paralel port 3" +#define STR_PARALLEL4 "Paralel port 4" + +#define STR_HDC "HD Kontrolcüsü:" +#define STR_FDC "FD Kontrolcüsü:" +#define STR_IDE_TER "Üçlü IDE Kontrolcüsü" +#define STR_IDE_QUA "Dörtlü IDE Kontrolcüsü" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Kontrolcü 1:" +#define STR_SCSI_2 "Kontrolcü 2:" +#define STR_SCSI_3 "Kontrolcü 3:" +#define STR_SCSI_4 "Kontrolcü 4:" +#define STR_CASSETTE "Kaset" + +#define STR_HDD "Hard diskler:" +#define STR_NEW "&Yeni..." +#define STR_EXISTING "&Var olan..." +#define STR_REMOVE "&Kaldır" +#define STR_BUS "Veri yolu:" +#define STR_CHANNEL "Kanal:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Belirle..." +#define STR_SECTORS "Sektörler:" +#define STR_HEADS "Veri Kafaları:" +#define STR_CYLS "Silindirler:" +#define STR_SIZE_MB "Boyut (MB):" +#define STR_TYPE "Tip:" +#define STR_IMG_FORMAT "İmaj Düzeni:" +#define STR_BLOCK_SIZE "Blok Boyutu:" + +#define STR_FLOPPY_DRIVES "Disket sürücüleri:" +#define STR_TURBO "Turbo zamanlamaları" +#define STR_CHECKBPB "BPB'yi denetle" +#define STR_CDROM_DRIVES "CD-ROM sürücüleri:" +#define STR_CD_SPEED "Hız:" + +#define STR_MO_DRIVES "MO sürücüleri:" +#define STR_ZIP_DRIVES "ZIP sürücüleri:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "ISA Bellek Artırma" +#define STR_ISAMEM_1 "Kart 1:" +#define STR_ISAMEM_2 "Kart 2:" +#define STR_ISAMEM_3 "Kart 3:" +#define STR_ISAMEM_4 "Kart 4:" +#define STR_BUGGER "ISABugger cihazı" +#define STR_POSTCARD "POST kartı" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Hata" + IDS_2050 "Kritik hata" + IDS_2051 " - PAUSED" + IDS_2052 "Pencere moduna geri dönmek için Ctrl+Alt+PgDn tuşlarına basın." + IDS_2053 "Hız" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP imajları (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box hiç bir kullanılabilir ROM imajı bulamadı.\n\nLütfen ROM setini indirin ve onu ""Roms"" klasörüne çıkarın." + IDS_2057 "(empty)" + IDS_2058 "ZIP imajları (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "Açık" + IDS_2061 "Kapalı" + IDS_2062 "Tüm imajlar (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basit sektör imajları (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Yüzey imajları (*.86F)\0*.86F\0" + IDS_2063 """%hs"" makinesi roms/machines klasöründe mevcut olmayan ROM imajı yüzünden mevcut değil. Mevcut olan bir makineye geçiş yapılıyor." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 """%hs"" ekran kartı roms/video klasöründe mevcut olmayan ROM imajı yüzünden mevcut değil. Mevcut olan bir ekran kartına geçiş yapılıyor." + IDS_2065 "Makine" + IDS_2066 "Görüntü" + IDS_2067 "Giriş aygıtları" + IDS_2068 "Ses" + IDS_2069 "Ağ" + IDS_2070 "Portlar (COM & LPT)" + IDS_2071 "Depolama kontrolcüleri" + IDS_2072 "Hard diskler" + IDS_2073 "Disket & CD-ROM sürücüleri" + IDS_2074 "Diğer kaldırılabilir cihazlar" + IDS_2075 "Diğer cihazlar" + IDS_2076 "Yüzey imajları (*.86F)\0*.86F\0" + IDS_2077 "Farenin yakalanması için tıklayın" + IDS_2078 "Farenin bırakılması için F8+F12 tuşlarına basın" + IDS_2079 "Farenin bırakılması için F8+F12 veya farenin orta tuşuna basın" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "FluidSynth başlatılamadı" + IDS_2081 "Veri yolu" + IDS_2082 "Dosya" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "BPB'yi kontrol et" + IDS_2088 "KB" + IDS_2089 "Video işleyici başlatılamadı." + IDS_2090 "Varsayılan" + IDS_2091 "%i Bekleme durumları" + IDS_2092 "Tür" + IDS_2093 "PCap ayarlanamadı" + IDS_2094 "Herhangi bir PCap cihazı bulunamadı" + IDS_2095 "Geçersiz PCap cihazı" + IDS_2096 "Standart 2-button oyun kolları" + IDS_2097 "Standart 4-button oyun kolu" + IDS_2098 "Standart 6-button oyun kolu" + IDS_2099 "Standart 8-button oyun kolu" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Kontrol Sistemi" + IDS_2103 "Hiçbiri" + IDS_2104 "Klavye ivdirgeçleri yüklenemedi." + IDS_2105 "Ham girdi kaydedilemedi." + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "Disket %i (%s): %ls" + IDS_2109 "Tüm imajlar (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Gelişmiş sektör imajları (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basit sektör imajları (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Yüzey imajları (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2110 "FreeType başlatılamadı" + IDS_2111 "SDL başlatılamadı, SDL2.dll gerekmektedir" + IDS_2112 "Emüle edilen makineyi yeniden başlatmak istediğinizden emin misiniz?" + IDS_2113 "86Box'tan çıkmak istediğinize emin misiniz?" + IDS_2114 "Ghostscript başlatılamadı" + IDS_2115 "MO %i (%ls): %ls" + IDS_2116 "MO imajları (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2117 "86Box'a hoşgeldiniz!" + IDS_2118 "Dahili kontrolcü" + IDS_2119 "Çıkış" + IDS_2120 "Hiçbir ROM imajı bulunamadı" + IDS_2121 "Ayarları kaydetmek istediğinizden emin misiniz?" + IDS_2122 "Bu makineyi yeniden başlatacak." + IDS_2123 "Kaydet" + IDS_2124 "86Box Hakkında" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "Bir eski bilgisayar emülatörü\n\nYapanlar: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, ve diğerleri.\n\nGNU Genel Kamu Lisansı versiyon 2 veya sonrası altında yayınlanmıştır. Daha fazla bilgi için LICENSE'ı gözden geçirin." + IDS_2127 "Tamam" + IDS_2128 "Donanım mevcut değil" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "" LIB_NAME_PCAP " kurulu olduğundan ve " LIB_NAME_PCAP "-uyumlu bir internet ağında bulunduğunuzdan emin olun." + IDS_2130 "Geçersiz konfigürasyon" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 LIB_NAME_FREETYPE " ESC/P yazıcı emülasyonu için gereklidir." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " PostScript dosyalarının otomatik olarak PDF dosyalarına çevirilmesi için gereklidir.\n\nGenel PostScript yazıcısına gönderilen tüm dökümanlar PostScript (.ps) dosyaları olarak kaydedilecektir." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 LIB_NAME_FLUIDSYNTH " FluidSynth MIDI çıkışı için gereklidir." + IDS_2134 "Tam ekran moduna geçiliyor" + IDS_2135 "Bu mesajı bir daha gösterme" + IDS_2136 "Çıkış yapma" + IDS_2137 "Yeniden başlat" + IDS_2138 "Yeniden başlatma" + IDS_2139 "MO imajları (*.IM?;*.MDI)\0*.IM?;*.MDI\0Tüm dosyalar (*.*)\0*.*\0" + IDS_2140 "CD-ROM imajları (*.ISO;*.CUE)\0*.ISO;*.CUE\0Tüm dosyalar (*.*)\0*.*\0" + IDS_2141 "%hs Cihaz Konfigürasyonu" + IDS_2142 "Monitör uyku modunda" + IDS_2143 "OpenGL Gölgelendiricileri (*.GLSL)\0*.GLSL\0Tüm dosyalar (*.*)\0*.*\0" + IDS_2144 "OpenGL ayarları" + IDS_2145 "Desteklenmeyen bir konfigürasyon yüklüyorsunuz" + IDS_2146 "Seçtiğiniz makineye uygun CPU (işlemci) türü filtrelemesi bu emülasyon için devre dışı bırakıldı.\n\nBu, normalde seçilen makine ile uyumlu olmayan bir CPU seçmenizi mümkün kılmaktadır. Ancak, bundan dolayı seçilen makinenin BIOS'u veya diğer yazılımlar ile uyumsuzluk sorunu yaşayabilirsiniz.\n\nBu filtrelemeyi devre dışı bırakmak emülatör tarafından resmi olarak desteklenmemektedir ve açtığınız bug (hata) raporları geçersiz olarak kapatılabilir." + IDS_2147 "Devam et" + IDS_2148 "Kaset: %s" + IDS_2149 "Kaset imajları (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Tüm dosyalar (*.*)\0*.*\0" + IDS_2150 "Kartuş %i: %ls" + IDS_2151 "Kartuş imajları (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Tüm dosyalar (*.*)\0*.*\0" + IDS_2152 "Error initializing renderer" + IDS_2153 "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." + IDS_2154 "Resume execution" + IDS_2155 "Pause execution" + IDS_2156 "Press Ctrl+Alt+Del" + IDS_2157 "Press Ctrl+Alt+Esc" + IDS_2158 "Hard reset" + IDS_2159 "ACPI shutdown" + IDS_2160 "Settings" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Hard disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL veya ESDI CD-ROM sürücüleri hiçbir zaman var olmamıştır" + IDS_4100 "Diğer..." + IDS_4101 "Diğer (büyük)..." + IDS_4102 "Yeni Hard Disk Dosyası Oluştur" + IDS_4103 "Var Olan Hard Disk Dosyası Ekle" + IDS_4104 "HDI disk imajları 4 GB'tan daha büyük olamaz." + IDS_4105 "Disk imajları 127 GB'tan daha büyük olamaz." + IDS_4106 "Hard disk imajları (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Tüm dosyalar (*.*)\0*.*\0" + IDS_4107 "Dosya okunamıyor" + IDS_4108 "Dosyanın üzerine yazılamıyor" + IDS_4109 "512 dışında sektör boyutu olan HDI veya HDX imajları desteklenmemektedir." + IDS_4110 "USB şu anda desteklenmemektedir" + IDS_4111 "Disk imaj dosyası zaten var olmakta" + IDS_4112 "Lütfen geçerli bir dosya ismi belirleyin." + IDS_4113 "Disk imajı oluşturuldu" + IDS_4114 "Dosyanın var olduğuna ve okunabildiğine emin olun." + IDS_4115 "Dosyanın yazılabilir bir klasöre kaydedildiğinden emin olun." + IDS_4116 "Disk imajı çok büyük" + IDS_4117 "Yeni oluşturulan diski bölmeyi ve formatlamayı unutmayın." + IDS_4118 "Seçili dosyanın üzerine yazılacaktır. Bunu yapmak istediğinizden emin misiniz?" + IDS_4119 "Desteklenmeyen disk imajı" + IDS_4120 "Üzerine yaz" + IDS_4121 "Üzerine yazma" + IDS_4122 "Ham imaj (.img)" + IDS_4123 "HDI imajı (.hdi)" + IDS_4124 "HDX imajı (.hdx)" + IDS_4125 "Sabit-boyutlu VHD (.vhd)" + IDS_4126 "Dinamik-boyutlu VHD (.vhd)" + IDS_4127 "Differencing VHD (.vhd)" + IDS_4128 "Büyük bloklar (2 MB)" + IDS_4129 "Küçük bloklar (512 KB)" + IDS_4130 "VHD dosyaları (*.VHD)\0*.VHD\0Tüm dosyalar (*.*)\0*.*\0" + IDS_4131 "Ana VHD dosyasını seçin" + IDS_4132 "Bu, farkı alınan imaj oluşturulduktan sonra ana imaj dosyasının düzenlendiği anlamına geliyor olabilir.\n\nBu durum ayrıca imaj dosyaları kopyalandığında veya yerleri değiştirildiğinde veya imaj dosyalarını oluşturan programdaki bir hatadan dolayı olmuş olabilir.\n\nZaman damgalarını düzeltmek ister misiniz?" + IDS_4133 "Ana ve ek disk zaman damgaları uyuşmuyor" + IDS_4134 "VHD zaman damgası düzeltilemedi." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Devre dışı" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Devre dışı" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 MB (ISO 10090)" + IDS_5903 "3.5"" 230 MB (ISO 13963)" + IDS_5904 "3.5"" 540 MB (ISO 15498)" + IDS_5905 "3.5"" 640 MB (ISO 15498)" + IDS_5906 "3.5"" 1.3 GB (GigaMO)" + IDS_5907 "3.5"" 2.3 GB (GigaMO 2)" + IDS_5908 "5.25"" 600 MB" + IDS_5909 "5.25"" 650 MB" + IDS_5910 "5.25"" 1 GB" + IDS_5911 "5.25"" 1.3 GB" + + IDS_6144 "Mükemmel RPM" + IDS_6145 "mükemmel RPM değerinin 1% altı" + IDS_6146 "mükemmel RPM değerinin 1.5% altı" + IDS_6147 "mükemmel RPM değerinin 2% altı" + + IDS_7168 "(Sistem Varsayılanı)" +END +#define IDS_LANG_TRTR IDS_7168 + +// Turkish (TR) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/uk-UA.rc b/src/win/languages/uk-UA.rc new file mode 100644 index 000000000..5a741a5c9 --- /dev/null +++ b/src/win/languages/uk-UA.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Ukrainian resources + +#ifdef _WIN32 +LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Дія" + BEGIN + MENUITEM "&Клавіатура потребує захвату", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "&Правий CTRL - це лівий ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Холодне перезавантаження...", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Пауза", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "&Вихід...", IDM_ACTION_EXIT + END + POPUP "&Вигляд" + BEGIN + MENUITEM "&Приховати рядок стану", IDM_VID_HIDE_STATUS_BAR + MENUITEM "&Приховати панель інструментів", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "&Змінний розмір вікна", IDM_VID_RESIZE + MENUITEM "&Запам'ятати розмір і становище", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "&Рендеринг" + BEGIN + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL + MENUITEM "Open&GL (3.0)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "&Вказати розміри...", IDM_VID_SPECIFY_DIM + MENUITEM "&Встановити відношення сторін 4:3", IDM_VID_FORCE43 + POPUP "&Масштаб вікна" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + POPUP "Метод фільтрації" + BEGIN + MENUITEM "&Найближчий", IDM_VID_FILTER_NEAREST + MENUITEM "&Лінійний", IDM_VID_FILTER_LINEAR + END + MENUITEM "Масштабування Hi&DPI", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "&Повноекранний режим\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "&Розстягування у повноекранному режимі" + BEGIN + MENUITEM "&На весь екран", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Квадратні пікселі (зберегти відношення)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Цілісночисленне масштабування", IDM_VID_FS_INT + END + POPUP "Налаштування E&GA/(S)VGA" + BEGIN + MENUITEM "&Інвертувати кольори VGA", IDM_VID_INVERT + POPUP "&Тип екрана VGA" + BEGIN + MENUITEM "RGB &кольоровий", IDM_VID_GRAY_RGB + MENUITEM "&RGB монохромний", IDM_VID_GRAY_MONO + MENUITEM "&Бурштиновий відтінок", IDM_VID_GRAY_AMBER + MENUITEM "&Зелений відтінок", IDM_VID_GRAY_GREEN + MENUITEM "&Білий відтінок", IDM_VID_GRAY_WHITE + END + POPUP "Тип монохромного &конвертування" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Усереднений", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "Вильоти розгортки CGA/PCjr/Tandy/E&GA/(S)VGA", IDM_VID_OVERSCAN + MENUITEM "Змінити контрастність &монохромного дисплея", IDM_VID_CGACON + END + MENUITEM "&Носії", IDM_MEDIA + POPUP "&Інструменти" + BEGIN + MENUITEM "&Налаштування машини...", IDM_CONFIG + MENUITEM "&Обновлення значків рядка стану", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Зробити &знімок\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "&Параметри...", IDM_PREFERENCES + MENUITEM "Увімкнути інтеграцію &Discord", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "&Посилення звуку...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "Почати трасування\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "Завершити трасування\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "&Допомога" + BEGIN + MENUITEM "&Документація...", IDM_DOCS + MENUITEM "&Про програму 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новий образ...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Вибрати образ...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "Вибрати образ (&Захист від запису)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Запис", IDM_CASSETTE_RECORD + MENUITEM "&Відтворення", IDM_CASSETTE_PLAY + MENUITEM "&Перемотування на початок", IDM_CASSETTE_REWIND + MENUITEM "&Перемотування у кінець", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "&Вилучити", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Образ...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "&Вилучити", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новий образ...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Вибрати образ...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "Вибрати образ (&Захист від запису)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Експорт в 86F...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "&Вилучити", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Відключити звук", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "&Пустий", IDM_CDROM_EMPTY + MENUITEM "&Знову завантажити попередній образ", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Образ...", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новий образ...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Вибрати образ...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "Вибрати образ (&Захист від запису)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Вилучити", IDM_ZIP_EJECT + MENUITEM "&Знову завантажити попередній образ", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Новий образ...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "&Вибрати образ...", IDM_MO_IMAGE_EXISTING + MENUITEM "Вибрати образ (&Захист від запису)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "&Вилучити", IDM_MO_EJECT + MENUITEM "&Знову завантажити попередній образ", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "Цільова &частота кадрів" + BEGIN + MENUITEM "&Синхронізація з відео", IDM_VID_GL_FPS_BLITTER + MENUITEM "&25 кадрів в секунду", IDM_VID_GL_FPS_25 + MENUITEM "&30 кадрів в секунду", IDM_VID_GL_FPS_30 + MENUITEM "&50 кадрів в секунду", IDM_VID_GL_FPS_50 + MENUITEM "&60 кадрів в секунду", IDM_VID_GL_FPS_60 + MENUITEM "&75 кадрів в секунду", IDM_VID_GL_FPS_75 + END + MENUITEM "&VSync", IDM_VID_GL_VSYNC + MENUITEM "&Вибрати шейдер...", IDM_VID_GL_SHADER + MENUITEM "&Видалити шейдер", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "Параметри" +#define STR_SND_GAIN "Посилення звуку" +#define STR_NEW_FLOPPY "Новий образ" +#define STR_CONFIG "Налаштування" +#define STR_SPECIFY_DIM "Вказати розміри головного вікна" + +#define STR_OK "OK" +#define STR_CANCEL "Відміна" +#define STR_GLOBAL "Зберегти ці параметри як &глобальні за замовчуванням" +#define STR_DEFAULT "&За замовчуванням" +#define STR_LANGUAGE "Язык:" +#define STR_ICONSET "Набір іконок:" + +#define STR_GAIN "Посилення" + +#define STR_FILE_NAME "Ім'я файлу:" +#define STR_DISK_SIZE "Розмір диска:" +#define STR_RPM_MODE "RPM режим:" +#define STR_PROGRESS "Прогрес:" + +#define STR_WIDTH "Ширина:" +#define STR_HEIGHT "Висота:" +#define STR_LOCK_TO_SIZE "Зафіксувати розмір" + +#define STR_MACHINE_TYPE "Тип машини:" +#define STR_MACHINE "Системна плата:" +#define STR_CONFIGURE "Налаштування" +#define STR_CPU_TYPE "Тип ЦП:" +#define STR_CPU_SPEED "Швидкість:" +#define STR_FPU "FPU:" +#define STR_WAIT_STATES "Цикли очікування:" +#define STR_MB "МБ" +#define STR_MEMORY "Пам'ять:" +#define STR_TIME_SYNC "Синхронізація часу" +#define STR_DISABLED "Відключити" +#define STR_ENABLED_LOCAL "Увімкнути (місцеве)" +#define STR_ENABLED_UTC "Увімкнути (UTC)" +#define STR_DYNAREC "Динамічний рекомпілятор" + +#define STR_VIDEO "Відеокарта:" +#define STR_VOODOO "Прискорювач Voodoo" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "Миша:" +#define STR_JOYSTICK "Джойстик:" +#define STR_JOY1 "Джойстик 1..." +#define STR_JOY2 "Джойстик 2..." +#define STR_JOY3 "Джойстик 3..." +#define STR_JOY4 "Джойстик 4..." + +#define STR_SOUND "Звукова карта:" +#define STR_MIDI_OUT "MIDI Out при-ій:" +#define STR_MIDI_IN "MIDI In при-ій:" +#define STR_MPU401 "Окремий MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "FLOAT32 звук" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "Тип мережі:" +#define STR_PCAP "Пристрій PCap:" +#define STR_NET "Мережева карта:" + +#define STR_COM1 "Пристрій COM1:" +#define STR_COM2 "Пристрій COM2:" +#define STR_COM3 "Пристрій COM3:" +#define STR_COM4 "Пристрій COM4:" +#define STR_LPT1 "Пристрій LPT1:" +#define STR_LPT2 "Пристрій LPT2:" +#define STR_LPT3 "Пристрій LPT3:" +#define STR_LPT4 "Пристрій LPT4:" +#define STR_SERIAL1 "Послідов. порт COM1" +#define STR_SERIAL2 "Послідов. порт COM2" +#define STR_SERIAL3 "Послідов. порт COM3" +#define STR_SERIAL4 "Послідов. порт COM4" +#define STR_PARALLEL1 "Паралельний порт LPT1" +#define STR_PARALLEL2 "Паралельний порт LPT2" +#define STR_PARALLEL3 "Паралельний порт LPT3" +#define STR_PARALLEL4 "Паралельний порт LPT4" + +#define STR_HDC "Контролер HD:" +#define STR_FDC "Контролер FD:" +#define STR_IDE_TER "Третинний IDE контролер" +#define STR_IDE_QUA "Четвертинний IDE контролер" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "Контролер 1:" +#define STR_SCSI_2 "Контролер 2:" +#define STR_SCSI_3 "Контролер 3:" +#define STR_SCSI_4 "Контролер 4:" +#define STR_CASSETTE "Касета" + +#define STR_HDD "Жорсткі диски:" +#define STR_NEW "&Створити..." +#define STR_EXISTING "&Вибрати..." +#define STR_REMOVE "&Прибрати" +#define STR_BUS "Шина:" +#define STR_CHANNEL "Канал:" +#define STR_ID "ID:" + +#define STR_SPECIFY "&Вказати..." +#define STR_SECTORS "Сектора:" +#define STR_HEADS "Головки:" +#define STR_CYLS "Циліндри:" +#define STR_SIZE_MB "Розмір (МБ):" +#define STR_TYPE "Тип:" +#define STR_IMG_FORMAT "Тип образу:" +#define STR_BLOCK_SIZE "Розмір блоку:" + +#define STR_FLOPPY_DRIVES "Гнучкі диски:" +#define STR_TURBO "Турбо таймінги" +#define STR_CHECKBPB "Перевіряти BPB" +#define STR_CDROM_DRIVES "Дисководи CD-ROM:" +#define STR_CD_SPEED "Швидкість:" + +#define STR_MO_DRIVES "Магнітооптичні дисководи:" +#define STR_ZIP_DRIVES "ZIP дисководи:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA RTC:" +#define STR_ISAMEM "Карта розширення пам'яті (ISA)" +#define STR_ISAMEM_1 "Карта 1:" +#define STR_ISAMEM_2 "Карта 2:" +#define STR_ISAMEM_3 "Карта 3:" +#define STR_ISAMEM_4 "Карта 4:" +#define STR_BUGGER "Пристрій ISABugger" +#define STR_POSTCARD "Карта POST" + +#define FONT_SIZE 9 +#define FONT_NAME "Segoe UI" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "Помилка" + IDS_2050 "Непереробна помилка" + IDS_2051 " - PAUSED" + IDS_2052 "Натисніть Ctrl+Alt+PgDn для повернення у віконний режим." + IDS_2053 "Швидкість" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "Образи ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box не зміг знайти жодного відповідного для використання файлу з ПЗУ.\n\nБудь ласка завантажте набір ПЗУ і витягніть його в каталог ""roms""." + IDS_2057 "(порожньо)" + IDS_2058 "Образи ZIP (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0Всі файли (*.*)\0*.*\0" + IDS_2059 "Турбо" + IDS_2060 "Увімк" + IDS_2061 "Вимк" + IDS_2062 "Всі образи (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Прості посекторні образи (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Образ поверхні (*.86F)\0*.86F\0" + IDS_2063 "Системна плата ""%hs"" недоступна через відсутність файлу її ПЗУ в каталозі roms/machines. Переключення на доступну системну плату." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Відеокарта ""%hs"" недоступна через відсутність файлу її ПЗУ в каталозі roms/video. Переключення на доступну відеокарту." + IDS_2065 "Комп'ютер" + IDS_2066 "Дисплей" + IDS_2067 "Пристрій введення" + IDS_2068 "Звук" + IDS_2069 "Мережа" + IDS_2070 "Порти (COM и LPT)" + IDS_2071 "Контролери дисків" + IDS_2072 "Жорсткі диски" + IDS_2073 "Гнучкі диски і CD-ROM" + IDS_2074 "Інші знімні при-ої" + IDS_2075 "Інша периферія" + IDS_2076 "Образи Surface (*.86F)\0*.86F\0" + IDS_2077 "Клацніть мишею для захвату курсора" + IDS_2078 "Натисніть F8+F12, щоб звільнити курсор" + IDS_2079 "Натисніть F8+F12 або середню кнопку миші, щоб звільнити курсор" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "Неможливо ініціалізувати FluidSynth" + IDS_2081 "Шина" + IDS_2082 "Файл" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "МБ" + IDS_2087 "Перевіряти BPB" + IDS_2088 "КБ" + IDS_2089 "Не вдалося ініціалізувати рендер відео." + IDS_2090 "За замовчуванням" + IDS_2091 "%i WS" + IDS_2092 "Тип" + IDS_2093 "Не вдалося налаштувати PCap" + IDS_2094 "Пристрої PCap не знайдені" + IDS_2095 "Невірний пристрій PCap" + IDS_2096 "Стандартний 2-кнопковий джойстик" + IDS_2097 "Стандартний 4-кнопковий джойстик" + IDS_2098 "Стандартний 6-кнопковий джойстик" + IDS_2099 "Стандартний 8-кнопковий джойстик" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Система управління польотом Thrustmaster" + IDS_2103 "Ні" + IDS_2104 "Неможливо завантажити прискорювачі клавіатури." + IDS_2105 "Неможливо зарреєструвати необроблене (RAW) введення." + IDS_2106 "%u" + IDS_2107 "%u МБ (CHS: %i, %i, %i)" + IDS_2108 "Дисковод %i (%s): %ls" + IDS_2109 "Всі образи (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Розширені образи секторів (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Основні образи секторів (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Образи Flux (*.FDI)\0*.FDI\0Образи Surface (*.86F;*.MFM)\0*.86F;*.MFM\0Всі файли (*.*)\0*.*\0" + IDS_2110 "Неможливо ініціалізувати FreeType" + IDS_2111 "Неможливо ініціалізувати SDL, потрібно SDL2.dll" + IDS_2112 "Ви впевнені, що хочете виконати холодне перезавантаження емульованої машини?" + IDS_2113 "Ви впевнені, що хочете вийти з 86Box?" + IDS_2114 "Неможливо ініціалізувати Ghostscript" + IDS_2115 "Магнітооптичний %i (%ls): %ls" + IDS_2116 "Образи магнітооптичних дисків (*.IM?;*.MDI)\0*.IM?;*.MDI\0Все файлы (*.*)\0*.*\0" + IDS_2117 "Ласкаво просимо в 86Box!" + IDS_2118 "Вбудований контролер" + IDS_2119 "Вихід" + IDS_2120 "ПЗУ не знайдені" + IDS_2121 "Чи бажаєте ви зберегти налаштування?" + IDS_2122 "Це призведе до холодної перезагрузки емульованої машини." + IDS_2123 "Зберегти" + IDS_2124 "Про 86Box" + IDS_2125 "86Box v." EMU_VERSION + + IDS_2126 "Емулятор старих комп'ютерів\n\nАвтори: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, Tiseno100, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nВипускаєтся під ліцензією GNU General Public License версії 2 або більше пізніше. Додадкову інформацію см. у файлі LICENSE." + IDS_2127 "OK" + IDS_2128 "Обладнання недоступне" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "Переконайтесь, що " LIB_NAME_PCAP " встановлений і ваше мережеве з'єднання, сумісне з " LIB_NAME_PCAP "." + IDS_2130 "Неприпустима конфігурація" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 "Для емуляції принтера ESC/P потрібно " LIB_NAME_FREETYPE "." +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " потрібно для автоматичного перетворення файлів PostScript в PDF.\n\nВсі документи, відправлені на загальний принтер PostScript, будуть збережені у вигляді файлів PostScript (.ps)." +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 "Для FluidSynth MIDI-висновку потрібно " LIB_NAME_FLUIDSYNTH "." + IDS_2134 "Вхід у повноекранний режим" + IDS_2135 "Більше не показувати це повідомлення" + IDS_2136 "Не виходити" + IDS_2137 "Перезавантажити" + IDS_2138 "Не перезавантажувати" + IDS_2139 "Образи магнітооптичних дисків (*.IM?;*.MDI)\0*.IM?;*.MDI\0Усі файли (*.*)\0*.*\0" + IDS_2140 "Образи CD-ROM (*.ISO;*.CUE)\0*.ISO;*.CUE\0Усі файли (*.*)\0*.*\0" + IDS_2141 "Конфігурація пристрою %hs" + IDS_2142 "Монітор у сплячому режимі" + IDS_2143 "Шейдери OpenGL (*.GLSL)\0*.GLSL\0Усі файли (*.*)\0*.*\0" + IDS_2144 "Параметри OpenGL" + IDS_2145 "Ви завантажуєте непідтримувану конфігурацію" + IDS_2146 "Вибір типів ЦП для цієї системної плати на даній емульованій машині відключено.\n\nЦе дозволяє вибрати процесор, який в іншому випадку не сумісний з вибраною материнською платою. Однак, ви можете зіткнутися з несумісністю з BIOS материнської плати або іншим ПО.\n\nВключення цього параметра офіційно не підтримується, і всі подані звіти про помилки можуть бути закриті як недійсні." + IDS_2147 "Продовжити" + IDS_2148 "Касета: %s" + IDS_2149 "Образи касет (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0Усі файли (*.*)\0*. *\0" + IDS_2150 "Картридж %i: %ls" + IDS_2151 "Образи картриджів (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0Всі файли (*.*)\0*.*\0" + IDS_2152 "Помилка ініціалізації рендерера" + IDS_2153 "Неможливо ініціалізувати рендерер OpenGL (3.0). Будь ласка, використовуйте інший рендерер." + IDS_2154 "Відновити виконання" + IDS_2155 "Призупинити виконання" + IDS_2156 "Натиснути Ctrl+Alt+Del" + IDS_2157 "Натиснути Ctrl+Alt+Esc" + IDS_2158 "Холодне перезавантаження" + IDS_2159 "Сигнал завершення ACPI" + IDS_2160 "Налаштування машини" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Жорсткий диск (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "MFM/RLL або ESDI дисководів CD-ROM ніколи не існувало" + IDS_4100 "Задати вручну..." + IDS_4101 "Задати вручну (large)..." + IDS_4102 "Створити новий жорсткий диск" + IDS_4103 "Вибрати існуючий жорсткий диск" + IDS_4104 "Розмір образів дисків HDI не може перевищувати 4 ГБ." + IDS_4105 "Розмір образів дисків не може перевищувати 127 ГБ." + IDS_4106 "Образи жорстких дисків (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0Всі файли (*.*)\0*.*\0 " + IDS_4107 "Неможливо прочитати файл" + IDS_4108 "Неможливо записати файл" + IDS_4109 "Образи HDI або HDX з розміром сектора, відмінним від 512, не підтримуються." + IDS_4110 "USB поки не підтримується" + IDS_4111 "Файл образу диска вже існує" + IDS_4112 "Вкажіть правильне ім'я файлу." + IDS_4113 "Образ диску створено" + IDS_4114 "Переконайтеся, що файл є доступним для читання." + IDS_4115 "Переконайтеся, що файл зберігається в каталог, який є доступним для запису." + IDS_4116 "Занадто великий образ диска" + IDS_4117 "Не забудьте розмітити та відформатувати новостворений диск." + IDS_4118 "Вибраний файл буде перезаписано. Ви впевнені, що хочете використовувати його?" + IDS_4119 "Образ диска, що не підтримується" + IDS_4120 "Перезаписати" + IDS_4121 "Не перезаписувати" + IDS_4122 "RAW образ (.img)" + IDS_4123 "Образ HDI (.hdi)" + IDS_4124 "Образ HDX (.hdx)" + IDS_4125 "VHD фіксованого розміру (.vhd)" + IDS_4126 "VHD динамічного розміру (.vhd)" + IDS_4127 "Диференційований образ VHD (.vhd)" + IDS_4128 "Великі блоки (2 МБ)" + IDS_4129 "Маленькі блоки (512 КБ)" + IDS_4130 "Файли VHD (*.VHD)\0*.VHD\0Всі файли (*.*)\0*.*\0" + IDS_4131 "Виберіть батьківський VHD" + IDS_4132 "Це може означати, що батьківський образ був змінений після того, як було створено диференційований образ.\n\nЦе також може статися, якщо файли зображення були переміщені або скопійовані, або через помилку в програмі, що створила цей диск.\n \nВи хочете виправити тимчасові позначки?" + IDS_4133 "Тимчасові мітки батьківського та дочірнього дисків не співпадають" + IDS_4134 "Не вдалося виправити тимчасову позначку VHD." + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Відключено" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "Відключено" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 кБ" + IDS_5889 "180 кБ" + IDS_5890 "320 кБ" + IDS_5891 "360 кБ" + IDS_5892 "640 кБ" + IDS_5893 "720 кБ" + IDS_5894 "1.2 МБ" + IDS_5895 "1.25 МБ" + IDS_5896 "1.44 МБ" + IDS_5897 "DMF (кластер 1024)" + IDS_5898 "DMF (кластер 2048)" + IDS_5899 "2.88 МБ" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5"" 128 МБ (ISO 10090)" + IDS_5903 "3.5"" 230 МБ (ISO 13963)" + IDS_5904 "3.5"" 540 МБ (ISO 15498)" + IDS_5905 "3.5"" 640 МБ (ISO 15498)" + IDS_5906 "3.5"" 1.3 ГБ (GigaMO)" + IDS_5907 "3.5"" 2.3 ГБ (GigaMO 2)" + IDS_5908 "5.25"" 600 МБ" + IDS_5909 "5.25"" 650 МБ" + IDS_5910 "5.25"" 1 ГБ" + IDS_5911 "5.25"" 1.3 ГБ" + + IDS_6144 "Точний RPM" + IDS_6145 "На 1% повільніше точного RPM" + IDS_6146 "На 1.5% повільніше точного RPM" + IDS_6147 "На 2% повільніше точного RPM" + + IDS_7168 "(Системний)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Ukrainian resources +//////////////////////////////////////////////////////////////////////////// diff --git a/src/win/languages/zh-CN.rc b/src/win/languages/zh-CN.rc new file mode 100644 index 000000000..3151b7143 --- /dev/null +++ b/src/win/languages/zh-CN.rc @@ -0,0 +1,622 @@ +//////////////////////////////////////////////////////////////////////////// +// Simplified Chinese resources + +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(65001) +#endif //_WIN32 + +#define AUTHORS + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "操作(&A)" + BEGIN + MENUITEM "键盘需要捕捉(&K)", IDM_ACTION_KBD_REQ_CAPTURE + MENUITEM "将右 CTRL 键映射为左 ALT 键(&R)", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "硬重置(&H)...", IDM_ACTION_HRESET + MENUITEM "Ctrl+Alt+Del(&C)\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+Esc(&E)", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "暂停(&P)", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "退出(&X)...", IDM_ACTION_EXIT + END + POPUP "查看(&V)" + BEGIN + MENUITEM "隐藏状态栏(&H)", IDM_VID_HIDE_STATUS_BAR + MENUITEM "隐藏工具栏(&T)", IDM_VID_HIDE_TOOLBAR + MENUITEM SEPARATOR + MENUITEM "窗口大小可调(&R)", IDM_VID_RESIZE + MENUITEM "记住窗口大小和位置(&E)", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "渲染器(&N)" + BEGIN + MENUITEM "SDL (软件)(&S)", IDM_VID_SDL_SW + MENUITEM "SDL (硬件)(&H)", IDM_VID_SDL_HW + MENUITEM "SDL (OpenGL)(&O)", IDM_VID_SDL_OPENGL + MENUITEM "OpenGL (3.0 核心)(&G)", IDM_VID_OPENGL_CORE +#ifdef USE_VNC + MENUITEM "VNC(&V)", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + MENUITEM "指定窗口大小...", IDM_VID_SPECIFY_DIM + MENUITEM "强制 4:3 显示比例(&O)", IDM_VID_FORCE43 + POPUP "窗口缩放系数(&W)" + BEGIN + MENUITEM "0.5x(&0)", IDM_VID_SCALE_1X + MENUITEM "1x(&1)", IDM_VID_SCALE_2X + MENUITEM "1.5x(&5)", IDM_VID_SCALE_3X + MENUITEM "2x(&2)", IDM_VID_SCALE_4X + END + POPUP "过滤方式" + BEGIN + MENUITEM "邻近(&N)", IDM_VID_FILTER_NEAREST + MENUITEM "线性(&L)", IDM_VID_FILTER_LINEAR + END + MENUITEM "HiDPI 缩放(&D)", IDM_VID_HIDPI + MENUITEM SEPARATOR + MENUITEM "全屏(&F)\tCtrl+Alt+PgUp", IDM_VID_FULLSCREEN + POPUP "全屏拉伸模式(&S)" + BEGIN + MENUITEM "全屏拉伸(&F)", IDM_VID_FS_FULL + MENUITEM "4:3(&4)", IDM_VID_FS_43 + MENUITEM "保持比例(&S)", IDM_VID_FS_KEEPRATIO + MENUITEM "整数比例(&I)", IDM_VID_FS_INT + END + POPUP "EGA/(S)VGA 设置(&G)" + BEGIN + MENUITEM "VGA 显示器反色显示(&I)", IDM_VID_INVERT + POPUP "VGA 屏幕类型(&T)" + BEGIN + MENUITEM "RGB 彩色(&C)", IDM_VID_GRAY_RGB + MENUITEM "RGB 灰度(&R)", IDM_VID_GRAY_MONO + MENUITEM "琥珀色单色显示器(&A)", IDM_VID_GRAY_AMBER + MENUITEM "绿色单色显示器(&G)", IDM_VID_GRAY_GREEN + MENUITEM "白色单色显示器(&W)", IDM_VID_GRAY_WHITE + END + POPUP "灰度转换类型(&C)" + BEGIN + MENUITEM "BT601 (NTSC/PAL)(&6)", IDM_VID_GRAYCT_601 + MENUITEM "BT709 (HDTV)(&7)", IDM_VID_GRAYCT_709 + MENUITEM "平均(&A)", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "CGA/PCjr/Tandy/EGA/(S)VGA 过扫描(&G)", IDM_VID_OVERSCAN + MENUITEM "更改单色显示对比度(&M)", IDM_VID_CGACON + END + MENUITEM "介质(&M)", IDM_MEDIA + POPUP "工具(&T)" + BEGIN + MENUITEM "设置(&S)...", IDM_CONFIG + MENUITEM "更新状态栏图标(&U)", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "截图(&C)\tCtrl+F11", IDM_ACTION_SCREENSHOT + MENUITEM SEPARATOR + MENUITEM "首选项(&P)...", IDM_PREFERENCES + MENUITEM "启用 Discord 集成(&D)", IDM_DISCORD + MENUITEM SEPARATOR + MENUITEM "音量增益(&G)...", IDM_SND_GAIN +#ifdef MTR_ENABLED + MENUITEM SEPARATOR + MENUITEM "开始追踪\tCtrl+T", IDM_ACTION_BEGIN_TRACE + MENUITEM "结束追踪\tCtrl+T", IDM_ACTION_END_TRACE +#endif + END + POPUP "帮助(&H)" + BEGIN + MENUITEM "文档(&D)...", IDM_DOCS + MENUITEM "关于 86Box(&A)...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + +CassetteSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新建镜像(&N)...", IDM_CASSETTE_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "打开已存在的镜像(&E)...", IDM_CASSETTE_IMAGE_EXISTING + MENUITEM "打开已存在的镜像并写保护(&W)...", IDM_CASSETTE_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "录制(&R)", IDM_CASSETTE_RECORD + MENUITEM "播放(&P)", IDM_CASSETTE_PLAY + MENUITEM "倒带至起点(&R)", IDM_CASSETTE_REWIND + MENUITEM "快进至终点(&F)", IDM_CASSETTE_FAST_FORWARD + MENUITEM SEPARATOR + MENUITEM "弹出(&J)", IDM_CASSETTE_EJECT + END +END + +CartridgeSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "镜像(&I)...", IDM_CARTRIDGE_IMAGE + MENUITEM SEPARATOR + MENUITEM "弹出(&J)", IDM_CARTRIDGE_EJECT + END +END + +FloppySubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新建镜像(&N)...", IDM_FLOPPY_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "打开已存在的镜像(&E)...", IDM_FLOPPY_IMAGE_EXISTING + MENUITEM "打开已存在的镜像并写保护(&W)...", IDM_FLOPPY_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "导出为 86F 格式(&x)...", IDM_FLOPPY_EXPORT_TO_86F + MENUITEM SEPARATOR + MENUITEM "弹出(&J)", IDM_FLOPPY_EJECT + END +END + +CdromSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "静音(&M)", IDM_CDROM_MUTE + MENUITEM SEPARATOR + MENUITEM "空置驱动器(&M)", IDM_CDROM_EMPTY + MENUITEM "载入上一个镜像(&R)", IDM_CDROM_RELOAD + MENUITEM SEPARATOR + MENUITEM "镜像(&I)", IDM_CDROM_IMAGE + END +END + +ZIPSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新建镜像(&N)...", IDM_ZIP_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "打开已存在的镜像(&E)...", IDM_ZIP_IMAGE_EXISTING + MENUITEM "打开已存在的镜像并写保护(&W)...", IDM_ZIP_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "弹出(&J)", IDM_ZIP_EJECT + MENUITEM "载入上一个镜像(&R)", IDM_ZIP_RELOAD + END +END + +MOSubmenu MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "新建镜像(&N)...", IDM_MO_IMAGE_NEW + MENUITEM SEPARATOR + MENUITEM "打开已存在的镜像(&E)...", IDM_MO_IMAGE_EXISTING + MENUITEM "打开已存在的镜像并写保护(&W)...", IDM_MO_IMAGE_EXISTING_WP + MENUITEM SEPARATOR + MENUITEM "弹出(&J)", IDM_MO_EJECT + MENUITEM "载入上一个镜像(&R)", IDM_MO_RELOAD + END +END + +VidGLSubMenu MENU DISCARDABLE +BEGIN + POPUP "目标帧率(&F)" + BEGIN + MENUITEM "与视频同步(&S)", IDM_VID_GL_FPS_BLITTER + MENUITEM "25 fps(&2)", IDM_VID_GL_FPS_25 + MENUITEM "30 fps(&3)", IDM_VID_GL_FPS_30 + MENUITEM "50 fps(&5)", IDM_VID_GL_FPS_50 + MENUITEM "60 fps(&6)", IDM_VID_GL_FPS_60 + MENUITEM "75 fps(&7)", IDM_VID_GL_FPS_75 + END + MENUITEM "垂直同步(&V)", IDM_VID_GL_VSYNC + MENUITEM "选择着色器(&S)...", IDM_VID_GL_SHADER + MENUITEM "移除着色器(&R)", IDM_VID_GL_NOSHADER +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#define STR_PREFERENCES "首选项" +#define STR_SND_GAIN "音量增益" +#define STR_NEW_FLOPPY "新建镜像" +#define STR_CONFIG "设置" +#define STR_SPECIFY_DIM "指定主窗口大小" + +#define STR_OK "确定" +#define STR_CANCEL "取消" +#define STR_GLOBAL "将以上设置存储为全局默认值(&G)" +#define STR_DEFAULT "默认(&D)" +#define STR_LANGUAGE "语言:" +#define STR_ICONSET "图标集:" + +#define STR_GAIN "增益" + +#define STR_FILE_NAME "文件名:" +#define STR_DISK_SIZE "磁盘大小:" +#define STR_RPM_MODE "转速 (RPM) 模式:" +#define STR_PROGRESS "进度:" + +#define STR_WIDTH "宽度:" +#define STR_HEIGHT "高度:" +#define STR_LOCK_TO_SIZE "锁定此大小" + +#define STR_MACHINE_TYPE "机器类型:" +#define STR_MACHINE "机型:" +#define STR_CONFIGURE "配置" +#define STR_CPU_TYPE "CPU 类型:" +#define STR_CPU_SPEED "速度:" +#define STR_FPU "浮点处理器 (FPU):" +#define STR_WAIT_STATES "等待状态 (WS):" +#define STR_MB "MB" +#define STR_MEMORY "内存:" +#define STR_TIME_SYNC "时间同步" +#define STR_DISABLED "禁用" +#define STR_ENABLED_LOCAL "启用 (本地时间)" +#define STR_ENABLED_UTC "启用 (UTC)" +#define STR_DYNAREC "动态重编译器" + +#define STR_VIDEO "显卡:" +#define STR_VOODOO "Voodoo Graphics" +#define STR_IBM8514 "IBM 8514/a Graphics" +#define STR_XGA "XGA Graphics" + +#define STR_MOUSE "鼠标:" +#define STR_JOYSTICK "操纵杆:" +#define STR_JOY1 "操纵杆 1..." +#define STR_JOY2 "操纵杆 2..." +#define STR_JOY3 "操纵杆 3..." +#define STR_JOY4 "操纵杆 4..." + +#define STR_SOUND "声卡:" +#define STR_MIDI_OUT "MIDI 输出设备:" +#define STR_MIDI_IN "MIDI 输入设备:" +#define STR_MPU401 "独立 MPU-401" +#define STR_SSI "Innovation SSI-2001" +#define STR_CMS "CMS / Game Blaster" +#define STR_GUS "Gravis Ultrasound" +#define STR_FLOAT "使用单精度浮点 (FLOAT32)" +#define STR_FM_DRIVER "FM synth driver" +#define STR_FM_DRV_NUKED "Nuked (more accurate)" +#define STR_FM_DRV_YMFM "YMFM (faster)" + +#define STR_NET_TYPE "网络类型:" +#define STR_PCAP "PCap 设备:" +#define STR_NET "网络适配器:" + +#define STR_COM1 "COM1 设备:" +#define STR_COM2 "COM2 设备:" +#define STR_COM3 "COM3 设备:" +#define STR_COM4 "COM4 设备:" +#define STR_LPT1 "LPT1 设备:" +#define STR_LPT2 "LPT2 设备:" +#define STR_LPT3 "LPT3 设备:" +#define STR_LPT4 "LPT4 设备:" +#define STR_SERIAL1 "串口 1" +#define STR_SERIAL2 "串口 2" +#define STR_SERIAL3 "串口 3" +#define STR_SERIAL4 "串口 4" +#define STR_PARALLEL1 "并口 1" +#define STR_PARALLEL2 "并口 2" +#define STR_PARALLEL3 "并口 3" +#define STR_PARALLEL4 "并口 4" + +#define STR_HDC "硬盘控制器:" +#define STR_FDC "软盘控制器:" +#define STR_IDE_TER "第三 IDE 控制器" +#define STR_IDE_QUA "第四 IDE 控制器" +#define STR_SCSI "SCSI" +#define STR_SCSI_1 "控制器 1:" +#define STR_SCSI_2 "控制器 2:" +#define STR_SCSI_3 "控制器 3:" +#define STR_SCSI_4 "控制器 4:" +#define STR_CASSETTE "磁带" + +#define STR_HDD "硬盘:" +#define STR_NEW "新建(&N)..." +#define STR_EXISTING "已有镜像(&E)..." +#define STR_REMOVE "移除(&R)" +#define STR_BUS "总线:" +#define STR_CHANNEL "通道:" +#define STR_ID "ID:" + +#define STR_SPECIFY "指定(&S)..." +#define STR_SECTORS "扇区(S):" +#define STR_HEADS "磁头(H):" +#define STR_CYLS "柱面(C):" +#define STR_SIZE_MB "大小 (MB):" +#define STR_TYPE "类型:" +#define STR_IMG_FORMAT "镜像格式:" +#define STR_BLOCK_SIZE "块大小:" + +#define STR_FLOPPY_DRIVES "软盘驱动器:" +#define STR_TURBO "加速时序" +#define STR_CHECKBPB "检查 BPB" +#define STR_CDROM_DRIVES "光盘驱动器:" +#define STR_CD_SPEED "速度:" + +#define STR_MO_DRIVES "磁光盘驱动器:" +#define STR_ZIP_DRIVES "ZIP 驱动器:" +#define STR_250 "ZIP 250" + +#define STR_ISARTC "ISA 实时时钟:" +#define STR_ISAMEM "ISA 内存扩充" +#define STR_ISAMEM_1 "扩展卡 1:" +#define STR_ISAMEM_2 "扩展卡 2:" +#define STR_ISAMEM_3 "扩展卡 3:" +#define STR_ISAMEM_4 "扩展卡 4:" +#define STR_BUGGER "ISABugger 设备" +#define STR_POSTCARD "自检 (POST) 卡" + +#define FONT_SIZE 9 +#define FONT_NAME "Microsoft YaHei" + +#include "dialogs.rc" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "错误" + IDS_2050 "致命错误" + IDS_2051 " - 已暂停" + IDS_2052 "按下 Ctrl+Alt+PgDn 返回到窗口模式。" + IDS_2053 "速度" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP 镜像 (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "86Box 找不到任何可用的 ROM 镜像。\n\n请下载ROM 包并将其解压到 ""roms"" 文件夹。" + IDS_2057 "(空)" + IDS_2058 "ZIP 镜像 (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0所有文件 (*.*)\0*.*\0" + IDS_2059 "加速" + IDS_2060 "开" + IDS_2061 "关" + IDS_2062 "所有镜像 (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0基本扇区镜像 (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0表面镜像 (*.86F)\0*.86F\0" + IDS_2063 "由于 roms/machines 文件夹中缺少合适的 ROM,机型 ""%hs"" 不可用。将切换到其他可用机型。" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "由于 roms/video 文件夹中缺少合适的 ROM,显卡 ""%hs"" 不可用。将切换到其他可用显卡。" + IDS_2065 "机型" + IDS_2066 "显示" + IDS_2067 "输入设备" + IDS_2068 "声音" + IDS_2069 "网络" + IDS_2070 "端口 (COM 和 LPT)" + IDS_2071 "存储控制器" + IDS_2072 "硬盘" + IDS_2073 "软盘/光盘驱动器" + IDS_2074 "其他可移动设备" + IDS_2075 "其他外围设备" + IDS_2076 "表面镜像 (*.86F)\0*.86F\0" + IDS_2077 "单击窗口捕捉鼠标" + IDS_2078 "按下 F8+F12 释放鼠标" + IDS_2079 "按下 F8+F12 或鼠标中键释放鼠标" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "无法初始化 FluidSynth" + IDS_2081 "总线" + IDS_2082 "文件" + IDS_2083 "C" + IDS_2084 "H" + IDS_2085 "S" + IDS_2086 "MB" + IDS_2087 "检查 BPB" + IDS_2088 "KB" + IDS_2089 "无法初始化视频渲染器。" + IDS_2090 "默认" + IDS_2091 "%i 等待状态 (WS)" + IDS_2092 "类型" + IDS_2093 "设置 PCap 失败" + IDS_2094 "未找到 PCap 设备" + IDS_2095 "无效 PCap 设备" + IDS_2096 "标准 2 键操纵杆" + IDS_2097 "标准 4 键操纵杆" + IDS_2098 "标准 6 键操纵杆" + IDS_2099 "标准 8 键操纵杆" + IDS_2100 "CH Flightstick Pro" + IDS_2101 "Microsoft SideWinder Pad" + IDS_2102 "Thrustmaster Flight Control System" + IDS_2103 "无" + IDS_2104 "无法加载键盘加速器。" + IDS_2105 "无法注册原始输入。" + IDS_2106 "%u" + IDS_2107 "%u MB (CHS: %i, %i, %i)" + IDS_2108 "软盘 %i (%s): %ls" + IDS_2109 "所有镜像 (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0高级扇区镜像 (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0基本扇区镜像 (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux 镜像 (*.FDI)\0*.FDI\0表面镜像 (*.86F;*.MFM)\0*.86F;*.MFM\0所有文件 (*.*)\0*.*\0" + IDS_2110 "无法初始化 FreeType" + IDS_2111 "无法初始化 SDL,需要 SDL2.dll" + IDS_2112 "确定要硬重置模拟器吗?" + IDS_2113 "确定要退出 86Box 吗?" + IDS_2114 "无法初始化 Ghostscript" + IDS_2115 "磁光盘 %i (%ls): %ls" + IDS_2116 "磁光盘镜像 (*.IM?;*.MDI)\0*.IM?;*.MDI\0所有文件 (*.*)\0*.*\0" + IDS_2117 "欢迎使用 86Box!" + IDS_2118 "内部控制器" + IDS_2119 "退出" + IDS_2120 "找不到 ROM" + IDS_2121 "要保存设置吗?" + IDS_2122 "此操作将硬重置模拟器。" + IDS_2123 "保存" + IDS_2124 "关于 86Box" + IDS_2125 "86Box v" EMU_VERSION + + IDS_2126 "一个旧式计算机模拟器\n\n作者: Sarah Walker、Miran Grca、Fred N. van Kempen (waltje)、SA1988、Tiseno100、reenigne、leilei、JohnElliott、greatpsycho 等人。\n\n本软件依据 GNU 通用公共许可证第二版或更新版本发布。详情见 LICENSE 文件。" + IDS_2127 "确定" + IDS_2128 "硬件不可用" +#ifdef _WIN32 +#define LIB_NAME_PCAP "WinPcap" +#else +#define LIB_NAME_PCAP "libpcap" +#endif + IDS_2129 "请确认 " LIB_NAME_PCAP " 已安装且使用兼容 " LIB_NAME_PCAP " 的网络连接。" + IDS_2130 "无效配置" +#ifdef _WIN32 +#define LIB_NAME_FREETYPE "freetype.dll" +#else +#define LIB_NAME_FREETYPE "libfreetype" +#endif + IDS_2131 "ESC/P 打印机模拟需要" LIB_NAME_FREETYPE +#ifdef _WIN32 +#define LIB_NAME_GS "gsdll32.dll" +#else +#define LIB_NAME_GS "libgs" +#endif + IDS_2132 LIB_NAME_GS " 是将 PostScript 文件转换为 PDF 所需要的库。\n\n使用通用 PostScript 打印机打印的文档将被保存为 PostScript (.ps) 文件。" +#ifdef _WIN32 +#define LIB_NAME_FLUIDSYNTH "libfluidsynth.dll" +#else +#define LIB_NAME_FLUIDSYNTH "libfluidsynth" +#endif + IDS_2133 "FluidSynth MIDI 输出需要" LIB_NAME_FLUIDSYNTH + IDS_2134 "正在进入全屏模式" + IDS_2135 "不要再显示此消息" + IDS_2136 "不退出" + IDS_2137 "重置" + IDS_2138 "不重置" + IDS_2139 "磁光盘镜像 (*.IM?;*.MDI)\0*.IM?;*.MDI\0所有文件 (*.*)\0*.*\0" + IDS_2140 "光盘镜像 (*.ISO;*.CUE)\0*.ISO;*.CUE\0所有文件 (*.*)\0*.*\0" + IDS_2141 "%hs 设备配置" + IDS_2142 "显示器处在睡眠状态" + IDS_2143 "OpenGL 着色器 (*.GLSL)\0*.GLSL\0所有文件 (*.*)\0*.*\0" + IDS_2144 "OpenGL 选项" + IDS_2145 "正在载入一个不受支持的配置" + IDS_2146 "此模拟计算机禁用了基于选定计算机的 CPU 类型过滤。\n\n能够选中与所选机器本不兼容的 CPU,但是可能会遇到与机器 BIOS 或其他软件不兼容的问题。\n\n启用此设置不受官方支持,并且提交的任何错误报告可能会视为无效而关闭。" + IDS_2147 "继续" + IDS_2148 "磁带: %s" + IDS_2149 "磁带镜像 (*.PCM;*.RAW;*.WAV;*.CAS)\0*.PCM;*.RAW;*.WAV;*.CAS\0所有文件 (*.*)\0*.*\0" + IDS_2150 "卡带 %i: %ls" + IDS_2151 "卡带镜像 (*.A;*.B;*.JRC)\0*.A;*.B;*.JRC\0所有文件 (*.*)\0*.*\0" + IDS_2152 "初始化渲染器时出错" + IDS_2153 "无法初始化 OpenGL (3.0 核心) 渲染器。请使用其他渲染器。" + IDS_2154 "恢复执行" + IDS_2155 "暂停执行" + IDS_2156 "按下 Ctrl+Alt+Del" + IDS_2157 "按下 Ctrl+Alt+Esc" + IDS_2158 "硬重置" + IDS_2159 "ACPI 关机" + IDS_2160 "设置" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "硬盘 (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%01i" + IDS_4099 "不存在 MFM/RLL 或 ESDI CD-ROM 驱动器" + IDS_4100 "自定义..." + IDS_4101 "自定义 (大容量)..." + IDS_4102 "添加新硬盘" + IDS_4103 "添加已存在的硬盘" + IDS_4104 "HDI 磁盘镜像不能超过 4 GB。" + IDS_4105 "磁盘镜像不能超过 127 GB。" + IDS_4106 "硬盘镜像 (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0所有文件 (*.*)\0*.*\0" + IDS_4107 "无法读取文件" + IDS_4108 "无法写入文件" + IDS_4109 "不支持非 512 字节扇区大小的 HDI 或 HDX 镜像。" + IDS_4110 "尚未支持 USB" + IDS_4111 "磁盘镜像文件已存在" + IDS_4112 "请指定有效的文件名。" + IDS_4113 "已创建磁盘镜像" + IDS_4114 "请确定此文件已存在并可读取。" + IDS_4115 "请确定此文件保存在可写目录中。" + IDS_4116 "磁盘镜像太大" + IDS_4117 "请记得为新创建的镜像分区并格式化。" + IDS_4118 "选定的文件将被覆盖。确定继续使用此文件吗?" + IDS_4119 "不支持的磁盘镜像" + IDS_4120 "覆盖" + IDS_4121 "不覆盖" + IDS_4122 "原始镜像 (.img)" + IDS_4123 "HDI 镜像 (.hdi)" + IDS_4124 "HDX 镜像 (.hdx)" + IDS_4125 "固定大小 VHD (.vhd)" + IDS_4126 "动态大小 VHD (.vhd)" + IDS_4127 "差分 VHD (.vhd)" + IDS_4128 "大块 (2 MB)" + IDS_4129 "小块 (512 KB)" + IDS_4130 "VHD 文件 (*.VHD)\0*.VHD\0所有文件 (*.*)\0*.*\0" + IDS_4131 "选择父 VHD 文件" + IDS_4132 "父映像可能在创建差异镜像后被修改。\n\n如果镜像文件被移动或复制,或创建此磁盘的程序中存在错误,也可能发生这种情况。\n\n是否需要修复时间戳?" + IDS_4133 "父盘与子盘的时间戳不匹配" + IDS_4134 "无法修复 VHD 时间戳。" + IDS_4135 "%01i:%02i" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "ATAPI" + IDS_4357 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "ATAPI (%01i:%01i)" + IDS_4613 "SCSI (%01i:%02i)" + + IDS_5120 "光盘 %i (%s): %s" + + IDS_5376 "禁用" + IDS_5381 "ATAPI" + IDS_5382 "SCSI" + + IDS_5632 "禁用" + IDS_5637 "ATAPI (%01i:%01i)" + IDS_5638 "SCSI (%01i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (1024 簇)" + IDS_5898 "DMF (2048 簇)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + IDS_5902 "3.5 英寸 128 MB (ISO 10090)" + IDS_5903 "3.5 英寸 230 MB (ISO 13963)" + IDS_5904 "3.5 英寸 540 MB (ISO 15498)" + IDS_5905 "3.5 英寸 640 MB (ISO 15498)" + IDS_5906 "3.5 英寸 1.3 GB (GigaMO)" + IDS_5907 "3.5 英寸 2.3 GB (GigaMO 2)" + IDS_5908 "5.25 英寸 600 MB" + IDS_5909 "5.25 英寸 650 MB" + IDS_5910 "5.25 英寸 1 GB" + IDS_5911 "5.25 英寸 1.3 GB" + + IDS_6144 "标准转速 (RPM)" + IDS_6145 "低于标准转速的 1%" + IDS_6146 "低于标准转速的 1.5%" + IDS_6147 "低于标准转速的 2%" + + IDS_7168 "(系统默认)" +END +#define IDS_LANG_ENUS IDS_7168 + +// Simplified Chinese resources +///////////////////////////////////////////////////////////////////////////// diff --git a/src/win/win.c b/src/win/win.c index c109c9b8b..c526fd760 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -17,10 +17,12 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2021 Laci bá' */ #define UNICODE #define NTDDI_VERSION 0x06010000 #include +#include #include #include #include @@ -30,51 +32,69 @@ #include #include #include +#include #include +#include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/config.h> #include <86box/device.h> #include <86box/keyboard.h> #include <86box/mouse.h> +#include <86box/timer.h> +#include <86box/nvr.h> #include <86box/video.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/path.h> #define GLOBAL #include <86box/plat.h> -#include <86box/plat_midi.h> +#include <86box/thread.h> #include <86box/ui.h> #ifdef USE_VNC # include <86box/vnc.h> #endif #include <86box/win_sdl.h> +#include <86box/win_opengl.h> #include <86box/win.h> - +#include <86box/version.h> +#include <86box/gdbstub.h> +#ifdef MTR_ENABLED +#include +#endif typedef struct { - WCHAR str[512]; + WCHAR str[1024]; } rc_str_t; /* Platform Public data, specific. */ HINSTANCE hinstance; /* application instance */ HANDLE ghMutex; -LCID lang_id; /* current language ID used */ +uint32_t lang_id, lang_sys; /* current and system language ID */ DWORD dwSubLangID; +int acp_utf8; /* Windows supports UTF-8 codepage */ +volatile int cpu_thread_run = 1; /* Local data. */ static HANDLE thMain; -static rc_str_t *lpRCstr2048, - *lpRCstr4096, - *lpRCstr4352, - *lpRCstr4608, - *lpRCstr5120, - *lpRCstr5376, - *lpRCstr5632, - *lpRCstr5888, - *lpRCstr6144, - *lpRCstr7168; +static rc_str_t *lpRCstr2048 = NULL, + *lpRCstr4096 = NULL, + *lpRCstr4352 = NULL, + *lpRCstr4608 = NULL, + *lpRCstr5120 = NULL, + *lpRCstr5376 = NULL, + *lpRCstr5632 = NULL, + *lpRCstr5888 = NULL, + *lpRCstr6144 = NULL, + *lpRCstr7168 = NULL; static int vid_api_inited = 0; -static wchar_t *argbuf; +static char *argbuf; +static int first_use = 1; +static LARGE_INTEGER StartingTime; +static LARGE_INTEGER Frequency; static const struct { @@ -85,24 +105,22 @@ static const struct { void (*resize)(int x, int y); int (*pause)(void); void (*enable)(int enable); -} vid_apis[2][RENDERERS_NUM] = { - { - { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable } + void (*set_fs)(int fs); + void (*reload)(void); +} vid_apis[RENDERERS_NUM] = { + { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, sdl_reload }, + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, sdl_reload }, + { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, sdl_reload } + ,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs, opengl_reload} #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, NULL } #endif - }, - { - { "SDL_Software", 1, (int(*)(void*))sdl_inits_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable } -#ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } -#endif - }, }; +extern int title_update; + + #ifdef ENABLE_WIN_LOG int win_do_log = ENABLE_WIN_LOG; @@ -122,73 +140,142 @@ win_log(const char *fmt, ...) #define win_log(fmt, ...) #endif +void +free_string(rc_str_t **str) +{ + if (*str != NULL) { + free(*str); + *str = NULL; + } +} + static void LoadCommonStrings(void) { int i; - lpRCstr2048 = (rc_str_t *)malloc(STR_NUM_2048*sizeof(rc_str_t)); - lpRCstr4096 = (rc_str_t *)malloc(STR_NUM_4096*sizeof(rc_str_t)); - lpRCstr4352 = (rc_str_t *)malloc(STR_NUM_4352*sizeof(rc_str_t)); - lpRCstr4608 = (rc_str_t *)malloc(STR_NUM_4608*sizeof(rc_str_t)); - lpRCstr5120 = (rc_str_t *)malloc(STR_NUM_5120*sizeof(rc_str_t)); - lpRCstr5376 = (rc_str_t *)malloc(STR_NUM_5376*sizeof(rc_str_t)); - lpRCstr5632 = (rc_str_t *)malloc(STR_NUM_5632*sizeof(rc_str_t)); - lpRCstr5888 = (rc_str_t *)malloc(STR_NUM_5888*sizeof(rc_str_t)); - lpRCstr6144 = (rc_str_t *)malloc(STR_NUM_6144*sizeof(rc_str_t)); - lpRCstr7168 = (rc_str_t *)malloc(STR_NUM_7168*sizeof(rc_str_t)); + free_string(&lpRCstr7168); + free_string(&lpRCstr6144); + free_string(&lpRCstr5888); + free_string(&lpRCstr5632); + free_string(&lpRCstr5376); + free_string(&lpRCstr5120); + free_string(&lpRCstr4608); + free_string(&lpRCstr4352); + free_string(&lpRCstr4096); + free_string(&lpRCstr2048); + + lpRCstr2048 = calloc(STR_NUM_2048, sizeof(rc_str_t)); + lpRCstr4096 = calloc(STR_NUM_4096, sizeof(rc_str_t)); + lpRCstr4352 = calloc(STR_NUM_4352, sizeof(rc_str_t)); + lpRCstr4608 = calloc(STR_NUM_4608, sizeof(rc_str_t)); + lpRCstr5120 = calloc(STR_NUM_5120, sizeof(rc_str_t)); + lpRCstr5376 = calloc(STR_NUM_5376, sizeof(rc_str_t)); + lpRCstr5632 = calloc(STR_NUM_5632, sizeof(rc_str_t)); + lpRCstr5888 = calloc(STR_NUM_5888, sizeof(rc_str_t)); + lpRCstr6144 = calloc(STR_NUM_6144, sizeof(rc_str_t)); + lpRCstr7168 = calloc(STR_NUM_7168, sizeof(rc_str_t)); for (i=0; i 3)) - LoadString(hinstance, 5376+i, lpRCstr5376[i].str, 512); + LoadString(hinstance, 5376+i, lpRCstr5376[i].str, 1024); } for (i=0; i 3)) - LoadString(hinstance, 5632+i, lpRCstr5632[i].str, 512); + LoadString(hinstance, 5632+i, lpRCstr5632[i].str, 1024); } for (i=0; i= argc_max) { argc_max += 64; - args = realloc(args, sizeof(wchar_t *)*argc_max); + args = realloc(args, sizeof(char *)*argc_max); if (args == NULL) { free(argbuf); return(0); @@ -327,7 +433,7 @@ ProcessCommandLine(wchar_t ***argw) } while ((argbuf[i]) && ((q) - ? (argbuf[i]!=q) : (argbuf[i]!=L' '))) i++; + ? (argbuf[i]!=q) : (argbuf[i]!=' '))) i++; if (argbuf[i]) { argbuf[i] = 0; @@ -337,7 +443,7 @@ ProcessCommandLine(wchar_t ***argw) } args[argc] = NULL; - *argw = args; + *argv = args; return(argc); } @@ -347,11 +453,17 @@ ProcessCommandLine(wchar_t ***argw) int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) { - wchar_t **argw = NULL; + char **argv = NULL; int argc, i; - wchar_t * AppID = L"86Box.86Box\0"; - SetCurrentProcessExplicitAppUserModelID(AppID); + /* Initialize the COM library for the main thread. */ + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + /* Check if Windows supports UTF-8 */ + if (GetACP() == CP_UTF8) + acp_utf8 = 1; + else + acp_utf8 = 0; /* Set this to the default value (windowed mode). */ video_fullscreen = 0; @@ -360,20 +472,17 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) hinstance = hInst; /* Set the application version ID string. */ - sprintf(emu_version, "%s v%s", EMU_NAME, EMU_VERSION); + sprintf(emu_version, "%s v%s", EMU_NAME, EMU_VERSION_FULL); - /* First, set our (default) language. */ - set_language(0x0409); - - /* Create console window. */ - if (force_debug) - CreateConsole(1); + /* First, set our (default) language. */ + lang_sys = GetThreadUILanguage(); + set_language(DEFAULT_LANGUAGE); /* Process the command line for options. */ - argc = ProcessCommandLine(&argw); + argc = ProcessCommandLine(&argv); /* Pre-initialize the system, this loads the config file. */ - if (! pc_init(argc, argw)) { + if (! pc_init(argc, argv)) { /* Detach from console. */ if (force_debug) CreateConsole(0); @@ -382,26 +491,83 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain); free(argbuf); - free(argw); + free(argv); return(1); } - - /* Enable crash dump services. */ - if (enable_crashdump) - InitCrashDump(); - if (force_debug) + extern int gfxcard_2; + gfxcard_2 = 0; + + /* Create console window. */ + if (force_debug) { + CreateConsole(1); atexit(CloseConsole); +} /* Handle our GUI. */ i = ui_init(nCmdShow); + /* Uninitialize COM before exit. */ + CoUninitialize(); + free(argbuf); - free(argw); + free(argv); return(i); } +void +main_thread(void *param) +{ + uint32_t old_time, new_time; + int drawits, frames; + + framecountx = 0; + title_update = 1; + old_time = GetTickCount(); + drawits = frames = 0; + while (!is_quit && cpu_thread_run) { + /* See if it is time to run a frame of code. */ + new_time = GetTickCount(); +#ifdef USE_GDBSTUB + if (gdbstub_next_asap && (drawits <= 0)) + drawits = 10; + else +#endif + drawits += (new_time - old_time); + old_time = new_time; + if (drawits > 0 && !dopause) { + /* Yes, so do one frame now. */ + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + pc_run(); + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + nvr_save(); + nvr_dosave = 0; + frames = 0; + } + } else /* Just so we dont overload the host OS. */ + Sleep(1); + + /* If needed, handle a screen resize. */ + if (atomic_load(&doresize_monitors[0]) && !video_fullscreen && !is_quit) { + if (vid_resize & 2) + plat_resize(fixed_size_x, fixed_size_y); + else + plat_resize(scrnsz_x, scrnsz_y); + atomic_store(&doresize_monitors[0], 0); + } + } + + is_quit = 1; +} + + /* * We do this here since there is platform-specific stuff * going on here, and we do it in a function separate from @@ -413,7 +579,7 @@ do_start(void) LARGE_INTEGER qpc; /* We have not stopped yet. */ - quited = 0; + is_quit = 0; /* Initialize the high-precision timer. */ timeBeginPeriod(1); @@ -422,7 +588,7 @@ do_start(void) win_log("Main timer precision: %llu\n", timer_freq); /* Start the emulator, really. */ - thMain = thread_create(pc_thread, &quited); + thMain = thread_create(main_thread, NULL); SetThreadPriority(thMain, THREAD_PRIORITY_HIGHEST); } @@ -431,101 +597,171 @@ do_start(void) void do_stop(void) { - quited = 1; + /* Claim the video blitter. */ + startblit(); - plat_delay_ms(100); - - if (source_hwnd) - PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain); + vid_apis[vid_api].close(); pc_close(thMain); thMain = NULL; + + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain); } void -plat_get_exe_name(wchar_t *s, int size) +plat_get_exe_name(char *s, int size) { - GetModuleFileName(hinstance, s, size); + wchar_t *temp; + + if (acp_utf8) + GetModuleFileNameA(hinstance, s, size); + else { + temp = malloc(size * sizeof(wchar_t)); + GetModuleFileNameW(hinstance, temp, size); + c16stombs(s, temp, size); + free(temp); + } } void -plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix) +plat_tempfile(char *bufp, char *prefix, char *suffix) { SYSTEMTIME SystemTime; - char temp[1024]; if (prefix != NULL) - sprintf(temp, "%ls-", prefix); + sprintf(bufp, "%s-", prefix); else - strcpy(temp, ""); + strcpy(bufp, ""); GetSystemTime(&SystemTime); - sprintf(&temp[strlen(temp)], "%d%02d%02d-%02d%02d%02d-%03d%ls", + sprintf(&bufp[strlen(bufp)], "%d%02d%02d-%02d%02d%02d-%03d%s", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, suffix); - mbstowcs(bufp, temp, strlen(temp)+1); } int -plat_getcwd(wchar_t *bufp, int max) +plat_getcwd(char *bufp, int max) { - (void)_wgetcwd(bufp, max); + wchar_t *temp; + + if (acp_utf8) + (void)_getcwd(bufp, max); + else { + temp = malloc(max * sizeof(wchar_t)); + (void)_wgetcwd(temp, max); + c16stombs(bufp, temp, max); + free(temp); + } return(0); } int -plat_chdir(wchar_t *path) +plat_chdir(char *path) { - return(_wchdir(path)); + wchar_t *temp; + int len, ret; + + if (acp_utf8) + return(_chdir(path)); + else { + len = mbstoc16s(NULL, path, 0) + 1; + temp = malloc(len * sizeof(wchar_t)); + mbstoc16s(temp, path, len); + + ret = _wchdir(temp); + + free(temp); + return ret; + } } FILE * -plat_fopen(wchar_t *path, wchar_t *mode) +plat_fopen(const char *path, const char *mode) { - return(_wfopen(path, mode)); + wchar_t *pathw, *modew; + int len; + FILE *fp; + + if (acp_utf8) + return fopen(path, mode); + else { + len = mbstoc16s(NULL, path, 0) + 1; + pathw = malloc(sizeof(wchar_t) * len); + mbstoc16s(pathw, path, len); + + len = mbstoc16s(NULL, mode, 0) + 1; + modew = malloc(sizeof(wchar_t) * len); + mbstoc16s(modew, mode, len); + + fp = _wfopen(pathw, modew); + + free(pathw); + free(modew); + + return fp; + } } /* Open a file, using Unicode pathname, with 64bit pointers. */ FILE * -plat_fopen64(const wchar_t *path, const wchar_t *mode) +plat_fopen64(const char *path, const char *mode) { - return(_wfopen(path, mode)); + return plat_fopen(path, mode); } void -plat_remove(wchar_t *path) +plat_remove(char *path) { - _wremove(path); + wchar_t *temp; + int len; + + if (acp_utf8) + remove(path); + else { + len = mbstoc16s(NULL, path, 0) + 1; + temp = malloc(len * sizeof(wchar_t)); + mbstoc16s(temp, path, len); + + _wremove(temp); + + free(temp); + } } +void +path_normalize(char* path) +{ + /* No-op */ +} /* Make sure a path ends with a trailing (back)slash. */ void -plat_path_slash(wchar_t *path) +path_slash(char *path) { - if ((path[wcslen(path)-1] != L'\\') && - (path[wcslen(path)-1] != L'/')) { - wcscat(path, L"\\"); + if ((path[strlen(path)-1] != '\\') && + (path[strlen(path)-1] != '/')) { + strcat(path, "\\"); } } /* Check if the given path is absolute or not. */ int -plat_path_abs(wchar_t *path) +path_abs(char *path) { - if ((path[1] == L':') || (path[0] == L'\\') || (path[0] == L'/')) + if ((path[1] == ':') || (path[0] == '\\') || (path[0] == '/')) return(1); return(0); @@ -533,33 +769,33 @@ plat_path_abs(wchar_t *path) /* Return the last element of a pathname. */ -wchar_t * -plat_get_basename(const wchar_t *path) +char * +plat_get_basename(const char *path) { - int c = (int)wcslen(path); + int c = (int)strlen(path); while (c > 0) { - if (path[c] == L'/' || path[c] == L'\\') - return((wchar_t *)&path[c]); + if (path[c] == '/' || path[c] == '\\') + return((char *)&path[c + 1]); c--; } - return((wchar_t *)path); + return((char *)path); } /* Return the 'directory' element of a pathname. */ void -plat_get_dirname(wchar_t *dest, const wchar_t *path) +path_get_dirname(char *dest, const char *path) { - int c = (int)wcslen(path); - wchar_t *ptr; + int c = (int)strlen(path); + char *ptr; - ptr = (wchar_t *)path; + ptr = (char *)path; while (c > 0) { - if (path[c] == L'/' || path[c] == L'\\') { - ptr = (wchar_t *)&path[c]; + if (path[c] == '/' || path[c] == '\\') { + ptr = (char *)&path[c]; break; } c--; @@ -568,17 +804,17 @@ plat_get_dirname(wchar_t *dest, const wchar_t *path) /* Copy to destination. */ while (path < ptr) *dest++ = *path++; - *dest = L'\0'; + *dest = '\0'; } -wchar_t * -plat_get_filename(wchar_t *s) +char * +path_get_filename(char *s) { - int c = wcslen(s) - 1; + int c = strlen(s) - 1; while (c > 0) { - if (s[c] == L'/' || s[c] == L'\\') + if (s[c] == '/' || s[c] == '\\') return(&s[c+1]); c--; } @@ -587,47 +823,61 @@ plat_get_filename(wchar_t *s) } -wchar_t * -plat_get_extension(wchar_t *s) +char * +path_get_extension(char *s) { - int c = wcslen(s) - 1; + int c = strlen(s) - 1; if (c <= 0) return(s); - while (c && s[c] != L'.') + while (c && s[c] != '.') c--; if (!c) - return(&s[wcslen(s)]); + return(&s[strlen(s)]); return(&s[c+1]); } void -plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2) +path_append_filename(char *dest, const char *s1, const char *s2) { - wcscat(dest, s1); - plat_path_slash(dest); - wcscat(dest, s2); + strcpy(dest, s1); + path_slash(dest); + strcat(dest, s2); } void -plat_put_backslash(wchar_t *s) +plat_put_backslash(char *s) { - int c = wcslen(s) - 1; + int c = strlen(s) - 1; - if (s[c] != L'/' && s[c] != L'\\') - s[c] = L'/'; + if (s[c] != '/' && s[c] != '\\') + s[c] = '/'; } int -plat_dir_check(wchar_t *path) +plat_dir_check(char *path) { - DWORD dwAttrib = GetFileAttributes(path); + DWORD dwAttrib; + int len; + wchar_t *temp; + + if (acp_utf8) + dwAttrib = GetFileAttributesA(path); + else { + len = mbstoc16s(NULL, path, 0) + 1; + temp = malloc(len * sizeof(wchar_t)); + mbstoc16s(temp, path, len); + + dwAttrib = GetFileAttributesW(temp); + + free(temp); + } return(((dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) ? 1 : 0); @@ -635,9 +885,62 @@ plat_dir_check(wchar_t *path) int -plat_dir_create(wchar_t *path) +plat_dir_create(char *path) { - return((int)SHCreateDirectory(hwndMain, path)); + int ret, len; + wchar_t *temp; + + if (acp_utf8) + return (int)SHCreateDirectoryExA(NULL, path, NULL); + else { + len = mbstoc16s(NULL, path, 0) + 1; + temp = malloc(len * sizeof(wchar_t)); + mbstoc16s(temp, path, len); + + ret = (int)SHCreateDirectoryExW(NULL, temp, NULL); + + free(temp); + + return ret; + } +} + + +void * +plat_mmap(size_t size, uint8_t executable) +{ + return VirtualAlloc(NULL, size, MEM_COMMIT, executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); +} + + +void +plat_init_rom_paths() +{ + wchar_t appdata_dir[1024] = { L'\0' }; + + if (_wgetenv(L"LOCALAPPDATA") && _wgetenv(L"LOCALAPPDATA")[0] != L'\0') { + char appdata_dir_a[1024] = { '\0' }; + size_t len = 0; + wcsncpy(appdata_dir, _wgetenv(L"LOCALAPPDATA"), 1024); + len = wcslen(appdata_dir); + if (appdata_dir[len - 1] != L'\\') { + appdata_dir[len] = L'\\'; + appdata_dir[len + 1] = L'\0'; + } + wcscat(appdata_dir, L"86box"); + CreateDirectoryW(appdata_dir, NULL); + wcscat(appdata_dir, L"\\roms"); + CreateDirectoryW(appdata_dir, NULL); + wcscat(appdata_dir, L"\\"); + c16stombs(appdata_dir_a, appdata_dir, 1024); + rom_add_path(appdata_dir_a); + } +} + +void +plat_munmap(void *ptr, size_t size) +{ + VirtualFree(ptr, 0, MEM_RELEASE); } @@ -651,13 +954,42 @@ plat_timer_read(void) return(li.QuadPart); } +static LARGE_INTEGER +plat_get_ticks_common(void) +{ + LARGE_INTEGER EndingTime, ElapsedMicroseconds; + + if (first_use) { + QueryPerformanceFrequency(&Frequency); + QueryPerformanceCounter(&StartingTime); + first_use = 0; + } + + QueryPerformanceCounter(&EndingTime); + ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; + + /* We now have the elapsed number of ticks, along with the + number of ticks-per-second. We use these values + to convert to the number of elapsed microseconds. + To guard against loss-of-precision, we convert + to microseconds *before* dividing by ticks-per-second. */ + ElapsedMicroseconds.QuadPart *= 1000000; + ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; + + return ElapsedMicroseconds; +} uint32_t plat_get_ticks(void) { - return(GetTickCount()); + return (uint32_t)(plat_get_ticks_common().QuadPart / 1000); } +uint32_t +plat_get_micro_ticks(void) +{ + return (uint32_t)plat_get_ticks_common().QuadPart; +} void plat_delay_ms(uint32_t count) @@ -679,8 +1011,8 @@ plat_vidapi(char *name) if (!strcasecmp(name, "ddraw") || !strcasecmp(name, "sdl")) return(1); for (i = 0; i < RENDERERS_NUM; i++) { - if (vid_apis[0][i].name && - !strcasecmp(vid_apis[0][i].name, name)) return(i); + if (vid_apis[i].name && + !strcasecmp(vid_apis[i].name, name)) return(i); } /* Default value. */ @@ -700,9 +1032,14 @@ plat_vidapi_name(int api) break; case 1: break; - -#ifdef USE_VNC case 2: + name = "sdl_opengl"; + break; + case 3: + name = "opengl_core"; + break; +#ifdef USE_VNC + case 4: name = "vnc"; break; #endif @@ -722,19 +1059,18 @@ plat_setvid(int api) win_log("Initializing VIDAPI: api=%d\n", api); startblit(); - video_wait_for_blit(); /* Close the (old) API. */ - vid_apis[0][vid_api].close(); + vid_apis[vid_api].close(); vid_api = api; - if (vid_apis[0][vid_api].local) + if (vid_apis[vid_api].local) ShowWindow(hwndRender, SW_SHOW); else ShowWindow(hwndRender, SW_HIDE); /* Initialize the (new) API. */ - i = vid_apis[0][vid_api].init((void *)hwndRender); + i = vid_apis[vid_api].init((void *)hwndRender); endblit(); if (! i) return(0); @@ -750,11 +1086,10 @@ plat_setvid(int api) void plat_vidsize(int x, int y) { - if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].resize) return; + if (!vid_api_inited || !vid_apis[vid_api].resize) return; startblit(); - video_wait_for_blit(); - vid_apis[video_fullscreen][vid_api].resize(x, y); + vid_apis[vid_api].resize(x, y); endblit(); } @@ -762,73 +1097,181 @@ plat_vidsize(int x, int y) void plat_vidapi_enable(int enable) { - if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].enable) return; + int i = 1; - startblit(); - video_wait_for_blit(); - vid_apis[video_fullscreen][vid_api].enable(enable); - endblit(); + if (!vid_api_inited || !vid_apis[vid_api].enable) + return; + + vid_apis[vid_api].enable(enable != 0); + + if (! i) + return; + + if (enable) + device_force_redraw(); } + int get_vidpause(void) { - return(vid_apis[video_fullscreen][vid_api].pause()); + return(vid_apis[vid_api].pause()); } void plat_setfullscreen(int on) { - HWND *hw; + RECT rect; + int temp_x, temp_y; + int dpi = win_get_dpi(hwndMain); - /* Want off and already off? */ - if (!on && !video_fullscreen) return; - - /* Want on and already on? */ - if (on && video_fullscreen) return; + /* Are we changing from the same state to the same state? */ + if ((!!(on & 1)) == (!!video_fullscreen)) + return; if (on && video_fullscreen_first) { - if (ui_msgbox_header(MBX_INFO | MBX_DONTASK, (wchar_t *) IDS_2134, (wchar_t *) IDS_2052) == 10) + video_fullscreen |= 2; + if (ui_msgbox_header(MBX_INFO | MBX_DONTASK, (wchar_t *) IDS_2134, (wchar_t *) IDS_2052) == 10) { video_fullscreen_first = 0; + config_save(); + } + video_fullscreen &= 1; } /* OK, claim the video. */ - startblit(); - video_wait_for_blit(); - - plat_vidapi_enable(0); - - win_mouse_close(); + if (!(on & 2)) + win_mouse_close(); /* Close the current mode, and open the new one. */ - vid_apis[video_fullscreen][vid_api].close(); - video_fullscreen = on; - hw = (video_fullscreen) ? &hwndMain : &hwndRender; - vid_apis[video_fullscreen][vid_api].init((void *) *hw); + video_fullscreen = (on & 1) | 2; + if (vid_apis[vid_api].set_fs) + vid_apis[vid_api].set_fs(on & 1); + if (!(on & 1)) { + plat_resize(scrnsz_x, scrnsz_y); + if (vid_resize) { + /* scale the screen base on DPI */ + if (!(vid_resize & 2) && window_remember) { + MoveWindow(hwndMain, window_x, window_y, window_w, window_h, TRUE); + GetClientRect(hwndMain, &rect); + + temp_x = rect.right - rect.left + 1; + temp_y = rect.bottom - rect.top + 1 - (hide_status_bar ? 0 : sbar_height) - (hide_tool_bar ? 0 : tbar_height); + } else { + if (dpi_scale) { + temp_x = MulDiv((vid_resize & 2) ? fixed_size_x : unscaled_size_x, dpi, 96); + temp_y = MulDiv((vid_resize & 2) ? fixed_size_y : unscaled_size_y, dpi, 96); + } else { + temp_x = (vid_resize & 2) ? fixed_size_x : unscaled_size_x; + temp_y = (vid_resize & 2) ? fixed_size_y : unscaled_size_y; + } + + /* Main Window. */ + if (vid_resize >= 2) + MoveWindow(hwndMain, window_x, window_y, window_w, window_h, TRUE); + + ResizeWindowByClientArea(hwndMain, temp_x, temp_y + (hide_status_bar ? 0 : sbar_height) + (hide_tool_bar ? 0 : tbar_height)); + } + + /* Toolbar. */ + MoveWindow(hwndRebar, 0, 0, temp_x, tbar_height, TRUE); + + /* Render window. */ + MoveWindow(hwndRender, 0, hide_tool_bar ? 0 : tbar_height, temp_x, temp_y, TRUE); + + /* Status bar. */ + GetClientRect(hwndMain, &rect); + MoveWindow(hwndSBAR, 0, rect.bottom - sbar_height, temp_x, sbar_height, TRUE); + + if (mouse_capture) + ClipCursor(&rect); + + scrnsz_x = (vid_resize & 2) ? fixed_size_x : unscaled_size_x; + scrnsz_y = (vid_resize & 2) ? fixed_size_y : unscaled_size_y; + } + } + video_fullscreen &= 1; + video_force_resize_set(1); + if (!(on & 1)) + atomic_store(&doresize_monitors[0], 1); win_mouse_init(); - plat_vidapi_enable(1); + if (!(on & 2)) { + /* Release video and make it redraw the screen. */ + device_force_redraw(); - /* Release video and make it redraw the screen. */ - endblit(); - device_force_redraw(); - - /* Send a CTRL break code so CTRL does not get stuck. */ - keyboard_input(0, 0x01D); + /* Send a CTRL break code so CTRL does not get stuck. */ + keyboard_input(0, 0x01D); + } /* Finally, handle the host's mouse cursor. */ /* win_log("%s full screen, %s cursor\n", on ? "enter" : "leave", on ? "hide" : "show"); */ show_cursor(video_fullscreen ? 0 : -1); + + if (!(on & 2)) { + /* This is needed for OpenGL. */ + plat_vidapi_enable(0); + plat_vidapi_enable(1); + } } +void +plat_vid_reload_options(void) +{ + if (!vid_api_inited || !vid_apis[vid_api].reload) + return; + + vid_apis[vid_api].reload(); +} + + +void +plat_vidapi_reload(void) +{ + vid_apis[vid_api].reload(); +} + + +/* Sets up the program language before initialization. */ +uint32_t +plat_language_code(char* langcode) +{ + if (!strcmp(langcode, "system")) + return 0xFFFF; + + int len = mbstoc16s(NULL, langcode, 0) + 1; + wchar_t *temp = malloc(len * sizeof(wchar_t)); + mbstoc16s(temp, langcode, len); + + LCID lcid = LocaleNameToLCID((LPWSTR)temp, 0); + + free(temp); + return lcid; +} + +/* Converts back the language code to LCID */ +void +plat_language_code_r(uint32_t lcid, char* outbuf, int len) +{ + if (lcid == 0xFFFF) + { + strcpy(outbuf, "system"); + return; + } + + wchar_t buffer[LOCALE_NAME_MAX_LENGTH + 1]; + LCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0); + + c16stombs(outbuf, buffer, len); +} + void take_screenshot(void) { startblit(); - screenshots++; + monitors[0].mon_screenshots++; endblit(); device_force_redraw(); } diff --git a/src/win/win_about.c b/src/win/win_about.c index b09efa478..c508c7b3c 100644 --- a/src/win/win_about.c +++ b/src/win/win_about.c @@ -30,6 +30,7 @@ #include <86box/86box.h> #include <86box/plat.h> #include <86box/win.h> +#include <86box/version.h> void @@ -38,17 +39,23 @@ AboutDialogCreate(HWND hwnd) int i; TASKDIALOGCONFIG tdconfig = {0}; TASKDIALOG_BUTTON tdbuttons[] = { - {IDOK, EMU_SITE}, - {IDCANCEL, MAKEINTRESOURCE(IDS_2127)} + {IDOK, EMU_SITE_W}, + {IDCANCEL, MAKEINTRESOURCE(IDS_2127)} }; + wchar_t emu_version[256]; + i = swprintf(emu_version, sizeof(emu_version), L"%ls v%ls", EMU_NAME_W, EMU_VERSION_FULL_W); +#ifdef EMU_GIT_HASH + swprintf(&emu_version[i], sizeof(emu_version) - i, L" [%ls]", EMU_GIT_HASH_W); +#endif + tdconfig.cbSize = sizeof(tdconfig); tdconfig.hwndParent = hwnd; tdconfig.hInstance = hinstance; tdconfig.dwCommonButtons = 0; tdconfig.pszWindowTitle = MAKEINTRESOURCE(IDS_2124); tdconfig.pszMainIcon = (PCWSTR) 10; - tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2125); + tdconfig.pszMainInstruction = emu_version; tdconfig.pszContent = MAKEINTRESOURCE(IDS_2126); tdconfig.cButtons = ARRAYSIZE(tdbuttons); tdconfig.pButtons = tdbuttons; @@ -56,5 +63,5 @@ AboutDialogCreate(HWND hwnd) TaskDialogIndirect(&tdconfig, &i, NULL, NULL); if (i == IDOK) - ShellExecute(hwnd, L"open", L"https://" EMU_SITE, NULL, NULL, SW_SHOW); + ShellExecute(hwnd, L"open", L"https://" EMU_SITE_W, NULL, NULL, SW_SHOW); } diff --git a/src/win/win_cdrom.c b/src/win/win_cdrom.c index f470c0a57..8a32df295 100644 --- a/src/win/win_cdrom.c +++ b/src/win/win_cdrom.c @@ -27,8 +27,12 @@ #include #include #include +#include <86box/86box.h> #include <86box/config.h> #include <86box/timer.h> +#include <86box/device.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> #include <86box/fdd.h> #include <86box/hdd.h> #include <86box/scsi_device.h> @@ -42,17 +46,69 @@ void -floppy_mount(uint8_t id, wchar_t *fn, uint8_t wp) +cassette_mount(char *fn, uint8_t wp) +{ + pc_cas_set_fname(cassette, NULL); + memset(cassette_fname, 0, sizeof(cassette_fname)); + cassette_ui_writeprot = wp; + pc_cas_set_fname(cassette, fn); + if (fn != NULL) + memcpy(cassette_fname, fn, MIN(511, strlen(fn))); + ui_sb_update_icon_state(SB_CASSETTE, (fn == NULL) ? 1 : 0); + media_menu_update_cassette(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + + +void +cassette_eject(void) +{ + pc_cas_set_fname(cassette, NULL); + memset(cassette_fname, 0x00, sizeof(cassette_fname)); + ui_sb_update_icon_state(SB_CASSETTE, 1); + media_menu_update_cassette(); + ui_sb_update_tip(SB_CASSETTE); + config_save(); +} + + +void +cartridge_mount(uint8_t id, char *fn, uint8_t wp) +{ + cart_close(id); + cart_load(id, fn); + ui_sb_update_icon_state(SB_CARTRIDGE | id, strlen(cart_fns[id]) ? 0 : 1); + media_menu_update_cartridge(id); + ui_sb_update_tip(SB_CARTRIDGE | id); + config_save(); +} + + +void +cartridge_eject(uint8_t id) +{ + cart_close(id); + ui_sb_update_icon_state(SB_CARTRIDGE | id, 1); + media_menu_update_cartridge(id); + ui_sb_update_tip(SB_CARTRIDGE | id); + config_save(); +} + + +void +floppy_mount(uint8_t id, char *fn, uint8_t wp) { fdd_close(id); ui_writeprot[id] = wp; fdd_load(id, fn); - ui_sb_update_icon_state(SB_FLOPPY | id, wcslen(floppyfns[id]) ? 0 : 1); + ui_sb_update_icon_state(SB_FLOPPY | id, strlen(floppyfns[id]) ? 0 : 1); media_menu_update_floppy(id); ui_sb_update_tip(SB_FLOPPY | id); config_save(); } + void floppy_eject(uint8_t id) { @@ -80,10 +136,10 @@ plat_cdrom_ui_update(uint8_t id, uint8_t reload) } void -cdrom_mount(uint8_t id, wchar_t *fn) +cdrom_mount(uint8_t id, char *fn) { cdrom[id].prev_host_drive = cdrom[id].host_drive; - wcscpy(cdrom[id].prev_image_path, cdrom[id].image_path); + strcpy(cdrom[id].prev_image_path, cdrom[id].image_path); if (cdrom[id].ops && cdrom[id].ops->exit) cdrom[id].ops->exit(&(cdrom[id])); cdrom[id].ops = NULL; @@ -92,7 +148,7 @@ cdrom_mount(uint8_t id, wchar_t *fn) /* Signal media change to the emulated machine. */ if (cdrom[id].insert) cdrom[id].insert(cdrom[id].priv); - cdrom[id].host_drive = (wcslen(cdrom[id].image_path) == 0) ? 0 : 200; + cdrom[id].host_drive = (strlen(cdrom[id].image_path) == 0) ? 0 : 200; if (cdrom[id].host_drive == 200) { ui_sb_update_icon_state(SB_CDROM | id, 0); } else { @@ -122,7 +178,7 @@ mo_eject(uint8_t id) void -mo_mount(uint8_t id, wchar_t *fn, uint8_t wp) +mo_mount(uint8_t id, char *fn, uint8_t wp) { mo_t *dev = (mo_t *) mo_drives[id].priv; @@ -131,7 +187,7 @@ mo_mount(uint8_t id, wchar_t *fn, uint8_t wp) mo_load(dev, fn); mo_insert(dev); - ui_sb_update_icon_state(SB_MO | id, wcslen(mo_drives[id].image_path) ? 0 : 1); + ui_sb_update_icon_state(SB_MO | id, strlen(mo_drives[id].image_path) ? 0 : 1); media_menu_update_mo(id); ui_sb_update_tip(SB_MO | id); @@ -145,7 +201,7 @@ mo_reload(uint8_t id) mo_t *dev = (mo_t *) mo_drives[id].priv; mo_disk_reload(dev); - if (wcslen(mo_drives[id].image_path) == 0) { + if (strlen(mo_drives[id].image_path) == 0) { ui_sb_update_icon_state(SB_MO|id, 1); } else { ui_sb_update_icon_state(SB_MO|id, 0); @@ -176,7 +232,7 @@ zip_eject(uint8_t id) void -zip_mount(uint8_t id, wchar_t *fn, uint8_t wp) +zip_mount(uint8_t id, char *fn, uint8_t wp) { zip_t *dev = (zip_t *) zip_drives[id].priv; @@ -185,7 +241,7 @@ zip_mount(uint8_t id, wchar_t *fn, uint8_t wp) zip_load(dev, fn); zip_insert(dev); - ui_sb_update_icon_state(SB_ZIP | id, wcslen(zip_drives[id].image_path) ? 0 : 1); + ui_sb_update_icon_state(SB_ZIP | id, strlen(zip_drives[id].image_path) ? 0 : 1); media_menu_update_zip(id); ui_sb_update_tip(SB_ZIP | id); @@ -199,7 +255,7 @@ zip_reload(uint8_t id) zip_t *dev = (zip_t *) zip_drives[id].priv; zip_disk_reload(dev); - if (wcslen(zip_drives[id].image_path) == 0) { + if (strlen(zip_drives[id].image_path) == 0) { ui_sb_update_icon_state(SB_ZIP|id, 1); } else { ui_sb_update_icon_state(SB_ZIP|id, 0); diff --git a/src/win/win_crashdump.c b/src/win/win_crashdump.c deleted file mode 100644 index e1123c1e5..000000000 --- a/src/win/win_crashdump.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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. - * - * Handle generation of crash-dump reports. - * - * - * - * Authors: Riley - * Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2016,2017 Riley. - * Copyright 2016,2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. - */ -#define _WIN32_WINNT 0x0501 -#include -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/plat.h> -#include <86box/win.h> - - -#define ExceptionHandlerBufferSize (10240) - - -static PVOID hExceptionHandler; -static char *ExceptionHandlerBuffer, - *CurrentBufferPointer; - - -LONG CALLBACK MakeCrashDump(PEXCEPTION_POINTERS ExceptionInfo) -{ - SYSTEMTIME SystemTime; - HANDLE hDumpFile; - char *BufPtr; - - /* - * Win32-specific functions will be used wherever possible, - * just in case the C stdlib-equivalents try to allocate - * memory. - * (The Win32-specific functions are generally just wrappers - * over NT system calls anyway.) - */ - if ((ExceptionInfo->ExceptionRecord->ExceptionCode >> 28) != 0xC) { - /* - * ExceptionCode is not a fatal exception (high 4b of - * ntstatus = 0xC) Not going to crash, let's not make - * a crash dump. - */ - return(EXCEPTION_CONTINUE_SEARCH); - } - - /* - * So, the program is about to crash. Oh no what do? - * Let's create a crash dump file as a debugging-aid. - * - * First, get the path to the executable. - */ - GetModuleFileName(NULL,ExceptionHandlerBuffer,ExceptionHandlerBufferSize); - if (GetLastError() != ERROR_SUCCESS) { - /* Could not get full path, create in current directory. */ - BufPtr = ExceptionHandlerBuffer; - } else { - /* - * Walk through the string backwards looking for the - * last backslash, so as to remove the "86Box.exe" - * filename from the string. - */ - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - for (; BufPtr > ExceptionHandlerBuffer; BufPtr--) { - if (BufPtr[0] == '\\') { - /* Found backslash, terminate the string after it. */ - BufPtr[1] = 0; - break; - } - } - - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - } - - /* - * What would a good filename be? - * - * It should contain the current date and time so as - * to be (hopefully!) unique. - */ - GetSystemTime(&SystemTime); - sprintf(CurrentBufferPointer, - "86box-%d%02d%02d-%02d-%02d-%02d-%03d.dmp", - SystemTime.wYear, - SystemTime.wMonth, - SystemTime.wDay, - SystemTime.wHour, - SystemTime.wMinute, - SystemTime.wSecond, - SystemTime.wMilliseconds); - - /* Now the filename is in the buffer, the file can be created. */ - hDumpFile = CreateFile( - ExceptionHandlerBuffer, // The filename of the file to open. - GENERIC_WRITE, // The permissions to request. - 0, // Make sure other processes can't - // touch the crash dump at all - // while it's open. - NULL, // Leave the security descriptor - // undefined, it doesn't matter. - OPEN_ALWAYS, // Opens the file if it exists, - // creates a new file if it doesn't. - FILE_ATTRIBUTE_NORMAL, // File attributes / etc don't matter. - NULL); // A template file is not being used. - - /* Check to make sure the file was actually created. */ - if (hDumpFile == INVALID_HANDLE_VALUE) { - /* CreateFile() failed, so just do nothing more. */ - return(EXCEPTION_CONTINUE_SEARCH); - } - - /* - * Write the data we were passed out in a human-readable format. - * - * Get the name of the module where the exception occurred. - */ - HMODULE hMods[1024]; - MODULEINFO modInfo; - HMODULE ipModule = 0; - DWORD cbNeeded; - - /* Try to get a list of all loaded modules. */ - if (EnumProcessModules(GetCurrentProcess(), - hMods, sizeof(hMods), &cbNeeded)) { - /* Got it, now walk through all modules.. */ - for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { - /* For each module, get the module information. */ - GetModuleInformation(GetCurrentProcess(), - hMods[i], &modInfo, sizeof(MODULEINFO)); - /* If the exception address is in the range of this module.. */ - if ( (ExceptionInfo->ExceptionRecord->ExceptionAddress >= modInfo.lpBaseOfDll) && - (ExceptionInfo->ExceptionRecord->ExceptionAddress < (void*)((char*)modInfo.lpBaseOfDll + modInfo.SizeOfImage))) { - /* ...this is the module we're looking for! */ - ipModule = hMods[i]; - break; - } - } - } - - /* Start to put the crash-dump string into the buffer. */ - sprintf(ExceptionHandlerBuffer, - "#\r\n# %s\r\n#\r\n" - "# Crash on %d-%02d-%02d at %02d:%02d:%02d.%03d\r\n#\r\n" - "\r\n" - "Exception details:\r\n" - " NTSTATUS code: 0x%08lx\r\n Address: 0x%p", - emu_version, - SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, - SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, - SystemTime.wMilliseconds, - ExceptionInfo->ExceptionRecord->ExceptionCode, - (void *)ExceptionInfo->ExceptionRecord->ExceptionAddress); - - /* - * If we found the correct module, get the full path to - * the module the exception occured at and include it. - */ - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - if (ipModule != 0) { - sprintf(BufPtr," ["); - GetModuleFileName(ipModule, &BufPtr[2], - ExceptionHandlerBufferSize - strlen(ExceptionHandlerBuffer)); - if (GetLastError() == ERROR_SUCCESS) { - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - sprintf(BufPtr,"]"); - BufPtr += 1; - } - } - - sprintf(BufPtr, - "\r\nNumber of parameters: %lu\r\nException parameters: ", - ExceptionInfo->ExceptionRecord->NumberParameters); - - for (int i = 0; i < ExceptionInfo->ExceptionRecord->NumberParameters; i++) { - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - sprintf(BufPtr,"0x%p ", - (void *)ExceptionInfo->ExceptionRecord->ExceptionInformation[i]); - } - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer) - 1]; - -#if defined(__i386__) && !defined(__x86_64) - PCONTEXT Registers = ExceptionInfo->ContextRecord; - - /* This binary is being compiled for x86, include a register dump. */ - sprintf(BufPtr, - "\r\n\r\nRegister dump:\r\n\r\n" - "EIP:0x%08lx\r\n" - "EAX:0x%08lx EBX:0x%08lx ECX:0x%08lx EDX:0x%08lx\r\n" - "EBP:0x%08lx ESP:0x%08lx ESI:0x%08lx EDI:0x%08lx\r\n\r\n", - Registers->Eip, - Registers->Eax, Registers->Ebx, Registers->Ecx, Registers->Edx, - Registers->Ebp, Registers->Esp, Registers->Esi, Registers->Edi); -#else - /* Register dump not supported by this architecture. */ - /* (MinGW headers seem to lack the x64 CONTEXT structure definition) */ - sprintf(BufPtr, "\r\n"); -#endif - - /* Write the string to disk. */ - WriteFile(hDumpFile, ExceptionHandlerBuffer, - strlen(ExceptionHandlerBuffer), NULL, NULL); - - /* Close the file. */ - CloseHandle(hDumpFile); - - /* Return, therefore causing the crash. */ - return(EXCEPTION_CONTINUE_SEARCH); -} - - -void -InitCrashDump(void) -{ - /* - * An exception handler should not allocate memory, - * so allocate 10kb for it to use if it gets called, - * an amount which should be more than enough. - */ - ExceptionHandlerBuffer = malloc(ExceptionHandlerBufferSize); - CurrentBufferPointer = ExceptionHandlerBuffer; - - /* - * Register the exception handler. - * Zero first argument means this exception handler gets - * called last, therefore, crash dump is only made, when - * a crash is going to happen. - */ - hExceptionHandler = AddVectoredExceptionHandler(0, MakeCrashDump); -} diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index d07482f46..01bd58d0d 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -25,7 +25,9 @@ #include <86box/config.h> #include <86box/device.h> #include <86box/plat.h> -#include <86box/plat_midi.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/midi_rtmidi.h> #include <86box/ui.h> #include <86box/win.h> #include @@ -33,7 +35,8 @@ static device_context_t config_device; -static uint8_t deviceconfig_changed = 0; +static uint8_t deviceconfig_changed = 0; +static int combo_to_struct[256]; #if defined(__amd64__) || defined(__aarch64__) @@ -45,12 +48,17 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; - int val_int, id, c, d, num; + int val_int, id, c, d; + int p, q; +#ifdef USE_RTMIDI + int num; +#endif int changed, cid; const device_config_t *config; const device_config_selection_t *selection; + const device_config_bios_t *bios; char s[512], file_filter[512]; - char *str; + char *str, *val_str; wchar_t ws[512], *wstr; LPTSTR lptsTemp; @@ -62,9 +70,11 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) config = config_device.dev->config; lptsTemp = (LPTSTR) malloc(512); + memset(combo_to_struct, 0, 256 * sizeof(int)); while (config->type != -1) { selection = config->selection; + bios = config->bios; h = GetDlgItem(hdlg, id); switch (config->type) { @@ -81,7 +91,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) (char *) config->name, config->default_int); c = 0; - while (selection->description && selection->description[0]) { + while (selection && selection->description && selection->description[0]) { mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); @@ -93,13 +103,38 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - case CONFIG_MIDI: + case CONFIG_BIOS: + val_str = config_get_string((char *) config_device.name, + (char *) config->name, (char *) config->default_string); + + c = 0; + q = 0; + while (bios && bios->name && bios->name[0]) { + mbstowcs(lptsTemp, bios->name, strlen(bios->name) + 1); + p = 0; + for (d = 0; d < bios->files_no; d++) + p += !!rom_present((char *) bios->files[d]); + if (p == bios->files_no) { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (!strcmp(val_str, bios->internal_name)) + SendMessage(h, CB_SETCURSEL, c, 0); + combo_to_struct[c] = q; + c++; + } + q++; + bios++; + } + + id += 2; + break; +#ifdef USE_RTMIDI + case CONFIG_MIDI_OUT: val_int = config_get_int((char *) config_device.name, (char *) config->name, config->default_int); - num = plat_midi_get_num_devs(); + num = rtmidi_out_get_num_devs(); for (c = 0; c < num; c++) { - plat_midi_get_dev_name(c, s); + rtmidi_out_get_dev_name(c, s); mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); if (val_int == c) @@ -112,9 +147,9 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) val_int = config_get_int((char *) config_device.name, (char *) config->name, config->default_int); - num = plat_midi_in_get_num_devs(); + num = rtmidi_in_get_num_devs(); for (c = 0; c < num; c++) { - plat_midi_in_get_dev_name(c, s); + rtmidi_in_get_dev_name(c, s); mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); if (val_int == c) @@ -122,7 +157,8 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } id += 2; - break; + break; +#endif case CONFIG_SPINNER: val_int = config_get_int((char *) config_device.name, (char *) config->name, config->default_int); @@ -144,7 +180,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) (char *) config->name, config->default_int); c = 0; - while (selection->description && selection->description[0]) { + while (selection && selection->description && selection->description[0]) { mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); @@ -161,7 +197,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) (char *) config->name, config->default_int); c = 0; - while (selection->description && selection->description[0]) { + while (selection && selection->description && selection->description[0]) { mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); @@ -183,6 +219,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (cid == IDOK) { id = IDC_CONFIG_BASE; config = config_device.dev->config; + bios = config->bios; changed = 0; char s[512]; @@ -214,7 +251,21 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - case CONFIG_MIDI: + case CONFIG_BIOS: + val_str = config_get_string((char *) config_device.name, + (char *) config->name, (char *) config->default_string); + + c = combo_to_struct[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + for (; c > 0; c--) + bios++; + + if (strcmp(val_str, bios->internal_name)) + changed = 1; + + id += 2; + break; + case CONFIG_MIDI_OUT: val_int = config_get_int((char *) config_device.name, (char *) config->name, config->default_int); @@ -324,7 +375,15 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - case CONFIG_MIDI: + case CONFIG_BIOS: + c = combo_to_struct[SendMessage(h, CB_GETCURSEL, 0, 0)]; + for (; c > 0; c--) + bios++; + config_set_string((char *) config_device.name, (char *) config->name, (char *) bios->internal_name); + + id += 2; + break; + case CONFIG_MIDI_OUT: c = SendMessage(h, CB_GETCURSEL, 0, 0); config_set_int((char *) config_device.name, (char *) config->name, c); @@ -389,7 +448,10 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id++; break; case CONFIG_SELECTION: - case CONFIG_MIDI: + case CONFIG_HEX16: + case CONFIG_HEX20: + case CONFIG_BIOS: + case CONFIG_MIDI_OUT: case CONFIG_MIDI_IN: case CONFIG_SPINNER: id += 2; @@ -401,31 +463,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); file_filter[0] = 0; - c = 0; - while (config->file_filter[c].description && config->file_filter[c].description[0]) { - if (c > 0) - strcat(file_filter, "|"); - strcat(file_filter, config->file_filter[c].description); - strcat(file_filter, " ("); - d = 0; - while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) { - if (d > 0) - strcat(file_filter, ";"); - strcat(file_filter, "*."); - strcat(file_filter, config->file_filter[c].extensions[d]); - d++; - } - strcat(file_filter, ")|"); - d = 0; - while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) { - if (d > 0) - strcat(file_filter, ";"); - strcat(file_filter, "*."); - strcat(file_filter, config->file_filter[c].extensions[d]); - d++; - } - c++; - } + strcat(file_filter, config->file_filter); strcat(file_filter, "|All files (*.*)|*.*|"); mbstowcs(ws, file_filter, strlen(file_filter) + 1); d = strlen(file_filter); @@ -436,7 +474,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) ws[c] = 0; } - if (!file_dlg(hdlg, ws, s, 0)) + if (!file_dlg(hdlg, ws, s, NULL, 0)) SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); } break; @@ -478,7 +516,8 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) *data++ = 0; /*no menu*/ *data++ = 0; /*predefined dialog box class*/ - data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 120); + + data += wsprintf(data, plat_get_string(IDS_2141), device->name) + 1; *data++ = 9; /*Point*/ data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); @@ -494,7 +533,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) item->y = y; item->id = id++; - item->cx = 80; + item->cx = 100; item->cy = 15; item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; @@ -510,7 +549,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) break; case CONFIG_SELECTION: - case CONFIG_MIDI: + case CONFIG_MIDI_OUT: case CONFIG_MIDI_IN: case CONFIG_HEX16: case CONFIG_HEX20: @@ -523,7 +562,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -538,11 +577,11 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; item->cx = 60; - item->cy = 15; + item->cy = 20; item->style = WS_CHILD | WS_VISIBLE; @@ -585,11 +624,11 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; item->cx = 60; - item->cy = 15; + item->cy = 20; item->style = WS_CHILD | WS_VISIBLE; @@ -652,11 +691,11 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; item->cx = 60; - item->cy = 15; + item->cy = 20; item->style = WS_CHILD | WS_VISIBLE; @@ -683,8 +722,8 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) dlg->cdit = (id - IDC_CONFIG_BASE) + 2; item = (DLGITEMTEMPLATE *)data; - item->x = 20; - item->y = y; + item->x = 100; + item->y = y + 5; item->cx = 50; item->cy = 14; item->id = IDOK; /* OK button identifier */ @@ -701,8 +740,8 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) data++; item = (DLGITEMTEMPLATE *)data; - item->x = 80; - item->y = y; + item->x = 160; + item->y = y + 5; item->cx = 50; item->cy = 14; item->id = IDCANCEL; /* OK button identifier */ @@ -715,7 +754,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); *data++ = 0; /* no creation data */ - dlg->cy = y + 20; + dlg->cy = y + 25; device_set_context(&config_device, device, inst); diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index bc8964f95..3bf8f1662 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -35,7 +35,7 @@ -#define STRING_OR_RESOURCE(s) ((!(s)) ? (NULL) : ((((uintptr_t)s) < ((uintptr_t)65636)) ? (MAKEINTRESOURCE(s)) : (s))) +#define STRING_OR_RESOURCE(s) ((!(s)) ? (NULL) : ((((uintptr_t)s) < ((uintptr_t)65636)) ? (MAKEINTRESOURCE((uintptr_t)s)) : (s))) WCHAR wopenfilestring[512]; @@ -100,13 +100,14 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi case MBX_QUESTION: /* question */ case MBX_QUESTION_YN: + case MBX_QUESTION_OK: if (!btn1) /* replace default "OK" button with "Yes" button */ - tdconfig.dwCommonButtons = TDCBF_YES_BUTTON; + tdconfig.dwCommonButtons = (flags & MBX_QUESTION_OK) ? TDCBF_OK_BUTTON : TDCBF_YES_BUTTON; if (btn2) /* "No" button */ tdbuttons[tdconfig.cButtons++] = tdb_no; else - tdconfig.dwCommonButtons |= TDCBF_NO_BUTTON; + tdconfig.dwCommonButtons |= (flags & MBX_QUESTION_OK) ? TDCBF_CANCEL_BUTTON : TDCBF_NO_BUTTON; if (flags & MBX_QUESTION) { if (btn3) /* "Cancel" button */ @@ -114,13 +115,16 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi else tdconfig.dwCommonButtons |= TDCBF_CANCEL_BUTTON; } + + if (flags & MBX_WARNING) + tdconfig.pszMainIcon = TD_WARNING_ICON; break; } /* If the message is an ANSI string, convert it. */ tdconfig.pszContent = (WCHAR *) STRING_OR_RESOURCE(message); if (flags & MBX_ANSI) { - mbstowcs(temp, (char *)message, strlen((char *)message)+1); + mbstoc16s(temp, (char *)message, strlen((char *)message)+1); tdconfig.pszContent = temp; } @@ -144,6 +148,7 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi else if (ret == IDCANCEL) ret = -1; else ret = 0; + /* 10 is added to the return value if "don't show again" is checked. */ if (checked) ret += 10; return(ret); @@ -151,11 +156,12 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi int -file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) +file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, WCHAR *title, int save) { OPENFILENAME ofn; BOOL r; /* DWORD err; */ + int old_dopause; /* Initialize OPENFILENAME */ ZeroMemory(&ofn, sizeof(ofn)); @@ -167,6 +173,7 @@ file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) * Set lpstrFile[0] to '\0' so that GetOpenFileName does * not use the contents of szFile to initialize itself. */ + memset(ofn.lpstrFile, 0x00, 512 * sizeof(WCHAR)); memcpy(ofn.lpstrFile, fn, (wcslen(fn) << 1) + 2); ofn.nMaxFile = sizeof_w(wopenfilestring); ofn.lpstrFilter = f; @@ -177,17 +184,22 @@ file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) ofn.Flags = OFN_PATHMUSTEXIST; if (! save) ofn.Flags |= OFN_FILEMUSTEXIST; + if (title) + ofn.lpstrTitle = title; /* Display the Open dialog box. */ + old_dopause = dopause; + plat_pause(1); if (save) r = GetSaveFileName(&ofn); else r = GetOpenFileName(&ofn); + plat_pause(old_dopause); plat_chdir(usr_path); if (r) { - wcstombs(openfilestring, wopenfilestring, sizeof(openfilestring)); + c16stombs(openfilestring, wopenfilestring, sizeof(openfilestring)); filterindex = ofn.nFilterIndex; return(0); @@ -198,37 +210,44 @@ file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) int -file_dlg(HWND hwnd, WCHAR *f, char *fn, int save) +file_dlg(HWND hwnd, WCHAR *f, char *fn, char *title, int save) { - WCHAR ufn[512]; + WCHAR ufn[512], title_buf[512]; - mbstowcs(ufn, fn, strlen(fn) + 1); + mbstoc16s(ufn, fn, strlen(fn) + 1); + if (title) + mbstoc16s(title_buf, title, sizeof title_buf); - return(file_dlg_w(hwnd, f, ufn, save)); + return(file_dlg_w(hwnd, f, ufn, title ? title_buf : NULL, save)); } int -file_dlg_mb(HWND hwnd, char *f, char *fn, int save) +file_dlg_mb(HWND hwnd, char *f, char *fn, char *title, int save) { - WCHAR uf[512], ufn[512]; + WCHAR uf[512], ufn[512], title_buf[512]; - mbstowcs(uf, f, strlen(fn) + 1); - mbstowcs(ufn, fn, strlen(fn) + 1); + mbstoc16s(uf, f, strlen(f) + 1); + mbstoc16s(ufn, fn, strlen(fn) + 1); + if (title) + mbstoc16s(title_buf, title, sizeof title_buf); - return(file_dlg_w(hwnd, uf, ufn, save)); + return(file_dlg_w(hwnd, uf, ufn, title ? title_buf : NULL, save)); } int -file_dlg_w_st(HWND hwnd, int id, WCHAR *fn, int save) +file_dlg_w_st(HWND hwnd, int id, WCHAR *fn, char *title, int save) { - return(file_dlg_w(hwnd, plat_get_string(id), fn, save)); + WCHAR title_buf[512]; + if (title) + mbstoc16s(title_buf, title, sizeof title_buf); + return(file_dlg_w(hwnd, plat_get_string(id), fn, title ? title_buf : NULL, save)); } int -file_dlg_st(HWND hwnd, int id, char *fn, int save) +file_dlg_st(HWND hwnd, int id, char *fn, char *title, int save) { - return(file_dlg(hwnd, plat_get_string(id), fn, save)); + return(file_dlg(hwnd, plat_get_string(id), fn, title, save)); } diff --git a/src/win/win_discord.c b/src/win/win_discord.c deleted file mode 100644 index ec379ea9f..000000000 --- a/src/win/win_discord.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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. - * - * Discord integration module. - * - * - * - * Authors: David Hrdlička, - * - * Copyright 2019 David Hrdlička. - */ -#include -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include "cpu.h" -#include <86box/machine.h> -#include <86box/plat.h> -#include <86box/plat_dynld.h> -#include <86box/win_discord.h> -#include - -#define PATH_DISCORD_DLL "discord_game_sdk.dll" - -int discord_loaded = 0; - -static void *discord_handle = NULL; -static struct IDiscordCore *discord_core = NULL; -static struct IDiscordActivityManager *discord_activities = NULL; - -static enum EDiscordResult (*discord_create)(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result); - -static dllimp_t discord_imports[] = { - { "DiscordCreate", &discord_create }, - { NULL, NULL } -}; - -#ifndef ENABLE_DISCORD_LOG -int discord_do_log = 1; - - -static void -discord_log(const char *fmt, ...) -{ - va_list ap; - - if (discord_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define discord_log(fmt, ...) -#endif - -void -discord_update_activity(int paused) -{ - struct DiscordActivity activity; - wchar_t config_name_w[1024]; - char config_name[128]; - char *temp; - - if(discord_activities == NULL) - return; - - discord_log("win_discord: discord_update_activity(paused=%d)\n", paused); - - memset(&activity, 0x00, sizeof(activity)); - - plat_get_dirname(config_name_w, usr_path); - if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, plat_get_filename(config_name_w), -1, config_name, 128, NULL, NULL) > 0) - { - sprintf_s(activity.details, 128, "Running \"%s\"", config_name); - sprintf_s(activity.state, 128, "%s (%s)", strchr(machine_getname(), ']') + 2, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); - } - else - { - temp = strchr(machine_getname(), ']') + 2; - - if (strlen(temp) <= 127) - strcpy(activity.details, temp); - else - strncpy(activity.details, temp, 127); - - if (strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name) <= 127) - strcpy(activity.state, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); - else - strncpy(activity.state, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, 127); - } - - activity.timestamps.start = time(NULL); - -#ifdef RELEASE_BUILD - strcpy(activity.assets.large_image, "86box-rb"); -#else - strcpy(activity.assets.large_image, "86box"); -#endif - - if (paused) - { - strcpy(activity.assets.small_image, "status-paused"); - strcpy(activity.assets.small_text, "Paused"); - } - else - { - strcpy(activity.assets.small_image, "status-running"); - strcpy(activity.assets.small_text, "Running"); - } - - discord_activities->update_activity(discord_activities, &activity, NULL, NULL); -} - -int -discord_load() -{ - if (discord_handle != NULL) - return(1); - - // Try to load the DLL - discord_handle = dynld_module(PATH_DISCORD_DLL, discord_imports); - - if (discord_handle == NULL) - { - discord_log("win_discord: couldn't load " PATH_DISCORD_DLL "\n"); - discord_close(); - - return(0); - } - - discord_loaded = 1; - return(1); -} - -void -discord_init() -{ - enum EDiscordResult result; - struct DiscordCreateParams params; - - if(discord_handle == NULL) - return; - - DiscordCreateParamsSetDefault(¶ms); - params.client_id = 651478134352248832; - params.flags = DiscordCreateFlags_NoRequireDiscord; - - result = discord_create(DISCORD_VERSION, ¶ms, &discord_core); - if (result != DiscordResult_Ok) - { - discord_log("win_discord: DiscordCreate returned %d\n", result); - discord_close(); - return; - } - - discord_activities = discord_core->get_activity_manager(discord_core); - - return; -} - -void -discord_close() -{ - if (discord_core != NULL) - discord_core->destroy(discord_core); - - discord_core = NULL; - discord_activities = NULL; -} - -void -discord_run_callbacks() -{ - if(discord_core == NULL) - return; - - discord_core->run_callbacks(discord_core); -} diff --git a/src/win/win_dynld.c b/src/win/win_dynld.c index 41942ba61..98eb4739f 100644 --- a/src/win/win_dynld.c +++ b/src/win/win_dynld.c @@ -55,7 +55,7 @@ dynld_module(const char *name, dllimp_t *table) /* See if we can load the desired module. */ if ((h = LoadLibrary(name)) == NULL) { - dynld_log("DynLd(\"%s\"): library not found!\n", name); + dynld_log("DynLd(\"%s\"): library not found! (%08X)\n", name, GetLastError()); return(NULL); } @@ -63,8 +63,8 @@ dynld_module(const char *name, dllimp_t *table) for (imp=table; imp->name!=NULL; imp++) { func = GetProcAddress(h, imp->name); if (func == NULL) { - dynld_log("DynLd(\"%s\"): function '%s' not found!\n", - name, imp->name); + dynld_log("DynLd(\"%s\"): function '%s' not found! (%08X)\n", + name, imp->name, GetLastError()); FreeLibrary(h); return(NULL); } @@ -74,6 +74,7 @@ dynld_module(const char *name, dllimp_t *table) } /* All good. */ + dynld_log("loaded %s\n", name); return((void *)h); } diff --git a/src/win/win_icon.c b/src/win/win_icon.c new file mode 100644 index 000000000..c11125ecd --- /dev/null +++ b/src/win/win_icon.c @@ -0,0 +1,165 @@ +/* + * 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. + * + * Implement the application's icon changing system. + * + * + * Authors: Laci bá' + * + * Copyright 2021 Laci bá'. + */ + +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/path.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/win.h> + +HICON hIcon[256]; /* icon data loaded from resources */ +char icon_set[256] = ""; /* name of the iconset to be used */ + +void win_clear_icon_set() +{ + int i; + + for (i = 0; i < 256; i++) + if (hIcon[i] != 0) + { + DestroyIcon(hIcon[i]); + hIcon[i] = 0; + } +} + +void win_system_icon_set() +{ + int i, x = win_get_system_metrics(SM_CXSMICON, dpi), y = win_get_system_metrics(SM_CYSMICON, dpi); + + for (i = 0; i < 256; i++) + hIcon[i] = LoadImage(hinstance, MAKEINTRESOURCE(i), IMAGE_ICON, x, y, LR_DEFAULTCOLOR); +} + +typedef struct +{ + int id; + char* filename; +} _ICON_DATA; + +const _ICON_DATA icon_files[] = + { + {16, "floppy_525.ico"}, + {17, "floppy_525_active.ico"}, + {24, "floppy_35.ico"}, + {25, "floppy_35_active.ico"}, + {32, "cdrom.ico"}, + {33, "cdrom_active.ico"}, + {48, "zip.ico"}, + {49, "zip_active.ico"}, + {56, "mo.ico"}, + {57, "mo_active.ico"}, + {64, "cassette.ico"}, + {65, "cassette_active.ico"}, + {80, "hard_disk.ico"}, + {81, "hard_disk_active.ico"}, + {96, "network.ico"}, + {97, "network_active.ico"}, + {104, "cartridge.ico"}, + {144, "floppy_525_empty.ico"}, + {145, "floppy_525_empty_active.ico"}, + {152, "floppy_35_empty.ico"}, + {153, "floppy_35_empty_active.ico"}, + {160, "cdrom_empty.ico"}, + {161, "cdrom_empty_active.ico"}, + {176, "zip_empty.ico"}, + {177, "zip_empty_active.ico"}, + {184, "mo_empty.ico"}, + {185, "mo_empty_active.ico"}, + {192, "cassette_empty.ico"}, + {193, "cassette_empty_active.ico"}, + {200, "run.ico"}, + {201, "pause.ico"}, + {202, "send_cad.ico"}, + {203, "send_cae.ico"}, + {204, "hard_reset.ico"}, + {205, "acpi_shutdown.ico"}, + {206, "settings.ico"}, + {232, "cartridge_empty.ico"}, + {240, "machine.ico"}, + {241, "display.ico"}, + {242, "input_devices.ico"}, + {243, "sound.ico"}, + {244, "ports.ico"}, + {245, "other_peripherals.ico"}, + {246, "floppy_and_cdrom_drives.ico"}, + {247, "other_removable_devices.ico"}, + {248, "floppy_disabled.ico"}, + {249, "cdrom_disabled.ico"}, + {250, "zip_disabled.ico"}, + {251, "mo_disabled.ico"}, + {252, "storage_controllers.ico"} + }; + +void win_get_icons_path(char* path_root) +{ + char roms_root[1024] = {0}; + if (rom_path[0]) + strcpy(roms_root, rom_path); + else + path_append_filename(roms_root, exe_path, "roms"); + + path_append_filename(path_root, roms_root, "icons"); + path_slash(path_root); +} + +void win_load_icon_set() +{ + win_clear_icon_set(); + win_system_icon_set(); + + if (strlen(icon_set) == 0) { + ToolBarLoadIcons(); + return; + } + + char path_root[2048] = {0}, temp[2048] = {0}; + wchar_t wtemp[2048] = {0}; + + win_get_icons_path(path_root); + strcat(path_root, icon_set); + path_slash(path_root); + + int i, count = sizeof(icon_files) / sizeof(_ICON_DATA), + x = win_get_system_metrics(SM_CXSMICON, dpi), y = win_get_system_metrics(SM_CYSMICON, dpi); + for (i = 0; i < count; i++) + { + path_append_filename(temp, path_root, icon_files[i].filename); + mbstoc16s(wtemp, temp, strlen(temp) + 1); + + HICON ictemp; + ictemp = LoadImageW(NULL, (LPWSTR)wtemp, IMAGE_ICON, x, y, LR_LOADFROMFILE | LR_DEFAULTCOLOR); + if (ictemp) + { + if (hIcon[icon_files[i].id]) + DestroyIcon(hIcon[icon_files[i].id]); + hIcon[icon_files[i].id] = ictemp; + } + } + + uint32_t curr_lang = lang_id; + lang_id = 0; + set_language(curr_lang); + + ToolBarLoadIcons(); +} diff --git a/src/win/win_joystick.cpp b/src/win/win_joystick.cpp index 1f9de5ee6..a48538eec 100644 --- a/src/win/win_joystick.cpp +++ b/src/win/win_joystick.cpp @@ -67,23 +67,23 @@ static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, UNUSED(LP { if (joysticks_present >= MAX_JOYSTICKS) return DIENUM_STOP; - + joystick_log("joystick_enum_callback : found joystick %i : %s\n", joysticks_present, lpddi->tszProductName); - + joystick_guids[joysticks_present++] = lpddi->guidInstance; if (joysticks_present >= MAX_JOYSTICKS) return DIENUM_STOP; - + return DIENUM_CONTINUE; } -BOOL CALLBACK DIEnumDeviceObjectsCallback( +BOOL CALLBACK DIEnumDeviceObjectsCallback( LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) { plat_joystick_t *state = (plat_joystick_t *)pvRef; - + if (lpddoi->guidType == GUID_XAxis || lpddoi->guidType == GUID_YAxis || lpddoi->guidType == GUID_ZAxis || lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis) { @@ -122,7 +122,7 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( joystick_log("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); state->nr_povs++; } - } + } else if (lpddoi->guidType == GUID_Slider) { if (state->nr_sliders < 2) @@ -133,7 +133,7 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( state->nr_sliders++; } } - + return DIENUM_CONTINUE; } @@ -142,30 +142,30 @@ void joystick_init() int c; atexit(joystick_close); - + joysticks_present = 0; - + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) - fatal("joystick_init : DirectInputCreate failed\n"); + fatal("joystick_init : DirectInputCreate failed\n"); if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY))) fatal("joystick_init : EnumDevices failed\n"); joystick_log("joystick_init: joysticks_present=%i\n", joysticks_present); - + for (c = 0; c < joysticks_present; c++) - { + { LPDIRECTINPUTDEVICE8 lpdi_joystick_temp = NULL; DIPROPRANGE joy_axis_range; DIDEVICEINSTANCE device_instance; DIDEVCAPS devcaps; - + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) fatal("joystick_init : CreateDevice failed\n"); if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice8, (void **)&lpdi_joystick[c]))) fatal("joystick_init : CreateDevice failed\n"); lpdi_joystick_temp->Release(); - + memset(&device_instance, 0, sizeof(device_instance)); device_instance.dwSize = sizeof(device_instance); if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&device_instance))) @@ -183,8 +183,8 @@ void joystick_init() joystick_log(" Buttons = %i\n", devcaps.dwButtons); joystick_log(" POVs = %i\n", devcaps.dwPOVs); - lpdi_joystick[c]->EnumObjects(DIEnumDeviceObjectsCallback, &plat_joystick_state[c], DIDFT_ALL); - + lpdi_joystick[c]->EnumObjects(DIEnumDeviceObjectsCallback, &plat_joystick_state[c], DIDFT_ALL); + if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(hwndMain, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) fatal("joystick_init : SetCooperativeLevel failed\n"); if (FAILED(lpdi_joystick[c]->SetDataFormat(&c_dfDIJoystick))) @@ -211,7 +211,7 @@ void joystick_init() lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); joy_axis_range.diph.dwObj = DIJOFS_SLIDER(1); lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); - + if (FAILED(lpdi_joystick[c]->Acquire())) fatal("joystick_init : Acquire failed\n"); } @@ -263,13 +263,13 @@ void joystick_process(void) { int c, d; - if (joystick_type == JOYSTICK_TYPE_NONE) return; + if (!joystick_type) return; for (c = 0; c < joysticks_present; c++) - { + { DIJOYSTATE joystate; int b; - + if (FAILED(lpdi_joystick[c]->Poll())) { lpdi_joystick[c]->Acquire(); @@ -281,7 +281,7 @@ void joystick_process(void) lpdi_joystick[c]->Poll(); lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); } - + plat_joystick_state[c].a[0] = joystate.lX; plat_joystick_state[c].a[1] = joystate.lY; plat_joystick_state[c].a[2] = joystate.lZ; @@ -290,7 +290,7 @@ void joystick_process(void) plat_joystick_state[c].a[5] = joystate.lRz; plat_joystick_state[c].s[0] = joystate.rglSlider[0]; plat_joystick_state[c].s[1] = joystate.rglSlider[1]; - + for (b = 0; b < 16; b++) plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; @@ -298,13 +298,13 @@ void joystick_process(void) plat_joystick_state[c].p[b] = joystate.rgdwPOV[b]; // joystick_log("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); } - + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { if (joystick_state[c].plat_joystick_nr) { int joystick_nr = joystick_state[c].plat_joystick_nr - 1; - + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); for (d = 0; d < joystick_get_button_count(joystick_type); d++) @@ -317,10 +317,10 @@ void joystick_process(void) x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); - + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); magnitude = sqrt((double)x*(double)x + (double)y*(double)y); - + if (magnitude < 16384) joystick_state[c].pov[d] = -1; else diff --git a/src/win/win_joystick_rawinput.c b/src/win/win_joystick_rawinput.c index c4f947bac..d1fca0491 100644 --- a/src/win/win_joystick_rawinput.c +++ b/src/win/win_joystick_rawinput.c @@ -55,8 +55,8 @@ joystick_log(const char *fmt, ...) typedef struct { HANDLE hdevice; PHIDP_PREPARSED_DATA data; - - USAGE usage_button[128]; + + USAGE usage_button[256]; struct raw_axis_t { USAGE usage; @@ -127,7 +127,7 @@ void joystick_add_axis(raw_joystick_t* rawjoy, plat_joystick_t* joy, PHIDP_VALUE } else { /* * Some joysticks will send -1 in LogicalMax, like Xbox Controllers - * so we need to mask that to appropriate value (instead of 0xFFFFFFFF) + * so we need to mask that to appropriate value (instead of 0xFFFFFFFF) */ rawjoy->axis[joy->nr_axes].max = prop->LogicalMax & ((1 << prop->BitSize) - 1); } @@ -158,7 +158,7 @@ void joystick_get_capabilities(raw_joystick_t* rawjoy, plat_joystick_t* joy) { rawjoy->data = malloc(size); if (GetRawInputDeviceInfoW(rawjoy->hdevice, RIDI_PREPARSEDDATA, rawjoy->data, &size) <= 0) fatal("joystick_get_capabilities: Failed to get preparsed data.\n"); - + HIDP_CAPS caps; HidP_GetCaps(rawjoy->data, &caps); @@ -213,7 +213,7 @@ void joystick_get_device_name(raw_joystick_t* rawjoy, plat_joystick_t* joy, PRID if (GetRawInputDeviceInfoA(rawjoy->hdevice, RIDI_DEVICENAME, device_name, &size) <= 0) fatal("joystick_get_capabilities: Failed to get device name.\n"); - HANDLE hDevObj = CreateFile(device_name, GENERIC_READ | GENERIC_WRITE, + HANDLE hDevObj = CreateFile(device_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevObj) { HidD_GetProductString(hDevObj, device_desc_wide, sizeof(WCHAR) * 200); @@ -223,8 +223,8 @@ void joystick_get_device_name(raw_joystick_t* rawjoy, plat_joystick_t* joy, PRID int result = WideCharToMultiByte(CP_ACP, 0, device_desc_wide, 200, joy->name, 260, NULL, NULL); if (result == 0 || strlen(joy->name) == 0) - sprintf(joy->name, - "RawInput %s, VID:%04lX PID:%04lX", + sprintf(joy->name, + "RawInput %s, VID:%04lX PID:%04lX", info->hid.usUsage == HID_USAGE_GENERIC_JOYSTICK ? "Joystick" : "Gamepad", info->hid.dwVendorId, info->hid.dwProductId); @@ -248,8 +248,8 @@ void joystick_init() PRID_DEVICE_INFO info = NULL; if (joysticks_present >= MAX_PLAT_JOYSTICKS) break; - if (deviceList[i].dwType != RIM_TYPEHID) continue; - + if (deviceList[i].dwType != RIM_TYPEHID) continue; + /* Get device info: hardware IDs and usage IDs */ GetRawInputDeviceInfoA(deviceList[i].hDevice, RIDI_DEVICEINFO, NULL, &size); info = malloc(size); @@ -259,9 +259,9 @@ void joystick_init() /* If this is not a joystick/gamepad, skip */ if (info->hid.usUsagePage != HID_USAGE_PAGE_GENERIC) goto end_loop; - if (info->hid.usUsage != HID_USAGE_GENERIC_JOYSTICK && + if (info->hid.usUsage != HID_USAGE_GENERIC_JOYSTICK && info->hid.usUsage != HID_USAGE_GENERIC_GAMEPAD) goto end_loop; - + plat_joystick_t *joy = &plat_joystick_state[joysticks_present]; raw_joystick_t *rawjoy = &raw_joystick_state[joysticks_present]; rawjoy->hdevice = deviceList[i].hDevice; @@ -269,7 +269,7 @@ void joystick_init() joystick_get_capabilities(rawjoy, joy); joystick_get_device_name(rawjoy, joy, info); - joystick_log("joystick_init: %s - %d buttons, %d axes, %d POVs\n", + joystick_log("joystick_init: %s - %d buttons, %d axes, %d POVs\n", joy->name, joy->nr_buttons, joy->nr_axes, joy->nr_povs); joysticks_present++; @@ -277,7 +277,7 @@ void joystick_init() end_loop: free(info); } - + joystick_log("joystick_init: joysticks_present=%i\n", joysticks_present); /* Initialize the RawInput (joystick and gamepad) module. */ @@ -293,7 +293,7 @@ void joystick_init() ridev[1].usUsage = HID_USAGE_GENERIC_GAMEPAD; if (!RegisterRawInputDevices(ridev, 2, sizeof(RAWINPUTDEVICE))) - fatal("plat_joystick_init: RegisterRawInputDevices failed\n"); + fatal("plat_joystick_init: RegisterRawInputDevices failed\n"); } void joystick_close() @@ -326,7 +326,7 @@ void win_joystick_handle(PRAWINPUT raw) } } if (j == -1) return; - + /* Read buttons */ USAGE usage_list[128] = {0}; ULONG usage_length = plat_joystick_state[j].nr_buttons; @@ -334,7 +334,7 @@ void win_joystick_handle(PRAWINPUT raw) r = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usage_list, &usage_length, raw_joystick_state[j].data, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid); - + if (r == HIDP_STATUS_SUCCESS) { for (int i=0; imax - axis->min + 1) / 2; - r = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, axis->link, axis->usage, &uvalue, + r = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, axis->link, axis->usage, &uvalue, raw_joystick_state[j].data, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid); - + if (r == HIDP_STATUS_SUCCESS) { if (axis->min < 0) { /* extend signed uvalue to LONG */ @@ -371,7 +371,7 @@ void win_joystick_handle(PRAWINPUT raw) } plat_joystick_state[j].a[a] = value; - //joystick_log("%s %-06d ", plat_joystick_state[j].axis[a].name, plat_joystick_state[j].a[a]); + //joystick_log("%s %-06d ", plat_joystick_state[j].axis[a].name, plat_joystick_state[j].a[a]); } /* read povs */ @@ -379,10 +379,10 @@ void win_joystick_handle(PRAWINPUT raw) struct raw_pov_t* pov = &raw_joystick_state[j].pov[p]; ULONG uvalue = 0; LONG value = -1; - - r = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, pov->link, pov->usage, &uvalue, + + r = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, pov->link, pov->usage, &uvalue, raw_joystick_state[j].data, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid); - + if (r == HIDP_STATUS_SUCCESS && (uvalue >= pov->min && uvalue <= pov->max)) { value = (uvalue - pov->min) * 36000; value /= (pov->max - pov->min + 1); @@ -392,7 +392,7 @@ void win_joystick_handle(PRAWINPUT raw) plat_joystick_state[j].p[p] = value; //joystick_log("%s %-3d ", plat_joystick_state[j].pov[p].name, plat_joystick_state[j].p[p]); - + } //joystick_log("\n"); } @@ -405,13 +405,13 @@ static int joystick_get_axis(int joystick_nr, int mapping) int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; if (LOWORD(pov) == 0xFFFF) return 0; - else + else return sin((2*M_PI * (double)pov) / 36000.0) * 32767; } else if (mapping & POV_Y) { int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; - + if (LOWORD(pov) == 0xFFFF) return 0; else @@ -419,7 +419,7 @@ static int joystick_get_axis(int joystick_nr, int mapping) } else return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; - + } @@ -434,7 +434,7 @@ void joystick_process(void) if (joystick_state[c].plat_joystick_nr) { int joystick_nr = joystick_state[c].plat_joystick_nr - 1; - + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); for (d = 0; d < joystick_get_button_count(joystick_type); d++) @@ -447,10 +447,10 @@ void joystick_process(void) x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); - + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); magnitude = sqrt((double)x*(double)x + (double)y*(double)y); - + if (magnitude < 16384) joystick_state[c].pov[d] = -1; else @@ -468,4 +468,3 @@ void joystick_process(void) } } } - diff --git a/src/win/win_joystick_xinput.c b/src/win/win_joystick_xinput.c index 0e3f5fdce..325d87bd9 100644 --- a/src/win/win_joystick_xinput.c +++ b/src/win/win_joystick_xinput.c @@ -82,9 +82,9 @@ void joystick_init() int c; atexit(joystick_close); - + joysticks_present = 0; - + memset(controllers, 0, sizeof(XINPUT_STATE) * XINPUT_MAX_JOYSTICKS); for (c=0; c> 1); } - + return axis_sel - nr_povs; } @@ -188,31 +188,31 @@ joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) for (c = 0; c < joysticks_present; c++) SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[c].name); - + SendMessage(h, CB_SETCURSEL, joystick, 0); rebuild_axis_button_selections(hdlg); - + if (joystick_state[joystick_nr].plat_joystick_nr) { nr_axes = plat_joystick_state[joystick-1].nr_axes; nr_povs = plat_joystick_state[joystick-1].nr_povs; - + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) { int mapping = joystick_state[joystick_nr].axis_mapping[c]; - + h = GetDlgItem(hdlg, id); if (mapping & POV_X) SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); else if (mapping & POV_Y) SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); else if (mapping & SLIDER) - SendMessage(h, CB_SETCURSEL, nr_axes + nr_povs * 2 + (mapping & 3), 0); + SendMessage(h, CB_SETCURSEL, nr_axes + nr_povs * 2 + (mapping & 3), 0); else SendMessage(h, CB_SETCURSEL, mapping, 0); id += 2; - } + } for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) { h = GetDlgItem(hdlg, id); @@ -243,7 +243,7 @@ joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } } return TRUE; - + case WM_COMMAND: switch (LOWORD(wParam)) { @@ -251,21 +251,21 @@ joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (HIWORD(wParam) == CBN_SELCHANGE) rebuild_axis_button_selections(hdlg); break; - + case IDOK: { id = IDC_CONFIG_BASE + 2; - + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0); - + if (joystick_state[joystick_nr].plat_joystick_nr) { for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) { joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id); id += 2; - } + } for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) { h = GetDlgItem(hdlg, id); @@ -308,27 +308,27 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) char s[269]; joystickconfig_changed = 0; - + joystick_nr = joy_nr; joystick_config_type = type; memset(data_block, 0, 4096); - + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; dlg->x = 10; dlg->y = 10; dlg->cx = 220; dlg->cy = 70; - + data = (uint16_t *)(dlg + 1); - + *data++ = 0; /*no menu*/ *data++ = 0; /*predefined dialog box class*/ - data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + data += MultiByteToWideChar(CP_ACP, 0, "Joystick Configuration", -1, data, 50); + + *data++ = 9; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 50); - *data++ = 8; /*Point*/ - data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); - if (((uintptr_t)data) & 2) data++; @@ -338,11 +338,11 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) item->x = 70; item->y = y; item->id = id++; - + item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -350,16 +350,16 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; - + item->cx = 60; item->cy = 15; @@ -369,9 +369,9 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) *data++ = 0xFFFF; *data++ = 0x0082; /* static class */ - data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; @@ -385,11 +385,11 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) item->x = 70; item->y = y; item->id = id++; - + item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -397,16 +397,16 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; - + item->cx = 60; item->cy = 15; @@ -418,12 +418,12 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; y += 20; - } + } for (c = 0; c < joystick_get_button_count(type); c++) { @@ -432,11 +432,11 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) item->x = 70; item->y = y; item->id = id++; - + item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -444,16 +444,16 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; - + item->cx = 60; item->cy = 15; @@ -465,13 +465,13 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; y += 20; - } - + } + for (c = 0; c < joystick_get_pov_count(type)*2; c++) { /*Combo box*/ @@ -479,11 +479,11 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) item->x = 70; item->y = y; item->id = id++; - + item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -495,16 +495,16 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) sprintf(s, "%s (X axis)", joystick_get_pov_name(type, c/2)); data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; - + item->cx = 60; item->cy = 15; @@ -516,7 +516,7 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); *data++ = 0; /* no creation data */ - + if (((uintptr_t)data) & 2) data++; @@ -526,8 +526,8 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) dlg->cdit = (id - IDC_CONFIG_BASE) + 2; item = (DLGITEMTEMPLATE *)data; - item->x = 20; - item->y = y; + item->x = 100; + item->y = y + 5; item->cx = 50; item->cy = 14; item->id = IDOK; /* OK button identifier */ @@ -542,14 +542,14 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) if (((uintptr_t)data) & 2) data++; - + item = (DLGITEMTEMPLATE *)data; - item->x = 80; - item->y = y; + item->x = 160; + item->y = y + 5; item->cx = 50; item->cy = 14; - item->id = IDCANCEL; /* OK button identifier */ - item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + item->id = IDCANCEL; /* Cancel button identifier */ + item->style = WS_CHILD | WS_VISIBLE; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -558,7 +558,7 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); *data++ = 0; /* no creation data */ - dlg->cy = y + 20; + dlg->cy = y + 25; DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc); diff --git a/src/win/win_keyboard.c b/src/win/win_keyboard.c index 8d286e297..e60da87d4 100644 --- a/src/win/win_keyboard.c +++ b/src/win/win_keyboard.c @@ -114,89 +114,92 @@ keyboard_handle(PRAWINPUT raw) static int recv_lalt = 0, recv_ralt = 0, recv_tab = 0; RAWKEYBOARD rawKB = raw->data.keyboard; - scancode = rawKB.MakeCode; + scancode = rawKB.MakeCode; - /* If it's not a scan code that starts with 0xE1 */ - if (!(rawKB.Flags & RI_KEY_E1)) { - if (rawKB.Flags & RI_KEY_E0) - scancode |= 0x100; + if (kbd_req_capture && !mouse_capture && !video_fullscreen) + return; - /* Translate the scan code to 9-bit */ - scancode = convert_scan_code(scancode); + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) { + if (rawKB.Flags & RI_KEY_E0) + scancode |= 0x100; - /* Remap it according to the list from the Registry */ - if (scancode != scancode_map[scancode]) - pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); - scancode = scancode_map[scancode]; + /* Translate the scan code to 9-bit */ + scancode = convert_scan_code(scancode); - /* If it's not 0xFFFF, send it to the emulated - keyboard. - We use scan code 0xFFFF to mean a mapping that - has a prefix other than E0 and that is not E1 1D, - which is, for our purposes, invalid. */ - if ((scancode == 0x00F) && - !(rawKB.Flags & RI_KEY_BREAK) && - (recv_lalt || recv_ralt) && - !mouse_capture) { - /* We received a TAB while ALT was pressed, while the mouse - is not captured, suppress the TAB and send an ALT key up. */ - if (recv_lalt) { - keyboard_input(0, 0x038); - /* Extra key press and release so the guest is not stuck in the - menu bar. */ - keyboard_input(1, 0x038); - keyboard_input(0, 0x038); - recv_lalt = 0; - } - if (recv_ralt) { - keyboard_input(0, 0x138); - /* Extra key press and release so the guest is not stuck in the - menu bar. */ - keyboard_input(1, 0x138); - keyboard_input(0, 0x138); - recv_ralt = 0; - } - } else if (((scancode == 0x038) || (scancode == 0x138)) && - !(rawKB.Flags & RI_KEY_BREAK) && - recv_tab && - !mouse_capture) { - /* We received an ALT while TAB was pressed, while the mouse - is not captured, suppress the ALT and send a TAB key up. */ - keyboard_input(0, 0x00F); - recv_tab = 0; - } else { - switch(scancode) { - case 0x00F: - recv_tab = !(rawKB.Flags & RI_KEY_BREAK); - break; - case 0x038: - recv_lalt = !(rawKB.Flags & RI_KEY_BREAK); - break; - case 0x138: - recv_ralt = !(rawKB.Flags & RI_KEY_BREAK); - break; - } + /* Remap it according to the list from the Registry */ + if (scancode != scancode_map[scancode]) + pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); + scancode = scancode_map[scancode]; - /* Translate right CTRL to left ALT if the user has so - chosen. */ - if ((scancode == 0x11D) && rctrl_is_lalt) - scancode = 0x038; - - /* Normal scan code pass through, pass it through as is if - it's not an invalid scan code. */ - if (scancode != 0xFFFF) - keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + /* If it's not 0xFFFF, send it to the emulated + keyboard. + We use scan code 0xFFFF to mean a mapping that + has a prefix other than E0 and that is not E1 1D, + which is, for our purposes, invalid. */ + if ((scancode == 0x00F) && + !(rawKB.Flags & RI_KEY_BREAK) && + (recv_lalt || recv_ralt) && + !mouse_capture) { + /* We received a TAB while ALT was pressed, while the mouse + is not captured, suppress the TAB and send an ALT key up. */ + if (recv_lalt) { + keyboard_input(0, 0x038); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x038); + keyboard_input(0, 0x038); + recv_lalt = 0; } + if (recv_ralt) { + keyboard_input(0, 0x138); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x138); + keyboard_input(0, 0x138); + recv_ralt = 0; + } + } else if (((scancode == 0x038) || (scancode == 0x138)) && + !(rawKB.Flags & RI_KEY_BREAK) && + recv_tab && + !mouse_capture) { + /* We received an ALT while TAB was pressed, while the mouse + is not captured, suppress the ALT and send a TAB key up. */ + keyboard_input(0, 0x00F); + recv_tab = 0; } else { - if (rawKB.MakeCode == 0x1D) { - scancode = scancode_map[0x100]; /* Translate E1 1D to 0x100 (which would - otherwise be E0 00 but that is invalid - anyway). - Also, take a potential mapping into - account. */ - } else - scancode = 0xFFFF; + switch(scancode) { + case 0x00F: + recv_tab = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x038: + recv_lalt = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x138: + recv_ralt = !(rawKB.Flags & RI_KEY_BREAK); + break; + } + + /* Translate right CTRL to left ALT if the user has so + chosen. */ + if ((scancode == 0x11D) && rctrl_is_lalt) + scancode = 0x038; + + /* Normal scan code pass through, pass it through as is if + it's not an invalid scan code. */ if (scancode != 0xFFFF) keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); } + } else { + if (rawKB.MakeCode == 0x1D) { + scancode = scancode_map[0x100]; /* Translate E1 1D to 0x100 (which would + otherwise be E0 00 but that is invalid + anyway). + Also, take a potential mapping into + account. */ + } else + scancode = 0xFFFF; + if (scancode != 0xFFFF) + keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + } } diff --git a/src/win/win_media_menu.c b/src/win/win_media_menu.c index 6340d36b4..cf7974dd4 100644 --- a/src/win/win_media_menu.c +++ b/src/win/win_media_menu.c @@ -8,6 +8,8 @@ #include <86box/config.h> #include <86box/device.h> #include <86box/timer.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> #include <86box/fdd.h> #include <86box/fdd_86f.h> #include <86box/hdc.h> @@ -22,17 +24,23 @@ #include <86box/zip.h> #include <86box/win.h> -#define MACHINE_HAS_IDE ((machines[machine].flags & MACHINE_HDC) || !memcmp(hdc_get_internal_name(hdc_current), "ide", 3)) +#define MACHINE_HAS_IDE (machine_has_flags(machine, MACHINE_IDE_QUAD)) +#define MACHINE_HAS_SCSI (machine_has_flags(machine, MACHINE_SCSI_DUAL)) + +#define CASSETTE_FIRST 0 +#define CARTRIDGE_FIRST CASSETTE_FIRST + 1 +#define FDD_FIRST CARTRIDGE_FIRST + 2 +#define CDROM_FIRST FDD_FIRST + FDD_NUM +#define ZIP_FIRST CDROM_FIRST + CDROM_NUM +#define MO_FIRST ZIP_FIRST + ZIP_NUM -#define FDD_FIRST 0 -#define CDROM_FIRST FDD_FIRST + FDD_NUM -#define ZIP_FIRST CDROM_FIRST + CDROM_NUM -#define MO_FIRST ZIP_FIRST + ZIP_NUM static HMENU media_menu, stbar_menu; -static HMENU menus[FDD_NUM + CDROM_NUM + ZIP_NUM + MO_NUM]; +static HMENU menus[1 + 2 + FDD_NUM + CDROM_NUM + ZIP_NUM + MO_NUM]; + static char index_map[255]; + static void media_menu_set_ids(HMENU hMenu, int id) { @@ -50,6 +58,7 @@ media_menu_set_ids(HMENU hMenu, int id) } } + /* Loads the submenu from resource by name */ static HMENU media_menu_load_resource(wchar_t *lpName) @@ -66,20 +75,66 @@ media_menu_load_resource(wchar_t *lpName) return actual; } + +static void +media_menu_set_name_cassette(void) +{ + wchar_t name[512], fn[512]; + MENUITEMINFO mii = { 0 }; + + if (strlen(cassette_fname) == 0) + _swprintf(name, plat_get_string(IDS_2148), plat_get_string(IDS_2057)); + else { + mbstoc16s(fn, cassette_fname, sizeof_w(fn)); + _swprintf(name, plat_get_string(IDS_2148), fn); + } + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING; + mii.dwTypeData = name; + + SetMenuItemInfo(media_menu, (UINT_PTR)menus[CASSETTE_FIRST], FALSE, &mii); +} + + +static void +media_menu_set_name_cartridge(int drive) +{ + wchar_t name[512], fn[512]; + MENUITEMINFO mii = { 0 }; + + if (strlen(cart_fns[drive]) == 0) { + _swprintf(name, plat_get_string(IDS_2150), + drive + 1, plat_get_string(IDS_2057)); + } else { + mbstoc16s(fn, cart_fns[drive], sizeof_w(fn)); + _swprintf(name, plat_get_string(IDS_2150), + drive + 1, fn); + } + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING; + mii.dwTypeData = name; + + SetMenuItemInfo(media_menu, (UINT_PTR)menus[CARTRIDGE_FIRST + drive], FALSE, &mii); +} + + static void media_menu_set_name_floppy(int drive) { - wchar_t name[512], temp[512]; + wchar_t name[512], temp[512], fn[512]; MENUITEMINFO mii = { 0 }; - mbstowcs(temp, fdd_getname(fdd_get_type(drive)), + mbstoc16s(temp, fdd_getname(fdd_get_type(drive)), strlen(fdd_getname(fdd_get_type(drive))) + 1); - if (wcslen(floppyfns[drive]) == 0) { + if (strlen(floppyfns[drive]) == 0) { _swprintf(name, plat_get_string(IDS_2108), drive + 1, temp, plat_get_string(IDS_2057)); } else { + mbstoc16s(fn, floppyfns[drive], sizeof_w(fn)); _swprintf(name, plat_get_string(IDS_2108), - drive + 1, temp, floppyfns[drive]); + drive + 1, temp, fn); } mii.cbSize = sizeof(mii); @@ -89,10 +144,11 @@ media_menu_set_name_floppy(int drive) SetMenuItemInfo(media_menu, (UINT_PTR)menus[FDD_FIRST + drive], FALSE, &mii); } + static void media_menu_set_name_cdrom(int drive) { - wchar_t name[512], *temp; + wchar_t name[512], *temp, fn[512]; MENUITEMINFO mii = { 0 }; int bus = cdrom[drive].bus_type; @@ -101,10 +157,14 @@ media_menu_set_name_cdrom(int drive) temp = plat_get_string(id); if (cdrom[drive].host_drive == 200) { - if (wcslen(cdrom[drive].image_path) == 0) - _swprintf(name, plat_get_string(IDS_5120), drive+1, temp, plat_get_string(IDS_2057)); - else - _swprintf(name, plat_get_string(IDS_5120), drive+1, temp, cdrom[drive].image_path); + if (strlen(cdrom[drive].image_path) == 0) { + _swprintf(name, plat_get_string(IDS_5120), + drive+1, temp, plat_get_string(IDS_2057)); + } else { + mbstoc16s(fn, cdrom[drive].image_path, sizeof_w(fn)); + _swprintf(name, plat_get_string(IDS_5120), + drive+1, temp, fn); + } } else _swprintf(name, plat_get_string(IDS_5120), drive+1, temp, plat_get_string(IDS_2057)); @@ -115,10 +175,11 @@ media_menu_set_name_cdrom(int drive) SetMenuItemInfo(media_menu, (UINT_PTR)menus[CDROM_FIRST + drive], FALSE, &mii); } + static void media_menu_set_name_zip(int drive) { - wchar_t name[512], *temp; + wchar_t name[512], *temp, fn[512]; MENUITEMINFO mii = { 0 }; int bus = zip_drives[drive].bus_type; @@ -128,12 +189,13 @@ media_menu_set_name_zip(int drive) int type = zip_drives[drive].is_250 ? 250 : 100; - if (wcslen(zip_drives[drive].image_path) == 0) { + if (strlen(zip_drives[drive].image_path) == 0) { _swprintf(name, plat_get_string(IDS_2054), type, drive+1, temp, plat_get_string(IDS_2057)); } else { + mbstoc16s(fn, zip_drives[drive].image_path, sizeof_w(fn)); _swprintf(name, plat_get_string(IDS_2054), - type, drive+1, temp, zip_drives[drive].image_path); + type, drive+1, temp, fn); } mii.cbSize = sizeof(mii); @@ -143,10 +205,11 @@ media_menu_set_name_zip(int drive) SetMenuItemInfo(media_menu, (UINT_PTR)menus[ZIP_FIRST + drive], FALSE, &mii); } + static void media_menu_set_name_mo(int drive) { - wchar_t name[512], *temp; + wchar_t name[512], *temp, fn[512]; MENUITEMINFO mii = { 0 }; int bus = mo_drives[drive].bus_type; @@ -154,12 +217,13 @@ media_menu_set_name_mo(int drive) temp = plat_get_string(id); - if (wcslen(mo_drives[drive].image_path) == 0) { + if (strlen(mo_drives[drive].image_path) == 0) { _swprintf(name, plat_get_string(IDS_2115), drive+1, temp, plat_get_string(IDS_2057)); } else { + mbstoc16s(fn, mo_drives[drive].image_path, sizeof_w(fn)); _swprintf(name, plat_get_string(IDS_2115), - drive+1, temp, mo_drives[drive].image_path); + drive+1, temp, fn); } mii.cbSize = sizeof(mii); @@ -169,12 +233,59 @@ media_menu_set_name_mo(int drive) SetMenuItemInfo(media_menu, (UINT_PTR)menus[MO_FIRST + drive], FALSE, &mii); } + +void +media_menu_update_cassette(void) +{ + int i = CASSETTE_FIRST; + + if (strlen(cassette_fname) == 0) { + EnableMenuItem(menus[i], IDM_CASSETTE_EJECT, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(menus[i], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(menus[i], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_GRAYED); + CheckMenuItem(menus[i], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(menus[i], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_UNCHECKED); + EnableMenuItem(menus[i], IDM_CASSETTE_REWIND, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(menus[i], IDM_CASSETTE_FAST_FORWARD, MF_BYCOMMAND | MF_GRAYED); + } else { + EnableMenuItem(menus[i], IDM_CASSETTE_EJECT, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem(menus[i], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem(menus[i], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_ENABLED); + if (strcmp(cassette_mode, "save") == 0) { + CheckMenuItem(menus[i], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(menus[i], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_UNCHECKED); + } else { + CheckMenuItem(menus[i], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(menus[i], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_CHECKED); + } + EnableMenuItem(menus[i], IDM_CASSETTE_REWIND, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem(menus[i], IDM_CASSETTE_FAST_FORWARD, MF_BYCOMMAND | MF_ENABLED); + } + + media_menu_set_name_cassette(); +} + + +void +media_menu_update_cartridge(int id) +{ + int i = CARTRIDGE_FIRST + id; + + if (strlen(cart_fns[id]) == 0) + EnableMenuItem(menus[i], IDM_CARTRIDGE_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + else + EnableMenuItem(menus[i], IDM_CARTRIDGE_EJECT | id, MF_BYCOMMAND | MF_ENABLED); + + media_menu_set_name_cartridge(id); +} + + void media_menu_update_floppy(int id) { int i = FDD_FIRST + id; - if (floppyfns[id][0] == 0x0000) { + if (strlen(floppyfns[id]) == 0) { EnableMenuItem(menus[i], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(menus[i], IDM_FLOPPY_EXPORT_TO_86F | id, MF_BYCOMMAND | MF_GRAYED); } else { @@ -185,6 +296,7 @@ media_menu_update_floppy(int id) media_menu_set_name_floppy(id); } + void media_menu_update_cdrom(int id) { @@ -212,17 +324,18 @@ media_menu_update_cdrom(int id) media_menu_set_name_cdrom(id); } + void media_menu_update_zip(int id) { int i = ZIP_FIRST + id; - if (zip_drives[id].image_path[0] == 0x0000) + if (strlen(zip_drives[id].image_path) == 0) EnableMenuItem(menus[i], IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_GRAYED); else EnableMenuItem(menus[i], IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_ENABLED); - if(zip_drives[id].prev_image_path[0] == 0x0000) + if(strlen(zip_drives[id].prev_image_path) == 0) EnableMenuItem(menus[i], IDM_ZIP_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); else EnableMenuItem(menus[i], IDM_ZIP_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); @@ -230,17 +343,18 @@ media_menu_update_zip(int id) media_menu_set_name_zip(id); } + void media_menu_update_mo(int id) { int i = MO_FIRST + id; - if (mo_drives[id].image_path[0] == 0x0000) + if (strlen(mo_drives[id].image_path) == 0) EnableMenuItem(menus[i], IDM_MO_EJECT | id, MF_BYCOMMAND | MF_GRAYED); else EnableMenuItem(menus[i], IDM_MO_EJECT | id, MF_BYCOMMAND | MF_ENABLED); - if(mo_drives[id].prev_image_path[0] == 0x0000) + if(strlen(mo_drives[id].prev_image_path) == 0) EnableMenuItem(menus[i], IDM_MO_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); else EnableMenuItem(menus[i], IDM_MO_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); @@ -248,6 +362,7 @@ media_menu_update_mo(int id) media_menu_set_name_mo(id); } + static void media_menu_load_submenus() { @@ -255,6 +370,14 @@ media_menu_load_submenus() int curr = 0; + menus[curr] = media_menu_load_resource(CASSETTE_SUBMENU_NAME); + media_menu_set_ids(menus[curr++], 0); + + for(int i = 0; i < 2; i++) { + menus[curr] = media_menu_load_resource(CARTRIDGE_SUBMENU_NAME); + media_menu_set_ids(menus[curr++], i); + } + for(int i = 0; i < FDD_NUM; i++) { menus[curr] = media_menu_load_resource(FLOPPY_SUBMENU_NAME); media_menu_set_ids(menus[curr++], i); @@ -276,42 +399,66 @@ media_menu_load_submenus() } } + +static inline int +is_valid_cartridge(void) +{ + return (machine_has_cartridge(machine)); +} + + static inline int is_valid_fdd(int i) { return fdd_get_type(i) != 0; } + static inline int is_valid_cdrom(int i) { - if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && !MACHINE_HAS_IDE) + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && !MACHINE_HAS_IDE && + memcmp(hdc_get_internal_name(hdc_current), "xtide", 5) && + memcmp(hdc_get_internal_name(hdc_current), "ide", 3)) return 0; - if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && (scsi_card_current == 0)) + if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && !MACHINE_HAS_SCSI && + (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && + (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) return 0; return cdrom[i].bus_type != 0; } + static inline int is_valid_zip(int i) { - if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && !MACHINE_HAS_IDE) + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && !MACHINE_HAS_IDE && + memcmp(hdc_get_internal_name(hdc_current), "xtide", 5) && + memcmp(hdc_get_internal_name(hdc_current), "ide", 3)) return 0; - if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (scsi_card_current == 0)) + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && !MACHINE_HAS_SCSI && + (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && + (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) return 0; return zip_drives[i].bus_type != 0; } + static inline int is_valid_mo(int i) { - if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && !MACHINE_HAS_IDE) + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && !MACHINE_HAS_IDE && + memcmp(hdc_get_internal_name(hdc_current), "xtide", 5) && + memcmp(hdc_get_internal_name(hdc_current), "ide", 3)) return 0; - if ((mo_drives[i].bus_type == MO_BUS_SCSI) && (scsi_card_current == 0)) + if ((mo_drives[i].bus_type == MO_BUS_SCSI) && !MACHINE_HAS_SCSI && + (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && + (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) return 0; return mo_drives[i].bus_type != 0; } + void media_menu_reset() { @@ -324,6 +471,20 @@ media_menu_reset() /* Add new ones. */ int curr = 0; + if(cassette_enable) { + AppendMenu(media_menu, MF_POPUP | MF_STRING, (UINT_PTR)menus[curr], L"Test"); + media_menu_update_cassette(); + } + curr++; + + for(int i = 0; i < 2; i++) { + if(is_valid_cartridge()) { + AppendMenu(media_menu, MF_POPUP | MF_STRING, (UINT_PTR)menus[curr], L"Test"); + media_menu_update_cartridge(i); + } + curr++; + } + for(int i = 0; i < FDD_NUM; i++) { if(is_valid_fdd(i)) { AppendMenu(media_menu, MF_POPUP | MF_STRING, (UINT_PTR)menus[curr], L"Test"); @@ -357,6 +518,7 @@ media_menu_reset() } } + /* Initializes the Media menu in the main menu bar. */ static void media_menu_main_init() @@ -380,6 +542,7 @@ media_menu_main_init() free(lpMenuName); } + void media_menu_init() { @@ -397,6 +560,7 @@ media_menu_init() media_menu_reset(); } + int media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -405,6 +569,60 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) id = LOWORD(wParam) & 0x00ff; switch (LOWORD(wParam) & 0xff00) { + case IDM_CASSETTE_IMAGE_NEW: + ret = file_dlg_st(hwnd, IDS_2149, "", NULL, 1); + if (! ret) { + if (strlen(openfilestring) == 0) + cassette_mount(NULL, wp); + else + cassette_mount(openfilestring, wp); + } + break; + + case IDM_CASSETTE_RECORD: + pc_cas_set_mode(cassette, 1); + CheckMenuItem(menus[CASSETTE_FIRST], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(menus[CASSETTE_FIRST], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_UNCHECKED); + break; + case IDM_CASSETTE_PLAY: + pc_cas_set_mode(cassette, 0); + CheckMenuItem(menus[CASSETTE_FIRST], IDM_CASSETTE_RECORD, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(menus[CASSETTE_FIRST], IDM_CASSETTE_PLAY, MF_BYCOMMAND | MF_CHECKED); + break; + case IDM_CASSETTE_REWIND: + pc_cas_rewind(cassette); + break; + case IDM_CASSETTE_FAST_FORWARD: + pc_cas_append(cassette); + break; + + case IDM_CASSETTE_IMAGE_EXISTING_WP: + wp = 1; + /* FALLTHROUGH */ + case IDM_CASSETTE_IMAGE_EXISTING: + ret = file_dlg_st(hwnd, IDS_2149, cassette_fname, NULL, 0); + if (! ret) { + if (strlen(openfilestring) == 0) + cassette_mount(NULL, wp); + else + cassette_mount(openfilestring, wp); + } + break; + + case IDM_CASSETTE_EJECT: + cassette_eject(); + break; + + case IDM_CARTRIDGE_IMAGE: + ret = file_dlg_st(hwnd, IDS_2151, cart_fns[id], NULL, 0); + if (! ret) + cartridge_mount(id, openfilestring, wp); + break; + + case IDM_CARTRIDGE_EJECT: + cartridge_eject(id); + break; + case IDM_FLOPPY_IMAGE_NEW: NewFloppyDialogCreate(hwnd, id, 0); break; @@ -413,10 +631,9 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) wp = 1; /* FALLTHROUGH */ case IDM_FLOPPY_IMAGE_EXISTING: - ret = file_dlg_w_st(hwnd, IDS_2109, floppyfns[id], 0); - if (! ret) { - floppy_mount(id, wopenfilestring, wp); - } + ret = file_dlg_st(hwnd, IDS_2109, floppyfns[id], NULL, 0); + if (! ret) + floppy_mount(id, openfilestring, wp); break; case IDM_FLOPPY_EJECT: @@ -424,10 +641,10 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_FLOPPY_EXPORT_TO_86F: - ret = file_dlg_w_st(hwnd, IDS_2076, floppyfns[id], 1); + ret = file_dlg_st(hwnd, IDS_2076, floppyfns[id], NULL, 1); if (! ret) { plat_pause(1); - ret = d86f_export(id, wopenfilestring); + ret = d86f_export(id, openfilestring); if (!ret) ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_4108, (wchar_t *) IDS_4115); plat_pause(0); @@ -450,8 +667,8 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_CDROM_IMAGE: - if (!file_dlg_w_st(hwnd, IDS_2075, cdrom[id].image_path, 0)) { - cdrom_mount(id, wopenfilestring); + if (!file_dlg_st(hwnd, IDS_2140, cdrom[id].image_path, NULL, 0)) { + cdrom_mount(id, openfilestring); } break; @@ -463,9 +680,9 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) wp = 1; /* FALLTHROUGH */ case IDM_ZIP_IMAGE_EXISTING: - ret = file_dlg_w_st(hwnd, IDS_2058, zip_drives[id].image_path, 0); + ret = file_dlg_st(hwnd, IDS_2058, zip_drives[id].image_path, NULL, 0); if (! ret) - zip_mount(id, wopenfilestring, wp); + zip_mount(id, openfilestring, wp); break; case IDM_ZIP_EJECT: @@ -477,16 +694,16 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_MO_IMAGE_NEW: - NewFloppyDialogCreate(hwnd, id | 0x80, 0); /* NewZIPDialogCreate */ + NewFloppyDialogCreate(hwnd, id | 0x100, 0); /* NewZIPDialogCreate */ break; case IDM_MO_IMAGE_EXISTING_WP: wp = 1; /* FALLTHROUGH */ case IDM_MO_IMAGE_EXISTING: - ret = file_dlg_w_st(hwnd, IDS_2116, mo_drives[id].image_path, 0); + ret = file_dlg_st(hwnd, IDS_2116, mo_drives[id].image_path, NULL, 0); if (! ret) - mo_mount(id, wopenfilestring, wp); + mo_mount(id, openfilestring, wp); break; case IDM_MO_EJECT: @@ -504,24 +721,42 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) return(1); } + +HMENU +media_menu_get_cassette(void) +{ + return menus[CASSETTE_FIRST]; +} + + +HMENU +media_menu_get_cartridge(int id) +{ + return menus[CARTRIDGE_FIRST + id]; +} + + HMENU media_menu_get_floppy(int id) { return menus[FDD_FIRST + id]; } + HMENU media_menu_get_cdrom(int id) { return menus[CDROM_FIRST + id]; } + HMENU media_menu_get_zip(int id) { return menus[ZIP_FIRST + id]; } + HMENU media_menu_get_mo(int id) { diff --git a/src/win/win_midi.c b/src/win/win_midi.c deleted file mode 100644 index 86ff9d285..000000000 --- a/src/win/win_midi.c +++ /dev/null @@ -1,241 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/config.h> -#include <86box/midi.h> -#include <86box/plat.h> -#include <86box/plat_midi.h> - - -typedef struct -{ - int midi_id, midi_input_id; - - HANDLE m_event; - - HMIDIOUT midi_out_device; - HMIDIIN midi_in_device; - - MIDIHDR m_hdr; -} plat_midi_t; - -plat_midi_t *pm = NULL, *pm_in = NULL; - - -void -plat_midi_init(void) -{ - MMRESULT hr; - - pm = (plat_midi_t *) malloc(sizeof(plat_midi_t)); - memset(pm, 0, sizeof(plat_midi_t)); - - pm->midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); - - hr = MMSYSERR_NOERROR; - - pm->m_event = CreateEvent(NULL, TRUE, TRUE, NULL); - - hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, - (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n", hr); - pm->midi_id = 0; - hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, - (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n", hr); - return; - } - } - - midiOutReset(pm->midi_out_device); -} - - -void -plat_midi_close(void) -{ - if (pm) { - if (pm->midi_out_device != NULL) { - midiOutReset(pm->midi_out_device); - midiOutClose(pm->midi_out_device); - CloseHandle(pm->m_event); - } - - free(pm); - pm = NULL; - } -} - - -int -plat_midi_get_num_devs(void) -{ - return midiOutGetNumDevs(); -} - - -void -plat_midi_get_dev_name(int num, char *s) -{ - MIDIOUTCAPS caps; - - midiOutGetDevCaps(num, &caps, sizeof(caps)); - strcpy(s, caps.szPname); -} - - -void -plat_midi_play_msg(uint8_t *msg) -{ - if (!pm) - return; - - midiOutShortMsg(pm->midi_out_device, *(uint32_t *) msg); -} - - -void -plat_midi_play_sysex(uint8_t *sysex, unsigned int len) -{ - MMRESULT result; - - if (!pm) - return; - - if (WaitForSingleObject(pm->m_event, 2000) == WAIT_TIMEOUT) - return; - - midiOutUnprepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); - - pm->m_hdr.lpData = (char *) sysex; - pm->m_hdr.dwBufferLength = len; - pm->m_hdr.dwBytesRecorded = len; - pm->m_hdr.dwUser = 0; - - result = midiOutPrepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); - - if (result != MMSYSERR_NOERROR) - return; - ResetEvent(pm->m_event); - result = midiOutLongMsg(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); - if (result != MMSYSERR_NOERROR) { - SetEvent(pm->m_event); - return; - } -} - - -int -plat_midi_write(uint8_t val) -{ - return 0; -} - - -void CALLBACK -plat_midi_in_callback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - uint8_t msg[4] = { ((dwParam1 & 0xff)), (((dwParam1 & 0xff00) >> 8)), - (((dwParam1 & 0xff0000) >> 16)), MIDI_evt_len[((dwParam1 & 0xff))]}; - uint8_t *sysex; - uint32_t len; - MIDIHDR *hdr; - - switch (wMsg) { - case MM_MIM_DATA: /* 0x3C3 - midi message */ - midi_in_msg(msg); - break; - case MM_MIM_OPEN: /* 0x3C1 */ - break; - case MM_MIM_CLOSE: /* 0x3C2 */ - break; - case MM_MIM_LONGDATA: /* 0x3C4 - sysex */ - /* It is midi_in_sysex() that now does the loop. */ - hdr = (MIDIHDR *) dwParam1; - sysex = (uint8_t *) hdr->lpData; - len = (uint32_t) hdr->dwBytesRecorded; - midi_in_sysex(sysex, len); - - midiInUnprepareHeader(hMidiIn, hdr, sizeof(*hdr)); - hdr->dwBytesRecorded = 0; - midiInPrepareHeader(hMidiIn, hdr, sizeof(*hdr)); - break; - case MM_MIM_ERROR: - case MM_MIM_LONGERROR: - break; - default: - break; - } -} - - -void -plat_midi_input_init(void) -{ - MMRESULT hr; - - pm_in = (plat_midi_t *) malloc(sizeof(plat_midi_t)); - memset(pm_in, 0, sizeof(plat_midi_t)); - - pm_in->midi_input_id = config_get_int(MIDI_INPUT_NAME, "midi_input", 0); - - hr = MMSYSERR_NOERROR; - - hr = midiInOpen(&pm_in->midi_in_device, pm_in->midi_input_id, - (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); - if (hr != MMSYSERR_NOERROR) { - printf("midiInOpen error - %08X\n", hr); - pm_in->midi_input_id = 0; - hr = midiInOpen(&pm_in->midi_in_device, pm_in->midi_input_id, - (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); - if (hr != MMSYSERR_NOERROR) { - printf("midiInOpen error - %08X\n", hr); - return; - } - } - - pm_in->m_hdr.lpData = (char*)&MIDI_InSysexBuf[0]; - pm_in->m_hdr.dwBufferLength = SYSEX_SIZE; - pm_in->m_hdr.dwBytesRecorded = 0; - pm_in->m_hdr.dwUser = 0; - midiInPrepareHeader(pm_in->midi_in_device,&pm_in->m_hdr,sizeof(pm_in->m_hdr)); - midiInStart(pm_in->midi_in_device); -} - - -void -plat_midi_input_close(void) -{ - if (pm_in) { - if (pm_in->midi_in_device != NULL) { - midiInStop(pm_in->midi_in_device); - midiInClose(pm_in->midi_in_device); - } - - free(pm_in); - pm_in = NULL; - } -} - - -int -plat_midi_in_get_num_devs(void) -{ - return midiInGetNumDevs(); -} - - -void -plat_midi_in_get_dev_name(int num, char *s) -{ - MIDIINCAPS caps; - - midiInGetDevCaps(num, &caps, sizeof(caps)); - strcpy(s, caps.szPname); -} diff --git a/src/win/win_mouse.c b/src/win/win_mouse.c index 2e91085ec..b69646a6e 100644 --- a/src/win/win_mouse.c +++ b/src/win/win_mouse.c @@ -28,6 +28,7 @@ #include <86box/win.h> int mouse_capture; +double mouse_sensitivity = 1.0; /* Unused. */ typedef struct { int buttons; @@ -52,7 +53,7 @@ win_mouse_init(void) ridev.usUsagePage = 0x01; ridev.usUsage = 0x02; if (! RegisterRawInputDevices(&ridev, 1, sizeof(ridev))) - fatal("plat_mouse_init: RegisterRawInputDevices failed\n"); + fatal("plat_mouse_init: RegisterRawInputDevices failed\n"); memset(&mousestate, 0, sizeof(MOUSESTATE)); } @@ -85,13 +86,13 @@ win_mouse_handle(PRAWINPUT raw) if (state.usFlags & MOUSE_MOVE_ABSOLUTE) { - /* absolute mouse, i.e. RDP or VNC + /* absolute mouse, i.e. RDP or VNC * seems to work fine for RDP on Windows 10 * Not sure about other environments. */ mousestate.dx += (state.lLastX - x)/25; mousestate.dy += (state.lLastY - y)/25; - x=state.lLastX; + x=state.lLastX; y=state.lLastY; } else { /* relative mouse, i.e. regular mouse */ @@ -124,7 +125,7 @@ mouse_poll(void) mousestate.dx=0; mousestate.dy=0; mousestate.dwheel=0; - + //pclog("dx=%d, dy=%d, dwheel=%d\n", mouse_x, mouse_y, mouse_z); } diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index 33c83299f..12983bef8 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -30,6 +30,7 @@ #include <86box/random.h> #include <86box/ui.h> #include <86box/scsi_device.h> +#include <86box/mo.h> #include <86box/zip.h> #include <86box/win.h> @@ -51,8 +52,13 @@ typedef struct { } disk_size_t; -static const disk_size_t disk_sizes[14] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xfe, 2, 2, 1, 64 }, /* 160k */ - { 0, 1, 2, 1, 0, 40, 9, 2, 0xfc, 2, 2, 1, 64 }, /* 180k */ +static const disk_size_t disk_sizes[14] = { +// { 1, 1, 2, 1, 1, 77, 26, 0, 0, 4, 2, 6, 68 }, /* 250k 8" */ +// { 1, 2, 2, 1, 1, 77, 26, 0, 0, 4, 2, 6, 68 }, /* 500k 8" */ +// { 1, 1, 2, 1, 1, 77, 8, 3, 0, 1, 2, 2, 192 }, /* 616k 8" */ +// { 1, 2, 0, 1, 1, 77, 8, 3, 0, 1, 2, 2, 192 }, /* 1232k 8" */ + { 0, 1, 2, 1, 0, 40, 8, 2, 0xfe, 1, 2, 1, 64 }, /* 160k */ + { 0, 1, 2, 1, 0, 40, 9, 2, 0xfc, 1, 2, 2, 64 }, /* 180k */ { 0, 2, 2, 1, 0, 40, 8, 2, 0xff, 2, 2, 1, 112 }, /* 320k */ { 0, 2, 2, 1, 0, 40, 9, 2, 0xfd, 2, 2, 2, 112 }, /* 360k */ { 0, 2, 2, 1, 0, 80, 8, 2, 0xfb, 2, 2, 2, 112 }, /* 640k */ @@ -70,7 +76,7 @@ static unsigned char *empty; static int -create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) +create_86f(char *file_name, disk_size_t disk_size, uint8_t rpm_mode) { FILE *f; @@ -138,7 +144,7 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) memset(tarray, 0, 2048); memset(empty, 0, array_size); - f = plat_fopen(file_name, L"wb"); + f = plat_fopen(file_name, "wb"); if (!f) return 0; @@ -173,10 +179,11 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) static int is_zip; +static int is_mo; static int -create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) +create_sector_image(char *file_name, disk_size_t disk_size, uint8_t is_fdi) { FILE *f; uint32_t total_size = 0; @@ -188,8 +195,8 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) uint32_t fat2_offs = 0; uint32_t zero_bytes = 0; uint16_t base = 0x1000; - - f = plat_fopen(file_name, L"wb"); + + f = plat_fopen(file_name, "wb"); if (!f) return 0; @@ -204,7 +211,7 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) fat2_offs = fat1_offs + fat_size; zero_bytes = fat2_offs + fat_size + root_dir_bytes; - if (!is_zip && is_fdi) { + if (!is_zip && !is_mo && is_fdi) { empty = (unsigned char *) malloc(base); memset(empty, 0, base); @@ -222,7 +229,7 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) empty = (unsigned char *) malloc(total_size); memset(empty, 0x00, zero_bytes); - if (!is_zip) { + if (!is_zip && !is_mo) { memset(empty + zero_bytes, 0xF6, total_size - zero_bytes); empty[0x00] = 0xEB; /* Jump to make MS-DOS happy. */ @@ -282,7 +289,7 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) static int -create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, HWND hwnd) +create_zip_sector_image(char *file_name, disk_size_t disk_size, uint8_t is_zdi, HWND hwnd) { HWND h; FILE *f; @@ -298,8 +305,8 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, uint32_t pbar_max = 0; uint32_t i; MSG msg; - - f = plat_fopen(file_name, L"wb"); + + f = plat_fopen(file_name, "wb"); if (!f) return 0; @@ -323,7 +330,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, h = GetDlgItem(hwnd, IDC_COMBO_RPM_MODE); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); - h = GetDlgItem(hwnd, IDT_1751); + h = GetDlgItem(hwnd, IDT_FLP_RPM_MODE); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); @@ -331,7 +338,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); EnableWindow(h, TRUE); ShowWindow(h, SW_SHOW); - h = GetDlgItem(hwnd, IDT_1757); + h = GetDlgItem(hwnd, IDT_FLP_PROGRESS); EnableWindow(h, TRUE); ShowWindow(h, SW_SHOW); @@ -352,10 +359,21 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, fwrite(empty, 1, 2048, f); SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + fwrite(&empty[0x0800], 1, 2048, f); free(empty); SendMessage(h, PBM_SETPOS, (WPARAM) 2, (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + pbar_max -= 2; } @@ -494,8 +512,8 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, SendMessage(h, PBM_SETPOS, (WPARAM) i + 2, (LPARAM) 0); while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { - TranslateMessage(&msg); - DispatchMessage(&msg); + TranslateMessage(&msg); + DispatchMessage(&msg); } } @@ -507,10 +525,133 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, } +static int +create_mo_sector_image(char *file_name, int8_t disk_size, uint8_t is_mdi, HWND hwnd) +{ + HWND h; + FILE *f; + const mo_type_t *dp = &mo_types[disk_size]; + uint8_t *empty, *empty2 = NULL; + uint32_t total_size = 0, total_size2; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint16_t base = 0x1000; + uint32_t pbar_max = 0, blocks_num; + uint32_t i, j; + MSG msg; + + f = plat_fopen(file_name, "wb"); + if (!f) + return 0; + + sector_bytes = dp->bytes_per_sector; + total_sectors = dp->sectors; + total_size = total_sectors * sector_bytes; + + total_size2 = (total_size >> 20) << 20; + total_size2 = total_size - total_size2; + + pbar_max = total_size; + pbar_max >>= 20; + blocks_num = pbar_max; + if (is_mdi) + pbar_max++; + if (total_size2 == 0) + pbar_max++; + + j = is_mdi ? 1 : 0; + + h = GetDlgItem(hwnd, IDC_COMBO_RPM_MODE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hwnd, IDT_FLP_RPM_MODE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) pbar_max - 1); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + h = GetDlgItem(hwnd, IDT_FLP_PROGRESS); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + + h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); + + if (is_mdi) { + empty = (unsigned char *) malloc(base); + memset(empty, 0, base); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) 25; + *(uint8_t *) &(empty[0x18]) = (uint8_t) 64; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) (dp->sectors / 64) / 25; + + fwrite(empty, 1, 2048, f); + SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + fwrite(&empty[0x0800], 1, 2048, f); + free(empty); + + SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + empty = (unsigned char *) malloc(1048576); + memset(empty, 0x00, 1048576); + + if (total_size2 > 0) { + empty2 = (unsigned char *) malloc(total_size2); + memset(empty, 0x00, total_size2); + } + + for (i = 0; i < blocks_num; i++) { + fwrite(empty, 1, 1048576, f); + + SendMessage(h, PBM_SETPOS, (WPARAM) i + j, (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + if (total_size2 > 0) { + fwrite(empty2, 1, total_size2, f); + + SendMessage(h, PBM_SETPOS, (WPARAM) pbar_max - 1, (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + if (empty2 != NULL) + free(empty2); + free(empty); + + fclose(f); + + return 1; +} + + static int fdd_id, sb_part; static int file_type = 0; /* 0 = IMG, 1 = Japanese FDI, 2 = 86F */ -static wchar_t fd_file_name[1024]; +static char fd_file_name[1024]; /* Show a MessageBox dialog. This is nasty, I know. --FvK */ @@ -562,20 +703,26 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) uint8_t disk_size, rpm_mode; int ret; FILE *f; - int zip_types; + int zip_types, mo_types, floppy_types; wchar_t *twcs; switch (message) { case WM_INITDIALOG: plat_pause(1); - memset(fd_file_name, 0, 1024 * sizeof(wchar_t)); + memset(fd_file_name, 0, 1024); h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); if (is_zip) { zip_types = zip_drives[fdd_id].is_250 ? 2 : 1; for (i = 0; i < zip_types; i++) SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5900 + i)); + } else if (is_mo) { + mo_types = 10; + /* TODO: Proper string ID's. */ + for (i = 0; i < mo_types; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5902 + i)); } else { - for (i = 0; i < 12; i++) + floppy_types = 12; + for (i = 0; i < floppy_types; i++) SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5888 + i)); } SendMessage(h, CB_SETCURSEL, 0, 0); @@ -586,7 +733,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, CB_SETCURSEL, 0, 0); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); - h = GetDlgItem(hdlg, IDT_1751); + h = GetDlgItem(hdlg, IDT_FLP_RPM_MODE); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); h = GetDlgItem(hdlg, IDOK); @@ -594,7 +741,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); - h = GetDlgItem(hdlg, IDT_1757); + h = GetDlgItem(hdlg, IDT_FLP_PROGRESS); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); break; @@ -606,22 +753,24 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) disk_size = SendMessage(h, CB_GETCURSEL, 0, 0); if (is_zip) disk_size += 12; - if (file_type == 2) { + if (!is_zip && !is_mo && (file_type == 2)) { h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); rpm_mode = SendMessage(h, CB_GETCURSEL, 0, 0); ret = create_86f(fd_file_name, disk_sizes[disk_size], rpm_mode); } else { if (is_zip) ret = create_zip_sector_image(fd_file_name, disk_sizes[disk_size], file_type, hdlg); + if (is_mo) + ret = create_mo_sector_image(fd_file_name, disk_size, file_type, hdlg); else ret = create_sector_image(fd_file_name, disk_sizes[disk_size], file_type); } if (ret) { if (is_zip) - //ui_sb_mount_zip_img(fdd_id, sb_part, 0, fd_file_name); zip_mount(fdd_id, fd_file_name, 0); + else if (is_mo) + mo_mount(fdd_id, fd_file_name, 0); else - //ui_sb_mount_floppy_img(fdd_id, sb_part, 0, fd_file_name); floppy_mount(fdd_id, fd_file_name, 0); } else { new_floppy_msgbox_header(hdlg, MBX_ERROR, (wchar_t *) IDS_4108, (wchar_t *) IDS_4115); @@ -634,12 +783,12 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; case IDC_CFILE: - if (!file_dlg_w(hdlg, plat_get_string(is_zip ? IDS_2055 : IDS_2062), L"", 1)) { + if (!file_dlg_w(hdlg, plat_get_string(is_mo ? IDS_2139 : (is_zip ? IDS_2055 : IDS_2062)), L"", NULL, 1)) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { twcs = &wopenfilestring[wcslen(wopenfilestring)]; twcs[0] = L'.'; - if (!is_zip && (filterindex == 3)) { + if (!is_zip && !is_mo && (filterindex == 3)) { twcs[1] = L'8'; twcs[2] = L'6'; twcs[3] = L'f'; @@ -659,7 +808,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); memset(fd_file_name, 0, sizeof(fd_file_name)); - wcscpy(fd_file_name, wopenfilestring); + c16stombs(fd_file_name, wopenfilestring, sizeof(fd_file_name)); h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); if (!is_zip || zip_drives[fdd_id].is_250) EnableWindow(h, TRUE); @@ -671,6 +820,11 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) file_type = 1; else file_type = 0; + } else if (is_mo) { + if (((wcs_len >= 4) && !wcsicmp(ext, L".MDI"))) + file_type = 1; + else + file_type = 0; } else { if (((wcs_len >= 4) && !wcsicmp(ext, L".FDI"))) file_type = 1; @@ -679,7 +833,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) else file_type = 0; } - h = GetDlgItem(hdlg, IDT_1751); + h = GetDlgItem(hdlg, IDT_FLP_RPM_MODE); if (file_type == 2) { EnableWindow(h, TRUE); ShowWindow(h, SW_SHOW); @@ -717,5 +871,10 @@ NewFloppyDialogCreate(HWND hwnd, int id, int part) fdd_id = id & 0x7f; sb_part = part; is_zip = !!(id & 0x80); + is_mo = !!(id & 0x100); + if (is_zip && is_mo) { + fatal("Attempting to create a new image dialog that is for both ZIP and MO at the same time\n"); + return; + } DialogBox(hinstance, (LPCTSTR)DLG_NEW_FLOPPY, hwnd, NewFloppyDialogProcedure); } diff --git a/src/win/win_opendir.c b/src/win/win_opendir.c index 1740140cc..24fefc8c2 100644 --- a/src/win/win_opendir.c +++ b/src/win/win_opendir.c @@ -17,8 +17,6 @@ * Copyright 1998-2007 MicroWalt Corporation * Copyright 2017 Fred N. van Kempen */ -#define UNICODE -#include #include #include #include @@ -30,26 +28,15 @@ #include <86box/plat_dir.h> -#ifdef UNICODE -# define SUFFIX L"\\*" -# define FINDATA struct _wfinddata_t -# define FINDFIRST _wfindfirst -# define FINDNEXT _wfindnext -#else -# define SUFFIX "\\*" -# define FINDATA struct _finddata_t -# define FINDFIRST _findfirst -# define FINDNEXT _findnext -#endif +#define SUFFIX "\\*" +#define FINDATA struct _finddata_t +#define FINDFIRST _findfirst +#define FINDNEXT _findnext /* Open a directory. */ DIR * -#ifdef UNICODE -opendirw(const wchar_t *name) -#else opendir(const char *name) -#endif { DIR *p; @@ -71,20 +58,11 @@ opendir(const char *name) memset(p->dta, 0x00, sizeof(struct _finddata_t)); /* Add search filespec. */ -#ifdef UNICODE - wcscpy(p->dir, name); - wcscat(p->dir, SUFFIX); -#else strcpy(p->dir, name); strcat(p->dir, SUFFIX); -#endif /* Special case: flag if we are in the root directory. */ -#ifdef UNICODE - if (wcslen(p->dir) == 3) -#else if (strlen(p->dir) == 3) -#endif p->flags |= DIR_F_ISROOT; /* Start the searching by doing a FindFirst. */ @@ -124,7 +102,7 @@ closedir(DIR *p) * standard "." and ".." entries. Many applications do assume * this anyway, so we simply fake these entries. */ -struct direct * +struct dirent * readdir(DIR *p) { FINDATA *ffp; @@ -138,30 +116,18 @@ readdir(DIR *p) p->dent.d_off = p->offset++; switch(p->offset) { case 1: /* . */ -#ifdef UNICODE - wcsncpy(p->dent.d_name, L".", MAXNAMLEN+1); -#else strncpy(p->dent.d_name, ".", MAXNAMLEN+1); -#endif p->dent.d_reclen = 1; break; case 2: /* .. */ -#ifdef UNICODE - wcsncpy(p->dent.d_name, L"..", MAXNAMLEN+1); -#else strncpy(p->dent.d_name, "..", MAXNAMLEN+1); -#endif p->dent.d_reclen = 2; break; default: /* regular entry. */ -#ifdef UNICODE - wcsncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); -#else strncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); -#endif - p->dent.d_reclen = (char) wcslen(p->dent.d_name); + p->dent.d_reclen = (char)strlen(p->dent.d_name); } /* Read next entry. */ diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c new file mode 100644 index 000000000..271af462e --- /dev/null +++ b/src/win/win_opengl.c @@ -0,0 +1,1046 @@ +/* + * 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. + * + * Rendering module for OpenGL + * + * TODO: More shader features + * - scaling + * - multipass + * - previous frames + * (UI) options + * More error handling + * + * Authors: Teemu Korhonen + * + * Copyright 2021 Teemu Korhonen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#define UNICODE +#include +#include +#include +#include +#include + +#include +#include +#include + +#if !defined(_MSC_VER) || defined(__clang__) +#include +#else +typedef LONG atomic_flag; +#define atomic_flag_clear(OBJ) InterlockedExchange(OBJ, 0) +#define atomic_flag_test_and_set(OBJ) InterlockedExchange(OBJ, 1) +#endif + +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/win.h> +#include <86box/language.h> +#include <86box/win_opengl.h> +#include <86box/win_opengl_glslp.h> + +static const int INIT_WIDTH = 640; +static const int INIT_HEIGHT = 400; +static const int BUFFERPIXELS = 4194304; /* Same size as render_buffer, pow(2048+64,2). */ +static const int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ +static const int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ +static const int ROW_LENGTH = 2048; /* Source buffer row lenght (including padding) */ + +/** + * @brief A dedicated OpenGL thread. + * OpenGL context's don't handle multiple threads well. +*/ +static thread_t* thread = NULL; + +/** + * @brief A window usable with an OpenGL context +*/ +static SDL_Window* window = NULL; + +/** + * @brief SDL window handle +*/ +static HWND window_hwnd = NULL; + +/** + * @brief Parent window handle (hwndRender from win_ui) +*/ +static HWND parent = NULL; + +/** + * @brief Events listened in OpenGL thread. +*/ +static union +{ + struct + { + HANDLE closing; + HANDLE resize; + HANDLE reload; + HANDLE blit_waiting; + }; + HANDLE asArray[4]; +} sync_objects = { 0 }; + +/** + * @brief Blit event parameters. +*/ +typedef struct +{ + int w, h; + void* buffer; /* Buffer for pixel transfer, allocated by gpu driver. */ + volatile atomic_flag in_use; /* Is buffer currently in use. */ + GLsync sync; /* Fence sync object used by opengl thread to track pixel transfer completion. */ +} blit_info_t; + +/** + * @brief Array of blit_infos, one for each buffer. +*/ +static blit_info_t* blit_info = NULL; + +/** + * @brief Buffer index of next write operation. +*/ +static int write_pos = 0; + +/** + * @brief Resize event parameters. +*/ +static struct +{ + int width, height, fullscreen, scaling_mode; + mutex_t* mutex; +} resize_info = { 0 }; + +/** + * @brief Renderer options +*/ +static struct +{ + int vsync; /* Vertical sync; 0 = off, 1 = on */ + int frametime; /* Frametime in microseconds, or -1 to sync with blitter */ + char shaderfile[512]; /* Shader file path. Match the length of openfilestring in win_dialog.c */ + int shaderfile_changed; /* Has shader file path changed. To prevent unnecessary shader recompilation. */ + int filter; /* 0 = Nearest, 1 = Linear */ + int filter_changed; /* Has filter changed. */ + mutex_t* mutex; +} options = { 0 }; + +/** + * @brief Identifiers to OpenGL objects and uniforms. + */ +typedef struct +{ + GLuint vertexArrayID; + GLuint vertexBufferID; + GLuint textureID; + GLuint unpackBufferID; + GLuint shader_progID; + + /* Uniforms */ + + GLint input_size; + GLint output_size; + GLint texture_size; + GLint frame_count; +} gl_identifiers; + +/** + * @brief Set or unset OpenGL context window as a child window. + * + * Modifies the window style and sets the parent window. + * WS_EX_NOACTIVATE keeps the window from stealing input focus. + */ +static void set_parent_binding(int enable) +{ + long style = GetWindowLong(window_hwnd, GWL_STYLE); + long ex_style = GetWindowLong(window_hwnd, GWL_EXSTYLE); + + if (enable) + { + style |= WS_CHILD; + ex_style |= WS_EX_NOACTIVATE; + } + else + { + style &= ~WS_CHILD; + ex_style &= ~WS_EX_NOACTIVATE; + } + + SetWindowLong(window_hwnd, GWL_STYLE, style); + SetWindowLong(window_hwnd, GWL_EXSTYLE, ex_style); + + SetParent(window_hwnd, enable ? parent : NULL); +} + +/** + * @brief Windows message handler for our window. + * @param message + * @param wParam + * @param lParam + * @param fullscreen + * @return Was message handled +*/ +static int handle_window_messages(UINT message, WPARAM wParam, LPARAM lParam, int fullscreen) +{ + switch (message) + { + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + if (!fullscreen) + { + /* Bring main window to front. */ + SetForegroundWindow(GetAncestor(parent, GA_ROOT)); + + /* Mouse events that enter and exit capture. */ + PostMessage(parent, message, wParam, lParam); + } + return 1; + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + if (fullscreen) + { + PostMessage(parent, message, wParam, lParam); + } + return 1; + case WM_INPUT: + if (fullscreen) + { + /* Raw input handler from win_ui.c : input_proc */ + + UINT size = 0; + PRAWINPUT raw = NULL; + + /* Here we read the raw input data */ + GetRawInputData((HRAWINPUT)(LPARAM)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + raw = (PRAWINPUT)malloc(size); + if (GetRawInputData((HRAWINPUT)(LPARAM)lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)) == size) { + switch (raw->header.dwType) + { + case RIM_TYPEKEYBOARD: + keyboard_handle(raw); + break; + case RIM_TYPEMOUSE: + win_mouse_handle(raw); + break; + case RIM_TYPEHID: + win_joystick_handle(raw); + break; + } + } + free(raw); + } + return 1; + case WM_MOUSELEAVE: + if (fullscreen) + { + /* Leave fullscreen if mouse leaves the renderer window. */ + PostMessage(GetAncestor(parent, GA_ROOT), WM_LEAVEFULLSCREEN, 0, 0); + } + return 0; + } + + return 0; +} + +/** + * @brief (Re-)apply shaders to OpenGL context. + * @param gl Identifiers from initialize +*/ +static void apply_shaders(gl_identifiers* gl) +{ + GLuint old_shader_ID = 0; + + if (gl->shader_progID != 0) + old_shader_ID = gl->shader_progID; + + if (strlen(options.shaderfile) > 0) + gl->shader_progID = load_custom_shaders(options.shaderfile); + else + gl->shader_progID = 0; + + if (gl->shader_progID == 0) + gl->shader_progID = load_default_shaders(); + + glUseProgram(gl->shader_progID); + + /* Delete old shader if one exists (changing shader) */ + if (old_shader_ID != 0) + glDeleteProgram(old_shader_ID); + + GLint vertex_coord = glGetAttribLocation(gl->shader_progID, "VertexCoord"); + if (vertex_coord != -1) + { + glEnableVertexAttribArray(vertex_coord); + glVertexAttribPointer(vertex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); + } + + GLint tex_coord = glGetAttribLocation(gl->shader_progID, "TexCoord"); + if (tex_coord != -1) + { + glEnableVertexAttribArray(tex_coord); + glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat))); + } + + GLint color = glGetAttribLocation(gl->shader_progID, "Color"); + if (color != -1) + { + glEnableVertexAttribArray(color); + glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(4 * sizeof(GLfloat))); + } + + GLint mvp_matrix = glGetUniformLocation(gl->shader_progID, "MVPMatrix"); + if (mvp_matrix != -1) + { + static const GLfloat mvp[] = { + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f + }; + glUniformMatrix4fv(mvp_matrix, 1, GL_FALSE, mvp); + } + + GLint frame_direction = glGetUniformLocation(gl->shader_progID, "FrameDirection"); + if (frame_direction != -1) + glUniform1i(frame_direction, 1); /* always forward */ + + gl->input_size = glGetUniformLocation(gl->shader_progID, "InputSize"); + gl->output_size = glGetUniformLocation(gl->shader_progID, "OutputSize"); + gl->texture_size = glGetUniformLocation(gl->shader_progID, "TextureSize"); + gl->frame_count = glGetUniformLocation(gl->shader_progID, "FrameCount"); +} + +/** + * @brief Initialize OpenGL context + * @return Identifiers +*/ +static int initialize_glcontext(gl_identifiers* gl) +{ + /* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */ + static const GLfloat surface[] = { + -1.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, + 1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, + -1.f, -1.f, 0.f, 1.f, 1.f, 1.f, 1.f, 1.f, + 1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f + }; + + glGenVertexArrays(1, &gl->vertexArrayID); + + glBindVertexArray(gl->vertexArrayID); + + glGenBuffers(1, &gl->vertexBufferID); + glBindBuffer(GL_ARRAY_BUFFER, gl->vertexBufferID); + glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW); + + glGenTextures(1, &gl->textureID); + glBindTexture(GL_TEXTURE_2D, gl->textureID); + + static const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, options.filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, options.filter ? GL_LINEAR : GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, INIT_WIDTH, INIT_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glGenBuffers(1, &gl->unpackBufferID); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl->unpackBufferID); + + void* buf_ptr = NULL; + + if (GLAD_GL_ARB_buffer_storage) + { + /* Create persistent buffer for pixel transfer. */ + glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + + buf_ptr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + } + else + { + /* Fallback; create our own buffer. */ + buf_ptr = malloc(BUFFERBYTES * BUFFERCOUNT); + + glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW); + } + + if (buf_ptr == NULL) + return 0; /* Most likely out of memory. */ + + /* Split the buffer area for each blit_info and set them available for use. */ + for (int i = 0; i < BUFFERCOUNT; i++) + { + blit_info[i].buffer = (byte*)buf_ptr + BUFFERBYTES * i; + atomic_flag_clear(&blit_info[i].in_use); + } + + glClearColor(0.f, 0.f, 0.f, 1.f); + + apply_shaders(gl); + + return 1; +} + +/** + * @brief Clean up OpenGL context + * @param gl Identifiers from initialize +*/ +static void finalize_glcontext(gl_identifiers* gl) +{ + if (GLAD_GL_ARB_buffer_storage) + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + else + free(blit_info[0].buffer); + + glDeleteProgram(gl->shader_progID); + glDeleteBuffers(1, &gl->unpackBufferID); + glDeleteTextures(1, &gl->textureID); + glDeleteBuffers(1, &gl->vertexBufferID); + glDeleteVertexArrays(1, &gl->vertexArrayID); +} + +/** + * @brief Renders a frame and swaps the buffer + * @param gl Identifiers from initialize +*/ +static void render_and_swap(gl_identifiers* gl) +{ + static int frame_counter = 0; + + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + SDL_GL_SwapWindow(window); + + if (gl->frame_count != -1) + glUniform1i(gl->frame_count, frame_counter = (frame_counter + 1) & 1023); +} + +/** + * @brief Handle failure in OpenGL thread. + * Keeps the thread sleeping until closing. +*/ +static void opengl_fail() +{ + if (window != NULL) + { + SDL_DestroyWindow(window); + window = NULL; + } + + wchar_t* message = plat_get_string(IDS_2152); + wchar_t* header = plat_get_string(IDS_2153); + MessageBox(parent, header, message, MB_OK); + + WaitForSingleObject(sync_objects.closing, INFINITE); + + _endthread(); +} + +static void __stdcall opengl_debugmsg_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + pclog("OpenGL: %s\n", message); +} + +/** + * @brief Main OpenGL thread proc. + * + * OpenGL context should be accessed only from this single thread. + * Events are used to synchronize communication. +*/ +static void opengl_main(void* param) +{ + /* Initialize COM library for this thread before SDL does so. */ + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + SDL_InitSubSystem(SDL_INIT_VIDEO); + + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); /* Is this actually doing anything...? */ + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + + if (GLAD_GL_ARB_debug_output && log_path[0] != '\0') + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + + window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); + + if (window == NULL) + { + pclog("OpenGL: failed to create OpenGL window.\n"); + opengl_fail(); + } + + /* Keep track of certain parameters, only changed in this thread to avoid race conditions */ + int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT, + output_width = resize_info.width, output_height = resize_info.height, frametime = options.frametime; + + SDL_SysWMinfo wmi = { 0 }; + SDL_VERSION(&wmi.version); + SDL_GetWindowWMInfo(window, &wmi); + + if (wmi.subsystem != SDL_SYSWM_WINDOWS) + { + pclog("OpenGL: subsystem is not SDL_SYSWM_WINDOWS.\n"); + opengl_fail(); + } + + window_hwnd = wmi.info.win.window; + + if (!fullscreen) + set_parent_binding(1); + else + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + + SDL_GLContext context = SDL_GL_CreateContext(window); + + if (context == NULL) + { + pclog("OpenGL: failed to create OpenGL context.\n"); + opengl_fail(); + } + + SDL_GL_SetSwapInterval(options.vsync); + + if (!gladLoadGLLoader(SDL_GL_GetProcAddress)) + { + pclog("OpenGL: failed to set OpenGL loader.\n"); + SDL_GL_DeleteContext(context); + opengl_fail(); + } + + if (GLAD_GL_ARB_debug_output && log_path[0] != '\0') + { + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE_ARB, GL_DONT_CARE, 0, 0, GL_FALSE); + glDebugMessageCallbackARB(opengl_debugmsg_callback, NULL); + } + + pclog("OpenGL vendor: %s\n", glGetString(GL_VENDOR)); + pclog("OpenGL renderer: %s\n", glGetString(GL_RENDERER)); + pclog("OpenGL version: %s\n", glGetString(GL_VERSION)); + pclog("OpenGL shader language version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + + /* Check that the driver actually reports version 3.0 or later */ + GLint major = -1; + glGetIntegerv(GL_MAJOR_VERSION, &major); + if (major < 3) + { + pclog("OpenGL: Minimum OpenGL version 3.0 is required.\n"); + SDL_GL_DeleteContext(context); + opengl_fail(); + } + + /* Check if errors have been generated at this point */ + GLenum gl_error = glGetError(); + if (gl_error != GL_NO_ERROR) + { + /* Log up to 10 errors */ + int i = 0; + do + { + pclog("OpenGL: Error %u\n", gl_error); + i++; + } + while((gl_error = glGetError()) != GL_NO_ERROR && i < 10); + + SDL_GL_DeleteContext(context); + opengl_fail(); + } + + gl_identifiers gl = { 0 }; + + if (!initialize_glcontext(&gl)) + { + pclog("OpenGL: failed to initialize.\n"); + finalize_glcontext(&gl); + SDL_GL_DeleteContext(context); + opengl_fail(); + } + + if (gl.frame_count != -1) + glUniform1i(gl.frame_count, 0); + if (gl.output_size != -1) + glUniform2f(gl.output_size, output_width, output_height); + + uint32_t last_swap = plat_get_micro_ticks() - frametime; + + int read_pos = 0; /* Buffer index of next read operation. */ + + /* Render loop */ + int closing = 0; + while (!closing) + { + /* Rendering is done right after handling an event. */ + if (frametime < 0) + render_and_swap(&gl); + + DWORD wait_result = WAIT_TIMEOUT; + + do + { + /* Rendering is timed by frame capping. */ + if (frametime >= 0) + { + uint32_t ticks = plat_get_micro_ticks(); + + uint32_t elapsed = ticks - last_swap; + + if (elapsed + 1000 > frametime) + { + /* Spin the remaining time (< 1ms) to next frame */ + while (elapsed < frametime) + { + Sleep(0); /* Yield processor time */ + ticks = plat_get_micro_ticks(); + elapsed = ticks - last_swap; + } + + render_and_swap(&gl); + last_swap = ticks; + } + } + + if (GLAD_GL_ARB_sync) + { + /* Check if commands that use buffers have been completed. */ + for (int i = 0; i < BUFFERCOUNT; i++) + { + if (blit_info[i].sync != NULL && glClientWaitSync(blit_info[i].sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0) != GL_TIMEOUT_EXPIRED) + { + glDeleteSync(blit_info[i].sync); + blit_info[i].sync = NULL; + atomic_flag_clear(&blit_info[i].in_use); + } + } + } + + /* Handle window messages */ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.hwnd != window_hwnd || !handle_window_messages(msg.message, msg.wParam, msg.lParam, fullscreen)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + /* Wait for synchronized events for 1ms before going back to window events */ + wait_result = WaitForMultipleObjects(sizeof(sync_objects) / sizeof(HANDLE), sync_objects.asArray, FALSE, 1); + + } while (wait_result == WAIT_TIMEOUT); + + HANDLE sync_event = sync_objects.asArray[wait_result - WAIT_OBJECT_0]; + + if (sync_event == sync_objects.closing) + { + closing = 1; + } + else if (sync_event == sync_objects.blit_waiting) + { + blit_info_t* info = &blit_info[read_pos]; + + if (video_width != info->w || video_height != info->h) + { + video_width = info->w; + video_height = info->h; + + /* Resize the texture */ + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, video_width, video_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl.unpackBufferID); + + if (fullscreen) + SetEvent(sync_objects.resize); + } + + if (!GLAD_GL_ARB_buffer_storage) + { + /* Fallback method, copy data to pixel buffer. */ + glBufferSubData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * read_pos, info->h * ROW_LENGTH * sizeof(uint32_t), info->buffer); + } + + /* Update texture from pixel buffer. */ + glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * read_pos); + glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info->w, info->h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + if (GLAD_GL_ARB_sync) + { + /* Add fence to track when above gl commands are complete. */ + info->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } + else + { + /* No sync objects; block until commands are complete. */ + glFinish(); + atomic_flag_clear(&info->in_use); + } + + read_pos = (read_pos + 1) % BUFFERCOUNT; + + /* Update uniforms */ + if (gl.input_size != -1) + glUniform2f(gl.input_size, video_width, video_height); + if (gl.texture_size != -1) + glUniform2f(gl.texture_size, video_width, video_height); + } + else if (sync_event == sync_objects.resize) + { + thread_wait_mutex(resize_info.mutex); + + if (fullscreen != resize_info.fullscreen) + { + fullscreen = resize_info.fullscreen; + + set_parent_binding(!fullscreen); + + SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + + if (fullscreen) + { + SetForegroundWindow(window_hwnd); + SetFocus(window_hwnd); + + /* Clip cursor to prevent it moving to another monitor. */ + RECT rect; + GetWindowRect(window_hwnd, &rect); + ClipCursor(&rect); + } + else + ClipCursor(NULL); + } + + if (fullscreen) + { + int width, height, pad_x = 0, pad_y = 0, px_size = 1; + float ratio = 0; + const float ratio43 = 4.f / 3.f; + + SDL_GetWindowSize(window, &width, &height); + + if (video_width > 0 && video_height > 0) + { + switch (resize_info.scaling_mode) + { + case FULLSCR_SCALE_INT: + px_size = max(min(width / video_width, height / video_height), 1); + + pad_x = width - (video_width * px_size); + pad_y = height - (video_height * px_size); + break; + + case FULLSCR_SCALE_KEEPRATIO: + ratio = (float)video_width / (float)video_height; + case FULLSCR_SCALE_43: + if (ratio == 0) + ratio = ratio43; + if (ratio < ((float)width / (float)height)) + pad_x = width - (int)roundf((float)height * ratio); + else + pad_y = height - (int)roundf((float)width / ratio); + break; + + case FULLSCR_SCALE_FULL: + default: + break; + } + } + + output_width = width - pad_x; + output_height = height - pad_y; + + glViewport(pad_x / 2, pad_y / 2, output_width, output_height); + + if (gl.output_size != -1) + glUniform2f(gl.output_size, output_width, output_height); + } + else + { + SDL_SetWindowSize(window, resize_info.width, resize_info.height); + + /* SWP_NOZORDER is needed for child window and SDL doesn't enable it. */ + SetWindowPos(window_hwnd, parent, 0, 0, resize_info.width, resize_info.height, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE); + + output_width = resize_info.width; + output_height = resize_info.height; + + glViewport(0, 0, resize_info.width, resize_info.height); + + if (gl.output_size != -1) + glUniform2f(gl.output_size, resize_info.width, resize_info.height); + } + + thread_release_mutex(resize_info.mutex); + } + else if (sync_event == sync_objects.reload) + { + thread_wait_mutex(options.mutex); + + frametime = options.frametime; + + SDL_GL_SetSwapInterval(options.vsync); + + if (options.shaderfile_changed) + { + /* Change shader program. */ + apply_shaders(&gl); + + /* Uniforms need to be updated after proram change. */ + if (gl.input_size != -1) + glUniform2f(gl.input_size, video_width, video_height); + if (gl.output_size != -1) + glUniform2f(gl.output_size, output_width, output_height); + if (gl.texture_size != -1) + glUniform2f(gl.texture_size, video_width, video_height); + if (gl.frame_count != -1) + glUniform1i(gl.frame_count, 0); + + options.shaderfile_changed = 0; + } + + if (options.filter_changed) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, options.filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, options.filter ? GL_LINEAR : GL_NEAREST); + + options.filter_changed = 0; + } + + thread_release_mutex(options.mutex); + } + + /* Keep cursor hidden in full screen and mouse capture */ + int show_cursor = !(fullscreen || !!mouse_capture); + if (SDL_ShowCursor(-1) != show_cursor) + SDL_ShowCursor(show_cursor); + } + + if (GLAD_GL_ARB_sync) + { + for (int i = 0; i < BUFFERCOUNT; i++) + { + if (blit_info[i].sync != NULL) + glDeleteSync(blit_info[i].sync); + } + } + + finalize_glcontext(&gl); + + SDL_GL_DeleteContext(context); + + set_parent_binding(0); + + SDL_DestroyWindow(window); + + window = NULL; + + CoUninitialize(); +} + +static void opengl_blit(int x, int y, int w, int h, int monitor_index) +{ + int row; + + if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (thread == NULL) || + atomic_flag_test_and_set(&blit_info[write_pos].in_use) || monitor_index >= 1) + { + video_blit_complete_monitor(monitor_index); + return; + } + + for (row = 0; row < h; ++row) + video_copy(&(((uint8_t *) blit_info[write_pos].buffer)[row * ROW_LENGTH * sizeof(uint32_t)]), &(buffer32->line[y + row][x]), w * sizeof(uint32_t)); + + if (monitors[0].mon_screenshots) + video_screenshot(blit_info[write_pos].buffer, 0, 0, ROW_LENGTH); + + video_blit_complete(); + + blit_info[write_pos].w = w; + blit_info[write_pos].h = h; + + write_pos = (write_pos + 1) % BUFFERCOUNT; + + ReleaseSemaphore(sync_objects.blit_waiting, 1, NULL); +} + +static int framerate_to_frametime(int framerate) +{ + if (framerate < 0) + return -1; + + return (int)ceilf(1.e6f / (float)framerate); +} + +int opengl_init(HWND hwnd) +{ + if (thread != NULL) + return 0; + + for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++) + sync_objects.asArray[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + + sync_objects.closing = CreateEvent(NULL, FALSE, FALSE, NULL); + sync_objects.resize = CreateEvent(NULL, FALSE, FALSE, NULL); + sync_objects.reload = CreateEvent(NULL, FALSE, FALSE, NULL); + sync_objects.blit_waiting = CreateSemaphore(NULL, 0, BUFFERCOUNT * 2, NULL); + + parent = hwnd; + + RECT parent_size; + + GetWindowRect(parent, &parent_size); + + resize_info.width = parent_size.right - parent_size.left; + resize_info.height = parent_size.bottom - parent_size.top; + resize_info.fullscreen = video_fullscreen & 1; + resize_info.scaling_mode = video_fullscreen_scale; + resize_info.mutex = thread_create_mutex(); + + options.vsync = video_vsync; + options.frametime = framerate_to_frametime(video_framerate); + strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader); + options.shaderfile_changed = 0; + options.filter = video_filter_method; + options.filter_changed = 0; + options.mutex = thread_create_mutex(); + + blit_info = (blit_info_t*)malloc(BUFFERCOUNT * sizeof(blit_info_t)); + memset(blit_info, 0, BUFFERCOUNT * sizeof(blit_info_t)); + + /* Buffers are not yet allocated, set them as in use. */ + for (int i = 0; i < BUFFERCOUNT; i++) + atomic_flag_test_and_set(&blit_info[i].in_use); + + write_pos = 0; + + thread = thread_create(opengl_main, (void*)NULL); + + atexit(opengl_close); + + video_setblit(opengl_blit); + + return 1; +} + +int opengl_pause(void) +{ + return 0; +} + +void opengl_close(void) +{ + if (thread == NULL) + return; + + SetEvent(sync_objects.closing); + + thread_wait(thread); + + thread_close_mutex(resize_info.mutex); + thread_close_mutex(options.mutex); + + thread = NULL; + + free(blit_info); + + for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++) + { + CloseHandle(sync_objects.asArray[i]); + sync_objects.asArray[i] = (HANDLE)NULL; + } + + parent = NULL; +} + +void opengl_set_fs(int fs) +{ + if (thread == NULL) + return; + + thread_wait_mutex(resize_info.mutex); + + resize_info.fullscreen = fs; + resize_info.scaling_mode = video_fullscreen_scale; + + thread_release_mutex(resize_info.mutex); + + SetEvent(sync_objects.resize); +} + +void opengl_resize(int w, int h) +{ + if (thread == NULL) + return; + + thread_wait_mutex(resize_info.mutex); + + resize_info.width = w; + resize_info.height = h; + resize_info.scaling_mode = video_fullscreen_scale; + + thread_release_mutex(resize_info.mutex); + + SetEvent(sync_objects.resize); +} + +void opengl_reload(void) +{ + if (thread == NULL) + return; + + thread_wait_mutex(options.mutex); + + options.vsync = video_vsync; + options.frametime = framerate_to_frametime(video_framerate); + + if (strcmp(video_shader, options.shaderfile) != 0) + { + strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader); + options.shaderfile_changed = 1; + } + + if (video_filter_method != options.filter) + { + options.filter = video_filter_method; + options.filter_changed = 1; + } + + thread_release_mutex(options.mutex); + + SetEvent(sync_objects.reload); +} diff --git a/src/win/win_opengl_glslp.c b/src/win/win_opengl_glslp.c new file mode 100644 index 000000000..d8916bd83 --- /dev/null +++ b/src/win/win_opengl_glslp.c @@ -0,0 +1,272 @@ +/* + * 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. + * + * File parser for .glslp and .glsl shader files + * in the format of libretro. + * + * TODO: Read .glslp files for multipass shaders and settings. + * + * Authors: Teemu Korhonen + * + * Copyright 2021 Teemu Korhonen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/win_opengl_glslp.h> + + /** + * @brief Default vertex shader. + */ +static const GLchar* vertex_shader = "#version 130\n\ +in vec2 VertexCoord;\n\ +in vec2 TexCoord;\n\ +out vec2 tex;\n\ +void main(){\n\ + gl_Position = vec4(VertexCoord, 0.0, 1.0);\n\ + tex = TexCoord;\n\ +}\n"; + +/** + * @brief Default fragment shader. + */ +static const GLchar* fragment_shader = "#version 130\n\ +in vec2 tex;\n\ +uniform sampler2D texsampler;\n\ +out vec4 color;\n\ +void main() {\n\ + color = texture(texsampler, tex);\n\ +}\n"; + +/** + * @brief OpenGL shader program build targets +*/ +typedef enum +{ + OPENGL_BUILD_TARGET_VERTEX, + OPENGL_BUILD_TARGET_FRAGMENT, + OPENGL_BUILD_TARGET_LINK +} opengl_build_target_t; + +/** + * @brief Reads a whole file into a null terminated string. + * @param Path Path to the file relative to executable path. + * @return Pointer to the string or NULL on error. Remember to free() after use. +*/ +static char* read_file_to_string(const char* path) +{ + FILE* file_handle = plat_fopen(path, "rb"); + + if (file_handle != NULL) + { + /* get file size */ + fseek(file_handle, 0, SEEK_END); + + size_t file_size = (size_t)ftell(file_handle); + + fseek(file_handle, 0, SEEK_SET); + + /* read to buffer and close */ + char* content = (char*)malloc(sizeof(char) * (file_size + 1)); + + if (!content) + return NULL; + + size_t length = fread(content, sizeof(char), file_size, file_handle); + + fclose(file_handle); + + content[length] = 0; + + return content; + } + return NULL; +} + +static int check_status(GLuint id, opengl_build_target_t build_target, const char* shader_path) +{ + GLint status = GL_FALSE; + + if (build_target != OPENGL_BUILD_TARGET_LINK) + glGetShaderiv(id, GL_COMPILE_STATUS, &status); + else + glGetProgramiv(id, GL_LINK_STATUS, &status); + + if (status == GL_FALSE) + { + int info_log_length; + + if (build_target != OPENGL_BUILD_TARGET_LINK) + glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length); + else + glGetProgramiv(id, GL_INFO_LOG_LENGTH, &info_log_length); + + GLchar* info_log_text = (GLchar*)malloc(sizeof(GLchar) * info_log_length); + + if (build_target != OPENGL_BUILD_TARGET_LINK) + glGetShaderInfoLog(id, info_log_length, NULL, info_log_text); + else + glGetProgramInfoLog(id, info_log_length, NULL, info_log_text); + + const char* reason = NULL; + + switch (build_target) + { + case OPENGL_BUILD_TARGET_VERTEX: + reason = "compiling vertex shader"; + break; + case OPENGL_BUILD_TARGET_FRAGMENT: + reason = "compiling fragment shader"; + break; + case OPENGL_BUILD_TARGET_LINK: + reason = "linking shader program"; + break; + } + + /* Shader compilation log can be lengthy, mark begin and end */ + const char* line = "--------------------"; + + pclog("OpenGL: Error when %s in %s:\n%sBEGIN%s\n%s\n%s END %s\n", reason, shader_path, line, line, info_log_text, line, line); + + free(info_log_text); + + return 0; + } + + return 1; +} + +/** + * @brief Compile custom shaders into a program. + * @return Shader program identifier. +*/ +GLuint load_custom_shaders(const char* path) +{ + char* shader = read_file_to_string(path); + + if (shader != NULL) + { + int success = 1; + + const char* vertex_sources[3] = { "#version 130\n", "#define VERTEX\n", shader }; + const char* fragment_sources[3] = { "#version 130\n", "#define FRAGMENT\n", shader }; + + /* Check if the shader program defines version directive */ + char* version_start = strstr(shader, "#version"); + + /* If the shader program contains a version directive, + it must be captured and placed as the first statement. */ + if (version_start != NULL) + { + /* Version directive found, search the line end */ + char* version_end = strchr(version_start, '\n'); + + if (version_end != NULL) + { + char version[30] = ""; + + size_t version_len = MIN(version_end - version_start + 1, 29); + + strncat(version, version_start, version_len); + + /* replace the default version directive */ + vertex_sources[0] = version; + fragment_sources[0] = version; + } + + /* Comment out the original version directive + as only one is allowed. */ + memset(version_start, '/', 2); + } + + GLuint vertex_id = glCreateShader(GL_VERTEX_SHADER); + GLuint fragment_id = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vertex_id, 3, vertex_sources, NULL); + glCompileShader(vertex_id); + success *= check_status(vertex_id, OPENGL_BUILD_TARGET_VERTEX, path); + + glShaderSource(fragment_id, 3, fragment_sources, NULL); + glCompileShader(fragment_id); + success *= check_status(fragment_id, OPENGL_BUILD_TARGET_FRAGMENT, path); + + free(shader); + + GLuint prog_id = 0; + + if (success) + { + prog_id = glCreateProgram(); + + glAttachShader(prog_id, vertex_id); + glAttachShader(prog_id, fragment_id); + glLinkProgram(prog_id); + check_status(prog_id, OPENGL_BUILD_TARGET_LINK, path); + + glDetachShader(prog_id, vertex_id); + glDetachShader(prog_id, fragment_id); + } + + glDeleteShader(vertex_id); + glDeleteShader(fragment_id); + + return prog_id; + } + return 0; +} + +/** + * @brief Compile default shaders into a program. + * @return Shader program identifier. +*/ +GLuint load_default_shaders() +{ + GLuint vertex_id = glCreateShader(GL_VERTEX_SHADER); + GLuint fragment_id = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vertex_id, 1, &vertex_shader, NULL); + glCompileShader(vertex_id); + + glShaderSource(fragment_id, 1, &fragment_shader, NULL); + glCompileShader(fragment_id); + + GLuint prog_id = glCreateProgram(); + + glAttachShader(prog_id, vertex_id); + glAttachShader(prog_id, fragment_id); + + glLinkProgram(prog_id); + + glDetachShader(prog_id, vertex_id); + glDetachShader(prog_id, fragment_id); + + glDeleteShader(vertex_id); + glDeleteShader(fragment_id); + + return prog_id; +} diff --git a/src/win/win_preferences.c b/src/win/win_preferences.c new file mode 100644 index 000000000..74b5a186a --- /dev/null +++ b/src/win/win_preferences.c @@ -0,0 +1,293 @@ +/* + * 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. + * + * Handle the dialog for changing the program's language and other global settings. + * + * + * Authors: Laci bá' + * + * Copyright 2021 Laci bá' + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/plat.h> +#include <86box/sound.h> +#include <86box/win.h> +#include <86box/ui.h> +#include <86box/resource.h> + +/* Language */ +static LCID temp_language; + +static char temp_icon_set[256] = {0}; + +int enum_helper, c; + +HWND hwndPreferences; + +BOOL CALLBACK +EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam) +{ + wchar_t temp[LOCALE_NAME_MAX_LENGTH + 1]; + LCIDToLocaleName(wIDLanguage, temp, LOCALE_NAME_MAX_LENGTH, 0); + wchar_t dispname[MAX_PATH + 1]; + GetLocaleInfoEx(temp, LOCALE_SENGLISHDISPLAYNAME, dispname, MAX_PATH); + SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)dispname); + SendMessage((HWND)lParam, CB_SETITEMDATA, c, (LPARAM)wIDLanguage); + + if (wIDLanguage == lang_id) + enum_helper = c; + c++; + + return 1; +} + +/* Load available languages */ +static void +preferences_fill_languages(HWND hdlg) +{ + temp_language = GetThreadUILanguage(); + HWND lang_combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + + SendMessage(lang_combo, CB_RESETCONTENT, 0, 0); + SendMessage(lang_combo, CB_ADDSTRING, 0, win_get_string(IDS_7168)); + SendMessage(lang_combo, CB_SETITEMDATA, 0, 0xFFFF); + + enum_helper = 0; c = 1; + //if no one is selected, then it was 0xFFFF or unsupported language, in either case go with index enum_helper=0 + //also start enum index from c=1 + EnumResourceLanguages(hinstance, RT_MENU, L"MainMenu", &EnumResLangProc, (LPARAM)lang_combo); + + SendMessage(lang_combo, CB_SETCURSEL, enum_helper, 0); +} + +/* Load available iconsets */ +static void +preferences_fill_iconsets(HWND hdlg) +{ + HWND icon_combo = GetDlgItem(hdlg, IDC_COMBO_ICON); + + /* Add the default one */ + wchar_t buffer[512] = L"("; + wcscat(buffer, plat_get_string(IDS_2090)); + wcscat(buffer, L")"); + + SendMessage(icon_combo, CB_RESETCONTENT, 0, 0); + SendMessage(icon_combo, CB_ADDSTRING, 0, (LPARAM)buffer); + SendMessage(icon_combo, CB_SETITEMDATA, 0, (LPARAM)strdup("")); + + int combo_index = -1; + + /* Find for extra ones */ + HANDLE hFind; + WIN32_FIND_DATA data; + + char icon_path_root[512]; + win_get_icons_path(icon_path_root); + + wchar_t search[512]; + mbstoc16s(search, icon_path_root, strlen(icon_path_root) + 1); + wcscat(search, L"*.*"); + + hFind = FindFirstFile((LPCWSTR)search, &data); + + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..") && + (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + wchar_t temp[512] = {0}, dispname[512] = {0}; + mbstoc16s(temp, icon_path_root, strlen(icon_path_root) + 1); + wcscat(temp, data.cFileName); + wcscat(temp, L"\\iconinfo.txt"); + + wcscpy(dispname, data.cFileName); + FILE *fp = _wfopen(temp, L"r"); + if (fp) + { + char line[512] = {0}; + if (fgets(line, 511, fp)) + { + mbstoc16s(dispname, line, strlen(line) + 1); + } + + fclose(fp); + } + + char filename[512]; + c16stombs(filename, data.cFileName, 511); + + int index = SendMessage(icon_combo, CB_ADDSTRING, 0, (LPARAM)dispname); + SendMessage(icon_combo, CB_SETITEMDATA, index, (LPARAM)(strdup(filename))); + + if (!strcmp(filename, icon_set)) + combo_index = index; + } + } while (FindNextFile(hFind, &data)); + FindClose(hFind); + } + + if (combo_index == -1) + { + combo_index = 0; + strcpy(temp_icon_set, ""); + } + + SendMessage(icon_combo, CB_SETCURSEL, combo_index, 0); +} + +/* This returns 1 if any variable has changed, 0 if not. */ +static int +preferences_settings_changed(void) +{ + int i = 0; + + /* Language */ + i = i || has_language_changed(temp_language); + i = i || strcmp(temp_icon_set, icon_set); + + return i; +} + +/* IndexOf by ItemData */ +static int +preferences_indexof(HWND combo, LPARAM itemdata) +{ + int i; + for (i = 0; i < SendMessage(combo, CB_GETCOUNT, 0, 0); i++) + if (SendMessage(combo, CB_GETITEMDATA, i, 0) == itemdata) + return i; + + return -1; +} + +/* This saves the settings back to the global variables. */ +static void +preferences_settings_save(void) +{ + /* Language */ + set_language(temp_language); + + /* Iconset */ + strcpy(icon_set, temp_icon_set); + win_load_icon_set(); + + /* Update title bar */ + update_mouse_msg(); + + /* Update status bar */ + config_changed = 1; + ui_sb_set_ready(-1); + ui_sb_update_panes(); + ui_sb_update_text(); + + /* Save the language changes */ + config_save(); +} + +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +PreferencesDlgProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INITDIALOG: + hwndPreferences = hdlg; + /* Language */ + temp_language = lang_id; + strcpy(temp_icon_set, icon_set); + preferences_fill_languages(hdlg); + preferences_fill_iconsets(hdlg); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (preferences_settings_changed()) + preferences_settings_save(); + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + + case IDC_COMBO_LANG: + if (HIWORD(wParam) == CBN_SELCHANGE) { + HWND combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + int index = SendMessage(combo, CB_GETCURSEL, 0, 0); + temp_language = SendMessage(combo, CB_GETITEMDATA, index, 0); + } + break; + + case IDC_COMBO_ICON: + if (HIWORD(wParam) == CBN_SELCHANGE) { + HWND combo = GetDlgItem(hdlg, IDC_COMBO_ICON); + int index = SendMessage(combo, CB_GETCURSEL, 0, 0); + strcpy(temp_icon_set, (char*)SendMessage(combo, CB_GETITEMDATA, index, 0)); + } + break; + + case IDC_BUTTON_DEFAULT: { + HWND combo = GetDlgItem(hdlg, IDC_COMBO_LANG); + int index = preferences_indexof(combo, DEFAULT_LANGUAGE); + SendMessage(combo, CB_SETCURSEL, index, 0); + temp_language = DEFAULT_LANGUAGE; + break; + } + + case IDC_BUTTON_DEFICON: { + SendMessage(GetDlgItem(hdlg, IDC_COMBO_ICON), CB_SETCURSEL, 0, 0); + strcpy(temp_icon_set, ""); + break; + } + default: + break; + } + break; + + case WM_DESTROY: { + int i; + LRESULT temp; + HWND combo = GetDlgItem(hdlg, IDC_COMBO_ICON); + for (i = 0; i < SendMessage(combo, CB_GETCOUNT, 0, 0); i++) + { + temp = SendMessage(combo, CB_GETITEMDATA, i, 0); + if (temp) + { + free((void*)temp); + SendMessage(combo, CB_SETITEMDATA, i, 0); + } + } + } + break; + + } + + return(FALSE); +} + + +void +PreferencesDlgCreate(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR)DLG_PREFERENCES, hwnd, PreferencesDlgProcedure); +} diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index d80cbe222..ba9f5ba60 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -15,10 +15,10 @@ * * * Authors: Fred N. van Kempen, - * Michael Dr�ing, + * Michael Drüing, * * Copyright 2018-2020 Fred N. van Kempen. - * Copyright 2018-2020 Michael Dr�ing. + * Copyright 2018-2020 Michael Drüing. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -70,24 +70,68 @@ #include <86box/ui.h> #include <86box/win.h> #include <86box/win_sdl.h> +#include <86box/version.h> #define RENDERER_FULL_SCREEN 1 #define RENDERER_HARDWARE 2 +#define RENDERER_OPENGL 4 static SDL_Window *sdl_win = NULL; static SDL_Renderer *sdl_render = NULL; static SDL_Texture *sdl_tex = NULL; static HWND sdl_parent_hwnd = NULL; -static HWND sdl_hwnd = NULL; static int sdl_w, sdl_h; -static int sdl_fs; +static int sdl_fs, sdl_flags = -1; static int cur_w, cur_h; +static int cur_wx = 0, cur_wy = 0, cur_ww =0, cur_wh = 0; static volatile int sdl_enabled = 0; static SDL_mutex* sdl_mutex = NULL; +typedef struct +{ + const void *magic; + Uint32 id; + char *title; + SDL_Surface *icon; + int x, y; + int w, h; + int min_w, min_h; + int max_w, max_h; + Uint32 flags; + Uint32 last_fullscreen_flags; + + /* Stored position and size for windowed mode */ + SDL_Rect windowed; + + SDL_DisplayMode fullscreen_mode; + + float brightness; + Uint16 *gamma; + Uint16 *saved_gamma; /* (just offset into gamma) */ + + SDL_Surface *surface; + SDL_bool surface_valid; + + SDL_bool is_hiding; + SDL_bool is_destroying; + + void *shaper; + + SDL_HitTest hit_test; + void *hit_test_data; + + void *data; + + void *driverdata; + + SDL_Window *prev; + SDL_Window *next; +} SDL_Window_Ex; + + #ifdef ENABLE_SDL_LOG int sdl_do_log = ENABLE_SDL_LOG; @@ -136,6 +180,7 @@ sdl_stretch(int *w, int *h, int *x, int *y) switch (video_fullscreen_scale) { case FULLSCR_SCALE_FULL: + default: *w = sdl_w; *h = sdl_h; *x = 0; @@ -156,8 +201,8 @@ sdl_stretch(int *w, int *h, int *x, int *y) } dx = (hw - dw) / 2.0; dy = (hh - dh) / 2.0; - *w = (int) hw; - *h = (int) hh; + *w = (int) dw; + *h = (int) dh; *x = (int) dx; *y = (int) dy; break; @@ -184,52 +229,73 @@ sdl_stretch(int *w, int *h, int *x, int *y) static void -sdl_blit(int x, int y, int y1, int y2, int w, int h) +sdl_blit(int x, int y, int w, int h, int monitor_index) +{ + SDL_Rect r_src; + int ret; + + if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL) || monitor_index >= 1) { + video_blit_complete_monitor(monitor_index); + return; + } + + SDL_LockMutex(sdl_mutex); + + r_src.x = x; + r_src.y = y; + r_src.w = w; + r_src.h = h; + SDL_UpdateTexture(sdl_tex, &r_src, &(buffer32->line[y][x]), 2048 * sizeof(uint32_t)); + + if (monitors[0].mon_screenshots) + video_screenshot((uint32_t *) buffer32->dat, x, y, 2048); + + video_blit_complete(); + + SDL_RenderClear(sdl_render); + + r_src.x = x; + r_src.y = y; + r_src.w = w; + r_src.h = h; + + ret = SDL_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + if (ret) + sdl_log("SDL: unable to copy texture to renderer (%s)\n", sdl_GetError()); + + SDL_RenderPresent(sdl_render); + SDL_UnlockMutex(sdl_mutex); +} + + +static void +sdl_blit_ex(int x, int y, int w, int h, int monitor_index) { SDL_Rect r_src; void *pixeldata; - int pitch; - int yy, ret; + int pitch, ret; + int row; - if (!sdl_enabled) { - video_blit_complete(); - return; - } - - if ((y1 == y2) || (h <= 0)) { - video_blit_complete(); - return; - } - - if (render_buffer == NULL) { + if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) { video_blit_complete(); return; } SDL_LockMutex(sdl_mutex); - /* - * TODO: - * SDL_UpdateTexture() might be better here, as it is - * (reportedly) slightly faster. - */ SDL_LockTexture(sdl_tex, 0, &pixeldata, &pitch); - for (yy = y1; yy < y2; yy++) { - if ((y + yy) >= 0 && (y + yy) < render_buffer->h) - memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(render_buffer->line[y + yy][x]), w * 4); - } + for (row = 0; row < h; ++row) + video_copy(&(((uint8_t *) pixeldata)[row * 2048 * sizeof(uint32_t)]), &(buffer32->line[y + row][x]), w * sizeof(uint32_t)); - video_blit_complete(); + if (monitors[0].mon_screenshots) + video_screenshot((uint32_t *) pixeldata, 0, 0, 2048); SDL_UnlockTexture(sdl_tex); - if (sdl_fs) { - sdl_log("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); - if (w == unscaled_size_x) - sdl_resize(w, h); - sdl_log("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); - } + video_blit_complete(); + + SDL_RenderClear(sdl_render); r_src.x = 0; r_src.y = 0; @@ -241,14 +307,42 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) sdl_log("SDL: unable to copy texture to renderer (%s)\n", sdl_GetError()); SDL_RenderPresent(sdl_render); - SDL_UnlockMutex(sdl_mutex); } +static void +sdl_destroy_window(void) +{ + if (sdl_win != NULL) { + SDL_DestroyWindow(sdl_win); + sdl_win = NULL; + } +} + + +static void +sdl_destroy_texture(void) +{ + if (sdl_tex != NULL) { + SDL_DestroyTexture(sdl_tex); + sdl_tex = NULL; + } + + /* SDL_DestroyRenderer also automatically destroys all associated textures. */ + if (sdl_render != NULL) { + SDL_DestroyRenderer(sdl_render); + sdl_render = NULL; + } +} + + void sdl_close(void) { + if (sdl_mutex != NULL) + SDL_LockMutex(sdl_mutex); + /* Unregister our renderer! */ video_setblit(NULL); @@ -260,32 +354,10 @@ sdl_close(void) sdl_mutex = NULL; } - if (sdl_tex != NULL) { - SDL_DestroyTexture(sdl_tex); - sdl_tex = NULL; - } - - if (sdl_render != NULL) { - SDL_DestroyRenderer(sdl_render); - sdl_render = NULL; - } - - if (sdl_win != NULL) { - SDL_DestroyWindow(sdl_win); - sdl_win = NULL; - } - - if (sdl_hwnd != NULL) { - plat_set_input(hwndMain); - - ShowWindow(hwndRender, TRUE); - - SetFocus(hwndMain); - - if (sdl_fs) - DestroyWindow(sdl_hwnd); - sdl_hwnd = NULL; - } + sdl_destroy_texture(); + sdl_destroy_window(); + ImmAssociateContext(hwndMain, NULL); + SetFocus(hwndMain); if (sdl_parent_hwnd != NULL) { DestroyWindow(sdl_parent_hwnd); @@ -294,6 +366,7 @@ sdl_close(void) /* Quit. */ SDL_Quit(); + sdl_flags = -1; } @@ -317,13 +390,92 @@ sdl_select_best_hw_driver(void) } +static void +sdl_init_texture(void) +{ + if (sdl_flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + } else + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + + sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); +} + + +static void +sdl_reinit_texture(void) +{ + if (sdl_flags == -1) + return; + + sdl_destroy_texture(); + sdl_init_texture(); +} + + +void +sdl_set_fs(int fs) +{ + int w = 0, h = 0, x = 0, y = 0; + RECT rect; + + SDL_LockMutex(sdl_mutex); + sdl_enabled = 0; + + if (fs) { + ShowWindow(sdl_parent_hwnd, TRUE); + SetParent(hwndRender, sdl_parent_hwnd); + ShowWindow(hwndRender, TRUE); + MoveWindow(sdl_parent_hwnd, 0, 0, sdl_w, sdl_h, TRUE); + + /* Show the window, make it topmost, and give it focus. */ + w = unscaled_size_x; + h = efscrnsz_y; + sdl_stretch(&w, &h, &x, &y); + MoveWindow(hwndRender, x, y, w, h, TRUE); + ImmAssociateContext(sdl_parent_hwnd, NULL); + SetFocus(sdl_parent_hwnd); + + /* Redirect RawInput to this new window. */ + old_capture = mouse_capture; + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + mouse_capture = 1; + } else { + SetParent(hwndRender, hwndMain); + ShowWindow(sdl_parent_hwnd, FALSE); + ShowWindow(hwndRender, TRUE); + ImmAssociateContext(hwndMain, NULL); + SetFocus(hwndMain); + mouse_capture = old_capture; + + if (mouse_capture) { + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + } else + ClipCursor(&oldclip); + } + + sdl_fs = fs; + + if (fs) + sdl_flags |= RENDERER_FULL_SCREEN; + else + sdl_flags &= ~RENDERER_FULL_SCREEN; + + // sdl_reinit_texture(); + sdl_enabled = 1; + SDL_UnlockMutex(sdl_mutex); +} + + static int sdl_init_common(int flags) { wchar_t temp[128]; SDL_version ver; - int w = 0, h = 0, x = 0, y = 0; - RECT rect; sdl_log("SDL: init (fs=%d)\n", fs); @@ -337,123 +489,40 @@ sdl_init_common(int flags) return(0); } - if (flags & RENDERER_HARDWARE) - sdl_select_best_hw_driver(); - - if (flags & RENDERER_FULL_SCREEN) { - /* Get the size of the (current) desktop. */ - sdl_w = GetSystemMetrics(SM_CXSCREEN); - sdl_h = GetSystemMetrics(SM_CYSCREEN); - - /* Create the desktop-covering window. */ - _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); - sdl_parent_hwnd = CreateWindow(SUB_CLASS_NAME, - temp, - WS_POPUP, - 0, 0, sdl_w, sdl_h, - HWND_DESKTOP, - NULL, - hinstance, - NULL); - - SetWindowPos(sdl_parent_hwnd, HWND_TOPMOST, - 0, 0, sdl_w, sdl_h, SWP_SHOWWINDOW); - - /* Create the actual rendering window. */ - _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); - sdl_hwnd = CreateWindow(SUB_CLASS_NAME, - temp, - WS_POPUP, - 0, 0, sdl_w, sdl_h, - sdl_parent_hwnd, - NULL, - hinstance, - NULL); - sdl_log("SDL: FS %dx%d window at %08lx\n", sdl_w, sdl_h, sdl_hwnd); - - /* Redirect RawInput to this new window. */ - plat_set_input(sdl_hwnd); - - SetFocus(sdl_hwnd); - - /* Show the window, make it topmost, and give it focus. */ - w = unscaled_size_x; - h = efscrnsz_y; - sdl_stretch(&w, &h, &x, &y); - SetWindowPos(sdl_hwnd, sdl_parent_hwnd, - x, y, w, h, SWP_SHOWWINDOW); - - /* Now create the SDL window from that. */ - sdl_win = SDL_CreateWindowFrom((void *)sdl_hwnd); - - old_capture = mouse_capture; - - GetWindowRect(sdl_hwnd, &rect); - - ClipCursor(&rect); - - mouse_capture = 1; - } else { - /* Create the SDL window from the render window. */ - sdl_win = SDL_CreateWindowFrom((void *)hwndRender); - - mouse_capture = old_capture; - - if (mouse_capture) { - GetWindowRect(hwndRender, &rect); - - ClipCursor(&rect); - } + if (flags & RENDERER_HARDWARE) { + if (flags & RENDERER_OPENGL) + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "OpenGL"); + else + sdl_select_best_hw_driver(); } + + /* Get the size of the (current) desktop. */ + sdl_w = GetSystemMetrics(SM_CXSCREEN); + sdl_h = GetSystemMetrics(SM_CYSCREEN); + + /* Create the desktop-covering window. */ + _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_FULL_W); + sdl_parent_hwnd = CreateWindow(SDL_CLASS_NAME, temp, WS_POPUP, 0, 0, sdl_w, sdl_h, + HWND_DESKTOP, NULL, hinstance, NULL); + ShowWindow(sdl_parent_hwnd, FALSE); + + sdl_flags = flags; + if (sdl_win == NULL) { sdl_log("SDL: unable to CreateWindowFrom (%s)\n", SDL_GetError()); - sdl_close(); - return(0); } - /* - * TODO: - * SDL_RENDERER_SOFTWARE, because SDL tries to do funky stuff - * otherwise (it turns off Win7 Aero and it looks like it's - * trying to switch to fullscreen even though the window is - * not a fullscreen window?) - */ - if (flags & RENDERER_HARDWARE) { - sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); - } else - sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); - - if (sdl_render == NULL) { - sdl_log("SDL: unable to create renderer (%s)\n", SDL_GetError()); - sdl_close(); - return(0); - } - - /* - * TODO: - * Actually the source is (apparently) XRGB8888, but the alpha - * channel seems to be set to 255 everywhere, so ARGB8888 works - * just as well. - */ - sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, 2048, 2048); - if (sdl_tex == NULL) { - sdl_log("SDL: unable to create texture (%s)\n", SDL_GetError()); - sdl_close(); - return(0); - } + sdl_win = SDL_CreateWindowFrom((void *)hwndRender); + sdl_init_texture(); + sdl_set_fs(video_fullscreen & 1); /* Make sure we get a clean exit. */ atexit(sdl_close); /* Register our renderer! */ - video_setblit(sdl_blit); - - sdl_fs = !!(flags & RENDERER_FULL_SCREEN); + video_setblit((video_grayscale || invert_display) ? sdl_blit_ex : sdl_blit); sdl_enabled = 1; - sdl_mutex = SDL_CreateMutex(); return(1); @@ -475,16 +544,9 @@ sdl_inith(HWND h) int -sdl_inits_fs(HWND h) +sdl_initho(HWND h) { - return sdl_init_common(RENDERER_FULL_SCREEN); -} - - -int -sdl_inith_fs(HWND h) -{ - return sdl_init_common(RENDERER_FULL_SCREEN | RENDERER_HARDWARE); + return sdl_init_common(RENDERER_HARDWARE | RENDERER_OPENGL); } @@ -500,24 +562,68 @@ sdl_resize(int x, int y) { int ww = 0, wh = 0, wx = 0, wy = 0; + if (video_fullscreen & 2) + return; + if ((x == cur_w) && (y == cur_h)) return; + SDL_LockMutex(sdl_mutex); + ww = x; wh = y; if (sdl_fs) { sdl_stretch(&ww, &wh, &wx, &wy); - MoveWindow(sdl_hwnd, wx, wy, ww, wh, TRUE); + MoveWindow(hwndRender, wx, wy, ww, wh, TRUE); } cur_w = x; cur_h = y; + + cur_wx = wx; + cur_wy = wy; + cur_ww = ww; + cur_wh = wh; + + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + SDL_SetWindowPosition(sdl_win, cur_wx, cur_wy); + + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); } void sdl_enable(int enable) { - sdl_enabled = enable; + if (sdl_flags == -1) + return; + + SDL_LockMutex(sdl_mutex); + sdl_enabled = !!enable; + + if (enable == 1) { + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + sdl_reinit_texture(); + } + + SDL_UnlockMutex(sdl_mutex); +} + + +void +sdl_reload(void) +{ + if (sdl_flags & RENDERER_HARDWARE) { + SDL_LockMutex(sdl_mutex); + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_filter_method ? "1" : "0"); + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); + } + + video_setblit((video_grayscale || invert_display) ? sdl_blit_ex : sdl_blit); } diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 8eb444253..227c007b1 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -15,11 +15,14 @@ * * Copyright 2016-2019 Miran Grca. * Copyright 2018,2019 David Hrdlička. + * Copyright 2021 Laci bá' + * Copyright 2021-2022 Jasmine Iwanek. */ #define UNICODE #define BITMAP WINDOWS_BITMAP #include #include +#include #undef BITMAP #ifdef ENABLE_SETTINGS_LOG #include @@ -37,6 +40,7 @@ #include <86box/rom.h> #include <86box/device.h> #include <86box/timer.h> +#include <86box/cassette.h> #include <86box/nvr.h> #include <86box/machine.h> #include <86box/gameport.h> @@ -51,6 +55,7 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/zip.h> +#include <86box/mo.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> @@ -58,11 +63,14 @@ #include <86box/sound.h> #include <86box/midi.h> #include <86box/snd_mpu401.h> +#include <86box/snd_opl.h> #include <86box/video.h> +#include <86box/vid_xga_device.h> #include <86box/plat.h> -#include <86box/plat_midi.h> #include <86box/ui.h> #include <86box/win.h> +#include "../disk/minivhd/minivhd.h" +#include "../disk/minivhd/minivhd_util.h" /* Icon, Bus, File, C, H, S, Size */ @@ -72,32 +80,34 @@ static int first_cat = 0; /* Machine category */ -static int temp_machine_type, temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_fpu, temp_sync; +static int temp_machine_type, temp_machine, temp_cpu, temp_wait_states, temp_fpu, temp_sync; +static cpu_family_t *temp_cpu_f; static uint32_t temp_mem_size; #ifdef USE_DYNAREC static int temp_dynarec; #endif /* Video category */ -static int temp_gfxcard, temp_voodoo; +static int temp_gfxcard, temp_ibm8514, temp_voodoo, temp_xga; /* Input devices category */ static int temp_mouse, temp_joystick; /* Sound category */ -static int temp_sound_card, temp_midi_device, temp_midi_input_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS; -static int temp_float; +static int temp_sound_card, temp_midi_output_device, temp_midi_input_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS; +static int temp_float, temp_fm_driver; /* Network category */ static int temp_net_type, temp_net_card; static char temp_pcap_dev[522]; /* Ports category */ -static int temp_lpt_devices[3]; -static int temp_serial[2], temp_lpt[3]; +static int temp_lpt_devices[PARALLEL_MAX]; +static int temp_serial[SERIAL_MAX], temp_lpt[PARALLEL_MAX]; /* Other peripherals category */ -static int temp_fdc_card, temp_hdc, temp_scsi_card, temp_ide_ter, temp_ide_qua; +static int temp_fdc_card, temp_hdc, temp_ide_ter, temp_ide_qua, temp_cassette; +static int temp_scsi_card[SCSI_BUS_MAX]; static int temp_bugger; static int temp_postcard; static int temp_isartc; @@ -116,21 +126,21 @@ static int temp_fdd_check_bpb[FDD_NUM]; /* Other removable devices category */ static cdrom_t temp_cdrom[CDROM_NUM]; static zip_drive_t temp_zip_drives[ZIP_NUM]; +static mo_drive_t temp_mo_drives[MO_NUM]; static HWND hwndParentDialog, hwndChildDialog; static uint32_t displayed_category = 0; extern int is486; -static int listtomachinetype[256], machinetypetolist[256]; -static int listtomachine[256], machinetolist[256]; -static int settings_device_to_list[2][20], settings_list_to_device[2][20]; -static int settings_fdc_to_list[2][20], settings_list_to_fdc[2][20]; -static int settings_midi_to_list[20], settings_list_to_midi[20]; -static int settings_midi_in_to_list[20], settings_list_to_midi_in[20]; +static int listtomachinetype[256], listtomachine[256]; +static int listtocpufamily[256], listtocpu[256]; +static int settings_list_to_device[2][256], settings_list_to_fdc[20]; +static int settings_list_to_midi[20], settings_list_to_midi_in[20]; +static int settings_list_to_hdc[20]; static int max_spt = 63, max_hpc = 255, max_tracks = 266305; -static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[2]; +static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[8]; static uint64_t size; static int hd_listview_items, hdc_id_to_listview_index[HDD_NUM]; static int no_update = 0, existing = 0, chs_enabled = 0; @@ -141,31 +151,123 @@ static int spt, hpc, tracks, ignore_change = 0; static hard_disk_t new_hdd, *hdd_ptr; static wchar_t hd_file_name[512]; +static WCHAR device_name[512]; + + +static int +settings_get_check(HWND hdlg, int id) +{ + return SendMessage(GetDlgItem(hdlg, id), BM_GETCHECK, 0, 0); +} + + +static int +settings_get_cur_sel(HWND hdlg, int id) +{ + return SendMessage(GetDlgItem(hdlg, id), CB_GETCURSEL, 0, 0); +} + + +static void +settings_set_check(HWND hdlg, int id, int val) +{ + SendMessage(GetDlgItem(hdlg, id), BM_SETCHECK, val, 0); +} + + +static void +settings_set_cur_sel(HWND hdlg, int id, int val) +{ + SendMessage(GetDlgItem(hdlg, id), CB_SETCURSEL, val, 0); +} + + +static void +settings_reset_content(HWND hdlg, int id) +{ + SendMessage(GetDlgItem(hdlg, id), CB_RESETCONTENT, 0, 0); +} + + +static void +settings_add_string(HWND hdlg, int id, LPARAM string) +{ + SendMessage(GetDlgItem(hdlg, id), CB_ADDSTRING, 0, string); +} + + +static void +settings_enable_window(HWND hdlg, int id, int condition) +{ + EnableWindow(GetDlgItem(hdlg, id), condition ? TRUE : FALSE); +} + + +static void +settings_show_window(HWND hdlg, int id, int condition) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + EnableWindow(h, condition ? TRUE : FALSE); + ShowWindow(h, condition ? SW_SHOW : SW_HIDE); +} + + +static void +settings_listview_enable_styles(HWND hdlg, int id) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + SetWindowTheme(h, L"Explorer", NULL); + ListView_SetExtendedListViewStyle(h, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); +} + + +static void +settings_listview_select(HWND hdlg, int id, int selection) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + ListView_SetItemState(h, selection, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); +} + + +static void +settings_process_messages() +{ + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} static BOOL -image_list_init(HWND hwndList, const uint8_t *icon_ids) +image_list_init(HWND hdlg, int id, const uint8_t *icon_ids) { HICON hiconItem; HIMAGELIST hSmall; + HWND hwndList = GetDlgItem(hdlg, id); int i = 0; - hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), + hSmall = ListView_GetImageList(hwndList, LVSIL_SMALL); + if (hSmall != 0) ImageList_Destroy(hSmall); + + hSmall = ImageList_Create(win_get_system_metrics(SM_CXSMICON, dpi), + win_get_system_metrics(SM_CYSMICON, dpi), ILC_MASK | ILC_COLOR32, 1, 1); while(1) { if (icon_ids[i] == 0) break; -#if defined(__amd64__) || defined(__aarch64__) - hiconItem = LoadIcon(hinstance, (LPCWSTR) ((uint64_t) icon_ids[i])); -#else - hiconItem = LoadIcon(hinstance, (LPCWSTR) ((uint32_t) icon_ids[i])); -#endif + hiconItem = hIcon[icon_ids[i]]; ImageList_AddIcon(hSmall, hiconItem); - DestroyIcon(hiconItem); i++; } @@ -218,9 +320,9 @@ win_settings_init(void) int i = 0; /* Machine category */ - temp_machine_type = machines[machine].type; + temp_machine_type = machine_get_type(machine); temp_machine = machine; - temp_cpu_m = cpu_manufacturer; + temp_cpu_f = cpu_f; temp_wait_states = cpu_waitstates; temp_cpu = cpu; temp_mem_size = mem_size; @@ -233,6 +335,8 @@ win_settings_init(void) /* Video category */ temp_gfxcard = gfxcard; temp_voodoo = voodoo_enabled; + temp_ibm8514 = ibm8514_enabled; + temp_xga = xga_enabled; /* Input devices category */ temp_mouse = mouse_type; @@ -240,13 +344,14 @@ win_settings_init(void) /* Sound category */ temp_sound_card = sound_card_current; - temp_midi_device = midi_device_current; - temp_midi_input_device = midi_input_device_current; + temp_midi_output_device = midi_output_device_current; + temp_midi_input_device = midi_input_device_current; temp_mpu401 = mpu401_standalone_enable; temp_SSI2001 = SSI2001; temp_GAMEBLASTER = GAMEBLASTER; temp_GUS = GUS; temp_float = sound_is_float; + temp_fm_driver = fm_driver; /* Network category */ temp_net_type = network_type; @@ -258,29 +363,24 @@ win_settings_init(void) temp_net_card = network_card; /* Ports category */ - for (i = 0; i < 3; i++) { + for (i = 0; i < PARALLEL_MAX; i++) { temp_lpt_devices[i] = lpt_ports[i].device; temp_lpt[i] = lpt_ports[i].enabled; } - for (i = 0; i < 2; i++) + for (i = 0; i < SERIAL_MAX; i++) temp_serial[i] = serial_enabled[i]; - /* Other peripherals category */ - temp_scsi_card = scsi_card_current; + /* Storage devices category */ + for (i = 0; i < SCSI_BUS_MAX; i++) + temp_scsi_card[i] = scsi_card_current[i]; temp_fdc_card = fdc_type; temp_hdc = hdc_current; temp_ide_ter = ide_ter_enabled; temp_ide_qua = ide_qua_enabled; - temp_bugger = bugger_enabled; - temp_postcard = postcard_enabled; - temp_isartc = isartc_type; - - /* ISA memory boards. */ - for (i = 0; i < ISAMEM_MAX; i++) - temp_isamem[i] = isamem_type[i]; - + temp_cassette = cassette_enable; + mfm_tracking = xta_tracking = esdi_tracking = ide_tracking = 0; - for (i = 0; i < 2; i++) + for (i = 0; i < 8; i++) scsi_tracking[i] = 0; /* Hard disks category */ @@ -292,12 +392,12 @@ win_settings_init(void) xta_tracking |= (1 << (hdd[i].xta_channel << 3)); else if (hdd[i].bus == HDD_BUS_ESDI) esdi_tracking |= (1 << (hdd[i].esdi_channel << 3)); - else if (hdd[i].bus == HDD_BUS_IDE) + else if ((hdd[i].bus == HDD_BUS_IDE) || (hdd[i].bus == HDD_BUS_ATAPI)) ide_tracking |= (1 << (hdd[i].ide_channel << 3)); else if (hdd[i].bus == HDD_BUS_SCSI) scsi_tracking[hdd[i].scsi_id >> 3] |= (1 << ((hdd[i].scsi_id & 0x07) << 3)); - } - + } + /* Floppy drives category */ for (i = 0; i < FDD_NUM; i++) { temp_fdd_types[i] = fdd_get_type(i); @@ -320,6 +420,22 @@ win_settings_init(void) else if (zip_drives[i].bus_type == ZIP_BUS_SCSI) scsi_tracking[zip_drives[i].scsi_device_id >> 3] |= (1 << ((zip_drives[i].scsi_device_id & 0x07) << 3)); } + memcpy(temp_mo_drives, mo_drives, MO_NUM * sizeof(mo_drive_t)); + for (i = 0; i < MO_NUM; i++) { + if (mo_drives[i].bus_type == MO_BUS_ATAPI) + ide_tracking |= (1 << (mo_drives[i].ide_channel << 3)); + else if (mo_drives[i].bus_type == MO_BUS_SCSI) + scsi_tracking[mo_drives[i].scsi_device_id >> 3] |= (1 << ((mo_drives[i].scsi_device_id & 0x07) << 3)); + } + + /* Other peripherals category */ + temp_bugger = bugger_enabled; + temp_postcard = postcard_enabled; + temp_isartc = isartc_type; + + /* ISA memory boards. */ + for (i = 0; i < ISAMEM_MAX; i++) + temp_isamem[i] = isamem_type[i]; temp_deviceconfig = 0; } @@ -329,12 +445,11 @@ win_settings_init(void) static int win_settings_changed(void) { - int i = 0; - int j = 0; + int i = 0, j = 0; /* Machine category */ i = i || (machine != temp_machine); - i = i || (cpu_manufacturer != temp_cpu_m); + i = i || (cpu_f != temp_cpu_f); i = i || (cpu_waitstates != temp_wait_states); i = i || (cpu != temp_cpu); i = i || (mem_size != temp_mem_size); @@ -347,6 +462,8 @@ win_settings_changed(void) /* Video category */ i = i || (gfxcard != temp_gfxcard); i = i || (voodoo_enabled != temp_voodoo); + i = i || (ibm8514_enabled != temp_ibm8514); + i = i || (xga_enabled != temp_xga); /* Input devices category */ i = i || (mouse_type != temp_mouse); @@ -354,13 +471,14 @@ win_settings_changed(void) /* Sound category */ i = i || (sound_card_current != temp_sound_card); - i = i || (midi_device_current != temp_midi_device); - i = i || (midi_input_device_current != temp_midi_input_device); + i = i || (midi_output_device_current != temp_midi_output_device); + i = i || (midi_input_device_current != temp_midi_input_device); i = i || (mpu401_standalone_enable != temp_mpu401); i = i || (SSI2001 != temp_SSI2001); i = i || (GAMEBLASTER != temp_GAMEBLASTER); i = i || (GUS != temp_GUS); i = i || (sound_is_float != temp_float); + i = i || (fm_driver != temp_fm_driver); /* Network category */ i = i || (network_type != temp_net_type); @@ -368,27 +486,22 @@ win_settings_changed(void) i = i || (network_card != temp_net_card); /* Ports category */ - for (j = 0; j < 3; j++) { + for (j = 0; j < PARALLEL_MAX; j++) { i = i || (temp_lpt_devices[j] != lpt_ports[j].device); i = i || (temp_lpt[j] != lpt_ports[j].enabled); } - for (j = 0; j < 2; j++) + for (j = 0; j < SERIAL_MAX; j++) i = i || (temp_serial[j] != serial_enabled[j]); - /* Peripherals category */ - i = i || (scsi_card_current != temp_scsi_card); + /* Storage devices category */ + for (j = 0; j < SCSI_BUS_MAX; j++) + i = i || (temp_scsi_card[j] != scsi_card_current[j]); i = i || (fdc_type != temp_fdc_card); i = i || (hdc_current != temp_hdc); i = i || (temp_ide_ter != ide_ter_enabled); i = i || (temp_ide_qua != ide_qua_enabled); - i = i || (temp_bugger != bugger_enabled); - i = i || (temp_postcard != postcard_enabled); - i = i || (temp_isartc != isartc_type); + i = i || (temp_cassette != cassette_enable); - /* ISA memory boards. */ - for (j = 0; j < ISAMEM_MAX; j++) - i = i || (temp_isamem[j] != isamem_type[j]); - /* Hard disks category */ i = i || memcmp(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); @@ -402,6 +515,16 @@ win_settings_changed(void) /* Other removable devices category */ i = i || memcmp(cdrom, temp_cdrom, CDROM_NUM * sizeof(cdrom_t)); i = i || memcmp(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + i = i || memcmp(mo_drives, temp_mo_drives, MO_NUM * sizeof(mo_drive_t)); + + /* Other peripherals category */ + i = i || (temp_bugger != bugger_enabled); + i = i || (temp_postcard != postcard_enabled); + i = i || (temp_isartc != isartc_type); + + /* ISA memory boards. */ + for (j = 0; j < ISAMEM_MAX; j++) + i = i || (temp_isamem[j] != isamem_type[j]); i = i || !!temp_deviceconfig; @@ -409,32 +532,6 @@ win_settings_changed(void) } -static int -settings_msgbox_reset(void) -{ - int changed, i = 0; - HWND h; - - changed = win_settings_changed(); - - if (changed) { - h = hwndMain; - hwndMain = hwndParentDialog; - - i = ui_msgbox_ex(MBX_QUESTION | MBX_LINKS, (wchar_t *) IDS_2051, NULL, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123); - - hwndMain = h; - - if (i == 1) return(1); /* no */ - - if (i == -1) return(0); /* cancel */ - - return(2); /* yes */ - } else - return(1); -} - - /* This saves the settings back to the global variables. */ static void win_settings_save(void) @@ -445,7 +542,7 @@ win_settings_save(void) /* Machine category */ machine = temp_machine; - cpu_manufacturer = temp_cpu_m; + cpu_f = temp_cpu_f; cpu_waitstates = temp_wait_states; cpu = temp_cpu; mem_size = temp_mem_size; @@ -458,6 +555,8 @@ win_settings_save(void) /* Video category */ gfxcard = temp_gfxcard; voodoo_enabled = temp_voodoo; + ibm8514_enabled = temp_ibm8514; + xga_enabled = temp_xga; /* Input devices category */ mouse_type = temp_mouse; @@ -465,13 +564,14 @@ win_settings_save(void) /* Sound category */ sound_card_current = temp_sound_card; - midi_device_current = temp_midi_device; - midi_input_device_current = temp_midi_input_device; + midi_output_device_current = temp_midi_output_device; + midi_input_device_current = temp_midi_input_device; mpu401_standalone_enable = temp_mpu401; SSI2001 = temp_SSI2001; GAMEBLASTER = temp_GAMEBLASTER; GUS = temp_GUS; sound_is_float = temp_float; + fm_driver = temp_fm_driver; /* Network category */ network_type = temp_net_type; @@ -480,27 +580,22 @@ win_settings_save(void) network_card = temp_net_card; /* Ports category */ - for (i = 0; i < 3; i++) { + for (i = 0; i < PARALLEL_MAX; i++) { lpt_ports[i].device = temp_lpt_devices[i]; lpt_ports[i].enabled = temp_lpt[i]; } - for (i = 0; i < 2; i++) + for (i = 0; i < SERIAL_MAX; i++) serial_enabled[i] = temp_serial[i]; - /* Peripherals category */ - scsi_card_current = temp_scsi_card; + /* Storage devices category */ + for (i = 0; i < SCSI_BUS_MAX; i++) + scsi_card_current[i] = temp_scsi_card[i]; hdc_current = temp_hdc; fdc_type = temp_fdc_card; ide_ter_enabled = temp_ide_ter; ide_qua_enabled = temp_ide_qua; - bugger_enabled = temp_bugger; - postcard_enabled = temp_postcard; - isartc_type = temp_isartc; + cassette_enable = temp_cassette; - /* ISA memory boards. */ - for (i = 0; i < ISAMEM_MAX; i++) - isamem_type[i] = temp_isamem[i]; - /* Hard disks category */ memcpy(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); for (i = 0; i < HDD_NUM; i++) @@ -530,9 +625,23 @@ win_settings_save(void) zip_drives[i].f = NULL; zip_drives[i].priv = NULL; } + memcpy(mo_drives, temp_mo_drives, MO_NUM * sizeof(mo_drive_t)); + for (i = 0; i < MO_NUM; i++) { + mo_drives[i].f = NULL; + mo_drives[i].priv = NULL; + } + + /* Other peripherals category */ + bugger_enabled = temp_bugger; + postcard_enabled = temp_postcard; + isartc_type = temp_isartc; + + /* ISA memory boards. */ + for (i = 0; i < ISAMEM_MAX; i++) + isamem_type[i] = temp_isamem[i]; /* Mark configuration as changed. */ - config_changed = 1; + config_changed = 2; pc_reset_hard_init(); } @@ -541,56 +650,47 @@ win_settings_save(void) static void win_settings_machine_recalc_fpu(HWND hdlg) { - HWND h; int c, type; LPTSTR lptsTemp; const char *stransi; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_FPU); - SendMessage(h, CB_RESETCONTENT, 0, 0); + settings_reset_content(hdlg, IDC_COMBO_FPU); c = 0; while (1) { - stransi = (char *) fpu_get_name_from_index(temp_machine, temp_cpu_m, temp_cpu, c); - type = fpu_get_type_from_index(temp_machine, temp_cpu_m, temp_cpu, c); + stransi = (char *) fpu_get_name_from_index(temp_cpu_f, temp_cpu, c); + type = fpu_get_type_from_index(temp_cpu_f, temp_cpu, c); if (!stransi) break; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + settings_add_string(hdlg, IDC_COMBO_FPU, (LPARAM)(LPCSTR)lptsTemp); if (!c || (type == temp_fpu)) - SendMessage(h, CB_SETCURSEL, c, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_FPU, c); c++; } - if (c > 1) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + settings_enable_window(hdlg, IDC_COMBO_FPU, c > 1); + + temp_fpu = fpu_get_type_from_index(temp_cpu_f, temp_cpu, settings_get_cur_sel(hdlg, IDC_COMBO_FPU)); } static void win_settings_machine_recalc_cpu(HWND hdlg) { - HWND h; int cpu_type; #ifdef USE_DYNAREC int cpu_flags; #endif - h = GetDlgItem(hdlg, IDC_COMBO_WS); - cpu_type = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + cpu_type = temp_cpu_f->cpus[temp_cpu].cpu_type; + settings_enable_window(hdlg, IDC_COMBO_WS, (cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)); #ifdef USE_DYNAREC - h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); - cpu_flags = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + cpu_flags = temp_cpu_f->cpus[temp_cpu].cpu_flags; if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) { @@ -598,10 +698,12 @@ win_settings_machine_recalc_cpu(HWND hdlg) temp_dynarec = 0; if (cpu_flags & CPU_REQUIRES_DYNAREC) temp_dynarec = 1; - SendMessage(h, BM_SETCHECK, temp_dynarec, 0); - EnableWindow(h, FALSE); - } else - EnableWindow(h, TRUE); + settings_set_check(hdlg, IDC_CHECK_DYNAREC, temp_dynarec); + settings_enable_window(hdlg, IDC_CHECK_DYNAREC, FALSE); + } else { + settings_set_check(hdlg, IDC_CHECK_DYNAREC, temp_dynarec); + settings_enable_window(hdlg, IDC_CHECK_DYNAREC, TRUE); + } #endif win_settings_machine_recalc_fpu(hdlg); @@ -611,26 +713,39 @@ win_settings_machine_recalc_cpu(HWND hdlg) static void win_settings_machine_recalc_cpu_m(HWND hdlg) { - HWND h; - int c; + int c, i, first_eligible = -1, current_eligible = 0, last_eligible = 0; LPTSTR lptsTemp; char *stransi; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_CPU); - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = 0; - while (machines[temp_machine].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { - stransi = (char *) machines[temp_machine].cpu[temp_cpu_m].cpus[c].name; - mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + settings_reset_content(hdlg, IDC_COMBO_CPU_SPEED); + c = i = 0; + while (temp_cpu_f->cpus[c].cpu_type != 0) { + if (cpu_is_eligible(temp_cpu_f, c, temp_machine)) { + stransi = (char *) temp_cpu_f->cpus[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + settings_add_string(hdlg, IDC_COMBO_CPU_SPEED, (LPARAM)(LPCSTR)lptsTemp); + + if (first_eligible == -1) + first_eligible = i; + if (temp_cpu == c) + current_eligible = i; + last_eligible = i; + + listtocpu[i++] = c; + } c++; } - EnableWindow(h, TRUE); - if (temp_cpu >= c) - temp_cpu = (c - 1); - SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + if (i == 0) + fatal("No eligible CPUs for the selected family\n"); + settings_enable_window(hdlg, IDC_COMBO_CPU_SPEED, i != 1); + if (current_eligible < first_eligible) + current_eligible = first_eligible; + else if (current_eligible > last_eligible) + current_eligible = last_eligible; + temp_cpu = listtocpu[current_eligible]; + settings_set_cur_sel(hdlg, IDC_COMBO_CPU_SPEED, current_eligible); win_settings_machine_recalc_cpu(hdlg); @@ -642,57 +757,109 @@ static void win_settings_machine_recalc_machine(HWND hdlg) { HWND h; - int c; + int c, i, current_eligible; LPTSTR lptsTemp; - const char *stransi; + char *stransi; UDACCEL accel; device_t *d; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); d = (device_t *) machine_getdevice(temp_machine); - if (d && d->config) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + settings_enable_window(hdlg, IDC_CONFIGURE_MACHINE, d && d->config); - h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = 0; - while (machines[temp_machine].cpu[c].cpus != NULL && c < 4) { - stransi = machines[temp_machine].cpu[c].name; - mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + settings_reset_content(hdlg, IDC_COMBO_CPU_TYPE); + c = i = 0; + current_eligible = -1; + while (cpu_families[c].package != 0) { + if (cpu_family_is_eligible(&cpu_families[c], temp_machine)) { + stransi = malloc(strlen((char *) cpu_families[c].manufacturer) + strlen((char *) cpu_families[c].name) + 2); + sprintf(stransi, "%s %s", (char *) cpu_families[c].manufacturer, (char *) cpu_families[c].name); + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + free(stransi); + settings_add_string(hdlg, IDC_COMBO_CPU_TYPE, (LPARAM)(LPCSTR)lptsTemp); + if (&cpu_families[c] == temp_cpu_f) + current_eligible = i; + listtocpufamily[i++] = c; + } c++; } - EnableWindow(h, TRUE); - if (temp_cpu_m >= c) - temp_cpu_m = (c - 1); - SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); - EnableWindow(h, (c == 1) ? FALSE : TRUE); + if (i == 0) + fatal("No eligible CPU families for the selected machine\n"); + settings_enable_window(hdlg, IDC_COMBO_CPU_TYPE, TRUE); + if (current_eligible == -1) { + temp_cpu_f = (cpu_family_t *) &cpu_families[listtocpufamily[0]]; + settings_set_cur_sel(hdlg, IDC_COMBO_CPU_TYPE, 0); + } else { + settings_set_cur_sel(hdlg, IDC_COMBO_CPU_TYPE, current_eligible); + } + settings_enable_window(hdlg, IDC_COMBO_CPU_TYPE, i != 1); win_settings_machine_recalc_cpu_m(hdlg); - h = GetDlgItem(hdlg, IDC_MEMSPIN); - SendMessage(h, UDM_SETRANGE, 0, (machines[temp_machine].min_ram << 16) | machines[temp_machine].max_ram); - accel.nSec = 0; - accel.nInc = machines[temp_machine].ram_granularity; - SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); - if (!(machines[temp_machine].flags & MACHINE_AT) || (machines[temp_machine].ram_granularity >= 128)) { + if (machine_get_ram_granularity(temp_machine) & 1023) { + /* KB granularity */ + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (machine_get_min_ram(temp_machine) << 16) | machine_get_max_ram(temp_machine)); + + accel.nSec = 0; + accel.nInc = machine_get_ram_granularity(temp_machine); + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + SendMessage(h, UDM_SETPOS, 0, temp_mem_size); + h = GetDlgItem(hdlg, IDC_TEXT_MB); SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2088)); } else { - SendMessage(h, UDM_SETPOS, 0, temp_mem_size / 1024); + /* MB granularity */ + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (machine_get_min_ram(temp_machine) << 6) | (machine_get_max_ram(temp_machine) >> 10)); + + accel.nSec = 0; + accel.nInc = machine_get_ram_granularity(temp_machine) >> 10; + + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + + SendMessage(h, UDM_SETPOS, 0, temp_mem_size >> 10); + h = GetDlgItem(hdlg, IDC_TEXT_MB); SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2086)); } + settings_enable_window(hdlg, IDC_MEMSPIN, machine_get_min_ram(temp_machine) != machine_get_max_ram(temp_machine)); + settings_enable_window(hdlg, IDC_MEMTEXT, machine_get_min_ram(temp_machine) != machine_get_max_ram(temp_machine)); + free(lptsTemp); } +static char * +machine_type_get_internal_name(int id) +{ + if (id < MACHINE_TYPE_MAX) + return ""; + else + return NULL; +} + + +int +machine_type_available(int id) +{ + int c = 0; + + if ((id > 0) && (id < MACHINE_TYPE_MAX)) { + while (machine_get_internal_name_ex(c) != NULL) { + if (machine_available(c) && (machine_get_type(c) == id)) + return 1; + c++; + } + } + + return 0; +} + + #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else @@ -701,7 +868,7 @@ static BOOL CALLBACK win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h, h2; - int c, d, e, f; + int c, d; int old_machine_type; LPTSTR lptsTemp; char *stransi; @@ -710,83 +877,61 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_INITDIALOG: lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_MACHINE_TYPE); - f = 0; - memset(machinetypetolist, 0x00, sizeof(machinetypetolist)); + c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_MACHINE_TYPE); memset(listtomachinetype, 0x00, sizeof(listtomachinetype)); - for (c = 1; c < MACHINE_TYPE_MAX; c++) { - d = e = 0; - while (machine_get_internal_name_ex(d) != NULL) { - if (machine_available(d) && (machines[d].type == c)) - e++; - d++; - } - - if (e > 0) { + while (machine_type_get_internal_name(c) != NULL) { + if (machine_type_available(c)) { stransi = (char *)machine_types[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - machinetypetolist[c] = f; - listtomachinetype[f] = c; - f++; - } - } - SendMessage(h, CB_SETCURSEL, machinetypetolist[temp_machine_type], 0); - - h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); - c = d = 0; - memset(machinetolist, 0x00, sizeof(machinetolist)); - memset(listtomachine, 0x00, sizeof(listtomachine)); - while (machine_get_internal_name_ex(c) != NULL) { - if (machine_available(c) && (machines[c].type == temp_machine_type)) { - stransi = (char *)machines[c].name; - mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - machinetolist[c] = d; - listtomachine[d] = c; + settings_add_string(hdlg, IDC_COMBO_MACHINE_TYPE, (LPARAM) lptsTemp); + listtomachinetype[d] = c; + if (c == temp_machine_type) + settings_set_cur_sel(hdlg, IDC_COMBO_MACHINE_TYPE, d); d++; } c++; } - SendMessage(h, CB_SETCURSEL, machinetolist[temp_machine], 0); - h = GetDlgItem(hdlg, IDC_COMBO_WS); - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2090)); - - for (c = 0; c < 8; c++) { - wsprintf(lptsTemp, plat_get_string(IDS_2091), c); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_MACHINE); + memset(listtomachine, 0x00, sizeof(listtomachine)); + while (machine_get_internal_name_ex(c) != NULL) { + if (machine_available(c) && (machine_get_type(c) == temp_machine_type)) { + stransi = machine_getname_ex(c); + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + settings_add_string(hdlg, IDC_COMBO_MACHINE, (LPARAM) lptsTemp); + listtomachine[d] = c; + if (c == temp_machine) + settings_set_cur_sel(hdlg, IDC_COMBO_MACHINE, d); + d++; + } + c++; } - SendMessage(h, CB_SETCURSEL, temp_wait_states, 0); + settings_add_string(hdlg, IDC_COMBO_WS, win_get_string(IDS_2090)); + for (c = 0; c < 8; c++) { + wsprintf(lptsTemp, plat_get_string(IDS_2091), c); + settings_add_string(hdlg, IDC_COMBO_WS, (LPARAM) lptsTemp); + } + + settings_set_cur_sel(hdlg, IDC_COMBO_WS, temp_wait_states); #ifdef USE_DYNAREC - h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); - SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + settings_set_check(hdlg, IDC_CHECK_DYNAREC, 0); #endif h = GetDlgItem(hdlg, IDC_MEMSPIN); h2 = GetDlgItem(hdlg, IDC_MEMTEXT); SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); - if (temp_sync & TIME_SYNC_ENABLED) - { + if (temp_sync & TIME_SYNC_ENABLED) { if (temp_sync & TIME_SYNC_UTC) - { - h=GetDlgItem(hdlg, IDC_RADIO_TS_UTC); - SendMessage(h, BM_SETCHECK, BST_CHECKED, 0); - } + settings_set_check(hdlg, IDC_RADIO_TS_UTC, BST_CHECKED); else - { - h=GetDlgItem(hdlg, IDC_RADIO_TS_LOCAL); - SendMessage(h, BM_SETCHECK, BST_CHECKED, 0); - } - } - else - { - h=GetDlgItem(hdlg, IDC_RADIO_TS_DISABLED); - SendMessage(h, BM_SETCHECK, BST_CHECKED, 0); - } + settings_set_check(hdlg, IDC_RADIO_TS_LOCAL, BST_CHECKED); + } else + settings_set_check(hdlg, IDC_RADIO_TS_DISABLED, BST_CHECKED); win_settings_machine_recalc_machine(hdlg); @@ -795,76 +940,66 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_COMBO_MACHINE_TYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) { - h = GetDlgItem(hdlg, IDC_COMBO_MACHINE_TYPE); + switch (LOWORD(wParam)) { + case IDC_COMBO_MACHINE_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) { old_machine_type = temp_machine_type; - temp_machine_type = listtomachinetype[SendMessage(h,CB_GETCURSEL,0,0)]; + temp_machine_type = listtomachinetype[settings_get_cur_sel(hdlg, IDC_COMBO_MACHINE_TYPE)]; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); - SendMessage(h, CB_RESETCONTENT, 0, 0); + settings_reset_content(hdlg, IDC_COMBO_MACHINE); c = d = 0; - memset(machinetolist, 0x00, sizeof(machinetolist)); memset(listtomachine, 0x00, sizeof(listtomachine)); while (machine_get_internal_name_ex(c) != NULL) { - if (machine_available(c) && (machines[c].type == temp_machine_type)) { - stransi = (char *)machines[c].name; + if (machine_available(c) && (machine_get_type(c) == temp_machine_type)) { + stransi = machine_getname_ex(c); mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - machinetolist[c] = d; + settings_add_string(hdlg, IDC_COMBO_MACHINE, (LPARAM) lptsTemp); listtomachine[d] = c; + if (c == temp_machine) + settings_set_cur_sel(hdlg, IDC_COMBO_MACHINE, d); d++; } c++; } - if (old_machine_type == temp_machine_type) - SendMessage(h, CB_SETCURSEL, machinetolist[temp_machine], 0); - else { - SendMessage(h, CB_SETCURSEL, 0, 0); + if (old_machine_type != temp_machine_type) { + settings_set_cur_sel(hdlg, IDC_COMBO_MACHINE, 0); temp_machine = listtomachine[0]; win_settings_machine_recalc_machine(hdlg); } + + free(lptsTemp); } break; - case IDC_COMBO_MACHINE: - if (HIWORD(wParam) == CBN_SELCHANGE) { - h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); - temp_machine = listtomachine[SendMessage(h,CB_GETCURSEL,0,0)]; - + case IDC_COMBO_MACHINE: + if (HIWORD(wParam) == CBN_SELCHANGE) { + temp_machine = listtomachine[settings_get_cur_sel(hdlg, IDC_COMBO_MACHINE)]; win_settings_machine_recalc_machine(hdlg); } break; case IDC_COMBO_CPU_TYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) { - h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); - temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); - + if (HIWORD(wParam) == CBN_SELCHANGE) { + temp_cpu_f = (cpu_family_t *) &cpu_families[listtocpufamily[settings_get_cur_sel(hdlg, IDC_COMBO_CPU_TYPE)]]; temp_cpu = 0; win_settings_machine_recalc_cpu_m(hdlg); } break; - case IDC_COMBO_CPU: - if (HIWORD(wParam) == CBN_SELCHANGE) { - h = GetDlgItem(hdlg, IDC_COMBO_CPU); - temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); - + case IDC_COMBO_CPU_SPEED: + if (HIWORD(wParam) == CBN_SELCHANGE) { + temp_cpu = listtocpu[settings_get_cur_sel(hdlg, IDC_COMBO_CPU_SPEED)]; win_settings_machine_recalc_cpu(hdlg); } break; case IDC_COMBO_FPU: - if (HIWORD(wParam) == CBN_SELCHANGE) { - h = GetDlgItem(hdlg, IDC_COMBO_FPU); - temp_fpu = fpu_get_type_from_index(temp_machine, temp_cpu_m, temp_cpu, SendMessage(h, CB_GETCURSEL, 0, 0)); + if (HIWORD(wParam) == CBN_SELCHANGE) { + temp_fpu = fpu_get_type_from_index(temp_cpu_f, temp_cpu, + settings_get_cur_sel(hdlg, IDC_COMBO_FPU)); } break; case IDC_CONFIGURE_MACHINE: - h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); - temp_machine = listtomachine[SendMessage(h, CB_GETCURSEL, 0, 0)]; - + temp_machine = listtomachine[settings_get_cur_sel(hdlg, IDC_COMBO_MACHINE)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)machine_getdevice(temp_machine)); break; } @@ -876,36 +1011,31 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) stransi = (char *)malloc(512); #ifdef USE_DYNAREC - h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); - temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + temp_dynarec = settings_get_check(hdlg, IDC_CHECK_DYNAREC); #endif - h=GetDlgItem(hdlg, IDC_RADIO_TS_DISABLED); - if(SendMessage(h, BM_GETCHECK, 0, 0)) + if (settings_get_check(hdlg, IDC_RADIO_TS_DISABLED)) temp_sync = TIME_SYNC_DISABLED; - h=GetDlgItem(hdlg, IDC_RADIO_TS_LOCAL); - if(SendMessage(h, BM_GETCHECK, 0, 0)) + if (settings_get_check(hdlg, IDC_RADIO_TS_LOCAL)) temp_sync = TIME_SYNC_ENABLED; - h=GetDlgItem(hdlg, IDC_RADIO_TS_UTC); - if(SendMessage(h, BM_GETCHECK, 0, 0)) + if (settings_get_check(hdlg, IDC_RADIO_TS_UTC)) temp_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; - h = GetDlgItem(hdlg, IDC_COMBO_WS); - temp_wait_states = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_wait_states = settings_get_cur_sel(hdlg, IDC_COMBO_WS); h = GetDlgItem(hdlg, IDC_MEMTEXT); SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); wcstombs(stransi, lptsTemp, 512); sscanf(stransi, "%u", &temp_mem_size); - temp_mem_size &= ~(machines[temp_machine].ram_granularity - 1); - if (temp_mem_size < machines[temp_machine].min_ram) - temp_mem_size = machines[temp_machine].min_ram; - else if (temp_mem_size > machines[temp_machine].max_ram) - temp_mem_size = machines[temp_machine].max_ram; - if ((machines[temp_machine].flags & MACHINE_AT) && (machines[temp_machine].ram_granularity < 128)) - temp_mem_size *= 1024; + if (!(machine_get_ram_granularity(temp_machine) & 1023)) + temp_mem_size = temp_mem_size << 10; + temp_mem_size &= ~(machine_get_ram_granularity(temp_machine) - 1); + if (temp_mem_size < machine_get_min_ram(temp_machine)) + temp_mem_size = machine_get_min_ram(temp_machine); + else if (temp_mem_size > machine_get_max_ram(temp_machine)) + temp_mem_size = machine_get_max_ram(temp_machine); free(stransi); free(lptsTemp); @@ -918,51 +1048,25 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) static void -recalc_vid_list(HWND hdlg) +generate_device_name(const device_t *device, char *internal_name, int bus) { - HWND h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); - int c = 0, d = 0; - int found_card = 0; - WCHAR szText[512]; + char temp[512]; + WCHAR *wtemp; - SendMessage(h, CB_RESETCONTENT, 0, 0); - SendMessage(h, CB_SETCURSEL, 0, 0); + memset(device_name, 0x00, 512 * sizeof(WCHAR)); + memset(temp, 0x00, 512); - while (1) { - /* Skip "internal" if machine doesn't have it. */ - if ((c == 1) && !(machines[temp_machine].flags&MACHINE_VIDEO)) { - c++; - continue; - } + if (!strcmp(internal_name, "none")) { + /* Translate "None". */ + wtemp = (WCHAR *) win_get_string(IDS_2103); + memcpy(device_name, wtemp, (wcslen(wtemp) + 1) * sizeof(WCHAR)); + return; + } else if (!strcmp(internal_name, "internal")) + memcpy(temp, "Internal", 9); + else + device_get_name(device, bus, temp); - char *s = video_card_getname(c); - - if (!s[0]) - break; - - if (video_card_available(c) && - device_is_valid(video_card_getdevice(c), machines[temp_machine].flags)) { - mbstowcs(szText, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); - if (c == temp_gfxcard) { - SendMessage(h, CB_SETCURSEL, d, 0); - found_card = 1; - } - - d++; - } - - c++; - } - if (!found_card) - SendMessage(h, CB_SETCURSEL, 0, 0); - EnableWindow(h, (machines[temp_machine].flags & MACHINE_VIDEO_FIXED) ? FALSE : TRUE); - - h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); - EnableWindow(h, (machines[temp_machine].flags & MACHINE_PCI) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); - EnableWindow(h, ((machines[temp_machine].flags & MACHINE_PCI) && temp_voodoo) ? TRUE : FALSE); + mbstowcs(device_name, temp, strlen(temp) + 1); } @@ -973,97 +1077,106 @@ static BOOL CALLBACK #endif win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; - LPTSTR lptsTemp; - char *stransi; + int c = 0, d = 0; + int e; switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); + settings_reset_content(hdlg, IDC_COMBO_VIDEO); - recalc_vid_list(hdlg); + while (1) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !machine_has_flags(temp_machine, MACHINE_VIDEO)) { + c++; + continue; + } - h=GetDlgItem(hdlg, IDC_CHECK_VOODOO); - SendMessage(h, BM_SETCHECK, temp_voodoo, 0); + generate_device_name(video_card_getdevice(c), video_get_internal_name(c), 1); - h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); + if (!device_name[0]) + break; - h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); - if (video_card_has_config(temp_gfxcard)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + if (video_card_available(c) && + device_is_valid(video_card_getdevice(c), temp_machine)) { + if (c == 0) + settings_add_string(hdlg, IDC_COMBO_VIDEO, win_get_string(IDS_2103)); + else if (c == 1) + settings_add_string(hdlg, IDC_COMBO_VIDEO, win_get_string(IDS_2118)); + else + settings_add_string(hdlg, IDC_COMBO_VIDEO, (LPARAM) device_name); + settings_list_to_device[0][d] = c; + if ((c == 0) || (c == temp_gfxcard)) + settings_set_cur_sel(hdlg, IDC_COMBO_VIDEO, d); + d++; + } - free(stransi); - free(lptsTemp); + c++; + + settings_process_messages(); + } + + settings_enable_window(hdlg, IDC_COMBO_VIDEO, !machine_has_flags(temp_machine, MACHINE_VIDEO_ONLY)); + e = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_VIDEO)]; + settings_enable_window(hdlg, IDC_CONFIGURE_VID, video_card_has_config(e)); + + settings_enable_window(hdlg, IDC_CHECK_VOODOO, machine_has_bus(temp_machine, MACHINE_BUS_PCI)); + settings_set_check(hdlg, IDC_CHECK_VOODOO, temp_voodoo); + settings_enable_window(hdlg, IDC_BUTTON_VOODOO, machine_has_bus(temp_machine, MACHINE_BUS_PCI) && temp_voodoo); + + settings_enable_window(hdlg, IDC_CHECK_IBM8514, machine_has_bus(temp_machine, MACHINE_BUS_ISA16) || machine_has_bus(temp_machine, MACHINE_BUS_MCA)); + settings_set_check(hdlg, IDC_CHECK_IBM8514, temp_ibm8514); + + settings_enable_window(hdlg, IDC_CHECK_XGA, machine_has_bus(temp_machine, MACHINE_BUS_ISA16) || machine_has_bus(temp_machine, MACHINE_BUS_MCA)); + settings_set_check(hdlg, IDC_CHECK_XGA, temp_xga); + settings_enable_window(hdlg, IDC_BUTTON_XGA, (machine_has_bus(temp_machine, MACHINE_BUS_ISA16) || machine_has_bus(temp_machine, MACHINE_BUS_MCA)) && temp_xga); return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_COMBO_VIDEO: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); - temp_gfxcard = video_card_getid(stransi); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); - if (video_card_has_config(temp_gfxcard)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - free(stransi); - free(lptsTemp); + temp_gfxcard = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_VIDEO)]; + settings_enable_window(hdlg, IDC_CONFIGURE_VID, video_card_has_config(temp_gfxcard)); break; case IDC_CHECK_VOODOO: - h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); - temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + temp_voodoo = settings_get_check(hdlg, IDC_CHECK_VOODOO); + settings_enable_window(hdlg, IDC_BUTTON_VOODOO, temp_voodoo); + break; - h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); - EnableWindow(h, temp_voodoo ? TRUE : FALSE); + case IDC_CHECK_IBM8514: + temp_ibm8514 = settings_get_check(hdlg, IDC_CHECK_IBM8514); + break; + + case IDC_CHECK_XGA: + temp_xga = settings_get_check(hdlg, IDC_CHECK_XGA); + settings_enable_window(hdlg, IDC_BUTTON_XGA, temp_xga); break; case IDC_BUTTON_VOODOO: temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&voodoo_device); break; + case IDC_BUTTON_XGA: + if (machine_has_bus(temp_machine, MACHINE_BUS_MCA) > 0) { + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&xga_device); + } else { + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&xga_isa_device); + } + break; + case IDC_CONFIGURE_VID: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(stransi))); - - free(stransi); - free(lptsTemp); + temp_gfxcard = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_VIDEO)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)video_card_getdevice(temp_gfxcard)); break; } return FALSE; case WM_SAVESETTINGS: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); - temp_gfxcard = video_card_getid(stransi); - - h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); - temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); - - free(stransi); - free(lptsTemp); + temp_gfxcard = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_VIDEO)]; + temp_voodoo = settings_get_check(hdlg, IDC_CHECK_VOODOO); + temp_ibm8514 = settings_get_check(hdlg, IDC_CHECK_IBM8514); + temp_xga = settings_get_check(hdlg, IDC_CHECK_XGA); default: return FALSE; @@ -1078,10 +1191,10 @@ mouse_valid(int num, int m) const device_t *dev; if ((num == MOUSE_TYPE_INTERNAL) && - !(machines[m].flags & MACHINE_MOUSE)) return(0); + !machine_has_flags(m, MACHINE_MOUSE)) return(0); dev = mouse_get_device(num); - return(device_is_valid(dev, machines[m].flags)); + return(device_is_valid(dev, m)); } @@ -1093,125 +1206,78 @@ static BOOL CALLBACK win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { wchar_t str[128]; - char *joy_name; - HWND h; + char *joy_name; int c, d; switch (message) { case WM_INITDIALOG: - h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_MOUSE); for (c = 0; c < mouse_get_ndev(); c++) { - settings_device_to_list[0][c] = d; - if (mouse_valid(c, temp_machine)) { - mbstowcs(str, mouse_get_name(c), sizeof_w(str)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)str); - + generate_device_name(mouse_get_device(c), mouse_get_internal_name(c), 0); + if (c == 0) + settings_add_string(hdlg, IDC_COMBO_MOUSE, win_get_string(IDS_2103)); + else if (c == 1) + settings_add_string(hdlg, IDC_COMBO_MOUSE, win_get_string(IDS_2118)); + else + settings_add_string(hdlg, IDC_COMBO_MOUSE, (LPARAM) device_name); settings_list_to_device[0][d] = c; + if ((c == 0) || (c == temp_mouse)) + settings_set_cur_sel(hdlg, IDC_COMBO_MOUSE, d); d++; } } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_mouse], 0); + settings_enable_window(hdlg, IDC_CONFIGURE_MOUSE, mouse_has_config(temp_mouse)); - h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); - if (mouse_has_config(temp_mouse)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); c = 0; joy_name = joystick_get_name(c); while (joy_name) { mbstowcs(str, joy_name, strlen(joy_name) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)str); + settings_add_string(hdlg, IDC_COMBO_JOYSTICK, (LPARAM) str); - // SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2096 + c)); c++; joy_name = joystick_get_name(c); } - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_joystick, 0); + settings_enable_window(hdlg, IDC_COMBO_JOYSTICK, TRUE); + settings_set_cur_sel(hdlg, IDC_COMBO_JOYSTICK, temp_joystick); - h = GetDlgItem(hdlg, IDC_JOY1); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY2); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY3); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY4); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + for (c = 0; c < 4; c++) + settings_enable_window(hdlg, IDC_JOY1 + c, joystick_get_max_joysticks(temp_joystick) > c); return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_COMBO_MOUSE: - h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); - temp_mouse = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); - if (mouse_has_config(temp_mouse)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + temp_mouse = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_MOUSE)]; + settings_enable_window(hdlg, IDC_CONFIGURE_MOUSE, mouse_has_config(temp_mouse)); break; case IDC_CONFIGURE_MOUSE: - h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); - temp_mouse = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_mouse = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_MOUSE)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)mouse_get_device(temp_mouse)); break; case IDC_COMBO_JOYSTICK: - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); - temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_joystick = settings_get_cur_sel(hdlg, IDC_COMBO_JOYSTICK); - h = GetDlgItem(hdlg, IDC_JOY1); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY2); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY3); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_JOY4); - EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + for (c = 0; c < 4; c++) + settings_enable_window(hdlg, IDC_JOY1 + c, joystick_get_max_joysticks(temp_joystick) > c); break; - case IDC_JOY1: - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); - temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); - temp_deviceconfig |= joystickconfig_open(hdlg, 0, temp_joystick); - break; - - case IDC_JOY2: - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); - temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); - temp_deviceconfig |= joystickconfig_open(hdlg, 1, temp_joystick); - break; - - case IDC_JOY3: - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); - temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); - temp_deviceconfig |= joystickconfig_open(hdlg, 2, temp_joystick); - break; - - case IDC_JOY4: - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); - temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); - temp_deviceconfig |= joystickconfig_open(hdlg, 3, temp_joystick); + case IDC_JOY1: case IDC_JOY2: case IDC_JOY3: case IDC_JOY4: + temp_joystick = settings_get_cur_sel(hdlg, IDC_COMBO_JOYSTICK); + temp_deviceconfig |= joystickconfig_open(hdlg, LOWORD(wParam) - IDC_JOY1, temp_joystick); break; } return FALSE; case WM_SAVESETTINGS: - h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); - temp_mouse = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); - temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_mouse = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_MOUSE)]; + temp_joystick = settings_get_cur_sel(hdlg, IDC_COMBO_JOYSTICK); default: return FALSE; @@ -1232,8 +1298,11 @@ mpu401_standalone_allow(void) { char *md, *mdin; - md = midi_device_get_internal_name(temp_midi_device); - mdin = midi_in_device_get_internal_name(temp_midi_input_device); + if (!machine_has_bus(temp_machine, MACHINE_BUS_ISA) && !machine_has_bus(temp_machine, MACHINE_BUS_MCA)) + return 0; + + md = midi_out_device_get_internal_name(temp_midi_output_device); + mdin = midi_in_device_get_internal_name(temp_midi_input_device); if (md != NULL) { if (!strcmp(md, "none") && !strcmp(mdin, "none")) @@ -1250,269 +1319,217 @@ static BOOL CALLBACK #endif win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; int c, d; LPTSTR lptsTemp; const device_t *sound_dev; - char *s; switch (message) { case WM_INITDIALOG: lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_SOUND); c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_SOUND); while (1) { - s = sound_card_getname(c); + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !machine_has_flags(temp_machine, MACHINE_SOUND)) { + c++; + continue; + } - if (!s[0]) + generate_device_name(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); + + if (!device_name[0]) break; - settings_device_to_list[0][c] = d; - if (sound_card_available(c)) { sound_dev = sound_card_getdevice(c); - if (device_is_valid(sound_dev, machines[temp_machine].flags)) { + if (device_is_valid(sound_dev, temp_machine)) { if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); - else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } + settings_add_string(hdlg, IDC_COMBO_SOUND, win_get_string(IDS_2103)); + else if (c == 1) + settings_add_string(hdlg, IDC_COMBO_SOUND, win_get_string(IDS_2118)); + else + settings_add_string(hdlg, IDC_COMBO_SOUND, (LPARAM) device_name); settings_list_to_device[0][d] = c; + if ((c == 0) || (c == temp_sound_card)) + settings_set_cur_sel(hdlg, IDC_COMBO_SOUND, d); d++; } } c++; } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_sound_card], 0); - EnableWindow(h, d ? TRUE : FALSE); + settings_enable_window(hdlg, IDC_COMBO_SOUND, d); + settings_enable_window(hdlg, IDC_CONFIGURE_SND, sound_card_has_config(temp_sound_card)); - h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); - EnableWindow(h, sound_card_has_config(temp_sound_card) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_COMBO_MIDI); c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_MIDI_OUT); while (1) { - s = midi_device_getname(c); + generate_device_name(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); - if (!s[0]) + if (!device_name[0]) break; - settings_midi_to_list[c] = d; - - if (midi_device_available(c)) { + if (midi_out_device_available(c)) { if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); - else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } + settings_add_string(hdlg, IDC_COMBO_MIDI_OUT, win_get_string(IDS_2103)); + else + settings_add_string(hdlg, IDC_COMBO_MIDI_OUT, (LPARAM) device_name); settings_list_to_midi[d] = c; + if ((c == 0) || (c == temp_midi_output_device)) + settings_set_cur_sel(hdlg, IDC_COMBO_MIDI_OUT, d); d++; } c++; } - SendMessage(h, CB_SETCURSEL, settings_midi_to_list[temp_midi_device], 0); - h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); - if (midi_device_has_config(temp_midi_device)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + settings_enable_window(hdlg, IDC_CONFIGURE_MIDI_OUT, midi_out_device_has_config(temp_midi_output_device)); - h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_MIDI_IN); while (1) { - s = midi_in_device_getname(c); + generate_device_name(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); - if (!s[0]) + if (!device_name[0]) break; - settings_midi_in_to_list[c] = d; - if (midi_in_device_available(c)) { if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); - else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } + settings_add_string(hdlg, IDC_COMBO_MIDI_IN, win_get_string(IDS_2103)); + else + settings_add_string(hdlg, IDC_COMBO_MIDI_IN, (LPARAM) device_name); settings_list_to_midi_in[d] = c; + if ((c == 0) || (c == temp_midi_input_device)) + settings_set_cur_sel(hdlg, IDC_COMBO_MIDI_IN, d); d++; } c++; } - SendMessage(h, CB_SETCURSEL, settings_midi_in_to_list[temp_midi_input_device], 0); - h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI_IN); - if (midi_in_device_has_config(temp_midi_input_device)) - EnableWindow(h, TRUE); + settings_enable_window(hdlg, IDC_CONFIGURE_MIDI_IN, midi_in_device_has_config(temp_midi_input_device)); + settings_set_check(hdlg, IDC_CHECK_MPU401, temp_mpu401); + settings_enable_window(hdlg, IDC_CHECK_MPU401, mpu401_standalone_allow()); + settings_enable_window(hdlg, IDC_CONFIGURE_MPU401, mpu401_standalone_allow() && temp_mpu401); + settings_enable_window(hdlg, IDC_CHECK_CMS, machine_has_bus(temp_machine, MACHINE_BUS_ISA)); + settings_set_check(hdlg, IDC_CHECK_CMS, temp_GAMEBLASTER); + settings_enable_window(hdlg, IDC_CONFIGURE_CMS, machine_has_bus(temp_machine, MACHINE_BUS_ISA) && temp_GAMEBLASTER); + settings_enable_window(hdlg, IDC_CHECK_GUS, machine_has_bus(temp_machine, MACHINE_BUS_ISA16)); + settings_set_check(hdlg, IDC_CHECK_GUS, temp_GUS); + settings_enable_window(hdlg, IDC_CONFIGURE_GUS, machine_has_bus(temp_machine, MACHINE_BUS_ISA16) && temp_GUS); + settings_enable_window(hdlg, IDC_CHECK_SSI, machine_has_bus(temp_machine, MACHINE_BUS_ISA)); + settings_set_check(hdlg, IDC_CHECK_SSI, temp_SSI2001); + settings_enable_window(hdlg, IDC_CONFIGURE_SSI, machine_has_bus(temp_machine, MACHINE_BUS_ISA) && temp_SSI2001); + settings_set_check(hdlg, IDC_CHECK_FLOAT, temp_float); + + if (temp_fm_driver == FM_DRV_YMFM) + settings_set_check(hdlg, IDC_RADIO_FM_DRV_YMFM, BST_CHECKED); else - EnableWindow(h, FALSE); - - - h = GetDlgItem(hdlg, IDC_CHECK_MPU401); - SendMessage(h, BM_SETCHECK, temp_mpu401, 0); - EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); - EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); - - - h=GetDlgItem(hdlg, IDC_CHECK_CMS); - SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); - - h=GetDlgItem(hdlg, IDC_CHECK_GUS); - SendMessage(h, BM_SETCHECK, temp_GUS, 0); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_GUS); - EnableWindow(h, (temp_GUS) ? TRUE : FALSE); - - h=GetDlgItem(hdlg, IDC_CHECK_SSI); - SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); - - h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); - SendMessage(h, BM_SETCHECK, temp_float, 0); + settings_set_check(hdlg, IDC_RADIO_FM_DRV_NUKED, BST_CHECKED); free(lptsTemp); return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_COMBO_SOUND: - h = GetDlgItem(hdlg, IDC_COMBO_SOUND); - temp_sound_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); - if (sound_card_has_config(temp_sound_card)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CHECK_MPU401); - SendMessage(h, BM_SETCHECK, temp_mpu401, 0); - EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); - EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + temp_sound_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SOUND)]; + settings_enable_window(hdlg, IDC_CONFIGURE_SND, sound_card_has_config(temp_sound_card)); + settings_set_check(hdlg, IDC_CHECK_MPU401, temp_mpu401); + settings_enable_window(hdlg, IDC_CHECK_MPU401, mpu401_standalone_allow()); + settings_enable_window(hdlg, IDC_CONFIGURE_MPU401, mpu401_standalone_allow() && temp_mpu401); break; case IDC_CONFIGURE_SND: - h = GetDlgItem(hdlg, IDC_COMBO_SOUND); - temp_sound_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - + temp_sound_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SOUND)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card)); break; - case IDC_COMBO_MIDI: - h = GetDlgItem(hdlg, IDC_COMBO_MIDI); - temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); - if (midi_device_has_config(temp_midi_device)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CHECK_MPU401); - SendMessage(h, BM_SETCHECK, temp_mpu401, 0); - EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); - EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + case IDC_COMBO_MIDI_OUT: + temp_midi_output_device = settings_list_to_midi[settings_get_cur_sel(hdlg, IDC_COMBO_MIDI_OUT)]; + settings_enable_window(hdlg, IDC_CONFIGURE_MIDI_OUT, midi_out_device_has_config(temp_midi_output_device)); + settings_set_check(hdlg, IDC_CHECK_MPU401, temp_mpu401); + settings_enable_window(hdlg, IDC_CHECK_MPU401, mpu401_standalone_allow()); + settings_enable_window(hdlg, IDC_CONFIGURE_MPU401, mpu401_standalone_allow() && temp_mpu401); break; - case IDC_CONFIGURE_MIDI: - h = GetDlgItem(hdlg, IDC_COMBO_MIDI); - temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_device_getdevice(temp_midi_device)); + case IDC_CONFIGURE_MIDI_OUT: + temp_midi_output_device = settings_list_to_midi[settings_get_cur_sel(hdlg, IDC_COMBO_MIDI_OUT)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_out_device_getdevice(temp_midi_output_device)); break; case IDC_COMBO_MIDI_IN: - h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); - temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI_IN); - if (midi_in_device_has_config(temp_midi_input_device)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CHECK_MPU401); - SendMessage(h, BM_SETCHECK, temp_mpu401, 0); - EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); - EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + temp_midi_input_device = settings_list_to_midi_in[settings_get_cur_sel(hdlg, IDC_COMBO_MIDI_IN)]; + settings_enable_window(hdlg, IDC_CONFIGURE_MIDI_IN, midi_in_device_has_config(temp_midi_input_device)); + settings_set_check(hdlg, IDC_CHECK_MPU401, temp_mpu401); + settings_enable_window(hdlg, IDC_CHECK_MPU401, mpu401_standalone_allow()); + settings_enable_window(hdlg, IDC_CONFIGURE_MPU401, mpu401_standalone_allow() && temp_mpu401); break; case IDC_CONFIGURE_MIDI_IN: - h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); - temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; - + temp_midi_input_device = settings_list_to_midi_in[settings_get_cur_sel(hdlg, IDC_COMBO_MIDI_IN)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_in_device_getdevice(temp_midi_input_device)); break; case IDC_CHECK_MPU401: - h = GetDlgItem(hdlg, IDC_CHECK_MPU401); - temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + temp_mpu401 = settings_get_check(hdlg, IDC_CHECK_MPU401); - h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); - EnableWindow(h, mpu401_present() ? TRUE : FALSE); + settings_enable_window(hdlg, IDC_CONFIGURE_MPU401, mpu401_present()); break; case IDC_CONFIGURE_MPU401: - temp_deviceconfig |= deviceconfig_open(hdlg, (machines[temp_machine].flags & MACHINE_MCA) ? + temp_deviceconfig |= deviceconfig_open(hdlg, machine_has_bus(temp_machine, MACHINE_BUS_MCA) ? (void *)&mpu401_mca_device : (void *)&mpu401_device); break; - - case IDC_CHECK_GUS: - h = GetDlgItem(hdlg, IDC_CHECK_GUS); - temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CONFIGURE_GUS); - EnableWindow(h, temp_GUS ? TRUE : FALSE); + case IDC_CHECK_CMS: + temp_GAMEBLASTER = settings_get_check(hdlg, IDC_CHECK_CMS); + + settings_enable_window(hdlg, IDC_CONFIGURE_CMS, temp_GAMEBLASTER); + break; + + case IDC_CONFIGURE_CMS: + temp_deviceconfig |= deviceconfig_open(hdlg, &cms_device); + break; + + case IDC_CHECK_GUS: + temp_GUS = settings_get_check(hdlg, IDC_CHECK_GUS); + settings_enable_window(hdlg, IDC_CONFIGURE_GUS, temp_GUS); break; case IDC_CONFIGURE_GUS: temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&gus_device); break; + + case IDC_CHECK_SSI: + temp_SSI2001 = settings_get_check(hdlg, IDC_CHECK_SSI); + + settings_enable_window(hdlg, IDC_CONFIGURE_SSI, temp_SSI2001); + break; + + case IDC_CONFIGURE_SSI: + temp_deviceconfig |= deviceconfig_open(hdlg, &ssi2001_device); + break; } return FALSE; case WM_SAVESETTINGS: - h = GetDlgItem(hdlg, IDC_COMBO_SOUND); - temp_sound_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBO_MIDI); - temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); - temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CHECK_MPU401); - temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_CMS); - temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_GUS); - temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_SSI); - temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); - temp_float = SendMessage(h, BM_GETCHECK, 0, 0); - + temp_sound_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SOUND)]; + temp_midi_output_device = settings_list_to_midi[settings_get_cur_sel(hdlg, IDC_COMBO_MIDI_OUT)]; + temp_midi_input_device = settings_list_to_midi_in[settings_get_cur_sel(hdlg, IDC_COMBO_MIDI_IN)]; + temp_mpu401 = settings_get_check(hdlg, IDC_CHECK_MPU401); + temp_GAMEBLASTER = settings_get_check(hdlg, IDC_CHECK_CMS); + temp_GUS = settings_get_check(hdlg, IDC_CHECK_GUS); + temp_SSI2001 = settings_get_check(hdlg, IDC_CHECK_SSI); + temp_float = settings_get_check(hdlg, IDC_CHECK_FLOAT); + if (settings_get_check(hdlg, IDC_RADIO_FM_DRV_NUKED)) + temp_fm_driver = FM_DRV_NUKED; + if (settings_get_check(hdlg, IDC_RADIO_FM_DRV_YMFM)) + temp_fm_driver = FM_DRV_YMFM; default: return FALSE; } @@ -1527,7 +1544,6 @@ static BOOL CALLBACK #endif win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; int c, i; char *s; LPTSTR lptsTemp; @@ -1536,8 +1552,7 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_INITDIALOG: lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - for (i = 0; i < 3; i++) { - h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); + for (i = 0; i < PARALLEL_MAX; i++) { c = 0; while (1) { s = lpt_device_get_name(c); @@ -1546,27 +1561,22 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); + settings_add_string(hdlg, IDC_COMBO_LPT1 + i, win_get_string(IDS_2103)); else { mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_LPT1 + i, (LPARAM) lptsTemp); } c++; } - SendMessage(h, CB_SETCURSEL, temp_lpt_devices[i], 0); + settings_set_cur_sel(hdlg, IDC_COMBO_LPT1 + i, temp_lpt_devices[i]); - h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); - SendMessage(h, BM_SETCHECK, temp_lpt[i], 0); - - h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - EnableWindow(h, temp_lpt[i] ? TRUE : FALSE); + settings_set_check(hdlg, IDC_CHECK_PARALLEL1 + i, temp_lpt[i]); + settings_enable_window(hdlg, IDC_COMBO_LPT1 + i, temp_lpt[i]); } - for (i = 0; i < 2; i++) { - h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1 + i); - SendMessage(h, BM_SETCHECK, temp_serial[i], 0); - } + for (i = 0; i < SERIAL_MAX; i++) + settings_set_check(hdlg, IDC_CHECK_SERIAL1 + i, temp_serial[i]); free(lptsTemp); @@ -1577,35 +1587,22 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case IDC_CHECK_PARALLEL1: case IDC_CHECK_PARALLEL2: case IDC_CHECK_PARALLEL3: + case IDC_CHECK_PARALLEL4: i = LOWORD(wParam) - IDC_CHECK_PARALLEL1; - h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); - if (SendMessage(h, BM_GETCHECK, 0, 0) == BST_CHECKED) - { - h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - EnableWindow(h, TRUE); - } - else - { - h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - EnableWindow(h, FALSE); - } + settings_enable_window(hdlg, IDC_COMBO_LPT1 + i, + settings_get_check(hdlg, IDC_CHECK_PARALLEL1 + i) == BST_CHECKED); break; } break; case WM_SAVESETTINGS: - for (i = 0; i < 3; i++) { - h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - temp_lpt_devices[i] = SendMessage(h, CB_GETCURSEL, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); - temp_lpt[i] = SendMessage(h, BM_GETCHECK, 0, 0); + for (i = 0; i < PARALLEL_MAX; i++) { + temp_lpt_devices[i] = settings_get_cur_sel(hdlg, IDC_COMBO_LPT1 + i); + temp_lpt[i] = settings_get_check(hdlg, IDC_CHECK_PARALLEL1 + i); } - for (i = 0; i < 2; i++) { - h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1 + i); - temp_serial[i] = SendMessage(h, BM_GETCHECK, 0, 0); - } + for (i = 0; i < SERIAL_MAX; i++) + temp_serial[i] = settings_get_check(hdlg, IDC_CHECK_SERIAL1 + i); default: return FALSE; @@ -1613,64 +1610,20 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; } -static void -recalc_hdc_list(HWND hdlg) -{ - HWND h = GetDlgItem(hdlg, IDC_COMBO_HDC); - int c = 0, d = 0; - int found_card = 0; - WCHAR szText[512]; - - SendMessage(h, CB_RESETCONTENT, 0, 0); - SendMessage(h, CB_SETCURSEL, 0, 0); - - while (1) { - /* Skip "internal" if machine doesn't have it. */ - if ((c == 1) && !(machines[temp_machine].flags & MACHINE_HDC)) { - c++; - continue; - } - - char *s = hdc_get_name(c); - - if (!s[0]) - break; - - if (hdc_available(c) && - device_is_valid(hdc_get_device(c), machines[temp_machine].flags)) { - mbstowcs(szText, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); - if (c == temp_hdc) { - SendMessage(h, CB_SETCURSEL, d, 0); - found_card = 1; - } - - d++; - } - - c++; - } - if (!found_card) - SendMessage(h, CB_SETCURSEL, 0, 0); -} - #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif -win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +win_settings_storage_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; int c, d; - int e; + int e, is_at; LPTSTR lptsTemp; char *stransi; - const device_t *scsi_dev; - const device_t *dev; - const device_t *fdc_dev; - char *s; + const device_t *scsi_dev, *fdc_dev; + const device_t *hdc_dev; switch (message) { case WM_INITDIALOG: @@ -1678,72 +1631,97 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa stransi = (char *) malloc(512); /*HD controller config*/ - recalc_hdc_list(hdlg); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); - if (hdc_has_config(temp_hdc)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - - /*FD controller config*/ - h = GetDlgItem(hdlg, IDC_COMBO_FDC); c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_HDC); while (1) { - char *s = fdc_card_getname(c); + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !machine_has_flags(temp_machine, MACHINE_HDC)) { + c++; + continue; + } - if (!s[0]) + generate_device_name(hdc_get_device(c), hdc_get_internal_name(c), 1); + + if (!device_name[0]) break; - settings_fdc_to_list[0][c] = d; + if (hdc_available(c)) { + hdc_dev = hdc_get_device(c); - if (fdc_card_available(c)) { - fdc_dev = fdc_card_getdevice(c); - - if (device_is_valid(fdc_dev, machines[temp_machine].flags)) { + if (device_is_valid(hdc_dev, temp_machine)) { if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2118)); - else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } - settings_list_to_fdc[0][d] = c; + settings_add_string(hdlg, IDC_COMBO_HDC, win_get_string(IDS_2103)); + else if (c == 1) + settings_add_string(hdlg, IDC_COMBO_HDC, win_get_string(IDS_2118)); + else + settings_add_string(hdlg, IDC_COMBO_HDC, (LPARAM) device_name); + settings_list_to_hdc[d] = c; + if ((c == 0) || (c == temp_hdc)) + settings_set_cur_sel(hdlg, IDC_COMBO_HDC, d); d++; } } c++; } - SendMessage(h, CB_SETCURSEL, settings_fdc_to_list[0][temp_fdc_card], 0); - EnableWindow(h, d ? TRUE : FALSE); + settings_enable_window(hdlg, IDC_COMBO_HDC, d); + settings_enable_window(hdlg, IDC_CONFIGURE_HDC, hdc_has_config(temp_hdc)); - h = GetDlgItem(hdlg, IDC_CONFIGURE_FDC); - EnableWindow(h, fdc_card_has_config(temp_fdc_card) ? TRUE : FALSE); - - - /*SCSI config*/ - h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + /*FD controller config*/ c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_FDC); while (1) { - char *s = scsi_card_getname(c); + generate_device_name(fdc_card_getdevice(c), fdc_card_get_internal_name(c), 1); - if (!s[0]) + if (!device_name[0]) break; - settings_device_to_list[0][c] = d; + if (fdc_card_available(c)) { + fdc_dev = fdc_card_getdevice(c); + + if (device_is_valid(fdc_dev, temp_machine)) { + if (c == 0) + settings_add_string(hdlg, IDC_COMBO_FDC, win_get_string(IDS_2118)); + else + settings_add_string(hdlg, IDC_COMBO_FDC, (LPARAM) device_name); + settings_list_to_fdc[d] = c; + if ((c == 0) || (c == temp_fdc_card)) + settings_set_cur_sel(hdlg, IDC_COMBO_FDC, d); + d++; + } + } + + c++; + } + + settings_enable_window(hdlg, IDC_COMBO_FDC, d); + settings_enable_window(hdlg, IDC_CONFIGURE_FDC, fdc_card_has_config(temp_fdc_card)); + + /*SCSI config*/ + c = d = 0; + for (e = 0; e < SCSI_BUS_MAX; e++) + settings_reset_content(hdlg, IDC_COMBO_SCSI_1 + e); + while (1) { + generate_device_name(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); + + if (!device_name[0]) + break; if (scsi_card_available(c)) { scsi_dev = scsi_card_getdevice(c); - if (device_is_valid(scsi_dev, machines[temp_machine].flags)) { - if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); - else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + if (device_is_valid(scsi_dev, temp_machine)) { + for (e = 0; e < SCSI_BUS_MAX; e++) { + if (c == 0) + settings_add_string(hdlg, IDC_COMBO_SCSI_1 + e, win_get_string(IDS_2103)); + else + settings_add_string(hdlg, IDC_COMBO_SCSI_1 + e, (LPARAM) device_name); + + if ((c == 0) || (c == temp_scsi_card[e])) + settings_set_cur_sel(hdlg, IDC_COMBO_SCSI_1 + e, d); } + settings_list_to_device[0][d] = c; d++; } @@ -1751,89 +1729,19 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa c++; } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_scsi_card], 0); - EnableWindow(h, d ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); - EnableWindow(h, scsi_card_has_config(temp_scsi_card) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); - EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); - EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_ter) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); - EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); - EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_qua) ? TRUE : FALSE); - - h=GetDlgItem(hdlg, IDC_CHECK_IDE_TER); - SendMessage(h, BM_SETCHECK, temp_ide_ter, 0); - - h=GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); - SendMessage(h, BM_SETCHECK, temp_ide_qua, 0); - - h=GetDlgItem(hdlg, IDC_CHECK_BUGGER); - SendMessage(h, BM_SETCHECK, temp_bugger, 0); - - h=GetDlgItem(hdlg, IDC_CHECK_POSTCARD); - SendMessage(h, BM_SETCHECK, temp_postcard, 0); - - /* Populate the ISA RTC card dropdown. */ - e = 0; - h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); - for (d = 0; ; d++) { - s = isartc_get_name(d); - if (!s[0]) - break; - - settings_device_to_list[1][d] = e; - - if (d == 0) { - /* Translate "None". */ - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); - } else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } - - settings_list_to_device[1][e] = d; - e++; - } - SendMessage(h, CB_SETCURSEL, temp_isartc, 0); - h = GetDlgItem(hdlg, IDC_CONFIGURE_ISARTC); - if (temp_isartc != 0) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - /* Populate the ISA memory card dropdowns. */ - for (c = 0; c < ISAMEM_MAX; c++) { - h = GetDlgItem(hdlg, IDC_COMBO_ISAMEM_1 + c); - for (d = 0; ; d++) { - s = (char *) isamem_get_internal_name(d); - if (s == NULL) - break; - - if (d == 0) { - /* Translate "None". */ - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)win_get_string(IDS_2103)); - } else { - s = (char *) isamem_get_name(d); - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)lptsTemp); - } - } - SendMessage(h, CB_SETCURSEL, temp_isamem[c], 0); - h = GetDlgItem(hdlg, IDC_CONFIGURE_ISAMEM_1 + c); - if (temp_isamem[c] != 0) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + for (c = 0; c < SCSI_BUS_MAX; c++) { + settings_enable_window(hdlg, IDC_COMBO_SCSI_1 + c, d); + settings_enable_window(hdlg, IDC_CONFIGURE_SCSI_1 + c, scsi_card_has_config(temp_scsi_card[c])); } + is_at = IS_AT(temp_machine); + settings_enable_window(hdlg, IDC_CHECK_IDE_TER, is_at); + settings_enable_window(hdlg, IDC_BUTTON_IDE_TER, is_at && temp_ide_ter); + settings_enable_window(hdlg, IDC_CHECK_IDE_QUA, is_at); + settings_enable_window(hdlg, IDC_BUTTON_IDE_QUA, is_at && temp_ide_qua); + settings_set_check(hdlg, IDC_CHECK_IDE_TER, temp_ide_ter); + settings_set_check(hdlg, IDC_CHECK_IDE_QUA, temp_ide_qua); + settings_set_check(hdlg, IDC_CHECK_CASSETTE, temp_cassette); free(stransi); free(lptsTemp); @@ -1841,123 +1749,42 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_CONFIGURE_FDC: - h = GetDlgItem(hdlg, IDC_COMBO_FDC); - temp_fdc_card = settings_list_to_fdc[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - + temp_fdc_card = settings_list_to_fdc[settings_get_cur_sel(hdlg, IDC_COMBO_FDC)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)fdc_card_getdevice(temp_fdc_card)); break; case IDC_COMBO_FDC: - h = GetDlgItem(hdlg, IDC_COMBO_FDC); - temp_fdc_card = settings_list_to_fdc[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_fdc_card = settings_list_to_fdc[settings_get_cur_sel(hdlg, IDC_COMBO_FDC)]; + settings_enable_window(hdlg, IDC_CONFIGURE_FDC, fdc_card_has_config(temp_fdc_card)); + break; - h = GetDlgItem(hdlg, IDC_CONFIGURE_FDC); - if (fdc_card_has_config(temp_fdc_card)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - case IDC_CONFIGURE_HDC: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_HDC); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(hdc_get_id(stransi))); - - free(stransi); - free(lptsTemp); + temp_hdc = settings_list_to_hdc[settings_get_cur_sel(hdlg, IDC_COMBO_HDC)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(temp_hdc)); break; case IDC_COMBO_HDC: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_HDC); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); - temp_hdc = hdc_get_id(stransi); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); - if (hdc_has_config(temp_hdc)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - free(stransi); - free(lptsTemp); + temp_hdc = settings_list_to_hdc[settings_get_cur_sel(hdlg, IDC_COMBO_HDC)]; + settings_enable_window(hdlg, IDC_CONFIGURE_HDC, hdc_has_config(temp_hdc)); break; - case IDC_CONFIGURE_SCSI: - h = GetDlgItem(hdlg, IDC_COMBO_SCSI); - temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card)); + case IDC_CONFIGURE_SCSI_1 ... IDC_CONFIGURE_SCSI_4: + c = LOWORD(wParam) - IDC_CONFIGURE_SCSI_1; + temp_scsi_card[c] = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SCSI_1 + c)]; + temp_deviceconfig |= deviceconfig_inst_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card[c]), c + 1); break; - case IDC_COMBO_SCSI: - h = GetDlgItem(hdlg, IDC_COMBO_SCSI); - temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); - if (scsi_card_has_config(temp_scsi_card)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - - case IDC_CONFIGURE_ISARTC: - h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); - temp_isartc = settings_list_to_device[1][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)isartc_get_device(temp_isartc)); - break; - - case IDC_COMBO_ISARTC: - h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); - temp_isartc = settings_list_to_device[1][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CONFIGURE_ISARTC); - if (temp_isartc != 0) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - - case IDC_COMBO_ISAMEM_1: - case IDC_COMBO_ISAMEM_2: - case IDC_COMBO_ISAMEM_3: - case IDC_COMBO_ISAMEM_4: - c = LOWORD(wParam) - IDC_COMBO_ISAMEM_1; - h = GetDlgItem(hdlg, LOWORD(wParam)); - temp_isamem[c] = SendMessage(h, CB_GETCURSEL, 0, 0); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_ISAMEM_1 + c); - if (temp_isamem[c] != 0) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - break; - - case IDC_CONFIGURE_ISAMEM_1: - case IDC_CONFIGURE_ISAMEM_2: - case IDC_CONFIGURE_ISAMEM_3: - case IDC_CONFIGURE_ISAMEM_4: - c = LOWORD(wParam) - IDC_CONFIGURE_ISAMEM_1; - dev = isamem_get_device(temp_isamem[c]); - temp_deviceconfig |= deviceconfig_inst_open(hdlg, (void *)dev, c + 1); + case IDC_COMBO_SCSI_1 ... IDC_COMBO_SCSI_4: + c = LOWORD(wParam) - IDC_COMBO_SCSI_1; + temp_scsi_card[c] = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SCSI_1 + c)]; + settings_enable_window(hdlg, IDC_CONFIGURE_SCSI_1 + c, scsi_card_has_config(temp_scsi_card[c])); break; case IDC_CHECK_IDE_TER: - h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); - temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); - EnableWindow(h, temp_ide_ter ? TRUE : FALSE); + temp_ide_ter = settings_get_check(hdlg, IDC_CHECK_IDE_TER); + settings_enable_window(hdlg, IDC_BUTTON_IDE_TER, temp_ide_ter); break; case IDC_BUTTON_IDE_TER: @@ -1965,11 +1792,8 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa break; case IDC_CHECK_IDE_QUA: - h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); - temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); - EnableWindow(h, temp_ide_qua ? TRUE : FALSE); + temp_ide_qua = settings_get_check(hdlg, IDC_CHECK_IDE_QUA); + settings_enable_window(hdlg, IDC_BUTTON_IDE_QUA, temp_ide_qua); break; case IDC_BUTTON_IDE_QUA: @@ -1979,37 +1803,13 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa return FALSE; case WM_SAVESETTINGS: - lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - stransi = (char *) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_HDC); - SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); - wcstombs(stransi, lptsTemp, 512); - temp_hdc = hdc_get_id(stransi); - - h = GetDlgItem(hdlg, IDC_COMBO_FDC); - temp_fdc_card = settings_list_to_fdc[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBO_SCSI); - temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); - temp_isartc = settings_list_to_device[1][SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); - temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); - temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); - temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_POSTCARD); - temp_postcard = SendMessage(h, BM_GETCHECK, 0, 0); - - free(stransi); - free(lptsTemp); + temp_hdc = settings_list_to_hdc[settings_get_cur_sel(hdlg, IDC_COMBO_HDC)]; + temp_fdc_card = settings_list_to_fdc[settings_get_cur_sel(hdlg, IDC_COMBO_FDC)]; + for (c = 0; c < SCSI_BUS_MAX; c++) + temp_scsi_card[c] = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SCSI_1 + c)]; + temp_ide_ter = settings_get_check(hdlg, IDC_CHECK_IDE_TER); + temp_ide_qua = settings_get_check(hdlg, IDC_CHECK_IDE_QUA); + temp_cassette = settings_get_check(hdlg, IDC_CHECK_CASSETTE); default: return FALSE; @@ -2020,32 +1820,15 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa static void network_recalc_combos(HWND hdlg) { - HWND h; - ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_PCAP); - EnableWindow(h, (temp_net_type == NET_TYPE_PCAP) ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_COMBO_NET); - if (temp_net_type == NET_TYPE_SLIRP) - EnableWindow(h, TRUE); - else if ((temp_net_type == NET_TYPE_PCAP) && - (network_dev_to_id(temp_pcap_dev) > 0)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_NET); - if (network_card_has_config(temp_net_card) && - (temp_net_type == NET_TYPE_SLIRP)) - EnableWindow(h, TRUE); - else if (network_card_has_config(temp_net_card) && - (temp_net_type == NET_TYPE_PCAP) && - (network_dev_to_id(temp_pcap_dev) > 0)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); + settings_enable_window(hdlg, IDC_COMBO_PCAP, temp_net_type == NET_TYPE_PCAP); + settings_enable_window(hdlg, IDC_COMBO_NET, + (temp_net_type == NET_TYPE_SLIRP) || + ((temp_net_type == NET_TYPE_PCAP) && (network_dev_to_id(temp_pcap_dev) > 0))); + settings_enable_window(hdlg, IDC_CONFIGURE_NET, network_card_has_config(temp_net_card) && + ((temp_net_type == NET_TYPE_SLIRP) || + ((temp_net_type == NET_TYPE_PCAP) && (network_dev_to_id(temp_pcap_dev) > 0)))); ignore_change = 0; } @@ -2058,75 +1841,61 @@ static BOOL CALLBACK #endif win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; int c, d; LPTSTR lptsTemp; - char *s; switch (message) { case WM_INITDIALOG: lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"PCap"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"SLiRP"); - SendMessage(h, CB_SETCURSEL, temp_net_type, 0); + settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"None"); + settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"PCap"); + settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"SLiRP"); + settings_set_cur_sel(hdlg, IDC_COMBO_NET_TYPE, temp_net_type); + settings_enable_window(hdlg, IDC_COMBO_PCAP, temp_net_type == NET_TYPE_PCAP); - h = GetDlgItem(hdlg, IDC_COMBO_PCAP); - if (temp_net_type == NET_TYPE_PCAP) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBO_PCAP); for (c = 0; c < network_ndev; c++) { mbstowcs(lptsTemp, network_devs[c].description, strlen(network_devs[c].description) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_PCAP, (LPARAM) lptsTemp); } - SendMessage(h, CB_SETCURSEL, network_dev_to_id(temp_pcap_dev), 0); + settings_set_cur_sel(hdlg, IDC_COMBO_PCAP, network_dev_to_id(temp_pcap_dev)); - /*NIC config*/ - h = GetDlgItem(hdlg, IDC_COMBO_NET); + /* NIC config */ c = d = 0; + settings_reset_content(hdlg, IDC_COMBO_NET); while (1) { - s = network_card_getname(c); + generate_device_name(network_card_getdevice(c), network_card_get_internal_name(c), 1); - if (s[0] == '\0') + if (device_name[0] == L'\0') break; - settings_device_to_list[0][c] = d; - - if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machines[temp_machine].flags)) { + if (network_card_available(c) && device_is_valid(network_card_getdevice(c), temp_machine)) { if (c == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2103)); - else { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } + settings_add_string(hdlg, IDC_COMBO_NET, win_get_string(IDS_2103)); + else + settings_add_string(hdlg, IDC_COMBO_NET, (LPARAM) device_name); settings_list_to_device[0][d] = c; + if ((c == 0) || (c == temp_net_card)) + settings_set_cur_sel(hdlg, IDC_COMBO_NET, d); d++; } c++; } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_net_card], 0); - EnableWindow(h, d ? TRUE : FALSE); + settings_enable_window(hdlg, IDC_COMBO_NET, d); network_recalc_combos(hdlg); free(lptsTemp); return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_COMBO_NET_TYPE: if (ignore_change) return FALSE; - h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); - temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); - + temp_net_type = settings_get_cur_sel(hdlg, IDC_COMBO_NET_TYPE); network_recalc_combos(hdlg); break; @@ -2134,10 +1903,8 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (ignore_change) return FALSE; - h = GetDlgItem(hdlg, IDC_COMBO_PCAP); memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); - strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); - + strcpy(temp_pcap_dev, network_devs[settings_get_cur_sel(hdlg, IDC_COMBO_PCAP)].device); network_recalc_combos(hdlg); break; @@ -2145,9 +1912,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (ignore_change) return FALSE; - h = GetDlgItem(hdlg, IDC_COMBO_NET); - temp_net_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - + temp_net_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_NET)]; network_recalc_combos(hdlg); break; @@ -2155,24 +1920,17 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (ignore_change) return FALSE; - h = GetDlgItem(hdlg, IDC_COMBO_NET); - temp_net_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; - + temp_net_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_NET)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_net_card)); break; } return FALSE; case WM_SAVESETTINGS: - h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); - temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); - - h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + temp_net_type = settings_get_cur_sel(hdlg, IDC_COMBO_NET_TYPE); memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); - strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); - - h = GetDlgItem(hdlg, IDC_COMBO_NET); - temp_net_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; + strcpy(temp_pcap_dev, network_devs[settings_get_cur_sel(hdlg, IDC_COMBO_PCAP)].device); + temp_net_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_NET)]; default: return FALSE; @@ -2227,31 +1985,26 @@ static void add_locations(HWND hdlg) { LPTSTR lptsTemp; - HWND h; int i = 0; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - for (i = 0; i < 5; i++) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4352 + i)); + for (i = 0; i < 6; i++) + settings_add_string(hdlg, IDC_COMBO_HD_BUS, win_get_string(IDS_4352 + i)); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); for (i = 0; i < 2; i++) { wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_HD_CHANNEL, (LPARAM) lptsTemp); } - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - for (i = 0; i < 16; i++) { - wsprintf(lptsTemp, plat_get_string(IDS_4098), i); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + for (i = 0; i < 64; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4135), i >> 4, i & 15); + settings_add_string(hdlg, IDC_COMBO_HD_ID, (LPARAM) lptsTemp); } - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); for (i = 0; i < 8; i++) { wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_HD_CHANNEL_IDE, (LPARAM) lptsTemp); } free(lptsTemp); @@ -2291,7 +2044,7 @@ next_free_scsi_id(uint8_t *id) { int64_t i; - for (i = 0; i < 16; i++) { + for (i = 0; i < 64; i++) { if (!(scsi_tracking[i >> 3] & (0xffLL << ((i & 0x07) << 3LL)))) { *id = i; return; @@ -2305,117 +2058,64 @@ next_free_scsi_id(uint8_t *id) static void recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) { - int i = 0; - HWND h; + int i = 0, bus = 0; - int bus = 0; - - for (i = IDT_1722; i <= IDT_1723; i++) { - h = GetDlgItem(hdlg, i); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - } - - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); + for (i = IDT_CHANNEL; i <= IDT_ID; i++) + settings_show_window(hdlg, i, FALSE); + settings_show_window(hdlg, IDC_COMBO_HD_CHANNEL, FALSE); + settings_show_window(hdlg, IDC_COMBO_HD_ID, FALSE); + settings_show_window(hdlg, IDC_COMBO_HD_CHANNEL_IDE, FALSE); if ((hd_listview_items > 0) || is_add_dlg) { - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - bus = SendMessage(h, CB_GETCURSEL, 0, 0); - bus++; + bus = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BUS) + 1; switch(bus) { case HDD_BUS_MFM: /* MFM */ - h = GetDlgItem(hdlg, IDT_1722); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_CHANNEL, TRUE); + settings_show_window(hdlg, IDC_COMBO_HD_CHANNEL, TRUE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); if (assign_id) temp_hdd[lv1_current_sel].mfm_channel = next_free_binary_channel(&mfm_tracking); - SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.mfm_channel : temp_hdd[lv1_current_sel].mfm_channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL, is_add_dlg ? new_hdd.mfm_channel : temp_hdd[lv1_current_sel].mfm_channel); break; case HDD_BUS_XTA: /* XTA */ - h = GetDlgItem(hdlg, IDT_1722); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_CHANNEL, TRUE); + settings_show_window(hdlg, IDC_COMBO_HD_CHANNEL, TRUE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); if (assign_id) temp_hdd[lv1_current_sel].xta_channel = next_free_binary_channel(&xta_tracking); - SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.xta_channel : temp_hdd[lv1_current_sel].xta_channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL, is_add_dlg ? new_hdd.xta_channel : temp_hdd[lv1_current_sel].xta_channel); break; case HDD_BUS_ESDI: /* ESDI */ - h = GetDlgItem(hdlg, IDT_1722); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_CHANNEL, TRUE); + settings_show_window(hdlg, IDC_COMBO_HD_CHANNEL, TRUE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); if (assign_id) temp_hdd[lv1_current_sel].esdi_channel = next_free_binary_channel(&esdi_tracking); - SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.esdi_channel : temp_hdd[lv1_current_sel].esdi_channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL, is_add_dlg ? new_hdd.esdi_channel : temp_hdd[lv1_current_sel].esdi_channel); break; case HDD_BUS_IDE: /* IDE */ - h = GetDlgItem(hdlg, IDT_1722); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + case HDD_BUS_ATAPI: /* ATAPI */ + settings_show_window(hdlg, IDT_CHANNEL, TRUE); + settings_show_window(hdlg, IDC_COMBO_HD_CHANNEL_IDE, TRUE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); if (assign_id) temp_hdd[lv1_current_sel].ide_channel = next_free_ide_channel(); - SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.ide_channel : temp_hdd[lv1_current_sel].ide_channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL_IDE, is_add_dlg ? new_hdd.ide_channel : temp_hdd[lv1_current_sel].ide_channel); break; case HDD_BUS_SCSI: /* SCSI */ - h = GetDlgItem(hdlg, IDT_1723); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDT_1724); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_ID, TRUE); + settings_show_window(hdlg, IDT_LUN, TRUE); + settings_show_window(hdlg, IDC_COMBO_HD_ID, TRUE); if (assign_id) next_free_scsi_id((uint8_t *) (is_add_dlg ? &(new_hdd.scsi_id) : &(temp_hdd[lv1_current_sel].scsi_id))); - - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.scsi_id : temp_hdd[lv1_current_sel].scsi_id, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_ID, is_add_dlg ? new_hdd.scsi_id : temp_hdd[lv1_current_sel].scsi_id); } } - if ((hd_listview_items == 0) && !is_add_dlg) { - h = GetDlgItem(hdlg, IDT_1721); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); - } else { - h = GetDlgItem(hdlg, IDT_1721); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - } + settings_show_window(hdlg, IDT_BUS, (hd_listview_items != 0) || is_add_dlg); + settings_show_window(hdlg, IDC_COMBO_HD_BUS, (hd_listview_items != 0) || is_add_dlg); } @@ -2423,12 +2123,13 @@ static int bus_full(uint64_t *tracking, int count) { int full = 0; + switch(count) { case 2: default: full = (*tracking & 0xFF00LL); full = full && (*tracking & 0x00FFLL); - return full; + break; case 8: full = (*tracking & 0xFF00000000000000LL); full = full && (*tracking & 0x00FF000000000000LL); @@ -2438,19 +2139,20 @@ bus_full(uint64_t *tracking, int count) full = full && (*tracking & 0x0000000000FF0000LL); full = full && (*tracking & 0x000000000000FF00LL); full = full && (*tracking & 0x00000000000000FFLL); - return full; + break; } + + return full; } static void recalc_next_free_id(HWND hdlg) { - HWND h; int i, enable_add = 0; int c_mfm = 0, c_esdi = 0; int c_xta = 0, c_ide = 0; - int c_scsi = 0; + int c_atapi = 0, c_scsi = 0; next_free_id = -1; @@ -2463,6 +2165,8 @@ recalc_next_free_id(HWND hdlg) c_xta++; else if (temp_hdd[i].bus == HDD_BUS_IDE) c_ide++; + else if (temp_hdd[i].bus == HDD_BUS_ATAPI) + c_atapi++; else if (temp_hdd[i].bus == HDD_BUS_SCSI) c_scsi++; } @@ -2476,7 +2180,7 @@ recalc_next_free_id(HWND hdlg) enable_add = enable_add || (next_free_id >= 0); enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_esdi < ESDI_NUM) || (c_xta < XTA_NUM) || - (c_ide < IDE_NUM) || (c_scsi < SCSI_NUM)); + (c_ide < IDE_NUM) || (c_ide < ATAPI_NUM) || (c_scsi < SCSI_NUM)); enable_add = enable_add && !bus_full(&mfm_tracking, 2); enable_add = enable_add && !bus_full(&esdi_tracking, 2); enable_add = enable_add && !bus_full(&xta_tracking, 2); @@ -2484,21 +2188,18 @@ recalc_next_free_id(HWND hdlg) for (i = 0; i < 2; i++) enable_add = enable_add && !bus_full(&(scsi_tracking[i]), 8); - h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD_NEW); - EnableWindow(h, enable_add ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD); - EnableWindow(h, enable_add ? TRUE : FALSE); - - h = GetDlgItem(hdlg, IDC_BUTTON_HDD_REMOVE); - EnableWindow(h, ((c_mfm == 0) && (c_esdi == 0) && (c_xta == 0) && (c_ide == 0) && (c_scsi == 0)) ? - FALSE : TRUE); + settings_enable_window(hdlg, IDC_BUTTON_HDD_ADD_NEW, enable_add); + settings_enable_window(hdlg, IDC_BUTTON_HDD_ADD, enable_add); + settings_enable_window(hdlg, IDC_BUTTON_HDD_REMOVE, + (c_mfm != 0) || (c_esdi != 0) || (c_xta != 0) || (c_ide != 0) || + (c_atapi != 0) || (c_scsi != 0)); } static void -win_settings_hard_disks_update_item(HWND hwndList, int i, int column) +win_settings_hard_disks_update_item(HWND hdlg, int i, int column) { + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); LVITEM lvI; WCHAR szText[256]; @@ -2522,17 +2223,21 @@ win_settings_hard_disks_update_item(HWND hwndList, int i, int column) case HDD_BUS_IDE: wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); break; + case HDD_BUS_ATAPI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; case HDD_BUS_SCSI: - wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id); + wsprintf(szText, plat_get_string(IDS_4613), temp_hdd[i].scsi_id >> 4, temp_hdd[i].scsi_id & 15); break; } lvI.pszText = szText; lvI.iImage = 0; } else if (column == 1) { - if (!wcsnicmp(temp_hdd[i].fn, usr_path, wcslen(usr_path))) - lvI.pszText = temp_hdd[i].fn + wcslen(usr_path); + if (!strnicmp(temp_hdd[i].fn, usr_path, strlen(usr_path))) + mbstoc16s(szText, temp_hdd[i].fn + strlen(usr_path), sizeof_w(szText)); else - lvI.pszText = temp_hdd[i].fn; + mbstoc16s(szText, temp_hdd[i].fn, sizeof_w(szText)); + lvI.pszText = szText; lvI.iImage = 0; } else if (column == 2) { wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].tracks); @@ -2558,11 +2263,14 @@ win_settings_hard_disks_update_item(HWND hwndList, int i, int column) static BOOL -win_settings_hard_disks_recalc_list(HWND hwndList) +win_settings_hard_disks_recalc_list(HWND hdlg) { LVITEM lvI; int i, j = 0; - WCHAR szText[256]; + WCHAR szText[256], usr_path_w[1024]; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + + mbstoc16s(usr_path_w, usr_path, sizeof_w(usr_path_w)); hd_listview_items = 0; lv1_current_sel = -1; @@ -2589,8 +2297,11 @@ win_settings_hard_disks_recalc_list(HWND hwndList) case HDD_BUS_IDE: wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); break; + case HDD_BUS_ATAPI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; case HDD_BUS_SCSI: - wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id); + wsprintf(szText, plat_get_string(IDS_4613), temp_hdd[i].scsi_id >> 4, temp_hdd[i].scsi_id & 15); break; } lvI.pszText = szText; @@ -2601,12 +2312,11 @@ win_settings_hard_disks_recalc_list(HWND hwndList) return FALSE; lvI.iSubItem = 1; - if (!wcsnicmp(temp_hdd[i].fn, usr_path, wcslen(usr_path))) - lvI.pszText = temp_hdd[i].fn + wcslen(usr_path); + if (!strnicmp(temp_hdd[i].fn, usr_path, strlen(usr_path))) + mbstoc16s(szText, temp_hdd[i].fn + strlen(usr_path), sizeof_w(szText)); else - lvI.pszText = temp_hdd[i].fn; - lvI.iItem = j; - lvI.iImage = 0; + mbstoc16s(szText, temp_hdd[i].fn, sizeof_w(szText)); + lvI.pszText = szText; if (ListView_SetItem(hwndList, &lvI) == -1) return FALSE; @@ -2614,8 +2324,6 @@ win_settings_hard_disks_recalc_list(HWND hwndList) lvI.iSubItem = 2; wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].tracks); lvI.pszText = szText; - lvI.iItem = j; - lvI.iImage = 0; if (ListView_SetItem(hwndList, &lvI) == -1) return FALSE; @@ -2623,8 +2331,6 @@ win_settings_hard_disks_recalc_list(HWND hwndList) lvI.iSubItem = 3; wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].hpc); lvI.pszText = szText; - lvI.iItem = j; - lvI.iImage = 0; if (ListView_SetItem(hwndList, &lvI) == -1) return FALSE; @@ -2632,8 +2338,6 @@ win_settings_hard_disks_recalc_list(HWND hwndList) lvI.iSubItem = 4; wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].spt); lvI.pszText = szText; - lvI.iItem = j; - lvI.iImage = 0; if (ListView_SetItem(hwndList, &lvI) == -1) return FALSE; @@ -2641,8 +2345,6 @@ win_settings_hard_disks_recalc_list(HWND hwndList) lvI.iSubItem = 5; wsprintf(szText, plat_get_string(IDS_4098), (temp_hdd[i].tracks * temp_hdd[i].hpc * temp_hdd[i].spt) >> 11); lvI.pszText = szText; - lvI.iItem = j; - lvI.iImage = 0; if (ListView_SetItem(hwndList, &lvI) == -1) return FALSE; @@ -2658,11 +2360,32 @@ win_settings_hard_disks_recalc_list(HWND hwndList) } +static void +win_settings_hard_disks_resize_columns(HWND hdlg) +{ + /* Bus, File, Cylinders, Heads, Sectors, Size */ + int iCol, width[C_COLUMNS_HARD_DISKS] = {104, 354, 50, 26, 32, 50}; + int total = 0; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + RECT r; + + GetWindowRect(hwndList, &r); + for (iCol = 0; iCol < (C_COLUMNS_HARD_DISKS - 1); iCol++) { + width[iCol] = MulDiv(width[iCol], dpi, 96); + total += width[iCol]; + ListView_SetColumnWidth(hwndList, iCol, MulDiv(width[iCol], dpi, 96)); + } + width[C_COLUMNS_HARD_DISKS - 1] = (r.right - r.left) - 4 - total; + ListView_SetColumnWidth(hwndList, C_COLUMNS_HARD_DISKS - 1, width[C_COLUMNS_HARD_DISKS - 1]); +} + + static BOOL -win_settings_hard_disks_init_columns(HWND hwndList) +win_settings_hard_disks_init_columns(HWND hdlg) { LVCOLUMN lvc; int iCol; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; @@ -2672,24 +2395,27 @@ win_settings_hard_disks_init_columns(HWND hwndList) switch(iCol) { case 0: /* Bus */ - lvc.cx = 135; + lvc.cx = 104; + lvc.fmt = LVCFMT_LEFT; + break; + case 1: /* File */ + lvc.cx = 354; lvc.fmt = LVCFMT_LEFT; break; case 2: /* Cylinders */ - lvc.cx = 41; + lvc.cx = 50; lvc.fmt = LVCFMT_RIGHT; break; case 3: /* Heads */ - case 4: /* Sectors */ - lvc.cx = 25; + lvc.cx = 26; lvc.fmt = LVCFMT_RIGHT; break; - case 1: /* File */ - lvc.cx = 150; - lvc.fmt = LVCFMT_LEFT; + case 4: /* Sectors */ + lvc.cx = 32; + lvc.fmt = LVCFMT_RIGHT; break; case 5: /* Size (MB) 8 */ - lvc.cx = 41; + lvc.cx = 50; lvc.fmt = LVCFMT_RIGHT; break; } @@ -2698,6 +2424,7 @@ win_settings_hard_disks_init_columns(HWND hwndList) return FALSE; } + win_settings_hard_disks_resize_columns(hdlg); return TRUE; } @@ -2716,16 +2443,6 @@ get_edit_box_contents(HWND hdlg, int id, uint32_t *val) } -static void -get_combo_box_selection(HWND hdlg, int id, uint32_t *val) -{ - HWND h; - - h = GetDlgItem(hdlg, id); - *val = SendMessage(h, CB_GETCURSEL, 0, 0); -} - - static void set_edit_box_contents(HWND hdlg, int id, uint32_t val) { @@ -2737,10 +2454,20 @@ set_edit_box_contents(HWND hdlg, int id, uint32_t val) SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(szText), (LPARAM) szText); } +static void set_edit_box_text_contents(HWND hdlg, int id, WCHAR* text) +{ + HWND h = GetDlgItem(hdlg, id); + SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(text), (LPARAM) text); +} + +static void get_edit_box_text_contents(HWND hdlg, int id, WCHAR* text_buffer, int buffer_size) +{ + HWND h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, (WPARAM) buffer_size, (LPARAM) text_buffer); +} static int hdconf_initialize_hdt_combo(HWND hdlg) { - HWND h; int i = 0; uint64_t temp_size = 0; uint32_t size_mb = 0; @@ -2748,19 +2475,18 @@ static int hdconf_initialize_hdt_combo(HWND hdlg) selection = 127; - h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); - for (i = 0; i < 127; i++) { + for (i = 0; i < 127; i++) { temp_size = ((uint64_t) hdd_table[i][0]) * hdd_table[i][1] * hdd_table[i][2]; size_mb = (uint32_t) (temp_size >> 11LL); wsprintf(szText, plat_get_string(IDS_2107), size_mb, hdd_table[i][0], hdd_table[i][1], hdd_table[i][2]); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + settings_add_string(hdlg, IDC_COMBO_HD_TYPE, (LPARAM) szText); if ((tracks == (int) hdd_table[i][0]) && (hpc == (int) hdd_table[i][1]) && (spt == (int) hdd_table[i][2])) selection = i; } - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4100)); - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4101)); - SendMessage(h, CB_SETCURSEL, selection, 0); + settings_add_string(hdlg, IDC_COMBO_HD_TYPE, win_get_string(IDS_4100)); + settings_add_string(hdlg, IDC_COMBO_HD_TYPE, win_get_string(IDS_4101)); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, selection); return selection; } @@ -2768,12 +2494,10 @@ static int hdconf_initialize_hdt_combo(HWND hdlg) static void recalc_selection(HWND hdlg) { - HWND h; int i = 0; selection = 127; - h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); - for (i = 0; i < 127; i++) { + for (i = 0; i < 127; i++) { if ((tracks == (int) hdd_table[i][0]) && (hpc == (int) hdd_table[i][1]) && (spt == (int) hdd_table[i][2])) @@ -2781,7 +2505,152 @@ recalc_selection(HWND hdlg) } if ((selection == 127) && (hpc == 16) && (spt == 63)) selection = 128; - SendMessage(h, CB_SETCURSEL, selection, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, selection); +} + +HWND vhd_progress_hdlg; + +static void vhd_progress_callback(uint32_t current_sector, uint32_t total_sectors) +{ + MSG msg; + HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); + SendMessage(h, PBM_SETPOS, (WPARAM) current_sector, (LPARAM) 0); + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +/* If the disk geometry requested in the 86Box GUI is not compatible with the internal VHD geometry, + * we adjust it to the next-largest size that is compatible. On average, this will be a difference + * of about 21 MB, and should only be necessary for VHDs larger than 31.5 GB, so should never be more + * than a tenth of a percent change in size. + */ +static void adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry) +{ + if (_86box_geometry->cyl <= 65535) { + vhd_geometry->cyl = _86box_geometry->cyl; + vhd_geometry->heads = _86box_geometry->heads; + vhd_geometry->spt = _86box_geometry->spt; + return; + } + + int desired_sectors = _86box_geometry->cyl * _86box_geometry->heads * _86box_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors += (85680 - remainder); + + _86box_geometry->cyl = desired_sectors / (16 * 63); + _86box_geometry->heads = 16; + _86box_geometry->spt = 63; + + vhd_geometry->cyl = desired_sectors / (16 * 255); + vhd_geometry->heads = 16; + vhd_geometry->spt = 255; +} + +static void adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) +{ + if (vhd_geometry->spt <= 63) + return; + + int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors -= remainder; + + vhd_geometry->cyl = desired_sectors / (16 * 63); + vhd_geometry->heads = 16; + vhd_geometry->spt = 63; +} + +static MVHDGeom create_drive_vhd_fixed(char* filename, int cyl, int heads, int spt) +{ + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + + HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); + settings_show_window(vhd_progress_hdlg, IDT_FILE_NAME, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_EDIT_HD_FILE_NAME, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_CFILE, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE, TRUE); + settings_enable_window(vhd_progress_hdlg, IDT_PROGRESS, TRUE); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) vhd_geometry.cyl * vhd_geometry.heads * vhd_geometry.spt); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + + int vhd_error = 0; + MVHDMeta *vhd = mvhd_create_fixed(filename, vhd_geometry, &vhd_error, vhd_progress_callback); + if (vhd == NULL) { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } else { + mvhd_close(vhd); + } + + return _86box_geometry; +} + +static MVHDGeom create_drive_vhd_dynamic(char* filename, int cyl, int heads, int spt, int blocksize) +{ + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filename; + options.size_in_bytes = 0; + options.geometry = vhd_geometry; + options.type = MVHD_TYPE_DYNAMIC; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + if (vhd == NULL) { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } else { + mvhd_close(vhd); + } + + return _86box_geometry; +} + +static MVHDGeom create_drive_vhd_diff(char* filename, char* parent_filename, int blocksize) +{ + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filename; + options.parent_path = parent_filename; + options.type = MVHD_TYPE_DIFF; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + MVHDGeom vhd_geometry; + if (vhd == NULL) { + vhd_geometry.cyl = 0; + vhd_geometry.heads = 0; + vhd_geometry.spt = 0; + } else { + vhd_geometry = mvhd_get_geometry(vhd); + + if (vhd_geometry.spt > 63) { + vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); + vhd_geometry.heads = 16; + vhd_geometry.spt = 63; + } + + mvhd_close(vhd); + } + + return vhd_geometry; } @@ -2792,21 +2661,26 @@ static BOOL CALLBACK #endif win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; - FILE *f; - uint32_t temp, i = 0, sector_size = 512; - uint32_t zero = 0, base = 0x1000; - uint64_t signature = 0xD778A82044445459ll; - uint64_t temp_size, r = 0; - char buf[512], *big_buf; - int b = 0; - uint8_t channel = 0; - uint8_t id = 0; - wchar_t *twcs; - vhd_footer_t *vft = NULL; - MSG msg; + HWND h; + FILE *f; + uint32_t temp, i = 0, sector_size = 512; + uint32_t zero = 0, base = 0x1000; + uint64_t signature = 0xD778A82044445459ll; + uint64_t r = 0; + char *big_buf; + char hd_file_name_multibyte[1200]; + int b = 0; + int vhd_error = 0; + uint8_t channel = 0; + uint8_t id = 0; + wchar_t *twcs; + int img_format, block_size; + WCHAR text_buf[256]; + RECT rect; + POINT point; + int dlg_height_adjust; - switch (message) { + switch (message) { case WM_INITDIALOG: memset(hd_file_name, 0, sizeof(hd_file_name)); @@ -2824,37 +2698,66 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM size = (tracks * hpc * spt) << 9; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20LL)); hdconf_initialize_hdt_combo(hdlg); + + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4122)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4123)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4124)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4125)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4126)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4127)); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT, 0); + + settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, win_get_string(IDS_4128)); + settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, win_get_string(IDS_4129)); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_BLOCK_SIZE, 0); + + settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, FALSE); + settings_show_window(hdlg, IDT_BLOCK_SIZE, FALSE); + if (existing & 1) { - h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); - EnableWindow(h, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, FALSE); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, FALSE); + settings_show_window(hdlg, IDC_COMBO_HD_IMG_FORMAT, FALSE); + settings_show_window(hdlg, IDT_IMG_FORMAT, FALSE); + + /* adjust window size */ + GetWindowRect(hdlg, &rect); + OffsetRect(&rect, -rect.left, -rect.top); + dlg_height_adjust = rect.bottom / 5; + SetWindowPos(hdlg, NULL, 0, 0, rect.right, rect.bottom - dlg_height_adjust, SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER); + h = GetDlgItem(hdlg, IDOK); + GetWindowRect(h, &rect); + point.x = rect.left; + point.y = rect.top; + ScreenToClient(hdlg, &point); + SetWindowPos(h, NULL, point.x, point.y - dlg_height_adjust, 0, 0, SWP_NOSIZE | SWP_NOREPOSITION | SWP_NOZORDER); + h = GetDlgItem(hdlg, IDCANCEL); + GetWindowRect(h, &rect); + point.x = rect.left; + point.y = rect.top; + ScreenToClient(hdlg, &point); + SetWindowPos(h, NULL, point.x, point.y - dlg_height_adjust, 0, 0, SWP_NOSIZE | SWP_NOREPOSITION | SWP_NOZORDER); + chs_enabled = 0; } else chs_enabled = 1; + add_locations(hdlg); - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); hdd_ptr->bus = HDD_BUS_IDE; max_spt = 63; max_hpc = 255; - SendMessage(h, CB_SETCURSEL, hdd_ptr->bus, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_BUS, hdd_ptr->bus - 1); max_tracks = 266305; recalc_location_controls(hdlg, 1, 0); channel = next_free_ide_channel(); next_free_scsi_id(&id); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - SendMessage(h, CB_SETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - SendMessage(h, CB_SETCURSEL, id, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); - SendMessage(h, CB_SETCURSEL, channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_ID, id); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL_IDE, channel); new_hdd.mfm_channel = next_free_binary_channel(&mfm_tracking); new_hdd.esdi_channel = next_free_binary_channel(&esdi_tracking); @@ -2862,25 +2765,17 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM new_hdd.ide_channel = channel; new_hdd.scsi_id = id; - h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDT_1752); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); + settings_enable_window(hdlg, IDC_EDIT_HD_FILE_NAME, FALSE); + settings_show_window(hdlg, IDT_PROGRESS, FALSE); + settings_show_window(hdlg, IDC_PBAR_IMG_CREATE, FALSE); no_update = 0; return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDOK: - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - hdd_ptr->bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + hdd_ptr->bus = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BUS) + 1; /* Make sure no file name is allowed with removable SCSI hard disks. */ if (wcslen(hd_file_name) == 0) { @@ -2898,42 +2793,43 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM switch(hdd_ptr->bus) { case HDD_BUS_MFM: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - hdd_ptr->mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hdd_ptr->mfm_channel = settings_get_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL); break; case HDD_BUS_ESDI: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - hdd_ptr->esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hdd_ptr->esdi_channel = settings_get_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL); break; case HDD_BUS_XTA: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - hdd_ptr->xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hdd_ptr->xta_channel = settings_get_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL); break; case HDD_BUS_IDE: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); - hdd_ptr->ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + case HDD_BUS_ATAPI: + hdd_ptr->ide_channel = settings_get_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL_IDE); break; case HDD_BUS_SCSI: - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - hdd_ptr->scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + hdd_ptr->scsi_id = settings_get_cur_sel(hdlg, IDC_COMBO_HD_ID); break; } memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); - wcscpy(hdd_ptr->fn, hd_file_name); + c16stombs(hdd_ptr->fn, hd_file_name, sizeof(hdd_ptr->fn)); + strcpy(hd_file_name_multibyte, hdd_ptr->fn); sector_size = 512; if (!(existing & 1) && (wcslen(hd_file_name) > 0)) { - f = _wfopen(hd_file_name, L"wb"); - if (size > 0x1FFFFFFE00ll) { - fclose(f); settings_msgbox_header(MBX_ERROR, (wchar_t *) IDS_4116, (wchar_t *) IDS_4105); - return TRUE; + return TRUE; } - if (image_is_hdi(hd_file_name)) { + img_format = settings_get_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT); + if (img_format < 3) { + f = _wfopen(hd_file_name, L"wb"); + } else { + f = (FILE *) 0; + } + + if (img_format == 1) { /* HDI file */ if (size >= 0x100000000ll) { fclose(f); settings_msgbox_header(MBX_ERROR, (wchar_t *) IDS_4116, (wchar_t *) IDS_4104); @@ -2951,7 +2847,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM for (i = 0; i < 0x3f8; i++) fwrite(&zero, 1, 4, f); - } else if (image_is_hdx(hd_file_name, 0)) { + } else if (img_format == 2) { /* HDX file */ fwrite(&signature, 1, 8, f); /* 00000000: Signature */ fwrite(&size, 1, 8, f); /* 00000008: Full size of the data (64-bit) */ fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ @@ -2960,78 +2856,81 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ fwrite(&zero, 1, 4, f); /* 00000020: [Translation] Sectors per cylinder */ fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ + } else if (img_format >= 3) { /* VHD file */ + MVHDGeom _86box_geometry; + block_size = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BLOCK_SIZE) == 0 ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL; + switch (img_format) { + case 3: + vhd_progress_hdlg = hdlg; + _86box_geometry = create_drive_vhd_fixed(hd_file_name_multibyte, tracks, hpc, spt); + break; + case 4: + _86box_geometry = create_drive_vhd_dynamic(hd_file_name_multibyte, tracks, hpc, spt, block_size); + break; + case 5: + if (file_dlg_w(hdlg, plat_get_string(IDS_4130), L"", plat_get_string(IDS_4131), 0)) { + return TRUE; + } + _86box_geometry = create_drive_vhd_diff(hd_file_name_multibyte, openfilestring, block_size); + break; + } + + if (img_format != 5) + settings_msgbox_header(MBX_INFO, (wchar_t *) IDS_4113, (wchar_t *) IDS_4117); + + hdd_ptr->tracks = _86box_geometry.cyl; + hdd_ptr->hpc = _86box_geometry.heads; + hdd_ptr->spt = _86box_geometry.spt; + + hard_disk_added = 1; + EndDialog(hdlg, 0); + return TRUE; } big_buf = (char *) malloc(1048576); memset(big_buf, 0, 1048576); - temp_size = size; - r = size >> 20; size &= 0xfffff; if (size || r) { - h = GetDlgItem(hdlg, IDT_1731); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_CFILE); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); + settings_show_window(hdlg, IDT_FILE_NAME, FALSE); + settings_show_window(hdlg, IDC_EDIT_HD_FILE_NAME, FALSE); + settings_show_window(hdlg, IDC_CFILE, FALSE); + settings_show_window(hdlg, IDC_PBAR_IMG_CREATE, TRUE); + settings_enable_window(hdlg, IDT_PROGRESS, TRUE); h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); - EnableWindow(h, TRUE); - ShowWindow(h, SW_SHOW); SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) r); SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); - - h = GetDlgItem(hdlg, IDT_1752); - EnableWindow(h, TRUE); - ShowWindow(h, SW_SHOW); } h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); if (size) { - fwrite(big_buf, 1, size, f); + if (f) { + fwrite(big_buf, 1, size, f); + } SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); } if (r) { for (i = 0; i < r; i++) { - fwrite(big_buf, 1, 1048576, f); + if (f) { + fwrite(big_buf, 1, 1048576, f); + } SendMessage(h, PBM_SETPOS, (WPARAM) (i + 1), (LPARAM) 0); - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } + settings_process_messages(); } } - if (image_is_vhd(hd_file_name, 0)) { - /* VHD image. */ - /* Generate new footer. */ - new_vhd_footer(&vft); - vft->orig_size = vft->curr_size = temp_size; - vft->geom.cyl = tracks; - vft->geom.heads = hpc; - vft->geom.spt = spt; - generate_vhd_checksum(vft); - vhd_footer_to_bytes((uint8_t *) big_buf, vft); - fwrite(big_buf, 1, 512, f); - free(vft); - vft = NULL; - } - free(big_buf); - fclose(f); - settings_msgbox_header(MBX_INFO, (wchar_t *) IDS_4113, (wchar_t *) IDS_4117); + if (f) { + fclose(f); + } + settings_msgbox_header(MBX_INFO, (wchar_t *) IDS_4113, (wchar_t *) IDS_4117); } hard_disk_added = 1; @@ -3045,7 +2944,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM return TRUE; case IDC_CFILE: - if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", !(existing & 1))) { + if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", NULL, !(existing & 1))) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { twcs = &wopenfilestring[wcslen(wopenfilestring)]; @@ -3073,7 +2972,7 @@ hdd_add_file_open_error: return TRUE; } if (existing & 1) { - if (image_is_hdi(wopenfilestring) || image_is_hdx(wopenfilestring, 1)) { + if (image_is_hdi(openfilestring) || image_is_hdx(openfilestring, 1)) { fseeko64(f, 0x10, SEEK_SET); fread(§or_size, 1, 4, f); if (sector_size != 512) { @@ -3085,17 +2984,33 @@ hdd_add_file_open_error: fread(&spt, 1, 4, f); fread(&hpc, 1, 4, f); fread(&tracks, 1, 4, f); - } else if (image_is_vhd(wopenfilestring, 1)) { - fseeko64(f, -512, SEEK_END); - fread(buf, 1, 512, f); - new_vhd_footer(&vft); - vhd_footer_from_bytes(vft, (uint8_t *) buf); - size = vft->orig_size; - tracks = vft->geom.cyl; - hpc = vft->geom.heads; - spt = vft->geom.spt; - free(vft); - vft = NULL; + } else if (image_is_vhd(openfilestring, 1)) { + fclose(f); + MVHDMeta* vhd = mvhd_open(openfilestring, 0, &vhd_error); + if (vhd == NULL) { + settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); + return TRUE; + } else if (vhd_error == MVHD_ERR_TIMESTAMP) { + if (settings_msgbox_ex(MBX_QUESTION_YN | MBX_WARNING, plat_get_string(IDS_4133), plat_get_string(IDS_4132), NULL, NULL, NULL) != 0) { + int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); + if (ts_res != 0) { + settings_msgbox_header(MBX_ERROR, plat_get_string(IDS_2049), plat_get_string(IDS_4134)); + mvhd_close(vhd); + return TRUE; + } + } else { + mvhd_close(vhd); + return TRUE; + } + } + + MVHDGeom vhd_geom = mvhd_get_geometry(vhd); + adjust_vhd_geometry_for_86box(&vhd_geom); + tracks = vhd_geom.cyl; + hpc = vhd_geom.heads; + spt = vhd_geom.spt; + size = (uint64_t)tracks * hpc * spt * 512; + mvhd_close(vhd); } else { fseeko64(f, 0, SEEK_END); size = ftello64(f); @@ -3123,7 +3038,7 @@ hdd_add_file_open_error: } if ((spt > max_spt) || (hpc > max_hpc) || (tracks > max_tracks)) - goto hdd_add_file_open_error; + goto hdd_add_file_open_error; no_update = 1; set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); @@ -3132,16 +3047,11 @@ hdd_add_file_open_error: set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); recalc_selection(hdlg); - h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); - EnableWindow(h, TRUE); + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, TRUE); + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, TRUE); + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, TRUE); + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, TRUE); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); chs_enabled = 1; @@ -3278,7 +3188,7 @@ hdd_add_file_open_error: return FALSE; no_update = 1; - get_combo_box_selection(hdlg, IDC_COMBO_HD_TYPE, &temp); + temp = settings_get_cur_sel(hdlg, IDC_COMBO_HD_TYPE); if ((temp != selection) && (temp != 127) && (temp != 128)) { selection = temp; tracks = hdd_table[selection][0]; @@ -3334,91 +3244,132 @@ hdd_add_file_open_error: no_update = 1; recalc_location_controls(hdlg, 1, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - b = SendMessage(h,CB_GETCURSEL,0,0) + 1; - if (b == hdd_ptr->bus) - goto hd_add_bus_skip; + b = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BUS) + 1; + if (b != hdd_ptr->bus) { + hdd_ptr->bus = b; - hdd_ptr->bus = b; + switch(hdd_ptr->bus) { + case HDD_BUS_DISABLED: + default: + max_spt = max_hpc = max_tracks = 0; + break; + case HDD_BUS_MFM: + max_spt = 26; /* 17 for MFM, 26 for RLL. */ + max_hpc = 15; + max_tracks = 2047; + break; + case HDD_BUS_XTA: + max_spt = 63; + max_hpc = 16; + max_tracks = 1023; + break; + case HDD_BUS_ESDI: + max_spt = 99; /* ESDI drives usually had 32 to 43 sectors per track. */ + max_hpc = 16; + max_tracks = 266305; + break; + case HDD_BUS_IDE: + max_spt = 63; + max_hpc = 255; + max_tracks = 266305; + break; + case HDD_BUS_ATAPI: + case HDD_BUS_SCSI: + max_spt = 99; + max_hpc = 255; + max_tracks = 266305; + break; + } - switch(hdd_ptr->bus) { - case HDD_BUS_DISABLED: - default: - max_spt = max_hpc = max_tracks = 0; - break; - case HDD_BUS_MFM: - max_spt = 26; /* 17 for MFM, 26 for RLL. */ - max_hpc = 15; - max_tracks = 2047; - break; - case HDD_BUS_XTA: - max_spt = 63; - max_hpc = 16; - max_tracks = 1023; - break; - case HDD_BUS_ESDI: - max_spt = 99; /* ESDI drives usually had 32 to 43 sectors per track. */ - max_hpc = 16; - max_tracks = 266305; - break; - case HDD_BUS_IDE: - max_spt = 63; - max_hpc = 255; - max_tracks = 266305; - break; - case HDD_BUS_SCSI: - max_spt = 99; - max_hpc = 255; - max_tracks = 266305; - break; + if (!chs_enabled) { + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, FALSE); + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, FALSE); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, FALSE); + } + + if (spt > max_spt) { + spt = max_spt; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } } - if (!chs_enabled) { - h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); - EnableWindow(h, FALSE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); - EnableWindow(h, FALSE); - } - - if (spt > max_spt) { - spt = max_spt; - size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); - recalc_selection(hdlg); - } - - if (hpc > max_hpc) { - hpc = max_hpc; - size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); - recalc_selection(hdlg); - } - - if (tracks > max_tracks) { - tracks = max_tracks; - size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); - recalc_selection(hdlg); - } - -hd_add_bus_skip: no_update = 0; break; + case IDC_COMBO_HD_IMG_FORMAT: + img_format = settings_get_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT); + + no_update = 1; + if (img_format == 5) { /* They switched to a diff VHD; disable the geometry fields. */ + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_SPT, L"(N/A)"); + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_HPC, L"(N/A)"); + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_CYL, L"(N/A)"); + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_SIZE, L"(N/A)"); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, FALSE); + settings_reset_content(hdlg, IDC_COMBO_HD_TYPE); + settings_add_string(hdlg, IDC_COMBO_HD_TYPE, (LPARAM) L"(use parent)"); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, 0); + } else { + get_edit_box_text_contents(hdlg, IDC_EDIT_HD_SPT, text_buf, 256); + if (!wcscmp(text_buf, L"(N/A)")) { + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, 17); + spt = 17; + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, 15); + hpc = 15; + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, 1023); + tracks = 1023; + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) ((uint64_t)17 * 15 * 1023 * 512 >> 20)); + size = (uint64_t)17 * 15 * 1023 * 512; + + settings_reset_content(hdlg, IDC_COMBO_HD_TYPE); + hdconf_initialize_hdt_combo(hdlg); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); + } + } + no_update = 0; + + if (img_format == 4 || img_format == 5) { /* For dynamic and diff VHDs, show the block size dropdown. */ + settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, TRUE); + settings_show_window(hdlg, IDT_BLOCK_SIZE, TRUE); + } else { /* Hide it otherwise. */ + settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, FALSE); + settings_show_window(hdlg, IDT_BLOCK_SIZE, FALSE); + } + break; } return FALSE; - } + } - return FALSE; + return FALSE; } @@ -3452,6 +3403,7 @@ hard_disk_track(uint8_t id) xta_tracking |= (1 << (temp_hdd[id].xta_channel << 3)); break; case HDD_BUS_IDE: + case HDD_BUS_ATAPI: ide_tracking |= (1 << (temp_hdd[id].ide_channel << 3)); break; case HDD_BUS_SCSI: @@ -3475,6 +3427,7 @@ hard_disk_untrack(uint8_t id) xta_tracking &= ~(1 << (temp_hdd[id].xta_channel << 3)); break; case HDD_BUS_IDE: + case HDD_BUS_ATAPI: ide_tracking &= ~(1 << (temp_hdd[id].ide_channel << 3)); break; case HDD_BUS_SCSI: @@ -3501,9 +3454,8 @@ static BOOL CALLBACK #endif win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h = NULL; int old_sel = 0, b = 0, assign = 0; - const uint8_t hd_icons[2] = { 64, 0 }; + const uint8_t hd_icons[2] = { 80, 0 }; switch (message) { case WM_INITDIALOG: @@ -3512,21 +3464,21 @@ win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPar normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. This will cause an emulator reset prompt on the first opening of this category with a messy hard disk list (which can only happen by manually editing the configuration file). */ - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_init_columns(h); - image_list_init(h, (const uint8_t *) hd_icons); - win_settings_hard_disks_recalc_list(h); + win_settings_hard_disks_init_columns(hdlg); + image_list_init(hdlg, IDC_LIST_HARD_DISKS, (const uint8_t *) hd_icons); + win_settings_hard_disks_recalc_list(hdlg); recalc_next_free_id(hdlg); add_locations(hdlg); if (hd_listview_items > 0) { - ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + settings_listview_select(hdlg, IDC_LIST_HARD_DISKS, 0); lv1_current_sel = 0; - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - SendMessage(h, CB_SETCURSEL, temp_hdd[0].bus - 1, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_BUS, temp_hdd[0].bus - 1); } else lv1_current_sel = -1; recalc_location_controls(hdlg, 0, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_HARD_DISKS); + ignore_change = 0; return TRUE; @@ -3539,16 +3491,8 @@ win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPar lv1_current_sel = get_selected_hard_disk(hdlg); if (lv1_current_sel == old_sel) return FALSE; - else if (lv1_current_sel == -1) { - ignore_change = 1; - lv1_current_sel = old_sel; - ListView_SetItemState(h, lv1_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); - ignore_change = 0; - return FALSE; - } ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - SendMessage(h, CB_SETCURSEL, temp_hdd[lv1_current_sel].bus - 1, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_BUS, temp_hdd[lv1_current_sel].bus - 1); recalc_location_controls(hdlg, 0, 0); ignore_change = 0; } @@ -3558,80 +3502,54 @@ win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPar if (ignore_change && (LOWORD(wParam) != IDC_BUTTON_HDD_ADD) && (LOWORD(wParam) != IDC_BUTTON_HDD_ADD_NEW) && (LOWORD(wParam) != IDC_BUTTON_HDD_REMOVE)) return FALSE; - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_COMBO_HD_BUS: ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - b = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; - if (b == temp_hdd[lv1_current_sel].bus) - goto hd_bus_skip; - hard_disk_untrack(lv1_current_sel); - assign = (temp_hdd[lv1_current_sel].bus == b) ? 0 : 1; - temp_hdd[lv1_current_sel].bus = b; - recalc_location_controls(hdlg, 0, assign); - hard_disk_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_update_item(h, lv1_current_sel, 0); -hd_bus_skip: + b = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BUS) + 1; + if (b != temp_hdd[lv1_current_sel].bus) { + hard_disk_untrack(lv1_current_sel); + assign = (temp_hdd[lv1_current_sel].bus == b) ? 0 : 1; + temp_hdd[lv1_current_sel].bus = b; + recalc_location_controls(hdlg, 0, assign); + hard_disk_track(lv1_current_sel); + win_settings_hard_disks_update_item(hdlg, lv1_current_sel, 0); + } ignore_change = 0; return FALSE; case IDC_COMBO_HD_CHANNEL: ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); hard_disk_untrack(lv1_current_sel); - if (temp_hdd[lv1_current_sel].bus == HDD_BUS_MFM) - temp_hdd[lv1_current_sel].mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - else if (temp_hdd[lv1_current_sel].bus == HDD_BUS_ESDI) - temp_hdd[lv1_current_sel].esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - else if (temp_hdd[lv1_current_sel].bus == HDD_BUS_XTA) - temp_hdd[lv1_current_sel].xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_hdd[lv1_current_sel].channel = settings_get_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL); hard_disk_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_update_item(h, lv1_current_sel, 0); + win_settings_hard_disks_update_item(hdlg, lv1_current_sel, 0); ignore_change = 0; return FALSE; case IDC_COMBO_HD_CHANNEL_IDE: ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); hard_disk_untrack(lv1_current_sel); - temp_hdd[lv1_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_hdd[lv1_current_sel].ide_channel = settings_get_cur_sel(hdlg, IDC_COMBO_HD_CHANNEL_IDE); hard_disk_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_update_item(h, lv1_current_sel, 0); + win_settings_hard_disks_update_item(hdlg, lv1_current_sel, 0); ignore_change = 0; return FALSE; case IDC_COMBO_HD_ID: ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); hard_disk_untrack(lv1_current_sel); - temp_hdd[lv1_current_sel].scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_hdd[lv1_current_sel].scsi_id = settings_get_cur_sel(hdlg, IDC_COMBO_HD_ID); hard_disk_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_update_item(h, lv1_current_sel, 0); + win_settings_hard_disks_update_item(hdlg, lv1_current_sel, 0); ignore_change = 0; return FALSE; case IDC_BUTTON_HDD_ADD: - hard_disk_add_open(hdlg, 1); - if (hard_disk_added) { - ignore_change = 1; - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_recalc_list(h); - recalc_next_free_id(hdlg); - hard_disk_track_all(); - ignore_change = 0; - } - return FALSE; - case IDC_BUTTON_HDD_ADD_NEW: - hard_disk_add_open(hdlg, 0); + hard_disk_add_open(hdlg, (LOWORD(wParam) == IDC_BUTTON_HDD_ADD)); if (hard_disk_added) { ignore_change = 1; - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_recalc_list(h); + win_settings_hard_disks_recalc_list(hdlg); recalc_next_free_id(hdlg); hard_disk_track_all(); ignore_change = 0; @@ -3639,19 +3557,17 @@ hd_bus_skip: return FALSE; case IDC_BUTTON_HDD_REMOVE: - memcpy(temp_hdd[lv1_current_sel].fn, L"", sizeof(L"")); + temp_hdd[lv1_current_sel].fn[0] = '\0'; hard_disk_untrack(lv1_current_sel); temp_hdd[lv1_current_sel].bus = HDD_BUS_DISABLED; /* Only set the bus to zero, the list normalize code below will take care of turning this entire entry to a complete zero. */ normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. */ ignore_change = 1; - h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); - win_settings_hard_disks_recalc_list(h); + win_settings_hard_disks_recalc_list(hdlg); recalc_next_free_id(hdlg); if (hd_listview_items > 0) { - ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + settings_listview_select(hdlg, IDC_LIST_HARD_DISKS, 0); lv1_current_sel = 0; - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - SendMessage(h, CB_SETCURSEL, temp_hdd[0].bus - 1, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_BUS, temp_hdd[0].bus - 1); } else lv1_current_sel = -1; recalc_location_controls(hdlg, 0, 0); @@ -3659,6 +3575,10 @@ hd_bus_skip: return FALSE; } + case WM_DPICHANGED_AFTERPARENT: + win_settings_hard_disks_resize_columns(hdlg); + image_list_init(hdlg, IDC_LIST_HARD_DISKS, (const uint8_t *) hd_icons); + break; default: return FALSE; } @@ -3682,12 +3602,13 @@ combo_id_to_format_string_id(int combo_id) static BOOL -win_settings_floppy_drives_recalc_list(HWND hwndList) +win_settings_floppy_drives_recalc_list(HWND hdlg) { LVITEM lvI; int i = 0; char s[256], *t; WCHAR szText[256]; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.state = 0; @@ -3696,10 +3617,7 @@ win_settings_floppy_drives_recalc_list(HWND hwndList) lvI.iSubItem = 0; if (temp_fdd_types[i] > 0) { t = fdd_getname(temp_fdd_types[i]); - if (strlen(t) <= 256) - strcpy(s, t); - else - strncpy(s, t, 256); + strncpy(s, t, sizeof(s) - 1); mbstowcs(szText, s, strlen(s) + 1); lvI.pszText = szText; } else @@ -3732,14 +3650,15 @@ win_settings_floppy_drives_recalc_list(HWND hwndList) static BOOL -win_settings_cdrom_drives_recalc_list(HWND hwndList) +win_settings_cdrom_drives_recalc_list(HWND hdlg) { LVITEM lvI; int i = 0, fsid = 0; WCHAR szText[256]; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; - lvI.stateMask = lvI.iSubItem = lvI.state = 0; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; for (i = 0; i < 4; i++) { fsid = combo_id_to_format_string_id(temp_cdrom[i].bus_type); @@ -3757,7 +3676,7 @@ win_settings_cdrom_drives_recalc_list(HWND hwndList) lvI.iImage = 1; break; case CDROM_BUS_SCSI: - wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id); + wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id >> 4, temp_cdrom[i].scsi_device_id & 15); lvI.pszText = szText; lvI.iImage = 1; break; @@ -3787,16 +3706,81 @@ win_settings_cdrom_drives_recalc_list(HWND hwndList) static BOOL -win_settings_zip_drives_recalc_list(HWND hwndList) +win_settings_mo_drives_recalc_list(HWND hdlg) { LVITEM lvI; int i = 0, fsid = 0; WCHAR szText[256]; + char szType[30]; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < MO_NUM; i++) { + fsid = combo_id_to_format_string_id(temp_mo_drives[i].bus_type); + + lvI.iSubItem = 0; + switch (temp_mo_drives[i].bus_type) { + case MO_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case MO_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_mo_drives[i].ide_channel >> 1, temp_mo_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case MO_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_mo_drives[i].scsi_device_id >> 4, temp_mo_drives[i].scsi_device_id & 15); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + lvI.iItem = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + if (temp_mo_drives[i].bus_type == MO_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2103); + else { + memset(szType, 0, 30); + memcpy(szType, mo_drive_types[temp_mo_drives[i].type].vendor, 8); + szType[strlen(szType)] = ' '; + memcpy(szType + strlen(szType), mo_drive_types[temp_mo_drives[i].type].model, 16); + szType[strlen(szType)] = ' '; + memcpy(szType + strlen(szType), mo_drive_types[temp_mo_drives[i].type].revision, 4); + + mbstowcs(szText, szType, strlen(szType)+1); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_zip_drives_recalc_list(HWND hdlg) +{ + LVITEM lvI; + int i = 0, fsid = 0; + WCHAR szText[256]; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.iSubItem = lvI.state = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < ZIP_NUM; i++) { fsid = combo_id_to_format_string_id(temp_zip_drives[i].bus_type); lvI.iSubItem = 0; @@ -3812,7 +3796,7 @@ win_settings_zip_drives_recalc_list(HWND hwndList) lvI.iImage = 1; break; case ZIP_BUS_SCSI: - wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id); + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id >> 4, temp_zip_drives[i].scsi_device_id & 15); lvI.pszText = szText; lvI.iImage = 1; break; @@ -3836,10 +3820,30 @@ win_settings_zip_drives_recalc_list(HWND hwndList) } +static void +win_settings_floppy_drives_resize_columns(HWND hdlg) +{ + int iCol, width[3] = {292, 58, 89}; + int total = 0; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + RECT r; + + GetWindowRect(hwndList, &r); + for (iCol = 0; iCol < 2; iCol++) { + width[iCol] = MulDiv(width[iCol], dpi, 96); + total += width[iCol]; + ListView_SetColumnWidth(hwndList, iCol, MulDiv(width[iCol], dpi, 96)); + } + width[2] = (r.right - r.left) - 4 - total; + ListView_SetColumnWidth(hwndList, 2, width[2]); +} + + static BOOL -win_settings_floppy_drives_init_columns(HWND hwndList) +win_settings_floppy_drives_init_columns(HWND hdlg) { LVCOLUMN lvc; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; @@ -3855,7 +3859,7 @@ win_settings_floppy_drives_init_columns(HWND hwndList) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2059); - lvc.cx = 50; + lvc.cx = 58; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) @@ -3864,27 +3868,44 @@ win_settings_floppy_drives_init_columns(HWND hwndList) lvc.iSubItem = 2; lvc.pszText = plat_get_string(IDS_2087); - lvc.cx = 75; + lvc.cx = 89; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 2, &lvc) == -1) - return FALSE; + return FALSE; + win_settings_floppy_drives_resize_columns(hdlg); return TRUE; } +static void +win_settings_cdrom_drives_resize_columns(HWND hdlg) +{ + int width[2] = {292, 147}; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + RECT r; + + GetWindowRect(hwndList, &r); + width[0] = MulDiv(width[0], dpi, 96); + ListView_SetColumnWidth(hwndList, 0, MulDiv(width[0], dpi, 96)); + width[1] = (r.right - r.left) - 4 - width[0]; + ListView_SetColumnWidth(hwndList, 1, width[1]); +} + + static BOOL -win_settings_cdrom_drives_init_columns(HWND hwndList) +win_settings_cdrom_drives_init_columns(HWND hdlg) { LVCOLUMN lvc; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2081); - lvc.cx = 342; + lvc.cx = 292; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3893,27 +3914,44 @@ win_settings_cdrom_drives_init_columns(HWND hwndList) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2053); - lvc.cx = 50; + lvc.cx = 147; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) - return FALSE; + return FALSE; + win_settings_cdrom_drives_resize_columns(hdlg); return TRUE; } +static void +win_settings_mo_drives_resize_columns(HWND hdlg) +{ + int width[2] = {292, 147}; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); + RECT r; + + GetWindowRect(hwndList, &r); + width[0] = MulDiv(width[0], dpi, 96); + ListView_SetColumnWidth(hwndList, 0, MulDiv(width[0], dpi, 96)); + width[1] = (r.right - r.left) - 4 - width[0]; + ListView_SetColumnWidth(hwndList, 1, width[1]); +} + + static BOOL -win_settings_zip_drives_init_columns(HWND hwndList) +win_settings_mo_drives_init_columns(HWND hdlg) { LVCOLUMN lvc; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2081); - lvc.cx = 342; + lvc.cx = 292; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3922,12 +3960,59 @@ win_settings_zip_drives_init_columns(HWND hwndList) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2092); - lvc.cx = 50; + lvc.cx = 147; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + win_settings_mo_drives_resize_columns(hdlg); + return TRUE; +} + + +static void +win_settings_zip_drives_resize_columns(HWND hdlg) +{ + int width[2] = {292, 147}; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + RECT r; + + GetWindowRect(hwndList, &r); + width[0] = MulDiv(width[0], dpi, 96); + ListView_SetColumnWidth(hwndList, 0, MulDiv(width[0], dpi, 96)); + width[1] = (r.right - r.left) - 4 - width[0]; + ListView_SetColumnWidth(hwndList, 1, width[1]); +} + + +static BOOL +win_settings_zip_drives_init_columns(HWND hdlg) +{ + LVCOLUMN lvc; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2081); + + lvc.cx = 292; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) return FALSE; + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2092); + + lvc.cx = 147; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + win_settings_zip_drives_resize_columns(hdlg); return TRUE; } @@ -3951,11 +4036,12 @@ get_selected_drive(HWND hdlg, int id) static void -win_settings_floppy_drives_update_item(HWND hwndList, int i) +win_settings_floppy_drives_update_item(HWND hdlg, int i) { LVITEM lvI; char s[256], *t; WCHAR szText[256]; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.iSubItem = lvI.state = 0; @@ -3965,10 +4051,7 @@ win_settings_floppy_drives_update_item(HWND hwndList, int i) if (temp_fdd_types[i] > 0) { t = fdd_getname(temp_fdd_types[i]); - if (strlen(t) <= 256) - strcpy(s, t); - else - strncpy(s, t, 256); + strncpy(s, t, sizeof(s) - 1); mbstowcs(szText, s, strlen(s) + 1); lvI.pszText = szText; } else @@ -3997,11 +4080,12 @@ win_settings_floppy_drives_update_item(HWND hwndList, int i) static void -win_settings_cdrom_drives_update_item(HWND hwndList, int i) +win_settings_cdrom_drives_update_item(HWND hdlg, int i) { LVITEM lvI; WCHAR szText[256]; int fsid; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.iSubItem = lvI.state = 0; @@ -4023,7 +4107,7 @@ win_settings_cdrom_drives_update_item(HWND hwndList, int i) lvI.iImage = 1; break; case CDROM_BUS_SCSI: - wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id); + wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id >> 4, temp_cdrom[i].scsi_device_id & 15); lvI.pszText = szText; lvI.iImage = 1; break; @@ -4048,11 +4132,71 @@ win_settings_cdrom_drives_update_item(HWND hwndList, int i) static void -win_settings_zip_drives_update_item(HWND hwndList, int i) +win_settings_mo_drives_update_item(HWND hdlg, int i) +{ + LVITEM lvI; + WCHAR szText[256]; + char szType[30]; + int fsid; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_mo_drives[i].bus_type); + + switch (temp_mo_drives[i].bus_type) { + case MO_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case MO_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_mo_drives[i].ide_channel >> 1, temp_mo_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case MO_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_mo_drives[i].scsi_device_id >> 4, temp_mo_drives[i].scsi_device_id & 15); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + if (temp_mo_drives[i].bus_type == MO_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2103); + else { + memset(szType, 0, 30); + memcpy(szType, mo_drive_types[temp_mo_drives[i].type].vendor, 8); + szType[strlen(szType)] = ' '; + memcpy(szType + strlen(szType), mo_drive_types[temp_mo_drives[i].type].model, 16); + szType[strlen(szType)] = ' '; + memcpy(szType + strlen(szType), mo_drive_types[temp_mo_drives[i].type].revision, 4); + mbstowcs(szText, szType, strlen(szType)+1); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +win_settings_zip_drives_update_item(HWND hdlg, int i) { LVITEM lvI; WCHAR szText[256]; int fsid; + HWND hwndList = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.iSubItem = lvI.state = 0; @@ -4074,7 +4218,7 @@ win_settings_zip_drives_update_item(HWND hwndList, int i) lvI.iImage = 1; break; case ZIP_BUS_SCSI: - wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id); + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id >> 4, temp_zip_drives[i].scsi_device_id & 15); lvI.pszText = szText; lvI.iImage = 1; break; @@ -4097,105 +4241,149 @@ static void cdrom_add_locations(HWND hdlg) { LPTSTR lptsTemp; - HWND h; int i = 0; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI)) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); + settings_add_string(hdlg, IDC_COMBO_CD_BUS, win_get_string(combo_id_to_string_id(i))); } - h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); for (i = 1; i <= 72; i++) { wsprintf(lptsTemp, L"%ix", i); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_CD_SPEED, (LPARAM) lptsTemp); } - h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); - for (i = 0; i < 16; i++) { - wsprintf(lptsTemp, plat_get_string(IDS_4098), i); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + for (i = 0; i < 64; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4135), i >> 4, i & 15); + settings_add_string(hdlg, IDC_COMBO_CD_ID, (LPARAM) lptsTemp); } - h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); for (i = 0; i < 8; i++) { wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_CD_CHANNEL_IDE, (LPARAM) lptsTemp); } free(lptsTemp); } -static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) +static void +cdrom_recalc_location_controls(HWND hdlg, int assign_id) { int i = 0; - HWND h; + int bus = temp_cdrom[lv2_current_sel].bus_type; - int bus = temp_cdrom[lv1_current_sel].bus_type; + for (i = IDT_CD_ID; i <= (IDT_CD_LUN); i++) + settings_show_window(hdlg, i, FALSE); + settings_show_window(hdlg, IDC_COMBO_CD_ID, FALSE); + settings_show_window(hdlg, IDC_COMBO_CD_CHANNEL_IDE, FALSE); + settings_show_window(hdlg, IDC_COMBO_CD_SPEED, bus != CDROM_BUS_DISABLED); + settings_show_window(hdlg, IDT_CD_SPEED, bus != CDROM_BUS_DISABLED); - for (i = IDT_1741; i < (IDT_1742 + 1); i++) { - h = GetDlgItem(hdlg, i); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - } - - h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); - if (bus == CDROM_BUS_DISABLED) { - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - } else { - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].speed - 1, 0); - } - - h = GetDlgItem(hdlg, IDT_1758); - if (bus == CDROM_BUS_DISABLED) { - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - } else { - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - } + if (bus != CDROM_BUS_DISABLED) + settings_set_cur_sel(hdlg, IDC_COMBO_CD_SPEED, temp_cdrom[lv2_current_sel].speed - 1); switch(bus) { case CDROM_BUS_ATAPI: /* ATAPI */ - h = GetDlgItem(hdlg, IDT_1742); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_CD_LUN, TRUE); + settings_show_window(hdlg, IDC_COMBO_CD_CHANNEL_IDE, TRUE); if (assign_id) - temp_cdrom[lv1_current_sel].ide_channel = next_free_ide_channel(); + temp_cdrom[lv2_current_sel].ide_channel = next_free_ide_channel(); - h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].ide_channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_CD_CHANNEL_IDE, temp_cdrom[lv2_current_sel].ide_channel); break; case CDROM_BUS_SCSI: /* SCSI */ - h = GetDlgItem(hdlg, IDT_1741); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_CD_ID, TRUE); + settings_show_window(hdlg, IDC_COMBO_CD_ID, TRUE); if (assign_id) - next_free_scsi_id((uint8_t *) &temp_cdrom[lv1_current_sel].scsi_device_id); + next_free_scsi_id((uint8_t *) &temp_cdrom[lv2_current_sel].scsi_device_id); - h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].scsi_device_id, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_CD_ID, temp_cdrom[lv2_current_sel].scsi_device_id); + break; + } +} + + +static void +mo_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + char *temp; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + temp = (char*) malloc(30*sizeof(char)); + + for (i = MO_BUS_DISABLED; i <= MO_BUS_SCSI; i++) { + if ((i == MO_BUS_DISABLED) || (i >= MO_BUS_ATAPI)) + settings_add_string(hdlg, IDC_COMBO_MO_BUS, win_get_string(combo_id_to_string_id(i))); + } + + for (i = 0; i < 64; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4135), i >> 4, i & 15); + settings_add_string(hdlg, IDC_COMBO_MO_ID, (LPARAM) lptsTemp); + } + + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + settings_add_string(hdlg, IDC_COMBO_MO_CHANNEL_IDE, (LPARAM) lptsTemp); + } + + for (int i = 0; i < KNOWN_MO_DRIVE_TYPES; i++) { + memset(temp, 0, 30); + memcpy(temp, mo_drive_types[i].vendor, 8); + temp[strlen(temp)] = ' '; + memcpy(temp + strlen(temp), mo_drive_types[i].model, 16); + temp[strlen(temp)] = ' '; + memcpy(temp + strlen(temp), mo_drive_types[i].revision, 4); + + mbstowcs(lptsTemp, temp, strlen(temp)+1); + settings_add_string(hdlg, IDC_COMBO_MO_TYPE, (LPARAM) lptsTemp); + } + + free(temp); + free(lptsTemp); +} + + +static void +mo_recalc_location_controls(HWND hdlg, int assign_id) +{ + int i = 0; + int bus = temp_mo_drives[lv1_current_sel].bus_type; + + for (i = IDT_MO_ID; i <= (IDT_MO_CHANNEL); i++) + settings_show_window(hdlg, i, FALSE); + settings_show_window(hdlg, IDC_COMBO_MO_ID, FALSE); + settings_show_window(hdlg, IDC_COMBO_MO_CHANNEL_IDE, FALSE); + settings_show_window(hdlg, IDC_COMBO_MO_TYPE, bus != MO_BUS_DISABLED); + settings_show_window(hdlg, IDT_MO_TYPE, bus != MO_BUS_DISABLED); + + if (bus != MO_BUS_DISABLED) + settings_set_cur_sel(hdlg, IDC_COMBO_MO_TYPE, temp_mo_drives[lv1_current_sel].type); + + switch(bus) { + case MO_BUS_ATAPI: /* ATAPI */ + settings_show_window(hdlg, IDT_MO_CHANNEL, TRUE); + settings_show_window(hdlg, IDC_COMBO_MO_CHANNEL_IDE, TRUE); + + if (assign_id) + temp_mo_drives[lv1_current_sel].ide_channel = next_free_ide_channel(); + + settings_set_cur_sel(hdlg, IDC_COMBO_MO_CHANNEL_IDE, temp_mo_drives[lv1_current_sel].ide_channel); + break; + case MO_BUS_SCSI: /* SCSI */ + settings_show_window(hdlg, IDT_MO_ID, TRUE); + settings_show_window(hdlg, IDC_COMBO_MO_ID, TRUE); + + if (assign_id) + next_free_scsi_id((uint8_t *) &temp_mo_drives[lv1_current_sel].scsi_device_id); + + settings_set_cur_sel(hdlg, IDC_COMBO_MO_ID, temp_mo_drives[lv1_current_sel].scsi_device_id); break; } } @@ -4205,27 +4393,23 @@ static void zip_add_locations(HWND hdlg) { LPTSTR lptsTemp; - HWND h; int i = 0; lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); for (i = ZIP_BUS_DISABLED; i <= ZIP_BUS_SCSI; i++) { if ((i == ZIP_BUS_DISABLED) || (i >= ZIP_BUS_ATAPI)) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); + settings_add_string(hdlg, IDC_COMBO_ZIP_BUS, win_get_string(combo_id_to_string_id(i))); } - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); - for (i = 0; i < 16; i++) { - wsprintf(lptsTemp, plat_get_string(IDS_4098), i); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + for (i = 0; i < 64; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4135), i >> 4, i & 15); + settings_add_string(hdlg, IDC_COMBO_ZIP_ID, (LPARAM) lptsTemp); } - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); for (i = 0; i < 8; i++) { wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + settings_add_string(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE, (LPARAM) lptsTemp); } free(lptsTemp); @@ -4236,60 +4420,36 @@ static void zip_recalc_location_controls(HWND hdlg, int assign_id) { int i = 0; - HWND h; int bus = temp_zip_drives[lv2_current_sel].bus_type; - for (i = IDT_1754; i < (IDT_1755 + 1); i++) { - h = GetDlgItem(hdlg, i); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - } + for (i = IDT_ZIP_ID; i <= (IDT_ZIP_LUN); i++) + settings_show_window(hdlg, i, FALSE); + settings_show_window(hdlg, IDC_COMBO_ZIP_ID, FALSE); + settings_show_window(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE, FALSE); + settings_show_window(hdlg, IDC_CHECK250, bus != ZIP_BUS_DISABLED); - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - h = GetDlgItem(hdlg, IDC_CHECK250); - if (bus == ZIP_BUS_DISABLED) { - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - } else { - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, BM_SETCHECK, temp_zip_drives[lv2_current_sel].is_250, 0); - } + if (bus != ZIP_BUS_DISABLED) + settings_set_check(hdlg, IDC_CHECK250, temp_zip_drives[lv2_current_sel].is_250); switch(bus) { case ZIP_BUS_ATAPI: /* ATAPI */ - h = GetDlgItem(hdlg, IDT_1755); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_ZIP_LUN, TRUE); + settings_show_window(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE, TRUE); if (assign_id) temp_zip_drives[lv2_current_sel].ide_channel = next_free_ide_channel(); - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_zip_drives[lv2_current_sel].ide_channel, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE, temp_zip_drives[lv2_current_sel].ide_channel); break; case ZIP_BUS_SCSI: /* SCSI */ - h = GetDlgItem(hdlg, IDT_1754); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); + settings_show_window(hdlg, IDT_ZIP_ID, TRUE); + settings_show_window(hdlg, IDC_COMBO_ZIP_ID, TRUE); if (assign_id) next_free_scsi_id((uint8_t *) &temp_zip_drives[lv2_current_sel].scsi_device_id); - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); - ShowWindow(h, SW_SHOW); - EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_zip_drives[lv2_current_sel].scsi_device_id, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_ZIP_ID, temp_zip_drives[lv2_current_sel].scsi_device_id); break; } } @@ -4335,44 +4495,86 @@ zip_untrack(uint8_t id) } +static void +mo_track(uint8_t id) +{ + if (temp_mo_drives[id].bus_type == MO_BUS_ATAPI) + ide_tracking |= (1 << (temp_zip_drives[id].ide_channel << 3)); + else if (temp_mo_drives[id].bus_type == MO_BUS_SCSI) + scsi_tracking[temp_mo_drives[id].scsi_device_id >> 3] |= (1 << (temp_mo_drives[id].scsi_device_id & 0x07)); +} + + +static void +mo_untrack(uint8_t id) +{ + if (temp_mo_drives[id].bus_type == MO_BUS_ATAPI) + ide_tracking &= ~(1 << (temp_zip_drives[id].ide_channel << 3)); + else if (temp_mo_drives[id].bus_type == MO_BUS_SCSI) + scsi_tracking[temp_mo_drives[id].scsi_device_id >> 3] &= ~(1 << (temp_mo_drives[id].scsi_device_id & 0x07)); +} + + #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif -win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +win_settings_floppy_and_cdrom_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h = NULL; - int i = 0, old_sel = 0; + int i = 0, old_sel = 0, b = 0, assign = 0; + uint32_t b2 = 0; WCHAR szText[256]; const uint8_t fd_icons[15] = { 248, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 0 }; + const uint8_t cd_icons[3] = { 249, 32, 0 }; switch (message) { case WM_INITDIALOG: ignore_change = 1; lv1_current_sel = 0; - h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); - win_settings_floppy_drives_init_columns(h); - image_list_init(h, (const uint8_t *) fd_icons); - win_settings_floppy_drives_recalc_list(h); - ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); - h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + win_settings_floppy_drives_init_columns(hdlg); + image_list_init(hdlg, IDC_LIST_FLOPPY_DRIVES, (const uint8_t *) fd_icons); + win_settings_floppy_drives_recalc_list(hdlg); + settings_listview_select(hdlg, IDC_LIST_FLOPPY_DRIVES, 0); for (i = 0; i < 14; i++) { if (i == 0) - SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5376)); + settings_add_string(hdlg, IDC_COMBO_FD_TYPE, win_get_string(IDS_5376)); else { mbstowcs(szText, fdd_getname(i), strlen(fdd_getname(i)) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + settings_add_string(hdlg, IDC_COMBO_FD_TYPE, (LPARAM) szText); } } - SendMessage(h, CB_SETCURSEL, temp_fdd_types[lv1_current_sel], 0); + settings_set_cur_sel(hdlg, IDC_COMBO_FD_TYPE, temp_fdd_types[lv1_current_sel]); - h = GetDlgItem(hdlg, IDC_CHECKTURBO); - SendMessage(h, BM_SETCHECK, temp_fdd_turbo[lv1_current_sel], 0); + settings_set_check(hdlg, IDC_CHECKTURBO, temp_fdd_turbo[lv1_current_sel]); + settings_set_check(hdlg, IDC_CHECKBPB, temp_fdd_check_bpb[lv1_current_sel]); - h = GetDlgItem(hdlg, IDC_CHECKBPB); - SendMessage(h, BM_SETCHECK, temp_fdd_check_bpb[lv1_current_sel], 0); + settings_listview_enable_styles(hdlg, IDC_LIST_FLOPPY_DRIVES); + + lv2_current_sel = 0; + win_settings_cdrom_drives_init_columns(hdlg); + image_list_init(hdlg, IDC_LIST_CDROM_DRIVES, (const uint8_t *) cd_icons); + win_settings_cdrom_drives_recalc_list(hdlg); + settings_listview_select(hdlg, IDC_LIST_CDROM_DRIVES, 0); + cdrom_add_locations(hdlg); + + switch (temp_cdrom[lv2_current_sel].bus_type) { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI: + b = 1; + break; + case CDROM_BUS_SCSI: + b = 2; + break; + } + settings_set_cur_sel(hdlg, IDC_COMBO_CD_BUS, b); + cdrom_recalc_location_controls(hdlg, 0); + + settings_listview_enable_styles(hdlg, IDC_LIST_CDROM_DRIVES); ignore_change = 0; return TRUE; @@ -4386,20 +4588,33 @@ win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM l lv1_current_sel = get_selected_drive(hdlg, IDC_LIST_FLOPPY_DRIVES); if (lv1_current_sel == old_sel) return FALSE; - else if (lv1_current_sel == -1) { - ignore_change = 1; - lv1_current_sel = old_sel; - ListView_SetItemState(h, lv1_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); - ignore_change = 0; - return FALSE; - } ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); - SendMessage(h, CB_SETCURSEL, temp_fdd_types[lv1_current_sel], 0); - h = GetDlgItem(hdlg, IDC_CHECKTURBO); - SendMessage(h, BM_SETCHECK, temp_fdd_turbo[lv1_current_sel], 0); - h = GetDlgItem(hdlg, IDC_CHECKBPB); - SendMessage(h, BM_SETCHECK, temp_fdd_check_bpb[lv1_current_sel], 0); + settings_set_cur_sel(hdlg, IDC_COMBO_FD_TYPE, temp_fdd_types[lv1_current_sel]); + settings_set_check(hdlg, IDC_CHECKTURBO, temp_fdd_turbo[lv1_current_sel]); + settings_set_check(hdlg, IDC_CHECKBPB, temp_fdd_check_bpb[lv1_current_sel]); + ignore_change = 0; + } else if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_CDROM_DRIVES)) { + old_sel = lv2_current_sel; + lv2_current_sel = get_selected_drive(hdlg, IDC_LIST_CDROM_DRIVES); + if (lv2_current_sel == old_sel) + return FALSE; + ignore_change = 1; + + switch (temp_cdrom[lv2_current_sel].bus_type) { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI: + b = 1; + break; + case CDROM_BUS_SCSI: + b = 2; + break; + } + settings_set_cur_sel(hdlg, IDC_COMBO_CD_BUS, b); + + cdrom_recalc_location_controls(hdlg, 0); ignore_change = 0; } break; @@ -4409,30 +4624,74 @@ win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM l return FALSE; ignore_change = 1; - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDC_COMBO_FD_TYPE: - h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); - temp_fdd_types[lv1_current_sel] = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); - win_settings_floppy_drives_update_item(h, lv1_current_sel); + temp_fdd_types[lv1_current_sel] = settings_get_cur_sel(hdlg, IDC_COMBO_FD_TYPE); + win_settings_floppy_drives_update_item(hdlg, lv1_current_sel); break; case IDC_CHECKTURBO: - h = GetDlgItem(hdlg, IDC_CHECKTURBO); - temp_fdd_turbo[lv1_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); - win_settings_floppy_drives_update_item(h, lv1_current_sel); + temp_fdd_turbo[lv1_current_sel] = settings_get_check(hdlg, IDC_CHECKTURBO); + win_settings_floppy_drives_update_item(hdlg, lv1_current_sel); break; case IDC_CHECKBPB: - h = GetDlgItem(hdlg, IDC_CHECKBPB); - temp_fdd_check_bpb[lv1_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); - win_settings_floppy_drives_update_item(h, lv1_current_sel); + temp_fdd_check_bpb[lv1_current_sel] = settings_get_check(hdlg, IDC_CHECKBPB); + win_settings_floppy_drives_update_item(hdlg, lv1_current_sel); + break; + + case IDC_COMBO_CD_BUS: + b = settings_get_cur_sel(hdlg, IDC_COMBO_CD_BUS); + switch (b) { + case 0: + b2 = CDROM_BUS_DISABLED; + break; + case 1: + b2 = CDROM_BUS_ATAPI; + break; + case 2: + b2 = CDROM_BUS_SCSI; + break; + } + if (b2 == temp_cdrom[lv2_current_sel].bus_type) + break; + cdrom_untrack(lv2_current_sel); + assign = (temp_cdrom[lv2_current_sel].bus_type == b2) ? 0 : 1; + if (temp_cdrom[lv2_current_sel].bus_type == CDROM_BUS_DISABLED) + temp_cdrom[lv2_current_sel].speed = 8; + temp_cdrom[lv2_current_sel].bus_type = b2; + cdrom_recalc_location_controls(hdlg, assign); + cdrom_track(lv2_current_sel); + win_settings_cdrom_drives_update_item(hdlg, lv2_current_sel); + break; + + case IDC_COMBO_CD_ID: + cdrom_untrack(lv2_current_sel); + temp_cdrom[lv2_current_sel].scsi_device_id = settings_get_cur_sel(hdlg, IDC_COMBO_CD_ID); + cdrom_track(lv2_current_sel); + win_settings_cdrom_drives_update_item(hdlg, lv2_current_sel); + break; + + case IDC_COMBO_CD_CHANNEL_IDE: + cdrom_untrack(lv2_current_sel); + temp_cdrom[lv2_current_sel].ide_channel = settings_get_cur_sel(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + cdrom_track(lv2_current_sel); + win_settings_cdrom_drives_update_item(hdlg, lv2_current_sel); + break; + + case IDC_COMBO_CD_SPEED: + temp_cdrom[lv2_current_sel].speed = settings_get_cur_sel(hdlg, IDC_COMBO_CD_SPEED) + 1; + win_settings_cdrom_drives_update_item(hdlg, lv2_current_sel); break; } ignore_change = 0; + case WM_DPICHANGED_AFTERPARENT: + win_settings_floppy_drives_resize_columns(hdlg); + image_list_init(hdlg, IDC_LIST_FLOPPY_DRIVES, (const uint8_t *) fd_icons); + win_settings_cdrom_drives_resize_columns(hdlg); + image_list_init(hdlg, IDC_LIST_CDROM_DRIVES, (const uint8_t *) cd_icons); + break; default: return FALSE; } @@ -4448,10 +4707,9 @@ static BOOL CALLBACK #endif win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h = NULL; int old_sel = 0, b = 0, assign = 0; uint32_t b2 = 0; - const uint8_t cd_icons[3] = { 249, 32, 0 }; + const uint8_t mo_icons[3] = { 251, 56, 0 }; const uint8_t zip_icons[3] = { 250, 48, 0 }; switch (message) { @@ -4459,42 +4717,36 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam ignore_change = 1; lv1_current_sel = 0; - h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); - win_settings_cdrom_drives_init_columns(h); - image_list_init(h, (const uint8_t *) cd_icons); - win_settings_cdrom_drives_recalc_list(h); - ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); - cdrom_add_locations(hdlg); + win_settings_mo_drives_init_columns(hdlg); + image_list_init(hdlg, IDC_LIST_MO_DRIVES, (const uint8_t *) mo_icons); + win_settings_mo_drives_recalc_list(hdlg); + settings_listview_select(hdlg, IDC_LIST_MO_DRIVES, 0); + mo_add_locations(hdlg); - h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); - - switch (temp_cdrom[lv1_current_sel].bus_type) { - case CDROM_BUS_DISABLED: + switch (temp_mo_drives[lv1_current_sel].bus_type) { + case MO_BUS_DISABLED: default: b = 0; break; - case CDROM_BUS_ATAPI: + case MO_BUS_ATAPI: b = 1; break; - case CDROM_BUS_SCSI: + case MO_BUS_SCSI: b = 2; break; } + settings_set_cur_sel(hdlg, IDC_COMBO_MO_BUS, b); + mo_recalc_location_controls(hdlg, 0); - SendMessage(h, CB_SETCURSEL, b, 0); - - cdrom_recalc_location_controls(hdlg, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_MO_DRIVES); lv2_current_sel = 0; - h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); - win_settings_zip_drives_init_columns(h); - image_list_init(h, (const uint8_t *) zip_icons); - win_settings_zip_drives_recalc_list(h); - ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + win_settings_zip_drives_init_columns(hdlg); + image_list_init(hdlg, IDC_LIST_ZIP_DRIVES, (const uint8_t *) zip_icons); + win_settings_zip_drives_recalc_list(hdlg); + settings_listview_select(hdlg, IDC_LIST_ZIP_DRIVES, 0); zip_add_locations(hdlg); - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); - switch (temp_zip_drives[lv2_current_sel].bus_type) { case ZIP_BUS_DISABLED: default: @@ -4507,11 +4759,11 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam b = 2; break; } - - SendMessage(h, CB_SETCURSEL, b, 0); - + settings_set_cur_sel(hdlg, IDC_COMBO_ZIP_BUS, b); zip_recalc_location_controls(hdlg, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_ZIP_DRIVES); + ignore_change = 0; return TRUE; @@ -4519,55 +4771,36 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam if (ignore_change) return FALSE; - if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_CDROM_DRIVES)) { + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_MO_DRIVES)) { old_sel = lv1_current_sel; - lv1_current_sel = get_selected_drive(hdlg, IDC_LIST_CDROM_DRIVES); + lv1_current_sel = get_selected_drive(hdlg, IDC_LIST_MO_DRIVES); if (lv1_current_sel == old_sel) return FALSE; - else if (lv1_current_sel == -1) { - ignore_change = 1; - lv1_current_sel = old_sel; - ListView_SetItemState(h, lv1_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); - ignore_change = 0; - return FALSE; - } ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); - - switch (temp_cdrom[lv1_current_sel].bus_type) { - case CDROM_BUS_DISABLED: + switch (temp_mo_drives[lv1_current_sel].bus_type) { + case MO_BUS_DISABLED: default: b = 0; break; - case CDROM_BUS_ATAPI: + case MO_BUS_ATAPI: b = 1; break; - case CDROM_BUS_SCSI: + case MO_BUS_SCSI: b = 2; break; } + settings_set_cur_sel(hdlg, IDC_COMBO_MO_BUS, b); - SendMessage(h, CB_SETCURSEL, b, 0); - - cdrom_recalc_location_controls(hdlg, 0); + mo_recalc_location_controls(hdlg, 0); ignore_change = 0; } else if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_ZIP_DRIVES)) { old_sel = lv2_current_sel; lv2_current_sel = get_selected_drive(hdlg, IDC_LIST_ZIP_DRIVES); if (lv2_current_sel == old_sel) return FALSE; - else if (lv2_current_sel == -1) { - ignore_change = 1; - lv2_current_sel = old_sel; - ListView_SetItemState(h, lv2_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); - ignore_change = 0; - return FALSE; - } ignore_change = 1; - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); - switch (temp_zip_drives[lv2_current_sel].bus_type) { case ZIP_BUS_DISABLED: default: @@ -4580,11 +4813,9 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam b = 2; break; } - - SendMessage(h, CB_SETCURSEL, b, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_ZIP_BUS, b); zip_recalc_location_controls(hdlg, 0); - ignore_change = 0; } break; @@ -4594,62 +4825,53 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam return FALSE; ignore_change = 1; - switch (LOWORD(wParam)) { - case IDC_COMBO_CD_BUS: - h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); - b = SendMessage(h, CB_GETCURSEL, 0, 0); + switch (LOWORD(wParam)) { + case IDC_COMBO_MO_BUS: + b = settings_get_cur_sel(hdlg, IDC_COMBO_MO_BUS); switch (b) { case 0: - b2 = CDROM_BUS_DISABLED; + b2 = MO_BUS_DISABLED; break; case 1: - b2 = CDROM_BUS_ATAPI; + b2 = MO_BUS_ATAPI; break; case 2: - b2 = CDROM_BUS_SCSI; + b2 = MO_BUS_SCSI; break; } - if (b2 == temp_cdrom[lv1_current_sel].bus_type) + if (b2 == temp_mo_drives[lv1_current_sel].bus_type) break; - cdrom_untrack(lv1_current_sel); - assign = (temp_cdrom[lv1_current_sel].bus_type == b2) ? 0 : 1; - if (temp_cdrom[lv1_current_sel].bus_type == CDROM_BUS_DISABLED) - temp_cdrom[lv1_current_sel].speed = 8; - temp_cdrom[lv1_current_sel].bus_type = b2; - cdrom_recalc_location_controls(hdlg, assign); - cdrom_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); - win_settings_cdrom_drives_update_item(h, lv1_current_sel); + mo_untrack(lv1_current_sel); + assign = (temp_mo_drives[lv1_current_sel].bus_type == b2) ? 0 : 1; + if (temp_mo_drives[lv1_current_sel].bus_type == MO_BUS_DISABLED) + temp_mo_drives[lv1_current_sel].type = 0; + temp_mo_drives[lv1_current_sel].bus_type = b2; + mo_recalc_location_controls(hdlg, assign); + mo_track(lv1_current_sel); + win_settings_mo_drives_update_item(hdlg, lv1_current_sel); break; - case IDC_COMBO_CD_ID: - h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); - cdrom_untrack(lv1_current_sel); - temp_cdrom[lv1_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); - cdrom_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); - win_settings_cdrom_drives_update_item(h, lv1_current_sel); + case IDC_COMBO_MO_ID: + mo_untrack(lv1_current_sel); + temp_mo_drives[lv1_current_sel].scsi_device_id = settings_get_cur_sel(hdlg, IDC_COMBO_MO_ID); + mo_track(lv1_current_sel); + win_settings_mo_drives_update_item(hdlg, lv1_current_sel); break; - case IDC_COMBO_CD_CHANNEL_IDE: - h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); - cdrom_untrack(lv1_current_sel); - temp_cdrom[lv1_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - cdrom_track(lv1_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); - win_settings_cdrom_drives_update_item(h, lv1_current_sel); + case IDC_COMBO_MO_CHANNEL_IDE: + mo_untrack(lv1_current_sel); + temp_mo_drives[lv1_current_sel].ide_channel = settings_get_cur_sel(hdlg, IDC_COMBO_MO_CHANNEL_IDE); + mo_track(lv1_current_sel); + win_settings_mo_drives_update_item(hdlg, lv1_current_sel); break; - case IDC_COMBO_CD_SPEED: - h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); - temp_cdrom[lv1_current_sel].speed = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; - h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); - win_settings_cdrom_drives_update_item(h, lv1_current_sel); + case IDC_COMBO_MO_TYPE: + temp_mo_drives[lv1_current_sel].type = settings_get_cur_sel(hdlg, IDC_COMBO_MO_TYPE); + win_settings_mo_drives_update_item(hdlg, lv1_current_sel); break; case IDC_COMBO_ZIP_BUS: - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); - b = SendMessage(h, CB_GETCURSEL, 0, 0); + b = settings_get_cur_sel(hdlg, IDC_COMBO_ZIP_BUS); switch (b) { case 0: b2 = ZIP_BUS_DISABLED; @@ -4668,37 +4890,36 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam temp_zip_drives[lv2_current_sel].bus_type = b2; zip_recalc_location_controls(hdlg, assign); zip_track(lv2_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); - win_settings_zip_drives_update_item(h, lv2_current_sel); + win_settings_zip_drives_update_item(hdlg, lv2_current_sel); break; case IDC_COMBO_ZIP_ID: - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); zip_untrack(lv2_current_sel); - temp_zip_drives[lv2_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_zip_drives[lv2_current_sel].scsi_device_id = settings_get_cur_sel(hdlg, IDC_COMBO_ZIP_ID); zip_track(lv2_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); - win_settings_zip_drives_update_item(h, lv2_current_sel); + win_settings_zip_drives_update_item(hdlg, lv2_current_sel); break; case IDC_COMBO_ZIP_CHANNEL_IDE: - h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); zip_untrack(lv2_current_sel); - temp_zip_drives[lv2_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_zip_drives[lv2_current_sel].ide_channel = settings_get_cur_sel(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); zip_track(lv2_current_sel); - h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); - win_settings_zip_drives_update_item(h, lv2_current_sel); + win_settings_zip_drives_update_item(hdlg, lv2_current_sel); break; case IDC_CHECK250: - h = GetDlgItem(hdlg, IDC_CHECK250); - temp_zip_drives[lv2_current_sel].is_250 = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); - win_settings_zip_drives_update_item(h, lv2_current_sel); + temp_zip_drives[lv2_current_sel].is_250 = settings_get_check(hdlg, IDC_CHECK250); + win_settings_zip_drives_update_item(hdlg, lv2_current_sel); break; } ignore_change = 0; + case WM_DPICHANGED_AFTERPARENT: + win_settings_mo_drives_resize_columns(hdlg); + image_list_init(hdlg, IDC_LIST_MO_DRIVES, (const uint8_t *) mo_icons); + win_settings_zip_drives_resize_columns(hdlg); + image_list_init(hdlg, IDC_LIST_ZIP_DRIVES, (const uint8_t *) zip_icons); + break; default: return FALSE; } @@ -4707,6 +4928,126 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam } +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + int c, d; + int e; + LPTSTR lptsTemp; + char *stransi; + const device_t *dev; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); + + /* Populate the ISA RTC card dropdown. */ + e = 0; + settings_reset_content(hdlg, IDC_COMBO_ISARTC); + for (d = 0; ; d++) { + generate_device_name(isartc_get_device(d), isartc_get_internal_name(d), 0); + + if (!device_name[0]) + break; + dev = isartc_get_device(d); + if (device_is_valid(dev, temp_machine)) { + if (d == 0) { + settings_add_string(hdlg, IDC_COMBO_ISARTC, win_get_string(IDS_2103)); + settings_set_cur_sel(hdlg, IDC_COMBO_ISARTC, 0); + } else + settings_add_string(hdlg, IDC_COMBO_ISARTC, (LPARAM) device_name); + settings_list_to_device[1][e] = d; + if (d == temp_isartc) + settings_set_cur_sel(hdlg, IDC_COMBO_ISARTC, e); + e++; + } + } + settings_enable_window(hdlg, IDC_COMBO_ISARTC, machine_has_bus(temp_machine, MACHINE_BUS_ISA)); + settings_enable_window(hdlg, IDC_CONFIGURE_ISARTC, ((temp_isartc != 0) && machine_has_bus(temp_machine, MACHINE_BUS_ISA))); + + /* Populate the ISA memory card dropdowns. */ + for (c = 0; c < ISAMEM_MAX; c++) { + e = 0; + settings_reset_content(hdlg, IDC_COMBO_ISAMEM_1 + c); + for (d = 0; ; d++) { + generate_device_name(isamem_get_device(d), (char *) isamem_get_internal_name(d), 0); + + if (!device_name[0]) + break; + + dev = isamem_get_device(d); + if (device_is_valid(dev, temp_machine)) { + if (d == 0) { + settings_add_string(hdlg, IDC_COMBO_ISAMEM_1 + c, win_get_string(IDS_2103)); + settings_set_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c, 0); + } else + settings_add_string(hdlg, IDC_COMBO_ISAMEM_1 + c, (LPARAM) device_name); + settings_list_to_device[0][e] = d; + if (d == temp_isamem[c]) + settings_set_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c, e); + e++; + } + } + settings_enable_window(hdlg, IDC_COMBO_ISAMEM_1 + c, machine_has_bus(temp_machine, MACHINE_BUS_ISA)); + settings_enable_window(hdlg, IDC_CONFIGURE_ISAMEM_1 + c, ((temp_isamem[c] != 0) && machine_has_bus(temp_machine, MACHINE_BUS_ISA))); + } + + settings_enable_window(hdlg, IDC_CHECK_BUGGER, machine_has_bus(temp_machine, MACHINE_BUS_ISA)); + settings_set_check(hdlg, IDC_CHECK_BUGGER, temp_bugger); + settings_set_check(hdlg, IDC_CHECK_POSTCARD, temp_postcard); + + free(stransi); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_CONFIGURE_ISARTC: + temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)isartc_get_device(temp_isartc)); + break; + + case IDC_COMBO_ISARTC: + temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; + settings_enable_window(hdlg, IDC_CONFIGURE_ISARTC, temp_isartc != 0); + break; + + case IDC_COMBO_ISAMEM_1: case IDC_COMBO_ISAMEM_2: + case IDC_COMBO_ISAMEM_3: case IDC_COMBO_ISAMEM_4: + c = LOWORD(wParam) - IDC_COMBO_ISAMEM_1; + temp_isamem[c] = settings_list_to_device[0][settings_get_cur_sel(hdlg, LOWORD(wParam))]; + settings_enable_window(hdlg, IDC_CONFIGURE_ISAMEM_1 + c, temp_isamem[c] != 0); + break; + + case IDC_CONFIGURE_ISAMEM_1: case IDC_CONFIGURE_ISAMEM_2: + case IDC_CONFIGURE_ISAMEM_3: case IDC_CONFIGURE_ISAMEM_4: + c = LOWORD(wParam) - IDC_CONFIGURE_ISAMEM_1; + temp_deviceconfig |= deviceconfig_inst_open(hdlg, (void *)isamem_get_device(temp_isamem[c]), c + 1); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; + for (c = 0; c < ISAMEM_MAX; c++) { + temp_isamem[c] = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c)]; + } + temp_bugger = settings_get_check(hdlg, IDC_CHECK_BUGGER); + temp_postcard = settings_get_check(hdlg, IDC_CHECK_POSTCARD); + + default: + return FALSE; + } + return FALSE; +} + + void win_settings_show_child(HWND hwndParent, DWORD child_id) { if (child_id == displayed_category) @@ -4737,18 +5078,21 @@ void win_settings_show_child(HWND hwndParent, DWORD child_id) case SETTINGS_PAGE_PORTS: hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PORTS, hwndParent, win_settings_ports_proc); break; - case SETTINGS_PAGE_PERIPHERALS: - hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + case SETTINGS_PAGE_STORAGE: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_STORAGE, hwndParent, win_settings_storage_proc); break; case SETTINGS_PAGE_HARD_DISKS: hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS, hwndParent, win_settings_hard_disks_proc); break; - case SETTINGS_PAGE_FLOPPY_DRIVES: - hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_FLOPPY_DRIVES, hwndParent, win_settings_floppy_drives_proc); + case SETTINGS_PAGE_FLOPPY_AND_CDROM_DRIVES: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_FLOPPY_AND_CDROM_DRIVES, hwndParent, win_settings_floppy_and_cdrom_drives_proc); break; case SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES: hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_OTHER_REMOVABLE_DEVICES, hwndParent, win_settings_other_removable_devices_proc); break; + case SETTINGS_PAGE_PERIPHERALS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + break; default: fatal("Invalid child dialog ID\n"); return; @@ -4767,13 +5111,13 @@ win_settings_main_insert_categories(HWND hwndList) lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.iSubItem = lvI.state = 0; - for (i = 0; i < 10; i++) { - lvI.pszText = plat_get_string(IDS_2065+i); - lvI.iItem = i; - lvI.iImage = i; + for (i = 0; i < 11; i++) { + lvI.pszText = plat_get_string(IDS_2065+i); + lvI.iItem = i; + lvI.iImage = i; - if (ListView_InsertItem(hwndList, &lvI) == -1) - return FALSE; + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; } return TRUE; @@ -4786,23 +5130,67 @@ static LRESULT CALLBACK #else static BOOL CALLBACK #endif -win_settings_confirm(HWND hdlg, int button) +win_settings_confirm(HWND hdlg) { int i; SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); - i = settings_msgbox_reset(); - if (i > 0) { - if (i == 2) + + if (win_settings_changed()) { + if (confirm_save && !settings_only) + i = settings_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING | MBX_DONTASK, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123, NULL, NULL); + else + i = 0; + + if (i == 10) { + confirm_save = 0; + i = 0; + } + + if (i == 0) win_settings_save(); + else + return FALSE; + } - DestroyWindow(hwndChildDialog); - EndDialog(hdlg, 0); - win_notify_dlg_closed(); + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + win_notify_dlg_closed(); + return TRUE; +} - return button ? TRUE : FALSE; - } else - return button ? FALSE : TRUE; + +static void +win_settings_categories_resize_columns(HWND hdlg) +{ + HWND hwndList = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + RECT r; + + GetWindowRect(hwndList, &r); + ListView_SetColumnWidth(hwndList, 0, (r.right - r.left) + 1 - 5); +} + + +static BOOL +win_settings_categories_init_columns(HWND hdlg) +{ + LVCOLUMN lvc; + int iCol = 0; + HWND hwndList = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(2048); + + lvc.cx = 171; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) + return FALSE; + + win_settings_categories_resize_columns(hdlg); + return TRUE; } @@ -4815,23 +5203,26 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h = NULL; int category, i = 0, j = 0; - const uint8_t cat_icons[11] = { 240, 241, 242, 243, 80, 244, 245, 64, 246, 247, 0 }; + const uint8_t cat_icons[12] = { 240, 241, 242, 243, 96, 244, 252, 80, 246, 247, 245, 0 }; hwndParentDialog = hdlg; switch (message) { case WM_INITDIALOG: + dpi = win_get_dpi(hdlg); win_settings_init(); displayed_category = -1; h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); - image_list_init(h, (const uint8_t *) cat_icons); + win_settings_categories_init_columns(hdlg); + image_list_init(hdlg, IDC_SETTINGSCATLIST, (const uint8_t *) cat_icons); win_settings_main_insert_categories(h); - ListView_SetItemState(h, first_cat, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + settings_listview_select(hdlg, IDC_SETTINGSCATLIST, first_cat); + settings_listview_enable_styles(hdlg, IDC_SETTINGSCATLIST); return TRUE; case WM_NOTIFY: if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) { category = -1; - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); j = ListView_GetItemState(h, i, LVIS_SELECTED); if (j) @@ -4842,18 +5233,27 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_CLOSE: - return win_settings_confirm(hdlg, 0); + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + win_notify_dlg_closed(); + return TRUE; case WM_COMMAND: - switch (LOWORD(wParam)) { + switch (LOWORD(wParam)) { case IDOK: - return win_settings_confirm(hdlg, 1); + return win_settings_confirm(hdlg); case IDCANCEL: DestroyWindow(hwndChildDialog); - EndDialog(hdlg, 0); + EndDialog(hdlg, 0); win_notify_dlg_closed(); - return TRUE; + return TRUE; } break; + + case WM_DPICHANGED: + dpi = HIWORD(wParam); + win_settings_categories_resize_columns(hdlg); + image_list_init(hdlg, IDC_SETTINGSCATLIST, (const uint8_t *) cat_icons); + break; default: return FALSE; } diff --git a/src/win/win_specify_dim.c b/src/win/win_specify_dim.c new file mode 100644 index 000000000..f2d8a768d --- /dev/null +++ b/src/win/win_specify_dim.c @@ -0,0 +1,179 @@ +/* + * 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. + * + * Handle the dialog for specifying the dimensions of the main window. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/plat.h> +#include <86box/video.h> +#include <86box/sound.h> +#include <86box/win.h> + + +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +SpecifyDimensionsDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h, h2; + HMENU hmenu; + UDACCEL accel, accel2; + RECT r; + uint32_t temp_x = 0, temp_y = 0; + int dpi = 96, lock; + LPTSTR lptsTemp; + char *stransi; + + switch (message) { + case WM_INITDIALOG: + GetWindowRect(hwndRender, &r); + + h = GetDlgItem(hdlg, IDC_WIDTHSPIN); + h2 = GetDlgItem(hdlg, IDC_EDIT_WIDTH); + SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); + SendMessage(h, UDM_SETRANGE, 0, (120 << 16) | 2048); + accel.nSec = 0; + accel.nInc = 8; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + SendMessage(h, UDM_SETPOS, 0, r.right - r.left); + + h = GetDlgItem(hdlg, IDC_HEIGHTSPIN); + h2 = GetDlgItem(hdlg, IDC_EDIT_HEIGHT); + SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); + SendMessage(h, UDM_SETRANGE, 0, (120 << 16) | 2048); + accel2.nSec = 0; + accel2.nInc = 8; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel2); + SendMessage(h, UDM_SETPOS, 0, r.bottom - r.top); + + h = GetDlgItem(hdlg, IDC_CHECK_LOCK_SIZE); + SendMessage(h, BM_SETCHECK, !!(vid_resize & 2), 0); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *)malloc(512); + + h = GetDlgItem(hdlg, IDC_EDIT_WIDTH); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + sscanf(stransi, "%u", &temp_x); + fixed_size_x = temp_x; + + h = GetDlgItem(hdlg, IDC_EDIT_HEIGHT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + sscanf(stransi, "%u", &temp_y); + fixed_size_y = temp_y; + + h = GetDlgItem(hdlg, IDC_CHECK_LOCK_SIZE); + lock = SendMessage(h, BM_GETCHECK, 0, 0); + + if (lock) { + vid_resize = 2; + window_remember = 0; + } else { + vid_resize = 1; + window_remember = 1; + } + hmenu = GetMenu(hwndMain); + CheckMenuItem(hmenu, IDM_VID_REMEMBER, (window_remember == 1) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize == 1) ? MF_CHECKED : MF_UNCHECKED); + EnableMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize & 2) ? MF_GRAYED : MF_ENABLED); + + if (vid_resize == 1) + SetWindowLongPtr(hwndMain, GWL_STYLE, (WS_OVERLAPPEDWINDOW) | WS_VISIBLE); + else + SetWindowLongPtr(hwndMain, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX) | WS_VISIBLE); + + /* scale the screen base on DPI */ + if (dpi_scale) { + dpi = win_get_dpi(hwndMain); + temp_x = MulDiv(temp_x, dpi, 96); + temp_y = MulDiv(temp_y, dpi, 96); + } + + ResizeWindowByClientArea(hwndMain, temp_x, temp_y + sbar_height + tbar_height); + + if (vid_resize) { + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); + scale = 1; + } + EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); + + scrnsz_x = fixed_size_x; + scrnsz_y = fixed_size_y; + atomic_store(&doresize_monitors[0], 1); + + GetWindowRect(hwndMain, &r); + + if (mouse_capture) + ClipCursor(&r); + + if (window_remember || (vid_resize & 2)) { + window_x = r.left; + window_y = r.top; + if (!(vid_resize & 2)) { + window_w = r.right - r.left; + window_h = r.bottom - r.top; + } + } + + config_save(); + + free(stransi); + free(lptsTemp); + + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + + default: + break; + } + break; + } + + return(FALSE); +} + + +void +SpecifyDimensionsDialogCreate(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR)DLG_SPECIFY_DIM, hwnd, SpecifyDimensionsDialogProcedure); +} diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index f509b45a5..406ae4f0f 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -34,6 +34,8 @@ #include <86box/device.h> #include <86box/machine.h> #include <86box/timer.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> #include <86box/hdd.h> #include <86box/hdc.h> #include <86box/fdd.h> @@ -52,13 +54,9 @@ #include <86box/ui.h> #include <86box/win.h> -#ifndef GWL_WNDPROC -#define GWL_WNDPROC GWLP_WNDPROC -#endif - HWND hwndSBAR; -int update_icons = 1; +int update_icons = 1, reset_occurred = 1; static LONG_PTR OriginalProcedure; @@ -69,6 +67,9 @@ static uint8_t *sb_part_icons; static int sb_parts = 0; static int sb_ready = 0; static uint8_t sb_map[256]; +static int icon_width = 24; +static wchar_t sb_text[512] = L"\0"; +static wchar_t sb_bugtext[512] = L"\0"; /* Also used by win_settings.c */ intptr_t @@ -117,12 +118,17 @@ hdd_count(int bus) void ui_sb_timer_callback(int pane) { - sb_part_icons[pane] &= ~1; + if (!(reset_occurred & 1)) { + sb_part_icons[pane] &= ~1; - if (sb_part_icons && sb_part_icons[pane]) { - SendMessage(hwndSBAR, SB_SETICON, pane, - (LPARAM)hIcon[sb_part_icons[pane]]); - } + if (sb_part_icons && sb_part_icons[pane]) { + SendMessage(hwndSBAR, SB_SETICON, pane, + (LPARAM)hIcon[sb_part_icons[pane]]); + } + } else + reset_occurred &= ~1; + + reset_occurred &= ~2; } @@ -144,14 +150,16 @@ ui_sb_update_icon(int tag, int active) if ((found != 0xff) && ((sb_part_icons[found] ^ active) & 1) && active) { sb_part_icons[found] |= 1; - SendMessage(hwndSBAR, SB_SETICON, found, + PostMessage(hwndSBAR, SB_SETICON, found, (LPARAM)hIcon[sb_part_icons[found]]); + reset_occurred = 2; SetTimer(hwndMain, 0x8000 | found, 75, NULL); } } + /* API: This is for the drive state indicator. */ void ui_sb_update_icon_state(int tag, int state) @@ -172,22 +180,71 @@ ui_sb_update_icon_state(int tag, int state) } +static void +StatusBarCreateCassetteTip(int part) +{ + WCHAR tempTip[512]; + WCHAR fn[512]; + + if (strlen(cassette_fname) == 0) + _swprintf(tempTip, plat_get_string(IDS_2148), plat_get_string(IDS_2057)); + else { + mbstoc16s(fn, cassette_fname, sizeof_w(fn)); + _swprintf(tempTip, plat_get_string(IDS_2148), fn); + } + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateCartridgeTip(int part) +{ + WCHAR tempTip[512]; + WCHAR fn[512]; + int drive = sb_part_meanings[part] & 0xf; + + if (strlen(cart_fns[drive]) == 0) { + _swprintf(tempTip, plat_get_string(IDS_2150), + drive+1, plat_get_string(IDS_2057)); + } else { + mbstoc16s(fn, cart_fns[drive], sizeof_w(fn)); + _swprintf(tempTip, plat_get_string(IDS_2150), + drive+1, fn); + } + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + static void StatusBarCreateFloppyTip(int part) { WCHAR wtext[512]; WCHAR tempTip[512]; + WCHAR fn[512]; int drive = sb_part_meanings[part] & 0xf; - mbstowcs(wtext, fdd_getname(fdd_get_type(drive)), + mbstoc16s(wtext, fdd_getname(fdd_get_type(drive)), strlen(fdd_getname(fdd_get_type(drive))) + 1); - if (wcslen(floppyfns[drive]) == 0) { + if (strlen(floppyfns[drive]) == 0) { _swprintf(tempTip, plat_get_string(IDS_2108), drive+1, wtext, plat_get_string(IDS_2057)); } else { + mbstoc16s(fn, floppyfns[drive], sizeof_w(fn)); _swprintf(tempTip, plat_get_string(IDS_2108), - drive+1, wtext, floppyfns[drive]); + drive+1, wtext, fn); } if (sbTips[part] != NULL) { @@ -204,6 +261,7 @@ StatusBarCreateCdromTip(int part) { WCHAR tempTip[512]; WCHAR *szText; + WCHAR fn[512]; int id; int drive = sb_part_meanings[part] & 0xf; int bus = cdrom[drive].bus_type; @@ -212,10 +270,14 @@ StatusBarCreateCdromTip(int part) szText = plat_get_string(id); if (cdrom[drive].host_drive == 200) { - if (wcslen(cdrom[drive].image_path) == 0) - _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); - else - _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, cdrom[drive].image_path); + if (strlen(cdrom[drive].image_path) == 0) { + _swprintf(tempTip, plat_get_string(IDS_5120), + drive+1, szText, plat_get_string(IDS_2057)); + } else { + mbstoc16s(fn, cdrom[drive].image_path, sizeof_w(fn)); + _swprintf(tempTip, plat_get_string(IDS_5120), + drive+1, szText, fn); + } } else _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); @@ -233,6 +295,7 @@ StatusBarCreateZIPTip(int part) { WCHAR tempTip[512]; WCHAR *szText; + WCHAR fn[512]; int id; int drive = sb_part_meanings[part] & 0xf; int bus = zip_drives[drive].bus_type; @@ -242,12 +305,13 @@ StatusBarCreateZIPTip(int part) int type = zip_drives[drive].is_250 ? 250 : 100; - if (wcslen(zip_drives[drive].image_path) == 0) { + if (strlen(zip_drives[drive].image_path) == 0) { _swprintf(tempTip, plat_get_string(IDS_2054), type, drive+1, szText, plat_get_string(IDS_2057)); } else { + mbstoc16s(fn, zip_drives[drive].image_path, sizeof_w(fn)); _swprintf(tempTip, plat_get_string(IDS_2054), - type, drive+1, szText, zip_drives[drive].image_path); + type, drive+1, szText, fn); } if (sbTips[part] != NULL) { @@ -258,11 +322,13 @@ StatusBarCreateZIPTip(int part) wcscpy(sbTips[part], tempTip); } + static void StatusBarCreateMOTip(int part) { WCHAR tempTip[512]; WCHAR *szText; + WCHAR fn[512]; int id; int drive = sb_part_meanings[part] & 0xf; int bus = mo_drives[drive].bus_type; @@ -270,12 +336,13 @@ StatusBarCreateMOTip(int part) id = IDS_5377 + (bus - 1); szText = plat_get_string(id); - if (wcslen(mo_drives[drive].image_path) == 0) { + if (strlen(mo_drives[drive].image_path) == 0) { _swprintf(tempTip, plat_get_string(IDS_2115), drive+1, szText, plat_get_string(IDS_2057)); } else { + mbstoc16s(fn, mo_drives[drive].image_path, sizeof_w(fn)); _swprintf(tempTip, plat_get_string(IDS_2115), - drive+1, szText, mo_drives[drive].image_path); + drive+1, szText, fn); } if (sbTips[part] != NULL) { @@ -286,6 +353,7 @@ StatusBarCreateMOTip(int part) wcscpy(sbTips[part], tempTip); } + static void StatusBarCreateDiskTip(int part) { @@ -346,6 +414,14 @@ ui_sb_update_tip(int meaning) if (part != 0xff) { switch(meaning & 0xf0) { + case SB_CASSETTE: + StatusBarCreateCassetteTip(part); + break; + + case SB_CARTRIDGE: + StatusBarCreateCartridgeTip(part); + break; + case SB_FLOPPY: StatusBarCreateFloppyTip(part); break; @@ -405,9 +481,20 @@ StatusBarDestroyTips(void) /* API: mark the status bar as not ready. */ +/* Values: -1 - not ready, but don't clear POST text + 0 - not ready + 1 - ready */ void ui_sb_set_ready(int ready) { + if (ready == 0) { + ui_sb_bugui(NULL); + ui_sb_set_text(NULL); + } + + if (ready == -1) + ready = 0; + sb_ready = ready; } @@ -416,7 +503,8 @@ ui_sb_set_ready(int ready) void ui_sb_update_panes(void) { - int i, id, hdint; + int i, id; + int cart_int, mfm_int, xta_int, esdi_int, ide_int, scsi_int; int edge = 0; int c_mfm, c_esdi, c_xta; int c_ide, c_scsi; @@ -430,7 +518,13 @@ ui_sb_update_panes(void) sb_ready = 0; } - hdint = (machines[machine].flags & MACHINE_HDC) ? 1 : 0; + cart_int = machine_has_cartridge(machine) ? 1 : 0; + mfm_int = machine_has_flags(machine, MACHINE_MFM) ? 1 : 0; + xta_int = machine_has_flags(machine, MACHINE_XTA) ? 1 : 0; + esdi_int = machine_has_flags(machine, MACHINE_ESDI) ? 1 : 0; + ide_int = machine_has_flags(machine, MACHINE_IDE_QUAD) ? 1 : 0; + scsi_int = machine_has_flags(machine, MACHINE_SCSI_DUAL) ? 1 : 0; + c_mfm = hdd_count(HDD_BUS_MFM); c_esdi = hdd_count(HDD_BUS_ESDI); c_xta = hdd_count(HDD_BUS_XTA); @@ -463,6 +557,10 @@ ui_sb_update_panes(void) memset(sb_map, 0xff, sizeof(sb_map)); sb_parts = 0; + if (cassette_enable) + sb_parts++; + if (cart_int) + sb_parts += 2; for (i=0; i= (sb_parts - 1)) return; - pt.x = id * SB_ICON_WIDTH; /* Justify to the left. */ + pt.x = id * icon_width; /* Justify to the left. */ pt.y = 0; /* Justify to the top. */ ClientToScreen(hwnd, (LPPOINT) &pt); switch(sb_part_meanings[id] & 0xF0) { + case SB_CASSETTE: + menu = media_menu_get_cassette(); + break; + case SB_CARTRIDGE: + menu = media_menu_get_cartridge(sb_part_meanings[id] & 0x0F); + break; case SB_FLOPPY: menu = media_menu_get_floppy(sb_part_meanings[id] & 0x0F); break; @@ -729,6 +884,11 @@ StatusBarPopupMenu(HWND hwnd, POINT pt, int id) pt.x, pt.y, 0, hwndSBAR, NULL); } +/* API: Load status bar icons */ +void +StatusBarLoadIcon(HINSTANCE hInst) { + win_load_icon_set(); +} /* Handle messages for the Status Bar window. */ #if defined(__amd64__) || defined(__aarch64__) @@ -741,6 +901,8 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) RECT rc; POINT pt; int item_id = 0; + int i; + HINSTANCE hInst; switch (message) { case WM_COMMAND: @@ -753,20 +915,38 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); if (PtInRect((LPRECT) &rc, pt)) - StatusBarPopupMenu(hwnd, pt, (pt.x / SB_ICON_WIDTH)); + StatusBarPopupMenu(hwnd, pt, (pt.x / icon_width)); break; case WM_LBUTTONDBLCLK: GetClientRect(hwnd, (LPRECT)& rc); pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); - item_id = (pt.x / SB_ICON_WIDTH); + item_id = (pt.x / icon_width); if (PtInRect((LPRECT) &rc, pt) && (item_id < sb_parts)) { if (sb_part_meanings[item_id] == SB_SOUND) SoundGainDialogCreate(hwndMain); } break; + case WM_DPICHANGED_AFTERPARENT: + /* DPI changed, reload icons */ + hInst = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); + dpi = win_get_dpi(hwnd); + icon_width = MulDiv(SB_ICON_WIDTH, dpi, 96); + StatusBarLoadIcon(hInst); + + for (i=0; i #include <86box/86box.h> #include <86box/plat.h> +#include <86box/thread.h> typedef struct { @@ -44,24 +45,22 @@ thread_create(void (*func)(void *param), void *param) } -void -thread_kill(void *arg) -{ - if (arg == NULL) return; - - TerminateThread(arg, 0); -} - - int -thread_wait(thread_t *arg, int timeout) +thread_test_mutex(thread_t *arg) { if (arg == NULL) return(0); - if (timeout == -1) - timeout = INFINITE; + return (WaitForSingleObject(arg, 0) == WAIT_OBJECT_0) ? 1 : 0; +} - if (WaitForSingleObject(arg, timeout)) return(1); + + +int +thread_wait(thread_t *arg) +{ + if (arg == NULL) return(0); + + if (WaitForSingleObject(arg, INFINITE)) return(1); return(0); } @@ -134,16 +133,11 @@ thread_destroy_event(event_t *arg) mutex_t * thread_create_mutex(void) { - return((mutex_t*)CreateMutex(NULL, FALSE, NULL)); -} + mutex_t *mutex = malloc(sizeof(CRITICAL_SECTION)); + InitializeCriticalSection(mutex); -void -thread_close_mutex(mutex_t *mutex) -{ - if (mutex == NULL) return; - - CloseHandle((HANDLE)mutex); + return mutex; } @@ -152,11 +146,11 @@ thread_wait_mutex(mutex_t *mutex) { if (mutex == NULL) return(0); - DWORD dwres = WaitForSingleObject((HANDLE)mutex, INFINITE); + LPCRITICAL_SECTION critsec = (LPCRITICAL_SECTION)mutex; - if (dwres == WAIT_OBJECT_0) return(1); + EnterCriticalSection(critsec); - return(0); + return 1; } @@ -165,5 +159,22 @@ thread_release_mutex(mutex_t *mutex) { if (mutex == NULL) return(0); - return(!!ReleaseMutex((HANDLE)mutex)); + LPCRITICAL_SECTION critsec = (LPCRITICAL_SECTION)mutex; + + LeaveCriticalSection(critsec); + + return 1; +} + + +void +thread_close_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return; + + LPCRITICAL_SECTION critsec = (LPCRITICAL_SECTION)mutex; + + DeleteCriticalSection(critsec); + + free(critsec); } diff --git a/src/win/win_toolbar.c b/src/win/win_toolbar.c new file mode 100644 index 000000000..322038fda --- /dev/null +++ b/src/win/win_toolbar.c @@ -0,0 +1,220 @@ +#define UNICODE +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/resource.h> +#include <86box/ui.h> +#include <86box/video.h> +#include <86box/win.h> + +HWND hwndRebar = NULL; +static HWND hwndToolbar = NULL; +static HIMAGELIST hImageList = NULL; +static wchar_t wTitle[512] = { 0 }; +static WNDPROC pOriginalProcedure = NULL; + + +enum image_index { + RUN, + PAUSE, + CTRL_ALT_DEL, + CTRL_ALT_ESC, + HARD_RESET, + ACPI_SHUTDOWN, + SETTINGS +}; + + +void +ToolBarLoadIcons() +{ + if (!hwndToolbar) + return; + + if (hImageList) + ImageList_Destroy(hImageList); + + hImageList = ImageList_Create(win_get_system_metrics(SM_CXSMICON, dpi), + win_get_system_metrics(SM_CYSMICON, dpi), + ILC_MASK | ILC_COLOR32, 1, 1); + + // The icons must be loaded in the same order as the `image_index` + // enumeration above. + + ImageList_AddIcon(hImageList, hIcon[200]); // Run + ImageList_AddIcon(hImageList, hIcon[201]); // Pause + ImageList_AddIcon(hImageList, hIcon[202]); // Ctrl+Alt+Delete + ImageList_AddIcon(hImageList, hIcon[203]); // Ctrl+Alt+Esc + ImageList_AddIcon(hImageList, hIcon[204]); // Hard reset + ImageList_AddIcon(hImageList, hIcon[205]); // ACPI shutdown + ImageList_AddIcon(hImageList, hIcon[206]); // Settings + + SendMessage(hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM) hImageList); +} + + +int +ToolBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) { + case TTN_GETDISPINFO: { + LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam; + + // Set the instance of the module that contains the resource. + lpttt->hinst = hinstance; + + uintptr_t idButton = lpttt->hdr.idFrom; + + switch (idButton) { + case IDM_ACTION_PAUSE: + if (dopause) + lpttt->lpszText = MAKEINTRESOURCE(IDS_2154); + else + lpttt->lpszText = MAKEINTRESOURCE(IDS_2155); + break; + + case IDM_ACTION_RESET_CAD: + lpttt->lpszText = MAKEINTRESOURCE(IDS_2156); + break; + + case IDM_ACTION_CTRL_ALT_ESC: + lpttt->lpszText = MAKEINTRESOURCE(IDS_2157); + break; + + case IDM_ACTION_HRESET: + lpttt->lpszText = MAKEINTRESOURCE(IDS_2158); + break; + + case IDM_CONFIG: + lpttt->lpszText = MAKEINTRESOURCE(IDS_2160); + break; + } + + return TRUE; + } + } + } + + return(CallWindowProc(pOriginalProcedure, hwnd, message, wParam, lParam)); +} + + +void +ToolBarUpdatePause(int pause) +{ + TBBUTTONINFO tbbi; + + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_IMAGE; + tbbi.iImage = pause ? RUN : PAUSE; + + SendMessage(hwndToolbar, TB_SETBUTTONINFO, IDM_ACTION_PAUSE, (LPARAM) &tbbi); +} + + +static TBBUTTON buttons[] = { + { PAUSE, IDM_ACTION_PAUSE, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 }, + { HARD_RESET, IDM_ACTION_HRESET, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 }, + { ACPI_SHUTDOWN, 0, TBSTATE_HIDDEN, BTNS_BUTTON, { 0 }, 0, 0 }, + { 0, 0, TBSTATE_INDETERMINATE, BTNS_SEP, { 0 }, 0, 0 }, + { CTRL_ALT_DEL, IDM_ACTION_RESET_CAD, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 }, + { CTRL_ALT_ESC, IDM_ACTION_CTRL_ALT_ESC, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 }, + { 0, 0, TBSTATE_INDETERMINATE, BTNS_SEP, { 0 }, 0, 0 }, + { SETTINGS, IDM_CONFIG, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0, 0 } +}; + + +void +ToolBarCreate(HWND hwndParent, HINSTANCE hInst) +{ + REBARINFO rbi = { 0 }; + REBARBANDINFO rbbi = { 0 }; + int btnSize; + + // Create the toolbar. + hwndToolbar = CreateWindowEx(WS_EX_PALETTEWINDOW, TOOLBARCLASSNAME, NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | + WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | + TBSTYLE_FLAT | CCS_TOP | BTNS_AUTOSIZE | + CCS_NOPARENTALIGN | CCS_NORESIZE | + CCS_NODIVIDER, + 0, 0, 0, 0, + hwndParent, NULL, hInst, NULL); + + ToolBarLoadIcons(); + + // Add buttons. + SendMessage(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); + SendMessage(hwndToolbar, TB_ADDBUTTONS, sizeof(buttons) / sizeof(TBBUTTON), (LPARAM) &buttons); + + // Autosize the toolbar and determine its size. + btnSize = LOWORD(SendMessage(hwndToolbar, TB_GETBUTTONSIZE, 0,0)); + + // Replace the original procedure with ours. + pOriginalProcedure = (WNDPROC) GetWindowLongPtr(hwndToolbar, GWLP_WNDPROC); + SetWindowLongPtr(hwndToolbar, GWLP_WNDPROC, (LONG_PTR)&ToolBarProcedure); + + // Make sure the Pause button is in the correct state. + ToolBarUpdatePause(dopause); + + // Create the containing Rebar. + hwndRebar = CreateWindowEx(0, REBARCLASSNAME, NULL, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN | RBS_VARHEIGHT | + CCS_NODIVIDER | CCS_NOPARENTALIGN, + 0, 0, scrnsz_x, 0, + hwndParent, NULL, hInst, NULL); + + // Create and send the REBARINFO structure. + rbi.cbSize = sizeof(rbi); + SendMessage(hwndRebar, RB_SETBARINFO, 0, (LPARAM)&rbi); + + // Add the toolbar to the rebar. + rbbi.cbSize = sizeof(rbbi); + rbbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE; + rbbi.hwndChild = hwndToolbar; + rbbi.cxMinChild = 0; + rbbi.cyMinChild = btnSize; + rbbi.fStyle = RBBS_NOGRIPPER; + SendMessage(hwndRebar, RB_INSERTBAND, -1, (LPARAM)&rbbi); + + // Add a label for machine information. + rbbi.fMask = RBBIM_TEXT | RBBIM_STYLE; + rbbi.lpText = TEXT("Test"); + rbbi.fStyle = RBBS_NOGRIPPER; + SendMessage(hwndRebar, RB_INSERTBAND, -1, (LPARAM)&rbbi); + + SendMessage(hwndRebar, RB_MAXIMIZEBAND, 0, 0); + ShowWindow(hwndRebar, TRUE); + + return; +} + + +wchar_t * +ui_window_title(wchar_t *s) +{ + REBARBANDINFO rbbi = { 0 }; + if (! video_fullscreen) { + if (s != NULL) { + wcsncpy(wTitle, s, sizeof_w(wTitle) - 1); + } else + s = wTitle; + + rbbi.cbSize = sizeof(rbbi); + rbbi.fMask = RBBIM_TEXT; + rbbi.lpText = s; + SendMessage(hwndRebar, RB_SETBANDINFO, 1, (LPARAM) &rbbi); + } else { + if (s == NULL) + s = wTitle; + } + + return(s); +} diff --git a/src/win/win_ui.c b/src/win/win_ui.c index b2f01e215..b96d8ffb4 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -19,6 +19,7 @@ * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2019,2020 GH Cao. */ +#include #define UNICODE #include #include @@ -28,49 +29,119 @@ #include #include #include +#include <86box/plat.h> #include <86box/86box.h> #include <86box/config.h> +#include "../cpu/cpu.h" #include <86box/device.h> #include <86box/keyboard.h> #include <86box/mouse.h> +#include <86box/timer.h> +#include <86box/nvr.h> #include <86box/video.h> #include <86box/vid_ega.h> // for update_overscan -#include <86box/plat.h> -#include <86box/plat_midi.h> +#include <86box/plat_dynld.h> #include <86box/ui.h> #include <86box/win.h> -#ifdef USE_DISCORD -# include <86box/win_discord.h> -#endif +#include <86box/version.h> +#include <86box/discord.h> +#ifdef MTR_ENABLED +#include +#endif #define TIMER_1SEC 1 /* ID of the one-second timer */ /* Platform Public data, specific. */ -HWND hwndMain, /* application main window */ - hwndRender; /* machine render window */ +HWND hwndMain = NULL, /* application main window */ + hwndRender = NULL; /* machine render window */ HMENU menuMain; /* application main menu */ -HICON hIcon[256]; /* icon data loaded from resources */ RECT oldclip; /* mouse rect */ -int sbar_height = 23; /* statusbar height */ +int sbar_height = 23; /* statusbar height */ +int tbar_height = 23; /* toolbar height */ int minimized = 0; -int infocus = 1; +int infocus = 1, button_down = 0; int rctrl_is_lalt = 0; int user_resize = 0; +int fixed_size_x = 0, fixed_size_y = 0; +int kbd_req_capture = 0; +int hide_status_bar = 0; +int hide_tool_bar = 0; +int dpi = 96; extern char openfilestring[512]; extern WCHAR wopenfilestring[512]; /* Local data. */ -static wchar_t wTitle[512]; -static HHOOK hKeyboardHook; -static int hook_enabled = 0, manager_wm = 0; +static int manager_wm = 0; static int save_window_pos = 0, pause_state = 0; +static int padded_frame = 0; +static int vis = -1; +/* Per Monitor DPI Aware v2 APIs, Windows 10 v1703+ */ +void* user32_handle = NULL; +static UINT (WINAPI *pGetDpiForWindow)(HWND); +static UINT (WINAPI *pGetSystemMetricsForDpi)(int i, UINT dpi); +static DPI_AWARENESS_CONTEXT (WINAPI *pGetWindowDpiAwarenessContext)(HWND); +static BOOL (WINAPI *pAreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT A, DPI_AWARENESS_CONTEXT B); +static dllimp_t user32_imports[] = { +{ "GetDpiForWindow", &pGetDpiForWindow }, +{ "GetSystemMetricsForDpi", &pGetSystemMetricsForDpi }, +{ "GetWindowDpiAwarenessContext", &pGetWindowDpiAwarenessContext }, +{ "AreDpiAwarenessContextsEqual", &pAreDpiAwarenessContextsEqual }, +{ NULL, NULL } +}; -static int vis = -1; +/* Taskbar application ID API, Windows 7+ */ +void* shell32_handle = NULL; +static HRESULT (WINAPI *pSetCurrentProcessExplicitAppUserModelID)(PCWSTR AppID); +static dllimp_t shell32_imports[]= { +{ "SetCurrentProcessExplicitAppUserModelID", &pSetCurrentProcessExplicitAppUserModelID }, +{ NULL, NULL } +}; + +int +win_get_dpi(HWND hwnd) { + if (user32_handle != NULL) { + return pGetDpiForWindow(hwnd); + } else { + HDC dc = GetDC(hwnd); + UINT dpi = GetDeviceCaps(dc, LOGPIXELSX); + ReleaseDC(hwnd, dc); + return dpi; + } +} + +int win_get_system_metrics(int index, int dpi) { + if (user32_handle != NULL) { + /* Only call GetSystemMetricsForDpi when we are using PMv2 */ + DPI_AWARENESS_CONTEXT c = pGetWindowDpiAwarenessContext(hwndMain); + if (pAreDpiAwarenessContextsEqual(c, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + return pGetSystemMetricsForDpi(index, dpi); + } + + return GetSystemMetrics(index); +} + +void +ResizeWindowByClientArea(HWND hwnd, int width, int height) +{ + if ((vid_resize == 1) || padded_frame) { + int padding = win_get_system_metrics(SM_CXPADDEDBORDER, dpi); + width += (win_get_system_metrics(SM_CXFRAME, dpi) + padding) * 2; + height += (win_get_system_metrics(SM_CYFRAME, dpi) + padding) * 2; + } else { + width += win_get_system_metrics(SM_CXFIXEDFRAME, dpi) * 2; + height += win_get_system_metrics(SM_CYFIXEDFRAME, dpi) * 2; + } + + height += win_get_system_metrics(SM_CYCAPTION, dpi); + height += win_get_system_metrics(SM_CYBORDER, dpi) + win_get_system_metrics(SM_CYMENUSIZE, dpi); + + SetWindowPos(hwnd, NULL, 0, 0, width, height, SWP_NOMOVE); +} /* Set host cursor visible or not. */ void @@ -88,20 +159,10 @@ show_cursor(int val) vis = val; } - -HICON -LoadIconEx(PCTSTR pszIconName) -{ - return((HICON)LoadImage(hinstance, pszIconName, IMAGE_ICON, - 16, 16, LR_SHARED)); -} - - static void video_toggle_option(HMENU h, int *val, int id) { startblit(); - video_wait_for_blit(); *val ^= 1; CheckMenuItem(h, id, *val ? MF_CHECKED : MF_UNCHECKED); endblit(); @@ -109,44 +170,90 @@ video_toggle_option(HMENU h, int *val, int id) device_force_redraw(); } +/* Recursively finds and deletes target submenu */ +static int +delete_submenu(HMENU parent, HMENU target) +{ + for (int i = 0; i < GetMenuItemCount(parent); i++) + { + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU; + + if (GetMenuItemInfo(parent, i, TRUE, &mii) != 0) + { + if (mii.hSubMenu == target) + { + DeleteMenu(parent, i, MF_BYPOSITION); + return 1; + } + else if (mii.hSubMenu != NULL) + { + if (delete_submenu(mii.hSubMenu, target)) + return 1; + } + } + } + + return 0; +} + +static int menu_vidapi = -1; +static HMENU cur_menu = NULL; static void +show_render_options_menu() +{ + if (vid_api == menu_vidapi) + return; + + if (cur_menu != NULL) + { + if (delete_submenu(menuMain, cur_menu)) + cur_menu = NULL; + } + + if (cur_menu == NULL) + { + switch (IDM_VID_SDL_SW + vid_api) + { + case IDM_VID_OPENGL_CORE: + cur_menu = LoadMenu(hinstance, VID_GL_SUBMENU); + InsertMenu(GetSubMenu(menuMain, 1), 6, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT_PTR)cur_menu, plat_get_string(IDS_2144)); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_BLITTER, video_framerate == -1 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_25, video_framerate == 25 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_30, video_framerate == 30 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_50, video_framerate == 50 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_60, video_framerate == 60 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_FPS_75, video_framerate == 75 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED); + EnableMenuItem(menuMain, IDM_VID_GL_NOSHADER, strlen(video_shader) > 0 ? MF_ENABLED : MF_DISABLED); + break; + } + } + + menu_vidapi = vid_api; +} + +static void +video_set_filter_menu(HMENU menu) +{ + CheckMenuItem(menu, IDM_VID_FILTER_NEAREST, vid_api == 0 || video_filter_method == 0 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_FILTER_LINEAR, vid_api != 0 && video_filter_method == 1 ? MF_CHECKED : MF_UNCHECKED); + EnableMenuItem(menu, IDM_VID_FILTER_NEAREST, vid_api == 0 ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(menu, IDM_VID_FILTER_LINEAR, vid_api == 0 ? MF_GRAYED : MF_ENABLED); +} + +void ResetAllMenus(void) { -#ifndef DEV_BRANCH - /* FIXME: until we fix these.. --FvK */ - EnableMenuItem(menuMain, IDM_CONFIG_LOAD, MF_DISABLED); - EnableMenuItem(menuMain, IDM_CONFIG_SAVE, MF_DISABLED); -#endif - CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_ACTION_KBD_REQ_CAPTURE, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, MF_UNCHECKED); -#ifdef ENABLE_LOG_TOGGLES -# ifdef ENABLE_BUSLOGIC_LOG - CheckMenuItem(menuMain, IDM_LOG_BUSLOGIC, MF_UNCHECKED); -# endif -# ifdef ENABLE_CDROM_LOG - CheckMenuItem(menuMain, IDM_LOG_CDROM, MF_UNCHECKED); -# endif -# ifdef ENABLE_D86F_LOG - CheckMenuItem(menuMain, IDM_LOG_D86F, MF_UNCHECKED); -# endif -# ifdef ENABLE_FDC_LOG - CheckMenuItem(menuMain, IDM_LOG_FDC, MF_UNCHECKED); -# endif -# ifdef ENABLE_IDE_LOG - CheckMenuItem(menuMain, IDM_LOG_IDE, MF_UNCHECKED); -# endif -# ifdef ENABLE_SERIAL_LOG - CheckMenuItem(menuMain, IDM_LOG_SERIAL, MF_UNCHECKED); -# endif -# ifdef ENABLE_NIC_LOG - CheckMenuItem(menuMain, IDM_LOG_NIC, MF_UNCHECKED); -# endif -#endif - + CheckMenuItem(menuMain, IDM_VID_HIDE_STATUS_BAR, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_HIDE_TOOLBAR, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_FORCE43, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_OVERSCAN, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_INVERT, MF_UNCHECKED); @@ -154,6 +261,12 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_SW, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_HW, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SDL_OPENGL, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_OPENGL_CORE, MF_UNCHECKED); + + menu_vidapi = -1; + cur_menu = NULL; + show_render_options_menu(); #ifdef USE_VNC CheckMenuItem(menuMain, IDM_VID_VNC, MF_UNCHECKED); #endif @@ -167,6 +280,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_SCALE_1X+1, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+2, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+3, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_HIDPI, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_CGACON, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+0, MF_UNCHECKED); @@ -179,87 +293,51 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+4, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_ACTION_KBD_REQ_CAPTURE, kbd_req_capture ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); -#ifdef ENABLE_LOG_TOGGLES -# ifdef ENABLE_BUSLOGIC_LOG - CheckMenuItem(menuMain, IDM_LOG_BUSLOGIC, buslogic_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -# ifdef ENABLE_CDROM_LOG - CheckMenuItem(menuMain, IDM_LOG_CDROM, cdrom_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -# ifdef ENABLE_D86F_LOG - CheckMenuItem(menuMain, IDM_LOG_D86F, d86f_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -# ifdef ENABLE_FDC_LOG - CheckMenuItem(menuMain, IDM_LOG_FDC, fdc_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -# ifdef ENABLE_IDE_LOG - CheckMenuItem(menuMain, IDM_LOG_IDE, ide_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -# ifdef ENABLE_SERIAL_LOG - CheckMenuItem(menuMain, IDM_LOG_SERIAL, serial_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -# ifdef ENABLE_NIC_LOG - CheckMenuItem(menuMain, IDM_LOG_NIC, nic_do_log?MF_CHECKED:MF_UNCHECKED); -# endif -#endif - + CheckMenuItem(menuMain, IDM_VID_HIDE_STATUS_BAR, hide_status_bar ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_HIDE_TOOLBAR, hide_tool_bar ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_FORCE43, force_43?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_OVERSCAN, enable_overscan?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_INVERT, invert_display ? MF_CHECKED : MF_UNCHECKED); - if (vid_resize) + if (vid_resize == 1) CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_SW+vid_api, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_REMEMBER, window_remember?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+scale, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_HIDPI, dpi_scale?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_CGACON, vid_cga_contrast?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+video_grayscale, MF_CHECKED); -#ifdef USE_DISCORD + video_set_filter_menu(menuMain); + if (discord_loaded) CheckMenuItem(menuMain, IDM_DISCORD, enable_discord ? MF_CHECKED : MF_UNCHECKED); else EnableMenuItem(menuMain, IDM_DISCORD, MF_DISABLED); +#ifdef MTR_ENABLED + EnableMenuItem(menuMain, IDM_ACTION_END_TRACE, MF_DISABLED); #endif -} + if (vid_resize) { + if (vid_resize >= 2) { + CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_UNCHECKED); + EnableMenuItem(menuMain, IDM_VID_RESIZE, MF_GRAYED); + } -static LRESULT CALLBACK -LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) -{ - BOOL bControlKeyDown; - KBDLLHOOKSTRUCT *p; - - if (nCode < 0 || nCode != HC_ACTION || (!mouse_capture && !video_fullscreen)) - return(CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)); - - p = (KBDLLHOOKSTRUCT*)lParam; - - /* disable alt-tab */ - if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return(1); - - /* disable alt-space */ - if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return(1); - - /* disable alt-escape */ - if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return(1); - - /* disable windows keys */ - if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return(1); - - /* checks ctrl key pressed */ - bControlKeyDown = GetAsyncKeyState(VK_CONTROL)>>((sizeof(SHORT)*8)-1); - - /* disable ctrl-escape */ - if (p->vkCode == VK_ESCAPE && bControlKeyDown) return(1); - - return(CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)); + CheckMenuItem(menuMain, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SCALE_2X, MF_CHECKED); + EnableMenuItem(menuMain, IDM_VID_SCALE_1X, MF_GRAYED); + EnableMenuItem(menuMain, IDM_VID_SCALE_2X, MF_GRAYED); + EnableMenuItem(menuMain, IDM_VID_SCALE_3X, MF_GRAYED); + EnableMenuItem(menuMain, IDM_VID_SCALE_4X, MF_GRAYED); + } } @@ -284,963 +362,43 @@ win_notify_dlg_closed(void) } -static LRESULT CALLBACK -MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +void +plat_power_off(void) { - HMENU hmenu; + confirm_exit = 0; + nvr_save(); + config_save(); - int i, sb_borders[3]; - RECT rect; + /* Deduct a sufficiently large number of cycles that no instructions will + run before the main thread is terminated */ + cycles -= 99999999; - int temp_x, temp_y; + KillTimer(hwndMain, TIMER_1SEC); + PostQuitMessage(0); - switch (message) { - case WM_CREATE: - SetTimer(hwnd, TIMER_1SEC, 1000, NULL); - hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, - LowLevelKeyboardProc, - GetModuleHandle(NULL), 0); - hook_enabled = 1; - break; + /* Cleanly terminate all of the emulator's components so as + to avoid things like threads getting stuck. */ + // do_stop(); + cpu_thread_run = 0; - case WM_COMMAND: - hmenu = GetMenu(hwnd); - switch (LOWORD(wParam)) { - case IDM_ACTION_SCREENSHOT: - take_screenshot(); - break; - - case IDM_ACTION_HRESET: - win_notify_dlg_open(); - i = ui_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_2112, NULL, (wchar_t *) IDS_2137, (wchar_t *) IDS_2138, NULL); - if (i == 0) - pc_reset_hard(); - win_notify_dlg_closed(); - break; - - case IDM_ACTION_RESET_CAD: - pc_send_cad(); - break; - - case IDM_ACTION_EXIT: - win_notify_dlg_open(); - if (no_quit_confirm) - i = 0; - else - i = ui_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_2113, NULL, (wchar_t *) IDS_2119, (wchar_t *) IDS_2136, NULL); - if (i == 0) { - UnhookWindowsHookEx(hKeyboardHook); - KillTimer(hwnd, TIMER_1SEC); - PostQuitMessage(0); - } - win_notify_dlg_closed(); - break; - - case IDM_ACTION_CTRL_ALT_ESC: - pc_send_cae(); - break; - - case IDM_ACTION_RCTRL_IS_LALT: - rctrl_is_lalt ^= 1; - CheckMenuItem(hmenu, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); - config_save(); - break; - - case IDM_ACTION_PAUSE: - plat_pause(dopause ^ 1); - CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); - break; - - case IDM_CONFIG: - win_settings_open(hwnd); - break; - - case IDM_ABOUT: - AboutDialogCreate(hwnd); - break; - - case IDM_UPDATE_ICONS: - update_icons ^= 1; - CheckMenuItem(hmenu, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); - config_save(); - break; - - case IDM_VID_RESIZE: - vid_resize = !vid_resize; - CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)? MF_CHECKED : MF_UNCHECKED); - - if (vid_resize) - SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW) | WS_VISIBLE); - else - SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX) | WS_VISIBLE); - - SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); - - GetWindowRect(hwnd, &rect); - - /* Main Window. */ - if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { - /* For platforms that subsystem version < 6.0 (default on mingw/msys2) */ - /* In this case, border sizes are different between resizable and non-resizable window */ - MoveWindow(hwnd, rect.left, rect.top, - unscaled_size_x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), - unscaled_size_y + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); - } else { - /* For platforms that subsystem version >= 6.0 (default on llvm-mingw, mainly for Windows/ARM) */ - /* In this case, border sizes are the same between resizable and non-resizable window */ - MoveWindow(hwnd, rect.left, rect.top, - unscaled_size_x + ((GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2), - unscaled_size_y + ((GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); - } - - /* Render window. */ - MoveWindow(hwndRender, 0, 0, unscaled_size_x, unscaled_size_y, TRUE); - GetWindowRect(hwndRender, &rect); - - /* Status bar. */ - MoveWindow(hwndSBAR, - 0, rect.bottom + GetSystemMetrics(SM_CYEDGE), - unscaled_size_x, 17, TRUE); - - if (mouse_capture) { - GetWindowRect(hwndRender, &rect); - - ClipCursor(&rect); - } - - if (vid_resize) { - CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); - CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); - scale = 1; - } - EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); - EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); - EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); - EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); - doresize = 1; - config_save(); - break; - - case IDM_VID_REMEMBER: - window_remember = !window_remember; - CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); - GetWindowRect(hwnd, &rect); - if (window_remember) { - window_x = rect.left; - window_y = rect.top; - window_w = rect.right - rect.left; - window_h = rect.bottom - rect.top; - } - config_save(); - break; - - case IDM_VID_SDL_SW: - case IDM_VID_SDL_HW: -#ifdef USE_VNC - case IDM_VID_VNC: -#endif - CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_UNCHECKED); - plat_setvid(LOWORD(wParam) - IDM_VID_SDL_SW); - CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_CHECKED); - config_save(); - break; - - case IDM_VID_FULLSCREEN: - plat_setfullscreen(1); - config_save(); - break; - - case IDM_VID_FS_FULL: - case IDM_VID_FS_43: - case IDM_VID_FS_KEEPRATIO: - case IDM_VID_FS_INT: - CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_UNCHECKED); - video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; - CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); - device_force_redraw(); - config_save(); - break; - - case IDM_VID_SCALE_1X: - case IDM_VID_SCALE_2X: - case IDM_VID_SCALE_3X: - case IDM_VID_SCALE_4X: - CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_UNCHECKED); - scale = LOWORD(wParam) - IDM_VID_SCALE_1X; - CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_CHECKED); - device_force_redraw(); - video_force_resize_set(1); - config_save(); - break; - - case IDM_VID_FORCE43: - video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); - video_force_resize_set(1); - break; - - case IDM_VID_INVERT: - video_toggle_option(hmenu, &invert_display, IDM_VID_INVERT); - break; - - case IDM_VID_OVERSCAN: - update_overscan = 1; - video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); - video_force_resize_set(1); - break; - - case IDM_VID_CGACON: - vid_cga_contrast ^= 1; - CheckMenuItem(hmenu, IDM_VID_CGACON, vid_cga_contrast ? MF_CHECKED : MF_UNCHECKED); - cgapal_rebuild(); - config_save(); - break; - - case IDM_VID_GRAYCT_601: - case IDM_VID_GRAYCT_709: - case IDM_VID_GRAYCT_AVE: - CheckMenuItem(hmenu, IDM_VID_GRAYCT_601+video_graytype, MF_UNCHECKED); - video_graytype = LOWORD(wParam) - IDM_VID_GRAYCT_601; - CheckMenuItem(hmenu, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); - device_force_redraw(); - config_save(); - break; - - case IDM_VID_GRAY_RGB: - case IDM_VID_GRAY_MONO: - case IDM_VID_GRAY_AMBER: - case IDM_VID_GRAY_GREEN: - case IDM_VID_GRAY_WHITE: - CheckMenuItem(hmenu, IDM_VID_GRAY_RGB+video_grayscale, MF_UNCHECKED); - video_grayscale = LOWORD(wParam) - IDM_VID_GRAY_RGB; - CheckMenuItem(hmenu, IDM_VID_GRAY_RGB+video_grayscale, MF_CHECKED); - device_force_redraw(); - config_save(); - break; - -#ifdef USE_DISCORD - case IDM_DISCORD: - if (! discord_loaded) break; - enable_discord ^= 1; - CheckMenuItem(hmenu, IDM_DISCORD, enable_discord ? MF_CHECKED : MF_UNCHECKED); - if(enable_discord) { - discord_init(); - discord_update_activity(dopause); - } else - discord_close(); - break; -#endif - -#ifdef ENABLE_LOG_TOGGLES -# ifdef ENABLE_BUSLOGIC_LOG - case IDM_LOG_BUSLOGIC: - buslogic_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif - -# ifdef ENABLE_CDROM_LOG - case IDM_LOG_CDROM: - cdrom_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif - -# ifdef ENABLE_D86F_LOG - case IDM_LOG_D86F: - d86f_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif - -# ifdef ENABLE_FDC_LOG - case IDM_LOG_FDC: - fdc_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif - -# ifdef ENABLE_IDE_LOG - case IDM_LOG_IDE: - ide_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif - -# ifdef ENABLE_SERIAL_LOG - case IDM_LOG_SERIAL: - serial_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_SERIAL, serial_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif - -# ifdef ENABLE_NIC_LOG - case IDM_LOG_NIC: - nic_do_log ^= 1; - CheckMenuItem(hmenu, IDM_LOG_NIC, nic_do_log ? MF_CHECKED : MF_UNCHECKED); - break; -# endif -#endif - -#ifdef ENABLE_LOG_BREAKPOINT - case IDM_LOG_BREAKPOINT: - pclog("---- LOG BREAKPOINT ----\n"); - break; -#endif - -#ifdef ENABLE_VRAM_DUMP - case IDM_DUMP_VRAM: - svga_dump_vram(); - break; -#endif - default: - media_menu_proc(hwnd, message, wParam, lParam); - break; - } - return(0); - - case WM_ENTERMENULOOP: - break; - - case WM_SIZE: - if (user_resize && !vid_resize) - break; - - SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); - - temp_x = (lParam & 0xFFFF); - temp_y = (lParam >> 16); - - if ((temp_x <= 0) || (temp_y <= 0)) { - minimized = 1; - break; - } else if (minimized == 1) { - minimized = 0; - video_force_resize_set(1); - } - - plat_vidapi_enable(0); - temp_y -= sbar_height; - if (temp_y < 1) - temp_y = 1; - - if ((temp_x != scrnsz_x) || (temp_y != scrnsz_y)) - doresize = 1; - - scrnsz_x = temp_x; - scrnsz_y = temp_y; - - MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); - - GetWindowRect(hwndRender, &rect); - - /* Status bar. */ - MoveWindow(hwndSBAR, - 0, rect.bottom + GetSystemMetrics(SM_CYEDGE), - scrnsz_x, 17, TRUE); - - plat_vidsize(scrnsz_x, scrnsz_y); - - if (mouse_capture) { - GetWindowRect(hwndRender, &rect); - - ClipCursor(&rect); - } - - if (window_remember) { - GetWindowRect(hwnd, &rect); - window_x = rect.left; - window_y = rect.top; - window_w = rect.right - rect.left; - window_h = rect.bottom - rect.top; - save_window_pos = 1; - } - plat_vidapi_enable(1); - - config_save(); - break; - - case WM_MOVE: - if (window_remember) { - GetWindowRect(hwnd, &rect); - window_x = rect.left; - window_y = rect.top; - window_w = rect.right - rect.left; - window_h = rect.bottom - rect.top; - save_window_pos = 1; - } - break; - - case WM_TIMER: - if (wParam == TIMER_1SEC) - pc_onesec(); - else if ((wParam >= 0x8000) && (wParam <= 0x80ff)) - ui_sb_timer_callback(wParam & 0xff); - break; - - case WM_LEAVEFULLSCREEN: - plat_setfullscreen(0); - config_save(); - break; - - case WM_KEYDOWN: - case WM_KEYUP: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - return(0); - - case WM_CLOSE: - win_notify_dlg_open(); - if (no_quit_confirm) - i = 0; - else - i = ui_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_2113, NULL, (wchar_t *) IDS_2119, (wchar_t *) IDS_2136, NULL); - if (i == 0) { - UnhookWindowsHookEx(hKeyboardHook); - KillTimer(hwnd, TIMER_1SEC); - PostQuitMessage(0); - } - win_notify_dlg_closed(); - break; - - case WM_DESTROY: - UnhookWindowsHookEx(hKeyboardHook); - KillTimer(hwnd, TIMER_1SEC); - PostQuitMessage(0); - break; - - case WM_SHOWSETTINGS: - if (manager_wm) - break; - manager_wm = 1; - win_settings_open(hwnd); - manager_wm = 0; - break; - - case WM_PAUSE: - if (manager_wm) - break; - manager_wm = 1; - plat_pause(dopause ^ 1); - CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); - manager_wm = 0; - break; - - case WM_HARDRESET: - if (manager_wm) - break; - win_notify_dlg_open(); - i = ui_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_2112, NULL, (wchar_t *) IDS_2137, (wchar_t *) IDS_2138, NULL); - if (i == 0) - pc_reset_hard(); - win_notify_dlg_closed(); - break; - - case WM_SHUTDOWN: - if (manager_wm) - break; - win_notify_dlg_open(); - if (no_quit_confirm) - i = 0; - else - i = ui_msgbox_ex(MBX_QUESTION_YN, (wchar_t *) IDS_2113, NULL, (wchar_t *) IDS_2119, (wchar_t *) IDS_2136, NULL); - if (i == 0) { - UnhookWindowsHookEx(hKeyboardHook); - KillTimer(hwnd, TIMER_1SEC); - PostQuitMessage(0); - } - win_notify_dlg_closed(); - break; - - case WM_CTRLALTDEL: - if (manager_wm) - break; - manager_wm = 1; - pc_send_cad(); - manager_wm = 0; - break; - - case WM_SYSCOMMAND: - /* - * Disable ALT key *ALWAYS*, - * I don't think there's any use for - * reaching the menu that way. - */ - if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0) { - return 0; /*disable ALT key for menu*/ - } - - default: - return(DefWindowProc(hwnd, message, wParam, lParam)); - - case WM_SETFOCUS: - infocus = 1; - if (! hook_enabled) { - hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, - LowLevelKeyboardProc, - GetModuleHandle(NULL), - 0); - hook_enabled = 1; - } - break; - - case WM_KILLFOCUS: - infocus = 0; - plat_mouse_capture(0); - if (hook_enabled) { - UnhookWindowsHookEx(hKeyboardHook); - hook_enabled = 0; - } - break; - - case WM_ENTERSIZEMOVE: - user_resize = 1; - break; - - case WM_EXITSIZEMOVE: - user_resize = 0; - - /* If window is not resizable, then tell the main thread to - resize it, as sometimes, moves can mess up the window size. */ - if (!vid_resize) - doresize = 1; - break; - } - - return(0); + // exit(-1); } - -static LRESULT CALLBACK -SubWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +#ifdef MTR_ENABLED +static void +handle_trace(HMENU hmenu, int trace) { - return(DefWindowProc(hwnd, message, wParam, lParam)); -} - - -static HRESULT CALLBACK -TaskDialogProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) -{ - switch (message) { - case TDN_HYPERLINK_CLICKED: - /* open linked URL */ - ShellExecute(hwnd, L"open", (LPCWSTR) lParam, NULL, NULL, SW_SHOW); - break; - } - - return S_OK; -} - - -int -ui_init(int nCmdShow) -{ - WCHAR title[200]; - WNDCLASSEX wincl; /* buffer for main window's class */ - RAWINPUTDEVICE ridev; /* RawInput device */ - MSG messages; /* received-messages buffer */ - HWND hwnd = NULL; /* handle for our window */ - HACCEL haccel; /* handle to accelerator table */ - RECT sbar_rect; /* RECT of the status bar */ - int bRet; - TASKDIALOGCONFIG tdconfig = {0}; - TASKDIALOG_BUTTON tdbuttons[] = {{IDCANCEL, MAKEINTRESOURCE(IDS_2119)}}; - - /* Set up TaskDialog configuration. */ - tdconfig.cbSize = sizeof(tdconfig); - tdconfig.dwFlags = TDF_ENABLE_HYPERLINKS; - tdconfig.dwCommonButtons = 0; - tdconfig.pszWindowTitle = MAKEINTRESOURCE(IDS_STRINGS); - tdconfig.pszMainIcon = TD_ERROR_ICON; - tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2050); - tdconfig.cButtons = ARRAYSIZE(tdbuttons); - tdconfig.pButtons = tdbuttons; - tdconfig.pfCallback = TaskDialogProcedure; - - /* Start settings-only mode if requested. */ - if (settings_only) { - if (! pc_init_modules()) { - /* Dang, no ROMs found at all! */ - tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2120); - tdconfig.pszContent = MAKEINTRESOURCE(IDS_2056); - TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); - return(6); - } - - win_settings_open(NULL); - return(0); - } - -#ifdef USE_DISCORD - if(! discord_load()) { - enable_discord = 0; - } else if (enable_discord) { - /* Initialize the Discord API */ - discord_init(); - - /* Update Discord status */ - discord_update_activity(dopause); - } -#endif - - /* Create our main window's class and register it. */ - wincl.hInstance = hinstance; - wincl.lpszClassName = CLASS_NAME; - wincl.lpfnWndProc = MainWindowProcedure; - wincl.style = CS_DBLCLKS; /* Catch double-clicks */ - wincl.cbSize = sizeof(WNDCLASSEX); - wincl.hIcon = LoadIcon(hinstance, (LPCTSTR)10); - wincl.hIconSm = LoadIcon(hinstance, (LPCTSTR)10); - wincl.hCursor = NULL; - wincl.lpszMenuName = NULL; - wincl.cbClsExtra = 0; - wincl.cbWndExtra = 0; - wincl.hbrBackground = CreateSolidBrush(RGB(0,0,0)); - if (! RegisterClassEx(&wincl)) - return(2); - wincl.lpszClassName = SUB_CLASS_NAME; - wincl.lpfnWndProc = SubWindowProcedure; - if (! RegisterClassEx(&wincl)) - return(2); - - /* Load the Window Menu(s) from the resources. */ - menuMain = LoadMenu(hinstance, MENU_NAME); - - /* Now create our main window. */ - mbstowcs(title, emu_version, sizeof_w(title)); - hwnd = CreateWindowEx ( - 0, /* no extended possibilites */ - CLASS_NAME, /* class name */ - title, /* Title Text */ - (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX) | DS_3DLOOK, - CW_USEDEFAULT, /* Windows decides the position */ - CW_USEDEFAULT, /* where window ends up on the screen */ - scrnsz_x+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* width */ - scrnsz_y+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ - HWND_DESKTOP, /* window is a child to desktop */ - menuMain, /* menu */ - hinstance, /* Program Instance handler */ - NULL); /* no Window Creation data */ - hwndMain = tdconfig.hwndParent = hwnd; - - ui_window_title(title); - - /* Set up main window for resizing if configured. */ - if (vid_resize) - SetWindowLongPtr(hwnd, GWL_STYLE, - (WS_OVERLAPPEDWINDOW)); - else - SetWindowLongPtr(hwnd, GWL_STYLE, - (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)); - - /* Move to the last-saved position if needed. */ - if (window_remember) - MoveWindow(hwnd, window_x, window_y, window_w, window_h, TRUE); - - /* Reset all menus to their defaults. */ - ResetAllMenus(); - media_menu_init(); - - /* Make the window visible on the screen. */ - ShowWindow(hwnd, nCmdShow); - - /* Initialize the RawInput (keyboard) module. */ - memset(&ridev, 0x00, sizeof(ridev)); - ridev.usUsagePage = 0x01; - ridev.usUsage = 0x06; - ridev.dwFlags = RIDEV_NOHOTKEYS; - ridev.hwndTarget = NULL; /* current focus window */ - if (! RegisterRawInputDevices(&ridev, 1, sizeof(ridev))) { - tdconfig.pszContent = MAKEINTRESOURCE(IDS_2105); - TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); - return(4); - } - keyboard_getkeymap(); - - /* Set up the main window for RawInput. */ - plat_set_input(hwndMain); - - /* Load the accelerator table */ - haccel = LoadAccelerators(hinstance, ACCEL_NAME); - if (haccel == NULL) { - tdconfig.pszContent = MAKEINTRESOURCE(IDS_2104); - TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); - return(3); - } - - /* Initialize the mouse module. */ - win_mouse_init(); - - /* Create the status bar window. */ - StatusBarCreate(hwndMain, IDC_STATUS, hinstance); - - /* Get the actual height of the statusbar, - * since that is not something we can change. - */ - GetWindowRect(hwndSBAR, &sbar_rect); - sbar_height = sbar_rect.bottom - sbar_rect.top; - - /* - * Before we can create the Render window, we first have - * to prepare some other things that it depends on. - */ - ghMutex = CreateMutex(NULL, FALSE, NULL); - - /* Create the Machine Rendering window. */ - hwndRender = CreateWindow(L"STATIC", NULL, WS_CHILD|SS_BITMAP, - 0, 0, 1, 1, hwnd, NULL, hinstance, NULL); - MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); - - /* All done, fire up the actual emulated machine. */ - if (! pc_init_modules()) { - /* Dang, no ROMs found at all! */ - tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2120); - tdconfig.pszContent = MAKEINTRESOURCE(IDS_2056); - TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); - return(6); - } - - /* Initialize the configured Video API. */ - if (! plat_setvid(vid_api)) { - tdconfig.pszContent = MAKEINTRESOURCE(IDS_2089); - TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); - return(5); - } - - /* Initialize the rendering window, or fullscreen. */ - if (start_in_fullscreen) - plat_setfullscreen(1); - - /* Set up the current window size. */ - plat_resize(scrnsz_x, scrnsz_y); - - /* Fire up the machine. */ - pc_reset_hard_init(); - - /* Set the PAUSE mode depending on the renderer. */ - plat_pause(0); - - /* If so requested via the command line, inform the - * application that started us of our HWND, using the - * the hWnd and unique ID the application has given - * us. */ - if (source_hwnd) - PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) hwndMain); - - /* - * Everything has been configured, and all seems to work, - * so now it is time to start the main thread to do some - * real work, and we will hang in here, dealing with the - * UI until we're done. - */ - do_start(); - - /* Run the message loop. It will run until GetMessage() returns 0 */ - while (! quited) { - bRet = GetMessage(&messages, NULL, 0, 0); - if ((bRet == 0) || quited) break; - - if (bRet == -1) { - fatal("bRet is -1\n"); - } - - if (messages.message == WM_QUIT) { - quited = 1; - break; - } - - if (! TranslateAccelerator(hwnd, haccel, &messages)) { - TranslateMessage(&messages); - DispatchMessage(&messages); - } - - if (mouse_capture && keyboard_ismsexit()) { - /* Release the in-app mouse. */ - plat_mouse_capture(0); - } - - if (video_fullscreen && keyboard_isfsexit()) { - /* Signal "exit fullscreen mode". */ - plat_setfullscreen(0); - } - -#ifdef USE_DISCORD - /* Run Discord API callbacks */ - if (enable_discord) - discord_run_callbacks(); -#endif - } - - timeEndPeriod(1); - - if (mouse_capture) - plat_mouse_capture(0); - - /* Close down the emulator. */ - do_stop(); - - UnregisterClass(SUB_CLASS_NAME, hinstance); - UnregisterClass(CLASS_NAME, hinstance); - - win_mouse_close(); - -#ifdef USE_DISCORD - /* Shut down the Discord integration */ - discord_close(); -#endif - - return(messages.wParam); -} - - -wchar_t * -ui_window_title(wchar_t *s) -{ - if (! video_fullscreen) { - if (s != NULL) { - if (wcslen(s) <= 512) - wcscpy(wTitle, s); - else - wcsncpy(wTitle, s, 512); - } else - s = wTitle; - - SetWindowText(hwndMain, s); + EnableMenuItem(hmenu, IDM_ACTION_BEGIN_TRACE, trace? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_ACTION_END_TRACE, trace? MF_ENABLED : MF_GRAYED); + if (trace) { + init_trace(); } else { - if (s == NULL) - s = wTitle; + shutdown_trace(); } - - return(s); } - - -/* We should have the language ID as a parameter. */ -void -plat_pause(int p) -{ - static wchar_t oldtitle[512]; - wchar_t title[512], *t; - - /* If un-pausing, as the renderer if that's OK. */ - if (p == 0) - p = get_vidpause(); - - /* If already so, done. */ - if (dopause == p) { - /* Send the WM to a manager if needed. */ - if (source_hwnd) - PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDSTATUS, (WPARAM) !!dopause, (LPARAM) hwndMain); - - return; - } - - if (p) { - t = ui_window_title(NULL); - if (wcslen(t) <= 511) - wcscpy(oldtitle, ui_window_title(NULL)); - else - wcsncpy(oldtitle, ui_window_title(NULL), 511); - wcscpy(title, oldtitle); - wcscat(title, L" - PAUSED -"); - ui_window_title(title); - } else { - ui_window_title(oldtitle); - } - - dopause = p; - - /* Update the actual menu. */ - CheckMenuItem(menuMain, IDM_ACTION_PAUSE, - (dopause) ? MF_CHECKED : MF_UNCHECKED); - -#if USE_DISCORD - /* Update Discord status */ - if(enable_discord) - discord_update_activity(dopause); #endif - /* Send the WM to a manager if needed. */ - if (source_hwnd) - PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDSTATUS, (WPARAM) !!dopause, (LPARAM) hwndMain); -} - - -/* Tell the UI about a new screen resolution. */ -void -plat_resize(int x, int y) -{ - int sb_borders[3]; - RECT r; - - /* First, see if we should resize the UI window. */ - if (!vid_resize) { - video_wait_for_blit(); - - SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); - - GetWindowRect(hwndMain, &r); - - if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { - /* For platforms that subsystem version < 6.0 (gcc on mingw/msys2) */ - /* In this case, border sizes are different between resizable and non-resizable window */ - MoveWindow(hwndMain, r.left, r.top, - x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), - y + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); - } else { - /* For platforms that subsystem version >= 6.0 (clang/llvm on llvm-mingw, mainly for Windows/ARM) */ - /* In this case, border sizes are the same between resizable and non-resizable window */ - MoveWindow(hwndMain, r.left, r.top, - x + ((GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2), - y + ((GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); - } - - MoveWindow(hwndRender, 0, 0, x, y, TRUE); - GetWindowRect(hwndRender, &r); - - MoveWindow(hwndSBAR, - 0, r.bottom + GetSystemMetrics(SM_CYEDGE), - x, 17, TRUE); - - if (mouse_capture) { - GetWindowRect(hwndRender, &r); - ClipCursor(&r); - } - } -} - - -void -plat_mouse_capture(int on) -{ - RECT rect; - - if (mouse_type == MOUSE_TYPE_NONE) - return; - - if (on && !mouse_capture) { - /* Enable the in-app mouse. */ - GetClipCursor(&oldclip); - GetWindowRect(hwndRender, &rect); - ClipCursor(&rect); - show_cursor(0); - mouse_capture = 1; - } else if (!on && mouse_capture) { - /* Disable the in-app mouse. */ - ClipCursor(&oldclip); - show_cursor(-1); - - mouse_capture = 0; - } -} - - /* Catch WM_INPUT messages for 'current focus' window. */ -static LONG_PTR input_orig_proc; -static HWND input_orig_hwnd = NULL; #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else @@ -1276,27 +434,21 @@ input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_SETFOCUS: infocus = 1; - if (! hook_enabled) { - hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, - LowLevelKeyboardProc, - GetModuleHandle(NULL), - 0); - hook_enabled = 1; - } break; case WM_KILLFOCUS: infocus = 0; plat_mouse_capture(0); - if (hook_enabled) { - UnhookWindowsHookEx(hKeyboardHook); - hook_enabled = 0; - } + break; + + case WM_LBUTTONDOWN: + button_down |= 1; break; case WM_LBUTTONUP: - if (! video_fullscreen) + if ((button_down & 1) && !video_fullscreen) plat_mouse_capture(1); + button_down &= ~1; break; case WM_MBUTTONUP: @@ -1305,27 +457,1135 @@ input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; default: - return(CallWindowProc((WNDPROC)input_orig_proc, - hwnd, message, wParam, lParam)); + return(1); + /* return(CallWindowProc((WNDPROC)input_orig_proc, + hwnd, message, wParam, lParam)); */ } return(0); } -/* Set up a handler for the 'currently active' window. */ -void -plat_set_input(HWND h) +static LRESULT CALLBACK +MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - /* If needed, rest the old one first. */ - if (input_orig_hwnd != NULL) { - SetWindowLongPtr(input_orig_hwnd, GWLP_WNDPROC, - (LONG_PTR)input_orig_proc); + HMENU hmenu; + + int i; + RECT rect, *rect_p; + + WINDOWPOS *pos; + + int temp_x, temp_y; + + if (input_proc(hwnd, message, wParam, lParam) == 0) + return(0); + + switch (message) { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + break; + + case WM_COMMAND: + hmenu = GetMenu(hwnd); + switch (LOWORD(wParam)) { + case IDM_ACTION_SCREENSHOT: + take_screenshot(); + break; + +#ifdef MTR_ENABLED + case IDM_ACTION_BEGIN_TRACE: + case IDM_ACTION_END_TRACE: + case IDM_ACTION_TRACE: + tracing_on = !tracing_on; + handle_trace(hmenu, tracing_on); + break; +#endif + + case IDM_ACTION_HRESET: + win_notify_dlg_open(); + if (confirm_reset) + i = ui_msgbox_ex(MBX_QUESTION_YN | MBX_DONTASK, (wchar_t *) IDS_2112, NULL, (wchar_t *) IDS_2137, (wchar_t *) IDS_2138, NULL); + else + i = 0; + if ((i % 10) == 0) { + pc_reset_hard(); + if (i == 10) { + confirm_reset = 0; + nvr_save(); + config_save(); + } + } + win_notify_dlg_closed(); + break; + + case IDM_ACTION_RESET_CAD: + pc_send_cad(); + break; + + case IDM_ACTION_EXIT: + win_notify_dlg_open(); + if (confirm_exit && confirm_exit_cmdl) + i = ui_msgbox_ex(MBX_QUESTION_YN | MBX_DONTASK, (wchar_t *) IDS_2113, NULL, (wchar_t *) IDS_2119, (wchar_t *) IDS_2136, NULL); + else + i = 0; + if ((i % 10) == 0) { + if (i == 10) { + confirm_exit = 0; + nvr_save(); + config_save(); + } + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } + win_notify_dlg_closed(); + break; + + case IDM_ACTION_CTRL_ALT_ESC: + pc_send_cae(); + break; + + case IDM_ACTION_RCTRL_IS_LALT: + rctrl_is_lalt ^= 1; + CheckMenuItem(hmenu, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + + case IDM_ACTION_KBD_REQ_CAPTURE: + kbd_req_capture ^= 1; + CheckMenuItem(hmenu, IDM_ACTION_KBD_REQ_CAPTURE, kbd_req_capture ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + + case IDM_ACTION_PAUSE: + plat_pause(dopause ^ 1); + CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); + break; + + case IDM_CONFIG: + win_settings_open(hwnd); + break; + + case IDM_SND_GAIN: + SoundGainDialogCreate(hwnd); + break; + + case IDM_ABOUT: + AboutDialogCreate(hwnd); + break; + + case IDM_DOCS: + ShellExecute(hwnd, L"open", EMU_DOCS_URL_W, NULL, NULL, SW_SHOW); + break; + + case IDM_UPDATE_ICONS: + update_icons ^= 1; + CheckMenuItem(hmenu, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + + case IDM_VID_HIDE_STATUS_BAR: + hide_status_bar ^= 1; + CheckMenuItem(hmenu, IDM_VID_HIDE_STATUS_BAR, hide_status_bar ? MF_CHECKED : MF_UNCHECKED); + ShowWindow(hwndSBAR, hide_status_bar ? SW_HIDE : SW_SHOW); + GetWindowRect(hwnd, &rect); + if (hide_status_bar) + MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top - sbar_height, TRUE); + else + MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top + sbar_height, TRUE); + config_save(); + break; + + case IDM_VID_HIDE_TOOLBAR: + hide_tool_bar ^= 1; + CheckMenuItem(hmenu, IDM_VID_HIDE_TOOLBAR, hide_tool_bar ? MF_CHECKED : MF_UNCHECKED); + ShowWindow(hwndRebar, hide_tool_bar ? SW_HIDE : SW_SHOW); + GetWindowRect(hwnd, &rect); + if (hide_tool_bar) { + MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top - tbar_height, TRUE); + SetWindowPos(hwndRender, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } else { + MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top + tbar_height, TRUE); + SetWindowPos(hwndRender, NULL, 0, tbar_height, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + config_save(); + break; + + case IDM_VID_RESIZE: + vid_resize ^= 1; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize & 1) ? MF_CHECKED : MF_UNCHECKED); + + if (vid_resize == 1) + SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW) | WS_VISIBLE); + else + SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX) | WS_VISIBLE); + + /* scale the screen base on DPI */ + if (dpi_scale) { + temp_x = MulDiv(unscaled_size_x, dpi, 96); + temp_y = MulDiv(unscaled_size_y, dpi, 96); + } else { + temp_x = unscaled_size_x; + temp_y = unscaled_size_y; + } + + ResizeWindowByClientArea(hwnd, temp_x, temp_y + (hide_status_bar ? 0 : sbar_height) + (hide_tool_bar ? 0 : tbar_height)); + + if (mouse_capture) { + ClipCursor(&rect); + } + + if (vid_resize) { + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); + scale = 1; + } + EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); + + scrnsz_x = unscaled_size_x; + scrnsz_y = unscaled_size_y; + atomic_store(&doresize_monitors[0], 1); + config_save(); + break; + + case IDM_VID_REMEMBER: + window_remember = !window_remember; + CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + if (window_remember || (vid_resize & 2)) { + window_x = rect.left; + window_y = rect.top; + if (!(vid_resize & 2)) { + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + } + } + config_save(); + break; + + case IDM_VID_SDL_SW: + case IDM_VID_SDL_HW: + case IDM_VID_SDL_OPENGL: + case IDM_VID_OPENGL_CORE: +#ifdef USE_VNC + case IDM_VID_VNC: +#endif + CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_UNCHECKED); + plat_setvid(LOWORD(wParam) - IDM_VID_SDL_SW); + CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_CHECKED); + video_set_filter_menu(hmenu); + config_save(); + show_render_options_menu(); + break; + + case IDM_VID_GL_FPS_BLITTER: + case IDM_VID_GL_FPS_25: + case IDM_VID_GL_FPS_30: + case IDM_VID_GL_FPS_50: + case IDM_VID_GL_FPS_60: + case IDM_VID_GL_FPS_75: + { + static const int fps[] = { -1, 25, 30, 50, 60, 75 }; + int idx = 0; + for (; fps[idx] != video_framerate; idx++); + CheckMenuItem(hmenu, IDM_VID_GL_FPS_BLITTER + idx, MF_UNCHECKED); + video_framerate = fps[LOWORD(wParam) - IDM_VID_GL_FPS_BLITTER]; + CheckMenuItem(hmenu, LOWORD(wParam), MF_CHECKED); + plat_vid_reload_options(); + config_save(); + break; + } + case IDM_VID_GL_VSYNC: + video_vsync = !video_vsync; + CheckMenuItem(hmenu, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED); + plat_vid_reload_options(); + config_save(); + break; + case IDM_VID_GL_SHADER: + win_notify_dlg_open(); + if (file_dlg_st(hwnd, IDS_2143, video_shader, NULL, 0) == 0) + { + strcpy_s(video_shader, sizeof(video_shader), openfilestring); + EnableMenuItem(menuMain, IDM_VID_GL_NOSHADER, strlen(video_shader) > 0 ? MF_ENABLED : MF_DISABLED); + } + win_notify_dlg_closed(); + plat_vid_reload_options(); + break; + case IDM_VID_GL_NOSHADER: + video_shader[0] = '\0'; + EnableMenuItem(menuMain, IDM_VID_GL_NOSHADER, MF_DISABLED); + plat_vid_reload_options(); + break; + + case IDM_VID_FULLSCREEN: + plat_setfullscreen(1); + config_save(); + break; + + case IDM_VID_FS_FULL: + case IDM_VID_FS_43: + case IDM_VID_FS_KEEPRATIO: + case IDM_VID_FS_INT: + CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_UNCHECKED); + video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; + CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); + device_force_redraw(); + config_save(); + break; + + case IDM_VID_SCALE_1X: + case IDM_VID_SCALE_2X: + case IDM_VID_SCALE_3X: + case IDM_VID_SCALE_4X: + CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_UNCHECKED); + scale = LOWORD(wParam) - IDM_VID_SCALE_1X; + CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_CHECKED); + reset_screen_size(); + device_force_redraw(); + video_force_resize_set(1); + atomic_store(&doresize_monitors[0], 1); + config_save(); + break; + + case IDM_VID_FILTER_NEAREST: + case IDM_VID_FILTER_LINEAR: + video_filter_method = LOWORD(wParam) - IDM_VID_FILTER_NEAREST; + video_set_filter_menu(hmenu); + plat_vid_reload_options(); + config_save(); + break; + + case IDM_VID_HIDPI: + dpi_scale = !dpi_scale; + CheckMenuItem(hmenu, IDM_VID_HIDPI, dpi_scale ? MF_CHECKED : MF_UNCHECKED); + atomic_store(&doresize_monitors[0], 1); + config_save(); + break; + + case IDM_PREFERENCES: + PreferencesDlgCreate(hwnd); + break; + + case IDM_VID_SPECIFY_DIM: + SpecifyDimensionsDialogCreate(hwnd); + break; + + case IDM_VID_FORCE43: + video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); + video_force_resize_set(1); + break; + + case IDM_VID_INVERT: + video_toggle_option(hmenu, &invert_display, IDM_VID_INVERT); + video_copy = (video_grayscale || invert_display) ? video_transform_copy : memcpy; + plat_vidapi_reload(); + break; + + case IDM_VID_OVERSCAN: + update_overscan = 1; + video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); + video_force_resize_set(1); + break; + + case IDM_VID_CGACON: + vid_cga_contrast ^= 1; + CheckMenuItem(hmenu, IDM_VID_CGACON, vid_cga_contrast ? MF_CHECKED : MF_UNCHECKED); + cgapal_rebuild(); + config_save(); + break; + + case IDM_VID_GRAYCT_601: + case IDM_VID_GRAYCT_709: + case IDM_VID_GRAYCT_AVE: + CheckMenuItem(hmenu, IDM_VID_GRAYCT_601+video_graytype, MF_UNCHECKED); + video_graytype = LOWORD(wParam) - IDM_VID_GRAYCT_601; + CheckMenuItem(hmenu, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); + device_force_redraw(); + config_save(); + break; + + case IDM_VID_GRAY_RGB: + case IDM_VID_GRAY_MONO: + case IDM_VID_GRAY_AMBER: + case IDM_VID_GRAY_GREEN: + case IDM_VID_GRAY_WHITE: + CheckMenuItem(hmenu, IDM_VID_GRAY_RGB+video_grayscale, MF_UNCHECKED); + video_grayscale = LOWORD(wParam) - IDM_VID_GRAY_RGB; + video_copy = (video_grayscale || invert_display) ? video_transform_copy : memcpy; + plat_vidapi_reload(); + CheckMenuItem(hmenu, IDM_VID_GRAY_RGB+video_grayscale, MF_CHECKED); + device_force_redraw(); + config_save(); + break; + + case IDM_DISCORD: + if (! discord_loaded) break; + enable_discord ^= 1; + CheckMenuItem(hmenu, IDM_DISCORD, enable_discord ? MF_CHECKED : MF_UNCHECKED); + if(enable_discord) { + discord_init(); + discord_update_activity(dopause); + } else + discord_close(); + break; + + default: + media_menu_proc(hwnd, message, wParam, lParam); + break; + } + return(0); + + case WM_ENTERMENULOOP: + break; + + case WM_DPICHANGED: + dpi = HIWORD(wParam); + GetWindowRect(hwndSBAR, &rect); + sbar_height = rect.bottom - rect.top; + GetWindowRect(hwndRebar, &rect); + tbar_height = rect.bottom - rect.top; + rect_p = (RECT*)lParam; + if (vid_resize == 1) + MoveWindow(hwnd, rect_p->left, rect_p->top, rect_p->right - rect_p->left, rect_p->bottom - rect_p->top, TRUE); + else if (vid_resize >= 2) { + temp_x = fixed_size_x; + temp_y = fixed_size_y; + if (dpi_scale) { + temp_x = MulDiv(temp_x, dpi, 96); + temp_y = MulDiv(temp_y, dpi, 96); + } + + /* Main Window. */ + ResizeWindowByClientArea(hwndMain, temp_x, temp_y + (hide_status_bar ? 0 : sbar_height) + (hide_tool_bar ? 0 : tbar_height)); + } else if (!user_resize) + atomic_store(&doresize_monitors[0], 1); + break; + + case WM_WINDOWPOSCHANGED: + if (video_fullscreen & 1) + PostMessage(hwndMain, WM_LEAVEFULLSCREEN, 0, 0); + + pos = (WINDOWPOS*)lParam; + GetClientRect(hwndMain, &rect); + + if (IsIconic(hwndMain)) { + plat_vidapi_enable(0); + minimized = 1; + return(0); + } else if (minimized) { + minimized = 0; + video_force_resize_set(1); + } + + if (!(pos->flags & SWP_NOSIZE) && (window_remember || (vid_resize & 2))) { + window_x = pos->x; + window_y = pos->y; + if (!(vid_resize & 2)) { + window_w = pos->cx; + window_h = pos->cy; + } + save_window_pos = 1; + config_save(); + } + + if (!(pos->flags & SWP_NOSIZE) || !user_resize) { + plat_vidapi_enable(0); + + if (!hide_status_bar) + MoveWindow(hwndSBAR, 0, rect.bottom - sbar_height, sbar_height, rect.right, TRUE); + + if (!hide_tool_bar) + MoveWindow(hwndRebar, 0, 0, rect.right, tbar_height, TRUE); + + MoveWindow(hwndRender, 0, hide_tool_bar ? 0 : tbar_height, rect.right, rect.bottom - (hide_status_bar ? 0 : sbar_height) - (hide_tool_bar ? 0 : tbar_height), TRUE); + + GetClientRect(hwndRender, &rect); + if (dpi_scale) { + temp_x = MulDiv(rect.right, 96, dpi); + temp_y = MulDiv(rect.bottom, 96, dpi); + + if (temp_x != scrnsz_x || temp_y != scrnsz_y) { + scrnsz_x = temp_x; + scrnsz_y = temp_y; + atomic_store(&doresize_monitors[0], 1); + } + } else { + if (rect.right != scrnsz_x || rect.bottom != scrnsz_y) { + scrnsz_x = rect.right; + scrnsz_y = rect.bottom; + atomic_store(&doresize_monitors[0], 1); + } + } + + plat_vidsize(rect.right, rect.bottom); + + if (mouse_capture) { + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + } + + plat_vidapi_enable(2); + } + + return(0); + + case WM_TIMER: + if (wParam == TIMER_1SEC) + pc_onesec(); + else if ((wParam >= 0x8000) && (wParam <= 0x80ff)) + ui_sb_timer_callback(wParam & 0xff); + break; + + case WM_LEAVEFULLSCREEN: + plat_setfullscreen(0); + config_save(); + break; + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + return(0); + + case WM_CLOSE: + win_notify_dlg_open(); + if (confirm_exit && confirm_exit_cmdl) + i = ui_msgbox_ex(MBX_QUESTION_YN | MBX_DONTASK, (wchar_t *) IDS_2113, NULL, (wchar_t *) IDS_2119, (wchar_t *) IDS_2136, NULL); + else + i = 0; + if ((i % 10) == 0) { + if (i == 10) { + confirm_exit = 0; + nvr_save(); + config_save(); + } + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } + win_notify_dlg_closed(); + break; + + case WM_DESTROY: + win_clear_icon_set(); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + break; + + case WM_SHOWSETTINGS: + if (manager_wm) + break; + manager_wm = 1; + win_settings_open(hwnd); + manager_wm = 0; + break; + + case WM_PAUSE: + if (manager_wm) + break; + manager_wm = 1; + plat_pause(dopause ^ 1); + CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); + manager_wm = 0; + break; + + case WM_HARDRESET: + if (manager_wm) + break; + win_notify_dlg_open(); + if (confirm_reset) + i = ui_msgbox_ex(MBX_QUESTION_YN | MBX_DONTASK, (wchar_t *) IDS_2112, NULL, (wchar_t *) IDS_2137, (wchar_t *) IDS_2138, NULL); + else + i = 0; + if ((i % 10) == 0) { + pc_reset_hard(); + if (i == 10) { + confirm_reset = 0; + nvr_save(); + config_save(); + } + } + win_notify_dlg_closed(); + break; + + case WM_SHUTDOWN: + if (manager_wm) + break; + if (LOWORD(wParam) == 1) { + confirm_exit = 0; + nvr_save(); + config_save(); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } else { + win_notify_dlg_open(); + if (confirm_exit && confirm_exit_cmdl) + i = ui_msgbox_ex(MBX_QUESTION_YN | MBX_DONTASK, (wchar_t *) IDS_2113, NULL, (wchar_t *) IDS_2119, (wchar_t *) IDS_2136, NULL); + else + i = 0; + if ((i % 10) == 0) { + if (i == 10) { + confirm_exit = 0; + nvr_save(); + config_save(); + } + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } + win_notify_dlg_closed(); + } + break; + + case WM_CTRLALTDEL: + if (manager_wm) + break; + manager_wm = 1; + pc_send_cad(); + manager_wm = 0; + break; + + case WM_SYSCOMMAND: + /* + * Disable ALT key *ALWAYS*, + * I don't think there's any use for + * reaching the menu that way. + */ + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0) { + return 0; /*disable ALT key for menu*/ + } + + default: + return(DefWindowProc(hwnd, message, wParam, lParam)); + + case WM_SETFOCUS: + infocus = 1; + break; + + case WM_KILLFOCUS: + infocus = 0; + plat_mouse_capture(0); + break; + + case WM_ACTIVATE: + if ((wParam != WA_INACTIVE) && !(video_fullscreen & 2)) { + video_force_resize_set(1); + plat_vidapi_enable(0); + plat_vidapi_enable(1); + } + break; + + case WM_ACTIVATEAPP: + /* Leave full screen on switching application except + for OpenGL Core and VNC renderers. */ + if (video_fullscreen & 1 && wParam == FALSE && vid_api < 3) + PostMessage(hwndMain, WM_LEAVEFULLSCREEN, 0, 0); + break; + + case WM_ENTERSIZEMOVE: + user_resize = 1; + break; + + case WM_EXITSIZEMOVE: + user_resize = 0; + + /* If window is not resizable, then tell the main thread to + resize it, as sometimes, moves can mess up the window size. */ + if (!vid_resize) + atomic_store(&doresize_monitors[0], 1); + break; } - /* Redirect the window procedure so we can catch WM_INPUT. */ - input_orig_proc = GetWindowLongPtr(h, GWLP_WNDPROC); - input_orig_hwnd = h; - SetWindowLongPtr(h, GWLP_WNDPROC, (LONG_PTR)&input_proc); - ImmAssociateContext(h, NULL); + return(0); } + + +static LRESULT CALLBACK +SubWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_LBUTTONDOWN: + button_down |= 2; + break; + + case WM_LBUTTONUP: + if ((button_down & 2) && !video_fullscreen) + plat_mouse_capture(1); + button_down &= ~2; + break; + + case WM_MBUTTONUP: + if (mouse_get_buttons() < 3) + plat_mouse_capture(0); + break; + + default: + return(DefWindowProc(hwnd, message, wParam, lParam)); + } + + return(0); +} + + +static LRESULT CALLBACK +SDLMainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (input_proc(hwnd, message, wParam, lParam) == 0) + return(0); + + return(DefWindowProc(hwnd, message, wParam, lParam)); +} + + +static LRESULT CALLBACK +SDLSubWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + return(DefWindowProc(hwnd, message, wParam, lParam)); +} + + +static HRESULT CALLBACK +TaskDialogProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) +{ + switch (message) { + case TDN_HYPERLINK_CLICKED: + /* open linked URL */ + ShellExecute(hwnd, L"open", (LPCWSTR) lParam, NULL, NULL, SW_SHOW); + break; + } + + return S_OK; +} + + +int +ui_init(int nCmdShow) +{ + WCHAR title[200]; + WNDCLASSEX wincl; /* buffer for main window's class */ + RAWINPUTDEVICE ridev; /* RawInput device */ + MSG messages = {0}; /* received-messages buffer */ + HWND hwnd = NULL; /* handle for our window */ + HACCEL haccel; /* handle to accelerator table */ + RECT rect; + int bRet; + TASKDIALOGCONFIG tdconfig = {0}; + TASKDIALOG_BUTTON tdbuttons[] = {{IDCANCEL, MAKEINTRESOURCE(IDS_2119)}}; + uint32_t helper_lang; + + /* Load DPI related Windows 10 APIs */ + user32_handle = dynld_module("user32.dll", user32_imports); + + /* Set the application ID for the taskbar. */ + shell32_handle = dynld_module("shell32.dll", shell32_imports); + if (shell32_handle) + pSetCurrentProcessExplicitAppUserModelID(L"86Box.86Box"); + + /* Set up TaskDialog configuration. */ + tdconfig.cbSize = sizeof(tdconfig); + tdconfig.dwFlags = TDF_ENABLE_HYPERLINKS; + tdconfig.dwCommonButtons = 0; + tdconfig.pszWindowTitle = MAKEINTRESOURCE(IDS_STRINGS); + tdconfig.pszMainIcon = TD_ERROR_ICON; + tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2050); + tdconfig.cButtons = ARRAYSIZE(tdbuttons); + tdconfig.pButtons = tdbuttons; + tdconfig.pfCallback = TaskDialogProcedure; + + /* Load the desired iconset */ + win_load_icon_set(); + + /* Start settings-only mode if requested. */ + if (settings_only) { + if (! pc_init_modules()) { + /* Dang, no ROMs found at all! */ + tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2120); + tdconfig.pszContent = MAKEINTRESOURCE(IDS_2056); + TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); + return(6); + } + + + /* Load the desired language */ + helper_lang = lang_id; + lang_id = 0; + set_language(helper_lang); + + win_settings_open(NULL); + return(0); + } + + if(! discord_load()) { + enable_discord = 0; + } else if (enable_discord) { + /* Initialize the Discord API */ + discord_init(); + + /* Update Discord status */ + discord_update_activity(dopause); + } + + /* Create our main window's class and register it. */ + wincl.hInstance = hinstance; + wincl.lpszClassName = CLASS_NAME; + wincl.lpfnWndProc = MainWindowProcedure; + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof(WNDCLASSEX); + wincl.hIcon = NULL; + wincl.hIconSm = NULL; + wincl.hCursor = NULL; + wincl.lpszMenuName = NULL; + wincl.cbClsExtra = 0; + wincl.cbWndExtra = 0; + wincl.hbrBackground = CreateSolidBrush(RGB(0,0,0)); + + /* Load proper icons */ + wchar_t path[MAX_PATH + 1] = {0}; + GetModuleFileNameW(hinstance, path, MAX_PATH); + ExtractIconExW(path, 0, &wincl.hIcon, &wincl.hIconSm, 1); + + if (! RegisterClassEx(&wincl)) + return(2); + wincl.lpszClassName = SUB_CLASS_NAME; + wincl.lpfnWndProc = SubWindowProcedure; + if (! RegisterClassEx(&wincl)) + return(2); + wincl.lpszClassName = SDL_CLASS_NAME; + wincl.lpfnWndProc = SDLMainWindowProcedure; + if (! RegisterClassEx(&wincl)) + return(2); + wincl.lpszClassName = SDL_SUB_CLASS_NAME; + wincl.lpfnWndProc = SDLSubWindowProcedure; + if (! RegisterClassEx(&wincl)) + return(2); + + /* Now create our main window. */ + swprintf_s(title, sizeof_w(title), L"%hs - %s %s", vm_name, EMU_NAME_W, EMU_VERSION_FULL_W); + hwnd = CreateWindowEx ( + 0, /* no extended possibilites */ + CLASS_NAME, /* class name */ + title, /* Title Text */ + (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX) | DS_3DLOOK, + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where window ends up on the screen */ + scrnsz_x+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* width */ + scrnsz_y+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* window is a child to desktop */ + NULL, /* no menu (yet) */ + hinstance, /* Program Instance handler */ + NULL); /* no Window Creation data */ + hwndMain = tdconfig.hwndParent = hwnd; + + ui_window_title(title); + + /* Get the current DPI */ + dpi = win_get_dpi(hwndMain); + + /* Check if we have a padded window frame */ + padded_frame = (GetSystemMetrics(SM_CXPADDEDBORDER) != 0); + + /* Create the status bar window. */ + StatusBarCreate(hwndMain, IDC_STATUS, hinstance); + + /* Get the actual height of the status bar */ + GetWindowRect(hwndSBAR, &rect); + sbar_height = rect.bottom - rect.top; + if (hide_status_bar) + ShowWindow(hwndSBAR, SW_HIDE); + + /* Create the toolbar window. */ + ToolBarCreate(hwndMain, hinstance); + + /* Get the actual height of the toolbar */ + tbar_height = SendMessage(hwndRebar, RB_GETROWHEIGHT, 0, 0); + if (hide_tool_bar) + ShowWindow(hwndRebar, SW_HIDE); + + /* Set up main window for resizing if configured. */ + if (vid_resize == 1) + SetWindowLongPtr(hwnd, GWL_STYLE, + (WS_OVERLAPPEDWINDOW)); + else + SetWindowLongPtr(hwnd, GWL_STYLE, + (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)); + + /* Create the Machine Rendering window. */ + hwndRender = CreateWindow(/*L"STATIC"*/ SUB_CLASS_NAME, NULL, WS_CHILD|SS_BITMAP, + 0, 0, 1, 1, hwnd, NULL, hinstance, NULL); + + /* Initiate a resize in order to properly arrange all controls. + Move to the last-saved position if needed. */ + if ((vid_resize < 2) && window_remember) + MoveWindow(hwnd, window_x, window_y, window_w, window_h, TRUE); + else { + if (vid_resize >= 2) { + MoveWindow(hwnd, window_x, window_y, window_w, window_h, TRUE); + scrnsz_x = fixed_size_x; + scrnsz_y = fixed_size_y; + } + ResizeWindowByClientArea(hwnd, scrnsz_x, scrnsz_y + (hide_status_bar ? 0 : sbar_height) + (hide_tool_bar ? 0 : tbar_height)); + } + + /* Load the desired language */ + helper_lang = lang_id; + lang_id = 0; + set_language(helper_lang); + + /* Make the window visible on the screen. */ + ShowWindow(hwnd, nCmdShow); + + /* Warn the user about unsupported configs. */ + if (cpu_override && ui_msgbox_ex(MBX_WARNING | MBX_QUESTION_OK, (void*)IDS_2145, (void*)IDS_2146, (void*)IDS_2147, (void*)IDS_2119, NULL)) + { + DestroyWindow(hwnd); + return(0); + } + + GetClipCursor(&oldclip); + + /* Initialize the RawInput (keyboard) module. */ + memset(&ridev, 0x00, sizeof(ridev)); + ridev.usUsagePage = 0x01; + ridev.usUsage = 0x06; + ridev.dwFlags = RIDEV_NOHOTKEYS; + ridev.hwndTarget = NULL; /* current focus window */ + if (! RegisterRawInputDevices(&ridev, 1, sizeof(ridev))) { + tdconfig.pszContent = MAKEINTRESOURCE(IDS_2105); + TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); + return(4); + } + keyboard_getkeymap(); + + /* Load the accelerator table */ + haccel = LoadAccelerators(hinstance, ACCEL_NAME); + if (haccel == NULL) { + tdconfig.pszContent = MAKEINTRESOURCE(IDS_2104); + TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); + return(3); + } + + /* Initialize the mouse module. */ + if (!start_in_fullscreen) + win_mouse_init(); + + /* + * Before we can create the Render window, we first have + * to prepare some other things that it depends on. + */ + ghMutex = CreateMutex(NULL, FALSE, NULL); + + /* All done, fire up the actual emulated machine. */ + if (! pc_init_modules()) { + /* Dang, no ROMs found at all! */ + tdconfig.pszMainInstruction = MAKEINTRESOURCE(IDS_2120); + tdconfig.pszContent = MAKEINTRESOURCE(IDS_2056); + TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); + return(6); + } + + /* Initialize the configured Video API. */ + if (! plat_setvid(vid_api)) { + tdconfig.pszContent = MAKEINTRESOURCE(IDS_2089); + TaskDialogIndirect(&tdconfig, NULL, NULL, NULL); + return(5); + } + + /* Set up the current window size. */ + if (vid_resize & 2) + plat_resize(fixed_size_x, fixed_size_y); + else + plat_resize(scrnsz_x, scrnsz_y); + + /* Initialize the rendering window, or fullscreen. */ + if (start_in_fullscreen) + plat_setfullscreen(3); + + /* Fire up the machine. */ + pc_reset_hard_init(); + + /* Set the PAUSE mode depending on the renderer. */ + plat_pause(0); + + /* If so requested via the command line, inform the + * application that started us of our HWND, using the + * the hWnd and unique ID the application has given + * us. */ + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) hwndMain); + + /* + * Everything has been configured, and all seems to work, + * so now it is time to start the main thread to do some + * real work, and we will hang in here, dealing with the + * UI until we're done. + */ + do_start(); + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (! is_quit) { + bRet = GetMessage(&messages, NULL, 0, 0); + if ((bRet == 0) || is_quit) break; + + if (bRet == -1) { + fatal("bRet is -1\n"); + } + + /* On WM_QUIT, tell the CPU thread to stop running. That will then tell us + to stop running as well. */ + if (messages.message == WM_QUIT) + cpu_thread_run = 0; + + if (! TranslateAccelerator(hwnd, haccel, &messages)) + { + /* Don't process other keypresses. */ + if (messages.message == WM_SYSKEYDOWN || + messages.message == WM_SYSKEYUP || + messages.message == WM_KEYDOWN || + messages.message == WM_KEYUP) + continue; + + TranslateMessage(&messages); + DispatchMessage(&messages); + } + + if (mouse_capture && keyboard_ismsexit()) { + /* Release the in-app mouse. */ + plat_mouse_capture(0); + } + + if (video_fullscreen && keyboard_isfsexit()) { + /* Signal "exit fullscreen mode". */ + plat_setfullscreen(0); + } + + /* Run Discord API callbacks */ + if (enable_discord) + discord_run_callbacks(); + } + + timeEndPeriod(1); + + if (mouse_capture) + plat_mouse_capture(0); + + /* Close down the emulator. */ + do_stop(); + + UnregisterClass(SDL_SUB_CLASS_NAME, hinstance); + UnregisterClass(SDL_CLASS_NAME, hinstance); + UnregisterClass(SUB_CLASS_NAME, hinstance); + UnregisterClass(CLASS_NAME, hinstance); + + win_mouse_close(); + + /* Shut down the Discord integration */ + discord_close(); + + if (user32_handle != NULL) + dynld_close(user32_handle); + + return(messages.wParam); +} + + +/* We should have the language ID as a parameter. */ +void +plat_pause(int p) +{ + static wchar_t oldtitle[512]; + wchar_t title[512]; + + /* If un-pausing, as the renderer if that's OK. */ + if (p == 0) + p = get_vidpause(); + + /* If already so, done. */ + if (dopause == p) { + /* Send the WM to a manager if needed. */ + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDSTATUS, (WPARAM) !!dopause, (LPARAM) hwndMain); + + return; + } + + if (p) { + wcsncpy(oldtitle, ui_window_title(NULL), sizeof_w(oldtitle) - 1); + wcscpy(title, oldtitle); + wcscat(title, plat_get_string(IDS_2051)); + ui_window_title(title); + } else { + ui_window_title(oldtitle); + } + + /* If un-pausing, synchronize the internal clock with the host's time. */ + if ((p == 0) && (time_sync & TIME_SYNC_ENABLED)) + nvr_time_sync(); + + dopause = p; + + /* Update the actual menu. */ + CheckMenuItem(menuMain, IDM_ACTION_PAUSE, + (dopause) ? MF_CHECKED : MF_UNCHECKED); + + /* Update Discord status */ + if (enable_discord) + discord_update_activity(dopause); + + /* Update the toolbar */ + ToolBarUpdatePause(p); + + /* Send the WM to a manager if needed. */ + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDSTATUS, (WPARAM) !!dopause, (LPARAM) hwndMain); +} + + +/* Tell the UI about a new screen resolution. */ +void +plat_resize(int x, int y) +{ + /* First, see if we should resize the UI window. */ + if (!vid_resize) { + /* scale the screen base on DPI */ + if (dpi_scale) { + x = MulDiv(x, dpi, 96); + y = MulDiv(y, dpi, 96); + } + ResizeWindowByClientArea(hwndMain, x, y + (hide_status_bar ? 0 : sbar_height) + (hide_tool_bar ? 0 : tbar_height)); + } +} + + +void plat_resize_request(int w, int h, int monitor_index) +{ + atomic_store((&doresize_monitors[monitor_index]), 1); +} + + +void +plat_mouse_capture(int on) +{ + RECT rect; + + if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE)) + return; + + if (on && !mouse_capture) { + /* Enable the in-app mouse. */ + GetClipCursor(&oldclip); + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + show_cursor(0); + mouse_capture = 1; + } else if (!on && mouse_capture) { + /* Disable the in-app mouse. */ + ClipCursor(&oldclip); + show_cursor(-1); + + mouse_capture = 0; + } +} + +void ui_init_monitor(int monitor_index) {} +void ui_deinit_monitor(int monitor_index) {} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 000000000..f3b639078 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,61 @@ +{ + "name": "86box", + "version-string": "3.6", + "homepage": "https://86box.net/", + "documentation": "http://86box.readthedocs.io/", + "license": "GPL-2.0-or-later", + "dependencies": [ + "freetype", + "libpng", + "sdl2", + "rtmidi" + ], + "features": { + "qt-ui": { + "description": "Qt User Interface", + "dependencies": [ + { + "name": "qtbase", + "default-features": false, + "features": [ + "concurrent", + "default-features", + "gui", + "harfbuzz", + "network", + "vulkan", + "widgets", + "png", + "zstd" + ] + }, + { + "name": "qttools", + "default-features": false, + "features": [ + "linguist" + ], + "host": true + } + ] + }, + "munt": { + "description": "Roland MT-32 emulation", + "dependencies": [ + "libmt32emu" + ] + }, + "slirp": { + "description": "Slirp network support", + "dependencies": [ + "libslirp" + ] + }, + "openal": { + "description": "OpenAL sound backend", + "dependencies": [ + "openal-soft" + ] + } + } +} diff --git a/wl_protocols/pointer-constraints-unstable-v1.xml b/wl_protocols/pointer-constraints-unstable-v1.xml new file mode 100644 index 000000000..efd64b660 --- /dev/null +++ b/wl_protocols/pointer-constraints-unstable-v1.xml @@ -0,0 +1,339 @@ + + + + + Copyright © 2014 Jonas Ådahl + Copyright © 2015 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a set of interfaces used for adding constraints to + the motion of a pointer. Possible constraints include confining pointer + motions to a given region, or locking it to its current position. + + In order to constrain the pointer, a client must first bind the global + interface "wp_pointer_constraints" which, if a compositor supports pointer + constraints, is exposed by the registry. Using the bound global object, the + client uses the request that corresponds to the type of constraint it wants + to make. See wp_pointer_constraints for more details. + + Warning! The protocol described in this file is experimental and backward + incompatible changes may be made. Backward compatible changes may be added + together with the corresponding interface version bump. Backward + incompatible changes are done by bumping the version number in the protocol + and interface names and resetting the interface version. Once the protocol + is to be declared stable, the 'z' prefix and the version number in the + protocol and interface names are removed and the interface version number is + reset. + + + + + The global interface exposing pointer constraining functionality. It + exposes two requests: lock_pointer for locking the pointer to its + position, and confine_pointer for locking the pointer to a region. + + The lock_pointer and confine_pointer requests create the objects + wp_locked_pointer and wp_confined_pointer respectively, and the client can + use these objects to interact with the lock. + + For any surface, only one lock or confinement may be active across all + wl_pointer objects of the same seat. If a lock or confinement is requested + when another lock or confinement is active or requested on the same surface + and with any of the wl_pointer objects of the same seat, an + 'already_constrained' error will be raised. + + + + + These errors can be emitted in response to wp_pointer_constraints + requests. + + + + + + + These values represent different lifetime semantics. They are passed + as arguments to the factory requests to specify how the constraint + lifetimes should be managed. + + + + A oneshot pointer constraint will never reactivate once it has been + deactivated. See the corresponding deactivation event + (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for + details. + + + + + A persistent pointer constraint may again reactivate once it has + been deactivated. See the corresponding deactivation event + (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for + details. + + + + + + + Used by the client to notify the server that it will no longer use this + pointer constraints object. + + + + + + The lock_pointer request lets the client request to disable movements of + the virtual pointer (i.e. the cursor), effectively locking the pointer + to a position. This request may not take effect immediately; in the + future, when the compositor deems implementation-specific constraints + are satisfied, the pointer lock will be activated and the compositor + sends a locked event. + + The protocol provides no guarantee that the constraints are ever + satisfied, and does not require the compositor to send an error if the + constraints cannot ever be satisfied. It is thus possible to request a + lock that will never activate. + + There may not be another pointer constraint of any kind requested or + active on the surface for any of the wl_pointer objects of the seat of + the passed pointer when requesting a lock. If there is, an error will be + raised. See general pointer lock documentation for more details. + + The intersection of the region passed with this request and the input + region of the surface is used to determine where the pointer must be + in order for the lock to activate. It is up to the compositor whether to + warp the pointer or require some kind of user interaction for the lock + to activate. If the region is null the surface input region is used. + + A surface may receive pointer focus without the lock being activated. + + The request creates a new object wp_locked_pointer which is used to + interact with the lock as well as receive updates about its state. See + the the description of wp_locked_pointer for further information. + + Note that while a pointer is locked, the wl_pointer objects of the + corresponding seat will not emit any wl_pointer.motion events, but + relative motion events will still be emitted via wp_relative_pointer + objects of the same seat. wl_pointer.axis and wl_pointer.button events + are unaffected. + + + + + + + + + + + The confine_pointer request lets the client request to confine the + pointer cursor to a given region. This request may not take effect + immediately; in the future, when the compositor deems implementation- + specific constraints are satisfied, the pointer confinement will be + activated and the compositor sends a confined event. + + The intersection of the region passed with this request and the input + region of the surface is used to determine where the pointer must be + in order for the confinement to activate. It is up to the compositor + whether to warp the pointer or require some kind of user interaction for + the confinement to activate. If the region is null the surface input + region is used. + + The request will create a new object wp_confined_pointer which is used + to interact with the confinement as well as receive updates about its + state. See the the description of wp_confined_pointer for further + information. + + + + + + + + + + + + The wp_locked_pointer interface represents a locked pointer state. + + While the lock of this object is active, the wl_pointer objects of the + associated seat will not emit any wl_pointer.motion events. + + This object will send the event 'locked' when the lock is activated. + Whenever the lock is activated, it is guaranteed that the locked surface + will already have received pointer focus and that the pointer will be + within the region passed to the request creating this object. + + To unlock the pointer, send the destroy request. This will also destroy + the wp_locked_pointer object. + + If the compositor decides to unlock the pointer the unlocked event is + sent. See wp_locked_pointer.unlock for details. + + When unlocking, the compositor may warp the cursor position to the set + cursor position hint. If it does, it will not result in any relative + motion events emitted via wp_relative_pointer. + + If the surface the lock was requested on is destroyed and the lock is not + yet activated, the wp_locked_pointer object is now defunct and must be + destroyed. + + + + + Destroy the locked pointer object. If applicable, the compositor will + unlock the pointer. + + + + + + Set the cursor position hint relative to the top left corner of the + surface. + + If the client is drawing its own cursor, it should update the position + hint to the position of its own cursor. A compositor may use this + information to warp the pointer upon unlock in order to avoid pointer + jumps. + + The cursor position hint is double buffered. The new hint will only take + effect when the associated surface gets it pending state applied. See + wl_surface.commit for details. + + + + + + + + Set a new region used to lock the pointer. + + The new lock region is double-buffered. The new lock region will + only take effect when the associated surface gets its pending state + applied. See wl_surface.commit for details. + + For details about the lock region, see wp_locked_pointer. + + + + + + + Notification that the pointer lock of the seat's pointer is activated. + + + + + + Notification that the pointer lock of the seat's pointer is no longer + active. If this is a oneshot pointer lock (see + wp_pointer_constraints.lifetime) this object is now defunct and should + be destroyed. If this is a persistent pointer lock (see + wp_pointer_constraints.lifetime) this pointer lock may again + reactivate in the future. + + + + + + + The wp_confined_pointer interface represents a confined pointer state. + + This object will send the event 'confined' when the confinement is + activated. Whenever the confinement is activated, it is guaranteed that + the surface the pointer is confined to will already have received pointer + focus and that the pointer will be within the region passed to the request + creating this object. It is up to the compositor to decide whether this + requires some user interaction and if the pointer will warp to within the + passed region if outside. + + To unconfine the pointer, send the destroy request. This will also destroy + the wp_confined_pointer object. + + If the compositor decides to unconfine the pointer the unconfined event is + sent. The wp_confined_pointer object is at this point defunct and should + be destroyed. + + + + + Destroy the confined pointer object. If applicable, the compositor will + unconfine the pointer. + + + + + + Set a new region used to confine the pointer. + + The new confine region is double-buffered. The new confine region will + only take effect when the associated surface gets its pending state + applied. See wl_surface.commit for details. + + If the confinement is active when the new confinement region is applied + and the pointer ends up outside of newly applied region, the pointer may + warped to a position within the new confinement region. If warped, a + wl_pointer.motion event will be emitted, but no + wp_relative_pointer.relative_motion event. + + The compositor may also, instead of using the new region, unconfine the + pointer. + + For details about the confine region, see wp_confined_pointer. + + + + + + + Notification that the pointer confinement of the seat's pointer is + activated. + + + + + + Notification that the pointer confinement of the seat's pointer is no + longer active. If this is a oneshot pointer confinement (see + wp_pointer_constraints.lifetime) this object is now defunct and should + be destroyed. If this is a persistent pointer confinement (see + wp_pointer_constraints.lifetime) this pointer confinement may again + reactivate in the future. + + + + + diff --git a/wl_protocols/relative-pointer-unstable-v1.xml b/wl_protocols/relative-pointer-unstable-v1.xml new file mode 100644 index 000000000..ca6f81d12 --- /dev/null +++ b/wl_protocols/relative-pointer-unstable-v1.xml @@ -0,0 +1,136 @@ + + + + + Copyright © 2014 Jonas Ådahl + Copyright © 2015 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a set of interfaces used for making clients able to + receive relative pointer events not obstructed by barriers (such as the + monitor edge or other pointer barriers). + + To start receiving relative pointer events, a client must first bind the + global interface "wp_relative_pointer_manager" which, if a compositor + supports relative pointer motion events, is exposed by the registry. After + having created the relative pointer manager proxy object, the client uses + it to create the actual relative pointer object using the + "get_relative_pointer" request given a wl_pointer. The relative pointer + motion events will then, when applicable, be transmitted via the proxy of + the newly created relative pointer object. See the documentation of the + relative pointer interface for more details. + + Warning! The protocol described in this file is experimental and backward + incompatible changes may be made. Backward compatible changes may be added + together with the corresponding interface version bump. Backward + incompatible changes are done by bumping the version number in the protocol + and interface names and resetting the interface version. Once the protocol + is to be declared stable, the 'z' prefix and the version number in the + protocol and interface names are removed and the interface version number is + reset. + + + + + A global interface used for getting the relative pointer object for a + given pointer. + + + + + Used by the client to notify the server that it will no longer use this + relative pointer manager object. + + + + + + Create a relative pointer interface given a wl_pointer object. See the + wp_relative_pointer interface for more details. + + + + + + + + + A wp_relative_pointer object is an extension to the wl_pointer interface + used for emitting relative pointer events. It shares the same focus as + wl_pointer objects of the same seat and will only emit events when it has + focus. + + + + + + + + + Relative x/y pointer motion from the pointer of the seat associated with + this object. + + A relative motion is in the same dimension as regular wl_pointer motion + events, except they do not represent an absolute position. For example, + moving a pointer from (x, y) to (x', y') would have the equivalent + relative motion (x' - x, y' - y). If a pointer motion caused the + absolute pointer position to be clipped by for example the edge of the + monitor, the relative motion is unaffected by the clipping and will + represent the unclipped motion. + + This event also contains non-accelerated motion deltas. The + non-accelerated delta is, when applicable, the regular pointer motion + delta as it was before having applied motion acceleration and other + transformations such as normalization. + + Note that the non-accelerated delta does not represent 'raw' events as + they were read from some device. Pointer motion acceleration is device- + and configuration-specific and non-accelerated deltas and accelerated + deltas may have the same value on some devices. + + Relative motions are not coupled to wl_pointer.motion events, and can be + sent in combination with such events, but also independently. There may + also be scenarios where wl_pointer.motion is sent, but there is no + relative motion. The order of an absolute and relative motion event + originating from the same physical motion is not guaranteed. + + If the client needs button events or focus state, it can receive them + from a wl_pointer object of the same seat that the wp_relative_pointer + object is associated with. + + + + + + + + + + +